From 79066e229b97ccc6fcbc7e2313afb7f54a17aec5 Mon Sep 17 00:00:00 2001 From: Vincent Macri Date: Mon, 20 Apr 2026 16:46:06 -0600 Subject: [PATCH 1/3] black long line length --- pyproject.toml | 2 + .../algebras/affine_nil_temperley_lieb.py | 4 +- src/sage/algebras/all.py | 10 +- src/sage/algebras/askey_wilson.py | 93 +- src/sage/algebras/associated_graded.py | 10 +- src/sage/algebras/catalog.py | 10 +- src/sage/algebras/cellular_basis.py | 16 +- src/sage/algebras/clifford_algebra.py | 88 +- src/sage/algebras/cluster_algebra.py | 62 +- src/sage/algebras/commutative_dga.py | 244 +- src/sage/algebras/down_up_algebra.py | 59 +- .../algebras/exterior_algebra_groebner.pyi | 8 +- .../finite_dimensional_algebra.py | 38 +- .../finite_dimensional_algebra_ideal.py | 1 + .../finite_dimensional_algebra_morphism.py | 19 +- src/sage/algebras/finite_gca.py | 22 +- src/sage/algebras/free_algebra.py | 70 +- src/sage/algebras/free_algebra_element.py | 10 +- src/sage/algebras/free_algebra_quotient.py | 14 +- .../algebras/free_algebra_quotient_element.py | 14 +- src/sage/algebras/free_zinbiel_algebra.py | 52 +- src/sage/algebras/fusion_rings/all.py | 1 + src/sage/algebras/fusion_rings/f_matrix.py | 42 +- .../algebras/fusion_rings/fusion_double.py | 39 +- src/sage/algebras/fusion_rings/fusion_ring.py | 87 +- src/sage/algebras/group_algebra.py | 12 +- src/sage/algebras/hall_algebra.py | 34 +- .../hecke_algebras/ariki_koike_algebra.py | 196 +- .../ariki_koike_specht_modules.py | 32 +- .../hecke_algebras/cubic_hecke_algebra.py | 131 +- .../hecke_algebras/cubic_hecke_base_ring.py | 24 +- .../hecke_algebras/cubic_hecke_matrix_rep.py | 26 +- src/sage/algebras/iwahori_hecke_algebra.py | 151 +- src/sage/algebras/jordan_algebra.py | 96 +- src/sage/algebras/lie_algebras/abelian.py | 15 +- .../lie_algebras/affine_lie_algebra.py | 110 +- src/sage/algebras/lie_algebras/bch.py | 5 +- .../algebras/lie_algebras/bgg_dual_module.py | 39 +- .../algebras/lie_algebras/bgg_resolution.py | 19 +- src/sage/algebras/lie_algebras/center_uea.py | 34 +- .../lie_algebras/classical_lie_algebra.py | 319 +- src/sage/algebras/lie_algebras/examples.py | 64 +- .../algebras/lie_algebras/free_lie_algebra.py | 53 +- src/sage/algebras/lie_algebras/heisenberg.py | 72 +- src/sage/algebras/lie_algebras/lie_algebra.py | 85 +- src/sage/algebras/lie_algebras/morphism.py | 35 +- .../lie_algebras/nilpotent_lie_algebra.py | 66 +- src/sage/algebras/lie_algebras/onsager.py | 210 +- .../lie_algebras/poincare_birkhoff_witt.py | 40 +- src/sage/algebras/lie_algebras/quotient.py | 27 +- .../rank_two_heisenberg_virasoro.py | 44 +- .../algebras/lie_algebras/representation.py | 40 +- .../lie_algebras/structure_coefficients.py | 79 +- src/sage/algebras/lie_algebras/subalgebra.py | 36 +- .../lie_algebras/symplectic_derivation.py | 33 +- .../algebras/lie_algebras/verma_module.py | 74 +- src/sage/algebras/lie_algebras/virasoro.py | 59 +- .../abelian_lie_conformal_algebra.py | 16 +- .../affine_lie_conformal_algebra.py | 21 +- .../algebras/lie_conformal_algebras/all.py | 6 +- .../bosonic_ghosts_lie_conformal_algebra.py | 29 +- .../fermionic_ghosts_lie_conformal_algebra.py | 33 +- .../finitely_freely_generated_lca.py | 19 +- .../free_bosons_lie_conformal_algebra.py | 37 +- .../free_fermions_lie_conformal_algebra.py | 40 +- .../freely_generated_lie_conformal_algebra.py | 22 +- .../graded_lie_conformal_algebra.py | 21 +- .../lie_conformal_algebra.py | 25 +- .../lie_conformal_algebra_element.py | 37 +- .../lie_conformal_algebra_with_basis.py | 7 +- ..._conformal_algebra_with_structure_coefs.py | 50 +- .../n2_lie_conformal_algebra.py | 23 +- .../neveu_schwarz_lie_conformal_algebra.py | 18 +- .../virasoro_lie_conformal_algebra.py | 12 +- .../weyl_lie_conformal_algebra.py | 44 +- src/sage/algebras/nil_coxeter_algebra.py | 7 +- src/sage/algebras/orlik_solomon.py | 39 +- src/sage/algebras/orlik_terao.py | 27 +- src/sage/algebras/q_commuting_polynomials.py | 23 +- src/sage/algebras/q_system.py | 56 +- src/sage/algebras/quantum_clifford.py | 93 +- .../quantum_groups/ace_quantum_onsager.py | 95 +- src/sage/algebras/quantum_groups/all.py | 1 + .../algebras/quantum_groups/fock_space.py | 292 +- src/sage/algebras/quantum_groups/q_numbers.py | 4 +- .../quantum_groups/quantum_group_gap.py | 105 +- .../quantum_groups/representations.py | 37 +- .../quantum_matrix_coordinate_algebra.py | 65 +- src/sage/algebras/quantum_oscillator.py | 38 +- .../algebras/quatalg/quaternion_algebra.py | 202 +- src/sage/algebras/quaternion_algebra.py | 3 +- .../algebras/quaternion_algebra_element.py | 1 - .../algebras/rational_cherednik_algebra.py | 56 +- src/sage/algebras/schur_algebra.py | 42 +- src/sage/algebras/shuffle_algebra.py | 25 +- src/sage/algebras/splitting_algebra.py | 61 +- src/sage/algebras/steenrod/all.py | 2 + .../algebras/steenrod/steenrod_algebra.py | 247 +- .../steenrod/steenrod_algebra_bases.py | 149 +- .../steenrod/steenrod_algebra_misc.py | 49 +- .../steenrod/steenrod_algebra_mult.py | 124 +- src/sage/algebras/tensor_algebra.py | 56 +- src/sage/algebras/weyl_algebra.py | 85 +- src/sage/algebras/yangian.py | 96 +- src/sage/algebras/yokonuma_hecke_algebra.py | 60 +- src/sage/all.py | 97 +- src/sage/all_cmdline.py | 7 +- src/sage/all_test.py | 10 +- src/sage/arith/all.py | 109 +- src/sage/arith/misc.py | 135 +- src/sage/calculus/all.py | 19 +- src/sage/calculus/calculus.py | 116 +- src/sage/calculus/desolvers.py | 95 +- src/sage/calculus/expr.py | 4 +- src/sage/calculus/functional.py | 4 + src/sage/calculus/functions.py | 5 +- src/sage/calculus/transforms/all.py | 1 + src/sage/calculus/transforms/dft.py | 72 +- src/sage/categories/additive_groups.py | 7 +- src/sage/categories/additive_magmas.py | 19 +- src/sage/categories/additive_monoids.py | 7 +- src/sage/categories/additive_semigroups.py | 4 + src/sage/categories/affine_weyl_groups.py | 9 +- src/sage/categories/algebra_functor.py | 12 +- src/sage/categories/algebra_ideals.py | 2 + src/sage/categories/algebra_modules.py | 7 +- src/sage/categories/algebras.py | 27 +- src/sage/categories/algebras_with_basis.py | 7 +- src/sage/categories/all.py | 13 +- src/sage/categories/aperiodic_semigroups.py | 5 +- src/sage/categories/associative_algebras.py | 2 + src/sage/categories/basic.py | 1 + src/sage/categories/bialgebras_with_basis.py | 7 +- src/sage/categories/bimodules.py | 28 +- src/sage/categories/cartesian_product.py | 10 +- src/sage/categories/category.py | 138 +- src/sage/categories/category_types.py | 33 +- src/sage/categories/category_with_axiom.py | 87 +- src/sage/categories/chain_complexes.py | 11 +- src/sage/categories/classical_crystals.py | 14 +- src/sage/categories/coalgebras.py | 8 +- src/sage/categories/coalgebras_with_basis.py | 14 +- .../categories/commutative_additive_groups.py | 8 +- .../commutative_additive_monoids.py | 6 +- .../commutative_additive_semigroups.py | 6 +- .../categories/commutative_algebra_ideals.py | 6 +- src/sage/categories/commutative_algebras.py | 8 +- .../categories/commutative_ring_ideals.py | 6 +- src/sage/categories/commutative_rings.py | 18 +- .../categories/complete_discrete_valuation.py | 8 +- .../categories/complex_reflection_groups.py | 9 +- ...eflection_or_generalized_coxeter_groups.py | 11 +- .../covariant_functorial_construction.py | 30 +- src/sage/categories/coxeter_group_algebras.py | 6 +- src/sage/categories/coxeter_groups.py | 104 +- src/sage/categories/crystals.py | 180 +- src/sage/categories/cw_complexes.py | 7 +- src/sage/categories/dedekind_domains.py | 3 + src/sage/categories/discrete_valuation.py | 9 +- ...distributive_magmas_and_additive_magmas.py | 2 + src/sage/categories/division_rings.py | 6 +- src/sage/categories/domains.py | 10 +- src/sage/categories/drinfeld_modules.py | 19 +- src/sage/categories/dual.py | 6 +- src/sage/categories/enumerated_sets.py | 38 +- src/sage/categories/euclidean_domains.py | 19 +- .../examples/algebras_with_basis.py | 8 +- .../examples/commutative_additive_monoids.py | 1 + .../commutative_additive_semigroups.py | 4 +- .../categories/examples/coxeter_groups.py | 2 + src/sage/categories/examples/crystals.py | 10 +- src/sage/categories/examples/cw_complexes.py | 10 +- src/sage/categories/examples/facade_sets.py | 7 +- .../examples/filtered_algebras_with_basis.py | 15 +- .../examples/filtered_modules_with_basis.py | 4 +- .../examples/finite_coxeter_groups.py | 2 + .../finite_dimensional_algebras_with_basis.py | 21 +- ...ite_dimensional_lie_algebras_with_basis.py | 12 +- .../examples/finite_enumerated_sets.py | 9 +- .../categories/examples/finite_monoids.py | 3 +- .../categories/examples/finite_semigroups.py | 6 +- .../categories/examples/finite_weyl_groups.py | 2 + ...aded_connected_hopf_algebras_with_basis.py | 11 +- .../examples/graded_modules_with_basis.py | 4 +- src/sage/categories/examples/graphs.py | 4 +- .../examples/hopf_algebras_with_basis.py | 7 +- .../examples/infinite_enumerated_sets.py | 3 +- src/sage/categories/examples/lie_algebras.py | 16 +- .../examples/lie_algebras_with_basis.py | 20 +- src/sage/categories/examples/magmas.py | 9 +- src/sage/categories/examples/manifolds.py | 6 +- src/sage/categories/examples/monoids.py | 3 +- src/sage/categories/examples/posets.py | 1 + src/sage/categories/examples/semigroups.py | 9 +- src/sage/categories/examples/semirings.py | 3 + src/sage/categories/examples/sets_cat.py | 18 +- .../categories/examples/sets_with_grading.py | 6 +- .../categories/examples/with_realizations.py | 34 +- src/sage/categories/facade_sets.py | 7 +- src/sage/categories/fields.py | 12 + src/sage/categories/filtered_algebras.py | 6 +- .../filtered_algebras_with_basis.py | 21 +- .../filtered_hopf_algebras_with_basis.py | 20 +- src/sage/categories/filtered_modules.py | 3 + .../categories/filtered_modules_with_basis.py | 44 +- .../finite_complex_reflection_groups.py | 80 +- src/sage/categories/finite_coxeter_groups.py | 85 +- src/sage/categories/finite_crystals.py | 6 +- .../finite_dimensional_algebras_with_basis.py | 130 +- ...inite_dimensional_bialgebras_with_basis.py | 6 +- ...inite_dimensional_coalgebras_with_basis.py | 6 +- ...ensional_graded_lie_algebras_with_basis.py | 19 +- ...te_dimensional_hopf_algebras_with_basis.py | 1 + ...ite_dimensional_lie_algebras_with_basis.py | 167 +- .../finite_dimensional_modules_with_basis.py | 71 +- ...ional_nilpotent_lie_algebras_with_basis.py | 11 +- ...ensional_semisimple_algebras_with_basis.py | 26 +- src/sage/categories/finite_enumerated_sets.py | 50 +- src/sage/categories/finite_fields.py | 26 +- src/sage/categories/finite_groups.py | 14 +- src/sage/categories/finite_lattice_posets.py | 6 +- src/sage/categories/finite_monoids.py | 4 + .../categories/finite_permutation_groups.py | 8 +- src/sage/categories/finite_posets.py | 57 +- src/sage/categories/finite_semigroups.py | 6 +- src/sage/categories/finite_sets.py | 7 +- src/sage/categories/finite_weyl_groups.py | 1 + ...itely_generated_lambda_bracket_algebras.py | 11 +- ...nitely_generated_lie_conformal_algebras.py | 9 +- .../categories/finitely_generated_magmas.py | 5 +- .../finitely_generated_semigroups.py | 14 +- src/sage/categories/function_fields.py | 6 +- src/sage/categories/g_sets.py | 9 +- src/sage/categories/gcd_domains.py | 5 +- .../categories/generalized_coxeter_groups.py | 8 +- src/sage/categories/graded_algebras.py | 6 +- .../categories/graded_algebras_with_basis.py | 24 +- src/sage/categories/graded_bialgebras.py | 6 +- .../graded_bialgebras_with_basis.py | 6 +- src/sage/categories/graded_coalgebras.py | 6 +- .../graded_coalgebras_with_basis.py | 7 +- src/sage/categories/graded_hopf_algebras.py | 2 + .../graded_hopf_algebras_with_basis.py | 24 +- src/sage/categories/graded_lie_algebras.py | 4 + .../graded_lie_algebras_with_basis.py | 5 +- .../graded_lie_conformal_algebras.py | 4 +- src/sage/categories/graded_modules.py | 2 + .../categories/graded_modules_with_basis.py | 39 +- src/sage/categories/graphs.py | 7 +- src/sage/categories/group_algebras.py | 16 +- src/sage/categories/groupoid.py | 8 +- src/sage/categories/groups.py | 28 +- src/sage/categories/h_trivial_semigroups.py | 5 +- src/sage/categories/hecke_modules.py | 5 + .../categories/highest_weight_crystals.py | 64 +- src/sage/categories/homset.py | 25 +- src/sage/categories/homsets.py | 16 +- src/sage/categories/hopf_algebras.py | 5 + .../categories/hopf_algebras_with_basis.py | 45 +- .../categories/infinite_enumerated_sets.py | 5 +- src/sage/categories/integral_domains.py | 4 + src/sage/categories/isomorphic_objects.py | 8 +- src/sage/categories/j_trivial_semigroups.py | 5 +- src/sage/categories/kac_moody_algebras.py | 3 + src/sage/categories/kahler_algebras.py | 8 +- src/sage/categories/l_trivial_semigroups.py | 5 +- .../categories/lambda_bracket_algebras.py | 19 +- .../lambda_bracket_algebras_with_basis.py | 10 +- src/sage/categories/lattice_posets.py | 23 +- src/sage/categories/left_modules.py | 7 +- src/sage/categories/lie_algebras.py | 64 +- .../categories/lie_algebras_with_basis.py | 19 +- src/sage/categories/lie_conformal_algebras.py | 47 +- .../lie_conformal_algebras_with_basis.py | 11 +- src/sage/categories/lie_groups.py | 8 +- src/sage/categories/loop_crystals.py | 62 +- src/sage/categories/magmas.py | 19 +- .../categories/magmas_and_additive_magmas.py | 5 +- src/sage/categories/magmatic_algebras.py | 43 +- src/sage/categories/manifolds.py | 10 +- src/sage/categories/map.pyi | 8 +- src/sage/categories/matrix_algebras.py | 5 +- src/sage/categories/metric_spaces.py | 8 +- .../categories/modular_abelian_varieties.py | 8 +- src/sage/categories/modules.py | 34 +- src/sage/categories/modules_with_basis.py | 109 +- src/sage/categories/monoid_algebras.py | 2 + src/sage/categories/monoids.py | 30 +- src/sage/categories/noetherian_rings.py | 2 + src/sage/categories/number_fields.py | 11 +- src/sage/categories/objects.py | 5 +- src/sage/categories/ore_modules.py | 1 + .../categories/partially_ordered_monoids.py | 5 +- src/sage/categories/permutation_groups.py | 6 +- src/sage/categories/pointed_sets.py | 10 +- src/sage/categories/polyhedra.py | 6 +- src/sage/categories/poor_man_map.py | 14 +- src/sage/categories/posets.py | 19 +- .../categories/principal_ideal_domains.py | 20 +- src/sage/categories/pushout.py | 282 +- .../quantum_group_representations.py | 74 +- src/sage/categories/quotient_fields.py | 30 +- src/sage/categories/quotients.py | 5 +- src/sage/categories/r_trivial_semigroups.py | 5 +- src/sage/categories/realizations.py | 9 +- src/sage/categories/regular_crystals.py | 59 +- src/sage/categories/regular_supercrystals.py | 2 + src/sage/categories/right_modules.py | 5 +- src/sage/categories/ring_ideals.py | 2 + src/sage/categories/rings.py | 34 +- src/sage/categories/rngs.py | 4 + src/sage/categories/schemes.py | 10 + src/sage/categories/semigroups.py | 34 +- src/sage/categories/semirings.py | 2 + src/sage/categories/semisimple_algebras.py | 6 +- src/sage/categories/sets_cat.py | 129 +- src/sage/categories/sets_with_grading.py | 3 + src/sage/categories/sets_with_partial_maps.py | 8 +- src/sage/categories/shephard_groups.py | 6 +- src/sage/categories/signed_tensor.py | 3 + src/sage/categories/simplicial_complexes.py | 10 +- src/sage/categories/simplicial_sets.py | 89 +- src/sage/categories/subobjects.py | 5 +- src/sage/categories/subquotients.py | 5 +- src/sage/categories/super_algebras.py | 5 +- .../categories/super_algebras_with_basis.py | 8 +- .../super_hopf_algebras_with_basis.py | 23 +- .../super_lie_conformal_algebras.py | 40 +- src/sage/categories/super_modules.py | 40 +- .../categories/super_modules_with_basis.py | 14 +- .../categories/supercommutative_algebras.py | 13 +- src/sage/categories/supercrystals.py | 18 +- src/sage/categories/tensor.py | 3 + src/sage/categories/topological_spaces.py | 6 +- .../triangular_kac_moody_algebras.py | 12 +- .../unique_factorization_domains.py | 2 + src/sage/categories/unital_algebras.py | 5 +- src/sage/categories/vector_bundles.py | 8 +- src/sage/categories/vector_spaces.py | 19 +- src/sage/categories/weyl_groups.py | 45 +- src/sage/categories/with_realizations.py | 5 +- src/sage/cli/interactive_shell_cmd.py | 1 + src/sage/coding/abstract_code.py | 34 +- src/sage/coding/ag_code.py | 50 +- src/sage/coding/all.py | 4 +- src/sage/coding/bch_code.py | 43 +- src/sage/coding/bounds_catalog.py | 31 +- src/sage/coding/channel.py | 31 +- src/sage/coding/channels_catalog.py | 10 +- src/sage/coding/code_bounds.py | 76 +- src/sage/coding/code_constructions.py | 83 +- src/sage/coding/codes_catalog.py | 14 +- src/sage/coding/cyclic_code.py | 107 +- src/sage/coding/databases.py | 19 +- src/sage/coding/decoder.py | 5 +- src/sage/coding/decoders_catalog.py | 18 +- src/sage/coding/delsarte_bounds.py | 66 +- src/sage/coding/encoder.py | 7 +- src/sage/coding/encoders_catalog.py | 23 +- src/sage/coding/extended_code.py | 20 +- src/sage/coding/gabidulin_code.py | 51 +- src/sage/coding/golay_code.py | 91 +- src/sage/coding/goppa_code.py | 33 +- src/sage/coding/grs_code.py | 117 +- src/sage/coding/guava.py | 6 +- src/sage/coding/guruswami_sudan/gs_decoder.py | 69 +- .../coding/guruswami_sudan/interpolation.py | 21 +- src/sage/coding/guruswami_sudan/utils.py | 17 +- src/sage/coding/hamming_code.py | 13 +- src/sage/coding/information_set_decoder.py | 73 +- src/sage/coding/linear_code.py | 204 +- src/sage/coding/linear_code_no_metric.py | 44 +- src/sage/coding/linear_rank_metric.py | 23 +- src/sage/coding/parity_check_code.py | 25 +- src/sage/coding/punctured_code.py | 26 +- src/sage/coding/reed_muller_code.py | 76 +- src/sage/coding/self_dual_codes.py | 441 +- src/sage/coding/source_coding/huffman.py | 17 +- src/sage/coding/subfield_subcode.py | 25 +- src/sage/coding/two_weight_db.py | 370 +- src/sage/combinat/SJT.py | 16 +- src/sage/combinat/abstract_tree.py | 91 +- src/sage/combinat/affine_permutation.py | 257 +- src/sage/combinat/all.py | 105 +- src/sage/combinat/alternating_sign_matrix.py | 172 +- src/sage/combinat/backtrack.py | 4 +- src/sage/combinat/baxter_permutations.py | 26 +- src/sage/combinat/bijectionist.py | 115 +- .../combinat/binary_recurrence_sequences.py | 104 +- src/sage/combinat/binary_tree.py | 124 +- src/sage/combinat/blob_algebra.py | 52 +- src/sage/combinat/cartesian_product.py | 7 +- src/sage/combinat/chas/all.py | 2 + src/sage/combinat/chas/fsym.py | 53 +- src/sage/combinat/chas/wqsym.py | 118 +- .../combinat/cluster_algebra_quiver/all.py | 4 +- .../cluster_algebra_quiver/cluster_seed.py | 268 +- .../cluster_algebra_quiver/interact.py | 26 +- .../cluster_algebra_quiver/mutation_class.py | 19 +- .../cluster_algebra_quiver/mutation_type.py | 38 +- .../combinat/cluster_algebra_quiver/quiver.py | 187 +- .../quiver_mutation_type.py | 304 +- src/sage/combinat/cluster_complex.py | 21 +- src/sage/combinat/colored_permutations.py | 143 +- src/sage/combinat/combinat.py | 43 +- src/sage/combinat/combination.py | 14 +- src/sage/combinat/combinatorial_map.py | 3 + src/sage/combinat/composition.py | 48 +- src/sage/combinat/composition_signed.py | 5 +- src/sage/combinat/composition_tableau.py | 40 +- src/sage/combinat/constellation.py | 94 +- src/sage/combinat/core.py | 23 +- src/sage/combinat/crystals/affine.py | 12 +- .../combinat/crystals/affine_factorization.py | 66 +- src/sage/combinat/crystals/affinization.py | 14 +- src/sage/combinat/crystals/alcove_path.py | 168 +- src/sage/combinat/crystals/all.py | 2 + src/sage/combinat/crystals/bkk_crystals.py | 1 + src/sage/combinat/crystals/crystals.py | 6 +- src/sage/combinat/crystals/direct_sum.py | 18 +- .../combinat/crystals/elementary_crystals.py | 3 +- src/sage/combinat/crystals/fast_crystals.py | 91 +- .../fully_commutative_stable_grothendieck.py | 146 +- .../crystals/generalized_young_walls.py | 34 +- .../crystals/highest_weight_crystals.py | 40 +- .../combinat/crystals/induced_structure.py | 8 +- .../combinat/crystals/infinity_crystals.py | 45 +- src/sage/combinat/crystals/kac_modules.py | 81 +- .../combinat/crystals/kirillov_reshetikhin.py | 420 +- .../combinat/crystals/kyoto_path_model.py | 30 +- src/sage/combinat/crystals/littelmann_path.py | 65 +- .../combinat/crystals/monomial_crystals.py | 112 +- src/sage/combinat/crystals/multisegments.py | 31 +- src/sage/combinat/crystals/mv_polytopes.py | 21 +- src/sage/combinat/crystals/pbw_crystal.py | 19 +- .../crystals/polyhedral_realization.py | 13 +- src/sage/combinat/crystals/star_crystal.py | 10 +- src/sage/combinat/crystals/subcrystal.py | 40 +- src/sage/combinat/crystals/tensor_product.py | 72 +- src/sage/combinat/crystals/virtual_crystal.py | 28 +- .../combinat/cyclic_sieving_phenomenon.py | 12 +- src/sage/combinat/decorated_permutation.py | 8 +- src/sage/combinat/derangements.py | 3 +- src/sage/combinat/descent_algebra.py | 46 +- .../combinat/designs/MOLS_handbook_data.py | 10500 ++++++++++- src/sage/combinat/designs/all.py | 12 +- src/sage/combinat/designs/bibd.py | 480 +- src/sage/combinat/designs/block_design.py | 165 +- src/sage/combinat/designs/covering_array.py | 15 +- src/sage/combinat/designs/covering_design.py | 25 +- src/sage/combinat/designs/database.py | 4274 ++--- src/sage/combinat/designs/design_catalog.py | 48 +- .../combinat/designs/difference_family.py | 662 +- .../combinat/designs/difference_matrices.py | 39 +- src/sage/combinat/designs/ext_rep.py | 21 +- .../designs/group_divisible_designs.py | 52 +- .../combinat/designs/incidence_structures.py | 128 +- src/sage/combinat/designs/latin_squares.py | 43 +- .../combinat/designs/orthogonal_arrays.py | 403 +- .../orthogonal_arrays_build_recursive.py | 473 +- src/sage/combinat/designs/resolvable_bibd.py | 307 +- .../designs/steiner_quadruple_systems.py | 3100 +++- src/sage/combinat/designs/twographs.py | 16 +- src/sage/combinat/diagram.py | 51 +- src/sage/combinat/diagram_algebras.py | 376 +- src/sage/combinat/dlx.py | 3 +- src/sage/combinat/dyck_word.py | 165 +- src/sage/combinat/e_one_star.py | 37 +- src/sage/combinat/family.py | 3 +- src/sage/combinat/finite_state_machine.py | 1000 +- .../finite_state_machine_generators.py | 246 +- src/sage/combinat/fqsym.py | 80 +- src/sage/combinat/free_dendriform_algebra.py | 73 +- src/sage/combinat/free_module.py | 104 +- src/sage/combinat/free_prelie_algebra.py | 60 +- .../combinat/fully_commutative_elements.py | 30 +- src/sage/combinat/fully_packed_loop.py | 75 +- src/sage/combinat/gelfand_tsetlin_patterns.py | 81 +- src/sage/combinat/graph_path.py | 1 + src/sage/combinat/gray_codes.py | 55 +- src/sage/combinat/grossman_larson_algebras.py | 30 +- src/sage/combinat/growth.py | 343 +- src/sage/combinat/hall_polynomial.py | 13 +- src/sage/combinat/hillman_grassl.py | 2 + src/sage/combinat/integer_lists/__init__.py | 1 + src/sage/combinat/integer_lists/lists.py | 2 + src/sage/combinat/integer_lists/nn.py | 1 + src/sage/combinat/integer_matrices.py | 8 +- src/sage/combinat/integer_vector.py | 56 +- src/sage/combinat/integer_vector_weighted.py | 16 +- .../combinat/integer_vectors_mod_permgroup.py | 81 +- src/sage/combinat/interval_posets.py | 172 +- src/sage/combinat/k_tableau.py | 376 +- src/sage/combinat/kazhdan_lusztig.py | 9 +- src/sage/combinat/key_polynomial.py | 60 +- src/sage/combinat/knutson_tao_puzzles.py | 86 +- src/sage/combinat/lr_tableau.py | 27 +- src/sage/combinat/matrices/all.py | 8 +- src/sage/combinat/matrices/dlxcpp.py | 1 + src/sage/combinat/matrices/hadamard_matrix.py | 615 +- src/sage/combinat/matrices/latin.py | 102 +- src/sage/combinat/misc.py | 20 +- .../multiset_partition_into_sets_ordered.py | 177 +- src/sage/combinat/ncsf_qsym/all.py | 2 + src/sage/combinat/ncsf_qsym/combinatorics.py | 33 +- .../combinat/ncsf_qsym/generic_basis_code.py | 59 +- src/sage/combinat/ncsf_qsym/ncsf.py | 299 +- src/sage/combinat/ncsf_qsym/qsym.py | 227 +- src/sage/combinat/ncsym/all.py | 2 + src/sage/combinat/ncsym/bases.py | 36 +- src/sage/combinat/ncsym/dual.py | 39 +- src/sage/combinat/ncsym/ncsym.py | 218 +- src/sage/combinat/necklace.py | 26 +- .../non_decreasing_parking_function.py | 5 + src/sage/combinat/nu_dyck_word.py | 74 +- src/sage/combinat/nu_tamari_lattice.py | 12 +- src/sage/combinat/ordered_tree.py | 31 +- src/sage/combinat/output.py | 121 +- src/sage/combinat/parallelogram_polyomino.py | 358 +- src/sage/combinat/parking_functions.py | 39 +- src/sage/combinat/partition.py | 519 +- src/sage/combinat/partition_algebra.py | 33 +- src/sage/combinat/partition_kleshchev.py | 173 +- .../combinat/partition_shifting_algebras.py | 33 +- src/sage/combinat/partition_tuple.py | 151 +- src/sage/combinat/path_tableaux/all.py | 2 + src/sage/combinat/path_tableaux/catalog.py | 4 +- src/sage/combinat/path_tableaux/dyck_path.py | 30 +- src/sage/combinat/path_tableaux/frieze.py | 29 +- .../combinat/path_tableaux/path_tableau.py | 73 +- .../combinat/path_tableaux/semistandard.py | 45 +- src/sage/combinat/perfect_matching.py | 31 +- src/sage/combinat/permutation.py | 402 +- src/sage/combinat/plane_partition.py | 335 +- src/sage/combinat/posets/all.py | 2 + src/sage/combinat/posets/bubble_shuffle.py | 15 +- src/sage/combinat/posets/cartesian_product.py | 12 +- src/sage/combinat/posets/d_complete.py | 4 +- src/sage/combinat/posets/elements.py | 3 +- src/sage/combinat/posets/forest.py | 1 + src/sage/combinat/posets/hasse_diagram.py | 89 +- .../combinat/posets/hochschild_lattice.py | 17 +- .../combinat/posets/incidence_algebras.py | 15 +- src/sage/combinat/posets/lattices.py | 194 +- src/sage/combinat/posets/linear_extensions.py | 34 +- src/sage/combinat/posets/mobile.py | 8 +- src/sage/combinat/posets/moebius_algebra.py | 76 +- src/sage/combinat/posets/poset_examples.py | 143 +- src/sage/combinat/posets/posets.py | 379 +- src/sage/combinat/posets/sashes.py | 14 +- .../positive_integer_semigroup_test.py | 5 +- src/sage/combinat/q_analogues.py | 51 +- src/sage/combinat/ranker.py | 6 +- src/sage/combinat/recognizable_series.py | 102 +- src/sage/combinat/regular_sequence.py | 429 +- src/sage/combinat/regular_sequence_bounded.py | 16 +- src/sage/combinat/restricted_growth.py | 1 + src/sage/combinat/ribbon.py | 1 + src/sage/combinat/ribbon_shaped_tableau.py | 18 +- src/sage/combinat/ribbon_tableau.py | 53 +- .../combinat/rigged_configurations/all.py | 5 +- .../bij_abstract_class.py | 25 +- .../rigged_configurations/bij_infinity.py | 54 +- .../rigged_configurations/bij_type_A2_dual.py | 90 +- .../rigged_configurations/bij_type_A2_even.py | 32 +- .../rigged_configurations/bij_type_A2_odd.py | 19 +- .../rigged_configurations/bij_type_B.py | 156 +- .../rigged_configurations/bij_type_C.py | 47 +- .../rigged_configurations/bij_type_D.py | 60 +- .../rigged_configurations/bij_type_D_tri.py | 49 +- .../bij_type_D_twisted.py | 120 +- .../rigged_configurations/bij_type_E67.py | 20 +- .../rigged_configurations/bijection.py | 32 +- .../rigged_configurations/kleber_tree.py | 78 +- .../rigged_configurations/kr_tableaux.py | 53 +- .../rigged_configurations/rc_crystal.py | 33 +- .../rigged_configurations/rc_infinity.py | 29 +- .../rigged_configuration_element.py | 124 +- .../rigged_configurations.py | 157 +- .../tensor_product_kr_tableaux.py | 41 +- .../tensor_product_kr_tableaux_element.py | 18 +- src/sage/combinat/root_system/all.py | 22 +- .../combinat/root_system/ambient_space.py | 32 +- .../combinat/root_system/associahedron.py | 7 +- .../root_system/braid_move_calculator.py | 11 +- .../combinat/root_system/branching_rules.py | 681 +- .../combinat/root_system/cartan_matrix.py | 100 +- src/sage/combinat/root_system/cartan_type.py | 191 +- .../combinat/root_system/coxeter_group.py | 4 +- .../combinat/root_system/coxeter_matrix.py | 57 +- src/sage/combinat/root_system/coxeter_type.py | 23 +- .../combinat/root_system/dynkin_diagram.py | 36 +- .../root_system/extended_affine_weyl_group.py | 84 +- .../combinat/root_system/fundamental_group.py | 19 +- .../hecke_algebra_representation.py | 41 +- .../root_system/integrable_representations.py | 151 +- .../non_symmetric_macdonald_polynomials.py | 36 +- .../combinat/root_system/pieri_factors.py | 78 +- src/sage/combinat/root_system/plot.py | 80 +- .../root_system/reflection_group_complex.py | 186 +- .../root_system/reflection_group_real.py | 65 +- .../root_lattice_realization_algebras.py | 52 +- .../root_system/root_lattice_realizations.py | 294 +- src/sage/combinat/root_system/root_space.py | 20 +- src/sage/combinat/root_system/root_system.py | 9 +- src/sage/combinat/root_system/type_A.py | 34 +- .../combinat/root_system/type_A_affine.py | 25 +- .../combinat/root_system/type_A_infinity.py | 2 + src/sage/combinat/root_system/type_B.py | 35 +- .../combinat/root_system/type_BC_affine.py | 36 +- .../combinat/root_system/type_B_affine.py | 44 +- src/sage/combinat/root_system/type_C.py | 20 +- .../combinat/root_system/type_C_affine.py | 33 +- src/sage/combinat/root_system/type_D.py | 35 +- .../combinat/root_system/type_D_affine.py | 39 +- src/sage/combinat/root_system/type_E.py | 116 +- .../combinat/root_system/type_E_affine.py | 46 +- src/sage/combinat/root_system/type_F.py | 57 +- .../combinat/root_system/type_F_affine.py | 16 +- src/sage/combinat/root_system/type_G.py | 30 +- .../combinat/root_system/type_G_affine.py | 15 +- src/sage/combinat/root_system/type_H.py | 10 +- src/sage/combinat/root_system/type_I.py | 8 +- src/sage/combinat/root_system/type_Q.py | 14 +- src/sage/combinat/root_system/type_affine.py | 24 +- src/sage/combinat/root_system/type_dual.py | 46 +- src/sage/combinat/root_system/type_folded.py | 13 +- src/sage/combinat/root_system/type_marked.py | 28 +- .../combinat/root_system/type_reducible.py | 45 +- src/sage/combinat/root_system/type_relabel.py | 42 +- src/sage/combinat/root_system/type_super_A.py | 88 +- .../weight_lattice_realizations.py | 69 +- src/sage/combinat/root_system/weight_space.py | 29 +- .../combinat/root_system/weyl_characters.py | 52 +- src/sage/combinat/root_system/weyl_group.py | 86 +- src/sage/combinat/rooted_tree.py | 23 +- src/sage/combinat/rsk.py | 127 +- src/sage/combinat/schubert_polynomial.py | 10 +- src/sage/combinat/set_partition.py | 68 +- src/sage/combinat/set_partition_ordered.py | 40 +- src/sage/combinat/sf/abreu_nigro.py | 9 +- src/sage/combinat/sf/all.py | 5 +- src/sage/combinat/sf/character.py | 53 +- src/sage/combinat/sf/classical.py | 42 +- src/sage/combinat/sf/dual.py | 59 +- src/sage/combinat/sf/elementary.py | 27 +- src/sage/combinat/sf/hall_littlewood.py | 62 +- src/sage/combinat/sf/hecke.py | 33 +- src/sage/combinat/sf/homogeneous.py | 22 +- src/sage/combinat/sf/jack.py | 101 +- src/sage/combinat/sf/k_dual.py | 59 +- src/sage/combinat/sf/kfpoly.py | 48 +- src/sage/combinat/sf/llt.py | 67 +- src/sage/combinat/sf/macdonald.py | 147 +- src/sage/combinat/sf/monomial.py | 18 +- src/sage/combinat/sf/multiplicative.py | 4 +- src/sage/combinat/sf/new_kschur.py | 69 +- src/sage/combinat/sf/ns_macdonald.py | 37 +- src/sage/combinat/sf/orthogonal.py | 22 +- src/sage/combinat/sf/orthotriang.py | 15 +- src/sage/combinat/sf/powersum.py | 45 +- src/sage/combinat/sf/schur.py | 65 +- src/sage/combinat/sf/sf.py | 26 +- src/sage/combinat/sf/sfa.py | 279 +- src/sage/combinat/sf/symplectic.py | 22 +- src/sage/combinat/sf/witt.py | 20 +- src/sage/combinat/shard_order.py | 7 +- src/sage/combinat/shifted_primed_tableau.py | 236 +- src/sage/combinat/shuffle.py | 35 +- src/sage/combinat/sidon_sets.py | 1 + src/sage/combinat/similarity_class_type.py | 98 +- src/sage/combinat/sine_gordon.py | 61 +- src/sage/combinat/six_vertex_model.py | 116 +- src/sage/combinat/skew_partition.py | 147 +- src/sage/combinat/skew_tableau.py | 72 +- src/sage/combinat/sloane_functions.py | 278 +- src/sage/combinat/specht_module.py | 49 +- src/sage/combinat/species/all.py | 9 +- .../species/characteristic_species.py | 12 +- .../combinat/species/composition_species.py | 6 +- src/sage/combinat/species/cycle_species.py | 16 +- src/sage/combinat/species/empty_species.py | 1 + .../species/functorial_composition_species.py | 2 + .../combinat/species/generating_series.py | 11 +- src/sage/combinat/species/library.py | 1 + .../combinat/species/linear_order_species.py | 12 +- src/sage/combinat/species/misc.py | 9 +- .../combinat/species/partition_species.py | 20 +- .../combinat/species/permutation_species.py | 21 +- src/sage/combinat/species/product_species.py | 32 +- .../combinat/species/recursive_species.py | 1 + src/sage/combinat/species/set_species.py | 11 +- src/sage/combinat/species/species.py | 27 +- src/sage/combinat/species/structure.py | 53 +- src/sage/combinat/species/subset_species.py | 16 +- src/sage/combinat/species/sum_species.py | 22 +- src/sage/combinat/subset.py | 44 +- src/sage/combinat/subsets_hereditary.py | 13 +- src/sage/combinat/subsets_pairwise.py | 10 +- src/sage/combinat/subword.py | 5 +- src/sage/combinat/subword_complex.py | 121 +- src/sage/combinat/super_tableau.py | 83 +- src/sage/combinat/superpartition.py | 75 +- src/sage/combinat/symmetric_group_algebra.py | 144 +- .../symmetric_group_representations.py | 82 +- src/sage/combinat/t_sequences.py | 72 +- src/sage/combinat/tableau.py | 571 +- src/sage/combinat/tableau_residues.py | 44 +- src/sage/combinat/tableau_tuple.py | 223 +- src/sage/combinat/tamari_blossoming_tree.py | 115 +- src/sage/combinat/tamari_lattices.py | 17 +- src/sage/combinat/tiling.py | 138 +- src/sage/combinat/tools.py | 1 + src/sage/combinat/triangles_FHM.py | 39 +- src/sage/combinat/tuple.py | 6 +- src/sage/combinat/vector_partition.py | 16 +- src/sage/combinat/words/abstract_word.py | 35 +- src/sage/combinat/words/all.py | 3 + src/sage/combinat/words/alphabet.py | 20 +- src/sage/combinat/words/finite_word.py | 276 +- src/sage/combinat/words/infinite_word.py | 1 + src/sage/combinat/words/lyndon_word.py | 28 +- src/sage/combinat/words/morphic.py | 8 +- src/sage/combinat/words/morphism.py | 109 +- src/sage/combinat/words/paths.py | 146 +- src/sage/combinat/words/shuffle_product.py | 4 +- src/sage/combinat/words/suffix_trees.py | 149 +- src/sage/combinat/words/word.py | 44 +- src/sage/combinat/words/word_generators.py | 80 +- .../combinat/words/word_infinite_datatypes.py | 47 +- src/sage/combinat/words/word_options.py | 9 +- src/sage/combinat/words/words.py | 91 +- src/sage/combinat/yang_baxter_graph.py | 11 +- src/sage/config_test.py | 4 +- src/sage/cpython/__init__.py | 1 + src/sage/crypto/__init__.py | 1 + src/sage/crypto/all.py | 41 +- src/sage/crypto/block_cipher/des.py | 116 +- src/sage/crypto/block_cipher/miniaes.py | 161 +- src/sage/crypto/block_cipher/present.py | 41 +- src/sage/crypto/block_cipher/sdes.py | 72 +- src/sage/crypto/cipher.py | 9 +- src/sage/crypto/classical.py | 92 +- src/sage/crypto/classical_cipher.py | 53 +- src/sage/crypto/cryptosystem.py | 12 +- src/sage/crypto/lattice.py | 39 +- src/sage/crypto/lfsr.py | 6 +- src/sage/crypto/lwe.py | 77 +- src/sage/crypto/mq/__init__.py | 1 + .../crypto/mq/mpolynomialsystemgenerator.py | 3 +- src/sage/crypto/mq/rijndael_gf.py | 288 +- src/sage/crypto/mq/sbox.py | 5 +- src/sage/crypto/mq/sr.py | 620 +- src/sage/crypto/public_key/blum_goldwasser.py | 6 +- .../crypto/public_key/key_exchange/sidh.py | 28 +- src/sage/crypto/sboxes.py | 15168 ++++++++++++++-- src/sage/crypto/stream.py | 9 +- src/sage/crypto/stream_cipher.py | 18 +- src/sage/crypto/util.py | 5 +- src/sage/data_structures/all.py | 1 - src/sage/data_structures/mutable_poset.py | 80 +- src/sage/data_structures/stream.py | 272 +- src/sage/databases/all.py | 13 +- src/sage/databases/conway.py | 2 + src/sage/databases/cremona.py | 277 +- src/sage/databases/cubic_hecke_db.py | 454 +- src/sage/databases/cunningham_tables.py | 1 + src/sage/databases/db_class_polynomials.py | 15 +- src/sage/databases/db_modular_polynomials.py | 11 +- src/sage/databases/findstat.py | 487 +- src/sage/databases/jones.py | 2 +- src/sage/databases/knotinfo_db.py | 424 +- src/sage/databases/odlyzko.py | 1 + src/sage/databases/oeis.py | 111 +- src/sage/databases/sloane.py | 13 +- src/sage/databases/sql_db.py | 354 +- src/sage/databases/stein_watkins.py | 3 +- src/sage/databases/symbolic_data.py | 2 + src/sage/doctest/__main__.py | 105 +- src/sage/doctest/all.py | 1 + src/sage/doctest/check_tolerance.py | 62 +- src/sage/doctest/control.py | 103 +- src/sage/doctest/external.py | 45 +- src/sage/doctest/fixtures.py | 28 +- src/sage/doctest/forker.py | 160 +- src/sage/doctest/marked_output.py | 1 + src/sage/doctest/parsing.py | 96 +- src/sage/doctest/reporting.py | 6 +- src/sage/doctest/sources.py | 98 +- src/sage/doctest/util.py | 23 +- src/sage/dynamics/all.py | 5 +- .../dynamics/arithmetic_dynamics/affine_ds.py | 13 +- src/sage/dynamics/arithmetic_dynamics/all.py | 1 + .../arithmetic_dynamics/berkovich_ds.py | 48 +- .../dynamical_semigroup.py | 14 +- .../endPN_automorphism_group.py | 508 +- .../endPN_minimal_model.py | 288 +- .../arithmetic_dynamics/generic_ds.py | 33 +- .../product_projective_ds.py | 15 +- .../arithmetic_dynamics/projective_ds.py | 1083 +- .../dynamics/arithmetic_dynamics/wehlerK3.py | 568 +- src/sage/dynamics/cellular_automata/all.py | 4 +- .../dynamics/cellular_automata/catalog.py | 23 +- .../dynamics/cellular_automata/elementary.py | 44 +- src/sage/dynamics/cellular_automata/glca.py | 54 +- .../dynamics/cellular_automata/solitons.py | 116 +- src/sage/dynamics/complex_dynamics/all.py | 4 +- .../dynamics/complex_dynamics/mandel_julia.py | 144 +- src/sage/dynamics/finite_dynamical_system.py | 39 +- .../finite_dynamical_system_catalog.py | 43 +- src/sage/env.py | 20 +- src/sage/features/__init__.py | 23 +- src/sage/features/all.py | 1 + src/sage/features/bitness.py | 2 + src/sage/features/bliss.py | 9 +- src/sage/features/brial.py | 5 +- src/sage/features/cddlib.py | 4 +- src/sage/features/coxeter3.py | 5 +- src/sage/features/csdp.py | 12 +- src/sage/features/cython.py | 1 + src/sage/features/databases.py | 4 +- src/sage/features/dot2tex.py | 1 + src/sage/features/dvipng.py | 5 +- src/sage/features/ecm.py | 5 +- src/sage/features/ffmpeg.py | 32 +- src/sage/features/flatter.py | 1 + src/sage/features/four_ti_2.py | 22 +- src/sage/features/fricas.py | 15 +- src/sage/features/gap.py | 21 +- src/sage/features/gfan.py | 1 + src/sage/features/giac.py | 4 +- src/sage/features/graph_generators.py | 37 +- src/sage/features/graphviz.py | 21 +- src/sage/features/igraph.py | 5 +- src/sage/features/imagemagick.py | 23 +- src/sage/features/info.py | 4 +- src/sage/features/interfaces.py | 19 +- src/sage/features/internet.py | 1 + src/sage/features/jmol.py | 8 +- src/sage/features/join_feature.py | 3 +- src/sage/features/kenzo.py | 11 +- src/sage/features/khoca.py | 2 + src/sage/features/latex.py | 38 +- src/sage/features/latte.py | 15 +- src/sage/features/lrs.py | 34 +- src/sage/features/mcqd.py | 4 +- src/sage/features/meataxe.py | 5 +- src/sage/features/meson_editable.py | 2 + src/sage/features/mip_backends.py | 27 +- src/sage/features/msolve.py | 16 +- src/sage/features/normaliz.py | 4 +- src/sage/features/palp.py | 17 +- src/sage/features/pandoc.py | 5 +- src/sage/features/pdf2svg.py | 6 +- src/sage/features/phitigra.py | 1 + src/sage/features/pkg_systems.py | 10 +- src/sage/features/polymake.py | 4 +- src/sage/features/poppler.py | 5 +- src/sage/features/rubiks.py | 30 +- src/sage/features/sagemath.py | 327 +- src/sage/features/sat.py | 21 +- src/sage/features/singular.py | 4 +- src/sage/features/sirocco.py | 5 +- src/sage/features/sloane_database.py | 4 +- src/sage/features/sphinx.py | 8 +- src/sage/features/standard.py | 36 +- src/sage/features/symengine_py.py | 5 +- src/sage/features/tdlib.py | 5 +- src/sage/features/threejs.py | 8 +- src/sage/features/topcom.py | 10 +- src/sage/functions/airy.py | 78 +- src/sage/functions/all.py | 100 +- src/sage/functions/bessel.py | 147 +- src/sage/functions/error.py | 65 +- src/sage/functions/exp_integral.py | 92 +- src/sage/functions/gamma.py | 52 +- src/sage/functions/generalized.py | 47 +- src/sage/functions/hyperbolic.py | 39 +- src/sage/functions/hypergeometric.py | 104 +- src/sage/functions/jacobi.py | 262 +- src/sage/functions/log.py | 50 +- src/sage/functions/min_max.py | 6 +- src/sage/functions/orthogonal_polys.py | 283 +- src/sage/functions/other.py | 143 +- src/sage/functions/piecewise.py | 94 +- src/sage/functions/special.py | 133 +- src/sage/functions/spike_function.py | 22 +- src/sage/functions/transcendental.py | 58 +- src/sage/functions/trig.py | 59 +- src/sage/functions/wigner.py | 77 +- .../game_theory/catalog_normal_form_games.py | 21 +- src/sage/game_theory/cooperative_game.py | 7 +- src/sage/game_theory/matching_game.py | 14 +- src/sage/game_theory/normal_form_game.py | 77 +- src/sage/game_theory/parser.py | 6 +- src/sage/games/all.py | 1 - src/sage/games/hexad.py | 59 +- src/sage/games/quantumino.py | 60 +- src/sage/games/sudoku.py | 42 +- src/sage/geometry/all.py | 4 +- src/sage/geometry/cone.py | 307 +- src/sage/geometry/cone_catalog.py | 19 +- src/sage/geometry/cone_critical_angles.py | 90 +- src/sage/geometry/convex_set.py | 29 +- src/sage/geometry/fan.py | 249 +- src/sage/geometry/fan_isomorphism.py | 32 +- src/sage/geometry/fan_morphism.py | 151 +- src/sage/geometry/hasse_diagram.py | 33 +- .../hyperbolic_space/hyperbolic_coercion.py | 124 +- .../hyperbolic_space/hyperbolic_constants.py | 2 +- .../hyperbolic_space/hyperbolic_geodesic.py | 110 +- .../hyperbolic_space/hyperbolic_interface.py | 10 +- .../hyperbolic_space/hyperbolic_isometry.py | 70 +- .../hyperbolic_space/hyperbolic_model.py | 102 +- .../hyperbolic_space/hyperbolic_point.py | 33 +- .../hyperplane_arrangement/affine_subspace.py | 15 +- .../hyperplane_arrangement/arrangement.py | 126 +- .../hyperplane_arrangement/check_freeness.py | 10 +- .../hyperplane_arrangement/hyperplane.py | 24 +- .../hyperplane_arrangement/library.py | 34 +- .../ordered_arrangement.py | 7 +- .../geometry/hyperplane_arrangement/plot.py | 102 +- src/sage/geometry/integral_points.py | 4 +- src/sage/geometry/lattice_polytope.py | 284 +- src/sage/geometry/linear_expression.py | 20 +- src/sage/geometry/newton_polygon.py | 46 +- src/sage/geometry/polyhedral_complex.py | 248 +- src/sage/geometry/polyhedron/all.py | 5 +- src/sage/geometry/polyhedron/backend_cdd.py | 39 +- .../geometry/polyhedron/backend_cdd_rdf.py | 6 + src/sage/geometry/polyhedron/backend_field.py | 22 +- .../geometry/polyhedron/backend_normaliz.py | 84 +- .../polyhedron/backend_number_field.py | 19 +- .../geometry/polyhedron/backend_polymake.py | 44 +- src/sage/geometry/polyhedron/backend_ppl.py | 13 +- src/sage/geometry/polyhedron/base.py | 55 +- src/sage/geometry/polyhedron/base0.py | 30 +- src/sage/geometry/polyhedron/base1.py | 24 +- src/sage/geometry/polyhedron/base2.py | 24 +- src/sage/geometry/polyhedron/base3.py | 40 +- src/sage/geometry/polyhedron/base4.py | 26 +- src/sage/geometry/polyhedron/base5.py | 297 +- src/sage/geometry/polyhedron/base6.py | 117 +- src/sage/geometry/polyhedron/base7.py | 48 +- src/sage/geometry/polyhedron/base_QQ.py | 72 +- src/sage/geometry/polyhedron/base_RDF.py | 1 + src/sage/geometry/polyhedron/base_ZZ.py | 64 +- .../geometry/polyhedron/base_number_field.py | 6 +- .../geometry/polyhedron/cdd_file_format.py | 13 +- src/sage/geometry/polyhedron/constructor.py | 11 +- .../geometry/polyhedron/double_description.py | 27 +- .../double_description_inhomogeneous.py | 30 +- src/sage/geometry/polyhedron/face.py | 30 +- .../polyhedron/generating_function.py | 170 +- .../lattice_euclidean_group_element.py | 16 +- src/sage/geometry/polyhedron/library.py | 240 +- src/sage/geometry/polyhedron/misc.py | 1 + .../modules/formal_polyhedra_module.py | 8 +- src/sage/geometry/polyhedron/palp_database.py | 20 +- src/sage/geometry/polyhedron/parent.py | 54 +- src/sage/geometry/polyhedron/plot.py | 162 +- .../polyhedron/ppl_lattice_polygon.py | 63 +- .../polyhedron/ppl_lattice_polytope.py | 78 +- .../geometry/polyhedron/representation.py | 37 +- src/sage/geometry/pseudolines.py | 73 +- src/sage/geometry/ribbon_graph.py | 252 +- src/sage/geometry/riemannian_manifolds/all.py | 7 +- .../parametrized_surface3d.py | 140 +- .../surface3d_generators.py | 41 +- src/sage/geometry/toric_lattice.py | 90 +- src/sage/geometry/toric_plotter.py | 113 +- src/sage/geometry/triangulation/element.py | 129 +- .../triangulation/point_configuration.py | 221 +- src/sage/geometry/voronoi_diagram.py | 31 +- src/sage/graphs/all.py | 6 +- src/sage/graphs/bipartite_graph.py | 120 +- src/sage/graphs/cographs.py | 9 +- src/sage/graphs/cycle_enumeration.py | 92 +- src/sage/graphs/digraph.py | 202 +- src/sage/graphs/digraph_generators.py | 161 +- src/sage/graphs/domination.py | 54 +- src/sage/graphs/dot2tex_utils.py | 4 +- src/sage/graphs/generators/basic.py | 116 +- src/sage/graphs/generators/chessboard.py | 37 +- .../graphs/generators/classical_geometries.py | 212 +- src/sage/graphs/generators/degree_sequence.py | 19 +- src/sage/graphs/generators/families.py | 553 +- src/sage/graphs/generators/generators_test.py | 4 +- src/sage/graphs/generators/intersection.py | 38 +- src/sage/graphs/generators/platonic_solids.py | 57 +- src/sage/graphs/generators/random.py | 119 +- src/sage/graphs/generators/smallgraphs.py | 2565 +-- src/sage/graphs/generators/world_map.py | 651 +- src/sage/graphs/generic_graph.py | 1421 +- src/sage/graphs/graph.py | 562 +- src/sage/graphs/graph_database.py | 83 +- src/sage/graphs/graph_editor.py | 1 + src/sage/graphs/graph_generators.py | 704 +- src/sage/graphs/graph_input.py | 59 +- src/sage/graphs/graph_latex.py | 157 +- src/sage/graphs/graph_list.py | 15 +- src/sage/graphs/graph_plot.py | 363 +- src/sage/graphs/graph_plot_js.py | 40 +- src/sage/graphs/hypergraph_generators.py | 19 +- src/sage/graphs/isgci.py | 22 +- src/sage/graphs/lovasz_theta.py | 1 + src/sage/graphs/matching.py | 66 +- src/sage/graphs/matching_covered_graph.py | 169 +- src/sage/graphs/morphisms.py | 15 +- src/sage/graphs/orientations.py | 93 +- src/sage/graphs/partial_cube.py | 12 +- src/sage/graphs/pq_trees.py | 55 +- src/sage/graphs/print_graphs.py | 8 +- src/sage/graphs/schnyder.py | 41 +- .../graphs/tests/is_projective_planar_test.py | 1 + src/sage/graphs/tutte_polynomial.py | 39 +- src/sage/groups/abelian_gps/abelian_aut.py | 25 +- src/sage/groups/abelian_gps/abelian_group.py | 69 +- .../abelian_gps/abelian_group_element.py | 3 + .../groups/abelian_gps/abelian_group_gap.py | 20 +- .../abelian_gps/abelian_group_morphism.py | 40 +- src/sage/groups/abelian_gps/all.py | 4 +- .../groups/abelian_gps/dual_abelian_group.py | 7 +- .../abelian_gps/dual_abelian_group_element.py | 7 +- src/sage/groups/abelian_gps/element_base.py | 20 +- src/sage/groups/abelian_gps/values.py | 8 +- .../additive_abelian_group.py | 4 + .../additive_abelian_wrapper.py | 25 +- src/sage/groups/additive_abelian/all.py | 1 - src/sage/groups/additive_abelian/qmodnz.py | 1 + .../groups/additive_abelian/qmodnz_element.py | 1 + src/sage/groups/affine_gps/affine_group.py | 15 +- src/sage/groups/affine_gps/euclidean_group.py | 3 +- src/sage/groups/affine_gps/group_element.py | 36 +- src/sage/groups/all.py | 9 +- src/sage/groups/artin.py | 46 +- src/sage/groups/braid.py | 482 +- src/sage/groups/cactus_group.py | 71 +- src/sage/groups/class_function.py | 10 +- src/sage/groups/conjugacy_classes.py | 24 +- src/sage/groups/cubic_braid.py | 111 +- src/sage/groups/finitely_presented.py | 55 +- src/sage/groups/finitely_presented_named.py | 34 +- src/sage/groups/fqf_orthogonal.py | 35 +- src/sage/groups/free_group.py | 41 +- src/sage/groups/galois_group.py | 14 +- src/sage/groups/galois_group_perm.py | 4 + src/sage/groups/generic.py | 58 +- src/sage/groups/group_exp.py | 4 + src/sage/groups/group_semidirect_product.py | 36 +- src/sage/groups/indexed_free_group.py | 34 +- src/sage/groups/kernel_subgroup.py | 1 + src/sage/groups/libgap_mixin.py | 14 +- src/sage/groups/libgap_morphism.py | 18 +- .../groups/lie_gps/nilpotent_lie_group.py | 30 +- src/sage/groups/matrix_gps/binary_dihedral.py | 12 +- src/sage/groups/matrix_gps/coxeter_group.py | 24 +- .../groups/matrix_gps/finitely_generated.py | 21 +- .../matrix_gps/finitely_generated_gap.py | 80 +- src/sage/groups/matrix_gps/heisenberg.py | 19 +- src/sage/groups/matrix_gps/isometries.py | 35 +- src/sage/groups/matrix_gps/linear.py | 33 +- src/sage/groups/matrix_gps/linear_gap.py | 1 + src/sage/groups/matrix_gps/matrix_group.py | 24 +- .../groups/matrix_gps/matrix_group_gap.py | 6 +- src/sage/groups/matrix_gps/named_group.py | 6 +- src/sage/groups/matrix_gps/named_group_gap.py | 7 +- src/sage/groups/matrix_gps/orthogonal.py | 20 +- src/sage/groups/matrix_gps/orthogonal_gap.py | 3 +- .../groups/matrix_gps/pickling_overrides.py | 13 +- src/sage/groups/matrix_gps/symplectic.py | 14 +- src/sage/groups/matrix_gps/unitary.py | 18 +- src/sage/groups/matrix_gps/unitary_gap.py | 1 + src/sage/groups/misc_gps/argument_groups.py | 78 +- src/sage/groups/misc_gps/imaginary_groups.py | 24 +- src/sage/groups/pari_group.py | 3 +- src/sage/groups/perm_gps/all.py | 15 +- src/sage/groups/perm_gps/constructor.py | 1 + src/sage/groups/perm_gps/cubegroup.py | 341 +- src/sage/groups/perm_gps/permgroup.py | 203 +- .../groups/perm_gps/permgroup_morphism.py | 1 + src/sage/groups/perm_gps/permgroup_named.py | 124 +- .../perm_gps/permutation_groups_catalog.py | 2 +- .../groups/perm_gps/symgp_conjugacy_class.py | 12 +- src/sage/groups/raag.py | 24 +- .../semimonomial_transformation_group.py | 47 +- .../homology/algebraic_topological_model.py | 62 +- src/sage/homology/all.py | 1 + src/sage/homology/chain_complex.py | 172 +- src/sage/homology/chain_complex_homspace.py | 1 + src/sage/homology/chain_complex_morphism.py | 27 +- src/sage/homology/chain_homotopy.py | 47 +- src/sage/homology/chains.py | 56 +- src/sage/homology/free_resolution.py | 23 +- src/sage/homology/graded_resolution.py | 29 +- src/sage/homology/hochschild_complex.py | 46 +- src/sage/homology/homology_group.py | 8 +- src/sage/homology/homology_morphism.py | 25 +- .../homology_vector_space_with_basis.py | 65 +- src/sage/homology/koszul_complex.py | 16 +- src/sage/homology/matrix_utils.py | 21 +- src/sage/interacts/all.py | 1 + src/sage/interacts/library.py | 495 +- src/sage/interfaces/abc.py | 8 + src/sage/interfaces/all.py | 5 +- src/sage/interfaces/axiom.py | 66 +- src/sage/interfaces/ecm.py | 34 +- src/sage/interfaces/expect.py | 78 +- src/sage/interfaces/four_ti_2.py | 41 +- src/sage/interfaces/fricas.py | 118 +- src/sage/interfaces/fricas_translator.py | 92 +- src/sage/interfaces/frobby.py | 17 +- src/sage/interfaces/gap.py | 83 +- src/sage/interfaces/gap3.py | 40 +- src/sage/interfaces/gap_workspace.py | 2 +- src/sage/interfaces/genus2reduction.py | 7 +- src/sage/interfaces/gfan.py | 4 +- src/sage/interfaces/giac.py | 48 +- src/sage/interfaces/gnuplot.py | 38 +- src/sage/interfaces/gp.py | 51 +- src/sage/interfaces/interface.py | 34 +- src/sage/interfaces/jmoldata.py | 16 +- src/sage/interfaces/kash.py | 48 +- src/sage/interfaces/kenzo.py | 115 +- src/sage/interfaces/khoca.py | 9 +- src/sage/interfaces/latte.py | 20 +- src/sage/interfaces/lie.py | 70 +- src/sage/interfaces/lisp.py | 78 +- src/sage/interfaces/macaulay2.py | 93 +- src/sage/interfaces/magma.py | 79 +- src/sage/interfaces/magma_free.py | 4 +- src/sage/interfaces/maple.py | 110 +- src/sage/interfaces/mathematica.py | 91 +- src/sage/interfaces/mathics.py | 26 +- src/sage/interfaces/matlab.py | 46 +- src/sage/interfaces/maxima.py | 62 +- src/sage/interfaces/maxima_abstract.py | 121 +- src/sage/interfaces/maxima_lib.py | 130 +- src/sage/interfaces/mupad.py | 60 +- src/sage/interfaces/mwrank.py | 12 +- src/sage/interfaces/octave.py | 46 +- src/sage/interfaces/phc.py | 17 +- src/sage/interfaces/polymake.py | 62 +- src/sage/interfaces/povray.py | 1 + src/sage/interfaces/psage.py | 1 + src/sage/interfaces/qepcad.py | 93 +- src/sage/interfaces/quit.py | 1 + src/sage/interfaces/r.py | 31 +- src/sage/interfaces/read_data.py | 1 + src/sage/interfaces/regina.py | 21 +- src/sage/interfaces/rubik.py | 106 +- src/sage/interfaces/sage0.py | 54 +- src/sage/interfaces/scilab.py | 21 +- src/sage/interfaces/singular.py | 123 +- src/sage/interfaces/sympy.py | 109 +- src/sage/interfaces/sympy_wrapper.py | 1 + src/sage/interfaces/tab_completion.py | 6 +- src/sage/interfaces/tachyon.py | 6 +- src/sage/interfaces/tides.py | 117 +- src/sage/knots/free_knotinfo_monoid.py | 21 +- src/sage/knots/gauss_code.py | 4 +- src/sage/knots/knot.py | 13 +- src/sage/knots/knot_table.py | 499 +- src/sage/knots/knotinfo.py | 49 +- src/sage/knots/link.py | 160 +- src/sage/lfunctions/dokchitser.py | 40 +- src/sage/lfunctions/lcalc.py | 15 +- src/sage/lfunctions/pari.py | 38 +- src/sage/lfunctions/sympow.py | 11 +- src/sage/libs/all.py | 2 +- src/sage/libs/coxeter3/coxeter_group.py | 22 +- src/sage/libs/eclib/constructor.py | 1 + src/sage/libs/eclib/interface.py | 32 +- src/sage/libs/gap/all_documented_functions.py | 1 + src/sage/libs/gap/assigned_names.py | 6 +- src/sage/libs/gap/context_managers.py | 1 - src/sage/libs/gap/gap_functions.py | 2792 +-- src/sage/libs/gap/gap_globals.py | 32 +- src/sage/libs/gap/gap_test.py | 8 +- src/sage/libs/gap/operations.py | 4 +- src/sage/libs/lrcalc/lrcalc.py | 14 +- src/sage/libs/mpmath/all.py | 7 +- src/sage/libs/ntl/all.py | 23 +- src/sage/libs/singular/function_factory.py | 2 + src/sage/libs/singular/standard_options.py | 2 + src/sage/libs/symmetrica/all.py | 2 + src/sage/logic/booleval.py | 1 + src/sage/logic/boolformula.py | 152 +- src/sage/logic/logic.py | 15 +- src/sage/logic/logicparser.py | 7 +- src/sage/logic/logictable.py | 2 + src/sage/logic/propcalc.py | 1 + src/sage/manifolds/catalog.py | 34 +- src/sage/manifolds/chart.py | 182 +- src/sage/manifolds/chart_func.py | 36 +- src/sage/manifolds/continuous_map.py | 184 +- src/sage/manifolds/continuous_map_image.py | 4 +- .../differentiable/affine_connection.py | 195 +- .../differentiable/automorphismfield.py | 87 +- .../differentiable/automorphismfield_group.py | 26 +- .../differentiable/bundle_connection.py | 57 +- .../characteristic_cohomology_class.py | 86 +- src/sage/manifolds/differentiable/chart.py | 32 +- src/sage/manifolds/differentiable/curve.py | 68 +- .../differentiable/de_rham_cohomology.py | 6 +- .../manifolds/differentiable/degenerate.py | 57 +- .../differentiable/degenerate_submanifold.py | 169 +- .../manifolds/differentiable/diff_form.py | 95 +- .../differentiable/diff_form_module.py | 85 +- src/sage/manifolds/differentiable/diff_map.py | 146 +- .../differentiable_submanifold.py | 29 +- .../differentiable/examples/euclidean.py | 197 +- .../differentiable/examples/real_line.py | 72 +- .../differentiable/examples/sphere.py | 99 +- .../examples/symplectic_space.py | 12 +- .../differentiable/integrated_curve.py | 647 +- .../differentiable/levi_civita_connection.py | 134 +- src/sage/manifolds/differentiable/manifold.py | 219 +- .../differentiable/manifold_homset.py | 171 +- src/sage/manifolds/differentiable/metric.py | 232 +- .../manifolds/differentiable/mixed_form.py | 47 +- .../differentiable/mixed_form_algebra.py | 28 +- .../differentiable/multivector_module.py | 74 +- .../differentiable/multivectorfield.py | 145 +- .../differentiable/poisson_tensor.py | 16 +- .../differentiable/pseudo_riemannian.py | 45 +- .../pseudo_riemannian_submanifold.py | 226 +- .../manifolds/differentiable/scalarfield.py | 56 +- .../differentiable/scalarfield_algebra.py | 16 +- .../differentiable/symplectic_form.py | 88 +- .../differentiable/symplectic_form_test.py | 106 +- .../manifolds/differentiable/tangent_space.py | 18 +- .../differentiable/tangent_vector.py | 40 +- .../manifolds/differentiable/tensorfield.py | 303 +- .../differentiable/tensorfield_module.py | 168 +- .../differentiable/tensorfield_paral.py | 140 +- .../manifolds/differentiable/vector_bundle.py | 59 +- .../manifolds/differentiable/vectorfield.py | 143 +- .../differentiable/vectorfield_module.py | 286 +- .../manifolds/differentiable/vectorframe.py | 184 +- src/sage/manifolds/family.py | 13 +- src/sage/manifolds/local_frame.py | 176 +- src/sage/manifolds/manifold.py | 229 +- src/sage/manifolds/manifold_homset.py | 19 +- src/sage/manifolds/point.py | 56 +- src/sage/manifolds/scalarfield.py | 108 +- src/sage/manifolds/scalarfield_algebra.py | 39 +- src/sage/manifolds/section.py | 137 +- src/sage/manifolds/section_module.py | 80 +- src/sage/manifolds/structure.py | 12 +- src/sage/manifolds/subset.py | 85 +- src/sage/manifolds/subsets/closure.py | 4 +- src/sage/manifolds/subsets/pullback.py | 56 +- src/sage/manifolds/topological_submanifold.py | 90 +- src/sage/manifolds/trivialization.py | 35 +- src/sage/manifolds/utilities.py | 47 +- src/sage/manifolds/vector_bundle.py | 67 +- src/sage/manifolds/vector_bundle_fiber.py | 33 +- .../manifolds/vector_bundle_fiber_element.py | 11 +- src/sage/matrix/all.py | 6 +- src/sage/matrix/benchmark.py | 247 +- src/sage/matrix/berlekamp_massey.py | 3 +- src/sage/matrix/compute_J_ideal.py | 85 +- src/sage/matrix/matrix_integer_dense_hnf.py | 72 +- .../matrix/matrix_integer_dense_saturation.py | 9 +- src/sage/matrix/matrix_misc.py | 8 +- src/sage/matrix/matrix_space.py | 111 +- src/sage/matrix/operation_table.py | 68 +- src/sage/matrix/special.py | 157 +- src/sage/matrix/symplectic_basis.py | 78 +- src/sage/matroids/advanced.py | 1 + src/sage/matroids/all.py | 3 + src/sage/matroids/catalog.py | 139 +- src/sage/matroids/chow_ring.py | 23 +- src/sage/matroids/chow_ring_ideal.py | 55 +- src/sage/matroids/constructor.py | 29 +- src/sage/matroids/database_collections.py | 88 +- src/sage/matroids/database_matroids.py | 419 +- src/sage/matroids/dual_matroid.py | 4 +- src/sage/matroids/gammoid.py | 11 +- src/sage/matroids/matroids_plot_helpers.py | 184 +- src/sage/matroids/minor_matroid.py | 2 + src/sage/matroids/rank_matroid.py | 2 + src/sage/matroids/utilities.py | 21 +- src/sage/misc/abstract_method.py | 8 +- src/sage/misc/abstract_method.pyi | 25 +- src/sage/misc/all.py | 82 +- src/sage/misc/allocator.pyi | 7 +- src/sage/misc/banner.py | 13 +- src/sage/misc/benchmark.py | 10 +- src/sage/misc/binary_tree.pyi | 93 +- src/sage/misc/bindable_class.py | 5 + src/sage/misc/c3.pyi | 4 +- src/sage/misc/cachefunc.pyi | 140 +- src/sage/misc/call.py | 1 + src/sage/misc/callable_dict.pyi | 7 +- src/sage/misc/citation.pyi | 8 +- src/sage/misc/classgraph.py | 8 +- src/sage/misc/compat.py | 4 +- src/sage/misc/converting_dict.py | 1 + src/sage/misc/cython.py | 43 +- src/sage/misc/decorators.py | 59 +- src/sage/misc/defaults.py | 1 + src/sage/misc/dev_tools.py | 41 +- src/sage/misc/edit_module.py | 17 +- src/sage/misc/element_with_label.py | 4 +- src/sage/misc/explain_pickle.py | 41 +- src/sage/misc/flatten.py | 4 +- src/sage/misc/func_persist.py | 7 +- src/sage/misc/functional.py | 16 + src/sage/misc/gperftools.py | 19 +- src/sage/misc/html.py | 35 +- src/sage/misc/inline_fortran.py | 4 +- src/sage/misc/latex.py | 200 +- src/sage/misc/latex_macros.py | 49 +- src/sage/misc/latex_standalone.py | 176 +- src/sage/misc/lazy_attribute.pyi | 5 +- src/sage/misc/lazy_format.py | 5 +- src/sage/misc/lazy_import_cache.py | 4 +- src/sage/misc/map_threaded.py | 3 +- src/sage/misc/mathml.py | 9 +- src/sage/misc/messaging.py | 7 +- src/sage/misc/method_decorator.py | 2 + src/sage/misc/misc.py | 13 +- src/sage/misc/mrange.py | 19 +- src/sage/misc/multireplace.py | 3 +- src/sage/misc/namespace_package.py | 3 +- src/sage/misc/object_multiplexer.py | 6 +- src/sage/misc/package.py | 19 +- src/sage/misc/package_dir.py | 17 +- src/sage/misc/pager.py | 2 + src/sage/misc/profiler.py | 17 +- src/sage/misc/random_testing.py | 3 + src/sage/misc/remote_file.py | 1 + src/sage/misc/repr.py | 8 +- src/sage/misc/rest_index_of_methods.py | 48 +- src/sage/misc/sage_eval.py | 2 + src/sage/misc/sage_input.py | 42 +- src/sage/misc/sage_timeit.py | 6 +- src/sage/misc/sage_unittest.py | 10 +- src/sage/misc/sagedoc.py | 161 +- src/sage/misc/sagedoc_conf.py | 4 + src/sage/misc/sageinspect.py | 135 +- src/sage/misc/sh.py | 1 + src/sage/misc/sphinxify.py | 32 +- src/sage/misc/superseded.py | 23 +- src/sage/misc/table.py | 39 +- src/sage/misc/temporary_file.py | 18 +- src/sage/misc/test_class_pickling.py | 2 +- src/sage/misc/test_nested_class.py | 13 + src/sage/misc/timing.py | 4 +- src/sage/misc/trace.py | 2 + src/sage/misc/unknown.py | 3 + src/sage/misc/verbose.py | 5 +- src/sage/misc/viewer.py | 1 + src/sage/modular/abvar/abvar.py | 142 +- .../modular/abvar/abvar_ambient_jacobian.py | 20 +- src/sage/modular/abvar/abvar_newform.py | 14 +- src/sage/modular/abvar/constructor.py | 5 + src/sage/modular/abvar/cuspidal_subgroup.py | 3 + src/sage/modular/abvar/finite_subgroup.py | 16 +- src/sage/modular/abvar/homology.py | 19 +- src/sage/modular/abvar/homspace.py | 38 +- src/sage/modular/abvar/lseries.py | 25 +- src/sage/modular/abvar/morphism.py | 9 +- src/sage/modular/abvar/torsion_point.py | 2 + src/sage/modular/abvar/torsion_subgroup.py | 45 +- src/sage/modular/all.py | 11 +- src/sage/modular/arithgroup/all.py | 6 +- .../modular/arithgroup/arithgroup_generic.py | 66 +- .../modular/arithgroup/arithgroup_perm.py | 400 +- src/sage/modular/arithgroup/congroup_gamma.py | 51 +- .../modular/arithgroup/congroup_gamma0.py | 51 +- .../modular/arithgroup/congroup_gamma1.py | 41 +- .../modular/arithgroup/congroup_gammaH.py | 29 +- .../modular/arithgroup/congroup_generic.py | 21 +- src/sage/modular/arithgroup/congroup_sl2z.py | 36 +- src/sage/modular/arithgroup/tests.py | 15 +- src/sage/modular/btquotients/all.py | 1 + src/sage/modular/btquotients/btquotient.py | 194 +- .../modular/btquotients/pautomorphicform.py | 152 +- src/sage/modular/buzzard.py | 2 +- src/sage/modular/cusps.py | 30 +- src/sage/modular/cusps_nf.py | 68 +- src/sage/modular/dims.py | 27 +- src/sage/modular/dirichlet.py | 92 +- src/sage/modular/drinfeld_modform/element.py | 10 +- src/sage/modular/drinfeld_modform/ring.py | 49 +- src/sage/modular/etaproducts.py | 52 +- src/sage/modular/hecke/algebra.py | 17 +- src/sage/modular/hecke/all.py | 3 +- src/sage/modular/hecke/ambient_module.py | 16 +- src/sage/modular/hecke/degenmap.py | 1 + src/sage/modular/hecke/element.py | 1 + src/sage/modular/hecke/hecke_operator.py | 11 +- src/sage/modular/hecke/homspace.py | 1 + src/sage/modular/hecke/module.py | 38 +- src/sage/modular/hecke/morphism.py | 3 + src/sage/modular/hecke/submodule.py | 27 +- src/sage/modular/hypergeometric_motive.py | 140 +- src/sage/modular/local_comp/liftings.py | 7 +- src/sage/modular/local_comp/local_comp.py | 41 +- src/sage/modular/local_comp/smoothchar.py | 94 +- src/sage/modular/local_comp/type_space.py | 41 +- src/sage/modular/modform/all.py | 1 + src/sage/modular/modform/ambient.py | 30 +- src/sage/modular/modform/ambient_R.py | 3 +- src/sage/modular/modform/ambient_eps.py | 16 +- src/sage/modular/modform/ambient_g0.py | 3 + src/sage/modular/modform/ambient_g1.py | 5 +- src/sage/modular/modform/constructor.py | 42 +- .../modular/modform/cuspidal_submodule.py | 36 +- src/sage/modular/modform/defaults.py | 1 + src/sage/modular/modform/eis_series.py | 28 +- .../modular/modform/eisenstein_submodule.py | 31 +- src/sage/modular/modform/element.py | 142 +- src/sage/modular/modform/half_integral.py | 14 +- .../modular/modform/hecke_operator_on_qexp.py | 18 +- src/sage/modular/modform/j_invariant.py | 4 +- .../modular/modform/l_series_gross_zagier.py | 10 +- src/sage/modular/modform/numerical.py | 23 +- src/sage/modular/modform/ring.py | 41 +- src/sage/modular/modform/space.py | 130 +- src/sage/modular/modform/submodule.py | 10 +- src/sage/modular/modform/theta.py | 9 +- src/sage/modular/modform/vm_basis.py | 35 +- src/sage/modular/modform/weight1.py | 2 + .../modform_hecketriangle/abstract_ring.py | 86 +- .../modform_hecketriangle/abstract_space.py | 289 +- src/sage/modular/modform_hecketriangle/all.py | 12 +- .../modform_hecketriangle/analytic_type.py | 13 +- .../modform_hecketriangle/constructor.py | 55 +- .../modular/modform_hecketriangle/element.py | 21 +- .../modular/modform_hecketriangle/functors.py | 37 +- .../graded_ring_element.py | 90 +- .../hecke_triangle_group_element.py | 128 +- .../hecke_triangle_groups.py | 53 +- .../series_constructor.py | 84 +- .../modular/modform_hecketriangle/space.py | 16 +- .../modular/modform_hecketriangle/subspace.py | 2 +- src/sage/modular/modsym/all.py | 1 + src/sage/modular/modsym/ambient.py | 351 +- src/sage/modular/modsym/boundary.py | 85 +- src/sage/modular/modsym/element.py | 21 +- src/sage/modular/modsym/g1list.py | 8 +- src/sage/modular/modsym/ghlist.py | 8 +- src/sage/modular/modsym/manin_symbol_list.py | 105 +- src/sage/modular/modsym/modsym.py | 23 +- src/sage/modular/modsym/modular_symbols.py | 32 +- src/sage/modular/modsym/p1list_nf.py | 64 +- src/sage/modular/modsym/relation_matrix.py | 9 +- src/sage/modular/modsym/space.py | 73 +- src/sage/modular/modsym/subspace.py | 14 +- src/sage/modular/modsym/tests.py | 14 +- src/sage/modular/multiple_zeta.py | 90 +- src/sage/modular/multiple_zeta_F_algebra.py | 34 +- src/sage/modular/overconvergent/genus0.py | 52 +- .../modular/overconvergent/hecke_series.py | 81 +- .../modular/overconvergent/weightspace.py | 18 +- .../modular/pollack_stevens/distributions.py | 52 +- .../modular/pollack_stevens/fund_domain.py | 23 +- src/sage/modular/pollack_stevens/manin_map.py | 10 +- src/sage/modular/pollack_stevens/modsym.py | 53 +- .../modular/pollack_stevens/padic_lseries.py | 20 +- src/sage/modular/pollack_stevens/sigma0.py | 13 +- src/sage/modular/pollack_stevens/space.py | 45 +- src/sage/modular/quasimodform/element.py | 27 +- src/sage/modular/quasimodform/ring.py | 13 +- src/sage/modular/quatalg/all.py | 1 - src/sage/modular/quatalg/brandt.py | 35 +- src/sage/modular/ssmod/all.py | 5 +- src/sage/modular/ssmod/ssmod.py | 34 +- src/sage/modules/diamond_cutting.py | 16 +- src/sage/modules/fg_pid/fgp_element.py | 4 +- src/sage/modules/fg_pid/fgp_module.py | 33 +- src/sage/modules/fg_pid/fgp_morphism.py | 16 +- src/sage/modules/filtered_vector_space.py | 24 +- src/sage/modules/fp_graded/free_element.py | 3 +- src/sage/modules/fp_graded/free_homspace.py | 1 + src/sage/modules/fp_graded/free_module.py | 48 +- src/sage/modules/fp_graded/free_morphism.py | 4 +- src/sage/modules/fp_graded/homspace.py | 7 +- src/sage/modules/fp_graded/module.py | 40 +- src/sage/modules/fp_graded/morphism.py | 80 +- src/sage/modules/fp_graded/steenrod/module.py | 41 +- .../modules/fp_graded/steenrod/morphism.py | 24 +- src/sage/modules/free_module.py | 315 +- src/sage/modules/free_module_homspace.py | 5 +- src/sage/modules/free_module_integer.py | 48 +- src/sage/modules/free_module_morphism.py | 11 +- .../modules/free_module_pseudohomspace.py | 2 + .../modules/free_module_pseudomorphism.py | 11 +- src/sage/modules/free_quadratic_module.py | 234 +- ...free_quadratic_module_integer_symmetric.py | 155 +- src/sage/modules/matrix_morphism.py | 9 +- src/sage/modules/misc.py | 1 + src/sage/modules/module_functors.py | 1 + .../modules/multi_filtered_vector_space.py | 29 +- src/sage/modules/ore_module.py | 62 +- src/sage/modules/ore_module_element.py | 3 +- src/sage/modules/ore_module_homspace.py | 1 + src/sage/modules/ore_module_morphism.py | 14 +- src/sage/modules/quotient_module.py | 20 +- src/sage/modules/real_double_vector.py | 1 + src/sage/modules/submodule.py | 27 +- src/sage/modules/submodule_helper.py | 26 +- src/sage/modules/tensor_operations.py | 10 +- src/sage/modules/torsion_quadratic_module.py | 74 +- .../modules/vector_callable_symbolic_dense.py | 1 + src/sage/modules/vector_space_homspace.py | 2 + src/sage/modules/vector_space_morphism.py | 11 +- src/sage/modules/vector_symbolic_dense.py | 7 +- src/sage/modules/vector_symbolic_sparse.py | 7 +- src/sage/modules/with_basis/all.py | 2 + src/sage/modules/with_basis/cell_module.py | 26 +- src/sage/modules/with_basis/invariant.py | 47 +- src/sage/modules/with_basis/morphism.py | 140 +- src/sage/modules/with_basis/representation.py | 180 +- src/sage/modules/with_basis/subquotient.py | 32 +- src/sage/monoids/all.py | 10 +- src/sage/monoids/automatic_semigroup.py | 7 +- src/sage/monoids/free_abelian_monoid.py | 6 + src/sage/monoids/free_monoid.py | 15 +- src/sage/monoids/free_monoid_element.py | 18 +- src/sage/monoids/indexed_free_monoid.py | 40 +- src/sage/monoids/monoid.py | 2 + src/sage/monoids/string_monoid.py | 39 +- src/sage/monoids/string_monoid_element.py | 34 +- src/sage/monoids/string_ops.py | 13 +- src/sage/monoids/trace_monoid.py | 44 +- src/sage/numerical/all.py | 8 +- .../numerical/backends/cvxopt_backend_test.py | 3 +- .../backends/generic_backend_test.py | 1 + .../numerical/backends/logging_backend.py | 29 +- .../numerical/interactive_simplex_method.py | 384 +- src/sage/numerical/knapsack.py | 8 +- src/sage/numerical/linear_tensor.py | 5 + .../numerical/linear_tensor_constraints.py | 15 +- src/sage/numerical/optimize.py | 77 +- src/sage/parallel/all.py | 2 +- src/sage/parallel/decorate.py | 15 +- src/sage/parallel/map_reduce.py | 68 +- src/sage/parallel/multiprocessing_sage.py | 3 +- src/sage/parallel/parallelism.py | 7 +- src/sage/parallel/use_fork.py | 10 +- src/sage/plot/all.py | 7 +- src/sage/plot/animate.py | 120 +- src/sage/plot/arc.py | 53 +- src/sage/plot/arrow.py | 65 +- src/sage/plot/bar_chart.py | 14 +- src/sage/plot/bezier_path.py | 33 +- src/sage/plot/circle.py | 47 +- src/sage/plot/colors.py | 314 +- src/sage/plot/contour_plot.py | 179 +- src/sage/plot/density_plot.py | 24 +- src/sage/plot/disk.py | 39 +- src/sage/plot/ellipse.py | 49 +- src/sage/plot/graphics.py | 294 +- src/sage/plot/histogram.py | 48 +- src/sage/plot/hyperbolic_arc.py | 26 +- src/sage/plot/hyperbolic_polygon.py | 19 +- src/sage/plot/hyperbolic_regular_polygon.py | 29 +- src/sage/plot/line.py | 33 +- src/sage/plot/matrix_plot.py | 77 +- src/sage/plot/misc.py | 61 +- src/sage/plot/multigraphics.py | 65 +- src/sage/plot/plot.py | 156 +- src/sage/plot/plot3d/all.py | 2 +- src/sage/plot/plot3d/list_plot3d.py | 38 +- src/sage/plot/plot3d/parametric_plot3d.py | 11 +- src/sage/plot/plot3d/platonic.py | 41 +- src/sage/plot/plot3d/plot3d.py | 65 +- src/sage/plot/plot3d/plot_field3d.py | 12 +- src/sage/plot/plot3d/revolution_plot3d.py | 15 +- src/sage/plot/plot3d/shapes2.py | 112 +- src/sage/plot/plot3d/tachyon.py | 176 +- src/sage/plot/plot3d/texture.py | 37 +- src/sage/plot/plot3d/tri_plot.py | 99 +- src/sage/plot/plot_field.py | 34 +- src/sage/plot/point.py | 33 +- src/sage/plot/polygon.py | 29 +- src/sage/plot/primitive.py | 14 +- src/sage/plot/scatter_plot.py | 22 +- src/sage/plot/step.py | 6 +- src/sage/plot/streamline_plot.py | 31 +- src/sage/plot/text.py | 48 +- src/sage/probability/all.py | 10 +- src/sage/probability/random_variable.py | 25 +- src/sage/quadratic_forms/all.py | 10 +- src/sage/quadratic_forms/binary_qf.py | 95 +- src/sage/quadratic_forms/bqf_class_group.py | 6 +- src/sage/quadratic_forms/constructions.py | 5 +- src/sage/quadratic_forms/extras.py | 5 +- src/sage/quadratic_forms/genera/genus.py | 190 +- .../quadratic_forms/genera/normal_form.py | 65 +- .../quadratic_forms/genera/spinor_genus.py | 13 +- src/sage/quadratic_forms/qfsolve.py | 10 +- src/sage/quadratic_forms/quadratic_form.py | 124 +- .../quadratic_form__automorphisms.py | 10 +- .../quadratic_form__count_local_2.py | 2 + .../quadratic_form__equivalence_testing.py | 51 +- .../quadratic_forms/quadratic_form__genus.py | 3 +- ...uadratic_form__local_density_congruence.py | 68 +- ...uadratic_form__local_density_interfaces.py | 11 +- .../quadratic_form__local_field_invariants.py | 24 +- .../quadratic_form__local_normal_form.py | 15 +- ...c_form__local_representation_conditions.py | 29 +- .../quadratic_forms/quadratic_form__mass.py | 24 +- ...dratic_form__mass__Conway_Sloane_masses.py | 56 +- .../quadratic_form__mass__Siegel_densities.py | 80 +- .../quadratic_form__neighbors.py | 28 +- .../quadratic_form__reduction_theory.py | 14 +- .../quadratic_form__siegel_product.py | 28 +- .../quadratic_form__split_local_covering.py | 13 +- .../quadratic_form__ternary_Tornaria.py | 32 +- .../quadratic_forms/quadratic_form__theta.py | 26 +- .../quadratic_form__variable_substitutions.py | 14 +- .../quadratic_forms/random_quadraticform.py | 8 +- src/sage/quadratic_forms/special_values.py | 21 +- src/sage/quadratic_forms/ternary_qf.py | 395 +- src/sage/quivers/algebra.py | 32 +- src/sage/quivers/ar_quiver.py | 36 +- src/sage/quivers/homspace.py | 25 +- src/sage/quivers/morphism.py | 26 +- src/sage/quivers/path_semigroup.py | 19 +- src/sage/quivers/representation.py | 59 +- src/sage/repl/__init__.py | 2 + src/sage/repl/all.py | 5 +- src/sage/repl/configuration.py | 13 +- src/sage/repl/display/fancy_repr.py | 9 +- src/sage/repl/display/formatter.py | 13 +- src/sage/repl/display/jsmol_iframe.py | 18 +- src/sage/repl/display/pretty_print.py | 9 +- src/sage/repl/image.py | 3 + src/sage/repl/inputhook.py | 4 +- src/sage/repl/interface_magic.py | 16 +- src/sage/repl/interpreter.py | 44 +- src/sage/repl/ipython_extension.py | 16 +- src/sage/repl/ipython_kernel/__main__.py | 1 + src/sage/repl/ipython_kernel/all_jupyter.py | 3 +- src/sage/repl/ipython_kernel/install.py | 36 +- src/sage/repl/ipython_kernel/interact.py | 10 +- src/sage/repl/ipython_kernel/kernel.py | 12 +- src/sage/repl/ipython_kernel/widgets.py | 19 +- .../repl/ipython_kernel/widgets_sagenb.py | 14 +- src/sage/repl/load.py | 12 +- src/sage/repl/preparse.py | 72 +- src/sage/repl/rich_output/__init__.py | 1 - src/sage/repl/rich_output/backend_base.py | 16 +- src/sage/repl/rich_output/backend_doctest.py | 39 +- src/sage/repl/rich_output/backend_emacs.py | 16 +- src/sage/repl/rich_output/backend_ipython.py | 159 +- src/sage/repl/rich_output/buffer.py | 5 + src/sage/repl/rich_output/display_manager.py | 48 +- src/sage/repl/rich_output/output_basic.py | 14 +- src/sage/repl/rich_output/output_browser.py | 3 +- .../repl/rich_output/output_graphics3d.py | 9 +- src/sage/repl/rich_output/output_video.py | 17 +- src/sage/repl/rich_output/preferences.py | 17 +- src/sage/repl/rich_output/pretty_print.py | 2 + src/sage/repl/user_globals.py | 6 +- src/sage/rings/abc.pyi | 25 +- .../rings/algebraic_closure_finite_field.py | 42 +- src/sage/rings/all.py | 39 +- src/sage/rings/asymptotic/all.py | 4 +- .../asymptotic_expansion_generators.py | 148 +- src/sage/rings/asymptotic/asymptotic_ring.py | 432 +- ...otics_multivariate_generating_functions.py | 343 +- src/sage/rings/asymptotic/growth_group.py | 359 +- .../asymptotic/growth_group_cartesian.py | 173 +- src/sage/rings/asymptotic/misc.py | 80 +- src/sage/rings/asymptotic/term_monoid.py | 305 +- src/sage/rings/bernmm.pyi | 7 +- src/sage/rings/bernoulli_mod_p.pyi | 12 +- src/sage/rings/big_oh.py | 16 +- src/sage/rings/cfinite_sequence.py | 27 +- src/sage/rings/complex_arb.pyi | 34 +- src/sage/rings/complex_double.pyi | 18 +- src/sage/rings/complex_interval.pyi | 7 +- src/sage/rings/complex_interval_field.py | 4 +- src/sage/rings/complex_mpc.pyi | 18 +- src/sage/rings/complex_mpfr.pyi | 19 +- src/sage/rings/continued_fraction.py | 102 +- src/sage/rings/continued_fraction_gosper.py | 5 +- src/sage/rings/derivation.py | 88 +- src/sage/rings/factorint.pyi | 16 +- src/sage/rings/factorint_flint.pyi | 4 +- src/sage/rings/factorint_pari.pyi | 3 +- src/sage/rings/fast_arith.pyi | 82 +- src/sage/rings/finite_rings/all.py | 1 + .../rings/finite_rings/conway_polynomials.py | 72 +- .../finite_rings/finite_field_constructor.py | 19 +- .../rings/finite_rings/finite_field_givaro.py | 12 +- .../finite_rings/finite_field_ntl_gf2e.py | 7 +- .../finite_rings/finite_field_pari_ffelt.py | 7 +- .../finite_rings/finite_field_prime_modn.py | 16 +- src/sage/rings/finite_rings/galois_group.py | 1 + src/sage/rings/finite_rings/homset.py | 23 +- .../rings/finite_rings/integer_mod_ring.py | 58 +- .../rings/finite_rings/maps_finite_field.py | 19 +- src/sage/rings/fraction_field.py | 58 +- src/sage/rings/fraction_field_FpT.pyi | 238 +- src/sage/rings/fraction_field_element.pyi | 174 +- src/sage/rings/function_field/constructor.py | 8 +- src/sage/rings/function_field/derivations.py | 1 + .../function_field/derivations_polymod.py | 32 +- .../function_field/derivations_rational.py | 1 + src/sage/rings/function_field/differential.py | 9 +- src/sage/rings/function_field/divisor.py | 7 +- .../function_field/drinfeld_modules/action.py | 7 +- .../drinfeld_modules/carlitz_module.py | 11 +- .../charzero_drinfeld_module.py | 10 +- .../drinfeld_modules/drinfeld_module.py | 93 +- .../finite_drinfeld_module.py | 40 +- .../function_field/drinfeld_modules/homset.py | 27 +- .../drinfeld_modules/morphism.py | 19 +- src/sage/rings/function_field/element.pyi | 95 +- .../rings/function_field/element_polymod.pyi | 59 +- .../rings/function_field/element_rational.pyi | 83 +- src/sage/rings/function_field/extensions.py | 2 + .../rings/function_field/function_field.py | 36 +- .../function_field/function_field_polymod.py | 69 +- .../function_field/function_field_rational.py | 26 +- .../function_field/function_field_test.py | 9 +- .../hermite_form_polynomial.pyi | 3 +- src/sage/rings/function_field/ideal.py | 18 +- .../rings/function_field/ideal_polymod.py | 21 +- .../rings/function_field/ideal_rational.py | 2 + .../rings/function_field/jacobian_base.py | 12 +- .../rings/function_field/jacobian_hess.py | 13 +- .../function_field/jacobian_khuri_makdisi.py | 12 +- .../function_field/jacobian_unique_hess.py | 6 +- src/sage/rings/function_field/maps.py | 37 +- src/sage/rings/function_field/order.py | 5 + src/sage/rings/function_field/order_basis.py | 3 + .../rings/function_field/order_polymod.py | 29 +- .../rings/function_field/order_rational.py | 16 +- src/sage/rings/function_field/place.py | 4 + .../rings/function_field/place_polymod.py | 8 +- .../rings/function_field/place_rational.py | 2 + src/sage/rings/function_field/valuation.py | 40 +- .../rings/function_field/valuation_ring.py | 1 + src/sage/rings/generic.py | 10 +- src/sage/rings/homset.py | 8 +- src/sage/rings/ideal.py | 44 +- src/sage/rings/ideal_monoid.py | 3 +- src/sage/rings/imaginary_unit.py | 1 - src/sage/rings/infinity.py | 15 +- src/sage/rings/integer.pyi | 76 +- src/sage/rings/integer_fake.pyi | 7 +- src/sage/rings/integer_ring.pyi | 169 +- src/sage/rings/invariants/all.py | 1 + src/sage/rings/invariants/invariant_theory.py | 818 +- src/sage/rings/invariants/reconstruction.py | 89 +- src/sage/rings/khuri_makdisi.pyi | 87 +- src/sage/rings/laurent_series_ring.py | 52 +- .../rings/laurent_series_ring_element.pyi | 9 +- src/sage/rings/lazy_series.py | 773 +- src/sage/rings/lazy_series_ring.py | 242 +- src/sage/rings/lazy_species.py | 289 +- src/sage/rings/localization.py | 10 +- src/sage/rings/monomials.py | 10 +- src/sage/rings/multi_power_series_ring.py | 40 +- .../rings/multi_power_series_ring_element.py | 78 +- src/sage/rings/number_field/S_unit_solver.py | 221 +- src/sage/rings/number_field/all.py | 11 +- src/sage/rings/number_field/bdd_height.py | 51 +- src/sage/rings/number_field/class_group.py | 10 +- src/sage/rings/number_field/galois_group.py | 10 +- src/sage/rings/number_field/homset.py | 39 +- src/sage/rings/number_field/maps.py | 10 +- src/sage/rings/number_field/morphism.py | 24 +- src/sage/rings/number_field/number_field.py | 357 +- .../rings/number_field/number_field_base.pyi | 54 +- .../rings/number_field/number_field_ideal.py | 118 +- .../number_field/number_field_ideal_rel.py | 7 +- .../rings/number_field/number_field_rel.py | 55 +- src/sage/rings/number_field/order.py | 63 +- src/sage/rings/number_field/order_ideal.py | 49 +- src/sage/rings/number_field/selmer_group.py | 59 +- .../small_primes_of_degree_one.py | 12 +- .../rings/number_field/splitting_field.py | 38 +- src/sage/rings/number_field/structure.py | 15 +- .../rings/number_field/totallyreal_phc.py | 16 +- .../rings/number_field/totallyreal_rel.py | 279 +- src/sage/rings/number_field/unit_group.py | 34 +- src/sage/rings/numbers_abc.py | 4 +- .../padics/eisenstein_extension_generic.py | 15 +- src/sage/rings/padics/factory.py | 193 +- src/sage/rings/padics/generic_nodes.py | 68 +- src/sage/rings/padics/lattice_precision.py | 165 +- src/sage/rings/padics/local_generic.py | 160 +- src/sage/rings/padics/misc.py | 19 +- src/sage/rings/padics/padic_base_generic.py | 31 +- src/sage/rings/padics/padic_base_leaves.py | 57 +- .../rings/padics/padic_extension_generic.py | 64 +- .../rings/padics/padic_extension_leaves.py | 86 +- src/sage/rings/padics/padic_generic.py | 180 +- .../rings/padics/padic_lattice_element.py | 41 +- .../padics/padic_lattice_element_test.py | 8 +- src/sage/rings/padics/padic_valuation.py | 61 +- src/sage/rings/padics/precision_error.py | 4 +- .../rings/padics/relative_extension_leaves.py | 24 +- .../padics/unramified_extension_generic.py | 31 +- src/sage/rings/padics/witt_vector.py | 83 +- src/sage/rings/padics/witt_vector_ring.py | 188 +- src/sage/rings/pari_ring.py | 6 +- src/sage/rings/polynomial/all.py | 8 +- .../rings/polynomial/binary_form_reduce.py | 65 +- src/sage/rings/polynomial/complex_roots.py | 12 +- src/sage/rings/polynomial/convolution.py | 37 +- src/sage/rings/polynomial/flatten.py | 16 +- src/sage/rings/polynomial/groebner_fan.py | 72 +- src/sage/rings/polynomial/ideal.py | 7 +- .../polynomial/infinite_polynomial_element.py | 85 +- .../polynomial/infinite_polynomial_ring.py | 41 +- .../polynomial/integer_valued_polynomials.py | 61 +- .../polynomial/laurent_polynomial_ideal.py | 21 +- .../polynomial/laurent_polynomial_ring.py | 18 +- .../laurent_polynomial_ring_base.py | 15 +- src/sage/rings/polynomial/msolve.py | 36 +- .../polynomial/multi_polynomial_element.py | 93 +- .../polynomial/multi_polynomial_ideal.py | 305 +- .../rings/polynomial/multi_polynomial_ring.py | 58 +- .../polynomial/multi_polynomial_sequence.py | 88 +- src/sage/rings/polynomial/omega.py | 87 +- .../rings/polynomial/ore_function_element.py | 18 +- .../rings/polynomial/ore_function_field.py | 12 +- .../rings/polynomial/ore_polynomial_ring.py | 24 +- .../polynomial/padics/polynomial_padic.py | 15 +- .../polynomial_padic_capped_relative_dense.py | 145 +- .../padics/polynomial_padic_flat.py | 3 +- src/sage/rings/polynomial/pbori/__init__.py | 1 + src/sage/rings/polynomial/pbori/blocks.py | 83 +- src/sage/rings/polynomial/pbori/cnf.py | 19 +- src/sage/rings/polynomial/pbori/fglm.py | 6 +- src/sage/rings/polynomial/pbori/frontend.py | 10 +- src/sage/rings/polynomial/pbori/gbcore.py | 144 +- .../rings/polynomial/pbori/interpolate.py | 20 +- src/sage/rings/polynomial/pbori/ll.py | 37 +- src/sage/rings/polynomial/pbori/nf.py | 93 +- src/sage/rings/polynomial/pbori/parallel.py | 16 +- src/sage/rings/polynomial/pbori/randompoly.py | 19 +- src/sage/rings/polynomial/pbori/rank.py | 1 + .../rings/polynomial/pbori/specialsets.py | 18 +- .../polynomial/polynomial_element_generic.py | 124 +- .../polynomial/polynomial_quotient_ring.py | 101 +- .../polynomial_quotient_ring_element.py | 79 +- src/sage/rings/polynomial/polynomial_ring.py | 296 +- .../polynomial/polynomial_ring_constructor.py | 15 +- .../polynomial_singular_interface.py | 34 +- .../q_integer_valued_polynomials.py | 81 +- .../rings/polynomial/skew_polynomial_ring.py | 21 +- src/sage/rings/polynomial/symmetric_ideal.py | 44 +- src/sage/rings/polynomial/term_order.py | 151 +- src/sage/rings/polynomial/toy_buchberger.py | 21 +- src/sage/rings/polynomial/toy_d_basis.py | 20 +- src/sage/rings/polynomial/toy_variety.py | 2 + src/sage/rings/polynomial/weil/all.py | 1 + src/sage/rings/power_series_ring.py | 69 +- src/sage/rings/puiseux_series_ring.py | 15 +- src/sage/rings/qqbar.py | 154 +- src/sage/rings/qqbar_decorators.py | 14 +- src/sage/rings/quotient_ring.py | 28 +- src/sage/rings/quotient_ring_element.py | 11 +- src/sage/rings/rational_field.py | 86 +- src/sage/rings/real_field.py | 5 + src/sage/rings/ring.pyi | 8 +- src/sage/rings/ring_extension_homset.py | 3 +- .../non_negative_integer_semiring.py | 5 +- src/sage/rings/semirings/tropical_matrix.py | 14 +- .../rings/semirings/tropical_mpolynomial.py | 37 +- .../rings/semirings/tropical_polynomial.py | 65 +- src/sage/rings/semirings/tropical_variety.py | 52 +- src/sage/rings/species.py | 232 +- src/sage/rings/tate_algebra.py | 37 +- src/sage/rings/tests.py | 50 +- src/sage/rings/universal_cyclotomic_field.py | 48 +- .../rings/valuation/augmented_valuation.py | 75 +- .../rings/valuation/developing_valuation.py | 11 +- src/sage/rings/valuation/gauss_valuation.py | 18 +- .../rings/valuation/inductive_valuation.py | 82 +- src/sage/rings/valuation/limit_valuation.py | 32 +- src/sage/rings/valuation/mapped_valuation.py | 18 +- .../rings/valuation/mapped_valuation_test.py | 6 +- src/sage/rings/valuation/scaled_valuation.py | 5 + src/sage/rings/valuation/trivial_valuation.py | 12 +- src/sage/rings/valuation/valuation.py | 77 +- src/sage/rings/valuation/valuation_space.py | 91 +- src/sage/rings/valuation/value_group.py | 32 +- src/sage/sandpiles/examples.py | 14 +- src/sage/sandpiles/sandpile.py | 288 +- src/sage/sat/all.py | 1 + src/sage/sat/boolean_polynomials.py | 12 +- src/sage/sat/converters/polybori.py | 14 +- src/sage/sat/solvers/cryptominisat.py | 8 +- src/sage/sat/solvers/dimacs.py | 4 + src/sage/sat/solvers/picosat.py | 5 +- src/sage/sat/solvers/sat_lp.py | 3 +- src/sage/schemes/affine/affine_homset.py | 25 +- src/sage/schemes/affine/affine_morphism.py | 30 +- src/sage/schemes/affine/affine_point.py | 7 + .../schemes/affine/affine_rational_point.py | 3 + src/sage/schemes/affine/affine_space.py | 47 +- src/sage/schemes/affine/affine_subscheme.py | 16 +- .../schemes/berkovich/berkovich_cp_element.py | 124 +- src/sage/schemes/berkovich/berkovich_space.py | 31 +- src/sage/schemes/curves/affine_curve.py | 113 +- src/sage/schemes/curves/closed_point.py | 4 + src/sage/schemes/curves/constructor.py | 25 +- src/sage/schemes/curves/curve.py | 11 +- .../schemes/curves/plane_curve_arrangement.py | 53 +- src/sage/schemes/curves/point.py | 24 +- src/sage/schemes/curves/projective_curve.py | 137 +- .../curves/weighted_projective_curve.py | 13 +- src/sage/schemes/curves/zariski_vankampen.py | 146 +- .../cyclic_covers/charpoly_frobenius.py | 31 +- src/sage/schemes/cyclic_covers/constructor.py | 14 +- .../cyclic_covers/cycliccover_finite_field.py | 130 +- .../cyclic_covers/cycliccover_generic.py | 6 +- src/sage/schemes/elliptic_curves/BSD.py | 29 +- src/sage/schemes/elliptic_curves/Qcurves.py | 7 +- .../elliptic_curves/addition_formulas_ring.py | 44 +- src/sage/schemes/elliptic_curves/all.py | 16 +- .../schemes/elliptic_curves/cardinality.py | 49 +- src/sage/schemes/elliptic_curves/cm.py | 368 +- .../schemes/elliptic_curves/constructor.py | 49 +- .../schemes/elliptic_curves/ec_database.py | 1 + .../elliptic_curves/ell_curve_isogeny.py | 225 +- src/sage/schemes/elliptic_curves/ell_egros.py | 8 +- src/sage/schemes/elliptic_curves/ell_field.py | 83 +- .../elliptic_curves/ell_finite_field.py | 184 +- .../schemes/elliptic_curves/ell_generic.py | 286 +- .../schemes/elliptic_curves/ell_local_data.py | 146 +- .../elliptic_curves/ell_modular_symbols.py | 84 +- .../elliptic_curves/ell_number_field.py | 129 +- .../elliptic_curves/ell_padic_field.py | 89 +- src/sage/schemes/elliptic_curves/ell_point.py | 342 +- .../elliptic_curves/ell_rational_field.py | 601 +- .../schemes/elliptic_curves/ell_tate_curve.py | 67 +- .../schemes/elliptic_curves/ell_torsion.py | 17 +- src/sage/schemes/elliptic_curves/ell_wp.py | 50 +- .../schemes/elliptic_curves/formal_group.py | 77 +- src/sage/schemes/elliptic_curves/gal_reps.py | 133 +- .../elliptic_curves/gal_reps_number_field.py | 109 +- src/sage/schemes/elliptic_curves/gp_simon.py | 6 +- src/sage/schemes/elliptic_curves/heegner.py | 461 +- src/sage/schemes/elliptic_curves/height.py | 166 +- src/sage/schemes/elliptic_curves/hom.py | 65 +- .../schemes/elliptic_curves/hom_composite.py | 27 +- .../schemes/elliptic_curves/hom_fractional.py | 27 +- .../schemes/elliptic_curves/hom_frobenius.py | 14 +- .../schemes/elliptic_curves/hom_scalar.py | 7 +- src/sage/schemes/elliptic_curves/hom_sum.py | 52 +- .../schemes/elliptic_curves/hom_velusqrt.py | 86 +- src/sage/schemes/elliptic_curves/homset.py | 5 +- .../schemes/elliptic_curves/isogeny_class.py | 114 +- .../elliptic_curves/isogeny_small_degree.py | 494 +- src/sage/schemes/elliptic_curves/jacobian.py | 7 +- .../schemes/elliptic_curves/kodaira_symbol.py | 7 +- src/sage/schemes/elliptic_curves/kraus.py | 157 +- .../schemes/elliptic_curves/lseries_ell.py | 49 +- .../schemes/elliptic_curves/mod5family.py | 106 +- src/sage/schemes/elliptic_curves/mod_poly.py | 4 +- .../modular_parametrization.py | 3 + .../schemes/elliptic_curves/padic_lseries.py | 261 +- src/sage/schemes/elliptic_curves/padics.py | 220 +- .../schemes/elliptic_curves/period_lattice.py | 166 +- .../schemes/elliptic_curves/saturation.py | 72 +- src/sage/schemes/elliptic_curves/sha_tate.py | 50 +- .../elliptic_curves/weierstrass_morphism.py | 86 +- .../elliptic_curves/weierstrass_transform.py | 10 +- src/sage/schemes/generic/algebraic_scheme.py | 116 +- src/sage/schemes/generic/ambient_space.py | 41 +- src/sage/schemes/generic/divisor.py | 11 +- src/sage/schemes/generic/divisor_group.py | 12 +- src/sage/schemes/generic/glue.py | 10 +- src/sage/schemes/generic/homset.py | 36 +- src/sage/schemes/generic/hypersurface.py | 11 +- src/sage/schemes/generic/morphism.py | 20 +- src/sage/schemes/generic/point.py | 11 +- src/sage/schemes/generic/scheme.py | 30 +- src/sage/schemes/generic/spec.py | 5 +- .../hyperelliptic_curves/constructor.py | 8 +- .../hyperelliptic_finite_field.py | 32 +- .../hyperelliptic_curves/hyperelliptic_g2.py | 16 +- .../hyperelliptic_generic.py | 59 +- .../hyperelliptic_padic_field.py | 93 +- .../hyperelliptic_rational_field.py | 12 +- .../hyperelliptic_curves/invariants.py | 34 +- .../jacobian_endomorphism_utils.py | 28 +- .../jacobian_g2_generic.py | 13 +- .../hyperelliptic_curves/jacobian_generic.py | 25 +- .../jacobian_homset_generic.py | 50 +- .../jacobian_homset_inert.py | 4 +- .../jacobian_homset_split.py | 24 +- .../hyperelliptic_curves/jacobian_morphism.py | 16 +- .../hyperelliptic_curves/kummer_surface.py | 258 +- .../schemes/hyperelliptic_curves/mestre.py | 89 +- .../hyperelliptic_curves/monsky_washnitzer.py | 72 +- .../schemes/jacobians/abstract_jacobian.py | 4 +- src/sage/schemes/plane_conics/all.py | 1 + src/sage/schemes/plane_conics/con_field.py | 114 +- .../schemes/plane_conics/con_finite_field.py | 4 +- .../schemes/plane_conics/con_number_field.py | 43 +- .../plane_conics/con_rational_field.py | 18 +- .../con_rational_function_field.py | 72 +- src/sage/schemes/plane_conics/constructor.py | 26 +- .../plane_quartics/quartic_constructor.py | 4 +- src/sage/schemes/product_projective/homset.py | 15 +- .../schemes/product_projective/morphism.py | 34 +- src/sage/schemes/product_projective/point.py | 11 +- .../product_projective/rational_point.py | 35 +- src/sage/schemes/product_projective/space.py | 40 +- .../schemes/product_projective/subscheme.py | 84 +- .../schemes/projective/proj_bdd_height.py | 36 +- .../schemes/projective/projective_homset.py | 130 +- .../schemes/projective/projective_morphism.py | 88 +- .../schemes/projective/projective_point.py | 51 +- .../projective/projective_rational_point.py | 44 +- .../schemes/projective/projective_space.py | 131 +- .../projective/projective_subscheme.py | 29 +- .../riemann_surfaces/riemann_surface.py | 458 +- src/sage/schemes/toric/chow_group.py | 16 +- src/sage/schemes/toric/divisor.py | 62 +- src/sage/schemes/toric/fano_variety.py | 178 +- src/sage/schemes/toric/homset.py | 20 +- src/sage/schemes/toric/ideal.py | 16 +- src/sage/schemes/toric/library.py | 208 +- src/sage/schemes/toric/morphism.py | 36 +- src/sage/schemes/toric/points.py | 24 +- src/sage/schemes/toric/sheaf/constructor.py | 12 +- src/sage/schemes/toric/sheaf/klyachko.py | 22 +- src/sage/schemes/toric/toric_subscheme.py | 42 +- src/sage/schemes/toric/variety.py | 197 +- src/sage/schemes/toric/weierstrass.py | 22 +- .../schemes/toric/weierstrass_covering.py | 16 +- src/sage/schemes/toric/weierstrass_higher.py | 12 +- .../weighted_projective_point.py | 34 +- .../weighted_projective_space.py | 53 +- src/sage/sets/all.py | 3 + src/sage/sets/cartesian_product.py | 11 +- src/sage/sets/condition_set.py | 34 +- .../sets/disjoint_union_enumerated_sets.py | 20 +- src/sage/sets/finite_enumerated_set.py | 2 + src/sage/sets/finite_set_maps.py | 23 +- src/sage/sets/image_set.py | 12 +- src/sage/sets/integer_range.py | 54 +- src/sage/sets/non_negative_integers.py | 6 +- src/sage/sets/positive_integers.py | 3 + src/sage/sets/primes.py | 31 +- src/sage/sets/real_set.py | 74 +- src/sage/sets/set.py | 50 +- src/sage/sets/set_from_iterator.py | 48 +- src/sage/sets/totally_ordered_finite_set.py | 8 +- src/sage/stats/all.py | 3 +- src/sage/stats/basic_stats.py | 15 +- src/sage/stats/distributions/all.py | 1 + src/sage/stats/distributions/catalog.py | 2 + .../discrete_gaussian_lattice.py | 22 +- .../discrete_gaussian_polynomial.py | 2 + src/sage/stats/hmm/all.py | 4 +- src/sage/stats/r.py | 1 + src/sage/structure/all.py | 9 +- src/sage/structure/category_object.pyi | 4 +- src/sage/structure/coerce_actions.pyi | 1 - src/sage/structure/coerce_exceptions.py | 1 + src/sage/structure/coerce_maps.pyi | 2 - src/sage/structure/dynamic_class.py | 11 +- src/sage/structure/factorization.py | 34 +- src/sage/structure/factorization_integer.py | 7 +- src/sage/structure/formal_sum.py | 21 +- src/sage/structure/gens_py.py | 56 +- src/sage/structure/global_options.py | 46 +- src/sage/structure/indexed_generators.py | 39 +- src/sage/structure/list_clone_timings.py | 5 +- src/sage/structure/mutability.pyi | 1 - src/sage/structure/nonexact.py | 2 + src/sage/structure/parent.pyi | 20 +- src/sage/structure/proof/all.py | 6 + src/sage/structure/proof/proof.py | 5 +- src/sage/structure/sage_object_test.py | 2 +- src/sage/structure/sequence.py | 32 +- src/sage/structure/set_factories.py | 43 +- src/sage/structure/set_factories_example.py | 39 +- src/sage/structure/support_view.py | 1 + src/sage/structure/unique_representation.py | 5 +- src/sage/symbolic/all.py | 3 +- src/sage/symbolic/assumptions.py | 18 +- src/sage/symbolic/callable.py | 7 +- src/sage/symbolic/callable.pyi | 64 +- src/sage/symbolic/comparison_impl.pyi | 37 +- src/sage/symbolic/constants.py | 97 +- src/sage/symbolic/constants_c_impl.pyi | 7 +- .../expression_conversion_algebraic.py | 10 +- .../symbolic/expression_conversion_sympy.py | 9 +- src/sage/symbolic/expression_conversions.py | 97 +- src/sage/symbolic/function.pyi | 141 +- src/sage/symbolic/function_factory.py | 22 +- src/sage/symbolic/function_factory.pyi | 14 +- src/sage/symbolic/getitem_impl.pyi | 25 +- src/sage/symbolic/integration/external.py | 16 +- src/sage/symbolic/integration/integral.py | 31 +- src/sage/symbolic/operators.py | 23 +- src/sage/symbolic/operators.pyi | 64 +- src/sage/symbolic/random_tests.py | 42 +- src/sage/symbolic/relation.py | 66 +- src/sage/symbolic/ring.pyi | 132 +- src/sage/symbolic/subring.py | 52 +- src/sage/symbolic/symbols.py | 1 + src/sage/symbolic/tests.py | 1 + src/sage/symbolic/units.py | 673 +- src/sage/tensor/modules/all.py | 4 +- .../modules/alternating_contr_tensor.py | 49 +- src/sage/tensor/modules/comp.py | 544 +- .../tensor/modules/ext_pow_free_module.py | 54 +- .../tensor/modules/finite_rank_free_module.py | 214 +- src/sage/tensor/modules/format_utilities.py | 3 +- .../tensor/modules/free_module_alt_form.py | 47 +- .../modules/free_module_automorphism.py | 54 +- src/sage/tensor/modules/free_module_basis.py | 103 +- .../tensor/modules/free_module_element.py | 6 +- src/sage/tensor/modules/free_module_homset.py | 54 +- .../modules/free_module_linear_group.py | 40 +- .../tensor/modules/free_module_morphism.py | 132 +- src/sage/tensor/modules/free_module_tensor.py | 291 +- src/sage/tensor/modules/reflexive_module.py | 5 +- src/sage/tensor/modules/tensor_free_module.py | 112 +- .../tensor/modules/tensor_free_submodule.py | 38 +- .../modules/tensor_free_submodule_basis.py | 6 +- .../tensor/modules/tensor_with_indices.py | 157 +- src/sage/tests/__init__.py | 17 +- src/sage/tests/arxiv_0812_2725.py | 10 +- src/sage/tests/benchmark.py | 119 +- .../actions-sage-exercises.py | 14 +- .../judson_abstract_algebra/actions-sage.py | 14 +- .../judson_abstract_algebra/algcodes-sage.py | 14 +- .../judson_abstract_algebra/boolean-sage.py | 14 +- .../cosets-sage-exercises.py | 14 +- .../judson_abstract_algebra/cosets-sage.py | 14 +- .../judson_abstract_algebra/crypt-sage.py | 14 +- .../judson_abstract_algebra/cyclic-sage.py | 14 +- .../judson_abstract_algebra/domains-sage.py | 14 +- .../judson_abstract_algebra/fields-sage.py | 14 +- .../judson_abstract_algebra/finite-sage.py | 14 +- .../judson_abstract_algebra/galois-sage.py | 14 +- .../judson_abstract_algebra/groups-sage.py | 14 +- .../homomorph-sage-exercises.py | 14 +- .../judson_abstract_algebra/homomorph-sage.py | 14 +- .../judson_abstract_algebra/integers-sage.py | 14 +- .../judson_abstract_algebra/isomorph-sage.py | 14 +- .../judson_abstract_algebra/normal-sage.py | 14 +- .../judson_abstract_algebra/permute-sage.py | 14 +- .../judson_abstract_algebra/poly-sage.py | 14 +- .../judson_abstract_algebra/rings-sage.py | 14 +- .../judson_abstract_algebra/sets-sage.py | 14 +- .../judson_abstract_algebra/struct-sage.py | 14 +- .../judson_abstract_algebra/sylow-sage.py | 14 +- .../vect-sage-exercises.py | 14 +- .../judson_abstract_algebra/vect-sage.py | 14 +- src/sage/tests/finite_poset.py | 164 +- src/sage/tests/functools_partial_src.py | 1 + src/sage/tests/memcheck/run_tests.py | 1 + .../tests/memcheck/run_tests_in_valgrind.py | 10 +- .../tests/memcheck/symbolic_expression.py | 1 + src/sage/tests/memcheck/verify_no_leak.py | 11 +- src/sage/tests/test_deprecation.py | 1 + src/sage/topology/all.py | 1 + src/sage/topology/cell_complex.py | 47 +- src/sage/topology/cubical_complex.py | 113 +- src/sage/topology/delta_complex.py | 123 +- .../topology/filtered_simplicial_complex.py | 14 +- src/sage/topology/moment_angle_complex.py | 28 +- src/sage/topology/simplicial_complex.py | 253 +- .../topology/simplicial_complex_catalog.py | 19 +- .../topology/simplicial_complex_examples.py | 896 +- .../topology/simplicial_complex_homset.py | 3 +- .../topology/simplicial_complex_morphism.py | 36 +- src/sage/topology/simplicial_set.py | 218 +- src/sage/topology/simplicial_set_catalog.py | 7 +- .../topology/simplicial_set_constructions.py | 180 +- src/sage/topology/simplicial_set_examples.py | 114 +- src/sage/topology/simplicial_set_morphism.py | 74 +- src/sage/typeset/ascii_art.py | 9 +- src/sage/typeset/character_art.py | 37 +- src/sage/typeset/character_art_factory.py | 58 +- src/sage/typeset/symbols.py | 8 +- src/sage/typeset/unicode_art.py | 16 +- src/sage/typeset/unicode_characters.py | 18 +- 2189 files changed, 85844 insertions(+), 79433 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 14f8deeb242..5fffa6371be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -251,6 +251,8 @@ test = ["coverage", "pytest", "pytest-xdist"] # Python 3.12 is the minimum supported version target-version = "py312" +line-length = 320 + exclude = [ # This directory is full of old autogenerated files. # Linting it would just get in the way of adding stricter linter rules diff --git a/src/sage/algebras/affine_nil_temperley_lieb.py b/src/sage/algebras/affine_nil_temperley_lieb.py index f2b5ec218cd..c30199e6867 100644 --- a/src/sage/algebras/affine_nil_temperley_lieb.py +++ b/src/sage/algebras/affine_nil_temperley_lieb.py @@ -1,6 +1,7 @@ """ Affine nilTemperley Lieb Algebra of type A """ + # **************************************************************************** # Copyright (C) 2010 Anne Schilling # @@ -234,8 +235,7 @@ def has_no_braid_relation(self, w, i) -> bool: return False s = w.parent().simple_reflections() wi = w * s[i] - adjacent = [(i - 1) % w.parent().n, - (i + 1) % w.parent().n] + adjacent = [(i - 1) % w.parent().n, (i + 1) % w.parent().n] for j in adjacent: if j in w.descents(): return j not in wi.descents() diff --git a/src/sage/algebras/all.py b/src/sage/algebras/all.py index 0e995a677ec..c1b0129c49e 100644 --- a/src/sage/algebras/all.py +++ b/src/sage/algebras/all.py @@ -1,6 +1,7 @@ """ Algebras """ + # **************************************************************************** # Copyright (C) 2005 William Stein # @@ -38,11 +39,9 @@ lazy_import('sage.algebras.group_algebra', 'GroupAlgebra') lazy_import('sage.algebras.iwahori_hecke_algebra', 'IwahoriHeckeAlgebra') -lazy_import('sage.algebras.affine_nil_temperley_lieb', - 'AffineNilTemperleyLiebTypeA') +lazy_import('sage.algebras.affine_nil_temperley_lieb', 'AffineNilTemperleyLiebTypeA') lazy_import('sage.algebras.nil_coxeter_algebra', 'NilCoxeterAlgebra') -lazy_import('sage.algebras.schur_algebra', ['SchurAlgebra', - 'SchurTensorModule']) +lazy_import('sage.algebras.schur_algebra', ['SchurAlgebra', 'SchurTensorModule']) lazy_import('sage.algebras.hall_algebra', 'HallAlgebra') @@ -57,8 +56,7 @@ lazy_import('sage.algebras.commutative_dga', 'GradedCommutativeAlgebra') -lazy_import('sage.algebras.rational_cherednik_algebra', - 'RationalCherednikAlgebra') +lazy_import('sage.algebras.rational_cherednik_algebra', 'RationalCherednikAlgebra') lazy_import('sage.algebras.tensor_algebra', 'TensorAlgebra') diff --git a/src/sage/algebras/askey_wilson.py b/src/sage/algebras/askey_wilson.py index 363528b2a26..c93873d1426 100644 --- a/src/sage/algebras/askey_wilson.py +++ b/src/sage/algebras/askey_wilson.py @@ -203,6 +203,7 @@ class AskeyWilsonAlgebra(CombinatorialFreeModule): - [Terwilliger2011]_ """ + @staticmethod def __classcall_private__(cls, R, q=None): r""" @@ -250,11 +251,8 @@ def __init__(self, R, q) -> None: """ self._q = q cat = Algebras(Rings().Commutative()).WithBasis() - indices = cartesian_product([NonNegativeIntegers()]*6) - CombinatorialFreeModule.__init__(self, R, indices, prefix='AW', - sorting_key=_basis_key, - sorting_reverse=True, - category=cat) + indices = cartesian_product([NonNegativeIntegers()] * 6) + CombinatorialFreeModule.__init__(self, R, indices, prefix='AW', sorting_key=_basis_key, sorting_reverse=True, category=cat) self._assign_names('A,B,C,a,b,g') def _repr_term(self, t) -> str: @@ -271,12 +269,14 @@ def _repr_term(self, t) -> str: sage: AW._repr_term((0,1,0,3,7,2)) 'B*a^3*b^7*g^2' """ + def exp(l, e): if e == 0: return '' if e == 1: return '*' + l return '*' + l + '^{}'.format(e) + ret = ''.join(exp(l, e) for l, e in zip('ABCabg', t)) if not ret: return '1' @@ -307,6 +307,7 @@ def exp(l, e): if e == 1: return l return l + '^{{{}}}'.format(e) + var_names = ['A', 'B', 'C', '\\alpha', '\\beta', '\\gamma'] return ''.join(exp(l, e) for l, e in zip(var_names, t)) @@ -344,6 +345,7 @@ def build_monomial(g): exp = [0] * 6 exp[A.index(g)] = 1 return self.monomial(self._indices(exp)) + return Family(A, build_monomial) @cached_method @@ -370,7 +372,7 @@ def one_basis(self): sage: AW.one_basis() (0, 0, 0, 0, 0, 0) """ - return self._indices([0]*6) + return self._indices([0] * 6) def q(self): r""" @@ -401,10 +403,7 @@ def _an_element_(self): q = self._q I = self._indices R = self.base_ring() - elt = {I((1,0,0,0,0,0)): R(1), - I((1,0,2,0,1,0)): R.an_element(), - I((0,1,0,2,0,1)): q**2 * R(3), - I((0,0,0,1,1,3)): q**-3 + R(3) + R(2)*q + q**2} + elt = {I((1, 0, 0, 0, 0, 0)): R(1), I((1, 0, 2, 0, 1, 0)): R.an_element(), I((0, 1, 0, 2, 0, 1)): q**2 * R(3), I((0, 0, 0, 1, 1, 3)): q**-3 + R(3) + R(2) * q + q**2} return self.element_class(self, elt) def some_elements(self): @@ -450,13 +449,7 @@ def casimir_element(self): """ q = self._q I = self._indices - d = {I((1, 1, 1, 0, 0, 0)): q, # q ABC - I((2, 0, 0, 0, 0, 0)): q**2, # q^2 A^2 - I((0, 2, 0, 0, 0, 0)): q**-2, # q^-2 B^2 - I((0, 0, 2, 0, 0, 0)): q**2, # q^2 C^2 - I((1, 0, 0, 1, 0, 0)): -q, # -q A\alpha - I((0, 1, 0, 0, 1, 0)): -q**-1, # -q^-1 B\beta - I((0, 0, 1, 0, 0, 1)): -q} # -q C\gamma + d = {I((1, 1, 1, 0, 0, 0)): q, I((2, 0, 0, 0, 0, 0)): q**2, I((0, 2, 0, 0, 0, 0)): q**-2, I((0, 0, 2, 0, 0, 0)): q**2, I((1, 0, 0, 1, 0, 0)): -q, I((0, 1, 0, 0, 1, 0)): -(q**-1), I((0, 0, 1, 0, 0, 1)): -q} # q ABC # q^2 A^2 # q^-2 B^2 # q^2 C^2 # -q A\alpha # -q^-1 B\beta # -q C\gamma return self.element_class(self, d) @cached_method @@ -518,19 +511,15 @@ def product_on_basis(self, x, y): if rhs[0] > 0: # rhs has an A to commute with C lhs[2] -= 1 rhs[0] -= 1 - rel = {I((1, 0, 1, 0, 0, 0)): q**-2, # q^2 AC - I((0, 1, 0, 0, 0, 0)): q**-3 - q**1, # q^-1(q^-2-q^2) B - I((0, 0, 0, 0, 1, 0)): 1 - q**-2} # -q^-1(q^-1-q) b + rel = {I((1, 0, 1, 0, 0, 0)): q**-2, I((0, 1, 0, 0, 0, 0)): q**-3 - q**1, I((0, 0, 0, 0, 1, 0)): 1 - q**-2} # q^2 AC # q^-1(q^-2-q^2) B # -q^-1(q^-1-q) b rel = self.element_class(self, rel) - return self.monomial(I(lhs+[0]*3)) * (rel * self.monomial(I(rhs))) + return self.monomial(I(lhs + [0] * 3)) * (rel * self.monomial(I(rhs))) if rhs[1] > 0: # rhs has a B to commute with C lhs[2] -= 1 rhs[1] -= 1 - rel = {I((0, 1, 1, 0, 0, 0)): q**2, # q^2 BC - I((1, 0, 0, 0, 0, 0)): q**3 - q**-1, # q(q^2-q^-2) A - I((0, 0, 0, 1, 0, 0)): -q**2 + 1} # -q(q-q^-1) a + rel = {I((0, 1, 1, 0, 0, 0)): q**2, I((1, 0, 0, 0, 0, 0)): q**3 - q**-1, I((0, 0, 0, 1, 0, 0)): -(q**2) + 1} # q^2 BC # q(q^2-q^-2) A # -q(q-q^-1) a rel = self.element_class(self, rel) - return self.monomial(I(lhs+[0]*3)) * (rel * self.monomial(I(rhs))) + return self.monomial(I(lhs + [0] * 3)) * (rel * self.monomial(I(rhs))) # nothing to commute as rhs has no A nor B rhs[2] += lhs[2] rhs[1] = lhs[1] @@ -541,11 +530,9 @@ def product_on_basis(self, x, y): if rhs[0] > 0: # rhs has an A to commute with B lhs[1] -= 1 rhs[0] -= 1 - rel = {I((1, 1, 0, 0, 0, 0)): q**2, # q^2 AB - I((0, 0, 1, 0, 0, 0)): q**3 - q**-1, # q(q^2-q^-2) C - I((0, 0, 0, 0, 0, 1)): -q**2 + 1} # -q(q-q^-1) g + rel = {I((1, 1, 0, 0, 0, 0)): q**2, I((0, 0, 1, 0, 0, 0)): q**3 - q**-1, I((0, 0, 0, 0, 0, 1)): -(q**2) + 1} # q^2 AB # q(q^2-q^-2) C # -q(q-q^-1) g rel = self.element_class(self, rel) - return self.monomial(I(lhs+[0]*3)) * (rel * self.monomial(I(rhs))) + return self.monomial(I(lhs + [0] * 3)) * (rel * self.monomial(I(rhs))) # nothing to commute as rhs has no A rhs[1] += lhs[1] rhs[0] = lhs[0] @@ -590,8 +577,8 @@ def permutation_automorphism(self): sage: r3(AW.an_element()) == AW.an_element() True """ - A,B,C,a,b,g = self.gens() - return AlgebraMorphism(self, [B,C,A,b,g,a], codomain=self) + A, B, C, a, b, g = self.gens() + return AlgebraMorphism(self, [B, C, A, b, g, a], codomain=self) rho = permutation_automorphism @@ -637,11 +624,11 @@ def reflection_automorphism(self): sage: s2(AW.an_element()) == AW.an_element() True """ - A,B,C,a,b,g = self.gens() + A, B, C, a, b, g = self.gens() q = self._q # Note that sage: (A*B-B*A) / (q-q^-1) == -q*A*B - (1+q^2)*C + q*g - Cp = C - q*A*B - (1+q**2)*C + q*g - return AlgebraMorphism(self, [B,A,Cp,b,a,g], codomain=self) + Cp = C - q * A * B - (1 + q**2) * C + q * g + return AlgebraMorphism(self, [B, A, Cp, b, a, g], codomain=self) sigma = reflection_automorphism @@ -745,26 +732,25 @@ def loop_representation(self): True """ from sage.matrix.matrix_space import MatrixSpace + q = self._q base = LaurentPolynomialRing(self.base_ring().fraction_field(), 'lambda') la = base.gen() inv = ~la M = MatrixSpace(base, 2) - A = M([[la,1-inv],[0,inv]]) - Ai = M([[inv,inv-1],[0,la]]) - B = M([[inv,0],[la-1,la]]) - Bi = M([[la,0],[1-la,inv]]) - C = M([[1,1-la],[inv-1,la+inv-1]]) - Ci = M([[la+inv-1,la-1],[1-inv,1]]) + A = M([[la, 1 - inv], [0, inv]]) + Ai = M([[inv, inv - 1], [0, la]]) + B = M([[inv, 0], [la - 1, la]]) + Bi = M([[la, 0], [1 - la, inv]]) + C = M([[1, 1 - la], [inv - 1, la + inv - 1]]) + Ci = M([[la + inv - 1, la - 1], [1 - inv, 1]]) mu = la + inv nu = (self._q**2 + self._q**-2) * mu + mu**2 nuI = M(nu) # After #29374 is fixed, the category can become # Algebras(Rings().Commutative()) as it was before #29399. category = Rings() - return AlgebraMorphism(self, [q*A + q**-1*Ai, q*B + q**-1*Bi, q*C + q**-1*Ci, - nuI, nuI, nuI], - codomain=M, category=category) + return AlgebraMorphism(self, [q * A + q**-1 * Ai, q * B + q**-1 * Bi, q * C + q**-1 * Ci, nuI, nuI, nuI], codomain=M, category=category) pi = loop_representation @@ -789,8 +775,8 @@ class AlgebraMorphism(ModuleMorphismByLinearity): An algebra morphism of the Askey-Wilson algebra defined by the images of the generators. """ - def __init__(self, domain, on_generators, position=0, codomain=None, - category=None): + + def __init__(self, domain, on_generators, position=0, codomain=None, category=None): """ Given a map on the multiplicative basis of a free algebra, this method returns the algebra morphism that is the linear extension of its image @@ -816,8 +802,7 @@ def __init__(self, domain, on_generators, position=0, codomain=None, if category is None: category = Algebras(Rings().Commutative()).WithBasis() self._on_generators = tuple(on_generators) - ModuleMorphismByLinearity.__init__(self, domain=domain, codomain=codomain, - position=position, category=category) + ModuleMorphismByLinearity.__init__(self, domain=domain, codomain=codomain, position=position, category=category) def __eq__(self, other): """ @@ -835,12 +820,7 @@ def __eq__(self, other): sage: id == rho * rho * rho True """ - return (self.__class__ is other.__class__ and self.parent() == other.parent() - and self._zero == other._zero - and self._on_generators == other._on_generators - and self._position == other._position - and self._is_module_with_basis_over_same_base_ring - == other._is_module_with_basis_over_same_base_ring) + return self.__class__ is other.__class__ and self.parent() == other.parent() and self._zero == other._zero and self._on_generators == other._on_generators and self._position == other._position and self._is_module_with_basis_over_same_base_ring == other._is_module_with_basis_over_same_base_ring def _on_basis(self, c): r""" @@ -903,8 +883,7 @@ def _on_basis(self, c): 3*q^2*A*B*g - q*A*B - (3*q^-1-3*q^3)*C*g + (3-3*q^2)*g^2 - q^2*C + q*g """ - return self.codomain().prod(self._on_generators[i]**exp - for i, exp in enumerate(c)) + return self.codomain().prod(self._on_generators[i] ** exp for i, exp in enumerate(c)) def _composition_(self, right, homset): """ @@ -927,7 +906,5 @@ def _composition_(self, right, homset): """ if isinstance(right, AlgebraMorphism): cat = homset.homset_category() - return AlgebraMorphism(homset.domain(), - [right(g) for g in self._on_generators], - codomain=homset.codomain(), category=cat) + return AlgebraMorphism(homset.domain(), [right(g) for g in self._on_generators], codomain=homset.codomain(), category=cat) return super()._composition_(right, homset) diff --git a/src/sage/algebras/associated_graded.py b/src/sage/algebras/associated_graded.py index 388e80dac05..69c74d29805 100644 --- a/src/sage/algebras/associated_graded.py +++ b/src/sage/algebras/associated_graded.py @@ -162,6 +162,7 @@ class AssociatedGradedAlgebra(CombinatorialFreeModule): - :wikipedia:`Filtered_algebra#Associated_graded_algebra` """ + def __init__(self, A, category=None): """ Initialize ``self``. @@ -188,8 +189,7 @@ def __init__(self, A, category=None): except AttributeError: opts = {'prefix': 'Abar'} - CombinatorialFreeModule.__init__(self, base_ring, A.basis().keys(), - category=category, **opts) + CombinatorialFreeModule.__init__(self, base_ring, A.basis().keys(), category=category, **opts) # Setup the conversion back phi = self.module_morphism(diagonal=lambda x: base_one, codomain=A) @@ -208,6 +208,7 @@ def _repr_(self) -> str: with cross product over Rational Field """ from sage.categories.algebras_with_basis import AlgebrasWithBasis + if self in AlgebrasWithBasis: return "Graded Algebra of {}".format(self._A) return "Graded Module of {}".format(self._A) @@ -223,6 +224,7 @@ def _latex_(self) -> str: \operatorname{gr} ... """ from sage.misc.latex import latex + return "\\operatorname{gr} " + latex(self._A) def _element_constructor_(self, x): @@ -338,6 +340,4 @@ def product_on_basis(self, x, y): """ ret = self._A.product_on_basis(x, y) deg = self._A.degree_on_basis(x) + self._A.degree_on_basis(y) - return self.sum_of_terms([(i,c) for i,c in ret - if self._A.degree_on_basis(i) == deg], - distinct=True) + return self.sum_of_terms([(i, c) for i, c in ret if self._A.degree_on_basis(i) == deg], distinct=True) diff --git a/src/sage/algebras/catalog.py b/src/sage/algebras/catalog.py index afa5db12e8e..83e3aca7ddb 100644 --- a/src/sage/algebras/catalog.py +++ b/src/sage/algebras/catalog.py @@ -87,11 +87,11 @@ """ from sage.misc.lazy_import import lazy_import + lazy_import('sage.algebras.free_algebra', 'FreeAlgebra', as_='Free') lazy_import('sage.algebras.quatalg.quaternion_algebra', 'QuaternionAlgebra', as_='Quaternion') lazy_import('sage.algebras.steenrod.steenrod_algebra', 'SteenrodAlgebra', as_='Steenrod') -lazy_import('sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra', - 'FiniteDimensionalAlgebra', as_='FiniteDimensional') +lazy_import('sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra', 'FiniteDimensionalAlgebra', as_='FiniteDimensional') lazy_import('sage.algebras.group_algebra', 'GroupAlgebra', as_='Group') lazy_import('sage.algebras.clifford_algebra', 'CliffordAlgebra', as_='Clifford') lazy_import('sage.algebras.clifford_algebra', 'ExteriorAlgebra', as_='Exterior') @@ -131,15 +131,13 @@ lazy_import('sage.combinat.grossman_larson_algebras', 'GrossmanLarsonAlgebra', 'GrossmanLarson') lazy_import('sage.algebras.quantum_clifford', 'QuantumCliffordAlgebra', 'QuantumClifford') lazy_import('sage.algebras.quantum_oscillator', 'QuantumOscillatorAlgebra', 'QuantumOscillator') -lazy_import('sage.algebras.quantum_matrix_coordinate_algebra', - 'QuantumMatrixCoordinateAlgebra', 'QuantumMatrixCoordinate') +lazy_import('sage.algebras.quantum_matrix_coordinate_algebra', 'QuantumMatrixCoordinateAlgebra', 'QuantumMatrixCoordinate') lazy_import('sage.algebras.quantum_matrix_coordinate_algebra', 'QuantumGL') lazy_import('sage.algebras.q_commuting_polynomials', 'qCommutingPolynomials') lazy_import('sage.algebras.q_commuting_polynomials', 'qCommutingLaurentPolynomials') lazy_import('sage.algebras.tensor_algebra', 'TensorAlgebra', 'Tensor') lazy_import('sage.algebras.quantum_groups.quantum_group_gap', 'QuantumGroup') -lazy_import('sage.algebras.quantum_groups.ace_quantum_onsager', - 'ACEQuantumOnsagerAlgebra', 'AlternatingCentralExtensionQuantumOnsager') +lazy_import('sage.algebras.quantum_groups.ace_quantum_onsager', 'ACEQuantumOnsagerAlgebra', 'AlternatingCentralExtensionQuantumOnsager') lazy_import('sage.algebras.down_up_algebra', 'DownUpAlgebra', 'DownUp') lazy_import('sage.algebras.yangian', 'Yangian') lazy_import('sage.algebras.octonion_algebra', 'OctonionAlgebra', 'Octonion') diff --git a/src/sage/algebras/cellular_basis.py b/src/sage/algebras/cellular_basis.py index 8bb671d196f..a4e46a307c2 100644 --- a/src/sage/algebras/cellular_basis.py +++ b/src/sage/algebras/cellular_basis.py @@ -165,6 +165,7 @@ class CellularBasis(CombinatorialFreeModule): - C([2, 1], [[1, 3], [2]], [[1, 3], [2]]) + C([3], [[1, 2, 3]], [[1, 2, 3]]) """ + def __init__(self, A, to_algebra=None, from_algebra=None, **kwargs): r""" Initialize ``self``. @@ -176,17 +177,13 @@ def __init__(self, A, to_algebra=None, from_algebra=None, **kwargs): sage: TestSuite(C).run() """ self._algebra = A - I = [(la, s, t) for la in A.cell_poset() - for s in A.cell_module_indices(la) - for t in A.cell_module_indices(la)] + I = [(la, s, t) for la in A.cell_poset() for s in A.cell_module_indices(la) for t in A.cell_module_indices(la)] # TODO: Use instead A.category().Realizations() so # operations are defined by coercion? prefix = kwargs.pop('prefix', 'C') cat = Algebras(A.category().base_ring()).FiniteDimensional().WithBasis().Cellular() - CombinatorialFreeModule.__init__(self, A.base_ring(), I, - prefix=prefix, bracket=False, - category=cat, **kwargs) + CombinatorialFreeModule.__init__(self, A.base_ring(), I, prefix=prefix, bracket=False, category=cat, **kwargs) # Register coercions if from_algebra is None: @@ -194,13 +191,11 @@ def __init__(self, A, to_algebra=None, from_algebra=None, **kwargs): if to_algebra is None: to_algebra = A._from_cellular_index if from_algebra is not NotImplemented: - to_cellular = A.module_morphism(from_algebra, codomain=self, - category=cat) + to_cellular = A.module_morphism(from_algebra, codomain=self, category=cat) if to_algebra is NotImplemented: from_cellular = ~to_cellular else: - from_cellular = self.module_morphism(to_algebra, codomain=A, - category=cat) + from_cellular = self.module_morphism(to_algebra, codomain=A, category=cat) if from_algebra is NotImplemented: to_cellular = ~from_cellular to_cellular.register_as_coercion() @@ -231,6 +226,7 @@ def _latex_term(self, x) -> str: 'C^{...}_{\\left(...\\right)}' """ from sage.misc.latex import latex + la = x[0] m = (x[1], x[2]) # m contains "non-LaTeXed" strings, use string representation diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index f90ae6fc260..e028489a87c 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -6,6 +6,7 @@ - Travis Scrimshaw (2013-09-06): Initial version - Trevor K. Karn (2022-07-27): Rewrite basis indexing using FrozenBitset """ + # **************************************************************************** # Copyright (C) 2013-2022 Travis Scrimshaw # (C) 2022 Trevor Karn @@ -20,8 +21,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.structure.element import Element -from sage.structure.richcmp import (richcmp_method, op_EQ, op_NE, - op_LT, op_GT, op_LE, op_GE, rich_to_bool) +from sage.structure.richcmp import richcmp_method, op_EQ, op_NE, op_LT, op_GT, op_LE, op_GE, rich_to_bool from sage.data_structures.bitset import Bitset, FrozenBitset from sage.algebras.clifford_algebra_element import CliffordAlgebraElement, ExteriorAlgebraElement @@ -50,6 +50,7 @@ class CliffordAlgebraIndices(UniqueRepresentation, Parent): A facade parent for the indices of Clifford algebra. Users should not create instances of this class directly. """ + def __init__(self, Qdim, degree=None) -> None: r""" Initialize ``self``. @@ -85,9 +86,10 @@ def __init__(self, Qdim, degree=None) -> None: """ self._nbits = Qdim if degree is None: - self._cardinality = 2 ** Qdim + self._cardinality = 2**Qdim else: from sage.arith.misc import binomial + self._cardinality = binomial(Qdim, degree) self._degree = degree # the if statement here is in case Qdim is 0. @@ -253,6 +255,7 @@ def __iter__(self): [0] """ import itertools + n = self._nbits if self._degree is not None: if self._degree == 0: # special corner case @@ -351,6 +354,7 @@ def _an_element_(self): return FrozenBitset(range(self._degree)) from sage.combinat.subset import SubsetsSorted + X = SubsetsSorted(range(self._nbits)) return FrozenBitset(X.an_element()) @@ -475,6 +479,7 @@ class CliffordAlgebra(CombinatorialFreeModule): sage: d*c*b*a + a + 4*b*c a*b*c*d + 4*b*c + a """ + @staticmethod def __classcall_private__(cls, Q, names=None): """ @@ -546,8 +551,7 @@ def __init__(self, Q, names, category=None) -> None: category = category.Commutative() indices = CliffordAlgebraIndices(Q.dim()) - CombinatorialFreeModule.__init__(self, R, indices, category=category, - sorting_key=tuple) + CombinatorialFreeModule.__init__(self, R, indices, category=category, sorting_key=tuple) self._assign_names(names) def _repr_(self) -> str: @@ -684,8 +688,7 @@ def _coerce_map_from_(self, V): if isinstance(V, CliffordAlgebra): Q = self._quadratic_form try: - return (V.variable_names() == self.variable_names() and - V._quadratic_form.change_ring(self.base_ring()) == Q) + return V.variable_names() == self.variable_names() and V._quadratic_form.change_ring(self.base_ring()) == Q except (TypeError, AttributeError): return False @@ -733,8 +736,7 @@ def _element_constructor_(self, x): # if the base ring is different, attempt to coerce it into R return self.element_class(self, {FrozenBitset((i,)): R(c) for i, c in x.items() if R(c) != R.zero()}) - if (isinstance(x, CliffordAlgebraElement) - and self.has_coerce_map_from(x.parent())): + if isinstance(x, CliffordAlgebraElement) and self.has_coerce_map_from(x.parent()): R = self.base_ring() return self.element_class(self, {i: R(c) for i, c in x if R(c) != R.zero()}) @@ -939,7 +941,7 @@ def dimension(self): sage: Cl.dimension() 8 """ - return ZZ(2)**self._quadratic_form.dim() + return ZZ(2) ** self._quadratic_form.dim() def pseudoscalar(self): r""" @@ -1115,8 +1117,7 @@ def lift_module_morphism(self, m, names=None): Cl = CliffordAlgebra(Q, names) n = self._quadratic_form.dim() - f = lambda x: self.prod(self._from_dict({FrozenBitset((j, )): m[j, i] for j in range(n)}, - remove_zeros=True) for i in x) + f = lambda x: self.prod(self._from_dict({FrozenBitset((j,)): m[j, i] for j in range(n)}, remove_zeros=True) for i in x) cat = AlgebrasWithBasis(self.category().base_ring()).Super().FiniteDimensional() return Cl.module_morphism(on_basis=f, codomain=self, category=cat) @@ -1202,8 +1203,7 @@ def lift_isometry(self, m, names=None): n = Q.dim() - f = lambda x: Cl.prod(Cl._from_dict({FrozenBitset((j, )): m[j, i] for j in range(n)}, - remove_zeros=True) for i in x) + f = lambda x: Cl.prod(Cl._from_dict({FrozenBitset((j,)): m[j, i] for j in range(n)}, remove_zeros=True) for i in x) cat = AlgebrasWithBasis(self.category().base_ring()).Super().FiniteDimensional() return self.module_morphism(on_basis=f, codomain=Cl, category=cat) @@ -1279,11 +1279,10 @@ def center_basis(self): Bi = B[i] for b, j in enumerate(K): Bj = B[j] - for m, c in (Bi*Bj - Bj*Bi): - d[(a, K.index(m)+k*b)] = c - m = Matrix(R, d, nrows=k, ncols=k*k, sparse=True) - from_vector = lambda x: self.sum_of_terms(((K[i], c) for i, c in x.items()), - distinct=True) + for m, c in Bi * Bj - Bj * Bi: + d[(a, K.index(m) + k * b)] = c + m = Matrix(R, d, nrows=k, ncols=k * k, sparse=True) + from_vector = lambda x: self.sum_of_terms(((K[i], c) for i, c in x.items()), distinct=True) return tuple(map(from_vector, m.kernel().basis())) # Same as center except for superalgebras @@ -1365,8 +1364,7 @@ def supercenter_basis(self): for m, c in supercommutator: d[(a, K.index(m) + k * b)] = c m = Matrix(R, d, nrows=k, ncols=k * k, sparse=True) - from_vector = lambda x: self.sum_of_terms(((K[i], c) for i, c in x.items()), - distinct=True) + from_vector = lambda x: self.sum_of_terms(((K[i], c) for i, c in x.items()), distinct=True) return tuple(map(from_vector, m.kernel().basis())) Element = CliffordAlgebraElement @@ -1428,6 +1426,7 @@ class ExteriorAlgebra(CliffordAlgebra): - :wikipedia:`Exterior_algebra` """ + @staticmethod def __classcall_private__(cls, R, names=None, n=None): """ @@ -1526,7 +1525,7 @@ def _ascii_art_term(self, m): if len(m) == 0: return ascii_art('1') wedge = '/\\' - return ascii_art(*[repr(self.basis()[FrozenBitset((i, ))]) for i in m], sep=wedge) + return ascii_art(*[repr(self.basis()[FrozenBitset((i,))]) for i in m], sep=wedge) def _unicode_art_term(self, m): """ @@ -1669,8 +1668,7 @@ def lift_morphism(self, phi, names=None): n = phi.nrows() R = self.base_ring() E = ExteriorAlgebra(R, names, n) - f = lambda x: E.prod(E._from_dict({FrozenBitset((j, )): phi[j, i] for j in range(n)}, - remove_zeros=True) for i in x) + f = lambda x: E.prod(E._from_dict({FrozenBitset((j,)): phi[j, i] for j in range(n)}, remove_zeros=True) for i in x) cat = AlgebrasWithBasis(R).Super().FiniteDimensional() return self.module_morphism(on_basis=f, codomain=E, category=cat) @@ -1793,12 +1791,10 @@ def coproduct_on_basis(self, a): + z # x*y - x*z # y + y*z # x + x*y*z # 1 """ from sage.combinat.combinat import unshuffle_iterator + one = self.base_ring().one() L = unshuffle_iterator(tuple(a), one) - return self.tensor_square()._from_dict( - {tuple(FrozenBitset(e) if e else FrozenBitset() for e in t): c for t, c in L if c}, - coerce=False, - remove_zeros=False) + return self.tensor_square()._from_dict({tuple(FrozenBitset(e) if e else FrozenBitset() for e in t): c for t, c in L if c}, coerce=False, remove_zeros=False) def antipode_on_basis(self, m): r""" @@ -1817,7 +1813,7 @@ def antipode_on_basis(self, m): sage: E.antipode_on_basis((1,2)) y*z """ - return self.term(m, (-self.base_ring().one())**len(m)) + return self.term(m, (-self.base_ring().one()) ** len(m)) def counit(self, x): r""" @@ -1887,7 +1883,7 @@ def interior_product_on_basis(self, a, b): R = self.base_ring() if not t: # catch empty sets t = None - return self.term(FrozenBitset(t), (R.one() if sgn else - R.one())) + return self.term(FrozenBitset(t), (R.one() if sgn else -R.one())) def lifted_bilinear_form(self, M): r""" @@ -2022,10 +2018,10 @@ def lifted_form(x, y): del matrix_list result += cx * cy * MA.matrix(False).determinant() return result + from sage.categories.cartesian_product import cartesian_product - return PoorManMap(lifted_form, domain=cartesian_product([self, self]), - codomain=self.base_ring(), - name="Bilinear Form") + + return PoorManMap(lifted_form, domain=cartesian_product([self, self]), codomain=self.base_ring(), name="Bilinear Form") def _ideal_class_(self, n=0): """ @@ -2052,9 +2048,7 @@ def _ideal_class_(self, n=0): # Differentials -class ExteriorAlgebraDifferential(ModuleMorphismByLinearity, - UniqueRepresentation, - metaclass=InheritComparisonClasscallMetaclass): +class ExteriorAlgebraDifferential(ModuleMorphismByLinearity, UniqueRepresentation, metaclass=InheritComparisonClasscallMetaclass): r""" Internal class to store the data of a boundary or coboundary of an exterior algebra `\Lambda(L)` defined by the structure @@ -2069,6 +2063,7 @@ class ExteriorAlgebraDifferential(ModuleMorphismByLinearity, This is not a general class for differentials on the exterior algebra. """ + @staticmethod def __classcall__(cls, E, s_coeff): """ @@ -2119,6 +2114,7 @@ def __classcall__(cls, E, s_coeff): d[(k[1], k[0])] = -v from sage.sets.family import Family + return super().__classcall__(cls, E, Family(d)) def __init__(self, E, s_coeff) -> None: @@ -2292,6 +2288,7 @@ class ExteriorAlgebraBoundary(ExteriorAlgebraDifferential): - :wikipedia:`Exterior_algebra#Lie_algebra_homology` """ + def _repr_type(self) -> str: """ TESTS:: @@ -2323,6 +2320,7 @@ def _on_basis(self, m): 0 """ from itertools import combinations + E = self.domain() sc = self._s_coeff keys = sc.keys() @@ -2335,7 +2333,7 @@ def _on_basis(self, m): t = Bitset(m) t.discard(i) t.discard(j) - s += sc[i, j] * E.term(FrozenBitset(t), (-1)**b) + s += sc[i, j] * E.term(FrozenBitset(t), (-1) ** b) return s @@ -2384,6 +2382,7 @@ def chain_complex(self, R=None): """ from sage.homology.chain_complex import ChainComplex from sage.matrix.constructor import Matrix + E = self.domain() n = E.ngens() if R is None: @@ -2401,14 +2400,14 @@ def chain_complex(self, R=None): # situated in degree 0. # Group the basis into degrees - basis_by_deg = {deg: [] for deg in range(n+1)} + basis_by_deg = {deg: [] for deg in range(n + 1)} for b in E.basis().keys(): basis_by_deg[len(b)].append(b) # Construct the transition matrices data = {} prev_basis = basis_by_deg[0] - for deg in range(1, n+1): + for deg in range(1, n + 1): # Make sure within each basis we're sorted by lex basis = sorted(basis_by_deg[deg]) mat = [] @@ -2535,6 +2534,7 @@ class ExteriorAlgebraCoboundary(ExteriorAlgebraDifferential): - :wikipedia:`Exterior_algebra#Differential_geometry` """ + def __init__(self, E, s_coeff) -> None: """ Initialize ``self``. @@ -2621,7 +2621,7 @@ def _on_basis(self, m): else: above = E.monomial(FrozenBitset(above)) - tot += (-1)**sgn * below * cc[k] * above + tot += (-1) ** sgn * below * cc[k] * above return tot @@ -2670,6 +2670,7 @@ def chain_complex(self, R=None): """ from sage.homology.chain_complex import ChainComplex from sage.matrix.constructor import Matrix + E = self.domain() n = E.ngens() if R is None: @@ -2687,7 +2688,7 @@ def chain_complex(self, R=None): # situated in degree 0. # Group the basis into degrees - basis_by_deg = {deg: [] for deg in range(n+1)} + basis_by_deg = {deg: [] for deg in range(n + 1)} for b in E.basis().keys(): basis_by_deg[len(b)].append(b) @@ -2696,14 +2697,14 @@ def chain_complex(self, R=None): basis = basis_by_deg[0] for deg in range(n): # Make sure within each basis we're sorted by lex - next_basis = sorted(basis_by_deg[deg+1]) + next_basis = sorted(basis_by_deg[deg + 1]) mat = [] for b in basis: ret = self._on_basis(b) try: mat.append([ret.coefficient(p) for p in next_basis]) except AttributeError: # if ret is in E.base_ring() - mat.append([E.base_ring()(ret)]*len(next_basis)) + mat.append([E.base_ring()(ret)] * len(next_basis)) data[deg] = Matrix(mat).transpose().change_ring(R) basis = next_basis @@ -2730,6 +2731,7 @@ class ExteriorAlgebraIdeal(Ideal_nc): sage: xbar * ybar 0 """ + def __init__(self, ring, gens, coerce=True, side='twosided') -> None: """ Initialize ``self``. diff --git a/src/sage/algebras/cluster_algebra.py b/src/sage/algebras/cluster_algebra.py index e62c7c65e90..a654b5b2e6a 100644 --- a/src/sage/algebras/cluster_algebra.py +++ b/src/sage/algebras/cluster_algebra.py @@ -372,8 +372,7 @@ from sage.rings.infinity import infinity from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ -from sage.rings.polynomial.laurent_polynomial_ring import (LaurentPolynomialRing_generic, - LaurentPolynomialRing) +from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing_generic, LaurentPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ from sage.structure.element_wrapper import ElementWrapper @@ -393,6 +392,7 @@ class ClusterAlgebraElement(ElementWrapper): """ An element of a cluster algebra. """ + # AdditiveMagmas.Subobjects currently does not implements _add_ def _add_(self, other): r""" @@ -463,7 +463,7 @@ def d_vector(self) -> tuple: """ monomials = self.lift().monomial_coefficients() minimal = map(min, zip(*monomials)) - return tuple(-vector(minimal))[:self.parent().rank()] + return tuple(-vector(minimal))[: self.parent().rank()] def _repr_(self) -> str: r""" @@ -484,6 +484,7 @@ class PrincipalClusterAlgebraElement(ClusterAlgebraElement): """ An element in a cluster algebra with principle coefficients. """ + def g_vector(self): r""" Return the g-vector of ``self``. @@ -560,8 +561,7 @@ def homogeneous_components(self) -> dict: sage: x.homogeneous_components() {(0, 1): x1, (1, 0): x0} """ - deg_matrix = block_matrix([[identity_matrix(self.parent().rank()), - -self.parent().b_matrix()]]) + deg_matrix = block_matrix([[identity_matrix(self.parent().rank()), -self.parent().b_matrix()]]) components: dict[tuple, Any] = {} x = self.lift() monomials = x.monomials() @@ -574,7 +574,7 @@ def homogeneous_components(self) -> dict: for g_vect, compo in components.items(): compo._is_homogeneous = True compo._g_vector = g_vect - self._is_homogeneous = (len(components) == 1) + self._is_homogeneous = len(components) == 1 if self._is_homogeneous: self._g_vector = next(iter(components)) return components @@ -628,6 +628,7 @@ def theta_basis_decomposition(self): # Seeds ############################################################################## + class ClusterAlgebraSeed(SageObject): """ A seed in a Cluster Algebra. @@ -651,6 +652,7 @@ class ClusterAlgebraSeed(SageObject): :meth:`__eq__` is no longer guaranteed to give correct answers. Use at your own risk. """ + def __init__(self, B, C, G, parent, **kwargs): r""" Initialize ``self``. @@ -723,9 +725,7 @@ def __eq__(self, other): sage: S == A.current_seed() True """ - return (isinstance(other, ClusterAlgebraSeed) and - self.parent() == other.parent() and - frozenset(self.g_vectors()) == frozenset(other.g_vectors())) + return isinstance(other, ClusterAlgebraSeed) and self.parent() == other.parent() and frozenset(self.g_vectors()) == frozenset(other.g_vectors()) def __contains__(self, element) -> bool: r""" @@ -1104,7 +1104,7 @@ def mutate(self, direction, **kwargs): try: seq = iter(direction) except TypeError: - seq = iter((direction, )) + seq = iter((direction,)) # are we mutating F-polynomials? mutating_F = kwargs.pop('mutating_F', True) @@ -1207,6 +1207,7 @@ def _mutated_F(self, k, old_g_vector): neg *= self.F_polynomial(j) ** (-self._B[j, k]) return (pos + neg) // alg.F_polynomial(old_g_vector) + ############################################################################## # Cluster algebras ############################################################################## @@ -1317,16 +1318,14 @@ def __classcall__(self, data, **kwargs): # Determine the names of the initial cluster variables kwargs.setdefault('cluster_variable_prefix', 'x') - kwargs['cluster_variable_names'] = tuple(kwargs.get('cluster_variable_names', - [kwargs['cluster_variable_prefix'] + str(i) for i in range(n)])) + kwargs['cluster_variable_names'] = tuple(kwargs.get('cluster_variable_names', [kwargs['cluster_variable_prefix'] + str(i) for i in range(n)])) if len(kwargs['cluster_variable_names']) != n: raise ValueError("cluster_variable_names should be an iterable of %d valid variable names" % n) # Determine the names of the coefficients coefficient_prefix = kwargs.pop('coefficient_prefix', 'y') offset = n if coefficient_prefix == kwargs['cluster_variable_prefix'] else 0 - kwargs['coefficient_names'] = tuple(kwargs.get('coefficient_names', - [coefficient_prefix + str(i) for i in range(offset, m + offset)])) + kwargs['coefficient_names'] = tuple(kwargs.get('coefficient_names', [coefficient_prefix + str(i) for i in range(offset, m + offset)])) if len(kwargs['coefficient_names']) != m: raise ValueError("coefficient_names should be an iterable of %d valid variable names" % m) @@ -1335,11 +1334,8 @@ def __classcall__(self, data, **kwargs): # kwargs['cluster_variable_prefix']+str(j) is not the name of an # initial cluster variable nor a coefficient. This will be used in # mutate_initial to name new cluster variables. - splitnames = (w.partition(kwargs['cluster_variable_prefix']) - for w in - kwargs['cluster_variable_names'] + kwargs['coefficient_names']) - nfi = 1 + max((int(v) for u, _, v in splitnames - if u == '' and v.isdigit()), default=-1) + splitnames = (w.partition(kwargs['cluster_variable_prefix']) for w in kwargs['cluster_variable_names'] + kwargs['coefficient_names']) + nfi = 1 + max((int(v) for u, _, v in splitnames if u == '' and v.isdigit()), default=-1) kwargs.setdefault('next_free_index', nfi) # Determine scalars @@ -1379,7 +1375,7 @@ def __init__(self, B, **kwargs): # Rank self._n = B.ncols() - M0 = B[self._n:, :] + M0 = B[self._n :, :] m = M0.nrows() # Ambient space for F-polynomials @@ -1409,11 +1405,8 @@ def __init__(self, B, **kwargs): # Data to compute cluster variables using separation of additions # NOTE: storing both _B0 as rectangular matrix and _yhat is redundant. # We keep both around for speed purposes. - self._y = {self._U.gen(j): prod(self._base.gen(i) ** M0[i, j] for i in range(m)) - for j in range(self._n)} - self._yhat = {self._U.gen(j): prod(self._ambient.gen(i) ** self._B0[i, j] - for i in range(self._n + m)) - for j in range(self._n)} + self._y = {self._U.gen(j): prod(self._base.gen(i) ** M0[i, j] for i in range(m)) for j in range(self._n)} + self._yhat = {self._U.gen(j): prod(self._ambient.gen(i) ** self._B0[i, j] for i in range(self._n + m)) for j in range(self._n)} # Register embedding into self.ambient() embedding = SetMorphism(Hom(self, self.ambient()), lambda x: x.lift()) @@ -1525,7 +1518,7 @@ def _coerce_map_from_(self, other): m = M0.nrows() B = block_matrix([[self.b_matrix(), -M0.transpose()], [M0, matrix(m)]]) B.permute_rows_and_columns(perm, perm) - return B[:, :other.rank()] == other._B0 + return B[:, : other.rank()] == other._B0 # everything that is in the base can be coerced to self return self.base().has_coerce_map_from(other) @@ -1774,7 +1767,7 @@ def d_vector_to_g_vector(self, d) -> tuple: """ dm = vector(x if x < 0 else 0 for x in d) dp = vector(d) - dm - return tuple(- dm - self.euler_matrix() * dp) + return tuple(-dm - self.euler_matrix() * dp) def g_vector_to_d_vector(self, g) -> tuple: r""" @@ -2160,7 +2153,7 @@ def coefficient_names(self) -> tuple: sage: A2.coefficient_names() ('x3', 'x4', 'x5') """ - return self.variable_names()[self.rank():] + return self.variable_names()[self.rank() :] def initial_cluster_variable(self, j): r""" @@ -2190,7 +2183,7 @@ def initial_cluster_variables(self) -> tuple: sage: A.initial_cluster_variables() (x0, x1) """ - return tuple(map(self.retract, self.ambient().gens()[:self.rank()])) + return tuple(map(self.retract, self.ambient().gens()[: self.rank()])) def initial_cluster_variable_names(self) -> tuple: r""" @@ -2205,7 +2198,7 @@ def initial_cluster_variable_names(self) -> tuple: sage: A1.initial_cluster_variable_names() ('a0', 'a1') """ - return self.variable_names()[:self.rank()] + return self.variable_names()[: self.rank()] def seeds(self, **kwargs): r""" @@ -2266,8 +2259,7 @@ def seeds(self, **kwargs): mutating_F = kwargs.get('mutating_F', True) # which directions are we allowed to mutate into - allowed_dirs = sorted(kwargs.get('allowed_directions', - range(self.rank()))) + allowed_dirs = sorted(kwargs.get('allowed_directions', range(self.rank()))) # setup seeds storage cl = frozenset(seed.g_vectors()) @@ -2475,7 +2467,7 @@ def mutate_initial(self, direction, **kwargs): try: seq = iter(direction) except TypeError: - seq = iter((direction, )) + seq = iter((direction,)) # setup path_dict = copy(self._path_dict) @@ -2530,9 +2522,7 @@ def mutate_initial(self, direction, **kwargs): # create new algebra coeff_names = self.coefficient_names() scalars = self.scalars() - A = ClusterAlgebra(B0, cluster_variable_names=cv_names, - next_free_index=nfi, - coefficient_names=coeff_names, scalars=scalars) + A = ClusterAlgebra(B0, cluster_variable_names=cv_names, next_free_index=nfi, coefficient_names=coeff_names, scalars=scalars) # store computed data A._path_dict.update(path_dict) diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index 606c2e67149..9f324502b6f 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -139,8 +139,7 @@ def sorting_keys(element): return list(CR(V(x.basis_coefficients()))) -class Differential(UniqueRepresentation, Morphism, - metaclass=InheritComparisonClasscallMetaclass): +class Differential(UniqueRepresentation, Morphism, metaclass=InheritComparisonClasscallMetaclass): r""" Differential of a commutative graded algebra. @@ -163,6 +162,7 @@ class Differential(UniqueRepresentation, Morphism, sage: B.differential()(x) x*y """ + @staticmethod def __classcall__(cls, A, im_gens): r""" @@ -216,7 +216,7 @@ def image_monomial(exponent): cexp[i] -= 1 b = A.prod(A.gen(j) ** cexp[j] for j in range(len(cexp))) db = image_monomial(cexp) - im = da * b + (-1)**A._degrees[i] * a * db + im = da * b + (-1) ** A._degrees[i] * a * db return A(im) return A.zero() @@ -228,10 +228,7 @@ def image_monomial(exponent): for i in im_gens: x = im_gens[i] - if (not x.is_zero() - and (not x.is_homogeneous() - or total_degree(x.degree()) - != total_degree(i.degree()) + 1)): + if not x.is_zero() and (not x.is_homogeneous() or total_degree(x.degree()) != total_degree(i.degree()) + 1): raise ValueError("the given dictionary does not determine a degree 1 map") im_gens = tuple(im_gens.get(x, A.zero()) for x in A.gens()) @@ -310,13 +307,10 @@ def _call_(self, x): while keyl: exp = keyl.pop(0) if exp > 0: - v1 = (exp * self._dic_[x.parent().gen(idx)] - * x.parent().gen(idx)**(exp - 1)) - v2 = prod(x.parent().gen(i + idx + 1)**keyl[i] for i in - range(len(keyl))) + v1 = exp * self._dic_[x.parent().gen(idx)] * x.parent().gen(idx) ** (exp - 1) + v2 = prod(x.parent().gen(i + idx + 1) ** keyl[i] for i in range(len(keyl))) res += coef * v1 * v2 - coef *= ((-1) ** total_degree(x.parent()._degrees[idx]) - * x.parent().gen(idx)**exp) + coef *= (-1) ** total_degree(x.parent()._degrees[idx]) * x.parent().gen(idx) ** exp idx += 1 return res @@ -558,14 +552,10 @@ def cohomology(self, n): H_basis_raw = (H.lift(H.basis()[i]) for i in range(H.dimension())) A = self.domain() B = A.basis(n) - H_basis = (sum(c * b for (c, b) in zip(coeffs, B)) - for coeffs in H_basis_raw) + H_basis = (sum(c * b for (c, b) in zip(coeffs, B)) for coeffs in H_basis_raw) # Put brackets around classes. H_basis_brackets = [CohomologyClass(b, A) for b in H_basis] - return CombinatorialFreeModule(A.base_ring(), - H_basis_brackets, - sorting_key=sorting_keys, - monomial_reverse=True) + return CombinatorialFreeModule(A.base_ring(), H_basis_brackets, sorting_key=sorting_keys, monomial_reverse=True) homology = cohomology @@ -598,6 +588,7 @@ class Differential_multigraded(Differential): """ Differential of a commutative multi-graded algebra. """ + def __init__(self, A, im_gens): """ Initialize ``self``. @@ -852,14 +843,10 @@ def cohomology(self, n, total=False): H_basis_raw = (H.lift(H.basis()[i]) for i in range(H.dimension())) A = self.domain() B = A.basis(n, total) - H_basis = (sum(c * b for (c, b) in zip(coeffs, B)) - for coeffs in H_basis_raw) + H_basis = (sum(c * b for (c, b) in zip(coeffs, B)) for coeffs in H_basis_raw) # Put brackets around classes. H_basis_brackets = [CohomologyClass(b, A) for b in H_basis] - return CombinatorialFreeModule(A.base_ring(), - H_basis_brackets, - sorting_key=sorting_keys, - monomial_reverse=True) + return CombinatorialFreeModule(A.base_ring(), H_basis_brackets, sorting_key=sorting_keys, monomial_reverse=True) homology = cohomology @@ -867,6 +854,7 @@ def cohomology(self, n, total=False): ########################################################### # Commutative graded algebras + class GCAlgebra(UniqueRepresentation, QuotientRing_nc): r""" A graded commutative algebra. @@ -921,6 +909,7 @@ class GCAlgebra(UniqueRepresentation, QuotientRing_nc): Note that the function :func:`GradedCommutativeAlgebra` can also be used to construct these algebras. """ + # TODO: This should be a __classcall_private__? @staticmethod def __classcall__(cls, base, names=None, degrees=None, R=None, I=None, category=None): @@ -1000,22 +989,17 @@ def __classcall__(cls, base, names=None, degrees=None, R=None, I=None, category= tot_degs = [total_degree(d) for d in degrees] for i in range(len(gens) - 1): for j in range(i + 1, len(gens)): - rels[gens[j] * gens[i]] = ((-1)**(tot_degs[i] * tot_degs[j]) - * gens[i] * gens[j]) + rels[gens[j] * gens[i]] = (-1) ** (tot_degs[i] * tot_degs[j]) * gens[i] * gens[j] if n > 1: R = F.g_algebra(rels, order=TermOrder('wdegrevlex', tot_degs)) - else: # n = 1 + else: # n = 1 R = F.quotient(rels) if base.characteristic() == 2: I = R.ideal(0, side='twosided') else: - I = R.ideal([R.gen(i)**2 - for i in range(n) if is_odd(tot_degs[i])], - side='twosided') + I = R.ideal([R.gen(i) ** 2 for i in range(n) if is_odd(tot_degs[i])], side='twosided') - return super().__classcall__(cls, base=base, names=names, - degrees=degrees, R=R, I=I, - category=category) + return super().__classcall__(cls, base=base, names=names, degrees=degrees, R=R, I=I, category=category) def __init__(self, base, R=None, I=None, names=None, degrees=None, category=None): """ @@ -1068,8 +1052,7 @@ def _repr_(self) -> str: R = self.cover_ring() degrees = self._degrees if self.base().characteristic() != 2: - squares = [R.gen(i)**2 - for i in range(len(degrees)) if is_odd(degrees[i])] + squares = [R.gen(i) ** 2 for i in range(len(degrees)) if is_odd(degrees[i])] else: squares = [R.zero()] relns = [g for g in I.gens() if g not in squares] @@ -1126,11 +1109,9 @@ def _basis_for_free_alg(self, n): odd_degrees.append(a) if not even_degrees: # No even generators. - return [tuple(_) - for _ in exterior_algebra_basis(n, tuple(odd_degrees))] + return [tuple(_) for _ in exterior_algebra_basis(n, tuple(odd_degrees))] if not odd_degrees: # No odd generators. - return [tuple(_) - for _ in WeightedIntegerVectors(n, tuple(even_degrees))] + return [tuple(_) for _ in WeightedIntegerVectors(n, tuple(even_degrees))] # General case: both even and odd generators. result = [] @@ -1180,10 +1161,10 @@ def basis(self, n): free_basis = (tuple(reversed(e)) for e in fb_reversed_entries) basis = [] for v in free_basis: - el = prod([self.gen(i)**v[i] for i in range(len(v))]) + el = prod([self.gen(i) ** v[i] for i in range(len(v))]) di = el.monomial_coefficients() if len(di) == 1: - k, = di.keys() + (k,) = di.keys() if tuple(k) == v: basis.append(el) return basis @@ -1245,9 +1226,7 @@ def _coerce_map_from_(self, other): if isinstance(other, GCAlgebra): if self._names != other._names or self._degrees != other._degrees: return False - if set(self.defining_ideal().gens()) != set(other - .defining_ideal() - .gens()): + if set(self.defining_ideal().gens()) != set(other.defining_ideal().gens()): return False return self.cover_ring().has_coerce_map_from(other.cover_ring()) return super()._coerce_map_from_(other) @@ -1276,7 +1255,7 @@ def _element_constructor_(self, x, coerce=True): if isinstance(x, dict): res = self.zero() for i in x.keys(): - mon = prod(self.gen(j)**i[j] for j in range(len(i))) + mon = prod(self.gen(j) ** i[j] for j in range(len(i))) res += x[i] * mon return res if coerce: @@ -1328,13 +1307,10 @@ def _Hom_(self, B, category): # categories for self and B, which might be the category of # rings). if R != B.base_ring(): - raise NotImplementedError('homomorphisms of graded commutative ' - 'algebras have only been implemented ' - 'when the base rings are the same') + raise NotImplementedError('homomorphisms of graded commutative ' 'algebras have only been implemented ' 'when the base rings are the same') cat = Algebras(R).Graded() if category is not None and not category.is_subcategory(cat): - raise TypeError("{} is not a subcategory of graded algebras" - .format(category)) + raise TypeError("{} is not a subcategory of graded algebras".format(category)) return GCAlgebraHomset(self, B, category=category) def differential(self, diff): @@ -1419,6 +1395,7 @@ class Element(QuotientRingElement): r""" An element of a graded commutative algebra. """ + def __init__(self, A, rep): r""" Initialize ``self``. @@ -1631,11 +1608,11 @@ def __call__(self, *values, **kwargs): gens = self.parent().gens() images = list(gens) if values and not isinstance(values[0], dict): - for (i, p) in enumerate(values): + for i, p in enumerate(values): images[i] = p if len(values) == 1 and isinstance(values[0], dict): images = list(gens) - for (i, g) in enumerate(gens): + for i, g in enumerate(gens): if g in values[0]: images[i] = values[0][g] elif len(values) == len(gens): @@ -1644,13 +1621,13 @@ def __call__(self, *values, **kwargs): raise ValueError("number of arguments does not match number of variables in parent") else: images = list(gens) - for (i, g) in enumerate(gens): + for i, g in enumerate(gens): gstr = str(g) if gstr in kwargs: images[i] = kwargs[gstr] res = 0 for m, c in self.monomial_coefficients().items(): - term = prod((gen ** y for y, gen in zip(m, images)), c) + term = prod((gen**y for y, gen in zip(m, images)), c) res += term return res @@ -1766,6 +1743,7 @@ class GCAlgebra_multigraded(GCAlgebra): sage: c.degree(total=True) 2 """ + def __init__(self, base, degrees, names=None, R=None, I=None, category=None): """ Initialize ``self``. @@ -1780,8 +1758,7 @@ def __init__(self, base, degrees, names=None, R=None, I=None, category=None): sage: TestSuite(C).run() """ total_degs = [total_degree(d) for d in degrees] - GCAlgebra.__init__(self, base, R=R, I=I, names=names, - degrees=total_degs, category=category) + GCAlgebra.__init__(self, base, R=R, I=I, names=names, degrees=total_degs, category=category) self._degrees_multi = degrees self._grading_rank = len(list(degrees[0])) @@ -1837,8 +1814,7 @@ def quotient(self, I, check=True): gens2 = [i.lift() for i in I.gens()] gens = [g for g in gens1 + gens2 if g != NCR.zero()] J = NCR.ideal(gens, side='twosided') - return GCAlgebra_multigraded(self.base_ring(), self._names, - self._degrees_multi, NCR, J) + return GCAlgebra_multigraded(self.base_ring(), self._names, self._degrees_multi, NCR, J) def _coerce_map_from_(self, other): r""" @@ -1858,7 +1834,7 @@ def _coerce_map_from_(self, other): if isinstance(other, GCAlgebra_multigraded): if self._degrees_multi != other._degrees_multi: return False - elif isinstance(other, GCAlgebra): # Not multigraded + elif isinstance(other, GCAlgebra): # Not multigraded return False return super()._coerce_map_from_(other) @@ -2014,6 +1990,7 @@ def degree(self, total=False): ########################################################### # Differential algebras + class DifferentialGCAlgebra(GCAlgebra): """ A commutative differential graded algebra. @@ -2062,6 +2039,7 @@ class DifferentialGCAlgebra(GCAlgebra): See the function :func:`GradedCommutativeAlgebra` for more examples. """ + @staticmethod def __classcall__(cls, A, differential): """ @@ -2117,9 +2095,7 @@ def __init__(self, A, differential): ValueError: the given dictionary does not determine a valid differential """ cat = Algebras(A.base()).Graded() & ChainComplexes(A.base()) - GCAlgebra.__init__(self, A.base(), names=A._names, - degrees=A._degrees, R=A.cover_ring(), - I=A.defining_ideal(), category=cat) + GCAlgebra.__init__(self, A.base(), names=A._names, degrees=A._degrees, R=A.cover_ring(), I=A.defining_ideal(), category=cat) self._differential = Differential(self, differential._dic_) self._minimalmodels = {} self._numerical_invariants = {} @@ -2181,8 +2157,7 @@ def graded_commutative_algebra(self): sage: D.graded_commutative_algebra() == A True """ - return GCAlgebra(self.base(), names=self._names, degrees=self._degrees, - R=self.cover_ring(), I=self.defining_ideal()) + return GCAlgebra(self.base(), names=self._names, degrees=self._degrees, R=self.cover_ring(), I=self.defining_ideal()) def _base_repr(self): """ @@ -2496,8 +2471,7 @@ def cohomology_generators(self, max_degree): {1: [e1 - e2, e3, e4], 2: [e1*e3, e1*e4]} """ if not (max_degree in ZZ and max_degree > 0): - raise ValueError('the given maximal degree must be a ' - 'positive integer') + raise ValueError('the given maximal degree must be a ' 'positive integer') def vector_to_element(v, deg): """ @@ -2506,28 +2480,23 @@ def vector_to_element(v, deg): algebra again. """ return sum(c * b for (c, b) in zip(v, self.basis(deg))) + if max_degree == 1: cohom1 = self.cohomology(1).basis().keys() if not cohom1: return {} return {1: [g.representative() for g in cohom1]} - smaller_degree = {i: [g.representative() for g in - self.cohomology(i).basis().keys()] for i in - range(1, max_degree)} + smaller_degree = {i: [g.representative() for g in self.cohomology(i).basis().keys()] for i in range(1, max_degree)} already_generated = [] for i in range(1, max_degree): - already_generated += [a * b for a in smaller_degree[i] for b in - smaller_degree[max_degree - i]] + already_generated += [a * b for a in smaller_degree[i] for b in smaller_degree[max_degree - i]] CR = self.cohomology_raw(max_degree) V = CR.V() - S = CR.submodule([CR(V(g.basis_coefficients(total=True))) for g in - already_generated if not g.is_zero()]) + S = CR.submodule([CR(V(g.basis_coefficients(total=True))) for g in already_generated if not g.is_zero()]) Q = CR.quotient(S) res = self.cohomology_generators(max_degree - 1) if Q.basis(): - res[max_degree] = [vector_to_element(CR.lift(Q.lift(g)), - max_degree) - for g in Q.basis()] + res[max_degree] = [vector_to_element(CR.lift(Q.lift(g)), max_degree) for g in Q.basis()] return res def minimal_model(self, i=3, max_iterations=3, partial_result=False): @@ -2752,21 +2721,19 @@ def extend(phi, ndegrees, ndifs, nimags, nnames): B = phi.domain() names = [str(g) for g in B.gens()] degrees = [g.degree() for g in B.gens()] - A = GradedCommutativeAlgebra(B.base_ring(), names=names + nnames, - degrees=degrees + ndegrees) - h = B.hom(A.gens()[:B.ngens()], check=False) + A = GradedCommutativeAlgebra(B.base_ring(), names=names + nnames, degrees=degrees + ndegrees) + h = B.hom(A.gens()[: B.ngens()], check=False) d = B.differential() diff = {h(g): h(d(g)) for g in B.gens()} cndifs = copy(ndifs) - for g in A.gens()[B.ngens():]: + for g in A.gens()[B.ngens() :]: diff[g] = h(cndifs.pop(0)) NB = A.cdg_algebra(diff) return NB.hom([phi(g) for g in B.gens()] + nimags, check=False) def extendx(phi, degree): B = phi.domain() - imagesbcohom = [phi(g.representative()) - for g in B.cohomology(degree).basis().keys()] + imagesbcohom = [phi(g.representative()) for g in B.cohomology(degree).basis().keys()] CS = self.cohomology_raw(degree) VS = CS.V() CB = B.cohomology_raw(degree) @@ -2789,16 +2756,14 @@ def extendx(phi, degree): nbasis.append(g) nimags = nbasis ndegrees = [degree for _ in nbasis] - return extend(phi, ndegrees, [B.zero() for _ in nimags], - nimags, nnames) + return extend(phi, ndegrees, [B.zero() for _ in nimags], nimags, nnames) return phi def extendy(phi, degree): nnamesy = 0 for iteration in range(max_iterations): B = phi.domain() - imagesbcohom = [phi(g.representative()) - for g in B.cohomology(degree).basis().keys()] + imagesbcohom = [phi(g.representative()) for g in B.cohomology(degree).basis().keys()] CS = self.cohomology_raw(degree) VS = CS.V() CB = B.cohomology_raw(degree) @@ -2817,8 +2782,7 @@ def extendy(phi, degree): return (phi,) ndifs = [CB.lift(g) for g in K.basis()] basisdegree = B.basis(degree) - ndifs = [sum(basisdegree[j] * g[j] for j in - range(len(basisdegree))) for g in ndifs] + ndifs = [sum(basisdegree[j] * g[j] for j in range(len(basisdegree))) for g in ndifs] MS = self.differential().differential_matrix(degree - 1) nimags = [] for g in ndifs: @@ -2826,12 +2790,9 @@ def extendy(phi, degree): nimags.append(vector(MS.nrows() * [0])) else: nimags.append(MS.solve_left(vector(phi(g).basis_coefficients()))) - nimags = [sum(self.basis(degree - 1)[j] * g[j] - for j in range(len(self.basis(degree - 1))) - ) for g in nimags] + nimags = [sum(self.basis(degree - 1)[j] * g[j] for j in range(len(self.basis(degree - 1)))) for g in nimags] ndegrees = [degree - 1 for g in nimags] - nnames = ['y{}_{}'.format(degree - 1, j + nnamesy) - for j in range(len(nimags))] + nnames = ['y{}_{}'.format(degree - 1, j + nnamesy) for j in range(len(nimags))] nnamesy += len(nimags) phi = extend(phi, ndegrees, ndifs, nimags, nnames) @@ -2842,13 +2803,10 @@ def extendy(phi, degree): degnzero += 1 if degnzero > max_degree: raise ValueError("cohomology is trivial up to max_degree") - gens = [g.representative() - for g in self.cohomology(degnzero).basis().keys()] + gens = [g.representative() for g in self.cohomology(degnzero).basis().keys()] self._numerical_invariants[degnzero] = [len(gens)] names = ['x{}_{}'.format(degnzero, j) for j in range(len(gens))] - A = GradedCommutativeAlgebra(self.base_ring(), - names, - degrees=[degnzero for _ in names]) + A = GradedCommutativeAlgebra(self.base_ring(), names, degrees=[degnzero for _ in names]) B = A.cdg_algebra(A.differential({})) # Solve case that fails with one generator return B,gens phi = B.hom(gens) @@ -2918,9 +2876,7 @@ def cohomology_algebra(self, max_degree=3): for g in cohomgens[d]: degrees.append(d) chgens.append(g) - A = GradedCommutativeAlgebra(self.base_ring(), - [f'x{i}' for i in range(len(chgens))], - degrees) + A = GradedCommutativeAlgebra(self.base_ring(), [f'x{i}' for i in range(len(chgens))], degrees) rels = [] for d in range(1, max_degree + 1): B1 = A.basis(d) @@ -2932,7 +2888,7 @@ def cohomology_algebra(self, max_degree=3): images.append(V2.zero()) else: images.append(V2(V2.V()(ig.basis_coefficients()))) - V1 = self.base_ring()**len(B1) + V1 = self.base_ring() ** len(B1) h = V1.hom(images, codomain=V2) K = h.kernel() for g in K.basis(): @@ -2998,8 +2954,7 @@ def numerical_invariants(self, max_degree=3, max_iterations=3): For a precise definition and properties, see [Man2019]_ . """ self.minimal_model(max_degree, max_iterations) - return {i: self._numerical_invariants[i] - for i in range(1, max_degree + 1)} + return {i: self._numerical_invariants[i] for i in range(1, max_degree + 1)} def is_formal(self, i, max_iterations=3) -> bool: r""" @@ -3052,15 +3007,15 @@ def is_formal(self, i, max_iterations=3) -> bool: try: H.minimal_model(i, max_iterations) except ValueError: # If we could compute the minimal model in max_iterations - return False # but not for the cohomology, the invariants are distinct + return False # but not for the cohomology, the invariants are distinct N1 = self.numerical_invariants(i, max_iterations) N2 = H.numerical_invariants(i, max_iterations) if any(N1[n] != N2[n] for n in range(1, i + 1)): - return False # numerical invariants don't match + return False # numerical invariants don't match subsdict = {y.lift(): 0 for y in M.gens() if not y.differential().is_zero()} tocheck = [M(g.differential().lift().subs(subsdict)) for g in M.gens()] if all(c.is_coboundary() for c in tocheck): - return True # the morphism xi->[xi], yi->0 is i-quasi-iso + return True # the morphism xi->[xi], yi->0 is i-quasi-iso raise NotImplementedError("the implemented criteria cannot determine formality") class Element(GCAlgebra.Element): @@ -3145,8 +3100,7 @@ def is_cohomologous_to(self, other) -> bool: """ if other.is_zero(): return self.is_coboundary() - if (not isinstance(other, DifferentialGCAlgebra.Element) - or self.parent() is not other.parent()): + if not isinstance(other, DifferentialGCAlgebra.Element) or self.parent() is not other.parent(): raise ValueError(f'the element {other} does not lie in this DGA') if (self - other).is_homogeneous(): return (self - other).is_coboundary() @@ -3225,6 +3179,7 @@ def _cohomology_class_dict(self): [x0, x1, x2, x3, x4, x5, x6, x7, x8] """ from sage.misc.flatten import flatten + if not self.differential().is_zero(): raise ValueError("the element is not closed") if not self.is_homogeneous(): @@ -3235,16 +3190,13 @@ def _cohomology_class_dict(self): d = self.degree() gens = flatten(self.parent().cohomology_generators(d).values()) ebasis = exterior_algebra_basis(d, tuple(g.degree() for g in gens)) - gensd = [prod([gens[i]**b[i] - for i in range(len(b))]) for b in ebasis] + gensd = [prod([gens[i] ** b[i] for i in range(len(b))]) for b in ebasis] m = matrix([g.cohomology_class()._vector_() for g in gensd]) coeffs = m.solve_left(self.cohomology_class()._vector_()) - return {tuple(ebasis[i]): coeffs[i] - for i in range(len(ebasis)) if coeffs[i]} + return {tuple(ebasis[i]): coeffs[i] for i in range(len(ebasis)) if coeffs[i]} -class DifferentialGCAlgebra_multigraded(DifferentialGCAlgebra, - GCAlgebra_multigraded): +class DifferentialGCAlgebra_multigraded(DifferentialGCAlgebra, GCAlgebra_multigraded): """ A commutative differential multi-graded algebras. @@ -3267,6 +3219,7 @@ class DifferentialGCAlgebra_multigraded(DifferentialGCAlgebra, sage: B.cohomology(1, total=True) Free module generated by {[b]} over Rational Field """ + def __init__(self, A, differential): """ Initialize ``self``. @@ -3292,10 +3245,7 @@ def __init__(self, A, differential): ValueError: the differential does not have a well-defined degree """ cat = Algebras(A.base()).Graded() & ChainComplexes(A.base()) - GCAlgebra_multigraded.__init__(self, A.base(), names=A._names, - degrees=A._degrees_multi, - R=A.cover_ring(), I=A.defining_ideal(), - category=cat) + GCAlgebra_multigraded.__init__(self, A.base(), names=A._names, degrees=A._degrees_multi, R=A.cover_ring(), I=A.defining_ideal(), category=cat) self._differential = Differential_multigraded(self, differential._dic_) def _base_repr(self): @@ -3458,12 +3408,12 @@ class Element(GCAlgebra_multigraded.Element, DifferentialGCAlgebra.Element): Element class of a commutative differential multi-graded algebra. """ + ################################################ # Main entry point -def GradedCommutativeAlgebra(ring, names=None, degrees=None, max_degree=None, - **kwargs): +def GradedCommutativeAlgebra(ring, names=None, degrees=None, max_degree=None, **kwargs): r""" A graded commutative algebra. @@ -3650,8 +3600,8 @@ def GradedCommutativeAlgebra(ring, names=None, degrees=None, max_degree=None, """ if max_degree: from sage.algebras.finite_gca import FiniteGCAlgebra - return FiniteGCAlgebra(ring, names=names, degrees=degrees, - max_degree=max_degree, **kwargs) + + return FiniteGCAlgebra(ring, names=names, degrees=degrees, max_degree=max_degree, **kwargs) multi = False if degrees: try: @@ -3669,6 +3619,7 @@ def GradedCommutativeAlgebra(ring, names=None, degrees=None, max_degree=None, ################################################ # Morphisms + class GCAlgebraMorphism(RingHomomorphism_im_gens): """ Create a morphism between two :class:`graded commutative algebras `. @@ -3697,6 +3648,7 @@ class GCAlgebraMorphism(RingHomomorphism_im_gens): sage: f(x*y) -x*y """ + def __init__(self, parent, im_gens, check=True): r""" TESTS: @@ -3793,15 +3745,12 @@ def __init__(self, parent, im_gens, check=True): # We use check=False here because checking of nc-relations is # not implemented in RingHomomorphism_im_gens.__init__. # We check these relations below. - RingHomomorphism_im_gens.__init__(self, parent=parent, - im_gens=im_gens, - check=False) + RingHomomorphism_im_gens.__init__(self, parent=parent, im_gens=im_gens, check=False) self._im_gens = tuple(im_gens) # Now check that the relations are respected. if check: if any(x not in codomain for x in im_gens): - raise ValueError('not all elements of im_gens are in ' - 'the codomain') + raise ValueError('not all elements of im_gens are in ' 'the codomain') R = domain.cover_ring() from_R = dict(zip(R.gens(), im_gens)) if hasattr(R, 'free_algebra'): @@ -3812,26 +3761,21 @@ def __init__(self, parent, im_gens, check=True): for left in R.relations(): zero = left.subs(from_free) - R.relations()[left].subs(from_R) if zero: - raise ValueError('the proposed morphism does not respect ' - 'the nc-relations') + raise ValueError('the proposed morphism does not respect ' 'the nc-relations') # Now check any extra relations, including x**2=0 for x in # odd degree. These are defined by a list of generators of # the defining ideal. for g in domain.defining_ideal().gens(): zero = g.subs(from_R) if zero: - raise ValueError('the proposed morphism does not respect ' - 'the relations') + raise ValueError('the proposed morphism does not respect ' 'the relations') # If the domain and codomain have differentials, check # those, too. - if (isinstance(domain, DifferentialGCAlgebra) - and isinstance(codomain, DifferentialGCAlgebra)): + if isinstance(domain, DifferentialGCAlgebra) and isinstance(codomain, DifferentialGCAlgebra): dom_diff = domain.differential() cod_diff = codomain.differential() - if any(cod_diff(self(g)) != self(dom_diff(g)) - for g in domain.gens()): - raise ValueError('the proposed morphism does not respect ' - 'the differentials') + if any(cod_diff(self(g)) != self(dom_diff(g)) for g in domain.gens()): + raise ValueError('the proposed morphism does not respect ' 'the differentials') def _call_(self, x): """ @@ -3866,8 +3810,7 @@ def _call_(self, x): codomain = self.codomain() result = codomain.zero() for mono, coeff in x.monomial_coefficients().items(): - term = prod([gen**y for (y, gen) in zip(mono, self.im_gens())], - codomain.one()) + term = prod([gen**y for (y, gen) in zip(mono, self.im_gens())], codomain.one()) result += coeff * term return result @@ -3904,10 +3847,7 @@ def is_graded(self, total=False) -> bool: sage: H([z,z]).is_graded(total=True) True """ - return all(not y # zero is always allowed as an image - or (y.is_homogeneous() - and x.degree(total=total) == y.degree(total=total)) - for (x, y) in zip(self.domain().gens(), self.im_gens())) + return all(not y or (y.is_homogeneous() and x.degree(total=total) == y.degree(total=total)) for (x, y) in zip(self.domain().gens(), self.im_gens())) # zero is always allowed as an image def _repr_type(self) -> str: """ @@ -3922,8 +3862,7 @@ def _repr_type(self) -> str: sage: Hom(C,C)([x,0,0])._repr_type() 'Commutative Differential Graded Algebra' """ - if (isinstance(self.domain(), DifferentialGCAlgebra) - and isinstance(self.codomain(), DifferentialGCAlgebra)): + if isinstance(self.domain(), DifferentialGCAlgebra) and isinstance(self.codomain(), DifferentialGCAlgebra): return "Commutative Differential Graded Algebra" return "Graded Commutative Algebra" @@ -3942,6 +3881,7 @@ def _repr_defn(self) -> str: ################################################ # Homsets + class GCAlgebraHomset(RingHomset_generic): """ Set of morphisms between two graded commutative algebras. @@ -3993,8 +3933,7 @@ def zero(self): sage: zero(x) == zero(y) == 0 True """ - return GCAlgebraMorphism(self, [self.codomain().zero()] - * self.domain().ngens()) + return GCAlgebraMorphism(self, [self.codomain().zero()] * self.domain().ngens()) @cached_method def identity(self): @@ -4011,8 +3950,7 @@ def identity(self): False """ if self.domain() != self.codomain(): - raise TypeError('identity map is only defined for ' - 'endomorphism sets') + raise TypeError('identity map is only defined for ' 'endomorphism sets') return GCAlgebraMorphism(self, self.domain().gens()) def __call__(self, im_gens, check=True): @@ -4040,6 +3978,7 @@ def __call__(self, im_gens, check=True): Defn: (w, x) --> (y, y*z) """ from sage.categories.map import Map + if isinstance(im_gens, Map): return self._coerce_impl(im_gens) return GCAlgebraMorphism(self, im_gens, check=check) @@ -4048,6 +3987,7 @@ def __call__(self, im_gens, check=True): ################################################ # Miscellaneous utility classes and functions + class CohomologyClass(SageObject, CachedRepresentation): """ A class for representing cohomology classes. @@ -4107,6 +4047,7 @@ class CohomologyClass(SageObject, CachedRepresentation): e6 --> e1*e2 + e3*e4 Defn: (x1_0, x1_1, x1_2, x1_3, y1_0, y1_1) --> (e1, e2, e3, e4, e5, -e5 + e6) """ + def __init__(self, x, cdga=None): """ EXAMPLES:: @@ -4149,6 +4090,7 @@ def _latex_(self) -> str: \left[ x^{2} \right] """ from sage.misc.latex import latex + return '\\left[ {} \\right]'.format(latex(self._x)) def representative(self): diff --git a/src/sage/algebras/down_up_algebra.py b/src/sage/algebras/down_up_algebra.py index 8574fd712f0..5c632ab92ce 100644 --- a/src/sage/algebras/down_up_algebra.py +++ b/src/sage/algebras/down_up_algebra.py @@ -165,6 +165,7 @@ class DownUpAlgebra(CombinatorialFreeModule): - [BR1998]_ - [CM2000]_ """ + @staticmethod def __classcall_private__(cls, alpha, beta, gamma, base_ring=None): r""" @@ -181,6 +182,7 @@ def __classcall_private__(cls, alpha, beta, gamma, base_ring=None): """ if base_ring is None: from sage.structure.element import get_coercion_model + base_ring = get_coercion_model().common_parent(alpha, beta, gamma) if base_ring not in Rings().Commutative(): raise TypeError("base ring must be a commutative ring") @@ -209,6 +211,7 @@ def __init__(self, alpha, beta, gamma, base_ring): cat = Algebras(base_ring).WithBasis().Graded() if self._beta: from sage.categories.domains import Domains + cat &= Domains() indices = cartesian_product([NonNegativeIntegers()] * 3) CombinatorialFreeModule.__init__(self, base_ring, indices, category=cat, sorting_reverse=True) @@ -224,8 +227,7 @@ def _repr_(self) -> str: sage: DU Down-Up algebra with parameters (1, 2, 3) over Integer Ring """ - return "Down-Up algebra with parameters ({}, {}, {}) over {}".format( - self._alpha, self._beta, self._gamma, self.base_ring()) + return "Down-Up algebra with parameters ({}, {}, {}) over {}".format(self._alpha, self._beta, self._gamma, self.base_ring()) def _latex_(self) -> str: r""" @@ -313,8 +315,8 @@ def algebra_generators(self): sage: dict(DU.algebra_generators()) {'d': d, 'u': u} """ - u = self.monomial(self._indices([1,0,0])) - d = self.monomial(self._indices([0,0,1])) + u = self.monomial(self._indices([1, 0, 0])) + d = self.monomial(self._indices([0, 0, 1])) return Family({'d': d, 'u': u}) @cached_method @@ -395,41 +397,33 @@ def product_on_basis(self, m1, m2): if not d1: if not u2: - return self.monomial(I([u1, du1+du2, d2])) + return self.monomial(I([u1, du1 + du2, d2])) # else u2 > 0 if not du1: - return self.monomial(I([u1+u2, du2, d2])) + return self.monomial(I([u1 + u2, du2, d2])) # Perform du * u reduction - lhs = self.monomial(I([u1, du1-1, 0])) - mid = self._from_dict({I([1,1,0]): self._alpha, - I([2,0,1]): self._beta, - I([1,0,0]): self._gamma}) - rhs = self.monomial(I([u2-1, du2, d2])) + lhs = self.monomial(I([u1, du1 - 1, 0])) + mid = self._from_dict({I([1, 1, 0]): self._alpha, I([2, 0, 1]): self._beta, I([1, 0, 0]): self._gamma}) + rhs = self.monomial(I([u2 - 1, du2, d2])) else: # d1 > 0 if not u2: if not du2: - return self.monomial(I([u1, du1, d1+d2])) + return self.monomial(I([u1, du1, d1 + d2])) # Perform a d * du reduction - lhs = self.monomial(I([u1, du1, d1-1])) - mid = self._from_dict({I([0,1,1]): self._alpha, - I([1,0,2]): self._beta, - I([0,0,1]): self._gamma}) - rhs = self.monomial(I([0, du2-1, d2])) + lhs = self.monomial(I([u1, du1, d1 - 1])) + mid = self._from_dict({I([0, 1, 1]): self._alpha, I([1, 0, 2]): self._beta, I([0, 0, 1]): self._gamma}) + rhs = self.monomial(I([0, du2 - 1, d2])) elif u2 > 1: # Perform d * u^2 reduction - lhs = self.monomial(I([u1, du1, d1-1])) - mid = self._from_dict({I([1,1,0]): self._alpha, - I([2,0,1]): self._beta, - I([1,0,0]): self._gamma}) - rhs = self.monomial(I([u2-2, du2, d2])) + lhs = self.monomial(I([u1, du1, d1 - 1])) + mid = self._from_dict({I([1, 1, 0]): self._alpha, I([2, 0, 1]): self._beta, I([1, 0, 0]): self._gamma}) + rhs = self.monomial(I([u2 - 2, du2, d2])) elif u2 == 1: if d1 == 1: - return self.monomial(I([u1, du1+du2+1, d2])) + return self.monomial(I([u1, du1 + du2 + 1, d2])) # Perform a d^2 * u reduction - lhs = self.monomial(I([u1, du1, d1-2])) - mid = self._from_dict({I([0,1,1]): self._alpha, - I([1,0,2]): self._beta, - I([0,0,1]): self._gamma}) + lhs = self.monomial(I([u1, du1, d1 - 2])) + mid = self._from_dict({I([0, 1, 1]): self._alpha, I([1, 0, 2]): self._beta, I([0, 0, 1]): self._gamma}) rhs = self.monomial(I([0, du2, d2])) if lhs == self.one(): @@ -555,6 +549,7 @@ class VermaModule(CombinatorialFreeModule): sage: list(V.weights()[:8]) [5, 5*z6 + 5, 10*z6, 10*z6 - 5, 5*z6 - 5, 0, 5, 5*z6 + 5] """ + @staticmethod def __classcall_private__(cls, DU, la): """ @@ -617,8 +612,7 @@ def _la_iter(): self._weights = lazy_list(_la_iter()) cat = Modules(R).WithBasis() - CombinatorialFreeModule.__init__(self, R, NonNegativeIntegers(), - prefix='v', category=cat) + CombinatorialFreeModule.__init__(self, R, NonNegativeIntegers(), prefix='v', category=cat) def _repr_(self) -> str: r""" @@ -732,6 +726,7 @@ class Element(CombinatorialFreeModule.Element): r""" An element of a Verma module of a down-up algebra. """ + def _acted_upon_(self, scalar, self_on_left): r""" Return the action of ``scalar`` (an element of the base ring or @@ -769,9 +764,7 @@ def _acted_upon_(self, scalar, self_on_left): return None if self_on_left: return None - return P.linear_combination((P._action_on_basis(m, n), mc*nc) - for m, mc in scalar._monomial_coefficients.items() - for n, nc in self._monomial_coefficients.items()) + return P.linear_combination((P._action_on_basis(m, n), mc * nc) for m, mc in scalar._monomial_coefficients.items() for n, nc in self._monomial_coefficients.items()) def is_weight_vector(self) -> bool: r""" @@ -808,7 +801,7 @@ def is_weight_vector(self) -> bool: def get_wt(n): if not n: return (R(P._weights[0]), R.zero()) - return (R(P._weights[n]), R(P._weights[n-1])) + return (R(P._weights[n]), R(P._weights[n - 1])) it = iter(self._monomial_coefficients) wt = get_wt(next(it)) diff --git a/src/sage/algebras/exterior_algebra_groebner.pyi b/src/sage/algebras/exterior_algebra_groebner.pyi index 7aff993da24..daf65968b33 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyi +++ b/src/sage/algebras/exterior_algebra_groebner.pyi @@ -15,12 +15,8 @@ class GroebnerStrategy: def prod_GB_term(self, f: GBElement, t: Any) -> GBElement: ... def prod_term_GB(self, t: Any, f: GBElement) -> GBElement: ... def build_S_poly(self, f: GBElement, g: GBElement) -> bool: ... - def preprocessing( - self, P: list[tuple[GBElement, GBElement]], G: list[GBElement] - ) -> Set[GBElement]: ... - def reduction( - self, P: list[tuple[GBElement, GBElement]], G: list[GBElement] - ) -> list[GBElement]: ... + def preprocessing(self, P: list[tuple[GBElement, GBElement]], G: list[GBElement]) -> Set[GBElement]: ... + def reduction(self, P: list[tuple[GBElement, GBElement]], G: list[GBElement]) -> list[GBElement]: ... def compute_groebner(self, reduced: bool = True) -> None: ... def reduced_gb(self, G: list[GBElement]) -> int: ... def reduce_computed_gb(self) -> None: ... diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py index 94835ef4a10..ae69d6da26c 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py @@ -1,6 +1,7 @@ """ Finite-Dimensional Algebras """ + # *************************************************************************** # Copyright (C) 2011 Johan Bosman # Copyright (C) 2011, 2013 Peter Bruin @@ -133,9 +134,9 @@ class FiniteDimensionalAlgebra(UniqueRepresentation, Parent): Category of finite dimensional associative algebras with basis over Finite Field of size 3 """ + @staticmethod - def __classcall_private__(cls, k, table, names='e', assume_associative=False, - assume_unital=False, category=None): + def __classcall_private__(cls, k, table, names='e', assume_associative=False, assume_unital=False, category=None): """ Normalize input. @@ -226,8 +227,7 @@ def __classcall_private__(cls, k, table, names='e', assume_associative=False, names = normalize_names(n, names) - return super().__classcall__(cls, k, table, - names, category=cat) + return super().__classcall__(cls, k, table, names, category=cat) def __init__(self, k, table, names='e', category=None): """ @@ -341,6 +341,7 @@ def _Hom_(self, B, category): from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra_morphism import ( FiniteDimensionalAlgebraHomset, ) + return FiniteDimensionalAlgebraHomset(self, B, category=category) return super()._Hom_(B, category) @@ -387,6 +388,7 @@ def basis(self): Finite family {0: e0, 1: e1} """ from sage.sets.family import Family + return Family({i: self.gen(i) for i in range(self.ngens())}) def __iter__(self): @@ -543,8 +545,7 @@ def ideal(self, gens=None, given_by_matrix=False, side=None): Ideal (e0 + e1) of Finite-dimensional algebra of degree 2 over Finite Field of size 3 """ - return self._ideal_class_()(self, gens=gens, - given_by_matrix=given_by_matrix) + return self._ideal_class_()(self, gens=gens, given_by_matrix=given_by_matrix) @cached_method def is_associative(self) -> bool: @@ -573,7 +574,7 @@ def is_associative(self) -> bool: for i in range(n): for j in range(n): eiej = B[j][i] - if B[i]*B[j] != sum(eiej[k] * B[k] for k in range(n)): + if B[i] * B[j] != sum(eiej[k] * B[k] for k in range(n)): return False return True @@ -680,10 +681,8 @@ def is_unitary(self) -> bool: if n == 0: self._one = matrix(k, 1, n) return True - B1 = reduce(lambda x, y: x.augment(y), - self._table, matrix(k, n, 0)) - B2 = reduce(lambda x, y: x.augment(y), - self.left_table(), matrix(k, n, 0)) + B1 = reduce(lambda x, y: x.augment(y), self._table, matrix(k, n, 0)) + B2 = reduce(lambda x, y: x.augment(y), self.left_table(), matrix(k, n, 0)) # This is the vector obtained by concatenating the rows of the # n times n identity matrix: kone = k.one() @@ -820,11 +819,10 @@ def _is_valid_homomorphism_(self, other, im_gens, base_map=None): if base_map is None: base_map = lambda x: x B = self.table() - for i,gi in enumerate(im_gens): - for j,gj in enumerate(im_gens): + for i, gi in enumerate(im_gens): + for j, gj in enumerate(im_gens): eiej = B[j][i] - if (sum([other(im_gens[k]) * base_map(v) for k,v in enumerate(eiej)]) - != other(gi) * other(gj)): + if sum([other(im_gens[k]) * base_map(v) for k, v in enumerate(eiej)]) != other(gi) * other(gj): return False return True @@ -870,7 +868,7 @@ def quotient_map(self, ideal): table = [] for p in pivots: v = matrix(k, 1, self.degree()) - v[0,p] = 1 + v[0, p] = 1 v = self.element_class(self, v) table.append(f.solve_right(v.matrix() * f)) cat = self.category() @@ -915,8 +913,7 @@ def maximal_ideal(self): """ if self.degree() == 0: raise ValueError("the zero algebra is not local") - if not (self.is_unitary() and self.is_commutative() - and (self._assume_associative or self.is_associative())): + if not (self.is_unitary() and self.is_commutative() and (self._assume_associative or self.is_associative())): raise TypeError("algebra must be unitary, commutative and associative") gens = [] for x in self.gens(): @@ -975,8 +972,7 @@ def primary_decomposition(self): n = self.degree() if n == 0: return [] - if not (self.is_unitary() and self.is_commutative() - and (self._assume_associative or self.is_associative())): + if not (self.is_unitary() and self.is_commutative() and (self._assume_associative or self.is_associative())): raise TypeError("algebra must be unitary, commutative and associative") # Start with the trivial decomposition of self. components = [matrix.identity(k, n)] @@ -1001,7 +997,7 @@ def primary_decomposition(self): quotients = [] for i in range(len(components)): I = matrix(k, 0, n) - for j,c in enumerate(components): + for j, c in enumerate(components): if j != i: I = I.stack(c) quotients.append(self.quotient_map(self.ideal(I, given_by_matrix=True))) diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py index ccd163deda4..c25890fd08b 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py @@ -46,6 +46,7 @@ class FiniteDimensionalAlgebraIdeal(Ideal_generic): sage: A.ideal(A([0,1])) Ideal (e1) of Finite-dimensional algebra of degree 2 over Finite Field of size 3 """ + def __init__(self, A, gens=None, given_by_matrix=False) -> bool: """ EXAMPLES:: diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py index 8dea8499131..9213cf2d853 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py @@ -57,6 +57,7 @@ class FiniteDimensionalAlgebraMorphism(RingHomomorphism_im_gens): .. TODO:: An example illustrating unitary flag. """ + def __init__(self, parent, f, check=True, unitary=True): """ TESTS:: @@ -75,9 +76,7 @@ def __init__(self, parent, f, check=True, unitary=True): RingHomomorphism_im_gens.__init__(self, parent=parent, im_gens=f.rows(), check=check) self._matrix = f - if unitary and check and (not A.is_unitary() - or not B.is_unitary() - or self(A.one()) != B.one()): + if unitary and check and (not A.is_unitary() or not B.is_unitary() or self(A.one()) != B.one()): raise ValueError("homomorphism does not respect unit elements") def _repr_(self) -> str: @@ -93,8 +92,7 @@ def _repr_(self) -> str: sage: q._repr_() 'Morphism from Finite-dimensional algebra of degree 2 over Rational Field to Finite-dimensional algebra of degree 1 over Rational Field given by matrix\n[1]\n[0]' """ - return "Morphism from {} to {} given by matrix\n{}".format( - self.domain(), self.codomain(), self._matrix) + return "Morphism from {} to {} given by matrix\n{}".format(self.domain(), self.codomain(), self._matrix) def __call__(self, x): """ @@ -130,9 +128,7 @@ def __eq__(self, other): sage: phi == H.zero() False """ - return (isinstance(other, FiniteDimensionalAlgebraMorphism) - and self.parent() == other.parent() - and self._matrix == other._matrix) + return isinstance(other, FiniteDimensionalAlgebraMorphism) and self.parent() == other.parent() and self._matrix == other._matrix def __ne__(self, other): """ @@ -200,6 +196,7 @@ class FiniteDimensionalAlgebraHomset(RingHomset_generic): """ Set of morphisms between two finite-dimensional algebras. """ + @cached_method def zero(self): """ @@ -217,9 +214,8 @@ def zero(self): [0 0] """ from sage.matrix.constructor import matrix - return FiniteDimensionalAlgebraMorphism(self, matrix.zero(self.domain().ngens(), - self.codomain().ngens()), - False, False) + + return FiniteDimensionalAlgebraMorphism(self, matrix.zero(self.domain().ngens(), self.codomain().ngens()), False, False) def __call__(self, f, check=True, unitary=True): """ @@ -249,6 +245,7 @@ def __call__(self, f, check=True, unitary=True): return FiniteDimensionalAlgebraMorphism(self, f, check, unitary) try: from sage.matrix.constructor import matrix + return FiniteDimensionalAlgebraMorphism(self, matrix(f), check, unitary) except Exception: return RingHomset_generic.__call__(self, f, check) diff --git a/src/sage/algebras/finite_gca.py b/src/sage/algebras/finite_gca.py index 1477dde1a65..9f5f4a2c081 100644 --- a/src/sage/algebras/finite_gca.py +++ b/src/sage/algebras/finite_gca.py @@ -5,6 +5,7 @@ - Michael Jung (2021): initial version """ + # **************************************************************************** # Copyright (C) 2021 Michael Jung # @@ -132,9 +133,9 @@ class FiniteGCAlgebra(CombinatorialFreeModule): sage: type(A) """ + @staticmethod - def __classcall_private__(cls, base, names=None, degrees=None, - max_degree=None, category=None, **kwargs): + def __classcall_private__(cls, base, names=None, degrees=None, max_degree=None, category=None, **kwargs): r""" Normalize the input for the :meth:`__init__` method and the unique representation. @@ -172,12 +173,9 @@ def __classcall_private__(cls, base, names=None, degrees=None, else: degrees = tuple(degrees) - return super().__classcall__(cls, base=base, names=names, - degrees=degrees, max_degree=max_degree, - category=category, **kwargs) + return super().__classcall__(cls, base=base, names=names, degrees=degrees, max_degree=max_degree, category=category, **kwargs) - def __init__(self, base, names, degrees, max_degree, - category=None, **kwargs): + def __init__(self, base, names, degrees, max_degree, category=None, **kwargs): r""" Construct a commutative graded algebra with finite degree. @@ -204,15 +202,12 @@ def __init__(self, base, names, degrees, max_degree, self._mul_symbol = kwargs.pop('mul_symbol', '*') self._mul_latex_symbol = kwargs.pop('mul_latex_symbol', '') step = gcd(degrees) - universe = DisjointUnionEnumeratedSets(self._weighted_vectors.subset(k) - for k in range(0, max_degree, step)) + universe = DisjointUnionEnumeratedSets(self._weighted_vectors.subset(k) for k in range(0, max_degree, step)) base_cat = Algebras(base).WithBasis().Super().Supercommutative().FiniteDimensional() category = base_cat.or_subcategory(category, join=True) indices = ConditionSet(universe, self._valid_index) sorting_key = self._weighted_vectors.grading - CombinatorialFreeModule.__init__(self, base, indices, - sorting_key=sorting_key, - category=category) + CombinatorialFreeModule.__init__(self, base, indices, sorting_key=sorting_key, category=category) def _valid_index(self, w) -> bool: r""" @@ -340,7 +335,7 @@ def product_on_basis(self, w1, w2): if j == 0 or is_even(b): continue c += 1 - return (-1)**c * self.monomial(w_tot) + return (-1) ** c * self.monomial(w_tot) def degree_on_basis(self, i): r""" @@ -452,6 +447,7 @@ def algebra_generators(self): Family (x, y, z) """ from sage.sets.family import Family + return Family(self.gens()) @cached_method diff --git a/src/sage/algebras/free_algebra.py b/src/sage/algebras/free_algebra.py index 96d9ce81043..406fe0d3ad5 100644 --- a/src/sage/algebras/free_algebra.py +++ b/src/sage/algebras/free_algebra.py @@ -262,10 +262,8 @@ class FreeAlgebraFactory(UniqueFactory): sage: c^3 * a * b^2 a*b^2*c^3 """ - def create_key(self, base_ring, arg1=None, arg2=None, - sparse=None, order=None, - names=None, name=None, - implementation=None, degrees=None): + + def create_key(self, base_ring, arg1=None, arg2=None, sparse=None, order=None, names=None, name=None, implementation=None, degrees=None): """ Create the key under which a free algebra is stored. @@ -310,18 +308,18 @@ def create_key(self, base_ring, arg1=None, arg2=None, if degrees is None: return (PolRing,) from sage.rings.polynomial.term_order import TermOrder + T = TermOrder(PolRing.term_order(), PolRing.ngens() + 1) varnames = list(PolRing.variable_names()) newname = 'x' while newname in varnames: newname += '_' varnames.append(newname) - R = PolynomialRing( - PolRing.base(), varnames, - sparse=sparse, order=T) + R = PolynomialRing(PolRing.base(), varnames, sparse=sparse, order=T) return tuple(degrees), R # normalise the generator names from sage.rings.integer import Integer + if isinstance(arg1, (Integer, int)): arg1, arg2 = arg2, arg1 if names is not None: @@ -357,11 +355,13 @@ def create_object(self, version, key): from sage.algebras.letterplace.free_algebra_letterplace import ( FreeAlgebra_letterplace, ) + return FreeAlgebra_letterplace(key[0]) if isinstance(key[0], tuple): from sage.algebras.letterplace.free_algebra_letterplace import ( FreeAlgebra_letterplace, ) + return FreeAlgebra_letterplace(key[1], degrees=key[0]) if len(key) == 2: return FreeAlgebra_generic(key[0], len(key[1]), key[1]) @@ -435,6 +435,7 @@ class FreeAlgebra_generic(CombinatorialFreeModule): algebras in different implementations are not equal, but there is a coercion. """ + Element = FreeAlgebraElement def __init__(self, R, n, names, degrees=None) -> None: @@ -467,8 +468,7 @@ def __init__(self, R, n, names, degrees=None) -> None: raise ValueError("argument degrees must specify an integer for each generator") cat = cat.Graded() - CombinatorialFreeModule.__init__(self, R, indices, prefix='F', - category=cat) + CombinatorialFreeModule.__init__(self, R, indices, prefix='F', category=cat) self._assign_names(indices.variable_names()) if degrees is None: self._degrees = None @@ -540,10 +540,8 @@ def _repr_(self) -> str: """ txt = "generator" if self.__ngens == 1 else "generators" if self._degrees is None: - return "Free Algebra on {} {} {} over {}".format( - self.__ngens, txt, self.gens(), self.base_ring()) - return "Free Algebra on {} {} {} with degrees {} over {}".format( - self.__ngens, txt, self.gens(), tuple(self._degrees.values()), self.base_ring()) + return "Free Algebra on {} {} {} over {}".format(self.__ngens, txt, self.gens(), self.base_ring()) + return "Free Algebra on {} {} {} with degrees {} over {}".format(self.__ngens, txt, self.gens(), tuple(self._degrees.values()), self.base_ring()) def _latex_(self) -> str: r""" @@ -559,8 +557,8 @@ def _latex_(self) -> str: \Bold{Z}[q]\langle a, b, c\rangle """ from sage.misc.latex import latex - return "{}\\langle {}\\rangle".format(latex(self.base_ring()), - ', '.join(self.latex_variable_names())) + + return "{}\\langle {}\\rangle".format(latex(self.base_ring()), ', '.join(self.latex_variable_names())) def _element_constructor_(self, x): """ @@ -627,8 +625,7 @@ def _element_constructor_(self, x): return x # from another FreeAlgebra: if x not in self.base_ring(): - D = {self.monoid()(T): cf - for T, cf in x.monomial_coefficients().items()} + D = {self.monoid()(T): cf for T, cf in x.monomial_coefficients().items()} return self.element_class(self, D) elif hasattr(x, 'letterplace_polynomial'): P = x.parent() @@ -639,11 +636,11 @@ def _element_constructor_(self, x): def exp_to_monomial(T): return M([(i % ngens, Ti) for i, Ti in enumerate(T) if Ti]) - return self.element_class(self, {exp_to_monomial(T): c - for T, c in x.letterplace_polynomial().monomial_coefficients().items()}) + return self.element_class(self, {exp_to_monomial(T): c for T, c in x.letterplace_polynomial().monomial_coefficients().items()}) # ok, not a free algebra element (or should not be viewed as one). if isinstance(x, str): from sage.misc.sage_eval import sage_eval + G = self.gens() d = {str(v): G[i] for i, v in enumerate(self.variable_names())} return self(sage_eval(x, locals=d)) @@ -652,12 +649,12 @@ def exp_to_monomial(T): if isinstance(x, FreeMonoidElement) and x.parent() is self._indices: return self.element_class(self, {x: R.one()}) # coercion from the PBW basis - if isinstance(x, PBWBasisOfFreeAlgebra.Element) \ - and self.has_coerce_map_from(x.parent()._alg): + if isinstance(x, PBWBasisOfFreeAlgebra.Element) and self.has_coerce_map_from(x.parent()._alg): return self(x.parent().expansion(x)) # Check if it's a factorization from sage.structure.factorization import Factorization + if isinstance(x, Factorization): return self.prod(f**i for f, i in x) @@ -795,6 +792,7 @@ def algebra_generators(self): x = self.gen(i) ret[str(x)] = x from sage.sets.family import Family + return Family(self.variable_names(), lambda i: ret[i]) @cached_method @@ -872,6 +870,7 @@ def quotient(self, mons, mats=None, names=None, **args): if mats is None: return super().quotient(mons, names) from sage.algebras import free_algebra_quotient + return free_algebra_quotient.FreeAlgebraQuotient(self, mons, mats, names) quo = quotient @@ -946,6 +945,7 @@ def g_algebra(self, relations, names=None, order='degrevlex', check=True): (-t)*x*y + t*y + (t + 1) """ from sage.matrix.constructor import Matrix + commutative = not relations base_ring = self.base_ring() @@ -980,9 +980,8 @@ def g_algebra(self, relations, names=None, order='degrevlex', check=True): if d_poly: dmat[v2_ind, v1_ind] = polynomial_ring(d_poly) from sage.rings.polynomial.plural import g_Algebra - return g_Algebra(base_ring, cmat, dmat, - names=names or self.variable_names(), - order=order, check=check, commutative=commutative) + + return g_Algebra(base_ring, cmat, dmat, names=names or self.variable_names(), order=order, check=check, commutative=commutative) def poincare_birkhoff_witt_basis(self): """ @@ -1022,7 +1021,7 @@ def pbw_element(self, elt): lst = list(elt) support = [i[0].to_word() for i in lst] min_elt = support[0] - for word in support[1:len(support) - 1]: + for word in support[1 : len(support) - 1]: if min_elt.lex_less(word): min_elt = word coeff = lst[support.index(min_elt)][1] @@ -1167,6 +1166,7 @@ class PBWBasisOfFreeAlgebra(CombinatorialFreeModule): sage: all(F(PBW(F(m))) == F(m) for m in L) True """ + @staticmethod def __classcall_private__(cls, R, n=None, names=None): """ @@ -1203,8 +1203,7 @@ def __init__(self, alg): R = alg.base_ring() self._alg = alg category = AlgebrasWithBasis(R) - CombinatorialFreeModule.__init__(self, R, alg.monoid(), prefix='PBW', - category=category) + CombinatorialFreeModule.__init__(self, R, alg.monoid(), prefix='PBW', category=category) self._assign_names(alg.variable_names()) def _repr_(self) -> str: @@ -1420,8 +1419,7 @@ def expansion(self, t): sage: PBW.expansion(PBW.one()).parent() is F True """ - return sum([i[1] * self._alg.lie_polynomial(i[0]) for i in list(t)], - self._alg.zero()) + return sum([i[1] * self._alg.lie_polynomial(i[0]) for i in list(t)], self._alg.zero()) class Element(CombinatorialFreeModule.Element): def expand(self): @@ -1464,6 +1462,7 @@ class AssociativeFunctor(ConstructionFunctor): sage: F(f)(a * F(A)(x)) (a+b)*x """ + rank = 9 def __init__(self, vars, degs=None): @@ -1517,8 +1516,8 @@ def _apply_functor_to_morphism(self, f): codom = self(f.codomain()) def action(x): - return codom._from_dict({a: f(b) - for a, b in x.monomial_coefficients().items()}) + return codom._from_dict({a: f(b) for a, b in x.monomial_coefficients().items()}) + return dom.module_morphism(function=action, codomain=codom) def __eq__(self, other): @@ -1556,13 +1555,10 @@ def __mul__(self, other): return self if isinstance(other, AssociativeFunctor): if set(self.vars).intersection(other.vars): - raise CoercionException("Overlapping variables (%s,%s)" % - (self.vars, other.vars)) + raise CoercionException("Overlapping variables (%s,%s)" % (self.vars, other.vars)) return AssociativeFunctor(other.vars + self.vars) - if (isinstance(other, CompositeConstructionFunctor) and - isinstance(other.all[-1], AssociativeFunctor)): - return CompositeConstructionFunctor(other.all[:-1], - self * other.all[-1]) + if isinstance(other, CompositeConstructionFunctor) and isinstance(other.all[-1], AssociativeFunctor): + return CompositeConstructionFunctor(other.all[:-1], self * other.all[-1]) return CompositeConstructionFunctor(other, self) def merge(self, other): diff --git a/src/sage/algebras/free_algebra_element.py b/src/sage/algebras/free_algebra_element.py index 441fb8472a0..6ad02c52227 100644 --- a/src/sage/algebras/free_algebra_element.py +++ b/src/sage/algebras/free_algebra_element.py @@ -17,6 +17,7 @@ sage: (x*y)^3 x*y*x*y*x*y """ + # *************************************************************************** # Copyright (C) 2005 David Kohel # @@ -54,6 +55,7 @@ class FreeAlgebraElement(IndexedFreeModuleElement, AlgebraElement): sage: y * x < x * y False """ + def __init__(self, A, x) -> None: """ Create the element ``x`` of the FreeAlgebra ``A``. @@ -101,6 +103,7 @@ def _repr_(self) -> str: P = self.parent() M = P.monoid() from sage.structure.parent_gens import localvars + with localvars(M, P.variable_names(), normalize=False): return repr_lincomb(v, strip_one=True) @@ -155,8 +158,7 @@ def extract_from(kwds, g): pass return None - x = [extract_from(kwds, (p.gen(i), p.variable_name(i))) - for i in range(p.ngens())] + x = [extract_from(kwds, (p.gen(i), p.variable_name(i))) for i in range(p.ngens())] elif isinstance(x[0], tuple): x = x[0] @@ -266,6 +268,7 @@ def _acted_upon_(self, scalar, self_on_left=False): x^2 * y^3 * x """ from sage.structure.factorization import Factorization + # FIXME: Make factorization work properly in the coercion framework # Keep factorization since we want to "coerce" into a factorization if isinstance(scalar, Factorization): @@ -297,8 +300,7 @@ def _im_gens_(self, codomain, im_gens, base_map): if base_map is None: base_map = codomain - return codomain.sum(base_map(c) * m(*im_gens) - for m, c in self._monomial_coefficients.items()) + return codomain.sum(base_map(c) * m(*im_gens) for m, c in self._monomial_coefficients.items()) def variables(self) -> list: """ diff --git a/src/sage/algebras/free_algebra_quotient.py b/src/sage/algebras/free_algebra_quotient.py index 79770fc9953..abb4f66a780 100644 --- a/src/sage/algebras/free_algebra_quotient.py +++ b/src/sage/algebras/free_algebra_quotient.py @@ -88,8 +88,7 @@ def __classcall__(cls, A, mons, mats, names): M = M.parent()(M) M.set_immutable() new_mats.append(M) - return super().__classcall__(cls, A, tuple(mons), - tuple(new_mats), tuple(names)) + return super().__classcall__(cls, A, tuple(mons), tuple(new_mats), tuple(names)) Element = FreeAlgebraQuotientElement @@ -166,8 +165,7 @@ def __init__(self, A, mons, mats, names): self.__module = FreeModule(R, self.__dim) self.__matrix_action = mats self.__monomial_basis = mons # elements of free monoid - Parent.__init__(self, base=R, names=names, - normalize=True, category=Algebras(R)) + Parent.__init__(self, base=R, names=names, normalize=True, category=Algebras(R)) def _element_constructor_(self, x): """ @@ -258,8 +256,7 @@ def gens(self) -> tuple: """ one = self.base_ring().one() F = self.__free_algebra.monoid() - return tuple(self.element_class(self, {F.gen(i): one}) - for i in range(self.__ngens)) + return tuple(self.element_class(self, {F.gen(i): one}) for i in range(self.__ngens)) def ngens(self): """ @@ -391,13 +388,12 @@ def hamilton_quatalg(R): """ from sage.algebras.free_algebra import FreeAlgebra from sage.matrix.matrix_space import MatrixSpace + A = FreeAlgebra(R, 3, 'i') F = A.monoid() i, j, k = F.gens() mons = [F.one(), i, j, k] M = MatrixSpace(R, 4) - mats = [M([0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0]), - M([0, 0, 1, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, -1, 0, 0]), - M([0, 0, 0, 1, 0, 0, -1, 0, 0, 1, 0, 0, -1, 0, 0, 0])] + mats = [M([0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0]), M([0, 0, 1, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, -1, 0, 0]), M([0, 0, 0, 1, 0, 0, -1, 0, 0, 1, 0, 0, -1, 0, 0, 0])] H3 = FreeAlgebraQuotient(A, mons, mats, names=('i', 'j', 'k')) return H3, H3.gens() diff --git a/src/sage/algebras/free_algebra_quotient_element.py b/src/sage/algebras/free_algebra_quotient_element.py index 740436e5092..6a2c7caa514 100644 --- a/src/sage/algebras/free_algebra_quotient_element.py +++ b/src/sage/algebras/free_algebra_quotient_element.py @@ -6,6 +6,7 @@ - William Stein (2011-11-19): improved doctest coverage to 100% - David Kohel (2005-09): initial version """ + # *************************************************************************** # Copyright (C) 2005 David Kohel # @@ -70,7 +71,7 @@ def __init__(self, A, x) -> None: B = A.monomial_basis() if isinstance(x, (Integer, int)): - self.__vector = x*M.gen(0) + self.__vector = x * M.gen(0) elif isinstance(x, RingElement) and not isinstance(x, AlgebraElement) and x in R: self.__vector = x * M.gen(0) elif isinstance(x, FreeMonoidElement) and x.parent() is F: @@ -88,11 +89,11 @@ def __init__(self, A, x) -> None: # represented in the monomial basis. self.__vector = M(0) for m, c in x._FreeAlgebraElement__monomial_coefficients.items(): - self.__vector += c*M.gen(B.index(m)) + self.__vector += c * M.gen(B.index(m)) elif isinstance(x, dict): self.__vector = M(0) for m, c in x.items(): - self.__vector += c*M.gen(B.index(m)) + self.__vector += c * M.gen(B.index(m)) elif isinstance(x, AlgebraElement) and x.parent().ambient_algebra() is A: self.__vector = x.ambient_algebra_element().vector() else: @@ -228,6 +229,7 @@ def monomial_product(X, w, m): for _ in range(k): w *= M return w + u = self.__vector.__copy__() v = y.__vector z = A(0) @@ -235,7 +237,7 @@ def monomial_product(X, w, m): for i in range(A.dimension()): c = v[i] if c != 0: - z.__vector += monomial_product(A,c*u,B[i]) + z.__vector += monomial_product(A, c * u, B[i]) return z def _rmul_(self, c): @@ -248,7 +250,7 @@ def _rmul_(self, c): sage: (-1+i-2*j+k)._rmul_(3) -3 + 3*i - 6*j + 3*k """ - return self.parent([c*a for a in self.__vector]) + return self.parent([c * a for a in self.__vector]) def _lmul_(self, c): """ @@ -260,4 +262,4 @@ def _lmul_(self, c): sage: (-1+i-2*j+k)._lmul_(3) -3 + 3*i - 6*j + 3*k """ - return self.parent([a*c for a in self.__vector]) + return self.parent([a * c for a in self.__vector]) diff --git a/src/sage/algebras/free_zinbiel_algebra.py b/src/sage/algebras/free_zinbiel_algebra.py index 88286810142..404a060eb39 100644 --- a/src/sage/algebras/free_zinbiel_algebra.py +++ b/src/sage/algebras/free_zinbiel_algebra.py @@ -18,9 +18,7 @@ from sage.misc.cachefunc import cached_method from sage.categories.magmatic_algebras import MagmaticAlgebras from sage.categories.magmas import Magmas -from sage.categories.pushout import (ConstructionFunctor, - CompositeConstructionFunctor, - IdentityConstructionFunctor) +from sage.categories.pushout import ConstructionFunctor, CompositeConstructionFunctor, IdentityConstructionFunctor from sage.categories.coalgebras_with_basis import CoalgebrasWithBasis from sage.categories.rings import Rings from sage.categories.functor import Functor @@ -171,9 +169,9 @@ class FreeZinbielAlgebra(CombinatorialFreeModule): - [LV2012]_ """ + @staticmethod - def __classcall_private__(cls, R, n=None, names=None, - prefix=None, side=None): + def __classcall_private__(cls, R, n=None, names=None, prefix=None, side=None): """ Standardize input to ensure a unique representation. @@ -253,8 +251,7 @@ def __init__(self, R, n, names, prefix, side): self.product_on_basis = self.product_on_basis_right cat = MagmaticAlgebras(R).WithBasis().Graded() cat &= CoalgebrasWithBasis(R) - CombinatorialFreeModule.__init__(self, R, indices, prefix=prefix, - category=cat) + CombinatorialFreeModule.__init__(self, R, indices, prefix=prefix, category=cat) if self._n is not None: self._assign_names(names) @@ -285,10 +282,8 @@ def _repr_(self) -> str: Free Zinbiel algebra on generators indexed by Integer Ring over Rational Field """ if self._n is None: - return "Free Zinbiel algebra on generators indexed by {} over {}".format( - self._indices.alphabet(), self.base_ring()) - return "Free Zinbiel algebra on generators {} over {}".format( - self.gens(), self.base_ring()) + return "Free Zinbiel algebra on generators indexed by {} over {}".format(self._indices.alphabet(), self.base_ring()) + return "Free Zinbiel algebra on generators {} over {}".format(self.gens(), self.base_ring()) def side(self): """ @@ -514,13 +509,10 @@ def _element_constructor_(self, x): raise TypeError('not able to convert this to this algebra') if isinstance(P, FreeZinbielAlgebra) and self._coerce_map_from_(P): if self._side == P._side: - return self.element_class(self, - x.monomial_coefficients(copy=False)) + return self.element_class(self, x.monomial_coefficients(copy=False)) dic = x.monomial_coefficients(copy=False) # canonical isomorphism when switching side - return self.element_class(self, - {w.reversal(): cf - for w, cf in dic.items()}) + return self.element_class(self, {w.reversal(): cf for w, cf in dic.items()}) raise TypeError('not able to convert this to this algebra') # Ok, not a Zinbiel algebra element (or should not be viewed as one). @@ -597,9 +589,7 @@ def _coerce_map_from_(self, R): if isinstance(R, FreeZinbielAlgebra): if self._n is None or R._n is None: return False - return (all(x in self.variable_names() - for x in R.variable_names()) and - self.base_ring().has_coerce_map_from(R.base_ring())) + return all(x in self.variable_names() for x in R.variable_names()) and self.base_ring().has_coerce_map_from(R.base_ring()) return super()._coerce_map_from_(R) def construction(self): @@ -653,6 +643,7 @@ class ZinbielFunctor(ConstructionFunctor): sage: F(f)(a * F(A)(x)) (a+b)*Z[x] """ + rank = 9 def __init__(self, variables, side): @@ -668,8 +659,7 @@ def __init__(self, variables, side): Functor.__init__(self, Rings(), Magmas()) self.vars = variables self._side = side - self._finite_vars = (isinstance(variables, (list, tuple)) - or variables in Sets().Finite()) + self._finite_vars = isinstance(variables, (list, tuple)) or variables in Sets().Finite() def _apply_functor(self, R): """ @@ -693,8 +683,7 @@ def _apply_functor(self, R): Free Zinbiel algebra on generators indexed by Integer Ring over Integer Ring """ if self._finite_vars: - return FreeZinbielAlgebra(R, len(self.vars), self.vars, - side=self._side) + return FreeZinbielAlgebra(R, len(self.vars), self.vars, side=self._side) return FreeZinbielAlgebra(R, self.vars, side=self._side) def _apply_functor_to_morphism(self, f): @@ -715,8 +704,8 @@ def _apply_functor_to_morphism(self, f): codom = self(f.codomain()) def action(x): - return codom._from_dict({a: f(b) - for a, b in x.monomial_coefficients(copy=False).items()}) + return codom._from_dict({a: f(b) for a, b in x.monomial_coefficients(copy=False).items()}) + return dom.module_morphism(function=action, codomain=codom) def __eq__(self, other): @@ -783,13 +772,10 @@ def __mul__(self, other): if not self._finite_vars or not other._finite_vars: raise CoercionException("Unable to determine overlap for infinite sets") if set(self.vars).intersection(other.vars): - raise CoercionException("Overlapping variables (%s,%s)" % - (self.vars, other.vars)) + raise CoercionException("Overlapping variables (%s,%s)" % (self.vars, other.vars)) return ZinbielFunctor(other.vars + self.vars, self._side) - if (isinstance(other, CompositeConstructionFunctor) and - isinstance(other.all[-1], ZinbielFunctor)): - return CompositeConstructionFunctor(other.all[:-1], - self * other.all[-1]) + if isinstance(other, CompositeConstructionFunctor) and isinstance(other.all[-1], ZinbielFunctor): + return CompositeConstructionFunctor(other.all[:-1], self * other.all[-1]) return CompositeConstructionFunctor(other, self) def merge(self, other): @@ -850,13 +836,13 @@ def merge(self, other): """ if isinstance(other, ZinbielFunctor): if self._side != other._side: - raise TypeError('cannot merge free Zinbiel algebras ' - 'with distinct sides') + raise TypeError('cannot merge free Zinbiel algebras ' 'with distinct sides') if self.vars == other.vars: return self def check(x): return isinstance(x, (list, tuple)) or x in Sets().Finite() + if not check(self.vars) or not check(other.vars): return None ret = list(self.vars) diff --git a/src/sage/algebras/fusion_rings/all.py b/src/sage/algebras/fusion_rings/all.py index 44484309add..5500c99e811 100644 --- a/src/sage/algebras/fusion_rings/all.py +++ b/src/sage/algebras/fusion_rings/all.py @@ -1,6 +1,7 @@ """ Fusion Rings """ + # **************************************************************************** # Copyright (C) 2022 Guillermo Aboumrad # diff --git a/src/sage/algebras/fusion_rings/f_matrix.py b/src/sage/algebras/fusion_rings/f_matrix.py index d6f7e4e0a7c..1fb990d7abf 100644 --- a/src/sage/algebras/fusion_rings/f_matrix.py +++ b/src/sage/algebras/fusion_rings/f_matrix.py @@ -1,6 +1,7 @@ r""" The F-Matrix of a Fusion Ring """ + # **************************************************************************** # Copyright (C) 2019 Daniel Bump # Guillermo Aboumrad @@ -18,19 +19,8 @@ from os import getpid, remove import pickle -from sage.algebras.fusion_rings.fast_parallel_fmats_methods import ( - _backward_subs, _solve_for_linear_terms, - executor -) -from sage.algebras.fusion_rings.poly_tup_engine import ( - apply_coeff_map, constant_coeff, - compute_known_powers, - get_variables_degrees, variables, - poly_to_tup, _tup_to_poly, tup_to_univ_poly, - _unflatten_coeffs, - poly_tup_sortkey, - resize -) +from sage.algebras.fusion_rings.fast_parallel_fmats_methods import _backward_subs, _solve_for_linear_terms, executor +from sage.algebras.fusion_rings.poly_tup_engine import apply_coeff_map, constant_coeff, compute_known_powers, get_variables_degrees, variables, poly_to_tup, _tup_to_poly, tup_to_univ_poly, _unflatten_coeffs, poly_tup_sortkey, resize from sage.algebras.fusion_rings.shm_managers import KSHandler, FvarsHandler from sage.graphs.graph import Graph from sage.matrix.constructor import matrix @@ -263,6 +253,7 @@ class FMatrix(SageObject): sage: f.field() # long time Algebraic Field """ + def __init__(self, fusion_ring, fusion_label='f', var_prefix='fx', inject_variables=False): r""" Initialize ``self``. @@ -435,10 +426,7 @@ def fmat(self, a, b, c, d, x, y, data=True): (-zeta60^14 + zeta60^6 + zeta60^4 - 1), (zeta60^14 - zeta60^6 - zeta60^4 + 1)] """ - if (self._FR.Nk_ij(a, b, x) == 0 - or self._FR.Nk_ij(x, c, d) == 0 - or self._FR.Nk_ij(b, c, y) == 0 - or self._FR.Nk_ij(a, y, d) == 0): + if self._FR.Nk_ij(a, b, x) == 0 or self._FR.Nk_ij(x, c, d) == 0 or self._FR.Nk_ij(b, c, y) == 0 or self._FR.Nk_ij(a, y, d) == 0: return 0 # Some known zero F-symbols @@ -616,8 +604,7 @@ def f_from(self, a, b, c, d): sage: f.f_to(a1, a1, a2, a2) [a1, a3] """ - return [x for x in self._FR.basis() - if self._FR.Nk_ij(a, b, x) != 0 and self._FR.Nk_ij(x, c, d) != 0] + return [x for x in self._FR.basis() if self._FR.Nk_ij(a, b, x) != 0 and self._FR.Nk_ij(x, c, d) != 0] def f_to(self, a, b, c, d): r""" @@ -643,8 +630,7 @@ def f_to(self, a, b, c, d): sage: B.f_to(b2, b4, b2, b4) [b1, b3, b5] """ - return [y for y in self._FR.basis() - if self._FR.Nk_ij(b, c, y) != 0 and self._FR.Nk_ij(a, y, d) != 0] + return [y for y in self._FR.basis() if self._FR.Nk_ij(b, c, y) != 0 and self._FR.Nk_ij(a, y, d) != 0] #################### # Data getters # @@ -1007,10 +993,7 @@ def save_fvars(self, filename): True sage: os.remove(filename) """ - final_state = [self._fvars, - self._non_cyc_roots, - self.get_coerce_map_from_fr_cyclotomic_field(), - self._qqbar_embedding] + final_state = [self._fvars, self._non_cyc_roots, self.get_coerce_map_from_fr_cyclotomic_field(), self._qqbar_embedding] with open(filename, 'wb') as f: pickle.dump(final_state, f) @@ -1379,8 +1362,7 @@ def _map_triv_reduce(self, mapper, input_iter, worker_pool=None, chunksize=None, else: mapped = worker_pool.imap_unordered(executor, input_iter, chunksize=chunksize) # Reduce phase - results = {eqn for child_eqns in mapped if child_eqns is not None - for eqn in child_eqns} + results = {eqn for child_eqns in mapped if child_eqns is not None for eqn in child_eqns} return list(results) ######################## @@ -1484,9 +1466,7 @@ def get_defining_equations(self, option, output=True): self._reset_solver_state() n_proc = self.pool._processes if self.pool is not None else 1 params = [(child_id, n_proc, output) for child_id in range(n_proc)] - eqns = self._map_triv_reduce('get_reduced_' + option, params, - worker_pool=self.pool, chunksize=1, - mp_thresh=0) + eqns = self._map_triv_reduce('get_reduced_' + option, params, worker_pool=self.pool, chunksize=1, mp_thresh=0) if output: F = self._field for i, eq_tup in enumerate(eqns): @@ -1975,7 +1955,7 @@ def _get_explicit_solution(self, eqns=None, verbose=True): # Backward substitution step. Traverse variables in reverse lexicographical order. (System is in triangular form) self._fvars = {sextuple: apply_coeff_map(rhs, phi) for sextuple, rhs in self._fvars.items()} for fx, rhs in numeric_fvars.items(): - self._fvars[self._idx_to_sextuple[fx]] = ((ETuple({}, nvars), rhs), ) + self._fvars[self._idx_to_sextuple[fx]] = ((ETuple({}, nvars), rhs),) _backward_subs(self, flatten=False) self._fvars = {sextuple: constant_coeff(rhs, self._field) for sextuple, rhs in self._fvars.items()} diff --git a/src/sage/algebras/fusion_rings/fusion_double.py b/src/sage/algebras/fusion_rings/fusion_double.py index 907089aafd1..d770370c066 100644 --- a/src/sage/algebras/fusion_rings/fusion_double.py +++ b/src/sage/algebras/fusion_rings/fusion_double.py @@ -133,6 +133,7 @@ class FusionDouble(CombinatorialFreeModule): sage: b13^2 # long time (4s) b0 + b3 + b37 """ + @staticmethod def __classcall_private__(cls, G, prefix='s', inject_variables=False): """ @@ -176,7 +177,7 @@ def __init__(self, G, prefix='s') -> None: self._unit_index = None # index of the unit element count = ZZ.zero() for g in sorted(G.conjugacy_classes_representatives(), key=str): - for chi in sorted(G.centralizer(g).irreducible_characters(), key=lambda chi:str(chi.values())): + for chi in sorted(G.centralizer(g).irreducible_characters(), key=lambda chi: str(chi.values())): # NOTE: the trivial char is not necessarily the first one self._names[count] = "%s%s" % (prefix, count) self._elt[count] = g @@ -189,8 +190,7 @@ def __init__(self, G, prefix='s') -> None: self._fusion_labels = None self._field = None cat = AlgebrasWithBasis(ZZ) - CombinatorialFreeModule.__init__(self, ZZ, list(self._names), - prefix=prefix, bracket=False, category=cat) + CombinatorialFreeModule.__init__(self, ZZ, list(self._names), prefix=prefix, bracket=False, category=cat) def _repr_(self) -> str: """ @@ -257,8 +257,8 @@ def s_ij(self, i, j, unitary=False, base_coercion=True): """ sum_val = ZZ.zero() G = self._G - i, = list(i._monomial_coefficients) - j, = list(j._monomial_coefficients) + (i,) = list(i._monomial_coefficients) + (j,) = list(j._monomial_coefficients) a = self._elt[i] b = self._elt[j] for g in G: @@ -328,9 +328,7 @@ def s_matrix(self, unitary=False, base_coercion=True): [ 1/3 1/3 -1/3 0 0 2/3 -1/3 -1/3] """ b = self.basis() - return matrix([[self.s_ij(b[x], b[y], unitary=unitary, - base_coercion=base_coercion) - for x in self.get_order()] for y in self.get_order()]) + return matrix([[self.s_ij(b[x], b[y], unitary=unitary, base_coercion=base_coercion) for x in self.get_order()] for y in self.get_order()]) @cached_method def N_ijk(self, i, j, k): @@ -363,9 +361,7 @@ def N_ijk(self, i, j, k): True """ sz = self.one() - return ZZ(sum(self.s_ij(i, r, unitary=True) * self.s_ij(j, r, unitary=True) - * self.s_ij(k, r, unitary=True) / self.s_ij(sz, r, unitary=True) - for r in self.basis())) + return ZZ(sum(self.s_ij(i, r, unitary=True) * self.s_ij(j, r, unitary=True) * self.s_ij(k, r, unitary=True) / self.s_ij(sz, r, unitary=True) for r in self.basis())) @cached_method def Nk_ij(self, i, j, k, use_characters=False): @@ -462,8 +458,7 @@ def Nk_ij(self, i, j, k, use_characters=False): inner_summands = A.intersection(B).intersection(Set(CK)) i_twist_inv = i_twist.inverse() j_twist_inv = j_twist.inverse() - res += sum(ichar(i_twist * x * i_twist_inv) * jchar(j_twist * x * j_twist_inv) * kchar(x).conjugate() - for x in inner_summands) + res += sum(ichar(i_twist * x * i_twist_inv) * jchar(j_twist * x * j_twist_inv) * kchar(x).conjugate() for x in inner_summands) return c * res @cached_method @@ -560,10 +555,7 @@ def r_matrix(self, i, j, k, base_coercion=True): else: i0 = self.one() B = self.basis() - ret = sum(y.ribbon()**2 / (i.ribbon() * x.ribbon()**2) - * self.s_ij(i0, y) * self.s_ij(i, z) * self.s_ijconj(x, z) - * self.s_ijconj(k, x) * self.s_ijconj(y, z) / self.s_ij(i0, z) - for x in B for y in B for z in B) / (self.total_q_order()**4) + ret = sum(y.ribbon() ** 2 / (i.ribbon() * x.ribbon() ** 2) * self.s_ij(i0, y) * self.s_ij(i, z) * self.s_ijconj(x, z) * self.s_ijconj(k, x) * self.s_ijconj(y, z) / self.s_ij(i0, z) for x in B for y in B for z in B) / (self.total_q_order() ** 4) if (not base_coercion) or (self._basecoer is None): return ret @@ -635,14 +627,14 @@ def is_multiplicity_free(self, verbose=False) -> bool: if verbose: print("Checking multiplicity freeness") from itertools import product - for (i, j, k) in product(self.basis(), repeat=3): + + for i, j, k in product(self.basis(), repeat=3): if self.N_ijk(i, j, k) > 1: print("N(%s,%s,%s) = %s" % (i, j, k, self.N_ijk(i, j, k))) return False return True - return all(self.N_ijk(i, j, k) <= 1 for i in self.basis() - for j in self.basis() for k in self.basis()) + return all(self.N_ijk(i, j, k) <= 1 for i in self.basis() for j in self.basis() for k in self.basis()) @cached_method def one_basis(self): @@ -703,9 +695,7 @@ def product_on_basis(self, a, b): sage: Q.product_on_basis(3,4) q0 + q2 + q5 + q6 + q7 """ - d = {k.support_of_term(): val for k in self.basis() - if (val := self.N_ijk(self.monomial(a), self.monomial(b), - self.dual(k)))} + d = {k.support_of_term(): val for k in self.basis() if (val := self.N_ijk(self.monomial(a), self.monomial(b), self.dual(k)))} return self._from_dict(d, remove_zeros=False) def group(self): @@ -733,6 +723,7 @@ def get_fmatrix(self, *args, **kwargs): if not hasattr(self, 'fmats') or kwargs.get('new', False): kwargs.pop('new', None) from sage.algebras.fusion_rings.f_matrix import FMatrix + self.fmats = FMatrix(self, *args, **kwargs) return self.fmats @@ -841,7 +832,7 @@ def twist(self, reduced=True): rib = self.ribbon() norm = 2 * P._cyclotomic_order for k in range(4 * P._cyclotomic_order): - if zeta ** k == rib: + if zeta**k == rib: return k / norm def dual(self): diff --git a/src/sage/algebras/fusion_rings/fusion_ring.py b/src/sage/algebras/fusion_rings/fusion_ring.py index 4d1bf255621..f4b463b0098 100644 --- a/src/sage/algebras/fusion_rings/fusion_ring.py +++ b/src/sage/algebras/fusion_rings/fusion_ring.py @@ -1,6 +1,7 @@ """ Fusion rings """ + # **************************************************************************** # Copyright (C) 2019 Daniel Bump # Guillermo Aboumrad @@ -18,10 +19,7 @@ from itertools import product, zip_longest from multiprocessing import Pool, set_start_method from sage.combinat.q_analogues import q_int -from sage.algebras.fusion_rings.fast_parallel_fusion_ring_braid_repn import ( - executor, - _unflatten_entries -) +from sage.algebras.fusion_rings.fast_parallel_fusion_ring_braid_repn import executor, _unflatten_entries from sage.combinat.root_system.weyl_characters import WeylCharacterRing from sage.matrix.constructor import matrix from sage.matrix.special import diagonal_matrix @@ -298,6 +296,7 @@ class FusionRing(WeylCharacterRing): sage: C*T == T*C True """ + @staticmethod def __classcall__(cls, ct, k, base_ring=ZZ, prefix=None, style='coroots', conjugate=False, cyclotomic_order=None, fusion_labels=None, inject_variables=False): """ @@ -338,12 +337,7 @@ def __classcall__(cls, ct, k, base_ring=ZZ, prefix=None, style='coroots', conjug sage: E81 = FusionRing('E8', 1) sage: TestSuite(E81).run() """ - return super().__classcall__(cls, ct, base_ring=base_ring, - prefix=prefix, style=style, k=k, - conjugate=conjugate, - cyclotomic_order=cyclotomic_order, - fusion_labels=fusion_labels, - inject_variables=inject_variables) + return super().__classcall__(cls, ct, base_ring=base_ring, prefix=prefix, style=style, k=k, conjugate=conjugate, cyclotomic_order=cyclotomic_order, fusion_labels=fusion_labels, inject_variables=inject_variables) def _test_verlinde(self, **options): """ @@ -358,6 +352,7 @@ def _test_verlinde(self, **options): c = self.global_q_dimension() i0 = self.one() from sage.misc.misc import some_tuples + B = self.basis() for x, y, z in some_tuples(B, 3, tester._max_runs): v = sum(self.s_ij(x, w) * self.s_ij(y, w) * self.s_ij(z, w) / self.s_ij(i0, w) for w in B) @@ -408,12 +403,12 @@ def check_braid_representation(self, max_strands=6, anyon=None): sage: F41.check_braid_representation() # long time True """ - if not self.is_multiplicity_free(): # Braid group representation is not available if self is not multiplicity free + if not self.is_multiplicity_free(): # Braid group representation is not available if self is not multiplicity free raise NotImplementedError("only implemented for multiplicity free fusion rings") b = self.basis() results = [] # Test with different numbers of strands - for n_strands in range(3, max_strands+1): + for n_strands in range(3, max_strands + 1): # Randomly select a fusing anyon. Skip the identity element, since # its braiding matrices are trivial if anyon is not None: @@ -423,7 +418,7 @@ def check_braid_representation(self, max_strands=6, anyon=None): a = b.random_element() if a != self.one(): break - pow = a ** n_strands + pow = a**n_strands d = pow.monomials()[0] # Try to find 'interesting' braid group reps i.e. skip 1-d reps for k, v in pow.monomial_coefficients().items(): @@ -649,8 +644,7 @@ def some_elements(self): sage: D41.some_elements() [D41(1,0,0,0), D41(0,0,1,0), D41(0,0,0,1)] """ - return [self.monomial(x) for x in self.fundamental_weights() - if self.level(x) <= self._k] + return [self.monomial(x) for x in self.fundamental_weights() if self.level(x) <= self._k] def fusion_level(self): r""" @@ -844,9 +838,7 @@ def s_ij(self, elt_i, elt_j, base_coercion=True): [1, -zeta60^14 + zeta60^6 + zeta60^4, -zeta60^14 + zeta60^6 + zeta60^4, -1] """ ijtwist = elt_i.twist() + elt_j.twist() - ret = sum(k.q_dimension(base_coercion=False) * self.Nk_ij(elt_i, k, elt_j) - * self.root_of_unity(k.twist() - ijtwist, base_coercion=False) - for k in self.basis()) + ret = sum(k.q_dimension(base_coercion=False) * self.Nk_ij(elt_i, k, elt_j) * self.root_of_unity(k.twist() - ijtwist, base_coercion=False) for k in self.basis()) if (not base_coercion) or (self._basecoer is None): return ret return self._basecoer(ret) @@ -924,8 +916,7 @@ def s_matrix(self, unitary=False, base_coercion=True): [0 0 0 1] """ b = self.basis() - S = matrix([[self.s_ij(b[x], b[y], base_coercion=base_coercion) - for x in self.get_order()] for y in self.get_order()]) + S = matrix([[self.s_ij(b[x], b[y], base_coercion=base_coercion) for x in self.get_order()] for y in self.get_order()]) if unitary: return S / self.total_q_order(base_coercion=base_coercion) return S @@ -983,10 +974,7 @@ def r_matrix(self, i, j, k, base_coercion=True): else: i0 = self.one() B = self.basis() - ret = sum(y.ribbon(base_coercion=False)**2 / (i.ribbon(base_coercion=False) * x.ribbon(base_coercion=False)**2) - * self.s_ij(i0, y, base_coercion=False) * self.s_ij(i, z, base_coercion=False) * self.s_ijconj(x, z, base_coercion=False) - * self.s_ijconj(k, x, base_coercion=False) * self.s_ijconj(y, z, base_coercion=False) / self.s_ij(i0, z, base_coercion=False) - for x in B for y in B for z in B) / (self.total_q_order(base_coercion=False)**4) + ret = sum(y.ribbon(base_coercion=False) ** 2 / (i.ribbon(base_coercion=False) * x.ribbon(base_coercion=False) ** 2) * self.s_ij(i0, y, base_coercion=False) * self.s_ij(i, z, base_coercion=False) * self.s_ijconj(x, z, base_coercion=False) * self.s_ijconj(k, x, base_coercion=False) * self.s_ijconj(y, z, base_coercion=False) / self.s_ij(i0, z, base_coercion=False) for x in B for y in B for z in B) / (self.total_q_order(base_coercion=False) ** 4) if (not base_coercion) or (self._basecoer is None): return ret return self._basecoer(ret) @@ -1027,7 +1015,7 @@ def total_q_order(self, base_coercion=True): True """ c = self.virasoro_central_charge() - ret = self.D_plus(base_coercion=False) * self.root_of_unity(-c/4, base_coercion=False) + ret = self.D_plus(base_coercion=False) * self.root_of_unity(-c / 4, base_coercion=False) if (not base_coercion) or (self._basecoer is None): return ret return self._basecoer(ret) @@ -1053,7 +1041,7 @@ def D_plus(self, base_coercion=True): sage: Dp/Dm == B31.root_of_unity(c/2) True """ - ret = sum((x.q_dimension(base_coercion=False))**2 * x.ribbon(base_coercion=False) for x in self.basis()) + ret = sum((x.q_dimension(base_coercion=False)) ** 2 * x.ribbon(base_coercion=False) for x in self.basis()) if (not base_coercion) or (self._basecoer is None): return ret return self._basecoer(ret) @@ -1076,7 +1064,7 @@ def D_minus(self, base_coercion=True): sage: Dp*Dm == E83.global_q_dimension() True """ - ret = sum((x.q_dimension(base_coercion=False))**2 / x.ribbon(base_coercion=False) for x in self.basis()) + ret = sum((x.q_dimension(base_coercion=False)) ** 2 / x.ribbon(base_coercion=False) for x in self.basis()) if (not base_coercion) or (self._basecoer is None): return ret return self._basecoer(ret) @@ -1168,17 +1156,18 @@ def get_computational_basis(self, a, b, n_strands): sage: A14.get_computational_basis(one, two, 4) [(two, two), (two, zero), (zero, two)] """ + def _get_trees(fr, top_row, root): if len(top_row) == 2: m1, m2 = top_row return [[]] if fr.Nk_ij(m1, m2, root) else [] m1, m2 = top_row[:2] - return [(l, *b) for l in fr.basis() for b in _get_trees(fr, [l]+top_row[2:], root) if fr.Nk_ij(m1, m2, l)] + return [(l, *b) for l in fr.basis() for b in _get_trees(fr, [l] + top_row[2:], root) if fr.Nk_ij(m1, m2, l)] comp_basis = [] - for top in product((a*a).monomials(), repeat=n_strands//2): + for top in product((a * a).monomials(), repeat=n_strands // 2): # If the n_strands is odd, we must extend the top row by a fusing anyon - top_row = list(top)+[a]*(n_strands % 2) + top_row = list(top) + [a] * (n_strands % 2) comp_basis.extend((*top, *levels) for levels in _get_trees(self, top_row, b)) return comp_basis @@ -1199,6 +1188,7 @@ def get_fmatrix(self, *args, **kwargs): if not hasattr(self, 'fmats') or kwargs.get('new', False): kwargs.pop('new', None) from sage.algebras.fusion_rings.f_matrix import FMatrix + self.fmats = FMatrix(self, *args, **kwargs) return self.fmats @@ -1256,15 +1246,7 @@ def _emap(self, mapper, input_args, worker_pool=None): results.extend(worker_results) return results - def get_braid_generators(self, - fusing_anyon, - total_charge_anyon, - n_strands, - checkpoint=False, - save_results='', - warm_start='', - use_mp=True, - verbose=True): + def get_braid_generators(self, fusing_anyon, total_charge_anyon, n_strands, checkpoint=False, save_results='', warm_start='', use_mp=True, verbose=True): r""" Compute generators of the Artin braid group on ``n_strands`` strands. @@ -1342,11 +1324,7 @@ def get_braid_generators(self, # Construct associated FMatrix object and solve for F-symbols self.get_fmatrix() if self.fmats._chkpt_status < 7: - self.fmats.find_orthogonal_solution(checkpoint=checkpoint, - save_results=save_results, - warm_start=warm_start, - use_mp=use_mp, - verbose=verbose) + self.fmats.find_orthogonal_solution(checkpoint=checkpoint, save_results=save_results, warm_start=warm_start, use_mp=use_mp, verbose=verbose) # Set multiprocessing parameters. Context can only be set once, so we try to set it try: @@ -1364,15 +1342,15 @@ def get_braid_generators(self, print("Computing an {}-dimensional representation of the Artin braid group on {} strands...".format(d, n_strands)) # Compute diagonal odd-indexed generators using the 3j-symbols - gens = {2*i+1: diagonal_matrix(self.r_matrix(a, a, c[i]) for c in comp_basis) for i in range(n_strands//2)} + gens = {2 * i + 1: diagonal_matrix(self.r_matrix(a, a, c[i]) for c in comp_basis) for i in range(n_strands // 2)} # Compute even-indexed generators using F-matrices - for k in range(1, n_strands//2): + for k in range(1, n_strands // 2): entries = self._emap('sig_2k', (k, a, b, n_strands), pool) # Build cyclotomic field element objects from tuple of rationals repn _unflatten_entries(self, entries) - gens[2*k] = matrix(dict(entries)) + gens[2 * k] = matrix(dict(entries)) # If n_strands is odd, we compute the final generator if n_strands % 2: @@ -1380,7 +1358,7 @@ def get_braid_generators(self, # Build cyclotomic field element objects from tuple of rationals repn _unflatten_entries(self, entries) - gens[n_strands-1] = matrix(dict(entries)) + gens[n_strands - 1] = matrix(dict(entries)) return comp_basis, [gens[k] for k in sorted(gens)] @@ -1404,8 +1382,8 @@ def gens_satisfy_braid_gp_rels(self, sig): True """ n = len(sig) - braid_rels = all(sig[i] * sig[i+1] * sig[i] == sig[i+1] * sig[i] * sig[i+1] for i in range(n-1)) - far_comm = all(sig[i] * sig[j] == sig[j] * sig[i] for i, j in product(range(n), repeat=2) if abs(i-j) > 1 and i > j) + braid_rels = all(sig[i] * sig[i + 1] * sig[i] == sig[i + 1] * sig[i] * sig[i + 1] for i in range(n - 1)) + far_comm = all(sig[i] * sig[j] == sig[j] * sig[i] for i, j in product(range(n), repeat=2) if abs(i - j) > 1 and i > j) singular = any(s.is_singular() for s in sig) return braid_rels and far_comm and not singular @@ -1413,6 +1391,7 @@ class Element(WeylCharacterRing.Element): """ A class for FusionRing elements. """ + def is_simple_object(self) -> bool: r""" Determine whether ``self`` is a simple object of the fusion ring. @@ -1492,7 +1471,7 @@ def twist(self, reduced=True): # We copy self.weight() to skip the test (which was already done # by self.is_simple_object()). lam = next(iter(self._monomial_coefficients)) - inner = lam.inner_product(lam + 2*rho) + inner = lam.inner_product(lam + 2 * rho) twist = P._conj * P._nf * inner / P.fusion_l() # Reduce modulo 2 if reduced: @@ -1565,11 +1544,11 @@ def q_dimension(self, base_coercion=True): expr = R.fraction_field().one() for val, exp in powers.items(): if exp > 0: - expr *= q_int(P._nf * val, q)**exp + expr *= q_int(P._nf * val, q) ** exp elif exp < 0: - expr /= q_int(P._nf * val, q)**(-exp) + expr /= q_int(P._nf * val, q) ** (-exp) expr = R(expr) - expr = expr.substitute(q=q**4) / (q**(2 * expr.degree())) + expr = expr.substitute(q=q**4) / (q ** (2 * expr.degree())) zet = P.field().gen() ** (P._cyclotomic_order / P._l) ret = expr.substitute(q=zet) diff --git a/src/sage/algebras/group_algebra.py b/src/sage/algebras/group_algebra.py index 16e946ff980..3e73a3f4366 100644 --- a/src/sage/algebras/group_algebra.py +++ b/src/sage/algebras/group_algebra.py @@ -22,7 +22,7 @@ """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2008 William Stein # 2008 David Loeffler # 2009 Martin Raum @@ -33,7 +33,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.rings.integer_ring import IntegerRing from sage.categories.rings import Rings @@ -206,6 +206,7 @@ def _coerce_map_from_(self, S): G_coercion = G.coerce_map_from(S) if G_coercion is not None: from sage.categories.groups import Groups + # No coercion for additive groups because of ambiguity of + # being the group action or addition of a new term. if not self.category().is_subcategory(Groups().Algebras(K)): @@ -220,10 +221,9 @@ def _coerce_map_from_(self, S): hom_K = K.coerce_map_from(S_K) hom_G = G.coerce_map_from(S_G) if hom_K is not None and hom_G is not None: - return SetMorphism(S.Hom(self, category=self.category() | S.category()), - lambda x: self.sum_of_terms((hom_G(g), hom_K(c)) for g, c in x)) + return SetMorphism(S.Hom(self, category=self.category() | S.category()), lambda x: self.sum_of_terms((hom_G(g), hom_K(c)) for g, c in x)) from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.algebras.group_algebras', 'GroupAlgebra', - GroupAlgebra_class) + +register_unpickle_override('sage.algebras.group_algebras', 'GroupAlgebra', GroupAlgebra_class) diff --git a/src/sage/algebras/hall_algebra.py b/src/sage/algebras/hall_algebra.py index 88d939cb796..73704ad21d8 100644 --- a/src/sage/algebras/hall_algebra.py +++ b/src/sage/algebras/hall_algebra.py @@ -5,6 +5,7 @@ - Travis Scrimshaw (2013-10-17): Initial version """ + # **************************************************************************** # Copyright (C) 2013 Travis Scrimshaw # @@ -72,6 +73,7 @@ def check(m, l): if s1 > s2: return False return sum(l) <= sum(m) + if check(xexp, yexp): return 1 if check(yexp, xexp): @@ -210,6 +212,7 @@ class HallAlgebra(CombinatorialFreeModule): sage: e(H[1,1,1]) (q^-3)*e[3] """ + def __init__(self, base_ring, q, prefix='H'): """ Initialize ``self``. @@ -240,17 +243,11 @@ def __init__(self, base_ring, q, prefix='H'): category = HopfAlgebrasWithBasis(base_ring) else: category = AlgebrasWithBasis(base_ring) - CombinatorialFreeModule.__init__(self, base_ring, Partitions(), - prefix=prefix, bracket=False, - sorting_key=cmp_to_key(transpose_cmp), - category=category) + CombinatorialFreeModule.__init__(self, base_ring, Partitions(), prefix=prefix, bracket=False, sorting_key=cmp_to_key(transpose_cmp), category=category) # Coercions I = self.monomial_basis() - M = I.module_morphism(I._to_natural_on_basis, codomain=self, - triangular='upper', unitriangular=True, - inverse_on_support=lambda x: x.conjugate(), - invertible=True) + M = I.module_morphism(I._to_natural_on_basis, codomain=self, triangular='upper', unitriangular=True, inverse_on_support=lambda x: x.conjugate(), invertible=True) M.register_as_coercion() (~M).register_as_coercion() @@ -311,9 +308,7 @@ def product_on_basis(self, mu, la): return self.monomial(mu) if all(x == 1 for x in la): - return self.sum_of_terms([(p, hall_polynomial(p, mu, la, self._q)) - for p in Partitions(sum(mu) + len(la))], - distinct=True) + return self.sum_of_terms([(p, hall_polynomial(p, mu, la, self._q)) for p in Partitions(sum(mu) + len(la))], distinct=True) I = HallAlgebraMonomials(self.base_ring(), self._q) mu = self.monomial(mu) @@ -348,8 +343,7 @@ def coproduct_on_basis(self, la): S = self.tensor_square() if all(x == 1 for x in la): n = len(la) - return S.sum_of_terms([((Partition([1]*r), Partition([1]*(n-r))), self._q**(-r*(n-r))) - for r in range(n+1)], distinct=True) + return S.sum_of_terms([((Partition([1] * r), Partition([1] * (n - r))), self._q ** (-r * (n - r))) for r in range(n + 1)], distinct=True) I = HallAlgebraMonomials(self.base_ring(), self._q) la = self.monomial(la) @@ -481,9 +475,7 @@ def scalar(self, y): (4*q^2 + 9)/(q^2 - q) """ q = self.parent()._q - f = lambda la: ~(q**(sum(la) + 2*la.weighted_size()) - * prod(prod((1 - q**-i) for i in range(1,k+1)) - for k in la.to_exp())) + f = lambda la: ~(q ** (sum(la) + 2 * la.weighted_size()) * prod(prod((1 - q**-i) for i in range(1, k + 1)) for k in la.to_exp())) y = self.parent()(y) ret = q.parent().zero() for mx, cx in self: @@ -561,6 +553,7 @@ class HallAlgebraMonomials(CombinatorialFreeModule): H[4, 1] + 7*H[3, 2] + 37*H[3, 1, 1] + 136*H[2, 2, 1] + 1495*H[2, 1, 1, 1] + 62920*H[1, 1, 1, 1, 1] """ + def __init__(self, base_ring, q, prefix='I'): """ Initialize ``self``. @@ -591,9 +584,7 @@ def __init__(self, base_ring, q, prefix='I'): category = HopfAlgebrasWithBasis(base_ring) else: category = AlgebrasWithBasis(base_ring) - CombinatorialFreeModule.__init__(self, base_ring, Partitions(), - prefix=prefix, bracket=False, - category=category) + CombinatorialFreeModule.__init__(self, base_ring, Partitions(), prefix=prefix, bracket=False, category=category) # Coercions if hopf_structure: @@ -620,7 +611,7 @@ def _to_natural_on_basis(self, a): + (q^5+2*q^4+3*q^3+3*q^2+2*q+1)*H[1, 1, 1, 1] """ H = HallAlgebra(self.base_ring(), self._q) - return reduce(lambda cur,r: cur * H.monomial(Partition([1]*r)), a, H.one()) + return reduce(lambda cur, r: cur * H.monomial(Partition([1] * r)), a, H.one()) def _repr_(self) -> str: """ @@ -686,8 +677,7 @@ def coproduct_on_basis(self, a): + (q^-1)*I[1, 1] # I[1] + I[2] # I[1] + I[2, 1] # I[] """ S = self.tensor_square() - return S.prod(S.sum_of_terms([((Partition([r]), Partition([n-r])), self._q**(-r*(n-r))) - for r in range(n+1)], distinct=True) for n in a) + return S.prod(S.sum_of_terms([((Partition([r]), Partition([n - r])), self._q ** (-r * (n - r))) for r in range(n + 1)], distinct=True) for n in a) def antipode_on_basis(self, a): """ diff --git a/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py b/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py index 46e6808f409..54af0e10330 100644 --- a/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py +++ b/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py @@ -36,7 +36,7 @@ - [MM1998]_ """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2016-2018 Travis Scrimshaw # 2016-2018 Andrew Mathas # @@ -45,7 +45,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.cachefunc import cached_method @@ -73,6 +73,7 @@ class _Basis(CombinatorialFreeModule, BindableClass): r""" Abstract base class for bases of the Ariki-Koike algebra. """ + def __init__(self, algebra, prefix='AK'): r""" Initialize ``self``. @@ -92,9 +93,7 @@ def __init__(self, algebra, prefix='AK'): self._one_perm = self._Pn.one() C = cartesian_product([range(self._r)] * self._n) indices = cartesian_product([C, self._Pn]) - CombinatorialFreeModule.__init__(self, algebra.base_ring(), indices, - prefix=prefix, - category=algebra._BasesCategory()) + CombinatorialFreeModule.__init__(self, algebra.base_ring(), indices, prefix=prefix, category=algebra._BasesCategory()) @cached_method def one_basis(self): @@ -266,6 +265,7 @@ class ArikiKoikeAlgebra(Parent, UniqueRepresentation): sage: all(Ji^3 == A.one() for Ji in J) True """ + @staticmethod def __classcall_private__(cls, r, n, q=None, u=None, R=None, use_fraction_field=False): r""" @@ -297,10 +297,11 @@ def __classcall_private__(cls, r, n, q=None, u=None, R=None, use_fraction_field= if q is None: q = 'q' else: - if not isinstance(u, (list,tuple)): - u = [u]*r + if not isinstance(u, (list, tuple)): + u = [u] * r if R is None: from sage.structure.element import get_coercion_model + cm = get_coercion_model() if q is None: R = cm.common_parent(*[val.parent() for val in u]) @@ -358,8 +359,7 @@ def _repr_(self) -> str: over Multivariate Polynomial Ring in u0, u1, u2, u3, u4 over Integer Ring """ - return "Ariki-Koike algebra of rank {} and order {} with q={} and u={} over {}".format( - self._r, self._n, self._q, self._u, self.base_ring()) + return "Ariki-Koike algebra of rank {} and order {} with q={} and u={} over {}".format(self._r, self._n, self._q, self._u, self.base_ring()) def _latex_(self) -> str: r""" @@ -427,12 +427,14 @@ def specht_module(self, la): over ... over Integer Ring """ from sage.algebras.hecke_algebras.ariki_koike_specht_modules import SpechtModule + return SpechtModule(self, la) class _BasesCategory(Category_realization_of_parent): r""" The category of bases of a Ariki-Koike algebra. """ + def __init__(self, base): r""" Initialize ``self``. @@ -484,6 +486,7 @@ class ParentMethods: cases, these are just default implementations that will get specialized in a basis. """ + def _repr_(self) -> str: r""" Text representation of this basis of Iwahori-Hecke algebra. @@ -560,6 +563,7 @@ def dimension(self): 29160 """ from sage.arith.misc import factorial + return self._r**self._n * factorial(self._n) def some_elements(self): @@ -575,9 +579,9 @@ def some_elements(self): """ G = self.algebra_generators() elts = [self.an_element()] + list(G) - elts += [self.L(1)**2] + elts += [self.L(1) ** 2] if self._n > 1: - elts += [self.L(2)**(self._r//2)] + elts += [self.L(2) ** (self._r // 2)] return elts def specht_module(self, la): @@ -596,6 +600,7 @@ def specht_module(self, la): True """ from sage.algebras.hecke_algebras.ariki_koike_specht_modules import SpechtModule + return SpechtModule(self.realization_of(), la) # ----------------------------------------------------- @@ -611,6 +616,7 @@ class LT(_Basis): This was the basis defined in [AK1994]_ except using the renormalized Jucys-Murphy elements. """ + def __init__(self, algebra): r""" Initialize ``self``. @@ -640,8 +646,7 @@ def _repr_term(self, m) -> str: 'L1*L3^2*T[2,1,2]' """ gen_str = lambda e: '' if e == 1 else '^%s' % e - lhs = '*'.join('L%s' % (j+1) + gen_str(i) - for j,i in enumerate(m[0]) if i > 0) + lhs = '*'.join('L%s' % (j + 1) + gen_str(i) for j, i in enumerate(m[0]) if i > 0) redword = m[1].reduced_word() if not redword: if not lhs: @@ -663,8 +668,7 @@ def _latex_term(self, m) -> str: 'L_{1} L_{3}^{2} T_{2} T_{1} T_{2}' """ gen_str = lambda e: '' if e == 1 else '^{%s}' % e - lhs = ' '.join('L_{%s}' % (j+1) + gen_str(i) - for j,i in enumerate(m[0]) if i > 0) + lhs = ' '.join('L_{%s}' % (j + 1) + gen_str(i) for j, i in enumerate(m[0]) if i > 0) redword = m[1].reduced_word() if not redword: if not lhs: @@ -701,19 +705,15 @@ def _from_T_basis(self, t): ret = self.one() T = list(self._zero_tuple) one = self.base_ring().one() - for i,k in enumerate(t[0]): + for i, k in enumerate(t[0]): if k == 0: continue - perm = self._Pn.prod(self._Pn.simple_reflection(j) - for j in range(1,i+1)) - ret = ret * self._from_dict({(self._zero_tuple, perm): one}, - remove_zeros=False, coerce=False) + perm = self._Pn.prod(self._Pn.simple_reflection(j) for j in range(1, i + 1)) + ret = ret * self._from_dict({(self._zero_tuple, perm): one}, remove_zeros=False, coerce=False) T[0] = k - ret = ret * self._from_dict({(tuple(T), self._one_perm): one}, - remove_zeros=False, coerce=False) + ret = ret * self._from_dict({(tuple(T), self._one_perm): one}, remove_zeros=False, coerce=False) - return ret * self._from_dict({(self._zero_tuple, t[1]): one}, - remove_zeros=False, coerce=False) + return ret * self._from_dict({(self._zero_tuple, t[1]): one}, remove_zeros=False, coerce=False) @cached_method def algebra_generators(self): @@ -733,9 +733,9 @@ def algebra_generators(self): d = {} if self._r != 1: for i in range(self._n): - r = list(self._zero_tuple) # Make a copy + r = list(self._zero_tuple) # Make a copy r[i] = 1 - d['L%s' % (i+1)] = self.monomial((tuple(r), self._one_perm)) + d['L%s' % (i + 1)] = self.monomial((tuple(r), self._one_perm)) G = self._Pn.group_generators() for i in range(1, self._n): d['T%s' % i] = self.monomial((self._zero_tuple, G[i])) @@ -795,8 +795,8 @@ def L(self, i=None): G = self.algebra_generators() if i is None: if self._r == 1: - return [self._Li_power(j, 1) for j in range(1, self._n+1)] - return [G['L%s' % j] for j in range(1, self._n+1)] + return [self._Li_power(j, 1) for j in range(1, self._n + 1)] + return [G['L%s' % j] for j in range(1, self._n + 1)] if self._r == 1: return self._Li_power(i, 1) return G['L%s' % i] @@ -852,21 +852,20 @@ def product_on_basis(self, m1, m2): # otherwise we may end up in an infinite loop... # Product is of the form L1*T1*L2*T2: separate the L's and permutations - L1,T1 = m1 - L2,T2 = m2 + L1, T1 = m1 + L2, T2 = m2 if sum(L2) == 0: # Compute and return the product of T1 and T2, whilst fixing L - return self._from_dict(self._product_LTwTv(L1, T1, T2), - remove_zeros=False, coerce=False) + return self._from_dict(self._product_LTwTv(L1, T1, T2), remove_zeros=False, coerce=False) # If T1 is trivial then we just have L1*L2*T2 we only need to rewrite # all of the "large" powers that appear in L1*L2. Unfortunately, this # will almost certainly introduce more T_w's and it will be recursive # because L_n^r, for example, will introduce many powers of L_k for k 0) - * self.monomial((self._zero_tuple, T2)) - ) + return self.monomial((tuple(Lsmall), self._one_perm)) * prod(self._Li_power(i + 1, Lbig[i]) for i in reversed(range(self._n)) if Lbig[i] > 0) * self.monomial((self._zero_tuple, T2)) # If we are still here then both T1 and L2 are non-trivial. Using the # method _product_Tw_L we expand the product T1*L2 as a linear # combination of standard basis elements using the method and then, # recursively, multiply on the left and right by L1 and T2, # respectively. In other words, we multiply as L1*(T1*L2)*T2. - return (self.monomial((L1, self._one_perm)) - * self._product_Tw_L(T1, L2) - * self.monomial((self._zero_tuple, T2))) + return self.monomial((L1, self._one_perm)) * self._product_Tw_L(T1, L2) * self.monomial((self._zero_tuple, T2)) def _product_LTwTv(self, L, w, v): r""" @@ -1011,26 +1004,26 @@ def _product_Tw_L(self, w, L): for lv, c in wL.items(): L = list(lv[0]) # make a copy v = lv[1] - a, b = L[i-1], L[i] - L[i-1], L[i] = L[i], L[i-1] # swap L_i=L[i-1] and L_{i+1}=L[i] + a, b = L[i - 1], L[i] + L[i - 1], L[i] = L[i], L[i - 1] # swap L_i=L[i-1] and L_{i+1}=L[i] # the term L_1^{a_1} ... L_i^{a_{i+1}} L_{i+1}^{a_i} ... L_n^{a_n} T_i T_v # always appears - iaxpy(c, self._product_LTwTv(tuple(L), self._Pn.simple_reflections()[i], v), iL) # need T_i*T_v + iaxpy(c, self._product_LTwTv(tuple(L), self._Pn.simple_reflections()[i], v), iL) # need T_i*T_v if a < b: - Ls = [list(L) for k in range(b-a)] # make copies of L - for k in range(b-a): - Ls[k][i-1] = a + k + Ls = [list(L) for k in range(b - a)] # make copies of L + for k in range(b - a): + Ls[k][i - 1] = a + k Ls[k][i] = b - k - c *= (q - one) + c *= q - one iaxpy(1, {(tuple(l), v): c for l in Ls}, iL) elif a > b: - Ls = [list(L) for k in range(a-b)] # make copies of L - for k in range(a-b): - Ls[k][i-1] = b + k + Ls = [list(L) for k in range(a - b)] # make copies of L + for k in range(a - b): + Ls[k][i - 1] = b + k Ls[k][i] = a - k - c *= (one - q) + c *= one - q iaxpy(1, {(tuple(l), v): c for l in Ls}, iL) wL = iL # replace wL with iL and repeat @@ -1097,35 +1090,31 @@ def _Li_power(self, i, m): - (q^-2-2*q^-1+1)*L1*L2*L3*T[1,2] - (q^-2-2*q^-1+1)*L1^2*L3*T[1,2] - (q^-2-q^-1)*L1^2*L3*T[2,1,2] """ + # shorthand for returning a tuple of the form (0,...,a,b,...,0) with a,b # in the (i-1)th and i-th positions, respectively def Ltuple(a, b): - return tuple([b if j == i else a if j == i-1 else 0 - for j in range(1,self._n+1)]) + return tuple([b if j == i else a if j == i - 1 else 0 for j in range(1, self._n + 1)]) # return "small" powers of the generators without change if m < self._r: return self.monomial((Ltuple(0, m), self._one_perm)) if i > 1: - si = self._Pn.simple_reflections()[i-1] + si = self._Pn.simple_reflections()[i - 1] qsum = self.base_ring().one() - self._q**-1 # by calling _Li_power we avoid infinite recursion here - return (self.sum_of_terms(((Ltuple(c, m-c), si), qsum) for c in range(1, m)) - + self._q**-1 * self.T(i-1) * self._Li_power(i-1, m) * self.T(i-1)) + return self.sum_of_terms(((Ltuple(c, m - c), si), qsum) for c in range(1, m)) + self._q**-1 * self.T(i - 1) * self._Li_power(i - 1, m) * self.T(i - 1) # now left with the case i = 1 and m >= r if m > self._r: - return self.monomial((Ltuple(0, 1), self._one_perm)) * self._Li_power(i,m-1) + return self.monomial((Ltuple(0, 1), self._one_perm)) * self._Li_power(i, m - 1) z = PolynomialRing(self.base_ring(), 'DUMMY').gen() p = list(prod(z - val for val in self._u)) # [:-1] p.pop() # remove the highest power zero = self.base_ring().zero() - return self._from_dict({(Ltuple(0, exp), self._one_perm): -coeff - for exp, coeff in enumerate(p) - if coeff != zero}, - remove_zeros=False, coerce=False) + return self._from_dict({(Ltuple(0, exp), self._one_perm): -coeff for exp, coeff in enumerate(p) if coeff != zero}, remove_zeros=False, coerce=False) @cached_method def inverse_T(self, i): @@ -1176,11 +1165,11 @@ def __invert__(self): """ if len(self) != 1: raise NotImplementedError("inverse only implemented for monomials") - l,w = self.support_of_term() + l, w = self.support_of_term() if sum(l) != 0: raise NotImplementedError("inverse only implemented for monomials in T variables") H = self.parent() - return ~self[l,w] * H.prod(H.inverse_T(i) for i in reversed(w.reduced_word())) + return ~self[l, w] * H.prod(H.inverse_T(i) for i in reversed(w.reduced_word())) class T(_Basis): r""" @@ -1197,6 +1186,7 @@ class T(_Basis): `T_{1,k} = T_0^k`) and `w` is a reduced expression of an element in `\mathfrak{S}_n`. """ + def __init__(self, algebra): r""" Initialize ``self``. @@ -1223,7 +1213,7 @@ def _basis_to_word(self, t): for i, k in enumerate(t[0]): if not k: continue - redword.extend(list(range(i, 0, -1)) + [0]*k) + redword.extend(list(range(i, 0, -1)) + [0] * k) redword.extend(t[1].reduced_word()) return redword @@ -1240,8 +1230,7 @@ def _repr_term(self, t) -> str: redword = self._basis_to_word(t) if not redword: return "1" - return (self._print_options['prefix'] - + '[%s]' % ','.join('%d' % i for i in redword)) + return self._print_options['prefix'] + '[%s]' % ','.join('%d' % i for i in redword) def _latex_term(self, t) -> str: r""" @@ -1256,8 +1245,7 @@ def _latex_term(self, t) -> str: redword = self._basis_to_word(t) if not redword: return "1" - return ''.join("%s_{%d}" % (self._print_options['prefix'], i) - for i in redword) + return ''.join("%s_{%d}" % (self._print_options['prefix'], i) for i in redword) def _from_LT_basis(self, m): r""" @@ -1289,7 +1277,7 @@ def _from_LT_basis(self, m): sage: all(T(LT(b)) == b for b in T.basis()) # indirect doctest True """ - ret = self.prod(self.L(i+1)**k for i,k in enumerate(m[0])) + ret = self.prod(self.L(i + 1) ** k for i, k in enumerate(m[0])) return ret * self.monomial((self._zero_tuple, m[1])) @cached_method @@ -1400,14 +1388,14 @@ def L(self, i=None): True """ if i is None: - return [self.L(j) for j in range(1, self._n+1)] + return [self.L(j) for j in range(1, self._n + 1)] if i == 1: if self._r == 1: return self.from_base_ring(self._u[0]) return self.T(0) T = self.T() - return self._q**-1 * T[i-1] * self.L(i-1) * T[i-1] + return self._q**-1 * T[i - 1] * self.L(i - 1) * T[i - 1] @cached_method def product_on_basis(self, m1, m2): @@ -1491,8 +1479,8 @@ def product_on_basis(self, m1, m2): return self._from_dict({m2: one}, remove_zeros=False) if t2 == self._zero_tuple: return self._from_dict({(t1, s2): one}, remove_zeros=False) - k1 = max(k for k,a in enumerate(t1) if a != 0) - k2 = min(k for k,a in enumerate(t2) if a != 0) + k1 = max(k for k, a in enumerate(t1) if a != 0) + k2 = min(k for k, a in enumerate(t2) if a != 0) if k1 < k2: T = list(t1) for k in range(k2, len(t2)): @@ -1529,13 +1517,13 @@ def product_on_basis(self, m1, m2): # So S_{k-1} T_{k,a} = (q-1) T_{k,a} + q T_{k-1,a} # Make a copy of T since we need to mutate it new_t.append((list(T), {s: q * sprod[s] for s in sprod})) - new_t[-1][0][ind] = (k-1, a) + new_t[-1][0][ind] = (k - 1, a) for s in sprod: sprod[s] *= qm1 break elif j == k + 1: absorbed = True - T[ind] = (k+1, a) + T[ind] = (k + 1, a) break # elif j > k: pass if absorbed: @@ -1544,7 +1532,7 @@ def product_on_basis(self, m1, m2): continue # Do the usual Hecke product of S_j * S - temp = {} # start from 0 + temp = {} # start from 0 for p in sprod: c = sprod[p] # We have to flip the side due to Sage's @@ -1560,11 +1548,9 @@ def product_on_basis(self, m1, m2): # Compute t1 * T * sprod def compute(T, sprod): if not T: # T=1, so just do t1 * sprod, each of which is in order - return self._from_dict({(t1, s): sprod[s] for s in sprod}, - remove_zeros=False, coerce=False) + return self._from_dict({(t1, s): sprod[s] for s in sprod}, remove_zeros=False, coerce=False) - s_elt = self._from_dict({(self._zero_tuple, s): sprod[s] for s in sprod}, - remove_zeros=False, coerce=False) + s_elt = self._from_dict({(self._zero_tuple, s): sprod[s] for s in sprod}, remove_zeros=False, coerce=False) # Break T into basis vectors as much as possible to best take # advantage of the caching cur = list(t1) @@ -1573,7 +1559,7 @@ def compute(T, sprod): K = max(k for k, a in enumerate(t1) if a != 0) else: K = -1 - T.reverse() # reverse the list so we can pop off the front + T.reverse() # reverse the list so we can pop off the front while T: k, a = T.pop() if k > K: @@ -1583,9 +1569,7 @@ def compute(T, sprod): cur[k] = a product.append(cur) K = k - return self.prod(self._from_dict({(tuple(p), self._one_perm): one}, - remove_zeros=False, coerce=False) - for p in product) * s_elt + return self.prod(self._from_dict({(tuple(p), self._one_perm): one}, remove_zeros=False, coerce=False) for p in product) * s_elt return self.sum(compute(T, sprod) for T, sprod in tprod) @@ -1634,11 +1618,9 @@ def _reduced_T0_power(self, exp): return self.base_ring().one() PR = self._T0_polynomial.parent() z = PR.gen() - cur = z ** exp + cur = z**exp while cur.degree() >= self._r: - cur = (PR.sum(coeff * self._T0_polynomial * z**e - for e, coeff in enumerate(cur.list()[self._r:])) - + cur.truncate(self._r)) + cur = PR.sum(coeff * self._T0_polynomial * z**e for e, coeff in enumerate(cur.list()[self._r :])) + cur.truncate(self._r) return cur @cached_method @@ -1714,8 +1696,7 @@ def _product_TT(self, kp, a, k, b): if a + b < self._r: T = list(self._zero_tuple) T[kp] = a + b - return self._from_dict({(tuple(T), self._one_perm): one}, - remove_zeros=False, coerce=False) + return self._from_dict({(tuple(T), self._one_perm): one}, remove_zeros=False, coerce=False) def key(exp): if exp > 0 or kp == 0: @@ -1725,22 +1706,20 @@ def key(exp): # Note that kp is 0-based, but our 0-index in the T portion # is the power of T_0 perm = self._Pn.one() - for j in range(1, kp+1): + for j in range(1, kp + 1): perm = perm.apply_simple_reflection_left(j) return (self._zero_tuple, perm) + p = self._reduced_T0_power(a + b) zero = self.base_ring().zero() - return self._from_dict({key(exp): coeff - for exp, coeff in enumerate(p) - if coeff != zero}, - remove_zeros=False, coerce=False) + return self._from_dict({key(exp): coeff for exp, coeff in enumerate(p) if coeff != zero}, remove_zeros=False, coerce=False) # Otherwise k > 0 assert kp >= k s1 = self._Pn.simple_reflection(1) qm1 = self._q - one T = list(self._zero_tuple) - T[k-1] = b + T[k - 1] = b T[kp] = a ret = {(tuple(T), s1): one} zero = self.base_ring().zero() @@ -1750,40 +1729,39 @@ def T_index(exp, ind, i, indp): T[ind] = exp T[indp] = i return tuple(T) - for i in range(1, b+1): + + for i in range(1, b + 1): if a + b - i == i: continue if a + b - i < self._r: - T[k-1] = a + b - i + T[k - 1] = a + b - i T[kp] = i m = (tuple(T), self._one_perm) - T[k-1] = i + T[k - 1] = i T[kp] = a + b - i mp = (tuple(T), self._one_perm) iaxpy(1, {m: qm1, mp: -qm1}, ret) else: p = self._reduced_T0_power(a + b - i) - temp = {(T_index(exp, k-1, i, kp), self._one_perm): qm1 * coeff - for exp, coeff in enumerate(p) if coeff != zero} + temp = {(T_index(exp, k - 1, i, kp), self._one_perm): qm1 * coeff for exp, coeff in enumerate(p) if coeff != zero} if p[0] != zero and k > 1: # We need to add back in the permutation for the "T_{k-1,0}" # in the reduction from T_{k-1,a+b-i} perm = self._Pn.one() - for j in range(2, k+1): # Recall k is 0-based, we add 1 back from Lemma 2.3(a) + for j in range(2, k + 1): # Recall k is 0-based, we add 1 back from Lemma 2.3(a) perm = perm.apply_simple_reflection_left(j) - tind = T_index(0, k-1, i, kp) + tind = T_index(0, k - 1, i, kp) temp[(tind, perm)] = temp[(tind, self._one_perm)] del temp[(tind, self._one_perm)] iaxpy(1, temp, ret) - temp = {(T_index(exp, kp, i, k-1), self._one_perm): -qm1 * coeff - for exp, coeff in enumerate(p) if coeff != zero} + temp = {(T_index(exp, kp, i, k - 1), self._one_perm): -qm1 * coeff for exp, coeff in enumerate(p) if coeff != zero} if p[0] != zero: # We need to add back in the permutation for the "T_{k',0}" # in the reduction from T_{k',a+b-i} perm = self._Pn.one() - for j in range(1, kp+1): # Recall kp is 0-based + for j in range(1, kp + 1): # Recall kp is 0-based perm = perm.apply_simple_reflection_left(j) - tind = T_index(0, kp, i, k-1) + tind = T_index(0, kp, i, k - 1) temp[(tind, perm)] = temp[(tind, self._one_perm)] del temp[(tind, self._one_perm)] iaxpy(1, temp, ret) diff --git a/src/sage/algebras/hecke_algebras/ariki_koike_specht_modules.py b/src/sage/algebras/hecke_algebras/ariki_koike_specht_modules.py index d72d9042ef8..80c1540dbd5 100644 --- a/src/sage/algebras/hecke_algebras/ariki_koike_specht_modules.py +++ b/src/sage/algebras/hecke_algebras/ariki_koike_specht_modules.py @@ -6,7 +6,7 @@ - Travis Scrimshaw (2023-12-28): Initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2023 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.misc_c import prod from sage.misc.latex import latex @@ -109,6 +109,7 @@ class SpechtModule(CombinatorialFreeModule): - [Mathas2002]_ - [Mathas2004]_ """ + @staticmethod def __classcall_private__(cls, AK, la): """ @@ -210,22 +211,21 @@ def apply_T0_power(b, exp): AKelts = self._AK.some_elements() for b in tester.some_elements(): - t0 = self.linear_combination((apply_T0_power(b, exp), c) - for exp, c in enumerate(T0_poly)) + t0 = self.linear_combination((apply_T0_power(b, exp), c) for exp, c in enumerate(T0_poly)) tester.assertEqual(t0, self.zero()) tester.assertEqual(b.T([0, 1, 0, 1]), b.T([1, 0, 1, 0])) - tester.assertEqual(b.T(1).T(1), (q-1)*b.T(1) + q*b) + tester.assertEqual(b.T(1).T(1), (q - 1) * b.T(1) + q * b) for i in range(2, n): - tester.assertEqual(b.T(i).T(i), (q-1)*b.T(i) + q*b) + tester.assertEqual(b.T(i).T(i), (q - 1) * b.T(i) + q * b) tester.assertEqual(b.T(i).T(0), b.T(0).T(i)) if i < n - 1: - tester.assertEqual(b.T([i, i+1, i]), b.T([i+1, i, i+1])) - for j in range(i+2, n): + tester.assertEqual(b.T([i, i + 1, i]), b.T([i + 1, i, i + 1])) + for j in range(i + 2, n): tester.assertEqual(b.T([i, j]), b.T([j, i])) - for (x, y) in some_tuples(AKelts, 2, tester._max_runs): - tester.assertEqual(b*(x*y), (b*x)*y) + for x, y in some_tuples(AKelts, 2, tester._max_runs): + tester.assertEqual(b * (x * y), (b * x) * y) def _L_on_basis(self, i, t): """ @@ -252,7 +252,7 @@ def _L_on_basis(self, i, t): c = t.cells_containing(i)[0] if len(c) == 2: # it is of level 1 and a regular tableau c = (0,) + c - res = self._q**(c[2]-c[1]) * self._u[c[0]] + res = self._q ** (c[2] - c[1]) * self._u[c[0]] R = self.base_ring() return self.element_class(self, {t: R(res)}) @@ -288,7 +288,7 @@ def _T_on_basis(self, i, t): return self._L_on_basis(1, t) ct = t.cells_containing(i)[0] - cs = t.cells_containing(i+1)[0] + cs = t.cells_containing(i + 1)[0] if len(ct) == 2: # it is of level 1 and a regular tableau ct = (0,) + ct cs = (0,) + cs @@ -304,7 +304,7 @@ def _T_on_basis(self, i, t): assert s.parent() is t.parent() def res(cell): - return self._q**(cell[2]-cell[1]) * self._u[cell[0]] + return self._q ** (cell[2] - cell[1]) * self._u[cell[0]] # Note that the residue of i in t is given by the cell c # and of i in s corresponds to cell cp because the @@ -376,12 +376,10 @@ def _acted_upon_(self, scalar, self_on_left): return None scalar = P._AK(scalar) if scalar.parent() is P._AK.LT(): - return P.linear_combination((self.L(sum(([i]*val for i, val in enumerate(m[0], start=1)), [])).T(m[1].reduced_word()), c) - for m, c in scalar) + return P.linear_combination((self.L(sum(([i] * val for i, val in enumerate(m[0], start=1)), [])).T(m[1].reduced_word()), c) for m, c in scalar) if scalar.parent() is P._AK.T(): AKT = P._AK.T() - return P.linear_combination((self.T(AKT._basis_to_word(m)), c) - for m, c in scalar) + return P.linear_combination((self.T(AKT._basis_to_word(m)), c) for m, c in scalar) return self * P._AK.LT()(scalar) def L(self, i): diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index 07c037028c6..0a6ec4738c1 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -113,6 +113,7 @@ - Sebastian Oehms May 2020: initial version """ + # ########################################################################### # Copyright (C) 2020 Sebastian Oehms # @@ -155,6 +156,7 @@ class CubicHeckeElement(CombinatorialFreeModule.Element): sage: c1**3*~c2 u*w*c1^-1*c2^-1 + (u^2-v)*c1*c2^-1 - (u*v-w)*c2^-1 """ + # -------------------------------------------------------------------------- # Overloading inherited methods # -------------------------------------------------------------------------- @@ -186,8 +188,7 @@ def __invert__(self): inverse_Tietze = () len_self = len(self_Tietze) - inverse_Tietze = tuple([-1 * self_Tietze[len_self - i - 1] - for i in range(len_self)]) + inverse_Tietze = tuple([-1 * self_Tietze[len_self - i - 1] for i in range(len_self)]) P = self.parent() return P(inverse_Tietze) @@ -263,8 +264,8 @@ def braid_group_algebra_pre_image(self): def phi(bas_ele): return braid_group_algebra(braid_group(bas_ele)) - return ch_algebra._apply_module_morphism(self, phi, - codomain=braid_group_algebra) + + return ch_algebra._apply_module_morphism(self, phi, codomain=braid_group_algebra) def cubic_braid_group_algebra_pre_image(self): r""" @@ -296,8 +297,8 @@ def cubic_braid_group_algebra_pre_image(self): def phi(bas_ele): return cbraid_group_algebra(cbraid_group(bas_ele)) - return ch_algebra._apply_module_morphism(self, phi, - codomain=cbraid_group_algebra) + + return ch_algebra._apply_module_morphism(self, phi, codomain=cbraid_group_algebra) @cached_method def matrix(self, subdivide=False, representation_type=None, original=False): @@ -781,6 +782,7 @@ class CubicHeckeAlgebra(CombinatorialFreeModule): would take up to half an hour if the file cache is empty. A repetition takes less than half a minute. """ + Element = CubicHeckeElement repr_type = RepresentationType irred_repr = AbsIrreducibeRep @@ -827,10 +829,9 @@ def __classcall_private__(cls, n=None, names='c', cubic_equation_parameters=None n = len(names) from sage.structure.category_object import normalize_names + names = tuple(normalize_names(n, names)) - return super().__classcall__(cls, names, - cubic_equation_parameters=cubic_equation_parameters, - cubic_equation_roots=cubic_equation_roots) + return super().__classcall__(cls, names, cubic_equation_parameters=cubic_equation_parameters, cubic_equation_roots=cubic_equation_roots) def __init__(self, names, cubic_equation_parameters=None, cubic_equation_roots=None): r""" @@ -856,6 +857,7 @@ def __init__(self, names, cubic_equation_parameters=None, cubic_equation_roots=N # preparing use of data base anf file cache # ---------------------------------------------------------------------- from sage.databases.cubic_hecke_db import CubicHeckeDataBase, CubicHeckeFileCache + self._database = CubicHeckeDataBase() self._filecache = CubicHeckeFileCache(self._nstrands) @@ -910,9 +912,7 @@ def __init__(self, names, cubic_equation_parameters=None, cubic_equation_roots=N raise ValueError('cubic_equation_roots must consist of exactly 3 elements') if len(set(ring_of_definition_names + generic_extension_ring_names)) < 6: - raise ValueError('there is an overlap of names between cubic equation ' - 'parameters (%s) and cubic equation roots (%s)' - % (ring_of_definition_names, generic_extension_ring_names)) + raise ValueError('there is an overlap of names between cubic equation ' 'parameters (%s) and cubic equation roots (%s)' % (ring_of_definition_names, generic_extension_ring_names)) # ---------------------------------------------------------------------- # setting the generic rings @@ -937,22 +937,18 @@ def __init__(self, names, cubic_equation_parameters=None, cubic_equation_roots=N # ---------------------------------------------------------------------- if cubic_equation_parameters is None and cubic_equation_roots is not None: pa, pb, pc = cubic_equation_roots - cubic_equation_parameters = [pa+pb+pc, pa*pb+pb*pc+pa*pc, pa*pb*pc] - verbose('cubic_equation_parameters %s set according to ' - 'cubic_equation_roots %s' % (cubic_equation_parameters, - cubic_equation_roots), level=2) + cubic_equation_parameters = [pa + pb + pc, pa * pb + pb * pc + pa * pc, pa * pb * pc] + verbose('cubic_equation_parameters %s set according to ' 'cubic_equation_roots %s' % (cubic_equation_parameters, cubic_equation_roots), level=2) if cubic_equation_parameters is not None: base_ring = ring_of_definition.create_specialization(cubic_equation_parameters) cubic_equation_parameters = [base_ring(para) for para in cubic_equation_parameters] - verbose('base_ring %s set according to cubic_equation_parameters %s' - % (base_ring, cubic_equation_parameters), level=2) + verbose('base_ring %s set according to cubic_equation_parameters %s' % (base_ring, cubic_equation_parameters), level=2) else: base_ring = self._ring_of_definition cubic_equation_parameters = self._generic_cubic_equation_parameters - verbose('base_ring %s and cubic_equation_parameters %s defined' - % (base_ring, cubic_equation_parameters), level=2) + verbose('base_ring %s and cubic_equation_parameters %s defined' % (base_ring, cubic_equation_parameters), level=2) # ---------------------------------------------------------------------- # defining the cubic equation @@ -972,9 +968,7 @@ def __init__(self, names, cubic_equation_parameters=None, cubic_equation_roots=N # No roots given # -------------------------------------------------------------- ext_ring_names = list(generic_extension_ring_names) - cubic_equation_roots = solve_with_extension(cubic_equation, - ext_ring_names, - var='S', flatten=True) + cubic_equation_roots = solve_with_extension(cubic_equation, ext_ring_names, var='S', flatten=True) # ---------------------------------------------------------------------- # interpreting user given cubic equation roots to define the @@ -983,15 +977,13 @@ def __init__(self, names, cubic_equation_parameters=None, cubic_equation_roots=N if cubic_equation_roots is not None: extension_ring = generic_extension_ring.create_specialization(cubic_equation_roots) cubic_equation_roots = [extension_ring(root) for root in cubic_equation_roots] - verbose('extension_ring %s set according to cubic_equation_roots %s' - % (base_ring, cubic_equation_roots), level=2) + verbose('extension_ring %s set according to cubic_equation_roots %s' % (base_ring, cubic_equation_roots), level=2) else: extension_ring = generic_extension_ring.as_splitting_algebra() cubic_equation_roots = [extension_ring(a), extension_ring(b), extension_ring(c)] - verbose('cubic roots %s and extension ring %s defined' - % (cubic_equation_roots, extension_ring), level=2) + verbose('cubic roots %s and extension ring %s defined' % (cubic_equation_roots, extension_ring), level=2) pa, pb, pc = cubic_equation_roots # ---------------------------------------------------------------------- @@ -1007,7 +999,7 @@ def __init__(self, names, cubic_equation_parameters=None, cubic_equation_roots=N # ---------------------------------------------------------------------- # defining the base ring embedding into the extension ring # ---------------------------------------------------------------------- - im_base_gens = [pa+pb+pc, pa*pb+pa*pc+pb*pc, pa*pb*pc] + im_base_gens = [pa + pb + pc, pa * pb + pa * pc + pb * pc, pa * pb * pc] base_ring_embedding = extension_ring.coerce_map_from(base_ring) def check_base_ring_embedding(base_ring_embedding): @@ -1053,6 +1045,7 @@ def check_base_ring_embedding(base_ring_embedding): # defining the associated group algebras # ---------------------------------------------------------------------- from sage.algebras.group_algebra import GroupAlgebra + self._cubic_braid_group_algebra = GroupAlgebra(self._cubic_braid_group, R=base_ring) self._braid_group_algebra = GroupAlgebra(self._braid_group, R=base_ring) @@ -1093,14 +1086,14 @@ def check_base_ring_embedding(base_ring_embedding): # ---------------------------------------------------------------------- if self._cubic_braid_group.is_finite(): from sage.categories.finite_dimensional_algebras_with_basis import FiniteDimensionalAlgebrasWithBasis + category = FiniteDimensionalAlgebrasWithBasis(base_ring) else: from sage.categories.algebras_with_basis import AlgebrasWithBasis + category = AlgebrasWithBasis(base_ring) - CombinatorialFreeModule.__init__(self, base_ring, self._cubic_braid_group, - prefix='', names=names, bracket=False, - category=category) + CombinatorialFreeModule.__init__(self, base_ring, self._cubic_braid_group, prefix='', names=names, bracket=False, category=category) # ---------------------------------------------------------------------- # init the attributes being set on demand @@ -1252,7 +1245,7 @@ def _element_constructor_(self, x): img_xbv = vector([self.base_ring()(cf) for cf in xbv]) return self.from_vector(img_xbv) if other_ngens < ngens: - sub_alg = self.cubic_hecke_subalgebra(other_ngens+1) + sub_alg = self.cubic_hecke_subalgebra(other_ngens + 1) return self(sub_alg(xb)) elif other_ngens < ngens and other_params == params: @@ -1261,6 +1254,7 @@ def _element_constructor_(self, x): def fc(ele): return cbraid_img(cbraid_grp(ele)) + result = other_cbga._apply_module_morphism(cbraid_preimg, fc, codomain=self) verbose('end from smaller cubic Hecke algebra %s: %s' % (xb, result), level=2) return result @@ -1278,11 +1272,13 @@ def fc(ele): def fb(ele): return braid_img(ele) + result = braid_grp_alg._apply_module_morphism(xb, fb, codomain=self) verbose('end from braid_group algebra %s: %s' % (xb, result), level=2) return result from sage.groups.braid import Braid + if isinstance(xb, Braid) and xb.strands() == self._nstrands: result = braid_img(xb) verbose('end from braid_group %s: %s' % (xb, result), level=2) @@ -1298,6 +1294,7 @@ def fb(ele): return result from sage.groups.cubic_braid import CubicBraidElement + if isinstance(xb, CubicBraidElement) and xb.parent().strands() == self._nstrands: result = cbraid_img(xb) verbose('end from cubic braid_group %s: %s' % (xb, result), level=2) @@ -1363,6 +1360,7 @@ def _order_key(self, x): return self._rank_basis(x) except AttributeError: from sage.combinat.ranker import rank_from_list + self._rank_basis = rank_from_list(self._order) return self._rank_basis(x) @@ -1387,6 +1385,7 @@ def _dense_free_module(self, base_ring=None): if base_ring is None: base_ring = self.base_ring() from sage.modules.free_module import FreeModule + return FreeModule(base_ring, len(self.get_order())) def ngens(self): @@ -1412,6 +1411,7 @@ def algebra_generators(self): Finite family {c: c} """ from sage.sets.family import Family + return Family(self._cubic_braid_group.gens(), self.monomial) def gens(self) -> tuple: @@ -1465,18 +1465,18 @@ def _an_element_(self): n = self.ngens() + 1 base_ring = self.base_ring() u, v, w = (base_ring(para) for para in self._cubic_equation_parameters) - const = (u*~w - v) * self.one() + const = (u * ~w - v) * self.one() gens = self.gens() first_gens = [gen for gen in gens if gens.index(gen) < 3] if n == 2: - c1, = first_gens - return const + v*c1 + (c1,) = first_gens + return const + v * c1 if n == 3: c1, c2 = first_gens - return const + v*c1 - w*c1*~c2 + u*c2 + return const + v * c1 - w * c1 * ~c2 + u * c2 c1, c2, c3 = first_gens - return const + v*c1*~c3 - w*c1*~c2 + u*c3*c2 + return const + v * c1 * ~c3 - w * c1 * ~c2 + u * c3 * c2 @cached_method def chevie(self): @@ -1491,6 +1491,7 @@ def chevie(self): Hecke(G4,[[a,b,c]]) """ from sage.combinat.root_system.reflection_group_real import is_chevie_available + if not is_chevie_available(): raise NotImplementedError('this functionality needs GAP3 with package CHEVIE') @@ -1516,6 +1517,7 @@ def chevie(self): end;""" from sage.interfaces.gap3 import gap3 + gap3_function = gap3(gap3_function_str) na, nb, nc = ('\"%s\"' % indet for indet in self.extension_ring(generic=True).variable_names()) return gap3_function(st_number, na, nb, nc) @@ -1674,6 +1676,7 @@ def _fetch_matrix_list_from_chevie(self, number): GER = self.extension_ring(generic=True) gap3_result = self.chevie().Representations(number) from sage.matrix.constructor import matrix + matrix_list_gens = [matrix(GER, mat_gap) for mat_gap in gap3_result] for m in matrix_list_gens: m.set_immutable() @@ -1709,10 +1712,10 @@ def _test_ring_constructions(self, **options): a, b, c = self.cubic_equation_roots(generic=True) U, V, W = self.cubic_equation_parameters() u, v, w = self.cubic_equation_parameters(generic=True) - eleB = U*V - W**2 - eleBgen = u*v - w**2 - eleE = A*B - C**2 - eleEgen = a*b - c**2 + eleB = U * V - W**2 + eleBgen = u * v - w**2 + eleE = A * B - C**2 + eleEgen = a * b - c**2 mbr = self._ring_of_definition_map mer = self._generic_extension_ring_map @@ -1789,13 +1792,13 @@ def _test_matrix_constructions(self, **options): gens = self.gens() b1 = gens[0] b2 = self.an_element() - b12 = b1*b2 + b12 = b1 * b2 verbose('b12 %s' % b12) def check_matrix(representation_type): m1 = b1.matrix(representation_type=representation_type) m2 = b2.matrix(representation_type=representation_type) - m12mult = m1*m2 + m12mult = m1 * m2 m12mat = b12.matrix(representation_type=representation_type) test_matrix = self._tester(**options) test_matrix.assertEqual(m12mult, m12mat) @@ -1867,7 +1870,7 @@ def _init_basis_extension(self): cub_braid_group = self.cubic_braid_group() if not former_bas_ext: gens = cub_braid_group.gens() - last_gen = gens[len(gens)-1] + last_gen = gens[len(gens) - 1] self._cubic_braid_image(last_gen, check=False) self._cubic_braid_image(~last_gen, check=False) self._filecache.update_basis_extensions(self._basis_extension) @@ -1999,7 +2002,7 @@ def _braid_image(self, braid): result = self.zero() for i in range(len(coeffs)): braid_image = self._braid_image_from_reduced_powers(braids[i]) - result += coeffs[i]*braid_image + result += coeffs[i] * braid_image return result @@ -2039,7 +2042,7 @@ def _braid_image_from_reduced_powers(self, braid_tietze): if n == 1: if len_braid == 0: return self.one() - k = braid_tietze[0]*len_braid + k = braid_tietze[0] * len_braid result_vect = self._reduce_gen_power(k) return self.from_vector(result_vect) @@ -2290,9 +2293,9 @@ def _reduce_all_gen_powers(self, braid_tietze): continue pos = i for power in range(1, len_braid - pos + 1): - if pos+power == len_braid: + if pos + power == len_braid: break - if braid_list[pos] != braid_list[pos+power]: + if braid_list[pos] != braid_list[pos + power]: break break @@ -2312,7 +2315,7 @@ def _reduce_all_gen_powers(self, braid_tietze): exp = -power braid_list_start = [braid_list[i] for i in range(pos)] - braid_list_end = [braid_list[i] for i in range(pos+power, len_braid)] + braid_list_end = [braid_list[i] for i in range(pos + power, len_braid)] # ---------------------------------------------------------------------- # merging the new reduced tuple. Note that all the new tuples are @@ -2343,9 +2346,9 @@ def _reduce_all_gen_powers(self, braid_tietze): cf_one, cf_gen, cf_gen_inv = self._reduce_gen_power(exp) - one_coeffs = [cf*cf_one for cf in one_coeffs] - gen_coeffs = [cf*cf_gen for cf in gen_coeffs] - gen_inv_coeffs = [cf*cf_gen_inv for cf in gen_inv_coeffs] + one_coeffs = [cf * cf_one for cf in one_coeffs] + gen_coeffs = [cf * cf_gen for cf in gen_coeffs] + gen_inv_coeffs = [cf * cf_gen_inv for cf in gen_inv_coeffs] return one_coeffs + gen_coeffs + gen_inv_coeffs, one_braids + gen_braids + gen_inv_braids @@ -2445,8 +2448,7 @@ def _mult_by_regular_rep(self, vect, gen_tuple, representation_type, braid_preim (u*v/w, (-u^2)/w, -u, (-v)/w, (-v^2)/w, u/w, u*v/w, 1, v, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) """ - verbose('multiply %s (pre-image %s) by %s using %s' - % (vect, braid_preimage, gen_tuple, representation_type), level=2) + verbose('multiply %s (pre-image %s) by %s using %s' % (vect, braid_preimage, gen_tuple, representation_type), level=2) m = len(gen_tuple) braid_list = None if braid_preimage: @@ -2473,7 +2475,7 @@ def _mult_by_regular_rep(self, vect, gen_tuple, representation_type, braid_preim mat = gen.matrix(representation_type=representation_type) else: # data of inverse of generators is stored under negative strand-index - gen = self.gen(-gen_ind - 1)**(-1) + gen = self.gen(-gen_ind - 1) ** (-1) mat = gen.matrix(representation_type=representation_type) self._gens_reg_repres_matrix[(gen_ind, representation_type)] = mat @@ -2536,8 +2538,7 @@ def _cubic_braid_append_to_basis(self, cubic_braid): monomial = self.monomial(cubic_braid) self._finite_sub_basis_tuples.update({cubic_braid: cbTietze}) - verbose('registering new basis element: %s (par %s ind %s)' - % (cubic_braid, cubic_braid.parent(), next_index), level=2) + verbose('registering new basis element: %s (par %s ind %s)' % (cubic_braid, cubic_braid.parent(), next_index), level=2) self._filecache.update_basis_extensions(self._basis_extension) return monomial @@ -2579,8 +2580,7 @@ def _cubic_braid_basis_tuple(self, cubic_braid): cb_tup = self.cubic_braid_group()(tup) if cubic_braid == cb_tup: self._finite_sub_basis_tuples.update({cb_tup: tup}) - verbose('cubic_braid: %s added to finite_sub_basis with tuple %s' - % (cubic_braid, tup), level=2) + verbose('cubic_braid: %s added to finite_sub_basis with tuple %s' % (cubic_braid, tup), level=2) return tuple(tup) return None @@ -2693,6 +2693,7 @@ def _markov_trace_module(self, extended=False, field_embedding=False): """ from sage.modules.free_module import FreeModule from sage.databases.cubic_hecke_db import MarkovTraceModuleBasis + basis = [b for b in MarkovTraceModuleBasis if b.strands() <= self._nstrands] BRM = self.base_ring(generic=True).markov_trace_version() if extended: @@ -2732,7 +2733,7 @@ def _markov_trace_coeffs(self): sec = db.section.markov_tr_cfs cfs = db.read(sec, variables=M.base_ring().gens(), nstrands=self._nstrands) d = self.dimension() - return [sum(cfs[bas_ele][i]*M(bas_ele) for bas_ele in Mbas) for i in range(d)] + return [sum(cfs[bas_ele][i] * M(bas_ele) for bas_ele in Mbas) for i in range(d)] ############################################################################ # -------------------------------------------------------------------------- @@ -2896,6 +2897,7 @@ def brgrp_orientation_antiinvolution(braid): braid_list = list(braid.Tietze()) braid_list.reverse() return braid_group(tuple(braid_list)) + return self._extend_braid_automorphism(element, brgrp_orientation_antiinvolution) # -------------------------------------------------------------------------- @@ -2997,6 +2999,7 @@ def cubic_equation(self, var='h', as_coefficients=False, generic=False): if as_coefficients: return cf from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + P = PolynomialRing(BaseRing, var) return P(cf) @@ -3244,13 +3247,11 @@ def cubic_hecke_subalgebra(self, nstrands=None): if nstrands == self._nstrands - 1 and self._cubic_hecke_subalgebra is not None: return self._cubic_hecke_subalgebra - names_red = names[:nstrands - 1] + names_red = names[: nstrands - 1] if self.base_ring() == self.base_ring(generic=True): SubHeckeAlg = CubicHeckeAlgebra(names=names_red) else: - SubHeckeAlg = CubicHeckeAlgebra(names=names_red, - cubic_equation_parameters=tuple(self._cubic_equation_parameters), - cubic_equation_roots=tuple(self._cubic_equation_roots)) + SubHeckeAlg = CubicHeckeAlgebra(names=names_red, cubic_equation_parameters=tuple(self._cubic_equation_parameters), cubic_equation_roots=tuple(self._cubic_equation_roots)) if nstrands == self._nstrands - 1: self._cubic_hecke_subalgebra = SubHeckeAlg @@ -3498,10 +3499,12 @@ def characters(self, irr=None, original=True): over Multivariate Polynomial Ring in u, v, w over Integer Ring localized at (w,) """ + def char_function(ele): if isinstance(ele, self.element_class): m = ele.matrix(original=original) return m[irr].trace() + if irr: return char_function irrs = [irr for irr in self.irred_repr if irr.number_gens() == self._nstrands - 1] diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py index 6f9c4cc4c9a..7238bf4beff 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py @@ -11,6 +11,7 @@ - Sebastian Oehms May 2020: initial version """ + # ########################################################################### # Copyright (C) 2020 Sebastian Oehms # @@ -126,6 +127,7 @@ class GaloisGroupAction(Action): sage: s*p 3*x^2 + 5*y*z """ + def _act_(self, perm, pol): r""" Application of the action. @@ -207,6 +209,7 @@ class CubicHeckeExtensionRing(LaurentPolynomialRing_mpair): sage: _.an_element() b^2*c^-1 + e3*a """ + def __init__(self, names, order='degrevlex', ring_of_definition=None, third_unity_root_name='e3', markov_trace_version=False): r""" Initialize ``self``. @@ -249,6 +252,7 @@ def __init__(self, names, order='degrevlex', ring_of_definition=None, third_unit # ---------------------------------------------------------------------- from sage.groups.perm_gps.permgroup_named import SymmetricGroup from operator import mul + self._galois_group = SymmetricGroup(3) galois_group_action = GaloisGroupAction(self._galois_group, self, op=mul) self._unset_coercions_used() @@ -307,6 +311,7 @@ def _element_constructor_(self, x, mon=None): [-b c] """ from sage.interfaces.gap3 import GAP3Element + if isinstance(x, GAP3Element): return self._convert_from_gap3_mvp(x) return super()._element_constructor_(x, mon=mon) @@ -381,9 +386,7 @@ def hom(self, im_gens, codomain=None, check=True, base_map=None): verbose("hom_cycl_gen %s" % hom_cycl_gen, level=2) return super().hom(im_remain, codomain=codomain, check=check, base_map=hom_cycl_gen) if base_map is None: - raise ValueError('number of images must be four (including a ' - 'third root of unity at first position) or a ' - 'base_map (on %s) must be given' % self.base_ring()) + raise ValueError('number of images must be four (including a ' 'third root of unity at first position) or a ' 'base_map (on %s) must be given' % self.base_ring()) return super().hom(im_gens, codomain=codomain, check=check, base_map=base_map) def _an_element_(self): @@ -405,7 +408,7 @@ def _an_element_(self): s = self.one() if rem: s = rem[0] - return b**2/c + a*e3/s + return b**2 / c + a * e3 / s ############################################################################ # local methods @@ -451,6 +454,7 @@ def _convert_from_gap3_mvp(self, mvp_expression): a*b*c^-2 + a^2*b^-1*c^-1 + a^-1*b^2*c^-1 + 2 + a*b^-2*c + a^-2*b*c + a^-1*b^-1*c^2 """ from sage.misc.sage_eval import sage_eval + E3 = self.cyclotomic_generator() a, b, c, *rem = self.gens() na, nb, nc = self.variable_names() @@ -777,10 +781,10 @@ def as_splitting_algebra(self): # check of embedding fails in this case as long as the images of # ``iu`` and ``iv`` need to be invertible (see comment in # :meth:`__init__` of :class:`CubicHeckeRingOfDefinition`). - map_back = S.hom([e3, b, a, a + b + c, a*b+a*c+b*c, a*b*c, s], check=False) + map_back = S.hom([e3, b, a, a + b + c, a * b + a * c + b * c, a * b * c, s], check=False) else: S = self.create_specialization([A, B, C]) - map_back = S.hom([e3, b, a, a + b + c, a*b+a*c+b*c, a*b*c]) + map_back = S.hom([e3, b, a, a + b + c, a * b + a * c + b * c, a * b * c]) self.register_coercion(map_back) self._splitting_algebra = S return self._splitting_algebra @@ -842,6 +846,7 @@ def field_embedding(self, characteristic=0): """ if characteristic == 0: from sage.rings.number_field.number_field import CyclotomicField + C3 = CyclotomicField(3) E3 = C3.gen() else: @@ -849,6 +854,7 @@ def field_embedding(self, characteristic=0): raise ValueError('characteristic must be a prime integer') from sage.rings.finite_rings.finite_field_constructor import GF from sage.misc.functional import cyclotomic_polynomial + G = GF(characteristic) c3 = cyclotomic_polynomial(3).change_ring(G) C3 = c3.splitting_field('a') @@ -959,6 +965,7 @@ class CubicHeckeRingOfDefinition(Localization): - 5*E(105)^62 - 5*E(105)^68 - 8*E(105)^71 - 5*E(105)^74 - 5*E(105)^83 - 5*E(105)^86 - 5*E(105)^89 - 5*E(105)^92 - 5*E(105)^101 - 5*E(105)^104 """ + def __init__(self, names=('u', 'v', 'w', 's'), order='degrevlex', markov_trace_version=False): r""" Initialize ``self``. @@ -1041,7 +1048,7 @@ def _an_element_(self): s = self.one() if rem: s = rem[0] - return u**2/w+v/s + return u**2 / w + v / s ############################################################################ # Local Methods @@ -1353,6 +1360,7 @@ def specialize_homfly(self): if not self._is_markov_trace_version(): raise ValueError('functionality only available for Markov trace version') from sage.knots.link import Link + H = Link([]).homfly_polynomial().parent() L, M = H.gens() HL = H.localization(1 - M) @@ -1404,6 +1412,7 @@ def specialize_kauffman(self): if not self._is_markov_trace_version(): raise ValueError('functionality only available for Markov trace version') from sage.knots.knotinfo import KnotInfo + K = KnotInfo.L2a1_1.kauffman_polynomial().parent() a, z = K.gens() ku = z * a + 1 @@ -1456,6 +1465,7 @@ def specialize_links_gould(self): if not self._is_markov_trace_version(): raise ValueError('functionality only available for Markov trace version') from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + L = LaurentPolynomialRing(ZZ, 't0, t1') t0, t1 = L.gens() lu = t0 + t1 - 1 diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py b/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py index 707e20ebc18..2cc3c8dd561 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py @@ -13,6 +13,7 @@ - Sebastian Oehms May 2020: initial version """ + # ########################################################################### # Copyright (C) 2020 Sebastian Oehms # @@ -49,6 +50,7 @@ class GenSign(Enum): sage: chmr.GenSign.neg """ + pos = 1 neg = -1 @@ -73,6 +75,7 @@ class RepresentationType(Enum): sage: chmr.RepresentationType.RegularLeft.is_regular() True """ + def is_split(self) -> bool: r""" Return ``True`` if this representation type is absolutely split, @@ -191,6 +194,7 @@ class AbsIrreducibeRep(Enum): - [MW2012]_ """ + def alternative_name(self): r""" Return the name of the split irreducible representation for cubic Hecke @@ -571,6 +575,7 @@ def reduce_to_irr_block(self, irr): else: ind = Integer(irr) from copy import copy + mat_list = copy(self.parent().zero().block_diagonal_list()) mat_list[ind] = self[ind] return block_diagonal_matrix(mat_list, subdivide=self.parent()._subdivide, sparse=True) @@ -612,6 +617,7 @@ class CubicHeckeMatrixSpace(MatrixSpace): [ 1 u 0] [ 0 w 0] """ + @staticmethod def __classcall_private__(cls, cubic_hecke_algebra, representation_type=None, subdivide=False, original=False): r""" @@ -638,6 +644,7 @@ def __classcall_private__(cls, cubic_hecke_algebra, representation_type=None, su if representation_type == RepresentationType.SplitIrredChevie: from sage.combinat.root_system.reflection_group_real import is_chevie_available + if not is_chevie_available(): raise ValueError('CHEVIE is not available') @@ -647,16 +654,9 @@ def __classcall_private__(cls, cubic_hecke_algebra, representation_type=None, su dimension = cubic_hecke_algebra._dim_irr_rep base_ring = cubic_hecke_algebra.extension_ring(generic=original) # Bypass the MatrixSpace.__classcall__ - return super(MatrixSpace, cls).__classcall__(cls, base_ring, int(dimension), - cubic_hecke_algebra=cubic_hecke_algebra, - representation_type=representation_type, - subdivide=subdivide) - - def __init__(self, base_ring, - dimension, - cubic_hecke_algebra, - representation_type, - subdivide): + return super(MatrixSpace, cls).__classcall__(cls, base_ring, int(dimension), cubic_hecke_algebra=cubic_hecke_algebra, representation_type=representation_type, subdivide=subdivide) + + def __init__(self, base_ring, dimension, cubic_hecke_algebra, representation_type, subdivide): r""" Initialize ``self``. @@ -796,6 +796,7 @@ def __call__(self, entries=None, coerce=True, copy=None): [ 0 0 -b - a + u] """ from sage.algebras.hecke_algebras.cubic_hecke_algebra import CubicHeckeAlgebra + if entries is None: return super().__call__(entries=entries, coerce=coerce, copy=copy) if not hasattr(entries, 'parent'): @@ -886,15 +887,14 @@ def invert_gen(matr): Return the inverse matrix of generators. """ cfs = ch_algebra.cubic_equation(as_coefficients=True, generic=True) - fac = - 1 / cfs[0] + fac = -1 / cfs[0] cf0, cf1, cf2, cf3 = (original_base_ring(cf * fac) for cf in cfs) matri = cf1 * matr.parent().one() matri += cf2 * matr matri += cf3 * matr**2 d1, d2 = matr.dimensions() - return matrix(original_base_ring, d1, d2, - lambda i, j: original_base_ring(matri[i, j])) + return matrix(original_base_ring, d1, d2, lambda i, j: original_base_ring(matri[i, j])) if n == 2: if representation_type.is_split(): diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 747eb034133..ca123726eab 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -13,6 +13,7 @@ Implemented direct computation of products in the `C^{\prime}` basis using du Cloux's Coxeter3 package """ + # **************************************************************************** # Copyright (C) 2013 Brant Jones # Daniel Bump @@ -423,6 +424,7 @@ class IwahoriHeckeAlgebra(Parent, UniqueRepresentation): problem is that it is not clear how to recognise when the parameters are "generic". """ + @staticmethod def __classcall_private__(cls, W, q1, q2=-1, base_ring=None): r""" @@ -511,15 +513,13 @@ def __init__(self, W, q1, q2, base_ring): if base_ring.is_commutative() and W.is_commutative(): self._category = self._category.Commutative() - Parent.__init__(self, base=base_ring, - category=self._category.WithRealizations()) + Parent.__init__(self, base=base_ring, category=self._category.WithRealizations()) self._is_generic = False # needed for initialisation of _KLHeckeBasis # The following is used by the bar involution = self._bar_on_coefficients try: - self._inverse_base_ring_generators = {g: self.base_ring()(g) ** -1 - for g in self.base_ring().variable_names()} + self._inverse_base_ring_generators = {g: self.base_ring()(g) ** -1 for g in self.base_ring().variable_names()} except TypeError: self._inverse_base_ring_generators = {} @@ -535,8 +535,7 @@ def _repr_(self) -> str: ct = self._coxeter_type._repr_(compact=True) except TypeError: ct = repr(self._coxeter_type) - return "Iwahori-Hecke algebra of type {} in {},{} over {}".format( - ct, self._q1, self._q2, self.base_ring()) + return "Iwahori-Hecke algebra of type {} in {},{} over {}".format(ct, self._q1, self._q2, self.base_ring()) def _latex_(self) -> str: r""" @@ -555,8 +554,8 @@ def _latex_(self) -> str: \mathcal{H}_{q,-1}\left(A_{2}, \Bold{Z}[q^{\pm 1}]\right) """ from sage.misc.latex import latex - return "\\mathcal{{H}}_{{{},{}}}\\left({}, {}\\right)".format(latex(self._q1), - latex(self._q2), latex(self._coxeter_type), latex(self.base_ring())) + + return "\\mathcal{{H}}_{{{},{}}}\\left({}, {}\\right)".format(latex(self._q1), latex(self._q2), latex(self._coxeter_type), latex(self.base_ring())) def _bar_on_coefficients(self, c): r""" @@ -654,6 +653,7 @@ class _BasesCategory(Category_realization_of_parent): r""" The category of bases of a Iwahori-Hecke algebra. """ + def __init__(self, base): r""" Initialize the bases of a Iwahori-Hecke algebra. @@ -703,6 +703,7 @@ class ParentMethods: cases, these are just default implementations that will get specialized in a basis. """ + def _repr_(self) -> str: """ Text representation of this basis of Iwahori-Hecke algebra. @@ -717,8 +718,7 @@ def _repr_(self) -> str: sage: H.Cp() Iwahori-Hecke algebra of type B2 in 1,-1 over Integer Ring in the Cp-basis """ - return "%s in the %s-basis" % (self.realization_of(), - self._basis_name) + return "%s in the %s-basis" % (self.realization_of(), self._basis_name) def __getitem__(self, i): """ @@ -1028,8 +1028,7 @@ def bar(self): T = B.realization_of().T() return B(T(self).bar()) H = B.realization_of() - return sum(H._bar_on_coefficients(c) * B.bar_on_basis(w) - for (w, c) in self) + return sum(H._bar_on_coefficients(c) * B.bar_on_basis(w) for (w, c) in self) def hash_involution(self): r""" @@ -1217,17 +1216,16 @@ def specialize_to(self, new_hecke, num_vars=2): elif num_vars == 1: args = (q1,) else: - return new_basis._from_dict({w: new_hecke._base(c) - for w, c in self}) + return new_basis._from_dict({w: new_hecke._base(c) for w, c in self}) - return new_basis._from_dict({w: new_hecke._base(c(args)) - for w, c in self}) + return new_basis._from_dict({w: new_hecke._base(c(args)) for w, c in self}) class _Basis(CombinatorialFreeModule, BindableClass): r""" Technical methods (i.e., not mathematical) that are inherited by each basis of the algebra. These methods cannot be defined in the category. """ + def __init__(self, algebra, prefix=None): r""" Initialises a basis class for the Iwahori-Hecke algebra ``algebra``. @@ -1247,12 +1245,7 @@ def __init__(self, algebra, prefix=None): else: self._prefix = prefix - CombinatorialFreeModule.__init__(self, - algebra.base_ring(), - algebra._W, - category=algebra._BasesCategory(), - sorting_key=sorting_key, - prefix=self._prefix) + CombinatorialFreeModule.__init__(self, algebra.base_ring(), algebra._W, category=algebra._BasesCategory(), sorting_key=sorting_key, prefix=self._prefix) # This **must** match the name of the class in order for # specialize_to() to work @@ -1290,8 +1283,7 @@ def _latex_term(self, t) -> str: redword = t.reduced_word() if not redword: return '1' - return ''.join("%s_{%d}" % (self._print_options['prefix'], i) - for i in redword) + return ''.join("%s_{%d}" % (self._print_options['prefix'], i) for i in redword) def product_on_basis(self, w1, w2): r""" @@ -1377,7 +1369,8 @@ class T(_Basis): sage: all(T[x].bar() == sum(v^(-2*y.length()) * KL.R(y, x).substitute(v=v^-2) * T[y] for y in W) for x in W) # long time True """ - _basis_name = "T" # this is used, for example, by specialize_to and is the default prefix + + _basis_name = "T" # this is used, for example, by specialize_to and is the default prefix def inverse_generator(self, i): r""" @@ -1415,11 +1408,11 @@ def inverse_generator(self, i): # This currently works better than ~(self._q1) if # self.base_ring() is a Laurent polynomial ring since it # avoids accidental coercion into a field of fractions. - i1 = normalized_laurent_polynomial(A._base, A._q1 ** -1) - i2 = normalized_laurent_polynomial(A._base, A._q2 ** -1) + i1 = normalized_laurent_polynomial(A._base, A._q1**-1) + i2 = normalized_laurent_polynomial(A._base, A._q2**-1) except Exception: raise ValueError("%s and %s must be invertible" % (A._q1, A._q2)) - return (-i1*i2)*self.algebra_generator(i)+(i1+i2) + return (-i1 * i2) * self.algebra_generator(i) + (i1 + i2) @cached_method def inverse_generators(self): @@ -1503,8 +1496,7 @@ def product_by_generator_on_basis(self, w, i, side='right'): A = self.realization_of() if w.has_descent(i, side=side): # 10% faster than a plain addition on the example of #12528 - return self.sum_of_terms(((w, A._q_sum), (wi, A._q_prod)), - distinct=True) + return self.sum_of_terms(((w, A._q_sum), (wi, A._q_prod)), distinct=True) return self.monomial(wi) def product_by_generator(self, x, i, side='right'): @@ -1521,8 +1513,7 @@ def product_by_generator(self, x, i, side='right'): sage: [H.product_by_generator(x, 1, side = "left") for x in [T1,T2]] [(q-1)*T[1] + q, T[1,2]] """ - return self.linear_combination((self.product_by_generator_on_basis(w, i, side), c) - for (w, c) in x) + return self.linear_combination((self.product_by_generator_on_basis(w, i, side), c) for (w, c) in x) def to_C_basis(self, w): r""" @@ -1633,7 +1624,7 @@ def hash_involution_on_basis(self, w): True """ H = self.realization_of() - return (-H._q_prod)**(-w.length())*self.monomial(w) + return (-H._q_prod) ** (-w.length()) * self.monomial(w) def goldman_involution_on_basis(self, w): r""" @@ -1684,7 +1675,7 @@ def goldman_involution_on_basis(self, w): True """ H = self.realization_of() - return (-H._q_prod)**w.length() * self.monomial(w.inverse()).inverse() + return (-H._q_prod) ** w.length() * self.monomial(w.inverse()).inverse() class Element(CombinatorialFreeModule.Element): r""" @@ -1731,6 +1722,7 @@ class Element(CombinatorialFreeModule.Element): sage: T1.parent() Iwahori-Hecke algebra of type A2 in 1,-1 over Integer Ring in the T-basis """ + def __invert__(self): r""" Return the inverse if ``self`` is a basis element. @@ -1777,6 +1769,7 @@ class _KLHeckeBasis(_Basis): Abstract class for the common methods for the Kazhdan-Lusztig `C` and `C^{\prime}` bases. """ + def __init__(self, IHAlgebra, prefix=None): r""" Initialize the Kazhdan-Lusztig basis of the Iwahori-Hecke @@ -1790,8 +1783,7 @@ def __init__(self, IHAlgebra, prefix=None): sage: C = H.C() """ if IHAlgebra._root is None: - raise ValueError('the Kazhdan-Lusztig bases are defined ' - 'only when -q_1*q_2 is a square') + raise ValueError('the Kazhdan-Lusztig bases are defined ' 'only when -q_1*q_2 is a square') if IHAlgebra._is_generic: klbasis = IwahoriHeckeAlgebra_nonstandard._KLHeckeBasis @@ -1801,14 +1793,11 @@ def __init__(self, IHAlgebra, prefix=None): # Define conversion from the KL-basis to the T-basis via # specialization from the generic Hecke algebra - self.module_morphism(self.to_T_basis, codomain=IHAlgebra.T(), category=self.category() - ).register_as_coercion() + self.module_morphism(self.to_T_basis, codomain=IHAlgebra.T(), category=self.category()).register_as_coercion() # ...and from the T_basis to the KL-basis. T = IHAlgebra.T() - T.module_morphism(getattr(T, 'to_{}_basis'.format(self._basis_name)), - codomain=self, category=self.category() - ).register_as_coercion() + T.module_morphism(getattr(T, 'to_{}_basis'.format(self._basis_name)), codomain=self, category=self.category()).register_as_coercion() def bar_on_basis(self, w): r""" @@ -1975,7 +1964,8 @@ class Cp(_KLHeckeBasis): sage: all(Cp(C(Cp[x])) == Cp[x] for x in W) # long time True """ - _basis_name = 'Cp' # this is used, for example, by specialize_to and is the default prefix + + _basis_name = 'Cp' # this is used, for example, by specialize_to and is the default prefix def __init__(self, IHAlgebra, prefix=None): r""" @@ -2004,11 +1994,12 @@ def __init__(self, IHAlgebra, prefix=None): # normalized presentations of the Hecke algebra. v = IHAlgebra.base_ring().gen(0) parameters = {IHAlgebra.q1(), IHAlgebra.q2()} - if v == IHAlgebra.base_ring().one() or (parameters != {v**2, -1} and parameters != {v, -1/v}): + if v == IHAlgebra.base_ring().one() or (parameters != {v**2, -1} and parameters != {v, -1 / v}): return # check if products can be computed directly using ``coxeter3`` from sage.features.coxeter3 import Coxeter3 + if Coxeter3().is_present(): from sage.libs.coxeter3.coxeter_group import CoxeterGroup as Coxeter3Group else: @@ -2039,7 +2030,7 @@ def hash_involution_on_basis(self, w): sage: Cp[s].hash_involution() -Cp[1] + (v^-1+v) """ - return (-1)**w.length() * self(self.realization_of().C().monomial(w)) + return (-1) ** w.length() * self(self.realization_of().C().monomial(w)) def product_on_basis(self, w1, w2): r""" @@ -2161,7 +2152,7 @@ def product_on_basis(self, w1, w2): # Multiplication: multiply the generators in each term of the above # polynomial onto other_element and add that summand onto result. result = self.zero() - for (p, coeff) in gen_expression.items(): + for p, coeff in gen_expression.items(): summand = coeff * other_element if side == 'right': for s in p: @@ -2177,8 +2168,7 @@ def product_on_basis(self, w1, w2): # the original underlying Coxeter group. if self._W_Coxeter3 != self.realization_of()._W: _W = self.realization_of()._W - result = self._from_dict({_W.from_reduced_word(w.reduced_word()): c - for (w, c) in result}, remove_zeros=False) + result = self._from_dict({_W.from_reduced_word(w.reduced_word()): c for (w, c) in result}, remove_zeros=False) return result @@ -2319,9 +2309,9 @@ def _decompose_into_generators(self, u): # recursion: decompose C'_s * C'_w and the lower order terms result = {(s,) + gens: coeff for (gens, coeff) in self._decompose_into_generators(w).items()} zero = R.zero() - for (z, c1) in sum_term.items(): + for z, c1 in sum_term.items(): # Subtract off each term from sum_term. - for (gens, c2) in self._decompose_into_generators(z).items(): + for gens, c2 in self._decompose_into_generators(z).items(): result[gens] = result.get(gens, zero) - c1 * c2 return result @@ -2426,7 +2416,8 @@ class C(_KLHeckeBasis): sage: all(C((-1)**x.length()*Cp[x].hash_involution()) == C[x] for x in W) # long time True """ - _basis_name = "C" # this is used, for example, by specialize_to and is the default prefix + + _basis_name = "C" # this is used, for example, by specialize_to and is the default prefix def hash_involution_on_basis(self, w): r""" @@ -2447,7 +2438,7 @@ def hash_involution_on_basis(self, w): sage: C[s].hash_involution() -C[1] - (v^-1+v) """ - return (-1)**w.length() * self(self.realization_of().Cp().monomial(w)) + return (-1) ** w.length() * self(self.realization_of().Cp().monomial(w)) class A(_Basis): r""" @@ -2490,6 +2481,7 @@ class A(_Basis): ... TypeError: the A-basis is defined only when 2 is invertible """ + _basis_name = "A" def __init__(self, IHAlgebra, prefix=None): @@ -2504,16 +2496,14 @@ def __init__(self, IHAlgebra, prefix=None): """ R = IHAlgebra.base_ring() try: - R(R.one()/2) + R(R.one() / 2) except (TypeError, ZeroDivisionError): raise TypeError('the A-basis is defined only when 2 is invertible') super().__init__(IHAlgebra, prefix) # Define and register coercions from the A basis to the T basis and back again - from_A_to_T = self.module_morphism(self.to_T_basis, codomain=IHAlgebra.T(), - triangular='lower', key=sorting_key, - category=self.category()) + from_A_to_T = self.module_morphism(self.to_T_basis, codomain=IHAlgebra.T(), triangular='lower', key=sorting_key, category=self.category()) from_A_to_T.register_as_coercion() from_T_to_A = ~from_A_to_T from_T_to_A.register_as_coercion() @@ -2536,7 +2526,7 @@ def to_T_basis(self, w): A[1,2] - (1/2-1/2*v^2)*A[1] - (1/2-1/2*v^2)*A[2] """ T = self.realization_of().T() - return (T.monomial(w) + (-1)**w.length()*T.goldman_involution_on_basis(w)) / 2 + return (T.monomial(w) + (-1) ** w.length() * T.goldman_involution_on_basis(w)) / 2 def goldman_involution_on_basis(self, w): r""" @@ -2557,7 +2547,7 @@ def goldman_involution_on_basis(self, w): sage: A[1,2].goldman_involution() A[1,2] """ - return (-1)**w.length() * self.monomial(w) + return (-1) ** w.length() * self.monomial(w) class B(_Basis): r""" @@ -2622,6 +2612,7 @@ class B(_Basis): ... TypeError: the B-basis is defined only when 2 is invertible """ + _basis_name = "B" def __init__(self, IHAlgebra, prefix=None): @@ -2636,16 +2627,14 @@ def __init__(self, IHAlgebra, prefix=None): """ R = IHAlgebra.base_ring() try: - R(R.one()/2) + R(R.one() / 2) except (TypeError, ZeroDivisionError): raise TypeError('the B-basis is defined only when 2 is invertible') super().__init__(IHAlgebra, prefix) # Define and register coercions from the B basis to the T basis and back again - from_B_to_T = self.module_morphism(self.to_T_basis, codomain=IHAlgebra.T(), - triangular='lower', key=sorting_key, - category=self.category()) + from_B_to_T = self.module_morphism(self.to_T_basis, codomain=IHAlgebra.T(), triangular='lower', key=sorting_key, category=self.category()) from_B_to_T.register_as_coercion() from_T_to_B = ~from_B_to_T from_T_to_B.register_as_coercion() @@ -2670,10 +2659,8 @@ def to_T_basis(self, w): """ T = self.realization_of().T() Bw = T(self.realization_of().A()[w]) - odd = [v for v in Bw.support() - if v != w and not (v.length() - w.length()) % 2] - return Bw - T.sum(Bw.coefficient(v) * self.to_T_basis(v) - for v in odd) + odd = [v for v in Bw.support() if v != w and not (v.length() - w.length()) % 2] + return Bw - T.sum(Bw.coefficient(v) * self.to_T_basis(v) for v in odd) def goldman_involution_on_basis(self, w): r""" @@ -2694,7 +2681,7 @@ def goldman_involution_on_basis(self, w): sage: B[1,2].goldman_involution() B[1,2] """ - return (-1)**w.length() * self.monomial(w) + return (-1) ** w.length() * self.monomial(w) # The IwahoriHeckeAlgebra_nonstandard class must have the same basis classes as @@ -2742,6 +2729,7 @@ class IwahoriHeckeAlgebra_nonstandard(IwahoriHeckeAlgebra): and are related to the standard parameters by an outer automorphism that is non-trivial on the `T`-basis. """ + @staticmethod def __classcall_private__(cls, W): r""" @@ -2774,14 +2762,14 @@ def __init__(self, W): # try and attach a generic Hecke algebra to this algebra leading to # an infinite loop. self._q1 = u - self._q2 = normalized_laurent_polynomial(base_ring, -v**2*u**-1) + self._q2 = normalized_laurent_polynomial(base_ring, -(v**2) * u**-1) self._root = v # Used when multiplying generators: minor speed-up as it avoids the # need to constantly add and multiply the parameters when applying the # quadratic relation: T^2 = (q1+q2)T - q1*q2 - self._q_sum = normalized_laurent_polynomial(base_ring, self._q1+self._q2) - self._q_prod = normalized_laurent_polynomial(base_ring, -self._q1*self._q2) + self._q_sum = normalized_laurent_polynomial(base_ring, self._q1 + self._q2) + self._q_prod = normalized_laurent_polynomial(base_ring, -self._q1 * self._q2) self.u_inv = normalized_laurent_polynomial(base_ring, u**-1) self.v_inv = normalized_laurent_polynomial(base_ring, v**-1) @@ -2807,8 +2795,7 @@ def _repr_(self) -> str: ct = self._coxeter_type._repr_(compact=True) except TypeError: ct = repr(self._coxeter_type) - return "A generic Iwahori-Hecke algebra of type {} in {},{} over {}".format( - ct, self._q1, self._q2, self.base_ring()) + return "A generic Iwahori-Hecke algebra of type {} in {},{} over {}".format(ct, self._q1, self._q2, self.base_ring()) def _bar_on_coefficients(self, c): r""" @@ -2835,6 +2822,7 @@ class _BasesCategory(IwahoriHeckeAlgebra._BasesCategory): """ Category of bases for a generic Iwahori-Hecke algebra. """ + def super_categories(self): r""" The super categories of ``self``. @@ -2892,6 +2880,7 @@ def specialize_to(self, new_hecke): def new_coeff(c): return new_hecke._base(normalized_laurent_polynomial(hecke._base, c)(q1, root)) + new_basis = getattr(new_hecke, self.parent()._basis_name)() return new_basis._from_dict({w: new_coeff(c) for w, c in self}) @@ -2899,6 +2888,7 @@ class T(IwahoriHeckeAlgebra.T): r""" The `T`-basis for the generic Iwahori-Hecke algebra. """ + @cached_method def to_Cp_basis(self, w): r""" @@ -2935,8 +2925,8 @@ def to_Cp_basis(self, w): result = Cp.zero() while inp != T0: (x, c) = inp.trailing_item(key=sorting_key) - inp = inp - c * A._root**x.length() * Cp.to_T_basis(x) - result = result + c * A._root**x.length() * Cp.monomial(x) + inp = inp - c * A._root ** x.length() * Cp.to_T_basis(x) + result = result + c * A._root ** x.length() * Cp.monomial(x) return result @@ -2984,15 +2974,15 @@ def to_C_basis(self, w): v^3*C[1,2,1] + u*v^2*C[2,1] + u*v^2*C[1,2] + u^2*v*C[1] + u^2*v*C[2] + u^3 """ H = self.realization_of() - q_w = (-H._q_prod)**w.length() - return self.sum_of_terms((v, (-1)**v.length()*q_w*H._bar_on_coefficients(c)) - for (v, c) in self.to_Cp_basis(w)) + q_w = (-H._q_prod) ** w.length() + return self.sum_of_terms((v, (-1) ** v.length() * q_w * H._bar_on_coefficients(c)) for (v, c) in self.to_Cp_basis(w)) class Cp(IwahoriHeckeAlgebra.Cp): r""" The Kazhdan-Lusztig `C^{\prime}`-basis for the generic Iwahori-Hecke algebra. """ + @cached_method def to_T_basis(self, w): r""" @@ -3041,7 +3031,7 @@ def key_func(x): while i < len(cpw_s): (x, c) = sorted(cpw_s.terms(), key=key_func)[i].leading_item() - mu = normalized_laurent_polynomial(A._base, c)[0, -x.length()] # the coefficient of v^-len(x) + mu = normalized_laurent_polynomial(A._base, c)[0, -x.length()] # the coefficient of v^-len(x) if mu != 0: cpw_s -= mu * self.to_T_basis(x) else: @@ -3055,6 +3045,7 @@ class C(IwahoriHeckeAlgebra.C): r""" The Kazhdan-Lusztig `C`-basis for the generic Iwahori-Hecke algebra. """ + @cached_method def to_T_basis(self, w): r""" @@ -3087,9 +3078,9 @@ def to_T_basis(self, w): # then apply the Hecke involution to the result. This gives the # desired result because C_w = (-1)^{len(w)) \tau( C_w' ), where # \tau is the Hecke involution. - return (-1)**w.length()*self.realization_of().Cp().to_T_basis(w).hash_involution() + return (-1) ** w.length() * self.realization_of().Cp().to_T_basis(w).hash_involution() from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.algebras.iwahori_hecke_algebra', - 'IwahoriHeckeAlgebraT', IwahoriHeckeAlgebra) + +register_unpickle_override('sage.algebras.iwahori_hecke_algebra', 'IwahoriHeckeAlgebraT', IwahoriHeckeAlgebra) diff --git a/src/sage/algebras/jordan_algebra.py b/src/sage/algebras/jordan_algebra.py index 21bc5529b86..ad4aafe62cd 100644 --- a/src/sage/algebras/jordan_algebra.py +++ b/src/sage/algebras/jordan_algebra.py @@ -162,6 +162,7 @@ class JordanAlgebra(UniqueRepresentation, Parent): - [McC1978]_ - [Al1947]_ """ + @staticmethod def __classcall_private__(self, arg0, arg1=None, names=None): """ @@ -209,6 +210,7 @@ def __classcall_private__(self, arg0, arg1=None, names=None): if arg1 is None: if not isinstance(arg0, Matrix): from sage.algebras.octonion_algebra import OctonionAlgebra + if isinstance(arg0, OctonionAlgebra): return ExceptionalJordanAlgebra(arg0) if arg0.base_ring().characteristic() == 2: @@ -244,6 +246,7 @@ def _test_jordan_relations(self, **options): tester = self._tester(**options) S = tester.some_elements() from sage.misc.misc import some_tuples + for x, y in some_tuples(S, 2, tester._max_runs): tester.assertEqual(x * y, y * x) tester.assertEqual((x * y) * (x * x), x * (y * (x * x))) @@ -253,6 +256,7 @@ class SpecialJordanAlgebra(JordanAlgebra): r""" A (special) Jordan algebra `A^+` from an associative algebra `A`. """ + def __init__(self, A, names=None) -> None: """ Initialize ``self``. @@ -338,8 +342,7 @@ def basis(self) -> Family: Lazy family (Term map(i))_{i in Free monoid on 3 generators (x, y, z)} """ B = self._A.basis() - return Family(B.keys(), lambda x: self.element_class(self, B[x]), - name="Term map") + return Family(B.keys(), lambda x: self.element_class(self, B[x]), name="Term map") algebra_generators = basis @@ -403,6 +406,7 @@ class Element(AlgebraElement): """ An element of a special Jordan algebra. """ + def __init__(self, parent, x) -> None: """ Initialize ``self``. @@ -449,7 +453,7 @@ def __hash__(self) -> int: sage: hash(J.one()) in ZZ True """ - return hash( (self.parent(), self._x) ) + return hash((self.parent(), self._x)) def _repr_(self) -> str: """ @@ -478,6 +482,7 @@ def _latex_(self) -> str: x_{0} + 2 x_{1} - x_{2} """ from sage.misc.latex import latex + return latex(self._x) def __bool__(self) -> bool: @@ -600,7 +605,7 @@ def _mul_(self, other): y = other._x # This is safer than dividing by 2 R = self.parent().base_ring() - return self.__class__(self.parent(), (x*y + y*x) * ~R(2)) + return self.__class__(self.parent(), (x * y + y * x) * ~R(2)) def _lmul_(self, other): """ @@ -667,6 +672,7 @@ class JordanAlgebraSymmetricBilinear(JordanAlgebra): sage: J.gens() (1 + (0, 0), 0 + (1, 0), 0 + (0, 1)) """ + def __init__(self, R, form, names=None) -> None: """ Initialize ``self``. @@ -694,8 +700,7 @@ def _repr_(self) -> str: [-2 3] [ 3 4] """ - return "Jordan algebra over {} given by the symmetric bilinear" \ - " form:\n{}".format(self.base_ring(), self._form) + return "Jordan algebra over {} given by the symmetric bilinear" " form:\n{}".format(self.base_ring(), self._form) def _element_constructor_(self, *args): """ @@ -770,8 +775,7 @@ def _element_constructor_(self, *args): return self.element_class(self, R(s), self._M.zero()) - if len(args) == 2 and (isinstance(args[1], (list, tuple)) - or args[1] in self._M): + if len(args) == 2 and (isinstance(args[1], (list, tuple)) or args[1] in self._M): return self.element_class(self, R(args[0]), self._M(args[1])) if len(args) == self._form.ncols() + 1: @@ -821,8 +825,7 @@ def basis(self) -> Family: """ R = self.base_ring() ret = (self.element_class(self, R.one(), self._M.zero()),) - ret += tuple(self.element_class(self, R.zero(), x) - for x in self._M.basis()) + ret += tuple(self.element_class(self, R.zero(), x) for x in self._M.basis()) return Family(ret) algebra_generators = basis @@ -859,6 +862,7 @@ class Element(AlgebraElement): """ An element of a Jordan algebra defined by a symmetric bilinear form. """ + def __init__(self, parent, s, v) -> None: """ Initialize ``self``. @@ -882,7 +886,7 @@ def __hash__(self): sage: hash(J.one()) in ZZ True """ - return hash( (self.parent(), self._s, self._v) ) + return hash((self.parent(), self._s, self._v)) def _repr_(self) -> str: """ @@ -909,6 +913,7 @@ def _latex_(self) -> str: 1 + \left(2,\,-1\right) """ from sage.misc.latex import latex + return "{} + {}".format(latex(self._s), latex(self._v)) def __bool__(self) -> bool: @@ -1034,10 +1039,7 @@ def _mul_(self, other): 21 + (6, 2) """ P = self.parent() - return self.__class__(P, - self._s * other._s - + (self._v * P._form * other._v.column())[0], - other._s * self._v + self._s * other._v) + return self.__class__(P, self._s * other._s + (self._v * P._form * other._v.column())[0], other._s * self._v + self._s * other._v) def _lmul_(self, other): """ @@ -1086,7 +1088,7 @@ def monomial_coefficients(self, copy=True) -> dict: """ d = {0: self._s} for i, c in enumerate(self._v): - d[i+1] = c + d[i + 1] = c return d def trace(self): @@ -1122,8 +1124,7 @@ def norm(self): sage: x.norm() 13 """ - return self._s * self._s - (self._v * self.parent()._form - * self._v.column())[0] + return self._s * self._s - (self._v * self.parent()._form * self._v.column())[0] def bar(self): r""" @@ -1212,6 +1213,7 @@ class ExceptionalJordanAlgebra(JordanAlgebra): - :wikipedia:`Hurwitz's_theorem_(composition_algebras)#Applications_to_Jordan_algebras` - ``_ """ + def __init__(self, Octo) -> None: r""" Initialize ``self``. @@ -1263,6 +1265,7 @@ def __init__(self, Octo) -> None: self._half = R(2).inverse_of_unit() from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + Onames = list(Octo.variable_names()) Onames.extend(Onames[3] + Onames[i] for i in range(3)) self._repr_poly_ring = PolynomialRing(R, Onames) @@ -1313,7 +1316,7 @@ def _element_constructor_(self, x): R = self.base_ring() for i in range(3): x[i] = R(x[i]) - x[3+i] = self._O(x[3+i]) + x[3 + i] = self._O(x[3 + i]) return self.element_class(self, x) def _test_multiplication_self_adjoint(self, **options): @@ -1331,15 +1334,12 @@ def _test_multiplication_self_adjoint(self, **options): data_pairs = [(0, 0), (1, 1), (2, 2), (0, 1), (0, 2), (1, 2)] zerO = self._O.zero() from sage.misc.misc import some_tuples + for x, y in some_tuples(S, 2, tester._max_runs): SD = x._data OD = y._data - X = [[SD[0], SD[3], SD[4]], - [SD[3].conjugate(), SD[1], SD[5]], - [SD[4].conjugate(), SD[5].conjugate(), SD[2]]] - Y = [[OD[0], OD[3], OD[4]], - [OD[3].conjugate(), OD[1], OD[5]], - [OD[4].conjugate(), OD[5].conjugate(), OD[2]]] + X = [[SD[0], SD[3], SD[4]], [SD[3].conjugate(), SD[1], SD[5]], [SD[4].conjugate(), SD[5].conjugate(), SD[2]]] + Y = [[OD[0], OD[3], OD[4]], [OD[3].conjugate(), OD[1], OD[5]], [OD[4].conjugate(), OD[5].conjugate(), OD[2]]] for r, c in data_pairs: if r != c: val = sum(X[r][i] * Y[i][c] + Y[r][i] * X[i][c] for i in range(3)) * self._half @@ -1389,7 +1389,7 @@ def basis(self) -> Family: for i in range(3): for b in OB: temp = list(base) - temp[3+i] = b + temp[3 + i] = b ret.append(self.element_class(self, temp)) return Family(ret) @@ -1508,18 +1508,16 @@ def some_elements(self) -> list: [ k -j 0]] """ B = self.basis() - S = [self.an_element(), self.one(), self.zero(), - B[1], B[5], B[17], B[1] + self._half*B[25], - self.one() + B[13] + 2*B[16]] + S = [self.an_element(), self.one(), self.zero(), B[1], B[5], B[17], B[1] + self._half * B[25], self.one() + B[13] + 2 * B[16]] S.append(sum(B[::5])) - S.append(sum(self._half * ind * b - for ind, b in enumerate(B[::7], start=2))) + S.append(sum(self._half * ind * b for ind, b in enumerate(B[::7], start=2))) return S class Element(AlgebraElement): r""" An element of an exceptional Jordan algebra. """ + def __init__(self, parent, data) -> None: """ Initialize ``self``. @@ -1543,7 +1541,7 @@ def __hash__(self): sage: hash(J.one()) in ZZ True """ - return hash( (self.parent(), self._data) ) + return hash((self.parent(), self._data)) def _to_print_matrix(self): r""" @@ -1562,18 +1560,12 @@ def _to_print_matrix(self): PR = self.parent()._repr_poly_ring gens = [PR.one()] + list(PR.gens()) data = [PR(self._data[i]) for i in range(3)] - data.extend(PR.sum(c * g - for c, g in zip(self._data[3+i].vector(), gens)) - for i in range(3)) + data.extend(PR.sum(c * g for c, g in zip(self._data[3 + i].vector(), gens)) for i in range(3)) # add the conjugates for i in range(1, 8): gens[i] = -gens[i] - data.extend(PR.sum(c * g - for c, g in zip(self._data[3+i].vector(), gens)) - for i in range(3)) - return matrix(PR, [[data[0], data[3], data[4]], - [data[6], data[1], data[5]], - [data[7], data[8], data[2]]]) + data.extend(PR.sum(c * g for c, g in zip(self._data[3 + i].vector(), gens)) for i in range(3)) + return matrix(PR, [[data[0], data[3], data[4]], [data[6], data[1], data[5]], [data[7], data[8], data[2]]]) def _repr_(self) -> str: r""" @@ -1606,6 +1598,7 @@ def _latex_(self) -> str: \end{array}\right) """ from sage.misc.latex import latex + return latex(self._to_print_matrix()) def _ascii_art_(self): @@ -1622,6 +1615,7 @@ def _ascii_art_(self): [ 0 0 6/5] """ from sage.typeset.ascii_art import ascii_art + return ascii_art(self._to_print_matrix()) def _unicode_art_(self): @@ -1638,6 +1632,7 @@ def _unicode_art_(self): ⎝ 0 0 6/5⎠ """ from sage.typeset.unicode_art import unicode_art + return unicode_art(self._to_print_matrix()) def __bool__(self) -> bool: @@ -1752,19 +1747,12 @@ def _mul_(self, other): P = self.parent() SD = self._data OD = other._data - X = [[SD[0], SD[3], SD[4]], - [SD[3].conjugate(), SD[1], SD[5]], - [SD[4].conjugate(), SD[5].conjugate(), SD[2]]] - Y = [[OD[0], OD[3], OD[4]], - [OD[3].conjugate(), OD[1], OD[5]], - [OD[4].conjugate(), OD[5].conjugate(), OD[2]]] + X = [[SD[0], SD[3], SD[4]], [SD[3].conjugate(), SD[1], SD[5]], [SD[4].conjugate(), SD[5].conjugate(), SD[2]]] + Y = [[OD[0], OD[3], OD[4]], [OD[3].conjugate(), OD[1], OD[5]], [OD[4].conjugate(), OD[5].conjugate(), OD[2]]] # we do a simplified multiplication for the diagonal entries since # we have, e.g., \alpha * \alpha' + (x (x')^* + x' x^* + y (y')^* + y' y^*) / 2 - ret = [X[0][0] * Y[0][0] + (X[0][1] * Y[1][0]).real_part() + (X[0][2] * Y[2][0]).real_part(), - X[1][1] * Y[1][1] + (X[1][0] * Y[0][1]).real_part() + (X[1][2] * Y[2][1]).real_part(), - X[2][2] * Y[2][2] + (X[2][0] * Y[0][2]).real_part() + (X[2][1] * Y[1][2]).real_part()] - ret += [sum(X[r][i] * Y[i][c] + Y[r][i] * X[i][c] for i in range(3)) * P._half - for r, c in [(0, 1), (0, 2), (1, 2)]] + ret = [X[0][0] * Y[0][0] + (X[0][1] * Y[1][0]).real_part() + (X[0][2] * Y[2][0]).real_part(), X[1][1] * Y[1][1] + (X[1][0] * Y[0][1]).real_part() + (X[1][2] * Y[2][1]).real_part(), X[2][2] * Y[2][2] + (X[2][0] * Y[0][2]).real_part() + (X[2][1] * Y[1][2]).real_part()] + ret += [sum(X[r][i] * Y[i][c] + Y[r][i] * X[i][c] for i in range(3)) * P._half for r, c in [(0, 1), (0, 2), (1, 2)]] return self.__class__(P, ret) def _lmul_(self, other): @@ -1838,7 +1826,7 @@ def monomial_coefficients(self, copy=True) -> dict: for i in range(3): if self._data[i]: ret[i] = self._data[i] - mc = self._data[3+i].monomial_coefficients() + mc = self._data[3 + i].monomial_coefficients() for k, coeff in mc.items(): - ret[3+i*8+k] = coeff + ret[3 + i * 8 + k] = coeff return ret diff --git a/src/sage/algebras/lie_algebras/abelian.py b/src/sage/algebras/lie_algebras/abelian.py index dbacc53167b..216066673eb 100644 --- a/src/sage/algebras/lie_algebras/abelian.py +++ b/src/sage/algebras/lie_algebras/abelian.py @@ -6,7 +6,7 @@ - Travis Scrimshaw (2016-06-07): Initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2013-2017 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -14,10 +14,9 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** -from sage.structure.indexed_generators import (IndexedGenerators, - standardize_names_index_set) +from sage.structure.indexed_generators import IndexedGenerators, standardize_names_index_set from sage.categories.lie_algebras import LieAlgebras from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement from sage.algebras.lie_algebras.lie_algebra import InfinitelyGeneratedLieAlgebra @@ -40,6 +39,7 @@ class AbelianLieAlgebra(LieAlgebraWithStructureCoefficients): sage: L.bracket(x, y) 0 """ + @staticmethod def __classcall_private__(cls, R, names=None, index_set=None, category=None, **kwds): """ @@ -68,8 +68,7 @@ def __init__(self, R, names, index_set, category, **kwds): """ cat = LieAlgebras(R).FiniteDimensional().WithBasis().Nilpotent() category = cat.or_subcategory(category) - LieAlgebraWithStructureCoefficients.__init__(self, R, Family({}), names, - index_set, category, **kwds) + LieAlgebraWithStructureCoefficients.__init__(self, R, Family({}), names, index_set, category, **kwds) def _repr_(self): """ @@ -83,8 +82,7 @@ def _repr_(self): gens = self.lie_algebra_generators() if gens.cardinality() == 1: return "Abelian Lie algebra on generator {} over {}".format(tuple(gens)[0], self.base_ring()) - return "Abelian Lie algebra on {} generators {} over {}".format( - gens.cardinality(), tuple(gens), self.base_ring()) + return "Abelian Lie algebra on {} generators {} over {}".format(gens.cardinality(), tuple(gens), self.base_ring()) def _construct_UEA(self): """ @@ -134,6 +132,7 @@ class InfiniteDimensionalAbelianLieAlgebra(InfinitelyGeneratedLieAlgebra, Indexe A Lie algebra `\mathfrak{g}` is abelian if `[x, y] = 0` for all `x, y \in \mathfrak{g}`. """ + def __init__(self, R, index_set, prefix='L', **kwds): """ Initialize ``self``. diff --git a/src/sage/algebras/lie_algebras/affine_lie_algebra.py b/src/sage/algebras/lie_algebras/affine_lie_algebra.py index 2d0c397aec1..14af8a70beb 100644 --- a/src/sage/algebras/lie_algebras/affine_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/affine_lie_algebra.py @@ -6,7 +6,7 @@ - Travis Scrimshaw (2013-05-03): Initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2013-2017 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute @@ -63,6 +63,7 @@ class AffineLieAlgebra(FinitelyGeneratedLieAlgebra): - [Ka1990]_ """ + @staticmethod def __classcall_private__(cls, arg0, cartan_type=None, kac_moody=True): """ @@ -166,6 +167,7 @@ def basis(self): else: K = TwistedAffineIndices(self._cartan_type) from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + c = FiniteEnumeratedSet(['c']) if self._kac_moody: d = FiniteEnumeratedSet(['d']) @@ -191,8 +193,7 @@ def _element_constructor_(self, x): """ P = parent(x) if P is self.derived_subalgebra(): - return self.element_class(self, x.t_dict(), x.c_coefficient(), - x.d_coefficient()) + return self.element_class(self, x.t_dict(), x.c_coefficient(), x.d_coefficient()) if P == self._g: zero = self.base_ring().zero() return self.element_class(self, {0: x}, zero, zero) @@ -383,32 +384,26 @@ def lie_algebra_generators(self): if self._cartan_type.is_untwisted_affine(): # e_0 = f_{\theta} t - d['e0'] = self.element_class(self, {1: self._g.highest_root_basis_elt(False)}, - zero, zero) + d['e0'] = self.element_class(self, {1: self._g.highest_root_basis_elt(False)}, zero, zero) # f_0 = e_{\theta} t^-1 - d['f0'] = self.element_class(self, {-1: self._g.highest_root_basis_elt(True)}, - zero, zero) + d['f0'] = self.element_class(self, {-1: self._g.highest_root_basis_elt(True)}, zero, zero) elif self._cartan_type.type() != 'BC': a = self._cartan_type.a() Q = self._g._Q theta = Q._from_dict({i: a[i] for i in Q.index_set()}, remove_zeros=False) # e_0 = f_{\theta} t - d['e0'] = self.element_class(self, {1: self._g.basis()[-theta]}, - zero, zero) + d['e0'] = self.element_class(self, {1: self._g.basis()[-theta]}, zero, zero) # f_0 = e_{\theta} t^-1 - d['f0'] = self.element_class(self, {-1: self._g.basis()[theta]}, - zero, zero) + d['f0'] = self.element_class(self, {-1: self._g.basis()[theta]}, zero, zero) else: n = self._g.cartan_type().rank() a = self._cartan_type.a() Q = self._g._Q theta = Q._from_dict({i: ZZ(2) for i in Q.index_set()}, remove_zeros=False) # e_0 = f_{\theta} t - d[f'e{n}'] = self.element_class(self, {1: self._g1.basis()[-theta]}, - zero, zero) + d[f'e{n}'] = self.element_class(self, {1: self._g1.basis()[-theta]}, zero, zero) # f_0 = e_{\theta} t^-1 - d[f'f{n}'] = self.element_class(self, {-1: self._g1.basis()[theta]}, - zero, zero) + d[f'f{n}'] = self.element_class(self, {-1: self._g1.basis()[theta]}, zero, zero) return Family(self.variable_names(), d.__getitem__) @@ -578,6 +573,7 @@ class UntwistedAffineLieAlgebra(AffineLieAlgebra): sage: D.d() 0 """ + def __init__(self, g, kac_moody) -> None: """ Initialize ``self``. @@ -608,7 +604,7 @@ def _repr_(self): if self._kac_moody: old_len = len(rep) rep = rep.replace("Lie", "Kac-Moody") - if len(rep) == old_len: # We did not replace anything + if len(rep) == old_len: # We did not replace anything base += "Kac-Moody " return base + rep @@ -671,6 +667,7 @@ class TwistedAffineLieAlgebra(AffineLieAlgebra): weights in this representation with the roots of type `B_n` and the double all of its short roots. """ + def __init__(self, R, cartan_type, kac_moody) -> None: """ Initialize ``self``. @@ -702,25 +699,25 @@ def __init__(self, R, cartan_type, kac_moody) -> None: if cartan_type.type() == 'BC': classical = cartan_type.classical().dual() n = classical.rank() - classical = classical.relabel({n-i: i for i in range(n)}) + classical = classical.relabel({n - i: i for i in range(n)}) else: classical = cartan_type.classical() g = LieAlgebra(R, cartan_type=classical) n = classical.rank() - names = ['e%s' % i for i in range(1, n+1)] - names.extend('f%s' % i for i in range(1, n+1)) + names = ['e%s' % i for i in range(1, n + 1)] + names.extend('f%s' % i for i in range(1, n + 1)) if cartan_type.type() == 'BC': names.extend('h%s' % i for i in range(n)) else: - names.extend('h%s' % i for i in range(1, n+1)) + names.extend('h%s' % i for i in range(1, n + 1)) names += ['e0', 'f0', 'c'] super().__init__(g, cartan_type, names, kac_moody) # setup the ambient simply-laced algebra basic_ct = cartan_type.basic_untwisted() if cartan_type.dual().type() == 'B': - ep = [(i, i+1) for i in range(1, n)] - ep.extend((i+1, i) for i in range(n, 2*n-1)) + ep = [(i, i + 1) for i in range(1, n)] + ep.extend((i + 1, i) for i in range(n, 2 * n - 1)) elif cartan_type.dual().type() == 'F': ep = [(1, 3), (3, 4), (5, 4), (6, 5), (4, 2)] elif cartan_type.dual().type() == 'G': @@ -730,8 +727,9 @@ def __init__(self, R, cartan_type, kac_moody) -> None: if self._cartan_type.dual().type() == 'G': from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + RP = PolynomialRing(R, 'x') - Rext = RP.quotient(RP.gen(0)**3 - 1) + Rext = RP.quotient(RP.gen(0) ** 3 - 1) self._basic = LieAlgebra(Rext, cartan_type=basic_ct, epsilon=ep) else: self._basic = LieAlgebra(R, cartan_type=basic_ct, epsilon=ep) @@ -771,19 +769,18 @@ def __init__(self, R, cartan_type, kac_moody) -> None: reindex = {2: 4, 4: 3, 3: 2, 1: 1} def build_root(O): - return Q._from_dict({reindex[i]: c * (ord // a[reindex[i]]) / len(O) for i, c in sum(O) if i in reindex}, - remove_zeros=False) + return Q._from_dict({reindex[i]: c * (ord // a[reindex[i]]) / len(O) for i, c in sum(O) if i in reindex}, remove_zeros=False) + elif self._cartan_type.type() == 'BC': - reindex = {n-i: i for i in range(finite_ct.rank())} + reindex = {n - i: i for i in range(finite_ct.rank())} def build_root(O): - return Q._from_dict({reindex[i]: c * (ord // len(O)) for i, c in sum(O) if i in reindex}, - remove_zeros=False) + return Q._from_dict({reindex[i]: c * (ord // len(O)) for i, c in sum(O) if i in reindex}, remove_zeros=False) + else: def build_root(O): - return Q._from_dict({i: c * (ord // a[i]) / len(O) for i, c in sum(O) if i in I}, - remove_zeros=False) + return Q._from_dict({i: c * (ord // a[i]) / len(O) for i, c in sum(O) if i in I}, remove_zeros=False) self._root_mapping = {build_root(O): O for O in orbits} for r in list(self._root_mapping.keys()): @@ -796,6 +793,7 @@ def build_root(O): else: assert {r / 2 for r in self._root_mapping if len(self._root_mapping[r]) == 1} == set(Q.short_roots()) from sage.combinat.free_module import CombinatorialFreeModule + X = sorted(self._root_mapping, key=str) self._g1 = CombinatorialFreeModule(R, X, prefix='E') else: @@ -839,10 +837,11 @@ def _test_classical_subalgebra(self, **options): B = self.basis() roots = set(self._g._Q.roots()) from sage.misc.misc import some_tuples + for r, s in some_tuples(roots, 2, tester._max_runs): ret = B[r, 0].bracket(B[s, 0]) if r + s in roots: - tester.assertEqual(list(ret.support()), [(r+s, 0)], f"obtained [{r}, {s}] == {ret}") + tester.assertEqual(list(ret.support()), [(r + s, 0)], f"obtained [{r}, {s}] == {ret}") elif r == -s: supp = {(ac, 0) for ac in r.associated_coroot().monomials()} tester.assertEqual(set(ret.support()), supp, f"obtained [{r}, {s}] == {ret}") @@ -919,24 +918,16 @@ def retract(self, x): if self._cartan_type.dual().type() == 'G': R = self.base_ring() for i in t_dict: - t_dict[i] = self._g._from_dict({self._inverse_root_map[r]: R(c.lift()) - for r, c in t_dict[i] if r in self._inverse_root_map}, - remove_zeros=False) + t_dict[i] = self._g._from_dict({self._inverse_root_map[r]: R(c.lift()) for r, c in t_dict[i] if r in self._inverse_root_map}, remove_zeros=False) elif self._cartan_type.type() == 'BC': for i in t_dict: if i % 2: - t_dict[i] = self._g1._from_dict({self._inverse_root_map[r]: c for r, c in t_dict[i] - if r in self._inverse_root_map}, - remove_zeros=False) + t_dict[i] = self._g1._from_dict({self._inverse_root_map[r]: c for r, c in t_dict[i] if r in self._inverse_root_map}, remove_zeros=False) else: - t_dict[i] = self._g._from_dict({self._inverse_root_map[r]: c for r, c in t_dict[i] - if r in self._inverse_root_map}, - remove_zeros=False) + t_dict[i] = self._g._from_dict({self._inverse_root_map[r]: c for r, c in t_dict[i] if r in self._inverse_root_map}, remove_zeros=False) else: for i in t_dict: - t_dict[i] = self._g._from_dict({self._inverse_root_map[r]: c for r, c in t_dict[i] - if r in self._inverse_root_map}, - remove_zeros=False) + t_dict[i] = self._g._from_dict({self._inverse_root_map[r]: c for r, c in t_dict[i] if r in self._inverse_root_map}, remove_zeros=False) return self.element_class(self, t_dict, c_coeff, d_coeff) @lazy_attribute @@ -960,8 +951,8 @@ def to_ambient(self): def basis_map(r): O = self._root_mapping[r] - return self._basic._from_dict({O[0]: one, O[1]: mone**(1+O[1].height())}, - remove_zeros=False) + return self._basic._from_dict({O[0]: one, O[1]: mone ** (1 + O[1].height())}, remove_zeros=False) + else: def basis_map(r): @@ -971,22 +962,21 @@ def basis_map(r): zeta3 = self._basic.base_ring().gen() def basis_alt(r): - return self._basic._from_dict({s: zeta3**ind for ind, s in enumerate(self._root_mapping[r])}, - remove_zeros=False) + return self._basic._from_dict({s: zeta3**ind for ind, s in enumerate(self._root_mapping[r])}, remove_zeros=False) + elif self._cartan_type.type() == 'BC': def basis_alt(r): O = self._root_mapping[r] if len(O) == 1: return self._basic.monomial(O[0]) - return self._basic._from_dict({O[0]: one, O[1]: mone**O[1].height()}, - remove_zeros=False) + return self._basic._from_dict({O[0]: one, O[1]: mone ** O[1].height()}, remove_zeros=False) + else: mone = -one def basis_alt(r): - return self._basic._from_dict({s: mone**ind for ind, s in enumerate(self._root_mapping[r])}, - remove_zeros=False) + return self._basic._from_dict({s: mone**ind for ind, s in enumerate(self._root_mapping[r])}, remove_zeros=False) def lift_map(elt): t_dict = elt.t_dict() @@ -994,11 +984,9 @@ def lift_map(elt): d_coeff = elt.d_coefficient() for i in t_dict: if i % 2: - t_dict[i] = self._basic.linear_combination((basis_alt(r), c) - for r, c in t_dict[i]) + t_dict[i] = self._basic.linear_combination((basis_alt(r), c) for r, c in t_dict[i]) else: - t_dict[i] = self._basic.linear_combination((basis_map(r), c) - for r, c in t_dict[i]) + t_dict[i] = self._basic.linear_combination((basis_map(r), c) for r, c in t_dict[i]) return self._ambient.element_class(self._ambient, t_dict, c_coeff, d_coeff) return self.module_morphism(function=lift_map, codomain=self._ambient) @@ -1087,6 +1075,7 @@ class TwistedAffineIndices(UniqueRepresentation, Set_generic): (-alpha[0], 1), (2*alpha[0], 1), (-2*alpha[0], 1), (alphacheck[0], 1), (alpha[0], -1), (-alpha[0], -1)] """ + @staticmethod def __classcall_private__(cls, cartan_type): """ @@ -1121,13 +1110,13 @@ def __init__(self, cartan_type) -> None: if cartan_type.type() == 'BC': finite_ct = cartan_type.classical().dual() n = finite_ct.rank() - Q = finite_ct.relabel({n-i: i for i in range(n)}).root_system().root_lattice() + Q = finite_ct.relabel({n - i: i for i in range(n)}).root_system().root_lattice() self._roots = tuple(Q.roots()) self._ac = tuple(Q.simple_coroots()) if cartan_type.rank() == 2: - self._short_roots = self._roots + tuple(2*r for r in Q.roots()) + self._short_roots = self._roots + tuple(2 * r for r in Q.roots()) else: - self._short_roots = self._roots + tuple(2*r for r in Q.short_roots()) + self._short_roots = self._roots + tuple(2 * r for r in Q.short_roots()) self._short_roots += self._ac facade = cartesian_product([self._short_roots, ZZ]) else: @@ -1139,6 +1128,7 @@ def __init__(self, cartan_type) -> None: self._short_roots += tuple([ac[i] for i in Q.index_set() if Q.simple_root(i).is_short_root()]) facade = cartesian_product([self._roots + self._ac, ZZ]) from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets + super().__init__(facade=facade, category=InfiniteEnumeratedSets()) def __contains__(self, x) -> bool: @@ -1195,7 +1185,7 @@ def __iter__(self): if self._cartan_type.type() == 'BC': finite_ct = self._cartan_type.classical().dual() n = finite_ct.rank() - finite_ct = finite_ct.relabel({n-i: i for i in range(n)}) + finite_ct = finite_ct.relabel({n - i: i for i in range(n)}) else: finite_ct = self._cartan_type.classical() P = self._facade_for[0] diff --git a/src/sage/algebras/lie_algebras/bch.py b/src/sage/algebras/lie_algebras/bch.py index 88ccebd69e2..cb4f4a766b5 100644 --- a/src/sage/algebras/lie_algebras/bch.py +++ b/src/sage/algebras/lie_algebras/bch.py @@ -177,8 +177,7 @@ def bch_iterator(X=None, Y=None): R = L.base_ring() if not R.has_coerce_map_from(QQ): - raise TypeError("the BCH formula is not well defined since %s " - "has no coercion from %s" % (R, QQ)) + raise TypeError("the BCH formula is not well defined since %s " "has no coercion from %s" % (R, QQ)) xdif = X - Y Z = [0, X + Y] # 1-based indexing for convenience @@ -201,7 +200,7 @@ def bch_iterator(X=None, Y=None): if p <= len(norm_ber): norm_ber.append(bernoulli(2 * p) / QQ(factorial(2 * p))) coeff = norm_ber[p] / QQ(m) - partitions = IntegerListsLex(m-1, length=2*p, min_part=1) + partitions = IntegerListsLex(m - 1, length=2 * p, min_part=1) temp = L.zero() for kvec in partitions: W = Z[1] diff --git a/src/sage/algebras/lie_algebras/bgg_dual_module.py b/src/sage/algebras/lie_algebras/bgg_dual_module.py index a3c7e4a3ce9..dc2a1c21bbf 100644 --- a/src/sage/algebras/lie_algebras/bgg_dual_module.py +++ b/src/sage/algebras/lie_algebras/bgg_dual_module.py @@ -6,7 +6,7 @@ - Travis Scrimshaw (2024-01-07): Initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2024 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from typing import Self @@ -100,6 +100,7 @@ class BGGDualModule(CombinatorialFreeModule): - [Humphreys08]_ """ + def __init__(self, module) -> None: r""" Initialize ``self``. @@ -122,8 +123,7 @@ def __init__(self, module) -> None: base_ring = module.base_ring() indices = module.indices() category = module.category() - CombinatorialFreeModule.__init__(self, base_ring, indices, category=category, - **module.print_options()) + CombinatorialFreeModule.__init__(self, base_ring, indices, category=category, **module.print_options()) def _repr_(self): r""" @@ -154,6 +154,7 @@ def _latex_(self): { M_{2 \Lambda_{1}} }^{\vee} """ from sage.misc.latex import latex + return "{" + latex(self._module) + "}^{\\vee}" def _repr_generator(self, m): @@ -362,8 +363,7 @@ def _pbw_monomial_on_basis(self, p, m): ret = self.monomial(m) for b, exp in reversed(p._sorted_items()): for _ in range(exp): - ret = self.linear_combination((self._lie_algebra_on_basis(b, m), mc) - for m, mc in ret._monomial_coefficients.items()) + ret = self.linear_combination((self._lie_algebra_on_basis(b, m), mc) for m, mc in ret._monomial_coefficients.items()) return ret class Element(CombinatorialFreeModule.Element): @@ -402,26 +402,21 @@ def _acted_upon_(self, scalar, self_on_left=False): if self_on_left: # only implemented as a left module return None mc = scalar.monomial_coefficients(copy=False) - return P.linear_combination((P._lie_algebra_on_basis(b, m), bc * mc) - for b, bc in mc.items() - for m, mc in self._monomial_coefficients.items()) + return P.linear_combination((P._lie_algebra_on_basis(b, m), bc * mc) for b, bc in mc.items() for m, mc in self._monomial_coefficients.items()) # Check for PBW elements try: scalar = P._pbw(scalar) except (ValueError, TypeError): # Cannot be made into a PBW element, so propagate it up - return CombinatorialFreeModule.Element._acted_upon_(self, - scalar, self_on_left) + return CombinatorialFreeModule.Element._acted_upon_(self, scalar, self_on_left) # We only implement x * self, i.e., as a left module if self_on_left: return None mc = scalar.monomial_coefficients(copy=False) - return P.linear_combination((P._pbw_monomial_on_basis(p, m), pc * mc) - for p, pc in mc.items() - for m, mc in self._monomial_coefficients.items()) + return P.linear_combination((P._pbw_monomial_on_basis(p, m), pc * mc) for p, pc in mc.items() for m, mc in self._monomial_coefficients.items()) ##################################################################### @@ -441,6 +436,7 @@ class SimpleModuleIndices(IndexedFreeAbelianMonoid): The current implementation assumes the Lie algebra `\mathfrak{g}` is finite dimensional. """ + # This is only necessary because of the IndexedMonoid.__classcall__. @staticmethod def __classcall__(cls, simple, prefix='f', **kwds): @@ -491,8 +487,7 @@ def __init__(self, simple, prefix, category=None, **kwds) -> None: sorting_key = kwds.pop('sorting_key', self._simple._pbw._monoid_key) IndexedGenerators.__init__(self, self._indices, prefix, sorting_key=sorting_key, **kwds) - self._sorted_supp = sorted(self._g._negative_half_index_set(), key=self._simple._pbw._basis_key, - reverse=self.print_options()['sorting_reverse']) + self._sorted_supp = sorted(self._g._negative_half_index_set(), key=self._simple._pbw._basis_key, reverse=self.print_options()['sorting_reverse']) self._basis = {self.one(): self._simple._ambient.highest_weight_vector()} self._lead_supp_to_index = {self._simple._ambient.highest_weight_vector().leading_support(): self.one()} # This is used for iteration and keeps track of the current depth @@ -784,8 +779,10 @@ def cardinality(self): from sage.combinat.crystals.monomial_crystals import ( CrystalOfNakajimaMonomials, ) + return CrystalOfNakajimaMonomials(la).cardinality() from sage.rings.infinity import infinity + return infinity @@ -794,6 +791,7 @@ class SimpleModule(ModulePrinting, CombinatorialFreeModule): Return the simple module `L_{\lambda}` as the image of the natural morphism `\phi: M_{\lambda} \to M_{\lambda}^{\vee}`. """ + @staticmethod def __classcall_private__(cls, g, weight, *args, **kwds): r""" @@ -843,8 +841,7 @@ def __init__(self, g, weight, prefix='f', basis_key=None, **kwds) -> None: if self._dom_int: category = category.FiniteDimensional() ModulePrinting.__init__(self, 'u') - CombinatorialFreeModule.__init__(self, base_ring, indices, category=category, - **self._ambient.print_options()) + CombinatorialFreeModule.__init__(self, base_ring, indices, category=category, **self._ambient.print_options()) def _repr_(self): r""" @@ -873,6 +870,7 @@ def _latex_(self): L_{2 \Lambda_{1}} """ from sage.misc.latex import latex + return "L_{{{}}}".format(latex(self._weight)) def ambient(self): @@ -1026,8 +1024,7 @@ def highest_weight_vector(self): u[Lambda[1] + Lambda[2]] """ one = self.base_ring().one() - return self._from_dict({self._indices.one(): one}, - remove_zeros=False, coerce=False) + return self._from_dict({self._indices.one(): one}, remove_zeros=False, coerce=False) def lie_algebra(self): r""" @@ -1162,6 +1159,7 @@ class FiniteDimensionalSimpleModule(SimpleModule): """ A finite dimensional simple module. """ + def bgg_resolution(self): """ Return the BGG resolution of ``self``. @@ -1176,4 +1174,5 @@ def bgg_resolution(self): of Lie algebra of ['A', 2] in the Chevalley basis """ from sage.algebras.lie_algebras.bgg_resolution import BGGResolution + return BGGResolution(self) diff --git a/src/sage/algebras/lie_algebras/bgg_resolution.py b/src/sage/algebras/lie_algebras/bgg_resolution.py index 396d149df52..228358649a9 100644 --- a/src/sage/algebras/lie_algebras/bgg_resolution.py +++ b/src/sage/algebras/lie_algebras/bgg_resolution.py @@ -6,7 +6,7 @@ - Travis Scrimshaw (2024-01-07): Initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2024 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.cachefunc import cached_function from sage.structure.unique_representation import UniqueRepresentation @@ -65,6 +65,7 @@ class BGGResolution(UniqueRepresentation, ChainComplex_class): ....: for i in range(w0.length())) True """ + def __init__(self, L): r""" Initialize ``self``. @@ -78,6 +79,7 @@ def __init__(self, L): sage: TestSuite(res).run() """ from sage.combinat.root_system.weyl_group import WeylGroup + ct = L.lie_algebra().cartan_type() self._cartan_type = ct self._simple = L @@ -187,18 +189,19 @@ def build_differentials(W): 4: [s2*s1*s2*s1]} """ from itertools import combinations + w0 = W.long_element() maxlen = w0.length() - module_order = {i: [] for i in range(maxlen+1)} + module_order = {i: [] for i in range(maxlen + 1)} for w in sorted(W): module_order[w.length()].append(w) one = ZZ.one() # Set the initial step - prev = {w: (j, frozenset([0])) for j, w in enumerate(module_order[maxlen-1])} - prev_mat = matrix(ZZ, [[one]]*len(module_order[maxlen-1]), immutable=True) + prev = {w: (j, frozenset([0])) for j, w in enumerate(module_order[maxlen - 1])} + prev_mat = matrix(ZZ, [[one]] * len(module_order[maxlen - 1]), immutable=True) differentials = {maxlen: prev_mat} - for i in range(maxlen-2, -1, -1): + for i in range(maxlen - 2, -1, -1): mat = matrix.zero(ZZ, len(module_order[i]), len(prev)) cur = {} for j, w in enumerate(module_order[i]): @@ -222,9 +225,9 @@ def build_differentials(W): mat[j, vpind] = -mat[j, vind] * prev_mat[vpind, uind] * prev_mat[vind, uind] else: assert mat[j, vpind] * prev_mat[vpind, uind] + mat[j, vind] * prev_mat[vind, uind] == 0 - differentials[i+1] = mat + differentials[i + 1] = mat prev = cur prev_mat = mat differentials[0] = matrix.zero(ZZ, 0, 1) - differentials[maxlen+1] = matrix.zero(ZZ, 1, 0) + differentials[maxlen + 1] = matrix.zero(ZZ, 1, 0) return differentials, module_order diff --git a/src/sage/algebras/lie_algebras/center_uea.py b/src/sage/algebras/lie_algebras/center_uea.py index e5c06dc1283..e5f030ba6b4 100644 --- a/src/sage/algebras/lie_algebras/center_uea.py +++ b/src/sage/algebras/lie_algebras/center_uea.py @@ -51,6 +51,7 @@ class CenterIndices(IndexedFreeAbelianMonoid): component in increasing order (as each is a finite dimensional vector space). For more precise details, see [Motsak2006]_. """ + @staticmethod def __classcall__(cls, center): r""" @@ -128,6 +129,7 @@ def _latex_(self): B\left( Z\left( PBW\left( \mathcal{W}(5)_{\Bold{F}_{5}} \right) \right) \right) """ from sage.misc.latex import latex + return r"B\left( {} \right)".format(latex(self._center)) def lift_on_basis(self, m): @@ -166,8 +168,7 @@ def lift_on_basis(self, m): supp = m.support() # We might have not computed the correct degree, but we can lift the # element if we have computed all of the corresponding generators. - if all(i in self._gen_degrees and self._gen_degrees[i] in self._lift_map - for i in supp): + if all(i in self._gen_degrees and self._gen_degrees[i] in self._lift_map for i in supp): ret = self._envelop_alg.one() divisors = [mp for mp in self._cur_basis_inv if mp.divides(m) and not mp.is_one()] while not m.is_one(): @@ -223,7 +224,7 @@ def some_elements(self): gens = [next(it) for _ in range(4)] # We construct it as a set in case we introduce duplicates. ret = set(gens) - ret.update([self.prod(gens), gens[1] * gens[3]**4, gens[1]**4 * gens[2]**3]) + ret.update([self.prod(gens), gens[1] * gens[3] ** 4, gens[1] ** 4 * gens[2] ** 3]) # Sort the output for uniqueness return sorted(ret, key=lambda m: (self.degree(m), m.to_word_list())) @@ -274,8 +275,8 @@ def _construct_next_degree(self): # so the product order doesn't matter. # Since we always update this, it is sufficient to compute it new_red = {} - for i in range(1, self._cur_deg//2+1): - for ls, lelt in self._lift_map[self._cur_deg-i].items(): + for i in range(1, self._cur_deg // 2 + 1): + for ls, lelt in self._lift_map[self._cur_deg - i].items(): for rs, relt in self._lift_map[i].items(): supp = ls * rs new_red[supp] = lelt * relt @@ -309,11 +310,10 @@ def _construct_next_degree(self): continue M = matrix(R, [[v[s] for v in ad] for s in supp]) ker = M.right_kernel_matrix() - vecs = [self._reduce(UEA.linear_combination((vecs[i], c) for i, c in kv.items())) - for kv in ker.rows()] + vecs = [self._reduce(UEA.linear_combination((vecs[i], c) for i, c in kv.items())) for kv in ker.rows()] # Lastly, update the appropriate data - if not vecs: # No new central elements, so nothing to do + if not vecs: # No new central elements, so nothing to do return new_gens = {} for v in vecs: @@ -323,8 +323,7 @@ def _construct_next_degree(self): ls = v.trailing_support(key=UEA._monomial_key) self._cur_vecs.remove(UEA.monomial(ls)) new_gens[ls] = self._reduce(v) - assert (self._cur_num_gens not in self._gen_degrees - or self._gen_degrees[self._cur_num_gens] == self._cur_deg) + assert self._cur_num_gens not in self._gen_degrees or self._gen_degrees[self._cur_num_gens] == self._cur_deg self._gen_degrees[self._cur_num_gens] = self._cur_deg mon = self.gen(self._cur_num_gens) self._cur_basis[ls] = mon @@ -382,6 +381,7 @@ class SimpleLieCenterIndices(CenterIndices): For more information, see :class:`~sage.algebras.lie_algebras.center_uea.CenterIndices`. """ + def __init__(self, center): r""" Initialize ``self``. @@ -419,7 +419,7 @@ def __iter__(self): wts = sorted(self._gen_degrees.values(), reverse=True) while True: for exps in intvecwt_iterator(deg, wts): - yield self.element_class(self, {n-1-i: e for i, e in enumerate(exps) if e}) + yield self.element_class(self, {n - 1 - i: e for i, e in enumerate(exps) if e}) deg += 1 @@ -497,6 +497,7 @@ class CenterUEA(CombinatorialFreeModule): sage: all(v * g == g * v for g in U.algebra_generators() for v in elts) True """ + def __init__(self, g, UEA): r""" Initialize ``self``. @@ -522,18 +523,14 @@ def __init__(self, g, UEA): self._g = g self._envelop_alg = UEA - if (self._g in KacMoodyAlgebras - and self._g.cartan_type().is_finite() - and R.characteristic() == 0): + if self._g in KacMoodyAlgebras and self._g.cartan_type().is_finite() and R.characteristic() == 0: indices = SimpleLieCenterIndices(self) else: indices = CenterIndices(self) category = UEA.category() base = category.base() category = GradedAlgebrasWithBasis(base).Commutative() | category.Subobjects() - CombinatorialFreeModule.__init__(self, R, indices, category=category, - prefix='', bracket=False, latex_bracket=False, - sorting_key=self._sorting_key) + CombinatorialFreeModule.__init__(self, R, indices, category=category, prefix='', bracket=False, latex_bracket=False, sorting_key=self._sorting_key) self.lift.register_as_coercion() def _repr_(self): @@ -563,6 +560,7 @@ def _latex_(self): Z\left( PBW\left( \mathcal{W}(5)_{\Bold{F}_{5}} \right) \right) """ from sage.misc.latex import latex + return r"Z\left( {} \right)".format(latex(self._envelop_alg)) def _sorting_key(self, m): @@ -743,7 +741,7 @@ def retract(self, elt): # in the Chevalley basis as ee are unable to pass a key for the # module morphism. Additionally, the implementation below does more # operations in-place than the module morphism. - #return self.lift.section() + # return self.lift.section() UEA = self._envelop_alg elt = UEA(elt) # We manipulate the dictionary (in place) to avoid creating elements diff --git a/src/sage/algebras/lie_algebras/classical_lie_algebra.py b/src/sage/algebras/lie_algebras/classical_lie_algebra.py index 8c622da566a..11e42689daa 100644 --- a/src/sage/algebras/lie_algebras/classical_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/classical_lie_algebra.py @@ -66,6 +66,7 @@ class ClassicalMatrixLieAlgebra(MatrixLieAlgebraFromAssociative): sage: lie_algebras.ClassicalMatrix(QQ, cartan_type=['D',4]) Special orthogonal Lie algebra of rank 8 over Rational Field """ + @staticmethod def __classcall_private__(cls, R, cartan_type): """ @@ -93,11 +94,11 @@ def __classcall_private__(cls, R, cartan_type): if cartan_type.type() == 'A': return sl(R, cartan_type.rank() + 1) if cartan_type.type() == 'B': - return so(R, 2*cartan_type.rank() + 1) + return so(R, 2 * cartan_type.rank() + 1) if cartan_type.type() == 'C': - return sp(R, 2*cartan_type.rank()) + return sp(R, 2 * cartan_type.rank()) if cartan_type.type() == 'D': - return so(R, 2*cartan_type.rank()) + return so(R, 2 * cartan_type.rank()) if cartan_type.type() == 'E': if cartan_type.rank() == 6: return e6(R) @@ -152,19 +153,16 @@ def __init__(self, R, ct, e, f, h, sparse=True): names += ['h%s' % i for i in I] category = LieAlgebras(R).FiniteDimensional().WithBasis() from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + index_set = FiniteEnumeratedSet(names) - MatrixLieAlgebraFromAssociative.__init__(self, e[0].parent(), - gens=tuple(e + f + h), - names=tuple(names), - index_set=index_set, - category=category) + MatrixLieAlgebraFromAssociative.__init__(self, e[0].parent(), gens=tuple(e + f + h), names=tuple(names), index_set=index_set, category=category) self._cartan_type = ct self._sparse = sparse gens = tuple(self.gens()) self._e = Family({i: gens[c] for c, i in enumerate(I)}) - self._f = Family({i: gens[n+c] for c, i in enumerate(I)}) - self._h = Family({i: gens[2*n+c] for c, i in enumerate(I)}) + self._f = Family({i: gens[n + c] for c, i in enumerate(I)}) + self._h = Family({i: gens[2 * n + c] for c, i in enumerate(I)}) def e(self, i): r""" @@ -249,7 +247,7 @@ def epsilon(self, i, h): sage: g.epsilon(3, g.h(1)) 0 """ - return h[i-1,i-1] + return h[i - 1, i - 1] # Do we want this to be optional or required? # There probably is a generic implementation we can do. @@ -286,7 +284,7 @@ def highest_root_basis_elt(self, pos=True): RL = self._cartan_type.root_system().root_lattice() coroots = RL.simple_coroots() theta = RL.highest_root() - i,w = theta.to_simple_root(True) + i, w = theta.to_simple_root(True) r = RL.simple_root(i) if pos: gens = self._e @@ -339,12 +337,12 @@ def basis(self): def set_row(mat, row, val): for k, v in val.dict().items(): a, b = k - mat[row, a*m+b] = v + mat[row, a * m + b] = v def build_assoc(row): ret = {} for i, v in row.dict().items(): - ret[i//m, i % m] = v + ret[i // m, i % m] = v return self._assoc(ret) while added: @@ -374,7 +372,7 @@ def build_assoc(row): pivots = cur_mat.pivots() added = [] if len(pivots) != len(basis_pivots): - for i,p in enumerate(pivots): + for i, p in enumerate(pivots): if p in basis_pivots: continue basis_pivots.add(p) @@ -384,11 +382,9 @@ def build_assoc(row): added.append(self.element_class(self, self._assoc(cur_mat[i].list()))) cur_mat = cur_mat.submatrix(nrows=len(pivots)) if self._sparse: - basis = [self.element_class(self, build_assoc(cur_mat[i])) - for i in range(cur_mat.rank())] + basis = [self.element_class(self, build_assoc(cur_mat[i])) for i in range(cur_mat.rank())] else: - basis = [self.element_class(self, self._assoc(cur_mat[i].list())) - for i in range(cur_mat.rank())] + basis = [self.element_class(self, self._assoc(cur_mat[i].list())) for i in range(cur_mat.rank())] return Family(basis) def affine(self, kac_moody=True): @@ -406,6 +402,7 @@ def affine(self, kac_moody=True): Affine Special orthogonal Lie algebra of rank 5 over Rational Field """ from sage.algebras.lie_algebras.affine_lie_algebra import AffineLieAlgebra + return AffineLieAlgebra(self, kac_moody=kac_moody) @@ -421,6 +418,7 @@ class gl(MatrixLieAlgebraFromAssociative): - ``R`` -- the base ring - ``n`` -- the size of the matrix """ + def __init__(self, R, n): """ Initialize ``self``. @@ -454,11 +452,9 @@ def __init__(self, R, n): self._n = n category = LieAlgebras(R).FiniteDimensional().WithBasis() from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + index_set = FiniteEnumeratedSet(names) - MatrixLieAlgebraFromAssociative.__init__(self, MS, tuple(gens), - names=tuple(names), - index_set=index_set, - category=category) + MatrixLieAlgebraFromAssociative.__init__(self, MS, tuple(gens), names=tuple(names), index_set=index_set, category=category) def _repr_(self): """ @@ -490,8 +486,7 @@ def killing_form(self, x, y): sage: g.killing_form(x, y) 8 """ - return (2 * self._n * (x.value * y.value).trace() - - 2 * x.value.trace() * y.value.trace()) + return 2 * self._n * (x.value * y.value).trace() - 2 * x.value.trace() * y.value.trace() @cached_method def basis(self): @@ -561,6 +556,7 @@ class sl(ClassicalMatrixLieAlgebra): The Lie algebra `\mathfrak{sl}_n`, which consists of all `n \times n` matrices with trace 0. This is the Lie algebra of type `A_{n-1}`. """ + def __init__(self, R, n): """ Initialize ``self``. @@ -572,11 +568,11 @@ def __init__(self, R, n): """ MS = MatrixSpace(R, n, sparse=True) one = R.one() - e = [MS({(i,i+1):one}) for i in range(n-1)] - f = [MS({(i+1,i):one}) for i in range(n-1)] - h = [MS({(i,i):one, (i+1,i+1):-one}) for i in range(n-1)] + e = [MS({(i, i + 1): one}) for i in range(n - 1)] + f = [MS({(i + 1, i): one}) for i in range(n - 1)] + h = [MS({(i, i): one, (i + 1, i + 1): -one}) for i in range(n - 1)] self._n = n - ClassicalMatrixLieAlgebra.__init__(self, R, CartanType(['A', n-1]), e, f, h) + ClassicalMatrixLieAlgebra.__init__(self, R, CartanType(['A', n - 1]), e, f, h) def _repr_(self): """ @@ -625,7 +621,7 @@ def simple_root(self, i, h): [ 0 0 -1 2] """ i = self.index_set().index(i) - return h[i,i] - h[i+1,i+1] + return h[i, i] - h[i + 1, i + 1] class so(ClassicalMatrixLieAlgebra): @@ -661,6 +657,7 @@ class so(ClassicalMatrixLieAlgebra): This is the Lie algebra of type `B_{(n-1)/2}` or `D_{n/2}` if `n` is odd or even respectively. """ + def __init__(self, R, n): """ Initialize ``self``. @@ -678,23 +675,22 @@ def __init__(self, R, n): if n % 2 == 0: # Even m = n // 2 - 1 # -1 for indexing n -= 1 - e = [MS({(m-1, n): one, (m, n-1): -one})] - f = [MS({(n, m-1): one, (n-1, m): -one})] - h = [MS({(m-1, m-1): one, (m, m): one, (n-1, n-1): -one, (n, n): -one})] + e = [MS({(m - 1, n): one, (m, n - 1): -one})] + f = [MS({(n, m - 1): one, (n - 1, m): -one})] + h = [MS({(m - 1, m - 1): one, (m, m): one, (n - 1, n - 1): -one, (n, n): -one})] m += 1 ct = CartanType(['D', m]) else: # Odd - m = (n-1) // 2 - 1 # -1 for indexing + m = (n - 1) // 2 - 1 # -1 for indexing n -= 1 - e = [MS({(m, n): 2, (n, n-1): -2})] - f = [MS({(n, m): one, (n-1, n): -one})] - h = [MS({(m, m): 2, (n-1, n-1): -2})] + e = [MS({(m, n): 2, (n, n - 1): -2})] + f = [MS({(n, m): one, (n - 1, n): -one})] + h = [MS({(m, m): 2, (n - 1, n - 1): -2})] m += 1 ct = CartanType(['B', m]) - e = [MS({(i, i+1): one, (m+i+1, m+i): -one}) for i in range(m-1)] + e - f = [MS({(i+1, i): one, (m+i, m+i+1): -one}) for i in range(m-1)] + f - h = [MS({(i, i): one, (i+1, i+1): -one, (m+i, m+i): -one, (m+i+1, m+i+1): one}) - for i in range(m-1)] + h + e = [MS({(i, i + 1): one, (m + i + 1, m + i): -one}) for i in range(m - 1)] + e + f = [MS({(i + 1, i): one, (m + i, m + i + 1): -one}) for i in range(m - 1)] + f + h = [MS({(i, i): one, (i + 1, i + 1): -one, (m + i, m + i): -one, (m + i + 1, m + i + 1): one}) for i in range(m - 1)] + h ClassicalMatrixLieAlgebra.__init__(self, R, ct, e, f, h) def _repr_(self): @@ -764,10 +760,10 @@ def simple_root(self, i, h): i = self.index_set().index(i) if i == len(self.index_set()) - 1: if self._n % 2 == 0: - return h[i-1, i-1] + h[i, i] + return h[i - 1, i - 1] + h[i, i] # otherwise we are odd return h[i, i] - return h[i, i] - h[i+1, i+1] + return h[i, i] - h[i + 1, i + 1] class sp(ClassicalMatrixLieAlgebra): @@ -792,6 +788,7 @@ class sp(ClassicalMatrixLieAlgebra): This is the Lie algebra of type `C_k`. """ + def __init__(self, R, n): """ Initialize ``self``. @@ -805,12 +802,12 @@ def __init__(self, R, n): one = R.one() self._n = n n = n // 2 - e = [MS({(i,i+1):one, (n+i+1,n+i):-one}) for i in range(n-1)] - e.append(MS({(n-1,2*n-1):one})) # -1 for indexing - f = [MS({(i+1,i):one, (n+i,n+i+1):-one}) for i in range(n-1)] - f.append(MS({(2*n-1,n-1):one})) # -1 for indexing - h = [MS({(i,i):one, (i+1,i+1):-one, (n+i,n+i):-one, (n+i+1,n+i+1):one}) for i in range(n-1)] - h.append(MS({(n-1,n-1):one, (2*n-1,2*n-1):-one})) # -1 for indexing + e = [MS({(i, i + 1): one, (n + i + 1, n + i): -one}) for i in range(n - 1)] + e.append(MS({(n - 1, 2 * n - 1): one})) # -1 for indexing + f = [MS({(i + 1, i): one, (n + i, n + i + 1): -one}) for i in range(n - 1)] + f.append(MS({(2 * n - 1, n - 1): one})) # -1 for indexing + h = [MS({(i, i): one, (i + 1, i + 1): -one, (n + i, n + i): -one, (n + i + 1, n + i + 1): one}) for i in range(n - 1)] + h.append(MS({(n - 1, n - 1): one, (2 * n - 1, 2 * n - 1): -one})) # -1 for indexing ClassicalMatrixLieAlgebra.__init__(self, R, CartanType(['C', n]), e, f, h) def _repr_(self): @@ -861,14 +858,15 @@ def simple_root(self, i, h): """ i = self.index_set().index(i) if i == self._n / 2 - 1: - return 2*h[i,i] - return h[i,i] - h[i+1,i+1] + return 2 * h[i, i] + return h[i, i] - h[i + 1, i + 1] class ExceptionalMatrixLieAlgebra(ClassicalMatrixLieAlgebra): """ A matrix Lie algebra of exceptional type. """ + def __init__(self, R, cartan_type, e, f, h=None, sparse=False): """ Initialize ``self``. @@ -902,6 +900,7 @@ class e6(ExceptionalMatrixLieAlgebra): The simple Lie algebra `\mathfrak{e}_6` of type `E_6`. The matrix representation is given following [HRT2000]_. """ + def __init__(self, R): """ Initialize ``self``. @@ -913,14 +912,9 @@ def __init__(self, R): """ MS = MatrixSpace(R, 27, sparse=True) one = R.one() - coords = [[(0,1), (10,12), (13,15), (16,17), (18,19), (20,21)], - [(3,4), (5,6), (7,9), (18,20), (19,21), (22,23)], - [(1,2), (8,10), (11,13), (14,16), (19,22), (21,23)], - [(2,3), (6,8), (9,11), (16,18), (17,19), (23,24)], - [(3,5), (4,6), (11,14), (13,16), (15,17), (24,25)], - [(5,7), (6,9), (8,11), (10,13), (12,15), (25,26)]] + coords = [[(0, 1), (10, 12), (13, 15), (16, 17), (18, 19), (20, 21)], [(3, 4), (5, 6), (7, 9), (18, 20), (19, 21), (22, 23)], [(1, 2), (8, 10), (11, 13), (14, 16), (19, 22), (21, 23)], [(2, 3), (6, 8), (9, 11), (16, 18), (17, 19), (23, 24)], [(3, 5), (4, 6), (11, 14), (13, 16), (15, 17), (24, 25)], [(5, 7), (6, 9), (8, 11), (10, 13), (12, 15), (25, 26)]] e = [MS({c: one for c in coord}) for coord in coords] - f = [MS({(c[1],c[0]): one for c in coord}) for coord in coords] + f = [MS({(c[1], c[0]): one for c in coord}) for coord in coords] ExceptionalMatrixLieAlgebra.__init__(self, R, CartanType(['E', 6]), e, f) @@ -931,6 +925,7 @@ class e7(ExceptionalMatrixLieAlgebra): The simple Lie algebra `\mathfrak{e}_7` of type `E_7`. The matrix representation is given following [HRT2000]_. """ + def __init__(self, R): """ Initialize ``self``. @@ -947,13 +942,7 @@ def __init__(self, R): """ MS = MatrixSpace(R, 56, sparse=True) one = R.one() - coords = [[(6,7), (8,9), (10,11), (12,14), (15,17), (18,21), (34,37), (38,40), (41,43), (44,45), (46,47), (48,49)], - [(4,5), (6,8), (7,9), (19,22), (23,25), (26,28), (27,29), (30,32), (33,36), (46,48), (47,49), (50,51)], - [(4,6), (5,8), (11,13), (14,16), (17,20), (21,24), (31,34), (35,38), (39,41), (42,44), (47,50), (49,51)], - [(3,4), (8,10), (9,11), (16,19), (20,23), (24,27), (28,31), (32,35), (36,39), (44,46), (45,47), (51,52)], - [(2,3), (10,12), (11,14), (13,16), (23,26), (25,28), (27,30), (29,32), (39,42), (41,44), (43,45), (52,53)], - [(1,2), (12,15), (14,17), (16,20), (19,23), (22,25), (30,33), (32,36), (35,39), (38,41), (40,43), (53,54)], - [(0,1), (15,18), (17,21), (20,24), (23,27), (25,29), (26,30), (28,32), (31,35), (34,38), (37,40), (54,55)]] + coords = [[(6, 7), (8, 9), (10, 11), (12, 14), (15, 17), (18, 21), (34, 37), (38, 40), (41, 43), (44, 45), (46, 47), (48, 49)], [(4, 5), (6, 8), (7, 9), (19, 22), (23, 25), (26, 28), (27, 29), (30, 32), (33, 36), (46, 48), (47, 49), (50, 51)], [(4, 6), (5, 8), (11, 13), (14, 16), (17, 20), (21, 24), (31, 34), (35, 38), (39, 41), (42, 44), (47, 50), (49, 51)], [(3, 4), (8, 10), (9, 11), (16, 19), (20, 23), (24, 27), (28, 31), (32, 35), (36, 39), (44, 46), (45, 47), (51, 52)], [(2, 3), (10, 12), (11, 14), (13, 16), (23, 26), (25, 28), (27, 30), (29, 32), (39, 42), (41, 44), (43, 45), (52, 53)], [(1, 2), (12, 15), (14, 17), (16, 20), (19, 23), (22, 25), (30, 33), (32, 36), (35, 39), (38, 41), (40, 43), (53, 54)], [(0, 1), (15, 18), (17, 21), (20, 24), (23, 27), (25, 29), (26, 30), (28, 32), (31, 35), (34, 38), (37, 40), (54, 55)]] e = [MS({c: one for c in coord}) for coord in coords] f = [MS({(c[1], c[0]): one for c in coord}) for coord in coords] ExceptionalMatrixLieAlgebra.__init__(self, R, CartanType(['E', 7]), e, f) @@ -966,6 +955,7 @@ class e8(ExceptionalMatrixLieAlgebra): The simple Lie algebra `\mathfrak{e}_8` of type `E_8` built from the adjoint representation in the Chevalley basis. """ + def __init__(self, R): """ Initialize ``self``. @@ -1009,6 +999,7 @@ class f4(ExceptionalMatrixLieAlgebra): representation is given following [HRT2000]_ but indexed in the reversed order (i.e., interchange 1 with 4 and 2 with 3). """ + def __init__(self, R): """ Initialize ``self``. @@ -1021,27 +1012,17 @@ def __init__(self, R): MS = MatrixSpace(R, 26, sparse=True) one = R.one() - coords = [[(0,1), (5,7), (6,9), (8,11), (10,12), (10,13), (12,14), - (15,16), (17,18), (19,20), (24,25)], - [(1,2), (3,5), (4,6), (8,10), (11,12), (11,13), (13,15), - (14,16), (18,21), (20,22), (23,24)], - [(2,3), (6,8), (9,11), (15,17), (16,18), (22,23)], - [(3,4), (5,6), (7,9), (17,19), (18,20), (21,22)]] + coords = [[(0, 1), (5, 7), (6, 9), (8, 11), (10, 12), (10, 13), (12, 14), (15, 16), (17, 18), (19, 20), (24, 25)], [(1, 2), (3, 5), (4, 6), (8, 10), (11, 12), (11, 13), (13, 15), (14, 16), (18, 21), (20, 22), (23, 24)], [(2, 3), (6, 8), (9, 11), (15, 17), (16, 18), (22, 23)], [(3, 4), (5, 6), (7, 9), (17, 19), (18, 20), (21, 22)]] e = [MS({c: one for c in coord}) for coord in coords] # Double (10, 12) in e1 and (11,13) in e2 - e[0][10,12] = 2*one - e[1][11,13] = 2*one - - coords = [[(1,0), (7,5), (9,6), (11,8), (12,10), (14,12), (14,13), - (16,15), (18,17), (20,19), (25,24)], - [(2,1), (5,3), (6,4), (10,8), (13,11), (15,12), (15,13), - (16,14), (21,18), (22,20), (24,23)], - [(3,2), (8,6), (11,9), (17,15), (18,16), (23,22)], - [(4,3), (6,5), (9,7), (19,17), (20,18), (22,21)]] + e[0][10, 12] = 2 * one + e[1][11, 13] = 2 * one + + coords = [[(1, 0), (7, 5), (9, 6), (11, 8), (12, 10), (14, 12), (14, 13), (16, 15), (18, 17), (20, 19), (25, 24)], [(2, 1), (5, 3), (6, 4), (10, 8), (13, 11), (15, 12), (15, 13), (16, 14), (21, 18), (22, 20), (24, 23)], [(3, 2), (8, 6), (11, 9), (17, 15), (18, 16), (23, 22)], [(4, 3), (6, 5), (9, 7), (19, 17), (20, 18), (22, 21)]] f = [MS({c: one for c in coord}) for coord in coords] # Double (14, 12) in f1 and (15,13) in f2 - f[0][14,12] = 2*one - f[1][15,13] = 2*one + f[0][14, 12] = 2 * one + f[1][15, 13] = 2 * one # Our Cartan matrix convention is dual to that of [HRT2000]_ e.reverse() @@ -1056,6 +1037,7 @@ class g2(ExceptionalMatrixLieAlgebra): The simple Lie algebra `\mathfrak{g}_2` of type `G_2`. The matrix representation is given following [HRT2000]_. """ + def __init__(self, R): """ Initialize ``self``. @@ -1067,18 +1049,16 @@ def __init__(self, R): """ MS = MatrixSpace(R, 7, sparse=True) one = R.one() - e = [MS({(0,1): one, (2,3): 2*one, (3,4): one, (5,6): one}), - MS({(1,2): one, (4,5): one})] - f = [MS({(1,0): one, (3,2): one, (4,3): 2*one, (6,5): one}), - MS({(2,1): one, (5,4): one})] - h = [MS({(0,0): one, (1,1): -one, (2,2): 2*one, (4,4): -2*one, (5,5): one, (6,6): -one}), - MS({(1,1): one, (2,2): -one, (4,4): one, (5,5): -one})] + e = [MS({(0, 1): one, (2, 3): 2 * one, (3, 4): one, (5, 6): one}), MS({(1, 2): one, (4, 5): one})] + f = [MS({(1, 0): one, (3, 2): one, (4, 3): 2 * one, (6, 5): one}), MS({(2, 1): one, (5, 4): one})] + h = [MS({(0, 0): one, (1, 1): -one, (2, 2): 2 * one, (4, 4): -2 * one, (5, 5): one, (6, 6): -one}), MS({(1, 1): one, (2, 2): -one, (4, 4): one, (5, 5): -one})] ExceptionalMatrixLieAlgebra.__init__(self, R, CartanType(['G', 2]), e, f, h) ####################################### # Compact real form + class MatrixCompactRealForm(FinitelyGeneratedLieAlgebra): r""" The compact real form of a matrix Lie algebra. @@ -1116,6 +1096,7 @@ class MatrixCompactRealForm(FinitelyGeneratedLieAlgebra): ... TypeError: no conversion of this rational to integer """ + def __init__(self, R, cartan_type): """ Initialize ``self``. @@ -1132,12 +1113,11 @@ def __init__(self, R, cartan_type): self._MS = self._classical._assoc dim = self._classical.dimension() from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + index_set = FiniteEnumeratedSet(range(dim)) names = tuple(['CR%s' % s for s in range(dim)]) category = LieAlgebras(R).FiniteDimensional().WithBasis() - FinitelyGeneratedLieAlgebra.__init__(self, R, names=names, - index_set=index_set, - category=category) + FinitelyGeneratedLieAlgebra.__init__(self, R, names=names, index_set=index_set, category=category) @cached_method def basis(self): @@ -1169,19 +1149,16 @@ def basis(self): ] """ from sage.matrix.constructor import matrix + zero = self._MS.zero() basis = self._classical.basis() R = self.base_ring() - mat = matrix(R, [((b.value - b.value.transpose()) / 2).list() for b in basis], - sparse=self._MS.is_sparse()) + mat = matrix(R, [((b.value - b.value.transpose()) / 2).list() for b in basis], sparse=self._MS.is_sparse()) mat.echelonize() - ret = [self.element_class(self, self._MS(mat[i].list()), zero) - for i in range(mat.rank())] - mat = matrix(R, [((b.value + b.value.transpose()) / 2).list() for b in basis], - sparse=self._MS.is_sparse()) + ret = [self.element_class(self, self._MS(mat[i].list()), zero) for i in range(mat.rank())] + mat = matrix(R, [((b.value + b.value.transpose()) / 2).list() for b in basis], sparse=self._MS.is_sparse()) mat.echelonize() - ret += [self.element_class(self, zero, self._MS(mat[i].list())) - for i in range(mat.rank())] + ret += [self.element_class(self, zero, self._MS(mat[i].list())) for i in range(mat.rank())] return Family(ret) @cached_method @@ -1258,6 +1235,7 @@ class Element(Element): """ An element of a matrix Lie algebra in its compact real form. """ + def __init__(self, parent, real, imag): """ Initialize ``self``. @@ -1297,6 +1275,7 @@ def _combined_matrix(self): Univariate Polynomial Ring in i over Rational Field """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + MS = self.parent()._MS R = PolynomialRing(MS.base_ring(), 'i') return self._real + R.gen() * self._imag @@ -1335,6 +1314,7 @@ def _latex_(self): \end{array}\right) """ from sage.misc.latex import latex + return latex(self._combined_matrix()) def _ascii_art_(self): @@ -1351,6 +1331,7 @@ def _ascii_art_(self): [6/7*i - 2/7 8/7*i - 3/7 -11/7*i] """ from sage.typeset.ascii_art import ascii_art + return ascii_art(self._combined_matrix()) def _unicode_art_(self): @@ -1367,6 +1348,7 @@ def _unicode_art_(self): ⎝6/7*i - 2/7 8/7*i - 3/7 -11/7*i⎠ """ from sage.typeset.unicode_art import unicode_art + return unicode_art(self._combined_matrix()) def __bool__(self) -> bool: @@ -1431,8 +1413,7 @@ def _add_(self, other): [ i - 1 i - 1 -i - 1 -i] """ P = self.parent() - return P.element_class(P, self._real + other._real, - self._imag + other._imag) + return P.element_class(P, self._real + other._real, self._imag + other._imag) def _sub_(self, other): r""" @@ -1451,8 +1432,7 @@ def _sub_(self, other): True """ P = self.parent() - return P.element_class(P, self._real - other._real, - self._imag - other._imag) + return P.element_class(P, self._real - other._real, self._imag - other._imag) def _neg_(self): r""" @@ -1498,8 +1478,7 @@ def _bracket_(self, other): A, B = self._real, self._imag X, Y = other._real, other._imag P = self.parent() - return P.element_class(P, A*X - X*A - B*Y + Y*B, - A*Y - Y*A + B*X - X*B) + return P.element_class(P, A * X - X * A - B * Y + Y * B, A * Y - Y * A + B * X - X * B) def _acted_upon_(self, x, self_on_left): r""" @@ -1529,7 +1508,7 @@ def _acted_upon_(self, x, self_on_left): [ 0 0 0 0 0 -7 0 0] """ P = self.parent() - return P.element_class(P, x*self._real, x*self._imag) + return P.element_class(P, x * self._real, x * self._imag) def monomial_coefficients(self, copy=False): """ @@ -1551,7 +1530,7 @@ def monomial_coefficients(self, copy=False): F = FreeModule(R, len(B[0])) dep = list(F.linear_dependence([F(b) for b in B])[0]) last = dep.pop() - self._mc = {i: R(-val / last) for i,val in enumerate(dep) if val != 0} + self._mc = {i: R(-val / last) for i, val in enumerate(dep) if val != 0} if copy: return dict(self._mc) return self._mc @@ -1560,6 +1539,7 @@ def monomial_coefficients(self, copy=False): ####################################### # Chevalley Basis + class LieAlgebraChevalleyBasis(LieAlgebraWithStructureCoefficients): r""" A simple finite dimensional Lie algebra in the Chevalley basis. @@ -1591,6 +1571,7 @@ class LieAlgebraChevalleyBasis(LieAlgebraWithStructureCoefficients): For simply-laced types, an alternative construction using an asymmetry function is given by :class:`LieAlgebraChevalleyBasis_simply_laced`. """ + @staticmethod def __classcall_private__(cls, R, cartan_type, epsilon=None): """ @@ -1642,9 +1623,9 @@ def __classcall_private__(cls, R, cartan_type, epsilon=None): raise ValueError("not a valid Dynkin orientation") else: from sage.graphs.graph import Graph + G = Graph(epsilon, multiedges=True, loops=True, format='list_of_edges') - if (G.has_multiple_edges() or G.has_loops() - or cartan_type.dynkin_diagram().to_undirected() != G.to_simple()): + if G.has_multiple_edges() or G.has_loops() or cartan_type.dynkin_diagram().to_undirected() != G.to_simple(): raise ValueError("not a valid Dynkin orientation") return LieAlgebraChevalleyBasis_simply_laced(R, cartan_type, epsilon) return super().__classcall__(cls, R, cartan_type) @@ -1662,8 +1643,7 @@ def __init__(self, R, cartan_type): self._Q = cartan_type.root_system().root_lattice() p_roots = list(self._Q.positive_roots_by_height()) n_roots = [-x for x in p_roots] - self._p_roots_index = OrderedDict((al, i) - for i, al in enumerate(p_roots)) + self._p_roots_index = OrderedDict((al, i) for i, al in enumerate(p_roots)) alphacheck = self._Q.simple_coroots() # We pass p_roots and n_roots so we don't have to reconstruct them @@ -1687,10 +1667,9 @@ def __init__(self, R, cartan_type): self._cartan_indices = range(len(p_roots), len(p_roots) + len(alphacheck)) names = tuple(names) from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + index_set = FiniteEnumeratedSet(index_set) - LieAlgebraWithStructureCoefficients.__init__(self, R, s_coeffs, names, index_set, - category, prefix='E', bracket='[', - sorting_key=self._basis_key) + LieAlgebraWithStructureCoefficients.__init__(self, R, s_coeffs, names, index_set, category, prefix='E', bracket='[', sorting_key=self._basis_key) def _construct_struct_coeffs(self, R, p_roots): """ @@ -1749,56 +1728,54 @@ def _construct_struct_coeffs(self, R, p_roots): # We do everything initially over QQ and then convert to R at the end # since this is a ZZ-basis. from sage.rings.rational_field import QQ + one = QQ.one() # Determine the signs for the structure coefficients from the root system # We first create the special roots sp_sign = {} - for i,a in enumerate(p_roots): - for b in p_roots[i+1:]: + for i, a in enumerate(p_roots): + for b in p_roots[i + 1 :]: if a + b not in p_roots: continue # Compute the sign for the extra special pair x, y = (a + b).extraspecial_pair() - if (x, y) == (a, b): # If it already is an extra special pair + if (x, y) == (a, b): # If it already is an extra special pair if (x, y) not in sp_sign: # This swap is so the structure coefficients match with GAP - if (sum(x.coefficients()) == sum(y.coefficients()) - and str(x) > str(y)): - y,x = x,y + if sum(x.coefficients()) == sum(y.coefficients()) and str(x) > str(y): + y, x = x, y sp_sign[(x, y)] = -one sp_sign[(y, x)] = one continue if b - x in roots: - t1 = ((b-x).norm_squared() / b.norm_squared() - * sp_sign[(x, b-x)] * sp_sign[(a, y-a)]) + t1 = (b - x).norm_squared() / b.norm_squared() * sp_sign[(x, b - x)] * sp_sign[(a, y - a)] else: t1 = 0 if a - x in roots: - t2 = ((a-x).norm_squared() / a.norm_squared() - * sp_sign[(x, a-x)] * sp_sign[(b, y-b)]) + t2 = (a - x).norm_squared() / a.norm_squared() * sp_sign[(x, a - x)] * sp_sign[(b, y - b)] else: t2 = 0 if t1 - t2 > 0: - sp_sign[(a,b)] = -one + sp_sign[(a, b)] = -one elif t2 - t1 > 0: - sp_sign[(a,b)] = one - sp_sign[(b,a)] = -sp_sign[(a,b)] + sp_sign[(a, b)] = one + sp_sign[(b, a)] = -sp_sign[(a, b)] # Function to construct the structure coefficients (up to sign) def e_coeff(r, s): p = 1 - while r - p*s in roots: + while r - p * s in roots: p += 1 return p # Now we can compute all necessary structure coefficients s_coeffs = {} - for i,r in enumerate(p_roots): + for i, r in enumerate(p_roots): # [e_r, h_i] and [h_i, f_r] for ac in alphacheck: c = R(r.scalar(ac)) @@ -1808,20 +1785,19 @@ def e_coeff(r, s): s_coeffs[(ac, -r)] = {-r: -c} # [e_r, f_r] - s_coeffs[(r, -r)] = {alphacheck[j]: Rc - for j, c in r.associated_coroot() if (Rc := R(c))} + s_coeffs[(r, -r)] = {alphacheck[j]: Rc for j, c in r.associated_coroot() if (Rc := R(c))} # [e_r, e_s] and [e_r, f_s] with r != +/-s # We assume s is positive, as otherwise we negate # both r and s and the resulting coefficient - for j, s in enumerate(p_roots[i+1:], start=i+1): - #j += i + 1 # Offset + for j, s in enumerate(p_roots[i + 1 :], start=i + 1): + # j += i + 1 # Offset # Since h(s) >= h(r), we have s - r > 0 when s - r is a root # [f_r, e_s] if s - r in p_roots: c = e_coeff(r, -s) - a, b = s-r, r - if self._p_roots_index[a] > self._p_roots_index[b]: # Note a != b + a, b = s - r, r + if self._p_roots_index[a] > self._p_roots_index[b]: # Note a != b c *= -sp_sign[(b, a)] else: c *= sp_sign[(a, b)] @@ -1863,6 +1839,7 @@ def _latex_(self): \mathfrak{g}(A_{2})_{\Bold{Q}} """ from sage.misc.latex import latex + return r"\mathfrak{{g}}({})_{{{}}}".format(latex(self._cartan_type), latex(self.base_ring())) def _test_structure_coeffs(self, **options): @@ -1879,6 +1856,7 @@ def _test_structure_coeffs(self, **options): # Setup the GAP objects from sage.libs.gap.libgap import libgap + L = libgap.SimpleLieAlgebra(ct.letter, ct.n, libgap(self.base_ring())) pos_B, neg_B, _ = libgap.ChevalleyBasis(L) gap_p_roots = libgap.PositiveRoots(libgap.RootSystem(L)).sage() @@ -1890,30 +1868,23 @@ def _test_structure_coeffs(self, **options): WL = ct.root_system().weight_lattice() La = WL.fundamental_weights() convert = {WL(root): root for root in p_roots} - index = {convert[sum(c*La[j+1] for j,c in enumerate(rt))]: i - for i, rt in enumerate(gap_p_roots)} + index = {convert[sum(c * La[j + 1] for j, c in enumerate(rt))]: i for i, rt in enumerate(gap_p_roots)} # Run the check basis = self.basis() roots = frozenset(p_roots) - for i,x in enumerate(p_roots): - for y in p_roots[i+1:]: + for i, x in enumerate(p_roots): + for y in p_roots[i + 1 :]: if x + y in roots: c = basis[x].bracket(basis[y]).leading_coefficient() a, b = (x + y).extraspecial_pair() - if (x, y) == (a, b): # If it already is an extra special pair - tester.assertEqual(pos_B[index[x]] * pos_B[index[y]], - c * pos_B[index[x+y]], - "extra special pair differ for [{}, {}]".format(x, y)) + if (x, y) == (a, b): # If it already is an extra special pair + tester.assertEqual(pos_B[index[x]] * pos_B[index[y]], c * pos_B[index[x + y]], "extra special pair differ for [{}, {}]".format(x, y)) else: - tester.assertEqual(pos_B[index[x]] * pos_B[index[y]], - c * pos_B[index[x+y]], - "incorrect structure coefficient for [{}, {}]".format(x, y)) - if x - y in roots: # This must be a negative root if it is a root + tester.assertEqual(pos_B[index[x]] * pos_B[index[y]], c * pos_B[index[x + y]], "incorrect structure coefficient for [{}, {}]".format(x, y)) + if x - y in roots: # This must be a negative root if it is a root c = basis[x].bracket(basis[-y]).leading_coefficient() - tester.assertEqual(pos_B[index[x]] * neg_B[index[y]], - c * neg_B[index[x-y]], - "incorrect structure coefficient for [{}, {}]".format(x, y)) + tester.assertEqual(pos_B[index[x]] * neg_B[index[y]], c * neg_B[index[x - y]], "incorrect structure coefficient for [{}, {}]".format(x, y)) def _repr_generator(self, m): """ @@ -1980,9 +1951,7 @@ def _basis_key(self, x): if x in self._p_roots_index: return self._p_roots_index[x] if -x in self._p_roots_index: - return (len(self._p_roots_index) - + self._cartan_type.rank() - + self._p_roots_index[-x]) + return len(self._p_roots_index) + self._cartan_type.rank() + self._p_roots_index[-x] alphacheck = list(self._Q.simple_coroots()) try: return len(self._p_roots_index) + alphacheck.index(x) @@ -2075,6 +2044,7 @@ def affine(self, kac_moody=True): Affine Kac-Moody algebra of ['A', 3] in the Chevalley basis """ from sage.algebras.lie_algebras.affine_lie_algebra import AffineLieAlgebra + return AffineLieAlgebra(self, kac_moody=kac_moody) # Useful in creating the UEA @@ -2089,7 +2059,7 @@ def indices_to_positive_roots_map(self): sage: L.indices_to_positive_roots_map() {1: alpha[1], 2: alpha[2], 3: alpha[1] + alpha[2]} """ - return {i+1: r for i, r in enumerate(self._Q.positive_roots())} + return {i + 1: r for i, r in enumerate(self._Q.positive_roots())} @cached_method def lie_algebra_generators(self, str_keys=False): @@ -2121,18 +2091,14 @@ def lie_algebra_generators(self, str_keys=False): ret['e{}'.format(i)] = B[al] ret['f{}'.format(i)] = B[-al] ret['h{}'.format(i)] = B[alphacheck[i]] - keys = (['e{}'.format(i) for i in index_set] - + ['f{}'.format(i) for i in index_set] - + ['h{}'.format(i) for i in index_set]) + keys = ['e{}'.format(i) for i in index_set] + ['f{}'.format(i) for i in index_set] + ['h{}'.format(i) for i in index_set] else: for i in index_set: al = alpha[i] ret[al] = B[al] ret[-al] = B[-al] ret[alphacheck[i]] = B[alphacheck[i]] - keys = ([alpha[i] for i in index_set] - + [-alpha[i] for i in index_set] - + [alphacheck[i] for i in index_set]) + keys = [alpha[i] for i in index_set] + [-alpha[i] for i in index_set] + [alphacheck[i] for i in index_set] return Family(keys, ret.__getitem__) @@ -2239,6 +2205,7 @@ def killing_form_matrix(self): B = self.basis() Q = self._Q from sage.matrix.constructor import matrix + ret = matrix.zero(self.base_ring(), self._M.rank()) keys = list(B.keys()) for i, a in enumerate(keys): @@ -2307,6 +2274,7 @@ class LieAlgebraChevalleyBasis_simply_laced(LieAlgebraChevalleyBasis): sage: L.e(1).bracket(L.e(2)) -E[alpha[1] + alpha[2]] """ + def __init__(self, R, cartan_type, epsilon): """ Initialize ``self``. @@ -2347,29 +2315,24 @@ def _construct_struct_coeffs(self, R, p_roots): s_coeffs[(ac, -r)] = {-r: -c} # [e_r, f_r] - s_coeffs[(r, -r)] = {alphacheck[j]: c - for j, c in r.associated_coroot()} + s_coeffs[(r, -r)] = {alphacheck[j]: c for j, c in r.associated_coroot()} # [e_r, e_s] and [e_r, f_s] with r != +/-s # We assume s is positive, as otherwise we negate # both r and s and the resulting coefficient - for j, s in enumerate(p_roots[i+1:], start=i+1): + for j, s in enumerate(p_roots[i + 1 :], start=i + 1): if r + s in p_roots_set: - coeff = R.prod((-1)**(ca*cb) if (ii, jj) in self._epsilon or ii == jj else 1 - for ii, ca in r._monomial_coefficients.items() - for jj, cb in s._monomial_coefficients.items()) - s_coeffs[r, s] = {r+s: coeff} - s_coeffs[-r, -s] = {-r-s: -coeff} + coeff = R.prod((-1) ** (ca * cb) if (ii, jj) in self._epsilon or ii == jj else 1 for ii, ca in r._monomial_coefficients.items() for jj, cb in s._monomial_coefficients.items()) + s_coeffs[r, s] = {r + s: coeff} + s_coeffs[-r, -s] = {-r - s: -coeff} if r - s in p_roots_set or s - r in p_roots_set: - coeff = R.prod((-1)**(ca*cb) if (ii, jj) in self._epsilon or ii == jj else 1 - for ii, ca in r._monomial_coefficients.items() - for jj, cb in s._monomial_coefficients.items()) + coeff = R.prod((-1) ** (ca * cb) if (ii, jj) in self._epsilon or ii == jj else 1 for ii, ca in r._monomial_coefficients.items() for jj, cb in s._monomial_coefficients.items()) if r - s in p_roots_set: - s_coeffs[r, -s] = {r-s: -coeff} - s_coeffs[-r, s] = {s-r: coeff} + s_coeffs[r, -s] = {r - s: -coeff} + s_coeffs[-r, s] = {s - r: coeff} else: - s_coeffs[r, -s] = {r-s: coeff} - s_coeffs[-r, s] = {s-r: -coeff} + s_coeffs[r, -s] = {r - s: coeff} + s_coeffs[-r, s] = {s - r: -coeff} return s_coeffs @@ -2418,7 +2381,7 @@ def asymmetry_function(self): roots = set(self._Q.roots()) al = self._Q.simple_roots() - ep = {(r, r): (-1)**(r.scalar(r.associated_coroot()) // 2) for r in roots} + ep = {(r, r): (-1) ** (r.scalar(r.associated_coroot()) // 2) for r in roots} next_level = set() for i in self._Q.index_set(): # ep[i,0] = ep[i,-j] * ep[i,j] = ep[i,0]^2 @@ -2507,8 +2470,8 @@ def _test_structure_coeffs(self, **options): if r + s not in roots: continue x = B[r].bracket(B[s]) - tester.assertEqual(list(x.support()), [r+s], f"[{r}, {s}] = {x} is not a root vector") + tester.assertEqual(list(x.support()), [r + s], f"[{r}, {s}] = {x} is not a root vector") sign = 1 if (r in p_roots) == (s in p_roots) else -1 if (r + s) not in p_roots: sign = -sign - tester.assertEqual(x[r+s], sign * ep[r, s], f"[{r}, {s}] = {x[r+s]} != {sign*ep[r,s]}") + tester.assertEqual(x[r + s], sign * ep[r, s], f"[{r}, {s}] = {x[r+s]} != {sign*ep[r,s]}") diff --git a/src/sage/algebras/lie_algebras/examples.py b/src/sage/algebras/lie_algebras/examples.py index 28b7446f2ff..ce2c683b1ce 100644 --- a/src/sage/algebras/lie_algebras/examples.py +++ b/src/sage/algebras/lie_algebras/examples.py @@ -21,6 +21,7 @@ - Travis Scrimshaw (07-15-2013): Initial implementation """ + # **************************************************************************** # Copyright (C) 2013-2017 Travis Scrimshaw # @@ -94,7 +95,8 @@ def three_dimensional(R, a, b, c, d, names=['X', 'Y', 'Z']): Y = names[1] Z = names[2] from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients - s_coeff = {(X,Y): {Z:a, Y:d}, (Y,Z): {X:b}, (Z,X): {Y:c, Z:d}} + + s_coeff = {(X, Y): {Z: a, Y: d}, (Y, Z): {X: b}, (Z, X): {Y: c, Z: d}} return LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names)) @@ -158,6 +160,7 @@ def three_dimensional_by_rank(R, n, a=None, names=['X', 'Y', 'Z']): if n == 0: from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra + return AbelianLieAlgebra(R, names=names) if n == 1: @@ -172,13 +175,14 @@ def three_dimensional_by_rank(R, n, a=None, names=['X', 'Y', 'Z']): Y = names[1] Z = names[2] from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients + if a == 0: - s_coeff = {(X,Y): {Y:R.one()}, (X,Z): {Y:R(a)}} + s_coeff = {(X, Y): {Y: R.one()}, (X, Z): {Y: R(a)}} # Why use R(a) here if R == 0 ? Also this has rank 1. L = LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names)) L.rename("Degenerate Lie algebra of dimension 3 and rank 2 over {}".format(R)) else: - s_coeff = {(X,Y): {Y:R.one()}, (X,Z): {Y:R.one(), Z:R.one()}} + s_coeff = {(X, Y): {Y: R.one()}, (X, Z): {Y: R.one(), Z: R.one()}} # a doesn't appear here :/ L = LieAlgebraWithStructureCoefficients(R, s_coeff, tuple(names)) L.rename("Lie algebra of dimension 3 and rank 2 with parameter {} over {}".format(a, R)) @@ -187,6 +191,7 @@ def three_dimensional_by_rank(R, n, a=None, names=['X', 'Y', 'Z']): if n == 3: # return sl(R, 2) from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients + E = names[0] F = names[1] H = names[2] @@ -222,15 +227,18 @@ def affine_transformations_line(R, names=['X', 'Y'], representation='bracket'): names = tuple(names) if representation == 'matrix': from sage.matrix.matrix_space import MatrixSpace + MS = MatrixSpace(R, 2, sparse=True) one = R.one() - gens = tuple(MS({(0,i):one}) for i in range(2)) + gens = tuple(MS({(0, i): one}) for i in range(2)) from sage.algebras.lie_algebras.lie_algebra import LieAlgebraFromAssociative + return LieAlgebraFromAssociative(MS, gens, names=names) X = names[0] Y = names[1] from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients - s_coeff = {(X,Y): {Y:R.one()}} + + s_coeff = {(X, Y): {Y: R.one()}} L = LieAlgebraWithStructureCoefficients(R, s_coeff, names=names) L.rename("Lie algebra of affine transformations of a line over {}".format(R)) return L @@ -255,12 +263,13 @@ def abelian(R, names=None, index_set=None): index_set = names names = None from sage.rings.infinity import infinity - if (index_set is not None - and not isinstance(index_set, (list, tuple)) - and index_set.cardinality() == infinity): + + if index_set is not None and not isinstance(index_set, (list, tuple)) and index_set.cardinality() == infinity: from sage.algebras.lie_algebras.abelian import InfiniteDimensionalAbelianLieAlgebra + return InfiniteDimensionalAbelianLieAlgebra(R, index_set=index_set) from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra + return AbelianLieAlgebra(R, names=names, index_set=index_set) @@ -284,13 +293,17 @@ def Heisenberg(R, n, representation='structure'): Heisenberg algebra of rank 3 over Rational Field """ from sage.rings.infinity import infinity + if n == infinity: from sage.algebras.lie_algebras.heisenberg import InfiniteHeisenbergAlgebra + return InfiniteHeisenbergAlgebra(R) if representation == "matrix": from sage.algebras.lie_algebras.heisenberg import HeisenbergAlgebra_matrix + return HeisenbergAlgebra_matrix(R, n) from sage.algebras.lie_algebras.heisenberg import HeisenbergAlgebra + return HeisenbergAlgebra(R, n) @@ -310,6 +323,7 @@ def regular_vector_fields(R): The Lie algebra of regular vector fields over Rational Field """ from sage.algebras.lie_algebras.virasoro import LieAlgebraRegularVectorFields + return LieAlgebraRegularVectorFields(R) @@ -331,6 +345,7 @@ def pwitt(R, p): The 5-Witt Lie algebra over Finite Field of size 5 """ from sage.algebras.lie_algebras.virasoro import WittLieAlgebra_charp + return WittLieAlgebra_charp(R, p) @@ -364,12 +379,13 @@ def upper_triangular_matrices(R, n): """ from sage.matrix.matrix_space import MatrixSpace from sage.algebras.lie_algebras.lie_algebra import LieAlgebraFromAssociative + MS = MatrixSpace(R, n, sparse=True) one = R.one() - names = tuple('n{}'.format(i) for i in range(n-1)) + names = tuple('n{}'.format(i) for i in range(n - 1)) names += tuple('t{}'.format(i) for i in range(n)) - gens = [MS({(i,i+1):one}) for i in range(n-1)] - gens += [MS({(i,i):one}) for i in range(n)] + gens = [MS({(i, i + 1): one}) for i in range(n - 1)] + gens += [MS({(i, i): one}) for i in range(n)] L = LieAlgebraFromAssociative(MS, gens, names=names) L.rename("Lie algebra of {}-dimensional upper triangular matrices over {}".format(n, L.base_ring())) return L @@ -408,14 +424,16 @@ def strictly_upper_triangular_matrices(R, n): """ from sage.matrix.matrix_space import MatrixSpace from sage.algebras.lie_algebras.lie_algebra import LieAlgebraFromAssociative + MS = MatrixSpace(R, n, sparse=True) one = R.one() - names = tuple('n{}'.format(i) for i in range(n-1)) - gens = tuple(MS({(i,i+1): one}) for i in range(n-1)) + names = tuple('n{}'.format(i) for i in range(n - 1)) + gens = tuple(MS({(i, i + 1): one}) for i in range(n - 1)) L = LieAlgebraFromAssociative(MS, gens, names=names) L.rename("Lie algebra of {}-dimensional strictly upper triangular matrices over {}".format(n, L.base_ring())) return L + ##################################################################### # Classical Lie algebras @@ -465,9 +483,11 @@ def sl(R, n, representation='bracket'): """ if representation == 'bracket': from sage.algebras.lie_algebras.classical_lie_algebra import LieAlgebraChevalleyBasis - return LieAlgebraChevalleyBasis(R, ['A', n-1]) + + return LieAlgebraChevalleyBasis(R, ['A', n - 1]) if representation == 'matrix': from sage.algebras.lie_algebras.classical_lie_algebra import sl as sl_matrix + return sl_matrix(R, n) raise ValueError("invalid representation") @@ -514,11 +534,13 @@ def su(R, n, representation='matrix'): """ if representation == 'bracket': from sage.algebras.lie_algebras.classical_lie_algebra import LieAlgebraChevalleyBasis - return LieAlgebraChevalleyBasis(R, ['A', n-1]) + + return LieAlgebraChevalleyBasis(R, ['A', n - 1]) if representation == 'matrix': from sage.algebras.lie_algebras.classical_lie_algebra import MatrixCompactRealForm from sage.combinat.root_system.cartan_type import CartanType - return MatrixCompactRealForm(R, CartanType(['A', n-1])) + + return MatrixCompactRealForm(R, CartanType(['A', n - 1])) raise ValueError("invalid representation") @@ -591,11 +613,13 @@ def so(R, n, representation='bracket'): """ if representation == 'bracket': from sage.algebras.lie_algebras.classical_lie_algebra import LieAlgebraChevalleyBasis + if n % 2 == 0: - return LieAlgebraChevalleyBasis(R, ['D', n//2]) - return LieAlgebraChevalleyBasis(R, ['B', (n-1)//2]) + return LieAlgebraChevalleyBasis(R, ['D', n // 2]) + return LieAlgebraChevalleyBasis(R, ['B', (n - 1) // 2]) if representation == 'matrix': from sage.algebras.lie_algebras.classical_lie_algebra import so as so_matrix + return so_matrix(R, n) raise ValueError("invalid representation") @@ -673,8 +697,10 @@ def sp(R, n, representation='bracket'): raise ValueError("n must be even") if representation == 'bracket': from sage.algebras.lie_algebras.classical_lie_algebra import LieAlgebraChevalleyBasis - return LieAlgebraChevalleyBasis(R, ['C', n//2]) + + return LieAlgebraChevalleyBasis(R, ['C', n // 2]) if representation == 'matrix': from sage.algebras.lie_algebras.classical_lie_algebra import sp as sp_matrix + return sp_matrix(R, n) raise ValueError("invalid representation") diff --git a/src/sage/algebras/lie_algebras/free_lie_algebra.py b/src/sage/algebras/lie_algebras/free_lie_algebra.py index 20b76e15b57..d7decf0c001 100644 --- a/src/sage/algebras/lie_algebras/free_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/free_lie_algebra.py @@ -26,18 +26,14 @@ from sage.misc.bindable_class import BindableClass from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.indexed_generators import (IndexedGenerators, - standardize_names_index_set) +from sage.structure.indexed_generators import IndexedGenerators, standardize_names_index_set from sage.categories.realizations import Realizations, Category_realization_of_parent from sage.categories.lie_algebras import LieAlgebras from sage.categories.homset import Hom from sage.algebras.free_algebra import FreeAlgebra from sage.algebras.lie_algebras.lie_algebra import FinitelyGeneratedLieAlgebra -from sage.algebras.lie_algebras.lie_algebra_element import (LieGenerator, - GradedLieBracket, - LyndonBracket, - FreeLieAlgebraElement) +from sage.algebras.lie_algebras.lie_algebra_element import LieGenerator, GradedLieBracket, LyndonBracket, FreeLieAlgebraElement from sage.algebras.lie_algebras.morphism import LieAlgebraHomomorphism_im_gens from sage.misc.superseded import experimental_warning @@ -48,6 +44,7 @@ class FreeLieBasis_abstract(FinitelyGeneratedLieAlgebra, IndexedGenerators, Bind """ Abstract base class for all (stratified) bases of a free Lie algebra. """ + def __init__(self, lie, basis_name): """ Initialize ``self``. @@ -61,9 +58,7 @@ def __init__(self, lie, basis_name): self._basis_name = basis_name IndexedGenerators.__init__(self, lie._indices, prefix='', bracket=False) cat = FreeLieAlgebraBases(lie).Graded().Stratified() - FinitelyGeneratedLieAlgebra.__init__(self, lie.base_ring(), - names=lie._names, index_set=lie._indices, - category=cat) + FinitelyGeneratedLieAlgebra.__init__(self, lie.base_ring(), names=lie._names, index_set=lie._indices, category=cat) def _repr_(self): """ @@ -129,6 +124,7 @@ def _ascii_art_term(self, x): [x, y] """ from sage.typeset.ascii_art import ascii_art + return ascii_art(x) def _unicode_art_term(self, x): @@ -147,6 +143,7 @@ def _unicode_art_term(self, x): [x, y] """ from sage.typeset.unicode_art import unicode_art + return unicode_art(x) def _element_constructor_(self, x): @@ -230,6 +227,7 @@ def basis(self): from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.positive_integers import PositiveIntegers from sage.sets.family import Family + return DisjointUnionEnumeratedSets(Family(PositiveIntegers(), self.graded_basis, name="graded basis")) def degree_on_basis(self, x): @@ -290,9 +288,10 @@ def graded_dimension(self, k): if k == 0: return ZZ.zero() from sage.arith.misc import moebius + s = len(self.lie_algebra_generators()) k = ZZ(k) # Make sure we have something that is in ZZ - return ZZ.sum(moebius(d) * s**(k // d) for d in k.divisors()) // k + return ZZ.sum(moebius(d) * s ** (k // d) for d in k.divisors()) // k @abstract_method def graded_basis(self, k): @@ -374,6 +373,7 @@ class FreeLieAlgebra(Parent, UniqueRepresentation): sage: all(H(Lyn(x)) == x for x in H.graded_basis(5)) True """ + @staticmethod def __classcall_private__(cls, R, names=None, index_set=None): """ @@ -401,8 +401,7 @@ def __init__(self, R, names, index_set): """ self._names = names self._indices = index_set - Parent.__init__(self, base=R, names=names, - category=LieAlgebras(R).WithRealizations()) + Parent.__init__(self, base=R, names=names, category=LieAlgebras(R).WithRealizations()) def _repr_(self): """ @@ -497,6 +496,7 @@ class Hall(FreeLieBasis_abstract): :class:`~sage.algebras.lie_algebras.lie_algebra_element.GradedLieBracket` (in degree `> 1`). """ + def __init__(self, lie): r""" EXAMPLES:: @@ -537,20 +537,15 @@ def _generate_hall_set(self, k): if k <= 0: return () if k == 1: - return tuple(map(LieGenerator, self.variable_names(), - range(len(self.variable_names())))) + return tuple(map(LieGenerator, self.variable_names(), range(len(self.variable_names())))) if k == 2: basis = self._generate_hall_set(1) - ret = [GradedLieBracket(a, b, 2) for i, a in enumerate(basis) - for b in basis[i+1:]] + ret = [GradedLieBracket(a, b, 2) for i, a in enumerate(basis) for b in basis[i + 1 :]] return tuple(ret) # We don't want to do the middle when we're even, so we add 1 and # take the floor after dividing by 2. - ret = [GradedLieBracket(a, b, k) for i in range(1, (k+1) // 2) - for a in self._generate_hall_set(i) - for b in self._generate_hall_set(k-i) - if b._left <= a] + ret = [GradedLieBracket(a, b, k) for i in range(1, (k + 1) // 2) for a in self._generate_hall_set(i) for b in self._generate_hall_set(k - i) if b._left <= a] # Special case for when k = 4, we get the pairs [[a, b], [x, y]] # where a,b,x,y are all grade 1 elements. Thus if we take @@ -558,13 +553,13 @@ def _generate_hall_set(self, k): if k == 4: basis = self._generate_hall_set(2) for i, a in enumerate(basis): - for b in basis[i+1:]: + for b in basis[i + 1 :]: ret.append(GradedLieBracket(a, b, k)) # Do the middle case when we are even and k > 4 elif k % 2 == 0: basis = self._generate_hall_set(k // 2) # grade >= 2 for i, a in enumerate(basis): - for b in basis[i+1:]: + for b in basis[i + 1 :]: if b._left <= a: ret.append(GradedLieBracket(a, b, k)) @@ -604,8 +599,7 @@ def graded_basis(self, k): [3, 3, 8, 18, 48, 116, 312, 810, 2184, 5880] """ one = self.base_ring().one() - return tuple([self.element_class(self, {x: one}) - for x in self._generate_hall_set(k)]) + return tuple([self.element_class(self, {x: one}) for x in self._generate_hall_set(k)]) # We require l < r because it is a requirement and to make the # caching more efficient @@ -700,6 +694,7 @@ class Lyndon(FreeLieBasis_abstract): sage: y.bracket(z) -[z, y] """ + def __init__(self, lie): r""" EXAMPLES:: @@ -826,9 +821,7 @@ def _standard_bracket(self, lw): for i in range(1, len(lw)): if is_lyndon(lw[i:]): - return LyndonBracket(self._standard_bracket(lw[:i]), - self._standard_bracket(lw[i:]), - len(lw)) + return LyndonBracket(self._standard_bracket(lw[:i]), self._standard_bracket(lw[i:]), len(lw)) @cached_method def graded_basis(self, k): @@ -878,10 +871,10 @@ def graded_basis(self, k): names = self.variable_names() one = self.base_ring().one() if k == 1: - return tuple(self.element_class(self, {LieGenerator(n, k): one}) - for k, n in enumerate(names)) + return tuple(self.element_class(self, {LieGenerator(n, k): one}) for k, n in enumerate(names)) from sage.combinat.combinat_cython import lyndon_word_iterator + n = len(self._indices) ret = [] for lw in lyndon_word_iterator(n, k): @@ -908,10 +901,12 @@ def pbw_basis(self, **kwds): ####################################### # Category for the realizations + class FreeLieAlgebraBases(Category_realization_of_parent): r""" The category of bases of a free Lie algebra. """ + def __init__(self, base): r""" Initialize the bases of a free Lie algebra. diff --git a/src/sage/algebras/lie_algebras/heisenberg.py b/src/sage/algebras/lie_algebras/heisenberg.py index 377ac303465..d3ea37dee08 100644 --- a/src/sage/algebras/lie_algebras/heisenberg.py +++ b/src/sage/algebras/lie_algebras/heisenberg.py @@ -19,10 +19,8 @@ from sage.misc.cachefunc import cached_method from sage.structure.indexed_generators import IndexedGenerators -from sage.algebras.lie_algebras.lie_algebra import (LieAlgebraFromAssociative, - LieAlgebraWithGenerators) -from sage.algebras.lie_algebras.lie_algebra_element import (LieAlgebraElement, - LieAlgebraMatrixWrapper) +from sage.algebras.lie_algebras.lie_algebra import LieAlgebraFromAssociative, LieAlgebraWithGenerators +from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement, LieAlgebraMatrixWrapper from sage.categories.lie_algebras import LieAlgebras from sage.categories.cartesian_product import cartesian_product from sage.matrix.matrix_space import MatrixSpace @@ -37,6 +35,7 @@ class HeisenbergAlgebra_abstract(IndexedGenerators): """ The common methods for the (non-matrix) Heisenberg algebras. """ + def __init__(self, I): """ Initialize ``self``. @@ -45,8 +44,7 @@ def __init__(self, I): sage: L = lie_algebras.Heisenberg(QQ, oo) # indirect doctest """ - IndexedGenerators.__init__(self, I, prefix='', bracket=False, - latex_bracket=False, string_quotes=False) + IndexedGenerators.__init__(self, I, prefix='', bracket=False, latex_bracket=False, string_quotes=False) def p(self, i): """ @@ -102,7 +100,7 @@ def bracket_on_basis(self, x, y): sage: H.bracket_on_basis(p1, q1) z """ - if y == 'z': # No need to test for x == 'z' since x < y is assumed. + if y == 'z': # No need to test for x == 'z' since x < y is assumed. return self.zero() if x[0] == 'p' and y[0] == 'q' and x[1] == y[1]: return self.z() @@ -137,6 +135,7 @@ def _ascii_art_term(self, m): p2 + 2*p3 + 3*q1 + 4*q2 + 5*q3 + 6*z """ from sage.typeset.ascii_art import ascii_art + return ascii_art(m) def _latex_term(self, m): @@ -155,7 +154,7 @@ def _latex_term(self, m): """ if len(m) == 1: return m - return "%s_{%s}" % (m[0], m[1:]) # else it is of length at least 2 + return "%s_{%s}" % (m[0], m[1:]) # else it is of length at least 2 def _unicode_art_term(self, m): r""" @@ -172,9 +171,10 @@ def _unicode_art_term(self, m): p₁₀ """ from sage.typeset.unicode_art import unicode_art, unicode_subscript + if len(m) == 1: return unicode_art(m) - return unicode_art(str(m[0]) + unicode_subscript(m[1:])) # else it is of length at least 2 + return unicode_art(str(m[0]) + unicode_subscript(m[1:])) # else it is of length at least 2 def step(self): r""" @@ -200,6 +200,7 @@ class HeisenbergAlgebra_fd: """ Common methods for finite-dimensional Heisenberg algebras. """ + def __init__(self, n): """ Initialize ``self``. @@ -279,10 +280,10 @@ def lie_algebra_generators(self): """ if self._n == 0: return Family(['z'], lambda i: self.z()) - k = ['p%s' % i for i in range(1, self._n+1)] - k += ['q%s' % i for i in range(1, self._n+1)] + k = ['p%s' % i for i in range(1, self._n + 1)] + k += ['q%s' % i for i in range(1, self._n + 1)] d = {} - for i in range(1, self._n+1): + for i in range(1, self._n + 1): d['p%s' % i] = self.p(i) d['q%s' % i] = self.q(i) return Family(k, lambda i: d[i]) @@ -299,7 +300,7 @@ def basis(self): Finite family {'p1': p1, 'q1': q1, 'z': z} """ d = {} - for i in range(1, self._n+1): + for i in range(1, self._n + 1): d['p%s' % i] = self.p(i) d['q%s' % i] = self.q(i) d['z'] = self.z() @@ -345,12 +346,11 @@ def _coerce_map_from_(self, H): if isinstance(H, HeisenbergAlgebra_fd): if H._n <= self._n and self.base_ring().has_coerce_map_from(H.base_ring()): return H.module_morphism(lambda i: self.basis()[i], codomain=self) - return None # Otherwise no coercion + return None # Otherwise no coercion return super()._coerce_map_from_(H) -class HeisenbergAlgebra(HeisenbergAlgebra_fd, HeisenbergAlgebra_abstract, - LieAlgebraWithGenerators): +class HeisenbergAlgebra(HeisenbergAlgebra_fd, HeisenbergAlgebra_abstract, LieAlgebraWithGenerators): r""" A Heisenberg algebra defined using structure coefficients. @@ -391,6 +391,7 @@ class HeisenbergAlgebra(HeisenbergAlgebra_fd, HeisenbergAlgebra_abstract, sage: L = lie_algebras.Heisenberg(QQ, 2) """ + def __init__(self, R, n): """ Initialize ``self``. @@ -403,11 +404,8 @@ def __init__(self, R, n): sage: TestSuite(L).run() """ HeisenbergAlgebra_fd.__init__(self, n) - names = tuple(['p%s' % i for i in range(1,n+1)] - + ['q%s' % i for i in range(1,n+1)] - + ['z']) - LieAlgebraWithGenerators.__init__(self, R, names=names, index_set=names, - category=LieAlgebras(R).Nilpotent().FiniteDimensional().WithBasis()) + names = tuple(['p%s' % i for i in range(1, n + 1)] + ['q%s' % i for i in range(1, n + 1)] + ['z']) + LieAlgebraWithGenerators.__init__(self, R, names=names, index_set=names, category=LieAlgebras(R).Nilpotent().FiniteDimensional().WithBasis()) HeisenbergAlgebra_abstract.__init__(self, names) def _repr_(self): @@ -430,6 +428,7 @@ class InfiniteHeisenbergAlgebra(HeisenbergAlgebra_abstract, LieAlgebraWithGenera other words, this is the Heisenberg algebra of rank `\infty`. See :class:`HeisenbergAlgebra` for more information. """ + def __init__(self, R): """ Initialize ``self``. @@ -443,7 +442,7 @@ def __init__(self, R): sage: L.q(1).bracket(L.p(1)) == -L.z() True """ - S = cartesian_product([PositiveIntegers(), ['p','q']]) + S = cartesian_product([PositiveIntegers(), ['p', 'q']]) cat = LieAlgebras(R).Nilpotent().WithBasis() LieAlgebraWithGenerators.__init__(self, R, index_set=S, category=cat) HeisenbergAlgebra_abstract.__init__(self, S) @@ -483,8 +482,7 @@ def lie_algebra_generators(self): Lazy family (generator map(i))_{i in The Cartesian product of (Positive integers, {'p', 'q'})} """ - return Family(self._indices, lambda x: self.monomial(x[1] + str(x[0])), - name='generator map') + return Family(self._indices, lambda x: self.monomial(x[1] + str(x[0])), name='generator map') def basis(self): """ @@ -508,6 +506,7 @@ def basis_elt(x): if isinstance(x, str): return self.monomial(x) return self.monomial(x[1] + str(x[0])) + return Family(I, basis_elt, name="basis map") def _from_fd_on_basis(self, i): @@ -569,7 +568,7 @@ def _coerce_map_from_(self, H): return None # Otherwise no coercion if isinstance(H, InfiniteHeisenbergAlgebra): if self.base_ring().has_coerce_map_from(H.base_ring()): - return lambda C,x: self._from_dict(x._monomial_coefficients, coerce=True) + return lambda C, x: self._from_dict(x._monomial_coefficients, coerce=True) return None # Otherwise no coercion return super()._coerce_map_from_(H) @@ -577,6 +576,7 @@ def _coerce_map_from_(self, H): ####################################################### # Finite rank Heisenberg algebra using matrices + class HeisenbergAlgebra_matrix(HeisenbergAlgebra_fd, LieAlgebraFromAssociative): r""" A Heisenberg algebra represented using matrices. @@ -691,6 +691,7 @@ class HeisenbergAlgebra_matrix(HeisenbergAlgebra_fd, LieAlgebraFromAssociative): Finite family {'z': [0 1] [0 0]} """ + def __init__(self, R, n): """ Initialize ``self``. @@ -701,16 +702,15 @@ def __init__(self, R, n): sage: TestSuite(L).run() """ HeisenbergAlgebra_fd.__init__(self, n) - MS = MatrixSpace(R, n+2, sparse=True) + MS = MatrixSpace(R, n + 2, sparse=True) one = R.one() - p = tuple(MS({(0,i): one}) for i in range(1, n+1)) - q = tuple(MS({(i,n+1): one}) for i in range(1, n+1)) - z = (MS({(0,n+1): one}),) - names = tuple('p%s' % i for i in range(1,n+1)) - names = names + tuple('q%s' % i for i in range(1,n+1)) + ('z',) + p = tuple(MS({(0, i): one}) for i in range(1, n + 1)) + q = tuple(MS({(i, n + 1): one}) for i in range(1, n + 1)) + z = (MS({(0, n + 1): one}),) + names = tuple('p%s' % i for i in range(1, n + 1)) + names = names + tuple('q%s' % i for i in range(1, n + 1)) + ('z',) cat = LieAlgebras(R).Nilpotent().FiniteDimensional().WithBasis() - LieAlgebraFromAssociative.__init__(self, MS, p + q + z, names=names, - index_set=names, category=cat) + LieAlgebraFromAssociative.__init__(self, MS, p + q + z, names=names, index_set=names, category=cat) def _repr_(self): """ @@ -808,11 +808,11 @@ def monomial_coefficients(self, copy=True): n = self.parent()._n for i, mon in enumerate(self.parent().basis().keys()): if i < n: - entry = self[0, i+1] + entry = self[0, i + 1] elif i < 2 * n: - entry = self[i-n+1, n+1] + entry = self[i - n + 1, n + 1] else: - entry = self[0, n+1] + entry = self[0, n + 1] if entry: d[mon] = entry return d diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 4a77475976b..3613930a86a 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -5,6 +5,7 @@ - Travis Scrimshaw (2013-05-03): Initial version """ + # **************************************************************************** # Copyright (C) 2013-2017 Travis Scrimshaw # @@ -27,8 +28,7 @@ from sage.categories.morphism import SetMorphism from sage.categories.homset import Hom -from sage.algebras.lie_algebras.lie_algebra_element import (LieAlgebraElementWrapper, - LieAlgebraMatrixWrapper) +from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElementWrapper, LieAlgebraMatrixWrapper from sage.rings.integer_ring import ZZ from sage.matrix.matrix_space import MatrixSpace from sage.sets.family import Family, AbstractFamily @@ -358,12 +358,11 @@ class LieAlgebra(Parent, UniqueRepresentation): # IndexedGenerators): - [Ka1990]_ Victor Kac, *Infinite dimensional Lie algebras*. - :wikipedia:`Lie_algebra` """ + # This works because it is an abstract base class and this # __classcall_private__ will only be called when calling LieAlgebra @staticmethod - def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, - index_set=None, abelian=False, nilpotent=False, - category=None, **kwds): + def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, index_set=None, abelian=False, nilpotent=False, category=None, **kwds): """ Select the correct parent based upon input. @@ -380,8 +379,7 @@ def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, assoc = kwds.get("associative", None) if assoc is not None: - return LieAlgebraFromAssociative(assoc, names=names, index_set=index_set, - category=category) + return LieAlgebraFromAssociative(assoc, names=names, index_set=index_set, category=category) # Parse input as a Cartan type # ----- @@ -389,22 +387,26 @@ def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, ct = kwds.pop("cartan_type", None) if ct is not None: from sage.combinat.root_system.cartan_type import CartanType + ct = CartanType(ct) if ct.is_affine(): from sage.algebras.lie_algebras.affine_lie_algebra import AffineLieAlgebra - return AffineLieAlgebra(R, cartan_type=ct, - kac_moody=kwds.get("kac_moody", True)) + + return AffineLieAlgebra(R, cartan_type=ct, kac_moody=kwds.get("kac_moody", True)) if not ct.is_finite(): raise NotImplementedError("non-finite types are not implemented yet, see trac #14901 for details") rep = kwds.pop("representation", "bracket") if rep == 'bracket': from sage.algebras.lie_algebras.classical_lie_algebra import LieAlgebraChevalleyBasis + return LieAlgebraChevalleyBasis(R, ct, **kwds) if rep == 'matrix': from sage.algebras.lie_algebras.classical_lie_algebra import ClassicalMatrixLieAlgebra + return ClassicalMatrixLieAlgebra(R, ct, **kwds) if rep == 'compact real': from sage.algebras.lie_algebras.classical_lie_algebra import MatrixCompactRealForm + return MatrixCompactRealForm(R, ct, **kwds) raise ValueError("invalid representation") @@ -415,9 +417,8 @@ def __classcall_private__(cls, R=None, arg0=None, arg1=None, names=None, raise ValueError("invalid arguments") def check_assoc(A): - return (isinstance(A, MatrixSpace) - or A in Rings() - or A in Algebras(R).Associative()) + return isinstance(A, MatrixSpace) or A in Rings() or A in Algebras(R).Associative() + if arg0 in ZZ or check_assoc(arg1): # Check if we need to swap the arguments arg0, arg1 = arg1, arg0 @@ -428,6 +429,7 @@ def check_assoc(A): if isinstance(arg0, dict): if not arg0: from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra + return AbelianLieAlgebra(R, names, index_set) if isinstance(next(iter(arg0.keys())), (list, tuple)): # We assume it is some structure coefficients @@ -449,12 +451,12 @@ def check_assoc(A): # Assume it is some structure coefficients if nilpotent or (category is not None and category.is_subcategory(LieAlgebras(R).Nilpotent())): from sage.algebras.lie_algebras.nilpotent_lie_algebra import NilpotentLieAlgebra_dense - return NilpotentLieAlgebra_dense(R, arg1, names, index_set, - category=category, **kwds) + + return NilpotentLieAlgebra_dense(R, arg1, names, index_set, category=category, **kwds) from sage.algebras.lie_algebras.structure_coefficients import LieAlgebraWithStructureCoefficients - return LieAlgebraWithStructureCoefficients(R, arg1, names, index_set, - category=category, **kwds) + + return LieAlgebraWithStructureCoefficients(R, arg1, names, index_set, category=category, **kwds) # Otherwise it must be either a free (nilpotent) or abelian Lie algebra @@ -463,11 +465,11 @@ def check_assoc(A): if step: # Parse input as a free nilpotent Lie algebra from sage.algebras.lie_algebras.nilpotent_lie_algebra import FreeNilpotentLieAlgebra + del kwds["step"] return FreeNilpotentLieAlgebra(R, arg1, step, names=names, **kwds) if nilpotent: - raise ValueError("free nilpotent Lie algebras must have a" - " 'step' parameter given") + raise ValueError("free nilpotent Lie algebras must have a" " 'step' parameter given") if isinstance(arg0, str): names = arg0 @@ -477,19 +479,16 @@ def check_assoc(A): if isinstance(names, str): names = tuple(names.split(',')) if arg1 != 1 and len(names) == 1: - names = tuple('{}{}'.format(names[0], i) - for i in range(arg1)) + names = tuple('{}{}'.format(names[0], i) for i in range(arg1)) if arg1 != len(names): - raise ValueError("the number of names must equal the" - " number of generators") + raise ValueError("the number of names must equal the" " number of generators") if "step" in kwds or nilpotent: - raise ValueError("free nilpotent Lie algebras must have both" - " a number of generators and step parameters" - " specified") + raise ValueError("free nilpotent Lie algebras must have both" " a number of generators and step parameters" " specified") if abelian: from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra + return AbelianLieAlgebra(R, names, index_set) # Otherwise it is the free Lie algebra @@ -499,6 +498,7 @@ def check_assoc(A): # free (associative unital) algebra # TODO: Change this to accept an index set once FreeAlgebra accepts one from sage.algebras.free_algebra import FreeAlgebra + F = FreeAlgebra(R, names) if index_set is None: index_set = F.variable_names() @@ -507,6 +507,7 @@ def check_assoc(A): return LieAlgebraFromAssociative(F, F.gens(), names=names, index_set=index_set) from sage.algebras.lie_algebras.free_lie_algebra import FreeLieAlgebra + return FreeLieAlgebra(R, names, index_set) def __init__(self, R, names=None, category=None): @@ -698,6 +699,7 @@ def _Hom_(self, Y, category): if Y not in cat: raise TypeError(f"{Y} is not a Lie algebra") from sage.algebras.lie_algebras.morphism import LieAlgebraHomset + return LieAlgebraHomset(self, Y, category=category) @cached_method @@ -802,6 +804,7 @@ class LieAlgebraWithGenerators(LieAlgebra): """ A Lie algebra with distinguished generators. """ + def __init__(self, R, names=None, index_set=None, category=None, prefix='L', **kwds): """ The Lie algebra. @@ -888,6 +891,7 @@ class FinitelyGeneratedLieAlgebra(LieAlgebraWithGenerators): r""" A finitely generated Lie algebra. """ + def __init__(self, R, names=None, index_set=None, category=None): """ Initialize ``self``. @@ -922,10 +926,8 @@ def _repr_(self) -> str: Lie algebra on 2 generators (x, y) over Rational Field """ if self.__ngens == 1: - return "Lie algebra on the generator {} over {}".format( - self.gen(0), self.base_ring()) - return "Lie algebra on {} generators {} over {}".format( - self.__ngens, self.gens(), self.base_ring()) + return "Lie algebra on the generator {} over {}".format(self.gen(0), self.base_ring()) + return "Lie algebra on {} generators {} over {}".format(self.__ngens, self.gens(), self.base_ring()) @lazy_attribute def _ordered_indices(self): @@ -957,6 +959,7 @@ class InfinitelyGeneratedLieAlgebra(LieAlgebraWithGenerators): r""" An infinitely generated Lie algebra. """ + def _an_element_(self): """ Return an element of ``self``. @@ -969,6 +972,7 @@ def _an_element_(self): """ return self.lie_algebra_generators()[self._indices.an_element()] + # Do we want this to return lie_algebra_generators()? Perhaps in the category? # def gens(self) -> tuple: # """ @@ -1072,9 +1076,9 @@ class LieAlgebraFromAssociative(LieAlgebraWithGenerators): [-6 14] [14 6] """ + @staticmethod - def __classcall_private__(cls, A, gens=None, names=None, index_set=None, - free_lie_algebra=False, category=None): + def __classcall_private__(cls, A, gens=None, names=None, index_set=None, free_lie_algebra=False, category=None): """ Normalize input to ensure a unique representation. @@ -1158,12 +1162,9 @@ def __classcall_private__(cls, A, gens=None, names=None, index_set=None, if gens is not None: for g in gens: g.set_immutable() - return MatrixLieAlgebraFromAssociative(A, gens, names=names, - index_set=index_set, - category=category) + return MatrixLieAlgebraFromAssociative(A, gens, names=names, index_set=index_set, category=category) - return super().__classcall__(cls, A, gens, names=names, - index_set=index_set, category=category) + return super().__classcall__(cls, A, gens, names=names, index_set=index_set, category=category) def __init__(self, A, gens=None, names=None, index_set=None, category=None): """ @@ -1189,13 +1190,10 @@ def __init__(self, A, gens=None, names=None, index_set=None, category=None): if isinstance(gens, tuple): # This guarantees that the generators have a specified ordering - d = {self._indices[i]: self.element_class(self, v) - for i, v in enumerate(gens)} + d = {self._indices[i]: self.element_class(self, v) for i, v in enumerate(gens)} gens = Family(self._indices, lambda i: d[i]) elif gens is not None: # It is a family - gens = Family(self._indices, - lambda i: self.element_class(self, gens[i]), - name="generator map") + gens = Family(self._indices, lambda i: self.element_class(self, gens[i]), name="generator map") self._gens = gens # We don't need to store the original generators because we can @@ -1480,6 +1478,7 @@ class LiftMorphismToAssociative(LiftMorphism): The natural lifting morphism from a Lie algebra constructed from an associative algebra `A` to `A`. """ + def preimage(self, x): """ Return the preimage of ``x`` under ``self``. @@ -1527,8 +1526,7 @@ def section(self): From: Free Algebra on 3 generators (x, y, z) over Rational Field To: Lie algebra generated by (x, y, z) in Free Algebra on 3 generators (x, y, z) over Rational Field """ - return SetMorphism(Hom(self.codomain(), self.domain()), - self.preimage) + return SetMorphism(Hom(self.codomain(), self.domain()), self.preimage) class MatrixLieAlgebraFromAssociative(LieAlgebraFromAssociative): @@ -1538,6 +1536,7 @@ class MatrixLieAlgebraFromAssociative(LieAlgebraFromAssociative): This means a Lie algebra consisting of matrices, with commutator as Lie bracket. """ + class Element(LieAlgebraMatrixWrapper, LieAlgebraFromAssociative.Element): def matrix(self): r""" diff --git a/src/sage/algebras/lie_algebras/morphism.py b/src/sage/algebras/lie_algebras/morphism.py index ddb41991a55..fb0c9c3c95c 100644 --- a/src/sage/algebras/lie_algebras/morphism.py +++ b/src/sage/algebras/lie_algebras/morphism.py @@ -6,6 +6,7 @@ - Travis Scrimshaw (07-15-2013): Initial implementation - Eero Hakavuori (08-09-2018): Morphisms defined by a generating subset """ + # **************************************************************************** # Copyright (C) 2013 Travis Scrimshaw # 2018 Eero Hakavuori @@ -89,6 +90,7 @@ class LieAlgebraHomomorphism_im_gens(Morphism): sage: phi(X).bracket(phi(Y)) -i*C """ + def __init__(self, parent, im_gens, base_map=None, check=True): """ EXAMPLES:: @@ -114,10 +116,11 @@ def __init__(self, parent, im_gens, base_map=None, check=True): if base_map is not None and not (base_map.domain() is parent.domain().base_ring() and parent.codomain().base_ring().has_coerce_map_from(base_map.codomain())): raise ValueError("invalid base homomorphism") # TODO: Implement a (meaningful) _is_valid_homomorphism_() - #if not parent.domain()._is_valid_homomorphism_(parent.codomain(), im_gens, base_map=base_map): + # if not parent.domain()._is_valid_homomorphism_(parent.codomain(), im_gens, base_map=base_map): # raise ValueError("relations do not all (canonically) map to 0 under map determined by images of generators") if not im_gens.is_immutable(): import copy + im_gens = copy.copy(im_gens) im_gens.set_immutable() self._im_gens = im_gens @@ -233,8 +236,7 @@ def _repr_defn(self): z |--> z """ D = self.domain() - s = '\n'.join('%s |--> %s' % (x, gen) - for gen, x in zip(self._im_gens, D.gens())) + s = '\n'.join('%s |--> %s' % (x, gen) for gen, x in zip(self._im_gens, D.gens())) if s and self._base_map is not None: s += '\nwith map of base ring' return s @@ -267,6 +269,7 @@ class LieAlgebraHomset(Homset): This is a very minimal implementation which does not have coercions of the morphisms. """ + def __init__(self, X, Y, category=None, base=None, check=True): """ Initialize ``self``. @@ -300,8 +303,7 @@ def _repr_(self): from Free Lie algebra generated by (x, y, z) over Rational Field in the Lyndon basis to Free Lie algebra generated by (x, y, z) over Rational Field in the Hall basis """ - return "Set of Lie algebra morphisms from {} to {}".format( - self.domain(), self.codomain()) + return "Set of Lie algebra morphisms from {} to {}".format(self.domain(), self.codomain()) def __call__(self, im_gens, check=True): """ @@ -330,12 +332,10 @@ def __call__(self, im_gens, check=True): if isinstance(im_gens, Morphism): return im_gens from sage.categories.lie_algebras import LieAlgebras - if (self.domain() in LieAlgebras.FiniteDimensional.WithBasis - and self.codomain() in LieAlgebras.FiniteDimensional.WithBasis): + + if self.domain() in LieAlgebras.FiniteDimensional.WithBasis and self.codomain() in LieAlgebras.FiniteDimensional.WithBasis: try: - return LieAlgebraMorphism_from_generators(self.domain(), im_gens, - codomain=self.codomain(), - check=check) + return LieAlgebraMorphism_from_generators(self.domain(), im_gens, codomain=self.codomain(), check=check) except (TypeError, ValueError): pass return LieAlgebraHomomorphism_im_gens(self, im_gens) @@ -471,6 +471,7 @@ class LieAlgebraMorphism_from_generators(LieAlgebraHomomorphism_im_gens): Z |--> 0 W |--> 0 """ + def __init__(self, on_generators, domain=None, codomain=None, check=True, base_map=None, category=None): r""" Initialize ``self``. @@ -570,12 +571,11 @@ def solve_linear_system(A, b, check): # vectors, need to expand the matrix product by hand. M = A * A_inv for Mi, bk in zip(M.rows(), b): - test_bk = sum((R(Mij) * bj for Mij,bj in zip(Mi,b)), cm.zero()) + test_bk = sum((R(Mij) * bj for Mij, bj in zip(Mi, b)), cm.zero()) if test_bk != bk: raise ValueError("contradictory linear system") - return [sum((R(Aij) * bk for Aij,bk in zip(Ai,b)), cm.zero()) - for Ai in A_inv.rows()] + return [sum((R(Aij) * bk for Aij, bk in zip(Ai, b)), cm.zero()) for Ai in A_inv.rows()] bracketlength = 1 n = 0 @@ -587,9 +587,7 @@ def solve_linear_system(A, b, check): try: im_gens = solve_linear_system(A, im_gens, check) except ValueError: - raise ValueError("this does not define a Lie algebra morphism; " - "contradictory values for brackets of length %d" - % bracketlength) + raise ValueError("this does not define a Lie algebra morphism; " "contradictory values for brackets of length %d" % bracketlength) spanning_set = list(sm.basis()) if n == len(spanning_set): @@ -599,7 +597,7 @@ def solve_linear_system(A, b, check): # compute brackets and repeat bracketlength += 1 n = len(spanning_set) - for i,j in combinations(range(n), 2): + for i, j in combinations(range(n), 2): # add the value of the bracket to known images Z = domain.bracket(spanning_set[i], spanning_set[j]) imZ = codomain.bracket(im_gens[i], im_gens[j]) @@ -608,8 +606,7 @@ def solve_linear_system(A, b, check): # verify that sm is the full module m if not sm.has_coerce_map_from(m): - raise ValueError("%s is not a generating set of %s" - % (list(on_generators), domain)) + raise ValueError("%s is not a generating set of %s" % (list(on_generators), domain)) A = matrix(m.base_ring(), spanning_set) im_gens = solve_linear_system(A, im_gens, check) diff --git a/src/sage/algebras/lie_algebras/nilpotent_lie_algebra.py b/src/sage/algebras/lie_algebras/nilpotent_lie_algebra.py index 90707f23644..37e4128652b 100644 --- a/src/sage/algebras/lie_algebras/nilpotent_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/nilpotent_lie_algebra.py @@ -71,8 +71,7 @@ class NilpotentLieAlgebra_dense(LieAlgebraWithStructureCoefficients): """ @staticmethod - def __classcall_private__(cls, R, s_coeff, names=None, index_set=None, - category=None, **kwds): + def __classcall_private__(cls, R, s_coeff, names=None, index_set=None, category=None, **kwds): """ Normalize input to ensure a unique representation. @@ -124,15 +123,14 @@ def __classcall_private__(cls, R, s_coeff, names=None, index_set=None, names.append(k) from sage.structure.indexed_generators import standardize_names_index_set + names, index_set = standardize_names_index_set(names, index_set) - s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff( - s_coeff, index_set) + s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff(s_coeff, index_set) cat = LieAlgebras(R).FiniteDimensional().WithBasis().Nilpotent() category = cat.or_subcategory(category) - return super().__classcall__(cls, R, s_coeff, names, - index_set, category=category, **kwds) + return super().__classcall__(cls, R, s_coeff, names, index_set, category=category, **kwds) def __init__(self, R, s_coeff, names, index_set, step=None, **kwds) -> None: r""" @@ -146,9 +144,7 @@ def __init__(self, R, s_coeff, names, index_set, step=None, **kwds) -> None: if step is not None: self._step = step - LieAlgebraWithStructureCoefficients.__init__(self, R, s_coeff, - names, index_set, - **kwds) + LieAlgebraWithStructureCoefficients.__init__(self, R, s_coeff, names, index_set, **kwds) def _repr_(self) -> str: """ @@ -327,6 +323,7 @@ class FreeNilpotentLieAlgebra(NilpotentLieAlgebra_dense): sage: len(set(repr(b) for b in L.basis())) == L.dimension() True """ + @staticmethod def __classcall_private__(cls, R, r, s, names=None, naming='index', category=None, **kwds): """ @@ -346,9 +343,7 @@ def __classcall_private__(cls, R, r, s, names=None, naming='index', category=Non cat = LieAlgebras(R).FiniteDimensional().WithBasis() category = cat.Graded().Stratified().or_subcategory(category) - return super().__classcall__( - cls, R, r, s, names=tuple(names), naming=naming, - category=category, **kwds) + return super().__classcall__(cls, R, r, s, names=tuple(names), naming=naming, category=category, **kwds) def __init__(self, R, r, s, names, naming, category, **kwds) -> None: r""" @@ -363,8 +358,7 @@ def __init__(self, R, r, s, names, naming, category, **kwds) -> None: sage: TestSuite(L).run() # long time """ if r not in ZZ or r <= 0: - raise ValueError("number of generators %s is not " - "a positive integer" % r) + raise ValueError("number of generators %s is not " "a positive integer" % r) if s not in ZZ or s <= 0: raise ValueError("step %s is not a positive integer" % s) @@ -380,32 +374,31 @@ def __init__(self, R, r, s, names, naming, category, **kwds) -> None: for d in range(1, s + 1): for X in L.graded_basis(d): # convert brackets of form [X_1, [X_1, X_2]] to words (1,1,2) - w = tuple(free_gen_names_inv[s] - for s in X.leading_support().to_word()) + w = tuple(free_gen_names_inv[s] for s in X.leading_support().to_word()) basis_by_deg[d].append((w, X)) index_set = [ind for d in basis_by_deg for ind, val in basis_by_deg[d]] if len(names) == 1 and len(index_set) > 1: if naming == 'linear': - names = ['%s_%d' % (names[0], k + 1) - for k in range(len(index_set))] + names = ['%s_%d' % (names[0], k + 1) for k in range(len(index_set))] elif naming == 'index': if r < 10: let = repr elif r <= 16: - hexdata = [repr(i) for i in range(10)] + ['a','b','c','d','e','f'] + hexdata = [repr(i) for i in range(10)] + ['a', 'b', 'c', 'd', 'e', 'f'] def let(i): return hexdata[i] + else: rlen = len(repr(r)) def let(i): ret = repr(i) - return '0'*(rlen-len(ret)) + ret - names = ['%s_%s' % (names[0], "".join(let(s) for s in ind)) - for ind in index_set] + return '0' * (rlen - len(ret)) + ret + + names = ['%s_%s' % (names[0], "".join(let(s) for s in ind)) for ind in index_set] else: raise ValueError("unknown naming scheme %s" % naming) @@ -418,27 +411,22 @@ def let(i): if dx == dy: for i, val in enumerate(basis_by_deg[dx]): X_ind, X = val - for Y_ind, Y in basis_by_deg[dy][i + 1:]: + for Y_ind, Y in basis_by_deg[dy][i + 1 :]: Z = L[X, Y] if not Z.is_zero(): - s_coeff[(X_ind, Y_ind)] = {W_ind: Z[W.leading_support()] - for W_ind, W in basis_by_deg[dx + dy]} + s_coeff[(X_ind, Y_ind)] = {W_ind: Z[W.leading_support()] for W_ind, W in basis_by_deg[dx + dy]} else: for X_ind, X in basis_by_deg[dx]: for Y_ind, Y in basis_by_deg[dy]: Z = L[X, Y] if not Z.is_zero(): - s_coeff[(X_ind, Y_ind)] = {W_ind: Z[W.leading_support()] - for W_ind, W in basis_by_deg[dx + dy]} + s_coeff[(X_ind, Y_ind)] = {W_ind: Z[W.leading_support()] for W_ind, W in basis_by_deg[dx + dy]} names, index_set = standardize_names_index_set(names, index_set) - s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff( - s_coeff, index_set) + s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff(s_coeff, index_set) self._rank = r - NilpotentLieAlgebra_dense.__init__(self, R, s_coeff, names, - index_set, s, - category=category, **kwds) + NilpotentLieAlgebra_dense.__init__(self, R, s_coeff, names, index_set, s, category=category, **kwds) class options(GlobalOptions): r""" @@ -461,13 +449,10 @@ class options(GlobalOptions): + [[[X_1, X_2], X_2], X_2] sage: L.options._reset() """ + NAME = 'FreeNilpotentLieAlgebra' module = 'sage.algebras.lie_algebras.nilpotent_lie_algebra' - display = dict(default='variables', - description='Controls the way elements are printed', - values=dict(variables='print basis elements as variables', - brackets='print basis elements as brackets'), - case_sensitive=False) + display = dict(default='variables', description='Controls the way elements are printed', values=dict(variables='print basis elements as variables', brackets='print basis elements as brackets'), case_sensitive=False) def _repr_generator(self, w, use_latex=False) -> str: r""" @@ -505,9 +490,10 @@ def _repr_generator(self, w, use_latex=False) -> str: ret = self.variable_names()[i] if use_latex: from sage.misc.latex import latex + ind = ret.find("_") if ind != -1: - ret = ret[:ind] + "_{{{}}}".format(latex(ret[ind+1:])) + ret = ret[:ind] + "_{{{}}}".format(latex(ret[ind + 1 :])) return ret basis = self.basis() @@ -524,6 +510,7 @@ def standard_bracket(lw): if use_latex: from sage.misc.latex import latex + return latex(standard_bracket(w)) return repr(standard_bracket(w)) @@ -568,8 +555,7 @@ def _repr_(self) -> str: sage: L Free Nilpotent Lie algebra of rank 2 and step 5 over Rational Field """ - return "Free Nilpotent Lie algebra of rank {} and step {} over {}".format( - self._rank, self._step, self.base_ring()) + return "Free Nilpotent Lie algebra of rank {} and step {} over {}".format(self._rank, self._step, self.base_ring()) def degree_on_basis(self, w) -> int: r""" diff --git a/src/sage/algebras/lie_algebras/onsager.py b/src/sage/algebras/lie_algebras/onsager.py index e002f7b55b1..a98c5dee32d 100644 --- a/src/sage/algebras/lie_algebras/onsager.py +++ b/src/sage/algebras/lie_algebras/onsager.py @@ -6,7 +6,7 @@ - Travis Scrimshaw (2017-07): Initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2017 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.cachefunc import cached_method from sage.categories.algebras import Algebras @@ -111,6 +111,7 @@ class OnsagerAlgebra(LieAlgebraWithGenerators, IndexedGenerators): - [Onsager1944]_ - [DG1982]_ """ + def __init__(self, R): """ Initialize ``self``. @@ -122,9 +123,9 @@ def __init__(self, R): """ cat = LieAlgebras(R).WithBasis() from sage.sets.finite_enumerated_set import FiniteEnumeratedSet - IndexedGenerators.__init__(self, FiniteEnumeratedSet([0,1])) - LieAlgebraWithGenerators.__init__(self, R, index_set=self._indices, - names=('A0', 'A1'), category=cat) + + IndexedGenerators.__init__(self, FiniteEnumeratedSet([0, 1])) + LieAlgebraWithGenerators.__init__(self, R, index_set=self._indices, names=('A0', 'A1'), category=cat) def _repr_(self): """ @@ -148,6 +149,7 @@ def _latex_(self): \mathcal{O}_{\Bold{Q}} """ from sage.misc.latex import latex + return "\\mathcal{{O}}_{{{}}}".format(latex(self.base_ring())) def _repr_generator(self, m): @@ -201,8 +203,8 @@ def basis(self): from sage.rings.integer_ring import ZZ from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.positive_integers import PositiveIntegers - I = DisjointUnionEnumeratedSets([ZZ, PositiveIntegers()], - keepkey=True, facade=True) + + I = DisjointUnionEnumeratedSets([ZZ, PositiveIntegers()], keepkey=True, facade=True) return Family(I, self.monomial, name='Onsager monomial') @cached_method @@ -216,7 +218,7 @@ def lie_algebra_generators(self): sage: O.lie_algebra_generators() Finite family {'A0': A[0], 'A1': A[1]} """ - d = {"A0": self.basis()[0,0], "A1": self.basis()[0,1]} + d = {"A0": self.basis()[0, 0], "A1": self.basis()[0, 1]} return Family(self._names, d.__getitem__) def bracket_on_basis(self, x, y): @@ -239,11 +241,11 @@ def bracket_on_basis(self, x, y): # Therefore, we have [G_n, G_{n'}] = 0 return self.zero() R = self.base_ring() - if y[0] == 1: # [A_m, G_n] = -(2A_{m-n} - 2A_{m+n}) - d = {(0, x[1]-y[1]): R(-2), (0, x[1]+y[1]): R(2)} + if y[0] == 1: # [A_m, G_n] = -(2A_{m-n} - 2A_{m+n}) + d = {(0, x[1] - y[1]): R(-2), (0, x[1] + y[1]): R(2)} return self.element_class(self, d) # [A_m, A_{m'}] = -G_{m' - m}, where m < m' - return self.element_class(self, {(1, y[1]-x[1]): -R.one()}) + return self.element_class(self, {(1, y[1] - x[1]): -R.one()}) def _an_element_(self): """ @@ -256,7 +258,7 @@ def _an_element_(self): -2*A[-3] + A[2] + 3*G[2] """ B = self.basis() - return B[0,2] - 2*B[0,-3] + 3*B[1,2] + return B[0, 2] - 2 * B[0, -3] + 3 * B[1, 2] def some_elements(self): """ @@ -269,7 +271,7 @@ def some_elements(self): [A[0], A[2], A[-1], G[4], -2*A[-3] + A[2] + 3*G[2]] """ B = self.basis() - return [B[0,0], B[0,2], B[0,-1], B[1,4], self.an_element()] + return [B[0, 0], B[0, 2], B[0, -1], B[1, 4], self.an_element()] def quantum_group(self, q=None, c=None): r""" @@ -295,6 +297,7 @@ def quantum_group(self, q=None, c=None): """ if q is None: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + q = PolynomialRing(self.base_ring(), 'q').fraction_field().gen() if c is None: c = q @@ -317,6 +320,7 @@ def alternating_central_extension(self): Element = LieAlgebraElement + ##################################################################### # q-Onsager algebra (the quantum group) @@ -388,6 +392,7 @@ class QuantumOnsagerAlgebra(CombinatorialFreeModule): - [BK2017]_ """ + def __init__(self, g, q, c): """ Initialize ``self``. @@ -404,13 +409,9 @@ def __init__(self, g, q, c): self._q_two = q + ~q R = self._q_two.parent() from sage.monoids.indexed_free_monoid import IndexedFreeAbelianMonoid - monomials = IndexedFreeAbelianMonoid(g.basis().keys(), - prefix='B', bracket=False, - sorting_key=self._monoid_key) - CombinatorialFreeModule.__init__(self, R, monomials, - prefix='', bracket=False, latex_bracket=False, - sorting_key=self._monomial_key, - category=Algebras(R).WithBasis().Filtered()) + + monomials = IndexedFreeAbelianMonoid(g.basis().keys(), prefix='B', bracket=False, sorting_key=self._monoid_key) + CombinatorialFreeModule.__init__(self, R, monomials, prefix='', bracket=False, latex_bracket=False, sorting_key=self._monomial_key, category=Algebras(R).WithBasis().Filtered()) def _basis_key(self, k): r""" @@ -430,7 +431,7 @@ def _basis_key(self, k): sage: Q._basis_key((1,2)) (0, 2) """ - if k[0] == 0: # B_{m\delta + \alpha_1} + if k[0] == 0: # B_{m\delta + \alpha_1} if k[1] < 0: return (-1, -k[1]) return (1, -k[1]) @@ -481,8 +482,7 @@ def _repr_(self): q-Onsager algebra with c=q over Fraction Field of Univariate Polynomial Ring in q over Rational Field """ - return "{}-Onsager algebra with c={} over {}".format(self._q, self._c, - self.base_ring()) + return "{}-Onsager algebra with c={} over {}".format(self._q, self._c, self.base_ring()) def _latex_(self): r""" @@ -496,8 +496,8 @@ def _latex_(self): U_{-1}(\mathcal{O}_{\Bold{Q}})_{-1} """ from sage.misc.latex import latex - return "U_{{{}}}(\\mathcal{{O}}_{{{}}})_{{{}}}".format(latex(self._q), - latex(self._g.base_ring()), latex(self._c)) + + return "U_{{{}}}(\\mathcal{{O}}_{{{}}})_{{{}}}".format(latex(self._q), latex(self._g.base_ring()), latex(self._c)) def _repr_term(self, m): r""" @@ -517,15 +517,16 @@ def _repr_term(self, m): sage: Q._repr_term(I[0,-1]^2 * I[1,3]^13 * I[0,3]) 'B[a0]^2*B[3d]^13*B[3d+a1]' """ + def to_str(x): - k,e = x + k, e = x if k[0] == 0: if k[1] == -1: ret = 'B[a0]' elif k[1] == 0: ret = 'B[a1]' elif k[1] < -1: - ret = 'B[{}d+a0]'.format(-k[1]-1) + ret = 'B[{}d+a0]'.format(-k[1] - 1) elif k[1] > 0: ret = 'B[{}d+a1]'.format(k[1]) else: @@ -533,6 +534,7 @@ def to_str(x): if e > 1: ret = ret + '^{}'.format(e) return ret + return '*'.join(to_str(x) for x in m._sorted_items()) def _latex_term(self, m): @@ -553,15 +555,16 @@ def _latex_term(self, m): sage: Q._latex_term(I[0,-1]^2 * I[1,3]^13 * I[0,3]) 'B_{\\alpha_0}^{2} B_{3\\delta}^{13} B_{3\\delta+\\alpha_1}' """ + def to_str(x): - k,e = x + k, e = x if k[0] == 0: if k[1] == -1: ret = 'B_{\\alpha_0}' elif k[1] == 0: ret = 'B_{\\alpha_1}' elif k[1] < -1: - ret = 'B_{{{}\\delta+\\alpha_0}}'.format(-k[1]-1) + ret = 'B_{{{}\\delta+\\alpha_0}}'.format(-k[1] - 1) elif k[1] > 0: ret = 'B_{{{}\\delta+\\alpha_1}}'.format(k[1]) else: @@ -569,6 +572,7 @@ def to_str(x): if e > 1: ret = ret + '^{{{}}}'.format(e) return ret + return ' '.join(to_str(x) for x in m._sorted_items()) def lie_algebra(self): @@ -599,8 +603,7 @@ def algebra_generators(self): Family (Integer Ring, Positive integers)} """ G = self._indices.gens() - return Family(self._indices._indices, lambda x: self.monomial(G[x]), - name="generator map") + return Family(self._indices._indices, lambda x: self.monomial(G[x]), name="generator map") gens = algebra_generators @@ -659,7 +662,7 @@ def _an_element_(self): -2*B[2d+a0] + q*B[2d] + B[2d+a1] """ G = self.algebra_generators() - return G[0,2] - 2*G[0,-3] + self.base_ring().an_element()*G[1,2] + return G[0, 2] - 2 * G[0, -3] + self.base_ring().an_element() * G[1, 2] def some_elements(self): """ @@ -673,7 +676,7 @@ def some_elements(self): [B[a1], B[3d+a1], B[a0], B[1d], B[4d]] """ G = self.algebra_generators() - return [G[0,0], G[0,3], G[0,-1], G[1,1], G[1,4]] + return [G[0, 0], G[0, 3], G[0, -1], G[1, 1], G[1, 4]] def degree_on_basis(self, m): r""" @@ -781,23 +784,22 @@ def product_on_basis(self, lhs, rhs): return self.monomial(lhs * B[kr]) * self.monomial(rhs // B[kr]) if kl[0] == 0 and kr[0] == 0: + def a(m, p): if p <= (m - 1) // 2: - return q**(-2*(p-1)) * (1 + q**-2) + return q ** (-2 * (p - 1)) * (1 + q**-2) # Assume m is even and p == m/2 assert p == m // 2 and m % 2 == 0 - return q**(-m+2) + return q ** (-m + 2) + if kl[1] * kr[1] > 0 or (kl[1] == 0 and kr[1] > 0): # Same sign # [B[rd+a1], B[(r+m)d+a1]] m = kr[1] - kl[1] assert m > 0 terms = q**-2 * self.monomial(B[kr] * B[kl]) - terms -= self.monomial(B[1,m]) - temp = (-sum(q**(-2*(p-1)) * self.monomial(B[1,m-2*p]) - for p in range(1, (m - 1) // 2 + 1)) - + sum(a(m,p) * self.monomial(B[0,kr[1]-p]) * self.monomial(B[0,p+kl[1]]) - for p in range(1, m // 2 + 1))) + terms -= self.monomial(B[1, m]) + temp = -sum(q ** (-2 * (p - 1)) * self.monomial(B[1, m - 2 * p]) for p in range(1, (m - 1) // 2 + 1)) + sum(a(m, p) * self.monomial(B[0, kr[1] - p]) * self.monomial(B[0, p + kl[1]]) for p in range(1, m // 2 + 1)) terms += (q**-2 - 1) * temp else: r = -kr[1] - 1 @@ -805,32 +807,22 @@ def a(m, p): if r <= kl[1]: # [B[rd+a0], B[sd+a1]] r <= s terms = -self.monomial(B[kr] * B[kl]) - terms -= self.monomial(B[1,r+kl[1]+1]) - terms -= (q**2-1) * sum(q**(2*k) * self.monomial(B[1,r+kl[1]-1-2*k]) - for k in range(r)) - terms -= (q**2-q**-2) * sum(q**(2*(r-1-k)) * self.monomial(B[0,-(k+1)]) * self.monomial(B[0,-r+kl[1]+k]) - for k in range(r)) + terms -= self.monomial(B[1, r + kl[1] + 1]) + terms -= (q**2 - 1) * sum(q ** (2 * k) * self.monomial(B[1, r + kl[1] - 1 - 2 * k]) for k in range(r)) + terms -= (q**2 - q**-2) * sum(q ** (2 * (r - 1 - k)) * self.monomial(B[0, -(k + 1)]) * self.monomial(B[0, -r + kl[1] + k]) for k in range(r)) m = -r + kl[1] + 1 - temp = (-sum(q**(-2*(p-1)) * self.monomial(B[1,m-2*p]) - for p in range(1, (m - 1) // 2 + 1)) - + sum(a(m,p) * self.monomial(B[0,m-p-1]) * self.monomial(B[0,p-1]) - for p in range(1, m // 2 + 1))) - terms += (q**-2 - 1) * q**(2*r) * temp + temp = -sum(q ** (-2 * (p - 1)) * self.monomial(B[1, m - 2 * p]) for p in range(1, (m - 1) // 2 + 1)) + sum(a(m, p) * self.monomial(B[0, m - p - 1]) * self.monomial(B[0, p - 1]) for p in range(1, m // 2 + 1)) + terms += (q**-2 - 1) * q ** (2 * r) * temp else: # [B[rd+a0], B[sd+a1]] r > s terms = -self.monomial(B[kr] * B[kl]) - terms -= self.monomial(B[1,r+kl[1]+1]) - terms -= (q**2-1) * sum(q**(2*k) * self.monomial(B[1,r+kl[1]-1-2*k]) - for k in range(kl[1])) - terms -= (q**2-q**-2) * sum(q**(2*(kl[1]-1-k)) * self.monomial(B[0,-(r-kl[1]+k+1)]) * self.monomial(B[0,k]) - for k in range(kl[1])) + terms -= self.monomial(B[1, r + kl[1] + 1]) + terms -= (q**2 - 1) * sum(q ** (2 * k) * self.monomial(B[1, r + kl[1] - 1 - 2 * k]) for k in range(kl[1])) + terms -= (q**2 - q**-2) * sum(q ** (2 * (kl[1] - 1 - k)) * self.monomial(B[0, -(r - kl[1] + k + 1)]) * self.monomial(B[0, k]) for k in range(kl[1])) m = r - kl[1] + 1 - temp = (-sum(q**(-2*(p-1)) * self.monomial(B[1,m-2*p]) - for p in range(1, (m - 1) // 2 + 1)) - + sum(a(m,p) * self.monomial(B[0,-p]) * self.monomial(B[0,p-m]) - for p in range(1, m // 2 + 1))) - terms += (q**-2 - 1) * q**(2*kl[1]) * temp - terms = -q**2 * terms + temp = -sum(q ** (-2 * (p - 1)) * self.monomial(B[1, m - 2 * p]) for p in range(1, (m - 1) // 2 + 1)) + sum(a(m, p) * self.monomial(B[0, -p]) * self.monomial(B[0, p - m]) for p in range(1, m // 2 + 1)) + terms += (q**-2 - 1) * q ** (2 * kl[1]) * temp + terms = -(q**2) * terms elif kl[0] == 1 and kr[0] == 0: terms = self.monomial(B[kr] * B[kl]) # We have kr[1] < 0 @@ -839,88 +831,33 @@ def a(m, p): if p < kl[1]: # [B[md], B[pd+a0]] with p < m # m = kl[1] - terms += self._c * self._q_two * ( - q**(-2*(kl[1]-1)) * self.monomial(B[0,-(kl[1]+p+1)]) - + (q**2 - q**-2) * sum(q**(-2*(kl[1]-2*p+2*h)) - * self.monomial(B[0,-(kl[1]-p+2*h+1)]) - for h in range(p)) - - q**(-2*(kl[1]-2*p-1)) * self.monomial(B[0,kl[1]-p-1]) - ) - terms -= (q**2 - q**-2) * sum( - q**(-2*(ell-1)) * self.monomial(B[0,-(ell+p+1)] * B[1,kl[1]-ell]) - + (q**2 - q**-2) * sum(q**(-2*(ell-2*h)) * self.monomial(B[0,-(ell+p-2*h+1)] * B[1,kl[1]-ell]) - for h in range(1, ell)) - - q**(2*(ell-1)) * self.monomial(B[0,-(p-ell+1)] * B[1,kl[1]-ell]) - for ell in range(1, p+1)) - terms -= (q**2 - q**-2) * sum( - q**(-2*(ell-1)) * self.monomial(B[0,-(ell+p+1)] * B[1,kl[1]-ell]) - + (q**2 - q**-2) * sum(q**(-2*(ell-2*h)) * self.monomial(B[0,-(ell+p-2*h+1)] * B[1,kl[1]-ell]) - for h in range(1, p+1)) - for ell in range(p+1, kl[1])) - terms += (q**2 - q**-2) * sum( - q**(-2*(ell-2*p-1)) * self.monomial(B[1,kl[1]-ell] * B[0,ell-p-1]) - for ell in range(p+1, kl[1])) + terms += self._c * self._q_two * (q ** (-2 * (kl[1] - 1)) * self.monomial(B[0, -(kl[1] + p + 1)]) + (q**2 - q**-2) * sum(q ** (-2 * (kl[1] - 2 * p + 2 * h)) * self.monomial(B[0, -(kl[1] - p + 2 * h + 1)]) for h in range(p)) - q ** (-2 * (kl[1] - 2 * p - 1)) * self.monomial(B[0, kl[1] - p - 1])) + terms -= (q**2 - q**-2) * sum(q ** (-2 * (ell - 1)) * self.monomial(B[0, -(ell + p + 1)] * B[1, kl[1] - ell]) + (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * h)) * self.monomial(B[0, -(ell + p - 2 * h + 1)] * B[1, kl[1] - ell]) for h in range(1, ell)) - q ** (2 * (ell - 1)) * self.monomial(B[0, -(p - ell + 1)] * B[1, kl[1] - ell]) for ell in range(1, p + 1)) + terms -= (q**2 - q**-2) * sum(q ** (-2 * (ell - 1)) * self.monomial(B[0, -(ell + p + 1)] * B[1, kl[1] - ell]) + (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * h)) * self.monomial(B[0, -(ell + p - 2 * h + 1)] * B[1, kl[1] - ell]) for h in range(1, p + 1)) for ell in range(p + 1, kl[1])) + terms += (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * p - 1)) * self.monomial(B[1, kl[1] - ell] * B[0, ell - p - 1]) for ell in range(p + 1, kl[1])) else: # [B[md], B[pd+a0]] with p >= m # m = kl[1] - terms += self._c * self._q_two * ( - q**(-2*(kl[1]-1)) * self.monomial(B[0,-(p+kl[1]+1)]) - + (q**2 - q**-2) * sum(q**(2*(kl[1]-2-2*h)) - * self.monomial(B[0,-(p-kl[1]+2+2*h+1)]) - for h in range(kl[1]-1)) - - q**(2*(kl[1]-1)) * self.monomial(B[0,-(p-kl[1]+1)]) - ) - terms -= (q**2 - q**-2) * sum( - q**(-2*(ell-1)) * self.monomial(B[0,-(p+ell+1)] * B[1,kl[1]-ell]) - + (q**2 - q**-2) * sum(q**(-2*(ell-2*h)) * self.monomial(B[0,-(p+ell-2*h+1)] * B[1,kl[1]-ell]) - for h in range(1, ell)) - - q**(2*(ell-1)) * self.monomial(B[0,-(p-ell+1)] * B[1,kl[1]-ell]) - for ell in range(1, kl[1])) + terms += self._c * self._q_two * (q ** (-2 * (kl[1] - 1)) * self.monomial(B[0, -(p + kl[1] + 1)]) + (q**2 - q**-2) * sum(q ** (2 * (kl[1] - 2 - 2 * h)) * self.monomial(B[0, -(p - kl[1] + 2 + 2 * h + 1)]) for h in range(kl[1] - 1)) - q ** (2 * (kl[1] - 1)) * self.monomial(B[0, -(p - kl[1] + 1)])) + terms -= (q**2 - q**-2) * sum(q ** (-2 * (ell - 1)) * self.monomial(B[0, -(p + ell + 1)] * B[1, kl[1] - ell]) + (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * h)) * self.monomial(B[0, -(p + ell - 2 * h + 1)] * B[1, kl[1] - ell]) for h in range(1, ell)) - q ** (2 * (ell - 1)) * self.monomial(B[0, -(p - ell + 1)] * B[1, kl[1] - ell]) for ell in range(1, kl[1])) else: # kl[0] == 0 and kr[0] == 1: terms = self.monomial(B[kr] * B[kl]) if kl[1] < kr[1]: # [B[pd+a1], B[md]] with p < m # p = kl[1], m = kr[1] - terms += self._c * self._q_two * ( - q**(-2*(kr[1]-1)) * self.monomial(B[0,kr[1]+kl[1]]) - + (q**2 - q**-2) * sum(q**(-2*(kr[1]-2*kl[1]+2*h)) - * self.monomial(B[0,kr[1]-kl[1]+2*h]) - for h in range(kl[1])) - - q**(-2*(kr[1]-2*kl[1]-1)) * self.monomial(B[0,kl[1]-kr[1]]) - ) - terms -= (q**2 - q**-2) * sum( - q**(-2*(ell-1)) * self.monomial(B[1,kr[1]-ell] * B[0,ell+kl[1]]) - + (q**2 - q**-2) * sum(q**(-2*(ell-2*h)) * self.monomial(B[1,kr[1]-ell] * B[0,ell+kl[1]-2*h]) - for h in range(1, ell)) - - q**(2*(ell-1)) * self.monomial(B[1,kr[1]-ell] * B[0,kl[1]-ell]) - for ell in range(1, kl[1]+1)) - terms -= (q**2 - q**-2) * sum( - q**(-2*(ell-1)) * self.monomial(B[1,kr[1]-ell] * B[0,ell+kl[1]]) - + (q**2 - q**-2) * sum(q**(-2*(ell-2*h)) * self.monomial(B[1,kr[1]-ell] * B[0,ell+kl[1]-2*h]) - for h in range(1, kl[1]+1)) - for ell in range(kl[1]+1, kr[1])) - terms += (q**2 - q**-2) * sum( - q**(-2*(ell-2*kl[1]-1)) * self.monomial(B[0,kl[1]-ell] * B[1,kr[1]-ell]) - for ell in range(kl[1]+1, kr[1])) + terms += self._c * self._q_two * (q ** (-2 * (kr[1] - 1)) * self.monomial(B[0, kr[1] + kl[1]]) + (q**2 - q**-2) * sum(q ** (-2 * (kr[1] - 2 * kl[1] + 2 * h)) * self.monomial(B[0, kr[1] - kl[1] + 2 * h]) for h in range(kl[1])) - q ** (-2 * (kr[1] - 2 * kl[1] - 1)) * self.monomial(B[0, kl[1] - kr[1]])) + terms -= (q**2 - q**-2) * sum(q ** (-2 * (ell - 1)) * self.monomial(B[1, kr[1] - ell] * B[0, ell + kl[1]]) + (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * h)) * self.monomial(B[1, kr[1] - ell] * B[0, ell + kl[1] - 2 * h]) for h in range(1, ell)) - q ** (2 * (ell - 1)) * self.monomial(B[1, kr[1] - ell] * B[0, kl[1] - ell]) for ell in range(1, kl[1] + 1)) + terms -= (q**2 - q**-2) * sum(q ** (-2 * (ell - 1)) * self.monomial(B[1, kr[1] - ell] * B[0, ell + kl[1]]) + (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * h)) * self.monomial(B[1, kr[1] - ell] * B[0, ell + kl[1] - 2 * h]) for h in range(1, kl[1] + 1)) for ell in range(kl[1] + 1, kr[1])) + terms += (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * kl[1] - 1)) * self.monomial(B[0, kl[1] - ell] * B[1, kr[1] - ell]) for ell in range(kl[1] + 1, kr[1])) else: # [B[pd+a1], B[md]] with p >= m # p = kl[1], m = kr[1] - terms += self._c * self._q_two * ( - q**(-2*(kr[1]-1)) * self.monomial(B[0,kl[1]+kr[1]]) - + (q**2 - q**-2) * sum(q**(2*(kr[1]-2-2*h)) - * self.monomial(B[0,kl[1]-kr[1]+2+2*h]) - for h in range(kr[1]-1)) - - q**(2*(kr[1]-1)) * self.monomial(B[0,kl[1]-kr[1]]) - ) - terms -= (q**2 - q**-2) * sum( - q**(-2*(ell-1)) * self.monomial(B[1,kr[1]-ell] * B[0,kl[1]+ell]) - + (q**2 - q**-2) * sum(q**(-2*(ell-2*h)) * self.monomial(B[1,kr[1]-ell] * B[0,kl[1]+ell-2*h]) - for h in range(1, ell)) - - q**(2*(ell-1)) * self.monomial(B[1,kr[1]-ell] * B[0,kl[1]-ell]) - for ell in range(1, kr[1])) + terms += self._c * self._q_two * (q ** (-2 * (kr[1] - 1)) * self.monomial(B[0, kl[1] + kr[1]]) + (q**2 - q**-2) * sum(q ** (2 * (kr[1] - 2 - 2 * h)) * self.monomial(B[0, kl[1] - kr[1] + 2 + 2 * h]) for h in range(kr[1] - 1)) - q ** (2 * (kr[1] - 1)) * self.monomial(B[0, kl[1] - kr[1]])) + terms -= (q**2 - q**-2) * sum(q ** (-2 * (ell - 1)) * self.monomial(B[1, kr[1] - ell] * B[0, kl[1] + ell]) + (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * h)) * self.monomial(B[1, kr[1] - ell] * B[0, kl[1] + ell - 2 * h]) for h in range(1, ell)) - q ** (2 * (ell - 1)) * self.monomial(B[1, kr[1] - ell] * B[0, kl[1] - ell]) for ell in range(1, kr[1])) return self.monomial(lhs // B[kl]) * terms * self.monomial(rhs // B[kr]) + ##################################################################### # ACE of the Onsager algebra @@ -1031,6 +968,7 @@ class OnsagerAlgebraACE(InfinitelyGeneratedLieAlgebra, IndexedGenerators): ....: for k in range(-4,4) for m in range(-4,4)) True """ + def __init__(self, R): r""" Initialize ``self``. @@ -1048,6 +986,7 @@ def __init__(self, R): cat = LieAlgebras(R).WithBasis() from sage.rings.integer_ring import ZZ from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets + I = DisjointUnionEnumeratedSets([ZZ, ZZ], keepkey=True, facade=True) IndexedGenerators.__init__(self, I) InfinitelyGeneratedLieAlgebra.__init__(self, R, index_set=I, category=cat) @@ -1074,6 +1013,7 @@ def _latex_(self): \mathcal{O}_{\Bold{Q}} """ from sage.misc.latex import latex + return "\\mathcal{{O}}_{{{}}}".format(latex(self.base_ring())) def _repr_generator(self, m): @@ -1151,7 +1091,7 @@ def _an_element_(self): -2*A[-3] + A[2] + B[-1] + 3*B[2] """ B = self.basis() - return B[0,2] - 2*B[0,-3] + 3*B[1,2] + B[1,-1] + return B[0, 2] - 2 * B[0, -3] + 3 * B[1, 2] + B[1, -1] def some_elements(self): r""" @@ -1164,7 +1104,7 @@ def some_elements(self): [A[0], A[2], A[-1], B[4], B[-3], -2*A[-3] + A[2] + B[-1] + 3*B[2]] """ B = self.basis() - return [B[0,0], B[0,2], B[0,-1], B[1,4], B[1,-3], self.an_element()] + return [B[0, 0], B[0, 2], B[0, -1], B[1, 4], B[1, -3], self.an_element()] def bracket_on_basis(self, x, y): r""" @@ -1187,13 +1127,13 @@ def bracket_on_basis(self, x, y): return self.zero() R = self.base_ring() one = R.one() - if y[0] == 1: # [A_k, B_m] = A_{k+m} - A_{k-m} + if y[0] == 1: # [A_k, B_m] = A_{k+m} - A_{k-m} if y[1] == 0: # special case for m = 0, as A_k - A_k = 0 return self.zero() - d = {(0, x[1]-y[1]): -one, (0, y[1]+x[1]): one} + d = {(0, x[1] - y[1]): -one, (0, y[1] + x[1]): one} else: # [A_k, A_m] = B_{k-m} - B_{m-k} - d = {(1, x[1]-y[1]): one, (1, y[1]-x[1]): -one} + d = {(1, x[1] - y[1]): one, (1, y[1] - x[1]): -one} return self.element_class(self, d) def _coerce_map_from_(self, R): @@ -1307,7 +1247,7 @@ def _projection_on_basis(self, x): """ R = self.base_ring() O = OnsagerAlgebra(R) - if x[0] == 0: # A_k + if x[0] == 0: # A_k return O._from_dict({x: R.one()}, remove_zeros=False) # Otherwise B_k c = R.one() / 2 diff --git a/src/sage/algebras/lie_algebras/poincare_birkhoff_witt.py b/src/sage/algebras/lie_algebras/poincare_birkhoff_witt.py index 2fa3b0c8c0d..e628098ac71 100644 --- a/src/sage/algebras/lie_algebras/poincare_birkhoff_witt.py +++ b/src/sage/algebras/lie_algebras/poincare_birkhoff_witt.py @@ -7,7 +7,7 @@ - Travis Scrimshaw (2024-01-02): Adding the center """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2013-2024 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute @@ -108,6 +108,7 @@ class PoincareBirkhoffWittBasis(CombinatorialFreeModule): run any nontrivial sorting only once and avoid other potentially expensive comparisons between keys. """ + @staticmethod def __classcall_private__(cls, g, basis_key=None, prefix='PBW', **kwds): r""" @@ -149,12 +150,8 @@ def __init__(self, g, basis_key, prefix, **kwds): R = g.base_ring() self._g = g - monomials = IndexedFreeAbelianMonoid(g.basis().keys(), prefix, - sorting_key=self._monoid_key, **kwds) - CombinatorialFreeModule.__init__(self, R, monomials, - prefix='', bracket=False, latex_bracket=False, - sorting_key=self._monomial_key, - category=Algebras(R).WithBasis().Filtered()) + monomials = IndexedFreeAbelianMonoid(g.basis().keys(), prefix, sorting_key=self._monoid_key, **kwds) + CombinatorialFreeModule.__init__(self, R, monomials, prefix='', bracket=False, latex_bracket=False, sorting_key=self._monomial_key, category=Algebras(R).WithBasis().Filtered()) def _basis_key(self, x): """ @@ -197,7 +194,7 @@ def _basis_key(self, x): if self._basis_key_inverse is None: K = self._g.basis().keys() if isinstance(K, (list, tuple)) or K.cardinality() < float('inf'): - self._basis_key_inverse = {k: i for i,k in enumerate(K)} + self._basis_key_inverse = {k: i for i, k in enumerate(K)} else: self._basis_key_inverse = False if self._basis_key_inverse is False: @@ -274,6 +271,7 @@ def _latex_(self): PBW\left( \mathcal{W}(6)_{\Bold{F}_{3}} \right) """ from sage.misc.latex import latex + return r"PBW\left( {} \right)".format(latex(self._g)) def _coerce_map_from_(self, R): @@ -360,10 +358,9 @@ def basis_function(x): def inv_supp(m): return None if m.length() != 1 else m.leading_support() + # TODO: this diagonal, but with a smaller indexing set... - return self._g.module_morphism(basis_function, codomain=self, - triangular='upper', unitriangular=True, - inverse_on_support=inv_supp) + return self._g.module_morphism(basis_function, codomain=self, triangular='upper', unitriangular=True, inverse_on_support=inv_supp) coerce_map = self._g.coerce_map_from(R) if coerce_map: @@ -374,8 +371,8 @@ def inv_supp(m): I = self._indices def basis_function(x): - return self.prod(self.monomial(I.gen(g)**e) - for g, e in x._sorted_items()) + return self.prod(self.monomial(I.gen(g) ** e) for g, e in x._sorted_items()) + # TODO: this diagonal, but with a smaller indexing set... return R.module_morphism(basis_function, codomain=self) coerce_map = self._g.coerce_map_from(R._g) @@ -384,8 +381,8 @@ def basis_function(x): lift = self.coerce_map_from(self._g) def basis_function(x): - return self.prod(lift(coerce_map(g))**e - for g, e in x._sorted_items()) + return self.prod(lift(coerce_map(g)) ** e for g, e in x._sorted_items()) + # TODO: this diagonal, but with a smaller indexing set... return R.module_morphism(basis_function, codomain=self) @@ -416,8 +413,7 @@ def algebra_generators(self): Finite family {alpha[1]: PBW[alpha[1]], alphacheck[1]: PBW[alphacheck[1]], -alpha[1]: PBW[-alpha[1]]} """ G = self._indices.gens() - return Family(self._indices._indices, lambda x: self.monomial(G[x]), - name="generator map") + return Family(self._indices._indices, lambda x: self.monomial(G[x]), name="generator map") gens = algebra_generators @@ -502,7 +498,7 @@ def product_on_basis(self, lhs, rhs): lead = I.gen(lead) trail = I.gen(trail) mc = terms.monomial_coefficients(copy=False) - terms = self.sum_of_terms((I.gen(t), c) for t,c in mc.items()) + terms = self.sum_of_terms((I.gen(t), c) for t, c in mc.items()) terms += self.monomial(lead * trail) return self.monomial(lhs // trail) * terms * self.monomial(rhs // lead) @@ -561,6 +557,7 @@ def casimir_element(self, order=2, *args, **kwds): ValueError: the Lie algebra must be finite dimensional """ from sage.rings.infinity import Infinity + if self._g.dimension() == Infinity: raise ValueError("the Lie algebra must be finite dimensional") return self._g.casimir_element(order=order, UEA=self, *args, **kwds) @@ -588,6 +585,7 @@ def center(self): over Finite Field of size 3 in the Poincare-Birkhoff-Witt basis """ from sage.algebras.lie_algebras.center_uea import CenterUEA + return CenterUEA(self._g, self) class Element(CombinatorialFreeModule.Element): @@ -643,6 +641,7 @@ class PoincareBirkhoffWittBasisSemisimpleLieAlgebra(PoincareBirkhoffWittBasis): The Poincare-Birkhoff-Witt basis of a finite dimensional triangular Kac-Moody Lie algebra (i.e., a semisimple Lie algebra). """ + def __init__(self, g, basis_key=None, *args, **kwds): r""" Initialize ``self``. @@ -771,8 +770,7 @@ def _transpose_on_basis(self, m): """ I = self._indices basis_mapping = self._g._transpose_basis_mapping - return self.prod(self.monomial(I({basis_mapping[k]: e})) - for k, e in reversed(m._sorted_items())) + return self.prod(self.monomial(I({basis_mapping[k]: e})) for k, e in reversed(m._sorted_items())) @lazy_attribute def transpose(self): diff --git a/src/sage/algebras/lie_algebras/quotient.py b/src/sage/algebras/lie_algebras/quotient.py index 69bd9af9291..179f7162cf8 100644 --- a/src/sage/algebras/lie_algebras/quotient.py +++ b/src/sage/algebras/lie_algebras/quotient.py @@ -172,9 +172,9 @@ class LieQuotient_finite_dimensional_with_basis(LieAlgebraWithStructureCoefficie 2 sage: TestSuite(K).run() """ + @staticmethod - def __classcall_private__(cls, ambient, I, names=None, index_set=None, - index_set_mapping=None, category=None): + def __classcall_private__(cls, ambient, I, names=None, index_set=None, index_set_mapping=None, category=None): r""" Normalize input to ensure a unique representation. @@ -212,8 +212,7 @@ def __classcall_private__(cls, ambient, I, names=None, index_set=None, I = ambient.ideal(I) if not ambient.base_ring().is_field(): - raise NotImplementedError("quotients over non-fields " - "not implemented") + raise NotImplementedError("quotients over non-fields " "not implemented") # extract an index set from a complementary basis to the ideal I_supp = [X.leading_support() for X in I.leading_monomials()] @@ -236,8 +235,7 @@ def __classcall_private__(cls, ambient, I, names=None, index_set=None, if len(index_set) == 1: names = [names] else: - names = ['%s_%d' % (names, k + 1) - for k in range(len(index_set))] + names = ['%s_%d' % (names, k + 1) for k in range(len(index_set))] names, index_set = standardize_names_index_set(names, index_set) index_set_mapping = tuple([i for i in index_set_mapping if i[0] not in I_supp]) @@ -245,8 +243,7 @@ def __classcall_private__(cls, ambient, I, names=None, index_set=None, if ambient in LieAlgebras(ambient.base_ring()).Nilpotent(): cat = cat.Nilpotent() category = cat.Subquotients().or_subcategory(category) - return super().__classcall__(cls, ambient, I, names, index_set, - index_set_mapping, category=category) + return super().__classcall__(cls, ambient, I, names, index_set, index_set_mapping, category=category) def __init__(self, L, I, names, index_set, index_set_mapping, category=None): r""" @@ -262,8 +259,7 @@ def __init__(self, L, I, names, index_set, index_set_mapping, category=None): """ B = L.basis() self._index_set_mapping = dict(index_set_mapping) - sm = L.module().submodule_with_basis([I.reduce(B[k]).to_vector() - for k in self._index_set_mapping.values()]) + sm = L.module().submodule_with_basis([I.reduce(B[k]).to_vector() for k in self._index_set_mapping.values()]) SB = [L.from_vector(b) for b in sm.basis()] # compute and normalize structural coefficients for the quotient @@ -275,16 +271,14 @@ def __init__(self, L, I, names, index_set, index_set_mapping, category=None): brkt = I.reduce(SB[i].bracket(SB[j])) brktvec = sm.coordinate_vector(brkt.to_vector()) s_coeff[(ind_i, ind_j)] = dict(zip(index_set, brktvec)) - s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff( - s_coeff, index_set) + s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff(s_coeff, index_set) self._ambient = L self._I = I self._sm = sm self._triv_ideal = bool(I.dimension() == 0) - LieAlgebraWithStructureCoefficients.__init__( - self, L.base_ring(), s_coeff, names, index_set, category=category) + LieAlgebraWithStructureCoefficients.__init__(self, L.base_ring(), s_coeff, names, index_set, category=category) # register the quotient morphism as a conversion H = Hom(L, self) @@ -320,10 +314,7 @@ def _repr_(self): except AttributeError: ideal_repr = repr(tuple(self._I.gens())) - return ("Lie algebra quotient L/I of dimension %s" - " over %s where\nL: %s\nI: Ideal %s" % ( - self.dimension(), self.base_ring(), - self.ambient(), ideal_repr)) + return "Lie algebra quotient L/I of dimension %s" " over %s where\nL: %s\nI: Ideal %s" % (self.dimension(), self.base_ring(), self.ambient(), ideal_repr) def _repr_generator(self, i): r""" diff --git a/src/sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py b/src/sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py index b3fa2b0c7f4..4beaa8a506e 100644 --- a/src/sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py +++ b/src/sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py @@ -6,7 +6,7 @@ - Travis Scrimshaw (2018-08): Initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2018 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.cachefunc import cached_method from sage.categories.lie_algebras import LieAlgebras @@ -24,7 +24,7 @@ from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.structure.indexed_generators import IndexedGenerators from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement -from sage.algebras.lie_algebras.lie_algebra import (InfinitelyGeneratedLieAlgebra) +from sage.algebras.lie_algebras.lie_algebra import InfinitelyGeneratedLieAlgebra class RankTwoHeisenbergVirasoro(InfinitelyGeneratedLieAlgebra, IndexedGenerators): @@ -83,6 +83,7 @@ class RankTwoHeisenbergVirasoro(InfinitelyGeneratedLieAlgebra, IndexedGenerators - [LT2018]_ """ + def __init__(self, R): r""" Initialize ``self``. @@ -93,7 +94,7 @@ def __init__(self, R): sage: TestSuite(L).run() """ cat = LieAlgebras(R).WithBasis() - self._KI = FiniteEnumeratedSet([1,2,3,4]) + self._KI = FiniteEnumeratedSet([1, 2, 3, 4]) self._V = ZZ**2 d = {'K': self._KI, 'E': self._V, 't': self._V} indices = DisjointUnionEnumeratedSets(d, keepkey=True, facade=True) @@ -123,7 +124,7 @@ def _basis_key(self, x): return (0, x[1]) if x[0] == 't': return (1, tuple(x[1])) - return (2, tuple(x[1])) # x[0] == 'E' + return (2, tuple(x[1])) # x[0] == 'E' def _repr_term(self, m): r""" @@ -178,11 +179,11 @@ def _unicode_art_term(self, m): E(2,-4) """ from sage.typeset.unicode_art import unicode_art, unicode_subscript, unicode_superscript + if m[0] == 'K': return unicode_art('K' + unicode_subscript(m[1])) if m[0] == 't': - return unicode_art('t⁽{}˴{}⁾'.format(unicode_superscript(m[1][0]), - unicode_superscript(m[1][1]))) + return unicode_art('t⁽{}˴{}⁾'.format(unicode_superscript(m[1][0]), unicode_superscript(m[1][1]))) return unicode_art('E({},{})'.format(m[1][0], m[1][1])) def _repr_(self): @@ -225,7 +226,7 @@ def t(self, a, b): """ if a == b == 0: raise ValueError("no t(0, 0) element") - return self.monomial(('t', self._v(a,b))) + return self.monomial(('t', self._v(a, b))) def E(self, a, b): r""" @@ -239,7 +240,7 @@ def E(self, a, b): """ if a == b == 0: raise ValueError("no E(0, 0) element") - return self.monomial(('E', self._v(a,b))) + return self.monomial(('E', self._v(a, b))) def _v(self, a, b): r""" @@ -256,7 +257,7 @@ def _v(self, a, b): sage: hash(v) == hash(v) True """ - ret = self._V((a,b)) + ret = self._V((a, b)) ret.set_immutable() return ret @@ -295,20 +296,20 @@ def bracket_on_basis(self, i, j): if j[0] == 't': return self.zero() k = ('t', i[1] + j[1]) - if not k[1]: # == 0 - d = {('K',1): i[1][0], ('K',2): i[1][1]} # Kronecker delta summand + if not k[1]: # == 0 + d = {('K', 1): i[1][0], ('K', 2): i[1][1]} # Kronecker delta summand else: k[1].set_immutable() - d = {k: j[1][0]*i[1][1] - j[1][1]*i[1][0]} # determinant summand + d = {k: j[1][0] * i[1][1] - j[1][1] * i[1][0]} # determinant summand return self._from_dict(d) # else i[0] == 'E' k = ('E', i[1] + j[1]) - if not k[1]: # == 0 - d = {('K',3): i[1][0], ('K',4): i[1][1]} # Kronecker delta summand + if not k[1]: # == 0 + d = {('K', 3): i[1][0], ('K', 4): i[1][1]} # Kronecker delta summand else: k[1].set_immutable() - d = {k: (j[1][0]*i[1][1] - j[1][1]*i[1][0])} # determinant summand + d = {k: (j[1][0] * i[1][1] - j[1][1] * i[1][0])} # determinant summand return self._from_dict(d) def _an_element_(self): @@ -323,12 +324,7 @@ def _an_element_(self): """ d = self.monomial v = self._v - return ( - d(('E',v(1,-3))) - - self.base_ring().an_element() * d(('t',v(-1,3))) - + d(('E',v(2,2))) - + d(('K',3)) - ) + return d(('E', v(1, -3))) - self.base_ring().an_element() * d(('t', v(-1, 3))) + d(('E', v(2, 2))) + d(('K', 3)) def some_elements(self): r""" @@ -345,9 +341,7 @@ def some_elements(self): """ d = self.monomial v = self._v - return [d(('E',v(1,1))), d(('E',v(-2,-2))), d(('E',v(0,1))), - d(('t',v(1,1))), d(('t',v(4,-1))), d(('t',v(2,3))), - d(('K',2)), d(('K',4)), self.an_element()] + return [d(('E', v(1, 1))), d(('E', v(-2, -2))), d(('E', v(0, 1))), d(('t', v(1, 1))), d(('t', v(4, -1))), d(('t', v(2, 3))), d(('K', 2)), d(('K', 4)), self.an_element()] class Element(LieAlgebraElement): pass diff --git a/src/sage/algebras/lie_algebras/representation.py b/src/sage/algebras/lie_algebras/representation.py index f889a219ab2..8a5b163f023 100644 --- a/src/sage/algebras/lie_algebras/representation.py +++ b/src/sage/algebras/lie_algebras/representation.py @@ -31,6 +31,7 @@ class Representation_abstract: - ``lie_algebra`` -- a Lie algebra """ + def __init__(self, lie_algebra): r""" Initialize ``self``. @@ -89,6 +90,7 @@ def _test_representation(self, **options): if elts.cardinality() == float('inf'): elts = list(elts.some_elements()) from sage.misc.misc import some_tuples + for x, y in some_tuples(elts, 2, tester._max_runs): for v in S: tester.assertEqual(x.bracket(y) * v, x * (y * v) - y * (x * v)) @@ -207,6 +209,7 @@ class RepresentationByMorphism(CombinatorialFreeModule, Representation_abstract) R[1] + 5*R[2] - 3*R[3] sage: R._test_representation() # verify that it is a representation """ + @staticmethod def __classcall_private__(cls, lie_algebra, f=None, index_set=None, on_basis=False, **kwargs): r""" @@ -247,6 +250,7 @@ def __classcall_private__(cls, lie_algebra, f=None, index_set=None, on_basis=Fal ValueError: the index set needs to be specified """ from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + base = lie_algebra.base_ring() C = Modules(base).WithBasis().FiniteDimensional() C = C.or_subcategory(kwargs.pop('category', C)) @@ -285,8 +289,7 @@ def __classcall_private__(cls, lie_algebra, f=None, index_set=None, on_basis=Fal index_set = FiniteEnumeratedSet(index_set) - return super(cls, RepresentationByMorphism).__classcall__(cls, lie_algebra, - f, index_set, on_basis, category=C, **kwargs) + return super(cls, RepresentationByMorphism).__classcall__(cls, lie_algebra, f, index_set, on_basis, category=C, **kwargs) def __init__(self, lie_algebra, f, index_set, on_basis, category, **kwargs): r""" @@ -308,8 +311,7 @@ def __init__(self, lie_algebra, f, index_set, on_basis, category, **kwargs): self._on_basis = on_basis Representation_abstract.__init__(self, lie_algebra) - CombinatorialFreeModule.__init__(self, lie_algebra.base_ring(), index_set, - category=category, prefix=prefix, **kwargs) + CombinatorialFreeModule.__init__(self, lie_algebra.base_ring(), index_set, category=category, prefix=prefix, **kwargs) def _repr_(self): r""" @@ -338,6 +340,7 @@ def _repr_(self): """ ret = "Representation of {} defined by:".format(self._lie_algebra) from sage.typeset.ascii_art import ascii_art + if self._on_basis: B = self._lie_algebra.basis() if B.cardinality() < float('inf'): @@ -419,6 +422,7 @@ class TrivialRepresentation(CombinatorialFreeModule, Representation_abstract): - :wikipedia:`Trivial_representation` """ + def __init__(self, lie_algebra, **kwargs): r""" Initialize ``self``. @@ -540,6 +544,7 @@ class FaithfulRepresentationNilpotentPBW(CombinatorialFreeModule, Representation - [BEdG2009]_ """ + def __init__(self, L, minimal=False): r""" Initialize ``self``. @@ -598,10 +603,11 @@ def __init__(self, L, minimal=False): self._invcob = cob.inverse() scoeffs = {} for i, b in enumerate(L_basis): - for j, bp in enumerate(L_basis[i+1:], start=i + 1): + for j, bp in enumerate(L_basis[i + 1 :], start=i + 1): scoeffs[i, j] = (self._invcob * b.bracket(bp)._vector_()).dict() index_set = tuple(range(L.dimension())) from sage.algebras.lie_algebras.lie_algebra import LieAlgebra + self._Lp = LieAlgebra(L.base_ring(), scoeffs, index_set=index_set) self._pbw = self._Lp.pbw_basis() @@ -609,8 +615,8 @@ def __init__(self, L, minimal=False): from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.combinat.integer_vector_weighted import WeightedIntegerVectors - indices = DisjointUnionEnumeratedSets([WeightedIntegerVectors(n, self._degrees) - for n in range(self._step+1)]) + + indices = DisjointUnionEnumeratedSets([WeightedIntegerVectors(n, self._degrees) for n in range(self._step + 1)]) if self._minimal: X = {tuple(index) for index in indices} @@ -678,6 +684,7 @@ def _latex_(self): U(\text{\texttt{Heisenberg...}}) / U(\text{\texttt{Heisenberg...}})^{3} """ from sage.misc.latex import latex + g = latex(self._lie_algebra) ret = "U({0}) / U({0})^{{{1}}}".format(g, self._step + 1) if self._minimal: @@ -757,8 +764,7 @@ def _lift_pbw(self): P = self.parent() monoid = P._pbw._indices I = monoid._indices - return P._pbw.element_class(P._pbw, {monoid(list(zip(I, m))): coeff - for m, coeff in self._monomial_coefficients.items()}) + return P._pbw.element_class(P._pbw, {monoid(list(zip(I, m))): coeff for m, coeff in self._monomial_coefficients.items()}) def _acted_upon_(self, scalar, self_on_left=False): r""" @@ -820,6 +826,7 @@ class FaithfulRepresentationPBWPosChar(CombinatorialFreeModule, Representation_a sage: F.dimension() 243 """ + def __init__(self, L): r""" Initialize ``self``. @@ -849,22 +856,21 @@ def __init__(self, L): d = g.degree() # TODO: Use the sparse polynomial ring? x = g.parent().gen() - r = [x**(self._p**i) % g for i in range(d+1)] + r = [x ** (self._p**i) % g for i in range(d + 1)] deg = max(ri.degree() for ri in r) - mat = matrix(R, [[ri[j] for ri in r] for j in range(deg+1)]) + mat = matrix(R, [[ri[j] for ri in r] for j in range(deg + 1)]) la = mat.right_kernel_matrix()[0] if la: mongen = self._pbw._indices.monoid_generators()[k] - gb.append(self._pbw._from_dict({mongen ** (self._p ** i): val - for i, val in enumerate(la) if val}, - remove_zeros=False)) + gb.append(self._pbw._from_dict({mongen ** (self._p**i): val for i, val in enumerate(la) if val}, remove_zeros=False)) p_exp.append(max(la.support())) self._groebner_basis = gb self._p_exp = tuple(p_exp) - self._degrees = [self._p ** m for m in self._p_exp] + self._degrees = [self._p**m for m in self._p_exp] from sage.groups.abelian_gps.abelian_group import AbelianGroup + indices = AbelianGroup(self._degrees) Representation_abstract.__init__(self, L) @@ -896,6 +902,7 @@ def _latex_(self): PBW_{-\alpha_{1}}^{3} \rangle """ from sage.misc.latex import latex + g = latex(self._lie_algebra) data = ', '.join(latex(f) for f in self._groebner_basis) return "U({}) / \\langle {} \\rangle".format(g, data) @@ -1022,8 +1029,7 @@ def _acted_upon_(self, scalar, self_on_left=False): scalar = P._pbw(scalar) monoid = P._pbw._indices I = P._key_order - lift = P._pbw.element_class(P._pbw, {monoid(list(zip(I, m.exponents()))): coeff - for m, coeff in self._monomial_coefficients.items()}) + lift = P._pbw.element_class(P._pbw, {monoid(list(zip(I, m.exponents()))): coeff for m, coeff in self._monomial_coefficients.items()}) return P._project(scalar * lift) return super()._acted_upon_(scalar, self_on_left) diff --git a/src/sage/algebras/lie_algebras/structure_coefficients.py b/src/sage/algebras/lie_algebras/structure_coefficients.py index 32600ac7e26..d289ab6d011 100644 --- a/src/sage/algebras/lie_algebras/structure_coefficients.py +++ b/src/sage/algebras/lie_algebras/structure_coefficients.py @@ -6,7 +6,7 @@ - Travis Scrimshaw (2013-05-03): Initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2013-2017 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -14,20 +14,21 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.cachefunc import cached_method -#from sage.misc.lazy_attribute import lazy_attribute -from sage.structure.indexed_generators import (IndexedGenerators, - standardize_names_index_set) + +# from sage.misc.lazy_attribute import lazy_attribute +from sage.structure.indexed_generators import IndexedGenerators, standardize_names_index_set from sage.categories.lie_algebras import LieAlgebras from sage.algebras.lie_algebras.lie_algebra_element import StructureCoefficientsElement from sage.algebras.lie_algebras.lie_algebra import FinitelyGeneratedLieAlgebra -#from sage.algebras.lie_algebras.subalgebra import LieSubalgebra -#from sage.algebras.lie_algebras.ideal import LieAlgebraIdeal -#from sage.algebras.lie_algebras.quotient import QuotientLieAlgebra + +# from sage.algebras.lie_algebras.subalgebra import LieSubalgebra +# from sage.algebras.lie_algebras.ideal import LieAlgebraIdeal +# from sage.algebras.lie_algebras.quotient import QuotientLieAlgebra from sage.modules.free_module import FreeModule from sage.sets.family import Family @@ -97,6 +98,7 @@ class LieAlgebraWithStructureCoefficients(FinitelyGeneratedLieAlgebra, IndexedGe sage: L.basis() Finite family {'x': x, 'y': y} """ + @staticmethod def __classcall_private__(cls, R, s_coeff, names=None, index_set=None, **kwds): """ @@ -120,11 +122,10 @@ def __classcall_private__(cls, R, s_coeff, names=None, index_set=None, **kwds): # Make sure the structure coefficients are given by the index set if names is not None and names != tuple(index_set): - d = {x: index_set[i] for i,x in enumerate(names)} + d = {x: index_set[i] for i, x in enumerate(names)} get_pairs = lambda X: X.items() if isinstance(X, dict) else X try: - s_coeff = {(d[k[0]], d[k[1]]): [(d[x], y) for x,y in get_pairs(s_coeff[k])] - for k in s_coeff} + s_coeff = {(d[k[0]], d[k[1]]): [(d[x], y) for x, y in get_pairs(s_coeff[k])] for k in s_coeff} except (KeyError, ValueError): # At this point we assume they are given by the index set pass @@ -132,10 +133,12 @@ def __classcall_private__(cls, R, s_coeff, names=None, index_set=None, **kwds): s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff(s_coeff, index_set) if s_coeff.cardinality() == 0: from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra + return AbelianLieAlgebra(R, names, index_set, **kwds) if (names is None and len(index_set) <= 1) or (names is not None and len(names) <= 1): from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra + return AbelianLieAlgebra(R, names, index_set, **kwds) return super().__classcall__(cls, R, s_coeff, names, index_set, **kwds) @@ -157,10 +160,10 @@ def _standardize_s_coeff(s_coeff, index_set): Finite family {('x', 'y'): (('x', 1),)} """ # Try to handle infinite basis (once/if supported) - #if isinstance(s_coeff, AbstractFamily) and s_coeff.cardinality() == infinity: + # if isinstance(s_coeff, AbstractFamily) and s_coeff.cardinality() == infinity: # return s_coeff - index_to_pos = {k: i for i,k in enumerate(index_set)} + index_to_pos = {k: i for i, k in enumerate(index_set)} sc = {} # Make sure the first gen is smaller than the second in each key @@ -188,8 +191,7 @@ def _standardize_s_coeff(s_coeff, index_set): sc[key] = vals return Family(sc) - def __init__(self, R, s_coeff, names, index_set, category=None, prefix=None, - bracket=None, latex_bracket=None, string_quotes=None, **kwds): + def __init__(self, R, s_coeff, names, index_set, category=None, prefix=None, bracket=None, latex_bracket=None, string_quotes=None, **kwds): """ Initialize ``self``. @@ -198,7 +200,7 @@ def __init__(self, R, s_coeff, names, index_set, category=None, prefix=None, sage: L = LieAlgebra(QQ, 'x,y', {('x','y'): {'x':1}}) sage: TestSuite(L).run() """ - default = (names != tuple(index_set)) + default = names != tuple(index_set) if prefix is None: if default: prefix = 'L' @@ -211,30 +213,27 @@ def __init__(self, R, s_coeff, names, index_set, category=None, prefix=None, if string_quotes is None: string_quotes = default - #self._pos_to_index = dict(enumerate(index_set)) - self._index_to_pos = {k: i for i,k in enumerate(index_set)} + # self._pos_to_index = dict(enumerate(index_set)) + self._index_to_pos = {k: i for i, k in enumerate(index_set)} if "sorting_key" not in kwds: kwds["sorting_key"] = self._index_to_pos.__getitem__ cat = LieAlgebras(R).WithBasis().FiniteDimensional().or_subcategory(category) FinitelyGeneratedLieAlgebra.__init__(self, R, names, index_set, cat) - IndexedGenerators.__init__(self, self._indices, prefix=prefix, - bracket=bracket, latex_bracket=latex_bracket, - string_quotes=string_quotes, **kwds) + IndexedGenerators.__init__(self, self._indices, prefix=prefix, bracket=bracket, latex_bracket=latex_bracket, string_quotes=string_quotes, **kwds) self._M = FreeModule(R, len(index_set)) # Transform the values in the structure coefficients to elements def to_vector(tuples): - vec = [R.zero()]*len(index_set) - for k,c in tuples: + vec = [R.zero()] * len(index_set) + for k, c in tuples: vec[self._index_to_pos[k]] = c vec = self._M(vec) vec.set_immutable() return vec - self._s_coeff = {(self._index_to_pos[k[0]], self._index_to_pos[k[1]]): - to_vector(s_coeff[k]) - for k in s_coeff.keys()} + + self._s_coeff = {(self._index_to_pos[k[0]], self._index_to_pos[k[1]]): to_vector(s_coeff[k]) for k in s_coeff.keys()} # For compatibility with CombinatorialFreeModuleElement _repr_term = IndexedGenerators._repr_generator @@ -264,20 +263,18 @@ def structure_coefficients(self, include_zeros=False): """ if not include_zeros: pos_to_index = dict(enumerate(self._indices)) - return Family({(pos_to_index[k[0]], pos_to_index[k[1]]): - self.element_class(self, self._s_coeff[k]) - for k in self._s_coeff}) + return Family({(pos_to_index[k[0]], pos_to_index[k[1]]): self.element_class(self, self._s_coeff[k]) for k in self._s_coeff}) ret = {} zero = self._M.zero() - for i,x in enumerate(self._indices): - for j, y in enumerate(self._indices[i+1:]): - if (i, j+i+1) in self._s_coeff: - elt = self._s_coeff[i, j+i+1] - elif (j+i+1, i) in self._s_coeff: - elt = -self._s_coeff[j+i+1, i] + for i, x in enumerate(self._indices): + for j, y in enumerate(self._indices[i + 1 :]): + if (i, j + i + 1) in self._s_coeff: + elt = self._s_coeff[i, j + i + 1] + elif (j + i + 1, i) in self._s_coeff: + elt = -self._s_coeff[j + i + 1, i] else: elt = zero - ret[x,y] = self.element_class(self, elt) # +i+1 for offset + ret[x, y] = self.element_class(self, elt) # +i+1 for offset return Family(ret) def dimension(self): @@ -416,9 +413,7 @@ def change_ring(self, R): sage: LSR.structure_coefficients() Finite family {('x', 'y'): z} """ - return LieAlgebraWithStructureCoefficients( - R, self.structure_coefficients(), - names=self.variable_names(), index_set=self.indices()) + return LieAlgebraWithStructureCoefficients(R, self.structure_coefficients(), names=self.variable_names(), index_set=self.indices()) class Element(StructureCoefficientsElement): def _sorted_items_for_printing(self): @@ -449,9 +444,7 @@ def _sorted_items_for_printing(self): pos_to_index = dict(enumerate(self.parent()._indices)) v = [(pos_to_index[k], c) for k, c in self.value.items()] try: - v.sort(key=lambda monomial_coeff: - print_options['sorting_key'](monomial_coeff[0]), - reverse=print_options['sorting_reverse']) - except Exception: # Sorting the output is a plus, but if we can't, no big deal + v.sort(key=lambda monomial_coeff: print_options['sorting_key'](monomial_coeff[0]), reverse=print_options['sorting_reverse']) + except Exception: # Sorting the output is a plus, but if we can't, no big deal pass return v diff --git a/src/sage/algebras/lie_algebras/subalgebra.py b/src/sage/algebras/lie_algebras/subalgebra.py index 867b0fcc4cd..cdd2af7fdd3 100644 --- a/src/sage/algebras/lie_algebras/subalgebra.py +++ b/src/sage/algebras/lie_algebras/subalgebra.py @@ -7,6 +7,7 @@ - Travis Scrimshaw (2025-05-21): make all Lie subalgebras use elements in the ambient Lie algebra """ + # **************************************************************************** # Copyright (C) 2018 Eero Hakavuori # 2025 Travis Scrimshaw @@ -167,9 +168,9 @@ class LieSubalgebra_finite_dimensional_with_basis(Parent, UniqueRepresentation): sage: J.reduce(I(Z) + I(W)) W """ + @staticmethod - def __classcall_private__(cls, ambient, gens, ideal_of=None, - order=None, category=None): + def __classcall_private__(cls, ambient, gens, ideal_of=None, order=None, category=None): """ Normalize input to ensure a unique representation. @@ -255,11 +256,9 @@ def __classcall_private__(cls, ambient, gens, ideal_of=None, if ambient in LieAlgebras(ambient.base_ring()).Nilpotent(): category = category.Nilpotent() - return super().__classcall__(cls, ambient, gens, ideal_of, - order, category) + return super().__classcall__(cls, ambient, gens, ideal_of, order, category) - def __init__(self, ambient, gens, ideal_of, - order=None, category=None) -> None: + def __init__(self, ambient, gens, ideal_of, order=None, category=None) -> None: r""" Initialize ``self``. @@ -286,11 +285,9 @@ def __init__(self, ambient, gens, ideal_of, else: order = lambda x: x self._order = order - self._reversed_indices = sorted(ambient.indices(), key=order, - reverse=True) + self._reversed_indices = sorted(ambient.indices(), key=order, reverse=True) # helper to reorder a vector that has been jumbled by the above - self._reorganized_indices = [self._reversed_indices.index(i) - for i in ambient.indices()] + self._reorganized_indices = [self._reversed_indices.index(i) for i in ambient.indices()] super().__init__(ambient.base_ring(), category=category) @@ -491,8 +488,7 @@ def _to_m(self, X): M = self._ambient.module() R = M.base_ring() B = M.basis() - return M.sum(R(mc[self._reversed_indices[i]]) * B[i] - for i in range(len(B)) if self._reversed_indices[i] in mc) + return M.sum(R(mc[self._reversed_indices[i]]) * B[i] for i in range(len(B)) if self._reversed_indices[i] in mc) def _from_m(self, v): r""" @@ -532,8 +528,7 @@ def _from_m(self, v): R = M.base_ring() v_self = M.coordinate_vector(v) B = M.basis() - v_sorted = M.sum(R(v_self[self._reorganized_indices[i]]) * B[i] - for i in range(len(B))) + v_sorted = M.sum(R(v_self[self._reorganized_indices[i]]) * B[i] for i in range(len(B))) return L.from_vector(v_sorted) @lazy_attribute @@ -745,12 +740,10 @@ def basis(self): if self._ideal_of is None: B = SB - brackets = [self._to_m(ambient.bracket(self._from_m(v), self._from_m(w))) - for v in B for w in SB] + brackets = [self._to_m(ambient.bracket(self._from_m(v), self._from_m(w))) for v in B for w in SB] sm = m.submodule(sm.basis() + brackets) - basis = [self.element_class(self, self._from_m(v)) - for v in sm.echelonized_basis()] + basis = [self.element_class(self, self._from_m(v)) for v in sm.echelonized_basis()] indices = [self.lift(X).leading_support(key=self._order) for X in basis] basis = dict(zip(indices, basis)) @@ -784,8 +777,7 @@ def leading_monomials(self): sage: I.leading_monomials() Family (d, c, a) """ - return Family(self.lift(X).leading_monomial(key=self._order) - for X in self.basis()) + return Family(self.lift(X).leading_monomial(key=self._order) for X in self.basis()) def from_vector(self, v, order=None, coerce=False): r""" @@ -960,6 +952,4 @@ def adjoint_matrix(self, sparse=False): P = self.parent() basis = P.basis() M = P.module(sparse=sparse) - return matrix(self.base_ring(), - [M.coordinate_vector(P.bracket(self, b).to_vector(sparse=sparse)) - for b in basis], sparse=sparse).transpose() + return matrix(self.base_ring(), [M.coordinate_vector(P.bracket(self, b).to_vector(sparse=sparse)) for b in basis], sparse=sparse).transpose() diff --git a/src/sage/algebras/lie_algebras/symplectic_derivation.py b/src/sage/algebras/lie_algebras/symplectic_derivation.py index af294c4c4b0..a03cd437aff 100644 --- a/src/sage/algebras/lie_algebras/symplectic_derivation.py +++ b/src/sage/algebras/lie_algebras/symplectic_derivation.py @@ -90,6 +90,7 @@ class SymplecticDerivationLieAlgebra(InfinitelyGeneratedLieAlgebra, IndexedGener - [Harako2020]_ """ + def __init__(self, R, g): r""" Initialize ``self``. @@ -103,7 +104,7 @@ def __init__(self, R, g): raise ValueError("g must be at least 4") cat = LieAlgebras(R).WithBasis().Graded() self._g = g - d = Family(NonNegativeIntegers(), lambda n: Partitions(n, min_length=2, max_part=2*g)) + d = Family(NonNegativeIntegers(), lambda n: Partitions(n, min_length=2, max_part=2 * g)) indices = DisjointUnionEnumeratedSets(d) InfinitelyGeneratedLieAlgebra.__init__(self, R, index_set=indices, category=cat) IndexedGenerators.__init__(self, indices, sorting_key=self._basis_key) @@ -138,7 +139,8 @@ def _repr_term(self, m): g = self._g def label(i): - return "a{}".format(i) if i <= g else "b{}".format(i-g) + return "a{}".format(i) if i <= g else "b{}".format(i - g) + return "*".join(label(i) for i in reversed(m)) def _latex_term(self, m): @@ -154,7 +156,8 @@ def _latex_term(self, m): g = self._g def label(i): - return "a_{{{}}}".format(i) if i <= g else "b_{{{}}}".format(i-g) + return "a_{{{}}}".format(i) if i <= g else "b_{{{}}}".format(i - g) + return " ".join(label(i) for i in reversed(m)) def _unicode_art_term(self, m): @@ -168,10 +171,12 @@ def _unicode_art_term(self, m): a₁·a₂·a₅·b₂ """ from sage.typeset.unicode_art import unicode_art, unicode_subscript + g = self._g def label(i): - return "a{}".format(unicode_subscript(i)) if i <= g else "b{}".format(unicode_subscript(i-g)) + return "a{}".format(unicode_subscript(i)) if i <= g else "b{}".format(unicode_subscript(i - g)) + return unicode_art("·".join(label(i) for i in reversed(m))) def _repr_(self): @@ -226,23 +231,23 @@ def bracket_on_basis(self, x, y): g = self._g ret = {} one = self.base_ring().one() - for i,xi in enumerate(x): - for j,yj in enumerate(y): + for i, xi in enumerate(x): + for j, yj in enumerate(y): # The symplectic form will be 0 if (xi <= g and yj <= g) or (xi > g and yj > g): continue if xi <= g and yj > g: if xi != yj - g: continue - m = _Partitions(sorted(x[:i] + x[i+1:] + y[:j] + y[j+1:], reverse=True)) + m = _Partitions(sorted(x[:i] + x[i + 1 :] + y[:j] + y[j + 1 :], reverse=True)) if m in ret: ret[m] += one else: ret[m] = one - else: # if ci > g and yj <= g: + else: # if ci > g and yj <= g: if xi - g != yj: continue - m = _Partitions(sorted(x[:i] + x[i+1:] + y[:j] + y[j+1:], reverse=True)) + m = _Partitions(sorted(x[:i] + x[i + 1 :] + y[:j] + y[j + 1 :], reverse=True)) if m in ret: ret[m] -= one else: @@ -260,11 +265,7 @@ def _an_element_(self): a1*a2 - 1/2*a1*a2*a2*a5 + a1*a1*a2*b1*b4 """ d = self.monomial - return ( - d(_Partitions([2,1])) - - self.base_ring().an_element() * d(_Partitions([5,2,2,1])) - + d(_Partitions([2*self._g-1, self._g+1, 2, 1, 1])) - ) + return d(_Partitions([2, 1])) - self.base_ring().an_element() * d(_Partitions([5, 2, 2, 1])) + d(_Partitions([2 * self._g - 1, self._g + 1, 2, 1, 1])) def some_elements(self): r""" @@ -279,9 +280,7 @@ def some_elements(self): """ d = self.monomial g = self._g - return [d(_Partitions([2,1])), d(_Partitions([g+3,g+1])), d(_Partitions([2,1,1])), - d(_Partitions([2*g-1,2*g-2])), d(_Partitions([2*g-2,g-1,1])), - self.an_element()] + return [d(_Partitions([2, 1])), d(_Partitions([g + 3, g + 1])), d(_Partitions([2, 1, 1])), d(_Partitions([2 * g - 1, 2 * g - 2])), d(_Partitions([2 * g - 2, g - 1, 1])), self.an_element()] class Element(LieAlgebraElement): pass diff --git a/src/sage/algebras/lie_algebras/verma_module.py b/src/sage/algebras/lie_algebras/verma_module.py index 85054716e03..ae896262405 100644 --- a/src/sage/algebras/lie_algebras/verma_module.py +++ b/src/sage/algebras/lie_algebras/verma_module.py @@ -37,6 +37,7 @@ class ModulePrinting: """ Helper mixin class for printing the module vectors. """ + def __init__(self, vector_name='v'): r""" Initialize ``self``. @@ -100,6 +101,7 @@ def _latex_generator(self, m): if ret == '1': ret = '' from sage.misc.latex import latex + return ret + " {}_{{{}}}".format(self.__vector_name, latex(self._weight)) _repr_term = _repr_generator @@ -153,6 +155,7 @@ class VermaModule(ModulePrinting, CombinatorialFreeModule): - :wikipedia:`Verma_module` """ + def __init__(self, g, weight, basis_key=None, prefix='f', **kwds): """ Initialize ``self``. @@ -181,14 +184,8 @@ def __init__(self, g, weight, basis_key=None, prefix='f', **kwds): R = g.base_ring() self._g = g self._pbw = g.pbw_basis(basis_key=self._triangular_key) - monomials = IndexedFreeAbelianMonoid(g._negative_half_index_set(), - prefix, - sorting_key=self._monoid_key, - **kwds) - CombinatorialFreeModule.__init__(self, R, monomials, - prefix='', bracket=False, latex_bracket=False, - sorting_key=self._monomial_key, - category=Modules(R).WithBasis().Graded()) + monomials = IndexedFreeAbelianMonoid(g._negative_half_index_set(), prefix, sorting_key=self._monoid_key, **kwds) + CombinatorialFreeModule.__init__(self, R, monomials, prefix='', bracket=False, latex_bracket=False, sorting_key=self._monomial_key, category=Modules(R).WithBasis().Graded()) ModulePrinting.__init__(self) def _triangular_key(self, x): @@ -303,6 +300,7 @@ def _latex_(self): M_{2 \Lambda_{1} + 7 \Lambda_{4} - \frac{3}{4} \Lambda_{7}} """ from sage.misc.latex import latex + return "M_{{{}}}".format(latex(self._weight)) def lie_algebra(self): @@ -351,8 +349,7 @@ def highest_weight_vector(self): v[Lambda[1] - 3*Lambda[2]] """ one = self.base_ring().one() - return self._from_dict({self._indices.one(): one}, - remove_zeros=False, coerce=False) + return self._from_dict({self._indices.one(): one}, remove_zeros=False, coerce=False) def gens(self) -> tuple: r""" @@ -400,6 +397,7 @@ def dual(self): if self.is_simple(): return self from sage.algebras.lie_algebras.bgg_dual_module import BGGDualModule + return BGGDualModule(self) def degree_on_basis(self, m): @@ -423,8 +421,7 @@ def degree_on_basis(self, m): -Lambda[1] + 3*Lambda[2] """ P = self._weight.parent() - return self._weight + P.sum(P(e * self._g.degree_on_basis(k)) - for k,e in m.dict().items()) + return self._weight + P.sum(P(e * self._g.degree_on_basis(k)) for k, e in m.dict().items()) def _coerce_map_from_(self, R): r""" @@ -525,8 +522,7 @@ def contravariant_form(self, x, y): univ = pbw.contravariant_form(xlift, ylift) la = self._weight R = self.base_ring() - return R.sum(c * R.prod(la.scalar(k) ** e for k, e in m._monomial.items()) - for m, c in univ._monomial_coefficients.items()) + return R.sum(c * R.prod(la.scalar(k) ** e for k, e in m._monomial.items()) for m, c in univ._monomial_coefficients.items()) @lazy_attribute def _dominant_data(self): @@ -707,15 +703,14 @@ def degree(m): m = m.dict() if not m: return d.parent().zero() - return sum(e * self._g.degree_on_basis(k) - for k, e in m.items()).to_vector() + return sum(e * self._g.degree_on_basis(k) for k, e in m.items()).to_vector() + for i, fi in f.items(): if d[i] == 0: continue for b in self._homogeneous_component_f(d + basis[i]): temp = fi * b - ret.update([self.monomial(m) for m in temp.support() - if degree(m) == d]) + ret.update([self.monomial(m) for m in temp.support() if degree(m) == d]) return frozenset(ret) def _Hom_(self, Y, category=None, **options): @@ -747,9 +742,8 @@ def _Hom_(self, Y, category=None, **options): <...VermaModuleHomset_with_category_with_equality_by_id'> """ from sage.algebras.lie_algebras.bgg_dual_module import BGGDualModule, SimpleModule - if not ((isinstance(Y, (VermaModule, SimpleModule)) - or (isinstance(Y, BGGDualModule) and Y._module is self)) - and self._g is Y.lie_algebra()): + + if not ((isinstance(Y, (VermaModule, SimpleModule)) or (isinstance(Y, BGGDualModule) and Y._module is self)) and self._g is Y.lie_algebra()): raise TypeError("{} must be an object in Category O of {}".format(Y, self._g)) if category is not None and not category.is_subcategory(self.category()): raise TypeError("{} is not a subcategory of {}".format(category, self.category())) @@ -801,8 +795,7 @@ def _acted_upon_(self, scalar, self_on_left=False): scalar = P._pbw(scalar) except (ValueError, TypeError): # Cannot be made into a PBW element, so propagate it up - return CombinatorialFreeModule.Element._acted_upon_(self, - scalar, self_on_left) + return CombinatorialFreeModule.Element._acted_upon_(self, scalar, self_on_left) # We only implement x * self, i.e., as a left module if self_on_left: @@ -810,7 +803,7 @@ def _acted_upon_(self, scalar, self_on_left=False): # Lift ``self`` to the PBW basis and do multiplication there mc = self._monomial_coefficients - d = {P._pbw._indices(x.dict()): mc[x] for x in mc} # Lift the index set + d = {P._pbw._indices(x.dict()): mc[x] for x in mc} # Lift the index set ret = scalar * P._pbw._from_dict(d, remove_zeros=False, coerce=False) # Now have ``ret`` act on the highest weight vector @@ -824,7 +817,7 @@ def _acted_upon_(self, scalar, self_on_left=False): mp = None break if part == 0: - c *= P._g._weight_action(k, P._weight)**e + c *= P._g._weight_action(k, P._weight) ** e else: mp[k] = e # This term is 0, so nothing to do @@ -850,6 +843,7 @@ class VermaModuleMorphism(Morphism): r""" A morphism of a Verma module to another module in Category `\mathcal{O}`. """ + def __init__(self, parent, scalar): """ Initialize ``self``. @@ -967,8 +961,7 @@ def _call_(self, x): if not self._scalar or not self.parent().highest_weight_image(): return self.codomain().zero() mc = x.monomial_coefficients(copy=False) - return self.codomain().linear_combination((self._on_basis(m), self._scalar * c) - for m,c in mc.items()) + return self.codomain().linear_combination((self._on_basis(m), self._scalar * c) for m, c in mc.items()) def _on_basis(self, m): r""" @@ -1078,8 +1071,7 @@ def _composition_(self, right, homset): sage: xi._scalar 0 """ - if (isinstance(right, VermaModuleMorphism) - and right.domain()._g is self.codomain()._g): + if isinstance(right, VermaModuleMorphism) and right.domain()._g is self.codomain()._g: return homset.element_class(homset, right._scalar * self._scalar) return super()._composition_(right, homset) @@ -1145,6 +1137,7 @@ def is_surjective(self) -> bool: return self.domain() == self.codomain() from sage.algebras.lie_algebras.bgg_dual_module import SimpleModule + if isinstance(self.codomain(), SimpleModule): return self.domain().highest_weight() == self.codomain().highest_weight() @@ -1183,9 +1176,9 @@ def image(self): raise NotImplementedError("submodules of Verma modules not yet implemented") from sage.algebras.lie_algebras.bgg_dual_module import BGGDualModule, SimpleModule + if isinstance(C, BGGDualModule) and isinstance(C._module, VermaModule): - return SimpleModule(C.lie_algebra(), C.highest_weight(), prefix=C._indices.prefix(), - basis_key=C._module._basis_key) + return SimpleModule(C.lie_algebra(), C.highest_weight(), prefix=C._indices.prefix(), basis_key=C._module._basis_key) if isinstance(self.codomain(), SimpleModule): return self.codomain() @@ -1214,6 +1207,7 @@ class VermaModuleHomset(Homset): homset is `\delta_{\lambda\mu}` dimensional. When `\mu = \lambda`, the image is the simple module `L_{\lambda}`. """ + def __call__(self, x, **options): r""" Construct a morphism in this homset from ``x`` if possible. @@ -1253,7 +1247,7 @@ def __call__(self, x, **options): if x.parent() is self: return x if x.parent() == self: - x._set_parent(self) # needed due to non-uniqueness of homsets + x._set_parent(self) # needed due to non-uniqueness of homsets return x if x.domain() != self.domain(): @@ -1427,6 +1421,7 @@ def singular_vector(self): from sage.combinat.root_system.coxeter_group import CoxeterGroup from sage.matrix.constructor import matrix + W = CoxeterGroup(self.domain()._g._cartan_type) # We take the inverse to account for the left versus right action wp = W.from_reduced_word(reversed(self.domain()._dominant_data[1])) @@ -1444,9 +1439,9 @@ def singular_vector(self): elt = pbw.one() wt = C._weight pos_roots_by_ht = C._g._cartan_type.root_system().root_lattice().positive_roots_by_height() - assert all(sum(rt.coefficients()) == 1 for rt in pos_roots_by_ht[:len(index_set)]) + assert all(sum(rt.coefficients()) == 1 for rt in pos_roots_by_ht[: len(index_set)]) # for this, we don't need to check the simple roots - pos_roots_by_ht = pos_roots_by_ht[len(index_set):] + pos_roots_by_ht = pos_roots_by_ht[len(index_set) :] while cur_w != wp: ind = None @@ -1490,23 +1485,20 @@ def singular_vector(self): continue M = matrix(pbw.base_ring(), [[v[s] for v in image] for s in supp]) ker = M.right_kernel_matrix() - basis = [C.linear_combination((basis[j], c) - for j, c in kv.items()) - for kv in ker.rows()] + basis = [C.linear_combination((basis[j], c) for j, c in kv.items()) for kv in ker.rows()] assert len(basis) == 1 if Mp is C: # We've constructed the element in the codomain assert next_w == wp assert basis[0].degree() == self.domain().highest_weight() return basis[0] - pbw_elt = pbw.element_class(pbw, {pbw._indices(m._monomial): c - for m, c in basis[0]._monomial_coefficients.items()}) + pbw_elt = pbw.element_class(pbw, {pbw._indices(m._monomial): c for m, c in basis[0]._monomial_coefficients.items()}) elt = pbw_elt * elt wt = wt.dot_action(refl) cur_w = next_w break else: - #assert False, "unable to find root" + # assert False, "unable to find root" # Have a more explicit check at the beginning using the integral # orbit action for the correct version of dominance; see, e.g., # Humphreys "Representations of Semisimple Lie Algebras in the BGG Category O". @@ -1515,7 +1507,7 @@ def singular_vector(self): # Construct the singular vector by iterated embeddings of Verma # modules from the sl_2 relations (without constructing # the modules themselves) - elt = F[ind]**ZZ(exp) * elt + elt = F[ind] ** ZZ(exp) * elt wt = wt.dot_action([ind]) cur_w = cur_w.apply_simple_reflection_right(ind) ret = C.highest_weight_vector()._acted_upon_(elt, False) diff --git a/src/sage/algebras/lie_algebras/virasoro.py b/src/sage/algebras/lie_algebras/virasoro.py index 16e0c915ee2..4b2228bdb17 100644 --- a/src/sage/algebras/lie_algebras/virasoro.py +++ b/src/sage/algebras/lie_algebras/virasoro.py @@ -5,6 +5,7 @@ - Travis Scrimshaw (2013-05-03): Initial version """ + # **************************************************************************** # Copyright (C) 2013-2017 Travis Scrimshaw # @@ -25,8 +26,7 @@ from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.structure.indexed_generators import IndexedGenerators from sage.algebras.lie_algebras.lie_algebra_element import LieAlgebraElement -from sage.algebras.lie_algebras.lie_algebra import (InfinitelyGeneratedLieAlgebra, - FinitelyGeneratedLieAlgebra) +from sage.algebras.lie_algebras.lie_algebra import InfinitelyGeneratedLieAlgebra, FinitelyGeneratedLieAlgebra from sage.combinat.free_module import CombinatorialFreeModule @@ -56,6 +56,7 @@ class LieAlgebraRegularVectorFields(InfinitelyGeneratedLieAlgebra, IndexedGenera :class:`WittLieAlgebra_charp` """ + def __init__(self, R): """ Initialize ``self``. @@ -91,6 +92,7 @@ def _latex_(self): \mathcal{W}_{\Bold{Q}} """ from sage.misc.latex import latex + return r"\mathcal{{W}}_{{{}}}".format(latex(self.base_ring())) # For compatibility with CombinatorialFreeModuleElement @@ -153,7 +155,7 @@ def _an_element_(self): sage: L.an_element() d[-1] + d[0] - 3*d[1] """ - return self.monomial(0) - 3*self.monomial(1) + self.monomial(-1) + return self.monomial(0) - 3 * self.monomial(1) + self.monomial(-1) def some_elements(self): """ @@ -192,6 +194,7 @@ class WittLieAlgebra_charp(FinitelyGeneratedLieAlgebra, IndexedGenerators): :class:`LieAlgebraRegularVectorFields` """ + def __init__(self, R, p): """ Initialize ``self``. @@ -211,10 +214,8 @@ def __init__(self, R, p): if R(p) != 0: raise ValueError("{} is not 0 in {}".format(p, R)) cat = LieAlgebras(R).FiniteDimensional().WithBasis().Graded() - FinitelyGeneratedLieAlgebra.__init__(self, R, index_set=list(range(p)), - category=cat) - IndexedGenerators.__init__(self, list(range(p)), prefix='d', - bracket='[') + FinitelyGeneratedLieAlgebra.__init__(self, R, index_set=list(range(p)), category=cat) + IndexedGenerators.__init__(self, list(range(p)), prefix='d', bracket='[') self._p = p def _repr_(self): @@ -241,6 +242,7 @@ def _latex_(self): \mathcal{W}(15)_{\Bold{F}_{3}} """ from sage.misc.latex import latex + return r"\mathcal{{W}}({})_{{{}}}".format(latex(self._p), latex(self.base_ring())) # For compatibility with CombinatorialFreeModuleElement @@ -292,7 +294,7 @@ def _an_element_(self): sage: L.an_element() d[0] + 2*d[1] + d[4] """ - return self.monomial(0) - 3*self.monomial(1 % self._p) + self.monomial((-1) % self._p) + return self.monomial(0) - 3 * self.monomial(1 % self._p) + self.monomial((-1) % self._p) def some_elements(self): """ @@ -304,9 +306,7 @@ def some_elements(self): sage: L.some_elements() [d[0], d[2], d[3], d[0] + 2*d[1] + d[4]] """ - return [self.monomial(0), self.monomial(2 % self._p), - self.monomial((-2) % self._p), - self.an_element()] + return [self.monomial(0), self.monomial(2 % self._p), self.monomial((-2) % self._p), self.an_element()] def degree_on_basis(self, i): r""" @@ -342,6 +342,7 @@ def _basis_key(x): """ if x == 'c': from sage.rings.infinity import infinity + return infinity return x @@ -378,6 +379,7 @@ class VirasoroAlgebra(InfinitelyGeneratedLieAlgebra, IndexedGenerators): - :wikipedia:`Virasoro_algebra` """ + def __init__(self, R): """ Initialize ``self``. @@ -389,8 +391,7 @@ def __init__(self, R): """ cat = LieAlgebras(R).WithBasis().Graded() InfinitelyGeneratedLieAlgebra.__init__(self, R, index_set=ZZ, category=cat) - IndexedGenerators.__init__(self, ZZ, prefix='d', bracket='[', - sorting_key=_basis_key) + IndexedGenerators.__init__(self, ZZ, prefix='d', bracket='[', sorting_key=_basis_key) def _basis_key(self, m): """ @@ -457,6 +458,7 @@ def _unicode_art_term(self, m): d₋₁₃ """ from sage.typeset.unicode_art import unicode_art, unicode_subscript + if isinstance(m, str): return unicode_art(m) return unicode_art('d' + unicode_subscript(m)) @@ -483,6 +485,7 @@ def _latex_(self): \mathcal{V}_{\Bold{Q}} """ from sage.misc.latex import latex + return r"\mathcal{{V}}_{{{}}}".format(latex(self.base_ring())) @cached_method @@ -561,10 +564,10 @@ def bracket_on_basis(self, i, j): """ if i == 'c' or j == 'c': return self.zero() - ret = self._from_dict({i + j: i-j}) + ret = self._from_dict({i + j: i - j}) R = self.base_ring() if i == -j: - ret += R(i ** 3 - i) / R(12) * self.c() + ret += R(i**3 - i) / R(12) * self.c() return ret def degree_on_basis(self, i): @@ -597,7 +600,7 @@ def _an_element_(self): d[-1] + d[0] - 1/2*d[1] + c """ d = self.monomial - return d(0) - self.base_ring().an_element()*d(1) + d(-1) + d('c') + return d(0) - self.base_ring().an_element() * d(1) + d(-1) + d('c') def some_elements(self): """ @@ -651,6 +654,7 @@ def verma_module(self, c, h): class Element(LieAlgebraElement): pass + ##################################################################### # Representations @@ -729,6 +733,7 @@ class ChargelessRepresentation(CombinatorialFreeModule): - [Mat1992]_ - [IK2010]_ """ + def __init__(self, V, a, b): """ Initialize ``self``. @@ -759,8 +764,7 @@ def _repr_(self): Chargeless representation (1/2, 3/4) of The Virasoro algebra over Rational Field """ - return "Chargeless representation ({}, {}) of {}".format( - self._a, self._b, self._V) + return "Chargeless representation ({}, {}) of {}".format(self._a, self._b, self._V) def parameters(self): """ @@ -826,9 +830,7 @@ def _acted_upon_(self, scalar, self_on_left=False): # We implement only a left action if not self_on_left and scalar in P._V: scalar = P._V(scalar) - return P.sum_of_terms((n+k, (P._a * n + P._b - k) * cv * cm) - for n,cv in scalar.monomial_coefficients(copy=False).items() if n != 'c' - for k,cm in self.monomial_coefficients(copy=False).items()) + return P.sum_of_terms((n + k, (P._a * n + P._b - k) * cv * cm) for n, cv in scalar.monomial_coefficients(copy=False).items() if n != 'c' for k, cm in self.monomial_coefficients(copy=False).items()) return CombinatorialFreeModule.Element._acted_upon_(self, scalar, self_on_left) _rmul_ = _lmul_ = _acted_upon_ @@ -904,6 +906,7 @@ class VermaModule(CombinatorialFreeModule): - :wikipedia:`Virasoro_algebra#Representation_theory` """ + @staticmethod def __classcall_private__(cls, V, c, h): """ @@ -950,6 +953,7 @@ def __init__(self, V, c, h): self._h = h self._V = V from sage.combinat.partition import _Partitions + indices = _Partitions.map(VermaModule._partition_to_neg_tuple) R = V.base_ring() cat = Modules(R).WithBasis().Graded() @@ -986,6 +990,7 @@ def _latex_term(self, k): return 'v' d = self._V.basis() from sage.misc.latex import latex + return ' '.join(latex(d[i]) for i in k) + ' v' def _repr_(self): @@ -1000,8 +1005,7 @@ def _repr_(self): Verma module with charge 3 and conformal weight 0 of The Virasoro algebra over Rational Field """ - return "Verma module with charge {} and conformal weight {} of {}".format( - self._c, self._h, self._V) + return "Verma module with charge {} and conformal weight {} of {}".format(self._c, self._h, self._V) def _monomial(self, index): """ @@ -1124,8 +1128,7 @@ def _d_action_on_basis(self, n, k): k = k[1:] # We need to explicitly call the action as this method is # used in discovering the action - return (self._d_action_on_basis(n, k)._acted_upon_(d[m], False) - + self.monomial(k)._acted_upon_(d[n].bracket(d[m]), False)) + return self._d_action_on_basis(n, k)._acted_upon_(d[m], False) + self.monomial(k)._acted_upon_(d[n].bracket(d[m]), False) def degree_on_basis(self, d): r""" @@ -1173,12 +1176,10 @@ def _acted_upon_(self, scalar, self_on_left=False): R = P.base_ring() if S is R or scalar in R: scalar = R(scalar) - return P._from_dict({k: scalar*c for k,c in self._monomial_coefficients.items()}) + return P._from_dict({k: scalar * c for k, c in self._monomial_coefficients.items()}) if S is P._V or scalar in P._V: scalar = P._V(scalar) - return P.linear_combination((P._d_action_on_basis(n, k), cv * cm) - for n,cv in scalar.monomial_coefficients(copy=False).items() - for k,cm in self._monomial_coefficients.items()) + return P.linear_combination((P._d_action_on_basis(n, k), cv * cm) for n, cv in scalar.monomial_coefficients(copy=False).items() for k, cm in self._monomial_coefficients.items()) return CombinatorialFreeModule.Element._acted_upon_(self, scalar, self_on_left) _rmul_ = _lmul_ = _acted_upon_ diff --git a/src/sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py index a8fa76b853e..adf857a8169 100644 --- a/src/sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py @@ -76,8 +76,8 @@ class AbelianLieConformalAlgebra(GradedLieConformalAlgebra): implement its own class to speed up arithmetics in this case. """ - def __init__(self, R, ngens=1, weights=None, - parity=None, names=None, index_set=None) -> None: + + def __init__(self, R, ngens=1, weights=None, parity=None, names=None, index_set=None) -> None: """ Initialize ``self``. @@ -90,15 +90,10 @@ def __init__(self, R, ngens=1, weights=None, names = 'a' self._latex_names = tuple(r'a_{%d}' % i for i in range(ngens)) - names, index_set = standardize_names_index_set(names=names, - index_set=index_set, - ngens=ngens) + names, index_set = standardize_names_index_set(names=names, index_set=index_set, ngens=ngens) abeliandict = {} - GradedLieConformalAlgebra.__init__(self, R, abeliandict, names=names, - index_set=index_set, - weights=weights, - parity=parity) + GradedLieConformalAlgebra.__init__(self, R, abeliandict, names=names, index_set=index_set, weights=weights, parity=parity) def _repr_(self) -> str: """ @@ -109,5 +104,4 @@ def _repr_(self) -> str: sage: lie_conformal_algebras.Abelian(QQ) The Abelian Lie conformal algebra with generators (a,) over Rational Field """ - return "The Abelian Lie conformal algebra with generators {} over {}"\ - .format(self.gens(), self.base_ring()) + return "The Abelian Lie conformal algebra with generators {} over {}".format(self.gens(), self.base_ring()) diff --git a/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py index 031370da9ee..a736638da03 100644 --- a/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py @@ -82,6 +82,7 @@ class AffineLieConformalAlgebra(GradedLieConformalAlgebra): The Affine Lie conformal algebra associated with the finite dimensional simple Lie algebra of Cartan type ``ct``. """ + def __init__(self, R, ct, names=None, prefix=None, bracket=None) -> None: """ Initialize ``self``. @@ -93,13 +94,13 @@ def __init__(self, R, ct, names=None, prefix=None, bracket=None) -> None: """ if isinstance(ct, str): from sage.combinat.root_system.cartan_type import CartanType + try: ct = CartanType(ct) except IndexError: raise ValueError("ct must be a valid Cartan Type") if not (ct.is_finite() and ct.is_irreducible): - raise ValueError("only affine algebras of simple finite dimensional" - "Lie algebras are implemented") + raise ValueError("only affine algebras of simple finite dimensional" "Lie algebras are implemented") hv = Integer(ct.dual_coxeter_number()) g = LieAlgebra(R, cartan_type=ct) B = g.basis() @@ -109,13 +110,11 @@ def __init__(self, R, ct, names=None, prefix=None, bracket=None) -> None: for k2 in S: if S.rank(k2) <= S.rank(k1): myb = B[k1].bracket(B[k2]).monomial_coefficients() - myf = R(2).inverse_of_unit() * R(hv).inverse_of_unit()\ - * g.killing_form(B[k1], B[k2]) + myf = R(2).inverse_of_unit() * R(hv).inverse_of_unit() * g.killing_form(B[k1], B[k2]) if myb or myf: gdict[(k1, k2)] = {} if myb: - gdict[(k1, k2)][0] = {(nk, 0): v - for nk, v in myb.items()} + gdict[(k1, k2)][0] = {(nk, 0): v for nk, v in myb.items()} if myf: gdict[(k1, k2)][1] = {('K', 0): myf} @@ -124,12 +123,7 @@ def __init__(self, R, ct, names=None, prefix=None, bracket=None) -> None: if prefix is None and names is None: prefix = 'B' - GradedLieConformalAlgebra.__init__(self, - R, gdict, index_set=S, - central_elements=('K',), - weights=weights, - names=names, prefix=prefix, - bracket=bracket) + GradedLieConformalAlgebra.__init__(self, R, gdict, index_set=S, central_elements=('K',), weights=weights, names=names, prefix=prefix, bracket=bracket) def cartan_type(self): """ @@ -154,5 +148,4 @@ def _repr_(self) -> str: sage: lie_conformal_algebras.Affine(QQ, 'A1') The affine Lie conformal algebra of type ['A', 1] over Rational Field """ - return "The affine Lie conformal algebra of type {} over {}".format( - self._ct, self.base_ring()) + return "The affine Lie conformal algebra of type {} over {}".format(self._ct, self.base_ring()) diff --git a/src/sage/algebras/lie_conformal_algebras/all.py b/src/sage/algebras/lie_conformal_algebras/all.py index 31cd1725707..4da68296007 100644 --- a/src/sage/algebras/lie_conformal_algebras/all.py +++ b/src/sage/algebras/lie_conformal_algebras/all.py @@ -11,8 +11,6 @@ from sage.misc.lazy_import import lazy_import -lazy_import('sage.algebras.lie_conformal_algebras.lie_conformal_algebra', - 'LieConformalAlgebra') -lazy_import('sage.algebras.lie_conformal_algebras', - 'examples', 'lie_conformal_algebras') +lazy_import('sage.algebras.lie_conformal_algebras.lie_conformal_algebra', 'LieConformalAlgebra') +lazy_import('sage.algebras.lie_conformal_algebras', 'examples', 'lie_conformal_algebras') del lazy_import diff --git a/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py index 5ceede75ce0..cfa00218e59 100644 --- a/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py @@ -90,36 +90,28 @@ def __init__(self, R, ngens=2, names=None, index_set=None) -> None: sage: TestSuite(V).run() """ from sage.rings.integer_ring import ZZ + try: - assert (ngens in ZZ and ngens > 0 and not ngens % 2) + assert ngens in ZZ and ngens > 0 and not ngens % 2 except AssertionError: - raise ValueError("ngens should be an even positive integer, " + - "got {}".format(ngens)) + raise ValueError("ngens should be an even positive integer, " + "got {}".format(ngens)) latex_names = None half = ngens // 2 if (names is None) and (index_set is None): from sage.misc.defaults import latex_variable_names as laxnames from sage.misc.defaults import variable_names as varnames + names = varnames(half, 'beta') + varnames(half, 'gamma') - latex_names = tuple(laxnames(half, r'\beta') + - laxnames(half, r'\gamma')) + ('K',) + latex_names = tuple(laxnames(half, r'\beta') + laxnames(half, r'\gamma')) + ('K',) - names, index_set = standardize_names_index_set(names=names, - index_set=index_set, - ngens=ngens) + names, index_set = standardize_names_index_set(names=names, index_set=index_set, ngens=ngens) A = identity_matrix(R, half) from sage.matrix.special import block_matrix + gram_matrix = block_matrix([[R.zero(), A], [-A, R.zero()]]) - ghostsdict = {(i, j): {0: {('K', 0): gram_matrix[index_set.rank(i), - index_set.rank(j)]}} - for i in index_set for j in index_set} + ghostsdict = {(i, j): {0: {('K', 0): gram_matrix[index_set.rank(i), index_set.rank(j)]}} for i in index_set for j in index_set} weights = (1,) * half + (0,) * half - super().__init__(R, - ghostsdict, names=names, - latex_names=latex_names, - index_set=index_set, - weights=weights, - central_elements=('K',)) + super().__init__(R, ghostsdict, names=names, latex_names=latex_names, index_set=index_set, weights=weights, central_elements=('K',)) def _repr_(self) -> str: """ @@ -130,5 +122,4 @@ def _repr_(self) -> str: sage: lie_conformal_algebras.BosonicGhosts(QQbar) The Bosonic ghosts Lie conformal algebra with generators (beta, gamma, K) over Algebraic Field """ - return "The Bosonic ghosts Lie conformal algebra with generators {} "\ - "over {}".format(self.gens(), self.base_ring()) + return "The Bosonic ghosts Lie conformal algebra with generators {} " "over {}".format(self.gens(), self.base_ring()) diff --git a/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py index e394c9e774f..1a8e2ceabdf 100644 --- a/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py @@ -17,6 +17,7 @@ - Reimundo Heluani (2020-06-03): Initial implementation. """ + # *************************************************************************** # Copyright (C) 2020 Reimundo Heluani # @@ -73,6 +74,7 @@ class FermionicGhostsLieConformalAlgebra(GradedLieConformalAlgebra): sage: R.structure_coefficients() Finite family {('a', 'c'): ((0, K),), ('b', 'd'): ((0, K),), ('c', 'a'): ((0, K),), ('d', 'b'): ((0, K),)} """ + def __init__(self, R, ngens=2, names=None, index_set=None) -> None: """ Initialize ``self``. @@ -83,39 +85,31 @@ def __init__(self, R, ngens=2, names=None, index_set=None) -> None: sage: TestSuite(V).run() """ try: - assert (ngens > 0 and not ngens % 2) + assert ngens > 0 and not ngens % 2 except AssertionError: - raise ValueError("ngens should be an even positive integer, " + - "got {}".format(ngens)) + raise ValueError("ngens should be an even positive integer, " + "got {}".format(ngens)) latex_names = None half = ngens // 2 if (names is None) and (index_set is None): from sage.misc.defaults import latex_variable_names as laxnames from sage.misc.defaults import variable_names as varnames + names = varnames(half, 'b') + varnames(half, 'c') - latex_names = tuple(laxnames(half, 'b') + - laxnames(half, 'c')) + ('K',) + latex_names = tuple(laxnames(half, 'b') + laxnames(half, 'c')) + ('K',) from sage.structure.indexed_generators import standardize_names_index_set - names, index_set = standardize_names_index_set(names=names, - index_set=index_set, - ngens=ngens) + + names, index_set = standardize_names_index_set(names=names, index_set=index_set, ngens=ngens) from sage.matrix.special import identity_matrix + A = identity_matrix(R, half) from sage.matrix.special import block_matrix + gram_matrix = block_matrix([[R.zero(), A], [A, R.zero()]]) - ghostsdict = {(i, j): {0: {('K', 0): gram_matrix[index_set.rank(i), - index_set.rank(j)]}} - for i in index_set for j in index_set} + ghostsdict = {(i, j): {0: {('K', 0): gram_matrix[index_set.rank(i), index_set.rank(j)]}} for i in index_set for j in index_set} weights = (1,) * half + (0,) * half parity = (1,) * ngens - super().__init__(R, - ghostsdict, names=names, - latex_names=latex_names, - index_set=index_set, - weights=weights, - parity=parity, - central_elements=('K',)) + super().__init__(R, ghostsdict, names=names, latex_names=latex_names, index_set=index_set, weights=weights, parity=parity, central_elements=('K',)) def _repr_(self) -> str: """ @@ -126,5 +120,4 @@ def _repr_(self) -> str: sage: lie_conformal_algebras.FermionicGhosts(QQ) The Fermionic ghosts Lie conformal algebra with generators (b, c, K) over Rational Field """ - return "The Fermionic ghosts Lie conformal algebra with generators {} "\ - "over {}".format(self.gens(), self.base_ring()) + return "The Fermionic ghosts Lie conformal algebra with generators {} " "over {}".format(self.gens(), self.base_ring()) diff --git a/src/sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py b/src/sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py index 400eb517c8e..1f153012d38 100644 --- a/src/sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py +++ b/src/sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py @@ -5,6 +5,7 @@ - Reimundo Heluani (2019-08-09): Initial implementation. """ + # **************************************************************************** # Copyright (C) 2019 Reimundo Heluani # @@ -29,9 +30,8 @@ class FinitelyFreelyGeneratedLCA(FreelyGeneratedLieConformalAlgebra): This class provides minimal functionality, simply sets the number of generators. """ - def __init__(self, R, index_set=None, central_elements=None, category=None, - element_class=None, prefix=None, names=None, latex_names=None, - **kwds) -> None: + + def __init__(self, R, index_set=None, central_elements=None, category=None, element_class=None, prefix=None, names=None, latex_names=None, **kwds) -> None: """ Initialize ``self``. @@ -47,14 +47,11 @@ def __init__(self, R, index_set=None, central_elements=None, category=None, category = default_category.Super().or_subcategory(category) from sage.categories.sets_cat import Sets + if index_set not in Sets().Finite(): raise TypeError("index_set must be a finite set") - super().__init__(R, - index_set=index_set, - central_elements=central_elements, - category=category, element_class=element_class, - prefix=prefix, **kwds) + super().__init__(R, index_set=index_set, central_elements=central_elements, category=category, element_class=element_class, prefix=prefix, **kwds) self._ngens = len(self._generators) self._names = names self._latex_names = latex_names @@ -71,10 +68,8 @@ def _repr_(self) -> str: Lie conformal algebra with generators (a, K) over Rational Field """ if self._ngens == 1: - return "Lie conformal algebra generated by {} over {}".format( - self.gen(0), self.base_ring()) - return "Lie conformal algebra with generators {} over {}".format( - self.gens(), self.base_ring()) + return "Lie conformal algebra generated by {} over {}".format(self.gen(0), self.base_ring()) + return "Lie conformal algebra with generators {} over {}".format(self.gens(), self.base_ring()) def _an_element_(self): """ diff --git a/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py index 617952b4fb8..f6da23c8ad9 100644 --- a/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py @@ -100,8 +100,8 @@ class FreeBosonsLieConformalAlgebra(GradedLieConformalAlgebra): ValueError: the gram_matrix should be a symmetric 2 x 2 matrix, got [ 0 1] [-1 0] """ - def __init__(self, R, ngens=None, gram_matrix=None, names=None, - index_set=None): + + def __init__(self, R, ngens=None, gram_matrix=None, names=None, index_set=None): """ Initialize ``self``. @@ -111,19 +111,16 @@ def __init__(self, R, ngens=None, gram_matrix=None, names=None, sage: TestSuite(V).run() """ from sage.matrix.matrix_space import MatrixSpace + if gram_matrix is not None: if ngens is None: ngens = gram_matrix.dimensions()[0] try: - assert (gram_matrix in MatrixSpace(R, ngens, ngens)) + assert gram_matrix in MatrixSpace(R, ngens, ngens) except AssertionError: - raise ValueError("the gram_matrix should be a symmetric " + - "{0} x {0} matrix, got {1}".format(ngens, - gram_matrix)) + raise ValueError("the gram_matrix should be a symmetric " + "{0} x {0} matrix, got {1}".format(ngens, gram_matrix)) if not gram_matrix.is_symmetric(): - raise ValueError("the gram_matrix should be a symmetric " + - "{0} x {0} matrix, got {1}".format(ngens, - gram_matrix)) + raise ValueError("the gram_matrix should be a symmetric " + "{0} x {0} matrix, got {1}".format(ngens, gram_matrix)) else: if ngens is None: ngens = 1 @@ -132,20 +129,11 @@ def __init__(self, R, ngens=None, gram_matrix=None, names=None, latex_names = None if names is None and index_set is None: names = 'alpha' - latex_names = tuple(r'\alpha_{%d}' % i - for i in range(ngens)) + ('K',) - names, index_set = standardize_names_index_set(names=names, - index_set=index_set, - ngens=ngens) - bosondict = {(i, j): {1: {('K', 0): gram_matrix[index_set.rank(i), - index_set.rank(j)]}} - for i in index_set for j in index_set} - - GradedLieConformalAlgebra.__init__(self, R, bosondict, - names=names, - latex_names=latex_names, - index_set=index_set, - central_elements=('K',)) + latex_names = tuple(r'\alpha_{%d}' % i for i in range(ngens)) + ('K',) + names, index_set = standardize_names_index_set(names=names, index_set=index_set, ngens=ngens) + bosondict = {(i, j): {1: {('K', 0): gram_matrix[index_set.rank(i), index_set.rank(j)]}} for i in index_set for j in index_set} + + GradedLieConformalAlgebra.__init__(self, R, bosondict, names=names, latex_names=latex_names, index_set=index_set, central_elements=('K',)) self._gram_matrix = gram_matrix @@ -158,8 +146,7 @@ def _repr_(self) -> str: sage: lie_conformal_algebras.FreeBosons(AA) The free Bosons Lie conformal algebra with generators (alpha, K) over Algebraic Real Field """ - return "The free Bosons Lie conformal algebra with generators {}"\ - " over {}".format(self.gens(), self.base_ring()) + return "The free Bosons Lie conformal algebra with generators {}" " over {}".format(self.gens(), self.base_ring()) def gram_matrix(self): r""" diff --git a/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py index 2fb3bc52eb9..fbd4b0b0c0f 100644 --- a/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py @@ -22,6 +22,7 @@ - Reimundo Heluani (2020-06-03): Initial implementation. """ + # *************************************************************************** # Copyright (C) 2020 Reimundo Heluani # @@ -83,8 +84,8 @@ class FreeFermionsLieConformalAlgebra(GradedLieConformalAlgebra): sage: R.category() Category of H-graded super finitely generated Lie conformal algebras with basis over Algebraic Field """ - def __init__(self, R, ngens=None, gram_matrix=None, names=None, - index_set=None): + + def __init__(self, R, ngens=None, gram_matrix=None, names=None, index_set=None): """ Initialize ``self``. @@ -95,19 +96,16 @@ def __init__(self, R, ngens=None, gram_matrix=None, names=None, """ from sage.matrix.matrix_space import MatrixSpace from sage.matrix.special import identity_matrix + if gram_matrix is not None: if ngens is None: ngens = gram_matrix.dimensions()[0] try: - assert (gram_matrix in MatrixSpace(R, ngens, ngens)) + assert gram_matrix in MatrixSpace(R, ngens, ngens) except AssertionError: - raise ValueError("the Gram_matrix should be a symmetric " + - "{0} x {0} matrix, got {1}".format(ngens, - gram_matrix)) + raise ValueError("the Gram_matrix should be a symmetric " + "{0} x {0} matrix, got {1}".format(ngens, gram_matrix)) if not gram_matrix.is_symmetric(): - raise ValueError("the Gram_matrix should be a symmetric " + - "{0} x {0} matrix, got {1}".format(ngens, - gram_matrix)) + raise ValueError("the Gram_matrix should be a symmetric " + "{0} x {0} matrix, got {1}".format(ngens, gram_matrix)) else: if ngens is None: ngens = 1 @@ -117,26 +115,18 @@ def __init__(self, R, ngens=None, gram_matrix=None, names=None, if names is None and index_set is None: names = 'psi' if ngens == 1 else 'psi_' - latex_names = tuple(r"\psi_{%d}" % i - for i in range(ngens)) + ('K',) + latex_names = tuple(r"\psi_{%d}" % i for i in range(ngens)) + ('K',) from sage.structure.indexed_generators import standardize_names_index_set - names, index_set = standardize_names_index_set(names=names, - index_set=index_set, - ngens=ngens) - fermiondict = {(i, j): {0: {('K', 0): gram_matrix[index_set.rank(i), - index_set.rank(j)]}} - for i in index_set for j in index_set} + + names, index_set = standardize_names_index_set(names=names, index_set=index_set, ngens=ngens) + fermiondict = {(i, j): {0: {('K', 0): gram_matrix[index_set.rank(i), index_set.rank(j)]}} for i in index_set for j in index_set} from sage.rings.rational_field import QQ + weights = (QQ((1, 2)),) * ngens parity = (1,) * ngens - GradedLieConformalAlgebra.__init__(self, R, fermiondict, names=names, - latex_names=latex_names, - index_set=index_set, - weights=weights, - parity=parity, - central_elements=('K',)) + GradedLieConformalAlgebra.__init__(self, R, fermiondict, names=names, latex_names=latex_names, index_set=index_set, weights=weights, parity=parity, central_elements=('K',)) self._gram_matrix = gram_matrix @@ -149,9 +139,7 @@ def _repr_(self) -> str: sage: lie_conformal_algebras.FreeFermions(QQ) The free Fermions super Lie conformal algebra with generators (psi, K) over Rational Field """ - return "The free Fermions super Lie conformal algebra "\ - "with generators {} over {}".format(self.gens(), - self.base_ring()) + return "The free Fermions super Lie conformal algebra " "with generators {} over {}".format(self.gens(), self.base_ring()) def gram_matrix(self): r""" diff --git a/src/sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py index bc67c59b4ff..5f2c7795aa7 100644 --- a/src/sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py @@ -39,8 +39,8 @@ class FreelyGeneratedLieConformalAlgebra(LieConformalAlgebraWithBasis): We now only accept direct sums of free modules plus some central generators `C_i` such that `TC_i = 0`. """ - def __init__(self, R, index_set=None, central_elements=None, category=None, - element_class=None, prefix=None, **kwds) -> None: + + def __init__(self, R, index_set=None, central_elements=None, category=None, element_class=None, prefix=None, **kwds) -> None: """ Initialize ``self``. @@ -52,13 +52,10 @@ def __init__(self, R, index_set=None, central_elements=None, category=None, self._generators = Family(index_set) E = cartesian_product([index_set, NonNegativeIntegers()]) if central_elements is not None: - self._generators = DisjointUnionEnumeratedSets( - [index_set, Family(central_elements)]) - E = DisjointUnionEnumeratedSets((cartesian_product([ - Family(central_elements), {Integer(0)}]), E)) + self._generators = DisjointUnionEnumeratedSets([index_set, Family(central_elements)]) + E = DisjointUnionEnumeratedSets((cartesian_product([Family(central_elements), {Integer(0)}]), E)) - super().__init__(R, basis_keys=E, element_class=element_class, - category=category, prefix=prefix, **kwds) + super().__init__(R, basis_keys=E, element_class=element_class, category=category, prefix=prefix, **kwds) if central_elements is not None: self._central_elements = Family(central_elements) @@ -81,10 +78,9 @@ def lie_conformal_algebra_generators(self): sage: V.lie_conformal_algebra_generators() (B[alpha[1]], B[alphacheck[1]], B[-alpha[1]], B['K']) """ - F = Family(self._generators, - lambda i: self.monomial((i, Integer(0))), - name="generator map") + F = Family(self._generators, lambda i: self.monomial((i, Integer(0))), name="generator map") from sage.categories.sets_cat import Sets + if F in Sets().Finite(): return tuple(F) return F @@ -102,6 +98,4 @@ def central_elements(self) -> Family: sage: V.central_elements() (B['K'],) """ - return Family(self._central_elements, - lambda i: self.monomial((i, Integer(0))), - name="central_element map") + return Family(self._central_elements, lambda i: self.monomial((i, Integer(0))), name="central_element map") diff --git a/src/sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py index 60b773ab421..f9aca160b63 100644 --- a/src/sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py @@ -34,7 +34,6 @@ - Reimundo Heluani (2019-08-09): Initial implementation. """ - # *************************************************************************** # Copyright (C) 2019 Reimundo Heluani # @@ -101,9 +100,8 @@ class GradedLieConformalAlgebra(LieConformalAlgebraWithStructureCoefficients): sage: R.category() Category of H-graded finitely generated Lie conformal algebras with basis over Rational Field """ - def __init__(self, R, s_coeff, index_set=None, central_elements=None, - category=None, prefix=None, names=None, latex_names=None, - parity=None, weights=None, **kwds): + + def __init__(self, R, s_coeff, index_set=None, central_elements=None, category=None, prefix=None, names=None, latex_names=None, parity=None, weights=None, **kwds): """ Initialize ``self``. @@ -119,17 +117,10 @@ def __init__(self, R, s_coeff, index_set=None, central_elements=None, else: category = default_category.or_subcategory(category) - LieConformalAlgebraWithStructureCoefficients.__init__( - self, R, - s_coeff, index_set=index_set, central_elements=central_elements, - category=category, prefix=prefix, - names=names, latex_names=latex_names, parity=parity, **kwds) + LieConformalAlgebraWithStructureCoefficients.__init__(self, R, s_coeff, index_set=index_set, central_elements=central_elements, category=category, prefix=prefix, names=names, latex_names=latex_names, parity=parity, **kwds) if weights is None: - weights = (1,) * (len(self._generators) - - len(self.central_elements())) - if len(weights) != (len(self._generators) - - len(self.central_elements())): - raise ValueError("weights and (non-central) generator lists " - "must be of same length") + weights = (1,) * (len(self._generators) - len(self.central_elements())) + if len(weights) != (len(self._generators) - len(self.central_elements())): + raise ValueError("weights and (non-central) generator lists " "must be of same length") self._weights = weights diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py index fe01503f6a2..0a53aeb5539 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py @@ -161,7 +161,6 @@ - Reimundo Heluani (2019-08-09): Initial implementation. """ - # *************************************************************************** # Copyright (C) 2019 Reimundo Heluani # @@ -305,11 +304,9 @@ class LieConformalAlgebra(UniqueRepresentation, Parent): :mod:`sage.algebras.lie_conformal_algebras.graded_lie_conformal_algebra` """ + @staticmethod - def __classcall_private__(cls, R=None, arg0=None, index_set=None, - central_elements=None, category=None, - prefix=None, names=None, latex_names=None, - parity=None, weights=None, **kwds): + def __classcall_private__(cls, R=None, arg0=None, index_set=None, central_elements=None, category=None, prefix=None, names=None, latex_names=None, parity=None, weights=None, **kwds): """ Lie conformal algebra factory. @@ -324,8 +321,7 @@ def __classcall_private__(cls, R=None, arg0=None, index_set=None, raise ValueError(f"arg0 must be a commutative ring got {R}") # This is the only exposed class so we clean keywords here - known_keywords = ['category', 'prefix', 'bracket', 'latex_bracket', - 'string_quotes', 'sorting_key', 'graded', 'super'] + known_keywords = ['category', 'prefix', 'bracket', 'latex_bracket', 'string_quotes', 'sorting_key', 'graded', 'super'] for key in kwds: if key not in known_keywords: raise ValueError("got an unexpected keyword argument '%s'" % key) @@ -336,18 +332,11 @@ def __classcall_private__(cls, R=None, arg0=None, index_set=None, from sage.algebras.lie_conformal_algebras.graded_lie_conformal_algebra import ( GradedLieConformalAlgebra, ) - return GradedLieConformalAlgebra( - R, Family(arg0), - index_set=index_set, central_elements=central_elements, - category=category, prefix=prefix, names=names, - latex_names=latex_names, parity=parity, weights=weights, - **kwds) + + return GradedLieConformalAlgebra(R, Family(arg0), index_set=index_set, central_elements=central_elements, category=category, prefix=prefix, names=names, latex_names=latex_names, parity=parity, weights=weights, **kwds) from sage.algebras.lie_conformal_algebras.lie_conformal_algebra_with_structure_coefs import ( LieConformalAlgebraWithStructureCoefficients, ) - return LieConformalAlgebraWithStructureCoefficients( - R, Family(arg0), - index_set=index_set, central_elements=central_elements, - category=category, prefix=prefix, names=names, - latex_names=latex_names, parity=parity, **kwds) + + return LieConformalAlgebraWithStructureCoefficients(R, Family(arg0), index_set=index_set, central_elements=central_elements, category=category, prefix=prefix, names=names, latex_names=latex_names, parity=parity, **kwds) raise NotImplementedError("not implemented") diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py index bf001160832..702abc17453 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py @@ -5,6 +5,7 @@ - Reimundo Heluani (2019-08-09): Initial implementation. """ + # ***************************************************************************** # Copyright (C) 2019 Reimundo Heluani # @@ -26,6 +27,7 @@ class LCAWithGeneratorsElement(IndexedFreeModuleElement): The element class of a Lie conformal algebra with a preferred set of generators. """ + def T(self, n=1): r""" The `n`-th derivative of this element. @@ -57,6 +59,7 @@ def T(self, n=1): 2*T^(2)L + 12*T^(3)G """ from sage.rings.integer_ring import ZZ + if n not in ZZ or n < 0: raise ValueError("n must be a nonnegative Integer") if n == 0 or self.is_zero(): @@ -67,8 +70,7 @@ def T(self, n=1): a, m = self.index() coef = self._monomial_coefficients[(a, m)] if (a, m + n) in p._indices: - return coef * prod(range(m + 1, m + n + 1))\ - * p.monomial((a, m + n)) + return coef * prod(range(m + 1, m + n + 1)) * p.monomial((a, m + n)) return p.zero() return sum(mon.T(n) for mon in self.terms()) @@ -92,6 +94,7 @@ class LCAStructureCoefficientsElement(LCAWithGeneratorsElement): An element of a Lie conformal algebra given by structure coefficients. """ + def _bracket_(self, right): """ The lambda bracket of these two elements. @@ -131,16 +134,10 @@ def _bracket_(self, right): except KeyError: return {} pole = max(mbr.keys()) - ret = {l: coefa * coefb * (-1)**k / factorial(k) * - sum(factorial(l) / factorial(m + k + j - l) - / factorial(l - k - j) / factorial(j) - * mbr[j].T(m + k + j - l) - for j in mbr if l - m - k <= j <= l - k) - for l in range(m + k + pole + 1)} + ret = {l: coefa * coefb * (-1) ** k / factorial(k) * sum(factorial(l) / factorial(m + k + j - l) / factorial(l - k - j) / factorial(j) * mbr[j].T(m + k + j - l) for j in mbr if l - m - k <= j <= l - k) for l in range(m + k + pole + 1)} return {k: v for k, v in ret.items() if v} - diclist = [i._bracket_(j) for i in self.terms() - for j in right.terms()] + diclist = [i._bracket_(j) for i in self.terms() for j in right.terms()] ret = {} pz = p.zero() for d in diclist: @@ -174,15 +171,9 @@ def _repr_(self) -> str: return "0" p = self.parent() if p._names: - terms = [(f"T^({k1}){p._names[p._index_to_pos[k0]]}", v) if k1 > 1 - else (f"T{p._names[p._index_to_pos[k0]]}", v) if k1 == 1 - else (f"{p._names[p._index_to_pos[k0]]}", v) - for (k0, k1), v in self.monomial_coefficients().items()] + terms = [(f"T^({k1}){p._names[p._index_to_pos[k0]]}", v) if k1 > 1 else (f"T{p._names[p._index_to_pos[k0]]}", v) if k1 == 1 else (f"{p._names[p._index_to_pos[k0]]}", v) for (k0, k1), v in self.monomial_coefficients().items()] else: - terms = [(f"T^({k1}){p._repr_generator(k0)}", v) if k1 > 1 - else (f"T{p._repr_generator(k0)}", v) if k1 == 1 - else (f"{p._repr_generator(k0)}", v) - for (k0, k1), v in self.monomial_coefficients().items()] + terms = [(f"T^({k1}){p._repr_generator(k0)}", v) if k1 > 1 else (f"T{p._repr_generator(k0)}", v) if k1 == 1 else (f"{p._repr_generator(k0)}", v) for (k0, k1), v in self.monomial_coefficients().items()] return repr_lincomb(terms, strip_one=True) @@ -222,14 +213,8 @@ def _latex_(self) -> str: except ValueError: names = None if names: - terms = [("T^{{({})}}{}".format(k1, names[p._index_to_pos[k0]]), v) if k1 > 1 - else ("T{}".format(names[p._index_to_pos[k0]]), v) if k1 == 1 - else ("{}".format(names[p._index_to_pos[k0]]), v) - for (k0, k1), v in self.monomial_coefficients().items()] + terms = [("T^{{({})}}{}".format(k1, names[p._index_to_pos[k0]]), v) if k1 > 1 else ("T{}".format(names[p._index_to_pos[k0]]), v) if k1 == 1 else ("{}".format(names[p._index_to_pos[k0]]), v) for (k0, k1), v in self.monomial_coefficients().items()] else: - terms = [("T^{{({})}}{}".format(k1, latex(k0)), v) if k1 > 1 - else ("T{}".format(latex(k0)), v) if k1 == 1 - else ("{}".format(latex(k0)), v) - for (k0, k1), v in self.monomial_coefficients().items()] + terms = [("T^{{({})}}{}".format(k1, latex(k0)), v) if k1 > 1 else ("T{}".format(latex(k0)), v) if k1 == 1 else ("{}".format(latex(k0)), v) for (k0, k1), v in self.monomial_coefficients().items()] return repr_lincomb(terms, is_latex=True, strip_one=True) diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py index 3b63da8dd9b..674cf248ecf 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py @@ -51,8 +51,8 @@ class LieConformalAlgebraWithBasis(CombinatorialFreeModule): sage: R._repr_generator(R.0) 'e' """ - def __init__(self, R, basis_keys=None, element_class=None, category=None, - prefix=None, **kwds): + + def __init__(self, R, basis_keys=None, element_class=None, category=None, prefix=None, **kwds): """ Initialize ``self``. @@ -72,5 +72,4 @@ def __init__(self, R, basis_keys=None, element_class=None, category=None, except ValueError: category = default_category.Super().or_subcategory(category) - super().__init__(R, basis_keys=basis_keys, element_class=element_class, - category=category, prefix=prefix, names=None, **kwds) + super().__init__(R, basis_keys=basis_keys, element_class=element_class, category=category, prefix=prefix, names=None, **kwds) diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py index b121c58e460..5d125aada20 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py @@ -32,8 +32,7 @@ ) -class LieConformalAlgebraWithStructureCoefficients( - FinitelyFreelyGeneratedLCA): +class LieConformalAlgebraWithStructureCoefficients(FinitelyFreelyGeneratedLCA): r""" A Lie conformal algebra with a set of specified structure coefficients. @@ -120,6 +119,7 @@ class LieConformalAlgebraWithStructureCoefficients( ValueError: two distinct values given for one and the same bracket. Skew-symmetry is not satisfied? """ + @staticmethod def _standardize_s_coeff(s_coeff, index_set, ce, parity=None): """ @@ -168,9 +168,7 @@ def _standardize_s_coeff(s_coeff, index_set, ce, parity=None): myvals = tuple((k, tuple(v.items())) for k, v in vals.items() if v) if key in sc and sorted(sc[key]) != sorted(myvals): - raise ValueError("two distinct values given for one " - "and the same bracket, skew-symmetry" - "is not satisfied?") + raise ValueError("two distinct values given for one " "and the same bracket, skew-symmetry" "is not satisfied?") if myvals: sc[key] = myvals @@ -192,10 +190,8 @@ def _standardize_s_coeff(s_coeff, index_set, ce, parity=None): i0, i1 = i i1j = i1 + j if (i0 not in ce) or (i0 in ce and i1j == 0): - kth_product[(i0, i1j)] = \ - kth_product.get((i0, i1j), 0) - kth_product[(i0, i1j)] += parsgn *\ - v[kj][i] * (-1)**(kj+1)*binomial(i1j, j) + kth_product[(i0, i1j)] = kth_product.get((i0, i1j), 0) + kth_product[(i0, i1j)] += parsgn * v[kj][i] * (-1) ** (kj + 1) * binomial(i1j, j) kth_product = {k: v for k, v in kth_product.items() if v} if kth_product: vals[k] = kth_product @@ -203,16 +199,12 @@ def _standardize_s_coeff(s_coeff, index_set, ce, parity=None): myvals = tuple((k, tuple(v.items())) for k, v in vals.items() if v) if key in sc and sorted(sc[key]) != sorted(myvals): - raise ValueError("two distinct values given for one " - "and the same bracket. " - "Skew-symmetry is not satisfied?") + raise ValueError("two distinct values given for one " "and the same bracket. " "Skew-symmetry is not satisfied?") if myvals: sc[key] = myvals return Family(sc) - def __init__(self, R, s_coeff, index_set=None, central_elements=None, - category=None, element_class=None, prefix=None, names=None, - latex_names=None, parity=None, **kwds) -> None: + def __init__(self, R, s_coeff, index_set=None, central_elements=None, category=None, element_class=None, prefix=None, names=None, latex_names=None, parity=None, **kwds) -> None: """ Initialize ``self``. @@ -227,16 +219,12 @@ def __init__(self, R, s_coeff, index_set=None, central_elements=None, if names is not None and names != tuple(index_set): names2 = names + tuple(central_elements) - index_set2 = DisjointUnionEnumeratedSets( - (index_set, Family(tuple(central_elements)))) + index_set2 = DisjointUnionEnumeratedSets((index_set, Family(tuple(central_elements)))) d = {x: index_set2[i] for i, x in enumerate(names2)} try: # If we are given a dictionary with names as keys, # convert to index_set as keys - s_coeff = {(d[k[0]], d[k[1]]): - {a: {(d[x[1]], x[2]): sck[a][x] for x in sck[a]} - for a in sck} - for k, sck in s_coeff.items()} + s_coeff = {(d[k[0]], d[k[1]]): {a: {(d[x[1]], x[2]): sck[a][x] for x in sck[a]} for a in sck} for k, sck in s_coeff.items()} except KeyError: # We assume the dictionary was given with keys in the @@ -252,12 +240,9 @@ def __init__(self, R, s_coeff, index_set=None, central_elements=None, try: assert len(parity) == index_set.cardinality() except AssertionError: - raise ValueError("parity should have the same length as the " - f"number of generators, got {parity}") + raise ValueError("parity should have the same length as the " f"number of generators, got {parity}") - s_coeff = LieConformalAlgebraWithStructureCoefficients\ - ._standardize_s_coeff(s_coeff, index_set, central_elements, - parity) + s_coeff = LieConformalAlgebraWithStructureCoefficients._standardize_s_coeff(s_coeff, index_set, central_elements, parity) if names is not None and central_elements is not None: names += tuple(central_elements) @@ -278,18 +263,11 @@ def __init__(self, R, s_coeff, index_set=None, central_elements=None, if element_class is None: element_class = LCAStructureCoefficientsElement - FinitelyFreelyGeneratedLCA.__init__( - self, R, index_set=index_set, central_elements=central_elements, - category=category, element_class=element_class, - prefix=prefix, names=names, latex_names=latex_names, **kwds) + FinitelyFreelyGeneratedLCA.__init__(self, R, index_set=index_set, central_elements=central_elements, category=category, element_class=element_class, prefix=prefix, names=names, latex_names=latex_names, **kwds) s_coeff = dict(s_coeff) - self._s_coeff = Family({k: - tuple((j, sum(c * self.monomial(i) - for i, c in v)) for j, v in sck) - for k, sck in s_coeff.items()}) - self._parity = dict(zip(self.gens(), - parity + (0,) * len(central_elements))) + self._s_coeff = Family({k: tuple((j, sum(c * self.monomial(i) for i, c in v)) for j, v in sck) for k, sck in s_coeff.items()}) + self._parity = dict(zip(self.gens(), parity + (0,) * len(central_elements))) def structure_coefficients(self) -> Family: """ diff --git a/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py index b72f580e42d..938f29bf262 100644 --- a/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py @@ -19,6 +19,7 @@ - Reimundo Heluani (2020-06-03): Initial implementation. """ + # ***************************************************************************** # Copyright (C) 2020 Reimundo Heluani # @@ -74,6 +75,7 @@ class N2LieConformalAlgebra(GradedLieConformalAlgebra): sage: G.bracket(G) {0: 2*L, 2: 2/3*C} """ + def __init__(self, R) -> None: """ Initialize ``self``. @@ -83,27 +85,12 @@ def __init__(self, R) -> None: sage: V = lie_conformal_algebras.N2(QQ) sage: TestSuite(V).run() # long time (:issue:`39569`) """ - n2dict = {('L', 'L'): {0: {('L', 1): 1}, - 1: {('L', 0): 2}, - 3: {('C', 0): R(2).inverse_of_unit()}}, - ('L', 'G1'): {0: {('G1', 1): 1}, - 1: {('G1', 0): 3 * R(2).inverse_of_unit()}}, - ('L', 'G2'): {0: {('G2', 1): 1}, - 1: {('G2', 0): 3 * R(2).inverse_of_unit()}}, - ('G1', 'G2'): {0: {('L', 0): 1, ('J', 1): R(2).inverse_of_unit()}, - 1: {('J', 0): 1}, - 2: {('C', 0): R(3).inverse_of_unit()}}, - ('L', 'J'): {0: {('J', 1): 1}, 1: {('J', 0): 1}}, - ('J', 'J'): {1: {('C', 0): R(3).inverse_of_unit()}}, - ('J', 'G1'): {0: {('G1', 0): 1}}, - ('J', 'G2'): {0: {('G2', 0): -1}}} + n2dict = {('L', 'L'): {0: {('L', 1): 1}, 1: {('L', 0): 2}, 3: {('C', 0): R(2).inverse_of_unit()}}, ('L', 'G1'): {0: {('G1', 1): 1}, 1: {('G1', 0): 3 * R(2).inverse_of_unit()}}, ('L', 'G2'): {0: {('G2', 1): 1}, 1: {('G2', 0): 3 * R(2).inverse_of_unit()}}, ('G1', 'G2'): {0: {('L', 0): 1, ('J', 1): R(2).inverse_of_unit()}, 1: {('J', 0): 1}, 2: {('C', 0): R(3).inverse_of_unit()}}, ('L', 'J'): {0: {('J', 1): 1}, 1: {('J', 0): 1}}, ('J', 'J'): {1: {('C', 0): R(3).inverse_of_unit()}}, ('J', 'G1'): {0: {('G1', 0): 1}}, ('J', 'G2'): {0: {('G2', 0): -1}}} from sage.rings.rational_field import QQ + weights = (2, 1, QQ(3) / 2, QQ(3) / 2) parity = (0, 0, 1, 1) - GradedLieConformalAlgebra.__init__(self, R, n2dict, - names=('L', 'J', 'G1', 'G2'), - central_elements=('C',), - weights=weights, parity=parity) + GradedLieConformalAlgebra.__init__(self, R, n2dict, names=('L', 'J', 'G1', 'G2'), central_elements=('C',), weights=weights, parity=parity) def _repr_(self) -> str: """ diff --git a/src/sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py index 2b966a3cb1d..b7984238d10 100644 --- a/src/sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py @@ -14,6 +14,7 @@ - Reimundo Heluani (2020-06-03): Initial implementation. """ + # *************************************************************************** # Copyright (C) 2020 Reimundo Heluani # @@ -51,6 +52,7 @@ class NeveuSchwarzLieConformalAlgebra(GradedLieConformalAlgebra): sage: G.degree() 3/2 """ + def __init__(self, R) -> None: """ Initialize ``self``. @@ -60,19 +62,12 @@ def __init__(self, R) -> None: sage: V = lie_conformal_algebras.NeveuSchwarz(QQ) sage: TestSuite(V).run() """ - nsdict = {('L', 'L'): {0: {('L', 1): 1}, - 1: {('L', 0): 2}, - 3: {('C', 0): R(2).inverse_of_unit()}}, - ('L', 'G'): {0: {('G', 1): 1}, - 1: {('G', 0): R(3) * R(2).inverse_of_unit()}}, - ('G', 'G'): {0: {('L', 0): 2}, - 2: {('C', 0): R(2) * R(3).inverse_of_unit()}}} + nsdict = {('L', 'L'): {0: {('L', 1): 1}, 1: {('L', 0): 2}, 3: {('C', 0): R(2).inverse_of_unit()}}, ('L', 'G'): {0: {('G', 1): 1}, 1: {('G', 0): R(3) * R(2).inverse_of_unit()}}, ('G', 'G'): {0: {('L', 0): 2}, 2: {('C', 0): R(2) * R(3).inverse_of_unit()}}} from sage.rings.rational_field import QQ + weights = (2, QQ((3, 2))) parity = (0, 1) - GradedLieConformalAlgebra.__init__(self, R, nsdict, names=('L', 'G'), - central_elements=('C',), - weights=weights, parity=parity) + GradedLieConformalAlgebra.__init__(self, R, nsdict, names=('L', 'G'), central_elements=('C',), weights=weights, parity=parity) def _repr_(self) -> str: """ @@ -83,5 +78,4 @@ def _repr_(self) -> str: sage: R = lie_conformal_algebras.NeveuSchwarz(GF(5)); R The Neveu-Schwarz super Lie conformal algebra over Finite Field of size 5 """ - return "The Neveu-Schwarz super Lie conformal algebra over {}".\ - format(self.base_ring()) + return "The Neveu-Schwarz super Lie conformal algebra over {}".format(self.base_ring()) diff --git a/src/sage/algebras/lie_conformal_algebras/virasoro_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/virasoro_lie_conformal_algebra.py index 945f17893d0..c017ed03ba6 100644 --- a/src/sage/algebras/lie_conformal_algebras/virasoro_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/virasoro_lie_conformal_algebra.py @@ -54,6 +54,7 @@ class VirasoroLieConformalAlgebra(GradedLieConformalAlgebra): sage: Vir.gens() (L, C) """ + def __init__(self, R) -> None: """ Initialize ``self``. @@ -63,12 +64,8 @@ def __init__(self, R) -> None: sage: V = lie_conformal_algebras.Virasoro(QQ) sage: TestSuite(V).run() """ - virdict = {('L', 'L'): {0: {('L', 1): 1}, - 1: {('L', 0): 2}, - 3: {('C', 0): R(2).inverse_of_unit()}}} - GradedLieConformalAlgebra.__init__(self, R, virdict, names=('L',), - central_elements=('C',), - weights=(2,)) + virdict = {('L', 'L'): {0: {('L', 1): 1}, 1: {('L', 0): 2}, 3: {('C', 0): R(2).inverse_of_unit()}}} + GradedLieConformalAlgebra.__init__(self, R, virdict, names=('L',), central_elements=('C',), weights=(2,)) def _repr_(self) -> str: """ @@ -79,5 +76,4 @@ def _repr_(self) -> str: sage: lie_conformal_algebras.Virasoro(QQbar) The Virasoro Lie conformal algebra over Algebraic Field """ - return "The Virasoro Lie conformal algebra over {}".format( - self.base_ring()) + return "The Virasoro Lie conformal algebra over {}".format(self.base_ring()) diff --git a/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py index f69eee58731..b43e708282b 100644 --- a/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py @@ -120,8 +120,8 @@ class WeylLieConformalAlgebra(LieConformalAlgebraWithStructureCoefficients): [0 1 0] [0 0 1] """ - def __init__(self, R, ngens=None, gram_matrix=None, names=None, - index_set=None): + + def __init__(self, R, ngens=None, gram_matrix=None, names=None, index_set=None): """ Initialize ``self``. @@ -131,48 +131,37 @@ def __init__(self, R, ngens=None, gram_matrix=None, names=None, sage: TestSuite(V).run() """ from sage.matrix.matrix_space import MatrixSpace + if ngens: from sage.rings.integer_ring import ZZ + if not (ngens in ZZ and not ngens % 2): - raise ValueError("ngens needs to be an even positive Integer, " - f"got {ngens}") + raise ValueError("ngens needs to be an even positive Integer, " f"got {ngens}") if gram_matrix is not None: if ngens is None: ngens = gram_matrix.dimensions()[0] try: - assert (gram_matrix in MatrixSpace(R, ngens, ngens)) + assert gram_matrix in MatrixSpace(R, ngens, ngens) except AssertionError: - raise ValueError("the Gram_matrix should be a " - "skew-symmetric {0} x {0} matrix, got {1}" - .format(ngens, gram_matrix)) - if (not gram_matrix.is_skew_symmetric() or - gram_matrix.is_singular()): - raise ValueError("the Gram_matrix should be a non degenerate " - "skew-symmetric {0} x {0} matrix, got {1}" - .format(ngens, gram_matrix)) + raise ValueError("the Gram_matrix should be a " "skew-symmetric {0} x {0} matrix, got {1}".format(ngens, gram_matrix)) + if not gram_matrix.is_skew_symmetric() or gram_matrix.is_singular(): + raise ValueError("the Gram_matrix should be a non degenerate " "skew-symmetric {0} x {0} matrix, got {1}".format(ngens, gram_matrix)) elif gram_matrix is None: if ngens is None: ngens = 2 A = identity_matrix(R, ngens // 2) from sage.matrix.special import block_matrix + gram_matrix = block_matrix([[R.zero(), A], [-A, R.zero()]]) latex_names = None if (names is None) and (index_set is None): names = 'alpha' - latex_names = tuple(r'\alpha_{%d}' % i - for i in range(ngens)) + ('K',) - names, index_set = standardize_names_index_set(names=names, - index_set=index_set, - ngens=ngens) - weyldict = {(i, j): {0: {('K', 0): gram_matrix[index_set.rank(i), - index_set.rank(j)]}} - for i in index_set for j in index_set} - - super().__init__(R, weyldict, names=names, - latex_names=latex_names, - index_set=index_set, - central_elements=('K',)) + latex_names = tuple(r'\alpha_{%d}' % i for i in range(ngens)) + ('K',) + names, index_set = standardize_names_index_set(names=names, index_set=index_set, ngens=ngens) + weyldict = {(i, j): {0: {('K', 0): gram_matrix[index_set.rank(i), index_set.rank(j)]}} for i in index_set for j in index_set} + + super().__init__(R, weyldict, names=names, latex_names=latex_names, index_set=index_set, central_elements=('K',)) self._gram_matrix = gram_matrix def _repr_(self) -> str: @@ -184,8 +173,7 @@ def _repr_(self) -> str: sage: R = lie_conformal_algebras.Weyl(ZZ); R The Weyl Lie conformal algebra with generators (alpha0, alpha1, K) over Integer Ring """ - return "The Weyl Lie conformal algebra with generators {} over {}"\ - .format(self.gens(), self.base_ring()) + return "The Weyl Lie conformal algebra with generators {} over {}".format(self.gens(), self.base_ring()) def gram_matrix(self): r""" diff --git a/src/sage/algebras/nil_coxeter_algebra.py b/src/sage/algebras/nil_coxeter_algebra.py index d34528042ea..2f8bad30576 100644 --- a/src/sage/algebras/nil_coxeter_algebra.py +++ b/src/sage/algebras/nil_coxeter_algebra.py @@ -1,6 +1,7 @@ """ Nil-Coxeter Algebra """ + # *************************************************************************** # Copyright (C) 2011 Chris Berg # Anne Schilling @@ -181,9 +182,9 @@ def k_schur_noncommutative_variables(self, la): """ assert self._cartan_type[0] == 'A' and len(self._cartan_type) == 3 and self._cartan_type[2] == 1, "%s is not affine type A." % (self._W) assert la in Partitions(), "%s is not a partition." % (la) - assert (len(la) == 0 or la[0] < self._W.n), "%s is not a %s-bounded partition." % (la, self._W.n-1) + assert len(la) == 0 or la[0] < self._W.n, "%s is not a %s-bounded partition." % (la, self._W.n - 1) Sym = SymmetricFunctions(self._base_ring) h = Sym.homogeneous() - ks = Sym.kschur(self._n-1,1) + ks = Sym.kschur(self._n - 1, 1) f = h(ks[la]) - return sum(f.coefficient(x)*self.homogeneous_noncommutative_variables(x) for x in f.support()) + return sum(f.coefficient(x) * self.homogeneous_noncommutative_variables(x) for x in f.support()) diff --git a/src/sage/algebras/orlik_solomon.py b/src/sage/algebras/orlik_solomon.py index 2f571dc5d74..18c41e53cea 100644 --- a/src/sage/algebras/orlik_solomon.py +++ b/src/sage/algebras/orlik_solomon.py @@ -84,6 +84,7 @@ class OrlikSolomonAlgebra(CombinatorialFreeModule): - [CE2001]_ """ + @staticmethod def __classcall_private__(cls, R, M, ordering=None): """ @@ -123,7 +124,7 @@ def __init__(self, R, M, ordering=None): sage: TestSuite(OS).run(elements=elts) """ self._M = M - self._sorting = {x:i for i,x in enumerate(ordering)} + self._sorting = {x: i for i, x in enumerate(ordering)} # set up the dictionary of broken circuits self._broken_circuits = {} @@ -132,10 +133,7 @@ def __init__(self, R, M, ordering=None): self._broken_circuits[frozenset(L[1:])] = L[0] cat = Algebras(R).FiniteDimensional().WithBasis().Graded() - CombinatorialFreeModule.__init__(self, R, list(M.no_broken_circuits_sets(ordering)), - prefix='OS', bracket='{', - sorting_key=self._sort_key, - category=cat) + CombinatorialFreeModule.__init__(self, R, list(M.no_broken_circuits_sets(ordering)), prefix='OS', bracket='{', sorting_key=self._sort_key, category=cat) def _sort_key(self, x): """ @@ -220,8 +218,7 @@ def algebra_generators(self): sage: OS.algebra_generators() Finite family {0: OS{0}, 1: OS{0}, 2: OS{0}} """ - return Family(sorted(self._M.groundset()), - lambda i: self.subset_image(frozenset([i]))) + return Family(sorted(self._M.groundset()), lambda i: self.subset_image(frozenset([i]))) @cached_method def product_on_basis(self, a, b): @@ -284,7 +281,7 @@ def product_on_basis(self, a, b): # insert i into nbc, keeping track of sign in coeff ns = b.union({i}) ns_sorted = sorted(ns, key=lambda x: self._sorting[x]) - coeff = (-1)**ns_sorted.index(i) + coeff = (-1) ** ns_sorted.index(i) return R(coeff) * self.subset_image(ns) @@ -294,7 +291,7 @@ def product_on_basis(self, a, b): if len(a) % 4 < 2: sign = R.one() else: - sign = - R.one() + sign = -R.one() r = self._from_dict({b: sign}, remove_zeros=False) # now do the multiplication generator by generator @@ -487,6 +484,7 @@ def as_gca(self): [1, 10, 29, 20, 0] """ from sage.algebras.commutative_dga import GradedCommutativeAlgebra + gens = self.algebra_generators() gkeys = gens.keys() names = ['e{}'.format(i) for i in range(len(gens))] @@ -497,7 +495,7 @@ def as_gca(self): indices = [gkeys.index(el) for el in bclist] indices.sort() rel = A.zero() - sign = -(-1)**len(indices) + sign = -((-1) ** len(indices)) for i in indices: mon = A.one() for j in indices: @@ -578,23 +576,24 @@ def aomoto_complex(self, omega): if not omega.is_homogeneous() or omega.degree() != 1: raise ValueError("omega must be a homogeneous element of degree 1") from sage.homology.chain_complex import ChainComplex + R = self.base_ring() from collections import defaultdict from sage.matrix.constructor import matrix + graded_basis = defaultdict(list) B = self.basis() for k in B.keys(): graded_basis[len(k)].append(k) degrees = list(graded_basis) - data = {i: matrix.zero(R, len(graded_basis[i+1]), len(graded_basis[i])) - for i in degrees} + data = {i: matrix.zero(R, len(graded_basis[i + 1]), len(graded_basis[i])) for i in degrees} for i in degrees: mat = data[i] for j, key in enumerate(graded_basis[i]): ret = (omega * B[key]).monomial_coefficients(copy=False) - for k, imkey in enumerate(graded_basis[i+1]): + for k, imkey in enumerate(graded_basis[i + 1]): if imkey in ret: - mat[k,j] = ret[imkey] + mat[k, j] = ret[imkey] mat.set_immutable() return ChainComplex(data, R) @@ -733,6 +732,7 @@ class OrlikSolomonInvariantAlgebra(FiniteDimensionalInvariantModule): `g \cdot I \in \mathcal{I}` for every `g \in G` and for every `I \in \mathcal{I}`. """ + def __init__(self, R, M, G, action_on_groundset=None, *args, **kwargs): r""" Initialize ``self``. @@ -762,8 +762,7 @@ def action_on_groundset(g, x): category = kwargs.pop('category', OS.category().Subobjects()) def action(g, m): - return OS.sum(c * self._basis_action(g, x) - for x, c in m._monomial_coefficients.items()) + return OS.sum(c * self._basis_action(g, x) for x, c in m._monomial_coefficients.items()) self._action = action @@ -783,12 +782,8 @@ def action(g, m): # by `OS_d.invariant_module`, and so we pass to the superclass # of `FiniteDimensionalInvariantModule`, which is `SubmoduleWithBasis`. from sage.modules.with_basis.subquotient import SubmoduleWithBasis - SubmoduleWithBasis.__init__(self, Family(B), - support_order=OS._compute_support_order(B), - ambient=OS, - unitriangular=False, - category=category, - *args, **kwargs) + + SubmoduleWithBasis.__init__(self, Family(B), support_order=OS._compute_support_order(B), ambient=OS, unitriangular=False, category=category, *args, **kwargs) # To subclass FiniteDimensionalInvariant module, we also need a # self._semigroup attribute. diff --git a/src/sage/algebras/orlik_terao.py b/src/sage/algebras/orlik_terao.py index e0df9cdaebd..965c3e802b3 100644 --- a/src/sage/algebras/orlik_terao.py +++ b/src/sage/algebras/orlik_terao.py @@ -101,6 +101,7 @@ class OrlikTeraoAlgebra(CombinatorialFreeModule): - [FL2001]_ - [CF2005]_ """ + @staticmethod def __classcall_private__(cls, R, M, ordering=None): """ @@ -160,10 +161,7 @@ def __init__(self, R, M, ordering=None): self._broken_circuits[frozenset(L[1:])] = L[0] cat = Algebras(R).FiniteDimensional().Commutative().WithBasis().Graded() - CombinatorialFreeModule.__init__(self, R, list(M.no_broken_circuits_sets(ordering)), - prefix='OT', bracket='{', - sorting_key=self._sort_key, - category=cat) + CombinatorialFreeModule.__init__(self, R, list(M.no_broken_circuits_sets(ordering)), prefix='OT', bracket='{', sorting_key=self._sort_key, category=cat) def _sort_key(self, x): r""" @@ -213,6 +211,7 @@ def _latex_term(self, m) -> str: from sage.misc.latex import latex from sage.sets.set import Set + return "e_{{{}}}".format(latex(Set(sorted(m)))) def _repr_(self) -> str: @@ -270,8 +269,7 @@ def algebra_generators(self): Finite family {'a': OT{a}, 'b': OT{b}, 'c': OT{c}, 'd': OT{d}, 'e': OT{e}, 'f': OT{f}, 'g': OT{g}} """ - return Family(sorted(self._M.groundset()), - lambda i: self.subset_image(frozenset([i]))) + return Family(sorted(self._M.groundset()), lambda i: self.subset_image(frozenset([i]))) def degree_on_basis(self, m): r""" @@ -506,7 +504,7 @@ def _chi(self, X): """ R = self.base_ring() assert self._M.is_independent(X) - #if not self._M.is_independent(X): + # if not self._M.is_independent(X): # return R.zero() M = self._M rep_vecs = M.representation_vectors() @@ -600,6 +598,7 @@ class OrlikTeraoInvariantAlgebra(FiniteDimensionalInvariantModule): sage: [OTG.lift(b) for b in OTG.basis()] [OT{}, OT{0} + OT{1} + OT{2} + OT{3} + OT{4} + OT{5}] """ + def __init__(self, R, M, G, action_on_groundset=None, *args, **kwargs): r""" Initialize ``self``. @@ -634,29 +633,25 @@ def action_on_groundset(g, x): category = kwargs.pop('category') else: from sage.categories.modules import Modules + category = Modules(R).FiniteDimensional().WithBasis().Subobjects() def action(g, m): - return OT.sum(c * self._basis_action(g, x) - for x, c in m._monomial_coefficients.items()) + return OT.sum(c * self._basis_action(g, x) for x, c in m._monomial_coefficients.items()) self._action = action max_deg = max([b.degree() for b in OT.basis()]) B = [] # compute invariant degree-by-degree - for d in range(max_deg+1): + for d in range(max_deg + 1): OT_d = OT.homogeneous_component(d) OTG_d = OT_d.invariant_module(G, action=action, category=category) B += [OT_d.lift(OTG_d.lift(b)) for b in OTG_d.basis()] from sage.modules.with_basis.subquotient import SubmoduleWithBasis - SubmoduleWithBasis.__init__(self, Family(B), - support_order=OT._compute_support_order(B), - ambient=OT, - unitriangular=False, - category=category, - *args, **kwargs) + + SubmoduleWithBasis.__init__(self, Family(B), support_order=OT._compute_support_order(B), ambient=OT, unitriangular=False, category=category, *args, **kwargs) self._semigroup = G diff --git a/src/sage/algebras/q_commuting_polynomials.py b/src/sage/algebras/q_commuting_polynomials.py index 1365ec17419..ce03991a37a 100644 --- a/src/sage/algebras/q_commuting_polynomials.py +++ b/src/sage/algebras/q_commuting_polynomials.py @@ -48,6 +48,7 @@ class qCommutingPolynomials_generic(CombinatorialFreeModule): This is a graded `R`-algebra with a natural basis given by monomials written in increasing order with respect to some total order on `I`. """ + @staticmethod def __classcall__(cls, q, n=None, B=None, base_ring=None, names=None): r""" @@ -71,6 +72,7 @@ def __classcall__(cls, q, n=None, B=None, base_ring=None, names=None): if names is None: raise ValueError("the names of the variables must be given") from sage.structure.category_object import normalize_names + if n is None: if isinstance(names, str): n = names.count(',') + 1 @@ -81,7 +83,7 @@ def __classcall__(cls, q, n=None, B=None, base_ring=None, names=None): if B is None: B = matrix.zero(ZZ, n) for i in range(n): - for j in range(i+1, n): + for j in range(i + 1, n): B[i, j] = 1 B[j, i] = -1 B.set_immutable() @@ -108,10 +110,7 @@ def __init__(self, q, B, indices, names): if base_ring not in CommutativeRings(): raise ValueError("the base ring must be a commutative ring") category = Algebras(base_ring).WithBasis().Graded() - CombinatorialFreeModule.__init__(self, base_ring, indices, - bracket=False, prefix='', - sorting_key=qCommutingPolynomials_generic._term_key, - names=names, category=category) + CombinatorialFreeModule.__init__(self, base_ring, indices, bracket=False, prefix='', sorting_key=qCommutingPolynomials_generic._term_key, names=names, category=category) @staticmethod def _term_key(x): @@ -275,6 +274,7 @@ class qCommutingPolynomials(qCommutingPolynomials_generic): sage: all(f[b] == q_binomial(10, b.list()[1], q^3) for b in f.support()) True """ + def __init__(self, q, B, names): r""" Initialize ``self``. @@ -396,7 +396,7 @@ def product_on_basis(self, x, y): # This could be made more efficient B = self._B qpow = sum(exp * sum(B[j, i] * val for j, val in enumerate(Ly[:i])) for i, exp in enumerate(Lx) if exp) - return self.term(x * y, self._q ** qpow) + return self.term(x * y, self._q**qpow) class qCommutingLaurentPolynomials(qCommutingPolynomials_generic): @@ -451,6 +451,7 @@ class qCommutingLaurentPolynomials(qCommutingPolynomials_generic): sage: all(f[b] == q_binomial(10, -b.list()[1], q^3) for b in f.support()) True """ + def __init__(self, q, B, names): r""" Initialize ``self``. @@ -495,6 +496,7 @@ def _latex_(self) -> str: \mathrm{Frac}(\Bold{Z}[q])[x^{\pm}, y^{\pm}, z^{\pm}]_{q} """ from sage.misc.latex import latex + names = ", ".join(r"{}^{{\pm}}".format(v) for v in self.variable_names()) return "{}[{}]_{{{}}}".format(latex(self.base_ring()), names, self._q) @@ -516,7 +518,7 @@ def _repr_term(self, m) -> str: if not m: return '1' G = self._display_group - return repr(G.prod(g ** val for g, val in zip(G.gens(), m) if val != 0)) + return repr(G.prod(g**val for g, val in zip(G.gens(), m) if val != 0)) def _latex_term(self, m) -> str: r""" @@ -536,7 +538,7 @@ def _latex_term(self, m) -> str: if not m: return '1' G = self._display_group - return latex(G.prod(g ** val for g, val in zip(G.gens(), m) if val != 0)) + return latex(G.prod(g**val for g, val in zip(G.gens(), m) if val != 0)) @cached_method def one_basis(self): @@ -631,7 +633,7 @@ def product_on_basis(self, x, y): qpow = sum(exp * sum(B[j, i] * y[j] for j in range(i)) for i, exp in enumerate(x) if exp) ret = x + y ret.set_immutable() - return self.term(ret, self._q ** qpow) + return self.term(ret, self._q**qpow) class Element(qCommutingPolynomials_generic.Element): def __invert__(self): @@ -664,8 +666,7 @@ def __invert__(self): m, c = next(iter(self._monomial_coefficients.items())) ret = -m n = len(m) - qpow = sum(exp * sum(B[j, i] * m[j] for j in range(i+1, n)) - for i, exp in enumerate(m) if exp) + qpow = sum(exp * sum(B[j, i] * m[j] for j in range(i + 1, n)) for i, exp in enumerate(m) if exp) ret.set_immutable() return P.term(ret, ~c * q**-qpow) return super().__invert__() diff --git a/src/sage/algebras/q_system.py b/src/sage/algebras/q_system.py index f388b9df247..cb7996f5703 100644 --- a/src/sage/algebras/q_system.py +++ b/src/sage/algebras/q_system.py @@ -7,7 +7,7 @@ - Travis Scrimshaw (2017-12-08): Added twisted Q-systems """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2013,2017 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** import itertools from sage.misc.cachefunc import cached_method @@ -124,6 +124,7 @@ class QSystem(CombinatorialFreeModule): - [HKOTY1999]_ - [KNS2011]_ """ + @staticmethod def __classcall__(cls, base_ring, cartan_type, level=None, twisted=False): """ @@ -172,12 +173,11 @@ def __init__(self, base_ring, cartan_type, level, twisted): self._cm = cartan_type.classical().cartan_matrix() else: self._cm = cartan_type.cartan_matrix() - self._Irev = {ind: pos for pos,ind in enumerate(self._cm.index_set())} - self._poly = PolynomialRing(ZZ, ['q'+str(i) for i in self._cm.index_set()]) + self._Irev = {ind: pos for pos, ind in enumerate(self._cm.index_set())} + self._poly = PolynomialRing(ZZ, ['q' + str(i) for i in self._cm.index_set()]) category = Algebras(base_ring).Commutative().WithBasis() - CombinatorialFreeModule.__init__(self, base_ring, basis, - prefix='Q', category=category) + CombinatorialFreeModule.__init__(self, base_ring, basis, prefix='Q', category=category) def _repr_(self) -> str: r""" @@ -218,6 +218,7 @@ def repr_gen(x): if x[1] > 1: ret += '^{}'.format(x[1]) return ret + return '*'.join(repr_gen(x) for x in t._sorted_items()) def _latex_term(self, t) -> str: @@ -240,6 +241,7 @@ def repr_gen(x): if x[1] > 1: ret = '\\bigl(' + ret + '\\bigr)^{{{}}}'.format(x[1]) return ret + return ' '.join(repr_gen(x) for x in t._sorted_items()) def _ascii_art_term(self, t): @@ -255,6 +257,7 @@ def _ascii_art_term(self, t): 1 + 2*Q1 + (Q1 ) *(Q1 ) *(Q1 ) + 3*Q1 """ from sage.typeset.ascii_art import AsciiArt + if t == self.one_basis(): return AsciiArt(["1"]) ret = AsciiArt("") @@ -265,12 +268,9 @@ def _ascii_art_term(self, t): else: first = False a, m = k - var = AsciiArt([" ({})".format(a), - "Q{}".format(m)], - baseline=0) + var = AsciiArt([" ({})".format(a), "Q{}".format(m)], baseline=0) if exp > 1: - var = (AsciiArt(['(', '('], baseline=0) + var - + AsciiArt([')', ')'], baseline=0)) + var = AsciiArt(['(', '('], baseline=0) + var + AsciiArt([')', ')'], baseline=0) var = AsciiArt([" " * len(var) + str(exp)], baseline=-1) * var ret += var return ret @@ -286,16 +286,16 @@ def _unicode_art_term(self, t): 1 + 2*Q₁⁽¹⁾ + (Q₁⁽¹⁾)²(Q₁⁽²⁾)²(Q₁⁽³⁾)³ + 3*Q₁⁽²⁾ """ from sage.typeset.unicode_art import UnicodeArt, unicode_subscript, unicode_superscript + if t == self.one_basis(): return UnicodeArt(["1"]) ret = UnicodeArt("") for k, exp in t._sorted_items(): - a,m = k + a, m = k var = UnicodeArt(["Q" + unicode_subscript(m) + '⁽' + unicode_superscript(a) + '⁾'], baseline=0) if exp > 1: - var = (UnicodeArt(['('], baseline=0) + var - + UnicodeArt([')' + unicode_superscript(exp)], baseline=0)) + var = UnicodeArt(['('], baseline=0) + var + UnicodeArt([')' + unicode_superscript(exp)], baseline=0) ret += var return ret @@ -445,12 +445,12 @@ def Q(self, a, m): if m == t[a] * self._level: return self.one() if m == 1: - return self.monomial(self._indices.gen((a,1))) - #if self._cartan_type.type() == 'A' and self._level is None: + return self.monomial(self._indices.gen((a, 1))) + # if self._cartan_type.type() == 'A' and self._level is None: # return self._jacobi_trudy(a, m) I = self._cm.index_set() p = self._Q_poly(a, m) - return p.subs({g: self.Q(I[i], 1) for i,g in enumerate(self._poly.gens())}) + return p.subs({g: self.Q(I[i], 1) for i, g in enumerate(self._poly.gens())}) @cached_method def _Q_poly(self, a, m): @@ -526,28 +526,28 @@ def _Q_poly(self, a, m): return self._poly.gen(self._Irev[a]) cm = self._cm - m -= 1 # So we don't have to do it everywhere + m -= 1 # So we don't have to do it everywhere cur = self._Q_poly(a, m) ** 2 if self._twisted: - ret = prod(self._Q_poly(b, m) ** -cm[self._Irev[b],self._Irev[a]] - for b in self._cm.dynkin_diagram().neighbors(a)) + ret = prod(self._Q_poly(b, m) ** -cm[self._Irev[b], self._Irev[a]] for b in self._cm.dynkin_diagram().neighbors(a)) else: ret = self._poly.one() i = self._Irev[a] for b in self._cm.dynkin_diagram().neighbors(a): j = self._Irev[b] - for k in range(-cm[i,j]): - ret *= self._Q_poly(b, (m * cm[j,i] - k) // cm[i,j]) + for k in range(-cm[i, j]): + ret *= self._Q_poly(b, (m * cm[j, i] - k) // cm[i, j]) cur -= ret if m > 1: - cur //= self._Q_poly(a, m-1) + cur //= self._Q_poly(a, m - 1) return cur class Element(CombinatorialFreeModule.Element): """ An element of a Q-system. """ + def _mul_(self, x): """ Return the product of ``self`` and ``x``. @@ -561,9 +561,7 @@ def _mul_(self, x): -Q^(1)[1]^2*Q^(2)[1]*Q^(4)[1] + Q^(1)[1]^2*Q^(3)[1]^2 + Q^(2)[1]^2*Q^(4)[1] - Q^(2)[1]*Q^(3)[1]^2 """ - return self.parent().sum_of_terms((tl*tr, cl*cr) - for tl, cl in self - for tr, cr in x) + return self.parent().sum_of_terms((tl * tr, cl * cr) for tl, cl in self for tr, cr in x) def is_tamely_laced(ct) -> bool: @@ -597,11 +595,9 @@ def is_tamely_laced(ct) -> bool: return True if ct.is_affine(): - return not (ct is CartanType(['A',1,1]) or - (ct.type() == 'BC' or ct.dual().type() == 'BC')) + return not (ct is CartanType(['A', 1, 1]) or (ct.type() == 'BC' or ct.dual().type() == 'BC')) cm = ct.cartan_matrix() d = cm.symmetrizer() I = ct.index_set() - return all(-cm[j,i] == 1 and d[i] == 1 - for i in I for j in I if cm[i,j] < -1) + return all(-cm[j, i] == 1 and d[i] == 1 for i in I for j in I if cm[i, j] < -1) diff --git a/src/sage/algebras/quantum_clifford.py b/src/sage/algebras/quantum_clifford.py index be33f760106..2dd0df93629 100644 --- a/src/sage/algebras/quantum_clifford.py +++ b/src/sage/algebras/quantum_clifford.py @@ -142,6 +142,7 @@ class QuantumCliffordAlgebra(CombinatorialFreeModule): sage: w0^2 1 """ + @staticmethod def __classcall_private__(cls, n, k=1, q=None, F=None): r""" @@ -165,7 +166,7 @@ def __classcall_private__(cls, n, k=1, q=None, F=None): F = FractionField(F) q = F(q) - if bool(q**(2*k) == 1): + if bool(q ** (2 * k) == 1): return QuantumCliffordAlgebraRootUnity(n, k, q, F) return QuantumCliffordAlgebraGeneric(n, k, q, F) @@ -199,8 +200,7 @@ def _repr_(self) -> str: Quantum Clifford algebra of rank 3 and twist 1 with q=q over Fraction Field of Univariate Polynomial Ring in q over Integer Ring """ - return "Quantum Clifford algebra of rank {} and twist {} with q={} over {}".format( - self._n, self._k, self._q, self.base_ring()) + return "Quantum Clifford algebra of rank {} and twist {} with q={} over {}".format(self._n, self._k, self._q, self.base_ring()) def _latex_(self) -> str: r""" @@ -268,7 +268,7 @@ def dimension(self): sage: Cl.dimension() # long time 65536 """ - return ZZ(8*self._k) ** self._n + return ZZ(8 * self._k) ** self._n @cached_method def algebra_generators(self): @@ -323,7 +323,7 @@ def one_basis(self): sage: Cl.one_basis() ((0, 0, 0), (0, 0, 0)) """ - return (self._psi([0]*self._n), (0,)*self._n) + return (self._psi([0] * self._n), (0,) * self._n) class QuantumCliffordAlgebraGeneric(QuantumCliffordAlgebra): @@ -356,6 +356,7 @@ class QuantumCliffordAlgebraGeneric(QuantumCliffordAlgebra): When `k = 2`, we recover the original definition given by Hayashi in [Hayashi1990]_. The `k = 1` version was used in [Kwon2014]_. """ + def __init__(self, n, k, q, F): r""" Initialize ``self``. @@ -373,10 +374,8 @@ def __init__(self, n, k, q, F): sage: elts = Cl.some_elements() + list(Cl.algebra_generators()) sage: TestSuite(Cl).run(elements=elts) # long time """ - psi = cartesian_product([(-1,0,1)]*n) - indices = [(tuple(p), tuple(w)) - for p in psi - for w in product(*[list(range((4-2*abs(p[i]))*k)) for i in range(n)])] + psi = cartesian_product([(-1, 0, 1)] * n) + indices = [(tuple(p), tuple(w)) for p in psi for w in product(*[list(range((4 - 2 * abs(p[i])) * k)) for i in range(n)])] super().__init__(n, k, q, F, psi, indices) def _repr_term(self, m) -> str: @@ -399,8 +398,7 @@ def _repr_term(self, m) -> str: 5 """ p, v = m - rp = '*'.join('psi%s' % i if p[i] > 0 else 'psid%s' % i - for i in range(self._n) if p[i] != 0) + rp = '*'.join('psi%s' % i if p[i] > 0 else 'psid%s' % i for i in range(self._n) if p[i] != 0) gen_str = lambda e: '' if e == 1 else '^%s' % e rv = '*'.join('w%s' % i + gen_str(v[i]) for i in range(self._n) if v[i] != 0) if rp: @@ -431,11 +429,9 @@ def _latex_term(self, m) -> str: 5 """ p, v = m - rp = ''.join('\\psi_{%s}' % i if p[i] > 0 else '\\psi^{\\dagger}_{%s}' % i - for i in range(self._n) if p[i] != 0) + rp = ''.join('\\psi_{%s}' % i if p[i] > 0 else '\\psi^{\\dagger}_{%s}' % i for i in range(self._n) if p[i] != 0) gen_str = lambda e: '' if e == 1 else '^{%s}' % e - rv = ''.join('\\omega_{%s}' % i + gen_str(v[i]) - for i in range(self._n) if v[i] != 0) + rv = ''.join('\\omega_{%s}' % i + gen_str(v[i]) for i in range(self._n) if v[i] != 0) if not rp and not rv: return '1' return rp + rv @@ -487,17 +483,17 @@ def product_on_basis(self, m1, m2): q_power += w1[i] * p2[i] if p1[i] != 0: # We make pairings 1-based because we cannot distinguish 0 and -0 - pairings.append((i+1) * p1[i]) + pairings.append((i + 1) * p1[i]) # we know p1[i] != p2[i] if nonzero, so their sum is -1, 0, 1 p[i] = p1[i] + p2[i] - supported.append(self._n-1) # To get between the last support and the end + supported.append(self._n - 1) # To get between the last support and the end # Get the sign of moving \psi_i and \psi_i^{\dagger} into position for i in reversed(range(1, len(supported))): if i % 2 != 0: - for j in reversed(range(supported[i-1]+1, supported[i]+1)): + for j in reversed(range(supported[i - 1] + 1, supported[i] + 1)): if p1[j] != 0: - sign = (-1)**i * sign + sign = (-1) ** i * sign # We move the pairs \psi_i \psi_i^{\dagger} (or the reverse) to the # end of the \psi part. This does not change the sign because they @@ -508,13 +504,13 @@ def product_on_basis(self, m1, m2): q = self._q for i in pairings: if i < 0: - i = -i - 1 # Go back to 0-based - vpik = -q**(2*k) * vp[i]**(3*k) + (1 + q**(2*k)) * vp[i]**k - poly *= -(vp[i]**k - vpik) / (q**k - q**(-k)) + i = -i - 1 # Go back to 0-based + vpik = -(q ** (2 * k)) * vp[i] ** (3 * k) + (1 + q ** (2 * k)) * vp[i] ** k + poly *= -(vp[i] ** k - vpik) / (q**k - q ** (-k)) else: - i -= 1 # Go back to 0-based - vpik = -q**(2*k) * vp[i]**(3*k) + (1 + q**(2*k)) * vp[i]**k - poly *= (q**k * vp[i]**k - q**(-k) * vpik) / (q**k - q**(-k)) + i -= 1 # Go back to 0-based + vpik = -(q ** (2 * k)) * vp[i] ** (3 * k) + (1 + q ** (2 * k)) * vp[i] ** k + poly *= (q**k * vp[i] ** k - q ** (-k) * vpik) / (q**k - q ** (-k)) v = list(w1) for i in range(self._n): @@ -524,17 +520,15 @@ def product_on_basis(self, m1, m2): # and same for \psi_i^{\dagger} for i in range(self._n): if p[i] > 0 and v[i] != 0: - q_power -= 2 * k * (v[i] // (2*k)) - v[i] = v[i] % (2*k) + q_power -= 2 * k * (v[i] // (2 * k)) + v[i] = v[i] % (2 * k) if p[i] < 0 and v[i] != 0: - v[i] = v[i] % (2*k) + v[i] = v[i] % (2 * k) poly *= self._w_poly.monomial(*v) - poly = poly.reduce([vp[i]**(4*k) - (1 + q**(-2*k)) * vp[i]**(2*k) + q**(-2*k) - for i in range(self._n)]) + poly = poly.reduce([vp[i] ** (4 * k) - (1 + q ** (-2 * k)) * vp[i] ** (2 * k) + q ** (-2 * k) for i in range(self._n)]) pdict = poly.monomial_coefficients() - ret = {(self._psi(p), tuple(e)): pdict[e] * q**q_power * sign - for e in pdict} + ret = {(self._psi(p), tuple(e)): pdict[e] * q**q_power * sign for e in pdict} return self._from_dict(ret) @@ -598,17 +592,15 @@ def inverse(self): if len(self) != 1: return super().__invert__() Cl = self.parent() - ((p, w), coeff), = list(self._monomial_coefficients.items()) + (((p, w), coeff),) = list(self._monomial_coefficients.items()) if any(p[i] != 0 for i in range(Cl._n)): return super().__invert__() poly = Cl._w_poly.monomial(*w) wp = Cl._w_poly.gens() q = Cl._q k = Cl._k - poly = poly.subs({wi: -q**(2*k) * wi**(4*k-1) + (1 + q**(2*k)) * wi**(2*k-1) - for wi in wp}) - poly = poly.reduce([wi**(4*k) - (1 + q**(-2*k)) * wi**(2*k) + q**(-2*k) - for wi in wp]) + poly = poly.subs({wi: -(q ** (2 * k)) * wi ** (4 * k - 1) + (1 + q ** (2 * k)) * wi ** (2 * k - 1) for wi in wp}) + poly = poly.reduce([wi ** (4 * k) - (1 + q ** (-2 * k)) * wi ** (2 * k) + q ** (-2 * k) for wi in wp]) pdict = poly.monomial_coefficients() coeff = coeff.inverse_of_unit() ret = {(p, tuple(e)): coeff * c for e, c in pdict.items()} @@ -652,6 +644,7 @@ class QuantumCliffordAlgebraRootUnity(QuantumCliffordAlgebra): (\psi_a \psi^*_a)^2 & = \psi_a \psi^*_a \omega_a^k. \end{aligned} """ + def __init__(self, n, k, q, F): r""" Initialize ``self``. @@ -673,10 +666,8 @@ def __init__(self, n, k, q, F): sage: elts = Cl.some_elements() + list(Cl.algebra_generators()) sage: TestSuite(Cl).run(elements=elts) # long time """ - psi = cartesian_product([(-1,0,1,2)]*n) - indices = [(tuple(p), tuple(w)) - for p in psi - for w in product(list(range(2*k)), repeat=n)] + psi = cartesian_product([(-1, 0, 1, 2)] * n) + indices = [(tuple(p), tuple(w)) for p in psi for w in product(list(range(2 * k)), repeat=n)] super().__init__(n, k, q, F, psi, indices) def _repr_term(self, m) -> str: @@ -707,7 +698,7 @@ def ppr(i): if val == 1: return 'psi%s' % i if val == 2: - return 'psi%s*psid%s' % (i,i) + return 'psi%s*psid%s' % (i, i) rp = '*'.join(ppr(i) for i in range(self._n) if p[i] != 0) gen_str = lambda e: '' if e == 1 else '^%s' % e @@ -752,8 +743,7 @@ def ppr(i): rp = ''.join(ppr(i) for i in range(self._n) if p[i] != 0) gen_str = lambda e: '' if e == 1 else '^{%s}' % e - rv = ''.join('\\omega_{%s}' % i + gen_str(v[i]) - for i in range(self._n) if v[i] != 0) + rv = ''.join('\\omega_{%s}' % i + gen_str(v[i]) for i in range(self._n) if v[i] != 0) if not rp and not rv: return '1' return rp + rv @@ -814,9 +804,7 @@ def product_on_basis(self, m1, m2): # \psi_i \psi_i^{\dagger} is a 2 in p1[i] and p2[i] # Check for \psi_i^2 == 0 and for the dagger version - if any((p1[i] % 2 != 0 and p1[i] == p2[i]) - or (p1[i] == 2 and p2[i] == -1) or (p2[i] == 2 and p1[i] == 1) - for i in range(self._n)): + if any((p1[i] % 2 != 0 and p1[i] == p2[i]) or (p1[i] == 2 and p2[i] == -1) or (p2[i] == 2 and p1[i] == 1) for i in range(self._n)): return self.zero() # Reduce any v_i^{2k} = 1 @@ -840,15 +828,15 @@ def product_on_basis(self, m1, m2): p[i] = p1[i] else: p[i] = p2[i] - elif p2[i] != 0: # == +1, -1 + elif p2[i] != 0: # == +1, -1 q_power += w1[i] * p2[i] # By the above check, we cannot have p1[i] == p2[i] if p1[i] == -1: pairings.append(i) - total_cross -= 1 # correction + total_cross -= 1 # correction p[i] = None elif p1[i] == 1: - total_cross -= 1 # correction + total_cross -= 1 # correction p[i] = 2 elif p1[i] == 2: q_power += k @@ -878,8 +866,7 @@ def key(X): return (self._psi(p), tuple(e)) q = self._q - ret = {key(X): (-1)**len(X) * sign * q**(q_power+k*(len(pairings) % 2)) - for X in powerset(pairings)} + ret = {key(X): (-1) ** len(X) * sign * q ** (q_power + k * (len(pairings) % 2)) for X in powerset(pairings)} return self._from_dict(ret) @@ -947,7 +934,7 @@ def inverse(self): if len(self) != 1: return super().__invert__() Cl = self.parent() - ((p, w), coeff), = list(self._monomial_coefficients.items()) + (((p, w), coeff),) = list(self._monomial_coefficients.items()) if any(p[i] != 0 for i in range(Cl._n)): return super().__invert__() tk = 2 * Cl._k diff --git a/src/sage/algebras/quantum_groups/ace_quantum_onsager.py b/src/sage/algebras/quantum_groups/ace_quantum_onsager.py index f3240aa663c..aa995678b39 100644 --- a/src/sage/algebras/quantum_groups/ace_quantum_onsager.py +++ b/src/sage/algebras/quantum_groups/ace_quantum_onsager.py @@ -104,6 +104,7 @@ class ACEQuantumOnsagerAlgebra(CombinatorialFreeModule): - [BS2010]_ - [Ter2021]_ """ + @staticmethod def __classcall_private__(cls, R=None, q=None): """ @@ -128,6 +129,7 @@ def __classcall_private__(cls, R=None, q=None): if R is None: raise ValueError("either base ring or q must be specified") from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + q = PolynomialRing(R, 'q').fraction_field().gen() R = q.parent() else: @@ -146,14 +148,10 @@ def __init__(self, R, q): sage: A = algebras.AlternatingCentralExtensionQuantumOnsager(QQ) sage: TestSuite(A).run() # long time """ - I = DisjointUnionEnumeratedSets([PositiveIntegers(), ZZ, PositiveIntegers()], - keepkey=True, facade=True) + I = DisjointUnionEnumeratedSets([PositiveIntegers(), ZZ, PositiveIntegers()], keepkey=True, facade=True) monomials = IndexedFreeAbelianMonoid(I, prefix='A', bracket=False) self._q = q - CombinatorialFreeModule.__init__(self, R, monomials, - prefix='', bracket=False, latex_bracket=False, - sorting_key=self._monomial_key, - category=Algebras(R).WithBasis().Filtered()) + CombinatorialFreeModule.__init__(self, R, monomials, prefix='', bracket=False, latex_bracket=False, sorting_key=self._monomial_key, category=Algebras(R).WithBasis().Filtered()) def _monomial_key(self, x): r""" @@ -182,8 +180,7 @@ def _repr_(self): Alternating Central Extension of q-Onsager algebra over Fraction Field of Univariate Polynomial Ring in q over Rational Field """ - return "Alternating Central Extension of {}-Onsager algebra over {}".format( - self._q, self.base_ring()) + return "Alternating Central Extension of {}-Onsager algebra over {}".format(self._q, self.base_ring()) def _latex_(self): r""" @@ -196,8 +193,8 @@ def _latex_(self): \mathcal{A}_{q,\mathrm{Frac}(\Bold{Q}[q])} """ from sage.misc.latex import latex - return "\\mathcal{{A}}_{{{},{}}}".format(latex(self._q), - latex(self.base_ring())) + + return "\\mathcal{{A}}_{{{},{}}}".format(latex(self._q), latex(self.base_ring())) def _repr_term(self, m): r""" @@ -218,6 +215,7 @@ def _repr_term(self, m): sage: A._repr_term(I[0,1]^2 * I[1,0] * I[1,3]^13 * I[2,3]) 'G[1]^2*W[0]*W[3]^13*Gt[3]' """ + def to_str(x): k, e = x if k[0] == 0: @@ -229,6 +227,7 @@ def to_str(x): if e > 1: ret = ret + "^{}".format(e) return ret + return '*'.join(to_str(x) for x in m._sorted_items()) def _latex_term(self, m): @@ -250,6 +249,7 @@ def _latex_term(self, m): sage: A._latex_term(I[0,1]^2 * I[1,0] * I[1,3]^13 * I[2,3]) '\\mathcal{G}_{1}^{2} \\mathcal{W}_{0} \\mathcal{W}_{3}^{13} \\widetilde{\\mathcal{G}}_{3}' """ + def to_str(x): k, e = x if k[0] == 0: @@ -261,6 +261,7 @@ def to_str(x): if e > 1: ret = ret + '^{{{}}}'.format(e) return ret + return ' '.join(to_str(x) for x in m._sorted_items()) @cached_method @@ -280,10 +281,10 @@ def algebra_generators(self): def monomial_map(x): if x[0] != 1 and x[1] == 0: - return self.term(self.one_basis(), -(q-~q)*(q+~q)**2) + return self.term(self.one_basis(), -(q - ~q) * (q + ~q) ** 2) return self.monomial(G[x]) - return Family(self._indices._indices, monomial_map, - name="generator map") + + return Family(self._indices._indices, monomial_map, name="generator map") gens = algebra_generators @@ -326,7 +327,7 @@ def _an_element_(self): q*G[2] - 2*W[-3] + W[2] - q*Gt[1] """ G = self.algebra_generators() - return G[1,2] - 2*G[1,-3] + self.base_ring().an_element()*(G[0,2] - G[2,1]) + return G[1, 2] - 2 * G[1, -3] + self.base_ring().an_element() * (G[0, 2] - G[2, 1]) def some_elements(self): r""" @@ -339,7 +340,7 @@ def some_elements(self): [W[0], W[3], W[-1], W[1], W[-2], G[1], G[2], Gt[1], Gt[2]] """ G = self.algebra_generators() - return [G[1,0], G[1,3], G[1,-1], G[1,1], G[1,-2], G[0,1], G[0,2], G[2,1], G[2,2]] + return [G[1, 0], G[1, 3], G[1, -1], G[1, 1], G[1, -2], G[0, 1], G[0, 2], G[2, 1], G[2, 2]] def degree_on_basis(self, m): r""" @@ -366,10 +367,12 @@ def degree_on_basis(self, m): sage: [x.degree() for x in A.some_elements()] [1, 5, 3, 1, 5, 2, 4, 2, 4] """ + def deg(k): if k[0] != 1: - return 2*k[1] - return -2*k[1]+1 if k[1] <= 0 else 2*k[1] - 1 + return 2 * k[1] + return -2 * k[1] + 1 if k[1] <= 0 else 2 * k[1] - 1 + return ZZ.sum(deg(k) * c for k, c in m._monomial.items()) @cached_method @@ -412,23 +415,23 @@ def quantum_onsager_pbw_generator(self, i): + ((-q^4+1)/q^2)*W[0]*W[2] + ((q^2-1)/q^4)*W[1]^2 - (1/(q^6+q^4-q^2-1))*Gt[1]^2 + 1/q^3*G[2] - 1/q^3*Gt[2] """ - W0 = self.algebra_generators()[1,0] - W1 = self.algebra_generators()[1,1] + W0 = self.algebra_generators()[1, 0] + W1 = self.algebra_generators()[1, 1] q = self._q if i[0] == 0: if i[1] < 0: if i[1] == -1: return W0 Bd = self.quantum_onsager_pbw_generator((1, 1)) - Bm1 = self.quantum_onsager_pbw_generator((0, i[1]+1)) - Bm2 = self.quantum_onsager_pbw_generator((0, i[1]+2)) - return Bm2 + q/(q**-3-~q-q+q**3) * (Bd * Bm1 - Bm1 * Bd) + Bm1 = self.quantum_onsager_pbw_generator((0, i[1] + 1)) + Bm2 = self.quantum_onsager_pbw_generator((0, i[1] + 2)) + return Bm2 + q / (q**-3 - ~q - q + q**3) * (Bd * Bm1 - Bm1 * Bd) if i[1] == 0: return W1 Bd = self.quantum_onsager_pbw_generator((1, 1)) - Bm1 = self.quantum_onsager_pbw_generator((0, i[1]-1)) - Bm2 = self.quantum_onsager_pbw_generator((0, i[1]-2)) - return Bm2 - q/(q**-3-~q-q+q**3) * (Bd * Bm1 - Bm1 * Bd) + Bm1 = self.quantum_onsager_pbw_generator((0, i[1] - 1)) + Bm2 = self.quantum_onsager_pbw_generator((0, i[1] - 2)) + return Bm2 - q / (q**-3 - ~q - q + q**3) * (Bd * Bm1 - Bm1 * Bd) if i[0] == 1: if i[1] == 1: return q**-2 * W1 * W0 - W0 * W1 @@ -436,10 +439,8 @@ def quantum_onsager_pbw_generator(self, i): raise ValueError("not an index of a PBW basis element") B = self.quantum_onsager_pbw_generator n = i[1] - Bm1 = self.quantum_onsager_pbw_generator((0, n-1)) - return (q**-2 * Bm1 * W0 - W0 * Bm1 - + (q**-2 - 1) * sum(B((0,ell)) * B((0,n-ell-2)) - for ell in range(n-1))) + Bm1 = self.quantum_onsager_pbw_generator((0, n - 1)) + return q**-2 * Bm1 * W0 - W0 * Bm1 + (q**-2 - 1) * sum(B((0, ell)) * B((0, n - ell - 2)) for ell in range(n - 1)) raise ValueError("not an index of a PBW basis element") @cached_method @@ -538,50 +539,40 @@ def product_on_basis(self, lhs, rhs): # relation (ii) i = kl[1] - 1 j = -kr[1] - denom = (q**2 - q**-2) * (q + q**-1)**2 - terms = A[1,-j]*A[1,i+1] + self.sum(A[0,ell]*A[2,i+j+1-ell] - A[0,i+j+1-ell]*A[2,ell] for ell in range(min(i,j)+1)) / denom + denom = (q**2 - q**-2) * (q + q**-1) ** 2 + terms = A[1, -j] * A[1, i + 1] + self.sum(A[0, ell] * A[2, i + j + 1 - ell] - A[0, i + j + 1 - ell] * A[2, ell] for ell in range(min(i, j) + 1)) / denom elif kl[0] == 2 and kr[0] == 0: # relation (iii) i = kl[1] - 1 j = kr[1] - 1 - coeff = (q**2 - q**-2)**3 - terms = (A[0,j+1]*A[2,i+1] - coeff * A[1,-i]*A[1,-j] + coeff * A[1,i+1]*A[1,j+1] - + coeff * sum(A[1,-ell]*A[1,i+j+2-ell] - A[1,ell-1-i-j]*A[1,ell+1] for ell in range(min(i,j)+1)) - - coeff * sum(A[1,1-ell]*A[1,i+j+1-ell] - A[1,ell-i-j]*A[1,ell] for ell in range(1, min(i,j)+1))) + coeff = (q**2 - q**-2) ** 3 + terms = A[0, j + 1] * A[2, i + 1] - coeff * A[1, -i] * A[1, -j] + coeff * A[1, i + 1] * A[1, j + 1] + coeff * sum(A[1, -ell] * A[1, i + j + 2 - ell] - A[1, ell - 1 - i - j] * A[1, ell + 1] for ell in range(min(i, j) + 1)) - coeff * sum(A[1, 1 - ell] * A[1, i + j + 1 - ell] - A[1, ell - i - j] * A[1, ell] for ell in range(1, min(i, j) + 1)) elif kl[0] == 1 and kr[0] == 0: if kl[1] > 0: # relation (vi) i = kl[1] - 1 j = kr[1] - 1 coeff = q * (q - ~q) - terms = (A[0,j+1]*A[1,i+1] + coeff * sum(A[0,ell]*A[1,ell-i-j] for ell in range(min(i,j)+1)) - + coeff * sum(A[0,i+j+1-ell]*A[1,ell+1] - A[0,ell]*A[1,i+j+2-ell] for ell in range(min(i,j)+1)) - - coeff * sum(A[0,i+j+1-ell]*A[1,1-ell] for ell in range(1, min(i,j)+1))) + terms = A[0, j + 1] * A[1, i + 1] + coeff * sum(A[0, ell] * A[1, ell - i - j] for ell in range(min(i, j) + 1)) + coeff * sum(A[0, i + j + 1 - ell] * A[1, ell + 1] - A[0, ell] * A[1, i + j + 2 - ell] for ell in range(min(i, j) + 1)) - coeff * sum(A[0, i + j + 1 - ell] * A[1, 1 - ell] for ell in range(1, min(i, j) + 1)) else: # relation (v) i = -kl[1] j = kr[1] - 1 coeff = ~q * (q - ~q) - terms = (A[0,j+1]*A[1,-i] - coeff * sum(A[0,ell]*A[1,i+j+1-ell] for ell in range(min(i,j)+1)) - + coeff * sum(A[0,ell]*A[1,ell-1-i-j] - A[0,i+j+1-ell]*A[1,-ell] for ell in range(min(i,j)+1)) - + coeff * sum(A[0,i+j+1-ell]*A[1,ell] for ell in range(1, min(i,j)+1))) + terms = A[0, j + 1] * A[1, -i] - coeff * sum(A[0, ell] * A[1, i + j + 1 - ell] for ell in range(min(i, j) + 1)) + coeff * sum(A[0, ell] * A[1, ell - 1 - i - j] - A[0, i + j + 1 - ell] * A[1, -ell] for ell in range(min(i, j) + 1)) + coeff * sum(A[0, i + j + 1 - ell] * A[1, ell] for ell in range(1, min(i, j) + 1)) elif kl[0] == 2 and kr[0] == 1: if kr[1] > 0: # relation (vi) i = kl[1] - 1 j = kr[1] - 1 coeff = q * (q - ~q) - terms = (A[1,j+1]*A[2,i+1] + coeff * sum(A[1,ell-i-j]*A[2,ell] for ell in range(min(i,j)+1)) - + coeff * sum(A[1,ell+1]*A[2,i+j+1-ell] - A[1,i+j+2-ell]*A[2,ell] for ell in range(min(i,j)+1)) - - coeff * sum(A[1,1-ell]*A[2,i+j+1-ell] for ell in range(1, min(i,j)+1))) + terms = A[1, j + 1] * A[2, i + 1] + coeff * sum(A[1, ell - i - j] * A[2, ell] for ell in range(min(i, j) + 1)) + coeff * sum(A[1, ell + 1] * A[2, i + j + 1 - ell] - A[1, i + j + 2 - ell] * A[2, ell] for ell in range(min(i, j) + 1)) - coeff * sum(A[1, 1 - ell] * A[2, i + j + 1 - ell] for ell in range(1, min(i, j) + 1)) else: # relation (vii) i = kl[1] - 1 j = -kr[1] coeff = ~q * (q - ~q) - terms = (A[1,-j]*A[2,i+1] - coeff * sum(A[1,i+j+1-ell]*A[2,ell] for ell in range(min(i,j)+1)) - + coeff * sum(A[1,ell-1-i-j]*A[2,ell] - A[1,-ell]*A[2,i+j+1-ell] for ell in range(min(i,j)+1)) - + coeff * sum(A[1,ell]*A[2,i+j+1-ell] for ell in range(1, min(i,j)+1))) + terms = A[1, -j] * A[2, i + 1] - coeff * sum(A[1, i + j + 1 - ell] * A[2, ell] for ell in range(min(i, j) + 1)) + coeff * sum(A[1, ell - 1 - i - j] * A[2, ell] - A[1, -ell] * A[2, i + j + 1 - ell] for ell in range(min(i, j) + 1)) + coeff * sum(A[1, ell] * A[2, i + j + 1 - ell] for ell in range(1, min(i, j) + 1)) return self.monomial(lhs // B[kl]) * terms * self.monomial(rhs // B[kr]) @@ -606,15 +597,17 @@ def _sigma_on_basis(self, x): (W[-2], W[3]), (G[1], Gt[1]), (G[2], Gt[2]), (Gt[1], G[1]), (Gt[2], G[2])] """ + def tw(m): if m[0] == 0: return (2, m[1]) if m[0] == 1: - return (1, -m[1]+1) + return (1, -m[1] + 1) if m[0] == 2: return (0, m[1]) + A = self.algebra_generators() - return self.prod(A[tw(m)]**e for m,e in x._sorted_items()) + return self.prod(A[tw(m)] ** e for m, e in x._sorted_items()) def _dagger_on_basis(self, x): r""" @@ -639,6 +632,7 @@ def _dagger_on_basis(self, x): (W[-2], W[-2]), (G[1], Gt[1]), (G[2], Gt[2]), (Gt[1], G[1]), (Gt[2], G[2])] """ + def tw(m): if m[0] == 0: return (2, m[1]) @@ -646,8 +640,9 @@ def tw(m): return (1, m[1]) if m[0] == 2: return (0, m[1]) + A = self.algebra_generators() - return self.prod(A[tw(m)]**e for m,e in reversed(x._sorted_items())) + return self.prod(A[tw(m)] ** e for m, e in reversed(x._sorted_items())) @lazy_attribute def sigma(self): diff --git a/src/sage/algebras/quantum_groups/all.py b/src/sage/algebras/quantum_groups/all.py index 33ff442e7b4..dce631c2d32 100644 --- a/src/sage/algebras/quantum_groups/all.py +++ b/src/sage/algebras/quantum_groups/all.py @@ -3,6 +3,7 @@ """ from sage.misc.lazy_import import lazy_import + lazy_import('sage.algebras.quantum_groups.fock_space', 'FockSpace') lazy_import('sage.algebras.quantum_groups.quantum_group_gap', 'QuantumGroup') del lazy_import diff --git a/src/sage/algebras/quantum_groups/fock_space.py b/src/sage/algebras/quantum_groups/fock_space.py index bf3ce8db53d..b61760b43c1 100644 --- a/src/sage/algebras/quantum_groups/fock_space.py +++ b/src/sage/algebras/quantum_groups/fock_space.py @@ -29,8 +29,7 @@ from sage.rings.fraction_field import FractionField from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.combinat.free_module import CombinatorialFreeModule -from sage.combinat.partition import (_Partitions, Partitions, - RegularPartitions_truncated) +from sage.combinat.partition import _Partitions, Partitions, RegularPartitions_truncated from sage.combinat.partition_tuple import PartitionTuples from sage.algebras.quantum_groups.q_numbers import q_factorial @@ -38,6 +37,7 @@ ############################# # Fock space options + class FockSpaceOptions(GlobalOptions): r""" Set and display the global options for elements of the Fock @@ -80,19 +80,17 @@ class FockSpaceOptions(GlobalOptions): sage: Partitions.options._reset() sage: FockSpace.options._reset() """ + NAME = 'FockSpace' module = 'sage.algebras.quantum_groups.fock_space' - display = {'default': "ket", - 'description': 'Specifies how terms of the natural basis of Fock space should be printed', - 'values': {'ket': 'displayed as a ket in bra-ket notation', - 'list': 'displayed as a list'}, - 'case_sensitive': False} + display = {'default': "ket", 'description': 'Specifies how terms of the natural basis of Fock space should be printed', 'values': {'ket': 'displayed as a ket in bra-ket notation', 'list': 'displayed as a list'}, 'case_sensitive': False} ############################################################################### # Fock space + class FockSpace(Parent, UniqueRepresentation): r""" The (fermionic) Fock space of `U_q(\widehat{\mathfrak{sl}}_n)` with @@ -308,6 +306,7 @@ class FockSpace(Parent, UniqueRepresentation): - [Fayers2010]_ - [GW1999]_ """ + @staticmethod def __classcall_private__(cls, n, multicharge=[0], q=None, base_ring=None, truncated=None): r""" @@ -369,8 +368,7 @@ def _repr_(self): Fock space of rank 4 of multicharge (2, 0, 1) over Fraction Field of Univariate Polynomial Ring in q over Integer Ring """ - return "Fock space of rank {} of multicharge {} over {}".format( - self._n, self._multicharge, self.base_ring()) + return "Fock space of rank {} of multicharge {} over {}".format(self._n, self._multicharge, self.base_ring()) def _latex_(self): r""" @@ -386,8 +384,8 @@ def _latex_(self): \mathcal{F}_{q}^{4}\left(2, 0, 1\right) """ from sage.misc.latex import latex - return "\\mathcal{{F}}_{{{q}}}^{{{n}}}{mc}".format(q=latex(self._q), n=self._n, - mc=latex(self._multicharge)) + + return "\\mathcal{{F}}_{{{q}}}^{{{n}}}{mc}".format(q=latex(self._q), n=self._n, mc=latex(self._multicharge)) options = FockSpaceOptions @@ -464,6 +462,7 @@ def inject_shorthands(self, verbose=True): in the lower global crystal basis """ from sage.misc.misc import inject_variable + for shorthand in ['A', 'F', 'G']: realization = getattr(self, shorthand)() if verbose: @@ -556,6 +555,7 @@ class F(CombinatorialFreeModule, BindableClass): sage: x.e(2) |3, 1> + q*|2, 1, 1> """ + def __init__(self, F): """ Initialize ``self``. @@ -570,20 +570,12 @@ def __init__(self, F): if len(F._multicharge) == 1: # For partitions self._above = lambda x, y: x[0] < y[0] else: # For partition tuples - self._above = lambda x,y: x[0] < y[0] or (x[0] == y[0] and x[1] < y[1]) - self._addable = lambda la,i: [x for x in la.outside_corners() - if la.content(*x, multicharge=F._multicharge) == i] - self._removable = lambda la,i: [x for x in la.corners() - if la.content(*x, multicharge=F._multicharge) == i] + self._above = lambda x, y: x[0] < y[0] or (x[0] == y[0] and x[1] < y[1]) + self._addable = lambda la, i: [x for x in la.outside_corners() if la.content(*x, multicharge=F._multicharge) == i] + self._removable = lambda la, i: [x for x in la.corners() if la.content(*x, multicharge=F._multicharge) == i] indices = PartitionTuples(level=len(F._multicharge)) - CombinatorialFreeModule.__init__(self, F.base_ring(), indices, - prefix='F', - latex_prefix='', - bracket=False, - latex_bracket=['\\left\\lvert', '\\right\\rangle'], - sorting_reverse=True, - category=FockSpaceBases(F)) + CombinatorialFreeModule.__init__(self, F.base_ring(), indices, prefix='F', latex_prefix='', bracket=False, latex_bracket=['\\left\\lvert', '\\right\\rangle'], sorting_reverse=True, category=FockSpaceBases(F)) options = FockSpaceOptions @@ -608,7 +600,7 @@ def _repr_term(self, m): """ if self.options.display != 'ket': return CombinatorialFreeModule._repr_term(self, m) - return '|' + m._repr_list()[1:-1] + ">" # Strip the outer brackets of m + return '|' + m._repr_list()[1:-1] + ">" # Strip the outer brackets of m def _ascii_art_term(self, m): r""" @@ -630,13 +622,14 @@ def _ascii_art_term(self, m): if self.options.display != 'ket': return CombinatorialFreeModule._ascii_art_term(self, m) from sage.typeset.ascii_art import AsciiArt, ascii_art + a = ascii_art(m) h = a.height() - l = AsciiArt(['|']*h) - r = AsciiArt([' '*i + '\\' for i in range(h//2)], baseline=0) + l = AsciiArt(['|'] * h) + r = AsciiArt([' ' * i + '\\' for i in range(h // 2)], baseline=0) if h % 2: - r *= AsciiArt([' '*(h//2) + '>'], baseline=0) - r *= AsciiArt([' '*i + '/' for i in reversed(range(h//2))], baseline=0) + r *= AsciiArt([' ' * (h // 2) + '>'], baseline=0) + r *= AsciiArt([' ' * i + '/' for i in reversed(range(h // 2))], baseline=0) ret = l + a + r ret._baseline = h - 1 return ret @@ -663,13 +656,14 @@ def _unicode_art_term(self, m): if self.options.display != 'ket': return CombinatorialFreeModule._ascii_art_term(self, m) from sage.typeset.unicode_art import UnicodeArt, unicode_art + a = unicode_art(m) h = a.height() - l = UnicodeArt(['│']*h, baseline=0) - r = UnicodeArt([" "*i + '╲' for i in range(h//2)], baseline=0) + l = UnicodeArt(['│'] * h, baseline=0) + r = UnicodeArt([" " * i + '╲' for i in range(h // 2)], baseline=0) if h % 2: - r *= UnicodeArt([" "*(h//2) + '〉'], baseline=0) - r *= UnicodeArt([" "*i + '╱' for i in reversed(range(h//2))], baseline=0) + r *= UnicodeArt([" " * (h // 2) + '〉'], baseline=0) + r *= UnicodeArt([" " * i + '╱' for i in reversed(range(h // 2))], baseline=0) ret = l + a + r ret._baseline = h - 1 return ret @@ -693,37 +687,29 @@ def _test_representation(self, **options): q = F.q() n = F._n I = F._index_set - A = CartanMatrix(['A',n-1,1]) - P = RootSystem(['A',n-1,1]).weight_lattice() + A = CartanMatrix(['A', n - 1, 1]) + P = RootSystem(['A', n - 1, 1]).weight_lattice() al = P.simple_roots() ac = P.simple_coroots() zero = self.zero() for x in self.some_elements(): for i in I: for j in I: - tester.assertEqual(x.h_inverse(j).f(i).h(j), q**-al[i].scalar(ac[j]) * x.f(i)) - tester.assertEqual(x.h_inverse(j).e(i).h(j), q**al[i].scalar(ac[j]) * x.e(i)) + tester.assertEqual(x.h_inverse(j).f(i).h(j), q ** -al[i].scalar(ac[j]) * x.f(i)) + tester.assertEqual(x.h_inverse(j).e(i).h(j), q ** al[i].scalar(ac[j]) * x.e(i)) if i == j: - tester.assertEqual(x.f(i).e(i) - x.e(i).f(i), - (x.h(i) - x.h_inverse(i)) / (q - q**-1)) + tester.assertEqual(x.f(i).e(i) - x.e(i).f(i), (x.h(i) - x.h_inverse(i)) / (q - q**-1)) continue tester.assertEqual(x.f(j).e(i) - x.e(i).f(j), zero) - aij = A[i,j] - tester.assertEqual(zero, - sum((-1)**k - * q_binomial(1-aij, k, q) - * x.e(*([i]*(1-aij-k) + [j] + [i]*k)) - for k in range(1-aij+1))) - tester.assertEqual(zero, - sum((-1)**k - * q_binomial(1-aij, k, q) - * x.f(*([i]*(1-aij-k) + [j] + [i]*k)) - for k in range(1-aij+1))) + aij = A[i, j] + tester.assertEqual(zero, sum((-1) ** k * q_binomial(1 - aij, k, q) * x.e(*([i] * (1 - aij - k) + [j] + [i] * k)) for k in range(1 - aij + 1))) + tester.assertEqual(zero, sum((-1) ** k * q_binomial(1 - aij, k, q) * x.f(*([i] * (1 - aij - k) + [j] + [i] * k)) for k in range(1 - aij + 1))) class Element(CombinatorialFreeModule.Element): """ An element in the Fock space. """ + def _e(self, i): r""" Apply `e_i` to ``self``. @@ -745,11 +731,10 @@ def _e(self, i): P = self.parent() def N_left(la, x, i): - return (sum(1 for y in P._addable(la, i) if P._above(x, y)) - - sum(1 for y in P._removable(la, i) if P._above(x, y))) + return sum(1 for y in P._addable(la, i) if P._above(x, y)) - sum(1 for y in P._removable(la, i) if P._above(x, y)) + q = P.realization_of()._q - return P.sum_of_terms((la.remove_cell(*x), c * q**(-N_left(la, x, i))) - for la,c in self for x in P._removable(la, i)) + return P.sum_of_terms((la.remove_cell(*x), c * q ** (-N_left(la, x, i))) for la, c in self for x in P._removable(la, i)) def e(self, *data): r""" @@ -841,11 +826,10 @@ def _f(self, i): P = self.parent() def N_right(la, x, i): - return (sum(1 for y in P._addable(la, i) if P._above(y, x)) - - sum(1 for y in P._removable(la, i) if P._above(y, x))) + return sum(1 for y in P._addable(la, i) if P._above(y, x)) - sum(1 for y in P._removable(la, i) if P._above(y, x)) + q = P.realization_of()._q - return P.sum_of_terms((la.add_cell(*x), c * q**N_right(la, x, i)) - for la,c in self for x in P._addable(la, i)) + return P.sum_of_terms((la.add_cell(*x), c * q ** N_right(la, x, i)) for la, c in self for x in P._addable(la, i)) def f(self, *data): r""" @@ -942,7 +926,7 @@ def h(self, *data): if i not in I: raise ValueError("{} not in the index set".format(i)) for la in d: - d[la] *= q**(len(P._addable(la, i)) - len(P._removable(la, i))) + d[la] *= q ** (len(P._addable(la, i)) - len(P._removable(la, i))) return P._from_dict(d, coerce=False) def h_inverse(self, *data): @@ -978,7 +962,7 @@ def h_inverse(self, *data): if i not in I: raise ValueError("{} not in the index set".format(i)) for la in d: - d[la] *= q**-(len(P._addable(la, i)) - len(P._removable(la, i))) + d[la] *= q ** -(len(P._addable(la, i)) - len(P._removable(la, i))) return P._from_dict(d, coerce=False) def d(self): @@ -1008,8 +992,7 @@ def d(self): q = R._q d = self.monomial_coefficients(copy=True) for la in d: - d[la] *= q**-sum(1 for x in la.cells() - if la.content(*x, multicharge=R._multicharge) == 0) + d[la] *= q ** -sum(1 for x in la.cells() if la.content(*x, multicharge=R._multicharge) == 0) return P._from_dict(d, coerce=False) natural = F @@ -1061,6 +1044,7 @@ class A(CombinatorialFreeModule, BindableClass): + q^2*|[], [4]> + q^3*|[], [3, 1]> + q^3*|[], [2, 1, 1]> + q^4*|[], [1, 1, 1, 1]> """ + def __init__(self, F): r""" Initialize ``self``. @@ -1071,15 +1055,9 @@ def __init__(self, F): sage: TestSuite(A).run() """ self._basis_name = "approximation" - indices = PartitionTuples(level=len(F._multicharge), - regular=F._n) - CombinatorialFreeModule.__init__(self, F.base_ring(), indices, - prefix='A', bracket=False, - sorting_reverse=True, - category=FockSpaceBases(F)) - self.module_morphism(self._A_to_fock_basis, - triangular='upper', unitriangular=True, - codomain=F.natural()).register_as_coercion() + indices = PartitionTuples(level=len(F._multicharge), regular=F._n) + CombinatorialFreeModule.__init__(self, F.base_ring(), indices, prefix='A', bracket=False, sorting_reverse=True, category=FockSpaceBases(F)) + self.module_morphism(self._A_to_fock_basis, triangular='upper', unitriangular=True, codomain=F.natural()).register_as_coercion() options = FockSpaceOptions @@ -1118,21 +1096,19 @@ def _A_to_fock_basis(self, la): # Reduce down to the lower level Fock space and do the computation # and then lift back up to us by prepending empty partitions - if k == len(R._multicharge): # This means we get the empty partition + if k == len(R._multicharge): # This means we get the empty partition cur = fock.highest_weight_vector() else: F = FockSpace(R._n, R._multicharge[k:], R._q, R.base_ring()) Gp = F.G() if k + 1 == len(R._multicharge): cur = Gp._G_to_fock_basis(Gp._indices(la[k])) - cur = fock.sum_of_terms((fock._indices([[]]*k + [p]), c) - for p,c in cur) + cur = fock.sum_of_terms((fock._indices([[]] * k + [p]), c) for p, c in cur) else: cur = Gp._G_to_fock_basis(Gp._indices(la[k:])) - cur = fock.sum_of_terms((fock._indices([[]]*k + list(pt)), c) - for pt,c in cur) - la = la[k-1] - r = R._multicharge[k-1] + cur = fock.sum_of_terms((fock._indices([[]] * k + list(pt)), c) for pt, c in cur) + la = la[k - 1] + r = R._multicharge[k - 1] else: cur = fock.highest_weight_vector() r = R._multicharge[0] @@ -1141,14 +1117,14 @@ def _A_to_fock_basis(self, la): corners = la.corners() cells = set(la.cells()) q = R._q - k = R._n - 1 # This is sl_{k+1} + k = R._n - 1 # This is sl_{k+1} b = ZZ.zero() # While there is some cell left to count - while any(c[1]*k + c[0] >= b for c in corners): + while any(c[1] * k + c[0] >= b for c in corners): power = 0 - i = -b + r # This will be converted to a mod n number + i = -b + r # This will be converted to a mod n number for x in range(b // k + 1): - if (b-x*k, x) in cells: + if (b - x * k, x) in cells: power += 1 cur = cur.f(i) cur /= q_factorial(power, q) @@ -1290,6 +1266,7 @@ class G(CombinatorialFreeModule, BindableClass): + q^2*|[], [4]> + q^3*|[], [3, 1]> + q^3*|[], [2, 1, 1]> + q^4*|[], [1, 1, 1, 1]> """ + def __init__(self, F): r""" Initialize ``self``. @@ -1300,15 +1277,9 @@ def __init__(self, F): sage: TestSuite(G).run() """ self._basis_name = "lower global crystal" - indices = PartitionTuples(level=len(F._multicharge), - regular=F._n) - CombinatorialFreeModule.__init__(self, F.base_ring(), indices, - prefix='G', bracket=False, - sorting_reverse=True, - category=FockSpaceBases(F)) - self.module_morphism(self._G_to_fock_basis, - triangular='upper', unitriangular=True, - codomain=F.natural()).register_as_coercion() + indices = PartitionTuples(level=len(F._multicharge), regular=F._n) + CombinatorialFreeModule.__init__(self, F.base_ring(), indices, prefix='G', bracket=False, sorting_reverse=True, category=FockSpaceBases(F)) + self.module_morphism(self._G_to_fock_basis, triangular='upper', unitriangular=True, codomain=F.natural()).register_as_coercion() options = FockSpaceOptions @@ -1362,9 +1333,9 @@ def _G_to_fock_basis(self, la): Gp = F.G() if k + 1 == len(R._multicharge): cur = Gp._G_to_fock_basis(Gp._indices(la[k])) - return fock.sum_of_terms((fock._indices([[]]*k + [p]), c) for p,c in cur) + return fock.sum_of_terms((fock._indices([[]] * k + [p]), c) for p, c in cur) cur = Gp._G_to_fock_basis(Gp._indices(la[k:])) - return fock.sum_of_terms((fock._indices([[]]*k + list(pt)), c) for pt,c in cur) + return fock.sum_of_terms((fock._indices([[]] * k + list(pt)), c) for pt, c in cur) cur = R.A()._A_to_fock_basis(la) @@ -1373,9 +1344,9 @@ def domorder_insertion(data, elt): Add ``elt`` at the largest position of ``data`` such that it dominants all larger entries. """ - for i in range(len(data)-1, -1, -1): + for i in range(len(data) - 1, -1, -1): if not data[i].dominates(elt): - data.insert(i+1, elt) + data.insert(i + 1, elt) return data.insert(0, elt) @@ -1404,8 +1375,7 @@ def domorder_insertion(data, elt): k = d.degree() n = cur[mu].numerator() if k != 0 or n.constant_coefficient() != 0: - gamma = sum(n[i] * (q**(i-k) + q**(k-i)) - for i in range(min(n.degree(), k))) + gamma = sum(n[i] * (q ** (i - k) + q ** (k - i)) for i in range(min(n.degree(), k))) gamma += n[k] cur -= gamma * self._G_to_fock_basis(mu) @@ -1425,10 +1395,12 @@ def domorder_insertion(data, elt): ############################################################################### # Bases Category + class FockSpaceBases(Category_realization_of_parent): r""" The category of bases of a (truncated) Fock space. """ + def __init__(self, base): r""" Initialize the bases of a Fock space. @@ -1584,7 +1556,7 @@ def highest_weight_vector(self): level = len(self.realization_of()._multicharge) if level == 1: return self.monomial(self._indices([])) - return self.monomial(self._indices([[]]*level)) + return self.monomial(self._indices([[]] * level)) def __getitem__(self, i): r""" @@ -1643,6 +1615,7 @@ def __getitem__(self, i): return self.highest_weight_vector() return self.monomial(i) + ############################################################################### # Truncated Fock space @@ -1690,6 +1663,7 @@ class FockSpaceTruncated(FockSpace): - [GW1999]_ """ + @staticmethod def __classcall_private__(cls, n, k, q=None, base_ring=None): r""" @@ -1770,6 +1744,7 @@ class F(CombinatorialFreeModule, BindableClass): sage: u3.f(0,3,2,1,1) 0 """ + def __init__(self, F): r""" Initialize ``self``. @@ -1781,21 +1756,15 @@ def __init__(self, F): """ self._basis_name = "natural" # If the cell x is above the cell y - if len(F._multicharge) == 1: # For partitions - self._above = lambda x,y: x[0] < y[0] - else: # For partition tuples - self._above = lambda x,y: x[0] < y[0] or (x[0] == y[0] and x[1] < y[1]) - self._addable = lambda la,i: [x for x in la.outside_corners() - if la.content(*x, multicharge=F._multicharge) == i] - self._removable = lambda la,i: [x for x in la.corners() - if la.content(*x, multicharge=F._multicharge) == i] + if len(F._multicharge) == 1: # For partitions + self._above = lambda x, y: x[0] < y[0] + else: # For partition tuples + self._above = lambda x, y: x[0] < y[0] or (x[0] == y[0] and x[1] < y[1]) + self._addable = lambda la, i: [x for x in la.outside_corners() if la.content(*x, multicharge=F._multicharge) == i] + self._removable = lambda la, i: [x for x in la.corners() if la.content(*x, multicharge=F._multicharge) == i] indices = Partitions(max_length=F._k) - CombinatorialFreeModule.__init__(self, F.base_ring(), indices, - prefix='', bracket=['|', '>'], - latex_bracket=['\\lvert', '\\rangle'], - sorting_reverse=True, - category=FockSpaceBases(F)) + CombinatorialFreeModule.__init__(self, F.base_ring(), indices, prefix='', bracket=['|', '>'], latex_bracket=['\\lvert', '\\rangle'], sorting_reverse=True, category=FockSpaceBases(F)) options = FockSpaceOptions @@ -1811,12 +1780,13 @@ def _repr_term(self, m): sage: F.highest_weight_vector() |> """ - return '|' + repr(m)[1:-1] + ">" # Strip the outer brackets of m + return '|' + repr(m)[1:-1] + ">" # Strip the outer brackets of m class Element(FockSpace.natural.Element): r""" An element in the truncated Fock space. """ + def _f(self, i): r""" Apply the action of `f_i` on ``self``. @@ -1841,13 +1811,11 @@ def _f(self, i): P = self.parent() def N_right(la, x, i): - return (sum(1 for y in P._addable(la, i) if P._above(y, x)) - - sum(1 for y in P._removable(la, i) if P._above(y, x))) + return sum(1 for y in P._addable(la, i) if P._above(y, x)) - sum(1 for y in P._removable(la, i) if P._above(y, x)) + q = P.realization_of()._q k = P.realization_of()._k - return P.sum_of_terms([(la.add_cell(*x), c * q**N_right(la, x, i)) - for la,c in self for x in P._addable(la, i) - if x[0] < k]) + return P.sum_of_terms([(la.add_cell(*x), c * q ** N_right(la, x, i)) for la, c in self for x in P._addable(la, i) if x[0] < k]) natural = F @@ -1890,6 +1858,7 @@ class A(CombinatorialFreeModule, BindableClass): sage: G._G_to_fock_basis(Partition([12,9]), 'LLT') |12, 9> + q*|12, 4, 4, 1> + q*|8, 8, 5> + q^2*|8, 8, 4, 1> """ + def __init__(self, F, algorithm='GW'): r""" Initialize ``self``. @@ -1907,13 +1876,8 @@ def __init__(self, F, algorithm='GW'): raise ValueError("invalid algorithm") self._alg = algorithm indices = RegularPartitions_truncated(F._n, F._k) - CombinatorialFreeModule.__init__(self, F.base_ring(), indices, - prefix='A', bracket=False, - sorting_reverse=True, - category=FockSpaceBases(F)) - self.module_morphism(self._A_to_fock_basis, - triangular='upper', unitriangular=True, - codomain=F.natural()).register_as_coercion() + CombinatorialFreeModule.__init__(self, F.base_ring(), indices, prefix='A', bracket=False, sorting_reverse=True, category=FockSpaceBases(F)) + self.module_morphism(self._A_to_fock_basis, triangular='upper', unitriangular=True, codomain=F.natural()).register_as_coercion() options = FockSpaceOptions @@ -1943,14 +1907,14 @@ def _LLT(self, la): corners = la.corners() cells = set(la.cells()) q = R._q - k = R._n - 1 # This is sl_{k+1} + k = R._n - 1 # This is sl_{k+1} r = R._multicharge[0] b = ZZ.zero() - while any(c[1]*k + c[0] >= b for c in corners): # While there is some cell left to count + while any(c[1] * k + c[0] >= b for c in corners): # While there is some cell left to count power = 0 - i = -b + r # This will be converted to a mod n number + i = -b + r # This will be converted to a mod n number for x in range(b // k + 1): - if (b-x*k, x) in cells: + if (b - x * k, x) in cells: power += 1 cur = cur.f(i) cur /= q_factorial(power, q) @@ -1980,7 +1944,7 @@ def _skew_tableau(self, cur, nu, d): q = R._q for i in reversed(range(len(d))): for dummy in range(d[i]): - for j in range(i+1): + for j in range(i + 1): col = nu[j] if j < len(nu) else 0 res = nu.content(j, col, multicharge=R._multicharge) if res != last: @@ -2040,47 +2004,46 @@ def _A_to_fock_basis(self, la): # For critical partitions n = self.realization_of()._n - if len(la) == k-1 and all((la[i] - la[i+1] + 1) % n == 0 for i in range(k-2)) \ - and (la[-1] + 1) % n == 0: + if len(la) == k - 1 and all((la[i] - la[i + 1] + 1) % n == 0 for i in range(k - 2)) and (la[-1] + 1) % n == 0: return fock.monomial(la) # For interior partitions - shifted = [la[i] - (n - 1)*(k - 1 - i) for i in range(len(la))] + shifted = [la[i] - (n - 1) * (k - 1 - i) for i in range(len(la))] if len(la) == k - 1 and shifted in _Partitions: # Construct the d's and the critical partition - d = [(la[i] - la[i+1] + 1) % n for i in range(len(la)-1)] + d = [(la[i] - la[i + 1] + 1) % n for i in range(len(la) - 1)] d.append((la[-1] + 1) % n) crit = list(la) - for i,d_i in enumerate(d): - for j in range(i+1): + for i, d_i in enumerate(d): + for j in range(i + 1): crit[j] -= d_i nu = fock._indices(crit) return self._skew_tableau(fock.monomial(nu), nu, d) # For non-interior partitions # Construct the d's and the partition ``a`` - a = list(la) + [0]*(k - 1 - len(la)) # Add 0s to get the correct length - a = [a[i] + (k - 1 - i) for i in range(k-1)] # Shift the diagram - #shifted = list(a) # Make a copy of the shifted partition in case we need it later - d = [(a[i] - a[i+1]) % n for i in range(k-2)] + a = list(la) + [0] * (k - 1 - len(la)) # Add 0s to get the correct length + a = [a[i] + (k - 1 - i) for i in range(k - 1)] # Shift the diagram + # shifted = list(a) # Make a copy of the shifted partition in case we need it later + d = [(a[i] - a[i + 1]) % n for i in range(k - 2)] d.append(a[-1] % n) - for i,d_i in enumerate(d): - for j in range(i+1): + for i, d_i in enumerate(d): + for j in range(i + 1): a[j] -= d_i - if sum(a) == 0: # a is contained in the fundamental box + if sum(a) == 0: # a is contained in the fundamental box return self._LLT(la) - p = list(a) # Make a copy that we can change - for i in range(k-2): - if a[i] - a[i+1] == 0: + p = list(a) # Make a copy that we can change + for i in range(k - 2): + if a[i] - a[i + 1] == 0: d[i] -= 1 - for j in range(i+1): + for j in range(i + 1): p[j] += 1 if a[-1] == 0: d[-1] -= 1 - for j in range(k-1): + for j in range(k - 1): p[j] += 1 - p = [p[i] - (k - 1 - i) for i in range(k-1)] + p = [p[i] - (k - 1 - i) for i in range(k - 1)] I = self._indices nu = I(p) @@ -2095,11 +2058,11 @@ def _A_to_fock_basis(self, la): if la == nu: j = -1 - for i in range(k-2): - if p[i] - p[i+1] == 0: + for i in range(k - 2): + if p[i] - p[i + 1] == 0: j = -2 break - if p[i] > n and p[i] - p[i+1] > n: + if p[i] > n and p[i] - p[i + 1] > n: j = i if j != -2 and p[-1] > n: j = k - 1 @@ -2107,8 +2070,8 @@ def _A_to_fock_basis(self, la): return self._LLT(la) G = self.realization_of().G() - nu = I([p[i] - n if i <= j else p[i] for i in range(k-1)]) - d = [0]*j + [n] + nu = I([p[i] - n if i <= j else p[i] for i in range(k - 1)]) + d = [0] * j + [n] return self._skew_tableau(G._G_to_fock_basis(nu), nu, d) G = self.realization_of().G() @@ -2163,6 +2126,7 @@ class G(CombinatorialFreeModule, BindableClass): sage: F(G[7]) |7> + q*|3, 3, 1> """ + def __init__(self, F): r""" Initialize ``self``. @@ -2176,13 +2140,8 @@ def __init__(self, F): """ self._basis_name = "lower global crystal" indices = RegularPartitions_truncated(F._n, F._k) - CombinatorialFreeModule.__init__(self, F.base_ring(), indices, - prefix='G', bracket=False, - sorting_reverse=True, - category=FockSpaceBases(F)) - self.module_morphism(self._G_to_fock_basis, - triangular='upper', unitriangular=True, - codomain=F.natural()).register_as_coercion() + CombinatorialFreeModule.__init__(self, F.base_ring(), indices, prefix='G', bracket=False, sorting_reverse=True, category=FockSpaceBases(F)) + self.module_morphism(self._G_to_fock_basis, triangular='upper', unitriangular=True, codomain=F.natural()).register_as_coercion() options = FockSpaceOptions @@ -2217,13 +2176,13 @@ def _G_to_fock_basis(self, la, algorithm='GW'): mu = _Partitions([p - x for p in la]) def add_cols(nu): - return _Partitions([v + x for v in list(nu) + [0]*(k - len(nu))]) - return fock.sum_of_terms((add_cols(nu), c) for nu,c in self._G_to_fock_basis(mu)) + return _Partitions([v + x for v in list(nu) + [0] * (k - len(nu))]) + + return fock.sum_of_terms((add_cols(nu), c) for nu, c in self._G_to_fock_basis(mu)) # For critical partitions n = self.realization_of()._n - if len(la) == k-1 and all((la[i] - la[i+1] + 1) % n == 0 for i in range(k-2)) \ - and (la[-1] + 1) % n == 0: + if len(la) == k - 1 and all((la[i] - la[i + 1] + 1) % n == 0 for i in range(k - 2)) and (la[-1] + 1) % n == 0: return fock.monomial(la) # Perform the triangular reduction @@ -2238,18 +2197,17 @@ def add_cols(nu): k = d.degree() n = cur[mu].numerator() if k != 0 or n.constant_coefficient() != 0: - gamma = sum(n[i] * (q**(i-k) + q**(k-i)) - for i in range(min(n.degree(), k))) + gamma = sum(n[i] * (q ** (i - k) + q ** (k - i)) for i in range(min(n.degree(), k))) gamma += n[k] cur -= gamma * self._G_to_fock_basis(mu, algorithm) # Add any new support elements for x in cur.support(): - if x == mu or not mu.dominates(x): # Add only things (strictly) dominated by mu + if x == mu or not mu.dominates(x): # Add only things (strictly) dominated by mu continue for i in reversed(range(len(s))): if not s[i].dominates(x): - s.insert(i+1, x) + s.insert(i + 1, x) break return cur diff --git a/src/sage/algebras/quantum_groups/q_numbers.py b/src/sage/algebras/quantum_groups/q_numbers.py index cdde70cd4b8..8f3a370878a 100644 --- a/src/sage/algebras/quantum_groups/q_numbers.py +++ b/src/sage/algebras/quantum_groups/q_numbers.py @@ -75,7 +75,7 @@ def q_int(n, q=None): R = q.parent() if n == 0: return R.zero() - return R.sum(q**(n - 2 * i - 1) for i in range(n)) + return R.sum(q ** (n - 2 * i - 1) for i in range(n)) def q_factorial(n, q=None): @@ -127,7 +127,7 @@ def q_factorial(n, q=None): ValueError: argument (-2) must be a nonnegative integer """ if n in ZZ and n >= 0: - return prod(q_int(i, q) for i in range(1, n+1)) + return prod(q_int(i, q) for i in range(1, n + 1)) raise ValueError("argument ({}) must be a nonnegative integer".format(n)) diff --git a/src/sage/algebras/quantum_groups/quantum_group_gap.py b/src/sage/algebras/quantum_groups/quantum_group_gap.py index 7ed1b9383e4..ac1a46c65e7 100644 --- a/src/sage/algebras/quantum_groups/quantum_group_gap.py +++ b/src/sage/algebras/quantum_groups/quantum_group_gap.py @@ -54,6 +54,7 @@ class QuaGroupModuleElement(Element): """ Base class for elements created using QuaGroup. """ + def __init__(self, parent, libgap_elt): """ Initialize ``self``. @@ -89,9 +90,7 @@ def _repr_(self) -> str: # Do the largest index first so, e.g., F12 gets replaced as 12 # instead of as 1. for i, al in reversed(list(enumerate(self.parent()._pos_roots))): - short = '+'.join('%s*a%s' % (coeff, index) - if coeff != 1 else 'a%s' % index - for index, coeff in al) + short = '+'.join('%s*a%s' % (coeff, index) if coeff != 1 else 'a%s' % index for index, coeff in al) ret = ret.replace('F%s' % (i + 1), 'F[%s]' % short) ret = ret.replace('E%s' % (i + 1), 'E[%s]' % short) return ret @@ -113,6 +112,7 @@ def _latex_(self) -> str: F_{\alpha_{3}}, F_{\alpha_{4}}\right] """ from sage.misc.latex import latex + ret = repr(self._libgap) # Do the largest index first so, e.g., F12 gets replaced as 12 # instead of as 1. @@ -129,7 +129,7 @@ def _latex_(self) -> str: ret = ret.replace('*', ' ') c = re.compile(r"q\^-?[0-9]*") for m in reversed(list(c.finditer(ret))): - ret = ret[:m.start() + 2] + '{' + ret[m.start() + 2:m.end()] + '}' + ret[m.end():] + ret = ret[: m.start() + 2] + '{' + ret[m.start() + 2 : m.end()] + '}' + ret[m.end() :] return ret def __reduce__(self): @@ -342,6 +342,7 @@ class QuantumGroup(UniqueRepresentation, Parent): - :wikipedia:`Quantum_group` """ + @staticmethod def __classcall_private__(cls, cartan_type, q=None): """ @@ -374,10 +375,7 @@ def __init__(self, cartan_type, q): R = libgap.eval('RootSystem("%s",%s)' % (cartan_type.type(), cartan_type.rank())) Q = self._cartan_type.root_system().root_lattice() I = cartan_type.index_set() - self._pos_roots = [Q.sum_of_terms([(ii, root[i]) - for i, ii in enumerate(I) - if root[i] != 0]) - for root in R.PositiveRootsInConvexOrder().sage()] + self._pos_roots = [Q.sum_of_terms([(ii, root[i]) for i, ii in enumerate(I) if root[i] != 0]) for root in R.PositiveRootsInConvexOrder().sage()] if q is None: self._libgap = R.QuantizedUEA() self._libgap_q = libgap.eval('_q') @@ -416,6 +414,7 @@ def _latex_(self) -> str: U_{\zeta_{3}}(G_2) """ from sage.misc.latex import latex + return "U_{%s}(%s)" % (latex(self._q), latex(self._cartan_type)) def _libgap_(self): @@ -509,8 +508,7 @@ def gens(self) -> tuple: K2, (-q + q^-1)*[ K2 ; 1 ] + K2, E[a1], E[a1+a2], E[a2]) """ - return tuple([self.element_class(self, gen) - for gen in self._libgap.GeneratorsOfAlgebra()]) + return tuple([self.element_class(self, gen) for gen in self._libgap.GeneratorsOfAlgebra()]) def E(self): r""" @@ -630,8 +628,7 @@ def algebra_generators(self): ret['K%s' % ii] = self.K()[ii] ret['Ki%s' % ii] = self.K_inverse()[ii] ret['E%s' % ii] = self.E()[al] - keys = (['F%s' % i for i in I] + ['K%s' % i for i in I] - + ['Ki%s' % i for i in I] + ['E%s' % i for i in I]) + keys = ['F%s' % i for i in I] + ['K%s' % i for i in I] + ['Ki%s' % i for i in I] + ['E%s' % i for i in I] return Family(keys, ret.__getitem__) def _an_element_(self): @@ -647,7 +644,7 @@ def _an_element_(self): """ i = self._cartan_type.index_set()[0] al = self._cartan_type.root_system().root_lattice().simple_root(i) - return self.E()[al] + self.K()[i] + self.K_inverse()[i]**2 + self.q()*self.F()[al] + return self.E()[al] + self.K()[i] + self.K_inverse()[i] ** 2 + self.q() * self.F()[al] def some_elements(self): """ @@ -661,8 +658,7 @@ def some_elements(self): + K1 + (-q^-1 + q^-3)*K1[ K1 ; 1 ], K1, F[a1], E[a1]] """ - return ([self.an_element()] + list(self.K()) - + list(self.F_simple()) + list(self.E_simple())) + return [self.an_element()] + list(self.K()) + list(self.F_simple()) + list(self.E_simple()) def q(self): """ @@ -767,7 +763,7 @@ def coproduct(self, elt, n=1): + -q + q^-1*(F[a2][ K2 ; 1 ]K2) + -q + q^-1*(F[a2]K2[ K2 ; 1 ]) + 1*(F[a2]K2K2)] """ - D = self._libgap.ComultiplicationMap(n+1) + D = self._libgap.ComultiplicationMap(n + 1) # TODO: This is not the correct parent. Need to create it. return self.element_class(self, libgap.Image(D, elt._libgap)) @@ -1067,10 +1063,12 @@ def _ft(self, i): ##################################################################### # Morphisms + class QuantumGroupMorphism(Morphism): r""" A morphism whose domain is a quantum group. """ + def __init__(self, parent, im_gens, check=True): r""" Initialize ``self``. @@ -1159,9 +1157,7 @@ def __richcmp__(self, other, op): False """ if op == op_EQ: - return (type(self) is type(other) - and self.domain() is other.domain() - and self._im_gens == other._im_gens) + return type(self) is type(other) and self.domain() is other.domain() and self._im_gens == other._im_gens if op == op_NE: return not (self == other) return NotImplemented @@ -1195,14 +1191,14 @@ def _repr_defn(self): (-q + q^-1)*[ K1 ; 1 ] + K1 |--> K1 E[a1] |--> F[a1] """ - return '\n'.join('%s |--> %s' % (gen, self._im_gens[i]) - for i, gen in enumerate(self.domain().algebra_generators())) + return '\n'.join('%s |--> %s' % (gen, self._im_gens[i]) for i, gen in enumerate(self.domain().algebra_generators())) class QuantumGroupHomset(HomsetWithBase): r""" The homset whose domain is a quantum group. """ + def __call__(self, im_gens, check=True): r""" Construct an element of ``self``. @@ -1271,10 +1267,12 @@ def projection_lower_half(Q): ##################################################################### # Representations + class QuaGroupRepresentationElement(QuaGroupModuleElement): """ Element of a quantum group representation. """ + def __reduce__(self): """ Used in pickling. @@ -1322,7 +1320,7 @@ def _acted_upon_(self, scalar, self_on_left=False): if scalar.parent() is self.parent()._Q: if self_on_left: # Only act: scalar * v return None - return self.__class__(self.parent(), scalar._libgap ** self._libgap) + return self.__class__(self.parent(), scalar._libgap**self._libgap) except AttributeError: pass return QuaGroupModuleElement._acted_upon_(self, scalar, self_on_left) @@ -1448,6 +1446,7 @@ class CrystalGraphVertex(SageObject): r""" Helper class used as the vertices of a crystal graph. """ + def __init__(self, V, s): """ Initialize ``self``. @@ -1526,6 +1525,7 @@ def _latex_(self): """ # Essentially same as QuaGroupModuleElement._latex_ from sage.misc.latex import latex + ret = self.s[1:-1] # Strip leading '<' and trailing '>' for i, al in enumerate(self.V._pos_roots): ret = ret.replace('F%s' % (i + 1), 'F_{%s}' % latex(al)) @@ -1541,7 +1541,7 @@ def _latex_(self): ret = ret.replace('', ' \\otimes ') c = re.compile(r"q\^-?[0-9]*") for m in reversed(list(c.finditer(ret))): - ret = ret[:m.start()+2]+'{'+ret[m.start()+2:m.end()]+'}'+ret[m.end():] + ret = ret[: m.start() + 2] + '{' + ret[m.start() + 2 : m.end()] + '}' + ret[m.end() :] return '\\langle {} \\rangle'.format(ret) @@ -1549,6 +1549,7 @@ class QuantumGroupModule(Parent, UniqueRepresentation): r""" Abstract base class for quantum group representations. """ + def __init__(self, Q, category): r""" Initialize ``self``. @@ -1582,6 +1583,7 @@ def _latex_(self): \end{tikzpicture} """ from sage.misc.latex import latex + return latex(self.crystal_graph()) def _libgap_(self): @@ -1667,6 +1669,7 @@ def R_matrix(self): R = self._libgap.RMatrix() F = self._Q.base_ring() from sage.matrix.constructor import matrix + M = matrix(F, [[F(str(elt)) for elt in row] for row in R]) M.set_immutable() return M @@ -1688,14 +1691,12 @@ def crystal_graph(self): """ G = self._libgap.CrystalGraph() vertices = [CrystalGraphVertex(self, repr(p)) for p in G['points']] - edges = [[vertices[e[0][0]-1], vertices[e[0][1]-1], e[1]] - for e in G['edges'].sage()] + edges = [[vertices[e[0][0] - 1], vertices[e[0][1] - 1], e[1]] for e in G['edges'].sage()] G = DiGraph([vertices, edges], format='vertices_and_edges') from sage.graphs.dot2tex_utils import have_dot2tex + if have_dot2tex(): - G.set_latex_options(format='dot2tex', - edge_labels=True, - color_by_label=self._cartan_type._index_set_coloring) + G.set_latex_options(format='dot2tex', edge_labels=True, color_by_label=self._cartan_type._index_set_coloring) return G @cached_method @@ -1717,6 +1718,7 @@ class HighestWeightModule(QuantumGroupModule): """ A highest weight module of a quantum group. """ + @staticmethod def __classcall_private__(cls, Q, weight): """ @@ -1778,6 +1780,7 @@ def _latex_(self) -> str: V(\Lambda_{1} + 2 \Lambda_{2}) """ from sage.misc.latex import latex + return "V({})".format(latex(self._weight)) @cached_method @@ -1860,6 +1863,7 @@ def _latex_(self): V(\Lambda_{1}) \otimes V(\Lambda_{1}) """ from sage.misc.latex import latex + return " \\otimes ".join(latex(M) for M in self._modules) @lazy_attribute @@ -1894,9 +1898,7 @@ def highest_weight_vectors(self): sage: T.highest_weight_vectors() [1*(1*v01*v0), -q^-1*(1*v0F[a1]*v0) + 1*(F[a1]*v01*v0)] """ - return [self.element_class(self, v) - for vecs in self._highest_weights_and_vectors[1] - for v in vecs] + return [self.element_class(self, v) for vecs in self._highest_weights_and_vectors[1] for v in vecs] some_elements = highest_weight_vectors @@ -1928,9 +1930,7 @@ def highest_weight_decomposition(self): [Highest weight submodule with weight 2*Lambda[1] generated by 1*(1*v01*v0), Highest weight submodule with weight Lambda[2] generated by -q^-1*(1*v0F[a1]*v0) + 1*(F[a1]*v01*v0)] """ - return [HighestWeightSubmodule(self, self.element_class(self, v), tuple(wt.sage())) - for wt, vecs in zip(*self._highest_weights_and_vectors) - for v in vecs] + return [HighestWeightSubmodule(self, self.element_class(self, v), tuple(wt.sage())) for wt, vecs in zip(*self._highest_weights_and_vectors) for v in vecs] def tensor_factors(self): r""" @@ -1967,7 +1967,7 @@ def __init__(self, ambient, gen, weight): # We do not use the generic ambient category since submodules of tensor # products are considered to be tensor products. # This should be reverted after this has changed. - #cat = ambient.category() + # cat = ambient.category() cat = Modules(ambient.base_ring()).FiniteDimensional().WithBasis() QuantumGroupModule.__init__(self, ambient._Q, cat.Subobjects()) @@ -2066,8 +2066,7 @@ def lift(self): + 1*(F[a1]*v0F[a1+a2]*v0) + q^-1*(F[a1+a2]*v01*v0) + q^-1*(F[a1+a2]*v0F[a1]*v0) + 1*(F[a1+a2]*v0F[a1+a2]*v0) """ - return self.module_morphism(self._ambient_basis_map.__getitem__, - codomain=self._ambient, unitriangular='lower') + return self.module_morphism(self._ambient_basis_map.__getitem__, codomain=self._ambient, unitriangular='lower') def retract(self, elt): """ @@ -2138,18 +2137,14 @@ def crystal_graph(self, use_ambient=True): return QuantumGroupModule.crystal_graph(self) # Mostly a copy; there is likely a better way with a helper function B = self.basis() - d = {repr(B[k]._libgap): '<{!r}>'.format(self._ambient_basis_map[k]) - for k in self._ambient_basis_map} - vertices = [CrystalGraphVertex(self, d[repr(p)[1:-1]]) - for p in G['points']] - edges = [[vertices[e[0][0]-1], vertices[e[0][1]-1], e[1]] - for e in G['edges'].sage()] + d = {repr(B[k]._libgap): '<{!r}>'.format(self._ambient_basis_map[k]) for k in self._ambient_basis_map} + vertices = [CrystalGraphVertex(self, d[repr(p)[1:-1]]) for p in G['points']] + edges = [[vertices[e[0][0] - 1], vertices[e[0][1] - 1], e[1]] for e in G['edges'].sage()] G = DiGraph([vertices, edges], format='vertices_and_edges') from sage.graphs.dot2tex_utils import have_dot2tex + if have_dot2tex(): - G.set_latex_options(format='dot2tex', - edge_labels=True, - color_by_label=self._cartan_type._index_set_coloring) + G.set_latex_options(format='dot2tex', edge_labels=True, color_by_label=self._cartan_type._index_set_coloring) return G Element = QuaGroupRepresentationElement @@ -2160,6 +2155,7 @@ class LowerHalfQuantumGroup(Parent, UniqueRepresentation): """ The lower half of the quantum group. """ + @staticmethod def __classcall_private__(cls, Q): """ @@ -2173,6 +2169,7 @@ def __classcall_private__(cls, Q): True """ from sage.combinat.root_system.cartan_type import CartanType_abstract + if isinstance(Q, CartanType_abstract): Q = QuantumGroup(Q) return super().__classcall__(cls, Q) @@ -2220,6 +2217,7 @@ def _latex_(self): U^-_{q}(A_{2}) """ from sage.misc.latex import latex + return "U^-_{%s}(%s)" % (latex(self._Q._q), latex(self._cartan_type)) def _element_constructor_(self, elt): @@ -2356,7 +2354,7 @@ def basis(self): sage: basis[1,0,4] F[a1]*F[a2]^(4) """ - I = cartesian_product([NonNegativeIntegers()]*len(self._pos_roots)) + I = cartesian_product([NonNegativeIntegers()] * len(self._pos_roots)) return Family(I, self._construct_monomial, name='monomial') def _construct_canonical_basis_elts(self, k): @@ -2389,7 +2387,7 @@ def canonical_basis_elements(self): sage: C[1,2] [F[a1]*F[a2]^(2), (q^2)*F[a1]*F[a2]^(2) + F[a1+a2]*F[a2]] """ - I = cartesian_product([NonNegativeIntegers()]*len(self._cartan_type.index_set())) + I = cartesian_product([NonNegativeIntegers()] * len(self._cartan_type.index_set())) return Family(I, self._construct_canonical_basis_elts, name='Canonical basis') def lift(self, elt): @@ -2427,6 +2425,7 @@ class Element(QuaGroupModuleElement): """ An element of the lower half of the quantum group. """ + def _acted_upon_(self, scalar, self_on_left=False): r""" Return the action of ``scalar`` on ``self``. @@ -2502,12 +2501,12 @@ def monomial_coefficients(self, copy=True): num_pos_roots = len(self.parent()._pos_roots) R = self.parent().base_ring() d = {} - for i in range(len(ext_rep)//2): + for i in range(len(ext_rep) // 2): exp = [0] * num_pos_roots - mon = ext_rep[2*i].sage() - for j in range(len(mon)//2): - exp[mon[2*j]-1] = mon[2*j+1] - d[tuple(exp)] = R(str(ext_rep[2*i+1])) + mon = ext_rep[2 * i].sage() + for j in range(len(mon) // 2): + exp[mon[2 * j] - 1] = mon[2 * j + 1] + d[tuple(exp)] = R(str(ext_rep[2 * i + 1])) return d def bar(self): diff --git a/src/sage/algebras/quantum_groups/representations.py b/src/sage/algebras/quantum_groups/representations.py index 0d90d7bcc00..67e47b6c9c2 100644 --- a/src/sage/algebras/quantum_groups/representations.py +++ b/src/sage/algebras/quantum_groups/representations.py @@ -6,7 +6,7 @@ - Travis Scrimshaw (2018): initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2018 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.combinat.free_module import CombinatorialFreeModule from sage.misc.lazy_attribute import lazy_attribute @@ -36,6 +36,7 @@ class QuantumGroupRepresentation(CombinatorialFreeModule): - ``q`` -- (default: the generator of ``R``) the parameter `q` of the quantum group """ + @staticmethod def __classcall__(cls, R, C, q=None): """ @@ -123,7 +124,7 @@ def K_on_basis(self, i, b, power=1): """ WLR = self.basis().keys().weight_lattice_realization() alc = WLR.simple_coroots() - return self.term(b, self._q**(b.weight().scalar(alc[i]) * self._d[i] * power)) + return self.term(b, self._q ** (b.weight().scalar(alc[i]) * self._d[i] * power)) class CyclicRepresentation(QuantumGroupRepresentation): @@ -139,6 +140,7 @@ class CyclicRepresentation(QuantumGroupRepresentation): and :class:`~sage.algebras.quantum_groups.representation.MinusculeRepresentation`. """ + def _repr_(self): """ Return a string representation of ``self``. @@ -181,6 +183,7 @@ def _latex_(self): except (TypeError, AttributeError): mg = self.basis().keys().module_generators[0] from sage.misc.latex import latex + return r"V\left( {} \right)".format(latex(mg.weight())) @cached_method @@ -299,6 +302,7 @@ class AdjointRepresentation(CyclicRepresentation): - [OS2018]_ """ + def __init__(self, R, C, q): """ Initialize ``self``. @@ -326,10 +330,11 @@ def __init__(self, R, C, q): CyclicRepresentation.__init__(self, R, C, q) ct = C.cartan_type() if ct.is_finite() and ct.type() == 'A': + def test_zero(x): wt = x.weight() - return all(wt.scalar(ac) == 0 - for ac in self._WLR_zero.parent().simple_coroots()) + return all(wt.scalar(ac) == 0 for ac in self._WLR_zero.parent().simple_coroots()) + self._check_zero_wt = test_zero else: self._check_zero_wt = lambda x: x.weight() == self._WLR_zero @@ -400,15 +405,11 @@ def e_on_basis(self, i, b): x = b.e(i) if x is None: return self.zero() - I = {j: pos for pos,j in enumerate(C.index_set())} + I = {j: pos for pos, j in enumerate(C.index_set())} if self._check_zero_wt(x): A = C.cartan_type().cartan_matrix() - return self.monomial(x) + sum(self.term(self._zero_elts[j], - q_int(-A[I[i],I[j]], self._q**self._d[i]) - / q_int(2, self._q**self._d[j])) - for j in C.index_set() - if A[I[i],I[j]] < 0 and j in self._zero_elts) - return self.term(x, q_int(x.phi(i), self._q**self._d[i])) + return self.monomial(x) + sum(self.term(self._zero_elts[j], q_int(-A[I[i], I[j]], self._q ** self._d[i]) / q_int(2, self._q ** self._d[j])) for j in C.index_set() if A[I[i], I[j]] < 0 and j in self._zero_elts) + return self.term(x, q_int(x.phi(i), self._q ** self._d[i])) def f_on_basis(self, i, b): r""" @@ -452,16 +453,11 @@ def f_on_basis(self, i, b): x = b.f(i) if x is None: return self.zero() - I = {j: pos for pos,j in enumerate(C.index_set())} + I = {j: pos for pos, j in enumerate(C.index_set())} if self._check_zero_wt(x): A = C.cartan_type().cartan_matrix() - return self.monomial(x) + sum(self.term(self._zero_elts[j], - q_int(-A[I[i],I[j]], - self._q**self._d[i]) - / q_int(2, self._q**self._d[j])) - for j in C.index_set() - if A[I[i],I[j]] < 0 and j in self._zero_elts) - return self.term(x, q_int(x.epsilon(i), self._q**self._d[i])) + return self.monomial(x) + sum(self.term(self._zero_elts[j], q_int(-A[I[i], I[j]], self._q ** self._d[i]) / q_int(2, self._q ** self._d[j])) for j in C.index_set() if A[I[i], I[j]] < 0 and j in self._zero_elts) + return self.term(x, q_int(x.epsilon(i), self._q ** self._d[i])) class MinusculeRepresentation(CyclicRepresentation): @@ -526,6 +522,7 @@ class MinusculeRepresentation(CyclicRepresentation): - [OS2018]_ """ + def e_on_basis(self, i, b): r""" Return the action of `e_i` on the basis element indexed by ``b``. diff --git a/src/sage/algebras/quantum_matrix_coordinate_algebra.py b/src/sage/algebras/quantum_matrix_coordinate_algebra.py index 616107ed48e..aaa89d71ff0 100644 --- a/src/sage/algebras/quantum_matrix_coordinate_algebra.py +++ b/src/sage/algebras/quantum_matrix_coordinate_algebra.py @@ -33,6 +33,7 @@ class QuantumMatrixCoordinateAlgebra_abstract(CombinatorialFreeModule): Abstract base class for quantum coordinate algebras of a set of matrices. """ + @staticmethod def __classcall__(cls, q=None, bar=None, R=None, **kwds): """ @@ -58,8 +59,7 @@ def __classcall__(cls, q=None, bar=None, R=None, **kwds): q = R(q) if q is None: q = LaurentPolynomialRing(R, 'q').gen() - return super().__classcall__(cls, - q=q, bar=bar, R=q.parent(), **kwds) + return super().__classcall__(cls, q=q, bar=bar, R=q.parent(), **kwds) def __init__(self, gp_indices, n, q, bar, R, category, indices_key=None): """ @@ -73,8 +73,10 @@ def __init__(self, gp_indices, n, q, bar, R, category, indices_key=None): self._n = n self._q = q if bar is None: + def bar(x): return x.subs(q=~self._q) + self._bar = bar if indices_key is None: indices = IndexedFreeAbelianMonoid(gp_indices) @@ -105,8 +107,8 @@ def _repr_term(self, m) -> str: def exp(e): return '^{}'.format(e) if e > 1 else '' - return '*'.join(('x[{},{}]'.format(*k) if k != 'c' else 'c') + exp(e) - for k, e in m._sorted_items()) + + return '*'.join(('x[{},{}]'.format(*k) if k != 'c' else 'c') + exp(e) for k, e in m._sorted_items()) def _latex_term(self, m) -> str: r""" @@ -131,8 +133,8 @@ def _latex_term(self, m) -> str: def exp(e): return '^{{{}}}'.format(e) if e > 1 else '' - return ' '.join(('x_{{{},{}}}'.format(*k) if k != 'c' else 'c') + exp(e) - for k, e in m._sorted_items()) + + return ' '.join(('x_{{{},{}}}'.format(*k) if k != 'c' else 'c') + exp(e) for k, e in m._sorted_items()) def n(self): """ @@ -236,9 +238,9 @@ def quantum_determinant(self): if hasattr(self, '_m') and self._m != self._n: raise ValueError("undefined for non-square quantum matrices") from sage.combinat.permutation import Permutations + q = self._q - return self._from_dict({self._indices({(i, p(i)): 1 for i in range(1, self._n + 1)}): - (-q) ** p.length() for p in Permutations(self._n)}) + return self._from_dict({self._indices({(i, p(i)): 1 for i in range(1, self._n + 1)}): (-q) ** p.length() for p in Permutations(self._n)}) def product_on_basis(self, a, b): """ @@ -272,7 +274,7 @@ def product_on_basis(self, a, b): G = self._indices.monoid_generators() one = self.base_ring().one() q = self._q - qi = q ** -1 + qi = q**-1 monomial = b coeff = one for pos in range(len(al) - 1, -1, -1): @@ -305,11 +307,7 @@ def product_on_basis(self, a, b): index = ml.index((bx, be)) a_key = self._indices(dict(al[:pos])) bp_key = self._indices(dict(ml[:index])) * G[ax] ** (ae - 1) - return (self.monomial(a_key) * - self.monomial(bp_key) * - ret * - self.term(self._indices(dict(ml[index + 1:])), - coeff)) + return self.monomial(a_key) * self.monomial(bp_key) * ret * self.term(self._indices(dict(ml[index + 1 :])), coeff) # Otherwise ax[1] > bx[1], but for this case they commute: # x_{st} x_{ij} = x_{ij} x_{st} if s > i, t < j @@ -356,6 +354,7 @@ class Element(CombinatorialFreeModule.Element): """ An element of a quantum matrix coordinate algebra. """ + def bar(self): r""" Return the image of ``self`` under the bar involution. @@ -480,6 +479,7 @@ class QuantumMatrixCoordinateAlgebra(QuantumMatrixCoordinateAlgebra_abstract): - [FRT1990]_ - [ZZ2005]_ """ + @staticmethod def __classcall_private__(cls, m, n=None, q=None, bar=None, R=None): r""" @@ -500,9 +500,7 @@ def __classcall_private__(cls, m, n=None, q=None, bar=None, R=None): """ if n is None: n = m - return super().__classcall__(cls, m=m, n=n, - q=q, bar=bar, - R=R) + return super().__classcall__(cls, m=m, n=n, q=q, bar=bar, R=R) def __init__(self, m, n, q, bar, R): """ @@ -535,7 +533,7 @@ def __init__(self, m, n, q, bar, R): # Set the names mb = len(str(m)) nb = len(str(n)) - base = 'x{{:0>{}}}{{:0>{}}}'.format(mb,nb) + base = 'x{{:0>{}}}{{:0>{}}}'.format(mb, nb) names = [base.format(*k) for k in gp_indices] self._assign_names(names) @@ -594,8 +592,7 @@ def algebra_generators(self) -> Family: sage: O.algebra_generators() Finite family {(1, 1): x[1,1], (1, 2): x[1,2], (2, 1): x[2,1], (2, 2): x[2,2]} """ - l = [(i, j) for i in range(1, self._m + 1) - for j in range(1, self._n + 1)] + l = [(i, j) for i in range(1, self._m + 1) for j in range(1, self._n + 1)] G = self._indices.monoid_generators() one = self.base_ring().one() return Family(l, lambda x: self.element_class(self, {G[x]: one})) @@ -625,9 +622,7 @@ def coproduct_on_basis(self, x): raise ValueError("undefined for non-square quantum matrices") T = self.tensor_square() I = self._indices.monoid_generators() - return T.prod(T.sum_of_monomials((I[t[0], k], I[k, t[1]]) - for k in range(1, self._n + 1)) ** e - for t, e in x._sorted_items()) + return T.prod(T.sum_of_monomials((I[t[0], k], I[k, t[1]]) for k in range(1, self._n + 1)) ** e for t, e in x._sorted_items()) class QuantumGL(QuantumMatrixCoordinateAlgebra_abstract): @@ -720,6 +715,7 @@ class QuantumGL(QuantumMatrixCoordinateAlgebra_abstract): - [DD1991]_ - [Kar1993]_ """ + @staticmethod def __classcall_private__(cls, n, q=None, bar=None, R=None): """ @@ -754,9 +750,7 @@ def __init__(self, n, q, bar, R): gp_indices = [(i, j) for i in range(1, n + 1) for j in range(1, n + 1)] gp_indices.append('c') cat = HopfAlgebras(R.category()).WithBasis() - QuantumMatrixCoordinateAlgebra_abstract.__init__(self, gp_indices, n, q, - bar, R, cat, - indices_key=_generator_key) + QuantumMatrixCoordinateAlgebra_abstract.__init__(self, gp_indices, n, q, bar, R, cat, indices_key=_generator_key) names = ['x{}{}'.format(*k) for k in gp_indices[:-1]] names.append('c') self._assign_names(names) @@ -797,8 +791,7 @@ def algebra_generators(self): sage: O.algebra_generators() Finite family {(1, 1): x[1,1], (1, 2): x[1,2], (2, 1): x[2,1], (2, 2): x[2,2], 'c': c} """ - l = [(i, j) for i in range(1, self._n + 1) - for j in range(1, self._n + 1)] + l = [(i, j) for i in range(1, self._n + 1) for j in range(1, self._n + 1)] l.append('c') G = self._indices.monoid_generators() one = self.base_ring().one() @@ -895,12 +888,12 @@ def product_on_basis(self, a, b): del L._monomial_coefficients[mon] temp = self.term(c ** (c_exp - 1), coeff) * self._qdet_remaining * rem if L != self.zero(): - temp -= self.term(c ** c_exp, coeff) * L + temp -= self.term(c**c_exp, coeff) * L for k in temp._monomial_coefficients: temp._monomial_coefficients[k] //= co other += temp except ValueError: # We cannot cancel, so we just add on the correct power of c - ret[c ** c_exp * mon] = coeff + ret[c**c_exp * mon] = coeff return self._from_dict(ret, remove_zeros=False) + other @cached_method @@ -916,16 +909,15 @@ def _antipode_on_generator(self, i, j): [-(q^-1)*c*x[1,2], c*x[1,1]]] """ from sage.combinat.permutation import Permutations + q = self._q I = list(range(1, j)) + list(range(j + 1, self._n + 1)) def lift(p): return [val if val < i else val + 1 for val in p] + gens = self.algebra_generators() - t_tilde = self.sum((-q) ** p.length() * gens['c'] * - self.prod(gens[I[k], val] - for k, val in enumerate(lift(p))) - for p in Permutations(self._n - 1)) + t_tilde = self.sum((-q) ** p.length() * gens['c'] * self.prod(gens[I[k], val] for k, val in enumerate(lift(p))) for p in Permutations(self._n - 1)) return (-q) ** (i - j) * t_tilde def antipode_on_basis(self, x): @@ -968,10 +960,7 @@ def coproduct_on_basis(self, x): """ T = self.tensor_square() I = self._indices.monoid_generators() - return T.prod(T.sum_of_monomials((I[t[0], k], I[k, t[1]]) - for k in range(1, self._n + 1)) ** e - if t != 'c' else T.monomial((I['c'], I['c'])) ** e - for t, e in x._sorted_items()) + return T.prod(T.sum_of_monomials((I[t[0], k], I[k, t[1]]) for k in range(1, self._n + 1)) ** e if t != 'c' else T.monomial((I['c'], I['c'])) ** e for t, e in x._sorted_items()) def _generator_key(t): diff --git a/src/sage/algebras/quantum_oscillator.py b/src/sage/algebras/quantum_oscillator.py index 910c27ba98a..23caaf736cf 100644 --- a/src/sage/algebras/quantum_oscillator.py +++ b/src/sage/algebras/quantum_oscillator.py @@ -6,7 +6,7 @@ - Travis Scrimshaw (2023-12): initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2023 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.cachefunc import cached_method from sage.misc.misc_c import prod @@ -121,6 +121,7 @@ class QuantumOscillatorAlgebra(CombinatorialFreeModule): - [Kuniba2022]_ Section 3.2 """ + @staticmethod def __classcall_private__(cls, q=None, R=None): r""" @@ -170,8 +171,7 @@ def _repr_(self) -> str: Quantum oscillator algebra with q=q over Fraction Field of Univariate Polynomial Ring in q over Integer Ring """ - return "Quantum oscillator algebra with q={} over {}".format( - self._q, self.base_ring()) + return "Quantum oscillator algebra with q={} over {}".format(self._q, self.base_ring()) def _latex_(self) -> str: r""" @@ -211,10 +211,7 @@ def algebra_generators(self): sage: O.algebra_generators() Finite family {'am': a-, 'ap': a+, 'k': k, 'ki': k^-1} """ - d = {'ap': self.monomial((ZZ.one(), ZZ.zero())), - 'am': self.monomial((-ZZ.one(), ZZ.zero())), - 'k': self.monomial((ZZ.zero(), ZZ.one())), - 'ki': self.monomial((ZZ.zero(), -ZZ.one()))} + d = {'ap': self.monomial((ZZ.one(), ZZ.zero())), 'am': self.monomial((-ZZ.one(), ZZ.zero())), 'k': self.monomial((ZZ.zero(), ZZ.one())), 'ki': self.monomial((ZZ.zero(), -ZZ.one()))} return Family(d) @cached_method @@ -255,9 +252,7 @@ def some_elements(self) -> tuple: a-^4*k^-3, 1 + 3*k + 2*a+ + a+*k) """ ap, am, k, ki = self.gens() - return (ap, am, k, ki, self.one(), - ap**3, am**4, k**2, ki**5, ap*k, am**4*ki**3, - self.an_element()) + return (ap, am, k, ki, self.one(), ap**3, am**4, k**2, ki**5, ap * k, am**4 * ki**3, self.an_element()) def fock_space_representation(self): r""" @@ -432,11 +427,11 @@ def product_on_basis(self, ml, mr): return self.element_class(self, {(al + ar, kl + kr): coeff}) # now al and ar have different signs if al < 0: # a^- * a^+ case - kp = self._k_poly.prod(1 - q**(2*(ar-i)) * k**2 for i in range(min(-al,ar))) + kp = self._k_poly.prod(1 - q ** (2 * (ar - i)) * k**2 for i in range(min(-al, ar))) else: # a^+ * a^- case - kp = self._k_poly.prod(1 - q**(2*(ar+i)) * k**2 for i in range(1,min(al,-ar)+1)) + kp = self._k_poly.prod(1 - q ** (2 * (ar + i)) * k**2 for i in range(1, min(al, -ar) + 1)) a = al + ar - return self.element_class(self, {(a, kl+kr+i): c * coeff for i, c in enumerate(kp) if c}) + return self.element_class(self, {(a, kl + kr + i): c * coeff for i, c in enumerate(kp) if c}) class Element(CombinatorialFreeModule.Element): def __invert__(self): @@ -471,7 +466,7 @@ def __invert__(self): if len(self) != 1 or self.leading_support()[0] != 0: raise NotImplementedError("only implemented for monomials in k") - ((a, k), coeff), = list(self._monomial_coefficients.items()) + (((a, k), coeff),) = list(self._monomial_coefficients.items()) O = self.parent() return O.element_class(O, {(a, -k): coeff.inverse_of_unit()}) @@ -481,6 +476,7 @@ class FockSpaceRepresentation(CombinatorialFreeModule): The unique Fock space representation of the :class:`~sage.algebras.quantum_oscillator.QuantumOscillatorAlgebra`. """ + def __init__(self, oscillator_algebra): r""" Initialize ``self``. @@ -493,8 +489,7 @@ def __init__(self, oscillator_algebra): """ self._O = oscillator_algebra ind = NonNegativeIntegers() - CombinatorialFreeModule.__init__(self, oscillator_algebra.base_ring(), ind, prefix='', bracket=['|', '>'], - latex_bracket=[r'\lvert', r'\rangle']) + CombinatorialFreeModule.__init__(self, oscillator_algebra.base_ring(), ind, prefix='', bracket=['|', '>'], latex_bracket=[r'\lvert', r'\rangle']) def _test_representation(self, **options): r""" @@ -511,12 +506,13 @@ def _test_representation(self, **options): S = self._O.some_elements() num_trials = 0 from itertools import product + for a, b in product(S, repeat=2): for elt in tester.some_elements(): num_trials += 1 if num_trials > tester._max_runs: return - tester.assertEqual((a*b)*elt, a*(b*elt)) + tester.assertEqual((a * b) * elt, a * (b * elt)) def _repr_(self) -> str: r""" @@ -613,9 +609,9 @@ def _acted_upon_(self, scalar, self_on_left=True): for fm, fc in self: if fm < -a: # the result will be 0 continue - c = q ** (fm*k) + c = q ** (fm * k) if a < 0: - c *= prod(1 - q**(2*(fm-i)) for i in range(-a)) + c *= prod(1 - q ** (2 * (fm - i)) for i in range(-a)) if c: - ret.append((fm+a, oc * fc * c)) + ret.append((fm + a, oc * fc * c)) return P.sum_of_terms(ret) diff --git a/src/sage/algebras/quatalg/quaternion_algebra.py b/src/sage/algebras/quatalg/quaternion_algebra.py index 03e4d42213a..d27d54db299 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra.py +++ b/src/sage/algebras/quatalg/quaternion_algebra.py @@ -322,6 +322,7 @@ class QuaternionAlgebraFactory(UniqueFactory): sage: set(ram[0]) == set([P,Q]) and ram[1] == emb_arch True """ + def create_key(self, arg0, arg1=None, arg2=None, names='i,j,k'): r""" Create a key that uniquely determines a quaternion algebra. @@ -379,7 +380,7 @@ def create_key(self, arg0, arg1=None, arg2=None, names='i,j,k'): if isinstance(K, RationalField): # Construct the quaternion algebra via ramification over the rationals - if len(arg2) > 1 or (len(arg2) == 1 and is_odd(len(primes) + 2*arg2[0])): + if len(arg2) > 1 or (len(arg2) == 1 and is_odd(len(primes) + 2 * arg2[0])): raise ValueError("quaternion algebra over the rationals must have an even number of ramified places") D = ZZ.ideal_monoid().prod(primes).gen() a, b = hilbert_conductor_inverse(D) @@ -412,10 +413,10 @@ def create_key(self, arg0, arg1=None, arg2=None, names='i,j,k'): # Transfer the primes to PARI and permute the local invariants fin_places_pari = [I.pari_prime() for I in primes] - inv_arch_pari = [arg2[i-1] for i in perm] + inv_arch_pari = [arg2[i - 1] for i in perm] # Compute the correct quaternion algebra over L in PARI - A = L.__pari__().alginit([2, [fin_places_pari, [QQ((1,2))] * len(fin_places_pari)], inv_arch_pari], flag=0) + A = L.__pari__().alginit([2, [fin_places_pari, [QQ((1, 2))] * len(fin_places_pari)], inv_arch_pari], flag=0) # Obtain representation of A in terms of invariants in L a_L = L(A.algsplittingfield().disc()[1]) @@ -717,7 +718,7 @@ def order(self): sage: Q.order() 625 """ - return self.base_ring().order()**4 + return self.base_ring().order() ** 4 def random_element(self, *args, **kwds): r""" @@ -808,6 +809,7 @@ class QuaternionAlgebra_ab(QuaternionAlgebra_abstract): sage: QuaternionAlgebra(QQ, -7, -21) # indirect doctest Quaternion Algebra (-7, -21) with base ring Rational Field """ + def __init__(self, base_ring, a, b, names='i,j,k') -> None: r""" Create the quaternion algebra with `i^2 = a`, `j^2 = b`, and @@ -852,8 +854,7 @@ def __init__(self, base_ring, a, b, names='i,j,k') -> None: self._b = b if isinstance(base_ring, RationalField) and a.denominator() == 1 == b.denominator(): self.Element = QuaternionAlgebraElement_rational_field - elif (isinstance(base_ring, NumberField) and base_ring.degree() > 2 and base_ring.is_absolute() and - a.denominator() == 1 == b.denominator() and base_ring.defining_polynomial().is_monic()): + elif isinstance(base_ring, NumberField) and base_ring.degree() > 2 and base_ring.is_absolute() and a.denominator() == 1 == b.denominator() and base_ring.defining_polynomial().is_monic(): # This QuaternionAlgebraElement_number_field class is not # designed to work with elements of a quadratic field. To # do that, the main thing would be to implement @@ -979,8 +980,7 @@ def maximal_order(self, take_shortcuts=True, order_basis=None): True """ if self.base_ring() != QQ: - raise NotImplementedError("maximal order only implemented for " - "rational quaternion algebras") + raise NotImplementedError("maximal order only implemented for " "rational quaternion algebras") d_A = self.discriminant() @@ -989,26 +989,24 @@ def maximal_order(self, take_shortcuts=True, order_basis=None): # (every quaternion algebra of prime discriminant has a representation # of such a form though) a, b = self.invariants() - if (not order_basis and take_shortcuts and d_A.is_prime() - and a in ZZ and b in ZZ): + if not order_basis and take_shortcuts and d_A.is_prime() and a in ZZ and b in ZZ: a = ZZ(a) b = ZZ(b) i, j, k = self.gens() # if necessary, try to swap invariants to match Pizer's paper - if (a != -1 and b == -1) or (b == -2) \ - or (a != -1 and a != -2 and (-a) % 8 != 1): + if (a != -1 and b == -1) or (b == -2) or (a != -1 and a != -2 and (-a) % 8 != 1): a, b = b, a i, j = j, i k = i * j basis = [] if (a, b) == (-1, -1): - basis = [(1+i+j+k)/2, i, j, k] + basis = [(1 + i + j + k) / 2, i, j, k] elif a == -1 and (-b).is_prime() and ((-b) % 4 == 3): - basis = [(1+j)/2, (i+k)/2, j, k] + basis = [(1 + j) / 2, (i + k) / 2, j, k] elif a == -2 and (-b).is_prime() and ((-b) % 8 == 5): - basis = [(1+j+k)/2, (i+2*j+k)/4, j, k] + basis = [(1 + j + k) / 2, (i + 2 * j + k) / 4, j, k] elif (-a).is_prime() and (-b).is_prime(): q = -b p = -a @@ -1017,7 +1015,7 @@ def maximal_order(self, take_shortcuts=True, order_basis=None): a = 0 while (a * a * p + 1) % q: a += 1 - basis = [(1+j)/2, (i+k)/2, -(j+a*k)/q, k] + basis = [(1 + j) / 2, (i + k) / 2, -(j + a * k) / q, k] if basis: return self.quaternion_order(basis) @@ -1031,8 +1029,7 @@ def maximal_order(self, take_shortcuts=True, order_basis=None): R = self.quaternion_order(order_basis) d_R = R.discriminant() except (TypeError, ValueError): - raise ValueError('order_basis is not a basis of an order of the' - ' given quaternion algebra') + raise ValueError('order_basis is not a basis of an order of the' ' given quaternion algebra') # Since Voight's algorithm only works for a starting basis having 1 as # its first vector, we derive such a basis from the given order basis @@ -1051,69 +1048,66 @@ def maximal_order(self, take_shortcuts=True, order_basis=None): # Ensure the basis lies in R by clearing denominators # (this may make the order smaller at q != p) # Also saturate the basis (divide out p as far as possible) - V = self.base_ring()**4 + V = self.base_ring() ** 4 A = matrix(self.base_ring(), 4, 4, [list(g) for g in e]) e_n = [] - x_rows = A.solve_left(matrix([V(vec.coefficient_tuple()) - for vec, val in f]), - check=False).rows() + x_rows = A.solve_left(matrix([V(vec.coefficient_tuple()) for vec, val in f]), check=False).rows() denoms = [x.denominator() for x in x_rows] for i in range(4): vec = f[i][0] val = f[i][1] - v = (val/2).floor() - e_n.append(denoms[i] / p**(v) * vec) + v = (val / 2).floor() + e_n.append(denoms[i] / p ** (v) * vec) # for e_n to become p-saturated we still need to sort by # ascending valuation of the quadratic form - lst = sorted(zip(e_n, [f[m][1].mod(2) for m in range(4)]), - key=itemgetter(1)) + lst = sorted(zip(e_n, [f[m][1].mod(2) for m in range(4)]), key=itemgetter(1)) e_n = list(next(zip(*lst))) # Final step: Enlarge the basis at p if p != 2: # ensure that v_p(e_n[1]**2) = 0 by swapping basis elements - if ZZ(e_n[1]**2).valuation(p) != 0: - if ZZ(e_n[2]**2).valuation(p) == 0: + if ZZ(e_n[1] ** 2).valuation(p) != 0: + if ZZ(e_n[2] ** 2).valuation(p) == 0: e_n[1], e_n[2] = e_n[2], e_n[1] else: e_n[1], e_n[3] = e_n[3], e_n[1] - a = ZZ(e_n[1]**2) - b = ZZ(e_n[2]**2) + a = ZZ(e_n[1] ** 2) + b = ZZ(e_n[2] ** 2) - if b.valuation(p) > 0: # if v_p(b) = 0, then already p-maximal + if b.valuation(p) > 0: # if v_p(b) = 0, then already p-maximal F = ZZ.quo(p) if F(a).is_square(): x = F(a).sqrt().lift() if (x**2 - a).mod(p**2) == 0: # make sure v_p(x**2 - a) = 1 x = x + p - g = 1/p*(x - e_n[1])*e_n[2] + g = 1 / p * (x - e_n[1]) * e_n[2] e_n[2] = g - e_n[3] = e_n[1]*g + e_n[3] = e_n[1] * g - else: # p == 2 + else: # p == 2 t = e_n[1].reduced_trace() a = -e_n[1].reduced_norm() - b = ZZ(e_n[2]**2) + b = ZZ(e_n[2] ** 2) if t.valuation(p) == 0: if b.valuation(p) > 0: x = a - if (x**2 - t*x + a).mod(p**2) == 0: # make sure v_p(...) = 1 + if (x**2 - t * x + a).mod(p**2) == 0: # make sure v_p(...) = 1 x = x + p - g = 1/p*(x - e_n[1])*e_n[2] + g = 1 / p * (x - e_n[1]) * e_n[2] e_n[2] = g - e_n[3] = e_n[1]*g + e_n[3] = e_n[1] * g - else: # t.valuation(p) > 0 + else: # t.valuation(p) > 0 y, z, w = maxord_solve_aux_eq(a, b, p) - g = 1/p*(1 + y*e_n[1] + z*e_n[2] + w*e_n[1]*e_n[2]) - h = (z*b)*e_n[1] - (y*a)*e_n[2] + g = 1 / p * (1 + y * e_n[1] + z * e_n[2] + w * e_n[1] * e_n[2]) + h = (z * b) * e_n[1] - (y * a) * e_n[2] e_n[1:4] = [g, h, g * h] - if (1 - a*y**2 - b*z**2 + a*b*w**2).valuation(2) > 2: + if (1 - a * y**2 - b * z**2 + a * b * w**2).valuation(2) > 2: e_n = basis_for_quaternion_lattice(list(e) + e_n[1:]) # e_n now contains elements that locally at p give a bigger order, @@ -1186,15 +1180,15 @@ def order_with_level(self, level): for p, r in fact: a = int(-p) // 2 - for v in GF(p)**4: + for v in GF(p) ** 4: x = sum([int(v[i] + a) * B[i] for i in range(4)]) - D = x.reduced_trace()**2 - 4 * x.reduced_norm() + D = x.reduced_trace() ** 2 - 4 * x.reduced_norm() # x = O.random_element((-p/2).floor(), (p/2).ceil()) if kronecker_symbol(D, p) == 1: break X = polygen(GF(p), 'x') a = ZZ((X**2 - ZZ(x.reduced_trace()) * X + ZZ(x.reduced_norm())).roots()[0][0]) - I = O._left_ideal_basis([p**r, (x - a)**r]) + I = O._left_ideal_basis([p**r, (x - a) ** r]) O = O._right_order_from_ideal_basis(I) # right_order returns the RightOrder of I inside O, so we # do not need to do another intersection @@ -1387,8 +1381,7 @@ def is_totally_definite(self) -> bool: # of just the number of them), we avoid a call of the `is_totally_real()`- # method by directly comparing the embedding list's length to the degree E = F.embeddings(AA) - return len(E) == F.degree() and all(F.hilbert_symbol(self._a, self._b, e) == -1 - for e in E) + return len(E) == F.degree() and all(F.hilbert_symbol(self._a, self._b, e) == -1 for e in E) @cached_method def ramified_places(self, inf=True): @@ -1497,10 +1490,7 @@ def ramified_places(self, inf=True): # For efficiency (and to not convert QQ into a number field manually), # we handle the case F = QQ first if isinstance(F, RationalField): - ram_fin = sorted([p for p in set([2]).union( - prime_divisors(a.numerator()), prime_divisors(a.denominator()), - prime_divisors(b.numerator()), prime_divisors(b.denominator())) - if hilbert_symbol(a, b, p) == -1]) + ram_fin = sorted([p for p in set([2]).union(prime_divisors(a.numerator()), prime_divisors(a.denominator()), prime_divisors(b.numerator()), prime_divisors(b.denominator())) if hilbert_symbol(a, b, p) == -1]) if not inf: return ram_fin @@ -1518,9 +1508,7 @@ def ramified_places(self, inf=True): raise ValueError("base field must be rational numbers or a number field") # Over the number field F, first compute the finite ramified places - ram_fin = [p for p in set(F.primes_above(2)).union(F.primes_above(a), - F.primes_above(b)) - if F.hilbert_symbol(a, b, p) == -1] + ram_fin = [p for p in set(F.primes_above(2)).union(F.primes_above(a), F.primes_above(b)) if F.hilbert_symbol(a, b, p) == -1] if not inf: return ram_fin @@ -1864,7 +1852,7 @@ def modp_splitting_data(self, p): for b in F: if not b: continue - c = j2 + i2inv * b*b + c = j2 + i2inv * b * b if c.is_square(): a = -c.sqrt() break @@ -1872,8 +1860,8 @@ def modp_splitting_data(self, p): if a is None: # do a fallback search, maybe needed in char 3 sometimes. for J in M: - K = I*J - if J*J == j2 and K == -J*I: + K = I * J + if J * J == j2 and K == -J * I: return I, J, K J = M([a, b, (j2 - a * a) / b, -a]) @@ -1907,7 +1895,8 @@ def modp_splitting_map(self, p): def phi(q): v = [F(a) for a in q.coefficient_tuple()] - return v[0] + I*v[1] + J*v[2] + K*v[3] + return v[0] + I * v[1] + J * v[2] + K * v[3] + return phi @@ -1944,6 +1933,7 @@ class QuaternionOrder(Parent): sage: type(QuaternionAlgebra(-1,-7).maximal_order()) """ + def __init__(self, A, basis, check=True) -> None: r""" INPUT: @@ -2009,7 +1999,7 @@ def __init__(self, A, basis, check=True) -> None: basis = tuple([A(x) for x in basis]) # has rank 4 - V = A.base_ring()**4 + V = A.base_ring() ** 4 if V.span([V(x.coefficient_tuple()) for x in basis]).dimension() != 4: raise ValueError("basis must have rank 4") @@ -2017,7 +2007,7 @@ def __init__(self, A, basis, check=True) -> None: # but we can't actually do much with an order defined over a number # field - if A.base_ring() == QQ: # fast code over QQ + if A.base_ring() == QQ: # fast code over QQ M = matrix(QQ, 4, 4, [x.coefficient_tuple() for x in basis]) v = M.solve_left(V([1, 0, 0, 0])) @@ -2030,7 +2020,7 @@ def __init__(self, A, basis, check=True) -> None: if M1 != M2: raise ValueError("given lattice must be a ring") - if A.base_ring() != QQ: # slow code over number fields (should eventually use PARI's nfhnf) + if A.base_ring() != QQ: # slow code over number fields (should eventually use PARI's nfhnf) O = None try: O = A.base_ring().maximal_order() @@ -2038,24 +2028,21 @@ def __init__(self, A, basis, check=True) -> None: pass if O: - M = matrix(A.base_ring(), 4, 4, [x.coefficient_tuple() - for x in basis]) + M = matrix(A.base_ring(), 4, 4, [x.coefficient_tuple() for x in basis]) v = M.solve_left(V([1, 0, 0, 0])) if any(a not in O for a in v): raise ValueError("lattice must contain 1") # check if multiplicatively closed - Y = matrix(QQ, 16, 4, [(x*y).coefficient_tuple() - for x in basis for y in basis]) + Y = matrix(QQ, 16, 4, [(x * y).coefficient_tuple() for x in basis for y in basis]) X = M.solve_left(Y) if any(a not in O for x in X for a in x): raise ValueError("given lattice must be a ring") self.__basis = tuple(basis) self.__quaternion_algebra = A - Parent.__init__(self, base=ZZ, facade=(A,), - category=Algebras(ZZ).Facade().FiniteDimensional()) + Parent.__init__(self, base=ZZ, facade=(A,), category=Algebras(ZZ).Facade().FiniteDimensional()) def _element_constructor_(self, x): r""" @@ -2193,6 +2180,7 @@ def __richcmp__(self, other, op) -> bool: True """ from sage.structure.richcmp import op_NE, richcmp + if not isinstance(other, QuaternionOrder): return op == op_NE return richcmp(self.unit_ideal(), other.unit_ideal(), op) @@ -2308,7 +2296,7 @@ def intersection(self, other): if other.quaternion_algebra() != A: raise ValueError("self and other must be in the same ambient quaternion algebra") - V = A.base_ring()**4 + V = A.base_ring() ** 4 B = V.span([V(list(g)) for g in self.basis()], ZZ) C = V.span([V(list(g)) for g in other.basis()], ZZ) @@ -2338,7 +2326,7 @@ def free_module(self): [ 0 0 1/2 1/2] [ 0 0 0 1] """ - V = self.quaternion_algebra().base_ring()**4 + V = self.quaternion_algebra().base_ring() ** 4 return V.span([V(list(g)) for g in self.basis()], ZZ) def discriminant(self): @@ -2455,7 +2443,7 @@ def _right_order_from_ideal_basis(self, basis): psi = [M([list(f * x) for x in Z.basis()]) for f in basis] # invert them - psi_inv = [x**(-1) for x in psi] + psi_inv = [x ** (-1) for x in psi] # apply the four inverses to I W = [I * x for x in psi_inv] @@ -2695,6 +2683,7 @@ def random_ideal(self, side='left', norm=None, *, reduce=None): if norm is None: from sage.arith.misc import next_prime + l = ZZ(3) while l.divides(self.discriminant()): l = next_prime(l) @@ -2716,11 +2705,11 @@ def random_ideal(self, side='left', norm=None, *, reduce=None): vecs, mods = [], [] for l, e in norm.factor(): mod = l**e - extra = l**(e + 1 + (l == 2)) + extra = l ** (e + 1 + (l == 2)) for _ in range(999): vec = vector([x] + [randrange(mod) for _ in range(3)]) nf = vec * gram * vec - if (rs := (nf - mod).roots(ring=Zmod(extra), multiplicities=False)): + if rs := (nf - mod).roots(ring=Zmod(extra), multiplicities=False): r = ZZ(choice(rs)) break else: @@ -2733,8 +2722,9 @@ def random_ideal(self, side='left', norm=None, *, reduce=None): mods.append(extra) from sage.arith.misc import CRT_vectors + vec = vector(ZZ, CRT_vectors(vecs, mods)) - elt = B.sum(c*g for c, g in zip(vec, O.gens())) + elt = B.sum(c * g for c, g in zip(vec, O.gens())) I = idl((norm, elt)) @@ -3072,9 +3062,9 @@ def attempt_isomorphism(self, other): N = self.intersection(other).free_module().index_in(self.free_module()) I = N * self * other gamma = I.minimal_element() - if self*gamma != I: + if self * gamma != I: return False, None - if gamma*other != I: + if gamma * other != I: return False, None return True, gamma @@ -3114,7 +3104,7 @@ def attempt_isomorphism(self, other): # We can tell if 1, i, j, k cover all the alpha we need to test, # by checking if we have additional ramified primes which are not the square-free parts of nrd(i), nrd(j) or nrd(k) a, b = -Q.invariants()[0], -Q.invariants()[1] - square_free_invariants = [a.squarefree_part(), b.squarefree_part(), (a*b).squarefree_part()] + square_free_invariants = [a.squarefree_part(), b.squarefree_part(), (a * b).squarefree_part()] is_result_guaranteed = len([a for a in Q.ramified_primes() if a not in square_free_invariants]) == 0 if is_result_guaranteed: @@ -3144,8 +3134,8 @@ class QuaternionFractionalIdeal_rational(QuaternionFractionalIdeal): - ``check`` -- boolean (default: ``True``); if ``False``, do no type checking. """ - def __init__(self, Q, basis, left_order=None, - right_order=None, check=True) -> None: + + def __init__(self, Q, basis, left_order=None, right_order=None, check=True) -> None: r""" EXAMPLES:: @@ -3172,8 +3162,7 @@ def __init__(self, Q, basis, left_order=None, raise TypeError("right_order must be a quaternion order or None") if not isinstance(basis, (list, tuple)): raise TypeError("basis must be a list or tuple") - basis = tuple([Q(v) for v in - (QQ**4).span([Q(v).coefficient_tuple() for v in basis], ZZ).basis()]) + basis = tuple([Q(v) for v in (QQ**4).span([Q(v).coefficient_tuple() for v in basis], ZZ).basis()]) if len(basis) != 4: raise ValueError("fractional ideal must have rank 4") self.__left_order = left_order @@ -3253,8 +3242,7 @@ def scale(self, alpha, left=False): gens = basis_for_quaternion_lattice([b * alpha for b in self.basis()]) left_order = self.__left_order if alpha in QQ or not left else None right_order = self.__right_order if alpha in QQ or left else None - return Q.ideal(gens, check=False, - left_order=left_order, right_order=right_order) + return Q.ideal(gens, check=False, left_order=left_order, right_order=right_order) def quaternion_algebra(self): r""" @@ -3470,7 +3458,7 @@ def gens_two(self): raise RuntimeError('bug in QuaternionFractionalIdeal_rational.gens_two()') B = self.quaternion_algebra() a = B.sum(c * g for c, g in zip(v, I.basis())) - return N/denom, a/denom + return N / denom, a / denom def __repr__(self) -> str: r""" @@ -3768,7 +3756,7 @@ def theta_series(self, B, var='q'): if var == self.__theta_series.variable(): return self.__theta_series.add_bigoh(B) p_ring = self._theta_series.parent().change_var(var) - p_ring(self.__theta_series.list()[:B+1]) + p_ring(self.__theta_series.list()[: B + 1]) except AttributeError: pass v = self.theta_series_vector(B) @@ -3852,9 +3840,7 @@ def conjugate(self): sage: I.conjugate() Fractional ideal (2 + 2*j + 28*k, 2*i + 4*j + 34*k, 8*j + 32*k, 40*k) """ - return self.quaternion_algebra().ideal([b.conjugate() for b in self.basis()], - left_order=self.__right_order, - right_order=self.__left_order) + return self.quaternion_algebra().ideal([b.conjugate() for b in self.basis()], left_order=self.__right_order, right_order=self.__left_order) def __mul__(self, right): r""" @@ -3879,7 +3865,7 @@ def __mul__(self, right): right = right.unit_ideal() if not isinstance(right, QuaternionFractionalIdeal_rational): return self.scale(right, left=False) - gens = [a*b for a in self.basis() for b in right.basis()] + gens = [a * b for a in self.basis() for b in right.basis()] # if self.__right_order == right.__left_order: # left_order = self.__left_order # right_order = right.__right_order @@ -4192,7 +4178,7 @@ def pullback(self, J, side=None): N = self.norm() if gcd(N, J.norm()) != 1: raise ValueError("self and J must have coprime norms") - return J*self + N*J.left_order() + return J * self + N * J.left_order() if side == "right": if self.right_order() != J.left_order(): @@ -4293,15 +4279,13 @@ def is_right_equivalent(self, J, B=10, certificate=False) -> bool | tuple: True """ if not isinstance(J, QuaternionFractionalIdeal_rational): - raise TypeError('J must be a fractional ideal' - ' in a rational quaternion algebra') + raise TypeError('J must be a fractional ideal' ' in a rational quaternion algebra') if self.right_order() != J.right_order(): raise ValueError('self and J must be right ideals over the same order') if not self.quaternion_algebra().is_definite(): - raise NotImplementedError('equivalence test of ideals not implemented' - ' for indefinite quaternion algebras') + raise NotImplementedError('equivalence test of ideals not implemented' ' for indefinite quaternion algebras') # Just test theta series first; if the theta series are # different, the ideals are definitely not equivalent @@ -4355,8 +4339,7 @@ def is_principal(self, certificate=False) -> bool | tuple: True """ if not self.quaternion_algebra().is_definite(): - raise NotImplementedError('principality test not implemented in' - ' indefinite quaternion algebras') + raise NotImplementedError('principality test not implemented in' ' indefinite quaternion algebras') c = self.theta_series_vector(2)[1] if not certificate: @@ -4455,7 +4438,7 @@ def __contains__(self, x) -> bool: """ try: x = self.quaternion_algebra()(x) - return self.basis_matrix().transpose().solve_right(vector(x)) in ZZ**4 + return self.basis_matrix().transpose().solve_right(vector(x)) in ZZ ** 4 except (ValueError, TypeError): return False @@ -4538,7 +4521,7 @@ def cyclic_right_subideals(self, p, alpha=None): f = Q.modp_splitting_map(p) if alpha is not None: alpha = f(alpha) - W = GF(p)**4 + W = GF(p) ** 4 try: A = W.span_of_basis([W(f(a).list()) for a in basis]) scale = 1 @@ -4563,7 +4546,7 @@ def cyclic_right_subideals(self, p, alpha=None): # Do not care about the denominator since we're really working in I/p*I. AiB, _ = AiB._clear_denom() - pB = p*IB + pB = p * IB pB, d = pB._clear_denom() ans = [] @@ -4590,7 +4573,7 @@ def cyclic_right_subideals(self, p, alpha=None): # Now construct submodule of the ideal I spanned by the # linear combinations given by z of the basis for J along # with p*I. - G = (d*z).stack(pB) # have to multiply by d since we divide by it below in the "gens = " line. + G = (d * z).stack(pB) # have to multiply by d since we divide by it below in the "gens = " line. H = G._hnf_pari(0, include_zero_rows=False) gens = tuple(quaternion_algebra_cython.rational_quaternions_from_integral_matrix_and_denom(Q, H, d)) if scale != 1: @@ -4681,7 +4664,7 @@ def primitive_decomposition(self): if g.is_one(): return self, g - J = self.scale(1/g) + J = self.scale(1 / g) return J, g @@ -4705,6 +4688,7 @@ def is_primitive(self) -> bool: _, g = self.primitive_decomposition() return g.is_one() + ####################################################################### # Some utility functions that are needed here and are too # specialized to go elsewhere. @@ -4871,11 +4855,11 @@ def normalize_basis_at_p(e, p, B=QuaternionAlgebraElement_abstract.pair): if v < min_v or (v == min_v and (min_m != min_n) and (m == n)): min_m, min_n, min_v = m, n, v - if (min_m == min_n) or p != 2: # In this case we can diagonalize - if min_m == min_n: # Diagonal entry has minimal valuation + if (min_m == min_n) or p != 2: # In this case we can diagonalize + if min_m == min_n: # Diagonal entry has minimal valuation f0 = e[min_m] else: - f0 = e[min_m] + e[min_n] # Only off-diagonal entries have min. val., but p!=2 + f0 = e[min_m] + e[min_n] # Only off-diagonal entries have min. val., but p!=2 # Swap with first vector e[0], e[min_m] = e[min_m], e[0] @@ -4912,10 +4896,9 @@ def normalize_basis_at_p(e, p, B=QuaternionAlgebraElement_abstract.pair): B11 = B(f1, f1) B01 = B(f0, f1) d = B00 * B11 - B01**2 - tu = [(B01 * B(f1, e[l]) - B11 * B(f0, e[l]), - B01 * B(f0, e[l]) - B00 * B(f1, e[l])) for l in range(2, N)] + tu = [(B01 * B(f1, e[l]) - B11 * B(f0, e[l]), B01 * B(f0, e[l]) - B00 * B(f1, e[l])) for l in range(2, N)] - e[2:N] = [e[l] + tu[l-2][0]/d * f0 + tu[l-2][1]/d * f1 for l in range(2, N)] + e[2:N] = [e[l] + tu[l - 2][0] / d * f0 + tu[l - 2][1] / d * f1 for l in range(2, N)] # Recursively normalize remaining vectors f = normalize_basis_at_p(e[2:N], p) @@ -4966,11 +4949,6 @@ def maxord_solve_aux_eq(a, b, p): raise RuntimeError("b must have v_p(b) in {0,1}") R = ZZ.quo(ZZ(4)) - lut = {(R(1), R(1)): (1, 1, 1), - (R(1), R(2)): (1, 0, 0), - (R(1), R(3)): (1, 0, 0), - (R(3), R(1)): (1, 1, 1), - (R(3), R(2)): (1, 0, 1), - (R(3), R(3)): (1, 1, 1)} + lut = {(R(1), R(1)): (1, 1, 1), (R(1), R(2)): (1, 0, 0), (R(1), R(3)): (1, 0, 0), (R(3), R(1)): (1, 1, 1), (R(3), R(2)): (1, 0, 1), (R(3), R(3)): (1, 1, 1)} return lut[(R(a), R(b))] diff --git a/src/sage/algebras/quaternion_algebra.py b/src/sage/algebras/quaternion_algebra.py index 2bb0e9989fb..02e636944cf 100644 --- a/src/sage/algebras/quaternion_algebra.py +++ b/src/sage/algebras/quaternion_algebra.py @@ -1,8 +1,8 @@ - ############################################################ # Backwards compatible unpickling ############################################################ + def unpickle_QuaternionAlgebra_v0(*key): """ The `0`-th version of pickling for quaternion algebras. @@ -15,4 +15,5 @@ def unpickle_QuaternionAlgebra_v0(*key): Quaternion Algebra (-5, -19) with base ring Rational Field """ from sage.algebras.quatalg.quaternion_algebra import QuaternionAlgebra + return QuaternionAlgebra(*key) diff --git a/src/sage/algebras/quaternion_algebra_element.py b/src/sage/algebras/quaternion_algebra_element.py index c778091690c..84b822f8c50 100644 --- a/src/sage/algebras/quaternion_algebra_element.py +++ b/src/sage/algebras/quaternion_algebra_element.py @@ -1,4 +1,3 @@ - ####################################################################### # Backward compatible unpickle functions ####################################################################### diff --git a/src/sage/algebras/rational_cherednik_algebra.py b/src/sage/algebras/rational_cherednik_algebra.py index ff47bac0345..e6eb2ace1f7 100644 --- a/src/sage/algebras/rational_cherednik_algebra.py +++ b/src/sage/algebras/rational_cherednik_algebra.py @@ -1,6 +1,7 @@ """ Rational Cherednik Algebras """ + # **************************************************************************** # Copyright (C) 2015 Travis Scrimshaw # @@ -72,6 +73,7 @@ class RationalCherednikAlgebra(CombinatorialFreeModule): - [GGOR2003]_ - [EM2001]_ """ + @staticmethod def __classcall_private__(cls, ct, c=1, t=None, base_ring=None, prefix=('a', 's', 'ac')): """ @@ -130,14 +132,10 @@ def __init__(self, ct, c, t, base_ring, prefix) -> None: self._t = t self._cartan_type = ct self._weyl = RootSystem(ct).root_lattice().weyl_group(prefix=prefix[1]) - self._hd = IndexedFreeAbelianMonoid(ct.index_set(), prefix=prefix[0], - bracket=False) - self._h = IndexedFreeAbelianMonoid(ct.index_set(), prefix=prefix[2], - bracket=False) + self._hd = IndexedFreeAbelianMonoid(ct.index_set(), prefix=prefix[0], bracket=False) + self._h = IndexedFreeAbelianMonoid(ct.index_set(), prefix=prefix[2], bracket=False) indices = DisjointUnionEnumeratedSets([self._hd, self._weyl, self._h]) - CombinatorialFreeModule.__init__(self, base_ring, indices, - category=Algebras(base_ring).WithBasis().Graded(), - sorting_key=self._genkey) + CombinatorialFreeModule.__init__(self, base_ring, indices, category=Algebras(base_ring).WithBasis().Graded(), sorting_key=self._genkey) def _genkey(self, t): r""" @@ -244,19 +242,14 @@ def algebra_generators(self): def gen_map(k): if k[0] == 's': i = int(k[1:]) - return self.monomial((self._hd.one(), - self._weyl.group_generators()[i], - self._h.one())) + return self.monomial((self._hd.one(), self._weyl.group_generators()[i], self._h.one())) if k[1] == 'c': i = int(k[2:]) - return self.monomial((self._hd.one(), - self._weyl.one(), - self._h.monoid_generators()[i])) + return self.monomial((self._hd.one(), self._weyl.one(), self._h.monoid_generators()[i])) i = int(k[1:]) - return self.monomial((self._hd.monoid_generators()[i], - self._weyl.one(), - self._h.one())) + return self.monomial((self._hd.monoid_generators()[i], self._weyl.one(), self._h.one())) + return Family(keys, gen_map) @cached_method @@ -328,7 +321,7 @@ def commute_w_hd(w, al): # al is given as a dictionary ret = P.one() for k in al: x = sum(c * gens_dict[i] for i, c in alpha[k].weyl_action(w)) - ret *= x**al[k] + ret *= x ** al[k] ret = ret.monomial_coefficients() for k in ret: yield (self._hd({I[i]: e for i, e in enumerate(k) if e != 0}), ret[k]) @@ -350,15 +343,12 @@ def commute_w_hd(w, al): # al is given as a dictionary del dr[ir] # We now commute right roots past the left reflections: s Ra = Ra' s - cur = self._from_dict({(hd, s * right[1], right[2]): c * cc - for s, c in terms - for hd, cc in commute_w_hd(s, dr)}) + cur = self._from_dict({(hd, s * right[1], right[2]): c * cc for s, c in terms for hd, cc in commute_w_hd(s, dr)}) cur = self.monomial((left[0], left[1], self._h(dl))) * cur # Add back in the commuted h and hd elements rem = self.monomial((left[0], left[1], self._h(dl))) - rem = rem * self.monomial((self._hd({ir: 1}), self._weyl.one(), - self._h({il: 1}))) + rem = rem * self.monomial((self._hd({ir: 1}), self._weyl.one(), self._h({il: 1}))) rem = rem * self.monomial((self._hd(dr), right[1], right[2])) return cur + rem @@ -370,23 +360,16 @@ def commute_w_hd(w, al): # al is given as a dictionary ret = P.one() r1_red = right[1].reduced_word() for k, dlk in dl.items(): - x = sum(c * gens_dict[i] - for i, c in alphacheck[k].weyl_action(r1_red, - inverse=True)) + x = sum(c * gens_dict[i] for i, c in alphacheck[k].weyl_action(r1_red, inverse=True)) ret *= x**dlk ret = ret.monomial_coefficients() w = left[1] * right[1] - return self._from_dict({(left[0], w, - self._h({I[i]: e for i, e in enumerate(k) - if e != 0}) * right[2] - ): ret[k] - for k in ret}) + return self._from_dict({(left[0], w, self._h({I[i]: e for i, e in enumerate(k) if e != 0}) * right[2]): ret[k] for k in ret}) # Otherwise dr is non-trivial and we have La Ls Ra Rs Rac, # so we must commute Ls Ra = Ra' Ls w = left[1] * right[1] - return self._from_dict({(left[0] * hd, w, right[2]): c - for hd, c in commute_w_hd(left[1], dr)}) + return self._from_dict({(left[0] * hd, w, right[2]): c for hd, c in commute_w_hd(left[1], dr)}) @cached_method def _product_coroot_root(self, i, j): @@ -433,8 +416,7 @@ def _product_coroot_root(self, i, j): for s in self._reflections: # p[0] is the root, p[1] is the coroot, p[2] the value c_s pr, pc, c = self._reflections[s] - terms.append((s, c * R(ac.scalar(pr) * pc.scalar(al) - / pc.scalar(pr)))) + terms.append((s, c * R(ac.scalar(pr) * pc.scalar(al) / pc.scalar(pr)))) return tuple(terms) def degree_on_basis(self, m): @@ -469,8 +451,7 @@ def trivial_idempotent(self): coeff = self.base_ring()(~self._weyl.cardinality()) hd_one = self._hd.one() # root - a h_one = self._h.one() # coroot - ac - return self._from_dict({(hd_one, w, h_one): coeff for w in self._weyl}, - remove_zeros=False) + return self._from_dict({(hd_one, w, h_one): coeff for w in self._weyl}, remove_zeros=False) @cached_method def deformed_euler(self): @@ -489,8 +470,7 @@ def deformed_euler(self): cm = ~CartanMatrix(self._cartan_type) n = len(I) ac = [G['ac' + str(i)] for i in I] - la = [sum(cm[i, j] * G['a' + str(I[i])] - for i in range(n)) for j in range(n)] + la = [sum(cm[i, j] * G['a' + str(I[i])] for i in range(n)) for j in range(n)] return self.sum(ac[i] * la[i] for i in range(n)) @cached_method diff --git a/src/sage/algebras/schur_algebra.py b/src/sage/algebras/schur_algebra.py index 813f16922bd..2b51ab010a5 100644 --- a/src/sage/algebras/schur_algebra.py +++ b/src/sage/algebras/schur_algebra.py @@ -120,8 +120,7 @@ def schur_representative_indices(n, r): I1 = _schur_I_nr_representatives(n, k) else: I2 = _schur_I_nr_representatives(n, k - j) - I1 = [I1[m1] + I2[m2] for m1 in range(len(I1)) - for m2 in range(len(I2))] + I1 = [I1[m1] + I2[m2] for m1 in range(len(I1)) for m2 in range(len(I2))] j = k elif k == l - 1: I2 = [] @@ -130,8 +129,7 @@ def schur_representative_indices(n, r): I1 = _schur_I_nr_representatives(n, k) else: I2 = _schur_I_nr_representatives(n, k - j) - I1 = [I1[m1] + I2[m2] for m1 in range(len(I1)) - for m2 in range(len(I2))] + I1 = [I1[m1] + I2[m2] for m1 in range(len(I1)) for m2 in range(len(I2))] else: k += 1 @@ -204,6 +202,7 @@ class SchurAlgebra(CombinatorialFreeModule): - [Gr2007]_ - :wikipedia:`Schur_algebra` """ + def __init__(self, R, n, r): """ Initialize ``self``. @@ -238,10 +237,7 @@ def __init__(self, R, n, r): self._n = n self._r = r - CombinatorialFreeModule.__init__(self, R, - schur_representative_indices(n, r), - prefix='S', bracket=False, - category=AlgebrasWithBasis(R).FiniteDimensional()) + CombinatorialFreeModule.__init__(self, R, schur_representative_indices(n, r), prefix='S', bracket=False, category=AlgebrasWithBasis(R).FiniteDimensional()) def _repr_(self) -> str: """ @@ -278,8 +274,7 @@ def one(self): sage: x * e == x True """ - tt = IntegerListsLex(length=self._r, min_part=1, max_part=self._n, - min_slope=0) + tt = IntegerListsLex(length=self._r, min_part=1, max_part=self._n, min_slope=0) words = [tuple(u) for u in tt] return self.sum(self._monomial((w, w)) for w in words) @@ -323,8 +318,7 @@ def product_on_basis(self, e_ij, e_kl): l = sorted(l) # Find basis elements (p,q) such that p ~ i and q ~ l - e_pq = [v for v in self.basis().keys() - if v[0] == i and sorted(v[1]) == l] + e_pq = [v for v in self.basis().keys() if v[0] == i and sorted(v[1]) == l] b = self.basis() product = self.zero() @@ -333,8 +327,7 @@ def product_on_basis(self, e_ij, e_kl): for e in e_pq: Z_ijklpq = self.base_ring().zero() for s in Permutations(list(j)): - if (schur_representative_from_index(e[0], s) == e_ij - and schur_representative_from_index(s, e[1]) == e_kl): + if schur_representative_from_index(e[0], s) == e_ij and schur_representative_from_index(s, e[1]) == e_kl: Z_ijklpq += self.base_ring().one() product += Z_ijklpq * b[e] @@ -359,7 +352,7 @@ def dimension(self): sage: S.dimension() 35 """ - return binomial(self._n ** 2 + self._r - 1, self._r) + return binomial(self._n**2 + self._r - 1, self._r) class SchurTensorModule(CombinatorialFreeModule_Tensor): @@ -411,6 +404,7 @@ class SchurTensorModule(CombinatorialFreeModule_Tensor): ....: for bT in T.basis() for bA in A.basis() for p in P) True """ + def __init__(self, R, n, r): """ Initialize ``self``. @@ -471,8 +465,7 @@ def _monomial_product(self, xi, v): B[1] # B[1] # B[2] + B[1] # B[2] # B[1] + B[2] # B[1] # B[1] """ L = range(1, self._n + 1) - ret = [tuple(i) for i in itertools.product(L, repeat=self._r) - if schur_representative_from_index(i, v) == xi] + ret = [tuple(i) for i in itertools.product(L, repeat=self._r) if schur_representative_from_index(i, v) == xi] return self.sum_of_monomials(ret) class Element(CombinatorialFreeModule_Tensor.Element): @@ -520,13 +513,10 @@ def _acted_upon_(self, elt, self_on_left=False): P = self.parent() if self_on_left: if elt in P._sga: - return P.sum_of_terms((tuple([m[i - 1] for i in me]), - c * ce) - for m, c in self for me, ce in elt) + return P.sum_of_terms((tuple([m[i - 1] for i in me]), c * ce) for m, c in self for me, ce in elt) if elt in P._sga._indices: - return P.sum_of_terms((tuple([m[i - 1] for i in elt]), c) - for m, c in self) + return P.sum_of_terms((tuple([m[i - 1] for i in elt]), c) for m, c in self) elif elt in P._schur: # self_on_left is False return P._schur_action(elt, self) @@ -583,6 +573,7 @@ def GL_irreducible_character(n, mu, KK): # make ST the superstandard tableau of shape mu from sage.combinat.tableau import from_shape_and_word + ST = from_shape_and_word(mu, list(range(1, r + 1)), convention='English') # make ell the reading word of the highest weight tableau of shape mu @@ -592,8 +583,7 @@ def GL_irreducible_character(n, mu, KK): # This is the notation `\{X\}` from just before (5.3a) of [Gr2007]_. S = SGA._indices - BracC = SGA._from_dict({S(x.tuple()): x.sign() for x in ST.column_stabilizer()}, - remove_zeros=False) + BracC = SGA._from_dict({S(x.tuple()): x.sign() for x in ST.column_stabilizer()}, remove_zeros=False) f = e * BracC # M.action_by_symmetric_group_algebra(e, BracC) # [Green, Theorem 5.3b] says that a basis of the Carter-Lusztig @@ -660,9 +650,7 @@ def GL_irreducible_character(n, mu, KK): phi = mbasis.zero() for aa, c_aa in enumerate(contents): - mat = [[elt_basis_aa.inner_product(elt_carter_lusztig) - for elt_carter_lusztig in carter_lusztig] - for elt_basis_aa in graded_basis[aa]] + mat = [[elt_basis_aa.inner_product(elt_carter_lusztig) for elt_carter_lusztig in carter_lusztig] for elt_basis_aa in graded_basis[aa]] angle = Matrix(mat) phi += (len(JJ[aa]) - angle.nullity()) * mbasis(c_aa) return phi diff --git a/src/sage/algebras/shuffle_algebra.py b/src/sage/algebras/shuffle_algebra.py index d38d7b2dfb4..8b2066a43e4 100644 --- a/src/sage/algebras/shuffle_algebra.py +++ b/src/sage/algebras/shuffle_algebra.py @@ -124,6 +124,7 @@ class ShuffleAlgebra(CombinatorialFreeModule): sage: A_d(x) -2*S[001] + S[010] """ + @staticmethod def __classcall_private__(cls, R, names, prefix=None): """ @@ -139,8 +140,7 @@ def __classcall_private__(cls, R, names, prefix=None): """ if prefix is None: prefix = 'B' - return super().__classcall__(cls, R, - Alphabet(names), prefix) + return super().__classcall__(cls, R, Alphabet(names), prefix) def __init__(self, R, names, prefix): r""" @@ -169,9 +169,7 @@ def __init__(self, R, names, prefix): self._alphabet = names self.__ngens = self._alphabet.cardinality() cat = GradedHopfAlgebrasWithBasis(R).Commutative().Connected() - CombinatorialFreeModule.__init__(self, R, Words(names, infinite=False), - latex_prefix='', prefix=prefix, - category=cat) + CombinatorialFreeModule.__init__(self, R, Words(names, infinite=False), latex_prefix='', prefix=prefix, category=cat) def variable_names(self): r""" @@ -214,8 +212,7 @@ def _repr_(self) -> str: gen = "one generator" else: gen = "%s generators" % self.__ngens - return "Shuffle Algebra on " + gen + " %s over %s" % ( - self._alphabet.list(), self.base_ring()) + return "Shuffle Algebra on " + gen + " %s over %s" % (self._alphabet.list(), self.base_ring()) @cached_method def one_basis(self): @@ -276,7 +273,7 @@ def antipode_on_basis(self, w): -B[bca] """ mone = -self.base_ring().one() - return self.term(w.reversal(), mone**len(w)) + return self.term(w.reversal(), mone ** len(w)) def gen(self, i): r""" @@ -445,6 +442,7 @@ def _element_constructor_(self, x): # ok, not a shuffle algebra element (or should not be viewed as one). if isinstance(x, str): from sage.misc.sage_eval import sage_eval + return sage_eval(x, locals=self.gens_dict()) R = self.base_ring() # coercion via base ring @@ -590,7 +588,7 @@ def to_dual_pbw_element(self, w): support = [W(i[0]) for i in list(w)] min_elt = W(support[0]) if len(support) > 1: - for word in support[1:len(support) - 1]: + for word in support[1 : len(support) - 1]: if min_elt.lex_less(word): min_elt = W(word) coeff = list(w)[support.index(min_elt)][1] @@ -655,6 +653,7 @@ class DualPBWBasis(CombinatorialFreeModule): sage: all(A(S(A(w))) == A(w) for w in W) True """ + @staticmethod def __classcall_private__(cls, R, names): """ @@ -682,8 +681,7 @@ def __init__(self, R, names): self._alphabet = names self._alg = ShuffleAlgebra(R, names) cat = GradedHopfAlgebrasWithBasis(R).Commutative().Connected() - CombinatorialFreeModule.__init__(self, R, Words(names), prefix='S', - category=cat) + CombinatorialFreeModule.__init__(self, R, Words(names), prefix='S', category=cat) def _repr_term(self, t) -> str: """ @@ -968,6 +966,7 @@ def expansion_on_basis(self, w): 2*B[aabb] + B[abab] """ from sage.arith.misc import factorial + if not w: return self._alg.one() if len(w) == 1: @@ -976,8 +975,7 @@ def expansion_on_basis(self, w): W = self.basis().keys() letter = W([w[0]]) expansion = self.expansion_on_basis(W(w[1:])) - return self._alg.sum_of_terms((letter * i, c) - for i, c in expansion) + return self._alg.sum_of_terms((letter * i, c) for i, c in expansion) lf = w.lyndon_factorization() powers = {} @@ -991,6 +989,7 @@ class Element(CombinatorialFreeModule.Element): """ An element in the dual PBW basis. """ + def expand(self): """ Expand ``self`` in words of the shuffle algebra. diff --git a/src/sage/algebras/splitting_algebra.py b/src/sage/algebras/splitting_algebra.py index c75852e8bcf..6dd1d20631b 100644 --- a/src/sage/algebras/splitting_algebra.py +++ b/src/sage/algebras/splitting_algebra.py @@ -59,6 +59,7 @@ class SplittingAlgebraElement(PolynomialQuotientRingElement): sage: type(CR6(5)) """ + def __invert__(self): r""" Return the inverse of ``self``. @@ -122,6 +123,7 @@ def monomial_coefficients(self, copy=True) -> dict: dict = monomial_coefficients + # --------------------------------------------------------------------------- # Parent class of the splitting algebra # --------------------------------------------------------------------------- @@ -200,10 +202,10 @@ class SplittingAlgebra(PolynomialQuotientRing_domain): - [Tho2011]_ - [LT2012]_ """ + Element = SplittingAlgebraElement - def __init__(self, monic_polynomial, names='X', - iterate=True, warning=True) -> None: + def __init__(self, monic_polynomial, names='X', iterate=True, warning=True) -> None: r""" Python constructor. @@ -225,10 +227,10 @@ def __init__(self, monic_polynomial, names='X', deg = monic_polynomial.degree() from sage.structure.category_object import normalize_names + self._root_names = normalize_names(deg - 1, names) root_names = list(self._root_names) - verbose("Create splitting algebra to base ring %s and polynomial %s (%s %s)" - % (base_ring, monic_polynomial, iterate, warning)) + verbose("Create splitting algebra to base ring %s and polynomial %s (%s %s)" % (base_ring, monic_polynomial, iterate, warning)) self._defining_polynomial = monic_polynomial self._iterate = iterate @@ -238,6 +240,7 @@ def __init__(self, monic_polynomial, names='X', raise TypeError("base_ring must be an integral domain") except NotImplementedError: from sage.categories.rings import Rings + if base_ring not in Rings(): raise TypeError("base_ring must be a ring") if warning: @@ -293,9 +296,7 @@ def __init__(self, monic_polynomial, names='X', # ----------------------------------------------------------- # successive solution via recursion (on base_ring_step) # ----------------------------------------------------------- - base_ring_step = SplittingAlgebra(monic_polynomial, - tuple(root_names), - iterate=False, warning=warning) + base_ring_step = SplittingAlgebra(monic_polynomial, tuple(root_names), iterate=False, warning=warning) first_root = base_ring_step.gen() verbose("base_ring_step %s defined:" % (base_ring_step)) @@ -304,6 +305,7 @@ def __init__(self, monic_polynomial, names='X', # splitting first root off # ------------------------------------------------------------- from copy import copy + root_names_reduces = copy(root_names) root_names_reduces.remove(root_name) @@ -313,8 +315,7 @@ def __init__(self, monic_polynomial, names='X', verbose("Invoking recursion with: %s" % (q,)) - SplittingAlgebra.__init__(self, q, root_names_reduces, - warning=warning) + SplittingAlgebra.__init__(self, q, root_names_reduces, warning=warning) splitting_roots = base_ring_step._splitting_roots + self._splitting_roots coefficients_list = base_ring_step._coefficients_list + self._coefficients_list @@ -380,9 +381,9 @@ def __init__(self, monic_polynomial, names='X', continue root_inv = self.one() for pos in range(deg_cf - 1): - root_inv = (-1)**(pos + 1) * cf[deg_cf - pos - 1] - root_inv * root + root_inv = (-1) ** (pos + 1) * cf[deg_cf - pos - 1] - root_inv * root verbose("inverse %s of root %s" % (root_inv, root)) - root_inv = (-1)**(deg_cf) * cf0_inv * root_inv + root_inv = (-1) ** (deg_cf) * cf0_inv * root_inv self._invertible_elements.update({root: root_inv}) verbose("adding inverse %s of root %s" % (root_inv, root)) invert_items = list(self._invertible_elements.items()) @@ -422,8 +423,7 @@ def __reduce__(self) -> tuple: # case of factorization algebra (intermediate construction step) par_pol = self.cover_ring() def_polynomial = par_pol(def_coefficients) - return self.__class__, (def_polynomial, self._root_names, - self._iterate, False) + return self.__class__, (def_polynomial, self._root_names, self._iterate, False) def _repr_(self) -> str: r""" @@ -445,13 +445,9 @@ def _repr_(self) -> str: over Integer Ring """ if self.is_completely_split(): - return ('Splitting Algebra of %s with roots %s over %s' - % (self.defining_polynomial(), self.splitting_roots(), - self.scalar_base_ring())) + return 'Splitting Algebra of %s with roots %s over %s' % (self.defining_polynomial(), self.splitting_roots(), self.scalar_base_ring()) - return ('Factorization Algebra of %s with roots %s over %s' - % (self.defining_polynomial(), self.splitting_roots(), - self.scalar_base_ring())) + return 'Factorization Algebra of %s with roots %s over %s' % (self.defining_polynomial(), self.splitting_roots(), self.scalar_base_ring()) def _first_ngens(self, n) -> tuple: r""" @@ -533,25 +529,21 @@ def hom(self, im_gens, codomain=None, check=True, base_map=None): all_gens = self.gens_dict_recursive() if len(im_gens) != len(all_gens): - return super().hom(im_gens, codomain=codomain, - check=check, base_map=base_map) + return super().hom(im_gens, codomain=codomain, check=check, base_map=base_map) num_gens = len(self.gens()) im_gens_start = [img for img in im_gens if im_gens.index(img) < num_gens] im_gens_end = [img for img in im_gens if im_gens.index(img) >= num_gens] if not im_gens_end: - return super().hom(im_gens, codomain=codomain, - check=check, base_map=base_map) + return super().hom(im_gens, codomain=codomain, check=check, base_map=base_map) verbose('base %s im_gens_end %s codomain %s check %s base_map %s' % (base_ring, im_gens_end, codomain, check, base_map)) - hom_on_base_recurs = base_ring.hom(im_gens_end, codomain=codomain, - check=check, base_map=base_map) + hom_on_base_recurs = base_ring.hom(im_gens_end, codomain=codomain, check=check, base_map=base_map) verbose('hom_on_base_recurs %s' % (hom_on_base_recurs)) cover_ring = self.cover_ring() - hom_from_cover = cover_ring.hom(im_gens_start, codomain=codomain, - check=check, base_map=hom_on_base_recurs) + hom_from_cover = cover_ring.hom(im_gens_start, codomain=codomain, check=check, base_map=hom_on_base_recurs) lift = self.lifting_map() return hom_from_cover * lift @@ -605,6 +597,7 @@ def lifting_map(self): I """ from sage.rings.morphism import RingMap_lift + return RingMap_lift(self, self.cover_ring()) def splitting_roots(self) -> list: @@ -677,8 +670,8 @@ def defining_polynomial(self): # ====================================================================== # ---------------------------------------------------------------------- -def solve_with_extension(monic_polynomial, root_names=None, var='x', - flatten=False, warning=True) -> list[tuple]: + +def solve_with_extension(monic_polynomial, root_names=None, var='x', flatten=False, warning=True) -> list[tuple]: r""" Return all roots of a monic polynomial in its base ring or in an appropriate extension ring, as far as possible. @@ -720,6 +713,7 @@ def solve_with_extension(monic_polynomial, root_names=None, var='x', sage: _[0][0].parent() Universal Cyclotomic Field """ + def create_roots(monic_polynomial, warning=warning): r""" This internal function creates all roots of a polynomial in an @@ -754,6 +748,7 @@ def create_roots(monic_polynomial, warning=warning): # ------------------------------------------------------------- reset_coercion = False from sage.rings.number_field.number_field import NumberField_generic + if isinstance(base_ring, NumberField_generic): reset_coercion = True elif base_ring.is_finite() and not base_ring.is_prime_field(): @@ -767,8 +762,7 @@ def create_roots(monic_polynomial, warning=warning): pol_emb = monic_polynomial.change_ring(ext_field) roots = pol_emb.roots() except NotImplementedError: - ext_ring = SplittingAlgebra(monic_polynomial, name_list, - warning=warning) + ext_ring = SplittingAlgebra(monic_polynomial, name_list, warning=warning) verbose("splitting algebra %s defined" % (ext_ring)) roots = [(r, 1) for r in ext_ring.splitting_roots()] return roots @@ -776,6 +770,7 @@ def create_roots(monic_polynomial, warning=warning): deg_pol = monic_polynomial.degree() if not root_names: from sage.structure.category_object import normalize_names + root_names = normalize_names(deg_pol - 1, 'r') name_list = list(root_names) root_list = [] @@ -803,10 +798,10 @@ def create_roots(monic_polynomial, warning=warning): h = monic_polynomial.variables()[0] divisor = monic_polynomial.base_ring().one() for r, m in root_list: - divisor *= (h - r)**m + divisor *= (h - r) ** m q, _ = monic_polynomial.quo_rem(divisor) if len(name_list) > deg_pol - num_roots - 1: - name_list = name_list[:deg_pol - num_roots - 1] + name_list = name_list[: deg_pol - num_roots - 1] verbose(f"{num_roots} root found in base ring, now solving {q}") missing_roots = create_roots(q, warning=True) roots = root_list + missing_roots diff --git a/src/sage/algebras/steenrod/all.py b/src/sage/algebras/steenrod/all.py index 5ba77d619b9..a09ad71713e 100644 --- a/src/sage/algebras/steenrod/all.py +++ b/src/sage/algebras/steenrod/all.py @@ -1,6 +1,8 @@ """ The Steenrod algebra """ + from sage.misc.lazy_import import lazy_import + lazy_import('sage.algebras.steenrod.steenrod_algebra', ['SteenrodAlgebra', 'Sq']) del lazy_import diff --git a/src/sage/algebras/steenrod/steenrod_algebra.py b/src/sage/algebras/steenrod/steenrod_algebra.py index ee9ad549315..9c36d8340af 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra.py +++ b/src/sage/algebras/steenrod/steenrod_algebra.py @@ -481,6 +481,7 @@ class SteenrodAlgebra_generic(CombinatorialFreeModule): sage: sage.algebras.steenrod.steenrod_algebra.SteenrodAlgebra_generic(5, 'adem') mod 5 Steenrod algebra, serre-cartan basis """ + @staticmethod def __classcall__(self, p=2, basis='milnor', **kwds): """ @@ -500,6 +501,7 @@ def __classcall__(self, p=2, basis='milnor', **kwds): get_basis_name, normalize_profile, ) + profile = kwds.get('profile', None) precision = kwds.get('precision', None) truncation_type = kwds.get('truncation_type', 'auto') @@ -514,10 +516,8 @@ def __classcall__(self, p=2, basis='milnor', **kwds): raise ValueError("option 'generic' is not a boolean") std_basis = get_basis_name(basis, p, generic=std_generic) - std_profile, std_type = normalize_profile(profile, precision=precision, - truncation_type=truncation_type, p=p, generic=std_generic) - return super().__classcall__(self, p=p, basis=std_basis, profile=std_profile, - truncation_type=std_type, generic=std_generic) + std_profile, std_type = normalize_profile(profile, precision=precision, truncation_type=truncation_type, p=p, generic=std_generic) + return super().__classcall__(self, p=p, basis=std_basis, profile=std_profile, truncation_type=std_type, generic=std_generic) def __init__(self, p=2, basis='milnor', **kwds) -> None: r""" @@ -601,10 +601,11 @@ def __init__(self, p=2, basis='milnor', **kwds) -> None: from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.infinity import Infinity from sage.sets.set_from_iterator import EnumeratedSetFromIterator + profile = kwds.get('profile', None) truncation_type = kwds.get('truncation_type', 'auto') self._generic = kwds.get('generic') - assert (self._generic is True or (p == 2 and self._generic is False)) + assert self._generic is True or (p == 2 and self._generic is False) if not is_prime(p): raise ValueError("%s is not prime" % p) @@ -612,40 +613,24 @@ def __init__(self, p=2, basis='milnor', **kwds) -> None: base_ring = GF(p) self._profile = profile self._truncation_type = truncation_type - if ((not self._generic and profile and profile[0] < Infinity) - or (self._generic and profile != ((), ()) and profile[0] - and profile[0][0] < Infinity) - or (truncation_type < Infinity)): + if (not self._generic and profile and profile[0] < Infinity) or (self._generic and profile != ((), ()) and profile[0] and profile[0][0] < Infinity) or (truncation_type < Infinity): if basis != 'milnor' and basis.find('pst') == -1: raise NotImplementedError("for sub-Hopf algebras of the Steenrod algebra, only the Milnor basis and the pst bases are implemented") self._basis_name = basis basis_category = FiniteEnumeratedSets() if self.is_finite() else InfiniteEnumeratedSets() - basis_set = EnumeratedSetFromIterator(self._basis_key_iterator, - category=basis_category, - name="basis key family of %s" % self, - cache=False) - - self._basis_fcn = partial(steenrod_algebra_basis, - p=p, - basis=basis, - profile=profile, - truncation_type=truncation_type, - generic=self._generic) + basis_set = EnumeratedSetFromIterator(self._basis_key_iterator, category=basis_category, name="basis key family of %s" % self, cache=False) + + self._basis_fcn = partial(steenrod_algebra_basis, p=p, basis=basis, profile=profile, truncation_type=truncation_type, generic=self._generic) cat = SuperHopfAlgebrasWithBasis(base_ring).Supercocommutative() - CombinatorialFreeModule.__init__(self, - base_ring, - basis_set, - prefix=self._basis_name, - element_class=self.Element, - category=cat, - scalar_mult=' ') + CombinatorialFreeModule.__init__(self, base_ring, basis_set, prefix=self._basis_name, element_class=self.Element, category=cat, scalar_mult=' ') # For the graded modules from sage.modules.fp_graded.steenrod.module import ( SteenrodFPModule, SteenrodFreeModule, ) + self._fp_graded_module_class = SteenrodFPModule self._free_graded_module_class = SteenrodFreeModule @@ -676,16 +661,13 @@ def _basis_key_iterator(self): from sage.rings.infinity import Infinity from sage.rings.integer import Integer from sage.sets.integer_range import IntegerRange + if self.is_finite(): maxdim = self.top_class().degree() Ir = IntegerRange(Integer(0), Integer(maxdim + 1)) else: Ir = IntegerRange(Integer(0), Infinity) - basfnc = partial(steenrod_algebra_basis, - p=self.prime(), - basis=self._basis_name, - profile=self._profile, - truncation_type=self._truncation_type) + basfnc = partial(steenrod_algebra_basis, p=self.prime(), basis=self._basis_name, profile=self._profile, truncation_type=self._truncation_type) return itertools.chain.from_iterable(basfnc(dim) for dim in Ir) def prime(self): @@ -743,15 +725,12 @@ def _has_nontrivial_profile(self) -> bool: True """ from sage.rings.infinity import Infinity + profile = self._profile trunc = self._truncation_type if not self._generic: - return ((profile and profile[0] < Infinity) - or (trunc < Infinity)) - return ((profile != ((), ()) and - ((profile[0] and profile[0][0] < Infinity) - or (profile[1] and min(profile[1]) == 1))) - or (trunc < Infinity)) + return (profile and profile[0] < Infinity) or (trunc < Infinity) + return (profile != ((), ()) and ((profile[0] and profile[0][0] < Infinity) or (profile[1] and min(profile[1]) == 1))) or (trunc < Infinity) def _repr_(self) -> str: r""" @@ -776,6 +755,7 @@ def _repr_(self) -> str: sage: SteenrodAlgebra(p=5, profile=(lambda n: 4, lambda n: 1)) sub-Hopf algebra of mod 5 Steenrod algebra, milnor basis, profile function ([4, 4, 4, ..., 4, 4, +Infinity, +Infinity, +Infinity, ...], [1, 1, 1, ..., 1, 1, 2, 2, ...]) """ + def abridge_list(li): """ String rep for list ``li`` if ``li`` is short enough; @@ -787,6 +767,7 @@ def abridge_list(li): return str(li[:3]).rstrip("]") + ", ..., " + str(li[-2:]).lstrip("[") from sage.rings.infinity import Infinity + profile = self._profile trunc = self._truncation_type p = self.prime() @@ -890,6 +871,7 @@ def _repr_term(self, t) -> str: wall_mono_to_string, wood_mono_to_string, ) + p = self.prime() basis = self.basis_name() if basis == 'milnor': @@ -955,6 +937,7 @@ def _latex_term(self, t) -> str: P^{1}_{3} """ import re + s = self._repr_term(t) s = re.sub(r"\^([0-9]*)", r"^{\1}", s) s = re.sub("_([0-9,]*)", r"_{\1}", s) @@ -1029,7 +1012,7 @@ def profile(self, i, component=0): if i <= 0: return 0 try: - return t[i-1] + return t[i - 1] except IndexError: return self._truncation_type else: @@ -1107,10 +1090,9 @@ def homogeneous_component(self, n): 0 """ from sage.rings.finite_rings.finite_field_constructor import GF + basis = self._basis_fcn(n) - M = CombinatorialFreeModule(GF(self.prime()), basis, - element_class=self.Element, - prefix=self._basis_name) + M = CombinatorialFreeModule(GF(self.prime()), basis, element_class=self.Element, prefix=self._basis_name) M._name = "Vector space spanned by %s" % (tuple(self.monomial(a) for a in basis),) return M @@ -1205,17 +1187,20 @@ def product_on_basis(self, t1, t2): from sage.algebras.steenrod.steenrod_algebra_mult import ( milnor_multiplication, ) + d = milnor_multiplication(t1, t2) else: from sage.algebras.steenrod.steenrod_algebra_mult import ( milnor_multiplication_odd, ) + d = milnor_multiplication_odd(t1, t2, p) return self._from_dict(d, coerce=True) if basis == 'serre-cartan': from sage.algebras.steenrod.steenrod_algebra_mult import ( make_mono_admissible, ) + if self._generic: # make sure output has an odd number of terms. if both t1 # and t2 have an odd number, concatenate them, adding the @@ -1291,6 +1276,7 @@ def coproduct_on_basis(self, t, algorithm=None): sage: all(A7.coproduct_on_basis((0,n,1), algorithm='milnor') == A7.coproduct_on_basis((0,n,1), algorithm='adem') for n in range(9)) # long time True """ + def coprod_list(t): """ If t = (n0, n1, ...), then return list of terms (i0, i1, @@ -1307,6 +1293,7 @@ def coprod_list(t): return ans from sage.algebras.steenrod.steenrod_algebra_misc import get_basis_name + p = self.prime() basis = self.basis_name() if algorithm is None: @@ -1342,6 +1329,7 @@ def coprod_list(t): ) from sage.combinat.permutation import Permutation from sage.sets.set import Set + left_p = coprod_list(t[1]) right_p = [[x - y for x, y in zip(t[1], m)] for m in left_p] old = list(left_p) @@ -1364,9 +1352,7 @@ def coprod_list(t): right_q = sorted(all_q - a) sign = Permutation(convert_perm(left_q + right_q)).signature() tens_q[(tuple(left_q), tuple(right_q))] = sign - tens = {((q[0], lp), (q[1], rp)): tq - for lp, rp in zip(left_p, right_p) - for q, tq in tens_q.items()} + tens = {((q[0], lp), (q[1], rp)): tq for lp, rp in zip(left_p, right_p) for q, tq in tens_q.items()} return self.tensor_square()._from_dict(tens, coerce=True) if basis == 'serre-cartan': result = self.tensor_square().one() @@ -1374,7 +1360,7 @@ def coprod_list(t): for n in t: s = self.tensor_square().zero() for i in range(n + 1): - s += tensor((self.Sq(i), self.Sq(n-i))) + s += tensor((self.Sq(i), self.Sq(n - i))) result = result * s return result bockstein = True @@ -1388,7 +1374,7 @@ def coprod_list(t): else: s = self.tensor_square().zero() for i in range(n + 1): - s += tensor((self.P(i), self.P(n-i))) + s += tensor((self.P(i), self.P(n - i))) bockstein = True result = result * s return result @@ -1397,9 +1383,7 @@ def coprod_list(t): x = A(self._change_basis_on_basis(t, algorithm)).coproduct(algorithm=algorithm) result = [] for (a, b), coeff in x: - result.append((tensor((A._change_basis_on_basis(a, basis), - A._change_basis_on_basis(b, basis))), - coeff)) + result.append((tensor((A._change_basis_on_basis(a, basis), A._change_basis_on_basis(b, basis))), coeff)) return self.tensor_square().linear_combination(result) def coproduct(self, x, algorithm='milnor'): @@ -1446,8 +1430,8 @@ def coproduct(self, x, algorithm='milnor'): def coprod(x): return self.coproduct_on_basis(x, algorithm) - return Hom(self, tensor([self, self]), - ModulesWithBasis(self.base_ring()))(on_basis=coprod)(x) + + return Hom(self, tensor([self, self]), ModulesWithBasis(self.base_ring()))(on_basis=coprod)(x) def antipode_on_basis(self, t): r""" @@ -1526,17 +1510,18 @@ def antipode_on_basis(self, t): antipode = self(sum(SteenrodAlgebra().basis(n))) * antipode else: from sage.misc.functional import is_even + for index, n in enumerate(t): if is_even(index): if n != 0: - antipode = -self.Q(0) * antipode * (-1)**antipode.degree() + antipode = -self.Q(0) * antipode * (-1) ** antipode.degree() else: - B = SteenrodAlgebra(p=p, generic=self._generic).basis(n * 2 * (p-1)) + B = SteenrodAlgebra(p=p, generic=self._generic).basis(n * 2 * (p - 1)) s = self(0) for b in B: if len(b.leading_support()[0]) == 0: s += self(b) - antipode = (-1)**n * s * antipode + antipode = (-1) ** n * s * antipode return antipode return self(self._change_basis_on_basis(t, 'serre-cartan').antipode()) @@ -1660,7 +1645,7 @@ def _milnor_on_basis(self, t): # each entry in t is a pair (m,k), corresponding to w(m,k), defined by # `w(m,k) = \text{Sq}^{2^m (2^{k+1}-1)}`. for m, k in t: - ans = ans * A.Sq(2**m * (2**(k+1) - 1)) + ans = ans * A.Sq(2**m * (2 ** (k + 1) - 1)) # wall[_long] elif basis.find('wall') >= 0: @@ -1669,7 +1654,7 @@ def _milnor_on_basis(self, t): for m, k in t: exponent = 2**k ans = ans * A.Sq(exponent) - for i in range(m-k): + for i in range(m - k): exponent = exponent * 2 ans = ans * A.Sq(exponent) @@ -1686,7 +1671,7 @@ def _milnor_on_basis(self, t): if t[0]: ans = ans * A.Q(*t[0]) for (i, j), n in t[1]: - ans = ans * (A.pst(i, j))**n + ans = ans * (A.pst(i, j)) ** n # arnona[_long] elif basis.find('arnona') >= 0: @@ -1695,7 +1680,7 @@ def _milnor_on_basis(self, t): for m, k in t: exponent = 2**k X = A.Sq(exponent) - for i in range(m-k): + for i in range(m - k): exponent = exponent * 2 X = A.Sq(exponent) * X ans = ans * X @@ -1708,8 +1693,8 @@ def _milnor_on_basis(self, t): # = Sq(2^i) and c_{i,j} = [c_{i,j-1}, Sq(2^{i+j-1})]. for i, j in t: comm = A.Sq(2**i) - for k in range(2, j+1): - y = A.Sq(2**(i+k-1)) + for k in range(2, j + 1): + y = A.Sq(2 ** (i + k - 1)) comm = comm * y + y * comm ans = ans * comm else: @@ -1722,8 +1707,8 @@ def _milnor_on_basis(self, t): ans = ans * A.Q(*t[0]) for (i, j), n in t[1]: comm = A.P(p**i) - for k in range(2, j+1): - y = A.P(p**(i+k-1)) + for k in range(2, j + 1): + y = A.P(p ** (i + k - 1)) comm = y * comm - comm * y ans = ans * comm**n return ans @@ -1815,6 +1800,7 @@ def _change_basis_on_basis(self, t, basis='milnor'): from sage.algebras.steenrod.steenrod_algebra_misc import get_basis_name from sage.matrix.constructor import matrix from sage.rings.finite_rings.finite_field_constructor import GF + basis = get_basis_name(basis, self.prime(), generic=self._generic) if basis == self.basis_name(): return self({t: 1}) @@ -1830,8 +1816,7 @@ def _change_basis_on_basis(self, t, basis='milnor'): Bnew = steenrod_algebra_basis(deg, basis, p, generic=self._generic) Bmil = steenrod_algebra_basis(deg, 'milnor', p, generic=self._generic) v = [d.get(a, 0) for a in Bmil] - out = (matrix(GF(p), 1, len(v), v) * - convert_from_milnor_matrix(deg, basis, p, generic=self._generic)) + out = matrix(GF(p), 1, len(v), v) * convert_from_milnor_matrix(deg, basis, p, generic=self._generic) new_d = dict(zip(Bnew, out[0])) return A(new_d) @@ -1868,6 +1853,7 @@ def _change_basis(self, x, basis='milnor'): def change(y): return self._change_basis_on_basis(y, basis) + f = self._module_morphism(change, codomain=A) return f(x) @@ -1918,6 +1904,7 @@ def degree_on_basis(self, t): sage: A11.degree_on_basis(((2,), ())) 241 """ + def p_degree(m, mult=1, prime=2): """ For m=(n_1, n_2, n_3, ...), Sum_i (mult) * n_i * (p^i - 1) @@ -1926,7 +1913,7 @@ def p_degree(m, mult=1, prime=2): deg = 0 for n in m: i += 1 - deg += n*mult*(prime**i - 1) + deg += n * mult * (prime**i - 1) return deg def q_degree(m, prime=3): @@ -1935,7 +1922,7 @@ def q_degree(m, prime=3): """ deg = 0 for n in m: - deg += 2*prime**n - 1 + deg += 2 * prime**n - 1 return deg p = self.prime() @@ -1965,7 +1952,7 @@ def q_degree(m, prime=3): if basis == 'woody' or basis == 'woodz': # each entry in t is a pair (m,k), corresponding to w(m,k), defined by # `w(m,k) = \text{Sq}^{2^m (2^{k+1}-1)}`. - return sum(2**m * (2**(k+1)-1) for m, k in t) + return sum(2**m * (2 ** (k + 1) - 1) for m, k in t) # wall, arnon_a if basis.find('wall') >= 0 or basis.find('arnona') >= 0: @@ -1976,7 +1963,7 @@ def q_degree(m, prime=3): # Arnon A: each entry in t is a pair (m,k), corresponding # to X^m_k, defined by `X^m_k = Sq(2^m) ... Sq(2^{k+1}) # Sq(2^k)` - return sum(2**k * (2**(m-k+1)-1) for m, k in t) + return sum(2**k * (2 ** (m - k + 1) - 1) for m, k in t) # pst, comm if basis.find('pst') >= 0 or basis.find('comm') >= 0: @@ -2069,25 +2056,22 @@ def _coerce_map_from_(self, S): from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.infinity import Infinity from sage.rings.integer_ring import ZZ + p = self.prime() if S == ZZ or S == GF(p): return True - if (isinstance(S, SteenrodAlgebra_generic) and p == S.prime() and self._generic == S._generic): + if isinstance(S, SteenrodAlgebra_generic) and p == S.prime() and self._generic == S._generic: # deal with profiles. if not self._generic: self_prec = len(self._profile) S_prec = len(S._profile) - return all(self.profile(i) >= S.profile(i) - for i in range(1, max(self_prec, S_prec)+1)) + return all(self.profile(i) >= S.profile(i) for i in range(1, max(self_prec, S_prec) + 1)) self_prec = len(self._profile[0]) S_prec = len(S._profile[0]) - return (all(self.profile(i) >= S.profile(i) - for i in range(1, max(self_prec, S_prec)+1)) - and all(self.profile(i, 1) >= S.profile(i, 1) - for i in range(1, max(self_prec, S_prec)+1))) - if (isinstance(S, CombinatorialFreeModule) - and S.dimension() < Infinity and p == S.base_ring().characteristic()): + return all(self.profile(i) >= S.profile(i) for i in range(1, max(self_prec, S_prec) + 1)) and all(self.profile(i, 1) >= S.profile(i, 1) for i in range(1, max(self_prec, S_prec) + 1)) + if isinstance(S, CombinatorialFreeModule) and S.dimension() < Infinity and p == S.base_ring().characteristic(): from sage.algebras.steenrod.steenrod_algebra_misc import get_basis_name + try: get_basis_name(S.prefix(), S.base_ring().characteristic()) # return all(a in self for a in S.basis()) @@ -2131,6 +2115,7 @@ def _element_constructor_(self, x): """ from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.integer_ring import ZZ + if x in GF(self.prime()) or x in ZZ: return self.from_base_ring_from_one_basis(x) @@ -2182,20 +2167,19 @@ def __contains__(self, x) -> bool: False """ from sage.rings.finite_rings.finite_field_constructor import GF + p = self.prime() if x in GF(p): return True - if (isinstance(x, self.Element) and x.prime() == p): + if isinstance(x, self.Element) and x.prime() == p: try: if x.parent()._generic != self._generic: return False except AttributeError: pass - A = SteenrodAlgebra(p=p, basis=self.basis_name(), - generic=self._generic) + A = SteenrodAlgebra(p=p, basis=self.basis_name(), generic=self._generic) if self._has_nontrivial_profile(): - return all(self._check_profile_on_basis(mono) - for mono in A(x).support()) + return all(self._check_profile_on_basis(mono) for mono in A(x).support()) return True # trivial profile, so True return False @@ -2270,6 +2254,7 @@ def basis(self, d=None): Q_0 Q_1 P(1), Q_0 Q_1 P(2), Q_1, Q_1 P(1), Q_1 P(2)] """ from sage.sets.family import Family + if d is None: return Family(self._indices, self.monomial) return Family([self.monomial(tuple(a)) for a in self._basis_fcn(d)]) @@ -2299,27 +2284,20 @@ def _check_profile_on_basis(self, t): False """ if self.basis_name() != 'milnor': - A = SteenrodAlgebra(p=self.prime(), - profile=self._profile, - truncation_type=self._truncation_type, - generic=self._generic) - return all(A._check_profile_on_basis(a[0]) - for a in self._milnor_on_basis(t)) + A = SteenrodAlgebra(p=self.prime(), profile=self._profile, truncation_type=self._truncation_type, generic=self._generic) + return all(A._check_profile_on_basis(a[0]) for a in self._milnor_on_basis(t)) from sage.rings.infinity import Infinity + p = self.prime() if not self._has_nontrivial_profile(): return True if not self._generic: - return all(self.profile(i+1) == Infinity - or t[i] < 2**self.profile(i+1) - for i in range(len(t))) + return all(self.profile(i + 1) == Infinity or t[i] < 2 ** self.profile(i + 1) for i in range(len(t))) # p odd: if any(self.profile(i, 1) != 2 for i in t[0]): return False - return all(self.profile(i + 1, 0) == Infinity - or t[1][i] < p**self.profile(i + 1, 0) - for i in range(len(t[1]))) + return all(self.profile(i + 1, 0) == Infinity or t[1][i] < p ** self.profile(i + 1, 0) for i in range(len(t[1]))) def P(self, *nums): r""" @@ -2356,9 +2334,9 @@ def P(self, *nums): P(2,0,1) """ from sage.rings.integer import Integer + if self.basis_name() != 'milnor': - return self(SteenrodAlgebra(p=self.prime(), - generic=self._generic).P(*nums)) + return self(SteenrodAlgebra(p=self.prime(), generic=self._generic).P(*nums)) while nums and nums[-1] == 0: nums = nums[:-1] if len(nums) == 0 or (len(nums) == 1 and nums[0] == 0): @@ -2374,8 +2352,7 @@ def P(self, *nums): else: t = ((), nums) if self._check_profile_on_basis(t): - A = SteenrodAlgebra_generic(p=self.prime(), - generic=self._generic) + A = SteenrodAlgebra_generic(p=self.prime(), generic=self._generic) a = A.monomial(t) return self(a) raise ValueError("element not in this algebra") @@ -2415,12 +2392,10 @@ def Q_exp(self, *nums): Q_0 Q_2 """ if not all(x in (0, 1) for x in nums): - raise ValueError("the tuple %s should consist " % (nums,) + - "only of 0s and 1s") + raise ValueError("the tuple %s should consist " % (nums,) + "only of 0s and 1s") if self.basis_name() != 'milnor': - return self(SteenrodAlgebra(p=self.prime(), - generic=self._generic).Q_exp(*nums)) + return self(SteenrodAlgebra(p=self.prime(), generic=self._generic).Q_exp(*nums)) lnums = list(nums) while lnums[-1] == 0: @@ -2471,12 +2446,11 @@ def Q(self, *nums): if len(nums) != len(set(nums)): return self(0) if self.basis_name() != 'milnor': - return self(SteenrodAlgebra(p=self.prime(), - generic=self._generic).Q(*nums)) + return self(SteenrodAlgebra(p=self.prime(), generic=self._generic).Q(*nums)) if not self._generic: if len(nums) == 0: return self.one() - list = (1+max(nums)) * [0] + list = (1 + max(nums)) * [0] for i in nums: list[i] = 1 return self.Sq(*tuple(list)) @@ -2511,6 +2485,7 @@ def _an_element_(self): P^0_1 """ from sage.rings.finite_rings.finite_field_constructor import GF + basis = self.basis_name() p = self.prime() @@ -2528,14 +2503,11 @@ def _an_element_(self): if basis == 'serre-cartan' and self._generic: return self.term((1, p, 0, 1, 0), GF(p)(p - 1)) if basis == 'woody' or basis == 'woodz': - return self._from_dict({((3, 0),): 1, - ((1, 1), (1, 0)): 1}, coerce=True) + return self._from_dict({((3, 0),): 1, ((1, 1), (1, 0)): 1}, coerce=True) if basis.find('wall') >= 0: - return self._from_dict({((1, 1), (1, 0)): 1, - ((2, 2), (0, 0)): 1}, coerce=True) + return self._from_dict({((1, 1), (1, 0)): 1, ((2, 2), (0, 0)): 1}, coerce=True) if basis.find('arnona') >= 0: - return self._from_dict({((3, 3),): 1, - ((1, 1), (2, 1)): 1}, coerce=True) + return self._from_dict({((3, 3),): 1, ((1, 1), (2, 1)): 1}, coerce=True) if basis == 'arnonc': return self._from_dict({(8,): 1, (4, 4): 1}, coerce=True) if basis.find('pst') >= 0: @@ -2577,14 +2549,14 @@ def pst(self, s, t): P(0,0,0,0,125) """ from sage.rings.integer import Integer + if self.basis_name() != 'milnor': - return self(SteenrodAlgebra(p=self.prime(), - generic=self._generic).pst(s, t)) + return self(SteenrodAlgebra(p=self.prime(), generic=self._generic).pst(s, t)) if not isinstance(s, (Integer, int)) and s >= 0: raise ValueError("%s is not a nonnegative integer" % s) if not isinstance(t, (Integer, int)) and t > 0: raise ValueError("%s is not a positive integer" % t) - nums = (0,)*(t-1) + (self.prime()**s,) + nums = (0,) * (t - 1) + (self.prime() ** s,) return self.P(*nums) def ngens(self): @@ -2623,14 +2595,15 @@ def ngens(self): 5 """ from sage.rings.infinity import Infinity + if self._truncation_type == Infinity: return Infinity n = self.profile(1) p = self.prime() - if not self._generic and self._profile == AA(n-1, p=p)._profile: + if not self._generic and self._profile == AA(n - 1, p=p)._profile: return n if self._generic and self._profile == AA(n, p=p)._profile: - return n+1 + return n + 1 if not self._generic: return sum(self._profile) return sum(self._profile[0]) + len([a for a in self._profile[1] if a == 2]) @@ -2694,6 +2667,7 @@ def gens(self) -> Family: """ from sage.rings.infinity import Infinity from sage.sets.non_negative_integers import NonNegativeIntegers + n = self.ngens() if n < Infinity: return Family([self.gen(i) for i in range(n)]) @@ -2769,6 +2743,7 @@ def gen(self, i=0): """ from sage.rings.infinity import Infinity from sage.rings.integer import Integer + p = self.prime() if not isinstance(i, (Integer, int)) and i >= 0: raise ValueError("%s is not a nonnegative integer" % i) @@ -2778,12 +2753,12 @@ def gen(self, i=0): raise ValueError("this algebra only has %s generators, so call gen(i) with 0 <= i < %s" % (num, num)) # check to see if equal to A(n) for some n. n = self.profile(1) - if not self._generic and self._profile == AA(n-1, p=p)._profile: + if not self._generic and self._profile == AA(n - 1, p=p)._profile: return self.pst(i, 1) if self._generic and self._profile == AA(n, p=p)._profile: if i == 0: return self.Q(0) - return self.pst(i-1, 1) + return self.pst(i - 1, 1) # if not A(n), return list of P^s_t's in algebra, along with Q's if p is odd idx = -1 if not self._generic: @@ -2792,8 +2767,8 @@ def gen(self, i=0): last_t = max(len(self._profile[0]), len(self._profile[1])) last_s = self.profile(last_t) for j in range(1, last_s + last_t + 1): - if self._generic and self.profile(j-1, 1) == 2: - guess = self.Q(j-1) + if self._generic and self.profile(j - 1, 1) == 2: + guess = self.Q(j - 1) idx += 1 if idx == i: elt = guess @@ -2815,7 +2790,7 @@ def gen(self, i=0): if self.profile(0, 1) == 2: if i == 0: return self.Q(0) - return self.P(p**(i-1)) + return self.P(p ** (i - 1)) # infinite-dimensional sub-Hopf algebra idx = -1 @@ -2824,12 +2799,12 @@ def gen(self, i=0): A = SteenrodAlgebra(p=p, generic=self._generic) while not found: if self._generic: - test = A.Q(tot-1) + test = A.Q(tot - 1) if test in self: idx += 1 if idx == i: break - for t in range(1, tot+1): + for t in range(1, tot + 1): s = tot - t test = A.pst(s, t) if test in self: @@ -2891,8 +2866,7 @@ def is_commutative(self) -> bool: n = max(self._profile) return all(self.profile(i) == 0 for i in range(1, n)) n = max(self._profile[0]) - return (all(self.profile(i, 0) == 0 for i in range(1, n)) - and all(self.profile(i, 1) == 1 for i in range(n))) + return all(self.profile(i, 0) == 0 for i in range(1, n)) and all(self.profile(i, 1) == 1 for i in range(n)) def is_finite(self) -> bool: r""" @@ -2937,12 +2911,13 @@ def dimension(self): 20 """ from sage.rings.infinity import Infinity + if not self.is_finite(): return Infinity p = self.prime() if not self._generic: - return 2**sum(self._profile) - return p**sum(self._profile[0]) * 2**len([a for a in self._profile[1] if a == 2]) + return 2 ** sum(self._profile) + return p ** sum(self._profile[0]) * 2 ** len([a for a in self._profile[1] if a == 2]) @cached_method def top_class(self): @@ -2991,7 +2966,7 @@ def top_class(self): else: rp, ep = self._profile e = [kk for kk in range(len(ep)) if ep[kk] == 2] - r = [p**kk-1 for kk in rp] + r = [p**kk - 1 for kk in rp] ans = AM.monomial((tuple(e), tuple(r))) return self(ans.change_basis(self.basis_name())) @@ -3020,6 +2995,7 @@ def order(self): True """ from sage.rings.infinity import Infinity + if not self.is_finite(): return Infinity return self.prime() ** self.dimension() @@ -3143,6 +3119,7 @@ class Element(CombinatorialFreeModule.Element): ``sage.algebras.steenrod.steenrod_algebra?``) for more information about elements of the Steenrod algebra. """ + def prime(self): """ The prime associated to ``self``. @@ -3509,6 +3486,7 @@ def excess(self): sage: (a * b).excess() 17 """ + def excess_odd(mono): """ Excess of mono, where mono has the form @@ -3624,6 +3602,7 @@ def may_weight(self): """ from sage.rings.infinity import Infinity from sage.rings.integer import Integer + p = self.prime() generic = self.parent()._generic if self == 0: @@ -3732,6 +3711,7 @@ def wall_height(self): [1, 2, 2, 1] """ from sage.rings.integer import Integer + if self.parent()._generic: raise NotImplementedError("Wall height is not defined at odd primes") if self == 0 or self == 1: @@ -3739,13 +3719,13 @@ def wall_height(self): result = [] deg = self.parent().degree_on_basis for r in self.milnor().support(): - h = [0]*(1 + deg(r)) + h = [0] * (1 + deg(r)) i = 1 for x in r: if x > 0: - for j in range(1+Integer(x).exact_log(2)): + for j in range(1 + Integer(x).exact_log(2)): if (2**j & x) != 0: - for k in range(j, i+j): + for k in range(j, i + j): h[k] += 1 i += 1 h.reverse() @@ -3784,6 +3764,7 @@ class SteenrodAlgebra_mod_two(SteenrodAlgebra_generic): documentation. (This differs from :class:`SteenrodAlgebra_generic` only in that it has a method :meth:`Sq` for defining elements.) """ + def Sq(self, *nums): r""" Milnor element `\text{Sq}(a,b,c,...)`. @@ -4228,7 +4209,7 @@ def AA(n=None, p=2): return SteenrodAlgebra(p=p) if p == 2: return SteenrodAlgebra(p=p, profile=list(range(n + 1, 0, -1))) - return SteenrodAlgebra(p=p, profile=(list(range(n, 0, -1)), [2]*(n+1))) + return SteenrodAlgebra(p=p, profile=(list(range(n, 0, -1)), [2] * (n + 1))) def Sq(*nums): diff --git a/src/sage/algebras/steenrod/steenrod_algebra_bases.py b/src/sage/algebras/steenrod/steenrod_algebra_bases.py index afcbfd9ede0..122aedcf0aa 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra_bases.py +++ b/src/sage/algebras/steenrod/steenrod_algebra_bases.py @@ -166,6 +166,7 @@ def convert_to_milnor_matrix(n, basis, p=2, generic='auto'): from sage.algebras.steenrod.steenrod_algebra import SteenrodAlgebra from sage.matrix.constructor import matrix from sage.rings.finite_rings.finite_field_constructor import GF + if generic == 'auto': generic = p != 2 if n == 0: @@ -333,6 +334,7 @@ def steenrod_algebra_basis(n, basis='milnor', p=2, **kwds): (((0, 1), (2, 1)), ((1, 1), (0, 2))) """ from sage.algebras.steenrod.steenrod_algebra_misc import get_basis_name + try: if n < 0 or int(n) != n: return () @@ -346,8 +348,7 @@ def steenrod_algebra_basis(n, basis='milnor', p=2, **kwds): basis_name = basis_name.rsplit('_', 1)[0] profile = kwds.get("profile", None) - if (profile is not None and profile != () and profile != ((), ()) - and basis != 'milnor' and basis.find('pst') == -1): + if profile is not None and profile != () and profile != ((), ()) and basis != 'milnor' and basis.find('pst') == -1: raise ValueError("profile functions may only be used with the Milnor or pst bases") # Milnor basis @@ -357,14 +358,10 @@ def steenrod_algebra_basis(n, basis='milnor', p=2, **kwds): if basis_name == 'serre-cartan': return serre_cartan_basis(n, p, **kwds) # Atomic bases, p odd: - if generic and (basis_name.find('pst') >= 0 - or basis_name.find('comm') >= 0): + if generic and (basis_name.find('pst') >= 0 or basis_name.find('comm') >= 0): return atomic_basis_odd(n, basis_name, p, **kwds) # Atomic bases, p=2 - if not generic and (basis_name == 'woody' or basis_name == 'woodz' - or basis_name == 'wall' or basis_name == 'arnona' - or basis_name.find('pst') >= 0 - or basis_name.find('comm') >= 0): + if not generic and (basis_name == 'woody' or basis_name == 'woodz' or basis_name == 'wall' or basis_name == 'arnona' or basis_name.find('pst') >= 0 or basis_name.find('comm') >= 0): return atomic_basis(n, basis_name, **kwds) # Arnon 'C' basis if not generic and basis == 'arnonc': @@ -374,6 +371,7 @@ def steenrod_algebra_basis(n, basis='milnor', p=2, **kwds): # helper functions for producing bases + def restricted_partitions(n, l, no_repeats=False): """ Iterator over 'restricted' partitions of `n`: partitions with parts taken @@ -484,10 +482,11 @@ def xi_degrees(n, p=2, reverse=True): [307, 18, 1] """ from sage.rings.integer import Integer + if n <= 0: return [] - N = Integer(n*(p-1) + 1) - l = [(p**d-1)//(p-1) for d in range(1, N.exact_log(p)+1)] + N = Integer(n * (p - 1) + 1) + l = [(p**d - 1) // (p - 1) for d in range(1, N.exact_log(p) + 1)] if reverse: l.reverse() return l @@ -503,6 +502,7 @@ def xi_degrees(n, p=2, reverse=True): # the pair ((i, j, ...), (a, b, ...)). See each function for more # information. + def milnor_basis(n, p=2, **kwds): r""" Milnor basis in dimension `n` with profile function ``profile``. @@ -577,6 +577,7 @@ def milnor_basis(n, p=2, **kwds): from sage.combinat.integer_vector_weighted import WeightedIntegerVectors from sage.rings.infinity import Infinity + profile = kwds.get("profile", None) trunc = kwds.get("truncation_type", None) if trunc is None: @@ -595,21 +596,19 @@ def milnor_basis(n, p=2, **kwds): okay = True if profile is not None and len(profile) > 0: for i in range(len(exponents)): - if ((len(profile) > i and exponents[i] >= 2**profile[i]) - or (len(profile) <= i and trunc < Infinity - and exponents[i] >= 2**trunc)): + if (len(profile) > i and exponents[i] >= 2 ** profile[i]) or (len(profile) <= i and trunc < Infinity and exponents[i] >= 2**trunc): okay = False break else: # profile is empty - okay = (trunc == Infinity) + okay = trunc == Infinity if okay: result.append(tuple(exponents)) else: # p odd # first find the P part of each basis element. # in this part of the code (the P part), all dimensions are # divided by 2(p-1). - for dim in range(n//(2*(p-1)) + 1): + for dim in range(n // (2 * (p - 1)) + 1): if dim == 0: P_result = [[0]] else: @@ -623,17 +622,14 @@ def milnor_basis(n, p=2, **kwds): # now find the Q part of the basis element. # dimensions here are back to normal. for p_mono in P_result: - deg = n - 2*dim*(p-1) - q_degrees = [1+2*(p-1)*d for d in - xi_degrees(int((deg - 1)//(2*(p-1))), p)] + [1] + deg = n - 2 * dim * (p - 1) + q_degrees = [1 + 2 * (p - 1) * d for d in xi_degrees(int((deg - 1) // (2 * (p - 1))), p)] + [1] q_degrees_decrease = q_degrees q_degrees.reverse() - if deg % (2*(p-1)) <= len(q_degrees): + if deg % (2 * (p - 1)) <= len(q_degrees): # if this inequality fails, no way to have a partition # with distinct parts. - for sigma in restricted_partitions(deg, - q_degrees_decrease, - no_repeats=True): + for sigma in restricted_partitions(deg, q_degrees_decrease, no_repeats=True): index = 0 q_mono = [] for q in q_degrees: @@ -642,24 +638,20 @@ def milnor_basis(n, p=2, **kwds): index += 1 # check profile: okay = True - if profile is not None and (len(profile[0]) > 0 - or len(profile[1]) > 0): + if profile is not None and (len(profile[0]) > 0 or len(profile[1]) > 0): # check profile function for q_mono for i in q_mono: - if ((len(profile[1]) > i and profile[1][i] == 1) - or (len(profile[1]) <= i and trunc == 0)): + if (len(profile[1]) > i and profile[1][i] == 1) or (len(profile[1]) <= i and trunc == 0): okay = False break # check profile function for p_mono for i in range(len(p_mono)): - if okay and ((len(profile[0]) > i and p_mono[i] >= p**profile[0][i]) - or (len(profile[0]) <= i and trunc < Infinity - and p_mono[i] >= p**trunc)): + if okay and ((len(profile[0]) > i and p_mono[i] >= p ** profile[0][i]) or (len(profile[0]) <= i and trunc < Infinity and p_mono[i] >= p**trunc)): okay = False break else: # profile is empty - okay = (trunc == Infinity) + okay = trunc == Infinity if okay: if list(p_mono) == [0]: p_mono = [] @@ -716,30 +708,28 @@ def serre_cartan_basis(n, p=2, bound=1, **kwds): # elements from serre_cartan_basis (n - last, bound=2 * last). # This means that 2 last <= n - last, or 3 last <= n. result = [(n,)] - for last in range(bound, 1+n//3): + for last in range(bound, 1 + n // 3): for vec in serre_cartan_basis(n - last, bound=2 * last): new = vec + (last,) result.append(new) else: # p odd - if n % (2 * (p-1)) == 0 and n//(2 * (p-1)) >= bound: - result = [(0, int(n//(2 * (p-1))), 0)] + if n % (2 * (p - 1)) == 0 and n // (2 * (p - 1)) >= bound: + result = [(0, int(n // (2 * (p - 1))), 0)] elif n == 1: result = [(1,)] else: result = [] # 2 cases: append P^{last}, or append P^{last} beta # case 1: append P^{last} - for last in range(bound, 1+n//(2*(p - 1))): - if n - 2*(p-1)*last > 0: - for vec in serre_cartan_basis(n - 2*(p-1)*last, - p, p*last, generic=generic): + for last in range(bound, 1 + n // (2 * (p - 1))): + if n - 2 * (p - 1) * last > 0: + for vec in serre_cartan_basis(n - 2 * (p - 1) * last, p, p * last, generic=generic): result.append(vec + (last, 0)) # case 2: append P^{last} beta if bound == 1: bound = 0 - for last in range(bound+1, 1+n//(2*(p - 1))): - basis = serre_cartan_basis(n - 2*(p-1)*last - 1, - p, p*last, generic=generic) + for last in range(bound + 1, 1 + n // (2 * (p - 1))): + basis = serre_cartan_basis(n - 2 * (p - 1) * last - 1, p, p * last, generic=generic) for vec in basis: if vec == (): vec = (0,) @@ -827,6 +817,7 @@ def atomic_basis(n, basis, **kwds): sage: atomic_basis(7,'comm_revz') (((0, 1), (1, 1), (2, 1)), ((0, 1), (1, 2)), ((0, 2), (2, 1)), ((0, 3),)) """ + def degree_dictionary(n, basis): """ Dictionary of atomic degrees for basis up to degree `n`. @@ -841,7 +832,7 @@ def degree_dictionary(n, basis): if basis.find('wood') >= 0: k = 0 m = 0 - deg = 2**m * (2**(k+1) - 1) + deg = 2**m * (2 ** (k + 1) - 1) while deg <= n: dict[deg] = (m, k) if m > 0: @@ -850,11 +841,11 @@ def degree_dictionary(n, basis): else: m = k + 1 k = 0 - deg = 2**m * (2**(k+1) - 1) + deg = 2**m * (2 ** (k + 1) - 1) elif basis.find('wall') >= 0 or basis.find('arnon') >= 0: k = 0 m = 0 - deg = 2**k * (2**(m-k+1) - 1) + deg = 2**k * (2 ** (m - k + 1) - 1) while deg <= n: dict[deg] = (m, k) if k == 0: @@ -862,7 +853,7 @@ def degree_dictionary(n, basis): k = m else: k = k - 1 - deg = 2**k * (2**(m-k+1) - 1) + deg = 2**k * (2 ** (m - k + 1) - 1) elif basis.find('pst') >= 0 or basis.find('comm') >= 0: s = 0 t = 1 @@ -881,22 +872,22 @@ def degree_dictionary(n, basis): deg = 2**s * (2**t - 1) return dict - def sorting_pair(s, t, basis): # pair used for sorting the basis + def sorting_pair(s, t, basis): # pair used for sorting the basis if basis.find('wood') >= 0 and basis.find('z') >= 0: - return (-s-t, -s) - if basis.find('wood') >= 0 or basis.find('wall') >= 0 or \ - basis.find('arnon') >= 0: + return (-s - t, -s) + if basis.find('wood') >= 0 or basis.find('wall') >= 0 or basis.find('arnon') >= 0: return (-s, -t) if basis.find('rlex') >= 0: return (t, s) if basis.find('llex') >= 0: return (s, t) if basis.find('deg') >= 0: - return (s+t, t) + return (s + t, t) if basis.find('revz') >= 0: - return (s+t, s) + return (s + t, s) from sage.rings.infinity import Infinity + profile = kwds.get("profile", None) trunc = kwds.get("truncation_type", None) if profile is not None and trunc is None: @@ -920,8 +911,7 @@ def sorting_pair(s, t, basis): # pair used for sorting the basis if basis.find('pst') >= 0: if profile is not None and len(profile) > 0: for s, t in big_list: - if ((len(profile) > t-1 and profile[t-1] <= s) - or (len(profile) <= t-1 and trunc < Infinity)): + if (len(profile) > t - 1 and profile[t - 1] <= s) or (len(profile) <= t - 1 and trunc < Infinity): okay = False break if okay: @@ -970,9 +960,7 @@ def arnonC_basis(n, bound=1): result = [(n,)] for first in range(bound, 1 + 2 * n // 3): tup = (first,) - result.extend(tup + vec - for vec in arnonC_basis(n - first, max(first // 2, 1)) - if not first % 2**len(vec)) + result.extend(tup + vec for vec in arnonC_basis(n - first, max(first // 2, 1)) if not first % 2 ** len(vec)) return tuple(result) @@ -1022,7 +1010,8 @@ def atomic_basis_odd(n, basis, p, **kwds): sage: atomic_basis_odd(18, 'pst_rlex', 3, profile=((), (2,2,2))) (((0, 2), ()),) """ - def sorting_pair(s, t, basis): # pair used for sorting the basis + + def sorting_pair(s, t, basis): # pair used for sorting the basis if basis.find('rlex') >= 0: return (t, s) if basis.find('llex') >= 0: @@ -1041,47 +1030,42 @@ def sorting_pair(s, t, basis): # pair used for sorting the basis from sage.combinat.integer_vector_weighted import WeightedIntegerVectors from sage.rings.infinity import Infinity from sage.rings.integer import Integer + profile = kwds.get("profile", None) trunc = kwds.get("truncation_type", 0) result = [] - for dim in range(n//(2*p-2) + 1): + for dim in range(n // (2 * p - 2) + 1): P_result = [] for v in WeightedIntegerVectors(dim, xi_degrees(dim, p=p, reverse=False)): mono = [] for t, a in enumerate(v): for s, pow in enumerate(Integer(a).digits(p)): if pow > 0: - mono.append(((s, t+1), pow)) + mono.append(((s, t + 1), pow)) P_result.append(mono) for p_mono in P_result: p_mono.sort(key=lambda x: sorting_pair(x[0][0], x[0][1], basis)) - deg = n - 2*dim*(p-1) - q_degrees = [1+2*(p-1)*d for d in - xi_degrees((deg - 1)//(2*(p-1)), p)] + [1] + deg = n - 2 * dim * (p - 1) + q_degrees = [1 + 2 * (p - 1) * d for d in xi_degrees((deg - 1) // (2 * (p - 1)), p)] + [1] q_degrees_decrease = q_degrees q_degrees.reverse() - if deg % (2*(p-1)) <= len(q_degrees): + if deg % (2 * (p - 1)) <= len(q_degrees): # if this inequality fails, no way to have a partition # with distinct parts. - for sigma in restricted_partitions(deg, - q_degrees_decrease, - no_repeats=True): - q_mono = [index for index, q in enumerate(q_degrees) - if q in sigma] + for sigma in restricted_partitions(deg, q_degrees_decrease, no_repeats=True): + q_mono = [index for index, q in enumerate(q_degrees) if q in sigma] # check profile: okay = True if profile is not None and profile != ((), ()): # check profile function for q_mono for i in q_mono: - if ((len(profile[1]) > i and profile[1][i] == 1) - or (len(profile[1]) <= i and trunc == 0)): + if (len(profile[1]) > i and profile[1][i] == 1) or (len(profile[1]) <= i and trunc == 0): okay = False break for (s, t), _ in p_mono: - if ((len(profile[0]) > t-1 and profile[0][t-1] <= s) - or (len(profile[0]) <= t-1 and trunc < Infinity)): + if (len(profile[0]) > t - 1 and profile[0][t - 1] <= s) or (len(profile[0]) <= t - 1 and trunc < Infinity): okay = False break @@ -1124,25 +1108,20 @@ def steenrod_basis_error_check(dim, p, **kwds): sage: steenrod_basis_error_check(80, 5) """ from sage.misc.verbose import verbose + generic = kwds.get('generic', p != 2) if not generic: - bases = ('adem', 'woody', 'woodz', 'wall', 'arnona', 'arnonc', - 'pst_rlex', 'pst_llex', 'pst_deg', 'pst_revz', - 'comm_rlex', 'comm_llex', 'comm_deg', 'comm_revz') + bases = ('adem', 'woody', 'woodz', 'wall', 'arnona', 'arnonc', 'pst_rlex', 'pst_llex', 'pst_deg', 'pst_revz', 'comm_rlex', 'comm_llex', 'comm_deg', 'comm_revz') else: - bases = ('adem', - 'pst_rlex', 'pst_llex', 'pst_deg', 'pst_revz', - 'comm_rlex', 'comm_llex', 'comm_deg', 'comm_revz') + bases = ('adem', 'pst_rlex', 'pst_llex', 'pst_deg', 'pst_revz', 'comm_rlex', 'comm_llex', 'comm_deg', 'comm_revz') for i in range(dim): if i % 5 == 0: verbose("up to dimension %s" % i) - milnor_dim = len(steenrod_algebra_basis.f(i, 'milnor', p=p, - generic=generic)) + milnor_dim = len(steenrod_algebra_basis.f(i, 'milnor', p=p, generic=generic)) for B in bases: - if milnor_dim != len(steenrod_algebra_basis.f(i, B, p, - generic=generic)): + if milnor_dim != len(steenrod_algebra_basis.f(i, B, p, generic=generic)): print("problem with milnor/{} in dimension {}".format(B, i)) mat = convert_to_milnor_matrix.f(i, B, p, generic=generic) if mat.nrows() != 0 and not mat.is_invertible(): @@ -1160,13 +1139,9 @@ def steenrod_basis_error_check(dim, p, **kwds): if i % 5 == 0: verbose("up to dimension %s" % i) for pro in profiles: - milnor_dim = len(steenrod_algebra_basis.f(i, 'milnor', p=p, - profile=pro, - generic=generic)) + milnor_dim = len(steenrod_algebra_basis.f(i, 'milnor', p=p, profile=pro, generic=generic)) for B in bases: - if milnor_dim != len(steenrod_algebra_basis.f(i, B, p, - profile=pro, - generic=generic)): + if milnor_dim != len(steenrod_algebra_basis.f(i, B, p, profile=pro, generic=generic)): print("problem with milnor/%s in dimension %s with profile %s" % (B, i, pro)) verbose("done checking with profiles") diff --git a/src/sage/algebras/steenrod/steenrod_algebra_misc.py b/src/sage/algebras/steenrod/steenrod_algebra_misc.py index 0f199ee3943..128b4c63805 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra_misc.py +++ b/src/sage/algebras/steenrod/steenrod_algebra_misc.py @@ -40,8 +40,7 @@ # basis names _steenrod_milnor_basis_names = ['milnor'] -_steenrod_serre_cartan_basis_names = ['serre_cartan', 'serre-cartan', 'sc', - 'adem', 'admissible'] +_steenrod_serre_cartan_basis_names = ['serre_cartan', 'serre-cartan', 'sc', 'adem', 'admissible'] def get_basis_name(basis, p, generic=None): @@ -179,6 +178,7 @@ def get_basis_name(basis, p, generic=None): raise ValueError("%s is not a recognized basis%s at the prime %s" % (basis, gencase, p)) return result + ###################################################### # profile functions @@ -254,27 +254,28 @@ def is_valid_profile(profile, truncation_type, p=2, generic=None) -> bool: True """ from sage.rings.infinity import Infinity + if generic is None: generic = p != 2 if not generic: - pro = list(profile) + [truncation_type]*len(profile) + pro = list(profile) + [truncation_type] * len(profile) r = 0 for pro_r in pro: r += 1 # index of pro_r if pro_r < Infinity: for i in range(1, r): - if pro_r < min(pro[r-i-1] - i, pro[i-1]): + if pro_r < min(pro[r - i - 1] - i, pro[i - 1]): return False else: # p odd: - e = list(profile[0]) + [truncation_type]*len(profile[0]) + e = list(profile[0]) + [truncation_type] * len(profile[0]) k = list(profile[1]) if not set(k).issubset({1, 2}): return False if truncation_type > 0: k = k + [2] else: - k = k + [1]*len(profile[0]) + k = k + [1] * len(profile[0]) if len(k) > len(e): e = e + [truncation_type] * (len(k) - len(e)) r = 0 @@ -282,15 +283,15 @@ def is_valid_profile(profile, truncation_type, p=2, generic=None) -> bool: r += 1 # index of e_r if e_r < Infinity: for i in range(1, r): - if e_r < min(e[r-i-1] - i, e[i-1]): + if e_r < min(e[r - i - 1] - i, e[i - 1]): return False r = -1 for k_r in k: r += 1 # index of k_r if k_r == 1: for j in range(r): - i = r-j - if e[i-1] > j and k[j] == 2: + i = r - j + if e[i - 1] > j and k[j] == 2: return False return True @@ -460,6 +461,7 @@ def normalize_profile(profile, precision=None, truncation_type='auto', p=2, gene ValueError: invalid profile """ from sage.rings.infinity import Infinity + if truncation_type == 'zero': truncation_type = 0 if truncation_type == 'infinity': @@ -507,8 +509,7 @@ def normalize_profile(profile, precision=None, truncation_type='auto', p=2, gene new_profile = ((), ()) truncation_type = Infinity else: # profile should be a list or tuple of length 2 - assert isinstance(profile, (list, tuple)) and len(profile) == 2, \ - "Invalid form for profile" + assert isinstance(profile, (list, tuple)) and len(profile) == 2, "Invalid form for profile" e = profile[0] k = profile[1] if isinstance(e, (list, tuple)): @@ -546,7 +547,7 @@ def normalize_profile(profile, precision=None, truncation_type='auto', p=2, gene k_precision = 100 else: k_precision = precision - k = tuple([k(i) for i in range(k_precision-1)]) + k = tuple([k(i) for i in range(k_precision - 1)]) # Remove trailing ones from k if truncation_type is 'zero', # remove trailing twos if truncation_type is 'Infinity'. if truncation_type == 0: @@ -560,6 +561,7 @@ def normalize_profile(profile, precision=None, truncation_type='auto', p=2, gene return new_profile, truncation_type raise ValueError("invalid profile") + ###################################################### # string representations for elements @@ -704,6 +706,7 @@ def serre_cartan_mono_to_string(mono, latex=False, generic=False): index = 0 for n in mono: from sage.misc.functional import is_even + if is_even(index): if n == 1: if latex: @@ -755,7 +758,7 @@ def wood_mono_to_string(mono, latex=False): return "1" string = "" for s, t in mono: - string = string + sq + "^{" + str(2**s * (2**(t+1)-1)) + "} " + string = string + sq + "^{" + str(2**s * (2 ** (t + 1) - 1)) + "} " return string.strip(" ") @@ -968,22 +971,19 @@ def pst_mono_to_string(mono, latex=False, generic=False): string = "" if not generic: for s, t in mono: - string = string + "P^{" + str(s) + "}_{" \ - + str(t) + "} " + string = string + "P^{" + str(s) + "}_{" + str(t) + "} " else: for e in mono[0]: string = string + "Q_{" + str(e) + "} " for (s, t), n in mono[1]: if n == 1: - string = string + "P^{" + str(s) + "}_{" \ - + str(t) + "} " + string = string + "P^{" + str(s) + "}_{" + str(t) + "} " else: if latex: pow = "{%s}" % n else: pow = str(n) - string = string + "(P^{" + str(s) + "}_{" \ - + str(t) + "})^" + pow + " " + string = string + "(P^{" + str(s) + "}_{" + str(t) + "})^" + pow + " " return string.strip(" ") @@ -1031,14 +1031,12 @@ def comm_mono_to_string(mono, latex=False, generic=False): string = "" if not generic: for s, t in mono: - string = string + "c_{" + str(s) + "," \ - + str(t) + "} " + string = string + "c_{" + str(s) + "," + str(t) + "} " else: for e in mono[0]: string = string + "Q_{" + str(e) + "} " for (s, t), n in mono[1]: - string = string + "c_{" + str(s) + "," \ - + str(t) + "}" + string = string + "c_{" + str(s) + "," + str(t) + "}" if n > 1: if latex: pow = "^{%s}" % n @@ -1100,7 +1098,7 @@ def comm_long_mono_to_string(mono, p, latex=False, generic=False): comma = "" string = string + "s_{" for i in range(t): - string = string + str(2**(s+i)) + comma + string = string + str(2 ** (s + i)) + comma string = string.strip(",") + "} " else: for e in mono[0]: @@ -1108,7 +1106,7 @@ def comm_long_mono_to_string(mono, p, latex=False, generic=False): for (s, t), n in mono[1]: string = string + "s_{" for i in range(t): - string = string + str(p**(s+i)) + "," + string = string + str(p ** (s + i)) + "," string = string.strip(",") + "}" if n > 1: if latex: @@ -1119,6 +1117,7 @@ def comm_long_mono_to_string(mono, p, latex=False, generic=False): string = string + " " return string.strip(" ") + # miscellany: diff --git a/src/sage/algebras/steenrod/steenrod_algebra_mult.py b/src/sage/algebras/steenrod/steenrod_algebra_mult.py index b9582bb9b3e..9860ee11b2d 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra_mult.py +++ b/src/sage/algebras/steenrod/steenrod_algebra_mult.py @@ -253,11 +253,11 @@ def milnor_multiplication(r, s): # initialize matrix M = list(range(rows)) for i in range(rows): - M[i] = [0]*cols + M[i] = [0] * cols for j in range(1, cols): - M[0][j] = s[j-1] + M[0][j] = s[j - 1] for i in range(1, rows): - M[i][0] = r[i-1] + M[i][0] = r[i - 1] for j in range(1, cols): M[i][j] = 0 found = True @@ -265,18 +265,17 @@ def milnor_multiplication(r, s): # check diagonals n = 1 okay = 1 - diagonal = [0]*diags + diagonal = [0] * diags while n <= diags and okay is not None: - nth_diagonal = [M[i][n-i] - for i in range(max(0, n-cols+1), min(1+n, rows))] + nth_diagonal = [M[i][n - i] for i in range(max(0, n - cols + 1), min(1 + n, rows))] okay = multinomial(nth_diagonal) - diagonal[n-1] = okay + diagonal[n - 1] = okay n = n + 1 if okay is not None: i = diags - 1 while i >= 0 and diagonal[i] == 0: i = i - 1 - t = tuple(diagonal[:i+1]) + t = tuple(diagonal[: i + 1]) # reduce mod two: if t in result: del result[t] @@ -299,7 +298,7 @@ def milnor_multiplication(r, s): if temp_col_sum != 0: found = True for row in range(1, i): - M[row][0] = r[row-1] + M[row][0] = r[row - 1] for col in range(1, cols): M[0][col] = M[0][col] + M[row][col] M[row][col] = 0 @@ -360,7 +359,7 @@ def multinomial(list): j = 1 while okay and j <= min(old_sum, list[i]): if j & old_sum == j: - okay = (j & list[i] == 0) + okay = j & list[i] == 0 j = j << 1 old_sum = old_sum + list[i] i = i + 1 @@ -368,6 +367,7 @@ def multinomial(list): return old_sum return None + # Milnor, p odd @@ -439,6 +439,7 @@ def milnor_multiplication_odd(m1, m2, p): http://mathweb.scranton.edu/monks/software/Steenrod/steen.html. """ from sage.rings.finite_rings.finite_field_constructor import GF + F = GF(p) f, s = m2 # First compute Q_e0 Q_e1 ... P(r1, r2, ...) Q_f0 Q_f1 ... @@ -451,10 +452,10 @@ def milnor_multiplication_odd(m1, m2, p): if k not in mono[0]: q_mono = set(mono[0]) if q_mono: - ind = len(q_mono.intersection(range(k, 1+max(q_mono)))) + ind = len(q_mono.intersection(range(k, 1 + max(q_mono)))) else: ind = 0 - coeff = (-1)**ind * old_answer[mono] + coeff = (-1) ** ind * old_answer[mono] lst = list(mono[0]) if ind == 0: lst.append(k) @@ -463,22 +464,22 @@ def milnor_multiplication_odd(m1, m2, p): q_mono = tuple(lst) p_mono = mono[1] answer[(q_mono, p_mono)] = F(coeff) - for i in range(1, 1+len(mono[1])): - if (k+i not in mono[0]) and (p**k <= mono[1][i-1]): + for i in range(1, 1 + len(mono[1])): + if (k + i not in mono[0]) and (p**k <= mono[1][i - 1]): q_mono = set(mono[0]) if q_mono: - ind = len(q_mono.intersection(range(k+i, 1+max(q_mono)))) + ind = len(q_mono.intersection(range(k + i, 1 + max(q_mono)))) else: ind = 0 - coeff = (-1)**ind * old_answer[mono] + coeff = (-1) ** ind * old_answer[mono] lst = list(mono[0]) if ind == 0: - lst.append(k+i) + lst.append(k + i) else: - lst.insert(-ind, k+i) + lst.insert(-ind, k + i) q_mono = tuple(lst) p_mono = list(mono[1]) - p_mono[i-1] = p_mono[i-1] - p**k + p_mono[i - 1] = p_mono[i - 1] - p**k # The next two lines were added so that p_mono will not # have trailing zeros. This makes p_mono uniquely @@ -504,11 +505,11 @@ def milnor_multiplication_odd(m1, m2, p): # initialize matrix M = list(range(rows)) for i in range(rows): - M[i] = [0]*cols + M[i] = [0] * cols for j in range(1, cols): - M[0][j] = s[j-1] + M[0][j] = s[j - 1] for i in range(1, rows): - M[i][0] = r[i-1] + M[i][0] = r[i - 1] for j in range(1, cols): M[i][j] = 0 found = True @@ -516,17 +517,17 @@ def milnor_multiplication_odd(m1, m2, p): # check diagonals n = 1 coeff = old_coeff - diagonal = [0]*diags + diagonal = [0] * diags while n <= diags and coeff != 0: - nth_diagonal = [M[i][n-i] for i in range(max(0, n-cols+1), min(1+n, rows))] + nth_diagonal = [M[i][n - i] for i in range(max(0, n - cols + 1), min(1 + n, rows))] coeff = coeff * multinomial_odd(nth_diagonal, p) - diagonal[n-1] = sum(nth_diagonal) + diagonal[n - 1] = sum(nth_diagonal) n = n + 1 if F(coeff) != 0: i = diags - 1 while i >= 0 and diagonal[i] == 0: i = i - 1 - t = tuple(diagonal[:i+1]) + t = tuple(diagonal[: i + 1]) if (e, t) in result: result[(e, t)] = F(coeff + result[(e, t)]) else: @@ -548,7 +549,7 @@ def milnor_multiplication_odd(m1, m2, p): if temp_col_sum != 0: found = True for row in range(1, i): - M[row][0] = r[row-1] + M[row][0] = r[row - 1] for col in range(1, cols): M[0][col] = M[0][col] + M[row][col] M[row][col] = 0 @@ -614,6 +615,7 @@ def multinomial_odd(list, p): from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF from sage.rings.integer import Integer from sage.arith.misc import binomial + n = sum(list) answer = 1 F = GF(p) @@ -631,6 +633,7 @@ def multinomial_odd(list, p): index += 1 return answer + # Adem relations, Serre-Cartan basis, admissible sequences @@ -658,7 +661,7 @@ def binomial_mod2(n, k): """ if n < k: return 0 - if ((n-k) & k) == 0: + if ((n - k) & k) == 0: return 1 return 0 @@ -684,7 +687,7 @@ def binomial_modp(n, k, p): """ if n < k: return 0 - return multinomial_odd([n-k, k], p) + return multinomial_odd([n - k, k], p) @cached_function @@ -764,21 +767,21 @@ def adem(a, b, c=0, p=2, generic=None): True """ if generic is None: - generic = (p != 2) + generic = p != 2 if not generic: if b == 0: return {(a,): 1} if a == 0: return {(b,): 1} - if a >= 2*b: + if a >= 2 * b: return {(a, b): 1} result = {} - for c in range(1 + a//2): - if binomial_mod2(b-c-1, a-2*c) == 1: + for c in range(1 + a // 2): + if binomial_mod2(b - c - 1, a - 2 * c) == 1: if c == 0: - result[(a+b,)] = 1 + result[(a + b,)] = 1 else: - result[(a+b-c, c)] = 1 + result[(a + b - c, c)] = 1 return result # p odd if a == 0 and b == 0: @@ -796,34 +799,34 @@ def adem(a, b, c=0, p=2, generic=None): if B == 0: return {(0, A, bockstein): 1} if bockstein == 0: - if A >= p*B: # admissible + if A >= p * B: # admissible return {(0, A, 0, B, 0): 1} result = {} - for j in range(1 + a//p): - coeff = (-1)**(A+j) * binomial_modp((B-j) * (p-1) - 1, A - p*j, p) + for j in range(1 + a // p): + coeff = (-1) ** (A + j) * binomial_modp((B - j) * (p - 1) - 1, A - p * j, p) if coeff % p != 0: if j == 0: - result[(0, A+B, 0)] = coeff + result[(0, A + B, 0)] = coeff else: - result[(0, A+B-j, 0, j, 0)] = coeff + result[(0, A + B - j, 0, j, 0)] = coeff else: - if A >= p*B + 1: # admissible + if A >= p * B + 1: # admissible return {(0, A, 1, B, 0): 1} result = {} - for j in range(1 + a//p): - coeff = (-1)**(A+j) * binomial_modp((B-j) * (p-1), A - p*j, p) + for j in range(1 + a // p): + coeff = (-1) ** (A + j) * binomial_modp((B - j) * (p - 1), A - p * j, p) if coeff % p != 0: if j == 0: - result[(1, A+B, 0)] = coeff + result[(1, A + B, 0)] = coeff else: - result[(1, A+B-j, 0, j, 0)] = coeff - for j in range(1 + (a-1)//p): - coeff = (-1)**(A+j-1) * binomial_modp((B-j) * (p-1) - 1, A - p*j - 1, p) + result[(1, A + B - j, 0, j, 0)] = coeff + for j in range(1 + (a - 1) // p): + coeff = (-1) ** (A + j - 1) * binomial_modp((B - j) * (p - 1) - 1, A - p * j - 1, p) if coeff % p != 0: if j == 0: - result[(0, A+B, 1)] = coeff + result[(0, A + B, 1)] = coeff else: - result[(0, A+B-j, 1, j, 0)] = coeff + result[(0, A + B - j, 1, j, 0)] = coeff return result @@ -891,6 +894,7 @@ def make_mono_admissible(mono, p=2, generic=None): Sq^10 Sq^4 Sq^1 + Sq^10 Sq^5 + Sq^12 Sq^3 + Sq^13 Sq^2 """ from sage.rings.finite_rings.finite_field_constructor import GF + if generic is None: generic = p != 2 F = GF(p) @@ -901,17 +905,17 @@ def make_mono_admissible(mono, p=2, generic=None): if not generic: # check to see if admissible: admissible = True - for j in range(len(mono)-1): - if mono[j] < 2*mono[j+1]: + for j in range(len(mono) - 1): + if mono[j] < 2 * mono[j + 1]: admissible = False break if admissible: return {mono: 1} # else j is the first index where admissibility fails ans = {} - y = adem(mono[j], mono[j+1]) + y = adem(mono[j], mono[j + 1]) for x in y: - new = mono[:j] + x + mono[j+2:] + new = mono[:j] + x + mono[j + 2 :] new = make_mono_admissible(new) for m in new: if m in ans: @@ -924,22 +928,22 @@ def make_mono_admissible(mono, p=2, generic=None): # p odd # check to see if admissible: admissible = True - for j in range(1, len(mono)-2, 2): - if mono[j] < mono[j+1] + p*mono[j+2]: + for j in range(1, len(mono) - 2, 2): + if mono[j] < mono[j + 1] + p * mono[j + 2]: admissible = False break if admissible: return {mono: 1} # else j is the first index where admissibility fails ans = {} - y = adem(*mono[j:j+3], p=p, generic=True) + y = adem(*mono[j : j + 3], p=p, generic=True) for x in y: new_x = list(x) - new_x[0] = mono[j-1] + x[0] - if len(mono) >= j+3: - new_x[-1] = mono[j+3] + x[-1] + new_x[0] = mono[j - 1] + x[0] + if len(mono) >= j + 3: + new_x[-1] = mono[j + 3] + x[-1] if new_x[0] <= 1 and new_x[-1] <= 1: - new = mono[:j-1] + tuple(new_x) + mono[j+4:] + new = mono[: j - 1] + tuple(new_x) + mono[j + 4 :] new = make_mono_admissible(new, p, generic=True) for m in new: if m in ans: diff --git a/src/sage/algebras/tensor_algebra.py b/src/sage/algebras/tensor_algebra.py index 9b95513dcff..5399f8192f1 100644 --- a/src/sage/algebras/tensor_algebra.py +++ b/src/sage/algebras/tensor_algebra.py @@ -90,6 +90,7 @@ class TensorAlgebra(CombinatorialFreeModule): sage: TA.algebra_generators() Finite family {'a': B['a'], 'b': B['b'], 'c': B['c']} """ + def __init__(self, M, prefix='T', category=None, **options): r""" Initialize ``self``. @@ -107,8 +108,7 @@ def __init__(self, M, prefix='T', category=None, **options): R = M.base_ring() category = GradedHopfAlgebrasWithBasis(R.category()).or_subcategory(category) - CombinatorialFreeModule.__init__(self, R, IndexedFreeMonoid(M.indices()), - prefix=prefix, category=category, **options) + CombinatorialFreeModule.__init__(self, R, IndexedFreeMonoid(M.indices()), prefix=prefix, category=category, **options) # the following is not the best option, but it's better than nothing. self._print_options['tensor_symbol'] = options.get('tensor_symbol', tensor.symbol) @@ -149,7 +149,7 @@ def _repr_term(self, m) -> str: symb = self._print_options['tensor_symbol'] if symb is None: symb = tensor.symbol - return symb.join(self._base_module._repr_term(k) for k,e in m._monomial for i in range(e)) + return symb.join(self._base_module._repr_term(k) for k, e in m._monomial for i in range(e)) def _latex_term(self, m) -> str: r""" @@ -170,7 +170,7 @@ def _latex_term(self, m) -> str: if len(m) == 0: return '1' symb = " \\otimes " - return symb.join(self._base_module._latex_term(k) for k,e in m._monomial for i in range(e)) + return symb.join(self._base_module._latex_term(k) for k, e in m._monomial for i in range(e)) def _ascii_art_term(self, m): """ @@ -204,13 +204,12 @@ def _ascii_art_term(self, m): if len(m) == 0: return '1' from sage.typeset.ascii_art import AsciiArt, ascii_art + symb = self._print_options['tensor_symbol'] if symb is None: symb = tensor.symbol M = self._base_module - return ascii_art(*(M._ascii_art_term(k) - for k, e in m._monomial for _ in range(e)), - sep=AsciiArt([symb], breakpoints=[len(symb)])) + return ascii_art(*(M._ascii_art_term(k) for k, e in m._monomial for _ in range(e)), sep=AsciiArt([symb], breakpoints=[len(symb)])) def _element_constructor_(self, x): """ @@ -240,7 +239,7 @@ def _element_constructor_(self, x): if x in FM._indices: return self.monomial(FM.gen(x)) if x in self._base_module: - return self.sum_of_terms((FM.gen(k), v) for k,v in x) + return self.sum_of_terms((FM.gen(k), v) for k, v in x) return CombinatorialFreeModule._element_constructor_(self, x) def _tensor_constructor_(self, elts): @@ -273,11 +272,11 @@ def _tensor_constructor_(self, elts): zero = self.base_ring().zero() I = self._indices - cur = {I.gen(k): v for k,v in elts[0]} + cur = {I.gen(k): v for k, v in elts[0]} for x in elts[1:]: next = {} - for k,v in cur.items(): - for m,c in x: + for k, v in cur.items(): + for m, c in x: i = k * I.gen(m) next[i] = cur.get(i, zero) + v * c cur = next @@ -361,20 +360,13 @@ def _coerce_map_from_(self, R): if isinstance(R, TensorAlgebra) and M.has_coerce_map_from(R._base_module): RM = R._base_module phi = M.coerce_map_from(RM) - return R.module_morphism(lambda m: self._tensor_constructor_( - [phi(RM.monomial(k)) for k in m.to_word_list()]), - codomain=self) + return R.module_morphism(lambda m: self._tensor_constructor_([phi(RM.monomial(k)) for k in m.to_word_list()]), codomain=self) # Coercions from tensor products - if (R in Modules(self_base_ring).WithBasis().TensorProducts() - and isinstance(R, CombinatorialFreeModule_Tensor) - and all(M.has_coerce_map_from(RM) for RM in R._sets)): + if R in Modules(self_base_ring).WithBasis().TensorProducts() and isinstance(R, CombinatorialFreeModule_Tensor) and all(M.has_coerce_map_from(RM) for RM in R._sets): modules = R._sets vector_map = [M.coerce_map_from(RM) for RM in R._sets] - return R.module_morphism(lambda x: self._tensor_constructor_( - [vector_map[i](M.monomial(x[i])) - for i,M in enumerate(modules)]), - codomain=self) + return R.module_morphism(lambda x: self._tensor_constructor_([vector_map[i](M.monomial(x[i])) for i, M in enumerate(modules)]), codomain=self) return super()._coerce_map_from_(R) @@ -461,9 +453,7 @@ def algebra_generators(self): sage: Tm.algebra_generators() Lazy family (generator(i))_{i in Partitions} """ - return Family(self._indices.indices(), - lambda i: self.monomial(self._indices.gen(i)), - name='generator') + return Family(self._indices.indices(), lambda i: self.monomial(self._indices.gen(i)), name='generator') gens = algebra_generators @@ -566,20 +556,20 @@ def coproduct_on_basis(self, m): return S.sum_of_monomials([(m, ob), (ob, m)]) I = self._indices - m_word = [k for k,e in m._monomial for dummy in range(e)] + m_word = [k for k, e in m._monomial for dummy in range(e)] ob = self.one_basis() - return S.prod(S.sum_of_monomials([(I.gen(x), ob), (ob, I.gen(x))]) - for x in m_word) + return S.prod(S.sum_of_monomials([(I.gen(x), ob), (ob, I.gen(x))]) for x in m_word) # TODO: Implement a coproduct using shuffles. # This isn't quite right: - #from sage.combinat.words.word import Word - #k = len(m) - #return S.sum_of_monomials( (I.prod(I.gen(m_word[i]) for i in w[:p]), + # from sage.combinat.words.word import Word + # k = len(m) + # return S.sum_of_monomials( (I.prod(I.gen(m_word[i]) for i in w[:p]), # I.prod(I.gen(m_word[i]) for i in w[p:])) # for p in range(k+1) # for w in Word(range(p)).shuffle(range(p, k)) ) + ##################################################################### # TensorAlgebra functor @@ -598,6 +588,7 @@ class TensorAlgebraFunctor(ConstructionFunctor): - ``base`` -- the base `R` """ + # We choose a larger (functor) rank than most ConstructionFunctors # since this should be applied after all of the module functors rank = 20 @@ -677,10 +668,10 @@ def _apply_functor_to_morphism(self, f): DB = f.domain() D = self(DB) C = self(f.codomain()) - phi = lambda m: C._tensor_constructor_([f(DB.monomial(k)) - for k in m.to_word_list()]) + phi = lambda m: C._tensor_constructor_([f(DB.monomial(k)) for k in m.to_word_list()]) return D.module_morphism(phi, codomain=C) + ##################################################################### # Lift map from the base ring @@ -690,6 +681,7 @@ class BaseRingLift(Morphism): Morphism `R \to T(M)` which identifies the base ring `R` of a tensor algebra `T(M)` with the `0`-th graded part of `T(M)`. """ + def _call_(self, x): """ Construct the image of ``x``. diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index 9625bf0f840..6231caeee19 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -203,6 +203,7 @@ def repr_factored(w, latex_output=False) -> str: gens = w.parent().polynomial_ring().gens() if latex_output: + def exp(e): return '^{{{}}}'.format(e) if e > 1 else '' @@ -210,19 +211,20 @@ def repr_dx(k): total = sum(k) if total == 0: return '' - denom = ' '.join('\\partial {}{}'.format(latex(g), exp(e)) - for e, g in zip(k, gens) if e != 0) + denom = ' '.join('\\partial {}{}'.format(latex(g), exp(e)) for e, g in zip(k, gens) if e != 0) return ''.join(' \\frac{{\\partial{}}}{{{}}}'.format(exp(total), denom)) + repr_x = latex else: + def exp(e): return '^{}'.format(e) if e > 1 else '' def repr_dx(k): return ''.join('*d{}{}'.format(g, exp(e)) for e, g in zip(k, gens) if e != 0) + repr_x = repr - ret = " + ".join("({}){}".format(repr_x(f[k]), repr_dx(k)) - for k in sorted(f)) + ret = " + ".join("({}){}".format(repr_x(f[k]), repr_dx(k)) for k in sorted(f)) if not ret: ret = '0' if latex_output: @@ -299,6 +301,7 @@ class DifferentialWeylAlgebraElement(IndexedFreeModuleElement): sage: dx < dy or dy < dx True """ + def _repr_(self) -> str: r""" Return a string representation of ``self``. @@ -327,6 +330,7 @@ def term(m): else: ret += '{}^{}'.format(name, power) return ret + return repr_from_monomials(self.list(), term) def _latex_(self) -> str: @@ -361,12 +365,11 @@ def half_term(mon, polynomial): total = sum(mon) if total == 0: return '1' - ret = ' '.join('{}{}'.format(latex(R.gen(i)), exp(power)) if polynomial - else '\\partial {}{}'.format(latex(R.gen(i)), exp(power)) - for i, power in enumerate(mon) if power > 0) + ret = ' '.join('{}{}'.format(latex(R.gen(i)), exp(power)) if polynomial else '\\partial {}{}'.format(latex(R.gen(i)), exp(power)) for i, power in enumerate(mon) if power > 0) if not polynomial: return '\\frac{{\\partial{}}}{{{}}}'.format(exp(total), ret) return ret + p = half_term(m[0], True) d = half_term(m[1], False) if p == '1': # No polynomial part @@ -374,6 +377,7 @@ def half_term(mon, polynomial): if d == '1': # No differential part return p return p + ' ' + d + return repr_from_monomials(self.list(), term, True) def _mul_(self, other): @@ -390,6 +394,7 @@ def _mul_(self, other): dx*dy*dz^2 + x^3*dx^2*dz^2 - z*dx^2*dz^2 - 10*x*dy - 10*x^4*dx + 10*x*z*dx - 10*x^3 + 10*z """ + def add_tuples(x, y): return tuple(a + y[i] for i, a in enumerate(x)) @@ -494,8 +499,7 @@ def list(self) -> list: (((0, 0, 1), (1, 0, 0)), 1), (((1, 0, 0), (1, 0, 0)), -3)] """ - return sorted(self._monomial_coefficients.items(), - key=lambda x: (-sum(x[0][1]), x[0][1], -sum(x[0][0]), x[0][0])) + return sorted(self._monomial_coefficients.items(), key=lambda x: (-sum(x[0][1]), x[0][1], -sum(x[0][0]), x[0][0])) # This is essentially copied from # sage.combinat.free_module.CombinatorialFreeModuleElement @@ -670,6 +674,7 @@ class DifferentialWeylAlgebra(UniqueRepresentation, Parent): Implement the :meth:`graded_algebra` as a polynomial ring once they are considered to be graded rings (algebras). """ + @staticmethod def __classcall_private__(cls, R, names=None, n=None): """ @@ -683,6 +688,7 @@ def __classcall_private__(cls, R, names=None, n=None): True """ from sage.rings.infinity import PlusInfinity + if n is PlusInfinity(): # hook for Infinite weyl algebra return InfGenDifferentialWeylAlgebra(R, names) if isinstance(R, (PolynomialRing_generic, MPolynomialRing_base)): @@ -734,8 +740,7 @@ def _repr_(self) -> str: Differential Weyl algebra of polynomials in x, y, z over Rational Field """ poly_gens = ', '.join(repr(x) for x in self.variables()) - return "Differential Weyl algebra of polynomials in {} over {}".format( - poly_gens, self.base_ring()) + return "Differential Weyl algebra of polynomials in {} over {}".format(poly_gens, self.base_ring()) # add options to class class options(GlobalOptions): @@ -764,11 +769,10 @@ class options(GlobalOptions): sage: D.options._reset() """ + NAME = 'DifferentialWeylAlgebra' module = 'sage.algebras.weyl_algebra' - factor_representation = {'default': False, - 'description': 'Controls whether to factor the differentials out or not in the output representations', - 'checker': lambda x: x in [True, False]} + factor_representation = {'default': False, 'description': 'Controls whether to factor the differentials out or not in the output representations', 'checker': lambda x: x in [True, False]} def _element_constructor_(self, x): """ @@ -797,8 +801,7 @@ def _element_constructor_(self, x): zero = R.zero() return self.element_class(self, {i: R(c) for i, c in x if R(c) != zero}) x = self._poly_ring(x) - return self.element_class(self, {(tuple(m), t): c - for m, c in x.monomial_coefficients().items()}) + return self.element_class(self, {(tuple(m), t): c for m, c in x.monomial_coefficients().items()}) def _coerce_map_from_(self, R): """ @@ -844,8 +847,7 @@ def _coerce_map_from_(self, R): if self._poly_ring.has_coerce_map_from(R): return True if isinstance(R, DifferentialWeylAlgebra): - return (R.variable_names() == self.variable_names() - and self.base_ring().has_coerce_map_from(R.base_ring())) + return R.variable_names() == self.variable_names() and self.base_ring().has_coerce_map_from(R.base_ring()) return super()._coerce_map_from_(R) def degree_on_basis(self, i): @@ -956,7 +958,7 @@ def variables(self): sage: W.variables() Finite family {'x': x, 'y': y, 'z': z} """ - N = self.variable_names()[:self._n] + N = self.variable_names()[: self._n] d = {x: self.gen(i) for i, x in enumerate(N)} return Family(N, lambda x: d[x]) @@ -975,7 +977,7 @@ def differentials(self): sage: W.differentials() Finite family {'dx': dx, 'dy': dy, 'dz': dz} """ - N = self.variable_names()[self._n:] + N = self.variable_names()[self._n :] d = {x: self.gen(self._n + i) for i, x in enumerate(N)} return Family(N, lambda x: d[x]) @@ -1133,8 +1135,7 @@ def _act_(self, g, x): 3*x^2*y^3 + 6*y^3 + y """ f = g * x - D = {y: c for (y, dy), c in f.monomial_coefficients(copy=False).items() - if all(dyi == 0 for dyi in dy)} + D = {y: c for (y, dy), c in f.monomial_coefficients(copy=False).items() if all(dyi == 0 for dyi in dy)} return self.right_domain()(D) @@ -1171,6 +1172,7 @@ class InfGenDifferentialWeylAlgebraElement(IndexedFreeModuleElement): sage: (-4/3) * (x[1] + dx[1]) -4/3*dx[1] - 4/3*x[1] """ + def _repr_(self) -> str: """ Return a string representation of ``self``. @@ -1182,6 +1184,7 @@ def _repr_(self) -> str: sage: dx[1]^2*x[1]^2 x[1]^2*dx[1]^2 + 4*x[1]*dx[1] + 2 """ + def term(m): res = '' if not m[0].is_one(): @@ -1191,6 +1194,7 @@ def term(m): res += '*' res += m[1]._repr_() return res if res != '' else '1' + return repr_from_monomials(self.list(), term) def _mul_(self, other): @@ -1215,7 +1219,7 @@ def _mul_(self, other): for mr in other._monomial_coefficients: cr = other._monomial_coefficients[mr] # apply derivative terms of ml to mr and simplify - cur = [((mr[0], zero_m), cl*cr)] + cur = [((mr[0], zero_m), cl * cr)] ldd = ml[1].dict() for i in ldd: @@ -1275,8 +1279,7 @@ def list(self): sage: p.list() [((x[1], dx[1]), 1), ((x[5], 1), 1), ((1, 1), 1)] """ - return sorted(self._monomial_coefficients.items(), - key=lambda x: (-x[0][1].length(), x[0][1], -x[0][0].length(), x[0][0])) + return sorted(self._monomial_coefficients.items(), key=lambda x: (-x[0][1].length(), x[0][1], -x[0][0].length(), x[0][0])) class InfGenDifferentialWeylAlgebra(UniqueRepresentation, Parent): @@ -1356,6 +1359,7 @@ class InfGenDifferentialWeylAlgebra(UniqueRepresentation, Parent): sage: W.differential(1)*R2.base_ring()('y')*W.gen(1) y*x[1]*dx[1] + y """ + @staticmethod def __classcall_private__(cls, R, names=None): """ @@ -1438,10 +1442,7 @@ def _element_constructor_(self, x): if isinstance(x, InfinitePolynomial): if x.parent().base_ring() is R: - return self.element_class(self, { - (prod(self._var_index.gen(len(m)-i-1)**m[i] for i in range(len(m))), - self._diff_index.one()): R(c) for m, c in x._p.monomial_coefficients().items() - }) + return self.element_class(self, {(prod(self._var_index.gen(len(m) - i - 1) ** m[i] for i in range(len(m))), self._diff_index.one()): R(c) for m, c in x._p.monomial_coefficients().items()}) if isinstance(x, InfGenDifferentialWeylAlgebraElement): if x.parent().base_ring() is R: return self.element_class(self, dict(x)) @@ -1449,10 +1450,7 @@ def _element_constructor_(self, x): zero = R.zero() return self.element_class(self, {m: R(c) for m, c in x if R(c) != zero}) - return self.element_class(self, - {(self._var_index(m[0]), - self._diff_index(m[1])): R(c) - for m, c in x.items()}) + return self.element_class(self, {(self._var_index(m[0]), self._diff_index(m[1])): R(c) for m, c in x.items()}) def _coerce_map_from_(self, R): """ @@ -1480,12 +1478,10 @@ def _coerce_map_from_(self, R): x[1]*dx[1] + 1 """ if isinstance(R, InfGenDifferentialWeylAlgebra): - return (self.variable_names() == R.variable_names() - and self.base_ring().has_coerce_map_from(R.base_ring())) + return self.variable_names() == R.variable_names() and self.base_ring().has_coerce_map_from(R.base_ring()) if isinstance(R, InfinitePolynomialRing_dense): - return (self.variable_names()[:-1] == R.variable_names() - and self.base_ring().has_coerce_map_from(R.base_ring())) + return self.variable_names()[:-1] == R.variable_names() and self.base_ring().has_coerce_map_from(R.base_ring()) return super()._coerce_map_from_(R) @@ -1507,8 +1503,7 @@ def gen(self, i): sage: W.gen(1) == x[1] True """ - return self.element_class(self, {(self._var_index.gen(i), - self._diff_index.one()): self.base_ring().one()}) + return self.element_class(self, {(self._var_index.gen(i), self._diff_index.one()): self.base_ring().one()}) @cached_method def polynomial_gens(self): @@ -1526,8 +1521,8 @@ def polynomial_gens(self): True """ from sage.sets.non_negative_integers import NonNegativeIntegers - return Family(NonNegativeIntegers(), lambda x: self.gen(x), - name=self.variable_names()[0]) + + return Family(NonNegativeIntegers(), lambda x: self.gen(x), name=self.variable_names()[0]) @cached_method def gens(self) -> tuple: @@ -1565,8 +1560,7 @@ def differential(self, i): sage: W.differential(1) == dx[1] True """ - return self.element_class(self, {(self._var_index.one(), - self._diff_index.gen(i)): self.base_ring().one()}) + return self.element_class(self, {(self._var_index.one(), self._diff_index.gen(i)): self.base_ring().one()}) @cached_method def differentials(self): @@ -1584,6 +1578,7 @@ def differentials(self): True """ from sage.sets.non_negative_integers import NonNegativeIntegers + return Family(NonNegativeIntegers(), lambda x: self.differential(x), name=self.variable_names()[1]) @cached_method @@ -1634,9 +1629,7 @@ def basis(self): """ index_set = cartesian_product([self._var_index, self._diff_index]) one = self.base_ring().one() - return Family(index_set, - lambda x: self.element_class(self, {(x[0], x[1]): one}), - name='basis map') + return Family(index_set, lambda x: self.element_class(self, {(x[0], x[1]): one}), name='basis map') def degree_on_basis(self, x): """ diff --git a/src/sage/algebras/yangian.py b/src/sage/algebras/yangian.py index ac8ca556e34..9eff91bbdbb 100644 --- a/src/sage/algebras/yangian.py +++ b/src/sage/algebras/yangian.py @@ -192,9 +192,9 @@ class Yangian(CombinatorialFreeModule): - [MNO1994]_ - [Mol2007]_ """ + @staticmethod - def __classcall_private__(cls, base_ring, n, level=None, - variable_name='t', filtration='loop'): + def __classcall_private__(cls, base_ring, n, level=None, variable_name='t', filtration='loop'): """ Return the correct parent based upon input. @@ -216,9 +216,7 @@ def __classcall_private__(cls, base_ring, n, level=None, return YangianLevel(base_ring, n, level, variable_name, filtration) # We need to specify the parameter name for pickling, so it doesn't pass # ``variable_name`` as ``level`` - return super().__classcall__(cls, base_ring, n, - variable_name=variable_name, - filtration=filtration) + return super().__classcall__(cls, base_ring, n, variable_name=variable_name, filtration=filtration) def __init__(self, base_ring, n, variable_name, filtration): r""" @@ -243,11 +241,8 @@ def __init__(self, base_ring, n, variable_name, filtration): indices = cartesian_product([PositiveIntegers(), self._index_set, self._index_set]) # We note that the generators are non-commutative, but we always sort # them, so they are, in effect, indexed by the free abelian monoid - basis_keys = IndexedFreeAbelianMonoid(indices, bracket=False, - prefix=variable_name) - CombinatorialFreeModule.__init__(self, base_ring, basis_keys, - sorting_key=Yangian._term_key, - prefix=variable_name, category=category) + basis_keys = IndexedFreeAbelianMonoid(indices, bracket=False, prefix=variable_name) + CombinatorialFreeModule.__init__(self, base_ring, basis_keys, sorting_key=Yangian._term_key, prefix=variable_name, category=category) def _repr_(self) -> str: r""" @@ -272,6 +267,7 @@ def _latex_(self) -> str: Y(\mathfrak{gl}_{4}, \Bold{Q}) """ from sage.misc.latex import latex + return "Y(\\mathfrak{{gl}}_{{{}}}, {})".format(self._n, latex(self.base_ring())) @staticmethod @@ -304,9 +300,7 @@ def _repr_term(self, m) -> str: if len(m) == 0: return '1' prefix = self.prefix() - return '*'.join(prefix + '({})[{},{}]'.format(r, i, j) - + ('^{}'.format(exp) if exp > 1 else '') - for (r, i, j), exp in m._sorted_items()) + return '*'.join(prefix + '({})[{},{}]'.format(r, i, j) + ('^{}'.format(exp) if exp > 1 else '') for (r, i, j), exp in m._sorted_items()) def _latex_term(self, m) -> str: r""" @@ -332,8 +326,8 @@ def term(r, i, j, exp): if exp == 1: return s return '\\left({}\\right)^{{{}}}'.format(s, exp) - return ' '.join(term(r, i, j, exp) - for (r, i, j), exp in m._sorted_items()) + + return ' '.join(term(r, i, j, exp) for (r, i, j), exp in m._sorted_items()) def _element_constructor_(self, x): """ @@ -574,14 +568,11 @@ def product_on_gens(self, a, b): # This is the special term of x = 1 x1 = self.zero() if b[1] == a[2]: - x1 += self.monomial(I.gen((a[0]+b[0]-1, a[1], b[2]))) + x1 += self.monomial(I.gen((a[0] + b[0] - 1, a[1], b[2]))) if a[1] == b[2]: - x1 -= self.monomial(I.gen((a[0]+b[0]-1, b[1], a[2]))) + x1 -= self.monomial(I.gen((a[0] + b[0] - 1, b[1], a[2]))) - return self.monomial(I.gen(b) * I.gen(a)) + x1 + self.sum( - self.monomial(I.gen((x-1, b[1], a[2])) * I.gen((a[0]+b[0]-x, a[1], b[2]))) - - self.product_on_gens((a[0]+b[0]-x, b[1], a[2]), (x-1, a[1], b[2])) - for x in range(2, b[0]+1)) + return self.monomial(I.gen(b) * I.gen(a)) + x1 + self.sum(self.monomial(I.gen((x - 1, b[1], a[2])) * I.gen((a[0] + b[0] - x, a[1], b[2]))) - self.product_on_gens((a[0] + b[0] - x, b[1], a[2]), (x - 1, a[1], b[2])) for x in range(2, b[0] + 1)) def coproduct_on_basis(self, m): r""" @@ -609,12 +600,7 @@ def coproduct_on_basis(self, m): """ T = self.tensor_square() I = self._indices - return T.prod(T.monomial((I.one(), I.gen((a[0],a[1],a[2])))) - + T.monomial((I.gen((a[0],a[1],a[2])), I.one())) - + T.sum_of_terms([((I.gen((s,a[1],k)), I.gen((a[0]-s,k,a[2]))), 1) - for k in range(1, self._n+1) - for s in range(1, a[0])]) - for a,exp in m._sorted_items() for p in range(exp)) + return T.prod(T.monomial((I.one(), I.gen((a[0], a[1], a[2])))) + T.monomial((I.gen((a[0], a[1], a[2])), I.one())) + T.sum_of_terms([((I.gen((s, a[1], k)), I.gen((a[0] - s, k, a[2]))), 1) for k in range(1, self._n + 1) for s in range(1, a[0])]) for a, exp in m._sorted_items() for p in range(exp)) def counit_on_basis(self, m): """ @@ -649,6 +635,7 @@ class YangianLevel(Yangian): t(1)[1,2]*t(1)[1,3]*t(3)[2,1] + t(1)[1,2]*t(3)[2,3] - t(1)[1,3]*t(3)[1,1] + t(1)[1,3]*t(3)[2,2] - t(3)[1,3] """ + def __init__(self, base_ring, n, level, variable_name, filtration): """ Initialize ``self``. @@ -662,15 +649,14 @@ def __init__(self, base_ring, n, level, variable_name, filtration): self._n = n self._filtration = filtration category = HopfAlgebrasWithBasis(base_ring).Filtered() - self._index_set = tuple(range(1,n+1)) + self._index_set = tuple(range(1, n + 1)) # The keys for the basis are tuples (l, i, j) L = range(1, self._level + 1) indices = cartesian_product([L, self._index_set, self._index_set]) # We note that the generators are non-commutative, but we always sort # them, so they are, in effect, indexed by the free abelian monoid basis_keys = IndexedFreeAbelianMonoid(indices, bracket=False, prefix=variable_name) - CombinatorialFreeModule.__init__(self, base_ring, basis_keys, - prefix=variable_name, category=category) + CombinatorialFreeModule.__init__(self, base_ring, basis_keys, prefix=variable_name, category=category) def _repr_(self) -> str: r""" @@ -681,8 +667,7 @@ def _repr_(self) -> str: sage: Yangian(QQ, 4, 3) Yangian of level 3 of gl(4) in the loop filtration over Rational Field """ - return "Yangian of level {} of gl({}) in the {} filtration over {}".format( - self._level, self._n, self._filtration, self.base_ring()) + return "Yangian of level {} of gl({}) in the {} filtration over {}".format(self._level, self._n, self._filtration, self.base_ring()) def _latex_(self) -> str: r""" @@ -694,8 +679,8 @@ def _latex_(self) -> str: Y_{5}(\mathfrak{gl}_{4}, \Bold{Q}) """ from sage.misc.latex import latex - return "Y_{{{}}}(\\mathfrak{{gl}}_{{{}}}, {})".format( - self._level, self._n, latex(self.base_ring())) + + return "Y_{{{}}}(\\mathfrak{{gl}}_{{{}}}, {})".format(self._level, self._n, latex(self.base_ring())) def _coerce_map_from_(self, R): """ @@ -741,7 +726,7 @@ def _coerce_map_from_(self, R): if isinstance(R, Yangian) and R._n <= self._n and R._filtration == self._filtration: if isinstance(R, YangianLevel) and self._level > R._level: return False - on_gens = lambda m: self.prod(self.gen(*a)**exp for a,exp in m._sorted_items()) + on_gens = lambda m: self.prod(self.gen(*a) ** exp for a, exp in m._sorted_items()) return R.module_morphism(on_gens, codomain=self) return super()._coerce_map_from_(R) @@ -779,7 +764,7 @@ def defining_polynomial(self, i, j, u=None): if u is None: u = PolynomialRing(self.base_ring(), 'u').gen(0) ell = self._level - return sum(self.gen(k, i, j) * u**(ell-k) for k in range(ell+1)) + return sum(self.gen(k, i, j) * u ** (ell - k) for k in range(ell + 1)) def quantum_determinant(self, u=None): r""" @@ -809,10 +794,9 @@ def quantum_determinant(self, u=None): if u is None: u = PolynomialRing(self.base_ring(), 'u').gen(0) from sage.combinat.permutation import Permutations + n = self._n - return sum(p.sign() * prod(self.defining_polynomial(p[k], k+1, u - k) - for k in range(n)) - for p in Permutations(n)) + return sum(p.sign() * prod(self.defining_polynomial(p[k], k + 1, u - k) for k in range(n)) for p in Permutations(n)) def gen(self, r, i=None, j=None): """ @@ -848,10 +832,7 @@ def gens(self) -> tuple: (t(1)[1,1], t(2)[1,1], t(1)[1,2], t(2)[1,2], t(1)[2,1], t(2)[2,1], t(1)[2,2], t(2)[2,2]) """ - return tuple(self.gen(r, i, j) - for i in range(1, self._n+1) - for j in range(1, self._n+1) - for r in range(1, self._level+1)) + return tuple(self.gen(r, i, j) for i in range(1, self._n + 1) for j in range(1, self._n + 1) for r in range(1, self._level + 1)) @cached_method def product_on_gens(self, a, b): @@ -878,16 +859,14 @@ def product_on_gens(self, a, b): # This is the special term of x = 1 x1 = self.zero() - if a[0]+b[0]-1 <= self._level: + if a[0] + b[0] - 1 <= self._level: if b[1] == a[2]: - x1 += self.monomial(I.gen((a[0]+b[0]-1, a[1], b[2]))) + x1 += self.monomial(I.gen((a[0] + b[0] - 1, a[1], b[2]))) if a[1] == b[2]: - x1 -= self.monomial(I.gen((a[0]+b[0]-1, b[1], a[2]))) + x1 -= self.monomial(I.gen((a[0] + b[0] - 1, b[1], a[2]))) + + return self.monomial(I.gen(b) * I.gen(a)) + x1 + self.sum(self.monomial(I.gen((x - 1, b[1], a[2])) * I.gen((a[0] + b[0] - x, a[1], b[2]))) - self.product_on_gens((a[0] + b[0] - x, b[1], a[2]), (x - 1, a[1], b[2])) for x in range(2, b[0] + 1) if a[0] + b[0] - x <= self._level) - return self.monomial(I.gen(b) * I.gen(a)) + x1 + self.sum( - self.monomial(I.gen((x-1, b[1], a[2])) * I.gen((a[0]+b[0]-x, a[1], b[2]))) - - self.product_on_gens((a[0]+b[0]-x, b[1], a[2]), (x-1, a[1], b[2])) - for x in range(2, b[0]+1) if a[0]+b[0]-x <= self._level) ##################################################################### # Graded algebras @@ -897,6 +876,7 @@ class GradedYangianBase(AssociatedGradedAlgebra): """ Base class for graded algebras associated to a Yangian. """ + def _repr_term(self, m) -> str: """ Return a string representation of the monomial indexed by ``m``. @@ -911,9 +891,7 @@ def _repr_term(self, m) -> str: if len(m) == 0: return '1' prefix = self.prefix() - return '*'.join(prefix + '({})[{},{}]'.format(r, i, j) - + ('^{}'.format(exp) if exp > 1 else '') - for (r, i, j), exp in m._sorted_items()) + return '*'.join(prefix + '({})[{},{}]'.format(r, i, j) + ('^{}'.format(exp) if exp > 1 else '') for (r, i, j), exp in m._sorted_items()) def _latex_term(self, m) -> str: r""" @@ -936,8 +914,8 @@ def term(r, i, j, exp): if exp == 1: return s return '\\left({}\\right)^{{{}}}'.format(s, exp) - return ' '.join(term(r, i, j, exp) - for (r, i, j), exp in m._sorted_items()) + + return ' '.join(term(r, i, j, exp) for (r, i, j), exp in m._sorted_items()) class GradedYangianNatural(GradedYangianBase): @@ -950,6 +928,7 @@ class GradedYangianNatural(GradedYangianBase): - ``Y`` -- a Yangian with the natural filtration """ + def __init__(self, Y): """ Initialize ``self``. @@ -995,6 +974,7 @@ class GradedYangianLoop(GradedYangianBase): - ``Y`` -- a Yangian with the loop filtration """ + def __init__(self, Y): """ Initialize ``self``. @@ -1043,8 +1023,7 @@ def antipode_on_basis(self, m): + 10*tbar(1)[1,2]*tbar(1)[1,3]^3*tbar(3)[1,2] + 15*tbar(1)[1,2]^2*tbar(1)[1,3]^2*tbar(3)[1,3] """ - return self.prod((-1)**exp * self.monomial(a**exp) - for a,exp in reversed(list(m))) + return self.prod((-1) ** exp * self.monomial(a**exp) for a, exp in reversed(list(m))) def coproduct_on_basis(self, m): """ @@ -1061,8 +1040,7 @@ def coproduct_on_basis(self, m): T = self.tensor_square() I = self._indices one = I.one() - return T.prod(T.sum_of_monomials([(one, a), (a, one)]) - for a, exp in m for p in range(exp)) + return T.prod(T.sum_of_monomials([(one, a), (a, one)]) for a, exp in m for p in range(exp)) def counit_on_basis(self, m): """ diff --git a/src/sage/algebras/yokonuma_hecke_algebra.py b/src/sage/algebras/yokonuma_hecke_algebra.py index 937659797c7..6c4acbba7df 100644 --- a/src/sage/algebras/yokonuma_hecke_algebra.py +++ b/src/sage/algebras/yokonuma_hecke_algebra.py @@ -38,6 +38,7 @@ class YokonumaHeckeAlgebra(CombinatorialFreeModule): Factor out the near-common features. """ + @staticmethod def __classcall_private__(cls, d, n, q=None, R=None): r""" @@ -62,6 +63,7 @@ def __classcall_private__(cls, d, n, q=None, R=None): raise TypeError("base ring must be a commutative ring") if n not in ZZ: from sage.combinat.root_system.cartan_type import CartanType + n = CartanType(n) return YokonumaHeckeAlgebraWeyl(d, n, q, R) return YokonumaHeckeAlgebraGL(d, n, q, R) @@ -81,8 +83,7 @@ def __init__(self, d, W, q, R, indices, category=None): self._cartan_type = W.cartan_type() self._q = q cat = Algebras(R).WithBasis().or_subcategory(category) - CombinatorialFreeModule.__init__(self, R, indices, prefix='Y', - category=cat) + CombinatorialFreeModule.__init__(self, R, indices, prefix='Y', category=cat) self._assign_names(self.algebra_generators().keys()) def cartan_type(self): @@ -262,6 +263,7 @@ class YokonumaHeckeAlgebraGL(YokonumaHeckeAlgebra): - [ERH2015]_ - [JPdA15]_ """ + def __init__(self, d, n, q, R): """ Initialize ``self``. @@ -275,6 +277,7 @@ def __init__(self, d, n, q, R): self._n = n W = Permutations(n) import itertools + C = itertools.product(*([range(d)] * n)) indices = list(itertools.product(C, W)) YokonumaHeckeAlgebra.__init__(self, d, W, q, R, indices) @@ -289,8 +292,7 @@ def _repr_(self) -> str: Yokonuma-Hecke algebra of rank 5 and order 2 with q=q over Univariate Laurent Polynomial Ring in q over Rational Field """ - return "Yokonuma-Hecke algebra of rank {} and order {} with q={} over {}".format( - self._d, self._n, self._q, self.base_ring()) + return "Yokonuma-Hecke algebra of rank {} and order {} with q={} over {}".format(self._d, self._n, self._q, self.base_ring()) def _latex_(self) -> str: r""" @@ -314,10 +316,11 @@ def _repr_term(self, m) -> str: sage: Y._repr_term( ((1, 0, 2), Permutation([3,2,1])) ) 't1*t3^2*g[2,1,2]' """ + def gen_str(e): return '' if e == 1 else '^%s' % e - lhs = '*'.join('t%s' % (j + 1) + gen_str(i) - for j, i in enumerate(m[0]) if i > 0) + + lhs = '*'.join('t%s' % (j + 1) + gen_str(i) for j, i in enumerate(m[0]) if i > 0) redword = m[1].reduced_word() if not redword: if not lhs: @@ -338,10 +341,11 @@ def _latex_term(self, m) -> str: sage: Y._latex_term( ((1, 0, 2), Permutation([3,2,1])) ) 't_{1} t_{3}^{2} g_{2} g_{1} g_{2}' """ + def gen_str(e): return '' if e == 1 else '^{%s}' % e - lhs = ' '.join('t_{%s}' % (j + 1) + gen_str(i) - for j, i in enumerate(m[0]) if i > 0) + + lhs = ' '.join('t_{%s}' % (j + 1) + gen_str(i) for j, i in enumerate(m[0]) if i > 0) redword = m[1].reduced_word() if not redword: if not lhs: @@ -364,9 +368,9 @@ def algebra_generators(self): zero = [0] * self._n d = {} for i in range(self._n): - r = list(zero) # Make a copy + r = list(zero) # Make a copy r[i] = 1 - d['t%s' % (i+1)] = self.monomial((tuple(r), one)) + d['t%s' % (i + 1)] = self.monomial((tuple(r), one)) G = self._W.group_generators() for i in range(1, self._n): d['g%s' % i] = self.monomial((tuple(zero), G[i])) @@ -403,12 +407,12 @@ def e(self, i): if i < 1 or i >= self._n: raise ValueError("invalid index") c = ~self.base_ring()(self._d) - zero = [0]*self._n + zero = [0] * self._n one = self._W.one() d = {} for s in range(self._d): - r = list(zero) # Make a copy - r[i-1] = s + r = list(zero) # Make a copy + r[i - 1] = s if s != 0: r[i] = self._d - s d[(tuple(r), one)] = c @@ -433,7 +437,7 @@ def t(self, i=None): """ G = self.algebra_generators() if i is None: - I = tuple(range(1, self._n+1)) + I = tuple(range(1, self._n + 1)) d = {i: G['t%s' % i] for i in I} return Family(I, d.__getitem__) return G['t%s' % i] @@ -458,11 +462,11 @@ def product_on_basis(self, m1, m2): sage: g21 * t1 t3*g[2,1] """ - t1,g1 = m1 - t2,g2 = m2 + t1, g1 = m1 + t2, g2 = m2 # Commute g1 and t2, then multiply t1 and t2 # ig1 = g1 - t = [(t1[i] + t2[g1.index(i+1)]) % self._d for i in range(self._n)] + t = [(t1[i] + t2[g1.index(i + 1)]) % self._d for i in range(self._n)] one = self._W.one() if g1 == one: return self.monomial((tuple(t), g2)) @@ -470,8 +474,7 @@ def product_on_basis(self, m1, m2): # We have to reverse the reduced word due to Sage's convention # for permutation multiplication for i in g2.reduced_word(): - ret = self.linear_combination((self._product_by_basis_gen(m, i), c) - for m,c in ret) + ret = self.linear_combination((self._product_by_basis_gen(m, i), c) for m, c in ret) return ret def _product_by_basis_gen(self, m, i): @@ -514,9 +517,9 @@ def _product_by_basis_gen(self, m, i): # We commute g_w and e_i and then multiply by t for s in range(self._d): r = list(t) - r[w[i-1]-1] = (r[w[i-1]-1] + s) % self._d + r[w[i - 1] - 1] = (r[w[i - 1] - 1] + s) % self._d if s != 0: - r[w[i]-1] = (r[w[i]-1] + self._d - s) % self._d + r[w[i] - 1] = (r[w[i] - 1] + self._d - s) % self._d d[(tuple(r), w)] = c return self._from_dict(d, remove_zeros=False) @@ -669,6 +672,7 @@ class YokonumaHeckeAlgebraWeyl(YokonumaHeckeAlgebra): - [Marin2018]_ """ + def __init__(self, d, ct, q, R): r""" Initialize ``self``. @@ -700,8 +704,7 @@ def _repr_(self) -> str: Yokonuma-Hecke algebra of rank 5 for ['E', 6] with q=q over Univariate Laurent Polynomial Ring in q over Rational Field """ - return "Yokonuma-Hecke algebra of rank {} for {} with q={} over {}".format( - self._d, self._cartan_type, self._q, self.base_ring()) + return "Yokonuma-Hecke algebra of rank {} for {} with q={} over {}".format(self._d, self._cartan_type, self._q, self.base_ring()) def _latex_(self) -> str: r""" @@ -726,6 +729,7 @@ def _repr_term(self, m) -> str: sage: Y._repr_term((al, prod(Y._W.gens()))) 'h1*h5^3*g[1,3,2,4,5,6]' """ + def gen_str(e): return '' if e == 1 else '^%s' % e @@ -752,6 +756,7 @@ def _latex_term(self, m) -> str: sage: Y._latex_term((al, prod(Y._W.gens()))) 'h_{1} h_{5}^{3} g_{1} g_{3} g_{2} g_{4} g_{5} g_{6}' """ + def gen_str(e): return '' if e == 1 else '^{%s}' % e @@ -836,7 +841,7 @@ def e(self, i=None): c = ~self.base_ring()(self._d) al = self._Q.simple_root(i) one = self._W.one() - d = {(k*al, one): c for k in self._Q.base_ring()} + d = {(k * al, one): c for k in self._Q.base_ring()} return self._from_dict(d, remove_zeros=False) def h(self, i=None): @@ -947,8 +952,7 @@ def product_on_basis(self, m1, m2): return self.monomial((h, g2)) ret = self.monomial((h, g1)) for i in g2.reduced_word(): - ret = self.linear_combination((self._product_by_basis_gen(m, i), c) - for m, c in ret) + ret = self.linear_combination((self._product_by_basis_gen(m, i), c) for m, c in ret) return ret def _product_by_basis_gen(self, m, i): @@ -990,8 +994,8 @@ def _product_by_basis_gen(self, m, i): # TODO: Optimize this by computing an explicit expression # for the commutation of w with ei. one = self.base_ring().one() - binomial = self.element_class(self, {(h,wi): one, (h,w): one}) - return mon + (q-1) * binomial * self.e(i) + binomial = self.element_class(self, {(h, wi): one, (h, w): one}) + return mon + (q - 1) * binomial * self.e(i) class Element(CombinatorialFreeModule.Element): def __invert__(self): diff --git a/src/sage/all.py b/src/sage/all.py index e00d9b32c64..73e082cbfe9 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -58,6 +58,7 @@ sage: x = int('1'*4301) """ + # **************************************************************************** # Copyright (C) 2005-2012 William Stein # @@ -90,88 +91,58 @@ warnings.filters.remove(deprecationWarning) # Ignore all deprecations from IPython etc. -warnings.filterwarnings('ignore', category=DeprecationWarning, - module='(IPython|ipykernel|jupyter_client|jupyter_core|nbformat|notebook|ipywidgets|storemagic|jedi)') +warnings.filterwarnings('ignore', category=DeprecationWarning, module='(IPython|ipykernel|jupyter_client|jupyter_core|nbformat|notebook|ipywidgets|storemagic|jedi)') # scipy 1.18 introduced deprecation warnings on a number of things they are moving to # numpy, e.g. DeprecationWarning: scipy.array is deprecated # and will be removed in SciPy 2.0.0, use numpy.array instead # This affects networkx 2.2 up and including 2.4 (cf. :issue:29766) -warnings.filterwarnings('ignore', category=DeprecationWarning, - module='(scipy|networkx)') +warnings.filterwarnings('ignore', category=DeprecationWarning, module='(scipy|networkx)') # However, be sure to keep OUR deprecation warnings -warnings.filterwarnings('default', category=DeprecationWarning, - message=r'[\s\S]*See https?://trac\.sagemath\.org/[0-9]* for details.') +warnings.filterwarnings('default', category=DeprecationWarning, message=r'[\s\S]*See https?://trac\.sagemath\.org/[0-9]* for details.') # Ignore packaging 20.5 deprecation warnings -warnings.filterwarnings('ignore', category=DeprecationWarning, - module='(.*[.]_vendor[.])?packaging') +warnings.filterwarnings('ignore', category=DeprecationWarning, module='(.*[.]_vendor[.])?packaging') # Ignore a few warnings triggered by pythran 0.12.1 -warnings.filterwarnings('ignore', category=DeprecationWarning, - message='\n\n `numpy.distutils` is deprecated since NumPy 1.23.0', - module='pythran.dist') -warnings.filterwarnings('ignore', category=DeprecationWarning, - message='pkg_resources is deprecated as an API|' - 'Deprecated call to `pkg_resources.declare_namespace(.*)`', - module='pkg_resources|setuptools.sandbox') -warnings.filterwarnings('ignore', category=DeprecationWarning, - message='msvccompiler is deprecated and slated to be removed', - module='distutils.msvccompiler') - -warnings.filterwarnings('ignore', category=DeprecationWarning, - message='The distutils(.sysconfig module| package) is deprecated', - module='Cython|distutils|numpy|sage.env|sage.features') +warnings.filterwarnings('ignore', category=DeprecationWarning, message='\n\n `numpy.distutils` is deprecated since NumPy 1.23.0', module='pythran.dist') +warnings.filterwarnings('ignore', category=DeprecationWarning, message='pkg_resources is deprecated as an API|' 'Deprecated call to `pkg_resources.declare_namespace(.*)`', module='pkg_resources|setuptools.sandbox') +warnings.filterwarnings('ignore', category=DeprecationWarning, message='msvccompiler is deprecated and slated to be removed', module='distutils.msvccompiler') + +warnings.filterwarnings('ignore', category=DeprecationWarning, message='The distutils(.sysconfig module| package) is deprecated', module='Cython|distutils|numpy|sage.env|sage.features') # triggered by pyparsing 2.4.7 -warnings.filterwarnings('ignore', category=DeprecationWarning, - message="module 'sre_constants' is deprecated", - module='pyparsing') +warnings.filterwarnings('ignore', category=DeprecationWarning, message="module 'sre_constants' is deprecated", module='pyparsing') # triggered by mpmath 1.4.1 -warnings.filterwarnings('ignore', category=DeprecationWarning, - message='bitcount function is deprecated', - module='mpmath\\.libmp\\.libintmath') +warnings.filterwarnings('ignore', category=DeprecationWarning, message='bitcount function is deprecated', module='mpmath\\.libmp\\.libintmath') # importlib.resources.path and ...read_binary are deprecated in python 3.11, # but the replacement importlib.resources.files needs python 3.9 -warnings.filterwarnings('ignore', category=DeprecationWarning, - message=r'(path|read_binary) is deprecated\. Use files\(\) instead\.', - module='sage.repl.rich_output.output_(graphics|graphics3d|video)') +warnings.filterwarnings('ignore', category=DeprecationWarning, message=r'(path|read_binary) is deprecated\. Use files\(\) instead\.', module='sage.repl.rich_output.output_(graphics|graphics3d|video)') # triggered by sphinx -warnings.filterwarnings('ignore', category=DeprecationWarning, - message="'imghdr' is deprecated and slated for removal in Python 3.13", - module='sphinx.util.images') +warnings.filterwarnings('ignore', category=DeprecationWarning, message="'imghdr' is deprecated and slated for removal in Python 3.13", module='sphinx.util.images') # triggered by docutils 0.19 on Python 3.11 -warnings.filterwarnings('ignore', category=DeprecationWarning, - message=r"Use setlocale\(\), getencoding\(\) and getlocale\(\) instead", - module='docutils.io') +warnings.filterwarnings('ignore', category=DeprecationWarning, message=r"Use setlocale\(\), getencoding\(\) and getlocale\(\) instead", module='docutils.io') # triggered by dateutil 2.8.2 and sphinx 7.0.1 on Python 3.12 # see: https://github.com/dateutil/dateutil/pull/1285 # see: https://github.com/sphinx-doc/sphinx/pull/11468 -warnings.filterwarnings('ignore', category=DeprecationWarning, - message=r"datetime.datetime.utcfromtimestamp\(\) is deprecated", - module='dateutil.tz.tz|sphinx.(builders.gettext|util.i18n)') +warnings.filterwarnings('ignore', category=DeprecationWarning, message=r"datetime.datetime.utcfromtimestamp\(\) is deprecated", module='dateutil.tz.tz|sphinx.(builders.gettext|util.i18n)') # triggered on Python 3.12 -warnings.filterwarnings('ignore', category=DeprecationWarning, - message=r"This process.* is multi-threaded, " - r"use of .*\(\) may lead to deadlocks in the child.") +warnings.filterwarnings('ignore', category=DeprecationWarning, message=r"This process.* is multi-threaded, " r"use of .*\(\) may lead to deadlocks in the child.") # rpy2>=3.6 emits warnings for R modifying LD_LIBRARY_PATH -warnings.filterwarnings('ignore', category=UserWarning, - message=r".*redefined by R and overriding existing variable.*", - module='rpy2.*') +warnings.filterwarnings('ignore', category=UserWarning, message=r".*redefined by R and overriding existing variable.*", module='rpy2.*') # ############### end setup warnings ############################### # This import also sets up the interrupt handler -from cysignals.signals import (AlarmInterrupt, SignalError, - sig_on_reset as sig_on_count) +from cysignals.signals import AlarmInterrupt, SignalError, sig_on_reset as sig_on_count from time import sleep @@ -196,7 +167,7 @@ import sage.misc.lazy_import -from sage.misc.all import * # takes a while +from sage.misc.all import * # takes a while from sage.typeset.all import * from sage.misc.sh import sh @@ -286,6 +257,7 @@ # The code executed here uses a large amount of Sage components from sage.rings.qqbar import _init_qqbar + _init_qqbar() ########################################################### @@ -305,30 +277,24 @@ false = False oo = infinity from sage.rings.imaginary_unit import I + i = I from sage.misc.copying import license + copying = license copyright = license from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.categories.category', 'Sets', Sets) -register_unpickle_override('sage.categories.category_types', 'HeckeModules', - HeckeModules) -register_unpickle_override('sage.categories.category_types', 'Objects', - Objects) -register_unpickle_override('sage.categories.category_types', 'Rings', - Rings) -register_unpickle_override('sage.categories.category_types', 'Fields', - Fields) -register_unpickle_override('sage.categories.category_types', 'VectorSpaces', - VectorSpaces) -register_unpickle_override('sage.categories.category_types', - 'Schemes_over_base', - sage.categories.schemes.Schemes_over_base) -register_unpickle_override('sage.categories.category_types', - 'ModularAbelianVarieties', - ModularAbelianVarieties) +register_unpickle_override('sage.categories.category_types', 'HeckeModules', HeckeModules) +register_unpickle_override('sage.categories.category_types', 'Objects', Objects) +register_unpickle_override('sage.categories.category_types', 'Rings', Rings) +register_unpickle_override('sage.categories.category_types', 'Fields', Fields) +register_unpickle_override('sage.categories.category_types', 'VectorSpaces', VectorSpaces) +register_unpickle_override('sage.categories.category_types', 'Schemes_over_base', sage.categories.schemes.Schemes_over_base) +register_unpickle_override('sage.categories.category_types', 'ModularAbelianVarieties', ModularAbelianVarieties) register_unpickle_override('sage.libs.pari.gen_py', 'pari', pari) # Cache the contents of star imports. @@ -350,6 +316,7 @@ # Relink imported lazy_import objects to point to the appropriate namespace from sage.misc.lazy_import import clean_namespace + clean_namespace() del clean_namespace diff --git a/src/sage/all_cmdline.py b/src/sage/all_cmdline.py index 33d0712c996..75963dda6cf 100644 --- a/src/sage/all_cmdline.py +++ b/src/sage/all_cmdline.py @@ -3,6 +3,7 @@ This is all.py (load all sage functions) plus set-up for the Sage commandline. """ + # **************************************************************************** # Copyright (C) 2007 William Stein # @@ -19,11 +20,7 @@ from sage.misc.lazy_import import lazy_import -for pkg in ['axiom', 'fricas', 'gap', 'gap3', 'giac', 'gp', - 'gnuplot', 'kash', 'magma', 'macaulay2', 'maple', - 'mathematica', 'mathics', 'matlab', - 'mupad', 'mwrank', 'octave', 'qepcad', 'singular', - 'sage0', 'lie', 'r']: +for pkg in ['axiom', 'fricas', 'gap', 'gap3', 'giac', 'gp', 'gnuplot', 'kash', 'magma', 'macaulay2', 'maple', 'mathematica', 'mathics', 'matlab', 'mupad', 'mwrank', 'octave', 'qepcad', 'singular', 'sage0', 'lie', 'r']: lazy_import(f'sage.interfaces.{pkg}', f'{pkg}_console') del pkg diff --git a/src/sage/all_test.py b/src/sage/all_test.py index fba1d133593..63be3bdae57 100644 --- a/src/sage/all_test.py +++ b/src/sage/all_test.py @@ -15,13 +15,9 @@ def test_import_sage_all_in_fresh_interpreter(): [sys.executable, "-c", "import sage.all"], capture_output=True, env=env, - text=True, check=False, - ) - assert proc.returncode == 0, ( - "Importing 'sage.all' in a fresh interpreter failed.\n" - f"Return code: {proc.returncode}\n" - f"Stdout:\n{proc.stdout}\n" - f"Stderr:\n{proc.stderr}" + text=True, + check=False, ) + assert proc.returncode == 0, "Importing 'sage.all' in a fresh interpreter failed.\n" f"Return code: {proc.returncode}\n" f"Stdout:\n{proc.stdout}\n" f"Stderr:\n{proc.stderr}" assert proc.stderr == "" assert proc.stdout == "" diff --git a/src/sage/arith/all.py b/src/sage/arith/all.py index 517d77f5791..44146d0f9d1 100644 --- a/src/sage/arith/all.py +++ b/src/sage/arith/all.py @@ -1,34 +1,95 @@ from sage.misc.lazy_import import lazy_import -from sage.arith.misc import (algdep, algebraic_dependency, - bernoulli, is_prime, is_prime_power, - is_pseudoprime, is_pseudoprime_power, - prime_powers, primes_first_n, eratosthenes, primes, - next_prime_power, next_probable_prime, next_prime, - previous_prime, previous_prime_power, random_prime, - divisors, sigma, gcd, GCD, xlcm, xgcd, xkcd, - inverse_mod, get_gcd, get_inverse_mod, power_mod, - rational_reconstruction, mqrr_rational_reconstruction, - trial_division, factor, prime_divisors, odd_part, prime_to_m_part, - is_square, is_squarefree, euler_phi, carmichael_lambda, crt, CRT, - CRT_list, CRT_basis, CRT_vectors, multinomial, multinomial_coefficients, - binomial, factorial, kronecker_symbol, kronecker, legendre_symbol, - primitive_root, nth_prime, quadratic_residues, moebius, - continuant, number_of_divisors, hilbert_symbol, hilbert_conductor, - hilbert_conductor_inverse, falling_factorial, rising_factorial, - integer_ceil, integer_floor, - two_squares, three_squares, four_squares, sum_of_k_squares, - subfactorial, is_power_of_two, differences, - sort_complex_numbers_for_display, - fundamental_discriminant, squarefree_divisors, - radical, binomial_coefficients, jacobi_symbol, - dedekind_sum, - prime_factors, prime_range, valuation) +from sage.arith.misc import ( + algdep, + algebraic_dependency, + bernoulli, + is_prime, + is_prime_power, + is_pseudoprime, + is_pseudoprime_power, + prime_powers, + primes_first_n, + eratosthenes, + primes, + next_prime_power, + next_probable_prime, + next_prime, + previous_prime, + previous_prime_power, + random_prime, + divisors, + sigma, + gcd, + GCD, + xlcm, + xgcd, + xkcd, + inverse_mod, + get_gcd, + get_inverse_mod, + power_mod, + rational_reconstruction, + mqrr_rational_reconstruction, + trial_division, + factor, + prime_divisors, + odd_part, + prime_to_m_part, + is_square, + is_squarefree, + euler_phi, + carmichael_lambda, + crt, + CRT, + CRT_list, + CRT_basis, + CRT_vectors, + multinomial, + multinomial_coefficients, + binomial, + factorial, + kronecker_symbol, + kronecker, + legendre_symbol, + primitive_root, + nth_prime, + quadratic_residues, + moebius, + continuant, + number_of_divisors, + hilbert_symbol, + hilbert_conductor, + hilbert_conductor_inverse, + falling_factorial, + rising_factorial, + integer_ceil, + integer_floor, + two_squares, + three_squares, + four_squares, + sum_of_k_squares, + subfactorial, + is_power_of_two, + differences, + sort_complex_numbers_for_display, + fundamental_discriminant, + squarefree_divisors, + radical, + binomial_coefficients, + jacobi_symbol, + dedekind_sum, + prime_factors, + prime_range, + valuation, +) from sage.arith.functions import lcm + LCM = lcm from sage.arith.srange import xsrange, srange, ellipsis_iter, ellipsis_range + sxrange = xsrange σ = sigma diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index 97b0f4460e8..a79dad9ad36 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -39,9 +39,7 @@ ################################################################## -def algebraic_dependency(z, degree, known_bits=None, - use_bits=None, known_digits=None, - use_digits=None, height_bound=None, proof=False): +def algebraic_dependency(z, degree, known_bits=None, use_bits=None, known_digits=None, use_digits=None, height_bound=None, proof=False): """ Return an irreducible polynomial of degree at most `degree` which is approximately satisfied by the number `z`. @@ -223,6 +221,7 @@ def algebraic_dependency(z, degree, known_bits=None, is_complex = isinstance(z.parent(), ComplexField) n = degree + 1 from sage.matrix.constructor import matrix + M = matrix(ZZ, n, n + 1 + int(is_complex)) r = ZZ.one() << prec M[0, 0] = 1 @@ -235,7 +234,7 @@ def algebraic_dependency(z, degree, known_bits=None, M[k, -2] = r.imag().round() else: M[k, -1] = r.round() - LLL = M.LLL(delta=.75) + LLL = M.LLL(delta=0.75) coeffs = LLL[0][:n] # we're supposed to find an irreducible polynomial, so we cannot # return a constant one. If the first LLL basis vector gives @@ -244,18 +243,21 @@ def algebraic_dependency(z, degree, known_bits=None, coeffs = LLL[1][:n] if height_bound: + def norm(v): # norm on an integer vector invokes Integer.sqrt() which tries to factor... from sage.rings.real_mpfi import RIF + return v.change_ring(RIF).norm() + if max(abs(a) for a in coeffs) > height_bound: if proof: # Given an LLL reduced basis $b_1, ..., b_n$, we only # know that $|b_1| <= 2^((n-1)/2) |x|$ for nonzero $x \in L$. - if norm(LLL[0]) <= 2**((n - 1) / 2) * n.sqrt() * height_bound: + if norm(LLL[0]) <= 2 ** ((n - 1) / 2) * n.sqrt() * height_bound: raise ValueError("insufficient precision for non-existence proof") return None - if proof and norm(LLL[1]) < 2**((n - 1) / 2) * max(norm(LLL[0]), n.sqrt() * height_bound): + if proof and norm(LLL[1]) < 2 ** ((n - 1) / 2) * max(norm(LLL[0]), n.sqrt() * height_bound): raise ValueError("insufficient precision for uniqueness proof") if coeffs[degree] < 0: coeffs = -coeffs @@ -266,6 +268,7 @@ def norm(v): else: from sage.libs.pari import pari + f = pari(z).algdep(degree) # f might be reducible. Find the best fitting irreducible factor @@ -369,27 +372,34 @@ def bernoulli(n, algorithm='default', num_threads=1): if algorithm == 'arb': import sage.libs.arb.arith as arb_arith + return arb_arith.bernoulli(n) if algorithm == 'flint': if n >= 100000: from warnings import warn + warn("flint is known to not be accurate for large Bernoulli numbers") from sage.libs.flint.arith_sage import bernoulli_number as flint_bernoulli + return flint_bernoulli(n) if algorithm == 'pari' or algorithm == 'gp': from sage.libs.pari import pari - x = pari(n).bernfrac() # Use the PARI C library + + x = pari(n).bernfrac() # Use the PARI C library return Rational(x) if algorithm == 'gap': from sage.libs.gap.libgap import libgap + x = libgap.Bernoulli(n).sage() return Rational(x) if algorithm == 'magma': import sage.interfaces.magma + x = sage.interfaces.magma.magma('Bernoulli(%s)' % n) return Rational(x) if algorithm == 'bernmm': import sage.rings.bernmm + return sage.rings.bernmm.bernmm_bern_rat(n, num_threads) raise ValueError("invalid choice of algorithm") @@ -469,6 +479,7 @@ def factorial(n, algorithm='gmp'): return ZZ(n).factorial() if algorithm == 'pari': from sage.libs.pari import pari + return pari.factorial(n) raise ValueError('unknown algorithm') @@ -556,13 +567,13 @@ def is_prime(n) -> bool: if R.is_field(): # number fields redefine .is_prime(), see #32340 from sage.rings.number_field.number_field_base import NumberField + if R is QQ or not isinstance(R, NumberField): import warnings - s = f'Testing primality in {R}, which is a field, ' \ - 'hence the result will always be False. ' + + s = f'Testing primality in {R}, which is a field, ' 'hence the result will always be False. ' if R is QQ: - s += 'To test whether n is a prime integer, use ' \ - 'is_prime(ZZ(n)) or ZZ(n).is_prime(). ' + s += 'To test whether n is a prime integer, use ' 'is_prime(ZZ(n)) or ZZ(n).is_prime(). ' s += 'Using n.is_prime() instead will silence this warning.' warnings.warn(s) @@ -997,7 +1008,7 @@ def eratosthenes(n): return [ZZ(2)] s = list(range(3, n + 3, 2)) - mroot = int(n ** 0.5) + mroot = int(n**0.5) half = (n + 1) // 2 i = 0 m = 3 @@ -1443,6 +1454,7 @@ def random_prime(n, proof=None, lbound=2): # since we do not want current_randstate to get # pulled when you say "from sage.arith.misc import *". from sage.structure.proof.proof import get_flag + proof = get_flag(proof, "arithmetic") n = ZZ(n) if n < 2: @@ -1635,6 +1647,7 @@ class Sigma: sage: sigma(mpz(100), mpz(4)) 106811523 """ + def __repr__(self): """ A description of this class, which computes the sum of the @@ -1668,13 +1681,10 @@ def __call__(self, n, k=1): if k == ZZ.zero(): return prod(expt + one for p, expt in factor(n)) if k == one: - return prod((p**(expt + one) - one).divide_knowing_divisible_by(p - one) - for p, expt in factor(n)) - return prod((p**((expt + one) * k) - one).divide_knowing_divisible_by(p**k - one) - for p, expt in factor(n)) + return prod((p ** (expt + one) - one).divide_knowing_divisible_by(p - one) for p, expt in factor(n)) + return prod((p ** ((expt + one) * k) - one).divide_knowing_divisible_by(p**k - one) for p, expt in factor(n)) - def plot(self, xmin=1, xmax=50, k=1, pointsize=30, rgbcolor=(0, 0, 1), join=True, - **kwds): + def plot(self, xmin=1, xmax=50, k=1, pointsize=30, rgbcolor=(0, 0, 1), join=True, **kwds): """ Plot the sigma (sum of `k`-th powers of divisors) function. @@ -1703,6 +1713,7 @@ def plot(self, xmin=1, xmax=50, k=1, pointsize=30, rgbcolor=(0, 0, 1), join=True """ v = [(n, sigma(n, k)) for n in range(xmin, xmax + 1)] from sage.plot.plot import list_plot + P = list_plot(v, pointsize=pointsize, rgbcolor=rgbcolor, **kwds) if join: P += list_plot(v, plotjoined=True, rgbcolor=(0.7, 0.7, 0.7), **kwds) @@ -1920,7 +1931,7 @@ def xlcm(m, n): n = py_scalar_to_element(n) g = gcd(m, n) - l = m * n // g # = lcm(m, n) + l = m * n // g # = lcm(m, n) g = gcd(m, n // g) # divisible by those primes which divide n to a higher power than m @@ -2180,8 +2191,7 @@ def xkcd(n=""): alt = data['alt'] title = data['safe_title'] link = f"http://xkcd.com/{data['num']}" - return html(f'

{title}

' - + '
Source: {0}
'.format(link)) + return html(f'

{title}

' + '
Source: {0}
'.format(link)) # TODO: raise this error in such a way that it's not clear that # it is produced by sage, see http://xkcd.com/1024/ @@ -2218,6 +2228,7 @@ def inverse_mod(a, m): except AttributeError: return Integer(a).inverse_mod(m) + ####################################################### # Functions to find the fastest available commands # for gcd and inverse_mod @@ -2238,9 +2249,9 @@ def get_gcd(order): sage: sage.arith.misc.get_gcd(4000000000) """ - if order <= 46340: # todo: don't hard code + if order <= 46340: # todo: don't hard code return arith_int().gcd_int - if order <= 2147483647: # todo: don't hard code + if order <= 2147483647: # todo: don't hard code return arith_llong().gcd_longlong return gcd @@ -2259,12 +2270,13 @@ def get_inverse_mod(order): sage: sage.arith.misc.get_inverse_mod(6000000000) """ - if order <= 46340: # todo: don't hard code + if order <= 46340: # todo: don't hard code return arith_int().inverse_mod_int - if order <= 2147483647: # todo: don't hard code + if order <= 2147483647: # todo: don't hard code return arith_llong().inverse_mod_longlong return inverse_mod + # def sqrt_mod(a, m): # """A square root of a modulo m.""" @@ -2494,7 +2506,7 @@ def mqrr_rational_reconstruction(u, m, T): t0, r0 = 0, m t1, r1 = 1, u while r1 != 0 and r0 > T: - q = r0 / r1 # C division implicit floor + q = r0 / r1 # C division implicit floor if q > T: n, d, T = r1, t1, q r0, r1 = r1, r0 - q * r1 @@ -2744,8 +2756,7 @@ def factor(n, proof=None, int_=False, algorithm=None, verbose=0, **kwds): m = n.factor if isinstance(n, Integer): - return m(proof=proof, algorithm=algorithm, int_=int_, - verbose=verbose, **kwds) + return m(proof=proof, algorithm=algorithm, int_=int_, verbose=verbose, **kwds) # Polynomial or other factorable object try: @@ -3128,6 +3139,7 @@ class Euler_Phi: - Alex Clemesha (2006-01-10): some examples """ + def __repr__(self): """ Return a string describing this class. @@ -3157,10 +3169,10 @@ def __call__(self, n): if n <= 2: return ZZ.one() from sage.libs.pari import pari + return ZZ(pari(n).eulerphi()) - def plot(self, xmin=1, xmax=50, pointsize=30, rgbcolor=(0, 0, 1), - join=True, **kwds): + def plot(self, xmin=1, xmax=50, pointsize=30, rgbcolor=(0, 0, 1), join=True, **kwds): """ Plot the Euler phi function. @@ -3187,6 +3199,7 @@ def plot(self, xmin=1, xmax=50, pointsize=30, rgbcolor=(0, 0, 1), """ v = [(n, euler_phi(n)) for n in range(xmin, xmax + 1)] from sage.plot.plot import list_plot + P = list_plot(v, pointsize=pointsize, rgbcolor=rgbcolor, **kwds) if join: P += list_plot(v, plotjoined=True, rgbcolor=(0.7, 0.7, 0.7), **kwds) @@ -3338,7 +3351,7 @@ def carmichael_lambda(n): t.append(1 << k) # then other prime factors - t.extend(p**(k - 1) * (p - 1) for p, k in L) + t.extend(p ** (k - 1) * (p - 1) for p, k in L) # finish the job return LCM_list(t) @@ -3606,6 +3619,7 @@ def CRT_list(values, moduli=None): return_mod = moduli is None if return_mod: from sage.rings.finite_rings.integer_mod import IntegerMod_abstract, Mod + if not values: return Mod(0, 1) if not all(isinstance(v, IntegerMod_abstract) for v in values): @@ -3627,6 +3641,7 @@ def CRT_list(values, moduli=None): # this scales much better than folding the list from one side. # See also sage.misc.misc_c.balanced_list_prod from sage.arith.functions import lcm + while len(values) > 1: vs, ms = values[::2], moduli[::2] for i, (v, m) in enumerate(zip(values[1::2], moduli[1::2])): @@ -3757,11 +3772,8 @@ def CRT_vectors(X, moduli): res = CRT_basis(moduli, require_coprime_moduli=False) a = res[0] modulus = LCM_list(moduli) - candidate = [sum(a[i] * X[i][j] for i in range(n)) % modulus - for j in range(len(X[0]))] - if not res[1] and any((X[i][j] - candidate[j]) % moduli[i] != 0 - for i in range(n) - for j in range(len(X[i]))): + candidate = [sum(a[i] * X[i][j] for i in range(n)) % modulus for j in range(len(X[0]))] + if not res[1] and any((X[i][j] - candidate[j]) % moduli[i] != 0 for i in range(n) for j in range(len(X[i]))): raise ValueError("solution does not exist") return candidate @@ -4514,6 +4526,7 @@ def primitive_root(n, check=True): 5 """ from sage.libs.pari import pari + if not check: return ZZ(pari(n).znprimroot()) n = ZZ(n).abs() @@ -4524,7 +4537,7 @@ def primitive_root(n, check=True): elif n % 2: # n odd if n.is_prime_power(): return ZZ(pari(n).znprimroot()) - else: # n even + else: # n even m = n // 2 if m % 2 and m.is_prime_power(): return ZZ(pari(n).znprimroot()) @@ -4571,6 +4584,7 @@ def nth_prime(n): if n <= 0: raise ValueError("nth prime meaningless for nonpositive n (=%s)" % n) from sage.libs.pari import pari + return ZZ(pari.prime(n)) @@ -4665,6 +4679,7 @@ class Moebius: sage: moebius(mpz(-5)) # needs sage.libs.pari -1 """ + def __call__(self, n): """ EXAMPLES:: @@ -4683,12 +4698,13 @@ def __call__(self, n): for _, e in F: if e >= 2: return 0 - return (-1)**len(F) + return (-1) ** len(F) # Use fast PARI algorithm if n == 0: return ZZ.zero() from sage.libs.pari import pari + return ZZ(pari(n).moebius()) def __repr__(self): @@ -4704,8 +4720,7 @@ def __repr__(self): """ return "The Moebius function" - def plot(self, xmin=0, xmax=50, pointsize=30, rgbcolor=(0, 0, 1), join=True, - **kwds): + def plot(self, xmin=0, xmax=50, pointsize=30, rgbcolor=(0, 0, 1), join=True, **kwds): """ Plot the Möbius function. @@ -4734,6 +4749,7 @@ def plot(self, xmin=0, xmax=50, pointsize=30, rgbcolor=(0, 0, 1), join=True, values = self.range(xmin, xmax + 1) v = [(n, values[n - xmin]) for n in range(xmin, xmax + 1)] from sage.plot.plot import list_plot + P = list_plot(v, pointsize=pointsize, rgbcolor=rgbcolor, **kwds) if join: P += list_plot(v, plotjoined=True, rgbcolor=(0.7, 0.7, 0.7), **kwds) @@ -4770,8 +4786,7 @@ def range(self, start, stop=None, step=None): step = int(step) if start <= 0 < stop and start % step == 0: - return self.range(start, 0, step) + [ZZ.zero()] + \ - self.range(step, stop, step) + return self.range(start, 0, step) + [ZZ.zero()] + self.range(step, stop, step) from sage.libs.pari import pari @@ -4779,8 +4794,7 @@ def range(self, start, stop=None, step=None): v = pari('vector(%s, i, moebius(i-1+%s))' % (stop - start, start)) else: n = len(range(start, stop, step)) # stupid - v = pari('vector(%s, i, moebius(%s*(i-1) + %s))' % ( - n, step, start)) + v = pari('vector(%s, i, moebius(%s*(i-1) + %s))' % (n, step, start)) return [Integer(x) for x in v] @@ -4790,6 +4804,7 @@ def range(self, start, stop=None, step=None): # Note: farey, convergent, continued_fraction_list and convergents # have been moved to sage.rings.continued_fraction + def continuant(v, n=None): r""" Function returns the continuant of the sequence `v` (list @@ -4904,6 +4919,7 @@ def number_of_divisors(n): if m.is_zero(): raise ValueError("input must be nonzero") from sage.libs.pari import pari + return ZZ(pari(m).numdiv()) @@ -4977,6 +4993,7 @@ def hilbert_symbol(a, b, p, algorithm='pari'): if p == -1: p = 0 from sage.libs.pari import pari + return ZZ(pari(a).hilbert(b, p)) if algorithm == 'direct': @@ -5060,9 +5077,7 @@ def hilbert_conductor(a, b): - Gonzalo Tornaria (2009-03-02) """ a, b = ZZ(a), ZZ(b) - return ZZ.prod(p for p in {2}.union(a.prime_divisors(), - b.prime_divisors()) - if hilbert_symbol(a, b, p) == -1) + return ZZ.prod(p for p in {2}.union(a.prime_divisors(), b.prime_divisors()) if hilbert_symbol(a, b, p) == -1) def hilbert_conductor_inverse(d): @@ -5253,13 +5268,13 @@ def falling_factorial(x, a): - Jaap Spies (2006-03-05) """ from sage.structure.element import Expression + x = py_scalar_to_element(x) a = py_scalar_to_element(a) - if (isinstance(a, Integer) or - (isinstance(a, Expression) and - a.is_integer())) and a >= 0: + if (isinstance(a, Integer) or (isinstance(a, Expression) and a.is_integer())) and a >= 0: return prod(((x - i) for i in range(a)), z=x.parent().one()) from sage.functions.gamma import gamma + return gamma(x + 1) / gamma(x - a + 1) @@ -5345,13 +5360,13 @@ def rising_factorial(x, a): - Jaap Spies (2006-03-05) """ from sage.structure.element import Expression + x = py_scalar_to_element(x) a = py_scalar_to_element(a) - if (isinstance(a, Integer) or - (isinstance(a, Expression) and - a.is_integer())) and a >= 0: + if (isinstance(a, Integer) or (isinstance(a, Expression) and a.is_integer())) and a >= 0: return prod(((x + i) for i in range(a)), z=x.parent().one()) from sage.functions.gamma import gamma + return gamma(x + a) / gamma(x) @@ -5517,6 +5532,7 @@ def two_squares(n): if n.nbits() <= 32: from sage.rings import sum_of_squares + return sum_of_squares.two_squares_pyx(n) # Start by factoring n (which seems to be unavoidable) @@ -5533,6 +5549,7 @@ def two_squares(n): # a sum of 2 squares and accumulate the product # (using multiplication in Z[I]) in a^2 + b^2. from sage.rings.finite_rings.integer_mod import Mod + a = ZZ.one() b = ZZ.zero() for p, e in F: @@ -5549,7 +5566,7 @@ def two_squares(n): # If y is a non-square, then y^((p-1)/4) is a square root of -1. y = Mod(2, p) while True: - s = y**((p - 1) / 4) + s = y ** ((p - 1) / 4) if not s * s + 1: s = s.lift() break @@ -5640,6 +5657,7 @@ def three_squares(n): if n.nbits() <= 32: from sage.rings import sum_of_squares + return sum_of_squares.three_squares_pyx(n) # First, remove all factors 4 from n @@ -5693,6 +5711,7 @@ def three_squares(n): # Normally, this should only happen for small values of N. if N > 10000: from warnings import warn + warn("Brute forcing sum of 3 squares for large N = %s" % N, RuntimeWarning) x = N.isqrt() @@ -5768,6 +5787,7 @@ def four_squares(n): if n.nbits() <= 32: from sage.rings import sum_of_squares + return sum_of_squares.four_squares_pyx(n) # First, remove all factors 4 from n @@ -5928,7 +5948,7 @@ def subfactorial(n): - Jaap Spies (2007-01-23) """ - return factorial(n) * sum((-1)**k / factorial(k) for k in range(n + 1)) + return factorial(n) * sum((-1) ** k / factorial(k) for k in range(n + 1)) def is_power_of_two(n): @@ -6305,10 +6325,12 @@ def dedekind_sum(p, q, algorithm='default'): """ if algorithm == 'default' or algorithm == 'flint': from sage.libs.flint.arith_sage import dedekind_sum as flint_dedekind_sum + return flint_dedekind_sum(p, q) if algorithm == 'pari': from sage.libs.pari import pari + x = pari.sumdedekind(p, q) return Rational(x) @@ -6409,6 +6431,7 @@ def gauss_sum(char_value, finite_field): for prime finite fields """ from sage.categories.fields import Fields + if finite_field not in Fields().Finite(): raise ValueError('second input must be a finite field') @@ -6485,6 +6508,7 @@ def smooth_part(x, base): 7 * 11^2 * 13 * 19 * 23 """ from sage.rings.generic import ProductTree + if isinstance(base, ProductTree): tree = base else: @@ -6504,6 +6528,7 @@ def smooth_part(x, base): v += 1 fs.append((p, v)) from sage.structure.factorization import Factorization + return Factorization(fs) diff --git a/src/sage/calculus/all.py b/src/sage/calculus/all.py index fc7f54a6758..3280c915fbe 100644 --- a/src/sage/calculus/all.py +++ b/src/sage/calculus/all.py @@ -1,33 +1,28 @@ - from .calculus import maxima as maxima_calculus -from .calculus import (laplace, inverse_laplace, - limit, lim) +from .calculus import laplace, inverse_laplace, limit, lim from .integration import numerical_integral, monte_carlo_integral + integral_numerical = numerical_integral from .interpolation import spline, Spline -from .functional import (diff, derivative, - expand, - taylor, simplify) +from .functional import diff, derivative, expand, taylor, simplify -from .functions import (wronskian, jacobian) +from .functions import wronskian, jacobian from .ode import ode_solver, ode_system -from .desolvers import (desolve, desolve_laplace, desolve_system, - eulers_method, eulers_method_2x2, - eulers_method_2x2_plot, desolve_rk4, desolve_system_rk4, - desolve_odeint, desolve_mintides, desolve_tides_mpfr) +from .desolvers import desolve, desolve_laplace, desolve_system, eulers_method, eulers_method_2x2, eulers_method_2x2_plot, desolve_rk4, desolve_system_rk4, desolve_odeint, desolve_mintides, desolve_tides_mpfr from sage.calculus.expr import symbolic_expression -from sage.calculus.var import (var, function, clear_vars) +from sage.calculus.var import var, function, clear_vars from .transforms.all import * # We lazy_import the following modules since they import numpy which slows down sage startup from sage.misc.lazy_import import lazy_import + lazy_import("sage.calculus.riemann", ["Riemann_Map"]) lazy_import("sage.calculus.interpolators", ["polygon_spline", "complex_cubic_spline"]) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index ce06cc41157..d742937b4c1 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -427,7 +427,8 @@ from sage.arith.misc import algebraic_dependency from sage.misc.lazy_import import lazy_import -lazy_import("sage.interfaces.maxima_lib","maxima") + +lazy_import("sage.interfaces.maxima_lib", "maxima") from sage.misc.latex import latex from sage.misc.parser import LookupNameMaker, Parser from sage.rings.cc import CC @@ -631,10 +632,11 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): if hold: from sage.functions.other import symbolic_sum as ssum + return ssum(expression, v, a, b) if algorithm == 'maxima': - return maxima.sr_sum(expression,v,a,b) + return maxima.sr_sum(expression, v, a, b) if algorithm == 'mathematica': try: @@ -642,6 +644,7 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): except TypeError: raise ValueError("Mathematica cannot make sense of input") from sage.interfaces.mathematica import mathematica + try: result = mathematica(sum) except TypeError: @@ -651,6 +654,7 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): if algorithm == 'maple': sum = "sum(%s, %s=%s..%s)" % tuple([repr(expr._maple_()) for expr in (expression, v, a, b)]) from sage.interfaces.maple import maple + try: result = maple(sum).simplify() except TypeError: @@ -660,6 +664,7 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): if algorithm == 'giac': sum = "sum(%s, %s, %s, %s)" % tuple([repr(expr._giac_()) for expr in (expression, v, a, b)]) from sage.interfaces.giac import giac + try: result = giac(sum) except TypeError: @@ -667,25 +672,23 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): return result.sage() if algorithm == 'sympy': - expression,v,a,b = (expr._sympy_() for expr in (expression, v, a, b)) + expression, v, a, b = (expr._sympy_() for expr in (expression, v, a, b)) from sympy import summation from sage.interfaces.sympy import sympy_init + sympy_init() result = summation(expression, (v, a, b)) try: return result._sage_() except AttributeError: - raise AttributeError("Unable to convert SymPy result (={}) into" - " Sage".format(result)) + raise AttributeError("Unable to convert SymPy result (={}) into" " Sage".format(result)) else: raise ValueError("unknown algorithm: %s" % algorithm) -def nintegral(ex, x, a, b, - desired_relative_error='1e-8', - maximum_num_subintervals=200): +def nintegral(ex, x, a, b, desired_relative_error='1e-8', maximum_num_subintervals=200): r""" Return a floating point machine precision numerical approximation to the integral of ``self`` from `a` to @@ -807,9 +810,7 @@ def nintegral(ex, x, a, b, Note that the input function above is a string in PARI syntax. """ try: - v = ex._maxima_().quad_qags(x, a, b, - epsrel=desired_relative_error, - limit=maximum_num_subintervals) + v = ex._maxima_().quad_qags(x, a, b, epsrel=desired_relative_error, limit=maximum_num_subintervals) except TypeError as err: if "ERROR" in str(err): raise ValueError("Maxima (via quadpack) cannot compute the integral") @@ -894,10 +895,11 @@ def symbolic_product(expression, v, a, b, algorithm='maxima', hold=False): if hold: from sage.functions.other import symbolic_product as sprod + return sprod(expression, v, a, b) if algorithm == 'maxima': - return maxima.sr_prod(expression,v,a,b) + return maxima.sr_prod(expression, v, a, b) if algorithm == 'mathematica': try: @@ -905,6 +907,7 @@ def symbolic_product(expression, v, a, b, algorithm='maxima', hold=False): except TypeError: raise ValueError("Mathematica cannot make sense of input") from sage.interfaces.mathematica import mathematica + try: result = mathematica(prod) except TypeError: @@ -914,6 +917,7 @@ def symbolic_product(expression, v, a, b, algorithm='maxima', hold=False): if algorithm == 'giac': prod = "product(%s, %s, %s, %s)" % tuple([repr(expr._giac_()) for expr in (expression, v, a, b)]) from sage.interfaces.giac import giac + try: result = giac(prod) except TypeError: @@ -921,17 +925,17 @@ def symbolic_product(expression, v, a, b, algorithm='maxima', hold=False): return result.sage() if algorithm == 'sympy': - expression,v,a,b = (expr._sympy_() for expr in (expression, v, a, b)) + expression, v, a, b = (expr._sympy_() for expr in (expression, v, a, b)) from sympy import product as sproduct from sage.interfaces.sympy import sympy_init + sympy_init() result = sproduct(expression, (v, a, b)) try: return result._sage_() except AttributeError: - raise AttributeError("Unable to convert SymPy result (={}) into" - " Sage".format(result)) + raise AttributeError("Unable to convert SymPy result (={}) into" " Sage".format(result)) else: raise ValueError("unknown algorithm: %s" % algorithm) @@ -1110,8 +1114,8 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): necessarily indicate that this number is transcendental. """ if algorithm is None or algorithm.startswith('numeric'): - bits_list = [bits] if bits else [100,200,500,1000] - degree_list = [degree] if degree else [2,4,8,12,24] + bits_list = [bits] if bits else [100, 200, 500, 1000] + degree_list = [degree] if degree else [2, 4, 8, 12, 24] for bits in bits_list: a = ex.numerical_approx(bits) @@ -1152,6 +1156,7 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): if algorithm is None or algorithm == 'algebraic': from sage.rings.qqbar import QQbar + return QQ[var](QQbar(ex).minpoly()) raise ValueError("Unknown algorithm: %s" % algorithm) @@ -1548,8 +1553,8 @@ def limit(ex, *args, dir=None, taylor=False, algorithm='maxima', **kwargs): v = None a = None - if len(args) == 2: # Syntax: limit(ex, v, a, ...) - if kwargs: # Cannot mix positional v, a with keyword args + if len(args) == 2: # Syntax: limit(ex, v, a, ...) + if kwargs: # Cannot mix positional v, a with keyword args raise ValueError("cannot mix positional specification of limit variable and point with keyword variable arguments") v = args[0] a = args[1] @@ -1560,7 +1565,7 @@ def limit(ex, *args, dir=None, taylor=False, algorithm='maxima', **kwargs): raise ValueError("three positional arguments (expr, v, a) or one positional and one keyword argument (expr, v=a) required") elif len(args) == 0: # Potential syntax: limit(ex, v=a, ...) or limit(ex) if len(kwargs) == 1: - k, = kwargs.keys() + (k,) = kwargs.keys() v = var(k) a = kwargs[k] elif len(kwargs) == 0: # For No variable specified at all @@ -1607,6 +1612,7 @@ def limit(ex, *args, dir=None, taylor=False, algorithm='maxima', **kwargs): l = maxima.sr_tlimit(ex, v, a, 'minus') elif effective_algorithm == 'sympy': import sympy + sympy_dir = '+-' if dir in dir_plus: sympy_dir = '+' @@ -1615,6 +1621,7 @@ def limit(ex, *args, dir=None, taylor=False, algorithm='maxima', **kwargs): l = sympy.limit(ex._sympy_(), v._sympy_(), a._sympy_(), dir=sympy_dir) elif effective_algorithm == 'fricas': from sage.interfaces.fricas import fricas + eq = fricas.equation(v._fricas_(), a._fricas_()) f = ex._fricas_() fricas_dir_arg = None @@ -1633,6 +1640,7 @@ def limit(ex, *args, dir=None, taylor=False, algorithm='maxima', **kwargs): l = l_raw elif effective_algorithm == 'giac': from sage.libs.giac.giac import libgiac + giac_v = v._giac_init_() giac_a = a._giac_init_() giac_dir_arg = 0 # Default for two-sided @@ -1683,6 +1691,7 @@ def mma_free_limit(expression, v, a, dir=None): request_wolfram_alpha, symbolic_expression_from_mathematica_string, ) + dir_plus = ['plus', '+', 'above', 'right'] dir_minus = ['minus', '-', 'below', 'left'] math_expr = expression._mathematica_init_() @@ -1920,6 +1929,7 @@ def laplace(ex, t, s, algorithm='maxima'): from sympy import laplace_transform from sage.interfaces.sympy import sympy_init + sympy_init() result = laplace_transform(ex_sy, t, s) if isinstance(result, tuple): @@ -1927,8 +1937,7 @@ def laplace(ex, t, s, algorithm='maxima'): (result, a, cond) = result return result._sage_(), a, cond except AttributeError: - raise AttributeError("Unable to convert SymPy result (={}) into" - " Sage".format(result)) + raise AttributeError("Unable to convert SymPy result (={}) into" " Sage".format(result)) elif 'LaplaceTransform' in format(result): return dummy_laplace(ex, t, s) else: @@ -1936,6 +1945,7 @@ def laplace(ex, t, s, algorithm='maxima'): elif algorithm == 'giac': from sage.interfaces.giac import giac + try: result = giac.laplace(ex, t, s) except TypeError: @@ -2105,6 +2115,7 @@ def inverse_laplace(ex, s, t, algorithm='maxima'): from sympy import inverse_laplace_transform from sage.interfaces.sympy import sympy_init + sympy_init() result = inverse_laplace_transform(ex_sy, s, t) try: @@ -2112,11 +2123,11 @@ def inverse_laplace(ex, s, t, algorithm='maxima'): except AttributeError: if 'InverseLaplaceTransform' in format(result): return dummy_inverse_laplace(ex, t, s) - raise AttributeError("Unable to convert SymPy result (={}) into" - " Sage".format(result)) + raise AttributeError("Unable to convert SymPy result (={}) into" " Sage".format(result)) elif algorithm == 'giac': from sage.interfaces.giac import giac + try: result = giac.invlaplace(ex, s, t) except TypeError: @@ -2199,8 +2210,7 @@ def at(ex, *args, **kwds): """ if not isinstance(ex, (Expression, Function)): ex = SR(ex) - kwds = {(k[10:] if k[:10] == "_SAGE_VAR_" else k): v - for k, v in kwds.items()} + kwds = {(k[10:] if k[:10] == "_SAGE_VAR_" else k): v for k, v in kwds.items()} if len(args) == 1 and isinstance(args[0], list): for c in args[0]: kwds[str(c.lhs())] = c.rhs() @@ -2300,6 +2310,7 @@ def dummy_pochhammer(*args): """ x, y = args from sage.functions.gamma import gamma + return gamma(x + y) / gamma(x) @@ -2309,6 +2320,7 @@ def dummy_pochhammer(*args): # ####################################################### + def _laplace_latex_(self, *args): r""" Return LaTeX expression for Laplace transform of a symbolic function. @@ -2348,18 +2360,14 @@ def _inverse_laplace_latex_(self, *args): # Return un-evaluated expression as instances of NewSymbolicFunction _laplace = function_factory('laplace', print_latex_func=_laplace_latex_) -_inverse_laplace = function_factory('ilt', - print_latex_func=_inverse_laplace_latex_) +_inverse_laplace = function_factory('ilt', print_latex_func=_inverse_laplace_latex_) ######################################i################ # Conversion dict for special maxima objects # c,k1,k2 are from ode2() -symtable = {'%pi': 'pi', '%e': 'e', '%i': 'I', - '%gamma': 'euler_gamma', - '%c': '_C', '%k1': '_K1', '%k2': '_K2', - 'e': '_e', 'i': '_i', 'I': '_I'} +symtable = {'%pi': 'pi', '%e': 'e', '%i': 'I', '%gamma': 'euler_gamma', '%c': '_C', '%k1': '_K1', '%k2': '_K2', 'e': '_e', 'i': '_i', 'I': '_I'} maxima_qp = re.compile(r"\?\%[\w]*") # e.g., ?%jacobi_cd @@ -2490,10 +2498,8 @@ def symbolic_expression_from_maxima_string(x, equals_sub=False, maxima=maxima): sage: sefms('%inf') +Infinity """ - var_syms = {k[0]: v for k, v in symbol_table.get('maxima', {}).items() - if not _is_function(v)} - function_syms = {k[0]: v for k, v in symbol_table.get('maxima', {}).items() - if _is_function(v)} + var_syms = {k[0]: v for k, v in symbol_table.get('maxima', {}).items() if not _is_function(v)} + function_syms = {k[0]: v for k, v in symbol_table.get('maxima', {}).items() if _is_function(v)} if not x: raise RuntimeError("invalid symbolic expression -- ''") @@ -2530,16 +2536,16 @@ def symbolic_expression_from_maxima_string(x, equals_sub=False, maxima=maxima): l = [] for m in maxima_var.finditer(s): if m.group(0) in symtable: - l.append(s[cursor:m.start()]) + l.append(s[cursor : m.start()]) l.append(symtable.get(m.group(0))) cursor = m.end() if cursor > 0: l.append(s[cursor:]) s = "".join(l) - s = s.replace("%","") + s = s.replace("%", "") - s = s.replace("#","!=") # a lot of this code should be refactored somewhere... + s = s.replace("#", "!=") # a lot of this code should be refactored somewhere... # we apply the square-bracket replacing patterns repeatedly # to ensure that nested brackets get handled (from inside to out) while True: @@ -2554,16 +2560,16 @@ def symbolic_expression_from_maxima_string(x, equals_sub=False, maxima=maxima): # unfortunately, this will turn != into !==, which we correct s = s.replace("!==", "!=") - #replace %union from to_poly_solve with a list + # replace %union from to_poly_solve with a list if s[0:5] == 'union': s = s[5:] - s = s[s.find("(") + 1:s.rfind(")")] + s = s[s.find("(") + 1 : s.rfind(")")] s = "[" + s + "]" # turn it into a string that looks like a list # replace %solve from to_poly_solve with the expressions if s[0:5] == 'solve': s = s[5:] - s = s[s.find("(") + 1:s.find("]") + 1] + s = s[s.find("(") + 1 : s.find("]") + 1] # replace all instances of Maxima's scientific notation # with regular notation @@ -2633,8 +2639,7 @@ def maxima_options(**kwds): sage: sage.calculus.calculus.maxima_options(an_option=True, another=False, foo='bar') 'an_option=true,another=false,foo=bar' """ - return ','.join('%s=%s' % (key, mapped_opts(val)) - for key, val in sorted(kwds.items())) + return ','.join('%s=%s' % (key, mapped_opts(val)) for key, val in sorted(kwds.items())) # Parser for symbolic ring elements @@ -2683,6 +2688,7 @@ def _find_var(name, interface=None): # try to find the name in the global namespace # needed for identifiers like 'e', etc. import sage.all + try: return SR(sage.all.__dict__[name]) except (KeyError, TypeError): @@ -2713,6 +2719,7 @@ def _find_func(name, create_when_missing=True): return f import sage.all + try: f = SR(sage.all.__dict__[name]) if not isinstance(f, Expression): @@ -2726,10 +2733,7 @@ def _find_func(name, create_when_missing=True): parser_make_var = LookupNameMaker({}, fallback=_find_var) parser_make_function = LookupNameMaker({}, fallback=_find_func) -SR_parser = Parser(make_int=lambda x: SR(Integer(x)), - make_float=lambda x: SR(create_RealNumber(x)), - make_var=parser_make_var, - make_function=parser_make_function) +SR_parser = Parser(make_int=lambda x: SR(Integer(x)), make_float=lambda x: SR(create_RealNumber(x)), make_var=parser_make_var, make_function=parser_make_function) def symbolic_expression_from_string(s, syms=None, accept_sequence=False, *, parser=None): @@ -2782,21 +2786,13 @@ def symbolic_expression_from_string(s, syms=None, accept_sequence=False, *, pars parser = SR_parser parse_func = parser.parse_sequence if accept_sequence else parser.parse_expression # this assumes that the parser has constructors of type `LookupNameMaker` - parser._variable_constructor().set_names({k[0]: v for k, v in syms.items() - if not _is_function(v)}) - parser._callable_constructor().set_names({k[0]: v for k, v in syms.items() - if _is_function(v)}) + parser._variable_constructor().set_names({k[0]: v for k, v in syms.items() if not _is_function(v)}) + parser._callable_constructor().set_names({k[0]: v for k, v in syms.items() if _is_function(v)}) return parse_func(s) parser_make_Mvar = LookupNameMaker({}, fallback=lambda x: _find_var(x, interface='maxima')) -SRM_parser = Parser(make_int=lambda x: SR(Integer(x)), - make_float=lambda x: SR(RealDoubleElement(x)), - make_var=parser_make_Mvar, - make_function=parser_make_function) +SRM_parser = Parser(make_int=lambda x: SR(Integer(x)), make_float=lambda x: SR(RealDoubleElement(x)), make_var=parser_make_Mvar, make_function=parser_make_function) -SR_parser_giac = Parser(make_int=lambda x: SR(Integer(x)), - make_float=lambda x: SR(create_RealNumber(x)), - make_var=LookupNameMaker({}, fallback=lambda x: _find_var(x, interface='giac')), - make_function=parser_make_function) +SR_parser_giac = Parser(make_int=lambda x: SR(Integer(x)), make_float=lambda x: SR(create_RealNumber(x)), make_var=LookupNameMaker({}, fallback=lambda x: _find_var(x, interface='giac')), make_function=parser_make_function) diff --git a/src/sage/calculus/desolvers.py b/src/sage/calculus/desolvers.py index 0cc671f6962..539125cc498 100644 --- a/src/sage/calculus/desolvers.py +++ b/src/sage/calculus/desolvers.py @@ -76,7 +76,8 @@ from sage.calculus.functional import diff from sage.misc.lazy_import import lazy_import -lazy_import("sage.interfaces.maxima_lib","maxima") + +lazy_import("sage.interfaces.maxima_lib", "maxima") from sage.misc.functional import N from sage.rings.real_mpfr import RealField from sage.structure.element import Expression @@ -105,6 +106,7 @@ def fricas_desolve(de, dvar, ics, ivar): """ from sage.interfaces.fricas import fricas from sage.symbolic.ring import SR + if ics is None: y = fricas(de).solve(dvar.operator(), ivar).sage() else: @@ -114,8 +116,7 @@ def fricas_desolve(de, dvar, ics, ivar): if isinstance(y, dict): basis = y["basis"] particular = y["particular"] - return particular + sum(SR.var("_C" + str(i)) * v - for i, v in enumerate(basis)) + return particular + sum(SR.var("_C" + str(i)) * v for i, v in enumerate(basis)) return y @@ -155,6 +156,7 @@ def fricas_desolve_system(des, dvars, ics, ivar): from sage.interfaces.fricas import fricas from sage.symbolic.relation import solve from sage.symbolic.ring import SR + ops = [dvar.operator() for dvar in dvars] y = fricas(des).solve(ops, ivar).sage() basis = y["basis"] @@ -173,8 +175,7 @@ def fricas_desolve_system(des, dvars, ics, ivar): return [dvar == sol for dvar, sol in zip(dvars, sols)] -def desolve(de, dvar, ics=None, ivar=None, show_method=False, contrib_ode=False, - algorithm='maxima'): +def desolve(de, dvar, ics=None, ivar=None, show_method=False, contrib_ode=False, algorithm='maxima'): r""" Solve a 1st or 2nd order linear ODE, including IVP and BVP. @@ -573,6 +574,7 @@ def desolve(de, dvar, ics=None, ivar=None, show_method=False, contrib_ode=False, def sanitize_var(exprs): return exprs.replace("'" + dvar_str + "(" + ivar_str + ")", dvar_str) + de0 = sanitize_var(de00) ode_solver = "ode2" cmd = "(TEMP:%s(%s,%s,%s), if TEMP=false then TEMP else substitute(%s=%s(%s),TEMP))" % (ode_solver, de0, dvar_str, ivar_str, dvar_str, dvar_str, ivar_str) @@ -611,13 +613,15 @@ def sanitize_var(exprs): soln = P(cmd) if len(ics) == 3: # fixed ic2 command from Maxima - we have to ensure that %k1, %k2 do not depend on variables, should be removed when fixed in Maxima - P("ic2_sage(soln,xa,ya,dya):=block([programmode:true,backsubst:true,singsolve:true,temp,%k2,%k1,TEMP_k], \ + P( + "ic2_sage(soln,xa,ya,dya):=block([programmode:true,backsubst:true,singsolve:true,temp,%k2,%k1,TEMP_k], \ noteqn(xa), noteqn(ya), noteqn(dya), boundtest('%k1,%k1), boundtest('%k2,%k2), \ temp: lhs(soln) - rhs(soln), \ TEMP_k:solve([subst([xa,ya],soln), subst([dya,xa], lhs(dya)=-subst(0,lhs(dya),diff(temp,lhs(xa)))/diff(temp,lhs(ya)))],[%k1,%k2]), \ if not freeof(lhs(ya),TEMP_k) or not freeof(lhs(xa),TEMP_k) then return (false), \ temp: maplist(lambda([zz], subst(zz,soln)), TEMP_k), \ - if length(temp)=1 then return(first(temp)) else return(temp))") + if length(temp)=1 then return(first(temp)) else return(temp))" + ) tempic = P(ivar == ics[0]).str() tempic += "," + P(dvar == ics[1]).str() tempic += ",'diff(" + dvar_str + "," + ivar_str + ")=" + P(ics[2]).str() @@ -630,12 +634,14 @@ def sanitize_var(exprs): raise NotImplementedError("Maxima was unable to solve this IVP. Remove the initial condition to get the general solution.") if len(ics) == 4: # fixed bc2 command from Maxima - we have to ensure that %k1, %k2 do not depend on variables, should be removed when fixed in Maxima - P("bc2_sage(soln,xa,ya,xb,yb):=block([programmode:true,backsubst:true,singsolve:true,temp,%k1,%k2,TEMP_k], \ + P( + "bc2_sage(soln,xa,ya,xb,yb):=block([programmode:true,backsubst:true,singsolve:true,temp,%k1,%k2,TEMP_k], \ noteqn(xa), noteqn(ya), noteqn(xb), noteqn(yb), boundtest('%k1,%k1), boundtest('%k2,%k2), \ TEMP_k:solve([subst([xa,ya],soln), subst([xb,yb],soln)], [%k1,%k2]), \ if not freeof(lhs(ya),TEMP_k) or not freeof(lhs(xa),TEMP_k) then return (false), \ temp: maplist(lambda([zz], subst(zz,soln)),TEMP_k), \ - if length(temp)=1 then return(first(temp)) else return(temp))") + if length(temp)=1 then return(first(temp)) else return(temp))" + ) cmd = "bc2_sage(%s(%s,%s,%s),%s,%s=%s,%s,%s=%s)" % (ode_solver, de00, dvar_str, ivar_str, P(ivar == ics[0]).str(), dvar_str, P(ics[1]).str(), P(ivar == ics[2]).str(), dvar_str, P(ics[3]).str()) cmd = "(TEMP:%s,substitute(%s=%s(%s),TEMP))" % (cmd, dvar_str, dvar_str, ivar_str) cmd = sanitize_var(cmd) @@ -770,7 +776,7 @@ def sanitize_var(exprs): de0 = de._maxima_() P = de0.parent() i = dvar_str.find('(') - dvar_str = dvar_str[:i + 1] + '_SAGE_VAR_' + dvar_str[i + 1:] + dvar_str = dvar_str[: i + 1] + '_SAGE_VAR_' + dvar_str[i + 1 :] cmd = sanitize_var("desolve(" + de0.str() + "," + dvar_str + ")") soln = P(cmd).rhs() if str(soln).strip() == 'false': @@ -1173,8 +1179,8 @@ def eulers_method_2x2_plot(f, g, t0, x0, y0, h, t1): x00 = x01 t00 = t00 + h soln.append([t00, x00, y00]) - Q1 = line([[x[0], x[1]] for x in soln], rgbcolor=(.25, .125, .75)) - Q2 = line([[x[0], x[2]] for x in soln], rgbcolor=(.5, .125, .25)) + Q1 = line([[x[0], x[1]] for x in soln], rgbcolor=(0.25, 0.125, 0.75)) + Q2 = line([[x[0], x[2]] for x in soln], rgbcolor=(0.5, 0.125, 0.25)) return [Q1, Q2] @@ -1326,14 +1332,20 @@ def desolve_rk4_inner(de, dvar): lower_bound, upper_bound = desolve_rk4_determine_bounds(ics, end_points) sol_1, sol_2 = [], [] if lower_bound < ics[0]: - cmd = "rk(%s,%s,%s,[%s,%s,%s,%s])\ - " % (de0.str(), '_SAGE_VAR_' + str(dvar), str(ics[1]), '_SAGE_VAR_' + str(ivar), str(ics[0]), lower_bound, -step) + cmd = ( + "rk(%s,%s,%s,[%s,%s,%s,%s])\ + " + % (de0.str(), '_SAGE_VAR_' + str(dvar), str(ics[1]), '_SAGE_VAR_' + str(ivar), str(ics[0]), lower_bound, -step) + ) sol_1 = maxima(cmd).sage() sol_1.pop(0) sol_1.reverse() if upper_bound > ics[0]: - cmd = "rk(%s,%s,%s,[%s,%s,%s,%s])\ - " % (de0.str(), '_SAGE_VAR_' + str(dvar), str(ics[1]), '_SAGE_VAR_' + str(ivar), str(ics[0]), upper_bound, step) + cmd = ( + "rk(%s,%s,%s,[%s,%s,%s,%s])\ + " + % (de0.str(), '_SAGE_VAR_' + str(dvar), str(ics[1]), '_SAGE_VAR_' + str(ivar), str(ics[0]), upper_bound, step) + ) sol_2 = maxima(cmd).sage() sol_2.pop(0) sol = sol_1 @@ -1344,6 +1356,7 @@ def desolve_rk4_inner(de, dvar): return sol from sage.plot.plot import list_plot from sage.plot.plot_field import plot_slope_field + R = list_plot(sol, plotjoined=True, **kwds) if output == 'plot': return R @@ -1363,6 +1376,7 @@ def desolve_rk4_inner(de, dvar): from sage.calculus.functional import diff from sage.symbolic.relation import solve from sage.symbolic.ring import SR + if isinstance(de, Expression) and de.is_relational(): de = de.lhs() - de.rhs() # consider to add warning if the solution is not unique @@ -1462,14 +1476,20 @@ def desolve_system_rk4(des, vars, ics=None, ivar=None, end_points=None, step=0.1 lower_bound, upper_bound = desolve_rk4_determine_bounds(ics, end_points) sol_1, sol_2 = [], [] if lower_bound < ics[0]: - cmd = "rk(%s,%s,%s,[%s,%s,%s,%s])\ - " % (desstr, varstr, icstr, '_SAGE_VAR_' + str(ivar), str(x0), lower_bound, -step) + cmd = ( + "rk(%s,%s,%s,[%s,%s,%s,%s])\ + " + % (desstr, varstr, icstr, '_SAGE_VAR_' + str(ivar), str(x0), lower_bound, -step) + ) sol_1 = maxima(cmd).sage() sol_1.pop(0) sol_1.reverse() if upper_bound > ics[0]: - cmd = "rk(%s,%s,%s,[%s,%s,%s,%s])\ - " % (desstr, varstr, icstr, '_SAGE_VAR_' + str(ivar), str(x0), upper_bound, step) + cmd = ( + "rk(%s,%s,%s,[%s,%s,%s,%s])\ + " + % (desstr, varstr, icstr, '_SAGE_VAR_' + str(ivar), str(x0), upper_bound, step) + ) sol_2 = maxima(cmd).sage() sol_2.pop(0) sol = sol_1 @@ -1479,9 +1499,7 @@ def desolve_system_rk4(des, vars, ics=None, ivar=None, end_points=None, step=0.1 return sol -def desolve_odeint(des, ics, times, dvars, ivar=None, compute_jac=False, args=(), - rtol=None, atol=None, tcrit=None, h0=0.0, hmax=0.0, hmin=0.0, ixpr=0, - mxstep=0, mxhnil=0, mxordn=12, mxords=5, printmessg=0): +def desolve_odeint(des, ics, times, dvars, ivar=None, compute_jac=False, args=(), rtol=None, atol=None, tcrit=None, h0=0.0, hmax=0.0, hmin=0.0, ixpr=0, mxstep=0, mxhnil=0, mxordn=12, mxords=5, printmessg=0): r""" Solve numerically a system of first-order ordinary differential equations using :func:`scipy:scipy.integrate.odeint`. @@ -1653,9 +1671,7 @@ def Dfun(y, t): v.append(t) return [[element(*v) for element in row] for row in J] - return odeint(func, ics, times, args=args, Dfun=Dfun, rtol=rtol, atol=atol, - tcrit=tcrit, h0=h0, hmax=hmax, hmin=hmin, ixpr=ixpr, mxstep=mxstep, - mxhnil=mxhnil, mxordn=mxordn, mxords=mxords, printmessg=printmessg) + return odeint(func, ics, times, args=args, Dfun=Dfun, rtol=rtol, atol=atol, tcrit=tcrit, h0=h0, hmax=hmax, hmin=hmin, ixpr=ixpr, mxstep=mxstep, mxhnil=mxhnil, mxordn=mxordn, mxords=mxords, printmessg=printmessg) if isinstance(dvars, Expression) and dvars.is_symbol(): dvars = [dvars] @@ -1671,6 +1687,7 @@ def Dfun(y, t): return desolve_odeint_inner(next(iter(ivars))) if not ivars: from sage.symbolic.ring import SR + with SR.temp_var() as ivar: return desolve_odeint_inner(ivar) else: @@ -1739,23 +1756,19 @@ def desolve_mintides(f, ics, initial, final, delta, tolrel=1e-16, tolabs=1e-16): `_ """ import subprocess + if subprocess.call('command -v gcc', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE): raise RuntimeError('Unable to run because gcc cannot be found') from sage.interfaces.tides import genfiles_mintides from sage.misc.temporary_file import tmp_dir + tempdir = tmp_dir() intfile = os.path.join(tempdir, 'integrator.c') drfile = os.path.join(tempdir, 'driver.c') fileoutput = os.path.join(tempdir, 'output') runmefile = os.path.join(tempdir, 'runme') - genfiles_mintides(intfile, drfile, f, [N(_) for _ in ics], - N(initial), N(final), N(delta), N(tolrel), - N(tolabs), fileoutput) - subprocess.check_call('gcc -o ' + runmefile + ' ' + os.path.join(tempdir, '*.c ') + - os.path.join('$SAGE_LOCAL', 'lib', 'libTIDES.a') + ' $LDFLAGS ' - + os.path.join('-L$SAGE_LOCAL', 'lib ') + ' -lm -O2 ' + - os.path.join('-I$SAGE_LOCAL', 'include '), - shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + genfiles_mintides(intfile, drfile, f, [N(_) for _ in ics], N(initial), N(final), N(delta), N(tolrel), N(tolabs), fileoutput) + subprocess.check_call('gcc -o ' + runmefile + ' ' + os.path.join(tempdir, '*.c ') + os.path.join('$SAGE_LOCAL', 'lib', 'libTIDES.a') + ' $LDFLAGS ' + os.path.join('-L$SAGE_LOCAL', 'lib ') + ' -lm -O2 ' + os.path.join('-I$SAGE_LOCAL', 'include '), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) subprocess.check_call(os.path.join(tempdir, 'runme'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) with open(fileoutput) as outfile: res = outfile.readlines() @@ -1833,29 +1846,25 @@ def desolve_tides_mpfr(f, ics, initial, final, delta, tolrel=1e-16, tolabs=1e-16 - [ABBR2012]_ """ import subprocess + if subprocess.call('command -v gcc', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE): raise RuntimeError('Unable to run because gcc cannot be found') from sage.functions.log import log from sage.functions.other import ceil from sage.interfaces.tides import genfiles_mpfr from sage.misc.temporary_file import tmp_dir + tempdir = tmp_dir() intfile = os.path.join(tempdir, 'integrator.c') drfile = os.path.join(tempdir, 'driver.c') fileoutput = os.path.join(tempdir, 'output') runmefile = os.path.join(tempdir, 'runme') - genfiles_mpfr(intfile, drfile, f, ics, initial, final, delta, [], [], - digits, tolrel, tolabs, fileoutput) - subprocess.check_call('gcc -o ' + runmefile + ' ' + os.path.join(tempdir, '*.c ') + - os.path.join('$SAGE_LOCAL', 'lib', 'libTIDES.a') + ' $LDFLAGS ' - + os.path.join('-L$SAGE_LOCAL', 'lib ') + '-lmpfr -lgmp -lm -O2 -w ' + - os.path.join('-I$SAGE_LOCAL', 'include '), - shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + genfiles_mpfr(intfile, drfile, f, ics, initial, final, delta, [], [], digits, tolrel, tolabs, fileoutput) + subprocess.check_call('gcc -o ' + runmefile + ' ' + os.path.join(tempdir, '*.c ') + os.path.join('$SAGE_LOCAL', 'lib', 'libTIDES.a') + ' $LDFLAGS ' + os.path.join('-L$SAGE_LOCAL', 'lib ') + '-lmpfr -lgmp -lm -O2 -w ' + os.path.join('-I$SAGE_LOCAL', 'include '), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) subprocess.check_call(os.path.join(tempdir, 'runme'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) with open(fileoutput) as outfile: res = outfile.readlines() for i in range(len(res)): - res[i] = [RealField(ceil(digits * log(10, 2)))(piece) - for piece in res[i].split(' ') if len(piece) > 2] + res[i] = [RealField(ceil(digits * log(10, 2)))(piece) for piece in res[i].split(' ') if len(piece) > 2] shutil.rmtree(tempdir) return res diff --git a/src/sage/calculus/expr.py b/src/sage/calculus/expr.py index aa8d498060e..8ff2c6b8175 100644 --- a/src/sage/calculus/expr.py +++ b/src/sage/calculus/expr.py @@ -185,13 +185,13 @@ def symbolic_expression(x): return matrix(rows) if callable(x): from inspect import signature, Parameter + try: s = signature(x) except ValueError: pass else: - if all(param.kind in (Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD) - for param in s.parameters.values()): + if all(param.kind in (Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD) for param in s.parameters.values()): vars = [SR.var(name) for name in s.parameters.keys()] result = x(*vars) if isinstance(result, (tuple, list)): diff --git a/src/sage/calculus/functional.py b/src/sage/calculus/functional.py index 12210e8a3ae..f44d481e9ca 100644 --- a/src/sage/calculus/functional.py +++ b/src/sage/calculus/functional.py @@ -165,6 +165,7 @@ def derivative(f, *args, **kwds): pass if not isinstance(f, Expression): from sage.symbolic.ring import SR + f = SR(f) return f.derivative(*args, **kwds) @@ -316,6 +317,7 @@ def integral(f, *args, **kwds): if not isinstance(f, Expression): from sage.symbolic.ring import SR + f = SR(f) return f.integral(*args, **kwds) @@ -372,6 +374,7 @@ def limit(f, dir=None, taylor=False, **argv): """ if not isinstance(f, Expression): from sage.symbolic.ring import SR + f = SR(f) return f.limit(dir=dir, taylor=taylor, **argv) @@ -419,6 +422,7 @@ def taylor(f, *args): """ if not isinstance(f, Expression): from sage.symbolic.ring import SR + f = SR(f) return f.taylor(*args) diff --git a/src/sage/calculus/functions.py b/src/sage/calculus/functions.py index 46479be8b0b..5d354ffde8c 100644 --- a/src/sage/calculus/functions.py +++ b/src/sage/calculus/functions.py @@ -92,6 +92,7 @@ def wronskian(*args): def row(n): return [diff(f, v, n) for f in fs] + else: # if the last argument is not a variable, just run # .derivative on everything @@ -99,6 +100,7 @@ def row(n): def row(n): return [diff(f, n) for f in fs] + # NOTE: I rewrote the below as two lines to avoid a possible subtle # memory management problem on some platforms (only VMware as far # as we know?). See trac #2990. @@ -138,8 +140,7 @@ def jacobian(functions, variables): [ cos(x)*cos(y) -sin(x)*sin(y)] [ 0 e^x] """ - if isinstance(functions, Matrix) and (functions.nrows() == 1 - or functions.ncols() == 1): + if isinstance(functions, Matrix) and (functions.nrows() == 1 or functions.ncols() == 1): functions = functions.list() elif not isinstance(functions, (tuple, list, Vector)): functions = [functions] diff --git a/src/sage/calculus/transforms/all.py b/src/sage/calculus/transforms/all.py index c42ae401653..4e9610900fc 100644 --- a/src/sage/calculus/transforms/all.py +++ b/src/sage/calculus/transforms/all.py @@ -3,4 +3,5 @@ lazy_import("sage.calculus.transforms.fft", ["FastFourierTransform", "FFT"]) lazy_import("sage.calculus.transforms.dwt", ["WaveletTransform", "DWT"]) from sage.calculus.transforms.dft import IndexedSequence + del lazy_import diff --git a/src/sage/calculus/transforms/dft.py b/src/sage/calculus/transforms/dft.py index bccfbcb8017..ff97cefd71a 100644 --- a/src/sage/calculus/transforms/dft.py +++ b/src/sage/calculus/transforms/dft.py @@ -64,6 +64,7 @@ - William Stein (2006-11) -- fix many bugs """ + ########################################################################## # Copyright (C) 2006 David Joyner # @@ -99,6 +100,7 @@ class IndexedSequence(SageObject): containing the same number of elements as ``self``, which is a list of elements taken from a field """ + def __init__(self, L, index_object): r""" Initialize ``self``. @@ -243,17 +245,13 @@ def plot_histogram(self, clr=(0, 0, 1), eps=0.4): sage: show(P) # not tested # needs sage.plot """ from sage.rings.real_mpfr import RR + # elements must be coercible into RR I = self.index_object() N = len(I) S = self.list() - P = [polygon([[RR(I[i]) - eps, 0], - [RR(I[i]) - eps, RR(S[i])], - [RR(I[i]) + eps, RR(S[i])], - [RR(I[i]) + eps, 0], - [RR(I[i]), 0]], rgbcolor=clr) for i in range(N)] - T = [text(str(I[i]), (RR(I[i]), -0.8), fontsize=15, rgbcolor=(1, 0, 0)) - for i in range(N)] + P = [polygon([[RR(I[i]) - eps, 0], [RR(I[i]) - eps, RR(S[i])], [RR(I[i]) + eps, RR(S[i])], [RR(I[i]) + eps, 0], [RR(I[i]), 0]], rgbcolor=clr) for i in range(N)] + T = [text(str(I[i]), (RR(I[i]), -0.8), fontsize=15, rgbcolor=(1, 0, 0)) for i in range(N)] return sum(P) + sum(T) def plot(self): @@ -272,6 +270,7 @@ def plot(self): sage: show(P) # not tested # needs sage.plot """ from sage.rings.real_mpfr import RR + # elements must be coercible into RR I = self.index_object() S = self.list() @@ -346,27 +345,26 @@ def dft(self, chi=None): """ if chi is None: chi = lambda x: x - J = self.index_object() # index set of length N + J = self.index_object() # index set of length N N = len(J) S = self.list() - F = self.base_ring() # elements must be coercible into QQ(zeta_N) + F = self.base_ring() # elements must be coercible into QQ(zeta_N) if J[0] not in ZZ: G = J[0].parent() # if J is not a range it is a group G if J[0] in ZZ and F.base_ring().fraction_field() == QQ: # assumes J is range(N) zeta = CyclotomicField(N).gen() - FT = [sum([S[i] * chi(zeta**(i * j)) for i in J]) for j in J] + FT = [sum([S[i] * chi(zeta ** (i * j)) for i in J]) for j in J] elif (J[0] not in ZZ) and G.is_abelian() and F == ZZ or (F.is_field() and F.base_ring() == QQ): if isinstance(J[0], PermutationGroupElement): # J is a CyclicPermGp n = G.order() a = list(n.factor()) - invs = [x[0]**x[1] for x in a] + invs = [x[0] ** x[1] for x in a] G = AbelianGroup(len(a), invs) # assumes J is AbelianGroup(...) Gd = G.dual_group() - FT = [sum([S[i] * chid(G.list()[i]) for i in range(N)]) - for chid in Gd] + FT = [sum([S[i] * chid(G.list()[i]) for i in range(N)]) for chid in Gd] elif (J[0] not in ZZ) and G.is_finite() and F == ZZ or (F.is_field() and F.base_ring() == QQ): # assumes J is the list of conj class representatives of a # PermutationGroup(...) or Matrixgroup(...) @@ -394,12 +392,12 @@ def idft(self): sage: it == s # needs sage.rings.number_field True """ - F = self.base_ring() # elements must be coercible into QQ(zeta_N) - J = self.index_object() # must be = range(N) + F = self.base_ring() # elements must be coercible into QQ(zeta_N) + J = self.index_object() # must be = range(N) N = len(J) S = self.list() zeta = CyclotomicField(N).gen() - iFT = [sum([S[i] * zeta**(-i * j) for i in J]) for j in J] + iFT = [sum([S[i] * zeta ** (-i * j) for i in J]) for j in J] if (J[0] not in ZZ) or F.base_ring().fraction_field() != QQ: raise NotImplementedError("Sorry this type of idft is not implemented yet.") return IndexedSequence(iFT, J) * (Integer(1) / N) @@ -417,14 +415,15 @@ def dct(self): Indexed sequence: [0, 1/16*(sqrt(5) + I*sqrt(-2*sqrt(5) + 10) + ... indexed by [0, 1, 2, 3, 4] """ - F = self.base_ring() # elements must be coercible into RR + F = self.base_ring() # elements must be coercible into RR try: pi = F.pi() except AttributeError: from sage.symbolic.constants import pi + pi = F(pi) - J = self.index_object() # must be = range(N) + J = self.index_object() # must be = range(N) N = len(J) S = self.list() PI = 2 * pi / N @@ -446,14 +445,15 @@ def dst(self): Indexed sequence: [0.000000000000000, 1.11022302462516e-16 - 2.50000000000000*I, ...] indexed by [0, 1, 2, 3, 4] """ - F = self.base_ring() # elements must be coercible into RR + F = self.base_ring() # elements must be coercible into RR try: pi = F.pi() except AttributeError: from sage.symbolic.constants import pi + pi = F(pi) - J = self.index_object() # must be = range(N) + J = self.index_object() # must be = range(N) N = len(J) S = self.list() PI = 2 * F(pi) / N @@ -503,18 +503,17 @@ def convolution(self, other): raise TypeError("IndexedSequences must have same index set") M = len(S) N = len(T) - if M < N: # first, extend by 0 if necessary + if M < N: # first, extend by 0 if necessary a = [S[i] for i in range(M)] + [F(0) for i in range(2 * N)] b = T + [E(0) for i in range(2 * M)] - if M > N: # python trick - a[-j] is really j from the *right* + if M > N: # python trick - a[-j] is really j from the *right* b = [T[i] for i in range(N)] + [E(0) for i in range(2 * M)] a = S + [F(0) for i in range(2 * M)] - if M == N: # so need only extend by 0 to the *right* + if M == N: # so need only extend by 0 to the *right* a = S + [F(0) for i in range(2 * M)] b = T + [E(0) for i in range(2 * M)] N = max(M, N) - return [sum([a[i] * b[j - i] for i in range(N)]) - for j in range(2 * N - 1)] + return [sum([a[i] * b[j - i] for i in range(N)]) for j in range(2 * N - 1)] def convolution_periodic(self, other): r""" @@ -559,7 +558,7 @@ def convolution_periodic(self, other): raise TypeError("IndexedSequences must have same index set") M = len(S) N = len(T) - if M < N: # first, extend by 0 if necessary + if M < N: # first, extend by 0 if necessary a = [S[i] for i in range(M)] + [F(0) for i in range(N - M)] b = other if M > N: @@ -569,8 +568,7 @@ def convolution_periodic(self, other): a = S b = T N = max(M, N) - return [sum([a[i] * b[(j - i) % N] for i in range(N)]) - for j in range(2 * N - 1)] + return [sum([a[i] * b[(j - i) % N] for i in range(N)]) for j in range(2 * N - 1)] def __mul__(self, other): """ @@ -620,7 +618,7 @@ def __eq__(self, other): return False for i in I: try: - if abs(S[i] - T[i]) > 10**(-8): + if abs(S[i] - T[i]) > 10 ** (-8): # tests if they differ as reals -- WHY 10^(-8)??? return False except TypeError: @@ -650,10 +648,11 @@ def fft(self): indexed by [0, 1, 2, 3, 4] """ from sage.rings.cc import CC + I = CC.gen() # elements must be coercible into RR - J = self.index_object() # must be = range(N) + J = self.index_object() # must be = range(N) N = len(J) S = self.list() a = FastFourierTransform(N) @@ -687,10 +686,11 @@ def ifft(self): 1 """ from sage.rings.cc import CC + I = CC.gen() # elements must be coercible into RR - J = self.index_object() # must be = range(N) + J = self.index_object() # must be = range(N) N = len(J) S = self.list() a = FastFourierTransform(N) @@ -739,9 +739,10 @@ def dwt(self, other='haar', wavelet_k=2): indexed by [0, 1, 2, 3, 4, 5, 6, 7] """ from sage.rings.real_mpfr import RR + # elements must be coercible into RR - J = self.index_object() # must be = range(N) - N = len(J) # must be 1 minus a power of 2 + J = self.index_object() # must be = range(N) + N = len(J) # must be 1 minus a power of 2 S = self.list() if other == "haar" or other == "haar_centered": if wavelet_k in [2]: @@ -817,9 +818,10 @@ def idwt(self, other='haar', wavelet_k=2): True """ from sage.rings.real_mpfr import RR + # elements must be coercible into RR - J = self.index_object() # must be = range(N) - N = len(J) # must be 1 minus a power of 2 + J = self.index_object() # must be = range(N) + N = len(J) # must be 1 minus a power of 2 S = self.list() k = wavelet_k if other == "haar" or other == "haar_centered": diff --git a/src/sage/categories/additive_groups.py b/src/sage/categories/additive_groups.py index 4b36c97d863..8bd28ce81bf 100644 --- a/src/sage/categories/additive_groups.py +++ b/src/sage/categories/additive_groups.py @@ -1,18 +1,20 @@ r""" Additive groups """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2013 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.lazy_import import LazyImport from sage.categories.category_with_axiom import CategoryWithAxiom_singleton, CategoryWithAxiom from sage.categories.algebra_functor import AlgebrasCategory from sage.categories.additive_monoids import AdditiveMonoids from sage.cpython.getattr import raw_getattr + Groups = LazyImport('sage.categories.groups', 'Groups', at_startup=True) @@ -53,6 +55,7 @@ class AdditiveGroups(CategoryWithAxiom_singleton): sage: C = AdditiveGroups() sage: TestSuite(C).run() """ + _base_category_class_and_axiom = (AdditiveMonoids, "AdditiveInverse") class Algebras(AlgebrasCategory): diff --git a/src/sage/categories/additive_magmas.py b/src/sage/categories/additive_magmas.py index 23209f2d9ea..718335e77c0 100644 --- a/src/sage/categories/additive_magmas.py +++ b/src/sage/categories/additive_magmas.py @@ -1,6 +1,7 @@ r""" Additive magmas """ + # **************************************************************************** # Copyright (C) 2010-2014 Nicolas M. Thiery # @@ -388,8 +389,8 @@ def addition_table(self, names='letters', elements=None): import operator from sage.matrix.operation_table import OperationTable - return OperationTable(self, operation=operator.add, - names=names, elements=elements) + + return OperationTable(self, operation=operator.add, names=names, elements=elements) class ElementMethods: @@ -485,9 +486,7 @@ def _add_(self, right): sage: 4 * x (4, 0) """ - return self.parent()._cartesian_product_of_elements( - x + y for x, y in zip(self.cartesian_factors(), - right.cartesian_factors())) + return self.parent()._cartesian_product_of_elements(x + y for x, y in zip(self.cartesian_factors(), right.cartesian_factors())) class Algebras(AlgebrasCategory): @@ -503,6 +502,7 @@ def extra_super_categories(self): Category of set algebras over Rational Field] """ from sage.categories.magmatic_algebras import MagmaticAlgebras + return [MagmaticAlgebras(self.base_ring()).WithBasis()] class ParentMethods: @@ -594,6 +594,7 @@ def extra_super_categories(self): Category of commutative magmas] """ from sage.categories.magmas import Magmas + return [Magmas().Commutative()] class AdditiveUnital(CategoryWithAxiom): @@ -893,6 +894,7 @@ def zero(self): sage: TestSuite(f).run() """ from sage.misc.constant_function import ConstantFunction + return self(ConstantFunction(self.codomain().zero())) class AdditiveInverse(CategoryWithAxiom): @@ -930,8 +932,7 @@ def _neg_(self): sage: x.parent() in C True """ - return self.parent()._cartesian_product_of_elements( - [-x for x in self.cartesian_factors()]) + return self.parent()._cartesian_product_of_elements([-x for x in self.cartesian_factors()]) class CartesianProducts(CartesianProductsCategory): def extra_super_categories(self): @@ -959,8 +960,7 @@ def zero(self): sage: GF(8, 'x').cartesian_product(GF(5)).zero() # needs sage.rings.finite_rings (0, 0) """ - return self._cartesian_product_of_elements( - _.zero() for _ in self.cartesian_factors()) + return self._cartesian_product_of_elements(_.zero() for _ in self.cartesian_factors()) class Algebras(AlgebrasCategory): @@ -977,6 +977,7 @@ def extra_super_categories(self): Category of unital algebras with basis over Rational Field] """ from sage.categories.magmas import Magmas + return [Magmas().Unital()] class ParentMethods: diff --git a/src/sage/categories/additive_monoids.py b/src/sage/categories/additive_monoids.py index 51553317926..d50c7ecd2a3 100644 --- a/src/sage/categories/additive_monoids.py +++ b/src/sage/categories/additive_monoids.py @@ -1,12 +1,13 @@ r""" Additive monoids """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2013-2014 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.lazy_import import LazyImport from sage.categories.category_with_axiom import CategoryWithAxiom_singleton @@ -42,6 +43,7 @@ class AdditiveMonoids(CategoryWithAxiom_singleton): True sage: TestSuite(C).run() """ + _base_category_class_and_axiom = (AdditiveSemigroups, "AdditiveUnital") AdditiveCommutative = LazyImport('sage.categories.commutative_additive_monoids', 'CommutativeAdditiveMonoids', at_startup=True) @@ -84,6 +86,7 @@ def sum(self, args): 0 """ from sage.misc.misc_c import balanced_sum + return balanced_sum(args, self.zero(), 20) class Homsets(HomsetsCategory): diff --git a/src/sage/categories/additive_semigroups.py b/src/sage/categories/additive_semigroups.py index 038221fe5be..6c9dc2411cf 100644 --- a/src/sage/categories/additive_semigroups.py +++ b/src/sage/categories/additive_semigroups.py @@ -1,6 +1,7 @@ r""" Additive semigroups """ + # **************************************************************************** # Copyright (C) 2013 Nicolas M. Thiery # @@ -48,6 +49,7 @@ class AdditiveSemigroups(CategoryWithAxiom_singleton): sage: TestSuite(C).run() """ + _base_category_class_and_axiom = (AdditiveMagmas, "AdditiveAssociative") AdditiveCommutative = LazyImport('sage.categories.commutative_additive_semigroups', 'CommutativeAdditiveSemigroups', at_startup=True) @@ -82,6 +84,7 @@ def _test_additive_associativity(self, **options): tester = self._tester(**options) S = tester.some_elements() from sage.misc.misc import some_tuples + for x, y, z in some_tuples(S, 3, tester._max_runs): tester.assertEqual((x + y) + z, x + (y + z)) @@ -134,6 +137,7 @@ def extra_super_categories(self): Category of additive commutative additive magma algebras over Rational Field] """ from sage.categories.semigroups import Semigroups + return [Semigroups()] class ParentMethods: diff --git a/src/sage/categories/affine_weyl_groups.py b/src/sage/categories/affine_weyl_groups.py index 1e58ac9231d..9927d5aa341 100644 --- a/src/sage/categories/affine_weyl_groups.py +++ b/src/sage/categories/affine_weyl_groups.py @@ -1,6 +1,7 @@ r""" Affine Weyl groups """ + # ***************************************************************************** # Copyright (C) 2009 Nicolas M. Thiery # @@ -126,13 +127,10 @@ def succ(pair): u, length = pair for i in u.descents(positive=True, side='left'): u1 = u.apply_simple_reflection(i, "left") - if (length < k and i == u1.first_descent(side='left') and - u1.is_affine_grassmannian()): + if length < k and i == u1.first_descent(side='left') and u1.is_affine_grassmannian(): yield (u1, length + 1) - return RecursivelyEnumeratedSet_forest(((self.one(), 0),), succ, algorithm='breadth', - category=FiniteEnumeratedSets(), - post_process=select_length) + return RecursivelyEnumeratedSet_forest(((self.one(), 0),), succ, algorithm='breadth', category=FiniteEnumeratedSets(), post_process=select_length) class ElementMethods: def is_affine_grassmannian(self) -> bool: @@ -199,6 +197,7 @@ def affine_grassmannian_to_core(self): """ from sage.combinat.partition import Partition from sage.combinat.core import Core + if not self.is_affine_grassmannian() or not self.parent().cartan_type().letter == 'A': raise ValueError("this only works on type 'A' affine Grassmannian elements") out = Partition([]) diff --git a/src/sage/categories/algebra_functor.py b/src/sage/categories/algebra_functor.py index 6be9a376aad..797c6ecb500 100644 --- a/src/sage/categories/algebra_functor.py +++ b/src/sage/categories/algebra_functor.py @@ -478,6 +478,7 @@ class AlgebraFunctor(CovariantFunctorialConstruction): Algebra of Dihedral group of order 6 as a permutation group over Rational Field """ + _functor_name = "algebra" _functor_category = "Algebras" @@ -491,6 +492,7 @@ def __init__(self, base_ring): sage: TestSuite(F).run() """ from sage.categories.rings import Rings + assert base_ring in Rings() self._base_ring = base_ring @@ -556,6 +558,7 @@ class GroupAlgebraFunctor(ConstructionFunctor): sage: A is KleinFourGroup().algebra(QQ) True """ + def __init__(self, group): r""" See :class:`GroupAlgebraFunctor` for full documentation. @@ -568,6 +571,7 @@ def __init__(self, group): """ self.__group = group from sage.categories.rings import Rings + ConstructionFunctor.__init__(self, Rings(), Rings()) def group(self): @@ -629,12 +633,12 @@ def _apply_functor_to_morphism(self, f): 2*() + 2*(2,3) + (1,2,3) + 4*(1,3,2) """ from sage.categories.rings import Rings + domain = self(f.domain()) codomain = self(f.codomain()) # we would want to use something like: # domain.module_morphism(on_coefficients=h, codomain=codomain, category=Rings()) - return SetMorphism(domain.Hom(codomain, category=Rings()), - lambda x: codomain.sum_of_terms((g, f(c)) for (g, c) in x)) + return SetMorphism(domain.Hom(codomain, category=Rings()), lambda x: codomain.sum_of_terms((g, f(c)) for (g, c) in x)) class AlgebrasCategory(CovariantConstructionCategory, Category_over_base_ring): @@ -674,8 +678,7 @@ def _repr_object_names(self): sage: Semigroups().Algebras(QQ) # indirect doctest Category of semigroup algebras over Rational Field """ - return "{} algebras over {}".format(self.base_category()._repr_object_names()[:-1], - self.base_ring()) + return "{} algebras over {}".format(self.base_category()._repr_object_names()[:-1], self.base_ring()) @staticmethod def __classcall__(cls, category=None, R=None): @@ -739,5 +742,6 @@ def coproduct_on_basis(self, g): 3*B[[1, 1, 1, 3]] # B[[1, 1, 1, 3]] """ from sage.categories.tensor import tensor + g = self.term(g) return tensor([g, g]) diff --git a/src/sage/categories/algebra_ideals.py b/src/sage/categories/algebra_ideals.py index a3ea866a42b..4ee7014581f 100644 --- a/src/sage/categories/algebra_ideals.py +++ b/src/sage/categories/algebra_ideals.py @@ -1,6 +1,7 @@ r""" Algebra ideals """ + # **************************************************************************** # Copyright (C) 2005 David Kohel # William Stein @@ -35,6 +36,7 @@ class AlgebraIdeals(Category_ideal): ``AlgebraRightIdeals`` of which ``AlgebraIdeals`` would be a subcategory. """ + def __init__(self, A): """ EXAMPLES:: diff --git a/src/sage/categories/algebra_modules.py b/src/sage/categories/algebra_modules.py index 86922f3c0dd..eea63da2280 100644 --- a/src/sage/categories/algebra_modules.py +++ b/src/sage/categories/algebra_modules.py @@ -1,14 +1,15 @@ r""" Algebra modules """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2005 David Kohel # William Stein # 2008-2009 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category_types import Category_module from sage.categories.commutative_algebras import CommutativeAlgebras @@ -32,6 +33,7 @@ class AlgebraModules(Category_module): and use cases for potential generalizations to the non commutative case are welcome. """ + def __init__(self, A): """ EXAMPLES:: @@ -73,6 +75,7 @@ def an_instance(cls): Category of algebra modules over Univariate Polynomial Ring in x over Rational Field """ from sage.rings.rational_field import QQ + return cls(QQ['x']) def algebra(self): diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index 9fe03c5c309..1d6f8a2478b 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -6,6 +6,7 @@ - David Kohel & William Stein (2005): initial revision - Nicolas M. Thiery (2008-2011): rewrote for the category framework """ + # **************************************************************************** # Copyright (C) 2005 David Kohel # William Stein @@ -56,6 +57,7 @@ class Algebras(CategoryWithAxiom_over_base_ring): sage: TestSuite(Algebras(ZZ)).run() """ + _base_category_class_and_axiom = (AssociativeAlgebras, 'Unital') # For backward compatibility? @@ -103,6 +105,7 @@ def Semisimple(self): Category of finite dimensional semisimple algebras with basis over Rational Field """ from sage.categories.semisimple_algebras import SemisimpleAlgebras + return self & SemisimpleAlgebras(self.base_ring()) @cached_method @@ -126,20 +129,14 @@ def Supercommutative(self): """ return self.Super().Supercommutative() - Commutative = LazyImport('sage.categories.commutative_algebras', - 'CommutativeAlgebras', at_startup=True) - Filtered = LazyImport('sage.categories.filtered_algebras', - 'FilteredAlgebras') - Graded = LazyImport('sage.categories.graded_algebras', - 'GradedAlgebras') - Super = LazyImport('sage.categories.super_algebras', - 'SuperAlgebras') + Commutative = LazyImport('sage.categories.commutative_algebras', 'CommutativeAlgebras', at_startup=True) + Filtered = LazyImport('sage.categories.filtered_algebras', 'FilteredAlgebras') + Graded = LazyImport('sage.categories.graded_algebras', 'GradedAlgebras') + Super = LazyImport('sage.categories.super_algebras', 'SuperAlgebras') # at_startup currently needed for MatrixSpace, see #22955 (e.g., comment:20) - WithBasis = LazyImport('sage.categories.algebras_with_basis', - 'AlgebrasWithBasis', at_startup=True) + WithBasis = LazyImport('sage.categories.algebras_with_basis', 'AlgebrasWithBasis', at_startup=True) # if/when Semisimple becomes an axiom - Semisimple = LazyImport('sage.categories.semisimple_algebras', - 'SemisimpleAlgebras') + Semisimple = LazyImport('sage.categories.semisimple_algebras', 'SemisimpleAlgebras') class ParentMethods: def characteristic(self): @@ -183,7 +180,7 @@ def has_standard_involution(self) -> bool: Traceback (most recent call last): ... NotImplementedError: has_standard_involution is not implemented for this algebra - """ + """ field = self.base_ring() try: basis = self.basis() @@ -212,7 +209,7 @@ def has_standard_involution(self) -> bool: b = ej**2 coef = b.coefficient_tuple() tj = coef[j] - nij = (ei + ej)**2 - (ti + tj) * (ei + ej) + nij = (ei + ej) ** 2 - (ti + tj) * (ei + ej) if nij not in field: return False except AttributeError: @@ -280,6 +277,7 @@ class CartesianProducts(CartesianProductsCategory): - http://groups.google.fr/group/sage-devel/browse_thread/thread/35a72b1d0a2fc77a/348f42ae77a66d16#348f42ae77a66d16 - :wikipedia:`Direct_product` """ + def extra_super_categories(self): """ A Cartesian product of algebras is endowed with a natural @@ -345,4 +343,5 @@ def extra_super_categories(self): See :issue:`15647`. """ from sage.categories.coalgebras import Coalgebras + return [Coalgebras(self.base_category().base_ring())] diff --git a/src/sage/categories/algebras_with_basis.py b/src/sage/categories/algebras_with_basis.py index a0c21058318..26553b935c9 100644 --- a/src/sage/categories/algebras_with_basis.py +++ b/src/sage/categories/algebras_with_basis.py @@ -1,6 +1,7 @@ r""" Algebras With Basis """ + # **************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2008-2013 Nicolas M. Thiery @@ -119,6 +120,7 @@ def example(self, alphabet=('a', 'b', 'c')): the free algebra on the generators (1, 2, 3) over Rational Field """ from sage.categories.examples.algebras_with_basis import Example + return Example(self.base_ring(), alphabet) Filtered = LazyImport('sage.categories.filtered_algebras_with_basis', 'FilteredAlgebrasWithBasis') @@ -152,6 +154,7 @@ def hochschild_complex(self, M): sage: H = SGA.hochschild_complex(T) """ from sage.homology.hochschild_complex import HochschildComplex + return HochschildComplex(self, M) class ElementMethods: @@ -364,11 +367,11 @@ def product_on_basis(self, t1, t2): TODO: optimize this implementation! """ - return tensor(module.monomial(x1) * module.monomial(x2) - for module, x1, x2 in zip(self._sets, t1, t2)) + return tensor(module.monomial(x1) * module.monomial(x2) for module, x1, x2 in zip(self._sets, t1, t2)) class ElementMethods: """ Implement operations on elements of tensor products of algebras with basis """ + pass diff --git a/src/sage/categories/all.py b/src/sage/categories/all.py index dd900818706..ecf1ef6d832 100644 --- a/src/sage/categories/all.py +++ b/src/sage/categories/all.py @@ -23,8 +23,10 @@ - :mod:`sage.categories.tensor` - :mod:`sage.categories.dual` """ + # install the docstring of this module to the containing package from sage.misc.namespace_package import install_doc + install_doc(__package__, __doc__) from sage.categories import primer @@ -46,12 +48,9 @@ from sage.categories.cartesian_product import cartesian_product -from sage.categories.functor import (ForgetfulFunctor, - IdentityFunctor) +from sage.categories.functor import ForgetfulFunctor, IdentityFunctor -from sage.categories.homset import (Hom, hom, - End, end, - Homset, HomsetWithBase) +from sage.categories.homset import Hom, hom, End, end, Homset, HomsetWithBase from sage.categories.morphism import Morphism @@ -104,6 +103,7 @@ from sage.categories.bimodules import Bimodules from sage.categories.modules import Modules + RingModules = Modules from sage.categories.vector_spaces import VectorSpaces @@ -122,6 +122,7 @@ # ideals from sage.categories.ring_ideals import RingIdeals + Ideals = RingIdeals from sage.categories.commutative_ring_ideals import CommutativeRingIdeals from sage.categories.algebra_modules import AlgebraModules @@ -134,6 +135,7 @@ # * with basis from sage.categories.modules_with_basis import ModulesWithBasis + FreeModules = ModulesWithBasis from sage.categories.hecke_modules import HeckeModules from sage.categories.algebras_with_basis import AlgebrasWithBasis @@ -164,6 +166,7 @@ # Coxeter groups from sage.categories.coxeter_groups import CoxeterGroups + lazy_import('sage.categories.finite_coxeter_groups', 'FiniteCoxeterGroups') from sage.categories.weyl_groups import WeylGroups from sage.categories.finite_weyl_groups import FiniteWeylGroups diff --git a/src/sage/categories/aperiodic_semigroups.py b/src/sage/categories/aperiodic_semigroups.py index 034e23b5eee..2b4afa4a4aa 100644 --- a/src/sage/categories/aperiodic_semigroups.py +++ b/src/sage/categories/aperiodic_semigroups.py @@ -1,7 +1,8 @@ r""" Aperiodic semigroups """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2016 Nicolas M. Thiéry # # This program is free software: you can redistribute it and/or modify @@ -9,7 +10,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.semigroups import Semigroups diff --git a/src/sage/categories/associative_algebras.py b/src/sage/categories/associative_algebras.py index 268c9054e97..90a452cc0a4 100644 --- a/src/sage/categories/associative_algebras.py +++ b/src/sage/categories/associative_algebras.py @@ -1,6 +1,7 @@ r""" Associative algebras """ + # **************************************************************************** # Copyright (C) 2011 Nicolas M. Thiery # @@ -41,6 +42,7 @@ class AssociativeAlgebras(CategoryWithAxiom_over_base_ring): True sage: TestSuite(C).run() """ + _base_category_class_and_axiom = (MagmaticAlgebras, "Associative") Unital = LazyImport('sage.categories.algebras', 'Algebras', at_startup=True) diff --git a/src/sage/categories/basic.py b/src/sage/categories/basic.py index 460f36a953f..053c4769a66 100644 --- a/src/sage/categories/basic.py +++ b/src/sage/categories/basic.py @@ -2,6 +2,7 @@ A subset of sage.categories.all with just the basic categories needed for sage startup (i.e. to define ZZ, QQ, ...). """ + # ***************************************************************************** # Copyright (C) 2008-2009 Nicolas M. Thiery # diff --git a/src/sage/categories/bialgebras_with_basis.py b/src/sage/categories/bialgebras_with_basis.py index 03d4ed28bec..fdb1dbed4d2 100644 --- a/src/sage/categories/bialgebras_with_basis.py +++ b/src/sage/categories/bialgebras_with_basis.py @@ -1,6 +1,7 @@ r""" Bialgebras with basis """ + # **************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # Copyright (C) 2008-2011 Nicolas M. Thiery @@ -31,6 +32,7 @@ class BialgebrasWithBasis(CategoryWithAxiom_over_base_ring): sage: TestSuite(BialgebrasWithBasis(ZZ)).run() """ + class ParentMethods: def convolution_product(self, *maps): @@ -400,9 +402,8 @@ def convolution_product(self, *maps): # ``split_convolve`` moves terms of the form x # y to x*Ti(y1) # y2 in Sweedler notation. def split_convolve(x_y): x, y = x_y - return (((xy1, y2), c * d) - for ((y1, y2), d) in H.term(y).coproduct() - for (xy1, c) in H.term(x) * mor(H.term(y1))) + return (((xy1, y2), c * d) for ((y1, y2), d) in H.term(y).coproduct() for (xy1, c) in H.term(x) * mor(H.term(y1))) + out = HH.module_morphism(on_basis=lambda t: HH.sum_of_terms(split_convolve(t)), codomain=HH)(out) # Apply final map `T_n` to last term, `y`, and multiply. diff --git a/src/sage/categories/bimodules.py b/src/sage/categories/bimodules.py index a7e5b0b4ee6..8322e7d22cb 100644 --- a/src/sage/categories/bimodules.py +++ b/src/sage/categories/bimodules.py @@ -1,7 +1,8 @@ r""" Bimodules """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2005 David Kohel # William Stein # 2008 Teresa Gomez-Diaz (CNRS) @@ -9,16 +10,17 @@ # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category import Category, CategoryWithParameters from sage.categories.left_modules import LeftModules from sage.categories.right_modules import RightModules from sage.categories.rings import Rings + _Rings = Rings() -#?class Bimodules(Category_over_base_rng, Category_over_base_rng): +# ?class Bimodules(Category_over_base_rng, Category_over_base_rng): class Bimodules(CategoryWithParameters): @@ -46,13 +48,9 @@ def __init__(self, left_base, right_base, name=None): sage: C = Bimodules(QQ, ZZ) sage: TestSuite(C).run() """ - if not (left_base in Rings() or - (isinstance(left_base, Category) - and left_base.is_subcategory(Rings()))): + if not (left_base in Rings() or (isinstance(left_base, Category) and left_base.is_subcategory(Rings()))): raise ValueError("the left base must be a ring or a subcategory of Rings()") - if not (right_base in Rings() or - (isinstance(right_base, Category) - and right_base.is_subcategory(Rings()))): + if not (right_base in Rings() or (isinstance(right_base, Category) and right_base.is_subcategory(Rings()))): raise ValueError("the right base must be a ring or a subcategory of Rings()") self._left_base_ring = left_base self._right_base_ring = right_base @@ -101,8 +99,7 @@ def _make_named_class_key(self, name): sage: Bimodules(Fields(), Rings())._make_named_class_key('element_class') (Category of fields, Category of rings) """ - return (self._left_base_ring if isinstance(self._left_base_ring, Category) else self._left_base_ring.category(), - self._right_base_ring if isinstance(self._right_base_ring, Category) else self._right_base_ring.category()) + return (self._left_base_ring if isinstance(self._left_base_ring, Category) else self._left_base_ring.category(), self._right_base_ring if isinstance(self._right_base_ring, Category) else self._right_base_ring.category()) @classmethod def an_instance(cls): @@ -116,6 +113,7 @@ def an_instance(cls): """ from sage.rings.rational_field import QQ from sage.rings.real_mpfr import RR + return cls(QQ, RR) def _repr_object_names(self): @@ -125,8 +123,7 @@ def _repr_object_names(self): sage: Bimodules(QQ, ZZ) # indirect doctest Category of bimodules over Rational Field on the left and Integer Ring on the right """ - return "bimodules over %s on the left and %s on the right" \ - % (self._left_base_ring, self._right_base_ring) + return "bimodules over %s on the left and %s on the right" % (self._left_base_ring, self._right_base_ring) def left_base_ring(self): """ @@ -162,9 +159,8 @@ def _latex_(self) -> str: {\mathbf{Bimodules}}_{\Bold{Q}, \Bold{Z}} """ from sage.misc.latex import latex - return "{{{}}}_{{{}, {}}}".format(Category._latex_(self), - latex(self._left_base_ring), - latex(self._right_base_ring)) + + return "{{{}}}_{{{}, {}}}".format(Category._latex_(self), latex(self._left_base_ring), latex(self._right_base_ring)) def super_categories(self): """ diff --git a/src/sage/categories/cartesian_product.py b/src/sage/categories/cartesian_product.py index 673fc3bbc28..4070bf18243 100644 --- a/src/sage/categories/cartesian_product.py +++ b/src/sage/categories/cartesian_product.py @@ -5,12 +5,13 @@ - Nicolas M. Thiery (2008-2010): initial revision and refactorization """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2010 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from typing import Self @@ -110,6 +111,7 @@ class CartesianProductFunctor(CovariantFunctorialConstruction, MultivariateConst ``Monoids(QQ)``. This nested class is itself a subclass of :class:`CartesianProductsCategory`. """ + _functor_name = "cartesian_product" _functor_category = "CartesianProducts" symbol = " (+) " @@ -127,6 +129,7 @@ def __init__(self, category=None): CovariantFunctorialConstruction.__init__(self) self._forced_category = category from sage.categories.sets_cat import Sets + if self._forced_category is not None: codomain = self._forced_category else: @@ -182,15 +185,18 @@ def __call__(self, args, **kwds): """ if any(type(arg) in native_python_containers for arg in args): from sage.categories.sets_cat import Sets + S = Sets() args = [S(a, enumerated_set=True) for a in args] elif not args: if self._forced_category is None: from sage.categories.sets_cat import Sets + cat = Sets().CartesianProducts() else: cat = self._forced_category from sage.sets.cartesian_product import CartesianProduct + return CartesianProduct((), cat) elif self._forced_category is not None: return super().__call__(args, category=self._forced_category, **kwds) diff --git a/src/sage/categories/category.py b/src/sage/categories/category.py index dda138211f2..3e70c213d7c 100644 --- a/src/sage/categories/category.py +++ b/src/sage/categories/category.py @@ -124,8 +124,7 @@ _join_cache = WeakValueDictionary() -HALL_OF_FAME = ['Coxeter', 'Hopf', 'Weyl', 'Lie', - 'Hecke', 'Dedekind', 'Stone'] +HALL_OF_FAME = ['Coxeter', 'Hopf', 'Weyl', 'Lie', 'Hecke', 'Dedekind', 'Stone'] class Category(UniqueRepresentation, SageObject): @@ -427,6 +426,7 @@ class inheritance from ``C.parent_class``. .. automethod:: Category.__classcall__ .. automethod:: Category.__init__ """ + @staticmethod def __classcall__(cls, *args, **options): """ @@ -482,10 +482,16 @@ def __init__(self): the class) is not adequate, please implement :meth:`_repr_object_names` to customize it. """ - self.__class__ = dynamic_class("{}_with_category".format(self.__class__.__name__), - (self.__class__, self.subcategory_class, ), - cache=False, reduction=None, - doccls=self.__class__) + self.__class__ = dynamic_class( + "{}_with_category".format(self.__class__.__name__), + ( + self.__class__, + self.subcategory_class, + ), + cache=False, + reduction=None, + doccls=self.__class__, + ) @lazy_attribute def _label(self): @@ -498,8 +504,8 @@ def _label(self): 'Rings' """ t = str(self.__class__.__base__) - t = t[t.rfind('.') + 1:] - return t[:t.rfind("'")] + t = t[t.rfind('.') + 1 :] + return t[: t.rfind("'")] def _repr_object_names(self): """ @@ -521,10 +527,8 @@ def _repr_object_names(self): sage: PrincipalIdealDomains()._repr_object_names() 'principal ideal domains' """ - words = "".join(letter if not letter.isupper() else ";" + letter - for letter in self._label).split(";") - return " ".join(w if w in HALL_OF_FAME else w.lower() - for w in words).lstrip() + words = "".join(letter if not letter.isupper() else ";" + letter for letter in self._label).split(";") + return " ".join(w if w in HALL_OF_FAME else w.lower() for w in words).lstrip() def _short_name(self): """ @@ -623,22 +627,22 @@ def _latex_(self): """ return "\\mathbf{%s}" % self._short_name() -# The convention for which hash function to use should be decided at the level of UniqueRepresentation -# The implementation below is bad (hash independent of the base ring) -# def __hash__(self): -# """ -# Returns a hash for this category. -# -# Currently this is just the hash of the string representing the category. -# -# EXAMPLES:: -# -# sage: hash(Algebras(QQ)) #indirect doctest -# 699942203 -# sage: hash(Algebras(ZZ)) -# 699942203 -# """ -# return hash(self.__category) # Any reason not to use id? + # The convention for which hash function to use should be decided at the level of UniqueRepresentation + # The implementation below is bad (hash independent of the base ring) + # def __hash__(self): + # """ + # Returns a hash for this category. + # + # Currently this is just the hash of the string representing the category. + # + # EXAMPLES:: + # + # sage: hash(Algebras(QQ)) #indirect doctest + # 699942203 + # sage: hash(Algebras(ZZ)) + # 699942203 + # """ + # return hash(self.__category) # Any reason not to use id? def _subcategory_hook_(self, category): """ @@ -860,13 +864,9 @@ def _all_super_categories(self): Category of sets, Category of sets with partial maps, Category of objects] """ - (result, bases) = C3_sorted_merge([cat._all_super_categories - for cat in self._super_categories] + - [self._super_categories], - category_sort_key) + (result, bases) = C3_sorted_merge([cat._all_super_categories for cat in self._super_categories] + [self._super_categories], category_sort_key) if not sorted(result, key=category_sort_key, reverse=True) == result: - warn("Inconsistent sorting results for all super categories of {}".format( - self.__class__)) + warn("Inconsistent sorting results for all super categories of {}".format(self.__class__)) self._super_categories_for_classes = bases return [self] + result @@ -1323,8 +1323,7 @@ def is_full_subcategory(self, other): sage: EuclideanDomains().is_full_subcategory(Rings()) False """ - return self.is_subcategory(other) and \ - len(self.structure()) == len(other.structure()) + return self.is_subcategory(other) and len(self.structure()) == len(other.structure()) @cached_method def full_super_categories(self): @@ -1382,8 +1381,7 @@ def full_super_categories(self): sage: Groups().full_super_categories() [Category of monoids, Category of inverse unital magmas] """ - return [C for C in self.super_categories() - if self.is_full_subcategory(C)] + return [C for C in self.super_categories() if self.is_full_subcategory(C)] ########################################################################## # Test methods @@ -1461,11 +1459,10 @@ def _test_category(self, **options): """ from sage.categories.objects import Objects from sage.categories.sets_cat import Sets + tester = self._tester(**options) - tester.assertTrue(isinstance(self.super_categories(), list), - "%s.super_categories() should return a list" % self) - tester.assertTrue(self.is_subcategory(Objects()), - "%s is not a subcategory of Objects()" % self) + tester.assertTrue(isinstance(self.super_categories(), list), "%s.super_categories() should return a list" % self) + tester.assertTrue(self.is_subcategory(Objects()), "%s is not a subcategory of Objects()" % self) tester.assertTrue(isinstance(self.parent_class, type)) tester.assertTrue(all(not isinstance(cat, JoinCategory) for cat in self._super_categories)) if not isinstance(self, JoinCategory): @@ -1474,10 +1471,7 @@ def _test_category(self, **options): for category in self._all_super_categories_proper: if self.is_full_subcategory(category): - tester.assertTrue(any(cat.is_subcategory(category) - for cat in self.full_super_categories()), - "Every full super category should be a super category" - "of some immediate full super category") + tester.assertTrue(any(cat.is_subcategory(category) for cat in self.full_super_categories()), "Every full super category should be a super category" "of some immediate full super category") if self.is_subcategory(Sets()): tester.assertTrue(isinstance(self.parent_class, type)) @@ -1599,8 +1593,7 @@ def _make_named_class(self, name, method_provider, cache=False, picklable=True): doccls = cls else: # Otherwise, check XXXMethods - assert inspect.isclass(method_provider_cls), \ - "%s.%s should be a class" % (cls.__name__, method_provider) + assert inspect.isclass(method_provider_cls), "%s.%s should be a class" % (cls.__name__, method_provider) mro = inspect.getmro(method_provider_cls) if len(mro) > 2 or (len(mro) == 2 and mro[1] is not object): warn("%s.%s should not have a super class" % (cls.__name__, method_provider)) @@ -1610,10 +1603,7 @@ def _make_named_class(self, name, method_provider, cache=False, picklable=True): reduction = (getattr, (self, name)) else: reduction = None - return dynamic_class(class_name, - tuple(getattr(cat, name) for cat in self._super_categories_for_classes), - method_provider_cls, prepend_cls_bases=False, - doccls=doccls, reduction=reduction, cache=cache) + return dynamic_class(class_name, tuple(getattr(cat, name) for cat in self._super_categories_for_classes), method_provider_cls, prepend_cls_bases=False, doccls=doccls, reduction=reduction, cache=cache) @lazy_attribute def subcategory_class(self): @@ -1657,8 +1647,7 @@ class hierarchy. sage: type(cls) """ - return self._make_named_class('subcategory_class', 'SubcategoryMethods', - cache=False, picklable=False) + return self._make_named_class('subcategory_class', 'SubcategoryMethods', cache=False, picklable=False) @lazy_attribute def parent_class(self): @@ -1796,8 +1785,7 @@ def required_methods(self): {'element': {'optional': ['_add_', '_mul_'], 'required': ['__bool__']}, 'parent': {'optional': ['algebra_generators'], 'required': ['__contains__']}} """ - return {"parent": abstract_methods_of_class(self.parent_class), - "element": abstract_methods_of_class(self.element_class)} + return {"parent": abstract_methods_of_class(self.parent_class), "element": abstract_methods_of_class(self.element_class)} # Operations on the lattice of categories def is_subcategory(self, c): @@ -1912,7 +1900,7 @@ def _is_subclass(self, c): sage: Algebras(QQ)._is_subclass(ModulesWithBasis) False """ - assert (isinstance(c, Category) or (issubclass(c.__class__, type) and issubclass(c, Category))) + assert isinstance(c, Category) or (issubclass(c.__class__, type) and issubclass(c, Category)) if isinstance(c, Category): return self.is_subcategory(c) return any(isinstance(cat, c) for cat in self._all_super_categories) @@ -2023,9 +2011,7 @@ def axioms(self): sage: (EnumeratedSets().Infinite() & Sets().Facade()).axioms() frozenset({'Enumerated', 'Facade', 'Infinite'}) """ - return frozenset(axiom - for category in self._super_categories - for axiom in category.axioms()) + return frozenset(axiom for category in self._super_categories for axiom in category.axioms()) @cached_method def _with_axiom_as_tuple(self, axiom): @@ -2057,7 +2043,7 @@ def _with_axiom_as_tuple(self, axiom): Category of finite dimensional vector spaces over Rational Field) """ if axiom in self.axioms(): - return (self, ) + return (self,) axiom_attribute = getattr(self.__class__, axiom, None) if axiom_attribute is None: # If the axiom is not defined for this category, ignore it @@ -2067,16 +2053,13 @@ def _with_axiom_as_tuple(self, axiom): if axiom in self.__class__.__base__.__dict__: # self implements this axiom from .category_with_axiom import CategoryWithAxiom + if inspect.isclass(axiom_attribute) and issubclass(axiom_attribute, CategoryWithAxiom): return (axiom_attribute(self),) - warn(("Expecting {}.{} to be a subclass of CategoryWithAxiom to" - " implement a category with axiom; got {}; ignoring").format( - self.__class__.__base__.__name__, axiom, axiom_attribute)) + warn(("Expecting {}.{} to be a subclass of CategoryWithAxiom to" " implement a category with axiom; got {}; ignoring").format(self.__class__.__base__.__name__, axiom, axiom_attribute)) # self does not implement this axiom - result = (self, ) + tuple(cat - for category in self._super_categories - for cat in category._with_axiom_as_tuple(axiom)) + result = (self,) + tuple(cat for category in self._super_categories for cat in category._with_axiom_as_tuple(axiom)) hook = getattr(self, axiom + "_extra_super_categories", None) if hook is not None: assert inspect.ismethod(hook) @@ -2488,6 +2471,7 @@ def join(categories, as_list=False, ignore_axioms=(), axioms=()): return [] # Since Objects() is the top category, it is the neutral element of join from .objects import Objects + return Objects() if len(categories) == 1: category = categories[0] @@ -2540,6 +2524,7 @@ def category(self): Category of objects """ from .objects import Objects + return Objects() def example(self, *args, **keywords): @@ -2581,6 +2566,7 @@ def example(self, *args, **keywords): return NotImplemented module_name = self.__module__.replace("sage.categories", "sage.categories.examples") import sys + try: __import__(module_name) module = sys.modules[module_name] @@ -2630,10 +2616,9 @@ def category_sample(): Category of vector spaces over Rational Field, ... """ import sage.categories.all + abstract_classes_for_categories = [Category] - return tuple(cls.an_instance() - for cls in sage.categories.all.__dict__.values() - if isinstance(cls, type) and issubclass(cls, Category) and cls not in abstract_classes_for_categories) + return tuple(cls.an_instance() for cls in sage.categories.all.__dict__.values() if isinstance(cls, type) and issubclass(cls, Category) and cls not in abstract_classes_for_categories) def category_graph(categories=None): @@ -2667,12 +2652,12 @@ def category_graph(categories=None): Graphics object consisting of ... graphics primitives """ from sage import graphs + if categories is None: categories = category_sample() # Include all the super categories # Get rid of join categories - categories = {cat for category in categories - for cat in category.all_super_categories(proper=isinstance(category, JoinCategory))} + categories = {cat for category in categories for cat in category.all_super_categories(proper=isinstance(category, JoinCategory))} g = graphs.digraph.DiGraph() for cat in categories: g.add_vertex(cat._repr_object_names()) @@ -2688,6 +2673,7 @@ def category_graph(categories=None): # the super categories ############################################################################## + class CategoryWithParameters(Category): """ A parametrized category whose parent/element classes depend only on @@ -2836,8 +2822,7 @@ def _make_named_class(self, name, method_provider, cache=False, **options): return self._make_named_class_cache[key] except KeyError: pass - result = Category._make_named_class(self, name, method_provider, - cache=cache, **options) + result = Category._make_named_class(self, name, method_provider, cache=cache, **options) if key[2] != self._make_named_class_key(name): # the object in the parameter may have had its category refined, which might modify the key # throw result away and recompute @@ -2975,6 +2960,7 @@ def _subcategory_hook_(self, C): # Join of several categories ############################################################# + class JoinCategory(CategoryWithParameters): """ A class for joins of several categories. Do not use directly; @@ -3251,8 +3237,7 @@ def _without_axioms(self, named=False): for category in self._super_categories: if category._with_axioms(axioms) is self: return category._without_axioms(named=named) - raise ValueError("This join category isn't built by adding axioms" - " to a single category") + raise ValueError("This join category isn't built by adding axioms" " to a single category") def _cmp_key(self): """ @@ -3295,6 +3280,7 @@ def _repr_object_names(self): ValueError: This join category isn't built by adding axioms to a single category """ from sage.categories.category_with_axiom import CategoryWithAxiom + return CategoryWithAxiom._repr_object_names_static(self._without_axioms(named=True), self.axioms()) def _repr_(self, as_join=False): diff --git a/src/sage/categories/category_types.py b/src/sage/categories/category_types.py index 8b8379e40a0..744bf503e04 100644 --- a/src/sage/categories/category_types.py +++ b/src/sage/categories/category_types.py @@ -5,14 +5,14 @@ (as morphisms must be very low in the hierarchy with the new coercion model). """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2005 David Kohel and # William Stein # 2008-2009 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.category import Category, CategoryWithParameters, JoinCategory from sage.misc.lazy_import import lazy_import @@ -21,8 +21,7 @@ lazy_import('sage.categories.objects', 'Objects') lazy_import('sage.misc.latex', 'latex') -lazy_import('sage.categories.chain_complexes', 'ChainComplexes', - deprecation=29917) +lazy_import('sage.categories.chain_complexes', 'ChainComplexes', deprecation=29917) #################################################################### # Different types of categories @@ -49,6 +48,7 @@ class Elements(Category): sage: loads(C.dumps()) == C True """ + def __init__(self, object): """ EXAMPLES:: @@ -69,6 +69,7 @@ def an_instance(cls): Category of elements of Rational Field """ from sage.rings.rational_field import QQ + return cls(QQ) def _call_(self, x): @@ -118,7 +119,7 @@ def __reduce__(self): sage: loads(dumps(C)) == C True """ - return Elements, (self.__object, ) + return Elements, (self.__object,) def _repr_object_names(self): """ @@ -204,13 +205,9 @@ def _test_category_over_bases(self, **options): from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from .bimodules import Bimodules from .schemes import Schemes + for cat in self.super_categories(): - tester.assertTrue(isinstance(cat, (Category_singleton, Category_over_base, - CategoryWithAxiom_over_base_ring, - Bimodules, Schemes)), - "The super categories of a category over base should" - " be a category over base (or the related Bimodules)" - " or a singleton category") + tester.assertTrue(isinstance(cat, (Category_singleton, Category_over_base, CategoryWithAxiom_over_base_ring, Bimodules, Schemes)), "The super categories of a category over base should" " be a category over base (or the related Bimodules)" " or a singleton category") def _make_named_class_key(self, name): r""" @@ -261,6 +258,7 @@ def an_instance(cls): Category of algebras over Rational Field """ from sage.rings.rational_field import QQ + return cls(QQ) def base(self): @@ -294,7 +292,7 @@ def _repr_object_names(self): base = self.__base if isinstance(base, Category): if isinstance(base, JoinCategory): - name = '('+' and '.join(C._repr_object_names() for C in base.super_categories())+')' + name = '(' + ' and '.join(C._repr_object_names() for C in base.super_categories()) + ')' else: name = base._repr_object_names() else: @@ -310,6 +308,7 @@ def _latex_(self): """ return "\\mathbf{%s}_{%s}" % (self._label, latex(self.__base)) + # def construction(self): # return (self.__class__, self.__base) @@ -356,8 +355,8 @@ def __init__(self, base, name=None): sage: TestSuite(C).run() """ from sage.categories.rings import Rings - if not (base in Rings() or - isinstance(base, Category) and base.is_subcategory(Rings())): + + if not (base in Rings() or isinstance(base, Category) and base.is_subcategory(Rings())): raise ValueError("base must be a ring or a subcategory of Rings()") Category_over_base.__init__(self, base, name) @@ -518,8 +517,7 @@ def __contains__(self, x) -> bool: try: # The issubclass test handles extension types or when the # category is not fully initialized - if isinstance(x, self.parent_class) or \ - issubclass(x.category().parent_class, self.parent_class): + if isinstance(x, self.parent_class) or issubclass(x.category().parent_class, self.parent_class): if isinstance(self.base(), Category): return True return x.base_ring() is self.base_ring() @@ -568,6 +566,7 @@ def _repr_(self): """ return Category._repr_(self) + " in %s" % self.__ambient + # def construction(self): # return (self.__class__, self.__ambient) @@ -589,6 +588,7 @@ def an_instance(cls): Category of algebra ideals in Univariate Polynomial Ring in x over Rational Field """ from sage.rings.rational_field import QQ + return cls(QQ['x']) def ring(self): @@ -614,6 +614,7 @@ def __contains__(self, x) -> bool: if super().__contains__(x): return True from sage.rings.ideal import Ideal_generic + return isinstance(x, Ideal_generic) and x.ring() == self.ring() def __call__(self, v): diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index 8da245cd619..fa173e1041f 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -1648,6 +1648,7 @@ class ``Sets.Finite``), or in a separate file (typically in a class sage: FiniteGroups().Algebras(QQ) Category of finite group algebras over Rational Field """ + # **************************************************************************** # Copyright (C) 2011-2014 Nicolas M. Thiery # @@ -1673,29 +1674,7 @@ class ``Sets.Finite``), or in a separate file (typically in a class # ``Category of commutative unital magmas'' all_axioms = AxiomContainer() -all_axioms += ("Flying", "Blue", - "Compact", - "Differentiable", "Smooth", "Analytic", "AlmostComplex", - "FinitelyGeneratedAsMagma", - "WellGenerated", - "Bounded", - "Facade", "Finite", "Infinite", "Enumerated", - "Complete", - "Nilpotent", - "FiniteDimensional", "FinitelyPresented", "Connected", - "FinitelyGeneratedAsLambdaBracketAlgebra", - "WithBasis", - "Irreducible", - "Supercommutative", "Supercocommutative", - "Commutative", "Cocommutative", "Associative", - "Inverse", "Unital", "Division", "NoZeroDivisors", "Cellular", - "AdditiveCommutative", "AdditiveAssociative", "AdditiveInverse", "AdditiveUnital", - "Extremal", "Trim", "Semidistributive", "CongruenceUniform", - "ChainGraded", "Distributive", "Stone", - "Endset", - "Pointed", - "Stratified" - ) +all_axioms += ("Flying", "Blue", "Compact", "Differentiable", "Smooth", "Analytic", "AlmostComplex", "FinitelyGeneratedAsMagma", "WellGenerated", "Bounded", "Facade", "Finite", "Infinite", "Enumerated", "Complete", "Nilpotent", "FiniteDimensional", "FinitelyPresented", "Connected", "FinitelyGeneratedAsLambdaBracketAlgebra", "WithBasis", "Irreducible", "Supercommutative", "Supercocommutative", "Commutative", "Cocommutative", "Associative", "Inverse", "Unital", "Division", "NoZeroDivisors", "Cellular", "AdditiveCommutative", "AdditiveAssociative", "AdditiveInverse", "AdditiveUnital", "Extremal", "Trim", "Semidistributive", "CongruenceUniform", "ChainGraded", "Distributive", "Stone", "Endset", "Pointed", "Stratified") def uncamelcase(s, separator=" "): @@ -1709,7 +1688,7 @@ def uncamelcase(s, separator=" "): sage: sage.categories.category_with_axiom.uncamelcase("FiniteDimensionalAlgebras", "_") 'finite_dimensional_algebras' """ - return re.sub("(?!^)[A-Z]", lambda match: separator+match.group()[0], s).lower() + return re.sub("(?!^)[A-Z]", lambda match: separator + match.group()[0], s).lower() def base_category_class_and_axiom(cls): @@ -1787,26 +1766,29 @@ def base_category_class_and_axiom(cls): name = cls.__name__ for axiom in all_axioms: if axiom == "WithBasis" and name.endswith(axiom): - base_name = name[:-len(axiom)] + base_name = name[: -len(axiom)] elif name.startswith(axiom): - base_name = name[len(axiom):] + base_name = name[len(axiom) :] else: continue - if base_name == "Sets": # Special case for Sets which is in sets_cat + if base_name == "Sets": # Special case for Sets which is in sets_cat base_module_name = "sets_cat" else: base_module_name = uncamelcase(base_name, "_") try: - base_module = importlib.import_module("sage.categories."+base_module_name) + base_module = importlib.import_module("sage.categories." + base_module_name) base_category_class = getattr(base_module, base_name) - assert getattr(base_category_class, axiom, None) is cls, \ - "Missing (lazy import) link for {} to {} for axiom {}?".format(base_category_class, cls, axiom) + assert getattr(base_category_class, axiom, None) is cls, "Missing (lazy import) link for {} to {} for axiom {}?".format(base_category_class, cls, axiom) return base_category_class, axiom - except (ImportError,AttributeError): + except (ImportError, AttributeError): pass - raise TypeError("""Could not retrieve the base category class and axiom for {}. + raise TypeError( + """Could not retrieve the base category class and axiom for {}. Please specify it explicitly using the attribute _base_category_class_and_axiom. -See CategoryWithAxiom for details.""".format(cls)) +See CategoryWithAxiom for details.""".format( + cls + ) + ) @cached_function @@ -1849,15 +1831,13 @@ def axiom_of_nested_class(cls, nested_cls): else: cls_name = cls.__name__.split(".")[-1] if nested_cls_name.startswith(cls_name): - axiom = nested_cls_name[len(cls_name):] + axiom = nested_cls_name[len(cls_name) :] elif nested_cls_name.endswith(cls_name): - axiom = nested_cls_name[:-len(cls_name)] + axiom = nested_cls_name[: -len(cls_name)] else: raise ValueError("could not infer axiom for the nested class {} of {}".format(nested_cls, cls)) - assert axiom in all_axioms, \ - "Incorrect deduction ({}) for the name of the axiom for the nested class {} of {}".format(axiom, nested_cls, cls) - assert axiom in cls.__dict__ and cls.__dict__[axiom] == nested_cls, \ - "{} not a nested axiom class of {} for axiom {}".format(nested_cls, cls, axiom) + assert axiom in all_axioms, "Incorrect deduction ({}) for the name of the axiom for the nested class {} of {}".format(axiom, nested_cls, cls) + assert axiom in cls.__dict__ and cls.__dict__[axiom] == nested_cls, "{} not a nested axiom class of {} for axiom {}".format(nested_cls, cls, axiom) return axiom @@ -2071,9 +2051,7 @@ def __classget__(cls, base_category, base_category_class): cls._base_category_class_and_axiom = (base_category_class, axiom_of_nested_class(base_category_class, cls)) cls._base_category_class_and_axiom_origin = "set by __classget__" else: - assert cls._base_category_class_and_axiom[0] is base_category_class, \ - "base category class for {} mismatch; expected {}, got {}".format( - cls, cls._base_category_class_and_axiom[0], base_category_class) + assert cls._base_category_class_and_axiom[0] is base_category_class, "base category class for {} mismatch; expected {}, got {}".format(cls, cls._base_category_class_and_axiom[0], base_category_class) # Workaround #15648: if Rings.Finite is a LazyImport object, # this forces the substitution of the object back into Rings @@ -2105,7 +2083,7 @@ def __init__(self, base_category): if isinstance(base_category, Category_singleton) and not isinstance(self, CategoryWithAxiom_singleton): cls = self.__class__ assert cls.__base__ == CategoryWithAxiom - cls.__bases__ = (CategoryWithAxiom_singleton,)+cls.__bases__[1:] + cls.__bases__ = (CategoryWithAxiom_singleton,) + cls.__bases__[1:] self._base_category = base_category Category.__init__(self) @@ -2184,13 +2162,7 @@ def super_categories(self): """ base_category = self._base_category axiom = self._axiom - return Category.join((base_category,) + - tuple(cat - for category in base_category._super_categories - for cat in category._with_axiom_as_tuple(axiom)) + - tuple(self.extra_super_categories()), - ignore_axioms=((base_category, axiom),), - as_list=True) + return Category.join((base_category,) + tuple(cat for category in base_category._super_categories for cat in category._with_axiom_as_tuple(axiom)) + tuple(self.extra_super_categories()), ignore_axioms=((base_category, axiom),), as_list=True) def additional_structure(self): r""" @@ -2263,9 +2235,10 @@ def _repr_object_names_static(category, axioms): 'finitely generated as magma rings' """ from sage.categories.additive_magmas import AdditiveMagmas - axioms = canonicalize_axioms(all_axioms,axioms) + + axioms = canonicalize_axioms(all_axioms, axioms) base_category = category._without_axioms(named=True) - if isinstance(base_category, CategoryWithAxiom): # Smelly runtime type checking + if isinstance(base_category, CategoryWithAxiom): # Smelly runtime type checking result = super(CategoryWithAxiom, base_category)._repr_object_names() else: result = base_category._repr_object_names() @@ -2294,8 +2267,7 @@ def _repr_object_names_static(category, axioms): elif axiom == "Endset" and "homsets" in result: # Without the space at the end to handle Homsets().Endset() result = result.replace("homsets", "endsets", 1) - elif axiom == "FinitelyGeneratedAsMagma" and \ - not base_category.is_subcategory(AdditiveMagmas()): + elif axiom == "FinitelyGeneratedAsMagma" and not base_category.is_subcategory(AdditiveMagmas()): result = "finitely generated " + result elif axiom == "FinitelyGeneratedAsLambdaBracketAlgebra": result = "finitely generated " + result @@ -2498,9 +2470,7 @@ def axioms(self): # return super(CategoryWithAxiom, self).axioms() | {self._axiom} # However one currently can't use super to call a cached # method in a super class. So we dup the code from there ... - return frozenset(axiom - for category in self._super_categories - for axiom in category.axioms()) | {self._axiom} + return frozenset(axiom for category in self._super_categories for axiom in category.axioms()) | {self._axiom} class CategoryWithAxiom_over_base_ring(CategoryWithAxiom, Category_over_base_ring): @@ -2591,8 +2561,10 @@ def axiom(axiom): sage: As().Finite() (<__main__.As ... at ...>, 'Finite') """ + def with_axiom(self): return self._with_axiom(axiom) + with_axiom.__name__ = axiom return with_axiom @@ -2619,6 +2591,7 @@ def super_categories(self): sage: TestSuite(Blahs()).run() """ from sage.categories.sets_cat import Sets + return [Sets()] class SubcategoryMethods: diff --git a/src/sage/categories/chain_complexes.py b/src/sage/categories/chain_complexes.py index f56fe7a3ba3..872df774a25 100644 --- a/src/sage/categories/chain_complexes.py +++ b/src/sage/categories/chain_complexes.py @@ -2,7 +2,7 @@ Category of chain complexes """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2007 Robert Bradshaw # 2009 Mike Hansen # 2013 Volker Braun @@ -11,7 +11,7 @@ # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.category_types import Category_module from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups @@ -48,6 +48,7 @@ def super_categories(self): from sage.categories.fields import Fields from sage.categories.modules import Modules from sage.categories.vector_spaces import VectorSpaces + base_ring = self.base_ring() if base_ring in Fields(): return [VectorSpaces(base_ring)] @@ -206,6 +207,7 @@ class HomologyFunctor(Functor): From: Z To: Z """ + def __init__(self, domain, n=None): r""" Construct the homology functor. @@ -261,7 +263,4 @@ def _apply_functor_to_morphism(self, f): lift = domain.lift_from_homology reduce = codomain.reduce_to_homology apply_f_star = lambda x: reduce(f(lift(x)), self._n) - return SetMorphism(Hom(domain.homology(self._n), - codomain.homology(self._n), - CommutativeAdditiveGroups()), - apply_f_star) + return SetMorphism(Hom(domain.homology(self._n), codomain.homology(self._n), CommutativeAdditiveGroups()), apply_f_star) diff --git a/src/sage/categories/classical_crystals.py b/src/sage/categories/classical_crystals.py index 20a225b65cc..b0ca7ec0cac 100644 --- a/src/sage/categories/classical_crystals.py +++ b/src/sage/categories/classical_crystals.py @@ -175,6 +175,7 @@ def demazure_character(self, w, f=None): """ from sage.misc.misc_c import prod from sage.rings.integer_ring import ZZ + if hasattr(w, 'reduced_word'): word = w.reduced_word() else: @@ -184,9 +185,10 @@ def demazure_character(self, w, f=None): u = self.demazure_operator(u, word) if f is None: from sage.symbolic.ring import SR as P - x = [P.var('x%s' % (i+1)) for i in range(n)] + + x = [P.var('x%s' % (i + 1)) for i in range(n)] # TODO: use P.linear_combination when PolynomialRing will be a ModulesWithBasis - return sum((coeff*prod((x[i]**(c.weight()[i]) for i in range(n)), P.one()) for c, coeff in u), P.zero()) + return sum((coeff * prod((x[i] ** (c.weight()[i]) for i in range(n)), P.one()) for c, coeff in u), P.zero()) return sum(coeff * f(c) for c, coeff in u) def character(self, R=None): @@ -230,13 +232,14 @@ def character(self, R=None): ValueError: Weyl character ring does not have the right Cartan type """ from sage.combinat.root_system.weyl_characters import WeylCharacterRing + if R is None: R = WeylCharacterRing(self.cartan_type()) if not R.cartan_type() == self.cartan_type(): raise ValueError("Weyl character ring does not have the right Cartan type") assert R.basis().keys() == self.weight_lattice_realization() - return R.sum_of_monomials( x.weight() for x in self.highest_weight_vectors() ) + return R.sum_of_monomials(x.weight() for x in self.highest_weight_vectors()) def __iter__(self): r""" @@ -386,6 +389,7 @@ def __iter__(self): #True """ from sage.combinat.crystals.crystals import CrystalBacktracker + return iter(CrystalBacktracker(self)) def _test_fast_iter(self, **options): @@ -417,8 +421,7 @@ def cardinality(self): sage: C.cardinality() 6 """ - return sum(self.weight_lattice_realization().weyl_dimension(x.weight()) - for x in self.highest_weight_vectors()) + return sum(self.weight_lattice_realization().weyl_dimension(x.weight()) for x in self.highest_weight_vectors()) class ElementMethods: @@ -475,6 +478,7 @@ class TensorProducts(TensorProductsCategory): The category of classical crystals constructed by tensor product of classical crystals. """ + @cached_method def extra_super_categories(self): """ diff --git a/src/sage/categories/coalgebras.py b/src/sage/categories/coalgebras.py index ac9a49be55d..14400669b67 100644 --- a/src/sage/categories/coalgebras.py +++ b/src/sage/categories/coalgebras.py @@ -39,6 +39,7 @@ class Coalgebras(Category_over_base_ring): sage: TestSuite(Coalgebras(ZZ)).run() """ + def super_categories(self): """ EXAMPLES:: @@ -52,7 +53,7 @@ def super_categories(self): Graded = LazyImport('sage.categories.graded_coalgebras', 'GradedCoalgebras') class ParentMethods: - #def __init_add__(self): # The analogue of initDomainAdd + # def __init_add__(self): # The analogue of initDomainAdd # # Will declare the coproduct of self to the coercion mechanism when it exists # pass @@ -104,7 +105,7 @@ def coproduct(self, x): sage: b, A.coproduct(b) (B[(1,3)], B[(1,3)] # B[(1,3)]) """ - #return self.tensor_square()(overloaded_coproduct(x)) + # return self.tensor_square()(overloaded_coproduct(x)) class ElementMethods: def coproduct(self): @@ -200,7 +201,7 @@ def extra_super_categories(self): class ParentMethods: # TODO: provide this default implementation of one if one_basis is not implemented - #def one(self): + # def one(self): # return tensor(module.one() for module in self.modules) pass @@ -231,6 +232,7 @@ def extra_super_categories(self): See :issue:`15647`. """ from sage.categories.algebras import Algebras + return [Algebras(self.base_category().base_ring())] class Super(SuperModulesCategory): diff --git a/src/sage/categories/coalgebras_with_basis.py b/src/sage/categories/coalgebras_with_basis.py index 70d66ea8128..5cd7d60ef86 100644 --- a/src/sage/categories/coalgebras_with_basis.py +++ b/src/sage/categories/coalgebras_with_basis.py @@ -1,13 +1,14 @@ r""" Coalgebras with basis """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # Copyright (C) 2008-2011 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.abstract_method import abstract_method from sage.misc.lazy_attribute import lazy_attribute @@ -36,8 +37,8 @@ class CoalgebrasWithBasis(CategoryWithAxiom_over_base_ring): sage: TestSuite(CoalgebrasWithBasis(ZZ)).run() """ - Graded = LazyImport('sage.categories.graded_coalgebras_with_basis', - 'GradedCoalgebrasWithBasis') + + Graded = LazyImport('sage.categories.graded_coalgebras_with_basis', 'GradedCoalgebrasWithBasis') class Filtered(FilteredModulesCategory): """ @@ -145,7 +146,7 @@ def counit(self): (B[(1,3)], 1) """ if self.counit_on_basis is not NotImplemented: - return self.module_morphism(self.counit_on_basis,codomain=self.base_ring()) + return self.module_morphism(self.counit_on_basis, codomain=self.base_ring()) if hasattr(self, "counit_by_coercion"): return self.counit_by_coercion @@ -213,8 +214,7 @@ def coproduct_iterated(self, n=1): # Use coassociativity of `\Delta` to perform many coproducts simultaneously. fn = Integer(n - 1) // 2 cn = Integer(n - 1) // 2 if n % 2 else Integer(n) // 2 - split = lambda a, b: tensor([a.coproduct_iterated(fn), - b.coproduct_iterated(cn)]) + split = lambda a, b: tensor([a.coproduct_iterated(fn), b.coproduct_iterated(cn)]) return self.coproduct().apply_multilinear_morphism(split) class Super(SuperModulesCategory): diff --git a/src/sage/categories/commutative_additive_groups.py b/src/sage/categories/commutative_additive_groups.py index 945c4b78a94..1c57f9ff952 100644 --- a/src/sage/categories/commutative_additive_groups.py +++ b/src/sage/categories/commutative_additive_groups.py @@ -1,12 +1,13 @@ r""" Commutative additive groups """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category_types import AbelianCategory from sage.categories.category_with_axiom import CategoryWithAxiom @@ -56,6 +57,7 @@ class CommutativeAdditiveGroups(CategoryWithAxiom, AbelianCategory): Also, it's likely that some code will end up there at some point. """ + _base_category_class_and_axiom = (AdditiveGroups, "AdditiveCommutative") class CartesianProducts(CartesianProductsCategory): @@ -89,10 +91,12 @@ def additive_order(self): 18 """ from sage.rings.infinity import Infinity + orders = [x.additive_order() for x in self.cartesian_factors()] if any(o is Infinity for o in orders): return Infinity from sage.arith.functions import LCM_list + return LCM_list(orders) class Algebras(AlgebrasCategory): diff --git a/src/sage/categories/commutative_additive_monoids.py b/src/sage/categories/commutative_additive_monoids.py index d1d3ba3dc2d..53907a9e883 100644 --- a/src/sage/categories/commutative_additive_monoids.py +++ b/src/sage/categories/commutative_additive_monoids.py @@ -1,13 +1,14 @@ r""" Commutative additive monoids """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2008-2009 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.additive_monoids import AdditiveMonoids @@ -38,4 +39,5 @@ class CommutativeAdditiveMonoids(CategoryWithAxiom): sage: TestSuite(CommutativeAdditiveMonoids()).run() """ + _base_category_class_and_axiom = (AdditiveMonoids, "AdditiveCommutative") diff --git a/src/sage/categories/commutative_additive_semigroups.py b/src/sage/categories/commutative_additive_semigroups.py index 5bf5097e5f8..3653b2185ad 100644 --- a/src/sage/categories/commutative_additive_semigroups.py +++ b/src/sage/categories/commutative_additive_semigroups.py @@ -1,12 +1,13 @@ r""" Commutative additive semigroups """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.additive_semigroups import AdditiveSemigroups @@ -41,4 +42,5 @@ class CommutativeAdditiveSemigroups(CategoryWithAxiom): sage: TestSuite(C).run() """ + _base_category_class_and_axiom = (AdditiveSemigroups, "AdditiveCommutative") diff --git a/src/sage/categories/commutative_algebra_ideals.py b/src/sage/categories/commutative_algebra_ideals.py index e47e1c4f87e..fc5ac0229df 100644 --- a/src/sage/categories/commutative_algebra_ideals.py +++ b/src/sage/categories/commutative_algebra_ideals.py @@ -1,14 +1,15 @@ r""" Commutative algebra ideals """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2005 David Kohel # William Stein # 2008-2009 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.algebra_ideals import AlgebraIdeals from sage.categories.category_types import Category_ideal, Category_in_ambient @@ -27,6 +28,7 @@ class CommutativeAlgebraIdeals(Category_ideal): Category of commutative algebra ideals in Univariate Polynomial Ring in x over Rational Field """ + def __init__(self, A): """ EXAMPLES:: diff --git a/src/sage/categories/commutative_algebras.py b/src/sage/categories/commutative_algebras.py index 506004a2dbb..8faea125db0 100644 --- a/src/sage/categories/commutative_algebras.py +++ b/src/sage/categories/commutative_algebras.py @@ -1,14 +1,15 @@ r""" Commutative algebras """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2005 David Kohel # William Stein # 2008-2009 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.cachefunc import cached_method from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring @@ -60,8 +61,7 @@ def __contains__(self, A) -> bool: TODO: get rid of this method once all commutative algebras in Sage declare themselves in this category """ - return super().__contains__(A) or \ - (A in Algebras(self.base_ring()) and hasattr(A, "is_commutative") and A.is_commutative()) + return super().__contains__(A) or (A in Algebras(self.base_ring()) and hasattr(A, "is_commutative") and A.is_commutative()) class TensorProducts(TensorProductsCategory): """ diff --git a/src/sage/categories/commutative_ring_ideals.py b/src/sage/categories/commutative_ring_ideals.py index 8659b0c793b..690879bdd35 100644 --- a/src/sage/categories/commutative_ring_ideals.py +++ b/src/sage/categories/commutative_ring_ideals.py @@ -1,14 +1,15 @@ r""" Commutative ring ideals """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2005 David Kohel # William Stein # 2008-2009 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category_types import Category_ideal from sage.categories.commutative_rings import CommutativeRings @@ -25,6 +26,7 @@ class CommutativeRingIdeals(Category_ideal): sage: C Category of commutative ring ideals in Integer Ring """ + def __init__(self, R): """ EXAMPLES:: diff --git a/src/sage/categories/commutative_rings.py b/src/sage/categories/commutative_rings.py index bb73028a665..233ccafba3f 100644 --- a/src/sage/categories/commutative_rings.py +++ b/src/sage/categories/commutative_rings.py @@ -1,6 +1,7 @@ r""" Commutative rings """ + # **************************************************************************** # Copyright (C) 2005 David Kohel # William Stein @@ -58,6 +59,7 @@ class CommutativeRings(CategoryWithAxiom): sage: A.is_commutative() # needs sage.combinat sage.modules False """ + class ParentMethods: def krull_dimension(self): """ @@ -170,6 +172,7 @@ def _ideal_class_(self, n=0): """ # One might need more than just n from sage.rings.ideal import Ideal_generic, Ideal_principal + return Ideal_principal if n == 1 else Ideal_generic def _test_divides(self, **options): @@ -331,6 +334,7 @@ def over(self, base=None, gen=None, gens=None, name=None, names=None): Rational Field] """ from sage.rings.ring_extension import RingExtension + if name is not None: if names is not None: raise ValueError("keyword argument 'name' cannot be combined with 'names'") @@ -372,6 +376,7 @@ def frobenius_endomorphism(self, n=1): 1 + u^25 """ from sage.rings.morphism import FrobeniusEndomorphism_generic + return FrobeniusEndomorphism_generic(self, n) def derivation_module(self, codomain=None, twist=None): @@ -465,6 +470,7 @@ def derivation_module(self, codomain=None, twist=None): :meth:`derivation` """ from sage.rings.derivation import RingDerivationModule + if codomain is None: codomain = self return RingDerivationModule(self, codomain, twist) @@ -638,11 +644,9 @@ def extension(self, poly, name=None, names=None, **kwds): name = str(poly.parent().gen(0)) for key, val in kwds.items(): - if key not in ['structure', 'implementation', 'prec', - 'embedding', 'latex_name', 'latex_names']: + if key not in ['structure', 'implementation', 'prec', 'embedding', 'latex_name', 'latex_names']: raise TypeError(f"extension() got an invalid keyword argument: {key}") - if not (val is None or isinstance(val, list) - and all(c is None for c in val)): + if not (val is None or isinstance(val, list) and all(c is None for c in val)): raise NotImplementedError(f"ring extension with prescribed {key} is not implemented") if self.is_zero(): @@ -795,6 +799,7 @@ def sqrt(self, extend=True, all=False, name=None): # is_square(root = True) option from sage.categories.integral_domains import IntegralDomains + P = self.parent() is_sqr, sq_rt = self.is_square(root=True) if is_sqr: @@ -818,9 +823,10 @@ def sqrt(self, extend=True, all=False, name=None): if name is None: raise TypeError("Polynomial is not a square. You must specify the name of the square root when using the default extend = True") from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + PY = PolynomialRing(P, 'y') y = PY.gen() - sq_rt = PY.quotient(y**2-self, names=name)(y) + sq_rt = PY.quotient(y**2 - self, names=name)(y) if all: if P.characteristic() == 2: return [sq_rt] @@ -838,6 +844,7 @@ class Finite(CategoryWithAxiom): ....: GF(5)]) in Rings().Commutative().Finite() True """ + def extra_super_categories(self): r""" Let Sage know that finite commutative rings are Noetherian. @@ -848,6 +855,7 @@ def extra_super_categories(self): [Category of noetherian rings] """ from sage.categories.noetherian_rings import NoetherianRings + return [NoetherianRings()] class ParentMethods: diff --git a/src/sage/categories/complete_discrete_valuation.py b/src/sage/categories/complete_discrete_valuation.py index 85658db3642..5e7d97cea2a 100644 --- a/src/sage/categories/complete_discrete_valuation.py +++ b/src/sage/categories/complete_discrete_valuation.py @@ -1,12 +1,13 @@ r""" Complete Discrete Valuation Rings (CDVR) and Fields (CDVF) """ -#************************************************************************** + +# ************************************************************************** # Copyright (C) 2013 Xavier Caruso # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#************************************************************************** +# ************************************************************************** from typing import Self @@ -18,7 +19,7 @@ ) from sage.misc.abstract_method import abstract_method -#from sage.misc.cachefunc import cached_method +# from sage.misc.cachefunc import cached_method class CompleteDiscreteValuationRings(Category_singleton): @@ -37,6 +38,7 @@ class CompleteDiscreteValuationRings(Category_singleton): False sage: TestSuite(CompleteDiscreteValuationRings()).run() """ + def super_categories(self): """ EXAMPLES:: diff --git a/src/sage/categories/complex_reflection_groups.py b/src/sage/categories/complex_reflection_groups.py index d8d59f4d3d4..90ddedfc2e6 100644 --- a/src/sage/categories/complex_reflection_groups.py +++ b/src/sage/categories/complex_reflection_groups.py @@ -1,7 +1,8 @@ r""" Complex reflection groups """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2011-2015 Christian Stump # # This program is free software: you can redistribute it and/or modify @@ -9,7 +10,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.cachefunc import cached_method from sage.misc.lazy_import import LazyImport @@ -120,6 +121,7 @@ def example(self): 5-colored permutations of size 3 """ from sage.combinat.colored_permutations import ColoredPermutations + return ColoredPermutations(5, 3) class ParentMethods: @@ -140,5 +142,4 @@ def rank(self): 3 """ - Finite = LazyImport('sage.categories.finite_complex_reflection_groups', - 'FiniteComplexReflectionGroups', as_name='Finite') + Finite = LazyImport('sage.categories.finite_complex_reflection_groups', 'FiniteComplexReflectionGroups', as_name='Finite') diff --git a/src/sage/categories/complex_reflection_or_generalized_coxeter_groups.py b/src/sage/categories/complex_reflection_or_generalized_coxeter_groups.py index 94df5f159d2..516b3f196cd 100644 --- a/src/sage/categories/complex_reflection_or_generalized_coxeter_groups.py +++ b/src/sage/categories/complex_reflection_or_generalized_coxeter_groups.py @@ -248,6 +248,7 @@ def simple_reflections(self): :meth:`.simple_reflection`. """ from sage.sets.family import Family + return Family(self.index_set(), self.simple_reflection) def number_of_simple_reflections(self): @@ -354,6 +355,7 @@ def mult_order(x): cur *= x ct += ZZ.one() return ZZ(ct) + return [mult_order(s[i]) for i in self.index_set()] def _an_element_(self): @@ -514,6 +516,7 @@ def reflections(self): 10 (4,27,21)(10,28,22)(11,19,13)(12,20,14)(16,30,26)(17,25,18)(23,29,24) """ from sage.sets.family import Family + return Family(self.reflection_index_set(), self.reflection) ########################################################################## @@ -637,6 +640,7 @@ def distinguished_reflections(self): 8 (3,13)(4,24)(9,19)(10,29)(11,15)(12,26)(14,21)(16,23)(17,30)(18,27)(20,22)(25,28) """ from sage.sets.family import Family + return Family(self.hyperplane_index_set(), self.distinguished_reflection) ########################################################################## @@ -767,11 +771,8 @@ def irreducible_component_index_sets(self): I = self.index_set() s = self.simple_reflections() from sage.graphs.graph import Graph - G = Graph([I, - [[i,j] - for i,j in itertools.combinations(I,2) - if s[i]*s[j] != s[j]*s[i] ]], - format='vertices_and_edges') + + G = Graph([I, [[i, j] for i, j in itertools.combinations(I, 2) if s[i] * s[j] != s[j] * s[i]]], format='vertices_and_edges') return G.connected_components(sort=False) @abstract_method(optional=True) diff --git a/src/sage/categories/covariant_functorial_construction.py b/src/sage/categories/covariant_functorial_construction.py index a67a6156440..6f81e0398c4 100644 --- a/src/sage/categories/covariant_functorial_construction.py +++ b/src/sage/categories/covariant_functorial_construction.py @@ -35,12 +35,13 @@ - Nicolas M. Thiery (2010): initial revision """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2010 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from typing import Self from sage.categories.category import Category @@ -143,6 +144,7 @@ def category_from_parents(self, parents): finite dimensional vector spaces with basis over Rational Field """ from sage.structure.parent import Parent + assert all(isinstance(parent, Parent) for parent in parents) # Should we pass a set of categories to reduce the cache size? # But then this would impose that, for any constructor, the @@ -227,7 +229,7 @@ def __call__(self, args, **kwargs): return getattr(args[0], self._functor_name)(*args[1:], **kwargs) -class FunctorialConstructionCategory(Category): # Should this be CategoryWithBase? +class FunctorialConstructionCategory(Category): # Should this be CategoryWithBase? """ Abstract class for categories `F_{Cat}` obtained through a functorial construction @@ -286,8 +288,9 @@ def _base_category_class(cls): :class:`CategoryWithAxiom._base_category_class`. Find a way to refactor this to avoid the duplication. """ - module_name = cls.__module__.replace(cls._functor_category.lower() + "_","") + module_name = cls.__module__.replace(cls._functor_category.lower() + "_", "") import sys + name = cls.__name__.replace(cls._functor_category, "") __import__(module_name) module = sys.modules[module_name] @@ -368,9 +371,7 @@ def __classget__(cls, base_category, base_category_class): if "_base_category_class" not in cls.__dict__: cls._base_category_class = (base_category_class,) else: - assert cls._base_category_class[0] is base_category_class, \ - "base category class for {} mismatch; expected {}, got {}".format( - cls, cls._base_category_class[0], base_category_class) + assert cls._base_category_class[0] is base_category_class, "base category class for {} mismatch; expected {}, got {}".format(cls, cls._base_category_class[0], base_category_class) # Workaround #15648: if Sets.Subquotients is a LazyImport object, # this forces the substitution of the object back into Sets @@ -379,8 +380,7 @@ def __classget__(cls, base_category, base_category_class): setattr(base_category_class, cls._functor_category, cls) if base_category is None: return cls - return getattr(super(base_category.__class__.__base__, base_category), - cls._functor_category) + return getattr(super(base_category.__class__.__base__, base_category), cls._functor_category) @classmethod @cached_function @@ -482,9 +482,7 @@ def super_categories(self): sage: Semigroups().Quotients().super_categories() [Category of subquotients of semigroups, Category of quotients of sets] """ - return Category.join([self.__class__.default_super_categories(self.base_category(), *self._args)] + - self.extra_super_categories(), - as_list=True) + return Category.join([self.__class__.default_super_categories(self.base_category(), *self._args)] + self.extra_super_categories(), as_list=True) def _repr_object_names(self): """ @@ -507,6 +505,7 @@ def _latex_(self): \mathbf{Algebras}(\mathbf{Semigroups}) """ from sage.misc.latex import latex + return "\\mathbf{%s}(%s)" % (self._short_name(), latex(self.base_category())) @@ -582,9 +581,7 @@ def default_super_categories(cls, category, *args): and Category of monoid algebras over Rational Field and Category of finite set algebras over Rational Field """ - return Category.join([getattr(cat, cls._functor_category)(*args) - for cat in category._super_categories - if hasattr(cat, cls._functor_category)]) + return Category.join([getattr(cat, cls._functor_category)(*args) for cat in category._super_categories if hasattr(cat, cls._functor_category)]) def is_construction_defined_by_base(self): r""" @@ -692,5 +689,4 @@ def default_super_categories(cls, category, *args): sage: C.__class__.default_super_categories(C.base_category(), *C._args) Category of unital subquotients of semigroups """ - return Category.join([category, - super().default_super_categories(category, *args)]) + return Category.join([category, super().default_super_categories(category, *args)]) diff --git a/src/sage/categories/coxeter_group_algebras.py b/src/sage/categories/coxeter_group_algebras.py index 0f939d84572..9802f46426e 100644 --- a/src/sage/categories/coxeter_group_algebras.py +++ b/src/sage/categories/coxeter_group_algebras.py @@ -11,8 +11,7 @@ class CoxeterGroupAlgebras(AlgebrasCategory): class ParentMethods: - def demazure_lusztig_operator_on_basis(self, w, i, q1, q2, - side='right'): + def demazure_lusztig_operator_on_basis(self, w, i, q1, q2, side='right'): r""" Return the result of applying the `i`-th Demazure Lusztig operator on ``w``. @@ -67,7 +66,7 @@ def demazure_lusztig_operator_on_basis(self, w, i, q1, q2, sage: KW.demazure_lusztig_operator_on_basis(w, 3, 1, -1) 12 """ - return (q1+q2) * self.monomial(w.apply_simple_projection(i,side=side)) - self.term(w.apply_simple_reflection(i, side=side), q2) + return (q1 + q2) * self.monomial(w.apply_simple_projection(i, side=side)) - self.term(w.apply_simple_reflection(i, side=side), q2) def demazure_lusztig_operators(self, q1, q2, side='right', affine=True): r""" @@ -130,6 +129,7 @@ def demazure_lusztig_operators(self, q1, q2, side='right', affine=True): using only untwisted affinizations. """ from sage.combinat.root_system.hecke_algebra_representation import HeckeAlgebraRepresentation + W = self.basis().keys() cartan_type = W.cartan_type() if affine and cartan_type.is_finite(): diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index adb2c15342e..9620e950273 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -1,6 +1,7 @@ r""" Coxeter Groups """ + # **************************************************************************** # Copyright (C) 2009 Nicolas M. Thiery # 2015 Christian Stump @@ -218,11 +219,10 @@ def braid_relations(self): M = self.coxeter_matrix() I = self.index_set() for ii, i in enumerate(I): - for j in I[ii + 1:]: + for j in I[ii + 1 :]: m = M[i, j] rel = [i, j] * m - rels.append([rel[:m], rel[m:] if m % 2 else - list(reversed(rel[m:]))]) + rels.append([rel[:m], rel[m:] if m % 2 else list(reversed(rel[m:]))]) return rels def braid_group_as_finitely_presented_group(self): @@ -252,7 +252,7 @@ def braid_group_as_finitely_presented_group(self): F = FreeGroup(["S%s" % i for i in I]) S = F.gens() rels = self.braid_relations() - return F / [prod(S[I.index(i)] for i in l) * prod(S[I.index(i)]**-1 for i in reversed(r)) for l, r in rels] + return F / [prod(S[I.index(i)] for i in l) * prod(S[I.index(i)] ** -1 for i in reversed(r)) for l, r in rels] def braid_orbit_iter(self, word): r""" @@ -284,13 +284,13 @@ def braid_orbit_iter(self, word): I = self.index_set() from sage.rings.integer_ring import ZZ + be_careful = any(i not in ZZ for i in I) if be_careful: Iinv = {i: j for j, i in enumerate(I)} word = [Iinv[i] for i in word] - braid_rels = [[[Iinv[i] for i in l], - [Iinv[i] for i in r]] for l, r in braid_rels] + braid_rels = [[[Iinv[i] for i in l], [Iinv[i] for i in r]] for l, r in braid_rels] orb = BraidOrbit(word, braid_rels) @@ -542,11 +542,10 @@ def succ(u): yield u1 from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups + default_category = FiniteEnumeratedSets() if self in FiniteCoxeterGroups() else EnumeratedSets() cat = default_category.or_subcategory(category) - return RecursivelyEnumeratedSet_forest((self.one(),), succ, - algorithm='breadth', - category=cat) + return RecursivelyEnumeratedSet_forest((self.one(),), succ, algorithm='breadth', category=cat) @cached_method def coxeter_element(self): @@ -658,8 +657,8 @@ class is not unique and we only obtain one such class. if not self.is_irreducible() or not self.is_well_generated(): raise ValueError("this method is available for irreducible, well-generated complex reflection groups") from sage.combinat.permutation import Permutations - return {self.from_reduced_word(w) - for w in Permutations(self.index_set())} + + return {self.from_reduced_word(w) for w in Permutations(self.index_set())} def grassmannian_elements(self, side='right'): """ @@ -689,8 +688,7 @@ def grassmannian_elements(self, side='right'): [(), (0,), (0,), (0,), (1,), (1,), (1,), (1,), (1,), (2,), (2,), (2,)] """ order_side = "left" if side == "right" else "right" - return self.weak_order_ideal(attrcall("is_grassmannian", side=side), - side=order_side) + return self.weak_order_ideal(attrcall("is_grassmannian", side=side), side=order_side) def fully_commutative_elements(self): r""" @@ -710,6 +708,7 @@ def fully_commutative_elements(self): [2 3 1] """ from sage.combinat.fully_commutative_elements import FullyCommutativeElements + return FullyCommutativeElements(self) def _test_reduced_word(self, **options): @@ -769,8 +768,7 @@ def simple_projection(self, i, side='right', length_increasing=True): """ if not (i in self.index_set() or i == 0): raise ValueError("%s is not 0 and not in the Dynkin node set %s" % (i, self.index_set())) - return lambda x: x.apply_simple_projection(i, side=side, - length_increasing=length_increasing) + return lambda x: x.apply_simple_projection(i, side=side, length_increasing=length_increasing) def kazhdan_lusztig_cells(self, side='left'): r""" @@ -959,6 +957,7 @@ def simple_projections(self, side='right', length_increasing=True): (1, 3, 2, 0) """ from sage.sets.family import Family + return Family(self.index_set(), lambda i: self.simple_projection(i, side=side, length_increasing=length_increasing)) def sign_representation(self, base_ring=None): @@ -985,8 +984,10 @@ def sign_representation(self, base_ring=None): """ if base_ring is None: from sage.rings.integer_ring import ZZ + base_ring = ZZ from sage.modules.with_basis.representation import SignRepresentationCoxeterGroup + return SignRepresentationCoxeterGroup(self, base_ring) def reflection_representation(self, base_ring=None, side='left'): @@ -1026,6 +1027,7 @@ def reflection_representation(self, base_ring=None, side='left'): (as a matrix group acting on the root space) """ from sage.modules.with_basis.representation import ReflectionRepresentation + return ReflectionRepresentation(self, base_ring) def demazure_product(self, Q): @@ -1124,6 +1126,7 @@ def bruhat_interval_poset(self, x, y, facade=False): if y == 1: y = self.one() from sage.combinat.posets.posets import Poset + if x == y: return Poset([[x], []]) if not x.bruhat_le(y): @@ -1145,10 +1148,8 @@ def bruhat_interval_poset(self, x, y, facade=False): curlayer = nextlayer from sage.graphs.digraph import DiGraph - return Poset(DiGraph(d, format='dict_of_lists', - data_structure='static_sparse'), - cover_relations=True, - facade=facade) + + return Poset(DiGraph(d, format='dict_of_lists', data_structure='static_sparse'), cover_relations=True, facade=facade) def bruhat_graph(self, x=None, y=None, edge_labels=False): r""" @@ -1231,6 +1232,7 @@ def bruhat_graph(self, x=None, y=None, edge_labels=False): d.append((u, v)) from sage.graphs.digraph import DiGraph + return DiGraph(d) def canonical_representation(self): @@ -1252,8 +1254,8 @@ def canonical_representation(self): [2 3 1] """ from sage.groups.matrix_gps.coxeter_group import CoxeterMatrixGroup - return CoxeterMatrixGroup(self.coxeter_matrix(), - index_set=self.index_set()) + + return CoxeterMatrixGroup(self.coxeter_matrix(), index_set=self.index_set()) def elements_of_length(self, n): r""" @@ -1305,6 +1307,7 @@ def random_element_of_length(self, n): True """ from sage.misc.prandom import randint + x = self.one() for _ in range(1, n + 1): antiD = x.descents(positive=True) @@ -1335,8 +1338,7 @@ def _test_simple_projections(self, **options): tester.assertEqual(opi[i](w), w.apply_simple_projection(i, side=side, length_increasing=False)) tester.assertTrue(pi[i](w).has_descent(i, side=side)) tester.assertFalse(opi[i](w).has_descent(i, side=side)) - tester.assertEqual({pi[i](w), opi[i](w)}, - {w, w.apply_simple_reflection(i, side=side)}) + tester.assertEqual({pi[i](w), opi[i](w)}, {w, w.apply_simple_reflection(i, side=side)}) def _test_has_descent(self, **options): """ @@ -1442,7 +1444,7 @@ def _test_coxeter_relations(self, **options): return I = cox_mat.index_set() for ii, i in enumerate(I): - for j in I[ii + 1:]: + for j in I[ii + 1 :]: mij = cox_mat[i, j] if mij == -1: # -1 stands for infinity continue @@ -1483,7 +1485,7 @@ def has_descent(self, i, side='right', positive=False) -> bool: raise ValueError("%s is neither 'right' nor 'left'" % side) return self.has_left_descent(i) != positive -# @abstract_method(optional = True) + # @abstract_method(optional = True) def has_right_descent(self, i) -> bool: """ Return whether `i` is a right descent of ``self``. @@ -1599,8 +1601,7 @@ def descents(self, side='right', index_set=None, positive=False): """ if index_set is None: index_set = self.parent().index_set() - return [i for i in index_set if self.has_descent(i, side=side, - positive=positive)] + return [i for i in index_set if self.has_descent(i, side=side, positive=positive)] def is_grassmannian(self, side='right') -> bool: """ @@ -1672,13 +1673,13 @@ def is_fully_commutative(self) -> bool: I = group.index_set() from sage.rings.integer_ring import ZZ + be_careful = any(i not in ZZ for i in I) if be_careful: Iinv = {i: j for j, i in enumerate(I)} word = [Iinv[i] for i in word] - braid_rels = [[[Iinv[i] for i in l], - [Iinv[i] for i in r]] for l, r in braid_rels] + braid_rels = [[[Iinv[i] for i in l], [Iinv[i] for i in r]] for l, r in braid_rels] return is_fully_comm(word, braid_rels) @@ -1917,6 +1918,7 @@ def reduced_word_graph(self): """ R = self.reduced_words() from sage.graphs.graph import Graph + # Special case for when the graph does not contain any edges if len(R) == 1: return Graph({tuple(R[0]): []}, immutable=True) @@ -1941,15 +1943,12 @@ def reduced_word_graph(self): if m % 2: subword.append(a) subword2.append(b) - if (x[j:j + m] != tuple(subword) - or y[j:j + m] != tuple(subword2) - or x[j + m:] != y[j + m:]): + if x[j : j + m] != tuple(subword) or y[j : j + m] != tuple(subword2) or x[j + m :] != y[j + m :]: continue edges.append([x, y, m]) G = Graph(edges, immutable=True, format='list_of_edges') colors = {2: 'blue', 3: 'red', 4: 'green'} - G.set_latex_options(edge_labels=True, - color_by_label=lambda x: colors[x]) + G.set_latex_options(edge_labels=True, color_by_label=lambda x: colors[x]) return G def length(self): @@ -2085,8 +2084,7 @@ def absolute_chain(self): """ reflections = self.absolute_chain_reflections() P = self.parent() - return [P.prod(reversed(reflections[:i])) - for i in range(len(reflections) + 1)] + return [P.prod(reversed(reflections[:i])) for i in range(len(reflections) + 1)] def absolute_chain_reflections(self): r""" @@ -2158,6 +2156,7 @@ def absolute_chain_reflections(self): return [left_refl, self * left_refl] import itertools + s = P.simple_reflections() rev = P.one() cur = P.one() @@ -2450,9 +2449,11 @@ def binary_factorizations(self, predicate=ConstantFunction(True)): sage: sage.combinat.permutation.Permutations.options._reset() """ from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest + W = self.parent() if not predicate(W.one()): from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + return FiniteEnumeratedSet([]) def succ(u_v): @@ -2461,8 +2462,8 @@ def succ(u_v): u1 = u.apply_simple_reflection_right(i) if i == u1.first_descent() and predicate(u1): yield u1, v.apply_simple_reflection_left(i) - return RecursivelyEnumeratedSet_forest(((W.one(), self),), succ, - category=FiniteEnumeratedSets()) + + return RecursivelyEnumeratedSet_forest(((W.one(), self),), succ, category=FiniteEnumeratedSets()) @cached_in_parent_method def bruhat_lower_covers(self): @@ -2553,9 +2554,7 @@ def bruhat_upper_covers(self): Covers = set() for i in self.parent().index_set(): if i in self.descents(side='right'): - Covers.update(x.apply_simple_reflection(i, side='right') - for x in self.apply_simple_reflection(i, side='right').bruhat_upper_covers() - if i not in x.descents(side='right')) + Covers.update(x.apply_simple_reflection(i, side='right') for x in self.apply_simple_reflection(i, side='right').bruhat_upper_covers() if i not in x.descents(side='right')) else: Covers.add(self.apply_simple_reflection(i, side='right')) return sorted(Covers) @@ -2590,11 +2589,7 @@ def bruhat_lower_covers_reflections(self): if i is None: return [] wi = self.apply_simple_reflection(i, side='right') - return [(u.apply_simple_reflection(i, side='right'), - r.apply_conjugation_by_simple_reflection(i)) - for u, r in wi.bruhat_lower_covers_reflections() - if not u.has_descent(i, side='right')] + [ - (wi, self.parent().simple_reflection(i))] + return [(u.apply_simple_reflection(i, side='right'), r.apply_conjugation_by_simple_reflection(i)) for u, r in wi.bruhat_lower_covers_reflections() if not u.has_descent(i, side='right')] + [(wi, self.parent().simple_reflection(i))] def lower_cover_reflections(self, side='right'): r""" @@ -2637,8 +2632,7 @@ def bruhat_upper_covers_reflections(self): for i in self.parent().index_set(): wi = self.apply_simple_reflection(i) if i in self.descents(): - Covers.update((u.apply_simple_reflection(i), r.apply_conjugation_by_simple_reflection(i)) - for u, r in wi.bruhat_upper_covers_reflections() if i not in u.descents()) + Covers.update((u.apply_simple_reflection(i), r.apply_conjugation_by_simple_reflection(i)) for u, r in wi.bruhat_upper_covers_reflections() if i not in u.descents()) else: Covers.add((wi, self.parent().simple_reflection(i))) return sorted(Covers) @@ -2849,9 +2843,7 @@ def weak_covers(self, side='right', index_set=None, positive=False): sage: [x.reduced_word() for x in w.weak_covers(index_set=[1,2])] # needs sage.combinat sage.groups [[2, 3, 2]] """ - return [self.apply_simple_reflection(i, side=side) - for i in self.descents(side=side, index_set=index_set, - positive=positive)] + return [self.apply_simple_reflection(i, side=side) for i in self.descents(side=side, index_set=index_set, positive=positive)] def coxeter_sorting_word(self, c): r""" @@ -2963,8 +2955,7 @@ def is_coxeter_sortable(self, c, sorting_word=None): i = 0 return True - def apply_demazure_product(self, element, side='right', - length_increasing=True): + def apply_demazure_product(self, element, side='right', length_increasing=True): r""" Return the Demazure or 0-Hecke product of ``self`` with another Coxeter group element. @@ -3255,8 +3246,7 @@ def lower_covers(self, side='right', index_set=None): sage: [x.reduced_word() for x in w.lower_covers(side='left')] # needs sage.combinat sage.groups [[3, 2, 1], [2, 3, 1]] """ - return self.weak_covers(side=side, index_set=index_set, - positive=False) + return self.weak_covers(side=side, index_set=index_set, positive=False) def upper_covers(self, side='right', index_set=None): """ @@ -3289,8 +3279,7 @@ def upper_covers(self, side='right', index_set=None): ....: for x in w.upper_covers(side='left', index_set=[1])] [[1, 2, 3]] """ - return self.weak_covers(side=side, index_set=index_set, - positive=True) + return self.weak_covers(side=side, index_set=index_set, positive=True) def kazhdan_lusztig_cell(self, side='left'): r""" @@ -3420,5 +3409,6 @@ def kazhdan_lusztig_cell(self, side='left'): queue.appendleft(y) from sage.graphs.digraph import DiGraph + g = DiGraph([list(vertices), list(edges)]) return set(g.strongly_connected_component_containing_vertex(w)) diff --git a/src/sage/categories/crystals.py b/src/sage/categories/crystals.py index 42eac098ae0..92e8c6dcb27 100644 --- a/src/sage/categories/crystals.py +++ b/src/sage/categories/crystals.py @@ -140,9 +140,11 @@ def example(self, choice='highwt', **kwds): A broken crystal, defined by digraph, of dimension five. """ import sage.categories.examples.crystals as examples + if choice == "naive": return examples.NaiveCrystal(**kwds) from sage.rings.integer import Integer + if isinstance(choice, Integer): return examples.HighestWeightCrystalOfTypeA(n=choice, **kwds) return examples.HighestWeightCrystalOfTypeA(**kwds) @@ -227,8 +229,7 @@ def is_strict(self) -> bool: index_set = self._cartan_type.index_set() for x in self.domain(): y = self(x) - if any(self(x.f(i)) != y.f(i) or self(x.e(i)) != y.e(i) - for i in index_set): + if any(self(x.f(i)) != y.f(i) or self(x.e(i)) != y.e(i) for i in index_set): return False return True @@ -386,13 +387,11 @@ def __iter__(self, index_set=None, max_depth=float('inf')): index_set = self.index_set() succ = lambda x: [x.f(i) for i in index_set] + [x.e(i) for i in index_set] from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet + R = RecursivelyEnumeratedSet(self.module_generators, succ, structure=None) return R.breadth_first_search_iterator(max_depth) - def subcrystal(self, index_set=None, generators=None, max_depth=float('inf'), - direction='both', contained=None, - virtualization=None, scaling_factors=None, - cartan_type=None, category=None): + def subcrystal(self, index_set=None, generators=None, max_depth=float('inf'), direction='both', contained=None, virtualization=None, scaling_factors=None, cartan_type=None, category=None): r""" Construct the subcrystal from ``generators`` using `e_i` and/or `f_i` for all `i` in ``index_set``. @@ -501,6 +500,7 @@ def subcrystal(self, index_set=None, generators=None, max_depth=float('inf'), cartan_type = self.cartan_type() else: from sage.combinat.root_system.cartan_type import CartanType + cartan_type = CartanType(cartan_type) if index_set is None: index_set = cartan_type.index_set() @@ -509,13 +509,9 @@ def subcrystal(self, index_set=None, generators=None, max_depth=float('inf'), if max_depth == float('inf'): if self not in FiniteCrystals(): - if (contained is None and index_set == self.index_set() - and generators == self.module_generators - and scaling_factors is None and virtualization is None): + if contained is None and index_set == self.index_set() and generators == self.module_generators and scaling_factors is None and virtualization is None: return self - return Subcrystal(self, contained, generators, - virtualization, scaling_factors, - cartan_type, index_set, category) + return Subcrystal(self, contained, generators, virtualization, scaling_factors, cartan_type, index_set, category) # else self is a finite crystal if direction == 'both': @@ -523,9 +519,7 @@ def subcrystal(self, index_set=None, generators=None, max_depth=float('inf'), category = FiniteCrystals() else: category = FiniteCrystals() & category - return Subcrystal(self, contained, generators, - virtualization, scaling_factors, - cartan_type, index_set, category) + return Subcrystal(self, contained, generators, virtualization, scaling_factors, cartan_type, index_set, category) # TODO: Make this work for virtual crystals as well if direction == 'both': @@ -538,16 +532,15 @@ def subcrystal(self, index_set=None, generators=None, max_depth=float('inf'), raise ValueError("direction must be either 'both', 'upper', or 'lower'") from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet - subset = RecursivelyEnumeratedSet(generators, succ, - structure=None, enumeration='breadth', - max_depth=max_depth) + + subset = RecursivelyEnumeratedSet(generators, succ, structure=None, enumeration='breadth', max_depth=max_depth) # We perform the filtering here since checking containment # in a frozenset should be fast if contained is not None: try: subset = frozenset(x for x in subset if x in contained) - except TypeError: # It does not have a containment test + except TypeError: # It does not have a containment test subset = frozenset(x for x in subset if contained(x)) else: subset = frozenset(subset) @@ -561,9 +554,7 @@ def subcrystal(self, index_set=None, generators=None, max_depth=float('inf'), if index_set == self.index_set(): return self - return Subcrystal(self, subset, generators, - virtualization, scaling_factors, - cartan_type, index_set, category) + return Subcrystal(self, subset, generators, virtualization, scaling_factors, cartan_type, index_set, category) def _Hom_(self, Y, category=None, **options): r""" @@ -598,11 +589,7 @@ def _Hom_(self, Y, category=None, **options): raise TypeError("{} is not a crystal".format(Y)) return CrystalHomset(self, Y, category=category, **options) - def crystal_morphism(self, on_gens, codomain=None, - cartan_type=None, index_set=None, generators=None, - automorphism=None, - virtualization=None, scaling_factors=None, - category=None, check=True): + def crystal_morphism(self, on_gens, codomain=None, cartan_type=None, index_set=None, generators=None, automorphism=None, virtualization=None, scaling_factors=None, category=None, check=True): r""" Construct a crystal morphism from ``self`` to another crystal ``codomain``. @@ -798,8 +785,7 @@ def crystal_morphism(self, on_gens, codomain=None, raise ValueError("the codomain must be a crystal") homset = Hom(self, codomain, category=category) - return homset(on_gens, cartan_type, index_set, generators, - automorphism, virtualization, scaling_factors, check) + return homset(on_gens, cartan_type, index_set, generators, automorphism, virtualization, scaling_factors, check) def digraph(self, subset=None, index_set=None): """ @@ -891,13 +877,13 @@ def digraph(self, subset=None, index_set=None): .. TODO:: Add more tests. """ from sage.graphs.digraph import DiGraph + d = {} # Parse optional arguments if subset is None: if self not in Crystals().Finite(): - raise NotImplementedError("crystals not known to be finite" - " must specify the subset") + raise NotImplementedError("crystals not known to be finite" " must specify the subset") subset = self if index_set is None: index_set = self.index_set() @@ -911,10 +897,9 @@ def digraph(self, subset=None, index_set=None): d[x][child] = i G = DiGraph(d) from sage.graphs.dot2tex_utils import have_dot2tex + if have_dot2tex(): - G.set_latex_options(format='dot2tex', - edge_labels=True, - color_by_label=self.cartan_type()._index_set_coloring) + G.set_latex_options(format='dot2tex', edge_labels=True, color_by_label=self.cartan_type()._index_set_coloring) return G def latex_file(self, filename): @@ -1033,11 +1018,11 @@ def metapost(self, filename, thicklines=False, labels=True, scaling_factor=1.0, # FIXME: those tests are not robust # Should use instead self.cartan_type() == CartanType(['B',2]) if self.cartan_type()[0] == 'B' and self.cartan_type()[1] == 2: - word = [2,1,2,1] + word = [2, 1, 2, 1] elif self.cartan_type()[0] == 'C' and self.cartan_type()[1] == 2: - word = [2,1,2,1] + word = [2, 1, 2, 1] elif self.cartan_type()[0] == 'A' and self.cartan_type()[1] == 2: - word = [1,2,1] + word = [1, 2, 1] else: raise NotImplementedError size = self.cardinality() @@ -1055,23 +1040,23 @@ def metapost(self, filename, thicklines=False, labels=True, scaling_factor=1.0, if self.cartan_type()[0] == 'A': if labels: - c0 = int(55*scaling_factor) - c1 = int(-25*scaling_factor) - c2 = int(45*tallness*scaling_factor) - c3 = int(-12*scaling_factor) - c4 = int(-12*scaling_factor) + c0 = int(55 * scaling_factor) + c1 = int(-25 * scaling_factor) + c2 = int(45 * tallness * scaling_factor) + c3 = int(-12 * scaling_factor) + c4 = int(-12 * scaling_factor) else: - c0 = int(45*scaling_factor) - c1 = int(-20*scaling_factor) - c2 = int(35*tallness*scaling_factor) - c3 = int(12*scaling_factor) - c4 = int(-12*scaling_factor) - outstring = "verbatimtex\n\\magnification=600\netex\n\nbeginfig(-1);\nsx:=35; sy:=30;\n\nz1000=(%d,0);\nz1001=(%d,%d);\nz1002=(%d,%d);\nz2001=(-3,3);\nz2002=(3,3);\nz2003=(0,-3);\nz2004=(7,0);\nz2005=(0,7);\nz2006=(-7,0);\nz2007=(0,7);\n\n" % (c0,c1,c2,c3,c4) + c0 = int(45 * scaling_factor) + c1 = int(-20 * scaling_factor) + c2 = int(35 * tallness * scaling_factor) + c3 = int(12 * scaling_factor) + c4 = int(-12 * scaling_factor) + outstring = "verbatimtex\n\\magnification=600\netex\n\nbeginfig(-1);\nsx:=35; sy:=30;\n\nz1000=(%d,0);\nz1001=(%d,%d);\nz1002=(%d,%d);\nz2001=(-3,3);\nz2002=(3,3);\nz2003=(0,-3);\nz2004=(7,0);\nz2005=(0,7);\nz2006=(-7,0);\nz2007=(0,7);\n\n" % (c0, c1, c2, c3, c4) else: if labels: - outstring = "verbatimtex\n\\magnification=600\netex\n\nbeginfig(-1);\n\nsx := %d;\nsy=%d;\n\nz1000=(2*sx,0);\nz1001=(-sx,sy);\nz1002=(-16,-10);\n\nz2001=(0,-3);\nz2002=(-5,3);\nz2003=(0,3);\nz2004=(5,3);\nz2005=(10,1);\nz2006=(0,10);\nz2007=(-10,1);\nz2008=(0,-8);\n\n" % (int(scaling_factor*40),int(tallness*scaling_factor*40)) + outstring = "verbatimtex\n\\magnification=600\netex\n\nbeginfig(-1);\n\nsx := %d;\nsy=%d;\n\nz1000=(2*sx,0);\nz1001=(-sx,sy);\nz1002=(-16,-10);\n\nz2001=(0,-3);\nz2002=(-5,3);\nz2003=(0,3);\nz2004=(5,3);\nz2005=(10,1);\nz2006=(0,10);\nz2007=(-10,1);\nz2008=(0,-8);\n\n" % (int(scaling_factor * 40), int(tallness * scaling_factor * 40)) else: - outstring = "beginfig(-1);\n\nsx := %d;\nsy := %d;\n\nz1000=(2*sx,0);\nz1001=(-sx,sy);\nz1002=(-5,-5);\n\nz1003=(10,10);\n\n" % (int(scaling_factor*35),int(tallness*scaling_factor*35)) + outstring = "beginfig(-1);\n\nsx := %d;\nsy := %d;\n\nz1000=(2*sx,0);\nz1001=(-sx,sy);\nz1002=(-5,-5);\n\nz1003=(10,10);\n\n" % (int(scaling_factor * 35), int(tallness * scaling_factor * 35)) for i in range(size): if self.cartan_type()[0] == 'A': a1, a2, a3 = string_data[i] @@ -1081,21 +1066,21 @@ def metapost(self, filename, thicklines=False, labels=True, scaling_factor=1.0, for j in range(i): if self.cartan_type()[0] == 'A': b1, b2, b3 = string_data[j] - if b1+b3 == a1+a3 and b2 == a2: + if b1 + b3 == a1 + a3 and b2 == a2: shift += 1 else: b1, b2, b3, b4 = string_data[j] - if b1+b3 == a1+a3 and b2+b4 == a2+a4: + if b1 + b3 == a1 + a3 and b2 + b4 == a2 + a4: shift += 1 if self.cartan_type()[0] == 'A': - outstring = outstring + "z%d=%d*z1000+%d*z1001+%d*z1002;\n" % (i,a1+a3,a2,shift) + outstring = outstring + "z%d=%d*z1000+%d*z1001+%d*z1002;\n" % (i, a1 + a3, a2, shift) else: - outstring = outstring + "z%d=%d*z1000+%d*z1001+%d*z1002;\n" % (i,a1+a3,a2+a4,shift) + outstring = outstring + "z%d=%d*z1000+%d*z1001+%d*z1002;\n" % (i, a1 + a3, a2 + a4, shift) outstring = outstring + "\n" if thicklines: outstring = outstring + "pickup pencircle scaled 2\n\n" for i in range(size): - for j in range(1,3): + for j in range(1, 3): dest = self.list()[i].f(j) if dest is not None: dest = self.list().index(dest) @@ -1104,18 +1089,18 @@ def metapost(self, filename, thicklines=False, labels=True, scaling_factor=1.0, else: col = "green; " if self.cartan_type()[0] == 'A': - a1, a2, a3 = string_data[i] # included to facilitate hand editing of the .mp file - outstring = outstring+"draw z%d--z%d withcolor %s %% %d %d %d\n" % (i,dest,col,a1,a2,a3) + a1, a2, a3 = string_data[i] # included to facilitate hand editing of the .mp file + outstring = outstring + "draw z%d--z%d withcolor %s %% %d %d %d\n" % (i, dest, col, a1, a2, a3) else: a1, a2, a3, a4 = string_data[i] - outstring = outstring+"draw z%d--z%d withcolor %s %% %d %d %d %d\n" % (i,dest,col,a1,a2,a3,a4) + outstring = outstring + "draw z%d--z%d withcolor %s %% %d %d %d %d\n" % (i, dest, col, a1, a2, a3, a4) outstring += "\npickup pencircle scaled 3;\n\n" for i in range(self.cardinality()): if labels: if self.cartan_type()[0] == 'A': - outstring = outstring+"pickup pencircle scaled 15;\nfill z%d+z2004..z%d+z2006..z%d+z2006..z%d+z2007..cycle withcolor white;\nlabel(btex %d etex, z%d+z2001);\nlabel(btex %d etex, z%d+z2002);\nlabel(btex %d etex, z%d+z2003);\npickup pencircle scaled .5;\ndraw z%d+z2004..z%d+z2006..z%d+z2006..z%d+z2007..cycle;\n" % (i,i,i,i,string_data[i][2],i,string_data[i][1],i,string_data[i][0],i,i,i,i,i) + outstring = outstring + "pickup pencircle scaled 15;\nfill z%d+z2004..z%d+z2006..z%d+z2006..z%d+z2007..cycle withcolor white;\nlabel(btex %d etex, z%d+z2001);\nlabel(btex %d etex, z%d+z2002);\nlabel(btex %d etex, z%d+z2003);\npickup pencircle scaled .5;\ndraw z%d+z2004..z%d+z2006..z%d+z2006..z%d+z2007..cycle;\n" % (i, i, i, i, string_data[i][2], i, string_data[i][1], i, string_data[i][0], i, i, i, i, i) else: - outstring = outstring+"%%%d %d %d %d\npickup pencircle scaled 1;\nfill z%d+z2005..z%d+z2006..z%d+z2007..z%d+z2008..cycle withcolor white;\nlabel(btex %d etex, z%d+z2001);\nlabel(btex %d etex, z%d+z2002);\nlabel(btex %d etex, z%d+z2003);\nlabel(btex %d etex, z%d+z2004);\npickup pencircle scaled .5;\ndraw z%d+z2005..z%d+z2006..z%d+z2007..z%d+z2008..cycle;\n\n" % (string_data[i][0],string_data[i][1],string_data[i][2],string_data[i][3],i,i,i,i,string_data[i][0],i,string_data[i][1],i,string_data[i][2],i,string_data[i][3],i,i,i,i,i) + outstring = outstring + "%%%d %d %d %d\npickup pencircle scaled 1;\nfill z%d+z2005..z%d+z2006..z%d+z2007..z%d+z2008..cycle withcolor white;\nlabel(btex %d etex, z%d+z2001);\nlabel(btex %d etex, z%d+z2002);\nlabel(btex %d etex, z%d+z2003);\nlabel(btex %d etex, z%d+z2004);\npickup pencircle scaled .5;\ndraw z%d+z2005..z%d+z2006..z%d+z2007..z%d+z2008..cycle;\n\n" % (string_data[i][0], string_data[i][1], string_data[i][2], string_data[i][3], i, i, i, i, string_data[i][0], i, string_data[i][1], i, string_data[i][2], i, string_data[i][3], i, i, i, i, i) else: outstring += "drawdot z%d;\n" % i outstring += "\nendfig;\n\nend;\n\n" @@ -1138,31 +1123,32 @@ def dot_tex(self): from sage.combinat import ranker rank = ranker.from_list(self.list())[0] - vertex_key = lambda x: "N_"+str(rank(x)) + vertex_key = lambda x: "N_" + str(rank(x)) # To do: check the regular expression # Removing %-style comments, newlines, quotes # This should probably be moved to sage.misc.latex from sage.misc.latex import latex - quoted_latex = lambda x: re.sub("\"|\r|(%[^\n]*)?\n","", latex(x)) + + quoted_latex = lambda x: re.sub("\"|\r|(%[^\n]*)?\n", "", latex(x)) result = "digraph G { \n node [ shape=plaintext ];\n" for x in self: - result += " " + vertex_key(x) + " [ label = \" \", texlbl = \"$"+quoted_latex(x)+"$\" ];\n" + result += " " + vertex_key(x) + " [ label = \" \", texlbl = \"$" + quoted_latex(x) + "$\" ];\n" for x in self: for i in self.index_set(): child = x.f(i) if child is None: continue - # result += " " + vertex_key(x) + " -> "+vertex_key(child)+ " [ label = \" \", texlbl = \""+quoted_latex(i)+"\" ];\n" + # result += " " + vertex_key(x) + " -> "+vertex_key(child)+ " [ label = \" \", texlbl = \""+quoted_latex(i)+"\" ];\n" if i == 0: option = "dir = back, " (source, target) = (child, x) else: option = "" (source, target) = (x, child) - result += " " + vertex_key(source) + " -> "+vertex_key(target) + " [ "+option+"label = \" \", texlbl = \""+quoted_latex(i)+"\" ];\n" + result += " " + vertex_key(source) + " -> " + vertex_key(target) + " [ " + option + "label = \" \", texlbl = \"" + quoted_latex(i) + "\" ];\n" result += "}" return result @@ -1217,6 +1203,7 @@ def tensor(self, *crystals, **options): ([2, 1, 1], [1, 2, 1]) """ from sage.combinat.crystals.tensor_product import TensorProductOfCrystals + return TensorProductOfCrystals(self, *crystals, **options) def direct_sum(self, X): @@ -1242,6 +1229,7 @@ def direct_sum(self, X): if X not in Crystals(): raise ValueError("{} is not a crystal".format(X)) from sage.combinat.crystals.direct_sum import DirectSumOfCrystals + return DirectSumOfCrystals([self, X]) __add__ = direct_sum @@ -1281,8 +1269,7 @@ def connected_components(self): [The crystal of tableaux of type ['A', 2] and shape(s) [[2, 1]], The crystal of letters for type ['A', 2]]] """ - return [self.subcrystal(generators=[mg]) - for mg in self.connected_components_generators()] + return [self.subcrystal(generators=[mg]) for mg in self.connected_components_generators()] def number_of_connected_components(self): """ @@ -1599,6 +1586,7 @@ def to_highest_weight(self, index_set=None): ValueError: this is not a highest weight crystal """ from sage.categories.highest_weight_crystals import HighestWeightCrystals + if index_set is None: if HighestWeightCrystals() not in self.parent().categories(): raise ValueError("this is not a highest weight crystal") @@ -1642,6 +1630,7 @@ def to_lowest_weight(self, index_set=None): ValueError: this is not a highest weight crystal """ from sage.categories.highest_weight_crystals import HighestWeightCrystals + if index_set is None: if HighestWeightCrystals() not in self.parent().categories(): raise ValueError("this is not a highest weight crystal") @@ -1699,8 +1688,7 @@ def all_paths_to_highest_weight(self, index_set=None): if hw: yield [] - def subcrystal(self, index_set=None, max_depth=float("inf"), direction='both', - contained=None, cartan_type=None, category=None): + def subcrystal(self, index_set=None, max_depth=float("inf"), direction='both', contained=None, cartan_type=None, category=None): r""" Construct the subcrystal generated by ``self`` using `e_i` and/or `f_i` for all `i` in ``index_set``. @@ -1754,9 +1742,7 @@ def subcrystal(self, index_set=None, max_depth=float("inf"), direction='both', sage: S.category() Category of finite highest weight crystals """ - return self.parent().subcrystal(generators=[self], index_set=index_set, - max_depth=max_depth, direction=direction, - category=category) + return self.parent().subcrystal(generators=[self], index_set=index_set, max_depth=max_depth, direction=direction, category=category) def tensor(self, *elts): r""" @@ -1788,6 +1774,7 @@ class SubcategoryMethods: """ Methods for all subcategories. """ + def TensorProducts(self): r""" Return the full subcategory of objects of ``self`` constructed @@ -1809,6 +1796,7 @@ class TensorProducts(TensorProductsCategory): """ The category of crystals constructed by tensor product of crystals. """ + @cached_method def extra_super_categories(self): """ @@ -1821,6 +1809,7 @@ def extra_super_categories(self): Finite = LazyImport('sage.categories.finite_crystals', 'FiniteCrystals') + ############################################################################### ## Morphisms @@ -1841,8 +1830,8 @@ class CrystalMorphism(Morphism): the index set of the domain and whose values are scaling factors for the weight, `\varepsilon` and `\varphi` """ - def __init__(self, parent, cartan_type=None, - virtualization=None, scaling_factors=None): + + def __init__(self, parent, cartan_type=None, virtualization=None, scaling_factors=None): """ Initialize ``self``. @@ -1867,6 +1856,7 @@ def __init__(self, parent, cartan_type=None, except (TypeError, ValueError): virtualization = {i: (virtualization(i),) for i in index_set} from sage.sets.family import Family + self._virtualization = Family(virtualization) self._scaling_factors = Family(scaling_factors) @@ -2053,9 +2043,8 @@ class CrystalMorphismByGenerators(CrystalMorphism): :meth:`sage.categories.crystals.Crystals.ParentMethods.crystal_morphism` """ - def __init__(self, parent, on_gens, cartan_type=None, - virtualization=None, scaling_factors=None, - gens=None, check=True): + + def __init__(self, parent, on_gens, cartan_type=None, virtualization=None, scaling_factors=None, gens=None, check=True): """ Construct a virtual crystal morphism. @@ -2071,8 +2060,7 @@ def __init__(self, parent, on_gens, cartan_type=None, sage: H = Hom(B, C) sage: psi = H(C.module_generators) """ - CrystalMorphism.__init__(self, parent, cartan_type, - virtualization, scaling_factors) + CrystalMorphism.__init__(self, parent, cartan_type, virtualization, scaling_factors) if gens is None: if isinstance(on_gens, collections.abc.Mapping): @@ -2116,8 +2104,7 @@ def _repr_defn(self): [[[1]], [[2]], [[1]]] |--> [[1, 1], [2]] [[[3]], [[2]], [[1]]] |--> None """ - return '\n'.join('{} |--> {}'.format(mg, im) - for mg, im in zip(self._gens, self.im_gens())) + return '\n'.join('{} |--> {}'.format(mg, im) for mg, im in zip(self._gens, self.im_gens())) def _check(self): """ @@ -2193,7 +2180,7 @@ def _call_(self, x): s = [] sf = self._scaling_factors[i] for j in self._virtualization[i]: - s += [j]*sf + s += [j] * sf if op == 'e': cur = cur.f_string(s) elif op == 'f': @@ -2255,7 +2242,7 @@ def to_module_generator(self, x): for i in index_set: next = cur.e(i) if next in mg: - gen,ef,indices = self._path_mg_cache[next] + gen, ef, indices = self._path_mg_cache[next] ef = cur_ef + ['e'] + ef indices = cur_indices + [i] + indices self._path_mg_cache[x] = (gen, ef, indices) @@ -2269,7 +2256,7 @@ def to_module_generator(self, x): # Now for f's next = cur.f(i) if next in mg: - gen,ef,indices = self._path_mg_cache[next] + gen, ef, indices = self._path_mg_cache[next] ef = cur_ef + ['f'] + ef indices = cur_indices + [i] + indices self._path_mg_cache[x] = (gen, ef, indices) @@ -2317,16 +2304,12 @@ def image(self): sage: psi.image() Virtual crystal of The crystal of tableaux of type ['D', 4] and shape(s) [[2]] of type ['B', 3] """ - #if not self.is_strict(): + # if not self.is_strict(): # raise NotImplementedError from sage.combinat.crystals.subcrystal import Subcrystal - return Subcrystal(self.codomain(), - virtualization=self._virtualization, - scaling_factors=self._scaling_factors, - generators=self.im_gens(), - cartan_type=self._cartan_type, - index_set=self._cartan_type.index_set(), - category=self.domain().category()) + + return Subcrystal(self.codomain(), virtualization=self._virtualization, scaling_factors=self._scaling_factors, generators=self.im_gens(), cartan_type=self._cartan_type, index_set=self._cartan_type.index_set(), category=self.domain().category()) + ############################################################################### ## Homset @@ -2497,6 +2480,7 @@ class CrystalHomset(Homset): [[-2]] |--> [[-2, -2]] [[-1]] |--> [[-1, -1]] """ + def __init__(self, X, Y, category=None): """ Initialize ``self``. @@ -2545,15 +2529,12 @@ def _coerce_impl(self, x): # Case 1: the parent fits if x.parent() == self: - return self.element_class(self, x._on_gens, - x._virtualization, x._scaling_factors, - x._cartan_type, x._gens) + return self.element_class(self, x._on_gens, x._virtualization, x._scaling_factors, x._cartan_type, x._gens) # TODO: Should we try extraordinary measures (like twisting)? raise ValueError - def __call__(self, on_gens, cartan_type=None, index_set=None, generators=None, - automorphism=None, virtualization=None, scaling_factors=None, check=True): + def __call__(self, on_gens, cartan_type=None, index_set=None, generators=None, automorphism=None, virtualization=None, scaling_factors=None, check=True): """ Construct a crystal morphism. @@ -2576,6 +2557,7 @@ def __call__(self, on_gens, cartan_type=None, index_set=None, generators=None, cartan_type = self.domain().cartan_type() else: from sage.combinat.root_system.cartan_type import CartanType + cartan_type = CartanType(cartan_type) if index_set is None: index_set = cartan_type.index_set() @@ -2603,9 +2585,7 @@ def __call__(self, on_gens, cartan_type=None, index_set=None, generators=None, else: virtualization = {i: (automorphism[i],) for i in automorphism} - return self.element_class(self, on_gens, cartan_type, - virtualization, scaling_factors, - generators, check) + return self.element_class(self, on_gens, cartan_type, virtualization, scaling_factors, generators, check) def _an_element_(self): """ diff --git a/src/sage/categories/cw_complexes.py b/src/sage/categories/cw_complexes.py index 844a51139cb..367cb7e171d 100644 --- a/src/sage/categories/cw_complexes.py +++ b/src/sage/categories/cw_complexes.py @@ -1,12 +1,13 @@ r""" CW Complexes """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2015 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method @@ -39,6 +40,7 @@ class CWComplexes(Category_singleton): sage: TestSuite(C).run() """ + @cached_method def super_categories(self): """ @@ -118,6 +120,7 @@ class Finite(CategoryWithAxiom): A finite CW complex is a CW complex with a finite number of cells. """ + def extra_super_categories(self): """ Return the extra super categories of ``self``. diff --git a/src/sage/categories/dedekind_domains.py b/src/sage/categories/dedekind_domains.py index 62e277bb528..d3cd5ec3874 100644 --- a/src/sage/categories/dedekind_domains.py +++ b/src/sage/categories/dedekind_domains.py @@ -1,6 +1,7 @@ r""" Dedekind Domains """ + # **************************************************************************** # Distributed under the terms of the GNU General Public License (GPL) # https://www.gnu.org/licenses/ @@ -29,6 +30,7 @@ class DedekindDomains(Category): sage: TestSuite(C).run() """ + def super_categories(self): """ EXAMPLES:: @@ -56,6 +58,7 @@ def krull_dimension(self): 1 """ from sage.rings.integer_ring import ZZ + return ZZ.one() def is_integrally_closed(self) -> bool: diff --git a/src/sage/categories/discrete_valuation.py b/src/sage/categories/discrete_valuation.py index 9007d368035..539fc7664c9 100644 --- a/src/sage/categories/discrete_valuation.py +++ b/src/sage/categories/discrete_valuation.py @@ -1,12 +1,13 @@ r""" Discrete Valuation Rings (DVR) and Fields (DVF) """ -#************************************************************************** + +# ************************************************************************** # Copyright (C) 2013 Xavier Caruso # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#************************************************************************** +# ************************************************************************** from sage.misc.abstract_method import abstract_method @@ -25,6 +26,7 @@ class DiscreteValuationRings(Category_singleton): True sage: TestSuite(DiscreteValuationRings()).run() """ + def super_categories(self): """ EXAMPLES:: @@ -201,6 +203,7 @@ def gcd(self, other): uniformizer. """ from sage.rings.infinity import Infinity + val = min(self.valuation(), other.valuation()) if val is Infinity: return self.parent()(0) @@ -213,6 +216,7 @@ def lcm(self, other): uniformizer. """ from sage.rings.infinity import Infinity + val = max(self.valuation(), other.valuation()) if val is Infinity: return self.parent()(0) @@ -304,6 +308,7 @@ def _matrix_hessenbergize(self, H): [ ...00000 ...44440 ...44443] """ from sage.matrix.matrix_cdv import hessenbergize_cdvf + hessenbergize_cdvf(H) class ElementMethods: diff --git a/src/sage/categories/distributive_magmas_and_additive_magmas.py b/src/sage/categories/distributive_magmas_and_additive_magmas.py index e9dd3d90e2b..31c9857ae3f 100644 --- a/src/sage/categories/distributive_magmas_and_additive_magmas.py +++ b/src/sage/categories/distributive_magmas_and_additive_magmas.py @@ -1,6 +1,7 @@ r""" Distributive Magmas and Additive Magmas """ + # **************************************************************************** # Copyright (C) 2010 Nicolas Borie # @@ -75,6 +76,7 @@ def _test_distributivity(self, **options): tester = self._tester(**options) tester.some_elements() from sage.misc.misc import some_tuples + for x, y, z in some_tuples(tester.some_elements(), 3, tester._max_runs): # left distributivity tester.assertEqual(x * (y + z), (x * y) + (x * z)) diff --git a/src/sage/categories/division_rings.py b/src/sage/categories/division_rings.py index 42a11a28b68..9548faeec6c 100644 --- a/src/sage/categories/division_rings.py +++ b/src/sage/categories/division_rings.py @@ -1,12 +1,13 @@ r""" Division rings """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.lazy_import import LazyImport from sage.categories.category_with_axiom import CategoryWithAxiom @@ -104,6 +105,7 @@ def Finite_extra_super_categories(self): True """ from sage.categories.magmas import Magmas + return (Magmas().Commutative(),) class ParentMethods: diff --git a/src/sage/categories/domains.py b/src/sage/categories/domains.py index ee6f1d585d2..cef51efa377 100644 --- a/src/sage/categories/domains.py +++ b/src/sage/categories/domains.py @@ -1,13 +1,14 @@ r""" Domains """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2012 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.lazy_import import LazyImport from sage.categories.category_with_axiom import CategoryWithAxiom @@ -78,7 +79,7 @@ def _test_zero_divisors(self, **options): sage: ZpFM(5)._test_zero_divisors() # needs sage.rings.padics """ if not self.is_exact(): - return # Can't check on inexact rings + return # Can't check on inexact rings tester = self._tester(**options) @@ -86,7 +87,8 @@ def _test_zero_divisors(self, **options): S = [s for s in tester.some_elements() if not s.is_zero()] from sage.misc.misc import some_tuples - for a,b in some_tuples(S, 2, tester._max_runs): + + for a, b in some_tuples(S, 2, tester._max_runs): p = a * b tester.assertFalse(p.is_zero()) diff --git a/src/sage/categories/drinfeld_modules.py b/src/sage/categories/drinfeld_modules.py index 62c4b8cbecc..d00e83cc954 100644 --- a/src/sage/categories/drinfeld_modules.py +++ b/src/sage/categories/drinfeld_modules.py @@ -237,11 +237,9 @@ def __init__(self, base_morphism, name='τ'): raise TypeError('input must be a field') # Check domain of base morphism is Fq[T] if not isinstance(function_ring, PolynomialRing_generic): - raise NotImplementedError('function ring must be a polynomial ' - 'ring') + raise NotImplementedError('function ring must be a polynomial ' 'ring') function_ring_base = function_ring.base_ring() - if not function_ring_base.is_field() \ - or not function_ring_base.is_finite(): + if not function_ring_base.is_field() or not function_ring_base.is_finite(): raise TypeError('function ring base must be a finite field') # Shortcuts Fq = function_ring_base @@ -251,8 +249,7 @@ def __init__(self, base_morphism, name='τ'): # Build K{t} d = log(Fq.cardinality(), Fq.characteristic()) tau = K.frobenius_endomorphism(d) - self._ore_polring = OrePolynomialRing(K, tau, names=name, - polcast=False) + self._ore_polring = OrePolynomialRing(K, tau, names=name, polcast=False) # Create constant coefficient self._constant_coefficient = base_morphism(T) # Create characteristic @@ -288,8 +285,7 @@ def _latex_(self): sage: latex(C) \text{Category{ }of{ }Drinfeld{ }modules{ }over{ }\Bold{F}_{11^{4}} """ - return f'\\text{{Category{{ }}of{{ }}Drinfeld{{ }}modules{{ }}' \ - f'over{{ }}{latex(self._base_field)}' + return f'\\text{{Category{{ }}of{{ }}Drinfeld{{ }}modules{{ }}' f'over{{ }}{latex(self._base_field)}' def _repr_(self): r""" @@ -436,8 +432,7 @@ def characteristic(self): 0 """ if self._characteristic is None: - raise NotImplementedError('function ring characteristic not ' - 'implemented in this case') + raise NotImplementedError('function ring characteristic not ' 'implemented in this case') return self._characteristic def constant_coefficient(self): @@ -505,12 +500,12 @@ def object(self, gen): True """ from sage.rings.function_field.drinfeld_modules.drinfeld_module import DrinfeldModule + # If gen is not in the Ore polring, an exception is raised gen = self._ore_polring(gen) T = self._function_ring.gen() if gen[0] != self._base_morphism(T): - raise ValueError('constant coefficient must equal that of the ' - 'category') + raise ValueError('constant coefficient must equal that of the ' 'category') return DrinfeldModule(self._function_ring, gen) def ore_polring(self): diff --git a/src/sage/categories/dual.py b/src/sage/categories/dual.py index fe5bce5307a..cbf7ca4d872 100644 --- a/src/sage/categories/dual.py +++ b/src/sage/categories/dual.py @@ -5,12 +5,13 @@ - Nicolas M. Thiery (2009-2010): initial revision """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2009 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** # could do SelfDualCategory @@ -21,6 +22,7 @@ class DualFunctor(CovariantFunctorialConstruction): """ A singleton class for the dual functor """ + _functor_name = "dual" _functor_category = "DualObjects" symbol = "^*" diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index 37291003dbf..4f004af1d01 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -1,6 +1,7 @@ r""" Enumerated sets """ + # **************************************************************************** # Copyright (C) 2009 Florent Hivert # @@ -15,6 +16,7 @@ from sage.categories.sets_cat import EmptySetError from sage.categories.cartesian_product import CartesianProductsCategory from sage.misc.lazy_import import lazy_import + lazy_import("sage.rings.integer", "Integer") @@ -149,6 +151,7 @@ def _call_(self, X): {0, 1, 2, 3} """ import sage.sets.set + if isinstance(X, (tuple, list, set, range, sage.sets.set.Set_object_enumerated)): return sage.sets.finite_enumerated_set.FiniteEnumeratedSet(X) raise NotImplementedError @@ -229,13 +232,12 @@ def __iter__(self): [5, 6, 7] """ # Check if .first() and .next(x) are overridden in the subclass - if ( self.first != self._first_from_iterator and - self.next != self._next_from_iterator ): + if self.first != self._first_from_iterator and self.next != self._next_from_iterator: return self._iterator_from_next() - #Check to see if .unrank() is overridden in the subclass + # Check to see if .unrank() is overridden in the subclass if self.unrank != self._unrank_from_iterator: return self._iterator_from_unrank() - #Finally, check to see if .list() is overridden in the subclass + # Finally, check to see if .list() is overridden in the subclass if self.list != self._list_default: return self._iterator_from_list() raise NotImplementedError("iterator called but not implemented") @@ -468,6 +470,7 @@ def __getitem__(self, i): to an integer """ from sage.rings.infinity import Infinity + if isinstance(i, slice): return self.unrank_range(i.start, i.stop, i.step) i = Integer(i) @@ -491,6 +494,7 @@ def __len__(self): 512 """ from sage.rings.infinity import Infinity + try: c = self.cardinality() if c is Infinity: @@ -520,7 +524,7 @@ def tuple(self): sage: l is R.tuple() True """ - try: # shortcut + try: # shortcut if self._list is not None: return self._tuple_from_list() except AttributeError: @@ -530,13 +534,15 @@ def tuple(self): return tuple(self.list()) from sage.rings.infinity import Infinity + try: if self.cardinality() is Infinity: raise NotImplementedError('cannot list an infinite set') - else: # finite cardinality + else: # finite cardinality return self._tuple_from_iterator() except AttributeError: raise NotImplementedError('unknown cardinality') + _tuple_default = tuple def _tuple_from_iterator(self): @@ -610,7 +616,8 @@ def list(self): [1, 2, 3] """ return list(self.tuple()) - _list_default = list # needed by the check system. + + _list_default = list # needed by the check system. def _list_from_iterator(self): r""" @@ -691,6 +698,7 @@ def _first_from_iterator(self): 1 """ return next(iter(self)) + first = _first_from_iterator def _next_from_iterator(self, obj): @@ -719,6 +727,7 @@ def _next_from_iterator(self, obj): while el != obj: el = next(it) return next(it) + next = _next_from_iterator def _unrank_from_iterator(self, r): @@ -749,6 +758,7 @@ def _unrank_from_iterator(self, r): ValueError: the rank must be greater than or equal to 0 """ from sage.rings.integer_ring import ZZ + if r < 0: raise ValueError("the rank must be greater than or equal to 0") if r not in ZZ: @@ -756,7 +766,8 @@ def _unrank_from_iterator(self, r): for counter, u in enumerate(self): if counter == r: return u - raise ValueError("the rank must be in the range from %s to %s" % (0,counter)) + raise ValueError("the rank must be in the range from %s to %s" % (0, counter)) + unrank = _unrank_from_iterator def _rank_from_iterator(self, x): @@ -908,7 +919,7 @@ def _an_element_from_iterator(self): # Should this be implemented from first instead? _an_element_ = _an_element_from_iterator - #FIXME: use combinatorial_class_from_iterator once class_from_iterator.patch is in + # FIXME: use combinatorial_class_from_iterator once class_from_iterator.patch is in def _some_elements_from_iterator(self): """ Return some elements in ``self``. @@ -1009,9 +1020,9 @@ def map(self, f, name=None, *, is_injective=True): image.rename(name) return image -# -# Consistency test suite for an enumerated set: -# + # + # Consistency test suite for an enumerated set: + # def _test_enumerated_set_contains(self, **options): """ Check that the methods :meth:`.__contains__` and :meth:`.__iter__` are consistent. @@ -1136,5 +1147,4 @@ def first(self): sage: cartesian_product([ZZ]*10).first() (0, 0, 0, 0, 0, 0, 0, 0, 0, 0) """ - return self._cartesian_product_of_elements( - tuple(c.first() for c in self.cartesian_factors())) + return self._cartesian_product_of_elements(tuple(c.first() for c in self.cartesian_factors())) diff --git a/src/sage/categories/euclidean_domains.py b/src/sage/categories/euclidean_domains.py index ebf3bca2bb4..a25068ca0b9 100644 --- a/src/sage/categories/euclidean_domains.py +++ b/src/sage/categories/euclidean_domains.py @@ -8,6 +8,7 @@ - Julian Rueth (2013-09-13): added euclidean degree, quotient remainder, and their tests """ + # **************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2013 Julian Rueth @@ -40,6 +41,7 @@ class EuclideanDomains(Category_singleton): sage: TestSuite(EuclideanDomains()).run() """ + def super_categories(self): """ EXAMPLES:: @@ -103,15 +105,17 @@ def gcd_free_basis(self, elts): ... TypeError: unable to convert x + 1 to an element of Rational Field """ + def refine(a, b): g = a.gcd(b) if g.is_unit(): return (a, set(), b) - l1, s1, r1 = refine(a//g, g) - l2, s2, r2 = refine(r1, b//g) + l1, s1, r1 = refine(a // g, g) + l2, s2, r2 = refine(r1, b // g) s1.update(s2) s1.add(l2) return (l1, s1, r2) + elts = Sequence(elts, universe=self) res = set() if len(elts) == 1: @@ -146,13 +150,15 @@ def _test_euclidean_degree(self, **options): min_degree = self.one().euclidean_degree() from sage.rings.semirings.non_negative_integer_semiring import NN + for a in S: tester.assertIn(a.euclidean_degree(), NN) tester.assertGreaterEqual(a.euclidean_degree(), min_degree) tester.assertEqual(a.euclidean_degree() == min_degree, a.is_unit()) from sage.misc.misc import some_tuples - for a,b in some_tuples(S, 2, tester._max_runs): + + for a, b in some_tuples(S, 2, tester._max_runs): p = a * b # For rings which are not exact, we might get something that # acts like a zero divisor. @@ -179,14 +185,15 @@ def _test_quo_rem(self, **options): tester = self._tester(**options) S = tester.some_elements() from sage.misc.misc import some_tuples - for a,b in some_tuples(S, 2, tester._max_runs): + + for a, b in some_tuples(S, 2, tester._max_runs): if b.is_zero(): tester.assertRaises(ZeroDivisionError, lambda: a.quo_rem(b)) else: - q,r = a.quo_rem(b) + q, r = a.quo_rem(b) tester.assertIn(q, self) tester.assertIn(r, self) - tester.assertEqual(a,q*b+r) + tester.assertEqual(a, q * b + r) if r != 0: tester.assertLess(r.euclidean_degree(), b.euclidean_degree()) diff --git a/src/sage/categories/examples/algebras_with_basis.py b/src/sage/categories/examples/algebras_with_basis.py index 995670f3a43..15cc39591c1 100644 --- a/src/sage/categories/examples/algebras_with_basis.py +++ b/src/sage/categories/examples/algebras_with_basis.py @@ -32,9 +32,7 @@ def __init__(self, R, alphabet=("a", "b", "c")): sage: TestSuite(A).run() # needs sage.modules """ self._alphabet = alphabet - CombinatorialFreeModule.__init__(self, R, - Words(alphabet, infinite=False), - category=AlgebrasWithBasis(R)) + CombinatorialFreeModule.__init__(self, R, Words(alphabet, infinite=False), category=AlgebrasWithBasis(R)) def _repr_(self): """ @@ -92,10 +90,10 @@ def algebra_generators(self): Family (B[word: a], B[word: b], B[word: c]) """ Words = self.basis().keys() - return Family( [self.monomial(Words(a)) for a in self._alphabet] ) + return Family([self.monomial(Words(a)) for a in self._alphabet]) # FIXME: use this once the keys argument of FiniteFamily will be honoured # for the specifying the order of the elements in the family - #return Family(self._alphabet, lambda a: self.term(self.basis().keys()(a))) + # return Family(self._alphabet, lambda a: self.term(self.basis().keys()(a))) Example = FreeAlgebra diff --git a/src/sage/categories/examples/commutative_additive_monoids.py b/src/sage/categories/examples/commutative_additive_monoids.py index 89862be09a4..8cc07ab6c80 100644 --- a/src/sage/categories/examples/commutative_additive_monoids.py +++ b/src/sage/categories/examples/commutative_additive_monoids.py @@ -1,6 +1,7 @@ """ Examples of commutative additive monoids """ + # *************************************************************************** # Copyright (C) 2008-2009 Nicolas M. Thiery # diff --git a/src/sage/categories/examples/commutative_additive_semigroups.py b/src/sage/categories/examples/commutative_additive_semigroups.py index 0c26e0c1f83..c6c77684290 100644 --- a/src/sage/categories/examples/commutative_additive_semigroups.py +++ b/src/sage/categories/examples/commutative_additive_semigroups.py @@ -1,6 +1,7 @@ """ Examples of commutative additive semigroups """ + # *************************************************************************** # Copyright (C) 2008-2009 Nicolas M. Thiery # @@ -180,8 +181,7 @@ def _repr_(self) -> str: 0 """ d = self.value - result = ' + '.join(("%s*%s" % (d[a], a) if d[a] != 1 else a) - for a in sorted(d.keys()) if d[a] != 0) + result = ' + '.join(("%s*%s" % (d[a], a) if d[a] != 1 else a) for a in sorted(d.keys()) if d[a] != 0) return '0' if not result else result def __hash__(self): diff --git a/src/sage/categories/examples/coxeter_groups.py b/src/sage/categories/examples/coxeter_groups.py index ac76a708bec..3e57e07f57e 100644 --- a/src/sage/categories/examples/coxeter_groups.py +++ b/src/sage/categories/examples/coxeter_groups.py @@ -1,7 +1,9 @@ """ Examples of Coxeter groups """ + # temporary until someone implements an appropriate example from . import finite_weyl_groups + Example = finite_weyl_groups.Example diff --git a/src/sage/categories/examples/crystals.py b/src/sage/categories/examples/crystals.py index d214413c678..3bb126741ec 100644 --- a/src/sage/categories/examples/crystals.py +++ b/src/sage/categories/examples/crystals.py @@ -137,8 +137,8 @@ def e(self, i): [[2, 1, 1], [3, 2, 2], [4, 3, 3], [5, 4, 4]] """ assert i in self.index_set() - if self.value == i+1: - return self.parent()(self.value-1) + if self.value == i + 1: + return self.parent()(self.value - 1) return None def f(self, i): @@ -153,7 +153,7 @@ def f(self, i): """ assert i in self.index_set() if self.value == i: - return self.parent()(self.value+1) + return self.parent()(self.value + 1) return None @@ -176,6 +176,7 @@ class NaiveCrystal(UniqueRepresentation, Parent): sage: C.highest_weight_vector() 0 """ + def __init__(self): """ EXAMPLES:: @@ -188,8 +189,7 @@ def __init__(self): self.n = 2 self._cartan_type = CartanType(['A', 2]) self.G = DiGraph(5) - self.G.add_edges([[0, 1, 1], [1, 2, 1], [2, 3, 1], - [3, 5, 1], [0, 4, 2], [4, 5, 2]]) + self.G.add_edges([[0, 1, 1], [1, 2, 1], [2, 3, 1], [3, 5, 1], [0, 4, 2], [4, 5, 2]]) self.module_generators = [self(0)] def __repr__(self): diff --git a/src/sage/categories/examples/cw_complexes.py b/src/sage/categories/examples/cw_complexes.py index 0fefb254c20..79517155fa5 100644 --- a/src/sage/categories/examples/cw_complexes.py +++ b/src/sage/categories/examples/cw_complexes.py @@ -1,6 +1,7 @@ """ Examples of CW complexes """ + # **************************************************************************** # Copyright (C) 2015 Travis Scrimshaw # @@ -33,6 +34,7 @@ class Surface(UniqueRepresentation, Parent): sage: TestSuite(X).run() """ + def __init__(self, bdy=(1, 2, 1, 2)): r""" EXAMPLES:: @@ -74,7 +76,7 @@ def cells(self): (2, (2-cell f,))] """ d = {0: (self.element_class(self, 0, 'v'),)} - d[1] = tuple([self.element_class(self, 0, 'e'+str(e)) for e in self._edges]) + d[1] = tuple([self.element_class(self, 0, 'e' + str(e)) for e in self._edges]) d[2] = (self.an_element(),) return Family(d) @@ -96,6 +98,7 @@ class Element(Element): """ A cell in a CW complex. """ + def __init__(self, parent, dim, name): """ Initialize ``self``. @@ -139,10 +142,7 @@ def __eq__(self, other): sage: e1 == f False """ - return (isinstance(other, Surface.Element) - and self.parent() is other.parent() - and self._dim == other._dim - and self._name == other._name) + return isinstance(other, Surface.Element) and self.parent() is other.parent() and self._dim == other._dim and self._name == other._name def dimension(self): """ diff --git a/src/sage/categories/examples/facade_sets.py b/src/sage/categories/examples/facade_sets.py index a2dbaadac6f..89501b71a13 100644 --- a/src/sage/categories/examples/facade_sets.py +++ b/src/sage/categories/examples/facade_sets.py @@ -1,12 +1,13 @@ r""" Example of facade set """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2010 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.sets_cat import Sets from sage.categories.monoids import Monoids @@ -60,6 +61,7 @@ class PositiveIntegerMonoid(UniqueRepresentation, Parent): running ._test_prod() . . . pass running ._test_some_elements() . . . pass """ + def __init__(self): r""" EXAMPLES:: @@ -158,6 +160,7 @@ class IntegersCompletion(UniqueRepresentation, Parent): running ._test_pickling() . . . pass running ._test_some_elements() . . . pass """ + def __init__(self): r""" EXAMPLES:: diff --git a/src/sage/categories/examples/filtered_algebras_with_basis.py b/src/sage/categories/examples/filtered_algebras_with_basis.py index 35bd9e715f7..3e916d87a61 100644 --- a/src/sage/categories/examples/filtered_algebras_with_basis.py +++ b/src/sage/categories/examples/filtered_algebras_with_basis.py @@ -1,12 +1,13 @@ r""" Examples of filtered algebra with basis """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.filtered_algebras_with_basis import FilteredAlgebrasWithBasis from sage.combinat.free_module import CombinatorialFreeModule @@ -45,6 +46,7 @@ class PBWBasisCrossProduct(CombinatorialFreeModule): by using :meth:`degree_on_basis` which returns the sum of exponents of the monomial """ + def __init__(self, base_ring): """ EXAMPLES:: @@ -55,10 +57,7 @@ def __init__(self, base_ring): """ I = IndexedFreeAbelianMonoid(['x', 'y', 'z'], prefix='U') - CombinatorialFreeModule.__init__(self, base_ring, I, bracket=False, - prefix='', - sorting_key=self._sort_key, - category=FilteredAlgebrasWithBasis(base_ring)) + CombinatorialFreeModule.__init__(self, base_ring, I, bracket=False, prefix='', sorting_key=self._sort_key, category=FilteredAlgebrasWithBasis(base_ring)) def _sort_key(self, x): """ @@ -171,14 +170,14 @@ def product_on_basis(self, s, t): if len(t) == 0: return self.monomial(s) if s.trailing_support() <= t.leading_support(): - return self.monomial(s*t) + return self.monomial(s * t) if len(t) == 1: if len(s) == 1: # Do the product of the generators a = s.leading_support() b = t.leading_support() - cur = self.monomial(s*t) + cur = self.monomial(s * t) if a <= b: return cur if a == 'z': diff --git a/src/sage/categories/examples/filtered_modules_with_basis.py b/src/sage/categories/examples/filtered_modules_with_basis.py index b9df0863119..84d845e8f55 100644 --- a/src/sage/categories/examples/filtered_modules_with_basis.py +++ b/src/sage/categories/examples/filtered_modules_with_basis.py @@ -81,6 +81,7 @@ class FilteredPartitionModule(CombinatorialFreeModule): sage: p.degree() # needs sage.modules 6 """ + def __init__(self, base_ring): """ EXAMPLES:: @@ -89,8 +90,7 @@ def __init__(self, base_ring): An example of a filtered module with basis: the free module on partitions over Rational Field sage: TestSuite(A).run() # needs sage.modules """ - CombinatorialFreeModule.__init__(self, base_ring, Partitions(), - category=FilteredModulesWithBasis(base_ring)) + CombinatorialFreeModule.__init__(self, base_ring, Partitions(), category=FilteredModulesWithBasis(base_ring)) # FIXME: this is currently required, because the implementation of ``basis`` # in CombinatorialFreeModule overrides that of GradedModulesWithBasis diff --git a/src/sage/categories/examples/finite_coxeter_groups.py b/src/sage/categories/examples/finite_coxeter_groups.py index 8d3d62cb9f2..73daede06f0 100644 --- a/src/sage/categories/examples/finite_coxeter_groups.py +++ b/src/sage/categories/examples/finite_coxeter_groups.py @@ -129,6 +129,7 @@ def __contains__(self, x) -> bool: (also tested by :meth:`test_an_element` :meth:`test_some_elements`) """ from sage.structure.element import parent + return parent(x) is self @cached_method @@ -230,6 +231,7 @@ def apply_simple_reflection_right(self, i): [(), (1,), (2,), (), (), (1, 2, 1), (2, 1, 2), (), (), (1, 2, 1, 2, 1)] """ from copy import copy + reduced_word = copy(self.value) n = self.parent().n if len(reduced_word) == n: diff --git a/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py index d2ffcd09177..b7fca33203b 100644 --- a/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py @@ -2,12 +2,12 @@ r""" Example of a finite dimensional algebra with basis """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2008-2015 Franco Saliola # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.cachefunc import cached_method from sage.categories.finite_dimensional_algebras_with_basis import FiniteDimensionalAlgebrasWithBasis @@ -36,14 +36,9 @@ def __init__(self, base_ring): sage: TestSuite(A).run() """ basis_keys = ['x', 'y', 'a', 'b'] - self._nonzero_products = { - 'xx':'x', 'xa':'a', 'xb':'b', - 'yy':'y', 'ay':'a', 'by':'b' - } + self._nonzero_products = {'xx': 'x', 'xa': 'a', 'xb': 'b', 'yy': 'y', 'ay': 'a', 'by': 'b'} - CombinatorialFreeModule.__init__( - self, base_ring, basis_keys, - category=FiniteDimensionalAlgebrasWithBasis(base_ring)) + CombinatorialFreeModule.__init__(self, base_ring, basis_keys, category=FiniteDimensionalAlgebrasWithBasis(base_ring)) def _repr_(self): r""" @@ -54,9 +49,7 @@ def _repr_(self): the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field """ - return "An example of a finite dimensional algebra with basis: " \ - "the path algebra of the Kronecker quiver " \ - "(containing the arrows a:x->y and b:x->y) over %s " % (self.base_ring()) + return "An example of a finite dimensional algebra with basis: " "the path algebra of the Kronecker quiver " "(containing the arrows a:x->y and b:x->y) over %s " % (self.base_ring()) def one(self): r""" @@ -104,8 +97,8 @@ def product_on_basis(self, w1, w2): sage: x*a*y a """ - if w1+w2 in self._nonzero_products: - return self.monomial(self._nonzero_products[w1+w2]) + if w1 + w2 in self._nonzero_products: + return self.monomial(self._nonzero_products[w1 + w2]) return self.zero() @cached_method diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index e43a73638c0..76987f45113 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -48,6 +48,7 @@ class AbelianLieAlgebra(Parent, UniqueRepresentation): The abelian Lie algebra on `M`. """ + @staticmethod def __classcall_private__(cls, R, n=None, M=None, ambient=None): """ @@ -96,6 +97,7 @@ def __init__(self, R, n=None, M=None, ambient=None): Parent.__init__(self, base=R, category=cat) from sage.categories.lie_algebras import LiftMorphism + self._lift_uea = LiftMorphism(self, self._construct_UEA()) self._lift_uea.register_as_coercion() @@ -107,9 +109,7 @@ def _repr_(self): An example of a finite dimensional Lie algebra with basis: the 3-dimensional abelian Lie algebra over Rational Field """ - ret = "An example of a finite dimensional Lie algebra with basis:" \ - " the {}-dimensional abelian Lie algebra over {}".format( - self.dimension(), self.base_ring()) + ret = "An example of a finite dimensional Lie algebra with basis:" " the {}-dimensional abelian Lie algebra over {}".format(self.dimension(), self.base_ring()) B = self._M.basis_matrix() if not B.is_one(): ret += " with basis matrix:\n{!r}".format(B) @@ -293,8 +293,7 @@ def basis(self): sage: L.basis() Finite family {0: (1, 0, 0), 1: (0, 1, 0), 2: (0, 0, 1)} """ - d = {i: self.element_class(self, b) - for i,b in enumerate(self._M.basis())} + d = {i: self.element_class(self, b) for i, b in enumerate(self._M.basis())} return Family(d) lie_algebra_generators = basis @@ -372,8 +371,7 @@ def leading_monomials(self): ((1, 0, 0), (0, 1, 0)) """ # for free modules, the leading monomial is actually the trailing monomial - return tuple([self._ambient._M(b.value).trailing_monomial() - for b in self.basis()]) + return tuple([self._ambient._M(b.value).trailing_monomial() for b in self.basis()]) class Element(BaseExample.Element): def __init__(self, parent, value): diff --git a/src/sage/categories/examples/finite_enumerated_sets.py b/src/sage/categories/examples/finite_enumerated_sets.py index e14386904e4..427f8b83f15 100644 --- a/src/sage/categories/examples/finite_enumerated_sets.py +++ b/src/sage/categories/examples/finite_enumerated_sets.py @@ -1,6 +1,7 @@ r""" Examples of finite enumerated sets """ + # **************************************************************************** # Copyright (C) 2009 Florent Hivert # @@ -78,8 +79,7 @@ def __init__(self): sage: TestSuite(C).run() """ self._set = [Integer(_) for _ in [1, 2, 3]] - Parent.__init__(self, facade=IntegerRing(), - category=FiniteEnumeratedSets()) + Parent.__init__(self, facade=IntegerRing(), category=FiniteEnumeratedSets()) def _repr_(self) -> str: """ @@ -126,8 +126,7 @@ def __init__(self, ambient=Example()): sage: TestSuite(C).run() """ self._ambient = ambient - Parent.__init__(self, facade=IntegerRing(), - category=FiniteEnumeratedSets().IsomorphicObjects()) + Parent.__init__(self, facade=IntegerRing(), category=FiniteEnumeratedSets().IsomorphicObjects()) def ambient(self): """ @@ -180,7 +179,7 @@ def retract(self, x): sage: C.retract(3) 9 """ - return x ** 2 + return x**2 def __contains__(self, x) -> bool: """ diff --git a/src/sage/categories/examples/finite_monoids.py b/src/sage/categories/examples/finite_monoids.py index 95c125139cf..9c1842a8afd 100644 --- a/src/sage/categories/examples/finite_monoids.py +++ b/src/sage/categories/examples/finite_monoids.py @@ -1,6 +1,7 @@ """ Examples of finite monoids """ + # *************************************************************************** # Copyright (C) 2008-2009 Nicolas M. Thiery # @@ -144,7 +145,7 @@ def an_element(self): """ return self(ZZ(42) % self.n) - class Element (ElementWrapper): + class Element(ElementWrapper): wrapped_class = Integer diff --git a/src/sage/categories/examples/finite_semigroups.py b/src/sage/categories/examples/finite_semigroups.py index a871cb6cedc..96395f064dd 100644 --- a/src/sage/categories/examples/finite_semigroups.py +++ b/src/sage/categories/examples/finite_semigroups.py @@ -1,6 +1,7 @@ """ Examples of finite semigroups """ + # *************************************************************************** # Copyright (C) 2008-2009 Nicolas M. Thiery # @@ -120,8 +121,7 @@ def __init__(self, alphabet=('a', 'b', 'c', 'd')) -> None: sage: TestSuite(S).run() """ self.alphabet = alphabet - Parent.__init__(self, - category=Semigroups().Finite().FinitelyGenerated()) + Parent.__init__(self, category=Semigroups().Finite().FinitelyGenerated()) def _repr_(self) -> str: r""" @@ -183,7 +183,7 @@ def an_element(self): return self(''.join(self.alphabet[2:] + self.alphabet[0:2])) - class Element (ElementWrapper): + class Element(ElementWrapper): wrapped_class = str __lt__ = ElementWrapper._lt_by_value diff --git a/src/sage/categories/examples/finite_weyl_groups.py b/src/sage/categories/examples/finite_weyl_groups.py index 15fdff01f5f..2d41c2e78dd 100644 --- a/src/sage/categories/examples/finite_weyl_groups.py +++ b/src/sage/categories/examples/finite_weyl_groups.py @@ -1,6 +1,7 @@ r""" Examples of finite Weyl groups """ + # **************************************************************************** # Copyright (C) 2008-2009 Nicolas M. Thiery # @@ -139,6 +140,7 @@ def cartan_type(self): ['A', 3] relabelled by {1: 0, 2: 1, 3: 2} """ from sage.combinat.root_system.cartan_type import CartanType + C = CartanType(['A', self.n - 1]) C = C.relabel(lambda i: i - 1) return C diff --git a/src/sage/categories/examples/graded_connected_hopf_algebras_with_basis.py b/src/sage/categories/examples/graded_connected_hopf_algebras_with_basis.py index 2fe5671a46d..43500356b1b 100644 --- a/src/sage/categories/examples/graded_connected_hopf_algebras_with_basis.py +++ b/src/sage/categories/examples/graded_connected_hopf_algebras_with_basis.py @@ -33,6 +33,7 @@ class GradedConnectedCombinatorialHopfAlgebraWithPrimitiveGenerator(Combinatoria where `\tau(x\otimes y) = y\otimes x`. """ + def __init__(self, base_ring): """ EXAMPLES:: @@ -40,8 +41,7 @@ def __init__(self, base_ring): sage: H = GradedHopfAlgebrasWithBasis(QQ).Connected().example() sage: TestSuite(H).run() """ - CombinatorialFreeModule.__init__(self, base_ring, NonNegativeIntegers(), - category=GradedHopfAlgebrasWithBasis(base_ring).Connected()) + CombinatorialFreeModule.__init__(self, base_ring, NonNegativeIntegers(), category=GradedHopfAlgebrasWithBasis(base_ring).Connected()) @cached_method def one_basis(self): @@ -120,7 +120,7 @@ def product_on_basis(self, i, j): sage: H.monomial(4) * H.monomial(5) P9 """ - return self.monomial(i+j) + return self.monomial(i + j) def coproduct_on_basis(self, i): r""" @@ -142,10 +142,7 @@ def coproduct_on_basis(self, i): sage: H.monomial(3).coproduct() P0 # P3 + 3*P1 # P2 + 3*P2 # P1 + P3 # P0 """ - return self.sum_of_terms( - ((i - j, j), Integer(i).binomial(j)) - for j in range(i + 1) - ) + return self.sum_of_terms(((i - j, j), Integer(i).binomial(j)) for j in range(i + 1)) Example = GradedConnectedCombinatorialHopfAlgebraWithPrimitiveGenerator diff --git a/src/sage/categories/examples/graded_modules_with_basis.py b/src/sage/categories/examples/graded_modules_with_basis.py index f69db23c8de..936a9c046cb 100644 --- a/src/sage/categories/examples/graded_modules_with_basis.py +++ b/src/sage/categories/examples/graded_modules_with_basis.py @@ -95,6 +95,7 @@ class GradedPartitionModule(CombinatorialFreeModule): sage: p.degree() # needs sage.modules 6 """ + def __init__(self, base_ring): """ EXAMPLES:: @@ -103,8 +104,7 @@ def __init__(self, base_ring): An example of a graded module with basis: the free module on partitions over Rational Field sage: TestSuite(A).run() # needs sage.modules """ - CombinatorialFreeModule.__init__(self, base_ring, Partitions(), - category=GradedModulesWithBasis(base_ring)) + CombinatorialFreeModule.__init__(self, base_ring, Partitions(), category=GradedModulesWithBasis(base_ring)) # FIXME: this is currently required, because the implementation of ``basis`` # in CombinatorialFreeModule overrides that of GradedModulesWithBasis diff --git a/src/sage/categories/examples/graphs.py b/src/sage/categories/examples/graphs.py index 063eeff1427..959b103a323 100644 --- a/src/sage/categories/examples/graphs.py +++ b/src/sage/categories/examples/graphs.py @@ -1,6 +1,7 @@ """ Examples of graphs """ + # **************************************************************************** # Copyright (C) 2015 Travis Scrimshaw # @@ -32,6 +33,7 @@ class Cycle(UniqueRepresentation, Parent): sage: TestSuite(C).run() """ + def __init__(self, n=5): r""" EXAMPLES:: @@ -95,7 +97,7 @@ def edges(self): sage: C.edges() [(0, 1), (1, 2), (2, 3), (3, 4), (4, 0)] """ - return [self( (i, (i+1) % self._n) ) for i in range(self._n)] + return [self((i, (i + 1) % self._n)) for i in range(self._n)] class Element(ElementWrapper): def dimension(self): diff --git a/src/sage/categories/examples/hopf_algebras_with_basis.py b/src/sage/categories/examples/hopf_algebras_with_basis.py index 68686fe06b3..608fe8c9be1 100644 --- a/src/sage/categories/examples/hopf_algebras_with_basis.py +++ b/src/sage/categories/examples/hopf_algebras_with_basis.py @@ -2,12 +2,12 @@ r""" Examples of Hopf algebras with basis """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2008-2009 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.cachefunc import cached_method from sage.sets.family import Family @@ -34,8 +34,7 @@ def __init__(self, R, G): sage: TestSuite(A).run() """ self._group = G - CombinatorialFreeModule.__init__(self, R, G, - category=HopfAlgebrasWithBasis(R)) + CombinatorialFreeModule.__init__(self, R, G, category=HopfAlgebrasWithBasis(R)) def _repr_(self): """ diff --git a/src/sage/categories/examples/infinite_enumerated_sets.py b/src/sage/categories/examples/infinite_enumerated_sets.py index 4d1dc54dc31..076e5ea941e 100644 --- a/src/sage/categories/examples/infinite_enumerated_sets.py +++ b/src/sage/categories/examples/infinite_enumerated_sets.py @@ -1,6 +1,7 @@ """ Examples of infinite enumerated sets """ + # **************************************************************************** # Copyright (C) 2009 Florent Hivert # @@ -161,7 +162,7 @@ def next(self, o): sage: NN.next(3) 4 """ - return self._element_constructor_(o+1) + return self._element_constructor_(o + 1) def _element_constructor_(self, i): """ diff --git a/src/sage/categories/examples/lie_algebras.py b/src/sage/categories/examples/lie_algebras.py index bb45b7673a6..dfd7a9e466f 100644 --- a/src/sage/categories/examples/lie_algebras.py +++ b/src/sage/categories/examples/lie_algebras.py @@ -2,14 +2,14 @@ r""" Examples of a Lie algebra """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** -#from sage.misc.cachefunc import cached_method +# from sage.misc.cachefunc import cached_method from sage.sets.family import Family from sage.categories.lie_algebras import LieAlgebras from sage.structure.parent import Parent @@ -63,6 +63,7 @@ class LieAlgebraFromAssociative(Parent, UniqueRepresentation): sage: h.bracket(f) == -2*f True """ + @staticmethod def __classcall_private__(cls, gens): """ @@ -103,9 +104,7 @@ def _repr_(self): Symmetric group algebra of order 3 over Rational Field generated by ([2, 1, 3], [2, 3, 1]) """ - return "An example of a Lie algebra: the Lie algebra from the" \ - " associative algebra {} generated by {}".format( - self._A, self._gens) + return "An example of a Lie algebra: the Lie algebra from the" " associative algebra {} generated by {}".format(self._A, self._gens) def _element_constructor_(self, value): """ @@ -151,6 +150,7 @@ class Element(ElementWrapper): """ Wrap an element as a Lie algebra element. """ + def __eq__(self, rhs): """ Check equality. @@ -269,10 +269,10 @@ def _acted_upon_(self, scalar, self_on_left=False): # enough information to detect apriori that this method only # accepts scalars; so it tries on some elements(), and we need # to make sure to report an error. - if hasattr( scalar, 'parent' ) and scalar.parent() != self.base_ring(): + if hasattr(scalar, 'parent') and scalar.parent() != self.base_ring(): # Temporary needed by coercion (see Polynomial/FractionField tests). if self.base_ring().has_coerce_map_from(scalar.parent()): - scalar = self.base_ring()( scalar ) + scalar = self.base_ring()(scalar) else: return None if self_on_left: diff --git a/src/sage/categories/examples/lie_algebras_with_basis.py b/src/sage/categories/examples/lie_algebras_with_basis.py index deb0dfd97da..8bb63b21b82 100644 --- a/src/sage/categories/examples/lie_algebras_with_basis.py +++ b/src/sage/categories/examples/lie_algebras_with_basis.py @@ -2,14 +2,14 @@ r""" Examples of a Lie algebra with basis """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** -#from sage.misc.cachefunc import cached_method +# from sage.misc.cachefunc import cached_method from sage.sets.family import Family from sage.categories.lie_algebras import LieAlgebras from sage.categories.algebras import Algebras @@ -24,6 +24,7 @@ class AbelianLieAlgebra(CombinatorialFreeModule): This class illustrates a minimal implementation of a Lie algebra with a distinguished basis. """ + def __init__(self, R, gens): """ EXAMPLES:: @@ -54,9 +55,7 @@ def _repr_(self): An example of a Lie algebra: the abelian Lie algebra on the generators indexed by Partitions over Rational Field """ - return "An example of a Lie algebra: the abelian Lie algebra on the" \ - " generators indexed by {} over {}".format( - self.basis().keys(), self.base_ring()) + return "An example of a Lie algebra: the abelian Lie algebra on the" " generators indexed by {} over {}".format(self.basis().keys(), self.base_ring()) def lie_algebra_generators(self): """ @@ -117,6 +116,7 @@ class IndexedPolynomialRing(CombinatorialFreeModule): for the example of the abelian Lie algebra. This should be factored out into a more complete class. """ + def __init__(self, R, indices, **kwds): """ Initialize ``self``. @@ -147,8 +147,7 @@ def _repr_(self): sage: L.universal_enveloping_algebra() Polynomial algebra with generators indexed by Partitions over Rational Field """ - return "Polynomial algebra with generators indexed by {} over {}".format( - self._indices._indices, self.base_ring()) + return "Polynomial algebra with generators indexed by {} over {}".format(self._indices._indices, self.base_ring()) def one_basis(self): """ @@ -177,7 +176,7 @@ def product_on_basis(self, x, y): sage: UEA.product_on_basis(I.an_element(), I.an_element()) P[F[]^4*F[1]^4*F[2]^6] """ - return self.monomial(x*y) + return self.monomial(x * y) def algebra_generators(self): """ @@ -191,5 +190,4 @@ def algebra_generators(self): Lazy family (algebra generator map(i))_{i in Partitions} """ I = self._indices - return Family(I._indices, lambda x: self.monomial(I.gen(x)), - name="algebra generator map") + return Family(I._indices, lambda x: self.monomial(I.gen(x)), name="algebra generator map") diff --git a/src/sage/categories/examples/magmas.py b/src/sage/categories/examples/magmas.py index 79cd0bc25cc..ae5d4a55a2c 100644 --- a/src/sage/categories/examples/magmas.py +++ b/src/sage/categories/examples/magmas.py @@ -1,6 +1,7 @@ r""" Examples of magmas """ + # **************************************************************************** # Copyright (C) 2020 Markus Wageringel # @@ -48,6 +49,7 @@ class FreeMagma(UniqueRepresentation, Parent): sage: TestSuite(M).run() """ + def __init__(self, alphabet=('a', 'b', 'c', 'd')) -> None: r""" The free magma. @@ -68,8 +70,7 @@ def __init__(self, alphabet=('a', 'b', 'c', 'd')) -> None: True """ if any('(' in x or ')' in x or '*' in x for x in alphabet): - raise ValueError("alphabet must not contain characters " - "'(', ')' or '*'") + raise ValueError("alphabet must not contain characters " "'(', ')' or '*'") if not alphabet: raise NotImplementedError("free magma must have at least one generator") @@ -85,8 +86,7 @@ def _repr_(self) -> str: sage: FreeMagma(('a', 'b', 'c'))._repr_() "An example of a magma: the free magma generated by ('a', 'b', 'c')" """ - return ("An example of a magma: the free magma generated by %s" - % (self.alphabet,)) + return "An example of a magma: the free magma generated by %s" % (self.alphabet,) def product(self, x, y): r""" @@ -155,6 +155,7 @@ class Element(ElementWrapper): r""" The class for elements of the free magma. """ + wrapped_class = str diff --git a/src/sage/categories/examples/manifolds.py b/src/sage/categories/examples/manifolds.py index 6a748884eec..464920933c7 100644 --- a/src/sage/categories/examples/manifolds.py +++ b/src/sage/categories/examples/manifolds.py @@ -1,6 +1,7 @@ """ Examples of manifolds """ + # **************************************************************************** # Copyright (C) 2015 Travis Scrimshaw # @@ -56,8 +57,7 @@ def _repr_(self): sage: Manifolds(QQ).example() An example of a Rational Field manifold: the 3-dimensional plane """ - return "An example of a {} manifold: the {}-dimensional plane".format( - self.base_ring(), self._n) + return "An example of a {} manifold: the {}-dimensional plane".format(self.base_ring(), self._n) def dimension(self): """ @@ -85,7 +85,7 @@ def an_element(self): (0, 0, 0) """ zero = self.base_ring().zero() - return self(tuple([zero]*self._n)) + return self(tuple([zero] * self._n)) Element = ElementWrapper diff --git a/src/sage/categories/examples/monoids.py b/src/sage/categories/examples/monoids.py index 10b6ea61bd8..533dd9748bc 100644 --- a/src/sage/categories/examples/monoids.py +++ b/src/sage/categories/examples/monoids.py @@ -1,6 +1,7 @@ r""" Examples of monoids """ + # *************************************************************************** # Copyright (C) 2008-2009 Nicolas M. Thiery # @@ -136,7 +137,7 @@ def monoid_generators(self): """ return Family(self.alphabet, self) - class Element (ElementWrapper): + class Element(ElementWrapper): wrapped_class = str diff --git a/src/sage/categories/examples/posets.py b/src/sage/categories/examples/posets.py index 638233956f1..ab9efd06697 100644 --- a/src/sage/categories/examples/posets.py +++ b/src/sage/categories/examples/posets.py @@ -1,6 +1,7 @@ """ Examples of posets """ + # *************************************************************************** # Copyright (C) 2011 Nicolas M. Thiery # diff --git a/src/sage/categories/examples/semigroups.py b/src/sage/categories/examples/semigroups.py index 20e67c5a755..d00845997f4 100644 --- a/src/sage/categories/examples/semigroups.py +++ b/src/sage/categories/examples/semigroups.py @@ -1,6 +1,7 @@ r""" Examples of semigroups """ + # *************************************************************************** # Copyright (C) 2008-2009 Nicolas M. Thiery # @@ -67,6 +68,7 @@ class LeftZeroSemigroup(UniqueRepresentation, Parent): running ._test_pickling() . . . pass running ._test_some_elements() . . . pass """ + def __init__(self) -> None: r""" The left zero semigroup. @@ -173,6 +175,7 @@ class FreeSemigroup(UniqueRepresentation, Parent): sage: TestSuite(S).run() """ + def __init__(self, alphabet=('a', 'b', 'c', 'd')) -> None: r""" The free semigroup. @@ -286,6 +289,7 @@ class Element(ElementWrapper): r""" The class for elements of the free semigroup. """ + wrapped_class = str @@ -341,6 +345,7 @@ class QuotientOfLeftZeroSemigroup(UniqueRepresentation, Parent): running ._test_pickling() . . . pass running ._test_some_elements() . . . pass """ + def _element_constructor_(self, x): r""" Convert ``x`` into an element of this semigroup. @@ -471,8 +476,7 @@ def some_elements(self) -> list: sage: S.some_elements() [1, 2, 3, 8, 42, 42] """ - return [self.retract(self.ambient()(i)) - for i in [1, 2, 3, 8, 42, 100]] + return [self.retract(self.ambient()(i)) for i in [1, 2, 3, 8, 42, 100]] def retract(self, x): r""" @@ -501,6 +505,7 @@ def retract(self, x): True """ from sage.rings.integer_ring import ZZ + assert x in self.ambient() and x.value in ZZ if x.value > 42: return self.the_answer() diff --git a/src/sage/categories/examples/semirings.py b/src/sage/categories/examples/semirings.py index a92c93afdf9..4e9de096e99 100644 --- a/src/sage/categories/examples/semirings.py +++ b/src/sage/categories/examples/semirings.py @@ -1,6 +1,7 @@ r""" Examples of semirings """ + # **************************************************************************** # Copyright (C) 2024 F. Chapoton # @@ -39,6 +40,7 @@ class Ternary(Element): The same semantic works for graphs instead of sets. """ + def __init__(self, parent, n) -> None: """ Initialize one element. @@ -156,6 +158,7 @@ class TernaryLogic(UniqueRepresentation, Parent): running ._test_some_elements() . . . pass running ._test_zero() . . . pass """ + def __init__(self) -> None: r""" The ternary-logic semiring. diff --git a/src/sage/categories/examples/sets_cat.py b/src/sage/categories/examples/sets_cat.py index 107396894b8..b9adf33dfe0 100644 --- a/src/sage/categories/examples/sets_cat.py +++ b/src/sage/categories/examples/sets_cat.py @@ -81,6 +81,7 @@ class PrimeNumbers(UniqueRepresentation, Parent): running ._test_pickling() . . . pass running ._test_some_elements() . . . pass """ + def __init__(self): """ TESTS:: @@ -166,6 +167,7 @@ class PrimeNumbers_Abstract(UniqueRepresentation, Parent): sage: P = Sets().example("inherits") sage: P = Sets().example("wrapper") """ + def __init__(self): """ TESTS:: @@ -302,7 +304,7 @@ def next(self): return self.parent().next(self) -#*************************************************************************# +# *************************************************************************# class PrimeNumbers_Inherits(PrimeNumbers_Abstract): """ An example of parent in the category of sets: the set of prime numbers. @@ -402,8 +404,7 @@ def __contains__(self, p) -> bool: sage: 12 in P False """ - return (isinstance(p, self.element_class) and p.parent() is self - or isinstance(p, Integer) and p.is_prime()) + return isinstance(p, self.element_class) and p.parent() is self or isinstance(p, Integer) and p.is_prime() def _from_integer_(self, p): """ @@ -435,7 +436,7 @@ def __init__(self, parent, p): IntegerWrapper.__init__(self, parent, p) -#*************************************************************************# +# *************************************************************************# class PrimeNumbers_Wrapper(PrimeNumbers_Abstract): """ An example of parent in the category of sets: the set of prime numbers. @@ -481,6 +482,7 @@ class PrimeNumbers_Wrapper(PrimeNumbers_Abstract): sage: TestSuite(P).run() """ + def __init__(self): """ TESTS:: @@ -498,6 +500,7 @@ def __init__(self): Parent.__init__(self, category=Sets()) from sage.rings.integer_ring import IntegerRing from sage.categories.homset import Hom + self.mor = Hom(self, IntegerRing())(lambda z: z.value) self._populate_coercion_lists_(embedding=self.mor) @@ -520,8 +523,7 @@ def __contains__(self, p) -> bool: sage: 12 in P False """ - return (isinstance(p, self.element_class) and p.parent() == self or - isinstance(p, Integer) and p.is_prime()) + return isinstance(p, self.element_class) and p.parent() == self or isinstance(p, Integer) and p.is_prime() def _from_integer_(self, e): """ @@ -541,7 +543,7 @@ def _from_integer_(self, e): from sage.structure.element_wrapper import ElementWrapper - class Element (ElementWrapper, PrimeNumbers_Abstract.Element): + class Element(ElementWrapper, PrimeNumbers_Abstract.Element): def _integer_(self, IntRing): """ Convert to an integer. @@ -556,7 +558,7 @@ def _integer_(self, IntRing): return IntRing(self.value) -#*************************************************************************# +# *************************************************************************# class PrimeNumbers_Facade(PrimeNumbers_Abstract): r""" An example of parent in the category of sets: the set of prime numbers. diff --git a/src/sage/categories/examples/sets_with_grading.py b/src/sage/categories/examples/sets_with_grading.py index 9968d83942b..807bd5b318a 100644 --- a/src/sage/categories/examples/sets_with_grading.py +++ b/src/sage/categories/examples/sets_with_grading.py @@ -1,6 +1,7 @@ r""" Example of a set with grading """ + from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.categories.sets_with_grading import SetsWithGrading @@ -24,14 +25,14 @@ class NonNegativeIntegers(UniqueRepresentation, Parent): sage: E.graded_component(100) {100} """ + def __init__(self): r""" TESTS:: sage: TestSuite(SetsWithGrading().example()).run() """ - Parent.__init__(self, category=SetsWithGrading().Infinite(), - facade=IntegerRing()) + Parent.__init__(self, category=SetsWithGrading().Infinite(), facade=IntegerRing()) def an_element(self): r""" @@ -92,6 +93,7 @@ def generating_series(self, var='z'): """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.integer import Integer + R = PolynomialRing(IntegerRing(), var) z = R.gen() return Integer(1) / (Integer(1) - z) diff --git a/src/sage/categories/examples/with_realizations.py b/src/sage/categories/examples/with_realizations.py index b9095d48067..3ba54f1e2f6 100644 --- a/src/sage/categories/examples/with_realizations.py +++ b/src/sage/categories/examples/with_realizations.py @@ -2,12 +2,12 @@ r""" Examples of parents endowed with multiple realizations """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2008-2009 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.cachefunc import cached_method from sage.misc.bindable_class import BindableClass @@ -182,18 +182,12 @@ def __init__(self, R, S): category = self.Bases() key = self.indices_key - In_to_F = In.module_morphism(F.sum_of_monomials * Subsets, - codomain=F, category=category, - triangular='upper', unitriangular=True, - key=key) - In_to_F .register_as_coercion() + In_to_F = In.module_morphism(F.sum_of_monomials * Subsets, codomain=F, category=category, triangular='upper', unitriangular=True, key=key) + In_to_F.register_as_coercion() (~In_to_F).register_as_coercion() - F_to_Out = F.module_morphism(Out.sum_of_monomials * self.supsets, - codomain=Out, category=category, - triangular='lower', unitriangular=True, - key=key) - F_to_Out .register_as_coercion() + F_to_Out = F.module_morphism(Out.sum_of_monomials * self.supsets, codomain=Out, category=category, triangular='lower', unitriangular=True, key=key) + F_to_Out.register_as_coercion() (~F_to_Out).register_as_coercion() _shorthands = ("F", "In", "Out") @@ -301,8 +295,7 @@ def super_categories(self): """ A = self.base() category = Algebras(A.base_ring()).Commutative() - return [A.Realizations(), - category.Realizations().WithBasis()] + return [A.Realizations(), category.Realizations().WithBasis()] class ParentMethods: @@ -342,6 +335,7 @@ def __getitem__(self, s): F[{1, 3}] """ from sage.rings.integer import Integer + if isinstance(s, Integer): return self.from_set(*(s,)) return self.from_set(*s) @@ -404,9 +398,7 @@ def __init__(self, A): The subset algebra of {1, 2, 3} over Rational Field in the Fundamental basis sage: TestSuite(F).run() """ - CombinatorialFreeModule.__init__(self, - A.base_ring(), A.indices(), - category=A.Bases(), prefix='F', sorting_key=A.indices_key) + CombinatorialFreeModule.__init__(self, A.base_ring(), A.indices(), category=A.Bases(), prefix='F', sorting_key=A.indices_key) def product_on_basis(self, left, right): r""" @@ -492,9 +484,7 @@ def __init__(self, A): The subset algebra of {1, 2, 3} over Rational Field in the In basis sage: TestSuite(In).run() """ - CombinatorialFreeModule.__init__(self, - A.base_ring(), A.indices(), - category=A.Bases(), prefix='In', sorting_key=A.indices_key) + CombinatorialFreeModule.__init__(self, A.base_ring(), A.indices(), category=A.Bases(), prefix='In', sorting_key=A.indices_key) class Out(CombinatorialFreeModule, BindableClass): r""" @@ -535,6 +525,4 @@ def __init__(self, A): The subset algebra of {1, 2, 3} over Rational Field in the Out basis sage: TestSuite(Out).run() """ - CombinatorialFreeModule.__init__(self, - A.base_ring(), A.indices(), - category=A.Bases(), prefix='Out', sorting_key=A.indices_key) + CombinatorialFreeModule.__init__(self, A.base_ring(), A.indices(), category=A.Bases(), prefix='Out', sorting_key=A.indices_key) diff --git a/src/sage/categories/facade_sets.py b/src/sage/categories/facade_sets.py index f9a619782dc..9cb41f5ac34 100644 --- a/src/sage/categories/facade_sets.py +++ b/src/sage/categories/facade_sets.py @@ -3,12 +3,13 @@ For background, see :ref:`What is a facade set? `. """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2010-2011 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom @@ -34,6 +35,7 @@ def example(self, choice='subset'): An example of facade set: the monoid of positive integers """ import sage.categories.examples.facade_sets as examples + if choice == "union": return examples.IntegersCompletion() if choice == 'subset': @@ -176,6 +178,7 @@ def is_parent_of(self, element): if parents is True: return True from sage.structure.element import parent + return parent(element) in parents def __contains__(self, element) -> bool: diff --git a/src/sage/categories/fields.py b/src/sage/categories/fields.py index 7b3bc1c0547..cb64ab4ef8c 100644 --- a/src/sage/categories/fields.py +++ b/src/sage/categories/fields.py @@ -1,6 +1,7 @@ r""" Fields """ + # **************************************************************************** # Copyright (C) 2005 David Kohel # William Stein @@ -50,6 +51,7 @@ class Fields(CategoryWithAxiom): sage: TestSuite(Fields()).run() """ + _base_category_class_and_axiom = (DivisionRings, "Commutative") def extra_super_categories(self): @@ -126,6 +128,7 @@ def __contains__(self, x) -> bool: 0 """ from sage.rings.ring import _is_Field + try: return self._contains_helper(x) or _is_Field(x) except Exception: @@ -324,6 +327,7 @@ def an_embedding(self, K): except TypeError: pass from sage.categories.sets_cat import EmptySetError + try: return H.an_element() except EmptySetError: @@ -341,9 +345,11 @@ def prime_subfield(self): """ if self.characteristic() == 0: import sage.rings.rational_field + return sage.rings.rational_field.RationalField() from sage.rings.finite_rings.finite_field_constructor import GF + return GF(self.characteristic()) def divides(self, x, y, coerce=True): @@ -700,6 +706,7 @@ def _squarefree_decomposition_univariate_polynomial(self, f): here. """ from sage.structure.factorization import Factorization + if f.degree() == 0: return Factorization([], unit=f[0]) if self.characteristic() != 0: @@ -774,6 +781,7 @@ def euclidean_degree(self): if self.is_zero(): raise ValueError("euclidean degree not defined for the zero element") from sage.rings.integer_ring import ZZ + return ZZ.zero() def quo_rem(self, other): @@ -865,6 +873,7 @@ def gcd(self, other): has_zero_char = False if has_zero_char: from sage.rings.integer_ring import ZZ + try: return P(ZZ(self).gcd(ZZ(other))) except (TypeError, ValueError): @@ -919,6 +928,7 @@ def lcm(self, other): has_zero_char = False if has_zero_char: from sage.rings.integer_ring import ZZ + try: return P(ZZ(self).lcm(ZZ(other))) except TypeError: @@ -982,6 +992,7 @@ def xgcd(self, other): has_zero_char = False if has_zero_char: from sage.rings.integer_ring import ZZ + try: return tuple(P(x) for x in ZZ(self).xgcd(ZZ(other))) except TypeError: @@ -1013,6 +1024,7 @@ def factor(self): if not self: raise ArithmeticError("factorization of {!r} is not defined".format(self)) from sage.structure.factorization import Factorization + return Factorization([], self) # No factor; "self" as unit def inverse_of_unit(self): diff --git a/src/sage/categories/filtered_algebras.py b/src/sage/categories/filtered_algebras.py index 50a4bdb00c2..093b7293df7 100644 --- a/src/sage/categories/filtered_algebras.py +++ b/src/sage/categories/filtered_algebras.py @@ -1,12 +1,13 @@ r""" Filtered Algebras """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.abstract_method import abstract_method from sage.categories.filtered_modules import FilteredModulesCategory @@ -40,6 +41,7 @@ class FilteredAlgebras(FilteredModulesCategory): - :wikipedia:`Filtered_algebra` """ + class ParentMethods: @abstract_method(optional=True) def graded_algebra(self): diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py index cb24cb7411d..e10c1101e91 100644 --- a/src/sage/categories/filtered_algebras_with_basis.py +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -9,12 +9,13 @@ :class:`~sage.categories.filtered_modules_with_basis.FilteredModulesWithBasis` for these two notions. """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.filtered_modules import FilteredModulesCategory @@ -45,6 +46,7 @@ class FilteredAlgebrasWithBasis(FilteredModulesCategory): sage: TestSuite(C).run() """ + class ParentMethods: def graded_algebra(self): r""" @@ -111,6 +113,7 @@ def graded_algebra(self): Lie algebra of RR^3 with cross product over Integer Ring """ from sage.algebras.associated_graded import AssociatedGradedAlgebra + return AssociatedGradedAlgebra(self) # Maps @@ -140,8 +143,7 @@ def to_graded_conversion(self): True """ base_one = self.base_ring().one() - return self.module_morphism(diagonal=lambda x: base_one, - codomain=self.graded_algebra()) + return self.module_morphism(diagonal=lambda x: base_one, codomain=self.graded_algebra()) def from_graded_conversion(self): r""" @@ -169,8 +171,7 @@ def from_graded_conversion(self): True """ base_one = self.base_ring().one() - return self.graded_algebra().module_morphism(diagonal=lambda x: base_one, - codomain=self) + return self.graded_algebra().module_morphism(diagonal=lambda x: base_one, codomain=self) def projection(self, i): r""" @@ -203,8 +204,7 @@ def projection(self, i): base_zero = self.base_ring().zero() base_one = self.base_ring().one() grA = self.graded_algebra() - proj = lambda x: (base_one if self.degree_on_basis(x) == i - else base_zero) + proj = lambda x: (base_one if self.degree_on_basis(x) == i else base_zero) return self.module_morphism(diagonal=proj, codomain=grA) def induced_graded_map(self, other, f): @@ -519,6 +519,7 @@ def induced_graded_map(self, other, f): grA = self.graded_algebra() grB = other.graded_algebra() from sage.categories.graded_modules_with_basis import GradedModulesWithBasis + cat = GradedModulesWithBasis(self.base_ring()) from_gr = self.from_graded_conversion() @@ -526,8 +527,8 @@ def on_basis(m): i = grA.degree_on_basis(m) lifted_img_of_m = f(from_gr(grA.monomial(m))) return other.projection(i)(lifted_img_of_m) - return grA.module_morphism(on_basis=on_basis, - codomain=grB, category=cat) + + return grA.module_morphism(on_basis=on_basis, codomain=grB, category=cat) # If we could assume that the projection of the basis # element of ``self`` indexed by an index ``m`` is the # basis element of ``grA`` indexed by ``m``, then this diff --git a/src/sage/categories/filtered_hopf_algebras_with_basis.py b/src/sage/categories/filtered_hopf_algebras_with_basis.py index dadd10dd70e..1357588bb6f 100644 --- a/src/sage/categories/filtered_hopf_algebras_with_basis.py +++ b/src/sage/categories/filtered_hopf_algebras_with_basis.py @@ -1,12 +1,13 @@ r""" Filtered Hopf algebras with basis """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2017 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.tensor import tensor @@ -46,6 +47,7 @@ class FilteredHopfAlgebrasWithBasis(FilteredModulesCategory): sage: TestSuite(C).run() """ + class WithRealizations(WithRealizationsCategory): @cached_method def super_categories(self): @@ -62,6 +64,7 @@ def super_categories(self): sage: TestSuite(HopfAlgebrasWithBasis(QQ).Filtered().WithRealizations()).run() """ from sage.categories.hopf_algebras import HopfAlgebras + R = self.base_category().base_ring() return [HopfAlgebras(R).Filtered()] @@ -103,13 +106,9 @@ def antipode_on_basis(self, index): return self.one() S = self.antipode_on_basis - x__S_Id = tensor([self, self]).module_morphism( - lambda ab: S(ab[0]) * self.monomial(ab[1]), - codomain=self) + x__S_Id = tensor([self, self]).module_morphism(lambda ab: S(ab[0]) * self.monomial(ab[1]), codomain=self) smi = self.monomial(index) - return -x__S_Id(smi.coproduct() - - tensor([smi, self.one()]) - ) + smi.counit() + return -x__S_Id(smi.coproduct() - tensor([smi, self.one()])) + smi.counit() def antipode(self, elem): r""" @@ -128,10 +127,7 @@ def antipode(self, elem): sage: (2*H.monomial(1) + 3*H.monomial(4)).antipode() # needs sage.modules -2*P1 + 3*P4 """ - return self.linear_combination( - (self.antipode_on_basis(mon), coeff) - for mon, coeff in elem.monomial_coefficients(copy=False).items() - ) + return self.linear_combination((self.antipode_on_basis(mon), coeff) for mon, coeff in elem.monomial_coefficients(copy=False).items()) class ElementMethods: pass diff --git a/src/sage/categories/filtered_modules.py b/src/sage/categories/filtered_modules.py index 417dba3b754..7b5d296a3d3 100644 --- a/src/sage/categories/filtered_modules.py +++ b/src/sage/categories/filtered_modules.py @@ -21,6 +21,7 @@ Implement `\operatorname{gr}` as a functor. """ + # **************************************************************************** # Copyright (C) 2014 Travis Scrimshaw # @@ -141,6 +142,7 @@ class FilteredModules(FilteredModulesCategory): - :wikipedia:`Filtration_(mathematics)` """ + def extra_super_categories(self): r""" Add :class:`VectorSpaces` to the super categories of ``self`` if @@ -170,6 +172,7 @@ def extra_super_categories(self): from sage.categories.modules import Modules from sage.categories.fields import Fields from sage.categories.category import Category + base_ring = self.base_ring() if base_ring in Fields() or (isinstance(base_ring, Category) and base_ring.is_subcategory(Fields())): return [Modules(base_ring)] diff --git a/src/sage/categories/filtered_modules_with_basis.py b/src/sage/categories/filtered_modules_with_basis.py index 6b906f3ee01..c344acf8e17 100644 --- a/src/sage/categories/filtered_modules_with_basis.py +++ b/src/sage/categories/filtered_modules_with_basis.py @@ -21,12 +21,13 @@ :class:`~sage.categories.filtered_modules_with_basis.FilteredModulesWithBasis` for further details. """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.filtered_modules import FilteredModulesCategory from sage.misc.abstract_method import abstract_method @@ -108,6 +109,7 @@ class in order to fully utilize the methods of this category. sage: C = ModulesWithBasis(QQ).Filtered() sage: TestSuite(C).run() """ + class ParentMethods: # TODO: which syntax do we prefer? # A.basis(degree = 3) @@ -186,6 +188,7 @@ def basis(self, d=None): """ if d is None: from sage.sets.family import Family + return Family(self._indices, self.monomial) return self.homogeneous_component_basis(d) @@ -216,6 +219,7 @@ def homogeneous_component_basis(self, d): Finite family {'b': B['b']} """ from sage.sets.family import Family + try: S = self._indices.subset(size=d) except (AttributeError, ValueError, TypeError): @@ -235,15 +239,11 @@ def homogeneous_component(self, d): """ from sage.categories.modules_with_basis import ModulesWithBasis from sage.categories.filtered_algebras import FilteredAlgebras + if self.base_ring() in FilteredAlgebras: - raise NotImplementedError("this is only a natural module over" - " the degree 0 component of the filtered" - " algebra and coordinate rings are not" - " yet implemented for submodules") + raise NotImplementedError("this is only a natural module over" " the degree 0 component of the filtered" " algebra and coordinate rings are not" " yet implemented for submodules") category = ModulesWithBasis(self.category().base_ring()) - M = self.submodule(self.homogeneous_component_basis(d), - category=category, - already_echelonized=True) + M = self.submodule(self.homogeneous_component_basis(d), category=category, already_echelonized=True) M.rename("Degree {} homogeneous component of {}".format(d, self)) return M @@ -284,11 +284,14 @@ def hilbert_series(self, prec=None): 1 + t + 2*t^2 + 3*t^3 + 5*t^4 + 7*t^5 + 11*t^6 + 15*t^7 + 22*t^8 + 30*t^9 + O(t^10) """ from sage.rings.integer_ring import ZZ + if prec is None: from sage.rings.lazy_series_ring import LazyPowerSeriesRing + R = LazyPowerSeriesRing(ZZ, 't') return R(lambda n: self.homogeneous_component_basis(n).cardinality()) from sage.rings.power_series_ring import PowerSeriesRing + R = PowerSeriesRing(ZZ, 't') elt = R([self.homogeneous_component_basis(n).cardinality() for n in range(prec)]) return elt.O(prec) @@ -347,6 +350,7 @@ def graded_algebra(self): the free module on partitions over Integer Ring """ from sage.algebras.associated_graded import AssociatedGradedAlgebra + return AssociatedGradedAlgebra(self) # Maps @@ -376,8 +380,7 @@ def to_graded_conversion(self): True """ base_one = self.base_ring().one() - return self.module_morphism(diagonal=lambda x: base_one, - codomain=self.graded_algebra()) + return self.module_morphism(diagonal=lambda x: base_one, codomain=self.graded_algebra()) def from_graded_conversion(self): r""" @@ -407,8 +410,7 @@ def from_graded_conversion(self): True """ base_one = self.base_ring().one() - return self.graded_algebra().module_morphism(diagonal=lambda x: base_one, - codomain=self) + return self.graded_algebra().module_morphism(diagonal=lambda x: base_one, codomain=self) def projection(self, i): r""" @@ -442,8 +444,7 @@ def projection(self, i): base_zero = self.base_ring().zero() base_one = self.base_ring().one() grA = self.graded_algebra() - proj = lambda x: (base_one if self.degree_on_basis(x) == i - else base_zero) + proj = lambda x: (base_one if self.degree_on_basis(x) == i else base_zero) return self.module_morphism(diagonal=proj, codomain=grA) def induced_graded_map(self, other, f): @@ -683,6 +684,7 @@ def induced_graded_map(self, other, f): grA = self.graded_algebra() grB = other.graded_algebra() from sage.categories.graded_modules_with_basis import GradedModulesWithBasis + cat = GradedModulesWithBasis(self.base_ring()) from_gr = self.from_graded_conversion() @@ -690,8 +692,8 @@ def on_basis(m): i = grA.degree_on_basis(m) lifted_img_of_m = f(from_gr(grA.monomial(m))) return other.projection(i)(lifted_img_of_m) - return grA.module_morphism(on_basis=on_basis, - codomain=grB, category=cat) + + return grA.module_morphism(on_basis=on_basis, codomain=grB, category=cat) # If we could assume that the projection of the basis # element of ``self`` indexed by an index ``m`` is the # basis element of ``grA`` indexed by ``m``, then this @@ -998,9 +1000,7 @@ def homogeneous_component(self, n): True """ degree_on_basis = self.parent().degree_on_basis - return self.parent().sum_of_terms((i, c) - for (i, c) in self - if degree_on_basis(i) == n) + return self.parent().sum_of_terms((i, c) for (i, c) in self if degree_on_basis(i) == n) def truncate(self, n): """ @@ -1070,8 +1070,7 @@ def truncate(self, n): True """ degree_on_basis = self.parent().degree_on_basis - return self.parent().sum_of_terms((i, c) for (i, c) in self - if degree_on_basis(i) < n) + return self.parent().sum_of_terms((i, c) for (i, c) in self if degree_on_basis(i) < n) class Subobjects(SubobjectsCategory): class ParentMethods: @@ -1195,6 +1194,7 @@ def hilbert_series(self, prec=None): from collections import defaultdict from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + PR = PolynomialRing(ZZ, 't') dims = defaultdict(ZZ) for b in self.basis(): diff --git a/src/sage/categories/finite_complex_reflection_groups.py b/src/sage/categories/finite_complex_reflection_groups.py index 3398e55667d..83b2fe01565 100644 --- a/src/sage/categories/finite_complex_reflection_groups.py +++ b/src/sage/categories/finite_complex_reflection_groups.py @@ -1,6 +1,7 @@ r""" Finite Complex Reflection Groups """ + # **************************************************************************** # Copyright (C) 2011-2015 Christian Stump # @@ -68,6 +69,7 @@ class FiniteComplexReflectionGroups(CategoryWithAxiom): sage: W in ComplexReflectionGroups().Finite() # optional - gap3 True """ + def example(self): r""" Return an example of a complex reflection group. @@ -79,6 +81,7 @@ def example(self): Reducible real reflection group of rank 4 and type A2 x B2 """ from sage.combinat.root_system.reflection_group_real import ReflectionGroup + return ReflectionGroup((1, 1, 3), (2, 1, 2)) class SubcategoryMethods: @@ -229,16 +232,11 @@ def _test_degrees(self, **options): tester = self._tester(**options) degrees = self.degrees() - tester.assertIsInstance(degrees, tuple, - "the degrees method should return a tuple") - tester.assertTrue(all(parent(d) is ZZ for d in degrees), - "the degrees should be integers") - tester.assertTrue(all(d >= 2 for d in degrees), - "the degrees should be larger than 2") - tester.assertEqual(len(degrees), self.rank(), - "the number of degrees should coincide with the rank") - tester.assertEqual(sum(d - 1 for d in degrees), self.number_of_reflections(), - "the sum of the degrees should be consistent with the number of reflections") + tester.assertIsInstance(degrees, tuple, "the degrees method should return a tuple") + tester.assertTrue(all(parent(d) is ZZ for d in degrees), "the degrees should be integers") + tester.assertTrue(all(d >= 2 for d in degrees), "the degrees should be larger than 2") + tester.assertEqual(len(degrees), self.rank(), "the number of degrees should coincide with the rank") + tester.assertEqual(sum(d - 1 for d in degrees), self.number_of_reflections(), "the sum of the degrees should be consistent with the number of reflections") def _test_codegrees(self, **options): """ @@ -284,17 +282,11 @@ def _test_codegrees(self, **options): tester = self._tester(**options) codegrees = self.codegrees() - tester.assertIsInstance(codegrees, tuple, - "the codegrees method should return a tuple") - tester.assertTrue(all(parent(d) is ZZ for d in codegrees), - "the codegrees should be integers") - tester.assertTrue(all(d >= 0 for d in codegrees), - "the codegrees should be nonnegative") - tester.assertEqual(len(codegrees), self.rank(), - "the number of codegrees should coincide with the rank") - tester.assertEqual(sum(d + 1 for d in codegrees), - self.number_of_reflection_hyperplanes(), - "the sum of the codegrees should be consistent with the number of reflection hyperplanes") + tester.assertIsInstance(codegrees, tuple, "the codegrees method should return a tuple") + tester.assertTrue(all(parent(d) is ZZ for d in codegrees), "the codegrees should be integers") + tester.assertTrue(all(d >= 0 for d in codegrees), "the codegrees should be nonnegative") + tester.assertEqual(len(codegrees), self.rank(), "the number of codegrees should coincide with the rank") + tester.assertEqual(sum(d + 1 for d in codegrees), self.number_of_reflection_hyperplanes(), "the sum of the codegrees should be consistent with the number of reflection hyperplanes") @cached_method def number_of_reflection_hyperplanes(self): @@ -329,6 +321,7 @@ def number_of_reflection_hyperplanes(self): 15 """ from sage.rings.integer_ring import ZZ + return ZZ.sum(codeg + 1 for codeg in self.codegrees()) @cached_method @@ -365,6 +358,7 @@ def number_of_reflections(self): 15 """ from sage.rings.integer_ring import ZZ + return ZZ.sum(deg - 1 for deg in self.degrees()) @cached_method @@ -426,6 +420,7 @@ def cardinality(self): 192 """ from sage.rings.integer_ring import ZZ + return ZZ.prod(self.degrees()) def is_well_generated(self) -> bool: @@ -536,6 +531,7 @@ def base_change_matrix(self): [E(4) 1] """ from sage.matrix.constructor import Matrix + return Matrix(list(self.independent_roots())).inverse() def milnor_fiber_poset(self): @@ -636,8 +632,10 @@ def milnor_fiber_poset(self): data[Xp] = [Yp] if self.is_well_generated(): from sage.combinat.posets.lattices import MeetSemilattice + return MeetSemilattice(data) from sage.combinat.posets.posets import Poset + return Poset(data) class ElementMethods: @@ -756,6 +754,7 @@ def reflection_length(self, in_unitary_group=False): W = self.parent() if in_unitary_group or W.is_real(): from sage.matrix.special import identity_matrix + I = identity_matrix(self.parent().rank()) return W.rank() - (self.canonical_matrix() - I).right_nullity() return len(self.reduced_word_in_reflections()) @@ -774,6 +773,7 @@ def example(self): Irreducible complex reflection group of rank 3 and type G(4,2,3) """ from sage.combinat.root_system.reflection_group_real import ReflectionGroup + return ReflectionGroup((4, 2, 3)) class ParentMethods: @@ -793,12 +793,9 @@ def coxeter_number(self): sage: W.coxeter_number() # optional - gap3 30 """ - return (self.number_of_reflection_hyperplanes() - + self.number_of_reflections()) // self.rank() + return (self.number_of_reflection_hyperplanes() + self.number_of_reflections()) // self.rank() - def absolute_order_ideal(self, gens=None, - in_unitary_group=True, - return_lengths=False): + def absolute_order_ideal(self, gens=None, in_unitary_group=True, return_lengths=False): r""" Return all elements in ``self`` below given elements in the absolute order of ``self``. @@ -893,17 +890,15 @@ def succ(seed): if u.reflection_length(in_unitary_group=in_unitary_group) == w_len: resu.append((u, w_len)) return resu - step = RecursivelyEnumeratedSet(seeds, succ, - structure='graded', - enumeration='breadth') + + step = RecursivelyEnumeratedSet(seeds, succ, structure='graded', enumeration='breadth') if return_lengths: return step return (x[0] for x in step) # TODO: have a cached and an uncached version @cached_method - def noncrossing_partition_lattice(self, c=None, L=None, - in_unitary_group=True): + def noncrossing_partition_lattice(self, c=None, L=None, in_unitary_group=True): r""" Return the interval `[1,c]` in the absolute order of ``self`` as a finite lattice. @@ -959,9 +954,7 @@ def noncrossing_partition_lattice(self, c=None, L=None, R = self.reflections() if L is None: - L = list(self.absolute_order_ideal(gens=c, - in_unitary_group=in_unitary_group, - return_lengths=True)) + L = list(self.absolute_order_ideal(gens=c, in_unitary_group=in_unitary_group, return_lengths=True)) else: L = [(pi, pi.reflection_length()) for pi in L] rels = [] @@ -974,8 +967,7 @@ def noncrossing_partition_lattice(self, c=None, L=None, P = Poset(([], rels), cover_relations=True, facade=True) if P.is_lattice(): - P = LatticePoset(P, - category=FiniteLatticePosets().ChainGraded()) + P = LatticePoset(P, category=FiniteLatticePosets().ChainGraded()) return P def generalized_noncrossing_partitions(self, m, c=None, positive=False): @@ -1030,6 +1022,7 @@ def generalized_noncrossing_partitions(self, m, c=None, positive=False): [[2], [1, 2, 1], []]] """ from sage.combinat.combination import Combinations + NC = self.noncrossing_partition_lattice(c=c) one = self.one() if c is None: @@ -1042,7 +1035,7 @@ def generalized_noncrossing_partitions(self, m, c=None, positive=False): while len(chain) <= m: chain.append(c) for i in range(len(chain) - 1, 0, -1): - chain[i] = chain[i - 1]**-1 * chain[i] + chain[i] = chain[i - 1] ** -1 * chain[i] k = m + 1 - len(chain) for positions in Combinations(range(m + 1), k): ncm = [] @@ -1119,6 +1112,7 @@ def example(self): Reducible complex reflection group of rank 4 and type A2 x G(3,1,2) """ from sage.combinat.root_system.reflection_group_real import ReflectionGroup + return ReflectionGroup((1, 1, 3), (3, 1, 2)) class ParentMethods: @@ -1232,6 +1226,7 @@ def milnor_fiber_complex(self): verts[C, Ip] = len(verts) facets = [[verts[k] for k in verts if g in k[0]] for g in self] from sage.topology.simplicial_complex import SimplicialComplex + return SimplicialComplex(facets) class Irreducible(CategoryWithAxiom): @@ -1239,6 +1234,7 @@ class Irreducible(CategoryWithAxiom): The category of finite irreducible well-generated finite complex reflection groups. """ + def example(self): r""" Return an example of an irreducible well-generated @@ -1252,6 +1248,7 @@ def example(self): 4-colored permutations of size 3 """ from sage.combinat.colored_permutations import ColoredPermutations + return ColoredPermutations(4, 3) class ParentMethods: @@ -1367,13 +1364,11 @@ def rational_catalan_number(self, p, polynomial=False): def f(n): return n - num = prod(f(p + (p * (deg - 1)) % h) - for deg in self.degrees()) + num = prod(f(p + (p * (deg - 1)) % h) for deg in self.degrees()) den = prod(f(deg) for deg in self.degrees()) return num // den - def fuss_catalan_number(self, m, positive=False, - polynomial=False): + def fuss_catalan_number(self, m, positive=False, polynomial=False): r""" Return the ``m``-th Fuss-Catalan number associated to ``self``. @@ -1502,5 +1497,4 @@ def catalan_number(self, positive=False, polynomial=False): sage: W.catalan_number(polynomial=True) q^8 + q^6 + 2*q^4 + q^2 + 1 """ - return self.fuss_catalan_number(1, positive=positive, - polynomial=polynomial) + return self.fuss_catalan_number(1, positive=positive, polynomial=polynomial) diff --git a/src/sage/categories/finite_coxeter_groups.py b/src/sage/categories/finite_coxeter_groups.py index 1a193d2fced..62c75a9cd56 100644 --- a/src/sage/categories/finite_coxeter_groups.py +++ b/src/sage/categories/finite_coxeter_groups.py @@ -50,6 +50,7 @@ class FiniteCoxeterGroups(CategoryWithAxiom): sage: DihedralGroup(5) Dihedral group of order 10 as a permutation group """ + def extra_super_categories(self): r""" EXAMPLES:: @@ -59,6 +60,7 @@ def extra_super_categories(self): Category of Coxeter groups] """ from sage.categories.complex_reflection_groups import ComplexReflectionGroups + return [ComplexReflectionGroups().Finite().WellGenerated()] class ParentMethods: @@ -83,6 +85,7 @@ class ParentMethods: sage: list(W) [(), (1,), (2,), (1, 2), (2, 1), (1, 2, 1)] """ + __iter__ = CoxeterGroups.ParentMethods.__dict__["__iter__"] @lazy_attribute @@ -213,6 +216,7 @@ def bruhat_poset(self, facade=False): handle large / infinite Coxeter groups. """ from sage.combinat.posets.posets import Poset + covers = tuple([u, v] for v in self for u in v.bruhat_lower_covers()) return Poset((self, covers), cover_relations=True, facade=facade) @@ -249,10 +253,8 @@ def shard_poset(self, side='right'): 34*q^3 + 22*q^2 + q """ from sage.combinat.posets.lattices import LatticePoset - data = {w: (frozenset(u.lift() - for u in w.covered_reflections_subgroup()), - frozenset((~w).inversions_as_reflections())) - for w in self} + + data = {w: (frozenset(u.lift() for u in w.covered_reflections_subgroup()), frozenset((~w).inversions_as_reflections())) for w in self} def shard_comparison(u, v): Gu, Nu = data[u] @@ -308,9 +310,7 @@ def covered_by(ux, vy): return False return all((v * iu).has_descent(x, positive=True) for x in Su) - vertices = [(u, u.inverse(), - tuple(set(u.reduced_word_reverse_iterator()))) - for u in self] + vertices = [(u, u.inverse(), tuple(set(u.reduced_word_reverse_iterator()))) for u in self] dg = DiGraph([vertices, covered_by]) dg.relabel(lambda x: x[0]) return Poset(dg, cover_relations=True) @@ -358,12 +358,9 @@ def degrees_of_irreducible_component(I): args = ((z.rational_argument(), m) for z, m in roots) args = [(z if z >= 0 else 1 + z, m) for z, m in args] h = max(z.denominator() for z, m in args) - return tuple(sorted(ZZ(z * h + 1) - for z, m in args if z - for i in range(m))) + return tuple(sorted(ZZ(z * h + 1) for z, m in args if z for i in range(m))) - return sum((degrees_of_irreducible_component(I) - for I in self.irreducible_component_index_sets()), ()) + return sum((degrees_of_irreducible_component(I) for I in self.irreducible_component_index_sets()), ()) def codegrees(self): """ @@ -476,14 +473,13 @@ def weak_poset(self, side='right', facade=False): """ from sage.combinat.posets.posets import Poset from sage.combinat.posets.lattices import LatticePoset + if side == "twosided": covers = tuple([u, v] for u in self for v in u.upper_covers(side='left') + u.upper_covers(side='right')) - return Poset((self, covers), cover_relations=True, - facade=facade) + return Poset((self, covers), cover_relations=True, facade=facade) covers = tuple([u, v] for u in self for v in u.upper_covers(side=side)) cat = FiniteLatticePosets().ChainGraded() - return LatticePoset((self, covers), cover_relations=True, - facade=facade, category=cat) + return LatticePoset((self, covers), cover_relations=True, facade=facade, category=cat) weak_lattice = weak_poset @@ -511,8 +507,7 @@ def inversion_sequence(self, word): sage: [t.reduced_word() for t in CoxeterGroup(["A",3]).inversion_sequence([2,1,3,2,1,3])] [[2], [1, 2, 1], [2, 3, 2], [1, 2, 3, 2, 1], [3], [1]] """ - return [self.from_reduced_word(word[:i+1]+list(reversed(word[:i]))) - for i in range(len(word))] + return [self.from_reduced_word(word[: i + 1] + list(reversed(word[:i]))) for i in range(len(word))] def reflections_from_w0(self): """ @@ -571,6 +566,7 @@ def m_cambrian_lattice(self, c, m=1, on_roots=False): """ from sage.categories.finite_lattice_posets import FiniteLatticePosets from sage.combinat.posets.lattices import LatticePoset + if hasattr(c, "reduced_word"): c = c.reduced_word() c = list(c) @@ -579,11 +575,9 @@ def m_cambrian_lattice(self, c, m=1, on_roots=False): if on_roots: if not hasattr(self.long_element(), "reflection_to_root"): - raise ValueError("The parameter 'on_root=True' needs " - "the ElementMethod 'reflection_to_root'") + raise ValueError("The parameter 'on_root=True' needs " "the ElementMethod 'reflection_to_root'") - inv_woc = [t.reflection_to_root() - for t in self.inversion_sequence(sorting_word)] + inv_woc = [t.reflection_to_root() for t in self.inversion_sequence(sorting_word)] S = [s.reflection_to_root() for s in self.simple_reflections()] PhiP = [t.reflection_to_root() for t in self.reflections()] else: @@ -616,7 +610,7 @@ def m_cambrian_lattice(self, c, m=1, on_roots=False): cov_element.append((-tmp, t_conj[1] - 1)) else: tmp = t[0] * t_conj[0] * t[0] - invs = self.inversion_sequence(Twords[t[0]]+Twords[t_conj[0]]) + invs = self.inversion_sequence(Twords[t[0]] + Twords[t_conj[0]]) plus_or_minus = invs.count(tmp) if plus_or_minus % 2: cov_element.append((tmp, t_conj[1])) @@ -630,8 +624,7 @@ def m_cambrian_lattice(self, c, m=1, on_roots=False): cat = FiniteLatticePosets() if m == 1: cat = cat.CongruenceUniform().Trim() - return LatticePoset([elements, covers], cover_relations=True, - category=cat) + return LatticePoset([elements, covers], cover_relations=True, category=cat) def cambrian_lattice(self, c, on_roots=False): """ @@ -749,16 +742,18 @@ def permutahedron(self, point=None, base_ring=None): weights = self.fundamental_weights() if point is None: from sage.rings.integer_ring import ZZ + point = [ZZ.one()] * n - v = sum(point[i-1] * weights[i] for i in weights.keys()) - vertices = [v*w for w in self] + v = sum(point[i - 1] * weights[i] for i in weights.keys()) + vertices = [v * w for w in self] if base_ring is None: - if isinstance(v.base_ring(), (sage.rings.abc.UniversalCyclotomicField, - sage.rings.abc.AlgebraicField_common)): + if isinstance(v.base_ring(), (sage.rings.abc.UniversalCyclotomicField, sage.rings.abc.AlgebraicField_common)): from sage.rings.qqbar import AA + vertices = [v.change_ring(AA) for v in vertices] base_ring = AA from sage.geometry.polyhedron.constructor import Polyhedron + return Polyhedron(vertices=vertices, base_ring=base_ring) def coxeter_poset(self): @@ -830,6 +825,7 @@ def coxeter_poset(self): data[X] = [Y] next_level.add(X) from sage.combinat.posets.lattices import MeetSemilattice + return MeetSemilattice(data) def coxeter_complex(self): @@ -906,6 +902,7 @@ def coxeter_complex(self): labels = {x: i for i, x in enumerate(verts)} result = [[labels[v] for v in F] for F in facets.values()] from sage.topology.simplicial_complex import SimplicialComplex + return SimplicialComplex(result) class ElementMethods: @@ -978,9 +975,7 @@ def bruhat_upper_covers(self): i = self.first_descent(positive=True, side='right') if i is not None: wsi = self.apply_simple_reflection(i, side='right') - return [u.apply_simple_reflection(i, side='right') - for u in wsi.bruhat_upper_covers() - if u.has_descent(i, side='right')] + [wsi] + return [u.apply_simple_reflection(i, side='right') for u in wsi.bruhat_upper_covers() if u.has_descent(i, side='right')] + [wsi] return [] def coxeter_knuth_neighbor(self, w): @@ -1024,19 +1019,19 @@ def coxeter_knuth_neighbor(self, w): d = [] for i in range(2, len(w)): v = list(w) - if w[i-2] == w[i]: - if w[i] == w[i-1] - 1: - v[i-2] = w[i-1] - v[i] = w[i-1] - v[i-1] = w[i] + if w[i - 2] == w[i]: + if w[i] == w[i - 1] - 1: + v[i - 2] = w[i - 1] + v[i] = w[i - 1] + v[i - 1] = w[i] d += [tuple(v)] - elif w[i-1] < w[i-2] and w[i-2] < w[i]: - v[i] = w[i-1] - v[i-1] = w[i] + elif w[i - 1] < w[i - 2] and w[i - 2] < w[i]: + v[i] = w[i - 1] + v[i - 1] = w[i] d += [tuple(v)] - elif w[i-2] < w[i] and w[i] < w[i-1]: - v[i-2] = w[i-1] - v[i-1] = w[i-2] + elif w[i - 2] < w[i] and w[i] < w[i - 1]: + v[i - 2] = w[i - 1] + v[i - 1] = w[i - 2] d += [tuple(v)] return set(d) @@ -1081,6 +1076,7 @@ def coxeter_knuth_graph(self): NotImplementedError: this has only been implemented in finite type A so far """ from sage.graphs.graph import Graph + R = [tuple(v) for v in self.reduced_words()] G = Graph() G.add_vertices(R) @@ -1137,6 +1133,5 @@ def covered_reflections_subgroup(self): """ W = self.parent() winv = ~self - cov_down = [self * W.simple_reflection(i) * winv - for i in self.descents(side='right')] + cov_down = [self * W.simple_reflection(i) * winv for i in self.descents(side='right')] return W.submonoid(cov_down) diff --git a/src/sage/categories/finite_crystals.py b/src/sage/categories/finite_crystals.py index 4f9d2e4dcb0..f21a0ab58cc 100644 --- a/src/sage/categories/finite_crystals.py +++ b/src/sage/categories/finite_crystals.py @@ -2,12 +2,12 @@ r""" Finite Crystals """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2010 Anne Schilling # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.cachefunc import cached_method from sage.categories.category_with_axiom import CategoryWithAxiom @@ -86,6 +86,7 @@ def example(self, n=3): Highest weight crystal of type A_3 of highest weight omega_1 """ from sage.categories.crystals import Crystals + return Crystals().example(n) class TensorProducts(TensorProductsCategory): @@ -93,6 +94,7 @@ class TensorProducts(TensorProductsCategory): The category of finite crystals constructed by tensor product of finite crystals. """ + @cached_method def extra_super_categories(self): """ diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 952b5940672..76be4fcff60 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -13,7 +13,8 @@ - [CR1962]_ """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2011-2015 Nicolas M. Thiéry # 2011-2015 Franco Saliola @@ -21,7 +22,7 @@ # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** import operator from sage.misc.cachefunc import cached_method @@ -179,17 +180,14 @@ def radical_basis(self): B = self.basis() product_on_basis = self.product_on_basis if product_on_basis is NotImplemented: + def product_on_basis(i, j): return B[i] * B[j] zero = F.zero() keys = B.keys() - cache = [{(i, j): c for i in keys - for j, c in product_on_basis(y, i).monomial_coefficients().items()} - for y in keys] - mat = [[F.sum(x.get((j, i), zero) * c for (i,j), c in y.items()) - for x in cache] - for y in cache] + cache = [{(i, j): c for i in keys for j, c in product_on_basis(y, i).monomial_coefficients().items()} for y in keys] + mat = [[F.sum(x.get((j, i), zero) * c for (i, j), c in y.items()) for x in cache] for y in cache] mat = matrix(F, mat) rad_basis = mat.kernel().basis() @@ -201,9 +199,12 @@ def product_on_basis(i, j): # I imagine that ``pth_root`` would be fastest, but it is not # always available.... if hasattr(F.one(), 'nth_root'): + def root_fcn(s, x): return x.nth_root(s) + else: + def root_fcn(s, x): return x ** (1 / s) @@ -212,12 +213,12 @@ def root_fcn(s, x): B = [b.on_left_matrix() for b in self.basis()] while s <= n: # we use that p_{AB}(x) = p_{BA}(x) here - data = [[None]*(len(B)+1) for _ in B] + data = [[None] * (len(B) + 1) for _ in B] for i, b in enumerate(B): for j, bb in enumerate(B[i:], start=i): - val = (-1)**s * (b*bb).charpoly()[n-s] + val = (-1) ** s * (b * bb).charpoly()[n - s] data[i][j] = data[j][i] = val - data[i][-1] = (-1)**s * b.charpoly()[n-s] + data[i][-1] = (-1) ** s * b.charpoly()[n - s] C = matrix(data).left_kernel().basis() if 1 < s < F.order(): C = [vector(F, [root_fcn(s, ci) for ci in c]) for c in C] @@ -284,9 +285,7 @@ def radical(self): sage: TestSuite(radical).run() """ category = AssociativeAlgebras(self.category().base_ring()).WithBasis().FiniteDimensional().Subobjects() - radical = self.submodule(self.radical_basis(), - category=category, - already_echelonized=True) + radical = self.submodule(self.radical_basis(), category=category, already_echelonized=True) radical.rename("Radical of {}".format(self)) return radical @@ -412,9 +411,7 @@ def center(self): category = Algebras(self.base_ring()).FiniteDimensional().Subobjects().Commutative().WithBasis() if self in Algebras.Semisimple: category = category.Semisimple() - center = self.submodule(self.center_basis(), - category=category, - already_echelonized=True) + center = self.submodule(self.center_basis(), category=category, already_echelonized=True) center.rename("Center of {}".format(self)) return center @@ -465,8 +462,7 @@ def _build_basis_by_generators(self, S, gens, order=None, side=2): def reduce_pivots(elt, trailsupp, sortsupp): if not elt: return elt - return elt - self.linear_combination((trailsupp[s], c // trailsupp[s][s]) - for s in sortsupp if (c := elt[s])) + return elt - self.linear_combination((trailsupp[s], c // trailsupp[s][s]) for s in sortsupp if (c := elt[s])) dim = self.dimension() basis = [] @@ -549,8 +545,7 @@ def subalgebra(self, gens, category=None, order=None, *args, **opts): C = FiniteDimensionalAlgebrasWithBasis(self.category().base_ring()) category = C.Subobjects().or_subcategory(category) - return self.submodule(basis, check=False, already_echelonized=True, - category=category, support_order=order, *args, **opts) + return self.submodule(basis, check=False, already_echelonized=True, category=category, support_order=order, *args, **opts) def ideal_submodule(self, gens, side='left', category=None, algorithm=None, *args, **opts): r""" @@ -652,17 +647,13 @@ def ideal_submodule(self, gens, side='left', category=None, algorithm=None, *arg if algorithm == "basis": if side == 'left': - return self.submodule([b * g for b in self.basis() for g in gens], - category=category, *args, **opts) + return self.submodule([b * g for b in self.basis() for g in gens], category=category, *args, **opts) if side == 'right': - return self.submodule([g * b for b in self.basis() for g in gens], - category=category, *args, **opts) + return self.submodule([g * b for b in self.basis() for g in gens], category=category, *args, **opts) if side == 'twosided': spanset = [b * g for b in self.basis() for g in gens] spanset.extend(g * b for b in self.basis() for g in gens) - return self.submodule([b * g * bp for b in self.basis() - for bp in self.basis() for g in gens], - category=category, *args, **opts) + return self.submodule([b * g * bp for b in self.basis() for bp in self.basis() for g in gens], category=category, *args, **opts) raise ValueError("side must be either 'left', 'right', or 'twosided'") if algorithm == "generators": @@ -682,8 +673,7 @@ def ideal_submodule(self, gens, side='left', category=None, algorithm=None, *arg C = AssociativeAlgebras(self.category().base_ring()).WithBasis().FiniteDimensional() category = C.Subobjects().or_subcategory(category) - return self.submodule(basis, category=category, already_echelonized=True, - support_order=order, *args, **opts) + return self.submodule(basis, category=category, already_echelonized=True, support_order=order, *args, **opts) raise ValueError("invalid algorithm") @@ -768,14 +758,11 @@ def principal_ideal(self, a, side='left', *args, **opts): """ opts.pop("coerce", None) if side == 'right': - return self.submodule([a * b - for b in self.basis()], *args, **opts) + return self.submodule([a * b for b in self.basis()], *args, **opts) if side == 'left': - return self.submodule([b * a - for b in self.basis()], *args, **opts) + return self.submodule([b * a for b in self.basis()], *args, **opts) if side == 'twosided': - return self.submodule([b1 * a * b2 for b1 in self.basis() - for b2 in self.basis()], *args, **opts) + return self.submodule([b1 * a * b2 for b1 in self.basis() for b2 in self.basis()], *args, **opts) raise ValueError("side must be either 'left', 'right', or 'twosided'") @cached_method @@ -933,8 +920,8 @@ def idempotent_lift(self, x): x_prev = None while x != x_prev: tmp = x - y = x ** 2 - x = 2*y - y**2 # == one - (one - x**2)**2 + y = x**2 + x = 2 * y - y**2 # == one - (one - x**2)**2 x_prev = tmp return x @@ -1059,17 +1046,18 @@ def cartan_invariants_matrix(self): """ from sage.matrix.constructor import Matrix from sage.rings.integer_ring import ZZ + A_quo = self.semisimple_quotient() idempotents_quo = A_quo.central_orthogonal_idempotents() # Dimension of simple modules - dim_simples = [A_quo.principal_ideal(e).dimension().sqrt() - for e in idempotents_quo] + dim_simples = [A_quo.principal_ideal(e).dimension().sqrt() for e in idempotents_quo] # Orthogonal idempotents idempotents = self.orthogonal_idempotents_central_mod_radical() def C(i, j): summand = self.peirce_summand(idempotents[i], idempotents[j]) return summand.dimension() / (dim_simples[i] * dim_simples[j]) + m = Matrix(ZZ, len(idempotents), C) m.set_immutable() return m @@ -1132,8 +1120,7 @@ def isotypic_projective_modules(self, side='left'): - :meth:`orthogonal_idempotents_central_mod_radical` - :meth:`peirce_decomposition` """ - return [self.principal_ideal(e, side) for e in - self.orthogonal_idempotents_central_mod_radical()] + return [self.principal_ideal(e, side) for e in self.orthogonal_idempotents_central_mod_radical()] @cached_method def peirce_summand(self, ei, ej): @@ -1187,12 +1174,10 @@ def peirce_summand(self, ei, ej): True """ B = self.basis() - phi = self.module_morphism(on_basis=lambda k: ei * B[k] * ej, - codomain=self, triangular='lower') + phi = self.module_morphism(on_basis=lambda k: ei * B[k] * ej, codomain=self, triangular='lower') ideal = phi.matrix(side='right').image() - return self.submodule([self.from_vector(v) for v in ideal.basis()], - already_echelonized=True) + return self.submodule([self.from_vector(v) for v in ideal.basis()], already_echelonized=True) def peirce_decomposition(self, idempotents=None, check=True): r""" @@ -1280,8 +1265,7 @@ def peirce_decomposition(self, idempotents=None, check=True): if check: if not self.is_identity_decomposition_into_orthogonal_idempotents(idempotents): raise ValueError("Not a decomposition of the identity into orthogonal idempotents") - return [[self.peirce_summand(ei, ej) for ej in idempotents] - for ei in idempotents] + return [[self.peirce_summand(ei, ej) for ej in idempotents] for ei in idempotents] def is_identity_decomposition_into_orthogonal_idempotents(self, l): r""" @@ -1389,10 +1373,7 @@ def is_identity_decomposition_into_orthogonal_idempotents(self, l): sage: A.is_identity_decomposition_into_orthogonal_idempotents(()) False """ - return (self.sum(l) == self.one() - and all(e*e == e for e in l) - and all(e*f == 0 and f*e == 0 for i, e in enumerate(l) - for f in l[:i])) + return self.sum(l) == self.one() and all(e * e == e for e in l) and all(e * f == 0 and f * e == 0 for i, e in enumerate(l) for f in l[:i]) @cached_method def is_commutative(self) -> bool: @@ -1414,7 +1395,7 @@ def is_commutative(self) -> bool: B.remove(self.one()) except ValueError: pass - return all(b*bp == bp*b for i,b in enumerate(B) for bp in B[i+1:]) + return all(b * bp == bp * b for i, b in enumerate(B) for bp in B[i + 1 :]) class ElementMethods: @@ -1621,6 +1602,7 @@ class Cellular(CategoryWithAxiom_over_base_ring): - :wikipedia:`Cellular_algebra` - http://webusers.imj-prg.fr/~bernhard.keller/ictp2006/lecturenotes/xi.pdf """ + class ParentMethods: def _test_cellular(self, **options): """ @@ -1644,17 +1626,14 @@ def _test_cellular(self, **options): basis_elt = B[(mu, s, t)] for a in B: elt = a * basis_elt - tester.assertTrue( all(P.lt(i[0], mu) or i[2] == t - for i in elt.support()) ) + tester.assertTrue(all(P.lt(i[0], mu) or i[2] == t for i in elt.support())) vals.append([elt[(mu, u, t)] for u in C]) for t in C[1:]: basis_elt = B[(mu, s, t)] - for i,a in enumerate(B): + for i, a in enumerate(B): elt = a * basis_elt - tester.assertTrue( all(P.lt(i[0], mu) or i[2] == t - for i in elt.support()) ) - tester.assertEqual(vals[i], [elt[(mu, u, t)] - for u in C]) + tester.assertTrue(all(P.lt(i[0], mu) or i[2] == t for i in elt.support())) + tester.assertEqual(vals[i], [elt[(mu, u, t)] for u in C]) @abstract_method def cell_poset(self): @@ -1735,8 +1714,7 @@ def cellular_involution(self, x): C = self.cellular_basis() if C is self: M = x.monomial_coefficients(copy=False) - return self._from_dict({(i[0], i[2], i[1]): M[i] for i in M}, - remove_zeros=False) + return self._from_dict({(i[0], i[2], i[1]): M[i] for i in M}, remove_zeros=False) return self(C(x).cellular_involution()) @cached_method @@ -1753,6 +1731,7 @@ def cells(self): [3]: Standard tableaux of shape [3]} """ from sage.sets.family import Family + return Family(self.cell_poset(), self.cell_module_indices) def cellular_basis(self): @@ -1767,6 +1746,7 @@ def cellular_basis(self): over Rational Field """ from sage.algebras.cellular_basis import CellularBasis + return CellularBasis(self) def cell_module(self, mu, **kwds): @@ -1781,6 +1761,7 @@ def cell_module(self, mu, **kwds): Symmetric group algebra of order 3 over Rational Field """ from sage.modules.with_basis.cell_module import CellModule + return CellModule(self.cellular_basis(), mu, **kwds) @cached_method @@ -1822,8 +1803,7 @@ def simple_module_parameterization(self): sage: TL.simple_module_parameterization() (2, 4, 6) """ - return tuple([mu for mu in self.cell_poset() - if self.cell_module(mu).nonzero_bilinear_form()]) + return tuple([mu for mu in self.cell_poset() if self.cell_module(mu).nonzero_bilinear_form()]) class ElementMethods: def cellular_involution(self): @@ -1848,6 +1828,7 @@ class TensorProducts(TensorProductsCategory): The category of cellular algebras constructed by tensor product of cellular algebras. """ + @cached_method def extra_super_categories(self): """ @@ -1900,8 +1881,8 @@ def cell_module_indices(self, mu): Standard tableaux of shape [2, 1]) """ from sage.categories.cartesian_product import cartesian_product - return cartesian_product([self._sets[i].cell_module_indices(x) - for i,x in enumerate(mu)]) + + return cartesian_product([self._sets[i].cell_module_indices(x) for i, x in enumerate(mu)]) @lazy_attribute def cellular_involution(self): @@ -1946,15 +1927,16 @@ def cellular_involution(self): + 7/48*[2, 1] # [3, 1, 2] + 49/48*[2, 1] # [3, 2, 1]) """ if self.cellular_basis() is self: + def func(x): M = x.monomial_coefficients(copy=False) - return self._from_dict({(i[0], i[2], i[1]): M[i] for i in M}, - remove_zeros=False) + return self._from_dict({(i[0], i[2], i[1]): M[i] for i in M}, remove_zeros=False) + return self.module_morphism(function=func, codomain=self) def on_basis(i): - return self._tensor_of_elements([A.basis()[i[j]].cellular_involution() - for j, A in enumerate(self._sets)]) + return self._tensor_of_elements([A.basis()[i[j]].cellular_involution() for j, A in enumerate(self._sets)]) + return self.module_morphism(on_basis, codomain=self) @cached_method @@ -1976,6 +1958,7 @@ def _to_cellular_element(self, i): C = [A.cellular_basis() for A in self._sets] elts = [C[j](self._sets[j].basis()[ij]) for j, ij in enumerate(i)] from sage.categories.tensor import tensor + T = tensor(C) temp = T._tensor_of_elements(elts) B = self.cellular_basis() @@ -1991,8 +1974,8 @@ def convert_index(i): t.append(c) C = self.cell_module_indices(mu) return (tuple(mu), C(s), C(t)) - return B._from_dict({convert_index(i): M[i] for i in M}, - remove_zeros=False) + + return B._from_dict({convert_index(i): M[i] for i in M}, remove_zeros=False) @cached_method def _from_cellular_index(self, x): @@ -2011,8 +1994,7 @@ def _from_cellular_index(self, x): ....: for k in C.basis().keys()) True """ - elts = [A(A.cellular_basis().basis()[ (x[0][i], x[1][i], x[2][i]) ]) - for i,A in enumerate(self._sets)] + elts = [A(A.cellular_basis().basis()[(x[0][i], x[1][i], x[2][i])]) for i, A in enumerate(self._sets)] return self._tensor_of_elements(elts) class SubcategoryMethods: diff --git a/src/sage/categories/finite_dimensional_bialgebras_with_basis.py b/src/sage/categories/finite_dimensional_bialgebras_with_basis.py index 2869add106a..b142c768ae9 100644 --- a/src/sage/categories/finite_dimensional_bialgebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_bialgebras_with_basis.py @@ -1,13 +1,14 @@ r""" Finite dimensional bialgebras with basis """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2011 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** def FiniteDimensionalBialgebrasWithBasis(base_ring): @@ -29,4 +30,5 @@ def FiniteDimensionalBialgebrasWithBasis(base_ring): sage: TestSuite(C).run() """ from sage.categories.bialgebras_with_basis import BialgebrasWithBasis + return BialgebrasWithBasis(base_ring).FiniteDimensional() diff --git a/src/sage/categories/finite_dimensional_coalgebras_with_basis.py b/src/sage/categories/finite_dimensional_coalgebras_with_basis.py index 60ce4af4a62..d995c62ebe6 100644 --- a/src/sage/categories/finite_dimensional_coalgebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_coalgebras_with_basis.py @@ -1,13 +1,14 @@ r""" Finite dimensional coalgebras with basis """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2011 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** def FiniteDimensionalCoalgebrasWithBasis(base_ring): @@ -29,4 +30,5 @@ def FiniteDimensionalCoalgebrasWithBasis(base_ring): sage: TestSuite(C).run() """ from sage.categories.coalgebras_with_basis import CoalgebrasWithBasis + return CoalgebrasWithBasis(base_ring).FiniteDimensional() diff --git a/src/sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py b/src/sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py index 7e1352de959..4aae1508e18 100644 --- a/src/sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py @@ -44,6 +44,7 @@ class FiniteDimensionalGradedLieAlgebrasWithBasis(CategoryWithAxiom_over_base_ri sage: C = LieAlgebras(QQ).FiniteDimensional().WithBasis().Graded() sage: TestSuite(C).run() """ + class ParentMethods: def _test_grading(self, **options): r""" @@ -73,6 +74,7 @@ def _test_grading(self, **options): tester = self._tester(**options) from sage.misc.misc import some_tuples + for X, Y in some_tuples(self.basis(), 2, tester._max_runs): i = X.degree() j = Y.degree() @@ -80,14 +82,8 @@ def _test_grading(self, **options): if Z == 0: continue Zdeg = Z.degree() - tester.assertEqual(Zdeg, i + j, - msg="Lie bracket [%s, %s] has degree %s, not degree %s " % - (X, Y, Zdeg, i + j)) - tester.assertIn( - Z.to_vector(), - self.homogeneous_component_as_submodule(i + j), - msg="Lie bracket [%s, %s] is not in the " - "homogeneous component of degree %s" % (X, Y, i + j)) + tester.assertEqual(Zdeg, i + j, msg="Lie bracket [%s, %s] has degree %s, not degree %s " % (X, Y, Zdeg, i + j)) + tester.assertIn(Z.to_vector(), self.homogeneous_component_as_submodule(i + j), msg="Lie bracket [%s, %s] is not in the " "homogeneous component of degree %s" % (X, Y, i + j)) @cached_method def homogeneous_component_as_submodule(self, d): @@ -134,6 +130,7 @@ class Stratified(CategoryWithAxiom_over_base_ring): sage: C = LieAlgebras(QQ).WithBasis().Graded().FiniteDimensional().Stratified() sage: TestSuite(C).run() """ + class ParentMethods: def _test_generated_by_degree_one(self, **options): r""" @@ -177,11 +174,9 @@ def _test_generated_by_degree_one(self, **options): return B = V.basis() d = V.dimension() - V = m.submodule(B + [self.bracket(X, Y).to_vector() - for X in B1 for Y in B]) + V = m.submodule(B + [self.bracket(X, Y).to_vector() for X in B1 for Y in B]) - tester.assertEqual(V, m, - msg="%s does not generate %s" % ([self(X) for X in B1], self)) + tester.assertEqual(V, m, msg="%s does not generate %s" % ([self(X) for X in B1], self)) def degree_on_basis(self, m): r""" diff --git a/src/sage/categories/finite_dimensional_hopf_algebras_with_basis.py b/src/sage/categories/finite_dimensional_hopf_algebras_with_basis.py index da3f1365584..cab10ecfd68 100644 --- a/src/sage/categories/finite_dimensional_hopf_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_hopf_algebras_with_basis.py @@ -1,6 +1,7 @@ r""" Finite dimensional Hopf algebras with basis """ + # **************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2011 Nicolas M. Thiery diff --git a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py index 22db61d54b3..3a209589711 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -61,6 +61,7 @@ class FiniteDimensionalLieAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): Many of these tests should use non-abelian Lie algebras and need to be added after :issue:`16820`. """ + _base_category_class_and_axiom = (LieAlgebras.FiniteDimensional, "WithBasis") def example(self, n=3): @@ -82,10 +83,10 @@ def example(self, n=3): the 5-dimensional abelian Lie algebra over Rational Field """ from sage.categories.examples.finite_dimensional_lie_algebras_with_basis import Example + return Example(self.base_ring(), n) - Nilpotent = LazyImport('sage.categories.finite_dimensional_nilpotent_lie_algebras_with_basis', - 'FiniteDimensionalNilpotentLieAlgebrasWithBasis') + Nilpotent = LazyImport('sage.categories.finite_dimensional_nilpotent_lie_algebras_with_basis', 'FiniteDimensionalNilpotentLieAlgebrasWithBasis') class ParentMethods: @cached_method @@ -143,6 +144,7 @@ def _construct_UEA(self): def names_map(x): return x + F = FreeAlgebra(self.base_ring(), names) except ValueError: names = ['b{}'.format(i) for i in range(self.dimension())] @@ -159,15 +161,16 @@ def names_map(x): def get_var(g): return d[names_map(g)] + # The function ``get_var`` sends an element of the basis of # ``self`` to the corresponding element of ``F``. for k in S.keys(): g0 = get_var(k[0]) g1 = get_var(k[1]) if g0 < g1: - rels[g1*g0] = g0*g1 - F.sum(val*get_var(g) for g, val in S[k]) + rels[g1 * g0] = g0 * g1 - F.sum(val * get_var(g) for g, val in S[k]) else: - rels[g0*g1] = g1*g0 + F.sum(val*get_var(g) for g, val in S[k]) + rels[g0 * g1] = g1 * g0 + F.sum(val * get_var(g) for g, val in S[k]) try: return F.g_algebra(rels) except RuntimeError: @@ -262,6 +265,7 @@ def _dense_free_module(self, R=None): if R is None: R = self.base_ring() from sage.modules.free_module import FreeModule + return FreeModule(R, self.dimension()) module = _dense_free_module @@ -365,8 +369,7 @@ def killing_form_matrix(self): from sage.matrix.constructor import matrix B = self.basis() - m = matrix(self.base_ring(), - [[self.killing_form(x, y) for x in B] for y in B]) + m = matrix(self.base_ring(), [[self.killing_form(x, y) for x in B] for y in B]) m.set_immutable() return m @@ -416,7 +419,7 @@ def structure_coefficients(self, include_zeros=False): K = list(B.keys()) zero = self.zero() for i, x in enumerate(K): - for y in K[i + 1:]: + for y in K[i + 1 :]: bx = B[x] by = B[y] val = self.bracket(bx, by) @@ -481,6 +484,7 @@ def centralizer_basis(self, S): # if isinstance(S, LieSubalgebra) or S is self: if S is self: from sage.matrix.special import identity_matrix + m = identity_matrix(self.base_ring(), self.dimension()) elif isinstance(S, (list, tuple)): m = matrix([v.to_vector() for v in self.echelon_form(S)]) @@ -495,11 +499,7 @@ def centralizer_basis(self, S): sc[k[1], k[0]] = -v X = self.basis().keys() d = len(X) - c_mat = matrix(self.base_ring(), - [[sum(m[i, j] * sc[x, xp][k] for j, xp in enumerate(X) - if (x, xp) in sc) - for x in X] - for i in range(m.nrows()) for k in range(d)]) + c_mat = matrix(self.base_ring(), [[sum(m[i, j] * sc[x, xp][k] for j, xp in enumerate(X) if (x, xp) in sc) for x in X] for i in range(m.nrows()) for k in range(d)]) C = c_mat.right_kernel().basis_matrix() return [self.from_vector(c) for c in C] @@ -605,13 +605,7 @@ def normalizer_basis(self, S): X = self.basis().keys() d = len(X) t = m.nrows() - c_mat = matrix(self.base_ring(), - [[sum(m[i, j] * sc[x, xp][k] - for j, xp in enumerate(X) if (x, xp) in sc) - for x in X] - + [0]*(i*t) + [-m[j, k] for j in range(t)] - + [0]*((t-i-1)*t) - for i in range(t) for k in range(d)]) + c_mat = matrix(self.base_ring(), [[sum(m[i, j] * sc[x, xp][k] for j, xp in enumerate(X) if (x, xp) in sc) for x in X] + [0] * (i * t) + [-m[j, k] for j in range(t)] + [0] * ((t - i - 1) * t) for i in range(t) for k in range(d)]) C = c_mat.right_kernel().basis_matrix() return [self.from_vector(c[:d]) for c in C] @@ -701,24 +695,19 @@ def derivations_basis(self): R = self.base_ring() B = self.basis() keys = list(B.keys()) - scoeffs = {(j, y, i): c for y in keys for i in keys - for j, c in self.bracket(B[y], B[i]) - } + scoeffs = {(j, y, i): c for y in keys for i in keys for j, c in self.bracket(B[y], B[i])} zero = R.zero() data = {} N = len(keys) for ii, i in enumerate(keys): - for ij, j in enumerate(keys[ii+1:]): + for ij, j in enumerate(keys[ii + 1 :]): ijp = ij + ii + 1 for il, l in enumerate(keys): row = ii + N * il + N**2 * ij for ik, k in enumerate(keys): - data[row, ik+N*il] = (data.get((row, ik+N*il), zero) - + scoeffs.get((k, i, j), zero)) - data[row, ii+N*ik] = (data.get((row, ii+N*ik), zero) - - scoeffs.get((l, k, j), zero)) - data[row, ijp+N*ik] = (data.get((row, ijp+N*ik), zero) - - scoeffs.get((l, i, k), zero)) + data[row, ik + N * il] = data.get((row, ik + N * il), zero) + scoeffs.get((k, i, j), zero) + data[row, ii + N * ik] = data.get((row, ii + N * ik), zero) - scoeffs.get((l, k, j), zero) + data[row, ijp + N * ik] = data.get((row, ijp + N * ik), zero) - scoeffs.get((l, i, k), zero) mat = matrix(R, data, sparse=True) return tuple([matrix(R, N, N, list(b)) for b in mat.right_kernel().basis()]) @@ -744,8 +733,7 @@ def inner_derivations_basis(self): R = self.base_ring() IDer = matrix(R, [b.adjoint_matrix().list() for b in self.basis()]) N = self.dimension() - return tuple([matrix(R, N, N, list(b)) - for b in IDer.row_module().basis()]) + return tuple([matrix(R, N, N, list(b)) for b in IDer.row_module().basis()]) @cached_method def nilradical_basis(self): @@ -845,19 +833,18 @@ def nilradical_basis(self): return tuple([self(L.lift(b)) for b in ret]) from sage.matrix.constructor import matrix + s = P.dimension() QP = L.quotient(P) MP = P.module() for b in QP.basis(): yi = QP.lift(b) brackets = [yi.bracket(P.lift(b)) for b in P.basis()] - adj = matrix([MP.coordinate_vector(elt.to_vector()) - for elt in brackets]).transpose() + adj = matrix([MP.coordinate_vector(elt.to_vector()) for elt in brackets]).transpose() if adj.rank() < s: J = L.ideal(brackets) QJ = L.quotient(J) - M = L.ideal([QJ.lift(b) for b in QJ.nilradical_basis()] - + list(J.basis())) + M = L.ideal([QJ.lift(b) for b in QJ.nilradical_basis()] + list(J.basis())) return tuple([self(L.lift(b.value)) for b in M.nilradical_basis()]) f = adj.minimal_polynomial() @@ -867,8 +854,7 @@ def nilradical_basis(self): phi = P.module_morphism(codomain=P, matrix=g(adj)) I = L.ideal([phi(p) for p in P.basis()]) QI = L.quotient(I) - M = L.ideal([QI.lift(b) for b in QI.nilradical_basis()] - + list(I.basis())) + M = L.ideal([QI.lift(b) for b in QI.nilradical_basis()] + list(I.basis())) return tuple([self(L.lift(b.value)) for b in M.nilradical_basis()]) return tuple([self(L.lift(b.value)) for b in P.basis()]) @@ -878,16 +864,14 @@ def nilradical_basis(self): from sage.matrix.matrix_space import MatrixSpace from sage.matrix.constructor import matrix + dim = self.dimension() MS = MatrixSpace(self.base_ring(), dim) gens = [b.adjoint_matrix() for b in self.basis()] A = MS.subalgebra(gens) RB = A.radical_basis() - mat = matrix(self.base_ring(), - [g._vector_() for g in gens] - + [A.lift(r)._vector_() for r in RB]) - return tuple([self.from_vector(w) for v in mat.left_kernel().basis() - if (w := v[:dim])]) + mat = matrix(self.base_ring(), [g._vector_() for g in gens] + [A.lift(r)._vector_() for r in RB]) + return tuple([self.from_vector(w) for v in mat.left_kernel().basis() if (w := v[:dim])]) def nilradical(self): r""" @@ -960,8 +944,8 @@ def solvable_radical_basis(self): Bad = [b.adjoint_matrix() for b in self.basis()] Pad = [self(p).adjoint_matrix() for p in P.basis()] from sage.matrix.constructor import matrix - mat = matrix(self.base_ring(), - [[(B * P).trace() for B in Bad] for P in Pad]) + + mat = matrix(self.base_ring(), [[(B * P).trace() for B in Bad] for P in Pad]) return tuple([self.from_vector(c) for c in mat.right_kernel().basis_matrix()]) # positive characteristic @@ -1036,11 +1020,11 @@ def subalgebra(self, *gens, **kwds): [X_12] """ from sage.algebras.lie_algebras.subalgebra import LieSubalgebra_finite_dimensional_with_basis + if len(gens) == 1 and isinstance(gens[0], (list, tuple)): gens = gens[0] category = kwds.pop('category', None) - return LieSubalgebra_finite_dimensional_with_basis( - self, gens, category=category, **kwds) + return LieSubalgebra_finite_dimensional_with_basis(self, gens, category=category, **kwds) def ideal(self, *gens, **kwds): r""" @@ -1075,11 +1059,11 @@ def ideal(self, *gens, **kwds): """ from sage.algebras.lie_algebras.subalgebra import LieSubalgebra_finite_dimensional_with_basis from sage.structure.element import Element + if len(gens) == 1 and not isinstance(gens[0], Element): gens = gens[0] category = kwds.pop('category', None) - return LieSubalgebra_finite_dimensional_with_basis( - self, gens, ideal_of=self, category=category, **kwds) + return LieSubalgebra_finite_dimensional_with_basis(self, gens, ideal_of=self, category=category, **kwds) @cached_method def is_ideal(self, A): @@ -1109,16 +1093,14 @@ def is_ideal(self, A): if A == self: return True if A not in LieAlgebras(self.base_ring()).FiniteDimensional().WithBasis(): - raise NotImplementedError("A must be a finite dimensional" - " Lie algebra with basis") + raise NotImplementedError("A must be a finite dimensional" " Lie algebra with basis") from sage.matrix.constructor import matrix B = self.basis() AB = A.basis() try: - b_mat = matrix(A.base_ring(), [A.bracket(b, ab).to_vector() - for b in B for ab in AB]) + b_mat = matrix(A.base_ring(), [A.bracket(b, ab).to_vector() for b in B for ab in AB]) except (ValueError, TypeError): return False return b_mat.row_space().is_submodule(self.module()) @@ -1168,9 +1150,8 @@ def quotient(self, I, names=None, category=None): NotImplementedError: quotients over non-fields not implemented """ from sage.algebras.lie_algebras.quotient import LieQuotient_finite_dimensional_with_basis - return LieQuotient_finite_dimensional_with_basis(self, I, - names=names, - category=category) + + return LieQuotient_finite_dimensional_with_basis(self, I, names=names, category=category) def product_space(self, L, submodule=False): r""" @@ -1245,8 +1226,7 @@ def product_space(self, L, submodule=False): LB = L.basis() B = self.basis() - b_mat = matrix(A.base_ring(), [A.bracket(b, lb).to_vector() - for b in B for lb in LB]) + b_mat = matrix(A.base_ring(), [A.bracket(b, lb).to_vector() for b in B for lb in LB]) if submodule is True or not (self.is_ideal(A) and L.is_ideal(A)): return b_mat.row_space() # We echelonize the matrix here @@ -1694,13 +1674,12 @@ def chevalley_eilenberg_complex(self, M=None, dual=False, sparse=True, ncpus=Non - [Wei1994]_ Chapter 7 """ if dual: - return self.chevalley_eilenberg_complex(M, dual=False, - sparse=sparse, - ncpus=ncpus).dual() + return self.chevalley_eilenberg_complex(M, dual=False, sparse=sparse, ncpus=ncpus).dual() from itertools import combinations, product from sage.matrix.matrix_space import MatrixSpace from sage.algebras.lie_algebras.representation import Representation_abstract + R = self.base_ring() zero = R.zero() mone = -R.one() @@ -1736,13 +1715,13 @@ def sgn(k, X): is ``(zero, None)``. """ Y = list(X) - for i in range(len(X)-1, -1, -1): + for i in range(len(X) - 1, -1, -1): val = X[i] if val == k: return zero, None if k > val: - Y.insert(i+1, k) - return mone**(i+1), tuple(Y) + Y.insert(i + 1, k) + return mone ** (i + 1), tuple(Y) Y.insert(0, k) return R.one(), tuple(Y) @@ -1755,7 +1734,7 @@ def compute_diff(k): Build the ``k``-th differential (in parallel). """ # The indices for the exterior algebra - ext_ind = {tuple(X): i for i, X in enumerate(combinations(LI, k-1))} + ext_ind = {tuple(X): i for i, X in enumerate(combinations(LI, k - 1))} # Compute the part independent of the module first ("part 2" of the computation) if sparse: @@ -1777,8 +1756,8 @@ def compute_diff(k): for j in range(i + 1, k): # We shift j by 1 because we already removed # an earlier element from X. - Z = tuple(Y[:j-1] + Y[j:]) - elt = mone**(i+j+1) * LB[X[i]].bracket(LB[X[j]]) + Z = tuple(Y[: j - 1] + Y[j:]) + elt = mone ** (i + j + 1) * LB[X[i]].bracket(LB[X[j]]) if not elt: continue if ambient: @@ -1832,7 +1811,7 @@ def compute_diff(k): elt = mone**i * LB[X[i]] * MB[v] if not elt: continue - Y = X[:i] + X[i+1:] + Y = X[:i] + X[i + 1 :] for j in MI: coeff = elt[MK[j]] if not coeff: @@ -1858,6 +1837,7 @@ def compute_diff(k): return ret from sage.homology.chain_complex import ChainComplex + ind = list(range(1, len(LI) + 1)) chain_data = {X[0][0]: M for X, M in compute_diff(ind)} return ChainComplex(chain_data, degree_of_differential=-1) @@ -1909,8 +1889,7 @@ def homology(self, deg=None, M=None, sparse=True, ncpus=None): :meth:`chevalley_eilenberg_complex` """ - C = self.chevalley_eilenberg_complex(M=M, sparse=sparse, - ncpus=ncpus) + C = self.chevalley_eilenberg_complex(M=M, sparse=sparse, ncpus=ncpus) return C.homology(deg=deg) def cohomology(self, deg=None, M=None, sparse=True, ncpus=None): @@ -1984,8 +1963,7 @@ def cohomology(self, deg=None, M=None, sparse=True, ncpus=None): - :wikipedia:`Lie_algebra_cohomology` """ - C = self.chevalley_eilenberg_complex(M=M, dual=True, sparse=sparse, - ncpus=ncpus) + C = self.chevalley_eilenberg_complex(M=M, dual=True, sparse=sparse, ncpus=ncpus) return C.homology(deg=deg) def as_finite_dimensional_algebra(self): @@ -2023,6 +2001,7 @@ def as_finite_dimensional_algebra(self): M.append(zero_vec) mats.append(matrix(R, M)) from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra import FiniteDimensionalAlgebra + return FiniteDimensionalAlgebra(R, mats, names=self._names) def morphism(self, on_generators, codomain=None, base_map=None, check=True): @@ -2096,8 +2075,8 @@ def morphism(self, on_generators, codomain=None, base_map=None, check=True): -i*A """ from sage.algebras.lie_algebras.morphism import LieAlgebraMorphism_from_generators - return LieAlgebraMorphism_from_generators(on_generators, domain=self, - codomain=codomain, base_map=base_map, check=check) + + return LieAlgebraMorphism_from_generators(on_generators, domain=self, codomain=codomain, base_map=base_map, check=check) @cached_method def universal_polynomials(self): @@ -2152,6 +2131,7 @@ def universal_polynomials(self): - X2_1*X7_7 - X3_7*X8_1 + X3_1*X8_7 + X0_4 """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + I = self.basis().keys() n = len(I) s_coeffs = self.structure_coefficients(True) @@ -2163,29 +2143,25 @@ def sc(i, j): if i > j: return -s_coeffs[I[j], I[i]] return s_coeffs[I[i], I[j]] + d = {} keys = [] if n >= 10: vs = 'X{}_{}' else: vs = 'X{}{}' - R = PolynomialRing(self.base_ring(), ','.join(vs.format(i, j) - for i in range(n) - for j in range(n))) - X = [[R.gen(i+n*j) for i in range(n)] for j in range(n)] + R = PolynomialRing(self.base_ring(), ','.join(vs.format(i, j) for i in range(n) for j in range(n))) + X = [[R.gen(i + n * j) for i in range(n)] for j in range(n)] for a in range(n): for i in range(n): - for j in range(i+1, n): + for j in range(i + 1, n): k = (I[a], I[i], I[j]) keys.append(k) if i != j: s = sc(i, j) - d[k] = (R.sum(s[I[u]] * X[a][u] for u in range(n)) - - R.sum(sc(s, t)[I[a]] * X[s][i] * X[t][j] - for s in range(n) for t in range(n) if s != t)) + d[k] = R.sum(s[I[u]] * X[a][u] for u in range(n)) - R.sum(sc(s, t)[I[a]] * X[s][i] * X[t][j] for s in range(n) for t in range(n) if s != t) else: - d[k] = -R.sum(sc(s, t)[I[a]] * X[s][i] * X[t][j] - for s in range(n) for t in range(n) if s != t) + d[k] = -R.sum(sc(s, t)[I[a]] * X[s][i] * X[t][j] for s in range(n) for t in range(n) if s != t) return Family(keys, d.__getitem__) @cached_method @@ -2339,8 +2315,7 @@ def casimir_element(self, order=2, UEA=None, force_generic=False, basis=False): # Special case for the quadratic using the Killing form try: K = self.killing_form_matrix().inverse() - return UEA.sum(K[i, j] * UEA(x) * UEA(y) for i, x in enumerate(B) - for j, y in enumerate(B) if K[i, j]) + return UEA.sum(K[i, j] * UEA(x) * UEA(y) for i, x in enumerate(B) for j, y in enumerate(B) if K[i, j]) except (ValueError, TypeError, ZeroDivisionError): # fall back to finding solutions to the system of equations pass @@ -2354,8 +2329,9 @@ def casimir_element(self, order=2, UEA=None, force_generic=False, basis=False): # setup the equations from sage.matrix.constructor import matrix from itertools import product - eqns = matrix.zero(self.base_ring(), dim**(order+1), dim**order, sparse=True) - for ii, p in enumerate(product(range(dim), repeat=order+1)): + + eqns = matrix.zero(self.base_ring(), dim ** (order + 1), dim**order, sparse=True) + for ii, p in enumerate(product(range(dim), repeat=order + 1)): i = p[0] a = keys[i] for j, b in enumerate(keys): @@ -2363,7 +2339,7 @@ def casimir_element(self, order=2, UEA=None, force_generic=False, basis=False): continue sc_val = s_coeffs[a, b] for k in range(order): - c = keys[p[k+1]] + c = keys[p[k + 1]] if not sc_val[c]: continue pp = list(p[1:]) @@ -2380,7 +2356,7 @@ def casimir_element(self, order=2, UEA=None, force_generic=False, basis=False): def to_prod(vec, index): coeff = vec[index] p = [0] * order - base = dim ** (order-1) + base = dim ** (order - 1) for i in range(order): p[i] = index // base index %= base @@ -2394,8 +2370,7 @@ def to_prod(vec, index): vec = tens[0] return UEA.sum(to_prod(vec, index) for index in vec.support()) - return [UEA.sum(to_prod(vec, index) for index in vec.support()) - for vec in tens] + return [UEA.sum(to_prod(vec, index) for index in vec.support()) for vec in tens] def faithful_representation(self, algorithm=None): r""" @@ -2479,13 +2454,16 @@ def faithful_representation(self, algorithm=None): algorithm = "regular" if algorithm == "regular": from sage.algebras.lie_algebras.representation import FaithfulRepresentationNilpotentPBW + return FaithfulRepresentationNilpotentPBW(self, minimal=False) if algorithm == "minimal": from sage.algebras.lie_algebras.representation import FaithfulRepresentationNilpotentPBW + return FaithfulRepresentationNilpotentPBW(self, minimal=True) if algorithm is None or algorithm == "generic": if self.base_ring().characteristic() > 0: from sage.algebras.lie_algebras.representation import FaithfulRepresentationPBWPosChar + return FaithfulRepresentationPBWPosChar(self) raise NotImplementedError("only implemented for nilpotent Lie algebras") raise ValueError("invalid algorithm '{}'".format(algorithm)) @@ -2545,9 +2523,7 @@ def adjoint_matrix(self, sparse=False): P = self.parent() basis = P.basis() - return matrix(self.base_ring(), - [P.bracket(self, b).to_vector(sparse=sparse) for b in basis], - sparse=sparse).transpose() + return matrix(self.base_ring(), [P.bracket(self, b).to_vector(sparse=sparse) for b in basis], sparse=sparse).transpose() def to_vector(self, sparse=False, order=None): r""" @@ -2594,6 +2570,7 @@ def to_vector(self, sparse=False, order=None): mc = self.monomial_coefficients(copy=False) if sparse: from sage.modules.free_module import FreeModule + M = FreeModule(self.parent().base_ring(), self.dimension(), sparse=True) if order is None: order = {b: i for i, b in enumerate(self.parent()._basis_ordering)} @@ -2611,6 +2588,7 @@ class Subobjects(SubobjectsCategory): A category for subalgebras of a finite dimensional Lie algebra with basis. """ + class ParentMethods: @abstract_method def ambient(self): @@ -2712,6 +2690,7 @@ def reduce(self, X): """ R = self.base_ring() from sage.categories.fields import Fields + is_field = R in Fields() P = X.parent() X = self.ambient()(X) # make sure it is in the ambient space diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index a792798c22e..4a20efacf7d 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -1,6 +1,7 @@ r""" Finite dimensional modules with basis """ + # **************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2011 Nicolas M. Thiery @@ -126,9 +127,7 @@ def annihilator(self, S, action=operator.mul, side='right', category=None): sage: sorted(P.cover_relations(), key=str) # needs sage.graphs [[Ax, A], [Axy, Ax], [Axy, Ay], [Ay, A]] """ - return self.submodule(self.annihilator_basis(S, action, side), - already_echelonized=True, - category=category) + return self.submodule(self.annihilator_basis(S, action, side), already_echelonized=True, category=category) def annihilator_basis(self, S, action=operator.mul, side='right'): """ @@ -233,14 +232,14 @@ def annihilator_basis(self, S, action=operator.mul, side='right'): """ # TODO: optimize this! from sage.matrix.constructor import matrix + if side == 'right': action_left = action - action = lambda b,s: action_left(s, b) + action = lambda b, s: action_left(s, b) mat = matrix(self.base_ring(), self.dimension(), 0) for s in S: - mat = mat.augment(matrix(self.base_ring(), - [action(s, b)._vector_() for b in self.basis()])) + mat = mat.augment(matrix(self.base_ring(), [action(s, b)._vector_() for b in self.basis()])) return tuple(map(self.from_vector, mat.left_kernel().basis())) @cached_method @@ -272,6 +271,7 @@ def _dense_free_module(self, base_ring=None): if base_ring is None: base_ring = self.base_ring() from sage.modules.free_module import FreeModule + return FreeModule(base_ring, self.dimension()) def from_vector(self, vector, order=None, coerce=True): @@ -291,14 +291,12 @@ def from_vector(self, vector, order=None, coerce=True): if order is None: try: order = sorted(self.basis().keys()) - except AttributeError: # Not a family, assume it is list-like + except AttributeError: # Not a family, assume it is list-like order = range(self.dimension()) if not coerce or vector.base_ring() is self.base_ring(): - return self._from_dict({order[i]: c for i,c in vector.items()}, - coerce=False) + return self._from_dict({order[i]: c for i, c in vector.items()}, coerce=False) R = self.base_ring() - return self._from_dict({order[i]: R(c) for i,c in vector.items() if R(c)}, - coerce=False, remove_zeros=False) + return self._from_dict({order[i]: R(c) for i, c in vector.items() if R(c)}, coerce=False, remove_zeros=False) def echelon_form(self, elements, row_reduced=False, order=None): r""" @@ -378,6 +376,7 @@ def echelon_form(self, elements, row_reduced=False, order=None): if order is not None: order = self._compute_support_order(elements, order) from sage.matrix.constructor import matrix + mat = matrix(self.base_ring(), [g._vector_(order=order) for g in elements]) # Echelonizing a matrix over a field returned the rref if row_reduced and self.base_ring() not in Fields(): @@ -390,8 +389,7 @@ def echelon_form(self, elements, row_reduced=False, order=None): ret = [self.from_vector(vec, order=order) for vec in mat if vec] return ret - def invariant_module(self, S, action=operator.mul, action_on_basis=None, - side='left', **kwargs): + def invariant_module(self, S, action=operator.mul, action_on_basis=None, side='left', **kwargs): r""" Return the submodule of ``self`` invariant under the action of ``S``. @@ -457,18 +455,16 @@ def invariant_module(self, S, action=operator.mul, action_on_basis=None, """ if action_on_basis is not None: from sage.modules.with_basis.representation import Representation + M = Representation(S, self, action_on_basis, side=side) else: M = self from sage.modules.with_basis.invariant import FiniteDimensionalInvariantModule + return FiniteDimensionalInvariantModule(M, S, action=action, side=side, **kwargs) - def twisted_invariant_module(self, G, chi, - action=operator.mul, - action_on_basis=None, - side='left', - **kwargs): + def twisted_invariant_module(self, G, chi, action=operator.mul, action_on_basis=None, side='left', **kwargs): r""" Create the isotypic component of the action of ``G`` on ``self`` with irreducible character given by ``chi``. @@ -505,14 +501,15 @@ def twisted_invariant_module(self, G, chi, if action_on_basis is not None: from sage.modules.with_basis.representation import Representation from sage.categories.modules import Modules + category = kwargs.pop('category', Modules(self.base_ring()).WithBasis()) M = Representation(G, self, action_on_basis, side=side, category=category) else: M = self from sage.modules.with_basis.invariant import FiniteDimensionalTwistedInvariantModule - return FiniteDimensionalTwistedInvariantModule(M, G, chi, - action, side, **kwargs) + + return FiniteDimensionalTwistedInvariantModule(M, G, chi, action, side, **kwargs) class ElementMethods: def dense_coefficient_list(self, order=None): @@ -540,7 +537,7 @@ def dense_coefficient_list(self, order=None): if order is None: try: order = sorted(self.parent().basis().keys()) - except AttributeError: # Not a family, assume it is list-like + except AttributeError: # Not a family, assume it is list-like order = range(self.parent().dimension()) return [self[i] for i in order] @@ -562,11 +559,10 @@ def _vector_(self, order=None): dense_free_module = self.parent()._dense_free_module() else: from sage.modules.free_module import FreeModule + dense_free_module = FreeModule(self.parent().base_ring(), len(order)) # We slightly break encapsulation for speed reasons - return dense_free_module.element_class(dense_free_module, - self.dense_coefficient_list(order), - coerce=True, copy=False) + return dense_free_module.element_class(dense_free_module, self.dense_coefficient_list(order), coerce=True, copy=False) class MorphismMethods: def matrix(self, base_ring=None, side='left'): @@ -662,6 +658,7 @@ def matrix(self, base_ring=None, side='left'): on_basis = self.on_basis() basis_keys = self.domain().basis().keys() from sage.matrix.matrix_space import MatrixSpace + if isinstance(basis_keys, list): nrows = len(basis_keys) else: @@ -697,8 +694,7 @@ def _repr_matrix(self): from sage.matrix.constructor import options if matrix.nrows() <= options.max_rows() and matrix.ncols() <= options.max_cols(): - return matrix.str(top_border=self.domain().basis().keys(), - left_border=self.codomain().basis().keys()) + return matrix.str(top_border=self.domain().basis().keys(), left_border=self.codomain().basis().keys()) return repr(matrix) @@ -726,9 +722,7 @@ def _ascii_art_matrix(self): from sage.matrix.constructor import options if matrix.nrows() <= options.max_rows() and matrix.ncols() <= options.max_cols(): - return matrix.str(character_art=True, - top_border=self.domain().basis().keys(), - left_border=self.codomain().basis().keys()) + return matrix.str(character_art=True, top_border=self.domain().basis().keys(), left_border=self.codomain().basis().keys()) from sage.typeset.ascii_art import AsciiArt @@ -758,9 +752,7 @@ def _unicode_art_matrix(self): from sage.matrix.constructor import options if matrix.nrows() <= options.max_rows() and matrix.ncols() <= options.max_cols(): - return matrix.str(unicode=True, character_art=True, - top_border=self.domain().basis().keys(), - left_border=self.codomain().basis().keys()) + return matrix.str(unicode=True, character_art=True, top_border=self.domain().basis().keys(), left_border=self.codomain().basis().keys()) from sage.typeset.unicode_art import UnicodeArt @@ -821,9 +813,7 @@ def __invert__(self): inv_mat = mat.parent()(~mat) except (ZeroDivisionError, TypeError): raise RuntimeError("morphism is not invertible") - return self.codomain().module_morphism( - matrix=inv_mat, - codomain=self.domain(), category=self.category_for()) + return self.codomain().module_morphism(matrix=inv_mat, codomain=self.domain(), category=self.category_for()) def kernel_basis(self): """ @@ -836,8 +826,7 @@ def kernel_basis(self): sage: f.kernel_basis() # needs sage.groups sage.modules ([1, 2, 3] - [3, 2, 1], [1, 3, 2] - [3, 2, 1], [2, 1, 3] - [3, 2, 1]) """ - return tuple(map( self.domain().from_vector, - self.matrix().right_kernel_matrix().rows() )) + return tuple(map(self.domain().from_vector, self.matrix().right_kernel_matrix().rows())) def kernel(self): """ @@ -855,8 +844,7 @@ def kernel(self): Symmetric group algebra of order 3 over Rational Field """ D = self.domain() - return D.submodule(self.kernel_basis(), already_echelonized=True, - category=self.category_for()) + return D.submodule(self.kernel_basis(), already_echelonized=True, category=self.category_for()) def image_basis(self): """ @@ -870,7 +858,7 @@ def image_basis(self): ([1, 2, 3], [2, 3, 1], [3, 1, 2]) """ C = self.codomain() - return tuple(C.echelon_form( map(self, self.domain().basis()) )) + return tuple(C.echelon_form(map(self, self.domain().basis()))) def image(self): """ @@ -884,8 +872,7 @@ def image(self): Free module generated by {0, 1, 2} over Rational Field """ C = self.codomain() - return C.submodule(self.image_basis(), already_echelonized=True, - category=self.category_for()) + return C.submodule(self.image_basis(), already_echelonized=True, category=self.category_for()) class Homsets(HomsetsCategory): diff --git a/src/sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py b/src/sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py index d78c7d7d30a..a1ec817166d 100644 --- a/src/sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring @@ -45,6 +45,7 @@ class FiniteDimensionalNilpotentLieAlgebrasWithBasis(CategoryWithAxiom_over_base True sage: TestSuite(C1).run() """ + _base_category_class_and_axiom = (LieAlgebras.FiniteDimensional.WithBasis, "Nilpotent") class ParentMethods: @@ -81,13 +82,10 @@ def _test_nilpotency(self, **options): tester = self._tester(**options) lcs = self.lower_central_series(submodule=True) - tester.assertEqual(lcs[-1].dimension(), 0, - msg="final term of lower central series is nonzero") + tester.assertEqual(lcs[-1].dimension(), 0, msg="final term of lower central series is nonzero") step = self.step() - tester.assertEqual(len(lcs) - 1, step, - msg="claimed nilpotency step %d does not match the " - "actual nilpotency step %d" % (step, len(lcs) - 1)) + tester.assertEqual(len(lcs) - 1, step, msg="claimed nilpotency step %d does not match the " "actual nilpotency step %d" % (step, len(lcs) - 1)) def lie_group(self, name='G', **kwds): r""" @@ -133,6 +131,7 @@ def lie_group(self, name='G', **kwds): :class:`~sage.groups.lie_gps.nilpotent_lie_group.NilpotentLieGroup` """ from sage.groups.lie_gps.nilpotent_lie_group import NilpotentLieGroup + return NilpotentLieGroup(self, name, **kwds) def step(self): diff --git a/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py b/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py index 86b24ca9d7a..012b486400e 100644 --- a/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py @@ -1,13 +1,14 @@ r""" Finite dimensional semisimple algebras with basis """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2011-2015 Nicolas M. Thiery # 2014-2015 Aladin Virmaux # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.algebras import Algebras from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring @@ -36,6 +37,7 @@ class FiniteDimensionalSemisimpleAlgebrasWithBasis(CategoryWithAxiom_over_base_r sage: TestSuite(C).run() """ + _base_category_class_and_axiom = (SemisimpleAlgebras.FiniteDimensional, "WithBasis") class ParentMethods: @@ -110,8 +112,7 @@ def central_orthogonal_idempotents(self): sage: Aquo.central_orthogonal_idempotents() (B['x'], B['y']) """ - return tuple([x.lift() - for x in self.center().central_orthogonal_idempotents()]) + return tuple([x.lift() for x in self.center().central_orthogonal_idempotents()]) class Commutative(CategoryWithAxiom_over_base_ring): @@ -189,23 +190,15 @@ def _orthogonal_decomposition(self, generators=None): for gen in generators: # Computing the eigenspaces of the # linear map x -> gen*x - phi = self.module_morphism( - on_basis=lambda i: - gen*self.term(i), - codomain=self) + phi = self.module_morphism(on_basis=lambda i: gen * self.term(i), codomain=self) eigenspaces = phi.matrix().eigenspaces_right() if len(eigenspaces) >= 2: # Gotcha! Let's split the algebra according to the eigenspaces - subalgebras = [ - self.submodule(map(self.from_vector, eigenspace.basis()), - category=category) - for eigenvalue, eigenspace in eigenspaces] + subalgebras = [self.submodule(map(self.from_vector, eigenspace.basis()), category=category) for eigenvalue, eigenspace in eigenspaces] # Decompose recursively each eigenspace - return tuple([idempotent.lift() - for subalgebra in subalgebras - for idempotent in subalgebra._orthogonal_decomposition()]) + return tuple([idempotent.lift() for subalgebra in subalgebras for idempotent in subalgebra._orthogonal_decomposition()]) # TODO: Should this be an assertion check? raise Exception("Unable to fully decompose %s!" % self) @@ -265,5 +258,4 @@ def central_orthogonal_idempotents(self): sage: Z4.is_identity_decomposition_into_orthogonal_idempotents(idempotents) True """ - return tuple([(e.leading_coefficient()/(e*e).leading_coefficient())*e - for e in self._orthogonal_decomposition()]) + return tuple([(e.leading_coefficient() / (e * e).leading_coefficient()) * e for e in self._orthogonal_decomposition()]) diff --git a/src/sage/categories/finite_enumerated_sets.py b/src/sage/categories/finite_enumerated_sets.py index cff04249ddc..5062d5d02d4 100644 --- a/src/sage/categories/finite_enumerated_sets.py +++ b/src/sage/categories/finite_enumerated_sets.py @@ -1,6 +1,7 @@ r""" Finite Enumerated Sets """ + # **************************************************************************** # Copyright (C) 2009 Florent Hivert # @@ -16,6 +17,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_import import lazy_import from sage.cpython.getattr import raw_getattr + lazy_import("sage.rings.integer", "Integer") @@ -161,7 +163,7 @@ def _cardinality_from_iterator(self, *ignored_args, **ignored_kwds): c += 1 return Integer(c) - #Set cardinality to the default implementation + # Set cardinality to the default implementation cardinality = _cardinality_from_iterator def _cardinality_from_list(self, *ignored_args, **ignored_kwds): @@ -230,7 +232,7 @@ def tuple(self): True """ # Simpler implementation because it does not have to check whether cardinality is finite - try: # shortcut + try: # shortcut if self._list is not None: return self._tuple_from_list() except AttributeError: @@ -240,6 +242,7 @@ def tuple(self): return tuple(self.list()) return self._tuple_from_iterator() + _tuple_default = tuple def _list_from_iterator(self): @@ -383,7 +386,7 @@ def unrank_range(self, start=None, stop=None, step=None): return list(self._list[start:stop:step]) except AttributeError: pass - card = self.cardinality() # This may set the list + card = self.cardinality() # This may set the list try: return list(self._list[start:stop:step]) except AttributeError: @@ -435,7 +438,7 @@ def iterator_range(self, start=None, stop=None, step=None): L = self._list except AttributeError: pass - card = self.cardinality() # This may set the list + card = self.cardinality() # This may set the list try: L = self._list except AttributeError: @@ -474,9 +477,11 @@ def _random_element_from_unrank(self): True """ from sage.misc.prandom import randint + c = self.cardinality() - r = randint(0, c-1) + r = randint(0, c - 1) return self.unrank(r) + # Set the default implementation of random_element random_element = _random_element_from_unrank @@ -502,13 +507,13 @@ def _test_random(self, random_seed=123332938836894739865, **options): sage: C = cartesian_product([list(range(5)) for _ in range(5)]) sage: C._test_random() """ - if (self.random_element == self._random_element_from_unrank or - self.cardinality == self._cardinality_from_iterator): + if self.random_element == self._random_element_from_unrank or self.cardinality == self._cardinality_from_iterator: return from sage.misc.randstate import seed from sage.probability.probability_distribution import RealDistribution from sage.rings.infinity import Infinity from collections import Counter + tester = self._tester(**options) n = self.cardinality() if not n: @@ -523,7 +528,7 @@ def _test_random(self, random_seed=123332938836894739865, **options): tester.assertEqual(self.an_element(), self.random_element()) return - T = RealDistribution('chisquared', n-1) + T = RealDistribution('chisquared', n - 1) critical = T.cum_distribution_function_inv(0.99) if critical.is_NaN(): # the cardinality is too large @@ -536,13 +541,9 @@ def _test_random(self, random_seed=123332938836894739865, **options): elements = [self.random_element() for _ in range(N)] # check that setting the seed actually worked with seed(random_seed): - tester.assertEqual(elements[:10], - [self.random_element() - for _ in range(10)], - f"random_element of {self} produced different elements with the same seed {random_seed}") + tester.assertEqual(elements[:10], [self.random_element() for _ in range(10)], f"random_element of {self} produced different elements with the same seed {random_seed}") E = float(N) / float(n) - chi_2 = sum(float(o) ** 2 - for o in Counter(elements).values()) / E - float(N) + chi_2 = sum(float(o) ** 2 for o in Counter(elements).values()) / E - float(N) tester.assertLessEqual(chi_2, critical, f"assuming random_element of {self} follows a uniform distribution, this outcome would only occur with probability {1-T.cum_distribution_function(chi_2)}") def _test_rank(self, **options): @@ -560,15 +561,14 @@ def _test_rank(self, **options): from sage.categories.complex_reflection_groups import ComplexReflectionGroups from sage.categories.finite_posets import FinitePosets from sage.categories.modules_with_basis import ModulesWithBasis - if (self in ComplexReflectionGroups() - or self in FinitePosets() - or (self.base_ring() is not None - and self in ModulesWithBasis(self.base_ring()))): + + if self in ComplexReflectionGroups() or self in FinitePosets() or (self.base_ring() is not None and self in ModulesWithBasis(self.base_ring())): # the meaning of rank is different in these categories return if self.rank == self._rank_from_iterator: return from sage.misc.prandom import sample + tester = self._tester(**options) n = self.cardinality() if not n: @@ -602,6 +602,7 @@ def _last_from_iterator(self): for i in self: pass return i + last = _last_from_iterator def _last_from_unrank(self): @@ -656,8 +657,7 @@ def _test_enumerated_set_iter_cardinality(self, **options): if self.cardinality != self._cardinality_from_iterator: card = self.cardinality() if card <= tester._max_runs: - tester.assertEqual(card, - self._cardinality_from_iterator()) + tester.assertEqual(card, self._cardinality_from_iterator()) class CartesianProducts(CartesianProductsCategory): @@ -699,6 +699,7 @@ class ParentMethods: sage: C.__iter__.__module__ # needs sage.combinat 'sage.categories.sets_cat' """ + random_element = raw_getattr(Sets.CartesianProducts.ParentMethods, "random_element") cardinality = raw_getattr(Sets.CartesianProducts.ParentMethods, "cardinality") __iter__ = raw_getattr(Sets.CartesianProducts.ParentMethods, "__iter__") @@ -714,8 +715,7 @@ def last(self): sage: C.last() # needs sage.combinat (41, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 4) """ - return self._cartesian_product_of_elements( - tuple(c.last() for c in self.cartesian_factors())) + return self._cartesian_product_of_elements(tuple(c.last() for c in self.cartesian_factors())) def rank(self, x): r""" @@ -763,11 +763,11 @@ def rank(self, x): ('a', 86, [7, 5, 4, 4]) """ from sage.rings.integer_ring import ZZ + x = self(x) b = ZZ.one() rank = ZZ.zero() - for f, c in zip(reversed(x.cartesian_factors()), - reversed(self.cartesian_factors())): + for f, c in zip(reversed(x.cartesian_factors()), reversed(self.cartesian_factors())): rank += b * c.rank(f) b *= c.cardinality() return rank @@ -805,6 +805,7 @@ def unrank(self, i): IndexError: index i (=2) is greater than the cardinality """ from sage.rings.integer_ring import ZZ + i = ZZ(i) if i < 0: raise IndexError("i (={}) must be a nonnegative integer") @@ -831,6 +832,7 @@ def example(self): The image by some isomorphism of An example of a finite enumerated set: {1,2,3} """ from sage.categories.examples.finite_enumerated_sets import IsomorphicObjectOfFiniteEnumeratedSet + return IsomorphicObjectOfFiniteEnumeratedSet() class ParentMethods: diff --git a/src/sage/categories/finite_fields.py b/src/sage/categories/finite_fields.py index 0bc341db145..78e21d2399d 100644 --- a/src/sage/categories/finite_fields.py +++ b/src/sage/categories/finite_fields.py @@ -1,6 +1,7 @@ r""" Finite fields """ + # **************************************************************************** # Copyright (C) 2005 David Kohel # William Stein @@ -78,6 +79,7 @@ def __contains__(self, x) -> bool: False """ from sage.categories.fields import Fields + return x in Fields() and x.is_finite() # As is, this does no more than the usual __call__ of Category, but for the error message @@ -181,6 +183,7 @@ def zeta(self, n=None): return self.multiplicative_generator() from sage.rings.integer import Integer + n = Integer(n) grouporder = self.order() - 1 co_order = grouporder // n @@ -237,10 +240,10 @@ def _element_of_factored_order(self, F): # this allows to handle the ring Integers(prime) g = self.multiplicative_generator() for x in self: - a = (g + x)**c + a = (g + x) ** c if not a: continue - if all(a**(n // p) != 1 for p in primes): + if all(a ** (n // p) != 1 for p in primes): return a raise AssertionError("no element found") @@ -300,7 +303,7 @@ def is_square(self) -> bool: if self.parent().characteristic() == 2: return True q = self.parent().order() - character = self**((q-1)//2) + character = self ** ((q - 1) // 2) is_square = character == self.parent().one() return is_square @@ -332,14 +335,14 @@ def _tonelli(self): g = self.parent().quadratic_nonresidue() even_exp, odd_order = (q - Integer(1)).val_unit(2) e = 0 - for i in range(2, even_exp+1): + for i in range(2, even_exp + 1): tmp = self * (pow(g, -e)) - condition = tmp**((q-1)//(2**i)) != self.parent().one() + condition = tmp ** ((q - 1) // (2**i)) != self.parent().one() if condition: - e = 2**(i-1) + e - h = self * (g**(-e)) - b = g**(e//2) * h**((odd_order+1)//2) + e = 2 ** (i - 1) + e + h = self * (g ** (-e)) + b = g ** (e // 2) * h ** ((odd_order + 1) // 2) return b def _cipolla(self): @@ -375,9 +378,10 @@ def _cipolla(self): t = parent.random_element() root = t**2 - 4 * self from sage.rings.polynomial.polynomial_ring import polygen + X = polygen(parent) - f = X**2 - t*X + self - b = pow(X, (q+1)//2, f) + f = X**2 - t * X + self + b = pow(X, (q + 1) // 2, f) return b def sqrt(self, all: bool = False, algorithm: str = 'tonelli'): @@ -464,7 +468,7 @@ def sqrt(self, all: bool = False, algorithm: str = 'tonelli'): return () raise ValueError("element is not a square") if cardinality % 4 == 3: - square_root = self**((cardinality+1)//4) + square_root = self ** ((cardinality + 1) // 4) elif algorithm == 'tonelli': square_root = self._tonelli() else: diff --git a/src/sage/categories/finite_groups.py b/src/sage/categories/finite_groups.py index 97c94834643..55c34d0c2a4 100644 --- a/src/sage/categories/finite_groups.py +++ b/src/sage/categories/finite_groups.py @@ -42,7 +42,8 @@ def example(self): General Linear Group of degree 2 over Finite Field of size 3 """ from sage.groups.matrix_gps.linear import GL - return GL(2,3) + + return GL(2, 3) class ParentMethods: @@ -135,11 +136,12 @@ def cayley_graph_disabled(self, connecting_set=None): raise RuntimeError("each element of the connecting set must be in the group") connecting_set = [self(g) for g in connecting_set] from sage.graphs.digraph import DiGraph + arrows = {} for x in self: arrows[x] = {} for g in connecting_set: - xg = x*g # cache the multiplication + xg = x * g # cache the multiplication if not xg == x: arrows[x][xg] = g @@ -209,9 +211,11 @@ def extra_super_categories(self): False """ from sage.categories.fields import Fields + K = self.base_ring() if K in Fields() and K.characteristic() == 0: from sage.categories.algebras import Algebras + return [Algebras(self.base_ring()).Semisimple()] return [] @@ -242,11 +246,9 @@ def __init_extra__(self): base_ring = self.base_ring() group = self.group() from sage.categories.fields import Fields + # If base_ring is of characteristic 0, this is handled # in the FiniteGroups.Algebras category # Maschke's theorem: under some conditions, the algebra is semisimple. - if (base_ring in Fields - and base_ring.characteristic() > 0 - and hasattr(group, "cardinality") - and group.cardinality() % base_ring.characteristic() != 0): + if base_ring in Fields and base_ring.characteristic() > 0 and hasattr(group, "cardinality") and group.cardinality() % base_ring.characteristic() != 0: self._refine_category_(self.category().Semisimple()) diff --git a/src/sage/categories/finite_lattice_posets.py b/src/sage/categories/finite_lattice_posets.py index 42939236314..5d9d0b7c85a 100644 --- a/src/sage/categories/finite_lattice_posets.py +++ b/src/sage/categories/finite_lattice_posets.py @@ -1,6 +1,7 @@ r""" Finite lattice posets """ + # **************************************************************************** # Copyright (C) 2011 Nicolas M. Thiery # @@ -41,6 +42,7 @@ class FiniteLatticePosets(CategoryWithAxiom): True sage: TestSuite(C).run() """ + @cached_method def extra_super_categories(self): r""" @@ -180,8 +182,9 @@ def irreducibles_poset(self): """ if self.cardinality() == 1: from sage.combinat.posets.posets import Poset + return Poset({self[0]: []}) - return self.subposet(self.join_irreducibles()+self.meet_irreducibles()) + return self.subposet(self.join_irreducibles() + self.meet_irreducibles()) ###################################################################### # Lattice morphisms @@ -251,6 +254,7 @@ def is_lattice_morphism(self, f, codomain) -> bool: # ensure that this is a poset morphism. It actually may # be sufficient to check just joins (or just meets). from sage.combinat.subset import Subsets + for x, y in Subsets(self, 2): if f(self.join(x, y)) != codomain.join(f(x), f(y)): return False diff --git a/src/sage/categories/finite_monoids.py b/src/sage/categories/finite_monoids.py index 2984c955a10..e2b8209de37 100644 --- a/src/sage/categories/finite_monoids.py +++ b/src/sage/categories/finite_monoids.py @@ -1,6 +1,7 @@ r""" Finite monoids """ + # **************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # @@ -35,6 +36,7 @@ class FiniteMonoids(CategoryWithAxiom): sage: M.one() 10 """ + class ParentMethods: def nerve(self): @@ -164,6 +166,7 @@ def nerve(self): 3: Vector space of dimension 1 over Finite Field of size 5} """ from sage.topology.simplicial_set_examples import Nerve + return Nerve(self) def rhodes_radical_congruence(self, base_ring=None): @@ -208,6 +211,7 @@ def rhodes_radical_congruence(self, base_ring=None): - [Rho69]_ """ from sage.rings.rational_field import QQ + if base_ring is None: base_ring = QQ kS = self.algebra(base_ring) diff --git a/src/sage/categories/finite_permutation_groups.py b/src/sage/categories/finite_permutation_groups.py index 5d6f5d99177..b7115eb02c4 100644 --- a/src/sage/categories/finite_permutation_groups.py +++ b/src/sage/categories/finite_permutation_groups.py @@ -88,6 +88,7 @@ def example(self): Dihedral group of order 6 as a permutation group """ from sage.groups.perm_gps.permgroup_named import DihedralGroup + return DihedralGroup(3) def extra_super_categories(self): @@ -225,16 +226,16 @@ def cycle_index(self, parent=None): p[1] """ from sage.categories.modules import Modules + if parent is None: from sage.rings.rational_field import QQ from sage.combinat.sf.sf import SymmetricFunctions + parent = SymmetricFunctions(QQ).powersum() elif parent not in Modules.WithBasis: raise ValueError("`parent` should be a module with basis indexed by partitions") base_ring = parent.base_ring() - return parent.sum_of_terms([C.an_element().cycle_type(), base_ring(C.cardinality())] - for C in self.conjugacy_classes() - ) / self.cardinality() + return parent.sum_of_terms([C.an_element().cycle_type(), base_ring(C.cardinality())] for C in self.conjugacy_classes()) / self.cardinality() @cached_method def profile_series(self, variable='z'): @@ -328,6 +329,7 @@ def profile(self, n, using_polya=True): if using_polya: return self.profile_polynomial()[n] from sage.libs.gap.libgap import libgap + subs_n = libgap.Combinations(list(self.domain()), n) return len(libgap.Orbits(self, subs_n, libgap.OnSets)) diff --git a/src/sage/categories/finite_posets.py b/src/sage/categories/finite_posets.py index 4d83ff9becb..f4e0a080a6c 100644 --- a/src/sage/categories/finite_posets.py +++ b/src/sage/categories/finite_posets.py @@ -88,8 +88,7 @@ def is_lattice(self): - Weaker properties: :meth:`~sage.combinat.posets.posets.FinitePoset.is_join_semilattice`, :meth:`~sage.combinat.posets.posets.FinitePoset.is_meet_semilattice` """ - return (self.cardinality() == 0 or - (self.has_bottom() and self.is_join_semilattice())) + return self.cardinality() == 0 or (self.has_bottom() and self.is_join_semilattice()) def is_self_dual(self): r""" @@ -266,7 +265,7 @@ def is_poset_morphism(self, f, codomain): """ for x in self: for y in self.upper_covers(x): - if not codomain.is_lequal(f(x),f(y)): + if not codomain.is_lequal(f(x), f(y)): return False return True @@ -328,8 +327,8 @@ def order_ideal_generators(self, ideal, direction='down'): covers = self.lower_covers ideal_as_set = set(ideal) from sage.sets.set import Set - return Set(x for x in ideal if all(y not in ideal_as_set - for y in covers(x))) + + return Set(x for x in ideal if all(y not in ideal_as_set for y in covers(x))) def order_filter_generators(self, filter): r""" @@ -469,12 +468,7 @@ def rowmotion(self, order_ideal): result = self.order_ideal_toggle(result, i) return result - def birational_free_labelling(self, linear_extension=None, - prefix='x', base_field=None, - reduced=False, addvars=None, - labels=None, - min_label=None, - max_label=None): + def birational_free_labelling(self, linear_extension=None, prefix='x', base_field=None, reduced=False, addvars=None, labels=None, min_label=None, max_label=None): r""" Return the birational free labelling of ``self``. @@ -865,6 +859,7 @@ def birational_free_labelling(self, linear_extension=None, """ if base_field is None: from sage.rings.rational_field import QQ + base_field = QQ if linear_extension is None: linear_extension = self.linear_extension() @@ -893,6 +888,7 @@ def birational_free_labelling(self, linear_extension=None, varnum = len(label_list) from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + PR = PolynomialRing(base_field, varstring, varnum) # Now, ``PR`` is the polynomial ring in `n + 2` indeterminates # (or more, if ``addvars`` was set; or less, if ``reduced`` is @@ -901,7 +897,7 @@ def birational_free_labelling(self, linear_extension=None, # ``a, x1, x2, ..., xn, b`` (if ``reduced`` is ``False``). # These will label the vertices of `\widehat{P}`. if reduced: - xs = tuple(PR.gens()[: n]) + xs = tuple(PR.gens()[:n]) else: xs = tuple(PR.gens()[1 : n + 1]) # So ``xs`` is the list ``[x1, x2, ..., xn]``. @@ -1113,8 +1109,8 @@ def birational_toggle(self, v, labelling): sage: t8[1][8] a*b/x1 """ - FF = labelling[0] # base field - a = labelling[2] # label at `0 \in \widehat{P}` + FF = labelling[0] # base field + a = labelling[2] # label at `0 \in \widehat{P}` b = labelling[3] newdict = labelling[1].copy() # Construct the harmonic sum ``x`` of the labels at the @@ -1453,8 +1449,7 @@ def rowmotion_orbits(self, element_constructor=set): [[()]] """ pan_orbits = self.panyushev_orbits(element_constructor=list) - return [[element_constructor(self.order_ideal(oideal)) - for oideal in orbit] for orbit in pan_orbits] + return [[element_constructor(self.order_ideal(oideal)) for oideal in orbit] for orbit in pan_orbits] def rowmotion_orbits_plots(self): r""" @@ -1474,6 +1469,7 @@ def rowmotion_orbits_plots(self): Graphics Array of size 1 x 1 """ from sage.plot.plot import graphics_array + plot_of_orb_plots = [] max_orbit_size = 0 for orb in self.rowmotion_orbits(): @@ -1530,13 +1526,13 @@ def toggling_orbits(self, vs, element_constructor=set): orbits = [] while OI: A = OI.pop() - orbit = [ A ] + orbit = [A] while True: A = self.order_ideal_toggles(A, vs) if A not in OI: break - orbit.append( A ) - OI.remove( A ) + orbit.append(A) + OI.remove(A) orbits.append([element_constructor(_) for _ in orbit]) return orbits @@ -1559,6 +1555,7 @@ def toggling_orbits_plots(self, vs): Graphics Array of size 1 x 1 """ from sage.plot.plot import graphics_array + plot_of_orb_plots = [] max_orbit_size = 0 for orb in self.toggling_orbits(vs): @@ -1570,8 +1567,7 @@ def toggling_orbits_plots(self, vs): plot_of_orb_plots.append(orb_plots) return graphics_array(plot_of_orb_plots, ncols=max_orbit_size) - def panyushev_orbit_iter(self, antichain, element_constructor=set, - stop=True, check=True): + def panyushev_orbit_iter(self, antichain, element_constructor=set, stop=True, check=True): r""" Iterate over the Panyushev orbit of an antichain ``antichain`` of ``self``. @@ -1646,7 +1642,7 @@ def panyushev_orbit_iter(self, antichain, element_constructor=set, if check: if not self.is_antichain_of_poset(antichain): raise ValueError("the given antichain is not an antichain") - starter = set(antichain) # sanitize input + starter = set(antichain) # sanitize input yield element_constructor(starter) next = starter if stop: @@ -1741,7 +1737,7 @@ def rowmotion_orbit_iter(self, oideal, element_constructor=set, stop=True, check if check: if not self.is_order_ideal(oideal): raise ValueError("the given order ideal is not an order ideal") - starter = set(oideal) # sanitize input + starter = set(oideal) # sanitize input yield element_constructor(starter) next = starter if stop: @@ -1854,7 +1850,7 @@ def toggling_orbit_iter(self, vs, oideal, element_constructor=set, stop=True, ch if check: if not self.is_order_ideal(oideal): raise ValueError("the given order ideal is not an order ideal") - starter = set(oideal) # sanitize input + starter = set(oideal) # sanitize input yield element_constructor(starter) next = starter if stop: @@ -1930,20 +1926,20 @@ def order_ideals_lattice(self, as_ideals=True, facade=None): """ from sage.combinat.posets.lattices import LatticePoset from sage.categories.finite_lattice_posets import FiniteLatticePosets + if facade is None: facade = self._is_facade if as_ideals: from sage.misc.call import attrcall from sage.sets.set import Set - ideals = [Set(self.order_ideal(antichain)) - for antichain in self.antichains()] - T = LatticePoset((ideals, attrcall("issubset")), - facade=facade, - category=FiniteLatticePosets().Distributive()) + + ideals = [Set(self.order_ideal(antichain)) for antichain in self.antichains()] + T = LatticePoset((ideals, attrcall("issubset")), facade=facade, category=FiniteLatticePosets().Distributive()) return T from sage.misc.cachefunc import cached_function + antichains = [tuple(a) for a in self.antichains()] @cached_function @@ -1953,8 +1949,7 @@ def is_above(a, xb): def compare(a, b): return all(is_above(a, xb) for xb in b) - T = LatticePoset((antichains, compare), facade=facade, - category=FiniteLatticePosets().Distributive()) + T = LatticePoset((antichains, compare), facade=facade, category=FiniteLatticePosets().Distributive()) return T @abstract_method(optional=True) diff --git a/src/sage/categories/finite_semigroups.py b/src/sage/categories/finite_semigroups.py index efb93eb633a..75468e3c779 100644 --- a/src/sage/categories/finite_semigroups.py +++ b/src/sage/categories/finite_semigroups.py @@ -1,6 +1,7 @@ r""" Finite semigroups """ + # **************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2008-2009 Florent Hivert @@ -107,8 +108,7 @@ def j_classes_of_idempotents(self) -> list[list]: [['a'], ['ab', 'ba'], ['abc', 'acb', 'bac', 'bca', 'cab', 'cba'], ['ac', 'ca'], ['b'], ['bc', 'cb'], ['c']] """ - it = ([x for x in cl if attrcall('is_idempotent')(x)] - for cl in self.j_classes()) + it = ([x for x in cl if attrcall('is_idempotent')(x)] for cl in self.j_classes()) return [ell for ell in it if ell] @cached_method @@ -126,11 +126,13 @@ def j_transversal_of_idempotents(self): sage: sorted(S.j_transversal_of_idempotents()) # random # needs sage.graphs ['a', 'ab', 'abc', 'ac', 'b', 'c', 'cb'] """ + def first_idempotent(l): for x in l: if x.is_idempotent(): return x return None + return [x for x in (first_idempotent(_) for _ in self.j_classes()) if x is not None] # TODO: compute eJe, where J is the J-class of e diff --git a/src/sage/categories/finite_sets.py b/src/sage/categories/finite_sets.py index e3cce0933a7..a2bab901d38 100644 --- a/src/sage/categories/finite_sets.py +++ b/src/sage/categories/finite_sets.py @@ -1,12 +1,13 @@ r""" Finite sets """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2011 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.algebra_functor import AlgebrasCategory @@ -37,6 +38,7 @@ class FiniteSets(CategoryWithAxiom): sage: C is Sets().Finite() True """ + class SubcategoryMethods: def Infinite(self): @@ -104,4 +106,5 @@ def extra_super_categories(self): True """ from sage.categories.modules_with_basis import ModulesWithBasis + return [ModulesWithBasis(self.base_ring()).FiniteDimensional()] diff --git a/src/sage/categories/finite_weyl_groups.py b/src/sage/categories/finite_weyl_groups.py index 8e0346eb5ab..18da4f17202 100644 --- a/src/sage/categories/finite_weyl_groups.py +++ b/src/sage/categories/finite_weyl_groups.py @@ -1,6 +1,7 @@ r""" Finite Weyl Groups """ + # **************************************************************************** # Copyright (C) 2009 Nicolas M. Thiery # diff --git a/src/sage/categories/finitely_generated_lambda_bracket_algebras.py b/src/sage/categories/finitely_generated_lambda_bracket_algebras.py index 029857e4af7..793db161482 100644 --- a/src/sage/categories/finitely_generated_lambda_bracket_algebras.py +++ b/src/sage/categories/finitely_generated_lambda_bracket_algebras.py @@ -6,7 +6,7 @@ - Reimundo Heluani (2020-08-21): Initial implementation. """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2020 Reimundo Heluani # # This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.graded_modules import GradedModulesCategory @@ -31,6 +31,7 @@ class FinitelyGeneratedLambdaBracketAlgebras(CategoryWithAxiom_over_base_ring): sage: LambdaBracketAlgebras(QQbar).FinitelyGenerated() # needs sage.rings.number_field Category of finitely generated lambda bracket algebras over Algebraic Field """ + _base_category_class_and_axiom = (LambdaBracketAlgebras, "FinitelyGeneratedAsLambdaBracketAlgebra") class ParentMethods: @@ -85,8 +86,9 @@ def some_elements(self): """ S = list(self.gens()) from sage.misc.misc import some_tuples - for x,y in some_tuples(S, 2, 0, max_samples=self.ngens()): - S.append(x.T() + 2*y.T(2)) + + for x, y in some_tuples(S, 2, 0, max_samples=self.ngens()): + S.append(x.T() + 2 * y.T(2)) return S class Graded(GradedModulesCategory): @@ -99,6 +101,7 @@ class Graded(GradedModulesCategory): Category of H-graded finitely generated Lie conformal algebras over Algebraic Field """ + def _repr_object_names(self): """ The names of the objects of ``self``. diff --git a/src/sage/categories/finitely_generated_lie_conformal_algebras.py b/src/sage/categories/finitely_generated_lie_conformal_algebras.py index 90b18df668f..3ed7d828e4a 100644 --- a/src/sage/categories/finitely_generated_lie_conformal_algebras.py +++ b/src/sage/categories/finitely_generated_lie_conformal_algebras.py @@ -31,6 +31,7 @@ class FinitelyGeneratedLieConformalAlgebras(CategoryWithAxiom_over_base_ring): sage: LieConformalAlgebras(QQbar).FinitelyGenerated() # needs sage.rings.number_field Category of finitely generated Lie conformal algebras over Algebraic Field """ + _base_category_class_and_axiom = (LieConformalAlgebras, "FinitelyGeneratedAsLambdaBracketAlgebra") class ParentMethods: @@ -53,8 +54,9 @@ def some_elements(self): """ S = list(self.gens()) from sage.misc.misc import some_tuples - for x,y in some_tuples(S, 2, 0, max_samples=self.ngens()): - S.append(x.T() + 2*y.T(2)) + + for x, y in some_tuples(S, 2, 0, max_samples=self.ngens()): + S.append(x.T() + 2 * y.T(2)) return S class Super(SuperModulesCategory): @@ -67,6 +69,7 @@ class Super(SuperModulesCategory): Category of super finitely generated Lie conformal algebras over Algebraic Real Field """ + class Graded(GradedModulesCategory): """ The category of H-graded super finitely generated Lie conformal algebras. @@ -77,6 +80,7 @@ class Graded(GradedModulesCategory): Category of H-graded super finitely generated Lie conformal algebras over Algebraic Field """ + def _repr_object_names(self): """ The names of the objects of ``self``. @@ -100,6 +104,7 @@ class Graded(GradedModulesCategory): Category of H-graded finitely generated Lie conformal algebras over Algebraic Field """ + def _repr_object_names(self): """ The names of the objects of ``self``. diff --git a/src/sage/categories/finitely_generated_magmas.py b/src/sage/categories/finitely_generated_magmas.py index 166c6722807..5ff45a6b2e2 100644 --- a/src/sage/categories/finitely_generated_magmas.py +++ b/src/sage/categories/finitely_generated_magmas.py @@ -1,12 +1,13 @@ r""" Finitely generated magmas """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2014 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.abstract_method import abstract_method from sage.categories.category_with_axiom import CategoryWithAxiom diff --git a/src/sage/categories/finitely_generated_semigroups.py b/src/sage/categories/finitely_generated_semigroups.py index 91a533354a8..8f88149cfdb 100644 --- a/src/sage/categories/finitely_generated_semigroups.py +++ b/src/sage/categories/finitely_generated_semigroups.py @@ -1,6 +1,7 @@ r""" Finitely generated semigroups """ + # **************************************************************************** # Copyright (C) 2014 Nicolas M. Thiery # @@ -120,8 +121,8 @@ def succ_generators(self, side='twosided'): sage: S.succ_generators("twosided" )(S('ca')) ('ac', 'bca', 'ca', 'dca', 'ca', 'cab', 'ca', 'cad') """ - left = (side == "left" or side == "twosided") - right = (side == "right" or side == "twosided") + left = side == "left" or side == "twosided" + right = side == "right" or side == "twosided" generators = self.semigroup_generators() return lambda x: (tuple(g * x for g in generators) if left else ()) + (tuple(x * g for g in generators) if right else ()) @@ -142,9 +143,8 @@ def __iter__(self): ['x', 'xy', 'y', 'yx'] """ from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet - return iter(RecursivelyEnumeratedSet(self.semigroup_generators(), - self.succ_generators(side='right'), - enumeration='breadth')) + + return iter(RecursivelyEnumeratedSet(self.semigroup_generators(), self.succ_generators(side='right'), enumeration='breadth')) def ideal(self, gens, side='twosided'): r""" @@ -186,8 +186,8 @@ def ideal(self, gens, side='twosided'): 'dcab', 'dcba'] """ from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet - return RecursivelyEnumeratedSet(gens, - self.succ_generators(side=side)) + + return RecursivelyEnumeratedSet(gens, self.succ_generators(side=side)) class Finite(CategoryWithAxiom): diff --git a/src/sage/categories/function_fields.py b/src/sage/categories/function_fields.py index f738522697b..b2d1b13b33c 100644 --- a/src/sage/categories/function_fields.py +++ b/src/sage/categories/function_fields.py @@ -1,7 +1,8 @@ r""" Function fields """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2005 David Kohel # William Stein # 2008 Teresa Gomez-Diaz (CNRS) @@ -9,7 +10,7 @@ # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category import Category from sage.misc.cachefunc import cached_method @@ -32,6 +33,7 @@ class FunctionFields(Category): sage: TestSuite(FunctionFields()).run() """ + @cached_method def super_categories(self): """ diff --git a/src/sage/categories/g_sets.py b/src/sage/categories/g_sets.py index 597c7982844..b31bd83a837 100644 --- a/src/sage/categories/g_sets.py +++ b/src/sage/categories/g_sets.py @@ -1,14 +1,15 @@ r""" G-Sets """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 David Kohel and # William Stein # Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category import Category from sage.categories.sets_cat import Sets @@ -30,6 +31,7 @@ class GSets(Category): TODO: should this derive from Category_over_base? """ + def __init__(self, G): """ TESTS:: @@ -49,7 +51,7 @@ def _repr_object_names(self): """ return "G-sets for %s" % self.__G - #def construction(self): + # def construction(self): # return (self.__class__, self.__G) def super_categories(self): @@ -72,5 +74,6 @@ def an_instance(cls): Category of G-sets for Symmetric group of order 8! as a permutation group """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup + G = SymmetricGroup(8) return cls(G) diff --git a/src/sage/categories/gcd_domains.py b/src/sage/categories/gcd_domains.py index b30cc1e3802..8228c3913c4 100644 --- a/src/sage/categories/gcd_domains.py +++ b/src/sage/categories/gcd_domains.py @@ -1,12 +1,13 @@ r""" Gcd domains """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category_singleton import Category_singleton from sage.categories.integral_domains import IntegralDomains diff --git a/src/sage/categories/generalized_coxeter_groups.py b/src/sage/categories/generalized_coxeter_groups.py index 0f5d8fee0c7..41baf733dc4 100644 --- a/src/sage/categories/generalized_coxeter_groups.py +++ b/src/sage/categories/generalized_coxeter_groups.py @@ -1,7 +1,8 @@ r""" Generalized Coxeter Groups """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2016 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -9,7 +10,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.cachefunc import cached_method from sage.categories.category_singleton import Category_singleton @@ -41,6 +42,7 @@ class GeneralizedCoxeterGroups(Category_singleton): sage: TestSuite(C).run() """ + @cached_method def super_categories(self): """ @@ -73,6 +75,7 @@ class Finite(CategoryWithAxiom): """ The category of finite generalized Coxeter groups. """ + def extra_super_categories(self): """ Implement that a finite generalized Coxeter group is a @@ -90,4 +93,5 @@ def extra_super_categories(self): True """ from sage.categories.complex_reflection_groups import ComplexReflectionGroups + return [ComplexReflectionGroups().Finite().WellGenerated()] diff --git a/src/sage/categories/graded_algebras.py b/src/sage/categories/graded_algebras.py index 223babd6307..8004856feff 100644 --- a/src/sage/categories/graded_algebras.py +++ b/src/sage/categories/graded_algebras.py @@ -1,13 +1,14 @@ r""" Graded Algebras """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2008-2011 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.graded_modules import GradedModulesCategory from sage.categories.signed_tensor import SignedTensorProductsCategory @@ -30,6 +31,7 @@ class GradedAlgebras(GradedModulesCategory): sage: TestSuite(GradedAlgebras(ZZ)).run() """ + class ParentMethods: def graded_algebra(self): """ diff --git a/src/sage/categories/graded_algebras_with_basis.py b/src/sage/categories/graded_algebras_with_basis.py index f820e448e76..cce1b1319a2 100644 --- a/src/sage/categories/graded_algebras_with_basis.py +++ b/src/sage/categories/graded_algebras_with_basis.py @@ -1,13 +1,14 @@ r""" Graded algebras with basis """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2008-2011 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.graded_modules import GradedModulesCategory from sage.categories.signed_tensor import SignedTensorProductsCategory, tensor_signed @@ -32,6 +33,7 @@ class GradedAlgebrasWithBasis(GradedModulesCategory): sage: TestSuite(C).run() """ + class ParentMethods: # This needs to be copied in GradedAlgebras because we need to have # FilteredAlgebrasWithBasis as an extra super category @@ -128,6 +130,7 @@ def free_graded_module(self, generator_degrees, names=None): return self._free_graded_module_class(self, generator_degrees, names=names) except AttributeError: from sage.modules.fp_graded.free_module import FreeGradedModule + return FreeGradedModule(self, generator_degrees, names=names) def formal_series_ring(self): @@ -147,6 +150,7 @@ def formal_series_ring(self): the Rational Field in the Complete basis """ from sage.rings.lazy_series_ring import LazyCompletionGradedAlgebra + return LazyCompletionGradedAlgebra(self) completion = formal_series_ring @@ -177,6 +181,7 @@ class SignedTensorProducts(SignedTensorProductsCategory): The category of algebras with basis constructed by signed tensor product of algebras with basis. """ + @cached_method def extra_super_categories(self): """ @@ -196,6 +201,7 @@ class ParentMethods: Implement operations on tensor products of super algebras with basis. """ + @cached_method def one_basis(self): """ @@ -243,13 +249,9 @@ def product_on_basis(self, t0, t1): TODO: optimize this implementation! """ - basic = tensor_signed(module.monomial(x0) * module.monomial(x1) - for (module, x0, x1) in zip(self._sets, t0, t1)) + basic = tensor_signed(module.monomial(x0) * module.monomial(x1) for (module, x0, x1) in zip(self._sets, t0, t1)) n = len(self._sets) - parity0 = [self._sets[idx].degree_on_basis(x0) - for (idx, x0) in enumerate(t0)] - parity1 = [self._sets[idx].degree_on_basis(x1) - for (idx, x1) in enumerate(t1)] - parity = sum(parity0[i] * parity1[j] - for j in range(n) for i in range(j+1,n)) - return (-1)**parity * basic + parity0 = [self._sets[idx].degree_on_basis(x0) for (idx, x0) in enumerate(t0)] + parity1 = [self._sets[idx].degree_on_basis(x1) for (idx, x1) in enumerate(t1)] + parity = sum(parity0[i] * parity1[j] for j in range(n) for i in range(j + 1, n)) + return (-1) ** parity * basic diff --git a/src/sage/categories/graded_bialgebras.py b/src/sage/categories/graded_bialgebras.py index e792ee89057..33a060877e4 100644 --- a/src/sage/categories/graded_bialgebras.py +++ b/src/sage/categories/graded_bialgebras.py @@ -1,13 +1,14 @@ r""" Graded bialgebras """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2011 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** def GradedBialgebras(base_ring): @@ -28,4 +29,5 @@ def GradedBialgebras(base_ring): sage: TestSuite(C).run() """ from sage.categories.bialgebras import Bialgebras + return Bialgebras(base_ring).Graded() diff --git a/src/sage/categories/graded_bialgebras_with_basis.py b/src/sage/categories/graded_bialgebras_with_basis.py index b8915d571f7..84ce6995df3 100644 --- a/src/sage/categories/graded_bialgebras_with_basis.py +++ b/src/sage/categories/graded_bialgebras_with_basis.py @@ -1,13 +1,14 @@ r""" Graded bialgebras with basis """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2011 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** def GradedBialgebrasWithBasis(base_ring): @@ -28,4 +29,5 @@ def GradedBialgebrasWithBasis(base_ring): sage: TestSuite(C).run() """ from sage.categories.bialgebras_with_basis import BialgebrasWithBasis + return BialgebrasWithBasis(base_ring).Graded() diff --git a/src/sage/categories/graded_coalgebras.py b/src/sage/categories/graded_coalgebras.py index f771cdb7085..fbc33d3e4be 100644 --- a/src/sage/categories/graded_coalgebras.py +++ b/src/sage/categories/graded_coalgebras.py @@ -1,13 +1,14 @@ r""" Graded Coalgebras """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2011-2013 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.graded_modules import GradedModulesCategory from sage.categories.signed_tensor import SignedTensorProductsCategory @@ -29,6 +30,7 @@ class GradedCoalgebras(GradedModulesCategory): sage: TestSuite(C).run() """ + class SubcategoryMethods: def SignedTensorProducts(self): r""" diff --git a/src/sage/categories/graded_coalgebras_with_basis.py b/src/sage/categories/graded_coalgebras_with_basis.py index b2eac60fb3a..230ea2cd847 100644 --- a/src/sage/categories/graded_coalgebras_with_basis.py +++ b/src/sage/categories/graded_coalgebras_with_basis.py @@ -1,14 +1,15 @@ r""" Graded coalgebras with basis """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2011 Nicolas M. Thiery # 2019 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.cachefunc import cached_method from sage.categories.graded_modules import GradedModulesCategory @@ -30,11 +31,13 @@ class GradedCoalgebrasWithBasis(GradedModulesCategory): sage: TestSuite(C).run() """ + class SignedTensorProducts(SignedTensorProductsCategory): """ The category of coalgebras with basis constructed by signed tensor product of coalgebras with basis. """ + @cached_method def extra_super_categories(self): """ diff --git a/src/sage/categories/graded_hopf_algebras.py b/src/sage/categories/graded_hopf_algebras.py index 60d5befd6f5..27495378cce 100644 --- a/src/sage/categories/graded_hopf_algebras.py +++ b/src/sage/categories/graded_hopf_algebras.py @@ -1,6 +1,7 @@ r""" Graded Hopf algebras """ + # **************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2008-2011 Nicolas M. Thiery @@ -37,4 +38,5 @@ def GradedHopfAlgebras(base_ring): `. """ from sage.categories.hopf_algebras import HopfAlgebras + return HopfAlgebras(base_ring).Graded() diff --git a/src/sage/categories/graded_hopf_algebras_with_basis.py b/src/sage/categories/graded_hopf_algebras_with_basis.py index f30a84b5f9b..59b65fec495 100644 --- a/src/sage/categories/graded_hopf_algebras_with_basis.py +++ b/src/sage/categories/graded_hopf_algebras_with_basis.py @@ -1,13 +1,14 @@ r""" Graded Hopf algebras with basis """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2008-2011 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.tensor import tensor from sage.categories.graded_modules import GradedModulesCategory @@ -37,6 +38,7 @@ class GradedHopfAlgebrasWithBasis(GradedModulesCategory): sage: TestSuite(C).run() """ + def example(self): """ Return an example of a graded Hopf algebra with @@ -47,8 +49,8 @@ def example(self): sage: GradedHopfAlgebrasWithBasis(QQ).example() # needs sage.modules An example of a graded connected Hopf algebra with basis over Rational Field """ - from sage.categories.examples.graded_connected_hopf_algebras_with_basis import \ - GradedConnectedCombinatorialHopfAlgebraWithPrimitiveGenerator + from sage.categories.examples.graded_connected_hopf_algebras_with_basis import GradedConnectedCombinatorialHopfAlgebraWithPrimitiveGenerator + return GradedConnectedCombinatorialHopfAlgebraWithPrimitiveGenerator(self.base()) class ParentMethods: @@ -73,6 +75,7 @@ def super_categories(self): sage: TestSuite(GradedHopfAlgebrasWithBasis(QQ).WithRealizations()).run() """ from sage.categories.graded_hopf_algebras import GradedHopfAlgebras + R = self.base_category().base_ring() return [GradedHopfAlgebras(R)] @@ -87,8 +90,8 @@ def example(self): sage: GradedHopfAlgebrasWithBasis(QQ).Connected().example() # needs sage.modules An example of a graded connected Hopf algebra with basis over Rational Field """ - from sage.categories.examples.graded_connected_hopf_algebras_with_basis import \ - GradedConnectedCombinatorialHopfAlgebraWithPrimitiveGenerator + from sage.categories.examples.graded_connected_hopf_algebras_with_basis import GradedConnectedCombinatorialHopfAlgebraWithPrimitiveGenerator + return GradedConnectedCombinatorialHopfAlgebraWithPrimitiveGenerator(self.base()) class ParentMethods: @@ -156,13 +159,8 @@ def antipode_on_basis(self, index): return self.one() S = self.antipode_on_basis - x__S_Id = tensor([self, self]).module_morphism( - lambda ab: S(ab[0]) * self.monomial(ab[1]), - codomain=self) - return -x__S_Id( - self.monomial(index).coproduct() - - tensor([self.monomial(index), self.one()]) - ) + x__S_Id = tensor([self, self]).module_morphism(lambda ab: S(ab[0]) * self.monomial(ab[1]), codomain=self) + return -x__S_Id(self.monomial(index).coproduct() - tensor([self.monomial(index), self.one()])) class ElementMethods: pass diff --git a/src/sage/categories/graded_lie_algebras.py b/src/sage/categories/graded_lie_algebras.py index ec4d052e28d..3d03661df66 100644 --- a/src/sage/categories/graded_lie_algebras.py +++ b/src/sage/categories/graded_lie_algebras.py @@ -29,6 +29,7 @@ class GradedLieAlgebras(GradedModulesCategory): sage: C = LieAlgebras(QQ).Graded() sage: TestSuite(C).run() """ + class SubcategoryMethods: def Stratified(self): r""" @@ -57,6 +58,7 @@ class Stratified(CategoryWithAxiom_over_base_ring): sage: C = LieAlgebras(QQ).Graded().Stratified() sage: TestSuite(C).run() """ + class FiniteDimensional(CategoryWithAxiom_over_base_ring): r""" Category of finite dimensional stratified Lie algebras. @@ -71,6 +73,7 @@ class FiniteDimensional(CategoryWithAxiom_over_base_ring): sage: C = LieAlgebras(QQ).Graded().Stratified().FiniteDimensional() sage: TestSuite(C).run() """ + def extra_super_categories(self): """ Implement the fact that a finite dimensional stratified Lie @@ -87,4 +90,5 @@ def extra_super_categories(self): True """ from sage.categories.lie_algebras import LieAlgebras + return [LieAlgebras(self.base_ring()).Nilpotent()] diff --git a/src/sage/categories/graded_lie_algebras_with_basis.py b/src/sage/categories/graded_lie_algebras_with_basis.py index 8552218e074..461aab16e01 100644 --- a/src/sage/categories/graded_lie_algebras_with_basis.py +++ b/src/sage/categories/graded_lie_algebras_with_basis.py @@ -38,6 +38,5 @@ class GradedLieAlgebrasWithBasis(GradedModulesCategory): sage: TestSuite(C).run() """ - FiniteDimensional = LazyImport('sage.categories.finite_dimensional_graded_lie_algebras_with_basis', - 'FiniteDimensionalGradedLieAlgebrasWithBasis', - as_name='FiniteDimensional') + + FiniteDimensional = LazyImport('sage.categories.finite_dimensional_graded_lie_algebras_with_basis', 'FiniteDimensionalGradedLieAlgebrasWithBasis', as_name='FiniteDimensional') diff --git a/src/sage/categories/graded_lie_conformal_algebras.py b/src/sage/categories/graded_lie_conformal_algebras.py index 9b34222283b..9251d846840 100644 --- a/src/sage/categories/graded_lie_conformal_algebras.py +++ b/src/sage/categories/graded_lie_conformal_algebras.py @@ -6,7 +6,7 @@ - Reimundo Heluani (2019-10-05): Initial implementation. """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2019 Reimundo Heluani # # This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.graded_modules import GradedModulesCategory from sage.misc.cachefunc import cached_method diff --git a/src/sage/categories/graded_modules.py b/src/sage/categories/graded_modules.py index ff66b885913..38f043e0baa 100644 --- a/src/sage/categories/graded_modules.py +++ b/src/sage/categories/graded_modules.py @@ -1,6 +1,7 @@ r""" Graded modules """ + # **************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2008-2013 Nicolas M. Thiery @@ -125,6 +126,7 @@ class GradedModules(GradedModulesCategory): sage: TestSuite(GradedModules(ZZ)).run() """ + class ParentMethods: pass diff --git a/src/sage/categories/graded_modules_with_basis.py b/src/sage/categories/graded_modules_with_basis.py index f72565281f2..0a63a8bbfe4 100644 --- a/src/sage/categories/graded_modules_with_basis.py +++ b/src/sage/categories/graded_modules_with_basis.py @@ -1,13 +1,14 @@ r""" Graded modules with basis """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2008-2011 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.graded_modules import GradedModulesCategory from sage.categories.quotients import QuotientsCategory @@ -31,6 +32,7 @@ class GradedModulesWithBasis(GradedModulesCategory): sage: TestSuite(C).run() """ + class ParentMethods: def degree_negation(self, element): r""" @@ -62,16 +64,11 @@ def degree_negation(self, element): -4*P[1] - 2*P[2] + P[3, 1] """ base_one = self.base_ring().one() - base_minusone = - base_one - diag = lambda x: (base_one if self.degree_on_basis(x) % 2 == 0 - else base_minusone) - return self.sum_of_terms([(key, diag(key) * value) - for key, value in - element.monomial_coefficients(copy=False).items()]) - - def submodule(self, gens, check=True, already_echelonized=False, - unitriangular=False, support_order=None, category=None, - *args, **opts): + base_minusone = -base_one + diag = lambda x: (base_one if self.degree_on_basis(x) % 2 == 0 else base_minusone) + return self.sum_of_terms([(key, diag(key) * value) for key, value in element.monomial_coefficients(copy=False).items()]) + + def submodule(self, gens, check=True, already_echelonized=False, unitriangular=False, support_order=None, category=None, *args, **opts): r""" Return the submodule spanned by a finite set of elements. @@ -179,6 +176,7 @@ def submodule(self, gens, check=True, already_echelonized=False, """ # Make sure gens consists of elements of ``self`` from sage.sets.family import Family, AbstractFamily + if isinstance(gens, AbstractFamily): gens = gens.map(self) elif isinstance(gens, dict): @@ -193,15 +191,12 @@ def submodule(self, gens, check=True, already_echelonized=False, if category is None: if all(g.is_homogeneous() for g in gens): category = GMod.Subobjects() - elif (category.is_subcategory(GMod.Subobjects()) - and not all(g.is_homogeneous() for g in gens)): + elif category.is_subcategory(GMod.Subobjects()) and not all(g.is_homogeneous() for g in gens): raise ValueError("all of the generators must be homogeneous") from sage.modules.with_basis.subquotient import SubmoduleWithBasis - return SubmoduleWithBasis(gens, ambient=self, - support_order=support_order, - unitriangular=unitriangular, - category=category, *args, **opts) + + return SubmoduleWithBasis(gens, ambient=self, support_order=support_order, unitriangular=unitriangular, category=category, *args, **opts) def quotient_module(self, submodule, check=True, already_echelonized=False, category=None): r""" @@ -243,17 +238,15 @@ def quotient_module(self, submodule, check=True, already_echelonized=False, cate - :class:`sage.modules.with_basis.subquotient.QuotientModuleWithBasis` """ from sage.modules.with_basis.subquotient import SubmoduleWithBasis, QuotientModuleWithBasis + if not isinstance(submodule, SubmoduleWithBasis): - submodule = self.submodule(submodule, check=check, - unitriangular=True, - already_echelonized=already_echelonized) + submodule = self.submodule(submodule, check=check, unitriangular=True, already_echelonized=already_echelonized) GMod = GradedModulesWithBasis(self.category().base_ring()) if category is None: if all(g.is_homogeneous() for g in submodule.basis()): category = GMod.Quotients() - elif (category.is_subcategory(GMod.Quotients()) - and not all(g.is_homogeneous() for g in submodule.basis())): + elif category.is_subcategory(GMod.Quotients()) and not all(g.is_homogeneous() for g in submodule.basis()): raise ValueError("all of the basis elements must be homogeneous") return QuotientModuleWithBasis(submodule, category=category) diff --git a/src/sage/categories/graphs.py b/src/sage/categories/graphs.py index d0157e42d04..158d869d3db 100644 --- a/src/sage/categories/graphs.py +++ b/src/sage/categories/graphs.py @@ -1,12 +1,13 @@ """ Graphs """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2015 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method @@ -30,6 +31,7 @@ class Graphs(Category_singleton): sage: TestSuite(C).run() """ + @cached_method def super_categories(self): """ @@ -119,6 +121,7 @@ class Connected(CategoryWithAxiom): sage: C = Graphs().Connected() sage: TestSuite(C).run() """ + def extra_super_categories(self): """ Return the extra super categories of ``self``. diff --git a/src/sage/categories/group_algebras.py b/src/sage/categories/group_algebras.py index 712d8647eff..5084ecda4c2 100644 --- a/src/sage/categories/group_algebras.py +++ b/src/sage/categories/group_algebras.py @@ -18,14 +18,14 @@ monoid algebras, and beyond -- see e.g. :issue:`18700`. """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2005 David Kohel # William Stein # 2008-2017 Nicolas M. Thiéry # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.cachefunc import cached_method from sage.categories.algebra_functor import AlgebrasCategory @@ -83,6 +83,7 @@ class GroupAlgebras(AlgebrasCategory): sage: C = GroupAlgebras(ZZ) sage: TestSuite(C).run() """ + def extra_super_categories(self): """ Implement the fact that the algebra of a group is a Hopf @@ -98,6 +99,7 @@ def extra_super_categories(self): Category of monoid algebras over Rational Field] """ from sage.categories.hopf_algebras import HopfAlgebras + return [HopfAlgebras(self.base_ring())] def example(self, G=None): @@ -117,6 +119,7 @@ def example(self, G=None): Alternating group of order 4!/2 as a permutation group over Rational Field """ from sage.groups.perm_gps.permgroup_named import DihedralGroup + if G is None: G = DihedralGroup(4) return G.algebra(self.base_ring()) @@ -148,7 +151,7 @@ def __init_extra__(self): ## some matrix groups assume that coercion is only valid to ## other matrix groups. This is a workaround ## call _element_constructor_ to coerce group elements - #try: + # try: self._populate_coercion_lists_(coerce_list=[self.group()]) def _latex_(self): @@ -162,6 +165,7 @@ def _latex_(self): \Bold{Z}[\langle (3,4), (1,2) \rangle] """ from sage.misc.latex import latex + return "%s[%s]" % (latex(self.base_ring()), latex(self.group())) def group(self): @@ -206,8 +210,7 @@ def center_basis(self): - :meth:`Groups.Algebras.ElementMethods.central_form` - :meth:`Monoids.Algebras.ElementMethods.is_central` """ - return tuple([self.sum_of_monomials(conj) for conj in - self.basis().keys().conjugacy_classes()]) + return tuple([self.sum_of_monomials(conj) for conj in self.basis().keys().conjugacy_classes()]) # Hopf algebra structure @@ -234,6 +237,7 @@ def coproduct_on_basis(self, g): () # () + 3*(1,2,3,4,5,6) # (1,2,3,4,5,6) + 3*(1,3,5)(2,4,6) # (1,3,5)(2,4,6) """ from sage.categories.tensor import tensor + g = self.term(g) return tensor([g, g]) @@ -331,6 +335,7 @@ def is_integral_domain(self, proof=True): False """ from sage.sets.set import Set + ans = False try: if self.base_ring().is_integral_domain(): @@ -424,6 +429,7 @@ def central_form(self): - :meth:`Monoids.Algebras.ElementMethods.is_central` """ from sage.combinat.free_module import CombinatorialFreeModule + conj_classes_reps = self.parent().basis().keys().conjugacy_classes_representatives() Z = CombinatorialFreeModule(self.base_ring(), conj_classes_reps) return sum(self[i] * Z.basis()[i] for i in Z.basis().keys()) diff --git a/src/sage/categories/groupoid.py b/src/sage/categories/groupoid.py index 1539722bfa6..c9098d97f20 100644 --- a/src/sage/categories/groupoid.py +++ b/src/sage/categories/groupoid.py @@ -2,14 +2,14 @@ r""" Groupoid """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2008 David Kohel and # William Stein # Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category import CategoryWithParameters from sage.categories.sets_cat import Sets @@ -42,6 +42,7 @@ def __init__(self, G=None): CategoryWithParameters.__init__(self) # "Groupoid") if G is None: from sage.groups.perm_gps.permgroup_named import SymmetricGroup + G = SymmetricGroup(8) self.__G = G @@ -76,7 +77,7 @@ def super_categories(self): sage: Groupoid(DihedralGroup(3)).super_categories() [Category of sets] """ - return [Sets()] # ??? + return [Sets()] # ??? @classmethod def an_instance(cls): @@ -89,5 +90,6 @@ def an_instance(cls): Groupoid with underlying set Symmetric group of order 8! as a permutation group """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup + G = SymmetricGroup(8) return cls(G) diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index 4ad06e31ad8..d54df15f086 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -1,6 +1,7 @@ r""" Groups """ + # **************************************************************************** # Copyright (C) 2005 David Kohel # William Stein @@ -36,6 +37,7 @@ class Groups(CategoryWithAxiom): sage: TestSuite(Groups()).run() """ + _base_category_class_and_axiom = (Monoids, "Inverse") def example(self): @@ -47,7 +49,8 @@ def example(self): """ from sage.rings.rational_field import QQ from sage.groups.matrix_gps.linear import GL - return GL(4,QQ) + + return GL(4, QQ) @staticmethod def free(index_set=None, names=None, **kwds): @@ -80,13 +83,16 @@ def free(index_set=None, names=None, **kwds): Free Group on generators {x, y, z} """ from sage.rings.integer_ring import ZZ + if index_set in ZZ or (index_set is None and names is not None): from sage.groups.free_group import FreeGroup + if names is None: return FreeGroup(index_set, **kwds) return FreeGroup(index_set, names, **kwds) from sage.groups.indexed_free_group import IndexedFreeGroup + return IndexedFreeGroup(index_set, **kwds) class ParentMethods: @@ -105,6 +111,7 @@ def group_generators(self): Family ((1,2,3), (2,3,4)) """ from sage.sets.family import Family + try: return Family(self.gens()) except AttributeError: @@ -131,9 +138,11 @@ def monoid_generators(self): """ G = self.group_generators() from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets + if G not in FiniteEnumeratedSets(): raise NotImplementedError("currently only implemented for finitely generated groups") from sage.sets.family import Family + return Family(tuple(G) + tuple(~x for x in G)) def _test_inverse(self, **options): @@ -432,6 +441,7 @@ class provides even greater flexibility, including changing """ from sage.matrix.operation_table import OperationTable import operator + return OperationTable(self, operation=operator.mul, names=names, elements=elements) def conjugacy_class(self, g): @@ -448,6 +458,7 @@ def conjugacy_class(self, g): """ from sage.groups.conjugacy_classes import ConjugacyClass + return ConjugacyClass(self, g) class ElementMethods: @@ -498,6 +509,7 @@ class Commutative(CategoryWithAxiom): A group `G` is *commutative* if `xy = yx` for all `x,y \in G`. """ + @staticmethod def free(index_set=None, names=None, **kwds): r""" @@ -524,6 +536,7 @@ def free(index_set=None, names=None, **kwds): Multiplicative Abelian group isomorphic to Z x Z x Z """ from sage.rings.integer_ring import ZZ + if names is not None: if isinstance(names, str): if ',' not in names and index_set in ZZ: @@ -535,13 +548,16 @@ def free(index_set=None, names=None, **kwds): index_set = ZZ(len(names)) if index_set in ZZ: from sage.groups.abelian_gps.abelian_group import AbelianGroup + return AbelianGroup(index_set, names=names, **kwds) if index_set in ZZ: from sage.groups.abelian_gps.abelian_group import AbelianGroup + return AbelianGroup(index_set, **kwds) from sage.groups.indexed_free_group import IndexedFreeAbelianGroup + return IndexedFreeAbelianGroup(index_set, names=names, **kwds) class CartesianProducts(CartesianProductsCategory): @@ -552,6 +568,7 @@ class CartesianProducts(CartesianProductsCategory): :wikipedia:`Direct_product` and :wikipedia:`Direct_product_of_groups` for more information. """ + def extra_super_categories(self): """ A Cartesian product of groups is endowed with a natural @@ -610,21 +627,19 @@ def lift(i, gen): cur = list(ids) cur[i] = gen return self._cartesian_product_of_elements(cur) + from sage.sets.family import Family # Finitely generated cat = FiniteEnumeratedSets() - if all(G.group_generators() in cat - or isinstance(G.group_generators(), (tuple, list)) for G in F): + if all(G.group_generators() in cat or isinstance(G.group_generators(), (tuple, list)) for G in F): ret = [lift(i, gen) for i, G in enumerate(F) for gen in G.group_generators()] return Family(ret) # Infinitely generated # This does not return a good output, but it is "correct" # TODO: Figure out a better way to do things - gens_prod = cartesian_product([Family(G.group_generators(), - lambda g: (i, g)) - for i, G in enumerate(F)]) + gens_prod = cartesian_product([Family(G.group_generators(), lambda g: (i, g)) for i, G in enumerate(F)]) return Family(gens_prod, lift, name='gen') def order(self): @@ -649,6 +664,7 @@ def order(self): ``_cardinality_from_iterator``. """ from sage.misc.misc_c import prod + return prod(c.cardinality() for c in self.cartesian_factors()) class Topological(TopologicalSpacesCategory): diff --git a/src/sage/categories/h_trivial_semigroups.py b/src/sage/categories/h_trivial_semigroups.py index 4712042781f..39dc228fc56 100644 --- a/src/sage/categories/h_trivial_semigroups.py +++ b/src/sage/categories/h_trivial_semigroups.py @@ -1,7 +1,8 @@ r""" H-trivial semigroups """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2016 Nicolas M. Thiéry # # This program is free software: you can redistribute it and/or modify @@ -9,7 +10,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.semigroups import Semigroups diff --git a/src/sage/categories/hecke_modules.py b/src/sage/categories/hecke_modules.py index c88d7b4e1c1..a134f6f4ec6 100644 --- a/src/sage/categories/hecke_modules.py +++ b/src/sage/categories/hecke_modules.py @@ -1,6 +1,7 @@ r""" Hecke modules """ + # **************************************************************************** # Copyright (C) 2005 David Kohel # William Stein @@ -58,6 +59,7 @@ class HeckeModules(Category_module): sage: TestSuite(HeckeModules(ZZ)).run() """ + def __init__(self, R): """ TESTS:: @@ -70,6 +72,7 @@ def __init__(self, R): TypeError: R (=Partitions of the integer 3) must be a commutative ring """ from .commutative_rings import CommutativeRings + if R not in CommutativeRings(): raise TypeError("R (=%s) must be a commutative ring" % R) Category_module.__init__(self, R) @@ -153,6 +156,7 @@ def _Hom_(self, Y, category): if category is not None and not category.is_subcategory(HeckeModules(self.base_ring())): raise TypeError("%s is not a subcategory of %s" % (category, HeckeModules(self.base_ring()))) from sage.modular.hecke.homspace import HeckeModuleHomspace + return HeckeModuleHomspace(self, Y, category=category) class Homsets(HomsetsCategory): @@ -178,6 +182,7 @@ def extra_super_categories(self): [Category of vector spaces over Rational Field, Category of homsets] """ from sage.categories.modules import Modules + return [Modules(self.base_category().base_ring())] class ParentMethods: diff --git a/src/sage/categories/highest_weight_crystals.py b/src/sage/categories/highest_weight_crystals.py index 8c9e2dde7f3..d2bdbced4c9 100644 --- a/src/sage/categories/highest_weight_crystals.py +++ b/src/sage/categories/highest_weight_crystals.py @@ -11,8 +11,7 @@ from sage.misc.cachefunc import cached_method from sage.categories.category_singleton import Category_singleton -from sage.categories.crystals import (Crystals, CrystalHomset, - CrystalMorphismByGenerators) +from sage.categories.crystals import Crystals, CrystalHomset, CrystalMorphismByGenerators from sage.categories.tensor import TensorProductsCategory @@ -90,6 +89,7 @@ def example(self): Highest weight crystal of type A_3 of highest weight omega_1 """ from sage.categories.crystals import Crystals + return Crystals().example() def additional_structure(self): @@ -211,10 +211,8 @@ def __iter__(self, index_set=None, max_depth=float("inf")): if index_set is None: index_set = self.index_set() from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet - return RecursivelyEnumeratedSet(self.module_generators, - lambda x: [x.f(i) for i in index_set], - structure='graded', - max_depth=max_depth).breadth_first_search_iterator() + + return RecursivelyEnumeratedSet(self.module_generators, lambda x: [x.f(i) for i in index_set], structure='graded', max_depth=max_depth).breadth_first_search_iterator() @cached_method def q_dimension(self, q=None, prec=None, use_product=False): @@ -331,6 +329,7 @@ def q_dimension(self, q=None, prec=None, use_product=False): [1, 1, 2, 2, 4, 5, 7, 9, 13, 16, 22, 27, 36, 44, 57, 70] """ from sage.rings.integer_ring import ZZ + WLR = self.weight_lattice_realization() I = self.index_set() mg = self.highest_weight_vectors() @@ -353,9 +352,11 @@ def iter_by_deg(gens): # def iter_by_deg from sage.categories.finite_crystals import FiniteCrystals + if self in FiniteCrystals(): if q is None: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + q = PolynomialRing(ZZ, 'q').gen(0) if use_product: @@ -366,8 +367,7 @@ def iter_by_deg(gens): ret = P.zero() for v in self.highest_weight_vectors(): hw = v.weight() - ret += P.prod((1 - q**(rho+hw).scalar(ac)) / (1 - q**rho.scalar(ac)) - for ac in pos_coroots) + ret += P.prod((1 - q ** (rho + hw).scalar(ac)) / (1 - q ** rho.scalar(ac)) for ac in pos_coroots) # We do a cast since the result would otherwise live in the fraction field return P(ret) @@ -375,6 +375,7 @@ def iter_by_deg(gens): # If we're here, we may not be a finite crystal. # In fact, we're probably infinite. from sage.rings.lazy_series_ring import LazyPowerSeriesRing + if q is None: P = LazyPowerSeriesRing(ZZ, names='q') else: @@ -385,6 +386,7 @@ def iter_by_deg(gens): return ret from sage.rings.power_series_ring import PowerSeriesRing, PowerSeriesRing_generic + if q is None: q = PowerSeriesRing(ZZ, 'q', default_prec=prec).gen(0) P = q.parent() @@ -493,10 +495,10 @@ def digraph(self, subset=None, index_set=None, depth=None): return Crystals().parent_class.digraph(self, subset, index_set) if self not in Crystals().Finite() and depth is None: - raise NotImplementedError("crystals not known to be finite must" - " specify either the subset or depth") + raise NotImplementedError("crystals not known to be finite must" " specify either the subset or depth") from sage.graphs.digraph import DiGraph + if index_set is None: index_set = self.index_set() @@ -507,23 +509,22 @@ def digraph(self, subset=None, index_set=None, depth=None): while depth is None or rank < depth: recently_visited = set() for x in visited: - d.setdefault(x, {}) # does nothing if there's a default + d.setdefault(x, {}) # does nothing if there's a default for i in index_set: xfi = x.f(i) if xfi is not None: d[x][xfi] = i recently_visited.add(xfi) - if not recently_visited: # No new nodes, nothing more to do + if not recently_visited: # No new nodes, nothing more to do break rank += 1 visited = recently_visited G = DiGraph(d) from sage.graphs.dot2tex_utils import have_dot2tex + if have_dot2tex(): - G.set_latex_options(format='dot2tex', - edge_labels=True, - color_by_label=self.cartan_type()._index_set_coloring) + G.set_latex_options(format='dot2tex', edge_labels=True, color_by_label=self.cartan_type()._index_set_coloring) return G class ElementMethods: @@ -636,9 +637,9 @@ def string_parameters(self, word=None): """ if word is None: if not self.cartan_type().is_finite(): - raise ValueError("the word must be specified because" - " the Weyl group is not finite") + raise ValueError("the word must be specified because" " the Weyl group is not finite") from sage.combinat.root_system.weyl_group import WeylGroup + word = WeylGroup(self.cartan_type()).long_element().reduced_word() x = self params = [] @@ -657,6 +658,7 @@ class TensorProducts(TensorProductsCategory): The category of highest weight crystals constructed by tensor product of highest weight crystals. """ + @cached_method def extra_super_categories(self): """ @@ -671,6 +673,7 @@ class ParentMethods: """ Implement operations on tensor products of crystals. """ + @cached_method def highest_weight_vectors(self) -> tuple: r""" @@ -784,20 +787,25 @@ def highest_weight_vectors_iterator(self): except (TypeError, NotImplementedError, AttributeError): raise NotImplementedError("not implemented for infinite crystals") from sage.categories.regular_crystals import RegularCrystals + if self in RegularCrystals: + def hw_test(b2, i, d): return d < 0 + else: + def hw_test(b2, i, d): return d < 0 and b2.e(i) is not None + T_len = [len(elts) for elts in T_elts] m = len(self.crystals) - 1 for b in self.crystals[-1].highest_weight_vectors(): T_pos = m - 1 # current tensor position - T_cur = [0]*m # index of current element for each tensor position - path = [None]*m + [b] + T_cur = [0] * m # index of current element for each tensor position + path = [None] * m + [b] # cache phi for path up to current tensor position - T_phi = [None]*(m-1) + [{i: b.phi(i) for i in I}] + T_phi = [None] * (m - 1) + [{i: b.phi(i) for i in I}] while T_pos < m: if T_cur[T_pos] == T_len[T_pos]: T_cur[T_pos] = 0 @@ -825,11 +833,11 @@ def hw_test(b2, i, d): T_pos -= 1 # In the regular case, the next line is simply # T_phi[T_pos] = {i: b2.phi(i) + b1_phi_minus_b2_epsilon[i] for i in I} - T_phi[T_pos] = {i: b2.phi(i) + max(0, b1_phi_minus_b2_epsilon[i]) - for i in I} + T_phi[T_pos] = {i: b2.phi(i) + max(0, b1_phi_minus_b2_epsilon[i]) for i in I} else: yield self.element_class(self, path) + ############################################################################### ## Morphisms @@ -857,9 +865,8 @@ class HighestWeightCrystalMorphism(CrystalMorphismByGenerators): - ``check`` -- boolean (default: ``True``); check if the crystal morphism is valid """ - def __init__(self, parent, on_gens, cartan_type=None, - virtualization=None, scaling_factors=None, - gens=None, check=True): + + def __init__(self, parent, on_gens, cartan_type=None, virtualization=None, scaling_factors=None, gens=None, check=True): """ Construct a crystal morphism. @@ -889,9 +896,7 @@ def __init__(self, parent, on_gens, cartan_type=None, self._hw_gens = all(x.is_highest_weight(I) for x in gens) else: self._hw_gens = False - CrystalMorphismByGenerators.__init__(self, parent, on_gens, cartan_type, - virtualization, scaling_factors, - gens, check) + CrystalMorphismByGenerators.__init__(self, parent, on_gens, cartan_type, virtualization, scaling_factors, gens, check) def _call_(self, x): """ @@ -947,7 +952,7 @@ def _call_(self, x): s = [] sf = self._scaling_factors[i] for j in self._virtualization[i]: - s += [j]*sf + s += [j] * sf cur = cur.f_string(s) return cur @@ -962,6 +967,7 @@ class HighestWeightCrystalHomset(CrystalHomset): See :class:`sage.categories.crystals.CrystalHomset` for more information. """ + def __init__(self, X, Y, category=None): """ Initialize ``self``. diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index 8938ab700bd..2bd43702338 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -86,12 +86,9 @@ _cache: TripleDict[SageObject, SageObject, Category | None, Homset] = TripleDict(weak_values=True) -def Hom[DomainElementT: Parent, CodomainElementT: Parent]( - X: DomainElementT, - Y: CodomainElementT, - category: Category | None = None, - check: bool = True, -) -> Homset[DomainElementT, CodomainElementT]: +def Hom[ + DomainElementT: Parent, CodomainElementT: Parent +](X: DomainElementT, Y: CodomainElementT, category: Category | None = None, check: bool = True,) -> Homset[DomainElementT, CodomainElementT]: """ Create the space of homomorphisms from X to Y in the category ``category``. @@ -614,6 +611,7 @@ class Homset[DomainElementT: Parent, CodomainElementT: Parent](Set_generic): sage: loads(dumps(H)) == H True """ + def __init__( self, X: DomainElementT, @@ -690,8 +688,7 @@ def __init__( # See also #15801. base = X.base_ring() - Parent.__init__(self, base=base, - category=category.Endsets() if X is Y else category.Homsets()) + Parent.__init__(self, base=base, category=category.Endsets() if X is Y else category.Homsets()) def __reduce__( self, @@ -759,8 +756,7 @@ def _repr_(self) -> str: sage: Hom(ZZ^2, QQ, category=Sets())._repr_() # needs sage.modules 'Set of Morphisms from Ambient free module of rank 2 over the principal ideal domain Integer Ring to Rational Field in Category of sets' """ - return "Set of Morphisms from {} to {} in {}".format( - self._domain, self._codomain, self.__category) + return "Set of Morphisms from {} to {} in {}".format(self._domain, self._codomain, self.__category) def __hash__(self) -> int: """ @@ -1109,9 +1105,7 @@ def __eq__(self, other) -> bool: """ if not isinstance(other, Homset): return False - return (self._domain == other._domain - and self._codomain == other._codomain - and self.__category == other.__category) + return self._domain == other._domain and self._codomain == other._codomain and self.__category == other.__category def __ne__(self, other) -> bool: """ @@ -1174,7 +1168,7 @@ def natural_map(self): from Univariate Polynomial Ring in t over Rational Field to Univariate Polynomial Ring in t over Finite Field of size 3 not defined """ - return morphism.FormalCoercionMorphism(self) # good default in many cases + return morphism.FormalCoercionMorphism(self) # good default in many cases def identity(self): """ @@ -1277,8 +1271,7 @@ def reversed(self) -> Homset[CodomainElementT, DomainElementT]: sage: type(H.reversed()) """ - return Hom(self.codomain(), self.domain(), - category=self.homset_category()) + return Hom(self.codomain(), self.domain(), category=self.homset_category()) # Really needed??? diff --git a/src/sage/categories/homsets.py b/src/sage/categories/homsets.py index 2116ef1fab9..3c3bea9dd55 100644 --- a/src/sage/categories/homsets.py +++ b/src/sage/categories/homsets.py @@ -1,6 +1,7 @@ r""" Homset categories """ + # **************************************************************************** # Copyright (C) 2014 Nicolas M. Thiery # @@ -110,8 +111,7 @@ def default_super_categories(cls, category): [Category of homsets] """ if category.full_super_categories(): - return Category.join([getattr(cat, cls._functor_category)() - for cat in category.full_super_categories()]) + return Category.join([getattr(cat, cls._functor_category)() for cat in category.full_super_categories()]) functor_category = getattr(category.__class__, cls._functor_category) if isinstance(functor_category, type) and issubclass(functor_category, Category): return Homsets() @@ -128,8 +128,8 @@ def _test_homsets_category(self, **options): sage: Sets().Homsets()._test_homsets_category() """ # TODO: remove if unneeded - #from sage.categories.objects import Objects - #from sage.categories.sets_cat import Sets + # from sage.categories.objects import Objects + # from sage.categories.sets_cat import Sets tester = self._tester(**options) tester.assertTrue(self.is_subcategory(Category.join(self.base_category().structure()).Homsets())) tester.assertTrue(self.is_subcategory(Homsets())) @@ -147,8 +147,9 @@ def base(self): Integer Ring """ from sage.categories.category_types import Category_over_base + for C in self._all_super_categories_proper: - if isinstance(C,Category_over_base): + if isinstance(C, Category_over_base): return C.base() raise AttributeError("This hom category has no base") @@ -193,6 +194,7 @@ class HomsetsOf(HomsetsCategory): sage: TestSuite(C).run(skip=['_test_category_graph']) sage: TestSuite(C).run() """ + _base_category_class = (Category,) def _repr_object_names(self): @@ -264,6 +266,7 @@ class Homsets(Category_singleton): This is tested in :meth:`HomsetsCategory._test_homsets_category`. """ + def super_categories(self): """ Return the super categories of ``self``. @@ -275,6 +278,7 @@ def super_categories(self): Category of homsets """ from .sets_cat import Sets + return [Sets()] class SubcategoryMethods: @@ -308,6 +312,7 @@ class Endset(CategoryWithAxiom): sage: Homsets().Endset() Category of endsets """ + def extra_super_categories(self): """ Implement the fact that endsets are monoids. @@ -321,6 +326,7 @@ def extra_super_categories(self): [Category of monoids] """ from .monoids import Monoids + return [Monoids()] class ParentMethods: diff --git a/src/sage/categories/hopf_algebras.py b/src/sage/categories/hopf_algebras.py index add9738b705..1ccce1ea05a 100644 --- a/src/sage/categories/hopf_algebras.py +++ b/src/sage/categories/hopf_algebras.py @@ -1,6 +1,7 @@ r""" Hopf algebras """ + # **************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # Nicolas M. Thiery @@ -33,6 +34,7 @@ class HopfAlgebras(Category_over_base_ring): sage: TestSuite(HopfAlgebras(ZZ)).run() """ + def super_categories(self): """ EXAMPLES:: @@ -104,6 +106,7 @@ class Morphism(Category): """ The category of Hopf algebra morphisms. """ + pass class Super(SuperModulesCategory): @@ -116,6 +119,7 @@ class Super(SuperModulesCategory): algebra with a `\ZZ/2\ZZ` grading due to the signed bialgebra compatibility conditions. """ + def dual(self): """ Return the dual category. @@ -148,6 +152,7 @@ class TensorProducts(TensorProductsCategory): """ The category of Hopf algebras constructed by tensor product of Hopf algebras """ + @cached_method def extra_super_categories(self): """ diff --git a/src/sage/categories/hopf_algebras_with_basis.py b/src/sage/categories/hopf_algebras_with_basis.py index 4130f17adb8..ed3bbf3981d 100644 --- a/src/sage/categories/hopf_algebras_with_basis.py +++ b/src/sage/categories/hopf_algebras_with_basis.py @@ -1,6 +1,7 @@ r""" Hopf algebras with basis """ + # **************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # Copyright (C) 2008-2011 Nicolas M. Thiery @@ -135,33 +136,30 @@ def example(self, G=None): """ from sage.categories.examples.hopf_algebras_with_basis import MyGroupAlgebra from sage.groups.perm_gps.permgroup_named import DihedralGroup + if G is None: G = DihedralGroup(3) return MyGroupAlgebra(self.base_ring(), G) -# This is only correct in the finite dimensional / graded case -# def dual(self): -# """ -# Returns the dual category + # This is only correct in the finite dimensional / graded case + # def dual(self): + # """ + # Returns the dual category -# EXAMPLES: + # EXAMPLES: -# The category of Hopf algebras over any field is self dual:: + # The category of Hopf algebras over any field is self dual:: -# sage: C = HopfAlgebrasWithBasis(QQ) -# sage: C.dual() -# Category of Hopf algebras with basis over Rational Field -# """ -# return self + # sage: C = HopfAlgebrasWithBasis(QQ) + # sage: C.dual() + # Category of Hopf algebras with basis over Rational Field + # """ + # return self - FiniteDimensional = LazyImport('sage.categories.finite_dimensional_hopf_algebras_with_basis', - 'FiniteDimensionalHopfAlgebrasWithBasis') - Filtered = LazyImport('sage.categories.filtered_hopf_algebras_with_basis', - 'FilteredHopfAlgebrasWithBasis') - Graded = LazyImport('sage.categories.graded_hopf_algebras_with_basis', - 'GradedHopfAlgebrasWithBasis') - Super = LazyImport('sage.categories.super_hopf_algebras_with_basis', - 'SuperHopfAlgebrasWithBasis') + FiniteDimensional = LazyImport('sage.categories.finite_dimensional_hopf_algebras_with_basis', 'FiniteDimensionalHopfAlgebrasWithBasis') + Filtered = LazyImport('sage.categories.filtered_hopf_algebras_with_basis', 'FilteredHopfAlgebrasWithBasis') + Graded = LazyImport('sage.categories.graded_hopf_algebras_with_basis', 'GradedHopfAlgebrasWithBasis') + Super = LazyImport('sage.categories.super_hopf_algebras_with_basis', 'SuperHopfAlgebrasWithBasis') class ParentMethods: @@ -221,8 +219,7 @@ def antipode(self): """ if self.antipode_on_basis is not NotImplemented: # Should give the information that this is an anti-morphism of algebra - return self._module_morphism(self.antipode_on_basis, - codomain=self) + return self._module_morphism(self.antipode_on_basis, codomain=self) if hasattr(self, "antipode_by_coercion"): return self.antipode_by_coercion @@ -260,11 +257,9 @@ def _test_antipode(self, **options): S = self.antipode - IS = lambda x: self.sum(c * self.monomial(t1) * S(self.monomial(t2)) - for ((t1, t2), c) in x.coproduct()) + IS = lambda x: self.sum(c * self.monomial(t1) * S(self.monomial(t2)) for ((t1, t2), c) in x.coproduct()) - SI = lambda x: self.sum(c * S(self.monomial(t1)) * self.monomial(t2) - for ((t1, t2), c) in x.coproduct()) + SI = lambda x: self.sum(c * S(self.monomial(t1)) * self.monomial(t2) for ((t1, t2), c) in x.coproduct()) for x in tester.some_elements(): diff --git a/src/sage/categories/infinite_enumerated_sets.py b/src/sage/categories/infinite_enumerated_sets.py index e27008a30ec..15ad57d323f 100644 --- a/src/sage/categories/infinite_enumerated_sets.py +++ b/src/sage/categories/infinite_enumerated_sets.py @@ -5,6 +5,7 @@ - Florent Hivert (2009-11): initial revision. """ + # **************************************************************************** # Copyright (C) 2009 Florent Hivert # @@ -88,7 +89,8 @@ def list(self): NotImplementedError: cannot list an infinite set """ raise NotImplementedError("cannot list an infinite set") - _list_default = list # needed by the check system. + + _list_default = list # needed by the check system. def _test_enumerated_set_iter_cardinality(self, **options): """ @@ -110,5 +112,6 @@ def _test_enumerated_set_iter_cardinality(self, **options): """ tester = self._tester(**options) from sage.rings.infinity import infinity + tester.assertEqual(self.cardinality(), infinity) tester.assertRaises(NotImplementedError, self.list) diff --git a/src/sage/categories/integral_domains.py b/src/sage/categories/integral_domains.py index 65653640002..63299c062be 100644 --- a/src/sage/categories/integral_domains.py +++ b/src/sage/categories/integral_domains.py @@ -22,6 +22,7 @@ Note that this raises a :exc:`NotImplementedError` if the answer is not known. """ + # **************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2012 Nicolas M. Thiery @@ -35,6 +36,7 @@ from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.category_singleton import Category_contains_method_by_parent_class from sage.categories.domains import Domains + lazy_import('sage.categories.fields', 'Fields') @@ -60,6 +62,7 @@ class IntegralDomains(CategoryWithAxiom): sage: TestSuite(C).run() """ + _base_category_class_and_axiom = (Domains, "Commutative") def __contains__(self, x) -> bool: @@ -171,6 +174,7 @@ def localization(self, additional_units, names=None, normalize=True, category=No True """ from sage.rings.localization import Localization + return Localization(self, additional_units, names=names, normalize=normalize, category=category) def _test_fraction_field(self, **options): diff --git a/src/sage/categories/isomorphic_objects.py b/src/sage/categories/isomorphic_objects.py index 8bcb55db743..43c7519e668 100644 --- a/src/sage/categories/isomorphic_objects.py +++ b/src/sage/categories/isomorphic_objects.py @@ -5,12 +5,13 @@ - Nicolas M. Thiery (2010): initial revision """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2009 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.category import Category from sage.categories.covariant_functorial_construction import RegressiveCovariantConstructionCategory @@ -68,5 +69,4 @@ def default_super_categories(cls, category): Category of quotients of semigroups and Category of isomorphic objects of sets """ - return Category.join([category.Subobjects(), category.Quotients(), - super().default_super_categories(category)]) + return Category.join([category.Subobjects(), category.Quotients(), super().default_super_categories(category)]) diff --git a/src/sage/categories/j_trivial_semigroups.py b/src/sage/categories/j_trivial_semigroups.py index cb819b79f0e..5b6f4601e6b 100644 --- a/src/sage/categories/j_trivial_semigroups.py +++ b/src/sage/categories/j_trivial_semigroups.py @@ -1,7 +1,8 @@ r""" J-trivial semigroups """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2016 Nicolas M. Thiéry # # This program is free software: you can redistribute it and/or modify @@ -9,7 +10,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.semigroups import Semigroups diff --git a/src/sage/categories/kac_moody_algebras.py b/src/sage/categories/kac_moody_algebras.py index 52f738243b8..e08dd1523ff 100644 --- a/src/sage/categories/kac_moody_algebras.py +++ b/src/sage/categories/kac_moody_algebras.py @@ -24,6 +24,7 @@ class KacMoodyAlgebras(Category_over_base_ring): """ Category of Kac-Moody algebras. """ + @cached_method def super_categories(self): """ @@ -52,6 +53,7 @@ def example(self, n=2): Lie algebra of ['A', 4] in the Chevalley basis """ from sage.algebras.lie_algebras.classical_lie_algebra import LieAlgebraChevalleyBasis + return LieAlgebraChevalleyBasis(self.base_ring(), ['A', n]) class ParentMethods: @@ -78,4 +80,5 @@ def weyl_group(self): Weyl Group of type ['A', 2] (as a matrix group acting on the ambient space) """ from sage.combinat.root_system.weyl_group import WeylGroup + return WeylGroup(self.cartan_type()) diff --git a/src/sage/categories/kahler_algebras.py b/src/sage/categories/kahler_algebras.py index d1286ff7574..0e2cd7c8fe6 100644 --- a/src/sage/categories/kahler_algebras.py +++ b/src/sage/categories/kahler_algebras.py @@ -5,6 +5,7 @@ - Shriya M """ + # **************************************************************************** # Copyright (C) 2024 Shriya M <25shriya at gmail.com> # @@ -67,6 +68,7 @@ class KahlerAlgebras(Category_over_base_ring): sage: C = KahlerAlgebras(QQ) sage: TestSuite(C).run() """ + def super_categories(self): r""" Return the super categories of ``self``. @@ -184,7 +186,7 @@ def hodge_riemann_relations(self, k): ValueError: k must be less than r/2 < 2 """ r = self.top_degree() - if k > (r/2): + if k > (r / 2): raise ValueError("k must be less than r/2 < 2") basis_k = [] lefschetz_el = self.lefschetz_element() @@ -192,7 +194,7 @@ def hodge_riemann_relations(self, k): if b.homogeneous_degree() == k: basis_k.append(b) coeff = [] - for i,el in enumerate(basis_k): + for i, el in enumerate(basis_k): for j in range(i, len(basis_k)): - coeff.append((el * (lefschetz_el ** (r-(2*k)) * basis_k[j])).degree()) + coeff.append((el * (lefschetz_el ** (r - (2 * k)) * basis_k[j])).degree()) return QuadraticForm(self.base_ring(), len(basis_k), coeff) diff --git a/src/sage/categories/l_trivial_semigroups.py b/src/sage/categories/l_trivial_semigroups.py index ef4a8c41016..1894982e602 100644 --- a/src/sage/categories/l_trivial_semigroups.py +++ b/src/sage/categories/l_trivial_semigroups.py @@ -1,7 +1,8 @@ r""" L-trivial semigroups """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2016 Nicolas M. Thiéry # # This program is free software: you can redistribute it and/or modify @@ -9,7 +10,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.magmas import Magmas diff --git a/src/sage/categories/lambda_bracket_algebras.py b/src/sage/categories/lambda_bracket_algebras.py index e6529429b2b..32c2be3c010 100644 --- a/src/sage/categories/lambda_bracket_algebras.py +++ b/src/sage/categories/lambda_bracket_algebras.py @@ -6,7 +6,7 @@ - Reimundo Heluani (2019-10-05): Initial implementation. """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2019 Reimundo Heluani # # This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.category_types import Category_over_base_ring from sage.categories.commutative_rings import CommutativeRings @@ -34,6 +34,7 @@ class LambdaBracketAlgebras(Category_over_base_ring): This is an abstract base category for Lie conformal algebras and super Lie conformal algebras. """ + @staticmethod def __classcall_private__(cls, R, check=True): r""" @@ -124,8 +125,7 @@ def ideal(self, *gens, **kwds): ... NotImplementedError: ideals of Lie Conformal algebras are not implemented yet """ - raise NotImplementedError("ideals of Lie Conformal algebras are " - "not implemented yet") + raise NotImplementedError("ideals of Lie Conformal algebras are " "not implemented yet") class ElementMethods: @@ -211,7 +211,7 @@ def nproduct(self, rhs, n): sage: E.nproduct(F, 1) B['K'] """ - return self._nproduct_(rhs,n) + return self._nproduct_(rhs, n) def _nproduct_(self, rhs, n): r""" @@ -238,7 +238,7 @@ def _nproduct_(self, rhs, n): B['K'] """ if n >= 0: - return self.bracket(rhs).get(n,self.parent().zero()) + return self.bracket(rhs).get(n, self.parent().zero()) raise NotImplementedError("vertex algebras are not implemented") @abstract_method @@ -270,9 +270,6 @@ def T(self, n=1): 0 """ - WithBasis = LazyImport("sage.categories.lambda_bracket_algebras_with_basis", - "LambdaBracketAlgebrasWithBasis", "WithBasis") + WithBasis = LazyImport("sage.categories.lambda_bracket_algebras_with_basis", "LambdaBracketAlgebrasWithBasis", "WithBasis") - FinitelyGeneratedAsLambdaBracketAlgebra = LazyImport( - 'sage.categories.finitely_generated_lambda_bracket_algebras', - 'FinitelyGeneratedLambdaBracketAlgebras') + FinitelyGeneratedAsLambdaBracketAlgebra = LazyImport('sage.categories.finitely_generated_lambda_bracket_algebras', 'FinitelyGeneratedLambdaBracketAlgebras') diff --git a/src/sage/categories/lambda_bracket_algebras_with_basis.py b/src/sage/categories/lambda_bracket_algebras_with_basis.py index 685abf2dacd..220fc8eecb1 100644 --- a/src/sage/categories/lambda_bracket_algebras_with_basis.py +++ b/src/sage/categories/lambda_bracket_algebras_with_basis.py @@ -6,7 +6,7 @@ - Reimundo Heluani (2020-08-21): Initial implementation. """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2020 Reimundo Heluani # # This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.graded_modules import GradedModulesCategory @@ -29,6 +29,7 @@ class LambdaBracketAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): sage: LieConformalAlgebras(QQbar).WithBasis() # needs sage.rings.number_field Category of Lie conformal algebras with basis over Algebraic Field """ + class ElementMethods: def index(self): @@ -53,8 +54,7 @@ def index(self): if self.is_zero(): return None if not self.is_monomial(): - raise ValueError("index can only be computed for " - "monomials, got {}".format(self)) + raise ValueError("index can only be computed for " "monomials, got {}".format(self)) return next(iter(self.monomial_coefficients())) @@ -76,6 +76,7 @@ class FinitelyGeneratedAsLambdaBracketAlgebra(CategoryWithAxiom_over_base_ring): sage: C1 is C2 True """ + class Graded(GradedModulesCategory): """ The category of H-graded finitely generated lambda bracket @@ -88,6 +89,7 @@ class Graded(GradedModulesCategory): Category of H-graded finitely generated Lie conformal algebras with basis over Algebraic Field """ + class ParentMethods: def degree_on_basis(self, m): diff --git a/src/sage/categories/lattice_posets.py b/src/sage/categories/lattice_posets.py index d7dc4e8d524..c041f52e9ef 100644 --- a/src/sage/categories/lattice_posets.py +++ b/src/sage/categories/lattice_posets.py @@ -1,6 +1,7 @@ r""" Lattice posets """ + # **************************************************************************** # Copyright (C) 2011 Nicolas M. Thiéry # @@ -42,6 +43,7 @@ class LatticePosets(Category): sage: C = LatticePosets() sage: TestSuite(C).run() """ + @cached_method def super_categories(self) -> list: r""" @@ -208,8 +210,7 @@ def Extremal(self): """ return self._with_axiom("Extremal") - Finite = LazyImport('sage.categories.finite_lattice_posets', - 'FiniteLatticePosets') + Finite = LazyImport('sage.categories.finite_lattice_posets', 'FiniteLatticePosets') class Extremal(CategoryWithAxiom): """ @@ -224,6 +225,7 @@ class Extremal(CategoryWithAxiom): [Category of finite lattice posets, Category of extremal lattice posets] """ + class ParentMethods: def is_extremal(self) -> bool: """ @@ -248,6 +250,7 @@ class Trim(CategoryWithAxiom): [Category of finite lattice posets, Category of trim lattice posets] """ + @cached_method def extra_super_categories(self) -> list: r""" @@ -288,6 +291,7 @@ class Semidistributive(CategoryWithAxiom): [Category of finite lattice posets, Category of semidistributive lattice posets] """ + class ParentMethods: def is_semidistributive(self) -> bool: """ @@ -444,15 +448,14 @@ def spine(self): Category of facade finite enumerated distributive lattices """ from sage.combinat.posets.lattices import LatticePoset + subset_H, _ = self._hasse_diagram.spine() subset = [self._vertex_to_element(v) for v in subset_H] H = self.hasse_diagram() - covers = [(x, y) for x in subset for y in H.neighbors_in(x) - if y in subset] + covers = [(x, y) for x in subset for y in H.neighbors_in(x) if y in subset] cat = LatticePosets().Finite().Distributive() - return LatticePoset([subset, covers], - cover_relations=True, category=cat) + return LatticePoset([subset, covers], cover_relations=True, category=cat) class CongruenceUniform(CategoryWithAxiom): """ @@ -466,6 +469,7 @@ class CongruenceUniform(CategoryWithAxiom): [Category of finite lattice posets, Category of congruence uniform lattice posets] """ + @cached_method def extra_super_categories(self) -> list: r""" @@ -506,6 +510,7 @@ class Stone(CategoryWithAxiom): [Category of finite distributive lattices, Category of stone lattice posets] """ + @cached_method def extra_super_categories(self) -> list: r""" @@ -546,6 +551,7 @@ class ChainGraded(CategoryWithAxiom): [Category of finite lattice posets, Category of chain graded lattice posets] """ + class ParentMethods: def is_graded(self) -> bool: """ @@ -561,6 +567,7 @@ def is_graded(self) -> bool: # the following was moved out of the main class + class DistributiveLattices(CategoryWithAxiom): """ The category of distributive lattices. @@ -580,8 +587,8 @@ class DistributiveLattices(CategoryWithAxiom): sage: LatticePosets().Distributive() is DistributiveLattices() True """ - _base_category_class_and_axiom = (LatticePosets.Trim, - "ChainGraded") + + _base_category_class_and_axiom = (LatticePosets.Trim, "ChainGraded") @cached_method def extra_super_categories(self) -> list: diff --git a/src/sage/categories/left_modules.py b/src/sage/categories/left_modules.py index 51de3497a53..cc294064274 100644 --- a/src/sage/categories/left_modules.py +++ b/src/sage/categories/left_modules.py @@ -1,18 +1,19 @@ r""" Left modules """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category_types import Category_over_base_ring from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups -#?class LeftModules(Category_over_base_rng): +# ?class LeftModules(Category_over_base_rng): class LeftModules(Category_over_base_ring): """ The category of left modules diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index 2e21344cacf..61f812fb73d 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -6,7 +6,7 @@ - Travis Scrimshaw (07-15-2013): Initial implementation """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2013 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method @@ -76,6 +76,7 @@ class LieAlgebras(Category_over_base_ring): Many of these tests should use Lie algebras that are not the minimal example and need to be added after :issue:`16820` (and :issue:`16823`). """ + @cached_method def super_categories(self): """ @@ -109,9 +110,7 @@ def Nilpotent(self): """ return self._with_axiom("Nilpotent") - Graded = LazyImport('sage.categories.graded_lie_algebras', - 'GradedLieAlgebras', - as_name='Graded') + Graded = LazyImport('sage.categories.graded_lie_algebras', 'GradedLieAlgebras', as_name='Graded') # TODO: Find some way to do this without copying most of the logic. def _repr_object_names(self): @@ -134,7 +133,7 @@ def _repr_object_names(self): base = self.base() if isinstance(base, Category): if isinstance(base, JoinCategory): - name = '('+' and '.join(C._repr_object_names() for C in base.super_categories())+')' + name = '(' + ' and '.join(C._repr_object_names() for C in base.super_categories()) + ')' else: name = base._repr_object_names() else: @@ -164,16 +163,16 @@ def example(self, gens=None): if gens is None: from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra from sage.rings.rational_field import QQ + gens = SymmetricGroupAlgebra(QQ, 3).algebra_generators() from sage.categories.examples.lie_algebras import Example + return Example(gens) - WithBasis = LazyImport('sage.categories.lie_algebras_with_basis', - 'LieAlgebrasWithBasis', as_name='WithBasis') + WithBasis = LazyImport('sage.categories.lie_algebras_with_basis', 'LieAlgebrasWithBasis', as_name='WithBasis') class FiniteDimensional(CategoryWithAxiom_over_base_ring): - WithBasis = LazyImport('sage.categories.finite_dimensional_lie_algebras_with_basis', - 'FiniteDimensionalLieAlgebrasWithBasis', as_name='WithBasis') + WithBasis = LazyImport('sage.categories.finite_dimensional_lie_algebras_with_basis', 'FiniteDimensionalLieAlgebrasWithBasis', as_name='WithBasis') def extra_super_categories(self): """ @@ -209,6 +208,7 @@ class Nilpotent(CategoryWithAxiom_over_base_ring): sage: C = LieAlgebras(QQ).Nilpotent() sage: TestSuite(C).run() """ + class ParentMethods: @abstract_method def step(self): @@ -235,8 +235,8 @@ def is_nilpotent(self): return True class ParentMethods: - #@abstract_method - #def lie_algebra_generators(self): + # @abstract_method + # def lie_algebra_generators(self): # """ # Return the generators of ``self`` as a Lie algebra. # """ @@ -488,8 +488,8 @@ def subalgebra(self, gens, names=None, index_set=None, category=None): NotImplementedError: subalgebras not yet implemented: see #17416 """ raise NotImplementedError("subalgebras not yet implemented: see #17416") - #from sage.algebras.lie_algebras.subalgebra import LieSubalgebra - #return LieSubalgebra(gens, names, index_set, category) + # from sage.algebras.lie_algebras.subalgebra import LieSubalgebra + # return LieSubalgebra(gens, names, index_set, category) def ideal(self, *gens, **kwds): r""" @@ -517,13 +517,13 @@ def ideal(self, *gens, **kwds): NotImplementedError: ideals not yet implemented: see #16824 """ raise NotImplementedError("ideals not yet implemented: see #16824") - #from sage.algebras.lie_algebras.ideal import LieIdeal - #if len(gens) == 1 and isinstance(gens[0], (list, tuple)): + # from sage.algebras.lie_algebras.ideal import LieIdeal + # if len(gens) == 1 and isinstance(gens[0], (list, tuple)): # gens = gens[0] - #names = kwds.pop("names", None) - #index_set = kwds.pop("index_set", None) - #category = kwds.pop("category", None) - #return LieIdeal(gens, names, index_set, category) + # names = kwds.pop("names", None) + # index_set = kwds.pop("index_set", None) + # category = kwds.pop("category", None) + # return LieIdeal(gens, names, index_set, category) def is_ideal(self, A): """ @@ -538,8 +538,8 @@ def is_ideal(self, A): if A == self: return True raise NotImplementedError("ideals not yet implemented: see #16824") - #from sage.algebras.lie_algebras.ideal import LieIdeal - #return isinstance(self, LieIdeal) and self._ambient is A + # from sage.algebras.lie_algebras.ideal import LieIdeal + # return isinstance(self, LieIdeal) and self._ambient is A @abstract_method(optional=True) def killing_form(self, x, y): @@ -706,9 +706,9 @@ def bch(self, X, Y, prec=None): sage: L.options._reset() # reset the printing options """ if self not in LieAlgebras.Nilpotent and prec is None: - raise ValueError("the Lie algebra is not known to be nilpotent," - " so you must specify the precision") + raise ValueError("the Lie algebra is not known to be nilpotent," " so you must specify the precision") from sage.algebras.lie_algebras.bch import bch_iterator + if prec is None: return self.sum(Z for Z in bch_iterator(X, Y)) bch = bch_iterator(X, Y) @@ -745,6 +745,7 @@ def trivial_representation(self): strictly upper triangular matrices over Rational Field """ from sage.algebras.lie_algebras.representation import TrivialRepresentation + return TrivialRepresentation(self) def representation(self, f=None, index_set=None, on_basis=False, **kwargs): @@ -789,6 +790,7 @@ def representation(self, f=None, index_set=None, on_basis=False, **kwargs): if f is None and on_basis is False and index_set is None: return self.trivial_representation(**kwargs) from sage.algebras.lie_algebras.representation import RepresentationByMorphism + return RepresentationByMorphism(self, f, index_set, on_basis, **kwargs) def _test_jacobi_identity(self, **options): @@ -819,9 +821,7 @@ def _test_jacobi_identity(self, **options): """ tester = self._tester(**options) elts = tester.some_elements() - jacobi = lambda x, y, z: self.bracket(x, self.bracket(y, z)) + \ - self.bracket(y, self.bracket(z, x)) + \ - self.bracket(z, self.bracket(x, y)) + jacobi = lambda x, y, z: self.bracket(x, self.bracket(y, z)) + self.bracket(y, self.bracket(z, x)) + self.bracket(z, self.bracket(x, y)) zero = self.zero() for x in elts: for y in elts: @@ -901,13 +901,12 @@ def _test_distributivity(self, **options): tester = self._tester(**options) S = tester.some_elements() from sage.misc.misc import some_tuples - for x,y,z in some_tuples(S, 3, tester._max_runs): + + for x, y, z in some_tuples(S, 3, tester._max_runs): # left distributivity - tester.assertEqual(self.bracket(x, (y + z)), - self.bracket(x, y) + self.bracket(x, z)) + tester.assertEqual(self.bracket(x, (y + z)), self.bracket(x, y) + self.bracket(x, z)) # right distributivity - tester.assertEqual(self.bracket((x + y), z), - self.bracket(x, z) + self.bracket(y, z)) + tester.assertEqual(self.bracket((x + y), z), self.bracket(x, z) + self.bracket(y, z)) class ElementMethods: @coerce_binop @@ -1048,6 +1047,7 @@ class LiftMorphism(Morphism): The natural lifting morphism from a Lie algebra to its enveloping algebra. """ + def __init__(self, domain, codomain): """ Initialize ``self``. diff --git a/src/sage/categories/lie_algebras_with_basis.py b/src/sage/categories/lie_algebras_with_basis.py index 703685668c6..7e31bf66aaa 100644 --- a/src/sage/categories/lie_algebras_with_basis.py +++ b/src/sage/categories/lie_algebras_with_basis.py @@ -6,7 +6,7 @@ - Travis Scrimshaw (07-15-2013): Initial implementation """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2013-2024 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.abstract_method import abstract_method from sage.misc.lazy_import import LazyImport @@ -26,6 +26,7 @@ class LieAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): """ Category of Lie algebras with a basis. """ + _base_category_class_and_axiom = (LieAlgebras, "WithBasis") def example(self, gens=None): @@ -48,13 +49,13 @@ def example(self, gens=None): """ if gens is None: from sage.combinat.partition import Partitions + gens = Partitions() from sage.categories.examples.lie_algebras_with_basis import Example + return Example(self.base_ring(), gens) - Graded = LazyImport('sage.categories.graded_lie_algebras_with_basis', - 'GradedLieAlgebrasWithBasis', - as_name='Graded') + Graded = LazyImport('sage.categories.graded_lie_algebras_with_basis', 'GradedLieAlgebrasWithBasis', as_name='Graded') class ParentMethods: def _basis_key(self, x): @@ -101,6 +102,7 @@ def module(self): Free module generated by Partitions over Rational Field """ from sage.combinat.free_module import CombinatorialFreeModule + try: # Try to see if it has an indexing set return CombinatorialFreeModule(self.base_ring(), self.basis().keys()) @@ -158,8 +160,8 @@ def pbw_basis(self, basis_key=None, **kwds): sage: L = lie_algebras.sl(QQ, 2) # needs sage.combinat sage.modules sage: PBW = L.pbw_basis() # needs sage.combinat sage.modules """ - from sage.algebras.lie_algebras.poincare_birkhoff_witt \ - import PoincareBirkhoffWittBasis + from sage.algebras.lie_algebras.poincare_birkhoff_witt import PoincareBirkhoffWittBasis + return PoincareBirkhoffWittBasis(self, basis_key, **kwds) poincare_birkhoff_witt_basis = pbw_basis @@ -193,8 +195,7 @@ def term(ml, mr): return P.bracket_on_basis(ml, mr) return -P.bracket_on_basis(mr, ml) - return P.sum(cl * cr * term(ml, mr) - for ml, cl in self for mr, cr in y) + return P.sum(cl * cr * term(ml, mr) for ml, cl in self for mr, cr in y) def to_vector(self, order=None): """ diff --git a/src/sage/categories/lie_conformal_algebras.py b/src/sage/categories/lie_conformal_algebras.py index 2d116662c03..84e78915aa8 100644 --- a/src/sage/categories/lie_conformal_algebras.py +++ b/src/sage/categories/lie_conformal_algebras.py @@ -114,7 +114,7 @@ - Reimundo Heluani (2019-10-05): Initial implementation. """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2019 Reimundo Heluani # # This program is free software: you can redistribute it and/or modify @@ -122,7 +122,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.category_types import Category_over_base_ring from sage.categories.lambda_bracket_algebras import LambdaBracketAlgebras @@ -174,6 +174,7 @@ class LieConformalAlgebras(Category_over_base_ring): ValueError: base must be a commutative ring got Quaternion Algebra (-1, -1) with base ring Rational Field """ + @cached_method def super_categories(self): """ @@ -227,6 +228,7 @@ def example(self): from sage.algebras.lie_conformal_algebras.virasoro_lie_conformal_algebra import ( VirasoroLieConformalAlgebra, ) + return VirasoroLieConformalAlgebra(self.base_ring()) def _repr_object_names(self): @@ -287,27 +289,27 @@ def _test_jacobi(self, **options): S = tester.some_elements() from sage.arith.misc import binomial from sage.misc.misc import some_tuples + pz = tester._instance.zero() - for x,y,z in some_tuples(S, 3, tester._max_runs): + for x, y, z in some_tuples(S, 3, tester._max_runs): brxy = x.bracket(y) brxz = x.bracket(z) bryz = y.bracket(z) - br1 = {k: x.bracket(v) for k,v in bryz.items()} - br2 = {k: v.bracket(z) for k,v in brxy.items()} - br3 = {k: y.bracket(v) for k,v in brxz.items()} - jac1 = {(j,k): v for k in br1 for j,v in br1[k].items()} - jac3 = {(k,j): v for k in br3 for j,v in br3[k].items()} + br1 = {k: x.bracket(v) for k, v in bryz.items()} + br2 = {k: v.bracket(z) for k, v in brxy.items()} + br3 = {k: y.bracket(v) for k, v in brxz.items()} + jac1 = {(j, k): v for k in br1 for j, v in br1[k].items()} + jac3 = {(k, j): v for k in br3 for j, v in br3[k].items()} jac2 = {} - for k,br in br2.items(): - for j,v in br.items(): - for r in range(j+1): - jac2[(k+r, j-r)] = (jac2.get((k+r, j-r), pz) - + binomial(k+r, r)*v) - for k,v in jac2.items(): + for k, br in br2.items(): + for j, v in br.items(): + for r in range(j + 1): + jac2[(k + r, j - r)] = jac2.get((k + r, j - r), pz) + binomial(k + r, r) * v + for k, v in jac2.items(): jac1[k] = jac1.get(k, pz) - v - for k,v in jac3.items(): + for k, v in jac3.items(): jac1[k] = jac1.get(k, pz) - v - jacobiator = {k: v for k,v in jac1.items() if v} + jacobiator = {k: v for k, v in jac1.items() if v} tester.assertDictEqual(jacobiator, {}) class ElementMethods: @@ -335,15 +337,10 @@ def is_even_odd(self): """ return 0 - Graded = LazyImport("sage.categories.graded_lie_conformal_algebras", - "GradedLieConformalAlgebras", "Graded") + Graded = LazyImport("sage.categories.graded_lie_conformal_algebras", "GradedLieConformalAlgebras", "Graded") - Super = LazyImport("sage.categories.super_lie_conformal_algebras", - "SuperLieConformalAlgebras", "Super") + Super = LazyImport("sage.categories.super_lie_conformal_algebras", "SuperLieConformalAlgebras", "Super") - WithBasis = LazyImport("sage.categories.lie_conformal_algebras_with_basis", - "LieConformalAlgebrasWithBasis", "WithBasis") + WithBasis = LazyImport("sage.categories.lie_conformal_algebras_with_basis", "LieConformalAlgebrasWithBasis", "WithBasis") - FinitelyGeneratedAsLambdaBracketAlgebra = LazyImport( - 'sage.categories.finitely_generated_lie_conformal_algebras', - 'FinitelyGeneratedLieConformalAlgebras') + FinitelyGeneratedAsLambdaBracketAlgebra = LazyImport('sage.categories.finitely_generated_lie_conformal_algebras', 'FinitelyGeneratedLieConformalAlgebras') diff --git a/src/sage/categories/lie_conformal_algebras_with_basis.py b/src/sage/categories/lie_conformal_algebras_with_basis.py index 6ad0574c493..db2faf9b151 100644 --- a/src/sage/categories/lie_conformal_algebras_with_basis.py +++ b/src/sage/categories/lie_conformal_algebras_with_basis.py @@ -6,7 +6,7 @@ - Reimundo Heluani (2019-10-05): Initial implementation. """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2019 Reimundo Heluani # # This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.graded_lie_conformal_algebras import GradedLieConformalAlgebrasCategory @@ -31,6 +31,7 @@ class LieConformalAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): sage: LieConformalAlgebras(QQbar).WithBasis() # needs sage.rings.number_field Category of Lie conformal algebras with basis over Algebraic Field """ + class Super(SuperModulesCategory): """ The category of super Lie conformal algebras with basis. @@ -41,6 +42,7 @@ class Super(SuperModulesCategory): Category of super Lie conformal algebras with basis over Algebraic Real Field """ + class ParentMethods: def _even_odd_on_basis(self, m): @@ -59,7 +61,7 @@ def _even_odd_on_basis(self, m): sage: V._even_odd_on_basis(B(('G', 1))) # needs sage.combinat sage.modules 1 """ - return self._parity[self.monomial((m[0],0))] + return self._parity[self.monomial((m[0], 0))] class Graded(GradedLieConformalAlgebrasCategory): """ @@ -96,6 +98,7 @@ class FinitelyGeneratedAsLambdaBracketAlgebra(CategoryWithAxiom_over_base_ring): sage: CWF is C.FinitelyGenerated().WithBasis() # needs sage.rings.number_field True """ + class Super(SuperModulesCategory): """ The category of super finitely generated Lie conformal @@ -107,6 +110,7 @@ class Super(SuperModulesCategory): Category of super finitely generated Lie conformal algebras with basis over Algebraic Real Field """ + class Graded(GradedModulesCategory): """ The category of H-graded super finitely generated Lie @@ -121,6 +125,7 @@ class Graded(GradedModulesCategory): sage: C.Graded().Super() is C.Super().Graded() # needs sage.rings.number_field True """ + def _repr_object_names(self): """ The names of the objects of ``self``. diff --git a/src/sage/categories/lie_groups.py b/src/sage/categories/lie_groups.py index 06f1e23200a..888d1098a2b 100644 --- a/src/sage/categories/lie_groups.py +++ b/src/sage/categories/lie_groups.py @@ -1,14 +1,15 @@ r""" Lie Groups """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2015 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** -#from sage.misc.abstract_method import abstract_method +# from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method from sage.categories.category_types import Category_over_base_ring from sage.categories.groups import Groups @@ -31,6 +32,7 @@ class LieGroups(Category_over_base_ring): sage: TestSuite(C).run(skip='_test_category_over_bases') """ + @cached_method def super_categories(self): """ diff --git a/src/sage/categories/loop_crystals.py b/src/sage/categories/loop_crystals.py index 22d9485a5ed..514676426a0 100644 --- a/src/sage/categories/loop_crystals.py +++ b/src/sage/categories/loop_crystals.py @@ -48,6 +48,7 @@ class LoopCrystals(Category_singleton): sage: B = FiniteCrystals().example() sage: TestSuite(B).run() """ + @cached_method def super_categories(self): r""" @@ -71,6 +72,7 @@ def example(self, n=3): Kirillov-Reshetikhin crystal of type ['A', 3, 1] with (r,s)=(1,1) """ from sage.combinat.crystals.kirillov_reshetikhin import KirillovReshetikhinCrystal + return KirillovReshetikhinCrystal(['A', n, 1], 1, 1) class ParentMethods: @@ -121,11 +123,14 @@ def digraph(self, subset=None, index_set=None): G = Crystals().parent_class.digraph(self, subset, index_set) if have_dot2tex(): + def eopt(u_v_label): return {"backward": u_v_label[2] == 0} + G.set_latex_options(edge_options=eopt) return G + # TODO: Should we make "regular" an axiom? @@ -134,6 +139,7 @@ class RegularLoopCrystals(Category_singleton): The category of regular `U_q'(\mathfrak{g})`-crystals, where `\mathfrak{g}` is of affine type. """ + @cached_method def super_categories(self): """ @@ -171,6 +177,7 @@ class KirillovReshetikhinCrystals(Category_singleton): """ Category of Kirillov-Reshetikhin crystals. """ + @cached_method def super_categories(self): r""" @@ -248,8 +255,7 @@ def cardinality(self): 4736732 """ CWLR = self.cartan_type().classical().root_system().ambient_space() - return sum(CWLR.weyl_dimension(mg.classical_weight()) - for mg in self.classically_highest_weight_vectors()) + return sum(CWLR.weyl_dimension(mg.classical_weight()) for mg in self.classically_highest_weight_vectors()) @cached_method def maximal_vector(self): @@ -288,11 +294,11 @@ def maximal_vector(self): s = self.s() if self.cartan_type().dual().type() == 'BC': if self.cartan_type().rank() - 1 == r: - weight = 2*s*Lambda[r] - s*Lambda[0] + weight = 2 * s * Lambda[r] - s * Lambda[0] else: - weight = s*Lambda[r] - s*Lambda[0] + weight = s * Lambda[r] - s * Lambda[0] else: - weight = s*Lambda[r] - s*Lambda[0] * Lambda[r].level() / Lambda[0].level() + weight = s * Lambda[r] - s * Lambda[0] * Lambda[r].level() / Lambda[0].level() # First check the module generators as it is likely to be in here for b in self.module_generators: @@ -336,6 +342,7 @@ def affinization(self): Affinization of Kirillov-Reshetikhin tableaux of type ['A', 2, 1] and shape (1, 1) """ from sage.combinat.crystals.affinization import AffinizationOfCrystal + return AffinizationOfCrystal(self) @cached_method @@ -407,6 +414,7 @@ def R_matrix(self, K): [[[2]], [[2], [3]]]: [[[2], [3]], [[2]]]}) """ from sage.combinat.crystals.tensor_product import TensorProductOfCrystals + T1 = TensorProductOfCrystals(self, K) T2 = TensorProductOfCrystals(K, self) gen1 = T1(self.maximal_vector(), K.maximal_vector()) @@ -544,9 +552,9 @@ def is_perfect(self, ell=None): Implement a version for tensor products of KR crystals. """ from sage.rings.integer_ring import ZZ + if ell is None: - if (self.cartan_type().dual().type() == 'BC' - and self.cartan_type().rank() - 1 == self.r()): + if self.cartan_type().dual().type() == 'BC' and self.cartan_type().rank() - 1 == self.r(): return True ell = self.s() / self.cartan_type().c()[self.r()] if ell not in ZZ: @@ -557,8 +565,7 @@ def is_perfect(self, ell=None): # [FOS2010]_ check if self.cartan_type().classical().type() not in ['E', 'F', 'G']: - if (self.cartan_type().dual().type() == 'BC' - and self.cartan_type().rank() - 1 == self.r()): + if self.cartan_type().dual().type() == 'BC' and self.cartan_type().rank() - 1 == self.r(): return ell == self.s() return ell == self.s() / self.cartan_type().c()[self.r()] @@ -579,6 +586,7 @@ def is_perfect(self, ell=None): rank = len(I) La = self.weight_lattice_realization().basis() from sage.combinat.integer_vector import IntegerVectors + for n in range(1, ell + 1): for c in IntegerVectors(n, rank): w = sum(c[i] * La[i] for i in I) @@ -627,8 +635,7 @@ def level(self): """ if not self.is_perfect(): raise ValueError("this crystal is not perfect") - if (self.cartan_type().dual().type() == 'BC' - and self.cartan_type().rank() - 1 == self.r()): + if self.cartan_type().dual().type() == 'BC' and self.cartan_type().rank() - 1 == self.r(): return self.s() return self.s() / self.cartan_type().c()[self.r()] @@ -716,6 +723,7 @@ class TensorProducts(TensorProductsCategory): """ The category of tensor products of Kirillov-Reshetikhin crystals. """ + @cached_method def extra_super_categories(self): """ @@ -811,8 +819,7 @@ def cardinality(self): 5130 """ CWLR = self.cartan_type().classical().root_system().ambient_space() - return sum(CWLR.weyl_dimension(mg.classical_weight()) - for mg in self.classically_highest_weight_vectors()) + return sum(CWLR.weyl_dimension(mg.classical_weight()) for mg in self.classically_highest_weight_vectors()) def one_dimensional_configuration_sum(self, q=None, group_components=True): r""" @@ -867,16 +874,15 @@ def one_dimensional_configuration_sum(self, q=None, group_components=True): """ if q is None: from sage.rings.rational_field import QQ + q = QQ['q'].gens()[0] P0 = self.weight_lattice_realization().classical() B = P0.algebra(q.parent()) if group_components: G = self.digraph(index_set=self.cartan_type().classical().index_set()) C = G.connected_components(sort=False) - return B.sum(q**(c[0].energy_function()) * B.sum(B(P0(b.weight())) - for b in c) - for c in C) - return B.sum(q**(b.energy_function()) * B(P0(b.weight())) for b in self) + return B.sum(q ** (c[0].energy_function()) * B.sum(B(P0(b.weight())) for b in c) for c in C) + return B.sum(q ** (b.energy_function()) * B(P0(b.weight())) for b in self) class ElementMethods: def energy_function(self, algorithm=None): @@ -977,8 +983,7 @@ def energy_function(self, algorithm=None): C = self.parent().crystals[0] ell = ceil(C.s() / C.cartan_type().c()[C.r()]) - is_perfect = all(ell == K.s() / K.cartan_type().c()[K.r()] - for K in self.parent().crystals) + is_perfect = all(ell == K.s() / K.cartan_type().c()[K.r()] for K in self.parent().crystals) if algorithm is None: if is_perfect: algorithm = 'grading' @@ -994,16 +999,15 @@ def energy_function(self, algorithm=None): if algorithm == 'definition': # Setup from sage.rings.integer_ring import ZZ + energy = ZZ.zero() - R_mats = [[K.R_matrix(Kp) for Kp in self.parent().crystals[i+1:]] - for i, K in enumerate(self.parent().crystals)] - H_funcs = [[K.local_energy_function(Kp) for Kp in self.parent().crystals[i+1:]] - for i, K in enumerate(self.parent().crystals)] + R_mats = [[K.R_matrix(Kp) for Kp in self.parent().crystals[i + 1 :]] for i, K in enumerate(self.parent().crystals)] + H_funcs = [[K.local_energy_function(Kp) for Kp in self.parent().crystals[i + 1 :]] for i, K in enumerate(self.parent().crystals)] for i, b in enumerate(self): for j, R in enumerate(R_mats[i]): H = H_funcs[i][j] - bp = self[i+j+1] + bp = self[i + j + 1] T = R.domain() t = T(b, bp) energy += H(t) @@ -1107,8 +1111,7 @@ def e_string_to_ground_state(self): """ from sage.arith.misc import integer_ceil as ceil - ell = max(ceil(K.s()/K.cartan_type().c()[K.r()]) - for K in self.parent().crystals) + ell = max(ceil(K.s() / K.cartan_type().c()[K.r()]) for K in self.parent().crystals) if self.cartan_type().dual().type() == 'BC': I = self.cartan_type().index_set() for i in I[:-1]: @@ -1130,6 +1133,7 @@ def e_string_to_ground_state(self): ##################################################################### # Local energy function + class LocalEnergyFunction(Map): r""" The local energy function. @@ -1174,6 +1178,7 @@ class LocalEnergyFunction(Map): [KKMMNN1992]_ """ + def __init__(self, B, Bp, normalization=0): """ Initialize ``self``. @@ -1197,14 +1202,15 @@ def __init__(self, B, Bp, normalization=0): [0, 1, 2, 1] """ from sage.rings.integer_ring import ZZ + self._B = B self._Bp = Bp self._R_matrix = self._B.R_matrix(self._Bp) T = B.tensor(Bp) - self._known_values = {T(*[K.maximal_vector() for K in T.crystals]): - ZZ(normalization)} + self._known_values = {T(*[K.maximal_vector() for K in T.crystals]): ZZ(normalization)} self._I0 = T.cartan_type().classical().index_set() from sage.categories.homset import Hom + Map.__init__(self, Hom(T, ZZ)) def _repr_(self): diff --git a/src/sage/categories/magmas.py b/src/sage/categories/magmas.py index 1634e574653..c0d7e5e38f1 100644 --- a/src/sage/categories/magmas.py +++ b/src/sage/categories/magmas.py @@ -1,6 +1,7 @@ r""" Magmas """ + # **************************************************************************** # Copyright (C) 2010 Nicolas M. Thiery # @@ -60,6 +61,7 @@ class Magmas(Category_singleton): sage: C = Magmas() sage: TestSuite(C).run() """ + def super_categories(self): """ EXAMPLES:: @@ -257,6 +259,7 @@ def FinitelyGenerated(self): interactive use or when there is no risk of ambiguity. """ from sage.categories.additive_magmas import AdditiveMagmas + if self.is_subcategory(AdditiveMagmas()): raise ValueError("FinitelyGenerated is ambiguous for {}.\nPlease use explicitly one of the FinitelyGeneratedAsXXX methods".format(self)) return self.FinitelyGeneratedAsMagma() @@ -312,9 +315,11 @@ def Distributive(self): 'sage.categories.magmas_and_additive_magmas' """ from .additive_magmas import AdditiveMagmas + if not self.is_subcategory(AdditiveMagmas()): raise ValueError("The distributive axiom only makes sense on a magma which is simultaneously an additive magma") from .magmas_and_additive_magmas import MagmasAndAdditiveMagmas + return (self & MagmasAndAdditiveMagmas()).Distributive() def JTrivial(self): @@ -371,6 +376,7 @@ def extra_super_categories(self): True """ from sage.categories.magmatic_algebras import MagmaticAlgebras + return [MagmaticAlgebras(self.base_ring())] class ParentMethods: @@ -645,8 +651,7 @@ def one(self): sage: cartesian_product([QQ, ZZ, RR]).one() # needs sage.rings.real_mpfr (1, 1, 1.00000000000000) """ - return self._cartesian_product_of_elements( - _.one() for _ in self.cartesian_factors()) + return self._cartesian_product_of_elements(_.one() for _ in self.cartesian_factors()) class ElementMethods: def __invert__(self): @@ -688,8 +693,7 @@ def __invert__(self): """ # variant without coercion: # return self.parent()._cartesian_product_of_elements( - return self.parent()( - ~x for x in self.cartesian_factors()) + return self.parent()(~x for x in self.cartesian_factors()) class Algebras(AlgebrasCategory): @@ -813,7 +817,7 @@ def __init_extra__(self): # So, in addition, it should be tested whether the element class exists # *and* has a custom _mul_, because in this case it must not be overridden. - if (self.product.__func__ == self.product_from_element_class_mul.__func__): + if self.product.__func__ == self.product_from_element_class_mul.__func__: return if not (hasattr(self, "element_class") and hasattr(self.element_class, "_mul_parent")): return @@ -984,6 +988,7 @@ def multiplication_table(self, names='letters', elements=None): """ from sage.matrix.operation_table import OperationTable import operator + return OperationTable(self, operation=operator.mul, names=names, elements=elements) class ElementMethods: @@ -1072,6 +1077,7 @@ def example(self): from .cartesian_product import cartesian_product from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ + return cartesian_product([QQ, ZZ, ZZ]) class ParentMethods: @@ -1096,8 +1102,7 @@ def product(self, left, right): sage: x*y B[(0, [1, 2, 3])] + B[(1, [3, 1, 2])] """ - prods = ((a * b) for a, b in zip(left.cartesian_factors(), - right.cartesian_factors())) + prods = ((a * b) for a, b in zip(left.cartesian_factors(), right.cartesian_factors())) return self._cartesian_product_of_elements(prods) class Subquotients(SubquotientsCategory): diff --git a/src/sage/categories/magmas_and_additive_magmas.py b/src/sage/categories/magmas_and_additive_magmas.py index 92c4a2bb398..9fce15b7154 100644 --- a/src/sage/categories/magmas_and_additive_magmas.py +++ b/src/sage/categories/magmas_and_additive_magmas.py @@ -1,12 +1,13 @@ r""" Magmas and Additive Magmas """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2010 Nicolas Borie # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.cachefunc import cached_method from sage.misc.lazy_import import LazyImport diff --git a/src/sage/categories/magmatic_algebras.py b/src/sage/categories/magmatic_algebras.py index 1ac43e7bd79..9772f0000f9 100644 --- a/src/sage/categories/magmatic_algebras.py +++ b/src/sage/categories/magmatic_algebras.py @@ -1,6 +1,7 @@ r""" Non-unital non-associative algebras """ + # **************************************************************************** # Copyright (C) 2011 Nicolas M. Thiery # @@ -196,14 +197,14 @@ def product(self): """ if self.product_on_basis is not NotImplemented: return self._product_from_product_on_basis_multiply - # return self._module_morphism(self._module_morphism(self.product_on_basis, position = 0, codomain=self), - # position = 1) + # return self._module_morphism(self._module_morphism(self.product_on_basis, position = 0, codomain=self), + # position = 1) if hasattr(self, "product_by_coercion"): return self.product_by_coercion return NotImplemented # Provides a product using the product_on_basis by calling linear_combination only once - def _product_from_product_on_basis_multiply( self, left, right ): + def _product_from_product_on_basis_multiply(self, left, right): r""" Compute the product of two elements by extending bilinearly the method :meth:`product_on_basis`. @@ -217,9 +218,7 @@ def _product_from_product_on_basis_multiply( self, left, right ): sage: A._product_from_product_on_basis_multiply(a*b + 2*c, a - b) # needs sage.combinat sage.modules B[word: aba] - B[word: abb] + 2*B[word: ca] - 2*B[word: cb] """ - return self.linear_combination((self.product_on_basis(mon_left, mon_right), coeff_left * coeff_right ) - for (mon_left, coeff_left) in left.monomial_coefficients(copy=False).items() - for (mon_right, coeff_right) in right.monomial_coefficients(copy=False).items() ) + return self.linear_combination((self.product_on_basis(mon_left, mon_right), coeff_left * coeff_right) for (mon_left, coeff_left) in left.monomial_coefficients(copy=False).items() for (mon_right, coeff_right) in right.monomial_coefficients(copy=False).items()) class FiniteDimensional(CategoryWithAxiom_over_base_ring): class ParentMethods: @@ -269,12 +268,9 @@ def to_finite_dimensional_algebra(self, names='e', assume_associative=True, assu True """ from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra import FiniteDimensionalAlgebra + R = self.base_ring() - return FiniteDimensionalAlgebra(R, [x.to_matrix(side="right").transpose() - for x in self.basis()], - names=names, - assume_associative=assume_associative, - assume_unital=assume_unital) + return FiniteDimensionalAlgebra(R, [x.to_matrix(side="right").transpose() for x in self.basis()], names=names, assume_associative=assume_associative, assume_unital=assume_unital) @cached_method def derivations_basis(self): @@ -339,24 +335,19 @@ def derivations_basis(self): R = self.base_ring() B = self.basis() keys = list(B.keys()) - scoeffs = {(j,y,i): c for y in keys for i in keys - for j,c in (B[y]*B[i]).monomial_coefficients(copy=False).items() - } + scoeffs = {(j, y, i): c for y in keys for i in keys for j, c in (B[y] * B[i]).monomial_coefficients(copy=False).items()} zero = R.zero() data = {} N = len(keys) - for ii,i in enumerate(keys): - for ij,j in enumerate(keys): - for il,l in enumerate(keys): + for ii, i in enumerate(keys): + for ij, j in enumerate(keys): + for il, l in enumerate(keys): row = ii + N * ij + N**2 * il - for ik,k in enumerate(keys): - data[row,ik+N*il] = (data.get((row,ik+N*il), zero) - + scoeffs.get((k, i, j), zero)) - data[row,ii+N*ik] = (data.get((row,ii+N*ik), zero) - - scoeffs.get((l, k, j), zero)) - data[row,ij+N*ik] = (data.get((row,ij+N*ik), zero) - - scoeffs.get((l, i, k), zero)) + for ik, k in enumerate(keys): + data[row, ik + N * il] = data.get((row, ik + N * il), zero) + scoeffs.get((k, i, j), zero) + data[row, ii + N * ik] = data.get((row, ii + N * ik), zero) - scoeffs.get((l, k, j), zero) + data[row, ij + N * ik] = data.get((row, ij + N * ik), zero) - scoeffs.get((l, i, k), zero) from sage.matrix.constructor import matrix + mat = matrix(R, data, sparse=True) - return tuple([matrix(R, N, N, list(b)) - for b in mat.right_kernel().basis()]) + return tuple([matrix(R, N, N, list(b)) for b in mat.right_kernel().basis()]) diff --git a/src/sage/categories/manifolds.py b/src/sage/categories/manifolds.py index b48c3955117..f2db123c1e2 100644 --- a/src/sage/categories/manifolds.py +++ b/src/sage/categories/manifolds.py @@ -1,12 +1,13 @@ r""" Manifolds """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2015 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method @@ -37,6 +38,7 @@ class Manifolds(Category_over_base_ring): sage: TestSuite(C).run(skip='_test_category_over_bases') # needs sage.rings.real_mpfr """ + def __init__(self, base, name=None): r""" Initialize ``self``. @@ -249,6 +251,7 @@ class Smooth(CategoryWithAxiom_over_base_ring): A smooth manifold is a manifold with a smooth atlas. """ + def extra_super_categories(self): """ Return the extra super categories of ``self``. @@ -270,6 +273,7 @@ class Analytic(CategoryWithAxiom_over_base_ring): An analytic manifold is a manifold with an analytic atlas. """ + def extra_super_categories(self): """ Return the extra super categories of ``self``. @@ -294,6 +298,7 @@ class AlmostComplex(CategoryWithAxiom_over_base_ring): vector bundle isomorphism `J : TM \to TM` on the tangent bundle. The tensor field `J` is called the *almost complex structure* of `M`. """ + def extra_super_categories(self): """ Return the extra super categories of ``self``. @@ -339,6 +344,7 @@ class ComplexManifolds(Category_over_base_ring): A `d`-dimensional complex manifold is a manifold whose underlying vector space is `\CC^d` and has a holomorphic atlas. """ + @cached_method def super_categories(self): """ diff --git a/src/sage/categories/map.pyi b/src/sage/categories/map.pyi index d6c947d9845..a7cf727e7f5 100644 --- a/src/sage/categories/map.pyi +++ b/src/sage/categories/map.pyi @@ -43,9 +43,7 @@ class Map[DomainElementT, CodomainElementT](Element): def _default_repr_(self) -> str: ... def domains(self) -> Iterator[Parent[Any] | None]: ... def category_for(self) -> Category: ... - def __call__( - self, x: DomainElementT, *args: Any, **kwds: Any - ) -> CodomainElementT: ... + def __call__(self, x: DomainElementT, *args: Any, **kwds: Any) -> CodomainElementT: ... def _call_(self, x: DomainElementT) -> CodomainElementT: ... def _call_with_args( self, @@ -65,9 +63,7 @@ class Map[DomainElementT, CodomainElementT](Element): def section(self) -> Map[Any, Any] | None: ... def __hash__(self) -> int: ... -class Section( - Map[SectionCodomainT, SectionDomainT], Generic[SectionDomainT, SectionCodomainT] -): +class Section(Map[SectionCodomainT, SectionDomainT], Generic[SectionDomainT, SectionCodomainT]): _inverse: Map[SectionDomainT, SectionCodomainT] def __init__(self, map: Map[SectionDomainT, SectionCodomainT]) -> None: ... diff --git a/src/sage/categories/matrix_algebras.py b/src/sage/categories/matrix_algebras.py index 08b102d7451..bcaf0cd0154 100644 --- a/src/sage/categories/matrix_algebras.py +++ b/src/sage/categories/matrix_algebras.py @@ -1,14 +1,15 @@ r""" Matrix algebras """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2005 David Kohel # William Stein # 2008-2009 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.algebras import Algebras from sage.categories.category_types import Category_over_base_ring diff --git a/src/sage/categories/metric_spaces.py b/src/sage/categories/metric_spaces.py index cb06982c392..06ff221efde 100644 --- a/src/sage/categories/metric_spaces.py +++ b/src/sage/categories/metric_spaces.py @@ -1,6 +1,7 @@ r""" Metric Spaces """ + # *************************************************************************** # Copyright (C) 2015 Travis Scrimshaw # @@ -59,8 +60,7 @@ def default_super_categories(cls, category): sage: sage.categories.metric_spaces.MetricSpacesCategory.default_super_categories(Groups()) Join of Category of topological groups and Category of metric spaces """ - return Category.join([category.Topological(), - super().default_super_categories(category)]) + return Category.join([category.Topological(), super().default_super_categories(category)]) # We currently don't have a use for this, but we probably will def _repr_object_names(self): @@ -107,6 +107,7 @@ class MetricSpaces(MetricSpacesCategory): Category of metric spaces sage: TestSuite(C).run() """ + def _repr_object_names(self): """ EXAMPLES:: @@ -322,8 +323,7 @@ def dist(self, a, b): sage: Q2.dist((0, 0), (2, 3)) 3 """ - return max(x.dist(y) for x, y in zip(self(a).cartesian_factors(), - self(b).cartesian_factors())) + return max(x.dist(y) for x, y in zip(self(a).cartesian_factors(), self(b).cartesian_factors())) class SubcategoryMethods: @cached_method diff --git a/src/sage/categories/modular_abelian_varieties.py b/src/sage/categories/modular_abelian_varieties.py index 804361a7f99..22907457027 100644 --- a/src/sage/categories/modular_abelian_varieties.py +++ b/src/sage/categories/modular_abelian_varieties.py @@ -1,14 +1,15 @@ r""" Modular abelian varieties """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2005 David Kohel # William Stein # 2008-2009 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category_types import Category_over_base from sage.categories.category_with_axiom import CategoryWithAxiom @@ -26,6 +27,7 @@ class ModularAbelianVarieties(Category_over_base): sage: ModularAbelianVarieties(QQ) Category of modular abelian varieties over Rational Field """ + def __init__(self, Y): """ TESTS:: @@ -60,7 +62,7 @@ def super_categories(self): sage: ModularAbelianVarieties(QQ).super_categories() [Category of sets] """ - return [Sets()] # FIXME + return [Sets()] # FIXME class Homsets(HomsetsCategory): diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index c1652da5cd4..3d85ad45d36 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -1,6 +1,7 @@ r""" Modules """ + # **************************************************************************** # Copyright (C) 2005 David Kohel # William Stein @@ -152,9 +153,9 @@ def __classcall_private__(cls, base_ring, dispatch=True): sage: TestSuite(C).run() """ if dispatch: - if base_ring in _Fields or (isinstance(base_ring, Category) - and base_ring.is_subcategory(_Fields)): + if base_ring in _Fields or (isinstance(base_ring, Category) and base_ring.is_subcategory(_Fields)): from .vector_spaces import VectorSpaces + return VectorSpaces(base_ring, check=False) result = super().__classcall__(cls, base_ring) result._reduction[2]['dispatch'] = False @@ -414,6 +415,7 @@ def Filtered(self, base_ring=None): """ assert base_ring is None or base_ring is self.base_ring() from sage.categories.filtered_modules import FilteredModulesCategory + return FilteredModulesCategory.category_of(self) @cached_method @@ -450,6 +452,7 @@ def Graded(self, base_ring=None): """ assert base_ring is None or base_ring is self.base_ring() from sage.categories.graded_modules import GradedModulesCategory + return GradedModulesCategory.category_of(self) @cached_method @@ -486,6 +489,7 @@ def Super(self, base_ring=None): """ assert base_ring is None or base_ring is self.base_ring() from sage.categories.super_modules import SuperModulesCategory + return SuperModulesCategory.category_of(self) @cached_method @@ -536,9 +540,7 @@ def extra_super_categories(self): """ base_ring = self.base_ring() FiniteSets = Sets().Finite() - if (isinstance(base_ring, Category) and - base_ring.is_subcategory(FiniteSets)) or \ - base_ring in FiniteSets: + if (isinstance(base_ring, Category) and base_ring.is_subcategory(FiniteSets)) or base_ring in FiniteSets: return [FiniteSets] return [] @@ -584,9 +586,7 @@ def extra_super_categories(self): """ base_ring = self.base_ring() FiniteSets = Sets().Finite() - if (isinstance(base_ring, Category) and - base_ring.is_subcategory(FiniteSets)) or \ - base_ring in FiniteSets: + if (isinstance(base_ring, Category) and base_ring.is_subcategory(FiniteSets)) or base_ring in FiniteSets: return [FiniteSets] return [] @@ -594,8 +594,7 @@ def extra_super_categories(self): Graded = LazyImport('sage.categories.graded_modules', 'GradedModules') Super = LazyImport('sage.categories.super_modules', 'SuperModules') # at_startup currently needed for MatrixSpace, see #22955 (e.g., comment:20) - WithBasis = LazyImport('sage.categories.modules_with_basis', 'ModulesWithBasis', - at_startup=True) + WithBasis = LazyImport('sage.categories.modules_with_basis', 'ModulesWithBasis', at_startup=True) class ParentMethods: @@ -624,10 +623,8 @@ def linear_combination(self, iter_of_elements_coeff, factor_on_left=True): 1 + (3, -1) """ if factor_on_left: - return self.sum(coeff * element - for element, coeff in iter_of_elements_coeff) - return self.sum(element * coeff - for element, coeff in iter_of_elements_coeff) + return self.sum(coeff * element for element, coeff in iter_of_elements_coeff) + return self.sum(element * coeff for element, coeff in iter_of_elements_coeff) @cached_method def tensor_square(self): @@ -805,6 +802,7 @@ def zero(self): To: Free module generated by {2, 3, 4} over Integer Ring """ from sage.misc.constant_function import ConstantFunction + return self(ConstantFunction(self.codomain().zero())) class Endset(CategoryWithAxiom_over_base_ring): @@ -812,6 +810,7 @@ class Endset(CategoryWithAxiom_over_base_ring): The category of endomorphism sets `End(X)` for `X` a module (this is not used yet) """ + def extra_super_categories(self): """ Implement the fact that the endomorphism set of a module is an algebra. @@ -827,6 +826,7 @@ def extra_super_categories(self): True """ from .magmatic_algebras import MagmaticAlgebras + return [MagmaticAlgebras(self.base_category().base_ring())] class CartesianProducts(CartesianProductsCategory): @@ -839,6 +839,7 @@ class CartesianProducts(CartesianProductsCategory): - http://groups.google.fr/group/sage-devel/browse_thread/thread/35a72b1d0a2fc77a/348f42ae77a66d16#348f42ae77a66d16 - :wikipedia:`Direct_product` """ + def extra_super_categories(self): """ A Cartesian product of modules is endowed with a natural @@ -926,13 +927,13 @@ def _lmul_(self, x): sage: 5*B(([1, 2], [3, 4])) # needs sage.modules ((5, 10), (15, 20)) """ - return self.parent()._cartesian_product_of_elements( - x * y for y in self.cartesian_factors()) + return self.parent()._cartesian_product_of_elements(x * y for y in self.cartesian_factors()) class TensorProducts(TensorProductsCategory): """ The category of modules constructed by tensor product of modules. """ + @cached_method def extra_super_categories(self): """ @@ -949,6 +950,7 @@ class ParentMethods: """ Implement operations on tensor products of modules. """ + def construction(self): """ Return the construction of ``self``. diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 875fe49df0a..8a702ac8a4f 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -8,13 +8,14 @@ - Christian Stump (2010): :issue:`9648` module_morphism's to a wider class of codomains """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2008-2014 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.lazy_import import LazyImport, lazy_import from sage.misc.lazy_attribute import lazy_attribute @@ -32,13 +33,7 @@ from sage.structure.element import Element, parent -lazy_import('sage.modules.with_basis.morphism', - ['ModuleMorphismByLinearity', - 'ModuleMorphismFromMatrix', - 'ModuleMorphismFromFunction', - 'DiagonalModuleMorphism', - 'TriangularModuleMorphismByLinearity', - 'TriangularModuleMorphismFromFunction']) +lazy_import('sage.modules.with_basis.morphism', ['ModuleMorphismByLinearity', 'ModuleMorphismFromMatrix', 'ModuleMorphismFromFunction', 'DiagonalModuleMorphism', 'TriangularModuleMorphismByLinearity', 'TriangularModuleMorphismFromFunction']) class ModulesWithBasis(CategoryWithAxiom_over_base_ring): @@ -222,11 +217,10 @@ def basis(self): [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] """ from sage.sets.family import Family + return Family(self._indices, self.monomial) - def module_morphism(self, on_basis=None, matrix=None, function=None, - diagonal=None, triangular=None, unitriangular=False, - **keywords): + def module_morphism(self, on_basis=None, matrix=None, function=None, diagonal=None, triangular=None, unitriangular=False, **keywords): r""" Construct a module morphism from ``self`` to ``codomain``. @@ -568,19 +562,11 @@ def module_morphism(self, on_basis=None, matrix=None, function=None, unitriangular = True if triangular is not None: if on_basis is not None: - return TriangularModuleMorphismByLinearity( - domain=self, on_basis=on_basis, - triangular=triangular, unitriangular=unitriangular, - **keywords) - return TriangularModuleMorphismFromFunction( - domain=self, function=function, - triangular=triangular, unitriangular=unitriangular, - **keywords) + return TriangularModuleMorphismByLinearity(domain=self, on_basis=on_basis, triangular=triangular, unitriangular=unitriangular, **keywords) + return TriangularModuleMorphismFromFunction(domain=self, function=function, triangular=triangular, unitriangular=unitriangular, **keywords) if on_basis is not None: - return ModuleMorphismByLinearity( - domain=self, on_basis=on_basis, **keywords) - return ModuleMorphismFromFunction( # Or just SetMorphism? - domain=self, function=function, **keywords) + return ModuleMorphismByLinearity(domain=self, on_basis=on_basis, **keywords) + return ModuleMorphismFromFunction(domain=self, function=function, **keywords) # Or just SetMorphism? _module_morphism = module_morphism @@ -710,6 +696,7 @@ def echelon_form(self, elements, row_reduced=False, order=None): order = self._compute_support_order(elements, order) from sage.matrix.constructor import matrix + mat = matrix(self.base_ring(), [[g[s] for s in order] for g in elements]) # Echelonizing a matrix over a field returned the rref if row_reduced and self.base_ring() not in Fields(): @@ -719,13 +706,9 @@ def echelon_form(self, elements, row_reduced=False, order=None): raise ValueError("unable to compute the row reduced echelon form") else: mat.echelonize() - return [self._from_dict({order[i]: c for i, c in enumerate(vec) if c}, - remove_zeros=False) - for vec in mat if vec] + return [self._from_dict({order[i]: c for i, c in enumerate(vec) if c}, remove_zeros=False) for vec in mat if vec] - def submodule(self, gens, check=True, already_echelonized=False, - unitriangular=False, support_order=None, category=None, - submodule_class=None, *args, **opts): + def submodule(self, gens, check=True, already_echelonized=False, unitriangular=False, support_order=None, category=None, submodule_class=None, *args, **opts): r""" The submodule spanned by a finite set of elements. @@ -896,6 +879,7 @@ def submodule(self, gens, check=True, already_echelonized=False, """ # Make sure gens consists of elements of ``self`` from sage.sets.family import Family, AbstractFamily + if isinstance(gens, AbstractFamily): gens = gens.map(self) elif isinstance(gens, dict): @@ -908,10 +892,7 @@ def submodule(self, gens, check=True, already_echelonized=False, if submodule_class is None: from sage.modules.with_basis.subquotient import SubmoduleWithBasis as submodule_class - return submodule_class(gens, ambient=self, - support_order=support_order, - unitriangular=unitriangular, - category=category, *args, **opts) + return submodule_class(gens, ambient=self, support_order=support_order, unitriangular=unitriangular, category=category, *args, **opts) def quotient_module(self, submodule, check=True, already_echelonized=False, category=None): r""" @@ -965,10 +946,9 @@ def quotient_module(self, submodule, check=True, already_echelonized=False, cate - :class:`sage.modules.with_basis.subquotient.QuotientModuleWithBasis` """ from sage.modules.with_basis.subquotient import SubmoduleWithBasis, QuotientModuleWithBasis + if not isinstance(submodule, SubmoduleWithBasis): - submodule = self.submodule(submodule, check=check, - unitriangular=True, - already_echelonized=already_echelonized) + submodule = self.submodule(submodule, check=check, unitriangular=True, already_echelonized=already_echelonized) return QuotientModuleWithBasis(submodule, category=category) def tensor(*parents, **kwargs): @@ -1053,10 +1033,12 @@ def cardinality(self): 1 """ from sage.rings.infinity import Infinity + if self.dimension() == Infinity: return Infinity if self.dimension() == 0: from sage.rings.integer_ring import ZZ + return ZZ.one() return self.base_ring().cardinality() ** self.dimension() @@ -1076,7 +1058,7 @@ def is_finite(self): sage: GroupAlgebra(AbelianGroup(1), IntegerModRing(10)).is_finite() # needs sage.groups sage.modules False """ - return (self.base_ring().is_finite() and self.basis().keys().is_finite()) + return self.base_ring().is_finite() and self.basis().keys().is_finite() def monomial(self, i): """ @@ -1247,6 +1229,7 @@ def _apply_module_morphism(self, x, on_basis, codomain=False): if x == self.zero(): if not codomain: from sage.sets.family import Family + B = Family(self.basis()) try: z = B.first() @@ -1265,8 +1248,7 @@ def _apply_module_morphism(self, x, on_basis, codomain=False): if hasattr(codomain, 'linear_combination'): mc = x.monomial_coefficients(copy=False) - return codomain.linear_combination((on_basis(key), coeff) - for key, coeff in mc.items()) + return codomain.linear_combination((on_basis(key), coeff) for key, coeff in mc.items()) return_sum = codomain.zero() mc = x.monomial_coefficients(copy=False) for key, coeff in mc.items(): @@ -1286,8 +1268,7 @@ def _apply_module_endomorphism(self, x, on_basis): 2*s[2, 1] + 2*s[3] """ mc = x.monomial_coefficients(copy=False) - return self.linear_combination((on_basis(key), coeff) - for key, coeff in mc.items()) + return self.linear_combination((on_basis(key), coeff) for key, coeff in mc.items()) def dimension(self): """ @@ -1303,6 +1284,7 @@ def dimension(self): return self.basis().cardinality() except (AttributeError, TypeError): from sage.rings.integer_ring import ZZ + return ZZ(len(self.basis())) def rank(self): @@ -1436,14 +1418,10 @@ def random_element(self, n=2): random_element = lambda c: c.random_element() else: from random import choice - random_element = choice - return self.sum( - self.term(random_element(indices), - self.base_ring().random_element()) - for _ in range(n) - ) + random_element = choice + return self.sum(self.term(random_element(indices), self.base_ring().random_element()) for _ in range(n)) class ElementMethods: # TODO: Define the appropriate element methods here (instead of in @@ -1524,11 +1502,8 @@ def _test_monomial_coefficients(self, **options): d = self.monomial_coefficients() except NotImplementedError: return - tester.assertTrue(all(value.parent() == base_ring - for value in d.values())) - tester.assertEqual(self, self.parent().linear_combination( - (basis[index], coefficient) - for index, coefficient in d.items())) + tester.assertTrue(all(value.parent() == base_ring for value in d.values())) + tester.assertEqual(self, self.parent().linear_combination((basis[index], coefficient) for index, coefficient in d.items())) def __getitem__(self, m): """ @@ -1730,6 +1705,7 @@ def support(self): return self._support_view except AttributeError: from sage.structure.support_view import SupportView + zero = self.parent().base_ring().zero() mc = self.monomial_coefficients(copy=False) support_view = SupportView(mc, zero=zero) @@ -1782,9 +1758,7 @@ def terms(self): """ P = self.parent() zero = P.base_ring().zero() - return [P.term(key, value) - for key, value in self.monomial_coefficients(copy=False).items() - if value != zero] + return [P.term(key, value) for key, value in self.monomial_coefficients(copy=False).items() if value != zero] def coefficients(self, sort=True): """ @@ -1824,8 +1798,7 @@ def coefficients(self, sort=True): if not sort: return [value for value in mc.values() if value != zero] - v = sorted([(key, value) for key, value in mc.items() - if value != zero]) + v = sorted([(key, value) for key, value in mc.items() if value != zero]) return [value for key, value in v] def support_of_term(self): @@ -2398,9 +2371,7 @@ def map_support_skip_none(self, f): sage: y.parent() is B # needs sage.modules True """ - return self.parent().sum_of_terms((fm, c) - for fm, c in ((f(m), c) for m, c in self.items()) - if fm is not None) + return self.parent().sum_of_terms((fm, c) for fm, c in ((f(m), c) for m, c in self.items()) if fm is not None) def map_item(self, f): """ @@ -2523,8 +2494,7 @@ def __call_on_basis__(self, **options): sage: H.zero().category_for() Category of finite dimensional vector spaces with basis over Rational Field """ - return self.domain().module_morphism(codomain=self.codomain(), - **options) + return self.domain().module_morphism(codomain=self.codomain(), **options) class MorphismMethods: @cached_method @@ -2578,6 +2548,7 @@ class CartesianProducts(CartesianProductsCategory): The category of modules with basis constructed by Cartesian products of modules with basis. """ + @cached_method def extra_super_categories(self): """ @@ -2616,6 +2587,7 @@ def _an_element_(self): 2*B[(0, word: )] + 2*B[(1, ())] + 3*B[(1, (1,3,2))] """ from .cartesian_product import cartesian_product + return cartesian_product([module.an_element() for module in self.modules]) class TensorProducts(TensorProductsCategory): @@ -2623,6 +2595,7 @@ class TensorProducts(TensorProductsCategory): The category of modules with basis constructed by tensor product of modules with basis. """ + @cached_method def extra_super_categories(self): """ @@ -2641,6 +2614,7 @@ class ParentMethods: """ Implement operations on tensor products of modules with basis. """ + pass class ElementMethods: @@ -2770,13 +2744,8 @@ def apply_multilinear_morphism(self, f, codomain=None): except AttributeError: codomain = f(*[module.zero() for module in modules]).parent() if codomain in ModulesWithBasis(K): - return codomain.linear_combination((f(*[module.monomial(t) - for module, t in zip(modules, m)]), c) - for m, c in self.items()) - return sum((c * f(*[module.monomial(t) - for module, t in zip(modules, m)]) - for m, c in self.items()), - codomain.zero()) + return codomain.linear_combination((f(*[module.monomial(t) for module, t in zip(modules, m)]), c) for m, c in self.items()) + return sum((c * f(*[module.monomial(t) for module, t in zip(modules, m)]) for m, c in self.items()), codomain.zero()) class DualObjects(DualObjectsCategory): diff --git a/src/sage/categories/monoid_algebras.py b/src/sage/categories/monoid_algebras.py index a387d7f74f4..3e5a794a8f6 100644 --- a/src/sage/categories/monoid_algebras.py +++ b/src/sage/categories/monoid_algebras.py @@ -1,6 +1,7 @@ r""" Monoid algebras """ + # **************************************************************************** # Copyright (C) 2005 David Kohel # William Stein @@ -34,4 +35,5 @@ def MonoidAlgebras(base_ring): sage: TestSuite(MonoidAlgebras(ZZ)).run() """ from sage.categories.monoids import Monoids + return Monoids().Algebras(base_ring) diff --git a/src/sage/categories/monoids.py b/src/sage/categories/monoids.py index a1a0f4945f7..dcc0705d072 100644 --- a/src/sage/categories/monoids.py +++ b/src/sage/categories/monoids.py @@ -1,6 +1,7 @@ r""" Monoids """ + # **************************************************************************** # Copyright (C) 2005 David Kohel # William Stein @@ -72,6 +73,7 @@ class Monoids(CategoryWithAxiom): sage: R.submonoid([R.one()]).list() # needs sage.combinat [1] """ + _base_category_class_and_axiom = (Semigroups, "Unital") Finite = LazyImport('sage.categories.finite_monoids', 'FiniteMonoids', at_startup=True) @@ -108,6 +110,7 @@ def free(index_set=None, names=None, **kwds): if names is not None: if isinstance(names, str): from sage.rings.integer_ring import ZZ + if ',' not in names and index_set in ZZ: names = [names + repr(i) for i in range(index_set)] else: @@ -117,6 +120,7 @@ def free(index_set=None, names=None, **kwds): index_set = names from sage.monoids.indexed_free_monoid import IndexedFreeMonoid + return IndexedFreeMonoid(index_set, names=names, **kwds) class ParentMethods: @@ -136,9 +140,11 @@ def semigroup_generators(self): """ G = self.monoid_generators() from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets + if G not in FiniteEnumeratedSets(): raise NotImplementedError("currently only implemented for finitely generated monoids") from sage.sets.family import Family + return Family((self.one(),) + tuple(G)) def prod(self, args): @@ -159,6 +165,7 @@ def prod(self, args): 'ab' """ from sage.misc.misc_c import prod + return prod(args, self.one()) def _test_prod(self, **options): @@ -394,6 +401,7 @@ class Commutative(CategoryWithAxiom): A monoid `M` is *commutative* if `xy = yx` for all `x,y \in M`. """ + @staticmethod def free(index_set=None, names=None, **kwds): r""" @@ -425,6 +433,7 @@ def free(index_set=None, names=None, **kwds): if names is not None: if isinstance(names, str): from sage.rings.integer_ring import ZZ + if ',' not in names and index_set in ZZ: names = [names + repr(i) for i in range(index_set)] else: @@ -434,6 +443,7 @@ def free(index_set=None, names=None, **kwds): index_set = names from sage.monoids.indexed_free_monoid import IndexedFreeAbelianMonoid + return IndexedFreeAbelianMonoid(index_set, names=names, **kwds) class WithRealizations(WithRealizationsCategory): @@ -499,6 +509,7 @@ def extra_super_categories(self): Category of unital magma algebras over Rational Field] """ from sage.categories.bialgebras import Bialgebras + return [Bialgebras(self.base_ring()), Monoids()] class ParentMethods: @@ -620,8 +631,7 @@ def is_central(self) -> bool: sage: sum(A.basis()).is_central() # needs sage.groups sage.modules True """ - return all(i * self == self * i - for i in self.parent().algebra_generators()) + return all(i * self == self * i for i in self.parent().algebra_generators()) class CartesianProducts(CartesianProductsCategory): """ @@ -630,6 +640,7 @@ class CartesianProducts(CartesianProductsCategory): This construction gives the direct product of monoids. See :wikipedia:`Direct_product` for more information. """ + def extra_super_categories(self): """ A Cartesian product of monoids is endowed with a natural @@ -678,24 +689,21 @@ def lift(i, gen): cur = list(ids) cur[i] = gen return self._cartesian_product_of_elements(cur) + from sage.sets.family import Family # Finitely generated cat = FiniteEnumeratedSets() - if all(M.monoid_generators() in cat or - isinstance(M.monoid_generators(), (tuple, list)) - for M in F): - ret = [lift(i, gen) for i, M in enumerate(F) - for gen in M.monoid_generators()] + if all(M.monoid_generators() in cat or isinstance(M.monoid_generators(), (tuple, list)) for M in F): + ret = [lift(i, gen) for i, M in enumerate(F) for gen in M.monoid_generators()] return Family(ret) # Infinitely generated # This does not return a good output, but it is "correct" # TODO: Figure out a better way to do things from sage.categories.cartesian_product import cartesian_product - gens_prod = cartesian_product([Family(M.monoid_generators(), - lambda g: (i, g)) - for i, M in enumerate(F)]) + + gens_prod = cartesian_product([Family(M.monoid_generators(), lambda g: (i, g)) for i, M in enumerate(F)]) return Family(gens_prod, lift, name='gen') class ElementMethods: @@ -713,10 +721,12 @@ def multiplicative_order(self): 12 """ from sage.rings.infinity import Infinity + orders = [x.multiplicative_order() for x in self.cartesian_factors()] if any(o is Infinity for o in orders): return Infinity from sage.arith.functions import LCM_list + return LCM_list(orders) def __invert__(self): diff --git a/src/sage/categories/noetherian_rings.py b/src/sage/categories/noetherian_rings.py index d57a3a6a9be..5b394054d18 100644 --- a/src/sage/categories/noetherian_rings.py +++ b/src/sage/categories/noetherian_rings.py @@ -15,6 +15,7 @@ sage: IntegerModRing(5) in NoetherianRings() True """ + # **************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2012 Nicolas M. Thiery @@ -48,6 +49,7 @@ class NoetherianRings(Category): sage: TestSuite(C).run() """ + def super_categories(self): """ EXAMPLES:: diff --git a/src/sage/categories/number_fields.py b/src/sage/categories/number_fields.py index 0fb41521a19..7c5e56cd878 100644 --- a/src/sage/categories/number_fields.py +++ b/src/sage/categories/number_fields.py @@ -1,6 +1,7 @@ r""" Number fields """ + # **************************************************************************** # Copyright (C) 2005 David Kohel # William Stein @@ -90,6 +91,7 @@ def __contains__(self, x) -> bool: False """ from sage.rings.number_field.number_field_base import NumberField + return isinstance(x, NumberField) def _call_(self, x): @@ -122,9 +124,7 @@ def _call_(self, x): raise TypeError("unable to canonically associate a number field to %s" % x) class ParentMethods: - def zeta_function(self, prec=53, - max_imaginary_part=0, - algorithm='pari'): + def zeta_function(self, prec=53, max_imaginary_part=0, algorithm='pari'): r""" Return the Dedekind zeta function of this number field. @@ -165,8 +165,8 @@ def zeta_function(self, prec=53, PARI zeta function associated to Rational Field """ from sage.lfunctions.pari import lfun_number_field, LFunction - Z = LFunction(lfun_number_field(self), prec=prec, - max_im=max_imaginary_part) + + Z = LFunction(lfun_number_field(self), prec=prec, max_im=max_imaginary_part) Z.rename(f'PARI zeta function associated to {self}') return Z @@ -188,6 +188,7 @@ def _test_absolute_disc(self, **options): sage: S._test_absolute_disc() # needs sage.rings.number_field """ from sage.rings.integer import Integer + tester = self._tester(**options) tester.assertIsInstance(self.absolute_discriminant(), Integer) diff --git a/src/sage/categories/objects.py b/src/sage/categories/objects.py index 4dd1c61e2c7..8b71de16111 100644 --- a/src/sage/categories/objects.py +++ b/src/sage/categories/objects.py @@ -1,7 +1,8 @@ r""" Objects """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2005 David Kohel # William Stein # 2008 Teresa Gomez-Diaz (CNRS) @@ -9,7 +10,7 @@ # # Distributed under the terms of the GNU General Public License (GPL) # https://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.cachefunc import cached_method from sage.categories.category_singleton import Category_singleton diff --git a/src/sage/categories/ore_modules.py b/src/sage/categories/ore_modules.py index 5d8d270f3ca..ee7a82953bd 100644 --- a/src/sage/categories/ore_modules.py +++ b/src/sage/categories/ore_modules.py @@ -27,6 +27,7 @@ class OreModules(Category_over_base_ring): r""" Category of Ore modules. """ + @staticmethod def __classcall_private__(cls, ring, twist): r""" diff --git a/src/sage/categories/partially_ordered_monoids.py b/src/sage/categories/partially_ordered_monoids.py index 0f41b6c330f..2b45dfc82ee 100644 --- a/src/sage/categories/partially_ordered_monoids.py +++ b/src/sage/categories/partially_ordered_monoids.py @@ -1,12 +1,13 @@ r""" Partially ordered monoids """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category_singleton import Category_singleton from sage.categories.basic import Posets, Monoids diff --git a/src/sage/categories/permutation_groups.py b/src/sage/categories/permutation_groups.py index 952e6a3fc3c..09bf14d8424 100644 --- a/src/sage/categories/permutation_groups.py +++ b/src/sage/categories/permutation_groups.py @@ -1,12 +1,13 @@ r""" Permutation groups """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2011 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.cachefunc import cached_method from sage.categories.category import Category @@ -47,6 +48,7 @@ class PermutationGroups(Category): sage: C = PermutationGroups() sage: TestSuite(C).run() """ + @cached_method def super_categories(self): """ diff --git a/src/sage/categories/pointed_sets.py b/src/sage/categories/pointed_sets.py index 27376140dbe..c2c3e9061b8 100644 --- a/src/sage/categories/pointed_sets.py +++ b/src/sage/categories/pointed_sets.py @@ -1,14 +1,15 @@ r""" Pointed sets """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 David Kohel and # William Stein # Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category_singleton import Category_singleton from sage.categories.sets_cat import Sets @@ -27,7 +28,8 @@ class PointedSets(Category_singleton): sage: TestSuite(PointedSets()).run() """ - #def __call__(self, X, pt): + + # def __call__(self, X, pt): # import sage.sets.all # return sage.sets.all.Set(X, pt) @@ -38,4 +40,4 @@ def super_categories(self): sage: PointedSets().super_categories() [Category of sets] """ - return [Sets()] # ??? + return [Sets()] # ??? diff --git a/src/sage/categories/polyhedra.py b/src/sage/categories/polyhedra.py index a254fada46d..d134b64e7eb 100644 --- a/src/sage/categories/polyhedra.py +++ b/src/sage/categories/polyhedra.py @@ -1,12 +1,13 @@ r""" Polyhedral subsets of free ZZ, QQ or RR-modules. """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2011 Volker Braun # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.cachefunc import cached_method from sage.categories.category_types import Category_over_base_ring @@ -70,4 +71,5 @@ def super_categories(self): """ from sage.categories.magmas import Magmas from sage.categories.additive_monoids import AdditiveMonoids + return [Magmas().Commutative(), AdditiveMonoids()] diff --git a/src/sage/categories/poor_man_map.py b/src/sage/categories/poor_man_map.py index a145f234c2c..0b97f8f15b9 100644 --- a/src/sage/categories/poor_man_map.py +++ b/src/sage/categories/poor_man_map.py @@ -1,6 +1,7 @@ r""" Poor Man's map """ + # **************************************************************************** # Copyright (C) 2009 Nicolas M. Thiery # 2016 Julian Rüth @@ -56,6 +57,7 @@ class PoorManMap(SageObject): sage: i == g*h True """ + def __init__(self, function, domain=None, codomain=None, name=None): """ TESTS:: @@ -68,6 +70,7 @@ def __init__(self, function, domain=None, codomain=None, name=None): sage: TestSuite(f*g).run() """ from collections.abc import Iterable + if not isinstance(function, Iterable): function = (function,) self._functions = tuple(function) @@ -89,9 +92,7 @@ def _repr_(self): sage: PoorManMap(lambda x: x+2, codomain=(3,4,5)) A map to (3, 4, 5) """ - return ((self._name if self._name is not None else "A map") + - (" from %s" % (self._domain,) if self._domain is not None else "") + - (" to %s" % (self._codomain,) if self._codomain is not None else "")) + return (self._name if self._name is not None else "A map") + (" from %s" % (self._domain,) if self._domain is not None else "") + (" to %s" % (self._codomain,) if self._codomain is not None else "") def domain(self): """ @@ -134,10 +135,7 @@ def __eq__(self, other): (True, False, False, False, False, False, False) """ if isinstance(other, PoorManMap): - return (self._functions == other._functions - and self._domain == other._domain - and self._codomain == other._codomain - and self._name == other._name) + return self._functions == other._functions and self._domain == other._domain and self._codomain == other._codomain and self._name == other._name return False def __ne__(self, other): @@ -219,6 +217,7 @@ def __mul__(self, other): if self_domain is not None and other_codomain is not None: from sage.structure.parent import Parent + if isinstance(self_domain, Parent) and isinstance(other_codomain, Parent): if not self_domain.has_coerce_map_from(other_codomain): raise ValueError("the codomain %r does not coerce into the domain %r" % (other_codomain, self_domain)) @@ -263,6 +262,7 @@ def _sympy_(self): sin """ from sympy import sympify + if len(self._functions) == 1: return sympify(self._functions[0]) raise NotImplementedError diff --git a/src/sage/categories/posets.py b/src/sage/categories/posets.py index 2daa961c73c..b382bc05c2e 100644 --- a/src/sage/categories/posets.py +++ b/src/sage/categories/posets.py @@ -89,6 +89,7 @@ class Posets(Category): sage: C = Posets() sage: TestSuite(C).run() """ + @cached_method def super_categories(self): r""" @@ -118,6 +119,7 @@ def example(self, choice=None): the positive integers ordered by divisibility """ from sage.categories.examples.posets import FiniteSetsOrderedByInclusion, PositiveIntegersOrderedByDivisibilityFacade + if choice == "facade": return PositiveIntegersOrderedByDivisibilityFacade() return FiniteSetsOrderedByInclusion() @@ -147,6 +149,7 @@ def __iter__(self): Finite poset containing 4 elements """ from sage.combinat.posets.posets import FinitePosets_n + n = 0 while True: yield from FinitePosets_n(n) @@ -196,7 +199,7 @@ def lt(self, x, y): sage: D.lt( 3, 5 ) False """ - return self.le(x,y) and x != y + return self.le(x, y) and x != y def ge(self, x, y): r""" @@ -218,7 +221,7 @@ def ge(self, x, y): sage: D.ge( 3, 5 ) False """ - return self.le(y,x) + return self.le(y, x) def gt(self, x, y): r""" @@ -240,7 +243,7 @@ def gt(self, x, y): sage: D.gt( 3, 5 ) False """ - return self.lt(y,x) + return self.lt(y, x) @abstract_method(optional=True) def upper_covers(self, x): @@ -419,10 +422,12 @@ def order_ideal_toggle(self, I, v): if v not in I: if all(u in I for u in self.lower_covers(v)): from sage.sets.set import Set + return I.union(Set({v})) else: if all(u not in I for u in self.upper_covers(v)): from sage.sets.set import Set + return I.difference(Set({v})) return I @@ -614,7 +619,7 @@ def is_chain_of_poset(self, o, ordered=False): list_o = list(o) if ordered: return all(self.lt(a, b) for a, b in zip(list_o, list_o[1:])) - for (i, x) in enumerate(list_o): + for i, x in enumerate(list_o): for y in list_o[:i]: if (not self.le(x, y)) and (not self.gt(x, y)): return False @@ -695,10 +700,9 @@ def is_antichain_of_poset(self, o): ....: R(set([1, 4])), R(set([4, 5]))]) False """ - return all(not self.lt(x,y) for x in o for y in o) + return all(not self.lt(x, y) for x in o for y in o) - CartesianProduct = LazyImport( - 'sage.combinat.posets.cartesian_product', 'CartesianProductPoset') + CartesianProduct = LazyImport('sage.combinat.posets.cartesian_product', 'CartesianProductPoset') class ElementMethods: pass @@ -745,6 +749,7 @@ class Bounded(CategoryWithAxiom): sage: cat.super_categories() [Category of posets] """ + class ParentMethods: def is_bounded(self): """ diff --git a/src/sage/categories/principal_ideal_domains.py b/src/sage/categories/principal_ideal_domains.py index a746ff7757f..a9661e123bd 100644 --- a/src/sage/categories/principal_ideal_domains.py +++ b/src/sage/categories/principal_ideal_domains.py @@ -1,6 +1,7 @@ r""" Principal ideal domains """ + # **************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # @@ -108,20 +109,11 @@ def _test_gcd_vs_xgcd(self, **options): except (AttributeError, NotImplementedError): has_gcd = False - tester.assertTrue(has_gcd, - "The ring {} provides a xgcd but no gcd".format(self)) + tester.assertTrue(has_gcd, "The ring {} provides a xgcd but no gcd".format(self)) for (x, y), gcd, xgcd in zip(pairs, gcds, xgcds): - tester.assertTrue(gcd.parent() == self, - "The parent of the gcd is {} for element of {}".format( - gcd.parent(), self)) - tester.assertTrue(xgcd[0].parent() == self and - xgcd[1].parent() == self == xgcd[2].parent(), - "The parent of output in xgcd is different from " - "the parent of input for elements in {}".format(self)) - tester.assertTrue(gcd == xgcd[0], - "The methods gcd and xgcd disagree on {}:\n" - " gcd({},{}) = {}\n" - " xgcd({},{}) = {}\n".format(self, x, y, gcd, x, y, xgcd)) + tester.assertTrue(gcd.parent() == self, "The parent of the gcd is {} for element of {}".format(gcd.parent(), self)) + tester.assertTrue(xgcd[0].parent() == self and xgcd[1].parent() == self == xgcd[2].parent(), "The parent of output in xgcd is different from " "the parent of input for elements in {}".format(self)) + tester.assertTrue(gcd == xgcd[0], "The methods gcd and xgcd disagree on {}:\n" " gcd({},{}) = {}\n" " xgcd({},{}) = {}\n".format(self, x, y, gcd, x, y, xgcd)) def is_noetherian(self) -> bool: """ @@ -144,6 +136,7 @@ def class_group(self): Trivial Abelian group """ from sage.groups.abelian_gps.abelian_group import AbelianGroup + return AbelianGroup([]) def gcd(self, x, y, coerce=True): @@ -263,6 +256,7 @@ def _ideal_class_(self, n=0): """ from sage.rings.ideal import Ideal_pid + return Ideal_pid class ElementMethods: diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index ec36c76dd99..539f6538a55 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -1,6 +1,7 @@ """ Coercion via construction functors """ + # **************************************************************************** # Copyright (C) 2007-2014 Robert Bradshaw # 2007-2018 David Roe @@ -124,6 +125,7 @@ class ConstructionFunctor(Functor): sage: F(f)(F(A)(x)*a) (a + b)*x """ + def __mul__(self, other): """ Compose ``self`` and ``other`` to a composite construction @@ -252,6 +254,7 @@ def _repr_(self): """ s = str(type(self)) import re + return re.sub(r"<.*'.*\.([^.]*)'>", "\\1", s) def merge(self, other) -> Self | None: @@ -369,12 +372,9 @@ def common_base(self, other_functor, self_bases, other_bases): CoercionException: No common base ("join") found for FractionField(Integer Ring) and The cartesian_product functorial construction(Integer Ring). """ - self._raise_common_base_exception_( - other_functor, self_bases, other_bases) + self._raise_common_base_exception_(other_functor, self_bases, other_bases) - def _raise_common_base_exception_(self, other_functor, - self_bases, other_bases, - reason=None): + def _raise_common_base_exception_(self, other_functor, self_bases, other_bases, reason=None): r""" Raise a coercion exception. @@ -406,11 +406,7 @@ def _raise_common_base_exception_(self, other_functor, reason = '.' else: reason = ': ' + reason + '.' - raise CoercionException( - 'No common base ("join") found for %s(%s) and %s(%s)%s' % - (self, ', '.join(str(b) for b in self_bases), - other_functor, ', '.join(str(b) for b in other_bases), - reason)) + raise CoercionException('No common base ("join") found for %s(%s) and %s(%s)%s' % (self, ', '.join(str(b) for b in self_bases), other_functor, ', '.join(str(b) for b in other_bases), reason)) class CompositeConstructionFunctor(ConstructionFunctor): @@ -439,6 +435,7 @@ class CompositeConstructionFunctor(ConstructionFunctor): over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) """ + def __init__(self, *args): """ TESTS:: @@ -606,6 +603,7 @@ class IdentityConstructionFunctor(ConstructionFunctor): sage: I == loads(dumps(I)) True """ + rank = -100 def __init__(self): @@ -620,6 +618,7 @@ def __init__(self): True """ from sage.categories.sets_cat import Sets + ConstructionFunctor.__init__(self, Sets(), Sets()) def _apply_functor(self, x): @@ -660,7 +659,7 @@ def __eq__(self, other): sage: I == QQ.construction()[0] False """ - c = (type(self) is type(other)) + c = type(self) is type(other) if not c: if isinstance(other, IdentityFunctor_generic): return True @@ -732,6 +731,7 @@ class MultivariateConstructionFunctor(ConstructionFunctor): sage: pushout(A, B) The Cartesian product of (Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field, Rational Field) """ + def common_base(self, other_functor, self_bases, other_bases): r""" This function is called by :func:`pushout` when no common parent @@ -771,16 +771,12 @@ def common_base(self, other_functor, self_bases, other_bases): CoercionException: No common base ("join") found ... """ if self != other_functor: - self._raise_common_base_exception_( - other_functor, self_bases, other_bases, - '(Multivariate) functors are incompatible') + self._raise_common_base_exception_(other_functor, self_bases, other_bases, '(Multivariate) functors are incompatible') if len(self_bases) != len(other_bases): - self._raise_common_base_exception_( - other_functor, self_bases, other_bases, - 'Functors need the same number of arguments') + self._raise_common_base_exception_(other_functor, self_bases, other_bases, 'Functors need the same number of arguments') from sage.structure.element import coercion_model - Z_bases = tuple(coercion_model.common_parent(S, O) - for S, O in zip(self_bases, other_bases)) + + Z_bases = tuple(coercion_model.common_parent(S, O) for S, O in zip(self_bases, other_bases)) return self(Z_bases) @@ -819,6 +815,7 @@ class PolynomialFunctor(ConstructionFunctor): sage: (S.0 + R.0).parent().is_sparse() False """ + rank = 9 def __init__(self, var, multi_variate=False, sparse=False, implementation=None): @@ -840,6 +837,7 @@ def __init__(self, var, multi_variate=False, sparse=False, implementation=None): True """ from .rings import Rings + Functor.__init__(self, Rings(), Rings()) self.var = var self.multi_variate = multi_variate @@ -857,6 +855,7 @@ def _apply_functor(self, R): Univariate Polynomial Ring in x over Finite Field of size 3 """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + kwds = {} if self.implementation: kwds['implementation'] = self.implementation @@ -881,6 +880,7 @@ def _apply_functor_to_morphism(self, f): from sage.rings.polynomial.polynomial_ring_homomorphism import ( PolynomialRingHomomorphism_from_base, ) + R = self._apply_functor(f.domain()) S = self._apply_functor(f.codomain()) return PolynomialRingHomomorphism_from_base(R.Hom(S), f) @@ -906,7 +906,7 @@ def __eq__(self, other): if isinstance(other, PolynomialFunctor): return self.var == other.var if isinstance(other, MultiPolynomialFunctor): - return (other == self) + return other == self return False def __ne__(self, other): @@ -1028,6 +1028,7 @@ def _apply_functor(self, R): Multivariate Polynomial Ring in x, y, z over Real Field with 53 bits of precision """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + return PolynomialRing(R, self.vars) def __eq__(self, other): @@ -1045,8 +1046,7 @@ def __eq__(self, other): False """ if isinstance(other, MultiPolynomialFunctor): - return (self.vars == other.vars and - self.term_order == other.term_order) + return self.vars == other.vars and self.term_order == other.term_order if isinstance(other, PolynomialFunctor): return self.vars == (other.var,) return False @@ -1091,8 +1091,7 @@ def __mul__(self, other): if set(self.vars).intersection(other.vars): raise CoercionException("Overlapping variables (%s,%s)" % (self.vars, other.vars)) return MultiPolynomialFunctor(other.vars + self.vars, self.term_order) - if (isinstance(other, CompositeConstructionFunctor) - and isinstance(other.all[-1], MultiPolynomialFunctor)): + if isinstance(other, CompositeConstructionFunctor) and isinstance(other.all[-1], MultiPolynomialFunctor): return CompositeConstructionFunctor(other.all[:-1], self * other.all[-1]) return CompositeConstructionFunctor(other, self) @@ -1298,6 +1297,7 @@ def _apply_functor(self, R): from sage.rings.polynomial.infinite_polynomial_ring import ( InfinitePolynomialRing, ) + return InfinitePolynomialRing(R, self._gens, order=self._order, implementation=self._imple) def _repr_(self): @@ -1321,9 +1321,7 @@ def __eq__(self, other): False """ if isinstance(other, InfinitePolynomialFunctor): - return (self._gens == other._gens and - self._order == other._order and - self._imple == other._imple) + return self._gens == other._gens and self._order == other._order and self._imple == other._imple return False def __ne__(self, other): @@ -1375,9 +1373,9 @@ def __mul__(self, other): if INT: # if there is overlap of generators, it must only be at the ends, so that # the resulting order after the merging is unique - if other._gens[-len(INT):] != self._gens[:len(INT)]: + if other._gens[-len(INT) :] != self._gens[: len(INT)]: raise CoercionException("Overlapping variables (%s,%s) are incompatible" % (self._gens, other._gens)) - OUTGENS = list(other._gens) + list(self._gens[len(INT):]) + OUTGENS = list(other._gens) + list(self._gens[len(INT) :]) else: OUTGENS = list(other._gens) + list(self._gens) # the orders must coincide @@ -1424,22 +1422,22 @@ def __mul__(self, other): if i == i0 and int(n) > int(n0): # wrong order BadOverlap = True OverlappingVars.append(x) - elif IsOverlap: # The overlap must be on the right end of the variable list + elif IsOverlap: # The overlap must be on the right end of the variable list BadOverlap = True - elif IsOverlap: # The overlap must be on the right end of the variable list + elif IsOverlap: # The overlap must be on the right end of the variable list BadOverlap = True - elif IsOverlap: # The overlap must be on the right end of the variable list + elif IsOverlap: # The overlap must be on the right end of the variable list BadOverlap = True - elif IsOverlap: # The overlap must be on the right end of the variable list + elif IsOverlap: # The overlap must be on the right end of the variable list BadOverlap = True - if BadOverlap: # the overlapping variables appear in the wrong order + if BadOverlap: # the overlapping variables appear in the wrong order raise CoercionException("Overlapping variables (%s,%s) are incompatible" % (self._gens, OverlappingVars)) - if len(OverlappingVars) > 1: # multivariate, hence, the term order matters + if len(OverlappingVars) > 1: # multivariate, hence, the term order matters if other.term_order.name() != self._order: raise CoercionException("Incompatible term orders %s, %s" % (self._order, other.term_order.name())) # ok, the overlap is fine, we will return something. - if RemainingVars: # we can only partially merge other into self + if RemainingVars: # we can only partially merge other into self if len(RemainingVars) > 1: return CompositeConstructionFunctor(MultiPolynomialFunctor(RemainingVars, term_order=other.term_order), self) return CompositeConstructionFunctor(PolynomialFunctor(RemainingVars[0]), self) @@ -1524,8 +1522,7 @@ def expand(self): """ if len(self._gens) == 1: return [self] - return [InfinitePolynomialFunctor((x,), self._order, self._imple) - for x in reversed(self._gens)] + return [InfinitePolynomialFunctor((x,), self._order, self._imple) for x in reversed(self._gens)] class MatrixFunctor(ConstructionFunctor): @@ -1559,6 +1556,7 @@ class MatrixFunctor(ConstructionFunctor): [ x + y x - y] [x^2 - y^2 2*x] """ + rank = 10 def __init__(self, nrows, ncols, is_sparse=False): @@ -1585,10 +1583,10 @@ def __init__(self, nrows, ncols, is_sparse=False): True """ if nrows == ncols: - Functor.__init__(self, Rings(), Rings()) # Algebras() takes a base ring + Functor.__init__(self, Rings(), Rings()) # Algebras() takes a base ring else: # Functor.__init__(self, Rings(), MatrixAlgebras()) # takes a base ring - Functor.__init__(self, Rings(), CommutativeAdditiveGroups()) # not a nice solution, but the best we can do. + Functor.__init__(self, Rings(), CommutativeAdditiveGroups()) # not a nice solution, but the best we can do. self.nrows = nrows self.ncols = ncols self.is_sparse = is_sparse @@ -1608,6 +1606,7 @@ def _apply_functor(self, R): True """ from sage.matrix.matrix_space import MatrixSpace + return MatrixSpace(R, self.nrows, self.ncols, sparse=self.is_sparse) def __eq__(self, other): @@ -1621,7 +1620,7 @@ def __eq__(self, other): False """ if isinstance(other, MatrixFunctor): - return (self.nrows == other.nrows and self.ncols == other.ncols) + return self.nrows == other.nrows and self.ncols == other.ncols return False def __ne__(self, other): @@ -1698,6 +1697,7 @@ class LaurentPolynomialFunctor(ConstructionFunctor): sage: F(f)(x*F(P).gen()^-2 + y*F(P).gen()^3) (x + 2*y)*t^-2 + (3*x - y)*t^3 """ + rank = 9 def __init__(self, var, multi_variate=False): @@ -1751,6 +1751,7 @@ def _apply_functor(self, R): from sage.rings.polynomial.laurent_polynomial_ring_base import ( LaurentPolynomialRing_generic, ) + if self.multi_variate and isinstance(R, LaurentPolynomialRing_generic): return LaurentPolynomialRing(R.base_ring(), list(R.variable_names()) + [self.var]) return LaurentPolynomialRing(R, self.var) @@ -1838,11 +1839,11 @@ class VectorFunctor(ConstructionFunctor): over the principal ideal domain Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X) """ - rank = 10 # ranking of functor, not rank of module. + + rank = 10 # ranking of functor, not rank of module. # This coincides with the rank of the matrix construction functor, but this is OK since they cannot both be applied in any order - def __init__(self, n=None, is_sparse=False, inner_product_matrix=None, *, - with_basis='standard', basis_keys=None, name_mapping=None, latex_name_mapping=None): + def __init__(self, n=None, is_sparse=False, inner_product_matrix=None, *, with_basis='standard', basis_keys=None, name_mapping=None, latex_name_mapping=None): """ INPUT: @@ -1876,8 +1877,8 @@ def __init__(self, n=None, is_sparse=False, inner_product_matrix=None, *, Sparse vector space of dimension 3 over Rational Field True """ -# Functor.__init__(self, Rings(), FreeModules()) # FreeModules() takes a base ring -# Functor.__init__(self, Objects(), Objects()) # Object() makes no sense, since FreeModule raises an error, e.g., on Set(['a',1]). + # Functor.__init__(self, Rings(), FreeModules()) # FreeModules() takes a base ring + # Functor.__init__(self, Objects(), Objects()) # Object() makes no sense, since FreeModule raises an error, e.g., on Set(['a',1]). # FreeModule requires a commutative ring. Thus, we have Functor.__init__(self, CommutativeRings(), CommutativeAdditiveGroups()) self.n = n @@ -1926,6 +1927,7 @@ def _apply_functor(self, R): M \otimes \Bold{Q} """ from sage.modules.free_module import FreeModule + name = self.name_mapping.get(R, None) latex_name = self.latex_name_mapping.get(R, None) if name is None: @@ -1934,14 +1936,13 @@ def _apply_functor(self, R): break if latex_name is None: from sage.misc.latex import latex + for latex_name in self.latex_name_mapping.values(): latex_name = fr'{latex_name} \otimes {latex(R)}' break if name is None and latex_name is None: - return FreeModule(R, self.n, sparse=self.is_sparse, inner_product_matrix=self.inner_product_matrix, - with_basis=self.with_basis, basis_keys=self.basis_keys) - return FreeModule(R, self.n, sparse=self.is_sparse, inner_product_matrix=self.inner_product_matrix, - with_basis=self.with_basis, basis_keys=self.basis_keys, name=name, latex_name=latex_name) + return FreeModule(R, self.n, sparse=self.is_sparse, inner_product_matrix=self.inner_product_matrix, with_basis=self.with_basis, basis_keys=self.basis_keys) + return FreeModule(R, self.n, sparse=self.is_sparse, inner_product_matrix=self.inner_product_matrix, with_basis=self.with_basis, basis_keys=self.basis_keys, name=name, latex_name=latex_name) def _apply_functor_to_morphism(self, f): """ @@ -1978,12 +1979,7 @@ def __eq__(self, other): True """ if isinstance(other, VectorFunctor): - return (self.n == other.n and - self.inner_product_matrix == other.inner_product_matrix and - self.with_basis == other.with_basis and - self.basis_keys == other.basis_keys and - self.name_mapping == other.name_mapping and - self.latex_name_mapping == other.latex_name_mapping) + return self.n == other.n and self.inner_product_matrix == other.inner_product_matrix and self.with_basis == other.with_basis and self.basis_keys == other.basis_keys and self.name_mapping == other.name_mapping and self.latex_name_mapping == other.latex_name_mapping return False def __ne__(self, other): @@ -2126,9 +2122,7 @@ def merge(self, other): if latex_name == other_latex_name: latex_name_mapping[base_ring] = latex_name - return VectorFunctor(n, is_sparse, inner_product_matrix, - with_basis=with_basis, basis_keys=basis_keys, - name_mapping=name_mapping, latex_name_mapping=latex_name_mapping) + return VectorFunctor(n, is_sparse, inner_product_matrix, with_basis=with_basis, basis_keys=basis_keys, name_mapping=name_mapping, latex_name_mapping=latex_name_mapping) class SubspaceFunctor(ConstructionFunctor): @@ -2156,7 +2150,8 @@ class SubspaceFunctor(ConstructionFunctor): [1 0 1] [0 1 0] """ - rank = 11 # ranking of functor, not rank of module + + rank = 11 # ranking of functor, not rank of module # The subspace construction returns an object admitting a coercion # map into the original, not vice versa. @@ -2179,8 +2174,8 @@ def __init__(self, basis): [1 2 3] [4 0 1] """ -# Functor.__init__(self, FreeModules(), FreeModules()) # takes a base ring -# Functor.__init__(self, Objects(), Objects()) # is too general + # Functor.__init__(self, FreeModules(), FreeModules()) # takes a base ring + # Functor.__init__(self, Objects(), Objects()) # is too general # It seems that the category of commutative additive groups # currently is the smallest base ring free category that # contains in- and output @@ -2278,7 +2273,7 @@ def __eq__(self, other): # Instead, we only test whether there are coercions. L = self.basis.universe() R = other.basis.universe() - c = (L == R) + c = L == R if L.has_coerce_map_from(R): return tuple(self.basis) == tuple(L(x) for x in other.basis) if R.has_coerce_map_from(L): @@ -2348,8 +2343,7 @@ def merge(self, other): if not self.basis: return other try: - P = pushout(self.basis[0].parent().ambient_module(), - other.basis[0].parent().ambient_module()) + P = pushout(self.basis[0].parent().ambient_module(), other.basis[0].parent().ambient_module()) except CoercionException: return None try: @@ -2392,6 +2386,7 @@ class FractionField(ConstructionFunctor): sage: F == loads(dumps(F)) True """ + rank = 5 def __init__(self): @@ -2407,6 +2402,7 @@ def __init__(self): """ from sage.categories.fields import Fields from sage.categories.integral_domains import IntegralDomains + Functor.__init__(self, IntegralDomains(), Fields()) def _apply_functor(self, R): @@ -2465,6 +2461,7 @@ class CompletionFunctor(ConstructionFunctor): sage: 1/2 + a (1 + O(5^20))*a + 3 + 2*5 + 2*5^2 + 2*5^3 + 2*5^4 + 2*5^5 + 2*5^6 + 2*5^7 + 2*5^8 + 2*5^9 + 2*5^10 + 2*5^11 + 2*5^12 + 2*5^13 + 2*5^14 + 2*5^15 + 2*5^16 + 2*5^17 + 2*5^18 + 2*5^19 + O(5^20) """ + rank = 4 _real_types = ['Interval', 'Ball', 'MPFR', 'RDF', 'RLF', 'RR'] _dvr_types = [None, 'fixed-mod', 'floating-point', 'capped-abs', 'capped-rel', 'lattice-cap', 'lattice-float', 'relaxed'] @@ -2521,6 +2518,7 @@ def __init__(self, p, prec, extras=None): self.extras = dict(extras) self.type = self.extras.pop('type', None) from sage.rings.infinity import Infinity + if self.p == Infinity: if self.type not in self._real_types: raise ValueError("completion type must be one of %s" % (", ".join(self._real_types))) @@ -2706,37 +2704,32 @@ def merge(self, other): ....: for P, Q in zip(pushouts, [pushout(a, b) for a in Plist for b in Plist])) True """ - if self == other: # both are Completion functors with the same p + if self == other: # both are Completion functors with the same p from sage.rings.infinity import Infinity + if self.p == Infinity: new_prec = min(self.prec, other.prec) - new_type = self._real_types[min(self._real_types.index(self.type), - self._real_types.index(other.type))] - new_scinot = max(self.extras.get('sci_not', 0), - other.extras.get('sci_not', 0)) - new_rnd = min(self.extras.get('rnd', 0), - other.extras.get('rnd', 0)) - return CompletionFunctor(self.p, new_prec, - {'type': new_type, - 'sci_not': new_scinot, - 'rnd': new_rnd}) + new_type = self._real_types[min(self._real_types.index(self.type), self._real_types.index(other.type))] + new_scinot = max(self.extras.get('sci_not', 0), other.extras.get('sci_not', 0)) + new_rnd = min(self.extras.get('rnd', 0), other.extras.get('rnd', 0)) + return CompletionFunctor(self.p, new_prec, {'type': new_type, 'sci_not': new_scinot, 'rnd': new_rnd}) new_type = self._dvr_types[min(self._dvr_types.index(self.type), self._dvr_types.index(other.type))] if new_type in ('fixed-mod', 'floating-point'): if self.type != other.type: - return None # no coercion into fixed-mod or floating-point + return None # no coercion into fixed-mod or floating-point new_prec = min(self.prec, other.prec) else: - new_prec = max(self.prec, other.prec) # since elements track their own precision, we don't want to truncate them + new_prec = max(self.prec, other.prec) # since elements track their own precision, we don't want to truncate them extras = self.extras.copy() extras.update(other.extras) extras['type'] = new_type return CompletionFunctor(self.p, new_prec, extras) -# Completion has a lower rank than FractionField -# and is thus applied first. However, fact is that -# both commute. This is used in the call method, -# since some fraction fields have no completion method -# implemented. + # Completion has a lower rank than FractionField + # and is thus applied first. However, fact is that + # both commute. This is used in the call method, + # since some fraction fields have no completion method + # implemented. def commutes(self, other): """ @@ -2813,10 +2806,10 @@ class QuotientFunctor(ConstructionFunctor): ... TypeError: Could not find a mapping of the passed element to this ring. """ + rank = 4.5 - def __init__(self, I, names=None, as_field=False, domain=None, - codomain=None, **kwds): + def __init__(self, I, names=None, as_field=False, domain=None, codomain=None, **kwds): """ INPUT: @@ -2902,8 +2895,10 @@ def _apply_functor(self, R): I = self.I if not I.is_zero(): from sage.categories.fields import Fields + if R in Fields(): from sage.rings.finite_rings.integer_mod_ring import Integers + return Integers(1) if I.ring() != R: if I.ring().has_coerce_map_from(R): @@ -2942,11 +2937,7 @@ def __eq__(self, other): """ if not isinstance(other, QuotientFunctor): return False - return (type(self) is type(other) and - self.domain() == other.domain() and - self.codomain() == other.codomain() and - self.names == other.names and - self.I == other.I) + return type(self) is type(other) and self.domain() == other.domain() and self.codomain() == other.codomain() and self.names == other.names and self.I == other.I def __ne__(self, other): """ @@ -3038,8 +3029,7 @@ def merge(self, other): raise TypeError("trivial quotient intersection") # GF(p) has a coercion from Integers(p). Hence, merging should # yield a field if either self or other yields a field. - return QuotientFunctor(I, names=self.names, as_field=as_field, - domain=domain, codomain=codomain, **kwds) + return QuotientFunctor(I, names=self.names, as_field=as_field, domain=domain, codomain=codomain, **kwds) class AlgebraicExtensionFunctor(ConstructionFunctor): @@ -3122,11 +3112,10 @@ class AlgebraicExtensionFunctor(ConstructionFunctor): sage: F(CyclotomicField(49)) Residue field in zbar of Fractional ideal (17) """ + rank = 3 - def __init__(self, polys, names, embeddings=None, structures=None, - cyclotomic=None, precs=None, implementations=None, - *, residue=None, latex_names=None, **kwds): + def __init__(self, polys, names, embeddings=None, structures=None, cyclotomic=None, precs=None, implementations=None, *, residue=None, latex_names=None, **kwds): """ INPUT: @@ -3272,6 +3261,7 @@ def __init__(self, polys, names, embeddings=None, structures=None, for i, name in enumerate(self.names): if latex_names[i] is not None: from sage.misc.latex import latex_variable_name + if latex_names[i] == latex_variable_name(name): latex_names[i] = None self.latex_names = latex_names @@ -3313,23 +3303,19 @@ def _apply_functor(self, R): """ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ + if self.cyclotomic: from sage.rings.number_field.number_field import CyclotomicField + if R == QQ: return CyclotomicField(self.cyclotomic) if R == ZZ: return CyclotomicField(self.cyclotomic).maximal_order() elif self.residue is not None: - return R.residue_field(R*self.residue, names=tuple(self.names)) + return R.residue_field(R * self.residue, names=tuple(self.names)) if len(self.polys) == 1: - return R.extension(self.polys[0], names=self.names[0], embedding=self.embeddings[0], - structure=self.structures[0], prec=self.precs[0], - implementation=self.implementations[0], - latex_names=self.latex_names[0], **self.kwds) - return R.extension(self.polys, names=self.names, embedding=self.embeddings, - structure=self.structures, prec=self.precs, - implementation=self.implementations, - latex_names=self.latex_names, **self.kwds) + return R.extension(self.polys[0], names=self.names[0], embedding=self.embeddings[0], structure=self.structures[0], prec=self.precs[0], implementation=self.implementations[0], latex_names=self.latex_names[0], **self.kwds) + return R.extension(self.polys, names=self.names, embedding=self.embeddings, structure=self.structures, prec=self.precs, implementation=self.implementations, latex_names=self.latex_names, **self.kwds) def __eq__(self, other): """ @@ -3357,11 +3343,7 @@ def __eq__(self, other): if not isinstance(other, AlgebraicExtensionFunctor): return False - return (self.polys == other.polys and - self.embeddings == other.embeddings and - self.structures == other.structures and - self.precs == other.precs and - self.latex_names == other.latex_names) + return self.polys == other.polys and self.embeddings == other.embeddings and self.structures == other.structures and self.precs == other.precs and self.latex_names == other.latex_names def __ne__(self, other): """ @@ -3484,19 +3466,20 @@ def merge(self, other): # But for being on the safe side...: if not (len(self.names) == 1 == len(other.names)): return None -# We don't accept a forgetful coercion, since, together -# with bidirectional coercions between two embedded -# number fields, it would yield to contradictions in -# the coercion system. -# if self.polys==other.polys and self.names==other.names: -# # We have a forgetful functor: -# if self.embeddings==[None]: -# return self -# if other.embeddings==[None]: -# return other + # We don't accept a forgetful coercion, since, together + # with bidirectional coercions between two embedded + # number fields, it would yield to contradictions in + # the coercion system. + # if self.polys==other.polys and self.names==other.names: + # # We have a forgetful functor: + # if self.embeddings==[None]: + # return self + # if other.embeddings==[None]: + # return other # ... or we may use the given embeddings: if self.embeddings != [None] and other.embeddings != [None]: from sage.rings.rational_field import QQ + KS = self(QQ) KO = other(QQ) if KS.has_coerce_map_from(KO): @@ -3507,6 +3490,7 @@ def merge(self, other): try: P = pushout(self.embeddings[0].parent(), other.embeddings[0].parent()) from sage.rings.number_field.number_field_base import NumberField + if isinstance(P, NumberField): return P.construction()[0] except CoercionException: @@ -3514,13 +3498,10 @@ def merge(self, other): # Finite fields and unramified local extensions may use # integers to encode degrees of extensions. from sage.rings.integer import Integer + kwds_self = dict(self.kwds.items()) kwds_other = dict(other.kwds.items()) - if (isinstance(self.polys[0], Integer) - and isinstance(other.polys[0], Integer) - and self.embeddings == other.embeddings == [None] - and self.structures == other.structures == [None] - and kwds_self == kwds_other): + if isinstance(self.polys[0], Integer) and isinstance(other.polys[0], Integer) and self.embeddings == other.embeddings == [None] and self.structures == other.structures == [None] and kwds_self == kwds_other: return AlgebraicExtensionFunctor([self.polys[0].lcm(other.polys[0])], [None], **kwds_self) def __mul__(self, other): @@ -3547,15 +3528,8 @@ def __mul__(self, other): if isinstance(other, AlgebraicExtensionFunctor): if set(self.names).intersection(other.names): raise CoercionException("Overlapping names (%s,%s)" % (self.names, other.names)) - return AlgebraicExtensionFunctor(self.polys + other.polys, self.names + other.names, - self.embeddings + other.embeddings, - self.structures + other.structures, - precs=self.precs + other.precs, - implementations=self.implementations + other.implementations, - latex_names=self.latex_names + other.latex_names, - **self.kwds) - if (isinstance(other, CompositeConstructionFunctor) - and isinstance(other.all[-1], AlgebraicExtensionFunctor)): + return AlgebraicExtensionFunctor(self.polys + other.polys, self.names + other.names, self.embeddings + other.embeddings, self.structures + other.structures, precs=self.precs + other.precs, implementations=self.implementations + other.implementations, latex_names=self.latex_names + other.latex_names, **self.kwds) + if isinstance(other, CompositeConstructionFunctor) and isinstance(other.all[-1], AlgebraicExtensionFunctor): return CompositeConstructionFunctor(other.all[:-1], self * other.all[-1]) return CompositeConstructionFunctor(other, self) @@ -3584,11 +3558,7 @@ def expand(self): n = len(self.polys) if n == 1: return [self] - return [AlgebraicExtensionFunctor([self.polys[i]], [self.names[i]], [self.embeddings[i]], - [self.structures[i]], precs=[self.precs[i]], - implementations=[self.implementations[i]], - latex_names=[self.latex_names[i]], **self.kwds) - for i in range(n)] + return [AlgebraicExtensionFunctor([self.polys[i]], [self.names[i]], [self.embeddings[i]], [self.structures[i]], precs=[self.precs[i]], implementations=[self.implementations[i]], latex_names=[self.latex_names[i]], **self.kwds) for i in range(n)] class AlgebraicClosureFunctor(ConstructionFunctor): @@ -3606,6 +3576,7 @@ class AlgebraicClosureFunctor(ConstructionFunctor): sage: F(F(QQ)) is F(QQ) True """ + rank = 3 def __init__(self): @@ -3704,8 +3675,8 @@ def __call__(self, R): Permutation Group with generators [(1,2)] """ from sage.groups.perm_gps.permgroup import PermutationGroup - return PermutationGroup([g for g in (R.gens() + self.gens()) if not g.is_one()], - domain=self._domain) + + return PermutationGroup([g for g in (R.gens() + self.gens()) if not g.is_one()], domain=self._domain) def gens(self) -> tuple: """ @@ -3743,8 +3714,7 @@ def merge(self, other): # Sorting the domain will sometimes fail with Python 3. # Fallback (not ideal: find a better solution?) new_domain = FiniteEnumeratedSet(sorted(new_domain, key=str)) - return PermutationGroupFunctor(self.gens() + other.gens(), - new_domain) + return PermutationGroupFunctor(self.gens() + other.gens(), new_domain) class EquivariantSubobjectConstructionFunctor(ConstructionFunctor): @@ -3830,8 +3800,8 @@ class EquivariantSubobjectConstructionFunctor(ConstructionFunctor): (Permutation Group with generators [(0,1)])-invariant submodule of Full MatrixSpace of 2 by 2 dense matrices over Rational Field """ - def __init__(self, S, action=operator.mul, side='left', - other_action=None, other_side='left'): + + def __init__(self, S, action=operator.mul, side='left', other_action=None, other_side='left'): """ EXAMPLES:: @@ -3846,6 +3816,7 @@ def __init__(self, S, action=operator.mul, side='left', Representation of S3 indexed by {1, 2, 3} over Integer Ring) """ from sage.categories.sets_cat import Sets + super().__init__(Sets(), Sets()) self.S = S self.action = action @@ -3909,6 +3880,7 @@ class BlackBoxConstructionFunctor(ConstructionFunctor): sage: FG == FS # needs sage.libs.gap sage.libs.singular False """ + rank = 100 def __init__(self, box): @@ -4401,6 +4373,7 @@ def pushout(R, S): # because tuples don't have has_coerce_map_from functions and to align with the # modification of Rs and Ss below from sage.structure.parent import Parent + if not isinstance(Rs[-1], Parent): Rs = Rs[:-1] if not isinstance(Ss[-1], Parent): @@ -4425,7 +4398,7 @@ def pushout(R, S): Rs.pop() Z = Ss.pop() else: - Rs = Rs[:Rs.index(Ss[-1])] + Rs = Rs[: Rs.index(Ss[-1])] Z = Ss.pop() # look for topmost coercion @@ -4445,12 +4418,12 @@ def pushout(R, S): if Z is None and R_tower[-1][0] is not None: Z = R_tower[-1][0].common_base(S_tower[-1][0], R_tower[-1][1], S_tower[-1][1]) - R_tower = expand_tower(R_tower[:len(Rs)]) - S_tower = expand_tower(S_tower[:len(Ss)]) + R_tower = expand_tower(R_tower[: len(Rs)]) + S_tower = expand_tower(S_tower[: len(Ss)]) else: # Rc is a list of functors from Z to R and Sc is a list of functors from Z to S - R_tower = expand_tower(R_tower[:len(Rs) + 1]) - S_tower = expand_tower(S_tower[:len(Ss) + 1]) + R_tower = expand_tower(R_tower[: len(Rs) + 1]) + S_tower = expand_tower(S_tower[: len(Ss) + 1]) Rc = [c[0] for c in R_tower[1:]] Sc = [c[0] for c in S_tower[1:]] @@ -4577,8 +4550,8 @@ def pushout_lattice(R, S): return None # truncate at common ancestor - R_tower = list(reversed(R_tower[:Rs.index(start) + 1])) - S_tower = list(reversed(S_tower[:Ss.index(start) + 1])) + R_tower = list(reversed(R_tower[: Rs.index(start) + 1])) + S_tower = list(reversed(S_tower[: Ss.index(start) + 1])) Rs = [c[1] for c in R_tower] # the list of objects Ss = [c[1] for c in S_tower] Rc = [c[0] for c in R_tower] # the list of functors @@ -4627,7 +4600,7 @@ def pushout_lattice(R, S): # and all subsequent squares will come from objects # where the operation was already performed (either # to the left or right) - Rc[i] = Sc[j] = None # IdentityConstructionFunctor() + Rc[i] = Sc[j] = None # IdentityConstructionFunctor() lattice[i + 1, j + 1] = lattice[i, j + 1] elif Rc[i] is None and Sc[j] is None: lattice[i + 1, j + 1] = lattice[i, j + 1] @@ -4652,8 +4625,7 @@ def pushout_lattice(R, S): print(ni, nj, R) except KeyError: break - raise CoercionException("%s does not support %s" - % (lattice[ni, nj], 'F')) + raise CoercionException("%s does not support %s" % (lattice[ni, nj], 'F')) # If we are successful, we should have something that looks like this. # @@ -4733,6 +4705,7 @@ def construction_tower(R): tower = [(None, R)] c = R.construction() from sage.structure.parent import Parent + while c is not None: f, R = c if not isinstance(f, ConstructionFunctor): @@ -4808,6 +4781,7 @@ def type_to_parent(P): TypeError: not a scalar type """ from sage.structure.coerce import py_scalar_parent + parent = py_scalar_parent(P) if parent is None: raise TypeError("not a scalar type") diff --git a/src/sage/categories/quantum_group_representations.py b/src/sage/categories/quantum_group_representations.py index 18c639d6e13..b2297eed9cb 100644 --- a/src/sage/categories/quantum_group_representations.py +++ b/src/sage/categories/quantum_group_representations.py @@ -6,7 +6,7 @@ - Travis Scrimshaw (2018): initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2018 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.abstract_method import abstract_method @@ -29,6 +29,7 @@ class QuantumGroupRepresentations(Category_module): """ The category of quantum group representations. """ + @cached_method def super_categories(self): """ @@ -57,7 +58,8 @@ def example(self): """ from sage.algebras.quantum_groups.representations import AdjointRepresentation from sage.combinat.crystals.tensor_product import CrystalOfTableaux - T = CrystalOfTableaux(['A',2], shape=[2,1]) + + T = CrystalOfTableaux(['A', 2], shape=[2, 1]) return AdjointRepresentation(self.base_ring(), T) class WithBasis(CategoryWithAxiom_over_base_ring): @@ -65,12 +67,14 @@ class WithBasis(CategoryWithAxiom_over_base_ring): The category of quantum group representations with a distinguished basis. """ + class TensorProducts(TensorProductsCategory): """ The category of quantum group representations with a distinguished basis constructed by tensor product of quantum group representations with a distinguished basis. """ + @cached_method def extra_super_categories(self): """ @@ -128,12 +132,12 @@ def e_on_basis(self, i, b): sage: v.e(4) # indirect doctest 0 """ - K_elt = [self._sets[k].K_on_basis(i, elt, -1) for k,elt in enumerate(b)] - mon = [self._sets[k].monomial(elt) for k,elt in enumerate(b)] + K_elt = [self._sets[k].K_on_basis(i, elt, -1) for k, elt in enumerate(b)] + mon = [self._sets[k].monomial(elt) for k, elt in enumerate(b)] t = self.tensor_constructor(self._sets) ret = self.zero() - for k,elt in enumerate(b): - ret += t(*(K_elt[:k] + [self._sets[k].e_on_basis(i, elt)] + mon[k+1:])) + for k, elt in enumerate(b): + ret += t(*(K_elt[:k] + [self._sets[k].e_on_basis(i, elt)] + mon[k + 1 :])) return ret def f_on_basis(self, i, b): @@ -191,12 +195,12 @@ def f_on_basis(self, i, b): + 6*B[[+--, []]] # B[[[1], [2]]] + 9*q^2*B[[+--, []]] # B[[[1], [3]]] """ - K_elt = [self._sets[k].K_on_basis(i, elt, 1) for k,elt in enumerate(b)] - mon = [self._sets[k].monomial(elt) for k,elt in enumerate(b)] + K_elt = [self._sets[k].K_on_basis(i, elt, 1) for k, elt in enumerate(b)] + mon = [self._sets[k].monomial(elt) for k, elt in enumerate(b)] t = self.tensor_constructor(self._sets) ret = self.zero() - for k,elt in enumerate(b): - ret += t(*(mon[:k] + [self._sets[k].f_on_basis(i, elt)] + K_elt[k+1:])) + for k, elt in enumerate(b): + ret += t(*(mon[:k] + [self._sets[k].f_on_basis(i, elt)] + K_elt[k + 1 :])) return ret def K_on_basis(self, i, b, power=1): @@ -234,8 +238,7 @@ def K_on_basis(self, i, b, power=1): + B[[[3]]] # B[[[1, 1], [2]]] """ t = self.tensor_constructor(self._sets) - return t(*[self._sets[k].K_on_basis(i, elt, power) - for k,elt in enumerate(b)]) + return t(*[self._sets[k].K_on_basis(i, elt, power) for k, elt in enumerate(b)]) class ParentMethods: def tensor(*factors): @@ -298,8 +301,7 @@ def e(self, i): """ F = self.parent() mc = self.monomial_coefficients(copy=False) - return F.linear_combination((F.e_on_basis(i, m), c) - for m, c in mc.items()) + return F.linear_combination((F.e_on_basis(i, m), c) for m, c in mc.items()) def f(self, i): r""" @@ -331,8 +333,7 @@ def f(self, i): """ F = self.parent() mc = self.monomial_coefficients(copy=False) - return F.linear_combination((F.f_on_basis(i, m), c) - for m, c in mc.items()) + return F.linear_combination((F.f_on_basis(i, m), c) for m, c in mc.items()) def K(self, i, power=1): r""" @@ -363,8 +364,7 @@ def K(self, i, power=1): """ F = self.parent() mc = self.monomial_coefficients(copy=False) - return F.linear_combination((F.K_on_basis(i, m, power), c) - for m, c in mc.items()) + return F.linear_combination((F.K_on_basis(i, m, power), c) for m, c in mc.items()) class TensorProducts(TensorProductsCategory): """ @@ -376,6 +376,7 @@ class TensorProducts(TensorProductsCategory): We use the reversed coproduct in order to match the tensor product rule on crystals. """ + @cached_method def extra_super_categories(self): """ @@ -457,37 +458,16 @@ def apply_f(d, elt): for x in self.basis(): for i in I: for j in I: - tester.assertEqual(x.K(j,-1).f(i).K(j,1), - q**-(al[i].scalar(ac[j]) * d[j]) * x.f(i), - "KfK^-1 -- i: {}, j: {}".format(i,j)) - tester.assertEqual(x.K(j,-1).e(i).K(j,1), - q**(al[i].scalar(ac[j]) * d[j]) * x.e(i), - "KeK^-1 -- i: {}, j: {}".format(i,j)) + tester.assertEqual(x.K(j, -1).f(i).K(j, 1), q ** -(al[i].scalar(ac[j]) * d[j]) * x.f(i), "KfK^-1 -- i: {}, j: {}".format(i, j)) + tester.assertEqual(x.K(j, -1).e(i).K(j, 1), q ** (al[i].scalar(ac[j]) * d[j]) * x.e(i), "KeK^-1 -- i: {}, j: {}".format(i, j)) if i == j: - tester.assertEqual(x.f(i).e(i) - x.e(i).f(i), - (x.K(i,1) - x.K(i,-1)) / (q**d[i] - q**(-d[i])), - "[e,f] = (K-K^-1)/(q_i-q_i^-1) -- i: {} j: {}".format(i, j)) + tester.assertEqual(x.f(i).e(i) - x.e(i).f(i), (x.K(i, 1) - x.K(i, -1)) / (q ** d[i] - q ** (-d[i])), "[e,f] = (K-K^-1)/(q_i-q_i^-1) -- i: {} j: {}".format(i, j)) continue - tester.assertEqual(x.f(j).e(i) - x.e(i).f(j), 0, - "[e,f] = 0 -- i: {} j: {}".format(i, j)) + tester.assertEqual(x.f(j).e(i) - x.e(i).f(j), 0, "[e,f] = 0 -- i: {} j: {}".format(i, j)) # Check quantum Serre - aij = A[I.index(i),I.index(j)] - tester.assertEqual(0, - sum((-1)**n - * q_factorial(1-aij, q**d[i]) - / (q_factorial(n, q**d[i]) - * q_factorial(1-aij-n, q**d[i])) - * apply_e([i]*(1-aij-n) + [j] + [i]*n, x) - for n in range(1-aij+1)), - "quantum Serre e -- i: {}, j: {}".format(i,j)) - tester.assertEqual(0, - sum((-1)**n - * q_factorial(1-aij, q**d[i]) - / (q_factorial(n, q**d[i]) - * q_factorial(1-aij-n, q**d[i])) - * apply_f([i]*(1-aij-n) + [j] + [i]*n, x) - for n in range(1-aij+1)), - "quantum Serre f -- i: {}, j: {}".format(i,j)) + aij = A[I.index(i), I.index(j)] + tester.assertEqual(0, sum((-1) ** n * q_factorial(1 - aij, q ** d[i]) / (q_factorial(n, q ** d[i]) * q_factorial(1 - aij - n, q ** d[i])) * apply_e([i] * (1 - aij - n) + [j] + [i] * n, x) for n in range(1 - aij + 1)), "quantum Serre e -- i: {}, j: {}".format(i, j)) + tester.assertEqual(0, sum((-1) ** n * q_factorial(1 - aij, q ** d[i]) / (q_factorial(n, q ** d[i]) * q_factorial(1 - aij - n, q ** d[i])) * apply_f([i] * (1 - aij - n) + [j] + [i] * n, x) for n in range(1 - aij + 1)), "quantum Serre f -- i: {}, j: {}".format(i, j)) count += 1 if count > tester._max_runs: return diff --git a/src/sage/categories/quotient_fields.py b/src/sage/categories/quotient_fields.py index a343e28fc13..98242b328c7 100644 --- a/src/sage/categories/quotient_fields.py +++ b/src/sage/categories/quotient_fields.py @@ -1,12 +1,13 @@ r""" Quotient fields """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category_singleton import Category_singleton from sage.misc.abstract_method import abstract_method @@ -129,7 +130,7 @@ def gcd(self, other): selfD = selfD // selfGCD otherN = otherN // otherGCD otherD = otherD // otherGCD - tmp = P(selfN.gcd(otherN))/P(selfD.lcm(otherD)) + tmp = P(selfN.gcd(otherN)) / P(selfD.lcm(otherD)) return tmp except (AttributeError, NotImplementedError, TypeError, ValueError): zero = P.zero() @@ -241,7 +242,7 @@ def lcm(self, other): selfD = selfD // selfGCD otherN = otherN // otherGCD otherD = otherD // otherGCD - return P(selfN.lcm(otherN))/P(selfD.gcd(otherD)) + return P(selfN.lcm(otherN)) / P(selfD.gcd(otherD)) except (AttributeError, NotImplementedError, TypeError, ValueError): zero = P.zero() if self == zero or other == zero: @@ -324,8 +325,8 @@ def xgcd(self, other): otherD = otherD // otherGCD lcmD = selfD.lcm(otherD) - g,s,t = selfN.xgcd(otherN) - return (P(g)/P(lcmD), P(s*selfD)/P(lcmD),P(t*otherD)/P(lcmD)) + g, s, t = selfN.xgcd(otherN) + return (P(g) / P(lcmD), P(s * selfD) / P(lcmD), P(t * otherD) / P(lcmD)) except (AttributeError, NotImplementedError, TypeError, ValueError): zero = self.parent().zero() one = self.parent().one() @@ -360,8 +361,7 @@ def factor(self, *args, **kwds): sage: f.factor() # needs sage.rings.finite_rings (x + y)^-1 * y * x """ - return (self.numerator().factor(*args, **kwds) / - self.denominator().factor(*args, **kwds)) + return self.numerator().factor(*args, **kwds) / self.denominator().factor(*args, **kwds) def partial_fraction_decomposition(self, decompose_powers=True): """ @@ -560,6 +560,7 @@ def partial_fraction_decomposition(self, decompose_powers=True): # TODO(robertwb): Should there be a category of univariate polynomials? from sage.rings.fraction_field_element import FractionFieldElement_1poly_field + is_polynomial_over_field = isinstance(self, FractionFieldElement_1poly_field) running_total = 0 @@ -580,10 +581,10 @@ def partial_fraction_decomposition(self, decompose_powers=True): for ee in range(e, 0, -1): n, n_part = n.quo_rem(r) if n_part: - r_parts.append(n_part/powers[ee]) + r_parts.append(n_part / powers[ee]) parts.extend(reversed(r_parts)) else: - parts.append(n/powers[e]) + parts.append(n / powers[e]) if not is_polynomial_over_field: # remainders not unique, need to re-compute whole to take into @@ -622,6 +623,7 @@ def derivative(self, *args): 2/(x^3 + 3*x^2*y + 3*x*y^2 + y^3) """ from sage.misc.derivative import multi_derivative + return multi_derivative(self, args) def _derivative(self, var=None): @@ -687,7 +689,7 @@ def _derivative(self, var=None): num = self.numerator() den = self.denominator() - if (num.is_zero()): + if num.is_zero(): return R.zero() if R.is_exact(): @@ -707,8 +709,7 @@ def _derivative(self, var=None): pass except NotImplementedError: pass - return self.__class__(R, tnum, tden, - coerce=False, reduce=False) + return self.__class__(R, tnum, tden, coerce=False, reduce=False) except AttributeError: pass except NotImplementedError: @@ -721,5 +722,4 @@ def _derivative(self, var=None): num = num._derivative(var) * den - num * den._derivative(var) den = den**2 - return self.__class__(R, num, den, - coerce=False, reduce=False) + return self.__class__(R, num, den, coerce=False, reduce=False) diff --git a/src/sage/categories/quotients.py b/src/sage/categories/quotients.py index 5a7d0c2aeb1..88f0c0ed0fe 100644 --- a/src/sage/categories/quotients.py +++ b/src/sage/categories/quotients.py @@ -5,12 +5,13 @@ - Nicolas M. Thiery (2010): initial revision """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2009 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.category import Category from sage.categories.covariant_functorial_construction import RegressiveCovariantConstructionCategory diff --git a/src/sage/categories/r_trivial_semigroups.py b/src/sage/categories/r_trivial_semigroups.py index a73f28931eb..e51b985e48f 100644 --- a/src/sage/categories/r_trivial_semigroups.py +++ b/src/sage/categories/r_trivial_semigroups.py @@ -1,7 +1,8 @@ r""" R-trivial semigroups """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2016 Nicolas M. Thiéry # # This program is free software: you can redistribute it and/or modify @@ -9,7 +10,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.semigroups import Semigroups diff --git a/src/sage/categories/realizations.py b/src/sage/categories/realizations.py index beef1ba2511..3476456f06c 100644 --- a/src/sage/categories/realizations.py +++ b/src/sage/categories/realizations.py @@ -9,12 +9,13 @@ for an introduction to covariant functorial constructions. - :mod:`sage.categories.examples.with_realizations` for an example. """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2010-2012 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.bindable_class import BindableClass from sage.categories.category import Category @@ -133,6 +134,7 @@ class Category_realization_of_parent(Category_over_base, BindableClass): as well as the name for that category. """ + def __init__(self, parent_with_realization): """ TESTS:: @@ -176,7 +178,8 @@ def _get_name(self): 'multiplicative bases on primitive elements' """ import re - return re.sub(".[A-Z]", lambda s: s.group()[0]+" "+s.group()[1], self.__class__.__base__.__name__.split(".")[-1]).lower() + + return re.sub(".[A-Z]", lambda s: s.group()[0] + " " + s.group()[1], self.__class__.__base__.__name__.split(".")[-1]).lower() def _repr_object_names(self): """ diff --git a/src/sage/categories/regular_crystals.py b/src/sage/categories/regular_crystals.py index 3ebb7004e60..0fc629ab808 100644 --- a/src/sage/categories/regular_crystals.py +++ b/src/sage/categories/regular_crystals.py @@ -2,7 +2,7 @@ r""" Regular Crystals """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2013 Anne Schilling # Travis Scrimshaw # @@ -16,7 +16,7 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#**************************************************************************** +# **************************************************************************** from sage.misc.cachefunc import cached_method from sage.categories.category_singleton import Category_singleton @@ -108,6 +108,7 @@ def example(self, n=3): Highest weight crystal of type A_3 of highest weight omega_1 """ from sage.categories.crystals import Crystals + return Crystals().example(n) def additional_structure(self): @@ -156,9 +157,7 @@ def is_isomorphism(self): sage: psi.is_isomorphism() True """ - return (self.is_strict() - and self.domain().number_of_connected_components() == - self.codomain().number_of_connected_components()) + return self.is_strict() and self.domain().number_of_connected_components() == self.codomain().number_of_connected_components() class ParentMethods: @@ -212,8 +211,7 @@ def demazure_operator(self, element, reduced_word): """ M = element.parent() for i in reversed(reduced_word): - element = M.linear_combination((c.demazure_operator_simple(i), coeff) - for c, coeff in element) + element = M.linear_combination((c.demazure_operator_simple(i), coeff) for c, coeff in element) return element def demazure_subcrystal(self, element, reduced_word, only_support=True): @@ -263,14 +261,14 @@ def demazure_subcrystal(self, element, reduced_word, only_support=True): """ from sage.combinat.free_module import CombinatorialFreeModule from sage.rings.rational_field import QQ + C = CombinatorialFreeModule(QQ, self) D = self.demazure_operator(C(element), reduced_word) if only_support: index_set = tuple(frozenset(reduced_word)) else: index_set = self.cartan_type().index_set() - return self.subcrystal(contained=D.support(), generators=[element], - index_set=index_set) + return self.subcrystal(contained=D.support(), generators=[element], index_set=index_set) def _test_stembridge_local_axioms(self, index_set=None, verbose=False, complete=False, **options): r""" @@ -445,11 +443,12 @@ def wt_zero(x): if checker(y): edges.append([x, y, i]) from sage.graphs.digraph import DiGraph + G = DiGraph([X, edges], format='vertices_and_edges', immutable=True) from sage.graphs.dot2tex_utils import have_dot2tex + if have_dot2tex(): - G.set_latex_options(format='dot2tex', edge_labels=True, - color_by_label=self.cartan_type()._index_set_coloring) + G.set_latex_options(format='dot2tex', edge_labels=True, color_by_label=self.cartan_type()._index_set_coloring) return G class ElementMethods: @@ -564,6 +563,7 @@ def demazure_operator_simple(self, i, ring=None): over Rational Field """ from sage.rings.integer_ring import ZZ + if ring is None: ring = ZZ C = self.parent().algebra(ring) @@ -577,10 +577,10 @@ def demazure_operator_simple(self, i, ring=None): return C.sum_of_monomials(l) l = [] element = self - for k in range(-r-1): + for k in range(-r - 1): element = element.e(i) l.append(element) - return - C.sum_of_monomials(l) + return -C.sum_of_monomials(l) def stembridgeDelta_depth(self, i, j): r""" @@ -672,7 +672,7 @@ def stembridgeDel_rise(self, i, j): """ if self.f(i) is None: return 0 - return self.phi(j)-self.f(i).phi(j) + return self.phi(j) - self.f(i).phi(j) def stembridgeTriple(self, i, j): r""" @@ -708,10 +708,10 @@ def stembridgeTriple(self, i, j): """ if self.e(i) is None: return None - b = self.stembridgeDelta_depth(i,j) - c = self.stembridgeDelta_rise(i,j) + b = self.stembridgeDelta_depth(i, j) + c = self.stembridgeDelta_rise(i, j) dd = self.cartan_type().dynkin_diagram() - a = dd[j,i] + a = dd[j, i] return (a, b, c) def _test_stembridge_local_axioms(self, index_set=None, verbose=False, **options): @@ -751,26 +751,26 @@ def _test_stembridge_local_axioms(self, index_set=None, verbose=False, **options from sage.combinat.subset import Subsets - for (i,j) in Subsets(index_set, 2): + for i, j in Subsets(index_set, 2): if self.e(i) is not None and self.e(j) is not None: - triple = self.stembridgeTriple(i,j) - #Test axioms P3 and P4. - if not triple[0] == triple[1]+triple[2] or triple[1] > 0 or triple[2] > 0: + triple = self.stembridgeTriple(i, j) + # Test axioms P3 and P4. + if not triple[0] == triple[1] + triple[2] or triple[1] > 0 or triple[2] > 0: if verbose: print('Warning: Failed axiom P3 or P4 at vector ', self, 'i,j=', i, j, 'Stembridge triple:', self.stembridgeTriple(i, j)) goodness = False else: tester.fail() - if self.stembridgeDelta_depth(i,j) == 0: - #check E_i E_j(x)= E_j E_i(x) + if self.stembridgeDelta_depth(i, j) == 0: + # check E_i E_j(x)= E_j E_i(x) if self.e(i).e(j) != self.e(j).e(i) or self.e(i).e(j).stembridgeDel_rise(j, i) != 0: if verbose: print('Warning: Failed axiom P5 at: vector ', self, 'i,j=', i, j, 'Stembridge triple:', self.stembridgeTriple(i, j)) goodness = False else: tester.fail() - if self.stembridgeDelta_depth(i,j) == -1 and self.stembridgeDelta_depth(j,i) == -1: - #check E_i E_j^2 E_i (x)= E_j E_i^2 E_j (x) + if self.stembridgeDelta_depth(i, j) == -1 and self.stembridgeDelta_depth(j, i) == -1: + # check E_i E_j^2 E_i (x)= E_j E_i^2 E_j (x) y1 = self.e(j).e(i).e(i).e(j) y2 = self.e(j).e(i).e(i).e(j) a = y1.stembridgeDel_rise(j, i) @@ -869,12 +869,12 @@ def dual_equivalence_class(self, index_set=None): if y not in visited: todo.add(y) from sage.graphs.graph import Graph - G = Graph([visited, edges], format='vertices_and_edges', - immutable=True, multiedges=True) + + G = Graph([visited, edges], format='vertices_and_edges', immutable=True, multiedges=True) from sage.graphs.dot2tex_utils import have_dot2tex + if have_dot2tex(): - G.set_latex_options(format='dot2tex', edge_labels=True, - color_by_label=self.cartan_type()._index_set_coloring) + G.set_latex_options(format='dot2tex', edge_labels=True, color_by_label=self.cartan_type()._index_set_coloring) return G class TensorProducts(TensorProductsCategory): @@ -882,6 +882,7 @@ class TensorProducts(TensorProductsCategory): The category of regular crystals constructed by tensor product of regular crystals. """ + @cached_method def extra_super_categories(self): """ diff --git a/src/sage/categories/regular_supercrystals.py b/src/sage/categories/regular_supercrystals.py index a1bcc10c3d5..9ef2235d334 100644 --- a/src/sage/categories/regular_supercrystals.py +++ b/src/sage/categories/regular_supercrystals.py @@ -92,6 +92,7 @@ class RegularSuperCrystals(Category_singleton): running ._test_rank() . . . pass running ._test_some_elements() . . . pass """ + def super_categories(self): r""" EXAMPLES:: @@ -157,6 +158,7 @@ class TensorProducts(TensorProductsCategory): The category of regular crystals constructed by tensor product of regular crystals. """ + @cached_method def extra_super_categories(self): """ diff --git a/src/sage/categories/right_modules.py b/src/sage/categories/right_modules.py index 47a8081d2a9..b0bb151e7c0 100644 --- a/src/sage/categories/right_modules.py +++ b/src/sage/categories/right_modules.py @@ -1,12 +1,13 @@ r""" Right modules """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category_types import Category_over_base_ring from sage.categories.commutative_additive_groups import CommutativeAdditiveGroups diff --git a/src/sage/categories/ring_ideals.py b/src/sage/categories/ring_ideals.py index fd634f1caef..15299ecdef2 100644 --- a/src/sage/categories/ring_ideals.py +++ b/src/sage/categories/ring_ideals.py @@ -1,6 +1,7 @@ r""" Ring ideals """ + # **************************************************************************** # Copyright (C) 2005 David Kohel # William Stein @@ -41,6 +42,7 @@ class RingIdeals(Category_ideal): - Make ``RingIdeals(R)``, return ``CommutativeRingIdeals(R)`` when ``R`` is commutative. """ + def __init__(self, R): """ EXAMPLES:: diff --git a/src/sage/categories/rings.py b/src/sage/categories/rings.py index d81e3109ff2..cd79878f107 100644 --- a/src/sage/categories/rings.py +++ b/src/sage/categories/rings.py @@ -1,6 +1,7 @@ r""" Rings """ + # **************************************************************************** # Copyright (C) 2005 David Kohel # William Stein @@ -58,6 +59,7 @@ class Rings(CategoryWithAxiom): - A parent P in the category ``Rings()`` should automatically be in the category ``Algebras(P)``. """ + _base_category_class_and_axiom = (Rngs, "Unital") class MorphismMethods: @@ -146,6 +148,7 @@ def is_injective(self) -> bool: return False from sage.categories.fields import Fields + if self.domain() in Fields(): # A ring homomorphism from a field to a ring is injective # (unless the codomain is the zero ring.) Note that ring @@ -163,11 +166,13 @@ def is_injective(self) -> bool: if self.codomain().characteristic() != 0: return False from sage.categories.integral_domains import IntegralDomains + if self.domain() in IntegralDomains(): # if all elements of the domain are algebraic over ZZ, # then the homomorphism must be injective (in # particular if the domain is ZZ) from sage.categories.number_fields import NumberFields + if self.domain().fraction_field() in NumberFields(): return True @@ -247,16 +252,17 @@ def extend_to_fraction_field(self): Defn: x |--> x + 1.00000000000000 """ from sage.rings.morphism import RingHomomorphism_from_fraction_field + if self.domain().is_field() and self.codomain().is_field(): return self try: if not self.is_injective(): raise ValueError("the morphism is not injective") - except (NotImplementedError, TypeError): # we trust the user + except (NotImplementedError, TypeError): # we trust the user pass domain = self.domain().fraction_field() codomain = self.codomain().fraction_field() - parent = domain.Hom(codomain) # category = category=self.category_for() ??? + parent = domain.Hom(codomain) # category = category=self.category_for() ??? return RingHomomorphism_from_fraction_field(parent, self) class SubcategoryMethods: @@ -504,9 +510,11 @@ def is_prime_field(self): # the case of QQ is handled by QQ itself from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_generic from sage.rings.rational_field import QQ + if isinstance(self, PolynomialQuotientRing_generic) and self.base_ring() is QQ: return self.absolute_degree() == 1 from sage.categories.finite_fields import FiniteFields + return self in FiniteFields() and self.absolute_degree() == 1 def is_zero(self) -> bool: @@ -710,6 +718,7 @@ def zeta(self, n=2, all=False): if P.degree() == 1: return -P[0] from sage.rings.integer_ring import ZZ + raise ValueError("no %s root of unity in %r" % (ZZ(n).ordinal_str(), self)) def zeta_order(self): @@ -814,6 +823,7 @@ def _Hom_(self, Y, category): if Y not in Rings(): raise TypeError(f"{Y} is not a ring") from sage.rings.homset import RingHomset + return RingHomset(self, Y, category=category) # this is already in sage.rings.ring.Ring, @@ -921,8 +931,10 @@ def __pow__(self, n): if isinstance(n, tuple): m, n = n from sage.matrix.matrix_space import MatrixSpace + return MatrixSpace(self, m, n) from sage.modules.free_module import FreeModule + return FreeModule(self, n) def nilradical(self): @@ -969,6 +981,7 @@ def characteristic(self): """ from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ + order_1 = self.one().additive_order() return ZZ.zero() if order_1 is infinity else order_1 @@ -993,6 +1006,7 @@ def _test_characteristic(self, **options): # test that #12988 is fixed from sage.rings.integer import Integer + tester.assertIsInstance(characteristic, Integer) def ideal(self, *args, **kwds): @@ -1098,6 +1112,7 @@ def ideal(self, *args, **kwds): coerce = True from sage.rings.ideal import Ideal_generic + if not args: gens = [self(0)] else: @@ -1128,6 +1143,7 @@ def ideal(self, *args, **kwds): gens = [self(g) for g in gens] from sage.categories.principal_ideal_domains import PrincipalIdealDomains + if self in PrincipalIdealDomains(): # Use GCD algorithm to obtain a principal ideal g = gens[0] @@ -1222,6 +1238,7 @@ def quotient(self, I, names=None, **kwds): False """ from sage.rings.quotient_ring import QuotientRing + return QuotientRing(self, I, names=names, **kwds) def quo(self, I, names=None, **kwds): @@ -1550,6 +1567,7 @@ def __getitem__(self, arg): To: Real Lazy Field Defn: a -> 1.414213562373095? """ + def normalize_arg(arg): if isinstance(arg, (tuple, list)): # Allowing arbitrary iterables would create confusion, @@ -1572,16 +1590,19 @@ def normalize_arg(arg): else: elts = normalize_arg(arg) from sage.rings.power_series_ring import PowerSeriesRing + return PowerSeriesRing(self, elts) if isinstance(arg, tuple): from sage.categories.morphism import Morphism + try: from sage.rings.derivation import RingDerivation except ImportError: RingDerivation = () if len(arg) == 2 and isinstance(arg[1], (Morphism, RingDerivation)): from sage.rings.polynomial.ore_polynomial_ring import OrePolynomialRing + return OrePolynomialRing(self, arg[1], names=arg[0]) # 2. Otherwise, if all specified elements are algebraic, try to @@ -1599,6 +1620,7 @@ def normalize_arg(arg): names = tuple(_gen_names(elts)) if len(elts) == 1: from sage.rings.cif import CIF + elt = elts[0] try: iv = CIF(elt) @@ -1614,6 +1636,7 @@ def normalize_arg(arg): # TODO: Rewrite using #19362 and/or #17886 and/or # #15600 once those issues are solved. from sage.rings.qqbar import AlgebraicNumber, ANRoot + try: elt = AlgebraicNumber(ANRoot(minpolys[0], iv)) except ValueError: @@ -1621,8 +1644,8 @@ def normalize_arg(arg): # Force a real embedding when possible, to get the # right ordered ring structure. from sage.rings.real_lazy import CLF, RLF - if (iv.imag().is_zero() or iv.imag().contains_zero() - and elt.imag().is_zero()): + + if iv.imag().is_zero() or iv.imag().contains_zero() and elt.imag().is_zero(): emb = RLF(elt) else: emb = CLF(elt) @@ -1637,6 +1660,7 @@ def normalize_arg(arg): # 2. Otherwise, try to return a polynomial ring from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + return PolynomialRing(self, elts) def free_module(self, base=None, basis=None, map=True): @@ -1695,6 +1719,7 @@ def free_module(self, base=None, basis=None, map=True): if not basis.is_unit(): raise ValueError("basis element must be a unit") from sage.modules.free_module_morphism import BaseIsomorphism1D_from_FM, BaseIsomorphism1D_to_FM + Hfrom = V.Hom(self) Hto = self.Hom(V) from_V = Hfrom.__make_element_class__(BaseIsomorphism1D_from_FM)(Hfrom, basis=basis) @@ -1949,6 +1974,7 @@ def _gen_names(elts): import re from sage.structure.category_object import certify_names from sage.combinat.words.words import Words + it = iter(Words("abcdefghijklmnopqrstuvwxyz", infinite=False)) next(it) # skip empty word for x in elts: diff --git a/src/sage/categories/rngs.py b/src/sage/categories/rngs.py index fcfd6fb7500..d6cd5eaa378 100644 --- a/src/sage/categories/rngs.py +++ b/src/sage/categories/rngs.py @@ -1,6 +1,7 @@ r""" Rngs """ + # **************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # 2012 Nicolas M. Thiery @@ -83,9 +84,11 @@ def ideal_monoid(self): """ try: from sage.rings.ideal_monoid import IdealMonoid + return IdealMonoid(self) except TypeError: from sage.rings.noncommutative_ideals import IdealMonoid_nc + return IdealMonoid_nc(self) def _ideal_class_(self, n=0): @@ -109,6 +112,7 @@ def _ideal_class_(self, n=0): """ from sage.rings.noncommutative_ideals import Ideal_nc + return Ideal_nc def principal_ideal(self, gen, coerce=True): diff --git a/src/sage/categories/schemes.py b/src/sage/categories/schemes.py index aea9492f233..725e7e84816 100644 --- a/src/sage/categories/schemes.py +++ b/src/sage/categories/schemes.py @@ -65,6 +65,7 @@ class Schemes(Category): sage: Schemes().Homsets().super_categories() [Category of homsets] """ + @staticmethod def __classcall_private__(cls, X=None): """ @@ -147,6 +148,7 @@ def _call_(self, x): return x from sage.categories.commutative_rings import CommutativeRings from sage.schemes.generic.spec import Spec + if x in CommutativeRings(): return Spec(x) if isinstance(x, Map) and x.category_for().is_subcategory(Rings()): @@ -170,6 +172,7 @@ class Schemes_over_base(Category_over_base): sage: C = Schemes(ZZ) sage: TestSuite(C).run() """ + def base_scheme(self): """ EXAMPLES:: @@ -196,6 +199,7 @@ def _repr_object_names(self): Category of schemes over Integer Ring """ from sage.schemes.generic.scheme import AffineScheme + base = self.base() if isinstance(base, AffineScheme): base = base.coordinate_ring() @@ -215,6 +219,7 @@ class AbelianVarieties(Schemes_over_base): ... ValueError: category of abelian varieties is only defined over fields """ + def __init__(self, base): r""" Constructor for the ``AbelianVarieties`` category. @@ -227,6 +232,7 @@ def __init__(self, base): Category of abelian varieties over Rational Field """ from sage.schemes.generic.scheme import AffineScheme + if isinstance(base, AffineScheme): base = base.coordinate_ring() if base not in Fields(): @@ -274,6 +280,7 @@ class Homsets(HomsetsCategory): sage: AbelianVarieties(QQ).Homsets().is_subcategory(CommutativeAdditiveGroups()) True """ + def extra_super_categories(self): r""" Register the homset as an additive abelian group. @@ -293,6 +300,7 @@ class Endset(CategoryWithAxiom): sage: AbelianVarieties(QQ).Endsets().is_subcategory(Rings()) True """ + def extra_super_categories(self): r""" Register the endset as a ring. @@ -318,6 +326,7 @@ class Jacobians(Schemes_over_base): sage: TestSuite(Jacobians(QQ)).run() """ + def __init__(self, base): r""" Constructor of this category. @@ -330,6 +339,7 @@ def __init__(self, base): Category of Jacobians over Rational Field """ from sage.schemes.generic.scheme import AffineScheme + if isinstance(base, AffineScheme): base = base.coordinate_ring() if base not in Fields(): diff --git a/src/sage/categories/semigroups.py b/src/sage/categories/semigroups.py index e6a171fa5f9..a8293b253eb 100644 --- a/src/sage/categories/semigroups.py +++ b/src/sage/categories/semigroups.py @@ -1,7 +1,8 @@ r""" Semigroups """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2005 David Kohel # William Stein # 2008 Teresa Gomez-Diaz (CNRS) @@ -10,7 +11,7 @@ # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method @@ -57,6 +58,7 @@ class Semigroups(CategoryWithAxiom): sage: TestSuite(C).run() """ + _base_category_class_and_axiom = (Magmas, "Associative") def example(self, choice='leftzero', **kwds): @@ -82,6 +84,7 @@ def example(self, choice='leftzero', **kwds): An example of a semigroup: the free semigroup generated by ('a', 'b') """ import sage.categories.examples.semigroups as examples + if choice == "leftzero": return examples.LeftZeroSemigroup(**kwds) return examples.FreeSemigroup(**kwds) @@ -115,6 +118,7 @@ def _test_associativity(self, **options): tester = self._tester(**options) S = tester.some_elements() from sage.misc.misc import some_tuples + for x, y, z in some_tuples(S, 3, tester._max_runs): tester.assertEqual((x * y) * z, x * (y * z)) @@ -166,11 +170,11 @@ def prod(self, args): AssertionError: Cannot compute an empty product in a semigroup """ from sage.misc.misc_c import prod + assert len(args) > 0, "Cannot compute an empty product in a semigroup" return prod(args[1:], args[0]) - def cayley_graph(self, side='right', simple=False, elements=None, - generators=None, connecting_set=None): + def cayley_graph(self, side='right', simple=False, elements=None, generators=None, connecting_set=None): r""" Return the Cayley graph for this finite semigroup. @@ -315,6 +319,7 @@ def cayley_graph(self, side='right', simple=False, elements=None, from sage.graphs.digraph import DiGraph from .monoids import Monoids from .groups import Groups + if side not in ["left", "right", "twosided"]: raise ValueError("option 'side' must be 'left', 'right' or 'twosided'") if elements is None: @@ -337,15 +342,15 @@ def cayley_graph(self, side='right', simple=False, elements=None, generators = self.semigroup_generators() if isinstance(generators, (list, tuple)): generators = {self(g): self(g) for g in generators} - left = (side == "left" or side == "twosided") - right = (side == "right" or side == "twosided") + left = side == "left" or side == "twosided" + right = side == "right" or side == "twosided" def add_edge(source, target, label, side_label): """ Skips edges whose targets are not in elements Return an appropriate edge given the options """ - if (elements is not self and target not in elements): + if elements is not self and target not in elements: return if simple: if source != target: @@ -354,10 +359,11 @@ def add_edge(source, target, label, side_label): result.add_edge([source, target, (label, side_label)]) else: result.add_edge([source, target, label]) + for x in elements: for i in generators.keys(): if left: - add_edge(x, generators[i] * x, i, "left" ) + add_edge(x, generators[i] * x, i, "left") if right: add_edge(x, x * generators[i], i, "right") return result @@ -434,8 +440,8 @@ def subsemigroup(self, generators, one=None, category=None): sage: TestSuite(M).run() # needs sage.combinat """ from sage.monoids.automatic_semigroup import AutomaticSemigroup - return AutomaticSemigroup(generators, ambient=self, one=one, - category=category) + + return AutomaticSemigroup(generators, ambient=self, one=one, category=category) def trivial_representation(self, base_ring=None, side='twosided'): r""" @@ -455,8 +461,10 @@ def trivial_representation(self, base_ring=None, side='twosided'): """ if base_ring is None: from sage.rings.integer_ring import ZZ + base_ring = ZZ from sage.modules.with_basis.representation import TrivialRepresentation + return TrivialRepresentation(self, base_ring) def regular_representation(self, base_ring=None, side='left'): @@ -475,8 +483,10 @@ def regular_representation(self, base_ring=None, side='left'): """ if base_ring is None: from sage.rings.integer_ring import ZZ + base_ring = ZZ from sage.modules.with_basis.representation import RegularRepresentation + return RegularRepresentation(self, base_ring, side) def representation(self, module, on_basis, side='left', *args, **kwargs): @@ -508,6 +518,7 @@ def representation(self, module, on_basis, side='left', *args, **kwargs): indexed by Subsets of {0,1,...,2} over Rational Field """ from sage.modules.with_basis.representation import Representation + return Representation(self, module, on_basis, side, *args, **kwargs) class ElementMethods: @@ -821,6 +832,7 @@ def example(self): An example of a (sub)quotient semigroup: a quotient of the left zero semigroup """ from sage.categories.examples.semigroups import QuotientOfLeftZeroSemigroup + return QuotientOfLeftZeroSemigroup(category=self.Subquotients()) class Quotients(QuotientsCategory): @@ -837,6 +849,7 @@ def example(self): An example of a (sub)quotient semigroup: a quotient of the left zero semigroup """ from sage.categories.examples.semigroups import QuotientOfLeftZeroSemigroup + return QuotientOfLeftZeroSemigroup() class ParentMethods: @@ -1055,4 +1068,5 @@ def representation(self, module, on_basis, side='left', *args, **kwargs): group indexed by {1, 2, 3, 4, 5} over Finite Field of size 2 """ from sage.modules.with_basis.representation import Representation + return Representation(self.group(), module, on_basis, side, *args, **kwargs) diff --git a/src/sage/categories/semirings.py b/src/sage/categories/semirings.py index 03755978b2e..9dde5bdd6ad 100644 --- a/src/sage/categories/semirings.py +++ b/src/sage/categories/semirings.py @@ -1,6 +1,7 @@ r""" Semirings """ + # **************************************************************************** # Copyright (C) 2010 Nicolas Borie # @@ -52,4 +53,5 @@ class Semirings(CategoryWithAxiom): sage: Semirings().example() An example of a semiring: the ternary-logic semiring """ + _base_category_class_and_axiom = (MagmasAndAdditiveMagmas.Distributive.AdditiveAssociative.AdditiveCommutative.AdditiveUnital.Associative, "Unital") diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index 9100f21aece..d23db6e88e4 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -1,12 +1,13 @@ r""" Semisimple Algebras """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2011-2015 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.algebras import Algebras from sage.categories.category_types import Category_over_base_ring @@ -55,6 +56,7 @@ class SemisimpleAlgebras(Category_over_base_ring): sage: TestSuite(C).run() """ + @staticmethod def __classget__(cls, base_category, base_category_class): """ diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 343079086a5..0e161ad7fd7 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1,6 +1,7 @@ r""" Sets """ + # **************************************************************************** # Copyright (C) 2005 David Kohel # William Stein @@ -35,6 +36,7 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.misc.lazy_import import lazy_import, LazyImport from sage.misc.lazy_format import LazyFormat + # Do not use sage.categories.all here to avoid initialization loop from sage.categories.category import Category from sage.categories.category_singleton import Category_singleton @@ -48,6 +50,7 @@ from sage.categories.realizations import RealizationsCategory, Category_realization_of_parent from sage.categories.with_realizations import WithRealizationsCategory from sage.categories.category_with_axiom import CategoryWithAxiom + lazy_import('sage.sets.cartesian_product', 'CartesianProduct') @@ -92,6 +95,7 @@ class EmptySetError(ValueError): ... EmptySetError: no elements """ + pass @@ -259,8 +263,10 @@ def _call_(self, X, enumerated_set=False): """ if enumerated_set and type(X) in (tuple, list, range): from sage.categories.enumerated_sets import EnumeratedSets + return EnumeratedSets()(X) from sage.sets.set import Set + return Set(X) def example(self, choice=None): @@ -285,15 +291,19 @@ def example(self, choice=None): """ if choice is None: from sage.categories.examples.sets_cat import PrimeNumbers + return PrimeNumbers() if choice == "inherits": from sage.categories.examples.sets_cat import PrimeNumbers_Inherits + return PrimeNumbers_Inherits() if choice == "facade": from sage.categories.examples.sets_cat import PrimeNumbers_Facade + return PrimeNumbers_Facade() if choice == "wrapper": from sage.categories.examples.sets_cat import PrimeNumbers_Wrapper + return PrimeNumbers_Wrapper() raise ValueError("unknown choice") @@ -677,6 +687,7 @@ def Topological(self): sage: TestSuite(Sets().Topological()).run() """ from sage.categories.topological_spaces import TopologicalSpacesCategory + return TopologicalSpacesCategory.category_of(self) @cached_method @@ -689,6 +700,7 @@ def Metric(self): sage: TestSuite(Sets().Metric()).run() """ from sage.categories.metric_spaces import MetricSpacesCategory + return MetricSpacesCategory.category_of(self) @cached_method @@ -728,8 +740,8 @@ def Algebras(self, base_ring): sage: TestSuite(Groups().Finite().Algebras(QQ)).run() """ from sage.categories.rings import Rings - assert base_ring in Rings() or (isinstance(base_ring, Category) - and base_ring.is_subcategory(Rings())) + + assert base_ring in Rings() or (isinstance(base_ring, Category) and base_ring.is_subcategory(Rings())) return AlgebrasCategory.category_of(self, base_ring) @cached_method @@ -1031,6 +1043,7 @@ def is_parent_of(self, element): (True, False) """ from sage.structure.element import parent + return parent(element) == self @abstract_method @@ -1105,11 +1118,11 @@ def _test_an_element(self, **options): except EmptySetError: return tester.assertIn(an_element, self, "self.an_element() is not in self") -# tester.assertTrue(self.is_parent_of(an_element), "self is not the parent of self.an_element()") -# tester.assertEqual(self(an_element), an_element, "element construction is not idempotent") + # tester.assertTrue(self.is_parent_of(an_element), "self is not the parent of self.an_element()") + # tester.assertEqual(self(an_element), an_element, "element construction is not idempotent") if self.is_parent_of(an_element): tester.assertEqual(self(an_element), an_element, "element construction is not idempotent") - else: # Allows self(an_element) to fails for facade parent. + else: # Allows self(an_element) to fails for facade parent. try: rebuilt_element = self(an_element) except NotImplementedError: @@ -1158,7 +1171,7 @@ def _test_elements(self, tester=None, **options): # The intention is to raise an exception only if this is # run as a sub-testsuite of a larger testsuite. - is_sub_testsuite = (tester is not None) + is_sub_testsuite = tester is not None tester = self._tester(tester=tester, **options) # Or do we want to run the test on some_elements? try: @@ -1166,9 +1179,7 @@ def _test_elements(self, tester=None, **options): except EmptySetError: return tester.info("\n Running the test suite of self.an_element()") - TestSuite(an_element).run(verbose=tester._verbose, - prefix=tester._prefix + " ", - raise_on_failure=is_sub_testsuite) + TestSuite(an_element).run(verbose=tester._verbose, prefix=tester._prefix + " ", raise_on_failure=is_sub_testsuite) tester.info(tester._prefix + " ", newline=False) def _test_elements_eq_reflexive(self, **options): @@ -1242,10 +1253,9 @@ def _test_elements_eq_symmetric(self, **options): tester = self._tester(**options) S = list(tester.some_elements()) + [None, 0] from sage.misc.misc import some_tuples + for x, y in some_tuples(S, 2, tester._max_runs): - tester.assertEqual(x == y, y == x, - LazyFormat("non symmetric equality: %s but %s") % ( - print_compare(x, y), print_compare(y, x))) + tester.assertEqual(x == y, y == x, LazyFormat("non symmetric equality: %s but %s") % (print_compare(x, y), print_compare(y, x))) def _test_elements_eq_transitive(self, **options): """ @@ -1273,12 +1283,13 @@ def _test_elements_eq_transitive(self, **options): tester = self._tester(**options) S = list(tester.some_elements()) n = max(tester._max_runs, 8) - if (len(S)+2)**3 <= n: + if (len(S) + 2) ** 3 <= n: S = list(S) + [None, 0] else: from random import sample from sage.rings.integer import Integer - S = sample(S, Integer(n).nth_root(3,truncate_mode=1)[0] - 2) + [None, 0] + + S = sample(S, Integer(n).nth_root(3, truncate_mode=1)[0] - 2) + [None, 0] for x in S: for y in S: @@ -1287,12 +1298,7 @@ def _test_elements_eq_transitive(self, **options): for z in S: if not y == z: continue - tester.assertEqual(x, z, - LazyFormat("non transitive equality:\n" - "%s and %s but %s") % ( - print_compare(x, y), - print_compare(y, z), - print_compare(x, z))) + tester.assertEqual(x, z, LazyFormat("non transitive equality:\n" "%s and %s but %s") % (print_compare(x, y), print_compare(y, z), print_compare(x, z))) def _test_elements_neq(self, **options): """ @@ -1332,11 +1338,9 @@ def _test_elements_neq(self, **options): S = list(tester.some_elements()) + [None, 0] from sage.misc.misc import some_tuples - for x,y in some_tuples(S, 2, tester._max_runs): - tester.assertNotEqual(x == y, x != y, - LazyFormat("__eq__ and __ne__ inconsistency:\n" - " %s == %s returns %s but %s != %s returns %s") % ( - x, y, (x == y), x, y, (x != y))) + + for x, y in some_tuples(S, 2, tester._max_runs): + tester.assertNotEqual(x == y, x != y, LazyFormat("__eq__ and __ne__ inconsistency:\n" " %s == %s returns %s but %s != %s returns %s") % (x, y, (x == y), x, y, (x != y))) def some_elements(self): """ @@ -1392,13 +1396,12 @@ def _test_some_elements(self, **options): tester = self._tester(**options) elements = self.some_elements() # Todo: enable this once - #tester.assertTrue(elements != iter(elements), + # tester.assertTrue(elements != iter(elements), # "self.some_elements() should return an iterable, not an iterator") for x in elements: - tester.assertIn(x, self, LazyFormat( - "the object %s in self.some_elements() is not in self") % (x,)) + tester.assertIn(x, self, LazyFormat("the object %s in self.some_elements() is not in self") % (x,)) - #Note: the four methods 'cardinality', 'is_finite_, 'is_empty' and + # Note: the four methods 'cardinality', 'is_finite_, 'is_empty' and # 'random_element' might or might not be implemented in the parent # objects. Most of the time a default implementation will be provided by # a subcategory of Sets. We do not declare them as optional abstract @@ -1433,14 +1436,14 @@ def _test_cardinality(self, **options): """ try: cardinality = self.cardinality() - except (AttributeError,NotImplementedError): + except (AttributeError, NotImplementedError): return from sage.structure.element import parent from sage.rings.infinity import Infinity from sage.rings.integer_ring import ZZ + tester = self._tester(**options) - tester.assertTrue(cardinality is Infinity or parent(cardinality) is ZZ, - "the output of the method cardinality must either be a Sage integer or infinity. Not {}.".format(type(cardinality))) + tester.assertTrue(cardinality is Infinity or parent(cardinality) is ZZ, "the output of the method cardinality must either be a Sage integer or infinity. Not {}.".format(type(cardinality))) # Functorial constructions @@ -1678,26 +1681,30 @@ def algebra(self, base_ring, category=None, **kwds): category = self.category() from sage.categories.semigroups import Semigroups from sage.categories.commutative_additive_semigroups import CommutativeAdditiveSemigroups + if category.is_subcategory(Semigroups()) and category.is_subcategory(CommutativeAdditiveSemigroups()): raise TypeError( -""" `S = {}` is both an additive and a multiplicative semigroup. + """ `S = {}` is both an additive and a multiplicative semigroup. Constructing its algebra is ambiguous. -Please use, e.g., S.algebra(QQ, category=Semigroups())""".format(self)) +Please use, e.g., S.algebra(QQ, category=Semigroups())""".format( + self + ) + ) from sage.categories.groups import Groups from sage.categories.additive_groups import AdditiveGroups from sage.algebras.group_algebra import GroupAlgebra_class + algebra_category = category.Algebras(base_ring) - if (category.is_subcategory(Groups()) - or category.is_subcategory(AdditiveGroups())): + if category.is_subcategory(Groups()) or category.is_subcategory(AdditiveGroups()): # Somewhat dirty hack to wrap non-atomic objects from sage.categories.modules_with_basis import ModulesWithBasis + if self not in ModulesWithBasis: if 'prefix' not in kwds: kwds['prefix'] = '' if 'bracket' not in kwds: kwds['bracket'] = False - result = GroupAlgebra_class(base_ring, self, - category=algebra_category, **kwds) + result = GroupAlgebra_class(base_ring, self, category=algebra_category, **kwds) result.__doc__ = Sets.ParentMethods.algebra.__doc__ return result @@ -1740,6 +1747,7 @@ def _sympy_(self): """ from sage.interfaces.sympy_wrapper import SageSet from sage.interfaces.sympy import sympy_init + sympy_init() return SageSet(self) @@ -1768,9 +1776,10 @@ def cartesian_product(*elements): FIXME: is this a policy that we want to enforce on all parents? """ from sage.structure.element import parent, Element + assert all(isinstance(element, Element) for element in elements) parents = [parent(element) for element in elements] - return cartesian_product(parents)._cartesian_product_of_elements(elements) # good name??? + return cartesian_product(parents)._cartesian_product_of_elements(elements) # good name??? class MorphismMethods: @abstract_method(optional=True) @@ -1867,6 +1876,7 @@ def image(self, domain_subset=None): domain_subset = D from sage.sets.set import Set_base from sage.sets.image_set import ImageSubobject, ImageSet + if isinstance(domain_subset, Set_base): # Most of our parents are sets, but the mixin class Set_base # provides the full kit of operators. The image should get them too. @@ -1878,10 +1888,8 @@ def image(self, domain_subset=None): # Lazy imports to avoid circularity issues. Enumerated = LazyImport('sage.categories.enumerated_sets', 'EnumeratedSets', at_startup=True) Finite = LazyImport('sage.categories.finite_sets', 'FiniteSets', at_startup=True) - Topological = LazyImport('sage.categories.topological_spaces', - 'TopologicalSpaces', 'Topological', at_startup=True) - Metric = LazyImport('sage.categories.metric_spaces', 'MetricSpaces', - 'Metric', at_startup=True) + Topological = LazyImport('sage.categories.topological_spaces', 'TopologicalSpaces', 'Topological', at_startup=True) + Metric = LazyImport('sage.categories.metric_spaces', 'MetricSpaces', 'Metric', at_startup=True) from sage.categories.facade_sets import FacadeSets as Facade class Infinite(CategoryWithAxiom): @@ -1947,6 +1955,7 @@ def cardinality(self): +Infinity """ from sage.rings.infinity import infinity + return infinity class Subquotients(SubquotientsCategory): @@ -2225,6 +2234,7 @@ def example(self): from .finite_enumerated_sets import FiniteEnumeratedSets from .infinite_enumerated_sets import InfiniteEnumeratedSets from .cartesian_product import cartesian_product + S1 = Sets().example() S2 = InfiniteEnumeratedSets().example() S3 = FiniteEnumeratedSets().example() @@ -2331,6 +2341,7 @@ def __iter__(self): factors = list(self.cartesian_factors()) if any(f not in Sets().Finite() for f in factors[1:]): from sage.misc.mrange import cantor_product + for t in cantor_product(*factors): yield self._cartesian_product_of_elements(t) return @@ -2344,7 +2355,7 @@ def __iter__(self): return while True: yield self._cartesian_product_of_elements(digits) - for i in range(len(digits)-1, -1, -1): + for i in range(len(digits) - 1, -1, -1): try: digits[i] = next(wheels[i]) break @@ -2522,17 +2533,20 @@ def cardinality(self): # Note: some parent might not implement "is_empty". So we # carefully isolate this test. is_empty = any(c.is_empty() for c in f) - except (AttributeError,NotImplementedError): + except (AttributeError, NotImplementedError): pass else: if is_empty: from sage.rings.integer_ring import ZZ + return ZZ.zero() if any(c in Sets().Infinite() for c in f): from sage.rings.infinity import Infinity + return Infinity from sage.misc.misc_c import prod + return prod(c.cardinality() for c in f) def random_element(self, *args): @@ -2562,8 +2576,7 @@ def random_element(self, *args): sage: all(4 <= i <= 7 for i in c2) True """ - return self._cartesian_product_of_elements( - c.random_element(*args) for c in self.cartesian_factors()) + return self._cartesian_product_of_elements(c.random_element(*args) for c in self.cartesian_factors()) @abstract_method def _sets_keys(self): @@ -2661,6 +2674,7 @@ def _sympy_(self): """ from sympy import ProductSet from sage.interfaces.sympy import sympy_init + sympy_init() return ProductSet(*self.cartesian_factors()) @@ -2714,9 +2728,8 @@ def cartesian_factors(self): [F, G, H] """ # TODO: optimize - return tuple(self.cartesian_projection(i) - for i in self.parent()._sets_keys()) - #return Family(self._sets.keys(), self.projection) + return tuple(self.cartesian_projection(i) for i in self.parent()._sets_keys()) + # return Family(self._sets.keys(), self.projection) class Algebras(AlgebrasCategory): @@ -2737,6 +2750,7 @@ def extra_super_categories(self): Category of objects] """ from sage.categories.modules_with_basis import ModulesWithBasis + return [ModulesWithBasis(self.base_ring())] class ParentMethods: @@ -2762,13 +2776,12 @@ def construction(self): sage: F(arg) is A # needs sage.groups sage.modules True """ - from sage.categories.algebra_functor import ( - GroupAlgebraFunctor, AlgebraFunctor) + from sage.categories.algebra_functor import GroupAlgebraFunctor, AlgebraFunctor + try: group = self.group() except AttributeError: - return (AlgebraFunctor(self.base_ring()), - self.basis().keys()) + return (AlgebraFunctor(self.base_ring()), self.basis().keys()) return GroupAlgebraFunctor(group), self.base_ring() def _repr_(self): @@ -2791,8 +2804,7 @@ def _repr_(self): """ if hasattr(self, "_name"): return self._name + " over {}".format(self.base_ring()) - return 'Algebra of {} over {}'.format(self.basis().keys(), - self.base_ring()) + return 'Algebra of {} over {}'.format(self.basis().keys(), self.base_ring()) class WithRealizations(WithRealizationsCategory): @@ -2824,11 +2836,13 @@ def example(self, base_ring=None, set=None): """ from sage.rings.rational_field import QQ from sage.sets.set import Set + if base_ring is None: base_ring = QQ if set is None: - set = Set([1,2,3]) + set = Set([1, 2, 3]) from sage.categories.examples.with_realizations import SubsetAlgebra + return SubsetAlgebra(base_ring, set) class ParentMethods: @@ -3015,6 +3029,7 @@ def inject_shorthands(self, shorthands=None, verbose=True): (True, True, True, True, True) """ from sage.misc.misc import inject_variable + if shorthands == 'all': shorthands = getattr(self, '_shorthands_all', None) if shorthands is None: diff --git a/src/sage/categories/sets_with_grading.py b/src/sage/categories/sets_with_grading.py index 6987f9e25f5..c84b7ce9f53 100644 --- a/src/sage/categories/sets_with_grading.py +++ b/src/sage/categories/sets_with_grading.py @@ -1,6 +1,7 @@ r""" Sets With a Grading """ + # **************************************************************************** # Copyright (C) 2010-2012 Nicolas M. Thiery # @@ -144,6 +145,7 @@ def grading_set(self): Non negative integers """ from sage.sets.non_negative_integers import NonNegativeIntegers + return NonNegativeIntegers() # TODO: @@ -221,6 +223,7 @@ def generating_series(self): from sage.rings.integer_ring import ZZ from sage.rings.lazy_series_ring import LazyPowerSeriesRing from sage.sets.non_negative_integers import NonNegativeIntegers + if isinstance(self.grading_set(), NonNegativeIntegers): R = LazyPowerSeriesRing(ZZ, names='z') return R(lambda n: self.graded_component(n).cardinality()) diff --git a/src/sage/categories/sets_with_partial_maps.py b/src/sage/categories/sets_with_partial_maps.py index 659652b59c7..3681db0100c 100644 --- a/src/sage/categories/sets_with_partial_maps.py +++ b/src/sage/categories/sets_with_partial_maps.py @@ -1,14 +1,15 @@ r""" SetsWithPartialMaps """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 David Kohel and # William Stein # Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category_singleton import Category_singleton from sage.categories.objects import Objects @@ -37,7 +38,8 @@ class SetsWithPartialMaps(Category_singleton): sage: TestSuite(SetsWithPartialMaps()).run() """ - #def __call__(self, X, pt): + + # def __call__(self, X, pt): # import sage.sets.all # return sage.sets.all.Set(X, pt) diff --git a/src/sage/categories/shephard_groups.py b/src/sage/categories/shephard_groups.py index 19c10efec90..7fab766f317 100644 --- a/src/sage/categories/shephard_groups.py +++ b/src/sage/categories/shephard_groups.py @@ -1,7 +1,8 @@ r""" Shephard Groups """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2016 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -9,7 +10,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.category_singleton import Category_singleton from sage.categories.generalized_coxeter_groups import GeneralizedCoxeterGroups @@ -30,6 +31,7 @@ class ShephardGroups(Category_singleton): sage: TestSuite(C).run() """ + @cached_method def super_categories(self): """ diff --git a/src/sage/categories/signed_tensor.py b/src/sage/categories/signed_tensor.py index c5281b7275a..4b6108e7b68 100644 --- a/src/sage/categories/signed_tensor.py +++ b/src/sage/categories/signed_tensor.py @@ -5,6 +5,7 @@ - Travis Scrimshaw (2019-07): initial version """ + # **************************************************************************** # Copyright (C) 2019 Travis Scrimshaw # @@ -52,6 +53,7 @@ class SignedTensorProductFunctor(CovariantFunctorialConstruction): sage: TestSuite(tensor_signed).run() """ + _functor_name = "tensor" _functor_category = "SignedTensorProducts" symbol = " # " @@ -88,6 +90,7 @@ class SignedTensorProductsCategory(CovariantConstructionCategory): \mathbf{SignedTensorProducts}(\mathbf{GradedAlgebrasWithBasis}(\mathbf{AlgebrasWithBasis}_{\Bold{Q}})) sage: TestSuite(C).run() """ + _functor_category = "SignedTensorProducts" def SignedTensorProducts(self): diff --git a/src/sage/categories/simplicial_complexes.py b/src/sage/categories/simplicial_complexes.py index c6a57b6e754..db1efc69ebe 100644 --- a/src/sage/categories/simplicial_complexes.py +++ b/src/sage/categories/simplicial_complexes.py @@ -1,18 +1,20 @@ """ Simplicial Complexes """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2015 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method from sage.categories.category_singleton import Category_singleton from sage.categories.category_with_axiom import CategoryWithAxiom -#from sage.categories.cw_complexes import CWComplexes + +# from sage.categories.cw_complexes import CWComplexes from sage.categories.sets_cat import Sets @@ -43,6 +45,7 @@ class SimplicialComplexes(Category_singleton): sage: TestSuite(C).run() """ + @cached_method def super_categories(self): """ @@ -60,6 +63,7 @@ class Finite(CategoryWithAxiom): """ Category of finite simplicial complexes. """ + class ParentMethods: @cached_method def dimension(self): diff --git a/src/sage/categories/simplicial_sets.py b/src/sage/categories/simplicial_sets.py index 6cf029aca18..600aea265ad 100644 --- a/src/sage/categories/simplicial_sets.py +++ b/src/sage/categories/simplicial_sets.py @@ -1,6 +1,7 @@ """ Simplicial Sets """ + # **************************************************************************** # Copyright (C) 2015 John H. Palmieri # @@ -59,6 +60,7 @@ class SimplicialSets(Category_singleton): sage: TestSuite(C).run() """ + @cached_method def super_categories(self): """ @@ -147,11 +149,11 @@ def set_base_point(self, point): ValueError: the point is not a simplex in this simplicial set """ from sage.topology.simplicial_set import SimplicialSet + if point.dimension() != 0: raise ValueError('the "point" is not a zero-simplex') if point not in self._simplices: - raise ValueError('the point is not a simplex in this ' - 'simplicial set') + raise ValueError('the point is not a simplex in this ' 'simplicial set') return SimplicialSet(self.face_data(), base_point=point) class Homsets(HomsetsCategory): @@ -169,9 +171,8 @@ def one(self): Defn: Identity map """ from sage.topology.simplicial_set_morphism import SimplicialSetMorphism - return SimplicialSetMorphism(domain=self.domain(), - codomain=self.codomain(), - identity=True) + + return SimplicialSetMorphism(domain=self.domain(), codomain=self.codomain(), identity=True) class Finite(CategoryWithAxiom): """ @@ -180,6 +181,7 @@ class Finite(CategoryWithAxiom): The objects are simplicial sets with finitely many non-degenerate simplices. """ + pass class SubcategoryMethods: @@ -263,6 +265,7 @@ def base_point_map(self, domain=None): Defn: Constant map at 1 """ from sage.topology.simplicial_set_examples import Point + if domain is None: domain = Point() else: @@ -345,6 +348,7 @@ def fundamental_group(self, simplify=True): """ # Import this here to prevent importing libgap upon startup. from sage.groups.free_group import FreeGroup + if not self.n_cells(1): return FreeGroup([]).quotient([]) FG = self._universal_cover_dict()[0] @@ -366,6 +370,7 @@ def _universal_cover_dict(self): [1, f, f * f] """ from sage.groups.free_group import FreeGroup + graph = self.graph() if not self.is_connected(): graph = graph.subgraph(self.base_point()) @@ -388,7 +393,7 @@ def _universal_cover_dict(self): else: # sigma is not in the correct connected component. z[i] = FG.one() - rels.append(z[0]*z[1].inverse()*z[2]) + rels.append(z[0] * z[1].inverse() * z[2]) G = FG.quotient(rels) char = {g: G.gen(i) for i, g in enumerate(gens)} for e in edges: @@ -470,6 +475,7 @@ def covering_map(self, character): """ from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet from sage.topology.simplicial_set_morphism import SimplicialSetMorphism + char = dict(character.items()) G = list(char.values())[0].parent() if not G.is_finite(): @@ -502,7 +508,7 @@ def covering_map(self, character): faces = self.faces(s) f0 = faces[0] for h in G: - if h == g*char[s]: + if h == g * char[s]: lifted = h break grelems = [cells_dict[(f0.nondegenerate(), lifted)].apply_degeneracies(*f0.degeneracies())] @@ -617,12 +623,10 @@ def _canonical_twisting_operator(self): QRP = R.quotient_ring(I) res = {} for s, el in d.items(): - res[s] = QRP(prod(images[abs(a)-1]**sign(a) for a in el.Tietze())) + res[s] = QRP(prod(images[abs(a) - 1] ** sign(a) for a in el.Tietze())) return res - def twisted_chain_complex(self, twisting_operator=None, dimensions=None, augmented=False, - cochain=False, verbose=False, subcomplex=None, - check=False): + def twisted_chain_complex(self, twisting_operator=None, dimensions=None, augmented=False, cochain=False, verbose=False, subcomplex=None, check=False): r""" Return the normalized chain complex twisted by some operator. @@ -706,6 +710,7 @@ def twisted_chain_complex(self, twisting_operator=None, dimensions=None, augment """ from sage.homology.chain_complex import ChainComplex from sage.structure.element import get_coercion_model + cm = get_coercion_model() if twisting_operator: @@ -723,15 +728,14 @@ def twist(s): if s.dimension() > 1: return twist(self.face(s, s.dimension())) return 1 + base_ring = cm.common_parent(*twop.values()) if dimensions is None: if not self.cells(): # Empty if cochain: - return ChainComplex({-1: matrix(base_ring, 0, 0)}, - degree_of_differential=1) - return ChainComplex({0: matrix(base_ring, 0, 0)}, - degree_of_differential=-1) + return ChainComplex({-1: matrix(base_ring, 0, 0)}, degree_of_differential=1) + return ChainComplex({0: matrix(base_ring, 0, 0)}, degree_of_differential=-1) dimensions = list(range(self.dimension() + 1)) else: if not isinstance(dimensions, (list, tuple, range)): @@ -770,9 +774,8 @@ def twist(s): rank = 0 current = [] if augmented and first == 0: - differentials[first-1] = matrix(base_ring, 0, 1) - differentials[first] = matrix(base_ring, 1, rank, - [1] * rank) + differentials[first - 1] = matrix(base_ring, 0, 1) + differentials[first] = matrix(base_ring, 1, rank, [1] * rank) else: differentials[first] = matrix(base_ring, 0, rank) @@ -794,17 +797,16 @@ def twist(s): sign = 1 twists = len(face_data[sigma]) * [1] twists[0] = twist(sigma) - for (ch, tau) in zip(twists, face_data[sigma]): + for ch, tau in zip(twists, face_data[sigma]): if tau.is_nondegenerate(): row = faces[tau] if (row, col) in matrix_data: - matrix_data[(row, col)] += sign*ch + matrix_data[(row, col)] += sign * ch else: - matrix_data[(row, col)] = sign*ch + matrix_data[(row, col)] = sign * ch sign *= -1 - differentials[d] = matrix(base_ring, old_rank, - rank, matrix_data, sparse=False) + differentials[d] = matrix(base_ring, old_rank, rank, matrix_data, sparse=False) else: rank = 0 @@ -812,12 +814,9 @@ def twist(s): differentials[d] = matrix(base_ring, old_rank, rank, sparse=False) if cochain: - new_diffs = {d - 1: diff_d.transpose() - for d, diff_d in differentials.items()} - return ChainComplex(new_diffs, degree_of_differential=1, - check=check) - return ChainComplex(differentials, degree_of_differential=-1, - check=check) + new_diffs = {d - 1: diff_d.transpose() for d, diff_d in differentials.items()} + return ChainComplex(new_diffs, degree_of_differential=1, check=check) + return ChainComplex(differentials, degree_of_differential=-1, check=check) def twisted_homology(self, n, reduced=False): r""" @@ -900,6 +899,7 @@ def twisted_homology(self, n, reduced=False): """ from sage.libs.singular.function import singular_function from sage.libs.singular.option import opt_verb + opt_verb['not_warn_sb'] = True singstd = singular_function("std") singsyz = singular_function("syz") @@ -915,12 +915,13 @@ def convert_to_polynomial(p): if hasattr(p, "lift"): return p.lift()._as_extended_polynomial() return p._as_extended_polynomial() + M1 = M1.apply_map(convert_to_polynomial) M2 = M2.apply_map(convert_to_polynomial) RP = R._extended_ring IP = RP.ideal([convert_to_polynomial(g) for g in I]) JP = R._extended_ring_ideal - GB = (IP+JP).groebner_basis() + GB = (IP + JP).groebner_basis() GBI = RP.ideal(GB) def reduce_laurent(a): @@ -930,9 +931,9 @@ def group_to_polynomial(el, RP): res = RP.one() for a in el.Tietze(): if a > 0: - res *= RP.gen(2*a-2) + res *= RP.gen(2 * a - 2) else: - res *= RP.gen(-2*a-1) + res *= RP.gen(-2 * a - 1) return res def mkernel(M): @@ -942,8 +943,8 @@ def mkernel(M): return M.T res = M n = res.ncols() - for g in (IP+JP).gens(): - res = res.stack(g*identity_matrix(n)) + for g in (IP + JP).gens(): + res = res.stack(g * identity_matrix(n)) syz = matrix(singsyz(res.T, ring=res.base_ring())).T trimmed = syz.T.submatrix(0, 0, syz.ncols(), M.nrows()) trimmed = trimmed.apply_map(reduce_laurent) @@ -955,7 +956,7 @@ def lift_to_submodule(S, M): return S res = M for g in GB: - res = res.stack(g*identity_matrix(M.ncols())) + res = res.stack(g * identity_matrix(M.ncols())) singres = matrix(singlift(res.T, S.T, ring=res.base_ring())) return singres.submatrix(0, 0, M.nrows(), S.nrows()) @@ -964,7 +965,7 @@ def mgb(M): return M res = M for g in GB: - res = res.stack(g*identity_matrix(M.ncols())) + res = res.stack(g * identity_matrix(M.ncols())) sres = matrix(singstd(res.T, ring=RP)) to_delete = [i for i, r in enumerate(sres.apply_map(reduce_laurent)) if not r] return sres.delete_rows(to_delete) @@ -988,7 +989,7 @@ def mgb(M): SM = AM.submodule([]) opt_verb.reset_default() return AM.quotient_module(SM) - for g in (IP+JP).gens(): + for g in (IP + JP).gens(): resmat = resmat.stack(g * identity_matrix(resmat.ncols())) if reduced: resmat = matrix(singstd(resmat.T, ring=RP)) @@ -1050,8 +1051,7 @@ def is_simply_connected(self): # code reaches this point, but there are certainly # groups for which these errors are raised. 'IsTrivial' # works for all of the examples I've seen, though. - raise ValueError('unable to determine if the fundamental ' - 'group is trivial') + raise ValueError('unable to determine if the fundamental ' 'group is trivial') def connectivity(self, max_dim=None): """ @@ -1104,14 +1104,12 @@ def connectivity(self, max_dim=None): # Note: at the moment, this will never be reached, # because our only examples (so far) of infinite # simplicial sets are not simply connected. - raise ValueError('this simplicial set may be infinite, ' - 'so specify a maximum dimension through ' - 'which to check') + raise ValueError('this simplicial set may be infinite, ' 'so specify a maximum dimension through ' 'which to check') H = self.homology(range(2, max_dim + 1)) for i in range(2, max_dim + 1): if i in H and H[i].order() != 1: - return i-1 + return i - 1 return Infinity class Finite(CategoryWithAxiom): @@ -1139,6 +1137,7 @@ def unset_base_point(self): False """ from sage.topology.simplicial_set import SimplicialSet + return SimplicialSet(self.face_data()) def fat_wedge(self, n): @@ -1166,11 +1165,12 @@ def fat_wedge(self, n): {0: 0, 1: Z x Z x Z x Z, 2: Z^6, 3: Z x Z x Z x Z} """ from sage.topology.simplicial_set_examples import Point + if n == 0: return Point() if n == 1: return self - return self.product(*[self]*(n-1)).fat_wedge_as_subset() + return self.product(*[self] * (n - 1)).fat_wedge_as_subset() def smash_product(self, *others): """ @@ -1198,4 +1198,5 @@ def smash_product(self, *others): {0: Z, 1: 0, 2: Z x Z, 3: Z} """ from sage.topology.simplicial_set_constructions import SmashProductOfSimplicialSets_finite + return SmashProductOfSimplicialSets_finite((self,) + others) diff --git a/src/sage/categories/subobjects.py b/src/sage/categories/subobjects.py index 0456b0689a5..4a0a7c0c3e6 100644 --- a/src/sage/categories/subobjects.py +++ b/src/sage/categories/subobjects.py @@ -5,12 +5,13 @@ - Nicolas M. Thiery (2010): initial revision """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2009 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.category import Category from sage.categories.covariant_functorial_construction import RegressiveCovariantConstructionCategory diff --git a/src/sage/categories/subquotients.py b/src/sage/categories/subquotients.py index 34fcc3bcfe1..6cbc97d70c2 100644 --- a/src/sage/categories/subquotients.py +++ b/src/sage/categories/subquotients.py @@ -5,12 +5,13 @@ - Nicolas M. Thiery (2010): initial revision """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2009 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.covariant_functorial_construction import RegressiveCovariantConstructionCategory diff --git a/src/sage/categories/super_algebras.py b/src/sage/categories/super_algebras.py index 697328fd10e..d8a555bd0d0 100644 --- a/src/sage/categories/super_algebras.py +++ b/src/sage/categories/super_algebras.py @@ -1,6 +1,7 @@ r""" Super Algebras """ + # **************************************************************************** # Copyright (C) 2015 Travis Scrimshaw # @@ -40,6 +41,7 @@ class SuperAlgebras(SuperModulesCategory): sage: TestSuite(Algebras(ZZ).Super()).run() """ + def extra_super_categories(self): """ EXAMPLES:: @@ -50,8 +52,7 @@ def extra_super_categories(self): """ return [self.base_category().Graded()] - Supercommutative = LazyImport('sage.categories.supercommutative_algebras', - 'SupercommutativeAlgebras') + Supercommutative = LazyImport('sage.categories.supercommutative_algebras', 'SupercommutativeAlgebras') class ParentMethods: def graded_algebra(self): diff --git a/src/sage/categories/super_algebras_with_basis.py b/src/sage/categories/super_algebras_with_basis.py index 12e68e1674a..16134f8f3c0 100644 --- a/src/sage/categories/super_algebras_with_basis.py +++ b/src/sage/categories/super_algebras_with_basis.py @@ -1,6 +1,7 @@ r""" Super algebras with basis """ + # **************************************************************************** # Copyright (C) 2015,2019 Travis Scrimshaw # @@ -26,6 +27,7 @@ class SuperAlgebrasWithBasis(SuperModulesCategory): sage: TestSuite(C).run() """ + def extra_super_categories(self): """ EXAMPLES:: @@ -58,6 +60,7 @@ def graded_algebra(self): polynomials in x, y over Rational Field """ from sage.algebras.associated_graded import AssociatedGradedAlgebra + return AssociatedGradedAlgebra(self) class ElementMethods: @@ -115,10 +118,10 @@ def supercommutator(self, x): ret = P.zero() for ms, cs in self: term_s = P.term(ms, cs) - sign_s = (-1)**P.degree_on_basis(ms) + sign_s = (-1) ** P.degree_on_basis(ms) for mx, cx in x: ret += term_s * P.term(mx, cx) - s = sign_s**P.degree_on_basis(mx) + s = sign_s ** P.degree_on_basis(mx) ret -= s * P.term(mx, cx) * term_s return ret @@ -127,6 +130,7 @@ class SignedTensorProducts(SignedTensorProductsCategory): The category of super algebras with basis constructed by tensor product of super algebras with basis. """ + @cached_method def extra_super_categories(self): """ diff --git a/src/sage/categories/super_hopf_algebras_with_basis.py b/src/sage/categories/super_hopf_algebras_with_basis.py index 89940e3eeca..b11f1a5e99e 100644 --- a/src/sage/categories/super_hopf_algebras_with_basis.py +++ b/src/sage/categories/super_hopf_algebras_with_basis.py @@ -1,6 +1,7 @@ r""" Super Hopf algebras with basis """ + # **************************************************************************** # Copyright (C) 2015 Travis Scrimshaw # @@ -29,6 +30,7 @@ class SuperHopfAlgebrasWithBasis(SuperModulesCategory): sage: C = HopfAlgebras(ZZ).WithBasis().Super() sage: TestSuite(C).run() """ + class ParentMethods: @lazy_attribute def antipode(self): @@ -55,8 +57,7 @@ def antipode(self): """ if self.antipode_on_basis is not NotImplemented: # Should give the information that this is an anti-morphism of algebra - return self._module_morphism(self.antipode_on_basis, - codomain=self) + return self._module_morphism(self.antipode_on_basis, codomain=self) if hasattr(self, "antipode_by_coercion"): return self.antipode_by_coercion @@ -95,11 +96,9 @@ def _test_antipode(self, **options): S = self.antipode - IS = lambda x: self.sum(c * self.monomial(t1) * S(self.monomial(t2)) - for ((t1, t2), c) in x.coproduct()) + IS = lambda x: self.sum(c * self.monomial(t1) * S(self.monomial(t2)) for ((t1, t2), c) in x.coproduct()) - SI = lambda x: self.sum(c * S(self.monomial(t1)) * self.monomial(t2) - for ((t1, t2), c) in x.coproduct()) + SI = lambda x: self.sum(c * S(self.monomial(t1)) * self.monomial(t2) for ((t1, t2), c) in x.coproduct()) for x in tester.some_elements(): x_even = x.even_component() @@ -109,14 +108,10 @@ def _test_antipode(self, **options): y_odd = y.odd_component() # The antipode is a graded anti-homomorphism. - tester.assertEqual(S(x_even) * S(y_even), - S(y_even * x_even)) - tester.assertEqual(S(x_even) * S(y_odd), - S(y_odd * x_even)) - tester.assertEqual(S(x_odd) * S(y_even), - S(y_even * x_odd)) - tester.assertEqual(S(x_odd) * S(y_odd), - -S(y_odd * x_odd)) + tester.assertEqual(S(x_even) * S(y_even), S(y_even * x_even)) + tester.assertEqual(S(x_even) * S(y_odd), S(y_odd * x_even)) + tester.assertEqual(S(x_odd) * S(y_even), S(y_even * x_odd)) + tester.assertEqual(S(x_odd) * S(y_odd), -S(y_odd * x_odd)) # mu * (S # I) * delta == counit * unit tester.assertEqual(SI(x), self.counit(x) * self.one()) diff --git a/src/sage/categories/super_lie_conformal_algebras.py b/src/sage/categories/super_lie_conformal_algebras.py index 04b25cfe541..5ef01bb72db 100644 --- a/src/sage/categories/super_lie_conformal_algebras.py +++ b/src/sage/categories/super_lie_conformal_algebras.py @@ -6,7 +6,7 @@ - Reimundo Heluani (2019-10-05): Initial implementation. """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2019 Reimundo Heluani # # This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.graded_modules import GradedModulesCategory from sage.categories.super_modules import SuperModulesCategory @@ -40,6 +40,7 @@ class SuperLieConformalAlgebras(SuperModulesCategory): sage: [g.is_even_odd() for g in R.gens()] # needs sage.combinat sage.modules [0, 0] """ + def extra_super_categories(self): """ The extra super categories of ``self``. @@ -61,8 +62,8 @@ def example(self): sage: LieConformalAlgebras(QQ).Super().example() # needs sage.combinat sage.modules The Neveu-Schwarz super Lie conformal algebra over Rational Field """ - from sage.algebras.lie_conformal_algebras.neveu_schwarz_lie_conformal_algebra\ - import NeveuSchwarzLieConformalAlgebra + from sage.algebras.lie_conformal_algebras.neveu_schwarz_lie_conformal_algebra import NeveuSchwarzLieConformalAlgebra + return NeveuSchwarzLieConformalAlgebra(self.base_ring()) class ParentMethods: @@ -125,8 +126,9 @@ def _test_jacobi(self, **options): S = elements from sage.misc.misc import some_tuples from sage.arith.misc import binomial + pz = tester._instance.zero() - for x,y,z in some_tuples(S, 3, tester._max_runs): + for x, y, z in some_tuples(S, 3, tester._max_runs): if x.is_zero() or y.is_zero(): sgn = 1 elif x.is_even_odd() * y.is_even_odd(): @@ -136,22 +138,21 @@ def _test_jacobi(self, **options): brxy = x.bracket(y) brxz = x.bracket(z) bryz = y.bracket(z) - br1 = {k: x.bracket(v) for k,v in bryz.items()} - br2 = {k: v.bracket(z) for k,v in brxy.items()} - br3 = {k: y.bracket(v) for k,v in brxz.items()} - jac1 = {(j,k): v for k in br1 for j,v in br1[k].items()} - jac3 = {(k,j): v for k in br3 for j,v in br3[k].items()} + br1 = {k: x.bracket(v) for k, v in bryz.items()} + br2 = {k: v.bracket(z) for k, v in brxy.items()} + br3 = {k: y.bracket(v) for k, v in brxz.items()} + jac1 = {(j, k): v for k in br1 for j, v in br1[k].items()} + jac3 = {(k, j): v for k in br3 for j, v in br3[k].items()} jac2 = {} - for k,br in br2.items(): - for j,v in br.items(): - for r in range(j+1): - jac2[(k+r, j-r)] = (jac2.get((k+r, j-r), pz) - + binomial(k+r, r)*v) - for k,v in jac2.items(): + for k, br in br2.items(): + for j, v in br.items(): + for r in range(j + 1): + jac2[(k + r, j - r)] = jac2.get((k + r, j - r), pz) + binomial(k + r, r) * v + for k, v in jac2.items(): jac1[k] = jac1.get(k, pz) - v - for k,v in jac3.items(): - jac1[k] = jac1.get(k, pz) - sgn*v - jacobiator = {k: v for k,v in jac1.items() if v} + for k, v in jac3.items(): + jac1[k] = jac1.get(k, pz) - sgn * v + jacobiator = {k: v for k, v in jac1.items() if v} tester.assertDictEqual(jacobiator, {}) class ElementMethods: @@ -180,6 +181,7 @@ class Graded(GradedModulesCategory): sage: LieConformalAlgebras(AA).Super().Graded() # needs sage.rings.number_field Category of H-graded super Lie conformal algebras over Algebraic Real Field """ + def _repr_object_names(self): """ The names of the objects of this category. diff --git a/src/sage/categories/super_modules.py b/src/sage/categories/super_modules.py index 267a151a5fa..b7b6543bfe2 100644 --- a/src/sage/categories/super_modules.py +++ b/src/sage/categories/super_modules.py @@ -1,27 +1,43 @@ r""" Super modules """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2015 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category_types import Category_over_base_ring from sage.categories.covariant_functorial_construction import CovariantConstructionCategory # Note, a commutative algebra is not a commutative super algebra, # therefore the following whitelist. -axiom_whitelist = frozenset(["Facade", "Finite", "Infinite", - "FiniteDimensional", "Connected", "WithBasis", - "FinitelyGeneratedAsLambdaBracketAlgebra", - # "Commutative", "Cocommutative", - "Supercommutative", "Supercocommutative", - "Associative", "Inverse", "Unital", "Division", - "AdditiveCommutative", "AdditiveAssociative", - "AdditiveInverse", "AdditiveUnital", - "NoZeroDivisors", "Distributive"]) +axiom_whitelist = frozenset( + [ + "Facade", + "Finite", + "Infinite", + "FiniteDimensional", + "Connected", + "WithBasis", + "FinitelyGeneratedAsLambdaBracketAlgebra", + # "Commutative", "Cocommutative", + "Supercommutative", + "Supercocommutative", + "Associative", + "Inverse", + "Unital", + "Division", + "AdditiveCommutative", + "AdditiveAssociative", + "AdditiveInverse", + "AdditiveUnital", + "NoZeroDivisors", + "Distributive", + ] +) class SuperModulesCategory(CovariantConstructionCategory, Category_over_base_ring): @@ -113,6 +129,7 @@ class SuperModules(SuperModulesCategory): sage: TestSuite(Modules(ZZ).Super()).run() """ + def super_categories(self): """ EXAMPLES:: @@ -157,6 +174,7 @@ def extra_super_categories(self): """ from sage.categories.modules import Modules from sage.categories.fields import Fields + base_ring = self.base_ring() if base_ring in Fields(): return [Modules(base_ring)] diff --git a/src/sage/categories/super_modules_with_basis.py b/src/sage/categories/super_modules_with_basis.py index b872f3694e8..4755c10930d 100644 --- a/src/sage/categories/super_modules_with_basis.py +++ b/src/sage/categories/super_modules_with_basis.py @@ -1,12 +1,13 @@ r""" Super modules with basis """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2015 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.super_modules import SuperModulesCategory @@ -34,6 +35,7 @@ class SuperModulesWithBasis(SuperModulesCategory): sage: TestSuite(C).run() """ + class ParentMethods: def _even_odd_on_basis(self, m): """ @@ -161,9 +163,7 @@ def even_component(self): True """ even_odd = self.parent()._even_odd_on_basis - return self.parent().sum_of_terms((i, c) - for (i, c) in self - if even_odd(i) == 0) + return self.parent().sum_of_terms((i, c) for (i, c) in self if even_odd(i) == 0) def odd_component(self): """ @@ -187,6 +187,4 @@ def odd_component(self): True """ even_odd = self.parent()._even_odd_on_basis - return self.parent().sum_of_terms((i, c) - for (i, c) in self - if even_odd(i) == 1) + return self.parent().sum_of_terms((i, c) for (i, c) in self if even_odd(i) == 1) diff --git a/src/sage/categories/supercommutative_algebras.py b/src/sage/categories/supercommutative_algebras.py index 2623b1f68fe..0f890360d25 100644 --- a/src/sage/categories/supercommutative_algebras.py +++ b/src/sage/categories/supercommutative_algebras.py @@ -1,12 +1,13 @@ r""" Supercommutative Algebras """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2019 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.super_algebras import SuperAlgebras @@ -39,6 +40,7 @@ class SupercommutativeAlgebras(CategoryWithAxiom_over_base_ring): sage: TestSuite(Algebras(ZZ).Supercommutative()).run() """ + _base_category_class_and_axiom = (SuperAlgebras, "Supercommutative") class SignedTensorProducts(SignedTensorProductsCategory): @@ -92,7 +94,6 @@ def _test_supercommutativity(self, **options): elements = options.pop("elements", self.basis()) tester = self._tester(**options) from sage.misc.misc import some_tuples - for x,y in some_tuples(elements, 2, tester._max_runs): - tester.assertEqual((x * y), - (-1)**(x.is_even_odd() * y.is_even_odd()) - * (y * x)) + + for x, y in some_tuples(elements, 2, tester._max_runs): + tester.assertEqual((x * y), (-1) ** (x.is_even_odd() * y.is_even_odd()) * (y * x)) diff --git a/src/sage/categories/supercrystals.py b/src/sage/categories/supercrystals.py index af0c8f881a0..7167c5bedbf 100644 --- a/src/sage/categories/supercrystals.py +++ b/src/sage/categories/supercrystals.py @@ -3,7 +3,7 @@ Supercrystals """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2017 Franco Saliola # 2017 Anne Schilling # 2019 Travis Scrimshaw @@ -13,7 +13,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.cachefunc import cached_method from sage.categories.category_singleton import Category_singleton @@ -62,13 +62,15 @@ def tensor(self, *crystals, **options): if cartan_type.letter == 'Q': from sage.combinat.crystals.tensor_product import FullTensorProductOfQueerSuperCrystals + return FullTensorProductOfQueerSuperCrystals((self,) + tuple(crystals), **options) from sage.combinat.crystals.tensor_product import FullTensorProductOfSuperCrystals + return FullTensorProductOfSuperCrystals((self,) + tuple(crystals), **options) class Finite(CategoryWithAxiom): class ParentMethods: - @cached_method(key=lambda s,i: tuple(i) if i is not None else s.index_set()) + @cached_method(key=lambda s, i: tuple(i) if i is not None else s.index_set()) def digraph(self, index_set=None): r""" Return the :class:`DiGraph` associated to ``self``. @@ -107,7 +109,7 @@ def digraph(self, index_set=None): def edge_options(data): u, v, l = data - edge_opts = { 'edge_string': '->', 'color': 'black' } + edge_opts = {'edge_string': '->', 'color': 'black'} if l > 0: edge_opts['color'] = CartanType._colors.get(l, 'black') edge_opts['label'] = LatexExpr(str(l)) @@ -165,6 +167,7 @@ def connected_components(self) -> list: """ category = SuperCrystals() from sage.categories.regular_supercrystals import RegularSuperCrystals + if self in RegularSuperCrystals(): category = RegularSuperCrystals() index_set = self.index_set() @@ -172,10 +175,7 @@ def connected_components(self) -> list: CCs = [] for mg in self.connected_components_generators(): - subcrystal = self.subcrystal(generators=(mg,), - index_set=index_set, - cartan_type=cartan_type, - category=category) + subcrystal = self.subcrystal(generators=(mg,), index_set=index_set, cartan_type=cartan_type, category=category) CCs.append(subcrystal) return CCs @@ -259,6 +259,7 @@ def character(self): + B[(0, 0, 0, 1, 0)] + B[(0, 0, 0, 0, 1)] """ from sage.rings.integer_ring import ZZ + A = self.weight_lattice_realization().algebra(ZZ) return A.sum(A(x.weight()) for x in self) @@ -390,6 +391,7 @@ class TensorProducts(TensorProductsCategory): The category of regular crystals constructed by tensor product of regular crystals. """ + @cached_method def extra_super_categories(self): """ diff --git a/src/sage/categories/tensor.py b/src/sage/categories/tensor.py index c2e8a0f6001..7b3a49f543e 100644 --- a/src/sage/categories/tensor.py +++ b/src/sage/categories/tensor.py @@ -5,6 +5,7 @@ - Nicolas M. Thiéry (2008-2010): initial revision and refactorization """ + # **************************************************************************** # Copyright (C) 2008-2010 Nicolas M. Thiéry # @@ -47,6 +48,7 @@ class TensorProductFunctor(CovariantFunctorialConstruction): sage: TestSuite(tensor).run() """ + _functor_name = "tensor" _functor_category = "TensorProducts" symbol = " # " @@ -81,6 +83,7 @@ class TensorProductsCategory(CovariantConstructionCategory): \mathbf{TensorProducts}(\mathbf{WithBasis}_{\Bold{Q}}) sage: TestSuite(C).run() """ + _functor_category = "TensorProducts" def TensorProducts(self): diff --git a/src/sage/categories/topological_spaces.py b/src/sage/categories/topological_spaces.py index e66a3f3fbfa..30dfb6d1ecd 100644 --- a/src/sage/categories/topological_spaces.py +++ b/src/sage/categories/topological_spaces.py @@ -1,12 +1,13 @@ r""" Topological Spaces """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2015 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.cachefunc import cached_method from sage.categories.category_with_axiom import CategoryWithAxiom @@ -50,6 +51,7 @@ class TopologicalSpaces(TopologicalSpacesCategory): sage: TestSuite(Sets().Topological()).run() """ + # We must override the general object because the names don't match _base_category_class = (Sets,) diff --git a/src/sage/categories/triangular_kac_moody_algebras.py b/src/sage/categories/triangular_kac_moody_algebras.py index 2fb1ccf32ab..340bec66fa4 100644 --- a/src/sage/categories/triangular_kac_moody_algebras.py +++ b/src/sage/categories/triangular_kac_moody_algebras.py @@ -32,6 +32,7 @@ class TriangularKacMoodyAlgebras(Category_over_base_ring): We require that the grading group is the root lattice of the appropriate Cartan type. """ + @cached_method def super_categories(self): """ @@ -117,12 +118,11 @@ def _part_generators(self, positive=False): P = self._cartan_type.root_system().root_lattice() ali = P.simple_roots().inverse_family() if positive: - d = {ali[g.degree()]: g for g in self.lie_algebra_generators() - if self._part(g) > 0} + d = {ali[g.degree()]: g for g in self.lie_algebra_generators() if self._part(g) > 0} if not positive: - d = {ali[-g.degree()]: g for g in self.lie_algebra_generators() - if self._part(g) < 0} + d = {ali[-g.degree()]: g for g in self.lie_algebra_generators() if self._part(g) < 0} from sage.sets.family import Family + return Family(I, d.__getitem__) def e(self, i=None): @@ -253,6 +253,7 @@ def verma_module(self, la, basis_key=None, **kwds): of Lie algebra of ['A', 2] in the Chevalley basis """ from sage.algebras.lie_algebras.verma_module import VermaModule + return VermaModule(self, la, basis_key=basis_key, **kwds) def simple_module(self, la, basis_key=None, **kwds): @@ -293,9 +294,11 @@ def simple_module(self, la, basis_key=None, **kwds): """ if la.is_verma_dominant(positive=False): from sage.algebras.lie_algebras.verma_module import VermaModule + return VermaModule(self, la, basis_key=basis_key, **kwds) from sage.algebras.lie_algebras.bgg_dual_module import SimpleModule + return SimpleModule(self, la, basis_key=basis_key, **kwds) class ElementMethods: @@ -344,6 +347,7 @@ class FiniteDimensional(CategoryWithAxiom_over_base_ring): to semisimple Lie algebras) with a distinguished basis that respects the triangular decomposition. """ + class ParentMethods: @lazy_attribute def _transpose_basis_mapping(self): diff --git a/src/sage/categories/unique_factorization_domains.py b/src/sage/categories/unique_factorization_domains.py index d0af431e855..38e22f9bd4e 100644 --- a/src/sage/categories/unique_factorization_domains.py +++ b/src/sage/categories/unique_factorization_domains.py @@ -1,6 +1,7 @@ r""" Unique factorization domains """ + # **************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) # @@ -174,6 +175,7 @@ def _gcd_univariate_polynomial(self, f, g): sage: ((p^4 - 1).gcd(p^3 + 1) / (p + 1)).is_unit() True """ + def content(X): """ Return the content of ``X`` up to a unit. diff --git a/src/sage/categories/unital_algebras.py b/src/sage/categories/unital_algebras.py index 124cda90533..07fe7f5cea9 100644 --- a/src/sage/categories/unital_algebras.py +++ b/src/sage/categories/unital_algebras.py @@ -1,6 +1,7 @@ r""" Unital algebras """ + # **************************************************************************** # Copyright (C) 2011 Nicolas M. Thiery # @@ -49,6 +50,7 @@ class UnitalAlgebras(CategoryWithAxiom_over_base_ring): True sage: TestSuite(C).run() """ + _base_category_class_and_axiom = (MagmaticAlgebras, "Unital") class ParentMethods: @@ -210,7 +212,7 @@ def _coerce_map_from_base_ring(self): # If there is a specialised from_base_ring(), then it should # be used unconditionally. generic_from_base_ring = self.category().parent_class.from_base_ring - from_base_ring = self.from_base_ring # bound method + from_base_ring = self.from_base_ring # bound method if from_base_ring.__func__ != generic_from_base_ring: # Custom from_base_ring() use_from_base_ring = True @@ -381,6 +383,7 @@ class CartesianProducts(CartesianProductsCategory): - http://groups.google.fr/group/sage-devel/browse_thread/thread/35a72b1d0a2fc77a/348f42ae77a66d16#348f42ae77a66d16 - :wikipedia:`Direct_product` """ + def extra_super_categories(self): """ A Cartesian product of algebras is endowed with a natural diff --git a/src/sage/categories/vector_bundles.py b/src/sage/categories/vector_bundles.py index f11dd094d72..a29dffa273d 100644 --- a/src/sage/categories/vector_bundles.py +++ b/src/sage/categories/vector_bundles.py @@ -2,12 +2,12 @@ r""" Vector Bundles """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2019 Michael Jung # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category_types import Category_over_base_ring from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring @@ -36,6 +36,7 @@ class VectorBundles(Category_over_base_ring): sage: TestSuite(C).run(skip='_test_category_over_bases') """ + def __init__(self, base_space, base_field, name=None): r""" Initialize ``self``. @@ -92,8 +93,7 @@ def _repr_object_names(self): space 2-dimensional differentiable manifold M' """ base_space = self._base_space - return Category_over_base_ring._repr_object_names(self) + \ - " with base space %s" % base_space + return Category_over_base_ring._repr_object_names(self) + " with base space %s" % base_space class SubcategoryMethods: @cached_method diff --git a/src/sage/categories/vector_spaces.py b/src/sage/categories/vector_spaces.py index 8749aa18c2f..eb478281d93 100644 --- a/src/sage/categories/vector_spaces.py +++ b/src/sage/categories/vector_spaces.py @@ -1,7 +1,8 @@ r""" Vector Spaces """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2005 David Kohel # William Stein # 2008 Teresa Gomez-Diaz (CNRS) @@ -9,7 +10,7 @@ # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.category import Category from sage.categories.category_types import Category_module from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring @@ -21,6 +22,7 @@ from sage.categories.fields import Fields from sage.categories.modules import Modules from sage.categories.modules_with_basis import ModulesWithBasis + _Fields = Fields() @@ -37,6 +39,7 @@ class VectorSpaces(Category_module): sage: VectorSpaces(QQ).super_categories() [Category of modules over Rational Field] """ + @staticmethod def __classcall_private__(cls, K, check=True): """ @@ -65,10 +68,8 @@ def __classcall_private__(cls, K, check=True): Category of vector spaces over Integer Ring """ if check: - if not (K in _Fields or - (isinstance(K, Category) and K.is_subcategory(_Fields))): - raise ValueError("base must be a field or a subcategory of Fields();" + - " got {}".format(K)) + if not (K in _Fields or (isinstance(K, Category) and K.is_subcategory(_Fields))): + raise ValueError("base must be a field or a subcategory of Fields();" + " got {}".format(K)) return super().__classcall__(cls, K) def __init__(self, K): @@ -112,7 +113,7 @@ def _call_(self, x): if V.base_field() != self.base_field(): V = V.change_ring(self.base_field()) except (TypeError, AttributeError) as msg: - raise TypeError("%s\nunable to coerce x (=%s) into %s" % (msg,x,self)) + raise TypeError("%s\nunable to coerce x (=%s) into %s" % (msg, x, self)) return V def base_field(self): @@ -244,6 +245,7 @@ class Graded(GradedModulesCategory): """ Category of graded vector spaces with basis. """ + def example(self, base_ring=None): """ Return an example of a graded vector space with basis, @@ -257,6 +259,7 @@ def example(self, base_ring=None): the free module on partitions over Rational Field """ from sage.categories.examples.graded_modules_with_basis import GradedPartitionModule + if base_ring is None: base_ring = self.base_ring() return GradedPartitionModule(base_ring=base_ring) @@ -265,6 +268,7 @@ class Filtered(FilteredModulesCategory): """ Category of filtered vector spaces with basis. """ + def example(self, base_ring=None): """ Return an example of a graded vector space with basis, @@ -278,6 +282,7 @@ def example(self, base_ring=None): the free module on partitions over Rational Field """ from sage.categories.examples.filtered_modules_with_basis import FilteredPartitionModule + if base_ring is None: base_ring = self.base_ring() return FilteredPartitionModule(base_ring=base_ring) diff --git a/src/sage/categories/weyl_groups.py b/src/sage/categories/weyl_groups.py index e3e134b029e..5a39ba192c5 100644 --- a/src/sage/categories/weyl_groups.py +++ b/src/sage/categories/weyl_groups.py @@ -146,6 +146,7 @@ def pieri_factors(self, *args, **keywords): # Do not remove this line which makes sure the pieri factor # code is properly inserted inside the Cartan Types import sage.combinat.root_system.pieri_factors + assert sage.combinat.root_system.pieri_factors ct = self.cartan_type() if hasattr(ct, "PieriFactors"): @@ -209,22 +210,17 @@ def bruhat_cone(self, x, y, side='upper', backend='cdd'): - [JS2021]_ """ from sage.modules.free_module_element import vector + if side == 'upper': - roots = [vector((x * r * x.inverse()).reflection_to_root().to_ambient()) - for z, r in x.bruhat_upper_covers_reflections() - if z.bruhat_le(y)] + roots = [vector((x * r * x.inverse()).reflection_to_root().to_ambient()) for z, r in x.bruhat_upper_covers_reflections() if z.bruhat_le(y)] elif side == 'lower': - roots = [vector((y * r * y.inverse()).reflection_to_root().to_ambient()) - for z, r in y.bruhat_lower_covers_reflections() - if x.bruhat_le(z)] + roots = [vector((y * r * y.inverse()).reflection_to_root().to_ambient()) for z, r in y.bruhat_lower_covers_reflections() if x.bruhat_le(z)] else: raise ValueError("side must be either 'upper' or 'lower'") from sage.geometry.polyhedron.constructor import Polyhedron - return Polyhedron(vertices=[vector([0] * self.degree())], - rays=roots, - ambient_dim=self.degree(), - backend=backend) + + return Polyhedron(vertices=[vector([0] * self.degree())], rays=roots, ambient_dim=self.degree(), backend=backend) @cached_method def quantum_bruhat_graph(self, index_set=()): @@ -280,9 +276,7 @@ def quantum_bruhat_graph(self, index_set=()): for alpha in NPR: ref = alpha.associated_reflection() alphacheck = alpha.associated_coroot() - NPR_data[alpha] = [self.from_reduced_word(ref), # the element - len(ref) == double_rho.scalar(alphacheck) - 1, # is_quantum - NPR_sum.scalar(alphacheck)] # the scalar + NPR_data[alpha] = [self.from_reduced_word(ref), len(ref) == double_rho.scalar(alphacheck) - 1, NPR_sum.scalar(alphacheck)] # the element # is_quantum # the scalar # We also create a temporary cache of lengths as they are # relatively expensive to compute and needed frequently visited = {} @@ -294,6 +288,7 @@ def length(x): return len_cache[x] len_cache[x] = x.length() return len_cache[x] + while todo: x = todo.pop() w_length_plus_one = length(x) + 1 @@ -314,10 +309,8 @@ def length(x): visited[x] = adj from sage.graphs.digraph import DiGraph - return DiGraph(visited, - name="Parabolic Quantum Bruhat Graph of %s for nodes %s" % (self, index_set), - format='dict_of_dicts', - data_structure='static_sparse') + + return DiGraph(visited, name="Parabolic Quantum Bruhat Graph of %s for nodes %s" % (self, index_set), format='dict_of_dicts', data_structure='static_sparse') class ElementMethods: @@ -414,6 +407,7 @@ def left_pieri_factorizations(self, max_length=None): """ if max_length is None: from sage.rings.infinity import infinity + max_length = infinity pieri_factors = self.parent().pieri_factors() @@ -489,18 +483,18 @@ def stanley_symmetric_function_as_polynomial(self, max_length=None): """ if max_length is None: from sage.rings.infinity import infinity + max_length = infinity W = self.parent() pieri_factors = W.pieri_factors() from sage.rings.rational_field import QQ + R = QQ[','.join('x%s' % l for l in range(1, pieri_factors.max_length() + 1))] x = R.gens() if self.is_one(): return R.one() - return R(sum(2**(pieri_factors.stanley_symm_poly_weight(u)) * x[u.length() - 1] * v.stanley_symmetric_function_as_polynomial(max_length=u.length()) - for (u, v) in self.left_pieri_factorizations(max_length) - if u != W.one())) + return R(sum(2 ** (pieri_factors.stanley_symm_poly_weight(u)) * x[u.length() - 1] * v.stanley_symmetric_function_as_polynomial(max_length=u.length()) for (u, v) in self.left_pieri_factorizations(max_length) if u != W.one())) def stanley_symmetric_function(self): r""" @@ -719,14 +713,15 @@ def inversion_arrangement(self, side='right'): """ inv = self.inversions(side=side, inversion_type='roots') from sage.geometry.hyperplane_arrangement.arrangement import HyperplaneArrangements + I = self.parent().cartan_type().index_set() from sage.rings.rational_field import QQ + H = HyperplaneArrangements(QQ, tuple(['a{}'.format(i) for i in I])) gens = H.gens() if not inv: return H() - return H([sum(c * gens[I.index(i)] for (i, c) in root) - for root in inv]) + return H([sum(c * gens[I.index(i)] for (i, c) in root) for root in inv]) def bruhat_lower_covers_coroots(self): r""" @@ -748,8 +743,7 @@ def bruhat_lower_covers_coroots(self): [(s1*s2*s1, alphacheck[1] + alphacheck[2] + alphacheck[3]), (s3*s2*s1, alphacheck[2]), (s3*s1*s2, alphacheck[1])] """ - return [(x[0], x[1].reflection_to_coroot()) - for x in self.bruhat_lower_covers_reflections()] + return [(x[0], x[1].reflection_to_coroot()) for x in self.bruhat_lower_covers_reflections()] def bruhat_upper_covers_coroots(self): r""" @@ -771,8 +765,7 @@ def bruhat_upper_covers_coroots(self): (s3*s4*s1*s2*s1, alphacheck[4]), (s4*s3*s1*s2*s1, alphacheck[1] + alphacheck[2] + alphacheck[3] + alphacheck[4])] """ - return [(x[0], x[1].reflection_to_coroot()) - for x in self.bruhat_upper_covers_reflections()] + return [(x[0], x[1].reflection_to_coroot()) for x in self.bruhat_upper_covers_reflections()] def quantum_bruhat_successors(self, index_set=None, roots=False, quantum_only=False): r""" diff --git a/src/sage/categories/with_realizations.py b/src/sage/categories/with_realizations.py index a143d255271..00249843dc2 100644 --- a/src/sage/categories/with_realizations.py +++ b/src/sage/categories/with_realizations.py @@ -8,12 +8,13 @@ - :mod:`sage.categories.covariant_functorial_construction` for an introduction to covariant functorial constructions. """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2010-2012 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.category import Category from sage.categories.covariant_functorial_construction import RegressiveCovariantConstructionCategory diff --git a/src/sage/cli/interactive_shell_cmd.py b/src/sage/cli/interactive_shell_cmd.py index 8c697f153b0..6ba0995be5f 100644 --- a/src/sage/cli/interactive_shell_cmd.py +++ b/src/sage/cli/interactive_shell_cmd.py @@ -16,6 +16,7 @@ def run(self) -> int: # early feedback that Sage is starting. if not self.options.quiet: from sage.misc.banner import banner + banner() from sage.repl.interpreter import SageTerminalApp diff --git a/src/sage/coding/abstract_code.py b/src/sage/coding/abstract_code.py index ce9d199eec8..c794e895615 100644 --- a/src/sage/coding/abstract_code.py +++ b/src/sage/coding/abstract_code.py @@ -108,14 +108,14 @@ def _explain_constructor(cl): """ if inspect.isclass(cl): argspec = sage_getargspec(cl.__init__) - skip = 2 # skip the self and code arguments + skip = 2 # skip the self and code arguments else: # Not a class, assume it's a factory function posing as a class argspec = sage_getargspec(cl) - skip = 1 # skip code argument + skip = 1 # skip code argument if argspec.defaults: - args = argspec.args[skip:-len(argspec.defaults)] - kwargs = argspec.args[-len(argspec.defaults):] + args = argspec.args[skip : -len(argspec.defaults)] + kwargs = argspec.args[-len(argspec.defaults) :] opts = "It takes the optional arguments {}.".format(kwargs) else: args = argspec.args[skip:] @@ -128,8 +128,7 @@ def _explain_constructor(cl): var = "It accepts unspecified arguments as well.\n" else: var = "" - return ("{}\n{}\n{}See the documentation of {}.{} for more details." - .format(reqs, opts, var, cl.__module__, cl.__name__)) + return "{}\n{}\n{}See the documentation of {}.{} for more details.".format(reqs, opts, var, cl.__module__, cl.__name__) class AbstractCode(Parent): @@ -202,8 +201,7 @@ class AbstractCode(Parent): and ``_latex_`` methods in the subclass. """ - def __init__(self, length, default_encoder_name=None, - default_decoder_name=None, metric='Hamming') -> None: + def __init__(self, length, default_encoder_name=None, default_decoder_name=None, metric='Hamming') -> None: r""" Initialize mandatory parameters that any code shares. @@ -542,7 +540,7 @@ def metric(self): """ return self._metric -###################### Encoding-Decoding ####################################### + ###################### Encoding-Decoding ####################################### def add_decoder(self, name, decoder): r""" @@ -818,14 +816,9 @@ def decoder(self, decoder_name=None, *args, **kwargs): try: return decClass(self, *args, **kwargs) except TypeError: - raise ValueError( - "Constructing the {0} decoder failed, possibly due " - "to missing or incorrect parameters.\n{1}".format( - decoder_name, _explain_constructor(decClass))) + raise ValueError("Constructing the {0} decoder failed, possibly due " "to missing or incorrect parameters.\n{1}".format(decoder_name, _explain_constructor(decClass))) else: - raise ValueError( - "There is no Decoder named '{0}'. The known Decoders are: " - "{1}".format(decoder_name, self.decoders_available())) + raise ValueError("There is no Decoder named '{0}'. The known Decoders are: " "{1}".format(decoder_name, self.decoders_available())) def decoders_available(self, classes=False): r""" @@ -993,14 +986,9 @@ def encoder(self, encoder_name=None, *args, **kwargs): try: return encClass(self, *args, **kwargs) except TypeError: - raise ValueError( - "Constructing the {0} encoder failed, possibly due " - "to missing or incorrect parameters.\n{1}".format( - encoder_name, _explain_constructor(encClass))) + raise ValueError("Constructing the {0} encoder failed, possibly due " "to missing or incorrect parameters.\n{1}".format(encoder_name, _explain_constructor(encClass))) else: - raise ValueError( - "There is no Encoder named '{0}'. The known Encoders are: " - "{1}".format(encoder_name, self.encoders_available())) + raise ValueError("There is no Encoder named '{0}'. The known Encoders are: " "{1}".format(encoder_name, self.encoders_available())) def encoders_available(self, classes=False): r""" diff --git a/src/sage/coding/ag_code.py b/src/sage/coding/ag_code.py index 177b4532b6a..a8f3c690be9 100644 --- a/src/sage/coding/ag_code.py +++ b/src/sage/coding/ag_code.py @@ -94,6 +94,7 @@ class AGCode(AbstractLinearCode): attribute that refers to an abstract functiom field or the function field of the underlying curve used to construct a code of the class. """ + def base_function_field(self): """ Return the function field used to construct the code. @@ -145,6 +146,7 @@ class EvaluationAGCode(AGCode): sage: codes.EvaluationAGCode(pls, G) [8, 5] evaluation AG code over GF(4) """ + _registered_encoders = {} _registered_decoders = {} @@ -181,8 +183,7 @@ def __init__(self, pls, G): self._registered_encoders['evaluation'] = EvaluationAGCodeEncoder self._registered_decoders['K'] = EvaluationAGCodeUniqueDecoder - super().__init__(K, n, default_encoder_name='evaluation', - default_decoder_name='K') + super().__init__(K, n, default_encoder_name='evaluation', default_decoder_name='K') # compute basis functions associated with a generator matrix basis_functions = G.basis_function_space() @@ -195,8 +196,7 @@ def __init__(self, pls, G): r = M.rank() self._generator_matrix = M.submatrix(0, 0, r) - self._basis_functions = [sum(c * b for c, b in zip(T[i], basis_functions)) - for i in range(r)] + self._basis_functions = [sum(c * b for c, b in zip(T[i], basis_functions)) for i in range(r)] self._pls = tuple(pls) self._G = G @@ -262,8 +262,7 @@ def _repr_(self): sage: codes.EvaluationAGCode(pls, 7*Q) [8, 7] evaluation AG code over GF(4) """ - return "[{}, {}] evaluation AG code over GF({})".format( - self.length(), self.dimension(), self.base_field().cardinality()) + return "[{}, {}] evaluation AG code over GF({})".format(self.length(), self.dimension(), self.base_field().cardinality()) def _latex_(self): r""" @@ -282,8 +281,7 @@ def _latex_(self): sage: latex(code) [8, 3]\text{ evaluation AG code over }\Bold{F}_{2^{2}} """ - return r"[{}, {}]\text{{ evaluation AG code over }}{}".format( - self.length(), self.dimension(), self.base_field()._latex_()) + return r"[{}, {}]\text{{ evaluation AG code over }}{}".format(self.length(), self.dimension(), self.base_field()._latex_()) def basis_functions(self): r""" @@ -384,6 +382,7 @@ class DifferentialAGCode(AGCode): sage: codes.DifferentialAGCode(pls, G) [3, 1] differential AG code over GF(4) """ + _registered_encoders = {} _registered_decoders = {} @@ -419,8 +418,7 @@ def __init__(self, pls, G): self._registered_encoders['residue'] = DifferentialAGCodeEncoder self._registered_decoders['K'] = DifferentialAGCodeUniqueDecoder - super().__init__(K, n, default_encoder_name='residue', - default_decoder_name='K') + super().__init__(K, n, default_encoder_name='residue', default_decoder_name='K') # compute basis differentials associated with a generator matrix basis_differentials = (-sum(pls) + G).basis_differential_space() @@ -433,8 +431,7 @@ def __init__(self, pls, G): r = M.rank() self._generator_matrix = M.submatrix(0, 0, r) - self._basis_differentials = [sum(c * w for c, w in zip(T[i], basis_differentials)) - for i in range(r)] + self._basis_differentials = [sum(c * w for c, w in zip(T[i], basis_differentials)) for i in range(r)] self._pls = tuple(pls) self._G = G @@ -503,8 +500,7 @@ def _repr_(self): sage: codes.DifferentialAGCode(pls, 3*Q) [8, 5] differential AG code over GF(4) """ - return "[{}, {}] differential AG code over GF({})".format( - self.length(), self.dimension(), self.base_field().cardinality()) + return "[{}, {}] differential AG code over GF({})".format(self.length(), self.dimension(), self.base_field().cardinality()) def _latex_(self): r""" @@ -523,8 +519,7 @@ def _latex_(self): sage: latex(code) [8, 5]\text{ differential AG code over }\Bold{F}_{2^{2}} """ - return r"[{}, {}]\text{{ differential AG code over }}{}".format( - self.length(), self.dimension(), self.base_field()._latex_()) + return r"[{}, {}]\text{{ differential AG code over }}{}".format(self.length(), self.dimension(), self.base_field()._latex_()) def basis_differentials(self): r""" @@ -632,6 +627,7 @@ class CartierCode(AGCode): sage: code.minimum_distance() # long time 2 """ + def __init__(self, pls, G, r=1, name=None): """ Initialize. @@ -685,15 +681,15 @@ def __init__(self, pls, G, r=1, name=None): W, fr_W, to_W = EE.differential_space() a = K.gen() - field_basis = [a**i for i in range(K.degree())] # over prime subfield + field_basis = [a**i for i in range(K.degree())] # over prime subfield basis = E.basis_differential_space() m = [] for w in basis: for c in field_basis: - cw = F(c) * w # c does not coerce... + cw = F(c) * w # c does not coerce... carcw = cw - for i in range(r): # apply cartier r times + for i in range(r): # apply cartier r times carcw = carcw.cartier() m.append([f for e in to_W(carcw - cw) for f in vector(e)]) @@ -703,7 +699,7 @@ def __init__(self, pls, G, r=1, name=None): s = len(field_basis) ncols = s * len(basis) for row in ker.basis(): - v = vector([K(row[d:d+s]) for d in range(0,ncols,s)]) + v = vector([K(row[d : d + s]) for d in range(0, ncols, s)]) R.append(fr_V(v)) # construct a generator matrix @@ -712,8 +708,8 @@ def __init__(self, pls, G, r=1, name=None): for w in R: row = [] for p in col_index: - res = w.residue(p).trace() # lies in constant base field - c = subfield(res) # as w is Cartier fixed + res = w.residue(p).trace() # lies in constant base field + c = subfield(res) # as w is Cartier fixed row.append(c) m.append(row) @@ -727,9 +723,7 @@ def __init__(self, pls, G, r=1, name=None): self._registered_encoders['GeneratorMatrix'] = LinearCodeGeneratorMatrixEncoder self._registered_decoders['Syndrome'] = LinearCodeSyndromeDecoder - super().__init__(subfield, n, - default_encoder_name='GeneratorMatrix', - default_decoder_name='Syndrome') + super().__init__(subfield, n, default_encoder_name='GeneratorMatrix', default_decoder_name='Syndrome') def __eq__(self, other): """ @@ -794,8 +788,7 @@ def _repr_(self): sage: codes.CartierCode(pls, G) # long time [9, 4] Cartier code over GF(3) """ - return "[{}, {}] Cartier code over GF({})".format( - self.length(), self.dimension(), self.base_field().cardinality()) + return "[{}, {}] Cartier code over GF({})".format(self.length(), self.dimension(), self.base_field().cardinality()) def _latex_(self): r""" @@ -815,8 +808,7 @@ def _latex_(self): sage: latex(code) # long time [9, 4]\text{ Cartier code over }\Bold{F}_{3} """ - return r"[{}, {}]\text{{ Cartier code over }}{}".format( - self.length(), self.dimension(), self.base_field()._latex_()) + return r"[{}, {}]\text{{ Cartier code over }}{}".format(self.length(), self.dimension(), self.base_field()._latex_()) def generator_matrix(self): r""" diff --git a/src/sage/coding/all.py b/src/sage/coding/all.py index 3d7b19900c1..a932f4384e5 100644 --- a/src/sage/coding/all.py +++ b/src/sage/coding/all.py @@ -1,8 +1,6 @@ - from sage.misc.lazy_import import lazy_import -lazy_import("sage.coding.code_constructions", ["permutation_action", - "walsh_matrix"]) +lazy_import("sage.coding.code_constructions", ["permutation_action", "walsh_matrix"]) lazy_import("sage.coding.linear_code", "LinearCode") diff --git a/src/sage/coding/bch_code.py b/src/sage/coding/bch_code.py index ebd9d7bc3b4..aae2b6325bb 100644 --- a/src/sage/coding/bch_code.py +++ b/src/sage/coding/bch_code.py @@ -104,8 +104,7 @@ class BCHCode(CyclicCode): 1 """ - def __init__(self, base_field, length, designed_distance, - primitive_root=None, offset=1, jump_size=1, b=0): + def __init__(self, base_field, length, designed_distance, primitive_root=None, offset=1, jump_size=1, b=0): """ TESTS: @@ -125,15 +124,12 @@ def __init__(self, base_field, length, designed_distance, q = base_field.cardinality() s = Zmod(length)(q).multiplicative_order() - if gcd(jump_size, q ** s - 1) != 1: - raise ValueError("jump_size must be coprime with the order of " - "the multiplicative group of the splitting field") + if gcd(jump_size, q**s - 1) != 1: + raise ValueError("jump_size must be coprime with the order of " "the multiplicative group of the splitting field") - D = [(offset + jump_size * i) % length - for i in range(designed_distance - 1)] + D = [(offset + jump_size * i) % length for i in range(designed_distance - 1)] - super().__init__(field=base_field, length=length, - D=D, primitive_root=primitive_root) + super().__init__(field=base_field, length=length, D=D, primitive_root=primitive_root) self._default_decoder_name = "UnderlyingGRS" self._jump_size = jump_size self._offset = offset @@ -152,11 +148,7 @@ def __eq__(self, other): sage: C1 == C2 True """ - return (isinstance(other, BCHCode) and - self.length() == other.length() and - self.jump_size() == other.jump_size() and - self.offset() == other.offset() and - self.primitive_root() == other.primitive_root()) + return isinstance(other, BCHCode) and self.length() == other.length() and self.jump_size() == other.jump_size() and self.offset() == other.offset() and self.primitive_root() == other.primitive_root() def _repr_(self): r""" @@ -168,9 +160,7 @@ def _repr_(self): sage: C [15, 5] BCH Code over GF(2) with designed distance 7 """ - return ("[%s, %s] BCH Code over GF(%s) with designed distance %d" - % (self.length(), self.dimension(), - self.base_field().cardinality(), self.designed_distance())) + return "[%s, %s] BCH Code over GF(%s) with designed distance %d" % (self.length(), self.dimension(), self.base_field().cardinality(), self.designed_distance()) def _latex_(self): r""" @@ -182,9 +172,7 @@ def _latex_(self): sage: latex(C) [15, 5] \textnormal{ BCH Code over } \Bold{F}_{2} \textnormal{ with designed distance } 7 """ - return ("[%s, %s] \\textnormal{ BCH Code over } %s \\textnormal{ with designed distance } %s" - % (self.length(), self.dimension(), - self.base_field()._latex_(), self.designed_distance())) + return "[%s, %s] \\textnormal{ BCH Code over } %s \\textnormal{ with designed distance } %s" % (self.length(), self.dimension(), self.base_field()._latex_(), self.designed_distance()) def jump_size(self): r""" @@ -244,13 +232,13 @@ def bch_to_grs(self): grs_dim = n - designed_distance + 1 alpha = self.primitive_root() - alpha_l = alpha ** l - alpha_b = alpha ** b - evals = [alpha_l ** i for i in range(n)] - pcm = [alpha_b ** i for i in range(n)] + alpha_l = alpha**l + alpha_b = alpha**b + evals = [alpha_l**i for i in range(n)] + pcm = [alpha_b**i for i in range(n)] - multipliers_product = [1/prod([evals[i] - evals[h] for h in range(n) if h != i]) for i in range(n)] - column_multipliers = [multipliers_product[i]/pcm[i] for i in range(n)] + multipliers_product = [1 / prod([evals[i] - evals[h] for h in range(n) if h != i]) for i in range(n)] + column_multipliers = [multipliers_product[i] / pcm[i] for i in range(n)] return GeneralizedReedSolomonCode(evals, grs_dim, column_multipliers) @@ -310,8 +298,7 @@ def _latex_(self): sage: latex(D) \textnormal{Decoder through the underlying GRS code of } [15, 11] \textnormal{ BCH Code over } \Bold{F}_{2^{2}} \textnormal{ with designed distance } 3 """ - return ("\\textnormal{Decoder through the underlying GRS code of } %s" - % self.code()._latex_()) + return "\\textnormal{Decoder through the underlying GRS code of } %s" % self.code()._latex_() def grs_code(self): r""" diff --git a/src/sage/coding/bounds_catalog.py b/src/sage/coding/bounds_catalog.py index aa4c2dd9996..ae61228757a 100644 --- a/src/sage/coding/bounds_catalog.py +++ b/src/sage/coding/bounds_catalog.py @@ -9,34 +9,15 @@ sage: from sage.coding.bounds_catalog import * """ + from sage.misc.lazy_import import lazy_import as _lazy_import -_lazy_import("sage.coding.code_bounds", ["codesize_upper_bound", - "dimension_upper_bound", - "volume_hamming", - "gilbert_lower_bound", - "plotkin_upper_bound", - "griesmer_upper_bound", - "elias_upper_bound", - "hamming_upper_bound", - "singleton_upper_bound", - "gv_info_rate", - "entropy", - "gv_bound_asymp", - "hamming_bound_asymp", - "singleton_bound_asymp", - "plotkin_bound_asymp", - "elias_bound_asymp", - "mrrw1_bound_asymp"]) - -_lazy_import("sage.coding.delsarte_bounds", - ["krawtchouk", - "eberlein", - "delsarte_bound_constant_weight_code", - "delsarte_bound_hamming_space", - "delsarte_bound_additive_hamming_space", - "delsarte_bound_Q_matrix"]) + +_lazy_import("sage.coding.code_bounds", ["codesize_upper_bound", "dimension_upper_bound", "volume_hamming", "gilbert_lower_bound", "plotkin_upper_bound", "griesmer_upper_bound", "elias_upper_bound", "hamming_upper_bound", "singleton_upper_bound", "gv_info_rate", "entropy", "gv_bound_asymp", "hamming_bound_asymp", "singleton_bound_asymp", "plotkin_bound_asymp", "elias_bound_asymp", "mrrw1_bound_asymp"]) + +_lazy_import("sage.coding.delsarte_bounds", ["krawtchouk", "eberlein", "delsarte_bound_constant_weight_code", "delsarte_bound_hamming_space", "delsarte_bound_additive_hamming_space", "delsarte_bound_Q_matrix"]) from sage.misc.rest_index_of_methods import gen_rest_table_index as _gen_rest_table_index import sys as _sys + __doc__ = __doc__.format(INDEX_OF_FUNCTIONS=_gen_rest_table_index(_sys.modules[__name__], only_local_functions=False)) diff --git a/src/sage/coding/channel.py b/src/sage/coding/channel.py index bb25564af8d..0e52a2856fa 100644 --- a/src/sage/coding/channel.py +++ b/src/sage/coding/channel.py @@ -90,7 +90,7 @@ def random_error_vector(n, F, error_positions): sage: random_error_vector(5, GF(2), [1,3]) (0, 1, 0, 1, 0) """ - vect = [F.zero()]*n + vect = [F.zero()] * n for i in error_positions: vect[i] = F._random_nonzero_element() return vector(F, vect) @@ -235,7 +235,7 @@ def transmit(self, message): return self.transmit_unsafe(message) raise TypeError("Message must be an element of the input space for the given channel") - #Alias for transmit method + # Alias for transmit method __call__ = transmit def input_space(self): @@ -355,8 +355,7 @@ def _repr_(self): Vector space of dimension 50 over Finite Field of size 59 """ no_err = self.number_errors() - return "Static error rate channel creating %s errors, of input and output space %s"\ - % (format_interval(no_err), self.input_space()) + return "Static error rate channel creating %s errors, of input and output space %s" % (format_interval(no_err), self.input_space()) def _latex_(self): r""" @@ -371,8 +370,7 @@ def _latex_(self): input and output space Vector space of dimension 50 over Finite Field of size 59} """ no_err = self.number_errors() - return "\\textnormal{Static error rate channel creating %s errors, of input and output space %s}"\ - % (format_interval(no_err), self.input_space()) + return "\\textnormal{Static error rate channel creating %s errors, of input and output space %s}" % (format_interval(no_err), self.input_space()) def transmit_unsafe(self, message): r""" @@ -413,7 +411,7 @@ def transmit_unsafe(self, message): R = V.base_ring() for i in sample(range(V.dimension()), number_errors): err = R.random_element() - while (w[i] == err): + while w[i] == err: err = R.random_element() w[i] = err return w @@ -525,8 +523,7 @@ def _repr_(self): """ no_err = self.number_errors() no_era = self.number_erasures() - return "Error-and-erasure channel creating %s errors and %s erasures of input space %s and output space %s"\ - % (format_interval(no_err), format_interval(no_era), self.input_space(), self.output_space()) + return "Error-and-erasure channel creating %s errors and %s erasures of input space %s and output space %s" % (format_interval(no_err), format_interval(no_era), self.input_space(), self.output_space()) def _latex_(self): r""" @@ -544,8 +541,7 @@ def _latex_(self): """ no_err = self.number_errors() no_era = self.number_erasures() - return "\\textnormal{Error-and-erasure channel creating %s errors and %s erasures of input space %s and output space %s}"\ - % (format_interval(no_err), format_interval(no_era), self.input_space(), self.output_space()) + return "\\textnormal{Error-and-erasure channel creating %s errors and %s erasures of input space %s and output space %s}" % (format_interval(no_err), format_interval(no_era), self.input_space(), self.output_space()) def transmit_unsafe(self, message): r""" @@ -596,7 +592,7 @@ def transmit_unsafe(self, message): erasure_positions = errors[number_errors:] error_vector = random_error_vector(n, V.base_ring(), error_positions) - erasure_vector = random_error_vector(n , GF(2), erasure_positions) + erasure_vector = random_error_vector(n, GF(2), erasure_positions) message = message + error_vector @@ -713,8 +709,7 @@ def __repr__(self): q-ary symmetric channel with error probability 0.300000000000000, of input and output space Vector space of dimension 50 over Finite Field of size 59 """ - return "q-ary symmetric channel with error probability %s, of input and output space %s"\ - % (self.error_probability(), self.input_space()) + return "q-ary symmetric channel with error probability %s, of input and output space %s" % (self.error_probability(), self.input_space()) def _latex_(self): r""" @@ -728,8 +723,7 @@ def _latex_(self): \textnormal{q-ary symmetric channel with error probability 0.300000000000000, of input and output space Vector space of dimension 50 over Finite Field of size 59} """ - return "\\textnormal{q-ary symmetric channel with error probability %s, of input and output space %s}"\ - % (self.error_probability(), self.input_space()) + return "\\textnormal{q-ary symmetric channel with error probability %s, of input and output space %s}" % (self.error_probability(), self.input_space()) def transmit_unsafe(self, message): r""" @@ -796,7 +790,7 @@ def probability_of_exactly_t_errors(self, t): """ n = self.input_space().dimension() epsilon = self.error_probability() - return binomial(n, t) * epsilon**t * (1-epsilon)**(n-t) + return binomial(n, t) * epsilon**t * (1 - epsilon) ** (n - t) def probability_of_at_most_t_errors(self, t): r""" @@ -814,5 +808,4 @@ def probability_of_at_most_t_errors(self, t): sage: Chan.probability_of_at_most_t_errors(20) 0.952236164579467 """ - return sum(self.probability_of_exactly_t_errors(i) - for i in range(t+1)) + return sum(self.probability_of_exactly_t_errors(i) for i in range(t + 1)) diff --git a/src/sage/coding/channels_catalog.py b/src/sage/coding/channels_catalog.py index 6d4750f1bed..06b785ce96f 100644 --- a/src/sage/coding/channels_catalog.py +++ b/src/sage/coding/channels_catalog.py @@ -13,16 +13,16 @@ sage: from sage.coding.channels_catalog import * """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2015 David Lucas # # Distributed under the terms of the GNU General Public License (GPL), # version 2 or later (at your preference). # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.lazy_import import lazy_import as _lazy_import -_lazy_import('sage.coding.channel', ['ErrorErasureChannel', - 'QarySymmetricChannel', - 'StaticErrorRateChannel']) + +_lazy_import('sage.coding.channel', ['ErrorErasureChannel', 'QarySymmetricChannel', 'StaticErrorRateChannel']) diff --git a/src/sage/coding/code_bounds.py b/src/sage/coding/code_bounds.py index eb53c61f37b..3c4dda358fd 100644 --- a/src/sage/coding/code_bounds.py +++ b/src/sage/coding/code_bounds.py @@ -176,8 +176,7 @@ from sage.rings.rational_field import QQ from sage.rings.real_double import RDF -from .delsarte_bounds import (delsarte_bound_hamming_space, - delsarte_bound_additive_hamming_space) +from .delsarte_bounds import delsarte_bound_hamming_space, delsarte_bound_additive_hamming_space lazy_import('sage.libs.gap.libgap', 'libgap') @@ -339,8 +338,7 @@ def volume_hamming(n, q, r): sage: codes.bounds.volume_hamming(10,2,3) 176 """ - return sum([binomial(n, i) * (q-1)**i - for i in range(r+1)]) + return sum([binomial(n, i) * (q - 1) ** i for i in range(r + 1)]) def gilbert_lower_bound(n, q, d): @@ -356,7 +354,7 @@ def gilbert_lower_bound(n, q, d): 128/7 """ _check_n_q_d(n, q, d, field_based=False) - ans = q**n/volume_hamming(n,q,d-1) + ans = q**n / volume_hamming(n, q, d - 1) return ans @@ -383,19 +381,20 @@ def plotkin_upper_bound(n, q, d, algorithm=None): GapPackage("guava", spkg='gap_packages').require() libgap.load_package("guava") return QQ(libgap.UpperBoundPlotkin(n, d, q)) - t = 1 - 1/q - if (q == 2) and (n == 2*d) and (d % 2 == 0): - return 4*d - if (q == 2) and (n == 2*d + 1) and (d % 2 == 1): - return 4*d + 4 - if d > t*n: - return int(d/( d - t*n)) - if d < t*n + 1: - fact = (d-1) / t + t = 1 - 1 / q + if (q == 2) and (n == 2 * d) and (d % 2 == 0): + return 4 * d + if (q == 2) and (n == 2 * d + 1) and (d % 2 == 1): + return 4 * d + 4 + if d > t * n: + return int(d / (d - t * n)) + if d < t * n + 1: + fact = (d - 1) / t from sage.rings.real_mpfr import RR + if RR(fact) == RR(int(fact)): fact = int(fact) + 1 - return int(d/( d - t * fact)) * q**(n - fact) + return int(d / (d - t * fact)) * q ** (n - fact) def griesmer_upper_bound(n, q, d, algorithm=None): @@ -443,14 +442,15 @@ def griesmer_upper_bound(n, q, d, algorithm=None): # To compute the bound, we keep summing up the terms on the RHS # until we start violating the inequality. from sage.arith.misc import integer_ceil as ceil + den = 1 s = 0 k = 0 while s <= n: - s += ceil(d/den) + s += ceil(d / den) den *= q k = k + 1 - return q**(k-1) + return q ** (k - 1) def elias_upper_bound(n, q, d, algorithm=None): @@ -469,15 +469,16 @@ def elias_upper_bound(n, q, d, algorithm=None): 232 """ _check_n_q_d(n, q, d, field_based=False) - r = 1-1/q + r = 1 - 1 / q if algorithm == "gap": GapPackage("guava", spkg='gap_packages').require() libgap.load_package("guava") return QQ(libgap.UpperBoundElias(n, d, q)) + def ff(n, d, w, q): - return r*n*d*q**n/((w**2-2*r*n*w+r*n*d)*volume_hamming(n,q,w)) + return r * n * d * q**n / ((w**2 - 2 * r * n * w + r * n * d) * volume_hamming(n, q, w)) - I = (i for i in range(1, int(r*n) + 1) if i**2 - 2*r*n*i + r*n*d > 0) + I = (i for i in range(1, int(r * n) + 1) if i ** 2 - 2 * r * n * i + r * n * d > 0) bnd = min([ff(n, d, w, q) for w in I]) return int(bnd) @@ -515,7 +516,7 @@ def hamming_upper_bound(n, q, d): 93 """ _check_n_q_d(n, q, d, field_based=False) - return int((q**n)/(volume_hamming(n, q, int((d-1)/2)))) + return int((q**n) / (volume_hamming(n, q, int((d - 1) / 2)))) def singleton_upper_bound(n, q, d): @@ -544,7 +545,7 @@ def singleton_upper_bound(n, q, d): 256 """ _check_n_q_d(n, q, d, field_based=False) - return q**(n - d + 1) + return q ** (n - d + 1) def gv_info_rate(n, delta, q): @@ -560,7 +561,7 @@ def gv_info_rate(n, delta, q): 0.36704992608261894 """ q = ZZ(q) - return log(gilbert_lower_bound(n,q,int(n*delta)),q)/n + return log(gilbert_lower_bound(n, q, int(n * delta)), q) / n def entropy(x, q=2): @@ -595,16 +596,15 @@ def entropy(x, q=2): ValueError: The value q must be an integer greater than 1 """ if x < 0 or x > 1: - raise ValueError("The entropy function is defined only for x in the" - " interval [0, 1]") - q = ZZ(q) # This will error out if q is not an integer - if q < 2: # Here we check that q is actually at least 2 + raise ValueError("The entropy function is defined only for x in the" " interval [0, 1]") + q = ZZ(q) # This will error out if q is not an integer + if q < 2: # Here we check that q is actually at least 2 raise ValueError("The value q must be an integer greater than 1") if x == 0: return 0 if x == 1: - return log(q-1,q) - H = x*log(q-1,q)-x*log(x,q)-(1-x)*log(1-x,q) + return log(q - 1, q) + H = x * log(q - 1, q) - x * log(x, q) - (1 - x) * log(1 - x, q) return H @@ -640,21 +640,21 @@ def entropy_inverse(x, q=2): """ # No nice way to compute the inverse. We resort to root finding. if x < 0 or x > 1: - raise ValueError("The inverse entropy function is defined only for " - "x in the interval [0, 1]") - q = ZZ(q) # This will error out if q is not an integer - if q < 2: # Here we check that q is actually at least 2 + raise ValueError("The inverse entropy function is defined only for " "x in the interval [0, 1]") + q = ZZ(q) # This will error out if q is not an integer + if q < 2: # Here we check that q is actually at least 2 raise ValueError("The value q must be an integer greater than 1") - eps = 4.5e-16 # find_root has about this as the default xtol - ymax = 1 - 1/q + eps = 4.5e-16 # find_root has about this as the default xtol + ymax = 1 - 1 / q if x <= eps: return 0 - if x >= 1-eps: + if x >= 1 - eps: return ymax # find_root will error out if the root can not be found from sage.numerical.optimize import find_root + f = lambda y: entropy(y, q) - x return find_root(f, 0, ymax) @@ -733,7 +733,7 @@ def elias_bound_asymp(delta, q): 0.39912396330... """ r = 1 - 1 / q - return RDF(1-entropy(r-sqrt(r*(r-delta)), q)) + return RDF(1 - entropy(r - sqrt(r * (r - delta)), q)) def mrrw1_bound_asymp(delta, q): @@ -747,4 +747,4 @@ def mrrw1_bound_asymp(delta, q): sage: codes.bounds.mrrw1_bound_asymp(1/4,2) # abs tol 4e-16 # needs sage.symbolic 0.3545789026652697 """ - return RDF(entropy((q-1-delta*(q-2)-2*sqrt((q-1)*delta*(1-delta)))/q,q)) + return RDF(entropy((q - 1 - delta * (q - 2) - 2 * sqrt((q - 1) * delta * (1 - delta))) / q, q)) diff --git a/src/sage/coding/code_constructions.py b/src/sage/coding/code_constructions.py index 167afe0828f..d62c7e3f1bb 100644 --- a/src/sage/coding/code_constructions.py +++ b/src/sage/coding/code_constructions.py @@ -158,8 +158,7 @@ def _is_a_splitting(S1, S2, n, return_automorphism=False): S2 = {R(x) for x in S2} # we first check whether (S1,S2) is a partition of R - {0} - if (len(S1) + len(S2) != n-1 or len(S1) != len(S2) or - R.zero() in S1 or R.zero() in S2 or not S1.isdisjoint(S2)): + if len(S1) + len(S2) != n - 1 or len(S1) != len(S2) or R.zero() in S1 or R.zero() in S2 or not S1.isdisjoint(S2): if return_automorphism: return False, None return False @@ -317,12 +316,13 @@ def walsh_matrix(m0): """ m = int(m0) if m == 1: - return matrix(GF(2), 1, 2, [ 0, 1]) + return matrix(GF(2), 1, 2, [0, 1]) if m > 1: - row2 = [x.list() for x in walsh_matrix(m-1).augment(walsh_matrix(m-1)).rows()] - return matrix(GF(2), m, 2**m, [[0]*2**(m-1) + [1]*2**(m-1)] + row2) + row2 = [x.list() for x in walsh_matrix(m - 1).augment(walsh_matrix(m - 1)).rows()] + return matrix(GF(2), m, 2**m, [[0] * 2 ** (m - 1) + [1] * 2 ** (m - 1)] + row2) raise ValueError("%s must be an integer > 0." % m0) + ##################### main constructions ##################### @@ -352,28 +352,30 @@ def DuadicCodeEvenPair(F, S1, S2): [11, 5] Cyclic Code over GF(3)) """ from sage.misc.stopgap import stopgap + stopgap("The function DuadicCodeEvenPair has several issues which may cause wrong results", 25896) from .cyclic_code import CyclicCode + n = len(S1) + len(S2) + 1 - if not _is_a_splitting(S1,S2,n): - raise TypeError("%s, %s must be a splitting of %s." % (S1,S2,n)) + if not _is_a_splitting(S1, S2, n): + raise TypeError("%s, %s must be a splitting of %s." % (S1, S2, n)) q = F.order() - k = Mod(q,n).multiplicative_order() - FF = GF(q**k,"z") + k = Mod(q, n).multiplicative_order() + FF = GF(q**k, "z") z = FF.gen() - zeta = z**((q**k-1)/n) - P1 = PolynomialRing(FF,"x") + zeta = z ** ((q**k - 1) / n) + P1 = PolynomialRing(FF, "x") x = P1.gen() - g1 = prod([x-zeta**i for i in S1+[0]]) - g2 = prod([x-zeta**i for i in S2+[0]]) - P2 = PolynomialRing(F,"x") + g1 = prod([x - zeta**i for i in S1 + [0]]) + g2 = prod([x - zeta**i for i in S2 + [0]]) + P2 = PolynomialRing(F, "x") x = P2.gen() gg1 = P2([_lift2smallest_field(c)[0] for c in g1.coefficients(sparse=False)]) gg2 = P2([_lift2smallest_field(c)[0] for c in g2.coefficients(sparse=False)]) C1 = CyclicCode(length=n, generator_pol=gg1) C2 = CyclicCode(length=n, generator_pol=gg2) - return C1,C2 + return C1, C2 def DuadicCodeOddPair(F, S1, S2): @@ -403,33 +405,35 @@ def DuadicCodeOddPair(F, S1, S2): This is consistent with Theorem 6.1.3 in [HP2003]_. """ from sage.misc.stopgap import stopgap + stopgap("The function DuadicCodeOddPair has several issues which may cause wrong results", 25896) from .cyclic_code import CyclicCode + n = len(S1) + len(S2) + 1 - if not _is_a_splitting(S1,S2,n): - raise TypeError("%s, %s must be a splitting of %s." % (S1,S2,n)) + if not _is_a_splitting(S1, S2, n): + raise TypeError("%s, %s must be a splitting of %s." % (S1, S2, n)) q = F.order() - k = Mod(q,n).multiplicative_order() - FF = GF(q**k,"z") + k = Mod(q, n).multiplicative_order() + FF = GF(q**k, "z") z = FF.gen() - zeta = z**((q**k-1)/n) - P1 = PolynomialRing(FF,"x") + zeta = z ** ((q**k - 1) / n) + P1 = PolynomialRing(FF, "x") x = P1.gen() - g1 = prod([x-zeta**i for i in S1+[0]]) - g2 = prod([x-zeta**i for i in S2+[0]]) - j = sum([x**i/n for i in range(n)]) - P2 = PolynomialRing(F,"x") + g1 = prod([x - zeta**i for i in S1 + [0]]) + g2 = prod([x - zeta**i for i in S2 + [0]]) + j = sum([x**i / n for i in range(n)]) + P2 = PolynomialRing(F, "x") x = P2.gen() - coeffs1 = [_lift2smallest_field(c)[0] for c in (g1+j).coefficients(sparse=False)] - coeffs2 = [_lift2smallest_field(c)[0] for c in (g2+j).coefficients(sparse=False)] + coeffs1 = [_lift2smallest_field(c)[0] for c in (g1 + j).coefficients(sparse=False)] + coeffs2 = [_lift2smallest_field(c)[0] for c in (g2 + j).coefficients(sparse=False)] gg1 = P2(coeffs1) gg2 = P2(coeffs2) gg1 = gcd(gg1, x**n - 1) gg2 = gcd(gg2, x**n - 1) C1 = CyclicCode(length=n, generator_pol=gg1) C2 = CyclicCode(length=n, generator_pol=gg2) - return C1,C2 + return C1, C2 def ExtendedQuadraticResidueCode(n, F): @@ -469,7 +473,7 @@ def ExtendedQuadraticResidueCode(n, F): - David Joyner (07-2006) """ - C = QuadraticResidueCodeOddPair(n,F)[0] + C = QuadraticResidueCodeOddPair(n, F)[0] return C.extended_code() @@ -538,7 +542,7 @@ def QuadraticResidueCode(n, F): - David Joyner (11-2005) """ - return QuadraticResidueCodeOddPair(n,F)[0] + return QuadraticResidueCodeOddPair(n, F)[0] def QuadraticResidueCodeEvenPair(n, F): @@ -593,6 +597,7 @@ def QuadraticResidueCodeEvenPair(n, F): """ from sage.arith.srange import srange from sage.categories.finite_fields import FiniteFields + if F not in FiniteFields(): raise ValueError("the argument F must be a finite field") q = F.order() @@ -600,11 +605,11 @@ def QuadraticResidueCodeEvenPair(n, F): if n <= 2 or not n.is_prime(): raise ValueError("the argument n must be an odd prime") Q = quadratic_residues(n) - Q.remove(0) # nonzero quad residues - N = [x for x in srange(1, n) if x not in Q] # nonzero quad non-residues + Q.remove(0) # nonzero quad residues + N = [x for x in srange(1, n) if x not in Q] # nonzero quad non-residues if q not in Q: raise ValueError("the order of the finite field must be a quadratic residue modulo n") - return DuadicCodeEvenPair(F,Q,N) + return DuadicCodeEvenPair(F, Q, N) def QuadraticResidueCodeOddPair(n, F): @@ -653,6 +658,7 @@ def QuadraticResidueCodeOddPair(n, F): """ from sage.arith.srange import srange from sage.categories.finite_fields import FiniteFields + if F not in FiniteFields(): raise ValueError("the argument F must be a finite field") q = F.order() @@ -660,11 +666,11 @@ def QuadraticResidueCodeOddPair(n, F): if n <= 2 or not n.is_prime(): raise ValueError("the argument n must be an odd prime") Q = quadratic_residues(n) - Q.remove(0) # nonzero quad residues - N = [x for x in srange(1, n) if x not in Q] # nonzero quad non-residues + Q.remove(0) # nonzero quad residues + N = [x for x in srange(1, n) if x not in Q] # nonzero quad non-residues if q not in Q: raise ValueError("the order of the finite field must be a quadratic residue modulo n") - return DuadicCodeOddPair(F,Q,N) + return DuadicCodeOddPair(F, Q, N) def random_linear_code(F, length, dimension): @@ -755,6 +761,7 @@ def ToricCode(P, F): - David Joyner (07-2006) """ from sage.combinat.tuple import Tuples + mset = [x for x in F if x != 0] d = len(P[0]) pts = Tuples(mset, d).list() @@ -763,7 +770,7 @@ def ToricCode(P, F): e = P[0] B = [] for e in P: - tmpvar = [prod([t[i]**e[i] for i in range(d)]) for t in pts] + tmpvar = [prod([t[i] ** e[i] for i in range(d)]) for t in pts] B.append(tmpvar) # now B0 *should* be a full rank matrix MS = MatrixSpace(F, k, n) @@ -797,4 +804,4 @@ def WalshCode(m): - :wikipedia:`Walsh_code` """ - return LinearCode(walsh_matrix(m), d=2**(m - 1)) + return LinearCode(walsh_matrix(m), d=2 ** (m - 1)) diff --git a/src/sage/coding/codes_catalog.py b/src/sage/coding/codes_catalog.py index a842e19c2c6..6b4ebfd3f51 100644 --- a/src/sage/coding/codes_catalog.py +++ b/src/sage/coding/codes_catalog.py @@ -61,14 +61,15 @@ sage: from sage.coding.codes_catalog import * """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2009 David Lucas # # Distributed under the terms of the GNU General Public License (GPL), # version 2 or later (at your preference). # # https://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** # This module is imported as "codes" in all.py so that codes. is # available in the global namespace. @@ -77,12 +78,7 @@ from .linear_code import LinearCode -_lazy_import('sage.coding.code_constructions', - ['DuadicCodeEvenPair', 'DuadicCodeOddPair', - 'ExtendedQuadraticResidueCode', 'from_parity_check_matrix', - 'QuadraticResidueCode', 'QuadraticResidueCodeEvenPair', - 'QuadraticResidueCodeOddPair', 'random_linear_code', - 'ToricCode', 'WalshCode']) +_lazy_import('sage.coding.code_constructions', ['DuadicCodeEvenPair', 'DuadicCodeOddPair', 'ExtendedQuadraticResidueCode', 'from_parity_check_matrix', 'QuadraticResidueCode', 'QuadraticResidueCodeEvenPair', 'QuadraticResidueCodeOddPair', 'random_linear_code', 'ToricCode', 'WalshCode']) _lazy_import('sage.coding.subfield_subcode', 'SubfieldSubcode') _lazy_import('sage.coding.extended_code', 'ExtendedCode') @@ -107,4 +103,4 @@ from . import encoders_catalog as encoders from . import bounds_catalog as bounds -_lazy_import('sage.coding','databases') +_lazy_import('sage.coding', 'databases') diff --git a/src/sage/coding/cyclic_code.py b/src/sage/coding/cyclic_code.py index 81520bef7d6..672b7129948 100644 --- a/src/sage/coding/cyclic_code.py +++ b/src/sage/coding/cyclic_code.py @@ -34,9 +34,7 @@ # http://www.gnu.org/licenses/ # ***************************************************************************** -from .linear_code import (AbstractLinearCode, - LinearCodeSyndromeDecoder, - LinearCodeNearestNeighborDecoder) +from .linear_code import AbstractLinearCode, LinearCodeSyndromeDecoder, LinearCodeNearestNeighborDecoder from .encoder import Encoder from .decoder import Decoder from copy import copy @@ -85,7 +83,7 @@ def find_generator_polynomial(code, check=True): if check: n = code.length() k = code.dimension() - if (g.degree() != n - k): + if g.degree() != n - k: raise ValueError("The code is not cyclic.") c = _to_complete_list(g, n) if any(vector(c[i:] + c[:i]) not in code for i in range(n)): @@ -171,6 +169,7 @@ def bch_bound(n, D, arithmetic=False): sage: sage.coding.cyclic_code.bch_bound(n, D, True) (4, (2, 12)) """ + def longest_streak(step): max_len = 1 max_offset = 0 @@ -190,8 +189,7 @@ def longest_streak(step): try: isD[d] = 1 except IndexError: - raise ValueError("%s must contains integers between 0 and %s" % - (D, n - 1)) + raise ValueError("%s must contains integers between 0 and %s" % (D, n - 1)) if 0 not in isD: return (n + 1, (1, 0)) @@ -199,9 +197,7 @@ def longest_streak(step): one_len, offset = longest_streak(1) return (one_len + 1, (1, offset)) n = Integer(n) - longest_streak_list = [(longest_streak(step), step) - for step in n.coprime_integers(n // 2 + 1) - if step >= 1] + longest_streak_list = [(longest_streak(step), step) for step in n.coprime_integers(n // 2 + 1) if step >= 1] (max_len, offset), step = max(longest_streak_list) return (max_len + 1, (step, offset)) @@ -286,8 +282,7 @@ class CyclicCode(AbstractLinearCode): _registered_encoders = {} _registered_decoders = {} - def __init__(self, generator_pol=None, length=None, code=None, check=True, - D=None, field=None, primitive_root=None) -> None: + def __init__(self, generator_pol=None, length=None, code=None, check=True, D=None, field=None, primitive_root=None) -> None: r""" TESTS: @@ -357,24 +352,19 @@ def __init__(self, generator_pol=None, length=None, code=None, check=True, ValueError: primitive_root must be a primitive n-th root of unity """ # Case (1) : generator polynomial and length are provided. - if (generator_pol is not None and length is not None and - code is None and D is None and field is None and - primitive_root is None): + if generator_pol is not None and length is not None and code is None and D is None and field is None and primitive_root is None: F = generator_pol.base_ring() if not F.is_finite() or not F.is_field(): - raise ValueError("The generator polynomial must be defined " - "over a finite field.") + raise ValueError("The generator polynomial must be defined " "over a finite field.") q = F.cardinality() if not gcd(length, q) == 1: - raise ValueError("Only cyclic codes whose length and field " - "order are coprimes are implemented.") + raise ValueError("Only cyclic codes whose length and field " "order are coprimes are implemented.") R = generator_pol.parent() deg = generator_pol.degree() if not isinstance(length, Integer): length = Integer(length) if not generator_pol.divides(R.gen() ** length - 1): - raise ValueError("Provided polynomial must divide x^n - 1, " - "where n is the provided length.") + raise ValueError("Provided polynomial must divide x^n - 1, " "where n is the provided length.") self._polynomial_ring = R self._dimension = length - deg if not generator_pol.is_monic(): @@ -384,17 +374,14 @@ def __init__(self, generator_pol=None, length=None, code=None, check=True, super().__init__(F, length, "Vector", "Syndrome") # Case (2) : a code is provided. - elif (code is not None and - generator_pol is None and length is None and D is None and - field is None and primitive_root is None): + elif code is not None and generator_pol is None and length is None and D is None and field is None and primitive_root is None: if not isinstance(code, AbstractLinearCode): raise ValueError("code must be an AbstractLinearCode") F = code.base_ring() q = F.cardinality() n = code.length() if not gcd(n, q) == 1: - raise ValueError("Only cyclic codes whose length and field " - "order are coprimes are implemented.") + raise ValueError("Only cyclic codes whose length and field " "order are coprimes are implemented.") g = find_generator_polynomial(code, check) self._polynomial_ring = g.parent() self._generator_polynomial = g @@ -402,16 +389,14 @@ def __init__(self, generator_pol=None, length=None, code=None, check=True, super().__init__(code.base_ring(), n, "Vector", "Syndrome") # Case (3) : a defining set, a length and a field are provided - elif (D is not None and length is not None and field is not None and - generator_pol is None and code is None): + elif D is not None and length is not None and field is not None and generator_pol is None and code is None: F = field if not F.is_finite() or not F.is_field(): raise ValueError("You must provide a finite field.") n = length q = F.cardinality() if not gcd(n, q) == 1: - raise ValueError("Only cyclic codes whose length and field " - "order are coprimes are implemented.") + raise ValueError("Only cyclic codes whose length and field " "order are coprimes are implemented.") R = F['x'] s = Zmod(n)(q).multiplicative_order() @@ -421,13 +406,10 @@ def __init__(self, generator_pol=None, length=None, code=None, check=True, try: FE = Hom(F, Fsplit)[0] except Exception: - raise ValueError("primitive_root must belong to an " - "extension of the base field") + raise ValueError("primitive_root must belong to an " "extension of the base field") extension_degree = Fsplit.degree() // F.degree() - if (extension_degree != s or - primitive_root.multiplicative_order() != n): - raise ValueError("primitive_root must be a primitive " - "n-th root of unity") + if extension_degree != s or primitive_root.multiplicative_order() != n: + raise ValueError("primitive_root must be a primitive " "n-th root of unity") alpha = primitive_root else: Fsplit, FE = F.extension(Integer(s), map=True) @@ -457,9 +439,7 @@ def __init__(self, generator_pol=None, length=None, code=None, check=True, super().__init__(F, n, "Vector", "SurroundingBCH") else: - raise AttributeError("You must provide either a code, or a list " - "of powers and the length and the field, or " - "a generator polynomial and the code length") + raise AttributeError("You must provide either a code, or a list " "of powers and the length and the field, or " "a generator polynomial and the code length") def __contains__(self, word) -> bool: r""" @@ -481,7 +461,7 @@ def __contains__(self, word) -> bool: """ g = self.generator_polynomial() R = self._polynomial_ring - return (g.divides(R(word.list())) and word in self.ambient_space()) + return g.divides(R(word.list())) and word in self.ambient_space() def __eq__(self, other) -> bool: r""" @@ -504,9 +484,7 @@ def __eq__(self, other) -> bool: if not isinstance(other, CyclicCode): return False R = self._polynomial_ring - return (self.base_field() == other.base_field() and - self.length() == other.length() and - self.generator_polynomial() == R(other.generator_polynomial())) + return self.base_field() == other.base_field() and self.length() == other.length() and self.generator_polynomial() == R(other.generator_polynomial()) def _repr_(self): r""" @@ -521,9 +499,7 @@ def _repr_(self): sage: C [7, 4] Cyclic Code over GF(2) """ - return ("[%s, %s] Cyclic Code over GF(%s)" - % (self.length(), self.dimension(), - self.base_field().cardinality())) + return "[%s, %s] Cyclic Code over GF(%s)" % (self.length(), self.dimension(), self.base_field().cardinality()) def _latex_(self): r""" @@ -538,9 +514,7 @@ def _latex_(self): sage: latex(C) [7, 4] \textnormal{ Cyclic Code over } \Bold{F}_{2} """ - return ("[%s, %s] \\textnormal{ Cyclic Code over } %s" - % (self.length(), self.dimension(), - self.base_field()._latex_())) + return "[%s, %s] \\textnormal{ Cyclic Code over } %s" % (self.length(), self.dimension(), self.base_field()._latex_()) def generator_polynomial(self): r""" @@ -633,9 +607,7 @@ def defining_set(self, primitive_root=None): sage: C1.defining_set() == C2.defining_set() True """ - if (hasattr(self, "_defining_set") and - (primitive_root is None or - primitive_root == self._primitive_root)): + if hasattr(self, "_defining_set") and (primitive_root is None or primitive_root == self._primitive_root): return self._defining_set F = self.base_field() n = self.length() @@ -653,11 +625,9 @@ def defining_set(self, primitive_root=None): Fsplit = alpha.parent() FE = Hom(Fsplit, F)[0] except ValueError: - raise ValueError("primitive_root does not belong to the " - "right splitting field") + raise ValueError("primitive_root does not belong to the " "right splitting field") if alpha.multiplicative_order() != n: - raise ValueError("primitive_root must have multiplicative " - "order equal to the code length") + raise ValueError("primitive_root must have multiplicative " "order equal to the code length") Rsplit = Fsplit['xx'] gsplit = Rsplit([FE(coeff) for coeff in g]) @@ -802,9 +772,9 @@ def surrounding_bch_code(self): True """ from .bch_code import BCHCode + delta, params = self.bch_bound(arithmetic=True) - return BCHCode(self.base_field(), self.length(), delta, - offset=params[1], jump_size=params[0]) + return BCHCode(self.base_field(), self.length(), delta, offset=params[1], jump_size=params[0]) class CyclicCodePolynomialEncoder(Encoder): @@ -864,8 +834,7 @@ def __eq__(self, other) -> bool: sage: E1 == E2 True """ - return (isinstance(other, CyclicCodePolynomialEncoder) and - self.code() == other.code()) + return isinstance(other, CyclicCodePolynomialEncoder) and self.code() == other.code() def _repr_(self): r""" @@ -897,8 +866,7 @@ def _latex_(self): sage: latex(E) \textnormal{Polynomial-style encoder for }[7, 4] \textnormal{ Cyclic Code over } \Bold{F}_{2} """ - return ("\\textnormal{Polynomial-style encoder for }%s" % - self.code()._latex_()) + return "\\textnormal{Polynomial-style encoder for }%s" % self.code()._latex_() def encode(self, p): r""" @@ -1034,8 +1002,7 @@ def __eq__(self, other) -> bool: sage: E1 == E2 True """ - return (isinstance(other, CyclicCodeVectorEncoder) and - self.code() == other.code()) + return isinstance(other, CyclicCodeVectorEncoder) and self.code() == other.code() def _repr_(self): r""" @@ -1067,8 +1034,7 @@ def _latex_(self): sage: latex(E) \textnormal{Vector-style encoder for }[7, 4] \textnormal{ Cyclic Code over } \Bold{F}_{2} """ - return ("\\textnormal{Vector-style encoder for }%s" % - self.code()._latex_()) + return "\\textnormal{Vector-style encoder for }%s" % self.code()._latex_() def encode(self, m): r""" @@ -1194,6 +1160,7 @@ class CyclicCodeSurroundingBCHDecoder(Decoder): sage: D Decoder through the surrounding BCH code of the [15, 10] Cyclic Code over GF(16) """ + def __init__(self, code, **kwargs) -> None: r""" @@ -1221,9 +1188,7 @@ def __eq__(self, other) -> bool: sage: D1 == D2 True """ - return (isinstance(other, CyclicCodeSurroundingBCHDecoder) and - self.code() == other.code() and - self.bch_decoder() == other.bch_decoder()) + return isinstance(other, CyclicCodeSurroundingBCHDecoder) and self.code() == other.code() and self.bch_decoder() == other.bch_decoder() def _repr_(self): r""" @@ -1236,8 +1201,7 @@ def _repr_(self): sage: D Decoder through the surrounding BCH code of the [15, 10] Cyclic Code over GF(16) """ - return ("Decoder through the surrounding BCH code of the %s" % - self.code()) + return "Decoder through the surrounding BCH code of the %s" % self.code() def _latex_(self): r""" @@ -1250,8 +1214,7 @@ def _latex_(self): sage: latex(D) \textnormal{Decoder through the surrounding BCH code of the }[15, 10] \textnormal{ Cyclic Code over } \Bold{F}_{2^{4}} """ - return ("\\textnormal{Decoder through the surrounding BCH code of " - "the }%s" % self.code()._latex_()) + return "\\textnormal{Decoder through the surrounding BCH code of " "the }%s" % self.code()._latex_() def bch_code(self): r""" diff --git a/src/sage/coding/databases.py b/src/sage/coding/databases.py index 992280eef93..f614d1ec53f 100644 --- a/src/sage/coding/databases.py +++ b/src/sage/coding/databases.py @@ -50,8 +50,10 @@ def best_linear_code_in_guava(n, k, F): """ from sage.features.gap import GapPackage from .linear_code import LinearCode + GapPackage('guava', spkg='gap_packages').require() from sage.libs.gap.libgap import libgap + libgap.load_package('guava') C = libgap.BestKnownLinearCode(n, k, F) return LinearCode(C.GeneratorMat()._matrix_(F)) @@ -109,8 +111,10 @@ def bounds_on_minimum_distance_in_guava(n, k, F): upperBoundExplanation := ... ) """ from sage.features.gap import GapPackage + GapPackage('guava', spkg='gap_packages').require() from sage.libs.gap.libgap import libgap + libgap.load_package('guava') return libgap.BoundsMinimumDistance(n, k, F) @@ -157,6 +161,7 @@ def best_linear_code_in_codetables_dot_de(n, k, F, verbose=False): """ from urllib.request import urlopen from sage.cpython.string import bytes_to_str + q = F.order() if q not in [2, 3, 4, 5, 7, 8, 9]: raise ValueError("q (=%s) must be in [2,3,4,5,7,8,9]" % q) @@ -176,11 +181,10 @@ def best_linear_code_in_codetables_dot_de(n, k, F, verbose=False): j = s.find("") if i == -1 or j == -1: raise OSError("Error parsing data (missing pre tags).") - return s[i+5:j].strip() + return s[i + 5 : j].strip() -def self_orthogonal_binary_codes(n, k, b=2, parent=None, BC=None, equal=False, - in_test=None): +def self_orthogonal_binary_codes(n, k, b=2, parent=None, BC=None, equal=False, in_test=None): """ Return a Python iterator which generates a complete set of representatives of all permutation equivalence classes of @@ -284,10 +288,11 @@ def self_orthogonal_binary_codes(n, k, b=2, parent=None, BC=None, equal=False, raise ValueError("b (%s) must be a positive even integer." % b) from .linear_code import LinearCode from .binary_code import BinaryCode, BinaryCodeClassifier + if k < 1 or n < 2: return if equal: - in_test = lambda M: (M.ncols() - M.nrows()) <= (n-k) + in_test = lambda M: (M.ncols() - M.nrows()) <= (n - k) out_test = lambda C: (C.dimension() == k) and (C.length() == n) else: in_test = lambda M: True @@ -295,8 +300,8 @@ def self_orthogonal_binary_codes(n, k, b=2, parent=None, BC=None, equal=False, if BC is None: BC = BinaryCodeClassifier() if parent is None: - for j in range(d, n+1, d): - M = Matrix(FiniteField(2), [[1]*j]) + for j in range(d, n + 1, d): + M = Matrix(FiniteField(2), [[1] * j]) if in_test(M): for N in self_orthogonal_binary_codes(n, k, d, M, BC, in_test=in_test): if out_test(N): @@ -307,7 +312,7 @@ def self_orthogonal_binary_codes(n, k, b=2, parent=None, BC=None, equal=False, yield C if k == parent.nrows(): return - for nn in range(parent.ncols()+1, n+1): + for nn in range(parent.ncols() + 1, n + 1): if in_test(parent): for child in BC.generate_children(BinaryCode(parent), nn, d): for N in self_orthogonal_binary_codes(n, k, d, child, BC, in_test=in_test): diff --git a/src/sage/coding/decoder.py b/src/sage/coding/decoder.py index bb2325a468a..41b910ead8e 100644 --- a/src/sage/coding/decoder.py +++ b/src/sage/coding/decoder.py @@ -10,7 +10,7 @@ - David Lucas (2015-06-29): abstract class version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2009 David Joyner # 2015 David Lucas # @@ -18,7 +18,7 @@ # version 2 or later (at your preference). # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.abstract_method import abstract_method from sage.structure.sage_object import SageObject @@ -368,4 +368,5 @@ class DecodingError(Exception): r""" Special exception class to indicate an error during decoding. """ + pass diff --git a/src/sage/coding/decoders_catalog.py b/src/sage/coding/decoders_catalog.py index a9f2417880e..fbd3b765a2b 100644 --- a/src/sage/coding/decoders_catalog.py +++ b/src/sage/coding/decoders_catalog.py @@ -50,7 +50,8 @@ sage: from sage.coding.decoders_catalog import * """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2009 David Joyner # 2015 David Lucas # @@ -58,22 +59,18 @@ # version 2 or later (at your preference). # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.lazy_import import lazy_import lazy_import('sage.coding.bch_code', 'BCHUnderlyingGRSDecoder') lazy_import('sage.coding.cyclic_code', 'CyclicCodeSurroundingBCHDecoder') lazy_import('sage.coding.extended_code', 'ExtendedCodeOriginalCodeDecoder') -lazy_import('sage.coding.grs_code', ['GRSBerlekampWelchDecoder', - 'GRSErrorErasureDecoder', - 'GRSGaoDecoder', - 'GRSKeyEquationSyndromeDecoder']) +lazy_import('sage.coding.grs_code', ['GRSBerlekampWelchDecoder', 'GRSErrorErasureDecoder', 'GRSGaoDecoder', 'GRSKeyEquationSyndromeDecoder']) from .guruswami_sudan.gs_decoder import GRSGuruswamiSudanDecoder -lazy_import('sage.coding.linear_code', ['LinearCodeNearestNeighborDecoder', - 'LinearCodeSyndromeDecoder', - 'LinearCodeInformationSetDecoder']) + +lazy_import('sage.coding.linear_code', ['LinearCodeNearestNeighborDecoder', 'LinearCodeSyndromeDecoder', 'LinearCodeInformationSetDecoder']) lazy_import('sage.coding.punctured_code', 'PuncturedCodeOriginalCodeDecoder') lazy_import('sage.coding.subfield_subcode', 'SubfieldSubcodeOriginalCodeDecoder') @@ -81,7 +78,6 @@ lazy_import('sage.coding.linear_rank_metric', 'LinearRankMetricCodeNearestNeighborDecoder') lazy_import('sage.coding.gabidulin_code', 'GabidulinGaoDecoder') -lazy_import('sage.coding.ag_code_decoders', ['EvaluationAGCodeUniqueDecoder', - 'DifferentialAGCodeUniqueDecoder']) +lazy_import('sage.coding.ag_code_decoders', ['EvaluationAGCodeUniqueDecoder', 'DifferentialAGCodeUniqueDecoder']) del lazy_import diff --git a/src/sage/coding/delsarte_bounds.py b/src/sage/coding/delsarte_bounds.py index a34099fd548..2f3d052e677 100644 --- a/src/sage/coding/delsarte_bounds.py +++ b/src/sage/coding/delsarte_bounds.py @@ -103,17 +103,19 @@ def krawtchouk(n, q, l, x, check=True): """ from sage.arith.misc import binomial from sage.arith.srange import srange + # Use the expression in equation (55) of MacWilliams & Sloane, pg 151 # We write jth term = some_factor * (j-1)th term if check: from sage.rings.integer_ring import ZZ + l0 = ZZ(l) if l0 != l or l0 < 0: raise ValueError('l must be a nonnegative integer') l = l0 - kraw = jth_term = (q-1)**l * binomial(n, l) # j=0 - for j in srange(1, l+1): - jth_term *= -q*(l-j+1)*(x-j+1)/((q-1)*j*(n-j+1)) + kraw = jth_term = (q - 1) ** l * binomial(n, l) # j=0 + for j in srange(1, l + 1): + jth_term *= -q * (l - j + 1) * (x - j + 1) / ((q - 1) * j * (n - j + 1)) kraw += jth_term return kraw @@ -176,13 +178,13 @@ def eberlein(n, w, k, u, check=True): if check: from sage.rings.integer_ring import ZZ + n0 = ZZ(n) if n0 != n or n0 < 0: raise ValueError('l must be a nonnegative integer') n = n0 - return sum([(-1)**j*binomial(u, j)*binomial(w-u, k-j)*binomial(n-w-u, k-j) - for j in srange(k + 1)]) + return sum([(-1) ** j * binomial(u, j) * binomial(w - u, k - j) * binomial(n - w - u, k - j) for j in srange(k + 1)]) def _delsarte_LP_building(n, d, d_star, q, isinteger, solver, maxc=0): @@ -217,8 +219,7 @@ def _delsarte_LP_building(n, d, d_star, q, isinteger, solver, maxc=0): for i in range(1, d): p.add_constraint(A[i] == 0) for j in range(1, n + 1): - rhs = p.sum([krawtchouk(n, q, j, r, check=False) * A[r] - for r in range(n + 1)]) + rhs = p.sum([krawtchouk(n, q, j, r, check=False) * A[r] for r in range(n + 1)]) if j >= d_star: p.add_constraint(0 <= rhs) else: # rhs is proportional to j-th weight of the dual code @@ -273,22 +274,20 @@ def _delsarte_cwc_LP_building(n, d, w, solver, isinteger): p = MixedIntegerLinearProgram(maximization=True, solver=solver) A = p.new_variable(integer=isinteger, nonnegative=True) - p.set_objective(p.sum([A[2*r] for r in range(d//2, w+1)]) + 1) + p.set_objective(p.sum([A[2 * r] for r in range(d // 2, w + 1)]) + 1) def _q(k, i): mu_i = 1 - v_i = binomial(w, i)*binomial(n-w, i) - return mu_i*eberlein(n, w, i, k)/v_i + v_i = binomial(w, i) * binomial(n - w, i) + return mu_i * eberlein(n, w, i, k) / v_i - for k in range(1, w+1): - p.add_constraint(p.sum([A[2*i]*_q(k, i) for i in range(d//2, w+1)]), - min=-1) + for k in range(1, w + 1): + p.add_constraint(p.sum([A[2 * i] * _q(k, i) for i in range(d // 2, w + 1)]), min=-1) return A, p -def delsarte_bound_constant_weight_code(n, d, w, return_data=False, - solver='PPL', isinteger=False): +def delsarte_bound_constant_weight_code(n, d, w, return_data=False, solver='PPL', isinteger=False): r""" Find the Delsarte bound on a constant weight code. @@ -337,12 +336,10 @@ def delsarte_bound_constant_weight_code(n, d, w, return_data=False, from sage.numerical.mip import MIPSolverException if d < 4: - raise ValueError("Violated constraint d>=4 for " - "Binary Constant Weight Codes") + raise ValueError("Violated constraint d>=4 for " "Binary Constant Weight Codes") - if d >= 2*w or 2*w > n: - raise ValueError("Violated constraint d<2w<=n for " - "Binary Constant Weight Codes") + if d >= 2 * w or 2 * w > n: + raise ValueError("Violated constraint d<2w<=n for " "Binary Constant Weight Codes") # minimum distance is even => if there is an odd lower bound on d we can # increase it by 1 @@ -359,8 +356,7 @@ def delsarte_bound_constant_weight_code(n, d, w, return_data=False, return (A, p, bd) if return_data else int(bd) -def delsarte_bound_hamming_space(n, d, q, return_data=False, - solver='PPL', isinteger=False): +def delsarte_bound_hamming_space(n, d, q, return_data=False, solver='PPL', isinteger=False): r""" Find the Delsarte bound on codes in ``H_q^n`` of minimal distance ``d``. @@ -433,6 +429,7 @@ def delsarte_bound_hamming_space(n, d, q, return_data=False, False """ from sage.numerical.mip import MIPSolverException + A, p = _delsarte_LP_building(n, d, 0, q, isinteger, solver) try: bd = p.solve() @@ -443,8 +440,7 @@ def delsarte_bound_hamming_space(n, d, q, return_data=False, return (A, p, bd) if return_data else bd -def delsarte_bound_additive_hamming_space(n, d, q, d_star=1, q_base=0, return_data=False, - solver='PPL', isinteger=False): +def delsarte_bound_additive_hamming_space(n, d, q, d_star=1, q_base=0, return_data=False, solver='PPL', isinteger=False): r""" Find a modified Delsarte bound on additive codes in Hamming space `H_q^n` of minimal distance `d`. @@ -524,6 +520,7 @@ def delsarte_bound_additive_hamming_space(n, d, q, d_star=1, q_base=0, return_da 3 """ from sage.numerical.mip import MIPSolverException + if q_base == 0: q_base = q @@ -538,27 +535,26 @@ def delsarte_bound_additive_hamming_space(n, d, q, d_star=1, q_base=0, return_da # this implementation assumes that our LP solver to be unable to do a hot # restart with an adjusted constraint - m = kk*n # this is to emulate repeat/until block - bd = q**n+1 + m = kk * n # this is to emulate repeat/until block + bd = q**n + 1 while q_base**m < bd: # need to solve the LP repeatedly, as this is a new constraint! # we might become infeasible. More precisely, after rounding down # to the closest value of q_base^m, the LP, with the constraint that # the objective function is at most q_base^m, - A, p = _delsarte_LP_building(n, d, d_star, q, isinteger, - solver, q_base**m) + A, p = _delsarte_LP_building(n, d, d_star, q, isinteger, solver, q_base**m) try: bd = p.solve() except MIPSolverException as exc: print("Solver exception:", exc) return (A, p, False) if return_data else False - # rounding the bound down to the nearest power of q_base, for q=q_base^m - # bd_r = roundres(log(bd, base=q_base)) + # rounding the bound down to the nearest power of q_base, for q=q_base^m + # bd_r = roundres(log(bd, base=q_base)) m = -1 - while q_base**(m+1) < bd: + while q_base ** (m + 1) < bd: m += 1 - if q_base**(m+1) == bd: + if q_base ** (m + 1) == bd: m += 1 return (A, p, m) if return_data else m @@ -637,8 +633,7 @@ def _delsarte_Q_LP_building(q, d, solver, isinteger): return A, p -def delsarte_bound_Q_matrix(q, d, return_data=False, - solver='PPL', isinteger=False): +def delsarte_bound_Q_matrix(q, d, return_data=False, solver='PPL', isinteger=False): r""" Delsarte bound on a code with Q matrix ``q`` and lower bound on min. dist. ``d``. @@ -695,8 +690,7 @@ def delsarte_bound_Q_matrix(q, d, return_data=False, from sage.structure.element import Matrix if not isinstance(q, Matrix): - raise ValueError("Input to delsarte_bound_Q_matrix " - "should be a sage Matrix()") + raise ValueError("Input to delsarte_bound_Q_matrix " "should be a sage Matrix()") A, p = _delsarte_Q_LP_building(q, d, solver, isinteger) try: diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py index 4bf5ad5ca3d..75167475a0b 100644 --- a/src/sage/coding/encoder.py +++ b/src/sage/coding/encoder.py @@ -8,7 +8,7 @@ - David Lucas (2015): initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2015 David Lucas # # This program is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.modules.free_module_element import vector from sage.misc.abstract_method import abstract_method @@ -357,7 +357,7 @@ def message_space(self): sage: E.message_space() Vector space of dimension 4 over Finite Field of size 2 """ - return self.code().base_field()**(self.code().dimension()) + return self.code().base_field() ** (self.code().dimension()) @abstract_method(optional=True) def generator_matrix(self): @@ -387,4 +387,5 @@ class EncodingError(Exception): r""" Special exception class to indicate an error during encoding or unencoding. """ + pass diff --git a/src/sage/coding/encoders_catalog.py b/src/sage/coding/encoders_catalog.py index e6ac68267fd..1191052e2b6 100644 --- a/src/sage/coding/encoders_catalog.py +++ b/src/sage/coding/encoders_catalog.py @@ -30,7 +30,8 @@ sage: from sage.coding.encoders_catalog import * """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2009 David Joyner # 2015 David Lucas # 2016 Tania Richmond @@ -39,25 +40,19 @@ # version 2 or later (at your preference). # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.lazy_import import lazy_import as _lazy_import -_lazy_import('sage.coding.cyclic_code', ['CyclicCodePolynomialEncoder', - 'CyclicCodeVectorEncoder']) +_lazy_import('sage.coding.cyclic_code', ['CyclicCodePolynomialEncoder', 'CyclicCodeVectorEncoder']) _lazy_import('sage.coding.extended_code', 'ExtendedCodeExtendedMatrixEncoder') -_lazy_import('sage.coding.grs_code', ['GRSEvaluationVectorEncoder', - 'GRSEvaluationPolynomialEncoder']) +_lazy_import('sage.coding.grs_code', ['GRSEvaluationVectorEncoder', 'GRSEvaluationPolynomialEncoder']) _lazy_import('sage.coding.linear_code', 'LinearCodeGeneratorMatrixEncoder') _lazy_import('sage.coding.linear_code_no_metric', 'LinearCodeSystematicEncoder') _lazy_import('sage.coding.punctured_code', 'PuncturedCodePuncturedMatrixEncoder') -_lazy_import('sage.coding.reed_muller_code', ['ReedMullerVectorEncoder', - 'ReedMullerPolynomialEncoder']) +_lazy_import('sage.coding.reed_muller_code', ['ReedMullerVectorEncoder', 'ReedMullerPolynomialEncoder']) _lazy_import('sage.coding.subfield_subcode', 'SubfieldSubcodeParityCheckEncoder') -_lazy_import('sage.coding.parity_check_code', ['ParityCheckCodeGeneratorMatrixEncoder', - 'ParityCheckCodeStraightforwardEncoder']) +_lazy_import('sage.coding.parity_check_code', ['ParityCheckCodeGeneratorMatrixEncoder', 'ParityCheckCodeStraightforwardEncoder']) _lazy_import('sage.coding.goppa_code', ['GoppaCodeEncoder']) -_lazy_import('sage.coding.gabidulin_code', ['GabidulinVectorEvaluationEncoder', - 'GabidulinPolynomialEvaluationEncoder']) -_lazy_import('sage.coding.ag_code_decoders', ['EvaluationAGCodeEncoder', - 'DifferentialAGCodeEncoder']) +_lazy_import('sage.coding.gabidulin_code', ['GabidulinVectorEvaluationEncoder', 'GabidulinPolynomialEvaluationEncoder']) +_lazy_import('sage.coding.ag_code_decoders', ['EvaluationAGCodeEncoder', 'DifferentialAGCodeEncoder']) diff --git a/src/sage/coding/extended_code.py b/src/sage/coding/extended_code.py index 4243da85b24..58c5c2adaf3 100644 --- a/src/sage/coding/extended_code.py +++ b/src/sage/coding/extended_code.py @@ -11,7 +11,7 @@ See [HP2003]_ (pp 15-16) for details. """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2016 David Lucas # # This program is free software: you can redistribute it and/or modify @@ -19,11 +19,9 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** -from .linear_code import (AbstractLinearCode, - LinearCodeSyndromeDecoder, - LinearCodeNearestNeighborDecoder) +from .linear_code import AbstractLinearCode, LinearCodeSyndromeDecoder, LinearCodeNearestNeighborDecoder from .encoder import Encoder from .decoder import Decoder from sage.misc.cachefunc import cached_method @@ -65,8 +63,7 @@ def __init__(self, C): """ if not isinstance(C, AbstractLinearCode): raise ValueError("Provided code must be a linear code") - super().__init__(C.base_ring(), C.length() + 1, - "ExtendedMatrix", "OriginalDecoder") + super().__init__(C.base_ring(), C.length() + 1, "ExtendedMatrix", "OriginalDecoder") self._original_code = C self._dimension = C.dimension() @@ -82,8 +79,7 @@ def __eq__(self, other): sage: C1 == C2 True """ - return isinstance(other, ExtendedCode)\ - and self.original_code() == other.original_code() + return isinstance(other, ExtendedCode) and self.original_code() == other.original_code() def _repr_(self): r""" @@ -248,8 +244,7 @@ def __eq__(self, other): sage: D1 is D2 False """ - return isinstance(other, ExtendedCodeExtendedMatrixEncoder) \ - and self.code() == other.code() + return isinstance(other, ExtendedCodeExtendedMatrixEncoder) and self.code() == other.code() @cached_method def generator_matrix(self): @@ -332,8 +327,7 @@ def __init__(self, code, original_decoder=None, **kwargs): self._decoder_type = copy(self._decoder_type) self._decoder_type.remove("dynamic") self._decoder_type = self._original_decoder.decoder_type() - super().__init__(code, code.ambient_space(), - self._original_decoder.connected_encoder()) + super().__init__(code, code.ambient_space(), self._original_decoder.connected_encoder()) def _repr_(self): r""" diff --git a/src/sage/coding/gabidulin_code.py b/src/sage/coding/gabidulin_code.py index 216444e4758..6a6a92ff7f2 100644 --- a/src/sage/coding/gabidulin_code.py +++ b/src/sage/coding/gabidulin_code.py @@ -54,11 +54,11 @@ class GabidulinCode(AbstractLinearRankMetricCode): sage: C [2, 2, 1] linear Gabidulin code over GF(16)/GF(4) """ + _registered_encoders = {} _registered_decoders = {} - def __init__(self, base_field, length, dimension, sub_field=None, - twisting_homomorphism=None, evaluation_points=None): + def __init__(self, base_field, length, dimension, sub_field=None, twisting_homomorphism=None, evaluation_points=None): r""" Representation of a Gabidulin Code. @@ -171,8 +171,8 @@ def __init__(self, base_field, length, dimension, sub_field=None, ValueError: if 'sub_field' is not given, the twisting homomorphism has to have a 'fixed_field' method """ twist_fix_field = None - have_twist = (twisting_homomorphism is not None) - have_subfield = (sub_field is not None) + have_twist = twisting_homomorphism is not None + have_subfield = sub_field is not None if have_twist and have_subfield: try: @@ -202,7 +202,7 @@ def __init__(self, base_field, length, dimension, sub_field=None, if length > self.extension_degree(): raise ValueError("'length' can be at most the degree of the extension, {}".format(self.extension_degree())) if evaluation_points is None: - evaluation_points = [base_field.gen()**i for i in range(base_field.degree())][:length] + evaluation_points = [base_field.gen() ** i for i in range(base_field.degree())][:length] else: if not len(evaluation_points) == length: raise ValueError("the number of evaluation points should be equal to the length of the code") @@ -245,8 +245,7 @@ def _latex_(self): [2, 2, 1] \textnormal{ linear Gabidulin code over } \Bold{F}_{2^{4}}/\Bold{F}_{2^{2}} """ txt = "[%s, %s, %s] \\textnormal{ linear Gabidulin code over } %s/%s" - return txt % (self.length(), self.dimension(), self.minimum_distance(), - self.base_field()._latex_(), self.sub_field()._latex_()) + return txt % (self.length(), self.dimension(), self.minimum_distance(), self.base_field()._latex_(), self.sub_field()._latex_()) def __eq__(self, other): """ @@ -272,12 +271,7 @@ def __eq__(self, other): sage: C3.__eq__(C2) False """ - return isinstance(other, GabidulinCode) \ - and self.base_field() == other.base_field() \ - and self.sub_field() == other.sub_field() \ - and self.length() == other.length() \ - and self.dimension() == other.dimension() \ - and self.evaluation_points() == other.evaluation_points() + return isinstance(other, GabidulinCode) and self.base_field() == other.base_field() and self.sub_field() == other.sub_field() and self.length() == other.length() and self.dimension() == other.dimension() and self.evaluation_points() == other.evaluation_points() def twisting_homomorphism(self): r""" @@ -327,8 +321,7 @@ def parity_evaluation_points(self): k = self.dimension() sigma = self.twisting_homomorphism() - coefficient_matrix = matrix(self.base_field(), n - 1, n, - lambda i, j: (sigma**(-n + k + 1 + i))(eval_pts[j])) + coefficient_matrix = matrix(self.base_field(), n - 1, n, lambda i, j: (sigma ** (-n + k + 1 + i))(eval_pts[j])) solution_space = coefficient_matrix.right_kernel() return list(solution_space.basis()[0]) @@ -348,11 +341,7 @@ def dual_code(self): sage: C == C1.dual_code() True """ - return GabidulinCode(self.base_field(), self.length(), - self.length() - self.dimension(), - self.sub_field(), - self.twisting_homomorphism(), - self.parity_evaluation_points()) + return GabidulinCode(self.base_field(), self.length(), self.length() - self.dimension(), self.sub_field(), self.twisting_homomorphism(), self.parity_evaluation_points()) def parity_check_matrix(self): r""" @@ -384,6 +373,7 @@ def evaluation_points(self): """ return self._evaluation_points + # ---------------------- encoders ------------------------------ @@ -483,8 +473,7 @@ def __eq__(self, other): sage: E3.__eq__(E2) False """ - return isinstance(other, GabidulinVectorEvaluationEncoder) \ - and self.code() == other.code() + return isinstance(other, GabidulinVectorEvaluationEncoder) and self.code() == other.code() def generator_matrix(self): """ @@ -500,15 +489,15 @@ def generator_matrix(self): True """ from functools import reduce + C = self.code() eval_pts = C.evaluation_points() sigma = C.twisting_homomorphism() def create_matrix_elements(A, k, f): - return reduce(lambda L, x: [x] + - [list(map(f, l)) for l in L], [A] * k, []) - return matrix(C.base_field(), C.dimension(), C.length(), - create_matrix_elements(eval_pts, C.dimension(), sigma)) + return reduce(lambda L, x: [x] + [list(map(f, l)) for l in L], [A] * k, []) + + return matrix(C.base_field(), C.dimension(), C.length(), create_matrix_elements(eval_pts, C.dimension(), sigma)) class GabidulinPolynomialEvaluationEncoder(Encoder): @@ -639,8 +628,7 @@ def __eq__(self, other): sage: E3.__eq__(E2) False """ - return isinstance(other, GabidulinPolynomialEvaluationEncoder) \ - and self.code() == other.code() + return isinstance(other, GabidulinPolynomialEvaluationEncoder) and self.code() == other.code() def message_space(self): r""" @@ -864,8 +852,7 @@ def __eq__(self, other) -> bool: sage: D3.__eq__(D2) False """ - return isinstance(other, GabidulinGaoDecoder) \ - and self.code() == other.code() + return isinstance(other, GabidulinGaoDecoder) and self.code() == other.code() def _partial_xgcd(self, a, b, d_stop): """ @@ -960,8 +947,7 @@ def _decode_to_code_and_message(self, r): points = [(eval_pts[i], r[i]) for i in range(len(eval_pts))] # R = S.lagrange_polynomial(eval_pts, list(r)) R = S.lagrange_polynomial(points) - r_out, u_out = self._partial_xgcd(S.minimal_vanishing_polynomial(eval_pts), - R, (C.length() + C.dimension()) // 2) + r_out, u_out = self._partial_xgcd(S.minimal_vanishing_polynomial(eval_pts), R, (C.length() + C.dimension()) // 2) quo, rem = r_out.left_quo_rem(u_out) if not rem.is_zero(): raise DecodingError("Decoding failed because the number of errors exceeded the decoding radius") @@ -1046,6 +1032,7 @@ def decoding_radius(self): """ return (self.code().minimum_distance() - 1) // 2 + # ----------------------------- registration -------------------------------- diff --git a/src/sage/coding/golay_code.py b/src/sage/coding/golay_code.py index 88b80da5d52..64adc11fd06 100644 --- a/src/sage/coding/golay_code.py +++ b/src/sage/coding/golay_code.py @@ -16,7 +16,7 @@ - :wikipedia:`Golay_code` """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2016 Arpit Merchant # 2016 David Lucas # @@ -25,12 +25,11 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.matrix.constructor import matrix from sage.rings.finite_rings.finite_field_constructor import GF -from .linear_code import (AbstractLinearCode, - LinearCodeGeneratorMatrixEncoder) +from .linear_code import AbstractLinearCode, LinearCodeGeneratorMatrixEncoder class GolayCode(AbstractLinearCode): @@ -118,9 +117,7 @@ def __eq__(self, other): sage: C1.__eq__(C2) True """ - return isinstance(other, GolayCode) \ - and self.base_field() == other.base_field() \ - and self.length() == other.length() + return isinstance(other, GolayCode) and self.base_field() == other.base_field() and self.length() == other.length() def _repr_(self): r""" @@ -135,8 +132,7 @@ def _repr_(self): ext = "" if n % 2 == 0: ext = "Extended" - return "[%s, %s, %s] %s Golay code over GF(%s)" % (n, self.dimension(), - self.minimum_distance(), ext, self.base_field().cardinality()) + return "[%s, %s, %s] %s Golay code over GF(%s)" % (n, self.dimension(), self.minimum_distance(), ext, self.base_field().cardinality()) def _latex_(self): r""" @@ -152,9 +148,7 @@ def _latex_(self): ext = "" if n % 2 == 0: ext = "Extended" - return "[%s, %s, %s] \\textnormal{ %s Golay Code over } %s"\ - % (n, self.dimension(), self.minimum_distance(), ext, - self.base_field()._latex_()) + return "[%s, %s, %s] \\textnormal{ %s Golay Code over } %s" % (n, self.dimension(), self.minimum_distance(), ext, self.base_field()._latex_()) def dual_code(self): r""" @@ -256,14 +250,13 @@ def weight_distribution(self): """ n = self.length() if n == 23: - return ([1]+[0]*6+[253]+[506]+[0]*2+[1288]*2+[0]*2+[506] - + [253]+[0]*6+[1]) + return [1] + [0] * 6 + [253] + [506] + [0] * 2 + [1288] * 2 + [0] * 2 + [506] + [253] + [0] * 6 + [1] if n == 24: - return ([1]+[0]*7+[759]+[0]*3+[2576]+[0]*3+[759]+[0]*7+[1]) + return [1] + [0] * 7 + [759] + [0] * 3 + [2576] + [0] * 3 + [759] + [0] * 7 + [1] if n == 11: - return [1]+[0]*4+[132]*2+[0]+[330]+[110]+[0]+[24] + return [1] + [0] * 4 + [132] * 2 + [0] + [330] + [110] + [0] + [24] if n == 12: - return [1]+[0]*5+[264]+[0]*2+[440]+[0]*2+[24] + return [1] + [0] * 5 + [264] + [0] * 2 + [440] + [0] * 2 + [24] def generator_matrix(self): r""" @@ -291,49 +284,13 @@ def generator_matrix(self): """ n = self.length() if n == 23: - G = matrix(GF(2), - [[1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1]]) + G = matrix(GF(2), [[1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1]]) elif n == 24: - G = matrix(GF(2), - [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1], - [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0], - [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1], - [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0], - [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1], - [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1], - [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1], - [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1]]) + G = matrix(GF(2), [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0], [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1]]) elif n == 11: - G = matrix(GF(3), - [[2, 0, 1, 2, 1, 1, 0, 0, 0, 0, 0], - [0, 2, 0, 1, 2, 1, 1, 0, 0, 0, 0], - [0, 0, 2, 0, 1, 2, 1, 1, 0, 0, 0], - [0, 0, 0, 2, 0, 1, 2, 1, 1, 0, 0], - [0, 0, 0, 0, 2, 0, 1, 2, 1, 1, 0], - [0, 0, 0, 0, 0, 2, 0, 1, 2, 1, 1]]) + G = matrix(GF(3), [[2, 0, 1, 2, 1, 1, 0, 0, 0, 0, 0], [0, 2, 0, 1, 2, 1, 1, 0, 0, 0, 0], [0, 0, 2, 0, 1, 2, 1, 1, 0, 0, 0], [0, 0, 0, 2, 0, 1, 2, 1, 1, 0, 0], [0, 0, 0, 0, 2, 0, 1, 2, 1, 1, 0], [0, 0, 0, 0, 0, 2, 0, 1, 2, 1, 1]]) else: - G = matrix(GF(3), - [[1, 0, 0, 0, 0, 0, 2, 0, 1, 2, 1, 2], - [0, 1, 0, 0, 0, 0, 1, 2, 2, 2, 1, 0], - [0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1], - [0, 0, 0, 1, 0, 0, 1, 1, 0, 2, 2, 2], - [0, 0, 0, 0, 1, 0, 2, 1, 2, 2, 0, 1], - [0, 0, 0, 0, 0, 1, 0, 2, 1, 2, 2, 1]]) + G = matrix(GF(3), [[1, 0, 0, 0, 0, 0, 2, 0, 1, 2, 1, 2], [0, 1, 0, 0, 0, 0, 1, 2, 2, 2, 1, 0], [0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1], [0, 0, 0, 1, 0, 0, 1, 1, 0, 2, 2, 2], [0, 0, 0, 0, 1, 0, 2, 1, 2, 2, 0, 1], [0, 0, 0, 0, 0, 1, 0, 2, 1, 2, 2, 1]]) return G def parity_check_matrix(self): @@ -358,25 +315,9 @@ def parity_check_matrix(self): """ n = self.length() if n == 23: - H = matrix(GF(2), - [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0], - [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1], - [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0], - [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1], - [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1], - [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1], - [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1]]) + H = matrix(GF(2), [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1], [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1], [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1]]) elif n == 11: - H = matrix(GF(3), - [[1, 0, 0, 0, 0, 1, 2, 2, 2, 1, 0], - [0, 1, 0, 0, 0, 0, 1, 2, 2, 2, 1], - [0, 0, 1, 0, 0, 2, 1, 2, 0, 1, 2], - [0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1], - [0, 0, 0, 0, 1, 2, 2, 2, 1, 0, 1]]) + H = matrix(GF(3), [[1, 0, 0, 0, 0, 1, 2, 2, 2, 1, 0], [0, 1, 0, 0, 0, 0, 1, 2, 2, 2, 1], [0, 0, 1, 0, 0, 2, 1, 2, 0, 1, 2], [0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1], [0, 0, 0, 0, 1, 2, 2, 2, 1, 0, 1]]) else: H = self.generator_matrix() return H diff --git a/src/sage/coding/goppa_code.py b/src/sage/coding/goppa_code.py index 45c3c87d52c..f213f38ec82 100644 --- a/src/sage/coding/goppa_code.py +++ b/src/sage/coding/goppa_code.py @@ -21,7 +21,7 @@ - Filip Ion, Marketa Slukova (2019-06): initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2019 Filip Ion , # Marketa Slukova # @@ -29,7 +29,7 @@ # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.coding.linear_code import AbstractLinearCode from sage.coding.encoder import Encoder from sage.modules.free_module_element import vector @@ -93,6 +93,7 @@ class GoppaCode(AbstractLinearCode): sage: C [55, 16] Goppa code over GF(2) """ + _registered_encoders = {} _registered_decoders = {} @@ -119,7 +120,7 @@ def __init__(self, generating_pol, defining_set): if not generating_pol.is_monic(): raise ValueError("generating polynomial must be monic") F = self._field - if (not F.is_field() or not F.is_finite()): + if not F.is_field() or not F.is_finite(): raise ValueError("generating polynomial must be defined over a finite field") for a in defining_set: if generating_pol(a) == 0: @@ -139,9 +140,7 @@ def _repr_(self): sage: C [8, 2] Goppa code over GF(2) """ - return "[{}, {}] Goppa code over GF({})".format( - self.length(), self.dimension(), - self.base_field().cardinality()) + return "[{}, {}] Goppa code over GF({})".format(self.length(), self.dimension(), self.base_field().cardinality()) def _latex_(self): r""" @@ -157,8 +156,7 @@ def _latex_(self): sage: latex(C) [8, 2]\text{ Goppa code over }\Bold{F}_{2} """ - return r"[{}, {}]\text{{ Goppa code over }}{}".format(self.length(), self.dimension(), - self.base_field()._latex_()) + return r"[{}, {}]\text{{ Goppa code over }}{}".format(self.length(), self.dimension(), self.base_field()._latex_()) def __eq__(self, other): """ @@ -185,10 +183,7 @@ def __eq__(self, other): sage: C == E False """ - return (isinstance(other, GoppaCode) - and self.length() == other.length() - and self._generating_pol == other._generating_pol - and self._defining_set == other._defining_set) + return isinstance(other, GoppaCode) and self.length() == other.length() and self._generating_pol == other._generating_pol and self._defining_set == other._defining_set def parity_check_matrix(self): r""" @@ -228,7 +223,7 @@ def parity_check_matrix(self): D = self._defining_set h = [(g(D[i]).inverse_of_unit()) for i in range(n)] - #assemble top row + # assemble top row M = _columnize(alpha) for i in range(n): v = _columnize(h[i]) @@ -236,11 +231,11 @@ def parity_check_matrix(self): M = M.delete_columns([0]) old = M - for t in range(1,d): - #assemble row + for t in range(1, d): + # assemble row M = _columnize(alpha) for i in range(n): - v = _columnize(h[i]*(D[i]**t)) + v = _columnize(h[i] * (D[i] ** t)) M = M.augment(v) M = M.delete_columns([0]) new = M @@ -282,7 +277,7 @@ def _parity_check_matrix_vandermonde(self): GLI = [j.inverse_of_unit() for j in GL] D = diagonal_matrix(GLI) VF = matrix([V.row(i) for i in range(t)]) - H = VF*D + H = VF * D matrices = [matrix([vector(i) for i in H.row(j)]) for j in range(t)] matrices = [m.transpose() for m in matrices] @@ -342,6 +337,7 @@ class GoppaCodeEncoder(Encoder): sage: c in C True """ + def __init__(self, code): """ Initialize. @@ -408,8 +404,7 @@ def __eq__(self, other): sage: E1 == E2 True """ - return (isinstance(other, GoppaCodeEncoder) - and self.code() == other.code()) + return isinstance(other, GoppaCodeEncoder) and self.code() == other.code() def generator_matrix(self): r""" diff --git a/src/sage/coding/grs_code.py b/src/sage/coding/grs_code.py index aead68b0bb3..9d84cc34ee4 100644 --- a/src/sage/coding/grs_code.py +++ b/src/sage/coding/grs_code.py @@ -138,6 +138,7 @@ class GeneralizedReedSolomonCode(AbstractLinearCode): sage: D.decode_to_message(y) (3, 0) """ + _registered_encoders = {} _registered_decoders = {} @@ -218,8 +219,8 @@ def __init__(self, evaluation_points, dimension, column_multipliers=None): try: common_points = vector(list(evaluation_points) + list(column_multipliers)) F = common_points.base_ring() - self._evaluation_points = common_points[:len(evaluation_points)] - self._column_multipliers = common_points[len(evaluation_points):] + self._evaluation_points = common_points[: len(evaluation_points)] + self._column_multipliers = common_points[len(evaluation_points) :] except (TypeError, ValueError) as e: raise ValueError("Failed converting all evaluation points and column multipliers to the same field (%s)" % e) else: @@ -232,8 +233,7 @@ def __init__(self, evaluation_points, dimension, column_multipliers=None): if not F.is_finite() or not F.is_field(): raise ValueError("Evaluation points must be in a finite field (and %s is not one)" % F) - super().__init__(F, - len(self._evaluation_points), "EvaluationVector", "Gao") + super().__init__(F, len(self._evaluation_points), "EvaluationVector", "Gao") if dimension not in ZZ or dimension > self._length or dimension < 1: raise ValueError("The dimension must be a positive integer at most the length of the code.") @@ -257,12 +257,7 @@ def __eq__(self, other): sage: C1 == C2 True """ - return isinstance(other, GeneralizedReedSolomonCode) \ - and self.base_field() == other.base_field() \ - and self.length() == other.length() \ - and self.dimension() == other.dimension() \ - and self.evaluation_points() == other.evaluation_points() \ - and self.column_multipliers() == other.column_multipliers() + return isinstance(other, GeneralizedReedSolomonCode) and self.base_field() == other.base_field() and self.length() == other.length() and self.dimension() == other.dimension() and self.evaluation_points() == other.evaluation_points() and self.column_multipliers() == other.column_multipliers() def __hash__(self): """ @@ -277,9 +272,7 @@ def __hash__(self): sage: hash(C1) == hash(C2) True """ - return hash((self.base_field(), self.length(), self.dimension(), - tuple(self.evaluation_points()), - tuple(self.column_multipliers()))) + return hash((self.base_field(), self.length(), self.dimension(), tuple(self.evaluation_points()), tuple(self.column_multipliers()))) def _repr_(self): r""" @@ -297,10 +290,7 @@ def _repr_(self): sage: C2 [40, 12, 29] Generalized Reed-Solomon Code over GF(59) """ - return "[%s, %s, %s] %sReed-Solomon Code over GF(%s)"\ - % (self.length(), self.dimension(), self.minimum_distance(), - "Generalized " if self.is_generalized() else "", - self.base_field().cardinality()) + return "[%s, %s, %s] %sReed-Solomon Code over GF(%s)" % (self.length(), self.dimension(), self.minimum_distance(), "Generalized " if self.is_generalized() else "", self.base_field().cardinality()) def _latex_(self): r""" @@ -318,10 +308,7 @@ def _latex_(self): sage: latex(C2) [40, 12, 29] \textnormal{ Generalized Reed-Solomon Code over } \Bold{F}_{59} """ - return "[%s, %s, %s] \\textnormal{ %sReed-Solomon Code over } %s"\ - % (self.length(), self.dimension(), self.minimum_distance(), - "Generalized " if self.is_generalized() else "", - self.base_field()._latex_()) + return "[%s, %s, %s] \\textnormal{ %sReed-Solomon Code over } %s" % (self.length(), self.dimension(), self.minimum_distance(), "Generalized " if self.is_generalized() else "", self.base_field()._latex_()) def minimum_distance(self): r""" @@ -412,8 +399,7 @@ def multipliers_product(self): """ a = self.evaluation_points() one = self.base_ring().one() - return [one / prod(ai - ah for h, ah in enumerate(a) if h != i) - for i, ai in enumerate(a)] + return [one / prod(ai - ah for h, ah in enumerate(a) if h != i) for i, ai in enumerate(a)] @cached_method def parity_column_multipliers(self): @@ -473,9 +459,7 @@ def dual_code(self): True """ col_mults = self.parity_column_multipliers() - return GeneralizedReedSolomonCode(self.evaluation_points(), - self.length() - self.dimension(), - col_mults) + return GeneralizedReedSolomonCode(self.evaluation_points(), self.length() - self.dimension(), col_mults) def covering_radius(self): r""" @@ -540,7 +524,7 @@ def weight_distribution(self): wd = [1] + [0] * (d - 1) for i in range(d, n + 1): tmp = binomial(n, i) * (q - 1) - wd.append(tmp * symbolic_sum(binomial(i-1, s) * (-1)**s * q**(i - d - s), s, 0, i-d)) + wd.append(tmp * symbolic_sum(binomial(i - 1, s) * (-1) ** s * q ** (i - d - s), s, 0, i - d)) return wd def _punctured_form(self, points): @@ -639,16 +623,17 @@ def ReedSolomonCode(base_field, length, dimension, primitive_root=None): sage: C == D False """ - if not length.divides(base_field.cardinality()-1): + if not length.divides(base_field.cardinality() - 1): raise ValueError("A classical Reed-Solomon code has a length which divides the field cardinality minus 1") if primitive_root is None: g = base_field.multiplicative_generator() - primitive_root = g**((base_field.cardinality()-1)/length) + primitive_root = g ** ((base_field.cardinality() - 1) / length) else: if primitive_root.multiplicative_order() != length: raise ValueError("Supplied primitive_root is not a primitive n'th root of unity") return GeneralizedReedSolomonCode([primitive_root**i for i in range(length)], dimension) + # ###################### encoders ############################### @@ -722,8 +707,7 @@ def __eq__(self, other): sage: D1 is D2 False """ - return isinstance(other, GRSEvaluationVectorEncoder) \ - and self.code() == other.code() + return isinstance(other, GRSEvaluationVectorEncoder) and self.code() == other.code() def _repr_(self): r""" @@ -788,7 +772,7 @@ def generator_matrix(self): C = self.code() alphas = C.evaluation_points() col_mults = C.column_multipliers() - g = matrix(C.base_field(), C.dimension(), C.length(), lambda i, j: col_mults[j] * alphas[j]**i) + g = matrix(C.base_field(), C.dimension(), C.length(), lambda i, j: col_mults[j] * alphas[j] ** i) g.set_immutable() return g @@ -874,6 +858,7 @@ def __init__(self, code, polynomial_ring=None): ValueError: polynomial_ring's base field has to be the same as code's """ from sage.rings.polynomial.polynomial_ring import PolynomialRing_commutative + super().__init__(code) if polynomial_ring is None: self._polynomial_ring = code.base_field()['x'] @@ -906,9 +891,7 @@ def __eq__(self, other): sage: D1.__eq__(D3) False """ - return (isinstance(other, GRSEvaluationPolynomialEncoder) - and self.code() == other.code() - and self.polynomial_ring() == other.polynomial_ring()) + return isinstance(other, GRSEvaluationPolynomialEncoder) and self.code() == other.code() and self.polynomial_ring() == other.polynomial_ring() def _repr_(self): r""" @@ -1010,7 +993,7 @@ def encode(self, p): raise ValueError("The polynomial to encode must have degree at most %s" % (C.dimension() - 1)) alphas = C.evaluation_points() col_mults = C.column_multipliers() - c = vector(C.base_ring(), [col_mults[i]*p(alphas[i]) for i in range(C.length())]) + c = vector(C.base_ring(), [col_mults[i] * p(alphas[i]) for i in range(C.length())]) return c def unencode_nocheck(self, c): @@ -1058,7 +1041,7 @@ def unencode_nocheck(self, c): alphas = C.evaluation_points() col_mults = C.column_multipliers() - c = [c[i]/col_mults[i] for i in range(C.length())] + c = [c[i] / col_mults[i] for i in range(C.length())] points = [(alphas[i], c[i]) for i in range(C.dimension())] Pc = self.polynomial_ring().lagrange_polynomial(points) @@ -1127,8 +1110,7 @@ def __init__(self, code): """ if not isinstance(code, GeneralizedReedSolomonCode): raise ValueError("code has to be a generalized Reed-Solomon code") - super().__init__(code, code.ambient_space(), - "EvaluationPolynomial") + super().__init__(code, code.ambient_space(), "EvaluationPolynomial") def __eq__(self, other): r""" @@ -1146,9 +1128,7 @@ def __eq__(self, other): sage: D1 is D2 False """ - return (isinstance(other, GRSBerlekampWelchDecoder) - and self.code() == other.code() - and self.input_space() == other.input_space()) + return isinstance(other, GRSBerlekampWelchDecoder) and self.code() == other.code() and self.input_space() == other.input_space() def _repr_(self): r""" @@ -1179,8 +1159,7 @@ def _latex_(self): \textnormal{Berlekamp Welch decoder for }[40, 12, 29] \textnormal{ Reed-Solomon Code over } \Bold{F}_{59} """ - return "\\textnormal{Berlekamp Welch decoder for }%s"\ - % self.code()._latex_() + return "\\textnormal{Berlekamp Welch decoder for }%s" % self.code()._latex_() def _decode_to_code_and_message(self, r): r""" @@ -1231,9 +1210,7 @@ def _decode_to_code_and_message(self, r): l0 = n - 1 - t l1 = n - t - k pts = C.evaluation_points() - S = matrix(C.base_field(), n, l0 + l1 + 2, - lambda i, j: (pts[i]**j if j < (l0 + 1) - else r_list[i] * pts[i]**(j - (l0 + 1)))) + S = matrix(C.base_field(), n, l0 + l1 + 2, lambda i, j: (pts[i] ** j if j < (l0 + 1) else r_list[i] * pts[i] ** (j - (l0 + 1)))) S = S.right_kernel() S = S.basis_matrix().row(0) R = C.base_field()['x'] @@ -1386,7 +1363,7 @@ def decoding_radius(self): sage: D.decoding_radius() 14 """ - return (self.code().minimum_distance()-1)//2 + return (self.code().minimum_distance() - 1) // 2 class GRSGaoDecoder(Decoder): @@ -1431,8 +1408,7 @@ def __init__(self, code): """ if not isinstance(code, GeneralizedReedSolomonCode): raise ValueError("code has to be a generalized Reed-Solomon code") - super().__init__(code, code.ambient_space(), - "EvaluationPolynomial") + super().__init__(code, code.ambient_space(), "EvaluationPolynomial") def __eq__(self, other): r""" @@ -1450,9 +1426,7 @@ def __eq__(self, other): sage: D1 is D2 False """ - return (isinstance(other, GRSGaoDecoder) - and self.code() == other.code() - and self.input_space() == other.input_space()) + return isinstance(other, GRSGaoDecoder) and self.code() == other.code() and self.input_space() == other.input_space() def __hash__(self): """ @@ -1526,7 +1500,7 @@ def _polynomial_vanishing_at_alphas(self, PolRing): G = PolRing.one() x = PolRing.gen() for i in range(self.code().length()): - G = G*(x-self.code().evaluation_points()[i]) + G = G * (x - self.code().evaluation_points()[i]) return G def _partial_xgcd(self, a, b, PolRing): @@ -1612,7 +1586,7 @@ def _decode_to_code_and_message(self, r): if n == C.dimension() or r in C: return r, self.connected_encoder().unencode_nocheck(r) - points = [(alphas[i], r[i]/col_mults[i]) for i in range(n)] + points = [(alphas[i], r[i] / col_mults[i]) for i in range(n)] R = PolRing.lagrange_polynomial(points) Q1, Q0 = self._partial_xgcd(G, R, PolRing) @@ -1821,8 +1795,7 @@ def __init__(self, code): """ if not isinstance(code, GeneralizedReedSolomonCode): raise ValueError("code has to be a generalized Reed-Solomon code") - input_space = cartesian_product([code.ambient_space(), - VectorSpace(GF(2), code.ambient_space().dimension())]) + input_space = cartesian_product([code.ambient_space(), VectorSpace(GF(2), code.ambient_space().dimension())]) super().__init__(code, input_space, "EvaluationVector") def __eq__(self, other): @@ -1841,8 +1814,7 @@ def __eq__(self, other): sage: D1 is D2 False """ - return isinstance(other, GRSErrorErasureDecoder) \ - and self.code() == other.code() + return isinstance(other, GRSErrorErasureDecoder) and self.code() == other.code() def _repr_(self) -> str: r""" @@ -1873,8 +1845,7 @@ def _latex_(self): \textnormal{Error-Erasure decoder for }[40, 12, 29] \textnormal{ Reed-Solomon Code over } \Bold{F}_{59} """ - return "\\textnormal{Error-Erasure decoder for }%s"\ - % self.code()._latex_() + return "\\textnormal{Error-Erasure decoder for }%s" % self.code()._latex_() def decode_to_message(self, word_and_erasure_vector): r""" @@ -1959,16 +1930,11 @@ def decode_to_message(self, word_and_erasure_vector): if erasure_vector.hamming_weight() >= self.code().minimum_distance(): raise DecodingError("Too many erasures in the received word") - punctured_word = vector(self.code().base_ring(), - [word[i] for i in range(len(word)) - if not erasure_vector[i]]) + punctured_word = vector(self.code().base_ring(), [word[i] for i in range(len(word)) if not erasure_vector[i]]) C1_length = len(punctured_word) - C1_evaluation_points = [self.code().evaluation_points()[i] for i in - range(n) if erasure_vector[i] != 1] - C1_column_multipliers = [self.code().column_multipliers()[i] for i in - range(n) if erasure_vector[i] != 1] - C1 = GeneralizedReedSolomonCode(C1_evaluation_points, k, - C1_column_multipliers) + C1_evaluation_points = [self.code().evaluation_points()[i] for i in range(n) if erasure_vector[i] != 1] + C1_column_multipliers = [self.code().column_multipliers()[i] for i in range(n) if erasure_vector[i] != 1] + C1 = GeneralizedReedSolomonCode(C1_evaluation_points, k, C1_column_multipliers) if C1_length == k: return C1.unencode(punctured_word, nocheck=True) return C1.decode_to_message(punctured_word) @@ -2061,8 +2027,7 @@ def __init__(self, code): raise ValueError("code has to be a generalized Reed-Solomon code") if code.base_field().zero() in code.evaluation_points(): raise ValueError("Impossible to use this decoder over a GRS code which contains 0 amongst its evaluation points") - super().__init__(code, code.ambient_space(), - "EvaluationVector") + super().__init__(code, code.ambient_space(), "EvaluationVector") def __eq__(self, other): r""" @@ -2080,9 +2045,7 @@ def __eq__(self, other): sage: D1 is D2 False """ - return isinstance(other, GRSKeyEquationSyndromeDecoder) \ - and self.code() == other.code()\ - and self.input_space() == other.input_space() + return isinstance(other, GRSKeyEquationSyndromeDecoder) and self.code() == other.code() and self.input_space() == other.input_space() def _repr_(self): r""" @@ -2221,9 +2184,9 @@ def _forney_formula(self, error_evaluator, error_locator): e = [] for i in range(C.length()): - alpha_inv = one/alphas[i] + alpha_inv = one / alphas[i] if error_locator(alpha_inv) == zero: - e.append(-alphas[i]/col_mults[i] * error_evaluator(alpha_inv)/ELPp(alpha_inv)) + e.append(-alphas[i] / col_mults[i] * error_evaluator(alpha_inv) / ELPp(alpha_inv)) else: e.append(zero) diff --git a/src/sage/coding/guava.py b/src/sage/coding/guava.py index 8a375af4bef..cba028b7a20 100644 --- a/src/sage/coding/guava.py +++ b/src/sage/coding/guava.py @@ -21,7 +21,7 @@ - Dima Pasechnik (2019-11): port to libgap """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2007 David Joyner # 2006 Nick Alexander # 2019 Dima Pasechnik @@ -29,7 +29,7 @@ # Distributed under the terms of the GNU General Public License (GPL) # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.libs.gap.libgap import libgap from sage.misc.randstate import current_randstate @@ -100,7 +100,7 @@ def RandomLinearCodeGuava(n, k, F): GapPackage('guava', spkg='gap_packages').require() libgap.load_package('guava') - C = libgap.RandomLinearCode(n,k,F) + C = libgap.RandomLinearCode(n, k, F) G = C.GeneratorMat() MS = MatrixSpace(F, len(G), len(G[0])) return LinearCode(MS(G)) diff --git a/src/sage/coding/guruswami_sudan/gs_decoder.py b/src/sage/coding/guruswami_sudan/gs_decoder.py index ff76ec2c106..e7cb089ac44 100644 --- a/src/sage/coding/guruswami_sudan/gs_decoder.py +++ b/src/sage/coding/guruswami_sudan/gs_decoder.py @@ -29,9 +29,7 @@ from sage.rings.integer_ring import ZZ from sage.coding.decoder import Decoder from sage.coding.guruswami_sudan.interpolation import gs_interpolation_linalg, gs_interpolation_lee_osullivan -from sage.coding.guruswami_sudan.utils import (johnson_radius, - gilt, - solve_degree2_to_integer_range) +from sage.coding.guruswami_sudan.utils import johnson_radius, gilt, solve_degree2_to_integer_range from sage.functions.other import floor from sage.misc.functional import sqrt @@ -295,22 +293,22 @@ def parameters_given_tau(tau, C=None, n_k=None): ValueError: The decoding radius must be less than the Johnson radius (which is 118.66) """ - n,k = n_k_params(C, n_k) + n, k = n_k_params(C, n_k) johnson = johnson_radius(n, n - k + 1) if tau >= johnson: - raise ValueError("The decoding radius must be less than the Johnson radius (which is %.2f)" - % float(johnson)) + raise ValueError("The decoding radius must be less than the Johnson radius (which is %.2f)" % float(johnson)) # We start with l=1 and check if a satisfiable s can be chosen. We keep # increasing l by 1 until this is the case. The governing equation is # s*(s+1)/2 * n < (l+1)*s*(n-tau) - l*(l+1)/2*(k-1) # See [GS1999]_ def try_l(l): - (mins,maxs) = solve_degree2_to_integer_range(n, n-2*(l+1)*(n-tau), (k-1)*l*(l+1)) + (mins, maxs) = solve_degree2_to_integer_range(n, n - 2 * (l + 1) * (n - tau), (k - 1) * l * (l + 1)) if maxs > 0 and maxs >= mins: return max(1, mins) return None + s, l = None, 0 while s is None: l += 1 @@ -371,18 +369,19 @@ def guruswami_sudan_decoding_radius(C=None, n_k=None, l=None, s=None): sage: GSD.guruswami_sudan_decoding_radius(n_k=(n, k), s=2, l=6) (92, (2, 6)) """ - n,k = n_k_params(C, n_k) + n, k = n_k_params(C, n_k) def get_tau(s, l): "Return the decoding radius given this s and l" if s <= 0 or l <= 0: return -1 - return gilt(n - n/2*(s+1)/(l+1) - (k-1)/2*l/s) + return gilt(n - n / 2 * (s + 1) / (l + 1) - (k - 1) / 2 * l / s) + if l is None and s is None: tau = gilt(johnson_radius(n, n - k + 1)) return (tau, GRSGuruswamiSudanDecoder.parameters_given_tau(tau, n_k=(n, k))) if l is not None and s is not None: - return (get_tau(s,l), (s,l)) + return (get_tau(s, l), (s, l)) # Either s or l is set, but not both. First a shared local function def find_integral_max(real_max, f): @@ -403,17 +402,17 @@ def find_integral_max(real_max, f): # knowing n and s, we can just minimise # ( n*(s+1 choose 2) + (ell+1 choose 2)*(k-1) )/(ell+1) # Differentiating and setting to zero yields ell best choice: - lmax = sqrt(n*s*(s+1.)/(k-1.)) - 1. - #the best integral value will be - (l,tau) = find_integral_max(lmax, lambda l: get_tau(s,l)) - #Note that we have not proven that this ell is minimal in integral - #sense! It just seems that this most often happens - return (tau,(s,l)) + lmax = sqrt(n * s * (s + 1.0) / (k - 1.0)) - 1.0 + # the best integral value will be + (l, tau) = find_integral_max(lmax, lambda l: get_tau(s, l)) + # Note that we have not proven that this ell is minimal in integral + # sense! It just seems that this most often happens + return (tau, (s, l)) if l is not None: # Acquired similarly to when restricting s - smax = sqrt((k-1.)/n*l*(l+1.)) - (s,tau) = find_integral_max(smax, lambda s: get_tau(s,l)) - return (tau, (s,l)) + smax = sqrt((k - 1.0) / n * l * (l + 1.0)) + (s, tau) = find_integral_max(smax, lambda s: get_tau(s, l)) + return (tau, (s, l)) @staticmethod def _suitable_parameters_given_tau(tau, C=None, n_k=None): @@ -480,13 +479,13 @@ def _suitable_parameters_given_tau(tau, C=None, n_k=None): sage: GSD._suitable_parameters_given_tau(118, C=C) (47, 89) """ - n,k = n_k_params(C, n_k) + n, k = n_k_params(C, n_k) w = k - 1 atau = n - tau - smin = tau * w / (atau ** 2 - n * w) + smin = tau * w / (atau**2 - n * w) s = floor(1 + smin) - D = (s - smin) * (atau ** 2 - n * w) * s + (w**2) / 4 - l = floor(atau / w * s + 0.5 - sqrt(D)/w) + D = (s - smin) * (atau**2 - n * w) * s + (w**2) / 4 + l = floor(atau / w * s + 0.5 - sqrt(D) / w) return (s, l) @staticmethod @@ -549,8 +548,8 @@ def gs_satisfactory(tau, s, l, C=None, n_k=None): ... ValueError: Please provide either the code or its length and dimension """ - n,k = n_k_params(C, n_k) - return l > 0 and s > 0 and n * s * (s+1) < (l+1) * (2*s*(n-tau) - (k-1) * l) + n, k = n_k_params(C, n_k) + return l > 0 and s > 0 and n * s * (s + 1) < (l + 1) * (2 * s * (n - tau) - (k - 1) * l) ####################### decoder itself ############################### def __init__(self, code, tau=None, parameters=None, interpolation_alg=None, root_finder=None): @@ -613,7 +612,7 @@ def __init__(self, code, tau=None, parameters=None, interpolation_alg=None, root elif parameters: self._s = parameters[0] self._ell = parameters[1] - (self._tau,_) = GRSGuruswamiSudanDecoder.guruswami_sudan_decoding_radius(C=code, s=self._s, l=self._ell) + (self._tau, _) = GRSGuruswamiSudanDecoder.guruswami_sudan_decoding_radius(C=code, s=self._s, l=self._ell) else: raise ValueError("Specify either tau or parameters") if callable(interpolation_alg): @@ -672,13 +671,7 @@ def __eq__(self, other): sage: D1.__eq__(D2) True """ - return isinstance(other, GRSGuruswamiSudanDecoder)\ - and self.code() == other.code()\ - and self.decoding_radius() == other.decoding_radius()\ - and self.multiplicity() == other.multiplicity()\ - and self.list_size() == other.list_size()\ - and self.interpolation_algorithm() == other.interpolation_algorithm()\ - and self.rootfinding_algorithm() == other.rootfinding_algorithm() + return isinstance(other, GRSGuruswamiSudanDecoder) and self.code() == other.code() and self.decoding_radius() == other.decoding_radius() and self.multiplicity() == other.multiplicity() and self.list_size() == other.list_size() and self.interpolation_algorithm() == other.interpolation_algorithm() and self.rootfinding_algorithm() == other.rootfinding_algorithm() def interpolation_algorithm(self): r""" @@ -847,11 +840,11 @@ def decode_to_code(self, r): l = self.list_size() tau = self.decoding_radius() # SETUP INTERPOLATION PROBLEM - wy = k-1 - points = [(alphas[i], r[i]/colmults[i]) for i in range(len(alphas))] + wy = k - 1 + points = [(alphas[i], r[i] / colmults[i]) for i in range(len(alphas))] # SOLVE INTERPOLATION try: - Q = self.interpolation_algorithm()(points, tau, (s,l), wy) + Q = self.interpolation_algorithm()(points, tau, (s, l), wy) except TypeError: raise ValueError("The provided interpolation algorithm has a wrong signature. See the documentation of `codes.decoders.GRSGuruswamiSudanDecoder.interpolation_algorithm()` for details") # EXAMINE THE FACTORS AND CONVERT TO CODEWORDS @@ -863,9 +856,9 @@ def decode_to_code(self, r): return [] E = self.connected_encoder() - codewords = [ E.encode(f) for f in polynomials] + codewords = [E.encode(f) for f in polynomials] # Root-finding might find spurious roots. Return only the ones which give nearby codewords - return [ c for c in codewords if (r - c).hamming_weight() <= tau ] + return [c for c in codewords if (r - c).hamming_weight() <= tau] def decoding_radius(self): r""" diff --git a/src/sage/coding/guruswami_sudan/interpolation.py b/src/sage/coding/guruswami_sudan/interpolation.py index bfeb0efd2a9..df0f912dc0f 100644 --- a/src/sage/coding/guruswami_sudan/interpolation.py +++ b/src/sage/coding/guruswami_sudan/interpolation.py @@ -50,6 +50,7 @@ def _flatten_once(lstlst): for lst in lstlst: yield from lst + # ************************************************************* # Linear algebraic Interpolation algorithm, helper functions # ************************************************************* @@ -122,6 +123,7 @@ def _interpolation_matrix_given_monomials(points, s, monomials): [ 0 0 1 10] [ 0 1 5 0] """ + def eqs_affine(x0, y0): r""" Make equation for the affine point x0, y0. Return a list of @@ -136,13 +138,12 @@ def eqs_affine(x0, y0): ihat = monomial[0] jhat = monomial[1] if ihat >= i and jhat >= j: - icoeff = binomial(ihat, i) * x0**(ihat-i) \ - if ihat > i else 1 - jcoeff = binomial(jhat, j) * y0**(jhat-j) \ - if jhat > j else 1 + icoeff = binomial(ihat, i) * x0 ** (ihat - i) if ihat > i else 1 + jcoeff = binomial(jhat, j) * y0 ** (jhat - j) if jhat > j else 1 eq[monomial] = jcoeff * icoeff eqs.append([eq.get(monomial, 0) for monomial in monomials]) return eqs + return matrix(list(_flatten_once([eqs_affine(*point) for point in points]))) @@ -157,7 +158,7 @@ def _interpolation_max_weighted_deg(n, tau, s): sage: _interpolation_max_weighted_deg(10, 3, 5) 35 """ - return (n-tau) * s + return (n - tau) * s def _interpolation_matrix_problem(points, tau, parameters, wy): @@ -286,8 +287,8 @@ def gs_interpolation_linalg(points, tau, parameters, wy): # Construct the Q polynomial PF = M.base_ring()['x', 'y'] # make that ring a ring in x, y = PF.gens() - return sum([x**m[0] * y**m[1] * sol[i] - for i, m in enumerate(monomials)]) + return sum([x ** m[0] * y ** m[1] * sol[i] for i, m in enumerate(monomials)]) + # ###################### Lee-O'Sullivan's method ############################### @@ -345,11 +346,10 @@ def lee_osullivan_module(points, parameters, wy): G = prod(x - points[i][0] for i in range(len(points))) PFy = PF['y'] y = PFy.gens()[0] - ybasis = [(y-R)**i * G**(s-i) for i in range(s + 1)] \ - + [y**(i-s) * (y-R)**s for i in range(s + 1, l + 1)] + ybasis = [(y - R) ** i * G ** (s - i) for i in range(s + 1)] + [y ** (i - s) * (y - R) ** s for i in range(s + 1, l + 1)] def pad(lst): - return lst + [0]*(l+1-len(lst)) + return lst + [0] * (l + 1 - len(lst)) modbasis = [pad(yb.coefficients(sparse=False)) for yb in ybasis] return matrix(PF, modbasis) @@ -396,6 +396,7 @@ def gs_interpolation_lee_osullivan(points, tau, parameters, wy): x^3*y + 2*x^3 - x^2*y + 5*x^2 + 5*x*y - 5*x + 2*y - 4 """ from .utils import _degree_of_vector + s, l = parameters[0], parameters[1] F = points[0][0].parent() M = lee_osullivan_module(points, (s, l), wy) diff --git a/src/sage/coding/guruswami_sudan/utils.py b/src/sage/coding/guruswami_sudan/utils.py index dbc40f748b7..891977fe9ec 100644 --- a/src/sage/coding/guruswami_sudan/utils.py +++ b/src/sage/coding/guruswami_sudan/utils.py @@ -44,7 +44,7 @@ def polynomial_to_list(p, len): sage: polynomial_to_list(p, 4) [37, 8, 9, 0] """ - return list(p) + [0]*max(0, len-p.degree()-1) + return list(p) + [0] * max(0, len - p.degree() - 1) def johnson_radius(n, d): @@ -63,7 +63,7 @@ def johnson_radius(n, d): sage: sage.coding.guruswami_sudan.utils.johnson_radius(250, 181) # needs sage.symbolic -5*sqrt(690) + 250 """ - return n - sqrt(n*(n-d)) + return n - sqrt(n * (n - d)) def ligt(x): @@ -129,15 +129,15 @@ def solve_degree2_to_integer_range(a, b, c): sage: solve_degree2_to_integer_range(50, 5, 42) (-2, -1) """ - D = b**2 - 4*a*c + D = b**2 - 4 * a * c if D < 0: - return (-2,-1) + return (-2, -1) sD = float(sqrt(D)) - minx, maxx = (-b-sD)/2.0/a , (-b+sD)/2.0/a + minx, maxx = (-b - sD) / 2.0 / a, (-b + sD) / 2.0 / a mini, maxi = (ligt(minx), gilt(maxx)) if mini > maxi: - return (-2,-1) - return (mini,maxi) + return (-2, -1) + return (mini, maxi) def _degree_of_vector(v, shifts=None): @@ -168,5 +168,4 @@ def _degree_of_vector(v, shifts=None): return max(vi.degree() for vi in v) if v.is_zero(): return -1 - return max(degi + si for (degi, si) in zip([vi.degree() for vi in v ], shifts) - if degi > -1) + return max(degi + si for (degi, si) in zip([vi.degree() for vi in v], shifts) if degi > -1) diff --git a/src/sage/coding/hamming_code.py b/src/sage/coding/hamming_code.py index 431e660fae7..1fac9845656 100644 --- a/src/sage/coding/hamming_code.py +++ b/src/sage/coding/hamming_code.py @@ -43,6 +43,7 @@ class HammingCode(AbstractLinearCode): sage: C [57, 54] Hamming Code over GF(7) """ + _registered_encoders = {} _registered_decoders = {} @@ -70,7 +71,7 @@ def __init__(self, base_field, order): raise ValueError("order has to be a Sage Integer or a Python int") q = base_field.order() - length = Integer((q ** order - 1) / (q - 1)) + length = Integer((q**order - 1) / (q - 1)) super().__init__(base_field, length, "Systematic", "Syndrome") self._dimension = length - order @@ -85,9 +86,7 @@ def __eq__(self, other): sage: C1 == C2 True """ - return isinstance(other, HammingCode)\ - and self.length() == other.length()\ - and self.dimension() == other.dimension() + return isinstance(other, HammingCode) and self.length() == other.length() and self.dimension() == other.dimension() def __hash__(self): """ @@ -112,8 +111,7 @@ def _repr_(self): sage: C [57, 54] Hamming Code over GF(7) """ - return "[%s, %s] Hamming Code over GF(%s)"\ - % (self.length(), self.dimension(), self.base_field().cardinality()) + return "[%s, %s] Hamming Code over GF(%s)" % (self.length(), self.dimension(), self.base_field().cardinality()) def _latex_(self): r""" @@ -125,8 +123,7 @@ def _latex_(self): sage: latex(C) [57, 54] \textnormal{ Hamming Code over }\Bold{F}_{7} """ - return "[%s, %s] \\textnormal{ Hamming Code over }%s"\ - % (self.length(), self.dimension(), self.base_field()._latex_()) + return "[%s, %s] \\textnormal{ Hamming Code over }%s" % (self.length(), self.dimension(), self.base_field()._latex_()) @cached_method def parity_check_matrix(self): diff --git a/src/sage/coding/information_set_decoder.py b/src/sage/coding/information_set_decoder.py index 5a147d077bd..9e00141c1c6 100644 --- a/src/sage/coding/information_set_decoder.py +++ b/src/sage/coding/information_set_decoder.py @@ -26,7 +26,7 @@ version """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2017 David Lucas # Johan Rosenkilde # Yann Laigle-Chapuy @@ -37,7 +37,7 @@ # (at your option) any later version. # # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.arith.misc import binomial from sage.rings.integer_ring import ZZ @@ -294,11 +294,7 @@ def __eq__(self, other): sage: A2 == LeeBrickellISDAlgorithm(C, (0,4), search_size=A.parameters()['search_size']) True """ - return isinstance(other, self.__class__)\ - and self.code() == other.code()\ - and self.decoding_interval() == other.decoding_interval()\ - and self._parameters_specified == other._parameters_specified\ - and (not self._parameters_specified or self.parameters() == other.parameters()) + return isinstance(other, self.__class__) and self.code() == other.code() and self.decoding_interval() == other.decoding_interval() and self._parameters_specified == other._parameters_specified and (not self._parameters_specified or self.parameters() == other.parameters()) def __hash__(self): r""" @@ -398,6 +394,7 @@ class LeeBrickellISDAlgorithm(InformationSetAlgorithm): ISD Algorithm (Lee-Brickell) for [24, 12, 8] Extended Golay code over GF(2) decoding between 2 and 3 errors """ + def __init__(self, code, decoding_interval, search_size=None): r""" TESTS: @@ -421,10 +418,8 @@ def __init__(self, code, decoding_interval, search_size=None): if not isinstance(search_size, (Integer, int)) or search_size < 0: raise ValueError("The search size parameter has to be a positive integer") if search_size > decoding_interval[1]: - raise ValueError("The search size parameter has to be at most" - " the maximal number of allowed errors") - super().__init__(code, decoding_interval, "Lee-Brickell", - parameters={'search_size': search_size}) + raise ValueError("The search size parameter has to be at most" " the maximal number of allowed errors") + super().__init__(code, decoding_interval, "Lee-Brickell", parameters={'search_size': search_size}) self._parameters_specified = True else: self._parameters_specified = False @@ -464,6 +459,7 @@ def decode(self, r): """ import itertools from sage.misc.prandom import sample + C = self.code() n, k = C.length(), C.dimension() tau = self.decoding_interval() @@ -577,26 +573,24 @@ def time_information_set_steps(): def time_search_loop(p): y = random_vector(F, n) g = random_matrix(F, p, n).rows() - scalars = [ [ Fstar[randint(0,q-2)] for i in range(p) ] - for s in range(100) ] + scalars = [[Fstar[randint(0, q - 2)] for i in range(p)] for s in range(100)] before = process_time() for m in scalars: - e = y - sum(m[i]*g[i] for i in range(p)) - return (process_time() - before) / 100. - T = sum([ time_information_set_steps() for s in range(5) ]) / 5. - P = [ time_search_loop(p) for p in range(tau+1) ] + e = y - sum(m[i] * g[i] for i in range(p)) + return (process_time() - before) / 100.0 + + T = sum([time_information_set_steps() for s in range(5)]) / 5.0 + P = [time_search_loop(p) for p in range(tau + 1)] def compute_estimate(p): - iters = 1. * binomial(n, k) / \ - sum( binomial(n-tau, k-i)*binomial(tau,i) for i in range(p+1) ) - estimate = iters*(T + - sum(P[pi] * (q-1)**pi * binomial(k, pi) for pi in range(p+1) )) + iters = 1.0 * binomial(n, k) / sum(binomial(n - tau, k - i) * binomial(tau, i) for i in range(p + 1)) + estimate = iters * (T + sum(P[pi] * (q - 1) ** pi * binomial(k, pi) for pi in range(p + 1))) return estimate if self._parameters_specified: self._time_estimate = compute_estimate(self._parameters['search_size']) else: - self._calibrate_select([ compute_estimate(p) for p in range(tau+1) ]) + self._calibrate_select([compute_estimate(p) for p in range(tau + 1)]) def _calibrate_select(self, estimates): r""" @@ -629,7 +623,7 @@ def _calibrate_select(self, estimates): for p in range(1, len(estimates)): if estimates[p] < estimates[search_size]: search_size = p - self._parameters = { 'search_size': search_size } + self._parameters = {'search_size': search_size} self._time_estimate = estimates[search_size] @@ -759,6 +753,7 @@ class LinearCodeInformationSetDecoder(Decoder): Information-set decoder (Lee-Brickell) for [12, 6, 6] Extended Golay code over GF(3) decoding up to 2 errors """ + def __init__(self, code, number_errors, algorithm=None, **kwargs): r""" TESTS: @@ -824,15 +819,11 @@ def __init__(self, code, number_errors, algorithm=None, **kwargs): """ if isinstance(number_errors, (Integer, int)): number_errors = (0, number_errors) - if isinstance(number_errors, (tuple, list)) and len(number_errors) == 2 \ - and number_errors[0] in ZZ and number_errors[1] in ZZ: + if isinstance(number_errors, (tuple, list)) and len(number_errors) == 2 and number_errors[0] in ZZ and number_errors[1] in ZZ: if 0 > number_errors[0] or number_errors[0] > number_errors[1]: - raise ValueError( - "number_errors should be a positive integer or" - " a valid interval within the positive integers") + raise ValueError("number_errors should be a positive integer or" " a valid interval within the positive integers") if number_errors[1] > code.length(): - raise ValueError("The provided number of errors should be at" - " most the code's length") + raise ValueError("The provided number of errors should be at" " most the code's length") else: raise ValueError("number_errors should be an integer or a pair of integers") @@ -842,31 +833,22 @@ def __init__(self, code, number_errors, algorithm=None, **kwargs): if algorithm is None: if kwargs: - raise ValueError("Additional arguments to an information-set decoder" - " algorithm are only allowed if a specific" - " algorithm is selected by setting the algorithm" - " keyword") + raise ValueError("Additional arguments to an information-set decoder" " algorithm are only allowed if a specific" " algorithm is selected by setting the algorithm" " keyword") algorithm = "Lee-Brickell" algorithm_names = LinearCodeInformationSetDecoder.known_algorithms(dictionary=True) if isinstance(algorithm, InformationSetAlgorithm): if kwargs: - raise ValueError("ISD algorithm arguments are not allowed when" - " supplying a constructed ISD algorithm") + raise ValueError("ISD algorithm arguments are not allowed when" " supplying a constructed ISD algorithm") if number_errors != algorithm.decoding_interval(): - raise ValueError("number_errors must match that of the passed" - " ISD algorithm") + raise ValueError("number_errors must match that of the passed" " ISD algorithm") self._algorithm = algorithm elif algorithm in algorithm_names: self._algorithm = algorithm_names[algorithm](code, number_errors, **kwargs) else: - raise ValueError("Unknown ISD algorithm '{}'." - " The known algorithms are {}." - .format(algorithm, sorted(algorithm_names))) + raise ValueError("Unknown ISD algorithm '{}'." " The known algorithms are {}.".format(algorithm, sorted(algorithm_names))) - _known_algorithms = { - "Lee-Brickell": LeeBrickellISDAlgorithm - } + _known_algorithms = {"Lee-Brickell": LeeBrickellISDAlgorithm} @staticmethod def known_algorithms(dictionary=False): @@ -1026,5 +1008,4 @@ def _latex_(self): return "\\textnormal{{Information-set decoder ({}) for }}{} \\textnormal{{decoding {} errors}}".format(self.algorithm().name(), self.code()._latex_(), _format_decoding_interval(self.decoding_interval())) -LinearCodeInformationSetDecoder._decoder_type = {"hard-decision", - "probabilistic", "not-always-closest", "bounded-distance", "might-fail"} +LinearCodeInformationSetDecoder._decoder_type = {"hard-decision", "probabilistic", "not-always-closest", "bounded-distance", "might-fail"} diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 656a59b9838..098e61d6f4f 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -269,6 +269,7 @@ def _dump_code_in_leon_format(C): sage: f.close() """ from sage.misc.temporary_file import tmp_filename + F = C.base_ring() p = F.order() # must be prime and <11 s = "LIBRARY code;\n" + "code=seq(%s,%s,%s,seq(\n" % (p, C.dimension(), C.length()) @@ -339,11 +340,11 @@ class AbstractLinearCode(AbstractLinearCodeNoMetric): It is thus strongly recommended to set an encoder with a generator matrix implemented as a default encoder. """ + _registered_encoders = {} _registered_decoders = {} - def __init__(self, base_field, length, - default_encoder_name, default_decoder_name) -> None: + def __init__(self, base_field, length, default_encoder_name, default_decoder_name) -> None: """ Initialize mandatory parameters that any linear code shares. @@ -414,8 +415,7 @@ def __init__(self, base_field, length, self._registered_decoders['InformationSet'] = LinearCodeInformationSetDecoder self._generic_constructor = LinearCode - super().__init__(base_field, length, default_encoder_name, - default_decoder_name) + super().__init__(base_field, length, default_encoder_name, default_decoder_name) def _an_element_(self): r""" @@ -515,8 +515,7 @@ def automorphism_group_gens(self, equivalence='semilinear') -> tuple: 64) """ aut_group_can_label = self._canonize(equivalence) - return aut_group_can_label.get_autom_gens(), \ - aut_group_can_label.get_autom_order() + return aut_group_can_label.get_autom_gens(), aut_group_can_label.get_autom_order() def assmus_mattson_designs(self, t, mode=None): r""" @@ -605,20 +604,25 @@ def assmus_mattson_designs(self, t, mode=None): nonzerowts = [i for i in range(len(wts)) if wts[i] != 0 and d <= i <= n] if mode == "verbose": for w in nonzerowts: - print("The weight w={} codewords of C* form a t-(v,k,lambda) design, where\n \ + print( + "The weight w={} codewords of C* form a t-(v,k,lambda) design, where\n \ t={}, v={}, k={}, lambda={}. \nThere are {} block of this design.".format( - w, t, n, w, wts[w] * binomial(w, t) // binomial(n, t), wts[w])) + w, t, n, w, wts[w] * binomial(w, t) // binomial(n, t), wts[w] + ) + ) wtsp = Cp.weight_distribution() dp = next(i for i in range(1, len(wtsp)) if wtsp[i] != 0) - nonzerowtsp = [i for i in range(len(wtsp)) - if wtsp[i] != 0 and i <= n-t and i >= dp] - s = len([i for i in range(1, n) if wtsp[i] != 0 and 0 < i <= n-t]) + nonzerowtsp = [i for i in range(len(wtsp)) if wtsp[i] != 0 and i <= n - t and i >= dp] + s = len([i for i in range(1, n) if wtsp[i] != 0 and 0 < i <= n - t]) if mode == "verbose": for w in nonzerowtsp: - print("The weight w={} codewords of C* form a t-(v,k,lambda) design, where\n \ + print( + "The weight w={} codewords of C* form a t-(v,k,lambda) design, where\n \ t={}, v={}, k={}, lambda={}. \nThere are {} block of this design.".format( - w, t, n, w, wts[w] * binomial(w, t) // binomial(n, t), wts[w])) - if s <= d-t: + w, t, n, w, wts[w] * binomial(w, t) // binomial(n, t), wts[w] + ) + ) + if s <= d - t: des = [[t, (n, w, wts[w] * binomial(w, t) // binomial(n, t))] for w in nonzerowts] ans = ans + ["weights from C: ", nonzerowts, "designs from C: ", des] desp = [[t, (n, w, wtsp[w] * binomial(w, t) // binomial(n, t))] for w in nonzerowtsp] @@ -664,23 +668,24 @@ def binomial_moment(self, i): d = self.minimum_distance() F = self.base_ring() q = F.order() - J = range(1, n+1) + J = range(1, n + 1) Cp = self.dual_code() dp = Cp.minimum_distance() if i < d: return 0 if n - dp < i <= n: - return binomial(n, i)*(q**(i+k-n) - 1)//(q-1) + return binomial(n, i) * (q ** (i + k - n) - 1) // (q - 1) from sage.combinat.set_partition import SetPartitions + P = SetPartitions(J, 2).list() b = QQ(0) for p in P: p = list(p) S = p[0] - if len(S) == n-i: + if len(S) == n - i: C_S = self.shortened(S) k_S = C_S.dimension() - b = b + (q**(k_S) - 1)//(q-1) + b = b + (q ** (k_S) - 1) // (q - 1) return b @cached_method @@ -725,6 +730,7 @@ def _canonize(self, equivalence): Defn: z |--> z)] """ from sage.coding.codecan.autgroup_can_label import LinearCodeAutGroupCanLabel + return LinearCodeAutGroupCanLabel(self, algorithm_type=equivalence) def canonical_representative(self, equivalence='semilinear'): @@ -790,8 +796,7 @@ def canonical_representative(self, equivalence='semilinear'): sage: with ensure_interruptible_after(0.5): C.canonical_representative() # needs sage.libs.gap """ aut_group_can_label = self._canonize(equivalence) - return aut_group_can_label.get_canonical_form(), \ - aut_group_can_label.get_transporter() + return aut_group_can_label.get_canonical_form(), aut_group_can_label.get_transporter() def characteristic(self): r""" @@ -824,7 +829,7 @@ def characteristic_polynomial(self): k = C.dimension() n = C.length() q = (C.base_ring()).order() - return q**(n-k)*prod([1-x/j for j in Sd if j > 0]) + return q ** (n - k) * prod([1 - x / j for j in Sd if j > 0]) def chinen_polynomial(self): """ @@ -848,6 +853,7 @@ def chinen_polynomial(self): Riemann hypothesis", April 2007 preprint. """ from sage.misc.functional import sqrt + C = self n = C.length() RT = PolynomialRing(QQ, 2, "Ts") @@ -864,29 +870,29 @@ def chinen_polynomial(self): # an easy thing to do. Some tricky gymnastics are used to # make Sage deal with objects over QQ(sqrt(q)) nicely. if is_even(n): - Pd = q**(k-n//2) * RT(Cd.zeta_polynomial()) * T**(dperp - d) + Pd = q ** (k - n // 2) * RT(Cd.zeta_polynomial()) * T ** (dperp - d) else: - Pd = s * q**(k-(n+1)//2) * RT(Cd.zeta_polynomial()) * T**(dperp - d) - CP = P+Pd - f = CP/CP(1, s) + Pd = s * q ** (k - (n + 1) // 2) * RT(Cd.zeta_polynomial()) * T ** (dperp - d) + CP = P + Pd + f = CP / CP(1, s) return f(t, sqrt(q)) if dperp < d: - P = RT(C.zeta_polynomial())*T**(d - dperp) + P = RT(C.zeta_polynomial()) * T ** (d - dperp) if is_even(n): - Pd = q**(k-n/2)*RT(Cd.zeta_polynomial()) + Pd = q ** (k - n / 2) * RT(Cd.zeta_polynomial()) if not is_even(n): - Pd = s*q**(k-(n+1)/2)*RT(Cd.zeta_polynomial()) - CP = P+Pd - f = CP/CP(1, s) + Pd = s * q ** (k - (n + 1) / 2) * RT(Cd.zeta_polynomial()) + CP = P + Pd + f = CP / CP(1, s) return f(t, sqrt(q)) if dperp == d: P = RT(C.zeta_polynomial()) if is_even(n): - Pd = q**(k-n/2)*RT(Cd.zeta_polynomial()) + Pd = q ** (k - n / 2) * RT(Cd.zeta_polynomial()) if not is_even(n): - Pd = s*q**(k-(n+1)/2)*RT(Cd.zeta_polynomial()) - CP = P+Pd - f = CP/CP(1, s) + Pd = s * q ** (k - (n + 1) / 2) * RT(Cd.zeta_polynomial()) + CP = P + Pd + f = CP / CP(1, s) return f(t, sqrt(q)) @cached_method @@ -918,13 +924,12 @@ def covering_radius(self): is limited to computing with fields of size at most 256 """ from sage.libs.gap.libgap import libgap + GapPackage('guava', spkg='gap_packages').require() libgap.LoadPackage('guava') F = self.base_ring() if F.cardinality() > 256: - raise NotImplementedError("the GAP algorithm that Sage is using " - "is limited to computing with fields " - "of size at most 256") + raise NotImplementedError("the GAP algorithm that Sage is using " "is limited to computing with fields " "of size at most 256") gapG = libgap(self.generator_matrix()) C = gapG.GeneratorMatCode(libgap(F)) r = C.CoveringRadius() @@ -949,7 +954,7 @@ def divisor(self): C = self A = C.weight_distribution() n = C.length() - V = VectorSpace(QQ, n+1) + V = VectorSpace(QQ, n + 1) S = V(A).nonzero_positions() S0 = [S[i] for i in range(1, len(S))] if len(S) > 1: @@ -1166,7 +1171,7 @@ def construction_x(self, other, aux): ka = aux.dimension() F = self.base_field() - MS = MatrixSpace(F, k-ka, na) + MS = MatrixSpace(F, k - ka, na) Z = MS(0) right = Z.stack(Ga) G = left.augment(right) @@ -1189,6 +1194,7 @@ def extended_code(self): Extension of [21, 18] Hamming Code over GF(4) """ from .extended_code import ExtendedCode + return ExtendedCode(self) def galois_closure(self, F0): @@ -1223,8 +1229,8 @@ def galois_closure(self, F0): k = len(G.rows()) G0 = [[x**q0 for x in g.list()] for g in G.rows()] G1 = [list(g.list()) for g in G.rows()] - G2 = G0+G1 - MS = MatrixSpace(F, 2*k, n) + G2 = G0 + G1 + MS = MatrixSpace(F, 2 * k, n) G3 = MS(G2) r = G3.rank() MS = MatrixSpace(F, r, n) @@ -1283,6 +1289,7 @@ def is_permutation_equivalent(self, other, algorithm=None): False """ from sage.groups.perm_gps.partn_ref.refinement_binary import NonlinearBinaryCodeStruct + F = self.base_ring() F_o = other.base_ring() q = F.order() @@ -1301,7 +1308,7 @@ def is_permutation_equivalent(self, other, algorithm=None): if ans is not False: if algorithm == "verbose": Sn = SymmetricGroup(n) - return True, Sn([i+1 for i in ans])**(-1) + return True, Sn([i + 1 for i in ans]) ** (-1) return True return False @@ -1395,19 +1402,17 @@ def minimum_distance(self, algorithm=None): # the user then simply return the stored value. # This is done only if algorithm is None. if algorithm not in (None, 'gap', 'guava'): - raise ValueError("The algorithm argument must be one of None, " - "'gap' or 'guava'; got '{0}'".format(algorithm)) + raise ValueError("The algorithm argument must be one of None, " "'gap' or 'guava'; got '{0}'".format(algorithm)) F = self.base_ring() q = F.order() if q > 256: - raise NotImplementedError("the GAP algorithm that Sage is using " - "is limited to computing with fields " - "of size at most 256") + raise NotImplementedError("the GAP algorithm that Sage is using " "is limited to computing with fields " "of size at most 256") G = self.generator_matrix() if (q == 2 or q == 3) and algorithm == 'guava': from sage.libs.gap.libgap import libgap + libgap.LoadPackage('guava') C = libgap(G).GeneratorMatCode(libgap(F)) d = C.MinimumWeight() @@ -1453,6 +1458,7 @@ def _minimum_weight_codeword(self, algorithm=None): - David Joyner (11-2005) """ from sage.libs.gap.libgap import libgap + n, k = self.length(), self.dimension() F = self.base_field() Gmat = libgap(self.generator_matrix()) @@ -1472,8 +1478,8 @@ def _minimum_weight_codeword(self, algorithm=None): dist_min = libgap(n + 1) K = libgap.GF(q) v0 = (K**n).Zero() - for i in range(1, k+1): - v = Gmat.AClosestVectorCombinationsMatFFEVecFFECoords(K,v0,i,1)[0] + for i in range(1, k + 1): + v = Gmat.AClosestVectorCombinationsMatFFEVecFFECoords(K, v0, i, 1)[0] dist = v.WeightVecFFE() if dist and dist < dist_min: dist_min = dist @@ -1507,6 +1513,7 @@ def module_composition_factors(self, gp): ...) ] """ from sage.libs.gap.libgap import libgap + F = self.base_ring() gens = gp.gens() G = self.generator_matrix() @@ -1523,7 +1530,7 @@ def module_composition_factors(self, gp): M_gap = mats_gap.GModuleByMats(F) # our parser does not grok "foo.MTX.Bar" yet;so we cannot do # M_gap.MTX.CompositionFactors() yet - return libgap.eval('MTX.CompositionFactors('+str(M_gap)+')') + return libgap.eval('MTX.CompositionFactors(' + str(M_gap) + ')') def permutation_automorphism_group(self, algorithm='partition'): r""" @@ -1629,22 +1636,23 @@ def permutation_automorphism_group(self, algorithm='partition'): """ F = self.base_ring() q = F.order() - G = self.generator_matrix() if 2*self.dimension() <= self.length() else self.dual_code().generator_matrix() + G = self.generator_matrix() if 2 * self.dimension() <= self.length() else self.dual_code().generator_matrix() n = len(G.columns()) if "gap" in algorithm: from sage.libs.gap.libgap import libgap + GapPackage('guava', spkg='gap_packages').require() libgap.LoadPackage('guava') - wts = self.weight_distribution() # bottleneck 1 + wts = self.weight_distribution() # bottleneck 1 nonzerowts = [i for i in range(len(wts)) if wts[i] != 0] Sn = libgap.SymmetricGroup(n) Sn_sage = SymmetricGroup(n) - Gp = Sn # initializing G in gap + Gp = Sn # initializing G in gap C = libgap(G).GeneratorMatCode(libgap.GF(q)) eltsC = C.Elements() if algorithm == "gap+verbose": print("\n Minimum distance: %s \n Weight distribution: \n %s" % (nonzerowts[1], wts)) - stop = 0 # only stop if all gens are autos + stop = 0 # only stop if all gens are autos for i in range(1, len(nonzerowts)): if stop == 1: break @@ -1652,16 +1660,16 @@ def permutation_automorphism_group(self, algorithm='partition'): if algorithm == "gap+verbose": size = Gp.Size() print("\n Using the %s codewords of weight %s \n Supergroup size: \n %s\n " % (wts[wt], wt, size)) - Cwt = filter(lambda c: c.WeightCodeword() == wt, eltsC) # bottleneck 2 (repeated - matCwt = [c.VectorCodeword() for c in Cwt] # for each i until stop = 1) + Cwt = filter(lambda c: c.WeightCodeword() == wt, eltsC) # bottleneck 2 (repeated + matCwt = [c.VectorCodeword() for c in Cwt] # for each i until stop = 1) if len(matCwt) > 0: A = libgap(matCwt).MatrixAutomorphisms() Gp = A.Intersection2(Gp) # bottleneck 3 if Gp.Size() == 1: return PermutationGroup([()]) gens = Gp.GeneratorsOfGroup() - stop = 1 # get ready to stop - for x in gens: # if one of these gens is not an auto then don't stop + stop = 1 # get ready to stop + for x in gens: # if one of these gens is not an auto then don't stop if not self.is_permutation_automorphism(Sn_sage(x)): stop = 0 break @@ -1670,13 +1678,15 @@ def permutation_automorphism_group(self, algorithm='partition'): if algorithm == "partition": if q == 2: from sage.groups.perm_gps.partn_ref.refinement_binary import LinearBinaryCodeStruct + B = LinearBinaryCodeStruct(G) autgp = B.automorphism_group() - L = [[j+1 for j in gen] for gen in autgp[0]] + L = [[j + 1 for j in gen] for gen in autgp[0]] AutGp = PermutationGroup(L) else: from sage.groups.perm_gps.partn_ref.refinement_matrices import MatrixStruct from sage.matrix.constructor import matrix + weights = {} for c in self: wt = c.hamming_weight() @@ -1689,7 +1699,7 @@ def permutation_automorphism_group(self, algorithm='partition'): for wt, words in weights.items(): M = MatrixStruct(matrix(words)) autgp = M.automorphism_group() - L = [[j+1 for j in gen] for gen in autgp[0]] + L = [[j + 1 for j in gen] for gen in autgp[0]] G = PermutationGroup(L) AutGps.append(G) if len(AutGps) > 0: @@ -1721,6 +1731,7 @@ def punctured(self, L): Puncturing of [7, 4] Hamming Code over GF(2) on position(s) [1, 2] """ from .punctured_code import PuncturedCode + return PuncturedCode(self, set(L)) def _punctured_form(self, points): @@ -1854,13 +1865,15 @@ def weight_distribution(self, algorithm=None): n = self.length() if algorithm == "gap": from sage.libs.gap.libgap import libgap + Gmat = self.generator_matrix() q = self.base_ring().order() - z = 0*libgap.Z(q)*([0]*self.length()) # GAP zero vector + z = 0 * libgap.Z(q) * ([0] * self.length()) # GAP zero vector w = libgap(Gmat).DistancesDistributionMatFFEVecFFE(libgap.GF(q), z) return w.sage() if algorithm == "binary": from sage.coding.binary_code import weight_dist + return weight_dist(self.generator_matrix()) if algorithm == "leon": if F.order() not in [2, 3, 5, 7]: @@ -1868,6 +1881,7 @@ def weight_distribution(self, algorithm=None): # The GAP command DirectoriesPackageLibrary tells the location of the latest # version of the Guava libraries, so gives us the location of the Guava binaries too. from sage.libs.gap.libgap import libgap + guava_bin_dir = libgap.DirectoriesPackagePrograms('guava')[0].Filename("").sage() input = _dump_code_in_leon_format(self) + "::code" lines = subprocess.check_output([os.path.join(guava_bin_dir, 'wtdist'), input]) @@ -1902,7 +1916,7 @@ def support(self): """ n = self.length() F = self.base_ring() - V = VectorSpace(F, n+1) + V = VectorSpace(F, n + 1) return V(self.weight_distribution()).support() def weight_enumerator(self, names=None, bivariate=True): @@ -1953,10 +1967,10 @@ def weight_enumerator(self, names=None, bivariate=True): if bivariate: R = PolynomialRing(ZZ, 2, names) x, y = R.gens() - return sum(spec[i]*x**i*y**(n-i) for i in range(n+1)) + return sum(spec[i] * x**i * y ** (n - i) for i in range(n + 1)) R = PolynomialRing(ZZ, names) - x, = R.gens() - return sum(spec[i]*x**i for i in range(n+1)) + (x,) = R.gens() + return sum(spec[i] * x**i for i in range(n + 1)) def zeta_polynomial(self, name='T'): r""" @@ -2011,20 +2025,20 @@ def zeta_polynomial(self, name='T'): we = self.weight_enumerator() A = R(we) # B = A(x+y,y,T)-(x+y)**n - B = A(x, x+y, T)-(x+y)**n + B = A(x, x + y, T) - (x + y) ** n Bs = B.coefficients() Bs.reverse() - b = [Bs[i]/binomial(n, i+d) for i in range(len(Bs))] - r = n-d-dperp+2 + b = [Bs[i] / binomial(n, i + d) for i in range(len(Bs))] + r = n - d - dperp + 2 P_coeffs = [] for i in range(len(b)): if i == 0: P_coeffs.append(b[0]) if i == 1: - P_coeffs.append(b[1] - (q+1)*b[0]) + P_coeffs.append(b[1] - (q + 1) * b[0]) if i > 1: - P_coeffs.append(b[i] - (q+1)*b[i-1] + q*b[i-2]) - P = sum([P_coeffs[i]*T**i for i in range(r+1)]) + P_coeffs.append(b[i] - (q + 1) * b[i - 1] + q * b[i - 2]) + P = sum([P_coeffs[i] * T**i for i in range(r + 1)]) return RT(P) / RT(P)(1) def zeta_function(self, name='T'): @@ -2049,7 +2063,7 @@ def zeta_function(self, name='T'): q = self.base_ring().characteristic() RT = PolynomialRing(QQ, name) T = RT.gen() - return P/((1-T)*(1-q*T)) + return P / ((1 - T) * (1 - q * T)) def cosetGraph(self, immutable=False): r""" @@ -2108,16 +2122,16 @@ def cosetGraph(self, immutable=False): F = self.base_field() def e(i): - v = [0]*self.length() - v[i-1] = 1 + v = [0] * self.length() + v[i - 1] = 1 return vector(F, v, immutable=True) # Handle special cases if len(self.basis()) == self.length(): - return Graph(1, name=f"coset graph of {self.__repr__()}", - immutable=immutable) + return Graph(1, name=f"coset graph of {self.__repr__()}", immutable=immutable) if len(self.basis()) == 0: from sage.graphs.generators.families import HammingGraph + return HammingGraph(self.length(), F.order(), immutable=immutable) # we need to find a basis for the complement @@ -2158,7 +2172,7 @@ def e(i): v.set_immutable() Pei.append(v) - lPei = [l*u for l in F for u in Pei if not l.is_zero()] + lPei = [l * u for l in F for u in Pei if not l.is_zero()] def edges(): for v in vertices: @@ -2168,13 +2182,12 @@ def edges(): w.set_immutable() yield (v, w) - return Graph(edges(), format="list_of_edges", - name=f"coset graph of {self.__repr__()}", - immutable=immutable) + return Graph(edges(), format="list_of_edges", name=f"coset graph of {self.__repr__()}", immutable=immutable) # ########################### linear codes python class ######################## + class LinearCode(AbstractLinearCode): r""" Linear codes over a finite field or finite ring, represented using a @@ -2258,6 +2271,7 @@ class LinearCode(AbstractLinearCode): - David Joyner (11-2005) - Charles Prior (03-2016): :issue:`20198`, LinearCode from a code """ + def __init__(self, generator, d=None) -> None: r""" See the docstring for :meth:`LinearCode`. @@ -2354,8 +2368,7 @@ def __init__(self, generator, d=None) -> None: G_echelon = G.echelon_form() generator_matrix = G_echelon.matrix_from_rows([i for i, r in enumerate(G_echelon) if not r.is_zero()]) - super().__init__(base_ring, generator_matrix.ncols(), - "GeneratorMatrix", "Syndrome") + super().__init__(base_ring, generator_matrix.ncols(), "GeneratorMatrix", "Syndrome") self._generator_matrix = generator_matrix self._dimension = self._generator_matrix.rank() self._minimum_distance = d @@ -2394,8 +2407,7 @@ def _latex_(self) -> str: sage: latex(C) [7, 4]\textnormal{ Linear code over }\Bold{F}_{2} """ - return "[%s, %s]\\textnormal{ Linear code over }%s"\ - % (self.length(), self.dimension(), self.base_ring()._latex_()) + return "[%s, %s]\\textnormal{ Linear code over }%s" % (self.length(), self.dimension(), self.base_ring()._latex_()) def intersection(self, other): """ @@ -2481,6 +2493,7 @@ def generator_matrix(self, encoder_name=None, **kwargs): # ###################### encoders ############################### + class LinearCodeGeneratorMatrixEncoder(Encoder): r""" Encoder based on generator_matrix for Linear codes. @@ -2517,8 +2530,7 @@ def __eq__(self, other) -> bool: sage: E1 == E2 True """ - return isinstance(other, LinearCodeGeneratorMatrixEncoder)\ - and self.code() == other.code() + return isinstance(other, LinearCodeGeneratorMatrixEncoder) and self.code() == other.code() def _repr_(self) -> str: r""" @@ -2572,6 +2584,7 @@ def generator_matrix(self): # ###################### decoders ############################### + class LinearCodeSyndromeDecoder(Decoder): r""" Construct a decoder for Linear Codes based on syndrome lookup table. @@ -2752,9 +2765,7 @@ def __eq__(self, other) -> bool: sage: D1 == D2 True """ - return (isinstance(other, LinearCodeSyndromeDecoder) and - self.code() == other.code() and - self.maximum_error_weight() == other.maximum_error_weight()) + return isinstance(other, LinearCodeSyndromeDecoder) and self.code() == other.code() and self.maximum_error_weight() == other.maximum_error_weight() def __hash__(self) -> int: """ @@ -2869,18 +2880,18 @@ def _build_lookup_table(self): l.remove(zero) # Remember to include the no-error-vector to handle codes of minimum # distance 1 gracefully - zero_syndrome = vector(F, [F.zero()]*(n-k)) + zero_syndrome = vector(F, [F.zero()] * (n - k)) zero_syndrome.set_immutable() - lookup = {zero_syndrome: vector(F, [F.zero()]*n)} - error_position_tables = [cartesian_product([l]*i) for i in range(1, t+1)] + lookup = {zero_syndrome: vector(F, [F.zero()] * n)} + error_position_tables = [cartesian_product([l] * i) for i in range(1, t + 1)] first_collision = True # Filling the lookup table - for i in range(1, t+1): + for i in range(1, t + 1): stop = True patterns = Subsets(range(n), i) basic = vector(F, n) for p in patterns: - for error in error_position_tables[i-1]: + for error in error_position_tables[i - 1]: e = copy(basic) for ind, pos in enumerate(p): e[pos] = error[ind] @@ -2909,7 +2920,7 @@ def _build_lookup_table(self): self._decoder_type.add("bounded_distance") # Update decoder types depending on whether we are decoding beyond d/2 if self._code_minimum_distance: - if self._maximum_error_weight == (self._code_minimum_distance-1)//2: + if self._maximum_error_weight == (self._code_minimum_distance - 1) // 2: self._decoder_type.update({"minimum-distance", "always-succeed"}) else: # then t > (d-1)/2 @@ -3046,8 +3057,7 @@ def __eq__(self, other) -> bool: sage: D1 == D2 True """ - return isinstance(other, LinearCodeNearestNeighborDecoder)\ - and self.code() == other.code() + return isinstance(other, LinearCodeNearestNeighborDecoder) and self.code() == other.code() def _repr_(self) -> str: r""" diff --git a/src/sage/coding/linear_code_no_metric.py b/src/sage/coding/linear_code_no_metric.py index 27e9187fe34..5388504f640 100644 --- a/src/sage/coding/linear_code_no_metric.py +++ b/src/sage/coding/linear_code_no_metric.py @@ -135,11 +135,11 @@ class AbstractLinearCodeNoMetric(AbstractCode, Module): ... ValueError: 'base_field' must be a field (and Ring of integers modulo 4 is not one) """ + _registered_encoders = {} _registered_decoders = {} - def __init__(self, base_field, length, default_encoder_name, - default_decoder_name, metric='Hamming') -> None: + def __init__(self, base_field, length, default_encoder_name, default_decoder_name, metric='Hamming') -> None: """ Initialize mandatory parameters that any linear code shares. @@ -219,7 +219,7 @@ def ambient_space(self): sage: C.ambient_space() Vector space of dimension 7 over Finite Field of size 2 """ - return VectorSpace(self.base_ring(),self.length()) + return VectorSpace(self.base_ring(), self.length()) def generator_matrix(self, encoder_name=None, **kwargs): r""" @@ -268,10 +268,7 @@ def __eq__(self, other) -> bool: False """ # Fail without computing the generator matrix if possible: - if not (isinstance(other, AbstractLinearCodeNoMetric) - and self.length() == other.length() - and self.dimension() == other.dimension() - and self.base_ring() == other.base_ring()): + if not (isinstance(other, AbstractLinearCodeNoMetric) and self.length() == other.length() and self.dimension() == other.dimension() and self.base_ring() == other.base_ring()): return False # Check that basis elements of `other` are all in `self.` # Since we're over a field and since the dimensions match, the codes @@ -357,7 +354,7 @@ def cardinality(self): sage: len(C) 16 """ - return self.base_ring().order()**self.dimension() + return self.base_ring().order() ** self.dimension() __len__ = cardinality @@ -407,6 +404,7 @@ def basis(self): """ gens = self.gens() from sage.structure.sequence import Sequence + return Sequence(gens, universe=self.ambient_space(), check=False, immutable=True, cr=True) @cached_method @@ -489,7 +487,7 @@ def syndrome(self, r): sage: C.syndrome(c) (0, 0, 0, 0, 0, 0, 0, 0) """ - return self.parity_check_matrix()*r + return self.parity_check_matrix() * r def __contains__(self, v) -> bool: r""" @@ -591,6 +589,7 @@ def standard_form(self, return_permutation=True): E = self.encoder("Systematic") if E.systematic_positions() == tuple(range(self.dimension())): from sage.combinat.permutation import Permutation + return self, Permutation([]) perm = E.systematic_permutation() return self.permuted_code(perm), perm @@ -712,8 +711,8 @@ def __iter__(self): sage: L[10].is_immutable() True """ - from sage.modules.finite_submodule_iter import \ - FiniteFieldsubspace_iterator + from sage.modules.finite_submodule_iter import FiniteFieldsubspace_iterator + return FiniteFieldsubspace_iterator(self.generator_matrix(), immutable=True) def __getitem__(self, i): @@ -794,17 +793,14 @@ def __getitem__(self, i): # list(self)[i] and self[i] both return the same element. F = self.base_ring() - maxindex = F.order()**self.dimension() - 1 + maxindex = F.order() ** self.dimension() - 1 if i < 0 or i > maxindex: - raise IndexError("The value of the index 'i' (={}) must be between " - "0 and 'q^k -1' (={}), inclusive, where 'q' is " - "the size of the base field and 'k' is the " - "dimension of the code.".format(i, maxindex)) + raise IndexError("The value of the index 'i' (={}) must be between " "0 and 'q^k -1' (={}), inclusive, where 'q' is " "the size of the base field and 'k' is the " "dimension of the code.".format(i, maxindex)) a = F.primitive_element() m = F.degree() p = F.prime_subfield().order() - A = [a ** k for k in range(m)] + A = [a**k for k in range(m)] G = self.generator_matrix() N = self.dimension() * F.degree() # the total length of p-adic vector ivec = Integer(i).digits(p, padto=N) @@ -1128,8 +1124,7 @@ def __init__(self, code, systematic_positions=None) -> None: # Test that systematic_positions consists of integers in the right # range. We test that len(systematic_positions) = code.dimension() # in self.generator_matrix() to avoid possible infinite recursion. - if (not all( e in ZZ and e >= 0 and e < code.length() for e in systematic_positions)) \ - or len(systematic_positions) != len(set(systematic_positions)): + if (not all(e in ZZ and e >= 0 and e < code.length() for e in systematic_positions)) or len(systematic_positions) != len(set(systematic_positions)): raise ValueError("systematic positions must be a tuple of distinct integers in the range 0 to n-1 where n is the length of the code") # Test that the systematic positions are an information set self.generator_matrix() @@ -1153,9 +1148,7 @@ def __eq__(self, other) -> bool: sage: E1 == E3 False """ - return isinstance(other, LinearCodeSystematicEncoder)\ - and self.code() == other.code()\ - and self.systematic_positions() == other.systematic_positions() + return isinstance(other, LinearCodeSystematicEncoder) and self.code() == other.code() and self.systematic_positions() == other.systematic_positions() def _repr_(self): r""" @@ -1252,14 +1245,14 @@ def generator_matrix(self): if not self._systematic_positions: M.echelonize() else: - k = M.nrows() # it is important that k is *not* computed as C.dimension() to avoid possible cyclic dependency + k = M.nrows() # it is important that k is *not* computed as C.dimension() to avoid possible cyclic dependency if len(self._systematic_positions) != k: raise ValueError("systematic_positions must be a tuple of length equal to the dimension of the code") # Permute the columns of M and bring to reduced row echelon formb perm = self.systematic_permutation() M.permute_columns(perm) M.echelonize() - if M[:,:k].is_singular(): + if M[:, :k].is_singular(): raise ValueError("systematic_positions are not an information set") M.permute_columns(perm.inverse()) M.set_immutable() @@ -1284,7 +1277,7 @@ def systematic_permutation(self): systematic_positions = self.systematic_positions() k = len(systematic_positions) lp = [None] * n - for (i, j) in zip(range(k), systematic_positions): + for i, j in zip(range(k), systematic_positions): lp[i] = j j = k set_sys_pos = set(systematic_positions) @@ -1293,6 +1286,7 @@ def systematic_permutation(self): lp[j] = i j += 1 from sage.combinat.permutation import Permutation + return Permutation([1 + e for e in lp]) def systematic_positions(self): diff --git a/src/sage/coding/linear_rank_metric.py b/src/sage/coding/linear_rank_metric.py index 910027d3b92..b130a00f894 100644 --- a/src/sage/coding/linear_rank_metric.py +++ b/src/sage/coding/linear_rank_metric.py @@ -173,7 +173,7 @@ def to_matrix_representation(v, sub_field=None, basis=None): if not sub_field: sub_field = base_field.prime_subfield() n = v.length() - m = base_field.degree()//sub_field.degree() + m = base_field.degree() // sub_field.degree() extension, to_big_field, from_big_field = base_field.vector_space(sub_field, basis, map=True) return matrix(sub_field, m, n, lambda i, j: from_big_field(v[j])[i]) @@ -353,11 +353,11 @@ class AbstractLinearRankMetricCode(AbstractLinearCodeNoMetric): It is thus strongly recommended to set an encoder with a generator matrix implemented as a default encoder. """ + _registered_encoders = {} _registered_decoders = {} - def __init__(self, base_field, sub_field, length, default_encoder_name, - default_decoder_name, basis=None): + def __init__(self, base_field, sub_field, length, default_encoder_name, default_decoder_name, basis=None): r""" Initialize mandatory parameters that every linear rank metric code has. @@ -477,8 +477,7 @@ def __init__(self, base_field, sub_field, length, default_encoder_name, self._sub_field = sub_field self._generic_constructor = LinearRankMetricCode - super().__init__(base_field, length, default_encoder_name, - default_decoder_name, "rank") + super().__init__(base_field, length, default_encoder_name, default_decoder_name, "rank") def sub_field(self): r""" @@ -768,6 +767,7 @@ def __init__(self, generator, sub_field=None, basis=None): gen_basis = generator.basis() # vector space etc. case if gen_basis is not None: from sage.matrix.constructor import matrix + generator = matrix(base_field, gen_basis) if generator.nrows() == 0: raise ValueError("this linear code contains no nonzero vector") @@ -777,8 +777,7 @@ def __init__(self, generator, sub_field=None, basis=None): self._generator_matrix = generator self._length = generator.ncols() - super().__init__(base_field, sub_field, self._length, - "GeneratorMatrix", "NearestNeighbor", basis) + super().__init__(base_field, sub_field, self._length, "GeneratorMatrix", "NearestNeighbor", basis) def _repr_(self): r""" @@ -808,8 +807,7 @@ def _latex_(self): sage: latex(C) [3, 2]\textnormal{ Linear rank metric code over }\Bold{F}_{2^{6}}/\Bold{F}_{2^{2}} """ - return "[%s, %s]\\textnormal{ Linear rank metric code over }%s/%s"\ - % (self.length(), self.dimension(), self.base_field()._latex_(), self.sub_field()._latex_()) + return "[%s, %s]\\textnormal{ Linear rank metric code over }%s/%s" % (self.length(), self.dimension(), self.base_field()._latex_(), self.sub_field()._latex_()) def generator_matrix(self, encoder_name=None, **kwargs): r""" @@ -878,8 +876,7 @@ def __eq__(self, other): sage: D1 == D2 True """ - return isinstance(other, LinearRankMetricCodeNearestNeighborDecoder)\ - and self.code() == other.code() + return isinstance(other, LinearRankMetricCodeNearestNeighborDecoder) and self.code() == other.code() def _repr_(self): r""" @@ -932,8 +929,8 @@ def decode_to_code(self, r): c_min = C.zero() h_min = C.rank_weight_of_vector(r) for c in C: - if C.rank_weight_of_vector(c-r) < h_min: - h_min = C.rank_weight_of_vector(c-r) + if C.rank_weight_of_vector(c - r) < h_min: + h_min = C.rank_weight_of_vector(c - r) c_min = c c_min.set_immutable() return c_min diff --git a/src/sage/coding/parity_check_code.py b/src/sage/coding/parity_check_code.py index 589c1c6f391..c15bbf7eb53 100644 --- a/src/sage/coding/parity_check_code.py +++ b/src/sage/coding/parity_check_code.py @@ -24,8 +24,7 @@ # http://www.gnu.org/licenses/ # ***************************************************************************** -from sage.coding.linear_code import AbstractLinearCode,\ - LinearCodeGeneratorMatrixEncoder +from sage.coding.linear_code import AbstractLinearCode, LinearCodeGeneratorMatrixEncoder from sage.coding.encoder import Encoder from sage.rings.integer import Integer from sage.rings.finite_rings.finite_field_constructor import GF @@ -78,9 +77,7 @@ def __init__(self, base_field=GF(2), dimension=7): raise ValueError("dimension must be an integer") self._dimension = dimension - super().__init__(base_field, dimension + 1, - "ParityCheckCodeGeneratorMatrixEncoder", - "Syndrome") + super().__init__(base_field, dimension + 1, "ParityCheckCodeGeneratorMatrixEncoder", "Syndrome") def __eq__(self, other): r""" @@ -93,9 +90,7 @@ def __eq__(self, other): sage: C1 == C2 True """ - return (isinstance(other, ParityCheckCode) - and self.base_field() == other.base_field() - and self.dimension() == other.dimension()) + return isinstance(other, ParityCheckCode) and self.base_field() == other.base_field() and self.dimension() == other.dimension() def _repr_(self): r""" @@ -107,9 +102,7 @@ def _repr_(self): sage: C [8, 7] parity-check code over GF(5) """ - return ("[%s, %s] parity-check code over GF(%s)" - % (self.length(), self.dimension(), - self.base_field().cardinality())) + return "[%s, %s] parity-check code over GF(%s)" % (self.length(), self.dimension(), self.base_field().cardinality()) def _latex_(self): r""" @@ -121,8 +114,7 @@ def _latex_(self): sage: latex(C) [8, 7] \textnormal{parity-check code over } \Bold{F}_{5} """ - return "[%s, %s] \\textnormal{parity-check code over } %s"\ - % (self.length(), self.dimension(), self.base_field()._latex_()) + return "[%s, %s] \\textnormal{parity-check code over } %s" % (self.length(), self.dimension(), self.base_field()._latex_()) def minimum_distance(self): r""" @@ -141,6 +133,7 @@ def minimum_distance(self): ####################### encoders ############################### + class ParityCheckCodeGeneratorMatrixEncoder(LinearCodeGeneratorMatrixEncoder): r""" Encoder for parity-check codes which uses a generator matrix to obtain @@ -267,8 +260,7 @@ def _latex_(self): sage: latex(E) \textnormal{Parity-check encoder for the } [8, 7] \textnormal{parity-check code over } \Bold{F}_{5} """ - return ("\\textnormal{Parity-check encoder for the } %s" % - self.code()._latex_()) + return "\\textnormal{Parity-check encoder for the } %s" % self.code()._latex_() def __eq__(self, other): r""" @@ -281,8 +273,7 @@ def __eq__(self, other): sage: C1 == C2 True """ - return (isinstance(other, ParityCheckCodeStraightforwardEncoder) - and self.code() == other.code()) + return isinstance(other, ParityCheckCodeStraightforwardEncoder) and self.code() == other.code() def encode(self, message): r""" diff --git a/src/sage/coding/punctured_code.py b/src/sage/coding/punctured_code.py index f7509287ea8..a89f38f9c14 100644 --- a/src/sage/coding/punctured_code.py +++ b/src/sage/coding/punctured_code.py @@ -7,7 +7,7 @@ on the `i`-th position. """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2015 David Lucas # # This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from .linear_code import AbstractLinearCode from .encoder import Encoder @@ -118,6 +118,7 @@ class PuncturedCode(AbstractLinearCode): sage: Cp Puncturing of [11, 5] linear code over GF(7) on position(s) [3, 5] """ + _registered_encoders = {} _registered_decoders = {} @@ -147,8 +148,7 @@ def __init__(self, C, positions): raise ValueError("Provided code must be a linear code") if not all(i in range(C.length()) for i in positions): raise ValueError("Positions to puncture must be positive integers smaller than the length of the provided code") - super().__init__(C.base_ring(), C.length() - len(positions), - "PuncturedMatrix", "OriginalCode") + super().__init__(C.base_ring(), C.length() - len(positions), "PuncturedMatrix", "OriginalCode") self._original_code = C self._positions = positions @@ -164,9 +164,7 @@ def __eq__(self, other): sage: Cp1 == Cp2 True """ - return isinstance(other, PuncturedCode) \ - and self.punctured_positions() == other.punctured_positions() \ - and self.original_code() == other.original_code() + return isinstance(other, PuncturedCode) and self.punctured_positions() == other.punctured_positions() and self.original_code() == other.original_code() def _repr_(self): r""" @@ -179,8 +177,7 @@ def _repr_(self): sage: Cp Puncturing of [11, 5] linear code over GF(7) on position(s) [3] """ - return "Puncturing of %s on position(s) %s"\ - % (self.original_code(), list(self.punctured_positions())) + return "Puncturing of %s on position(s) %s" % (self.original_code(), list(self.punctured_positions())) def _latex_(self): r""" @@ -193,8 +190,7 @@ def _latex_(self): sage: latex(Cp) \textnormal{Puncturing of [11, 5] linear code over GF(7) on position(s) } [3] """ - return "\\textnormal{Puncturing of %s on position(s) } %s"\ - % (self.original_code(), list(self.punctured_positions())) + return "\\textnormal{Puncturing of %s on position(s) } %s" % (self.original_code(), list(self.punctured_positions())) def punctured_positions(self): r""" @@ -335,7 +331,7 @@ def structured_representation(self): list_len = len(list_pts) for p in cur_pts: for i in range(list_len): - if (p <= list_pts[i]): + if p <= list_pts[i]: list_pts[i] += 1 list_pts += cur_pts C = C.original_code() @@ -567,8 +563,7 @@ def __init__(self, code, strategy=None, original_decoder=None, **kwargs): self._decoder_type = copy(self._decoder_type) self._decoder_type.remove("dynamic") self._decoder_type = self._original_decoder.decoder_type() - super().__init__(code, code.ambient_space(), - self._original_decoder.connected_encoder()) + super().__init__(code, code.ambient_space(), self._original_decoder.connected_encoder()) def _repr_(self): r""" @@ -643,8 +638,7 @@ def decode_to_code(self, y): e_list = e.list() e_list = _insert_punctured_positions(e_list, pts, one) else: - e_list = [one if i in pts else zero - for i in range(Cor.length())] + e_list = [one if i in pts else zero for i in range(Cor.length())] e = vector(GF(2), e_list) yl = y.list() yl = _insert_punctured_positions(yl, pts, zero) diff --git a/src/sage/coding/reed_muller_code.py b/src/sage/coding/reed_muller_code.py index c6c9e3a4339..17772195568 100644 --- a/src/sage/coding/reed_muller_code.py +++ b/src/sage/coding/reed_muller_code.py @@ -98,12 +98,13 @@ def _multivariate_polynomial_interpolation(evaluation, order, polynomial_ring): If there does not exist """ + def _interpolate(evaluation, num_of_var, order): if num_of_var == 0 or order == 0: return evaluation[0] base_field = polynomial_ring.base_ring() q = base_field.cardinality() - n_by_q = q**(num_of_var - 1) + n_by_q = q ** (num_of_var - 1) d = min(order + 1, q) multipoint_evaluation_list = [] uni_poly_ring = PolynomialRing(base_field, 'x') @@ -114,8 +115,7 @@ def _interpolate(evaluation, num_of_var, order): for i in range(d): xcoordinate = next(iterator) points.append((xcoordinate, evaluation[k + i * n_by_q])) - polyVector = uni_poly_ring.lagrange_polynomial( - points).coefficients(sparse=False) + polyVector = uni_poly_ring.lagrange_polynomial(points).coefficients(sparse=False) if len(polyVector) < d: # adding zeros to represent a (d-1) degree polynomial polyVector += [base_field_zero] * (d - len(polyVector)) @@ -124,10 +124,10 @@ def _interpolate(evaluation, num_of_var, order): z = 1 x = polynomial_ring.gen(num_of_var - 1) for k in range(d): # computing the polynomial - poly = poly + z * _interpolate([multipoint_evaluation_list[i][k] - for i in range(n_by_q)], num_of_var - 1, order - k) + poly = poly + z * _interpolate([multipoint_evaluation_list[i][k] for i in range(n_by_q)], num_of_var - 1, order - k) z *= x return poly + return _interpolate(evaluation, polynomial_ring.ngens(), order) @@ -265,8 +265,7 @@ def __init__(self, base_field, order, num_of_var): if order >= q: raise ValueError("The order must be less than %s" % q) - super().__init__(base_field, q**num_of_var, - "EvaluationVector", "Syndrome") + super().__init__(base_field, q**num_of_var, "EvaluationVector", "Syndrome") self._order = order self._num_of_var = num_of_var self._dimension = binomial(num_of_var + order, order) @@ -333,8 +332,7 @@ def _repr_(self): sage: C Reed-Muller Code of order 2 and 4 variables over Finite Field of size 59 """ - return "Reed-Muller Code of order %s and %s variables over %s" % ( - self.order(), self.number_of_variables(), self.base_field()) + return "Reed-Muller Code of order %s and %s variables over %s" % (self.order(), self.number_of_variables(), self.base_field()) def _latex_(self): r""" @@ -348,8 +346,7 @@ def _latex_(self): sage: latex(C) \textnormal{Reed-Muller Code of order} 2 \textnormal{and }4 \textnormal{variables over} \Bold{F}_{59} """ - return "\\textnormal{Reed-Muller Code of order} %s \\textnormal{and }%s \\textnormal{variables over} %s"\ - % (self.order(), self.number_of_variables(), self.base_field()._latex_()) + return "\\textnormal{Reed-Muller Code of order} %s \\textnormal{and }%s \\textnormal{variables over} %s" % (self.order(), self.number_of_variables(), self.base_field()._latex_()) def __eq__(self, other): r""" @@ -366,10 +363,7 @@ def __eq__(self, other): """ # I am not comparing the base field directly because of possible change # in variables - return isinstance(other, QAryReedMullerCode) \ - and self.base_field() == other.base_field() \ - and self.order() == other.order() \ - and self.number_of_variables() == other.number_of_variables() + return isinstance(other, QAryReedMullerCode) and self.base_field() == other.base_field() and self.order() == other.order() and self.number_of_variables() == other.number_of_variables() class BinaryReedMullerCode(AbstractLinearCode): @@ -439,10 +433,8 @@ def __init__(self, order, num_of_var): raise ValueError("The order of the code must be an integer") if not isinstance(num_of_var, (Integer, int)): raise ValueError("The number of variables must be an integer") - if (num_of_var < order): - raise ValueError( - "The order must be less than or equal to %s" % - num_of_var) + if num_of_var < order: + raise ValueError("The order must be less than or equal to %s" % num_of_var) super().__init__(GF(2), 2**num_of_var, "EvaluationVector", "Syndrome") self._order = order @@ -488,7 +480,7 @@ def minimum_distance(self): sage: C.minimum_distance() 4 """ - return 2**(self.number_of_variables() - self.order()) + return 2 ** (self.number_of_variables() - self.order()) def _repr_(self): r""" @@ -500,8 +492,7 @@ def _repr_(self): sage: C Binary Reed-Muller Code of order 2 and number of variables 4 """ - return "Binary Reed-Muller Code of order %s and number of variables %s" % ( - self.order(), self.number_of_variables()) + return "Binary Reed-Muller Code of order %s and number of variables %s" % (self.order(), self.number_of_variables()) def _latex_(self): r""" @@ -513,8 +504,7 @@ def _latex_(self): sage: latex(C) \textnormal{Binary Reed-Muller Code of order} 2 \textnormal{and number of variables} 4 """ - return "\\textnormal{Binary Reed-Muller Code of order} %s \\textnormal{and number of variables} %s" % ( - self.order(), self.number_of_variables()) + return "\\textnormal{Binary Reed-Muller Code of order} %s \\textnormal{and number of variables} %s" % (self.order(), self.number_of_variables()) def __eq__(self, other): r""" @@ -527,9 +517,7 @@ def __eq__(self, other): sage: C1.__eq__(C2) True """ - return isinstance(other, BinaryReedMullerCode) \ - and self.order() == other.order() \ - and self.number_of_variables() == other.number_of_variables() + return isinstance(other, BinaryReedMullerCode) and self.order() == other.order() and self.number_of_variables() == other.number_of_variables() class ReedMullerVectorEncoder(Encoder): @@ -641,8 +629,7 @@ def __eq__(self, other): sage: D1 is D2 False """ - return (isinstance(other, ReedMullerVectorEncoder) - ) and self.code() == other.code() + return (isinstance(other, ReedMullerVectorEncoder)) and self.code() == other.code() @cached_method def generator_matrix(self): @@ -671,10 +658,8 @@ def generator_matrix(self): matrix_list = [] max_individual_degree = min(order, (q - 1)) for degree in range(order + 1): - exponents = Subsets(list(range(num_of_var)) * max_individual_degree, - degree, submultiset=True) - matrix_list += [[reduce(mul, [x[i] for i in exponent], 1) - for x in points] for exponent in exponents] + exponents = Subsets(list(range(num_of_var)) * max_individual_degree, degree, submultiset=True) + matrix_list += [[reduce(mul, [x[i] for i in exponent], 1) for x in points] for exponent in exponents] M = matrix(base_field, matrix_list) M.set_immutable() return M @@ -694,7 +679,7 @@ def points(self): [(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2), (1, 2), (2, 2)] """ code = self.code() - return ((code.base_field())**code.number_of_variables()).list() + return ((code.base_field()) ** code.number_of_variables()).list() class ReedMullerPolynomialEncoder(Encoder): @@ -784,16 +769,12 @@ def __init__(self, code, polynomial_ring=None): raise ValueError("the code has to be a Reed-Muller code") super().__init__(code) if polynomial_ring is None: - self._polynomial_ring = PolynomialRing(code.base_field(), - code.number_of_variables(), 'x') + self._polynomial_ring = PolynomialRing(code.base_field(), code.number_of_variables(), 'x') else: - if (polynomial_ring.base_ring() == code.base_field()) and ( - len(polynomial_ring.variable_names()) == code.number_of_variables()): + if (polynomial_ring.base_ring() == code.base_field()) and (len(polynomial_ring.variable_names()) == code.number_of_variables()): self._polynomial_ring = polynomial_ring else: - raise ValueError( - "The Polynomial ring should be on %s and should have %s variables" % - (code.base_field(), code.number_of_variables())) + raise ValueError("The Polynomial ring should be on %s and should have %s variables" % (code.base_field(), code.number_of_variables())) def _repr_(self): r""" @@ -838,8 +819,7 @@ def __eq__(self, other): sage: D1 is D2 False """ - return isinstance(other, ReedMullerPolynomialEncoder) \ - and self.code() == other.code() + return isinstance(other, ReedMullerPolynomialEncoder) and self.code() == other.code() def encode(self, p): r""" @@ -888,8 +868,7 @@ def encode(self, p): raise ValueError("The value to encode must be in %s" % M) C = self.code() if p.degree() > C.order(): - raise ValueError("The polynomial to encode must have degree at most %s" - % C.order()) + raise ValueError("The polynomial to encode must have degree at most %s" % C.order()) base_fieldTuple = Tuples(C.base_field().list(), C.number_of_variables()) return vector(C.base_ring(), [p(x) for x in base_fieldTuple]) @@ -933,10 +912,7 @@ def unencode_nocheck(self, c): sage: E.encode(p) == c False """ - return _multivariate_polynomial_interpolation( - c, - self.code().order(), - self.polynomial_ring()) + return _multivariate_polynomial_interpolation(c, self.code().order(), self.polynomial_ring()) def message_space(self): r""" @@ -981,7 +957,7 @@ def points(self): [(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2), (1, 2), (2, 2)] """ code = self.code() - return ((code.base_field())**code.number_of_variables()).list() + return ((code.base_field()) ** code.number_of_variables()).list() # --------------- registration -------------- diff --git a/src/sage/coding/self_dual_codes.py b/src/sage/coding/self_dual_codes.py index 53d892a640d..b367b6c0033 100644 --- a/src/sage/coding/self_dual_codes.py +++ b/src/sage/coding/self_dual_codes.py @@ -112,7 +112,7 @@ def _MS(n): sage: self_dual_codes._MS(8) Full MatrixSpace of 4 by 8 dense matrices over Finite Field of size 2 """ - n2 = ZZ(n)/2 + n2 = ZZ(n) / 2 return MatrixSpace(_F, n2, n) @@ -134,11 +134,11 @@ def _matA(n): """ A = [] n2 = n.quo_rem(2)[0] - for j in range(n2+2): + for j in range(n2 + 2): MS0 = MatrixSpace(_F, j, j) I = MS0.identity_matrix() - O = MS0(j*j*[1]) - A.append(I+O) + O = MS0(j * j * [1]) + A.append(I + O) return A @@ -160,7 +160,7 @@ def _matId(n): Id = [] n2 = n.quo_rem(2)[0] for j in range(n2): - MSn = MatrixSpace(_F, n2-j, n2-j) + MSn = MatrixSpace(_F, n2 - j, n2 - j) Id.append(MSn.identity_matrix()) return Id @@ -216,13 +216,7 @@ def _And7(): [1 0 1 1 0 0 0] [1 1 0 1 0 0 0] """ - return matrix(_F, [[1, 1, 1, 0, 0, 1, 1], - [1, 1, 1, 0, 1, 0, 1], - [1, 1, 1, 0, 1, 1, 0], - [0, 0, 0, 0, 1, 1, 1], - [0, 1, 1, 1, 0, 0, 0], - [1, 0, 1, 1, 0, 0, 0], - [1, 1, 0, 1, 0, 0, 0]]) + return matrix(_F, [[1, 1, 1, 0, 0, 1, 1], [1, 1, 1, 0, 1, 0, 1], [1, 1, 1, 0, 1, 1, 0], [0, 0, 0, 0, 1, 1, 1], [0, 1, 1, 1, 0, 0, 0], [1, 0, 1, 1, 0, 0, 0], [1, 1, 0, 1, 0, 0, 0]]) @cached_function @@ -243,14 +237,8 @@ def _H8(): [ 1 1 -1 -1 -1 -1 1 1] [ 1 -1 -1 1 -1 1 1 -1] """ - return matrix(ZZ, [[1, 1, 1, 1, 1, 1, 1, 1], - [1, -1, 1, -1, 1, -1, 1, -1], - [1, 1, -1, -1, 1, 1, -1, -1], - [1, -1, -1, 1, 1, -1, -1, 1], - [1, 1, 1, 1, -1, -1, -1, -1], - [1, -1, 1, -1, -1, 1, -1, 1], - [1, 1, -1, -1, -1, -1, 1, 1], - [1, -1, -1, 1, -1, 1, 1, -1]]) # from Guava's Hadamard matrices database + return matrix(ZZ, [[1, 1, 1, 1, 1, 1, 1, 1], [1, -1, 1, -1, 1, -1, 1, -1], [1, 1, -1, -1, 1, 1, -1, -1], [1, -1, -1, 1, 1, -1, -1, 1], [1, 1, 1, 1, -1, -1, -1, -1], [1, -1, 1, -1, -1, 1, -1, 1], [1, 1, -1, -1, -1, -1, 1, 1], [1, -1, -1, 1, -1, 1, 1, -1]]) # from Guava's Hadamard matrices database + # Remark: The above matrix constructions aid in computing some "small" self-dual codes. @@ -310,9 +298,8 @@ def self_dual_binary_codes(n): genmat = _I2(n).augment(_I2(n)) # G = PermutationGroup([ "(2,4)", "(1,2)(3,4)" ]) spectrum = [1, 0, 2, 0, 1] - self_dual_codes_4_0 = {"order autgp":8,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"Unique."} - self_dual_codes["4"] = {"0":self_dual_codes_4_0} + self_dual_codes_4_0 = {"order autgp": 8, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Unique."} + self_dual_codes["4"] = {"0": self_dual_codes_4_0} return self_dual_codes if n == 6: @@ -321,9 +308,8 @@ def self_dual_binary_codes(n): genmat = _I2(n).augment(_I2(n)) # G = PermutationGroup( ["(3,6)", "(2,3)(5,6)", "(1,2)(4,5)"] ) spectrum = [1, 0, 3, 0, 3, 0, 1] - self_dual_codes_6_0 = {"order autgp":48,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"Unique"} - self_dual_codes["6"] = {"0":self_dual_codes_6_0} + self_dual_codes_6_0 = {"order autgp": 48, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Unique"} + self_dual_codes["6"] = {"0": self_dual_codes_6_0} return self_dual_codes if n == 8: @@ -333,16 +319,14 @@ def self_dual_binary_codes(n): genmat = _I2(n).augment(_I2(n)) # G = PermutationGroup( ["(4,8)", "(3,4)(7,8)", "(2,3)(6,7)", "(1,2)(5,6)"] ) spectrum = [1, 0, 4, 0, 6, 0, 4, 0, 1] - self_dual_codes_8_0 = {"order autgp":384,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"Unique Type I of this length."} + self_dual_codes_8_0 = {"order autgp": 384, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Unique Type I of this length."} # [8,1]: genmat = _I2(n).augment(_matA(n)[4]) # G = PermutationGroup( ["(4,5)(6,7)", "(4,6)(5,7)", "(3,4)(7,8)",\ # "(2,3)(6,7)", "(1,2)(5,6)"] ) spectrum = [1, 0, 0, 0, 14, 0, 0, 0, 1] - self_dual_codes_8_1 = {"order autgp":1344,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"II","Comment":"Unique Type II of this length."} - self_dual_codes["8"] = {"0":self_dual_codes_8_0,"1":self_dual_codes_8_1} + self_dual_codes_8_1 = {"order autgp": 1344, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "II", "Comment": "Unique Type II of this length."} + self_dual_codes["8"] = {"0": self_dual_codes_8_0, "1": self_dual_codes_8_1} return self_dual_codes if n == 10: @@ -352,16 +336,14 @@ def self_dual_binary_codes(n): # G = PermutationGroup( ["(5,10)", "(4,5)(9,10)", "(3,4)(8,9)",\ # "(2,3)(7,8)", "(1,2)(6,7)"] ) spectrum = [1, 0, 5, 0, 10, 0, 10, 0, 5, 0, 1] - self_dual_codes_10_0 = {"order autgp":3840,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"No Type II of this length."} + self_dual_codes_10_0 = {"order autgp": 3840, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "No Type II of this length."} # [10,1]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matId(n)[4]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4], _matId(n)[4]])) # G = PermutationGroup( ["(5,10)", "(4,6)(7,8)", "(4,7)(6,8)", "(3,4)(8,9)",\ # "(2,3)(7,8)", "(1,2)(6,7)"] ) spectrum = [1, 0, 1, 0, 14, 0, 14, 0, 1, 0, 1] - self_dual_codes_10_1 = {"order autgp":2688,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"Unique lowest weight nonzero codeword."} - self_dual_codes["10"] = {"0":self_dual_codes_10_0,"1":self_dual_codes_10_1} + self_dual_codes_10_1 = {"order autgp": 2688, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Unique lowest weight nonzero codeword."} + self_dual_codes["10"] = {"0": self_dual_codes_10_0, "1": self_dual_codes_10_1} return self_dual_codes if n == 12: @@ -371,23 +353,20 @@ def self_dual_binary_codes(n): # G = PermutationGroup( ["(6,12)", "(5,6)(11,12)", "(4,5)(10,11)", "(3,4)(9,10)",\ # "(2,3)(8,9)", "(1,2)(7,8)"] ) spectrum = [1, 0, 6, 0, 15, 0, 20, 0, 15, 0, 6, 0, 1] - self_dual_codes_12_0 = {"order autgp":48080,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"No Type II of this length."} + self_dual_codes_12_0 = {"order autgp": 48080, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "No Type II of this length."} # [12,1]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matId(n)[4]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4], _matId(n)[4]])) # G = PermutationGroup( ["(2,3)(4,7)", "(2,4)(3,7)", "(2,4,9)(3,7,8)", "(2,4,8,10)(3,9)",\ # "(1,2,4,7,8,10)(3,9)", "(2,4,8,10)(3,9)(6,12)", "(2,4,8,10)(3,9)(5,6,11,12)"] ) spectrum = [1, 0, 2, 0, 15, 0, 28, 0, 15, 0, 2, 0, 1] - self_dual_codes_12_1 = {"order autgp":10752,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"Smallest automorphism group of these."} + self_dual_codes_12_1 = {"order autgp": 10752, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Smallest automorphism group of these."} # [12,2]: genmat = _I2(n).augment(_matA(n)[6]) # G = PermutationGroup( ["(5,6)(11,12)", "(5,11)(6,12)", "(4,5)(10,11)", "(3,4)(9,10)",\ # "(2,3)(8,9)", "(1,2)(7,8)"] ) spectrum = [1, 0, 0, 0, 15, 0, 32, 0, 15, 0, 0, 0, 1] - self_dual_codes_12_2 = {"order autgp":23040,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"Largest minimum distance of these."} - self_dual_codes["12"] = {"0":self_dual_codes_12_0,"1":self_dual_codes_12_1,"2":self_dual_codes_12_2} + self_dual_codes_12_2 = {"order autgp": 23040, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Largest minimum distance of these."} + self_dual_codes["12"] = {"0": self_dual_codes_12_0, "1": self_dual_codes_12_1, "2": self_dual_codes_12_2} return self_dual_codes if n == 14: @@ -398,32 +377,27 @@ def self_dual_binary_codes(n): # G = PermutationGroup( ["(7,14)", "(6,7)(13,14)", "(5,6)(12,13)", "(4,5)(11,12)",\ # "(3,4)(10,11)", "(2,3)(9,10)", "(1,2)(8,9)"] ) spectrum = [1, 0, 7, 0, 21, 0, 35, 0, 35, 0, 21, 0, 7, 0, 1] - self_dual_codes_14_0 = {"order autgp":645120,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"No Type II of this length. Huge aut gp."} + self_dual_codes_14_0 = {"order autgp": 645120, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "No Type II of this length. Huge aut gp."} # [14,1]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matId(n)[4]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4], _matId(n)[4]])) # G = PermutationGroup( ["(7,14)", "(6,7)(13,14)", "(5,6)(12,13)", "(4,8)(9,10)",\ # "(4,9)(8,10)", "(3,4)(10,11)", "(2,3)(9,10)", "(1,2)(8,9)"] ) spectrum = [1, 0, 3, 0, 17, 0, 43, 0, 43, 0, 17, 0, 3, 0, 1] - self_dual_codes_14_1 = {"order autgp":64512,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"Automorphism group has order 64512."} + self_dual_codes_14_1 = {"order autgp": 64512, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Automorphism group has order 64512."} # [14,2]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6],_matId(n)[6]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6], _matId(n)[6]])) # G = PermutationGroup( ["(7,14)", "(5,6)(12,13)", "(5,12)(6,13)", "(4,5)(11,12)",\ # "(3,4)(10,11)", "(2,3)(9,10)", "(1,2)(8,9)"] ) spectrum = [1, 0, 1, 0, 15, 0, 47, 0, 47, 0, 15, 0, 1, 0, 1] - self_dual_codes_14_2 = {"order autgp":46080,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"Unique codeword of weight 2."} + self_dual_codes_14_2 = {"order autgp": 46080, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Unique codeword of weight 2."} # [14,3]: genmat = _I2(n).augment(_And7()) # G = PermutationGroup( ["(7,11)(12,13)", "(7,12)(11,13)", "(6,9)(10,14)",\ # "(6,10)(9,14)", "(5,6)(8,9)", "(4,5)(9,10), (2,3)(11,12)", "(2,7)(3,13)",\ # "(1,2)(12,13)", "(1,4)(2,5)(3,8)(6,7)(9,13)(10,12)(11,14)"]) spectrum = [1, 0, 0, 0, 14, 0, 49, 0, 49, 0, 14, 0, 0, 0, 1] - self_dual_codes_14_3 = {"order autgp":56448,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"Largest minimum distance of these."} - self_dual_codes["14"] = {"0":self_dual_codes_14_0,"1":self_dual_codes_14_1,"2":self_dual_codes_14_2, - "3":self_dual_codes_14_3} + self_dual_codes_14_3 = {"order autgp": 56448, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Largest minimum distance of these."} + self_dual_codes["14"] = {"0": self_dual_codes_14_0, "1": self_dual_codes_14_1, "2": self_dual_codes_14_2, "3": self_dual_codes_14_3} return self_dual_codes if n == 16: @@ -434,30 +408,26 @@ def self_dual_binary_codes(n): # G = PermutationGroup( [ "(8,16)", "(7,8)(15,16)", "(6,7)(14,15)", "(5,6)(13,14)", # "(4,5)(12,13)", "(3,4)(11,12)", "(2,3)(10,11)", "(1,2)(9,10)"] ) spectrum = [1, 0, 8, 0, 28, 0, 56, 0, 70, 0, 56, 0, 28, 0, 8, 0, 1] - self_dual_codes_16_0 = {"order autgp":10321920,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"Huge aut gp."} + self_dual_codes_16_0 = {"order autgp": 10321920, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Huge aut gp."} # [16,1]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matId(n)[4]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4], _matId(n)[4]])) # G = PermutationGroup( [ "(8,16)", "(7,8)(15,16)", "(6,7)(14,15)", "(5,6)(13,14)",\ # "(4,9)(10,11)", "(4,10)(9,11)", "(3,4)(11,12)", "(2,3)(10,11)", "(1,2)(9,10)"] ) spectrum = [1, 0, 4, 0, 20, 0, 60, 0, 86, 0, 60, 0, 20, 0, 4, 0, 1] - self_dual_codes_16_1 = {"order autgp":516096,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":""} + self_dual_codes_16_1 = {"order autgp": 516096, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": ""} # [16,2]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matA(n)[4]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4], _matA(n)[4]])) # G = PermutationGroup( [ "(8,13)(14,15)", "(8,14)(13,15)", "(7,8)(15,16)", "(6,7)(14,15)",\ # "(5,6)(13,14)", "(4,9)(10,11)", "(4,10)(9,11)", "(3,4)(11,12)", "(2,3)(10,11)",\ # "(1,2)(9,10)","(1,5)(2,6)(3,7)(4,8)(9,13)(10,14)(11,15)(12,16)"] ) spectrum = [1, 0, 0, 0, 28, 0, 0, 0, 198, 0, 0, 0, 28, 0, 0, 0, 1] - self_dual_codes_16_2 = {"order autgp":3612672,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"II","Comment":"Same spectrum as the other Type II code."} + self_dual_codes_16_2 = {"order autgp": 3612672, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "II", "Comment": "Same spectrum as the other Type II code."} # [16,3]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6],_matId(n)[6]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6], _matId(n)[6]])) # G = PermutationGroup( [ "(8,16)", "(7,8)(15,16)", "(5,6)(13,14)", "(5,13)(6,14)",\ # "(4,5)(12,13)", "(3,4)(11,12)", "(2,3)(10,11)", "(1,2)(9,10)"] ) spectrum = [1, 0, 2, 0, 16, 0, 62, 0, 94, 0, 62, 0, 16, 0, 2, 0, 1] - self_dual_codes_16_3 = {"order autgp":184320,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":""} + self_dual_codes_16_3 = {"order autgp": 184320, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": ""} # [16,4]: genmat = _I2(n).augment(_matA(n)[8]) # an equivalent form: See also [20,8] using A[10] @@ -472,28 +442,24 @@ def self_dual_binary_codes(n): # G = PermutationGroup( [ "(7,8)(15,16)", "(7,15)(8,16)", "(6,7)(14,15)",\ # "(5,6)(13,14)","(4,5)(12,13)","(3,4)(11,12)", "(2,3)(10,11)", "(1,2)(9,10)"] ) spectrum = [1, 0, 0, 0, 28, 0, 0, 0, 198, 0, 0, 0, 28, 0, 0, 0, 1] - self_dual_codes_16_4 = {"order autgp":5160960,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"II","Comment":"Same spectrum as the other Type II code. Large aut gp."} + self_dual_codes_16_4 = {"order autgp": 5160960, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "II", "Comment": "Same spectrum as the other Type II code. Large aut gp."} # [16,5]: - genmat = _I2(n).augment(block_diagonal_matrix([_And7(),_matId(n)[7]])) + genmat = _I2(n).augment(block_diagonal_matrix([_And7(), _matId(n)[7]])) # G = PermutationGroup( [ "(8,16)", "(7,12)(13,14)", "(7,13)(12,14)",\ # "(6,10)(11,15)", "(6,11)(10,15)", "(5,6)(9,10)", "(4,5)(10,11)",\ # "(2,3)(12,13)", "(2,7)(3,14)", "(1,2)(13,14)",\ # "(1,4)(2,5)(3,9)(6,7)(10,14)(11,13)(12,15)" ] ) spectrum = [1, 0, 1, 0, 14, 0, 63, 0, 98, 0, 63, 0, 14, 0, 1, 0, 1] - self_dual_codes_16_5 = {"order autgp":112896,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"'Exceptional' construction."} + self_dual_codes_16_5 = {"order autgp": 112896, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "'Exceptional' construction."} # [16,6]: - J8 = MatrixSpace(ZZ,8,8)(64*[1]) - genmat = _I2(n).augment(_I2(n)+_MS2(n)((_H8()+J8)/2)) + J8 = MatrixSpace(ZZ, 8, 8)(64 * [1]) + genmat = _I2(n).augment(_I2(n) + _MS2(n)((_H8() + J8) / 2)) # G = PermutationGroup( [ "(7,9)(10,16)", "(7,10)(9,16)", "(6,7)(10,11)",\ # "(4,6)(11,13)", "(3,5)(12,14)", "(3,12)(5,14)", "(2,3)(14,15)",\ # "(1,2)(8,15)", "(1,4)(2,6)(3,7)(5,16)(8,13)(9,12)(10,14)(11,15)" ] ) spectrum = [1, 0, 0, 0, 12, 0, 64, 0, 102, 0, 64, 0, 12, 0, 0, 0, 1] - self_dual_codes_16_6 = {"order autgp":73728,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"'Exceptional' construction. Min dist 4."} - self_dual_codes["16"] = {"0":self_dual_codes_16_0,"1":self_dual_codes_16_1,"2":self_dual_codes_16_2, - "3":self_dual_codes_16_3,"4":self_dual_codes_16_4,"5":self_dual_codes_16_5,"6":self_dual_codes_16_6} + self_dual_codes_16_6 = {"order autgp": 73728, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "'Exceptional' construction. Min dist 4."} + self_dual_codes["16"] = {"0": self_dual_codes_16_0, "1": self_dual_codes_16_1, "2": self_dual_codes_16_2, "3": self_dual_codes_16_3, "4": self_dual_codes_16_4, "5": self_dual_codes_16_5, "6": self_dual_codes_16_6} return self_dual_codes if n == 18: @@ -505,45 +471,52 @@ def self_dual_binary_codes(n): # G = PermutationGroup( [ "(9,18)", "(8,9)(17,18)", "(7,8)(16,17)", "(6,7)(15,16)",\ # "(5,6)(14,15)", "(4,5)(13,14)", "(3,4)(12,13)", "(2,3)(11,12)", "(1,2)(10,11)" ] ) spectrum = [1, 0, 9, 0, 36, 0, 84, 0, 126, 0, 126, 0, 84, 0, 36, 0, 9, 0, 1] - self_dual_codes_18_0 = {"order autgp":185794560,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment": "Huge aut gp. S_9x(ZZ/2ZZ)^9?"} + self_dual_codes_18_0 = {"order autgp": 185794560, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Huge aut gp. S_9x(ZZ/2ZZ)^9?"} # [18,1]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matId(n)[4]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4], _matId(n)[4]])) # G = PermutationGroup( [ "(9,18)", "(8,9)(17,18)", "(7,8)(16,17)", "(6,7)(15,16)",\ # "(5,6)(14,15)", "(4,10)(11,12)", "(4,11)(10,12)", "(3,4)(12,13)",\ # "(2,3)(11,12)", "(1,2)(10,11)" ] ) spectrum = [1, 0, 5, 0, 24, 0, 80, 0, 146, 0, 146, 0, 80, 0, 24, 0, 5, 0, 1] - self_dual_codes_18_1 = {"order autgp":5160960,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment": "Large aut gp."} + self_dual_codes_18_1 = {"order autgp": 5160960, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Large aut gp."} # [18,2]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6],_matId(n)[6]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6], _matId(n)[6]])) # G = PermutationGroup( [ "(9,18)", "(8,9)(17,18)", "(7,8)(16,17)", "(5,6)(14,15)",\ # "(5,14)(6,15)","(4,5)(13,14)", "(3,4)(12,13)", "(2,3)(11,12)", "(1,2)(10,11)"] ) spectrum = [1, 0, 3, 0, 18, 0, 78, 0, 156, 0, 156, 0, 78, 0, 18, 0, 3, 0, 1] - self_dual_codes_18_2 = {"order autgp":1105920,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment": ""} + self_dual_codes_18_2 = {"order autgp": 1105920, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": ""} # [18,3]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matA(n)[4],_matId(n)[8]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4], _matA(n)[4], _matId(n)[8]])) # G = PermutationGroup( [ "(9,18)", "(8,14)(15,16)", "(8,15)(14,16)", "(7,8)(16,17)",\ # "(6,7)(15,16)","(5,6)(14,15)", "(4,10)(11,12)", "(4,11)(10,12)",\ # "(3,4)(12,13)", "(2,3)(11,12)","(1,2)(10,11)",\ # "(1,5)(2,6)(3,7)(4,8)(10,14)(11,15)(12,16)(13,17)" ] ) spectrum = [1, 0, 1, 0, 28, 0, 28, 0, 198, 0, 198, 0, 28, 0, 28, 0, 1, 0, 1] - self_dual_codes_18_3 = {"order autgp":7225344,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment": "Large aut gp. Unique codeword of smallest nonzero wt.\ - Same spectrum as '[18,4]' sd code."} + self_dual_codes_18_3 = { + "order autgp": 7225344, + "code": LinearCode(genmat), + "spectrum": spectrum, + "Type": "I", + "Comment": "Large aut gp. Unique codeword of smallest nonzero wt.\ + Same spectrum as '[18,4]' sd code.", + } # [18,4]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[8],_matId(n)[8]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[8], _matId(n)[8]])) # G = PermutationGroup( [ "(9,18)", "(7,8)(16,17)", "(7,16)(8,17)", "(6,7)(15,16)", \ # "(5,6)(14,15)", "(4,5)(13,14)", "(3,4)(12,13)", "(2,3)(11,12)", "(1,2)(10,11)" ] ) spectrum = [1, 0, 1, 0, 28, 0, 28, 0, 198, 0, 198, 0, 28, 0, 28, 0, 1, 0, 1] - self_dual_codes_18_4 = {"order autgp":10321920,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment": "Huge aut gp. Unique codeword of smallest nonzero wt.\ - Same spectrum as '[18,3]' sd code."} + self_dual_codes_18_4 = { + "order autgp": 10321920, + "code": LinearCode(genmat), + "spectrum": spectrum, + "Type": "I", + "Comment": "Huge aut gp. Unique codeword of smallest nonzero wt.\ + Same spectrum as '[18,3]' sd code.", + } # [18,5]: - C = self_dual_binary_codes(n-2)["%s" % (n-2)]["5"]["code"] + C = self_dual_binary_codes(n - 2)["%s" % (n - 2)]["5"]["code"] A0 = C.redundancy_matrix() - genmat = _I2(n).augment(block_diagonal_matrix([A0,_matId(n)[8]])) + genmat = _I2(n).augment(block_diagonal_matrix([A0, _matId(n)[8]])) # G = PermutationGroup( [ "(5,10)(6,11)", "(5,11)(6,10)", "(5,11,12)(6,7,10)",\ # "(5,11,10,7,12,6,13)", "(2,15)(3,16)(5,11,10,7,12,6,13)",\ # "(2,16)(3,15)(5,11,10,7,12,6,13)", "(2,16,14)(3,15,4)(5,11,10,7,12,6,13)",\ @@ -551,113 +524,66 @@ def self_dual_binary_codes(n): # "(2,16,14)(3,15,4)(5,11,10,7,12,6,13)(9,18)",\ # "(2,16,14)(3,15,4)(5,11,10,7,12,6,13)(8,9,17,18)" ] ) spectrum = [1, 0, 2, 0, 15, 0, 77, 0, 161, 0, 161, 0, 77, 0, 15, 0, 2, 0, 1] - self_dual_codes_18_5 = {"order autgp":451584,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment": "'Exceptional' construction."} + self_dual_codes_18_5 = {"order autgp": 451584, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "'Exceptional' construction."} # [18,6]: - C = self_dual_binary_codes(n-2)["%s" % (n-2)]["6"]["code"] + C = self_dual_binary_codes(n - 2)["%s" % (n - 2)]["6"]["code"] A0 = C.redundancy_matrix() - genmat = _I2(n).augment(block_diagonal_matrix([A0,_matId(n)[8]])) - G = PermutationGroup( [ "(9,18)", "(7,10)(11,17)", "(7,11)(10,17)", "(6,7)(11,12)", - "(4,6)(12,14)", "(3,5)(13,15)", "(3,13)(5,15)", "(2,3)(15,16)", "(1,2)(8,16)", - "(1,4)(2,6)(3,7)(5,17)(8,14)(10,13)(11,15)(12,16)" ] ) + genmat = _I2(n).augment(block_diagonal_matrix([A0, _matId(n)[8]])) + G = PermutationGroup(["(9,18)", "(7,10)(11,17)", "(7,11)(10,17)", "(6,7)(11,12)", "(4,6)(12,14)", "(3,5)(13,15)", "(3,13)(5,15)", "(2,3)(15,16)", "(1,2)(8,16)", "(1,4)(2,6)(3,7)(5,17)(8,14)(10,13)(11,15)(12,16)"]) spectrum = [1, 0, 1, 0, 12, 0, 76, 0, 166, 0, 166, 0, 76, 0, 12, 0, 1, 0, 1] - self_dual_codes_18_6 = {"order autgp":147456,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment": "'Exceptional'. Unique codeword of smallest nonzero wt."} + self_dual_codes_18_6 = {"order autgp": 147456, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "'Exceptional'. Unique codeword of smallest nonzero wt."} # [18,7] (equiv to H18 in [P]) - genmat = _MS(n)([[1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0], - [0,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1], - [0,0,1,0,0,0,0,0,0,1,1,1,0,0,1,0,0,1], - [0,0,0,1,0,0,0,0,0,1,1,1,1,0,0,0,0,1], - [0,0,0,0,1,0,0,0,0,1,1,0,0,1,0,1,1,0], - [0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,1,1,0], - [0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0], - [0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,1], - [0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,1]]) + genmat = _MS(n)([[1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1], [0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1], [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1]]) # G = PermutationGroup( [ "(9,10)(16,18)", "(9,16)(10,18)", "(8,9)(14,16)",\ # "(7,11)(12,17)", "(7,12)(11,17)", "(5,6)(11,12)", "(5,7)(6,17)",\ # "(4,13)(5,8)(6,14)(7,9)(10,12)(11,18)(16,17)", "(3,4)(13,15)",\ # "(1,2)(5,8)(6,14)(7,9)(10,12)(11,18)(16,17)", "(1,3)(2,15)",\ # "(1,5)(2,6)(3,7)(4,11)(10,18)(12,13)(15,17)" ] ) spectrum = [1, 0, 0, 0, 9, 0, 75, 0, 171, 0, 171, 0, 75, 0, 9, 0, 0, 0, 1] - self_dual_codes_18_7 = {"order autgp":82944,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment": "'Exceptional' construction. Min dist 4."} + self_dual_codes_18_7 = {"order autgp": 82944, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "'Exceptional' construction. Min dist 4."} # [18, 8] (equiv to I18 in [P]) - I18 = _MS(n)([[1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0], - [0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0], - [1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0], - [0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0], - [0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0], - [0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1], - [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]]) - genmat = _MS(n)([[1,0,0,0,0,0,0,0,0, 1, 1, 1, 1, 1, 0, 0, 0, 0], - [0,1,0,0,0,0,0,0,0, 1, 0, 1, 1, 1, 0, 1, 1, 1], - [0,0,1,0,0,0,0,0,0, 0, 1, 1, 0, 0, 0, 1, 1, 1], - [0,0,0,1,0,0,0,0,0, 0, 1, 0, 0, 1, 0, 1, 1, 1], - [0,0,0,0,1,0,0,0,0, 0, 1, 0, 1, 0, 0, 1, 1, 1], - [0,0,0,0,0,1,0,0,0, 1, 1, 0, 0, 0, 0, 1, 1, 1], - [0,0,0,0,0,0,1,0,0, 0, 0, 0, 0, 0, 1, 0, 1, 1], - [0,0,0,0,0,0,0,1,0, 0, 0, 0, 0, 0, 1, 1, 0, 1], - [0,0,0,0,0,0,0,0,1, 0, 0, 0, 0, 0, 1, 1, 1, 0]]) - G = PermutationGroup( [ "(9,15)(16,17)", "(9,16)(15,17)", "(8,9)(17,18)", - "(7,8)(16,17)", "(5,6)(10,13)", "(5,10)(6,13)", "(4,5)(13,14)", - "(3,4)(12,14)", "(1,2)(6,10)", "(1,3)(2,12)" ] ) + I18 = _MS(n)([[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]) + genmat = _MS(n)([[1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1], [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1], [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0]]) + G = PermutationGroup(["(9,15)(16,17)", "(9,16)(15,17)", "(8,9)(17,18)", "(7,8)(16,17)", "(5,6)(10,13)", "(5,10)(6,13)", "(4,5)(13,14)", "(3,4)(12,14)", "(1,2)(6,10)", "(1,3)(2,12)"]) spectrum = [1, 0, 0, 0, 17, 0, 51, 0, 187, 0, 187, 0, 51, 0, 17, 0, 0, 0, 1] - self_dual_codes_18_8 = {"order autgp":322560,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment": "'Exceptional' construction. Min dist 4."} - self_dual_codes["18"] = {"0":self_dual_codes_18_0,"1":self_dual_codes_18_1,"2":self_dual_codes_18_2, - "3":self_dual_codes_18_3,"4":self_dual_codes_18_4,"5":self_dual_codes_18_5, - "6":self_dual_codes_18_6,"7":self_dual_codes_18_7,"8":self_dual_codes_18_8} + self_dual_codes_18_8 = {"order autgp": 322560, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "'Exceptional' construction. Min dist 4."} + self_dual_codes["18"] = {"0": self_dual_codes_18_0, "1": self_dual_codes_18_1, "2": self_dual_codes_18_2, "3": self_dual_codes_18_3, "4": self_dual_codes_18_4, "5": self_dual_codes_18_5, "6": self_dual_codes_18_6, "7": self_dual_codes_18_7, "8": self_dual_codes_18_8} return self_dual_codes if n == 20: # all of these of these are Type I; 2 of these codes # are formally equivalent but with different automorphism groups; # one of these has a unique codeword of lowest weight - A10 = MatrixSpace(_F, 10, 10)([[1, 1, 1, 1, 1, 1, 1, 1, 1, 0], - [1, 1, 1, 0, 1, 0, 1, 0, 1, 1], - [1, 0, 0, 1, 0, 1, 0, 1, 0, 1], - [0, 0, 0, 1, 1, 1, 0, 1, 0, 1], - [0, 0, 1, 1, 0, 1, 0, 1, 0, 1], - [0, 0, 0, 1, 0, 1, 1, 1, 0, 1], - [0, 1, 0, 1, 0, 1, 0, 1, 0, 1], - [0, 0, 0, 1, 0, 0, 0, 0, 1, 1], - [0, 0, 0, 0, 0, 1, 0, 0, 1, 1], - [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]]) + A10 = MatrixSpace(_F, 10, 10)([[1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [1, 1, 1, 0, 1, 0, 1, 0, 1, 1], [1, 0, 0, 1, 0, 1, 0, 1, 0, 1], [0, 0, 0, 1, 1, 1, 0, 1, 0, 1], [0, 0, 1, 1, 0, 1, 0, 1, 0, 1], [0, 0, 0, 1, 0, 1, 1, 1, 0, 1], [0, 1, 0, 1, 0, 1, 0, 1, 0, 1], [0, 0, 0, 1, 0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 1, 0, 0, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]]) # [20,0]: genmat = _I2(n).augment(_I2(n)) # G = PermutationGroup( ["(10,20)", "(9,10)(19,20)", "(8,9)(18,19)", "(7,8)(17,18)", "(6,7)(16,17)",\ # "(5,6)(15,16)", "(4,5)(14,15)", "(3,4)(13,14)", "(2,3)(12,13)", "(1,2)(11,12)"] ) spectrum = [1, 0, 10, 0, 45, 0, 120, 0, 210, 0, 252, 0, 210, 0, 120, 0, 45, 0, 10, 0, 1] - self_dual_codes_20_0 = {"order autgp":3715891200,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment": "Huge aut gp"} + self_dual_codes_20_0 = {"order autgp": 3715891200, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Huge aut gp"} # [20,1]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matId(n)[4]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4], _matId(n)[4]])) # G = PermutationGroup( [ "(10,20)", "(9,10)(19,20)", "(8,9)(18,19)", "(7,8)(17,18)", "(6,7)(16,17)",\ # "(5,6)(15,16)", "(4,11)(12,13)", "(4,12)(11,13)", "(3,4)(13,14)",\ # "(2,3)(12,13)", "(1,2)(11,12)"] ) spectrum = [1, 0, 6, 0, 29, 0, 104, 0, 226, 0, 292, 0, 226, 0, 104, 0, 29, 0, 6, 0, 1] - self_dual_codes_20_1 = {"order autgp":61931520,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":""} + self_dual_codes_20_1 = {"order autgp": 61931520, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": ""} # [20,2]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6],_matId(n)[6]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6], _matId(n)[6]])) # G = PermutationGroup( [ "(10,20)", "(9,10)(19,20)", "(8,9)(18,19)", "(7,8)(17,18)",\ # "(5,6)(15,16)", "(5,15)(6,16)", "(4,5)(14,15)", "(3,4)(13,14)",\ # "(2,3)(12,13)", "(1,2)(11,12)"] ) spectrum = [1, 0, 4, 0, 21, 0, 96, 0, 234, 0, 312, 0, 234, 0, 96, 0, 21, 0, 4, 0, 1] - self_dual_codes_20_2 = {"order autgp":8847360,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":""} + self_dual_codes_20_2 = {"order autgp": 8847360, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": ""} # [20,3]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6],_matA(n)[4]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6], _matA(n)[4]])) # G = PermutationGroup( [ "(5,6)(15,16)", "(5,15)(6,16)", "(4,5)(14,15)", "(3,4)(13,14)",\ # "(2,3)(12,13)", "(1,2)(11,12)", "(8,17)(9,10)", "(8,10)(9,17)", "(8,10,20)(9,19,17)",\ # "(8,19,20,9,17,10,18)", "(7,8,19,20,9,18)(10,17)"] ) spectrum = [1, 0, 0, 0, 29, 0, 32, 0, 226, 0, 448, 0, 226, 0, 32, 0, 29, 0, 0, 0, 1] - self_dual_codes_20_3 = {"order autgp":30965760,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"Min dist 4."} + self_dual_codes_20_3 = {"order autgp": 30965760, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Min dist 4."} # [20,4]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matA(n)[4],_matId(n)[8]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4], _matA(n)[4], _matId(n)[8]])) # G = PermutationGroup( [ "(5,15)(6,16)", "(5,16)(6,15)", "(5,16,7)(6,17,15)", "(5,15,8)(6,17,7)",\ # "(5,17,18)(6,15,8), (3,14)(4,13)(5,17,18)(6,15,8)", "(3,13)(4,14)(5,17,18)(6,15,8)",\ # "(2,3,14)(4,13,11)(5,17,18)(6,15,8)"," (2,3,12)(4,11,14)(5,17,18)(6,15,8)",\ @@ -665,76 +591,44 @@ def self_dual_binary_codes(n): # "(2,3,12)(4,11,14)(5,17,18)(6,15,8)(10,20)",\ # "(2,3,12)(4,11,14)(5,17,18)(6,15,8)(9,10,19,20)"] ) spectrum = [1, 0, 2, 0, 29, 0, 56, 0, 226, 0, 396, 0, 226, 0, 56, 0, 29, 0, 2, 0, 1] - self_dual_codes_20_4 = {"order autgp":28901376,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":""} + self_dual_codes_20_4 = {"order autgp": 28901376, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": ""} # [20,5]: - genmat = _I2(n).augment(block_diagonal_matrix([_And7(),_matId(n)[7]])) + genmat = _I2(n).augment(block_diagonal_matrix([_And7(), _matId(n)[7]])) # G = PermutationGroup( [ "(10,20)", "(9,10)(19,20)", "(8,9)(18,19)",\ # "(7,11)(12,14)", "(7,12)(11,14)", "(6,7)(12,13)", "(5,6)(11,12)",\ # "(4,15)(16,17)", "(4,16)(15,17)", "(2,3)(16,17)", "(2,4)(3,15)",\ # "(1,2)(15,16)", "(1,5)(2,6)(3,13)(4,7)(11,16)(12,15)(14,17)" ] ) # order 2709504 spectrum = [1, 0, 3, 0, 17, 0, 92, 0, 238, 0, 322, 0, 238, 0, 92, 0, 17, 0, 3, 0, 1] - self_dual_codes_20_5 = {"order autgp":2709504,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment": "'Exceptional' construction."} + self_dual_codes_20_5 = {"order autgp": 2709504, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "'Exceptional' construction."} # [20,6]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[8],_matId(n)[8]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[8], _matId(n)[8]])) # G = PermutationGroup( [ "(7,8)(17,18)", "(7,17)(8,18)", "(6,7)(16,17)", "(5,6)(15,16)",\ # "(4,5)(14,15)", "(3,4)(13,14)", "(2,3)(12,13)", "(1,2)(11,12)",\ # "(10,20)", "(9,10,19,20)"] ) spectrum = [1, 0, 2, 0, 29, 0, 56, 0, 226, 0, 396, 0, 226, 0, 56, 0, 29, 0, 2, 0, 1] - self_dual_codes_20_6 = {"order autgp":41287680,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":""} + self_dual_codes_20_6 = {"order autgp": 41287680, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": ""} # [20,7]: - A0 = self_dual_binary_codes(n-4)["16"]["6"]["code"].redundancy_matrix() - genmat = _I2(n).augment(block_diagonal_matrix([A0,_matId(n)[8]])) + A0 = self_dual_binary_codes(n - 4)["16"]["6"]["code"].redundancy_matrix() + genmat = _I2(n).augment(block_diagonal_matrix([A0, _matId(n)[8]])) # G = PermutationGroup( [ "(10,20)", "(9,10)(19,20)", "(7,11)(12,18)",\ # "(7,12)(11,18)", "(6,7)(12,13)", "(4,6)(13,15)", "(3,5)(14,16)",\ # "(3,14)(5,16)", "(2,3)(16,17)", "(1,2)(8,17)",\ # "(1,4)(2,6)(3,7)(5,18)(8,15)(11,14)(12,16)(13,17)" ] ) - spectrum = [1,0,2,0,13,0,88,0,242,0,332,0,242,0,88,0,13,0,2,0,1] - self_dual_codes_20_7 = {"order autgp":589824,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"'Exceptional' construction."} + spectrum = [1, 0, 2, 0, 13, 0, 88, 0, 242, 0, 332, 0, 242, 0, 88, 0, 13, 0, 2, 0, 1] + self_dual_codes_20_7 = {"order autgp": 589824, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "'Exceptional' construction."} # [20,8]: (genmat, J20, and genmat2 are all equiv) genmat = _I2(n).augment(_matA(n)[10]) - J20 = _MS(n)([[1,1,1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0,0,1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0,0,0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0,0,0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0,0,0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], - [0,0,0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], - [0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], - [0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0], - [0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], - [1,0,1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]]) - genmat2 = _MS(n)([[1,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1], - [0,1,0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1], - [0,0,1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], - [0,0,0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0], - [0,0,0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0], - [0,0,0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], - [0,0,0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0], - [0,0,0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0], - [0,0,0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0], - [0,0,0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1]]) + J20 = _MS(n)([[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]]) + genmat2 = _MS(n)([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1]]) # G = PermutationGroup( [ "(9,10)(19,20)", "(9,19)(10,20)", "(8,9)(18,19)", "(7,8)(17,18)",\ # "(6,7)(16,17)", "(5,6)(15,16)", "(4,5)(14,15)", "(3,4)(13,14)",\ # "(2,3)(12,13)", "(1,2)(11,12)"] ) spectrum = [1, 0, 0, 0, 45, 0, 0, 0, 210, 0, 512, 0, 210, 0, 0, 0, 45, 0, 0, 0, 1] - self_dual_codes_20_8 = {"order autgp":1857945600,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"Huge aut gp. Min dist 4."} + self_dual_codes_20_8 = {"order autgp": 1857945600, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Huge aut gp. Min dist 4."} # [20,9]: (genmat, K20 are equiv) genmat = _I2(n).augment(A10) - K20 = _MS(n)([[1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0], - [0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0], - [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0], - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0], - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1], - [1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,0,0,0,0,0], - [0,0,0,0,0,0,0,0,0,0,1,1,1,0,1,0,1,0,1,0]]) - #genmat = K20 # not in standard form + K20 = _MS(n)([[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0]]) + # genmat = K20 # not in standard form # G = PermutationGroup( [ "(4,13)(5,15)", "(4,15)(5,13)", "(3,4,13)(5,11,15)", # "(3,4,6,11,15,17)(5,13)", "(3,5,17,4,12)(6,15,7,11,13)", # "(1,2)(3,5,17,4,7,11,13,6,15,12)", "(1,3,5,17,4,12)(2,11,13,6,15,7)", @@ -742,79 +636,39 @@ def self_dual_binary_codes(n): # "(3,5,17,4,12)(6,15,7,11,13)(9,10)(16,18)", # "(3,5,17,4,12)(6,15,7,11,13)(8,9)(14,16)" ] ) spectrum = [1, 0, 0, 0, 21, 0, 48, 0, 234, 0, 416, 0, 234, 0, 48, 0, 21, 0, 0, 0, 1] - self_dual_codes_20_9 = {"order autgp":4423680,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment": "Min dist 4."} + self_dual_codes_20_9 = {"order autgp": 4423680, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Min dist 4."} # [20,10] - L20 = _MS(n)([[1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0], - [0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0], - [0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,0], - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0], - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1], - [0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,1,0,0,0,0], - [0,1,0,1,0,1,0,0,0,0,0,0,0,0,1,0,1,0,1,0]]) - genmat = L20 # not in standard form + L20 = _MS(n)([[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], [0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0], [0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0]]) + genmat = L20 # not in standard form # G = PermutationGroup( [ "(17,18)(19,20)", "(17,19)(18,20)", "(15,16)(19,20)", # "(15,17)(16,18)", "(10,11)(12,13)", "(10,12)(11,13)", "(9,10)(13,14)", # "(8,9)(12,13)", "(3,4)(5,6)", "(3,5)(4,6)", "(2,3)(6,7)", "(1,2)(5,6)", # "(1,8)(2,9)(3,10)(4,11)(5,12)(6,13)(7,14)(19,20)" ] ) # order 1354752 spectrum = [1, 0, 0, 0, 17, 0, 56, 0, 238, 0, 400, 0, 238, 0, 56, 0, 17, 0, 0, 0, 1] - self_dual_codes_20_10 = {"order autgp":1354752,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment": "Min dist 4."} + self_dual_codes_20_10 = {"order autgp": 1354752, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Min dist 4."} # [20,11] - S20 = _MS(n)([[1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0], - [0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0], - [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0], - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1], - [1,0,1,0,1,0,1,0,1,1,0,0,0,0,0,0,1,1,0,0], - [1,1,0,0,0,0,0,0,1,0,1,0,1,0,1,0,1,1,0,0], - [1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,0,1,0]] ) - genmat = S20 # not in standard form + S20 = _MS(n)([[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], [1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0]]) + genmat = S20 # not in standard form # G = PermutationGroup( [ "(17,18)(19,20)", "(17,19)(18,20)", "(13,14)(15,16)", # "(13,15)(14,16)", "(11,12)(15,16)", "(11,13)(12,14)", "(9,10)(15,16)", # "(9,11)(10,12)", "(5,6)(7,8)", "(5,7)(6,8)", "(3,4)(7,8)", "(3,5)(4,6)", # "(1,2)(7,8)", "(1,3)(2,4)", "(1,9)(2,10)(3,11)(4,12)(5,13)(6,14)(7,15)(8,16)" ] ) # G.order() = 294912 spectrum = [1, 0, 0, 0, 13, 0, 64, 0, 242, 0, 384, 0, 242, 0, 64, 0, 13, 0, 0, 0, 1] - self_dual_codes_20_11 = {"order autgp":294912,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"Min dist 4."} + self_dual_codes_20_11 = {"order autgp": 294912, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Min dist 4."} # [20,12] - R20 = _MS(n)([[0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0], - [0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0], - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0], - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1], - [0,1,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,1,1,0], - [1,1,1,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0], - [1,1,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,1,0,1], - [1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1]]) - genmat = R20 # not in standard form + R20 = _MS(n)([[0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], [0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0], [1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1], [1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1]]) + genmat = R20 # not in standard form # G = PermutationGroup( [ "(17,18)(19,20)", "(17,19)(18,20)", "(15,16)(19,20)", # "(15,17)(16,18)", "(11,12)(13,14)", "(11,13)(12,14)", "(9,10)(13,14)", # "(9,11)(10,12)", "(5,6)(7,8)", "(5,7)(6,8)", "(3,4)(7,8)", "(3,5)(4,6)", # "(3,9,15)(4,10,16)(5,11,17)(6,12,18)(7,14,19)(8,13,20)", # "(1,2)(7,8)(9,15)(10,16)(11,17)(12,18)(13,19)(14,20)" ] ) # order 82944 spectrum = [1, 0, 0, 0, 9, 0, 72, 0, 246, 0, 368, 0, 246, 0, 72, 0, 9, 0, 0, 0, 1] - self_dual_codes_20_12 = {"order autgp":82944,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"Min dist 4."} + self_dual_codes_20_12 = {"order autgp": 82944, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Min dist 4."} # [20,13] - M20 = _MS(n)([[1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0], - [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0], - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1], - [0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0], - [1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0], - [0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1], - [0,0,1,1,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0], - [0,0,0,0,0,0,1,1,0,1,1,0,1,0,0,1,0,0,0,0]]) - genmat = M20 # not in standard form + M20 = _MS(n)([[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0], [0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1], [0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0]]) + genmat = M20 # not in standard form # G = PermutationGroup( [ "(17,18)(19,20)", "(17,19)(18,20)", "(13,14)(15,16)", # "(13,15)(14,16)", "(9,10)(11,12)", "(9,11)(10,12)", "(5,6)(7,8)", # "(5,7)(6,8)", "(5,9)(6,11)(7,12)(8,10)(13,17)(14,19)(15,18)(16,20)", @@ -824,11 +678,10 @@ def self_dual_binary_codes(n): # "(1,2)(6,7)(11,12)(13,17)(14,18)(15,19)(16,20)", # "(1,5)(2,6)(3,7)(4,8)(9,17)(10,18)(11,19)(12,20)" ] ) spectrum = [1, 0, 0, 0, 5, 0, 80, 0, 250, 0, 352, 0, 250, 0, 80, 0, 5, 0, 0, 0, 1] - self_dual_codes_20_13 = {"order autgp":122880,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment": "Min dist 4."} + self_dual_codes_20_13 = {"order autgp": 122880, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Min dist 4."} # [20,14]: # aut gp of this computed using a program by Robert Miller - A0 = self_dual_binary_codes(n-2)["18"]["8"]["code"].redundancy_matrix() - genmat = _I2(n).augment(block_diagonal_matrix([A0,_matId(n)[9]])) + A0 = self_dual_binary_codes(n - 2)["18"]["8"]["code"].redundancy_matrix() + genmat = _I2(n).augment(block_diagonal_matrix([A0, _matId(n)[9]])) # [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0], # [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0], # [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0], @@ -843,11 +696,10 @@ def self_dual_binary_codes(n): # "(7,8)(17,18)", "(4,15)(5,14)", "(4,5)(14,15)", "(4,15)(6,11)", "(5,6)(11,14)", # "(3,13)(4,15)", "(3,15)(4,13)", "(1,2)(4,15)", "(1,4)(2,15)(3,5)(13,14)", "(10,20)" ] ) spectrum = [1, 0, 1, 0, 17, 0, 68, 0, 238, 0, 374, 0, 238, 0, 68, 0, 17, 0, 1, 0, 1] - self_dual_codes_20_14 = {"order autgp":645120,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment": "'Exceptional' construction."} + self_dual_codes_20_14 = {"order autgp": 645120, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "'Exceptional' construction."} # [20,15]: - A0 = self_dual_binary_codes(n-2)["18"]["7"]["code"].redundancy_matrix() - genmat = _I2(n).augment(block_diagonal_matrix([A0,_matId(n)[9]])) + A0 = self_dual_binary_codes(n - 2)["18"]["7"]["code"].redundancy_matrix() + genmat = _I2(n).augment(block_diagonal_matrix([A0, _matId(n)[9]])) # [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0], # [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0], # [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0], @@ -864,14 +716,8 @@ def self_dual_binary_codes(n): # "(1,2)(5,8)(6,15)(7,9)(11,13)(12,19)(17,18)", "(1,3)(2,16)", # "(1,5)(2,6)(3,7)(4,12)(11,19)(13,14)(16,18)" ] ) # order 165888 spectrum = [1, 0, 1, 0, 9, 0, 84, 0, 246, 0, 342, 0, 246, 0, 84, 0, 9, 0, 1, 0, 1] - self_dual_codes_20_15 = {"order autgp":165888,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"'Exceptional' construction. Unique lowest wt codeword."} - self_dual_codes["20"] = {"0":self_dual_codes_20_0,"1":self_dual_codes_20_1,"2":self_dual_codes_20_2, - "3":self_dual_codes_20_3,"4":self_dual_codes_20_4,"5":self_dual_codes_20_5, - "6":self_dual_codes_20_6,"7":self_dual_codes_20_7,"8":self_dual_codes_20_8, - "9":self_dual_codes_20_9,"10":self_dual_codes_20_10,"11":self_dual_codes_20_11, - "12":self_dual_codes_20_12,"13":self_dual_codes_20_13,"14":self_dual_codes_20_14, - "15":self_dual_codes_20_15} + self_dual_codes_20_15 = {"order autgp": 165888, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "'Exceptional' construction. Unique lowest wt codeword."} + self_dual_codes["20"] = {"0": self_dual_codes_20_0, "1": self_dual_codes_20_1, "2": self_dual_codes_20_2, "3": self_dual_codes_20_3, "4": self_dual_codes_20_4, "5": self_dual_codes_20_5, "6": self_dual_codes_20_6, "7": self_dual_codes_20_7, "8": self_dual_codes_20_8, "9": self_dual_codes_20_9, "10": self_dual_codes_20_10, "11": self_dual_codes_20_11, "12": self_dual_codes_20_12, "13": self_dual_codes_20_13, "14": self_dual_codes_20_14, "15": self_dual_codes_20_15} return self_dual_codes if n == 22: @@ -884,58 +730,49 @@ def self_dual_binary_codes(n): # "(8,9)(19,20)", "(7,8)(18,19)", "(6,7)(17,18)", "(5,6)(16,17)",\ # "(4,5)(15,16)", "(3,4)(14,15)", "(2,3)(13,14)", "(1,2)(12,13)" ] ) # S_11x(ZZ/2ZZ)^11?? spectrum = [1, 0, 11, 0, 55, 0, 165, 0, 330, 0, 462, 0, 462, 0, 330, 0, 165, 0, 55, 0, 11, 0, 1] - self_dual_codes_22_0 = {"order autgp":81749606400,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"Huge aut gp."} + self_dual_codes_22_0 = {"order autgp": 81749606400, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Huge aut gp."} # [22,1]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matId(n)[4]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4], _matId(n)[4]])) # G = PermutationGroup( [ "(11,22)", "(10,11)(21,22)", "(9,10)(20,21)",\ # "(8,9)(19,20)", "(7,8)(18,19)", "(6,7)(17,18)", "(5,6)(16,17)",\ # "(4,12)(13,14)", "(4,13)(12,14)", "(3,4)(14,15)", "(2,3)(13,14)", "(1,2)(12,13)" ] ) spectrum = [1, 0, 7, 0, 35, 0, 133, 0, 330, 0, 518, 0, 518, 0, 330, 0, 133, 0, 35, 0, 7, 0, 1] - self_dual_codes_22_1 = {"order autgp":867041280,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":""} + self_dual_codes_22_1 = {"order autgp": 867041280, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": ""} # [22,2]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6],_matId(n)[6]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6], _matId(n)[6]])) # G = PermutationGroup( [ "(11,22)", "(10,11)(21,22)", "(9,10)(20,21)",\ # "(8,9)(19,20)", "(7,8)(18,19)", "(5,6)(16,17)", "(5,16)(6,17)",\ # "(4,5)(15,16)", "(3,4)(14,15)", "(2,3)(13,14)", "(1,2)(12,13)" ] ) spectrum = [1, 0, 5, 0, 25, 0, 117, 0, 330, 0, 546, 0, 546, 0, 330, 0, 117, 0, 25, 0, 5, 0, 1] - self_dual_codes_22_2 = {"order autgp":88473600,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":""} + self_dual_codes_22_2 = {"order autgp": 88473600, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": ""} # [22,3]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[8],_matId(n)[8]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[8], _matId(n)[8]])) # G = PermutationGroup( [ "(11,22)", "(10,11)(21,22)", "(9,10)(20,21)",\ # "(7,8)(18,19)", "(7,18)(8,19)", "(6,7)(17,18)", "(5,6)(16,17)",\ # "(4,5)(15,16)", "(3,4)(14,15)", "(2,3)(13,14)", "(1,2)(12,13)" ] ) spectrum = [1, 0, 3, 0, 31, 0, 85, 0, 282, 0, 622, 0, 622, 0, 282, 0, 85, 0, 31, 0, 3, 0, 1] - self_dual_codes_22_3 = {"order autgp":247726080,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"Same spectrum as the '[20,5]' code."} + self_dual_codes_22_3 = {"order autgp": 247726080, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Same spectrum as the '[20,5]' code."} # [22,4]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[10],_matId(n)[10]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[10], _matId(n)[10]])) # G = PermutationGroup( [ "(11,22)", "(9,10)(20,21)", "(9,20)(10,21)",\ # "(8,9)(19,20)", "(7,8)(18,19)", "(6,7)(17,18)", "(5,6)(16,17)",\ # "(4,5)(15,16)", "(3,4)(14,15)", "(2,3)(13,14)", "(1,2)(12,13)" ] ) spectrum = [1, 0, 1, 0, 45, 0, 45, 0, 210, 0, 722, 0, 722, 0, 210, 0, 45, 0, 45, 0, 1, 0, 1] - self_dual_codes_22_4 = {"order autgp":3715891200,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"Unique lowest weight codeword."} + self_dual_codes_22_4 = {"order autgp": 3715891200, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Unique lowest weight codeword."} # [22,5]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4],_matA(n)[4],_matId(n)[8]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[4], _matA(n)[4], _matId(n)[8]])) # G = PermutationGroup( [ "(11,22)", "(10,11)(21,22)", "(9,10)(20,21)",\ # "(8,16)(17,18)", "(8,17)(16,18)", "(7,8)(18,19)", "(6,7)(17,18)",\ # "(5,6)(16,17)", "(4,12)(13,14)", "(4,13)(12,14)", "(3,4)(14,15)",\ # "(2,3)(13,14)", "(1,2)(12,13)", "(1,5)(2,6)(3,7)(4,8)(12,16)(13,17)(14,18)(15,19)" ] ) spectrum = [1, 0, 3, 0, 31, 0, 85, 0, 282, 0, 622, 0, 622, 0, 282, 0, 85, 0, 31, 0, 3, 0, 1] - self_dual_codes_22_5 = {"order autgp":173408256,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"Same spectrum as the '[20,3]' code."} + self_dual_codes_22_5 = {"order autgp": 173408256, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Same spectrum as the '[20,3]' code."} # [22,6]: - genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6],_matA(n)[4],_matId(n)[10]])) + genmat = _I2(n).augment(block_diagonal_matrix([_matA(n)[6], _matA(n)[4], _matId(n)[10]])) # G = PermutationGroup( [ "(11,22)", "(10,18)(19,20)", "(10,19)(18,20)",\ # "(9,10)(20,21)", "(8,9)(19,20)", "(7,8)(18,19)", "(5,6)(16,17)",\ # "(5,16)(6,17)", "(4,5)(15,16)", "(3,4)(14,15)", "(2,3)(13,14)", "(1,2)(12,13)" ] ) spectrum = [1, 0, 1, 0, 29, 0, 61, 0, 258, 0, 674, 0, 674, 0, 258, 0, 61, 0, 29, 0, 1, 0, 1] - self_dual_codes_22_6 = {"order autgp":61931520,"code":LinearCode(genmat),"spectrum":spectrum, - "Type":"I","Comment":"Unique lowest weight codeword."} - self_dual_codes["22"] = {"0":self_dual_codes_22_0,"1":self_dual_codes_22_1,"2":self_dual_codes_22_2, - "3":self_dual_codes_22_3,"4":self_dual_codes_22_4,"5":self_dual_codes_22_5, - "6":self_dual_codes_22_6} + self_dual_codes_22_6 = {"order autgp": 61931520, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Unique lowest weight codeword."} + self_dual_codes["22"] = {"0": self_dual_codes_22_0, "1": self_dual_codes_22_1, "2": self_dual_codes_22_2, "3": self_dual_codes_22_3, "4": self_dual_codes_22_4, "5": self_dual_codes_22_5, "6": self_dual_codes_22_6} return self_dual_codes diff --git a/src/sage/coding/source_coding/huffman.py b/src/sage/coding/source_coding/huffman.py index 444652d5e8f..47dda722e1c 100644 --- a/src/sage/coding/source_coding/huffman.py +++ b/src/sage/coding/source_coding/huffman.py @@ -39,6 +39,7 @@ # ########################################################################### + def frequency_table(string): r""" Return the frequency table corresponding to the given string. @@ -281,12 +282,8 @@ def _build_code_from_tree(self, tree, d, prefix): # feeding this class a sufficiently large alphabet, it is possible to # exceed the maximum recursion depth and hence result in a RuntimeError. try: - self._build_code_from_tree(tree[0], - d, - prefix="".join([prefix, "0"])) - self._build_code_from_tree(tree[1], - d, - prefix="".join([prefix, "1"])) + self._build_code_from_tree(tree[0], d, prefix="".join([prefix, "0"])) + self._build_code_from_tree(tree[1], d, prefix="".join([prefix, "1"])) except TypeError: d[tree] = prefix @@ -336,9 +333,7 @@ def _build_code(self, dic): # symbols in the alphabet; we could explicitly handle the corner # cases of 0 or 1 characters, but they are also pretty useless so # enforce 2 or more characters - raise ValueError( - "The alphabet for {} must contain at least two symbols.".format( - self.__class__.__name__)) + raise ValueError("The alphabet for {} must contain at least two symbols.".format(self.__class__.__name__)) symbols = sorted(dic.items(), key=lambda x: (x[1], x[0])) @@ -368,8 +363,7 @@ def pop(): # is associated with the empty string. self._build_code_from_tree(self._tree, d, prefix="") self._index = {i: s for i, (s, w) in enumerate(symbols)} - self._character_to_code = { - s: d[i] for i, (s, w) in enumerate(symbols)} + self._character_to_code = {s: d[i] for i, (s, w) in enumerate(symbols)} def encode(self, string): r""" @@ -509,6 +503,7 @@ def tree(self): """ from sage.graphs.digraph import DiGraph + g = DiGraph() g.add_edges(self._generate_edges(self._tree)) return g diff --git a/src/sage/coding/subfield_subcode.py b/src/sage/coding/subfield_subcode.py index f65f2cd7355..a553f9f0441 100644 --- a/src/sage/coding/subfield_subcode.py +++ b/src/sage/coding/subfield_subcode.py @@ -9,7 +9,7 @@ `Cs` is called the subfield subcode of `C` over `\GF{q}` """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2016 David Lucas, Inria # # This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from .linear_code import AbstractLinearCode from sage.misc.cachefunc import cached_method @@ -48,6 +48,7 @@ class SubfieldSubcode(AbstractLinearCode): sage: codes.SubfieldSubcode(C, GF(4, 'a')) Subfield subcode of [7, 3] linear code over GF(16) down to GF(4) """ + _registered_encoders = {} _registered_decoders = {} @@ -107,9 +108,7 @@ def __eq__(self, other): sage: Cs1 == Cs2 True """ - return isinstance(other, SubfieldSubcode) \ - and self.original_code() == other.original_code()\ - and self.embedding() == other.embedding() + return isinstance(other, SubfieldSubcode) and self.original_code() == other.original_code() and self.embedding() == other.embedding() def _repr_(self): r""" @@ -122,8 +121,7 @@ def _repr_(self): sage: Cs Subfield subcode of [7, 3] linear code over GF(16) down to GF(4) """ - return "Subfield subcode of %s down to GF(%s)"\ - % (self.original_code(), self.base_field().cardinality()) + return "Subfield subcode of %s down to GF(%s)" % (self.original_code(), self.base_field().cardinality()) def _latex_(self): r""" @@ -136,8 +134,7 @@ def _latex_(self): sage: latex(Cs) \textnormal{Subfield subcode of }[7, 3]\textnormal{ Linear code over }\Bold{F}_{2^{4}}\textnormal{ down to }\Bold{F}_{2^{2}} """ - return "\\textnormal{Subfield subcode of }%s\\textnormal{ down to }%s"\ - % (self.original_code()._latex_(), self.base_field()._latex_()) + return "\\textnormal{Subfield subcode of }%s\\textnormal{ down to }%s" % (self.original_code()._latex_(), self.base_field()._latex_()) def dimension(self): r""" @@ -180,7 +177,7 @@ def dimension_lower_bound(self): n = C.length() k = C.dimension() m = self._extension_degree - return n - m*(n-k) + return n - m * (n - k) def original_code(self): r""" @@ -250,7 +247,7 @@ def parity_check_matrix(self): for j in range(n): h_vec = to_V(H_original[i][j]) for k in range(m): - H[i*m+k, j] = h_vec[k] + H[i * m + k, j] = h_vec[k] H = H.echelon_form() delete = [i for i in range(H.nrows()) if H.row(i) == 0] @@ -307,8 +304,7 @@ def __init__(self, code, original_decoder=None, **kwargs): else: self._original_decoder = original_code.decoder(**kwargs) - super().__init__(code, code.ambient_space(), - self._original_decoder.connected_encoder()) + super().__init__(code, code.ambient_space(), self._original_decoder.connected_encoder()) self._decoder_type = copy(self._decoder_type) self._decoder_type.remove("dynamic") @@ -391,8 +387,7 @@ def decode_to_code(self, y): try: cw = vector([sec(c) for c in result]) except ValueError: # not a codeword of this code - raise DecodingError("Original decoder does not output a subfield codeword. " - "You may have exceeded the decoding radius.") + raise DecodingError("Original decoder does not output a subfield codeword. " "You may have exceeded the decoding radius.") return cw def decoding_radius(self, **kwargs): diff --git a/src/sage/coding/two_weight_db.py b/src/sage/coding/two_weight_db.py index 8b546714bd2..cafc022964e 100644 --- a/src/sage/coding/two_weight_db.py +++ b/src/sage/coding/two_weight_db.py @@ -38,361 +38,269 @@ data = [ { - 'n' : 68, - 'k' : 8, + 'n': 68, + 'k': 8, 'w1': 32, 'w2': 40, - 'K' : GF(2), - 'M' : ("10000000100111100110000001101000100111000011100101011010111111010110", - "01000000010011110011000000110100010011100001110010101101011111101011", - "00100000001001111101100000011010001001110000111001010110101111110101", - "00010000100011011100110001100101100011111011111001100001101000101100", - "00001000110110001100011001011010011110111110011001111010001011000000", - "00000100111100100000001101000101101000011100101001110111111010110110", - "00000010011110010000000110100010111100001110010100101011111101011011", - "00000001001111001100000011010001011110000111001010010101111110101101"), + 'K': GF(2), + 'M': ("10000000100111100110000001101000100111000011100101011010111111010110", "01000000010011110011000000110100010011100001110010101101011111101011", "00100000001001111101100000011010001001110000111001010110101111110101", "00010000100011011100110001100101100011111011111001100001101000101100", "00001000110110001100011001011010011110111110011001111010001011000000", "00000100111100100000001101000101101000011100101001110111111010110110", "00000010011110010000000110100010111100001110010100101011111101011011", "00000001001111001100000011010001011110000111001010010101111110101101"), 'source': "Shared by Eric Chen [ChenDB]_.", }, { - 'n' : 140, - 'k' : 6, + 'n': 140, + 'k': 6, 'w1': 90, 'w2': 99, - 'K' : GF(3), - 'M' : ("10111011111111101110101110111100111011111011101111101001001111011011011111100100111101000111101111101100011011001111101110111110101111111001", - "01220121111211011101011101112101220022120121011222010110011010120110112112001101021010101111012211011000020110012221212101011101211122020011", - "22102021112110111120211021122012100012202220112110101200110101202102122120011110020201211110021210110000101200121222122010211022211210110101", - "11010221121101111102210221220221000111011101121102012101101012012022222000211200202012211100111201200001122001211011120102110212212102121001", - "20201121211111111012202022201210001220122121211010121011010020110121220201212002010222011001111012100011010212110021202021102112221012110011", - "02022222111111110112020112011200022102212222110102210110100101102211201211220020002120110011110221100110002121100222120211021112010112220101"), + 'K': GF(3), + 'M': ("10111011111111101110101110111100111011111011101111101001001111011011011111100100111101000111101111101100011011001111101110111110101111111001", "01220121111211011101011101112101220022120121011222010110011010120110112112001101021010101111012211011000020110012221212101011101211122020011", "22102021112110111120211021122012100012202220112110101200110101202102122120011110020201211110021210110000101200121222122010211022211210110101", "11010221121101111102210221220221000111011101121102012101101012012022222000211200202012211100111201200001122001211011120102110212212102121001", "20201121211111111012202022201210001220122121211010121011010020110121220201212002010222011001111012100011010212110021202021102112221012110011", "02022222111111110112020112011200022102212222110102210110100101102211201211220020002120110011110221100110002121100222120211021112010112220101"), 'source': "Found by Axel Kohnert [Koh2007]_ and shared by Alfred Wassermann.", }, { - 'n' : 98, - 'k' : 6, + 'n': 98, + 'k': 6, 'w1': 63, 'w2': 72, - 'K' : GF(3), - 'M' : ("10000021022112121121110122000110112002010011100120022110120200120111220220122120012012100201110210", - "01000020121020200200211101202121120002211002210100021021202220112122012212101102010210010221221201", - "00100021001211011111111202120022221002201111021101021212210122101020121111002000210000101222202000", - "00010022122200222202201212211112001102200112202202121201211212010210202001222120000002110021000110", - "00001021201002010011020210221221012112200012020011201200111021021102212120211102012002011201210221", - "00000120112212122122202110022202210010200022002120112200101002202221111102110100210212001022201202"), + 'K': GF(3), + 'M': ("10000021022112121121110122000110112002010011100120022110120200120111220220122120012012100201110210", "01000020121020200200211101202121120002211002210100021021202220112122012212101102010210010221221201", "00100021001211011111111202120022221002201111021101021212210122101020121111002000210000101222202000", "00010022122200222202201212211112001102200112202202121201211212010210202001222120000002110021000110", "00001021201002010011020210221221012112200012020011201200111021021102212120211102012002011201210221", "00000120112212122122202110022202210010200022002120112200101002202221111102110100210212001022201202"), 'source': "Shared by Eric Chen [ChenDB]_.", }, { - 'n' : 84, - 'k' : 6, + 'n': 84, + 'k': 6, 'w1': 54, 'w2': 63, - 'K' : GF(3), - 'M' : ("100000210221121211211212100002020022102220010202100220112211111022012202220001210020", - "010000201210202002002200010022222022012112111222010212120102222221210102112001001022", - "001000210012110111111202101021212221000101021021021211021221000111100202101200010122", - "000100221222002222022202010121111210202200012001222011212000211200122202100120211002", - "000010212010020100110002001011101112122110211102212121200111102212021122100010201120", - "000001201122121221222212000110100102011101201012001102201222221110211011100001200102"), + 'K': GF(3), + 'M': ("100000210221121211211212100002020022102220010202100220112211111022012202220001210020", "010000201210202002002200010022222022012112111222010212120102222221210102112001001022", "001000210012110111111202101021212221000101021021021211021221000111100202101200010122", "000100221222002222022202010121111210202200012001222011212000211200122202100120211002", "000010212010020100110002001011101112122110211102212121200111102212021122100010201120", "000001201122121221222212000110100102011101201012001102201222221110211011100001200102"), 'source': "Shared by Eric Chen [ChenDB]_.", }, { - 'n' : 56, - 'k' : 6, + 'n': 56, + 'k': 6, 'w1': 36, 'w2': 45, - 'K' : GF(3), - 'M' : ("10000021022112022210202200202122221120200112100200111102", - "01000020121020221101202120220001110202220110010222122212", - "00100021001211211020022112222122002210122100101222020020", - "00010022122200010012221111121001121211212002110020010101", - "00001021201002220211121011010222000111021002011201112112", - "00000120112212111201011001002111121101002212001022222010"), + 'K': GF(3), + 'M': ("10000021022112022210202200202122221120200112100200111102", "01000020121020221101202120220001110202220110010222122212", "00100021001211211020022112222122002210122100101222020020", "00010022122200010012221111121001121211212002110020010101", "00001021201002220211121011010222000111021002011201112112", "00000120112212111201011001002111121101002212001022222010"), 'source': "Shared by Eric Chen [ChenDB]_.", }, { - 'n' : 65, - 'k' : 4, + 'n': 65, + 'k': 4, 'w1': 50, 'w2': 55, - 'K' : GF(5), - 'M' : ("10004323434444234221223441130101034431234004441141003110400203240", - "01003023101220331314013121123212111200011403221341101031340421204", - "00104120244011212302124203142422240001230144213220111213034240310", - "00012321211123213343321143204040211243210011144140014401003023101"), + 'K': GF(5), + 'M': ("10004323434444234221223441130101034431234004441141003110400203240", "01003023101220331314013121123212111200011403221341101031340421204", "00104120244011212302124203142422240001230144213220111213034240310", "00012321211123213343321143204040211243210011144140014401003023101"), 'source': "Shared by Eric Chen [ChenDB]_.", }, { - 'n' : 52, - 'k' : 4, + 'n': 52, + 'k': 4, 'w1': 40, 'w2': 45, - 'K' : GF(5), - 'M' : ("1000432343444423422122344123113041011022221414310431", - "0100302310122033131401312133032331123141114414001300", - "0010412024401121230212420301411224123332332300210011", - "0001232121112321334332114324420140440343341412401244"), + 'K': GF(5), + 'M': ("1000432343444423422122344123113041011022221414310431", "0100302310122033131401312133032331123141114414001300", "0010412024401121230212420301411224123332332300210011", "0001232121112321334332114324420140440343341412401244"), 'source': "Shared by Eric Chen [ChenDB]_.", }, { - 'n' : 39, - 'k' : 4, + 'n': 39, + 'k': 4, 'w1': 30, 'w2': 35, - 'K' : GF(5), - 'M' : ("111111111111111111111111111111000000000", - "111111222222333333444444000000111111000", - "223300133440112240112240133440123400110", - "402340414201142301132013234230044330401"), + 'K': GF(5), + 'M': ("111111111111111111111111111111000000000", "111111222222333333444444000000111111000", "223300133440112240112240133440123400110", "402340414201142301132013234230044330401"), 'source': "From Bouyukliev and Simonis ([BS2003]_, Theorem 4.1)", }, { - 'n' : 55, - 'k' : 5, + 'n': 55, + 'k': 5, 'w1': 36, 'w2': 45, - 'K' : GF(3), - 'M' : ("1000010122200120121002211022111101011212112022022020002", - "0100011101120102100102202121022211112000020211221222002", - "0010021021222220122011212220021121100021220002100102201", - "0001012221012012100200102211110211121211201002202000222", - "0000101222101201210020110221111020112121120120220200022"), + 'K': GF(3), + 'M': ("1000010122200120121002211022111101011212112022022020002", "0100011101120102100102202121022211112000020211221222002", "0010021021222220122011212220021121100021220002100102201", "0001012221012012100200102211110211121211201002202000222", "0000101222101201210020110221111020112121120120220200022"), 'source': "Shared by Eric Chen [ChenDB]_.", }, { - 'n' : 126, - 'k' : 6, + 'n': 126, + 'k': 6, 'w1': 81, 'w2': 90, - 'K' : GF(3), - 'M' : ("100000210221121211211101220021210000100011020200201101121021122102020111100122122221120200110001010222000021110110011211110210", - "010000201210202002002111012020001001110012222220221211200120201212222102210100001110202220121001110211200120221121012001221201", - "001000210012110111111112021220210102211012212122200222212000112220212011021102122002210122122101120210120100102212112112202000", - "000100221222002222022012122120201012021112211112111120010221100121011012202201001121211212002211120210012201120021222121000110", - "000010212010020100110202102200200102002122111011112210121010202111121212020010222000111021000222122210001011222102100121210221", - "000001201122121221222021100221200012000220101001022022100122112010102222002122111121101002200020221110000122202000221222201202"), + 'K': GF(3), + 'M': ("100000210221121211211101220021210000100011020200201101121021122102020111100122122221120200110001010222000021110110011211110210", "010000201210202002002111012020001001110012222220221211200120201212222102210100001110202220121001110211200120221121012001221201", "001000210012110111111112021220210102211012212122200222212000112220212011021102122002210122122101120210120100102212112112202000", "000100221222002222022012122120201012021112211112111120010221100121011012202201001121211212002211120210012201120021222121000110", "000010212010020100110202102200200102002122111011112210121010202111121212020010222000111021000222122210001011222102100121210221", "000001201122121221222021100221200012000220101001022022100122112010102222002122111121101002200020221110000122202000221222201202"), 'source': "Shared by Eric Chen [ChenDB]_.", }, { - 'n' : 154, - 'k' : 6, + 'n': 154, + 'k': 6, 'w1': 99, 'w2': 108, - 'K' : GF(3), - 'M' : ("10000021022112121121110122002121000010001102020020110112102112202221021020201" + - "20202212102220222022222110122210022201211222111110211101121002011102101111002", - "01000020121020200200211101202000100111001222222022121120012020122110122122221" + - "02222102012112111221111021101101021121002001022221202211100102212212010222102", - "00100021001211011111111202122021010221101221212220022221200011221102002202120" + - "20121121000101000111020212200020121210011112210001001022001012222020000100212", - "00010022122200222202201212212020101202111221111211112001022110001001221210110" + - "12211020202200222000021101010212001022212020002112011200021100210001100121020", - "00001021201002010011020210220020010200212211101111221012101020222021111111212" + - "11120012122110211222201220220201222200102101111020112221020112012102211120101", - "00000120112212122122202110022120001200022010100102202210012211211120100101022" + - "01011212011101110111112202111200111021221112222211222020120010222012022220012"), + 'K': GF(3), + 'M': ("10000021022112121121110122002121000010001102020020110112102112202221021020201" + "20202212102220222022222110122210022201211222111110211101121002011102101111002", "01000020121020200200211101202000100111001222222022121120012020122110122122221" + "02222102012112111221111021101101021121002001022221202211100102212212010222102", "00100021001211011111111202122021010221101221212220022221200011221102002202120" + "20121121000101000111020212200020121210011112210001001022001012222020000100212", "00010022122200222202201212212020101202111221111211112001022110001001221210110" + "12211020202200222000021101010212001022212020002112011200021100210001100121020", "00001021201002010011020210220020010200212211101111221012101020222021111111212" + "11120012122110211222201220220201222200102101111020112221020112012102211120101", "00000120112212122122202110022120001200022010100102202210012211211120100101022" + "01011212011101110111112202111200111021221112222211222020120010222012022220012"), 'source': "Shared by Eric Chen [ChenDB]_.", }, { - 'n' : 198, - 'k' : 10, + 'n': 198, + 'k': 10, 'w1': 96, 'w2': 112, - 'K' : GF(2), - 'M' : ("1000000000111111101010000100011001111101101010010010011110001101111001101100111000111101010101110011" + - "11110010100111101001001100111101011110111100101101110100111100011111011011100111110010100110110000", - "0100000000010110011100100010101010101111011010001001010110011010101011011101000110000001101101010110" + - "10110111110101000000011011001100010111110001001011011100111100100000110001011001110110011101011000", - "0010000000011100111110111011000011010100100011110000001100011011101111001010001100110110000001111000" + - "11000000101011010111110101000111110010011011101110000010110100000011100010011111100100111101010010", - "0001000000001111100010000000100101010001110111100010010010010111000100101100010001001110111101110100" + - "10010101101100110011010011101100110100100011011101100000110011110011111000000010110101011111101111", - "0000100000110010010000010110000111010011010101000010110100101010011011000011001100001110011011110001" + - "11101000010000111101101100111100001011010010111011100101101001111000100011000010110111111111011100", - "0000010000110100111001111011010000101110001011100010010010010111100101011001011011100110101110100001" + - "01101010110010100011000101111100100001110111001001001001001100001101110110000110101010011010101101", - "0000001000011011110010110100010010001100000011001000011101000110001101001000110110010101011011001111" + - "01111111010011111010100110011001110001001000001110000110111011010000011101001110111001011011001011", - "0000000100111001101011110010111100100001010100100110001100100110010101111001100101101001000101011000" + - "10001001111101011101001001010111010011011101010011010000101010011001010110011110010000011011111001", - "0000000010101011010101010101011100111101111110100011011001001010111101100111010110100101100110101100" + - "00000001100011110110010101100001000000010100001101111011111000110001100101101010000001110101011100", - "0000000001101100111101011000010000000011010100000110101010011010100111100001000011010011011101110111" + - "01110111011110101100100100110110011100001001000001010011010010010111110011101011101001101101011010"), + 'K': GF(2), + 'M': ( + "1000000000111111101010000100011001111101101010010010011110001101111001101100111000111101010101110011" + "11110010100111101001001100111101011110111100101101110100111100011111011011100111110010100110110000", + "0100000000010110011100100010101010101111011010001001010110011010101011011101000110000001101101010110" + "10110111110101000000011011001100010111110001001011011100111100100000110001011001110110011101011000", + "0010000000011100111110111011000011010100100011110000001100011011101111001010001100110110000001111000" + "11000000101011010111110101000111110010011011101110000010110100000011100010011111100100111101010010", + "0001000000001111100010000000100101010001110111100010010010010111000100101100010001001110111101110100" + "10010101101100110011010011101100110100100011011101100000110011110011111000000010110101011111101111", + "0000100000110010010000010110000111010011010101000010110100101010011011000011001100001110011011110001" + "11101000010000111101101100111100001011010010111011100101101001111000100011000010110111111111011100", + "0000010000110100111001111011010000101110001011100010010010010111100101011001011011100110101110100001" + "01101010110010100011000101111100100001110111001001001001001100001101110110000110101010011010101101", + "0000001000011011110010110100010010001100000011001000011101000110001101001000110110010101011011001111" + "01111111010011111010100110011001110001001000001110000110111011010000011101001110111001011011001011", + "0000000100111001101011110010111100100001010100100110001100100110010101111001100101101001000101011000" + "10001001111101011101001001010111010011011101010011010000101010011001010110011110010000011011111001", + "0000000010101011010101010101011100111101111110100011011001001010111101100111010110100101100110101100" + "00000001100011110110010101100001000000010100001101111011111000110001100101101010000001110101011100", + "0000000001101100111101011000010000000011010100000110101010011010100111100001000011010011011101110111" + "01110111011110101100100100110110011100001001000001010011010010010111110011101011101001101101011010", + ), 'source': "Shared by Eric Chen [ChenDB]_.", }, { - 'n' : 219, - 'k' : 9, + 'n': 219, + 'k': 9, 'w1': 96, 'w2': 112, - 'K' : GF(2), - 'M' : ("10100011001110100010100010010000100100001011110010001010011000000001101011110011001001000010011110111011111" + - "0001001010110110110111001100111100011011101000000110101110001010100011110011111111110111010100101011000101111111", - "01100010110101110100001000010110001010010010011000111101111001011101000011101011100111111110001100000111010" + - "1101001000110001111011001100101011110101011110010001101011110000100000101101100010110100001111001100110011001111", - "00010010001001011011001110011101111110000000101110101000110110011001110101011011101011011011000010010011111" + - "1110110100111111000000110011101101000000001010000000011000111111100101100001110011110001110011110110100111100001", - "00001000100010101110101110011100010101110011010110000001111111100111010000101110001010100100000001011010111" + - "1001001000000011000011001100100100111010000000001010111001001100100101011110001100110001000000111001100100100111", - "00000101010100010101101110011101001000101110000000000111101100011000000001110100000001011010101001111110110" + - "0010110111100111000000110011110110101101110000001111100001010001100101100001110011110001101101000000000000100001", - "00000000000000000000010000011101011100100010000110110100101011001011001100000001011000101010100111000111101" + - "0011100011011011011111100010011100010111101001011001001101100010011010001011010110001110100001001111110010100100", - "00000000000000000000000001011010110110101111010110101001001001000101010000000000001011000011000010100100110" + - "0000110000111101100010000111111111101101001010110000111111101110101011010010010001011101110011111001100100101110", - "00000000000000000000000000110111101011110010101110000110010010100010001010000000010100011000101000010011000" + - "0110000111100110100001001011111111111010110000001010111111110011110110001100100010101011101101110110011000110110", - "00000000000000000000000000000000000000000000000001111111111111111111111110000001111111111111111111111111111" + - "1111111100000000000011111111111111000000111111111111111111000000000000111111111111000000000000000000111111000110"), + 'K': GF(2), + 'M': ( + "10100011001110100010100010010000100100001011110010001010011000000001101011110011001001000010011110111011111" + "0001001010110110110111001100111100011011101000000110101110001010100011110011111111110111010100101011000101111111", + "01100010110101110100001000010110001010010010011000111101111001011101000011101011100111111110001100000111010" + "1101001000110001111011001100101011110101011110010001101011110000100000101101100010110100001111001100110011001111", + "00010010001001011011001110011101111110000000101110101000110110011001110101011011101011011011000010010011111" + "1110110100111111000000110011101101000000001010000000011000111111100101100001110011110001110011110110100111100001", + "00001000100010101110101110011100010101110011010110000001111111100111010000101110001010100100000001011010111" + "1001001000000011000011001100100100111010000000001010111001001100100101011110001100110001000000111001100100100111", + "00000101010100010101101110011101001000101110000000000111101100011000000001110100000001011010101001111110110" + "0010110111100111000000110011110110101101110000001111100001010001100101100001110011110001101101000000000000100001", + "00000000000000000000010000011101011100100010000110110100101011001011001100000001011000101010100111000111101" + "0011100011011011011111100010011100010111101001011001001101100010011010001011010110001110100001001111110010100100", + "00000000000000000000000001011010110110101111010110101001001001000101010000000000001011000011000010100100110" + "0000110000111101100010000111111111101101001010110000111111101110101011010010010001011101110011111001100100101110", + "00000000000000000000000000110111101011110010101110000110010010100010001010000000010100011000101000010011000" + "0110000111100110100001001011111111111010110000001010111111110011110110001100100010101011101101110110011000110110", + "00000000000000000000000000000000000000000000000001111111111111111111111110000001111111111111111111111111111" + "1111111100000000000011111111111111000000111111111111111111000000000000111111111111000000000000000000111111000110", + ), 'source': "Shared by Eric Chen [ChenDB]_.", }, { - 'n' : 73, - 'k' : 9, + 'n': 73, + 'k': 9, 'w1': 32, 'w2': 40, - 'K' : GF(2), - 'M' : ("1010010100000010100000101010001100110101101101000010110010100100111011101", - "0110000110000101101111001101000100111111101011011101110010110001100111100", - "0001010000000001111111011010100101001111011010101100001010000001110100001", - "0000100100000001111111100111000011110011110101000001010110000001011010001", - "0000001010000001111110111100011000111100101110010010101100000001101001001", - "0000000001000111001010110010011001101001011010110110011001010111100010010", - "0000000000100100011000100100111100001100101111010001011011111000110011110", - "0000000000010111001100101011111110101010000000000100111110000001111111100", - "0000000000001011100001000011011010110001110101101100001100101110101110110"), + 'K': GF(2), + 'M': ("1010010100000010100000101010001100110101101101000010110010100100111011101", "0110000110000101101111001101000100111111101011011101110010110001100111100", "0001010000000001111111011010100101001111011010101100001010000001110100001", "0000100100000001111111100111000011110011110101000001010110000001011010001", "0000001010000001111110111100011000111100101110010010101100000001101001001", "0000000001000111001010110010011001101001011010110110011001010111100010010", "0000000000100100011000100100111100001100101111010001011011111000110011110", "0000000000010111001100101011111110101010000000000100111110000001111111100", "0000000000001011100001000011011010110001110101101100001100101110101110110"), 'source': "Shared by Eric Chen [ChenDB]_.", }, { - 'n' : 70, - 'k' : 9, + 'n': 70, + 'k': 9, 'w1': 32, 'w2': 40, - 'K' : GF(2), - 'M' : ("0100011110111000001011010110110111100010001000001000001001010110101101", - "1000111101110000000110101111101111000100010000010000000010101111001011", - "0001111011100000011101011101011110011000100000100000000101011100010111", - "0011110101000000111010111010111100110001000011000000001010111000101101", - "0111101000000001110101110111111001100010000100000000010101110011001011", - "1111010000000011101011101101110011010100001000000000101011100100010111", - "1110100010000111000111011011100110111000010000000001000111001010101101", - "1101000110001110001110110101001101110000100010000010001110010101001011", - "1010001110011100001101101010011011110001000100000100001100101010010111"), + 'K': GF(2), + 'M': ("0100011110111000001011010110110111100010001000001000001001010110101101", "1000111101110000000110101111101111000100010000010000000010101111001011", "0001111011100000011101011101011110011000100000100000000101011100010111", "0011110101000000111010111010111100110001000011000000001010111000101101", "0111101000000001110101110111111001100010000100000000010101110011001011", "1111010000000011101011101101110011010100001000000000101011100100010111", "1110100010000111000111011011100110111000010000000001000111001010101101", "1101000110001110001110110101001101110000100010000010001110010101001011", "1010001110011100001101101010011011110001000100000100001100101010010111"), 'source': "Found by Axel Kohnert [Koh2007]_ and shared by Alfred Wassermann.", }, { - 'n' : 85, - 'k' : 8, + 'n': 85, + 'k': 8, 'w1': 40, 'w2': 48, - 'K' : GF(2), - 'M' : ("1000000010011101010001000011100111000111111010110001101101000110010011001101011100001", - "0100000011010011111001100010010100100100000111101001011011100101011010101011110010001", - "0010000011110100101101110010101101010101111001000101000000110100111110011000100101001", - "0001000011100111000111111010110001101101000110010011001101011100001100000001001110101", - "0000100011101110110010111110111111110001011001111000001011101000010101001101111011011", - "0000010011101010001000011100111000111111010110001101101000110010011001101011100001100", - "0000001001110101000100001110011100011111101011000110110100011001001100110101110000110", - "0000000100111010100010000111001110001111110101100011011010001100100110011010111000011"), + 'K': GF(2), + 'M': ("1000000010011101010001000011100111000111111010110001101101000110010011001101011100001", "0100000011010011111001100010010100100100000111101001011011100101011010101011110010001", "0010000011110100101101110010101101010101111001000101000000110100111110011000100101001", "0001000011100111000111111010110001101101000110010011001101011100001100000001001110101", "0000100011101110110010111110111111110001011001111000001011101000010101001101111011011", "0000010011101010001000011100111000111111010110001101101000110010011001101011100001100", "0000001001110101000100001110011100011111101011000110110100011001001100110101110000110", "0000000100111010100010000111001110001111110101100011011010001100100110011010111000011"), 'source': "Shared by Eric Chen [ChenDB]_.", }, { - 'n' : 15, - 'k' : 4, + 'n': 15, + 'k': 4, 'w1': 9, 'w2': 12, - 'K' : GF(3), - 'M' : ("100022021001111", - "010011211122000", - "001021112100011", - "000110120222220"), + 'K': GF(3), + 'M': ("100022021001111", "010011211122000", "001021112100011", "000110120222220"), 'source': "Shared by Eric Chen [ChenDB]_.", }, { - 'n' : 34, - 'k' : 4, + 'n': 34, + 'k': 4, 'w1': 24, 'w2': 28, - 'K' : GF(4,name='x'), - 'M' : [[1,0,0,0, 1,'x', 'x','x^2', 1, 0, 'x','x', 0, 1,'x^2','x','x','x^2','x^2','x^2','x', 'x','x^2','x^2','x^2', 1,'x^2','x',1,0, 1, 'x','x^2', 1], - [0,1,0,0,'x','x', 1,'x^2', 1, 1,'x^2', 1,'x', 'x', 0, 0, 1, 0, 'x', 'x', 0, 1,'x^2', 'x', 'x', 1, 0, 0,0,1,'x', 'x','x^2', 1], - [0,0,1,0, 1, 0, 0, 'x','x', 1,'x^2', 1, 1,'x^2', 1,'x','x', 'x','x^2', 1, 0, 'x', 'x', 0, 1,'x^2', 'x','x',1,0, 0, 0, 1, 'x'], - [0,0,0,1,'x','x','x^2', 1, 0,'x', 'x', 0, 1,'x^2', 'x','x', 1,'x^2','x^2', 'x','x','x^2','x^2','x^2', 1,'x^2', 'x', 1,0,1,'x','x^2', 1,'x^2']], + 'K': GF(4, name='x'), + 'M': [[1, 0, 0, 0, 1, 'x', 'x', 'x^2', 1, 0, 'x', 'x', 0, 1, 'x^2', 'x', 'x', 'x^2', 'x^2', 'x^2', 'x', 'x', 'x^2', 'x^2', 'x^2', 1, 'x^2', 'x', 1, 0, 1, 'x', 'x^2', 1], [0, 1, 0, 0, 'x', 'x', 1, 'x^2', 1, 1, 'x^2', 1, 'x', 'x', 0, 0, 1, 0, 'x', 'x', 0, 1, 'x^2', 'x', 'x', 1, 0, 0, 0, 1, 'x', 'x', 'x^2', 1], [0, 0, 1, 0, 1, 0, 0, 'x', 'x', 1, 'x^2', 1, 1, 'x^2', 1, 'x', 'x', 'x', 'x^2', 1, 0, 'x', 'x', 0, 1, 'x^2', 'x', 'x', 1, 0, 0, 0, 1, 'x'], [0, 0, 0, 1, 'x', 'x', 'x^2', 1, 0, 'x', 'x', 0, 1, 'x^2', 'x', 'x', 1, 'x^2', 'x^2', 'x', 'x', 'x^2', 'x^2', 'x^2', 1, 'x^2', 'x', 1, 0, 1, 'x', 'x^2', 1, 'x^2']], 'source': "Shared by Eric Chen [ChenDB]_.", }, { - 'n' : 121, - 'k' : 5, + 'n': 121, + 'k': 5, 'w1': 88, 'w2': 96, - 'K' : GF(4,name='x'), - 'M' : [map({'0':0,'1':1,'a':'x','b':'x**2'}.get,x) for x in - ["11b1aab0a0101010b1b0a0bab0a0a0b011a0a1b1aab0b1a0b1bab0b0a0b1b011a011a011a011b0b1b0b0b0b0aab1a1b0aab0b010aab1a010b0a1a1aab", + 'K': GF(4, name='x'), + 'M': [ + map({'0': 0, '1': 1, 'a': 'x', 'b': 'x**2'}.get, x) + for x in [ + "11b1aab0a0101010b1b0a0bab0a0a0b011a0a1b1aab0b1a0b1bab0b0a0b1b011a011a011a011b0b1b0b0b0b0aab1a1b0aab0b010aab1a010b0a1a1aab", "01100110011aa0011aabb0011bb11aabb00bb00aabb11bb11aa0011aabb00aabb00aabb0011bb0011aa00aabb0011aa11aabb00aabb0011aabb00aabb", "000111100000011111111aaaaaabbbbbb0000111111aaaabbbb00000000111111aaaaaabbbbbb000000111111aaaaaa000000111111aaaaaaaabbbbbb", "00000001111111111111111111111111100000000000000000011111111111111111111111111aaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbb", "0000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", - ]], - 'source' : "From [Di2000]_", + ] + ], + 'source': "From [Di2000]_", }, { - 'n' : 132, - 'k' : 5, + 'n': 132, + 'k': 5, 'w1': 96, 'w2': 104, - 'K' : GF(4,name='x'), - 'M' : [map({'0':0,'1':1,'a':'x','b':'x**2'}.get,x) for x in - ["aab1a1ab0b11b1a10b0b101ab00ab1b01ab01abbabab10a1b0a0101a1a1a01ab1b0101ab01ba00bb1bb111b11b1011b1ab0abb1b01abab00abab0aab01001ab0a11b", + 'K': GF(4, name='x'), + 'M': [ + map({'0': 0, '1': 1, 'a': 'x', 'b': 'x**2'}.get, x) + for x in [ + "aab1a1ab0b11b1a10b0b101ab00ab1b01ab01abbabab10a1b0a0101a1a1a01ab1b0101ab01ba00bb1bb111b11b1011b1ab0abb1b01abab00abab0aab01001ab0a11b", "10011b0011abb001aaaab00001ab011aaaabbbb1aabb011aabb001aabb01a00abb001111bbb01aab001ab001bb011aa011aaab001111aab00abb0011aab000011abb", "011111000000011111aaabbbbbbb0000000000011111aaaaaaabbbbbbb00011111aaaaaaaaabbbbb0000011111aaaaabbbbbbb00000000011111aaaaaaabbbbbbbbb", "00000011111111111111111111110000000000000000000000000000001111111111111111111111aaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", - ]], - 'source' : "From [Di2000]_", + ] + ], + 'source': "From [Di2000]_", }, { - 'n' : 143, - 'k' : 5, + 'n': 143, + 'k': 5, 'w1': 104, 'w2': 112, - 'K' : GF(4,name='x'), - 'M' : [map({'0':0,'1':1,'a':'x','b':'x**2'}.get,x) for x in - ["1a01a01ab0aaab0bab0a1ab0bab0ab0a01a0a011aab00a01a1a011b00101b1a1bb0a0abab00a1a01a1b11a010b01ab1ab0a011a01ab00a10b0a01babab1a1ba011ab0a1ab0a0b01", + 'K': GF(4, name='x'), + 'M': [ + map({'0': 0, '1': 1, 'a': 'x', 'b': 'x**2'}.get, x) + for x in [ + "1a01a01ab0aaab0bab0a1ab0bab0ab0a01a0a011aab00a01a1a011b00101b1a1bb0a0abab00a1a01a1b11a010b01ab1ab0a011a01ab00a10b0a01babab1a1ba011ab0a1ab0a0b01", "0011abbbb001aabb00aabbb0011aaabb00011bb0011abb000aabb001aa00b11aab00111aa0110011abb0aabb001111aaabb0011aaaab001bb00111aa0011aab11aaabb00011aabb", "11111111100000001111111aaaaaaaaabbbbbbb00000001111111aaaaabbb000001111111aaabbbbbbb0000011111111111aaaaaaaaabbbbb00000001111111aaaaaaabbbbbbbbb", "00000000011111111111111111111111111111100000000000000000000001111111111111111111111aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "00000000000000000000000000000000000000011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", - ]], - 'source' : "From [Di2000]_", + ] + ], + 'source': "From [Di2000]_", }, { - 'n' : 168, - 'k' : 6, + 'n': 168, + 'k': 6, 'w1': 108, 'w2': 117, - 'K' : GF(3), - 'M' : ["101212212122202012010102120101112012121001201012120220122112001121201201201201010020012201001201201201202120121122012021201221021110200212121011211002012220000122201201", - "011100122001200111220011220020011222001200022000220012220122011220011101122012012001222010122200012011120112220112000120120012002012201122001220012122000201212001211211", - "000011111000011111112000001112000000111122222000001111112222000001111122222000111222222001111122222000001111112222000001112222000111122222000001111222000011122000011122", - "000000000111111111111000000000111111111111111222222222222222000000000000000111111111111222222222222000000000000000111111111111222222222222000000000000111111111222222222", - "000000000000000000000111111111111111111111111111111111111111000000000000000000000000000000000000000111111111111111111111111111111111111111222222222222222222222222222222", - "000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"], - 'source' : "From [Di2000]_", + 'K': GF(3), + 'M': [ + "101212212122202012010102120101112012121001201012120220122112001121201201201201010020012201001201201201202120121122012021201221021110200212121011211002012220000122201201", + "011100122001200111220011220020011222001200022000220012220122011220011101122012012001222010122200012011120112220112000120120012002012201122001220012122000201212001211211", + "000011111000011111112000001112000000111122222000001111112222000001111122222000111222222001111122222000001111112222000001112222000111122222000001111222000011122000011122", + "000000000111111111111000000000111111111111111222222222222222000000000000000111111111111222222222222000000000000000111111111111222222222222000000000000111111111222222222", + "000000000000000000000111111111111111111111111111111111111111000000000000000000000000000000000000000111111111111111111111111111111111111111222222222222222222222222222222", + "000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", + ], + 'source': "From [Di2000]_", }, ] # Build actual matrices. for code in data: - code['M'] = Matrix(code['K'],[list(R) for R in code['M']]) + code['M'] = Matrix(code['K'], [list(R) for R in code['M']]) -DB_INDEX = (".. csv-table::\n" - " :class: contentstable\n" - " :widths: 7,7,7,7,7,50\n" - " :delim: @\n\n") +DB_INDEX = ".. csv-table::\n" " :class: contentstable\n" " :widths: 7,7,7,7,7,50\n" " :delim: @\n\n" -data.sort(key=lambda x:(x['K'].cardinality(),x['k'],x['n'])) +data.sort(key=lambda x: (x['K'].cardinality(), x['k'], x['n'])) for x in data: - s = " `q={}` @ `n={}` @ `k={}` @ `w_1={}` @ `w_2={}` @ {}\n".format(x['K'].cardinality(),x['n'],x['k'],x['w1'],x['w2'],x.get('source','')) + s = " `q={}` @ `n={}` @ `k={}` @ `w_1={}` @ `w_2={}` @ {}\n".format(x['K'].cardinality(), x['n'], x['k'], x['w1'], x['w2'], x.get('source', '')) DB_INDEX += s __doc__ = __doc__.format(DB_INDEX=DB_INDEX) diff --git a/src/sage/combinat/SJT.py b/src/sage/combinat/SJT.py index 3b3aef5aebc..f64e3da1262 100644 --- a/src/sage/combinat/SJT.py +++ b/src/sage/combinat/SJT.py @@ -89,6 +89,7 @@ class SJT(CombinatorialElement): sage: s = s.next(); s False """ + def __init__(self, l, directions=None) -> None: r""" Transpose two elements at positions ``a`` and ``b`` in ``perm`` and @@ -142,10 +143,8 @@ def __init__(self, l, directions=None) -> None: return if directions is None: - if not all(l[i] <= l[i+1] for i in range(self._n - 1)): - raise ValueError("no internal state directions were given for " - "non-identity starting permutation for " - "Steinhaus-Johnson-Trotter algorithm") + if not all(l[i] <= l[i + 1] for i in range(self._n - 1)): + raise ValueError("no internal state directions were given for " "non-identity starting permutation for " "Steinhaus-Johnson-Trotter algorithm") self._directions = [-1] * self._n # The first element has null direction. @@ -213,8 +212,7 @@ def next(self): # If this element has null direction, find the largest whose is # non-null. if direction == 0: - xi = self.__idx_largest_element_non_zero_direction(perm, - directions) + xi = self.__idx_largest_element_non_zero_direction(perm, directions) if xi is None: # We have created every permutation. Detected when all elements # have null direction. @@ -226,14 +224,12 @@ def next(self): # Proceed to transpose elements and corresponding directions. perm[xi], perm[new_pos] = perm[new_pos], perm[xi] - directions[xi], directions[new_pos] = \ - directions[new_pos], directions[xi] + directions[xi], directions[new_pos] = directions[new_pos], directions[xi] # If the transposition results in the largest element being on one edge # or if the following element in its direction is greater than it, then # then set its direction to 0 - if (new_pos == 0 or new_pos == self._n - 1 or - perm[new_pos + direction] > selected_elt): + if new_pos == 0 or new_pos == self._n - 1 or perm[new_pos + direction] > selected_elt: directions[new_pos] = 0 # After each permutation, update each element's direction. If diff --git a/src/sage/combinat/abstract_tree.py b/src/sage/combinat/abstract_tree.py index 61531907df8..f52abe21e9d 100644 --- a/src/sage/combinat/abstract_tree.py +++ b/src/sage/combinat/abstract_tree.py @@ -61,6 +61,7 @@ - Florent Hivert (2010-2011): initial revision - Frédéric Chapoton (2011): contributed some methods """ + import itertools from sage.misc.latex import latex @@ -197,8 +198,7 @@ def pre_order_traversal_iter(self): if self.is_empty(): return yield self - yield from itertools.chain(*[c.pre_order_traversal_iter() - for c in self]) + yield from itertools.chain(*[c.pre_order_traversal_iter() for c in self]) def iterative_pre_order_traversal(self, action=None): r""" @@ -270,8 +270,10 @@ def iterative_pre_order_traversal(self, action=None): if self.is_empty(): return if action is None: + def action(x): return None + stack = [] stack.append(self) while stack: @@ -385,8 +387,10 @@ def pre_order_traversal(self, action=None): 7 """ if action is None: + def action(x): return None + for node in self.pre_order_traversal_iter(): action(node) @@ -480,8 +484,7 @@ def post_order_traversal_iter(self): """ if self.is_empty(): return - yield from itertools.chain(*[c.post_order_traversal_iter() - for c in self]) + yield from itertools.chain(*[c.post_order_traversal_iter() for c in self]) yield self def post_order_traversal(self, action=None): @@ -552,8 +555,10 @@ def post_order_traversal(self, action=None): 7 """ if action is None: + def action(x): return None + for node in self.post_order_traversal_iter(): action(node) @@ -628,8 +633,10 @@ def iterative_post_order_traversal(self, action=None): if self.is_empty(): return if action is None: + def action(x): return None + stack = [self] while stack: node = stack[-1] @@ -719,17 +726,25 @@ def contour_traversal(self, first_action=None, middle_action=None, final_action= 7 """ if first_action is None: + def first_action(x): return + if middle_action is None: + def middle_action(x): return + if final_action is None: + def final_action(x): return + if leaf_action is None: + def leaf_action(x): return + stack = [] stack.append(self) corners = [0, 0] @@ -823,8 +838,10 @@ def breadth_first_order_traversal(self, action=None): if self.is_empty(): return if action is None: + def action(x): return None + queue = [] queue.append(self) while queue: @@ -1069,8 +1086,7 @@ def number_of_nodes_to_the_right(self, path): depth = len(path) if depth == 0: return Integer(0) - result = sum(son.number_of_nodes_at_depth(depth - 1) - for son in self[path[0] + 1:]) + result = sum(son.number_of_nodes_at_depth(depth - 1) for son in self[path[0] + 1 :]) if path[0] < len(self) and path[0] >= 0: result += self[path[0]].number_of_nodes_to_the_right(path[1:]) return result @@ -1222,8 +1238,7 @@ def count(node): # Using post-order # Thus _node_number is computed for all non-empty subtrees node._node_number = Integer(1) - node._node_number += sum(e._node_number for e in node - if not e.is_empty()) + node._node_number += sum(e._node_number for e in node if not e.is_empty()) self.iterative_post_order_traversal(count) return self._node_number @@ -1350,14 +1365,17 @@ def _ascii_art_(self): / / 14 15 """ + def node_to_str(t): return str(t.label()) if hasattr(t, "label") else "o" if self.is_empty(): from sage.typeset.ascii_art import empty_ascii_art + return empty_ascii_art from sage.typeset.ascii_art import AsciiArt + if len(self) == 0: t_repr = AsciiArt([node_to_str(self)]) t_repr._root = 1 @@ -1388,7 +1406,7 @@ def node_to_str(t): ls_sep += " " * (t_repr._root) + "/" + " " * (t_repr._l - t_repr._root) mid = whitesep + (len(lf_sep) - whitesep) // 2 node = node_to_str(self) - t_repr = AsciiArt([lf_sep[:mid - 1] + node + lf_sep[mid + len(node) - 1:], ls_sep]) * acc + t_repr = AsciiArt([lf_sep[: mid - 1] + node + lf_sep[mid + len(node) - 1 :], ls_sep]) * acc t_repr._root = mid t_repr._baseline = t_repr._h - 1 return t_repr @@ -1469,13 +1487,16 @@ def node_to_str(t): if hasattr(t, "label"): return str(t.label()) return "o" + # other possible choices for nodes would be u"█ ▓ ░ ╋ ╬" if self.is_empty(): from sage.typeset.unicode_art import empty_unicode_art + return empty_unicode_art from sage.typeset.unicode_art import UnicodeArt + if not len(self): t_repr = UnicodeArt([node_to_str(self)]) t_repr._root = 0 @@ -1508,8 +1529,7 @@ def node_to_str(t): ls_sep += " " * (tr._root) + "│" + " " * (tr._l - tr._root) mid = whitesep + (len(lf_sep) - whitesep) // 2 node = node_to_str(self) - lf_sep = (lf_sep[:mid - len(node) // 2] + node + - lf_sep[mid + len(node) - len(node) // 2:]) + lf_sep = lf_sep[: mid - len(node) // 2] + node + lf_sep[mid + len(node) - len(node) // 2 :] t_repr = UnicodeArt([lf_sep, ls_sep]) * acc t_repr._root = mid t_repr._baseline = t_repr._h - 1 @@ -1540,11 +1560,11 @@ def canonical_labelling(self, shift=1): sage: BinaryTree().canonical_labelling() . """ + def aux(tree, LTR, curlabel): mylabel = curlabel[0] curlabel[0] += 1 - newtree = LTR([aux(st, LTR, curlabel) for st in tree], - label=mylabel) + newtree = LTR([aux(st, LTR, curlabel) for st in tree], label=mylabel) return newtree return aux(self, self.parent().labelled_trees(), [shift]) @@ -1675,6 +1695,7 @@ def _latex_(self): def node_to_str(node): return " " + node + " " * (len(space) - 1 - len(node)) + # # TODO:: modify how to create nodes --> new_cmd : \\node[...] in create_node num = [0] @@ -1695,9 +1716,7 @@ def create_node(self): """ name = "".join(chr(ord(x) + 49) for x in str(num[0])) node = cmd + name - nodes.append((name, - (str(self.label()) if hasattr(self, "label") else "")) - ) + nodes.append((name, (str(self.label()) if hasattr(self, "label") else ""))) num[0] += 1 return node, name @@ -1843,8 +1862,7 @@ def pair_nodes_tree(self, nodes, edges, matrix): tmp(self[i], edge, nodes, edges, matrix) # # create the root line - root_line = (spacesep * (nb_of_and + 1) + node_to_str(node) + - sepspace * (matrix[0].count(sep) - nb_of_and - 1)) + root_line = spacesep * (nb_of_and + 1) + node_to_str(node) + sepspace * (matrix[0].count(sep) - nb_of_and - 1) matrix.insert(0, root_line) # add edges from the root edges.append(edge) @@ -1938,15 +1956,14 @@ def odd_nodes_tree(self, nodes, edges, matrix): tmp(self[i], edge, nodes, edges, matrix) # # create the root line - root_line = (spacesep * (nb_of_and) + node_to_str(node) + - sepspace * (matrix[0].count(sep) - nb_of_and)) + root_line = spacesep * (nb_of_and) + node_to_str(node) + sepspace * (matrix[0].count(sep) - nb_of_and) matrix.insert(0, root_line) # add edges from the root edges.append(edge) + if self.is_empty(): empty_tree() - elif len(self) == 0 or all(subtree.is_empty() - for subtree in self): + elif len(self) == 0 or all(subtree.is_empty() for subtree in self): one_node_tree(self) elif not len(self) % 2: pair_nodes_tree(self, nodes, edges, matrix) @@ -1959,9 +1976,7 @@ def odd_nodes_tree(self, nodes, edges, matrix): def make_cmd(nodes): cmds = [] for name, label in nodes: - cmds.append(new_cmd1 + name + new_cmd2 + - name + new_cmd3 + - label + new_cmd4) + cmds.append(new_cmd1 + name + new_cmd2 + name + new_cmd3 + label + new_cmd4) return cmds def make_edges(edges): @@ -1972,19 +1987,8 @@ def make_edges(edges): path += " edge (%s)" % edge[i] all_paths.append(path) return all_paths - return ("{ " + - "".join(make_cmd(nodes)) + - begin_env + - (matrix_begin + - "\\\\ \n".join(matrix) + - matrix_end + - ("\n" + - path_begin + - "\n\t".join(make_edges(edges)) + - path_end if edges else "") - if matrix else "") + - end_env + - "}") + + return "{ " + "".join(make_cmd(nodes)) + begin_env + (matrix_begin + "\\\\ \n".join(matrix) + matrix_end + ("\n" + path_begin + "\n\t".join(make_edges(edges)) + path_end if edges else "") if matrix else "") + end_env + "}" class AbstractClonableTree(AbstractTree): @@ -2528,8 +2532,8 @@ def as_digraph(self): Digraph on 4 vertices """ from sage.graphs.digraph import DiGraph - resu = {self.label(): - [t.label() for t in self if not t.is_empty()]} + + resu = {self.label(): [t.label() for t in self if not t.is_empty()]} resu = DiGraph(resu, format='dict_of_lists') for t in self: if not t.is_empty(): @@ -2537,8 +2541,7 @@ def as_digraph(self): return resu -class AbstractLabelledClonableTree(AbstractLabelledTree, - AbstractClonableTree): +class AbstractLabelledClonableTree(AbstractLabelledTree, AbstractClonableTree): """ Abstract Labelled Clonable Tree. @@ -2681,8 +2684,7 @@ def map_labels(self, f): """ if self.is_empty(): return self - return self.parent()([t.map_labels(f) for t in self], - label=f(self.label())) + return self.parent()([t.map_labels(f) for t in self], label=f(self.label())) def from_hexacode(ch, parent=None, label='@'): @@ -2731,6 +2733,7 @@ def from_hexacode(ch, parent=None, label='@'): """ if parent is None: from sage.combinat.ordered_tree import LabelledOrderedTrees + parent = LabelledOrderedTrees() return _from_hexacode_aux(ch, parent, label)[0] diff --git a/src/sage/combinat/affine_permutation.py b/src/sage/combinat/affine_permutation.py index 4ff20937a68..4147116c105 100644 --- a/src/sage/combinat/affine_permutation.py +++ b/src/sage/combinat/affine_permutation.py @@ -98,8 +98,7 @@ def _repr_(self) -> str: sage: p Type A affine permutation with window [3, -1, 0, 6, 5, 4, 10, 9] """ - return ("Type " + self.parent().cartan_type().letter - + " affine permutation with window " + str(list(self))) + return "Type " + self.parent().cartan_type().letter + " affine permutation with window " + str(list(self)) def __rmul__(self, q) -> AffinePermutation: r""" @@ -311,7 +310,7 @@ def reduced_word(self) -> list[int]: if x.has_descent(i): x = x.apply_simple_reflection_right(i) word.append(i) - i = (i+1) % (self.k+1) + i = (i + 1) % (self.k + 1) word.reverse() return word @@ -327,7 +326,7 @@ def signature(self) -> int: sage: p.signature() 1 """ - return (-1)**self.length() + return (-1) ** self.length() @cached_method def to_weyl_group_element(self): @@ -467,9 +466,9 @@ def value(self, i, base_window=False): 11 """ if base_window: - self[i-1] - window = (i-1) // (self.k+1) - return self[(i-1) % (self.k+1)] + window*(self.k+1) + self[i - 1] + window = (i - 1) // (self.k + 1) + return self[(i - 1) % (self.k + 1)] + window * (self.k + 1) def position(self, i): r""" @@ -484,11 +483,11 @@ def position(self, i): sage: p.position(11) 9 """ - for r in range(self.k+1): - if self[r] % (self.k+1) == i % (self.k+1): + for r in range(self.k + 1): + if self[r] % (self.k + 1) == i % (self.k + 1): # i sits in position i, but some number of windows away. - diff = (i-self[r]) // (self.k+1) - return r + diff*(self.k+1) + 1 + diff = (i - self[r]) // (self.k + 1) + return r + diff * (self.k + 1) + 1 return False def apply_simple_reflection_right(self, i) -> AffinePermutationTypeA: @@ -507,7 +506,7 @@ def apply_simple_reflection_right(self, i) -> AffinePermutationTypeA: sage: p.apply_simple_reflection_right(11) Type A affine permutation with window [3, -1, 6, 0, 5, 4, 10, 9] """ - j = i % (self.k+1) + j = i % (self.k + 1) # Cloning is currently kinda broken, in that caches don't clear which # leads to strangeness with the cloned object. # The clone approach is quite a bit (2x) faster, though, so this should @@ -516,11 +515,11 @@ def apply_simple_reflection_right(self, i) -> AffinePermutationTypeA: l = self[:] if j == 0: a = l[0] - l[0] = l[-1] - (self.k+1) - l[-1] = a + (self.k+1) + l[0] = l[-1] - (self.k + 1) + l[-1] = a + (self.k + 1) else: - a = l[j-1] - l[j-1] = l[j] + a = l[j - 1] + l[j - 1] = l[j] l[j] = a return type(self)(self.parent(), l, check=False) @@ -642,7 +641,7 @@ def flip_automorphism(self) -> AffinePermutationTypeA: Type A affine permutation with window [0, -1, 5, 4, 3, 9, 10, 6] """ # Note: There should be a more combinatorial (ie, faster) way to do this. - w = [(self.k+1-i) % (self.k+1) for i in self.reduced_word()] + w = [(self.k + 1 - i) % (self.k + 1) for i in self.reduced_word()] return self.parent().from_word(w) def promotion(self) -> AffinePermutationTypeA: @@ -660,8 +659,7 @@ def promotion(self) -> AffinePermutationTypeA: l.extend(self[i] + 1 for i in range(self.k)) return type(self)(self.parent(), l) - def maximal_cyclic_factor(self, typ='decreasing', - side='right', verbose=False) -> list: + def maximal_cyclic_factor(self, typ='decreasing', side='right', verbose=False) -> list: r""" For an affine permutation `x`, find the unique maximal subset `A` of the index set such that `x = yd_A` is a reduced product. @@ -705,16 +703,16 @@ def maximal_cyclic_factor(self, typ='decreasing', j = i for _ in range(1, self.k): if (typ[0], side[0]) == ('d', 'r'): - j = (j+1) % (k+1) + j = (j + 1) % (k + 1) if (typ[0], side[0]) == ('i', 'r'): - j = (j-1) % (k+1) + j = (j - 1) % (k + 1) if (typ[0], side[0]) == ('d', 'l'): - j = (j-1) % (k+1) + j = (j - 1) % (k + 1) if (typ[0], side[0]) == ('i', 'l'): - j = (j+1) % (k+1) + j = (j + 1) % (k + 1) if y.has_descent(j, side): y = y.apply_simple_reflection(j, side) - T.append(j % (k+1)) + T.append(j % (k + 1)) if verbose: print(i, T) if len(T) > len(best_T): @@ -830,47 +828,47 @@ def to_lehmer_code(self, typ='decreasing', side='right') -> Composition: True True """ - code = [0 for i in range(self.k+1)] + code = [0 for i in range(self.k + 1)] if typ[0] == 'i' and side[0] == 'r': # Find number of positions to the right of position i with smaller # value than the number in position i. - for i in range(self.k+1): + for i in range(self.k + 1): a = self(i) - for j in range(i+1, i+self.k+1): + for j in range(i + 1, i + self.k + 1): b = self(j) if b < a: - code[i] += (a-b) // (self.k+1) + 1 + code[i] += (a - b) // (self.k + 1) + 1 elif typ[0] == 'd' and side[0] == 'r': # Find number of positions to the left of position i with larger # value than the number in position i. Then cyclically shift # the resulting vector. - for i in range(self.k+1): + for i in range(self.k + 1): a = self(i) - for j in range(i-self.k, i): + for j in range(i - self.k, i): b = self(j) # A small rotation is necessary for the reduced word from # the Lehmer code to match the element. if a < b: - code[i-1] += ((b-a)//(self.k+1)+1) + code[i - 1] += (b - a) // (self.k + 1) + 1 elif typ[0] == 'i' and side[0] == 'l': # Find number of positions to the right of i smaller than i, then # cyclically shift the resulting vector. - for i in range(self.k+1): + for i in range(self.k + 1): pos = self.position(i) - for j in range(pos+1, pos+self.k+1): + for j in range(pos + 1, pos + self.k + 1): b = self(j) # A small rotation is necessary for the reduced word from # the lehmer code to match the element. if b < i: - code[i-1] += (i-b) // (self.k+1) + 1 + code[i - 1] += (i - b) // (self.k + 1) + 1 elif typ[0] == 'd' and side[0] == 'l': # Find number of positions to the left of i larger than i. - for i in range(self.k+1): + for i in range(self.k + 1): pos = self.position(i) - for j in range(pos-self.k, pos): + for j in range(pos - self.k, pos): b = self(j) if b > i: - code[i] += (b-i) // (self.k+1) + 1 + code[i] += (b - i) // (self.k + 1) + 1 return Composition(code) def is_fully_commutative(self) -> bool: @@ -956,8 +954,7 @@ def to_core(self, typ='decreasing', side='right'): """ return self.to_bounded_partition(typ, side).to_core(self.k) - def to_dominant(self, typ='decreasing', - side='right') -> AffinePermutationTypeA: + def to_dominant(self, typ='decreasing', side='right') -> AffinePermutationTypeA: r""" Find the Lehmer code and then sort it. Return the affine permutation with the given sorted Lehmer code. @@ -1043,15 +1040,15 @@ def tableau_of_word(self, w, typ='decreasing', side='right', alpha=None): j = 0 x = self.parent().one() cx = x.to_lehmer_code(typ, side) - n = len(w)-1 + n = len(w) - 1 for i in range(len(w)): if side[0] == 'r': # y=g[w[n-i]]*x - y = x.apply_simple_reflection_left(w[n-i]) + y = x.apply_simple_reflection_left(w[n - i]) else: y = x.apply_simple_reflection_right(w[i]) cy = y.to_lehmer_code(typ, side) - for r in range(self.k+1): + for r in range(self.k + 1): if cy[r] > cx[r]: tab[r].append(label) j += 1 @@ -1064,6 +1061,7 @@ def tableau_of_word(self, w, typ='decreasing', side='right', alpha=None): cx = cy return tab + # ----------------------------------------------------------------------------- @@ -1108,15 +1106,15 @@ def value(self, i): sage: all(x.value(i) == i for i in range(-10,10)) True """ - N = 2*self.k + 1 + N = 2 * self.k + 1 window = i // N index = i % N if index == 0: return i if index <= self.k: - return self[index-1]+window*N + return self[index - 1] + window * N if index > self.k: - return -(self[N-index-1]-N)+window*N + return -(self[N - index - 1] - N) + window * N def position(self, i): r""" @@ -1129,19 +1127,19 @@ def position(self, i): sage: all(x.position(i) == i for i in range(-10,10)) True """ - N = 2*self.k + 1 + N = 2 * self.k + 1 index = i % N if index == 0: return i for r in range(len(self)): if self[r] % N == index: # i sits in position i, but some number of windows away. - diff = (i-self[r]) // N - return r + diff*N + 1 + diff = (i - self[r]) // N + return r + diff * N + 1 if self[r] % N == N - index: # then we sit some number of windows from position -r. - diff = (i+self[r]) // N - return -r + diff*N - 1 + diff = (i + self[r]) // N + return -r + diff * N - 1 return False def apply_simple_reflection_right(self, i) -> AffinePermutationTypeC: @@ -1164,13 +1162,13 @@ def apply_simple_reflection_right(self, i) -> AffinePermutationTypeC: j = i l = self[:] if j != 0 and j != self.k: - a = l[j-1] - l[j-1] = l[j] + a = l[j - 1] + l[j - 1] = l[j] l[j] = a elif j == 0: l[0] = -l[0] elif j == self.k: - l[self.k-1] = self(self.k+1) + l[self.k - 1] = self(self.k + 1) # return l return type(self)(self.parent(), l, check=False) @@ -1245,7 +1243,7 @@ def has_right_descent(self, i) -> bool: False True """ - return self.value(i) > self.value(i+1) + return self.value(i) > self.value(i + 1) def has_left_descent(self, i) -> bool: r""" @@ -1319,11 +1317,9 @@ def check(self) -> None: reslist.append(r) # Check that we have an even number of 'small' elements right # of the zeroth entry. - s = sum(-i // self.N + 1 for j in range(1, self.N + 1) - if (i := self.value(j)) < 0) + s = sum(-i // self.N + 1 for j in range(1, self.N + 1) if (i := self.value(j)) < 0) if s % 2: - raise ValueError("type B affine permutations have an even number of " - "entries less than 0 to the right of the 0th position") + raise ValueError("type B affine permutations have an even number of " "entries less than 0 to the right of the 0th position") def apply_simple_reflection_right(self, i) -> AffinePermutationTypeB: r""" @@ -1346,12 +1342,12 @@ def apply_simple_reflection_right(self, i) -> AffinePermutationTypeB: l = self[:] if j != 0 and j != self.k: # just swap l[j], l[j-1] - (l[j-1], l[j]) = (l[j], l[j-1]) + (l[j - 1], l[j]) = (l[j], l[j - 1]) elif j == 0: l[0] = -self(2) l[1] = -self(1) elif j == self.k: - l[self.k-1] = self(self.k+1) + l[self.k - 1] = self(self.k + 1) return type(self)(self.parent(), l, check=False) def apply_simple_reflection_left(self, i) -> AffinePermutationTypeB: @@ -1377,26 +1373,26 @@ def apply_simple_reflection_left(self, i) -> AffinePermutationTypeB: for m in range(self.k): res = self[m] % self.N if res == i: - l.append(self[m]+1) + l.append(self[m] + 1) elif res == i + 1: - l.append(self[m]-1) + l.append(self[m] - 1) elif res == j: - l.append(self[m]-1) + l.append(self[m] - 1) elif res == j - 1: - l.append(self[m]+1) + l.append(self[m] + 1) else: l.append(self[m]) elif i == 0: for m in range(self.k): res = self[m] % self.N if res == 1: - l.append(self[m]-3) + l.append(self[m] - 3) elif res == self.N - 2: - l.append(self[m]+3) + l.append(self[m] + 3) elif res == 2: - l.append(self[m]-3) + l.append(self[m] - 3) elif res == self.N - 1: - l.append(self[m]+3) + l.append(self[m] + 3) else: l.append(self[m]) elif i == self.k: @@ -1427,7 +1423,7 @@ def has_right_descent(self, i) -> bool: """ if i == 0: return self.value(-2) > self.value(1) - return self.value(i) > self.value(i+1) + return self.value(i) > self.value(i + 1) def has_left_descent(self, i) -> bool: r""" @@ -1482,18 +1478,13 @@ def check(self) -> None: reslist.append(r) # Check that we have an even number of 'big' elements left of # the kth entry. - s = sum(i // self.N + 1 - (i % self.N <= self.k) - for j in range(-self.k, self.k + 1) - if (i := self.value(j)) > self.k) + s = sum(i // self.N + 1 - (i % self.N <= self.k) for j in range(-self.k, self.k + 1) if (i := self.value(j)) > self.k) if s % 2: - raise ValueError("type D affine permutations have an even number of entries" - " greater than x.k weakly to the left of the x.k position") + raise ValueError("type D affine permutations have an even number of entries" " greater than x.k weakly to the left of the x.k position") # Check that we have an even number of 'small' elements right of the zeroth entry. - s = sum(-i // self.N + 1 for j in range(1, self.N + 1) - if (i := self.value(j)) < 0) + s = sum(-i // self.N + 1 for j in range(1, self.N + 1) if (i := self.value(j)) < 0) if s % 2: - raise ValueError("type D affine permutations have an even number of entries" - " less than 0 to the right of the 0th position") + raise ValueError("type D affine permutations have an even number of entries" " less than 0 to the right of the 0th position") def apply_simple_reflection_right(self, i) -> AffinePermutationTypeD: r""" @@ -1515,16 +1506,16 @@ def apply_simple_reflection_right(self, i) -> AffinePermutationTypeD: j = i l = self[:] if j != 0 and j != self.k: - a = l[j-1] - l[j-1] = l[j] + a = l[j - 1] + l[j - 1] = l[j] l[j] = a elif j == 0: c = l[0] l[0] = -l[1] l[1] = -c elif j == self.k: - l[self.k-2] = self(self.k+1) - l[self.k-1] = self(self.k+2) + l[self.k - 2] = self(self.k + 1) + l[self.k - 1] = self(self.k + 2) return type(self)(self.parent(), l, check=False) def apply_simple_reflection_left(self, i) -> AffinePermutationTypeD: @@ -1550,39 +1541,39 @@ def apply_simple_reflection_left(self, i) -> AffinePermutationTypeD: for m in range(self.k): res = self[m] % self.N if res == i: - l.append(self[m]+1) - elif res == i+1: - l.append(self[m]-1) + l.append(self[m] + 1) + elif res == i + 1: + l.append(self[m] - 1) elif res == j: - l.append(self[m]-1) - elif res == j-1: - l.append(self[m]+1) + l.append(self[m] - 1) + elif res == j - 1: + l.append(self[m] + 1) else: l.append(self[m]) elif i == 0: for m in range(self.k): res = self[m] % self.N if res == 1: - l.append(self[m]-3) - elif res == self.N-2: - l.append(self[m]+3) + l.append(self[m] - 3) + elif res == self.N - 2: + l.append(self[m] + 3) elif res == 2: - l.append(self[m]-3) - elif res == self.N-1: - l.append(self[m]+3) + l.append(self[m] - 3) + elif res == self.N - 1: + l.append(self[m] + 3) else: l.append(self[m]) elif i == self.k: for m in range(self.k): res = self[m] % self.N if res == self.k: - l.append(self[m]+2) - elif res == self.k+2: - l.append(self[m]-2) - elif res == self.k-1: - l.append(self[m]+2) - elif res == self.k+1: - l.append(self[m]-2) + l.append(self[m] + 2) + elif res == self.k + 2: + l.append(self[m] - 2) + elif res == self.k - 1: + l.append(self[m] + 2) + elif res == self.k + 1: + l.append(self[m] - 2) else: l.append(self[m]) return type(self)(self.parent(), l, check=False) @@ -1605,8 +1596,8 @@ def has_right_descent(self, i) -> bool: if i == 0: return self.value(-2) > self.value(1) if i == self.k: - return self.value(i) > self.value(i+2) - return self.value(i) > self.value(i+1) + return self.value(i) > self.value(i + 2) + return self.value(i) > self.value(i + 1) def has_left_descent(self, i) -> bool: r""" @@ -1626,8 +1617,8 @@ def has_left_descent(self, i) -> bool: if i == 0: return self.position(-2) > self.position(1) if i == self.k: - return self.position(i) > self.position(i+2) - return self.position(i) > self.position(i+1) + return self.position(i) > self.position(i + 2) + return self.position(i) > self.position(i + 1) class AffinePermutationTypeG(AffinePermutation): @@ -1651,15 +1642,13 @@ def check(self) -> None: if not len(self) == 6: raise ValueError("length of list must be 6") # Check that we have an even number of 'big' elements left of the 7th entry. - s = sum(i//6 - (i % 6 == 0) for i in self if i > 6) + s = sum(i // 6 - (i % 6 == 0) for i in self if i > 6) if s % 2: - raise ValueError("type G affine permutations have an even number of" - " entries greater than 6 to the left of the 7th position") + raise ValueError("type G affine permutations have an even number of" " entries greater than 6 to the left of the 7th position") # Check that we have an even number of 'small' elements right of the zeroth entry. - s = sum(-i//6 + 1 for i in self if i <= 0) + s = sum(-i // 6 + 1 for i in self if i <= 0) if s % 2: - raise ValueError("type G affine permutations have an even number of" - " entries less than 0 to the right of the 0th position") + raise ValueError("type G affine permutations have an even number of" " entries less than 0 to the right of the 0th position") def value(self, i, base_window=False): r""" @@ -1680,9 +1669,9 @@ def value(self, i, base_window=False): """ N = 6 if base_window: - self[i-1] - window = (i-1) // N - return self[(i-1) % N] + window*(N) + self[i - 1] + window = (i - 1) // N + return self[(i - 1) % N] + window * (N) def position(self, i): r""" @@ -1699,8 +1688,8 @@ def position(self, i): for r in range(N): if self[r] % N == i % N: # i sits in position i, but some number of windows away. - diff = (i-self[r]) // N - return r + diff*N + 1 + diff = (i - self[r]) // N + return r + diff * N + 1 return False def apply_simple_reflection_right(self, i) -> AffinePermutationTypeG: @@ -1763,27 +1752,27 @@ def apply_simple_reflection_left(self, i) -> AffinePermutationTypeG: for m in range(6): res = self[m] % 6 if res == 1 or res == 3 or res == 5: - l.append(self[m]+1) + l.append(self[m] + 1) elif res == 2 or res == 4 or res == 0: - l.append(self[m]-1) + l.append(self[m] - 1) else: l.append(self[m]) elif i == 2: for m in range(6): res = self[m] % 6 if res == 2 or res == 4: - l.append(self[m]+1) + l.append(self[m] + 1) elif res == 3 or res == 5: - l.append(self[m]-1) + l.append(self[m] - 1) else: l.append(self[m]) elif i == 0: for m in range(6): res = self[m] % 6 if res == 1 or res == 2: - l.append(self[m]-2) + l.append(self[m] - 2) elif res == 5 or res == 0: - l.append(self[m]+2) + l.append(self[m] + 2) else: l.append(self[m]) return type(self)(self.parent(), l, check=False) @@ -1807,7 +1796,7 @@ def has_right_descent(self, i) -> bool: raise ValueError('index not in index set') if i == 0: return self.value(0) > self.value(2) - return self.value(i) > self.value(i+1) + return self.value(i) > self.value(i + 1) def has_left_descent(self, i) -> bool: r""" @@ -1828,7 +1817,7 @@ def has_left_descent(self, i) -> bool: raise ValueError('index not in index set') if i == 0: return self.position(0) > self.position(2) - return self.position(i) > self.position(i+1) + return self.position(i) > self.position(i + 1) def to_type_a(self) -> AffinePermutationTypeA: r""" @@ -1850,6 +1839,7 @@ def to_type_a(self) -> AffinePermutationTypeA: # Class of all affine permutations. # ----------------------------------------------------------------------- + def AffinePermutationGroup(cartan_type): r""" Wrapper function for specific affine permutation groups. @@ -2009,6 +1999,7 @@ class AffinePermutationGroupGeneric(UniqueRepresentation, Parent): sage: AffinePermutationGroup(['A',7,1])([3, -1, 0, 6, 5, 4, 10, 9]) Type A affine permutation with window [3, -1, 0, 6, 5, 4, 10, 9] """ + # ---------------------- # Type-free methods. # ---------------------- @@ -2060,8 +2051,7 @@ def _test_enumeration(self, n=4, **options): W = self.weyl_group() I = W.weak_order_ideal(ConstantFunction(True), side='right') n2 = len(list(I.elements_of_depth_iterator(n))) - tester.assertEqual(n1, n2, "number of (ranked) elements of affine" - " permutation group disagrees with Weyl group") + tester.assertEqual(n1, n2, "number of (ranked) elements of affine" " permutation group disagrees with Weyl group") def weyl_group(self): r""" @@ -2086,7 +2076,7 @@ def classical(self): Symmetric group of order 8! as a permutation group """ if self._cartan_type.letter == 'A': - return SymmetricGroup(self.k+1) + return SymmetricGroup(self.k + 1) return WeylGroup(self._cartan_type.classical()) def cartan_type(self): @@ -2247,8 +2237,7 @@ def one(self) -> AffinePermutation: # Type-unique methods. # (Methods which do not exist in all types.) # ------------------------ - def from_lehmer_code(self, C, typ='decreasing', - side='right') -> AffinePermutation: + def from_lehmer_code(self, C, typ='decreasing', side='right') -> AffinePermutation: r""" Return the affine permutation with the supplied Lehmer code (a weak composition with `k+1` parts, at least one of which is 0). @@ -2276,12 +2265,12 @@ def from_lehmer_code(self, C, typ='decreasing', True """ if len(C) - 1 != self.k: - raise ValueError("composition must have {} entries".format(self.k+1)) + raise ValueError("composition must have {} entries".format(self.k + 1)) if 0 not in C: raise ValueError("composition must contain a zero entry") k = self.k # Find a zero entry in C. - for r in range(self.k+1): + for r in range(self.k + 1): if C[r] == 0: break D = list(C) @@ -2306,9 +2295,9 @@ def from_lehmer_code(self, C, typ='decreasing', l = ['x'] * (self.k + 1) ll = [] # read off a row of C. - for j in range(self.k+1): - pos = (r + s0*t0*j) % (k+1) - residue = (r + s0*t0*(row + j)) % (k+1) + for j in range(self.k + 1): + pos = (r + s0 * t0 * j) % (k + 1) + residue = (r + s0 * t0 * (row + j)) % (k + 1) if D[pos] != 0: ll.append(residue) l[pos] = [residue] diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index a525760659d..d2c64a36221 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -37,27 +37,23 @@ - :ref:`sage.combinat.combinatorial_map` - :ref:`sage.combinat.misc` """ + from sage.misc.namespace_package import install_doc, install_dict + # install the docstring of this module to the containing package install_doc(__package__, __doc__) del install_doc # install modules quickref and tutorial to the containing package from sage.combinat import quickref, tutorial + install_dict(__package__, {'quickref': quickref, 'tutorial': tutorial}) del install_dict del quickref, tutorial from sage.misc.lazy_import import lazy_import -from sage.combinat.combinat import (CombinatorialObject, - bell_number, bell_polynomial, bernoulli_polynomial, - catalan_number, euler_number, - fibonacci, fibonacci_sequence, fibonacci_xrange, - lucas_number1, lucas_number2, - number_of_tuples, number_of_unordered_tuples, - polygonal_number, stirling_number1, stirling_number2, - tuples, unordered_tuples) +from sage.combinat.combinat import CombinatorialObject, bell_number, bell_polynomial, bernoulli_polynomial, catalan_number, euler_number, fibonacci, fibonacci_sequence, fibonacci_xrange, lucas_number1, lucas_number2, number_of_tuples, number_of_unordered_tuples, polygonal_number, stirling_number1, stirling_number2, tuples, unordered_tuples from sage.combinat.expnums import expnums @@ -75,6 +71,7 @@ from sage.combinat.debruijn_sequence import DeBruijnSequences from sage.combinat.schubert_polynomial import SchubertPolynomialRing + lazy_import('sage.combinat.key_polynomial', 'KeyPolynomialBasis', as_='KeyPolynomials') lazy_import('sage.combinat.key_polynomial', 'AtomPolynomialBasis', as_='AtomPolynomials') from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra, HeckeAlgebraSymmetricGroupT @@ -84,10 +81,10 @@ # Permutations from sage.combinat.permutation import Permutation, Permutations, Arrangements, CyclicPermutations, CyclicPermutationsOfPartition from sage.combinat.affine_permutation import AffinePermutationGroup -lazy_import('sage.combinat.colored_permutations', ['ColoredPermutations', - 'SignedPermutation', - 'SignedPermutations']) + +lazy_import('sage.combinat.colored_permutations', ['ColoredPermutations', 'SignedPermutation', 'SignedPermutations']) from sage.combinat.derangements import Derangements + lazy_import('sage.combinat.baxter_permutations', ['BaxterPermutations']) # RSK @@ -107,9 +104,7 @@ from sage.combinat.composition_signed import SignedCompositions # Partitions -from sage.combinat.partition import (Partition, Partitions, PartitionsInBox, - OrderedPartitions, PartitionsGreatestLE, - PartitionsGreatestEQ, number_of_partitions) +from sage.combinat.partition import Partition, Partitions, PartitionsInBox, OrderedPartitions, PartitionsGreatestLE, PartitionsGreatestEQ, number_of_partitions lazy_import('sage.combinat.partition_tuple', ['PartitionTuple', 'PartitionTuples']) lazy_import('sage.combinat.partition_kleshchev', ['KleshchevPartitions']) @@ -128,8 +123,7 @@ lazy_import('sage.combinat.descent_algebra', 'DescentAlgebra') # Vector Partitions -lazy_import('sage.combinat.vector_partition', - ['VectorPartition', 'VectorPartitions']) +lazy_import('sage.combinat.vector_partition', ['VectorPartition', 'VectorPartitions']) # Similarity class types from sage.combinat.similarity_class_type import PrimarySimilarityClassType, PrimarySimilarityClassTypes, SimilarityClassType, SimilarityClassTypes @@ -138,26 +132,20 @@ from sage.combinat.core import Core, Cores # Tableaux -lazy_import('sage.combinat.tableau', - ["Tableau", "SemistandardTableau", "StandardTableau", "RowStandardTableau", "IncreasingTableau", - "Tableaux", "SemistandardTableaux", "StandardTableaux", "RowStandardTableaux", "IncreasingTableaux"]) +lazy_import('sage.combinat.tableau', ["Tableau", "SemistandardTableau", "StandardTableau", "RowStandardTableau", "IncreasingTableau", "Tableaux", "SemistandardTableaux", "StandardTableaux", "RowStandardTableaux", "IncreasingTableaux"]) from sage.combinat.skew_tableau import SkewTableau, SkewTableaux, StandardSkewTableaux, SemistandardSkewTableaux from sage.combinat.ribbon_shaped_tableau import RibbonShapedTableau, RibbonShapedTableaux, StandardRibbonShapedTableaux from sage.combinat.ribbon_tableau import RibbonTableaux, RibbonTableau, MultiSkewTableaux, MultiSkewTableau, SemistandardMultiSkewTableaux from sage.combinat.composition_tableau import CompositionTableau, CompositionTableaux -lazy_import('sage.combinat.tableau_tuple', - ['TableauTuple', 'StandardTableauTuple', 'RowStandardTableauTuple', - 'TableauTuples', 'StandardTableauTuples', 'RowStandardTableauTuples']) +lazy_import('sage.combinat.tableau_tuple', ['TableauTuple', 'StandardTableauTuple', 'RowStandardTableauTuple', 'TableauTuples', 'StandardTableauTuples', 'RowStandardTableauTuples']) from sage.combinat.k_tableau import WeakTableau, WeakTableaux, StrongTableau, StrongTableaux -lazy_import('sage.combinat.lr_tableau', ['LittlewoodRichardsonTableau', - 'LittlewoodRichardsonTableaux']) -lazy_import('sage.combinat.shifted_primed_tableau', ['ShiftedPrimedTableaux', - 'ShiftedPrimedTableau']) + +lazy_import('sage.combinat.lr_tableau', ['LittlewoodRichardsonTableau', 'LittlewoodRichardsonTableaux']) +lazy_import('sage.combinat.shifted_primed_tableau', ['ShiftedPrimedTableaux', 'ShiftedPrimedTableau']) # SuperTableaux -lazy_import('sage.combinat.super_tableau', - ["StandardSuperTableau", "SemistandardSuperTableau", "StandardSuperTableaux", "SemistandardSuperTableaux"]) +lazy_import('sage.combinat.super_tableau', ["StandardSuperTableau", "SemistandardSuperTableau", "StandardSuperTableaux", "SemistandardSuperTableaux"]) # Words from sage.combinat.words.all import * @@ -170,59 +158,50 @@ from sage.combinat.tuple import Tuples, UnorderedTuples # Alternating sign matrices -lazy_import('sage.combinat.alternating_sign_matrix', ('AlternatingSignMatrix', - 'AlternatingSignMatrices', - 'MonotoneTriangles', - 'ContreTableaux', - 'TruncatedStaircases')) +lazy_import('sage.combinat.alternating_sign_matrix', ('AlternatingSignMatrix', 'AlternatingSignMatrices', 'MonotoneTriangles', 'ContreTableaux', 'TruncatedStaircases')) # Decorated Permutations -lazy_import('sage.combinat.decorated_permutation', ('DecoratedPermutation', - 'DecoratedPermutations')) +lazy_import('sage.combinat.decorated_permutation', ('DecoratedPermutation', 'DecoratedPermutations')) # Plane Partitions -lazy_import('sage.combinat.plane_partition', ('PlanePartition', - 'PlanePartitions')) +lazy_import('sage.combinat.plane_partition', ('PlanePartition', 'PlanePartitions')) # Parking Functions -lazy_import('sage.combinat.non_decreasing_parking_function', - ['NonDecreasingParkingFunctions', 'NonDecreasingParkingFunction']) -lazy_import('sage.combinat.parking_functions', - ['ParkingFunctions', 'ParkingFunction']) +lazy_import('sage.combinat.non_decreasing_parking_function', ['NonDecreasingParkingFunctions', 'NonDecreasingParkingFunction']) +lazy_import('sage.combinat.parking_functions', ['ParkingFunctions', 'ParkingFunction']) # Trees and Tamari interval posets -from sage.combinat.ordered_tree import (OrderedTree, OrderedTrees, - LabelledOrderedTree, LabelledOrderedTrees) -from sage.combinat.binary_tree import (BinaryTree, BinaryTrees, - LabelledBinaryTree, LabelledBinaryTrees) +from sage.combinat.ordered_tree import OrderedTree, OrderedTrees, LabelledOrderedTree, LabelledOrderedTrees +from sage.combinat.binary_tree import BinaryTree, BinaryTrees, LabelledBinaryTree, LabelledBinaryTrees + lazy_import('sage.combinat.interval_posets', ['TamariIntervalPoset', 'TamariIntervalPosets']) -lazy_import('sage.combinat.rooted_tree', ('RootedTree', 'RootedTrees', - 'LabelledRootedTree', 'LabelledRootedTrees')) +lazy_import('sage.combinat.rooted_tree', ('RootedTree', 'RootedTrees', 'LabelledRootedTree', 'LabelledRootedTrees')) from sage.combinat.combination import Combinations from sage.combinat.set_partition import SetPartition, SetPartitions from sage.combinat.set_partition_ordered import OrderedSetPartition, OrderedSetPartitions -lazy_import('sage.combinat.multiset_partition_into_sets_ordered', - ['OrderedMultisetPartitionIntoSets', - 'OrderedMultisetPartitionsIntoSets']) + +lazy_import('sage.combinat.multiset_partition_into_sets_ordered', ['OrderedMultisetPartitionIntoSets', 'OrderedMultisetPartitionsIntoSets']) from sage.combinat.subset import Subsets, subsets, powerset, uniq from sage.combinat.necklace import Necklaces + lazy_import('sage.combinat.dyck_word', ('DyckWords', 'DyckWord')) lazy_import('sage.combinat.nu_dyck_word', ('NuDyckWords', 'NuDyckWord')) from sage.combinat.sloane_functions import sloane -lazy_import('sage.combinat.superpartition', ('SuperPartition', - 'SuperPartitions')) -lazy_import('sage.combinat.parallelogram_polyomino', - ['ParallelogramPolyomino', 'ParallelogramPolyominoes']) +lazy_import('sage.combinat.superpartition', ('SuperPartition', 'SuperPartitions')) + +lazy_import('sage.combinat.parallelogram_polyomino', ['ParallelogramPolyomino', 'ParallelogramPolyominoes']) from sage.combinat.root_system.all import * from sage.combinat.sf.all import * from sage.combinat.ncsf_qsym.all import * from sage.combinat.ncsym.all import * + lazy_import('sage.combinat.fqsym', 'FreeQuasisymmetricFunctions') from sage.combinat.matrices.all import * + # Posets from sage.combinat.posets.all import * @@ -243,8 +222,7 @@ lazy_import('sage.combinat.degree_sequences', 'DegreeSequences') -lazy_import('sage.combinat.cyclic_sieving_phenomenon', - ['CyclicSievingPolynomial', 'CyclicSievingCheck']) +lazy_import('sage.combinat.cyclic_sieving_phenomenon', ['CyclicSievingPolynomial', 'CyclicSievingCheck']) lazy_import('sage.combinat.sidon_sets', 'sidon_sets') @@ -252,18 +230,14 @@ lazy_import('sage.combinat.knutson_tao_puzzles', 'KnutsonTaoPuzzleSolver') # Gelfand-Tsetlin patterns -lazy_import('sage.combinat.gelfand_tsetlin_patterns', - ['GelfandTsetlinPattern', 'GelfandTsetlinPatterns']) +lazy_import('sage.combinat.gelfand_tsetlin_patterns', ['GelfandTsetlinPattern', 'GelfandTsetlinPatterns']) # Finite State Machines (Automaton, Transducer) -lazy_import('sage.combinat.finite_state_machine', - ['Automaton', 'Transducer', 'FiniteStateMachine']) -lazy_import('sage.combinat.finite_state_machine_generators', - ['automata', 'transducers']) +lazy_import('sage.combinat.finite_state_machine', ['Automaton', 'Transducer', 'FiniteStateMachine']) +lazy_import('sage.combinat.finite_state_machine_generators', ['automata', 'transducers']) # Sequences -lazy_import('sage.combinat.binary_recurrence_sequences', - 'BinaryRecurrenceSequence') +lazy_import('sage.combinat.binary_recurrence_sequences', 'BinaryRecurrenceSequence') lazy_import('sage.combinat.recognizable_series', 'RecognizableSeriesSpace') lazy_import('sage.combinat.regular_sequence', 'RegularSequenceRing') @@ -293,6 +267,5 @@ lazy_import('sage.combinat.bijectionist', 'Bijectionist') # TamariBlossomingTree -lazy_import('sage.combinat.tamari_blossoming_tree', - ['TamariBlossomingTree', 'TamariBlossomingTrees']) +lazy_import('sage.combinat.tamari_blossoming_tree', ['TamariBlossomingTree', 'TamariBlossomingTrees']) del lazy_import diff --git a/src/sage/combinat/alternating_sign_matrix.py b/src/sage/combinat/alternating_sign_matrix.py index 14e3de453b8..43c4aadadf9 100644 --- a/src/sage/combinat/alternating_sign_matrix.py +++ b/src/sage/combinat/alternating_sign_matrix.py @@ -63,24 +63,21 @@ def _inplace_height_function_gyration(hf): k = hf.nrows() - 1 for i in range(1, k): for j in range(1, k): - if (i+j) % 2 == 0 \ - and hf[i-1,j] == hf[i+1,j] == hf[i,j+1] == hf[i,j-1]: - if hf[i,j] < hf[i+1,j]: - hf[i,j] += 2 + if (i + j) % 2 == 0 and hf[i - 1, j] == hf[i + 1, j] == hf[i, j + 1] == hf[i, j - 1]: + if hf[i, j] < hf[i + 1, j]: + hf[i, j] += 2 else: - hf[i,j] -= 2 - for i in range(1,k): - for j in range(1,k): - if (i+j) % 2 == 1 \ - and hf[i-1,j] == hf[i+1,j] == hf[i,j+1] == hf[i,j-1]: - if hf[i,j] < hf[i+1,j]: - hf[i,j] += 2 + hf[i, j] -= 2 + for i in range(1, k): + for j in range(1, k): + if (i + j) % 2 == 1 and hf[i - 1, j] == hf[i + 1, j] == hf[i, j + 1] == hf[i, j - 1]: + if hf[i, j] < hf[i + 1, j]: + hf[i, j] += 2 else: - hf[i,j] -= 2 + hf[i, j] -= 2 -class AlternatingSignMatrix(Element, - metaclass=InheritComparisonClasscallMetaclass): +class AlternatingSignMatrix(Element, metaclass=InheritComparisonClasscallMetaclass): r""" An alternating sign matrix. @@ -90,6 +87,7 @@ class AlternatingSignMatrix(Element, These were introduced in [MRR1983]_. """ + @staticmethod def __classcall_private__(cls, asm, check=True): """ @@ -267,8 +265,7 @@ def to_monotone_triangle(self): add_row = zero_vector(ZZ, n) for j, row in enumerate(self._matrix): add_row = row + add_row - triangle[n - 1 - j] = [i + 1 for i in range(n - 1, -1, -1) - if add_row[i] == 1] + triangle[n - 1 - j] = [i + 1 for i in range(n - 1, -1, -1) if add_row[i] == 1] return MonotoneTriangles(n)(triangle) @combinatorial_map(name='rotate counterclockwise') @@ -472,7 +469,7 @@ def height_function(self): for i in range(n): for j in range(n): col_sum[j] += asm[i, j] - ans[j+1, i+1] = ans[j, i+1] + 1 - 2 * col_sum[j] + ans[j + 1, i + 1] = ans[j, i + 1] + 1 - 2 * col_sum[j] return ans def to_six_vertex_model(self): @@ -535,6 +532,7 @@ def to_fully_packed_loop(self): │ │ """ from sage.combinat.fully_packed_loop import FullyPackedLoop + return FullyPackedLoop(self) def link_pattern(self): @@ -685,8 +683,7 @@ def ASM_compatible(self, B): BB = B.corner_sum_matrix() for i in range(len(AA[0])): for j in range(len(AA[0])): - if not (AA[i,j] >= BB[i,j] and AA[i,j] >= BB[i+1,j+1]-1 - and AA[i,j] <= BB[i+1,j] and AA[i,j] <= BB[i,j+1]): + if not (AA[i, j] >= BB[i, j] and AA[i, j] >= BB[i + 1, j + 1] - 1 and AA[i, j] <= BB[i + 1, j] and AA[i, j] <= BB[i, j + 1]): return False return True @@ -723,36 +720,36 @@ def ASM_compatible_bigger(self): n = self.parent()._n + 1 M = AlternatingSignMatrices(n) sign = [] - B = matrix(ZZ, n+1) + B = matrix(ZZ, n + 1) A = 2 * self.height_function() for i in range(n): for j in range(n): A.add_to_entry(i, j, ZZ.one()) - for a in range(n+1): - B[a,0] = B[0,a] = 2*a - B[a,n] = B[n,a] = 2*(n-a) - - for i in range(1,n): - for j in range(1,n): - if A[i-1,j-1] == A[i,j] == A[i-1,j]-2 == A[i,j-1]-2: - B[i,j] = -A[i,j] - sign.append([i,j]) + for a in range(n + 1): + B[a, 0] = B[0, a] = 2 * a + B[a, n] = B[n, a] = 2 * (n - a) + + for i in range(1, n): + for j in range(1, n): + if A[i - 1, j - 1] == A[i, j] == A[i - 1, j] - 2 == A[i, j - 1] - 2: + B[i, j] = -A[i, j] + sign.append([i, j]) else: - s = {A[i-1,j-1]-1,A[i-1,j-1]+3} & {A[i-1,j]-3,A[i-1,j]+1} & {A[i,j-1]-3,A[i,j-1]+1} & {A[i,j]-1,A[i,j]+3} + s = {A[i - 1, j - 1] - 1, A[i - 1, j - 1] + 3} & {A[i - 1, j] - 3, A[i - 1, j] + 1} & {A[i, j - 1] - 3, A[i, j - 1] + 1} & {A[i, j] - 1, A[i, j] + 3} assert len(s) == 1 - B[i,j] = s.pop() + B[i, j] = s.pop() output = [B] for b in range(len(sign)): N = len(output) for c in range(N): d = copy.copy(output[c]) - output[c][sign[b][0],sign[b][1]] = -output[c][sign[b][0], sign[b][1]] + 3 - d[sign[b][0],sign[b][1]] = -d[sign[b][0], sign[b][1]]-1 + output[c][sign[b][0], sign[b][1]] = -output[c][sign[b][0], sign[b][1]] + 3 + d[sign[b][0], sign[b][1]] = -d[sign[b][0], sign[b][1]] - 1 output.append(d) for k in range(len(output)): - output[k] = M.from_height_function(output[k]/2) + output[k] = M.from_height_function(output[k] / 2) return output def ASM_compatible_smaller(self): @@ -781,34 +778,34 @@ def ASM_compatible_smaller(self): ] """ n = self.parent()._n - M = AlternatingSignMatrices(n-1) + M = AlternatingSignMatrices(n - 1) A = matrix(ZZ, n) - B = 2*self.height_function()[:n,:n] + B = 2 * self.height_function()[:n, :n] sign = [] for a in range(n): - A[a,0] = 2*a + 1 - A[0,a] = 2*a + 1 - A[n-1,a] = 2*(n-a) - 1 - A[a,n-1] = 2*(n-a) - 1 - - for i in range(n-1): - for j in range(n-1): - if B[i+1,j+1] == B[i,j] == B[i,j+1]+2 == B[i+1,j]+2: - A[i,j] = -B[i,j] - sign.append([i,j]) + A[a, 0] = 2 * a + 1 + A[0, a] = 2 * a + 1 + A[n - 1, a] = 2 * (n - a) - 1 + A[a, n - 1] = 2 * (n - a) - 1 + + for i in range(n - 1): + for j in range(n - 1): + if B[i + 1, j + 1] == B[i, j] == B[i, j + 1] + 2 == B[i + 1, j] + 2: + A[i, j] = -B[i, j] + sign.append([i, j]) else: - A[i,j] = list({B[i,j]+1,B[i,j]-3} & {B[i,j+1]+3,B[i,j+1]-1} & {B[i+1,j]+3,B[i+1,j]-1} & {B[i+1,j+1]+1,B[i+1,j+1]-3})[0] + A[i, j] = list({B[i, j] + 1, B[i, j] - 3} & {B[i, j + 1] + 3, B[i, j + 1] - 1} & {B[i + 1, j] + 3, B[i + 1, j] - 1} & {B[i + 1, j + 1] + 1, B[i + 1, j + 1] - 3})[0] output = [A] for b in range(len(sign)): N = len(output) for c in range(N): d = copy.copy(output[c]) - output[c][sign[b][0], sign[b][1]] = -output[c][sign[b][0], sign[b][1]]+1 - d[sign[b][0], sign[b][1]] = -d[sign[b][0], sign[b][1]]-3 + output[c][sign[b][0], sign[b][1]] = -output[c][sign[b][0], sign[b][1]] + 1 + d[sign[b][0], sign[b][1]] = -d[sign[b][0], sign[b][1]] - 3 output.append(d) for k in range(len(output)): - output[k] = M.from_height_function((output[k]-matrix.ones(n, n))/2) + output[k] = M.from_height_function((output[k] - matrix.ones(n, n)) / 2) return output @combinatorial_map(name='to Dyck word') @@ -866,6 +863,7 @@ def to_dyck_word(self, algorithm): if algorithm == 'link_pattern': from sage.combinat.perfect_matching import PerfectMatching from sage.combinat.dyck_word import DyckWords + p = PerfectMatching(self.link_pattern()).to_noncrossing_set_partition() asm = self.to_matrix() n = asm.nrows() @@ -951,11 +949,12 @@ def to_semistandard_tableau(self): Semistandard tableaux """ from sage.combinat.tableau import SemistandardTableau + mt = self.to_monotone_triangle() - ssyt = [[0]*(len(mt) - j) for j in range(len(mt))] + ssyt = [[0] * (len(mt) - j) for j in range(len(mt))] for i in range(len(mt)): for j in range(len(mt[i])): - ssyt[i][j] = mt[j][-(i+1)] + ssyt[i][j] = mt[j][-(i + 1)] return SemistandardTableau(ssyt) def left_key(self): @@ -988,10 +987,10 @@ def left_key(self): Alternating sign matrices of size 3 """ lkey = self.to_semistandard_tableau().left_key_tableau() - mt = [[0]*(len(lkey) - j) for j in range(len(lkey))] + mt = [[0] * (len(lkey) - j) for j in range(len(lkey))] for i in range(len(lkey)): for j in range(len(lkey[i])): - mt[i][j] = lkey[len(lkey[i])-j-1][i] + mt[i][j] = lkey[len(lkey[i]) - j - 1][i] A = AlternatingSignMatrices(len(lkey)) return A.from_monotone_triangle(mt) @@ -1154,11 +1153,11 @@ def __contains__(self, asm) -> bool: # and i-th column are either 0 or 1 rs = cs = ZZ.zero() for j in range(n): - rs += asm[i,j] + rs += asm[i, j] if not (rs.is_zero() or rs.is_one()): return False - cs += asm[j,i] + cs += asm[j, i] if not (cs.is_zero() or cs.is_one()): return False @@ -1256,6 +1255,7 @@ def random_element(self): an alternating sign matrix. """ from sage.combinat.gelfand_tsetlin_patterns import GelfandTsetlinPatterns + n = self._n toprow = [n - i for i in range(n)] gt = GelfandTsetlinPatterns(top_row=toprow, strict=True) @@ -1325,8 +1325,8 @@ def from_corner_sum(self, corner): True """ n = self._n - corner = MatrixSpace(ZZ, n+1)(corner) - asm = corner[1:,1:] + corner[:n,:n] - corner[:n,1:] - corner[1:,:n] + corner = MatrixSpace(ZZ, n + 1)(corner) + asm = corner[1:, 1:] + corner[:n, :n] - corner[:n, 1:] - corner[1:, :n] return self.element_class(self, asm) def from_height_function(self, height): @@ -1347,9 +1347,7 @@ def from_height_function(self, height): """ n = self._n height = MatrixSpace(ZZ, n + 1)(height) - return self.from_corner_sum([[(i + j - height[i, j]) // 2 - for i in range(n + 1)] - for j in range(n + 1)]) + return self.from_corner_sum([[(i + j - height[i, j]) // 2 for i in range(n + 1)] for j in range(n + 1)]) def from_contre_tableau(self, comps): r""" @@ -1371,12 +1369,12 @@ def from_contre_tableau(self, comps): M = [[0 for _ in range(n)] for _ in range(n)] previous_set = set() - for col in range(n-1, -1, -1): + for col in range(n - 1, -1, -1): s = set(comps[col]) for x in s.difference(previous_set): - M[x-1][col] = 1 + M[x - 1][col] = 1 for x in previous_set.difference(s): - M[x-1][col] = -1 + M[x - 1][col] = -1 previous_set = s @@ -1410,8 +1408,7 @@ def cardinality(self): sage: [AlternatingSignMatrices(n).cardinality() for n in range(11)] [1, 1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460, 129534272700] """ - return Integer(prod(factorial(3 * k + 1) / factorial(self._n + k) - for k in range(self._n))) + return Integer(prod(factorial(3 * k + 1) / factorial(self._n + k) for k in range(self._n))) def matrix_space(self): """ @@ -1566,8 +1563,7 @@ def lattice(self): Finite lattice containing 7 elements """ cat = FiniteLatticePosets().Distributive() - return LatticePoset(self._lattice_initializer(), cover_relations=True, - check=False, category=cat) + return LatticePoset(self._lattice_initializer(), cover_relations=True, check=False, category=cat) @cached_method def gyration_orbits(self): @@ -1594,9 +1590,8 @@ def gyration_orbits(self): )) """ ASMs = list(self) - perm = Permutation([ASMs.index(asm.gyration())+1 for asm in ASMs]) - return tuple([tuple([ASMs[i-1] for i in cyc]) - for cyc in perm.cycle_tuples()]) + perm = Permutation([ASMs.index(asm.gyration()) + 1 for asm in ASMs]) + return tuple([tuple([ASMs[i - 1] for i in cyc]) for cyc in perm.cycle_tuples()]) def gyration_orbit_sizes(self): r""" @@ -1675,7 +1670,7 @@ def __init__(self, n): sage: M is M2 True """ - GelfandTsetlinPatternsTopRow.__init__(self, tuple(reversed(range(1, n+1))), True) + GelfandTsetlinPatternsTopRow.__init__(self, tuple(reversed(range(1, n + 1))), True) def _repr_(self): r""" @@ -1706,8 +1701,7 @@ def cardinality(self): sage: M.cardinality() 42 """ - return Integer(prod(factorial(3 * k + 1) / factorial(self._n + k) - for k in range(self._n))) + return Integer(prod(factorial(3 * k + 1) / factorial(self._n + k) for k in range(self._n))) def _lattice_initializer(self): r""" @@ -1766,8 +1760,7 @@ def lattice(self): sage: P Finite lattice containing 7 elements """ - return LatticePoset(self._lattice_initializer(), cover_relations=True, - check=False) + return LatticePoset(self._lattice_initializer(), cover_relations=True, check=False) def _is_a_cover(mt0, mt1): @@ -1798,6 +1791,7 @@ def _is_a_cover(mt0, mt1): from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.combinat.alternating_sign_matrix', 'AlternatingSignMatrices_n', AlternatingSignMatrices) register_unpickle_override('sage.combinat.alternating_sign_matrix', 'MonotoneTriangles_n', MonotoneTriangles) @@ -1813,6 +1807,7 @@ class ContreTableaux(Parent, metaclass=ClasscallMetaclass): sage: ct4.cardinality() 42 """ + @staticmethod def __classcall_private__(cls, n, **kwds): r""" @@ -1868,8 +1863,7 @@ def cardinality(self): sage: [ContreTableaux(n).cardinality() for n in range(11)] [1, 1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460, 129534272700] """ - return Integer(prod(factorial(3 * k + 1) / factorial(self.n + k) - for k in range(self.n))) + return Integer(prod(factorial(3 * k + 1) / factorial(self.n + k) for k in range(self.n))) def _iterator_rec(self, i): """ @@ -1888,9 +1882,9 @@ def _iterator_rec(self, i): elif i == 1: yield [list(range(1, self.n + 1))] else: - for columns in self._iterator_rec(i-1): + for columns in self._iterator_rec(i - 1): previous_column = columns[-1] - for column in _next_column_iterator(previous_column, len(previous_column)-1): + for column in _next_column_iterator(previous_column, len(previous_column) - 1): yield columns + [column] def __iter__(self): @@ -1939,13 +1933,13 @@ def _next_column_iterator(previous_column, height, i=None): if i == 0: yield [-1] * height else: - for column in _next_column_iterator(previous_column, height, i-1): - min_value = previous_column[i-1] + for column in _next_column_iterator(previous_column, height, i - 1): + min_value = previous_column[i - 1] if i > 1: - min_value = max(min_value, column[i-2]+1) - for value in range(min_value, previous_column[i]+1): + min_value = max(min_value, column[i - 2] + 1) + for value in range(min_value, previous_column[i] + 1): c = column[:] - c[i-1] = value + c[i - 1] = value yield c @@ -1973,6 +1967,7 @@ class TruncatedStaircases(Parent, metaclass=ClasscallMetaclass): sage: t4.cardinality() 4 """ + @staticmethod def __classcall_private__(cls, n, last_column, **kwds): r""" @@ -2029,9 +2024,9 @@ def _iterator_rec(self, i): elif i == len(self.last_column): yield [self.last_column] else: - for columns in self._iterator_rec(i-1): + for columns in self._iterator_rec(i - 1): previous_column = columns[0] - for column in _previous_column_iterator(previous_column, len(previous_column)+1, self.n): + for column in _previous_column_iterator(previous_column, len(previous_column) + 1, self.n): yield [column] + columns def __iter__(self): @@ -2052,8 +2047,7 @@ def __eq__(self, other): sage: T == loads(dumps(T)) True """ - return (self.n == other.n and - self.last_column == other.last_column) + return self.n == other.n and self.last_column == other.last_column def cardinality(self): r""" diff --git a/src/sage/combinat/backtrack.py b/src/sage/combinat/backtrack.py index 52673e92d80..2def999f267 100644 --- a/src/sage/combinat/backtrack.py +++ b/src/sage/combinat/backtrack.py @@ -10,6 +10,7 @@ This module has mostly been superseded by ``RecursivelyEnumeratedSet``. """ + # **************************************************************************** # Copyright (C) 2008 Mike Hansen , # 2009 Nicolas M. Thiery @@ -28,8 +29,7 @@ # **************************************************************************** from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.monoids import Monoids -from sage.categories.commutative_additive_semigroups import ( - CommutativeAdditiveSemigroups) +from sage.categories.commutative_additive_semigroups import CommutativeAdditiveSemigroups from sage.structure.unique_representation import UniqueRepresentation from sage.rings.integer_ring import ZZ from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_forest diff --git a/src/sage/combinat/baxter_permutations.py b/src/sage/combinat/baxter_permutations.py index c2c97ee36f9..70a8092fdfc 100644 --- a/src/sage/combinat/baxter_permutations.py +++ b/src/sage/combinat/baxter_permutations.py @@ -1,6 +1,7 @@ """ Baxter permutations """ + from collections.abc import Iterator from sage.combinat.permutation import Permutations @@ -43,6 +44,7 @@ class BaxterPermutations(UniqueRepresentation, Parent): sage: BaxterPermutations() Baxter permutations """ + @staticmethod def __classcall_private__(classe, n=None): """ @@ -71,6 +73,7 @@ class BaxterPermutations_size(BaxterPermutations): sage: BaxterPermutations_size(5) Baxter permutations of size 5 """ + def __init__(self, n) -> None: """ EXAMPLES:: @@ -82,6 +85,7 @@ def __init__(self, n) -> None: self.element_class = Permutations(n).element_class self._n = Integer(n) from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets + super().__init__(category=FiniteEnumeratedSets()) def _repr_(self) -> str: @@ -129,7 +133,7 @@ def __contains__(self, x) -> bool: if x_j > a and x_j < b and x_j > max_l: max_l = x_j min_r = len(x) + 1 - for x_j in x[i + 2:]: + for x_j in x[i + 2 :]: if x_j > a and x_j < b and x_j < min_r: min_r = x_j if max_l > min_r: @@ -140,7 +144,7 @@ def __contains__(self, x) -> bool: if x_j < a and x_j > b and x_j < min_l: min_l = x_j max_r = 0 - for x_j in x[i + 2:]: + for x_j in x[i + 2 :]: if x_j < a and x_j > b and x_j > max_r: max_r = x_j if min_l < max_r: @@ -190,7 +194,7 @@ def __iter__(self) -> Iterator: yield Permutations(self._n)(b[:i] + [self._n] + b[i:]) # Right to left maxima. for i in b.saliances(): - yield Permutations(self._n)(b[:i + 1] + [self._n] + b[i + 1:]) + yield Permutations(self._n)(b[: i + 1] + [self._n] + b[i + 1 :]) def _an_element_(self): """ @@ -231,10 +235,7 @@ def cardinality(self): if self._n == 0: return ZZ.one() n = self._n + 1 - return sum((n.binomial(k) * - n.binomial(k + 1) * - n.binomial(k + 2)) // (n * n.binomial(2)) - for k in range(self._n)) + return sum((n.binomial(k) * n.binomial(k + 1) * n.binomial(k + 2)) // (n * n.binomial(2)) for k in range(self._n)) def lattice(self): """ @@ -251,8 +252,7 @@ def lattice(self): - [Law2011]_ """ - return LatticePoset([list(self), lambda a, b: a.weak_le(b)], - check=False) + return LatticePoset([list(self), lambda a, b: a.weak_le(b)], check=False) class BaxterPermutations_all(DisjointUnionEnumeratedSets, BaxterPermutations): @@ -268,6 +268,7 @@ class BaxterPermutations_all(DisjointUnionEnumeratedSets, BaxterPermutations): sage: BaxterPermutations_all() Baxter permutations """ + def __init__(self, n=None) -> None: r""" EXAMPLES:: @@ -279,10 +280,8 @@ def __init__(self, n=None) -> None: self.element_class = Permutations().element_class from sage.sets.family import Family from sage.sets.non_negative_integers import NonNegativeIntegers - DisjointUnionEnumeratedSets.__init__(self, - Family(NonNegativeIntegers(), - BaxterPermutations_size), - facade=False, keepkey=False) + + DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), BaxterPermutations_size), facade=False, keepkey=False) def _repr_(self) -> str: r""" @@ -356,6 +355,7 @@ def to_pair_of_twin_binary_trees(self, p) -> tuple: (3[1[., 2[., .]], 4[., .]], 2[1[., .], 4[3[., .], .]]) """ from sage.combinat.binary_tree import LabelledBinaryTree + left = LabelledBinaryTree(None) right = LabelledBinaryTree(None) for a in p: diff --git a/src/sage/combinat/bijectionist.py b/src/sage/combinat/bijectionist.py index 3e03063a1a7..d656c12eca6 100644 --- a/src/sage/combinat/bijectionist.py +++ b/src/sage/combinat/bijectionist.py @@ -483,10 +483,8 @@ class Bijectionist(SageObject): :meth:`set_constant_blocks`, etc., is irrelevant. Calling any of these methods a second time overrides the previous specification. """ - def __init__(self, A, B, tau=None, alpha_beta=tuple(), P=None, - pi_rho=tuple(), phi_psi=tuple(), Q=None, - elements_distributions=tuple(), - value_restrictions=tuple(), solver=None, key=None): + + def __init__(self, A, B, tau=None, alpha_beta=tuple(), P=None, pi_rho=tuple(), phi_psi=tuple(), Q=None, elements_distributions=tuple(), value_restrictions=tuple(), solver=None, key=None): """ Initialize the bijectionist. @@ -768,8 +766,7 @@ def set_statistics(self, *alpha_beta): self._statistics_fibers[v][1].append(b) # check compatibility - if not all(len(fiber[0]) == len(fiber[1]) - for fiber in self._statistics_fibers.values()): + if not all(len(fiber[0]) == len(fiber[1]) for fiber in self._statistics_fibers.values()): raise ValueError("statistics alpha and beta are not equidistributed") self._W = list(self._statistics_fibers) @@ -780,8 +777,7 @@ def set_statistics(self, *alpha_beta): for a in self._A: v = self._alpha(a) if v not in tau_beta_inverse: - tau_beta_inverse[v] = set(self._tau[b] - for b in self._statistics_fibers[v][1]) + tau_beta_inverse[v] = set(self._tau[b] for b in self._statistics_fibers[v][1]) self._statistics_possible_values[a] = tau_beta_inverse[v] def statistics_fibers(self): @@ -940,8 +936,7 @@ def statistics_table(self, header=True): # table for alpha n_statistics = self._n_statistics if header: - output_alphas = [["a"] + ["\u03b1_" + str(i) + "(a)" - for i in range(1, n_statistics + 1)]] + output_alphas = [["a"] + ["\u03b1_" + str(i) + "(a)" for i in range(1, n_statistics + 1)]] else: output_alphas = [] @@ -953,8 +948,7 @@ def statistics_table(self, header=True): # table for beta and tau if header: - output_tau_betas = [["b", "\u03c4"] + ["\u03b2_" + str(i) + "(b)" - for i in range(1, n_statistics + 1)]] + output_tau_betas = [["b", "\u03c4"] + ["\u03b2_" + str(i) + "(b)" for i in range(1, n_statistics + 1)]] else: output_tau_betas = [] for b in self._B: @@ -1088,8 +1082,7 @@ def _compute_possible_block_values(self): """ self._possible_block_values = {} # P -> Power(Z) for p, block in self._P.root_to_elements_dict().items(): - sets = ([self._restrictions_possible_values[a] for a in block] - + [self._statistics_possible_values[a] for a in block]) + sets = [self._restrictions_possible_values[a] for a in block] + [self._statistics_possible_values[a] for a in block] self._possible_block_values[p] = _non_copying_intersection(sets) if not self._possible_block_values[p]: if len(block) == 1: @@ -1634,9 +1627,7 @@ def _forced_constant_blocks(self): solution = next(self._bmilp.solutions_iterator(True, [])) # multiple_preimages[tZ] are the blocks p which have the same # value tZ[i] in the i-th known solution - multiple_preimages = {(z,): tP - for z, tP in _invert_dict(solution).items() - if len(tP) > 1} + multiple_preimages = {(z,): tP for z, tP in _invert_dict(solution).items() if len(tP) > 1} # _P has to be copied to not mess with the solution process # since we do not want to regenerate the bmilp in each step, @@ -1646,9 +1637,7 @@ def _forced_constant_blocks(self): # check whether blocks p1 and p2 can have different values, # if so return such a solution def different_values(p1, p2): - tmp_constraints = [self._bmilp._x[p1, z] + self._bmilp._x[p2, z] <= 1 - for z in self._possible_block_values[p1] - if z in self._possible_block_values[p2]] + tmp_constraints = [self._bmilp._x[p1, z] + self._bmilp._x[p2, z] <= 1 for z in self._possible_block_values[p1] if z in self._possible_block_values[p2]] return next(self._bmilp.solutions_iterator(True, tmp_constraints)) # try to find a pair of blocks having the same value on all @@ -1675,8 +1664,7 @@ def merge_until_split(): if solution is None: self._P = tmp_P # recreate the MILP - self._bmilp = _BijectionistMILP(self, - self._bmilp._solution_cache) + self._bmilp = _BijectionistMILP(self, self._bmilp._solution_cache) return updated_multiple_preimages = defaultdict(list) @@ -1878,13 +1866,11 @@ def minimal_subdistributions_iterator(self): yield ([a for a in self._A if d[a]], values) # get all variables with value 1 - active_vars = [D[a] for a in self._A - if minimal_subdistribution.get_values(D[a], convert=bool, tolerance=0.1)] + active_vars = [D[a] for a in self._A if minimal_subdistribution.get_values(D[a], convert=bool, tolerance=0.1)] # add constraint that not all of these can be 1, thus vetoing # the current solution - minimal_subdistribution.add_constraint(sum(active_vars) <= len(active_vars) - 1, - name='veto') + minimal_subdistribution.add_constraint(sum(active_vars) <= len(active_vars) - 1, name='veto') else: s = new_s @@ -1929,9 +1915,7 @@ def _find_counterexample(self, P, s0, d, on_blocks): # try to find a solution which has a different # subdistribution on d than s0 - z_in_d = sum(d[p] * bmilp._x[self._P.find(p), z] - for p in P - if z in self._possible_block_values[self._P.find(p)]) + z_in_d = sum(d[p] * bmilp._x[self._P.find(p), z] for p in P if z in self._possible_block_values[self._P.find(p)]) # it is sufficient to require that z occurs less often as # a value among {a | d[a] == 1} than it does in @@ -2075,8 +2059,7 @@ def minimal_subdistributions_blocks_iterator(self): def add_counter_example_constraint(s): for v in self._Z: - minimal_subdistribution.add_constraint(sum(D[p] for p in P - if s[p] == v) == V[v]) + minimal_subdistribution.add_constraint(sum(D[p] for p in P if s[p] == v) == V[v]) if self._bmilp is None: self._bmilp = _BijectionistMILP(self) @@ -2091,15 +2074,11 @@ def add_counter_example_constraint(s): d = minimal_subdistribution.get_values(D, convert=ZZ, tolerance=0.1) # a dict from P to multiplicities new_s = self._find_counterexample(P, s, d, True) if new_s is None: - yield ([p for p in P for _ in range(ZZ(d[p]))], - self._sorter["Z"](s[p] - for p in P - for _ in range(ZZ(d[p])))) + yield ([p for p in P for _ in range(ZZ(d[p]))], self._sorter["Z"](s[p] for p in P for _ in range(ZZ(d[p])))) support = [X[p] for p in P if d[p]] # add constraint that the support is different - minimal_subdistribution.add_constraint(sum(support) <= len(support) - 1, - name='veto') + minimal_subdistribution.add_constraint(sum(support) <= len(support) - 1, name='veto') else: s = new_s add_counter_example_constraint(s) @@ -2459,6 +2438,7 @@ class _BijectionistMILP: This class is used to manage the MILP, add constraints, solve the problem and check for uniqueness of solution values. """ + def __init__(self, bijectionist: Bijectionist, solutions=None): r""" Initialize the mixed integer linear program. @@ -2499,16 +2479,13 @@ def __init__(self, bijectionist: Bijectionist, solutions=None): self.milp = MixedIntegerLinearProgram(solver=bijectionist._solver) self.milp.set_objective(None) - indices = [(p, z) - for p, tZ in bijectionist._possible_block_values.items() - for z in tZ] + indices = [(p, z) for p, tZ in bijectionist._possible_block_values.items() for z in tZ] self._x = self.milp.new_variable(binary=True, indices=indices) tZ = bijectionist._possible_block_values P = bijectionist._P for p in _disjoint_set_roots(P): - self.milp.add_constraint(sum(self._x[p, z] for z in tZ[p]) == 1, - name=f"block {p}"[:50]) + self.milp.add_constraint(sum(self._x[p, z] for z in tZ[p]) == 1, name=f"block {p}"[:50]) self.add_alpha_beta_constraints() self.add_distribution_constraints() self.add_quadratic_relation_constraints() @@ -2520,8 +2497,7 @@ def __init__(self, bijectionist: Bijectionist, solutions=None): self._solution_cache = [] if solutions is not None: for solution in solutions: - self._add_solution({(P.find(a), z): value - for (a, z), value in solution.items()}) + self._add_solution({(P.find(a), z): value for (a, z), value in solution.items()}) def show(self, variables=True): r""" @@ -2568,12 +2544,7 @@ def show(self, variables=True): c = ZZ(c) if c == 0: continue - print((("+ " if (not first and c > 0) else "") + - ("" if c == 1 else - ("- " if c == -1 else - (str(c) + " " if first and c < 0 else - ("- " + str(abs(c)) + " " if c < 0 else str(c) + " ")))) - + varid_name[j]), end=" ") + print((("+ " if (not first and c > 0) else "") + ("" if c == 1 else ("- " if c == -1 else (str(c) + " " if first and c < 0 else ("- " + str(abs(c)) + " " if c < 0 else str(c) + " ")))) + varid_name[j]), end=" ") first = False # Upper bound print("<= " + str(ZZ(ub)) if ub is not None else "") @@ -2582,8 +2553,7 @@ def show(self, variables=True): print("Variables are:") P = self._bijectionist._P.root_to_elements_dict() for (p, z), v in self._x.items(): - print(f" {v}: " + "".join([f"s({a}) = " - for a in P[p]]) + f"{z}") + print(f" {v}: " + "".join([f"s({a}) = " for a in P[p]]) + f"{z}") def _prepare_solution(self, on_blocks, solution): r""" @@ -2655,20 +2625,17 @@ def solutions_iterator(self, on_blocks, additional_constraints): while i < len(self._solution_cache): solution = self._solution_cache[i] i += 1 - if all(self._is_solution(constraint, solution) - for constraint in additional_constraints): + if all(self._is_solution(constraint, solution) for constraint in additional_constraints): yield self._prepare_solution(on_blocks, solution) break else: new_indices = [] for constraint in additional_constraints: - new_indices.extend(self.milp.add_constraint(constraint, - return_indices=True)) + new_indices.extend(self.milp.add_constraint(constraint, return_indices=True)) try: self.milp.solve() # moving this out of the try...finally block breaks SCIP - solution = self.milp.get_values(self._x, - convert=bool, tolerance=0.1) + solution = self.milp.get_values(self._x, convert=bool, tolerance=0.1) except MIPSolverException: return finally: @@ -2717,12 +2684,8 @@ def _add_solution(self, solution): x_2: s(b) = b x_3: s(b) = a """ - active_vars = [self._x[p, z] - for p in _disjoint_set_roots(self._bijectionist._P) - for z in self._bijectionist._possible_block_values[p] - if solution[(p, z)]] - self.milp.add_constraint(sum(active_vars) <= len(active_vars) - 1, - name='veto') + active_vars = [self._x[p, z] for p in _disjoint_set_roots(self._bijectionist._P) for z in self._bijectionist._possible_block_values[p] if solution[(p, z)]] + self.milp.add_constraint(sum(active_vars) <= len(active_vars) - 1, name='veto') self._solution_cache.append(solution) def _is_solution(self, constraint, values): @@ -2758,9 +2721,7 @@ def _is_solution(self, constraint, values): index_block_value_dict[variable_index] = (p, z) def evaluate(f): - return sum(coeff if index == -1 else - coeff * values[index_block_value_dict[index]] - for index, coeff in f.dict().items()) + return sum(coeff if index == -1 else coeff * values[index_block_value_dict[index]] for index, coeff in f.dict().items()) if any(evaluate(lhs - rhs) for lhs, rhs in constraint.equations()): return False @@ -2813,8 +2774,7 @@ def add_alpha_beta_constraints(self): for w in range(len(W)): for z in range(len(Z)): - self.milp.add_constraint(AZ_matrix[z][w] == B_matrix[z][w], - name='statistics') + self.milp.add_constraint(AZ_matrix[z][w] == B_matrix[z][w], name='statistics') def add_distribution_constraints(self): r""" @@ -2931,19 +2891,15 @@ def add_intertwining_relation_constraints(self): if (p_tuple, p) not in pi_blocks: pi_blocks.add((p_tuple, p)) for z_tuple in itertools.product(*[tZ[p] for p in p_tuple]): - rhs = (1 - pi_rho.numargs - + sum(self._x[p_i, z_i] - for p_i, z_i in zip(p_tuple, z_tuple))) + rhs = 1 - pi_rho.numargs + sum(self._x[p_i, z_i] for p_i, z_i in zip(p_tuple, z_tuple)) z = pi_rho.rho(*z_tuple) if z in tZ[p]: c = self._x[p, z] - rhs if c.is_zero(): continue - self.milp.add_constraint(c >= 0, - name=f"pi/rho({composition_index})") + self.milp.add_constraint(c >= 0, name=f"pi/rho({composition_index})") else: - self.milp.add_constraint(rhs <= 0, - name=f"pi/rho({composition_index})") + self.milp.add_constraint(rhs <= 0, name=f"pi/rho({composition_index})") def add_quadratic_relation_constraints(self): r""" @@ -3031,13 +2987,12 @@ def add_homomesic_constraints(self): tZ = self._bijectionist._possible_block_values def sum_q(q): - return sum(sum(z * self._x[P.find(a), z] for z in tZ[P.find(a)]) - for a in q) + return sum(sum(z * self._x[P.find(a), z] for z in tZ[P.find(a)]) for a in q) + q0 = Q[0] v0 = sum_q(q0) for q in Q[1:]: - self.milp.add_constraint(len(q0) * sum_q(q) == len(q) * v0, - name=f"h: ({q})~({q0})") + self.milp.add_constraint(len(q0) * sum_q(q) == len(q) * v0, name=f"h: ({q})~({q0})") def _invert_dict(d): diff --git a/src/sage/combinat/binary_recurrence_sequences.py b/src/sage/combinat/binary_recurrence_sequences.py index 9453ab60cfc..d6ed543f4ed 100644 --- a/src/sage/combinat/binary_recurrence_sequences.py +++ b/src/sage/combinat/binary_recurrence_sequences.py @@ -246,18 +246,18 @@ def is_degenerate(self) -> bool: else: A = QuadraticField(D, 'x').gen() - aa = (self.u1 - self.u0 * (self.b + A)/2)/(A) # called `a` in Docstring - bb = (self.u1 - self.u0 * (self.b - A)/2)/(A) # called `b` in Docstring + aa = (self.u1 - self.u0 * (self.b + A) / 2) / (A) # called `a` in Docstring + bb = (self.u1 - self.u0 * (self.b - A) / 2) / (A) # called `b` in Docstring # (b+A)/2 is called alpha in Docstring, (b-A)/2 is called beta in Docstring if self.b != A: - if ((self.b+A)/(self.b-A))**6 == 1: + if ((self.b + A) / (self.b - A)) ** 6 == 1: return True else: return True - return aa*bb*(self.b + A)*(self.b - A) == 0 + return aa * bb * (self.b + A) * (self.b - A) == 0 return True @@ -284,7 +284,7 @@ def is_geometric(self) -> bool: # We decide if u0, u1, u2 = b*u1+c*u0 are in geometric progression by whether u1^2 = (b*u1+c*u0)*u0 - return (self.u1)**2 == (self.b*self.u1 + self.c*self.u0)*self.u0 + return (self.u1) ** 2 == (self.b * self.u1 + self.c * self.u0) * self.u0 def is_quasigeometric(self) -> bool: """ @@ -319,12 +319,12 @@ def is_quasigeometric(self) -> bool: # Otherwise test if alpha/beta is a root of unity that is not 1 D = self.b**2 + 4 * self.c - if D != 0: # thus alpha/beta != 1 + if D != 0: # thus alpha/beta != 1 if D.is_square(): A = sqrt(D) else: A = QuadraticField(D, 'x').gen() - if ((self.b+A)/(self.b-A))**6 == 1: + if ((self.b + A) / (self.b - A)) ** 6 == 1: return True return False @@ -446,9 +446,8 @@ def period(self, m, *, eventual=False): # m^2 must be in periodic part of the sequence. Hence, the # sequence starting with the terms numbered m^2 and m^2 + 1 must # be purely periodic. - an = (A**(m**2)) * w - return BinaryRecurrenceSequence(self.b, self.c, - an[0], an[1]).period(m, eventual=False) + an = (A ** (m**2)) * w + return BinaryRecurrenceSequence(self.b, self.c, an[0], an[1]).period(m, eventual=False) # To compute the period mod m, we compute the least integer n such that A^n*w == w. This necessarily # divides the order of A as a matrix in GL_2(Z/mZ). @@ -466,8 +465,8 @@ def period(self, m, *, eventual=False): else: F = A.change_ring(GF(p)) v = w.change_ring(GF(p)) - FF = F**(p-1) - p1fac = list((p-1).factor()) + FF = F ** (p - 1) + p1fac = list((p - 1).factor()) # The order of any matrix in GL_2(F_p) either divides p(p-1) or (p-1)(p+1). # The order divides p-1 if it is diagonalizable. In any case, det(F^(p-1))=1, @@ -478,20 +477,20 @@ def period(self, m, *, eventual=False): # these conditions hold for the period as well. # check if the order divides (p-1) - if FF*v == v: - M = p-1 + if FF * v == v: + M = p - 1 Mfac = p1fac # check if the trace is 2, then the order is a multiple of p dividing p*(p-1) elif FF.trace() == 2: - M = p-1 + M = p - 1 Mfac = p1fac - F = F**p # replace F by F^p as now we only need to determine the factor dividing (p-1) + F = F**p # replace F by F^p as now we only need to determine the factor dividing (p-1) # otherwise it will divide (p+1)(p-1) else: - M = (p+1)*(p-1) - p2fac = list((p+1).factor()) # factor the (p+1) and (p-1) terms separately and then combine for speed + M = (p + 1) * (p - 1) + p2fac = list((p + 1).factor()) # factor the (p+1) and (p-1) terms separately and then combine for speed Mfac_dic = {} for i0, i1 in list(p1fac + p2fac): if i0 not in Mfac_dic: @@ -522,26 +521,24 @@ def period(self, m, *, eventual=False): F = A.change_ring(Integers(p**e)) v = w.change_ring(Integers(p**e)) FF = F**perp - if FF*v == v: + if FF * v == v: perpe = perp else: tries = 0 while True: tries += 1 FF = FF**p - if FF*v == v: - perpe = perp*p**tries + if FF * v == v: + perpe = perp * p**tries break if tries > e: - raise ValueError("Binary recurrence sequence " + - f"modulo {m} is not a purely " + - "periodic sequence.") + raise ValueError("Binary recurrence sequence " + f"modulo {m} is not a purely " + "periodic sequence.") Periods[p] = perpe # take the lcm of the periods mod all distinct primes dividing m period = lcm(Periods.values()) - self._period_dict[m] = period # cache the period mod m + self._period_dict[m] = period # cache the period mod m return period def pthpowers(self, p, Bound): @@ -622,7 +619,7 @@ def pthpowers(self, p, Bound): if self.is_geometric() or self.is_quasigeometric(): no_powers = True - for i in range(1, 6*p+1): + for i in range(1, 6 * p + 1): if _is_p_power(self(i), p): no_powers = False break @@ -635,11 +632,11 @@ def pthpowers(self, p, Bound): # If the sequence is degenerate without being geometric or quasigeometric, there # may be many ``p`` th powers or no ``p`` th powers. - elif (self.b**2+4*self.c) == 0: + elif (self.b**2 + 4 * self.c) == 0: # This is the case if the matrix F is not diagonalizable, ie b^2 +4c = 0, and alpha/beta = 1. - alpha = self.b/2 + alpha = self.b / 2 # In this case, u_n = u_0*alpha^n + (u_1 - u_0*alpha)*n*alpha^(n-1) = alpha^(n-1)*(u_0 +n*(u_1 - u_0*alpha)), # that is, it is a geometric term (alpha^(n-1)) times an arithmetic term (u_0 + n*(u_1-u_0*alpha)). @@ -651,8 +648,8 @@ def pthpowers(self, p, Bound): # The linear equation alpha^(k-1)*u_0 + (k+pm)*(alpha^(k-1)*u1 - u0*alpha^k) # must thus be a pth power. This is a linear equation in m, namely, A + B*m, where - A = (alpha**(k-1)*self.u0 + k*(alpha**(k-1)*self.u1 - self.u0*alpha**k)) - B = p*(alpha**(k-1)*self.u1 - self.u0*alpha**k) + A = alpha ** (k - 1) * self.u0 + k * (alpha ** (k - 1) * self.u1 - self.u0 * alpha**k) + B = p * (alpha ** (k - 1) * self.u1 - self.u0 * alpha**k) # This linear equation represents a pth power iff A is a pth power mod B. @@ -700,19 +697,19 @@ def pthpowers(self, p, Bound): if _is_p_power(self(n), p): powers.append(n) - a0, a1 = a1, bf*a1 + cf*a0 # step up the variables + a0, a1 = a1, bf * a1 + cf * a0 # step up the variables else: - powers = [] # documents the indices of the sequence that provably correspond to pth powers - cong = [0] # list of necessary congruences on the index for it to correspond to pth powers - Possible_count = {} # keeps track of the number of rounds a congruence lasts in cong + powers = [] # documents the indices of the sequence that provably correspond to pth powers + cong = [0] # list of necessary congruences on the index for it to correspond to pth powers + Possible_count = {} # keeps track of the number of rounds a congruence lasts in cong # These parameters are involved in how we choose primes to increase the modulus - qqold = 1 # we believe that we know complete information coming from primes good by qqold - M1 = 1 # we have congruences modulo M1, this may not be the tightest list - M2 = p # we want to move to have congruences mod M2 - qq = 1 # the largest prime power divisor of M1 is qq + qqold = 1 # we believe that we know complete information coming from primes good by qqold + M1 = 1 # we have congruences modulo M1, this may not be the tightest list + M2 = p # we want to move to have congruences mod M2 + qq = 1 # the largest prime power divisor of M1 is qq # This loop ups the modulus. while True: @@ -720,8 +717,7 @@ def pthpowers(self, p, Bound): # Try to get good data mod M2 # patience of how long we should search for a "good prime" - patience = 0.01 * _estimated_time(lcm(M2, p * next_prime_power(qq)), - M1, len(cong), p) + patience = 0.01 * _estimated_time(lcm(M2, p * next_prime_power(qq)), M1, len(cong), p) tries = 0 # This loop uses primes to get a small set of congruences mod M2. @@ -736,24 +732,23 @@ def pthpowers(self, p, Bound): # makes a new list from cong that is now mod M = lcm(M1, modu) instead of M1 M = lcm(M1, modu) - CongNew = [k * M1 + i for k in range(M // M1) - for i in cong] + CongNew = [k * M1 + i for k in range(M // M1) for i in cong] cong = set(CongNew) M1 = M - killed_something = False # keeps track of when cong1 can rule out a congruence in cong + killed_something = False # keeps track of when cong1 can rule out a congruence in cong # CRT by hand to gain speed for i in list(cong): - if i % modu not in cong1: # congruence in cong is inconsistent with any in cong1 - cong.remove(i) # remove that congruence + if i % modu not in cong1: # congruence in cong is inconsistent with any in cong1 + cong.remove(i) # remove that congruence killed_something = True if M1 == M2: if not killed_something: tries += 1 - if tries == 2: # try twice to rule out congruences + if tries == 2: # try twice to rule out congruences cong = list(cong) qqold = qq qq = next_prime_power(qq) @@ -918,14 +913,13 @@ def _next_good_prime(p, R, qq, patience, qqold): # Possible_Primes keeps track of possible primes satisfying our goodness requirements we might return # check to see if anything in R._PGoodness fits our goodness requirements - Possible_Primes = [item[0] for j, item in R._PGoodness.items() - if qqold < j <= qq and item] + Possible_Primes = [item[0] for j, item in R._PGoodness.items() if qqold < j <= qq and item] # If we found good primes, we take the smallest if Possible_Primes: q = min(Possible_Primes) n = _goodness(q, R, p) - del R._PGoodness[n][0] # if we are going to use it, then we delete it from R._PGoodness + del R._PGoodness[n][0] # if we are going to use it, then we delete it from R._PGoodness return q # If nothing is already stored in R._PGoodness, we start (from where we left off at R._ell) checking @@ -941,7 +935,7 @@ def _next_good_prime(p, R, qq, patience, qqold): # requiring that b^2 + 4c is a square in GF(R._ell) ensures that the period mod R._ell # divides R._ell - 1 - if legendre_symbol(R.b**2 + 4*R.c, R._ell) == 1: + if legendre_symbol(R.b**2 + 4 * R.c, R._ell) == 1: N = _goodness(R._ell, R, p) @@ -1023,7 +1017,7 @@ def _is_p_power_mod(a, p, N): # otherwise aa if a pth power mod q iff aa^(q-1)/p == 1 - if GF(q)(aa)**((q - 1) / p) != 1: + if GF(q)(aa) ** ((q - 1) / p) != 1: return False # If q = p and ee = 1, then everything is a pth power p by Fermat's little theorem. @@ -1038,7 +1032,7 @@ def _is_p_power_mod(a, p, N): # ZZ/(p^2)ZZ^\times is abstractly isomorphic to ZZ/(p)ZZ cross ZZ/(p-1)ZZ. then # aa is a pth power mod p^2 if (aa)^(p*(p-1)/p) == 1, ie if aa^(p-1) == 1. - if Integers(p**2)(aa)**(p - 1) != 1: + if Integers(p**2)(aa) ** (p - 1) != 1: return False # Otherwise, p=2. By the strong statement of Hensel's lemma, if aa is a pth power @@ -1089,7 +1083,7 @@ def _estimated_time(M2, M1, length, p): Q = p * log(M2) # Size of our primes. NPrimes = log(M2 / M1) / log(Q) # The number of primes - return (length * (Q / p)**NPrimes).n() + return (length * (Q / p) ** NPrimes).n() # Find the list of necessary congruences for the index n of binary recurrence @@ -1121,7 +1115,7 @@ def _find_cong1(p, R, ell): u1 = F(R.u1) bf, cf = F(R.b), F(R.c) a0 = u0 - a1 = u1 # a0 and a1 are variables for terms in sequence + a1 = u1 # a0 and a1 are variables for terms in sequence # The set of pth powers mod ell PPowers = set(i**p for i in F) @@ -1140,7 +1134,7 @@ def _find_cong1(p, R, ell): # to the list of necessary congruences cong1.append(n) - a0, a1 = a1, bf * a1 + cf * a0 # step up the variables + a0, a1 = a1, bf * a1 + cf * a0 # step up the variables cong1.sort() diff --git a/src/sage/combinat/binary_tree.py b/src/sage/combinat/binary_tree.py index a95c67a6ffd..339cfaa7a71 100644 --- a/src/sage/combinat/binary_tree.py +++ b/src/sage/combinat/binary_tree.py @@ -14,6 +14,7 @@ - Florent Hivert (2010-2011): initial implementation. - Adrien Boussicault (2015): Hook statistics. """ + # **************************************************************************** # Copyright (C) 2010 Florent Hivert , # @@ -23,8 +24,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** from sage.structure.list_clone import ClonableArray -from sage.combinat.abstract_tree import (AbstractClonableTree, - AbstractLabelledClonableTree) +from sage.combinat.abstract_tree import AbstractClonableTree, AbstractLabelledClonableTree from sage.combinat.ordered_tree import LabelledOrderedTrees from sage.rings.integer import Integer from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass @@ -40,8 +40,7 @@ from sage.misc.cachefunc import cached_method -class BinaryTree(AbstractClonableTree, ClonableArray, - metaclass=InheritComparisonClasscallMetaclass): +class BinaryTree(AbstractClonableTree, ClonableArray, metaclass=InheritComparisonClasscallMetaclass): """ Binary trees. @@ -100,6 +99,7 @@ class BinaryTree(AbstractClonableTree, ClonableArray, sage: t1 == t1c False """ + @staticmethod def __classcall_private__(cls, *args, **opts): """ @@ -179,6 +179,7 @@ def __init__(self, parent, children=None, check=True): if isinstance(children, str): # if the input is the repr of a binary tree children = children.replace(".", "None") from ast import literal_eval + children = literal_eval(children) if children is None: @@ -186,17 +187,13 @@ def __init__(self, parent, children=None, check=True): elif isinstance(children, (list, tuple)) and not children: E = self.__class__(parent, None, check=check) children = [E, E] - elif (children.__class__ is self.__class__ and - children.parent() == parent): + elif children.__class__ is self.__class__ and children.parent() == parent: children = list(children) else: children = list(children) if children and len(children) != 2: raise ValueError('this is not a binary tree') - children = [x if (x.__class__ is self.__class__ and - x.parent() == parent) - else self.__class__(parent, x, check=check) - for x in children] + children = [x if (x.__class__ is self.__class__ and x.parent() == parent) else self.__class__(parent, x, check=check) for x in children] ClonableArray.__init__(self, parent, children, check=check) def check(self): @@ -386,14 +383,17 @@ def _ascii_art_(self): / \ / \ o o o o """ + def node_to_str(bt): return str(bt.label()) if hasattr(bt, "label") else "o" if self.is_empty(): from sage.typeset.ascii_art import empty_ascii_art + return empty_ascii_art from sage.typeset.ascii_art import AsciiArt + if self[0].is_empty() and self[1].is_empty(): bt_repr = AsciiArt([node_to_str(self)]) bt_repr._root = 1 @@ -589,14 +589,17 @@ def _unicode_art_(self): ╱ ╲ ╱ ╲ o o o o """ + def node_to_str(bt): return str(bt.label()) if hasattr(bt, "label") else "o" if self.is_empty(): from sage.typeset.unicode_art import empty_unicode_art + return empty_unicode_art from sage.typeset.unicode_art import UnicodeArt + if self[0].is_empty() and self[1].is_empty(): bt_repr = UnicodeArt([node_to_str(self)]) bt_repr._root = 1 @@ -746,7 +749,7 @@ def graph(self, with_leaves=True): """ from sage.graphs.digraph import DiGraph - if with_leaves: # We want leaves and nodes. + if with_leaves: # We want leaves and nodes. # Special treatment for the case when self is empty. # In this case, rec(self, 0) would give a false result. @@ -848,6 +851,7 @@ def canonical_labelling(self, shift=1): sage: BinaryTree([[[], [[], None]], [[], []]]).canonical_labelling() 5[2[1[., .], 4[3[., .], .]], 7[6[., .], 8[., .]]] """ + def aux(tree, LTR, curlabel): if not tree: return LTR(None) @@ -1067,6 +1071,7 @@ def tamari_interval(self, other): [.] """ from sage.combinat.interval_posets import TamariIntervalPosets + return TamariIntervalPosets.from_binary_trees(self, other) def tamari_join(self, other): @@ -1301,6 +1306,7 @@ def to_dyck_word(self, usemap='1L0R'): True """ from sage.combinat.dyck_word import DyckWord + if usemap not in ["1L0R", "1R0L", "L1R0", "R1L0"]: raise ValueError("%s is not a correct map" % usemap) return DyckWord(self._to_dyck_word_rec(usemap)) @@ -1330,19 +1336,17 @@ def _to_ordered_tree(self, bijection='left', root=None): close_root = False if root is None: from sage.combinat.ordered_tree import OrderedTree + root = OrderedTree().clone() close_root = True if self: left, right = self[0], self[1] if bijection == "left": root = left._to_ordered_tree(bijection=bijection, root=root) - root.append(right._to_ordered_tree(bijection=bijection, - root=None)) + root.append(right._to_ordered_tree(bijection=bijection, root=None)) elif bijection == "right": - root.append(left._to_ordered_tree(bijection=bijection, - root=None)) - root = right._to_ordered_tree(bijection=bijection, - root=root) + root.append(left._to_ordered_tree(bijection=bijection, root=None)) + root = right._to_ordered_tree(bijection=bijection, root=root) else: raise ValueError("the bijection argument should be either left or right") if close_root: @@ -1507,6 +1511,7 @@ def to_312_avoiding_permutation(self): True """ from sage.combinat.permutation import Permutation + return Permutation(self._postfix_word()) @combinatorial_map(name="To complete tree") @@ -1539,8 +1544,10 @@ def as_ordered_tree(self, with_leaves=True): children = [child.as_ordered_tree(with_leaves) for child in self if not child.is_empty()] if self in LabelledBinaryTrees(): from sage.combinat.ordered_tree import LabelledOrderedTree + return LabelledOrderedTree(children, label=self.label()) from sage.combinat.ordered_tree import OrderedTree + return OrderedTree(children) @combinatorial_map(name="To graph") @@ -1587,6 +1594,7 @@ def to_undirected_graph(self, with_leaves=False): if (not with_leaves) and (not self): # this case needs extra care :( from sage.graphs.graph import Graph + return Graph([]) return self.as_ordered_tree(with_leaves).to_undirected_graph() @@ -1726,6 +1734,7 @@ def to_poset(self, with_leaves=False, root_to_leaf=False): if (not with_leaves) and (not self): # this case needs extra care :( from sage.combinat.posets.posets import Poset + return Poset({}) return self.as_ordered_tree(with_leaves).to_poset(root_to_leaf) @@ -1757,6 +1766,7 @@ def to_132_avoiding_permutation(self): True """ from sage.combinat.permutation import Permutation + return Permutation(self._postfix_word(left_first=False)) def number_of_left_nodes(self, direction='left'): @@ -1956,6 +1966,7 @@ def add_leaf_rec(tr): add_leaf_rec(tr[i]) else: res.append(1 - i) + add_leaf_rec(self) return res[1:-1] @@ -2128,6 +2139,7 @@ def in_order_traversal(self, node_action=None, leaf_action=None): def leaf_action(x): return None + if node_action is None: def node_action(x): @@ -2299,6 +2311,7 @@ def tamari_greater(self): [[[., [., .]], .], .], [[[[., .], .], .], .]] """ from sage.combinat.tools import transitive_ideal + return transitive_ideal(lambda x: x.tamari_succ(), self) def tamari_pred(self): @@ -2350,9 +2363,7 @@ def tamari_pred(self): else: res = [] B = self.parent()._element_constructor_ - return (res + - [B([g, s1], check=False) for g in s0.tamari_pred()] + - [B([s0, d], check=False) for d in s1.tamari_pred()]) + return res + [B([g, s1], check=False) for g in s0.tamari_pred()] + [B([s0, d], check=False) for d in s1.tamari_pred()] def tamari_smaller(self): r""" @@ -2410,6 +2421,7 @@ def tamari_smaller(self): [[[[[., .], .], .], .]] """ from sage.combinat.tools import transitive_ideal + return transitive_ideal(lambda x: x.tamari_pred(), self) def tamari_succ(self): @@ -2463,9 +2475,7 @@ def tamari_succ(self): B = self.parent()._element_constructor_ if not self[0].is_empty(): res.append(self.right_rotate()) - return (res + - [B([g, self[1]]) for g in self[0].tamari_succ()] + - [B([self[0], d]) for d in self[1].tamari_succ()]) + return res + [B([g, self[1]]) for g in self[0].tamari_succ()] + [B([self[0], d]) for d in self[1].tamari_succ()] def single_edge_cut_shapes(self): r""" @@ -2515,12 +2525,10 @@ def single_edge_cut_shapes(self): L = left.number_of_nodes() R = right.number_of_nodes() if L: - resu += [(m + R + 1, i, n) - for m, i, n in left.single_edge_cut_shapes()] + resu += [(m + R + 1, i, n) for m, i, n in left.single_edge_cut_shapes()] resu += [(R + 1, 1, L)] if R: - resu += [(m + L + 1, i + L + 1, n) - for m, i, n in right.single_edge_cut_shapes()] + resu += [(m + L + 1, i + L + 1, n) for m, i, n in right.single_edge_cut_shapes()] resu += [(L + 1, L + 2, R)] return resu @@ -2604,6 +2612,7 @@ def _comb(side): res.append(tree[1 - side]) tree = tree[side] return res + if side == 'left': return _comb(0) if side == 'right': @@ -2662,8 +2671,7 @@ def hook_number(self): """ if self.is_empty(): return 0 - return 1 + sum(t.hook_number() - for t in self.comb('left') + self.comb('right')) + return 1 + sum(t.hook_number() for t in self.comb('left') + self.comb('right')) def twisting_number(self): r""" @@ -2895,34 +2903,29 @@ def q_hook_length_fraction(self, q=None, q_factor=False): if q is None: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.integer_ring import ZZ + basering = PolynomialRing(ZZ, 'q') q = basering.gen() else: basering = q.base_ring() if q_factor: + def product_of_subtrees(b): if b.is_empty(): return basering.one() b0 = b[0] b1 = b[1] - return (q_binomial(b.number_of_nodes() - 1, - b0.number_of_nodes(), - q=q) - * product_of_subtrees(b0) - * product_of_subtrees(b1) - * q ** b1.number_of_nodes()) + return q_binomial(b.number_of_nodes() - 1, b0.number_of_nodes(), q=q) * product_of_subtrees(b0) * product_of_subtrees(b1) * q ** b1.number_of_nodes() + else: + def product_of_subtrees(b): if b.is_empty(): return basering.one() b0 = b[0] b1 = b[1] - return (q_binomial(b.number_of_nodes() - 1, - b0.number_of_nodes(), - q=q) - * product_of_subtrees(b0) - * product_of_subtrees(b1)) + return q_binomial(b.number_of_nodes() - 1, b0.number_of_nodes(), q=q) * product_of_subtrees(b0) * product_of_subtrees(b1) return product_of_subtrees(self) @@ -3436,6 +3439,7 @@ def dendriform_shuffle(self, other): """ from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 from sage.combinat.words.word import Word + if self.is_empty(): yield other elif other.is_empty(): @@ -3603,21 +3607,20 @@ def sylvester_class(self, left_to_right=False): return from itertools import product from sage.combinat.words.word import Word as W - from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 \ - as shuffle + from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 as shuffle if left_to_right: def builder(i, p): return [i] + list(p) + else: def builder(i, p): return list(p) + [i] shift = self[0].number_of_nodes() + 1 - for l, r in product(self[0].sylvester_class(left_to_right=left_to_right), - self[1].sylvester_class(left_to_right=left_to_right)): + for l, r in product(self[0].sylvester_class(left_to_right=left_to_right), self[1].sylvester_class(left_to_right=left_to_right)): for p in shuffle(W(l), W([shift + ri for ri in r])): yield builder(shift, p) @@ -3980,6 +3983,7 @@ class BinaryTrees(UniqueRepresentation, Parent): is an implementation detail. It could be changed in the future and one should not rely on it. """ + @staticmethod def __classcall_private__(cls, n=None, full=False): """ @@ -4065,8 +4069,8 @@ def from_tamari_sorting_tuple(key): if v == n - i - 1: break - return BinaryTree([from_tamari_sorting_tuple(key[: i]), - from_tamari_sorting_tuple(key[i + 1:])]) + return BinaryTree([from_tamari_sorting_tuple(key[:i]), from_tamari_sorting_tuple(key[i + 1 :])]) + ################################################################# # Enumerated set of all binary trees @@ -4096,9 +4100,7 @@ def __init__(self): True sage: TestSuite(B).run() # long time """ - DisjointUnionEnumeratedSets.__init__( - self, Family(NonNegativeIntegers(), BinaryTrees_size), - facade=True, keepkey=False) + DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), BinaryTrees_size), facade=True, keepkey=False) def _repr_(self): """ @@ -4198,8 +4200,7 @@ def __init__(self, size): sage: S is BinaryTrees(3) True """ - super().__init__(facade=BinaryTrees_all(), - category=FiniteEnumeratedSets()) + super().__init__(facade=BinaryTrees_all(), category=FiniteEnumeratedSets()) self._size = size def _repr_(self): @@ -4246,6 +4247,7 @@ def cardinality(self): 42 """ from .combinat import catalan_number + return catalan_number(self._size) def random_element(self): @@ -4271,6 +4273,7 @@ def random_element(self): True """ from sage.combinat.dyck_word import CompleteDyckWords_size + dw = CompleteDyckWords_size(self._size).random_element() return dw.to_binary_tree_tamari() @@ -4323,6 +4326,7 @@ def _element_constructor_(self, *args, **keywords): # Enumerated set of all full binary trees ################################################################# + class FullBinaryTrees_all(DisjointUnionEnumeratedSets, BinaryTrees): """ All full binary trees. @@ -4349,9 +4353,7 @@ def __init__(self): True sage: TestSuite(FB).run() # long time """ - DisjointUnionEnumeratedSets.__init__( - self, Family(NonNegativeIntegers(), _full_construction), - facade=True, keepkey=False) + DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), _full_construction), facade=True, keepkey=False) def _repr_(self): """ @@ -4395,6 +4397,7 @@ def _element_constructor_(self, *args, **keywords): raise ValueError("not full") return res + ################################################################# # Enumerated set of full binary trees of a given size ################################################################# @@ -4434,8 +4437,7 @@ def __init__(self, size): sage: for i in range(1,6): ....: TestSuite(BinaryTrees(2*i-1, full=True)).run() """ - super().__init__(facade=BinaryTrees_all(), - category=FiniteEnumeratedSets()) + super().__init__(facade=BinaryTrees_all(), category=FiniteEnumeratedSets()) self._size = size def _repr_(self): @@ -4461,9 +4463,7 @@ def __contains__(self, x): sage: BinaryTree([None, []]) in FB3 False """ - return (isinstance(x, BinaryTree) - and x.number_of_nodes() == self._size - and x.is_full()) + return isinstance(x, BinaryTree) and x.number_of_nodes() == self._size and x.is_full() def _an_element_(self): r""" @@ -4499,6 +4499,7 @@ def cardinality(self): if self._size == 0: return Integer(1) from sage.combinat.combinat import catalan_number + return catalan_number((self._size - 1) // 2) def random_element(self): @@ -4526,6 +4527,7 @@ def random_element(self): True """ from sage.combinat.dyck_word import CompleteDyckWords_size + if self._size == 0: return BinaryTree(None) dw = CompleteDyckWords_size((self._size - 1) // 2).random_element() @@ -4710,6 +4712,7 @@ class LabelledBinaryTree(AbstractLabelledClonableTree, BinaryTree): sage: t2.__class__, t2[0].__class__ (, ) """ + @staticmethod def __classcall_private__(cls, *args, **opts): """ @@ -5269,8 +5272,7 @@ def binary_search_tree_shape(w, left_to_right=True): root = w[-1] left = [x for x in w if x < root] right = [x for x in w if x > root] - return BinaryTree([binary_search_tree_shape(left, left_to_right), - binary_search_tree_shape(right, left_to_right)]) + return BinaryTree([binary_search_tree_shape(left, left_to_right), binary_search_tree_shape(right, left_to_right)]) ################################################################ diff --git a/src/sage/combinat/blob_algebra.py b/src/sage/combinat/blob_algebra.py index 85128cfd7b0..d3d99df581c 100644 --- a/src/sage/combinat/blob_algebra.py +++ b/src/sage/combinat/blob_algebra.py @@ -19,8 +19,7 @@ from sage.categories.algebras import Algebras from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.combinat.diagram_algebras import (TemperleyLiebDiagrams, diagram_latex, - TL_diagram_ascii_art) +from sage.combinat.diagram_algebras import TemperleyLiebDiagrams, diagram_latex, TL_diagram_ascii_art from sage.combinat.dyck_word import DyckWords from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.subset import powerset @@ -71,10 +70,7 @@ def _repr_(self): sage: BD4([[1,-3]], [[2,-4], [3,4], [-1,-2]]) ({{-3, 1}}, {{-4, 2}, {-2, -1}, {3, 4}}) """ - return '({{{}}}, {{{}}})'.format(', '.join('{' + repr(X)[1:-1] + '}' - for X in self.marked), - ', '.join('{' + repr(X)[1:-1] + '}' - for X in self.unmarked)) + return '({{{}}}, {{{}}})'.format(', '.join('{' + repr(X)[1:-1] + '}' for X in self.marked), ', '.join('{' + repr(X)[1:-1] + '}' for X in self.unmarked)) def __hash__(self): r""" @@ -130,9 +126,7 @@ def _richcmp_(self, other, op): ({{-1, 3}, {1, 2}}, {{-3, -2}}), ({{-3, 3}, {-2, -1}, {1, 2}}, {})] """ - return richcmp((len(self.marked), self.marked, self.unmarked), - (len(other.marked), other.marked, other.unmarked), - op) + return richcmp((len(self.marked), self.marked, self.unmarked), (len(other.marked), other.marked, other.unmarked), op) def temperley_lieb_diagram(self): r""" @@ -354,14 +348,14 @@ def __iter__(self): unmarked = [] unpaired = [] # Determine the pairing and which pairings are markable - for i,d in enumerate(D): + for i, d in enumerate(D): if i >= self._n: - i = -2*self._n + i + i = -2 * self._n + i else: i += 1 if d == 1: unpaired.append(i) - else: # d == 0 + else: # d == 0 m = unpaired.pop() if not unpaired: markable.add((m, i)) @@ -414,6 +408,7 @@ class BlobAlgebra(CombinatorialFreeModule): - [MS1994]_ - [ILZ2018]_ """ + @staticmethod def __classcall_private__(cls, k, q1, q2, q3, base_ring=None, prefix='B'): r""" @@ -453,8 +448,7 @@ def __init__(self, k, q1, q2, q3, base_ring, prefix): self._q3 = q3 diagrams = BlobDiagrams(k) cat = Algebras(base_ring.category()).FiniteDimensional().WithBasis() - CombinatorialFreeModule.__init__(self, base_ring, diagrams, category=cat, - prefix=prefix, bracket=False) + CombinatorialFreeModule.__init__(self, base_ring, diagrams, category=cat, prefix=prefix, bracket=False) def _ascii_art_term(self, diagram): r""" @@ -471,8 +465,7 @@ def _ascii_art_term(self, diagram): .-. .0. .-. o o o o o o """ - return TL_diagram_ascii_art(diagram.marked+diagram.unmarked, use_unicode=False, - blobs=diagram.marked) + return TL_diagram_ascii_art(diagram.marked + diagram.unmarked, use_unicode=False, blobs=diagram.marked) def _unicode_art_term(self, diagram): r""" @@ -489,8 +482,7 @@ def _unicode_art_term(self, diagram): ╭─╮ ╭●╮ ╭─╮ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ """ - return TL_diagram_ascii_art(diagram.marked+diagram.unmarked, use_unicode=True, - blobs=diagram.marked) + return TL_diagram_ascii_art(diagram.marked + diagram.unmarked, use_unicode=True, blobs=diagram.marked) def _latex_term(self, diagram): r""" @@ -529,6 +521,7 @@ def _latex_term(self, diagram): \draw[] (G--2) .. controls +(-0.5, 0.5) and +(0.5, 0.5) .. (G--1); \end{tikzpicture} """ + def edge_options(P): if P[1] < P[0]: P = [P[1], P[0]] @@ -542,9 +535,8 @@ def edge_additions(P): if tuple(P) in diagram.marked: return 'node[midway,circle,fill,scale=0.6] {} ' return '' - return diagram_latex(diagram.marked+diagram.unmarked, - edge_options=edge_options, - edge_additions=edge_additions) + + return diagram_latex(diagram.marked + diagram.unmarked, edge_options=edge_options, edge_additions=edge_additions) def order(self): r""" @@ -575,7 +567,7 @@ def one_basis(self): ({}, {{-4, 4}, {-3, 3}, {-2, 2}, {-1, 1}}) """ B = self._indices - return B.element_class(B, [], [[i, -i] for i in range(1, self.order()+1)]) + return B.element_class(B, [], [[i, -i] for i in range(1, self.order() + 1)]) def product_on_basis(self, top, bot): r""" @@ -609,7 +601,7 @@ def product_on_basis(self, top, bot): # We are starting a new strand cur, stop = top_set.pop() # note that cur < stop unmarked = is_unmarked - #print(top_set, unmarked, cur, stop) + # print(top_set, unmarked, cur, stop) if cur > 0: # Both are anchored to the top ret_lists[unmarked].append((cur, stop)) continue @@ -618,7 +610,7 @@ def product_on_basis(self, top, bot): # Follow the path from cur until we either reach stop or # we break out of the loop because both ends are anchored while anchored or cur != stop: - #print(anchored, unmarked, cur, stop) + # print(anchored, unmarked, cur, stop) cur = -cur # Move cur to the bottom diagram for X in bot_marked: if cur in X: @@ -627,13 +619,13 @@ def product_on_basis(self, top, bot): else: coeff *= self._q2 prev = cur - cur = X[1-X.index(prev)] + cur = X[1 - X.index(prev)] bot_marked.remove(X) break for X in bot_unmarked: if cur in X: prev = cur - cur = X[1-X.index(prev)] + cur = X[1 - X.index(prev)] bot_unmarked.remove(X) break if cur < 0: # cur is anchored at the bottom @@ -642,7 +634,7 @@ def product_on_basis(self, top, bot): break else: anchored = True - stop, cur = cur, stop # stop is now anchored to the bottom + stop, cur = cur, stop # stop is now anchored to the bottom continue cur = -cur # bring cur back to the top diagram for X in top_marked: @@ -652,13 +644,13 @@ def product_on_basis(self, top, bot): else: coeff *= self._q2 prev = cur - cur = X[1-X.index(prev)] + cur = X[1 - X.index(prev)] top_marked.remove(X) break for X in top_unmarked: if cur in X: prev = cur - cur = X[1-X.index(prev)] + cur = X[1 - X.index(prev)] top_unmarked.remove(X) break if cur > 0: # cur is anchored at the top @@ -667,7 +659,7 @@ def product_on_basis(self, top, bot): break else: anchored = True - stop, cur = cur, stop # stop is now anchored to the top + stop, cur = cur, stop # stop is now anchored to the top if cur == stop: # We have found a (marked) loop if unmarked: coeff *= self._q1 diff --git a/src/sage/combinat/cartesian_product.py b/src/sage/combinat/cartesian_product.py index 2be7fb63dab..051e0ef1c69 100644 --- a/src/sage/combinat/cartesian_product.py +++ b/src/sage/combinat/cartesian_product.py @@ -1,6 +1,7 @@ r""" Cartesian products """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # @@ -106,11 +107,9 @@ def iterfunc(): # we can not use self.__iterate__ directly because # that leads to an infinite recursion in __eq__ return self.__iterate__() + name = "Cartesian product of " + ", ".join(map(str, self.iters)) - EnumeratedSetFromIterator.__init__(self, iterfunc, - name=name, - category=category, - cache=False) + EnumeratedSetFromIterator.__init__(self, iterfunc, name=name, category=category, cache=False) def __hash__(self): r""" diff --git a/src/sage/combinat/chas/all.py b/src/sage/combinat/chas/all.py index cc4da145e9a..e84b5b17e03 100644 --- a/src/sage/combinat/chas/all.py +++ b/src/sage/combinat/chas/all.py @@ -10,8 +10,10 @@ - :ref:`sage.combinat.grossman_larson_algebras` - :ref:`sage.combinat.chas.wqsym` """ + # install the docstring of this module to the containing package from sage.misc.namespace_package import install_doc + install_doc(__package__, __doc__) from sage.misc.lazy_import import lazy_import diff --git a/src/sage/combinat/chas/fsym.py b/src/sage/combinat/chas/fsym.py index f16de16e544..7b700c2ac57 100644 --- a/src/sage/combinat/chas/fsym.py +++ b/src/sage/combinat/chas/fsym.py @@ -41,6 +41,7 @@ class FSymBasis_abstract(CombinatorialFreeModule, BindableClass): - ``_prefix`` -- the basis prefix """ + def __init__(self, alg, graded=True): r""" Initialize ``self``. @@ -69,10 +70,7 @@ def __init__(self, alg, graded=True): F[12|3] : -F[12|3] F[1|2|3] : -F[123] """ - CombinatorialFreeModule.__init__(self, alg.base_ring(), - StandardTableaux(), - category=FSymBases(alg), - bracket='', prefix=self._prefix) + CombinatorialFreeModule.__init__(self, alg.base_ring(), StandardTableaux(), category=FSymBases(alg), bracket='', prefix=self._prefix) def _coerce_map_from_(self, R): r""" @@ -144,8 +142,7 @@ def _coerce_map_from_(self, R): FSym = self.realization_of() if R.realization_of() == FSym: return True - if (isinstance(R.realization_of(), FreeSymmetricFunctions) != - isinstance(FSym, FreeSymmetricFunctions)): + if isinstance(R.realization_of(), FreeSymmetricFunctions) != isinstance(FSym, FreeSymmetricFunctions): # If they are dual bases, then no coercion return False if not self.base_ring().has_coerce_map_from(R.base_ring()): @@ -155,6 +152,7 @@ def _coerce_map_from_(self, R): def coerce_base_ring(self, x): return self._from_dict(x.monomial_coefficients()) + return coerce_base_ring # Otherwise lift that basis up and then coerce over target = getattr(FSym, R._realization_name())() @@ -193,9 +191,7 @@ def _repr_term(self, phi): sage: G[[1,3,5],[2,4]] G[135|24] """ - return "{}[{}]".format(self._prefix, - "|".join("".join(map(str, block)) - for block in phi)) + return "{}[{}]".format(self._prefix, "|".join("".join(map(str, block)) for block in phi)) class FSymBases(Category_realization_of_parent): @@ -203,6 +199,7 @@ class FSymBases(Category_realization_of_parent): The category of graded bases of `FSym` and `FSym^*` indexed by standard tableaux. """ + def super_categories(self): """ The super categories of ``self``. @@ -220,9 +217,7 @@ def super_categories(self): Category of graded connected Hopf algebras with basis over Integer Ring] """ R = self.base().base_ring() - return [self.base().Realizations(), - HopfAlgebras(R).Graded().Realizations(), - HopfAlgebras(R).Graded().WithBasis().Graded().Connected()] + return [self.base().Realizations(), HopfAlgebras(R).Graded().Realizations(), HopfAlgebras(R).Graded().WithBasis().Graded().Connected()] class ParentMethods: def _repr_(self): @@ -286,6 +281,7 @@ def basis(self, degree=None): [G[123], G[13|2], G[12|3], G[1|2|3]] """ from sage.sets.family import Family + if degree is None: return Family(self._indices, self.monomial) return Family(StandardTableaux(degree), self.monomial) @@ -368,10 +364,9 @@ def duality_pairing_matrix(self, basis, degree): [0 0 0 1] """ from sage.matrix.constructor import matrix + keys = self.basis(degree=degree).keys() - return matrix(self.base_ring(), - [[self.duality_pairing(self[s], basis[t]) - for t in keys] for s in keys]) + return matrix(self.base_ring(), [[self.duality_pairing(self[s], basis[t]) for t in keys] for s in keys]) def degree_on_basis(self, t): """ @@ -484,6 +479,7 @@ class FreeSymmetricFunctions(UniqueRepresentation, Parent): sage: TG[t].to_symmetric_function() s[2, 2, 1] """ + def __init__(self, base_ring): r""" TESTS:: @@ -554,6 +550,7 @@ class Fundamental(FSymBasis_abstract): sage: TG = FSym.G() sage: TestSuite(TG).run() """ + _prefix = "G" def _coerce_map_from_(self, R): @@ -623,14 +620,15 @@ def _coerce_map_from_(self, R): A = R.realization_of() # NSym to FSym from sage.combinat.ncsf_qsym.ncsf import NonCommutativeSymmetricFunctions + if isinstance(A, NonCommutativeSymmetricFunctions): ribbon = A.ribbon() if R is ribbon: ST = self._indices def R_to_G_on_basis(alpha): - return self.sum_of_monomials(ST(t) for t in StandardTableaux(alpha.size()) - if descent_composition(t) == alpha) + return self.sum_of_monomials(ST(t) for t in StandardTableaux(alpha.size()) if descent_composition(t) == alpha) + return ribbon.module_morphism(R_to_G_on_basis, codomain=self) return self._coerce_map_via([ribbon], R) return super()._coerce_map_from_(R) @@ -674,9 +672,7 @@ def product_on_basis(self, t1, t2): """ n = t1.size() m = n + t2.size() - tableaux = [t for t in StandardTableaux(m) - if t.restrict(n) == t1 - and standardize(t.anti_restrict(n).rectify()) == t2] + tableaux = [t for t in StandardTableaux(m) if t.restrict(n) == t1 and standardize(t.anti_restrict(n).rectify()) == t2] return self.sum_of_monomials(tableaux) @cached_method @@ -724,6 +720,7 @@ def to_fqsym(self): + G[4, 1, 5, 3, 2] + G[4, 2, 5, 3, 1] """ from sage.combinat.fqsym import FreeQuasisymmetricFunctions + R = self.parent().base_ring() G = FreeQuasisymmetricFunctions(R).G() return G(self) @@ -789,6 +786,7 @@ class FreeSymmetricFunctions_Dual(UniqueRepresentation, Parent): sage: TF(F[[5, 1, 4, 2, 3]]) F[135|2|4] """ + def __init__(self, base_ring) -> None: r""" Initialize ``self``. @@ -862,6 +860,7 @@ class FundamentalDual(FSymBasis_abstract): sage: TF = FSym.dual().F() sage: TestSuite(TF).run() """ + _prefix = "F" def _coerce_map_from_(self, R): @@ -946,11 +945,14 @@ def _coerce_map_from_(self, R): A = R.realization_of() # FQSym to FSym^* from sage.combinat.fqsym import FreeQuasisymmetricFunctions + if isinstance(A, FreeQuasisymmetricFunctions): F = A.F() if R is F: + def F_to_SF_on_basis(sigma): return self.monomial(sigma.right_tableau()) + return F.module_morphism(F_to_SF_on_basis, codomain=self) return self._coerce_map_via([F], R) @@ -958,8 +960,10 @@ def F_to_SF_on_basis(sigma): if isinstance(A, SymmetricFunctions): s = A.s() if R is s: + def s_to_F_on_basis(mu): return self.sum_of_monomials(StandardTableaux(mu)) + return s.module_morphism(s_to_F_on_basis, codomain=self) return self._coerce_map_via([s], R) return super()._coerce_map_from_(R) @@ -997,6 +1001,7 @@ def product_on_basis(self, t1, t2): npmp1 = n + m + 1 ST = self._indices from itertools import combinations + for I in combinations(range(1, npmp1), n): J = [j for j in range(1, npmp1) if (j not in I)] tt1 = [[I[x - 1] for x in row] for row in t1] @@ -1016,8 +1021,7 @@ def coproduct_on_basis(self, t): F[] # F[125|34] + F[1] # F[134|2] + F[12] # F[123] + F[12|3] # F[12] + F[12|34] # F[1] + F[125|34] # F[] """ - terms = [(t.restrict(i), standardize(t.anti_restrict(i).rectify())) - for i in range(t.size() + 1)] + terms = [(t.restrict(i), standardize(t.anti_restrict(i).rectify())) for i in range(t.size() + 1)] return self.tensor_square().sum_of_monomials(terms) class Element(FSymBasis_abstract.Element): @@ -1040,15 +1044,16 @@ def to_quasisymmetric_function(self): F[1, 2, 2] """ from sage.combinat.ncsf_qsym.qsym import QuasiSymmetricFunctions + QF = QuasiSymmetricFunctions(self.base_ring()).Fundamental() - return QF.sum_of_terms((descent_composition(t), coeff) - for t, coeff in self) + return QF.sum_of_terms((descent_composition(t), coeff) for t, coeff in self) F = FundamentalDual # some utility functions for tableaux + def standardize(t): r""" Return the standard tableau corresponding to a given diff --git a/src/sage/combinat/chas/wqsym.py b/src/sage/combinat/chas/wqsym.py index 6a75d8b7c7e..458b39cb551 100644 --- a/src/sage/combinat/chas/wqsym.py +++ b/src/sage/combinat/chas/wqsym.py @@ -59,6 +59,7 @@ class WQSymBasis_abstract(CombinatorialFreeModule, BindableClass): - ``_basis_name`` -- the name of the basis (must match one of the names that the basis can be constructed from `WQSym`) """ + def __init__(self, alg, graded=True): r""" Initialize ``self``. @@ -68,13 +69,11 @@ def __init__(self, alg, graded=True): sage: M = algebras.WQSym(QQ).M() sage: TestSuite(M).run() # long time """ + def sorting_key(X): return (sum(map(len, X)), X) - CombinatorialFreeModule.__init__(self, alg.base_ring(), - OrderedSetPartitions(), - category=WQSymBases(alg, graded), - sorting_key=sorting_key, - bracket='', prefix=self._prefix) + + CombinatorialFreeModule.__init__(self, alg.base_ring(), OrderedSetPartitions(), category=WQSymBases(alg, graded), sorting_key=sorting_key, bracket='', prefix=self._prefix) def _repr_term(self, osp): r""" @@ -227,8 +226,10 @@ def _coerce_map_from_(self, R): if not self.base_ring().has_coerce_map_from(R.base_ring()): return False if self._basis_name == R._basis_name: # The same basis + def coerce_base_ring(self, x): return self._from_dict(x.monomial_coefficients()) + return coerce_base_ring # Otherwise lift that basis up and then coerce over target = getattr(self.realization_of(), R._basis_name)() @@ -461,6 +462,7 @@ class WordQuasiSymmetricFunctions(UniqueRepresentation, Parent): - Dendriform structure. """ + def __init__(self, R): """ Initialize ``self``. @@ -548,20 +550,12 @@ class options(GlobalOptions): sage: elt M[{1, 2}, {3}] + M[{1, 2, 3}] + M[{3}, {1, 2}] """ + NAME = 'WordQuasiSymmetricFunctions element' module = 'sage.combinat.chas.wqsym' option_class = 'WordQuasiSymmetricFunctions' - objects = dict(default='compositions', - description='Specifies how basis elements of WordQuasiSymmetricFunctions should be indexed', - values=dict(compositions="Indexing the basis by ordered set partitions", - words="Indexing the basis by packed words"), - case_sensitive=False) - display = dict(default='normal', - description='Specifies how basis elements of WordQuasiSymmetricFunctions should be printed', - values=dict(normal="Using the normal representation", - tight="Dropping spaces after commas", - compact="Using a severely compacted representation"), - case_sensitive=False) + objects = dict(default='compositions', description='Specifies how basis elements of WordQuasiSymmetricFunctions should be indexed', values=dict(compositions="Indexing the basis by ordered set partitions", words="Indexing the basis by packed words"), case_sensitive=False) + display = dict(default='normal', description='Specifies how basis elements of WordQuasiSymmetricFunctions should be printed', values=dict(normal="Using the normal representation", tight="Dropping spaces after commas", compact="Using a severely compacted representation"), case_sensitive=False) class Monomial(WQSymBasis_abstract): r""" @@ -581,6 +575,7 @@ class Monomial(WQSymBasis_abstract): sage: sorted(M.basis(2)) [M[{1}, {2}], M[{2}, {1}], M[{1, 2}]] """ + _prefix = "M" _basis_name = "Monomial" @@ -631,8 +626,7 @@ def product_on_basis(self, x, y): def union(X, Y): return X.union(Y) - return self.sum_of_monomials(ShuffleProduct_overlapping(x, yshift, - K, union)) + return self.sum_of_monomials(ShuffleProduct_overlapping(x, yshift, K, union)) def coproduct_on_basis(self, x): r""" @@ -663,9 +657,9 @@ def standardize(P): # standardize an ordered set partition # d is the unique order isomorphism from base to # {1, 2, ..., |base|} (encoded as dict). return K([[d[x] for x in part] for part in P]) + T = self.tensor_square() - return T.sum_of_monomials((standardize(x[:i]), standardize(x[i:])) - for i in range(len(x) + 1)) + return T.sum_of_monomials((standardize(x[:i]), standardize(x[i:])) for i in range(len(x) + 1)) M = Monomial @@ -709,6 +703,7 @@ class Characteristic(WQSymBasis_abstract): sage: X(M[[1, 3], [2]]) X[{1, 3}, {2}] """ + _prefix = "X" _basis_name = "Characteristic" @@ -727,7 +722,8 @@ def __init__(self, alg): mone = -self.base_ring().one() def sgn(P): - return mone**len(P) + return mone ** len(P) + self.module_morphism(codomain=M, diagonal=sgn).register_as_coercion() M.module_morphism(codomain=self, diagonal=sgn).register_as_coercion() @@ -765,8 +761,7 @@ def algebraic_complement(self): # for the formula we're using here. Q = self.parent() OSPs = Q.basis().keys() - return Q._from_dict({OSPs(A.reversed()): c for A, c in self}, - remove_zeros=False) + return Q._from_dict({OSPs(A.reversed()): c for A, c in self}, remove_zeros=False) def coalgebraic_complement(self): r""" @@ -802,8 +797,7 @@ def coalgebraic_complement(self): # for the formula we're using here. Q = self.parent() OSPs = Q.basis().keys() - return Q._from_dict({OSPs(A.complement()): c for A, c in self}, - remove_zeros=False) + return Q._from_dict({OSPs(A.complement()): c for A, c in self}, remove_zeros=False) def star_involution(self): r""" @@ -838,8 +832,7 @@ def star_involution(self): # for the formula we're using here. Q = self.parent() OSPs = Q.basis().keys() - return Q._from_dict({OSPs(A.complement().reversed()): c for A, c in self}, - remove_zeros=False) + return Q._from_dict({OSPs(A.complement().reversed()): c for A, c in self}, remove_zeros=False) X = Characteristic @@ -905,6 +898,7 @@ class Cone(WQSymBasis_abstract): basis seem to be always `0, 1, -1`. Is this true? What is the formula? """ + _prefix = "C" _basis_name = "Cone" @@ -1054,6 +1048,7 @@ class StronglyCoarser(WQSymBasis_abstract): - Section 6 of [BerZab05]_ """ + _prefix = "Q" _basis_name = "Q" @@ -1111,8 +1106,7 @@ def _Q_to_M(self, P): OSP = self.basis().keys() R = M.base_ring() one = R.one() - return M._from_dict({OSP(G): one for G in P.strongly_fatter()}, - coerce=False) + return M._from_dict({OSP(G): one for G in P.strongly_fatter()}, coerce=False) def _M_to_Q(self, P): """ @@ -1154,8 +1148,8 @@ def sign(R): if len(R) % 2 == lenP % 2: return one return -one - return Q._from_dict({OSP(G): sign(G) for G in P.strongly_fatter()}, - coerce=False) + + return Q._from_dict({OSP(G): sign(G) for G in P.strongly_fatter()}, coerce=False) def product_on_basis(self, x, y): r""" @@ -1232,9 +1226,9 @@ def standardize(P): # standardize an ordered set partition # d is the unique order isomorphism from base to # {1, 2, ..., |base|} (encoded as dict). return K([[d[x] for x in part] for part in P]) + T = self.tensor_square() - return T.sum_of_monomials((standardize(x[:i]), standardize(x[i:])) - for i in range(len(x) + 1)) + return T.sum_of_monomials((standardize(x[:i]), standardize(x[i:])) for i in range(len(x) + 1)) class Element(WQSymBasis_abstract.Element): def algebraic_complement(self): @@ -1281,9 +1275,8 @@ def img(A): # The image of the basis element Q[A], written as a # dictionary (of its coordinates in the Q-basis). Rs = [Rr.reversed() for Rr in A.strongly_fatter()] - return {OSPs(P): (one if (len(R) % 2 == len(P) % 2) - else mine) - for R in Rs for P in R.strongly_fatter()} + return {OSPs(P): (one if (len(R) % 2 == len(P) % 2) else mine) for R in Rs for P in R.strongly_fatter()} + return Q._from_dict(linear_combination((img(A), c) for A, c in self)) def coalgebraic_complement(self): @@ -1329,9 +1322,8 @@ def img(A): # The image of the basis element Q[A], written as a # dictionary (of its coordinates in the Q-basis). Rs = [Rr.complement() for Rr in A.strongly_fatter()] - return {OSPs(P): (one if (len(R) % 2 == len(P) % 2) - else mine) - for R in Rs for P in R.strongly_fatter()} + return {OSPs(P): (one if (len(R) % 2 == len(P) % 2) else mine) for R in Rs for P in R.strongly_fatter()} + return Q._from_dict(linear_combination((img(A), c) for A, c in self)) def star_involution(self): @@ -1367,8 +1359,7 @@ def star_involution(self): # for the formula we're using here. Q = self.parent() OSPs = Q.basis().keys() - return Q._from_dict({OSPs(A.complement().reversed()): c for A, c in self}, - remove_zeros=False) + return Q._from_dict({OSPs(A.complement().reversed()): c for A, c in self}, remove_zeros=False) Q = StronglyCoarser @@ -1436,6 +1427,7 @@ class StronglyFiner(WQSymBasis_abstract): - Section 2.7.2 of [NovThi06]_ """ + _prefix = "Phi" _basis_name = "Phi" @@ -1495,8 +1487,7 @@ def _Phi_to_M(self, P): OSP = self.basis().keys() R = M.base_ring() one = R.one() - return M._from_dict({OSP(G): one for G in P.strongly_finer()}, - coerce=False) + return M._from_dict({OSP(G): one for G in P.strongly_finer()}, coerce=False) def _M_to_Phi(self, P): """ @@ -1540,8 +1531,8 @@ def sign(R): if len(R) % 2 == lenP % 2: return one return -one - return Phi._from_dict({OSP(G): sign(G) for G in P.strongly_finer()}, - coerce=False) + + return Phi._from_dict({OSP(G): sign(G) for G in P.strongly_finer()}, coerce=False) def product_on_basis(self, x, y): r""" @@ -1635,9 +1626,7 @@ def product_on_basis(self, x, y): return self.monomial(y) if not y: return self.monomial(x) - xlist = [(j, (k == 0)) - for part in x - for k, j in enumerate(sorted(part))] + xlist = [(j, (k == 0)) for part in x for k, j in enumerate(sorted(part))] # xlist is a list of the form # [(e_1, s_1), (e_2, s_2), ..., (e_n, s_n)], # where e_1, e_2, ..., e_n are the entries of the parts of @@ -1645,9 +1634,7 @@ def product_on_basis(self, x, y): # part from bottom to top), and where s_i = True if e_i is # the smallest element of its part and False otherwise. m = max(max(part) for part in x) # The degree of x - ylist = [(m + j, (k == 0)) - for part in y - for k, j in enumerate(sorted(part))] + ylist = [(m + j, (k == 0)) for part in y for k, j in enumerate(sorted(part))] # ylist is like xlist, but for y instead of x, and with # a shift by m. @@ -1677,6 +1664,7 @@ def digest(s): block.append(s0[i]) blocks.append(block) return K(blocks) + return self.sum_of_monomials(digest(s) for s in ShuffleProduct(xlist, ylist)) def coproduct_on_basis(self, x): @@ -1743,16 +1731,16 @@ def standardize(P): # standardize an ordered set partition # d is the unique order isomorphism from base to # {1, 2, ..., |base|} (encoded as dict). return K([[d[x] for x in part] for part in P]) + deconcatenates = [(x[:i], x[i:]) for i in range(len(x) + 1)] for i in range(len(x)): xi = sorted(x[i]) for j in range(1, len(xi)): left = K(list(x[:i]) + [xi[:j]]) - right = K([xi[j:]] + list(x[i + 1:])) + right = K([xi[j:]] + list(x[i + 1 :])) deconcatenates.append((left, right)) T = self.tensor_square() - return T.sum_of_monomials((standardize(left), standardize(right)) - for left, right in deconcatenates) + return T.sum_of_monomials((standardize(left), standardize(right)) for left, right in deconcatenates) class Element(WQSymBasis_abstract.Element): def algebraic_complement(self): @@ -1798,9 +1786,8 @@ def img(A): # The image of the basis element Phi[A], written as a # dictionary (of its coordinates in the Phi-basis). Rs = [Rr.reversed() for Rr in A.strongly_finer()] - return {OSPs(P): (one if (len(R) % 2 == len(P) % 2) - else mine) - for R in Rs for P in R.strongly_finer()} + return {OSPs(P): (one if (len(R) % 2 == len(P) % 2) else mine) for R in Rs for P in R.strongly_finer()} + return Phi._from_dict(linear_combination((img(A), c) for A, c in self)) def coalgebraic_complement(self): @@ -1846,9 +1833,8 @@ def img(A): # The image of the basis element Phi[A], written as a # dictionary (of its coordinates in the Phi-basis). Rs = [Rr.complement() for Rr in A.strongly_finer()] - return {OSPs(P): (one if (len(R) % 2 == len(P) % 2) - else mine) - for R in Rs for P in R.strongly_finer()} + return {OSPs(P): (one if (len(R) % 2 == len(P) % 2) else mine) for R in Rs for P in R.strongly_finer()} + return Phi._from_dict(linear_combination((img(A), c) for A, c in self)) def star_involution(self): @@ -1884,8 +1870,7 @@ def star_involution(self): # for the formula we're using here. Phi = self.parent() OSPs = Phi.basis().keys() - return Phi._from_dict({OSPs(A.complement().reversed()): c for A, c in self}, - remove_zeros=False) + return Phi._from_dict({OSPs(A.complement().reversed()): c for A, c in self}, remove_zeros=False) Phi = StronglyFiner @@ -1897,6 +1882,7 @@ class WQSymBases(Category_realization_of_parent): r""" The category of bases of `WQSym`. """ + def __init__(self, base, graded): r""" Initialize ``self``. @@ -1968,9 +1954,7 @@ def super_categories(self): cat = cat.Graded() else: cat = cat.Filtered() - return [self.base().Realizations(), - HopfAlgebras(R).Graded().Realizations(), - cat.Connected()] + return [self.base().Realizations(), HopfAlgebras(R).Graded().Realizations(), cat.Connected()] class ParentMethods: def _repr_(self): @@ -2586,7 +2570,7 @@ def to_quasisymmetric_function(self): M[4] """ from sage.combinat.ncsf_qsym.qsym import QuasiSymmetricFunctions + M = QuasiSymmetricFunctions(self.parent().base_ring()).Monomial() MW = self.parent().realization_of().M() - return M.sum_of_terms((i.to_composition(), coeff) - for i, coeff in MW(self)) + return M.sum_of_terms((i.to_composition(), coeff) for i, coeff in MW(self)) diff --git a/src/sage/combinat/cluster_algebra_quiver/all.py b/src/sage/combinat/cluster_algebra_quiver/all.py index ea38e23c9be..cf1fcf0e84e 100644 --- a/src/sage/combinat/cluster_algebra_quiver/all.py +++ b/src/sage/combinat/cluster_algebra_quiver/all.py @@ -7,13 +7,13 @@ - :ref:`sage.combinat.cluster_algebra_quiver.quiver` - :ref:`sage.combinat.cluster_algebra_quiver.cluster_seed` """ + # install the docstring of this module to the containing package from sage.misc.lazy_import import lazy_import from sage.misc.namespace_package import install_doc install_doc(__package__, __doc__) -lazy_import("sage.combinat.cluster_algebra_quiver.quiver_mutation_type", - "QuiverMutationType") +lazy_import("sage.combinat.cluster_algebra_quiver.quiver_mutation_type", "QuiverMutationType") lazy_import("sage.combinat.cluster_algebra_quiver.quiver", "ClusterQuiver") lazy_import("sage.combinat.cluster_algebra_quiver.cluster_seed", "ClusterSeed") diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index f02b244e429..ed8c52d2997 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -315,13 +315,13 @@ def __init__(self, data, frozen=None, is_principal=False, user_labels=None, user elif isinstance(data, ClusterQuiver): quiver = ClusterQuiver(data) - self._M = copy(quiver._M) # B-tilde exchange matrix + self._M = copy(quiver._M) # B-tilde exchange matrix self._M.set_immutable() self._n = quiver._n self._m = quiver._m self._nlist = copy(quiver._nlist) self._mlist = copy(quiver._mlist) - self._B = copy(self._M[:self._n, :self._n]) # Square Part of the B_matrix + self._B = copy(self._M[: self._n, : self._n]) # Square Part of the B_matrix # If initializing from a ClusterQuiver rather than a ClusterSeed, the initial B-matrix is reset to be the input B-matrix. self._b_initial = copy(self._M) @@ -340,8 +340,7 @@ def __init__(self, data, frozen=None, is_principal=False, user_labels=None, user # Sanitizes our ``user_labels`` to use Integers instead of ints user_labels = [Integer(x) if x in ZZ else x for x in user_labels] if labelset != set(self._nlist + self._mlist) and labelset != set(range(self._n + self._m)): - raise ValueError('user_labels conflict with both the given' - ' vertex labels and the default labels') + raise ValueError('user_labels conflict with both the given' ' vertex labels and the default labels') # We are now updating labels from user's most recent choice. self._is_principal = is_principal @@ -377,19 +376,14 @@ def __init__(self, data, frozen=None, is_principal=False, user_labels=None, user self._U = PolynomialRing(QQ, [f'y{i}' for i in range(self._n)]) self._F = {i: self._U(1) for i in self._init_exch.values()} self._R = PolynomialRing(QQ, list(self._init_vars.values())) - self._y = {self._U.gen(j): prod([self._R.gen(i)**self._M[i, j] for i in range(self._n, self._n + self._m)]) - for j in range(self._n)} - self._yhat = {self._U.gen(j): prod([self._R.gen(i)**self._M[i, j] for i in range(self._n + self._m)]) - for j in range(self._n)} + self._y = {self._U.gen(j): prod([self._R.gen(i) ** self._M[i, j] for i in range(self._n, self._n + self._m)]) for j in range(self._n)} + self._yhat = {self._U.gen(j): prod([self._R.gen(i) ** self._M[i, j] for i in range(self._n + self._m)]) for j in range(self._n)} self._use_fpolys = True # in all other cases, we construct the corresponding ClusterQuiver first else: quiver = ClusterQuiver(data, frozen=frozen, user_labels=user_labels) - self.__init__(quiver, frozen=frozen, - is_principal=is_principal, - user_labels=user_labels, - user_labels_prefix=user_labels_prefix) + self.__init__(quiver, frozen=frozen, is_principal=is_principal, user_labels=user_labels, user_labels_prefix=user_labels_prefix) def use_c_vectors(self, use=True, bot_is_c=False, force=False): r""" @@ -440,8 +434,8 @@ def use_c_vectors(self, use=True, bot_is_c=False, force=False): if self._use_c_vec: # self._C = matrix.identity(self._n) try: - self._use_c_vec = False # temporarily turns off c-vectors to see if they can be recovered. - self._C = self.c_matrix() # if not just sets it to be identity matrix, i.e. reinitialized. + self._use_c_vec = False # temporarily turns off c-vectors to see if they can be recovered. + self._C = self.c_matrix() # if not just sets it to be identity matrix, i.e. reinitialized. self._BC = copy(self._M).stack(self.c_matrix()) self._use_c_vec = True except ValueError: @@ -466,13 +460,13 @@ def use_c_vectors(self, use=True, bot_is_c=False, force=False): if self._bot_is_c: self._use_c_vec = True if self._m == self._n: # in this case, the second half of a 2n x n matrix is a c-matrix. - self._C = copy(self._M[self._n:(self._n + self._m), :self._n]) + self._C = copy(self._M[self._n : (self._n + self._m), : self._n]) self._BC = copy(self._M) else: # self._n != self._m raise ValueError('There are immutable elements not in the c-matrix. Storing the c-matrix separately.') - self._C = copy(self._M[self._m:(self._n + self._m), :self._n]) + self._C = copy(self._M[self._m : (self._n + self._m), : self._n]) self._BC = copy(self._M) - self._M = self._M[:self._m:self._n] + self._M = self._M[: self._m : self._n] self._M.set_immutable() self._bot_is_c = False @@ -540,8 +534,8 @@ def use_g_vectors(self, use=True, force=False): if self._use_g_vec: # self._G = matrix.identity(self._n) if self._use_g_vec else None try: - self._use_g_vec = False # temporarily turns off g-vectors to see if they can be recovered. - self._G = self.g_matrix() # if not just sets it to be identity matrix, i.e. reinitialized. + self._use_g_vec = False # temporarily turns off g-vectors to see if they can be recovered. + self._G = self.g_matrix() # if not just sets it to be identity matrix, i.e. reinitialized. self._use_g_vec = True except ValueError: if not force: @@ -709,12 +703,10 @@ def use_fpolys(self, use=True, user_labels=None, user_labels_prefix=None): self._U = PolynomialRing(QQ, [f'y{i}' for i in range(self._n)]) self._F = {i: self._U(1) for i in self._init_exch.values()} self._R = PolynomialRing(QQ, list(self._init_vars.values())) - self._y = {self._U.gen(j): prod([self._R.gen(i)**self._M[i, j] for i in range(self._n, self._n + self._m)]) - for j in range(self._n)} - self._yhat = {self._U.gen(j): prod([self._R.gen(i)**self._M[i, j] for i in range(self._n + self._m)]) - for j in range(self._n)} + self._y = {self._U.gen(j): prod([self._R.gen(i) ** self._M[i, j] for i in range(self._n, self._n + self._m)]) for j in range(self._n)} + self._yhat = {self._U.gen(j): prod([self._R.gen(i) ** self._M[i, j] for i in range(self._n + self._m)]) for j in range(self._n)} elif self._cluster: - raise ValueError("should not be possible to have cluster variables without f-polynomials") # added this as a sanity check. This error should never appear however. + raise ValueError("should not be possible to have cluster variables without f-polynomials") # added this as a sanity check. This error should never appear however. elif self._track_mut: # If we can navigate from the root to where we are if not self._use_g_vec: self.use_g_vectors(True) @@ -875,8 +867,7 @@ def _sanitize_init_vars(self, user_labels, user_labels_prefix='x'): raise ValueError("the input 'user_labels' must be a dictionary or a list") if len(self._init_vars) != self._n + self._m: - raise ValueError("the number of user-defined labels is not the" - " number of exchangeable and frozen variables") + raise ValueError("the number of user-defined labels is not the" " number of exchangeable and frozen variables") def set_c_matrix(self, data): r""" @@ -1020,8 +1011,7 @@ def _repr_(self): """ name = self._description if self._mutation_type: - if isinstance(self._mutation_type, (QuiverMutationType_Irreducible, - QuiverMutationType_Reducible)): + if isinstance(self._mutation_type, (QuiverMutationType_Irreducible, QuiverMutationType_Reducible)): name += ' of type ' + str(self._mutation_type) # the following case allows description of 'undetermined finite mutation type' else: @@ -1075,8 +1065,7 @@ def plot(self, circular=False, mark=None, save_pos=False, force_c=False, with_gr else: quiver = self.quiver() - return quiver.plot(circular=circular, mark=mark, save_pos=save_pos, - greens=greens) + return quiver.plot(circular=circular, mark=mark, save_pos=save_pos, greens=greens) def show(self, fig_size=1, circular=False, mark=None, save_pos=False, force_c=False, with_greens=False, add_labels=False): r""" @@ -1116,8 +1105,7 @@ def show(self, fig_size=1, circular=False, mark=None, save_pos=False, force_c=Fa else: quiver = self.quiver() - quiver.show(fig_size=fig_size, circular=circular, mark=mark, - save_pos=save_pos, greens=greens) + quiver.show(fig_size=fig_size, circular=circular, mark=mark, save_pos=save_pos, greens=greens) def interact(self, fig_size=1, circular=True): r""" @@ -1240,11 +1228,7 @@ def x(self, k): elif k in self._nlist: x = self._R.gens()[self._nlist.index(k)] - return ClusterVariable(FractionField(self._R), - x.numerator(), x.denominator(), - mutation_type=self._mutation_type, - variable_type='cluster variable', - xdim=self._n) + return ClusterVariable(FractionField(self._R), x.numerator(), x.denominator(), mutation_type=self._mutation_type, variable_type='cluster variable', xdim=self._n) raise ValueError("the input is not in an index of a cluster variable") def y(self, k): @@ -1278,11 +1262,7 @@ def y(self, k): x = self._R.gens()[self._n + k] elif k in self._mlist: x = self._R.gens()[self._mlist.index(k) + self._n] - return ClusterVariable(FractionField(self._R), - x.numerator(), x.denominator(), - mutation_type=self._mutation_type, - variable_type='frozen variable', - xdim=self._n) + return ClusterVariable(FractionField(self._R), x.numerator(), x.denominator(), mutation_type=self._mutation_type, variable_type='frozen variable', xdim=self._n) raise ValueError("the input is not in an index of a frozen variable") def n(self): @@ -1391,7 +1371,7 @@ def cluster_variable(self, k): elif k in IE: k = IE.index(k) - g_mon = prod([self._R.gen(i)**self._G[i, k] for i in range(self._n)]) + g_mon = prod([self._R.gen(i) ** self._G[i, k] for i in range(self._n)]) F_num = self._F[IE[k]].subs(self._yhat) F_den = self._R(self._F[IE[k]].subs(self._y).denominator()) cluster_variable = g_mon * F_num * F_den @@ -1468,13 +1448,13 @@ def _f_mutate(self, k): for j in range(self._n): if C[j, k] > 0: - pos *= self._U.gen(j)**C[j, k] + pos *= self._U.gen(j) ** C[j, k] else: - neg *= self._U.gen(j)**(-C[j, k]) + neg *= self._U.gen(j) ** (-C[j, k]) if B[j, k] > 0: - pos *= F[IE[j]]**B[j, k] + pos *= F[IE[j]] ** B[j, k] else: - neg *= F[IE[j]]**(-B[j, k]) + neg *= F[IE[j]] ** (-B[j, k]) # can the following be improved? self._F[IE[k]] = (pos + neg) // F[IE[k]] @@ -1630,6 +1610,7 @@ def g_matrix(self, show_warnings=True): """ from sage.matrix.constructor import matrix + if self._use_g_vec: return copy(self._G) if self._use_fpolys and self._cluster: # This only calls g_vector when it will not create a loop. @@ -1638,13 +1619,13 @@ def g_matrix(self, show_warnings=True): if self.b_matrix().is_skew_symmetric(): return copy(self._C).inverse().transpose() if self._track_mut: - BC1 = copy(self._b_initial[0:self._n]) + BC1 = copy(self._b_initial[0 : self._n]) BC1 = -BC1.transpose() BC1 = BC1.stack(matrix.identity(self._n)) seq = iter(self.mutations()) for k in seq: BC1.mutate(k) - return copy(BC1[self._n:2 * self._n]).inverse().transpose() + return copy(BC1[self._n : 2 * self._n]).inverse().transpose() raise ValueError("Unable to calculate g-vectors. Need to use g vectors.") elif self._track_mut: catchup = ClusterSeed(self._b_initial) @@ -1756,27 +1737,27 @@ def c_matrix(self, show_warnings=True): """ if self._bot_is_c: - return copy(self._M[self._m:(self._n + self._m), :self._n]) + return copy(self._M[self._m : (self._n + self._m), : self._n]) if self._use_c_vec: return copy(self._C) if self._use_g_vec or self._use_fpolys: # both of these will populate g_matrix() successfully if self.b_matrix().is_skew_symmetric(): return self.g_matrix().inverse().transpose() if self._track_mut: - BC1 = copy(self._b_initial[0:self._n]) + BC1 = copy(self._b_initial[0 : self._n]) BC1 = BC1.stack(matrix.identity(self._n)) seq = iter(self.mutations()) for k in seq: BC1.mutate(k) - return copy(BC1[self._n:2 * self._n]) + return copy(BC1[self._n : 2 * self._n]) raise ValueError("Unable to calculate c-vectors. Need to use c vectors.") elif self._track_mut: - BC1 = copy(self._b_initial[0:self._n]) + BC1 = copy(self._b_initial[0 : self._n]) BC1 = BC1.stack(matrix.identity(self._n)) seq = iter(self.mutations()) for k in seq: BC1.mutate(k) - return copy(BC1[self._n:2 * self._n]) + return copy(BC1[self._n : 2 * self._n]) elif show_warnings: raise ValueError("Unable to calculate c-vectors. Need to use c vectors.") else: @@ -1801,8 +1782,8 @@ def d_vector(self, k): if self._use_fpolys: f = self.cluster_variable(k) if f in self._R.gens(): - return -vector(f.numerator().monomials()[0].exponents()[0][:self._n]) - return vector(f.denominator().monomials()[0].exponents()[0][:self._n]) + return -vector(f.numerator().monomials()[0].exponents()[0][: self._n]) + return vector(f.denominator().monomials()[0].exponents()[0][: self._n]) if self._track_mut: catchup = ClusterSeed(self._b_initial) catchup.use_fpolys(False) @@ -1901,13 +1882,13 @@ def coefficient(self, k): if k not in range(self._n): raise ValueError("The cluster seed does not have a coefficient of index %s." % k) if self._m == 0: - return self.x(0)**0 - try: # are c vectors being tracked? + return self.x(0) ** 0 + try: # are c vectors being tracked? exp = self.c_vector(k) - except Exception: # if not try and reconstruct them + except Exception: # if not try and reconstruct them exp = self.c_matrix().column(k) - return prod(self.y(i)**exp[i] for i in range(self._m)) + return prod(self.y(i) ** exp[i] for i in range(self._m)) def coefficients(self): r""" @@ -1934,9 +1915,9 @@ def quiver(self): Quiver on 3 vertices of type ['A', 3] """ from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver + if self._quiver is None: - self._quiver = ClusterQuiver(self._M, - user_labels=self._nlist + self._mlist) + self._quiver = ClusterQuiver(self._M, user_labels=self._nlist + self._mlist) return self._quiver def is_acyclic(self) -> bool: @@ -2481,8 +2462,7 @@ def mutate(self, sequence, inplace=True, input_type=None): # check for sanitizable data if not isinstance(inplace, bool): - raise ValueError("the second parameter must be boolean; to mutate" - " at a sequence of length 2, input it as a list") + raise ValueError("the second parameter must be boolean; to mutate" " at a sequence of length 2, input it as a list") if inplace: seed = self @@ -2507,6 +2487,7 @@ def mutate(self, sequence, inplace=True, input_type=None): elif sequence[0] == '[' and sequence[-1] == ']': # convert to list from ast import literal_eval + temp_list = literal_eval(sequence) sequence = self._user_labels_prefix @@ -2533,8 +2514,7 @@ def mutate(self, sequence, inplace=True, input_type=None): n, m = seed.n(), seed.m() - if (sequence in range(n) or sequence in IE - or isinstance(sequence, str) or sequence in seed._nlist): + if sequence in range(n) or sequence in IE or isinstance(sequence, str) or sequence in seed._nlist: seqq = [sequence] else: seqq = sequence @@ -2542,8 +2522,7 @@ def mutate(self, sequence, inplace=True, input_type=None): if isinstance(seqq, tuple): seqq = list(seqq) if not isinstance(seqq, list): - raise ValueError("the quiver can only be mutated at a vertex" - " or at a sequence of vertices") + raise ValueError("the quiver can only be mutated at a vertex" " or at a sequence of vertices") # These boolean variables classify the input type is_vertices = set(seqq).issubset(set(seed._nlist)) @@ -2556,39 +2535,30 @@ def mutate(self, sequence, inplace=True, input_type=None): # Ensures the sequence has elements of type input_type. if input_type: if input_type == "vertices" and not is_vertices: - raise ValueError('input_type set to "vertices" but not everything' - ' in the mutation sequence is a vertex.') + raise ValueError('input_type set to "vertices" but not everything' ' in the mutation sequence is a vertex.') elif input_type == "indices" and not is_indices: - raise ValueError('input_type set to "indices" but not everything' - ' in the mutation sequence is an index.') + raise ValueError('input_type set to "indices" but not everything' ' in the mutation sequence is an index.') elif input_type == "cluster_vars" and not is_cluster_vars: - raise ValueError('input_type set to "cluster_vars" but not' - ' everything in the mutation sequence is a' - ' cluster variable.') + raise ValueError('input_type set to "cluster_vars" but not' ' everything in the mutation sequence is a' ' cluster variable.') elif input_type not in ["vertices", "indices", "cluster_vars"]: - raise ValueError('input_type must be either "vertices",' - ' "indices", or "cluster_vars"') + raise ValueError('input_type must be either "vertices",' ' "indices", or "cluster_vars"') # Classifies the input_type. Raises warnings if the input is ambiguous, and errors if the input is not all of the same type. elif is_vertices: input_type = "vertices" for x in seqq: if is_indices and seed._nlist[x] != x: - print("Input can be ambiguously interpreted as both" - " vertices and indices." - " Mutating at vertices by default.") + print("Input can be ambiguously interpreted as both" " vertices and indices." " Mutating at vertices by default.") break elif is_cluster_vars: cluster_var_index = seed.cluster_index(x) vertex_index = seed._nlist.index(x) if isinstance(cluster_var_index, int) and cluster_var_index != vertex_index: - print("Input can be ambiguously interpreted as" - " both vertices and cluster variables." - " Mutating at vertices by default.") + print("Input can be ambiguously interpreted as" " both vertices and cluster variables." " Mutating at vertices by default.") break # It should be impossible to interpret an index as a cluster variable. @@ -2597,8 +2567,7 @@ def mutate(self, sequence, inplace=True, input_type=None): elif is_cluster_vars: input_type = "cluster_vars" else: - raise ValueError('mutation sequences must consist of exactly' - ' one of vertices, indices, or cluster variables') + raise ValueError('mutation sequences must consist of exactly' ' one of vertices, indices, or cluster variables') if input_type == "cluster_vars" and len(seqq) > 1: mutation_seed = deepcopy(seed) @@ -2609,9 +2578,7 @@ def mutate(self, sequence, inplace=True, input_type=None): mutation_seed.mutate(new_index, input_type='indices') index_list.append(new_index) except (ValueError, TypeError): - raise ValueError('input interpreted as cluster variables,' - ' but the input sequence did not consist' - ' of cluster variables') + raise ValueError('input interpreted as cluster variables,' ' but the input sequence did not consist' ' of cluster variables') input_type = "indices" seqq = index_list @@ -2647,11 +2614,11 @@ def mutate(self, sequence, inplace=True, input_type=None): seed._d_mutate(k) seed._BC.mutate(k) - seed._M = copy(seed._BC[:n + m, :n]) + seed._M = copy(seed._BC[: n + m, :n]) self._M.set_immutable() if seed._use_c_vec: - seed._C = seed._BC[n + m:2 * n + m, :n + m] + seed._C = seed._BC[n + m : 2 * n + m, : n + m] if seed._track_mut: # delete involutive mutations @@ -2686,18 +2653,13 @@ def cluster_index(self, cluster_str): """ if self._use_fpolys and isinstance(cluster_str, str): c = FractionField(self._R)(cluster_str) - cluster_str = ClusterVariable(FractionField(self._R), - c.numerator(), c.denominator(), - mutation_type=self._mutation_type, - variable_type='cluster variable', - xdim=self._n) + cluster_str = ClusterVariable(FractionField(self._R), c.numerator(), c.denominator(), mutation_type=self._mutation_type, variable_type='cluster variable', xdim=self._n) if cluster_str in self.cluster(): return self.cluster().index(cluster_str) return None - def mutation_sequence(self, sequence, show_sequence=False, - fig_size=1.2, return_output='seed'): + def mutation_sequence(self, sequence, show_sequence=False, fig_size=1.2, return_output='seed'): r""" Return the seeds obtained by mutating ``self`` at all vertices in ``sequence``. @@ -3019,11 +2981,9 @@ def exchangeable_part(self): [(0, 1, (1, -1)), (2, 1, (1, -1))] """ from sage.combinat.cluster_algebra_quiver.mutation_class import _principal_part + eval_dict = {self.y(i): 1 for i in range(self._m)} - seed = ClusterSeed(_principal_part(self._M), is_principal=True, - user_labels=self._nlist, - user_labels_prefix=self._user_labels_prefix, - frozen=None) + seed = ClusterSeed(_principal_part(self._M), is_principal=True, user_labels=self._nlist, user_labels_prefix=self._user_labels_prefix, frozen=None) seed.use_c_vectors(self._use_c_vec) seed.use_fpolys(self._use_fpolys) seed.use_g_vectors(self._use_g_vec) @@ -3031,8 +2991,7 @@ def exchangeable_part(self): seed.track_mutations(self._track_mut) if self._use_fpolys: self.cluster() - seed._cluster = [self._cluster[k].subs(eval_dict) - for k in range(self._n)] + seed._cluster = [self._cluster[k].subs(eval_dict) for k in range(self._n)] seed._mutation_type = self._mutation_type return seed @@ -3099,12 +3058,9 @@ def universal_extension(self): True """ if self._m != 0: - raise ValueError("To have universal coefficients we need " - "to start from a coefficient-free seed") + raise ValueError("To have universal coefficients we need " "to start from a coefficient-free seed") if not self.is_bipartite() or not self.is_finite(): - raise ValueError("Universal coefficients are defined only " - "for finite type cluster algebras at a " - "bipartite initial cluster") + raise ValueError("Universal coefficients are defined only " "for finite type cluster algebras at a " "bipartite initial cluster") from sage.matrix.constructor import matrix from sage.combinat.root_system.cartan_matrix import CartanMatrix @@ -3115,10 +3071,8 @@ def universal_extension(self): rs = CartanMatrix(A, index_set=list(range(1, A.ncols() + 1))).root_space() almost_positive_coroots = rs.almost_positive_roots() - sign = [-1 if all(x <= 0 for x in self.b_matrix()[i]) else 1 - for i in range(self._n)] - C = matrix([[sign[j] * alpha[j + 1] for j in range(self._n)] - for alpha in almost_positive_coroots]) + sign = [-1 if all(x <= 0 for x in self.b_matrix()[i]) else 1 for i in range(self._n)] + C = matrix([[sign[j] * alpha[j + 1] for j in range(self._n)] for alpha in almost_positive_coroots]) M = self._M.stack(C) n = C.nrows() @@ -3129,9 +3083,7 @@ def universal_extension(self): elif isinstance(self._user_labels, dict): new_labels = copy(self._user_labels) new_labels.update({(i + self._n): f'y{i}' for i in range(n)}) - seed = ClusterSeed(M, is_principal=False, user_labels=new_labels, - user_labels_prefix=self._user_labels_prefix, - frozen=None) + seed = ClusterSeed(M, is_principal=False, user_labels=new_labels, user_labels_prefix=self._user_labels_prefix, frozen=None) seed.use_c_vectors(self._use_c_vec) seed.use_fpolys(self._use_fpolys) seed.use_g_vectors(self._use_g_vec) @@ -3185,10 +3137,11 @@ def principal_extension(self): True """ from sage.matrix.special import identity_matrix + if self._m != 0: raise ValueError("the b-matrix is not square") M = self._M.stack(identity_matrix(self._n)) - is_principal = (self._m == 0) + is_principal = self._m == 0 new_labels = None if self._user_labels: if isinstance(self._user_labels, list): @@ -3196,8 +3149,7 @@ def principal_extension(self): elif isinstance(self._user_labels, dict): new_labels = copy(self._user_labels) new_labels.update({(i + self._n): f'y{i}' for i in range(self._n)}) - seed = ClusterSeed(M, is_principal=is_principal, user_labels=new_labels, - user_labels_prefix=self._user_labels_prefix, frozen=None) + seed = ClusterSeed(M, is_principal=is_principal, user_labels=new_labels, user_labels_prefix=self._user_labels_prefix, frozen=None) seed.use_c_vectors(self._use_c_vec) seed.use_fpolys(self._use_fpolys) seed.use_g_vectors(self._use_g_vec) @@ -3294,8 +3246,7 @@ def set_cluster(self, cluster, force=False): if not force: # if already have f_polynomials, using set_cluster might yield data inconsistent with them. print("Warning: using set_cluster at this point could lead to inconsistent seed data.") else: - self._cluster = [FractionField(self._R)(x) - for x in cluster][0:self._n] + self._cluster = [FractionField(self._R)(x) for x in cluster][0 : self._n] self._is_principal = None else: print("Warning: clusters not being tracked so this command is ignored.") @@ -3390,8 +3341,7 @@ def reset_coefficients(self): """ n, m = self._n, self._m if not n == m: - raise ValueError("The numbers of cluster variables " - "and of frozen variables do not coincide.") + raise ValueError("The numbers of cluster variables " "and of frozen variables do not coincide.") newM = copy(self._M) for i in range(m): for j in range(n): @@ -3404,9 +3354,7 @@ def reset_coefficients(self): self._quiver = None self._is_principal = None - def mutation_class_iter(self, depth=infinity, show_depth=False, - return_paths=False, up_to_equivalence=True, - only_sink_source=False): + def mutation_class_iter(self, depth=infinity, show_depth=False, return_paths=False, up_to_equivalence=True, only_sink_source=False): r""" Return an iterator for the mutation class of ``self`` with respect to certain constraints. @@ -3603,8 +3551,7 @@ def mutation_class_iter(self, depth=infinity, show_depth=False, nr += ' ' * (10 - len(nr)) print(f"Depth: {dc} found: {nr} Time: {timer2 - timer:.2f} s") - def mutation_class(self, depth=infinity, show_depth=False, return_paths=False, - up_to_equivalence=True, only_sink_source=False): + def mutation_class(self, depth=infinity, show_depth=False, return_paths=False, up_to_equivalence=True, only_sink_source=False): r""" Return the mutation class of ``self`` with respect to certain constraints. @@ -4237,11 +4184,11 @@ def greedy(self, a1, a2, algorithm='by_recursion'): b = abs(self.b_matrix()[0, 1]) c = abs(self.b_matrix()[1, 0]) if algorithm == 'by_recursion': - ans = self.x(0)**(-a1)*self.x(1)**(-a2) - for p in range(max(a2, 0)+1): - for q in range(max(a1, 0)+1): + ans = self.x(0) ** (-a1) * self.x(1) ** (-a2) + for p in range(max(a2, 0) + 1): + for q in range(max(a1, 0) + 1): if p != 0 or q != 0: - ans += self._R(coeff_recurs(p, q, a1, a2, b, c))*self.x(0)**(b*p-a1)*self.x(1)**(c*q-a2) + ans += self._R(coeff_recurs(p, q, a1, a2, b, c)) * self.x(0) ** (b * p - a1) * self.x(1) ** (c * q - a2) return ans if algorithm == 'by_combinatorics': if b == 0: @@ -4254,30 +4201,29 @@ def greedy(self, a1, a2, algorithm='by_recursion'): else: PS = PathSubset(a2, a1) from sage.combinat.subset import Subsets + for T in Subsets(PS): if a1 >= a2: if is_LeeLiZel_allowable(T, a1, a2, b, c): oddT = set(T).intersection(PathSubset(a1, 0)) evenT = set(T).symmetric_difference(oddT) - ans = ans + S.x(0)**(b*len(evenT)) * S.x(1)**(c*len(oddT)) + ans = ans + S.x(0) ** (b * len(evenT)) * S.x(1) ** (c * len(oddT)) elif is_LeeLiZel_allowable(T, a2, a1, c, b): oddT = set(T).intersection(PathSubset(a2, 0)) evenT = set(T).symmetric_difference(oddT) - ans = ans + S.x(0)**(b*len(oddT)) * S.x(1)**(c*len(evenT)) - ans = ans*S.x(0)**(-a1)*S.x(1)**(-a2) + ans = ans + S.x(0) ** (b * len(oddT)) * S.x(1) ** (c * len(evenT)) + ans = ans * S.x(0) ** (-a1) * S.x(1) ** (-a2) return ans if algorithm == 'just_numbers': ans = 1 - for p in range(max(a2, 0)+1): - for q in range(max(a1, 0)+1): + for p in range(max(a2, 0) + 1): + for q in range(max(a1, 0) + 1): if p != 0 or q != 0: ans += coeff_recurs(p, q, a1, a2, b, c) return ans - raise ValueError("The third input should be 'by_recursion', " - "'by_combinatorics', or 'just_numbers'.") + raise ValueError("The third input should be 'by_recursion', " "'by_combinatorics', or 'just_numbers'.") else: - raise ValueError("Greedy elements are only currently " - "defined for cluster seeds of rank two.") + raise ValueError("Greedy elements are only currently " "defined for cluster seeds of rank two.") def oriented_exchange_graph(self): """ @@ -4408,12 +4354,10 @@ def find_upper_bound(self, verbose=False): deep_gens = [initial_product] for t in range(rank): - neighbor_product = '*'.join(xpvars[s] if s == t else xvars[s] - for s in range(rank)) + neighbor_product = '*'.join(xpvars[s] if s == t else xvars[s] for s in range(rank)) deep_gens += [neighbor_product] - rels = [f"-{gens[t]}*{gens[t + rank]}+{lower_var[t + rank].numerator()}" - for t in range(rank)] + rels = [f"-{gens[t]}*{gens[t + rank]}+{lower_var[t + rank].numerator()}" for t in range(rank)] while True: R = PolynomialRing(QQ, gens, order='invlex') @@ -4534,6 +4478,7 @@ def LLM_gen_set(self, size_limit=-1): """ from sage.modules.free_module import VectorSpace from sage.rings.finite_rings.finite_field_constructor import GF + B = self.b_matrix() aSet = VectorSpace(GF(2), B.ncols()).list() genSet = [] @@ -4697,7 +4642,7 @@ def _produce_upper_cluster_algebra_element(self, vd, cList): expn = 0 # The exponent is determined by the vectors a,s, and the matrix B. for k in range(num_cols): - expn += (vdi[0][k]-s[k])*max(0, B[j][k])+s[k]*max(0, -B[j][k]) + expn += (vdi[0][k] - s[k]) * max(0, B[j][k]) + s[k] * max(0, -B[j][k]) term *= x**expn numerator += term # Gives a numerator for the negative vector, or else the product would be zero. @@ -4708,9 +4653,9 @@ def _produce_upper_cluster_algebra_element(self, vd, cList): denominator = 1 powers = vdi[0] for ell in range(num_cols): - denominator = denominator * R.gen(ell)**powers[ell] + denominator = denominator * R.gen(ell) ** powers[ell] # Each copy of a vector in vd contributes a factor of the Laurent polynomial calculated from it. - final = (numerator / denominator)**vdi[1] + final = (numerator / denominator) ** vdi[1] finalP.append(final) laurentP = 1 # The UCA element for the vector a is the product of the elements produced from the vectors in its decomposition. @@ -4751,12 +4696,8 @@ def coeff_recurs(p, q, a1, a2, b, c): if p < 0 or q < 0: return 0 if c * a1 * q <= b * a2 * p: - return sum((-1)**(k - 1) * coeff_recurs(p - k, q, a1, a2, b, c) - * _bino(a2 - c * q + k - 1, k) - for k in range(1, p + 1)) - return sum((-1)**(k - 1) * coeff_recurs(p, q - k, a1, a2, b, c) - * _bino(a1 - b * p + k - 1, k) - for k in range(1, q + 1)) + return sum((-1) ** (k - 1) * coeff_recurs(p - k, q, a1, a2, b, c) * _bino(a2 - c * q + k - 1, k) for k in range(1, p + 1)) + return sum((-1) ** (k - 1) * coeff_recurs(p, q - k, a1, a2, b, c) * _bino(a1 - b * p + k - 1, k) for k in range(1, q + 1)) def PathSubset(n, m): @@ -4785,7 +4726,7 @@ def PathSubset(n, m): S = {2 * i + 1 for i in range(n)} if m > 0: for j in range(n): - if ((j+1)*m) // n - (j*m) // n == 1: + if ((j + 1) * m) // n - (j * m) // n == 1: S.add(2 * j) return set(S) @@ -4809,14 +4750,14 @@ def SetToPath(T): sage: SetToPath(PathSubset(4,4)) [1, 0, 3, 2, 5, 4, 7, 6] """ - n = (max(T)+1) // 2 + n = (max(T) + 1) // 2 ans = [1] - for i in range(n-1): - if 2*i in T: - ans.append(2*i) - ans.append(2*i+3) - if 2*n-2 in T: - ans.append(2*n-2) + for i in range(n - 1): + if 2 * i in T: + ans.append(2 * i) + ans.append(2 * i + 3) + if 2 * n - 2 in T: + ans.append(2 * n - 2) return ans @@ -4845,6 +4786,7 @@ def is_LeeLiZel_allowable(T, n, m, b, c) -> bool: for u in horiz: from sage.combinat.words.word import Word from sage.modules.free_module_element import vector + WW = Word(Latt) LattCycled = vector(WW.conjugate(Latt.index(u))).list() for v in vert: @@ -5131,6 +5073,7 @@ class ClusterVariable(FractionFieldElement): (x0*x2 + 1)/x1 alpha[2] (x0*x2 + x1 + 1)/(x1*x2) alpha[2] + alpha[3] """ + def __init__(self, parent, numerator, denominator, coerce=True, reduce=True, mutation_type=None, variable_type=None, xdim=0): r""" Initialize a cluster variable in the same way that elements in the field of rational functions are initialized. @@ -5180,11 +5123,12 @@ def almost_positive_root(self): self._mutation_type = self.parent().mutation_type() if self._mutation_type.is_finite(): from sage.combinat.root_system.root_system import RootSystem + # the import above is used in the line below mt = self._mutation_type._repr_() # mt is a string of the shape "['A', 15]" # where A is a single letter and 15 is an integer - Phi = RootSystem([mt[2: 3], Integer(mt[6: -1])]) + Phi = RootSystem([mt[2:3], Integer(mt[6:-1])]) Phiplus = Phi.root_lattice().simple_roots() if self.denominator() == 1: diff --git a/src/sage/combinat/cluster_algebra_quiver/interact.py b/src/sage/combinat/cluster_algebra_quiver/interact.py index 74cb730b0bf..f0c3c5ca15a 100644 --- a/src/sage/combinat/cluster_algebra_quiver/interact.py +++ b/src/sage/combinat/cluster_algebra_quiver/interact.py @@ -1,6 +1,7 @@ """ Interactive display of quivers """ + import ipywidgets as widgets from sage.misc.latex import latex from sage.repl.rich_output.pretty_print import pretty_print @@ -35,25 +36,17 @@ def cluster_interact(self, fig_size=1, circular=True, kind='seed'): if kind not in ['seed', 'quiver']: raise ValueError('kind must be "seed" or "quiver"') - show_seq = widgets.Checkbox(value=True, - description="Display mutation sequence") + show_seq = widgets.Checkbox(value=True, description="Display mutation sequence") - show_vars = widgets.Checkbox(value=True, - description="Display cluster variables") + show_vars = widgets.Checkbox(value=True, description="Display cluster variables") - show_matrix = widgets.Checkbox(value=True, - description="Display B-matrix") + show_matrix = widgets.Checkbox(value=True, description="Display B-matrix") - show_lastmutation = widgets.Checkbox(value=True, - description="Show last mutation vertex") + show_lastmutation = widgets.Checkbox(value=True, description="Show last mutation vertex") - mut_buttons = widgets.ToggleButtons(options=list(range(self._n)), - style={'button_width': 'initial'}, - description='Mutate at: ') + mut_buttons = widgets.ToggleButtons(options=list(range(self._n)), style={'button_width': 'initial'}, description='Mutate at: ') - which_plot = widgets.Dropdown(options=['circular', 'spring'], - value='circular' if circular else "spring", - description='Display style:') + which_plot = widgets.Dropdown(options=['circular', 'spring'], value='circular' if circular else "spring", description='Display style:') out = widgets.Output() @@ -117,7 +110,4 @@ def do_mutation(*args, **kwds): else: top = widgets.HBox([show_seq]) - return widgets.VBox([which_plot, - top, - widgets.HBox([show_matrix, show_lastmutation]), - mut_buttons, out]) + return widgets.VBox([which_plot, top, widgets.HBox([show_matrix, show_lastmutation]), mut_buttons, out]) diff --git a/src/sage/combinat/cluster_algebra_quiver/mutation_class.py b/src/sage/combinat/cluster_algebra_quiver/mutation_class.py index 43cf6c5e2f9..1ae92db6bb1 100644 --- a/src/sage/combinat/cluster_algebra_quiver/mutation_class.py +++ b/src/sage/combinat/cluster_algebra_quiver/mutation_class.py @@ -104,10 +104,8 @@ def _digraph_mutate(dg, k, frozen=None): edge_it = dg.outgoing_edge_iterator([k], True) out_edges = list(edge_it) - in_edges_new = [(v2, v1, (-label[1], -label[0])) - for v1, v2, label in in_edges] - out_edges_new = [(v2, v1, (-label[1], -label[0])) - for v1, v2, label in out_edges] + in_edges_new = [(v2, v1, (-label[1], -label[0])) for v1, v2, label in in_edges] + out_edges_new = [(v2, v1, (-label[1], -label[0])) for v1, v2, label in out_edges] diag_edges_new = [] diag_edges_del = [] @@ -138,8 +136,7 @@ def _digraph_mutate(dg, k, frozen=None): del_edges += diag_edges_del new_edges = in_edges_new + out_edges_new new_edges += diag_edges_new - new_edges += [(*ed, edges[ed]) for ed in edges - if ed not in del_edges] + new_edges += [(*ed, edges[ed]) for ed in edges if ed not in del_edges] dg_new = DiGraph() dg_new.add_vertices(list(dg)) @@ -244,8 +241,7 @@ def _dg_canonical_form(dg, frozen=None): partition_add, edges = _graph_without_edge_labels(dg, vertices) partition += partition_add - automorphism_group, _, iso = search_tree(dg, partition=partition, lab=True, - dig=True, certificate=True) + automorphism_group, _, iso = search_tree(dg, partition=partition, lab=True, dig=True, certificate=True) orbits = get_orbits(automorphism_group, n_plus_m) orbits = [[iso[i] for i in orbit] for orbit in orbits] @@ -400,9 +396,7 @@ def _digraph_to_dig6(dg, hashable=False) -> tuple[str, dict | tuple]: ('COD?', {}) """ dig6 = dg.dig6_string() - D = {(E0, E1): E2 - for E0, E1, E2 in dg._backend.iterator_in_edges(dg, True) - if E2 != (1, -1)} + D = {(E0, E1): E2 for E0, E1, E2 in dg._backend.iterator_in_edges(dg, True) if E2 != (1, -1)} if hashable: D = tuple(sorted(D.items())) return (dig6, D) @@ -516,8 +510,7 @@ def _graph_without_edge_labels(dg, vertices): """ vertices = list(vertices) edges = dg.edge_iterator(labels=True) - edge_labels = tuple(sorted({label for _, _, label in edges - if label != (1, -1)})) + edge_labels = tuple(sorted({label for _, _, label in edges if label != (1, -1)})) edge_partition = [[] for _ in edge_labels] i = 0 while i in vertices: diff --git a/src/sage/combinat/cluster_algebra_quiver/mutation_type.py b/src/sage/combinat/cluster_algebra_quiver/mutation_type.py index e417980ee15..9359536002d 100644 --- a/src/sage/combinat/cluster_algebra_quiver/mutation_type.py +++ b/src/sage/combinat/cluster_algebra_quiver/mutation_type.py @@ -77,6 +77,7 @@ def is_mutation_finite(M, nr_of_checks=None) -> tuple[bool, list[int] | None]: True """ import random + n = M.ncols() if n <= 2: return True, None @@ -120,6 +121,7 @@ def _triangles(dg) -> list[tuple[list, bool]]: [([(1, 0), (2, 1), (0, 2)], True)] """ from itertools import combinations + trians = [] for x in dg.vertices(sort=True): nx = sorted(y for y in dg.neighbor_iterator(x) if x < y) @@ -188,6 +190,7 @@ def _all_induced_cycles_iter(dg) -> Iterator[tuple]: is_oriented = False yield (sg.edges(sort=True, labels=False), is_oriented) + # a debug function @@ -203,9 +206,9 @@ def _false_return(s=False) -> str: sage: _false_return() 'unknown' """ -# Uncomment these three lines for debugging purposes. -# if s: -# print('DEBUG: error %s' % s) + # Uncomment these three lines for debugging purposes. + # if s: + # print('DEBUG: error %s' % s) return 'unknown' @@ -249,8 +252,7 @@ def _reset_dg(dg, vertices, dict_in_out, del_vertices) -> None: dict_in_out[v] = (dg.in_degree(v), dg.out_degree(v), dg.degree(v)) -def _check_special_BC_cases(dg, n, check_letter_list, check_twist_list, - hope_letter_list, conn_vert_list=False): +def _check_special_BC_cases(dg, n, check_letter_list, check_twist_list, hope_letter_list, conn_vert_list=False): """ Test if dg (on at most `n` vertices) is a quiver of type `A` or `D` (as given in hope_letter_list) with conn_vert_list (if @@ -976,6 +978,7 @@ def _connected_mutation_type_AAtildeD(dg: DiGraph, ret_conn_vert=False): # test that no edge is in more than two oriented triangles from collections import Counter + edge_count = Counter(oriented_trian_edges) multiple_trian_edges = [] for edge, count in edge_count.items(): @@ -994,9 +997,7 @@ def _connected_mutation_type_AAtildeD(dg: DiGraph, ret_conn_vert=False): # if two edges appearing in exactly two oriented triangles, test # that the two edges together determine a unique triangle if count > 1: - test_triangles = [[tuple(trian) for trian in oriented_trians - if edge in trian] - for edge in multiple_trian_edges] + test_triangles = [[tuple(trian) for trian in oriented_trians if edge in trian] for edge in multiple_trian_edges] unique_triangle_set = set.intersection(*map(set, test_triangles)) if len(unique_triangle_set) != 1: return _false_return(19) @@ -1155,7 +1156,7 @@ def _connected_mutation_type_AAtildeD(dg: DiGraph, ret_conn_vert=False): if len(long_cycle[0]) == 2: edge = long_cycle[0][0] sg = DiGraph(dg) - sg. delete_vertices(edge) + sg.delete_vertices(edge) connected_components = sg.connected_components(sort=False) cycle = [] if connected_components: @@ -1165,7 +1166,7 @@ def _connected_mutation_type_AAtildeD(dg: DiGraph, ret_conn_vert=False): else: for edge in tmp: sg = DiGraph(dg) - sg. delete_vertices(edge) + sg.delete_vertices(edge) connected_components = sg.connected_components(sort=False) if len(connected_components) == 2: # if len(list_intersection([connected_components[0], list_substract(long_cycle[0], [edge])[0]])) > 0: @@ -1181,8 +1182,7 @@ def _connected_mutation_type_AAtildeD(dg: DiGraph, ret_conn_vert=False): r = sum(x[2] for x in cycle) r = max(r, n - r) if ret_conn_vert: - return [QuiverMutationType(['A', [r, n - r], 1]), - connecting_vertices] + return [QuiverMutationType(['A', [r, n - r], 1]), connecting_vertices] return QuiverMutationType(['A', [r, n - r], 1]) # post-parsing 2: if we are in another type, it is returned @@ -1284,6 +1284,7 @@ def _mutation_type_from_data(n: int, dig6, compute_if_necessary=True): # if this didn't work, we construct all exceptional quivers with n vertices if compute_if_necessary and data == {}: from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import save_quiver_data + save_quiver_data(n, up_to=False, types='Exceptional', verbose=False) load_data.clear_cache() data = load_data(n) @@ -1359,12 +1360,14 @@ def _mutation_type_test(n): from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import _construct_classical_mutation_classes from sage.combinat.cluster_algebra_quiver.mutation_class import _dig6_to_digraph from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver + data = _construct_classical_mutation_classes(n) keys = data.keys() for mutation_type in sorted(keys, key=str): mt = QuiverMutationType(mutation_type) print(all(ClusterQuiver(_dig6_to_digraph(dig6)).mutation_type() == mt for dig6 in data[mutation_type]), mutation_type) from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import _construct_exceptional_mutation_classes + data = _construct_exceptional_mutation_classes(n) keys = data.keys() for mutation_type in sorted(keys, key=str): @@ -1400,6 +1403,7 @@ def _random_tests(mt, k, mut_class=None, nr_mut=5): from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver from sage.combinat.cluster_algebra_quiver.mutation_class import _dig6_to_matrix, _matrix_to_digraph, _digraph_mutate, _edge_list_to_matrix import random + if mut_class is None: mut_class = ClusterQuiver(mt).mutation_class(data_type='dig6') print("testing " + str(mt)) @@ -1456,11 +1460,9 @@ def _random_tests(mt, k, mut_class=None, nr_mut=5): mt_new = _connected_mutation_type(dg_new) if mt != mt_new: print("FOUND ERROR!") - print(_edge_list_to_matrix(dg.edges(sort=True), - list(range(dg.order())), [])) + print(_edge_list_to_matrix(dg.edges(sort=True), list(range(dg.order())), [])) print("has mutation type " + str(mt) + " while it has mutation type " + str(mt_new) + " after mutating at " + str(mut) + ":") - print(_edge_list_to_matrix(dg_new.edges(sort=True), - list(range(dg.order())), [])) + print(_edge_list_to_matrix(dg_new.edges(sort=True), list(range(dg.order())), [])) return dg, dg_new dg = dg_new @@ -1507,7 +1509,7 @@ def _random_multi_tests(n, k, nr_mut=5): testing ('D', 4) """ from sage.combinat.cluster_algebra_quiver.quiver_mutation_type import _construct_classical_mutation_classes + mutation_classes = _construct_classical_mutation_classes(n) for mutation_type in sorted(mutation_classes, key=str): - _random_tests(mutation_type, k, - mut_class=mutation_classes[mutation_type], nr_mut=nr_mut) + _random_tests(mutation_type, k, mut_class=mutation_classes[mutation_type], nr_mut=nr_mut) diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver.py b/src/sage/combinat/cluster_algebra_quiver/quiver.py index 8083464266a..278b908ddf6 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver.py @@ -234,20 +234,14 @@ def __init__(self, data, frozen=None, user_labels=None) -> None: from sage.structure.element import Matrix if isinstance(user_labels, list): - user_labels = [tuple(x) if isinstance(x, list) else x - for x in user_labels] + user_labels = [tuple(x) if isinstance(x, list) else x for x in user_labels] elif isinstance(user_labels, dict): - user_labels = {x: tuple(label) if isinstance(label, list) - else label - for x, label in user_labels.items()} + user_labels = {x: tuple(label) if isinstance(label, list) else label for x, label in user_labels.items()} # constructs a quiver from a mutation type - if isinstance(data, (QuiverMutationType_Irreducible, - QuiverMutationType_Reducible)): + if isinstance(data, (QuiverMutationType_Irreducible, QuiverMutationType_Reducible)): if frozen is not None: - print('The input specifies a mutation type, so the' - ' additional parameter frozen is ignored.' - ' Use set_frozen to freeze vertices.') + print('The input specifies a mutation type, so the' ' additional parameter frozen is ignored.' ' Use set_frozen to freeze vertices.') mutation_type = data self.__init__(mutation_type.standard_quiver()) @@ -260,13 +254,9 @@ def __init__(self, data, frozen=None, user_labels=None) -> None: # NOTE: for now, any string representing a *reducible type* is # coerced into the standard quiver, but there is now more flexibility # in how to input a connected (irreducible) quiver. - elif (isinstance(data, (list, tuple)) - and (isinstance(data[0], str) or - all(isinstance(comp, (list, tuple)) - and isinstance(comp[0], str) for comp in data))): + elif isinstance(data, (list, tuple)) and (isinstance(data[0], str) or all(isinstance(comp, (list, tuple)) and isinstance(comp[0], str) for comp in data)): if frozen is not None: - print('The input specifies a mutation type, so the additional' - ' parameter frozen is ignored. Use set_frozen to freeze vertices.') + print('The input specifies a mutation type, so the additional' ' parameter frozen is ignored. Use set_frozen to freeze vertices.') mutation_type = QuiverMutationType(data) # The command QuiverMutationType_Irreducible (which is not imported @@ -289,13 +279,11 @@ def __init__(self, data, frozen=None, user_labels=None) -> None: self.__init__(mutation_type.standard_quiver()) elif len(data) == 3 and isinstance(data[0], str): d0, d1, d2 = data - if ((d0 == 'F' and d1 == 4 and d2 == [2, 1]) or - (d0 == 'G' and d1 == 2 and d2 == [3, 1])): + if (d0 == 'F' and d1 == 4 and d2 == [2, 1]) or (d0 == 'G' and d1 == 2 and d2 == [3, 1]): quiv = ClusterQuiver(QuiverMutationType_Irreducible(d0, d1, tuple(d2))._digraph) quiv._mutation_type = mutation_type self.__init__(quiv) - elif ((d0 == 'F' and d1 == 4 and d2 == (2, 1)) or - (d0 == 'G' and d1 == 2 and d2 == (3, 1))): + elif (d0 == 'F' and d1 == 4 and d2 == (2, 1)) or (d0 == 'G' and d1 == 2 and d2 == (3, 1)): quiv = ClusterQuiver(QuiverMutationType_Irreducible(d0, d1, d2)._digraph) quiv._mutation_type = mutation_type self.__init__(quiv) @@ -335,8 +323,7 @@ def __init__(self, data, frozen=None, user_labels=None) -> None: # constructs a quiver from a quiver elif isinstance(data, ClusterQuiver): if frozen is not None: - print('The input data is a quiver, therefore the additional' - ' parameter frozen is ignored. Use set_frozen to freeze vertices.') + print('The input data is a quiver, therefore the additional' ' parameter frozen is ignored. Use set_frozen to freeze vertices.') self._M = copy(data._M) self._M.set_immutable() @@ -368,10 +355,10 @@ def __init__(self, data, frozen=None, user_labels=None) -> None: if user_labels: if isinstance(user_labels, dict): self._nlist = list(user_labels)[0:n] - self._mlist = list(user_labels)[n:n+m] + self._mlist = list(user_labels)[n : n + m] elif isinstance(user_labels, list): self._nlist = user_labels[0:n] - self._mlist = user_labels[n:n+m] + self._mlist = user_labels[n : n + m] self._digraph.relabel(self._nlist + self._mlist) else: self._mlist = list(range(n, n + m)) @@ -408,8 +395,7 @@ def __init__(self, data, frozen=None, user_labels=None) -> None: if data.has_loops(): raise ValueError("the input DiGraph contains a loop") - if any(data.has_edge((b, a)) - for a, b in data.edge_iterator(labels=False)): + if any(data.has_edge((b, a)) for a, b in data.edge_iterator(labels=False)): raise ValueError("the input DiGraph contains two-cycles") dg = copy(data) @@ -425,20 +411,17 @@ def __init__(self, data, frozen=None, user_labels=None) -> None: multi_edges = {} for v1, v2, label in multiple_edges: if label not in ZZ: - raise ValueError("the input DiGraph contains multiple" - " edges labeled by non-integers") + raise ValueError("the input DiGraph contains multiple" " edges labeled by non-integers") elif (v1, v2) in multi_edges: multi_edges[(v1, v2)] += label else: multi_edges[(v1, v2)] = label dg.delete_edge(v1, v2) - dg.add_edges([(v1, v2, multi_edges[(v1, v2)]) - for v1, v2 in multi_edges]) + dg.add_edges([(v1, v2, multi_edges[(v1, v2)]) for v1, v2 in multi_edges]) for e0, e1, lab in dg.edge_iterator(): if e0 >= n and e1 >= n: - raise ValueError("the input digraph contains edges" - " within the frozen vertices") + raise ValueError("the input digraph contains edges" " within the frozen vertices") if lab is None: lab = (1, -1) dg.set_edge_label(e0, e1, lab) @@ -446,20 +429,16 @@ def __init__(self, data, frozen=None, user_labels=None) -> None: lab = (lab, -lab) dg.set_edge_label(e0, e1, lab) elif isinstance(lab, list) and len(lab) != 2: - raise ValueError("the input digraph contains an edge with" - " the wrong type of list as a label") + raise ValueError("the input digraph contains an edge with" " the wrong type of list as a label") elif isinstance(lab, list) and len(lab) == 2: lab = tuple(lab) dg.set_edge_label(e0, e1, lab) elif (e0 >= n or e1 >= n) and not lab[0] == -lab[1]: - raise ValueError("the input digraph contains an edge to or" - " from a frozen vertex which is not skew-symmetric") + raise ValueError("the input digraph contains an edge to or" " from a frozen vertex which is not skew-symmetric") if lab[0] < 0: - raise ValueError("the input digraph contains an edge of " - "the form (a,-b) with negative a") + raise ValueError("the input digraph contains an edge of " "the form (a,-b) with negative a") - M = _edge_list_to_matrix(dg.edge_iterator(), list(range(n)), - list(range(n, n + m))) + M = _edge_list_to_matrix(dg.edge_iterator(), list(range(n)), list(range(n, n + m))) if not _principal_part(M).is_skew_symmetrizable(positive=True): raise ValueError("the input digraph must be skew-symmetrizable") @@ -480,8 +459,7 @@ def __init__(self, data, frozen=None, user_labels=None) -> None: # if data is a list of edges, the appropriate digraph is constructed. - elif (isinstance(data, (list, EdgesView)) - and all(isinstance(x, (list, tuple)) for x in data)): + elif isinstance(data, (list, EdgesView)) and all(isinstance(x, (list, tuple)) for x in data): dg = DiGraph(data) self.__init__(data=dg, frozen=frozen) @@ -492,6 +470,7 @@ def __init__(self, data, frozen=None, user_labels=None) -> None: # stopgap for bugs arising from coefficients if self._m: from sage.misc.stopgap import stopgap + stopgap("Having frozen nodes is known to produce wrong answers", 22381) def __eq__(self, other) -> bool: @@ -546,8 +525,7 @@ def _repr_(self) -> str: name += ' with %s frozen vertices' % self._m return name - def plot(self, circular=True, center=(0, 0), directed=True, mark=None, - save_pos=False, greens=[]): + def plot(self, circular=True, center=(0, 0), directed=True, mark=None, save_pos=False, greens=[]): """ Return the plot of the underlying digraph of ``self``. @@ -581,6 +559,7 @@ def plot(self, circular=True, center=(0, 0), directed=True, mark=None, from sage.symbolic.constants import e, pi from sage.rings.cc import CC from sage.rings.imaginary_unit import I + graphs = GraphGenerators() # returns positions for graph vertices on two concentric cycles with radius 1 and 2 @@ -588,10 +567,10 @@ def _graphs_concentric_circles(n, m): g1 = graphs.CycleGraph(n).get_pos() g2 = graphs.CycleGraph(m).get_pos() for i in g2: - z = CC(g2[i])*e**(-pi*I/(2*m)) + z = CC(g2[i]) * e ** (-pi * I / (2 * m)) g2[i] = (z.real_part(), z.imag_part()) for i in range(m): - g1[n+i] = [2*g2[i][0], 2*g2[i][1]] + g1[n + i] = [2 * g2[i][0], 2 * g2[i][1]] return g1 n, m = self._n, self._m @@ -599,8 +578,7 @@ def _graphs_concentric_circles(n, m): nlist = copy(self._nlist) mlist = copy(self._mlist) colors = rainbow(11) - color_dict = {colors[0]: [], colors[1]: [], - colors[6]: [], colors[5]: []} + color_dict = {colors[0]: [], colors[1]: [], colors[6]: [], colors[5]: []} # Set up our graph. If it's directed we have a digraph, else # just a normal graph @@ -650,9 +628,7 @@ def _graphs_concentric_circles(n, m): mlist.remove(i) partition = (nlist, mlist, greens) - vertex_color_dict = {'tomato': partition[0], - 'lightblue': partition[1], - 'lightgreen': partition[2]} + vertex_color_dict = {'tomato': partition[0], 'lightblue': partition[1], 'lightgreen': partition[2]} options = { 'graph_border': True, @@ -670,8 +646,7 @@ def _graphs_concentric_circles(n, m): vkey = self._vertex_dictionary[v] else: vkey = v - options['pos'][vkey] = (pp[v][0] + center[0], - pp[v][1] + center[1]) + options['pos'][vkey] = (pp[v][0] + center[0], pp[v][1] + center[1]) return dg.plot(**options) @@ -700,12 +675,11 @@ def show(self, fig_size=1, circular=False, directed=True, mark=None, save_pos=Fa sage: Q.show() # long time """ n, m = self._n, self._m - plot = self.plot(circular=circular, directed=directed, - mark=mark, save_pos=save_pos, greens=greens) + plot = self.plot(circular=circular, directed=directed, mark=mark, save_pos=save_pos, greens=greens) if circular: - plot.show(figsize=[fig_size*3*(n+m)/4+1, fig_size*3*(n+m)/4+1]) + plot.show(figsize=[fig_size * 3 * (n + m) / 4 + 1, fig_size * 3 * (n + m) / 4 + 1]) else: - plot.show(figsize=[fig_size*n+1, fig_size*n+1]) + plot.show(figsize=[fig_size * n + 1, fig_size * n + 1]) def interact(self, fig_size=1, circular=True): r""" @@ -784,6 +758,7 @@ def qmu_save(self, filename=None): if self.m(): from sage.matrix.constructor import matrix from sage.matrix.constructor import block_matrix + M1 = M.matrix_from_rows(range(self.n())) M2 = M.matrix_from_rows(list(range(self.n(), self.n() + self.m()))) M3 = matrix(self.m(), self.m()) @@ -811,8 +786,7 @@ def qmu_save(self, filename=None): string.append('1') string.append('//Matrix') string.append(str(m) + ' ' + str(m)) - string.extend(' '.join(str(M[i, j]) for j in range(m)) - for i in range(m)) + string.extend(' '.join(str(M[i, j]) for j in range(m)) for i in range(m)) string.append('//Points') for i in range(m): @@ -1066,8 +1040,7 @@ def mutation_type(self): elif len(mutation_type) == 1: mutation_type = mutation_type[0] # the reducible quiver case - elif not any(isinstance(mut_type_part, str) - for mut_type_part in mutation_type): + elif not any(isinstance(mut_type_part, str) for mut_type_part in mutation_type): mutation_type = QuiverMutationType(mutation_type) self._mutation_type = mutation_type return self._mutation_type @@ -1178,11 +1151,9 @@ def canonical_label(self, certificate=False): Q._mutation_type = self._mutation_type else: CC = sorted(self._digraph.connected_components(sort=False)) - CC_new = sorted(zip([sorted(iso[i] for i in L) for L in CC], - range(len(CC)))) + CC_new = sorted(zip([sorted(iso[i] for i in L) for L in CC], range(len(CC)))) comp_iso = [L[1] for L in CC_new] - Q._mutation_type = [copy(self._mutation_type.irreducible_components()[comp_i]) - for comp_i in comp_iso] + Q._mutation_type = [copy(self._mutation_type.irreducible_components()[comp_i]) for comp_i in comp_iso] Q._mutation_type = QuiverMutationType(Q._mutation_type) if certificate: return Q, iso @@ -1276,8 +1247,7 @@ def principal_extension(self, inplace=False): """ dg = self._digraph.copy(immutable=False) dg.add_edges([(self._n + self._m + i, i) for i in range(self._n)]) - Q = ClusterQuiver(dg, frozen=list(range(self._n, - 2 * self._n + self._m))) + Q = ClusterQuiver(dg, frozen=list(range(self._n, 2 * self._n + self._m))) Q._mutation_type = self._mutation_type if inplace: self.__init__(Q) @@ -1529,17 +1499,16 @@ def mutation_sequence(self, sequence, show_sequence=False, fig_size=1.2): m = self._m if m == 0: width_factor = 3 - fig_size = fig_size*2*n/3 + fig_size = fig_size * 2 * n / 3 else: width_factor = 6 - fig_size = fig_size*4*n/3 + fig_size = fig_size * 4 * n / 3 V = range(n) if isinstance(sequence, tuple): sequence = list(sequence) if not isinstance(sequence, list): - raise ValueError('the quiver can only be mutated at a vertex' - ' or at a sequence of vertices') + raise ValueError('the quiver can only be mutated at a vertex' ' or at a sequence of vertices') if any(v not in V for v in sequence): v = next(v for v in sequence if v not in V) raise ValueError(f'the quiver can only be mutated at the vertex {v}') @@ -1557,11 +1526,10 @@ def mutation_sequence(self, sequence, show_sequence=False, fig_size=1.2): from sage.plot.text import text def _plot_arrow(v, k, center=(0, 0)): - return text(r"$\longleftrightarrow$", (center[0], center[1]), fontsize=25) + text(r"$\mu_"+str(v)+"$", (center[0], center[1]+0.15), fontsize=15) \ - + text("$"+str(k)+"$", (center[0], center[1]-0.2), fontsize=15) + return text(r"$\longleftrightarrow$", (center[0], center[1]), fontsize=25) + text(r"$\mu_" + str(v) + "$", (center[0], center[1] + 0.15), fontsize=15) + text("$" + str(k) + "$", (center[0], center[1] - 0.2), fontsize=15) - plot_sequence = [quiver_sequence[i].plot(circular=True, center=(i*width_factor, 0)) for i in range(len(quiver_sequence))] - arrow_sequence = [_plot_arrow(sequence[i], i+1, center=((i+0.5)*width_factor, 0)) for i in range(len(sequence))] + plot_sequence = [quiver_sequence[i].plot(circular=True, center=(i * width_factor, 0)) for i in range(len(quiver_sequence))] + arrow_sequence = [_plot_arrow(sequence[i], i + 1, center=((i + 0.5) * width_factor, 0)) for i in range(len(sequence))] sequence = [] for i in range(len(plot_sequence)): if i < len(arrow_sequence): @@ -1571,8 +1539,7 @@ def _plot_arrow(v, k, center=(0, 0)): plot_obj = Graphics() for elem in sequence: plot_obj += elem - plot_obj.show(axes=False, figsize=[fig_size * len(quiver_sequence), - fig_size]) + plot_obj.show(axes=False, figsize=[fig_size * len(quiver_sequence), fig_size]) return quiver_sequence def reorient(self, data): @@ -1630,8 +1597,7 @@ def reorient(self, data): else: dg_new.add_edge(edge[1], edge[0], edge[2]) self._digraph = dg_new - self._M = _edge_list_to_matrix(dg_new.edges(sort=True), - self._nlist, self._mlist) + self._M = _edge_list_to_matrix(dg_new.edges(sort=True), self._nlist, self._mlist) self._M.set_immutable() self._mutation_type = None elif isinstance(first, (list, tuple)) and len(first) == 2: @@ -1641,17 +1607,13 @@ def reorient(self, data): label = self._digraph.edge_label(edge[1], edge[0]) self._digraph.delete_edge(edge[1], edge[0]) self._digraph.add_edge(edge[0], edge[1], label) - self._M = _edge_list_to_matrix(self._digraph.edges(sort=True), - self._nlist, self._mlist) + self._M = _edge_list_to_matrix(self._digraph.edges(sort=True), self._nlist, self._mlist) self._M.set_immutable() self._mutation_type = None else: - raise ValueError('not a total order on the vertices of the quiver' - ' or a list of edges to be oriented') + raise ValueError('not a total order on the vertices of the quiver' ' or a list of edges to be oriented') - def mutation_class_iter(self, depth=infinity, show_depth=False, - return_paths=False, data_type='quiver', - up_to_equivalence=True, sink_source=False): + def mutation_class_iter(self, depth=infinity, show_depth=False, return_paths=False, data_type='quiver', up_to_equivalence=True, sink_source=False): """ Return an iterator for the mutation class of ``self`` together with certain constraints. @@ -1769,11 +1731,7 @@ def mutation_class_iter(self, depth=infinity, show_depth=False, dg = ClusterQuiver(self._M).digraph() frozen = list(range(self._n, self._n + self._m)) - MC_iter = _mutation_class_iter(dg, self._n, self._m, depth=depth, - return_dig6=return_dig6, - show_depth=show_depth, - up_to_equivalence=up_to_equivalence, - sink_source=sink_source) + MC_iter = _mutation_class_iter(dg, self._n, self._m, depth=depth, return_dig6=return_dig6, show_depth=show_depth, up_to_equivalence=up_to_equivalence, sink_source=sink_source) for data in MC_iter: if data_type == "quiver": next_element = ClusterQuiver(data[0], frozen=frozen) @@ -1787,15 +1745,13 @@ def mutation_class_iter(self, depth=infinity, show_depth=False, elif data_type == "path": next_element = data[1] else: - raise ValueError("the parameter for data_type was " - "not recognized") + raise ValueError("the parameter for data_type was " "not recognized") if return_paths: yield (next_element, data[1]) else: yield next_element - def mutation_class(self, depth=infinity, show_depth=False, return_paths=False, - data_type='quiver', up_to_equivalence=True, sink_source=False): + def mutation_class(self, depth=infinity, show_depth=False, return_paths=False, data_type='quiver', up_to_equivalence=True, sink_source=False): """ Return the mutation class of ``self`` together with certain constraints. @@ -1895,13 +1851,8 @@ def mutation_class(self, depth=infinity, show_depth=False, return_paths=False, True """ if depth is infinity and not self.is_mutation_finite(): - raise ValueError('the mutation class can - for infinite mutation' - ' types - only be computed up to a given depth') - return list(self.mutation_class_iter(depth=depth, show_depth=show_depth, - return_paths=return_paths, - data_type=data_type, - up_to_equivalence=up_to_equivalence, - sink_source=sink_source)) + raise ValueError('the mutation class can - for infinite mutation' ' types - only be computed up to a given depth') + return list(self.mutation_class_iter(depth=depth, show_depth=show_depth, return_paths=return_paths, data_type=data_type, up_to_equivalence=up_to_equivalence, sink_source=sink_source)) def is_finite(self) -> bool: """ @@ -1943,8 +1894,7 @@ def is_finite(self) -> bool: False """ mt = self.mutation_type() - return (type(mt) in [QuiverMutationType_Irreducible, - QuiverMutationType_Reducible] and mt.is_finite()) + return type(mt) in [QuiverMutationType_Irreducible, QuiverMutationType_Reducible] and mt.is_finite() def is_mutation_finite(self, nr_of_checks=None, return_path=False) -> bool: """ @@ -1984,15 +1934,10 @@ def is_mutation_finite(self, nr_of_checks=None, return_path=False) -> bool: path = None elif not return_path and self._mutation_type == 'undetermined infinite mutation type': is_finite = False - elif (isinstance(self._mutation_type, (QuiverMutationType_Irreducible, - QuiverMutationType_Reducible)) - and self._mutation_type.is_mutation_finite()): + elif isinstance(self._mutation_type, (QuiverMutationType_Irreducible, QuiverMutationType_Reducible)) and self._mutation_type.is_mutation_finite(): is_finite = True path = None - elif (not return_path and isinstance(self._mutation_type, - (QuiverMutationType_Irreducible, - QuiverMutationType_Reducible)) - and not self._mutation_type.is_mutation_finite()): + elif not return_path and isinstance(self._mutation_type, (QuiverMutationType_Irreducible, QuiverMutationType_Reducible)) and not self._mutation_type.is_mutation_finite(): is_finite = False else: # turning dg_component into a canonical form @@ -2066,8 +2011,7 @@ def relabel(self, relabelling, inplace=True): # If the key is in the old vertices, use that mapping digraph_labels[key] = val # And place it in the right order for our dictionary - loc = [i for i, x in enumerate(old_vertices) - if x == key][0] + loc = [i for i, x in enumerate(old_vertices) if x == key][0] dict_labels[loc] = val elif isinstance(key, int) and len(old_vertices) > key: # If the key is an integer, grab that particular vertex @@ -2149,16 +2093,14 @@ def poincare_semistable(self, theta, d): n = self.n() b_mat = self.b_matrix() - Eu = matrix(ZZ, n, n, - lambda i, j: -b_mat[i, j] if b_mat[i, j] > 0 else 0) + Eu = matrix(ZZ, n, n, lambda i, j: -b_mat[i, j] if b_mat[i, j] > 0 else 0) Eu = 1 + Eu edges = list(self.digraph().edges(sort=True, labels=False)) mu_d = theta.dot_product(d) / sum(d) Li = [0 * d] - it = (vector(e) for e in product(*[range(d_i + 1) - for d_i in d])) + it = (vector(e) for e in product(*[range(d_i + 1) for d_i in d])) Li += [e for e in it if e.dot_product(theta) > mu_d * sum(e)] Li.append(d) N = len(Li) - 1 @@ -2167,8 +2109,7 @@ def poincare_semistable(self, theta, d): def cardinal_RG(d): cardinal_G = prod(q**d_i - q**k for d_i in d for k in range(d_i)) - cardinal_R = prod(q**(b_mat[i, j] * d[i] * d[j]) - for i, j in edges) + cardinal_R = prod(q ** (b_mat[i, j] * d[i] * d[j]) for i, j in edges) return cardinal_R / cardinal_G Reineke_submat = matrix(q.parent().fraction_field(), N, N) @@ -2183,7 +2124,7 @@ def cardinal_RG(d): power = (-f_e) * Eu * e Reineke_submat[i, j] = q**power * cardinal_RG(f_e) - poly = (-1)**N * ((1 - q) * Reineke_submat.det()).numerator() + poly = (-1) ** N * ((1 - q) * Reineke_submat.det()).numerator() return poly(q**2) # replacing q by v**2 def d_vector_fan(self): @@ -2233,8 +2174,7 @@ def d_vector_fan(self): from sage.geometry.cone import Cone seed = ClusterSeed(self) - return Fan([Cone(s.d_matrix().columns()) - for s in seed.mutation_class()]) + return Fan([Cone(s.d_matrix().columns()) for s in seed.mutation_class()]) def g_vector_fan(self): r""" @@ -2281,5 +2221,4 @@ def g_vector_fan(self): if not (self.is_finite()): raise ValueError('only supported for quivers of finite type') seed = ClusterSeed(self).principal_extension() - return Fan([Cone(s.g_matrix().columns()) - for s in seed.mutation_class()]) + return Fan([Cone(s.g_matrix().columns()) for s in seed.mutation_class()]) diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py index c3d41dfcd78..8be3d2138fe 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py @@ -67,9 +67,7 @@ def __call__(self, *args): _mutation_type_error(data) # check for reducible types - if all(isinstance(data_component, (list, tuple, - QuiverMutationType_Irreducible)) - for data_component in data): + if all(isinstance(data_component, (list, tuple, QuiverMutationType_Irreducible)) for data_component in data): if len(data) == 1: return QuiverMutationType(data[0]) data = tuple(QuiverMutationType(comp) for comp in data) @@ -219,8 +217,7 @@ def _repr_(self) -> str: """ return "QuiverMutationType" - def samples(self, finite=None, affine=None, elliptic=None, - mutation_finite=None): + def samples(self, finite=None, affine=None, elliptic=None, mutation_finite=None): """ Return a sample of the available quiver mutations types. @@ -271,8 +268,7 @@ def samples(self, finite=None, affine=None, elliptic=None, if elliptic is not None: result = [t for t in result if t.is_elliptic() == elliptic] if mutation_finite is not None: - result = [t for t in result - if t.is_mutation_finite() == mutation_finite] + result = [t for t in result if t.is_mutation_finite() == mutation_finite] return result @cached_method @@ -284,19 +280,11 @@ def _samples(self): sage: X = QuiverMutationType._samples() """ - finite_types = \ - [QuiverMutationType(t) for t in [['A', 1], ['A', 5], ['B', 2], ['B', 5], - ['C', 3], ['C', 5], ['D', 2], ['D', 5], - ["E", 6], ["E", 7], ["E", 8], ["F", 4], - ["G", 2]]] - affine_types = \ - [QuiverMutationType(t) for t in [['A', [1, 1], 1], ['A', [4, 5], 1], ['D', 4, 1], ['BB', 5, 1]]] - elliptic_types = \ - [QuiverMutationType(t) for t in [['E', 6, [1, 1]], ['E', 7, [1, 1]]]] - mutation_finite_types = \ - [QuiverMutationType(t) for t in [['R2', (1, 5)], ['R2', (3, 5)]]] - mutation_infinite_types = \ - [QuiverMutationType(t) for t in [['E', 10], ['BE', 5], ['GR', (3, 10)], ['T', (3, 3, 4)]]] + finite_types = [QuiverMutationType(t) for t in [['A', 1], ['A', 5], ['B', 2], ['B', 5], ['C', 3], ['C', 5], ['D', 2], ['D', 5], ["E", 6], ["E", 7], ["E", 8], ["F", 4], ["G", 2]]] + affine_types = [QuiverMutationType(t) for t in [['A', [1, 1], 1], ['A', [4, 5], 1], ['D', 4, 1], ['BB', 5, 1]]] + elliptic_types = [QuiverMutationType(t) for t in [['E', 6, [1, 1]], ['E', 7, [1, 1]]]] + mutation_finite_types = [QuiverMutationType(t) for t in [['R2', (1, 5)], ['R2', (3, 5)]]] + mutation_infinite_types = [QuiverMutationType(t) for t in [['E', 10], ['BE', 5], ['GR', (3, 10)], ['T', (3, 3, 4)]]] return finite_types + affine_types + elliptic_types + mutation_finite_types + mutation_infinite_types @@ -304,8 +292,7 @@ def _samples(self): QuiverMutationType = QuiverMutationTypeFactory() -QuiverMutationType.__doc__ = \ - r""" +QuiverMutationType.__doc__ = r""" *Quiver mutation types* can be seen as a slight generalization of *generalized Cartan types*. @@ -836,6 +823,7 @@ def standard_quiver(self): Quiver on 12 vertices of type [ ['A', 3], ['B', 3], ['X', 6] ] """ from .quiver import ClusterQuiver + Q = ClusterQuiver(self._digraph) Q._mutation_type = self return Q @@ -1215,11 +1203,11 @@ def __init__(self, letter, rank, twist=None): else: _mutation_type_error(data) for i in range(rank - 2): - self._graph.add_edge(i, i+1, 1) - if (rank % 2 == 0): - self._graph.add_edge(rank-2, rank-1, (1, -2)) + self._graph.add_edge(i, i + 1, 1) + if rank % 2 == 0: + self._graph.add_edge(rank - 2, rank - 1, (1, -2)) else: - self._graph.add_edge(rank-2, rank-1, (2, -1)) + self._graph.add_edge(rank - 2, rank - 1, (2, -1)) # type C (finite) elif letter == 'C': @@ -1230,11 +1218,11 @@ def __init__(self, letter, rank, twist=None): else: _mutation_type_error(data) for i in range(rank - 2): - self._graph.add_edge(i, i+1, 1) - if (rank % 2 == 0): - self._graph.add_edge(rank-2, rank-1, (2, -1)) + self._graph.add_edge(i, i + 1, 1) + if rank % 2 == 0: + self._graph.add_edge(rank - 2, rank - 1, (2, -1)) else: - self._graph.add_edge(rank-2, rank-1, (1, -2)) + self._graph.add_edge(rank - 2, rank - 1, (1, -2)) # type BB (affine) elif letter == 'BB': @@ -1245,11 +1233,11 @@ def __init__(self, letter, rank, twist=None): else: _mutation_type_error(data) for i in range(rank - 2): - self._graph.add_edge(i, i+1, 1) + self._graph.add_edge(i, i + 1, 1) if rank % 2 == 0: - self._graph.add_edge(rank-2, rank-1, (1, -2)) + self._graph.add_edge(rank - 2, rank - 1, (1, -2)) else: - self._graph.add_edge(rank-2, rank-1, (2, -1)) + self._graph.add_edge(rank - 2, rank - 1, (2, -1)) self._graph.add_edge(rank, 0, (1, -2)) # type CC (affine) @@ -1261,11 +1249,11 @@ def __init__(self, letter, rank, twist=None): else: _mutation_type_error(data) for i in range(rank - 2): - self._graph.add_edge(i, i+1, 1) + self._graph.add_edge(i, i + 1, 1) if rank % 2 == 0: - self._graph.add_edge(rank-2, rank-1, (2, -1)) + self._graph.add_edge(rank - 2, rank - 1, (2, -1)) else: - self._graph.add_edge(rank-2, rank-1, (1, -2)) + self._graph.add_edge(rank - 2, rank - 1, (1, -2)) self._graph.add_edge(rank, 0, (2, -1)) # type BC (affine) @@ -1280,11 +1268,11 @@ def __init__(self, letter, rank, twist=None): self._graph.add_edge(0, 1, (1, -4)) else: for i in range(rank - 2): - self._graph.add_edge(i, i+1, 1) - if (rank % 2 == 0): - self._graph.add_edge(rank-2, rank-1, (2, -1)) + self._graph.add_edge(i, i + 1, 1) + if rank % 2 == 0: + self._graph.add_edge(rank - 2, rank - 1, (2, -1)) else: - self._graph.add_edge(rank-2, rank-1, (1, -2)) + self._graph.add_edge(rank - 2, rank - 1, (1, -2)) if twist == 1: self._graph.add_edge(rank, 0, (1, -2)) @@ -1297,11 +1285,11 @@ def __init__(self, letter, rank, twist=None): else: _mutation_type_error(data) for i in range(rank - 2): - self._graph.add_edge(i, i+1, 1) - if (rank % 2 == 0): - self._graph.add_edge(rank-2, rank-1, (1, -2)) + self._graph.add_edge(i, i + 1, 1) + if rank % 2 == 0: + self._graph.add_edge(rank - 2, rank - 1, (1, -2)) else: - self._graph.add_edge(rank-2, rank-1, (2, -1)) + self._graph.add_edge(rank - 2, rank - 1, (2, -1)) if twist == 1: self._graph.add_edge(rank, 1, 1) @@ -1314,11 +1302,11 @@ def __init__(self, letter, rank, twist=None): else: _mutation_type_error(data) for i in range(rank - 2): - self._graph.add_edge(i, i+1, 1) - if (rank % 2 == 0): - self._graph.add_edge(rank-2, rank-1, (2, -1)) + self._graph.add_edge(i, i + 1, 1) + if rank % 2 == 0: + self._graph.add_edge(rank - 2, rank - 1, (2, -1)) else: - self._graph.add_edge(rank-2, rank-1, (1, -2)) + self._graph.add_edge(rank - 2, rank - 1, (1, -2)) if twist == 1: self._graph.add_edge(rank, 1, 1) @@ -1339,9 +1327,9 @@ def __init__(self, letter, rank, twist=None): else: _mutation_type_error(data) for i in range(rank - 2): - self._graph.add_edge(i, i+1, 1) + self._graph.add_edge(i, i + 1, 1) - self._graph.add_edge(rank-3, rank-1, 1) + self._graph.add_edge(rank - 3, rank - 1, 1) if twist is not None: self._graph.add_edge(rank, 1, 1) @@ -1356,11 +1344,9 @@ def __init__(self, letter, rank, twist=None): if rank == 6: self._graph.add_edges([(0, 1), (1, 2), (2, 3), (3, 4), (2, 5)]) elif rank == 7: - self._graph.add_edges([(0, 1), (1, 2), (2, 3), - (3, 4), (4, 5), (2, 6)]) + self._graph.add_edges([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (2, 6)]) elif rank == 8: - self._graph.add_edges([(0, 1), (1, 2), (2, 3), - (3, 4), (4, 5), (5, 6), (2, 7)]) + self._graph.add_edges([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (2, 7)]) elif rank in [6, 7, 8] and twist == 1: self._rank = rank + 1 self._info['mutation_finite'] = True @@ -1381,19 +1367,17 @@ def __init__(self, letter, rank, twist=None): if rank == 6: self._digraph.add_edges([(0, 1, 1), (1, 2, 1), (3, 2, 1), (3, 4, 1), (5, 6, 1), (6, 7, 1), (5, 1, 1), (2, 5, 2), (5, 3, 1), (6, 2, 1)]) elif rank == 7: - self._digraph.add_edges([(1, 0, 1), (1, 2, 1), (2, 3, 1), (4, 3, 1), (4, 5, 1), - (6, 5, 1), (7, 8, 1), (3, 7, 2), (7, 2, 1), (7, 4, 1), (8, 3, 1)]) + self._digraph.add_edges([(1, 0, 1), (1, 2, 1), (2, 3, 1), (4, 3, 1), (4, 5, 1), (6, 5, 1), (7, 8, 1), (3, 7, 2), (7, 2, 1), (7, 4, 1), (8, 3, 1)]) elif rank == 8: - self._digraph.add_edges([(0, 1, 1), (1, 9, 1), (3, 9, 1), (3, 4, 1), (2, 8, 1), (2, 1, 1), - (9, 2, 2), (2, 3, 1), (8, 9, 1), (5, 4, 1), (5, 6, 1), (7, 6, 1)]) + self._digraph.add_edges([(0, 1, 1), (1, 9, 1), (3, 9, 1), (3, 4, 1), (2, 8, 1), (2, 1, 1), (9, 2, 2), (2, 3, 1), (8, 9, 1), (5, 4, 1), (5, 6, 1), (7, 6, 1)]) # type E (mutation infinite) elif rank > 9 and twist is None: self._info['simply_laced'] = True self._info['skew_symmetric'] = True self._rank = rank - for i in range(rank-2): - self._graph.add_edge(i, i+1, 1) - self._graph.add_edge(2, rank-1) + for i in range(rank - 2): + self._graph.add_edge(i, i + 1, 1) + self._graph.add_edge(2, rank - 1) else: _mutation_type_error(data) @@ -1413,12 +1397,12 @@ def __init__(self, letter, rank, twist=None): self._graph.add_edges([(0, 1, 2), (1, 2, None)]) else: self._digraph.add_edge(self._rank - 2, 0) - for i in range(self._rank-2): + for i in range(self._rank - 2): if i < (2 * self._bi_rank[0]) and i % 2 == 0: self._digraph.add_edge(i + 1, i) else: self._digraph.add_edge(i, i + 1) - self._digraph.add_edge(self._rank-2, self._rank-1) + self._digraph.add_edge(self._rank - 2, self._rank - 1) else: _mutation_type_error(data) @@ -1426,13 +1410,13 @@ def __init__(self, letter, rank, twist=None): elif letter == 'BE': if rank > 4 and twist is None: self._rank = rank - for i in range(rank-3): - self._graph.add_edge(i, i+1) - self._graph.add_edge(2, rank-1) + for i in range(rank - 3): + self._graph.add_edge(i, i + 1) + self._graph.add_edge(2, rank - 1) if rank % 2 == 0: - self._graph.add_edge(rank-3, rank-2, (2, -1)) + self._graph.add_edge(rank - 3, rank - 2, (2, -1)) else: - self._graph.add_edge(rank-3, rank-2, (1, -2)) + self._graph.add_edge(rank - 3, rank - 2, (1, -2)) else: _mutation_type_error(data) @@ -1440,13 +1424,13 @@ def __init__(self, letter, rank, twist=None): elif letter == 'CE': if rank > 4 and twist is None: self._rank = rank - for i in range(rank-3): - self._graph.add_edge(i, i+1) - self._graph.add_edge(2, rank-1) + for i in range(rank - 3): + self._graph.add_edge(i, i + 1) + self._graph.add_edge(2, rank - 1) if rank % 2 == 0: - self._graph.add_edge(rank-3, rank-2, (1, -2)) + self._graph.add_edge(rank - 3, rank - 2, (1, -2)) else: - self._graph.add_edge(rank-3, rank-2, (2, -1)) + self._graph.add_edge(rank - 3, rank - 2, (2, -1)) else: _mutation_type_error(data) @@ -1456,10 +1440,10 @@ def __init__(self, letter, rank, twist=None): self._rank = rank self._info['simply_laced'] = True self._info['skew_symmetric'] = True - for i in range(rank-3): - self._graph.add_edge(i, i+1) - self._graph.add_edge(2, rank-2) - self._graph.add_edge(rank-4, rank-1) + for i in range(rank - 3): + self._graph.add_edge(i, i + 1) + self._graph.add_edge(2, rank - 2) + self._graph.add_edge(rank - 4, rank - 1) else: _mutation_type_error(data) @@ -1474,43 +1458,32 @@ def __init__(self, letter, rank, twist=None): self._rank = rank + 1 self._info['mutation_finite'] = True self._info['affine'] = True - self._graph.add_edges([(0, 1, None), (1, 2, None), - (2, 3, (1, -2)), (3, 4, None)]) + self._graph.add_edges([(0, 1, None), (1, 2, None), (2, 3, (1, -2)), (3, 4, None)]) elif rank == 4 and twist == -1: self._rank = rank + 1 self._info['mutation_finite'] = True self._info['affine'] = True - self._graph.add_edges([(0, 1, None), (1, 2, None), - (2, 3, (2, -1)), (3, 4, None)]) + self._graph.add_edges([(0, 1, None), (1, 2, None), (2, 3, (2, -1)), (3, 4, None)]) elif rank == 4 and (twist == [1, 2]): self._rank = rank + 2 self._info['mutation_finite'] = True self._info['elliptic'] = True - self._digraph.add_edges([(0, 1, None), (1, 2, None), - (2, 3, (2, -1)), (4, 2, (1, -2)), - (3, 4, 2), (4, 5, None), (5, 3, None)]) + self._digraph.add_edges([(0, 1, None), (1, 2, None), (2, 3, (2, -1)), (4, 2, (1, -2)), (3, 4, 2), (4, 5, None), (5, 3, None)]) elif rank == 4 and (twist == [2, 1]): self._rank = rank + 2 self._info['mutation_finite'] = True self._info['elliptic'] = True - self._digraph.add_edges([(0, 1, None), (1, 2, None), - (2, 3, (1, -2)), (4, 2, (2, -1)), - (3, 4, 2), (4, 5, None), (5, 3, None)]) + self._digraph.add_edges([(0, 1, None), (1, 2, None), (2, 3, (1, -2)), (4, 2, (2, -1)), (3, 4, 2), (4, 5, None), (5, 3, None)]) elif rank == 4 and twist == [2, 2]: self._rank = rank + 2 self._info['mutation_finite'] = True self._info['elliptic'] = True - self._digraph.add_edges([(0, 1, None), (1, 2, None), - (3, 1, None), (2, 3, 2), - (4, 2, (2, -1)), (3, 4, (1, -2)), - (5, 4, None)]) + self._digraph.add_edges([(0, 1, None), (1, 2, None), (3, 1, None), (2, 3, 2), (4, 2, (2, -1)), (3, 4, (1, -2)), (5, 4, None)]) elif rank == 4 and twist == [1, 1]: self._rank = rank + 2 self._info['mutation_finite'] = True self._info['elliptic'] = True - self._digraph.add_edges([(0, 1, None), (1, 2, None), - (3, 1, None), (2, 3, 2), (4, 2, (1, -2)), - (3, 4, (2, -1)), (5, 4, None)]) + self._digraph.add_edges([(0, 1, None), (1, 2, None), (3, 1, None), (2, 3, 2), (4, 2, (1, -2)), (3, 4, (2, -1)), (5, 4, None)]) else: _mutation_type_error(data) @@ -1535,49 +1508,45 @@ def __init__(self, letter, rank, twist=None): self._rank = rank + 2 self._info['mutation_finite'] = True self._info['elliptic'] = True - self._digraph.add_edges([(0, 1, None), (1, 2, (3, -1)), - (3, 1, (1, -3)), (2, 3, 2)]) + self._digraph.add_edges([(0, 1, None), (1, 2, (3, -1)), (3, 1, (1, -3)), (2, 3, 2)]) elif rank == 2 and (twist == [3, 1]): self._rank = rank + 2 self._info['mutation_finite'] = True self._info['elliptic'] = True - self._digraph.add_edges([(0, 1, None), (1, 2, (1, -3)), - (3, 1, (3, -1)), (2, 3, 2)]) + self._digraph.add_edges([(0, 1, None), (1, 2, (1, -3)), (3, 1, (3, -1)), (2, 3, 2)]) elif rank == 2 and twist == [3, 3]: self._rank = rank + 2 self._info['mutation_finite'] = True self._info['elliptic'] = True - self._digraph.add_edges([(1, 0, None), (0, 2, 2), (3, 0, (3, -1)), - (2, 1, None), (2, 3, (1, -3))]) + self._digraph.add_edges([(1, 0, None), (0, 2, 2), (3, 0, (3, -1)), (2, 1, None), (2, 3, (1, -3))]) elif rank == 2 and twist == [1, 1]: self._rank = rank + 2 self._info['mutation_finite'] = True self._info['elliptic'] = True - self._digraph.add_edges([(1, 0, None), (0, 2, 2), (3, 0, (1, -3)), - (2, 1, None), (2, 3, (3, -1))]) + self._digraph.add_edges([(1, 0, None), (0, 2, 2), (3, 0, (1, -3)), (2, 1, None), (2, 3, (3, -1))]) else: _mutation_type_error(data) # type GR (mutation infinite) elif letter == 'GR': if twist is None and isinstance(rank, list) and len(rank) == 2 and all(rank[i] in ZZ and rank[i] > 0 for i in [0, 1]) and rank[1] - 1 > rank[0] > 1: - gr_rank = (rank[0]-1, rank[1]-rank[0]-1) + gr_rank = (rank[0] - 1, rank[1] - rank[0] - 1) self._rank = prod(gr_rank) self._info['simply_laced'] = True self._info['skew_symmetric'] = True a, b = gr_rank for i in range(a): for j in range(b): - if i < a-1: - if (i+j) % 2 == 0: - self._digraph.add_edge(i*b+j, (i+1)*b+j) + if i < a - 1: + if (i + j) % 2 == 0: + self._digraph.add_edge(i * b + j, (i + 1) * b + j) else: - self._digraph.add_edge((i+1)*b+j, i*b+j) - if j < b-1: - if (i+j) % 2 == 0: - self._digraph.add_edge(i*b+j+1, i*b+j) + self._digraph.add_edge((i + 1) * b + j, i * b + j) + if j < b - 1: + if (i + j) % 2 == 0: + self._digraph.add_edge(i * b + j + 1, i * b + j) else: - self._digraph.add_edge(i*b+j, i*b+j+1) + self._digraph.add_edge(i * b + j, i * b + j + 1) else: _mutation_type_error(data) @@ -1604,17 +1573,17 @@ def __init__(self, letter, rank, twist=None): self._info['simply_laced'] = True self._info['skew_symmetric'] = True r, p, q = rank - for i in range(q-1): + for i in range(q - 1): if i == 0: self._graph.add_edge(0, 1) self._graph.add_edge(0, r) - self._graph.add_edge(0, r+p-1) + self._graph.add_edge(0, r + p - 1) else: - if i < r-1: - self._graph.add_edge(i, i+1) - if i < p-1: - self._graph.add_edge(i+r-1, i+r) - self._graph.add_edge(i+r+p-2, i+r+p-1) + if i < r - 1: + self._graph.add_edge(i, i + 1) + if i < p - 1: + self._graph.add_edge(i + r - 1, i + r) + self._graph.add_edge(i + r + p - 2, i + r + p - 1) else: _mutation_type_error(data) @@ -1624,16 +1593,16 @@ def __init__(self, letter, rank, twist=None): if twist is None and rank == 1: self._graph.add_vertex(0) elif twist is None and rank > 1: - self._rank = rank*(rank+1)//2 + self._rank = rank * (rank + 1) // 2 self._info['simply_laced'] = True self._info['skew_symmetric'] = True level = 0 while level < rank: - nr = rank*level-sum(range(level)) - for i in range(nr, nr+rank-level-1): - self._digraph.add_edge(i, i+1) - self._digraph.add_edge(i+rank-level, i) - self._digraph.add_edge(i+1, i+rank-level) + nr = rank * level - sum(range(level)) + for i in range(nr, nr + rank - level - 1): + self._digraph.add_edge(i, i + 1) + self._digraph.add_edge(i + rank - level, i) + self._digraph.add_edge(i + 1, i + rank - level) level += 1 else: _mutation_type_error(data) @@ -1644,9 +1613,7 @@ def __init__(self, letter, rank, twist=None): self._rank = rank self._info['mutation_finite'] = True self._info['skew_symmetric'] = True - self._digraph.add_edges([(0, 1, 2), (1, 2, None), (2, 0, None), - (2, 3, None), (3, 4, 2), (4, 2, None), - (2, 5, None)]) + self._digraph.add_edges([(0, 1, 2), (1, 2, None), (2, 0, None), (2, 3, None), (3, 4, 2), (4, 2, None), (2, 5, None)]) if rank == 7: self._digraph.add_edges([(5, 6, 2), (6, 2, None)]) else: @@ -1661,8 +1628,7 @@ def __init__(self, letter, rank, twist=None): if self._graph.is_bipartite(): self._digraph = _bipartite_graph_to_digraph(self._graph) else: - raise ValueError('The QuiverMutationType does not have ' - 'a Coxeter diagram.') + raise ValueError('The QuiverMutationType does not have ' 'a Coxeter diagram.') # in the other cases, the graph is constructed from the digraph if not self._graph: @@ -1746,28 +1712,22 @@ def class_size(self): # cluster-tilted algebras of type A if self.is_finite(): n = self._rank - a = binomial(2*(n+1), n+1) // (n+2) + a = binomial(2 * (n + 1), n + 1) // (n + 2) if n % 2 == 1: - a += binomial(n+1, (n+1)//2) + a += binomial(n + 1, (n + 1) // 2) if n % 3 == 0: - a += 2 * binomial(2*n//3, n//3) - return a // (n+3) + a += 2 * binomial(2 * n // 3, n // 3) + return a // (n + 3) # the formula is taken from Bastian, Prellberg, Rubey, Stump if self.is_affine(): i, j = self._bi_rank i = ZZ(i) j = ZZ(j) - n = i+j + n = i + j f = euler_phi if i == j: - return (binomial(2 * i, i) + - sum(f(k) * binomial(2 * i // k, i // k)**2 - for k in i.divisors() - if k in j.divisors()) // n) // 4 - return sum(f(k) * binomial(2 * i // k, i // k) * - binomial(2 * j // k, j // k) - for k in i.divisors() - if k in j.divisors()) // (2 * n) + return (binomial(2 * i, i) + sum(f(k) * binomial(2 * i // k, i // k) ** 2 for k in i.divisors() if k in j.divisors()) // n) // 4 + return sum(f(k) * binomial(2 * i // k, i // k) * binomial(2 * j // k, j // k) for k in i.divisors() if k in j.divisors()) // (2 * n) # types B and C (finite and affine) elif self._letter in ['B', 'C']: @@ -1779,8 +1739,7 @@ def class_size(self): elif self._letter in ['BB', 'CC']: # these two formulas are not yet proven - print("Warning: This method uses a formula " - "which has not been proved correct.") + print("Warning: This method uses a formula " "which has not been proved correct.") if self.is_affine(): if self._twist == 1: n = self._rank - 1 @@ -1792,8 +1751,7 @@ def class_size(self): # type BC (affine) elif self._letter == 'BC': # this formula is not yet proven - print("Warning: This method uses a formula " - "which has not been proved correct.") + print("Warning: This method uses a formula " "which has not been proved correct.") if self.is_affine(): if self._twist == 1: n = self._rank - 1 @@ -1802,8 +1760,7 @@ def class_size(self): # types BD and CD (affine) elif self._letter in ['BD', 'CD']: # this formula is not yet proven - print("Warning: This method uses a formula " - "which has not been proved correct.") + print("Warning: This method uses a formula " "which has not been proved correct.") if self.is_affine(): if self._twist == 1: n = self._rank - 2 @@ -1817,15 +1774,13 @@ def class_size(self): return 6 f = euler_phi n = ZZ(self._rank) - return sum(f(n // k) * binomial(2 * k, k) - for k in n.divisors()) // (2 * n) + return sum(f(n // k) * binomial(2 * k, k) for k in n.divisors()) // (2 * n) # this formula is not yet proven if self.is_affine(): n = self._rank - 3 if n == 2: return 9 - print("Warning: This method uses a formula " - "which has not been proved correct.") + print("Warning: This method uses a formula " "which has not been proved correct.") if n % 2: return 2 * binomial(2 * n, n) return 2 * binomial(2 * n, n) + binomial(n, n // 2) @@ -1933,7 +1888,7 @@ def dual(self): return self if self.is_affine(): rank = self._rank - 1 - twist = - self._twist + twist = -self._twist elif self.is_elliptic(): twist = self._twist rank = self._rank - 2 @@ -1981,12 +1936,9 @@ def __init__(self, *args): # _info is initialized self._info = {} self._info['irreducible'] = False - self._info['mutation_finite'] = all(comp.is_mutation_finite() - for comp in data) - self._info['simply_laced'] = all(comp.is_simply_laced() - for comp in data) - self._info['skew_symmetric'] = all(comp.is_skew_symmetric() - for comp in data) + self._info['mutation_finite'] = all(comp.is_mutation_finite() for comp in data) + self._info['simply_laced'] = all(comp.is_simply_laced() for comp in data) + self._info['skew_symmetric'] = all(comp.is_skew_symmetric() for comp in data) self._info['finite'] = all(comp.is_finite() for comp in data) self._info['irreducible_components'] = copy(data) @@ -2003,10 +1955,8 @@ def __init__(self, *args): self._letter += ' x ' self._letter += comp._letter self._rank += comp._rank - self._graph = self._graph.disjoint_union(comp._graph, - labels='integers') - self._digraph = self._digraph.disjoint_union(comp._digraph, - labels='integers') + self._graph = self._graph.disjoint_union(comp._graph, labels='integers') + self._digraph = self._digraph.disjoint_union(comp._digraph, labels='integers') self._graph.name('') self._digraph.name('') @@ -2082,9 +2032,7 @@ def class_size(self): if NotImplemented in sizes: print("Size unknown") return NotImplemented - return prod(binomial(sizes[i] + multiplicities[i] - 1, - multiplicities[i]) - for i in range(len(sizes))) + return prod(binomial(sizes[i] + multiplicities[i] - 1, multiplicities[i]) for i in range(len(sizes))) def dual(self): """ @@ -2120,40 +2068,41 @@ def _construct_classical_mutation_classes(n) -> dict[tuple, list | set]: ('AO', (((0, 1), (4, -1)),))] """ from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver + data: dict[tuple, set | list] = {} # finite A data[('A', n)] = ClusterQuiver(['A', n]).mutation_class(data_type='dig6') # affine A - for j in range(1, n//2+1): - data[('A', (n-j, j), 1)] = ClusterQuiver(['A', [n-j, j], 1]).mutation_class(data_type='dig6') + for j in range(1, n // 2 + 1): + data[('A', (n - j, j), 1)] = ClusterQuiver(['A', [n - j, j], 1]).mutation_class(data_type='dig6') # finite B if n > 1: data[('B', n)] = ClusterQuiver(['B', n]).mutation_class(data_type='dig6') # affine B if n > 2: - data[('BB', n-1, 1)] = ClusterQuiver(['BB', n-1, 1]).mutation_class(data_type='dig6') + data[('BB', n - 1, 1)] = ClusterQuiver(['BB', n - 1, 1]).mutation_class(data_type='dig6') # finite C if n > 2: data[('C', n)] = ClusterQuiver(['C', n]).mutation_class(data_type='dig6') # affine C if n > 1: - data[('BC', n-1, 1)] = ClusterQuiver(['BC', n-1, 1]).mutation_class(data_type='dig6') + data[('BC', n - 1, 1)] = ClusterQuiver(['BC', n - 1, 1]).mutation_class(data_type='dig6') # affine CC if n > 2: - data[('CC', n-1, 1)] = ClusterQuiver(['CC', n-1, 1]).mutation_class(data_type='dig6') + data[('CC', n - 1, 1)] = ClusterQuiver(['CC', n - 1, 1]).mutation_class(data_type='dig6') # affine BD if n > 3: - data[('BD', n-1, 1)] = ClusterQuiver(['BD', n-1, 1]).mutation_class(data_type='dig6') + data[('BD', n - 1, 1)] = ClusterQuiver(['BD', n - 1, 1]).mutation_class(data_type='dig6') # affine CD if n > 3: - data[('CD', n-1, 1)] = ClusterQuiver(['CD', n-1, 1]).mutation_class(data_type='dig6') + data[('CD', n - 1, 1)] = ClusterQuiver(['CD', n - 1, 1]).mutation_class(data_type='dig6') # finite D if n > 3: data[('D', n)] = ClusterQuiver(['D', n]).mutation_class(data_type='dig6') # affine D if n > 4: - data[('D', n-1, 1)] = ClusterQuiver(['D', n-1, 1]).mutation_class(data_type='dig6') + data[('D', n - 1, 1)] = ClusterQuiver(['D', n - 1, 1]).mutation_class(data_type='dig6') return data @@ -2182,6 +2131,7 @@ def _construct_exceptional_mutation_classes(n) -> dict[tuple, list | set]: ('BP_', (((0, 1), (2, -2)), ((1, 2), (1, -3)), ((2, 0), (3, -1))))] """ from sage.combinat.cluster_algebra_quiver.quiver import ClusterQuiver + data: dict[tuple, list | set] = {} # finite E if n in [6, 7, 8]: @@ -2255,8 +2205,7 @@ def _save_data_dig6(n, types='ClassicalExceptional', verbose=False): data = {} possible_types = ['Classical', 'ClassicalExceptional', 'Exceptional'] if types not in possible_types: - raise ValueError('The third input must be either ClassicalExceptional' - ' (default), Classical, or Exceptional.') + raise ValueError('The third input must be either ClassicalExceptional' ' (default), Classical, or Exceptional.') if types in possible_types[:2]: data.update(_construct_classical_mutation_classes(n)) @@ -2264,10 +2213,12 @@ def _save_data_dig6(n, types='ClassicalExceptional', verbose=False): data.update(_construct_exceptional_mutation_classes(n)) from sage.env import DOT_SAGE + types_path = Path(DOT_SAGE) / 'cluster_algebra_quiver' types_path.mkdir(exist_ok=True) types_file = types_path / f'mutation_classes_{n}.dig6' from sage.misc.temporary_file import atomic_write + with atomic_write(types_file, binary=True) as f: pickle.dump(data, f) if verbose: @@ -2324,6 +2275,7 @@ def save_quiver_data(n, up_to=True, types='ClassicalExceptional', verbose=True): sage: save_quiver_data(2,up_to=False, verbose=False) """ from sage.combinat.cluster_algebra_quiver.mutation_type import load_data + if up_to is True: ranks = range(1, n + 1) elif up_to is False: diff --git a/src/sage/combinat/cluster_complex.py b/src/sage/combinat/cluster_complex.py index c99dc0df6f3..920bc6c0b65 100644 --- a/src/sage/combinat/cluster_complex.py +++ b/src/sage/combinat/cluster_complex.py @@ -107,8 +107,7 @@ def product_of_upper_cluster(self): [1, 2] """ W = self.parent().group() - return W.prod(W.reflections()[beta] - for beta in reversed(self.upper_cluster())) + return W.prod(W.reflections()[beta] for beta in reversed(self.upper_cluster())) class ClusterComplex(SubwordComplex): @@ -189,8 +188,7 @@ def __classcall__(cls, W, k=1, coxeter_element=None, algorithm='inductive'): True """ if k not in NN: - raise ValueError("the additional parameter must be a " - "nonnegative integer") + raise ValueError("the additional parameter must be a " "nonnegative integer") if W not in CoxeterGroups: W = CoxeterGroup(W) @@ -204,9 +202,7 @@ def __classcall__(cls, W, k=1, coxeter_element=None, algorithm='inductive'): coxeter_element = coxeter_element.reduced_word() coxeter_element = tuple(coxeter_element) - return super(SubwordComplex, cls).__classcall__(cls, W=W, k=k, - coxeter_element=coxeter_element, - algorithm=algorithm) + return super(SubwordComplex, cls).__classcall__(cls, W=W, k=k, coxeter_element=coxeter_element, algorithm=algorithm) def __init__(self, W, k, coxeter_element, algorithm): """ @@ -272,9 +268,7 @@ def _repr_(self): name = 'Cluster complex' else: name = 'Multi-cluster complex' - name += (' of type %s with %s vertices and %s facets' - % (self.cartan_type(), len(self.vertices()), - len(self._facets))) + name += ' of type %s with %s vertices and %s facets' % (self.cartan_type(), len(self.vertices()), len(self._facets)) return name def k(self): @@ -298,8 +292,8 @@ def minimal_nonfaces(self): [[0, 2], [0, 3], [1, 3], [1, 4], [2, 4]] """ from sage.combinat.combination import Combinations - return [X for X in Combinations(self.vertices(), self.k() + 1) - if not any(set(X).issubset(F) for F in self.facets())] + + return [X for X in Combinations(self.vertices(), self.k() + 1) if not any(set(X).issubset(F) for F in self.facets())] def cyclic_rotation(self): """ @@ -318,8 +312,9 @@ def cyclic_rotation(self): S = W.simple_reflections() S_inv = {S[j]: j for j in W.index_set()} Q = Q + tuple(S_inv[w * S[k] * w] for k in Q) - D = {i: (Q[i + 1:].index(Q[i]) + i + 1) % l for i in range(l)} + D = {i: (Q[i + 1 :].index(Q[i]) + i + 1) % l for i in range(l)} def act(F): return self.parent().element_class(sorted([D[i] for i in F])) + return act diff --git a/src/sage/combinat/colored_permutations.py b/src/sage/combinat/colored_permutations.py index 6a874fca8ef..337435aab79 100644 --- a/src/sage/combinat/colored_permutations.py +++ b/src/sage/combinat/colored_permutations.py @@ -6,6 +6,7 @@ Much of the colored permutations (and element) class can be generalized to `G \wr S_n` """ + import itertools from sage.arith.functions import lcm @@ -42,6 +43,7 @@ class ColoredPermutation(MultiplicativeGroupElement): """ A colored permutation. """ + def __init__(self, parent, colors, perm): """ Initialize ``self``. @@ -92,8 +94,7 @@ def _latex_(self): [3_{1}, 1_{0}, 2_{0}] """ ret = "[" - ret += ", ".join("{}_{{{}}}".format(x, c) - for c, x in zip(self._colors, self._perm)) + ret += ", ".join("{}_{{{}}}".format(x, c) for c, x in zip(self._colors, self._perm)) return ret + "]" def __len__(self): @@ -120,8 +121,7 @@ def _mul_(self, other): sage: s1*s2*s1 == s2*s1*s2 True """ - colors = tuple(c + other._colors[val - 1] # -1 for indexing - for c, val in zip(self._colors, self._perm)) + colors = tuple(c + other._colors[val - 1] for c, val in zip(self._colors, self._perm)) # -1 for indexing p = self._perm._left_to_right_multiply_on_right(other._perm) return self.__class__(self.parent(), colors, p) @@ -139,9 +139,7 @@ def __invert__(self): True """ ip = ~self._perm - return self.__class__(self.parent(), - tuple(-self._colors[i - 1] for i in ip), # -1 for indexing - ip) + return self.__class__(self.parent(), tuple(-self._colors[i - 1] for i in ip), ip) # -1 for indexing def __eq__(self, other): """ @@ -160,9 +158,7 @@ def __eq__(self, other): """ if not isinstance(other, ColoredPermutation): return False - return (self.parent() is other.parent() - and self._colors == other._colors - and self._perm == other._perm) + return self.parent() is other.parent() and self._colors == other._colors and self._perm == other._perm def __ne__(self, other): """ @@ -417,6 +413,7 @@ def length(self): """ return ZZ(len(self.reduced_word())) + # TODO: Parts of this should be put in the category of complex # reflection groups @@ -464,6 +461,7 @@ class ShephardToddFamilyGroup(UniqueRepresentation, Parent): sage: groups.misc.ShephardToddFamily(6, 6, 4) Complex reflection group G(6, 6, 4) """ + @staticmethod def __classcall_private__(cls, m, p, n): r""" @@ -514,11 +512,13 @@ def __init__(self, m, p, n) -> None: if self._p <= self._m <= 2 or (self._n == 2 and self._p == self._m): from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups + category = FiniteCoxeterGroups() if not (self._n == self._m == self._p == 2): # special case of type D_2 category = category.Irreducible() else: from sage.categories.complex_reflection_groups import ComplexReflectionGroups + category = ComplexReflectionGroups().Finite().Irreducible() if self._p in [1, self._m]: category = category.WellGenerated() @@ -647,6 +647,7 @@ def coxeter_matrix(self): [2 2 4 1] """ from sage.combinat.root_system.cartan_type import CartanType + if self._p == 1: if self._m == 1: return CartanType(['A', self._n - 1]).coxeter_matrix() @@ -671,8 +672,7 @@ def one(self): sage: C.one() [[0, 0, 0], [1, 2, 3]] """ - return self.element_class(self, [self._C.zero()] * self._n, - self._P.identity()) + return self.element_class(self, [self._C.zero()] * self._n, self._P.identity()) def random_element(self): r""" @@ -742,10 +742,10 @@ def simple_reflection(self, i): return sn if i == self._n + 1 or self._n == 1: - return sn ** self._p + return sn**self._p snm = self.simple_reflection(self._n - 1) - return sn**(self._m - 1) * snm * sn + return sn ** (self._m - 1) * snm * sn @cached_method def _inverse_simple_reflections(self): @@ -802,6 +802,7 @@ def matrix_group(self): ) """ from sage.groups.matrix_gps.finitely_generated import MatrixGroup + return MatrixGroup([g.to_matrix() for g in self.gens()]) def as_permutation_group(self): @@ -815,6 +816,7 @@ def as_permutation_group(self): Complex reflection group G(4, 1, 3) as a permutation group """ from sage.groups.perm_gps.permgroup_named import ComplexReflectionGroup + return ComplexReflectionGroup(self._m, self._p, self._n) def _element_constructor_(self, x): @@ -883,10 +885,7 @@ def _coerce_map_from_(self, C): if isinstance(C, Permutations) and C.n == self._n: return lambda P, x: P.element_class(P, [P._C.zero()] * P._n, x) if self._m == 2 and self._p == 1 and isinstance(C, SignedPermutations) and C._n == self._n: - return lambda P, x: P.element_class(P, - [P._C.zero() if v == 1 else P._C.one() - for v in x._colors], - x._perm) + return lambda P, x: P.element_class(P, [P._C.zero() if v == 1 else P._C.one() for v in x._colors], x._perm) return super()._coerce_map_from_(C) def __iter__(self): @@ -940,7 +939,7 @@ def cardinality(self): sage: C.cardinality() == 4**3 * factorial(3) True """ - ret = self._m ** self._n * self._P.cardinality() + ret = self._m**self._n * self._P.cardinality() if self._p == 1: return ret return ret // self._p @@ -1055,11 +1054,11 @@ def codegrees(self) -> tuple: """ # Special case for the usual symmetric group if self._m == 1: - return tuple([ZZ(v) for v in reversed(range(self._n-1))]) + return tuple([ZZ(v) for v in reversed(range(self._n - 1))]) if self._p < self._m: return tuple([self._m * i for i in reversed(range(self._n))]) - codegrees = [self._m * i for i in reversed(range(self._n-1))] - codegrees.append((self._n-1)*self._m - self._n) + codegrees = [self._m * i for i in reversed(range(self._n - 1))] + codegrees.append((self._n - 1) * self._m - self._n) return tuple(sorted(codegrees, reverse=True)) def number_of_reflection_hyperplanes(self): @@ -1219,6 +1218,7 @@ class ColoredPermutations(ShephardToddFamilyGroup): - :wikipedia:`Generalized_symmetric_group` - :wikipedia:`Complex_reflection_group` """ + def __init__(self, m, n): r""" Initialize ``self``. @@ -1271,11 +1271,11 @@ def __iter__(self): # Signed permutations -class SignedPermutation(ColoredPermutation, - metaclass=InheritComparisonClasscallMetaclass): +class SignedPermutation(ColoredPermutation, metaclass=InheritComparisonClasscallMetaclass): """ A signed permutation. """ + @staticmethod def __classcall_private__(cls, pi): """ @@ -1332,8 +1332,7 @@ def _mul_(self, other): sage: s3*s4*s3*s4 == s4*s3*s4*s3 True """ - colors = tuple(c * other._colors[val - 1] # -1 for indexing - for c, val in zip(self._colors, self._perm)) + colors = tuple(c * other._colors[val - 1] for c, val in zip(self._colors, self._perm)) # -1 for indexing p = self._perm._left_to_right_multiply_on_right(other._perm) return self.__class__(self.parent(), colors, p) @@ -1352,9 +1351,7 @@ def __invert__(self): True """ ip = ~self._perm - return self.__class__(self.parent(), - tuple(self._colors[i - 1] for i in ip), # -1 for indexing - ip) + return self.__class__(self.parent(), tuple(self._colors[i - 1] for i in ip), ip) # -1 for indexing def __iter__(self): """ @@ -1413,8 +1410,7 @@ def __call__(self, i): return -self._colors[-i - 1] * self._perm[-i - 1] return self._colors[i - 1] * self._perm[i - 1] - raise TypeError("i (= %s) must equal +/- an integer between %s and %s" - % (i, 1, len(self))) + raise TypeError("i (= %s) must equal +/- an integer between %s and %s" % (i, 1, len(self))) def to_matrix(self): """ @@ -1567,7 +1563,7 @@ def cycle_type(self): pos_cycles = [] neg_cycles = [] for C in cycles: - if (not len(C) % 2) and C[0] == -C[len(C)//2]: + if (not len(C) % 2) and C[0] == -C[len(C) // 2]: neg_cycles.append(C) else: pos_cycles.append(C) @@ -1649,6 +1645,7 @@ class SignedPermutations(ColoredPermutations): - :wikipedia:`Hyperoctahedral_group` """ + def __init__(self, n): """ Initialize ``self``. @@ -1682,8 +1679,7 @@ def one(self): sage: S.one() [1, 2, 3, 4] """ - return self.element_class(self, [ZZ.one()] * self._n, - self._P.identity()) + return self.element_class(self, [ZZ.one()] * self._n, self._P.identity()) def random_element(self): """ @@ -1697,10 +1693,7 @@ def random_element(self): sage: s in C True """ - return self.element_class(self, - [choice([ZZ.one(), -ZZ.one()]) - for _ in range(self._n)], - self._P.random_element()) + return self.element_class(self, [choice([ZZ.one(), -ZZ.one()]) for _ in range(self._n)], self._P.random_element()) def simple_reflection(self, i): r""" @@ -1822,10 +1815,7 @@ def _coerce_map_from_(self, C): if isinstance(C, Permutations) and C.n == self._n: return lambda P, x: P.element_class(P, [1] * P._n, x) if isinstance(C, ColoredPermutations) and C._n == self._n and C._m == 2: - return lambda P, x: P.element_class(P, - [1 if v == 0 else -1 - for v in x._colors], - x._perm) + return lambda P, x: P.element_class(P, [1 if v == 0 else -1 for v in x._colors], x._perm) return super()._coerce_map_from_(C) def tabloid_module(self, shape, base_ring): @@ -1990,24 +1980,25 @@ def conjugacy_class_representative(self, nu): cnt = 0 for i in la: - cyc += [tuple(range(cnt+1, cnt+i+1))] + [tuple(range(-cnt-1, -cnt-i-1, -1))] + cyc += [tuple(range(cnt + 1, cnt + i + 1))] + [tuple(range(-cnt - 1, -cnt - i - 1, -1))] cnt += i for i in mu: - cyc += [tuple(range(cnt+1, cnt+i+1)) + tuple(range(-cnt-1, -cnt-i-1, -1))] + cyc += [tuple(range(cnt + 1, cnt + i + 1)) + tuple(range(-cnt - 1, -cnt - i - 1, -1))] cnt += i p = [None] * self._n for c in cyc: - for i in range(len(c)-1): + for i in range(len(c) - 1): if c[i] > 0: - p[c[i]-1] = c[i+1] + p[c[i] - 1] = c[i + 1] if c[-1] > 0: - p[c[-1]-1] = c[0] + p[c[-1] - 1] = c[0] return self(p) Element = SignedPermutation + # TODO: Make this a subgroup # class EvenSignedPermutations(SignedPermutations): # """ @@ -2046,6 +2037,7 @@ class SignedPermutationGroupConjugacyClass(ConjugacyClass): - ``group`` -- the signed permutations of `n` - ``shape`` -- a pair of partitions or an element of ``group`` """ + def __init__(self, group, shape): """ Initialize ``self``. @@ -2183,6 +2175,7 @@ class TabloidModule(Representation_abstract, CombinatorialFreeModule): - [Morris1981]_ """ + @staticmethod def __classcall_private__(cls, G, base_ring, diagram): r""" @@ -2217,6 +2210,7 @@ def __init__(self, G, base_ring, diagram): """ self._diagram = diagram from sage.categories.modules_with_basis import ModulesWithBasis + cat = ModulesWithBasis(base_ring).FiniteDimensional() # Build the tabloids @@ -2224,16 +2218,13 @@ def __init__(self, G, base_ring, diagram): from sage.combinat.set_partition_ordered import OrderedSetPartitions from sage.categories.sets_cat import cartesian_product from itertools import product + la, mu = self._diagram - data = [cartesian_product([OrderedSetPartitions([val * x for x, val in zip(sorted(X), signs)], la), - OrderedSetPartitions(sorted(Y), mu)]) - for (X, Y) in OrderedSetPartitions(G._n, [sum(la), sum(mu)]) - for signs in product([1, -1], repeat=sum(la))] + data = [cartesian_product([OrderedSetPartitions([val * x for x, val in zip(sorted(X), signs)], la), OrderedSetPartitions(sorted(Y), mu)]) for (X, Y) in OrderedSetPartitions(G._n, [sum(la), sum(mu)]) for signs in product([1, -1], repeat=sum(la))] tabloids = DisjointUnionEnumeratedSets(data) tabloids.rename(f"Tabloids of shape {self._diagram}") - CombinatorialFreeModule.__init__(self, base_ring, tabloids, - category=cat, prefix='T', bracket='') + CombinatorialFreeModule.__init__(self, base_ring, tabloids, category=cat, prefix='T', bracket='') Representation_abstract.__init__(self, G, "left") def _repr_(self): @@ -2285,6 +2276,7 @@ def _ascii_art_term(self, TP): """ # This is basically copied from CombinatorialFreeModule._ascii_art_term from sage.typeset.ascii_art import AsciiArt, ascii_art + pref = AsciiArt([self.prefix()]) data = [] for T in TP: @@ -2310,6 +2302,7 @@ def _unicode_art_term(self, T): {3} , {5} {3} , {4} {2} , {5} """ from sage.typeset.unicode_art import unicode_art + r = unicode_art(repr(self._ascii_art_term(T))) r._baseline = r._h - 1 return r @@ -2357,11 +2350,13 @@ def _latex_term(self, TP): """ data = [] import re + for T in TP: if not T: tab = "\\emptyset" else: from sage.combinat.output import tex_from_array + A = list(map(sorted, T)) tab = str(tex_from_array(A)) tab = tab.replace("|", "") @@ -2413,8 +2408,7 @@ def _semigroup_action(self, g, vec, vec_on_left): """ if self._left_repr == vec_on_left: g = ~g - return self.sum_of_terms((self._semigroup_basis_action(g, T), c) - for T, c in vec._monomial_coefficients.items()) + return self.sum_of_terms((self._semigroup_basis_action(g, T), c) for T, c in vec._monomial_coefficients.items()) def specht_module(self): r""" @@ -2498,6 +2492,7 @@ class SpechtModule(Representation_abstract, SubmoduleWithBasis): - [Morris1981]_ """ + def __init__(self, ambient): r""" Initialize ``self``. @@ -2510,8 +2505,7 @@ def __init__(self, ambient): sage: SM = B5.specht_module([[2], [2,1]], QQ) sage: TestSuite(SM).run() """ - Representation_abstract.__init__(self, ambient._semigroup, ambient._side, - algebra=ambient._semigroup_algebra) + Representation_abstract.__init__(self, ambient._semigroup, ambient._side, algebra=ambient._semigroup_algebra) self._diagram = ambient._diagram ambient_basis = ambient.basis() @@ -2527,21 +2521,16 @@ def group_elements(sigma): n = T.size() for sigma in T.column_stabilizer(): sigma = sigma.tuple() - for signs in product(*[[1, -1] if i not in mu_vals else [1] - for i in range(1, n+1)]): + for signs in product(*[[1, -1] if i not in mu_vals else [1] for i in range(1, n + 1)]): yield self._semigroup([s * val for s, val in zip(signs, sigma)]) - return ambient.sum_of_terms((ambient._semigroup_basis_action(elt, tab), - 1 - 2*(elt.length() % 2)) # == (-1)**elt.length() - for elt in group_elements(T)) + return ambient.sum_of_terms((ambient._semigroup_basis_action(elt, tab), 1 - 2 * (elt.length() % 2)) for elt in group_elements(T)) # == (-1)**elt.length() from sage.sets.family import Family - basis = Family({T: elt(T) - for T in self._diagram.standard_tableaux()}) + + basis = Family({T: elt(T) for T in self._diagram.standard_tableaux()}) cat = ambient.category().Subobjects() - SubmoduleWithBasis.__init__(self, basis, support_order, ambient=ambient, - unitriangular=False, category=cat, - prefix='S', bracket='') + SubmoduleWithBasis.__init__(self, basis, support_order, ambient=ambient, unitriangular=False, category=cat, prefix='S', bracket='') def _repr_(self): """ @@ -2626,7 +2615,7 @@ def retract(self): Uinv = U.matrix_from_rows(range(n)).inverse() # This is a slight abuse as the codomain should be a module with a different # S_n action, but we only use it internally, so there isn't any problems - PLinv = (P*L).inverse() + PLinv = (P * L).inverse() def retraction(elt): vec = PLinv * elt.to_vector(order=self._support_order) @@ -2754,6 +2743,7 @@ class MaximalSpechtSubmodule(Representation_abstract, SubmoduleWithBasis): sage: sum(U.semigroup_algebra().basis()) * u # long time 0 """ + def __init__(self, specht_module): r""" Initialize ``self``. @@ -2775,11 +2765,11 @@ def __init__(self, specht_module): sage: U.dimension() 0 """ - Representation_abstract.__init__(self, specht_module._semigroup, specht_module._side, - algebra=specht_module._semigroup_algebra) + Representation_abstract.__init__(self, specht_module._semigroup, specht_module._side, algebra=specht_module._semigroup_algebra) self._diagram = specht_module._diagram from sage.sets.family import Family + p = specht_module.base_ring().characteristic() if p == 0: basis = Family([]) @@ -2797,9 +2787,7 @@ def __init__(self, specht_module): unitriangular = all(b.leading_support() == 1 for b in basis) support_order = list(specht_module.basis().keys()) cat = specht_module.category().Subobjects() - SubmoduleWithBasis.__init__(self, basis, support_order, ambient=specht_module, - unitriangular=unitriangular, category=cat, - prefix='U') + SubmoduleWithBasis.__init__(self, basis, support_order, ambient=specht_module, unitriangular=unitriangular, category=cat, prefix='U') def _repr_(self): r""" @@ -2920,6 +2908,7 @@ class SimpleModule(Representation_abstract, QuotientModuleWithBasis): [0 0 0 0 0 0 1 0] [0 0 0 0 0 0 0 1] """ + def __init__(self, specht_module) -> None: r""" Initialize ``self``. @@ -2934,13 +2923,9 @@ def __init__(self, specht_module) -> None: d = self._diagram = specht_module._diagram if (p == 2 and d[0]) or not all(la.is_regular(p) for la in d): raise ValueError(f"the partition must be {p}-regular") - Representation_abstract.__init__(self, specht_module._semigroup, - specht_module._side, - algebra=specht_module._semigroup_algebra) + Representation_abstract.__init__(self, specht_module._semigroup, specht_module._side, algebra=specht_module._semigroup_algebra) cat = specht_module.category() - QuotientModuleWithBasis.__init__(self, - specht_module.maximal_submodule(), - cat, prefix='D', bracket='') + QuotientModuleWithBasis.__init__(self, specht_module.maximal_submodule(), cat, prefix='D', bracket='') def _repr_(self) -> str: r""" diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index 6ea09ec9850..3d2b29e318d 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -344,6 +344,7 @@ def bell_number(n, algorithm='flint', **options) -> Integer: raise ArithmeticError('Bell numbers not defined for negative indices') if algorithm == 'mpmath': from mpmath import bell, mag, mp + old_prec = mp.dps if 'prec' in options: mp.dps = options['prec'] @@ -361,10 +362,12 @@ def bell_number(n, algorithm='flint', **options) -> Integer: if algorithm == 'flint': import sage.libs.flint.arith_sage + return sage.libs.flint.arith_sage.bell_number(n) if algorithm == 'gap': from sage.libs.gap.libgap import libgap + return libgap.Bell(n).sage() if algorithm == 'dobinski': @@ -380,7 +383,7 @@ def bell_number(n, algorithm='flint', **options) -> Integer: partfact = ZZ.one() v = ZZ.zero() for i in range(si - 1, -1, -1): - v += partfact * (k + i)**n + v += partfact * (k + i) ** n partfact *= k + i fact *= partfact v = (q * v) // fact @@ -389,6 +392,7 @@ def bell_number(n, algorithm='flint', **options) -> Integer: b += v k += si from sage.rings.real_mpfr import RealField + R = RealField(b.exact_log(2) + 1, rnd='RNDD') return ((R(-1).exp() / q) * b).ceil() @@ -526,6 +530,7 @@ def euler_number(n, algorithm='flint') -> Integer: return ZZ(maxima.euler(n)) # type:ignore if algorithm == 'flint': import sage.libs.flint.arith_sage + return sage.libs.flint.arith_sage.euler_number(n) raise ValueError("algorithm must be 'flint' or 'maxima'") @@ -571,8 +576,7 @@ def eulerian_number(n, k, algorithm='recursive') -> Integer: s = (n - k) * eulerian_number(n - 1, k - 1, algorithm=algorithm) s += (k + 1) * eulerian_number(n - 1, k, algorithm=algorithm) return s - return sum((-1)**m * (n + 1).binomial(m) * (k + 1 - m)**n - for m in range(k + 1)) + return sum((-1) ** m * (n + 1).binomial(m) * (k + 1 - m) ** n for m in range(k + 1)) @cached_function(key=lambda n, a: n) @@ -677,6 +681,7 @@ def fibonacci(n, algorithm='pari') -> Integer: return ZZ(pari(n).fibonacci()) if algorithm == 'gap': from sage.libs.gap.libgap import libgap + return libgap.Fibonacci(n).sage() raise ValueError("no algorithm {}".format(algorithm)) @@ -747,6 +752,7 @@ def lucas_number1(n, P, Q): P = QQ(P) Q = QQ(Q) from sage.libs.gap.libgap import libgap + return libgap.Lucas(P, Q, n)[0].sage() @@ -795,6 +801,7 @@ def lucas_number2(n, P, Q): P = QQ(P) Q = QQ(Q) from sage.libs.gap.libgap import libgap + return libgap.Lucas(P, Q, n)[1].sage() @@ -847,9 +854,11 @@ def stirling_number1(n, k, algorithm='gap') -> Integer: return ZZ.zero() if n else ZZ.one() if algorithm == 'gap': from sage.libs.gap.libgap import libgap + return libgap.Stirling1(n, k).sage() if algorithm == 'flint': import sage.libs.flint.arith_sage + return sage.libs.flint.arith_sage.stirling_number_1(n, k) raise ValueError("unknown algorithm: %s" % algorithm) @@ -979,9 +988,11 @@ def stirling_number2(n, k, algorithm=None) -> Integer: return _stirling_number2(n, k) if algorithm == 'gap': from sage.libs.gap.libgap import libgap + return libgap.Stirling2(n, k).sage() if algorithm == 'flint': import sage.libs.flint.arith_sage + return sage.libs.flint.arith_sage.stirling_number_2(n, k) if algorithm == 'maxima': return ZZ(maxima.stirling2(n, k)) # type:ignore @@ -1481,8 +1492,7 @@ def index(self, key): return self._list.index(key) -class CombinatorialElement(CombinatorialObject, Element, - metaclass=InheritComparisonClasscallMetaclass): +class CombinatorialElement(CombinatorialObject, Element, metaclass=InheritComparisonClasscallMetaclass): """ ``CombinatorialElement`` is both a :class:`CombinatorialObject` and an :class:`Element`. So it represents a list which is an @@ -1564,12 +1574,13 @@ def __init__(self, parent, *args, **kwds): if len(args) == 1 and not kwds: L = args[0] elif len(kwds) == 1 and not args: - L, = kwds.values() + (L,) = kwds.values() else: raise TypeError("__init__() takes exactly 2 arguments ({} given)".format(1 + len(args) + len(kwds))) super().__init__(L) super(CombinatorialObject, self).__init__(parent) + ##################################################### # combinatorial sets/lists @@ -1637,6 +1648,7 @@ def tuples(S, k, algorithm='itertools'): """ if algorithm == 'itertools': import itertools + return list(itertools.product(S, repeat=k)) if algorithm == 'native': return _tuples_native(S, k) @@ -1712,10 +1724,11 @@ def number_of_tuples(S, k, algorithm='naive') -> Integer: 1 """ if algorithm == 'naive': - return ZZ(len(set(S)))**k # The set is there to avoid duplicates + return ZZ(len(set(S))) ** k # The set is there to avoid duplicates if algorithm == 'gap': k = ZZ(k) from sage.libs.gap.libgap import libgap + S = libgap.eval(str(S)) return libgap.NrTuples(S, k).sage() raise ValueError('invalid algorithm') @@ -1781,10 +1794,12 @@ def unordered_tuples(S, k, algorithm='itertools'): """ if algorithm == 'itertools': import itertools + return list(itertools.combinations_with_replacement(sorted(set(S)), k)) if algorithm == 'gap': k = ZZ(k) from sage.libs.gap.libgap import libgap + S = libgap.eval(str(S)) return [tuple(x) for x in libgap.UnorderedTuples(S, k).sage()] raise ValueError('invalid algorithm') @@ -1832,6 +1847,7 @@ def number_of_unordered_tuples(S, k, algorithm='naive') -> Integer: if algorithm == 'gap': k = ZZ(k) from sage.libs.gap.libgap import libgap + S = libgap.eval(str(S)) return libgap.NrUnorderedTuples(S, k).sage() raise ValueError('invalid algorithm') @@ -1881,6 +1897,7 @@ def unshuffle_iterator(a, one=1) -> Iterator: (((3, 1), ()), 3/2)] """ from sage.combinat.subset import powerset + n = len(a) for I in powerset(range(n)): sorted_I = tuple(sorted(I)) @@ -1894,9 +1911,7 @@ def unshuffle_iterator(a, one=1) -> Iterator: sign = not sign if len(sorted_I) % 4 > 1: sign = not sign - yield ((tuple([a[i] for i in sorted_I]), - tuple([a[i] for i in sorted_nonI])), - (one if sign else - one)) + yield ((tuple([a[i] for i in sorted_I]), tuple([a[i] for i in sorted_nonI])), (one if sign else -one)) def bell_polynomial(n: Integer, k=None, ordinary=False): @@ -2052,6 +2067,7 @@ def bell_polynomial(n: Integer, k=None, ordinary=False): """ from sage.arith.misc import multinomial from sage.combinat.partition import Partitions + if k is None: partitions = Partitions(n) # We set k = 1 to use the correct ring @@ -2071,7 +2087,7 @@ def bell_polynomial(n: Integer, k=None, ordinary=False): else: factorial_product = 1 for part, count in p.to_exp_dict().items(): - factorial_product *= factorial(count) * factorial(part)**count + factorial_product *= factorial(count) * factorial(part) ** count coefficient = factorial(n) // factorial_product result += coefficient * prod(vars[i - 1] for i in p) return result @@ -2239,14 +2255,13 @@ def bernoulli_polynomial(x, n: Integer): raise ValueError("the second argument must be a nonnegative integer") if n == 0: - return x**0 # result should be in the parent of x + return x**0 # result should be in the parent of x if n == 1: return x - ZZ.one() / 2 k = n.mod(2) - coeffs = [0] * k + sum(([n.binomial(i) * bernoulli(n - i), 0] - for i in range(k, n + 1, 2)), []) + coeffs = [0] * k + sum(([n.binomial(i) * bernoulli(n - i), 0] for i in range(k, n + 1, 2)), []) coeffs[-3] = -n / 2 if isinstance(x, Polynomial): diff --git a/src/sage/combinat/combination.py b/src/sage/combinat/combination.py index 503881fe17d..a8fa3c41927 100644 --- a/src/sage/combinat/combination.py +++ b/src/sage/combinat/combination.py @@ -9,6 +9,7 @@ - Antoine Genitrini (2020) : new implementation of the lexicographic unranking of combinations """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # @@ -291,8 +292,7 @@ def cardinality(self) -> Integer: sage: Combinations(['a','a','b']).cardinality() # needs sage.libs.gap 6 """ - return ZZ.sum(Combinations_msetk(self.mset, k).cardinality() - for k in range(len(self.mset) + 1)) + return ZZ.sum(Combinations_msetk(self.mset, k).cardinality() for k in range(len(self.mset) + 1)) class Combinations_set(Combinations_mset): @@ -352,7 +352,7 @@ def cardinality(self): sage: Combinations(range(16000)).cardinality() == 2^16000 True """ - return ZZ(2)**len(self.mset) + return ZZ(2) ** len(self.mset) class Combinations_msetk(Parent): @@ -403,8 +403,7 @@ def __eq__(self, other) -> bool: sage: c == Combinations([1,2,2,3], 2) False """ - return (isinstance(other, Combinations_msetk) and - self.mset == other.mset and self.k == other.k) + return isinstance(other, Combinations_msetk) and self.mset == other.mset and self.k == other.k def __ne__(self, other) -> bool: """ @@ -440,8 +439,7 @@ def __iter__(self): for i in items: counts[indices.index(i)] += 1 for iv in IntegerVectors(self.k, len(indices), outer=counts): - result = sum([[self.mset[indices[i]]] * iv[i] - for i in range(len(indices))], []) + result = sum([[self.mset[indices[i]]] * iv[i] for i in range(len(indices))], []) yield tuple(result) if self.as_tuples else result def cardinality(self) -> Integer: @@ -457,6 +455,7 @@ def cardinality(self) -> Integer: 12 """ from sage.libs.gap.libgap import libgap + items = [self.mset.index(i) for i in self.mset] nc = libgap.function_factory('NrCombinations') return ZZ(nc(items, ZZ(self.k))) @@ -765,6 +764,7 @@ def from_rank(r, n, k): D[k - 1] = n0 + r + k - 1 - B return tuple(D) + ########################################################## # Deprecations diff --git a/src/sage/combinat/combinatorial_map.py b/src/sage/combinat/combinatorial_map.py index 45e748592ac..376bd5eab43 100644 --- a/src/sage/combinat/combinatorial_map.py +++ b/src/sage/combinat/combinatorial_map.py @@ -47,6 +47,7 @@ For real use cases, it is probably best to just edit this source file statically (see below). """ + # **************************************************************************** # Copyright (C) 2011 Christian Stump # @@ -221,6 +222,7 @@ def __init__(self, f, order=None, name=None): '__main__' """ import types + if not isinstance(f, types.FunctionType): raise ValueError("only plain functions are supported") self._f = f @@ -267,6 +269,7 @@ def _sage_src_lines_(self): 2653 """ from sage.misc.sageinspect import sage_getsourcelines + return sage_getsourcelines(self._f) def __get__(self, inst, cls=None) -> Self: diff --git a/src/sage/combinat/composition.py b/src/sage/combinat/composition.py index d0d446ef967..db3cfc5232c 100644 --- a/src/sage/combinat/composition.py +++ b/src/sage/combinat/composition.py @@ -20,6 +20,7 @@ - MuPAD-Combinat developers (algorithms and design inspiration) - Travis Scrimshaw (2013-02-03): Removed ``CombinatorialClass`` """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen # 2009 Nicolas M. Thiery @@ -46,6 +47,7 @@ from sage.misc.persist import register_unpickle_override from sage.misc.lazy_import import lazy_import + lazy_import("sage.combinat.partition", "Partition") @@ -136,6 +138,7 @@ class Composition(CombinatorialElement): sage: C = Composition([3,1,2]) sage: TestSuite(C).run() """ + @staticmethod def __classcall_private__(cls, co=None, descents=None, code=None, from_subset=None): """ @@ -172,8 +175,7 @@ def __classcall_private__(cls, co=None, descents=None, code=None, from_subset=No """ if descents is not None: if isinstance(descents, tuple): - return Compositions().from_descents(descents[0], - nps=descents[1]) + return Compositions().from_descents(descents[0], nps=descents[1]) return Compositions().from_descents(descents) if code is not None: return Compositions().from_code(code) @@ -217,6 +219,7 @@ def _ascii_art_(self): sage: Partitions.options._reset() """ from sage.typeset.ascii_art import ascii_art + return ascii_art(self.to_skew_partition()) def _unicode_art_(self): @@ -240,6 +243,7 @@ def _unicode_art_(self): sage: Partitions.options._reset() """ from sage.typeset.unicode_art import unicode_art + return unicode_art(self.to_skew_partition()) def __setstate__(self, state): @@ -255,7 +259,7 @@ def __setstate__(self, state): sage: loads(dumps( Composition([1,2,1]) )) # indirect doctest [1, 2, 1] """ - if isinstance(state, dict): # for old pickles from Composition_class + if isinstance(state, dict): # for old pickles from Composition_class self._set_parent(Compositions()) self.__dict__ = state else: @@ -310,8 +314,7 @@ def conjugate(self) -> Composition: cocjg += [i + 1 for _ in range(coofcp[ni - 1] - coofcp[ni - 2])] cocjg += [n for j in range(coofcp[0])] - return self.parent()([cocjg[0]] + [cocjg[i] - cocjg[i - 1] + 1 - for i in range(1, len(cocjg))]) + return self.parent()([cocjg[0]] + [cocjg[i] - cocjg[i - 1] + 1 for i in range(1, len(cocjg))]) @combinatorial_map(order=2, name='reversed') def reversed(self) -> Composition: @@ -910,7 +913,7 @@ def fatten(self, grouping) -> Composition: result = [0] * len(grouping) j = 0 for i, gi in enumerate(grouping): - result[i] = sum(self[j:j + gi]) + result[i] = sum(self[j : j + gi]) j += gi return parent(result) @@ -1032,8 +1035,7 @@ def major_index(self) -> int: lv = len(self) if lv == 1: return 0 - return sum([(lv - (i + 1)) * ci - for i, ci in enumerate(self)]) + return sum([(lv - (i + 1)) * ci for i, ci in enumerate(self)]) def to_code(self) -> list: r""" @@ -1147,6 +1149,7 @@ def to_subset(self, final=False): True """ from sage.sets.set import Set + return Set(self.partial_sums(final=final)) def descents(self, final_descent=False) -> list: @@ -1194,8 +1197,7 @@ def peaks(self) -> list: [4, 7] """ descents = set(d - 1 for d in self.to_subset(final=True)) - return [i + 1 for i in range(len(self)) - if i not in descents and i + 1 in descents] + return [i + 1 for i in range(len(self)) if i not in descents and i + 1 in descents] @combinatorial_map(name='to partition') def to_partition(self): @@ -1241,6 +1243,7 @@ def to_skew_partition(self, overlap=1): [2, 2] / [1] """ from sage.combinat.skew_partition import SkewPartition + outer = [] inner = [] sum_outer = -overlap @@ -1255,9 +1258,7 @@ def to_skew_partition(self, overlap=1): else: return SkewPartition([[], []]) - return SkewPartition( - [[x for x in reversed(outer) if x != 0], - [x for x in reversed(inner) if x != 0]]) + return SkewPartition([[x for x in reversed(outer) if x != 0], [x for x in reversed(inner) if x != 0]]) def shuffle_product(self, other, overlap=False): r""" @@ -1336,9 +1337,10 @@ def shuffle_product(self, other, overlap=False): """ if overlap: from sage.combinat.shuffle import ShuffleProduct_overlapping - return ShuffleProduct_overlapping(self, other, - Compositions()) + + return ShuffleProduct_overlapping(self, other, Compositions()) from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 + return ShuffleProduct_w1w2(self, other) def wll_gt(self, co2) -> bool: @@ -1435,8 +1437,10 @@ def specht_module(self, base_ring=None): """ from sage.combinat.specht_module import SpechtModule from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra + if base_ring is None: from sage.rings.rational_field import QQ + base_ring = QQ R = SymmetricGroupAlgebra(base_ring, sum(self)) cells = [(i, j) for i, row in enumerate(self) for j in range(row)] @@ -1458,6 +1462,7 @@ def specht_module_dimension(self, base_ring=None): 5 """ from sage.combinat.specht_module import specht_module_rank + return specht_module_rank(self, base_ring) @@ -1695,6 +1700,7 @@ class Compositions(UniqueRepresentation, Parent): sage: Compositions(5, max_slope=1, min_slope=-2, min_length=2, max_length=4, outer=[2,5,2]).list() [[2, 3], [2, 2, 1], [2, 1, 2], [1, 2, 2]] """ + @staticmethod def __classcall_private__(self, n=None, **kwargs): """ @@ -1718,8 +1724,7 @@ def __classcall_private__(self, n=None, **kwargs): else: # FIXME: should inherit from IntegerListLex, and implement repr, or _name as a lazy attribute txt = "Compositions of the integer %s satisfying constraints %s" - kwargs['name'] = txt % (n, ", ".join(f"{key}={kwargs[key]}" - for key in sorted(kwargs))) + kwargs['name'] = txt % (n, ", ".join(f"{key}={kwargs[key]}" for key in sorted(kwargs))) kwargs['element_class'] = Composition if 'min_part' not in kwargs: kwargs['min_part'] = 1 @@ -1880,8 +1885,7 @@ def from_subset(self, S, n) -> Composition: return self.element_class(self, [n]) if n <= d[-1]: - raise ValueError("S (=%s) is not a subset of {1, ..., %s}" - % (d, n - 1)) + raise ValueError("S (=%s) is not a subset of {1, ..., %s}" % (d, n - 1)) else: d.append(n) @@ -1935,8 +1939,7 @@ def __setstate__(self, data): """ n = data['n'] self.__class__ = IntegerListsLex - constraints = {'min_part': 1, - 'element_class': Composition} + constraints = {'min_part': 1, 'element_class': Composition} constraints.update(data['constraints']) self.__init__(n, **constraints) @@ -2033,6 +2036,7 @@ class Compositions_n(Compositions): """ Class of compositions of a fixed `n`. """ + @staticmethod def __classcall_private__(cls, n): """ @@ -2100,7 +2104,7 @@ def cardinality(self) -> Integer: 1 """ if self.n >= 1: - return ZZ(2)**(self.n - 1) + return ZZ(2) ** (self.n - 1) if self.n == 0: return ZZ.one() return ZZ.zero() diff --git a/src/sage/combinat/composition_signed.py b/src/sage/combinat/composition_signed.py index 52e50a91b59..301c4e05cc3 100644 --- a/src/sage/combinat/composition_signed.py +++ b/src/sage/combinat/composition_signed.py @@ -1,6 +1,7 @@ r""" Signed compositions """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # @@ -117,8 +118,7 @@ def cardinality(self): sage: SignedCompositions(3).cardinality() 18 """ - return ZZ.sum(binomial(self.n - 1, i - 1) * 2**i - for i in range(1, self.n + 1)) + return ZZ.sum(binomial(self.n - 1, i - 1) * 2**i for i in range(1, self.n + 1)) def __iter__(self): """ @@ -138,4 +138,5 @@ def __iter__(self): from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.combinat.composition_signed', 'SignedCompositions_n', SignedCompositions) diff --git a/src/sage/combinat/composition_tableau.py b/src/sage/combinat/composition_tableau.py index d982ab9db8f..3401ade59e3 100644 --- a/src/sage/combinat/composition_tableau.py +++ b/src/sage/combinat/composition_tableau.py @@ -5,6 +5,7 @@ - Chris Berg, Jeff Ferreira (2012-9): initial version """ + from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.non_negative_integers import NonNegativeIntegers from sage.sets.family import Family @@ -48,6 +49,7 @@ class CompositionTableau(CombinatorialElement, metaclass=ClasscallMetaclass): sage: CompositionTableau([]) [] """ + @staticmethod def __classcall_private__(self, t): r""" @@ -111,11 +113,11 @@ def __init__(self, parent, t): # Verify triple condition l = len(t) m = max((len(r) for r in t), default=0) - TT = [row+[0]*(m-len(row)) for row in t] + TT = [row + [0] * (m - len(row)) for row in t] for i in range(l): - for j in range(i+1, l): + for j in range(i + 1, l): for k in range(1, m): - if TT[j][k] and TT[i][k] <= TT[j][k] <= TT[i][k-1]: + if TT[j][k] and TT[i][k] <= TT[j][k] <= TT[i][k - 1]: raise ValueError("triple condition must be satisfied") CombinatorialElement.__init__(self, parent, t) @@ -132,8 +134,7 @@ def _repr_diagram(self) -> str: 3 2 4 4 """ - return '\n'.join("".join("%3s" % str(x) for x in row) - for row in self) + return '\n'.join("".join("%3s" % str(x) for x in row) for row in self) def __call__(self, *cell): r""" @@ -339,6 +340,7 @@ class CompositionTableaux(UniqueRepresentation, Parent): sage: list(CT) [[]] """ + @staticmethod def __classcall_private__(cls, *args, **kwargs): r""" @@ -418,10 +420,10 @@ def __classcall_private__(cls, *args, **kwargs): raise ValueError("max_entry must be positive") # Dispatch to appropriate class - if (shape is not None): + if shape is not None: return CompositionTableaux_shape(shape, max_entry) - if (size is not None): + if size is not None: return CompositionTableaux_size(size, max_entry) return CompositionTableaux_all(max_entry) @@ -491,21 +493,21 @@ def __contains__(self, T): # leftmost column of T strictly increases from top to bottom first_col = [row[0] for row in T] - if any(first_col[i] >= first_col[i+1] for i in range(len(T)-1)): + if any(first_col[i] >= first_col[i + 1] for i in range(len(T) - 1)): return False # rows of T weakly decrease from left to right for row in T: - if any(row[i] < row[i+1] for i in range(len(row)-1)): + if any(row[i] < row[i + 1] for i in range(len(row) - 1)): return False # for 1 <= i < j <= len(comp), for 2 <= k <= m, # T[j,k] \neq 0 and T[j,k] >= T[i,k] ==> T[j,k] > T[i,k-1] l = len(T) m = max((len(r) for r in T), default=0) - TT = [row+[0]*(m-len(row)) for row in T] + TT = [row + [0] * (m - len(row)) for row in T] for i in range(l): - for j in range(i+1, l): + for j in range(i + 1, l): for k in range(1, m): - if TT[j][k] != 0 and TT[j][k] >= TT[i][k] and TT[j][k] <= TT[i][k-1]: + if TT[j][k] != 0 and TT[j][k] >= TT[i][k] and TT[j][k] <= TT[i][k - 1]: return False return True @@ -526,9 +528,7 @@ def __init__(self, max_entry=None): """ self.max_entry = max_entry CT_n = lambda n: CompositionTableaux_size(n, max_entry) - DisjointUnionEnumeratedSets.__init__(self, - Family(NonNegativeIntegers(), CT_n), - facade=True, keepkey=False) + DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), CT_n), facade=True, keepkey=False) def _repr_(self): r""" @@ -580,8 +580,7 @@ def __init__(self, n, max_entry=None): """ if max_entry is None: max_entry = n - super().__init__(max_entry=max_entry, - category=FiniteEnumeratedSets()) + super().__init__(max_entry=max_entry, category=FiniteEnumeratedSets()) self.size = n def __contains__(self, x): @@ -666,6 +665,7 @@ class CompositionTableaux_shape(CompositionTableaux): - ``comp`` -- a composition - ``max_entry`` -- nonnegative integer (default: size of ``comp``) """ + def __init__(self, comp, max_entry=None): """ Initialize ``self``. @@ -680,8 +680,7 @@ def __init__(self, comp, max_entry=None): """ if max_entry is None: max_entry = sum(comp) - super().__init__(max_entry=max_entry, - category=FiniteEnumeratedSets()) + super().__init__(max_entry=max_entry, category=FiniteEnumeratedSets()) self.shape = comp def __iter__(self): @@ -823,8 +822,7 @@ def _rec(self, obj, state): # We check to make sure that k does not violate the Triple Rule if j != 0 and i != 0 and any(k == obj_copy[m][j] for m in range(i)): continue - if j != 0 and i != 0 and any(obj_copy[m][j] < k <= obj_copy[m][j - 1] - for m in range(i)): + if j != 0 and i != 0 and any(obj_copy[m][j] < k <= obj_copy[m][j - 1] for m in range(i)): continue # Fill in the in the i,j box with k diff --git a/src/sage/combinat/constellation.py b/src/sage/combinat/constellation.py index 90f783a4de2..e372cf2c2ad 100644 --- a/src/sage/combinat/constellation.py +++ b/src/sage/combinat/constellation.py @@ -53,8 +53,7 @@ from sage.structure.parent import Parent from sage.structure.element import Element from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.richcmp import (op_NE, op_EQ, richcmp_not_equal, - rich_to_bool) +from sage.structure.richcmp import op_NE, op_EQ, richcmp_not_equal, rich_to_bool from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ @@ -123,8 +122,7 @@ def Constellations(*data, **options): if len(sym.domain()) != degree: raise ValueError("the size of the domain should be equal to the degree") - return Constellations_ld(Integer(length), Integer(degree), - sym, bool(connected)) + return Constellations_ld(Integer(length), Integer(degree), sym, bool(connected)) raise ValueError("you must either provide a profile or a pair (length, degree)") @@ -175,9 +173,8 @@ def Constellation(g=None, mutable=False, connected=True, check=True): l = len(g) sym, _ = perms_sym_init([x for x in g if x is not None]) d = len(sym.domain()) - return Constellations(l, d, - domain=sym.domain(), - connected=connected)(g, mutable=mutable, check=check) + return Constellations(l, d, domain=sym.domain(), connected=connected)(g, mutable=mutable, check=check) + # classes @@ -299,8 +296,7 @@ def switch(self, i, j0, j1): sage: c._check() """ if not self._mutable: - raise ValueError("this constellation is immutable." - " Take a mutable copy first.") + raise ValueError("this constellation is immutable." " Take a mutable copy first.") S = SymmetricGroup(list(range(self.degree()))) tr = S((j0, j1)) i = int(i) @@ -336,9 +332,7 @@ def euler_characteristic(self): sage: parent(c.euler_characteristic()) Integer Ring """ - return Integer(self.degree() * 2 - - sum(sum(j - 1 for j in self.profile(i)) - for i in range(self.length()))) + return Integer(self.degree() * 2 - sum(sum(j - 1 for j in self.profile(i)) for i in range(self.length()))) def genus(self): r""" @@ -387,7 +381,7 @@ def _check(self): raise ValueError("the product is not identity") if self._connected and not perms_are_connected(self._g): - raise ValueError("not connected") + raise ValueError("not connected") def __copy__(self): r""" @@ -406,9 +400,7 @@ def __copy__(self): sage: c is copy(c) False """ - return self.parent()(list(self._g), - check=False, - mutable=self._mutable) + return self.parent()(list(self._g), check=False, mutable=self._mutable) copy = __copy__ @@ -423,9 +415,7 @@ def mutable_copy(self): sage: d.is_mutable() True """ - return self.parent()(list(self._g), - check=False, - mutable=True) + return self.parent()(list(self._g), check=False, mutable=True) # GENERAL PROPERTIES @@ -566,8 +556,7 @@ def is_isomorphic(self, other, return_map=False): True """ if return_map: - if not (self.degree() == other.degree() and - self.length() == other.length()): + if not (self.degree() == other.degree() and self.length() == other.length()): return False, None sn, sn_map = self.relabel(return_map=True) on, on_map = other.relabel(return_map=True) @@ -575,9 +564,7 @@ def is_isomorphic(self, other, return_map=False): return False, None return True, sn_map * ~on_map - return (self.degree() == other.degree() and - self.length() == other.length() and - self.relabel() == other.relabel()) + return self.degree() == other.degree() and self.length() == other.length() and self.relabel() == other.relabel() def _repr_(self): r""" @@ -589,8 +576,7 @@ def _repr_(self): sage: c._repr_() 'Constellation of length 4 and degree 3\ng0 (0,1)(2)\ng1 (0,2)(1)\ng2 (0)(1,2)\ng3 (0,2)(1)' """ - s = "Constellation of length {} and degree {}".format(self.length(), - self.degree()) + s = "Constellation of length {} and degree {}".format(self.length(), self.degree()) for i in range(self.length()): s += "\ng{} {}".format(i, self._g[i].cycle_string(True)) return s @@ -690,6 +676,7 @@ def g(self, i=None): [(0,1,2)(3,4), (0,3), (0,4,3,2,1)] """ from copy import copy + if i is None: return copy(self._g) gi = self._g[i] @@ -769,9 +756,7 @@ def relabel(self, perm=None, return_map=False): g = [perm_inv * g_k * perm for g_k in self._g] P = self.parent() return P.element_class(P, g, self._connected, self._mutable, False) - return self.parent()(g, - check=False, - mutable=self._mutable) + return self.parent()(g, check=False, mutable=self._mutable) if return_map: try: @@ -786,8 +771,7 @@ def relabel(self, perm=None, return_map=False): # compute canonical labels if not self.is_connected(): - raise ValueError("no canonical labels implemented for" - " non connected constellation") + raise ValueError("no canonical labels implemented for" " non connected constellation") # get the permutations on {0, 1, ..., d-1} # compute the canonical labels @@ -866,7 +850,7 @@ def braid_group_action(self, i): txt = "i should be between 0 and {}" raise ValueError(txt.format(self.length() - 1)) j = i + 1 - if j == self.length(): # wrap around the cylinder + if j == self.length(): # wrap around the cylinder j = 0 h = self.copy() si = self._g[i] @@ -925,6 +909,7 @@ class Constellations_ld(UniqueRepresentation, Parent): sage: Constellations(2,3,connected=False).cardinality() 6 """ + Element = Constellation_class def __init__(self, length, degree, sym=None, connected=True): @@ -941,6 +926,7 @@ def __init__(self, length, degree, sym=None, connected=True): ....: TestSuite(Constellations(l, d)).run() """ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets + Parent.__init__(self, category=FiniteEnumeratedSets()) self._length = length self._degree = degree @@ -970,8 +956,7 @@ def is_empty(self) -> bool: sage: Constellations(2, 1).is_empty() False """ - return self._connected and (not self._degree - or (self._degree > 1 and self._length == 1)) + return self._connected and (not self._degree or (self._degree > 1 and self._length == 1)) def __contains__(self, elt) -> bool: r""" @@ -1010,10 +995,7 @@ def __contains__(self, elt) -> bool: if not isinstance(elt, Constellation_class): return False - return (elt.parent() is self or - (elt.length() == self._length and - elt.degree() == self._degree and - (not self._connected or elt.is_connected()))) + return elt.parent() is self or (elt.length() == self._length and elt.degree() == self._degree and (not self._connected or elt.is_connected())) def _repr_(self): """ @@ -1024,9 +1006,7 @@ def _repr_(self): sage: Constellations(3,3,connected=False)._repr_() 'Constellations of length 3 and degree 3 on {1, 2, 3}' """ - s = "of length {} and degree {} on {}".format(self._length, - self._degree, - self._sym.domain()) + s = "of length {} and degree {} on {}".format(self._length, self._degree, self._sym.domain()) if self._connected: return "Connected constellations " + s return "Constellations " + s @@ -1085,7 +1065,7 @@ def cardinality(self): return ZZ.zero() if not self._connected: - return factorial(self._degree) ** (k-1) + return factorial(self._degree) ** (k - 1) # recurrence from :oeis:`A220754` if not self._degree: @@ -1094,10 +1074,7 @@ def cardinality(self): a = [] for n in range(self._degree): n = ZZ(n) - a.append(factorial(n+1) ** (k-1) - - (factorial(n) - * ZZ.sum(a[i] * factorial(n-i) ** (k-2) // factorial(i) - for i in range(n)))) + a.append(factorial(n + 1) ** (k - 1) - (factorial(n) * ZZ.sum(a[i] * factorial(n - i) ** (k - 2) // factorial(i) for i in range(n)))) return ZZ(a[-1]) def random_element(self, mutable=False): @@ -1120,6 +1097,7 @@ def random_element(self, mutable=False): True """ from sage.categories.sets_cat import EmptySetError + if self.is_empty(): raise EmptySetError @@ -1155,8 +1133,7 @@ def _element_constructor_(self, *data, **options): ... ValueError: not connected """ - if len(data) == 1 and isinstance(data[0], (list, tuple)) and \ - len(data[0]) == self._length: + if len(data) == 1 and isinstance(data[0], (list, tuple)) and len(data[0]) == self._length: g = list(data[0]) else: g = list(data) @@ -1223,6 +1200,7 @@ def _an_element_(self): EmptySetError """ from sage.categories.sets_cat import EmptySetError + if self.is_empty(): raise EmptySetError @@ -1233,7 +1211,7 @@ def _an_element_(self): domain = list(Sd.domain()) if self._connected: d = self._degree - g = [[domain[d - 1]] + domain[:d - 1], domain[1:] + [domain[0]]] + g = [[domain[d - 1]] + domain[: d - 1], domain[1:] + [domain[0]]] g += [domain] * (self._length - 2) else: g = [domain] * self._length @@ -1348,8 +1326,7 @@ def __init__(self, profile, domain=None, connected=True): d = Integer(sum(profile[0])) for p in profile: if sum(p) != d: - raise ValueError("all partition in the passport should " - "have the same sum.") + raise ValueError("all partition in the passport should " "have the same sum.") if domain is None: sym = SymmetricGroup(d) else: @@ -1360,6 +1337,7 @@ def __init__(self, profile, domain=None, connected=True): self._cd = Constellations_ld(l, d, sym, connected) self._profile = profile from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets + Parent.__init__(self, category=FiniteEnumeratedSets()) def _repr_(self): @@ -1369,8 +1347,7 @@ def _repr_(self): sage: Constellations(profile=[[3,2,1],[3,3],[3,3]]) Connected constellations with profile ([3, 2, 1], [3, 3], [3, 3]) on {1, 2, 3, 4, 5, 6} """ - s = "with profile {} on {}".format(self._profile, - self._cd._sym.domain()) + s = "with profile {} on {}".format(self._profile, self._cd._sym.domain()) if self._cd._connected: return "Connected constellations " + s return "Constellations " + s @@ -1479,6 +1456,7 @@ def __iter__(self): if c.profile() == self._profile: yield c + # ************************************************************************* # auxiliary functions # ************************************************************************* @@ -1504,8 +1482,7 @@ def perm_sym_domain(g): return set(g) if isinstance(g, str): # perms given as strings of cycles assert g.startswith('(') and g.endswith(')') - domain = set().union(*[a for cyc in g[1:-1].split(')(') - for a in cyc.split(',')]) + domain = set().union(*[a for cyc in g[1:-1].split(')(') for a in cyc.split(',')]) if all(s.isdigit() for s in domain): return [int(x) for x in domain] return domain @@ -1558,8 +1535,7 @@ def perms_sym_init(g, sym=None): if sym is None: domain = set().union(*[perm_sym_domain(gg) for gg in g]) - if all(isinstance(s, (int, Integer)) and s > 0 - for s in domain): + if all(isinstance(s, (int, Integer)) and s > 0 for s in domain): domain = max(domain) else: domain = sorted(domain) @@ -1693,8 +1669,8 @@ def perms_canonical_labels_from(x, y, j0, verbose=False): else: # found: complete cycle from new guy j0 = y[l][j1] if l < len(waiting) - 1: - waiting[l + 1].extend(waiting[l][:i + 1]) - del waiting[l][:i + 1] + waiting[l + 1].extend(waiting[l][: i + 1]) + del waiting[l][: i + 1] break return mapping diff --git a/src/sage/combinat/core.py b/src/sage/combinat/core.py index 76ffff6627e..91915958d24 100644 --- a/src/sage/combinat/core.py +++ b/src/sage/combinat/core.py @@ -11,6 +11,7 @@ - Anne Schilling and Mike Zabrocki (2011): initial version - Travis Scrimshaw (2012): Added latex output for Core class """ + # **************************************************************************** # Copyright (C) 2011 Anne Schilling # Mike Zabrocki @@ -49,6 +50,7 @@ class Core(CombinatorialElement): ... ValueError: [3, 1] is not a 4-core """ + @staticmethod def __classcall_private__(cls, part, k): r""" @@ -119,8 +121,7 @@ def __eq__(self, other) -> bool: False """ if isinstance(other, Core): - return (self._list == other._list and - self.parent().k == other.parent().k) + return self._list == other._list and self.parent().k == other.parent().k return False def __ne__(self, other) -> bool: @@ -326,11 +327,9 @@ def affine_symmetric_group_simple_action(self, i): True """ mu = self.to_partition() - corners = [p for p in mu.outside_corners() - if mu.content(p[0], p[1]) % self.k() == i] + corners = [p for p in mu.outside_corners() if mu.content(p[0], p[1]) % self.k() == i] if not corners: - corners = [p for p in mu.corners() - if mu.content(p[0], p[1]) % self.k() == i] + corners = [p for p in mu.corners() if mu.content(p[0], p[1]) % self.k() == i] if not corners: return self for p in corners: @@ -413,8 +412,7 @@ def _transposition_to_reduced_word(self, t): if t[0] > t[1]: return self._transposition_to_reduced_word([t[1], t[0]]) resu = [i % k for i in range(t[0], t[1] - (t[1] - t[0]) // k)] - resu += [(t[1] - (t[1] - t[0]) // k - 2 - i) % k - for i in range(t[1] - (t[1] - t[0]) // k - t[0] - 1)] + resu += [(t[1] - (t[1] - t[0]) // k - 2 - i) % k for i in range(t[1] - (t[1] - t[0]) // k - t[0] - 1)] return resu def weak_le(self, other): @@ -567,8 +565,7 @@ def strong_down_list(self): """ if not self: return [] - return [ga for ga in Cores(self.k(), length=self.length() - 1) - if self.contains(ga)] + return [ga for ga in Cores(self.k(), length=self.length() - 1) if self.contains(ga)] def Cores(k, length=None, **kwargs): @@ -654,8 +651,7 @@ def list(self): sage: C.list() [[4, 2], [3, 1, 1], [2, 2, 1, 1]] """ - return [la.to_core(self.k - 1) - for la in Partitions(self.n, max_part=self.k - 1)] + return [la.to_core(self.k - 1) for la in Partitions(self.n, max_part=self.k - 1)] def from_partition(self, part): r""" @@ -719,8 +715,7 @@ def list(self): sage: C.list() [[3, 1], [2, 1, 1]] """ - return [Core(x, self.k) for x in Partitions(self.n) - if x.is_core(self.k)] + return [Core(x, self.k) for x in Partitions(self.n) if x.is_core(self.k)] def from_partition(self, part): r""" diff --git a/src/sage/combinat/crystals/affine.py b/src/sage/combinat/crystals/affine.py index a0a406fe8a6..8689d32b037 100644 --- a/src/sage/combinat/crystals/affine.py +++ b/src/sage/combinat/crystals/affine.py @@ -64,6 +64,7 @@ class AffineCrystalFromClassical(UniqueRepresentation, Parent): sage: [x.s(1) for x in A.list()] [[[2]], [[1]], [[3]]] """ + @staticmethod def __classcall__(cls, cartan_type, *args, **options): """ @@ -116,8 +117,7 @@ def __init__(self, cartan_type, classical_crystal, category=None): self._cartan_type = cartan_type Parent.__init__(self, category=category) self.classical_crystal = classical_crystal - self.module_generators = [self.retract(gen) - for gen in self.classical_crystal.module_generators] + self.module_generators = [self.retract(gen) for gen in self.classical_crystal.module_generators] self.element_class._latex_ = lambda x: x.lift()._latex_() def _repr_(self): @@ -353,7 +353,7 @@ def e(self, i): if i == self.parent()._cartan_type.special_node(): return self.e0() x = self.lift().e(i) - if (x is None): + if x is None: return None return self.parent().retract(x) @@ -376,7 +376,7 @@ def f(self, i): if i == self.parent()._cartan_type.special_node(): return self.f0() x = self.lift().f(i) - if (x is None): + if x is None: return None return self.parent().retract(x) @@ -670,7 +670,7 @@ def e0(self): [[3]] """ x = self.parent().automorphism(self).e(self.parent().dynkin_node) - if (x is None): + if x is None: return None return self.parent().inverse_automorphism(x) @@ -691,7 +691,7 @@ def f0(self): [[1]] """ x = self.parent().automorphism(self).f(self.parent().dynkin_node) - if (x is None): + if x is None: return None return self.parent().inverse_automorphism(x) diff --git a/src/sage/combinat/crystals/affine_factorization.py b/src/sage/combinat/crystals/affine_factorization.py index 65508ac5868..e3bafd8106d 100644 --- a/src/sage/combinat/crystals/affine_factorization.py +++ b/src/sage/combinat/crystals/affine_factorization.py @@ -2,12 +2,12 @@ r""" Affine factorization crystal of type `A` """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2014 Anne Schilling # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.misc.lazy_attribute import lazy_attribute from sage.misc.lazy_import import lazy_import @@ -97,6 +97,7 @@ class AffineFactorizationCrystal(UniqueRepresentation, Parent): ... ValueError: x cannot be in reduced word of s0*s3*s2 """ + @staticmethod def __classcall_private__(cls, w, n, x=None, k=None): r""" @@ -113,14 +114,15 @@ def __classcall_private__(cls, w, n, x=None, k=None): if k is not None: from sage.combinat.core import Core from sage.combinat.partition import Partition - W = WeylGroup(['A',k,1], prefix='s') + + W = WeylGroup(['A', k, 1], prefix='s') if isinstance(w[0], Core): w = [w[0].to_bounded_partition(), w[1].to_bounded_partition()] else: w = [Partition(w[0]), Partition(w[1])] w0 = W.from_reduced_word(w[0].from_kbounded_to_reduced_word(k)) w1 = W.from_reduced_word(w[1].from_kbounded_to_reduced_word(k)) - w = w0*(w1.inverse()) + w = w0 * (w1.inverse()) return super().__classcall__(cls, w, n, x) def __init__(self, w, n, x=None): @@ -151,23 +153,23 @@ def __init__(self, w, n, x=None): """ Parent.__init__(self, category=ClassicalCrystals()) self.n = n - self.k = w.parent().n-1 + self.k = w.parent().n - 1 self.w = w - cartan_type = CartanType(['A',n-1]) + cartan_type = CartanType(['A', n - 1]) self._cartan_type = cartan_type from sage.combinat.sf.sf import SymmetricFunctions from sage.rings.rational_field import QQ + Sym = SymmetricFunctions(QQ) s = Sym.schur() support = s(w.stanley_symmetric_function()).support() - support = [ [0]*(n-len(mu))+[mu[len(mu)-i-1] for i in range(len(mu))] for mu in support] - generators = [tuple(p) for mu in support for p in affine_factorizations(w,n,mu)] - #generators = [tuple(p) for p in affine_factorizations(w, n)] + support = [[0] * (n - len(mu)) + [mu[len(mu) - i - 1] for i in range(len(mu))] for mu in support] + generators = [tuple(p) for mu in support for p in affine_factorizations(w, n, mu)] + # generators = [tuple(p) for p in affine_factorizations(w, n)] self.module_generators = [self(t) for t in generators] if x is None: if generators: - x = min( set(range(self.k+1)).difference(set( - sum([i.reduced_word() for i in generators[0]],[])))) + x = min(set(range(self.k + 1)).difference(set(sum([i.reduced_word() for i in generators[0]], [])))) else: x = 0 if x in set(w.reduced_word()): @@ -186,7 +188,7 @@ def _repr_(self): sage: crystals.AffineFactorization([[3,1],[1]], 4, k=3) Crystal on affine factorizations of type A3 associated to s3*s2*s1 """ - return "Crystal on affine factorizations of type A{} associated to {}".format(self.n-1, self.w) + return "Crystal on affine factorizations of type A{} associated to {}".format(self.n - 1, self.w) # temporary workaround while an_element is overridden by Parent _an_element_ = EnumeratedSets.ParentMethods._an_element_ @@ -222,6 +224,7 @@ def mg_to_shape(mg): while l and l[-1] == 0: l.pop() return l + sh = [mg_to_shape(mg) for mg in self.highest_weight_vectors()] C = CrystalOfTableaux(self.cartan_type(), shapes=sh) phi = FactorizationToTableaux(Hom(self, C, category=self.category())) @@ -253,13 +256,13 @@ def e(self, i): k = self.parent().k n = self.parent().n a = min(b[0]) - left = [j for j in (self.value[n-i-1]).reduced_word() if j != (a+x) % (k+1)] - right = [(j-x) % (k+1) for j in (self.value[n-i]).reduced_word()] - m = max([j for j in range(a) if (j+x) % (k+1) not in left]) - right += [m+1] + left = [j for j in (self.value[n - i - 1]).reduced_word() if j != (a + x) % (k + 1)] + right = [(j - x) % (k + 1) for j in (self.value[n - i]).reduced_word()] + m = max([j for j in range(a) if (j + x) % (k + 1) not in left]) + right += [m + 1] right.sort(reverse=True) - right = [(j+x) % (k+1) for j in right] - t = [self.value[j] for j in range(n-i-1)] + [W.from_reduced_word(left)] + [W.from_reduced_word(right)] + [self.value[j] for j in range(n-i+1,n)] + right = [(j + x) % (k + 1) for j in right] + t = [self.value[j] for j in range(n - i - 1)] + [W.from_reduced_word(left)] + [W.from_reduced_word(right)] + [self.value[j] for j in range(n - i + 1, n)] return self.parent()(tuple(t)) def f(self, i): @@ -287,13 +290,13 @@ def f(self, i): k = self.parent().k n = self.parent().n a = max(b[1]) - right = [j for j in (self.value[n-i]).reduced_word() if j != (a+x) % (k+1)] - left = [(j-x) % (k+1) for j in (self.value[n-i-1]).reduced_word()] - m = min([j for j in range(a+1,k+2) if (j+x) % (k+1) not in right]) - left += [m-1] + right = [j for j in (self.value[n - i]).reduced_word() if j != (a + x) % (k + 1)] + left = [(j - x) % (k + 1) for j in (self.value[n - i - 1]).reduced_word()] + m = min([j for j in range(a + 1, k + 2) if (j + x) % (k + 1) not in right]) + left += [m - 1] left.sort(reverse=True) - left = [(j+x) % (k+1) for j in left] - t = [self.value[j] for j in range(n-i-1)] + [W.from_reduced_word(left)] + [W.from_reduced_word(right)] + [self.value[j] for j in range(n-i+1,n)] + left = [(j + x) % (k + 1) for j in left] + t = [self.value[j] for j in range(n - i - 1)] + [W.from_reduced_word(left)] + [W.from_reduced_word(right)] + [self.value[j] for j in range(n - i + 1, n)] return self.parent()(tuple(t)) def bracketing(self, i): @@ -312,10 +315,10 @@ def bracketing(self, i): n = self.parent().n x = self.parent().x k = self.parent().k - right = (self.value[n-i]).reduced_word() - left = (self.value[n-i-1]).reduced_word() - right_n = [(j-x) % (k+1) for j in right] - left_n = [(j-x) % (k+1) for j in left] + right = (self.value[n - i]).reduced_word() + left = (self.value[n - i - 1]).reduced_word() + right_n = [(j - x) % (k + 1) for j in right] + left_n = [(j - x) % (k + 1) for j in left] left_unbracketed = [] while left_n: m = max(left_n) @@ -436,16 +439,15 @@ def affine_factorizations(w, l, weight=None): if w.is_one(): return [[]] return [] - return [[u] + p for u, v in w.left_pieri_factorizations() - for p in affine_factorizations(v, l - 1)] + return [[u] + p for u, v in w.left_pieri_factorizations() for p in affine_factorizations(v, l - 1)] if l != len(weight): return [] if l == 0: if w.is_one(): return [[]] return [] - return [[u] + p for u, v in w.left_pieri_factorizations(max_length=weight[0]) if u.length() == weight[0] - for p in affine_factorizations(v, l - 1, weight[1:])] + return [[u] + p for u, v in w.left_pieri_factorizations(max_length=weight[0]) if u.length() == weight[0] for p in affine_factorizations(v, l - 1, weight[1:])] + ##################################################################### # Crystal isomorphisms diff --git a/src/sage/combinat/crystals/affinization.py b/src/sage/combinat/crystals/affinization.py index d30c2723df1..7b81d1c56b9 100644 --- a/src/sage/combinat/crystals/affinization.py +++ b/src/sage/combinat/crystals/affinization.py @@ -3,7 +3,7 @@ Affinization crystals """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2015 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) @@ -16,7 +16,7 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#**************************************************************************** +# **************************************************************************** from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation @@ -94,8 +94,7 @@ def __init__(self, B): self._B = B self._cartan_type = B.cartan_type() Parent.__init__(self, category=(RegularCrystals(), InfiniteEnumeratedSets())) - self.module_generators = tuple([self.element_class(self, b, 0) - for b in B.module_generators]) + self.module_generators = tuple([self.element_class(self, b, 0) for b in B.module_generators]) def _repr_(self): """ @@ -159,6 +158,7 @@ def _latex_(self): } (0) """ from sage.misc.latex import latex + return latex(self._b) + "({})".format(self._m) def __hash__(self): @@ -233,7 +233,7 @@ def e(self, i): if bp is None: return None if i == 0: - return self.__class__(self.parent(), bp, self._m+1) + return self.__class__(self.parent(), bp, self._m + 1) return self.__class__(self.parent(), bp, self._m) def f(self, i): @@ -261,7 +261,7 @@ def f(self, i): if bp is None: return None if i == 0: - return self.__class__(self.parent(), bp, self._m-1) + return self.__class__(self.parent(), bp, self._m - 1) return self.__class__(self.parent(), bp, self._m) def epsilon(self, i): @@ -327,4 +327,4 @@ def weight(self): """ WLR = self.parent().weight_lattice_realization() La = WLR.fundamental_weights() - return WLR.sum(c*La[i] for i,c in self._b.weight()) + self._m * WLR.null_root() + return WLR.sum(c * La[i] for i, c in self._b.weight()) + self._m * WLR.null_root() diff --git a/src/sage/combinat/crystals/alcove_path.py b/src/sage/combinat/crystals/alcove_path.py index 47de1d71032..1e7a0c4a6ea 100644 --- a/src/sage/combinat/crystals/alcove_path.py +++ b/src/sage/combinat/crystals/alcove_path.py @@ -224,8 +224,7 @@ class CrystalOfAlcovePaths(UniqueRepresentation, Parent): """ @staticmethod - def __classcall_private__(cls, starting_weight, cartan_type=None, - highest_weight_crystal=None): + def __classcall_private__(cls, starting_weight, cartan_type=None, highest_weight_crystal=None): """ Classcall to mend the input. @@ -270,8 +269,7 @@ def __classcall_private__(cls, starting_weight, cartan_type=None, P = R.weight_space(extended=extended) Lambda = P.basis() offset = R.index_set()[Integer(0)] - starting_weight = P.sum(starting_weight[j - offset] * Lambda[j] - for j in R.index_set()) + starting_weight = P.sum(starting_weight[j - offset] * Lambda[j] for j in R.index_set()) # set defaults if highest_weight_crystal is None: @@ -280,8 +278,7 @@ def __classcall_private__(cls, starting_weight, cartan_type=None, if not starting_weight.is_dominant(): raise ValueError("{0} is not a dominant weight".format(starting_weight)) - return super().__classcall__(cls, starting_weight, - highest_weight_crystal) + return super().__classcall__(cls, starting_weight, highest_weight_crystal) def __init__(self, starting_weight, highest_weight_crystal): r""" @@ -435,8 +432,7 @@ def vertices(self): for x in lst: suc = getattr(x[0], successors)() for j in range(x[1][-1] + 1, len_lambda_chain): - temp = x[0] * prod( - [s[k] for k in lambda_chain[j].root.associated_reflection()]) + temp = x[0] * prod([s[k] for k in lambda_chain[j].root.associated_reflection()]) if temp in suc: lst2.append((temp, x[1] + [j])) l.append((temp, x[1] + [j])) @@ -682,8 +678,7 @@ def weight(self): WLR = self.parent().weight_lattice_realization() if self.cartan_type().is_affine() and self.parent()._highest_weight_crystal: # We assume that WLR is the (extended) weight lattice - wt = WLR._from_dict({i: Integer(c) for i, c in -weight}, - remove_zeros=False) + wt = WLR._from_dict({i: Integer(c) for i, c in -weight}, remove_zeros=False) return wt La = WLR.fundamental_weights() wt = WLR.sum(Integer(c) * La[i] for i, c in -weight) @@ -837,8 +832,7 @@ def _folding_data(self, i): for j in range(len(J)): Beta = Beta.reflection(J[j].root) sign_Beta = self._sign(Beta) - max_height_Beta = weight.scalar( - (sign_Beta * Beta).associated_coroot()) + max_height_Beta = weight.scalar((sign_Beta * Beta).associated_coroot()) # some optimization so we don't initialize too many objects # range(c1,c2) can be replaced by range(max_height_Beta) but it @@ -848,16 +842,13 @@ def _folding_data(self, i): if j == len(J) - 1: c2 = max_height_Beta else: - c2 = min(max_height_Beta, J[j+1]._cmp_v[0]*max_height_Beta + 1) + c2 = min(max_height_Beta, J[j + 1]._cmp_v[0] * max_height_Beta + 1) for k in range(int(c1), int(c2)): x = R(sign_Beta * Beta, k) - if ( - (j < len(J) - 1 and J[j] < x <= J[j + 1]) or - (j == len(J) - 1 and J[j] < x) - ): + if (j < len(J) - 1 and J[j] < x <= J[j + 1]) or (j == len(J) - 1 and J[j] < x): signs[x] = sign_Beta signs['infinity'] = sign_Beta @@ -892,12 +883,12 @@ def e(self, i): positions, gi = self._gi(i) m = max(gi) - m_index = len(gi)-1-list(reversed(gi)).index(m) # last max in gi + m_index = len(gi) - 1 - list(reversed(gi)).index(m) # last max in gi if finite_cartan_type and i == 0: - M = Integer(m)/2 + Integer(1)/2 + M = Integer(m) / 2 + Integer(1) / 2 else: - M = Integer(m)/2 - Integer(1)/2 + M = Integer(m) / 2 - Integer(1) / 2 KR_test = finite_cartan_type and i == 0 and m_index < len(gi) - 1 KR_test = KR_test and M >= 1 @@ -980,13 +971,8 @@ def _gi(self, i): gi = [signs[positions[0]]] for j in range(1, len(positions)): - gi.append( - gi[j-1] + - signs[positions[j-1]] * self._eps(positions[j-1]) + - signs[positions[j]]) - gi.append(gi[-1] + - signs[positions[-1]] * self._eps(positions[-1]) + - signs['infinity']) + gi.append(gi[j - 1] + signs[positions[j - 1]] * self._eps(positions[j - 1]) + signs[positions[j]]) + gi.append(gi[-1] + signs[positions[-1]] * self._eps(positions[-1]) + signs['infinity']) return (positions, gi) @@ -1020,9 +1006,9 @@ def f(self, i): if finite_cartan_type and i == 0: # python doesn't handle fractions natively - M = Integer(m)/2 + Integer(1)/2 + M = Integer(m) / 2 + Integer(1) / 2 else: - M = Integer(m)/2 - Integer(1)/2 + M = Integer(m) / 2 - Integer(1) / 2 # boolean determining when to move a folding in KR case KR_test = finite_cartan_type and i == 0 @@ -1134,6 +1120,7 @@ class InfinityCrystalOfAlcovePaths(UniqueRepresentation, Parent): r""" `\mathcal{B}(\infty)` crystal of alcove paths. """ + @staticmethod def __classcall_private__(cls, cartan_type): """ @@ -1223,16 +1210,13 @@ def e(self, i): # So we do not need to check for the shift being 0. prev = y shift -= 1 - A = CrystalOfAlcovePaths(self.parent()._cartan_type, [shift]*n) + A = CrystalOfAlcovePaths(self.parent()._cartan_type, [shift] * n) try: y = A(tuple([A._R(rt.root, rt.height - s(rt.root)) for rt in y.value])) except ValueError: # Invalid height (and not admissible) break shift += 1 - return type(self)(self.parent(), - tuple([(rt.root, rt.height - shift*s(rt.root)) - for rt in prev.value]), - shift) + return type(self)(self.parent(), tuple([(rt.root, rt.height - shift * s(rt.root)) for rt in prev.value]), shift) def f(self, i): """ @@ -1258,19 +1242,13 @@ def f(self, i): s = lambda rt: int(sum(rt.associated_coroot().coefficients())) y = self.projection().f(i) if y is not None: - return type(self)(self.parent(), - tuple([(rt.root, rt.height - self._shift*s(rt.root)) - for rt in y.value]), - self._shift) + return type(self)(self.parent(), tuple([(rt.root, rt.height - self._shift * s(rt.root)) for rt in y.value]), self._shift) shift = self._shift + 1 n = self.parent()._cartan_type.rank() - A = CrystalOfAlcovePaths(self.parent()._cartan_type, [shift]*n) - y = A(tuple([A._R(rt, h + shift*s(rt)) for rt, h in self.value])).f(i) - return type(self)(self.parent(), - tuple([(rt.root, rt.height - shift*s(rt.root)) - for rt in y.value]), - shift) + A = CrystalOfAlcovePaths(self.parent()._cartan_type, [shift] * n) + y = A(tuple([A._R(rt, h + shift * s(rt)) for rt, h in self.value])).f(i) + return type(self)(self.parent(), tuple([(rt.root, rt.height - shift * s(rt.root)) for rt in y.value]), shift) def epsilon(self, i): r""" @@ -1387,7 +1365,7 @@ def projection(self, k=None): s = lambda rt: int(sum(rt.associated_coroot().coefficients())) n = self.parent()._cartan_type.rank() A = CrystalOfAlcovePaths(self.parent()._cartan_type, [k] * n) - return A(tuple([A._R(rt, h + k*s(rt)) for rt, h in self.value])) + return A(tuple([A._R(rt, h + k * s(rt)) for rt, h in self.value])) class RootsWithHeight(UniqueRepresentation, Parent): @@ -1456,7 +1434,7 @@ def __classcall_private__(cls, starting_weight, cartan_type=None): P = R.weight_space() Lambda = P.basis() offset = R.index_set()[Integer(0)] - starting_weight = P.sum(starting_weight[j-offset]*Lambda[j] for j in R.index_set()) + starting_weight = P.sum(starting_weight[j - offset] * Lambda[j] for j in R.index_set()) return super().__classcall__(cls, starting_weight) @@ -1489,8 +1467,7 @@ def _repr_(self): sage: RootsWithHeight(['A',2],[3,2]) Roots with height of Cartan type ['A', 2] and dominant weight 3*Lambda[1] + 2*Lambda[2] """ - return "Roots with height of Cartan type %s and dominant weight %s" % ( - self._root_system.cartan_type(), self.weight) + return "Roots with height of Cartan type %s and dominant weight %s" % (self._root_system.cartan_type(), self.weight) def _max_height(self, root): r""" @@ -1571,8 +1548,7 @@ def lambda_chain(self): if not self._root_lattice.cartan_type().is_finite(): raise ValueError("Cartan type {0} is not finite".format(self._root_lattice.cartan_type())) - l = (self(i, j) for i in self._root_lattice.positive_roots() - for j in range(self._max_height(i))) + l = (self(i, j) for i in self._root_lattice.positive_roots() for j in range(self._max_height(i))) return sorted(l) @@ -1653,8 +1629,7 @@ def __init__(self, parent, root, height): raise ValueError("%d out of allowed range [%d,%d)" % (height, 0, max_height)) v = [height / max_height] - v.extend(x / max_height - for x in root.associated_coroot().to_vector()) + v.extend(x / max_height for x in root.associated_coroot().to_vector()) # v.insert(0, height/max_height) # the map from (root, height) --> _cmp_v is injective @@ -1768,21 +1743,7 @@ def _test_some_specific_examples(clss=CrystalOfAlcovePaths): C = clss(['G', 2], [0, 1]) G = C.digraph() - GT = DiGraph({ - (): {(0): 2}, - (0): {(0, 8): 1}, - (0, 1): {(0, 1, 7): 2}, - (0, 1, 2): {(0, 1, 2, 9): 1}, - (0, 1, 2, 3): {(0, 1, 2, 3, 4): 2}, - (0, 1, 2, 6): {(0, 1, 2, 3): 1}, - (0, 1, 2, 9): {(0, 1, 2, 6): 1}, - (0, 1, 7): {(0, 1, 2): 2}, - (0, 1, 7, 9): {(0, 1, 2, 9): 2}, - (0, 5): {(0, 1): 1, (0, 5, 7): 2}, - (0, 5, 7): {(0, 5, 7, 9): 1}, - (0, 5, 7, 9): {(0, 1, 7, 9): 1}, - (0, 8): {(0, 5): 1} - }) + GT = DiGraph({(): {(0): 2}, (0): {(0, 8): 1}, (0, 1): {(0, 1, 7): 2}, (0, 1, 2): {(0, 1, 2, 9): 1}, (0, 1, 2, 3): {(0, 1, 2, 3, 4): 2}, (0, 1, 2, 6): {(0, 1, 2, 3): 1}, (0, 1, 2, 9): {(0, 1, 2, 6): 1}, (0, 1, 7): {(0, 1, 2): 2}, (0, 1, 7, 9): {(0, 1, 2, 9): 2}, (0, 5): {(0, 1): 1, (0, 5, 7): 2}, (0, 5, 7): {(0, 5, 7, 9): 1}, (0, 5, 7, 9): {(0, 1, 7, 9): 1}, (0, 8): {(0, 5): 1}}) if not G.is_isomorphic(GT): return False @@ -1793,21 +1754,7 @@ def _test_some_specific_examples(clss=CrystalOfAlcovePaths): # type C, ex. 8.3.5, pg. 189 C = clss(['C', 3], [0, 0, 1]) G = C.digraph() - GT = DiGraph({ - (): {(0): 3}, - (0): {(0, 6): 2}, - (0, 1): {(0, 1, 3): 3, (0, 1, 7): 1}, - (0, 1, 2): {(0, 1, 2, 3): 3}, - (0, 1, 2, 3): {(0, 1, 2, 3, 8): 2}, - (0, 1, 2, 3, 4): {(0, 1, 2, 3, 4, 5): 3}, - (0, 1, 2, 3, 8): {(0, 1, 2, 3, 4): 2}, - (0, 1, 3): {(0, 1, 3, 7): 1}, - (0, 1, 3, 7): {(0, 1, 2, 3): 1, (0, 1, 3, 7, 8): 2}, - (0, 1, 3, 7, 8): {(0, 1, 2, 3, 8): 1}, - (0, 1, 7): {(0, 1, 2): 1, (0, 1, 3, 7): 3}, - (0, 6): {(0, 1): 2, (0, 6, 7): 1}, - (0, 6, 7): {(0, 1, 7): 2} - }) + GT = DiGraph({(): {(0): 3}, (0): {(0, 6): 2}, (0, 1): {(0, 1, 3): 3, (0, 1, 7): 1}, (0, 1, 2): {(0, 1, 2, 3): 3}, (0, 1, 2, 3): {(0, 1, 2, 3, 8): 2}, (0, 1, 2, 3, 4): {(0, 1, 2, 3, 4, 5): 3}, (0, 1, 2, 3, 8): {(0, 1, 2, 3, 4): 2}, (0, 1, 3): {(0, 1, 3, 7): 1}, (0, 1, 3, 7): {(0, 1, 2, 3): 1, (0, 1, 3, 7, 8): 2}, (0, 1, 3, 7, 8): {(0, 1, 2, 3, 8): 1}, (0, 1, 7): {(0, 1, 2): 1, (0, 1, 3, 7): 3}, (0, 6): {(0, 1): 2, (0, 6, 7): 1}, (0, 6, 7): {(0, 1, 7): 2}}) if not G.is_isomorphic(GT): return False @@ -1817,34 +1764,7 @@ def _test_some_specific_examples(clss=CrystalOfAlcovePaths): C = clss(['B', 3], [2, 0, 0]) G = C.digraph() - GT = DiGraph({ - (): {(6): 1}, - (0): {(0, 7): 2}, - (0, 1): {(0, 1, 11): 3}, - (0, 1, 2): {(0, 1, 2, 9): 2}, - (0, 1, 2, 3): {(0, 1, 2, 3, 10): 1}, - (0, 1, 2, 3, 10): {(0, 1, 2, 3, 4): 1}, - (0, 1, 2, 9): {(0, 1, 2, 3): 2, (0, 1, 2, 9, 10): 1}, - (0, 1, 2, 9, 10): {(0, 1, 2, 3, 10): 2}, - (0, 1, 5): {(0, 1, 2): 3, (0, 1, 5, 9): 2}, - (0, 1, 5, 9): {(0, 1, 2, 9): 3, (0, 1, 5, 9, 10): 1}, - (0, 1, 5, 9, 10): {(0, 1, 2, 9, 10): 3}, - (0, 1, 8): {(0, 1, 5): 3}, - (0, 1, 8, 9): {(0, 1, 5, 9): 3, (0, 1, 8, 9, 10): 1}, - (0, 1, 8, 9, 10): {(0, 1, 5, 9, 10): 3}, - (0, 1, 11): {(0, 1, 8): 3}, - (0, 7): {(0, 1): 2, (0, 7, 11): 3}, - (0, 7, 8): {(0, 7, 8, 9): 2}, - (0, 7, 8, 9): {(0, 1, 8, 9): 2}, - (0, 7, 8, 9, 10): {(0, 1, 8, 9, 10): 2}, - (0, 7, 11): {(0, 1, 11): 2, (0, 7, 8): 3}, - (6): {(0): 1, (6, 7): 2}, - (6, 7): {(0, 7): 1, (6, 7, 11): 3}, - (6, 7, 8): {(0, 7, 8): 1, (6, 7, 8, 9): 2}, - (6, 7, 8, 9): {(6, 7, 8, 9, 10): 1}, - (6, 7, 8, 9, 10): {(0, 7, 8, 9, 10): 1}, - (6, 7, 11): {(0, 7, 11): 1, (6, 7, 8): 3} - }) + GT = DiGraph({(): {(6): 1}, (0): {(0, 7): 2}, (0, 1): {(0, 1, 11): 3}, (0, 1, 2): {(0, 1, 2, 9): 2}, (0, 1, 2, 3): {(0, 1, 2, 3, 10): 1}, (0, 1, 2, 3, 10): {(0, 1, 2, 3, 4): 1}, (0, 1, 2, 9): {(0, 1, 2, 3): 2, (0, 1, 2, 9, 10): 1}, (0, 1, 2, 9, 10): {(0, 1, 2, 3, 10): 2}, (0, 1, 5): {(0, 1, 2): 3, (0, 1, 5, 9): 2}, (0, 1, 5, 9): {(0, 1, 2, 9): 3, (0, 1, 5, 9, 10): 1}, (0, 1, 5, 9, 10): {(0, 1, 2, 9, 10): 3}, (0, 1, 8): {(0, 1, 5): 3}, (0, 1, 8, 9): {(0, 1, 5, 9): 3, (0, 1, 8, 9, 10): 1}, (0, 1, 8, 9, 10): {(0, 1, 5, 9, 10): 3}, (0, 1, 11): {(0, 1, 8): 3}, (0, 7): {(0, 1): 2, (0, 7, 11): 3}, (0, 7, 8): {(0, 7, 8, 9): 2}, (0, 7, 8, 9): {(0, 1, 8, 9): 2}, (0, 7, 8, 9, 10): {(0, 1, 8, 9, 10): 2}, (0, 7, 11): {(0, 1, 11): 2, (0, 7, 8): 3}, (6): {(0): 1, (6, 7): 2}, (6, 7): {(0, 7): 1, (6, 7, 11): 3}, (6, 7, 8): {(0, 7, 8): 1, (6, 7, 8, 9): 2}, (6, 7, 8, 9): {(6, 7, 8, 9, 10): 1}, (6, 7, 8, 9, 10): {(0, 7, 8, 9, 10): 1}, (6, 7, 11): {(0, 7, 11): 1, (6, 7, 8): 3}}) if not G.is_isomorphic(GT): return False @@ -1853,28 +1773,7 @@ def _test_some_specific_examples(clss=CrystalOfAlcovePaths): C = clss(['B', 3], [0, 1, 0]) G = C.digraph() - GT = DiGraph({ - (): {(0): 2}, - (0): {(0, 1): 1, (0, 7): 3}, - (0, 1): {(0, 1, 7): 3}, - (0, 1, 2): {(0, 1, 2, 8): 2}, - (0, 1, 2, 3): {(0, 1, 2, 3, 5): 1, (0, 1, 2, 3, 9): 3}, - (0, 1, 2, 3, 4): {(0, 1, 2, 3, 4, 5): 1}, - (0, 1, 2, 3, 4, 5): {(0, 1, 2, 3, 4, 5, 6): 2}, - (0, 1, 2, 3, 5): {(0, 1, 2, 3, 5, 9): 3}, - (0, 1, 2, 3, 5, 9): {(0, 1, 2, 3, 4, 5): 3}, - (0, 1, 2, 3, 9): {(0, 1, 2, 3, 4): 3, (0, 1, 2, 3, 5, 9): 1}, - (0, 1, 2, 5): {(0, 1, 2, 3, 5): 2}, - (0, 1, 2, 8): {(0, 1, 2, 3): 2}, - (0, 1, 2, 8, 9): {(0, 1, 2, 3, 9): 2}, - (0, 1, 7): {(0, 1, 2): 3, (0, 1, 7, 8): 2}, - (0, 1, 7, 8): {(0, 1, 7, 8, 9): 3}, - (0, 1, 7, 8, 9): {(0, 1, 2, 8, 9): 3}, - (0, 2): {(0, 1, 2): 1, (0, 2, 5): 2}, - (0, 2, 5): {(0, 2, 5, 8): 1}, - (0, 2, 5, 8): {(0, 1, 2, 5): 1}, - (0, 7): {(0, 1, 7): 1, (0, 2): 3} - }) + GT = DiGraph({(): {(0): 2}, (0): {(0, 1): 1, (0, 7): 3}, (0, 1): {(0, 1, 7): 3}, (0, 1, 2): {(0, 1, 2, 8): 2}, (0, 1, 2, 3): {(0, 1, 2, 3, 5): 1, (0, 1, 2, 3, 9): 3}, (0, 1, 2, 3, 4): {(0, 1, 2, 3, 4, 5): 1}, (0, 1, 2, 3, 4, 5): {(0, 1, 2, 3, 4, 5, 6): 2}, (0, 1, 2, 3, 5): {(0, 1, 2, 3, 5, 9): 3}, (0, 1, 2, 3, 5, 9): {(0, 1, 2, 3, 4, 5): 3}, (0, 1, 2, 3, 9): {(0, 1, 2, 3, 4): 3, (0, 1, 2, 3, 5, 9): 1}, (0, 1, 2, 5): {(0, 1, 2, 3, 5): 2}, (0, 1, 2, 8): {(0, 1, 2, 3): 2}, (0, 1, 2, 8, 9): {(0, 1, 2, 3, 9): 2}, (0, 1, 7): {(0, 1, 2): 3, (0, 1, 7, 8): 2}, (0, 1, 7, 8): {(0, 1, 7, 8, 9): 3}, (0, 1, 7, 8, 9): {(0, 1, 2, 8, 9): 3}, (0, 2): {(0, 1, 2): 1, (0, 2, 5): 2}, (0, 2, 5): {(0, 2, 5, 8): 1}, (0, 2, 5, 8): {(0, 1, 2, 5): 1}, (0, 7): {(0, 1, 7): 1, (0, 2): 3}}) if not G.is_isomorphic(GT): return False @@ -1949,6 +1848,7 @@ def _test_against_tableaux(R, N, k, clss=CrystalOfAlcovePaths): """ from sage.combinat.partition import Partitions from sage.combinat.crystals.tensor_product import CrystalOfTableaux + shapes = Partitions(k).list() for shape in shapes: print("** Shape ", shape) @@ -1958,8 +1858,7 @@ def _test_against_tableaux(R, N, k, clss=CrystalOfAlcovePaths): # T.digraph().show(edge_labels=True) H = T.digraph() weight = T.module_generators[0].weight() - w = [weight.scalar(RootSystem(R).ambient_space().simple_coroot(i)) - for i in range(1, N + 1)] + w = [weight.scalar(RootSystem(R).ambient_space().simple_coroot(i)) for i in range(1, N + 1)] print(" C weight ", w) C = clss(R, w) @@ -1997,6 +1896,7 @@ def _test_with_lspaths_crystal(cartan_type, weight, depth=10): True """ from sage.combinat.crystals.littelmann_path import CrystalOfLSPaths + G1 = CrystalOfAlcovePaths(cartan_type, weight).digraph(depth=depth) C = CrystalOfLSPaths(cartan_type, weight) G2 = C.digraph(subset=C.subcrystal(max_depth=depth, direction='lower')) diff --git a/src/sage/combinat/crystals/all.py b/src/sage/combinat/crystals/all.py index be8576c0e02..f56f00f8449 100644 --- a/src/sage/combinat/crystals/all.py +++ b/src/sage/combinat/crystals/all.py @@ -21,8 +21,10 @@ -- The categories for crystals - :ref:`sage.combinat.root_system.all` """ + # install the docstring of this module to the containing package from sage.misc.namespace_package import install_doc + install_doc(__package__, __doc__) from sage.misc.lazy_import import lazy_import diff --git a/src/sage/combinat/crystals/bkk_crystals.py b/src/sage/combinat/crystals/bkk_crystals.py index 785f3fc7619..ad1f41b7db6 100644 --- a/src/sage/combinat/crystals/bkk_crystals.py +++ b/src/sage/combinat/crystals/bkk_crystals.py @@ -44,6 +44,7 @@ class CrystalOfBKKTableaux(CrystalOfWords): sage: T.cardinality() 20 """ + @staticmethod def __classcall_private__(cls, ct, shape): """ diff --git a/src/sage/combinat/crystals/crystals.py b/src/sage/combinat/crystals/crystals.py index fb8f150e479..c29065113ee 100644 --- a/src/sage/combinat/crystals/crystals.py +++ b/src/sage/combinat/crystals/crystals.py @@ -142,7 +142,7 @@ MuPAD-Combinat (see /lib/COMBINAT/crystals.mu). """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2007 Anne Schilling # Nicolas Thiery # @@ -229,8 +229,8 @@ def _rec(self, x, state): sage: list(CB._rec(C(1), 'n/a')) [(2, 'n/a', True)] """ - #We will signal the initial case by having a object and state - #of None and consider it separately. + # We will signal the initial case by having a object and state + # of None and consider it separately. if x is None and state is None: for gen in self._crystal.highest_weight_vectors(): yield gen, "n/a", True diff --git a/src/sage/combinat/crystals/direct_sum.py b/src/sage/combinat/crystals/direct_sum.py index 5e18215c76a..baa6c49251d 100644 --- a/src/sage/combinat/crystals/direct_sum.py +++ b/src/sage/combinat/crystals/direct_sum.py @@ -83,6 +83,7 @@ class DirectSumOfCrystals(DisjointUnionEnumeratedSets): sage: TestSuite(C).run() """ + @staticmethod def __classcall_private__(cls, crystals, facade=True, keepkey=False, category=None): """ @@ -116,8 +117,7 @@ def __classcall_private__(cls, crystals, facade=True, keepkey=False, category=No else: ret.append(x) category = Category.meet([Category.join(c.categories()) for c in ret]) - return super().__classcall__(cls, - Family(ret), facade=facade, keepkey=keepkey, category=category) + return super().__classcall__(cls, Family(ret), facade=facade, keepkey=keepkey, category=category) def __init__(self, crystals, facade, keepkey, category, **options): """ @@ -134,8 +134,7 @@ def __init__(self, crystals, facade, keepkey, category, **options): sage: isinstance(B, DirectSumOfCrystals) True """ - DisjointUnionEnumeratedSets.__init__(self, crystals, keepkey=keepkey, - facade=facade, category=category) + DisjointUnionEnumeratedSets.__init__(self, crystals, keepkey=keepkey, facade=facade, category=category) self.rename("Direct sum of the crystals {}".format(crystals)) self._keepkey = keepkey self.crystals = crystals @@ -145,9 +144,7 @@ def __init__(self, crystals, facade, keepkey, category, **options): assert all(crystal.cartan_type() == crystals[0].cartan_type() for crystal in crystals) self._cartan_type = crystals[0].cartan_type() if keepkey: - self.module_generators = tuple([self((i, b)) - for i, B in enumerate(crystals) - for b in B.module_generators]) + self.module_generators = tuple([self((i, b)) for i, B in enumerate(crystals) for b in B.module_generators]) else: self.module_generators = sum((tuple(B.module_generators) for B in crystals), ()) @@ -174,8 +171,7 @@ def weight_lattice_realization(self): Extended weight space over the Rational Field of the Root system of type ['A', 2, 1] """ cm = get_coercion_model() - return cm.common_parent(*[crystal.weight_lattice_realization() - for crystal in self.crystals]) + return cm.common_parent(*[crystal.weight_lattice_realization() for crystal in self.crystals]) class Element(ElementWrapper): r""" @@ -197,7 +193,7 @@ def e(self, i): vn = v[1].e(i) if vn is None: return None - return self.parent()(tuple([v[0],vn])) + return self.parent()(tuple([v[0], vn])) def f(self, i): r""" @@ -214,7 +210,7 @@ def f(self, i): vn = v[1].f(i) if vn is None: return None - return self.parent()(tuple([v[0],vn])) + return self.parent()(tuple([v[0], vn])) def weight(self): r""" diff --git a/src/sage/combinat/crystals/elementary_crystals.py b/src/sage/combinat/crystals/elementary_crystals.py index 730fe252adc..2d3dab9958f 100644 --- a/src/sage/combinat/crystals/elementary_crystals.py +++ b/src/sage/combinat/crystals/elementary_crystals.py @@ -554,8 +554,7 @@ def _repr_(self): The dual R crystal of weight Lambda[1] and type ['E', 6] """ dual_str = " dual" if self._dual else "" - return "The{} R crystal of weight {} and type {}".format( - dual_str, self._weight, self._cartan_type) + return "The{} R crystal of weight {} and type {}".format(dual_str, self._weight, self._cartan_type) def _element_constructor_(self, weight): r""" diff --git a/src/sage/combinat/crystals/fast_crystals.py b/src/sage/combinat/crystals/fast_crystals.py index 37d7e356381..e29318656b7 100644 --- a/src/sage/combinat/crystals/fast_crystals.py +++ b/src/sage/combinat/crystals/fast_crystals.py @@ -100,6 +100,7 @@ class FastCrystal(UniqueRepresentation, Parent): [1, 1, 0], [2, 1, 0]] """ + @staticmethod def __classcall__(cls, cartan_type, shape, format='string'): """ @@ -116,7 +117,7 @@ def __classcall__(cls, cartan_type, shape, format='string'): shape = tuple(shape) if len(shape) > 2: raise ValueError("The shape must have length <=2") - shape = shape + (0,)*(2-len(shape)) + shape = shape + (0,) * (2 - len(shape)) return super().__classcall__(cls, cartan_type, shape, format) def __init__(self, ct, shape, format): @@ -128,7 +129,7 @@ def __init__(self, ct, shape, format): sage: TestSuite(C).run() """ Parent.__init__(self, category=ClassicalCrystals()) -# super().__init__(category = FiniteEnumeratedSets()) + # super().__init__(category = FiniteEnumeratedSets()) self._cartan_type = ct if ct[1] != 2: raise NotImplementedError @@ -156,27 +157,27 @@ def __init__(self, ct, shape, format): for i in range(self.size): target = list(self.delpat[i]) - target[0] = target[0]-1 + target[0] = target[0] - 1 e1 = None if target not in self.delpat else self.delpat.index(target) - target[0] = target[0]+1+1 + target[0] = target[0] + 1 + 1 f1 = None if target not in self.delpat else self.delpat.index(target) target = list(self.gampat[i]) - target[0] = target[0]-1 + target[0] = target[0] - 1 e2 = None if target not in self.gampat else self.gampat.index(target) - target[0] = target[0]+1+1 + target[0] = target[0] + 1 + 1 f2 = None if target not in self.gampat else self.gampat.index(target) - self._rootoperators.append([e1,f1,e2,f2]) + self._rootoperators.append([e1, f1, e2, f2]) - if int(2*l1) % 2 == 0: + if int(2 * l1) % 2 == 0: l1_str = "%d" % l1 l2_str = "%d" % l2 else: - assert self._cartan_type[0] == 'B' and int(2*l2) % 2 == 1 - l1_str = "%d/2" % int(2*l1) - l2_str = "%d/2" % int(2*l2) - self.rename("The fast crystal for %s2 with shape [%s,%s]" % (ct[0],l1_str,l2_str)) + assert self._cartan_type[0] == 'B' and int(2 * l2) % 2 == 1 + l1_str = "%d/2" % int(2 * l1) + l2_str = "%d/2" % int(2 * l2) + self.rename("The fast crystal for %s2 with shape [%s,%s]" % (ct[0], l1_str, l2_str)) self.module_generators = [self(0)] # self._digraph = ClassicalCrystal.digraph(self) self._digraph = super().digraph() @@ -192,17 +193,17 @@ def _type_a_init(self, l1, l2): sage: C.gampat [[0, 0, 0], [1, 0, 0], [0, 1, 1]] """ - for b in range(l2,-1,-1): - for a in range(l1,l2-1,-1): - for c in range(a,b-1,-1): - a3 = l1-a - a2 = l1+l2-a-b - a1 = a-c - b1 = max(a3,a2-a1) - b2 = a1+a3 - b3 = min(a2-a3,a1) - self.delpat.append([a1,a2,a3]) - self.gampat.append([b1,b2,b3]) + for b in range(l2, -1, -1): + for a in range(l1, l2 - 1, -1): + for c in range(a, b - 1, -1): + a3 = l1 - a + a2 = l1 + l2 - a - b + a1 = a - c + b1 = max(a3, a2 - a1) + b2 = a1 + a3 + b3 = min(a2 - a3, a1) + self.delpat.append([a1, a2, a3]) + self.gampat.append([b1, b2, b3]) def _type_bc_init(self, l1, l2): """ @@ -223,24 +224,24 @@ def _type_bc_init(self, l1, l2): m1, m2 = l1 + l2, l1 - l2 else: m1, m2 = l1, l2 - for b in range(m2,-1,-1): - for a in range(m1,m2-1,-1): - for c in range(b,a+1): - for d in range(c,-1,-1): - a1 = c-d - a2 = m1+m2+c-a-2*b - a3 = m1+m2-a-b - a4 = m1-a - b1 = max(a4,2*a3-a2,a2-2*a1) - b2 = max(a3, a1+a4, a1+2*a3-a2) - b3 = min(a2, 2*a2-2*a3+a4, 2*a1+a4) - b4 = min(a1, a2-a3, a3-a4) + for b in range(m2, -1, -1): + for a in range(m1, m2 - 1, -1): + for c in range(b, a + 1): + for d in range(c, -1, -1): + a1 = c - d + a2 = m1 + m2 + c - a - 2 * b + a3 = m1 + m2 - a - b + a4 = m1 - a + b1 = max(a4, 2 * a3 - a2, a2 - 2 * a1) + b2 = max(a3, a1 + a4, a1 + 2 * a3 - a2) + b3 = min(a2, 2 * a2 - 2 * a3 + a4, 2 * a1 + a4) + b4 = min(a1, a2 - a3, a3 - a4) if self._cartan_type[0] == 'B': - self.delpat.append([a1,a2,a3,a4]) - self.gampat.append([b1,b2,b3,b4]) + self.delpat.append([a1, a2, a3, a4]) + self.gampat.append([b1, b2, b3, b4]) else: - self.gampat.append([a1,a2,a3,a4]) - self.delpat.append([b1,b2,b3,b4]) + self.gampat.append([a1, a2, a3, a4]) + self.delpat.append([b1, b2, b3, b4]) def __call__(self, value): """ @@ -293,9 +294,9 @@ def cmp_elements(self, x, y): 0 """ assert x.parent() == self and y.parent() == self - if self._digraph_closure.has_edge(x,y): + if self._digraph_closure.has_edge(x, y): return -1 - if self._digraph_closure.has_edge(y,x): + if self._digraph_closure.has_edge(y, x): return 1 return 0 @@ -334,10 +335,12 @@ def weight(self): """ delpat = self.parent().delpat[self.value] if self.parent()._cartan_type[0] == 'A': - delpat = delpat + [0,] + delpat = delpat + [ + 0, + ] alpha1, alpha2 = self.parent().weight_lattice_realization().simple_roots() - hwv = sum(self.parent().shape[i]*self.parent().weight_lattice_realization().monomial(i) for i in range(2)) - return hwv - (delpat[0]+delpat[2])*alpha1 - (delpat[1]+delpat[3])*alpha2 + hwv = sum(self.parent().shape[i] * self.parent().weight_lattice_realization().monomial(i) for i in range(2)) + return hwv - (delpat[0] + delpat[2]) * alpha1 - (delpat[1] + delpat[3]) * alpha2 def _repr_(self) -> str: """ diff --git a/src/sage/combinat/crystals/fully_commutative_stable_grothendieck.py b/src/sage/combinat/crystals/fully_commutative_stable_grothendieck.py index 1b7091c5520..9bd8fd2707e 100644 --- a/src/sage/combinat/crystals/fully_commutative_stable_grothendieck.py +++ b/src/sage/combinat/crystals/fully_commutative_stable_grothendieck.py @@ -73,6 +73,7 @@ class DecreasingHeckeFactorization(Element, metaclass=InheritComparisonClasscall sage: h.parent() Decreasing Hecke factorizations with 3 factors associated to [2, 1, 3, 2, 1] with excess 1 """ + @staticmethod def __classcall_private__(self, t, max_value=None, parent=None): """ @@ -112,14 +113,15 @@ def __classcall_private__(self, t, max_value=None, parent=None): letters = [x for factor in t for x in factor] max_value = max(letters) if letters else 1 from sage.monoids.hecke_monoid import HeckeMonoid - S = SymmetricGroup(max_value+1) + + S = SymmetricGroup(max_value + 1) H = HeckeMonoid(S) word = H.from_reduced_word(x for factor in t for x in factor).reduced_word() factors = len(t) excess = sum(len(l) for l in t) - len(word) p = permutation.from_reduced_word(word) - if p.has_pattern([3,2,1]): + if p.has_pattern([3, 2, 1]): word = S.from_reduced_word(word) parent = DecreasingHeckeFactorizations(word, factors, excess) else: @@ -185,7 +187,7 @@ def _repr_(self): sage: h = DecreasingHeckeFactorization(t); h ()(2, 1)(2)()(2) """ - return "".join("("+repr(list(factor))[1:-1]+")" for factor in self.value) + return "".join("(" + repr(list(factor))[1:-1] + ")" for factor in self.value) def __hash__(self): """ @@ -263,7 +265,7 @@ def _latex_(self): s = "" for factor in self.value: if factor: - s += r"\left("+repr(list(factor))[1:-1]+r"\right)" + s += r"\left(" + repr(list(factor))[1:-1] + r"\right)" else: s += r"\left(\;\right)" return s @@ -308,10 +310,10 @@ def to_increasing_hecke_biword(self): sage: h.to_increasing_hecke_biword() [[1, 1, 1, 2, 2, 4], [1, 3, 4, 1, 2, 2]] """ - L = [[],[]] + L = [[], []] for j in range(len(self.value)): - L[1] += list(self.value[-j-1][::-1]) - L[0] += [j+1]*len(self.value[-j-1]) + L[1] += list(self.value[-j - 1][::-1]) + L[0] += [j + 1] * len(self.value[-j - 1]) return L @@ -337,6 +339,7 @@ class DecreasingHeckeFactorizations(UniqueRepresentation, Parent): sage: F.list() [(3, 1)(3, 1)(3, 2, 1), (3, 1)(3, 2, 1)(2, 1), (3, 2, 1)(2, 1)(2, 1)] """ + @staticmethod def __classcall_private__(cls, w, factors, excess): """ @@ -359,6 +362,7 @@ def __classcall_private__(cls, w, factors, excess): True """ from sage.monoids.hecke_monoid import HeckeMonoid + if isinstance(w.parent(), SymmetricGroup): H = HeckeMonoid(w.parent()) w = H.from_reduced_word(w.reduced_word()) @@ -487,6 +491,7 @@ class FullyCommutativeStableGrothendieckCrystal(UniqueRepresentation, Parent): sage: b.f(2) (3, 1)(1)(3, 2) """ + @staticmethod def __classcall_private__(cls, w, factors, excess, shape=False): """ @@ -507,9 +512,11 @@ def __classcall_private__(cls, w, factors, excess, shape=False): True """ from sage.monoids.hecke_monoid import HeckeMonoid + if shape: from sage.combinat.partition import _Partitions from sage.combinat.skew_partition import SkewPartition + cond1 = isinstance(w, (tuple, list)) and len(w) == 2 and w[0] in _Partitions and w[1] in _Partitions cond2 = isinstance(w, SkewPartition) if cond1 or cond2: @@ -520,7 +527,7 @@ def __classcall_private__(cls, w, factors, excess, shape=False): raise ValueError("w needs to be a (skew) partition") word = _to_reduced_word(sh) max_value = max(word) if word else 1 - H = HeckeMonoid(SymmetricGroup(max_value+1)) + H = HeckeMonoid(SymmetricGroup(max_value + 1)) w = H.from_reduced_word(word) else: if isinstance(w.parent(), SymmetricGroup): @@ -569,7 +576,7 @@ def __init__(self, w, factors, excess): # Check if w is fully commutative word = w.reduced_word() p = permutation.from_reduced_word(word) - if p.has_pattern([3,2,1]): + if p.has_pattern([3, 2, 1]): raise ValueError("w should be fully commutative") Parent.__init__(self, category=ClassicalCrystals()) @@ -578,7 +585,7 @@ def __init__(self, w, factors, excess): self.H = w.parent() self.max_value = len(self.H.gens()) self.excess = excess - self._cartan_type = CartanType(['A', self.factors-1]) + self._cartan_type = CartanType(['A', self.factors - 1]) @lazy_attribute def module_generators(self): @@ -613,7 +620,7 @@ def _repr_(self): sage: crystals.FullyCommutativeStableGrothendieck(w, 3, 1) Fully commutative stable Grothendieck crystal of type A_2 associated to [2, 1, 3, 2] with excess 1 """ - return "Fully commutative stable Grothendieck crystal of type A_{} associated to {} with excess {}".format(self.factors-1, list(self.w), self.excess) + return "Fully commutative stable Grothendieck crystal of type A_{} associated to {} with excess {}".format(self.factors - 1, list(self.w), self.excess) class Element(DecreasingHeckeFactorization): def __init__(self, parent, t): @@ -661,21 +668,21 @@ def e(self, i): """ P = self.parent() m = P.factors - L = list(self.value[m-i-1]) - R = list(self.value[m-i]) + L = list(self.value[m - i - 1]) + R = list(self.value[m - i]) b = self.bracketing(i) if not b[0]: return None y = b[0][-1] - if y-1 in L and y-1 in R: + if y - 1 in L and y - 1 in R: # special case: (--x+1--)(--x+1,x--) -->> (--x+1,x--)(--x--) - L.remove(y-1) + L.remove(y - 1) else: L.remove(y) R.append(y) L.sort(reverse=True) R.sort(reverse=True) - s = [self.value[j] for j in range(m-i-1)]+[L]+[R]+[self.value[j] for j in range(m-i+1, m)] + s = [self.value[j] for j in range(m - i - 1)] + [L] + [R] + [self.value[j] for j in range(m - i + 1, m)] return P.element_class(P, s) def f(self, i): @@ -697,21 +704,21 @@ def f(self, i): """ P = self.parent() m = P.factors - L = list(self.value[m-i-1]) - R = list(self.value[m-i]) + L = list(self.value[m - i - 1]) + R = list(self.value[m - i]) b = self.bracketing(i) if not b[1]: return None x = b[1][0] - if x+1 in L and x+1 in R: + if x + 1 in L and x + 1 in R: # special case: (--x+1--)(--x+1,x--) -->> (--x+1,x--)(--x--) - R.remove(x+1) + R.remove(x + 1) else: R.remove(x) L.append(x) L.sort(reverse=True) R.sort(reverse=True) - s = [self.value[j] for j in range(m-i-1)]+[L]+[R]+[self.value[j] for j in range(m-i+1, m)] + s = [self.value[j] for j in range(m - i - 1)] + [L] + [R] + [self.value[j] for j in range(m - i + 1, m)] return P.element_class(P, s) def bracketing(self, i): @@ -731,8 +738,8 @@ def bracketing(self, i): """ P = self.parent() m = P.factors - L = list(self.value[m-i-1]) - R = list(self.value[m-i]) + L = list(self.value[m - i - 1]) + R = list(self.value[m - i]) right_n = list(R) left_n = list(L) left_unbracketed = [] @@ -751,6 +758,7 @@ def bracketing(self, i): # Helper functions # #################### + def _check_decreasing_hecke_factorization(t): """ Check if ``t`` is a suitable data type for a decreasing factorization in a 0-Hecke monoid. @@ -778,10 +786,10 @@ def _check_decreasing_hecke_factorization(t): for factor in t: if not isinstance(factor, (tuple, list)): raise ValueError("each factor in t should be a list or tuple") - if not all(isinstance(x,(int, Integer)) for x in factor): + if not all(isinstance(x, (int, Integer)) for x in factor): raise ValueError("each nonempty factor should contain integers") - for i in range(len(factor)-1): - if factor[i] <= factor[i+1]: + for i in range(len(factor) - 1): + if factor[i] <= factor[i + 1]: raise ValueError("each nonempty factor should be a strictly decreasing sequence") @@ -825,6 +833,7 @@ def _check_containment(t, parent): factors = len(t) max_value = parent.max_value from sage.monoids.hecke_monoid import HeckeMonoid + H = HeckeMonoid(SymmetricGroup(max_value + 1)) w = tuple(H.from_reduced_word(x for factor in t for x in factor).reduced_word()) excess = sum(len(l) for l in t) - len(w) @@ -832,8 +841,7 @@ def _check_containment(t, parent): if factors != parent.factors: raise ValueError("number of factors do not match") if w != parent.w: - raise ValueError("self and parent must be specified based " - "on equivalent words") + raise ValueError("self and parent must be specified based " "on equivalent words") if excess != parent.excess: raise ValueError("number of excess letters do not match") @@ -877,12 +885,12 @@ def _generate_decreasing_hecke_factorizations(w, factors, ex, weight=None, paren """ if parent is None: max_value = max(w) if w else 1 - S = SymmetricGroup(max_value+1) + S = SymmetricGroup(max_value + 1) v = S.from_reduced_word(w) parent = DecreasingHeckeFactorizations(v, factors, ex) - _canonical_word = lambda w, ex: [list(w)[0]]*ex + list(w) - wt = lambda t:[len(factor) for factor in reversed(t)] + _canonical_word = lambda w, ex: [list(w)[0]] * ex + list(w) + wt = lambda t: [len(factor) for factor in reversed(t)] L = _list_equivalent_words(_canonical_word(w, ex)) Factors = [] @@ -907,11 +915,12 @@ def _list_all_decreasing_runs(word, m): [[2, 2, 1, 1], [3, 2, 1, 1], [3, 3, 1, 1], [3, 3, 2, 1], [3, 3, 2, 2]] """ from sage.combinat.integer_vector import IntegerVectors + J = _jumps(word) - jump_vector = [1]+[int(j in J) for j in range(1, len(word))] - I = sorted(IntegerVectors(m-1-len(J), len(word)+1), reverse=True) - P = [[elt[i]+jump_vector[i] for i in range(len(word))] for elt in I] - V = [[m+1-sum(elt[:i+1]) for i in range(len(elt))] for elt in P] + jump_vector = [1] + [int(j in J) for j in range(1, len(word))] + I = sorted(IntegerVectors(m - 1 - len(J), len(word) + 1), reverse=True) + P = [[elt[i] + jump_vector[i] for i in range(len(word))] for elt in I] + V = [[m + 1 - sum(elt[: i + 1]) for i in range(len(elt))] for elt in P] return V @@ -946,7 +955,7 @@ def _to_reduced_word(P): for i in range(m, -1, -1): for j in range(n, -1, -1): if (i, j) in cells: - L += [j-i+m] + L += [j - i + m] return L @@ -995,24 +1004,24 @@ def _lowest_weights(w, factors, ex, parent=None): [(3, 2, 1)(1)(1)()()] """ p = permutation.from_reduced_word(w) - if p.has_pattern([3,2,1]): + if p.has_pattern([3, 2, 1]): raise ValueError("the word w should be fully commutative") if parent is None: k = max(w) - S = SymmetricGroup(k+1) + S = SymmetricGroup(k + 1) word = S.from_reduced_word(w) parent = FullyCommutativeStableGrothendieckCrystal(word, factors, ex) - _canonical_word = lambda w, ex: [list(w)[0]]*ex + list(w) + _canonical_word = lambda w, ex: [list(w)[0]] * ex + list(w) L = _list_equivalent_words(_canonical_word(w, ex)) M = [] for v in L: if _is_valid_column_word(v, factors): J = [0] + _jumps(v) + [len(v)] - t = [v[J[i]:J[i+1]] for i in range(len(J)-1)] - if len(J) < factors+1: - t += [()]*(factors+1-len(J)) + t = [v[J[i] : J[i + 1]] for i in range(len(J) - 1)] + if len(J) < factors + 1: + t += [()] * (factors + 1 - len(J)) M.append(parent.element_class(parent, t)) return sorted(M) @@ -1028,7 +1037,7 @@ def _jumps(w): sage: _jumps(w) [2, 4, 8, 10] """ - return [i+1 for i in range(len(w)-1) if w[i] <= w[i+1]] + return [i + 1 for i in range(len(w) - 1) if w[i] <= w[i + 1]] def _is_valid_column_word(w, m=None): @@ -1059,14 +1068,13 @@ def _is_valid_column_word(w, m=None): True """ J = [0] + _jumps(w) + [len(w)] - L = [w[J[i+1]-1:J[i]:-1] for i in range(len(J)-1)] - if all(len(L[i]) >= len(L[i+1]) for i in range(len(L)-1)): - if m is None or len(_jumps(w)) <= m-1: + L = [w[J[i + 1] - 1 : J[i] : -1] for i in range(len(J) - 1)] + if all(len(L[i]) >= len(L[i + 1]) for i in range(len(L) - 1)): + if m is None or len(_jumps(w)) <= m - 1: # By construction the sequences along rows of L are strictly # decreasing, so it remains to verify that the sequences along # columns of L are weakly increasing - return all(L[i+1][j] >= L[i][j] for i in range(len(L)-1) - for j in range(len(L[i+1]))) + return all(L[i + 1][j] >= L[i][j] for i in range(len(L) - 1) for j in range(len(L[i + 1]))) return False @@ -1110,19 +1118,19 @@ def _applicable_relations(word): along with the type of relation. """ L = [] - for i in range(len(word)-2): - p, q, r = word[i:(i+2)+1] - if abs(p-q) > 1: - L += [[i,"pq=qp"]] - elif abs(p-q) == 1: + for i in range(len(word) - 2): + p, q, r = word[i : (i + 2) + 1] + if abs(p - q) > 1: + L += [[i, "pq=qp"]] + elif abs(p - q) == 1: if p == r: # p != q by the abs test - L += [[i,"pqp=qpq"]] + L += [[i, "pqp=qpq"]] elif r != p: # We must have p == q - L += [[i,"ppq=pqq"]] + L += [[i, "ppq=pqq"]] if q == r and r != p: - L += [[i,"pqq=ppq"]] - if len(word) > 1 and abs(word[-2]-word[-1]) > 1: - L += [[len(word)-2,"pq=qp"]] + L += [[i, "pqq=ppq"]] + if len(word) > 1 and abs(word[-2] - word[-1]) > 1: + L += [[len(word) - 2, "pq=qp"]] return L V = set() @@ -1175,31 +1183,31 @@ def _apply_relations(word, position, move): # Type 1 if move == "pq=qp": p = w[position] - q = w[position+1] + q = w[position + 1] w[position] = q - w[position+1] = p + w[position + 1] = p # Type 2 elif move == "pqp=qpq": p = w[position] - q = w[position+1] + q = w[position + 1] w[position] = q - w[position+1] = p - w[position+2] = q + w[position + 1] = p + w[position + 2] = q # Type 3 elif move == "pqq=ppq": p = w[position] - q = w[position+2] - w[position+1] = p + q = w[position + 2] + w[position + 1] = p # Type 4 elif move == "ppq=pqq": p = w[position] - q = w[position+2] - w[position+1] = q + q = w[position + 2] + w[position + 1] = q # Type 5 elif move == "pp=p": p = w[position] - w = w[:position+1] + w[position+2:] + w = w[: position + 1] + w[position + 2 :] elif move == "p=pp": p = w[position] - w = w[:position+1] + [p] + w[position+1:] + w = w[: position + 1] + [p] + w[position + 1 :] return w diff --git a/src/sage/combinat/crystals/generalized_young_walls.py b/src/sage/combinat/crystals/generalized_young_walls.py index 25d3df26d17..0d0693ddcda 100644 --- a/src/sage/combinat/crystals/generalized_young_walls.py +++ b/src/sage/combinat/crystals/generalized_young_walls.py @@ -137,6 +137,7 @@ def _ascii_art_(self): 1|2|0| """ from sage.typeset.ascii_art import AsciiArt + return AsciiArt(self._repr_diagram().splitlines()) def _unicode_art_(self): @@ -166,15 +167,16 @@ def _unicode_art_(self): └───┴───┴───┘ """ from sage.typeset.unicode_art import UnicodeArt + if not self.data: return UnicodeArt(["0"]) from sage.combinat.output import ascii_art_table import unicodedata + v = unicodedata.lookup('BOX DRAWINGS LIGHT VERTICAL') vl = unicodedata.lookup('BOX DRAWINGS LIGHT VERTICAL AND LEFT') - table = [[None] * (self.cols - len(row)) + list(reversed(row)) - for row in reversed(self)] + table = [[None] * (self.cols - len(row)) + list(reversed(row)) for row in reversed(self)] ret = [] for i, row in enumerate(ascii_art_table(table, use_unicode=True).splitlines()): if row[-1] == " ": @@ -389,12 +391,11 @@ def number_of_parts(self): i = 0 while i < len(new): r = new[i] - if not r or r in new[i + 1:]: + if not r or r in new[i + 1 :]: new.pop(i) elif r[0] == n and not len(r) % (n + 1): for j in range(n + 1): - temp = [k % (n + 1) - for k in range(j + len(r) // (n + 1) - 1, j - 1, -1)] + temp = [k % (n + 1) for k in range(j + len(r) // (n + 1) - 1, j - 1, -1)] if temp not in new: new.insert(i + 1, temp) new.pop(i) @@ -518,8 +519,7 @@ def latex_large(self) -> str: s += "\\emptyset" else: s += "\\begin{tikzpicture}[baseline=5,scale=.45] \n \\foreach \\x [count=\\s from 0] in \n" - s += "{" + ','.join("{" + ','.join(str(i) for i in r) + "}" - for r in self.data) + "} \n" + s += "{" + ','.join("{" + ','.join(str(i) for i in r) + "}" for r in self.data) + "} \n" s += "{\\foreach \\y [count=\\t from 0] in \\x { \\node[font=\\scriptsize] at (-\\t,\\s) {$\\y$}; \n \\draw (-\\t+.5,\\s+.5) to (-\\t-.5,\\s+.5); \n \\draw (-\\t+.5,\\s-.5) to (-\\t-.5,\\s-.5); \n \\draw (-\\t-.5,\\s-.5) to (-\\t-.5,\\s+.5); } \n \\draw[-,thick] (.5,\\s+1) to (.5,-.5) to (-\\s-1,-.5); } \n \\end{tikzpicture} \n" return s @@ -540,8 +540,7 @@ def _latex_(self) -> str: s += "\\emptyset" else: s += "\\begin{tikzpicture}[baseline=5,scale=.25] \\foreach \\x [count=\\s from 0] in \n" - s += "{" + ','.join("{" + ','.join(str(i) for i in r) + "}" - for r in self.data) + "} \n" + s += "{" + ','.join("{" + ','.join(str(i) for i in r) + "}" for r in self.data) + "} \n" s += "{\\foreach \\y [count=\\t from 0] in \\x { \\node[font=\\tiny] at (-\\t,\\s) {$\\y$}; \n \\draw (-\\t+.5,\\s+.5) to (-\\t-.5,\\s+.5); \n \\draw (-\\t+.5,\\s-.5) to (-\\t-.5,\\s-.5); \n \\draw (-\\t-.5,\\s-.5) to (-\\t-.5,\\s+.5); } \n \\draw[-] (.5,\\s+1) to (.5,-.5) to (-\\s-1,-.5); } \n \\end{tikzpicture} \n" return s @@ -656,8 +655,7 @@ def column(self, k): sage: hw.column(1) [] """ - return [row[k - 1] if k - 1 < len(row) else None - for row in self.data] + return [row[k - 1] if k - 1 < len(row) else None for row in self.data] def a(self, i, k): r""" @@ -674,8 +672,7 @@ def a(self, i, k): sage: y.a(3,2) 0 """ - A = [1 for c in range(len(self.column(k))) - if self.column(k)[c] == i] + A = [1 for c in range(len(self.column(k))) if self.column(k)[c] == i] return len(A) def in_highest_weight_crystal(self, La): @@ -721,8 +718,7 @@ def in_highest_weight_crystal(self, La): diff = self.a(j, k) - self.a((j - 1) % (n + 1), k) if diff <= 0: continue - if not any((j + k - p - 1) % (n + 1) == 0 - and diff <= La.scalar(ac[p]) for p in index_set): + if not any((j + k - p - 1) % (n + 1) == 0 and diff <= La.scalar(ac[p]) for p in index_set): return False return True @@ -877,6 +873,7 @@ def _repr_(self): # Highest weight GYW # ######################## + class CrystalOfGeneralizedYoungWallsElement(GeneralizedYoungWall): r""" Element of the highest weight crystal of generalized Young walls. @@ -1009,6 +1006,7 @@ class CrystalOfGeneralizedYoungWalls(InfinityCrystalOfGeneralizedYoungWalls): sage: G = YLa.digraph(subset=S) sage: view(G) # not tested """ + @staticmethod def __classcall_private__(cls, n, La): r""" @@ -1035,10 +1033,8 @@ def __init__(self, n, La): sage: TestSuite(YLa).run(skip=["_test_enumerated_set_contains","_test_stembridge_local_axioms"]) # long time """ - cat = (RegularCrystals(), HighestWeightCrystals(), - InfiniteEnumeratedSets()) - InfinityCrystalOfGeneralizedYoungWalls.__init__(self, n, - category=cat) + cat = (RegularCrystals(), HighestWeightCrystals(), InfiniteEnumeratedSets()) + InfinityCrystalOfGeneralizedYoungWalls.__init__(self, n, category=cat) self.hw = La Element = CrystalOfGeneralizedYoungWallsElement diff --git a/src/sage/combinat/crystals/highest_weight_crystals.py b/src/sage/combinat/crystals/highest_weight_crystals.py index 09a1596756c..9a9ea3d2877 100644 --- a/src/sage/combinat/crystals/highest_weight_crystals.py +++ b/src/sage/combinat/crystals/highest_weight_crystals.py @@ -3,7 +3,7 @@ Highest weight crystals """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2009 Anne Schilling # # Distributed under the terms of the GNU General Public License (GPL) @@ -16,13 +16,12 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#**************************************************************************** +# **************************************************************************** from sage.categories.classical_crystals import ClassicalCrystals from sage.structure.parent import Parent from sage.combinat.crystals.letters import CrystalOfLetters -from sage.combinat.crystals.tensor_product import TensorProductOfCrystals, \ - TensorProductOfRegularCrystalsElement +from sage.combinat.crystals.tensor_product import TensorProductOfCrystals, TensorProductOfRegularCrystalsElement from sage.combinat.crystals.tensor_product import CrystalOfTableaux from sage.combinat.crystals.alcove_path import CrystalOfAlcovePaths @@ -198,7 +197,7 @@ def HighestWeightCrystal(dominant_weight, model=None): if cartan_type.is_finite(): if cartan_type.type() == 'E': model = 'TypeE' - elif cartan_type.type() in ['A','B','C','D','G']: + elif cartan_type.type() in ['A', 'B', 'C', 'D', 'G']: model = 'Tableaux' else: model = 'LSPaths' @@ -237,7 +236,7 @@ def HighestWeightCrystal(dominant_weight, model=None): P = dominant_weight.parent().root_system.weight_space(extended=True) else: P = dominant_weight.parent().root_system.weight_space() - wt = P.sum_of_terms((i, c) for i,c in dominant_weight) + wt = P.sum_of_terms((i, c) for i, c in dominant_weight) return CrystalOfLSPaths(wt) if model == 'AlcovePaths': @@ -250,8 +249,8 @@ def HighestWeightCrystal(dominant_weight, model=None): raise NotImplementedError("only for affine type A") # Make sure it's in the weight lattice P = dominant_weight.parent().root_system.weight_lattice(extended=True) - wt = P.sum_of_terms((i, c) for i,c in dominant_weight) - return CrystalOfGeneralizedYoungWalls(cartan_type.rank()-1, wt) + wt = P.sum_of_terms((i, c) for i, c in dominant_weight) + return CrystalOfGeneralizedYoungWalls(cartan_type.rank() - 1, wt) if model == 'RiggedConfigurations': return CrystalOfRiggedConfigurations(cartan_type, dominant_weight) @@ -302,8 +301,7 @@ def _repr_(self): sage: crystals.HighestWeight(2*La[2]) Finite dimensional highest weight crystal of type ['E', 6] and highest weight 2*Lambda[2] """ - return "Finite dimensional highest weight crystal of type {} and highest weight {}".format( - self._cartan_type, self._highest_weight) + return "Finite dimensional highest weight crystal of type {} and highest weight {}".format(self._cartan_type, self._highest_weight) Element = TensorProductOfRegularCrystalsElement @@ -330,7 +328,7 @@ def module_generator(self): [[(-7, 1), (7,)]] """ dominant_weight = self._highest_weight - tensor = sum(( [self.column_crystal[i]]*dominant_weight.coefficient(i) for i in dominant_weight.support()), []) + tensor = sum(([self.column_crystal[i]] * dominant_weight.coefficient(i) for i in dominant_weight.support()), []) return self._element_constructor_(*[B.module_generators[0] for B in tensor]) @@ -376,13 +374,9 @@ def __init__(self, dominant_weight): sage: T.cardinality() 2430 """ - B1 = CrystalOfLetters(['E',6]) - B6 = CrystalOfLetters(['E',6], dual=True) - self.column_crystal = {1 : B1, 6 : B6, - 4 : TensorProductOfCrystals(B1,B1,B1,generators=[[B1([-3,4]),B1([-1,3]),B1([1])]]), - 3 : TensorProductOfCrystals(B1,B1,generators=[[B1([-1,3]),B1([1])]]), - 5 : TensorProductOfCrystals(B6,B6,generators=[[B6([5,-6]),B6([6])]]), - 2 : TensorProductOfCrystals(B6,B1,generators=[[B6([2,-1]),B1([1])]])} + B1 = CrystalOfLetters(['E', 6]) + B6 = CrystalOfLetters(['E', 6], dual=True) + self.column_crystal = {1: B1, 6: B6, 4: TensorProductOfCrystals(B1, B1, B1, generators=[[B1([-3, 4]), B1([-1, 3]), B1([1])]]), 3: TensorProductOfCrystals(B1, B1, generators=[[B1([-1, 3]), B1([1])]]), 5: TensorProductOfCrystals(B6, B6, generators=[[B6([5, -6]), B6([6])]]), 2: TensorProductOfCrystals(B6, B1, generators=[[B6([2, -1]), B1([1])]])} FiniteDimensionalHighestWeightCrystal_TypeE.__init__(self, dominant_weight) @@ -424,12 +418,6 @@ def __init__(self, dominant_weight): sage: T.cardinality() 7371 """ - B = CrystalOfLetters(['E',7]) - self.column_crystal = {7 : B, - 1 : TensorProductOfCrystals(B,B,generators=[[B([-7,1]),B([7])]]), - 2 : TensorProductOfCrystals(B,B,B,generators=[[B([-1,2]),B([-7,1]),B([7])]]), - 3 : TensorProductOfCrystals(B,B,B,B,generators=[[B([-2,3]),B([-1,2]),B([-7,1]),B([7])]]), - 4 : TensorProductOfCrystals(B,B,B,B,generators=[[B([-5,4]),B([-6,5]),B([-7,6]),B([7])]]), - 5 : TensorProductOfCrystals(B,B,B,generators=[[B([-6,5]),B([-7,6]),B([7])]]), - 6 : TensorProductOfCrystals(B,B,generators=[[B([-7,6]),B([7])]])} + B = CrystalOfLetters(['E', 7]) + self.column_crystal = {7: B, 1: TensorProductOfCrystals(B, B, generators=[[B([-7, 1]), B([7])]]), 2: TensorProductOfCrystals(B, B, B, generators=[[B([-1, 2]), B([-7, 1]), B([7])]]), 3: TensorProductOfCrystals(B, B, B, B, generators=[[B([-2, 3]), B([-1, 2]), B([-7, 1]), B([7])]]), 4: TensorProductOfCrystals(B, B, B, B, generators=[[B([-5, 4]), B([-6, 5]), B([-7, 6]), B([7])]]), 5: TensorProductOfCrystals(B, B, B, generators=[[B([-6, 5]), B([-7, 6]), B([7])]]), 6: TensorProductOfCrystals(B, B, generators=[[B([-7, 6]), B([7])]])} FiniteDimensionalHighestWeightCrystal_TypeE.__init__(self, dominant_weight) diff --git a/src/sage/combinat/crystals/induced_structure.py b/src/sage/combinat/crystals/induced_structure.py index 7795b2492c4..bb8900a484a 100644 --- a/src/sage/combinat/crystals/induced_structure.py +++ b/src/sage/combinat/crystals/induced_structure.py @@ -9,7 +9,7 @@ - Travis Scrimshaw (2014-05-15): initial implementation """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) @@ -22,7 +22,7 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#**************************************************************************** +# **************************************************************************** from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent @@ -103,6 +103,7 @@ class InducedCrystal(UniqueRepresentation, Parent): sage: I.digraph() Digraph on 16 vertices """ + @staticmethod def __classcall_private__(cls, X, phi, inverse=None, from_crystal=False): """ @@ -473,8 +474,7 @@ def __init__(self, X, phi, inverse): self._cartan_type = X.cartan_type() Parent.__init__(self, category=X.category()) - self.module_generators = tuple(self.element_class(self, phi(mg)) - for mg in X.module_generators) + self.module_generators = tuple(self.element_class(self, phi(mg)) for mg in X.module_generators) def _repr_(self): """ diff --git a/src/sage/combinat/crystals/infinity_crystals.py b/src/sage/combinat/crystals/infinity_crystals.py index 959979fe082..d0f45624b18 100644 --- a/src/sage/combinat/crystals/infinity_crystals.py +++ b/src/sage/combinat/crystals/infinity_crystals.py @@ -39,10 +39,7 @@ from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.crystals.letters import CrystalOfLetters from sage.combinat.crystals.tensor_product import CrystalOfWords -from sage.combinat.crystals.tensor_product_element import ( - CrystalOfTableauxElement, - InfinityCrystalOfTableauxElement, InfinityCrystalOfTableauxElementTypeD, - InfinityQueerCrystalOfTableauxElement) +from sage.combinat.crystals.tensor_product_element import CrystalOfTableauxElement, InfinityCrystalOfTableauxElement, InfinityCrystalOfTableauxElementTypeD, InfinityQueerCrystalOfTableauxElement class InfinityCrystalOfTableaux(CrystalOfWords): @@ -189,6 +186,7 @@ class InfinityCrystalOfTableaux(CrystalOfWords): sage: crystal_test(B, C) True """ + @staticmethod def __classcall_private__(cls, cartan_type): """ @@ -217,8 +215,7 @@ def __init__(self, cartan_type): sage: B = crystals.infinity.Tableaux(['A',2]) sage: TestSuite(B).run() # long time """ - Parent.__init__(self, category=(HighestWeightCrystals(), - InfiniteEnumeratedSets())) + Parent.__init__(self, category=(HighestWeightCrystals(), InfiniteEnumeratedSets())) self._cartan_type = cartan_type self.letters = CrystalOfLetters(cartan_type) self.module_generators = (self.module_generator(),) @@ -251,7 +248,7 @@ def module_generator(self): n = self._cartan_type.rank() p = Partition(list(reversed(range(1, n + 1)))) # The column canonical tableau, read by columns - module_generator = flatten([[p[j]-i for i in range(p[j])] for j in range(n)]) + module_generator = flatten([[p[j] - i for i in range(p[j])] for j in range(n)]) return self(list=[self.letters(x) for x in module_generator]) def _element_constructor_(self, *args, **options): @@ -281,12 +278,11 @@ def _coerce_map_from_(self, P): From: The infinity crystal of rigged configurations of type ['A', 3] To: The infinity crystal of tableaux of type ['A', 3] """ - from sage.combinat.rigged_configurations.rc_infinity import (InfinityCrystalOfRiggedConfigurations, - InfinityCrystalOfNonSimplyLacedRC) - if (isinstance(P, InfinityCrystalOfRiggedConfigurations) - and (self.cartan_type().is_simply_laced() - or isinstance(P, InfinityCrystalOfNonSimplyLacedRC))): + from sage.combinat.rigged_configurations.rc_infinity import InfinityCrystalOfRiggedConfigurations, InfinityCrystalOfNonSimplyLacedRC + + if isinstance(P, InfinityCrystalOfRiggedConfigurations) and (self.cartan_type().is_simply_laced() or isinstance(P, InfinityCrystalOfNonSimplyLacedRC)): from sage.combinat.rigged_configurations.bij_infinity import FromRCIsomorphism + return FromRCIsomorphism(Hom(P, self)) return super()._coerce_map_from_(P) @@ -395,9 +391,8 @@ def weight(self): n = self.cartan_type().rank() ty = self.cartan_type().type() for i in range(1, len(self)): - if self[i-1] < self[i] or (self[i-1].value != 0 and self[i-1] == self[i]): - if (cur_col_len == n - 1 and ty == 'D') or \ - (cur_col_len == n and ty == 'B'): + if self[i - 1] < self[i] or (self[i - 1].value != 0 and self[i - 1] == self[i]): + if (cur_col_len == n - 1 and ty == 'D') or (cur_col_len == n and ty == 'B'): shape_wt += La[n] shape_wt += La[cur_col_len] cur_col_len = 1 @@ -434,7 +429,7 @@ def reduced_form(self): j = 0 row = list(row) while j < len(row): - if row[j] == i+1: + if row[j] == i + 1: row.pop(j) if not row: row.append('*') @@ -442,6 +437,7 @@ def reduced_form(self): j += 1 newtab.append(row) from sage.misc.stopgap import stopgap + stopgap("Return value is no longer a Tableau.", 17997) return newtab @@ -501,19 +497,19 @@ def seg(self): segments = [] for r in range(len(tab)): for c in range(len(tab[r])): - if tab[r][c] != r+1: + if tab[r][c] != r + 1: if [r, tab[r][c]] not in segments: segments.append([r, tab[r][c]]) if self.parent().cartan_type().type() == 'B': for r in range(len(tab)): for c in range(len(tab[r])): - if tab[r][c] == 0 and tab[r][-1] == -r-1: + if tab[r][c] == 0 and tab[r][-1] == -r - 1: segments.remove([r, tab[r][c]]) if self.parent().cartan_type().type() == 'D': n = self.parent().cartan_type().rank() add = [] for r in range(len(tab)): - if tab[r][-1] == -1*(r+1): + if tab[r][-1] == -1 * (r + 1): for c in range(len(tab[r])): if tab[r][c] != n and tab[r][c] != -n: if [r, n] not in add: @@ -594,6 +590,7 @@ class InfinityCrystalOfTableauxTypeD(InfinityCrystalOfTableaux): sage: b.weight() (-1, 0, -2, -1) """ + @staticmethod def __classcall_private__(cls, cartan_type): """ @@ -625,19 +622,21 @@ def module_generator(self): n = self._cartan_type.rank() p = Partition(list(reversed(range(1, n)))) # The column canonical tableau, read by columns - module_generator = flatten([[p[j]-i for i in range(p[j])] for j in range(n-1)]) + module_generator = flatten([[p[j] - i for i in range(p[j])] for j in range(n - 1)]) return self(list=[self.letters(x) for x in module_generator]) class Element(InfinityCrystalOfTableauxElementTypeD, InfinityCrystalOfTableaux.Element): r""" Elements in `\mathcal{B}(\infty)` crystal of tableaux for type `D_n`. """ + pass ######################################################### # Queer superalgebra + class DualInfinityQueerCrystalOfTableaux(CrystalOfWords): @staticmethod def __classcall_private__(cls, cartan_type): @@ -694,8 +693,8 @@ def module_generator(self): [[5, 5, 5, 5, 5], [4, 4, 4, 4], [3, 3, 3], [2, 2], [1]] """ n = self._cartan_type.rank() + 1 - row_lens = list(reversed(range(1, n+1))) - module_generator = flatten([[val]*val for val in row_lens]) + row_lens = list(reversed(range(1, n + 1))) + module_generator = flatten([[val] * val for val in row_lens]) return self.element_class(self, [self.letters(x) for x in module_generator], row_lens) @cached_method @@ -710,7 +709,7 @@ def index_set(self): (1, 2, -1) """ n = self._cartan_type.rank() - return tuple(range(1, n+1)) + (-1,) + return tuple(range(1, n + 1)) + (-1,) def _element_constructor_(self, *args, **options): """ diff --git a/src/sage/combinat/crystals/kac_modules.py b/src/sage/combinat/crystals/kac_modules.py index a496317f581..c0874e18d03 100644 --- a/src/sage/combinat/crystals/kac_modules.py +++ b/src/sage/combinat/crystals/kac_modules.py @@ -3,7 +3,7 @@ Crystals of Kac modules of the general-linear Lie superalgebra """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2017 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -11,7 +11,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.structure.parent import Parent from sage.structure.element_wrapper import ElementWrapper @@ -51,6 +51,7 @@ class CrystalOfOddNegativeRoots(UniqueRepresentation, Parent): sage: mg.f_string([0,-1,0,1,2,1,0]) {-e[-2]+e[3], -e[-1]+e[1], -e[-1]+e[2]} """ + @staticmethod def __classcall_private__(cls, cartan_type): """ @@ -138,10 +139,7 @@ def _repr_(self): sage: mg.f_string([0,-1,0]) {-e[-2]+e[1], -e[-1]+e[1]} """ - return ('{' - + ", ".join("-e[{}]+e[{}]".format(*i) - for i in sorted(self.value)) - + '}') + return '{' + ", ".join("-e[{}]+e[{}]".format(*i) for i in sorted(self.value)) + '}' def _latex_(self): r""" @@ -158,10 +156,7 @@ def _latex_(self): sage: latex(mg.f_string([0,-1,0])) \{-e_{-2}+e_{1}, -e_{-1}+e_{1}\} """ - return (r'\{' - + ", ".join("-e_{{{}}}+e_{{{}}}".format(*i) - for i in sorted(self.value)) - + r'\}') + return r'\{' + ", ".join("-e_{{{}}}+e_{{{}}}".format(*i) for i in sorted(self.value)) + r'\}' def e(self, i): r""" @@ -184,9 +179,9 @@ def e(self, i): {} """ if i == 0: - if (-1,1) not in self.value: + if (-1, 1) not in self.value: return None - return type(self)(self.parent(), self.value.difference([(-1,1)])) + return type(self)(self.parent(), self.value.difference([(-1, 1)])) count = 0 act_val = None @@ -243,9 +238,9 @@ def f(self, i): {-e[-2]+e[3], -e[-1]+e[2]} """ if i == 0: - if (-1,1) in self.value: + if (-1, 1) in self.value: return None - return type(self)(self.parent(), self.value.union([(-1,1)])) + return type(self)(self.parent(), self.value.union([(-1, 1)])) count = 0 act_val = None @@ -262,7 +257,7 @@ def f(self, i): count += 1 if act_val is None: return None - ret = self.value.difference([act_val]).union([(i-1, act_val[1])]) + ret = self.value.difference([act_val]).union([(i - 1, act_val[1])]) return type(self)(self.parent(), ret) # else i > 0 @@ -278,7 +273,7 @@ def f(self, i): count += 1 if act_val is None: return None - ret = self.value.difference([act_val]).union([(act_val[0], i+1)]) + ret = self.value.difference([act_val]).union([(act_val[0], i + 1)]) return type(self)(self.parent(), ret) def epsilon(self, i): @@ -314,7 +309,7 @@ def epsilon(self, i): ....: assert x.epsilon(i) == count_e(x, i) """ if i == 0: - return ZZ.one() if (-1,1) in self.value else ZZ.zero() + return ZZ.one() if (-1, 1) in self.value else ZZ.zero() count = 0 ret = 0 @@ -330,7 +325,7 @@ def epsilon(self, i): elif val[0] == i: count += 1 - else: # i > 0 + else: # i > 0 lst = sorted(self.value, key=lambda x: (-x[0], -x[1])) for val in reversed(lst): # We don't have to check val[0] because this is an odd root @@ -375,7 +370,7 @@ def phi(self, i): ....: assert x.phi(i) == count_f(x, i) """ if i == 0: - return ZZ.zero() if (-1,1) in self.value else ZZ.one() + return ZZ.zero() if (-1, 1) in self.value else ZZ.one() count = 0 ret = 0 @@ -391,7 +386,7 @@ def phi(self, i): elif val[0] == i - 1: count += 1 - else: # i > 0 + else: # i > 0 lst = sorted(self.value, key=lambda x: (-x[0], -x[1])) for val in lst: # We don't have to check val[0] because this is an odd root @@ -518,6 +513,7 @@ class CrystalOfKacModule(UniqueRepresentation, Parent): - [Kwon2012]_ """ + @staticmethod def __classcall_private__(cls, cartan_type, la, mu): """ @@ -551,9 +547,7 @@ def __init__(self, cartan_type, la, mu): self._S = CrystalOfOddNegativeRoots(self._cartan_type) self._dual = CrystalOfTableaux(['A', self._cartan_type.m], shape=la) self._reg = CrystalOfTableaux(['A', self._cartan_type.n], shape=mu) - data = (self._S.module_generators[0], - self._dual.module_generators[0], - self._reg.module_generators[0]) + data = (self._S.module_generators[0], self._dual.module_generators[0], self._reg.module_generators[0]) self.module_generators = (self.element_class(self, data),) def _repr_(self): @@ -565,8 +559,7 @@ def _repr_(self): sage: crystals.KacModule(['A', [2,1]], [3,1], [1]) Crystal of Kac module K([3, 1], [1]) of type ['A', [2, 1]] """ - return "Crystal of Kac module K({}, {}) of type {}".format( - self._la, self._mu, self._cartan_type) + return "Crystal of Kac module K({}, {}) of type {}".format(self._la, self._mu, self._cartan_type) def module_generator(self): """ @@ -643,9 +636,8 @@ def _latex_(self): } """ from sage.misc.latex import latex - return r" \otimes ".join([latex(self.value[0]), - latex_dual(self.value[1]), - latex(self.value[2])]) + + return r" \otimes ".join([latex(self.value[0]), latex_dual(self.value[1]), latex(self.value[2])]) def e(self, i): r""" @@ -686,8 +678,8 @@ def e(self, i): return type(self)(self.parent(), (self.value[0], self.value[1], x)) # else i < 0 M = self.parent()._cartan_type.m + 1 - if self.value[0].phi(i) < self.value[1].epsilon(M+i): - x = self.value[1].e(M+i) + if self.value[0].phi(i) < self.value[1].epsilon(M + i): + x = self.value[1].e(M + i) if x is None: return None return type(self)(self.parent(), (self.value[0], x, self.value[2])) @@ -734,12 +726,12 @@ def f(self, i): return type(self)(self.parent(), (x, self.value[1], self.value[2])) # else i < 0 M = self.parent()._cartan_type.m + 1 - if self.value[0].phi(i) > self.value[1].epsilon(M+i): + if self.value[0].phi(i) > self.value[1].epsilon(M + i): x = self.value[0].f(i) if x is None: return None return type(self)(self.parent(), (x, self.value[1], self.value[2])) - x = self.value[1].f(M+i) + x = self.value[1].f(M + i) if x is None: return None return type(self)(self.parent(), (self.value[0], x, self.value[2])) @@ -765,10 +757,11 @@ def weight(self): e = self.parent().weight_lattice_realization().basis() M = self.parent()._cartan_type.m + 1 wt = self.value[0].weight() - wt += sum(c*e[i-M] for i,c in self.value[1].weight()) - wt += sum(c*e[i+1] for i,c in self.value[2].weight()) + wt += sum(c * e[i - M] for i, c in self.value[1].weight()) + wt += sum(c * e[i + 1] for i, c in self.value[2].weight()) return wt + ##################################################################### ## Helper functions @@ -803,15 +796,16 @@ def to_dual_tableau(elt): ({}, [], []) """ from sage.combinat.tableau import Tableau + M = elt.parent().cartan_type().rank() + 2 if not elt: return Tableau([]) - tab = [ [elt[0].value-M] ] + tab = [[elt[0].value - M]] for i in range(1, len(elt)): - if elt[i-1] < elt[i] or (elt[i-1].value != 0 and elt[i-1] == elt[i]): - tab.append([elt[i].value-M]) + if elt[i - 1] < elt[i] or (elt[i - 1].value != 0 and elt[i - 1] == elt[i]): + tab.append([elt[i].value - M]) else: - tab[len(tab)-1].append(elt[i].value-M) + tab[len(tab) - 1].append(elt[i].value - M) for x in tab: x.reverse() return Tableau(tab).conjugate() @@ -839,18 +833,19 @@ def latex_dual(elt): M = elt.parent().cartan_type().rank() + 2 from sage.combinat.tableau import Tableau from sage.combinat.output import tex_from_array + # Modified version of to_tableau() to have the entries be letters # rather than their values if not elt: return "{\\emptyset}" - tab = [ ["\\overline{{{}}}".format(M-elt[0].value)] ] + tab = [["\\overline{{{}}}".format(M - elt[0].value)]] for i in range(1, len(elt)): - if elt[i-1] < elt[i] or (elt[i-1].value != 0 and elt[i-1] == elt[i]): - tab.append(["\\overline{{{}}}".format(M-elt[i].value)]) + if elt[i - 1] < elt[i] or (elt[i - 1].value != 0 and elt[i - 1] == elt[i]): + tab.append(["\\overline{{{}}}".format(M - elt[i].value)]) else: - l = len(tab)-1 - tab[l].append("\\overline{{{}}}".format(M-elt[i].value)) + l = len(tab) - 1 + tab[l].append("\\overline{{{}}}".format(M - elt[i].value)) for x in tab: x.reverse() diff --git a/src/sage/combinat/crystals/kirillov_reshetikhin.py b/src/sage/combinat/crystals/kirillov_reshetikhin.py index eb28d931b58..226382beec7 100644 --- a/src/sage/combinat/crystals/kirillov_reshetikhin.py +++ b/src/sage/combinat/crystals/kirillov_reshetikhin.py @@ -33,10 +33,7 @@ from sage.categories.map import Map from sage.rings.integer import Integer from sage.rings.rational_field import QQ -from sage.combinat.crystals.affine import (AffineCrystalFromClassical, - AffineCrystalFromClassicalElement, - AffineCrystalFromClassicalAndPromotion, - AffineCrystalFromClassicalAndPromotionElement) +from sage.combinat.crystals.affine import AffineCrystalFromClassical, AffineCrystalFromClassicalElement, AffineCrystalFromClassicalAndPromotion, AffineCrystalFromClassicalAndPromotionElement from sage.combinat.crystals.highest_weight_crystals import HighestWeightCrystal from sage.combinat.crystals.littelmann_path import CrystalOfProjectedLevelZeroLSPaths from sage.combinat.crystals.direct_sum import DirectSumOfCrystals @@ -135,7 +132,7 @@ def KirillovReshetikhinCrystalFromLSPaths(cartan_type, r, s=1): """ R = RootSystem(cartan_type) La = R.weight_space().basis() - weight = s*La[r] + weight = s * La[r] return CrystalOfProjectedLevelZeroLSPaths(weight) @@ -327,9 +324,11 @@ def KirillovReshetikhinCrystal(cartan_type, r, s, model='KN'): return KashiwaraNakashimaTableaux(cartan_type, r, s) if model in ['KR', 'KirillovReshetikhinTableaux']: from sage.combinat.rigged_configurations.kr_tableaux import KirillovReshetikhinTableaux + return KirillovReshetikhinTableaux(cartan_type, r, s) if model in ['RC', 'RiggedConfigurations']: from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations + return RiggedConfigurations(cartan_type, [[r, s]]) if model == 'LSPaths': return KirillovReshetikhinCrystalFromLSPaths(cartan_type, r, s) @@ -376,21 +375,21 @@ def KashiwaraNakashimaTableaux(cartan_type, r, s): if ct.type() == 'A': return KR_type_A(ct, r, s) if ct.type() == 'D': - if r < ct.rank()-2: + if r < ct.rank() - 2: return KR_type_vertical(ct, r, s) - if r in {ct.rank()-2, ct.rank()-1}: + if r in {ct.rank() - 2, ct.rank() - 1}: return KR_type_spin(ct, r, s) raise ValueError("wrong range of parameters") elif ct.type() == 'B': - if r < ct.rank()-1: + if r < ct.rank() - 1: return KR_type_vertical(ct, r, s) - if r == ct.rank()-1: + if r == ct.rank() - 1: return KR_type_Bn(ct, r, s) raise ValueError("wrong range of parameters") elif ct.type() == 'C': - if r < ct.rank()-1: + if r < ct.rank() - 1: return KR_type_C(ct, r, s) - if r == ct.rank()-1: + if r == ct.rank() - 1: return KR_type_Cn(ct, r, s) raise ValueError("wrong range of parameters") elif ct == CartanType(['E', 6, 1]) and r in [1, 6, 2]: @@ -407,9 +406,9 @@ def KashiwaraNakashimaTableaux(cartan_type, r, s): if ct.dual().type() == 'BC': return KR_type_A2(ct, r, s) if ct.dual().type() == 'C': - if r < ct.rank()-1: + if r < ct.rank() - 1: return KR_type_box(ct, r, s) - if r == ct.rank()-1: + if r == ct.rank() - 1: return KR_type_Dn_twisted(ct, r, s) raise ValueError("wrong range of parameters") elif ct.dual().type() == 'G': @@ -451,8 +450,7 @@ def __init__(self, cartan_type, r, s, dual=None): self._r = r self._s = s self._dual = dual - AffineCrystalFromClassical.__init__(self, cartan_type, self.classical_decomposition(), - KirillovReshetikhinCrystals()) + AffineCrystalFromClassical.__init__(self, cartan_type, self.classical_decomposition(), KirillovReshetikhinCrystals()) def _repr_(self): """ @@ -474,11 +472,11 @@ def _element_constructor_(self, *args, **options): [[1], [2]] """ from sage.combinat.rigged_configurations.kr_tableaux import KirillovReshetikhinTableauxElement + if isinstance(args[0], KirillovReshetikhinTableauxElement): elt = args[0] # Check to make sure it can be converted - if elt.cartan_type() != self.cartan_type() \ - or elt.parent().r() != self._r or elt.parent().s() != self._s: + if elt.cartan_type() != self.cartan_type() or elt.parent().r() != self._r or elt.parent().s() != self._s: raise ValueError("the Kirillov-Reshetikhin tableau must have the same Cartan type and shape") to_hw = elt.to_classical_highest_weight() @@ -486,7 +484,7 @@ def _element_constructor_(self, *args, **options): letters = elt.parent().letters for i, mult in sorted(to_hw[0].classical_weight()): # val in classical weight is a pair (i, mult) - rows.append([letters(i+1)] * int(mult)) + rows.append([letters(i + 1)] * int(mult)) hw_elt = self(rows=rows) f_str = reversed(to_hw[1]) return hw_elt.f_string(f_str) @@ -514,7 +512,7 @@ def module_generator(self): Lambda = R.fundamental_weights() r = self.r() s = self.s() - weight = s*Lambda[r] - s*Lambda[0] * Lambda[r].level() / Lambda[0].level() + weight = s * Lambda[r] - s * Lambda[0] * Lambda[r].level() / Lambda[0].level() return next(b for b in self.module_generators if b.weight() == weight) def r(self): @@ -552,8 +550,7 @@ def classically_highest_weight_vectors(self): sage: K.classically_highest_weight_vectors() ([], [[1], [2]], [[1, 1], [2, 2]]) """ - return tuple([self.retract(mg) - for mg in self.classical_decomposition().module_generators]) + return tuple([self.retract(mg) for mg in self.classical_decomposition().module_generators]) def kirillov_reshetikhin_tableaux(self): """ @@ -567,6 +564,7 @@ def kirillov_reshetikhin_tableaux(self): Kirillov-Reshetikhin tableaux of type ['D', 4, 1] and shape (2, 2) """ from sage.combinat.rigged_configurations.kr_tableaux import KirillovReshetikhinTableaux + return KirillovReshetikhinTableaux(self.cartan_type(), self._r, self._s) @@ -666,8 +664,7 @@ def lusztig_involution(self): KirillovReshetikhinGenericCrystal.Element = KirillovReshetikhinGenericCrystalElement -class KirillovReshetikhinCrystalFromPromotion(KirillovReshetikhinGenericCrystal, - AffineCrystalFromClassicalAndPromotion): +class KirillovReshetikhinCrystalFromPromotion(KirillovReshetikhinGenericCrystal, AffineCrystalFromClassicalAndPromotion): r""" This generic class assumes that the Kirillov-Reshetikhin crystal is constructed from a classical crystal using the @@ -693,19 +690,14 @@ def __init__(self, cartan_type, r, s): sage: TestSuite(K).run() """ KirillovReshetikhinGenericCrystal.__init__(self, cartan_type, r, s) - AffineCrystalFromClassicalAndPromotion.__init__(self, cartan_type, - self.classical_decomposition(), - self.promotion(), - self.promotion_inverse(), - self.dynkin_diagram_automorphism(0), - KirillovReshetikhinCrystals()) + AffineCrystalFromClassicalAndPromotion.__init__(self, cartan_type, self.classical_decomposition(), self.promotion(), self.promotion_inverse(), self.dynkin_diagram_automorphism(0), KirillovReshetikhinCrystals()) -class KirillovReshetikhinCrystalFromPromotionElement(AffineCrystalFromClassicalAndPromotionElement, - KirillovReshetikhinGenericCrystalElement): +class KirillovReshetikhinCrystalFromPromotionElement(AffineCrystalFromClassicalAndPromotionElement, KirillovReshetikhinGenericCrystalElement): """ Element for a Kirillov-Reshetikhin crystal from promotion. """ + pass @@ -734,8 +726,7 @@ def classical_decomposition(self): sage: K.classical_decomposition() The crystal of tableaux of type ['A', 3] and shape(s) [[2, 2]] """ - return CrystalOfTableaux(self.cartan_type().classical(), - shape=[self.s()]*self.r()) + return CrystalOfTableaux(self.cartan_type().classical(), shape=[self.s()] * self.r()) @cached_method def promotion(self): @@ -755,9 +746,7 @@ def promotion(self): """ T = self.classical_crystal ct = self._cartan_type[1] - return CrystalDiagramAutomorphism(T, - lambda x: T(x.to_tableau().promotion(ct)), - cache=False) + return CrystalDiagramAutomorphism(T, lambda x: T(x.to_tableau().promotion(ct)), cache=False) @cached_method def promotion_inverse(self): @@ -780,9 +769,7 @@ def promotion_inverse(self): """ T = self.classical_crystal ct = self._cartan_type[1] - return CrystalDiagramAutomorphism(T, - lambda x: T(x.to_tableau().promotion_inverse(ct)), - cache=False) + return CrystalDiagramAutomorphism(T, lambda x: T(x.to_tableau().promotion_inverse(ct)), cache=False) def dynkin_diagram_automorphism(self, i): r""" @@ -856,8 +843,7 @@ def classical_decomposition(self): sage: K.classical_decomposition() The crystal of tableaux of type ['D', 4] and shape(s) [[], [1, 1], [2, 2]] """ - return CrystalOfTableaux(self.cartan_type().classical(), - shapes=vertical_dominoes_removed(self.r(), self.s())) + return CrystalOfTableaux(self.cartan_type().classical(), shapes=vertical_dominoes_removed(self.r(), self.s())) @cached_method def promotion(self): @@ -971,7 +957,7 @@ def from_highest_weight_vector_to_pm_diagram(self, b): True """ n = self.cartan_type().rank() - 1 - inner = Partition([Integer(b.weight()[i]) for i in range(1, n+1)]) + inner = Partition([Integer(b.weight()[i]) for i in range(1, n + 1)]) inter = Partition([len([i for i in r if i > 0]) for r in b.to_tableau()]) outer = b.to_tableau().shape() return PMDiagram([self.r(), self.s(), outer, inter, inner], from_shapes=True) @@ -989,8 +975,7 @@ def from_pm_diagram_to_highest_weight_vector(self, pm): sage: K.from_pm_diagram_to_highest_weight_vector(pm) [[2], [-2]] """ - u = next(b for b in self.classical_decomposition().module_generators - if b.to_tableau().shape() == pm.outer_shape()) + u = next(b for b in self.classical_decomposition().module_generators if b.to_tableau().shape() == pm.outer_shape()) ct = self.cartan_type() rank = ct.rank() - 1 ct_type = ct.classical().type() @@ -1000,11 +985,11 @@ def from_pm_diagram_to_highest_weight_vector(self, pm): ulist += list(range(1, h + 1)) for h in pm.heights_of_minus(): if ct_type == 'D': - ulist += list(range(1, rank+1)) + [rank-2-k for k in range(rank-1-h)] + ulist += list(range(1, rank + 1)) + [rank - 2 - k for k in range(rank - 1 - h)] elif ct_type == 'B': - ulist += list(range(1, rank+1)) + [rank-k for k in range(rank+1-h)] + ulist += list(range(1, rank + 1)) + [rank - k for k in range(rank + 1 - h)] else: - ulist += list(range(1, rank+1)) + [rank-1-k for k in range(rank-h)] + ulist += list(range(1, rank + 1)) + [rank - 1 - k for k in range(rank - h)] for i in reversed(ulist): u = u.f(i) return u @@ -1080,12 +1065,10 @@ def classical_decomposition(self): if self.r() in [1, 6]: dw = [self.s() * La[self.r()]] elif self.r() == 2: - dw = [k*La[2] for k in range(self.s()+1)] + dw = [k * La[2] for k in range(self.s() + 1)] else: raise NotImplementedError - return DirectSumOfCrystals([HighestWeightCrystal(dominant_weight) - for dominant_weight in dw], - keepkey=False) + return DirectSumOfCrystals([HighestWeightCrystal(dominant_weight) for dominant_weight in dw], keepkey=False) def dynkin_diagram_automorphism(self, i): r""" @@ -1131,11 +1114,9 @@ def affine_weight(self, b): cl = self.cartan_type().classical() simple_roots = cl.root_system().ambient_space().simple_roots() index_set = cl.index_set() - weight = [Integer(b.weight().scalar(simple_roots[i])) - for i in index_set] + weight = [Integer(b.weight().scalar(simple_roots[i])) for i in index_set] E6_coeffs = [1, 2, 2, 3, 2, 1] - return tuple([-sum(weight[i] * coeff - for i, coeff in enumerate(E6_coeffs))] + weight) + return tuple([-sum(weight[i] * coeff for i, coeff in enumerate(E6_coeffs))] + weight) @cached_method def hw_auxiliary(self): @@ -1156,8 +1137,7 @@ def hw_auxiliary(self): [[(1, -3), (-1, 3)]], [[(-1,), (-1, 3)]]) """ - return tuple([x for x in self.classical_decomposition() - if all(x.epsilon(i) == 0 for i in [2, 3, 4, 5])]) + return tuple([x for x in self.classical_decomposition() if all(x.epsilon(i) == 0 for i in [2, 3, 4, 5])]) @cached_method def highest_weight_dict(self): @@ -1244,8 +1224,7 @@ def promotion_on_highest_weight_vectors(self): for weight, i in dic.values(): dic_weight[weight] = dic_weight.get(weight, []) + [i] map_index = lambda i_list: max(i_list[1]) + min(i_list[1]) - i_list[0] - map_element = lambda x: (self.automorphism_on_affine_weight(dic[x][0]), - map_index((dic[x][1], dic_weight[dic[x][0]]))) + map_element = lambda x: (self.automorphism_on_affine_weight(dic[x][0]), map_index((dic[x][1], dic_weight[dic[x][0]]))) return {x: dic_inv[map_element(x)] for x in dic} @cached_method @@ -1282,8 +1261,7 @@ def promotion(self): """ T = self.classical_decomposition() ind = [1, 2, 3, 4, 5] - return CrystalDiagramAutomorphism(T, self.promotion_on_highest_weight_vectors(), ind, - automorphism=self.dynkin_diagram_automorphism) + return CrystalDiagramAutomorphism(T, self.promotion_on_highest_weight_vectors(), ind, automorphism=self.dynkin_diagram_automorphism) @cached_method def promotion_inverse(self): @@ -1337,8 +1315,7 @@ def classical_decomposition(self): sage: K.classical_decomposition() The crystal of tableaux of type ['C', 3] and shape(s) [[], [2], [2, 2]] """ - return CrystalOfTableaux(self.cartan_type().classical(), - shapes=horizontal_dominoes_removed(self.r(), self.s())) + return CrystalOfTableaux(self.cartan_type().classical(), shapes=horizontal_dominoes_removed(self.r(), self.s())) def ambient_crystal(self): r""" @@ -1353,8 +1330,7 @@ def ambient_crystal(self): sage: K.ambient_crystal() Kirillov-Reshetikhin crystal of type ['B', 4, 1]^* with (r,s)=(2,3) """ - return KashiwaraNakashimaTableaux(['A', 2*self.cartan_type().classical().rank()+1, 2], - self.r(), self.s()) + return KashiwaraNakashimaTableaux(['A', 2 * self.cartan_type().classical().rank() + 1, 2], self.r(), self.s()) @cached_method def ambient_dict_pm_diagrams(self): @@ -1381,9 +1357,7 @@ def ambient_dict_pm_diagrams(self): s = self.s() r = self.r() m = s // 2 - ulist = (PMDiagram([[j, j] for j in la]+[[s-2*m+2*i]]) - for i in range(m + 1) - for la in IntegerVectors(m-i, min_length=r, max_length=r)) + ulist = (PMDiagram([[j, j] for j in la] + [[s - 2 * m + 2 * i]]) for i in range(m + 1) for la in IntegerVectors(m - i, min_length=r, max_length=r)) return {x.inner_shape(): x for x in ulist} @cached_method @@ -1403,8 +1377,7 @@ def ambient_highest_weight_dict(self): """ A = self.ambient_dict_pm_diagrams() ambient = self.ambient_crystal() - return {key: ambient.retract(ambient.from_pm_diagram_to_highest_weight_vector(A[key])) - for key in A} + return {key: ambient.retract(ambient.from_pm_diagram_to_highest_weight_vector(A[key])) for key in A} @cached_method def highest_weight_dict(self): @@ -1442,9 +1415,7 @@ def to_ambient_crystal(self): ahwd = self.ambient_highest_weight_dict() pdict = {hwd[key]: ahwd[key] for key in hwd} classical = self.cartan_type().classical() - return self.crystal_morphism(pdict, index_set=classical.index_set(), - automorphism=lambda i: i+1, - cartan_type=classical, check=False) + return self.crystal_morphism(pdict, index_set=classical.index_set(), automorphism=lambda i: i + 1, cartan_type=classical, check=False) @cached_method def from_ambient_crystal(self): @@ -1465,9 +1436,8 @@ def from_ambient_crystal(self): hwd = self.highest_weight_dict() ahwd = self.ambient_highest_weight_dict() pdict_inv = {ahwd[key]: hwd[key] for key in hwd} - ind = [j+1 for j in self.cartan_type().classical().index_set()] - return AmbientRetractMap(self, self.ambient_crystal(), pdict_inv, - index_set=ind, automorphism=lambda i: i-1) + ind = [j + 1 for j in self.cartan_type().classical().index_set()] + return AmbientRetractMap(self, self.ambient_crystal(), pdict_inv, index_set=ind, automorphism=lambda i: i - 1) class KR_type_CElement(KirillovReshetikhinGenericCrystalElement): @@ -1615,9 +1585,9 @@ def module_generator(self): Lambda = R.fundamental_weights() r = self.r() s = self.s() - weight = s*Lambda[r] - s*Lambda[0] + weight = s * Lambda[r] - s * Lambda[0] if r == self.cartan_type().rank() - 1: - weight += s*Lambda[r] # Special case for r == n + weight += s * Lambda[r] # Special case for r == n return next(b for b in self.module_generators if b.weight() == weight) def classical_decomposition(self): @@ -1639,8 +1609,7 @@ def classical_decomposition(self): sage: K.classical_decomposition() The crystal of tableaux of type ['B', 2] and shape(s) [[], [2], [2, 2]] """ - return CrystalOfTableaux(['B', self.cartan_type().rank()-1], - shapes=horizontal_dominoes_removed(self.r(), self.s())) + return CrystalOfTableaux(['B', self.cartan_type().rank() - 1], shapes=horizontal_dominoes_removed(self.r(), self.s())) def ambient_crystal(self): r""" @@ -1683,9 +1652,7 @@ def ambient_dict_pm_diagrams(self): s = self.s() r = self.r() m = s // 2 - ulist = (PMDiagram([[j, j] for j in la] + [[s-2*m+2*i]]) - for i in range(m + 1) - for la in IntegerVectors(m-i, min_length=r, max_length=r)) + ulist = (PMDiagram([[j, j] for j in la] + [[s - 2 * m + 2 * i]]) for i in range(m + 1) for la in IntegerVectors(m - i, min_length=r, max_length=r)) return {x.inner_shape(): x for x in ulist} @cached_method @@ -1706,8 +1673,7 @@ def ambient_highest_weight_dict(self): """ A = self.ambient_dict_pm_diagrams() ambient = self.ambient_crystal() - return {key: ambient.retract(ambient.from_pm_diagram_to_highest_weight_vector(A[key])) - for key in A} + return {key: ambient.retract(ambient.from_pm_diagram_to_highest_weight_vector(A[key])) for key in A} @cached_method def highest_weight_dict(self): @@ -1748,9 +1714,7 @@ def to_ambient_crystal(self): ahwd = self.ambient_highest_weight_dict() pdict = {hwd[key]: ahwd[key] for key in hwd} classical = self.cartan_type().classical() - return self.crystal_morphism(pdict, index_set=classical.index_set(), - automorphism=lambda i: i+1, - cartan_type=classical, check=False) + return self.crystal_morphism(pdict, index_set=classical.index_set(), automorphism=lambda i: i + 1, cartan_type=classical, check=False) @cached_method def from_ambient_crystal(self): @@ -1772,9 +1736,8 @@ def from_ambient_crystal(self): hwd = self.highest_weight_dict() ahwd = self.ambient_highest_weight_dict() pdict_inv = {ahwd[key]: hwd[key] for key in hwd} - ind = [j+1 for j in self.cartan_type().classical().index_set()] - return AmbientRetractMap(self, self.ambient_crystal(), pdict_inv, index_set=ind, - automorphism=lambda i: i-1) + ind = [j + 1 for j in self.cartan_type().classical().index_set()] + return AmbientRetractMap(self, self.ambient_crystal(), pdict_inv, index_set=ind, automorphism=lambda i: i - 1) class KR_type_A2Element(KirillovReshetikhinGenericCrystalElement): @@ -1896,8 +1859,7 @@ def __init__(self, cartan_type, r, s): sage: TestSuite(K).run() """ KirillovReshetikhinGenericCrystal.__init__(self, cartan_type, r, s) - AffineCrystalFromClassical.__init__(self, cartan_type, self.classical_decomposition(), - KirillovReshetikhinCrystals()) + AffineCrystalFromClassical.__init__(self, cartan_type, self.classical_decomposition(), KirillovReshetikhinCrystals()) def classical_decomposition(self): r""" @@ -1918,8 +1880,7 @@ def classical_decomposition(self): sage: K.classical_decomposition() The crystal of tableaux of type ['B', 3] and shape(s) [[], [1], [2], [1, 1], [3], [2, 1], [3, 1], [2, 2], [3, 2], [3, 3]] """ - return CrystalOfTableaux(self.cartan_type().classical(), - shapes=partitions_in_box(self.r(), self.s())) + return CrystalOfTableaux(self.cartan_type().classical(), shapes=partitions_in_box(self.r(), self.s())) def ambient_crystal(self): r""" @@ -1936,7 +1897,7 @@ def ambient_crystal(self): """ # calling KR_type_C instead of KirillovReshetikhin(['C',n,1],r,s) has the advantage that # that this also works for r=n for A_{2n}^{(2)}. - return KR_type_C(['C', self.cartan_type().classical().rank(), 1], self.r(), 2*self.s()) + return KR_type_C(['C', self.cartan_type().classical().rank(), 1], self.r(), 2 * self.s()) @cached_method def highest_weight_dict(self): @@ -1955,8 +1916,7 @@ def highest_weight_dict(self): [4, 2]: [[1, 1], [2]], [4, 4]: [[1, 1], [2, 2]]} """ - return {Partition([2*i for i in x.lift().to_tableau().shape()]): x - for x in self.module_generators} + return {Partition([2 * i for i in x.lift().to_tableau().shape()]): x for x in self.module_generators} @cached_method def ambient_highest_weight_dict(self): @@ -1975,8 +1935,7 @@ def ambient_highest_weight_dict(self): [4, 2]: [[1, 1, 1, 1], [2, 2]], [4, 4]: [[1, 1, 1, 1], [2, 2, 2, 2]]} """ - return {x.lift().to_tableau().shape(): x - for x in self.ambient_crystal().module_generators} + return {x.lift().to_tableau().shape(): x for x in self.ambient_crystal().module_generators} def similarity_factor(self): r""" @@ -2015,10 +1974,7 @@ def to_ambient_crystal(self): ahwd = self.ambient_highest_weight_dict() pdict = {hwd[key]: ahwd[key] for key in hwd} classical = self.cartan_type().classical() - return self.crystal_morphism(pdict, codomain=self.ambient_crystal(), - index_set=classical.index_set(), - scaling_factors=self.similarity_factor(), - cartan_type=classical, check=False) + return self.crystal_morphism(pdict, codomain=self.ambient_crystal(), index_set=classical.index_set(), scaling_factors=self.similarity_factor(), cartan_type=classical, check=False) @cached_method def from_ambient_crystal(self): @@ -2043,9 +1999,7 @@ def from_ambient_crystal(self): hwd = self.highest_weight_dict() ahwd = self.ambient_highest_weight_dict() pdict_inv = {ahwd[key]: hwd[key] for key in hwd} - return AmbientRetractMap(self, self.ambient_crystal(), pdict_inv, - index_set=self.cartan_type().classical().index_set(), - similarity_factor_domain=self.similarity_factor()) + return AmbientRetractMap(self, self.ambient_crystal(), pdict_inv, index_set=self.cartan_type().classical().index_set(), similarity_factor_domain=self.similarity_factor()) class KR_type_boxElement(KirillovReshetikhinGenericCrystalElement): @@ -2167,11 +2121,11 @@ def _element_constructor_(self, *args, **options): True """ from sage.combinat.rigged_configurations.kr_tableaux import KirillovReshetikhinTableauxElement + if isinstance(args[0], KirillovReshetikhinTableauxElement): elt = args[0] # Check to make sure it can be converted - if elt.cartan_type() != self.cartan_type() \ - or elt.parent().r() != self._r or elt.parent().s() != self._s: + if elt.cartan_type() != self.cartan_type() or elt.parent().r() != self._r or elt.parent().s() != self._s: raise ValueError("the Kirillov-Reshetikhin tableau must have the same Cartan type and shape") to_hw = elt.to_classical_highest_weight() @@ -2208,8 +2162,7 @@ def classical_decomposition(self): r = self.r() shapes = vertical_dominoes_removed(r, s // 2) if is_odd(s): - shapes = [[i+QQ(1)/QQ(2) for i in sh] + [QQ(1)/QQ(2)]*(r-len(sh)) - for sh in shapes] + shapes = [[i + QQ(1) / QQ(2) for i in sh] + [QQ(1) / QQ(2)] * (r - len(sh)) for sh in shapes] return CrystalOfTableaux(self.cartan_type().classical(), shapes=shapes) def ambient_crystal(self): @@ -2225,8 +2178,7 @@ def ambient_crystal(self): sage: K.ambient_crystal() Kirillov-Reshetikhin crystal of type ['B', 3, 1]^* with (r,s)=(3,2) """ - return KashiwaraNakashimaTableaux(['A', 2*self.cartan_type().classical().rank()-1, 2], - self.r(), self.s()) + return KashiwaraNakashimaTableaux(['A', 2 * self.cartan_type().classical().rank() - 1, 2], self.r(), self.s()) @cached_method def highest_weight_dict(self): @@ -2243,8 +2195,7 @@ def highest_weight_dict(self): sage: K.highest_weight_dict() {(3, 1, 1): [+++, [[1]]], (3, 3, 3): [+++, [[1], [2], [3]]]} """ - return {tuple([2*i[1] for i in sorted(x.classical_weight())]): x - for x in self.module_generators} + return {tuple([2 * i[1] for i in sorted(x.classical_weight())]): x for x in self.module_generators} @cached_method def ambient_highest_weight_dict(self): @@ -2265,8 +2216,7 @@ def ambient_highest_weight_dict(self): (3, 2, 2): [[1, 1, 1], [2, 2], [3, 3]], (3, 3, 3): [[1, 1, 1], [2, 2, 2], [3, 3, 3]]} """ - return {tuple([i[1] for i in sorted(x.classical_weight())]): x - for x in self.ambient_crystal().module_generators} + return {tuple([i[1] for i in sorted(x.classical_weight())]): x for x in self.ambient_crystal().module_generators} def similarity_factor(self): r""" @@ -2299,10 +2249,7 @@ def to_ambient_crystal(self): ahwd = self.ambient_highest_weight_dict() pdict = {hwd[key]: ahwd[key] for key in hwd} classical = self.cartan_type().classical() - return self.crystal_morphism(pdict, codomain=self.ambient_crystal(), - index_set=classical.index_set(), - scaling_factors=self.similarity_factor(), - cartan_type=classical, check=False) + return self.crystal_morphism(pdict, codomain=self.ambient_crystal(), index_set=classical.index_set(), scaling_factors=self.similarity_factor(), cartan_type=classical, check=False) @cached_method def from_ambient_crystal(self): @@ -2325,9 +2272,7 @@ def from_ambient_crystal(self): hwd = self.highest_weight_dict() ahwd = self.ambient_highest_weight_dict() pdict_inv = {ahwd[key]: hwd[key] for key in hwd} - return AmbientRetractMap(self, self.ambient_crystal(), pdict_inv, - index_set=self.cartan_type().classical().index_set(), - similarity_factor_domain=self.similarity_factor()) + return AmbientRetractMap(self, self.ambient_crystal(), pdict_inv, index_set=self.cartan_type().classical().index_set(), similarity_factor_domain=self.similarity_factor()) class KR_type_BnElement(KirillovReshetikhinGenericCrystalElement): @@ -2441,8 +2386,7 @@ def classical_decomposition(self): sage: K.classical_decomposition() The crystal of tableaux of type ['C', 3] and shape(s) [[2, 2, 2]] """ - return CrystalOfTableaux(self.cartan_type().classical(), - shape=[self.s()] * self.r()) + return CrystalOfTableaux(self.cartan_type().classical(), shape=[self.s()] * self.r()) def from_highest_weight_vector_to_pm_diagram(self, b): r""" @@ -2466,8 +2410,8 @@ def from_highest_weight_vector_to_pm_diagram(self, b): sage: all(K.from_pm_diagram_to_highest_weight_vector(K.from_highest_weight_vector_to_pm_diagram(b)) == b for b in hw) True """ - n = self.cartan_type().rank()-1 - inner = Partition([Integer(b.weight()[i]) for i in range(1, n+1)]) + n = self.cartan_type().rank() - 1 + inner = Partition([Integer(b.weight()[i]) for i in range(1, n + 1)]) inter = Partition([len([i for i in r if i > 0]) for r in b.to_tableau()]) outer = b.to_tableau().shape() return PMDiagram([self.r(), self.s(), outer, inter, inner], from_shapes=True) @@ -2485,17 +2429,16 @@ def from_pm_diagram_to_highest_weight_vector(self, pm): sage: K.from_pm_diagram_to_highest_weight_vector(pm) [[2, 2], [3, 3], [-3, -1]] """ - u = next(b for b in self.classical_decomposition().module_generators - if b.to_tableau().shape() == pm.outer_shape()) + u = next(b for b in self.classical_decomposition().module_generators if b.to_tableau().shape() == pm.outer_shape()) ct = self.cartan_type() - rank = ct.rank()-1 + rank = ct.rank() - 1 ct_type = ct.classical().type() assert ct_type in ['C'] ulist = [] for h in pm.heights_of_addable_plus(): ulist += list(range(1, h + 1)) for h in pm.heights_of_minus(): - ulist += list(range(1, rank+1))+[rank-1-k for k in range(rank-h)] + ulist += list(range(1, rank + 1)) + [rank - 1 - k for k in range(rank - h)] for i in reversed(ulist): u = u.f(i) return u @@ -2536,10 +2479,10 @@ def e0(self): n = self.parent().cartan_type().n b, l = self.lift().to_highest_weight(index_set=range(2, n + 1)) pm = self.parent().from_highest_weight_vector_to_pm_diagram(b) - l1, l2 = pm.pm_diagram[n-1] + l1, l2 = pm.pm_diagram[n - 1] if l1 == 0: return None - pm.pm_diagram[n-1] = [l1-1, l2+1] + pm.pm_diagram[n - 1] = [l1 - 1, l2 + 1] pm = PMDiagram(pm.pm_diagram) b = self.parent().from_pm_diagram_to_highest_weight_vector(pm) b = b.f_string(reversed(l)) @@ -2561,10 +2504,10 @@ def f0(self): n = self.parent().cartan_type().n b, l = self.lift().to_highest_weight(index_set=range(2, n + 1)) pm = self.parent().from_highest_weight_vector_to_pm_diagram(b) - l1, l2 = pm.pm_diagram[n-1] + l1, l2 = pm.pm_diagram[n - 1] if l2 == 0: return None - pm.pm_diagram[n-1] = [l1+1, l2-1] + pm.pm_diagram[n - 1] = [l1 + 1, l2 - 1] pm = PMDiagram(pm.pm_diagram) b = self.parent().from_pm_diagram_to_highest_weight_vector(pm) b = b.f_string(reversed(l)) @@ -2584,7 +2527,7 @@ def epsilon0(self): n = self.parent().cartan_type().n b = self.lift().to_highest_weight(index_set=range(2, n + 1))[0] pm = self.parent().from_highest_weight_vector_to_pm_diagram(b) - l1, l2 = pm.pm_diagram[n-1] + l1, l2 = pm.pm_diagram[n - 1] return l1 def phi0(self): @@ -2601,7 +2544,7 @@ def phi0(self): n = self.parent().cartan_type().n b = self.lift().to_highest_weight(index_set=range(2, n + 1))[0] pm = self.parent().from_highest_weight_vector_to_pm_diagram(b) - l1, l2 = pm.pm_diagram[n-1] + l1, l2 = pm.pm_diagram[n - 1] return l2 @@ -2639,13 +2582,12 @@ def _element_constructor_(self, *args, **options): True """ from sage.combinat.rigged_configurations.kr_tableaux import KirillovReshetikhinTableauxElement + if isinstance(args[0], KirillovReshetikhinTableauxElement): elt = args[0] # Check to make sure it can be converted - if elt.cartan_type() != self.cartan_type() \ - or elt.parent().r() != self._r or elt.parent().s() != self._s: - raise ValueError("the Kirillov-Reshetikhin tableau must have" - " the same Cartan type and shape") + if elt.cartan_type() != self.cartan_type() or elt.parent().r() != self._r or elt.parent().s() != self._s: + raise ValueError("the Kirillov-Reshetikhin tableau must have" " the same Cartan type and shape") to_hw = elt.to_classical_highest_weight() wt = to_hw[0].classical_weight() @@ -2678,8 +2620,7 @@ def classical_decomposition(self): s = s // 2 else: s = s / 2 - return CrystalOfTableaux(self.cartan_type().classical(), - shape=[s]*self.r()) + return CrystalOfTableaux(self.cartan_type().classical(), shape=[s] * self.r()) def from_highest_weight_vector_to_pm_diagram(self, b): r""" @@ -2740,28 +2681,25 @@ def from_highest_weight_vector_to_pm_diagram(self, b): b = b[1] else: t = b.parent()(rows=[]) - inner = [Integer(2*b.weight()[i]+2*t.weight()[i]) - for i in range(1, n+1)] - inter1 = Partition([len([1 for i in r if i > 0]) - for r in b.to_tableau()]) - inter = Partition([len([1 for i in r if i >= 0]) - for r in b.to_tableau()]) + inner = [Integer(2 * b.weight()[i] + 2 * t.weight()[i]) for i in range(1, n + 1)] + inter1 = Partition([len([1 for i in r if i > 0]) for r in b.to_tableau()]) + inter = Partition([len([1 for i in r if i >= 0]) for r in b.to_tableau()]) if inter != inter1: - inner[n-1] += 2 + inner[n - 1] += 2 inner = Partition(inner) - inter = [2*i for i in inter]+[0]*(n-len(inter)) + inter = [2 * i for i in inter] + [0] * (n - len(inter)) w = t.weight() - if w[0] == 0 and w[n-1] == 0: - v = [0]*n + if w[0] == 0 and w[n - 1] == 0: + v = [0] * n else: - v = [1]*n - if w[0] < 0 and w[n-1] > 0: - v[n-1] = 0 - elif w[0] > 0 and w[n-1] < 0: - v[n-1] = 0 - v[n-2] = -1 + v = [1] * n + if w[0] < 0 and w[n - 1] > 0: + v[n - 1] = 0 + elif w[0] > 0 and w[n - 1] < 0: + v[n - 1] = 0 + v[n - 2] = -1 inter = Partition([inter[i] + v[i] for i in range(n)]) - outer = Partition([s]*n) + outer = Partition([s] * n) return PMDiagram([n, s, outer, inter, inner], from_shapes=True) def from_pm_diagram_to_highest_weight_vector(self, pm): @@ -2779,15 +2717,15 @@ def from_pm_diagram_to_highest_weight_vector(self, pm): """ u = self.classical_decomposition().module_generators[0] ct = self.cartan_type() - rank = ct.rank()-1 + rank = ct.rank() - 1 assert ct.classical().type() in ['B'] ulist = [] plus = pm.heights_of_addable_plus() minus = pm.heights_of_minus() - l = len([i for i in plus if i == rank-1]) + l = len([i for i in plus if i == rank - 1]) a = (len(plus) + l) // 2 - ulist += sum(([i]*a for i in range(1, rank+1)), []) - a = (len(minus)-l) // 2 + ulist += sum(([i] * a for i in range(1, rank + 1)), []) + a = (len(minus) - l) // 2 ulist += (list(range(1, rank + 1)) + [rank]) * a for i in reversed(ulist): u = u.f(i) @@ -2820,23 +2758,23 @@ def e0(self): sage: b.e(0) # indirect doctest [+++, [[2], [3], [0]]] """ - n = self.parent().cartan_type().rank()-1 + n = self.parent().cartan_type().rank() - 1 s = self.parent().s() b, l = self.lift().to_highest_weight(index_set=range(2, n + 1)) pm = self.parent().from_highest_weight_vector_to_pm_diagram(b) - l1, l2 = pm.pm_diagram[n-1] - l3 = pm.pm_diagram[n-2][0] - if l1+l2+l3 == s and l1 == 0: + l1, l2 = pm.pm_diagram[n - 1] + l3 = pm.pm_diagram[n - 2][0] + if l1 + l2 + l3 == s and l1 == 0: return None - if l1+l2+l3 < s: - pm.pm_diagram[n-1][1] = l2+2 + if l1 + l2 + l3 < s: + pm.pm_diagram[n - 1][1] = l2 + 2 pm.pm_diagram[n][0] -= 2 elif l1 > 1: - pm.pm_diagram[n-1][0] = l1-2 + pm.pm_diagram[n - 1][0] = l1 - 2 pm.pm_diagram[n][0] += 2 elif l1 == 1: - pm.pm_diagram[n-1][0] = 0 - pm.pm_diagram[n-1][1] = l2+1 + pm.pm_diagram[n - 1][0] = 0 + pm.pm_diagram[n - 1][1] = l2 + 1 pm = PMDiagram(pm.pm_diagram) b = self.parent().from_pm_diagram_to_highest_weight_vector(pm) b = b.f_string(reversed(l)) @@ -2855,23 +2793,23 @@ def f0(self): sage: b = K.module_generators[0] sage: b.f(0) # indirect doctest """ - n = self.parent().cartan_type().rank()-1 + n = self.parent().cartan_type().rank() - 1 s = self.parent().s() b, l = self.lift().to_highest_weight(index_set=range(2, n + 1)) pm = self.parent().from_highest_weight_vector_to_pm_diagram(b) - l1, l2 = pm.pm_diagram[n-1] - l3 = pm.pm_diagram[n-2][0] - if l1+l2+l3 == s and l2 == 0: + l1, l2 = pm.pm_diagram[n - 1] + l3 = pm.pm_diagram[n - 2][0] + if l1 + l2 + l3 == s and l2 == 0: return None - if l1+l2+l3 < s: - pm.pm_diagram[n-1][0] = l1+2 + if l1 + l2 + l3 < s: + pm.pm_diagram[n - 1][0] = l1 + 2 pm.pm_diagram[n][0] -= 2 elif l2 > 1: - pm.pm_diagram[n-1][1] = l2-2 + pm.pm_diagram[n - 1][1] = l2 - 2 pm.pm_diagram[n][0] += 2 elif l2 == 1: - pm.pm_diagram[n-1][1] = 0 - pm.pm_diagram[n-1][0] = l1+1 + pm.pm_diagram[n - 1][1] = 0 + pm.pm_diagram[n - 1][0] = l1 + 1 pm = PMDiagram(pm.pm_diagram) b = self.parent().from_pm_diagram_to_highest_weight_vector(pm) b = b.f_string(reversed(l)) @@ -2906,7 +2844,7 @@ def epsilon0(self): n = self.parent().cartan_type().rank() - 1 b, l = self.lift().to_highest_weight(index_set=range(2, n + 1)) pm = self.parent().from_highest_weight_vector_to_pm_diagram(b) - l1 = pm.pm_diagram[n-1][0] + l1 = pm.pm_diagram[n - 1][0] l4 = pm.pm_diagram[n][0] return l1 + l4 // 2 @@ -2939,7 +2877,7 @@ def phi0(self): n = self.parent().cartan_type().rank() - 1 b, l = self.lift().to_highest_weight(index_set=range(2, n + 1)) pm = self.parent().from_highest_weight_vector_to_pm_diagram(b) - l2 = pm.pm_diagram[n-1][1] + l2 = pm.pm_diagram[n - 1][1] l4 = pm.pm_diagram[n][0] return l2 + l4 // 2 @@ -3029,11 +2967,11 @@ def _element_constructor_(self, *args, **options): True """ from sage.combinat.rigged_configurations.kr_tableaux import KirillovReshetikhinTableauxElement + if isinstance(args[0], KirillovReshetikhinTableauxElement): elt = args[0] # Check to make sure it can be converted - if elt.cartan_type() != self.cartan_type() \ - or elt.parent().r() != self._r or elt.parent().s() != self._s: + if elt.cartan_type() != self.cartan_type() or elt.parent().r() != self._r or elt.parent().s() != self._s: raise ValueError("the Kirillov-Reshetikhin tableau must have the same Cartan type and shape") to_hw = elt.to_classical_highest_weight() @@ -3072,9 +3010,9 @@ def classical_decomposition(self): C = self.cartan_type().classical() s = QQ(self.s()) if self.r() == C.n: - c = [s / QQ(2)]*C.n + c = [s / QQ(2)] * C.n else: - c = [s / QQ(2)]*(C.n-1) + [-s / QQ(2)] + c = [s / QQ(2)] * (C.n - 1) + [-s / QQ(2)] return CrystalOfTableaux(C, shape=c) def dynkin_diagram_automorphism(self, i): @@ -3141,7 +3079,7 @@ def promotion_on_highest_weight_vectors(self): C = T.cartan_type() n = C.n sh = list(T.shapes[0]) - sh[n-1] = -sh[n-1] + sh[n - 1] = -sh[n - 1] T_dual = CrystalOfTableaux(C, shape=sh) hw = [t for t in T if t.is_highest_weight(index_set=ind)] hw_dual = [t for t in T_dual if t.is_highest_weight(index_set=ind)] @@ -3258,7 +3196,7 @@ def classical_decomposition(self): The crystal of tableaux of type ['G', 2] and shape(s) [[], [1], [2], [3], [4], [5]] """ - sh = [Partition([j]) for j in range(self._s+1)] + sh = [Partition([j]) for j in range(self._s + 1)] return CrystalOfTableaux(self.cartan_type().classical(), shapes=sh) def from_coordinates(self, coords): @@ -3277,9 +3215,7 @@ def from_coordinates(self, coords): return self.element_class(self, C.module_generators[0]) l = C.letters - lst = ([l(1)]*coords[0] + [l(2)]*coords[1] + [l(3)]*(coords[2]//2) - + [l(0)]*(coords[2] % 2) + [l(-3)]*(coords[3]//2) - + [l(-2)]*coords[4] + [l(-1)]*coords[5]) + lst = [l(1)] * coords[0] + [l(2)] * coords[1] + [l(3)] * (coords[2] // 2) + [l(0)] * (coords[2] % 2) + [l(-3)] * (coords[3] // 2) + [l(-2)] * coords[4] + [l(-1)] * coords[5] return self.element_class(self, C(*lst)) def _element_constructor_(self, *args, **options): @@ -3300,11 +3236,11 @@ def _element_constructor_(self, *args, **options): True """ from sage.combinat.rigged_configurations.kr_tableaux import KirillovReshetikhinTableauxElement + if isinstance(args[0], KirillovReshetikhinTableauxElement): elt = args[0] # Check to make sure it can be converted - if elt.cartan_type() != self.cartan_type() \ - or elt.parent().r() != self._r or elt.parent().s() != self._s: + if elt.cartan_type() != self.cartan_type() or elt.parent().r() != self._r or elt.parent().s() != self._s: raise ValueError("the Kirillov-Reshetikhin tableau must have the same Cartan type and shape") to_hw = elt.to_classical_highest_weight() @@ -3312,7 +3248,7 @@ def _element_constructor_(self, *args, **options): wt = sum(x.value for x in to_hw[0] if x.value != 'E') letters = elt.parent().letters if wt: - rows = [[letters(1)]*int(wt)] + rows = [[letters(1)] * int(wt)] else: rows = [] hw_elt = self(rows=rows) @@ -3334,10 +3270,7 @@ def coordinates(self): """ letters = self.parent().classical_decomposition().letters l = list(self.value) - return (l.count(letters(1)), l.count(letters(2)), - 2*l.count(letters(3)) + l.count(letters(0)), - 2*l.count(letters(-3)) + l.count(letters(0)), - l.count(letters(-2)), l.count(letters(-1))) + return (l.count(letters(1)), l.count(letters(2)), 2 * l.count(letters(3)) + l.count(letters(0)), 2 * l.count(letters(-3)) + l.count(letters(0)), l.count(letters(-2)), l.count(letters(-1))) @lazy_attribute def _A(self): @@ -3354,10 +3287,8 @@ def _A(self): [(0, 0, 0, 0, 0, 0), (0, -1, -1, -1, -1, -2)] """ coords = self.coordinates() - z = [coords[-1] - coords[0], coords[-2] - coords[-3], - coords[2] - coords[1], (coords[-3] - coords[2]) // 2] - return (0, z[0], z[0] + z[1], z[0] + z[1] + 3*z[3], - sum(z) + 2*z[3], sum(z) + z[0] + 2*z[3]) + z = [coords[-1] - coords[0], coords[-2] - coords[-3], coords[2] - coords[1], (coords[-3] - coords[2]) // 2] + return (0, z[0], z[0] + z[1], z[0] + z[1] + 3 * z[3], sum(z) + 2 * z[3], sum(z) + z[0] + 2 * z[3]) def e0(self): r""" @@ -3452,7 +3383,7 @@ def epsilon0(self): c = self.coordinates() z = [c[-1] - c[0], c[-2] - c[-3], c[2] - c[1], (c[-3] - c[2]) // 2] s = c[0] + c[1] + (c[2] + c[3]) // 2 + c[4] + c[5] - return self.parent()._s - s + max(self._A) - (2*z[0] + z[1] + z[2] + 3*z[3]) + return self.parent()._s - s + max(self._A) - (2 * z[0] + z[1] + z[2] + 3 * z[3]) def phi0(self): r""" @@ -3495,7 +3426,7 @@ def module_generator(self, shape): """ if len(shape) != 1: raise NotImplementedError("only implemented for single row shapes") - return self(*[self.letters.highest_weight_vector()]*shape[0]) + return self(*[self.letters.highest_weight_vector()] * shape[0]) class KR_type_E7(KirillovReshetikhinGenericCrystal): @@ -3528,8 +3459,7 @@ def classical_decomposition(self): sage: K.classical_decomposition() The crystal of tableaux of type ['E', 7] and shape(s) [[4]] """ - return CrystalOfTableaux_E7(self.cartan_type().classical(), - shapes=(Partition([self._s]),)) + return CrystalOfTableaux_E7(self.cartan_type().classical(), shapes=(Partition([self._s]),)) @cached_method def A7_decomposition(self): @@ -3553,15 +3483,10 @@ def A7_decomposition(self): [2, 2, 2, 2, 1, 1], [2, 2, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1]] """ from sage.geometry.polyhedron.constructor import Polyhedron + # variables are m_4, m_5, m_6, m_7 - P = Polyhedron(ieqs=[[0, 1, 0, 0, 0], - [0, 0, 1, 0, 0], - [0, 0, 0, 1, 0], - [0, 0, 0, 0, 1], - [0, -1, -1, 0, 1]], - eqns=[[-self._s, 1, 1, 1, 1]]) - shapes = [Partition([6]*(p[3]-p[1]-p[0])+[4]*p[1]+[2]*p[2]).conjugate() - for p in P.integral_points()] + P = Polyhedron(ieqs=[[0, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1], [0, -1, -1, 0, 1]], eqns=[[-self._s, 1, 1, 1, 1]]) + shapes = [Partition([6] * (p[3] - p[1] - p[0]) + [4] * p[1] + [2] * p[2]).conjugate() for p in P.integral_points()] return CrystalOfTableaux(['A', 7], shapes=shapes) @lazy_attribute @@ -3594,7 +3519,7 @@ def _highest_weight_to_A7_elements(self): if not b.is_highest_weight([1, 3, 4, 5, 6, 7]): continue wt = [b.phi(i) for i in [7, 6, 5, 4, 3, 1]] - la = Partition([6]*(wt[4]+wt[5])+[4]*(wt[2]+wt[3])+[2]*(wt[0]+wt[1])).conjugate() + la = Partition([6] * (wt[4] + wt[5]) + [4] * (wt[2] + wt[3]) + [2] * (wt[0] + wt[1])).conjugate() # mu = Partition(sum(([6-i]*m for i,m in enumerate(wt)), [])).conjugate() x = A7.module_generator(la) for i in range(wt[0]): @@ -3623,10 +3548,7 @@ def to_A7_crystal(self): Defn: ... """ d = self._highest_weight_to_A7_elements - return self.crystal_morphism(d, automorphism={1: 6, 3: 5, 4: 4, - 5: 3, 6: 2, 7: 1}, - index_set=[1, 3, 4, 5, 6, 7], - check=False) + return self.crystal_morphism(d, automorphism={1: 6, 3: 5, 4: 4, 5: 3, 6: 2, 7: 1}, index_set=[1, 3, 4, 5, 6, 7], check=False) @cached_method def from_A7_crystal(self): @@ -3647,10 +3569,7 @@ def from_A7_crystal(self): A7 = self.A7_decomposition() d = self._highest_weight_to_A7_elements d_inv = {d[b]: b for b in d} - return A7.crystal_morphism(d_inv, automorphism={6: 1, 5: 3, 4: 4, - 3: 5, 2: 6, 1: 7}, - index_set=[1, 2, 3, 4, 5, 6], - check=False) + return A7.crystal_morphism(d_inv, automorphism={6: 1, 5: 3, 4: 4, 3: 5, 2: 6, 1: 7}, index_set=[1, 2, 3, 4, 5, 6], check=False) class Element(KirillovReshetikhinGenericCrystalElement): def e0(self): @@ -3694,6 +3613,7 @@ def f0(self): return None return P.from_A7_crystal()(x) + ##################################################################### @@ -3762,18 +3682,18 @@ def __init__(self, pm_diagram, from_shapes=None): if from_shapes: n = pm_diagram[0] s = pm_diagram[1] - outer = [s] + list(pm_diagram[2]) + [0]*n - intermediate = [s] + list(pm_diagram[3]) + [0]*n - inner = [s] + list(pm_diagram[4]) + [0]*n + outer = [s] + list(pm_diagram[2]) + [0] * n + intermediate = [s] + list(pm_diagram[3]) + [0] * n + inner = [s] + list(pm_diagram[4]) + [0] * n pm = [[inner[n]]] - for i in range((n+1)//2): - pm.append([intermediate[n-2*i]-inner[n-2*i], inner[n-2*i-1]-intermediate[n-2*i]]) - pm.append([outer[n-2*i]-inner[n-2*i-1], inner[n-2*i-2]-outer[n-2*i]]) + for i in range((n + 1) // 2): + pm.append([intermediate[n - 2 * i] - inner[n - 2 * i], inner[n - 2 * i - 1] - intermediate[n - 2 * i]]) + pm.append([outer[n - 2 * i] - inner[n - 2 * i - 1], inner[n - 2 * i - 2] - outer[n - 2 * i]]) if is_odd(n): - pm.pop(n+1) + pm.pop(n + 1) pm_diagram = list(reversed(pm)) self.pm_diagram = pm_diagram - self.n = len(pm_diagram)-1 + self.n = len(pm_diagram) - 1 self._list = [i for a in reversed(pm_diagram) for i in a] self.width = sum(self._list) @@ -3808,8 +3728,7 @@ def _repr_diagram(self) -> str: ish = self.inner_shape() + [0] * self.n msh = self.intermediate_shape() + [0] * self.n osh = self.outer_shape() + [0] * self.n - t = (['.'] * ish[i] + ['+'] * (msh[i]-ish[i]) + ['-'] * (osh[i]-msh[i]) - for i in range(self.n)) + t = (['.'] * ish[i] + ['+'] * (msh[i] - ish[i]) + ['-'] * (osh[i] - msh[i]) for i in range(self.n)) t = [i for i in t if i] return Tableau(t)._repr_diagram() if t else '' @@ -3849,7 +3768,7 @@ def inner_shape(self): [10, 7, 5, 3, 1] """ ll = self._list - t = [sum(ll[0:2*i+1]) for i in range(self.n)] + t = [sum(ll[0 : 2 * i + 1]) for i in range(self.n)] return Partition(list(reversed(t))) def outer_shape(self): @@ -3872,10 +3791,10 @@ def outer_shape(self): t = [] ll = self._list for i in range(self.n // 2): - t.append(sum(ll[0:4*i+4])) - t.append(sum(ll[0:4*i+4])) - if is_even(self.n+1): - t.append(sum(ll[0:2*self.n+2])) + t.append(sum(ll[0 : 4 * i + 4])) + t.append(sum(ll[0 : 4 * i + 4])) + if is_even(self.n + 1): + t.append(sum(ll[0 : 2 * self.n + 2])) return Partition(list(reversed(t))) def intermediate_shape(self): @@ -3905,7 +3824,7 @@ def intermediate_shape(self): p = self.inner_shape() p = p + [0 for _ in range(self.n)] ll = list(reversed(self._list)) - p = [p[i] + ll[2*i+1] for i in range(self.n)] + p = [p[i] + ll[2 * i + 1] for i in range(self.n)] return Partition(p) def heights_of_minus(self) -> list: @@ -3925,7 +3844,7 @@ def heights_of_minus(self) -> list: n = self.n heights = [] for i in range((n + 1) // 2): - heights += [n-2*i]*((self.outer_shape()+[0]*n)[n-2*i-1]-(self.intermediate_shape()+[0]*n)[n-2*i-1]) + heights += [n - 2 * i] * ((self.outer_shape() + [0] * n)[n - 2 * i - 1] - (self.intermediate_shape() + [0] * n)[n - 2 * i - 1]) return heights def heights_of_addable_plus(self) -> list: @@ -3943,8 +3862,8 @@ def heights_of_addable_plus(self) -> list: [1, 2, 3, 4] """ heights = [] - for i in range(1, self.n+1): - heights += [i]*self.sigma().pm_diagram[i][0] + for i in range(1, self.n + 1): + heights += [i] * self.sigma().pm_diagram[i][0] return heights def sigma(self): @@ -3965,6 +3884,7 @@ def sigma(self): ####################################################################### + def partitions_in_box(r, s): """ Return all partitions in a box of width s and height r. @@ -3975,8 +3895,7 @@ def partitions_in_box(r, s): [[], [1], [2], [1, 1], [2, 1], [1, 1, 1], [2, 2], [2, 1, 1], [2, 2, 1], [2, 2, 2]] """ - return [x for n in range(r*s+1) - for x in Partitions(n, max_part=s, max_length=r)] + return [x for n in range(r * s + 1) for x in Partitions(n, max_part=s, max_length=r)] def vertical_dominoes_removed(r, s): @@ -4008,10 +3927,11 @@ def horizontal_dominoes_removed(r, s): sage: sage.combinat.crystals.kirillov_reshetikhin.horizontal_dominoes_removed(3,2) [[], [2], [2, 2], [2, 2, 2]] """ - ulist = [list(x) + [0]*(r-x.length()) for x in partitions_in_box(r, s//2)] + ulist = [list(x) + [0] * (r - x.length()) for x in partitions_in_box(r, s // 2)] two = lambda x: 2 * (x - s // 2) + s return [Partition([two(y) for y in x]) for x in ulist] + ##################################################################### # Morphisms @@ -4026,8 +3946,7 @@ class AmbientRetractMap(Map): `\tilde{\phi} \circ \phi` is the identity on `X`. """ - def __init__(self, base, ambient, pdict_inv, index_set, - similarity_factor_domain=None, automorphism=None): + def __init__(self, base, ambient, pdict_inv, index_set, similarity_factor_domain=None, automorphism=None): """ Initialize ``self``. @@ -4038,6 +3957,7 @@ def __init__(self, base, ambient, pdict_inv, index_set, sage: TestSuite(phi).run(skip=['_test_category', '_test_pickling']) """ from sage.categories.sets_with_partial_maps import SetsWithPartialMaps + Map.__init__(self, Hom(ambient, base, SetsWithPartialMaps())) if similarity_factor_domain is None: diff --git a/src/sage/combinat/crystals/kyoto_path_model.py b/src/sage/combinat/crystals/kyoto_path_model.py index b6a0d9f9f89..8090b1b22fd 100644 --- a/src/sage/combinat/crystals/kyoto_path_model.py +++ b/src/sage/combinat/crystals/kyoto_path_model.py @@ -21,8 +21,7 @@ from sage.structure.parent import Parent from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.highest_weight_crystals import HighestWeightCrystals -from sage.combinat.crystals.tensor_product import TensorProductOfCrystals, \ - TensorProductOfRegularCrystalsElement +from sage.combinat.crystals.tensor_product import TensorProductOfCrystals, TensorProductOfRegularCrystalsElement class KyotoPathModel(TensorProductOfCrystals): @@ -195,6 +194,7 @@ class KyotoPathModel(TensorProductOfCrystals): sage: x.weight() Lambda[0] - delta """ + @staticmethod def __classcall_private__(cls, crystals, weight, P=None): """ @@ -224,8 +224,7 @@ def __classcall_private__(cls, crystals, weight, P=None): ct = crystals[0].cartan_type() if P is None: P = weight.parent() - if sum(ct.dual().c()[i] * weight.scalar(h) - for i, h in enumerate(P.simple_coroots())) != level: + if sum(ct.dual().c()[i] * weight.scalar(h) for i, h in enumerate(P.simple_coroots())) != level: raise ValueError(f"{weight} is not a level {level} weight") return super().__classcall__(cls, crystals, weight, P) @@ -248,17 +247,13 @@ def __init__(self, crystals, weight, P): if weight.parent().is_extended(): # public for TensorProductOfCrystals self.crystals = tuple([C.affinization() for C in crystals]) - self._epsilon_dicts = [{b.Epsilon(): self.crystals[i](b, 0) for b in B} - for i,B in enumerate(crystals)] - self._phi_dicts = [{b.Phi(): self.crystals[i](b, 0) for b in B} - for i,B in enumerate(crystals)] + self._epsilon_dicts = [{b.Epsilon(): self.crystals[i](b, 0) for b in B} for i, B in enumerate(crystals)] + self._phi_dicts = [{b.Phi(): self.crystals[i](b, 0) for b in B} for i, B in enumerate(crystals)] else: # public for TensorProductOfCrystals self.crystals = tuple(crystals) - self._epsilon_dicts = [{b.Epsilon(): b for b in B} - for B in crystals] - self._phi_dicts = [{b.Phi(): b for b in B} - for B in crystals] + self._epsilon_dicts = [{b.Epsilon(): b for b in B} for B in crystals] + self._phi_dicts = [{b.Phi(): b for b in B} for B in crystals] self.module_generators = (self.element_class(self, [self._phi_dicts[0][weight]]),) def _repr_(self): @@ -321,6 +316,7 @@ class Element(TensorProductOfRegularCrystalsElement): """ An element in the Kyoto path model. """ + # For simplicity (and safety), we use the regular crystals implementation def epsilon(self, i): @@ -396,10 +392,10 @@ def e(self, i): k = self.position_of_first_unmatched_plus(i) if k is None: return None - if k == len(self)-1: + if k == len(self) - 1: return None crystal = self[k].e(i) - if k == len(self)-2 and crystal.Epsilon() == self[-1].Phi(): + if k == len(self) - 2 and crystal.Epsilon() == self[-1].Phi(): l = self[:-1] l[-1] = crystal return self.__class__(self.parent(), l) @@ -424,10 +420,10 @@ def f(self, i): k = self.position_of_last_unmatched_minus(i) if k is None: return None - if k == len(self)-1: + if k == len(self) - 1: l = list(self) k = len(l) % len(self.parent().crystals) - l.append(self.parent()._phi_dicts[k][ l[-1].Epsilon() ]) + l.append(self.parent()._phi_dicts[k][l[-1].Epsilon()]) l[-2] = l[-2].f(i) return self.__class__(self.parent(), l) return self._set_index(k, self[k].f(i)) @@ -492,5 +488,5 @@ def truncate(self, k=None): N = len(self.parent().crystals) while len(l) < k: i = len(l) % N - l.append(self.parent()._phi_dicts[i][ l[-1].Epsilon() ]) + l.append(self.parent()._phi_dicts[i][l[-1].Epsilon()]) return P(*l) diff --git a/src/sage/combinat/crystals/littelmann_path.py b/src/sage/combinat/crystals/littelmann_path.py index 8c7e10da731..50350550f27 100644 --- a/src/sage/combinat/crystals/littelmann_path.py +++ b/src/sage/combinat/crystals/littelmann_path.py @@ -36,8 +36,7 @@ from sage.categories.regular_crystals import RegularCrystals from sage.categories.classical_crystals import ClassicalCrystals from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets -from sage.categories.loop_crystals import (RegularLoopCrystals, - KirillovReshetikhinCrystals) +from sage.categories.loop_crystals import RegularLoopCrystals, KirillovReshetikhinCrystals from sage.combinat.root_system.cartan_type import CartanType from sage.rings.integer import Integer from sage.rings.rational_field import QQ @@ -123,6 +122,7 @@ class CrystalOfLSPaths(UniqueRepresentation, Parent): - [Li1995b]_ """ + @staticmethod def __classcall_private__(cls, starting_weight, cartan_type=None, starting_weight_parent=None): """ @@ -172,7 +172,7 @@ def __classcall_private__(cls, starting_weight, cartan_type=None, starting_weigh Lambda = P.basis() if not isinstance(starting_weight, P.Element): offset = R.index_set()[Integer(0)] - starting_weight = P.sum(starting_weight[j-offset]*Lambda[j] for j in R.index_set()) + starting_weight = P.sum(starting_weight[j - offset] * Lambda[j] for j in R.index_set()) if starting_weight_parent is None: starting_weight_parent = starting_weight.parent() else: @@ -227,9 +227,7 @@ def __init__(self, starting_weight, starting_weight_parent): self._cartan_type = cartan_type if cartan_type.is_affine(): if all(i >= 0 for i in starting_weight.coefficients()): - Parent.__init__(self, category=(RegularCrystals(), - HighestWeightCrystals(), - InfiniteEnumeratedSets())) + Parent.__init__(self, category=(RegularCrystals(), HighestWeightCrystals(), InfiniteEnumeratedSets())) elif starting_weight.parent().is_extended(): Parent.__init__(self, category=(RegularCrystals(), InfiniteEnumeratedSets())) else: @@ -282,6 +280,7 @@ class Element(ElementWrapper): sage: c = C.an_element() sage: TestSuite(c).run() """ + def endpoint(self): r""" Compute the endpoint of ``self``. @@ -307,7 +306,7 @@ def endpoint(self): if not self.value: return self.parent().weight.parent().zero() return sum(self.value) - #return self.parent().R.weight_space(extended = self.parent().extended).zero() + # return self.parent().R.weight_space(extended = self.parent().extended).zero() def compress(self): r""" @@ -353,7 +352,7 @@ def split_step(self, which_step, r): (1/3*Lambda[1] + 1/3*Lambda[2], 2/3*Lambda[1] + 2/3*Lambda[2]) """ v = self.value[which_step] - return self.parent()(self.value[:which_step] + (r*v,(1-r)*v) + self.value[which_step+1:]) + return self.parent()(self.value[:which_step] + (r * v, (1 - r) * v) + self.value[which_step + 1 :]) def reflect_step(self, which_step, i): r""" @@ -368,7 +367,7 @@ def reflect_step(self, which_step, i): sage: b.reflect_step(0,2) (2*Lambda[1] - Lambda[2],) """ - return self.parent()(self.value[:which_step]+tuple([self.value[which_step].simple_reflection(i)])+self.value[which_step+1:]) + return self.parent()(self.value[:which_step] + tuple([self.value[which_step].simple_reflection(i)]) + self.value[which_step + 1 :]) def _string_data(self, i): r""" @@ -400,7 +399,7 @@ def _string_data(self, i): for ix, step in enumerate(steps): ps = ps + step if ps < psmin: - minima_pos.append((ix,ps,step)) + minima_pos.append((ix, ps, step)) psmin = ps return tuple(minima_pos) @@ -498,11 +497,11 @@ def e(self, i, power=1, to_string_end=False, length_only=False): if ix == 0: prev_ht = M + p else: - prev_ht = min(data[ix-1][1], M+p) + prev_ht = min(data[ix - 1][1], M + p) # if necessary split the step. Then reflect the wet part. if data[ix][1] - data[ix][2] > prev_ht: - ws = ws.split_step(j, 1-(prev_ht-data[ix][1])/(-data[ix][2])) - ws = ws.reflect_step(j+1, i) + ws = ws.split_step(j, 1 - (prev_ht - data[ix][1]) / (-data[ix][2])) + ws = ws.reflect_step(j + 1, i) else: ws = ws.reflect_step(j, i) ix -= 1 @@ -685,6 +684,7 @@ class CrystalOfProjectedLevelZeroLSPaths(CrystalOfLSPaths): (Lambda[0] - Lambda[1],), (Lambda[1] - 2*Lambda[2],)] """ + @staticmethod def __classcall_private__(cls, weight): """ @@ -716,8 +716,7 @@ def __classcall_private__(cls, weight): raise ValueError("the weight should be in the non-extended weight lattice") La = weight.parent().basis() weight = weight - weight.level() * La[0] / La[0].level() - return super().__classcall__(cls, weight, - starting_weight_parent=weight.parent()) + return super().__classcall__(cls, weight, starting_weight_parent=weight.parent()) @cached_method def maximal_vector(self): @@ -816,8 +815,9 @@ def one_dimensional_configuration_sum(self, q=None, group_components=True): """ if q is None: from sage.rings.rational_field import QQ + q = QQ['q'].gens()[0] - #P0 = self.weight_lattice_realization().classical() + # P0 = self.weight_lattice_realization().classical() P0 = RootSystem(self.cartan_type().classical()).weight_lattice() R = P0.base_ring() B = P0.algebra(q.parent()) @@ -831,8 +831,8 @@ def weight(x): if group_components: G = self.digraph(index_set=self.cartan_type().classical().index_set()) C = G.connected_components(sort=False) - return sum(q**(c[0].energy_function()) * B.sum(B(weight(b)) for b in c) for c in C) - return B.sum(q**(b.energy_function()) * B(weight(b)) for b in self) + return sum(q ** (c[0].energy_function()) * B.sum(B(weight(b)) for b in c) for c in C) + return B.sum(q ** (b.energy_function()) * B(weight(b)) for b in self) def is_perfect(self, level=1) -> bool: r""" @@ -909,7 +909,8 @@ def is_perfect(self, level=1) -> bool: WLR = self.weight_lattice_realization() R = WLR.base_ring() from sage.combinat.integer_vector import integer_vectors_nk_fast_iter - for n in range(1, level+1): + + for n in range(1, level + 1): for c in integer_vectors_nk_fast_iter(n, rank): w = WLR.element_class(WLR, {i: R(c[i]) for i in I if c[i]}) if w.level() == level: @@ -920,6 +921,7 @@ class Element(CrystalOfLSPaths.Element): """ Element of a crystal of projected level zero LS paths. """ + @cached_in_parent_method def scalar_factors(self): r""" @@ -1171,26 +1173,24 @@ def dualize(x): def stretch_short_root(a): # stretches roots by translation factor if ct.dual().type() == 'BC': - return ct.c()[a.to_simple_root()]*a - return ct.dual().c()[a.to_simple_root()]*a - #if a.is_short_root(): + return ct.c()[a.to_simple_root()] * a + return ct.dual().c()[a.to_simple_root()] * a + # if a.is_short_root(): # if cartan_dual.type() == 'G': # return 3*a # else: # return 2*a - #return a + # return a - paths = [G.shortest_path(L[i+1],L[i]) for i in range(len(L)-1)] - paths_labels = [[G.edge_label(p[i],p[i+1]) for i in range(len(p)-1) if p[i].length()+1 != p[i+1].length()] for p in paths] + paths = [G.shortest_path(L[i + 1], L[i]) for i in range(len(L) - 1)] + paths_labels = [[G.edge_label(p[i], p[i + 1]) for i in range(len(p) - 1) if p[i].length() + 1 != p[i + 1].length()] for p in paths] scalars = self.scalar_factors() if untwisted: - s = sum((1 - scalars[i]) * c_weight.scalar(Qv.sum(root.associated_coroot() for root in label)) - for i, label in enumerate(paths_labels)) + s = sum((1 - scalars[i]) * c_weight.scalar(Qv.sum(root.associated_coroot() for root in label)) for i, label in enumerate(paths_labels)) if ct.type() == 'BC': return 2 * s return s - s = sum((1 - scalars[i]) * c_weight.scalar(dualize(Qd.sum(stretch_short_root(root) for root in label))) - for i, label in enumerate(paths_labels)) + s = sum((1 - scalars[i]) * c_weight.scalar(dualize(Qd.sum(stretch_short_root(root) for root in label))) for i, label in enumerate(paths_labels)) if ct.dual().type() == 'BC': return s / 2 return s @@ -1215,6 +1215,7 @@ class InfinityCrystalOfLSPaths(UniqueRepresentation, Parent): - [LZ2011]_ """ + @staticmethod def __classcall_private__(cls, cartan_type): """ @@ -1242,8 +1243,7 @@ def __init__(self, cartan_type): sage: B = crystals.infinity.LSPaths(['B',3]) sage: TestSuite(B).run() # long time """ - Parent.__init__(self, category=(HighestWeightCrystals(), - InfiniteEnumeratedSets())) + Parent.__init__(self, category=(HighestWeightCrystals(), InfiniteEnumeratedSets())) self._cartan_type = cartan_type self.module_generators = (self.module_generator(),) @@ -1342,8 +1342,7 @@ def e(self, i, power=1, length_only=False): sage: len(B.subcrystal(max_depth=7)) 116 """ - ret = super().e(i, power=power, - length_only=length_only) + ret = super().e(i, power=power, length_only=length_only) if ret is None: return None if length_only: diff --git a/src/sage/combinat/crystals/monomial_crystals.py b/src/sage/combinat/crystals/monomial_crystals.py index 25ccda603e9..2b5016d57cb 100644 --- a/src/sage/combinat/crystals/monomial_crystals.py +++ b/src/sage/combinat/crystals/monomial_crystals.py @@ -177,8 +177,7 @@ def _repr_Y(self): L = sorted(self._Y.items(), key=lambda x: (x[0][0], x[0][1])) exp = lambda e: "^{}".format(e) if e != 1 else "" - return ' '.join("Y({},{})".format(mon[0][0], mon[0][1]) + exp(mon[1]) - for mon in L) + return ' '.join("Y({},{})".format(mon[0][0], mon[0][1]) + exp(mon[1]) for mon in L) def _repr_A(self): r""" @@ -192,7 +191,7 @@ def _repr_A(self): 'A(1,1)^-1 A(2,0)^-1 A(4,0)^-1' """ try: - Y = {(i,0): c for i,c in self.parent().hw} + Y = {(i, 0): c for i, c in self.parent().hw} except Exception: Y = {} @@ -201,15 +200,13 @@ def _repr_A(self): L = sorted(Y.items(), key=lambda x: (x[0][0], x[0][1])) exp = lambda e: "^{}".format(e) if e != 1 else "" - ret = ' '.join("Y({},{})".format(mon[0][0], mon[0][1]) + exp(mon[1]) - for mon in L) + ret = ' '.join("Y({},{})".format(mon[0][0], mon[0][1]) + exp(mon[1]) for mon in L) if not self._A: return ret if Y: ret += ' ' L = sorted(self._A.items(), key=lambda x: (x[0][0], x[0][1])) - return ret + ' '.join("A({},{})".format(mon[0][0], mon[0][1]) + exp(mon[1]) - for mon in L) + return ret + ' '.join("A({},{})".format(mon[0][0], mon[0][1]) + exp(mon[1]) for mon in L) def __hash__(self): r""" @@ -298,13 +295,13 @@ def _latex_Y(self): if not self._Y: return "\\boldsymbol{1}" - L = sorted(self._Y.items(), key=lambda x:(x[0][0],x[0][1])) + L = sorted(self._Y.items(), key=lambda x: (x[0][0], x[0][1])) return_str = '' for x in L: if x[1] != 1: - return_str += "Y_{%s,%s}" % (x[0][0],x[0][1]) + "^{%s} " % x[1] + return_str += "Y_{%s,%s}" % (x[0][0], x[0][1]) + "^{%s} " % x[1] else: - return_str += "Y_{%s,%s} " % (x[0][0],x[0][1]) + return_str += "Y_{%s,%s} " % (x[0][0], x[0][1]) return return_str def _latex_A(self): @@ -319,26 +316,26 @@ def _latex_A(self): 'A_{2,0}^{-1} A_{3,1}^{-1} A_{4,0}^{-1} ' """ try: - Y = {(i,0): c for i,c in self.parent().hw} + Y = {(i, 0): c for i, c in self.parent().hw} except Exception: Y = {} if not Y and not self._A: return "\\boldsymbol{1}" - L = sorted(Y.items(), key=lambda x:(x[0][0],x[0][1])) + L = sorted(Y.items(), key=lambda x: (x[0][0], x[0][1])) return_str = '' for x in L: if x[1] != 1: - return_str += "Y_{%s,%s}" % (x[0][0],x[0][1]) + "^{%s} " % x[1] + return_str += "Y_{%s,%s}" % (x[0][0], x[0][1]) + "^{%s} " % x[1] else: - return_str += "Y_{%s,%s} " % (x[0][0],x[0][1]) - L = sorted(self._A.items(), key=lambda x:(x[0][0],x[0][1])) + return_str += "Y_{%s,%s} " % (x[0][0], x[0][1]) + L = sorted(self._A.items(), key=lambda x: (x[0][0], x[0][1])) for x in L: if x[1] != 1: - return_str += "A_{%s,%s}" % (x[0][0],x[0][1]) + "^{%s} " % x[1] + return_str += "A_{%s,%s}" % (x[0][0], x[0][1]) + "^{%s} " % x[1] else: - return_str += "A_{%s,%s} " % (x[0][0],x[0][1]) + return_str += "A_{%s,%s} " % (x[0][0], x[0][1]) return return_str def _classical_weight(self): @@ -360,7 +357,7 @@ def _classical_weight(self): """ P = self.parent().weight_lattice_realization() La = P.fundamental_weights() - return P(sum(v*La[k[0]] for k,v in self._Y.items())) + return P(sum(v * La[k[0]] for k, v in self._Y.items())) def weight_in_root_lattice(self): r""" @@ -386,7 +383,7 @@ def weight_in_root_lattice(self): """ Q = RootSystem(self.parent().cartan_type()).root_lattice() al = Q.simple_roots() - return Q.sum(e*al[k[0]] for k,e in self._A.items()) + return Q.sum(e * al[k[0]] for k, e in self._A.items()) def weight(self): r""" @@ -462,9 +459,8 @@ def phi(self, i): for a in range(K): if (i, a) not in d: d[(i, a)] = 0 - S = sorted((x for x in d.items() if x[0][0] == i), - key=lambda x: x[0][1]) - return max(sum(S[k][1] for k in range(s)) for s in range(1, len(S)+1)) + S = sorted((x for x in d.items() if x[0][0] == i), key=lambda x: x[0][1]) + return max(sum(S[k][1] for k in range(s)) for s in range(1, len(S) + 1)) def _ke(self, i): r""" @@ -483,7 +479,7 @@ def _ke(self, i): """ h = self.parent().weight_lattice_realization().simple_coroots() phi = self.phi(i) - if phi == self._classical_weight().scalar(h[i]): # self.epsilon(i) == 0 + if phi == self._classical_weight().scalar(h[i]): # self.epsilon(i) == 0 return Infinity d = copy(self._Y) @@ -493,8 +489,7 @@ def _ke(self, i): d[(i, a)] = 0 total = ZZ.zero() L = [] - S = sorted((x for x in d.items() if x[0][0] == i), - key=lambda x: x[0][1]) + S = sorted((x for x in d.items() if x[0][0] == i), key=lambda x: x[0][1]) for var, exp in S: total += exp if total == phi: @@ -525,8 +520,7 @@ def _kf(self, i): for a in range(K): if (i, a) not in d: d[(i, a)] = 0 - S = sorted((x for x in d.items() if x[0][0] == i), - key=lambda x: x[0][1]) + S = sorted((x for x in d.items() if x[0][0] == i), key=lambda x: x[0][1]) sum = 0 phi = self.phi(i) for var, exp in S: @@ -583,31 +577,31 @@ def e(self, i): newdict = copy(self._Y) ke = self._ke(i) - Aik = {(i, ke): 1, (i, ke+1): 1} + Aik = {(i, ke): 1, (i, ke + 1): 1} ct = self.parent().cartan_type() cm = ct.cartan_matrix() shift = 0 if self.parent().cartan_type().is_finite(): shift = 1 - for j_index,j in enumerate(self.parent().index_set()): + for j_index, j in enumerate(self.parent().index_set()): if i == j: continue - c = self.parent()._c[j_index,i-shift] - if cm[j_index,i-shift] != 0: - Aik[(j, ke+c)] = cm[j_index,i-shift] + c = self.parent()._c[j_index, i - shift] + if cm[j_index, i - shift] != 0: + Aik[(j, ke + c)] = cm[j_index, i - shift] # Multiply by Aik - for key,value in Aik.items(): + for key, value in Aik.items(): if key in newdict: - if newdict[key] == -value: # The result would be a 0 exponent + if newdict[key] == -value: # The result would be a 0 exponent del newdict[key] else: newdict[key] += value else: newdict[key] = value A = copy(self._A) - A[(i,ke)] = A.get((i,ke),0) + 1 - if not A[(i,ke)]: - del A[(i,ke)] + A[(i, ke)] = A.get((i, ke), 0) + 1 + if not A[(i, ke)]: + del A[(i, ke)] return self.__class__(self.parent(), newdict, A) def f(self, i): @@ -632,31 +626,31 @@ def f(self, i): raise ValueError("i must be an element of the index set") newdict = copy(self._Y) kf = self._kf(i) - Aik = {(i, kf): -1, (i, kf+1): -1} + Aik = {(i, kf): -1, (i, kf + 1): -1} ct = self.parent().cartan_type() cm = ct.cartan_matrix() shift = 0 if ct.is_finite(): shift = 1 - for j_index,j in enumerate(self.parent().index_set()): + for j_index, j in enumerate(self.parent().index_set()): if i == j: continue - c = self.parent()._c[j_index,i-shift] - if cm[j_index,i-shift] != 0: - Aik[(j, kf+c)] = -cm[j_index,i-shift] + c = self.parent()._c[j_index, i - shift] + if cm[j_index, i - shift] != 0: + Aik[(j, kf + c)] = -cm[j_index, i - shift] # Multiply by Aik - for key,value in Aik.items(): + for key, value in Aik.items(): if key in newdict: - if newdict[key] == -value: # The result would be a 0 exponent + if newdict[key] == -value: # The result would be a 0 exponent del newdict[key] else: newdict[key] += value else: newdict[key] = value A = copy(self._A) - A[(i,kf)] = A.get((i,kf),0) - 1 - if not A[(i,kf)]: - del A[(i,kf)] + A[(i, kf)] = A.get((i, kf), 0) - 1 + if not A[(i, kf)]: + del A[(i, kf)] return self.__class__(self.parent(), newdict, A) @@ -756,6 +750,7 @@ class InfinityCrystalOfNakajimaMonomials(UniqueRepresentation, Parent): sage: BG.is_isomorphic(MG,edge_labels=True) # long time True """ + @staticmethod def _normalize_c(c, n): """ @@ -806,11 +801,11 @@ def _normalize_c(c, n): MS = MatrixSpace(ZZ, n, n) c = MS(c) c.set_immutable() - if any(c[i,i] != 0 for i in range(n)): + if any(c[i, i] != 0 for i in range(n)): raise ValueError("the c matrix must have 0s on the diagonal") - if any(c[i,j] + c[j,i] != 1 for i in range(n) for j in range(i)): + if any(c[i, j] + c[j, i] != 1 for i in range(n) for j in range(i)): raise ValueError("transpose entries do not sum to 1") - if any(c[i,j] < 0 or c[j,i] < 0 for i in range(n) for j in range(i)): + if any(c[i, j] < 0 or c[j, i] < 0 for i in range(n) for j in range(i)): raise ValueError("the c matrix must have nonnegative entries") return c @@ -885,7 +880,7 @@ def _element_constructor_(self, Y=None, A=None): if Y is None: return self.module_generators[0] # This is a crude way to determine the A, but it works - hw,path = self.element_class(self, Y, {}).to_highest_weight() + hw, path = self.element_class(self, Y, {}).to_highest_weight() hw._A = {} return hw.f_string(reversed(path)) if Y is None or Y == 0: @@ -898,15 +893,15 @@ def _element_constructor_(self, Y=None, A=None): if ct.is_finite(): shift = 1 Y = {} - for k,v in A.items(): + for k, v in A.items(): Y[k] = Y.get(k, 0) + v - Y[(k[0],k[1]+1)] = Y.get((k[0],k[1]+1), 0) + v - for j_index,j in enumerate(I): + Y[(k[0], k[1] + 1)] = Y.get((k[0], k[1] + 1), 0) + v + for j_index, j in enumerate(I): if k[0] == j: continue - c = self._c[j_index,k[0]-shift] - if cm[j_index,k[0]-shift] != 0: - Y[(j,k[1]+c)] = Y.get((j,k[1]+c), 0) + v*cm[j_index,k[0]-shift] + c = self._c[j_index, k[0] - shift] + if cm[j_index, k[0] - shift] != 0: + Y[(j, k[1] + c)] = Y.get((j, k[1] + c), 0) + v * cm[j_index, k[0] - shift] for k in list(Y): if Y[k] == 0: del Y[k] @@ -1174,6 +1169,7 @@ class CrystalOfNakajimaMonomials(InfinityCrystalOfNakajimaMonomials): Y(1,0) Y(1,3) Y(2,0) Y(2,3)^-1, Y(1,0)^2] """ + @staticmethod def __classcall_private__(cls, cartan_type, La=None, c=None): r""" @@ -1219,7 +1215,7 @@ def __init__(self, ct, La, c): InfinityCrystalOfNakajimaMonomials.__init__(self, ct, c, cat) self._cartan_type = ct self.hw = La - gen = {(i,0): c for i,c in La} + gen = {(i, 0): c for i, c in La} self.module_generators = (self.element_class(self, gen, {}),) def _repr_(self): diff --git a/src/sage/combinat/crystals/multisegments.py b/src/sage/combinat/crystals/multisegments.py index 075eacd3b20..8daad8de39d 100644 --- a/src/sage/combinat/crystals/multisegments.py +++ b/src/sage/combinat/crystals/multisegments.py @@ -3,7 +3,7 @@ Crystal of Bernstein-Zelevinsky multisegments """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2017 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -11,7 +11,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.cachefunc import cached_method from sage.structure.parent import Parent @@ -145,7 +145,7 @@ def __init__(self, n): sage: TestSuite(B).run() """ self._cartan_type = CartanType(['A', n, 1]) - self._Zn = IntegerModRing(n+1) + self._Zn = IntegerModRing(n + 1) Parent.__init__(self, category=(HighestWeightCrystals(), InfiniteEnumeratedSets())) self.module_generators = (self.highest_weight_vector(),) @@ -200,10 +200,12 @@ def __init__(self, parent, value): sage: mg = B.highest_weight_vector() sage: TestSuite(mg).run() """ + def sort_key(x): return (-x[0], ZZ(x[1])) + ZM = parent._Zn - value = [(k, ZM(i)) for k,i in value] + value = [(k, ZM(i)) for k, i in value] ElementWrapper.__init__(self, parent, tuple(sorted(value, key=sort_key))) def _repr_(self): @@ -230,6 +232,7 @@ def seg(x): if c != 1: return "{} * ({}; {}]".format(c, m[0], m[1]) return "({}; {}]".format(m[0], m[1]) + d = {} for x in self.value: d[x] = d.get(x, 0) + 1 @@ -259,6 +262,7 @@ def seg(x): if c != 1: return "{} ({}; {}]".format(c, m[0], m[1]) return "({}; {}]".format(m[0], m[1]) + d = {} for x in self.value: d[x] = d.get(x, 0) + 1 @@ -304,15 +308,15 @@ def _sig(self, i): pos = [] block = self.value[0][0] cur = 0 - for k,j in self.value: + for k, j in self.value: if k != block: if cur != 0: pos.append((block, cur)) cur = 0 block = k - if j + 1 == i: # + or ( + if j + 1 == i: # + or ( cur += 1 - elif j == i: # - or ) + elif j == i: # - or ) cur -= 1 if cur != 0: pos.append((block, cur)) @@ -321,7 +325,7 @@ def _sig(self, i): m = None p = None ep = 0 - for k,c in pos: + for k, c in pos: old = cur cur += c if cur < 0: @@ -362,8 +366,8 @@ def e(self, i): a = M.index((m, i)) k = M[a][0] if k == 1: - return self.__class__(self.parent(), M[:a] + M[a+1:]) - return self.__class__(self.parent(), M[:a] + ((k-1,i-1),) + M[a+1:]) + return self.__class__(self.parent(), M[:a] + M[a + 1 :]) + return self.__class__(self.parent(), M[:a] + ((k - 1, i - 1),) + M[a + 1 :]) def f(self, i): r""" @@ -390,8 +394,8 @@ def f(self, i): if p is None: return self.__class__(self.parent(), ((1, i),) + M) - a = M.index((p, i-1)) - return self.__class__(self.parent(), M[:a] + ((M[a][0]+1,i),) + M[a+1:]) + a = M.index((p, i - 1)) + return self.__class__(self.parent(), M[:a] + ((M[a][0] + 1, i),) + M[a + 1 :]) def epsilon(self, i): r""" @@ -457,5 +461,4 @@ def weight(self): WLR = self.parent().weight_lattice_realization() alpha = WLR.simple_roots() n = self.parent()._cartan_type.rank() - return WLR.sum(-1*alpha[j % n] for k,i in self.value - for j in range(ZZ(i),ZZ(i)+k)) + return WLR.sum(-1 * alpha[j % n] for k, i in self.value for j in range(ZZ(i), ZZ(i) + k)) diff --git a/src/sage/combinat/crystals/mv_polytopes.py b/src/sage/combinat/crystals/mv_polytopes.py index b30572173c0..1817be7a272 100644 --- a/src/sage/combinat/crystals/mv_polytopes.py +++ b/src/sage/combinat/crystals/mv_polytopes.py @@ -7,7 +7,7 @@ - Dinakar Muthiah, Travis Scrimshaw (2015-05-11): initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2015 Dinakar Muthiah # 2015 Travis Scrimshaw # @@ -16,7 +16,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.combinat.crystals.pbw_crystal import PBWCrystalElement, PBWCrystal @@ -99,10 +99,12 @@ def _latex_(self): proj = plot_options.projection if proj(P.zero()).parent().dimension() != 2: from sage.misc.latex import latex + return latex(repr(self)) # We need this to use tikz from sage.graphs.graph_latex import setup_latex_preamble + setup_latex_preamble() pbw_data = self._pbw_datum.parent @@ -117,8 +119,7 @@ def _latex_(self): cur = proj(P.zero()) red = tuple(red) ret += str(cur) - roots = [proj(P.sum(c*al[a] for a,c in root)) - for root in pbw_data._root_list_from(red)] + roots = [proj(P.sum(c * al[a] for a, c in root)) for root in pbw_data._root_list_from(red)] datum = pbw_data.convert_to_new_long_word(self._pbw_datum, red) for i in reversed(range(len(datum.lusztig_datum))): cur -= roots[i] * datum.lusztig_datum[i] @@ -164,10 +165,9 @@ def _polytope_vertices(self, P): for red in sorted(w0.reduced_words()): cur = P.zero() red = tuple(red) - roots = [P.sum(c*al[a] for a,c in root) - for root in pbw_data._root_list_from(red)] + roots = [P.sum(c * al[a] for a, c in root) for root in pbw_data._root_list_from(red)] datum = pbw_data.convert_to_new_long_word(self._pbw_datum, red) - for i,c in enumerate(datum.lusztig_datum): + for i, c in enumerate(datum.lusztig_datum): cur = cur + roots[i] * c vertices.add(cur) return list(vertices) @@ -199,6 +199,7 @@ def polytope(self, P=None): P = self.parent().weight_lattice_realization() from sage.geometry.polyhedron.constructor import Polyhedron + return Polyhedron([v.to_vector() for v in self._polytope_vertices(P)]) def plot(self, P=None, **options): @@ -368,10 +369,7 @@ def __init__(self, cartan_type): sage: TestSuite(MV).run() """ PBWCrystal.__init__(self, cartan_type) - self._latex_options = {"projection": True, - "mark_endpoints": True, - "P": self.weight_lattice_realization(), - "circle_size": 0.1} + self._latex_options = {"projection": True, "mark_endpoints": True, "P": self.weight_lattice_realization(), "circle_size": 0.1} def _repr_(self): """ @@ -461,6 +459,7 @@ def latex_options(self): 'projection': True} """ from copy import copy + return copy(self._latex_options) Element = MVPolytope diff --git a/src/sage/combinat/crystals/pbw_crystal.py b/src/sage/combinat/crystals/pbw_crystal.py index 8b7b8a42325..3740253fbd5 100644 --- a/src/sage/combinat/crystals/pbw_crystal.py +++ b/src/sage/combinat/crystals/pbw_crystal.py @@ -89,8 +89,8 @@ def _latex_(self): lusztig_datum = list(pbw_datum.lusztig_datum) al = self.parent()._pbw_datum_parent._root_list_from(self.parent()._default_word) from sage.misc.latex import latex - ret_str = ' '.join("f_{%s}%s" % (latex(al[i]), "^{%s}" % latex(exp) if exp > 1 else "") - for i, exp in enumerate(lusztig_datum) if exp) + + ret_str = ' '.join("f_{%s}%s" % (latex(al[i]), "^{%s}" % latex(exp) if exp > 1 else "") for i, exp in enumerate(lusztig_datum) if exp) if ret_str == '': return '1' return ret_str @@ -283,7 +283,7 @@ def weight(self): """ WLR = self.parent().weight_lattice_realization() al = WLR.simple_roots() - return WLR.sum(c*al[i] for i,c in self._pbw_datum.weight()) + return WLR.sum(c * al[i] for i, c in self._pbw_datum.weight()) def star(self): r""" @@ -339,8 +339,7 @@ def star(self): sage: test_star(P, 5) """ starred_pbw_datum = self._pbw_datum.star() - return type(self)(self.parent(), starred_pbw_datum.lusztig_datum, - starred_pbw_datum.long_word) + return type(self)(self.parent(), starred_pbw_datum.lusztig_datum, starred_pbw_datum.long_word) class PBWCrystal(Parent, UniqueRepresentation): @@ -387,6 +386,7 @@ class PBWCrystal(Parent, UniqueRepresentation): sage: x.to_highest_weight()[1] [1, 2, 2, 2, 2, 2, 1, 3, 3, 3, 3, 2, 3, 2, 3, 3, 2, 3, 3, 2, 1, 3] """ + @staticmethod def __classcall__(cls, cartan_type): """ @@ -422,10 +422,8 @@ def __init__(self, cartan_type): # There must be a better way to do the following i = self._cartan_type.index_set()[0] self._default_word = self._pbw_datum_parent._long_word_begin_with(i) - zero_lusztig_datum = [0]*len(self._default_word) - self.module_generators = (self.element_class(self, - zero_lusztig_datum, - self._default_word),) + zero_lusztig_datum = [0] * len(self._default_word) + self.module_generators = (self.element_class(self, zero_lusztig_datum, self._default_word),) def _repr_(self): """ @@ -474,8 +472,7 @@ def _check_is_long_word(self, word): ValueError: not a reduced word of the long element """ W = self._pbw_datum_parent.weyl_group - if (len(word) != len(self._default_word) - or W.from_reduced_word(word) != W.long_element()): + if len(word) != len(self._default_word) or W.from_reduced_word(word) != W.long_element(): raise ValueError("not a reduced word of the long element") def set_default_long_word(self, word): diff --git a/src/sage/combinat/crystals/polyhedral_realization.py b/src/sage/combinat/crystals/polyhedral_realization.py index a5daef3b0e8..989dfd98898 100644 --- a/src/sage/combinat/crystals/polyhedral_realization.py +++ b/src/sage/combinat/crystals/polyhedral_realization.py @@ -21,8 +21,7 @@ from sage.structure.parent import Parent from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.categories.highest_weight_crystals import HighestWeightCrystals -from sage.combinat.crystals.tensor_product import TensorProductOfCrystals, \ - TensorProductOfCrystalsElement +from sage.combinat.crystals.tensor_product import TensorProductOfCrystals, TensorProductOfCrystalsElement from sage.combinat.crystals.elementary_crystals import ElementaryCrystal from sage.combinat.root_system.cartan_type import CartanType @@ -139,6 +138,7 @@ class InfinityCrystalAsPolyhedralRealization(TensorProductOfCrystals): sage: mg.f_string([2,1,2,2]) [0, -3, -1, 0, 0, 0] """ + @staticmethod def __classcall_private__(cls, cartan_type, seq=None): """ @@ -215,6 +215,7 @@ class Element(TensorProductOfCrystalsElement): r""" An element in the polyhedral realization of `B(\infty)`. """ + # For simplicity (and safety), we use the regular crystals implementation def epsilon(self, i): @@ -285,8 +286,7 @@ def e(self, i): N = len(self) + 1 pos = None for k in range(1, N): - if all(self._sig(i,k) > self._sig(i,j) for j in range(1, k)) and \ - all(self._sig(i,k) >= self._sig(i,j) for j in range(k+1, N)): + if all(self._sig(i, k) > self._sig(i, j) for j in range(1, k)) and all(self._sig(i, k) >= self._sig(i, j) for j in range(k + 1, N)): crystal = self[-k].e(i) pos = k break @@ -297,7 +297,7 @@ def e(self, i): l = list(self) l[-pos] = crystal - if pos <= 2*nf and all(b._m == 0 for b in l[-2*nf:-nf]): + if pos <= 2 * nf and all(b._m == 0 for b in l[-2 * nf : -nf]): return self.__class__(self.parent(), l[:-nf]) return self.__class__(self.parent(), l) @@ -317,8 +317,7 @@ def f(self, i): N = len(self) + 1 pos = None for k in range(1, N): - if all(self._sig(i,k) >= self._sig(i,j) for j in range(1, k)) and \ - all(self._sig(i,k) > self._sig(i,j) for j in range(k+1, N)): + if all(self._sig(i, k) >= self._sig(i, j) for j in range(1, k)) and all(self._sig(i, k) > self._sig(i, j) for j in range(k + 1, N)): crystal = self[-k].f(i) pos = k break diff --git a/src/sage/combinat/crystals/star_crystal.py b/src/sage/combinat/crystals/star_crystal.py index 4d96d908efe..3eaf9b8265a 100644 --- a/src/sage/combinat/crystals/star_crystal.py +++ b/src/sage/combinat/crystals/star_crystal.py @@ -8,7 +8,7 @@ - Travis Scrimshaw: initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2016 Ben Salisbury # Travis Scrimshaw # @@ -17,7 +17,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation @@ -102,7 +102,7 @@ def __init__(self, Binf): Parent.__init__(self, category=HighestWeightCrystals().Infinite()) self.module_generators = (self(self._Binf.module_generators[0]),) t0 = Binf.highest_weight_vector() - B = {i: ElementaryCrystal(Binf.cartan_type(),i) for i in self.index_set()} + B = {i: ElementaryCrystal(Binf.cartan_type(), i) for i in self.index_set()} self._tens = {i: B[i].tensor(Binf) for i in self.index_set()} gens = {i: self._tens[i](B[i](0), t0) for i in self.index_set()} self._embedding = {i: Binf.crystal_morphism({t0: gens[i]}) for i in self.index_set()} @@ -149,7 +149,7 @@ def e(self, i): image = P._embedding[i](self.value) if image[0].e(i)._m > 0: return None - return P(P._pullback[i]( P._tens[i](image[0].e(i),image[1]) )) + return P(P._pullback[i](P._tens[i](image[0].e(i), image[1]))) def f(self, i): r""" @@ -175,7 +175,7 @@ def f(self, i): """ P = self.parent() image = P._embedding[i](self.value) - return P(P._pullback[i]( P._tens[i](image[0].f(i),image[1]) )) + return P(P._pullback[i](P._tens[i](image[0].f(i), image[1]))) def weight(self): r""" diff --git a/src/sage/combinat/crystals/subcrystal.py b/src/sage/combinat/crystals/subcrystal.py index b9caabafd72..8c75ee7427f 100644 --- a/src/sage/combinat/crystals/subcrystal.py +++ b/src/sage/combinat/crystals/subcrystal.py @@ -9,7 +9,7 @@ - Travis Scrimshaw (2013-10-16): Initial implementation """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2013 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) @@ -22,7 +22,7 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#**************************************************************************** +# **************************************************************************** import collections.abc @@ -114,10 +114,9 @@ class Subcrystal(UniqueRepresentation, Parent): sage: S.category() Category of finite super crystals """ + @staticmethod - def __classcall_private__(cls, ambient, contained=None, generators=None, - virtualization=None, scaling_factors=None, - cartan_type=None, index_set=None, category=None): + def __classcall_private__(cls, ambient, contained=None, generators=None, virtualization=None, scaling_factors=None, cartan_type=None, index_set=None, category=None): """ Normalize arguments to ensure a (relatively) unique representation. @@ -131,7 +130,7 @@ def __classcall_private__(cls, ambient, contained=None, generators=None, """ if isinstance(contained, (collections.abc.Sequence, collections.abc.Set)): contained = frozenset(contained) - #elif contained in Sets(): + # elif contained in Sets(): if cartan_type is None: cartan_type = ambient.cartan_type() @@ -150,23 +149,19 @@ def __classcall_private__(cls, ambient, contained=None, generators=None, if virtualization is not None: if scaling_factors is None: - scaling_factors = {i:1 for i in index_set} + scaling_factors = {i: 1 for i in index_set} from sage.combinat.crystals.virtual_crystal import VirtualCrystal - return VirtualCrystal(ambient, virtualization, scaling_factors, contained, - generators, cartan_type, index_set, category) + + return VirtualCrystal(ambient, virtualization, scaling_factors, contained, generators, cartan_type, index_set, category) if scaling_factors is not None: # virtualization must be None - virtualization = {i:(i,) for i in index_set} + virtualization = {i: (i,) for i in index_set} from sage.combinat.crystals.virtual_crystal import VirtualCrystal - return VirtualCrystal(ambient, virtualization, scaling_factors, contained, - generators, cartan_type, index_set, category) + + return VirtualCrystal(ambient, virtualization, scaling_factors, contained, generators, cartan_type, index_set, category) # We need to give these as optional arguments so it unpickles correctly - return super().__classcall__(cls, ambient, contained, - tuple(generators), - cartan_type=cartan_type, - index_set=tuple(index_set), - category=category) + return super().__classcall__(cls, ambient, contained, tuple(generators), cartan_type=cartan_type, index_set=tuple(index_set), category=category) def __init__(self, ambient, contained, generators, cartan_type, index_set, category): """ @@ -180,12 +175,11 @@ def __init__(self, ambient, contained, generators, cartan_type, index_set, categ """ self._ambient = ambient self._contained = contained - self._cardinality = None # ``None`` means currently unknown + self._cardinality = None # ``None`` means currently unknown self._cartan_type = cartan_type self._index_set = tuple(index_set) Parent.__init__(self, category=category) - self.module_generators = tuple(self.element_class(self, g) for g in generators - if self._containing(g)) + self.module_generators = tuple(self.element_class(self, g) for g in generators if self._containing(g)) if isinstance(contained, frozenset): self._cardinality = Integer(len(contained)) @@ -221,7 +215,7 @@ def _containing(self): return lambda x: True if isinstance(self._contained, frozenset): return self._contained.__contains__ - return self._contained # Otherwise it should be a function + return self._contained # Otherwise it should be a function def __contains__(self, x): """ @@ -252,8 +246,8 @@ def __contains__(self, x): # TODO: make this work for infinite crystals import warnings - warnings.warn("Testing containment in an infinite crystal" - " defaults to returning True") + + warnings.warn("Testing containment in an infinite crystal" " defaults to returning True") return True def cardinality(self): diff --git a/src/sage/combinat/crystals/tensor_product.py b/src/sage/combinat/crystals/tensor_product.py index c96249b9e55..055b0dccb0f 100644 --- a/src/sage/combinat/crystals/tensor_product.py +++ b/src/sage/combinat/crystals/tensor_product.py @@ -15,7 +15,7 @@ the regularity - Travis Scrimshaw (2020): added queer crystal """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2007 Anne Schilling # Nicolas Thiery # 2020 Travis Scrimshaw @@ -31,7 +31,7 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#**************************************************************************** +# **************************************************************************** import operator from sage.misc.cachefunc import cached_method @@ -47,9 +47,7 @@ from sage.combinat.partition import _Partitions from .letters import CrystalOfLetters from .spins import CrystalOfSpins, CrystalOfSpinsMinus, CrystalOfSpinsPlus -from sage.combinat.crystals.tensor_product_element import (TensorProductOfCrystalsElement, - TensorProductOfRegularCrystalsElement, CrystalOfTableauxElement, - TensorProductOfSuperCrystalsElement, TensorProductOfQueerSuperCrystalsElement) +from sage.combinat.crystals.tensor_product_element import TensorProductOfCrystalsElement, TensorProductOfRegularCrystalsElement, CrystalOfTableauxElement, TensorProductOfSuperCrystalsElement, TensorProductOfQueerSuperCrystalsElement from sage.misc.flatten import flatten from sage.structure.element import get_coercion_model from sage.rings.semirings.non_negative_integer_semiring import NN @@ -60,6 +58,7 @@ # Support classes ############################################################################## + class CrystalOfWords(UniqueRepresentation, Parent): """ Auxiliary class to provide a call method to create tensor product elements. @@ -321,6 +320,7 @@ class TensorProductOfCrystals(CrystalOfWords): [2, 1] sage: crystals.TensorProduct.options._reset() """ + @staticmethod def __classcall_private__(cls, *crystals, **options): """ @@ -398,8 +398,7 @@ def __classcall_private__(cls, *crystals, **options): return TensorProductOfCrystalsWithGenerators(crystals, generators, cartan_type) # Flatten out tensor products - tp = sum([B.crystals if isinstance(B, FullTensorProductOfCrystals) else (B,) - for B in crystals], ()) + tp = sum([B.crystals if isinstance(B, FullTensorProductOfCrystals) else (B,) for B in crystals], ()) if all(c in RegularCrystals() for c in crystals): return FullTensorProductOfRegularCrystals(tp, cartan_type=cartan_type) @@ -445,14 +444,10 @@ class options(GlobalOptions): True sage: crystals.TensorProduct.options._reset() """ + NAME = 'TensorProductOfCrystals' module = 'sage.combinat.crystals' - convention = dict(default='antiKashiwara', - description='Sets the convention used for displaying/inputting tensor product of crystals', - values=dict(antiKashiwara='use the anti-Kashiwara convention', - Kashiwara='use the Kashiwara convention'), - alias=dict(anti='antiKashiwara', opposite='antiKashiwara'), - case_sensitive=False) + convention = dict(default='antiKashiwara', description='Sets the convention used for displaying/inputting tensor product of crystals', values=dict(antiKashiwara='use the anti-Kashiwara convention', Kashiwara='use the Kashiwara convention'), alias=dict(anti='antiKashiwara', opposite='antiKashiwara'), case_sensitive=False) def _element_constructor_(self, *crystalElements): """ @@ -618,14 +613,14 @@ def weight_lattice_realization(self): Ambient space of the Root system of type ['A', 4] """ cm = get_coercion_model() - return cm.common_parent(*[crystal.weight_lattice_realization() - for crystal in self.crystals]) + return cm.common_parent(*[crystal.weight_lattice_realization() for crystal in self.crystals]) class FullTensorProductOfRegularCrystals(FullTensorProductOfCrystals): """ Full tensor product of regular crystals. """ + class Element(TensorProductOfRegularCrystalsElement): pass @@ -634,6 +629,7 @@ class TensorProductOfRegularCrystalsWithGenerators(TensorProductOfCrystalsWithGe """ Tensor product of regular crystals with a generating set. """ + class Element(TensorProductOfRegularCrystalsElement): pass @@ -649,6 +645,7 @@ class FullTensorProductOfSuperCrystals(FullTensorProductOfCrystals): sage: T.cardinality() 64 """ + class Element(TensorProductOfSuperCrystalsElement): pass @@ -657,6 +654,7 @@ class QueerSuperCrystalsMixin: """ Mixin class with methods for a finite queer supercrystal. """ + @cached_method def index_set(self): """ @@ -670,7 +668,7 @@ def index_set(self): (-4, -3, -2, -1, 1, 2) """ n = self.cartan_type().n - return tuple(range(-2*n, 0)) + tuple(range(1, n+1)) + return tuple(range(-2 * n, 0)) + tuple(range(1, n + 1)) @cached_method def _long_element(self): @@ -688,14 +686,16 @@ def _long_element(self): (3, 2, 1, 3, 2, 3) """ from sage.combinat.permutation import Permutations + n = self.cartan_type().n - return tuple(Permutations(n+1).long_element().reduced_word()) + return tuple(Permutations(n + 1).long_element().reduced_word()) class FullTensorProductOfQueerSuperCrystals(FullTensorProductOfCrystals, QueerSuperCrystalsMixin): r""" Tensor product of queer super crystals. """ + class Element(TensorProductOfQueerSuperCrystalsElement): pass @@ -703,6 +703,7 @@ class Element(TensorProductOfQueerSuperCrystalsElement): ######################################################### ## Crystal of tableaux + class CrystalOfTableaux(CrystalOfWords): r""" A class for crystals of tableaux with integer valued shapes. @@ -915,9 +916,10 @@ def __classcall_private__(cls, cartan_type, shapes=None, shape=None): shape = shapes shape = _Partitions(shape) from sage.combinat.crystals.bkk_crystals import CrystalOfBKKTableaux + return CrystalOfBKKTableaux(cartan_type, shape=shape) if cartan_type.letter == 'Q': - if any(shape[i] == shape[i+1] for i in range(len(shape)-1)): + if any(shape[i] == shape[i + 1] for i in range(len(shape) - 1)): raise ValueError("not a strict partition") shape = _Partitions(shape) return CrystalOfQueerTableaux(cartan_type, shape=shape) @@ -933,13 +935,13 @@ def __classcall_private__(cls, cartan_type, shapes=None, shape=None): n1 = n if not all(i == 0 for shape in shapes for i in shape[n1:]): raise ValueError("shapes should all have length at most equal to the rank or the rank + 1 in type A") - spin_shapes = tuple((tuple(shape) + (0,)*(n1-len(shape)))[:n1] for shape in shapes) + spin_shapes = tuple((tuple(shape) + (0,) * (n1 - len(shape)))[:n1] for shape in shapes) try: shapes = tuple(tuple(trunc(i) for i in shape) for shape in spin_shapes) except Exception: raise ValueError("shapes should all be partitions or half-integer partitions") if spin_shapes == shapes: - shapes = tuple(_Partitions(shape) if shape[n1-1] in NN else shape for shape in shapes) + shapes = tuple(_Partitions(shape) if shape[n1 - 1] in NN else shape for shape in shapes) return super().__classcall__(cls, cartan_type, shapes) # Handle the construction of a crystals of spin tableaux @@ -949,7 +951,7 @@ def __classcall_private__(cls, cartan_type, shapes=None, shape=None): # minus spins if any(len(sh) != n for sh in shapes): raise ValueError("the length of all half-integer partition shapes should be the rank") - if any(2*i % 2 != 1 for shape in spin_shapes for i in shape): + if any(2 * i % 2 != 1 for shape in spin_shapes for i in shape): raise ValueError("shapes should be either all partitions or all half-integer partitions") if any(any(i < j for i, j in zip(shape, shape[1:-1] + (abs(shape[-1]),))) for shape in spin_shapes): raise ValueError("entries of each shape must be weakly decreasing") @@ -966,8 +968,7 @@ def __classcall_private__(cls, cartan_type, shapes=None, shape=None): S = CrystalOfSpins(cartan_type) B = CrystalOfTableaux(cartan_type, shapes=shapes) T = TensorProductOfCrystals(S, B, generators=[[S.module_generators[0], x] for x in B.module_generators]) - T.rename("The crystal of tableaux of type %s and shape(s) %s" % - (cartan_type, [list(shape) for shape in spin_shapes])) + T.rename("The crystal of tableaux of type %s and shape(s) %s" % (cartan_type, [list(shape) for shape in spin_shapes])) T.shapes = spin_shapes return T @@ -992,10 +993,8 @@ def __init__(self, cartan_type, shapes): Parent.__init__(self, category=ClassicalCrystals()) self.letters = CrystalOfLetters(cartan_type) self.shapes = shapes - self.module_generators = tuple(self.module_generator(la) - for la in shapes) - self.rename("The crystal of tableaux of type %s and shape(s) %s" - % (cartan_type, [list(shape) for shape in shapes])) + self.module_generators = tuple(self.module_generator(la) for la in shapes) + self.rename("The crystal of tableaux of type %s and shape(s) %s" % (cartan_type, [list(shape) for shape in shapes])) def cartan_type(self): """ @@ -1033,14 +1032,14 @@ def module_generator(self, shape): 294 """ type = self.cartan_type() - if type[0] == 'D' and len(shape) == type[1] and shape[type[1]-1] < 0: + if type[0] == 'D' and len(shape) == type[1] and shape[type[1] - 1] < 0: invert = True - shape = shape[:-1] + (-shape[type[1]-1],) + shape = shape[:-1] + (-shape[type[1] - 1],) else: invert = False p = _Partitions(shape).conjugate() # The column canonical tableau, read by columns - module_generator = flatten([[val-i for i in range(val)] for val in p]) + module_generator = flatten([[val - i for i in range(val)] for val in p]) if invert: module_generator = [(-x if x == type[1] else x) for x in module_generator] return self(list=[self.letters(x) for x in module_generator]) @@ -1087,12 +1086,13 @@ def __init__(self, cartan_type, shape): """ from sage.categories.regular_supercrystals import RegularSuperCrystals from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets + Parent.__init__(self, category=(RegularSuperCrystals(), FiniteEnumeratedSets())) self.shape = shape self._cartan_type = cartan_type self.letters = CrystalOfLetters(cartan_type) n = cartan_type.rank() + 1 - data = sum(([self.letters(n-i)] * row_len for i,row_len in enumerate(shape)), []) + data = sum(([self.letters(n - i)] * row_len for i, row_len in enumerate(shape)), []) mg = self.element_class(self, list=data) self.module_generators = (mg,) @@ -1134,8 +1134,8 @@ def _ascii_art_(self): 1 """ from sage.typeset.ascii_art import AsciiArt - ret = [" "*(3*i) + "".join("%3s" % str(x) for x in reversed(row)) - for i, row in enumerate(self.rows())] + + ret = [" " * (3 * i) + "".join("%3s" % str(x) for x in reversed(row)) for i, row in enumerate(self.rows())] return AsciiArt(ret) def _latex_(self): @@ -1156,8 +1156,8 @@ def _latex_(self): } """ from sage.combinat.output import tex_from_array - return tex_from_array([[None]*i + list(reversed(row)) - for i, row in enumerate(self.rows())]) + + return tex_from_array([[None] * i + list(reversed(row)) for i, row in enumerate(self.rows())]) def rows(self): """ @@ -1173,6 +1173,6 @@ def rows(self): ret = [] pos = 0 for l in self.parent().shape: - ret.append(self[pos:pos+l]) + ret.append(self[pos : pos + l]) pos += l return ret diff --git a/src/sage/combinat/crystals/virtual_crystal.py b/src/sage/combinat/crystals/virtual_crystal.py index e1e25aecbcf..822b72f0ac2 100644 --- a/src/sage/combinat/crystals/virtual_crystal.py +++ b/src/sage/combinat/crystals/virtual_crystal.py @@ -10,7 +10,7 @@ - Travis Scrimshaw (2013-10-16): initial implementation """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2013 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) @@ -23,7 +23,7 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#**************************************************************************** +# **************************************************************************** from sage.categories.crystals import Crystals from sage.categories.finite_crystals import FiniteCrystals from sage.combinat.root_system.cartan_type import CartanType @@ -152,10 +152,9 @@ class VirtualCrystal(Subcrystal): - [OSS03]_ - [OSS2003]_ """ + @staticmethod - def __classcall_private__(cls, ambient, virtualization, scaling_factors, - contained=None, generators=None, - cartan_type=None, index_set=None, category=None): + def __classcall_private__(cls, ambient, virtualization, scaling_factors, contained=None, generators=None, cartan_type=None, index_set=None, category=None): """ Normalize arguments to ensure a unique representation. @@ -195,13 +194,9 @@ def __classcall_private__(cls, ambient, virtualization, scaling_factors, if ambient in FiniteCrystals() or isinstance(contained, frozenset): category = category.Finite() - return super().__classcall__(cls, ambient, virtualization, - scaling_factors, contained, - tuple(generators), cartan_type, - tuple(index_set), category) + return super().__classcall__(cls, ambient, virtualization, scaling_factors, contained, tuple(generators), cartan_type, tuple(index_set), category) - def __init__(self, ambient, virtualization, scaling_factors, - contained, generators, cartan_type, index_set, category): + def __init__(self, ambient, virtualization, scaling_factors, contained, generators, cartan_type, index_set, category): """ Initialize ``self``. @@ -215,8 +210,7 @@ def __init__(self, ambient, virtualization, scaling_factors, """ self._virtualization = virtualization self._scaling_factors = scaling_factors - Subcrystal.__init__(self, ambient, contained, generators, - cartan_type, index_set, category) + Subcrystal.__init__(self, ambient, contained, generators, cartan_type, index_set, category) def _repr_(self): """ @@ -319,7 +313,7 @@ def e(self, i): P = self.parent() sf = P._scaling_factors[i] for j in P._virtualization[i]: - s += [j]*sf + s += [j] * sf ret = self.value.e_string(s) if ret is None: return None @@ -344,7 +338,7 @@ def f(self, i): P = self.parent() sf = P._scaling_factors[i] for j in P._virtualization[i]: - s += [j]*sf + s += [j] * sf ret = self.value.f_string(s) if ret is None: return None @@ -413,7 +407,7 @@ def weight(self): La = WLR.fundamental_weights() v = P._virtualization sf = P._scaling_factors - return WLR.sum(wt.scalar(ac[v[i][0]]) // sf[i] * La[i] - for i in self.index_set()) + return WLR.sum(wt.scalar(ac[v[i][0]]) // sf[i] * La[i] for i in self.index_set()) + # TODO: implement a devirtualization map diff --git a/src/sage/combinat/cyclic_sieving_phenomenon.py b/src/sage/combinat/cyclic_sieving_phenomenon.py index 21099f129f1..9583bd8ed62 100644 --- a/src/sage/combinat/cyclic_sieving_phenomenon.py +++ b/src/sage/combinat/cyclic_sieving_phenomenon.py @@ -13,6 +13,7 @@ - Christian Stump """ + # **************************************************************************** # Copyright (C) 2010 Christian Stump christian.stump@univie.ac.at # @@ -97,8 +98,7 @@ def CyclicSievingPolynomial(L, cyc_act=None, order=None, get_order=False): if order: if order.mod(n): - raise ValueError("order is not a multiple of the order" - " of the cyclic action") + raise ValueError("order is not a multiple of the order" " of the cyclic action") else: order = n @@ -106,11 +106,10 @@ def CyclicSievingPolynomial(L, cyc_act=None, order=None, get_order=False): if i == 0: j = sum(orbit_sizes.values()) else: - j = sum(orb for l, orb in orbit_sizes.items() - if not ZZ(i).mod(n // l)) + j = sum(orb for l, orb in orbit_sizes.items() if not ZZ(i).mod(n // l)) p += j * q**i - p = p(q**(order // n)) + p = p(q ** (order // n)) return [p, order] if get_order else p @@ -151,8 +150,7 @@ def CyclicSievingCheck(L, cyc_act, f, order=None) -> bool: sage: CyclicSievingCheck( S42, cyc_act, p ) True """ - p1, n = CyclicSievingPolynomial(L, cyc_act=cyc_act, order=order, - get_order=True) + p1, n = CyclicSievingPolynomial(L, cyc_act=cyc_act, order=order, get_order=True) R = p1.parent() q = R.gen() return p1 == R(f).mod(q**n - 1) diff --git a/src/sage/combinat/decorated_permutation.py b/src/sage/combinat/decorated_permutation.py index 01b3b112caa..a827724c5b3 100644 --- a/src/sage/combinat/decorated_permutation.py +++ b/src/sage/combinat/decorated_permutation.py @@ -5,6 +5,7 @@ - Martin Rubey (2020): Initial version """ + # **************************************************************************** # Copyright (C) 2020 Martin Rubey # @@ -31,14 +32,14 @@ from sage.structure.list_clone import ClonableArray -class DecoratedPermutation(ClonableArray, - metaclass=InheritComparisonClasscallMetaclass): +class DecoratedPermutation(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): r""" A decorated permutation. A decorated permutation is a signed permutation where all non-fixed points have positive sign. """ + @staticmethod def __classcall_private__(cls, pi): """ @@ -246,8 +247,7 @@ def cardinality(self): sage: [DecoratedPermutations(n).cardinality() for n in range(11)] [1, 2, 5, 16, 65, 326, 1957, 13700, 109601, 986410, 9864101] """ - return Integer(sum(factorial(self._n) // factorial(k) - for k in range(self._n + 1))) + return Integer(sum(factorial(self._n) // factorial(k) for k in range(self._n + 1))) def __iter__(self): r""" diff --git a/src/sage/combinat/derangements.py b/src/sage/combinat/derangements.py index d04b6dcb63a..181eba81020 100644 --- a/src/sage/combinat/derangements.py +++ b/src/sage/combinat/derangements.py @@ -131,6 +131,7 @@ class Derangements(UniqueRepresentation, Parent): sage: D2.random_element() # random [2, 3, 1, 3, 1, 2] """ + @staticmethod def __classcall_private__(cls, x): """ @@ -434,7 +435,7 @@ def cardinality(self): A = [self._set.count(i) for i in sL] R = PolynomialRing(QQ, 'x', len(A)) S = sum(R.gens()) - e = prod((S - x)**y for x, y in zip(R.gens(), A)) + e = prod((S - x) ** y for x, y in zip(R.gens(), A)) return Integer(e.coefficient(dict(zip(R.gens(), A)))) return self._count_der(len(self._set)) diff --git a/src/sage/combinat/descent_algebra.py b/src/sage/combinat/descent_algebra.py index 555dfe4095b..43dd2e56604 100644 --- a/src/sage/combinat/descent_algebra.py +++ b/src/sage/combinat/descent_algebra.py @@ -229,20 +229,13 @@ def __init__(self, alg, prefix='D'): """ self._prefix = prefix self._basis_name = "standard" - CombinatorialFreeModule.__init__(self, alg.base_ring(), - SubsetsSorted(range(1, alg._n)), - category=DescentAlgebraBases(alg), - bracket='', prefix=prefix) + CombinatorialFreeModule.__init__(self, alg.base_ring(), SubsetsSorted(range(1, alg._n)), category=DescentAlgebraBases(alg), bracket='', prefix=prefix) # Change of basis: B = alg.B() - self.module_morphism(self.to_B_basis, - codomain=B, category=self.category() - ).register_as_coercion() + self.module_morphism(self.to_B_basis, codomain=B, category=self.category()).register_as_coercion() - B.module_morphism(B.to_D_basis, - codomain=self, category=self.category() - ).register_as_coercion() + B.module_morphism(B.to_D_basis, codomain=self, category=self.category()).register_as_coercion() def _element_constructor_(self, x): """ @@ -332,8 +325,7 @@ def to_B_basis(self, S): n = self.realization_of()._n C = Compositions(n) lenS = len(S) - return B.sum_of_terms([(C.from_subset(T, n), (-1)**(lenS - len(T))) - for T in SubsetsSorted(S)]) + return B.sum_of_terms([(C.from_subset(T, n), (-1) ** (lenS - len(T))) for T in SubsetsSorted(S)]) def to_symmetric_group_algebra_on_basis(self, S): """ @@ -448,15 +440,10 @@ def __init__(self, alg, prefix='B'): """ self._prefix = prefix self._basis_name = "subset" - CombinatorialFreeModule.__init__(self, alg.base_ring(), - Compositions(alg._n), - category=DescentAlgebraBases(alg), - bracket='', prefix=prefix) + CombinatorialFreeModule.__init__(self, alg.base_ring(), Compositions(alg._n), category=DescentAlgebraBases(alg), bracket='', prefix=prefix) S = NonCommutativeSymmetricFunctions(alg.base_ring()).Complete() - self.module_morphism(self.to_nsym, - codomain=S, category=Algebras(alg.base_ring()) - ).register_as_coercion() + self.module_morphism(self.to_nsym, codomain=S, category=Algebras(alg.base_ring())).register_as_coercion() def product_on_basis(self, p, q): r""" @@ -476,6 +463,7 @@ def product_on_basis(self, p, q): def to_composition(m): return P([x for x in m.list() if x != 0]) + return self.sum_of_monomials([to_composition(mat) for mat in IM]) @cached_method @@ -681,20 +669,13 @@ def __init__(self, alg, prefix='I'): """ self._prefix = prefix self._basis_name = "idempotent" - CombinatorialFreeModule.__init__(self, alg.base_ring(), - Compositions(alg._n), - category=DescentAlgebraBases(alg), - bracket='', prefix=prefix) + CombinatorialFreeModule.__init__(self, alg.base_ring(), Compositions(alg._n), category=DescentAlgebraBases(alg), bracket='', prefix=prefix) # Change of basis: B = alg.B() - self.module_morphism(self.to_B_basis, - codomain=B, category=self.category() - ).register_as_coercion() + self.module_morphism(self.to_B_basis, codomain=B, category=self.category()).register_as_coercion() - B.module_morphism(B.to_I_basis, - codomain=self, category=self.category() - ).register_as_coercion() + B.module_morphism(B.to_I_basis, codomain=self, category=self.category()).register_as_coercion() def product_on_basis(self, p, q): r""" @@ -830,10 +811,10 @@ def idempotent(self, la): True """ from sage.combinat.permutation import Permutations + k = len(la) C = Compositions(self.realization_of()._n) - return self.sum_of_terms([(C(x), QQ((1, factorial(k)))) - for x in Permutations(la)]) + return self.sum_of_terms([(C(x), QQ((1, factorial(k)))) for x in Permutations(la)]) idempotent = I @@ -953,8 +934,7 @@ def to_symmetric_group_algebra(self): + [3, 2, 4, 1] + [4, 1, 2, 3] + [4, 1, 3, 2] + [4, 2, 3, 1] """ SGA = SymmetricGroupAlgebra(self.base_ring(), self.realization_of()._n) - return self.module_morphism(self.to_symmetric_group_algebra_on_basis, - codomain=SGA) + return self.module_morphism(self.to_symmetric_group_algebra_on_basis, codomain=SGA) def to_symmetric_group_algebra_on_basis(self, S): """ diff --git a/src/sage/combinat/designs/MOLS_handbook_data.py b/src/sage/combinat/designs/MOLS_handbook_data.py index 09d5dc71760..b95df02ff65 100644 --- a/src/sage/combinat/designs/MOLS_handbook_data.py +++ b/src/sage/combinat/designs/MOLS_handbook_data.py @@ -25,506 +25,10006 @@ _LOWER_BOUNDS: tuple[int, ...] _LOWER_BOUNDS = ( - 0,0,1,2,3,4,1,6,7,8,2,10,5,12,3,4,15,16,3,18, # 0 - 4,5,3,22,7,24,4,26,5,28,4,30,31,5,4,5,8,36,4,5, # 20 - 7,40,5,42,5,6,4,46,8,48,6,5,5,52,5,6,7,7,5,58, # 40 - 5,60,5,6,63,7,5,66,5,6,6,70,7,72,5,7,6,6,6,78, # 60 - 9,80,8,82,6,6,6,6,7,88,6,7,6,6,6,6,7,96,6,8, # 80 - 8,100,6,102,7,7,6,106,6,108,6,6,13,112,6,7,6,8,6,6, # 100 - 7,120,6,6,6,124,6,126,127,7,6,130,6,7,6,7,7,136,6,138, # 120 - 6,7,6,10,10,7,6,7,6,148,6,150,7,8,8,7,6,156,7,6, # 140 - 9,7,6,162,6,7,6,166,7,168,6,8,6,172,6,6,14,9,6,178, # 160 - 6,180,6,6,7,9,6,10,6,8,6,190,7,192,6,7,6,196,6,198, # 180 - 7,8,6,7,6,8,6,8,14,11,10,210,6,7,6,7,7,8,6,10, # 200 - 6,12,6,222,13,8,6,226,6,228,6,7,7,232,6,7,6,7,6,238, # 220 - 7,240,6,242,6,7,6,12,7,7,6,250,6,12,9,7,255,256,6,12, # 240 - 6,8,8,262,7,8,7,10,7,268,7,270,15,16,6,13,10,276,6,9, # 260 - 7,280,6,282,6,12,6,7,15,288,6,6,6,292,6,6,7,10,10,12, # 280 - 7,7,7,7,15,15,6,306,7,7,7,310,7,312,7,10,7,316,7,10, # 300 - 15,15,6,16,8,12,6,7,7,9,6,330,7,8,7,6,8,336,6,7, # 320 - 6,10,10,342,7,7,6,346,6,348,8,12,18,352,6,9,7,9,6,358, # 340 - 8,360,6,7,7,10,6,366,15,15,7,15,7,372,7,15,7,13,7,378, # 360 - 7,12,7,382,15,15,7,15,7,388,7,16,7,8,7,7,8,396,7,7, # 380 - 15,400,7,15,11,8,7,15,8,408,7,13,8,12,10,9,18,15,7,418, # 400 - 7,420,7,15,7,16,6,7,7,10,6,430,15,432,6,15,6,18,7,438, # 420 - 7,15,7,442,7,13,7,11,15,448,7,15,7,7,7,15,7,456,7,16, # 440 - 7,460,7,462,15,15,7,466,8,8,7,15,7,15,10,18,7,15,6,478, # 460 - 15,15,6,15,8,7,6,486,7,15,6,490,6,16,6,7,15,15,6,498, # 480 - 7,12,9,502,7,15,6,15,7,508,6,15,511,18,7,15,8,12,8,15, # 500 - 8,520,10,522,12,15,8,16,15,528,7,15,8,12,7,15,8,15,10,15, # 520 - 12,540,7,15,18,7,7,546,7,8,7,18,7,7,7,7,7,556,7,12, # 540 - 15,7,7,562,7,7,6,7,7,568,6,570,7,7,15,22,8,576,7,7, # 560 - 7,8,7,10,7,8,7,586,7,18,17,7,15,592,8,15,7,7,8,598, # 580 - 14,600,12,15,7,15,16,606,18,15,7,15,8,612,8,15,7,616,7,618, # 600 - 8,22,8,15,15,624,7,8,8,16,7,630,7,8,7,8,7,12,7,8, # 620 - 9,640,7,642,7,7,7,646,8,10,7,7,7,652,7,7,15,15,7,658, # 640 - 7,660,7,15,7,15,7,22,7,15,7,15,15,672,7,24,8,676,7,15, # 660 - 7,15,7,682,8,15,7,15,15,15,7,690,8,15,7,15,7,16,7,15, # 680 - 8,700,7,18,15,15,7,15,8,708,7,15,7,22,21,15,7,15,8,718, # 700 - 15,9,8,12,10,24,12,726,7,728,16,16,18,732,7,7,22,10,8,738, # 720 - 7,7,7,742,7,15,7,8,7,10,7,750,15,15,8,15,8,756,8,15, # 740 - 7,760,8,15,8,15,8,15,15,768,8,15,8,772,8,24,23,15,8,18, # 760 - 8,18,7,26,15,15,10,786,12,15,7,15,20,15,18,15,8,796,22,16, # 780 - 24,15,8,15,8,15,8,15,8,808,8,810,8,15,8,15,15,18,8,8, # 800 - 8,820,8,822,8,15,8,826,8,828,8,15,12,16,7,8,7,26,25,838, # 820 - 8,840,8,20,8,10,8,16,15,15,12,22,7,852,16,15,22,856,7,858, # 840 - 22,15,24,862,26,15,7,15,8,15,9,15,7,15,7,15,7,876,8,15, # 860 - 15,880,8,882,8,15,7,886,7,15,8,15,10,18,8,15,13,15,8,28, # 880 - 27,16,8,8,8,22,8,906,8,18,10,910,15,14,8,15,16,10,18,918, # 900 - 24,8,22,12,24,24,26,8,28,928,7,18,7,7,7,14,7,936,7,15, # 920 - 7,940,7,22,15,15,7,946,7,12,12,15,7,952,7,15,7,15,8,15, # 940 - 15,960,29,15,8,15,8,966,8,15,8,970,10,18,12,15,15,976,16,18, # 960 - 18,15,7,982,27,15,24,15,26,22,28,990,31,31,7,15,8,996,25,26, # 980 - 7,15,21,16,19,15,7,18,15,1008,13,18,8,1012,9,22,7,28,7,1018, # 1000 - 7,1020,7,30,1023,24,7,15,9,15,9,1030,7,1032,7,15,8,16,9,1038, # 1020 - 15,15,8,15,8,15,8,15,8,1048,8,1050,8,15,8,15,15,16,8,8, # 1040 - 8,1060,8,1062,8,15,8,15,10,1068,7,15,15,28,7,24,7,15,8,15, # 1060 - 12,22,8,15,8,15,8,1086,16,15,8,1090,8,1092,8,15,8,1096,8,15, # 1080 - 8,15,8,1102,15,15,8,26,8,1108,8,18,8,15,8,15,8,1116,7,15, # 1100 - 16,18,7,1122,7,15,7,22,8,1128,7,15,8,15,10,9,15,15,7,16, # 1120 - 7,8,7,15,7,15,7,30,30,15,7,1150,15,1152,7,15,8,26,12,24, # 1140 - 12,26,7,1162,16,18,18,15,15,15,22,1170,24,15,26,24,28,15,30,30, # 1160 - 8,1180,8,15,31,15,8,1186,8,28,8,15,8,1192,8,15,8,15,8,15, # 1180 - 15,1200,8,15,8,15,8,16,8,15,8,15,8,1212,8,15,18,1216,7,22, # 1200 - 7,15,8,1222,7,24,7,15,7,1228,7,1230,15,9,8,15,7,1236,7,15, # 1220 - 7,16,8,10,8,7,8,28,8,1248,8,8,7,7,7,8,8,8,7,1258, # 1240 - 7,12,23,7,15,15,9,15,9,26,9,30,30,23,8,15,9,1276,9,1278, # 1260 - 15,30,10,1282,12,15,9,24,16,1288,18,1290,8,18,22,15,24,1296,26,15, # 1280 - 28,1300,30,1302,8,15,8,1306,30,15,8,15,31,15,12,15,8,15,8,1318, # 1300 - 8,1320,8,26,8,24,7,1326,15,15,8,1330,8,30,30,15,8,15,9,30, # 1320 - 12,15,8,30,15,30,12,15,9,26,16,24,18,15,9,20,22,22,24,15, # 1340 - 26,1360,28,28,30,30,9,1366,28,1368,30,15,9,1372,30,15,31,16,8,15, # 1360 - 8,1380,8,15,8,15,8,18,8,15,8,15,15,15,8,15,8,10,9,1398, # 1380 - 10,15,8,22,8,8,8,15,10,1408,8,16,7,9,9,22,9,12,7,8, # 1400 - 9,28,7,1422,15,24,9,1426,9,1428,7,26,7,1432,9,15,7,15,7,1438, # 1420 - 15,15,7,15,9,15,9,1446,7,15,7,1450,7,1452,9,15,15,30,30,1458, # 1440 - 8,15,8,30,8,15,8,30,10,30,12,1470,22,30,16,28,18,15,8,24, # 1460 - 22,1480,24,1482,26,18,28,1486,30,1488,13,15,8,1492,30,15,8,15,30,1498, # 1480 - 30,18,9,15,31,15,9,15,9,14,9,1510,9,24,9,9,9,36,9,30, # 1500 - 30,9,9,1522,9,30,9,9,9,30,10,1530,12,9,9,30,16,30,18,18, # 1520 - 8,26,22,1542,24,8,26,20,28,1548,30,30,15,1552,8,15,30,8,8,1558, # 1540 - 30,15,30,15,8,15,30,1566,31,15,8,1570,8,15,12,15,8,18,8,1578, # 1560 - 8,15,8,1582,15,24,8,8,8,15,8,36,7,26,8,15,8,1596,8,15, # 1580 - 24,1600,8,15,8,15,8,1606,8,1608,8,15,8,1612,7,15,15,15,8,1618, # 1600 - 8,1620,7,15,7,15,7,1626,7,15,7,15,24,22,8,15,8,1636,7,15, # 1620 - 7,15,7,30,30,15,7,26,15,30,7,15,11,30,10,30,12,1656,7,30, # 1640 - 16,30,18,1662,15,30,22,1666,24,1668,26,24,28,22,30,30,19,15,7,22, # 1660 - 30,1680,9,15,30,15,30,15,9,15,30,18,30,1692,9,15,31,1696,9,1698, # 1680 - 9,15,8,15,8,15,8,15,8,1708,21,28,15,15,8,15,10,16,7,15, # 1700 - 8,1720,9,1722,9,15,7,15,26,21,8,15,8,1732,7,15,7,15,7,36, # 1720 - 9,1740,8,15,15,15,8,1746,8,15,8,16,9,1752,9,15,9,15,8,1758, # 1740 - 26,15,8,40,9,15,8,15,8,28,8,27,8,15,8,24,15,1776,9,15, # 1760 - 8,15,8,1782,8,15,8,1786,8,1788,8,15,15,15,9,15,8,15,8,15, # 1780 - 8,1800,8,15,9,15,8,30,15,26,8,1810,8,36,7,15,9,22,9,16, # 1800 - 9,15,9,1822,26,24,9,15,9,30,30,1830,9,15,9,30,9,15,9,30, # 1820 - 15,30,12,18,9,30,16,1846,18,1848,9,30,22,16,24,15,28,30,28,28, # 1840 - 30,1860,25,22,8,22,30,1866,8,18,30,1870,30,1872,8,15,30,1876,30,1878, # 1860 - 8,15,30,8,8,8,8,15,31,1888,8,30,30,15,8,15,8,30,8,15, # 1880 - 8,1900,10,30,15,15,8,1906,16,30,18,15,8,1912,22,15,24,26,26,30, # 1900 - 28,30,30,30,27,9,7,40,30,9,8,1930,30,1932,30,8,15,15,30,15, # 1920 - 30,10,8,28,30,15,8,15,8,1948,30,1950,31,15,8,15,8,18,8,15, # 1940 - 8,36,8,15,8,15,8,15,15,15,8,26,8,1972,8,24,9,15,9,1978, # 1960 - 9,15,9,15,30,30,9,1986,9,15,30,15,10,1992,30,15,30,1996,9,1998, # 1980 - 30,16,30,2002,9,9,30,22,9,40,9,2010,30,28,30,30,31,2016,8,15, # 2000 - 27,42,8,15,23,30,21,2026,8,2028,8,30,15,30,13,15,11,30,8,2038, # 2020 - 8,15,8,30,8,30,8,22,2047,15,8,15,8,2052,8,15,8,16,10,28, # 2040 - 8,15,9,2062,15,15,8,15,8,2068,8,18,8,15,9,24,8,30,30,15, # 2060 - 30,2080,8,2082,8,15,8,2086,10,2088,12,15,8,30,16,30,18,15,8,2098, # 2080 - 22,36,24,15,26,30,28,42,30,30,30,2110,15,2112,30,15,9,28,30,24, # 2100 - 30,15,10,15,30,18,30,16,15,2128,30,2130,8,26,9,15,30,2136,30,15, # 2120 - 9,2140,9,2142,31,15,9,18,9,15,9,15,9,2152,10,15,12,15,9,16, # 2140 - 15,2160,9,15,9,14,9,15,9,15,10,14,12,40,9,15,16,15,9,2178, # 2160 - 8,15,9,36,9,15,9,2186,9,15,9,23,15,15,8,15,9,2196,12,15, # 2180 - 9,30,30,2202,8,15,9,2206,15,2208,8,30,10,2212,12,15,8,30,16,30, # 2200 - 18,2220,8,30,22,24,24,16,26,30,28,30,30,30,30,15,10,2236,30,2238, # 2220 - 16,30,30,2242,30,15,8,15,30,22,30,2250,8,18,30,15,15,36,8,15, # 2240 - 30,15,30,30,30,30,9,2266,30,2268,8,15,31,2272,10,30,12,15,8,42, # 2260 - 16,2280,18,15,8,30,22,2286,24,15,26,30,28,2292,30,30,30,2296,9,30, # 2280 - 30,15,9,46,30,30,30,15,9,2308,30,2310,30,22,9,20,30,15,9,15, # 2300 - 15,15,30,22,30,15,9,30,28,16,30,15,9,2332,30,15,31,15,9,2338, # 2320 - 8,2340,8,10,9,15,8,2346,8,28,8,2350,15,12,8,15,9,2356,9,10, # 2340 - 8,15,8,16,8,9,8,10,36,22,10,2370,8,10,8,18,26,2376,8,10, # 2360 - 8,2380,8,2382,15,15,8,15,8,2388,8,15,8,2392,8,42,10,15,13,2398, # 2380 - 15,2400,8,26,8,15,9,28,7,15,7,2410,8,18,17,15,15,2416,7,40, # 2400 - 8,15,8,2422,14,24,12,15,8,15,16,15,18,15,8,15,9,2436,9,15, # 2420 - 9,2440,10,15,10,15,10,2446,15,30,30,15,9,27,9,30,9,15,9,2458, # 2440 - 10,30,12,15,15,30,16,2466,18,15,9,30,22,2472,24,15,26,2476,28,36, # 2460 - 30,30,30,15,12,30,30,15,9,30,30,46,30,15,9,15,30,30,30,28, # 2480 - 8,40,30,2502,8,15,9,22,30,15,30,30,30,30,9,15,30,30,8,15, # 2500 - 30,2520,30,30,12,24,9,30,31,30,18,2530,9,30,22,15,24,42,26,2538, # 2520 - 28,30,30,2542,30,15,9,30,30,2548,9,2550,30,30,30,15,9,2556,30,30, # 2540 - 30,30,9,28,30,15,10,16,9,23,30,15,30,30,30,30,15,15,30,2578, # 2560 - 9,28,30,30,30,30,12,12,12,30,30,2590,31,2592,8,30,22,48,24,22, # 2580 - 26,30,28,30,30,30,30,9,15,2608,30,15,9,30,30,30,30,2616,8,26, # 2600 - 30,2620,30,42,40,30,30,36,8,15,8,24,30,2632,30,15,8,30,8,16, # 2620 - 30,18,8,15,30,15,30,2646,28,15,8,15,30,15,30,15,31,2656,10,2658, # 2640 - 8,15,9,2662,9,15,9,15,7,16,9,2670,15,15,8,24,8,2676,8,15, # 2660 - 9,15,8,2682,9,15,8,2686,15,2688,8,15,10,2692,8,15,8,15,9,2698, # 2680 - 9,36,8,15,15,15,10,2706,8,15,10,2710,9,2712,8,15,10,15,10,2718, # 2700 - 31,15,9,15,9,24,10,26,10,2728,10,2730,9,15,10,15,15,15,8,15, # 2720 - 8,2740,8,15,9,15,8,40,9,2748,8,15,42,2752,9,15,8,15,9,30, # 2740 - 30,15,8,15,9,30,7,2766,15,30,10,30,12,46,8,30,16,2776,18,15, # 2760 - 9,30,22,22,24,15,26,30,28,2788,30,2790,30,15,9,30,30,2796,9,30, # 2780 - 30,2800,30,2802,9,15,30,30,30,2808,8,30,30,28,9,15,15,30,30,2818, # 2800 - 30,15,8,30,9,24,30,15,8,18,30,18,30,2832,9,15,9,2836,30,23, # 2820 - 30,15,30,2842,8,15,8,15,31,15,10,2850,8,15,9,15,8,2856,8,15, # 2840 - 8,2860,29,13,29,15,9,46,29,18,29,15,8,16,29,22,8,15,8,2878, # 2860 - 29,42,29,15,9,29,9,2886,29,26,8,48,29,15,29,15,15,2896,9,15, # 2880 - 29,15,30,2902,8,15,8,15,8,2908,10,40,31,15,9,15,8,2916,9,15, # 2900 - 8,22,21,36,9,18,9,2926,15,28,9,15,10,15,12,15,9,15,16,2938, # 2920 - 18,16,9,26,22,15,9,15,9,15,9,15,9,2952,9,15,9,2956,9,15, # 2940 - 15,15,9,2962,9,15,9,15,9,2968,9,2970,9,15,10,15,15,15,12,15, # 2960 - 9,15,10,18,9,15,9,28,9,48,8,15,15,40,9,15,9,36,9,2998, # 2980 - 9,3000,9,15,10,15,9,30,46,15,9,3010,9,30,8,15,10,30,10,3018, # 3000 - 12,15,9,3022,16,30,18,15,9,30,22,15,24,15,26,30,28,3036,30,30, # 3020 - 31,3040,9,30,30,15,9,30,30,3048,30,26,9,42,30,30,30,30,9,30, # 3040 - 30,3060,9,15,9,30,30,3066,30,15,9,36,15,30,30,15,8,26,30,3078, # 3060 - 30,15,9,3082,9,18,30,15,30,3088,30,15,9,15,10,15,30,18,9,15, # 3080 - 9,15,9,28,31,15,9,25,9,3108,8,15,9,15,8,15,8,15,9,3118, # 3100 - 15,3120,8,15,9,3124,8,52,8,15,9,30,30,15,8,15,48,3136,9,42, # 3120 - 8,30,10,30,12,15,9,30,16,46,18,22,15,30,22,15,24,15,26,30, # 3140 - 28,30,30,3162,30,15,9,3166,30,3168,9,30,30,30,30,24,23,15,30,30, # 3160 - 30,3180,10,30,30,15,10,3186,12,30,30,3190,30,30,30,30,8,30,30,30, # 3180 - 24,30,30,3202,30,30,12,24,9,3208,30,30,30,18,30,30,22,3216,24,15, # 3200 - 30,3220,28,30,30,30,30,15,30,3228,30,15,31,52,30,30,30,15,9,40, # 3220 - 30,30,30,30,9,30,30,16,15,15,10,3250,30,3252,30,15,9,3256,9,3258, # 3240 - 30,15,10,30,30,30,30,26,10,26,9,3270,30,15,30,24,30,28,10,15, # 3260 - 15,16,30,48,9,15,10,18,28,15,30,15,9,36,30,15,31,15,9,3298, # 3280 - 10,3300,10,15,10,15,10,3306,10,15,9,15,15,3312,9,15,9,30,30,3318, # 3300 - 9,40,9,3322,9,23,9,30,14,3328,12,3330,10,30,16,30,18,46,9,30, # 3320 - 22,15,24,3342,26,30,28,3346,30,30,30,15,10,30,30,13,10,30,30,3358, # 3340 - 30,3360,10,15,30,30,30,30,12,30,30,3370,10,3372,10,30,30,15,30,30, # 3360 - 30,30,9,30,30,30,9,30,30,3388,30,3390,52,30,10,30,30,42,30,24, # 3380 - 30,39,22,40,24,23,30,3406,28,30,30,30,30,3412,30,30,30,15,30,30, # 3400 - 30,30,30,15,31,24,30,30,30,30,25,46,30,3432,9,15,10,30,30,18, # 3420 - 30,15,13,30,10,30,30,15,22,3448,30,30,30,13,24,30,26,3456,30,15, # 3440 - 30,3460,30,3462,9,15,9,3466,30,3468,9,10,15,22,10,24,30,18,9,48, # 3460 - 30,3480,30,42,10,15,30,39,31,15,9,3490,9,11,10,13,10,15,12,3498, # 3480 - 9,15,10,30,30,11,10,15,9,30,10,3510,9,30,10,30,12,3516,9,30, # 3500 - 26,30,18,15,12,30,22,3526,24,3528,26,30,28,3532,30,30,30,26,10,3538, # 3520 - 30,3540,11,30,30,30,30,3546,11,15,30,52,30,30,10,30,30,3556,10,3558, # 3540 - 11,30,30,12,30,12,11,30,15,42,30,3570,11,30,30,30,30,48,10,30, # 3560 - 10,3580,30,3582,30,30,30,16,10,36,10,15,30,3592,11,15,11,18,10,58, # 3580 - 30,15,10,13,30,15,30,3606,9,15,30,22,30,3612,9,15,31,3616,9,15, # 3600 - 10,15,9,3622,10,28,11,15,9,25,11,3630,15,15,10,15,10,3636,9,15, # 3620 - 9,15,8,3642,11,15,9,15,26,40,10,15,9,15,12,15,9,25,9,3658, # 3640 - 11,15,11,15,15,15,10,18,9,15,9,3670,10,3672,10,15,9,3676,8,21, # 3660 - 15,15,10,28,27,15,10,24,9,15,10,3690,10,18,10,16,15,3696,10,26, # 3680 - 16,3700,18,15,24,15,22,15,24,3708,26,15,28,46,10,15,10,15,9,3718, # 3700 - 10,3720,10,15,11,24,9,3726,15,15,9,15,10,3732,10,15,9,36,9,3738, # 3720 - 9,15,10,18,15,39,10,15,9,22,10,30,30,26,9,15,10,30,12,15, # 3740 - 15,3760,10,52,12,15,10,3766,16,3768,18,15,9,30,22,24,58,15,26,3778, # 3760 - 28,30,30,30,30,15,10,30,30,15,10,30,30,3792,30,15,10,3796,30,30, # 3780 - 30,30,10,3802,30,15,9,46,31,30,30,36,30,15,9,30,9,30,30,15, # 3800 - 10,3820,30,3822,30,15,10,42,10,30,30,15,30,3832,30,15,10,15,10,15, # 3820 - 30,30,10,15,10,26,10,3846,30,15,9,3850,30,3852,30,15,15,15,30,16, # 3840 - 30,15,10,3862,30,15,9,15,9,52,9,48,31,15,10,30,30,3876,10,15, # 3860 - 10,3880,9,15,10,30,10,30,15,3888,10,30,16,30,18,15,9,30,22,15, # 3880 - 24,48,26,30,60,30,30,3906,30,15,9,3910,30,15,11,30,30,3916,30,3918, # 3900 - 15,15,30,3922,30,30,9,30,30,3928,9,3930,9,30,30,15,30,30,30,30, # 3920 - 9,30,30,3942,9,30,30,3946,30,30,12,30,15,58,30,30,30,30,30,36, # 3940 - 26,40,24,15,30,30,28,3966,30,48,30,28,30,36,30,24,30,40,30,30, # 3960 - 30,18,30,16,30,30,30,30,30,3988,30,22,10,24,10,30,30,28,30,30, # 3980 - 31,4000,10,4002,30,30,10,4006,30,30,30,30,9,4012,9,30,30,30,30,4018, # 4000 - 30,4020,9,26,9,24,30,4026,9,30,9,30,30,36,30,30,9,26,30,30, # 4020 - 30,30,10,20,30,18,30,30,15,4048,30,4050,18,15,9,15,28,4056,30,15, # 4040 - 26,30,30,16,31,30,10,48,27,30,9,30,10,4072,21,30,19,30,16,4078, # 4060 - 18,30,10,30,22,15,24,60,26,30,28,4090,30,4092,30,30,4095,30,30,4098, # 4080 - 9,30,30,30,30,15,9,15,30,30,30,4110,15,30,30,15,10,22,10,30, # 4100 - 30,15,30,15,11,30,9,4126,30,4128,10,30,30,4132,30,15,11,30,10,4138, # 4120 - 30,40,30,30,30,15,10,15,10,15,30,30,9,4152,11,30,9,4156,30,4158, # 4140 - 15,30,30,22,30,15,29,24,30,22,30,42,29,15,30,24,29,4176,10,15, # 4160 - 10,36,30,46,29,15,30,52,30,58,29,15,31,15,29,15,29,15,10,15, # 4180 - 12,4200,29,15,29,15,29,15,15,15,10,4210,29,15,9,15,9,4216,10,4218, # 4200 - 29,15,9,40,29,24,29,15,10,4228,29,4230,29,15,10,15,29,18,13,26, # 4220 - 15,4240,10,4242,30,15,9,30,30,15,12,15,9,4252,13,15,31,30,10,4258, # 4240 - 12,4260,10,30,16,30,18,42,9,30,22,4270,24,4272,26,30,28,30,30,30, # 4260 - 30,15,10,4282,30,15,9,30,63,4288,30,15,10,52,30,30,30,4296,9,30, # 4280 - 30,15,10,15,15,30,30,58,30,30,30,30,9,30,30,30,9,30,30,30, # 4300 - 30,30,12,30,10,30,30,4326,30,30,30,60,22,15,24,15,30,4336,28,4338, # 4320 - 30,30,30,42,30,30,30,30,30,4348,30,30,30,30,30,28,30,4356,30,30, # 4340 - 30,48,30,4362,13,18,13,30,30,16,30,15,30,4372,30,30,30,15,30,30, # 4360 - 30,30,30,15,31,30,12,40,30,15,30,4390,30,22,13,15,13,4396,30,52, # 4380 - 15,26,12,30,13,30,30,15,13,4408,30,15,30,15,10,30,30,30,30,15, # 4400 - 12,4420,30,4422,13,15,13,20,12,42,30,15,15,15,30,15,30,30,12,22, # 4420 - 30,4440,11,15,13,15,30,4446,31,15,10,4450,12,60,13,15,12,4456,13,15, # 4440 - 13,15,13,4462,15,15,11,15,10,40,12,16,13,15,13,24,13,36,13,15, # 4460 - 16,4480,10,4482,10,15,12,15,13,4488,13,15,10,4492,13,15,15,15,10,25, # 4480 - 10,15,10,15,10,15,12,4506,13,26,13,15,15,4512,10,15,10,4516,10,4518, # 4500 - 10,15,12,4522,13,24,10,15,15,15,11,22,10,15,10,15,10,15,10,15, # 4520 - 12,18,13,15,63,15,10,4546,10,4548,10,15,10,28,10,15,12,15,12,46, # 4540 - 15,4560,11,26,11,15,10,4566,10,15,12,15,12,16,13,15,31,22,11,18, # 4560 - 10,15,10,4582,10,15,10,15,12,15,13,4590,15,15,10,15,10,4596,12,15, # 4580 - 10,42,10,4602,12,15,9,16,15,15,13,15,11,15,9,15,9,18,10,30, # 4600 - 30,4620,12,15,16,36,15,15,13,30,15,30,15,40,15,30,16,4636,18,4638, # 4620 - 31,30,22,4642,24,15,26,30,28,4648,30,4650,30,15,15,30,30,4656,12,30, # 4640 - 30,58,30,4662,14,15,30,30,30,30,14,30,63,4672,12,15,14,30,30,4678, # 4660 - 30,30,30,30,14,30,30,42,15,30,30,4690,30,30,14,30,15,30,30,36, # 4680 - 35,30,30,4702,22,15,24,15,30,30,28,30,30,30,30,30,30,52,30,30, # 4700 - 30,4720,30,4722,30,30,30,30,30,4728,30,31,30,4732,30,15,36,30,12,30, # 4720 - 30,15,30,15,30,30,30,46,30,15,30,4750,30,48,30,15,30,66,30,4758, # 4740 - 30,15,30,30,30,15,13,15,31,18,30,30,11,15,10,30,10,39,30,58, # 4760 - 15,30,30,4782,30,15,12,4786,30,4788,30,15,10,4792,30,15,14,15,15,4798, # 4780 - 15,4800,30,15,10,15,30,24,30,30,10,16,30,4812,14,15,15,4816,30,60, # 4800 - 30,15,10,22,28,24,12,15,12,15,30,4830,31,26,12,15,10,23,10,15, # 4820 - 10,46,11,28,12,15,15,36,15,15,11,15,10,22,10,15,11,15,10,42, # 4840 - 11,4860,14,15,18,17,12,30,30,15,10,4870,11,30,11,15,12,4876,11,30, # 4860 - 15,16,10,30,16,30,18,26,10,4888,22,66,24,15,26,30,28,58,30,30, # 4880 - 30,28,12,4902,30,15,10,30,30,4908,30,15,15,4912,30,30,30,30,10,4918, # 4900 - 30,15,11,15,10,30,30,15,30,15,12,4930,11,4932,30,15,11,4936,30,30, # 4920 - 30,60,10,4942,15,30,30,15,30,48,30,4950,10,15,10,15,30,4956,10,15, # 4940 - 15,40,11,30,30,15,12,4966,30,4968,30,15,10,4972,30,30,30,15,12,15, # 4960 - 30,16,10,15,11,30,10,4986,30,15,10,15,30,4992,30,30,10,18,30,4998, # 4980 - 11,15,10,5002,30,18,30,15,15,5008,10,5010,11,15,10,15,30,28,30,15, # 5000 - 10,5020,10,5022,31,15,10,15,10,46,10,15,9,15,10,15,10,15,10,5038, # 5020 - 15,5040,10,15,11,15,10,48,9,15,10,5050,10,30,30,15,63,15,10,5058, # 5040 - 11,15,10,60,10,30,12,15,10,36,16,30,18,15,10,30,22,5076,24,15, # 5060 - 26,5080,28,30,30,30,30,5086,31,30,30,15,12,30,30,30,30,15,10,5098, # 5080 - 30,5100,30,30,15,30,30,5106,11,15,10,30,30,5112,30,15,10,30,10,5118, # 5100 - 30,39,10,46,30,40,30,15,10,30,13,30,30,15,30,30,30,15,10,15, # 5120 - 11,52,30,36,11,15,13,5146,13,45,30,15,31,5152,30,15,30,26,10,30, # 5140 - 30,30,30,15,12,15,30,5166,15,15,15,5170,15,30,30,15,15,30,30,5178, # 5160 - 30,30,15,70,63,30,15,30,15,5188,30,28,30,30,16,30,18,5196,15,30, # 5180 - 22,15,30,42,30,30,28,40,39,5208,30,36,15,30,30,15,31,30,30,30, # 5200 - 30,22,15,15,30,30,30,5226,15,30,30,5230,24,5232,26,30,30,5236,30,31, # 5220 - 30,30,13,48,36,30,15,30,40,30,30,58,15,30,15,30,30,30,30,30, # 5240 - 30,5260,22,18,24,15,30,30,28,30,30,30,30,5272,30,30,30,30,30,5278, # 5260 - 31,5280,30,30,30,30,30,30,30,30,30,30,30,66,15,30,15,5296,30,16, # 5280 - 30,15,30,5302,30,30,30,15,30,5308,30,46,63,30,30,30,30,30,30,26, # 5300 - 30,30,30,5322,15,18,30,16,30,5328,12,16,10,5332,30,30,30,15,15,30, # 5320 - 30,48,30,15,31,30,30,5346,30,15,10,5350,30,52,11,15,15,30,15,30, # 5340 - 30,15,12,30,30,30,30,30,10,30,30,40,15,30,15,42,30,30,30,30, # 5360 - 16,5380,18,15,14,30,22,5386,30,18,30,30,28,5392,30,30,30,15,12,5398, # 5380 - 30,15,30,30,30,30,30,5406,31,15,30,30,30,5412,9,30,30,5416,12,5418, # 5400 - 11,30,30,15,30,15,13,66,12,60,30,5430,11,30,30,30,30,5436,15,30, # 5420 - 40,5440,30,5442,30,30,30,15,11,5448,11,15,30,30,15,15,15,30,10,52, # 5440 - 30,42,41,30,30,38,30,15,11,30,30,5470,30,30,12,16,30,5476,16,5478, # 5460 - 18,30,10,5482,30,18,24,15,30,30,30,30,30,31,30,30,38,22,36,30, # 5480 - 30,5500,40,5502,42,30,10,5506,14,15,12,24,30,36,30,15,10,15,10,5518, # 5500 - 30,5520,10,15,10,15,30,5526,10,15,30,5530,30,15,10,15,31,48,10,28, # 5520 - 10,15,9,25,9,15,10,15,12,30,30,15,15,15,11,30,10,5556,10,30, # 5540 - 10,66,12,5562,9,30,16,30,18,5568,10,30,22,5572,24,24,26,30,28,30, # 5560 - 30,5580,30,15,15,30,30,36,12,30,30,5590,30,15,13,15,30,30,30,30, # 5580 - 15,30,30,15,11,15,10,30,30,70,30,30,30,30,10,30,30,40,12,30, # 5600 - 30,30,30,5622,12,30,11,30,30,30,30,30,30,42,22,15,24,15,30,5638, # 5620 - 28,5640,30,30,30,30,30,5646,30,30,30,5650,30,5652,30,30,30,5656,30,5658, # 5640 - 30,30,30,30,30,15,10,30,10,5668,30,52,30,15,30,30,30,30,30,15, # 5660 - 30,30,30,5682,30,30,30,46,30,5688,30,30,30,5692,30,15,63,30,30,40, # 5680 - 30,5700,10,15,11,30,30,30,30,18,11,5710,30,28,30,15,30,5716,30,30, # 5700 - 30,15,30,58,30,24,10,15,31,30,10,30,30,15,11,15,30,5736,30,30, # 5720 - 11,5740,30,5742,15,15,10,30,30,5748,30,70,11,30,11,15,14,15,11,30, # 5740 - 30,30,30,15,11,15,11,72,30,15,11,28,11,22,30,15,16,52,30,5778, # 5760 - 30,15,11,5782,30,15,10,15,10,15,30,5790,31,15,10,15,11,15,10,15, # 5780 - 11,5800,11,15,9,15,11,5806,15,39,10,15,11,5812,12,15,10,15,10,15, # 5800 - 10,5820,13,15,63,24,10,5826,11,15,10,16,10,18,10,15,10,15,13,5838, # 5820 - 15,15,10,5842,10,15,10,15,11,5848,10,5850,10,15,12,15,15,5856,10,15, # 5840 - 10,5860,10,27,11,15,10,5866,10,5868,11,15,15,15,13,46,11,15,10,5878, # 5860 - 10,5880,10,15,10,15,12,15,22,21,13,42,13,70,11,15,13,5896,13,16, # 5880 - 13,15,13,5902,15,16,13,18,12,18,13,22,13,72,13,15,13,60,13,15, # 5900 - 15,30,30,5922,13,15,13,5926,13,48,13,30,13,30,13,15,15,30,16,5938, # 5920 - 18,15,10,30,22,16,24,18,26,30,28,30,30,5952,30,15,12,30,30,58, # 5940 - 13,30,30,66,30,15,13,15,30,46,45,30,11,42,30,24,13,42,11,36, # 5960 - 30,5980,30,30,30,30,16,5986,30,52,13,30,30,30,30,30,26,30,28,30, # 5980 - 30,31,30,30,30,30,36,6006,24,15,40,6010,42,30,30,30,46,30,30,30, # 6000 - 30,30,30,30,30,30,30,30,30,6028,30,45,30,30,30,30,30,6036,13,30, # 6020 - 13,30,30,6042,30,15,30,6046,30,30,30,15,30,6052,30,30,30,30,30,72, # 6040 - 30,30,30,30,30,30,30,6066,12,30,30,30,30,6072,12,24,12,58,30,6078, # 6060 - 46,30,10,30,30,15,30,24,30,6088,30,6090,30,15,30,15,30,15,13,15, # 6080 - 30,6100,30,30,30,15,12,30,30,40,30,30,31,6112,30,30,11,30,10,30, # 6100 - 30,6120,30,30,16,48,18,15,15,45,22,6130,30,6132,30,30,28,30,30,30, # 6120 - 30,15,12,6142,30,30,30,30,30,30,30,6150,30,15,30,30,30,46,11,30, # 6140 - 30,60,30,6162,30,30,30,15,30,30,30,30,11,6172,30,30,31,45,30,36, # 6160 - 30,30,12,30,11,30,30,30,30,30,30,40,22,15,24,15,30,6196,28,6198, # 6180 - 30,30,30,6202,30,30,30,30,63,30,30,6210,30,30,30,30,30,6216,30,30, # 6200 - 30,6220,30,48,47,30,11,44,30,6228,30,15,30,38,30,36,30,15,30,30, # 6220 - 30,6240,30,30,30,30,30,6246,30,30,30,30,30,36,30,31,30,6256,30,30, # 6240 - 36,15,15,6262,44,30,42,30,15,6268,46,6270,48,30,30,30,30,6276,30,16, # 6260 - 30,15,30,60,15,15,30,6286,30,30,30,26,15,15,30,30,30,30,30,6298, # 6280 - 30,6300,15,15,31,30,30,30,30,15,15,6310,15,58,15,15,15,6316,30,70, # 6300 - 30,15,15,6322,15,39,30,16,15,6328,15,30,30,15,15,30,30,6336,30,15, # 6320 - 15,16,30,6342,15,15,15,15,30,18,30,15,15,6352,15,18,15,15,15,6358, # 6340 - 30,6360,30,15,15,15,30,6366,31,15,15,22,15,6372,15,15,15,15,15,6378, # 6360 - 15,15,15,15,15,15,15,15,15,6388,15,70,15,15,15,15,15,6396,15,78, # 6380 - 24,36,15,18,11,15,15,42,15,48,15,15,15,52,15,15,15,16,15,48, # 6400 - 15,6420,15,22,15,24,15,6426,15,15,15,58,15,15,13,15,15,40,10,46, # 6420 - 15,15,15,16,15,15,15,15,15,6448,15,6450,11,26,13,16,15,15,15,15, # 6440 - 15,15,15,22,63,15,15,28,15,6468,12,15,15,6472,15,15,15,15,15,15, # 6460 - 15,6480,15,15,13,15,13,15,15,15,15,6490,15,42,15,15,31,72,13,66, # 6480 - 15,15,12,15,11,15,15,26,15,22,15,16,15,15,13,15,15,18,12,16, # 6500 - 11,6520,15,15,15,15,15,60,24,6528,13,15,15,46,11,17,12,15,15,15, # 6520 - 15,30,30,15,15,15,15,6546,11,15,14,6550,11,6552,12,15,15,78,16,30, # 6540 - 31,6560,15,6562,22,15,24,16,26,6568,28,6570,30,30,30,24,15,6576,30,15, # 6560 - 11,6580,30,30,30,15,11,15,30,30,30,30,63,30,30,15,11,15,11,6598, # 6580 - 30,15,30,15,11,30,10,6606,30,15,10,30,30,30,30,16,11,30,11,6618, # 6600 - 30,15,30,36,30,52,11,15,11,15,30,30,11,15,11,30,11,6636,30,15, # 6620 - 15,30,30,15,30,15,11,30,30,60,30,15,11,6652,30,15,15,15,11,6658, # 6640 - 11,6660,30,15,11,15,30,58,30,30,12,15,30,6672,12,15,11,30,30,6678, # 6660 - 30,15,12,40,12,15,14,15,18,6688,30,6690,30,15,11,15,12,36,30,15, # 6680 - 14,6700,12,6702,30,16,11,30,30,6708,30,15,11,48,30,15,11,15,14,6718, # 6700 - 30,30,30,80,11,24,12,23,11,15,11,52,51,6732,30,48,15,6736,30,22, # 6720 - 30,42,11,40,12,15,11,15,16,16,18,42,31,30,22,28,24,28,26,15, # 6740 - 28,6760,30,6762,12,15,10,66,36,17,11,15,40,15,42,24,15,26,46,6778, # 6760 - 48,6780,15,15,52,15,15,17,12,15,13,6790,15,6792,15,15,15,15,15,15, # 6780 - 15,15,15,6802,15,17,15,15,15,23,15,48,15,15,15,15,15,16,15,15, # 6800 - 15,18,15,6822,15,24,15,6826,15,6828,15,15,15,6832,15,15,15,15,15,15, # 6820 - 15,6840,15,15,15,15,15,40,63,21,15,15,15,15,15,15,15,6856,15,6858, # 6840 - 15,15,15,6862,15,15,15,15,15,6868,15,6870,15,16,15,15,15,15,15,15, # 6860 - 31,15,15,6882,15,15,15,70,15,6888,15,15,15,60,15,15,15,15,15,6898, # 6880 - 15,66,15,15,15,15,15,6906,15,15,15,6910,26,30,30,15,15,6916,15,30, # 6900 - 15,16,15,30,15,30,15,15,15,40,16,30,18,15,15,30,22,24,24,26, # 6920 - 26,30,28,52,31,30,30,6946,15,6948,30,15,15,30,30,30,30,15,15,6958, # 6940 - 30,6960,30,30,15,30,30,6966,15,16,15,6970,30,18,30,15,63,6976,15,30, # 6960 - 30,15,15,6982,30,30,30,15,15,30,15,6990,30,15,30,30,30,6996,15,15, # 6980 - 15,7000,30,46,15,15,15,30,15,42,30,15,15,7012,30,15,30,15,15,7018, # 7000 - 30,30,30,15,15,24,30,7026,15,15,15,78,15,30,30,15,15,30,30,7038, # 7020 - 30,30,15,7042,30,30,15,30,15,52,30,30,30,30,16,30,18,7056,15,30, # 7040 - 22,30,30,30,30,30,28,36,30,7068,30,15,16,30,30,30,30,30,30,7078, # 7060 - 30,72,30,15,30,30,30,30,15,30,30,15,30,40,30,30,30,46,30,39, # 7080 - 30,30,15,7102,30,30,30,30,30,7108,30,30,30,30,15,30,30,30,30,30, # 7100 - 30,7120,22,16,30,15,30,7126,28,7128,30,30,30,30,30,30,31,30,30,58, # 7120 - 30,36,30,30,30,30,30,30,30,30,30,7150,30,22,13,30,15,30,30,7158, # 7140 - 30,16,30,30,30,30,30,15,30,66,30,70,30,30,30,30,30,7176,30,30, # 7160 - 30,42,30,15,15,30,30,7186,30,30,13,15,13,7192,30,30,30,30,15,30, # 7180 - 30,18,30,30,30,30,30,7206,30,80,30,7210,30,7212,15,15,30,30,30,7218, # 7200 - 30,15,10,30,30,30,30,30,30,7228,30,30,63,30,30,30,30,7236,30,30, # 7220 - 16,30,18,7242,14,30,22,7246,30,30,30,30,28,7252,30,30,30,15,13,30, # 7240 - 30,52,30,30,31,30,30,42,30,15,30,30,30,30,13,30,30,18,30,30, # 7260 - 30,30,30,7282,30,15,11,30,12,36,30,30,30,30,30,30,30,7296,30,30, # 7280 - 15,48,30,66,30,30,30,7306,15,7308,30,16,30,70,13,15,13,30,15,30, # 7300 - 30,7320,30,30,30,24,30,16,31,30,30,7330,30,7332,15,15,30,15,15,40, # 7320 - 15,30,15,30,30,15,15,15,30,7348,30,7350,15,15,30,30,15,15,15,30, # 7340 - 30,30,30,36,15,30,15,52,15,7368,15,30,30,72,30,58,15,15,15,46, # 7360 - 30,60,15,30,15,30,30,82,15,30,30,30,30,7392,15,15,30,16,15,48, # 7380 - 24,15,30,30,30,15,15,15,15,30,30,7410,15,15,30,30,30,7416,15,30, # 7400 - 30,40,30,15,28,30,16,30,18,16,15,30,22,7432,30,20,26,30,28,42, # 7420 - 30,30,30,18,15,30,30,22,15,30,30,7450,30,28,15,15,31,7456,30,7458, # 7440 - 15,30,30,16,15,15,15,30,30,15,30,30,30,30,15,30,30,7476,15,30, # 7460 - 30,7480,30,30,15,30,15,7486,30,7488,30,30,30,58,57,15,24,54,30,7498, # 7480 - 28,30,30,48,30,46,30,7506,30,30,30,30,30,30,30,36,30,7516,30,72, # 7500 - 30,30,30,7522,30,31,15,30,15,7528,36,16,30,30,40,30,42,7536,30,30, # 7520 - 46,7540,48,30,30,30,52,7546,30,7548,30,30,58,30,30,30,22,30,30,7558, # 7540 - 30,7560,28,30,30,30,30,30,30,30,30,66,30,7572,30,30,30,7576,30,30, # 7560 - 30,30,30,7582,30,30,30,26,30,7588,30,7590,30,15,30,16,30,70,30,30, # 7580 - 30,30,30,7602,30,30,30,7606,30,30,30,30,30,30,30,39,58,30,13,30, # 7600 - 30,7620,30,30,15,60,15,30,30,30,30,30,30,30,30,15,30,30,30,7638, # 7620 - 30,30,30,7642,30,15,30,15,31,7648,30,30,30,30,30,15,15,15,30,30, # 7640 - 30,46,30,78,30,30,15,30,30,7668,30,30,30,7672,14,30,15,15,15,30, # 7660 - 15,7680,30,30,30,15,15,7686,15,15,30,7690,15,48,30,30,30,42,30,7698, # 7680 - 30,30,30,7702,30,15,30,15,15,15,30,17,31,30,30,15,15,7716,15,15, # 7700 - 14,15,14,7722,30,30,30,7726,15,58,30,30,30,15,15,30,15,15,14,70, # 7720 - 13,7740,15,30,63,30,15,60,59,15,15,56,15,7752,14,15,30,7756,17,7758, # 7740 - 30,15,30,16,16,17,30,15,28,38,22,36,30,15,30,24,31,30,30,31, # 7760 - 14,30,30,42,36,15,14,30,40,7788,42,30,15,7792,46,15,48,30,16,30, # 7780 - 56,28,15,30,22,15,58,36,60,30,28,72,30,30,30,15,15,7816,30,16, # 7800 - 15,30,30,7822,30,24,14,15,30,7828,30,40,15,30,30,16,15,16,13,30, # 7820 - 30,7840,30,15,14,30,15,30,30,46,15,30,30,7852,30,15,15,80,13,30, # 7840 - 30,23,30,30,30,15,15,7866,15,15,30,30,15,7872,13,30,15,7876,30,7878, # 7860 - 15,30,30,7882,30,15,15,30,30,30,30,15,15,15,30,15,15,52,15,30, # 7880 - 15,7900,30,15,18,15,30,7906,30,30,15,26,30,40,15,16,15,30,30,7918, # 7900 - 30,7920,15,30,15,24,15,7926,15,30,30,30,30,7932,15,15,30,7936,30,16, # 7920 - 15,30,30,46,30,15,30,30,30,7948,30,7950,30,16,30,18,15,72,30,22, # 7940 - 30,30,30,7962,30,28,30,30,31,30,15,15,30,30,30,15,30,30,30,78, # 7960 - 30,22,15,30,30,30,30,48,30,30,22,60,30,7992,30,30,28,30,30,30, # 7980 - 63,30,30,52,30,15,30,30,30,8008,30,8010,30,18,30,30,30,8016,30,30, # 8000 - 30,15,30,70,30,30,30,22,30,15,30,30,31,30,30,15,30,30,30,8038, # 8020 - 30,15,30,30,30,30,30,15,30,30,30,82,15,8052,30,15,30,30,15,8058, # 8040 - 15,30,30,30,30,15,15,30,30,8068,30,15,30,30,30,30,30,40,30,15, # 8060 - 30,8080,15,58,30,30,30,8086,30,8088,15,15,30,8092,30,30,31,18,30,30, # 8080 - 15,8100,30,30,30,30,30,66,15,30,15,8110,15,25,15,30,30,8116,30,22, # 8100 - 15,15,15,8122,30,15,15,30,63,62,30,46,59,30,30,30,30,78,53,15, # 8120 - 51,17,15,16,30,27,30,8146,30,28,41,22,39,30,30,26,30,28,33,40, # 8140 - 31,8160,29,30,30,36,30,8166,23,40,21,8170,18,15,17,46,22,48,30,8178, # 8160 - 26,80,28,48,30,30,30,58,26,60,30,8190,8191,30,30,30,30,15,15,24, # 8180 - 30,58,30,30,15,30,30,28,30,8208,30,30,30,42,30,22,15,30,30,8218, # 8200 - 30,8220,15,30,31,30,30,18,15,30,15,8230,30,8232,30,30,30,8236,15,57, # 8220 - 15,15,30,8242,15,15,15,30,15,72,30,36,15,30,30,15,62,22,15,30, # 8240 - 30,30,30,8262,15,15,30,18,15,8268,15,30,15,8272,30,24,15,15,30,30, # 8260 - 30,48,14,15,30,30,15,8286,15,30,30,8290,30,8292,15,30,15,8296,15,42, # 8280 - 15,30,30,30,30,16,15,15,15,15,30,8310,15,30,15,30,30,8316,15,30, # 8300 - 30,52,30,15,15,17,30,25,15,8328,15,15,30,30,30,15,15,15,14,30, # 8320 - 30,18,15,80,30,30,30,16,15,30,30,30,30,8352,14,30,16,60,18,15, # 8340 - 14,57,22,8362,30,30,26,30,28,8368,30,30,30,30,15,66,30,8376,30,30, # 8360 - 30,30,30,82,63,30,30,8386,30,8388,15,30,30,22,30,16,30,30,30,36, # 8380 - 30,30,30,30,30,30,30,30,15,30,30,30,30,46,15,30,31,30,30,8418, # 8400 - 30,30,30,8422,22,24,24,15,30,8428,28,8430,30,30,30,30,30,30,30,30, # 8420 - 30,30,30,8442,30,30,30,8446,30,30,30,30,30,78,30,15,15,30,15,30, # 8440 - 30,8460,30,30,30,30,30,8466,30,16,30,42,30,36,30,30,30,48,30,60, # 8460 - 30,30,30,30,30,15,22,30,30,30,30,30,28,15,29,30,30,30,30,30, # 8480 - 29,8500,30,15,30,30,30,46,30,66,65,16,30,8512,30,15,29,15,30,56, # 8500 - 30,8520,30,15,29,15,30,8526,30,30,30,44,30,42,29,30,30,8536,30,8538, # 8520 - 30,31,29,8542,29,30,36,30,15,82,40,30,42,15,15,20,46,42,48,30, # 8540 - 29,30,52,8562,30,30,30,30,58,30,60,30,30,8572,30,24,66,30,30,28, # 8560 - 30,8580,30,15,29,22,15,30,30,18,30,70,30,30,30,30,30,8596,30,8598, # 8580 - 30,15,30,30,16,30,18,15,31,8608,22,78,30,30,29,30,28,30,30,30, # 8600 - 30,36,15,8622,30,16,30,8626,30,8628,30,15,29,88,30,30,30,30,15,52, # 8620 - 30,8640,30,16,30,30,30,8646,30,15,15,40,30,30,30,16,29,30,30,30, # 8640 - 30,15,29,8662,30,30,30,80,30,8668,30,30,31,15,15,24,30,8676,15,15, # 8660 - 15,8680,15,30,30,15,15,30,30,8688,30,15,15,8692,30,30,30,15,15,8698, # 8680 - 30,18,15,16,16,30,15,8706,30,15,15,30,30,8712,30,30,15,30,30,8718, # 8700 - 15,30,15,30,30,30,30,30,16,30,18,8730,15,30,22,30,30,8736,30,30, # 8720 - 28,8740,30,30,30,15,15,8746,30,30,30,30,30,8752,30,30,30,15,30,30, # 8740 - 30,8760,15,30,30,15,30,30,63,30,30,48,30,30,30,30,15,66,30,8778, # 8760 - 30,30,30,8782,30,30,30,30,15,30,30,58,30,30,30,30,22,30,30,30, # 8780 - 31,30,28,8802,30,30,30,8806,30,30,30,30,30,30,30,30,30,30,30,8818, # 8800 - 30,8820,30,30,30,30,30,30,30,80,30,8830,30,72,30,15,30,8836,30,8838, # 8820 - 30,15,30,36,30,30,30,30,30,8848,30,52,30,30,30,30,30,16,30,30, # 8840 - 30,8860,30,8862,31,15,15,8866,30,48,30,30,15,30,30,70,30,30,30,30, # 8860 - 30,82,30,15,30,28,30,8886,15,15,30,30,30,8892,30,16,63,15,30,30, # 8880 - 30,30,30,30,30,30,15,30,30,58,30,30,30,30,15,30,15,36,15,30, # 8900 - 15,30,30,8922,30,15,15,78,15,8928,30,30,15,8932,30,30,30,30,30,30, # 8920 - 30,8940,30,30,30,40,30,22,15,30,30,8950,30,30,30,15,15,52,15,30, # 8940 - 30,30,30,8962,30,30,30,30,30,8968,30,8970,30,18,30,30,16,46,18,15, # 8960 - 30,30,30,30,30,30,26,30,30,88,30,36,31,30,15,30,30,15,30,8998, # 8980 - 30,9000,30,15,15,30,30,9006,30,30,15,9010,30,9012,30,16,30,70,69,30, # 9000 - 30,66,15,30,30,30,30,60,15,9028,30,30,30,15,16,30,30,30,30,48, # 9020 - 30,9040,30,9042,30,15,28,82,30,9048,30,15,15,34,36,30,31,30,40,9058, # 9040 - 42,16,30,24,46,30,48,9066,30,18,52,46,30,42,15,15,58,30,60,30, # 9060 - 30,63,15,30,66,30,30,30,70,60,30,9090,15,30,15,30,30,30,30,30, # 9080 - 16,30,18,9102,15,30,22,30,30,9108,30,30,28,30,30,30,30,15,15,30, # 9100 - 30,30,30,30,30,72,30,9126,30,16,30,30,30,9132,15,30,30,9136,30,30, # 9120 - 30,30,30,40,30,15,15,30,15,30,30,9150,63,80,30,30,30,9156,30,30, # 9140 - 15,9160,30,16,30,30,30,88,15,52,30,30,30,9172,15,24,15,30,15,66, # 9160 - 30,9180,30,30,30,30,30,9186,30,30,30,30,30,28,15,15,30,30,30,9198, # 9180 - 30,30,30,9202,30,30,15,15,30,9208,30,60,15,15,30,30,30,30,15,30, # 9200 - 30,9220,30,22,15,30,15,9226,30,18,30,30,30,30,30,15,30,15,15,9238, # 9220 - 30,9240,30,30,15,30,30,16,31,30,30,30,30,18,15,15,30,9256,15,46, # 9240 - 15,26,30,58,30,16,15,15,15,15,15,72,71,15,30,68,30,9276,15,30, # 9260 - 63,9280,30,9282,15,30,15,36,16,15,18,30,15,9292,30,48,24,15,26,16, # 9280 - 28,70,30,31,15,17,30,40,36,30,30,9310,40,66,42,30,30,26,46,9318, # 9300 - 48,30,30,9322,52,24,30,15,15,30,58,17,60,30,30,63,68,9336,66,30, # 9320 - 30,9340,70,9342,72,30,30,15,15,9348,15,40,30,46,30,15,16,15,15,48, # 9340 - 30,15,15,15,30,15,30,16,15,26,15,9370,30,15,15,15,31,9376,15,82, # 9360 - 15,15,15,17,15,15,15,15,15,40,15,9390,15,15,15,15,15,9396,15,15, # 9380 - 15,15,15,9402,15,15,15,22,15,9408,15,15,15,9412,15,15,15,15,15,9418, # 9400 - 15,9420,15,26,15,15,15,15,15,15,15,9430,15,9432,15,15,15,9436,15,9438, # 9420 - 15,15,15,15,15,15,15,15,15,15,15,15,15,29,15,16,15,48,15,15, # 9440 - 15,9460,15,9462,15,15,15,9466,15,16,15,15,36,9472,15,24,15,18,15,9478, # 9460 - 15,18,15,15,15,23,15,52,15,16,15,9490,15,15,15,22,15,9496,15,26, # 9480 - 15,28,15,30,31,18,15,15,15,36,15,9510,15,17,15,15,15,30,30,15, # 9500 - 15,9520,15,88,15,15,15,30,15,30,15,26,15,9532,16,30,63,15,15,9538, # 9520 - 22,15,24,15,26,30,28,9546,30,30,30,9550,15,40,30,15,15,30,30,78, # 9540 - 30,15,15,72,30,30,30,30,31,30,30,17,15,15,15,30,30,60,30,15, # 9560 - 15,30,15,30,30,15,15,9586,30,42,30,15,15,52,15,30,30,15,30,30, # 9580 - 30,9600,15,15,15,15,30,30,15,15,15,30,15,9612,30,15,15,58,30,9618, # 9600 - 30,15,15,9622,30,30,30,15,15,9628,30,9630,31,15,15,30,15,30,30,15, # 9620 - 15,30,30,9642,30,30,15,30,30,9648,15,30,15,48,30,30,30,30,16,30, # 9640 - 18,9660,15,30,63,30,30,30,30,30,28,30,30,30,30,15,15,9676,30,9678, # 9660 - 30,30,30,30,30,30,30,15,30,9688,30,30,15,30,30,17,30,9696,30,30, # 9680 - 30,88,30,30,30,30,15,30,30,30,30,30,30,30,30,30,30,30,15,9718, # 9700 - 30,9720,30,30,30,30,22,70,30,30,30,36,28,9732,30,30,30,30,30,9738, # 9720 - 30,30,30,9742,30,30,30,30,30,9748,30,48,30,30,30,30,30,30,30,30, # 9740 - 30,42,30,30,30,16,30,9766,30,9768,30,16,30,30,30,30,30,30,30,30, # 9760 - 30,9780,30,30,30,30,30,9786,30,30,30,9790,30,30,30,16,15,96,30,40, # 9780 - 30,80,15,9802,30,15,30,30,30,30,30,9810,30,15,30,15,30,9816,15,15, # 9800 - 30,30,30,30,31,16,15,30,30,9828,30,30,30,9832,30,30,15,30,30,9838, # 9820 - 30,30,30,30,16,30,18,42,15,30,22,9850,30,58,30,30,28,9856,30,9858, # 9840 - 30,30,15,30,30,30,30,30,30,70,30,9870,30,30,30,78,30,30,17,30, # 9860 - 30,40,30,9882,30,30,30,9886,30,15,15,30,30,30,30,30,30,30,30,30, # 9880 - 30,9900,30,30,30,30,30,9906,30,30,30,30,30,30,30,30,30,46,30,15, # 9900 - 16,30,30,9922,30,24,30,30,30,9928,30,9930,30,30,30,30,30,39,15,15, # 9920 - 30,9940,30,60,30,30,30,30,30,9948,17,15,31,36,30,30,15,16,30,46, # 9940 - 30,30,15,40,30,30,30,9966,15,30,15,58,30,9972,30,30,30,30,30,30, # 9960 - 30,15,15,66,30,30,30,30,15,30,30,96,30,30,30,30,30,18,15,15 # 9980 + 0, + 0, + 1, + 2, + 3, + 4, + 1, + 6, + 7, + 8, + 2, + 10, + 5, + 12, + 3, + 4, + 15, + 16, + 3, + 18, # 0 + 4, + 5, + 3, + 22, + 7, + 24, + 4, + 26, + 5, + 28, + 4, + 30, + 31, + 5, + 4, + 5, + 8, + 36, + 4, + 5, # 20 + 7, + 40, + 5, + 42, + 5, + 6, + 4, + 46, + 8, + 48, + 6, + 5, + 5, + 52, + 5, + 6, + 7, + 7, + 5, + 58, # 40 + 5, + 60, + 5, + 6, + 63, + 7, + 5, + 66, + 5, + 6, + 6, + 70, + 7, + 72, + 5, + 7, + 6, + 6, + 6, + 78, # 60 + 9, + 80, + 8, + 82, + 6, + 6, + 6, + 6, + 7, + 88, + 6, + 7, + 6, + 6, + 6, + 6, + 7, + 96, + 6, + 8, # 80 + 8, + 100, + 6, + 102, + 7, + 7, + 6, + 106, + 6, + 108, + 6, + 6, + 13, + 112, + 6, + 7, + 6, + 8, + 6, + 6, # 100 + 7, + 120, + 6, + 6, + 6, + 124, + 6, + 126, + 127, + 7, + 6, + 130, + 6, + 7, + 6, + 7, + 7, + 136, + 6, + 138, # 120 + 6, + 7, + 6, + 10, + 10, + 7, + 6, + 7, + 6, + 148, + 6, + 150, + 7, + 8, + 8, + 7, + 6, + 156, + 7, + 6, # 140 + 9, + 7, + 6, + 162, + 6, + 7, + 6, + 166, + 7, + 168, + 6, + 8, + 6, + 172, + 6, + 6, + 14, + 9, + 6, + 178, # 160 + 6, + 180, + 6, + 6, + 7, + 9, + 6, + 10, + 6, + 8, + 6, + 190, + 7, + 192, + 6, + 7, + 6, + 196, + 6, + 198, # 180 + 7, + 8, + 6, + 7, + 6, + 8, + 6, + 8, + 14, + 11, + 10, + 210, + 6, + 7, + 6, + 7, + 7, + 8, + 6, + 10, # 200 + 6, + 12, + 6, + 222, + 13, + 8, + 6, + 226, + 6, + 228, + 6, + 7, + 7, + 232, + 6, + 7, + 6, + 7, + 6, + 238, # 220 + 7, + 240, + 6, + 242, + 6, + 7, + 6, + 12, + 7, + 7, + 6, + 250, + 6, + 12, + 9, + 7, + 255, + 256, + 6, + 12, # 240 + 6, + 8, + 8, + 262, + 7, + 8, + 7, + 10, + 7, + 268, + 7, + 270, + 15, + 16, + 6, + 13, + 10, + 276, + 6, + 9, # 260 + 7, + 280, + 6, + 282, + 6, + 12, + 6, + 7, + 15, + 288, + 6, + 6, + 6, + 292, + 6, + 6, + 7, + 10, + 10, + 12, # 280 + 7, + 7, + 7, + 7, + 15, + 15, + 6, + 306, + 7, + 7, + 7, + 310, + 7, + 312, + 7, + 10, + 7, + 316, + 7, + 10, # 300 + 15, + 15, + 6, + 16, + 8, + 12, + 6, + 7, + 7, + 9, + 6, + 330, + 7, + 8, + 7, + 6, + 8, + 336, + 6, + 7, # 320 + 6, + 10, + 10, + 342, + 7, + 7, + 6, + 346, + 6, + 348, + 8, + 12, + 18, + 352, + 6, + 9, + 7, + 9, + 6, + 358, # 340 + 8, + 360, + 6, + 7, + 7, + 10, + 6, + 366, + 15, + 15, + 7, + 15, + 7, + 372, + 7, + 15, + 7, + 13, + 7, + 378, # 360 + 7, + 12, + 7, + 382, + 15, + 15, + 7, + 15, + 7, + 388, + 7, + 16, + 7, + 8, + 7, + 7, + 8, + 396, + 7, + 7, # 380 + 15, + 400, + 7, + 15, + 11, + 8, + 7, + 15, + 8, + 408, + 7, + 13, + 8, + 12, + 10, + 9, + 18, + 15, + 7, + 418, # 400 + 7, + 420, + 7, + 15, + 7, + 16, + 6, + 7, + 7, + 10, + 6, + 430, + 15, + 432, + 6, + 15, + 6, + 18, + 7, + 438, # 420 + 7, + 15, + 7, + 442, + 7, + 13, + 7, + 11, + 15, + 448, + 7, + 15, + 7, + 7, + 7, + 15, + 7, + 456, + 7, + 16, # 440 + 7, + 460, + 7, + 462, + 15, + 15, + 7, + 466, + 8, + 8, + 7, + 15, + 7, + 15, + 10, + 18, + 7, + 15, + 6, + 478, # 460 + 15, + 15, + 6, + 15, + 8, + 7, + 6, + 486, + 7, + 15, + 6, + 490, + 6, + 16, + 6, + 7, + 15, + 15, + 6, + 498, # 480 + 7, + 12, + 9, + 502, + 7, + 15, + 6, + 15, + 7, + 508, + 6, + 15, + 511, + 18, + 7, + 15, + 8, + 12, + 8, + 15, # 500 + 8, + 520, + 10, + 522, + 12, + 15, + 8, + 16, + 15, + 528, + 7, + 15, + 8, + 12, + 7, + 15, + 8, + 15, + 10, + 15, # 520 + 12, + 540, + 7, + 15, + 18, + 7, + 7, + 546, + 7, + 8, + 7, + 18, + 7, + 7, + 7, + 7, + 7, + 556, + 7, + 12, # 540 + 15, + 7, + 7, + 562, + 7, + 7, + 6, + 7, + 7, + 568, + 6, + 570, + 7, + 7, + 15, + 22, + 8, + 576, + 7, + 7, # 560 + 7, + 8, + 7, + 10, + 7, + 8, + 7, + 586, + 7, + 18, + 17, + 7, + 15, + 592, + 8, + 15, + 7, + 7, + 8, + 598, # 580 + 14, + 600, + 12, + 15, + 7, + 15, + 16, + 606, + 18, + 15, + 7, + 15, + 8, + 612, + 8, + 15, + 7, + 616, + 7, + 618, # 600 + 8, + 22, + 8, + 15, + 15, + 624, + 7, + 8, + 8, + 16, + 7, + 630, + 7, + 8, + 7, + 8, + 7, + 12, + 7, + 8, # 620 + 9, + 640, + 7, + 642, + 7, + 7, + 7, + 646, + 8, + 10, + 7, + 7, + 7, + 652, + 7, + 7, + 15, + 15, + 7, + 658, # 640 + 7, + 660, + 7, + 15, + 7, + 15, + 7, + 22, + 7, + 15, + 7, + 15, + 15, + 672, + 7, + 24, + 8, + 676, + 7, + 15, # 660 + 7, + 15, + 7, + 682, + 8, + 15, + 7, + 15, + 15, + 15, + 7, + 690, + 8, + 15, + 7, + 15, + 7, + 16, + 7, + 15, # 680 + 8, + 700, + 7, + 18, + 15, + 15, + 7, + 15, + 8, + 708, + 7, + 15, + 7, + 22, + 21, + 15, + 7, + 15, + 8, + 718, # 700 + 15, + 9, + 8, + 12, + 10, + 24, + 12, + 726, + 7, + 728, + 16, + 16, + 18, + 732, + 7, + 7, + 22, + 10, + 8, + 738, # 720 + 7, + 7, + 7, + 742, + 7, + 15, + 7, + 8, + 7, + 10, + 7, + 750, + 15, + 15, + 8, + 15, + 8, + 756, + 8, + 15, # 740 + 7, + 760, + 8, + 15, + 8, + 15, + 8, + 15, + 15, + 768, + 8, + 15, + 8, + 772, + 8, + 24, + 23, + 15, + 8, + 18, # 760 + 8, + 18, + 7, + 26, + 15, + 15, + 10, + 786, + 12, + 15, + 7, + 15, + 20, + 15, + 18, + 15, + 8, + 796, + 22, + 16, # 780 + 24, + 15, + 8, + 15, + 8, + 15, + 8, + 15, + 8, + 808, + 8, + 810, + 8, + 15, + 8, + 15, + 15, + 18, + 8, + 8, # 800 + 8, + 820, + 8, + 822, + 8, + 15, + 8, + 826, + 8, + 828, + 8, + 15, + 12, + 16, + 7, + 8, + 7, + 26, + 25, + 838, # 820 + 8, + 840, + 8, + 20, + 8, + 10, + 8, + 16, + 15, + 15, + 12, + 22, + 7, + 852, + 16, + 15, + 22, + 856, + 7, + 858, # 840 + 22, + 15, + 24, + 862, + 26, + 15, + 7, + 15, + 8, + 15, + 9, + 15, + 7, + 15, + 7, + 15, + 7, + 876, + 8, + 15, # 860 + 15, + 880, + 8, + 882, + 8, + 15, + 7, + 886, + 7, + 15, + 8, + 15, + 10, + 18, + 8, + 15, + 13, + 15, + 8, + 28, # 880 + 27, + 16, + 8, + 8, + 8, + 22, + 8, + 906, + 8, + 18, + 10, + 910, + 15, + 14, + 8, + 15, + 16, + 10, + 18, + 918, # 900 + 24, + 8, + 22, + 12, + 24, + 24, + 26, + 8, + 28, + 928, + 7, + 18, + 7, + 7, + 7, + 14, + 7, + 936, + 7, + 15, # 920 + 7, + 940, + 7, + 22, + 15, + 15, + 7, + 946, + 7, + 12, + 12, + 15, + 7, + 952, + 7, + 15, + 7, + 15, + 8, + 15, # 940 + 15, + 960, + 29, + 15, + 8, + 15, + 8, + 966, + 8, + 15, + 8, + 970, + 10, + 18, + 12, + 15, + 15, + 976, + 16, + 18, # 960 + 18, + 15, + 7, + 982, + 27, + 15, + 24, + 15, + 26, + 22, + 28, + 990, + 31, + 31, + 7, + 15, + 8, + 996, + 25, + 26, # 980 + 7, + 15, + 21, + 16, + 19, + 15, + 7, + 18, + 15, + 1008, + 13, + 18, + 8, + 1012, + 9, + 22, + 7, + 28, + 7, + 1018, # 1000 + 7, + 1020, + 7, + 30, + 1023, + 24, + 7, + 15, + 9, + 15, + 9, + 1030, + 7, + 1032, + 7, + 15, + 8, + 16, + 9, + 1038, # 1020 + 15, + 15, + 8, + 15, + 8, + 15, + 8, + 15, + 8, + 1048, + 8, + 1050, + 8, + 15, + 8, + 15, + 15, + 16, + 8, + 8, # 1040 + 8, + 1060, + 8, + 1062, + 8, + 15, + 8, + 15, + 10, + 1068, + 7, + 15, + 15, + 28, + 7, + 24, + 7, + 15, + 8, + 15, # 1060 + 12, + 22, + 8, + 15, + 8, + 15, + 8, + 1086, + 16, + 15, + 8, + 1090, + 8, + 1092, + 8, + 15, + 8, + 1096, + 8, + 15, # 1080 + 8, + 15, + 8, + 1102, + 15, + 15, + 8, + 26, + 8, + 1108, + 8, + 18, + 8, + 15, + 8, + 15, + 8, + 1116, + 7, + 15, # 1100 + 16, + 18, + 7, + 1122, + 7, + 15, + 7, + 22, + 8, + 1128, + 7, + 15, + 8, + 15, + 10, + 9, + 15, + 15, + 7, + 16, # 1120 + 7, + 8, + 7, + 15, + 7, + 15, + 7, + 30, + 30, + 15, + 7, + 1150, + 15, + 1152, + 7, + 15, + 8, + 26, + 12, + 24, # 1140 + 12, + 26, + 7, + 1162, + 16, + 18, + 18, + 15, + 15, + 15, + 22, + 1170, + 24, + 15, + 26, + 24, + 28, + 15, + 30, + 30, # 1160 + 8, + 1180, + 8, + 15, + 31, + 15, + 8, + 1186, + 8, + 28, + 8, + 15, + 8, + 1192, + 8, + 15, + 8, + 15, + 8, + 15, # 1180 + 15, + 1200, + 8, + 15, + 8, + 15, + 8, + 16, + 8, + 15, + 8, + 15, + 8, + 1212, + 8, + 15, + 18, + 1216, + 7, + 22, # 1200 + 7, + 15, + 8, + 1222, + 7, + 24, + 7, + 15, + 7, + 1228, + 7, + 1230, + 15, + 9, + 8, + 15, + 7, + 1236, + 7, + 15, # 1220 + 7, + 16, + 8, + 10, + 8, + 7, + 8, + 28, + 8, + 1248, + 8, + 8, + 7, + 7, + 7, + 8, + 8, + 8, + 7, + 1258, # 1240 + 7, + 12, + 23, + 7, + 15, + 15, + 9, + 15, + 9, + 26, + 9, + 30, + 30, + 23, + 8, + 15, + 9, + 1276, + 9, + 1278, # 1260 + 15, + 30, + 10, + 1282, + 12, + 15, + 9, + 24, + 16, + 1288, + 18, + 1290, + 8, + 18, + 22, + 15, + 24, + 1296, + 26, + 15, # 1280 + 28, + 1300, + 30, + 1302, + 8, + 15, + 8, + 1306, + 30, + 15, + 8, + 15, + 31, + 15, + 12, + 15, + 8, + 15, + 8, + 1318, # 1300 + 8, + 1320, + 8, + 26, + 8, + 24, + 7, + 1326, + 15, + 15, + 8, + 1330, + 8, + 30, + 30, + 15, + 8, + 15, + 9, + 30, # 1320 + 12, + 15, + 8, + 30, + 15, + 30, + 12, + 15, + 9, + 26, + 16, + 24, + 18, + 15, + 9, + 20, + 22, + 22, + 24, + 15, # 1340 + 26, + 1360, + 28, + 28, + 30, + 30, + 9, + 1366, + 28, + 1368, + 30, + 15, + 9, + 1372, + 30, + 15, + 31, + 16, + 8, + 15, # 1360 + 8, + 1380, + 8, + 15, + 8, + 15, + 8, + 18, + 8, + 15, + 8, + 15, + 15, + 15, + 8, + 15, + 8, + 10, + 9, + 1398, # 1380 + 10, + 15, + 8, + 22, + 8, + 8, + 8, + 15, + 10, + 1408, + 8, + 16, + 7, + 9, + 9, + 22, + 9, + 12, + 7, + 8, # 1400 + 9, + 28, + 7, + 1422, + 15, + 24, + 9, + 1426, + 9, + 1428, + 7, + 26, + 7, + 1432, + 9, + 15, + 7, + 15, + 7, + 1438, # 1420 + 15, + 15, + 7, + 15, + 9, + 15, + 9, + 1446, + 7, + 15, + 7, + 1450, + 7, + 1452, + 9, + 15, + 15, + 30, + 30, + 1458, # 1440 + 8, + 15, + 8, + 30, + 8, + 15, + 8, + 30, + 10, + 30, + 12, + 1470, + 22, + 30, + 16, + 28, + 18, + 15, + 8, + 24, # 1460 + 22, + 1480, + 24, + 1482, + 26, + 18, + 28, + 1486, + 30, + 1488, + 13, + 15, + 8, + 1492, + 30, + 15, + 8, + 15, + 30, + 1498, # 1480 + 30, + 18, + 9, + 15, + 31, + 15, + 9, + 15, + 9, + 14, + 9, + 1510, + 9, + 24, + 9, + 9, + 9, + 36, + 9, + 30, # 1500 + 30, + 9, + 9, + 1522, + 9, + 30, + 9, + 9, + 9, + 30, + 10, + 1530, + 12, + 9, + 9, + 30, + 16, + 30, + 18, + 18, # 1520 + 8, + 26, + 22, + 1542, + 24, + 8, + 26, + 20, + 28, + 1548, + 30, + 30, + 15, + 1552, + 8, + 15, + 30, + 8, + 8, + 1558, # 1540 + 30, + 15, + 30, + 15, + 8, + 15, + 30, + 1566, + 31, + 15, + 8, + 1570, + 8, + 15, + 12, + 15, + 8, + 18, + 8, + 1578, # 1560 + 8, + 15, + 8, + 1582, + 15, + 24, + 8, + 8, + 8, + 15, + 8, + 36, + 7, + 26, + 8, + 15, + 8, + 1596, + 8, + 15, # 1580 + 24, + 1600, + 8, + 15, + 8, + 15, + 8, + 1606, + 8, + 1608, + 8, + 15, + 8, + 1612, + 7, + 15, + 15, + 15, + 8, + 1618, # 1600 + 8, + 1620, + 7, + 15, + 7, + 15, + 7, + 1626, + 7, + 15, + 7, + 15, + 24, + 22, + 8, + 15, + 8, + 1636, + 7, + 15, # 1620 + 7, + 15, + 7, + 30, + 30, + 15, + 7, + 26, + 15, + 30, + 7, + 15, + 11, + 30, + 10, + 30, + 12, + 1656, + 7, + 30, # 1640 + 16, + 30, + 18, + 1662, + 15, + 30, + 22, + 1666, + 24, + 1668, + 26, + 24, + 28, + 22, + 30, + 30, + 19, + 15, + 7, + 22, # 1660 + 30, + 1680, + 9, + 15, + 30, + 15, + 30, + 15, + 9, + 15, + 30, + 18, + 30, + 1692, + 9, + 15, + 31, + 1696, + 9, + 1698, # 1680 + 9, + 15, + 8, + 15, + 8, + 15, + 8, + 15, + 8, + 1708, + 21, + 28, + 15, + 15, + 8, + 15, + 10, + 16, + 7, + 15, # 1700 + 8, + 1720, + 9, + 1722, + 9, + 15, + 7, + 15, + 26, + 21, + 8, + 15, + 8, + 1732, + 7, + 15, + 7, + 15, + 7, + 36, # 1720 + 9, + 1740, + 8, + 15, + 15, + 15, + 8, + 1746, + 8, + 15, + 8, + 16, + 9, + 1752, + 9, + 15, + 9, + 15, + 8, + 1758, # 1740 + 26, + 15, + 8, + 40, + 9, + 15, + 8, + 15, + 8, + 28, + 8, + 27, + 8, + 15, + 8, + 24, + 15, + 1776, + 9, + 15, # 1760 + 8, + 15, + 8, + 1782, + 8, + 15, + 8, + 1786, + 8, + 1788, + 8, + 15, + 15, + 15, + 9, + 15, + 8, + 15, + 8, + 15, # 1780 + 8, + 1800, + 8, + 15, + 9, + 15, + 8, + 30, + 15, + 26, + 8, + 1810, + 8, + 36, + 7, + 15, + 9, + 22, + 9, + 16, # 1800 + 9, + 15, + 9, + 1822, + 26, + 24, + 9, + 15, + 9, + 30, + 30, + 1830, + 9, + 15, + 9, + 30, + 9, + 15, + 9, + 30, # 1820 + 15, + 30, + 12, + 18, + 9, + 30, + 16, + 1846, + 18, + 1848, + 9, + 30, + 22, + 16, + 24, + 15, + 28, + 30, + 28, + 28, # 1840 + 30, + 1860, + 25, + 22, + 8, + 22, + 30, + 1866, + 8, + 18, + 30, + 1870, + 30, + 1872, + 8, + 15, + 30, + 1876, + 30, + 1878, # 1860 + 8, + 15, + 30, + 8, + 8, + 8, + 8, + 15, + 31, + 1888, + 8, + 30, + 30, + 15, + 8, + 15, + 8, + 30, + 8, + 15, # 1880 + 8, + 1900, + 10, + 30, + 15, + 15, + 8, + 1906, + 16, + 30, + 18, + 15, + 8, + 1912, + 22, + 15, + 24, + 26, + 26, + 30, # 1900 + 28, + 30, + 30, + 30, + 27, + 9, + 7, + 40, + 30, + 9, + 8, + 1930, + 30, + 1932, + 30, + 8, + 15, + 15, + 30, + 15, # 1920 + 30, + 10, + 8, + 28, + 30, + 15, + 8, + 15, + 8, + 1948, + 30, + 1950, + 31, + 15, + 8, + 15, + 8, + 18, + 8, + 15, # 1940 + 8, + 36, + 8, + 15, + 8, + 15, + 8, + 15, + 15, + 15, + 8, + 26, + 8, + 1972, + 8, + 24, + 9, + 15, + 9, + 1978, # 1960 + 9, + 15, + 9, + 15, + 30, + 30, + 9, + 1986, + 9, + 15, + 30, + 15, + 10, + 1992, + 30, + 15, + 30, + 1996, + 9, + 1998, # 1980 + 30, + 16, + 30, + 2002, + 9, + 9, + 30, + 22, + 9, + 40, + 9, + 2010, + 30, + 28, + 30, + 30, + 31, + 2016, + 8, + 15, # 2000 + 27, + 42, + 8, + 15, + 23, + 30, + 21, + 2026, + 8, + 2028, + 8, + 30, + 15, + 30, + 13, + 15, + 11, + 30, + 8, + 2038, # 2020 + 8, + 15, + 8, + 30, + 8, + 30, + 8, + 22, + 2047, + 15, + 8, + 15, + 8, + 2052, + 8, + 15, + 8, + 16, + 10, + 28, # 2040 + 8, + 15, + 9, + 2062, + 15, + 15, + 8, + 15, + 8, + 2068, + 8, + 18, + 8, + 15, + 9, + 24, + 8, + 30, + 30, + 15, # 2060 + 30, + 2080, + 8, + 2082, + 8, + 15, + 8, + 2086, + 10, + 2088, + 12, + 15, + 8, + 30, + 16, + 30, + 18, + 15, + 8, + 2098, # 2080 + 22, + 36, + 24, + 15, + 26, + 30, + 28, + 42, + 30, + 30, + 30, + 2110, + 15, + 2112, + 30, + 15, + 9, + 28, + 30, + 24, # 2100 + 30, + 15, + 10, + 15, + 30, + 18, + 30, + 16, + 15, + 2128, + 30, + 2130, + 8, + 26, + 9, + 15, + 30, + 2136, + 30, + 15, # 2120 + 9, + 2140, + 9, + 2142, + 31, + 15, + 9, + 18, + 9, + 15, + 9, + 15, + 9, + 2152, + 10, + 15, + 12, + 15, + 9, + 16, # 2140 + 15, + 2160, + 9, + 15, + 9, + 14, + 9, + 15, + 9, + 15, + 10, + 14, + 12, + 40, + 9, + 15, + 16, + 15, + 9, + 2178, # 2160 + 8, + 15, + 9, + 36, + 9, + 15, + 9, + 2186, + 9, + 15, + 9, + 23, + 15, + 15, + 8, + 15, + 9, + 2196, + 12, + 15, # 2180 + 9, + 30, + 30, + 2202, + 8, + 15, + 9, + 2206, + 15, + 2208, + 8, + 30, + 10, + 2212, + 12, + 15, + 8, + 30, + 16, + 30, # 2200 + 18, + 2220, + 8, + 30, + 22, + 24, + 24, + 16, + 26, + 30, + 28, + 30, + 30, + 30, + 30, + 15, + 10, + 2236, + 30, + 2238, # 2220 + 16, + 30, + 30, + 2242, + 30, + 15, + 8, + 15, + 30, + 22, + 30, + 2250, + 8, + 18, + 30, + 15, + 15, + 36, + 8, + 15, # 2240 + 30, + 15, + 30, + 30, + 30, + 30, + 9, + 2266, + 30, + 2268, + 8, + 15, + 31, + 2272, + 10, + 30, + 12, + 15, + 8, + 42, # 2260 + 16, + 2280, + 18, + 15, + 8, + 30, + 22, + 2286, + 24, + 15, + 26, + 30, + 28, + 2292, + 30, + 30, + 30, + 2296, + 9, + 30, # 2280 + 30, + 15, + 9, + 46, + 30, + 30, + 30, + 15, + 9, + 2308, + 30, + 2310, + 30, + 22, + 9, + 20, + 30, + 15, + 9, + 15, # 2300 + 15, + 15, + 30, + 22, + 30, + 15, + 9, + 30, + 28, + 16, + 30, + 15, + 9, + 2332, + 30, + 15, + 31, + 15, + 9, + 2338, # 2320 + 8, + 2340, + 8, + 10, + 9, + 15, + 8, + 2346, + 8, + 28, + 8, + 2350, + 15, + 12, + 8, + 15, + 9, + 2356, + 9, + 10, # 2340 + 8, + 15, + 8, + 16, + 8, + 9, + 8, + 10, + 36, + 22, + 10, + 2370, + 8, + 10, + 8, + 18, + 26, + 2376, + 8, + 10, # 2360 + 8, + 2380, + 8, + 2382, + 15, + 15, + 8, + 15, + 8, + 2388, + 8, + 15, + 8, + 2392, + 8, + 42, + 10, + 15, + 13, + 2398, # 2380 + 15, + 2400, + 8, + 26, + 8, + 15, + 9, + 28, + 7, + 15, + 7, + 2410, + 8, + 18, + 17, + 15, + 15, + 2416, + 7, + 40, # 2400 + 8, + 15, + 8, + 2422, + 14, + 24, + 12, + 15, + 8, + 15, + 16, + 15, + 18, + 15, + 8, + 15, + 9, + 2436, + 9, + 15, # 2420 + 9, + 2440, + 10, + 15, + 10, + 15, + 10, + 2446, + 15, + 30, + 30, + 15, + 9, + 27, + 9, + 30, + 9, + 15, + 9, + 2458, # 2440 + 10, + 30, + 12, + 15, + 15, + 30, + 16, + 2466, + 18, + 15, + 9, + 30, + 22, + 2472, + 24, + 15, + 26, + 2476, + 28, + 36, # 2460 + 30, + 30, + 30, + 15, + 12, + 30, + 30, + 15, + 9, + 30, + 30, + 46, + 30, + 15, + 9, + 15, + 30, + 30, + 30, + 28, # 2480 + 8, + 40, + 30, + 2502, + 8, + 15, + 9, + 22, + 30, + 15, + 30, + 30, + 30, + 30, + 9, + 15, + 30, + 30, + 8, + 15, # 2500 + 30, + 2520, + 30, + 30, + 12, + 24, + 9, + 30, + 31, + 30, + 18, + 2530, + 9, + 30, + 22, + 15, + 24, + 42, + 26, + 2538, # 2520 + 28, + 30, + 30, + 2542, + 30, + 15, + 9, + 30, + 30, + 2548, + 9, + 2550, + 30, + 30, + 30, + 15, + 9, + 2556, + 30, + 30, # 2540 + 30, + 30, + 9, + 28, + 30, + 15, + 10, + 16, + 9, + 23, + 30, + 15, + 30, + 30, + 30, + 30, + 15, + 15, + 30, + 2578, # 2560 + 9, + 28, + 30, + 30, + 30, + 30, + 12, + 12, + 12, + 30, + 30, + 2590, + 31, + 2592, + 8, + 30, + 22, + 48, + 24, + 22, # 2580 + 26, + 30, + 28, + 30, + 30, + 30, + 30, + 9, + 15, + 2608, + 30, + 15, + 9, + 30, + 30, + 30, + 30, + 2616, + 8, + 26, # 2600 + 30, + 2620, + 30, + 42, + 40, + 30, + 30, + 36, + 8, + 15, + 8, + 24, + 30, + 2632, + 30, + 15, + 8, + 30, + 8, + 16, # 2620 + 30, + 18, + 8, + 15, + 30, + 15, + 30, + 2646, + 28, + 15, + 8, + 15, + 30, + 15, + 30, + 15, + 31, + 2656, + 10, + 2658, # 2640 + 8, + 15, + 9, + 2662, + 9, + 15, + 9, + 15, + 7, + 16, + 9, + 2670, + 15, + 15, + 8, + 24, + 8, + 2676, + 8, + 15, # 2660 + 9, + 15, + 8, + 2682, + 9, + 15, + 8, + 2686, + 15, + 2688, + 8, + 15, + 10, + 2692, + 8, + 15, + 8, + 15, + 9, + 2698, # 2680 + 9, + 36, + 8, + 15, + 15, + 15, + 10, + 2706, + 8, + 15, + 10, + 2710, + 9, + 2712, + 8, + 15, + 10, + 15, + 10, + 2718, # 2700 + 31, + 15, + 9, + 15, + 9, + 24, + 10, + 26, + 10, + 2728, + 10, + 2730, + 9, + 15, + 10, + 15, + 15, + 15, + 8, + 15, # 2720 + 8, + 2740, + 8, + 15, + 9, + 15, + 8, + 40, + 9, + 2748, + 8, + 15, + 42, + 2752, + 9, + 15, + 8, + 15, + 9, + 30, # 2740 + 30, + 15, + 8, + 15, + 9, + 30, + 7, + 2766, + 15, + 30, + 10, + 30, + 12, + 46, + 8, + 30, + 16, + 2776, + 18, + 15, # 2760 + 9, + 30, + 22, + 22, + 24, + 15, + 26, + 30, + 28, + 2788, + 30, + 2790, + 30, + 15, + 9, + 30, + 30, + 2796, + 9, + 30, # 2780 + 30, + 2800, + 30, + 2802, + 9, + 15, + 30, + 30, + 30, + 2808, + 8, + 30, + 30, + 28, + 9, + 15, + 15, + 30, + 30, + 2818, # 2800 + 30, + 15, + 8, + 30, + 9, + 24, + 30, + 15, + 8, + 18, + 30, + 18, + 30, + 2832, + 9, + 15, + 9, + 2836, + 30, + 23, # 2820 + 30, + 15, + 30, + 2842, + 8, + 15, + 8, + 15, + 31, + 15, + 10, + 2850, + 8, + 15, + 9, + 15, + 8, + 2856, + 8, + 15, # 2840 + 8, + 2860, + 29, + 13, + 29, + 15, + 9, + 46, + 29, + 18, + 29, + 15, + 8, + 16, + 29, + 22, + 8, + 15, + 8, + 2878, # 2860 + 29, + 42, + 29, + 15, + 9, + 29, + 9, + 2886, + 29, + 26, + 8, + 48, + 29, + 15, + 29, + 15, + 15, + 2896, + 9, + 15, # 2880 + 29, + 15, + 30, + 2902, + 8, + 15, + 8, + 15, + 8, + 2908, + 10, + 40, + 31, + 15, + 9, + 15, + 8, + 2916, + 9, + 15, # 2900 + 8, + 22, + 21, + 36, + 9, + 18, + 9, + 2926, + 15, + 28, + 9, + 15, + 10, + 15, + 12, + 15, + 9, + 15, + 16, + 2938, # 2920 + 18, + 16, + 9, + 26, + 22, + 15, + 9, + 15, + 9, + 15, + 9, + 15, + 9, + 2952, + 9, + 15, + 9, + 2956, + 9, + 15, # 2940 + 15, + 15, + 9, + 2962, + 9, + 15, + 9, + 15, + 9, + 2968, + 9, + 2970, + 9, + 15, + 10, + 15, + 15, + 15, + 12, + 15, # 2960 + 9, + 15, + 10, + 18, + 9, + 15, + 9, + 28, + 9, + 48, + 8, + 15, + 15, + 40, + 9, + 15, + 9, + 36, + 9, + 2998, # 2980 + 9, + 3000, + 9, + 15, + 10, + 15, + 9, + 30, + 46, + 15, + 9, + 3010, + 9, + 30, + 8, + 15, + 10, + 30, + 10, + 3018, # 3000 + 12, + 15, + 9, + 3022, + 16, + 30, + 18, + 15, + 9, + 30, + 22, + 15, + 24, + 15, + 26, + 30, + 28, + 3036, + 30, + 30, # 3020 + 31, + 3040, + 9, + 30, + 30, + 15, + 9, + 30, + 30, + 3048, + 30, + 26, + 9, + 42, + 30, + 30, + 30, + 30, + 9, + 30, # 3040 + 30, + 3060, + 9, + 15, + 9, + 30, + 30, + 3066, + 30, + 15, + 9, + 36, + 15, + 30, + 30, + 15, + 8, + 26, + 30, + 3078, # 3060 + 30, + 15, + 9, + 3082, + 9, + 18, + 30, + 15, + 30, + 3088, + 30, + 15, + 9, + 15, + 10, + 15, + 30, + 18, + 9, + 15, # 3080 + 9, + 15, + 9, + 28, + 31, + 15, + 9, + 25, + 9, + 3108, + 8, + 15, + 9, + 15, + 8, + 15, + 8, + 15, + 9, + 3118, # 3100 + 15, + 3120, + 8, + 15, + 9, + 3124, + 8, + 52, + 8, + 15, + 9, + 30, + 30, + 15, + 8, + 15, + 48, + 3136, + 9, + 42, # 3120 + 8, + 30, + 10, + 30, + 12, + 15, + 9, + 30, + 16, + 46, + 18, + 22, + 15, + 30, + 22, + 15, + 24, + 15, + 26, + 30, # 3140 + 28, + 30, + 30, + 3162, + 30, + 15, + 9, + 3166, + 30, + 3168, + 9, + 30, + 30, + 30, + 30, + 24, + 23, + 15, + 30, + 30, # 3160 + 30, + 3180, + 10, + 30, + 30, + 15, + 10, + 3186, + 12, + 30, + 30, + 3190, + 30, + 30, + 30, + 30, + 8, + 30, + 30, + 30, # 3180 + 24, + 30, + 30, + 3202, + 30, + 30, + 12, + 24, + 9, + 3208, + 30, + 30, + 30, + 18, + 30, + 30, + 22, + 3216, + 24, + 15, # 3200 + 30, + 3220, + 28, + 30, + 30, + 30, + 30, + 15, + 30, + 3228, + 30, + 15, + 31, + 52, + 30, + 30, + 30, + 15, + 9, + 40, # 3220 + 30, + 30, + 30, + 30, + 9, + 30, + 30, + 16, + 15, + 15, + 10, + 3250, + 30, + 3252, + 30, + 15, + 9, + 3256, + 9, + 3258, # 3240 + 30, + 15, + 10, + 30, + 30, + 30, + 30, + 26, + 10, + 26, + 9, + 3270, + 30, + 15, + 30, + 24, + 30, + 28, + 10, + 15, # 3260 + 15, + 16, + 30, + 48, + 9, + 15, + 10, + 18, + 28, + 15, + 30, + 15, + 9, + 36, + 30, + 15, + 31, + 15, + 9, + 3298, # 3280 + 10, + 3300, + 10, + 15, + 10, + 15, + 10, + 3306, + 10, + 15, + 9, + 15, + 15, + 3312, + 9, + 15, + 9, + 30, + 30, + 3318, # 3300 + 9, + 40, + 9, + 3322, + 9, + 23, + 9, + 30, + 14, + 3328, + 12, + 3330, + 10, + 30, + 16, + 30, + 18, + 46, + 9, + 30, # 3320 + 22, + 15, + 24, + 3342, + 26, + 30, + 28, + 3346, + 30, + 30, + 30, + 15, + 10, + 30, + 30, + 13, + 10, + 30, + 30, + 3358, # 3340 + 30, + 3360, + 10, + 15, + 30, + 30, + 30, + 30, + 12, + 30, + 30, + 3370, + 10, + 3372, + 10, + 30, + 30, + 15, + 30, + 30, # 3360 + 30, + 30, + 9, + 30, + 30, + 30, + 9, + 30, + 30, + 3388, + 30, + 3390, + 52, + 30, + 10, + 30, + 30, + 42, + 30, + 24, # 3380 + 30, + 39, + 22, + 40, + 24, + 23, + 30, + 3406, + 28, + 30, + 30, + 30, + 30, + 3412, + 30, + 30, + 30, + 15, + 30, + 30, # 3400 + 30, + 30, + 30, + 15, + 31, + 24, + 30, + 30, + 30, + 30, + 25, + 46, + 30, + 3432, + 9, + 15, + 10, + 30, + 30, + 18, # 3420 + 30, + 15, + 13, + 30, + 10, + 30, + 30, + 15, + 22, + 3448, + 30, + 30, + 30, + 13, + 24, + 30, + 26, + 3456, + 30, + 15, # 3440 + 30, + 3460, + 30, + 3462, + 9, + 15, + 9, + 3466, + 30, + 3468, + 9, + 10, + 15, + 22, + 10, + 24, + 30, + 18, + 9, + 48, # 3460 + 30, + 3480, + 30, + 42, + 10, + 15, + 30, + 39, + 31, + 15, + 9, + 3490, + 9, + 11, + 10, + 13, + 10, + 15, + 12, + 3498, # 3480 + 9, + 15, + 10, + 30, + 30, + 11, + 10, + 15, + 9, + 30, + 10, + 3510, + 9, + 30, + 10, + 30, + 12, + 3516, + 9, + 30, # 3500 + 26, + 30, + 18, + 15, + 12, + 30, + 22, + 3526, + 24, + 3528, + 26, + 30, + 28, + 3532, + 30, + 30, + 30, + 26, + 10, + 3538, # 3520 + 30, + 3540, + 11, + 30, + 30, + 30, + 30, + 3546, + 11, + 15, + 30, + 52, + 30, + 30, + 10, + 30, + 30, + 3556, + 10, + 3558, # 3540 + 11, + 30, + 30, + 12, + 30, + 12, + 11, + 30, + 15, + 42, + 30, + 3570, + 11, + 30, + 30, + 30, + 30, + 48, + 10, + 30, # 3560 + 10, + 3580, + 30, + 3582, + 30, + 30, + 30, + 16, + 10, + 36, + 10, + 15, + 30, + 3592, + 11, + 15, + 11, + 18, + 10, + 58, # 3580 + 30, + 15, + 10, + 13, + 30, + 15, + 30, + 3606, + 9, + 15, + 30, + 22, + 30, + 3612, + 9, + 15, + 31, + 3616, + 9, + 15, # 3600 + 10, + 15, + 9, + 3622, + 10, + 28, + 11, + 15, + 9, + 25, + 11, + 3630, + 15, + 15, + 10, + 15, + 10, + 3636, + 9, + 15, # 3620 + 9, + 15, + 8, + 3642, + 11, + 15, + 9, + 15, + 26, + 40, + 10, + 15, + 9, + 15, + 12, + 15, + 9, + 25, + 9, + 3658, # 3640 + 11, + 15, + 11, + 15, + 15, + 15, + 10, + 18, + 9, + 15, + 9, + 3670, + 10, + 3672, + 10, + 15, + 9, + 3676, + 8, + 21, # 3660 + 15, + 15, + 10, + 28, + 27, + 15, + 10, + 24, + 9, + 15, + 10, + 3690, + 10, + 18, + 10, + 16, + 15, + 3696, + 10, + 26, # 3680 + 16, + 3700, + 18, + 15, + 24, + 15, + 22, + 15, + 24, + 3708, + 26, + 15, + 28, + 46, + 10, + 15, + 10, + 15, + 9, + 3718, # 3700 + 10, + 3720, + 10, + 15, + 11, + 24, + 9, + 3726, + 15, + 15, + 9, + 15, + 10, + 3732, + 10, + 15, + 9, + 36, + 9, + 3738, # 3720 + 9, + 15, + 10, + 18, + 15, + 39, + 10, + 15, + 9, + 22, + 10, + 30, + 30, + 26, + 9, + 15, + 10, + 30, + 12, + 15, # 3740 + 15, + 3760, + 10, + 52, + 12, + 15, + 10, + 3766, + 16, + 3768, + 18, + 15, + 9, + 30, + 22, + 24, + 58, + 15, + 26, + 3778, # 3760 + 28, + 30, + 30, + 30, + 30, + 15, + 10, + 30, + 30, + 15, + 10, + 30, + 30, + 3792, + 30, + 15, + 10, + 3796, + 30, + 30, # 3780 + 30, + 30, + 10, + 3802, + 30, + 15, + 9, + 46, + 31, + 30, + 30, + 36, + 30, + 15, + 9, + 30, + 9, + 30, + 30, + 15, # 3800 + 10, + 3820, + 30, + 3822, + 30, + 15, + 10, + 42, + 10, + 30, + 30, + 15, + 30, + 3832, + 30, + 15, + 10, + 15, + 10, + 15, # 3820 + 30, + 30, + 10, + 15, + 10, + 26, + 10, + 3846, + 30, + 15, + 9, + 3850, + 30, + 3852, + 30, + 15, + 15, + 15, + 30, + 16, # 3840 + 30, + 15, + 10, + 3862, + 30, + 15, + 9, + 15, + 9, + 52, + 9, + 48, + 31, + 15, + 10, + 30, + 30, + 3876, + 10, + 15, # 3860 + 10, + 3880, + 9, + 15, + 10, + 30, + 10, + 30, + 15, + 3888, + 10, + 30, + 16, + 30, + 18, + 15, + 9, + 30, + 22, + 15, # 3880 + 24, + 48, + 26, + 30, + 60, + 30, + 30, + 3906, + 30, + 15, + 9, + 3910, + 30, + 15, + 11, + 30, + 30, + 3916, + 30, + 3918, # 3900 + 15, + 15, + 30, + 3922, + 30, + 30, + 9, + 30, + 30, + 3928, + 9, + 3930, + 9, + 30, + 30, + 15, + 30, + 30, + 30, + 30, # 3920 + 9, + 30, + 30, + 3942, + 9, + 30, + 30, + 3946, + 30, + 30, + 12, + 30, + 15, + 58, + 30, + 30, + 30, + 30, + 30, + 36, # 3940 + 26, + 40, + 24, + 15, + 30, + 30, + 28, + 3966, + 30, + 48, + 30, + 28, + 30, + 36, + 30, + 24, + 30, + 40, + 30, + 30, # 3960 + 30, + 18, + 30, + 16, + 30, + 30, + 30, + 30, + 30, + 3988, + 30, + 22, + 10, + 24, + 10, + 30, + 30, + 28, + 30, + 30, # 3980 + 31, + 4000, + 10, + 4002, + 30, + 30, + 10, + 4006, + 30, + 30, + 30, + 30, + 9, + 4012, + 9, + 30, + 30, + 30, + 30, + 4018, # 4000 + 30, + 4020, + 9, + 26, + 9, + 24, + 30, + 4026, + 9, + 30, + 9, + 30, + 30, + 36, + 30, + 30, + 9, + 26, + 30, + 30, # 4020 + 30, + 30, + 10, + 20, + 30, + 18, + 30, + 30, + 15, + 4048, + 30, + 4050, + 18, + 15, + 9, + 15, + 28, + 4056, + 30, + 15, # 4040 + 26, + 30, + 30, + 16, + 31, + 30, + 10, + 48, + 27, + 30, + 9, + 30, + 10, + 4072, + 21, + 30, + 19, + 30, + 16, + 4078, # 4060 + 18, + 30, + 10, + 30, + 22, + 15, + 24, + 60, + 26, + 30, + 28, + 4090, + 30, + 4092, + 30, + 30, + 4095, + 30, + 30, + 4098, # 4080 + 9, + 30, + 30, + 30, + 30, + 15, + 9, + 15, + 30, + 30, + 30, + 4110, + 15, + 30, + 30, + 15, + 10, + 22, + 10, + 30, # 4100 + 30, + 15, + 30, + 15, + 11, + 30, + 9, + 4126, + 30, + 4128, + 10, + 30, + 30, + 4132, + 30, + 15, + 11, + 30, + 10, + 4138, # 4120 + 30, + 40, + 30, + 30, + 30, + 15, + 10, + 15, + 10, + 15, + 30, + 30, + 9, + 4152, + 11, + 30, + 9, + 4156, + 30, + 4158, # 4140 + 15, + 30, + 30, + 22, + 30, + 15, + 29, + 24, + 30, + 22, + 30, + 42, + 29, + 15, + 30, + 24, + 29, + 4176, + 10, + 15, # 4160 + 10, + 36, + 30, + 46, + 29, + 15, + 30, + 52, + 30, + 58, + 29, + 15, + 31, + 15, + 29, + 15, + 29, + 15, + 10, + 15, # 4180 + 12, + 4200, + 29, + 15, + 29, + 15, + 29, + 15, + 15, + 15, + 10, + 4210, + 29, + 15, + 9, + 15, + 9, + 4216, + 10, + 4218, # 4200 + 29, + 15, + 9, + 40, + 29, + 24, + 29, + 15, + 10, + 4228, + 29, + 4230, + 29, + 15, + 10, + 15, + 29, + 18, + 13, + 26, # 4220 + 15, + 4240, + 10, + 4242, + 30, + 15, + 9, + 30, + 30, + 15, + 12, + 15, + 9, + 4252, + 13, + 15, + 31, + 30, + 10, + 4258, # 4240 + 12, + 4260, + 10, + 30, + 16, + 30, + 18, + 42, + 9, + 30, + 22, + 4270, + 24, + 4272, + 26, + 30, + 28, + 30, + 30, + 30, # 4260 + 30, + 15, + 10, + 4282, + 30, + 15, + 9, + 30, + 63, + 4288, + 30, + 15, + 10, + 52, + 30, + 30, + 30, + 4296, + 9, + 30, # 4280 + 30, + 15, + 10, + 15, + 15, + 30, + 30, + 58, + 30, + 30, + 30, + 30, + 9, + 30, + 30, + 30, + 9, + 30, + 30, + 30, # 4300 + 30, + 30, + 12, + 30, + 10, + 30, + 30, + 4326, + 30, + 30, + 30, + 60, + 22, + 15, + 24, + 15, + 30, + 4336, + 28, + 4338, # 4320 + 30, + 30, + 30, + 42, + 30, + 30, + 30, + 30, + 30, + 4348, + 30, + 30, + 30, + 30, + 30, + 28, + 30, + 4356, + 30, + 30, # 4340 + 30, + 48, + 30, + 4362, + 13, + 18, + 13, + 30, + 30, + 16, + 30, + 15, + 30, + 4372, + 30, + 30, + 30, + 15, + 30, + 30, # 4360 + 30, + 30, + 30, + 15, + 31, + 30, + 12, + 40, + 30, + 15, + 30, + 4390, + 30, + 22, + 13, + 15, + 13, + 4396, + 30, + 52, # 4380 + 15, + 26, + 12, + 30, + 13, + 30, + 30, + 15, + 13, + 4408, + 30, + 15, + 30, + 15, + 10, + 30, + 30, + 30, + 30, + 15, # 4400 + 12, + 4420, + 30, + 4422, + 13, + 15, + 13, + 20, + 12, + 42, + 30, + 15, + 15, + 15, + 30, + 15, + 30, + 30, + 12, + 22, # 4420 + 30, + 4440, + 11, + 15, + 13, + 15, + 30, + 4446, + 31, + 15, + 10, + 4450, + 12, + 60, + 13, + 15, + 12, + 4456, + 13, + 15, # 4440 + 13, + 15, + 13, + 4462, + 15, + 15, + 11, + 15, + 10, + 40, + 12, + 16, + 13, + 15, + 13, + 24, + 13, + 36, + 13, + 15, # 4460 + 16, + 4480, + 10, + 4482, + 10, + 15, + 12, + 15, + 13, + 4488, + 13, + 15, + 10, + 4492, + 13, + 15, + 15, + 15, + 10, + 25, # 4480 + 10, + 15, + 10, + 15, + 10, + 15, + 12, + 4506, + 13, + 26, + 13, + 15, + 15, + 4512, + 10, + 15, + 10, + 4516, + 10, + 4518, # 4500 + 10, + 15, + 12, + 4522, + 13, + 24, + 10, + 15, + 15, + 15, + 11, + 22, + 10, + 15, + 10, + 15, + 10, + 15, + 10, + 15, # 4520 + 12, + 18, + 13, + 15, + 63, + 15, + 10, + 4546, + 10, + 4548, + 10, + 15, + 10, + 28, + 10, + 15, + 12, + 15, + 12, + 46, # 4540 + 15, + 4560, + 11, + 26, + 11, + 15, + 10, + 4566, + 10, + 15, + 12, + 15, + 12, + 16, + 13, + 15, + 31, + 22, + 11, + 18, # 4560 + 10, + 15, + 10, + 4582, + 10, + 15, + 10, + 15, + 12, + 15, + 13, + 4590, + 15, + 15, + 10, + 15, + 10, + 4596, + 12, + 15, # 4580 + 10, + 42, + 10, + 4602, + 12, + 15, + 9, + 16, + 15, + 15, + 13, + 15, + 11, + 15, + 9, + 15, + 9, + 18, + 10, + 30, # 4600 + 30, + 4620, + 12, + 15, + 16, + 36, + 15, + 15, + 13, + 30, + 15, + 30, + 15, + 40, + 15, + 30, + 16, + 4636, + 18, + 4638, # 4620 + 31, + 30, + 22, + 4642, + 24, + 15, + 26, + 30, + 28, + 4648, + 30, + 4650, + 30, + 15, + 15, + 30, + 30, + 4656, + 12, + 30, # 4640 + 30, + 58, + 30, + 4662, + 14, + 15, + 30, + 30, + 30, + 30, + 14, + 30, + 63, + 4672, + 12, + 15, + 14, + 30, + 30, + 4678, # 4660 + 30, + 30, + 30, + 30, + 14, + 30, + 30, + 42, + 15, + 30, + 30, + 4690, + 30, + 30, + 14, + 30, + 15, + 30, + 30, + 36, # 4680 + 35, + 30, + 30, + 4702, + 22, + 15, + 24, + 15, + 30, + 30, + 28, + 30, + 30, + 30, + 30, + 30, + 30, + 52, + 30, + 30, # 4700 + 30, + 4720, + 30, + 4722, + 30, + 30, + 30, + 30, + 30, + 4728, + 30, + 31, + 30, + 4732, + 30, + 15, + 36, + 30, + 12, + 30, # 4720 + 30, + 15, + 30, + 15, + 30, + 30, + 30, + 46, + 30, + 15, + 30, + 4750, + 30, + 48, + 30, + 15, + 30, + 66, + 30, + 4758, # 4740 + 30, + 15, + 30, + 30, + 30, + 15, + 13, + 15, + 31, + 18, + 30, + 30, + 11, + 15, + 10, + 30, + 10, + 39, + 30, + 58, # 4760 + 15, + 30, + 30, + 4782, + 30, + 15, + 12, + 4786, + 30, + 4788, + 30, + 15, + 10, + 4792, + 30, + 15, + 14, + 15, + 15, + 4798, # 4780 + 15, + 4800, + 30, + 15, + 10, + 15, + 30, + 24, + 30, + 30, + 10, + 16, + 30, + 4812, + 14, + 15, + 15, + 4816, + 30, + 60, # 4800 + 30, + 15, + 10, + 22, + 28, + 24, + 12, + 15, + 12, + 15, + 30, + 4830, + 31, + 26, + 12, + 15, + 10, + 23, + 10, + 15, # 4820 + 10, + 46, + 11, + 28, + 12, + 15, + 15, + 36, + 15, + 15, + 11, + 15, + 10, + 22, + 10, + 15, + 11, + 15, + 10, + 42, # 4840 + 11, + 4860, + 14, + 15, + 18, + 17, + 12, + 30, + 30, + 15, + 10, + 4870, + 11, + 30, + 11, + 15, + 12, + 4876, + 11, + 30, # 4860 + 15, + 16, + 10, + 30, + 16, + 30, + 18, + 26, + 10, + 4888, + 22, + 66, + 24, + 15, + 26, + 30, + 28, + 58, + 30, + 30, # 4880 + 30, + 28, + 12, + 4902, + 30, + 15, + 10, + 30, + 30, + 4908, + 30, + 15, + 15, + 4912, + 30, + 30, + 30, + 30, + 10, + 4918, # 4900 + 30, + 15, + 11, + 15, + 10, + 30, + 30, + 15, + 30, + 15, + 12, + 4930, + 11, + 4932, + 30, + 15, + 11, + 4936, + 30, + 30, # 4920 + 30, + 60, + 10, + 4942, + 15, + 30, + 30, + 15, + 30, + 48, + 30, + 4950, + 10, + 15, + 10, + 15, + 30, + 4956, + 10, + 15, # 4940 + 15, + 40, + 11, + 30, + 30, + 15, + 12, + 4966, + 30, + 4968, + 30, + 15, + 10, + 4972, + 30, + 30, + 30, + 15, + 12, + 15, # 4960 + 30, + 16, + 10, + 15, + 11, + 30, + 10, + 4986, + 30, + 15, + 10, + 15, + 30, + 4992, + 30, + 30, + 10, + 18, + 30, + 4998, # 4980 + 11, + 15, + 10, + 5002, + 30, + 18, + 30, + 15, + 15, + 5008, + 10, + 5010, + 11, + 15, + 10, + 15, + 30, + 28, + 30, + 15, # 5000 + 10, + 5020, + 10, + 5022, + 31, + 15, + 10, + 15, + 10, + 46, + 10, + 15, + 9, + 15, + 10, + 15, + 10, + 15, + 10, + 5038, # 5020 + 15, + 5040, + 10, + 15, + 11, + 15, + 10, + 48, + 9, + 15, + 10, + 5050, + 10, + 30, + 30, + 15, + 63, + 15, + 10, + 5058, # 5040 + 11, + 15, + 10, + 60, + 10, + 30, + 12, + 15, + 10, + 36, + 16, + 30, + 18, + 15, + 10, + 30, + 22, + 5076, + 24, + 15, # 5060 + 26, + 5080, + 28, + 30, + 30, + 30, + 30, + 5086, + 31, + 30, + 30, + 15, + 12, + 30, + 30, + 30, + 30, + 15, + 10, + 5098, # 5080 + 30, + 5100, + 30, + 30, + 15, + 30, + 30, + 5106, + 11, + 15, + 10, + 30, + 30, + 5112, + 30, + 15, + 10, + 30, + 10, + 5118, # 5100 + 30, + 39, + 10, + 46, + 30, + 40, + 30, + 15, + 10, + 30, + 13, + 30, + 30, + 15, + 30, + 30, + 30, + 15, + 10, + 15, # 5120 + 11, + 52, + 30, + 36, + 11, + 15, + 13, + 5146, + 13, + 45, + 30, + 15, + 31, + 5152, + 30, + 15, + 30, + 26, + 10, + 30, # 5140 + 30, + 30, + 30, + 15, + 12, + 15, + 30, + 5166, + 15, + 15, + 15, + 5170, + 15, + 30, + 30, + 15, + 15, + 30, + 30, + 5178, # 5160 + 30, + 30, + 15, + 70, + 63, + 30, + 15, + 30, + 15, + 5188, + 30, + 28, + 30, + 30, + 16, + 30, + 18, + 5196, + 15, + 30, # 5180 + 22, + 15, + 30, + 42, + 30, + 30, + 28, + 40, + 39, + 5208, + 30, + 36, + 15, + 30, + 30, + 15, + 31, + 30, + 30, + 30, # 5200 + 30, + 22, + 15, + 15, + 30, + 30, + 30, + 5226, + 15, + 30, + 30, + 5230, + 24, + 5232, + 26, + 30, + 30, + 5236, + 30, + 31, # 5220 + 30, + 30, + 13, + 48, + 36, + 30, + 15, + 30, + 40, + 30, + 30, + 58, + 15, + 30, + 15, + 30, + 30, + 30, + 30, + 30, # 5240 + 30, + 5260, + 22, + 18, + 24, + 15, + 30, + 30, + 28, + 30, + 30, + 30, + 30, + 5272, + 30, + 30, + 30, + 30, + 30, + 5278, # 5260 + 31, + 5280, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 66, + 15, + 30, + 15, + 5296, + 30, + 16, # 5280 + 30, + 15, + 30, + 5302, + 30, + 30, + 30, + 15, + 30, + 5308, + 30, + 46, + 63, + 30, + 30, + 30, + 30, + 30, + 30, + 26, # 5300 + 30, + 30, + 30, + 5322, + 15, + 18, + 30, + 16, + 30, + 5328, + 12, + 16, + 10, + 5332, + 30, + 30, + 30, + 15, + 15, + 30, # 5320 + 30, + 48, + 30, + 15, + 31, + 30, + 30, + 5346, + 30, + 15, + 10, + 5350, + 30, + 52, + 11, + 15, + 15, + 30, + 15, + 30, # 5340 + 30, + 15, + 12, + 30, + 30, + 30, + 30, + 30, + 10, + 30, + 30, + 40, + 15, + 30, + 15, + 42, + 30, + 30, + 30, + 30, # 5360 + 16, + 5380, + 18, + 15, + 14, + 30, + 22, + 5386, + 30, + 18, + 30, + 30, + 28, + 5392, + 30, + 30, + 30, + 15, + 12, + 5398, # 5380 + 30, + 15, + 30, + 30, + 30, + 30, + 30, + 5406, + 31, + 15, + 30, + 30, + 30, + 5412, + 9, + 30, + 30, + 5416, + 12, + 5418, # 5400 + 11, + 30, + 30, + 15, + 30, + 15, + 13, + 66, + 12, + 60, + 30, + 5430, + 11, + 30, + 30, + 30, + 30, + 5436, + 15, + 30, # 5420 + 40, + 5440, + 30, + 5442, + 30, + 30, + 30, + 15, + 11, + 5448, + 11, + 15, + 30, + 30, + 15, + 15, + 15, + 30, + 10, + 52, # 5440 + 30, + 42, + 41, + 30, + 30, + 38, + 30, + 15, + 11, + 30, + 30, + 5470, + 30, + 30, + 12, + 16, + 30, + 5476, + 16, + 5478, # 5460 + 18, + 30, + 10, + 5482, + 30, + 18, + 24, + 15, + 30, + 30, + 30, + 30, + 30, + 31, + 30, + 30, + 38, + 22, + 36, + 30, # 5480 + 30, + 5500, + 40, + 5502, + 42, + 30, + 10, + 5506, + 14, + 15, + 12, + 24, + 30, + 36, + 30, + 15, + 10, + 15, + 10, + 5518, # 5500 + 30, + 5520, + 10, + 15, + 10, + 15, + 30, + 5526, + 10, + 15, + 30, + 5530, + 30, + 15, + 10, + 15, + 31, + 48, + 10, + 28, # 5520 + 10, + 15, + 9, + 25, + 9, + 15, + 10, + 15, + 12, + 30, + 30, + 15, + 15, + 15, + 11, + 30, + 10, + 5556, + 10, + 30, # 5540 + 10, + 66, + 12, + 5562, + 9, + 30, + 16, + 30, + 18, + 5568, + 10, + 30, + 22, + 5572, + 24, + 24, + 26, + 30, + 28, + 30, # 5560 + 30, + 5580, + 30, + 15, + 15, + 30, + 30, + 36, + 12, + 30, + 30, + 5590, + 30, + 15, + 13, + 15, + 30, + 30, + 30, + 30, # 5580 + 15, + 30, + 30, + 15, + 11, + 15, + 10, + 30, + 30, + 70, + 30, + 30, + 30, + 30, + 10, + 30, + 30, + 40, + 12, + 30, # 5600 + 30, + 30, + 30, + 5622, + 12, + 30, + 11, + 30, + 30, + 30, + 30, + 30, + 30, + 42, + 22, + 15, + 24, + 15, + 30, + 5638, # 5620 + 28, + 5640, + 30, + 30, + 30, + 30, + 30, + 5646, + 30, + 30, + 30, + 5650, + 30, + 5652, + 30, + 30, + 30, + 5656, + 30, + 5658, # 5640 + 30, + 30, + 30, + 30, + 30, + 15, + 10, + 30, + 10, + 5668, + 30, + 52, + 30, + 15, + 30, + 30, + 30, + 30, + 30, + 15, # 5660 + 30, + 30, + 30, + 5682, + 30, + 30, + 30, + 46, + 30, + 5688, + 30, + 30, + 30, + 5692, + 30, + 15, + 63, + 30, + 30, + 40, # 5680 + 30, + 5700, + 10, + 15, + 11, + 30, + 30, + 30, + 30, + 18, + 11, + 5710, + 30, + 28, + 30, + 15, + 30, + 5716, + 30, + 30, # 5700 + 30, + 15, + 30, + 58, + 30, + 24, + 10, + 15, + 31, + 30, + 10, + 30, + 30, + 15, + 11, + 15, + 30, + 5736, + 30, + 30, # 5720 + 11, + 5740, + 30, + 5742, + 15, + 15, + 10, + 30, + 30, + 5748, + 30, + 70, + 11, + 30, + 11, + 15, + 14, + 15, + 11, + 30, # 5740 + 30, + 30, + 30, + 15, + 11, + 15, + 11, + 72, + 30, + 15, + 11, + 28, + 11, + 22, + 30, + 15, + 16, + 52, + 30, + 5778, # 5760 + 30, + 15, + 11, + 5782, + 30, + 15, + 10, + 15, + 10, + 15, + 30, + 5790, + 31, + 15, + 10, + 15, + 11, + 15, + 10, + 15, # 5780 + 11, + 5800, + 11, + 15, + 9, + 15, + 11, + 5806, + 15, + 39, + 10, + 15, + 11, + 5812, + 12, + 15, + 10, + 15, + 10, + 15, # 5800 + 10, + 5820, + 13, + 15, + 63, + 24, + 10, + 5826, + 11, + 15, + 10, + 16, + 10, + 18, + 10, + 15, + 10, + 15, + 13, + 5838, # 5820 + 15, + 15, + 10, + 5842, + 10, + 15, + 10, + 15, + 11, + 5848, + 10, + 5850, + 10, + 15, + 12, + 15, + 15, + 5856, + 10, + 15, # 5840 + 10, + 5860, + 10, + 27, + 11, + 15, + 10, + 5866, + 10, + 5868, + 11, + 15, + 15, + 15, + 13, + 46, + 11, + 15, + 10, + 5878, # 5860 + 10, + 5880, + 10, + 15, + 10, + 15, + 12, + 15, + 22, + 21, + 13, + 42, + 13, + 70, + 11, + 15, + 13, + 5896, + 13, + 16, # 5880 + 13, + 15, + 13, + 5902, + 15, + 16, + 13, + 18, + 12, + 18, + 13, + 22, + 13, + 72, + 13, + 15, + 13, + 60, + 13, + 15, # 5900 + 15, + 30, + 30, + 5922, + 13, + 15, + 13, + 5926, + 13, + 48, + 13, + 30, + 13, + 30, + 13, + 15, + 15, + 30, + 16, + 5938, # 5920 + 18, + 15, + 10, + 30, + 22, + 16, + 24, + 18, + 26, + 30, + 28, + 30, + 30, + 5952, + 30, + 15, + 12, + 30, + 30, + 58, # 5940 + 13, + 30, + 30, + 66, + 30, + 15, + 13, + 15, + 30, + 46, + 45, + 30, + 11, + 42, + 30, + 24, + 13, + 42, + 11, + 36, # 5960 + 30, + 5980, + 30, + 30, + 30, + 30, + 16, + 5986, + 30, + 52, + 13, + 30, + 30, + 30, + 30, + 30, + 26, + 30, + 28, + 30, # 5980 + 30, + 31, + 30, + 30, + 30, + 30, + 36, + 6006, + 24, + 15, + 40, + 6010, + 42, + 30, + 30, + 30, + 46, + 30, + 30, + 30, # 6000 + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 6028, + 30, + 45, + 30, + 30, + 30, + 30, + 30, + 6036, + 13, + 30, # 6020 + 13, + 30, + 30, + 6042, + 30, + 15, + 30, + 6046, + 30, + 30, + 30, + 15, + 30, + 6052, + 30, + 30, + 30, + 30, + 30, + 72, # 6040 + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 6066, + 12, + 30, + 30, + 30, + 30, + 6072, + 12, + 24, + 12, + 58, + 30, + 6078, # 6060 + 46, + 30, + 10, + 30, + 30, + 15, + 30, + 24, + 30, + 6088, + 30, + 6090, + 30, + 15, + 30, + 15, + 30, + 15, + 13, + 15, # 6080 + 30, + 6100, + 30, + 30, + 30, + 15, + 12, + 30, + 30, + 40, + 30, + 30, + 31, + 6112, + 30, + 30, + 11, + 30, + 10, + 30, # 6100 + 30, + 6120, + 30, + 30, + 16, + 48, + 18, + 15, + 15, + 45, + 22, + 6130, + 30, + 6132, + 30, + 30, + 28, + 30, + 30, + 30, # 6120 + 30, + 15, + 12, + 6142, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 6150, + 30, + 15, + 30, + 30, + 30, + 46, + 11, + 30, # 6140 + 30, + 60, + 30, + 6162, + 30, + 30, + 30, + 15, + 30, + 30, + 30, + 30, + 11, + 6172, + 30, + 30, + 31, + 45, + 30, + 36, # 6160 + 30, + 30, + 12, + 30, + 11, + 30, + 30, + 30, + 30, + 30, + 30, + 40, + 22, + 15, + 24, + 15, + 30, + 6196, + 28, + 6198, # 6180 + 30, + 30, + 30, + 6202, + 30, + 30, + 30, + 30, + 63, + 30, + 30, + 6210, + 30, + 30, + 30, + 30, + 30, + 6216, + 30, + 30, # 6200 + 30, + 6220, + 30, + 48, + 47, + 30, + 11, + 44, + 30, + 6228, + 30, + 15, + 30, + 38, + 30, + 36, + 30, + 15, + 30, + 30, # 6220 + 30, + 6240, + 30, + 30, + 30, + 30, + 30, + 6246, + 30, + 30, + 30, + 30, + 30, + 36, + 30, + 31, + 30, + 6256, + 30, + 30, # 6240 + 36, + 15, + 15, + 6262, + 44, + 30, + 42, + 30, + 15, + 6268, + 46, + 6270, + 48, + 30, + 30, + 30, + 30, + 6276, + 30, + 16, # 6260 + 30, + 15, + 30, + 60, + 15, + 15, + 30, + 6286, + 30, + 30, + 30, + 26, + 15, + 15, + 30, + 30, + 30, + 30, + 30, + 6298, # 6280 + 30, + 6300, + 15, + 15, + 31, + 30, + 30, + 30, + 30, + 15, + 15, + 6310, + 15, + 58, + 15, + 15, + 15, + 6316, + 30, + 70, # 6300 + 30, + 15, + 15, + 6322, + 15, + 39, + 30, + 16, + 15, + 6328, + 15, + 30, + 30, + 15, + 15, + 30, + 30, + 6336, + 30, + 15, # 6320 + 15, + 16, + 30, + 6342, + 15, + 15, + 15, + 15, + 30, + 18, + 30, + 15, + 15, + 6352, + 15, + 18, + 15, + 15, + 15, + 6358, # 6340 + 30, + 6360, + 30, + 15, + 15, + 15, + 30, + 6366, + 31, + 15, + 15, + 22, + 15, + 6372, + 15, + 15, + 15, + 15, + 15, + 6378, # 6360 + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 6388, + 15, + 70, + 15, + 15, + 15, + 15, + 15, + 6396, + 15, + 78, # 6380 + 24, + 36, + 15, + 18, + 11, + 15, + 15, + 42, + 15, + 48, + 15, + 15, + 15, + 52, + 15, + 15, + 15, + 16, + 15, + 48, # 6400 + 15, + 6420, + 15, + 22, + 15, + 24, + 15, + 6426, + 15, + 15, + 15, + 58, + 15, + 15, + 13, + 15, + 15, + 40, + 10, + 46, # 6420 + 15, + 15, + 15, + 16, + 15, + 15, + 15, + 15, + 15, + 6448, + 15, + 6450, + 11, + 26, + 13, + 16, + 15, + 15, + 15, + 15, # 6440 + 15, + 15, + 15, + 22, + 63, + 15, + 15, + 28, + 15, + 6468, + 12, + 15, + 15, + 6472, + 15, + 15, + 15, + 15, + 15, + 15, # 6460 + 15, + 6480, + 15, + 15, + 13, + 15, + 13, + 15, + 15, + 15, + 15, + 6490, + 15, + 42, + 15, + 15, + 31, + 72, + 13, + 66, # 6480 + 15, + 15, + 12, + 15, + 11, + 15, + 15, + 26, + 15, + 22, + 15, + 16, + 15, + 15, + 13, + 15, + 15, + 18, + 12, + 16, # 6500 + 11, + 6520, + 15, + 15, + 15, + 15, + 15, + 60, + 24, + 6528, + 13, + 15, + 15, + 46, + 11, + 17, + 12, + 15, + 15, + 15, # 6520 + 15, + 30, + 30, + 15, + 15, + 15, + 15, + 6546, + 11, + 15, + 14, + 6550, + 11, + 6552, + 12, + 15, + 15, + 78, + 16, + 30, # 6540 + 31, + 6560, + 15, + 6562, + 22, + 15, + 24, + 16, + 26, + 6568, + 28, + 6570, + 30, + 30, + 30, + 24, + 15, + 6576, + 30, + 15, # 6560 + 11, + 6580, + 30, + 30, + 30, + 15, + 11, + 15, + 30, + 30, + 30, + 30, + 63, + 30, + 30, + 15, + 11, + 15, + 11, + 6598, # 6580 + 30, + 15, + 30, + 15, + 11, + 30, + 10, + 6606, + 30, + 15, + 10, + 30, + 30, + 30, + 30, + 16, + 11, + 30, + 11, + 6618, # 6600 + 30, + 15, + 30, + 36, + 30, + 52, + 11, + 15, + 11, + 15, + 30, + 30, + 11, + 15, + 11, + 30, + 11, + 6636, + 30, + 15, # 6620 + 15, + 30, + 30, + 15, + 30, + 15, + 11, + 30, + 30, + 60, + 30, + 15, + 11, + 6652, + 30, + 15, + 15, + 15, + 11, + 6658, # 6640 + 11, + 6660, + 30, + 15, + 11, + 15, + 30, + 58, + 30, + 30, + 12, + 15, + 30, + 6672, + 12, + 15, + 11, + 30, + 30, + 6678, # 6660 + 30, + 15, + 12, + 40, + 12, + 15, + 14, + 15, + 18, + 6688, + 30, + 6690, + 30, + 15, + 11, + 15, + 12, + 36, + 30, + 15, # 6680 + 14, + 6700, + 12, + 6702, + 30, + 16, + 11, + 30, + 30, + 6708, + 30, + 15, + 11, + 48, + 30, + 15, + 11, + 15, + 14, + 6718, # 6700 + 30, + 30, + 30, + 80, + 11, + 24, + 12, + 23, + 11, + 15, + 11, + 52, + 51, + 6732, + 30, + 48, + 15, + 6736, + 30, + 22, # 6720 + 30, + 42, + 11, + 40, + 12, + 15, + 11, + 15, + 16, + 16, + 18, + 42, + 31, + 30, + 22, + 28, + 24, + 28, + 26, + 15, # 6740 + 28, + 6760, + 30, + 6762, + 12, + 15, + 10, + 66, + 36, + 17, + 11, + 15, + 40, + 15, + 42, + 24, + 15, + 26, + 46, + 6778, # 6760 + 48, + 6780, + 15, + 15, + 52, + 15, + 15, + 17, + 12, + 15, + 13, + 6790, + 15, + 6792, + 15, + 15, + 15, + 15, + 15, + 15, # 6780 + 15, + 15, + 15, + 6802, + 15, + 17, + 15, + 15, + 15, + 23, + 15, + 48, + 15, + 15, + 15, + 15, + 15, + 16, + 15, + 15, # 6800 + 15, + 18, + 15, + 6822, + 15, + 24, + 15, + 6826, + 15, + 6828, + 15, + 15, + 15, + 6832, + 15, + 15, + 15, + 15, + 15, + 15, # 6820 + 15, + 6840, + 15, + 15, + 15, + 15, + 15, + 40, + 63, + 21, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 6856, + 15, + 6858, # 6840 + 15, + 15, + 15, + 6862, + 15, + 15, + 15, + 15, + 15, + 6868, + 15, + 6870, + 15, + 16, + 15, + 15, + 15, + 15, + 15, + 15, # 6860 + 31, + 15, + 15, + 6882, + 15, + 15, + 15, + 70, + 15, + 6888, + 15, + 15, + 15, + 60, + 15, + 15, + 15, + 15, + 15, + 6898, # 6880 + 15, + 66, + 15, + 15, + 15, + 15, + 15, + 6906, + 15, + 15, + 15, + 6910, + 26, + 30, + 30, + 15, + 15, + 6916, + 15, + 30, # 6900 + 15, + 16, + 15, + 30, + 15, + 30, + 15, + 15, + 15, + 40, + 16, + 30, + 18, + 15, + 15, + 30, + 22, + 24, + 24, + 26, # 6920 + 26, + 30, + 28, + 52, + 31, + 30, + 30, + 6946, + 15, + 6948, + 30, + 15, + 15, + 30, + 30, + 30, + 30, + 15, + 15, + 6958, # 6940 + 30, + 6960, + 30, + 30, + 15, + 30, + 30, + 6966, + 15, + 16, + 15, + 6970, + 30, + 18, + 30, + 15, + 63, + 6976, + 15, + 30, # 6960 + 30, + 15, + 15, + 6982, + 30, + 30, + 30, + 15, + 15, + 30, + 15, + 6990, + 30, + 15, + 30, + 30, + 30, + 6996, + 15, + 15, # 6980 + 15, + 7000, + 30, + 46, + 15, + 15, + 15, + 30, + 15, + 42, + 30, + 15, + 15, + 7012, + 30, + 15, + 30, + 15, + 15, + 7018, # 7000 + 30, + 30, + 30, + 15, + 15, + 24, + 30, + 7026, + 15, + 15, + 15, + 78, + 15, + 30, + 30, + 15, + 15, + 30, + 30, + 7038, # 7020 + 30, + 30, + 15, + 7042, + 30, + 30, + 15, + 30, + 15, + 52, + 30, + 30, + 30, + 30, + 16, + 30, + 18, + 7056, + 15, + 30, # 7040 + 22, + 30, + 30, + 30, + 30, + 30, + 28, + 36, + 30, + 7068, + 30, + 15, + 16, + 30, + 30, + 30, + 30, + 30, + 30, + 7078, # 7060 + 30, + 72, + 30, + 15, + 30, + 30, + 30, + 30, + 15, + 30, + 30, + 15, + 30, + 40, + 30, + 30, + 30, + 46, + 30, + 39, # 7080 + 30, + 30, + 15, + 7102, + 30, + 30, + 30, + 30, + 30, + 7108, + 30, + 30, + 30, + 30, + 15, + 30, + 30, + 30, + 30, + 30, # 7100 + 30, + 7120, + 22, + 16, + 30, + 15, + 30, + 7126, + 28, + 7128, + 30, + 30, + 30, + 30, + 30, + 30, + 31, + 30, + 30, + 58, # 7120 + 30, + 36, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 7150, + 30, + 22, + 13, + 30, + 15, + 30, + 30, + 7158, # 7140 + 30, + 16, + 30, + 30, + 30, + 30, + 30, + 15, + 30, + 66, + 30, + 70, + 30, + 30, + 30, + 30, + 30, + 7176, + 30, + 30, # 7160 + 30, + 42, + 30, + 15, + 15, + 30, + 30, + 7186, + 30, + 30, + 13, + 15, + 13, + 7192, + 30, + 30, + 30, + 30, + 15, + 30, # 7180 + 30, + 18, + 30, + 30, + 30, + 30, + 30, + 7206, + 30, + 80, + 30, + 7210, + 30, + 7212, + 15, + 15, + 30, + 30, + 30, + 7218, # 7200 + 30, + 15, + 10, + 30, + 30, + 30, + 30, + 30, + 30, + 7228, + 30, + 30, + 63, + 30, + 30, + 30, + 30, + 7236, + 30, + 30, # 7220 + 16, + 30, + 18, + 7242, + 14, + 30, + 22, + 7246, + 30, + 30, + 30, + 30, + 28, + 7252, + 30, + 30, + 30, + 15, + 13, + 30, # 7240 + 30, + 52, + 30, + 30, + 31, + 30, + 30, + 42, + 30, + 15, + 30, + 30, + 30, + 30, + 13, + 30, + 30, + 18, + 30, + 30, # 7260 + 30, + 30, + 30, + 7282, + 30, + 15, + 11, + 30, + 12, + 36, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 7296, + 30, + 30, # 7280 + 15, + 48, + 30, + 66, + 30, + 30, + 30, + 7306, + 15, + 7308, + 30, + 16, + 30, + 70, + 13, + 15, + 13, + 30, + 15, + 30, # 7300 + 30, + 7320, + 30, + 30, + 30, + 24, + 30, + 16, + 31, + 30, + 30, + 7330, + 30, + 7332, + 15, + 15, + 30, + 15, + 15, + 40, # 7320 + 15, + 30, + 15, + 30, + 30, + 15, + 15, + 15, + 30, + 7348, + 30, + 7350, + 15, + 15, + 30, + 30, + 15, + 15, + 15, + 30, # 7340 + 30, + 30, + 30, + 36, + 15, + 30, + 15, + 52, + 15, + 7368, + 15, + 30, + 30, + 72, + 30, + 58, + 15, + 15, + 15, + 46, # 7360 + 30, + 60, + 15, + 30, + 15, + 30, + 30, + 82, + 15, + 30, + 30, + 30, + 30, + 7392, + 15, + 15, + 30, + 16, + 15, + 48, # 7380 + 24, + 15, + 30, + 30, + 30, + 15, + 15, + 15, + 15, + 30, + 30, + 7410, + 15, + 15, + 30, + 30, + 30, + 7416, + 15, + 30, # 7400 + 30, + 40, + 30, + 15, + 28, + 30, + 16, + 30, + 18, + 16, + 15, + 30, + 22, + 7432, + 30, + 20, + 26, + 30, + 28, + 42, # 7420 + 30, + 30, + 30, + 18, + 15, + 30, + 30, + 22, + 15, + 30, + 30, + 7450, + 30, + 28, + 15, + 15, + 31, + 7456, + 30, + 7458, # 7440 + 15, + 30, + 30, + 16, + 15, + 15, + 15, + 30, + 30, + 15, + 30, + 30, + 30, + 30, + 15, + 30, + 30, + 7476, + 15, + 30, # 7460 + 30, + 7480, + 30, + 30, + 15, + 30, + 15, + 7486, + 30, + 7488, + 30, + 30, + 30, + 58, + 57, + 15, + 24, + 54, + 30, + 7498, # 7480 + 28, + 30, + 30, + 48, + 30, + 46, + 30, + 7506, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 36, + 30, + 7516, + 30, + 72, # 7500 + 30, + 30, + 30, + 7522, + 30, + 31, + 15, + 30, + 15, + 7528, + 36, + 16, + 30, + 30, + 40, + 30, + 42, + 7536, + 30, + 30, # 7520 + 46, + 7540, + 48, + 30, + 30, + 30, + 52, + 7546, + 30, + 7548, + 30, + 30, + 58, + 30, + 30, + 30, + 22, + 30, + 30, + 7558, # 7540 + 30, + 7560, + 28, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 66, + 30, + 7572, + 30, + 30, + 30, + 7576, + 30, + 30, # 7560 + 30, + 30, + 30, + 7582, + 30, + 30, + 30, + 26, + 30, + 7588, + 30, + 7590, + 30, + 15, + 30, + 16, + 30, + 70, + 30, + 30, # 7580 + 30, + 30, + 30, + 7602, + 30, + 30, + 30, + 7606, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 39, + 58, + 30, + 13, + 30, # 7600 + 30, + 7620, + 30, + 30, + 15, + 60, + 15, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 15, + 30, + 30, + 30, + 7638, # 7620 + 30, + 30, + 30, + 7642, + 30, + 15, + 30, + 15, + 31, + 7648, + 30, + 30, + 30, + 30, + 30, + 15, + 15, + 15, + 30, + 30, # 7640 + 30, + 46, + 30, + 78, + 30, + 30, + 15, + 30, + 30, + 7668, + 30, + 30, + 30, + 7672, + 14, + 30, + 15, + 15, + 15, + 30, # 7660 + 15, + 7680, + 30, + 30, + 30, + 15, + 15, + 7686, + 15, + 15, + 30, + 7690, + 15, + 48, + 30, + 30, + 30, + 42, + 30, + 7698, # 7680 + 30, + 30, + 30, + 7702, + 30, + 15, + 30, + 15, + 15, + 15, + 30, + 17, + 31, + 30, + 30, + 15, + 15, + 7716, + 15, + 15, # 7700 + 14, + 15, + 14, + 7722, + 30, + 30, + 30, + 7726, + 15, + 58, + 30, + 30, + 30, + 15, + 15, + 30, + 15, + 15, + 14, + 70, # 7720 + 13, + 7740, + 15, + 30, + 63, + 30, + 15, + 60, + 59, + 15, + 15, + 56, + 15, + 7752, + 14, + 15, + 30, + 7756, + 17, + 7758, # 7740 + 30, + 15, + 30, + 16, + 16, + 17, + 30, + 15, + 28, + 38, + 22, + 36, + 30, + 15, + 30, + 24, + 31, + 30, + 30, + 31, # 7760 + 14, + 30, + 30, + 42, + 36, + 15, + 14, + 30, + 40, + 7788, + 42, + 30, + 15, + 7792, + 46, + 15, + 48, + 30, + 16, + 30, # 7780 + 56, + 28, + 15, + 30, + 22, + 15, + 58, + 36, + 60, + 30, + 28, + 72, + 30, + 30, + 30, + 15, + 15, + 7816, + 30, + 16, # 7800 + 15, + 30, + 30, + 7822, + 30, + 24, + 14, + 15, + 30, + 7828, + 30, + 40, + 15, + 30, + 30, + 16, + 15, + 16, + 13, + 30, # 7820 + 30, + 7840, + 30, + 15, + 14, + 30, + 15, + 30, + 30, + 46, + 15, + 30, + 30, + 7852, + 30, + 15, + 15, + 80, + 13, + 30, # 7840 + 30, + 23, + 30, + 30, + 30, + 15, + 15, + 7866, + 15, + 15, + 30, + 30, + 15, + 7872, + 13, + 30, + 15, + 7876, + 30, + 7878, # 7860 + 15, + 30, + 30, + 7882, + 30, + 15, + 15, + 30, + 30, + 30, + 30, + 15, + 15, + 15, + 30, + 15, + 15, + 52, + 15, + 30, # 7880 + 15, + 7900, + 30, + 15, + 18, + 15, + 30, + 7906, + 30, + 30, + 15, + 26, + 30, + 40, + 15, + 16, + 15, + 30, + 30, + 7918, # 7900 + 30, + 7920, + 15, + 30, + 15, + 24, + 15, + 7926, + 15, + 30, + 30, + 30, + 30, + 7932, + 15, + 15, + 30, + 7936, + 30, + 16, # 7920 + 15, + 30, + 30, + 46, + 30, + 15, + 30, + 30, + 30, + 7948, + 30, + 7950, + 30, + 16, + 30, + 18, + 15, + 72, + 30, + 22, # 7940 + 30, + 30, + 30, + 7962, + 30, + 28, + 30, + 30, + 31, + 30, + 15, + 15, + 30, + 30, + 30, + 15, + 30, + 30, + 30, + 78, # 7960 + 30, + 22, + 15, + 30, + 30, + 30, + 30, + 48, + 30, + 30, + 22, + 60, + 30, + 7992, + 30, + 30, + 28, + 30, + 30, + 30, # 7980 + 63, + 30, + 30, + 52, + 30, + 15, + 30, + 30, + 30, + 8008, + 30, + 8010, + 30, + 18, + 30, + 30, + 30, + 8016, + 30, + 30, # 8000 + 30, + 15, + 30, + 70, + 30, + 30, + 30, + 22, + 30, + 15, + 30, + 30, + 31, + 30, + 30, + 15, + 30, + 30, + 30, + 8038, # 8020 + 30, + 15, + 30, + 30, + 30, + 30, + 30, + 15, + 30, + 30, + 30, + 82, + 15, + 8052, + 30, + 15, + 30, + 30, + 15, + 8058, # 8040 + 15, + 30, + 30, + 30, + 30, + 15, + 15, + 30, + 30, + 8068, + 30, + 15, + 30, + 30, + 30, + 30, + 30, + 40, + 30, + 15, # 8060 + 30, + 8080, + 15, + 58, + 30, + 30, + 30, + 8086, + 30, + 8088, + 15, + 15, + 30, + 8092, + 30, + 30, + 31, + 18, + 30, + 30, # 8080 + 15, + 8100, + 30, + 30, + 30, + 30, + 30, + 66, + 15, + 30, + 15, + 8110, + 15, + 25, + 15, + 30, + 30, + 8116, + 30, + 22, # 8100 + 15, + 15, + 15, + 8122, + 30, + 15, + 15, + 30, + 63, + 62, + 30, + 46, + 59, + 30, + 30, + 30, + 30, + 78, + 53, + 15, # 8120 + 51, + 17, + 15, + 16, + 30, + 27, + 30, + 8146, + 30, + 28, + 41, + 22, + 39, + 30, + 30, + 26, + 30, + 28, + 33, + 40, # 8140 + 31, + 8160, + 29, + 30, + 30, + 36, + 30, + 8166, + 23, + 40, + 21, + 8170, + 18, + 15, + 17, + 46, + 22, + 48, + 30, + 8178, # 8160 + 26, + 80, + 28, + 48, + 30, + 30, + 30, + 58, + 26, + 60, + 30, + 8190, + 8191, + 30, + 30, + 30, + 30, + 15, + 15, + 24, # 8180 + 30, + 58, + 30, + 30, + 15, + 30, + 30, + 28, + 30, + 8208, + 30, + 30, + 30, + 42, + 30, + 22, + 15, + 30, + 30, + 8218, # 8200 + 30, + 8220, + 15, + 30, + 31, + 30, + 30, + 18, + 15, + 30, + 15, + 8230, + 30, + 8232, + 30, + 30, + 30, + 8236, + 15, + 57, # 8220 + 15, + 15, + 30, + 8242, + 15, + 15, + 15, + 30, + 15, + 72, + 30, + 36, + 15, + 30, + 30, + 15, + 62, + 22, + 15, + 30, # 8240 + 30, + 30, + 30, + 8262, + 15, + 15, + 30, + 18, + 15, + 8268, + 15, + 30, + 15, + 8272, + 30, + 24, + 15, + 15, + 30, + 30, # 8260 + 30, + 48, + 14, + 15, + 30, + 30, + 15, + 8286, + 15, + 30, + 30, + 8290, + 30, + 8292, + 15, + 30, + 15, + 8296, + 15, + 42, # 8280 + 15, + 30, + 30, + 30, + 30, + 16, + 15, + 15, + 15, + 15, + 30, + 8310, + 15, + 30, + 15, + 30, + 30, + 8316, + 15, + 30, # 8300 + 30, + 52, + 30, + 15, + 15, + 17, + 30, + 25, + 15, + 8328, + 15, + 15, + 30, + 30, + 30, + 15, + 15, + 15, + 14, + 30, # 8320 + 30, + 18, + 15, + 80, + 30, + 30, + 30, + 16, + 15, + 30, + 30, + 30, + 30, + 8352, + 14, + 30, + 16, + 60, + 18, + 15, # 8340 + 14, + 57, + 22, + 8362, + 30, + 30, + 26, + 30, + 28, + 8368, + 30, + 30, + 30, + 30, + 15, + 66, + 30, + 8376, + 30, + 30, # 8360 + 30, + 30, + 30, + 82, + 63, + 30, + 30, + 8386, + 30, + 8388, + 15, + 30, + 30, + 22, + 30, + 16, + 30, + 30, + 30, + 36, # 8380 + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 15, + 30, + 30, + 30, + 30, + 46, + 15, + 30, + 31, + 30, + 30, + 8418, # 8400 + 30, + 30, + 30, + 8422, + 22, + 24, + 24, + 15, + 30, + 8428, + 28, + 8430, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, # 8420 + 30, + 30, + 30, + 8442, + 30, + 30, + 30, + 8446, + 30, + 30, + 30, + 30, + 30, + 78, + 30, + 15, + 15, + 30, + 15, + 30, # 8440 + 30, + 8460, + 30, + 30, + 30, + 30, + 30, + 8466, + 30, + 16, + 30, + 42, + 30, + 36, + 30, + 30, + 30, + 48, + 30, + 60, # 8460 + 30, + 30, + 30, + 30, + 30, + 15, + 22, + 30, + 30, + 30, + 30, + 30, + 28, + 15, + 29, + 30, + 30, + 30, + 30, + 30, # 8480 + 29, + 8500, + 30, + 15, + 30, + 30, + 30, + 46, + 30, + 66, + 65, + 16, + 30, + 8512, + 30, + 15, + 29, + 15, + 30, + 56, # 8500 + 30, + 8520, + 30, + 15, + 29, + 15, + 30, + 8526, + 30, + 30, + 30, + 44, + 30, + 42, + 29, + 30, + 30, + 8536, + 30, + 8538, # 8520 + 30, + 31, + 29, + 8542, + 29, + 30, + 36, + 30, + 15, + 82, + 40, + 30, + 42, + 15, + 15, + 20, + 46, + 42, + 48, + 30, # 8540 + 29, + 30, + 52, + 8562, + 30, + 30, + 30, + 30, + 58, + 30, + 60, + 30, + 30, + 8572, + 30, + 24, + 66, + 30, + 30, + 28, # 8560 + 30, + 8580, + 30, + 15, + 29, + 22, + 15, + 30, + 30, + 18, + 30, + 70, + 30, + 30, + 30, + 30, + 30, + 8596, + 30, + 8598, # 8580 + 30, + 15, + 30, + 30, + 16, + 30, + 18, + 15, + 31, + 8608, + 22, + 78, + 30, + 30, + 29, + 30, + 28, + 30, + 30, + 30, # 8600 + 30, + 36, + 15, + 8622, + 30, + 16, + 30, + 8626, + 30, + 8628, + 30, + 15, + 29, + 88, + 30, + 30, + 30, + 30, + 15, + 52, # 8620 + 30, + 8640, + 30, + 16, + 30, + 30, + 30, + 8646, + 30, + 15, + 15, + 40, + 30, + 30, + 30, + 16, + 29, + 30, + 30, + 30, # 8640 + 30, + 15, + 29, + 8662, + 30, + 30, + 30, + 80, + 30, + 8668, + 30, + 30, + 31, + 15, + 15, + 24, + 30, + 8676, + 15, + 15, # 8660 + 15, + 8680, + 15, + 30, + 30, + 15, + 15, + 30, + 30, + 8688, + 30, + 15, + 15, + 8692, + 30, + 30, + 30, + 15, + 15, + 8698, # 8680 + 30, + 18, + 15, + 16, + 16, + 30, + 15, + 8706, + 30, + 15, + 15, + 30, + 30, + 8712, + 30, + 30, + 15, + 30, + 30, + 8718, # 8700 + 15, + 30, + 15, + 30, + 30, + 30, + 30, + 30, + 16, + 30, + 18, + 8730, + 15, + 30, + 22, + 30, + 30, + 8736, + 30, + 30, # 8720 + 28, + 8740, + 30, + 30, + 30, + 15, + 15, + 8746, + 30, + 30, + 30, + 30, + 30, + 8752, + 30, + 30, + 30, + 15, + 30, + 30, # 8740 + 30, + 8760, + 15, + 30, + 30, + 15, + 30, + 30, + 63, + 30, + 30, + 48, + 30, + 30, + 30, + 30, + 15, + 66, + 30, + 8778, # 8760 + 30, + 30, + 30, + 8782, + 30, + 30, + 30, + 30, + 15, + 30, + 30, + 58, + 30, + 30, + 30, + 30, + 22, + 30, + 30, + 30, # 8780 + 31, + 30, + 28, + 8802, + 30, + 30, + 30, + 8806, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 8818, # 8800 + 30, + 8820, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 80, + 30, + 8830, + 30, + 72, + 30, + 15, + 30, + 8836, + 30, + 8838, # 8820 + 30, + 15, + 30, + 36, + 30, + 30, + 30, + 30, + 30, + 8848, + 30, + 52, + 30, + 30, + 30, + 30, + 30, + 16, + 30, + 30, # 8840 + 30, + 8860, + 30, + 8862, + 31, + 15, + 15, + 8866, + 30, + 48, + 30, + 30, + 15, + 30, + 30, + 70, + 30, + 30, + 30, + 30, # 8860 + 30, + 82, + 30, + 15, + 30, + 28, + 30, + 8886, + 15, + 15, + 30, + 30, + 30, + 8892, + 30, + 16, + 63, + 15, + 30, + 30, # 8880 + 30, + 30, + 30, + 30, + 30, + 30, + 15, + 30, + 30, + 58, + 30, + 30, + 30, + 30, + 15, + 30, + 15, + 36, + 15, + 30, # 8900 + 15, + 30, + 30, + 8922, + 30, + 15, + 15, + 78, + 15, + 8928, + 30, + 30, + 15, + 8932, + 30, + 30, + 30, + 30, + 30, + 30, # 8920 + 30, + 8940, + 30, + 30, + 30, + 40, + 30, + 22, + 15, + 30, + 30, + 8950, + 30, + 30, + 30, + 15, + 15, + 52, + 15, + 30, # 8940 + 30, + 30, + 30, + 8962, + 30, + 30, + 30, + 30, + 30, + 8968, + 30, + 8970, + 30, + 18, + 30, + 30, + 16, + 46, + 18, + 15, # 8960 + 30, + 30, + 30, + 30, + 30, + 30, + 26, + 30, + 30, + 88, + 30, + 36, + 31, + 30, + 15, + 30, + 30, + 15, + 30, + 8998, # 8980 + 30, + 9000, + 30, + 15, + 15, + 30, + 30, + 9006, + 30, + 30, + 15, + 9010, + 30, + 9012, + 30, + 16, + 30, + 70, + 69, + 30, # 9000 + 30, + 66, + 15, + 30, + 30, + 30, + 30, + 60, + 15, + 9028, + 30, + 30, + 30, + 15, + 16, + 30, + 30, + 30, + 30, + 48, # 9020 + 30, + 9040, + 30, + 9042, + 30, + 15, + 28, + 82, + 30, + 9048, + 30, + 15, + 15, + 34, + 36, + 30, + 31, + 30, + 40, + 9058, # 9040 + 42, + 16, + 30, + 24, + 46, + 30, + 48, + 9066, + 30, + 18, + 52, + 46, + 30, + 42, + 15, + 15, + 58, + 30, + 60, + 30, # 9060 + 30, + 63, + 15, + 30, + 66, + 30, + 30, + 30, + 70, + 60, + 30, + 9090, + 15, + 30, + 15, + 30, + 30, + 30, + 30, + 30, # 9080 + 16, + 30, + 18, + 9102, + 15, + 30, + 22, + 30, + 30, + 9108, + 30, + 30, + 28, + 30, + 30, + 30, + 30, + 15, + 15, + 30, # 9100 + 30, + 30, + 30, + 30, + 30, + 72, + 30, + 9126, + 30, + 16, + 30, + 30, + 30, + 9132, + 15, + 30, + 30, + 9136, + 30, + 30, # 9120 + 30, + 30, + 30, + 40, + 30, + 15, + 15, + 30, + 15, + 30, + 30, + 9150, + 63, + 80, + 30, + 30, + 30, + 9156, + 30, + 30, # 9140 + 15, + 9160, + 30, + 16, + 30, + 30, + 30, + 88, + 15, + 52, + 30, + 30, + 30, + 9172, + 15, + 24, + 15, + 30, + 15, + 66, # 9160 + 30, + 9180, + 30, + 30, + 30, + 30, + 30, + 9186, + 30, + 30, + 30, + 30, + 30, + 28, + 15, + 15, + 30, + 30, + 30, + 9198, # 9180 + 30, + 30, + 30, + 9202, + 30, + 30, + 15, + 15, + 30, + 9208, + 30, + 60, + 15, + 15, + 30, + 30, + 30, + 30, + 15, + 30, # 9200 + 30, + 9220, + 30, + 22, + 15, + 30, + 15, + 9226, + 30, + 18, + 30, + 30, + 30, + 30, + 30, + 15, + 30, + 15, + 15, + 9238, # 9220 + 30, + 9240, + 30, + 30, + 15, + 30, + 30, + 16, + 31, + 30, + 30, + 30, + 30, + 18, + 15, + 15, + 30, + 9256, + 15, + 46, # 9240 + 15, + 26, + 30, + 58, + 30, + 16, + 15, + 15, + 15, + 15, + 15, + 72, + 71, + 15, + 30, + 68, + 30, + 9276, + 15, + 30, # 9260 + 63, + 9280, + 30, + 9282, + 15, + 30, + 15, + 36, + 16, + 15, + 18, + 30, + 15, + 9292, + 30, + 48, + 24, + 15, + 26, + 16, # 9280 + 28, + 70, + 30, + 31, + 15, + 17, + 30, + 40, + 36, + 30, + 30, + 9310, + 40, + 66, + 42, + 30, + 30, + 26, + 46, + 9318, # 9300 + 48, + 30, + 30, + 9322, + 52, + 24, + 30, + 15, + 15, + 30, + 58, + 17, + 60, + 30, + 30, + 63, + 68, + 9336, + 66, + 30, # 9320 + 30, + 9340, + 70, + 9342, + 72, + 30, + 30, + 15, + 15, + 9348, + 15, + 40, + 30, + 46, + 30, + 15, + 16, + 15, + 15, + 48, # 9340 + 30, + 15, + 15, + 15, + 30, + 15, + 30, + 16, + 15, + 26, + 15, + 9370, + 30, + 15, + 15, + 15, + 31, + 9376, + 15, + 82, # 9360 + 15, + 15, + 15, + 17, + 15, + 15, + 15, + 15, + 15, + 40, + 15, + 9390, + 15, + 15, + 15, + 15, + 15, + 9396, + 15, + 15, # 9380 + 15, + 15, + 15, + 9402, + 15, + 15, + 15, + 22, + 15, + 9408, + 15, + 15, + 15, + 9412, + 15, + 15, + 15, + 15, + 15, + 9418, # 9400 + 15, + 9420, + 15, + 26, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 9430, + 15, + 9432, + 15, + 15, + 15, + 9436, + 15, + 9438, # 9420 + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 15, + 29, + 15, + 16, + 15, + 48, + 15, + 15, # 9440 + 15, + 9460, + 15, + 9462, + 15, + 15, + 15, + 9466, + 15, + 16, + 15, + 15, + 36, + 9472, + 15, + 24, + 15, + 18, + 15, + 9478, # 9460 + 15, + 18, + 15, + 15, + 15, + 23, + 15, + 52, + 15, + 16, + 15, + 9490, + 15, + 15, + 15, + 22, + 15, + 9496, + 15, + 26, # 9480 + 15, + 28, + 15, + 30, + 31, + 18, + 15, + 15, + 15, + 36, + 15, + 9510, + 15, + 17, + 15, + 15, + 15, + 30, + 30, + 15, # 9500 + 15, + 9520, + 15, + 88, + 15, + 15, + 15, + 30, + 15, + 30, + 15, + 26, + 15, + 9532, + 16, + 30, + 63, + 15, + 15, + 9538, # 9520 + 22, + 15, + 24, + 15, + 26, + 30, + 28, + 9546, + 30, + 30, + 30, + 9550, + 15, + 40, + 30, + 15, + 15, + 30, + 30, + 78, # 9540 + 30, + 15, + 15, + 72, + 30, + 30, + 30, + 30, + 31, + 30, + 30, + 17, + 15, + 15, + 15, + 30, + 30, + 60, + 30, + 15, # 9560 + 15, + 30, + 15, + 30, + 30, + 15, + 15, + 9586, + 30, + 42, + 30, + 15, + 15, + 52, + 15, + 30, + 30, + 15, + 30, + 30, # 9580 + 30, + 9600, + 15, + 15, + 15, + 15, + 30, + 30, + 15, + 15, + 15, + 30, + 15, + 9612, + 30, + 15, + 15, + 58, + 30, + 9618, # 9600 + 30, + 15, + 15, + 9622, + 30, + 30, + 30, + 15, + 15, + 9628, + 30, + 9630, + 31, + 15, + 15, + 30, + 15, + 30, + 30, + 15, # 9620 + 15, + 30, + 30, + 9642, + 30, + 30, + 15, + 30, + 30, + 9648, + 15, + 30, + 15, + 48, + 30, + 30, + 30, + 30, + 16, + 30, # 9640 + 18, + 9660, + 15, + 30, + 63, + 30, + 30, + 30, + 30, + 30, + 28, + 30, + 30, + 30, + 30, + 15, + 15, + 9676, + 30, + 9678, # 9660 + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 15, + 30, + 9688, + 30, + 30, + 15, + 30, + 30, + 17, + 30, + 9696, + 30, + 30, # 9680 + 30, + 88, + 30, + 30, + 30, + 30, + 15, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 15, + 9718, # 9700 + 30, + 9720, + 30, + 30, + 30, + 30, + 22, + 70, + 30, + 30, + 30, + 36, + 28, + 9732, + 30, + 30, + 30, + 30, + 30, + 9738, # 9720 + 30, + 30, + 30, + 9742, + 30, + 30, + 30, + 30, + 30, + 9748, + 30, + 48, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, # 9740 + 30, + 42, + 30, + 30, + 30, + 16, + 30, + 9766, + 30, + 9768, + 30, + 16, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, # 9760 + 30, + 9780, + 30, + 30, + 30, + 30, + 30, + 9786, + 30, + 30, + 30, + 9790, + 30, + 30, + 30, + 16, + 15, + 96, + 30, + 40, # 9780 + 30, + 80, + 15, + 9802, + 30, + 15, + 30, + 30, + 30, + 30, + 30, + 9810, + 30, + 15, + 30, + 15, + 30, + 9816, + 15, + 15, # 9800 + 30, + 30, + 30, + 30, + 31, + 16, + 15, + 30, + 30, + 9828, + 30, + 30, + 30, + 9832, + 30, + 30, + 15, + 30, + 30, + 9838, # 9820 + 30, + 30, + 30, + 30, + 16, + 30, + 18, + 42, + 15, + 30, + 22, + 9850, + 30, + 58, + 30, + 30, + 28, + 9856, + 30, + 9858, # 9840 + 30, + 30, + 15, + 30, + 30, + 30, + 30, + 30, + 30, + 70, + 30, + 9870, + 30, + 30, + 30, + 78, + 30, + 30, + 17, + 30, # 9860 + 30, + 40, + 30, + 9882, + 30, + 30, + 30, + 9886, + 30, + 15, + 15, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, # 9880 + 30, + 9900, + 30, + 30, + 30, + 30, + 30, + 9906, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 30, + 46, + 30, + 15, # 9900 + 16, + 30, + 30, + 9922, + 30, + 24, + 30, + 30, + 30, + 9928, + 30, + 9930, + 30, + 30, + 30, + 30, + 30, + 39, + 15, + 15, # 9920 + 30, + 9940, + 30, + 60, + 30, + 30, + 30, + 30, + 30, + 9948, + 17, + 15, + 31, + 36, + 30, + 30, + 15, + 16, + 30, + 46, # 9940 + 30, + 30, + 15, + 40, + 30, + 30, + 30, + 9966, + 15, + 30, + 15, + 58, + 30, + 9972, + 30, + 30, + 30, + 30, + 30, + 30, # 9960 + 30, + 15, + 15, + 66, + 30, + 30, + 30, + 30, + 15, + 30, + 30, + 96, + 30, + 30, + 30, + 30, + 30, + 18, + 15, + 15, # 9980 ) diff --git a/src/sage/combinat/designs/all.py b/src/sage/combinat/designs/all.py index bf00b490c3b..3085a69435e 100644 --- a/src/sage/combinat/designs/all.py +++ b/src/sage/combinat/designs/all.py @@ -35,23 +35,23 @@ - :ref:`sage.combinat.designs.subhypergraph_search` - :ref:`sage.combinat.designs.evenly_distributed_sets` """ + # install the docstring of this module to the containing package from sage.misc.namespace_package import install_doc + install_doc(__package__, __doc__) from sage.misc.lazy_import import lazy_import lazy_import('sage.combinat.designs.incidence_structures', 'IncidenceStructure') -lazy_import('sage.combinat.designs.incidence_structures', - 'IncidenceStructure', 'BlockDesign') +lazy_import('sage.combinat.designs.incidence_structures', 'IncidenceStructure', 'BlockDesign') -lazy_import('sage.combinat.designs.incidence_structures', - 'IncidenceStructure', as_='Hypergraph') +lazy_import('sage.combinat.designs.incidence_structures', 'IncidenceStructure', as_='Hypergraph') -lazy_import('sage.combinat.designs.covering_design', - ['CoveringDesign', 'schonheim', 'trivial_covering_design']) +lazy_import('sage.combinat.designs.covering_design', ['CoveringDesign', 'schonheim', 'trivial_covering_design']) from sage.combinat.designs import design_catalog as designs + del lazy_import del install_doc diff --git a/src/sage/combinat/designs/bibd.py b/src/sage/combinat/designs/bibd.py index 6ce3385d5a7..9ff0128854e 100644 --- a/src/sage/combinat/designs/bibd.py +++ b/src/sage/combinat/designs/bibd.py @@ -106,8 +106,8 @@ def biplane(n, existence=False): ....: if designs.biplane(n, existence=True) is True] [0, 1, 2, 3, 4, 7, 9, 11] """ - k = n+2 - v = (k*(k-1))//2 + 1 + k = n + 2 + v = (k * (k - 1)) // 2 + 1 return balanced_incomplete_block_design(v, k, lambd=2, existence=existence) @@ -248,21 +248,25 @@ def balanced_incomplete_block_design(v, k, lambd=1, existence=False, use_LJCR=Fa if k == v: if existence: return True - return BIBD(v, [list(range(v)) for _ in range(lambd)],lambd=lambd, check=False, copy=False) + return BIBD(v, [list(range(v)) for _ in range(lambd)], lambd=lambd, check=False, copy=False) # Non-existence of BIBD - if (v < k or - k < 2 or - (lambd*(v-1)) % (k-1) != 0 or - (lambd*v*(v-1)) % (k*(k-1)) != 0 or + if ( + v < k + or k < 2 + or (lambd * (v - 1)) % (k - 1) != 0 + or (lambd * v * (v - 1)) % (k * (k - 1)) != 0 + or # From the Handbook of combinatorial designs: # # With lambda>1 other exceptions are # (15,5,2),(21,6,2),(22,7,2),(22,8,4). - (k == 6 and v in [36,46]) or - (k == 7 and v == 43) or + (k == 6 and v in [36, 46]) + or (k == 7 and v == 43) + or # Fisher's inequality - (lambd*v*(v-1))/(k*(k-1)) < v): + (lambd * v * (v - 1)) / (k * (k - 1)) < v + ): if existence: return False raise EmptySetError("There exists no ({},{},{})-BIBD".format(v, k, lambd)) @@ -271,12 +275,12 @@ def balanced_incomplete_block_design(v, k, lambd=1, existence=False, use_LJCR=Fa if BruckRyserChowla_check(v, k, lambd) is False: if existence: return False - raise EmptySetError("There exists no ({},{},{})-BIBD by Bruck-Ryser-Chowla Theorem".format(v,k,lambd)) + raise EmptySetError("There exists no ({},{},{})-BIBD by Bruck-Ryser-Chowla Theorem".format(v, k, lambd)) if k == 2: if existence: return True - return BIBD(v, [[x, y] for _ in range(lambd) for x in range(v) for y in range(x+1, v) if x != y], lambd=lambd, check=False, copy=True) + return BIBD(v, [[x, y] for _ in range(lambd) for x in range(v) for y in range(x + 1, v) if x != y], lambd=lambd, check=False, copy=True) if k == 3 and lambd == 1: if existence: return v % 6 == 1 or v % 6 == 3 @@ -296,7 +300,7 @@ def balanced_incomplete_block_design(v, k, lambd=1, existence=False, use_LJCR=Fa if (v, k, lambd) in BIBD_constructions: if existence: return True - return BIBD(v,BIBD_constructions[(v, k, lambd)](), lambd=lambd, copy=False) + return BIBD(v, BIBD_constructions[(v, k, lambd)](), lambd=lambd, copy=False) if lambd == 1 and BIBD_from_arc_in_desarguesian_projective_plane(v, k, existence=True): if existence: return True @@ -306,11 +310,12 @@ def balanced_incomplete_block_design(v, k, lambd=1, existence=False, use_LJCR=Fa if existence: return True return BIBD(v, BIBD_from_TD(v, k), copy=False) - if lambd == 1 and v == (k-1)**2+k and is_prime_power(k-1): + if lambd == 1 and v == (k - 1) ** 2 + k and is_prime_power(k - 1): if existence: return True from .block_design import projective_plane - return BIBD(v, projective_plane(k-1),copy=False) + + return BIBD(v, projective_plane(k - 1), copy=False) if difference_family(v, k, l=lambd, existence=True) is True: if existence: return True @@ -318,6 +323,7 @@ def balanced_incomplete_block_design(v, k, lambd=1, existence=False, use_LJCR=Fa return BIBD(v, BIBD_from_difference_family(G, D, check=False), lambd=lambd, copy=False) if lambd == 1 and use_LJCR: from .covering_design import best_known_covering_design_www + values_in_db = False try: B = best_known_covering_design_www(v, k, 2) @@ -339,15 +345,14 @@ def balanced_incomplete_block_design(v, k, lambd=1, existence=False, use_LJCR=Fa return True return BIBD(B.ground_set(), B.blocks(), k=k, lambd=1, copy=False) - if ( (k+lambd)*(k+lambd-1) == lambd*(v+k+lambd-1) and - balanced_incomplete_block_design(v+k+lambd, k+lambd, lambd, existence=True) is True): + if (k + lambd) * (k + lambd - 1) == lambd * (v + k + lambd - 1) and balanced_incomplete_block_design(v + k + lambd, k + lambd, lambd, existence=True) is True: # By removing a block and all points of that block from the # symmetric (v+k+lambd, k+lambd, lambd) BIBD # we get a (v, k, lambd) BIBD if existence: return True - D = balanced_incomplete_block_design(v+k+lambd, k+lambd, lambd) + D = balanced_incomplete_block_design(v + k + lambd, k + lambd, lambd) Br = D.blocks()[0] # block to remove blocks = D.blocks()[1:] @@ -419,11 +424,11 @@ def BruckRyserChowla_check(v, k, lambd): from sage.rings.rational_field import QQ # design is not symmetric - if k*(k-1) != lambd*(v-1): + if k * (k - 1) != lambd * (v - 1): return Unknown if v % 2 == 0: - return is_square(k-lambd) + return is_square(k - lambd) g = 1 if v % 4 == 1 else -1 C = Conic(QQ, [1, lambd - k, -g * lambd]) @@ -486,29 +491,26 @@ def steiner_triple_system(n): http://www.utu.fi/~honkala/designs.ps """ - name = "Steiner Triple System on "+str(n)+" elements" + name = "Steiner Triple System on " + str(n) + " elements" if n % 6 == 3: - t = (n-3) // 6 + t = (n - 3) // 6 Z = list(range(2 * t + 1)) - T = lambda x_y : x_y[0] + (2*t+1)*x_y[1] + T = lambda x_y: x_y[0] + (2 * t + 1) * x_y[1] - sts = [[(i,0),(i,1),(i,2)] for i in Z] + \ - [[(i,k),(j,k),(((t+1)*(i+j)) % (2*t+1),(k+1) % 3)] for k in range(3) for i in Z for j in Z if i != j] + sts = [[(i, 0), (i, 1), (i, 2)] for i in Z] + [[(i, k), (j, k), (((t + 1) * (i + j)) % (2 * t + 1), (k + 1) % 3)] for k in range(3) for i in Z for j in Z if i != j] elif n % 6 == 1: - t = (n-1) // 6 + t = (n - 1) // 6 N = list(range(2 * t)) - T = lambda x_y : x_y[0]+x_y[1]*t*2 if x_y != (-1,-1) else n-1 + T = lambda x_y: x_y[0] + x_y[1] * t * 2 if x_y != (-1, -1) else n - 1 - L1 = lambda i,j : (i+j) % ((n-1)//3) - L = lambda i,j : L1(i,j)//2 if L1(i,j) % 2 == 0 else t+(L1(i,j)-1)//2 + L1 = lambda i, j: (i + j) % ((n - 1) // 3) + L = lambda i, j: L1(i, j) // 2 if L1(i, j) % 2 == 0 else t + (L1(i, j) - 1) // 2 - sts = [[(i,0),(i,1),(i,2)] for i in range(t)] + \ - [[(-1,-1),(i,k),(i-t,(k+1) % 3)] for i in range(t,2*t) for k in [0,1,2]] + \ - [[(i,k),(j,k),(L(i,j),(k+1) % 3)] for k in [0,1,2] for i in N for j in N if i < j] + sts = [[(i, 0), (i, 1), (i, 2)] for i in range(t)] + [[(-1, -1), (i, k), (i - t, (k + 1) % 3)] for i in range(t, 2 * t) for k in [0, 1, 2]] + [[(i, k), (j, k), (L(i, j), (k + 1) % 3)] for k in [0, 1, 2] for i in N for j in N if i < j] else: raise EmptySetError("Steiner triple systems only exist for n = 1 mod 6 or n = 3 mod 6") @@ -516,7 +518,7 @@ def steiner_triple_system(n): # apply T and remove duplicates sts = set(frozenset(T(xx) for xx in x) for x in sts) - return BIBD(n, sts, name=name,check=False) + return BIBD(n, sts, name=name, check=False) def BIBD_from_TD(v, k, existence=False): @@ -598,58 +600,51 @@ def BIBD_from_TD(v, k, existence=False): NotImplementedError: I do not know how to build a (20,5,1)-BIBD! """ # First construction - if (v % k == 0 and - balanced_incomplete_block_design(v//k, k, existence=True) is True and - transversal_design(k, v//k, existence=True) is True): + if v % k == 0 and balanced_incomplete_block_design(v // k, k, existence=True) is True and transversal_design(k, v // k, existence=True) is True: if existence: return True - v = v//k - BIBDvk = balanced_incomplete_block_design(v,k)._blocks - TDkv = transversal_design(k,v,check=False) + v = v // k + BIBDvk = balanced_incomplete_block_design(v, k)._blocks + TDkv = transversal_design(k, v, check=False) BIBD = TDkv._blocks for i in range(k): - BIBD.extend([x+i*v for x in B] for B in BIBDvk) + BIBD.extend([x + i * v for x in B] for B in BIBDvk) # Second construction - elif ((v-1) % k == 0 and - balanced_incomplete_block_design((v-1)//k+1,k,existence=True) is True and - transversal_design(k,(v-1)//k,existence=True)) is True: + elif ((v - 1) % k == 0 and balanced_incomplete_block_design((v - 1) // k + 1, k, existence=True) is True and transversal_design(k, (v - 1) // k, existence=True)) is True: if existence: return True - v = (v-1)//k - BIBDv1k = balanced_incomplete_block_design(v+1,k)._blocks - TDkv = transversal_design(k,v,check=False)._blocks + v = (v - 1) // k + BIBDv1k = balanced_incomplete_block_design(v + 1, k)._blocks + TDkv = transversal_design(k, v, check=False)._blocks - inf = v*k + inf = v * k BIBD = TDkv for i in range(k): - BIBD.extend([inf if x == v else x+i*v for x in B] for B in BIBDv1k) + BIBD.extend([inf if x == v else x + i * v for x in B] for B in BIBDv1k) # Third construction - elif ((v-k) % k == 0 and - balanced_incomplete_block_design((v-k)//k+k,k,existence=True) is True - and transversal_design(k,(v-k)//k,existence=True) is True): + elif (v - k) % k == 0 and balanced_incomplete_block_design((v - k) // k + k, k, existence=True) is True and transversal_design(k, (v - k) // k, existence=True) is True: if existence: return True - v = (v-k)//k - BIBDvpkk = balanced_incomplete_block_design(v+k,k) - TDkv = transversal_design(k,v,check=False)._blocks - inf = v*k + v = (v - k) // k + BIBDvpkk = balanced_incomplete_block_design(v + k, k) + TDkv = transversal_design(k, v, check=False)._blocks + inf = v * k BIBD = TDkv # makes sure that [v,...,v+k-1] is a block of BIBDvpkk. Then, we remove it. - BIBDvpkk = _relabel_bibd(BIBDvpkk,v+k) + BIBDvpkk = _relabel_bibd(BIBDvpkk, v + k) BIBDvpkk = [B for B in BIBDvpkk if min(B) < v] for i in range(k): - BIBD.extend([(x-v)+inf if x >= v else x+i*v for x in B] - for B in BIBDvpkk) + BIBD.extend([(x - v) + inf if x >= v else x + i * v for x in B] for B in BIBDvpkk) BIBD.append(list(range(k * v, v * k + k))) @@ -657,7 +652,7 @@ def BIBD_from_TD(v, k, existence=False): else: if existence: return Unknown - raise NotImplementedError("I do not know how to build a ({},{},1)-BIBD!".format(v,k)) + raise NotImplementedError("I do not know how to build a ({},{},1)-BIBD!".format(v, k)) return BIBD @@ -719,6 +714,7 @@ def BIBD_from_difference_family(G, D, lambd=None, check=True): [20, 0, 3, 13, 15]] """ from .difference_family import group_law, block_stabilizer + identity, mul, inv = group_law(G) bibd = [] Gset = set(G) @@ -730,18 +726,19 @@ def BIBD_from_difference_family(G, D, lambd=None, check=True): while GG: g = GG.pop() if S: - GG.difference_update(mul(s,g) for s in S) - bibd.append([p_to_i[mul(i,g)] for i in b]) + GG.difference_update(mul(s, g) for s in S) + bibd.append([p_to_i[mul(i, g)] for i in b]) if check: if lambd is None: k = len(bibd[0]) v = G.cardinality() - lambd = (len(bibd) * k * (k-1)) // (v * (v-1)) + lambd = (len(bibd) * k * (k - 1)) // (v * (v - 1)) assert is_pairwise_balanced_design(bibd, G.cardinality(), [len(D[0])], lambd=lambd) return bibd + ################ # (v,4,1)-BIBD # ################ @@ -795,48 +792,100 @@ def v_4_1_BIBD(v, check=True): k = 4 if v == 0: return [] - if v <= 12 or v % 12 not in [1,4]: + if v <= 12 or v % 12 not in [1, 4]: raise EmptySetError("A K_4-decomposition of K_v exists iif v=2,4 mod 12, v>12 or v==0") # Step 1. Base cases. if v == 13: # note: this construction can also be obtained from difference_family from .block_design import projective_plane + return projective_plane(3)._blocks if v == 16: from .block_design import AffineGeometryDesign from sage.rings.finite_rings.finite_field_constructor import FiniteField - return AffineGeometryDesign(2,1,FiniteField(4,'x'))._blocks + + return AffineGeometryDesign(2, 1, FiniteField(4, 'x'))._blocks if v == 25 or v == 37: from .difference_family import difference_family - G,D = difference_family(v,4) - return BIBD_from_difference_family(G,D,check=False) + + G, D = difference_family(v, 4) + return BIBD_from_difference_family(G, D, check=False) if v == 28: - return [[0, 1, 23, 26], [0, 2, 10, 11], [0, 3, 16, 18], [0, 4, 15, 20], - [0, 5, 8, 9], [0, 6, 22, 25], [0, 7, 14, 21], [0, 12, 17, 27], - [0, 13, 19, 24], [1, 2, 24, 27], [1, 3, 11, 12], [1, 4, 17, 19], - [1, 5, 14, 16], [1, 6, 9, 10], [1, 7, 20, 25], [1, 8, 15, 22], - [1, 13, 18, 21], [2, 3, 21, 25], [2, 4, 12, 13], [2, 5, 18, 20], - [2, 6, 15, 17], [2, 7, 19, 22], [2, 8, 14, 26], [2, 9, 16, 23], - [3, 4, 22, 26], [3, 5, 7, 13], [3, 6, 14, 19], [3, 8, 20, 23], - [3, 9, 15, 27], [3, 10, 17, 24], [4, 5, 23, 27], [4, 6, 7, 8], - [4, 9, 14, 24], [4, 10, 16, 21], [4, 11, 18, 25], [5, 6, 21, 24], - [5, 10, 15, 25], [5, 11, 17, 22], [5, 12, 19, 26], [6, 11, 16, 26], - [6, 12, 18, 23], [6, 13, 20, 27], [7, 9, 17, 18], [7, 10, 26, 27], - [7, 11, 23, 24], [7, 12, 15, 16], [8, 10, 18, 19], [8, 11, 21, 27], - [8, 12, 24, 25], [8, 13, 16, 17], [9, 11, 19, 20], [9, 12, 21, 22], - [9, 13, 25, 26], [10, 12, 14, 20], [10, 13, 22, 23], [11, 13, 14, 15], - [14, 17, 23, 25], [14, 18, 22, 27], [15, 18, 24, 26], [15, 19, 21, 23], - [16, 19, 25, 27], [16, 20, 22, 24], [17, 20, 21, 26]] + return [ + [0, 1, 23, 26], + [0, 2, 10, 11], + [0, 3, 16, 18], + [0, 4, 15, 20], + [0, 5, 8, 9], + [0, 6, 22, 25], + [0, 7, 14, 21], + [0, 12, 17, 27], + [0, 13, 19, 24], + [1, 2, 24, 27], + [1, 3, 11, 12], + [1, 4, 17, 19], + [1, 5, 14, 16], + [1, 6, 9, 10], + [1, 7, 20, 25], + [1, 8, 15, 22], + [1, 13, 18, 21], + [2, 3, 21, 25], + [2, 4, 12, 13], + [2, 5, 18, 20], + [2, 6, 15, 17], + [2, 7, 19, 22], + [2, 8, 14, 26], + [2, 9, 16, 23], + [3, 4, 22, 26], + [3, 5, 7, 13], + [3, 6, 14, 19], + [3, 8, 20, 23], + [3, 9, 15, 27], + [3, 10, 17, 24], + [4, 5, 23, 27], + [4, 6, 7, 8], + [4, 9, 14, 24], + [4, 10, 16, 21], + [4, 11, 18, 25], + [5, 6, 21, 24], + [5, 10, 15, 25], + [5, 11, 17, 22], + [5, 12, 19, 26], + [6, 11, 16, 26], + [6, 12, 18, 23], + [6, 13, 20, 27], + [7, 9, 17, 18], + [7, 10, 26, 27], + [7, 11, 23, 24], + [7, 12, 15, 16], + [8, 10, 18, 19], + [8, 11, 21, 27], + [8, 12, 24, 25], + [8, 13, 16, 17], + [9, 11, 19, 20], + [9, 12, 21, 22], + [9, 13, 25, 26], + [10, 12, 14, 20], + [10, 13, 22, 23], + [11, 13, 14, 15], + [14, 17, 23, 25], + [14, 18, 22, 27], + [15, 18, 24, 26], + [15, 19, 21, 23], + [16, 19, 25, 27], + [16, 20, 22, 24], + [17, 20, 21, 26], + ] # Step 2 : this is function PBD_4_5_8_9_12 - PBD = PBD_4_5_8_9_12((v-1)//(k-1),check=False) + PBD = PBD_4_5_8_9_12((v - 1) // (k - 1), check=False) # Step 3 : Theorem 7.20 - bibd = BIBD_from_PBD(PBD,v,k,check=False) + bibd = BIBD_from_PBD(PBD, v, k, check=False) if check: - assert is_pairwise_balanced_design(bibd,v,[k]) + assert is_pairwise_balanced_design(bibd, v, [k]) return bibd @@ -870,24 +919,24 @@ def BIBD_from_PBD(PBD, v, k, check=True, base_cases=None): """ if base_cases is None: base_cases = {} - r = (v-1) // (k-1) + r = (v - 1) // (k - 1) bibd = [] for X in PBD: n = len(X) - N = (k-1)*n+1 - if (n,k) not in base_cases: - base_cases[n,k] = _relabel_bibd(balanced_incomplete_block_design(N,k), N) + N = (k - 1) * n + 1 + if (n, k) not in base_cases: + base_cases[n, k] = _relabel_bibd(balanced_incomplete_block_design(N, k), N) - for XX in base_cases[n,k]: - if N-1 in XX: + for XX in base_cases[n, k]: + if N - 1 in XX: continue - bibd.append([X[x//(k-1)] + (x % (k-1))*r for x in XX]) + bibd.append([X[x // (k - 1)] + (x % (k - 1)) * r for x in XX]) for x in range(r): - bibd.append([x+i*r for i in range(k-1)]+[v-1]) + bibd.append([x + i * r for i in range(k - 1)] + [v - 1]) if check: - assert is_pairwise_balanced_design(bibd,v,[k]) + assert is_pairwise_balanced_design(bibd, v, [k]) return bibd @@ -915,9 +964,9 @@ def _relabel_bibd(B, n, p=None): ... """ if p is None: - p = n-1 + p = n - 1 found = 0 - last = n-1 + last = n - 1 d = {} for X in B: if last in X: @@ -926,9 +975,9 @@ def _relabel_bibd(B, n, p=None): continue d[x] = found found += 1 - if found == n-1: + if found == n - 1: break - d[p] = n-1 + d[p] = n - 1 return [[d[x] for x in X] for X in B] @@ -970,51 +1019,46 @@ def PBD_4_5_8_9_12(v, check=True): elif v == 13 or v == 28: PBD = v_4_1_BIBD(v, check=False) elif v == 29: - TD47 = transversal_design(4,7)._blocks - four_more_sets = [[28]+[i*7+j for j in range(7)] for i in range(4)] + TD47 = transversal_design(4, 7)._blocks + four_more_sets = [[28] + [i * 7 + j for j in range(7)] for i in range(4)] PBD = TD47 + four_more_sets elif v == 41: - TD59 = transversal_design(5,9) - PBD = ([[x for x in X if x < 41] for X in TD59] - + [[i*9+j for j in range(9)] for i in range(4)] - + [[36,37,38,39,40]]) + TD59 = transversal_design(5, 9) + PBD = [[x for x in X if x < 41] for X in TD59] + [[i * 9 + j for j in range(9)] for i in range(4)] + [[36, 37, 38, 39, 40]] elif v == 44: - TD59 = transversal_design(5,9) - PBD = ([[x for x in X if x < 44] for X in TD59] - + [[i*9+j for j in range(9)] for i in range(4)] - + [[36,37,38,39,40,41,42,43]]) + TD59 = transversal_design(5, 9) + PBD = [[x for x in X if x < 44] for X in TD59] + [[i * 9 + j for j in range(9)] for i in range(4)] + [[36, 37, 38, 39, 40, 41, 42, 43]] elif v == 45: - TD59 = transversal_design(5,9)._blocks - PBD = (TD59+[[i*9+j for j in range(9)] for i in range(5)]) + TD59 = transversal_design(5, 9)._blocks + PBD = TD59 + [[i * 9 + j for j in range(9)] for i in range(5)] elif v == 48: - TD4_12 = transversal_design(4,12)._blocks - PBD = (TD4_12+[[i*12+j for j in range(12)] for i in range(4)]) + TD4_12 = transversal_design(4, 12)._blocks + PBD = TD4_12 + [[i * 12 + j for j in range(12)] for i in range(4)] elif v == 49: # Lemma 7.16 : A (49,{4,13})-PBD - TD4_12 = transversal_design(4,12)._blocks + TD4_12 = transversal_design(4, 12)._blocks # Replacing the block of size 13 with a BIBD BIBD_13_4 = v_4_1_BIBD(13) for i in range(4): for B in BIBD_13_4: - TD4_12.append([i*12+x if x != 12 else 48 - for x in B]) + TD4_12.append([i * 12 + x if x != 12 else 48 for x in B]) PBD = TD4_12 else: - t,u = _get_t_u(v) - TD = transversal_design(5,t) - TD = [[x for x in X if x < 4*t+u] for X in TD] - for B in [list(range(t*i,t*(i+1))) for i in range(4)]: + t, u = _get_t_u(v) + TD = transversal_design(5, t) + TD = [[x for x in X if x < 4 * t + u] for X in TD] + for B in [list(range(t * i, t * (i + 1))) for i in range(4)]: TD.extend(_PBD_4_5_8_9_12_closure([B])) if u > 1: - TD.extend(_PBD_4_5_8_9_12_closure([list(range(4*t,4*t+u))])) + TD.extend(_PBD_4_5_8_9_12_closure([list(range(4 * t, 4 * t + u))])) PBD = TD if check: - assert is_pairwise_balanced_design(PBD,v,[4,5,8,9,12]) + assert is_pairwise_balanced_design(PBD, v, [4, 5, 8, 9, 12]) return PBD @@ -1037,7 +1081,7 @@ def _PBD_4_5_8_9_12_closure(B): """ BB = [] for X in B: - if len(X) not in [4,5,8,9,12]: + if len(X) not in [4, 5, 8, 9, 12]: PBD = PBD_4_5_8_9_12(len(X), check=False) X = [[X[i] for i in XX] for XX in PBD] BB.extend(X) @@ -1047,31 +1091,31 @@ def _PBD_4_5_8_9_12_closure(B): table_7_1 = { - 0:{'t':-4,'u':16,'s':2}, - 1:{'t':-4,'u':17,'s':2}, - 4:{'t':1,'u':0,'s':1}, - 5:{'t':1,'u':1,'s':1}, - 8:{'t':1,'u':4,'s':1}, - 9:{'t':1,'u':5,'s':1}, - 12:{'t':1,'u':8,'s':1}, - 13:{'t':1,'u':9,'s':1}, - 16:{'t':4,'u':0,'s':0}, - 17:{'t':4,'u':1,'s':0}, - 20:{'t':5,'u':0,'s':0}, - 21:{'t':5,'u':1,'s':0}, - 24:{'t':5,'u':4,'s':0}, - 25:{'t':5,'u':5,'s':0}, - 28:{'t':5,'u':8,'s':1}, - 29:{'t':5,'u':9,'s':1}, - 32:{'t':8,'u':0,'s':0}, - 33:{'t':8,'u':1,'s':0}, - 36:{'t':8,'u':4,'s':0}, - 37:{'t':8,'u':5,'s':0}, - 40:{'t':8,'u':8,'s':0}, - 41:{'t':8,'u':9,'s':1}, - 44:{'t':8,'u':12,'s':1}, - 45:{'t':8,'u':13,'s':1}, - } + 0: {'t': -4, 'u': 16, 's': 2}, + 1: {'t': -4, 'u': 17, 's': 2}, + 4: {'t': 1, 'u': 0, 's': 1}, + 5: {'t': 1, 'u': 1, 's': 1}, + 8: {'t': 1, 'u': 4, 's': 1}, + 9: {'t': 1, 'u': 5, 's': 1}, + 12: {'t': 1, 'u': 8, 's': 1}, + 13: {'t': 1, 'u': 9, 's': 1}, + 16: {'t': 4, 'u': 0, 's': 0}, + 17: {'t': 4, 'u': 1, 's': 0}, + 20: {'t': 5, 'u': 0, 's': 0}, + 21: {'t': 5, 'u': 1, 's': 0}, + 24: {'t': 5, 'u': 4, 's': 0}, + 25: {'t': 5, 'u': 5, 's': 0}, + 28: {'t': 5, 'u': 8, 's': 1}, + 29: {'t': 5, 'u': 9, 's': 1}, + 32: {'t': 8, 'u': 0, 's': 0}, + 33: {'t': 8, 'u': 1, 's': 0}, + 36: {'t': 8, 'u': 4, 's': 0}, + 37: {'t': 8, 'u': 5, 's': 0}, + 40: {'t': 8, 'u': 8, 's': 0}, + 41: {'t': 8, 'u': 9, 's': 1}, + 44: {'t': 8, 'u': 12, 's': 1}, + 45: {'t': 8, 'u': 13, 's': 1}, +} def _get_t_u(v): @@ -1091,12 +1135,13 @@ def _get_t_u(v): # Table 7.1 v = int(v) d = table_7_1[v % 48] - s = v//48 + s = v // 48 if s < d['s']: raise RuntimeError("This should not have happened.") - t = 12*s+d['t'] + t = 12 * s + d['t'] u = d['u'] - return t,u + return t, u + ################ # (v,5,1)-BIBD # @@ -1136,44 +1181,45 @@ def v_5_1_BIBD(v, check=True): """ v = int(v) - assert (v > 1) - assert (v % 20 == 5 or v % 20 == 1) # note: equivalent to (v-1)%4 == 0 and (v*(v-1))%20 == 0 + assert v > 1 + assert v % 20 == 5 or v % 20 == 1 # note: equivalent to (v-1)%4 == 0 and (v*(v-1))%20 == 0 # Lemma 27 - if v % 5 == 0 and (v//5) % 4 == 1 and is_prime_power(v//5): - bibd = BIBD_5q_5_for_q_prime_power(v//5) + if v % 5 == 0 and (v // 5) % 4 == 1 and is_prime_power(v // 5): + bibd = BIBD_5q_5_for_q_prime_power(v // 5) # Lemma 28 - elif v in [21,41,61,81,141,161,281]: + elif v in [21, 41, 61, 81, 141, 161, 281]: from .difference_family import difference_family - G,D = difference_family(v,5) + + G, D = difference_family(v, 5) bibd = BIBD_from_difference_family(G, D, check=False) # Lemma 29 elif v == 165: - bibd = BIBD_from_PBD(v_5_1_BIBD(41,check=False),165,5,check=False) + bibd = BIBD_from_PBD(v_5_1_BIBD(41, check=False), 165, 5, check=False) elif v == 181: - bibd = BIBD_from_PBD(v_5_1_BIBD(45,check=False),181,5,check=False) - elif v in (201,285,301,401,421,425): + bibd = BIBD_from_PBD(v_5_1_BIBD(45, check=False), 181, 5, check=False) + elif v in (201, 285, 301, 401, 421, 425): # Call directly the BIBD_from_TD function # note: there are (201,5,1) and (421,5)-difference families that can be # obtained from the general constructor - bibd = BIBD_from_TD(v,5) + bibd = BIBD_from_TD(v, 5) # Theorem 31.2 - elif (v-1)//4 in [80, 81, 85, 86, 90, 91, 95, 96, 110, 111, 115, 116, 120, 121, 250, 251, 255, 256, 260, 261, 265, 266, 270, 271]: - r = (v-1)//4 + elif (v - 1) // 4 in [80, 81, 85, 86, 90, 91, 95, 96, 110, 111, 115, 116, 120, 121, 250, 251, 255, 256, 260, 261, 265, 266, 270, 271]: + r = (v - 1) // 4 if r <= 96: - k,t,u = 5, 16, r-80 + k, t, u = 5, 16, r - 80 elif r <= 121: - k,t,u = 10, 11, r-110 + k, t, u = 10, 11, r - 110 else: - k,t,u = 10, 25, r-250 - bibd = BIBD_from_PBD(PBD_from_TD(k,t,u),v,5,check=False) + k, t, u = 10, 25, r - 250 + bibd = BIBD_from_PBD(PBD_from_TD(k, t, u), v, 5, check=False) else: - r,s,t,u = _get_r_s_t_u(v) - bibd = BIBD_from_PBD(PBD_from_TD(5,t,u),v,5,check=False) + r, s, t, u = _get_r_s_t_u(v) + bibd = BIBD_from_PBD(PBD_from_TD(5, t, u), v, 5, check=False) if check: - assert is_pairwise_balanced_design(bibd,v,[5]) + assert is_pairwise_balanced_design(bibd, v, [5]) return bibd @@ -1194,30 +1240,30 @@ def _get_r_s_t_u(v): sage: _get_r_s_t_u(25) (6, 0, 1, 1) """ - r = int((v-1)/4) - s = r//150 + r = int((v - 1) / 4) + s = r // 150 x = r % 150 if x == 0: - t,u = 30*s-5, 25 + t, u = 30 * s - 5, 25 elif x == 1: - t,u = 30*s-5, 26 + t, u = 30 * s - 5, 26 elif x <= 21: - t,u = 30*s+1, x-5 + t, u = 30 * s + 1, x - 5 elif x == 25: - t,u = 30*s+5, 0 + t, u = 30 * s + 5, 0 elif x == 26: - t,u = 30*s+5, 1 + t, u = 30 * s + 5, 1 elif x == 30: - t,u = 30*s+5, 5 + t, u = 30 * s + 5, 5 elif x <= 51: - t,u = 30*s+5, x-25 + t, u = 30 * s + 5, x - 25 elif x <= 121: - t,u = 30*s+11, x-55 + t, u = 30 * s + 11, x - 55 elif x <= 146: - t,u = 30*s+25, x-125 + t, u = 30 * s + 25, x - 125 - return r,s,t,u + return r, s, t, u def PBD_from_TD(k, t, u): @@ -1242,12 +1288,13 @@ def PBD_from_TD(k, t, u): True """ from .orthogonal_arrays import transversal_design - TD = transversal_design(k+bool(u),t, check=False) - TD = [[x for x in X if x < k*t+u] for X in TD] + + TD = transversal_design(k + bool(u), t, check=False) + TD = [[x for x in X if x < k * t + u] for X in TD] for i in range(k): - TD.append(list(range(t*i,t*i+t))) + TD.append(list(range(t * i, t * i + t))) if u >= 2: - TD.append(list(range(k*t,k*t+u))) + TD.append(list(range(k * t, k * t + u))) return TD @@ -1272,21 +1319,24 @@ def BIBD_5q_5_for_q_prime_power(q): if q % 4 != 1 or not is_prime_power(q): raise ValueError("q is not a prime power or q%4!=1.") - d = (q-1)//4 + d = (q - 1) // 4 B = [] F = FiniteField(q, 'x') a = F.primitive_element() L = {b: i for i, b in enumerate(F)} for b, Lb in L.items(): - B.append([i*q + Lb for i in range(5)]) + B.append([i * q + Lb for i in range(5)]) for i in range(5): for j in range(d): - B.append([ i*q + Lb, - ((i+1) % 5)*q + L[ a**j+b ], - ((i+1) % 5)*q + L[-a**j+b ], - ((i+4) % 5)*q + L[ a**(j+d)+b], - ((i+4) % 5)*q + L[-a**(j+d)+b], - ]) + B.append( + [ + i * q + Lb, + ((i + 1) % 5) * q + L[a**j + b], + ((i + 1) % 5) * q + L[-(a**j) + b], + ((i + 4) % 5) * q + L[a ** (j + d) + b], + ((i + 4) % 5) * q + L[-(a ** (j + d)) + b], + ] + ) return B @@ -1351,16 +1401,11 @@ def BIBD_from_arc_in_desarguesian_projective_plane(n, k, existence=False): Journal of Combinatorial Theory 6, no. 3 (1969): 317-319. :doi:`10.1016/S0021-9800(69)80095-5` """ - q = (n-1)//(k-1)-1 - if (k % 2 or - q % 2 or - q <= k or - n != (k-1)*(q+1)+1 or - not is_prime_power(k) or - not is_prime_power(q)): + q = (n - 1) // (k - 1) - 1 + if k % 2 or q % 2 or q <= k or n != (k - 1) * (q + 1) + 1 or not is_prime_power(k) or not is_prime_power(q): if existence: return False - raise ValueError("This function cannot produce a ({},{},1)-BIBD".format(n,k)) + raise ValueError("This function cannot produce a ({},{},1)-BIBD".format(n, k)) if existence: return True @@ -1374,15 +1419,15 @@ def BIBD_from_arc_in_desarguesian_projective_plane(n, k, existence=False): from sage.libs.gap.libgap import libgap from sage.matrix.constructor import Matrix - K = GF(q,'a') + K = GF(q, 'a') one = K.one() # An irreducible quadratic form over K[X,Y] - GO = libgap.GeneralOrthogonalGroup(-1,2,q) + GO = libgap.GeneralOrthogonalGroup(-1, 2, q) M = libgap.InvariantQuadraticForm(GO)['matrix'] M = Matrix(M) M = M.change_ring(K) - Q = lambda xx,yy : M[0,0]*xx**2+(M[0,1]+M[1,0])*xx*yy+M[1,1]*yy**2 + Q = lambda xx, yy: M[0, 0] * xx**2 + (M[0, 1] + M[1, 0]) * xx * yy + M[1, 1] * yy**2 # Here, the additive subgroup H (of order n) of K mentioned in # [Denniston69] is the set of all elements of K of degree < log_n @@ -1390,10 +1435,10 @@ def BIBD_from_arc_in_desarguesian_projective_plane(n, k, existence=False): K_iter = list(K) # faster iterations log_n = is_prime_power(n, get_data=True)[1] - C = [(x, y, one) for x in K_iter for y in K_iter - if Q(x, y).polynomial().degree() < log_n] + C = [(x, y, one) for x in K_iter for y in K_iter if Q(x, y).polynomial().degree() < log_n] from sage.combinat.designs.block_design import DesarguesianProjectivePlaneDesign + return DesarguesianProjectivePlaneDesign(q).trace(C)._blocks @@ -1427,6 +1472,7 @@ class PairwiseBalancedDesign(GroupDivisibleDesign): modified in place (each block is sorted, and the whole list is sorted). Your ``blocks`` object will become the instance's internal data. """ + def __init__(self, points, blocks, K=None, lambd=1, check=True, copy=True, **kwds): r""" Constructor. @@ -1443,15 +1489,7 @@ def __init__(self, points, blocks, K=None, lambd=1, check=True, copy=True, **kwd else: points = list(range(i)) - GroupDivisibleDesign.__init__(self, - points, - [[x] for x in points], - blocks, - K=K, - lambd=lambd, - check=check, - copy=copy, - **kwds) + GroupDivisibleDesign.__init__(self, points, [[x] for x in points], blocks, K=K, lambd=lambd, check=check, copy=copy, **kwds) def __repr__(self): r""" @@ -1495,6 +1533,7 @@ class BalancedIncompleteBlockDesign(PairwiseBalancedDesign): sage: b=designs.balanced_incomplete_block_design(9,3); b (9,3,1)-Balanced Incomplete Block Design """ + def __init__(self, points, blocks, k=None, lambd=1, check=True, copy=True, **kwds): r""" Constructor. @@ -1504,14 +1543,7 @@ def __init__(self, points, blocks, k=None, lambd=1, check=True, copy=True, **kwd sage: b=designs.balanced_incomplete_block_design(9,3); b (9,3,1)-Balanced Incomplete Block Design """ - PairwiseBalancedDesign.__init__(self, - points, - blocks, - K=[k] if k is not None else None, - lambd=lambd, - check=check, - copy=copy, - **kwds) + PairwiseBalancedDesign.__init__(self, points, blocks, K=[k] if k is not None else None, lambd=lambd, check=check, copy=copy, **kwds) def __repr__(self): r""" @@ -1644,7 +1676,7 @@ def arc(self, s=2, solver=None, verbose=0, *, integrality_tolerance=1e-3): p.solve(log=verbose) values = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - return [self._points[i] for (i,j) in values.items() if j] + return [self._points[i] for (i, j) in values.items() if j] BIBD = BalancedIncompleteBlockDesign diff --git a/src/sage/combinat/designs/block_design.py b/src/sage/combinat/designs/block_design.py index 8240e1d31d6..9134ea5236a 100644 --- a/src/sage/combinat/designs/block_design.py +++ b/src/sage/combinat/designs/block_design.py @@ -87,9 +87,9 @@ def tdesign_params(t, v, k, L): x = binomial(v, t) y = binomial(k, t) b = divmod(L * x, y)[0] - x = binomial(v-1, t-1) - y = binomial(k-1, t-1) - r = integer_floor(L * x/y) + x = binomial(v - 1, t - 1) + y = binomial(k - 1, t - 1) + r = integer_floor(L * x / y) return (t, v, b, r, k, L) @@ -153,21 +153,19 @@ def are_hyperplanes_in_projective_geometry_parameters(v, k, lmbda, return_parame q1 = Integer(v - k) q2 = Integer(k - lmbda) - if (lmbda <= 0 or q1 < 4 or q2 < 2 or - not q1.is_prime_power() or - not q2.is_prime_power()): - return (False,(None,None)) if return_parameters else False + if lmbda <= 0 or q1 < 4 or q2 < 2 or not q1.is_prime_power() or not q2.is_prime_power(): + return (False, (None, None)) if return_parameters else False - p1,e1 = q1.factor()[0] - p2,e2 = q2.factor()[0] + p1, e1 = q1.factor()[0] + p2, e2 = q2.factor()[0] - k = gcd(e1,e2) - d = e1//k + k = gcd(e1, e2) + d = e1 // k q = p1**k - if e2//k != d-1 or lmbda != (q**(d-1)-1)//(q-1): - return (False,(None,None)) if return_parameters else False + if e2 // k != d - 1 or lmbda != (q ** (d - 1) - 1) // (q - 1): + return (False, (None, None)) if return_parameters else False - return (True, (q,d)) if return_parameters else True + return (True, (q, d)) if return_parameters else True def ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=True, check=True): @@ -258,26 +256,27 @@ def ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=True, ch q = F.cardinality() else: from sage.rings.finite_rings.finite_field_constructor import GF + F = GF(q) if algorithm is None: from sage.matrix.echelon_matrix import reduced_echelon_matrix_iterator - points = {p:i for i,p in enumerate(reduced_echelon_matrix_iterator(F,1,n+1,copy=True,set_immutable=True))} + points = {p: i for i, p in enumerate(reduced_echelon_matrix_iterator(F, 1, n + 1, copy=True, set_immutable=True))} blocks = [] - for m1 in reduced_echelon_matrix_iterator(F,d+1,n+1,copy=False): + for m1 in reduced_echelon_matrix_iterator(F, d + 1, n + 1, copy=False): b = [] - for m2 in reduced_echelon_matrix_iterator(F,1,d+1,copy=False): - m = m2*m1 + for m2 in reduced_echelon_matrix_iterator(F, 1, d + 1, copy=False): + m = m2 * m1 m.echelonize() m.set_immutable() b.append(points[m]) blocks.append(b) B = BlockDesign(len(points), blocks, name='ProjectiveGeometryDesign', check=check) if point_coordinates: - B.relabel({i:p[0] for p,i in points.items()}) + B.relabel({i: p[0] for p, i in points.items()}) - elif algorithm == "gap": # Requires GAP's Design + elif algorithm == "gap": # Requires GAP's Design libgap.load_package("design") D = libgap.PGPointFlatBlockDesign(n, F.order(), d) v = D['v'].sage() @@ -289,12 +288,10 @@ def ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=True, ch if check: from sage.combinat.q_analogues import q_binomial + q = F.cardinality() - if not B.is_t_design(t=2, v=q_binomial(n+1,1,q), - k=q_binomial(d+1,1,q), - l=q_binomial(n-1, d-1, q)): - raise RuntimeError("error in ProjectiveGeometryDesign " - "construction. Please e-mail sage-devel@googlegroups.com") + if not B.is_t_design(t=2, v=q_binomial(n + 1, 1, q), k=q_binomial(d + 1, 1, q), l=q_binomial(n - 1, d - 1, q)): + raise RuntimeError("error in ProjectiveGeometryDesign " "construction. Please e-mail sage-devel@googlegroups.com") return B @@ -348,7 +345,7 @@ def DesarguesianProjectivePlaneDesign(n, point_coordinates=True, check=True): # we relabel the points with the integers from 0 to n^2 + n as follows: # - the affine plane is the set of points [x:y:1] (i.e. the third coordinate # is nonzero) and gets relabeled from 0 to n^2-1 - affine_plane = lambda x,y: relabel[x] + n * relabel[y] + affine_plane = lambda x, y: relabel[x] + n * relabel[y] # - the affine line is the set of points [x:1:0] (i.e. the third coordinate is # zero but not the second one) and gets relabeled from n^2 to n^2 + n - 1 @@ -363,35 +360,34 @@ def DesarguesianProjectivePlaneDesign(n, point_coordinates=True, check=True): for s in Kiter: for a in Kiter: # points in the affine plane - blcks.append([affine_plane(s*y+a, y) for y in Kiter]) + blcks.append([affine_plane(s * y + a, y) for y in Kiter]) # point at infinity blcks[-1].append(line_infinity(s)) # the n horizontals of the form "y = az" for a in Kiter: # points in the affine plane - blcks.append([affine_plane(x,a) for x in Kiter]) + blcks.append([affine_plane(x, a) for x in Kiter]) # point at infinity blcks[-1].append(point_infinity) # the line at infinity "z = 0" - blcks.append(range(n2,n2+n+1)) + blcks.append(range(n2, n2 + n + 1)) if check: from .designs_pyx import is_projective_plane + if not is_projective_plane(blcks): raise RuntimeError('There is a problem in the function DesarguesianProjectivePlane') from .bibd import BalancedIncompleteBlockDesign - B = BalancedIncompleteBlockDesign(n2+n+1, blcks, check=check) + + B = BalancedIncompleteBlockDesign(n2 + n + 1, blcks, check=check) if point_coordinates: zero = K.zero() one = K.one() - d = {affine_plane(x,y): (x,y,one) - for x in Kiter - for y in Kiter} - d.update({line_infinity(x): (x,one,zero) - for x in Kiter}) - d[n2+n] = (one,zero,zero) + d = {affine_plane(x, y): (x, y, one) for x in Kiter for y in Kiter} + d.update({line_infinity(x): (x, one, zero) for x in Kiter}) + d[n2 + n] = (one, zero, zero) B.relabel(d) return B @@ -427,19 +423,20 @@ def q3_minus_one_matrix(K): if q.is_prime(): from sage.rings.finite_rings.conway_polynomials import conway_polynomial + try: - a,b,c,_ = conway_polynomial(q, 3) + a, b, c, _ = conway_polynomial(q, 3) except RuntimeError: # the polynomial is not in the database pass else: - return M([0,0,-a,1,0,-b,0,1,-c]) + return M([0, 0, -a, 1, 0, -b, 0, 1, -c]) m = M() - m[1,0] = m[2,1] = K.one() + m[1, 0] = m[2, 1] = K.one() while True: - m[0,2] = K._random_nonzero_element() - m[1,2] = K.random_element() - m[2,2] = K.random_element() + m[0, 2] = K._random_nonzero_element() + m[1, 2] = K.random_element() + m[2, 2] = K.random_element() if m.multiplicative_order() == q**3 - 1: return m @@ -477,14 +474,14 @@ def normalize_hughes_plane_point(p, q): sage: normalize_hughes_plane_point((2*x, one, zero), 9) (2*x, 1, 0) """ - for i in [2,1,0]: + for i in [2, 1, 0]: if p[i].is_one(): return tuple(p) if not p[i].is_zero(): k = ~p[i] if k.is_square(): - return (p[0] * k,p[1] * k,p[2] * k) - return ((p[0] * k)**q,(p[1]*k)**q,(p[2]*k)**q) + return (p[0] * k, p[1] * k, p[2] * k) + return ((p[0] * k) ** q, (p[1] * k) ** q, (p[2] * k) ** q) def HughesPlane(q2, check=True): @@ -602,10 +599,8 @@ def HughesPlane(q2, check=True): V = VectorSpace(K, 3) zero = K.zero() one = K.one() - points = [(x, y, one) for x in m for y in m] + \ - [(x, one, zero) for x in m] + \ - [(one, zero, zero)] - relabel = {tuple(p):i for i,p in enumerate(points)} + points = [(x, y, one) for x in m for y in m] + [(x, one, zero) for x in m] + [(one, zero, zero)] + relabel = {tuple(p): i for i, p in enumerate(points)} blcks = [] for a in m: if a not in F or a == 1: @@ -614,17 +609,18 @@ def HughesPlane(q2, check=True): l = [] l.append(V((-a, one, zero))) for x in m: - y = - aa * (x+one) + y = -aa * (x + one) if not y.is_square(): - y *= aa**(q-1) + y *= aa ** (q - 1) l.append(V((x, y, one))) # compute the orbit of L(a) - blcks.append([relabel[normalize_hughes_plane_point(p,q)] for p in l]) + blcks.append([relabel[normalize_hughes_plane_point(p, q)] for p in l]) for i in range(q2 + q): - l = [A*j for j in l] - blcks.append([relabel[normalize_hughes_plane_point(p,q)] for p in l]) + l = [A * j for j in l] + blcks.append([relabel[normalize_hughes_plane_point(p, q)] for p in l]) from .bibd import BalancedIncompleteBlockDesign - return BalancedIncompleteBlockDesign(q2**2+q2+1, blcks, check=check) + + return BalancedIncompleteBlockDesign(q2**2 + q2 + 1, blcks, check=check) def projective_plane_to_OA(pplane, pt=None, check=True): @@ -671,23 +667,25 @@ def projective_plane_to_OA(pplane, pt=None, check=True): sage: _ = projective_plane_to_OA(pp, pt=7) """ from .bibd import _relabel_bibd + pplane = pplane.blocks() n = len(pplane[0]) - 1 if pt is None: - pt = n**2+n + pt = n**2 + n - assert len(pplane) == n**2+n+1, "pplane is not a projective plane" - assert all(len(B) == n+1 for B in pplane), "pplane is not a projective plane" + assert len(pplane) == n**2 + n + 1, "pplane is not a projective plane" + assert all(len(B) == n + 1 for B in pplane), "pplane is not a projective plane" - pplane = _relabel_bibd(pplane,n**2+n+1,p=n**2+n) - OA = [[x % n for x in sorted(X)] for X in pplane if n**2+n not in X] + pplane = _relabel_bibd(pplane, n**2 + n + 1, p=n**2 + n) + OA = [[x % n for x in sorted(X)] for X in pplane if n**2 + n not in X] assert len(OA) == n**2, "pplane is not a projective plane" if check: from .designs_pyx import is_orthogonal_array - is_orthogonal_array(OA,n+1,n,2) + + is_orthogonal_array(OA, n + 1, n, 2) return OA @@ -761,21 +759,18 @@ def projective_plane(n, check=True, existence=False): if n == 10: if existence: return False - ref = ("C. Lam, L. Thiel and S. Swiercz \"The nonexistence of finite " - "projective planes of order 10\" (1989), Canad. J. Math.") + ref = "C. Lam, L. Thiel and S. Swiercz \"The nonexistence of finite " "projective planes of order 10\" (1989), Canad. J. Math." raise EmptySetError("No projective plane of order 10 exists by %s" % ref) - if BruckRyserChowla_check(n*n+n+1, n+1, 1) is False: + if BruckRyserChowla_check(n * n + n + 1, n + 1, 1) is False: if existence: return False - raise EmptySetError("By the Bruck-Ryser theorem, no projective" - " plane of order {} exists.".format(n)) + raise EmptySetError("By the Bruck-Ryser theorem, no projective" " plane of order {} exists.".format(n)) if not is_prime_power(n): if existence: return Unknown - raise NotImplementedError("If such a projective plane exists, we do " - "not know how to build it.") + raise NotImplementedError("If such a projective plane exists, we do " "not know how to build it.") if existence: return True @@ -853,6 +848,7 @@ def AffineGeometryDesign(n, d, F, point_coordinates=True, check=True): q = F.cardinality() else: from sage.rings.finite_rings.finite_field_constructor import GF + F = GF(q) n = int(n) @@ -862,17 +858,15 @@ def AffineGeometryDesign(n, d, F, point_coordinates=True, check=True): from sage.combinat.q_analogues import q_binomial from sage.matrix.echelon_matrix import reduced_echelon_matrix_iterator - points = {p:i for i,p in enumerate(reduced_echelon_matrix_iterator(F,1,n+1,copy=True,set_immutable=True)) if p[0,0]} + points = {p: i for i, p in enumerate(reduced_echelon_matrix_iterator(F, 1, n + 1, copy=True, set_immutable=True)) if p[0, 0]} blocks = [] - l1 = int(q_binomial(n+1, d+1, q) - q_binomial(n, d+1, q)) + l1 = int(q_binomial(n + 1, d + 1, q) - q_binomial(n, d + 1, q)) l2 = q**d - for m1 in islice(reduced_echelon_matrix_iterator(F,d+1,n+1,copy=False), - int(l1)): + for m1 in islice(reduced_echelon_matrix_iterator(F, d + 1, n + 1, copy=False), int(l1)): b = [] - for m2 in islice(reduced_echelon_matrix_iterator(F,1,d+1,copy=False), - int(l2)): - m = m2*m1 + for m2 in islice(reduced_echelon_matrix_iterator(F, 1, d + 1, copy=False), int(l2)): + m = m2 * m1 m.echelonize() m.set_immutable() b.append(points[m]) @@ -887,9 +881,8 @@ def AffineGeometryDesign(n, d, F, point_coordinates=True, check=True): B.relabel(rd) if check: - if not B.is_t_design(t=2, v=q**n, k=q**d, l=q_binomial(n-1, d-1, q)): - raise RuntimeError("error in AffineGeometryDesign " - "construction. Please e-mail sage-devel@googlegroups.com") + if not B.is_t_design(t=2, v=q**n, k=q**d, l=q_binomial(n - 1, d - 1, q)): + raise RuntimeError("error in AffineGeometryDesign " "construction. Please e-mail sage-devel@googlegroups.com") return B @@ -915,9 +908,9 @@ def CremonaRichmondConfiguration(): """ from sage.graphs.generators.smallgraphs import TutteCoxeterGraph from sage.combinat.designs.incidence_structures import IncidenceStructure + g = TutteCoxeterGraph() - H = IncidenceStructure([g.neighbors(v) - for v in g.bipartite_sets()[0]]) + H = IncidenceStructure([g.neighbors(v) for v in g.bipartite_sets()[0]]) H.relabel() return H @@ -995,12 +988,13 @@ def HadamardDesign(n): """ from sage.combinat.matrices.hadamard_matrix import hadamard_matrix from sage.matrix.constructor import matrix + H = hadamard_matrix(n + 1) # assumed to be normalised. - H1 = H.matrix_from_columns(range(1,n+1)) - H2 = H1.matrix_from_rows(range(1,n+1)) - J = matrix(ZZ,n,n,[1]*n*n) + H1 = H.matrix_from_columns(range(1, n + 1)) + H2 = H1.matrix_from_rows(range(1, n + 1)) + J = matrix(ZZ, n, n, [1] * n * n) MS = J.parent() - A = MS((H2+J)/2) # convert -1's to 0's; coerce entries to ZZ + A = MS((H2 + J) / 2) # convert -1's to 0's; coerce entries to ZZ # A is the incidence matrix of the block design return IncidenceStructure(incidence_matrix=A, name='HadamardDesign') @@ -1059,9 +1053,10 @@ def Hadamard3Design(n): raise ValueError("The Hadamard design with n = %s does not extend to a three design." % n) from sage.combinat.matrices.hadamard_matrix import hadamard_matrix from sage.matrix.constructor import matrix, block_matrix + H = hadamard_matrix(n) # assumed to be normalised. H1 = H.matrix_from_columns(range(1, n)) - J = matrix(ZZ, n, n-1, [1]*(n-1)*n) + J = matrix(ZZ, n, n - 1, [1] * (n - 1) * n) A1 = (H1 + J) / 2 A2 = (J - H1) / 2 A = block_matrix(1, 2, [A1, A2]) # the incidence matrix of the design. diff --git a/src/sage/combinat/designs/covering_array.py b/src/sage/combinat/designs/covering_array.py index 7ae38b24e8f..c927f3c0bf1 100644 --- a/src/sage/combinat/designs/covering_array.py +++ b/src/sage/combinat/designs/covering_array.py @@ -52,6 +52,7 @@ # ********************************************************************** from .orthogonal_arrays import OA_relabel, OA_standard_label + CA_relabel = OA_relabel CA_standard_label = OA_standard_label @@ -126,12 +127,13 @@ def Kleitman_Spencer_Katona(N): """ from itertools import combinations from sage.arith.misc import integer_ceil + if N < 4: raise ValueError("N must be greater than 3") col_list = [] - for p in combinations(range(N-1), integer_ceil(N/2)): - S = [0]*N + for p in combinations(range(N - 1), integer_ceil(N / 2)): + S = [0] * N for i in p: S[i] = 1 col_list.append(S) @@ -163,14 +165,12 @@ def column_Kleitman_Spencer_Katona(k): NotImplementedError: not implemented for k > 24310 """ - kdict = [(3, 4), (4, 5), (10, 6), (15, 7), (35, 8), (56, 9), - (126, 10), (210, 11), (462, 12), (792, 13), (1716, 14), - (3003, 15), (6435, 16), (11440, 17), (24310, 18)] + kdict = [(3, 4), (4, 5), (10, 6), (15, 7), (35, 8), (56, 9), (126, 10), (210, 11), (462, 12), (792, 13), (1716, 14), (3003, 15), (6435, 16), (11440, 17), (24310, 18)] if k > kdict[-1][0]: raise NotImplementedError("not implemented for k > {}".format(kdict[-1][0])) - for (ki, N) in kdict: + for ki, N in kdict: if k <= ki: return truncate_columns(Kleitman_Spencer_Katona(N), k) @@ -261,6 +261,5 @@ def covering_array(strength, number_columns, levels): if orthogonal_array(number_columns, levels, strength, existence=True) is True: return orthogonal_array(number_columns, levels, strength) - print("No direct construction known and/or implemented for a CA(N; {}, {}, {})".format( - strength, number_columns, levels)) + print("No direct construction known and/or implemented for a CA(N; {}, {}, {})".format(strength, number_columns, levels)) return diff --git a/src/sage/combinat/designs/covering_design.py b/src/sage/combinat/designs/covering_design.py index 2e75b2398d2..0fdf3579d04 100644 --- a/src/sage/combinat/designs/covering_design.py +++ b/src/sage/combinat/designs/covering_design.py @@ -35,6 +35,7 @@ Classes and methods ------------------- """ + # **************************************************************************** # Copyright (C) 2008 Daniel M. Gordon # @@ -146,8 +147,7 @@ def trivial_covering_design(v, k, t): return CoveringDesign(v, k, t, 1, range(v), [blk], 1, "Trivial") if t == 1: # blocks [0, ..., k-1], [k, ..., 2k-1], ... size = Rational((v, k)).ceil() - blocks = [list(range(i * k, (i + 1) * k)) - for i in range(size - 1)] + blocks = [list(range(i * k, (i + 1) * k)) for i in range(size - 1)] # last block: if k does not divide v, wrap around blk = list(range((size - 1) * k, v)) for j in range(k - len(blk)): @@ -156,9 +156,7 @@ def trivial_covering_design(v, k, t): blocks.append(blk) return CoveringDesign(v, k, t, size, range(v), blocks, size, "Trivial") # default case, all k-subsets - return CoveringDesign(v, k, t, binomial(v, k), range(v), - Combinations(range(v), k), schonheim(v, k, t), - "Trivial") + return CoveringDesign(v, k, t, binomial(v, k), range(v), Combinations(range(v), k), schonheim(v, k, t), "Trivial") class CoveringDesign(SageObject): @@ -180,8 +178,7 @@ class CoveringDesign(SageObject): - ``method``, ``creator``, ``timestamp`` -- database information """ - def __init__(self, v=0, k=0, t=0, size=0, points=None, blocks=None, - low_bd=0, method='', creator='', timestamp=''): + def __init__(self, v=0, k=0, t=0, size=0, points=None, blocks=None, low_bd=0, method='', creator='', timestamp=''): """ EXAMPLES:: @@ -229,8 +226,7 @@ def __repr__(self): Lower bound: 7 Method: Projective Plane """ - repr = ('(%d, %d, %d)-covering design of size %d\n' - % (self.__v, self.__k, self.__t, self.__size)) + repr = '(%d, %d, %d)-covering design of size %d\n' % (self.__v, self.__k, self.__t, self.__size) repr += 'Lower bound: %d\n' % (self.__low_bd) if self.__creator: repr += 'Created by: %s\n' % (self.__creator) @@ -263,19 +259,16 @@ def __str__(self): 2 4 5 """ if self.__size == self.__low_bd: # check if covering is optimal - repr = ('C(%d, %d, %d) = %d\n' % - (self.__v, self.__k, self.__t, self.__size)) + repr = 'C(%d, %d, %d) = %d\n' % (self.__v, self.__k, self.__t, self.__size) else: - repr = ('%d <= C(%d, %d, %d) <= %d\n' % (self.__low_bd, - self.__v, self.__k, self.__t, self.__size)) + repr = '%d <= C(%d, %d, %d) <= %d\n' % (self.__low_bd, self.__v, self.__k, self.__t, self.__size) if self.__creator: repr += 'Created by: %s\n' % (self.__creator) if self.__method: repr += 'Method: %s\n' % (self.__method) if self.__timestamp: repr += 'Submitted on: %s\n' % (self.__timestamp) - return repr + '\n'.join(' '.join(str(k) for k in block) for block in - self.__incidence_structure.blocks()) + return repr + '\n'.join(' '.join(str(k) for k in block) for block in self.__incidence_structure.blocks()) def is_covering(self): """ @@ -311,7 +304,7 @@ def is_covering(self): for z in Skt: y = (a[x] for x in z) tset[tuple(y)] = True - return all(tset[tuple(i)] for i in Svt) # everything was covered + return all(tset[tuple(i)] for i in Svt) # everything was covered def v(self): """ diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index ae34a6d2138..3541ff87c8d 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -57,16 +57,13 @@ Functions --------- """ + from __future__ import annotations -from sage.combinat.designs.orthogonal_arrays import (OA_from_quasi_difference_matrix, - QDM_from_Vmt, - OA_from_PBD, - OA_n_times_2_pow_c_from_matrix, - orthogonal_array) +from sage.combinat.designs.orthogonal_arrays import OA_from_quasi_difference_matrix, QDM_from_Vmt, OA_from_PBD, OA_n_times_2_pow_c_from_matrix, orthogonal_array from .orthogonal_arrays import wilson_construction # Cyclic shift of a list -cyclic_shift = lambda l,i : l[-i:]+l[:-i] +cyclic_shift = lambda l, i: l[-i:] + l[:-i] def _MOLS_from_string(s, k): @@ -86,8 +83,9 @@ def _MOLS_from_string(s, k): sage: _ = designs.mutually_orthogonal_latin_squares(2,10) # indirect doctest # needs sage.modules """ from sage.matrix.constructor import Matrix + matrices = [[] for _ in range(k)] - for i,l in enumerate(s.split()): + for i, l in enumerate(s.split()): l = [ord(x) - 97 for x in l] matrices[i % k].append(l) return [Matrix(_) for _ in matrices] @@ -114,27 +112,8 @@ def MOLS_10_2(): True """ from sage.matrix.constructor import Matrix - return [Matrix([[1,8,9,0,2,4,6,3,5,7], - [7,2,8,9,0,3,5,4,6,1], - [6,1,3,8,9,0,4,5,7,2], - [5,7,2,4,8,9,0,6,1,3], - [0,6,1,3,5,8,9,7,2,4], - [9,0,7,2,4,6,8,1,3,5], - [8,9,0,1,3,5,7,2,4,6], - [2,3,4,5,6,7,1,8,9,0], - [3,4,5,6,7,1,2,0,8,9], - [4,5,6,7,1,2,3,9,0,8]]), - - Matrix([[1,7,6,5,0,9,8,2,3,4], - [8,2,1,7,6,0,9,3,4,5], - [9,8,3,2,1,7,0,4,5,6], - [0,9,8,4,3,2,1,5,6,7], - [2,0,9,8,5,4,3,6,7,1], - [4,3,0,9,8,6,5,7,1,2], - [6,5,4,0,9,8,7,1,2,3], - [3,4,5,6,7,1,2,8,0,9], - [5,6,7,1,2,3,4,0,9,8], - [7,1,2,3,4,5,6,9,8,0]])] + + return [Matrix([[1, 8, 9, 0, 2, 4, 6, 3, 5, 7], [7, 2, 8, 9, 0, 3, 5, 4, 6, 1], [6, 1, 3, 8, 9, 0, 4, 5, 7, 2], [5, 7, 2, 4, 8, 9, 0, 6, 1, 3], [0, 6, 1, 3, 5, 8, 9, 7, 2, 4], [9, 0, 7, 2, 4, 6, 8, 1, 3, 5], [8, 9, 0, 1, 3, 5, 7, 2, 4, 6], [2, 3, 4, 5, 6, 7, 1, 8, 9, 0], [3, 4, 5, 6, 7, 1, 2, 0, 8, 9], [4, 5, 6, 7, 1, 2, 3, 9, 0, 8]]), Matrix([[1, 7, 6, 5, 0, 9, 8, 2, 3, 4], [8, 2, 1, 7, 6, 0, 9, 3, 4, 5], [9, 8, 3, 2, 1, 7, 0, 4, 5, 6], [0, 9, 8, 4, 3, 2, 1, 5, 6, 7], [2, 0, 9, 8, 5, 4, 3, 6, 7, 1], [4, 3, 0, 9, 8, 6, 5, 7, 1, 2], [6, 5, 4, 0, 9, 8, 7, 1, 2, 3], [3, 4, 5, 6, 7, 1, 2, 8, 0, 9], [5, 6, 7, 1, 2, 3, 4, 0, 9, 8], [7, 1, 2, 3, 4, 5, 6, 9, 8, 0]])] def MOLS_12_5(): @@ -166,7 +145,7 @@ def MOLS_12_5(): hgfelkjidcba lkjidcbahgfe ijklabcdefgh klijcdabghef efghijklabcd """ - return _MOLS_from_string(M,5) + return _MOLS_from_string(M, 5) def MOLS_14_4(): @@ -212,7 +191,7 @@ def MOLS_14_4(): kmjdneclgbihfa dnhjimbgclfeka ebgcjlkfamindh hkemdacngjblfi """ - return _MOLS_from_string(M,4) + return _MOLS_from_string(M, 4) def MOLS_15_4(): @@ -252,7 +231,7 @@ def MOLS_15_4(): cdefghijklmnoab cfhjmeboldgikna gdokhnelcifbmja kgblchmdineojfa """ - return _MOLS_from_string(M,4) + return _MOLS_from_string(M, 4) def MOLS_18_3(): @@ -295,7 +274,8 @@ def MOLS_18_3(): mjpbnforklgcqhedia qgrodnplbjfhcmieka iklpondqrcmhfgeajb """ - return _MOLS_from_string(M,3) + return _MOLS_from_string(M, 3) + # Index of the MOLS constructions # @@ -304,17 +284,10 @@ def MOLS_18_3(): # This dictionary is used by designs.mutually_orthogonal_latin_squares(k,n). -MOLS_constructions = { - 10 : (2, MOLS_10_2), - 12 : (5, MOLS_12_5), - 14 : (4, MOLS_14_4), - 15 : (4, MOLS_15_4), - 18 : (3, MOLS_18_3) -} +MOLS_constructions = {10: (2, MOLS_10_2), 12: (5, MOLS_12_5), 14: (4, MOLS_14_4), 15: (4, MOLS_15_4), 18: (3, MOLS_18_3)} # Add this data to the module's doc -LIST_OF_MOLS_CONSTRUCTIONS = ", ".join(":func:`{} MOLS of order {} `".format(k,n,n,k) - for n,(k,_) in MOLS_constructions.items()) +LIST_OF_MOLS_CONSTRUCTIONS = ", ".join(":func:`{} MOLS of order {} `".format(k, n, n, k) for n, (k, _) in MOLS_constructions.items()) def OA_7_18(): @@ -351,24 +324,19 @@ def OA_7_18(): """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic from sage.categories.cartesian_product import cartesian_product - G = cartesian_product([AdditiveCyclic(2),AdditiveCyclic(3),AdditiveCyclic(3)]) + + G = cartesian_product([AdditiveCyclic(2), AdditiveCyclic(3), AdditiveCyclic(3)]) M = [G([int(_) for _ in xx]) for xx in M.split()] - M = [M[i*12:(i+1)*12] for i in range(7)] + M = [M[i * 12 : (i + 1) * 12] for i in range(7)] Mb = [] - for a,b,c,d,e,f,g in zip(*M): + for a, b, c, d, e, f, g in zip(*M): for y in range(3): - Mb.append([a + G((0, 0 , 0 )), - b + G((0, 0 , y )), - c + G((0, y , 0 )), - d + G((0, 2*y , y )), - e + G((0, 2*y ,2*y)), - f + G((0, y ,2*y)), - g + G((0, 0 ,2*y))]) - - M = OA_from_quasi_difference_matrix(Mb,G,add_col=False) - M = [M[i] for i in range(len(M)) if i % 18 < 9] # only develop w.r.t the last two coordinates + Mb.append([a + G((0, 0, 0)), b + G((0, 0, y)), c + G((0, y, 0)), d + G((0, 2 * y, y)), e + G((0, 2 * y, 2 * y)), f + G((0, y, 2 * y)), g + G((0, 0, 2 * y))]) + + M = OA_from_quasi_difference_matrix(Mb, G, add_col=False) + M = [M[i] for i in range(len(M)) if i % 18 < 9] # only develop w.r.t the last two coordinates return M @@ -398,19 +366,10 @@ def OA_9_40(): """ from sage.rings.finite_rings.finite_field_constructor import FiniteField - A = [ - [(0,None),(0,None),(0,None),(0,None),(0,None),(0,None),(0,None),(0,None),(0,None),(0,None)], - [(0,None),(1,None), (2,2), (3,2), (4,2),(2,None),(3,None),(4,None), (0,2), (1,2)], - [(0,None), (2,5), (4,5), (1,2), (3,6), (3,4), (0,0), (2,1), (4,1), (1,6)], - [(0,None), (3,4), (1,4), (4,0), (2,5),(3,None), (1,0), (4,1), (2,2), (0,3)], - [(0,None), (4,6),(3,None), (2,3), (1,4), (2,1),(1,None), (0,4), (4,0), (3,2)], - [(0,None), (1,2), (4,6), (4,4), (1,0), (0,6), (2,3), (3,6), (3,5), (2,5)], - [(1,None), (0,3), (1,2), (4,5),(4,None), (2,3), (0,0), (2,2), (3,0),(3,None)], - [(4,None), (1,3), (0,0), (1,1), (4,0), (3,1), (2,5),(0,None), (2,1),(3,None)] - ] + A = [[(0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None)], [(0, None), (1, None), (2, 2), (3, 2), (4, 2), (2, None), (3, None), (4, None), (0, 2), (1, 2)], [(0, None), (2, 5), (4, 5), (1, 2), (3, 6), (3, 4), (0, 0), (2, 1), (4, 1), (1, 6)], [(0, None), (3, 4), (1, 4), (4, 0), (2, 5), (3, None), (1, 0), (4, 1), (2, 2), (0, 3)], [(0, None), (4, 6), (3, None), (2, 3), (1, 4), (2, 1), (1, None), (0, 4), (4, 0), (3, 2)], [(0, None), (1, 2), (4, 6), (4, 4), (1, 0), (0, 6), (2, 3), (3, 6), (3, 5), (2, 5)], [(1, None), (0, 3), (1, 2), (4, 5), (4, None), (2, 3), (0, 0), (2, 2), (3, 0), (3, None)], [(4, None), (1, 3), (0, 0), (1, 1), (4, 0), (3, 1), (2, 5), (0, None), (2, 1), (3, None)]] Y = [None, 0, 1, 6, 5, 4, 3, 2] - return OA_n_times_2_pow_c_from_matrix(9,3,FiniteField(5),A,Y,check=False) + return OA_n_times_2_pow_c_from_matrix(9, 3, FiniteField(5), A, Y, check=False) def OA_7_66(): @@ -440,7 +399,7 @@ def OA_7_66(): # base block of a (73,9,1) BIBD B = [0, 19, 26, 14, 63, 15, 32, 35, 65] # The corresponding BIBD - BIBD = [[(x+i) % 73 for x in B] for i in range(73)] + BIBD = [[(x + i) % 73 for x in B] for i in range(73)] # the first 7 elements of an oval # # (this is the only difference with the OA(7,68) construction) @@ -449,9 +408,9 @@ def OA_7_66(): PBD = [[x for x in B if x not in oval] for B in BIBD] # We relabel the points to 0,1,2,... V = [x for x in range(73) if x not in oval] - rel = dict(zip(V,range(len(V)))) + rel = dict(zip(V, range(len(V)))) PBD = [[rel[x] for x in B] for B in PBD] - return OA_from_PBD(7,66,PBD,check=False) + return OA_from_PBD(7, 66, PBD, check=False) def OA_7_68(): @@ -481,7 +440,7 @@ def OA_7_68(): # base block of a (73,9,1) BIBD B = [0, 19, 26, 14, 63, 15, 32, 35, 65] # The corresponding BIBD - BIBD = [[(x+i) % 73 for x in B] for i in range(73)] + BIBD = [[(x + i) % 73 for x in B] for i in range(73)] # the first 5 elements of an oval # # (this is the only difference with the OA(7,66) construction) @@ -490,9 +449,9 @@ def OA_7_68(): PBD = [[x for x in B if x not in oval] for B in BIBD] # We relabel the points to 0,1,2,... V = [x for x in range(73) if x not in oval] - rel = dict(zip(V,range(len(V)))) + rel = dict(zip(V, range(len(V)))) PBD = [[rel[x] for x in B] for B in PBD] - return OA_from_PBD(7,68,PBD,check=False) + return OA_from_PBD(7, 68, PBD, check=False) def OA_8_69(): @@ -519,10 +478,10 @@ def OA_8_69(): True """ # base block of a (73,9,1) BIBD - B = [1,2,4,8,16,32,37,55,64] + B = [1, 2, 4, 8, 16, 32, 37, 55, 64] # The corresponding BIBD - BIBD = [[(x+i) % 73 for x in B] for i in range(73)] - oval = [72,71,69,65] + BIBD = [[(x + i) % 73 for x in B] for i in range(73)] + oval = [72, 71, 69, 65] # PBD minus the oval PBD = [[x for x in B if x not in oval] for B in BIBD] @@ -535,35 +494,35 @@ def OA_8_69(): # We split them into "balanced" halves. O1 = sets_of_size_seven[:3] O2 = sets_of_size_seven[-3:] - assert all(x in sum(O1,[]) for x in (68,27,52)) - assert all(x in sum(O2,[]) for x in (68,27,52)) + assert all(x in sum(O1, []) for x in (68, 27, 52)) + assert all(x in sum(O2, []) for x in (68, 27, 52)) # Blocks of "others", without the 0..0,1..1,2..2 ... rows - OA = OA_from_PBD(8,69,others,check=False)[:-69] + OA = OA_from_PBD(8, 69, others, check=False)[:-69] # Blocks of O1 - OA_8_7 = orthogonal_array(8,7,check=False) + OA_8_7 = orthogonal_array(8, 7, check=False) for B in O1: for BB in OA_8_7: OA.append([B[i] for i in BB]) # Blocks of O2 OA_8_7_minus_TD_8_1 = OA_8_7 - OA_8_7_minus_TD_8_1.remove([0]*8) + OA_8_7_minus_TD_8_1.remove([0] * 8) for B in O2: # Making sure the double element is the first one - B.sort(key=lambda x: int(bool(x not in (68,27,52)))) + B.sort(key=lambda x: int(bool(x not in (68, 27, 52)))) for BB in OA_8_7: OA.append([B[i] for i in BB]) # Adding the missing 0..0,1..1,... rows - done = sum(O1,[])+sum(O2,[]) + done = sum(O1, []) + sum(O2, []) missing = [x for x in range(73) if x not in done and x not in oval] for x in missing: - OA.append([x]*8) + OA.append([x] * 8) # Relabelling everything to 0..68 - relabel = dict(zip([x for x in range(73) if x not in oval],range(69))) + relabel = dict(zip([x for x in range(73) if x not in oval], range(69))) OA = [[relabel[x] for x in B] for B in OA] return OA @@ -593,9 +552,9 @@ def OA_7_74(): """ # base block of a (91,10,1) BIBD - B = [0,1,3,9,27,81,61,49,56,77] + B = [0, 1, 3, 9, 27, 81, 61, 49, 56, 77] # The corresponding BIBD - BIBD = [[(x+i) % 91 for x in B] for i in range(91)] + BIBD = [[(x + i) % 91 for x in B] for i in range(91)] # an oval oval = [(-x) % 91 for x in B][-7:] # PBD minus the oval+B @@ -604,9 +563,9 @@ def OA_7_74(): PBD.remove([]) # We relabel the points to 0,1,2,... V = [x for x in range(91) if x not in to_delete] - rel = dict(zip(V,range(len(V)))) + rel = dict(zip(V, range(len(V)))) PBD = [[rel[x] for x in B] for B in PBD] - return OA_from_PBD(7,74,PBD,check=False) + return OA_from_PBD(7, 74, PBD, check=False) def OA_8_76(): @@ -633,10 +592,10 @@ def OA_8_76(): True """ # base block of a (91,10,1) BIBD - B = [0,1,3,9,27,81,61,49,56,77] + B = [0, 1, 3, 9, 27, 81, 61, 49, 56, 77] # The corresponding BIBD - BIBD = [[(x+i) % 91 for x in B] for i in range(91)] - oval = [2,4,5,12,24] + BIBD = [[(x + i) % 91 for x in B] for i in range(91)] + oval = [2, 4, 5, 12, 24] to_remove = oval + B # PBD minus the oval PBD = [[x for x in B if x not in to_remove] for B in BIBD] @@ -647,32 +606,32 @@ def OA_8_76(): # critical_points are the 10 elements appearing twice in the rows of the 10 # sets_of_size_seven, and each row contains exactly two of them - critical_points = [57,83,52,13,15,64,37,50,63,31] + critical_points = [57, 83, 52, 13, 15, 64, 37, 50, 63, 31] # We reorder the rows such that every element of critical_points is exactly # once the first element of a row. - for i,x in zip(critical_points,sets_of_size_seven): - x.sort(key=lambda x:-int(x == i)) + for i, x in zip(critical_points, sets_of_size_seven): + x.sort(key=lambda x: -int(x == i)) assert x[0] == i # Blocks of "others", without the 0..0,1..1,2..2 ... rows - OA = OA_from_PBD(8,76,others,check=False)[:-76] + OA = OA_from_PBD(8, 76, others, check=False)[:-76] - OA_8_7 = orthogonal_array(8,7,check=False) + OA_8_7 = orthogonal_array(8, 7, check=False) OA_8_7_minus_TD_8_1 = OA_8_7 - OA_8_7_minus_TD_8_1.remove([0]*8) + OA_8_7_minus_TD_8_1.remove([0] * 8) for B in sets_of_size_seven: for BB in OA_8_7: OA.append([B[i] for i in BB]) # Adding the missing 0..0,1..1,... rows - done = sum(sets_of_size_seven,[]) + done = sum(sets_of_size_seven, []) missing = [x for x in range(91) if x not in done and x not in to_remove] for x in missing: - OA.append([x]*8) + OA.append([x] * 8) # Relabelling everything to 0..68 - relabel = dict(zip([x for x in range(91) if x not in to_remove],range(91))) + relabel = dict(zip([x for x in range(91) if x not in to_remove], range(91))) OA = [[relabel[x] for x in B] for B in OA] return OA @@ -703,21 +662,10 @@ def OA_11_80(): """ from sage.rings.finite_rings.finite_field_constructor import FiniteField - A = [ - [(0,None), (0,None), (0,None), (0,None), (0,None), (0,None), (0,None), (0,None), (0,None), (0,None)], - [(0,None), (1,None), (2,3), (3,None), (4,3), (2,None), (3,3), (4,None), (0,3), (1,3)], - [(0,None), (2,8), (4,6), (1,3), (3,3), (3,13), (0,13), (2,6), (4,14), (1,12)], - [(0,None), (3,11), (1,0), (4,9), (2,0), (3,7), (1,8), (4,10), (2,10), (0,11)], - [(0,None), (4,8), (3,14), (2,14), (1,12), (2,10), (1,10), (0,3), (4,5), (3,8)], - [(0,None), (1,8), (4,14), (4,12), (1,1), (0,1), (2,8), (3,12), (3,6), (2,1)], - [(1,None), (0,6), (1,1), (4,4), (4,13), (2,6), (0,14), (2,9), (3,0), (3,3)], - [(4,None), (1,9), (0,7), (1,1), (4,8), (3,5), (2,14), (0,0), (2,None), (3,0)], - [(4,None), (4,6), (1,2), (0,None), (1,13), (3,8), (3,2), (2,0), (0,14), (2,None)], - [(1,None), (4,9), (4,1), (1,0), (0,4), (2,5), (3,None), (3,5), (2,None), (0,None)] - ] + A = [[(0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None)], [(0, None), (1, None), (2, 3), (3, None), (4, 3), (2, None), (3, 3), (4, None), (0, 3), (1, 3)], [(0, None), (2, 8), (4, 6), (1, 3), (3, 3), (3, 13), (0, 13), (2, 6), (4, 14), (1, 12)], [(0, None), (3, 11), (1, 0), (4, 9), (2, 0), (3, 7), (1, 8), (4, 10), (2, 10), (0, 11)], [(0, None), (4, 8), (3, 14), (2, 14), (1, 12), (2, 10), (1, 10), (0, 3), (4, 5), (3, 8)], [(0, None), (1, 8), (4, 14), (4, 12), (1, 1), (0, 1), (2, 8), (3, 12), (3, 6), (2, 1)], [(1, None), (0, 6), (1, 1), (4, 4), (4, 13), (2, 6), (0, 14), (2, 9), (3, 0), (3, 3)], [(4, None), (1, 9), (0, 7), (1, 1), (4, 8), (3, 5), (2, 14), (0, 0), (2, None), (3, 0)], [(4, None), (4, 6), (1, 2), (0, None), (1, 13), (3, 8), (3, 2), (2, 0), (0, 14), (2, None)], [(1, None), (4, 9), (4, 1), (1, 0), (0, 4), (2, 5), (3, None), (3, 5), (2, None), (0, None)]] Y = [None, 0, 1, 14, 12, 7, 2, 11, 3, 6] - return OA_n_times_2_pow_c_from_matrix(11,4,FiniteField(5),A,Y,check=False) + return OA_n_times_2_pow_c_from_matrix(11, 4, FiniteField(5), A, Y, check=False) def OA_15_112(): @@ -747,24 +695,24 @@ def OA_15_112(): from sage.rings.finite_rings.finite_field_constructor import FiniteField A = [ - [(0,None), (0,None), (0,None), (0,None), (0,None), (0,None), (0,None), (0,None), (1,None), (4,None), (2,None), (2,None), (4,None), (1,None)], - [(0,None), (1,None), (2,None), (3, 5), (4, 9), (5, 11), (6, 12), (1, 10), (0, 10), (1, 11), (4, 13), (2, 6), (2, 2), (4, 1)], - [(0,None), (2, 3), (4, 6), (6, 0), (1, 1), (3, 12), (5, 6), (4, 2), (1, 9), (0, 3), (1, 7), (4, 7), (2, 8), (2, 5)], - [(0,None), (3, 3), (6, 2), (2, 3), (5, 2), (1, 9), (4, 13), (2, 8), (4, 12), (1, 12), (0, 7), (1, 10), (4, 11), (2, 14)], - [(0,None), (4,None), (1, 0), (5, 1), (2, 0), (6, 7), (3, 4), (2, 11), (2, 9), (4, 13), (1, 3), (0, 7), (1, 11), (4, 2)], - [(0,None), (5,None), (3, 14), (1, 7), (6, 5), (4, 3), (2, 1), (4, 6), (2, 5), (2, 14), (4, 12), (1, 1), (0, 2), (1, 2)], - [(0,None), (6,None), (5, 0), (4, 4), (3, 11), (2, 2), (1, 7), (1, 13), (4, 8), (2, 11), (2, 3), (4,None), (1, 8), (0, 10)], - [(0,None), (4, 3), (2, 14), (1, 5), (1, 4), (2, 5), (4, 2), (0, 8), (6, 10), (3, 11), (5, 6), (5, 5), (3, 0), (6, 11)], - [(0,None), (5, 3), (4, 0), (4, 6), (5, 4), (0, 3), (3, 11), (6,None), (0, 4), (6, 5), (3, 13), (5, 6), (5, 4), (3, 4)], - [(0,None), (6, 3), (6, 4), (0, 5), (2, 5), (5, 5), (2,None), (3, 6), (6, 7), (0, 12), (6, 12), (3, 12), (5,None), (5, 10)], - [(0,None), (0, 3), (1,None), (3, 9), (6, 8), (3, 14), (1, 14), (5, 6), (3, 8), (6, 13), (0, 8), (6, 3), (3, 9), (5, 0)], # the last 3,9 was a 3,3 - [(0,None), (1, 3), (3, 1), (6, 6), (3,None), (1, 10), (0, 1), (5, 7), (5, 7), (3, 14), (6, 0), (0, 10), (6, 9), (3, 6)], - [(0,None), (2,None), (5, 3), (2, 10), (0, 8), (6, 5), (6, 0), (3, 7), (5, 1), (5, 12), (3, 14), (6, 4), (0, 10), (6, 4)], - [(0,None), (3,None), (0, 4), (5, 6), (4, 1), (4, 7), (5, 1), (6, 8), (3, 2), (5, 2), (5, 2), (3, 13), (6, 7), (0, 2)] + [(0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (1, None), (4, None), (2, None), (2, None), (4, None), (1, None)], + [(0, None), (1, None), (2, None), (3, 5), (4, 9), (5, 11), (6, 12), (1, 10), (0, 10), (1, 11), (4, 13), (2, 6), (2, 2), (4, 1)], + [(0, None), (2, 3), (4, 6), (6, 0), (1, 1), (3, 12), (5, 6), (4, 2), (1, 9), (0, 3), (1, 7), (4, 7), (2, 8), (2, 5)], + [(0, None), (3, 3), (6, 2), (2, 3), (5, 2), (1, 9), (4, 13), (2, 8), (4, 12), (1, 12), (0, 7), (1, 10), (4, 11), (2, 14)], + [(0, None), (4, None), (1, 0), (5, 1), (2, 0), (6, 7), (3, 4), (2, 11), (2, 9), (4, 13), (1, 3), (0, 7), (1, 11), (4, 2)], + [(0, None), (5, None), (3, 14), (1, 7), (6, 5), (4, 3), (2, 1), (4, 6), (2, 5), (2, 14), (4, 12), (1, 1), (0, 2), (1, 2)], + [(0, None), (6, None), (5, 0), (4, 4), (3, 11), (2, 2), (1, 7), (1, 13), (4, 8), (2, 11), (2, 3), (4, None), (1, 8), (0, 10)], + [(0, None), (4, 3), (2, 14), (1, 5), (1, 4), (2, 5), (4, 2), (0, 8), (6, 10), (3, 11), (5, 6), (5, 5), (3, 0), (6, 11)], + [(0, None), (5, 3), (4, 0), (4, 6), (5, 4), (0, 3), (3, 11), (6, None), (0, 4), (6, 5), (3, 13), (5, 6), (5, 4), (3, 4)], + [(0, None), (6, 3), (6, 4), (0, 5), (2, 5), (5, 5), (2, None), (3, 6), (6, 7), (0, 12), (6, 12), (3, 12), (5, None), (5, 10)], + [(0, None), (0, 3), (1, None), (3, 9), (6, 8), (3, 14), (1, 14), (5, 6), (3, 8), (6, 13), (0, 8), (6, 3), (3, 9), (5, 0)], # the last 3,9 was a 3,3 + [(0, None), (1, 3), (3, 1), (6, 6), (3, None), (1, 10), (0, 1), (5, 7), (5, 7), (3, 14), (6, 0), (0, 10), (6, 9), (3, 6)], + [(0, None), (2, None), (5, 3), (2, 10), (0, 8), (6, 5), (6, 0), (3, 7), (5, 1), (5, 12), (3, 14), (6, 4), (0, 10), (6, 4)], + [(0, None), (3, None), (0, 4), (5, 6), (4, 1), (4, 7), (5, 1), (6, 8), (3, 2), (5, 2), (5, 2), (3, 13), (6, 7), (0, 2)], ] Y = [None, 0, 1, 14, 12, 7, 2, 11, 3, 4, 5, 10, 8, 6] - return OA_n_times_2_pow_c_from_matrix(15,4,FiniteField(7),list(zip(*A)),Y,check=False) + return OA_n_times_2_pow_c_from_matrix(15, 4, FiniteField(7), list(zip(*A)), Y, check=False) def OA_9_120(): @@ -796,20 +744,20 @@ def OA_9_120(): True """ RBIBD_120 = RBIBD_120_8_1() - equiv = [RBIBD_120[i*15:(i+1)*15] for i in range(17)] + equiv = [RBIBD_120[i * 15 : (i + 1) * 15] for i in range(17)] - OA8 = orthogonal_array(9,8) - assert all( (len(set(B[:-1])) == 1) == (B[-1] == 0) for B in OA8) + OA8 = orthogonal_array(9, 8) + assert all((len(set(B[:-1])) == 1) == (B[-1] == 0) for B in OA8) OA = [] - for i,classs in enumerate(equiv): + for i, classs in enumerate(equiv): for S in classs: for B in OA8: if B[-1] != 0: - OA.append([S[x] for x in B[:-1]]+[i*7+B[-1]]) + OA.append([S[x] for x in B[:-1]] + [i * 7 + B[-1]]) for i in range(120): - OA.append([i]*8+[0]) + OA.append([i] * 8 + [0]) return OA @@ -852,8 +800,9 @@ def OA_9_135(): """ from .bibd import BIBD_from_difference_family from .difference_family import singer_difference_set - G,B = singer_difference_set(16,2) - PG16 = BIBD_from_difference_family(G,B) + + G, B = singer_difference_set(16, 2) + PG16 = BIBD_from_difference_family(G, B) n = 273 @@ -862,7 +811,7 @@ def OA_9_135(): # 0,1, or 3 points. The set of points congruent to 0 mod 39 does the job! # # ... check that it works - assert all(sum((x % 39 == 0) for x in B) in [0,1,3] for B in PG16) + assert all(sum((x % 39 == 0) for x in B) in [0, 1, 3] for B in PG16) # We now build an OA(17,16) from our PG16, in such a way that all points of # our PG(2,2) are in different columns. For this, we need to find a point p @@ -874,8 +823,8 @@ def OA_9_135(): # We can now build a TD from our PG16 by removing p. for B in PG16: - B.sort(key=lambda x:int(x % 39 != 0)) - PG16.sort(key=lambda B:sum((x % 39 == 0) for x in B)) + B.sort(key=lambda x: int(x % 39 != 0)) + PG16.sort(key=lambda B: sum((x % 39 == 0) for x in B)) r = {} for B in PG16: @@ -883,21 +832,21 @@ def OA_9_135(): for x in B: if x != p: r[x] = len(r) - r[p] = n-1 + r[p] = n - 1 # The columns containing points from PG2 will be the last 7 - assert all(r[x*39] >= (n-1)-16*7 for x in range(7)) + assert all(r[x * 39] >= (n - 1) - 16 * 7 for x in range(7)) # Those points are the first of each column - assert all(r[x*39] % 16 == 0 for x in range(7)) + assert all(r[x * 39] % 16 == 0 for x in range(7)) PG = [sorted([r[x] for x in B]) for B in PG16] - OA = [[x % 16 for x in B] for B in PG if n-1 not in B] + OA = [[x % 16 for x in B] for B in PG if n - 1 not in B] # We truncate the last 7 columns to size 1. We also drop the first column - truncated_OA = [B[1:-7]+[x if x == 0 else None for x in B[-7:]] for B in OA] + truncated_OA = [B[1:-7] + [x if x == 0 else None for x in B[-7:]] for B in OA] # And call Wilson's construction - return wilson_construction(truncated_OA, 9, 16, 8, (1,)*7, check=False) + return wilson_construction(truncated_OA, 9, 16, 8, (1,) * 7, check=False) def OA_11_160(): @@ -927,21 +876,21 @@ def OA_11_160(): from sage.rings.finite_rings.finite_field_constructor import FiniteField A = [ - [(0,None), (0,None), (0,None), (0,None), (0,None), (0,None), (1,None), (4,None), (4,None), (1,None)], - [(0,None), (1,None), (2, 5), (3, 9), (4, 9), (1, 16), (0, 20), (1, 23), (4, 24), (4, 19)], - [(0,None), (2, 4), (4, 3), (1, 10), (3, 10), (4, 20), (1, 1), (0, 24), (1, 5), (4, 2)], - [(0,None), (3,None), (1, 28), (4, 7), (2, 6), (4, 4), (4, 23), (1, 5), (0, 8), (1, 1)], - [(0,None), (4, 4), (3, 25), (2, 24), (1, 13), (1, 6), (4, 6), (4, 2), (1, 18), (0, 1)], - [(0,None), (2,None), (3, 3), (3, 21), (2, 18), (0, 6), (2, 20), (3, 3), (3, 11), (2, 1)], - [(0,None), (3, 4), (0, 5), (1, 27), (1, 30), (2,None), (0, 0), (2, 2), (3, 2), (3, 18)], - [(0,None), (4,None), (2, 19), (4, 26), (0, 12), (3, 19), (2, 4), (0, 2), (2, 0), (3, 0)], - [(0,None), (0, 4), (4, 29), (2, 29), (4,None), (3, 0), (3, 0), (2, 1), (0, 18), (2,None)], - [(0,None), (1, 4), (1, 5), (0, 19), (3, 2), (2, 0), (3,None), (3, 0), (2,None), (0,None)], - ] + [(0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (1, None), (4, None), (4, None), (1, None)], + [(0, None), (1, None), (2, 5), (3, 9), (4, 9), (1, 16), (0, 20), (1, 23), (4, 24), (4, 19)], + [(0, None), (2, 4), (4, 3), (1, 10), (3, 10), (4, 20), (1, 1), (0, 24), (1, 5), (4, 2)], + [(0, None), (3, None), (1, 28), (4, 7), (2, 6), (4, 4), (4, 23), (1, 5), (0, 8), (1, 1)], + [(0, None), (4, 4), (3, 25), (2, 24), (1, 13), (1, 6), (4, 6), (4, 2), (1, 18), (0, 1)], + [(0, None), (2, None), (3, 3), (3, 21), (2, 18), (0, 6), (2, 20), (3, 3), (3, 11), (2, 1)], + [(0, None), (3, 4), (0, 5), (1, 27), (1, 30), (2, None), (0, 0), (2, 2), (3, 2), (3, 18)], + [(0, None), (4, None), (2, 19), (4, 26), (0, 12), (3, 19), (2, 4), (0, 2), (2, 0), (3, 0)], + [(0, None), (0, 4), (4, 29), (2, 29), (4, None), (3, 0), (3, 0), (2, 1), (0, 18), (2, None)], + [(0, None), (1, 4), (1, 5), (0, 19), (3, 2), (2, 0), (3, None), (3, 0), (2, None), (0, None)], + ] Y = [None, 0, 1, 2, 15, 27, 22, 12, 3, 28] - return OA_n_times_2_pow_c_from_matrix(11,5,FiniteField(5),list(zip(*A)),Y,check=False) + return OA_n_times_2_pow_c_from_matrix(11, 5, FiniteField(5), list(zip(*A)), Y, check=False) def OA_16_176(): @@ -971,32 +920,32 @@ def OA_16_176(): from sage.rings.finite_rings.finite_field_constructor import FiniteField A = [ - [(0 ,None),(0 ,None),(0 ,None),(0 ,None),(0 ,None),(0 ,None),(0 ,None),(0 ,None),(0 ,None),(0 ,None),(0 ,None),(0 ,None),(1 ,None),(4 ,None),(9 ,None)], - [(0 ,None),(1 ,None),(2 ,None),(3 , 0),(4 , 2),(5 , 12),(6 , 5),(7 , 6),(8 , 13),(9 , 9),(10, 11),(1 , 3),(0 , 6),(1 , 14),(4 , 12)], - [(0 ,None),(2 ,None),(4 , 4),(6 , 4),(8 , 7),(10, 2),(1 , 2),(3 , 13),(5 , 0),(7 , 3),(9 , 7),(4 , 6),(1 , 12),(0 , 1),(1 , 10)], # 5,1 became 5,0 - [(0 ,None),(3 ,None),(6 , 3),(9 , 4),(1 , 6),(4 , 13),(7 , 1),(10, 1),(2 , 7),(5 , 1),(8 , 0),(9 , 6),(4 , 4),(1 , 5),(0 , 1)], - [(0 ,None),(4 ,None),(8 , 13),(1 , 8),(5 , 0),(9 , 5),(2 , 14),(6 ,None),(10, 5),(3 , 7),(7 , 10),(5 , 3),(9 , 10),(4 , 11),(1 , 14)], - [(0 ,None),(5 ,None),(10, 10),(4 , 2),(9 , 7),(3 , 2),(8 , 3),(2 , 13),(7 , 7),(1 , 9),(6 ,None),(3 , 7),(5 , 1),(9 , 10),(4 , 11)], - [(0 ,None),(6 ,None),(1 , 8),(7 , 14),(2 , 2),(8 , 3),(3 , 11),(9 , 12),(4 , 8),(10, 13),(5 , 1),(3 , 6),(3 , 5),(5 , 10),(9 , 9)], - [(0 ,None),(7 ,None),(3 , 3),(10,None),(6 , 14),(2 , 4),(9 , 1),(5 , 7),(1 , 5),(8 , 7),(4 , 13),(5 , 6),(3 , 6),(3 , 11),(5 , 3)], - [(0 ,None),(8 ,None),(5 , 14),(2 , 11),(10, 14),(7 , 8),(4 , 14),(1 , 14),(9 , 9),(6 , 14),(3 , 9),(9 , 2),(5 , 6),(3 , 3),(3 , 10)], - [(0 ,None),(9 ,None),(7 , 5),(5 , 5),(3 , 8),(1 , 8),(10,None),(8 , 12),(6 , 9),(4 , 12),(2 , 9),(4 , 7),(9 , 2),(5 , 0),(3 , 7)], - [(0 ,None),(10,None),(9 , 11),(8 , 7),(7 , 6),(6 , 12),(5 ,None),(4 , 1),(3 , 13),(2 , 8),(1 , 9),(1 ,None),(4 , 3),(9 , 7),(5 , 13)], - [(0 ,None),(6 , 3),(2 , 0),(10, 8),(8 , 12),(7 , 9),(7 , 2),(8 , 0),(10, 7),(2 , 10),(6 , 4),(0 , 7),(10, 10),(7 , 3),(2 , 11)], - [(0 ,None),(7 , 3),(4 ,None),(2 , 12),(1 , 10),(1 , 3),(2 , 8),(4 , 9),(7 , 0),(0 , 1),(5 , 6),(10, 3),(0 , 9),(10, 13),(7 , 11)], - [(0 ,None),(8 , 3),(6 , 8),(5 , 2),(5 , 13),(6 , 1),(8 , 9),(0 , 2),(4 , 10),(9 , 8),(4 , 12),(7 , 7),(10, 2),(0 , 12),(10, 4)], - [(0 ,None),(9 , 3),(8 , 3),(8 , 9),(9 , 1),(0 , 4),(3 , 3),(7 , 11),(1 , 9),(7 , 10),(3 , 8),(2 , 10),(7 , 6),(10, 14),(0 , 3)], - [(0 ,None),(10, 3),(10, 5),(0 , 1),(2 , 1),(5 , 8),(9 , 2),(3 , 5),(9 , 5),(5 , 3),(2 , 4),(6 , 12),(2 , 6),(7 , 11),(10, 7)], - [(0 ,None),(0 , 3),(1 ,None),(3 , 2),(6 , 8),(10, 11),(4 , 6),(10,None),(6 ,None),(3 , 1),(1 , 1),(8 , 0),(6 , 14),(2 , 0),(7 , 14)], - [(0 ,None),(1 , 3),(3 , 8),(6 , 9),(10, 8),(4 , 10),(10, 1),(6 , 10),(3 , 0),(1 , 8),(0 , 11),(8 , 10),(8 , 14),(6 , 10),(2 , 14)], - [(0 ,None),(2 , 3),(5 , 1),(9 , 8),(3 , 4),(9 , 14),(5 , 5),(2 , 4),(0 , 2),(10, 2),(10,None),(6 , 2),(8 , 5),(8 , 1),(6 , 9)], - [(0 ,None),(3 , 3),(7 , 0),(1 ,None),(7 , 1),(3 , 10),(0 , 8),(9 , 13),(8 ,None),(8 , 10),(9 , 14),(2 , 0),(6 , 5),(8 , 5),(8 , 7)], # 2,None became 2,0 - [(0 ,None),(4 , 3),(9 , 10),(4 , 14),(0 , 14),(8 , 14),(6 , 14),(5 , 6),(5 , 13),(6 , 5),(8 , 12),(7 , 1),(2 , 4),(6 , 3),(8 , 6)], - [(0 ,None),(5 , 3),(0 , 8),(7 , 3),(4 , 10),(2 , 1),(1 , 3),(1 , 10),(2 ,None),(4 , 8),(7 , 12),(10, 6),(7 , 10),(2 , 6),(6 , 1)], # 7,12 became 4,8 + [(0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (1, None), (4, None), (9, None)], + [(0, None), (1, None), (2, None), (3, 0), (4, 2), (5, 12), (6, 5), (7, 6), (8, 13), (9, 9), (10, 11), (1, 3), (0, 6), (1, 14), (4, 12)], + [(0, None), (2, None), (4, 4), (6, 4), (8, 7), (10, 2), (1, 2), (3, 13), (5, 0), (7, 3), (9, 7), (4, 6), (1, 12), (0, 1), (1, 10)], # 5,1 became 5,0 + [(0, None), (3, None), (6, 3), (9, 4), (1, 6), (4, 13), (7, 1), (10, 1), (2, 7), (5, 1), (8, 0), (9, 6), (4, 4), (1, 5), (0, 1)], + [(0, None), (4, None), (8, 13), (1, 8), (5, 0), (9, 5), (2, 14), (6, None), (10, 5), (3, 7), (7, 10), (5, 3), (9, 10), (4, 11), (1, 14)], + [(0, None), (5, None), (10, 10), (4, 2), (9, 7), (3, 2), (8, 3), (2, 13), (7, 7), (1, 9), (6, None), (3, 7), (5, 1), (9, 10), (4, 11)], + [(0, None), (6, None), (1, 8), (7, 14), (2, 2), (8, 3), (3, 11), (9, 12), (4, 8), (10, 13), (5, 1), (3, 6), (3, 5), (5, 10), (9, 9)], + [(0, None), (7, None), (3, 3), (10, None), (6, 14), (2, 4), (9, 1), (5, 7), (1, 5), (8, 7), (4, 13), (5, 6), (3, 6), (3, 11), (5, 3)], + [(0, None), (8, None), (5, 14), (2, 11), (10, 14), (7, 8), (4, 14), (1, 14), (9, 9), (6, 14), (3, 9), (9, 2), (5, 6), (3, 3), (3, 10)], + [(0, None), (9, None), (7, 5), (5, 5), (3, 8), (1, 8), (10, None), (8, 12), (6, 9), (4, 12), (2, 9), (4, 7), (9, 2), (5, 0), (3, 7)], + [(0, None), (10, None), (9, 11), (8, 7), (7, 6), (6, 12), (5, None), (4, 1), (3, 13), (2, 8), (1, 9), (1, None), (4, 3), (9, 7), (5, 13)], + [(0, None), (6, 3), (2, 0), (10, 8), (8, 12), (7, 9), (7, 2), (8, 0), (10, 7), (2, 10), (6, 4), (0, 7), (10, 10), (7, 3), (2, 11)], + [(0, None), (7, 3), (4, None), (2, 12), (1, 10), (1, 3), (2, 8), (4, 9), (7, 0), (0, 1), (5, 6), (10, 3), (0, 9), (10, 13), (7, 11)], + [(0, None), (8, 3), (6, 8), (5, 2), (5, 13), (6, 1), (8, 9), (0, 2), (4, 10), (9, 8), (4, 12), (7, 7), (10, 2), (0, 12), (10, 4)], + [(0, None), (9, 3), (8, 3), (8, 9), (9, 1), (0, 4), (3, 3), (7, 11), (1, 9), (7, 10), (3, 8), (2, 10), (7, 6), (10, 14), (0, 3)], + [(0, None), (10, 3), (10, 5), (0, 1), (2, 1), (5, 8), (9, 2), (3, 5), (9, 5), (5, 3), (2, 4), (6, 12), (2, 6), (7, 11), (10, 7)], + [(0, None), (0, 3), (1, None), (3, 2), (6, 8), (10, 11), (4, 6), (10, None), (6, None), (3, 1), (1, 1), (8, 0), (6, 14), (2, 0), (7, 14)], + [(0, None), (1, 3), (3, 8), (6, 9), (10, 8), (4, 10), (10, 1), (6, 10), (3, 0), (1, 8), (0, 11), (8, 10), (8, 14), (6, 10), (2, 14)], + [(0, None), (2, 3), (5, 1), (9, 8), (3, 4), (9, 14), (5, 5), (2, 4), (0, 2), (10, 2), (10, None), (6, 2), (8, 5), (8, 1), (6, 9)], + [(0, None), (3, 3), (7, 0), (1, None), (7, 1), (3, 10), (0, 8), (9, 13), (8, None), (8, 10), (9, 14), (2, 0), (6, 5), (8, 5), (8, 7)], # 2,None became 2,0 + [(0, None), (4, 3), (9, 10), (4, 14), (0, 14), (8, 14), (6, 14), (5, 6), (5, 13), (6, 5), (8, 12), (7, 1), (2, 4), (6, 3), (8, 6)], + [(0, None), (5, 3), (0, 8), (7, 3), (4, 10), (2, 1), (1, 3), (1, 10), (2, None), (4, 8), (7, 12), (10, 6), (7, 10), (2, 6), (6, 1)], # 7,12 became 4,8 ] Y = [None, 0, 1, 2, 8, 6, 9, 4, 10, 3, 5, 11, 13, 14, 12] - return OA_n_times_2_pow_c_from_matrix(16,4,FiniteField(11),list(zip(*A)),Y,check=False) + return OA_n_times_2_pow_c_from_matrix(16, 4, FiniteField(11), list(zip(*A)), Y, check=False) def OA_11_185(): @@ -1030,13 +979,13 @@ def OA_11_185(): """ from sage.combinat.designs.difference_family import difference_family - G,(B,) = difference_family(273,17) - BIBD = [[int(x+i) for x in B] for i in G] # a cyclic PG(2,16) + G, (B,) = difference_family(273, 17) + BIBD = [[int(x + i) for x in B] for i in G] # a cyclic PG(2,16) # All points congruent to 0 mod[39] form a Fano subplane with the property # that each block of the PG(2,16) intersect the Fano subplane in either 0,1 # or 3 points - assert all(sum(x % 39 == 0 for x in B) in [0,1,3] for B in BIBD) + assert all(sum(x % 39 == 0 for x in B) in [0, 1, 3] for B in BIBD) # Lines of the Fano subplane that are contained in blocks fano_lines = [B for B in BIBD if sum(x % 39 == 0 for x in B) == 3] @@ -1050,16 +999,16 @@ def OA_11_185(): # The PBD ground_set = not_on_a_fano_line.union(fano_lines[0]) PBD = [ground_set.intersection(B) for B in BIBD] - relabel = {v:i for i,v in enumerate(ground_set)} + relabel = {v: i for i, v in enumerate(ground_set)} PBD = [[relabel[x] for x in B] for B in PBD if len(B) > 1] special_set = [relabel[x] for x in fano_lines[0]] # Check that everything is fine - assert all(len(B) in (11,13) or set(B) == set(special_set) for B in PBD) + assert all(len(B) in (11, 13) or set(B) == set(special_set) for B in PBD) - OA = OA_from_PBD(11,185,[B for B in PBD if len(B) < 17],check=False)[:-185] - OA.extend([i]*11 for i in range(185) if i not in special_set) - OA.extend([special_set[x] for x in B] for B in orthogonal_array(11,17)) + OA = OA_from_PBD(11, 185, [B for B in PBD if len(B) < 17], check=False)[:-185] + OA.extend([i] * 11 for i in range(185) if i not in special_set) + OA.extend([special_set[x] for x in B] for B in orthogonal_array(11, 17)) return OA @@ -1105,43 +1054,39 @@ def OA_10_205(): True """ # Base block of a cyclic PG(2,4^2) - pplane_size = 16**2+16+1 - baer_subplane_size = 4**2+4+1 + pplane_size = 16**2 + 16 + 1 + baer_subplane_size = 4**2 + 4 + 1 B = [0, 1, 22, 33, 83, 122, 135, 141, 145, 159, 175, 200, 226, 229, 231, 238, 246] - pplane = [[(xx+i) % pplane_size for xx in B] for i in range(pplane_size)] - baer_subplane = {i * pplane_size / baer_subplane_size - for i in range(baer_subplane_size)} + pplane = [[(xx + i) % pplane_size for xx in B] for i in range(pplane_size)] + baer_subplane = {i * pplane_size / baer_subplane_size for i in range(baer_subplane_size)} p = list(baer_subplane)[0] # We want all lines through p, but keep only 9 of those which intersect the # subplane on 1 point. lines_through_p = [B for B in pplane if p in B] - lines_through_p.sort(key=lambda s:len(baer_subplane.intersection(s))) + lines_through_p.sort(key=lambda s: len(baer_subplane.intersection(s))) # Remove the Baer subplane and relabel everything to a (204,{9,13})-GDD of type # 12^5.16^9 whose groups are the subset of (truncated) lines through p - groups = [[xx for xx in l if xx not in baer_subplane] for l in lines_through_p[4**2-4-9:]] - relabel = {v:i for i,v in enumerate(sum(groups,[]))} + groups = [[xx for xx in l if xx not in baer_subplane] for l in lines_through_p[4**2 - 4 - 9 :]] + relabel = {v: i for i, v in enumerate(sum(groups, []))} GDD = [[relabel[xx] for xx in B if xx in relabel] for B in pplane if p not in B] # We turn the GDD into a PBD by extending the groups with a new point 204. - GDD.extend([relabel[xx] for xx in G]+[204] for G in groups) + GDD.extend([relabel[xx] for xx in G] + [204] for G in groups) # We build the OA, knowing that the blocks of size 9 are disjoint blocks_of_size_9 = [B for B in GDD if len(B) == 9] - blocks_of_size_9_union = sum(blocks_of_size_9,[]) + blocks_of_size_9_union = sum(blocks_of_size_9, []) - OA = OA_from_PBD(10,205,[B for B in GDD if len(B) != 9],check=False)[:-205] + OA = OA_from_PBD(10, 205, [B for B in GDD if len(B) != 9], check=False)[:-205] - OA.extend([B[xx] for xx in R] - for R in orthogonal_array(10,9) - for B in blocks_of_size_9) + OA.extend([B[xx] for xx in R] for R in orthogonal_array(10, 9) for B in blocks_of_size_9) # The missing [i,i,...] blocks - OA.extend([i]*10 - for i in set(range(205)).difference(blocks_of_size_9_union)) + OA.extend([i] * 10 for i in set(range(205)).difference(blocks_of_size_9_union)) return OA @@ -1173,37 +1118,37 @@ def OA_16_208(): from sage.rings.finite_rings.finite_field_constructor import FiniteField A = [ - [(0 ,None), (0 ,None), (0 ,None), (0 ,None), (0 ,None), (0 ,None), (0 ,None), (0 ,None), (0 ,None), (0 ,None), (0 ,None), (0 ,None), (0 ,None), (0 ,None), (1 ,None)], - [(0 ,None), (1 ,None), (2 , 0), (3 , 7), (4 , 1), (5 , 11), (6 , 2), (7 , 10), (8 ,None), (9 , 10), (10,None), (11, 3), (12, 3), (1 , 4), (0 , 8)], - [(0 ,None), (2 ,None), (4 , 4), (6 , 3), (8 , 0), (10, 5), (12, 14), (1 ,None), (3 , 10), (5 , 7), (7 , 3), (9 , 12), (11, 6), (4 , 9), (1 , 14)], - [(0 ,None), (3 ,None), (6 , 4), (9 , 6), (12, 10), (2 , 11), (5 , 14), (8 , 3), (11, 13), (1 , 1), (4 , 12), (7 , 14), (10, 1), (9 , 7), (4 , 8)], - [(0 ,None), (4 ,None), (8 , 9), (12, 5), (3 , 10), (7 , 14), (11, 0), (2 , 6), (6 , 11), (10, 11), (1 , 9), (5 , 3), (9 , 9), (3 , 6), (9 , 8)], - [(0 ,None), (5 ,None), (10, 5), (2 , 5), (7 , 3), (12, 3), (4 , 12), (9 , 3), (1 , 2), (6 , 2), (11,None), (3 , 13), (8 , 7), (12, 10), (3 , 1)], - [(0 ,None), (6 ,None), (12, 13), (5 , 5), (11, 13), (4 , 6), (10, 6), (3 , 2), (9 , 4), (2 , 12), (8 , 13), (1 , 13), (7 , 2), (10, 8), (12,None)], - [(0 ,None), (7 ,None), (1 , 2), (8 , 12), (2 , 4), (9 , 12), (3 , 0), (10, 10), (4 , 14), (11, 11), (5 , 14), (12, 9), (6 , 8), (10, 3), (10, 6)], - [(0 ,None), (8 ,None), (3 ,None), (11, 4), (6 , 12), (1 , 12), (9 , 14), (4 , 2), (12, 9), (7 , 9), (2 ,None), (10, 1), (5 , 14), (12, 5), (10, 8)], - [(0 ,None), (9 ,None), (5 , 9), (1 , 7), (10, 6), (6 , 3), (2 , 6), (11, 10), (7 , 11), (3 , 13), (12, 2), (8 , 0), (4 , 13), (3 , 3), (12, 14)], - [(0 ,None), (10,None), (7 , 7), (4 , 1), (1 , 8), (11, 1), (8 , 11), (5 , 4), (2 , 11), (12, 8), (9 , 12), (6 , 4), (3 , 0), (9 , 4), (3 , 8)], - [(0 ,None), (11,None), (9 , 3), (7 , 11), (5 , 14), (3 , 10), (1 , 10), (12, 0), (10, 2), (8 , 2), (6 , 6), (4 , 2), (2 , 12), (4 , 8), (9 , 10)], - [(0 ,None), (12,None), (11, 4), (10, 9), (9 , 2), (8 ,None), (7 , 9), (6 , 12), (5 , 5), (4 ,None), (3 , 7), (2 , 10), (1 , 13), (1 , 6), (4 , 0)], - [(0 ,None), (5 , 3), (7 , 5), (6 , 5), (2 , 14), (8 , 5), (11, 1), (11, 6), (8 , 13), (2 , 13), (6 , 9), (7 ,None), (5 , 10), (0 , 5), (2 , 8)], - [(0 ,None), (6 , 3), (9 , 4), (9 , 13), (6 , 4), (0 , 5), (4 , 6), (5 , 2), (3 ,None), (11, 14), (3 , 3), (5 , 7), (4 , 1), (2 , 8), (0 , 2)], - [(0 ,None), (7 , 3), (11, 5), (12, 12), (10,None), (5 , 5), (10, 7), (12, 9), (11, 9), (7 , 7), (0 , 0), (3 , 12), (3 , 11), (8 , 13), (2 , 14)], - [(0 ,None), (8 , 3), (0 , 8), (2 , 6), (1 ,None), (10, 9), (3 , 12), (6 , 8), (6 , 4), (3 , 9), (10, 2), (1 , 11), (2 , 7), (5 , 2), (8 , 2)], - [(0 ,None), (9 , 3), (2 , 3), (5 , 3), (5 , 8), (2 , 0), (9 , 1), (0 , 3), (1 , 14), (12, 3), (7 , 6), (12, 4), (1 , 3), (6 , 10), (5 , 7)], - [(0 ,None), (10, 3), (4 , 2), (8 , 0), (9 , 8), (7 , 1), (2 , 5), (7 ,None), (9 , 2), (8 , 4), (4 , 14), (10, 13), (0 , 10), (11, 7), (6 , 10)], - [(0 ,None), (11, 3), (6 , 9), (11, 14), (0 , 10), (12, 13), (8 , 6), (1 , 8), (4 , 7), (4 , 0), (1 , 14), (8 , 2), (12, 8), (7 , 10), (11, 7)], # 6,10 became 6,9 - [(0 ,None), (12, 3), (8 , 12), (1 , 9), (4 , 6), (4 , 13), (1 , 6), (8 , 1), (12, 4), (0 , 7), (11, 5), (6 , 6), (11, 14), (7 , 3), (7 , 5)], - [(0 ,None), (0 , 3), (10, 10), (4 , 2), (8 , 1), (9 ,None), (7 , 2), (2 , 10), (7 , 13), (9 , 5), (8 , 14), (4 , 7), (10, 11), (11, 13), (7 , 0)], - [(0 ,None), (1 , 3), (12, 11), (7 , 12), (12, 13), (1 , 2), (0 , 9), (9 , 6), (2 , 13), (5 , 4), (5 , 13), (2 , 4), (9 , 12), (6 , 5), (11, 1)], - [(0 ,None), (2 , 3), (1 , 8), (10,None), (3 , 13), (6 ,None), (6 , 1), (3 , 0), (10, 4), (1 , 14), (2 , 0), (0 , 3), (8 , 13), (5 , 1), (6 , 7)], # 2,None became 2,0 - [(0 ,None), (3 , 3), (3 , 14), (0 , 1), (7 , 14), (11, 4), (12, 9), (10, 1), (5 , 9), (10,None), (12, 13), (11,None), (7 , 7), (8 , 6), (5 , 0)], - [(0 ,None), (4 , 3), (5 , 10), (3 , 8), (11, 8), (3 , 0), (5 , 7), (4 , 12), (0 , 13), (6 ,None), (9 , 11), (9 , 5), (6 , 0), (2 , 5), (8 , 8)], + [(0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (1, None)], + [(0, None), (1, None), (2, 0), (3, 7), (4, 1), (5, 11), (6, 2), (7, 10), (8, None), (9, 10), (10, None), (11, 3), (12, 3), (1, 4), (0, 8)], + [(0, None), (2, None), (4, 4), (6, 3), (8, 0), (10, 5), (12, 14), (1, None), (3, 10), (5, 7), (7, 3), (9, 12), (11, 6), (4, 9), (1, 14)], + [(0, None), (3, None), (6, 4), (9, 6), (12, 10), (2, 11), (5, 14), (8, 3), (11, 13), (1, 1), (4, 12), (7, 14), (10, 1), (9, 7), (4, 8)], + [(0, None), (4, None), (8, 9), (12, 5), (3, 10), (7, 14), (11, 0), (2, 6), (6, 11), (10, 11), (1, 9), (5, 3), (9, 9), (3, 6), (9, 8)], + [(0, None), (5, None), (10, 5), (2, 5), (7, 3), (12, 3), (4, 12), (9, 3), (1, 2), (6, 2), (11, None), (3, 13), (8, 7), (12, 10), (3, 1)], + [(0, None), (6, None), (12, 13), (5, 5), (11, 13), (4, 6), (10, 6), (3, 2), (9, 4), (2, 12), (8, 13), (1, 13), (7, 2), (10, 8), (12, None)], + [(0, None), (7, None), (1, 2), (8, 12), (2, 4), (9, 12), (3, 0), (10, 10), (4, 14), (11, 11), (5, 14), (12, 9), (6, 8), (10, 3), (10, 6)], + [(0, None), (8, None), (3, None), (11, 4), (6, 12), (1, 12), (9, 14), (4, 2), (12, 9), (7, 9), (2, None), (10, 1), (5, 14), (12, 5), (10, 8)], + [(0, None), (9, None), (5, 9), (1, 7), (10, 6), (6, 3), (2, 6), (11, 10), (7, 11), (3, 13), (12, 2), (8, 0), (4, 13), (3, 3), (12, 14)], + [(0, None), (10, None), (7, 7), (4, 1), (1, 8), (11, 1), (8, 11), (5, 4), (2, 11), (12, 8), (9, 12), (6, 4), (3, 0), (9, 4), (3, 8)], + [(0, None), (11, None), (9, 3), (7, 11), (5, 14), (3, 10), (1, 10), (12, 0), (10, 2), (8, 2), (6, 6), (4, 2), (2, 12), (4, 8), (9, 10)], + [(0, None), (12, None), (11, 4), (10, 9), (9, 2), (8, None), (7, 9), (6, 12), (5, 5), (4, None), (3, 7), (2, 10), (1, 13), (1, 6), (4, 0)], + [(0, None), (5, 3), (7, 5), (6, 5), (2, 14), (8, 5), (11, 1), (11, 6), (8, 13), (2, 13), (6, 9), (7, None), (5, 10), (0, 5), (2, 8)], + [(0, None), (6, 3), (9, 4), (9, 13), (6, 4), (0, 5), (4, 6), (5, 2), (3, None), (11, 14), (3, 3), (5, 7), (4, 1), (2, 8), (0, 2)], + [(0, None), (7, 3), (11, 5), (12, 12), (10, None), (5, 5), (10, 7), (12, 9), (11, 9), (7, 7), (0, 0), (3, 12), (3, 11), (8, 13), (2, 14)], + [(0, None), (8, 3), (0, 8), (2, 6), (1, None), (10, 9), (3, 12), (6, 8), (6, 4), (3, 9), (10, 2), (1, 11), (2, 7), (5, 2), (8, 2)], + [(0, None), (9, 3), (2, 3), (5, 3), (5, 8), (2, 0), (9, 1), (0, 3), (1, 14), (12, 3), (7, 6), (12, 4), (1, 3), (6, 10), (5, 7)], + [(0, None), (10, 3), (4, 2), (8, 0), (9, 8), (7, 1), (2, 5), (7, None), (9, 2), (8, 4), (4, 14), (10, 13), (0, 10), (11, 7), (6, 10)], + [(0, None), (11, 3), (6, 9), (11, 14), (0, 10), (12, 13), (8, 6), (1, 8), (4, 7), (4, 0), (1, 14), (8, 2), (12, 8), (7, 10), (11, 7)], # 6,10 became 6,9 + [(0, None), (12, 3), (8, 12), (1, 9), (4, 6), (4, 13), (1, 6), (8, 1), (12, 4), (0, 7), (11, 5), (6, 6), (11, 14), (7, 3), (7, 5)], + [(0, None), (0, 3), (10, 10), (4, 2), (8, 1), (9, None), (7, 2), (2, 10), (7, 13), (9, 5), (8, 14), (4, 7), (10, 11), (11, 13), (7, 0)], + [(0, None), (1, 3), (12, 11), (7, 12), (12, 13), (1, 2), (0, 9), (9, 6), (2, 13), (5, 4), (5, 13), (2, 4), (9, 12), (6, 5), (11, 1)], + [(0, None), (2, 3), (1, 8), (10, None), (3, 13), (6, None), (6, 1), (3, 0), (10, 4), (1, 14), (2, 0), (0, 3), (8, 13), (5, 1), (6, 7)], # 2,None became 2,0 + [(0, None), (3, 3), (3, 14), (0, 1), (7, 14), (11, 4), (12, 9), (10, 1), (5, 9), (10, None), (12, 13), (11, None), (7, 7), (8, 6), (5, 0)], + [(0, None), (4, 3), (5, 10), (3, 8), (11, 8), (3, 0), (5, 7), (4, 12), (0, 13), (6, None), (9, 11), (9, 5), (6, 0), (2, 5), (8, 8)], ] Y = [None, 0, 1, 2, 12, 9, 13, 11, 7, 4, 8, 5, 14, 6, 3] - return OA_n_times_2_pow_c_from_matrix(16,4,FiniteField(13),list(zip(*A)),Y,check=False) + return OA_n_times_2_pow_c_from_matrix(16, 4, FiniteField(13), list(zip(*A)), Y, check=False) def OA_15_224(): @@ -1233,25 +1178,25 @@ def OA_15_224(): from sage.rings.finite_rings.finite_field_constructor import FiniteField A = [ - [(0,None), (0,None), (0,None), (0,None), (0,None), (0,None), (0,None), (0,None), (1,None), (4,None), (2,None), (2,None), (4,None), (1,None)], - [(0,None), (1,None), (2, 9), (3, 23), (4, 29), (5, 4), (6, 30), (1, 26), (0,None), (1, 11), (4, 2), (2, 28), (2,None), (4, 13)], - [(0,None), (2,None), (4, 8), (6,None), (1, 29), (3, 21), (5, 4), (4, 5), (1, 4), (0, 14), (1, 5), (4, 6), (2, 0), (2, 2)], - [(0,None), (3,None), (6, 8), (2, 12), (5, 4), (1, 1), (4, 2), (2, 1), (4, 18), (1, 27), (0, 5), (1,None), (4, 1), (2,None)], - [(0,None), (4,None), (1, 9), (5, 2), (2, 29), (6, 17), (3, 0), (2, 12), (2, 5), (4, 22), (1, 0), (0, 29), (1, 19), (4,None)], - [(0,None), (5,None), (3, 26), (1, 0), (6, 29), (4, 16), (2, 11), (4, 21), (2, 28), (2, 16), (4, 0), (1, 3), (0, 11), (1, 2)], - [(0,None), (6,None), (5, 3), (4, 19), (3, 24), (2, 20), (1, 28), (1, 12), (4, 23), (2, 0), (2, 5), (4, 29), (1, 0), (0, 2)], - [(0,None), (4, 4), (2, 14), (1, 23), (1, 22), (2, 17), (4, 17), (0, 25), (6, 21), (3, 11), (5, 2), (5, 27), (3, 5), (6, 2)], - [(0,None), (5, 4), (4, 3), (4, 0), (5, 20), (0, 4), (3, 8), (6, 28), (0, 16), (6, 1), (3, 22), (5, 0), (5, 0), (3, 2)], - [(0,None), (6, 4), (6,None), (0, 18), (2, 0), (5, 20), (2, 4), (3, 11), (6, 15), (0, 18), (6, 5), (3, 0), (5,None), (5, 2)], - [(0,None), (0, 4), (1, 15), (3, 29), (6, 20), (3, 24), (1, 13), (5, 30), (3, 2), (6,None), (0, 10), (6, 3), (3, 0), (5,None)], - [(0,None), (1, 4), (3, 4), (6, 12), (3, 28), (1, 27), (0, 6), (5, 7), (5, 29), (3, 0), (6, 0), (0, 0), (6, 0), (3,None)], # 6,19 became 6,12 - [(0,None), (2, 4), (5, 11), (2, 5), (0, 21), (6, 11), (6, 24), (3, 24), (5, 11), (5, 30), (3,None), (6,None), (0,None), (6, 1)], - [(0,None), (3, 4), (0, 11), (5, 11), (4, 22), (4, 2), (5, 23), (6, 22), (3, 27), (5, 1), (5, 0), (3,None), (6,None), (0,None)] + [(0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (1, None), (4, None), (2, None), (2, None), (4, None), (1, None)], + [(0, None), (1, None), (2, 9), (3, 23), (4, 29), (5, 4), (6, 30), (1, 26), (0, None), (1, 11), (4, 2), (2, 28), (2, None), (4, 13)], + [(0, None), (2, None), (4, 8), (6, None), (1, 29), (3, 21), (5, 4), (4, 5), (1, 4), (0, 14), (1, 5), (4, 6), (2, 0), (2, 2)], + [(0, None), (3, None), (6, 8), (2, 12), (5, 4), (1, 1), (4, 2), (2, 1), (4, 18), (1, 27), (0, 5), (1, None), (4, 1), (2, None)], + [(0, None), (4, None), (1, 9), (5, 2), (2, 29), (6, 17), (3, 0), (2, 12), (2, 5), (4, 22), (1, 0), (0, 29), (1, 19), (4, None)], + [(0, None), (5, None), (3, 26), (1, 0), (6, 29), (4, 16), (2, 11), (4, 21), (2, 28), (2, 16), (4, 0), (1, 3), (0, 11), (1, 2)], + [(0, None), (6, None), (5, 3), (4, 19), (3, 24), (2, 20), (1, 28), (1, 12), (4, 23), (2, 0), (2, 5), (4, 29), (1, 0), (0, 2)], + [(0, None), (4, 4), (2, 14), (1, 23), (1, 22), (2, 17), (4, 17), (0, 25), (6, 21), (3, 11), (5, 2), (5, 27), (3, 5), (6, 2)], + [(0, None), (5, 4), (4, 3), (4, 0), (5, 20), (0, 4), (3, 8), (6, 28), (0, 16), (6, 1), (3, 22), (5, 0), (5, 0), (3, 2)], + [(0, None), (6, 4), (6, None), (0, 18), (2, 0), (5, 20), (2, 4), (3, 11), (6, 15), (0, 18), (6, 5), (3, 0), (5, None), (5, 2)], + [(0, None), (0, 4), (1, 15), (3, 29), (6, 20), (3, 24), (1, 13), (5, 30), (3, 2), (6, None), (0, 10), (6, 3), (3, 0), (5, None)], + [(0, None), (1, 4), (3, 4), (6, 12), (3, 28), (1, 27), (0, 6), (5, 7), (5, 29), (3, 0), (6, 0), (0, 0), (6, 0), (3, None)], # 6,19 became 6,12 + [(0, None), (2, 4), (5, 11), (2, 5), (0, 21), (6, 11), (6, 24), (3, 24), (5, 11), (5, 30), (3, None), (6, None), (0, None), (6, 1)], + [(0, None), (3, 4), (0, 11), (5, 11), (4, 22), (4, 2), (5, 23), (6, 22), (3, 27), (5, 1), (5, 0), (3, None), (6, None), (0, None)], ] Y = [None, 0, 1, 2, 27, 22, 11, 4, 26, 25, 29, 24, 7, 20] - return OA_n_times_2_pow_c_from_matrix(15,5,FiniteField(7),list(zip(*A)),Y,check=False) + return OA_n_times_2_pow_c_from_matrix(15, 5, FiniteField(7), list(zip(*A)), Y, check=False) def OA_11_254(): @@ -1284,14 +1229,14 @@ def OA_11_254(): """ # Base block of a PG(2,19) - B = (0,1,19,28,96,118,151,153,176,202,240,254,290,296,300,307,337,361,366,369) - BIBD = [[(x+i) % 381 for x in B] for i in range(381)] + B = (0, 1, 19, 28, 96, 118, 151, 153, 176, 202, 240, 254, 290, 296, 300, 307, 337, 361, 366, 369) + BIBD = [[(x + i) % 381 for x in B] for i in range(381)] # We only keep points congruent to 0,1 mod 3 and relabel the PBD. The result is # a (254,{11,13,16})-PBD - BIBD = [[2*(x//3)+x % 3 for x in B if x % 3 < 2] for B in BIBD] + BIBD = [[2 * (x // 3) + x % 3 for x in B if x % 3 < 2] for B in BIBD] - return OA_from_PBD(11,254,BIBD,check=False) + return OA_from_PBD(11, 254, BIBD, check=False) def OA_20_352(): @@ -1325,33 +1270,33 @@ def OA_20_352(): # Column 14,line 1 : 4,1 became 4,0 # Column 18,line 18: 0,0 became 0,None A = [ - [(0,None),(0, None),(0,None),(0,None),(0,None),(0,None),(0,None),(0,None),(0,None),(0,None),(0,None),(0,None),(1,None),(4,None),(9,None),(5, None),(3,None),(3,None),(5,None)], - [(0,None),(1, None),(2, 13),(3, 2),(4, 0),(5, 8),(6, 30),(7, 0),(8, 13),(9, 26),(10, 10),(1, 29),(0, 9),(1, 11),(4, 0),(9, 23),(5, 7),(3, 25),(3, 29)], - [(0,None),(2, None),(4, 29),(6, 6),(8, 3),(10, 18),(1, 21),(3, 24),(5, 4),(7, 7),(9, 29),(4, 22),(1, 2),(0, 27),(1, 10),(4, 13),(9, 22),(5, 6),(3, 20)], - [(0,None),(3, None),(6, 25),(9, 21),(1, 23),(4, 25),(7, 12),(10, 16),(2, 26),(5, 27),(8, 19),(9, 27),(4, 6),(1, 5),(0, 6),(1, 15),(4, 10),(9, 2),(5, 14)], - [(0,None),(4, None),(8, 3),(1, 23),(5, 17),(9, 7),(2, 7),(6, 25),(10, 27),(3, 30),(7, 5),(5, 23),(9, 24),(4, 16),(1, 12),(0, 8),(1, 12),(4, 17),(9, 28)], - [(0,None),(5, None),(10, 10),(4, 27),(9, 4),(3, 24),(8, 21),(2, 3),(7, 22),(1, 21),(6, 24),(3, 28),(5, 3),(9, 26),(4, 29),(1, 9),(0, 19),(1, 2),(4, 0)], - [(0,None),(6, None),(1, 11),(7, 9),(2, 14),(8, 15),(3, 11),(9, 7),(4, 27),(10, 13),(5, 4),(3, 18),(3, 0),(5, 5),(9, 2),(4, 7),(1, 30),(0, 10),(1,None)], - [(0,None),(7, None),(3, 25),(10, 7),(6, 29),(2, 4),(9, 10),(5, 22),(1, 25),(8, 18),(4, 11),(5, 21),(3, 29),(3, 14),(5, 12),(9, 25),(4, 2),(1, 13),(0, 19)], - [(0,None),(8, None),(5, 27),(2, 30),(10, 24),(7, 4),(4, 6),(1, 4),(9, 5),(6, 27),(3, 0),(9, 2),(5, 20),(3, 10),(3, 13),(5, 2),(9, 5),(4, 21),(1, 12)], - [(0,None),(9, None),(7, 21),(5, 0),(3, 9),(1, 13),(10, 17),(8, 1),(6, 15),(4, 30),(2, 28),(4, 3),(9, 28),(5, 0),(3,None),(3, 2),(5, 23),(9, 10),(4, 15)], - [(0,None),(10,None),(9, 29),(8, 8),(7, 6),(6, 6),(5, 18),(4, 20),(3, 22),(2, 7),(1, 13),(1, 24),(4, 13),(9, 14),(5, 29),(3, 27),(3, 16),(5, 12),(9, 4)], - [(0,None),(6, 4),(2, 17),(10, 16),(8, 26),(7, 17),(7, 21),(8, 9),(10, 2),(2, 25),(6, 27),(0, 20),(10, 8),(7, 12),(2, 26),(6, 22),(8, 8),(8, 16),(6, 13)], - [(0,None),(7, 4),(4, 1),(2, 0),(1, 8),(1, 18),(2, 10),(4, 9),(7, 2),(0, 11),(5, 27),(10, 27),(0, 16),(10, 19),(7, 0),(2, 2),(6, 26),(8, 30),(8, 6)], - [(0,None),(8, 4),(6, 19),(5, 24),(5, 16),(6, 20),(8,None),(0, 17),(4, 5),(9, 23),(4, 27),(7, 22),(10, 25),(0, 23),(10, 11),(7, 10),(2, 16),(6, 28),(8, 3)], - [(0,None),(9, 4),(8, 14),(8, 30),(9, 16),(0, 0),(3, 25),(7, 30),(1, 27),(7, 4),(3, 10),(2, 5),(7, 3),(10, 11),(0, 21),(10,None),(7, 7),(2, 19),(6, 24)], - [(0,None),(10, 4),(10, 30),(0, 12),(2, 9),(5, 9),(9, 0),(3, 14),(9, 17),(5, 17),(2, 18),(6, 10),(2, 0),(7, 16),(10, 23),(0, 1),(10, 26),(7, 18),(2, 9)], - [(0,None),(0, 4),(1, 13),(3, 28),(6, 25),(10, 28),(4, 16),(10, 17),(6, 23),(3, 7),(1, 22),(8, 22),(6, 27),(2, 29),(7, 5),(10, 14),(0, 12),(10, 14),(7, 6)], - [(0,None),(1, 4),(3, 6),(6, 4),(10, 13),(4, 12),(10, 15),(6, 27),(3,None),(1, 26),(0, 3),(8, 21),(8, 26),(6, 13),(2, 27),(7, 11),(10, 5),(0, 3),(10, 3)], - [(0,None),(2, 4),(5, 12),(9, 27),(3, 7),(9, 21),(5,None),(2, 22),(0, 28),(10, 30),(10, 25),(6, 12),(8, 6),(8, 30),(6, 28),(2, 6),(7, 26),(10, 3),(0,None)], - [(0,None),(3, 4),(7, 22),(1, 7),(7, 8),(3, 12),(0, 27),(9, 1),(8, 17),(8, 4),(9, 12),(2, 16),(6, 23),(8, 14),(8, 2),(6, 26),(2, 14),(7, 22),(10, 30)], - [(0,None),(4, 4),(9, 21),(4, 25),(0, 9),(8, 23),(6, 5),(5, 20),(5, 13),(6, 19),(8, 0),(7, 30),(2, 29),(6, 24),(8, 18),(8, 10),(6, 9),(2, 20),(7, 4)], - [(0,None),(5, 4),(0, 25),(7, 4),(4, 20),(2, 3),(1,None),(1, 21),(2,None),(4, 26),(7, 1),(10, 23),(7, 20),(2, 3),(6, 5),(8, 19),(8, 9),(6, 23),(2, 7)], + [(0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (1, None), (4, None), (9, None), (5, None), (3, None), (3, None), (5, None)], + [(0, None), (1, None), (2, 13), (3, 2), (4, 0), (5, 8), (6, 30), (7, 0), (8, 13), (9, 26), (10, 10), (1, 29), (0, 9), (1, 11), (4, 0), (9, 23), (5, 7), (3, 25), (3, 29)], + [(0, None), (2, None), (4, 29), (6, 6), (8, 3), (10, 18), (1, 21), (3, 24), (5, 4), (7, 7), (9, 29), (4, 22), (1, 2), (0, 27), (1, 10), (4, 13), (9, 22), (5, 6), (3, 20)], + [(0, None), (3, None), (6, 25), (9, 21), (1, 23), (4, 25), (7, 12), (10, 16), (2, 26), (5, 27), (8, 19), (9, 27), (4, 6), (1, 5), (0, 6), (1, 15), (4, 10), (9, 2), (5, 14)], + [(0, None), (4, None), (8, 3), (1, 23), (5, 17), (9, 7), (2, 7), (6, 25), (10, 27), (3, 30), (7, 5), (5, 23), (9, 24), (4, 16), (1, 12), (0, 8), (1, 12), (4, 17), (9, 28)], + [(0, None), (5, None), (10, 10), (4, 27), (9, 4), (3, 24), (8, 21), (2, 3), (7, 22), (1, 21), (6, 24), (3, 28), (5, 3), (9, 26), (4, 29), (1, 9), (0, 19), (1, 2), (4, 0)], + [(0, None), (6, None), (1, 11), (7, 9), (2, 14), (8, 15), (3, 11), (9, 7), (4, 27), (10, 13), (5, 4), (3, 18), (3, 0), (5, 5), (9, 2), (4, 7), (1, 30), (0, 10), (1, None)], + [(0, None), (7, None), (3, 25), (10, 7), (6, 29), (2, 4), (9, 10), (5, 22), (1, 25), (8, 18), (4, 11), (5, 21), (3, 29), (3, 14), (5, 12), (9, 25), (4, 2), (1, 13), (0, 19)], + [(0, None), (8, None), (5, 27), (2, 30), (10, 24), (7, 4), (4, 6), (1, 4), (9, 5), (6, 27), (3, 0), (9, 2), (5, 20), (3, 10), (3, 13), (5, 2), (9, 5), (4, 21), (1, 12)], + [(0, None), (9, None), (7, 21), (5, 0), (3, 9), (1, 13), (10, 17), (8, 1), (6, 15), (4, 30), (2, 28), (4, 3), (9, 28), (5, 0), (3, None), (3, 2), (5, 23), (9, 10), (4, 15)], + [(0, None), (10, None), (9, 29), (8, 8), (7, 6), (6, 6), (5, 18), (4, 20), (3, 22), (2, 7), (1, 13), (1, 24), (4, 13), (9, 14), (5, 29), (3, 27), (3, 16), (5, 12), (9, 4)], + [(0, None), (6, 4), (2, 17), (10, 16), (8, 26), (7, 17), (7, 21), (8, 9), (10, 2), (2, 25), (6, 27), (0, 20), (10, 8), (7, 12), (2, 26), (6, 22), (8, 8), (8, 16), (6, 13)], + [(0, None), (7, 4), (4, 1), (2, 0), (1, 8), (1, 18), (2, 10), (4, 9), (7, 2), (0, 11), (5, 27), (10, 27), (0, 16), (10, 19), (7, 0), (2, 2), (6, 26), (8, 30), (8, 6)], + [(0, None), (8, 4), (6, 19), (5, 24), (5, 16), (6, 20), (8, None), (0, 17), (4, 5), (9, 23), (4, 27), (7, 22), (10, 25), (0, 23), (10, 11), (7, 10), (2, 16), (6, 28), (8, 3)], + [(0, None), (9, 4), (8, 14), (8, 30), (9, 16), (0, 0), (3, 25), (7, 30), (1, 27), (7, 4), (3, 10), (2, 5), (7, 3), (10, 11), (0, 21), (10, None), (7, 7), (2, 19), (6, 24)], + [(0, None), (10, 4), (10, 30), (0, 12), (2, 9), (5, 9), (9, 0), (3, 14), (9, 17), (5, 17), (2, 18), (6, 10), (2, 0), (7, 16), (10, 23), (0, 1), (10, 26), (7, 18), (2, 9)], + [(0, None), (0, 4), (1, 13), (3, 28), (6, 25), (10, 28), (4, 16), (10, 17), (6, 23), (3, 7), (1, 22), (8, 22), (6, 27), (2, 29), (7, 5), (10, 14), (0, 12), (10, 14), (7, 6)], + [(0, None), (1, 4), (3, 6), (6, 4), (10, 13), (4, 12), (10, 15), (6, 27), (3, None), (1, 26), (0, 3), (8, 21), (8, 26), (6, 13), (2, 27), (7, 11), (10, 5), (0, 3), (10, 3)], + [(0, None), (2, 4), (5, 12), (9, 27), (3, 7), (9, 21), (5, None), (2, 22), (0, 28), (10, 30), (10, 25), (6, 12), (8, 6), (8, 30), (6, 28), (2, 6), (7, 26), (10, 3), (0, None)], + [(0, None), (3, 4), (7, 22), (1, 7), (7, 8), (3, 12), (0, 27), (9, 1), (8, 17), (8, 4), (9, 12), (2, 16), (6, 23), (8, 14), (8, 2), (6, 26), (2, 14), (7, 22), (10, 30)], + [(0, None), (4, 4), (9, 21), (4, 25), (0, 9), (8, 23), (6, 5), (5, 20), (5, 13), (6, 19), (8, 0), (7, 30), (2, 29), (6, 24), (8, 18), (8, 10), (6, 9), (2, 20), (7, 4)], + [(0, None), (5, 4), (0, 25), (7, 4), (4, 20), (2, 3), (1, None), (1, 21), (2, None), (4, 26), (7, 1), (10, 23), (7, 20), (2, 3), (6, 5), (8, 19), (8, 9), (6, 23), (2, 7)], ] Y = [None, 0, 1, 2, 18, 5, 11, 4, 13, 26, 25, 29, 24, 7, 20, 19, 9, 12, 15] - return OA_n_times_2_pow_c_from_matrix(20,5,FiniteField(11),list(zip(*A)),Y,check=False) + return OA_n_times_2_pow_c_from_matrix(20, 5, FiniteField(11), list(zip(*A)), Y, check=False) def OA_20_416(): @@ -1382,37 +1327,37 @@ def OA_20_416(): Z = None A = [ - [(0,Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (0 , Z), (1 , Z), (4 , Z), (9 , Z), (3 , Z), (12, Z)], - [(0,Z), (1 , Z), (2 ,18), (3 , 2), (4 ,20), (5 ,22), (6 ,11), (7 ,19), (8 , 0), (9 ,26), (10, Z), (11, 5), (12,27), (1 ,17), (0 ,30), (1 ,22), (4 ,29), (9 , 6), (3 ,19)], - [(0,Z), (2 , 4), (4 ,21), (6 ,10), (8 ,24), (10,13), (12, 7), (1 ,11), (3 ,29), (5 ,12), (7 ,21), (9 , 2), (11,11), (4 , 5), (1 ,11), (0 ,23), (1 ,13), (4 , 6), (9 ,15)], - [(0,Z), (3 , 4), (6 ,17), (9 ,20), (12,26), (2 , 2), (5 ,12), (8 ,29), (11, 1), (1 , Z), (4 ,15), (7 ,16), (10,27), (9 , 2), (4 , 7), (1 , 5), (0 ,23), (1 ,24), (4 , 8)], - [(0,Z), (4 , 4), (8 ,29), (12, 8), (3 , 3), (7 , 8), (11, 2), (2 ,17), (6 , 4), (10, 2), (1 ,21), (5 ,29), (9 ,20), (3 , 2), (9 , 1), (4 ,14), (1 ,21), (0 ,24), (1 ,28)], - [(0,Z), (5 , 4), (10,22), (2 ,18), (7 , 6), (12, 2), (4 ,18), (9 ,27), (1 ,15), (6 , Z), (11,20), (3 ,15), (8 , 9), (12, 9), (3 , 3), (9 ,13), (4 , 4), (1 , 7), (0 ,14)], - [(0,Z), (6 , Z), (12,23), (5 ,13), (11,11), (4 ,10), (10, 0), (3 , 4), (9 ,16), (2 ,28), (8 ,27), (1 , 1), (7 ,23), (10,17), (12, 9), (3 ,20), (9 ,16), (4 ,17), (1 ,26)], - [(0,Z), (7 , Z), (1 , 3), (8 ,13), (2 , 8), (9 , 9), (3 , 0), (10,26), (4 , 5), (11, 6), (5 ,22), (12, 1), (6 ,17), (10,10), (10, 5), (12,15), (3 ,25), (9 , Z), (4 , 4)], - [(0,Z), (8 , 4), (3 ,10), (11, 3), (6 ,17), (1 ,21), (9 ,18), (4 , 5), (12,27), (7 ,20), (2 ,16), (10,25), (5 ,22), (12,21), (10,25), (10,12), (12,28), (3 ,19), (9 ,29)], - [(0,Z), (9 , 4), (5 , 6), (1 ,16), (10, 4), (6 ,24), (2 ,14), (11,11), (7 , 2), (3 , 9), (12,30), (8 ,28), (4 , 2), (3 , 7), (12, 6), (10,17), (10, 2), (12,13), (3 ,26)], - [(0,Z), (10, 4), (7 ,11), (4 ,18), (1 ,23), (11,21), (8 ,28), (5 ,21), (2 ,29), (12,20), (9 , 0), (6 , 8), (3 , 6), (9 , 7), (3 ,12), (12, 5), (10, 1), (10,21), (12, 5)], - [(0,Z), (11, 4), (9 ,22), (7 ,11), (5 ,17), (3 , Z), (1 ,17), (12,25), (10,14), (8 ,18), (6 , 2), (4 ,17), (2 ,25), (4 ,29), (9 , 6), (3 , 2), (12, 8), (10,13), (10,14)], - [(0,Z), (12, Z), (11, 7), (10,26), (9 ,24), (8 , 4), (7 ,25), (6 , Z), (5 ,13), (4 , 9), (3 , 5), (2 ,19), (1 ,10), (1 ,26), (4 ,14), (9 , 7), (3 ,11), (12, 9), (10,20)], - [(0,Z), (5 , Z), (7 , 7), (6 ,27), (2 , 5), (8 , 1), (11,23), (11, Z), (8 ,23), (2 ,21), (6 ,20), (7 , 5), (5 , 6), (0 , 2), (2 ,12), (8 ,15), (5 ,22), (6 ,25), (11,10)], - [(0,Z), (6 , 4), (9 ,24), (9 ,18), (6 ,26), (0 ,26), (4 ,17), (5 ,24), (3 , 5), (11, 9), (3 ,15), (5 ,23), (4 ,22), (2 ,26), (0 , 8), (2 ,21), (8 ,25), (5 ,15), (6 , 8)], - [(0,Z), (7 , 4), (11,11), (12, 9), (10,10), (5 , 6), (10, 1), (12,24), (11, 6), (7 ,26), (0 , 8), (3 ,10), (3 ,29), (8 , 3), (2 ,24), (0 ,22), (2 ,13), (8 , 2), (5 , 0)], - [(0,Z), (8 , Z), (0 ,27), (2 , 0), (1 ,25), (10,21), (3 ,10), (6 ,20), (6 ,14), (3 , 1), (10, 3), (1 ,15), (2 ,14), (5 ,12), (8 ,11), (2 ,28), (0 ,15), (2 ,13), (8 ,22)], - [(0,Z), (9 , Z), (2 ,13), (5 ,11), (5 , 6), (2 ,24), (9 , 9), (0 ,14), (1 ,30), (12, 1), (7 ,15), (12,15), (1 , 5), (6 ,23), (5 , 9), (8 , 3), (2 ,27), (0 ,28), (2 ,12)], - [(0,Z), (10, Z), (4 ,18), (8 ,23), (9 ,27), (7 , 4), (2 , 2), (7 , Z), (9 ,10), (8 , 8), (4 , 0), (10,12), (0 ,21), (11,28), (6 ,15), (5 ,23), (8 , 5), (2 ,28), (0 , 7)], - [(0,Z), (11, Z), (6 , 7), (11,27), (0 , 0), (12,17), (8 ,11), (1 ,12), (4 ,22), (4 ,15), (1 ,16), (8 , 0), (12, 6), (7 ,16), (11,30), (6 ,21), (5 ,14), (8 ,17), (2 ,26)], - [(0,Z), (12, 4), (8 ,28), (1 ,22), (4 , 2), (4 ,15), (1 , 6), (8 ,12), (12,19), (0 ,21), (11, 2), (6 , 4), (11,19), (7 ,30), (7 ,11), (11,12), (6 ,20), (5 , 3), (8 , 7)], - [(0,Z), (0 , 4), (10,21), (4 , 4), (8 , 1), (9 , 6), (7 ,30), (2 , 4), (7 , 8), (9 ,30), (8 , 3), (4 ,22), (10, 3), (11,25), (7 , 1), (7 ,24), (11,20), (6 ,30), (5 , 4)], - [(0,Z), (1 , 4), (12,21), (7 , 3), (12, 2), (1 , 1), (0 , 6), (9 ,14), (2 ,19), (5 , 6), (5 ,12), (2 , 9), (9 , 9), (6 ,19), (11, Z), (7 , 4), (7 , 6), (11,29), (6 ,15)], - [(0,Z), (2 , Z), (1 ,22), (10, Z), (3 , 5), (6 ,30), (6 ,26), (3 , 1), (10,12), (1 ,16), (2 ,28), (0 ,20), (8 ,11), (5 ,29), (6 , 7), (11,21), (7 ,14), (7 , 8), (11,11)], - [(0,Z), (3 , Z), (3 , 4), (0 ,18), (7 , 2), (11,16), (12,28), (10, 4), (5 ,28), (10, 0), (12, 4), (11,10), (7 ,11), (8 ,17), (5 , 6), (6 ,16), (11, 4), (7 ,22), (7 ,28)], - [(0,Z), (4 , Z), (5 ,22), (3 ,18), (11, Z), (3 ,15), (5 , 1), (4 ,26), (0 ,10), (6 , 8), (9 , 9), (9 ,29), (6 , Z), (2 ,23), (8 ,28), (5 ,30), (6 , 8), (11,24), (7 ,16)] + [(0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (1, Z), (4, Z), (9, Z), (3, Z), (12, Z)], + [(0, Z), (1, Z), (2, 18), (3, 2), (4, 20), (5, 22), (6, 11), (7, 19), (8, 0), (9, 26), (10, Z), (11, 5), (12, 27), (1, 17), (0, 30), (1, 22), (4, 29), (9, 6), (3, 19)], + [(0, Z), (2, 4), (4, 21), (6, 10), (8, 24), (10, 13), (12, 7), (1, 11), (3, 29), (5, 12), (7, 21), (9, 2), (11, 11), (4, 5), (1, 11), (0, 23), (1, 13), (4, 6), (9, 15)], + [(0, Z), (3, 4), (6, 17), (9, 20), (12, 26), (2, 2), (5, 12), (8, 29), (11, 1), (1, Z), (4, 15), (7, 16), (10, 27), (9, 2), (4, 7), (1, 5), (0, 23), (1, 24), (4, 8)], + [(0, Z), (4, 4), (8, 29), (12, 8), (3, 3), (7, 8), (11, 2), (2, 17), (6, 4), (10, 2), (1, 21), (5, 29), (9, 20), (3, 2), (9, 1), (4, 14), (1, 21), (0, 24), (1, 28)], + [(0, Z), (5, 4), (10, 22), (2, 18), (7, 6), (12, 2), (4, 18), (9, 27), (1, 15), (6, Z), (11, 20), (3, 15), (8, 9), (12, 9), (3, 3), (9, 13), (4, 4), (1, 7), (0, 14)], + [(0, Z), (6, Z), (12, 23), (5, 13), (11, 11), (4, 10), (10, 0), (3, 4), (9, 16), (2, 28), (8, 27), (1, 1), (7, 23), (10, 17), (12, 9), (3, 20), (9, 16), (4, 17), (1, 26)], + [(0, Z), (7, Z), (1, 3), (8, 13), (2, 8), (9, 9), (3, 0), (10, 26), (4, 5), (11, 6), (5, 22), (12, 1), (6, 17), (10, 10), (10, 5), (12, 15), (3, 25), (9, Z), (4, 4)], + [(0, Z), (8, 4), (3, 10), (11, 3), (6, 17), (1, 21), (9, 18), (4, 5), (12, 27), (7, 20), (2, 16), (10, 25), (5, 22), (12, 21), (10, 25), (10, 12), (12, 28), (3, 19), (9, 29)], + [(0, Z), (9, 4), (5, 6), (1, 16), (10, 4), (6, 24), (2, 14), (11, 11), (7, 2), (3, 9), (12, 30), (8, 28), (4, 2), (3, 7), (12, 6), (10, 17), (10, 2), (12, 13), (3, 26)], + [(0, Z), (10, 4), (7, 11), (4, 18), (1, 23), (11, 21), (8, 28), (5, 21), (2, 29), (12, 20), (9, 0), (6, 8), (3, 6), (9, 7), (3, 12), (12, 5), (10, 1), (10, 21), (12, 5)], + [(0, Z), (11, 4), (9, 22), (7, 11), (5, 17), (3, Z), (1, 17), (12, 25), (10, 14), (8, 18), (6, 2), (4, 17), (2, 25), (4, 29), (9, 6), (3, 2), (12, 8), (10, 13), (10, 14)], + [(0, Z), (12, Z), (11, 7), (10, 26), (9, 24), (8, 4), (7, 25), (6, Z), (5, 13), (4, 9), (3, 5), (2, 19), (1, 10), (1, 26), (4, 14), (9, 7), (3, 11), (12, 9), (10, 20)], + [(0, Z), (5, Z), (7, 7), (6, 27), (2, 5), (8, 1), (11, 23), (11, Z), (8, 23), (2, 21), (6, 20), (7, 5), (5, 6), (0, 2), (2, 12), (8, 15), (5, 22), (6, 25), (11, 10)], + [(0, Z), (6, 4), (9, 24), (9, 18), (6, 26), (0, 26), (4, 17), (5, 24), (3, 5), (11, 9), (3, 15), (5, 23), (4, 22), (2, 26), (0, 8), (2, 21), (8, 25), (5, 15), (6, 8)], + [(0, Z), (7, 4), (11, 11), (12, 9), (10, 10), (5, 6), (10, 1), (12, 24), (11, 6), (7, 26), (0, 8), (3, 10), (3, 29), (8, 3), (2, 24), (0, 22), (2, 13), (8, 2), (5, 0)], + [(0, Z), (8, Z), (0, 27), (2, 0), (1, 25), (10, 21), (3, 10), (6, 20), (6, 14), (3, 1), (10, 3), (1, 15), (2, 14), (5, 12), (8, 11), (2, 28), (0, 15), (2, 13), (8, 22)], + [(0, Z), (9, Z), (2, 13), (5, 11), (5, 6), (2, 24), (9, 9), (0, 14), (1, 30), (12, 1), (7, 15), (12, 15), (1, 5), (6, 23), (5, 9), (8, 3), (2, 27), (0, 28), (2, 12)], + [(0, Z), (10, Z), (4, 18), (8, 23), (9, 27), (7, 4), (2, 2), (7, Z), (9, 10), (8, 8), (4, 0), (10, 12), (0, 21), (11, 28), (6, 15), (5, 23), (8, 5), (2, 28), (0, 7)], + [(0, Z), (11, Z), (6, 7), (11, 27), (0, 0), (12, 17), (8, 11), (1, 12), (4, 22), (4, 15), (1, 16), (8, 0), (12, 6), (7, 16), (11, 30), (6, 21), (5, 14), (8, 17), (2, 26)], + [(0, Z), (12, 4), (8, 28), (1, 22), (4, 2), (4, 15), (1, 6), (8, 12), (12, 19), (0, 21), (11, 2), (6, 4), (11, 19), (7, 30), (7, 11), (11, 12), (6, 20), (5, 3), (8, 7)], + [(0, Z), (0, 4), (10, 21), (4, 4), (8, 1), (9, 6), (7, 30), (2, 4), (7, 8), (9, 30), (8, 3), (4, 22), (10, 3), (11, 25), (7, 1), (7, 24), (11, 20), (6, 30), (5, 4)], + [(0, Z), (1, 4), (12, 21), (7, 3), (12, 2), (1, 1), (0, 6), (9, 14), (2, 19), (5, 6), (5, 12), (2, 9), (9, 9), (6, 19), (11, Z), (7, 4), (7, 6), (11, 29), (6, 15)], + [(0, Z), (2, Z), (1, 22), (10, Z), (3, 5), (6, 30), (6, 26), (3, 1), (10, 12), (1, 16), (2, 28), (0, 20), (8, 11), (5, 29), (6, 7), (11, 21), (7, 14), (7, 8), (11, 11)], + [(0, Z), (3, Z), (3, 4), (0, 18), (7, 2), (11, 16), (12, 28), (10, 4), (5, 28), (10, 0), (12, 4), (11, 10), (7, 11), (8, 17), (5, 6), (6, 16), (11, 4), (7, 22), (7, 28)], + [(0, Z), (4, Z), (5, 22), (3, 18), (11, Z), (3, 15), (5, 1), (4, 26), (0, 10), (6, 8), (9, 9), (9, 29), (6, Z), (2, 23), (8, 28), (5, 30), (6, 8), (11, 24), (7, 16)], ] Y = [None, 0, 1, 2, 18, 5, 11, 4, 13, 26, 25, 29, 24, 7, 20, 19, 9, 12, 15] - return OA_n_times_2_pow_c_from_matrix(20,5,FiniteField(13),list(zip(*A)),Y,check=False) + return OA_n_times_2_pow_c_from_matrix(20, 5, FiniteField(13), list(zip(*A)), Y, check=False) def OA_20_544(): @@ -1444,45 +1389,45 @@ def OA_20_544(): Z = None A = [ - [(0,Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(0 , Z),(1 , Z)], - [(0,Z),(1 , 4),(2 , 7),(3 ,30),(4 ,17),(5 , 2),(6 ,22),(7 ,23),(8 ,28),(9 , 2),(10,27),(11,26),(12,13),(13,25),(14,18),(15,15),(16,18),(1 ,14),(0 , 1)], - [(0,Z),(2 , 4),(4 ,20),(6 ,29),(8 ,27),(10, 7),(12,20),(14,19),(16,26),(1 ,28),(3 , Z),(5 ,27),(7 , Z),(9 ,11),(11, Z),(13,17),(15, 1),(4 ,14),(1 ,14)], - [(0,Z),(3 , Z),(6 ,14),(9 ,26),(12,17),(15,15),(1 ,26),(4 ,24),(7 ,27),(10,13),(13,10),(16, 7),(2 , 1),(5 , Z),(8 , 1),(11,15),(14,18),(9 ,21),(4 , 6)], - [(0,Z),(4 , 4),(8 , Z),(12, 2),(16,23),(3 ,19),(7 ,26),(11, 7),(15,26),(2 , 3),(6 ,11),(10,16),(14,23),(1 ,30),(5 , 1),(9 ,30),(13,19),(16,10),(9 , 4)], - [(0,Z),(5 , Z),(10,17),(15,19),(3 ,13),(8 , 4),(13,21),(1 , 9),(6 , 7),(11, 4),(16,24),(4 , 6),(9 ,11),(14, Z),(2 , 6),(7 ,14),(12,10),(8 ,12),(16, 1)], - [(0,Z),(6 , Z),(12, 1),(1 ,23),(7 ,21),(13,10),(2 , 0),(8 ,15),(14,19),(3 ,30),(9 ,21),(15,17),(4 ,25),(10,20),(16,15),(5 ,16),(11,15),(2 ,22),(8 ,29)], # 2,Z -> 2,0 - [(0,Z),(7 , Z),(14,30),(4 ,26),(11,24),(1 ,22),(8 ,22),(15,27),(5 ,23),(12,13),(2 ,18),(9 ,22),(16, 6),(6 ,27),(13,19),(3 , 1),(10,16),(15, 9),(2 , 5)], - [(0,Z),(8 , 4),(16, 5),(7 ,18),(15,11),(6 , 1),(14,21),(5 ,28),(13,19),(4 , 7),(12,19),(3 ,15),(11,13),(2 ,23),(10, 1),(1 ,23),(9 ,19),(13,27),(15,25)], # 13,9 -> 15,25 - [(0,Z),(9 , Z),(1 , 3),(10, 4),(2 ,29),(11,13),(3 ,27),(12,11),(4 ,30),(13, 9),(5 ,18),(14,17),(6 ,18),(15,10),(7 ,11),(16,28),(8 ,26),(13,12),(13, 9)], - [(0,Z),(10, Z),(3 ,18),(13,21),(6 , 8),(16, 1),(9 ,11),(2 ,11),(12,12),(5 ,20),(15,21),(8 ,12),(1 , 5),(11,28),(4 ,16),(14,16),(7 ,21),(15, 0),(13,20)], - [(0,Z),(11, 4),(5 ,25),(16, 2),(10,18),(4 , 6),(15,20),(9 ,29),(3 ,13),(14,24),(8 ,18),(2 ,22),(13, 1),(7 , 8),(1 ,21),(12,16),(6 ,23),(2 ,10),(15,26)], - [(0,Z),(12, 4),(7 ,11),(2 , 4),(14,25),(9 , 0),(4 , 5),(16,21),(11,18),(6 ,18),(1 ,22),(13,27),(8 ,23),(3 ,20),(15,18),(10, 7),(5 ,10),(8 ,11),(2 ,18)], - [(0,Z),(13, Z),(9 ,21),(5 ,17),(1 ,26),(14,30),(10,11),(6 , 1),(2 , 8),(15, 9),(11, 5),(7 ,29),(3 ,17),(16, 3),(12, 3),(8 ,30),(4 , 3),(16, 5),(8 ,21)], - [(0,Z),(14, Z),(11,20),(8 ,24),(5 , Z),(2 , 2),(16,24),(13,12),(10,21),(7 ,26),(4 ,29),(1 , 1),(15, 1),(12,19),(9 , 8),(6 ,26),(3 ,10),(9 ,20),(16,21)], - [(0,Z),(15, Z),(13,21),(11,10),(9 , 7),(7 ,21),(5 ,11),(3 ,19),(1 ,29),(16,13),(14, 9),(12, 9),(10, 8),(8 ,16),(6 ,15),(4 ,14),(2 ,29),(4 ,16),(9 , 9)], - [(0,Z),(16, 4),(15,19),(14,21),(13, 0),(12,13),(11,28),(10,21),(9 , 5),(8 ,18),(7 , 2),(6 , Z),(5 ,20),(4 ,26),(3 , 8),(2 , 9),(1 ,23),(1 ,19),(4 ,23)], # 13,Z -> 13,0 - [(0,Z),(3 , 4),(12,11),(10,17),(14,14),(7 , 1),(6 ,27),(11,25),(5 , 2),(5 ,24),(11,15),(6 , 8),(7 ,28),(14,21),(10, 4),(12,20),(3 ,26),(0 , 5),(3 ,12)], - [(0,Z),(4 , Z),(14,17),(13,26),(1 ,12),(12,12),(12,23),(1 ,13),(13, 7),(14,10),(4 ,28),(0 ,11),(2 , 7),(10,15),(7 , Z),(10, 1),(2 , 6),(3 ,24),(0 ,18)], - [(0,Z),(5 , 4),(16,24),(16, 1),(5 ,27),(0 ,14),(1 ,11),(8 ,13),(4 ,25),(6 ,25),(14,14),(11, 6),(14, 4),(6 ,24),(4 , 4),(8 ,28),(1 ,14),(12,22),(3 ,11)], - [(0,Z),(6 , 4),(1 ,10),(2 , 6),(9 ,12),(5 , 3),(7 ,11),(15,30),(12,21),(15,26),(7 , 3),(5 ,12),(9 , 0),(2 ,25),(1 , 2),(6 , 0),(0 ,13),(10,13),(12,14)], - [(0,Z),(7 , 4),(3 ,24),(5 ,25),(13,20),(10,19),(13,16),(5 , 4),(3 ,23),(7 ,20),(0 , 8),(16, 4),(4 ,19),(15, 0),(15,10),(4 ,11),(16, 7),(14,11),(10, 6)], - [(0,Z),(8 , Z),(5 , 1),(8 ,21),(0 , 1),(15,17),(2 ,26),(12, 2),(11, 6),(16, 2),(10,15),(10,13),(16,16),(11,12),(12,22),(2 ,11),(15,22),(7 ,30),(14,22)], # 8,9 -> 8,21 - [(0,Z),(9 , 4),(7 ,20),(11,24),(4 , 7),(3 ,11),(8 ,21),(2 ,23),(2 , 2),(8 ,12),(3 , 8),(4 ,13),(11,17),(7 , 4),(9 , 3),(0 ,18),(14,12),(6 ,26),(7 ,28)], - [(0,Z),(10, 4),(9 ,22),(14,23),(8 , 5),(8 , 8),(14,12),(9 , 6),(10,20),(0 ,11),(13,23),(15,26),(6 ,12),(3 ,15),(6 , Z),(15,18),(13, 1),(11,22),(6 ,24)], - [(0,Z),(11, Z),(11,11),(0 ,28),(12,16),(13,18),(3 , 3),(16,22),(1 , 9),(9 , Z),(6 ,21),(9 , 6),(1 , 0),(16, 1),(3 , 2),(13,28),(12, 6),(5 ,18),(11, 9)], - [(0,Z),(12, Z),(13, 5),(3 ,14),(16,22),(1 , 5),(9 , 1),(6 , Z),(9 , 3),(1 , 9),(16,21),(3 ,18),(13,17),(12,29),(0 ,13),(11, 4),(11,18),(5 ,21),(5 , 6)], - [(0,Z),(13, 4),(15,27),(6 ,26),(3 ,20),(6 ,29),(15,11),(13,18),(0 , 4),(10, 5),(9 ,16),(14,26),(8 ,20),(8 , 8),(14,11),(9 ,10),(10, 9),(11,17),(5 ,21)], - [(0,Z),(14, 4),(0 ,29),(9 , 8),(7 , 2),(11,18),(4 ,22),(3 ,22),(8 ,13),(2 ,23),(2 ,21),(8 , 9),(3 ,30),(4 ,21),(11, 5),(7 ,25),(9 , Z),(6 , 0),(11,17)], - [(0,Z),(15, 4),(2 ,27),(12,27),(11,28),(16, 0),(10, 6),(10,12),(16,11),(11,15),(12, 2),(2 ,10),(15,19),(0 ,11),(8 ,10),(5 , 6),(8 , 5),(7 , 7),(6 ,16)], - [(0,Z),(16, Z),(4 ,23),(15, 4),(15,30),(4 ,27),(16,12),(0 , 8),(7 , 9),(3 , 6),(5 ,26),(13,28),(10,12),(13,14),(5 ,30),(3 ,27),(7 , 6),(14,15),(7 ,18)], - [(0,Z),(0 , 4),(6 ,13),(1 ,14),(2 , 2),(9 ,11),(5 , 5),(7 ,13),(15,24),(12,16),(15,20),(7 ,24),(5 ,19),(9 ,25),(2 ,26),(1 ,20),(6 ,28),(10, 5),(14,11)], - [(0,Z),(1 , Z),(8 ,25),(4 , 5),(6 , 6),(14, 6),(11,11),(14,22),(6 , 2),(4 , 2),(8 ,14),(1 ,13),(0 , 3),(5 , 6),(16,21),(16,11),(5 , 8),(12,15),(10,20)], # 12,14->12,15 - [(0,Z),(2 , Z),(10,19),(7 ,29),(10,22),(2 ,23),(0 ,15),(4 ,19),(14, 6),(13,14),(1 , 5),(12,24),(12, 8),(1 , 4),(13, 1),(14,21),(4 ,17),(3 , 3),(12,27)], + [(0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (0, Z), (1, Z)], + [(0, Z), (1, 4), (2, 7), (3, 30), (4, 17), (5, 2), (6, 22), (7, 23), (8, 28), (9, 2), (10, 27), (11, 26), (12, 13), (13, 25), (14, 18), (15, 15), (16, 18), (1, 14), (0, 1)], + [(0, Z), (2, 4), (4, 20), (6, 29), (8, 27), (10, 7), (12, 20), (14, 19), (16, 26), (1, 28), (3, Z), (5, 27), (7, Z), (9, 11), (11, Z), (13, 17), (15, 1), (4, 14), (1, 14)], + [(0, Z), (3, Z), (6, 14), (9, 26), (12, 17), (15, 15), (1, 26), (4, 24), (7, 27), (10, 13), (13, 10), (16, 7), (2, 1), (5, Z), (8, 1), (11, 15), (14, 18), (9, 21), (4, 6)], + [(0, Z), (4, 4), (8, Z), (12, 2), (16, 23), (3, 19), (7, 26), (11, 7), (15, 26), (2, 3), (6, 11), (10, 16), (14, 23), (1, 30), (5, 1), (9, 30), (13, 19), (16, 10), (9, 4)], + [(0, Z), (5, Z), (10, 17), (15, 19), (3, 13), (8, 4), (13, 21), (1, 9), (6, 7), (11, 4), (16, 24), (4, 6), (9, 11), (14, Z), (2, 6), (7, 14), (12, 10), (8, 12), (16, 1)], + [(0, Z), (6, Z), (12, 1), (1, 23), (7, 21), (13, 10), (2, 0), (8, 15), (14, 19), (3, 30), (9, 21), (15, 17), (4, 25), (10, 20), (16, 15), (5, 16), (11, 15), (2, 22), (8, 29)], # 2,Z -> 2,0 + [(0, Z), (7, Z), (14, 30), (4, 26), (11, 24), (1, 22), (8, 22), (15, 27), (5, 23), (12, 13), (2, 18), (9, 22), (16, 6), (6, 27), (13, 19), (3, 1), (10, 16), (15, 9), (2, 5)], + [(0, Z), (8, 4), (16, 5), (7, 18), (15, 11), (6, 1), (14, 21), (5, 28), (13, 19), (4, 7), (12, 19), (3, 15), (11, 13), (2, 23), (10, 1), (1, 23), (9, 19), (13, 27), (15, 25)], # 13,9 -> 15,25 + [(0, Z), (9, Z), (1, 3), (10, 4), (2, 29), (11, 13), (3, 27), (12, 11), (4, 30), (13, 9), (5, 18), (14, 17), (6, 18), (15, 10), (7, 11), (16, 28), (8, 26), (13, 12), (13, 9)], + [(0, Z), (10, Z), (3, 18), (13, 21), (6, 8), (16, 1), (9, 11), (2, 11), (12, 12), (5, 20), (15, 21), (8, 12), (1, 5), (11, 28), (4, 16), (14, 16), (7, 21), (15, 0), (13, 20)], + [(0, Z), (11, 4), (5, 25), (16, 2), (10, 18), (4, 6), (15, 20), (9, 29), (3, 13), (14, 24), (8, 18), (2, 22), (13, 1), (7, 8), (1, 21), (12, 16), (6, 23), (2, 10), (15, 26)], + [(0, Z), (12, 4), (7, 11), (2, 4), (14, 25), (9, 0), (4, 5), (16, 21), (11, 18), (6, 18), (1, 22), (13, 27), (8, 23), (3, 20), (15, 18), (10, 7), (5, 10), (8, 11), (2, 18)], + [(0, Z), (13, Z), (9, 21), (5, 17), (1, 26), (14, 30), (10, 11), (6, 1), (2, 8), (15, 9), (11, 5), (7, 29), (3, 17), (16, 3), (12, 3), (8, 30), (4, 3), (16, 5), (8, 21)], + [(0, Z), (14, Z), (11, 20), (8, 24), (5, Z), (2, 2), (16, 24), (13, 12), (10, 21), (7, 26), (4, 29), (1, 1), (15, 1), (12, 19), (9, 8), (6, 26), (3, 10), (9, 20), (16, 21)], + [(0, Z), (15, Z), (13, 21), (11, 10), (9, 7), (7, 21), (5, 11), (3, 19), (1, 29), (16, 13), (14, 9), (12, 9), (10, 8), (8, 16), (6, 15), (4, 14), (2, 29), (4, 16), (9, 9)], + [(0, Z), (16, 4), (15, 19), (14, 21), (13, 0), (12, 13), (11, 28), (10, 21), (9, 5), (8, 18), (7, 2), (6, Z), (5, 20), (4, 26), (3, 8), (2, 9), (1, 23), (1, 19), (4, 23)], # 13,Z -> 13,0 + [(0, Z), (3, 4), (12, 11), (10, 17), (14, 14), (7, 1), (6, 27), (11, 25), (5, 2), (5, 24), (11, 15), (6, 8), (7, 28), (14, 21), (10, 4), (12, 20), (3, 26), (0, 5), (3, 12)], + [(0, Z), (4, Z), (14, 17), (13, 26), (1, 12), (12, 12), (12, 23), (1, 13), (13, 7), (14, 10), (4, 28), (0, 11), (2, 7), (10, 15), (7, Z), (10, 1), (2, 6), (3, 24), (0, 18)], + [(0, Z), (5, 4), (16, 24), (16, 1), (5, 27), (0, 14), (1, 11), (8, 13), (4, 25), (6, 25), (14, 14), (11, 6), (14, 4), (6, 24), (4, 4), (8, 28), (1, 14), (12, 22), (3, 11)], + [(0, Z), (6, 4), (1, 10), (2, 6), (9, 12), (5, 3), (7, 11), (15, 30), (12, 21), (15, 26), (7, 3), (5, 12), (9, 0), (2, 25), (1, 2), (6, 0), (0, 13), (10, 13), (12, 14)], + [(0, Z), (7, 4), (3, 24), (5, 25), (13, 20), (10, 19), (13, 16), (5, 4), (3, 23), (7, 20), (0, 8), (16, 4), (4, 19), (15, 0), (15, 10), (4, 11), (16, 7), (14, 11), (10, 6)], + [(0, Z), (8, Z), (5, 1), (8, 21), (0, 1), (15, 17), (2, 26), (12, 2), (11, 6), (16, 2), (10, 15), (10, 13), (16, 16), (11, 12), (12, 22), (2, 11), (15, 22), (7, 30), (14, 22)], # 8,9 -> 8,21 + [(0, Z), (9, 4), (7, 20), (11, 24), (4, 7), (3, 11), (8, 21), (2, 23), (2, 2), (8, 12), (3, 8), (4, 13), (11, 17), (7, 4), (9, 3), (0, 18), (14, 12), (6, 26), (7, 28)], + [(0, Z), (10, 4), (9, 22), (14, 23), (8, 5), (8, 8), (14, 12), (9, 6), (10, 20), (0, 11), (13, 23), (15, 26), (6, 12), (3, 15), (6, Z), (15, 18), (13, 1), (11, 22), (6, 24)], + [(0, Z), (11, Z), (11, 11), (0, 28), (12, 16), (13, 18), (3, 3), (16, 22), (1, 9), (9, Z), (6, 21), (9, 6), (1, 0), (16, 1), (3, 2), (13, 28), (12, 6), (5, 18), (11, 9)], + [(0, Z), (12, Z), (13, 5), (3, 14), (16, 22), (1, 5), (9, 1), (6, Z), (9, 3), (1, 9), (16, 21), (3, 18), (13, 17), (12, 29), (0, 13), (11, 4), (11, 18), (5, 21), (5, 6)], + [(0, Z), (13, 4), (15, 27), (6, 26), (3, 20), (6, 29), (15, 11), (13, 18), (0, 4), (10, 5), (9, 16), (14, 26), (8, 20), (8, 8), (14, 11), (9, 10), (10, 9), (11, 17), (5, 21)], + [(0, Z), (14, 4), (0, 29), (9, 8), (7, 2), (11, 18), (4, 22), (3, 22), (8, 13), (2, 23), (2, 21), (8, 9), (3, 30), (4, 21), (11, 5), (7, 25), (9, Z), (6, 0), (11, 17)], + [(0, Z), (15, 4), (2, 27), (12, 27), (11, 28), (16, 0), (10, 6), (10, 12), (16, 11), (11, 15), (12, 2), (2, 10), (15, 19), (0, 11), (8, 10), (5, 6), (8, 5), (7, 7), (6, 16)], + [(0, Z), (16, Z), (4, 23), (15, 4), (15, 30), (4, 27), (16, 12), (0, 8), (7, 9), (3, 6), (5, 26), (13, 28), (10, 12), (13, 14), (5, 30), (3, 27), (7, 6), (14, 15), (7, 18)], + [(0, Z), (0, 4), (6, 13), (1, 14), (2, 2), (9, 11), (5, 5), (7, 13), (15, 24), (12, 16), (15, 20), (7, 24), (5, 19), (9, 25), (2, 26), (1, 20), (6, 28), (10, 5), (14, 11)], + [(0, Z), (1, Z), (8, 25), (4, 5), (6, 6), (14, 6), (11, 11), (14, 22), (6, 2), (4, 2), (8, 14), (1, 13), (0, 3), (5, 6), (16, 21), (16, 11), (5, 8), (12, 15), (10, 20)], # 12,14->12,15 + [(0, Z), (2, Z), (10, 19), (7, 29), (10, 22), (2, 23), (0, 15), (4, 19), (14, 6), (13, 14), (1, 5), (12, 24), (12, 8), (1, 4), (13, 1), (14, 21), (4, 17), (3, 3), (12, 27)], ] Y = [None, 0, 1, 2, 18, 5, 11, 4, 13, 26, 25, 29, 24, 7, 20, 19, 9, 12, 15] - return OA_n_times_2_pow_c_from_matrix(20,5,FiniteField(17),list(zip(*A)),Y,check=False) + return OA_n_times_2_pow_c_from_matrix(20, 5, FiniteField(17), list(zip(*A)), Y, check=False) def OA_17_560(): @@ -1505,6 +1450,7 @@ def OA_17_560(): True """ from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF + alpha = 5 beta = 4 p = 2 @@ -1513,14 +1459,14 @@ def OA_17_560(): n = p**alpha G = GF((p, alpha), prefix='x') - G_set = sorted(G) # sorted by lexicographic order, G[1] = 1 - G_to_int = {v:i for i,v in enumerate(G_set)} + G_set = sorted(G) # sorted by lexicographic order, G[1] = 1 + G_to_int = {v: i for i, v in enumerate(G_set)} # Builds an OA(n+1,n) whose last n-1 columns are # # \forall x \in G and x!=0, C_x(i,j) = i+x*j # # (only the necessary columns are built) - OA = [[G_to_int[i+x*j] for i in G_set for j in G_set] for x in G_set[k+1:0:-1]] + OA = [[G_to_int[i + x * j] for i in G_set for j in G_set] for x in G_set[k + 1 : 0 : -1]] OA.append([j for i in range(n) for j in range(n)]) OA.append([i for i in range(n) for j in range(n)]) @@ -1537,12 +1483,12 @@ def OA_17_560(): relabel[x] = None for C in OA[-3:]: - for i,x in enumerate(C): + for i, x in enumerate(C): C[i] = relabel[x] OA = list(zip(*OA)) - return wilson_construction(OA,k,n,m,[p**beta]*3,check=False) + return wilson_construction(OA, k, n, m, [p**beta] * 3, check=False) def OA_11_640(): @@ -1571,21 +1517,10 @@ def OA_11_640(): """ from sage.rings.finite_rings.finite_field_constructor import FiniteField - A = [ - [(0,None), (0,None), (0,None), (0,None), (0,None), (0,None), (1,None), (4,None), (4,None), (1,None)], - [(0,None), (1,None), (2, 7), (3, 55), (4, 54), (1, 87), (0, 124), (1, 123), (4, 83), (4, 61)], # 0,25 became 0,124 - [(0,None), (2,None), (4, 14), (1, 63), (3, 6), (4, 87), (1, 16), (0, 47), (1, 29), (4, 16)], - [(0,None), (3,None), (1, 1), (4, 15), (2, 5), (4, 32), (4, 30), (1, 3), (0, 12), (1, 14)], - [(0,None), (4,None), (3, 28), (2, 62), (1, 64), (1, 55), (4, 63), (4, 4), (1, 0), (0, 0)], - [(0,None), (2, 6), (3, 8), (3, 7), (2, 12), (0, 1), (2, 6), (3, 97), (3, 45), (2, 0)], - [(0,None), (3, 6), (0, 63), (1, 5), (1, 6), (2, 97), (0, 28), (2, 63), (3, 0), (3, 2)], - [(0,None), (4, 6), (2, 4), (4, 65), (0, 6), (3, 68), (2, 1), (0, 14), (2, 1), (3, 0)], - [(0,None), (0, 6), (4, 9), (2,None), (4, 29), (3, 15), (3, 0), (2, 1), (0, 7), (2, 4)], - [(0,None), (1, 6), (1, 14), (0, 14), (3, 4), (2, 0), (3,None), (3, 4), (2, 0), (0,None)] - ] + A = [[(0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (1, None), (4, None), (4, None), (1, None)], [(0, None), (1, None), (2, 7), (3, 55), (4, 54), (1, 87), (0, 124), (1, 123), (4, 83), (4, 61)], [(0, None), (2, None), (4, 14), (1, 63), (3, 6), (4, 87), (1, 16), (0, 47), (1, 29), (4, 16)], [(0, None), (3, None), (1, 1), (4, 15), (2, 5), (4, 32), (4, 30), (1, 3), (0, 12), (1, 14)], [(0, None), (4, None), (3, 28), (2, 62), (1, 64), (1, 55), (4, 63), (4, 4), (1, 0), (0, 0)], [(0, None), (2, 6), (3, 8), (3, 7), (2, 12), (0, 1), (2, 6), (3, 97), (3, 45), (2, 0)], [(0, None), (3, 6), (0, 63), (1, 5), (1, 6), (2, 97), (0, 28), (2, 63), (3, 0), (3, 2)], [(0, None), (4, 6), (2, 4), (4, 65), (0, 6), (3, 68), (2, 1), (0, 14), (2, 1), (3, 0)], [(0, None), (0, 6), (4, 9), (2, None), (4, 29), (3, 15), (3, 0), (2, 1), (0, 7), (2, 4)], [(0, None), (1, 6), (1, 14), (0, 14), (3, 4), (2, 0), (3, None), (3, 4), (2, 0), (0, None)]] # 0,25 became 0,124 Y = [None, 0, 1, 2, 121, 66, 77, 78, 41, 100] - return OA_n_times_2_pow_c_from_matrix(11,7,FiniteField(5),list(zip(*A)),Y,check=False) + return OA_n_times_2_pow_c_from_matrix(11, 7, FiniteField(5), list(zip(*A)), Y, check=False) def OA_10_796(): @@ -1624,39 +1559,37 @@ def OA_10_796(): from sage.combinat.designs.orthogonal_arrays import OA_from_PBD from .orthogonal_arrays import incomplete_orthogonal_array - OA = orthogonal_array(17,47) - OA = OA_relabel(OA,17,47,blocks=[OA[0]]) # making sure [46]*17 is a block - PBD = [[i*47+x for i,x in enumerate(B) if (x < 46 or i < 13)] for B in OA] + OA = orthogonal_array(17, 47) + OA = OA_relabel(OA, 17, 47, blocks=[OA[0]]) # making sure [46]*17 is a block + PBD = [[i * 47 + x for i, x in enumerate(B) if (x < 46 or i < 13)] for B in OA] extra_point = 10000 - PBD.extend(list(range(i*47,(i+1)*47-int(i >= 13)))+[extra_point] - for i in range(17)) # Adding the columns + PBD.extend(list(range(i * 47, (i + 1) * 47 - int(i >= 13))) + [extra_point] for i in range(17)) # Adding the columns - rel = {v:i for i,v in enumerate(set(range(17*47)).difference([(i+1)*47-1 for i in range(13,17)]))} + rel = {v: i for i, v in enumerate(set(range(17 * 47)).difference([(i + 1) * 47 - 1 for i in range(13, 17)]))} rel[extra_point] = len(rel) PBD = [[rel[x] for x in B] for B in PBD] - assert set(map(len,PBD)) == set([13, 16, 17, 47, 48]) + assert set(map(len, PBD)) == set([13, 16, 17, 47, 48]) extra_point = rel[extra_point] others = [] OA = [] span = set() - iOA = {47: incomplete_orthogonal_array(10,47,(1,)), - 48: incomplete_orthogonal_array(10,48,(1,))} + iOA = {47: incomplete_orthogonal_array(10, 47, (1,)), 48: incomplete_orthogonal_array(10, 48, (1,))} for B in PBD: if len(B) >= 47: - B.sort(key=lambda x:int(x == extra_point)) + B.sort(key=lambda x: int(x == extra_point)) OA.extend([B[i] for i in BB] for BB in iOA[len(B)]) span.update(B[:-1]) else: others.append(B) - OA.extend(OA_from_PBD(10,796,others,check=False)) - OA = OA[:-796] # removes the [x]*k + OA.extend(OA_from_PBD(10, 796, others, check=False)) + OA = OA[:-796] # removes the [x]*k for x in set(range(796)).difference(span): - OA.append([x]*10) + OA.append([x] * 10) return OA @@ -1706,32 +1639,28 @@ def OA_10_469(): OA = [] # A cyclic (1407,38,1)-BIBD - B = (0,1,27,44,63,69,102,149,237,249,395,436,510,515,525,533,547,592,665, - 731,824,837,848,932,1002,1051,1055,1089,1105,1145,1165,1196,1217,1226, - 1274,1281,1309,1405) + B = (0, 1, 27, 44, 63, 69, 102, 149, 237, 249, 395, 436, 510, 515, 525, 533, 547, 592, 665, 731, 824, 837, 848, 932, 1002, 1051, 1055, 1089, 1105, 1145, 1165, 1196, 1217, 1226, 1274, 1281, 1309, 1405) - BIBD = [[(x+i) % 1407 for x in B] for i in range(1407)] + BIBD = [[(x + i) % 1407 for x in B] for i in range(1407)] # Only keep points v congruent to 0 mod 3 and relabel - PBD = [[x//3 for x in B if x % 3 == 0] for B in BIBD] + PBD = [[x // 3 for x in B if x % 3 == 0] for B in BIBD] # Split the block according to their size - blocks = {9:[],13:[],16:[]} + blocks = {9: [], 13: [], 16: []} for B in PBD: blocks[len(B)].append(B) # Product of each symmetric design with the OA - for b_size,symmetric_design in blocks.items(): + for b_size, symmetric_design in blocks.items(): matrix = _reorder_matrix(symmetric_design) - OA.extend([[B[xx] for xx in R] - for R in incomplete_orthogonal_array(9,b_size,[1]*b_size) - for B in matrix]) + OA.extend([[B[xx] for xx in R] for R in incomplete_orthogonal_array(9, b_size, [1] * b_size) for B in matrix]) # Last parallel class - OA.extend([[i]*9 for i in range(469)]) + OA.extend([[i] * 9 for i in range(469)]) - for i,R in enumerate(OA): - R.append(i//469) + for i, R in enumerate(OA): + R.append(i // 469) return OA @@ -1777,36 +1706,36 @@ def OA_520_plus_x(x): True """ from .orthogonal_arrays import incomplete_orthogonal_array - k = 9+x+1 + + k = 9 + x + 1 # The OA(17,31) with a block [30,30,...] - OA = incomplete_orthogonal_array(17,31,[1]) - OA.append([30]*17) + OA = incomplete_orthogonal_array(17, 31, [1]) + OA.append([30] * 17) # We truncate [30,30,...] to its first 9+x coordinates, and add sets # corresponding to each (possibly truncated) group extended with a new # point. The result is a (520+x,{9+x,16,17,31,32})-PBD. - new_point = 31*17 - PBD = [[i*31+xx for i,xx in enumerate(B) if i < 9+x or xx < 30] for B in OA] # truncated blocks - PBD.extend([list(range(i*31,i*31+30+bool(i < 9+x)))+[new_point] for i in range(17)]) # extended (+truncated) groups + new_point = 31 * 17 + PBD = [[i * 31 + xx for i, xx in enumerate(B) if i < 9 + x or xx < 30] for B in OA] # truncated blocks + PBD.extend([list(range(i * 31, i * 31 + 30 + bool(i < 9 + x))) + [new_point] for i in range(17)]) # extended (+truncated) groups - relabel = {v:i for i,v in enumerate(sorted(set().union(*PBD)))} + relabel = {v: i for i, v in enumerate(sorted(set().union(*PBD)))} PBD = [[relabel[xx] for xx in B] for B in PBD] subdesigns = { - 9+x: orthogonal_array(k,9+x), - 16 : incomplete_orthogonal_array(k,16,[1]*16), - 17 : incomplete_orthogonal_array(k,17,[1]*17), - 31 : incomplete_orthogonal_array(k,31,[1]), - 32 : incomplete_orthogonal_array(k,32,[1]*2), - } + 9 + x: orthogonal_array(k, 9 + x), + 16: incomplete_orthogonal_array(k, 16, [1] * 16), + 17: incomplete_orthogonal_array(k, 17, [1] * 17), + 31: incomplete_orthogonal_array(k, 31, [1]), + 32: incomplete_orthogonal_array(k, 32, [1] * 2), + } OA = [] for B in PBD: - OA.extend([[B[xx] for xx in R] - for R in subdesigns[len(B)]]) + OA.extend([[B[xx] for xx in R] for R in subdesigns[len(B)]]) - OA.append([relabel[new_point]]*k) + OA.append([relabel[new_point]] * k) return OA @@ -1906,25 +1835,25 @@ def OA_15_896(): from sage.rings.finite_rings.finite_field_constructor import FiniteField A = [ - [(0,None), (0,None), (0,None), (0,None), (0,None), (0,None), (0,None), (0,None), (1,None), (4,None), (2,None), (2,None), (4,None), (1,None)], - [(0,None), (1,None), (2, 17), (3, 20), (4, 49), (5, 4), (6, 59), (1, 15), (0, 114), (1, 76), (4, 106), (2, 87), (2, 118), (4, 49)], # 4,120 became the leftmost 4,49 - [(0,None), (2,None), (4, 2), (6, 98), (1, 53), (3, 97), (5, 123), (4, 3), (1, 32), (0, 10), (1, 45), (4, 3), (2, 1), (2, 14)], - [(0,None), (3,None), (6, 16), (2, 86), (5, 102), (1, 64), (4, 69), (2, 11), (4, 55), (1, 90), (0, 115), (1, 15), (4, 7), (2, 0)], - [(0,None), (4,None), (1, 4), (5, 110), (2, 51), (6, 118), (3, 8), (2, 81), (2, 79), (4, 98), (1, 2), (0, 3), (1, 7), (4,None)], - [(0,None), (5,None), (3, 66), (1, 70), (6, 102), (4, 119), (2, 20), (4, 86), (2, 59), (2, 15), (4, 63), (1, 126), (0, 1), (1, 0)], - [(0,None), (6,None), (5, 94), (4, 48), (3, 90), (2, 2), (1, 13), (1, 53), (4, 117), (2, 21), (2, 2), (4, 1), (1, 0), (0, 0)], - [(0,None), (4, 6), (2, 21), (1, 112), (1, 36), (2, 14), (4, 60), (0, 1), (6, 64), (3, 0), (5, 31), (5, 3), (3, 3), (6, 14)], - [(0,None), (5, 6), (4, 61), (4,None), (5, 108), (0, 91), (3, 10), (6, 15), (0,None), (6, 15), (3, 7), (5, 0), (5, 1), (3, 0)], - [(0,None), (6, 6), (6, 107), (0, 88), (2, 12), (5, 44), (2, 31), (3, 64), (6, 0), (0,None), (6, 2), (3, 3), (5,None), (5, 0)], - [(0,None), (0, 6), (1, 52), (3, 115), (6, 30), (3, 78), (1, 64), (5, 63), (3, 5), (6,None), (0,None), (6, 3), (3, 1), (5,None)], - [(0,None), (1, 6), (3, 117), (6, 19), (3, 9), (1, 31), (0, 56), (5, 0), (5, 63), (3,None), (6,None), (0,None), (6, 7), (3,None)], - [(0,None), (2, 6), (5, 116), (2, 3), (0, 0), (6,None), (6, 1), (3, 0), (5, 0), (5, 2), (3,None), (6,None), (0,None), (6, 0)], - [(0,None), (3, 6), (0, 0), (5, 0), (4, 1), (4,None), (5,None), (6, 0), (3, 2), (5, 0), (5,None), (3,None), (6,None), (0,None)] # 0,0 became the rightmost 0,None + [(0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (1, None), (4, None), (2, None), (2, None), (4, None), (1, None)], + [(0, None), (1, None), (2, 17), (3, 20), (4, 49), (5, 4), (6, 59), (1, 15), (0, 114), (1, 76), (4, 106), (2, 87), (2, 118), (4, 49)], # 4,120 became the leftmost 4,49 + [(0, None), (2, None), (4, 2), (6, 98), (1, 53), (3, 97), (5, 123), (4, 3), (1, 32), (0, 10), (1, 45), (4, 3), (2, 1), (2, 14)], + [(0, None), (3, None), (6, 16), (2, 86), (5, 102), (1, 64), (4, 69), (2, 11), (4, 55), (1, 90), (0, 115), (1, 15), (4, 7), (2, 0)], + [(0, None), (4, None), (1, 4), (5, 110), (2, 51), (6, 118), (3, 8), (2, 81), (2, 79), (4, 98), (1, 2), (0, 3), (1, 7), (4, None)], + [(0, None), (5, None), (3, 66), (1, 70), (6, 102), (4, 119), (2, 20), (4, 86), (2, 59), (2, 15), (4, 63), (1, 126), (0, 1), (1, 0)], + [(0, None), (6, None), (5, 94), (4, 48), (3, 90), (2, 2), (1, 13), (1, 53), (4, 117), (2, 21), (2, 2), (4, 1), (1, 0), (0, 0)], + [(0, None), (4, 6), (2, 21), (1, 112), (1, 36), (2, 14), (4, 60), (0, 1), (6, 64), (3, 0), (5, 31), (5, 3), (3, 3), (6, 14)], + [(0, None), (5, 6), (4, 61), (4, None), (5, 108), (0, 91), (3, 10), (6, 15), (0, None), (6, 15), (3, 7), (5, 0), (5, 1), (3, 0)], + [(0, None), (6, 6), (6, 107), (0, 88), (2, 12), (5, 44), (2, 31), (3, 64), (6, 0), (0, None), (6, 2), (3, 3), (5, None), (5, 0)], + [(0, None), (0, 6), (1, 52), (3, 115), (6, 30), (3, 78), (1, 64), (5, 63), (3, 5), (6, None), (0, None), (6, 3), (3, 1), (5, None)], + [(0, None), (1, 6), (3, 117), (6, 19), (3, 9), (1, 31), (0, 56), (5, 0), (5, 63), (3, None), (6, None), (0, None), (6, 7), (3, None)], + [(0, None), (2, 6), (5, 116), (2, 3), (0, 0), (6, None), (6, 1), (3, 0), (5, 0), (5, 2), (3, None), (6, None), (0, None), (6, 0)], + [(0, None), (3, 6), (0, 0), (5, 0), (4, 1), (4, None), (5, None), (6, 0), (3, 2), (5, 0), (5, None), (3, None), (6, None), (0, None)], # 0,0 became the rightmost 0,None ] - Y = [None, 0,1,2,121,66,77,78,41,100,74,118,108,43] + Y = [None, 0, 1, 2, 121, 66, 77, 78, 41, 100, 74, 118, 108, 43] - return OA_n_times_2_pow_c_from_matrix(15,7,FiniteField(7),list(zip(*A)),Y,check=False) + return OA_n_times_2_pow_c_from_matrix(15, 7, FiniteField(7), list(zip(*A)), Y, check=False) def OA_9_1078(): @@ -1955,7 +1884,7 @@ def OA_9_1078(): sage: designs.orthogonal_arrays.is_available(9,1078) # needs sage.schemes True """ - return wilson_construction(None,9,11,89,[[(11,9)]]) + return wilson_construction(None, 9, 11, 89, [[(11, 9)]]) def OA_25_1262(): @@ -1984,16 +1913,14 @@ def OA_25_1262(): """ from sage.combinat.designs.orthogonal_arrays import OA_from_PBD - B = (0, 68, 78, 106, 227, 296, 304, 330, 354, 411, 624, 631, 636, 732, 747, - 772, 794, 846, 869, 939, 948, 1011, 1015, 1031, 1135, 1171, 1188, 1206, - 1217, 1219, 1220, 1261, 1306, 1349, 1370, 1400, 1461, 1480, 1517, 1714, - 1768, 1827, 1833, 1866) - BIBD = [[(x+i) % 1893 for x in B] for i in range(1893)] # a (1893,44,1)-BIBD - PBD = [[x for x in B if (x % 3) < 2] for B in BIBD] # We only keep the x with x%3=0,1 - PBD = [[2*(x//3)+(x % 3) for x in B] for B in PBD] # The (1262, {25, 31,32})-PBD + B = (0, 68, 78, 106, 227, 296, 304, 330, 354, 411, 624, 631, 636, 732, 747, 772, 794, 846, 869, 939, 948, 1011, 1015, 1031, 1135, 1171, 1188, 1206, 1217, 1219, 1220, 1261, 1306, 1349, 1370, 1400, 1461, 1480, 1517, 1714, 1768, 1827, 1833, 1866) + + BIBD = [[(x + i) % 1893 for x in B] for i in range(1893)] # a (1893,44,1)-BIBD + PBD = [[x for x in B if (x % 3) < 2] for B in BIBD] # We only keep the x with x%3=0,1 + PBD = [[2 * (x // 3) + (x % 3) for x in B] for B in PBD] # The (1262, {25, 31,32})-PBD - return OA_from_PBD(25,1262,PBD,check=False) + return OA_from_PBD(25, 1262, PBD, check=False) def OA_9_1612(): @@ -2024,7 +1951,7 @@ def OA_9_1612(): sage: designs.orthogonal_arrays.is_available(9,1612) # needs sage.schemes True """ - return wilson_construction(None,9,17,89,[[(11,9)]]) + return wilson_construction(None, 9, 17, 89, [[(11, 9)]]) def OA_10_1620(): @@ -2055,7 +1982,8 @@ def OA_10_1620(): sage: designs.orthogonal_arrays.is_available(10,1620) # needs sage.schemes True """ - return wilson_construction(None,10,11,144,[[(9,4)]]) + return wilson_construction(None, 10, 11, 144, [[(9, 4)]]) + # Index of the OA constructions # @@ -2065,43 +1993,42 @@ def OA_10_1620(): OA_constructions = { - 18 : (7 , OA_7_18), - 40 : (9 , OA_9_40), - 66 : (7 , OA_7_66), - 68 : (7 , OA_7_68), - 69 : (8 , OA_8_69), - 74 : (7 , OA_7_74), - 76 : (8 , OA_8_76), - 80 : (11 , OA_11_80), - 112 : (15 , OA_15_112), - 120 : (9 , OA_9_120), - 135 : (9 , OA_9_135), - 160 : (11 , OA_11_160), - 176 : (16 , OA_16_176), - 185 : (11 , OA_11_185), - 205 : (10 , OA_10_205), - 208 : (16 , OA_16_208), - 224 : (15 , OA_15_224), - 254 : (11 , OA_11_254), - 352 : (20 , OA_20_352), - 416 : (20 , OA_20_416), - 469 : (10 , OA_10_469), - 520 : (10 , OA_10_520), - 522 : (12 , OA_12_522), - 524 : (14 , OA_14_524), - 544 : (20 , OA_20_544), - 560 : (17 , OA_17_560), - 640 : (11 , OA_11_640), - 796 : (10 , OA_10_796), - 896 : (15 , OA_15_896), - 1078 : (9 , OA_9_1078), - 1262 : (25, OA_25_1262), - 1612 : (9 , OA_9_1612), - 1620 : (10, OA_10_1620), + 18: (7, OA_7_18), + 40: (9, OA_9_40), + 66: (7, OA_7_66), + 68: (7, OA_7_68), + 69: (8, OA_8_69), + 74: (7, OA_7_74), + 76: (8, OA_8_76), + 80: (11, OA_11_80), + 112: (15, OA_15_112), + 120: (9, OA_9_120), + 135: (9, OA_9_135), + 160: (11, OA_11_160), + 176: (16, OA_16_176), + 185: (11, OA_11_185), + 205: (10, OA_10_205), + 208: (16, OA_16_208), + 224: (15, OA_15_224), + 254: (11, OA_11_254), + 352: (20, OA_20_352), + 416: (20, OA_20_416), + 469: (10, OA_10_469), + 520: (10, OA_10_520), + 522: (12, OA_12_522), + 524: (14, OA_14_524), + 544: (20, OA_20_544), + 560: (17, OA_17_560), + 640: (11, OA_11_640), + 796: (10, OA_10_796), + 896: (15, OA_15_896), + 1078: (9, OA_9_1078), + 1262: (25, OA_25_1262), + 1612: (9, OA_9_1612), + 1620: (10, OA_10_1620), } # Add this data to the module's doc -LIST_OF_OA_CONSTRUCTIONS = ", ".join(":func:`OA({},{}) `".format(k,n,k,n) - for n,(k,_) in OA_constructions.items()) +LIST_OF_OA_CONSTRUCTIONS = ", ".join(":func:`OA({},{}) `".format(k, n, k, n) for n, (k, _) in OA_constructions.items()) def QDM_19_6_1_1_1(): @@ -2121,12 +2048,8 @@ def QDM_19_6_1_1_1(): True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic - M = [[None, 7, 13, 1, 16, 9, 2], - [ 0, 1, 15, 7, 17, 6, 14], - [ 0, 11, 10, 11, 5, 4, 3], - [ 7,None, 13, 16, 1, 2, 9], - [ 1, 0, 15, 17, 7, 14, 6], - [ 11, 0, 10, 5, 11, 3, 4]] + + M = [[None, 7, 13, 1, 16, 9, 2], [0, 1, 15, 7, 17, 6, 14], [0, 11, 10, 11, 5, 4, 3], [7, None, 13, 16, 1, 2, 9], [1, 0, 15, 17, 7, 14, 6], [11, 0, 10, 5, 11, 3, 4]] Mb = [] @@ -2156,33 +2079,25 @@ def QDM_21_5_1_1_1(): True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(21) M = [ - [ 1, 13, 18, 3, 16, 19,None], - [ 16, 19, 1, 13, 18, 3, 0], - [ 18, 3, 16, 19, 1, 13, 0], - [ 6, 15, 6, 15, 6, 15, 0], - [ 12, 9, 19, 16, 5, 2, 0], - ] + [1, 13, 18, 3, 16, 19, None], + [16, 19, 1, 13, 18, 3, 0], + [18, 3, 16, 19, 1, 13, 0], + [6, 15, 6, 15, 6, 15, 0], + [12, 9, 19, 16, 5, 2, 0], + ] - Mb = [[0,7,14,None,0], - [0,14,7,0,None]] + Mb = [[0, 7, 14, None, 0], [0, 14, 7, 0, None]] for R in zip(*M): - a,b,c,d,e = (G(x) if x is not None else None for x in R) - Mb.append([a,b,c,d,e]) + a, b, c, d, e = (G(x) if x is not None else None for x in R) + Mb.append([a, b, c, d, e]) - Mb.append([16*c, - None if a is None else 16*a, - 16*b, - 16*d+7, - 16*e+14]) + Mb.append([16 * c, None if a is None else 16 * a, 16 * b, 16 * d + 7, 16 * e + 14]) - Mb.append([4*b, - 4*c, - None if a is None else 4*a, - 4*d+14, - 4*e+7]) + Mb.append([4 * b, 4 * c, None if a is None else 4 * a, 4 * d + 14, 4 * e + 7]) return G, Mb @@ -2204,26 +2119,27 @@ def QDM_21_6_1_1_5(): True """ M = [ - [None,None,None,None,None], - [ 0, 0, 0, 0, 0], - [ 1, 6, 7, 8, 14], - [ 3, 11, 20, 18, 10], - [ 6, 10, 14, 1, 5], - [ 4, 19, 5, 12, 2], - ] + [None, None, None, None, None], + [0, 0, 0, 0, 0], + [1, 6, 7, 8, 14], + [3, 11, 20, 18, 10], + [6, 10, 14, 1, 5], + [4, 19, 5, 12, 2], + ] from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(21) - Mb = [[0,0,0,0,0,0]] + Mb = [[0, 0, 0, 0, 0, 0]] for R in zip(*M): - a,b,c,d,e,f = R - Mb.append([a,b,c,d,e,f]) - Mb.append([b,c,d,e,f,a]) - Mb.append([c,d,e,f,a,b]) - Mb.append([d,e,f,a,b,c]) - Mb.append([e,f,a,b,c,d]) - Mb.append([f,a,b,c,d,e]) + a, b, c, d, e, f = R + Mb.append([a, b, c, d, e, f]) + Mb.append([b, c, d, e, f, a]) + Mb.append([c, d, e, f, a, b]) + Mb.append([d, e, f, a, b, c]) + Mb.append([e, f, a, b, c, d]) + Mb.append([f, a, b, c, d, e]) return G, Mb @@ -2244,32 +2160,20 @@ def QDM_25_6_1_1_5(): sage: is_quasi_difference_matrix(M,G,6,1,1,5) # needs sage.modules True """ - M = [ - [(0,0),None,(0,0),(0,0),(0,0),(0,0),(0,0)], - [(0,0),(0,0),None,(0,4),(0,2),(0,3),(0,1)], - [(0,0),(3,1),(3,0),None,(4,0),(1,0),(2,0)], - [(0,0),(3,0),(0,2),(1,2),None,(0,1),(0,3)], - [(0,0),(3,3),(1,2),(4,2),(2,0),None,(0,4)], - [(0,0),(4,2),(2,4),(0,3),(2,3),(3,2),None] - ] + M = [[(0, 0), None, (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)], [(0, 0), (0, 0), None, (0, 4), (0, 2), (0, 3), (0, 1)], [(0, 0), (3, 1), (3, 0), None, (4, 0), (1, 0), (2, 0)], [(0, 0), (3, 0), (0, 2), (1, 2), None, (0, 1), (0, 3)], [(0, 0), (3, 3), (1, 2), (4, 2), (2, 0), None, (0, 4)], [(0, 0), (4, 2), (2, 4), (0, 3), (2, 3), (3, 2), None]] from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup from sage.modules.free_module_element import free_module_element as vector - G = AdditiveAbelianGroup([5,5]) + + G = AdditiveAbelianGroup([5, 5]) M = [[None if x is None else G(vector(x)) for x in L] for L in M] Mb = [] for R in zip(*M): - a,b,c,d,e,f = R + a, b, c, d, e, f = R for i in range(5): - Mb.append([ - None if a is None else a+G(vector((i,i))), - None if b is None else b+G(vector((2*i,i))), - None if c is None else c+G(vector((i,0))), - None if d is None else d+G(vector((4*i,0))), - None if e is None else e+G(vector((3*i,4*i))), - None if f is None else f+G(vector((4*i,4*i)))]) + Mb.append([None if a is None else a + G(vector((i, i))), None if b is None else b + G(vector((2 * i, i))), None if c is None else c + G(vector((i, 0))), None if d is None else d + G(vector((4 * i, 0))), None if e is None else e + G(vector((3 * i, 4 * i))), None if f is None else f + G(vector((4 * i, 4 * i)))]) return G, Mb @@ -2290,30 +2194,20 @@ def QDM_33_6_1_1_1(): sage: is_quasi_difference_matrix(M,G,6,1,1,1) True """ - M = [ - [None, 0, 0, 0, 0, 0], - [ 30, 17, 10, 25, 23, 8], - [ 22, 4, 32, 29, 28, 22], - [ 25, 10, 20, 15, 21, 16], - [ 0, 12, 15, 16, 32, 23], - [ 6, 11, 18, 14, 9, 20] - ] + M = [[None, 0, 0, 0, 0, 0], [30, 17, 10, 25, 23, 8], [22, 4, 32, 29, 28, 22], [25, 10, 20, 15, 21, 16], [0, 12, 15, 16, 32, 23], [6, 11, 18, 14, 9, 20]] from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(33) - Mb = [[ 0, 0, 0, 0, 0, 0], - [ 1, 4, 16, 31, 25, 11], - [ 3, 12, 15, 27, 9, 11], - [10, 7, 28, 13, 19, 0], - [ 5, 20, 14, 23, 26,None]] + Mb = [[0, 0, 0, 0, 0, 0], [1, 4, 16, 31, 25, 11], [3, 12, 15, 27, 9, 11], [10, 7, 28, 13, 19, 0], [5, 20, 14, 23, 26, None]] - times4 = lambda x : None if x is None else 4*x + times4 = lambda x: None if x is None else 4 * x for R in zip(*M): - a,b,c,d,e,f = (None if x is None else G(x) for x in R) + a, b, c, d, e, f = (None if x is None else G(x) for x in R) for i in range(5): - Mb.append([a,b,c,d,e,f]) - a,b,c,d,e,f = map(times4,[e,a,b,c,d,f]) + Mb.append([a, b, c, d, e, f]) + a, b, c, d, e, f = map(times4, [e, a, b, c, d, f]) return G, Mb @@ -2334,25 +2228,19 @@ def QDM_37_6_1_1_1(): sage: is_quasi_difference_matrix(M,G,6,1,1,1) True """ - M = [ - [None, 10, 1, 2, 6, 3, 22, 5, 7, 9, 14, 18, 28], - [ 0, 1, 10, 20, 23, 30, 35, 13, 33, 16, 29, 32, 21], - [ 0, 26, 26, 15, 8, 4, 17, 19, 34, 12, 31, 24, 25], - [ 10,None, 10, 6, 2, 22, 3, 7, 5, 14, 9, 28, 18], - [ 1, 0, 26, 23, 20, 35, 30, 33, 13, 29, 16, 21, 32], - [ 26, 0, 1, 8, 15, 17, 4, 34, 19, 31, 12, 25, 24] - ] + M = [[None, 10, 1, 2, 6, 3, 22, 5, 7, 9, 14, 18, 28], [0, 1, 10, 20, 23, 30, 35, 13, 33, 16, 29, 32, 21], [0, 26, 26, 15, 8, 4, 17, 19, 34, 12, 31, 24, 25], [10, None, 10, 6, 2, 22, 3, 7, 5, 14, 9, 28, 18], [1, 0, 26, 23, 20, 35, 30, 33, 13, 29, 16, 21, 32], [26, 0, 1, 8, 15, 17, 4, 34, 19, 31, 12, 25, 24]] from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(37) Mb = [] for R in zip(*M): - a,b,c,d,e,f = R - Mb.append([a,b,c,d,e,f]) - Mb.append([b,c,a,f,d,e]) - Mb.append([c,a,b,e,f,d]) + a, b, c, d, e, f = R + Mb.append([a, b, c, d, e, f]) + Mb.append([b, c, a, f, d, e]) + Mb.append([c, a, b, e, f, d]) return G, Mb @@ -2373,24 +2261,17 @@ def QDM_35_7_1_1_7(): sage: is_quasi_difference_matrix(M,G,7,1,1,7) True """ - M = [ - [None,None,None,None,None,None,None], - [ 0, 0, 0, 0, 0, 0, 0], - [ 18, -18, 11, -11, 5, -5, 4], - [ 26, -26, 10, -10, 30, -30, 23], - [ 20, -20, 3, -3, 33, -33, 23], - [ 5, -5, 25, -25, 24, -24, 4], - [ 17, -17, 4, -4, 22, -22, 0] - ] + M = [[None, None, None, None, None, None, None], [0, 0, 0, 0, 0, 0, 0], [18, -18, 11, -11, 5, -5, 4], [26, -26, 10, -10, 30, -30, 23], [20, -20, 3, -3, 33, -33, 23], [5, -5, 25, -25, 24, -24, 4], [17, -17, 4, -4, 22, -22, 0]] from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(35) Mb = [] for R in zip(*M): for i in range(7): - Mb.append(cyclic_shift(R,i)) + Mb.append(cyclic_shift(R, i)) return G, Mb @@ -2412,23 +2293,24 @@ def QDM_45_7_1_1_9(): True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(45) M = [ - [None,None,None,None,None,None,None,None,None], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0], - [ 1, 27, 16, 7, -1, -27, -16, -7, 3], - [ 24, 40, 1, 35, -24, -40, -1, -35, 7], - [ 10, 30, 22, 44, -10, -30, -22, -44, 7], - [ 5, 18, 14, 33, -5, -18, -14, -33, 3], - [ 30, 16, 33, 27, -30, -16, -33, -27, 0], - ] + [None, None, None, None, None, None, None, None, None], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [1, 27, 16, 7, -1, -27, -16, -7, 3], + [24, 40, 1, 35, -24, -40, -1, -35, 7], + [10, 30, 22, 44, -10, -30, -22, -44, 7], + [5, 18, 14, 33, -5, -18, -14, -33, 3], + [30, 16, 33, 27, -30, -16, -33, -27, 0], + ] Mb = [] for R in zip(*M): for c in range(7): - Mb.append(cyclic_shift(R,c)) + Mb.append(cyclic_shift(R, c)) return G, Mb @@ -2450,23 +2332,16 @@ def QDM_54_7_1_1_8(): True """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(54) - M = [ - [ 0 ,None,None,None, 0 ,None ,None ,None,None,None], - [17 , 0 , 0 , 0 , -17 , 0 , 0 , 0 , 1 , 11 ], - [29 , 28 , 35 , 23 , -29 , -28 , -35 , -23, 3 , 19 ], - [36 , 50 , 5 , 33 , -36 , -50 , -5 , -33, 7 , 33 ], - [31 , 2 , 43 , 30 , -31 , - 2 , -43 , -30, 34 , 33 ], - [16 , 47 , 44 , 51 , -16 , -47 , -44 , -51, 30 , 19 ], - [41 , 11 , 1 , 17 , -41 , -11 , - 1 , -17, 28 , 11 ] - ] + M = [[0, None, None, None, 0, None, None, None, None, None], [17, 0, 0, 0, -17, 0, 0, 0, 1, 11], [29, 28, 35, 23, -29, -28, -35, -23, 3, 19], [36, 50, 5, 33, -36, -50, -5, -33, 7, 33], [31, 2, 43, 30, -31, -2, -43, -30, 34, 33], [16, 47, 44, 51, -16, -47, -44, -51, 30, 19], [41, 11, 1, 17, -41, -11, -1, -17, 28, 11]] Mb = [] for R in zip(*M): for c in range(7): - Mb.append(cyclic_shift(R,c)) + Mb.append(cyclic_shift(R, c)) return G, Mb @@ -2489,15 +2364,16 @@ def QDM_57_9_1_1_8(): """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as G - B = [None,1, 6, 7, 9, 19, 38, 42, 49] # Base block of a (57,8,1)-BIBD - OA = orthogonal_array(9,9,2) + B = [None, 1, 6, 7, 9, 19, 38, 42, 49] # Base block of a (57,8,1)-BIBD + OA = orthogonal_array(9, 9, 2) M = [R for R in OA if any(R[0] != x for x in R)] - M = [[B[x] for x in R] for R in M] # replacing [0,..,8] by the elements of B - M.append([0]*9) + M = [[B[x] for x in R] for R in M] # replacing [0,..,8] by the elements of B + M.append([0] * 9) return G(57), M + # Quasi-difference matrices # # The syntax of the dictionary is @@ -2510,25 +2386,13 @@ def QDM_57_9_1_1_8(): QDM: dict[tuple[int, int], dict] = {} -for ((n,k,lmbda,mu,u),f) in [((19,6,1,1,1), QDM_19_6_1_1_1), - ((21,5,1,1,1), QDM_21_5_1_1_1), - ((21,6,1,1,5), QDM_21_6_1_1_5), - ((25,6,1,1,5), QDM_25_6_1_1_5), - ((33,6,1,1,1), QDM_33_6_1_1_1), - ((37,6,1,1,1), QDM_37_6_1_1_1), - ((35,7,1,1,7), QDM_35_7_1_1_7), - ((45,7,1,1,9), QDM_45_7_1_1_9), - ((54,7,1,1,8), QDM_54_7_1_1_8), - ((57,9,1,1,8), QDM_57_9_1_1_8)]: - if (n+u,lmbda) not in QDM: - QDM[n+u,lmbda] = {} - QDM[n+u,lmbda][n,lmbda,mu,u] = (k,f) +for (n, k, lmbda, mu, u), f in [((19, 6, 1, 1, 1), QDM_19_6_1_1_1), ((21, 5, 1, 1, 1), QDM_21_5_1_1_1), ((21, 6, 1, 1, 5), QDM_21_6_1_1_5), ((25, 6, 1, 1, 5), QDM_25_6_1_1_5), ((33, 6, 1, 1, 1), QDM_33_6_1_1_1), ((37, 6, 1, 1, 1), QDM_37_6_1_1_1), ((35, 7, 1, 1, 7), QDM_35_7_1_1_7), ((45, 7, 1, 1, 9), QDM_45_7_1_1_9), ((54, 7, 1, 1, 8), QDM_54_7_1_1_8), ((57, 9, 1, 1, 8), QDM_57_9_1_1_8)]: + if (n + u, lmbda) not in QDM: + QDM[n + u, lmbda] = {} + QDM[n + u, lmbda][n, lmbda, mu, u] = (k, f) # Create the list of QDM matrices for the doc -LIST_OF_QDM = ", ".join("`({},{};{},{};{})`".format(n,k,lmbda,mu,u) - for n,k,lmbda,mu,u in - sorted((n,k,lmbda,mu,u) for entry in QDM.values() - for (n,lmbda,mu,u),(k,_) in sorted(entry.items()))) +LIST_OF_QDM = ", ".join("`({},{};{},{};{})`".format(n, k, lmbda, mu, u) for n, k, lmbda, mu, u in sorted((n, k, lmbda, mu, u) for entry in QDM.values() for (n, lmbda, mu, u), (k, _) in sorted(entry.items()))) _ref_Handbook = """Handbook of Combinatorial Designs (2ed), C. Colbourn, J. Dinitz, 2010 CRC Press""" @@ -2546,221 +2410,219 @@ def QDM_57_9_1_1_8(): Journal of Combinatorial Designs 2003, vol 11, num 4, pp 304-306""" Vmt_vectors = { - (3 ,2 ) : ((0,1,3,6), _ref_Handbook), - (3 ,4 ) : ((0,1,3,9), _ref_Handbook), - (3 ,10) : ((0,1,4,13), _ref_Handbook), - (3 ,12) : ((0,1,3,10), _ref_Handbook), - (3 ,20) : ((0,1,3,13), _ref_Handbook), - (3 ,6 ) : ((0,1,3,7), _ref_Handbook), - (3 ,26) : ((0,1,3,8), _ref_Handbook), - (3 ,32) : ((0,1,3,9), _ref_Handbook), - (3 ,14) : ((0,1,4,13), _ref_Handbook), - (3 ,24) : ((0,1,3,15), _ref_Handbook), - (3 ,34) : ((0,1,3,7), _ref_Handbook), - (4 ,3 ) : ((0,1,3,7,2), _ref_Handbook), - (4 ,7 ) : ((0,1,3,7,19), _ref_Handbook), - (4 ,9 ) : ((0,1,3,2,8), _ref_Brouwer_vanRees), - (4 ,13) : ((0,1,3,7,19), _ref_Handbook), - (4 ,15) : ((0,1,3,7,5), _ref_Handbook), - (4 ,25) : ((0,1,3,2,31), _ref_Handbook), - (5 ,6 ) : ((0,1,3,7,30,17), _ref_Handbook), - (5 ,8 ) : ((0,1,3,22,14,18), _ref_Handbook), - (5 ,12) : ((0,1,3,7,23,50), _ref_Handbook), - (5 ,14) : ((0,1,3,9,25,54), _ref_Handbook), - (5 ,20) : ((0,1,3,10,43,91), _ref_Handbook), - (5 ,26) : ((0,1,3,6,48,15), _ref_Handbook), - (6 ,5 ) : ((0,1,7,30,12,21,15), _ref_Handbook), - (6 ,7 ) : ((0,1,3,16,35,26,36), _ref_Colbourn), - (6 ,11) : ((0,1,3,14,7,24,27), _ref_Handbook), - (6 ,13) : ((0,1,3,7,55,47,34), _ref_Handbook), - (6 ,17) : ((0,1,3,2,14,99,29), _ref_Handbook), - (6 ,21) : ((0,1,4,13,66,93,45), _ref_Handbook), - (7 ,6 ) : ((0,1,12,27,37,16,30,35), _ref_Handbook), - (7 ,10) : ((0,1,3,45,9,50,28,16), _ref_Handbook), - (7 ,16) : ((0,1,3,7,82,72,93,39), _ref_Handbook), - (7 ,18) : ((0,1,3,6,97,114,99,26), _ref_Handbook), - (8 ,9 ) : ((0,1,20,70,23,59,3,8,19), _ref_Colbourn), - (8 ,11) : ((0,1,6,56,22,35,47,23,60), _ref_Colbourn), - (8 ,17) : ((0,1,3,2,133,126,47,109,74), _ref_Colbourn), - (8 ,29) : ((0,1,4,11,94,60,85,16,198), _ref_Colbourn), - (8 ,57) : ((0,1,3,2,12,333,363,154,340), _ref_Brouwer_vanRees), - (9 ,12) : ((0,1,4,19,56,22,83,95,52,96), _ref_Handbook), - (9 ,14) : ((0,1,11,25,37,8,100,23,95,42), _ref_Handbook), - (9 ,18) : ((0,1,3,7,36,30,158,94,52,70), _ref_Handbook), - (9 ,20) : ((0,1,3,19,145,70,173,159,18,85), _ref_Handbook), - (9 ,22) : ((0,1,3,31,99,190,174,46,87,127), _ref_Handbook), - (9 ,30) : ((0,1,3,8,197,68,119,13,215,105), _ref_Handbook), - (9 ,34) : ((0,1,3,13,140,81,74,131,303,238), _ref_Handbook), - (9 ,42) : ((0,1,3,6,66,258,186,346,104,152), _ref_Handbook), - (9 ,44) : ((0,1,4,11,144,103,216,77,160,363), _ref_Handbook), - (10,13) : ((0,1,5,10,22,6,14,9,53,129,84), _ref_Colbourn), - (10,15) : ((0,1,45,146,51,97,70,137,85,133,18), _ref_Handbook), - (10,19) : ((0,1,3,96,143,156,182,142,4,189,25), _ref_Colbourn), - (10,21) : ((0,1,6,188,205,39,101,113,30,32,42), _ref_Handbook), - (10,25) : ((0,1,3,85,140,178,195,22,48,179,188), _ref_Colbourn), - (10,27) : ((0,1,3,82,109,241,36,112,141,263,126), _ref_Colbourn), - (10,31) : ((0,1,3,57,128,247,289,239,70,271,96), _ref_Colbourn), - (10,33) : ((0,1,3,67,319,44,249,146,302,282,90), _ref_Handbook), - (10,43) : ((0,1,6,29,170,207,385,290,375,32,336), _ref_Colbourn), - (10,49) : ((0,1,3,8,406,72,335,197,324,383,395), _ref_Handbook), - (10,81) : ((0,1,3,2,27,438,615,708,168,410,656), _ref_Colbourn), - (10,97) : ((0,1,3,6,11,274,772,340,707,157,556), _ref_Colbourn), - (10,103) : ((0,1,3,2,7,744,342,797,468,46,561), _ref_Colbourn), - (10,181) : ((0,1,3,8,5,68,514,16,1168,225,929), _ref_Colbourn), - (10,187) : ((0,1,3,7,2,325,1138,730,1013,534,366), _ref_Colbourn), - (10,259) : ((0,1,3,7,2,15,324,1956,1353,2041,1616), _ref_Colbourn), - (10,273) : ((0,1,3,6,11,28,2573,38,1215,1299,2468), _ref_Colbourn), - (10,319) : ((0,1,3,7,2,43,239,1335,1586,2724,63), _ref_Colbourn), - (10,391) : ((0,1,3,2,5,32,555,3450,1242,1823,3833), _ref_Colbourn), - (10,409) : ((0,1,3,2,5,11,505,3202,1502,2521,3023), _ref_Colbourn), - (11,30 ) : ((0,1,58,61,235,82,160,120,260,161,204,174), _ref_Abel_v_11_t), - (11,32 ) : ((0,1,90,6,158,125,293,76,250,123,341,79), _ref_Abel_v_11_t), - (11,36 ) : ((0,1,3,57,250,77,196,255,371,107,305,260), _ref_Abel_v_11_t), - (11,38 ) : ((0,1,43,27,179,37,345,70,17,255,238,147), _ref_Abel_v_11_t), - (11,42 ) : ((0,1,3,12,87,104,392,328,346,314,23,359), _ref_Abel_v_11_t), - (11,56 ) : ((0,1,26,50,76,246,255,146,513,271,123,555), _ref_Abel_v_11_t), - (11,60 ) : ((0,1,5,46,324,206,537,621,304,307,529,547), _ref_Abel_v_11_t), - (11,62 ) : ((0,1,11,31,395,251,605,55,336,321,6,213), _ref_Abel_v_11_t), - (11,66 ) : ((0,1,4,32,15,586,669,112,240,496,490,210), _ref_Abel_v_11_t), - (11,78 ) : ((0,1,4,31,97,264,277,746,816,808,298,741), _ref_Abel_v_11_t), - (11,80 ) : ((0,1,3,73,68,71,569,409,127,110,554,432), _ref_Abel_v_11_t), - (11,86 ) : ((0,1,13,32,17,236,380,340,849,855,189,774), _ref_Abel_v_11_t), - (11,90 ) : ((0,1,6,19,193,213,529,661,52,952,638,605), _ref_Abel_v_11_t), - (11,92 ) : ((0,1,4,80,177,182,508,581,511,664,25,425), _ref_Abel_v_11_t), - (11,102) : ((0,1,9,34,747,766,884,887,812,12,255,475), _ref_Abel_v_11_t), - (11,116) : ((0,1,3,16,692,7,36,183,201,846,661,759), _ref_Abel_v_11_t), - (11,120) : ((0,1,4,29,531,536,732,1167,65,1033,508,1255), _ref_Abel_v_11_t), - (11,128) : ((0,1,6,53,50,492,599,1230,430,131,1063,677), _ref_Abel_v_11_t), - (11,132) : ((0,1,4,81,626,632,694,1352,744,60,105,821), _ref_Abel_v_11_t), - (11,146) : ((0,1,7,18,92,176,193,1088,114,515,791,548), _ref_Abel_v_11_t), - (11,162) : ((0,1,8,28,314,323,401,1569,1197,1455,1269,382), _ref_Abel_v_11_t), - (11,170) : ((0,1,8,41,1573,1585,1686,1750,358,1732,271,340), _ref_Abel_v_11_t), - (11,182) : ((0,1,5,23,675,682,732,1800,1821,1485,763,1913), _ref_Abel_v_11_t), - (11,188) : ((0,1,5,29,1454,1463,1493,1838,903,98,1692,1846), _ref_Abel_v_11_t), - (11,192) : ((0,1,4,9,1842,1851,1876,2035,139,979,1027,350), _ref_Abel_v_11_t), - (11,198) : ((0,1,3,52,250,255,278,347,418,856,1298,780), _ref_Abel_v_11_t), - (11,206) : ((0,1,6,99,1465,1469,1501,1530,869,2074,1786,674), _ref_Abel_v_11_t), - (11,210) : ((0,1,8,39,2228,2244,2274,2293,188,2181,537,867), _ref_Abel_v_11_t), - (11,212) : ((0,1,9,32,2219,2241,2310,2319,1253,352,920,365), _ref_Abel_v_11_t), - (11,216) : ((0,1,5,15,1606,1611,1627,2101,211,1821,1564,1688), _ref_Abel_v_11_t), - (11,218) : ((0,1,8,23,1347,1352,1358,1846,1479,2157,1910,292), _ref_Abel_v_11_t), - (11,230) : ((0,1,6,33,2387,2394,2488,2518,1893,728,246,65), _ref_Abel_v_11_t), - (11,242) : ((0,1,8,57,378,392,404,637,1708,567,1356,1903), _ref_Abel_v_11_t), - (11,246) : ((0,1,7,97,389,400,413,1253,1625,1071,1756,1440), _ref_Abel_v_11_t), - (11,248) : ((0,1,6,67,2112,2118,2142,2181,365,1315,2336,1283), _ref_Abel_v_11_t), - (11,260) : ((0,1,5,20,1158,1165,1171,1609,449,1990,1546,1222), _ref_Abel_v_11_t), - (11,266) : ((0,1,4,45,2132,2136,2164,2354,2407,2194,1459,394), _ref_Abel_v_11_t), - (11,270) : ((0,1,9,31,2085,2089,2100,2348,57,748,1440,2254), _ref_Abel_v_11_t), - (11,276) : ((0,1,5,42,1905,1910,1925,2382,618,594,2820,322), _ref_Abel_v_11_t), - (11,288) : ((0,1,7,21,2651,2656,2694,2953,190,545,311,3063), _ref_Abel_v_11_t), - (11,290) : ((0,1,5,95,1487,1492,1512,1523,1599,939,2724,971), _ref_Abel_v_11_t), - (11,296) : ((0,1,7,68,856,860,868,2884,2872,2339,2965,1715), _ref_Abel_v_11_t), - (11,300) : ((0,1,9,24,2221,2232,2246,2349,2196,3173,2190,1661), _ref_Abel_v_11_t), - (11,302) : ((0,1,8,24,1273,1277,1290,1750,2662,733,511,1147), _ref_Abel_v_11_t), - (11,308) : ((0,1,4,29,1159,1168,1174,2322,2963,1778,3071,2317), _ref_Abel_v_11_t), - (11,312) : ((0,1,4,43,121,128,136,1266,2919,603,3199,2590), _ref_Abel_v_11_t), - (11,318) : ((0,1,8,36,2701,2712,2733,2995,3281,2830,1262,2203), _ref_Abel_v_11_t), - (11,330) : ((0,1,9,22,2312,2316,2326,2517,1311,488,1406,267), _ref_Abel_v_11_t), - (11,336) : ((0,1,3,69,117,126,133,456,1399,579,3469,1157), _ref_Abel_v_11_t), - (11,338) : ((0,1,9,52,1012,1017,1027,1511,3139,243,2560,139), _ref_Abel_v_11_t), - (11,350) : ((0,1,5,37,2650,2655,2666,3213,3709,86,3456,1383), _ref_Abel_v_11_t), - (11,356) : ((0,1,6,23,2647,2651,2657,2942,2733,1481,301,831), _ref_Abel_v_11_t), - (11,366) : ((0,1,6,28,1144,1151,1160,1349,392,1114,1006,1906), _ref_Abel_v_11_t), - (11,368) : ((0,1,9,47,1259,1263,1269,1319,1029,2121,2206,3959), _ref_Abel_v_11_t), - (11,372) : ((0,1,7,89,1015,1022,1035,1280,361,3425,1101,2744), _ref_Abel_v_11_t), - (11,378) : ((0,1,3,35,551,558,570,750,481,464,118,2491), _ref_Abel_v_11_t), - (11,396) : ((0,1,9,58,1938,1942,1956,2251,434,768,582,1489), _ref_Abel_v_11_t), - (11,402) : ((0,1,8,49,4331,4336,4350,4399,4169,1114,3877,3795), _ref_Abel_v_11_t), - (11,420) : ((0,1,9,23,207,214,220,359,1273,1500,1817,1048), _ref_Abel_v_11_t), - (11,422) : ((0,1,7,27,86,97,125,246,3796,3663,2211,2422), _ref_Abel_v_11_t), - (11,450) : ((0,1,7,31,4808,4812,4826,4931,1333,4783,1152,162), _ref_Abel_v_11_t), - (11,452) : ((0,1,5,58,4530,4536,4544,4568,3644,1121,561,1732), _ref_Abel_v_11_t), - (12,33 ) : ((0,1,117,331,131,309,321,386,204,276,278,40,118), _ref_Abel_v_12_t), - (12,35 ) : ((0,1,110,361,349,226,98,68,80,234,347,198,321), _ref_Abel_v_12_t), - (12,45 ) : ((0,1,128,372,85,361,484,394,242,41,412,388,480), _ref_Abel_v_12_t), - (12,51 ) : ((0,1,216,516,92,426,559,292,568,184,387,460,162), _ref_Abel_v_12_t), - (12,55 ) : ((0,1,354,581,101,391,639,534,523,252,338,379,77), _ref_Abel_v_12_t), - (12,59 ) : ((0,1,287,561,431,482,527,513,234,518,366,673,670), _ref_Abel_v_12_t), - (12,61 ) : ((0,1,289,562,361,385,125,613,219,637,686,732,185), _ref_Abel_v_12_t), - (12,63 ) : ((0,1,216,562,384,653,218,584,188,704,11,29,122), _ref_Abel_v_12_t), - (12,69 ) : ((0,1,527,449,471,497,677,20,778,88,366,721,753), _ref_Abel_v_12_t), - (12,71 ) : ((0,1,645,446,813,543,413,7,55,177,468,503,646), _ref_Abel_v_12_t), - (12,73 ) : ((0,1,607,719,837,496,240,645,184,829,451,830,770), _ref_Abel_v_12_t), - (12,83 ) : ((0,1,627,898,836,939,742,42,847,531,173,607,361), _ref_Abel_v_12_t), - (12,85 ) : ((0,1,778,1000,913,819,961,456,507,186,509,495,300), _ref_Abel_v_12_t), - (12,89 ) : ((0,1,602,894,827,661,350,647,304,47,430,533,550), _ref_Abel_v_12_t), - (12,91 ) : ((0,1,777,1054,855,892,792,134,224,740,240,898,631), _ref_Abel_v_12_t), - (12,93 ) : ((0,1,601,1004,872,557,599,819,381,248,270,1091,49), _ref_Abel_v_12_t), - (12,101) : ((0,1,787,1049,818,1064,288,346,464,958,1188,340,1192), _ref_Abel_v_12_t), - (12,103) : ((0,1,770,1027,806,1082,515,436,1096,1060,57,1135,1144), _ref_Abel_v_12_t), - (12,115) : ((0,1,747,1179,873,484,969,692,679,153,1237,1110,616), _ref_Abel_v_12_t), - (12,119) : ((0,1,701,1225,834,515,367,727,1349,407,891,1189,153), _ref_Abel_v_12_t), - (12,121) : ((0,1,713,1265,848,421,998,69,874,1126,693,467,1164), _ref_Abel_v_12_t), - (12,129) : ((0,1,623,1170,824,450,1099,418,948,177,207,797,59), _ref_Abel_v_12_t), - (12,133) : ((0,1,648,1157,822,371,407,180,1120,898,342,548,117), _ref_Abel_v_12_t), - (12,135) : ((0,1,712,1253,844,623,943,992,191,845,299,1381,611), _ref_Abel_v_12_t), - (12,139) : ((0,1,627,1216,711,489,642,904,733,1246,96,1617,12), _ref_Abel_v_12_t), - (12,141) : ((0,1,447,522,967,763,1035,344,93,561,1137,523,828), _ref_Abel_v_12_t), - (12,145) : ((0,1,426,582,937,534,1538,1606,1148,1436,191,1406,823), _ref_Abel_v_12_t), - (12,149) : ((0,1,420,509,957,593,835,1031,1502,319,1552,1047,993), _ref_Abel_v_12_t), - (12,155) : ((0,1,300,482,962,638,1207,1682,885,211,1838,1244,531), _ref_Abel_v_12_t), - (12,161) : ((0,1,455,318,952,400,470,584,1368,292,678,1138,383), _ref_Abel_v_12_t), - (12,169) : ((0,1,425,326,951,1211,1881,1063,1631,1363,1554,665,1600), _ref_Abel_v_12_t), - (12,171) : ((0,1,432,319,933,688,549,63,2002,1702,653,1081,1813), _ref_Abel_v_12_t), - (12,185) : ((0,1,404,324,935,605,366,360,178,221,533,1940,30), _ref_Abel_v_12_t), - (12,189) : ((0,1,303,329,957,866,2180,1899,597,2209,1186,994,1301), _ref_Abel_v_12_t), - (12,191) : ((0,1,491,527,939,377,1685,1735,1967,1176,391,2192,681), _ref_Abel_v_12_t), - (12,195) : ((0,1,331,313,934,384,2105,479,1546,86,184,1127,1822), _ref_Abel_v_12_t), - (12,199) : ((0,1,377,524,946,560,316,1591,2036,273,1841,2091,713), _ref_Abel_v_12_t), - (12,203) : ((0,1,324,312,933,341,547,68,39,1008,561,1372,1300), _ref_Abel_v_12_t), - (12,213) : ((0,1,343,312,933,378,229,60,1179,1781,1960,66,536), _ref_Abel_v_12_t), - (12,223) : ((0,1,463,316,933,413,970,1083,2322,491,1226,1809,560), _ref_Abel_v_12_t), - (12,229) : ((0,1,338,312,933,380,401,2398,612,1279,1514,268,528), _ref_Abel_v_12_t), - (12,233) : ((0,1,405,314,934,398,1053,310,2254,2250,2652,1300,1079), _ref_Abel_v_12_t), - (12,243) : ((0,1,486,314,933,375,697,151,1964,1623,1590,1756,1152), _ref_Abel_v_12_t), - (12,253) : ((0,1,322,312,933,395,1047,12,176,1859,881,1220,2465), _ref_Abel_v_12_t), - (12,255) : ((0,1,463,316,938,345,360,2537,2648,2270,789,2959,2796), _ref_Abel_v_12_t), - (12,259) : ((0,1,486,314,933,350,575,1962,2347,750,3054,2719,1841), _ref_Abel_v_12_t), - (12,265) : ((0,1,333,312,933,343,759,1754,2650,1633,2479,2718,1164), _ref_Abel_v_12_t), - (12,269) : ((0,1,432,312,938,345,567,2441,966,1935,470,2105,3043), _ref_Abel_v_12_t), - (12,271) : ((0,1,463,313,933,356,453,2869,793,748,2116,3126,2839), _ref_Abel_v_12_t), - (12,275) : ((0,1,477,313,943,358,474,2312,1258,52,1452,2370,260), _ref_Abel_v_12_t), - (12,281) : ((0,1,483,313,933,387,418,961,1586,766,2937,275,2569), _ref_Abel_v_12_t), - (12,289) : ((0,1,474,313,943,367,963,3147,2157,238,12,1610,2189), _ref_Abel_v_12_t), - (12,293) : ((0,1,423,335,945,397,235,2878,1793,2484,2440,503,1609), _ref_Abel_v_12_t), - (12,295) : ((0,1,428,337,931,406,360,1978,68,375,721,2390,2465), _ref_Abel_v_12_t), - (12,301) : ((0,1,436,351,924,367,1196,265,2527,720,664,105,250), _ref_Abel_v_12_t), - (12,303) : ((0,1,487,572,946,462,2646,2616,1249,3143,21,2537,2128), _ref_Abel_v_12_t), - (12,309) : ((0,1,417,327,944,341,1924,1975,2308,1234,1658,1829,1606), _ref_Abel_v_12_t), - (12,311) : ((0,1,435,557,937,371,267,428,1289,3355,2948,3030,861), _ref_Abel_v_12_t), - (12,321) : ((0,1,319,325,952,364,674,2128,643,393,1025,619,868), _ref_Abel_v_12_t), - (12,323) : ((0,1,445,344,920,365,567,3483,3364,1240,344,2683,3070), _ref_Abel_v_12_t), - (12,335) : ((0,1,478,557,969,462,1587,1457,2552,2575,2420,168,924), _ref_Abel_v_12_t), - (12,341) : ((0,1,498,362,954,440,584,421,3867,3964,404,664,2233), _ref_Abel_v_12_t), - (12,355) : ((0,1,415,329,927,512,615,2336,127,2245,2250,2272,1888), _ref_Abel_v_12_t), - (12,363) : ((0,1,541,368,971,370,297,555,148,4195,1197,1527,211), _ref_Abel_v_12_t), - (12,379) : ((0,1,424,545,948,415,378,1181,2984,3458,3288,3888,74), _ref_Abel_v_12_t), - (12,383) : ((0,1,477,534,964,441,246,972,2504,3957,3101,4366,2168), _ref_Abel_v_12_t), - (12,385) : ((0,1,543,334,943,531,793,1852,538,4231,4492,580,3816), _ref_Abel_v_12_t), - (12,399) : ((0,1,487,571,964,391,300,4515,2211,3063,2771,2586,1056), _ref_Abel_v_12_t), - (12,401) : ((0,1,442,543,964,514,567,763,3816,3621,2124,1092,1456), _ref_Abel_v_12_t), - (12,405) : ((0,1,433,552,963,385,684,63,4243,3494,3500,560,4611), _ref_Abel_v_12_t), - (12,409) : ((0,1,426,541,954,411,708,1875,2058,2443,1913,2924,3673), _ref_Abel_v_12_t), - (12,411) : ((0,1,430,558,963,397,372,492,2502,3948,18,1191,3761), _ref_Abel_v_12_t), - (12,413) : ((0,1,436,546,977,467,242,3695,682,483,3026,461,1334), _ref_Abel_v_12_t), + (3, 2): ((0, 1, 3, 6), _ref_Handbook), + (3, 4): ((0, 1, 3, 9), _ref_Handbook), + (3, 10): ((0, 1, 4, 13), _ref_Handbook), + (3, 12): ((0, 1, 3, 10), _ref_Handbook), + (3, 20): ((0, 1, 3, 13), _ref_Handbook), + (3, 6): ((0, 1, 3, 7), _ref_Handbook), + (3, 26): ((0, 1, 3, 8), _ref_Handbook), + (3, 32): ((0, 1, 3, 9), _ref_Handbook), + (3, 14): ((0, 1, 4, 13), _ref_Handbook), + (3, 24): ((0, 1, 3, 15), _ref_Handbook), + (3, 34): ((0, 1, 3, 7), _ref_Handbook), + (4, 3): ((0, 1, 3, 7, 2), _ref_Handbook), + (4, 7): ((0, 1, 3, 7, 19), _ref_Handbook), + (4, 9): ((0, 1, 3, 2, 8), _ref_Brouwer_vanRees), + (4, 13): ((0, 1, 3, 7, 19), _ref_Handbook), + (4, 15): ((0, 1, 3, 7, 5), _ref_Handbook), + (4, 25): ((0, 1, 3, 2, 31), _ref_Handbook), + (5, 6): ((0, 1, 3, 7, 30, 17), _ref_Handbook), + (5, 8): ((0, 1, 3, 22, 14, 18), _ref_Handbook), + (5, 12): ((0, 1, 3, 7, 23, 50), _ref_Handbook), + (5, 14): ((0, 1, 3, 9, 25, 54), _ref_Handbook), + (5, 20): ((0, 1, 3, 10, 43, 91), _ref_Handbook), + (5, 26): ((0, 1, 3, 6, 48, 15), _ref_Handbook), + (6, 5): ((0, 1, 7, 30, 12, 21, 15), _ref_Handbook), + (6, 7): ((0, 1, 3, 16, 35, 26, 36), _ref_Colbourn), + (6, 11): ((0, 1, 3, 14, 7, 24, 27), _ref_Handbook), + (6, 13): ((0, 1, 3, 7, 55, 47, 34), _ref_Handbook), + (6, 17): ((0, 1, 3, 2, 14, 99, 29), _ref_Handbook), + (6, 21): ((0, 1, 4, 13, 66, 93, 45), _ref_Handbook), + (7, 6): ((0, 1, 12, 27, 37, 16, 30, 35), _ref_Handbook), + (7, 10): ((0, 1, 3, 45, 9, 50, 28, 16), _ref_Handbook), + (7, 16): ((0, 1, 3, 7, 82, 72, 93, 39), _ref_Handbook), + (7, 18): ((0, 1, 3, 6, 97, 114, 99, 26), _ref_Handbook), + (8, 9): ((0, 1, 20, 70, 23, 59, 3, 8, 19), _ref_Colbourn), + (8, 11): ((0, 1, 6, 56, 22, 35, 47, 23, 60), _ref_Colbourn), + (8, 17): ((0, 1, 3, 2, 133, 126, 47, 109, 74), _ref_Colbourn), + (8, 29): ((0, 1, 4, 11, 94, 60, 85, 16, 198), _ref_Colbourn), + (8, 57): ((0, 1, 3, 2, 12, 333, 363, 154, 340), _ref_Brouwer_vanRees), + (9, 12): ((0, 1, 4, 19, 56, 22, 83, 95, 52, 96), _ref_Handbook), + (9, 14): ((0, 1, 11, 25, 37, 8, 100, 23, 95, 42), _ref_Handbook), + (9, 18): ((0, 1, 3, 7, 36, 30, 158, 94, 52, 70), _ref_Handbook), + (9, 20): ((0, 1, 3, 19, 145, 70, 173, 159, 18, 85), _ref_Handbook), + (9, 22): ((0, 1, 3, 31, 99, 190, 174, 46, 87, 127), _ref_Handbook), + (9, 30): ((0, 1, 3, 8, 197, 68, 119, 13, 215, 105), _ref_Handbook), + (9, 34): ((0, 1, 3, 13, 140, 81, 74, 131, 303, 238), _ref_Handbook), + (9, 42): ((0, 1, 3, 6, 66, 258, 186, 346, 104, 152), _ref_Handbook), + (9, 44): ((0, 1, 4, 11, 144, 103, 216, 77, 160, 363), _ref_Handbook), + (10, 13): ((0, 1, 5, 10, 22, 6, 14, 9, 53, 129, 84), _ref_Colbourn), + (10, 15): ((0, 1, 45, 146, 51, 97, 70, 137, 85, 133, 18), _ref_Handbook), + (10, 19): ((0, 1, 3, 96, 143, 156, 182, 142, 4, 189, 25), _ref_Colbourn), + (10, 21): ((0, 1, 6, 188, 205, 39, 101, 113, 30, 32, 42), _ref_Handbook), + (10, 25): ((0, 1, 3, 85, 140, 178, 195, 22, 48, 179, 188), _ref_Colbourn), + (10, 27): ((0, 1, 3, 82, 109, 241, 36, 112, 141, 263, 126), _ref_Colbourn), + (10, 31): ((0, 1, 3, 57, 128, 247, 289, 239, 70, 271, 96), _ref_Colbourn), + (10, 33): ((0, 1, 3, 67, 319, 44, 249, 146, 302, 282, 90), _ref_Handbook), + (10, 43): ((0, 1, 6, 29, 170, 207, 385, 290, 375, 32, 336), _ref_Colbourn), + (10, 49): ((0, 1, 3, 8, 406, 72, 335, 197, 324, 383, 395), _ref_Handbook), + (10, 81): ((0, 1, 3, 2, 27, 438, 615, 708, 168, 410, 656), _ref_Colbourn), + (10, 97): ((0, 1, 3, 6, 11, 274, 772, 340, 707, 157, 556), _ref_Colbourn), + (10, 103): ((0, 1, 3, 2, 7, 744, 342, 797, 468, 46, 561), _ref_Colbourn), + (10, 181): ((0, 1, 3, 8, 5, 68, 514, 16, 1168, 225, 929), _ref_Colbourn), + (10, 187): ((0, 1, 3, 7, 2, 325, 1138, 730, 1013, 534, 366), _ref_Colbourn), + (10, 259): ((0, 1, 3, 7, 2, 15, 324, 1956, 1353, 2041, 1616), _ref_Colbourn), + (10, 273): ((0, 1, 3, 6, 11, 28, 2573, 38, 1215, 1299, 2468), _ref_Colbourn), + (10, 319): ((0, 1, 3, 7, 2, 43, 239, 1335, 1586, 2724, 63), _ref_Colbourn), + (10, 391): ((0, 1, 3, 2, 5, 32, 555, 3450, 1242, 1823, 3833), _ref_Colbourn), + (10, 409): ((0, 1, 3, 2, 5, 11, 505, 3202, 1502, 2521, 3023), _ref_Colbourn), + (11, 30): ((0, 1, 58, 61, 235, 82, 160, 120, 260, 161, 204, 174), _ref_Abel_v_11_t), + (11, 32): ((0, 1, 90, 6, 158, 125, 293, 76, 250, 123, 341, 79), _ref_Abel_v_11_t), + (11, 36): ((0, 1, 3, 57, 250, 77, 196, 255, 371, 107, 305, 260), _ref_Abel_v_11_t), + (11, 38): ((0, 1, 43, 27, 179, 37, 345, 70, 17, 255, 238, 147), _ref_Abel_v_11_t), + (11, 42): ((0, 1, 3, 12, 87, 104, 392, 328, 346, 314, 23, 359), _ref_Abel_v_11_t), + (11, 56): ((0, 1, 26, 50, 76, 246, 255, 146, 513, 271, 123, 555), _ref_Abel_v_11_t), + (11, 60): ((0, 1, 5, 46, 324, 206, 537, 621, 304, 307, 529, 547), _ref_Abel_v_11_t), + (11, 62): ((0, 1, 11, 31, 395, 251, 605, 55, 336, 321, 6, 213), _ref_Abel_v_11_t), + (11, 66): ((0, 1, 4, 32, 15, 586, 669, 112, 240, 496, 490, 210), _ref_Abel_v_11_t), + (11, 78): ((0, 1, 4, 31, 97, 264, 277, 746, 816, 808, 298, 741), _ref_Abel_v_11_t), + (11, 80): ((0, 1, 3, 73, 68, 71, 569, 409, 127, 110, 554, 432), _ref_Abel_v_11_t), + (11, 86): ((0, 1, 13, 32, 17, 236, 380, 340, 849, 855, 189, 774), _ref_Abel_v_11_t), + (11, 90): ((0, 1, 6, 19, 193, 213, 529, 661, 52, 952, 638, 605), _ref_Abel_v_11_t), + (11, 92): ((0, 1, 4, 80, 177, 182, 508, 581, 511, 664, 25, 425), _ref_Abel_v_11_t), + (11, 102): ((0, 1, 9, 34, 747, 766, 884, 887, 812, 12, 255, 475), _ref_Abel_v_11_t), + (11, 116): ((0, 1, 3, 16, 692, 7, 36, 183, 201, 846, 661, 759), _ref_Abel_v_11_t), + (11, 120): ((0, 1, 4, 29, 531, 536, 732, 1167, 65, 1033, 508, 1255), _ref_Abel_v_11_t), + (11, 128): ((0, 1, 6, 53, 50, 492, 599, 1230, 430, 131, 1063, 677), _ref_Abel_v_11_t), + (11, 132): ((0, 1, 4, 81, 626, 632, 694, 1352, 744, 60, 105, 821), _ref_Abel_v_11_t), + (11, 146): ((0, 1, 7, 18, 92, 176, 193, 1088, 114, 515, 791, 548), _ref_Abel_v_11_t), + (11, 162): ((0, 1, 8, 28, 314, 323, 401, 1569, 1197, 1455, 1269, 382), _ref_Abel_v_11_t), + (11, 170): ((0, 1, 8, 41, 1573, 1585, 1686, 1750, 358, 1732, 271, 340), _ref_Abel_v_11_t), + (11, 182): ((0, 1, 5, 23, 675, 682, 732, 1800, 1821, 1485, 763, 1913), _ref_Abel_v_11_t), + (11, 188): ((0, 1, 5, 29, 1454, 1463, 1493, 1838, 903, 98, 1692, 1846), _ref_Abel_v_11_t), + (11, 192): ((0, 1, 4, 9, 1842, 1851, 1876, 2035, 139, 979, 1027, 350), _ref_Abel_v_11_t), + (11, 198): ((0, 1, 3, 52, 250, 255, 278, 347, 418, 856, 1298, 780), _ref_Abel_v_11_t), + (11, 206): ((0, 1, 6, 99, 1465, 1469, 1501, 1530, 869, 2074, 1786, 674), _ref_Abel_v_11_t), + (11, 210): ((0, 1, 8, 39, 2228, 2244, 2274, 2293, 188, 2181, 537, 867), _ref_Abel_v_11_t), + (11, 212): ((0, 1, 9, 32, 2219, 2241, 2310, 2319, 1253, 352, 920, 365), _ref_Abel_v_11_t), + (11, 216): ((0, 1, 5, 15, 1606, 1611, 1627, 2101, 211, 1821, 1564, 1688), _ref_Abel_v_11_t), + (11, 218): ((0, 1, 8, 23, 1347, 1352, 1358, 1846, 1479, 2157, 1910, 292), _ref_Abel_v_11_t), + (11, 230): ((0, 1, 6, 33, 2387, 2394, 2488, 2518, 1893, 728, 246, 65), _ref_Abel_v_11_t), + (11, 242): ((0, 1, 8, 57, 378, 392, 404, 637, 1708, 567, 1356, 1903), _ref_Abel_v_11_t), + (11, 246): ((0, 1, 7, 97, 389, 400, 413, 1253, 1625, 1071, 1756, 1440), _ref_Abel_v_11_t), + (11, 248): ((0, 1, 6, 67, 2112, 2118, 2142, 2181, 365, 1315, 2336, 1283), _ref_Abel_v_11_t), + (11, 260): ((0, 1, 5, 20, 1158, 1165, 1171, 1609, 449, 1990, 1546, 1222), _ref_Abel_v_11_t), + (11, 266): ((0, 1, 4, 45, 2132, 2136, 2164, 2354, 2407, 2194, 1459, 394), _ref_Abel_v_11_t), + (11, 270): ((0, 1, 9, 31, 2085, 2089, 2100, 2348, 57, 748, 1440, 2254), _ref_Abel_v_11_t), + (11, 276): ((0, 1, 5, 42, 1905, 1910, 1925, 2382, 618, 594, 2820, 322), _ref_Abel_v_11_t), + (11, 288): ((0, 1, 7, 21, 2651, 2656, 2694, 2953, 190, 545, 311, 3063), _ref_Abel_v_11_t), + (11, 290): ((0, 1, 5, 95, 1487, 1492, 1512, 1523, 1599, 939, 2724, 971), _ref_Abel_v_11_t), + (11, 296): ((0, 1, 7, 68, 856, 860, 868, 2884, 2872, 2339, 2965, 1715), _ref_Abel_v_11_t), + (11, 300): ((0, 1, 9, 24, 2221, 2232, 2246, 2349, 2196, 3173, 2190, 1661), _ref_Abel_v_11_t), + (11, 302): ((0, 1, 8, 24, 1273, 1277, 1290, 1750, 2662, 733, 511, 1147), _ref_Abel_v_11_t), + (11, 308): ((0, 1, 4, 29, 1159, 1168, 1174, 2322, 2963, 1778, 3071, 2317), _ref_Abel_v_11_t), + (11, 312): ((0, 1, 4, 43, 121, 128, 136, 1266, 2919, 603, 3199, 2590), _ref_Abel_v_11_t), + (11, 318): ((0, 1, 8, 36, 2701, 2712, 2733, 2995, 3281, 2830, 1262, 2203), _ref_Abel_v_11_t), + (11, 330): ((0, 1, 9, 22, 2312, 2316, 2326, 2517, 1311, 488, 1406, 267), _ref_Abel_v_11_t), + (11, 336): ((0, 1, 3, 69, 117, 126, 133, 456, 1399, 579, 3469, 1157), _ref_Abel_v_11_t), + (11, 338): ((0, 1, 9, 52, 1012, 1017, 1027, 1511, 3139, 243, 2560, 139), _ref_Abel_v_11_t), + (11, 350): ((0, 1, 5, 37, 2650, 2655, 2666, 3213, 3709, 86, 3456, 1383), _ref_Abel_v_11_t), + (11, 356): ((0, 1, 6, 23, 2647, 2651, 2657, 2942, 2733, 1481, 301, 831), _ref_Abel_v_11_t), + (11, 366): ((0, 1, 6, 28, 1144, 1151, 1160, 1349, 392, 1114, 1006, 1906), _ref_Abel_v_11_t), + (11, 368): ((0, 1, 9, 47, 1259, 1263, 1269, 1319, 1029, 2121, 2206, 3959), _ref_Abel_v_11_t), + (11, 372): ((0, 1, 7, 89, 1015, 1022, 1035, 1280, 361, 3425, 1101, 2744), _ref_Abel_v_11_t), + (11, 378): ((0, 1, 3, 35, 551, 558, 570, 750, 481, 464, 118, 2491), _ref_Abel_v_11_t), + (11, 396): ((0, 1, 9, 58, 1938, 1942, 1956, 2251, 434, 768, 582, 1489), _ref_Abel_v_11_t), + (11, 402): ((0, 1, 8, 49, 4331, 4336, 4350, 4399, 4169, 1114, 3877, 3795), _ref_Abel_v_11_t), + (11, 420): ((0, 1, 9, 23, 207, 214, 220, 359, 1273, 1500, 1817, 1048), _ref_Abel_v_11_t), + (11, 422): ((0, 1, 7, 27, 86, 97, 125, 246, 3796, 3663, 2211, 2422), _ref_Abel_v_11_t), + (11, 450): ((0, 1, 7, 31, 4808, 4812, 4826, 4931, 1333, 4783, 1152, 162), _ref_Abel_v_11_t), + (11, 452): ((0, 1, 5, 58, 4530, 4536, 4544, 4568, 3644, 1121, 561, 1732), _ref_Abel_v_11_t), + (12, 33): ((0, 1, 117, 331, 131, 309, 321, 386, 204, 276, 278, 40, 118), _ref_Abel_v_12_t), + (12, 35): ((0, 1, 110, 361, 349, 226, 98, 68, 80, 234, 347, 198, 321), _ref_Abel_v_12_t), + (12, 45): ((0, 1, 128, 372, 85, 361, 484, 394, 242, 41, 412, 388, 480), _ref_Abel_v_12_t), + (12, 51): ((0, 1, 216, 516, 92, 426, 559, 292, 568, 184, 387, 460, 162), _ref_Abel_v_12_t), + (12, 55): ((0, 1, 354, 581, 101, 391, 639, 534, 523, 252, 338, 379, 77), _ref_Abel_v_12_t), + (12, 59): ((0, 1, 287, 561, 431, 482, 527, 513, 234, 518, 366, 673, 670), _ref_Abel_v_12_t), + (12, 61): ((0, 1, 289, 562, 361, 385, 125, 613, 219, 637, 686, 732, 185), _ref_Abel_v_12_t), + (12, 63): ((0, 1, 216, 562, 384, 653, 218, 584, 188, 704, 11, 29, 122), _ref_Abel_v_12_t), + (12, 69): ((0, 1, 527, 449, 471, 497, 677, 20, 778, 88, 366, 721, 753), _ref_Abel_v_12_t), + (12, 71): ((0, 1, 645, 446, 813, 543, 413, 7, 55, 177, 468, 503, 646), _ref_Abel_v_12_t), + (12, 73): ((0, 1, 607, 719, 837, 496, 240, 645, 184, 829, 451, 830, 770), _ref_Abel_v_12_t), + (12, 83): ((0, 1, 627, 898, 836, 939, 742, 42, 847, 531, 173, 607, 361), _ref_Abel_v_12_t), + (12, 85): ((0, 1, 778, 1000, 913, 819, 961, 456, 507, 186, 509, 495, 300), _ref_Abel_v_12_t), + (12, 89): ((0, 1, 602, 894, 827, 661, 350, 647, 304, 47, 430, 533, 550), _ref_Abel_v_12_t), + (12, 91): ((0, 1, 777, 1054, 855, 892, 792, 134, 224, 740, 240, 898, 631), _ref_Abel_v_12_t), + (12, 93): ((0, 1, 601, 1004, 872, 557, 599, 819, 381, 248, 270, 1091, 49), _ref_Abel_v_12_t), + (12, 101): ((0, 1, 787, 1049, 818, 1064, 288, 346, 464, 958, 1188, 340, 1192), _ref_Abel_v_12_t), + (12, 103): ((0, 1, 770, 1027, 806, 1082, 515, 436, 1096, 1060, 57, 1135, 1144), _ref_Abel_v_12_t), + (12, 115): ((0, 1, 747, 1179, 873, 484, 969, 692, 679, 153, 1237, 1110, 616), _ref_Abel_v_12_t), + (12, 119): ((0, 1, 701, 1225, 834, 515, 367, 727, 1349, 407, 891, 1189, 153), _ref_Abel_v_12_t), + (12, 121): ((0, 1, 713, 1265, 848, 421, 998, 69, 874, 1126, 693, 467, 1164), _ref_Abel_v_12_t), + (12, 129): ((0, 1, 623, 1170, 824, 450, 1099, 418, 948, 177, 207, 797, 59), _ref_Abel_v_12_t), + (12, 133): ((0, 1, 648, 1157, 822, 371, 407, 180, 1120, 898, 342, 548, 117), _ref_Abel_v_12_t), + (12, 135): ((0, 1, 712, 1253, 844, 623, 943, 992, 191, 845, 299, 1381, 611), _ref_Abel_v_12_t), + (12, 139): ((0, 1, 627, 1216, 711, 489, 642, 904, 733, 1246, 96, 1617, 12), _ref_Abel_v_12_t), + (12, 141): ((0, 1, 447, 522, 967, 763, 1035, 344, 93, 561, 1137, 523, 828), _ref_Abel_v_12_t), + (12, 145): ((0, 1, 426, 582, 937, 534, 1538, 1606, 1148, 1436, 191, 1406, 823), _ref_Abel_v_12_t), + (12, 149): ((0, 1, 420, 509, 957, 593, 835, 1031, 1502, 319, 1552, 1047, 993), _ref_Abel_v_12_t), + (12, 155): ((0, 1, 300, 482, 962, 638, 1207, 1682, 885, 211, 1838, 1244, 531), _ref_Abel_v_12_t), + (12, 161): ((0, 1, 455, 318, 952, 400, 470, 584, 1368, 292, 678, 1138, 383), _ref_Abel_v_12_t), + (12, 169): ((0, 1, 425, 326, 951, 1211, 1881, 1063, 1631, 1363, 1554, 665, 1600), _ref_Abel_v_12_t), + (12, 171): ((0, 1, 432, 319, 933, 688, 549, 63, 2002, 1702, 653, 1081, 1813), _ref_Abel_v_12_t), + (12, 185): ((0, 1, 404, 324, 935, 605, 366, 360, 178, 221, 533, 1940, 30), _ref_Abel_v_12_t), + (12, 189): ((0, 1, 303, 329, 957, 866, 2180, 1899, 597, 2209, 1186, 994, 1301), _ref_Abel_v_12_t), + (12, 191): ((0, 1, 491, 527, 939, 377, 1685, 1735, 1967, 1176, 391, 2192, 681), _ref_Abel_v_12_t), + (12, 195): ((0, 1, 331, 313, 934, 384, 2105, 479, 1546, 86, 184, 1127, 1822), _ref_Abel_v_12_t), + (12, 199): ((0, 1, 377, 524, 946, 560, 316, 1591, 2036, 273, 1841, 2091, 713), _ref_Abel_v_12_t), + (12, 203): ((0, 1, 324, 312, 933, 341, 547, 68, 39, 1008, 561, 1372, 1300), _ref_Abel_v_12_t), + (12, 213): ((0, 1, 343, 312, 933, 378, 229, 60, 1179, 1781, 1960, 66, 536), _ref_Abel_v_12_t), + (12, 223): ((0, 1, 463, 316, 933, 413, 970, 1083, 2322, 491, 1226, 1809, 560), _ref_Abel_v_12_t), + (12, 229): ((0, 1, 338, 312, 933, 380, 401, 2398, 612, 1279, 1514, 268, 528), _ref_Abel_v_12_t), + (12, 233): ((0, 1, 405, 314, 934, 398, 1053, 310, 2254, 2250, 2652, 1300, 1079), _ref_Abel_v_12_t), + (12, 243): ((0, 1, 486, 314, 933, 375, 697, 151, 1964, 1623, 1590, 1756, 1152), _ref_Abel_v_12_t), + (12, 253): ((0, 1, 322, 312, 933, 395, 1047, 12, 176, 1859, 881, 1220, 2465), _ref_Abel_v_12_t), + (12, 255): ((0, 1, 463, 316, 938, 345, 360, 2537, 2648, 2270, 789, 2959, 2796), _ref_Abel_v_12_t), + (12, 259): ((0, 1, 486, 314, 933, 350, 575, 1962, 2347, 750, 3054, 2719, 1841), _ref_Abel_v_12_t), + (12, 265): ((0, 1, 333, 312, 933, 343, 759, 1754, 2650, 1633, 2479, 2718, 1164), _ref_Abel_v_12_t), + (12, 269): ((0, 1, 432, 312, 938, 345, 567, 2441, 966, 1935, 470, 2105, 3043), _ref_Abel_v_12_t), + (12, 271): ((0, 1, 463, 313, 933, 356, 453, 2869, 793, 748, 2116, 3126, 2839), _ref_Abel_v_12_t), + (12, 275): ((0, 1, 477, 313, 943, 358, 474, 2312, 1258, 52, 1452, 2370, 260), _ref_Abel_v_12_t), + (12, 281): ((0, 1, 483, 313, 933, 387, 418, 961, 1586, 766, 2937, 275, 2569), _ref_Abel_v_12_t), + (12, 289): ((0, 1, 474, 313, 943, 367, 963, 3147, 2157, 238, 12, 1610, 2189), _ref_Abel_v_12_t), + (12, 293): ((0, 1, 423, 335, 945, 397, 235, 2878, 1793, 2484, 2440, 503, 1609), _ref_Abel_v_12_t), + (12, 295): ((0, 1, 428, 337, 931, 406, 360, 1978, 68, 375, 721, 2390, 2465), _ref_Abel_v_12_t), + (12, 301): ((0, 1, 436, 351, 924, 367, 1196, 265, 2527, 720, 664, 105, 250), _ref_Abel_v_12_t), + (12, 303): ((0, 1, 487, 572, 946, 462, 2646, 2616, 1249, 3143, 21, 2537, 2128), _ref_Abel_v_12_t), + (12, 309): ((0, 1, 417, 327, 944, 341, 1924, 1975, 2308, 1234, 1658, 1829, 1606), _ref_Abel_v_12_t), + (12, 311): ((0, 1, 435, 557, 937, 371, 267, 428, 1289, 3355, 2948, 3030, 861), _ref_Abel_v_12_t), + (12, 321): ((0, 1, 319, 325, 952, 364, 674, 2128, 643, 393, 1025, 619, 868), _ref_Abel_v_12_t), + (12, 323): ((0, 1, 445, 344, 920, 365, 567, 3483, 3364, 1240, 344, 2683, 3070), _ref_Abel_v_12_t), + (12, 335): ((0, 1, 478, 557, 969, 462, 1587, 1457, 2552, 2575, 2420, 168, 924), _ref_Abel_v_12_t), + (12, 341): ((0, 1, 498, 362, 954, 440, 584, 421, 3867, 3964, 404, 664, 2233), _ref_Abel_v_12_t), + (12, 355): ((0, 1, 415, 329, 927, 512, 615, 2336, 127, 2245, 2250, 2272, 1888), _ref_Abel_v_12_t), + (12, 363): ((0, 1, 541, 368, 971, 370, 297, 555, 148, 4195, 1197, 1527, 211), _ref_Abel_v_12_t), + (12, 379): ((0, 1, 424, 545, 948, 415, 378, 1181, 2984, 3458, 3288, 3888, 74), _ref_Abel_v_12_t), + (12, 383): ((0, 1, 477, 534, 964, 441, 246, 972, 2504, 3957, 3101, 4366, 2168), _ref_Abel_v_12_t), + (12, 385): ((0, 1, 543, 334, 943, 531, 793, 1852, 538, 4231, 4492, 580, 3816), _ref_Abel_v_12_t), + (12, 399): ((0, 1, 487, 571, 964, 391, 300, 4515, 2211, 3063, 2771, 2586, 1056), _ref_Abel_v_12_t), + (12, 401): ((0, 1, 442, 543, 964, 514, 567, 763, 3816, 3621, 2124, 1092, 1456), _ref_Abel_v_12_t), + (12, 405): ((0, 1, 433, 552, 963, 385, 684, 63, 4243, 3494, 3500, 560, 4611), _ref_Abel_v_12_t), + (12, 409): ((0, 1, 426, 541, 954, 411, 708, 1875, 2058, 2443, 1913, 2924, 3673), _ref_Abel_v_12_t), + (12, 411): ((0, 1, 430, 558, 963, 397, 372, 492, 2502, 3948, 18, 1191, 3761), _ref_Abel_v_12_t), + (12, 413): ((0, 1, 436, 546, 977, 467, 242, 3695, 682, 483, 3026, 461, 1334), _ref_Abel_v_12_t), } # Translate all V(m,t) into (mt+1,m+2;1,0;t)-QDM constructors -for (m,t),(vec,source) in Vmt_vectors.items(): - n,k,lmbda,mu,u = (m*t+1,m+2,1,0,t) - if (n+u,lmbda) not in QDM: - QDM[n+u,lmbda] = {} - QDM[n+u,lmbda][n,lmbda,mu,u] = (k,lambda m=m,t=t,vec=vec:QDM_from_Vmt(m,t,vec)) +for (m, t), (vec, source) in Vmt_vectors.items(): + n, k, lmbda, mu, u = (m * t + 1, m + 2, 1, 0, t) + if (n + u, lmbda) not in QDM: + QDM[n + u, lmbda] = {} + QDM[n + u, lmbda][n, lmbda, mu, u] = (k, lambda m=m, t=t, vec=vec: QDM_from_Vmt(m, t, vec)) # Create the list of V(m,t) vectors for the doc -_all_m = sorted(set(m for m,_ in Vmt_vectors.keys())) -LIST_OF_VMT_VECTORS = "\n".join(" - `m={}` and `t=` ".format(m) + - ", ".join("`{}`".format(t) for _,t in sorted(Vmt_vectors.keys()) if _ == m) - for m in _all_m) +_all_m = sorted(set(m for m, _ in Vmt_vectors.keys())) +LIST_OF_VMT_VECTORS = "\n".join(" - `m={}` and `t=` ".format(m) + ", ".join("`{}`".format(t) for _, t in sorted(Vmt_vectors.keys()) if _ == m) for m in _all_m) r""" Test for the Vmt vectors @@ -2778,452 +2640,561 @@ def QDM_57_9_1_1_8(): """ DF = { -############## -# lambda = 1 # -############## -( 15, 3, 1): - {(15,): [[0,1,4],[0,2,9],[0,5,10]]}, -( 21, 3, 1): - {(21,): [[0,1,3],[0,4,12],[0,5,11],[0,7,14]]}, -( 21, 5, 1): - {(21,): [[0,1,4,14,16]]}, -( 25, 3, 1): - {(25,): [[0,1,3],[0,4,11],[0,5,13],[0,6,15]]}, -( 25, 4, 1): - {(5,5): [[(0,0),(0,1),(1,0),(2,2)],[(0,0),(0,2),(2,0),(4,4)]]}, -( 27, 3, 1): - {(27,): [[0,1,3],[0,4,11],[0,5,15],[0,6,14],[0,9,18]]}, -( 33, 3, 1): - {(33,): [[0,1,3],[0,4,10],[0,5,18],[0,7,19],[0,8,17],[0,11,22]]}, -( 37, 4, 1): - {(37,): [[0,1,3,24],[0,4,26,32],[0,10,18,30]]}, -( 39, 3, 1): - {(39,): [[0,1,3],[0,4,18],[0,5,27],[0,6,16],[0,7,15],[0,9,20],[0,13,26]]}, -( 40, 4, 1): - {(40,): [[0,1,4,13],[0,2,7,24],[0,6,14,25],[0,10,20,30]]}, -( 45, 3, 1): - {(45,): [[0,1,3],[0,4,10],[0,5,28],[0,7,34],[0,8,32],[0,9,29],[0,12,26],[0,15,30]]}, -( 45, 5, 1): - {(3,3,5): [[(0,1,0),(0,2,0),(1,0,2),(2,0,2),(0,0,1)], - [(2,1,0),(1,2,0),(2,2,2),(1,1,2),(0,0,1)], - [(0,0,0),(0,0,1),(0,0,2),(0,0,3),(0,0,4)]]}, -( 49, 3, 1): - {(49,): [[0,1,3],[0,4,9],[0,6,17],[0,7,23],[0,8,30],[0,10,31],[0,12,36],[0,14,34]]}, -( 49, 4, 1): - {(49,): [[0,1,3,8,],[0,4,18,29],[0,6,21,33],[0,9,19,32]]}, -( 51, 3, 1): - {(51,): [[0,1,3],[0,4,9],[0,6,25],[0,7,35], - [0,8,22],[0,10,21],[0,12,27],[0,13,31],[0,17,34]]}, -( 52, 4, 1): - {(52,): [[0,1,3,7,],[0,5,19,35],[0,8,20,31],[0,9,24,34],[0,13,26,39]]}, -( 55, 3, 1): - {(55,): [[0,1,3],[0,4,9],[0,6,16],[0,7,32],[0,8,29], - [0,11,42],[0,12,27],[0,14,36],[0,17,37]]}, -( 57, 3, 1): - {(57,): [[0,1,3],[0,4,9],[0,6,13],[0,8,26],[0,10,33], - [0,11,32],[0,12,40],[0,14,41],[0,15,35],[0,19,38]]}, -( 63, 3, 1): - {(63,): [[0,1,3],[0,4,9],[0,6,13],[0,8,25],[0,10,41],[0,11,44], - [0,12,36],[0,14,37],[0,15,43],[0,16,34],[0,21,42]]}, -( 64, 4, 1): - {(64,): [[0,1,3,7,],[0,5,18,47],[0,8,33,44], - [0,9,19,43],[0,12,26,49],[0,16,32,48]]}, -( 65, 5, 1): - {(65,): [[0,1,3,31,45],[0,4,10,19,57],[0,5,16,41,48],[0,13,26,39,52]]}, -( 69, 3, 1): - {(69,): [[0,1,3],[0,4,9],[0,6,13],[0,8,24],[0,10,38],[0,11,47],[0,12,32], - [0,14,40],[0,15,50],[0,17,42],[0,18,39],[0,23,46]]}, -( 75, 3, 1): - {(75,): [[0,1,67],[0,2,47],[0,3,41],[0,4,69],[0,5,68],[0,11,55],[0,13,61], - [0,15,33],[0,16,52],[0,17,43],[0,19,40],[0,22,51],[0,25,50]]}, -( 76, 4, 1): - {(76,): [[0,1,7,22],[0,2,11,45],[0,3,59,71],[0,4,32,50], - [0,10,37,51],[0,13,36,60],[0,19,38,57]]}, -( 81, 3, 1): - {(81,): [[0,1,39],[0,2,58],[0,3,34],[0,4,21],[0,5,67],[0,6,15],[0,7,36], - [0,8,59],[0,10,63],[0,11,37],[0,12,61],[0,13,48],[0,16,40],[0,27,54]]}, -( 81, 5, 1): - {(81,): [[0,1,5,12,26],[0,2,10,40,64],[0,3,18,47,53],[0,9,32,48,68]]}, -( 85, 4, 1): - {(85,): [[0,2,41,42],[0,17,32,38],[0,18,27,37],[0,13,29,36], - [0,11,31,35],[0,12,26,34,],[0,5,30,33]]}, -( 91, 6, 1): - {(91,): [[0,1,3,7,25,38], [0,16,21,36,48,62], [0,30,40,63,74,82]]}, - -( 91, 7, 1): # from the La Jolla covering repository, attributed to Jan de Heer and Steve Muir - {(91,): [[8, 9, 14, 25, 58, 81, 85], [5, 33, 35, 42, 45, 67, 88], [4, 17, 30, 43, 56, 69, 82]]}, - -(121, 5, 1): - {(121,): [[0,14,26,51,60],[0,15,31,55,59],[0,10,23,52,58], - [0,3,36,56,57],[0,7,18,45,50],[0,8,30,47,49]]}, -(121, 6, 1): - {(11,11): [[(0,0),(0,3),(0,4),(1,1),(1,7),(4,6)], - [(0,0),(0,2),(2,5),(4,7),(6,4),(8,0)], - [(0,0),(1,5),(2,0),(4,1),(6,0),(7,2)], - [(0,0),(1,0),(3,9),(4,8),(6,1),(9,5)]]}, -(141, 5, 1): - {(141,): [[0,33,60,92,97],[0,3,45,88,110],[0,18,39,68,139],[0,12,67,75,113], - [0,1,15,84,94],[0,7,11,24,30],[0,36,90,116,125]]}, -(161, 5, 1): - {(161,): [[0,19,34,73,80],[0,16,44,71,79],[0,12,33,74,78],[0,13,30,72,77], - [0,11,36,67,76],[0,18,32,69,75],[0,10,48,68,70],[0,3,29,52,53]]}, -(175, 7, 1): - {(7,5,5): [[(0,0,0),(1,0,0),(2,0,0),(3,0,0),(4,0,0),(5,0,0),(6,0,0)], - [(0,0,0),(1,1,3),(1,4,2),(2,2,2),(2,3,3),(4,2,0),(4,3,0)], - [(0,0,0),(1,3,4),(1,2,1),(2,2,3),(2,3,2),(4,0,2),(4,0,3)], - [(0,0,0),(1,1,2),(1,4,3),(2,1,1),(2,4,4),(4,0,1),(4,0,4)], - [(0,0,0),(1,3,1),(1,2,4),(2,4,1),(2,1,4),(4,1,0),(4,4,0)]]}, -(201, 5, 1): - {(201,): [[0,1,45,98,100],[0,3,32,65,89],[0,4,54,70,75],[0,6,49,69,91],[0,7,58,81,95], - [0,8,34,72,90],[0,9,36,77,96],[0,10,35,83,94],[0,12,40,79,92],[0,15,46,76,93]]}, -(217, 7, 1): - {(217,): [[0,1,37,67,88,92,149],[0,15,18,65,78,121,137],[0,8,53,79,85,102,107], - [0,11,86,100,120,144,190],[0,29,64,165,198,205,207],[0,31,62,93,124,155,186]]}, -(221, 5, 1): - {(221,): [[0,1,24,61,116],[0,3,46,65,113],[0,4,73,89,130],[0,5,77,122,124], - [0,6,39,50,118],[0,7,66,81,94],[0,8,38,64,139],[0,9,29,80,107], - [0,10,35,93,135],[0,12,34,52,88],[0,14,31,63,84]]}, - -(259, 7, 1): # the following one is lemma 2.2 in Abel "Some new BIBDs with block size 7" - {(7,37): [[(0,0),(1,0),(2,0),(3,0),(4,0),(5,0),(6,0)], - [(0,0),(0,1),(0,6),(1,4),(2,19),(3,25),(6,26)], - [(0,0),(0,10),(0,23),(2,3),(4,5),(5,1),(6,28)], - [(0,0),(0,8),(0,26),(1,13),(3,10),(4,30),(5,21)], - [(0,0),(0,4),(1,25),(1,34),(2,33),(2,35),(4,10)], - [(0,0),(0,3),(1,26),(2,7),(2,28),(4,17),(4,34)], - [(0,0),(0,30),(1,7),(1,22),(2,1),(4,21),(4,33)]]}, - -############## -# lambda = 2 # -############## -( 16, 3, 2): - {(16,): [[0,1,2],[0,2,8],[0,3,7],[0,4,7],[0,5,10]]}, -( 28, 3, 2): - {(28,): [[0,1,12],[0,2,11],[0,2,12],[0,3,7],[0,3,13], - [0,4,9],[0,5,13],[0,6,7],[0,6,14]]}, -( 40, 3, 2): - {(40,): [[0,1,4],[0,1,16],[0,2,7],[0,2,9],[0,3,17],[0,4,17],[0,5,19], - [0,6,16],[0,6,18],[0,8,18],[0,8,19],[0,9,20],[0,12,25]]}, -( 19, 4, 2): - {(19,): [[0,1,3,12],[0,1,5,13],[0,4,6,9]]}, -( 21, 4, 3): - {(21,): [[0,2,3,7],[0,3,5,9],[0,1,7,11],[0,2,8,11],[0,1,9,14]]}, -( 22, 4, 2): - {(22,): [[0,4,16,17],[0,12,14,21],[0,14,16,19],[0,4,11,15]]}, -( 31, 4, 2): - {(31,): [[0,1,8,11],[0,1,13,17],[0,2,11,14],[0,5,7,13],[0,5,9,15]]}, -( 34, 4, 2): - {(34,): [[0,1,22,24],[0,1,19,25],[0,2,6,29],[0,4,7,20],[0,5,8,20],[0,8,17,25]]}, -( 43, 4, 2): - {(43,): [[0,1,6,36],[0,3,18,22],[0,9,11,23],[0,10,12,26],[0,26,27,33], - [0,13,35,38],[0,19,28,39,]]}, -( 46, 4, 2): - {(46,): [[0,2,7,10],[0,4,19,32],[0,10,34,35],[0,5,8,24],[0,26,30,39], - [0,17,26,32],[0,28,34,45],[0,2,23,25]]}, -(31, 5, 2): - {(31,): [[0,1,3,7,15],[0,3,9,14,21],[0,4,5,13,15,]]}, -( 35, 5, 2): - {(35,): [[0,2,8,12,13],[0,3,18,22,27],[0,17,23,32,33], - [0,7,14,21,28],[0,7,14,21,28]]}, -( 51, 5, 2): - {(51,): [[0,1,14,31,35],[0,1,9,23,33],[0,11,16,18,42], - [0,7,13,36,39],[0,4,10,12,15]]}, -( 71, 5, 2): - {(71,): [[1,5,25,54,57],[3,4,15,20,29],[9,12,16,45,60],[27,36,38,48,64], - [2,10,37,43,50],[6,8,30,40,58],[18,19,24,32,49]]}, -( 46, 6, 2): - {(46,): [[0,1,3,11,31,35],[0,1,4,10,23,29],[0,2,7,15,32,41]]}, -( 61, 6, 2): - {(61,): [[12,15,28,34,35,59],[1,13,18,47,51,53], - [8,10,11,21,29,43],[16,20,25,32,40,50]]}, -( 43, 7, 2): - {(43,): [[0,1,11,19,31,38,40],[0,2,10,16,25,38,42]]}, -( 64, 7, 2): - {(64,): [[0,1,2,4,7,28,52],[0,4,9,21,31,39,53],[0,6,15,23,34,41,54]]}, -( 75, 5, 2): - {(5,15): [[(0,0),(1,10),(1,8),(4,1),(4,2)], - [(0,0),(2,5),(2,10),(3,7),(3,13)], - [(0,0),(1,10),(1,2),(4,4),(4,8)], - [(0,0),(2,5),(2,10),(3,14),(3,11)], - [(0,0),(1,4),(1,5),(4,1),(4,8)], - [(0,0),(1,1),(1,5),(4,4),(4,2)], - [(0,0),(2,7),(2,13),(3,1),(3,4)], - [(0,0),(1,0),(2,0),(3,0),(4,0)], - [(0,0),(1,0),(2,0),(3,0),(4,0)]]}, -( 85, 7, 2): - {(85,): [[0,1,11,20,32,35,39],[0,2,6,16,29,50,65], - [0,3,9,27,55,72,80],[0,5,7,30,47,48,59]]}, -( 85, 8, 2): - {(85,): [[24,31,39,50,67,68,70,82],[20,49,51,55,56,60,72,81], - [9,19,29,37,43,56,59,81]]}, -(153, 9, 2): - {(3,3,17): [[(0,0,0),(0,1,0),(0,2,0),(1,0,0),(1,1,0),(1,2,0),(2,0,0),(2,1,0),(2,2,0)], - [(0,0,0),(0,1,0),(0,2,0),(1,0,0),(1,1,0),(1,2,0),(2,0,0),(2,1,0),(2,2,0)], - [(0,0,0),(0,1,1),(0,1,16),(0,2,4),(0,2,13),(1,0,3),(1,0,14),(2,0,5),(2,0,12)], - [(0,0,0),(0,1,2),(0,1,15),(0,2,8),(0,2,9),(1,0,6),(1,0,11),(2,0,10),(2,0,7)], - [(0,0,0),(0,1,3),(0,1,14),(0,2,12),(0,2,5),(1,0,9),(1,0,8),(2,0,15),(2,0,2)], - [(0,0,0),(0,1,6),(0,1,11),(0,2,7),(0,2,10),(1,0,1),(1,0,16),(2,0,13),(2,0,4)]]}, -(181,10, 2): - {(181,): [[1,7,40,42,51,59,113,125,135,151], - [19,22,31,35,36,64,74,133,154,156], - [10,15,34,47,58,65,83,87,161,164], - [12,18,32,52,77,78,142,157,165,172]]}, - -############## -# lambda = 3 # -############## - -( 21, 6, 3): - {(21,): [[0,2,10,15,19,20],[0,3,7,9,10,16]]}, -( 41, 6, 3): - {(41,): [[0,1,10,16,18,37],[0,6,14,17,19,26], - [0,2,20,32,33,36],[0,11,12,28,34,38]]}, -( 51, 6, 3): - {(51,): [[15,17,18,27,34,48],[3,17,30,34,42,45],[9,17,24,33,34,39], - [3,25,41,43,44,48],[3,5,25,29,43,48]]}, -( 61, 6, 3): - {(61,): [[0,1,9,20,58,34],[0,2,7,18,40,55],[0,4,14,19,36,49], - [0,8,11,28,37,38],[0,13,15,16,22,56],[0,26,30,32,44,51]]}, -( 29, 7, 3): - {(29,): [[1,7,16,20,23,24,25],[2,3,11,14,17,19,21]]}, -( 43, 7, 3): - {(43,): [[1,4,11,16,21,35,41],[3,5,12,19,20,33,37],[9,13,14,15,17,25,36]]}, -( 57, 7, 3): - {(57,): [[0,1,11,12,15,35,53],[0,7,17,20,27,29,48], - [0,5,18,26,32,49,51],[0,2,6,9,14,41,42]]}, -( 61,10, 3): - {(61,): [[1,4,18,20,32,35,36,41,42,54],[11,13,14,21,23,28,34,39,43,47]]}, -( 71, 7, 3): - {(71,): [[1,20,30,32,37,45,48],[2,3,19,25,40,60,64],[4,6,9,38,49,50,57], - [5,8,12,18,27,29,43],[10,15,16,24,36,54,58]]}, -( 85, 7, 3): - {(85,): [[0,7,23,27,28,31,71],[0,12,22,41,61,74,79], - [0,6,11,13,38,42,77],[0,1,7,16,19,27,49], - [0,9,26,39,54,56,71],[0,2,3,12,37,53,63]]}, -( 97, 9, 3): - {(97,): [[1,2,25,35,46,58,61,70,90],[3,4,8,38,43,50,69,86,87], - [6,12,16,32,53,55,57,75,82],[9,18,24,26,31,34,37,48,64]]}, -( 49, 9, 3): - {(49,): [[0,1,3,5,9,14,19,25,37],[0,2,12,13,16,19,34,41,42]]}, -(121,10, 3): - {(11,11): [[(0,1),(0,3),(0,4),(0,5),(0,9),(1,8),(3,2),(4,10),(5,7),(9,6)], - [(1,2),(3,6),(4,8),(5,10),(9,7),(10,2),(8,6),(7,8),(6,10),(2,7)], - [(1,7),(3,10),(4,6),(5,2),(9,8),(1,4),(3,1),(4,5),(5,9),(9,3)], - [(10,10),(8,8),(7,7),(6,6),(2,2),(1,0),(3,0),(4,0),(5,0),(9,0)]]}, - -############### -# lambda = 4 # -############### - -( 22, 7, 4): - {(22,): [[0,2,6,8,9,10,13],[0,3,5,6,12,13,17]]}, -( 29, 8, 4): - {(29,): [[0,1,7,16,20,23,24,25],[0,2,3,11,14,17,19,21]]}, -( 71, 8, 4): - {(71,): [[0,1,20,30,32,37,45,48],[0,2,3,19,25,40,60,64], - [0,4,6,9,38,49,50,57],[0,5,8,12,18,27,29,43], - [0,10,15,16,24,36,54,58]]}, -( 43, 8, 4): - {(43,): [[0,1,4,11,16,21,35,41],[0,3,5,12,19,20,33,37], - [0,9,13,14,15,17,25,36]]}, -( 46,10, 4): - {(46,): [[3,7,13,16,23,24,25,28,30,42],[2,10,12,18,25,34,40,43,44,45]]}, -( 55, 9, 4): - {(55,): [[0,4,21,25,26,42,45,53,54],[0,6,8,25,37,39,45,48,52], - [2,5,6,13,15,20,25,39,45]]}, -( 67,12, 4): - {(67,): [[1,8,23,25,28,29,31,37,47,54,55,64], - [3,20,25,32,36,39,44,45,54,55,57,59]]}, - -############## -# lambda = 5 # -############## - -( 13, 5, 5): - {(13,): [[0,1,2,4,8],[0,1,3,6,12],[0,2,5,6,10]]}, -( 17, 5, 5): - {(17,): [[0,1,4,13,16],[0,3,5,12,14],[0,2,8,9,15],[0,6,7,10,11]]}, -( 21, 6, 5): - {(21,): [[0,2,6,12,15,16],[0,3,6,7,11,19], - [0,7,15,16,17,18],[0,2,7,9,14,16]]}, -( 22, 6, 5): - {(22,): [[0,1,2,5,10,13],[0,1,5,6,8,15], - [0,2,3,6,16,18],[0,2,6,11,13,17]]}, -( 28, 6, 5): - {(28,): [[0,4,7,8,16,21],[5,7,8,9,14,20],[7,12,14,16,17,25], - [1,4,7,13,14,24],[2,4,8,16,18,22]]}, -( 33, 5, 5): - {(33,): [[0,2,3,7,25],[0,3,13,14,29],[0,4,5,12,13],[0,2,12,16,26], - [0,3,12,20,31],[3,9,12,15,27],[0,8,13,14,31],[0,2,7,13,29]]}, -( 33, 6, 5): - {(33,): [[0,3,12,17,18,28],[0,2,3,16,28,29],[0,16,20,26,28,30], - [0,2,3,12,16,27],[0,6,20,21,28,30],[0,4,11,15,22,26]]}, -( 37,10, 5): - {(37,): [[0,1,7,9,10,12,16,26,33,34],[0,2,14,15,18,20,24,29,31,32]]}, -( 39, 6,5): - {(39,): [[0,3,4,17,19,32],[0,1,5,12,30,36],[0,3,8,9,25,27],[0,7,10,12,17,21], - [0,16,18,19,27,35],[0,2,18,27,28,33],[0,6,13,19,26,32]]}, -( 45,11, 5): - {(45,): [[1,3,7,10,22,25,30,35,37,38,44],[0,2,3,14,22,26,27,28,31,32,38]]}, -( 46,10, 5): - {(46,): [[0,4,6,11,12,15,24,25,28,42],[0,2,5,7,8,9,14,24,34,35], - [0,2,12,32,40,23,25,35,9,17]]}, -( 55,10, 5): - {(55,): [[0,5,11,15,20,22,25,33,44,45],[3,7,8,10,31,37,39,45,46,49], - [3,7,8,10,31,37,39,45,46,49]]}, -( 67,11, 5): - {(67,): [[1,9,14,15,22,24,25,40,59,62,64],[2,13,18,28,30,44,48,50,51,57,61], - [4,21,26,29,33,35,36,47,55,56,60]]}, -( 73,10, 5): - {(73,): [[0,1,2,4,8,16,32,37,55,64],[0,5,7,10,14,20,28,39,40,56], - [0,25,27,35,49,50,54,61,67,70],[0,11,15,21,22,30,42,44,47,60]]}, - -############### -# lambda >= 6 # -############### - -( 11, 4,6): - {(11,): [[0,1,8,9],[0,2,5,7],[0,1,4,5],[0,2,3,5],[0,4,5,9]]}, - -( 15, 4,6): - {(15,): [[0,1,2,3],[0,2,4,6],[0,4,8,12],[0,8,1,9], - [3,6,9,12],[0,1,5,10],[0,2,5,10]]}, -( 15, 5,6): - {(15,): [[0,1,2,3,6],[0,2,4,7,8],[0,2,4,9,10], - [0,3,6,10,11],[0,3,6,9,12]]}, -( 21, 8,14): - {(21,): [[0,9,10,13,14,15,18,19],[0,1,4,7,9,15,16,18],[0,1,2,4,6,14,15,16], - [0,1,3,4,8,14,16,18],[0,1,4,9,11,12,14,16]]}, -( 21, 10, 9): - {(21,): [[0,1,2,3,4,7,8,11,14,16],[0,6,7,9,11,12,15,16,17,19]]}, -( 22, 8, 8): - {(22,): [[0,1,5,7,13,17,20,21],[0,2,7,11,13,14,16,17],[0,3,4,12,14,15,17,21]]}, -( 22, 8,12): - {(22,): [[1,2,3,5,6,9,15,18], [1,2,3,5,8,9,10,15], - [1,3,4,9,13,18,19,21], [2,4,6,12,13,15,17,1], - [2,4,8,12,13,15,19,1], [2,4,8,16,13,15,19,5]]}, -( 25, 7, 7): - {(5,5): [[(0,0),(0,1),(0,4),(1,1),(1,2),(4,3),(4,4)], - [(0,0),(1,0),(1,3),(2,3),(3,2),(4,0),(4,2)], - [(0,0),(0,2),(0,3),(2,2),(2,4),(3,1),(3,3)], - [(0,0),(1,4),(2,0),(2,1),(3,0),(3,4),(4,1)]]}, -( 29, 8,6): - {(29,): [[0,5,10,11,12,13,16,20],[0,8,10,12,17,22,23,26], - [0,4,5,11,13,23,25,26]]}, -( 34,12, 8): - {(34,): [[0,5,9,14,15,17,20,25,26,27,28,30], - [0,6,7,10,13,17,18,20,22,24,25,26]]}, -( 34,12,10): - {(34,): [[0,2,3,4,8,9,11,13,14,24,27,30], - [0,2,6,7,8,11,13,14,22,25,26,32], - [0,2,10,18,22,32,17,19,27,1,5,15]]}, -( 43,15,10): - {(43,): [[1,3,6,13,18,21,22,25,26,27,33,35,36,38,40], - [9,10,11,13,16,17,19,23,26,27,28,33,35,38,39]]}, -( 45,12, 3): - {(3,3,5): [[(0,0,0),(0,0,1),(0,0,2),(0,2,1),(0,0,3),(0,1,1), - (1,0,0),(1,1,2),(1,2,3),(2,0,0),(2,1,3),(2,2,2)]]}, -( 46,10, 6): - {(46,): [[0,2,11,13,21,22,30,33,34,40],[0,2,6,7,22,23,28,32,35,38], - [0,2,4,7,8,9,12,23,26,41]]}, -( 49,21,10): - {(7,7): [[(0,1),(0,2),(0,4),(1,1),(1,2),(1,4),(2,1),(2,2),(2,4),(3,1),(3,2), - (3,4),(4,1),(4,2),(4,4),(5,1),(5,2),(5,4),(6,1),(6,2),(6,4)], - [(1,0),(1,1),(1,2),(1,4),(2,0),(2,1),(2,2),(2,4),(4,0),(4,1),(4,2), - (4,4),(3,3),(3,5),(3,6),(5,3),(5,5),(5,6),(6,3),(6,5),(6,6)]]}, -( 53,13, 6): - {(53,): [[1,10,13,15,16,24,28,36,42,44,46,47,49], - [2,3,19,20,26,30,31,32,35,39,41,45,48]]}, -( 53,14, 7): - {(53,): [[0,1,10,13,15,16,24,28,36,42,44,46,47,49], - [0,2,3,19,20,26,30,31,32,35,39,41,45,48]]}, -( 61,15, 7): - {(61,): [[0,1,3,4,8,10,13,22,30,35,44,45,46,50,58], - [0,1,3,5,13,18,29,34,35,37,41,43,44,51,55]]}, -( 67,12, 6): - {(67,): [[0,1,9,14,15,22,24,25,40,59,62,64], - [0,2,13,18,28,30,44,48,50,51,57,61], - [0,4,21,26,29,33,35,36,47,55,56,60]]}, - -# a (133,33,8)-cyclic difference set -# see https://dmgordon.org/diffset -(133,33, 8): - {(133,): [[1,5,14,22,25,27,29,32,34,38, - 46,64,65,66,76,78,81,82,84,89, - 92,93,99,103,104,106,107,112,113,122, - 126,128,129]]}, - -# a (144,66,30) non-cyclic difference set in AbelianGroup([2,8,3,3]) -# given in unpublished paper by Kroeger, Miller, Mooney, Shepard and Smith -# see https://dmgordon.org/diffset -(144,66,30): - {(2,8,3,3): [[(0,1,0,0),(0,7,0,2),(0,5,0,1),(0,3,0,0),(0,6,0,1), - (0,1,0,2),(0,4,0,0),(0,2,0,2),(0,6,0,0),(0,1,0,1), - (0,4,0,2),(0,2,0,1),(1,2,2,0),(1,3,2,0),(1,4,2,0), - (1,5,2,0),(1,6,2,0),(1,7,2,0),(0,6,1,2),(0,1,1,0), - (0,4,1,1),(0,3,1,0),(0,1,1,2),(0,4,1,0),(0,7,1,1), - (0,2,1,2),(0,6,1,0),(0,1,1,1),(0,2,1,1),(0,5,1,2), - (1,0,0,0),(1,6,0,2),(1,1,0,0),(1,4,0,1),(1,7,0,2), - (1,2,0,0),(1,5,0,1),(1,0,0,2),(1,3,0,0),(1,1,0,2), - (1,0,0,1),(1,1,0,1),(0,0,2,0),(0,6,2,2),(0,4,2,1), - (0,0,2,2),(0,3,2,0),(0,6,2,1),(0,2,2,2),(0,5,2,0), - (0,0,2,1),(0,4,2,2),(0,7,2,0),(0,2,2,1),(1,0,1,0), - (1,1,1,0),(1,2,1,0),(1,0,1,2),(1,3,1,0),(1,6,1,1), - (1,1,1,2),(1,7,1,1),(1,0,1,1),(1,1,1,1),(1,4,1,2), - (1,5,1,2)]]}, - -# a (320,88,24) non-cyclic difference set in AbelianGroup([4,4,4,5]), -# given in Arasu and Chen, Designs, Codes and Cryptography 2001 -# see https://dmgordon.org/diffset -(320,88,24): - {(4,4,4,5): [[(3,3,3,0),(2,3,2,0),(3,1,3,0),(2,2,3,0),(1,3,3,0), - (3,2,1,0),(2,2,2,0),(2,2,1,0),(2,1,2,0),(0,3,2,0), - (2,0,3,0),(1,1,3,0),(0,2,3,0),(3,0,1,0),(1,2,1,0), - (2,0,2,0),(0,2,2,0),(2,0,1,0),(0,2,1,0),(0,1,2,0), - (0,0,3,0),(1,0,1,0),(0,0,2,0),(0,0,1,0),(3,3,3,1), - (3,3,1,1),(3,0,3,1),(0,3,3,1),(3,0,1,1),(0,3,1,1), - (1,1,2,1),(1,0,2,1),(0,1,2,1),(0,0,3,1),(1,1,0,1), - (0,0,2,1),(1,0,0,1),(0,1,0,1),(0,0,1,1),(0,0,0,1), - (1,1,3,2),(3,1,1,2),(2,3,3,2),(2,2,3,2),(0,3,2,2), - (0,3,1,2),(0,2,1,2),(3,2,2,2),(3,1,2,2),(3,0,3,2), - (2,3,0,2),(2,0,2,2),(1,2,0,2),(1,1,0,2),(1,0,1,2), - (0,0,0,2),(1,1,1,3),(1,3,3,3),(3,2,1,3),(2,2,3,3), - (3,0,0,3),(3,0,3,3),(1,3,0,3),(2,0,1,3),(3,2,2,3), - (2,3,2,3),(0,3,3,3),(1,1,2,3),(0,2,2,3),(2,1,0,3), - (0,1,1,3),(0,0,0,3),(2,0,3,4),(1,1,2,4),(0,2,1,4), - (0,1,3,4),(3,2,3,4),(3,2,2,4),(2,3,2,4),(3,1,3,4), - (3,3,0,4),(2,3,1,4),(1,0,1,4),(2,2,2,4),(1,3,1,4), - (1,0,0,4),(0,1,0,4),(0,0,0,4)]]}, - -# a (901,225,56)-cyclic difference set -# see https://dmgordon.org/diffset -(901,225,56): - {(901,): [[ 0, 1, 5, 9, 12, 13, 14, 16, 22, 25, 41, 43, - 45, 47, 53, 59, 60, 65, 69, 70, 71, 79, 80, 81, - 89, 92, 93,106,108,109,110,114,117,124,125,126, - 133,139,144,147,152,156,159,167,168,169,173,174, - 182,183,192,194,196,198,202,203,205,208,209,212, - 214,215,219,222,223,224,225,226,229,231,232,233, - 235,244,254,256,259,264,265,274,277,286,292,293, - 295,296,300,307,308,313,318,319,325,326,345,350, - 352,355,363,369,371,379,382,387,394,395,397,400, - 401,402,405,407,419,422,423,424,433,445,447,460, - 461,465,467,469,477,484,492,498,502,503,516,523, - 526,529,530,531,533,536,540,543,545,550,559,564, - 570,571,574,577,579,581,583,585,587,596,599,602, - 611,617,618,620,621,622,625,630,634,636,639,641, - 656,658,661,664,665,688,689,691,694,695,706,708, - 711,713,720,721,724,729,735,737,742,746,752,760, - 766,767,772,778,780,786,795,801,813,824,826,827, - 828,835,837,840,843,845,848,849,852,853,859,862, - 863,865,870,874,878,881,886,897,898]]} + ############## + # lambda = 1 # + ############## + (15, 3, 1): {(15,): [[0, 1, 4], [0, 2, 9], [0, 5, 10]]}, + (21, 3, 1): {(21,): [[0, 1, 3], [0, 4, 12], [0, 5, 11], [0, 7, 14]]}, + (21, 5, 1): {(21,): [[0, 1, 4, 14, 16]]}, + (25, 3, 1): {(25,): [[0, 1, 3], [0, 4, 11], [0, 5, 13], [0, 6, 15]]}, + (25, 4, 1): {(5, 5): [[(0, 0), (0, 1), (1, 0), (2, 2)], [(0, 0), (0, 2), (2, 0), (4, 4)]]}, + (27, 3, 1): {(27,): [[0, 1, 3], [0, 4, 11], [0, 5, 15], [0, 6, 14], [0, 9, 18]]}, + (33, 3, 1): {(33,): [[0, 1, 3], [0, 4, 10], [0, 5, 18], [0, 7, 19], [0, 8, 17], [0, 11, 22]]}, + (37, 4, 1): {(37,): [[0, 1, 3, 24], [0, 4, 26, 32], [0, 10, 18, 30]]}, + (39, 3, 1): {(39,): [[0, 1, 3], [0, 4, 18], [0, 5, 27], [0, 6, 16], [0, 7, 15], [0, 9, 20], [0, 13, 26]]}, + (40, 4, 1): {(40,): [[0, 1, 4, 13], [0, 2, 7, 24], [0, 6, 14, 25], [0, 10, 20, 30]]}, + (45, 3, 1): {(45,): [[0, 1, 3], [0, 4, 10], [0, 5, 28], [0, 7, 34], [0, 8, 32], [0, 9, 29], [0, 12, 26], [0, 15, 30]]}, + (45, 5, 1): {(3, 3, 5): [[(0, 1, 0), (0, 2, 0), (1, 0, 2), (2, 0, 2), (0, 0, 1)], [(2, 1, 0), (1, 2, 0), (2, 2, 2), (1, 1, 2), (0, 0, 1)], [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 0, 4)]]}, + (49, 3, 1): {(49,): [[0, 1, 3], [0, 4, 9], [0, 6, 17], [0, 7, 23], [0, 8, 30], [0, 10, 31], [0, 12, 36], [0, 14, 34]]}, + (49, 4, 1): { + (49,): [ + [ + 0, + 1, + 3, + 8, + ], + [0, 4, 18, 29], + [0, 6, 21, 33], + [0, 9, 19, 32], + ] + }, + (51, 3, 1): {(51,): [[0, 1, 3], [0, 4, 9], [0, 6, 25], [0, 7, 35], [0, 8, 22], [0, 10, 21], [0, 12, 27], [0, 13, 31], [0, 17, 34]]}, + (52, 4, 1): { + (52,): [ + [ + 0, + 1, + 3, + 7, + ], + [0, 5, 19, 35], + [0, 8, 20, 31], + [0, 9, 24, 34], + [0, 13, 26, 39], + ] + }, + (55, 3, 1): {(55,): [[0, 1, 3], [0, 4, 9], [0, 6, 16], [0, 7, 32], [0, 8, 29], [0, 11, 42], [0, 12, 27], [0, 14, 36], [0, 17, 37]]}, + (57, 3, 1): {(57,): [[0, 1, 3], [0, 4, 9], [0, 6, 13], [0, 8, 26], [0, 10, 33], [0, 11, 32], [0, 12, 40], [0, 14, 41], [0, 15, 35], [0, 19, 38]]}, + (63, 3, 1): {(63,): [[0, 1, 3], [0, 4, 9], [0, 6, 13], [0, 8, 25], [0, 10, 41], [0, 11, 44], [0, 12, 36], [0, 14, 37], [0, 15, 43], [0, 16, 34], [0, 21, 42]]}, + (64, 4, 1): { + (64,): [ + [ + 0, + 1, + 3, + 7, + ], + [0, 5, 18, 47], + [0, 8, 33, 44], + [0, 9, 19, 43], + [0, 12, 26, 49], + [0, 16, 32, 48], + ] + }, + (65, 5, 1): {(65,): [[0, 1, 3, 31, 45], [0, 4, 10, 19, 57], [0, 5, 16, 41, 48], [0, 13, 26, 39, 52]]}, + (69, 3, 1): {(69,): [[0, 1, 3], [0, 4, 9], [0, 6, 13], [0, 8, 24], [0, 10, 38], [0, 11, 47], [0, 12, 32], [0, 14, 40], [0, 15, 50], [0, 17, 42], [0, 18, 39], [0, 23, 46]]}, + (75, 3, 1): {(75,): [[0, 1, 67], [0, 2, 47], [0, 3, 41], [0, 4, 69], [0, 5, 68], [0, 11, 55], [0, 13, 61], [0, 15, 33], [0, 16, 52], [0, 17, 43], [0, 19, 40], [0, 22, 51], [0, 25, 50]]}, + (76, 4, 1): {(76,): [[0, 1, 7, 22], [0, 2, 11, 45], [0, 3, 59, 71], [0, 4, 32, 50], [0, 10, 37, 51], [0, 13, 36, 60], [0, 19, 38, 57]]}, + (81, 3, 1): {(81,): [[0, 1, 39], [0, 2, 58], [0, 3, 34], [0, 4, 21], [0, 5, 67], [0, 6, 15], [0, 7, 36], [0, 8, 59], [0, 10, 63], [0, 11, 37], [0, 12, 61], [0, 13, 48], [0, 16, 40], [0, 27, 54]]}, + (81, 5, 1): {(81,): [[0, 1, 5, 12, 26], [0, 2, 10, 40, 64], [0, 3, 18, 47, 53], [0, 9, 32, 48, 68]]}, + (85, 4, 1): { + (85,): [ + [0, 2, 41, 42], + [0, 17, 32, 38], + [0, 18, 27, 37], + [0, 13, 29, 36], + [0, 11, 31, 35], + [ + 0, + 12, + 26, + 34, + ], + [0, 5, 30, 33], + ] + }, + (91, 6, 1): {(91,): [[0, 1, 3, 7, 25, 38], [0, 16, 21, 36, 48, 62], [0, 30, 40, 63, 74, 82]]}, + (91, 7, 1): {(91,): [[8, 9, 14, 25, 58, 81, 85], [5, 33, 35, 42, 45, 67, 88], [4, 17, 30, 43, 56, 69, 82]]}, # from the La Jolla covering repository, attributed to Jan de Heer and Steve Muir + (121, 5, 1): {(121,): [[0, 14, 26, 51, 60], [0, 15, 31, 55, 59], [0, 10, 23, 52, 58], [0, 3, 36, 56, 57], [0, 7, 18, 45, 50], [0, 8, 30, 47, 49]]}, + (121, 6, 1): {(11, 11): [[(0, 0), (0, 3), (0, 4), (1, 1), (1, 7), (4, 6)], [(0, 0), (0, 2), (2, 5), (4, 7), (6, 4), (8, 0)], [(0, 0), (1, 5), (2, 0), (4, 1), (6, 0), (7, 2)], [(0, 0), (1, 0), (3, 9), (4, 8), (6, 1), (9, 5)]]}, + (141, 5, 1): {(141,): [[0, 33, 60, 92, 97], [0, 3, 45, 88, 110], [0, 18, 39, 68, 139], [0, 12, 67, 75, 113], [0, 1, 15, 84, 94], [0, 7, 11, 24, 30], [0, 36, 90, 116, 125]]}, + (161, 5, 1): {(161,): [[0, 19, 34, 73, 80], [0, 16, 44, 71, 79], [0, 12, 33, 74, 78], [0, 13, 30, 72, 77], [0, 11, 36, 67, 76], [0, 18, 32, 69, 75], [0, 10, 48, 68, 70], [0, 3, 29, 52, 53]]}, + (175, 7, 1): {(7, 5, 5): [[(0, 0, 0), (1, 0, 0), (2, 0, 0), (3, 0, 0), (4, 0, 0), (5, 0, 0), (6, 0, 0)], [(0, 0, 0), (1, 1, 3), (1, 4, 2), (2, 2, 2), (2, 3, 3), (4, 2, 0), (4, 3, 0)], [(0, 0, 0), (1, 3, 4), (1, 2, 1), (2, 2, 3), (2, 3, 2), (4, 0, 2), (4, 0, 3)], [(0, 0, 0), (1, 1, 2), (1, 4, 3), (2, 1, 1), (2, 4, 4), (4, 0, 1), (4, 0, 4)], [(0, 0, 0), (1, 3, 1), (1, 2, 4), (2, 4, 1), (2, 1, 4), (4, 1, 0), (4, 4, 0)]]}, + (201, 5, 1): {(201,): [[0, 1, 45, 98, 100], [0, 3, 32, 65, 89], [0, 4, 54, 70, 75], [0, 6, 49, 69, 91], [0, 7, 58, 81, 95], [0, 8, 34, 72, 90], [0, 9, 36, 77, 96], [0, 10, 35, 83, 94], [0, 12, 40, 79, 92], [0, 15, 46, 76, 93]]}, + (217, 7, 1): {(217,): [[0, 1, 37, 67, 88, 92, 149], [0, 15, 18, 65, 78, 121, 137], [0, 8, 53, 79, 85, 102, 107], [0, 11, 86, 100, 120, 144, 190], [0, 29, 64, 165, 198, 205, 207], [0, 31, 62, 93, 124, 155, 186]]}, + (221, 5, 1): {(221,): [[0, 1, 24, 61, 116], [0, 3, 46, 65, 113], [0, 4, 73, 89, 130], [0, 5, 77, 122, 124], [0, 6, 39, 50, 118], [0, 7, 66, 81, 94], [0, 8, 38, 64, 139], [0, 9, 29, 80, 107], [0, 10, 35, 93, 135], [0, 12, 34, 52, 88], [0, 14, 31, 63, 84]]}, + (259, 7, 1): {(7, 37): [[(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0)], [(0, 0), (0, 1), (0, 6), (1, 4), (2, 19), (3, 25), (6, 26)], [(0, 0), (0, 10), (0, 23), (2, 3), (4, 5), (5, 1), (6, 28)], [(0, 0), (0, 8), (0, 26), (1, 13), (3, 10), (4, 30), (5, 21)], [(0, 0), (0, 4), (1, 25), (1, 34), (2, 33), (2, 35), (4, 10)], [(0, 0), (0, 3), (1, 26), (2, 7), (2, 28), (4, 17), (4, 34)], [(0, 0), (0, 30), (1, 7), (1, 22), (2, 1), (4, 21), (4, 33)]]}, # the following one is lemma 2.2 in Abel "Some new BIBDs with block size 7" + ############## + # lambda = 2 # + ############## + (16, 3, 2): {(16,): [[0, 1, 2], [0, 2, 8], [0, 3, 7], [0, 4, 7], [0, 5, 10]]}, + (28, 3, 2): {(28,): [[0, 1, 12], [0, 2, 11], [0, 2, 12], [0, 3, 7], [0, 3, 13], [0, 4, 9], [0, 5, 13], [0, 6, 7], [0, 6, 14]]}, + (40, 3, 2): {(40,): [[0, 1, 4], [0, 1, 16], [0, 2, 7], [0, 2, 9], [0, 3, 17], [0, 4, 17], [0, 5, 19], [0, 6, 16], [0, 6, 18], [0, 8, 18], [0, 8, 19], [0, 9, 20], [0, 12, 25]]}, + (19, 4, 2): {(19,): [[0, 1, 3, 12], [0, 1, 5, 13], [0, 4, 6, 9]]}, + (21, 4, 3): {(21,): [[0, 2, 3, 7], [0, 3, 5, 9], [0, 1, 7, 11], [0, 2, 8, 11], [0, 1, 9, 14]]}, + (22, 4, 2): {(22,): [[0, 4, 16, 17], [0, 12, 14, 21], [0, 14, 16, 19], [0, 4, 11, 15]]}, + (31, 4, 2): {(31,): [[0, 1, 8, 11], [0, 1, 13, 17], [0, 2, 11, 14], [0, 5, 7, 13], [0, 5, 9, 15]]}, + (34, 4, 2): {(34,): [[0, 1, 22, 24], [0, 1, 19, 25], [0, 2, 6, 29], [0, 4, 7, 20], [0, 5, 8, 20], [0, 8, 17, 25]]}, + (43, 4, 2): { + (43,): [ + [0, 1, 6, 36], + [0, 3, 18, 22], + [0, 9, 11, 23], + [0, 10, 12, 26], + [0, 26, 27, 33], + [0, 13, 35, 38], + [ + 0, + 19, + 28, + 39, + ], + ] + }, + (46, 4, 2): {(46,): [[0, 2, 7, 10], [0, 4, 19, 32], [0, 10, 34, 35], [0, 5, 8, 24], [0, 26, 30, 39], [0, 17, 26, 32], [0, 28, 34, 45], [0, 2, 23, 25]]}, + (31, 5, 2): { + (31,): [ + [0, 1, 3, 7, 15], + [0, 3, 9, 14, 21], + [ + 0, + 4, + 5, + 13, + 15, + ], + ] + }, + (35, 5, 2): {(35,): [[0, 2, 8, 12, 13], [0, 3, 18, 22, 27], [0, 17, 23, 32, 33], [0, 7, 14, 21, 28], [0, 7, 14, 21, 28]]}, + (51, 5, 2): {(51,): [[0, 1, 14, 31, 35], [0, 1, 9, 23, 33], [0, 11, 16, 18, 42], [0, 7, 13, 36, 39], [0, 4, 10, 12, 15]]}, + (71, 5, 2): {(71,): [[1, 5, 25, 54, 57], [3, 4, 15, 20, 29], [9, 12, 16, 45, 60], [27, 36, 38, 48, 64], [2, 10, 37, 43, 50], [6, 8, 30, 40, 58], [18, 19, 24, 32, 49]]}, + (46, 6, 2): {(46,): [[0, 1, 3, 11, 31, 35], [0, 1, 4, 10, 23, 29], [0, 2, 7, 15, 32, 41]]}, + (61, 6, 2): {(61,): [[12, 15, 28, 34, 35, 59], [1, 13, 18, 47, 51, 53], [8, 10, 11, 21, 29, 43], [16, 20, 25, 32, 40, 50]]}, + (43, 7, 2): {(43,): [[0, 1, 11, 19, 31, 38, 40], [0, 2, 10, 16, 25, 38, 42]]}, + (64, 7, 2): {(64,): [[0, 1, 2, 4, 7, 28, 52], [0, 4, 9, 21, 31, 39, 53], [0, 6, 15, 23, 34, 41, 54]]}, + (75, 5, 2): {(5, 15): [[(0, 0), (1, 10), (1, 8), (4, 1), (4, 2)], [(0, 0), (2, 5), (2, 10), (3, 7), (3, 13)], [(0, 0), (1, 10), (1, 2), (4, 4), (4, 8)], [(0, 0), (2, 5), (2, 10), (3, 14), (3, 11)], [(0, 0), (1, 4), (1, 5), (4, 1), (4, 8)], [(0, 0), (1, 1), (1, 5), (4, 4), (4, 2)], [(0, 0), (2, 7), (2, 13), (3, 1), (3, 4)], [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0)], [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0)]]}, + (85, 7, 2): {(85,): [[0, 1, 11, 20, 32, 35, 39], [0, 2, 6, 16, 29, 50, 65], [0, 3, 9, 27, 55, 72, 80], [0, 5, 7, 30, 47, 48, 59]]}, + (85, 8, 2): {(85,): [[24, 31, 39, 50, 67, 68, 70, 82], [20, 49, 51, 55, 56, 60, 72, 81], [9, 19, 29, 37, 43, 56, 59, 81]]}, + (153, 9, 2): {(3, 3, 17): [[(0, 0, 0), (0, 1, 0), (0, 2, 0), (1, 0, 0), (1, 1, 0), (1, 2, 0), (2, 0, 0), (2, 1, 0), (2, 2, 0)], [(0, 0, 0), (0, 1, 0), (0, 2, 0), (1, 0, 0), (1, 1, 0), (1, 2, 0), (2, 0, 0), (2, 1, 0), (2, 2, 0)], [(0, 0, 0), (0, 1, 1), (0, 1, 16), (0, 2, 4), (0, 2, 13), (1, 0, 3), (1, 0, 14), (2, 0, 5), (2, 0, 12)], [(0, 0, 0), (0, 1, 2), (0, 1, 15), (0, 2, 8), (0, 2, 9), (1, 0, 6), (1, 0, 11), (2, 0, 10), (2, 0, 7)], [(0, 0, 0), (0, 1, 3), (0, 1, 14), (0, 2, 12), (0, 2, 5), (1, 0, 9), (1, 0, 8), (2, 0, 15), (2, 0, 2)], [(0, 0, 0), (0, 1, 6), (0, 1, 11), (0, 2, 7), (0, 2, 10), (1, 0, 1), (1, 0, 16), (2, 0, 13), (2, 0, 4)]]}, + (181, 10, 2): {(181,): [[1, 7, 40, 42, 51, 59, 113, 125, 135, 151], [19, 22, 31, 35, 36, 64, 74, 133, 154, 156], [10, 15, 34, 47, 58, 65, 83, 87, 161, 164], [12, 18, 32, 52, 77, 78, 142, 157, 165, 172]]}, + ############## + # lambda = 3 # + ############## + (21, 6, 3): {(21,): [[0, 2, 10, 15, 19, 20], [0, 3, 7, 9, 10, 16]]}, + (41, 6, 3): {(41,): [[0, 1, 10, 16, 18, 37], [0, 6, 14, 17, 19, 26], [0, 2, 20, 32, 33, 36], [0, 11, 12, 28, 34, 38]]}, + (51, 6, 3): {(51,): [[15, 17, 18, 27, 34, 48], [3, 17, 30, 34, 42, 45], [9, 17, 24, 33, 34, 39], [3, 25, 41, 43, 44, 48], [3, 5, 25, 29, 43, 48]]}, + (61, 6, 3): {(61,): [[0, 1, 9, 20, 58, 34], [0, 2, 7, 18, 40, 55], [0, 4, 14, 19, 36, 49], [0, 8, 11, 28, 37, 38], [0, 13, 15, 16, 22, 56], [0, 26, 30, 32, 44, 51]]}, + (29, 7, 3): {(29,): [[1, 7, 16, 20, 23, 24, 25], [2, 3, 11, 14, 17, 19, 21]]}, + (43, 7, 3): {(43,): [[1, 4, 11, 16, 21, 35, 41], [3, 5, 12, 19, 20, 33, 37], [9, 13, 14, 15, 17, 25, 36]]}, + (57, 7, 3): {(57,): [[0, 1, 11, 12, 15, 35, 53], [0, 7, 17, 20, 27, 29, 48], [0, 5, 18, 26, 32, 49, 51], [0, 2, 6, 9, 14, 41, 42]]}, + (61, 10, 3): {(61,): [[1, 4, 18, 20, 32, 35, 36, 41, 42, 54], [11, 13, 14, 21, 23, 28, 34, 39, 43, 47]]}, + (71, 7, 3): {(71,): [[1, 20, 30, 32, 37, 45, 48], [2, 3, 19, 25, 40, 60, 64], [4, 6, 9, 38, 49, 50, 57], [5, 8, 12, 18, 27, 29, 43], [10, 15, 16, 24, 36, 54, 58]]}, + (85, 7, 3): {(85,): [[0, 7, 23, 27, 28, 31, 71], [0, 12, 22, 41, 61, 74, 79], [0, 6, 11, 13, 38, 42, 77], [0, 1, 7, 16, 19, 27, 49], [0, 9, 26, 39, 54, 56, 71], [0, 2, 3, 12, 37, 53, 63]]}, + (97, 9, 3): {(97,): [[1, 2, 25, 35, 46, 58, 61, 70, 90], [3, 4, 8, 38, 43, 50, 69, 86, 87], [6, 12, 16, 32, 53, 55, 57, 75, 82], [9, 18, 24, 26, 31, 34, 37, 48, 64]]}, + (49, 9, 3): {(49,): [[0, 1, 3, 5, 9, 14, 19, 25, 37], [0, 2, 12, 13, 16, 19, 34, 41, 42]]}, + (121, 10, 3): {(11, 11): [[(0, 1), (0, 3), (0, 4), (0, 5), (0, 9), (1, 8), (3, 2), (4, 10), (5, 7), (9, 6)], [(1, 2), (3, 6), (4, 8), (5, 10), (9, 7), (10, 2), (8, 6), (7, 8), (6, 10), (2, 7)], [(1, 7), (3, 10), (4, 6), (5, 2), (9, 8), (1, 4), (3, 1), (4, 5), (5, 9), (9, 3)], [(10, 10), (8, 8), (7, 7), (6, 6), (2, 2), (1, 0), (3, 0), (4, 0), (5, 0), (9, 0)]]}, + ############### + # lambda = 4 # + ############### + (22, 7, 4): {(22,): [[0, 2, 6, 8, 9, 10, 13], [0, 3, 5, 6, 12, 13, 17]]}, + (29, 8, 4): {(29,): [[0, 1, 7, 16, 20, 23, 24, 25], [0, 2, 3, 11, 14, 17, 19, 21]]}, + (71, 8, 4): {(71,): [[0, 1, 20, 30, 32, 37, 45, 48], [0, 2, 3, 19, 25, 40, 60, 64], [0, 4, 6, 9, 38, 49, 50, 57], [0, 5, 8, 12, 18, 27, 29, 43], [0, 10, 15, 16, 24, 36, 54, 58]]}, + (43, 8, 4): {(43,): [[0, 1, 4, 11, 16, 21, 35, 41], [0, 3, 5, 12, 19, 20, 33, 37], [0, 9, 13, 14, 15, 17, 25, 36]]}, + (46, 10, 4): {(46,): [[3, 7, 13, 16, 23, 24, 25, 28, 30, 42], [2, 10, 12, 18, 25, 34, 40, 43, 44, 45]]}, + (55, 9, 4): {(55,): [[0, 4, 21, 25, 26, 42, 45, 53, 54], [0, 6, 8, 25, 37, 39, 45, 48, 52], [2, 5, 6, 13, 15, 20, 25, 39, 45]]}, + (67, 12, 4): {(67,): [[1, 8, 23, 25, 28, 29, 31, 37, 47, 54, 55, 64], [3, 20, 25, 32, 36, 39, 44, 45, 54, 55, 57, 59]]}, + ############## + # lambda = 5 # + ############## + (13, 5, 5): {(13,): [[0, 1, 2, 4, 8], [0, 1, 3, 6, 12], [0, 2, 5, 6, 10]]}, + (17, 5, 5): {(17,): [[0, 1, 4, 13, 16], [0, 3, 5, 12, 14], [0, 2, 8, 9, 15], [0, 6, 7, 10, 11]]}, + (21, 6, 5): {(21,): [[0, 2, 6, 12, 15, 16], [0, 3, 6, 7, 11, 19], [0, 7, 15, 16, 17, 18], [0, 2, 7, 9, 14, 16]]}, + (22, 6, 5): {(22,): [[0, 1, 2, 5, 10, 13], [0, 1, 5, 6, 8, 15], [0, 2, 3, 6, 16, 18], [0, 2, 6, 11, 13, 17]]}, + (28, 6, 5): {(28,): [[0, 4, 7, 8, 16, 21], [5, 7, 8, 9, 14, 20], [7, 12, 14, 16, 17, 25], [1, 4, 7, 13, 14, 24], [2, 4, 8, 16, 18, 22]]}, + (33, 5, 5): {(33,): [[0, 2, 3, 7, 25], [0, 3, 13, 14, 29], [0, 4, 5, 12, 13], [0, 2, 12, 16, 26], [0, 3, 12, 20, 31], [3, 9, 12, 15, 27], [0, 8, 13, 14, 31], [0, 2, 7, 13, 29]]}, + (33, 6, 5): {(33,): [[0, 3, 12, 17, 18, 28], [0, 2, 3, 16, 28, 29], [0, 16, 20, 26, 28, 30], [0, 2, 3, 12, 16, 27], [0, 6, 20, 21, 28, 30], [0, 4, 11, 15, 22, 26]]}, + (37, 10, 5): {(37,): [[0, 1, 7, 9, 10, 12, 16, 26, 33, 34], [0, 2, 14, 15, 18, 20, 24, 29, 31, 32]]}, + (39, 6, 5): {(39,): [[0, 3, 4, 17, 19, 32], [0, 1, 5, 12, 30, 36], [0, 3, 8, 9, 25, 27], [0, 7, 10, 12, 17, 21], [0, 16, 18, 19, 27, 35], [0, 2, 18, 27, 28, 33], [0, 6, 13, 19, 26, 32]]}, + (45, 11, 5): {(45,): [[1, 3, 7, 10, 22, 25, 30, 35, 37, 38, 44], [0, 2, 3, 14, 22, 26, 27, 28, 31, 32, 38]]}, + (46, 10, 5): {(46,): [[0, 4, 6, 11, 12, 15, 24, 25, 28, 42], [0, 2, 5, 7, 8, 9, 14, 24, 34, 35], [0, 2, 12, 32, 40, 23, 25, 35, 9, 17]]}, + (55, 10, 5): {(55,): [[0, 5, 11, 15, 20, 22, 25, 33, 44, 45], [3, 7, 8, 10, 31, 37, 39, 45, 46, 49], [3, 7, 8, 10, 31, 37, 39, 45, 46, 49]]}, + (67, 11, 5): {(67,): [[1, 9, 14, 15, 22, 24, 25, 40, 59, 62, 64], [2, 13, 18, 28, 30, 44, 48, 50, 51, 57, 61], [4, 21, 26, 29, 33, 35, 36, 47, 55, 56, 60]]}, + (73, 10, 5): {(73,): [[0, 1, 2, 4, 8, 16, 32, 37, 55, 64], [0, 5, 7, 10, 14, 20, 28, 39, 40, 56], [0, 25, 27, 35, 49, 50, 54, 61, 67, 70], [0, 11, 15, 21, 22, 30, 42, 44, 47, 60]]}, + ############### + # lambda >= 6 # + ############### + (11, 4, 6): {(11,): [[0, 1, 8, 9], [0, 2, 5, 7], [0, 1, 4, 5], [0, 2, 3, 5], [0, 4, 5, 9]]}, + (15, 4, 6): {(15,): [[0, 1, 2, 3], [0, 2, 4, 6], [0, 4, 8, 12], [0, 8, 1, 9], [3, 6, 9, 12], [0, 1, 5, 10], [0, 2, 5, 10]]}, + (15, 5, 6): {(15,): [[0, 1, 2, 3, 6], [0, 2, 4, 7, 8], [0, 2, 4, 9, 10], [0, 3, 6, 10, 11], [0, 3, 6, 9, 12]]}, + (21, 8, 14): {(21,): [[0, 9, 10, 13, 14, 15, 18, 19], [0, 1, 4, 7, 9, 15, 16, 18], [0, 1, 2, 4, 6, 14, 15, 16], [0, 1, 3, 4, 8, 14, 16, 18], [0, 1, 4, 9, 11, 12, 14, 16]]}, + (21, 10, 9): {(21,): [[0, 1, 2, 3, 4, 7, 8, 11, 14, 16], [0, 6, 7, 9, 11, 12, 15, 16, 17, 19]]}, + (22, 8, 8): {(22,): [[0, 1, 5, 7, 13, 17, 20, 21], [0, 2, 7, 11, 13, 14, 16, 17], [0, 3, 4, 12, 14, 15, 17, 21]]}, + (22, 8, 12): {(22,): [[1, 2, 3, 5, 6, 9, 15, 18], [1, 2, 3, 5, 8, 9, 10, 15], [1, 3, 4, 9, 13, 18, 19, 21], [2, 4, 6, 12, 13, 15, 17, 1], [2, 4, 8, 12, 13, 15, 19, 1], [2, 4, 8, 16, 13, 15, 19, 5]]}, + (25, 7, 7): {(5, 5): [[(0, 0), (0, 1), (0, 4), (1, 1), (1, 2), (4, 3), (4, 4)], [(0, 0), (1, 0), (1, 3), (2, 3), (3, 2), (4, 0), (4, 2)], [(0, 0), (0, 2), (0, 3), (2, 2), (2, 4), (3, 1), (3, 3)], [(0, 0), (1, 4), (2, 0), (2, 1), (3, 0), (3, 4), (4, 1)]]}, + (29, 8, 6): {(29,): [[0, 5, 10, 11, 12, 13, 16, 20], [0, 8, 10, 12, 17, 22, 23, 26], [0, 4, 5, 11, 13, 23, 25, 26]]}, + (34, 12, 8): {(34,): [[0, 5, 9, 14, 15, 17, 20, 25, 26, 27, 28, 30], [0, 6, 7, 10, 13, 17, 18, 20, 22, 24, 25, 26]]}, + (34, 12, 10): {(34,): [[0, 2, 3, 4, 8, 9, 11, 13, 14, 24, 27, 30], [0, 2, 6, 7, 8, 11, 13, 14, 22, 25, 26, 32], [0, 2, 10, 18, 22, 32, 17, 19, 27, 1, 5, 15]]}, + (43, 15, 10): {(43,): [[1, 3, 6, 13, 18, 21, 22, 25, 26, 27, 33, 35, 36, 38, 40], [9, 10, 11, 13, 16, 17, 19, 23, 26, 27, 28, 33, 35, 38, 39]]}, + (45, 12, 3): {(3, 3, 5): [[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 2, 1), (0, 0, 3), (0, 1, 1), (1, 0, 0), (1, 1, 2), (1, 2, 3), (2, 0, 0), (2, 1, 3), (2, 2, 2)]]}, + (46, 10, 6): {(46,): [[0, 2, 11, 13, 21, 22, 30, 33, 34, 40], [0, 2, 6, 7, 22, 23, 28, 32, 35, 38], [0, 2, 4, 7, 8, 9, 12, 23, 26, 41]]}, + (49, 21, 10): {(7, 7): [[(0, 1), (0, 2), (0, 4), (1, 1), (1, 2), (1, 4), (2, 1), (2, 2), (2, 4), (3, 1), (3, 2), (3, 4), (4, 1), (4, 2), (4, 4), (5, 1), (5, 2), (5, 4), (6, 1), (6, 2), (6, 4)], [(1, 0), (1, 1), (1, 2), (1, 4), (2, 0), (2, 1), (2, 2), (2, 4), (4, 0), (4, 1), (4, 2), (4, 4), (3, 3), (3, 5), (3, 6), (5, 3), (5, 5), (5, 6), (6, 3), (6, 5), (6, 6)]]}, + (53, 13, 6): {(53,): [[1, 10, 13, 15, 16, 24, 28, 36, 42, 44, 46, 47, 49], [2, 3, 19, 20, 26, 30, 31, 32, 35, 39, 41, 45, 48]]}, + (53, 14, 7): {(53,): [[0, 1, 10, 13, 15, 16, 24, 28, 36, 42, 44, 46, 47, 49], [0, 2, 3, 19, 20, 26, 30, 31, 32, 35, 39, 41, 45, 48]]}, + (61, 15, 7): {(61,): [[0, 1, 3, 4, 8, 10, 13, 22, 30, 35, 44, 45, 46, 50, 58], [0, 1, 3, 5, 13, 18, 29, 34, 35, 37, 41, 43, 44, 51, 55]]}, + (67, 12, 6): {(67,): [[0, 1, 9, 14, 15, 22, 24, 25, 40, 59, 62, 64], [0, 2, 13, 18, 28, 30, 44, 48, 50, 51, 57, 61], [0, 4, 21, 26, 29, 33, 35, 36, 47, 55, 56, 60]]}, + # a (133,33,8)-cyclic difference set + # see https://dmgordon.org/diffset + (133, 33, 8): {(133,): [[1, 5, 14, 22, 25, 27, 29, 32, 34, 38, 46, 64, 65, 66, 76, 78, 81, 82, 84, 89, 92, 93, 99, 103, 104, 106, 107, 112, 113, 122, 126, 128, 129]]}, + # a (144,66,30) non-cyclic difference set in AbelianGroup([2,8,3,3]) + # given in unpublished paper by Kroeger, Miller, Mooney, Shepard and Smith + # see https://dmgordon.org/diffset + (144, 66, 30): {(2, 8, 3, 3): [[(0, 1, 0, 0), (0, 7, 0, 2), (0, 5, 0, 1), (0, 3, 0, 0), (0, 6, 0, 1), (0, 1, 0, 2), (0, 4, 0, 0), (0, 2, 0, 2), (0, 6, 0, 0), (0, 1, 0, 1), (0, 4, 0, 2), (0, 2, 0, 1), (1, 2, 2, 0), (1, 3, 2, 0), (1, 4, 2, 0), (1, 5, 2, 0), (1, 6, 2, 0), (1, 7, 2, 0), (0, 6, 1, 2), (0, 1, 1, 0), (0, 4, 1, 1), (0, 3, 1, 0), (0, 1, 1, 2), (0, 4, 1, 0), (0, 7, 1, 1), (0, 2, 1, 2), (0, 6, 1, 0), (0, 1, 1, 1), (0, 2, 1, 1), (0, 5, 1, 2), (1, 0, 0, 0), (1, 6, 0, 2), (1, 1, 0, 0), (1, 4, 0, 1), (1, 7, 0, 2), (1, 2, 0, 0), (1, 5, 0, 1), (1, 0, 0, 2), (1, 3, 0, 0), (1, 1, 0, 2), (1, 0, 0, 1), (1, 1, 0, 1), (0, 0, 2, 0), (0, 6, 2, 2), (0, 4, 2, 1), (0, 0, 2, 2), (0, 3, 2, 0), (0, 6, 2, 1), (0, 2, 2, 2), (0, 5, 2, 0), (0, 0, 2, 1), (0, 4, 2, 2), (0, 7, 2, 0), (0, 2, 2, 1), (1, 0, 1, 0), (1, 1, 1, 0), (1, 2, 1, 0), (1, 0, 1, 2), (1, 3, 1, 0), (1, 6, 1, 1), (1, 1, 1, 2), (1, 7, 1, 1), (1, 0, 1, 1), (1, 1, 1, 1), (1, 4, 1, 2), (1, 5, 1, 2)]]}, + # a (320,88,24) non-cyclic difference set in AbelianGroup([4,4,4,5]), + # given in Arasu and Chen, Designs, Codes and Cryptography 2001 + # see https://dmgordon.org/diffset + (320, 88, 24): { + (4, 4, 4, 5): [ + [ + (3, 3, 3, 0), + (2, 3, 2, 0), + (3, 1, 3, 0), + (2, 2, 3, 0), + (1, 3, 3, 0), + (3, 2, 1, 0), + (2, 2, 2, 0), + (2, 2, 1, 0), + (2, 1, 2, 0), + (0, 3, 2, 0), + (2, 0, 3, 0), + (1, 1, 3, 0), + (0, 2, 3, 0), + (3, 0, 1, 0), + (1, 2, 1, 0), + (2, 0, 2, 0), + (0, 2, 2, 0), + (2, 0, 1, 0), + (0, 2, 1, 0), + (0, 1, 2, 0), + (0, 0, 3, 0), + (1, 0, 1, 0), + (0, 0, 2, 0), + (0, 0, 1, 0), + (3, 3, 3, 1), + (3, 3, 1, 1), + (3, 0, 3, 1), + (0, 3, 3, 1), + (3, 0, 1, 1), + (0, 3, 1, 1), + (1, 1, 2, 1), + (1, 0, 2, 1), + (0, 1, 2, 1), + (0, 0, 3, 1), + (1, 1, 0, 1), + (0, 0, 2, 1), + (1, 0, 0, 1), + (0, 1, 0, 1), + (0, 0, 1, 1), + (0, 0, 0, 1), + (1, 1, 3, 2), + (3, 1, 1, 2), + (2, 3, 3, 2), + (2, 2, 3, 2), + (0, 3, 2, 2), + (0, 3, 1, 2), + (0, 2, 1, 2), + (3, 2, 2, 2), + (3, 1, 2, 2), + (3, 0, 3, 2), + (2, 3, 0, 2), + (2, 0, 2, 2), + (1, 2, 0, 2), + (1, 1, 0, 2), + (1, 0, 1, 2), + (0, 0, 0, 2), + (1, 1, 1, 3), + (1, 3, 3, 3), + (3, 2, 1, 3), + (2, 2, 3, 3), + (3, 0, 0, 3), + (3, 0, 3, 3), + (1, 3, 0, 3), + (2, 0, 1, 3), + (3, 2, 2, 3), + (2, 3, 2, 3), + (0, 3, 3, 3), + (1, 1, 2, 3), + (0, 2, 2, 3), + (2, 1, 0, 3), + (0, 1, 1, 3), + (0, 0, 0, 3), + (2, 0, 3, 4), + (1, 1, 2, 4), + (0, 2, 1, 4), + (0, 1, 3, 4), + (3, 2, 3, 4), + (3, 2, 2, 4), + (2, 3, 2, 4), + (3, 1, 3, 4), + (3, 3, 0, 4), + (2, 3, 1, 4), + (1, 0, 1, 4), + (2, 2, 2, 4), + (1, 3, 1, 4), + (1, 0, 0, 4), + (0, 1, 0, 4), + (0, 0, 0, 4), + ] + ] + }, + # a (901,225,56)-cyclic difference set + # see https://dmgordon.org/diffset + (901, 225, 56): { + (901,): [ + [ + 0, + 1, + 5, + 9, + 12, + 13, + 14, + 16, + 22, + 25, + 41, + 43, + 45, + 47, + 53, + 59, + 60, + 65, + 69, + 70, + 71, + 79, + 80, + 81, + 89, + 92, + 93, + 106, + 108, + 109, + 110, + 114, + 117, + 124, + 125, + 126, + 133, + 139, + 144, + 147, + 152, + 156, + 159, + 167, + 168, + 169, + 173, + 174, + 182, + 183, + 192, + 194, + 196, + 198, + 202, + 203, + 205, + 208, + 209, + 212, + 214, + 215, + 219, + 222, + 223, + 224, + 225, + 226, + 229, + 231, + 232, + 233, + 235, + 244, + 254, + 256, + 259, + 264, + 265, + 274, + 277, + 286, + 292, + 293, + 295, + 296, + 300, + 307, + 308, + 313, + 318, + 319, + 325, + 326, + 345, + 350, + 352, + 355, + 363, + 369, + 371, + 379, + 382, + 387, + 394, + 395, + 397, + 400, + 401, + 402, + 405, + 407, + 419, + 422, + 423, + 424, + 433, + 445, + 447, + 460, + 461, + 465, + 467, + 469, + 477, + 484, + 492, + 498, + 502, + 503, + 516, + 523, + 526, + 529, + 530, + 531, + 533, + 536, + 540, + 543, + 545, + 550, + 559, + 564, + 570, + 571, + 574, + 577, + 579, + 581, + 583, + 585, + 587, + 596, + 599, + 602, + 611, + 617, + 618, + 620, + 621, + 622, + 625, + 630, + 634, + 636, + 639, + 641, + 656, + 658, + 661, + 664, + 665, + 688, + 689, + 691, + 694, + 695, + 706, + 708, + 711, + 713, + 720, + 721, + 724, + 729, + 735, + 737, + 742, + 746, + 752, + 760, + 766, + 767, + 772, + 778, + 780, + 786, + 795, + 801, + 813, + 824, + 826, + 827, + 828, + 835, + 837, + 840, + 843, + 845, + 848, + 849, + 852, + 853, + 859, + 862, + 863, + 865, + 870, + 874, + 878, + 881, + 886, + 897, + 898, + ] + ] + }, } # Create the list of DF for the documentation -_all_l = sorted(set(l for v,k,l in DF.keys())) -LIST_OF_DF = "\n".join(r" - `\lambda={}`:\n ".format(l) + - ", ".join("`({},{},{})`".format(v, k, l) for v,k,_ in sorted(DF.keys()) if _ == l) - for l in _all_l) +_all_l = sorted(set(l for v, k, l in DF.keys())) +LIST_OF_DF = "\n".join(r" - `\lambda={}`:\n ".format(l) + ", ".join("`({},{},{})`".format(v, k, l) for v, k, _ in sorted(DF.keys()) if _ == l) for l in _all_l) def DM_12_6_1(): @@ -3252,21 +3223,11 @@ def DM_12_6_1(): Discrete Mathematics, Volume 11, Issue 3, 1975, Pages 255-369. """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(2).cartesian_product(AdditiveCyclic(6)) - M = [[(0,0),(0,0),(0,0),(0,0),(0,0),(0,0)], - [(0,0),(0,1),(1,0),(0,3),(1,2),(0,4)], - [(0,0),(0,2),(1,2),(1,0),(0,1),(1,5)], - [(0,0),(0,3),(0,2),(0,1),(1,5),(1,4)], - [(0,0),(0,4),(1,1),(1,3),(0,5),(0,2)], - [(0,0),(0,5),(0,1),(1,5),(1,3),(1,1)], - [(0,0),(1,0),(1,3),(0,2),(0,3),(1,2)], - [(0,0),(1,1),(1,5),(1,2),(1,4),(1,0)], - [(0,0),(1,2),(0,4),(0,5),(0,2),(1,3)], - [(0,0),(1,3),(1,4),(0,4),(1,1),(0,1)], - [(0,0),(1,4),(0,5),(1,1),(1,0),(0,3)], - [(0,0),(1,5),(0,3),(1,4),(0,4),(0,5)]] - - return G,M + M = [[(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)], [(0, 0), (0, 1), (1, 0), (0, 3), (1, 2), (0, 4)], [(0, 0), (0, 2), (1, 2), (1, 0), (0, 1), (1, 5)], [(0, 0), (0, 3), (0, 2), (0, 1), (1, 5), (1, 4)], [(0, 0), (0, 4), (1, 1), (1, 3), (0, 5), (0, 2)], [(0, 0), (0, 5), (0, 1), (1, 5), (1, 3), (1, 1)], [(0, 0), (1, 0), (1, 3), (0, 2), (0, 3), (1, 2)], [(0, 0), (1, 1), (1, 5), (1, 2), (1, 4), (1, 0)], [(0, 0), (1, 2), (0, 4), (0, 5), (0, 2), (1, 3)], [(0, 0), (1, 3), (1, 4), (0, 4), (1, 1), (0, 1)], [(0, 0), (1, 4), (0, 5), (1, 1), (1, 0), (0, 3)], [(0, 0), (1, 5), (0, 3), (1, 4), (0, 4), (0, 5)]] + + return G, M def DM_21_6_1(): @@ -3288,19 +3249,16 @@ def DM_21_6_1(): sage: _ = designs.difference_matrix(21,6) # needs sage.rings.finite_rings """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic - M = [[ 8, 17, 20, 2], - [ 9, 16, 4, 15], - [ 11, 5, 10, 6], - [ 14, 1, 3, 13], - [ 18, 19, 12, 7]] - - Mb = [[0,0,0,0,0,0]] - for a,b,c,d,e in zip(*M): - Mb.append([a,b,c,d,e,0]) - Mb.append([b,c,d,e,a,0]) - Mb.append([c,d,e,a,b,0]) - Mb.append([d,e,a,b,c,0]) - Mb.append([e,a,b,c,d,0]) + + M = [[8, 17, 20, 2], [9, 16, 4, 15], [11, 5, 10, 6], [14, 1, 3, 13], [18, 19, 12, 7]] + + Mb = [[0, 0, 0, 0, 0, 0]] + for a, b, c, d, e in zip(*M): + Mb.append([a, b, c, d, e, 0]) + Mb.append([b, c, d, e, a, 0]) + Mb.append([c, d, e, a, b, 0]) + Mb.append([d, e, a, b, c, 0]) + Mb.append([e, a, b, c, d, 0]) return AdditiveCyclic(21), Mb @@ -3323,32 +3281,19 @@ def DM_24_8_1(): sage: _ = designs.difference_matrix(24,8) """ - M = ("0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 " + - "0000 0010 0100 0110 1000 1010 1100 1110 2000 2010 2100 2110 " + - "0000 0011 1001 2110 0111 2011 2111 1000 0100 1100 1101 2010 " + - "0000 1010 1011 2000 1101 2110 0001 0101 2100 2001 0111 1100 " + - "0000 0001 2010 1111 2111 2100 1101 0011 1010 2101 1000 0110 " + - "0000 1000 2001 1011 0100 1100 0110 2101 2111 0010 1111 2011 " + - "0000 1001 0111 2100 2000 0010 1110 2011 1100 1011 0101 2111 " + - "0000 1011 2101 0100 2110 1001 2000 0110 0101 1111 2011 1010 ") + M = "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 " + "0000 0010 0100 0110 1000 1010 1100 1110 2000 2010 2100 2110 " + "0000 0011 1001 2110 0111 2011 2111 1000 0100 1100 1101 2010 " + "0000 1010 1011 2000 1101 2110 0001 0101 2100 2001 0111 1100 " + "0000 0001 2010 1111 2111 2100 1101 0011 1010 2101 1000 0110 " + "0000 1000 2001 1011 0100 1100 0110 2101 2111 0010 1111 2011 " + "0000 1001 0111 2100 2000 0010 1110 2011 1100 1011 0101 2111 " + "0000 1011 2101 0100 2110 1001 2000 0110 0101 1111 2011 1010 " from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic from sage.categories.cartesian_product import cartesian_product + G = cartesian_product([AdditiveCyclic(_) for _ in [2, 2, 6]]) - rlabel = {(x % 2,x % 3):x for x in range(6)} - M = [G([int(c),int(d),rlabel[int(b),int(a)]]) for a,b,c,d in M.split()] - M = [M[i*12:(i+1)*12] for i in range(8)] + rlabel = {(x % 2, x % 3): x for x in range(6)} + M = [G([int(c), int(d), rlabel[int(b), int(a)]]) for a, b, c, d in M.split()] + M = [M[i * 12 : (i + 1) * 12] for i in range(8)] Mb = [] - for a,b,c,d,e,f,g,h in zip(*M): - Mb.append([a,b,c,d,e,f,g,h]) - Mb.append([a + G([0,0,rlabel[0,0]]), - b + G([0,1,rlabel[0,0]]), - c + G([1,0,rlabel[0,0]]), - d + G([1,1,rlabel[0,0]]), - e + G([0,0,rlabel[1,0]]), - f + G([0,1,rlabel[1,0]]), - g + G([1,0,rlabel[1,0]]), - h + G([1,1,rlabel[1,0]])]) + for a, b, c, d, e, f, g, h in zip(*M): + Mb.append([a, b, c, d, e, f, g, h]) + Mb.append([a + G([0, 0, rlabel[0, 0]]), b + G([0, 1, rlabel[0, 0]]), c + G([1, 0, rlabel[0, 0]]), d + G([1, 1, rlabel[0, 0]]), e + G([0, 0, rlabel[1, 0]]), f + G([0, 1, rlabel[1, 0]]), g + G([1, 0, rlabel[1, 0]]), h + G([1, 1, rlabel[1, 0]])]) return G, Mb @@ -3373,26 +3318,27 @@ def DM_28_6_1(): """ z = 2 M = [ - [(0,0), (z+1,6),(1,1) ,(1,1) ,(1,3) ,(1,4) ,(0,0) ,(1,4), (z,5) ], - [(z,2), (0,0) ,(1,5) ,(z,1) ,(z,2) ,(z,6) ,(z+1,3),(0,0), (z,1) ], - [(z,3), (z+1,4),(0,0) ,(z+1,5),(z+1,2),(z+1,4),(z+1,2),(1,6), (0,0) ], - [(0,5), (z,6) ,(0,5) ,(0,6) ,(z,3) ,(0,0) ,(0,4) ,(1,5), (z+1,4)], - [(0,3), (0,3) ,(z+1,5),(0,0) ,(0,5) ,(z+1,6),(1,1) ,(0,1), (z,3) ], - [(1,3), (0,6) ,(0,6) ,(1,5) ,(0,0) ,(0,3) ,(z+1,6),(z,2), (0,2) ], - ] + [(0, 0), (z + 1, 6), (1, 1), (1, 1), (1, 3), (1, 4), (0, 0), (1, 4), (z, 5)], + [(z, 2), (0, 0), (1, 5), (z, 1), (z, 2), (z, 6), (z + 1, 3), (0, 0), (z, 1)], + [(z, 3), (z + 1, 4), (0, 0), (z + 1, 5), (z + 1, 2), (z + 1, 4), (z + 1, 2), (1, 6), (0, 0)], + [(0, 5), (z, 6), (0, 5), (0, 6), (z, 3), (0, 0), (0, 4), (1, 5), (z + 1, 4)], + [(0, 3), (0, 3), (z + 1, 5), (0, 0), (0, 5), (z + 1, 6), (1, 1), (0, 1), (z, 3)], + [(1, 3), (0, 6), (0, 6), (1, 5), (0, 0), (0, 3), (z + 1, 6), (z, 2), (0, 2)], + ] from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup from sage.modules.free_module_element import free_module_element as vector - G = AdditiveAbelianGroup([2,2,7]) - M = [[G(vector([x//2,x % 2,y])) for x,y in L] for L in M] - Mb = [[0,0,0,0,0,0]] + G = AdditiveAbelianGroup([2, 2, 7]) + M = [[G(vector([x // 2, x % 2, y])) for x, y in L] for L in M] + + Mb = [[0, 0, 0, 0, 0, 0]] for R in zip(*M): - a,b,c,d,e,f = R - Mb.append([a,b,c,d,e,f]) - Mb.append([b,c,a,f,d,e]) - Mb.append([c,a,b,e,f,d]) + a, b, c, d, e, f = R + Mb.append([a, b, c, d, e, f]) + Mb.append([b, c, a, f, d, e]) + Mb.append([c, a, b, e, f, d]) return G, Mb @@ -3415,27 +3361,19 @@ def DM_33_6_1(): sage: _ = designs.difference_matrix(33,6) # needs sage.rings.finite_rings """ - M = [ - [ 0, 0, 0, 0, 0, 0], - [ 15, 11, 22, 4, 17, 8], - [ 19, 7, 14, 32, 22, 18], - [ 22, 19, 8, 24, 21, 6], - [ 9, 12, 15, 7, 26, 14], - [ 14, 28, 23, 2, 19, 3] - ] + M = [[0, 0, 0, 0, 0, 0], [15, 11, 22, 4, 17, 8], [19, 7, 14, 32, 22, 18], [22, 19, 8, 24, 21, 6], [9, 12, 15, 7, 26, 14], [14, 28, 23, 2, 19, 3]] from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(33) - Mb = [[0, 0, 0, 0, 0, 0], - [1, 4,16,31,25,22], - [7,28,13,19,10, 0]] + Mb = [[0, 0, 0, 0, 0, 0], [1, 4, 16, 31, 25, 22], [7, 28, 13, 19, 10, 0]] for R in zip(*M): - a,b,c,d,e,f = R + a, b, c, d, e, f = R for i in range(5): - Mb.append([a,b,c,d,e,f]) - a,b,c,d,e,f = 4*e,4*a,4*b,4*c,4*d,4*f + Mb.append([a, b, c, d, e, f]) + a, b, c, d, e, f = 4 * e, 4 * a, 4 * b, 4 * c, 4 * d, 4 * f return G, Mb @@ -3458,16 +3396,10 @@ def DM_35_6_1(): sage: _ = designs.difference_matrix(35,6) # needs sage.rings.finite_rings """ - M = [ - [ 0, 15, 30, 10, 25, 1, 16, 31, 11, 26, 2, 17, 32, 12, 6, 3, 18, 33, 27, 21, 4, 19, 13, 7, 22, 5, 34, 28, 8, 23, 20, 14, 29, 9, 24], - [ 0, 22, 16, 3, 4, 9, 10, 32, 26, 13, 18, 5, 27, 14, 15, 20, 7, 1, 23, 31, 29, 2, 24, 11, 19, 17, 25, 12, 6, 28, 33, 34, 21, 8, 30], - [ 0, 29, 2, 31, 18, 10, 32, 26, 34, 28, 27, 21, 15, 9, 17, 30, 3, 4, 5, 20, 12, 6, 14, 22, 16, 8, 23, 24, 25, 33, 11, 19, 13, 7, 1], - [ 0, 8, 9, 17, 11, 25, 19, 27, 28, 1, 15, 23, 31, 4, 26, 12, 6, 14, 29, 16, 2, 3, 18, 33, 34, 20, 7, 22, 30, 24, 10, 32, 5, 13, 21], - [ 0, 1, 23, 24, 32, 33, 6, 7, 29, 30, 10, 11, 12, 13, 28, 8, 9, 31, 4, 5, 27, 14, 15, 16, 3, 25, 26, 34, 21, 22, 2, 17, 18, 19, 20], - [0]*35 - ] + M = [[0, 15, 30, 10, 25, 1, 16, 31, 11, 26, 2, 17, 32, 12, 6, 3, 18, 33, 27, 21, 4, 19, 13, 7, 22, 5, 34, 28, 8, 23, 20, 14, 29, 9, 24], [0, 22, 16, 3, 4, 9, 10, 32, 26, 13, 18, 5, 27, 14, 15, 20, 7, 1, 23, 31, 29, 2, 24, 11, 19, 17, 25, 12, 6, 28, 33, 34, 21, 8, 30], [0, 29, 2, 31, 18, 10, 32, 26, 34, 28, 27, 21, 15, 9, 17, 30, 3, 4, 5, 20, 12, 6, 14, 22, 16, 8, 23, 24, 25, 33, 11, 19, 13, 7, 1], [0, 8, 9, 17, 11, 25, 19, 27, 28, 1, 15, 23, 31, 4, 26, 12, 6, 14, 29, 16, 2, 3, 18, 33, 34, 20, 7, 22, 30, 24, 10, 32, 5, 13, 21], [0, 1, 23, 24, 32, 33, 6, 7, 29, 30, 10, 11, 12, 13, 28, 8, 9, 31, 4, 5, 27, 14, 15, 16, 3, 25, 26, 34, 21, 22, 2, 17, 18, 19, 20], [0] * 35] from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(35) return G, list(zip(*M)) @@ -3492,37 +3424,29 @@ def DM_36_9_1(): sage: _ = designs.difference_matrix(36,9) # needs sage.modules """ M = [ - [(0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0), (0,0,0,0)], - [(0,0,0,0), (0,1,0,0), (1,0,0,0), (1,1,0,0), (0,0,0,1), (0,1,0,1), (1,0,0,1), (1,1,0,1), (0,0,0,2), (0,1,0,2), (1,0,0,2), (1,1,0,2)], - [(0,0,0,0), (1,1,1,2), (0,0,2,1), (0,0,1,2), (0,1,2,0), (0,1,0,2), (1,1,1,1), (0,1,1,1), (1,1,1,0), (1,0,2,2), (1,0,0,1), (1,0,1,0)], - [(0,0,0,0), (0,0,1,0), (1,0,1,0), (0,1,0,0), (1,1,0,0), (1,0,2,0), (1,0,0,0), (0,1,2,0), (1,1,2,0), (0,0,2,0), (1,1,1,0), (0,1,1,0)], - [(0,0,0,0), (0,1,2,0), (0,0,1,0), (1,1,1,0), (1,0,2,0), (1,0,1,0), (0,1,0,0), (0,0,2,0), (0,1,1,0), (1,1,0,0), (1,1,2,0), (1,0,0,0)], - [(0,0,0,0), (0,1,1,0), (0,1,2,0), (1,1,2,0), (1,1,0,2), (0,0,1,2), (1,1,2,2), (1,0,0,2), (1,0,0,1), (1,0,1,1), (0,0,2,1), (0,1,1,1)], - [(0,0,0,0), (1,0,1,0), (1,1,0,1), (1,0,1,2), (1,0,2,2), (0,0,2,1), (0,1,0,1), (0,1,0,0), (1,1,2,2), (0,1,1,0), (0,0,1,2), (1,1,2,1)], - [(0,0,0,0), (1,1,0,0), (0,1,1,0), (1,0,2,1), (0,1,0,2), (1,0,2,2), (0,0,2,2), (1,1,1,0), (1,0,1,1), (0,1,2,1), (1,1,1,1), (0,0,0,2)], - [(0,0,0,0), (1,0,0,0), (1,1,1,0), (0,1,1,2), (1,1,2,1), (0,1,1,1), (0,0,1,1), (1,0,2,0), (0,1,2,2), (1,1,0,2), (1,0,2,2), (0,0,0,1)] - ] + [(0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)], + [(0, 0, 0, 0), (0, 1, 0, 0), (1, 0, 0, 0), (1, 1, 0, 0), (0, 0, 0, 1), (0, 1, 0, 1), (1, 0, 0, 1), (1, 1, 0, 1), (0, 0, 0, 2), (0, 1, 0, 2), (1, 0, 0, 2), (1, 1, 0, 2)], + [(0, 0, 0, 0), (1, 1, 1, 2), (0, 0, 2, 1), (0, 0, 1, 2), (0, 1, 2, 0), (0, 1, 0, 2), (1, 1, 1, 1), (0, 1, 1, 1), (1, 1, 1, 0), (1, 0, 2, 2), (1, 0, 0, 1), (1, 0, 1, 0)], + [(0, 0, 0, 0), (0, 0, 1, 0), (1, 0, 1, 0), (0, 1, 0, 0), (1, 1, 0, 0), (1, 0, 2, 0), (1, 0, 0, 0), (0, 1, 2, 0), (1, 1, 2, 0), (0, 0, 2, 0), (1, 1, 1, 0), (0, 1, 1, 0)], + [(0, 0, 0, 0), (0, 1, 2, 0), (0, 0, 1, 0), (1, 1, 1, 0), (1, 0, 2, 0), (1, 0, 1, 0), (0, 1, 0, 0), (0, 0, 2, 0), (0, 1, 1, 0), (1, 1, 0, 0), (1, 1, 2, 0), (1, 0, 0, 0)], + [(0, 0, 0, 0), (0, 1, 1, 0), (0, 1, 2, 0), (1, 1, 2, 0), (1, 1, 0, 2), (0, 0, 1, 2), (1, 1, 2, 2), (1, 0, 0, 2), (1, 0, 0, 1), (1, 0, 1, 1), (0, 0, 2, 1), (0, 1, 1, 1)], + [(0, 0, 0, 0), (1, 0, 1, 0), (1, 1, 0, 1), (1, 0, 1, 2), (1, 0, 2, 2), (0, 0, 2, 1), (0, 1, 0, 1), (0, 1, 0, 0), (1, 1, 2, 2), (0, 1, 1, 0), (0, 0, 1, 2), (1, 1, 2, 1)], + [(0, 0, 0, 0), (1, 1, 0, 0), (0, 1, 1, 0), (1, 0, 2, 1), (0, 1, 0, 2), (1, 0, 2, 2), (0, 0, 2, 2), (1, 1, 1, 0), (1, 0, 1, 1), (0, 1, 2, 1), (1, 1, 1, 1), (0, 0, 0, 2)], + [(0, 0, 0, 0), (1, 0, 0, 0), (1, 1, 1, 0), (0, 1, 1, 2), (1, 1, 2, 1), (0, 1, 1, 1), (0, 0, 1, 1), (1, 0, 2, 0), (0, 1, 2, 2), (1, 1, 0, 2), (1, 0, 2, 2), (0, 0, 0, 1)], + ] from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup from sage.modules.free_module_element import free_module_element as vector - G = AdditiveAbelianGroup([2,2,3,3]) + + G = AdditiveAbelianGroup([2, 2, 3, 3]) M = [[G(vector(x)) for x in L] for L in M] Mb = [] for R in zip(*M): - a,b,c,d,e,f,g,h,i = R + a, b, c, d, e, f, g, h, i = R for y in range(3): - Mb.append([ - a+G(vector([0,0,0,0])), - b+G(vector([0,0,y,0])), - c+G(vector([0,0,2*y,0])), - d+G(vector([0,0,0,y])), - e+G(vector([0,0,0,2*y])), - f+G(vector([0,0,y,y])), - g+G(vector([0,0,2*y,2*y])), - h+G(vector([0,0,y,2*y])), - i+G(vector([0,0,2*y,y]))]) + Mb.append([a + G(vector([0, 0, 0, 0])), b + G(vector([0, 0, y, 0])), c + G(vector([0, 0, 2 * y, 0])), d + G(vector([0, 0, 0, y])), e + G(vector([0, 0, 0, 2 * y])), f + G(vector([0, 0, y, y])), g + G(vector([0, 0, 2 * y, 2 * y])), h + G(vector([0, 0, y, 2 * y])), i + G(vector([0, 0, 2 * y, y]))]) return G, Mb @@ -3546,30 +3470,22 @@ def DM_39_6_1(): sage: designs.difference_matrix(39,6,existence=True) # needs sage.rings.finite_rings True """ - M = [ - [ 0, 0, 0, 0, 0, 0], - [ 4, 23, 13, 5, 12, 11], - [ 25, 11, 22, 34, 23, 6], - [ 13, 4, 20, 17, 15, 29], - [ 27, 21, 8, 16, 19, 26], - [ 16, 19, 34, 38, 26, 21] - ] + M = [[0, 0, 0, 0, 0, 0], [4, 23, 13, 5, 12, 11], [25, 11, 22, 34, 23, 6], [13, 4, 20, 17, 15, 29], [27, 21, 8, 16, 19, 26], [16, 19, 34, 38, 26, 21]] from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(39) - Mb = [[ 0, 0, 0, 0, 0, 0], - [ 1, 16, 22, 17, 38, 23], - [-1,-16,-22,-17,-38,-23]] + Mb = [[0, 0, 0, 0, 0, 0], [1, 16, 22, 17, 38, 23], [-1, -16, -22, -17, -38, -23]] for R in zip(*M): - a,b,c,d,e,f = map(G,R) + a, b, c, d, e, f = map(G, R) for i in range(3): - Mb.append([ a, b, c, d, e, f]) - Mb.append([-a,-b,-c,-d,-e,-f]) - a,b,c,d,e,f = (16*x for x in [c,a,b,f,d,e]) + Mb.append([a, b, c, d, e, f]) + Mb.append([-a, -b, -c, -d, -e, -f]) + a, b, c, d, e, f = (16 * x for x in [c, a, b, f, d, e]) - return G,Mb + return G, Mb def DM_44_6_1(): @@ -3595,16 +3511,9 @@ def DM_44_6_1(): G2 = AdditiveCyclic(2) G11 = AdditiveCyclic(11) - G2211 = cartesian_product((G2,G2,G11)) + G2211 = cartesian_product((G2, G2, G11)) - M = [ - [(0,0,0), (0,0,0), (0,0,0), (0,0,0), (0,0,0), (0,0,0), (0,0,0), (0,0,0)], - [(1,1,4), (0,1,4), (1,1,7), (1,0,6), (1,1,9), (0,1,2), (0,1,5), (0,1,1)], - [(1,0,6), (0,1,3), (1,0,0), (0,1,9), (1,1,1), (0,1,4), (1,1,9), (1,0,9)], - [(1,1,6), (1,1,9), (0,1,2), (1,1,0), (0,1,0), (1,1,5), (0,0,4), (0,0,9)], - [(1,0,9), (0,0,2), (0,0,1), (1,0,2), (0,0,7), (1,1,6), (1,1,0), (1,0,7)], - [(1,0,1), (1,0,6), (1,1,3), (0,1,5), (0,0,5), (0,1,3), (0,1,0), (1,1,0)] - ] + M = [[(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)], [(1, 1, 4), (0, 1, 4), (1, 1, 7), (1, 0, 6), (1, 1, 9), (0, 1, 2), (0, 1, 5), (0, 1, 1)], [(1, 0, 6), (0, 1, 3), (1, 0, 0), (0, 1, 9), (1, 1, 1), (0, 1, 4), (1, 1, 9), (1, 0, 9)], [(1, 1, 6), (1, 1, 9), (0, 1, 2), (1, 1, 0), (0, 1, 0), (1, 1, 5), (0, 0, 4), (0, 0, 9)], [(1, 0, 9), (0, 0, 2), (0, 0, 1), (1, 0, 2), (0, 0, 7), (1, 1, 6), (1, 1, 0), (1, 0, 7)], [(1, 0, 1), (1, 0, 6), (1, 1, 3), (0, 1, 5), (0, 0, 5), (0, 1, 3), (0, 1, 0), (1, 1, 0)]] M = [[G2211(x) for x in L] for L in M] @@ -3612,22 +3521,12 @@ def DM_44_6_1(): for R in zip(*M): for c in range(5): - (x1,y1,z1),(x2,y2,z2),(x3,y3,z3),(x4,y4,z4),(x5,y5,z5),(x6,y6,z6) = R + (x1, y1, z1), (x2, y2, z2), (x3, y3, z3), (x4, y4, z4), (x5, y5, z5), (x6, y6, z6) = R Mb.append(list(R)) - R = [(x5,y5,5*z5), - (x1,y1,5*z1), - (x2,y2,5*z2), - (x3,y3,5*z3), - (x4,y4,5*z4), - (x6,y6,5*z6)] - - for x,y,z in [(0,0,0), (1,0,1),(1,1,2),(0,0,8)]: - Mb.append([(x,y,z), - (x,y,5*z), - (x,y,3*z), - (x,y,4*z), - (x,y,9*z), - (0,0,0)]) + R = [(x5, y5, 5 * z5), (x1, y1, 5 * z1), (x2, y2, 5 * z2), (x3, y3, 5 * z3), (x4, y4, 5 * z4), (x6, y6, 5 * z6)] + + for x, y, z in [(0, 0, 0), (1, 0, 1), (1, 1, 2), (0, 0, 8)]: + Mb.append([(x, y, z), (x, y, 5 * z), (x, y, 3 * z), (x, y, 4 * z), (x, y, 9 * z), (0, 0, 0)]) return G2211, Mb @@ -3656,35 +3555,21 @@ def DM_45_7_1(): from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.categories.cartesian_product import cartesian_product - G533 = cartesian_product((FiniteField(5),FiniteField(3),FiniteField(3))) + G533 = cartesian_product((FiniteField(5), FiniteField(3), FiniteField(3))) - M = [ - [(0,0,0), (2,2,1), (3,1,1), (4,1,2), (4,0,1), (0,1,1), (0,2,1), (3,2,2)], - [(0,0,0), (1,2,1), (4,2,2), (1,2,0), (4,1,0), (3,1,1), (3,0,0), (2,1,2)], - [(0,0,0), (4,1,1), (2,2,1), (3,2,0), (1,2,0), (2,1,0), (1,0,0), (3,2,1)], - [(0,0,0), (0,1,0), (2,1,1), (4,0,0), (0,0,2), (4,2,2), (3,2,2), (1,2,2)], - [(0,0,0), (3,1,2), (2,1,0), (0,2,2), (4,2,1), (0,2,1), (2,0,1), (1,1,2)], - [(0,0,0), (2,1,1), (1,2,2), (3,0,1), (2,0,1), (1,0,0), (4,2,1), (1,1,0)], - [(0,0,0), (0,0,0), (0,0,0), (0,0,0), (0,0,0), (0,0,0), (0,0,0), (0,0,0)] - ] + M = [[(0, 0, 0), (2, 2, 1), (3, 1, 1), (4, 1, 2), (4, 0, 1), (0, 1, 1), (0, 2, 1), (3, 2, 2)], [(0, 0, 0), (1, 2, 1), (4, 2, 2), (1, 2, 0), (4, 1, 0), (3, 1, 1), (3, 0, 0), (2, 1, 2)], [(0, 0, 0), (4, 1, 1), (2, 2, 1), (3, 2, 0), (1, 2, 0), (2, 1, 0), (1, 0, 0), (3, 2, 1)], [(0, 0, 0), (0, 1, 0), (2, 1, 1), (4, 0, 0), (0, 0, 2), (4, 2, 2), (3, 2, 2), (1, 2, 2)], [(0, 0, 0), (3, 1, 2), (2, 1, 0), (0, 2, 2), (4, 2, 1), (0, 2, 1), (2, 0, 1), (1, 1, 2)], [(0, 0, 0), (2, 1, 1), (1, 2, 2), (3, 0, 1), (2, 0, 1), (1, 0, 0), (4, 2, 1), (1, 1, 0)], [(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)]] for i in range(6): - M[i].extend(M[5-i][1:8]) + M[i].extend(M[5 - i][1:8]) M[6].extend(M[6][1:8]) Mb = [] for R in zip(*M): - (x1,y1,z1),(x2,y2,z2),(x3,y3,z3),(x4,y4,z4),(x5,y5,z5),(x6,y6,z6),(x7,y7,z7) = R + (x1, y1, z1), (x2, y2, z2), (x3, y3, z3), (x4, y4, z4), (x5, y5, z5), (x6, y6, z6), (x7, y7, z7) = R for i in range(3): - Mb.append([(x1, y1 , z1+i ), - (x2, y2+2*i, z2 ), - (x3, y3+i , z3+2*i), - (x4, y4+2*i, z4+i ), - (x5, y5+i , z5 ), - (x6, y6 , z6+2*i), - (x7, y7 , z7 )]) + Mb.append([(x1, y1, z1 + i), (x2, y2 + 2 * i, z2), (x3, y3 + i, z3 + 2 * i), (x4, y4 + 2 * i, z4 + i), (x5, y5 + i, z5), (x6, y6, z6 + 2 * i), (x7, y7, z7)]) return G533, Mb @@ -3708,33 +3593,34 @@ def DM_48_9_1(): sage: _ = designs.difference_matrix(48,9) # needs sage.rings.finite_rings """ from sage.rings.finite_rings.finite_field_constructor import FiniteField - F16 = FiniteField(16,'x') + + F16 = FiniteField(16, 'x') F3 = FiniteField(3) F3F16 = F3.cartesian_product(F16) w = F16.primitive_element() - assert w**4 == w+1 + assert w**4 == w + 1 A = [ - [ (0, 4), (2, 2), (2,2), (0,13), (0,4), (2,13), (0,1), (0,7), (1,7) , (2,2) , (0,6), (2,9)], - [ (2, 7), (0, 9), (2,7), (2,3) , (0,3), (0,9) , (1,12), (0,6), (0,12), (2,14), (2,7), (0,11)], - [ (2,12), (2,12), (0,14), (0,14), (2,8), (0,8) , (0,2), (1,2), (0,11), (0,1) , (2,4), (2,12)], - [ (1, 3), (0, 2), (0,10), (0,14), (0,9), (1,3) , (0,12), (2,13), (2,1) , (2,9) , (2,0), (1,7)], - [ (0, 0), (1, 8), (0,7), (1,8) , (0,4), (0,14), (2,6), (0,2), (2,3) , (1,12), (2,14), (2,5)], - [ (0,12), (0, 5), (1,13), (0,4) , (1,13), (0,9) , (2,8), (2,11), (0,7) , (2,10), (1,2), (2,4)], - [ (1,12), (2, 0), (1,14), (0,6) , (1,9), (0,14), (1,4), (0,5), (1,8) , (1,3) , (2,1), (1,1)], - [ (1, 4), (1, 2), (2,5), (0,4) , (0,11), (1,14), (1,13), (1,9), (0,10), (1,6) , (1,8), (2,6)], - [ (2,10), (1, 9), (1,7), (1,4) , (0,9), (0,1) , (0,0), (1,3), (1,14), (2,11), (1,11), (1,13)], - ] + [(0, 4), (2, 2), (2, 2), (0, 13), (0, 4), (2, 13), (0, 1), (0, 7), (1, 7), (2, 2), (0, 6), (2, 9)], + [(2, 7), (0, 9), (2, 7), (2, 3), (0, 3), (0, 9), (1, 12), (0, 6), (0, 12), (2, 14), (2, 7), (0, 11)], + [(2, 12), (2, 12), (0, 14), (0, 14), (2, 8), (0, 8), (0, 2), (1, 2), (0, 11), (0, 1), (2, 4), (2, 12)], + [(1, 3), (0, 2), (0, 10), (0, 14), (0, 9), (1, 3), (0, 12), (2, 13), (2, 1), (2, 9), (2, 0), (1, 7)], + [(0, 0), (1, 8), (0, 7), (1, 8), (0, 4), (0, 14), (2, 6), (0, 2), (2, 3), (1, 12), (2, 14), (2, 5)], + [(0, 12), (0, 5), (1, 13), (0, 4), (1, 13), (0, 9), (2, 8), (2, 11), (0, 7), (2, 10), (1, 2), (2, 4)], + [(1, 12), (2, 0), (1, 14), (0, 6), (1, 9), (0, 14), (1, 4), (0, 5), (1, 8), (1, 3), (2, 1), (1, 1)], + [(1, 4), (1, 2), (2, 5), (0, 4), (0, 11), (1, 14), (1, 13), (1, 9), (0, 10), (1, 6), (1, 8), (2, 6)], + [(2, 10), (1, 9), (1, 7), (1, 4), (0, 9), (0, 1), (0, 0), (1, 3), (1, 14), (2, 11), (1, 11), (1, 13)], + ] - A = [[F3F16((F3(a),w**b)) for a,b in L] for L in A] - V = [12,2,7,0,5,10,3,8,13] + A = [[F3F16((F3(a), w**b)) for a, b in L] for L in A] + V = [12, 2, 7, 0, 5, 10, 3, 8, 13] Mb = [] for L in zip(*A): Mb.append(L) - for u in [0,1,4]: - Mb.append([e+F3F16((0,w**(x+u))) for (e,x) in zip(L,V)]) + for u in [0, 1, 4]: + Mb.append([e + F3F16((0, w ** (x + u))) for (e, x) in zip(L, V)]) return F3F16, Mb @@ -3758,15 +3644,10 @@ def DM_51_6_1(): sage: _ = designs.difference_matrix(51,6) # needs sage.rings.finite_rings """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(51) - M = [ - [ 5, 33, 29, 30, 1], - [ 8, 3, 47, 10, 13], - [ 14, 27, 6, 12, 28], - [ 9, 16, 44, 49, 11], - [ 34, 32, 36, 26, 20] - ] + M = [[5, 33, 29, 30, 1], [8, 3, 47, 10, 13], [14, 27, 6, 12, 28], [9, 16, 44, 49, 11], [34, 32, 36, 26, 20]] Mb = [[0, 0, 0, 0, 0]] @@ -3800,56 +3681,43 @@ def DM_52_6_1(): sage: _ = designs.difference_matrix(52,6) # needs sage.rings.finite_rings """ from sage.rings.finite_rings.finite_field_constructor import FiniteField - F4 = FiniteField(4,'z') + + F4 = FiniteField(4, 'z') G13 = FiniteField(13) G = F4.cartesian_product(G13) z = F4('z') - assert z**2 == z+1 + assert z**2 == z + 1 - M = [ - [ (0,0), (0,0), (0,0), (0,0), (0,0)], - [(z**2,10), (0,7), (1,10), (z,10),(z**2,3)], - [ (z,10), (z**2,2), (1,11), (z,2),(z**2,7)], - [ (z,8),(z**2,12), (0,10),(z**2,11),(z**2,6)], - [ (1,2), (0,2), (z**2,8), (z,3), (z,7)], - [ (1,6), (z,12), (0,7), (z**2,6), (z,2)] - ] + M = [[(0, 0), (0, 0), (0, 0), (0, 0), (0, 0)], [(z**2, 10), (0, 7), (1, 10), (z, 10), (z**2, 3)], [(z, 10), (z**2, 2), (1, 11), (z, 2), (z**2, 7)], [(z, 8), (z**2, 12), (0, 10), (z**2, 11), (z**2, 6)], [(1, 2), (0, 2), (z**2, 8), (z, 3), (z, 7)], [(1, 6), (z, 12), (0, 7), (z**2, 6), (z, 2)]] - M2 = [ - [ (1,1),(z**2,11)], - [ (z,3), (1,7)], - [ (z**2,9), (z,8)], - [ (1,4), (z**2,3)], - [ (z,12), (1,9)], - [(z**2,10), (z,1)] - ] + M2 = [[(1, 1), (z**2, 11)], [(z, 3), (1, 7)], [(z**2, 9), (z, 8)], [(1, 4), (z**2, 3)], [(z, 12), (1, 9)], [(z**2, 10), (z, 1)]] M = [[G(x) for x in L] for L in M] M2 = [[G(x) for x in L] for L in M2] - Mb = [[(0,0)]*6] + Mb = [[(0, 0)] * 6] from itertools import product def t1(i, R): if i > 1: - return t1(1,t1(i-1,R)) - ((x1,y1),(x2,y2),(x3,y3),(x4,y4),(x5,y5),(x6,y6)) = R - return [(z*x3, 3*y3), (z*x1, 3*y1), (z*x2, 3*y2), (z*x6, 3*y6), (z*x4, 3*y4), (z*x5, 3*y5)] + return t1(1, t1(i - 1, R)) + ((x1, y1), (x2, y2), (x3, y3), (x4, y4), (x5, y5), (x6, y6)) = R + return [(z * x3, 3 * y3), (z * x1, 3 * y1), (z * x2, 3 * y2), (z * x6, 3 * y6), (z * x4, 3 * y4), (z * x5, 3 * y5)] def t2(i, R): if i > 1: - return t2(1,t2(i-1,R)) - ((x1,y1),(x2,y2),(x3,y3),(x4,y4),(x5,y5),(x6,y6)) = R - return [( x3, y3), ( x1, y1), ( x2, y2), ( x5, y5), ( x6, y6), ( x4, y4)] + return t2(1, t2(i - 1, R)) + ((x1, y1), (x2, y2), (x3, y3), (x4, y4), (x5, y5), (x6, y6)) = R + return [(x3, y3), (x1, y1), (x2, y2), (x5, y5), (x6, y6), (x4, y4)] for R in zip(*M): - for c1,c2 in product([1,2,3],repeat=2): - Mb.append(t2(c2,t1(c1,R))) + for c1, c2 in product([1, 2, 3], repeat=2): + Mb.append(t2(c2, t1(c1, R))) for R in zip(*M2): - for c2 in [1,2,3]: - Mb.append(t2(c2,R)) + for c2 in [1, 2, 3]: + Mb.append(t2(c2, R)) return G, Mb @@ -3873,23 +3741,17 @@ def DM_55_7_1(): sage: _ = designs.difference_matrix(55,7) # needs sage.rings.finite_rings """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(55) - M = [ - [ 1 , 7 , 14 , 19 , 28 , 33 , 40 , 46 , 50], - [ 2 , 13 , 25 , 38 , 52 , 12 , 20 , 32 , 45], - [ 39 , 6 , 8 , 26 , 24 , 51 , 11 , 34 , 37], - [ 54 , 48 , 41 , 36 , 27 , 22 , 15 , 9 , 5], - [ 53 , 42 , 30 , 17 , 3 , 43 , 35 , 23 , 10], - [ 16 , 49 , 47 , 29 , 31 , 4 , 44 , 21 , 18] - ] + M = [[1, 7, 14, 19, 28, 33, 40, 46, 50], [2, 13, 25, 38, 52, 12, 20, 32, 45], [39, 6, 8, 26, 24, 51, 11, 34, 37], [54, 48, 41, 36, 27, 22, 15, 9, 5], [53, 42, 30, 17, 3, 43, 35, 23, 10], [16, 49, 47, 29, 31, 4, 44, 21, 18]] - Mb = [[0,0,0,0,0,0,0]] + Mb = [[0, 0, 0, 0, 0, 0, 0]] for R in zip(*M): R = list(R) for c in range(6): - Mb.append(cyclic_shift(R,c)+[0]) + Mb.append(cyclic_shift(R, c) + [0]) return G, Mb @@ -3913,31 +3775,23 @@ def DM_56_8_1(): sage: _ = designs.difference_matrix(56,8) # needs sage.rings.finite_rings """ from sage.rings.finite_rings.finite_field_constructor import FiniteField - F8 = FiniteField(8,'z') + + F8 = FiniteField(8, 'z') F7 = FiniteField(7) G = F8.cartesian_product(F7) w = F8.primitive_element() - assert w**3 == w+1 + assert w**3 == w + 1 - M = [ - [(0,0), (w**0,0), (w**1,0), (w**2,0), (w**3,0), (w**4,0), (w**5,0), (w**6,0)], - [(0,1), (w**1,6), (w**2,1), (w**3,1), (w**4,6), (w**5,1), (w**6,6), (w**0,6)], - [(0,4), (w**2,3), (w**3,4), (w**4,4), (w**5,3), (w**6,4), (w**0,3), (w**1,3)], - [(0,2), (w**3,5), (w**4,2), (w**5,2), (w**6,5), (w**0,2), (w**1,5), (w**2,5)], - [(0,2), (w**4,5), (w**5,2), (w**6,2), (w**0,5), (w**1,2), (w**2,5), (w**3,5)], - [(0,4), (w**5,3), (w**6,4), (w**0,4), (w**1,3), (w**2,4), (w**3,3), (w**4,3)], - [(0,1), (w**6,6), (w**0,1), (w**1,1), (w**2,6), (w**3,1), (w**4,6), (w**5,6)], - [(1,0), ( 1,0), ( 1,0), ( 1,0), ( 1,0), ( 1,0), ( 1,0), ( 1,0)] - ] + M = [[(0, 0), (w**0, 0), (w**1, 0), (w**2, 0), (w**3, 0), (w**4, 0), (w**5, 0), (w**6, 0)], [(0, 1), (w**1, 6), (w**2, 1), (w**3, 1), (w**4, 6), (w**5, 1), (w**6, 6), (w**0, 6)], [(0, 4), (w**2, 3), (w**3, 4), (w**4, 4), (w**5, 3), (w**6, 4), (w**0, 3), (w**1, 3)], [(0, 2), (w**3, 5), (w**4, 2), (w**5, 2), (w**6, 5), (w**0, 2), (w**1, 5), (w**2, 5)], [(0, 2), (w**4, 5), (w**5, 2), (w**6, 2), (w**0, 5), (w**1, 2), (w**2, 5), (w**3, 5)], [(0, 4), (w**5, 3), (w**6, 4), (w**0, 4), (w**1, 3), (w**2, 4), (w**3, 3), (w**4, 3)], [(0, 1), (w**6, 6), (w**0, 1), (w**1, 1), (w**2, 6), (w**3, 1), (w**4, 6), (w**5, 6)], [(1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0)]] Mb = [] for R in zip(*M): for _ in range(7): Mb.append(R) - (x1,y1),(x2,y2),(x3,y3),(x4,y4),(x5,y5),(x6,y6),(x7,y7),(x8,y8) = R - R = [(w*x7,y7), (w*x1,y1), (w*x2,y2), (w*x3,y3), (w*x4,y4), (w*x5,y5), (w*x6,y6), (w*x8,y8)] + (x1, y1), (x2, y2), (x3, y3), (x4, y4), (x5, y5), (x6, y6), (x7, y7), (x8, y8) = R + R = [(w * x7, y7), (w * x1, y1), (w * x2, y2), (w * x3, y3), (w * x4, y4), (w * x5, y5), (w * x6, y6), (w * x8, y8)] return G, Mb @@ -3960,13 +3814,14 @@ def DM_57_8_1(): sage: _ = designs.difference_matrix(57,8) # needs sage.rings.finite_rings sage.schemes """ - M = orthogonal_array(8,8) - M = [R for R in M if any(x != R[0] for x in R)] # removing the 0..0, 1..1, 7..7 rows. - B = (1,6,7,9,19,38,42,49) # base block of a (57,8,1) BIBD + M = orthogonal_array(8, 8) + M = [R for R in M if any(x != R[0] for x in R)] # removing the 0..0, 1..1, 7..7 rows. + B = (1, 6, 7, 9, 19, 38, 42, 49) # base block of a (57,8,1) BIBD M = [[B[x] for x in R] for R in M] - M.append([0]*8) + M.append([0] * 8) from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(57) return G, M @@ -3998,27 +3853,23 @@ def DM_60_6_1(): sage: _ = designs.difference_matrix(60,6) """ - M60 = [[(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)], - [(1, 10), (1, 6), (0, 17), (0, 7), (1, 5), (0, 9), (0, 3), (1, 13), (1, 17), (0, 13)], - [(1, 22), (1, 1), (1, 8), (0, 9), (1, 21), (1, 29), (1, 0), (0, 2), (0, 12), (1, 15)], - [(1, 24), (1, 1), (0, 14), (0, 0), (0, 16), (0, 18), (0, 8), (0, 28), (0, 17), (0, 7)], - [(0, 17), (0, 7), (0, 20), (0, 1), (1, 4), (0, 26), (0, 19), (0, 28), (1, 21), (0, 6)], - [(1, 14), (1, 9), (0, 10), (0, 27), (1, 20), (0, 11), (0, 13), (1, 12), (0, 28), (1, 18)]] + M60 = [[(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)], [(1, 10), (1, 6), (0, 17), (0, 7), (1, 5), (0, 9), (0, 3), (1, 13), (1, 17), (0, 13)], [(1, 22), (1, 1), (1, 8), (0, 9), (1, 21), (1, 29), (1, 0), (0, 2), (0, 12), (1, 15)], [(1, 24), (1, 1), (0, 14), (0, 0), (0, 16), (0, 18), (0, 8), (0, 28), (0, 17), (0, 7)], [(0, 17), (0, 7), (0, 20), (0, 1), (1, 4), (0, 26), (0, 19), (0, 28), (1, 21), (0, 6)], [(1, 14), (1, 9), (0, 10), (0, 27), (1, 20), (0, 11), (0, 13), (1, 12), (0, 28), (1, 18)]] from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic from sage.categories.cartesian_product import cartesian_product - G = cartesian_product((AdditiveCyclic(2),AdditiveCyclic(30))) + + G = cartesian_product((AdditiveCyclic(2), AdditiveCyclic(30))) M60b = [] - onezero = G((1,0)) + onezero = G((1, 0)) for R in zip(*M60): - a,b,c,d,e,f = map(G,R) - M60b.append([a,b,c,d,e,f]) - M60b.append([c,a,b,e,f,d]) - M60b.append([b,c,a,f,d,e]) - M60b.append([-d,-e,-f,-a+onezero,-b+onezero,-c+onezero]) - M60b.append([-e,-f,-d,-c+onezero,-a+onezero,-b+onezero]) - M60b.append([-f,-d,-e,-b+onezero,-c+onezero,-a+onezero]) + a, b, c, d, e, f = map(G, R) + M60b.append([a, b, c, d, e, f]) + M60b.append([c, a, b, e, f, d]) + M60b.append([b, c, a, f, d, e]) + M60b.append([-d, -e, -f, -a + onezero, -b + onezero, -c + onezero]) + M60b.append([-e, -f, -d, -c + onezero, -a + onezero, -b + onezero]) + M60b.append([-f, -d, -e, -b + onezero, -c + onezero, -a + onezero]) return G, M60b @@ -4046,28 +3897,19 @@ def DM_75_8_1(): F3 = FiniteField(3) F5 = FiniteField(5) - G = cartesian_product((F3,F5,F5)) + G = cartesian_product((F3, F5, F5)) - M = [ - [(2,0,0), (0,0,0), (0,0,0), (1,0,0), (0,0,0), (1,0,0), (1,0,0), (0,0,0)], - [(0,2,3), (1,4,4), (1,1,3), (1,0,4), (2,4,3), (0,0,3), (1,4,4), (0,0,0)], - [(1,3,2), (2,1,1), (1,4,0), (0,3,0), (1,0,4), (2,4,1), (0,1,2), (0,0,0)], - [(0,2,4), (1,3,1), (2,0,2), (0,0,1), (2,4,0), (1,2,2), (0,0,0), (0,0,0)], - [(1,1,2), (2,2,3), (0,3,1), (1,4,2), (2,1,0), (1,4,3), (2,4,4), (0,0,0)], - [(0,1,4), (0,4,4), (2,4,1), (1,3,0), (1,3,1), (2,0,0), (2,4,0), (0,0,0)], - [(0,4,4), (2,0,1), (2,3,3), (2,3,2), (0,0,2), (2,1,2), (1,4,2), (0,0,0)], - [(2,4,2), (2,4,1), (2,3,1), (1,2,2), (1,3,0), (0,0,2), (2,4,2), (0,0,0)] - ] + M = [[(2, 0, 0), (0, 0, 0), (0, 0, 0), (1, 0, 0), (0, 0, 0), (1, 0, 0), (1, 0, 0), (0, 0, 0)], [(0, 2, 3), (1, 4, 4), (1, 1, 3), (1, 0, 4), (2, 4, 3), (0, 0, 3), (1, 4, 4), (0, 0, 0)], [(1, 3, 2), (2, 1, 1), (1, 4, 0), (0, 3, 0), (1, 0, 4), (2, 4, 1), (0, 1, 2), (0, 0, 0)], [(0, 2, 4), (1, 3, 1), (2, 0, 2), (0, 0, 1), (2, 4, 0), (1, 2, 2), (0, 0, 0), (0, 0, 0)], [(1, 1, 2), (2, 2, 3), (0, 3, 1), (1, 4, 2), (2, 1, 0), (1, 4, 3), (2, 4, 4), (0, 0, 0)], [(0, 1, 4), (0, 4, 4), (2, 4, 1), (1, 3, 0), (1, 3, 1), (2, 0, 0), (2, 4, 0), (0, 0, 0)], [(0, 4, 4), (2, 0, 1), (2, 3, 3), (2, 3, 2), (0, 0, 2), (2, 1, 2), (1, 4, 2), (0, 0, 0)], [(2, 4, 2), (2, 4, 1), (2, 3, 1), (1, 2, 2), (1, 3, 0), (0, 0, 2), (2, 4, 2), (0, 0, 0)]] for i in range(8): - M[i].extend(M[7-i][:7]) + M[i].extend(M[7 - i][:7]) Mb = [] for R in zip(*M): for x in range(5): - V = [(0,0,x), (0,x,0), (0,x,2*x),(0,2*x,2*x), (0,3*x,3*x), (0,4*x,3*x), (0,4*x,0), (0,0,4*x)] - Mb.append([G(e)+G(ee) for e,ee in zip(R,V)]) + V = [(0, 0, x), (0, x, 0), (0, x, 2 * x), (0, 2 * x, 2 * x), (0, 3 * x, 3 * x), (0, 4 * x, 3 * x), (0, 4 * x, 0), (0, 0, 4 * x)] + Mb.append([G(e) + G(ee) for e, ee in zip(R, V)]) return G, Mb @@ -4090,13 +3932,14 @@ def DM_273_17_1(): sage: _ = designs.difference_matrix(273,17) # needs sage.schemes """ - M = orthogonal_array(17,17) - M = [R for R in M if any(x != R[0] for x in R)] # removing the 0..0, 1..1, ... rows. - B = (1,2,4,8,16,32,64,91,117,128,137,182,195,205,234,239,256) # (273,17,1) difference set + M = orthogonal_array(17, 17) + M = [R for R in M if any(x != R[0] for x in R)] # removing the 0..0, 1..1, ... rows. + B = (1, 2, 4, 8, 16, 32, 64, 91, 117, 128, 137, 182, 195, 205, 234, 239, 256) # (273,17,1) difference set M = [[B[x] for x in R] for R in M] - M.append([0]*17) + M.append([0] * 17) from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(273) return G, M @@ -4119,47 +3962,44 @@ def DM_993_32_1(): sage: _ = designs.difference_matrix(993,32) # needs sage.schemes """ - M = orthogonal_array(32,32) - M = [R for R in M if any(x != R[0] for x in R)] # removing the 0..0, 1..1, ... rows. - B = (0,74,81,126,254,282,308,331,344,375,387,409,525,563, # (993,32,1) difference set - 572,611,631,661,694,702,734,763,798,809,814,851,906, - 908,909,923,927,933) + M = orthogonal_array(32, 32) + M = [R for R in M if any(x != R[0] for x in R)] # removing the 0..0, 1..1, ... rows. + B = (0, 74, 81, 126, 254, 282, 308, 331, 344, 375, 387, 409, 525, 563, 572, 611, 631, 661, 694, 702, 734, 763, 798, 809, 814, 851, 906, 908, 909, 923, 927, 933) # (993,32,1) difference set M = [[B[x] for x in R] for R in M] - M.append([0]*32) + M.append([0] * 32) from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic + G = AdditiveCyclic(993) return G, M DM = { - (12 ,1) : (6 ,DM_12_6_1), - (21 ,1) : (6 ,DM_21_6_1), - (24 ,1) : (8 ,DM_24_8_1), - (28 ,1) : (6 ,DM_28_6_1), - (33 ,1) : (6 ,DM_33_6_1), - (35 ,1) : (6 ,DM_35_6_1), - (36 ,1) : (9 ,DM_36_9_1), - (39 ,1) : (6 ,DM_39_6_1), - (44 ,1) : (6 ,DM_44_6_1), - (45 ,1) : (7 ,DM_45_7_1), - (48 ,1) : (9 ,DM_48_9_1), - (51 ,1) : (6 ,DM_51_6_1), - (52 ,1) : (6 ,DM_52_6_1), - (55 ,1) : (7 ,DM_55_7_1), - (56 ,1) : (8 ,DM_56_8_1), - (57 ,1) : (8 ,DM_57_8_1), - (60 ,1) : (6 ,DM_60_6_1), - (75 ,1) : (8 ,DM_75_8_1), - (273,1) : (17,DM_273_17_1), - (993,1) : (32,DM_993_32_1), - } + (12, 1): (6, DM_12_6_1), + (21, 1): (6, DM_21_6_1), + (24, 1): (8, DM_24_8_1), + (28, 1): (6, DM_28_6_1), + (33, 1): (6, DM_33_6_1), + (35, 1): (6, DM_35_6_1), + (36, 1): (9, DM_36_9_1), + (39, 1): (6, DM_39_6_1), + (44, 1): (6, DM_44_6_1), + (45, 1): (7, DM_45_7_1), + (48, 1): (9, DM_48_9_1), + (51, 1): (6, DM_51_6_1), + (52, 1): (6, DM_52_6_1), + (55, 1): (7, DM_55_7_1), + (56, 1): (8, DM_56_8_1), + (57, 1): (8, DM_57_8_1), + (60, 1): (6, DM_60_6_1), + (75, 1): (8, DM_75_8_1), + (273, 1): (17, DM_273_17_1), + (993, 1): (32, DM_993_32_1), +} # Create the list of DM for the documentation -_all_l = sorted(set(l for v,l in DM.keys())) -LIST_OF_DM = "\n".join(r" - `\lambda={}`:\n ".format(l) + - ", ".join("`({},{},{})`".format(v,k,l) for (v,_),(k,__) in sorted(DM.items()) if _ == l) - for l in _all_l) +_all_l = sorted(set(l for v, l in DM.keys())) +LIST_OF_DM = "\n".join(r" - `\lambda={}`:\n ".format(l) + ", ".join("`({},{},{})`".format(v, k, l) for (v, _), (k, __) in sorted(DM.items()) if _ == l) for l in _all_l) def RBIBD_120_8_1(): @@ -4208,11 +4048,12 @@ def RBIBD_120_8_1(): sage: _ = designs.balanced_incomplete_block_design(120,8) # needs sage.modules """ from .incidence_structures import IncidenceStructure + n = 273 # Base block of a cyclic BIBD(273,16,1) - B = [1,2,4,8,16,32,64,91,117,128,137,182,195,205,234,239,256] - BIBD = [[(x+c) % n for x in B] for c in range(n)] + B = [1, 2, 4, 8, 16, 32, 64, 91, 117, 128, 137, 182, 195, 205, 234, 239, 256] + BIBD = [[(x + c) % n for x in B] for c in range(n)] # A (precomputed) set that every block of the BIBD intersects on 0 or 2 points hyperoval = [128, 192, 194, 4, 262, 140, 175, 48, 81, 180, 245, 271, 119, 212, 249, 189, 62, 255] @@ -4233,11 +4074,11 @@ def RBIBD_120_8_1(): BIBD = new_BIBD - r = {v:i for i,v in enumerate(x for x in range(n) if x not in hyperoval)} - BIBD = [[r[x] for x in B] for B in BIBD ] + r = {v: i for i, v in enumerate(x for x in range(n) if x not in hyperoval)} + BIBD = [[r[x] for x in B] for B in BIBD] equiv = [[r[x] for x in B] for B in equiv] - BIBD = IncidenceStructure(range(255),BIBD) + BIBD = IncidenceStructure(range(255), BIBD) M = BIBD.incidence_matrix() equiv = [[M.nonzero_positions_in_row(x) for x in S] for S in equiv] @@ -4284,43 +4125,238 @@ def BIBD_45_9_8(from_code=False): if from_code: from sage.coding.code_constructions import ExtendedQuadraticResidueCode from sage.rings.finite_rings.finite_field_constructor import FiniteField - C = ExtendedQuadraticResidueCode(47,FiniteField(2)) - min_weight = [map(int,x)[3:] for x in C - if x.hamming_weight() == 12 and - x[0] == 1 and x[1] == 1 and x[2] == 1] - return [[i for i,v in enumerate(x) if v] for x in min_weight] + C = ExtendedQuadraticResidueCode(47, FiniteField(2)) + min_weight = [map(int, x)[3:] for x in C if x.hamming_weight() == 12 and x[0] == 1 and x[1] == 1 and x[2] == 1] + + return [[i for i, v in enumerate(x) if v] for x in min_weight] from sage.rings.integer import Integer - B = ['acs1v', 'l8lsx', '4ga1vw', '6q9amr', 'nb3ui8', 'sgjocw', '11vsoy2', '28791ts', '30tm1z8', '38ktnwh', - '3saz8jk', '41qkwme', '4g3jxmt', '56qhwuc', '711w45k', '8nz2gx4', '903uha8', '957z8dc', '9wejz7k', 'fs905ic', - 'ftzzh28', 'gb4g448', 'hvreal0', 'nqlhxu8', 'rmluazm', 'vlyqayx', 'w52detk', 'zisjk02', 'zw9811c', '10i7qfl1', - '13ibtse8', '1rbsbvvc', '1sdy0o5c', '1z14s09e', '2nbz5a80', '2uuhib2a', '2wkn4r9d', '3iaaat5w', '3iiwq53s', - '3j9ubv43', '3mpxpngz', '3qamndc0', '3saomh3t', '3uhhi5cw', '4334rx4x', '4dxy3xts', '4tn9w2z1', '4vlr2h00', - '59f1meqm', '59h6udc1', '5cep4nc0', '5ddcxsw2', '70msua7k', '70ofjm82', '70p8jig0', '721o664h', '72jutmfk', - '74jowaad', '78ihrfgo', '7meufihs', '7wv5mtxj', '84akgj0w', '8m9vyb60', '8s0c6p04', '8soi6m8g', '9kawy0ow', - 'awnpg9a8', 'biu8xww0', 'e1lptwxx', 'e79x2we8', 'eh0t1q9y', 'eh65daci', 'ehxytwjk', 'extc1udk', 'f4toqhpg', - 'fgeqg214', 'ftiem9lk', 'fw77kcnc', 'h5kt9cf4', 'hjwhwym8', 'hz8d60xs', 'jb6bp0g0', 'l22bzw1w', 'l3pj9hq8', - 'lbj1fubp', 'lxal1lk2', 's27vq70q', 's2bb5mki', 's2w95y0w', 's3cek9og', 's4703jk4', 's67g5qf5', 's8kgdkat', - 'sckruupw', 'se4vzkao', 'si57d0vl', 'sjhd20i8', 'sqne2mf6', 'sxtju9ds', 'ttd710kw', 'ttkayw5e', 'u96baslc', - 'vtdhrbj5', 'y79i706c', 'zycu7tsa', '10uwf8sh4', '11boo6mmc', '12sxyeebs', '163xyccg3', '16cpesdfk', - '18q18bpc0', '1k4hvvgq4', '1k5f63ok4', '1k5olig3u', '1k6fsqalm', '1kacr2gi8', '1kcc6rzu1', '1kkpot632', - '1kwdghpts', '1l2644l68', '1l3yxmj9s', '1m04wgmyo', '1mtm16z5s', '1np6u1q0w', '1nuo1tbfk', '1oy4n1mo0', - '1r5lsxju0', '1sx57vdfq', '1v4j675ds', '1y5oldkzm', '1ydfr4jno', '1ylc38ah4', '1z14mw0td', '223vcx1xc', - '26xq9hn29', '2c7wa6r0w', '2cbc8qbcw', '2jn9ojll5', '2qjlkoz69', '2tr1zn5ds', '348vfurgh', '348vlaoc0', - '348ynt0qx', '34ahl37ds', '34b3cgc8y', '34ooa1ix0', '34r4ejl82', '35p5m8r28', '360i7uazl', '36289j761', - '3650mzlzg', '36aev2c00', '36noxmex2', '36vlw3k3k', '37rw4rghs', '37t554ikq', '387avhseb', '3b9o5lbwi', - '3ewmteale', '3ibz0r8n4', '3id5iv5ky', '3ihxwcvvc', '3k5k1k174', '3pau9ujnl', '3wf1e2dck', '43rfm4du8', - '47pqff6yo', '4e2i4y684', '4hio30v0o', '4odb0lr5s', '4odcmkvt0', '4p94elixc', '4p9zffz0k', '4qciqf9mp', - '4ywafln9c', '5hf4nw08w', '68ijggco4', '68jq73cxs', '68maap98g', '68prdfhqg', '68qm8divl', '691ibd2ps', - '69dbnd8ur', '69esd0djg', '69w6eo0sh', '6ad6zcetk', '6aonwwkjk', '6aozhe8zl', '6cvyitslw', '6dr7i6olg', - '6fibvzxtw', '6fmd4bv28', '6gmqtkr9e', '6j14n6n7k', '6miukvtc1', '6mjvifon4', '6mormb3fm', '6mr9hvhna', - '6q533lm6w', '6rsie7cbk', '6tjgpxic0', '70k7ao9m0', '7103zqlvk', '71i1x52bm', '7447g0dfw', '7sogja9z4', - '7up5z9m9u', '7w7esu6fm', '7zmqtlrpd', '81tsbnzsw', '8kofgi1he', '8mhi35nc1', '9cv1pjiaw', '9d6ef1dah', - '9dftsor9c', '9du8c1vcw', '9jr5vsnj4', 'a8b405mps', 'ajqhmxkj4', 'ax2xsvfic'] + + B = [ + 'acs1v', + 'l8lsx', + '4ga1vw', + '6q9amr', + 'nb3ui8', + 'sgjocw', + '11vsoy2', + '28791ts', + '30tm1z8', + '38ktnwh', + '3saz8jk', + '41qkwme', + '4g3jxmt', + '56qhwuc', + '711w45k', + '8nz2gx4', + '903uha8', + '957z8dc', + '9wejz7k', + 'fs905ic', + 'ftzzh28', + 'gb4g448', + 'hvreal0', + 'nqlhxu8', + 'rmluazm', + 'vlyqayx', + 'w52detk', + 'zisjk02', + 'zw9811c', + '10i7qfl1', + '13ibtse8', + '1rbsbvvc', + '1sdy0o5c', + '1z14s09e', + '2nbz5a80', + '2uuhib2a', + '2wkn4r9d', + '3iaaat5w', + '3iiwq53s', + '3j9ubv43', + '3mpxpngz', + '3qamndc0', + '3saomh3t', + '3uhhi5cw', + '4334rx4x', + '4dxy3xts', + '4tn9w2z1', + '4vlr2h00', + '59f1meqm', + '59h6udc1', + '5cep4nc0', + '5ddcxsw2', + '70msua7k', + '70ofjm82', + '70p8jig0', + '721o664h', + '72jutmfk', + '74jowaad', + '78ihrfgo', + '7meufihs', + '7wv5mtxj', + '84akgj0w', + '8m9vyb60', + '8s0c6p04', + '8soi6m8g', + '9kawy0ow', + 'awnpg9a8', + 'biu8xww0', + 'e1lptwxx', + 'e79x2we8', + 'eh0t1q9y', + 'eh65daci', + 'ehxytwjk', + 'extc1udk', + 'f4toqhpg', + 'fgeqg214', + 'ftiem9lk', + 'fw77kcnc', + 'h5kt9cf4', + 'hjwhwym8', + 'hz8d60xs', + 'jb6bp0g0', + 'l22bzw1w', + 'l3pj9hq8', + 'lbj1fubp', + 'lxal1lk2', + 's27vq70q', + 's2bb5mki', + 's2w95y0w', + 's3cek9og', + 's4703jk4', + 's67g5qf5', + 's8kgdkat', + 'sckruupw', + 'se4vzkao', + 'si57d0vl', + 'sjhd20i8', + 'sqne2mf6', + 'sxtju9ds', + 'ttd710kw', + 'ttkayw5e', + 'u96baslc', + 'vtdhrbj5', + 'y79i706c', + 'zycu7tsa', + '10uwf8sh4', + '11boo6mmc', + '12sxyeebs', + '163xyccg3', + '16cpesdfk', + '18q18bpc0', + '1k4hvvgq4', + '1k5f63ok4', + '1k5olig3u', + '1k6fsqalm', + '1kacr2gi8', + '1kcc6rzu1', + '1kkpot632', + '1kwdghpts', + '1l2644l68', + '1l3yxmj9s', + '1m04wgmyo', + '1mtm16z5s', + '1np6u1q0w', + '1nuo1tbfk', + '1oy4n1mo0', + '1r5lsxju0', + '1sx57vdfq', + '1v4j675ds', + '1y5oldkzm', + '1ydfr4jno', + '1ylc38ah4', + '1z14mw0td', + '223vcx1xc', + '26xq9hn29', + '2c7wa6r0w', + '2cbc8qbcw', + '2jn9ojll5', + '2qjlkoz69', + '2tr1zn5ds', + '348vfurgh', + '348vlaoc0', + '348ynt0qx', + '34ahl37ds', + '34b3cgc8y', + '34ooa1ix0', + '34r4ejl82', + '35p5m8r28', + '360i7uazl', + '36289j761', + '3650mzlzg', + '36aev2c00', + '36noxmex2', + '36vlw3k3k', + '37rw4rghs', + '37t554ikq', + '387avhseb', + '3b9o5lbwi', + '3ewmteale', + '3ibz0r8n4', + '3id5iv5ky', + '3ihxwcvvc', + '3k5k1k174', + '3pau9ujnl', + '3wf1e2dck', + '43rfm4du8', + '47pqff6yo', + '4e2i4y684', + '4hio30v0o', + '4odb0lr5s', + '4odcmkvt0', + '4p94elixc', + '4p9zffz0k', + '4qciqf9mp', + '4ywafln9c', + '5hf4nw08w', + '68ijggco4', + '68jq73cxs', + '68maap98g', + '68prdfhqg', + '68qm8divl', + '691ibd2ps', + '69dbnd8ur', + '69esd0djg', + '69w6eo0sh', + '6ad6zcetk', + '6aonwwkjk', + '6aozhe8zl', + '6cvyitslw', + '6dr7i6olg', + '6fibvzxtw', + '6fmd4bv28', + '6gmqtkr9e', + '6j14n6n7k', + '6miukvtc1', + '6mjvifon4', + '6mormb3fm', + '6mr9hvhna', + '6q533lm6w', + '6rsie7cbk', + '6tjgpxic0', + '70k7ao9m0', + '7103zqlvk', + '71i1x52bm', + '7447g0dfw', + '7sogja9z4', + '7up5z9m9u', + '7w7esu6fm', + '7zmqtlrpd', + '81tsbnzsw', + '8kofgi1he', + '8mhi35nc1', + '9cv1pjiaw', + '9d6ef1dah', + '9dftsor9c', + '9du8c1vcw', + '9jr5vsnj4', + 'a8b405mps', + 'ajqhmxkj4', + 'ax2xsvfic', + ] B = [Integer(x, base=36) for x in B] - return [[i for i in range(45) if x & (1 << i)] - for x in B] + return [[i for i in range(45) if x & (1 << i)] for x in B] def BIBD_66_6_1(): @@ -4337,13 +4373,7 @@ def BIBD_66_6_1(): sage: BalancedIncompleteBlockDesign(66, BIBD_66_6_1()) (66,6,1)-Balanced Incomplete Block Design """ - BIBD = [frozenset([(x+i*5) % 65 if x < 65 else x for x in b]) - for i in range(65) - for b in - [[6, 38, 42, 46, 53, 62], [9, 11, 21, 49, 56, 60], [18, 31, 37, 44, 52, 60], - [0, 12, 29, 46, 51, 63], [0, 6, 21, 30, 43, 48], [4, 17, 22, 36, 47, 59], - [0, 1, 2, 3, 4, 65], [23, 39, 44, 53, 59, 63], [12, 22, 28, 48, 55, 60], - [19, 22, 25, 40, 49, 50], [4, 30, 37, 50, 58, 61]]] + BIBD = [frozenset([(x + i * 5) % 65 if x < 65 else x for x in b]) for i in range(65) for b in [[6, 38, 42, 46, 53, 62], [9, 11, 21, 49, 56, 60], [18, 31, 37, 44, 52, 60], [0, 12, 29, 46, 51, 63], [0, 6, 21, 30, 43, 48], [4, 17, 22, 36, 47, 59], [0, 1, 2, 3, 4, 65], [23, 39, 44, 53, 59, 63], [12, 22, 28, 48, 55, 60], [19, 22, 25, 40, 49, 50], [4, 30, 37, 50, 58, 61]]] return [list(t) for t in frozenset(BIBD)] @@ -4361,13 +4391,7 @@ def BIBD_76_6_1(): sage: BalancedIncompleteBlockDesign(76, BIBD_76_6_1()) (76,6,1)-Balanced Incomplete Block Design """ - BIBD = [frozenset([(x+i*4) % 76 if x < 76 else x for x in b]) - for i in range(76) - for b in - [[3, 5, 21, 33, 72, 73], [4, 37, 57, 58, 64, 75], [7, 14, 44, 47, 59, 63], - [10, 20, 61, 63, 71, 72], [13, 26, 30, 39, 45, 67], [11, 21, 25, 30, 55, 58], - [2, 5, 34, 52, 54, 70], [6, 8, 29, 48, 70, 71], [10, 15, 36, 41, 44, 56], - [0, 6, 13, 27, 44, 72]]] + BIBD = [frozenset([(x + i * 4) % 76 if x < 76 else x for x in b]) for i in range(76) for b in [[3, 5, 21, 33, 72, 73], [4, 37, 57, 58, 64, 75], [7, 14, 44, 47, 59, 63], [10, 20, 61, 63, 71, 72], [13, 26, 30, 39, 45, 67], [11, 21, 25, 30, 55, 58], [2, 5, 34, 52, 54, 70], [6, 8, 29, 48, 70, 71], [10, 15, 36, 41, 44, 56], [0, 6, 13, 27, 44, 72]]] return [list(t) for t in frozenset(BIBD)] @@ -4385,12 +4409,7 @@ def BIBD_96_6_1(): sage: BalancedIncompleteBlockDesign(96, BIBD_96_6_1()) (96,6,1)-Balanced Incomplete Block Design """ - BIBD = [frozenset([(x+i*2) % 96 if x < 96 else x for x in b]) - for i in range(96) - for b in - [[3, 13, 32, 47, 68, 87], [9, 36, 70, 75, 81, 88], [22, 52, 72, 76, 78, 79], - [15, 23, 41, 43, 46, 58], [7, 8, 21, 57, 66, 94], [8, 22, 30, 51, 55, 93], - [15, 31, 47, 63, 79, 95], [2, 18, 34, 50, 66, 82]]] + BIBD = [frozenset([(x + i * 2) % 96 if x < 96 else x for x in b]) for i in range(96) for b in [[3, 13, 32, 47, 68, 87], [9, 36, 70, 75, 81, 88], [22, 52, 72, 76, 78, 79], [15, 23, 41, 43, 46, 58], [7, 8, 21, 57, 66, 94], [8, 22, 30, 51, 55, 93], [15, 31, 47, 63, 79, 95], [2, 18, 34, 50, 66, 82]]] return [list(t) for t in frozenset(BIBD)] @@ -4407,15 +4426,9 @@ def BIBD_106_6_1(): sage: BalancedIncompleteBlockDesign(106, BIBD_106_6_1()) (106,6,1)-Balanced Incomplete Block Design """ - bibd = [((0,0), ( 1,0), ( 3,0), (11,0), (38,0), ( 0,1)), - ((0,0), (13,0), (30,0), (23,1), (35,1), (51,1)), - ((0,0), ( 5,0), (19,0), (25,0), (36,1), (39,1)), - ((0,0), ( 4,0), (28,1), (30,1), (37,1), (47,1)), - ((0,0), ( 7,0), (29,0), ( 8,1), (16,1), (48,1)), - ((0,0), ( 2,1), ( 7,1), (25,1), (29,1), (49,1)), - ((0,0), ( 9,0), (21,0), (12,1), (13,1), (27,1))] + bibd = [((0, 0), (1, 0), (3, 0), (11, 0), (38, 0), (0, 1)), ((0, 0), (13, 0), (30, 0), (23, 1), (35, 1), (51, 1)), ((0, 0), (5, 0), (19, 0), (25, 0), (36, 1), (39, 1)), ((0, 0), (4, 0), (28, 1), (30, 1), (37, 1), (47, 1)), ((0, 0), (7, 0), (29, 0), (8, 1), (16, 1), (48, 1)), ((0, 0), (2, 1), (7, 1), (25, 1), (29, 1), (49, 1)), ((0, 0), (9, 0), (21, 0), (12, 1), (13, 1), (27, 1))] - return [[((x+i) % 53+y*53) for x,y in B] for i in range(53) for B in bibd] + return [[((x + i) % 53 + y * 53) for x, y in B] for i in range(53) for B in bibd] def BIBD_111_6_1(): @@ -4433,19 +4446,10 @@ def BIBD_111_6_1(): """ from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from .incidence_structures import IncidenceStructure - bibd = [(( 0, 0), ( 1, 0), ( 3, 0), ( 7, 0), (17, 0), ( 0, 1)), - (( 0, 0), ( 5, 0), (19, 1), (28, 1), (10, 2), (30, 2)), - (( 5, 0), (33, 0), (13, 1), (34, 1), (19, 2), ( 7, 2)), - (( 9, 0), (27, 0), (16, 1), (11, 1), (12, 2), (36, 2)), - ((10, 0), (23, 0), (26, 1), ( 8, 1), ( 1, 2), ( 6, 2)), - ((13, 0), (24, 0), (19, 1), (18, 1), ( 5, 2), (32, 2)), - ((26, 0), (34, 0), ( 1, 1), ( 7, 1), (10, 2), (33, 2))] - gens = lambda B: [frozenset(((x * 10) % 37, (y + 1) % 3) - for x, y in B), - frozenset(((x + 1) % 37, y) - for x, y in B)] - bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], - successors=gens) + + bibd = [((0, 0), (1, 0), (3, 0), (7, 0), (17, 0), (0, 1)), ((0, 0), (5, 0), (19, 1), (28, 1), (10, 2), (30, 2)), ((5, 0), (33, 0), (13, 1), (34, 1), (19, 2), (7, 2)), ((9, 0), (27, 0), (16, 1), (11, 1), (12, 2), (36, 2)), ((10, 0), (23, 0), (26, 1), (8, 1), (1, 2), (6, 2)), ((13, 0), (24, 0), (19, 1), (18, 1), (5, 2), (32, 2)), ((26, 0), (34, 0), (1, 1), (7, 1), (10, 2), (33, 2))] + gens = lambda B: [frozenset(((x * 10) % 37, (y + 1) % 3) for x, y in B), frozenset(((x + 1) % 37, y) for x, y in B)] + bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], successors=gens) return IncidenceStructure(bibd)._blocks @@ -4463,18 +4467,11 @@ def BIBD_126_6_1(): (126,6,1)-Balanced Incomplete Block Design """ from itertools import product - bibd = [[((x+xx) % 5, (y+yy) % 5, (z+zz) % 5) for x,y,z in B] - for xx,yy,zz in product(range(5),repeat=3) - for B in - [[(0,0,1),(0,0,4),(1,2,2),(1,3,3),(4,2,1),(4,3,4)], - [(0,0,2),(0,0,3),(1,4,4),(1,1,1),(4,4,2),(4,1,3)], - [(0,4,3),(0,1,2),(2,2,0),(2,3,0),(3,3,2),(3,2,3)], - [(0,3,1),(0,2,4),(2,4,0),(2,1,0),(3,1,4),(3,4,1)]]] - bibd.extend([[(125,0,0), (0,x,y),(1,x,y),(2,x,y),(3,x,y),(4,x,y)] - for x,y in product(range(5),repeat=2)]) - return [[x+y*5+z*25 for x,y,z in B] - for B in bibd] + bibd = [[((x + xx) % 5, (y + yy) % 5, (z + zz) % 5) for x, y, z in B] for xx, yy, zz in product(range(5), repeat=3) for B in [[(0, 0, 1), (0, 0, 4), (1, 2, 2), (1, 3, 3), (4, 2, 1), (4, 3, 4)], [(0, 0, 2), (0, 0, 3), (1, 4, 4), (1, 1, 1), (4, 4, 2), (4, 1, 3)], [(0, 4, 3), (0, 1, 2), (2, 2, 0), (2, 3, 0), (3, 3, 2), (3, 2, 3)], [(0, 3, 1), (0, 2, 4), (2, 4, 0), (2, 1, 0), (3, 1, 4), (3, 4, 1)]]] + + bibd.extend([[(125, 0, 0), (0, x, y), (1, x, y), (2, x, y), (3, x, y), (4, x, y)] for x, y in product(range(5), repeat=2)]) + return [[x + y * 5 + z * 25 for x, y, z in B] for B in bibd] def BIBD_136_6_1(): @@ -4492,19 +4489,11 @@ def BIBD_136_6_1(): """ from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from .incidence_structures import IncidenceStructure - inf = (None,None) - bibd = [((0,0), ( 3,0), (15,0), (35,0), ( 6,2), (10,2)), - ((0,0), (22,0), (11,1), (30,1), ( 1,2), (18,2)), - ((0,0), ( 5,0), (18,1), (41,1), (13,2), (42,2)), - ((0,0), (11,0), (17,0), ( 4,2), ( 5,2), (28,2)), - ((0,0), ( 1,0), ( 0,1), (16,1), ( 0,2), (31,2)), - ( inf ,( 0,0), ( 9,0), (18,0), (27,0), (36,0))] - gens = lambda B: [frozenset(((x * 16) % 45,(y + 1) % 3) - if (x, y) != inf else inf for x, y in B), - frozenset(((x + 1) % 45,y) - if (x, y) != inf else inf for x, y in B)] - bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], - successors=gens) + + inf = (None, None) + bibd = [((0, 0), (3, 0), (15, 0), (35, 0), (6, 2), (10, 2)), ((0, 0), (22, 0), (11, 1), (30, 1), (1, 2), (18, 2)), ((0, 0), (5, 0), (18, 1), (41, 1), (13, 2), (42, 2)), ((0, 0), (11, 0), (17, 0), (4, 2), (5, 2), (28, 2)), ((0, 0), (1, 0), (0, 1), (16, 1), (0, 2), (31, 2)), (inf, (0, 0), (9, 0), (18, 0), (27, 0), (36, 0))] + gens = lambda B: [frozenset(((x * 16) % 45, (y + 1) % 3) if (x, y) != inf else inf for x, y in B), frozenset(((x + 1) % 45, y) if (x, y) != inf else inf for x, y in B)] + bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], successors=gens) return IncidenceStructure(bibd)._blocks @@ -4523,23 +4512,13 @@ def BIBD_141_6_1(): """ from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from .incidence_structures import IncidenceStructure + a = 'a' - inf = (None,None) - bibd = [((0,0), (16,0), (24,0), (24,1), (15,2), (25,2)), - ((0,0), ( 3,0), (26,0), (13,1), (33,1), (34,a)), - ((0,0), (13,0), (18,0), (15,1), ( 7,2), ( 0,a)), - ((0,0), ( 2,0), (14,1), (23,1), (26,a), (32,a)), - ((0,0), ( 4,0), (29,1), ( 6,2), ( 9,a), (20,a)), - ((0,0), ( 1,0), (12,2), ( 2,a), ( 4,a), (19,a)), - ( inf ,( 0,0), ( 7,0), (14,0), (21,0), (28,0)), - ( inf ,( 0,a), ( 7,a), (14,a), (21,a), (28,a))] - - gens = lambda B: [frozenset(((x * 16) % 35, (y + 1) % 3 if y != a else a) - if (x, y) != inf else inf for x, y in B), - frozenset(((x + 1) % 35, y) - if (x, y) != inf else inf for x, y in B)] - bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], - successors=gens) + inf = (None, None) + bibd = [((0, 0), (16, 0), (24, 0), (24, 1), (15, 2), (25, 2)), ((0, 0), (3, 0), (26, 0), (13, 1), (33, 1), (34, a)), ((0, 0), (13, 0), (18, 0), (15, 1), (7, 2), (0, a)), ((0, 0), (2, 0), (14, 1), (23, 1), (26, a), (32, a)), ((0, 0), (4, 0), (29, 1), (6, 2), (9, a), (20, a)), ((0, 0), (1, 0), (12, 2), (2, a), (4, a), (19, a)), (inf, (0, 0), (7, 0), (14, 0), (21, 0), (28, 0)), (inf, (0, a), (7, a), (14, a), (21, a), (28, a))] + + gens = lambda B: [frozenset(((x * 16) % 35, (y + 1) % 3 if y != a else a) if (x, y) != inf else inf for x, y in B), frozenset(((x + 1) % 35, y) if (x, y) != inf else inf for x, y in B)] + bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], successors=gens) return IncidenceStructure(bibd)._blocks @@ -4558,20 +4537,11 @@ def BIBD_171_6_1(): """ from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from .incidence_structures import IncidenceStructure - bibd = [(( 0,0), (19,0), (39,0), (41,0), (14,1), (38,2)), - (( 0,0), (21,0), (44,0), (48,0), (26,1), (11,2)), - (( 0,0), ( 1,0), (43,0), ( 8,2), (15,2), (44,2)), - (( 0,0), ( 3,0), (31,0), (23,1), (43,1), (36,2)), - (( 0,0), (40,0), (50,0), (11,1), (25,2), (34,2)), - (( 0,0), (12,0), ( 0,1), (27,1), ( 0,2), (18,2)), - ((37,0), (42,0), (31,1), ( 9,1), (46,2), ( 6,2))] - - gens = lambda B: [frozenset(((x * 7) % 57, (y + 1) % 3) - for x, y in B), - frozenset(((x + 1) % 57, y) - for x, y in B)] - bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], - successors=gens) + + bibd = [((0, 0), (19, 0), (39, 0), (41, 0), (14, 1), (38, 2)), ((0, 0), (21, 0), (44, 0), (48, 0), (26, 1), (11, 2)), ((0, 0), (1, 0), (43, 0), (8, 2), (15, 2), (44, 2)), ((0, 0), (3, 0), (31, 0), (23, 1), (43, 1), (36, 2)), ((0, 0), (40, 0), (50, 0), (11, 1), (25, 2), (34, 2)), ((0, 0), (12, 0), (0, 1), (27, 1), (0, 2), (18, 2)), ((37, 0), (42, 0), (31, 1), (9, 1), (46, 2), (6, 2))] + + gens = lambda B: [frozenset(((x * 7) % 57, (y + 1) % 3) for x, y in B), frozenset(((x + 1) % 57, y) for x, y in B)] + bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], successors=gens) return IncidenceStructure(bibd)._blocks @@ -4621,13 +4591,13 @@ def HigmanSimsDesign(): """ from sage.combinat.designs.block_design import WittDesign from .incidence_structures import IncidenceStructure + W = WittDesign(24) a, b = 0, 1 Wa = [set(B) for B in W if a in B and b not in B] Wb = [set(B) for B in W if b in B and a not in B] - H = [[i for i, A in enumerate(Wa) if len(A & B) != 2] - for B in Wb] + H = [[i for i, A in enumerate(Wa) if len(A & B) != 2] for B in Wb] return IncidenceStructure(H) @@ -4647,24 +4617,12 @@ def BIBD_196_6_1(): """ from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from .incidence_structures import IncidenceStructure + a = 'a' - bibd = [((0,0), ( 2,0), (12,0), (45,0), ( 3,1), (11,a)), - ((0,0), ( 3,0), ( 8,0), ( 5,1), (17,1), (39,a)), - ((0,0), ( 9,0), (36,0), (24,1), (44,1), (37,a)), - ((0,0), (15,0), (34,1), (41,1), (47,2), (18,a)), - ((0,0), ( 7,0), (31,0), (13,1), (35,2), (41,a)), - ((0,0), (14,0), (32,1), (10,2), (22,a), (44,a)), - ((0,0), (23,0), (21,1), (39,1), (19,a), (25,a)), - ((0,0), (33,1), ( 0,a), ( 5,a), (29,a), (47,a)), - ((0,0), ( 1,0), ( 0,1), (30,1), ( 0,2), (18,2)), - ((8,0), (19,0), (44,1), (31,1), (46,2), (48,2))] - - gens = lambda B: [frozenset(((x * 30) % 49, (y + 1) % 3 if y != a else a) - for x, y in B), - frozenset(((x + 1) % 49, y) - for x, y in B)] - bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], - successors=gens) + bibd = [((0, 0), (2, 0), (12, 0), (45, 0), (3, 1), (11, a)), ((0, 0), (3, 0), (8, 0), (5, 1), (17, 1), (39, a)), ((0, 0), (9, 0), (36, 0), (24, 1), (44, 1), (37, a)), ((0, 0), (15, 0), (34, 1), (41, 1), (47, 2), (18, a)), ((0, 0), (7, 0), (31, 0), (13, 1), (35, 2), (41, a)), ((0, 0), (14, 0), (32, 1), (10, 2), (22, a), (44, a)), ((0, 0), (23, 0), (21, 1), (39, 1), (19, a), (25, a)), ((0, 0), (33, 1), (0, a), (5, a), (29, a), (47, a)), ((0, 0), (1, 0), (0, 1), (30, 1), (0, 2), (18, 2)), ((8, 0), (19, 0), (44, 1), (31, 1), (46, 2), (48, 2))] + + gens = lambda B: [frozenset(((x * 30) % 49, (y + 1) % 3 if y != a else a) for x, y in B), frozenset(((x + 1) % 49, y) for x, y in B)] + bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], successors=gens) return IncidenceStructure(bibd)._blocks @@ -4683,21 +4641,11 @@ def BIBD_201_6_1(): """ from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from .incidence_structures import IncidenceStructure - bibd = [((0,0), ( 1,0), ( 4,2), ( 9,2), (34,2), (62,2)), - ((0,1), ( 2,1), (15,1), ( 8,2), (27,2), (49,2)), - ((0,0), ( 3,0), (22,0), (54,1), (13,2), (40,2)), - ((0,0), (36,0), (40,0), (31,1), (34,1), ( 5,2)), - ((0,0), (50,0), (55,0), ( 6,1), (24,1), (26,2)), - ((0,0), ( 2,0), ( 3,1), (14,1), (35,1), (25,2)), - ((3,1), (20,1), (44,1), (36,2), (39,2), (59,2)), - ((0,0), ( 0,1), (30,1), (38,1), (66,1), ( 0,2))] - - gens = lambda B: [frozenset(((x * 29) % 67, y) - for x, y in B), - frozenset(((x + 1) % 67, y) - for x, y in B)] - bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], - successors=gens) + + bibd = [((0, 0), (1, 0), (4, 2), (9, 2), (34, 2), (62, 2)), ((0, 1), (2, 1), (15, 1), (8, 2), (27, 2), (49, 2)), ((0, 0), (3, 0), (22, 0), (54, 1), (13, 2), (40, 2)), ((0, 0), (36, 0), (40, 0), (31, 1), (34, 1), (5, 2)), ((0, 0), (50, 0), (55, 0), (6, 1), (24, 1), (26, 2)), ((0, 0), (2, 0), (3, 1), (14, 1), (35, 1), (25, 2)), ((3, 1), (20, 1), (44, 1), (36, 2), (39, 2), (59, 2)), ((0, 0), (0, 1), (30, 1), (38, 1), (66, 1), (0, 2))] + + gens = lambda B: [frozenset(((x * 29) % 67, y) for x, y in B), frozenset(((x + 1) % 67, y) for x, y in B)] + bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], successors=gens) return IncidenceStructure(bibd)._blocks @@ -4723,10 +4671,10 @@ def BIBD_79_13_2(): g11 = libgap.Z(11) # generator for GF(11) one = g11**0 - zero = 0*g11 + zero = 0 * g11 X = libgap([[one, one], [zero, one]]) - Y = libgap([[5*one, zero], [zero, 9*one]]) + Y = libgap([[5 * one, zero], [zero, 9 * one]]) Z = libgap([[-one, zero], [zero, one]]) G = libgap.Group(X, Y, Z) @@ -4742,29 +4690,29 @@ def BIBD_79_13_2(): libgap.set_global("p23Act", P23Action) libgap.set_global("p4Act", P4Action) - action = libgap.function_factory("""function(pair, g) + action = libgap.function_factory( + """function(pair, g) local i, C, homs; i := pair[1]; C := pair[2]; homs := [p1Act, p23Act, p23Act, p4Act]; return [i, C^(ImageElm(homs[i],g))]; - end;""") + end;""" + ) - p1 = (1,1) - p2 = (2,1) - p3 = (3,1) - p4 = (4,1) + p1 = (1, 1) + p2 = (2, 1) + p3 = (3, 1) + p4 = (4, 1) B1 = list(libgap.Orbit(H4, p1, action)) + list(libgap.Orbit(G, p2, action)) B2 = list(libgap.Orbit(H4, p1, action)) + list(libgap.Orbit(G, p3, action)) B3 = list(libgap([p1, p2, p3])) + list(libgap.Orbit(libgap.Group(Y), action(p4, X), action)) + list(libgap.Orbit(libgap.Group(Y), action(p4, X**4), action)) - B4 = [action(p2, X**2), action(p2, X**-2), action(p3, X**5), action(p3, X**-5), p4, - action(p4, X * Y**2), action(p4, X**-1 * Y**2), action(p4, X*Y), action(p4, X**-1 * Y), - action(p4, X**5 * Y), action(p4, X**-5 * Y), action(p4, X**5 * Y**4), action(p4, X**-5 * Y**4)] + B4 = [action(p2, X**2), action(p2, X**-2), action(p3, X**5), action(p3, X**-5), p4, action(p4, X * Y**2), action(p4, X**-1 * Y**2), action(p4, X * Y), action(p4, X**-1 * Y), action(p4, X**5 * Y), action(p4, X**-5 * Y), action(p4, X**5 * Y**4), action(p4, X**-5 * Y**4)] points = [] - for i in range(1,5): - points += list(libgap.Orbit(G, (i,1), action)) + for i in range(1, 5): + points += list(libgap.Orbit(G, (i, 1), action)) permAction = libgap.Action(G, points, action) @@ -4778,7 +4726,7 @@ def BIBD_79_13_2(): libgap.unset_global("p1Act") libgap.unset_global("p23Act") libgap.unset_global("p4Act") - return [[int(t)-1 for t in y] for y in blocks] + return [[int(t) - 1 for t in y] for y in blocks] def BIBD_56_11_2(): @@ -4801,7 +4749,7 @@ def BIBD_56_11_2(): from sage.libs.gap.libgap import libgap from .incidence_structures import IncidenceStructure - a = list(range(2,57)) + [50] + a = list(range(2, 57)) + [50] a[6] = 1 a[13] = 8 a[20] = 15 @@ -4810,15 +4758,13 @@ def BIBD_56_11_2(): a[41] = 36 a[48] = 43 - b = [1,8,27,36,20,14,42,41,29,52,24,30,55,22,26,21,10,40,23,53, - 56,6,49,46,50,32,28,3,34,48,4,15,13,9,18,31,51,39,43,35, - 2,54,38,25,45,11,37,12,19,44,47,17,5,7,33,16] + b = [1, 8, 27, 36, 20, 14, 42, 41, 29, 52, 24, 30, 55, 22, 26, 21, 10, 40, 23, 53, 56, 6, 49, 46, 50, 32, 28, 3, 34, 48, 4, 15, 13, 9, 18, 31, 51, 39, 43, 35, 2, 54, 38, 25, 45, 11, 37, 12, 19, 44, 47, 17, 5, 7, 33, 16] a = libgap.PermList(a) b = libgap.PermList(b) - G = libgap.Group(a,b) + G = libgap.Group(a, b) - B = libgap.Set([1,12,19,23,30,37,45,47,48,49,51]) + B = libgap.Set([1, 12, 19, 23, 30, 37, 45, 47, 48, 49, 51]) D = IncidenceStructure(libgap.Orbit(G, B, libgap.OnSets)) return D._blocks @@ -4832,29 +4778,27 @@ def BIBD_56_11_2(): # This dictionary is used by designs.BalancedIncompleteBlockDesign # Note that the values are a list of blocks and not a design object BIBD_constructions = { - ( 45,9,8): BIBD_45_9_8, - (56,11,2): BIBD_56_11_2, - ( 66,6,1): BIBD_66_6_1, - ( 76,6,1): BIBD_76_6_1, - (79,13,2): BIBD_79_13_2, - ( 96,6,1): BIBD_96_6_1, - (120,8,1): RBIBD_120_8_1, - (106,6,1): BIBD_106_6_1, - (111,6,1): BIBD_111_6_1, - (126,6,1): BIBD_126_6_1, - (136,6,1): BIBD_136_6_1, - (141,6,1): BIBD_141_6_1, - (171,6,1): BIBD_171_6_1, - (176,50,14): lambda : HigmanSimsDesign().blocks(), - (196,6,1): BIBD_196_6_1, - (201,6,1): BIBD_201_6_1, + (45, 9, 8): BIBD_45_9_8, + (56, 11, 2): BIBD_56_11_2, + (66, 6, 1): BIBD_66_6_1, + (76, 6, 1): BIBD_76_6_1, + (79, 13, 2): BIBD_79_13_2, + (96, 6, 1): BIBD_96_6_1, + (120, 8, 1): RBIBD_120_8_1, + (106, 6, 1): BIBD_106_6_1, + (111, 6, 1): BIBD_111_6_1, + (126, 6, 1): BIBD_126_6_1, + (136, 6, 1): BIBD_136_6_1, + (141, 6, 1): BIBD_141_6_1, + (171, 6, 1): BIBD_171_6_1, + (176, 50, 14): lambda: HigmanSimsDesign().blocks(), + (196, 6, 1): BIBD_196_6_1, + (201, 6, 1): BIBD_201_6_1, } # Create the list of DF for the documentation -_all_l = sorted(set(l for v,k,l in BIBD_constructions.keys())) -LIST_OF_BIBD = "\n".join(r" - `\lambda={}`:\n ".format(l) + - ", ".join("`({},{},{})`".format(v, k, l) for v,k,_ in sorted(BIBD_constructions) if _ == l) - for l in _all_l) +_all_l = sorted(set(l for v, k, l in BIBD_constructions.keys())) +LIST_OF_BIBD = "\n".join(r" - `\lambda={}`:\n ".format(l) + ", ".join("`({},{},{})`".format(v, k, l) for v, k, _ in sorted(BIBD_constructions) if _ == l) for l in _all_l) # Evenly Distributed Sets (EDS) # @@ -4873,276 +4817,264 @@ def BIBD_56_11_2(): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.integer_ring import ZZ -R = PolynomialRing(ZZ,'a') + +R = PolynomialRing(ZZ, 'a') a = R.gen() EDS = { -4:{ - 13: (None, [0, 1, 11, 5]), - 25: (a**2 + 4*a + 2, [0, 1, a, 3*a + 4]), - 37: (None, [0, 1, 17, 30]), - 49: (a**2 + 6*a + 3, [0, 1, a + 6, 4*a + 1]), - 61: (None, [0, 1, 6, 37]), - 73: (None, [0, 1, 5, 18]), - 97: (None, [0, 1, 5, 24]), - 109: (None, [0, 1, 6, 60]), - 121: (a**2 + 7*a + 2, [0, 1, 2*a, 3*a + 7]), - 157: (None, [0, 1, 20, 132]), - 169: (a**2 + 12*a + 2, [0, 1, a + 12, a + 6]), - 181: (None, [0, 1, 10, 87]), - 193: (None, [0, 1, 5, 11]), - 229: (None, [0, 1, 6, 13]), - 241: (None, [0, 1, 11, 24]), - 277: (None, [0, 1, 11, 228]), - 289: (a**2 + 16*a + 3, [0, 1, a, 6*a + 13]), - 313: (None, [0, 1, 10, 121]), - 337: (None, [0, 1, 10, 21]), - 349: (None, [0, 1, 7, 19]), - 361: (a**2 + 18*a + 2, [0, 1, a + 3, 9*a + 5]), - 373: (None, [0, 1, 5, 231]), - 397: (None, [0, 1, 18, 11]), - 409: (None, [0, 1, 21, 60]), - 421: (None, [0, 1, 14, 31]), - 433: (None, [0, 1, 10, 97]), - 457: (None, [0, 1, 13, 195]), - 529: (a**2 + 21*a + 5, [0, 1, a + 5, 3*a + 11]), - 541: (None, [0, 1, 11, 45]), - 577: (None, [0, 1, 5, 115]), - 601: (None, [0, 1, 7, 69]), - 613: (None, [0, 1, 6, 88]), - 625: (a**4 + 4*a**2 + 4*a + 2, [0, 1, a + 3, 2*a**2 + a]), - 661: (None, [0, 1, 6, 66]), - 673: (None, [0, 1, 5, 46]), - 709: (None, [0, 1, 17, 256]), - 733: (None, [0, 1, 6, 49]), - 757: (None, [0, 1, 5, 224]), - 769: (None, [0, 1, 11, 79]), - 829: (None, [0, 1, 19, 44]), - 841: (a**2 + 24*a + 2, [0, 1, a + 8, 4*a + 27]), - 853: (None, [0, 1, 6, 58]), - 877: (None, [0, 1, 5, 46]), - 937: (None, [0, 1, 5, 160]), - 961: (a**2 + 29*a + 3, [0, 1, a + 16, 3*a + 8]), - 997: (None, [0, 1, 7, 102]), - 1009: (None, [0, 1, 11, 131]), - 1021: (None, [0, 1, 19, 153]), - 1033: (None, [0, 1, 5, 15]), - 1069: (None, [0, 1, 6, 36]), - 1093: (None, [0, 1, 15, 25]), - 1117: (None, [0, 1, 6, 23]), - 1129: (None, [0, 1, 11, 37]), - 1153: (None, [0, 1, 5, 151]), - 1201: (None, [0, 1, 17, 48]), - 1213: (None, [0, 1, 20, 217]), - 1237: (None, [0, 1, 7, 199]), - 1249: (None, [0, 1, 7, 36]), - 1297: (None, [0, 1, 10, 103]), - 1321: (None, [0, 1, 7, 112]), - 1369: (a**2 + 33*a + 2, [0, 1, a + 33, a + 9]), - 1381: (None, [0, 1, 19, 84]), - 1429: (None, [0, 1, 14, 116]), - 1453: (None, [0, 1, 5, 377]), - 1489: (None, [0, 1, 14, 44]), - 1549: (None, [0, 1, 22, 89]), - 1597: (None, [0, 1, 33, 228]), - 1609: (None, [0, 1, 7, 95]), - 1621: (None, [0, 1, 6, 165]), - 1657: (None, [0, 1, 11, 121]), - 1669: (None, [0, 1, 6, 155]), - 1681: (a**2 + 38*a + 6, [0, 1, a, 6*a + 6]), - 1693: (None, [0, 1, 5, 50]), - 1741: (None, [0, 1, 19, 341]), - 1753: (None, [0, 1, 7, 146]), - 1777: (None, [0, 1, 10, 100]), - 1789: (None, [0, 1, 6, 238]), - 1801: (None, [0, 1, 11, 79]), - 1849: (a**2 + 42*a + 3, [0, 1, a + 5, 2*a + 35]), - 1861: (None, [0, 1, 18, 110]), - 1873: (None, [0, 1, 10, 40]), - 1933: (None, [0, 1, 14, 100]), - 1993: (None, [0, 1, 5, 34]), - 2017: (None, [0, 1, 10, 57]), - 2029: (None, [0, 1, 6, 25]), - 2053: (None, [0, 1, 14, 95]), - 2089: (None, [0, 1, 7, 66]), - 2113: (None, [0, 1, 7, 117]), - 2137: (None, [0, 1, 10, 60]), - 2161: (None, [0, 1, 31, 78]), - 2197: (a**3 + 2*a + 11, [0, 1, 2*a + 9, 11*a + 3]), - 2209: (a**2 + 45*a + 5, [0, 1, a + 5, 2*a + 12]), - 2221: (None, [0, 1, 18, 201]), - 2269: (None, [0, 1, 6, 99]), - 2281: (None, [0, 1, 7, 212]), - 2293: (None, [0, 1, 5, 116]), - 2341: (None, [0, 1, 7, 99]), - 2377: (None, [0, 1, 5, 214]), - 2389: (None, [0, 1, 18, 29]), - 2401: (a**4 + 5*a**2 + 4*a + 3, [0, 1, a, 2*a**2 + 6]), - 2437: (None, [0, 1, 5, 45]), - 2473: (None, [0, 1, 5, 298]), - 2521: (None, [0, 1, 17, 150]), - 2557: (None, [0, 1, 5, 68]), - 2593: (None, [0, 1, 7, 255]), - 2617: (None, [0, 1, 5, 11]), - 2677: (None, [0, 1, 7, 57]), - 2689: (None, [0, 1, 19, 115]), - 2713: (None, [0, 1, 5, 139]), - 2749: (None, [0, 1, 13, 243]), - 2797: (None, [0, 1, 5, 95]), - 2809: (a**2 + 49*a + 2, [0, 1, a, 3*a + 22])}, - -5: { - 41: (None, [0, 1, 13, 38, 31]), - 61: (None, [0, 1, 26, 11, 7]), - 101: (None, [0, 1, 12, 43, 81]), - 121: (a**2 + 7*a + 2, [0, 1, a, 9*a + 5, 3*a + 1]), - 181: (None, [0, 1, 21, 47, 123]), - 241: (None, [0, 1, 7, 51, 189]), - 281: (None, [0, 1, 3, 143, 74]), - 361: (a**2 + 18*a + 2, [0, 1, a, 2*a + 14, 18*a + 9]), - 401: (None, [0, 1, 3, 128, 133]), - 421: (None, [0, 1, 40, 132, 8]), - 461: (None, [0, 1, 28, 53, 287]), - 521: (None, [0, 1, 3, 9, 217]), - 541: (None, [0, 1, 30, 124, 370]), - 601: (None, [0, 1, 7, 10, 545]), - 641: (None, [0, 1, 12, 79, 185]), - 661: (None, [0, 1, 6, 36, 286]), - 701: (None, [0, 1, 12, 97, 365]), - 761: (None, [0, 1, 11, 4, 260]), - 821: (None, [0, 1, 13, 62, 571]), - 841: (a**2 + 24*a + 2, [0, 1, a, 2*a + 5, 5*a + 19]), - 881: (None, [0, 1, 3, 9, 836]), - 941: (None, [0, 1, 7, 49, 96]), - 961: (a**2 + 29*a + 3, [0, 1, a, 3, 3*a]), - 1021: (None, [0, 1, 30, 6, 171]), - 1061: (None, [0, 1, 15, 51, 60]), - 1181: (None, [0, 1, 7, 90, 87]), - 1201: (None, [0, 1, 11, 14, 621]), - 1301: (None, [0, 1, 7, 19, 138]), - 1321: (None, [0, 1, 13, 5, 1168]), - 1361: (None, [0, 1, 3, 9, 159]), - 1381: (None, [0, 1, 26, 35, 547]), - 1481: (None, [0, 1, 3, 9, 730]), - 1601: (None, [0, 1, 3, 17, 1077]), - 1621: (None, [0, 1, 14, 4, 1380]), - 1681: (a**2 + 38*a + 6, [0, 1, a, a + 15, 40*a + 22]), - 1721: (None, [0, 1, 3, 121, 687]), - 1741: (None, [0, 1, 7, 29, 32]), - 1801: (None, [0, 1, 11, 51, 142]), - 1861: (None, [0, 1, 10, 62, 643]), - 1901: (None, [0, 1, 12, 4, 477]) + 4: { + 13: (None, [0, 1, 11, 5]), + 25: (a**2 + 4 * a + 2, [0, 1, a, 3 * a + 4]), + 37: (None, [0, 1, 17, 30]), + 49: (a**2 + 6 * a + 3, [0, 1, a + 6, 4 * a + 1]), + 61: (None, [0, 1, 6, 37]), + 73: (None, [0, 1, 5, 18]), + 97: (None, [0, 1, 5, 24]), + 109: (None, [0, 1, 6, 60]), + 121: (a**2 + 7 * a + 2, [0, 1, 2 * a, 3 * a + 7]), + 157: (None, [0, 1, 20, 132]), + 169: (a**2 + 12 * a + 2, [0, 1, a + 12, a + 6]), + 181: (None, [0, 1, 10, 87]), + 193: (None, [0, 1, 5, 11]), + 229: (None, [0, 1, 6, 13]), + 241: (None, [0, 1, 11, 24]), + 277: (None, [0, 1, 11, 228]), + 289: (a**2 + 16 * a + 3, [0, 1, a, 6 * a + 13]), + 313: (None, [0, 1, 10, 121]), + 337: (None, [0, 1, 10, 21]), + 349: (None, [0, 1, 7, 19]), + 361: (a**2 + 18 * a + 2, [0, 1, a + 3, 9 * a + 5]), + 373: (None, [0, 1, 5, 231]), + 397: (None, [0, 1, 18, 11]), + 409: (None, [0, 1, 21, 60]), + 421: (None, [0, 1, 14, 31]), + 433: (None, [0, 1, 10, 97]), + 457: (None, [0, 1, 13, 195]), + 529: (a**2 + 21 * a + 5, [0, 1, a + 5, 3 * a + 11]), + 541: (None, [0, 1, 11, 45]), + 577: (None, [0, 1, 5, 115]), + 601: (None, [0, 1, 7, 69]), + 613: (None, [0, 1, 6, 88]), + 625: (a**4 + 4 * a**2 + 4 * a + 2, [0, 1, a + 3, 2 * a**2 + a]), + 661: (None, [0, 1, 6, 66]), + 673: (None, [0, 1, 5, 46]), + 709: (None, [0, 1, 17, 256]), + 733: (None, [0, 1, 6, 49]), + 757: (None, [0, 1, 5, 224]), + 769: (None, [0, 1, 11, 79]), + 829: (None, [0, 1, 19, 44]), + 841: (a**2 + 24 * a + 2, [0, 1, a + 8, 4 * a + 27]), + 853: (None, [0, 1, 6, 58]), + 877: (None, [0, 1, 5, 46]), + 937: (None, [0, 1, 5, 160]), + 961: (a**2 + 29 * a + 3, [0, 1, a + 16, 3 * a + 8]), + 997: (None, [0, 1, 7, 102]), + 1009: (None, [0, 1, 11, 131]), + 1021: (None, [0, 1, 19, 153]), + 1033: (None, [0, 1, 5, 15]), + 1069: (None, [0, 1, 6, 36]), + 1093: (None, [0, 1, 15, 25]), + 1117: (None, [0, 1, 6, 23]), + 1129: (None, [0, 1, 11, 37]), + 1153: (None, [0, 1, 5, 151]), + 1201: (None, [0, 1, 17, 48]), + 1213: (None, [0, 1, 20, 217]), + 1237: (None, [0, 1, 7, 199]), + 1249: (None, [0, 1, 7, 36]), + 1297: (None, [0, 1, 10, 103]), + 1321: (None, [0, 1, 7, 112]), + 1369: (a**2 + 33 * a + 2, [0, 1, a + 33, a + 9]), + 1381: (None, [0, 1, 19, 84]), + 1429: (None, [0, 1, 14, 116]), + 1453: (None, [0, 1, 5, 377]), + 1489: (None, [0, 1, 14, 44]), + 1549: (None, [0, 1, 22, 89]), + 1597: (None, [0, 1, 33, 228]), + 1609: (None, [0, 1, 7, 95]), + 1621: (None, [0, 1, 6, 165]), + 1657: (None, [0, 1, 11, 121]), + 1669: (None, [0, 1, 6, 155]), + 1681: (a**2 + 38 * a + 6, [0, 1, a, 6 * a + 6]), + 1693: (None, [0, 1, 5, 50]), + 1741: (None, [0, 1, 19, 341]), + 1753: (None, [0, 1, 7, 146]), + 1777: (None, [0, 1, 10, 100]), + 1789: (None, [0, 1, 6, 238]), + 1801: (None, [0, 1, 11, 79]), + 1849: (a**2 + 42 * a + 3, [0, 1, a + 5, 2 * a + 35]), + 1861: (None, [0, 1, 18, 110]), + 1873: (None, [0, 1, 10, 40]), + 1933: (None, [0, 1, 14, 100]), + 1993: (None, [0, 1, 5, 34]), + 2017: (None, [0, 1, 10, 57]), + 2029: (None, [0, 1, 6, 25]), + 2053: (None, [0, 1, 14, 95]), + 2089: (None, [0, 1, 7, 66]), + 2113: (None, [0, 1, 7, 117]), + 2137: (None, [0, 1, 10, 60]), + 2161: (None, [0, 1, 31, 78]), + 2197: (a**3 + 2 * a + 11, [0, 1, 2 * a + 9, 11 * a + 3]), + 2209: (a**2 + 45 * a + 5, [0, 1, a + 5, 2 * a + 12]), + 2221: (None, [0, 1, 18, 201]), + 2269: (None, [0, 1, 6, 99]), + 2281: (None, [0, 1, 7, 212]), + 2293: (None, [0, 1, 5, 116]), + 2341: (None, [0, 1, 7, 99]), + 2377: (None, [0, 1, 5, 214]), + 2389: (None, [0, 1, 18, 29]), + 2401: (a**4 + 5 * a**2 + 4 * a + 3, [0, 1, a, 2 * a**2 + 6]), + 2437: (None, [0, 1, 5, 45]), + 2473: (None, [0, 1, 5, 298]), + 2521: (None, [0, 1, 17, 150]), + 2557: (None, [0, 1, 5, 68]), + 2593: (None, [0, 1, 7, 255]), + 2617: (None, [0, 1, 5, 11]), + 2677: (None, [0, 1, 7, 57]), + 2689: (None, [0, 1, 19, 115]), + 2713: (None, [0, 1, 5, 139]), + 2749: (None, [0, 1, 13, 243]), + 2797: (None, [0, 1, 5, 95]), + 2809: (a**2 + 49 * a + 2, [0, 1, a, 3 * a + 22]), }, - -6: { - 31: (None, [0, 1, 3, 12, 18, 8]), - 151: (None, [0, 1, 69, 36, 57, 89]), - 181: (None, [0, 1, 14, 4, 59, 139]), - 211: (None, [0, 1, 24, 141, 128, 202]), - 241: (None, [0, 1, 7, 151, 232, 136]), - 271: (None, [0, 1, 6, 15, 81, 225]), - 331: (None, [0, 1, 29, 113, 21, 69]), - 361: (a**2 + 18*a + 2, [0, 1, a, 3*a + 2, 14*a, 10*a + 9]), - 421: (None, [0, 1, 11, 4, 111, 394]), - 541: (None, [0, 1, 5, 42, 157, 322]), - 571: (None, [0, 1, 3, 52, 549, 137]), - 601: (None, [0, 1, 6, 114, 490, 359]), - 631: (None, [0, 1, 3, 73, 144, 466]), - 661: (None, [0, 1, 6, 73, 182, 44]), - 691: (None, [0, 1, 3, 9, 554, 425]), - 751: (None, [0, 1, 3, 9, 314, 226]), - 811: (None, [0, 1, 3, 9, 504, 341]), - 841: (a**2 + 24*a + 2, [0, 1, a, 3*a + 11, 12*a + 24, 22*a + 10]), - 961: (a**2 + 29*a + 3, [0, 1, 11, 28, 15*a + 25, 4*a + 3]), - 991: (None, [0, 1, 6, 36, 234, 834]), - 1021: (None, [0, 1, 30, 6, 476, 154]), - 1051: (None, [0, 1, 7, 23, 324, 266]), - 1171: (None, [0, 1, 37, 4, 1163, 302]), - 1201: (None, [0, 1, 11, 5, 130, 146]), - 1231: (None, [0, 1, 3, 9, 768, 476]), - 1291: (None, [0, 1, 45, 79, 320, 390]), - 1321: (None, [0, 1, 13, 33, 445, 894]), - 1381: (None, [0, 1, 26, 56, 474, 839]), - 1471: (None, [0, 1, 6, 36, 425, 676]), - 1531: (None, [0, 1, 38, 8, 465, 1376]), - 1621: (None, [0, 1, 5, 20, 117, 1486]), - 1681: (a**2 + 38*a + 6, [0, 1, a, a + 5, 2*a + 28, 2*a + 34]), - 1741: (None, [0, 1, 9, 4, 301, 420]), - 1801: (None, [0, 1, 6, 4, 1263, 260]), - 1831: (None, [0, 1, 3, 9, 452, 1532]), - 1861: (None, [0, 1, 10, 4, 188, 1405]), - 1951: (None, [0, 1, 3, 7, 27, 1032]), + 5: { + 41: (None, [0, 1, 13, 38, 31]), + 61: (None, [0, 1, 26, 11, 7]), + 101: (None, [0, 1, 12, 43, 81]), + 121: (a**2 + 7 * a + 2, [0, 1, a, 9 * a + 5, 3 * a + 1]), + 181: (None, [0, 1, 21, 47, 123]), + 241: (None, [0, 1, 7, 51, 189]), + 281: (None, [0, 1, 3, 143, 74]), + 361: (a**2 + 18 * a + 2, [0, 1, a, 2 * a + 14, 18 * a + 9]), + 401: (None, [0, 1, 3, 128, 133]), + 421: (None, [0, 1, 40, 132, 8]), + 461: (None, [0, 1, 28, 53, 287]), + 521: (None, [0, 1, 3, 9, 217]), + 541: (None, [0, 1, 30, 124, 370]), + 601: (None, [0, 1, 7, 10, 545]), + 641: (None, [0, 1, 12, 79, 185]), + 661: (None, [0, 1, 6, 36, 286]), + 701: (None, [0, 1, 12, 97, 365]), + 761: (None, [0, 1, 11, 4, 260]), + 821: (None, [0, 1, 13, 62, 571]), + 841: (a**2 + 24 * a + 2, [0, 1, a, 2 * a + 5, 5 * a + 19]), + 881: (None, [0, 1, 3, 9, 836]), + 941: (None, [0, 1, 7, 49, 96]), + 961: (a**2 + 29 * a + 3, [0, 1, a, 3, 3 * a]), + 1021: (None, [0, 1, 30, 6, 171]), + 1061: (None, [0, 1, 15, 51, 60]), + 1181: (None, [0, 1, 7, 90, 87]), + 1201: (None, [0, 1, 11, 14, 621]), + 1301: (None, [0, 1, 7, 19, 138]), + 1321: (None, [0, 1, 13, 5, 1168]), + 1361: (None, [0, 1, 3, 9, 159]), + 1381: (None, [0, 1, 26, 35, 547]), + 1481: (None, [0, 1, 3, 9, 730]), + 1601: (None, [0, 1, 3, 17, 1077]), + 1621: (None, [0, 1, 14, 4, 1380]), + 1681: (a**2 + 38 * a + 6, [0, 1, a, a + 15, 40 * a + 22]), + 1721: (None, [0, 1, 3, 121, 687]), + 1741: (None, [0, 1, 7, 29, 32]), + 1801: (None, [0, 1, 11, 51, 142]), + 1861: (None, [0, 1, 10, 62, 643]), + 1901: (None, [0, 1, 12, 4, 477]), }, - -7: { - 169: (a**2 + 12*a + 2, [0, 1, a, 5*a + 3, 11*a + 10, 11*a + 6, 5*a + 6]), - 337: (None, [0, 1, 10, 28, 80, 224, 129]), - 379: (None, [0, 1, 9, 175, 287, 14, 271]), - 421: (None, [0, 1, 26, 4, 191, 250, 298]), - 463: (None, [0, 1, 3, 9, 310, 243, 415]), - 547: (None, [0, 1, 25, 4, 430, 9, 210]), - 631: (None, [0, 1, 3, 104, 303, 257, 447]), - 673: (None, [0, 1, 5, 25, 405, 476, 131]), - 757: (None, [0, 1, 6, 36, 232, 557, 274]), - 841: (a**2 + 24*a + 2, [0, 1, a + 28, 2*a + 1, 7*a + 22, 25*a + 20, 11*a + 10]), - 883: (None, [0, 1, 54, 4, 870, 638, 310]), - 967: (None, [0, 1, 5, 22, 775, 577, 819]), - 1009: (None, [0, 1, 5, 36, 911, 650, 412]), - 1051: (None, [0, 1, 7, 49, 274, 1012, 213]), - 1093: (None, [0, 1, 5, 25, 274, 214, 735]), - 1303: (None, [0, 1, 30, 70, 1107, 39, 1271]), - 1429: (None, [0, 1, 6, 15, 289, 975, 314]), - 1471: (None, [0, 1, 6, 36, 216, 947, 568]), - 1597: (None, [0, 1, 7, 38, 266, 223, 1316]), - 1681: (a**2 + 38*a + 6, [0, 1, a, 2*a + 12, 7*a + 9, 35*a + 29, 33*a + 2]), - 1723: (None, [0, 1, 3, 9, 1169, 420, 1651]), - 1849: (a**2 + 42*a + 3, [0, 1, 13, 3, 39, 19, 5*a + 13]), - 1933: (None, [0, 1, 5, 25, 319, 1607, 1782]) + 6: { + 31: (None, [0, 1, 3, 12, 18, 8]), + 151: (None, [0, 1, 69, 36, 57, 89]), + 181: (None, [0, 1, 14, 4, 59, 139]), + 211: (None, [0, 1, 24, 141, 128, 202]), + 241: (None, [0, 1, 7, 151, 232, 136]), + 271: (None, [0, 1, 6, 15, 81, 225]), + 331: (None, [0, 1, 29, 113, 21, 69]), + 361: (a**2 + 18 * a + 2, [0, 1, a, 3 * a + 2, 14 * a, 10 * a + 9]), + 421: (None, [0, 1, 11, 4, 111, 394]), + 541: (None, [0, 1, 5, 42, 157, 322]), + 571: (None, [0, 1, 3, 52, 549, 137]), + 601: (None, [0, 1, 6, 114, 490, 359]), + 631: (None, [0, 1, 3, 73, 144, 466]), + 661: (None, [0, 1, 6, 73, 182, 44]), + 691: (None, [0, 1, 3, 9, 554, 425]), + 751: (None, [0, 1, 3, 9, 314, 226]), + 811: (None, [0, 1, 3, 9, 504, 341]), + 841: (a**2 + 24 * a + 2, [0, 1, a, 3 * a + 11, 12 * a + 24, 22 * a + 10]), + 961: (a**2 + 29 * a + 3, [0, 1, 11, 28, 15 * a + 25, 4 * a + 3]), + 991: (None, [0, 1, 6, 36, 234, 834]), + 1021: (None, [0, 1, 30, 6, 476, 154]), + 1051: (None, [0, 1, 7, 23, 324, 266]), + 1171: (None, [0, 1, 37, 4, 1163, 302]), + 1201: (None, [0, 1, 11, 5, 130, 146]), + 1231: (None, [0, 1, 3, 9, 768, 476]), + 1291: (None, [0, 1, 45, 79, 320, 390]), + 1321: (None, [0, 1, 13, 33, 445, 894]), + 1381: (None, [0, 1, 26, 56, 474, 839]), + 1471: (None, [0, 1, 6, 36, 425, 676]), + 1531: (None, [0, 1, 38, 8, 465, 1376]), + 1621: (None, [0, 1, 5, 20, 117, 1486]), + 1681: (a**2 + 38 * a + 6, [0, 1, a, a + 5, 2 * a + 28, 2 * a + 34]), + 1741: (None, [0, 1, 9, 4, 301, 420]), + 1801: (None, [0, 1, 6, 4, 1263, 260]), + 1831: (None, [0, 1, 3, 9, 452, 1532]), + 1861: (None, [0, 1, 10, 4, 188, 1405]), + 1951: (None, [0, 1, 3, 7, 27, 1032]), }, - -8: { - 449: (None, [0, 1, 3, 332, 8, 104, 381, 61]), - 617: (None, [0, 1, 3, 610, 397, 318, 465, 84]), - 673: (None, [0, 1, 20, 355, 92, 491, 315, 478]), - 729: (a**6 + 2*a**4 + a**2 + 2*a + 2, [0, 1, a, - a**2, 2*a**4 + a**3 + a**2 + a + 1, - a**4, a**3 + 2*a**2 + 2, 2*a**5 + a**4 + 2*a**2 + 2*a]), - 841: (a**2 + 24*a + 2, [0, 1, a, 27, 27*a + 25, 5*a + 18, - 11*a + 14, 14*a + 2]), - 953: (None, [0, 1, 3, 36, 727, 636, 899, 448]), - 1009: (None, [0, 1, 11, 20, 202, 283, 698, 629]), - 1289: (None, [0, 1, 6, 133, 579, 793, 361, 658]), - 1681: (a**2 + 38*a + 6, [0, 1, a, 3*a + 25, 5*a + 33, 34*a + 12, - 23*a + 31, 38*a + 14]), - 1849: (a**2 + 42*a + 3, [0, 1, a, a + 2, 4*a + 36, 5*a, - 20*a + 22, 18*a + 5]), + 7: { + 169: (a**2 + 12 * a + 2, [0, 1, a, 5 * a + 3, 11 * a + 10, 11 * a + 6, 5 * a + 6]), + 337: (None, [0, 1, 10, 28, 80, 224, 129]), + 379: (None, [0, 1, 9, 175, 287, 14, 271]), + 421: (None, [0, 1, 26, 4, 191, 250, 298]), + 463: (None, [0, 1, 3, 9, 310, 243, 415]), + 547: (None, [0, 1, 25, 4, 430, 9, 210]), + 631: (None, [0, 1, 3, 104, 303, 257, 447]), + 673: (None, [0, 1, 5, 25, 405, 476, 131]), + 757: (None, [0, 1, 6, 36, 232, 557, 274]), + 841: (a**2 + 24 * a + 2, [0, 1, a + 28, 2 * a + 1, 7 * a + 22, 25 * a + 20, 11 * a + 10]), + 883: (None, [0, 1, 54, 4, 870, 638, 310]), + 967: (None, [0, 1, 5, 22, 775, 577, 819]), + 1009: (None, [0, 1, 5, 36, 911, 650, 412]), + 1051: (None, [0, 1, 7, 49, 274, 1012, 213]), + 1093: (None, [0, 1, 5, 25, 274, 214, 735]), + 1303: (None, [0, 1, 30, 70, 1107, 39, 1271]), + 1429: (None, [0, 1, 6, 15, 289, 975, 314]), + 1471: (None, [0, 1, 6, 36, 216, 947, 568]), + 1597: (None, [0, 1, 7, 38, 266, 223, 1316]), + 1681: (a**2 + 38 * a + 6, [0, 1, a, 2 * a + 12, 7 * a + 9, 35 * a + 29, 33 * a + 2]), + 1723: (None, [0, 1, 3, 9, 1169, 420, 1651]), + 1849: (a**2 + 42 * a + 3, [0, 1, 13, 3, 39, 19, 5 * a + 13]), + 1933: (None, [0, 1, 5, 25, 319, 1607, 1782]), }, - -9: { - 73: (None, [0, 1, 5, 21, 59, 18, 12, 51, 49]), - 433: (None, [0, 1, 5, 145, 347, 248, 57, 267, 110]), - 937: (None, [0, 1, 5, 265, 828, 773, 328, 587, 866]), - 1009: (None, [0, 1, 11, 251, 944, 497, 700, 99, 545]), - 1153: (None, [0, 1, 5, 522, 1116, 495, 215, 859, 167]), - 1297: (None, [0, 1, 10, 244, 30, 1111, 392, 1183, 123]), - 1369: (a**2 + 33*a + 2, [0, 1, a, 8*a + 34, 36*a + 33, 2*a + 21, 20, - 32*a + 15, 25*a + 20]), - 1657: (None, [0, 1, 11, 121, 396, 269, 266, 873, 345]), - 1801: (None, [0, 1, 11, 105, 603, 966, 746, 1585, 1298]), - 1873: (None, [0, 1, 10, 32, 1837, 1823, 1040, 1826, 1496]), + 8: { + 449: (None, [0, 1, 3, 332, 8, 104, 381, 61]), + 617: (None, [0, 1, 3, 610, 397, 318, 465, 84]), + 673: (None, [0, 1, 20, 355, 92, 491, 315, 478]), + 729: (a**6 + 2 * a**4 + a**2 + 2 * a + 2, [0, 1, a, a**2, 2 * a**4 + a**3 + a**2 + a + 1, a**4, a**3 + 2 * a**2 + 2, 2 * a**5 + a**4 + 2 * a**2 + 2 * a]), + 841: (a**2 + 24 * a + 2, [0, 1, a, 27, 27 * a + 25, 5 * a + 18, 11 * a + 14, 14 * a + 2]), + 953: (None, [0, 1, 3, 36, 727, 636, 899, 448]), + 1009: (None, [0, 1, 11, 20, 202, 283, 698, 629]), + 1289: (None, [0, 1, 6, 133, 579, 793, 361, 658]), + 1681: (a**2 + 38 * a + 6, [0, 1, a, 3 * a + 25, 5 * a + 33, 34 * a + 12, 23 * a + 31, 38 * a + 14]), + 1849: (a**2 + 42 * a + 3, [0, 1, a, a + 2, 4 * a + 36, 5 * a, 20 * a + 22, 18 * a + 5]), + }, + 9: { + 73: (None, [0, 1, 5, 21, 59, 18, 12, 51, 49]), + 433: (None, [0, 1, 5, 145, 347, 248, 57, 267, 110]), + 937: (None, [0, 1, 5, 265, 828, 773, 328, 587, 866]), + 1009: (None, [0, 1, 11, 251, 944, 497, 700, 99, 545]), + 1153: (None, [0, 1, 5, 522, 1116, 495, 215, 859, 167]), + 1297: (None, [0, 1, 10, 244, 30, 1111, 392, 1183, 123]), + 1369: (a**2 + 33 * a + 2, [0, 1, a, 8 * a + 34, 36 * a + 33, 2 * a + 21, 20, 32 * a + 15, 25 * a + 20]), + 1657: (None, [0, 1, 11, 121, 396, 269, 266, 873, 345]), + 1801: (None, [0, 1, 11, 105, 603, 966, 746, 1585, 1298]), + 1873: (None, [0, 1, 10, 32, 1837, 1823, 1040, 1826, 1496]), + }, + 10: { + 1171: (None, [0, 1, 817, 856, 143, 881, 833, 82, 870, 564]), + 1531: (None, [0, 1, 61, 1109, 417, 590, 1273, 11, 1445, 326]), + 1621: (None, [0, 1, 52, 111, 779, 365, 1225, 378, 535, 1012]), + 1801: (None, [0, 1, 6, 369, 80, 1717, 138, 1782, 1301, 82]), }, - -10:{ - 1171: (None, [0, 1, 817, 856, 143, 881, 833, 82, 870, 564]), - 1531: (None, [0, 1, 61, 1109, 417, 590, 1273, 11, 1445, 326]), - 1621: (None, [0, 1, 52, 111, 779, 365, 1225, 378, 535, 1012]), - 1801: (None, [0, 1, 6, 369, 80, 1717, 138, 1782, 1301, 82]), - } } -LIST_OF_EDS = "\n".join(" - `k = {}`: {}".format( - k, ', '.join('`{}`'.format(q) for q in sorted(EDS[k]) if EDS[k][q] is not False)) - for k in sorted(EDS)) +LIST_OF_EDS = "\n".join(" - `k = {}`: {}".format(k, ', '.join('`{}`'.format(q) for q in sorted(EDS[k]) if EDS[k][q] is not False)) for k in sorted(EDS)) def ca_11_2_5_3(): @@ -5160,17 +5092,7 @@ def ca_11_2_5_3(): True """ - return [[0, 0, 1, 0, 1], - [0, 0, 2, 1, 0], - [0, 1, 0, 1, 2], - [0, 2, 1, 2, 2], - [1, 0, 0, 2, 1], - [1, 1, 1, 2, 0], - [1, 1, 2, 0, 2], - [1, 2, 2, 1, 1], - [2, 0, 2, 2, 2], - [2, 1, 1, 1, 1], - [2, 2, 0, 0, 0]] + return [[0, 0, 1, 0, 1], [0, 0, 2, 1, 0], [0, 1, 0, 1, 2], [0, 2, 1, 2, 2], [1, 0, 0, 2, 1], [1, 1, 1, 2, 0], [1, 1, 2, 0, 2], [1, 2, 2, 1, 1], [2, 0, 2, 2, 2], [2, 1, 1, 1, 1], [2, 2, 0, 0, 0]] def ca_12_2_7_3(): @@ -5188,18 +5110,7 @@ def ca_12_2_7_3(): True """ - return [[0, 0, 0, 2, 2, 0, 0], - [0, 0, 2, 1, 1, 1, 1], - [0, 1, 0, 0, 0, 1, 2], - [0, 2, 1, 2, 0, 2, 1], - [1, 0, 2, 0, 0, 2, 0], - [1, 1, 1, 1, 2, 0, 1], - [1, 1, 1, 2, 1, 1, 0], - [1, 2, 0, 1, 1, 2, 2], - [2, 0, 1, 0, 1, 0, 2], - [2, 1, 2, 2, 2, 2, 2], - [2, 2, 0, 0, 2, 1, 1], - [2, 2, 2, 1, 0, 0, 0]] + return [[0, 0, 0, 2, 2, 0, 0], [0, 0, 2, 1, 1, 1, 1], [0, 1, 0, 0, 0, 1, 2], [0, 2, 1, 2, 0, 2, 1], [1, 0, 2, 0, 0, 2, 0], [1, 1, 1, 1, 2, 0, 1], [1, 1, 1, 2, 1, 1, 0], [1, 2, 0, 1, 1, 2, 2], [2, 0, 1, 0, 1, 0, 2], [2, 1, 2, 2, 2, 2, 2], [2, 2, 0, 0, 2, 1, 1], [2, 2, 2, 1, 0, 0, 0]] def ca_13_2_9_3(): @@ -5217,19 +5128,7 @@ def ca_13_2_9_3(): True """ - return [[0, 0, 0, 2, 0, 2, 2, 2, 0], - [0, 0, 2, 0, 1, 1, 1, 2, 1], - [0, 1, 1, 1, 2, 0, 1, 2, 0], - [0, 1, 2, 1, 0, 1, 2, 0, 2], - [0, 2, 2, 2, 2, 1, 0, 1, 0], - [1, 0, 1, 0, 2, 1, 2, 0, 0], - [1, 0, 2, 1, 2, 2, 0, 2, 2], - [1, 1, 0, 0, 0, 0, 0, 1, 1], - [1, 2, 0, 2, 1, 0, 1, 0, 2], - [2, 0, 2, 1, 1, 0, 2, 1, 0], - [2, 1, 1, 2, 1, 2, 0, 0, 1], - [2, 2, 0, 1, 2, 1, 2, 2, 1], - [2, 2, 1, 0, 0, 2, 1, 1, 2]] + return [[0, 0, 0, 2, 0, 2, 2, 2, 0], [0, 0, 2, 0, 1, 1, 1, 2, 1], [0, 1, 1, 1, 2, 0, 1, 2, 0], [0, 1, 2, 1, 0, 1, 2, 0, 2], [0, 2, 2, 2, 2, 1, 0, 1, 0], [1, 0, 1, 0, 2, 1, 2, 0, 0], [1, 0, 2, 1, 2, 2, 0, 2, 2], [1, 1, 0, 0, 0, 0, 0, 1, 1], [1, 2, 0, 2, 1, 0, 1, 0, 2], [2, 0, 2, 1, 1, 0, 2, 1, 0], [2, 1, 1, 2, 1, 2, 0, 0, 1], [2, 2, 0, 1, 2, 1, 2, 2, 1], [2, 2, 1, 0, 0, 2, 1, 1, 2]] def ca_14_2_10_3(): @@ -5247,20 +5146,7 @@ def ca_14_2_10_3(): True """ - return [[0, 0, 0, 0, 2, 2, 2, 1, 1, 0], - [0, 0, 0, 2, 1, 0, 0, 2, 1, 1], - [0, 0, 1, 1, 1, 2, 1, 0, 2, 2], - [0, 1, 0, 2, 0, 1, 2, 0, 1, 2], - [0, 2, 2, 2, 1, 2, 2, 1, 0, 0], - [1, 0, 2, 1, 0, 1, 1, 1, 1, 1], - [1, 1, 1, 2, 1, 1, 1, 2, 2, 0], - [1, 1, 2, 0, 0, 2, 2, 2, 2, 1], - [1, 1, 2, 1, 0, 0, 0, 0, 0, 0], - [1, 2, 0, 1, 2, 0, 1, 2, 2, 2], - [2, 0, 0, 0, 1, 0, 1, 2, 0, 2], - [2, 1, 2, 2, 2, 2, 0, 1, 2, 2], - [2, 2, 1, 0, 2, 1, 0, 0, 0, 1], - [2, 2, 1, 1, 0, 0, 2, 1, 1, 0]] + return [[0, 0, 0, 0, 2, 2, 2, 1, 1, 0], [0, 0, 0, 2, 1, 0, 0, 2, 1, 1], [0, 0, 1, 1, 1, 2, 1, 0, 2, 2], [0, 1, 0, 2, 0, 1, 2, 0, 1, 2], [0, 2, 2, 2, 1, 2, 2, 1, 0, 0], [1, 0, 2, 1, 0, 1, 1, 1, 1, 1], [1, 1, 1, 2, 1, 1, 1, 2, 2, 0], [1, 1, 2, 0, 0, 2, 2, 2, 2, 1], [1, 1, 2, 1, 0, 0, 0, 0, 0, 0], [1, 2, 0, 1, 2, 0, 1, 2, 2, 2], [2, 0, 0, 0, 1, 0, 1, 2, 0, 2], [2, 1, 2, 2, 2, 2, 0, 1, 2, 2], [2, 2, 1, 0, 2, 1, 0, 0, 0, 1], [2, 2, 1, 1, 0, 0, 2, 1, 1, 0]] def ca_15_2_20_3(): @@ -5278,21 +5164,7 @@ def ca_15_2_20_3(): True """ - return [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - [0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], - [0, 1, 1, 1, 1, 0, 1, 2, 2, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2], - [0, 2, 2, 2, 2, 2, 2, 0, 1, 0, 0, 0, 0, 1, 2, 2, 0, 1, 1, 1], - [1, 0, 1, 1, 1, 2, 2, 0, 1, 0, 1, 1, 2, 0, 0, 1, 1, 0, 1, 2], - [1, 1, 2, 2, 2, 1, 0, 1, 0, 2, 1, 1, 0, 0, 2, 1, 2, 2, 1, 0], - [1, 2, 0, 1, 2, 0, 2, 1, 0, 2, 0, 2, 2, 1, 0, 2, 1, 0, 2, 1], - [1, 2, 1, 0, 2, 2, 1, 2, 0, 1, 2, 1, 1, 0, 1, 2, 0, 2, 0, 1], - [1, 2, 1, 2, 0, 2, 1, 1, 2, 2, 1, 0, 1, 2, 0, 0, 2, 1, 0, 0], - [2, 0, 2, 2, 2, 0, 1, 2, 2, 1, 2, 2, 0, 2, 2, 0, 1, 0, 1, 2], - [2, 1, 0, 2, 1, 2, 0, 2, 2, 2, 1, 2, 2, 0, 1, 2, 0, 1, 2, 0], - [2, 1, 2, 0, 1, 1, 2, 0, 2, 1, 0, 1, 1, 2, 1, 0, 2, 0, 2, 1], - [2, 1, 2, 1, 0, 1, 2, 2, 1, 1, 2, 0, 2, 1, 0, 0, 1, 2, 0, 0], - [2, 2, 1, 1, 1, 1, 0, 1, 0, 0, 2, 2, 1, 2, 2, 1, 0, 1, 0, 2]] + return [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [0, 1, 1, 1, 1, 0, 1, 2, 2, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2], [0, 2, 2, 2, 2, 2, 2, 0, 1, 0, 0, 0, 0, 1, 2, 2, 0, 1, 1, 1], [1, 0, 1, 1, 1, 2, 2, 0, 1, 0, 1, 1, 2, 0, 0, 1, 1, 0, 1, 2], [1, 1, 2, 2, 2, 1, 0, 1, 0, 2, 1, 1, 0, 0, 2, 1, 2, 2, 1, 0], [1, 2, 0, 1, 2, 0, 2, 1, 0, 2, 0, 2, 2, 1, 0, 2, 1, 0, 2, 1], [1, 2, 1, 0, 2, 2, 1, 2, 0, 1, 2, 1, 1, 0, 1, 2, 0, 2, 0, 1], [1, 2, 1, 2, 0, 2, 1, 1, 2, 2, 1, 0, 1, 2, 0, 0, 2, 1, 0, 0], [2, 0, 2, 2, 2, 0, 1, 2, 2, 1, 2, 2, 0, 2, 2, 0, 1, 0, 1, 2], [2, 1, 0, 2, 1, 2, 0, 2, 2, 2, 1, 2, 2, 0, 1, 2, 0, 1, 2, 0], [2, 1, 2, 0, 1, 1, 2, 0, 2, 1, 0, 1, 1, 2, 1, 0, 2, 0, 2, 1], [2, 1, 2, 1, 0, 1, 2, 2, 1, 1, 2, 0, 2, 1, 0, 0, 1, 2, 0, 0], [2, 2, 1, 1, 1, 1, 0, 1, 0, 0, 2, 2, 1, 2, 2, 1, 0, 1, 0, 2]] def ca_19_2_6_4(): @@ -5310,25 +5182,7 @@ def ca_19_2_6_4(): True """ - return [[0, 0, 0, 2, 0, 0], - [0, 0, 1, 0, 1, 1], - [0, 1, 3, 1, 2, 1], - [0, 2, 2, 3, 0, 2], - [0, 3, 3, 2, 3, 3], - [1, 0, 3, 1, 1, 2], - [1, 1, 0, 3, 1, 3], - [1, 1, 2, 0, 3, 0], - [1, 2, 1, 2, 2, 0], - [1, 3, 1, 3, 0, 1], - [2, 0, 2, 3, 2, 3], - [2, 1, 1, 2, 3, 2], - [2, 2, 0, 1, 3, 1], - [2, 2, 3, 0, 0, 3], - [2, 3, 2, 1, 1, 0], - [3, 0, 3, 3, 3, 0], - [3, 1, 1, 1, 0, 3], - [3, 2, 2, 2, 1, 1], - [3, 3, 0, 0, 2, 2]] + return [[0, 0, 0, 2, 0, 0], [0, 0, 1, 0, 1, 1], [0, 1, 3, 1, 2, 1], [0, 2, 2, 3, 0, 2], [0, 3, 3, 2, 3, 3], [1, 0, 3, 1, 1, 2], [1, 1, 0, 3, 1, 3], [1, 1, 2, 0, 3, 0], [1, 2, 1, 2, 2, 0], [1, 3, 1, 3, 0, 1], [2, 0, 2, 3, 2, 3], [2, 1, 1, 2, 3, 2], [2, 2, 0, 1, 3, 1], [2, 2, 3, 0, 0, 3], [2, 3, 2, 1, 1, 0], [3, 0, 3, 3, 3, 0], [3, 1, 1, 1, 0, 3], [3, 2, 2, 2, 1, 1], [3, 3, 0, 0, 2, 2]] def ca_21_2_7_4(): @@ -5347,27 +5201,7 @@ def ca_21_2_7_4(): True """ - return [[0, 0, 1, 0, 0, 0, 0], - [0, 0, 3, 1, 1, 1, 1], - [0, 1, 1, 2, 2, 2, 2], - [0, 1, 2, 3, 0, 1, 3], - [0, 2, 0, 3, 3, 0, 2], - [0, 3, 1, 3, 3, 3, 1], - [1, 0, 0, 3, 2, 3, 3], - [1, 1, 3, 1, 3, 3, 0], - [1, 2, 1, 2, 1, 0, 3], - [1, 2, 3, 2, 0, 2, 1], - [1, 3, 2, 0, 1, 1, 2], - [2, 0, 3, 0, 3, 2, 3], - [2, 1, 2, 1, 2, 0, 1], - [2, 2, 1, 1, 0, 3, 2], - [2, 2, 2, 3, 1, 2, 0], - [2, 3, 0, 2, 3, 1, 0], - [3, 0, 2, 2, 3, 3, 2], - [3, 1, 0, 0, 1, 3, 1], - [3, 2, 1, 0, 2, 1, 0], - [3, 3, 0, 1, 0, 2, 3], - [3, 3, 3, 3, 2, 0, 2]] + return [[0, 0, 1, 0, 0, 0, 0], [0, 0, 3, 1, 1, 1, 1], [0, 1, 1, 2, 2, 2, 2], [0, 1, 2, 3, 0, 1, 3], [0, 2, 0, 3, 3, 0, 2], [0, 3, 1, 3, 3, 3, 1], [1, 0, 0, 3, 2, 3, 3], [1, 1, 3, 1, 3, 3, 0], [1, 2, 1, 2, 1, 0, 3], [1, 2, 3, 2, 0, 2, 1], [1, 3, 2, 0, 1, 1, 2], [2, 0, 3, 0, 3, 2, 3], [2, 1, 2, 1, 2, 0, 1], [2, 2, 1, 1, 0, 3, 2], [2, 2, 2, 3, 1, 2, 0], [2, 3, 0, 2, 3, 1, 0], [3, 0, 2, 2, 3, 3, 2], [3, 1, 0, 0, 1, 3, 1], [3, 2, 1, 0, 2, 1, 0], [3, 3, 0, 1, 0, 2, 3], [3, 3, 3, 3, 2, 0, 2]] def ca_29_2_7_5(): @@ -5385,35 +5219,7 @@ def ca_29_2_7_5(): True """ - return [[0, 2, 2, 3, 0, 0, 0], - [1, 4, 3, 4, 2, 3, 0], - [2, 3, 0, 0, 4, 2, 0], - [3, 0, 1, 2, 3, 4, 0], - [4, 1, 4, 1, 1, 1, 0], - [0, 0, 2, 4, 1, 2, 1], - [1, 2, 4, 0, 2, 4, 1], - [1, 3, 1, 2, 1, 0, 1], - [2, 1, 2, 2, 4, 3, 1], - [3, 3, 3, 1, 0, 1, 1], - [4, 4, 0, 3, 3, 0, 1], - [0, 1, 3, 0, 3, 0, 2], - [1, 0, 3, 3, 4, 1, 2], - [2, 2, 1, 4, 3, 1, 2], - [2, 4, 4, 2, 0, 2, 2], - [3, 2, 0, 1, 1, 3, 2], - [4, 3, 2, 4, 2, 4, 2], - [0, 3, 4, 3, 3, 3, 3], - [1, 1, 0, 4, 0, 4, 3], - [2, 0, 4, 1, 2, 0, 3], - [3, 1, 1, 3, 2, 2, 3], - [3, 4, 2, 0, 1, 1, 3], - [4, 2, 3, 2, 4, 2, 3], - [0, 0, 0, 2, 2, 1, 4], - [0, 4, 1, 1, 4, 4, 4], - [1, 1, 2, 1, 3, 2, 4], - [2, 2, 3, 3, 1, 4, 4], - [3, 3, 4, 4, 4, 0, 4], - [4, 0, 1, 0, 0, 3, 4]] + return [[0, 2, 2, 3, 0, 0, 0], [1, 4, 3, 4, 2, 3, 0], [2, 3, 0, 0, 4, 2, 0], [3, 0, 1, 2, 3, 4, 0], [4, 1, 4, 1, 1, 1, 0], [0, 0, 2, 4, 1, 2, 1], [1, 2, 4, 0, 2, 4, 1], [1, 3, 1, 2, 1, 0, 1], [2, 1, 2, 2, 4, 3, 1], [3, 3, 3, 1, 0, 1, 1], [4, 4, 0, 3, 3, 0, 1], [0, 1, 3, 0, 3, 0, 2], [1, 0, 3, 3, 4, 1, 2], [2, 2, 1, 4, 3, 1, 2], [2, 4, 4, 2, 0, 2, 2], [3, 2, 0, 1, 1, 3, 2], [4, 3, 2, 4, 2, 4, 2], [0, 3, 4, 3, 3, 3, 3], [1, 1, 0, 4, 0, 4, 3], [2, 0, 4, 1, 2, 0, 3], [3, 1, 1, 3, 2, 2, 3], [3, 4, 2, 0, 1, 1, 3], [4, 2, 3, 2, 4, 2, 3], [0, 0, 0, 2, 2, 1, 4], [0, 4, 1, 1, 4, 4, 4], [1, 1, 2, 1, 3, 2, 4], [2, 2, 3, 3, 1, 4, 4], [3, 3, 4, 4, 4, 0, 4], [4, 0, 1, 0, 0, 3, 4]] def ca_37_2_4_6(): @@ -5431,43 +5237,7 @@ def ca_37_2_4_6(): True """ - return [[0, 0, 1, 0], - [0, 0, 2, 1], - [0, 1, 0, 2], - [0, 2, 0, 5], - [0, 3, 3, 3], - [0, 4, 4, 4], - [0, 5, 5, 5], - [1, 0, 0, 4], - [1, 1, 1, 5], - [1, 2, 3, 1], - [1, 3, 4, 0], - [1, 4, 5, 3], - [1, 5, 2, 2], - [2, 0, 0, 3], - [2, 1, 4, 1], - [2, 2, 5, 4], - [2, 3, 1, 2], - [2, 4, 2, 5], - [2, 5, 3, 0], - [3, 0, 5, 2], - [3, 1, 3, 4], - [3, 2, 2, 0], - [3, 3, 0, 5], - [3, 4, 1, 1], - [3, 5, 4, 3], - [4, 0, 3, 5], - [4, 1, 2, 3], - [4, 2, 4, 2], - [4, 3, 5, 1], - [4, 4, 0, 0], - [4, 5, 1, 4], - [5, 0, 4, 5], - [5, 1, 5, 0], - [5, 2, 1, 3], - [5, 3, 2, 4], - [5, 4, 3, 2], - [5, 5, 0, 1]] + return [[0, 0, 1, 0], [0, 0, 2, 1], [0, 1, 0, 2], [0, 2, 0, 5], [0, 3, 3, 3], [0, 4, 4, 4], [0, 5, 5, 5], [1, 0, 0, 4], [1, 1, 1, 5], [1, 2, 3, 1], [1, 3, 4, 0], [1, 4, 5, 3], [1, 5, 2, 2], [2, 0, 0, 3], [2, 1, 4, 1], [2, 2, 5, 4], [2, 3, 1, 2], [2, 4, 2, 5], [2, 5, 3, 0], [3, 0, 5, 2], [3, 1, 3, 4], [3, 2, 2, 0], [3, 3, 0, 5], [3, 4, 1, 1], [3, 5, 4, 3], [4, 0, 3, 5], [4, 1, 2, 3], [4, 2, 4, 2], [4, 3, 5, 1], [4, 4, 0, 0], [4, 5, 1, 4], [5, 0, 4, 5], [5, 1, 5, 0], [5, 2, 1, 3], [5, 3, 2, 4], [5, 4, 3, 2], [5, 5, 0, 1]] def ca_39_2_5_6(): @@ -5485,45 +5255,7 @@ def ca_39_2_5_6(): True """ - return [[0, 0, 1, 1, 0], - [1, 5, 2, 2, 0], - [2, 4, 5, 4, 0], - [3, 2, 0, 3, 0], - [4, 3, 4, 5, 0], - [5, 1, 3, 0, 0], - [0, 4, 4, 3, 1], - [1, 3, 5, 0, 1], - [2, 2, 1, 2, 1], - [3, 0, 3, 5, 1], - [4, 1, 2, 1, 1], - [5, 5, 0, 4, 1], - [0, 5, 5, 5, 2], - [1, 1, 1, 3, 2], - [2, 3, 0, 1, 2], - [3, 4, 2, 0, 2], - [4, 2, 3, 4, 2], - [5, 0, 4, 2, 2], - [0, 1, 0, 4, 3], - [0, 3, 3, 2, 3], - [1, 0, 2, 4, 3], - [2, 2, 4, 0, 3], - [3, 5, 4, 1, 3], - [4, 0, 5, 3, 3], - [5, 4, 1, 5, 3], - [0, 0, 0, 0, 4], - [1, 2, 0, 5, 4], - [1, 4, 3, 1, 4], - [2, 1, 4, 4, 4], - [3, 1, 5, 2, 4], - [4, 5, 1, 0, 4], - [5, 3, 2, 3, 4], - [0, 2, 2, 0, 5], - [1, 1, 4, 5, 5], - [2, 0, 2, 5, 5], - [2, 5, 3, 3, 5], - [3, 3, 1, 4, 5], - [4, 4, 0, 2, 5], - [5, 2, 5, 1, 5]] + return [[0, 0, 1, 1, 0], [1, 5, 2, 2, 0], [2, 4, 5, 4, 0], [3, 2, 0, 3, 0], [4, 3, 4, 5, 0], [5, 1, 3, 0, 0], [0, 4, 4, 3, 1], [1, 3, 5, 0, 1], [2, 2, 1, 2, 1], [3, 0, 3, 5, 1], [4, 1, 2, 1, 1], [5, 5, 0, 4, 1], [0, 5, 5, 5, 2], [1, 1, 1, 3, 2], [2, 3, 0, 1, 2], [3, 4, 2, 0, 2], [4, 2, 3, 4, 2], [5, 0, 4, 2, 2], [0, 1, 0, 4, 3], [0, 3, 3, 2, 3], [1, 0, 2, 4, 3], [2, 2, 4, 0, 3], [3, 5, 4, 1, 3], [4, 0, 5, 3, 3], [5, 4, 1, 5, 3], [0, 0, 0, 0, 4], [1, 2, 0, 5, 4], [1, 4, 3, 1, 4], [2, 1, 4, 4, 4], [3, 1, 5, 2, 4], [4, 5, 1, 0, 4], [5, 3, 2, 3, 4], [0, 2, 2, 0, 5], [1, 1, 4, 5, 5], [2, 0, 2, 5, 5], [2, 5, 3, 3, 5], [3, 3, 1, 4, 5], [4, 4, 0, 2, 5], [5, 2, 5, 1, 5]] def ca_41_2_6_6(): @@ -5542,73 +5274,23 @@ def ca_41_2_6_6(): True """ - return [[0, 0, 0, 0, 0, 0], - [1, 1, 4, 5, 4, 0], - [2, 3, 3, 5, 2, 0], - [3, 0, 2, 3, 3, 0], - [3, 5, 5, 2, 1, 0], - [4, 2, 1, 4, 5, 0], - [5, 4, 4, 1, 1, 0], - [0, 0, 1, 1, 1, 1], - [1, 2, 5, 1, 2, 1], - [2, 4, 4, 3, 5, 1], - [2, 5, 2, 4, 0, 1], - [3, 1, 3, 0, 4, 1], - [4, 4, 0, 5, 3, 1], - [5, 3, 1, 2, 0, 1], - [0, 1, 2, 2, 2, 2], - [1, 3, 1, 3, 4, 2], - [1, 5, 4, 0, 3, 2], - [2, 0, 5, 5, 1, 2], - [3, 3, 0, 1, 5, 2], - [4, 4, 3, 2, 0, 2], - [5, 2, 3, 4, 3, 2], - [0, 2, 3, 3, 1, 3], - [0, 5, 1, 5, 5, 3], - [1, 4, 2, 1, 0, 3], - [2, 2, 0, 2, 4, 3], - [3, 3, 5, 4, 3, 3], - [4, 0, 4, 4, 2, 3], - [5, 1, 5, 0, 5, 3], - [0, 3, 4, 2, 3, 4], - [1, 1, 0, 4, 1, 4], - [2, 2, 2, 0, 5, 4], - [3, 4, 1, 0, 2, 4], - [4, 1, 5, 3, 0, 4], - [4, 5, 3, 1, 4, 4], - [5, 0, 2, 5, 4, 4], - [0, 4, 5, 4, 4, 5], - [1, 0, 3, 2, 5, 5], - [2, 1, 1, 1, 3, 5], - [3, 2, 4, 5, 0, 5], - [4, 3, 2, 0, 1, 5], - [5, 5, 0, 3, 2, 5]] + return [[0, 0, 0, 0, 0, 0], [1, 1, 4, 5, 4, 0], [2, 3, 3, 5, 2, 0], [3, 0, 2, 3, 3, 0], [3, 5, 5, 2, 1, 0], [4, 2, 1, 4, 5, 0], [5, 4, 4, 1, 1, 0], [0, 0, 1, 1, 1, 1], [1, 2, 5, 1, 2, 1], [2, 4, 4, 3, 5, 1], [2, 5, 2, 4, 0, 1], [3, 1, 3, 0, 4, 1], [4, 4, 0, 5, 3, 1], [5, 3, 1, 2, 0, 1], [0, 1, 2, 2, 2, 2], [1, 3, 1, 3, 4, 2], [1, 5, 4, 0, 3, 2], [2, 0, 5, 5, 1, 2], [3, 3, 0, 1, 5, 2], [4, 4, 3, 2, 0, 2], [5, 2, 3, 4, 3, 2], [0, 2, 3, 3, 1, 3], [0, 5, 1, 5, 5, 3], [1, 4, 2, 1, 0, 3], [2, 2, 0, 2, 4, 3], [3, 3, 5, 4, 3, 3], [4, 0, 4, 4, 2, 3], [5, 1, 5, 0, 5, 3], [0, 3, 4, 2, 3, 4], [1, 1, 0, 4, 1, 4], [2, 2, 2, 0, 5, 4], [3, 4, 1, 0, 2, 4], [4, 1, 5, 3, 0, 4], [4, 5, 3, 1, 4, 4], [5, 0, 2, 5, 4, 4], [0, 4, 5, 4, 4, 5], [1, 0, 3, 2, 5, 5], [2, 1, 1, 1, 3, 5], [3, 2, 4, 5, 0, 5], [4, 3, 2, 0, 1, 5], [5, 5, 0, 3, 2, 5]] # Make dictionary with keys (t, v) and values (N, k) which are the # smallest N and largest k such that a CA(N; t, k, v) can be made using # the database. -CA_constructions = { - (2,3): ((11,5), (12,7), (13,9), (14,10), (15,20)), - (2,4): ((19,6), (21,7)), - (2,5): ((29,7),), - (2,6): ((37,4), (39,5), (41,6)) -} +CA_constructions = {(2, 3): ((11, 5), (12, 7), (13, 9), (14, 10), (15, 20)), (2, 4): ((19, 6), (21, 7)), (2, 5): ((29, 7),), (2, 6): ((37, 4), (39, 5), (41, 6))} # Add this data to the module's doc. -LIST_OF_CA_CONSTRUCTIONS = ", ".join(":func:`CA({},{},{},{}) `".format(N,t,k,v,N,t,k,v) - for (t,v) in CA_constructions for (N,k) in CA_constructions[(t,v)]) - - -__doc__ = __doc__.format( - LIST_OF_OA_CONSTRUCTIONS=LIST_OF_OA_CONSTRUCTIONS, - LIST_OF_MOLS_CONSTRUCTIONS=LIST_OF_MOLS_CONSTRUCTIONS, - LIST_OF_VMT_VECTORS=LIST_OF_VMT_VECTORS, - LIST_OF_BIBD=LIST_OF_BIBD, - LIST_OF_DF=LIST_OF_DF, - LIST_OF_DM=LIST_OF_DM, - LIST_OF_QDM=LIST_OF_QDM, - LIST_OF_EDS=LIST_OF_EDS, - LIST_OF_CA_CONSTRUCTIONS=LIST_OF_CA_CONSTRUCTIONS) -del LIST_OF_OA_CONSTRUCTIONS, LIST_OF_MOLS_CONSTRUCTIONS, LIST_OF_VMT_VECTORS,LIST_OF_DF, LIST_OF_DM, LIST_OF_QDM, LIST_OF_EDS, LIST_OF_BIBD, LIST_OF_CA_CONSTRUCTIONS -del PolynomialRing, ZZ, a, f, +LIST_OF_CA_CONSTRUCTIONS = ", ".join(":func:`CA({},{},{},{}) `".format(N, t, k, v, N, t, k, v) for (t, v) in CA_constructions for (N, k) in CA_constructions[(t, v)]) + + +__doc__ = __doc__.format(LIST_OF_OA_CONSTRUCTIONS=LIST_OF_OA_CONSTRUCTIONS, LIST_OF_MOLS_CONSTRUCTIONS=LIST_OF_MOLS_CONSTRUCTIONS, LIST_OF_VMT_VECTORS=LIST_OF_VMT_VECTORS, LIST_OF_BIBD=LIST_OF_BIBD, LIST_OF_DF=LIST_OF_DF, LIST_OF_DM=LIST_OF_DM, LIST_OF_QDM=LIST_OF_QDM, LIST_OF_EDS=LIST_OF_EDS, LIST_OF_CA_CONSTRUCTIONS=LIST_OF_CA_CONSTRUCTIONS) +del LIST_OF_OA_CONSTRUCTIONS, LIST_OF_MOLS_CONSTRUCTIONS, LIST_OF_VMT_VECTORS, LIST_OF_DF, LIST_OF_DM, LIST_OF_QDM, LIST_OF_EDS, LIST_OF_BIBD, LIST_OF_CA_CONSTRUCTIONS +del ( + PolynomialRing, + ZZ, + a, + f, +) diff --git a/src/sage/combinat/designs/design_catalog.py b/src/sage/combinat/designs/design_catalog.py index 7ee184646bc..69be7c3c5be 100644 --- a/src/sage/combinat/designs/design_catalog.py +++ b/src/sage/combinat/designs/design_catalog.py @@ -74,50 +74,28 @@ .. [1] La Jolla Covering Repository, https://dmgordon.org/cover """ + from sage.misc.lazy_import import lazy_import -lazy_import('sage.combinat.designs.block_design', - ('BlockDesign', - 'ProjectiveGeometryDesign', - 'DesarguesianProjectivePlaneDesign', - 'projective_plane', - 'AffineGeometryDesign', - 'WittDesign', - 'HadamardDesign', - 'Hadamard3Design', - 'HughesPlane', - 'CremonaRichmondConfiguration')) +lazy_import('sage.combinat.designs.block_design', ('BlockDesign', 'ProjectiveGeometryDesign', 'DesarguesianProjectivePlaneDesign', 'projective_plane', 'AffineGeometryDesign', 'WittDesign', 'HadamardDesign', 'Hadamard3Design', 'HughesPlane', 'CremonaRichmondConfiguration')) lazy_import('sage.combinat.designs.database', 'HigmanSimsDesign') -lazy_import('sage.combinat.designs.steiner_quadruple_systems', - 'steiner_quadruple_system') +lazy_import('sage.combinat.designs.steiner_quadruple_systems', 'steiner_quadruple_system') -lazy_import('sage.combinat.designs.covering_design', - 'best_known_covering_design_www', - as_='best_known_covering_design_from_LJCR') +lazy_import('sage.combinat.designs.covering_design', 'best_known_covering_design_www', as_='best_known_covering_design_from_LJCR') -lazy_import('sage.combinat.designs.latin_squares', - 'mutually_orthogonal_latin_squares') +lazy_import('sage.combinat.designs.latin_squares', 'mutually_orthogonal_latin_squares') -lazy_import('sage.combinat.designs.orthogonal_arrays', - ('transversal_design', 'incomplete_orthogonal_array')) +lazy_import('sage.combinat.designs.orthogonal_arrays', ('transversal_design', 'incomplete_orthogonal_array')) lazy_import('sage.combinat.designs.difference_family', 'difference_family') lazy_import('sage.combinat.designs.difference_matrices', 'difference_matrix') -lazy_import('sage.combinat.designs.bibd', - ('balanced_incomplete_block_design', 'steiner_triple_system', 'biplane')) -lazy_import('sage.combinat.designs.resolvable_bibd', - ('resolvable_balanced_incomplete_block_design', - 'kirkman_triple_system')) -lazy_import('sage.combinat.designs.group_divisible_designs', - 'group_divisible_design') - -lazy_import('sage.combinat.designs.orthogonal_arrays', - 'OAMainFunctions', as_='orthogonal_arrays') - -lazy_import('sage.combinat.designs.gen_quadrangles_with_spread', - ('generalised_quadrangle_with_spread', - 'generalised_quadrangle_symplectic_with_spread', - 'generalised_quadrangle_hermitian_with_ovoid')) +lazy_import('sage.combinat.designs.bibd', ('balanced_incomplete_block_design', 'steiner_triple_system', 'biplane')) +lazy_import('sage.combinat.designs.resolvable_bibd', ('resolvable_balanced_incomplete_block_design', 'kirkman_triple_system')) +lazy_import('sage.combinat.designs.group_divisible_designs', 'group_divisible_design') + +lazy_import('sage.combinat.designs.orthogonal_arrays', 'OAMainFunctions', as_='orthogonal_arrays') + +lazy_import('sage.combinat.designs.gen_quadrangles_with_spread', ('generalised_quadrangle_with_spread', 'generalised_quadrangle_symplectic_with_spread', 'generalised_quadrangle_hermitian_with_ovoid')) diff --git a/src/sage/combinat/designs/difference_family.py b/src/sage/combinat/designs/difference_family.py index 4e6ee0eba72..6ec1ce8fa2d 100644 --- a/src/sage/combinat/designs/difference_family.py +++ b/src/sage/combinat/designs/difference_family.py @@ -38,6 +38,7 @@ Functions --------- """ + # **************************************************************************** # Copyright (C) 2014 Vincent Delecroix <20100.delecroix@gmail.com> # @@ -77,7 +78,7 @@ def group_law(G) -> tuple: from sage.categories.groups import Groups from sage.categories.additive_groups import AdditiveGroups - if G in Groups(): # multiplicative groups + if G in Groups(): # multiplicative groups return (G.one(), operator.mul, operator.inv) if G in AdditiveGroups(): # additive groups return (G.zero(), operator.add, operator.neg) @@ -251,19 +252,19 @@ def is_difference_family(G, D, v=None, k=None, l=None, verbose=False) -> bool: nb_diff = 0 stab = [] for d in D: - s = block_stabilizer(G,d) + s = block_stabilizer(G, d) stab.append(s) - nb_diff += k*(k-1) // len(s) + nb_diff += k * (k - 1) // len(s) if l is None: - if nb_diff % (v-1) != 0: + if nb_diff % (v - 1) != 0: if verbose: - print("the number of differences (={}) must be a multiple of v-1={}".format(nb_diff, v-1)) + print("the number of differences (={}) must be a multiple of v-1={}".format(nb_diff, v - 1)) return False - l = nb_diff // (v-1) + l = nb_diff // (v - 1) else: - if nb_diff != l*(v-1): + if nb_diff != l * (v - 1): if verbose: - print("the number of differences (={}) is not equal to l*(v-1) = {}".format(nb_diff, l*(v-1))) + print("the number of differences (={}) is not equal to l*(v-1) = {}".format(nb_diff, l * (v - 1))) return False # Check that every x \in G-{0},occurs exactly l times as a difference @@ -271,7 +272,7 @@ def is_difference_family(G, D, v=None, k=None, l=None, verbose=False) -> bool: where = {g: set() for g in Glist} del counter[identity] - for i,d in enumerate(D): + for i, d in enumerate(D): tmp_counter = {} for b in d: for c in d: @@ -313,13 +314,11 @@ def is_difference_family(G, D, v=None, k=None, l=None, verbose=False) -> bool: if too_few: print("Too few:") for g in too_few: - print(" {} is obtained {} times in blocks {}".format( - g, counter[g], sorted(where[g]))) + print(" {} is obtained {} times in blocks {}".format(g, counter[g], sorted(where[g]))) if too_much: print("Too much:") for g in too_much: - print(" {} is obtained {} times in blocks {}".format( - g, counter[g], sorted(where[g]))) + print(" {} is obtained {} times in blocks {}".format(g, counter[g], sorted(where[g]))) if too_few or too_much: return False @@ -385,12 +384,12 @@ def singer_difference_set(q, d) -> tuple: # build a polynomial c over GF(q) such that GF(q)[x] / (c(x)) is a # GF(q**(d+1)) and such that x is a multiplicative generator. - p,e = q.factor()[0] - c = conway_polynomial(p, e*(d+1)) + p, e = q.factor()[0] + c = conway_polynomial(p, e * (d + 1)) if e != 1: # i.e. q is not a prime, so we factorize c over GF(q) and pick # one of its factor - K = GF(q,'z') + K = GF(q, 'z') c = c.change_ring(K).factor()[0][0] else: K = GF(q) @@ -403,14 +402,14 @@ def singer_difference_set(q, d) -> tuple: powers = [0] i = 1 x = z - k = (q**d-1)//(q-1) + k = (q**d - 1) // (q - 1) while len(powers) < k: - if x.degree() <= (d-1): + if x.degree() <= (d - 1): powers.append(i) - x = (x*z).mod(c) + x = (x * z).mod(c) i += 1 - return Zmod((q**(d+1)-1)//(q-1)), [powers] + return Zmod((q ** (d + 1) - 1) // (q - 1)), [powers] def df_q_6_1(K, existence=False, check=True): @@ -444,22 +443,22 @@ def df_q_6_1(K, existence=False, check=True): if existence: return False raise EmptySetError("k(k-1)=30 should divide (v-1)") - t = (v-1) // 30 # number of blocks + t = (v - 1) // 30 # number of blocks - r = x**((v-1)//3) # primitive cube root of unity - r2 = r*r # the other primitive cube root + r = x ** ((v - 1) // 3) # primitive cube root of unity + r2 = r * r # the other primitive cube root # we now compute the cosets of x**i xx = x**5 - to_coset = {x**i * xx**j: i for i in range(5) for j in range((v-1)/5)} + to_coset = {x**i * xx**j: i for i in range(5) for j in range((v - 1) / 5)} for c in to_coset: # the loop runs through all nonzero elements of K if c == one or c == r or c == r2: continue - if len(set(to_coset[elt] for elt in (r-one, c*(r-one), c-one, c-r, c-r**2))) == 5: + if len(set(to_coset[elt] for elt in (r - one, c * (r - one), c - one, c - r, c - r**2))) == 5: if existence: return True - B = [one,r,r2,c,c*r,c*r2] + B = [one, r, r2, c, c * r, c * r2] D = [[xx**i * b for b in B] for i in range(t)] break else: @@ -546,49 +545,49 @@ def radical_difference_set(K, k, l=1, existence=False, check=True): """ v = K.cardinality() - if l*(v-1) != k*(k-1): + if l * (v - 1) != k * (k - 1): if existence: return False raise EmptySetError("l*(v-1) is not equal to k*(k-1)") # trivial case - if (v-1) == k: + if (v - 1) == k: if existence: return True add_zero = False # q = 3 mod 4 - elif v % 4 == 3 and k == (v-1)//2: + elif v % 4 == 3 and k == (v - 1) // 2: if existence: return True add_zero = False # q = 3 mod 4 - elif v % 4 == 3 and k == (v+1)//2: + elif v % 4 == 3 and k == (v + 1) // 2: if existence: return True add_zero = True # q = 4t^2 + 1, t odd - elif v % 8 == 5 and k == (v-1)//4 and is_square((v-1)//4): + elif v % 8 == 5 and k == (v - 1) // 4 and is_square((v - 1) // 4): if existence: return True add_zero = False # q = 4t^2 + 9, t odd - elif v % 8 == 5 and k == (v+3)//4 and is_square((v-9)//4): + elif v % 8 == 5 and k == (v + 3) // 4 and is_square((v - 9) // 4): if existence: return True add_zero = True # exceptional case 1 - elif (v,k,l) == (16,6,2): + elif (v, k, l) == (16, 6, 2): if existence: return True add_zero = True # exceptional case 2 - elif (v,k,l) == (73,9,1): + elif (v, k, l) == (73, 9, 1): if existence: return True add_zero = False @@ -596,22 +595,18 @@ def radical_difference_set(K, k, l=1, existence=False, check=True): # are there more ?? else: x = K.multiplicative_generator() - D = K.cyclotomic_cosets(x**((v-1)//k), [K.one()]) + D = K.cyclotomic_cosets(x ** ((v - 1) // k), [K.one()]) if is_difference_family(K, D, v, k, l): - print("** You found a new example of radical difference set **\n" - "** for the parameters (v,k,l)=({},{},{}). **\n" - "** Please contact sage-devel@googlegroups.com **\n".format(v, k, l)) + print("** You found a new example of radical difference set **\n" "** for the parameters (v,k,l)=({},{},{}). **\n" "** Please contact sage-devel@googlegroups.com **\n".format(v, k, l)) if existence: return True add_zero = False else: - D = K.cyclotomic_cosets(x**((v-1)//(k-1)), [K.one()]) - D[0].insert(0,K.zero()) + D = K.cyclotomic_cosets(x ** ((v - 1) // (k - 1)), [K.one()]) + D[0].insert(0, K.zero()) if is_difference_family(K, D, v, k, l): - print("** You found a new example of radical difference set **\n" - "** for the parameters (v,k,l)=({},{},{}). **\n" - "** Please contact sage-devel@googlegroups.com **\n".format(v, k, l)) + print("** You found a new example of radical difference set **\n" "** for the parameters (v,k,l)=({},{},{}). **\n" "** Please contact sage-devel@googlegroups.com **\n".format(v, k, l)) if existence: return True add_zero = True @@ -619,22 +614,19 @@ def radical_difference_set(K, k, l=1, existence=False, check=True): elif existence: return False else: - raise EmptySetError("no radical difference set exist " - "for the parameters (v,k,l) = ({},{},{}".format(v,k,l)) + raise EmptySetError("no radical difference set exist " "for the parameters (v,k,l) = ({},{},{}".format(v, k, l)) x = K.multiplicative_generator() if add_zero: - r = x**((v-1)//(k-1)) + r = x ** ((v - 1) // (k - 1)) D = K.cyclotomic_cosets(r, [K.one()]) D[0].insert(0, K.zero()) else: - r = x**((v-1)//k) + r = x ** ((v - 1) // k) D = K.cyclotomic_cosets(r, [K.one()]) if check and not is_difference_family(K, D, v, k, l): - raise RuntimeError("Sage tried to build a radical difference set with " - "parameters ({},{},{}) but it seems that it failed! Please " - "e-mail sage-devel@googlegroups.com".format(v,k,l)) + raise RuntimeError("Sage tried to build a radical difference set with " "parameters ({},{},{}) but it seems that it failed! Please " "e-mail sage-devel@googlegroups.com".format(v, k, l)) return D @@ -690,17 +682,17 @@ def one_cyclic_tiling(A, n): n = int(n) d = len(A) if len(set(a % d for a in A)) == d: - return [i*d for i in range(n//d)] + return [i * d for i in range(n // d)] # next, we consider an exhaustive search from sage.combinat.dlx import DLXMatrix rows = [] for i in range(n): - rows.append([i+1, [(i+a) % n+1 for a in A]]) + rows.append([i + 1, [(i + a) % n + 1 for a in A]]) M = DLXMatrix(rows) for c in M: - return [i-1 for i in c] + return [i - 1 for i in c] def one_radical_difference_family(K, k): @@ -783,25 +775,25 @@ def one_radical_difference_family(K, k): q = K.cardinality() x = K.multiplicative_generator() - e = k*(k-1) + e = k * (k - 1) if q % e != 1: raise ValueError("q%e is not 1") # We define A by (see the function's documentation): # ΔB = C.A if k % 2 == 1: - m = (k-1) // 2 - r = x ** ((q-1) // k) # k-th root of unity - A = [r**i - 1 for i in range(1,m+1)] + m = (k - 1) // 2 + r = x ** ((q - 1) // k) # k-th root of unity + A = [r**i - 1 for i in range(1, m + 1)] else: m = k // 2 - r = x ** ((q-1) // (k-1)) # (k-1)-th root of unity - A = [r**i - 1 for i in range(1,m)] + r = x ** ((q - 1) // (k - 1)) # (k-1)-th root of unity + A = [r**i - 1 for i in range(1, m)] A.append(K.one()) # instead of the complicated multiplicative group K^*/(±C) we use the # discrete logarithm to convert everything into the additive group Z/cZ - c = m * (q-1) // e # cardinal of ±C + c = m * (q - 1) // e # cardinal of ±C logA = [a.log(x) % c for a in A] # if two elements of A are equal modulo c then no tiling is possible @@ -816,7 +808,7 @@ def one_radical_difference_family(K, k): D = K.cyclotomic_cosets(r, [x**i for i in tiling]) if k % 2 == 0: for d in D: - d.insert(K.zero(),0) + d.insert(K.zero(), 0) return D @@ -892,19 +884,18 @@ def radical_difference_family(K, k, l=1, existence=False, check=True): """ v = K.cardinality() x = K.multiplicative_generator() - e = k*(k-1) - if (l*(v-1)) % e: - raise ValueError("k (k-1) = {} should be a multiple of l (v-1) ={}".format( - k*(k-1), l*(v-1))) - t = l*(v-1) // e # number of blocks + e = k * (k - 1) + if (l * (v - 1)) % e: + raise ValueError("k (k-1) = {} should be a multiple of l (v-1) ={}".format(k * (k - 1), l * (v - 1))) + t = l * (v - 1) // e # number of blocks if t == 1: return radical_difference_set(K, k, l, existence=existence, check=check) - if l == (k-1): + if l == (k - 1): if existence: return True - return K.cyclotomic_cosets(x**((v-1)//k))[1:] + return K.cyclotomic_cosets(x ** ((v - 1) // k))[1:] # all the other cases below concern the case l == 1 if l != 1: @@ -913,7 +904,7 @@ def radical_difference_family(K, k, l=1, existence=False, check=True): raise NotImplementedError("No radical families implemented for l > 2") else: - D = one_radical_difference_family(K,k) + D = one_radical_difference_family(K, k) if D is None: if existence: return False @@ -922,10 +913,7 @@ def radical_difference_family(K, k, l=1, existence=False, check=True): return True if check and not is_difference_family(K, D, v, k, l): - raise RuntimeError("radical_difference_family produced a wrong " - "difference family with parameters v={}, " - "k={}, l={}. Please contact " - "sage-devel@googlegroups.com".format(v,k,l)) + raise RuntimeError("radical_difference_family produced a wrong " "difference family with parameters v={}, " "k={}, l={}. Please contact " "sage-devel@googlegroups.com".format(v, k, l)) return D @@ -961,8 +949,9 @@ def twin_prime_powers_difference_set(p, check=True): from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.categories.cartesian_product import cartesian_product from itertools import product - Fp = FiniteField(p,'x') - Fq = FiniteField(p+2,'x') + + Fp = FiniteField(p, 'x') + Fq = FiniteField(p + 2, 'x') Fpset = set(Fp) Fqset = set(Fq) Fp_squares = set(x**2 for x in Fpset) @@ -970,18 +959,16 @@ def twin_prime_powers_difference_set(p, check=True): # Pairs of squares, pairs of non-squares d = [] - d.extend(product(Fp_squares.difference([0]),Fq_squares.difference([0]))) - d.extend(product(Fpset.difference(Fp_squares),Fqset.difference(Fq_squares))) + d.extend(product(Fp_squares.difference([0]), Fq_squares.difference([0]))) + d.extend(product(Fpset.difference(Fp_squares), Fqset.difference(Fq_squares))) # All (x,0) - d.extend((x,0) for x in Fpset) + d.extend((x, 0) for x in Fpset) - G = cartesian_product([Fp,Fq]) + G = cartesian_product([Fp, Fq]) if check and not is_difference_family(G, [d]): - raise RuntimeError("twin_prime_powers_difference_set produced a wrong " - "difference set with p={}. Please contact " - "sage-devel@googlegroups.com".format(p)) + raise RuntimeError("twin_prime_powers_difference_set produced a wrong " "difference set with p={}. Please contact " "sage-devel@googlegroups.com".format(p)) return G, [d] @@ -1037,26 +1024,24 @@ def are_mcfarland_1973_parameters(v, k, lmbda, return_parameters=False): k = ZZ(k) lmbda = ZZ(lmbda) qs, r = (k - lmbda).sqrtrem() # sqrt(k-l) should be q^s - if r or (qs*(qs-1)) % lmbda: + if r or (qs * (qs - 1)) % lmbda: return (False, None) if return_parameters else False - q = qs*(qs-1) // lmbda + 1 - if (q <= 1 or - v * (q-1) != qs*q * (qs*q+q-2) or - k * (q-1) != qs * (qs*q-1)): + q = qs * (qs - 1) // lmbda + 1 + if q <= 1 or v * (q - 1) != qs * q * (qs * q + q - 2) or k * (q - 1) != qs * (qs * q - 1): return (False, None) if return_parameters else False # NOTE: below we compute the value of s so that qs = q^s. If the method # is_power_of of integers would be able to return the exponent, we could use # that... but currently this is not the case # see github issue #19792 - p1,a1 = qs.is_prime_power(get_data=True) - p2,a2 = q.is_prime_power(get_data=True) + p1, a1 = qs.is_prime_power(get_data=True) + p2, a2 = q.is_prime_power(get_data=True) if a1 == 0 or a2 == 0 or p1 != p2 or a1 % a2: return (False, None) if return_parameters else False - return (True, (q, a1//a2)) if return_parameters else True + return (True, (q, a1 // a2)) if return_parameters else True def mcfarland_1973_construction(q, s): @@ -1108,19 +1093,19 @@ def mcfarland_1973_construction(q, s): from sage.rings.finite_rings.integer_mod_ring import Zmod from sage.categories.cartesian_product import cartesian_product - r = (q**(s+1)-1) // (q-1) - F = GF(q,'a') - V = VectorSpace(F, s+1) - K = Zmod(r+1) + r = (q ** (s + 1) - 1) // (q - 1) + F = GF(q, 'a') + V = VectorSpace(F, s + 1) + K = Zmod(r + 1) - G = cartesian_product([F]*(s+1) + [K]) + G = cartesian_product([F] * (s + 1) + [K]) D = [] for k, H in zip(K, V.subspaces(s)): for v in H: D.append(G(tuple(v) + (k,))) - return G,[D] + return G, [D] def are_hadamard_difference_set_parameters(v, k, lmbda): @@ -1139,9 +1124,9 @@ def are_hadamard_difference_set_parameters(v, k, lmbda): sage: are_hadamard_difference_set_parameters(60, 13, 5) False """ - N = k - 2*lmbda - N2 = N*N - return v == 4*N2 and k == 2*N2 - N and lmbda == N2 - N + N = k - 2 * lmbda + N2 = N * N + return v == 4 * N2 and k == 2 * N2 - N and lmbda == N2 - N @cached_function @@ -1168,22 +1153,22 @@ def hadamard_difference_set_product_parameters(N): if N % 2: return False - for N1 in (N//2).divisors()[1:]: - if 4*N1 > N: + for N1 in (N // 2).divisors()[1:]: + if 4 * N1 > N: break - v1 = 4*N1*N1 - k1 = 2*N1*N1 - N1 - l1 = N1*N1 - N1 + v1 = 4 * N1 * N1 + k1 = 2 * N1 * N1 - N1 + l1 = N1 * N1 - N1 if not difference_family(v1, k1, l1, existence=True): continue - N2 = N // (2*N1) - v2 = 4*N2*N2 - k2 = 2*N2*N2 - N2 - l2 = N2*N2 - N2 + N2 = N // (2 * N1) + v2 = 4 * N2 * N2 + k2 = 2 * N2 * N2 - N2 + l2 = N2 * N2 - N2 if not difference_family(v2, k2, l2, existence=True): continue - return (N1,N2) + return (N1, N2) return None @@ -1216,14 +1201,13 @@ def hadamard_difference_set_product(G1, D1, G2, D2): """ from sage.categories.cartesian_product import cartesian_product - G = cartesian_product([G1,G2]) + G = cartesian_product([G1, G2]) D1 = set(D1[0]) D1c = set(s for s in G1 if s not in D1) D2 = set(D2[0]) D2c = set(s for s in G2 if s not in D2) - D = set().union((G((s1,s2)) for s1 in D1 for s2 in D2), - (G((s1,s2)) for s1 in D1c for s2 in D2c)) + D = set().union((G((s1, s2)) for s1 in D1 for s2 in D2), (G((s1, s2)) for s1 in D1c for s2 in D2c)) return G, [[s for s in G if s not in D]] @@ -1255,17 +1239,14 @@ def turyn_1965_3x3xK(k=4): if k == 2: G = cartesian_product([Zmod(3), Zmod(3), Zmod(2), Zmod(2)]) - K = [(0,0), (0,1), (1,0), (1,1)] + K = [(0, 0), (0, 1), (1, 0), (1, 1)] elif k == 4: G = cartesian_product([Zmod(3), Zmod(3), Zmod(4)]) K = [(0,), (1,), (2,), (3,)] else: raise ValueError("k must be 2 or 4") - L = [[(0,1),(1,1),(2,1),(0,2),(1,2),(2,2)], # complement of y=0 - [(0,0),(1,1),(2,2)], # x-y=0 - [(0,0),(1,2),(2,1)], # x+y=0 - [(0,0),(0,1),(0,2)]] # x=0 + L = [[(0, 1), (1, 1), (2, 1), (0, 2), (1, 2), (2, 2)], [(0, 0), (1, 1), (2, 2)], [(0, 0), (1, 2), (2, 1)], [(0, 0), (0, 1), (0, 2)]] # complement of y=0 # x-y=0 # x+y=0 # x=0 return G, [[G(v + k) for l, k in zip(L, K) for v in l]] @@ -1292,18 +1273,18 @@ def _is_periodic_sequence(seq, period): sage: _is_periodic_sequence([0, 1, 1, 1, 0, 1, 2, 1], 4) False """ - assert len(seq) >= 2*period + assert len(seq) >= 2 * period for per in range(1, period): first = seq[:per] periodic = True - for j in range(1, len(seq)//per): - if seq[j*per : (j+1)*per] != first: + for j in range(1, len(seq) // per): + if seq[j * per : (j + 1) * per] != first: periodic = False break if periodic: return False - return seq[:period] == seq[period:2 * period] + return seq[:period] == seq[period : 2 * period] def _create_m_sequence(q, n, check=True): @@ -1355,8 +1336,8 @@ def _create_m_sequence(q, n, check=True): exps = primitive.exponents() period = q**n - 1 - seq_len = period*2 if check else period - seq = [1] + [0]*(n-1) + seq_len = period * 2 if check else period + seq = [1] + [0] * (n - 1) while len(seq) < seq_len: nxt = 0 @@ -1467,8 +1448,8 @@ def relative_difference_set_from_m_sequence(q, N, check=True, return_group=False set1 = [i for i in G if m_seq[i[0]] == 1] if check: - H = _get_submodule_of_order(G, q-1) - assert is_relative_difference_set(set1, G, H, (period // (q-1), q - 1, q**(N-1), q**(N-2))) + H = _get_submodule_of_order(G, q - 1) + assert is_relative_difference_set(set1, G, H, (period // (q - 1), q - 1, q ** (N - 1), q ** (N - 2))) if return_group: return G, set1 @@ -1535,22 +1516,22 @@ def relative_difference_set_from_homomorphism(q, N, d, check=True, return_group= raise ValueError('q must be a prime power') if N < 2: raise ValueError('N must be at least 2') - if (q-1) % d != 0: + if (q - 1) % d != 0: raise ValueError('q-1 must be a multiple of d') G = AdditiveAbelianGroup([q**N - 1]) K = _get_submodule_of_order(G, d) assert K is not None, 'Could not find kernel' - G2 = G/K + G2 = G / K theta = G.hom([G2.gen(0)], G2) diff_set = relative_difference_set_from_m_sequence(q, N, check=False) second_diff_set = [theta(x) for x in diff_set] if check: - H = _get_submodule_of_order(G2, (q-1) // d) - assert is_relative_difference_set(second_diff_set, G2, H, ((q**N-1) // (q-1), (q-1) // d, q**(N-1), q**(N-2) * d)) + H = _get_submodule_of_order(G2, (q - 1) // d) + assert is_relative_difference_set(second_diff_set, G2, H, ((q**N - 1) // (q - 1), (q - 1) // d, q ** (N - 1), q ** (N - 2) * d)) if return_group: return G2, second_diff_set @@ -1700,6 +1681,7 @@ def is_supplementary_difference_set(Ks, v=None, lmbda=None, G=None, verbose=Fals if G is None: from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup + G = AdditiveAbelianGroup([v]) if v is not None and G.order() != v: @@ -1810,10 +1792,10 @@ def supplementary_difference_set_from_rel_diff_set(q, existence=False, check=Tru s = 0 m = -1 - while q > 2**(s+1) and (q-1) % 2**(s+1) == 0: - prime_pow = (q-1)//2**(s+1) - 1 + while q > 2 ** (s + 1) and (q - 1) % 2 ** (s + 1) == 0: + prime_pow = (q - 1) // 2 ** (s + 1) - 1 if is_prime_power(prime_pow) and prime_pow % 2 == 1: - m = (q - (2**(s+1) + 1)) // 2**(s+1) + 1 + m = (q - (2 ** (s + 1) + 1)) // 2 ** (s + 1) + 1 break s += 1 @@ -1825,9 +1807,10 @@ def supplementary_difference_set_from_rel_diff_set(q, existence=False, check=Tru if m == -1: raise ValueError('There is no s for which m-1 is an odd prime power') - set1 = relative_difference_set_from_homomorphism(m - 1, 2, (m-2) // 2, check=False) + set1 = relative_difference_set_from_homomorphism(m - 1, 2, (m - 2) // 2, check=False) from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + P = PolynomialRing(ZZ, 'x') # Compute psi3, psi4 @@ -1841,20 +1824,19 @@ def get_T(k): T += P.monomial(i) return T - modulo = P.monomial(2*m) - 1 + modulo = P.monomial(2 * m) - 1 - diff = get_T(2*m) - (1+P.monomial(m))*hall + diff = get_T(2 * m) - (1 + P.monomial(m)) * hall diff = diff.mod(modulo) exp1, exp2 = diff.exponents() - a = (exp1+exp2-m) // 2 + a = (exp1 + exp2 - m) // 2 psi3 = (P.monomial(a) + hall).mod(modulo) - psi4 = (P.monomial(a+m) + hall).mod(modulo) + psi4 = (P.monomial(a + m) + hall).mod(modulo) for i in range(s): m_start = 2**i * m - psi3, psi4 = (psi3(P.monomial(2)) + P.monomial(1)*psi4(P.monomial(2))).mod(P.monomial(4*m_start)-1), \ - (psi3(P.monomial(2)) + P.monomial(1)*(get_T(2*m_start)(P.monomial(2)) - psi4(P.monomial(2)))).mod(P.monomial(4*m_start)-1) + psi3, psi4 = (psi3(P.monomial(2)) + P.monomial(1) * psi4(P.monomial(2))).mod(P.monomial(4 * m_start) - 1), (psi3(P.monomial(2)) + P.monomial(1) * (get_T(2 * m_start)(P.monomial(2)) - psi4(P.monomial(2)))).mod(P.monomial(4 * m_start) - 1) # Construction of psi1, psi2 G2, set2 = relative_difference_set_from_m_sequence(q, 2, check=False, return_group=True) @@ -1862,36 +1844,37 @@ def get_T(k): phi_exps = [] for i in range(len(s3)): - for j in range(i+1, len(s3)): + for j in range(i + 1, len(s3)): diff = s3[i] - s3[j] - if diff % (q-1) == 0 and diff % (q**2-1) != 0: + if diff % (q - 1) == 0 and diff % (q**2 - 1) != 0: phi_exps.append(s3[i]) - exps1 = [(x+1)//2 for x in phi_exps if x % 2 == 1] - exps2 = [x//2 for x in phi_exps if x % 2 == 0] + exps1 = [(x + 1) // 2 for x in phi_exps if x % 2 == 1] + exps2 = [x // 2 for x in phi_exps if x % 2 == 0] theta1 = 0 for exp in exps1: theta1 += P.monomial(exp) - theta1 = theta1.mod(P.monomial(q-1)-1) + theta1 = theta1.mod(P.monomial(q - 1) - 1) theta2 = 0 for exp in exps2: theta2 += P.monomial(exp) - theta2 = theta2.mod(P.monomial(q-1) - 1) + theta2 = theta2.mod(P.monomial(q - 1) - 1) - psi1 = ((1 + P.monomial((q-1)//2)) * theta1).mod(P.monomial(q-1) - 1) - psi2 = (1 + (1 + P.monomial((q-1)//2)) * theta2).mod(P.monomial(q-1) - 1) + psi1 = ((1 + P.monomial((q - 1) // 2)) * theta1).mod(P.monomial(q - 1) - 1) + psi2 = (1 + (1 + P.monomial((q - 1) // 2)) * theta2).mod(P.monomial(q - 1) - 1) from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup - G = AdditiveAbelianGroup([q-1]) + + G = AdditiveAbelianGroup([q - 1]) K1 = [G[x] for x in psi1.exponents()] K2 = [G[x] for x in psi2.exponents()] K3 = [G[x] for x in psi3.exponents()] K4 = [G[x] for x in psi4.exponents()] if check: - assert is_supplementary_difference_set([K1, K2, K3, K4], lmbda=q-1, G=G) + assert is_supplementary_difference_set([K1, K2, K3, K4], lmbda=q - 1, G=G) return G, [K1, K2, K3, K4] @@ -1956,7 +1939,7 @@ def get_fixed_relative_difference_set(G, rel_diff_set, as_elements=False): s2 = None for el in G: - fixed_set = [el+x for x in rel_diff_set] + fixed_set = [el + x for x in rel_diff_set] if is_fixed_relative_difference_set(fixed_set, q): s2 = fixed_set break @@ -1964,7 +1947,7 @@ def get_fixed_relative_difference_set(G, rel_diff_set, as_elements=False): s3 = None for i in range(G.order()): - temp = [((q+1)*i+x[0]) % G.order() for x in s2] + temp = [((q + 1) * i + x[0]) % G.order() for x in s2] if 0 in temp: s3 = temp break @@ -2052,14 +2035,7 @@ def skew_supplementary_difference_set_over_polynomial_ring(n, existence=False, c ... NotImplementedError: skew SDS of order 7 not yet implemented """ - data = { - 81: (3, lambda x: x**4 - x**3 - 1, 16, 5, - [1, 2, 4, 6, 8, 10, 12, 14], [1, 2, 3, 4, 10, 11, 13], - [4, 5, 6, 8, 12, 13, 14], [2, 4, 5, 6, 7, 11, 12, 13, 15]), - 169: (13, lambda x: x**2 - 4*x + 6, 24, 7, - [0, 2, 5, 7, 9, 10, 12, 15, 16, 18, 21, 22], [0, 1, 2, 7, 8, 9, 13, 14, 18, 20, 23], - [1, 4, 6, 7, 9, 14, 16, 17, 20, 21, 23], [3, 5, 6, 9, 10, 12, 13, 14, 15, 17, 20]) - } + data = {81: (3, lambda x: x**4 - x**3 - 1, 16, 5, [1, 2, 4, 6, 8, 10, 12, 14], [1, 2, 3, 4, 10, 11, 13], [4, 5, 6, 8, 12, 13, 14], [2, 4, 5, 6, 7, 11, 12, 13, 15]), 169: (13, lambda x: x**2 - 4 * x + 6, 24, 7, [0, 2, 5, 7, 9, 10, 12, 15, 16, 18, 21, 22], [0, 1, 2, 7, 8, 9, 13, 14, 18, 20, 23], [1, 4, 6, 7, 9, 14, 16, 17, 20, 21, 23], [3, 5, 6, 9, 10, 12, 13, 14, 15, 17, 20])} if existence: return n in data @@ -2080,8 +2056,8 @@ def skew_supplementary_difference_set_over_polynomial_ring(n, existence=False, c cosets = [] for i in range((n - 1) // (2 * order)): - cosets.append([F.gen()**i * el for el in H]) - cosets.append([-F.gen()**i * el for el in H]) + cosets.append([F.gen() ** i * el for el in H]) + cosets.append([-F.gen() ** i * el for el in H]) def generate_set(index_set, cosets): return sum((cosets[idx] for idx in index_set), []) @@ -2152,9 +2128,7 @@ def skew_supplementary_difference_set_with_paley_todd(n, existence=False, check= } indices = { - 239: [[1, 3, 5, 6, 15, 17, 19, 28, 34, 38, 39, 57, 58, 63, 85, 95, 107], - [1, 3, 4, 5, 15, 16, 17, 18, 19, 21, 23, 29, 35, 45, 58, 63], - [0, 1, 4, 6, 7, 8, 13, 16, 18, 34, 35, 45, 47, 58, 63, 95]], + 239: [[1, 3, 5, 6, 15, 17, 19, 28, 34, 38, 39, 57, 58, 63, 85, 95, 107], [1, 3, 4, 5, 15, 16, 17, 18, 19, 21, 23, 29, 35, 45, 58, 63], [0, 1, 4, 6, 7, 8, 13, 16, 18, 34, 35, 45, 47, 58, 63, 95]], } if existence: @@ -2321,43 +2295,10 @@ def spin_goethals_seidel_difference_family(n, existence=False, check=True): ... NotImplementedError: Data for spin type Goethals Seidel family of order 5 not yet implemented """ - full_data = { - 7: ([0], [0, 1, 6], 2), - 9: ([0, 3, 6], [0, 1, 8], 4), - 13: ([0, 1, 4, 6], [0, 4, 6, 7, 9], 3), - 19: ([4, 6, 9, 10, 13, 15], [0, 1, 5, 8, 9, 10, 11, 13], 7), - 21: ([1, 4, 5, 8, 10, 11, 12, 17, 19], [1, 3, 8, 9, 12, 13, 18, 20], 4), - 31: ([2, 4, 6, 12, 14, 16, 17, 19, 25, 26, 28, 29], - [0, 3, 9, 11, 13, 14, 15, 16, 17, 18, 20, 22, 28], 5), - 37: ([0, 3, 4, 5, 7, 13, 18, 19, 24, 30, 32, 33, 34], - [0, 1, 2, 3, 4, 6, 12, 13, 18, 19, 24, 25, 31, 33, 34, 35, 36], 10), - 39: ([1, 4, 6, 10, 14, 15, 16, 17, 18, 21, 22, 23, 24, 25, 29, 33, 35, 38], - [0, 2, 4, 6, 7, 10, 11, 14, 16, 19, 20, 22, 26, 32, 33, 38], 16), - 57: ([0, 4, 11, 12, 18, 19, 20, 25, 26, 27, 28, 29, 30, 31, 32, 37, 38, 39, 45, 46, 53], - [1, 2, 5, 6, 7, 8, 9, 10, 12, 17, 19, 21, 22, 24, 25, 28, 30, 31, 34, 37, 39, 41, 42, 43, 44, 46, 53, 54], - 7) - } - compact_data = { - 73: ([1, 8, 64], - [0, 9, 13, 18, 25, 26, 27, 35, 36, 43], - [1, 2, 4, 9, 11, 14, 18, 21, 26, 34, 36, 43], 4), - 91: ([1, 16, 74], - [0, 3, 4, 5, 8, 11, 19, 25, 27, 43, 45, 50, 55], - [0, 1, 4, 5, 13, 14, 15, 25, 28, 33, 38, 43, 44, 49, 55], 9), - 93: ([1, 4, 16, 64, 70], - [3, 10, 11, 14, 21, 23, 33, 34, 46], - [3, 9, 11, 17, 23, 33, 34, 46, 62], 25), - 129: ([1, 4, 16, 64, 97, 121, 127], - [1, 9, 10, 14, 19, 21, 23, 26, 27], - [2, 5, 9, 10, 13, 18, 22, 27, 43, 86], 13), - 397: ([1, 16, 31, 99, 126, 167, 256, 273, 290, 333, 393], - [3, 5, 9, 10, 11, 12, 18, 20, 21, 23, 29, 33, 36, 40, 44, 47, 61, 72], - [2, 3, 6, 10, 17, 22, 24, 33, 34, 36, 40, 46, 47, 53, 58, 71, 72], - 34) - } + full_data = {7: ([0], [0, 1, 6], 2), 9: ([0, 3, 6], [0, 1, 8], 4), 13: ([0, 1, 4, 6], [0, 4, 6, 7, 9], 3), 19: ([4, 6, 9, 10, 13, 15], [0, 1, 5, 8, 9, 10, 11, 13], 7), 21: ([1, 4, 5, 8, 10, 11, 12, 17, 19], [1, 3, 8, 9, 12, 13, 18, 20], 4), 31: ([2, 4, 6, 12, 14, 16, 17, 19, 25, 26, 28, 29], [0, 3, 9, 11, 13, 14, 15, 16, 17, 18, 20, 22, 28], 5), 37: ([0, 3, 4, 5, 7, 13, 18, 19, 24, 30, 32, 33, 34], [0, 1, 2, 3, 4, 6, 12, 13, 18, 19, 24, 25, 31, 33, 34, 35, 36], 10), 39: ([1, 4, 6, 10, 14, 15, 16, 17, 18, 21, 22, 23, 24, 25, 29, 33, 35, 38], [0, 2, 4, 6, 7, 10, 11, 14, 16, 19, 20, 22, 26, 32, 33, 38], 16), 57: ([0, 4, 11, 12, 18, 19, 20, 25, 26, 27, 28, 29, 30, 31, 32, 37, 38, 39, 45, 46, 53], [1, 2, 5, 6, 7, 8, 9, 10, 12, 17, 19, 21, 22, 24, 25, 28, 30, 31, 34, 37, 39, 41, 42, 43, 44, 46, 53, 54], 7)} + compact_data = {73: ([1, 8, 64], [0, 9, 13, 18, 25, 26, 27, 35, 36, 43], [1, 2, 4, 9, 11, 14, 18, 21, 26, 34, 36, 43], 4), 91: ([1, 16, 74], [0, 3, 4, 5, 8, 11, 19, 25, 27, 43, 45, 50, 55], [0, 1, 4, 5, 13, 14, 15, 25, 28, 33, 38, 43, 44, 49, 55], 9), 93: ([1, 4, 16, 64, 70], [3, 10, 11, 14, 21, 23, 33, 34, 46], [3, 9, 11, 17, 23, 33, 34, 46, 62], 25), 129: ([1, 4, 16, 64, 97, 121, 127], [1, 9, 10, 14, 19, 21, 23, 26, 27], [2, 5, 9, 10, 13, 18, 22, 27, 43, 86], 13), 397: ([1, 16, 31, 99, 126, 167, 256, 273, 290, 333, 393], [3, 5, 9, 10, 11, 12, 18, 20, 21, 23, 29, 33, 36, 40, 44, 47, 61, 72], [2, 3, 6, 10, 17, 22, 24, 33, 34, 36, 40, 46, 47, 53, 58, 71, 72], 34)} - exist = n in full_data or n in compact_data or \ - skew_spin_goethals_seidel_difference_family(n, existence=True) + exist = n in full_data or n in compact_data or skew_spin_goethals_seidel_difference_family(n, existence=True) if existence: return exist @@ -2439,36 +2380,15 @@ def skew_spin_goethals_seidel_difference_family(n, existence=False, check=True): ... NotImplementedError: Data for skew spin type Goethals Seidel family of order 5 not yet implemented """ - full_data = { - 7: ([1, 2, 4], [1, 6], 2), - 19: ([1, 4, 5, 6, 7, 9, 11, 16, 17], [0, 1, 7, 8, 11, 12, 18], -2), - 37: ([2, 3, 4, 6, 8, 11, 15, 18, 20, 21, 23, 24, 25, 27, 28, 30, 32, 36], - [0, 1, 2, 5, 9, 13, 14, 15, 22, 23, 24, 28, 32, 35, 36], - 10) - } + full_data = {7: ([1, 2, 4], [1, 6], 2), 19: ([1, 4, 5, 6, 7, 9, 11, 16, 17], [0, 1, 7, 8, 11, 12, 18], -2), 37: ([2, 3, 4, 6, 8, 11, 15, 18, 20, 21, 23, 24, 25, 27, 28, 30, 32, 36], [0, 1, 2, 5, 9, 13, 14, 15, 22, 23, 24, 28, 32, 35, 36], 10)} compact_data = { - 61: ([1, 9, 20, 34, 58], [3, 4, 5, 6, 8, 10], [0, 8, 10, 13, 23, 26], 13), - 127: ([1, 2, 4, 8, 16, 32, 64], - [1, 3, 7, 9, 11, 19, 21, 23, 47], - [0, 3, 7, 9, 11, 15, 29, 31, 55], 19), - 271: ([1, 28, 106, 125, 169, 178, 242, 248, 258], - [1, 4, 5, 7, 8, 11, 14, 16, 19, 21, 22, 25, 31, 43, 44], - [1, 2, 3, 5, 7, 8, 12, 19, 22, 27, 38, 42, 44, 51], 5), - 331: ([1, 74, 80, 85, 111, 120, 167, 180, 270, 274, 293], - [5, 10, 11, 13, 16, 19, 20, 22, 32, 38, 53, 56, 64, 76, 101], - [0, 4, 11, 16, 20, 28, 31, 37, 41, 49, 53, 56, 73, 88, 101], 31), - 397: ([1, 16, 31, 99, 126, 167, 256, 273, 290, 333, 393], - [1, 6, 7, 8, 9, 10, 11, 12, 17, 18, 20, 21, 29, 34, 46, 47, 53, 106], - [2, 11, 12, 17, 18, 20, 24, 27, 33, 34, 36, 40, 46, 47, 53, 58, 71], - 34), - 547: ([1, 46, 237, 261, 293, 350, 353, 375, 440, 475, 509, 517, 519], - [1, 4, 5, 6, 10, 11, 13, 14, 17, 25, 29, 34, 35, 40, 49, 52, 55, 64, 69, 110, 123], - [1, 4, 5, 11, 16, 17, 20, 26, 32, 33, 34, 41, 49, 52, 55, 64, 70, 80, 123, 207], - 40), - 631: ([1, 8, 43, 64, 79, 188, 228, 242, 279, 310, 339, 344, 512, 562, 587], - [1, 2, 3, 4, 6, 7, 12, 13, 14, 17, 19, 21, 26, 27, 31, 38, 42, 52, 62, 76, 124], - [0, 11, 13, 14, 18, 19, 21, 22, 29, 35, 39, 46, 62, 63, 65, 66, 67, 92, 117, 124, 187], - 2) + 61: ([1, 9, 20, 34, 58], [3, 4, 5, 6, 8, 10], [0, 8, 10, 13, 23, 26], 13), + 127: ([1, 2, 4, 8, 16, 32, 64], [1, 3, 7, 9, 11, 19, 21, 23, 47], [0, 3, 7, 9, 11, 15, 29, 31, 55], 19), + 271: ([1, 28, 106, 125, 169, 178, 242, 248, 258], [1, 4, 5, 7, 8, 11, 14, 16, 19, 21, 22, 25, 31, 43, 44], [1, 2, 3, 5, 7, 8, 12, 19, 22, 27, 38, 42, 44, 51], 5), + 331: ([1, 74, 80, 85, 111, 120, 167, 180, 270, 274, 293], [5, 10, 11, 13, 16, 19, 20, 22, 32, 38, 53, 56, 64, 76, 101], [0, 4, 11, 16, 20, 28, 31, 37, 41, 49, 53, 56, 73, 88, 101], 31), + 397: ([1, 16, 31, 99, 126, 167, 256, 273, 290, 333, 393], [1, 6, 7, 8, 9, 10, 11, 12, 17, 18, 20, 21, 29, 34, 46, 47, 53, 106], [2, 11, 12, 17, 18, 20, 24, 27, 33, 34, 36, 40, 46, 47, 53, 58, 71], 34), + 547: ([1, 46, 237, 261, 293, 350, 353, 375, 440, 475, 509, 517, 519], [1, 4, 5, 6, 10, 11, 13, 14, 17, 25, 29, 34, 35, 40, 49, 52, 55, 64, 69, 110, 123], [1, 4, 5, 11, 16, 17, 20, 26, 32, 33, 34, 41, 49, 52, 55, 64, 70, 80, 123, 207], 40), + 631: ([1, 8, 43, 64, 79, 188, 228, 242, 279, 310, 339, 344, 512, 562, 587], [1, 2, 3, 4, 6, 7, 12, 13, 14, 17, 19, 21, 26, 27, 31, 38, 42, 52, 62, 76, 124], [0, 11, 13, 14, 18, 19, 21, 22, 29, 35, 39, 46, 62, 63, 65, 66, 67, 92, 117, 124, 187], 2), } if existence: @@ -2587,104 +2507,35 @@ def skew_supplementary_difference_set(n, existence=False, check=True, return_gro # If -1 is present in an index set, it means that {0} should be added to that set indices = { - 37: [[0, 3, 5, 7, 9, 10], [0, 5, 6, 7, 8], - [1, 2, 6, 7, 9], [2, 6, 8, 9, 10]], - 39: [[1, 3, 5, 6, 8, 10, 12], [0, 1, 5, 8, 12, 13], - [1, 3, 4, 7, 9, 12, 13], [0, 1, 2, 3, 7, 8]], + 37: [[0, 3, 5, 7, 9, 10], [0, 5, 6, 7, 8], [1, 2, 6, 7, 9], [2, 6, 8, 9, 10]], + 39: [[1, 3, 5, 6, 8, 10, 12], [0, 1, 5, 8, 12, 13], [1, 3, 4, 7, 9, 12, 13], [0, 1, 2, 3, 7, 8]], 43: [[1, 2, 4], [1, 2, 4], [0, 2, 3], [3, 4, -1]], - 49: [[1, 2, 5, 7, 8, 10, 13, 14], [4, 5, 6, 7, 10, 11], - [0, 1, 2, 4, 6, 7, 12, 14], [1, 2, 3, 5, 6, 10, 12, 13, 14]], - 65: [[1, 3, 5, 6, 8, 10, 13, 14, 17, 18, 20, 22], - [0, 3, 7, 10, 16, 17, 18, 20, 21], - [2, 4, 6, 8, 9, 10, 14, 15, 16, 17, 18, 20], - [5, 7, 8, 9, 11, 12, 13, 14, 16, 18, 19, 20, 21]], - 67: [[0, 3, 5, 6, 9, 10, 13, 14, 17, 18, 20], - [0, 2, 4, 9, 11, 12, 13, 16, 19, 21], - [1, 3, 6, 10, 11, 13, 14, 16, 20, 21], - [2, 4, 6, 8, 9, 11, 14, 17, 19]], + 49: [[1, 2, 5, 7, 8, 10, 13, 14], [4, 5, 6, 7, 10, 11], [0, 1, 2, 4, 6, 7, 12, 14], [1, 2, 3, 5, 6, 10, 12, 13, 14]], + 65: [[1, 3, 5, 6, 8, 10, 13, 14, 17, 18, 20, 22], [0, 3, 7, 10, 16, 17, 18, 20, 21], [2, 4, 6, 8, 9, 10, 14, 15, 16, 17, 18, 20], [5, 7, 8, 9, 11, 12, 13, 14, 16, 18, 19, 20, 21]], + 67: [[0, 3, 5, 6, 9, 10, 13, 14, 17, 18, 20], [0, 2, 4, 9, 11, 12, 13, 16, 19, 21], [1, 3, 6, 10, 11, 13, 14, 16, 20, 21], [2, 4, 6, 8, 9, 11, 14, 17, 19]], 73: [[4, 6, 8, 14], [8, 10, 12, 14], [4, 6, 10, 12], [-1, 0, 2, 10]], - 93: [[0, 3, 4, 6, 9, 10, 12, 14, 17, 18], - [2, 3, 4, 5, 9, 13, 15, 18, 19], - [1, 2, 3, 4, 5, 6, 7, 8, 16], - [1, 4, 6, 11, 12, 13, 15, 16, 17, 18]], - 97: [[1, 2, 4, 6, 9, 11, 13, 14, 17, 18, 21, 23, 25, 27, 29, 30], - [1, 2, 6, 7, 8, 9, 10, 11, 12, 13, 23, 27, 29], - [0, 1, 2, 5, 6, 12, 13, 15, 16, 20, 24, 25, 26, 29, 30, 31], - [0, 2, 3, 4, 7, 8, 9, 11, 12, 13, 15, 16, 17, 18, 23, 28, 29]], - 103: [[1, 3, 4, 6, 8, 11, 12, 14, 17, 18, 20, 22, 25, 27, 28, 30, 32], - [2, 9, 10, 12, 13, 14, 15, 16, 20, 21, 22, 23, 24, 26, 28, 29, 30], - [0, 1, 2, 3, 4, 11, 12, 13, 16, 17, 19, 20, 21, 24, 25, 26, 28, 30, 31], - [0, 1, 2, 3, 4, 5, 6, 13, 15, 18, 19, 20, 23, 24, 25, 26, 27, 28, 29, 31]], - 109: [[0, 2, 5, 7, 8, 10, 12, 15, 16, 19, 20, 23, 24, 26, 29, 30, 33, 34], - [4, 5, 6, 7, 11, 15, 18, 19, 20, 22, 25, 30, 32, 33, 35], - [0, 1, 5, 6, 9, 10, 11, 14, 17, 20, 24, 26, 27, 28, 29, 31, 32], - [0, 3, 4, 6, 7, 9, 10, 12, 13, 22, 24, 25, 26, 27, 28, 29, 31, 33, 35]], - 113: [[0, 3, 4, 6, 8, 10, 13, 14], - [1, 3, 8, 9, 10, 11, 12, 13], - [0, 2, 3, 5, 6, 7, 12], - [1, 2, 3, 5, 8, 9, 15]], - 121: [[0, 2, 4, 7, 8, 11, 13, 14, 16, 19, 20, 22], - [0, 1, 4, 5, 8, 9, 10, 15, 17, 20, 23], - [1, 2, 3, 7, 9, 16, 18, 19, 20, 21, 22, 23], - [0, 2, 9, 10, 11, 12, 13, 14, 15, 17, 18, 21, 22, 23]], - 127: [[0, 3, 5, 7, 8, 10, 12, 14, 16], - [0, 1, 3, 6, 7, 9, 10, 12, 14, 15], - [0, 1, 3, 4, 5, 7, 8, 9, 15, 16], - [1, 4, 5, 6, 9, 10, 13, 14, 15, 16]], - 129: [[1, 2, 4, 7, 9, 11, 12, 14, 16, 18], - [0, 1, 2, 3, 9, 11, 14, 15, 19], - [0, 1, 3, 6, 8, 10, 12, 16, 18, 19], - [0, 3, 7, 8, 9, 10, 12, 14, 15, 17]], - 133: [[1, 2, 5, 6, 9, 11, 12, 14], [1, 4, 7, 9, 10, 12, 13, 15], - [0, 5, 6, 8, 11, 12, 13, 15], [0, 1, 2, 5, 7, 8, 9, 13, 14, 15]], - 145: [[1, 2, 4, 7, 9, 10, 13, 14, 16, 19, 20, 22], [0, 2, 4, 7, 10, 11, 14, 18, 19, 20, 21, 22], - [1, 3, 6, 9, 12, 13, 14, 17, 19, 20, 21, 22, 23], [2, 3, 5, 6, 7, 9, 12, 13, 15, 16, 19, 20, 21, 22, 23]], - 151: [[0, 3, 5, 6, 8, 11, 13, 14, 16, 19, 21, 23, 25, 27, 28], - [2, 3, 6, 13, 16, 17, 20, 23, 25, 26, 27, 28, 29], - [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 23, 24, 27, 28], - [1, 4, 5, 10, 11, 12, 13, 14, 16, 18, 19, 22, 25, 26, 27, 28]], - 157: [[0, 2, 5, 7, 8, 11], - [0, 4, 5, 6, 9, 11], - [6, 7, 8, 9, 10, 11], - [0, 5, 6, 7, 8, 10, 11]], - 163: [[0, 2, 5, 6, 9, 10, 13, 14, 17], - [0, 1, 7, 10, 12, 15, 16, 17], - [0, 1, 3, 5, 8, 13, 15, 16, 17], - [3, 6, 7, 8, 11, 12, 13, 14, 16, 17]], - 181: [[0, 3, 5, 6, 8, 10, 13, 15, 16, 19], - [4, 5, 7, 8, 11, 14, 15, 16, 18, 19], - [0, 4, 10, 11, 13, 15, 16, 18, 19], - [2, 4, 5, 7, 11, 13, 15, 17, 19]], - 213: [[1, 2, 5, 6, 9, 11, 12, 14, 16, 19, 20, 23, 24, 26, 29, 30], - [3, 6, 8, 12, 13, 14, 15, 17, 20, 22, 23, 25, 26, 27, 28, 31], - [2, 3, 5, 7, 9, 13, 16, 17, 19, 21, 23, 24, 27, 28, 29], - [0, 5, 6, 9, 11, 13, 14, 17, 20, 22, 23, 26, 29, 31]], - 217: [[0, 3, 5, 7, 8, 11, 12, 14], [1, 3, 4, 7, 9, 11, 12, 15], - [3, 4, 5, 6, 7, 9, 10, 14, 15], [1, 3, 4, 5, 7, 8, 11, 13, 14]], - 219: [[1, 3, 5, 6, 8, 11, 12, 15, 17, 18, 21, 22, 24], - [2, 6, 8, 10, 11, 12, 13, 16, 19, 22, 23, 24], - [0, 1, 5, 6, 10, 11, 13, 14, 17, 20, 21, 24, 25], - [0, 2, 3, 4, 5, 6, 7, 11, 12, 13, 16, 20, 23]], - 241: [[0, 2, 4, 6, 8, 11, 12, 14], - [1, 3, 4, 6, 7, 13, 14, 15], - [6, 8, 9, 10, 12, 13, 14, 15], - [3, 4, 5, 9, 10, 13, 14]], - 247: [[0, 2, 4, 7, 8, 10, 12, 15, 16, 18, 20, 23, 25, 27, 29], - [0, 2, 7, 9, 11, 12, 14, 15, 16, 18, 20, 22, 26], - [2, 3, 4, 12, 13, 14, 15, 16, 18, 20, 23, 24, 26, 27, 29], - [0, 3, 4, 6, 10, 11, 12, 14, 18, 19, 20, 22, 25, 29]], - 267: [[0, 3, 4, 7, 8, 11, 13, 15, 16, 19, 21, 22, 25], - [0, 1, 4, 5, 6, 8, 14, 15, 18, 21, 23], - [0, 2, 4, 5, 7, 9, 10, 11, 14, 15, 16, 17, 25], - [0, 1, 3, 4, 6, 14, 15, 16, 17, 18, 20, 22, 23, 25]], - 331: [[1, 2, 4, 7, 9, 10, 12, 15, 16, 18, 21, 22, 24, 26, 28], - [-1, 0, 2, 6, 9, 11, 12, 14, 15, 17, 20, 21, 24, 25, 28], - [-1, 0, 1, 5, 6, 7, 8, 9, 10, 12, 15, 18, 23, 28, 29], - [-1, 0, 3, 7, 8, 10, 11, 12, 14, 16, 19, 20, 21, 26, 29]], - 631: [[0, 2, 4, 6, 9, 10, 12, 15, 16, 18, 20, 23, 24, 26, 29, 30, 32, 35, 36, 38, 40], - [0, 1, 2, 4, 6, 8, 9, 10, 11, 12, 13, 14, 16, 20, 23, 28, 29, 30, 32, 36, 38, 41], - [0, 2, 3, 4, 6, 9, 10, 12, 14, 15, 16, 17, 18, 19, 20, 22, 24, 25, 26, 29, 34, 40], - [0, 2, 4, 5, 6, 7, 8, 10, 15, 16, 18, 22, 23, 24, 26, 30, 31, 33, 35, 36, 37, 38]], + 93: [[0, 3, 4, 6, 9, 10, 12, 14, 17, 18], [2, 3, 4, 5, 9, 13, 15, 18, 19], [1, 2, 3, 4, 5, 6, 7, 8, 16], [1, 4, 6, 11, 12, 13, 15, 16, 17, 18]], + 97: [[1, 2, 4, 6, 9, 11, 13, 14, 17, 18, 21, 23, 25, 27, 29, 30], [1, 2, 6, 7, 8, 9, 10, 11, 12, 13, 23, 27, 29], [0, 1, 2, 5, 6, 12, 13, 15, 16, 20, 24, 25, 26, 29, 30, 31], [0, 2, 3, 4, 7, 8, 9, 11, 12, 13, 15, 16, 17, 18, 23, 28, 29]], + 103: [[1, 3, 4, 6, 8, 11, 12, 14, 17, 18, 20, 22, 25, 27, 28, 30, 32], [2, 9, 10, 12, 13, 14, 15, 16, 20, 21, 22, 23, 24, 26, 28, 29, 30], [0, 1, 2, 3, 4, 11, 12, 13, 16, 17, 19, 20, 21, 24, 25, 26, 28, 30, 31], [0, 1, 2, 3, 4, 5, 6, 13, 15, 18, 19, 20, 23, 24, 25, 26, 27, 28, 29, 31]], + 109: [[0, 2, 5, 7, 8, 10, 12, 15, 16, 19, 20, 23, 24, 26, 29, 30, 33, 34], [4, 5, 6, 7, 11, 15, 18, 19, 20, 22, 25, 30, 32, 33, 35], [0, 1, 5, 6, 9, 10, 11, 14, 17, 20, 24, 26, 27, 28, 29, 31, 32], [0, 3, 4, 6, 7, 9, 10, 12, 13, 22, 24, 25, 26, 27, 28, 29, 31, 33, 35]], + 113: [[0, 3, 4, 6, 8, 10, 13, 14], [1, 3, 8, 9, 10, 11, 12, 13], [0, 2, 3, 5, 6, 7, 12], [1, 2, 3, 5, 8, 9, 15]], + 121: [[0, 2, 4, 7, 8, 11, 13, 14, 16, 19, 20, 22], [0, 1, 4, 5, 8, 9, 10, 15, 17, 20, 23], [1, 2, 3, 7, 9, 16, 18, 19, 20, 21, 22, 23], [0, 2, 9, 10, 11, 12, 13, 14, 15, 17, 18, 21, 22, 23]], + 127: [[0, 3, 5, 7, 8, 10, 12, 14, 16], [0, 1, 3, 6, 7, 9, 10, 12, 14, 15], [0, 1, 3, 4, 5, 7, 8, 9, 15, 16], [1, 4, 5, 6, 9, 10, 13, 14, 15, 16]], + 129: [[1, 2, 4, 7, 9, 11, 12, 14, 16, 18], [0, 1, 2, 3, 9, 11, 14, 15, 19], [0, 1, 3, 6, 8, 10, 12, 16, 18, 19], [0, 3, 7, 8, 9, 10, 12, 14, 15, 17]], + 133: [[1, 2, 5, 6, 9, 11, 12, 14], [1, 4, 7, 9, 10, 12, 13, 15], [0, 5, 6, 8, 11, 12, 13, 15], [0, 1, 2, 5, 7, 8, 9, 13, 14, 15]], + 145: [[1, 2, 4, 7, 9, 10, 13, 14, 16, 19, 20, 22], [0, 2, 4, 7, 10, 11, 14, 18, 19, 20, 21, 22], [1, 3, 6, 9, 12, 13, 14, 17, 19, 20, 21, 22, 23], [2, 3, 5, 6, 7, 9, 12, 13, 15, 16, 19, 20, 21, 22, 23]], + 151: [[0, 3, 5, 6, 8, 11, 13, 14, 16, 19, 21, 23, 25, 27, 28], [2, 3, 6, 13, 16, 17, 20, 23, 25, 26, 27, 28, 29], [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 23, 24, 27, 28], [1, 4, 5, 10, 11, 12, 13, 14, 16, 18, 19, 22, 25, 26, 27, 28]], + 157: [[0, 2, 5, 7, 8, 11], [0, 4, 5, 6, 9, 11], [6, 7, 8, 9, 10, 11], [0, 5, 6, 7, 8, 10, 11]], + 163: [[0, 2, 5, 6, 9, 10, 13, 14, 17], [0, 1, 7, 10, 12, 15, 16, 17], [0, 1, 3, 5, 8, 13, 15, 16, 17], [3, 6, 7, 8, 11, 12, 13, 14, 16, 17]], + 181: [[0, 3, 5, 6, 8, 10, 13, 15, 16, 19], [4, 5, 7, 8, 11, 14, 15, 16, 18, 19], [0, 4, 10, 11, 13, 15, 16, 18, 19], [2, 4, 5, 7, 11, 13, 15, 17, 19]], + 213: [[1, 2, 5, 6, 9, 11, 12, 14, 16, 19, 20, 23, 24, 26, 29, 30], [3, 6, 8, 12, 13, 14, 15, 17, 20, 22, 23, 25, 26, 27, 28, 31], [2, 3, 5, 7, 9, 13, 16, 17, 19, 21, 23, 24, 27, 28, 29], [0, 5, 6, 9, 11, 13, 14, 17, 20, 22, 23, 26, 29, 31]], + 217: [[0, 3, 5, 7, 8, 11, 12, 14], [1, 3, 4, 7, 9, 11, 12, 15], [3, 4, 5, 6, 7, 9, 10, 14, 15], [1, 3, 4, 5, 7, 8, 11, 13, 14]], + 219: [[1, 3, 5, 6, 8, 11, 12, 15, 17, 18, 21, 22, 24], [2, 6, 8, 10, 11, 12, 13, 16, 19, 22, 23, 24], [0, 1, 5, 6, 10, 11, 13, 14, 17, 20, 21, 24, 25], [0, 2, 3, 4, 5, 6, 7, 11, 12, 13, 16, 20, 23]], + 241: [[0, 2, 4, 6, 8, 11, 12, 14], [1, 3, 4, 6, 7, 13, 14, 15], [6, 8, 9, 10, 12, 13, 14, 15], [3, 4, 5, 9, 10, 13, 14]], + 247: [[0, 2, 4, 7, 8, 10, 12, 15, 16, 18, 20, 23, 25, 27, 29], [0, 2, 7, 9, 11, 12, 14, 15, 16, 18, 20, 22, 26], [2, 3, 4, 12, 13, 14, 15, 16, 18, 20, 23, 24, 26, 27, 29], [0, 3, 4, 6, 10, 11, 12, 14, 18, 19, 20, 22, 25, 29]], + 267: [[0, 3, 4, 7, 8, 11, 13, 15, 16, 19, 21, 22, 25], [0, 1, 4, 5, 6, 8, 14, 15, 18, 21, 23], [0, 2, 4, 5, 7, 9, 10, 11, 14, 15, 16, 17, 25], [0, 1, 3, 4, 6, 14, 15, 16, 17, 18, 20, 22, 23, 25]], + 331: [[1, 2, 4, 7, 9, 10, 12, 15, 16, 18, 21, 22, 24, 26, 28], [-1, 0, 2, 6, 9, 11, 12, 14, 15, 17, 20, 21, 24, 25, 28], [-1, 0, 1, 5, 6, 7, 8, 9, 10, 12, 15, 18, 23, 28, 29], [-1, 0, 3, 7, 8, 10, 11, 12, 14, 16, 19, 20, 21, 26, 29]], + 631: [[0, 2, 4, 6, 9, 10, 12, 15, 16, 18, 20, 23, 24, 26, 29, 30, 32, 35, 36, 38, 40], [0, 1, 2, 4, 6, 8, 9, 10, 11, 12, 13, 14, 16, 20, 23, 28, 29, 30, 32, 36, 38, 41], [0, 2, 3, 4, 6, 9, 10, 12, 14, 15, 16, 17, 18, 19, 20, 22, 24, 25, 26, 29, 34, 40], [0, 2, 4, 5, 6, 7, 8, 10, 15, 16, 18, 22, 23, 24, 26, 30, 31, 33, 35, 36, 37, 38]], } # If the element is a list, that is the coset. @@ -2705,10 +2556,7 @@ def skew_supplementary_difference_set(n, existence=False, check=True, return_gro 127: [1, 3, 5, 7, 9, 11, 13, 19, 21], 129: [1, 3, 5, 7, 9, 11, 13, 19, 21, [43]], 133: [1, 2, 3, 6, 7, 9, 18, [19, 38, 76]], - 145: [1, [2, 17, 32, 72, 77, 127, 137], [3, 43, 48, 98, 108, 118, 133], [6, 51, 71, 86, 91, 96, 121], - [7, 52, 82, 107, 112, 117, 132], [11, 21, 31, 46, 61, 101, 106], [14, 19, 69, 79, 89, 104, 119], - [22, 42, 57, 62, 67, 92, 122], [5, 35, 80, 100, 115, 120, 125], [10, 15, 55, 70, 85, 95, 105], - [29], [58]], + 145: [1, [2, 17, 32, 72, 77, 127, 137], [3, 43, 48, 98, 108, 118, 133], [6, 51, 71, 86, 91, 96, 121], [7, 52, 82, 107, 112, 117, 132], [11, 21, 31, 46, 61, 101, 106], [14, 19, 69, 79, 89, 104, 119], [22, 42, 57, 62, 67, 92, 122], [5, 35, 80, 100, 115, 120, 125], [10, 15, 55, 70, 85, 95, 105], [29], [58]], 151: [1, 2, 3, 4, 5, 6, 9, 10, 11, 12, 15, 22, 27, 29, 30], 157: [1, 2, 3, 5, 9, 15], 163: [1, 2, 3, 5, 6, 9, 10, 15, 18], @@ -2717,11 +2565,7 @@ def skew_supplementary_difference_set(n, existence=False, check=True, return_gro 217: [1, 2, 4, 5, 7, 10, 19, [31, 62, 124]], 219: [1, 2, 3, 5, 7, 9, 11, 15, 19, 22, 23, 33, [73]], 241: [1, 2, 4, 5, 7, 13, 19, 35], - 247: [1, [2, 18, 31, 32, 41, 110, 122, 162, 223], [3, 27, 48, 165, 170, 183, 185, 211, 243], - [5, 28, 45, 58, 80, 158, 187, 201, 226], [6, 54, 83, 93, 96, 119, 123, 175, 239], [7, 20, 63, 73, 112, 138, 163, 180, 232], - [10, 56, 69, 90, 116, 127, 155, 160, 205], [11, 47, 99, 102, 111, 115, 150, 176, 177], [13, 52, 65, 78, 91, 117, 143, 208, 221], - [14, 29, 40, 79, 113, 126, 146, 217, 224], [17, 25, 43, 49, 140, 142, 153, 194, 225], [19, 57, 171], - [33, 34, 37, 50, 59, 86, 98, 141, 203], [35, 66, 68, 74, 100, 118, 159, 172, 196], [38, 95, 114]], + 247: [1, [2, 18, 31, 32, 41, 110, 122, 162, 223], [3, 27, 48, 165, 170, 183, 185, 211, 243], [5, 28, 45, 58, 80, 158, 187, 201, 226], [6, 54, 83, 93, 96, 119, 123, 175, 239], [7, 20, 63, 73, 112, 138, 163, 180, 232], [10, 56, 69, 90, 116, 127, 155, 160, 205], [11, 47, 99, 102, 111, 115, 150, 176, 177], [13, 52, 65, 78, 91, 117, 143, 208, 221], [14, 29, 40, 79, 113, 126, 146, 217, 224], [17, 25, 43, 49, 140, 142, 153, 194, 225], [19, 57, 171], [33, 34, 37, 50, 59, 86, 98, 141, 203], [35, 66, 68, 74, 100, 118, 159, 172, 196], [38, 95, 114]], 267: [1, 2, 3, 5, 7, 9, 10, 13, 14, 15, 19, 39, [89]], 331: [1, 2, 4, 5, 7, 8, 10, 13, 14, 16, 19, 20, 28, 32, 56], 631: [1, 2, 3, 4, 5, 6, 7, 9, 12, 14, 17, 18, 19, 21, 23, 27, 31, 35, 38, 42, 62], @@ -2861,6 +2705,7 @@ def _construction_supplementary_difference_set(n, H, indices, cosets_gen, check= :func:`skew_supplementary_difference_set` """ + def generate_set(index_set, cosets): S = set() for idx in index_set: @@ -2878,7 +2723,7 @@ def generate_set(index_set, cosets): if isinstance(el, list): even_coset = {Z(x) for x in el} else: - even_coset = {x*el for x in H} + even_coset = {x * el for x in H} odd_coset = {-x for x in even_coset} cosets.append(even_coset) cosets.append(odd_coset) @@ -2958,18 +2803,9 @@ def supplementary_difference_set_hadamard(n, existence=False, check=True): """ indices = { - 191: [[1, 7, 9, 10, 11, 13, 17, 18, 25, 26, 30, 31, 33, 34, 35, 36, 37], - [1, 4, 7, 9, 11, 12, 13, 14, 19, 21, 22, 23, 24, 25, 26, 29, 36, 37], - [0, 3, 4, 5, 7, 8, 9, 16, 17, 19, 24, 25, 29, 30, 31, 33, 35, 37], - [1, 3, 4, 5, 8, 11, 14, 18, 19, 20, 21, 23, 24, 25, 28, 29, 30, 32, 34, 35]], - 239: [[0, 1, 2, 3, 4, 5, 6, 7, 14, 18, 19, 21, 24, 25, 29, 30], - [0, 1, 3, 7, 9, 12, 15, 18, 20, 22, 26, 28, 29, 30, 31, 32, 33], - [2, 3, 4, 5, 8, 9, 10, 11, 13, 17, 19, 21, 22, 24, 27, 31, 32], - [0, 1, 2, 3, 6, 7, 8, 11, 13, 15, 17, 18, 19, 22, 25, 26, 27, 32, 33]], - 251: [[2, 6, 8, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 27, 28, 35, 36, 39, 41, 43, 44, 47, 48], - [2, 5, 10, 11, 17, 18, 21, 23, 24, 25, 26, 28, 29, 30, 34, 35, 38, 39, 40, 41, 42, 43, 44, 49], - [0, 2, 6, 7, 10, 11, 14, 15, 16, 18, 21, 22, 24, 26, 30, 35, 37, 38, 45, 46, 47, 48, 49], - [1, 2, 3, 4, 8, 9, 12, 17, 21, 22, 27, 28, 29, 30, 33, 34, 39, 41, 42, 43, 46, 47, 48]], + 191: [[1, 7, 9, 10, 11, 13, 17, 18, 25, 26, 30, 31, 33, 34, 35, 36, 37], [1, 4, 7, 9, 11, 12, 13, 14, 19, 21, 22, 23, 24, 25, 26, 29, 36, 37], [0, 3, 4, 5, 7, 8, 9, 16, 17, 19, 24, 25, 29, 30, 31, 33, 35, 37], [1, 3, 4, 5, 8, 11, 14, 18, 19, 20, 21, 23, 24, 25, 28, 29, 30, 32, 34, 35]], + 239: [[0, 1, 2, 3, 4, 5, 6, 7, 14, 18, 19, 21, 24, 25, 29, 30], [0, 1, 3, 7, 9, 12, 15, 18, 20, 22, 26, 28, 29, 30, 31, 32, 33], [2, 3, 4, 5, 8, 9, 10, 11, 13, 17, 19, 21, 22, 24, 27, 31, 32], [0, 1, 2, 3, 6, 7, 8, 11, 13, 15, 17, 18, 19, 22, 25, 26, 27, 32, 33]], + 251: [[2, 6, 8, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 27, 28, 35, 36, 39, 41, 43, 44, 47, 48], [2, 5, 10, 11, 17, 18, 21, 23, 24, 25, 26, 28, 29, 30, 34, 35, 38, 39, 40, 41, 42, 43, 44, 49], [0, 2, 6, 7, 10, 11, 14, 15, 16, 18, 21, 22, 24, 26, 30, 35, 37, 38, 45, 46, 47, 48, 49], [1, 2, 3, 4, 8, 9, 12, 17, 21, 22, 27, 28, 29, 30, 33, 34, 39, 41, 42, 43, 46, 47, 48]], } cosets_gens = { @@ -3100,7 +2936,7 @@ def are_complementary_difference_sets(G, A, B, verbose=False): print(f'A and B must have size {m}') return False - if not is_supplementary_difference_set([A, B], lmbda=m-1, G=G): + if not is_supplementary_difference_set([A, B], lmbda=m - 1, G=G): if verbose: print(f'The sets are not supplementary difference sets with lambda = {m-1}') return False @@ -3240,6 +3076,7 @@ def complementary_difference_setsII(n, check=True): raise ValueError(f'the parameter {n} is not valid') from sage.rings.finite_rings.finite_field_constructor import GF + G = GF(n, 'a') A, B = None, None @@ -3316,19 +3153,20 @@ def complementary_difference_setsIII(n, check=True): :func:`complementary_difference_sets` """ m = (n - 1) // 2 - q = 4*m + 3 + q = 4 * m + 3 if n % 2 != 1 or not is_prime_power(q): raise ValueError(f'the parameter {n} is not valid') from sage.rings.finite_rings.finite_field_constructor import GF + G = Zmod(n) G2 = GF(q) rho = G2.primitive_element() - Q = [rho ** (2*b) for b in range(1, n+1)] + Q = [rho ** (2 * b) for b in range(1, n + 1)] - A = [G(a) for a in range(n) if rho**(2*a) - 1 in Q] - B = [G(b) for b in range(n) if -rho**(2*b) - 1 not in Q] + A = [G(a) for a in range(n) if rho ** (2 * a) - 1 in Q] + B = [G(b) for b in range(n) if -(rho ** (2 * b)) - 1 not in Q] if check: assert are_complementary_difference_sets(G, A, B) @@ -3417,7 +3255,7 @@ def complementary_difference_sets(n, existence=False, check=True): if existence: return True G, A, B = complementary_difference_setsII(n, check=False) - elif is_prime_power(2*n + 1): + elif is_prime_power(2 * n + 1): if existence: return True G, A, B = complementary_difference_setsIII(n, check=False) @@ -3725,130 +3563,132 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch return False raise EmptySetError("No difference family eixsts with negative parameters") - if (v,k,l) in DF: + if (v, k, l) in DF: if existence: return True if explain_construction: - return "The database contains a ({},{},{})-difference family".format(v,k,l) + return "The database contains a ({},{},{})-difference family".format(v, k, l) - vv, blocks = next(iter(DF[v,k,l].items())) + vv, blocks = next(iter(DF[v, k, l].items())) # Build the group from sage.rings.finite_rings.integer_mod_ring import Zmod + if len(vv) == 1: G = Zmod(vv[0]) else: from sage.categories.cartesian_product import cartesian_product + G = cartesian_product([Zmod(i) for i in vv]) df = [[G(i) for i in b] for b in blocks] if check and not is_difference_family(G, df, v=v, k=k, l=l): - raise RuntimeError("There is an invalid ({},{},{})-difference " - "family in the database... Please contact " - "sage-devel@googlegroups.com".format(v,k,l)) + raise RuntimeError("There is an invalid ({},{},{})-difference " "family in the database... Please contact " "sage-devel@googlegroups.com".format(v, k, l)) - return G,df + return G, df if l == 1 and k in EDS and v in EDS[k]: if existence: return True if explain_construction: - return "The database contains a ({},{})-evenly distributed set".format(v,k) + return "The database contains a ({},{})-evenly distributed set".format(v, k) from sage.rings.finite_rings.finite_field_constructor import GF - poly,B = EDS[k][v] + + poly, B = EDS[k][v] if poly is None: # q is prime K = G = GF(v) else: - K = G = GF(v,'a',modulus=poly) + K = G = GF(v, 'a', modulus=poly) B = [K(b) for b in B] - e = k*(k-1)//2 - xe = G.multiplicative_generator()**e - df = [[xe**j*b for b in B] for j in range((v-1)//(2*e))] + e = k * (k - 1) // 2 + xe = G.multiplicative_generator() ** e + df = [[xe**j * b for b in B] for j in range((v - 1) // (2 * e))] if check and not is_difference_family(G, df, v=v, k=k, l=l): - raise RuntimeError("There is an invalid ({},{})-evenly distributed " - "set in the database... Please contact " - "sage-devel@googlegroups.com".format(v, k)) + raise RuntimeError("There is an invalid ({},{})-evenly distributed " "set in the database... Please contact " "sage-devel@googlegroups.com".format(v, k)) return G, df - if k in [0,1]: + if k in [0, 1]: # Then \Delta D_i is empty # So if G\{0} is empty is good, otherwise not if v == 1: if existence: return True from sage.rings.finite_rings.integer_mod_ring import Zmod + l = [0] if k == 1 else [] - return Zmod(1),[l] + return Zmod(1), [l] if existence: return False raise EmptySetError("No difference family exists with k=1 and v!=1") - e = k*(k-1) - if (l*(v-1)) % e: + e = k * (k - 1) + if (l * (v - 1)) % e: if existence: return Unknown - raise NotImplementedError("No construction available for ({},{},{})-difference family".format(v,k,l)) + raise NotImplementedError("No construction available for ({},{},{})-difference family".format(v, k, l)) # trivial construction - if k == (v-1) and l == (v-2): + if k == (v - 1) and l == (v - 2): if existence: return True if explain_construction: return "Trivial difference family" from sage.rings.finite_rings.integer_mod_ring import Zmod + G = Zmod(v) return G, [list(range(1, v))] factorization = factor(v) if len(factorization) == 1: from sage.rings.finite_rings.finite_field_constructor import GF - K = GF(v,'z') - if are_mcfarland_1973_parameters(v,k,l): + K = GF(v, 'z') + + if are_mcfarland_1973_parameters(v, k, l): if existence: return True if explain_construction: return "McFarland 1973 construction" - _, (q,s) = are_mcfarland_1973_parameters(v,k,l,True) - G,D = mcfarland_1973_construction(q,s) + _, (q, s) = are_mcfarland_1973_parameters(v, k, l, True) + G, D = mcfarland_1973_construction(q, s) - elif are_hyperplanes_in_projective_geometry_parameters(v,k,l): + elif are_hyperplanes_in_projective_geometry_parameters(v, k, l): if existence: return True if explain_construction: return "Singer difference set" - _, (q,d) = are_hyperplanes_in_projective_geometry_parameters(v,k,l,True) - G,D = singer_difference_set(q,d) + _, (q, d) = are_hyperplanes_in_projective_geometry_parameters(v, k, l, True) + G, D = singer_difference_set(q, d) - elif are_hadamard_difference_set_parameters(v,k,l) and k-2*l == 3: + elif are_hadamard_difference_set_parameters(v, k, l) and k - 2 * l == 3: if existence: return True if explain_construction: return "Turyn 1965 construction" - G,D = turyn_1965_3x3xK(4) + G, D = turyn_1965_3x3xK(4) - elif are_hadamard_difference_set_parameters(v,k,l) and hadamard_difference_set_product_parameters(k-2*l): - N1,N2 = hadamard_difference_set_product_parameters(k-2*l) + elif are_hadamard_difference_set_parameters(v, k, l) and hadamard_difference_set_product_parameters(k - 2 * l): + N1, N2 = hadamard_difference_set_product_parameters(k - 2 * l) if existence: return True if explain_construction: - return "Hadamard difference set product from N1={} and N2={}".format(N1,N2) - v1 = 4*N1*N1 - v2 = 4*N2*N2 - k1 = 2*N1*N1 - N1 - k2 = 2*N2*N2 - N2 - l1 = N1*N1 - N1 - l2 = N2*N2 - N2 - G1, D1 = difference_family(v1,k1,l1) - G2, D2 = difference_family(v2,k2,l2) - G, D = hadamard_difference_set_product(G1,D1,G2,D2) - - elif are_hadamard_difference_set_parameters(v,k,l) and (k-2*l).is_prime(): + return "Hadamard difference set product from N1={} and N2={}".format(N1, N2) + v1 = 4 * N1 * N1 + v2 = 4 * N2 * N2 + k1 = 2 * N1 * N1 - N1 + k2 = 2 * N2 * N2 - N2 + l1 = N1 * N1 - N1 + l2 = N2 * N2 - N2 + G1, D1 = difference_family(v1, k1, l1) + G2, D2 = difference_family(v2, k2, l2) + G, D = hadamard_difference_set_product(G1, D1, G2, D2) + + elif are_hadamard_difference_set_parameters(v, k, l) and (k - 2 * l).is_prime(): if existence: return False raise EmptySetError("by McFarland 1989 such difference family does not exist") @@ -3858,13 +3698,10 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch return True if explain_construction: return "Radical difference family on a finite field" - D = radical_difference_family(K,k,l) + D = radical_difference_family(K, k, l) G = K - elif (len(factorization) == 1 - and l == 1 - and k == 6 - and df_q_6_1(K, existence=True) is True): + elif len(factorization) == 1 and l == 1 and k == 6 and df_q_6_1(K, existence=True) is True: if existence: return True if explain_construction: @@ -3872,10 +3709,7 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch D = df_q_6_1(K) G = K - elif (k == (v-1)//2 and - l == (k-1)//2 and - len(factorization) == 2 and - abs(pow(*factorization[0]) - pow(*factorization[1])) == 2): + elif k == (v - 1) // 2 and l == (k - 1) // 2 and len(factorization) == 2 and abs(pow(*factorization[0]) - pow(*factorization[1])) == 2: # Twin prime powers construction # i.e. v = p(p+2) where p and p+2 are prime powers # k = (v-1)/2 @@ -3887,10 +3721,10 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch p = pow(*factorization[0]) q = pow(*factorization[1]) if p > q: - p,q = q,p - G,D = twin_prime_powers_difference_set(p,check=False) + p, q = q, p + G, D = twin_prime_powers_difference_set(p, check=False) - elif (v-1)//2 == k and (v-1)//2-1 == l and complementary_difference_sets(v, existence=True): + elif (v - 1) // 2 == k and (v - 1) // 2 - 1 == l and complementary_difference_sets(v, existence=True): if existence: return True if explain_construction: @@ -3903,15 +3737,13 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch return Unknown raise NotImplementedError("No constructions for these parameters") - if check and not is_difference_family(G,D,v=v,k=k,l=l,verbose=False): - raise RuntimeError("There is a problem. Sage built the following " - "difference family on G='{}' with parameters ({},{},{}):\n " - "{}\nwhich seems to not be a difference family... " - "Please contact sage-devel@googlegroups.com".format(G,v,k,l,D)) + if check and not is_difference_family(G, D, v=v, k=k, l=l, verbose=False): + raise RuntimeError("There is a problem. Sage built the following " "difference family on G='{}' with parameters ({},{},{}):\n " "{}\nwhich seems to not be a difference family... " "Please contact sage-devel@googlegroups.com".format(G, v, k, l, D)) return G, D from sage.misc.rest_index_of_methods import gen_rest_table_index import sys + __doc__ = __doc__.format(INDEX_OF_FUNCTIONS=gen_rest_table_index(sys.modules[__name__])) diff --git a/src/sage/combinat/designs/difference_matrices.py b/src/sage/combinat/designs/difference_matrices.py index b85340e1122..d07671eda01 100644 --- a/src/sage/combinat/designs/difference_matrices.py +++ b/src/sage/combinat/designs/difference_matrices.py @@ -46,7 +46,7 @@ def find_product_decomposition(g, k, lmbda=1): False """ for lmbda1 in divisors(lmbda): - lmbda2 = lmbda//lmbda1 + lmbda2 = lmbda // lmbda1 # To avoid infinite loop: # if lmbda1 == lmbda, then g1 should not be g @@ -63,12 +63,11 @@ def find_product_decomposition(g, k, lmbda=1): div = divisors(g) for g1 in div: - g2 = g//g1 + g2 = g // g1 if g1 > g2: break - if (difference_matrix(g1,k,lmbda1,existence=True) is True and - difference_matrix(g2,k,lmbda2,existence=True) is True): - return (g1,lmbda1),(g2,lmbda2) + if difference_matrix(g1, k, lmbda1, existence=True) is True and difference_matrix(g2, k, lmbda2, existence=True) is True: + return (g1, lmbda1), (g2, lmbda2) return False @@ -111,17 +110,18 @@ def difference_matrix_product(k, M1, G1, lmbda1, M2, G2, lmbda2, check=True): """ g1 = G1.cardinality() g2 = G2.cardinality() - g = g1*g2 - lmbda = lmbda1*lmbda2 + g = g1 * g2 + lmbda = lmbda1 * lmbda2 from sage.categories.cartesian_product import cartesian_product - G = cartesian_product([G1,G2]) - M = [[G((M1[j1][i],M2[j2][i])) for i in range(k)] for j1 in range(lmbda1*g1) for j2 in range(lmbda2*g2)] + G = cartesian_product([G1, G2]) - if check and not is_difference_matrix(M,G,k,lmbda,True): - raise RuntimeError("In the product construction, Sage built something which is not a ({},{},{})-DM!".format(g,k,lmbda)) + M = [[G((M1[j1][i], M2[j2][i])) for i in range(k)] for j1 in range(lmbda1 * g1) for j2 in range(lmbda2 * g2)] - return G,M + if check and not is_difference_matrix(M, G, k, lmbda, True): + raise RuntimeError("In the product construction, Sage built something which is not a ({},{},{})-DM!".format(g, k, lmbda)) + + return G, M def difference_matrix(g, k, lmbda=1, existence=False, check=True): @@ -224,7 +224,7 @@ def difference_matrix(g, k, lmbda=1, existence=False, check=True): if lmbda == 1 and k is not None and k > g: if existence: return False - raise EmptySetError("No ({},{},{})-Difference Matrix exists as k(={})>g(={})".format(g,k,lmbda,k,g)) + raise EmptySetError("No ({},{},{})-Difference Matrix exists as k(={})>g(={})".format(g, k, lmbda, k, g)) # Prime powers elif lmbda == 1 and is_prime_power(g): @@ -234,20 +234,20 @@ def difference_matrix(g, k, lmbda=1, existence=False, check=True): k = g elif existence: return True - F = FiniteField(g,'x') + F = FiniteField(g, 'x') F_set = list(F) F_k_set = F_set[:k] G = F - M = [[x*y for y in F_k_set] for x in F_set] + M = [[x * y for y in F_k_set] for x in F_set] # Treat the case k=None # (find the max k such that there exists a DM) elif k is None: i = 2 - while difference_matrix(g=g,k=i,lmbda=lmbda,existence=True) is True: + while difference_matrix(g=g, k=i, lmbda=lmbda, existence=True) is True: i += 1 - return i-1 + return i - 1 # From the database elif (g, lmbda) in DM_constructions and DM_constructions[g, lmbda][0] >= k: @@ -264,13 +264,12 @@ def difference_matrix(g, k, lmbda=1, existence=False, check=True): (g1, lmbda1), (g2, lmbda2) = find_product_decomposition(g, k, lmbda) G1, M1 = difference_matrix(g1, k, lmbda1) G2, M2 = difference_matrix(g2, k, lmbda2) - G, M = difference_matrix_product(k, M1, G1, lmbda1, - M2, G2, lmbda2, check=False) + G, M = difference_matrix_product(k, M1, G1, lmbda1, M2, G2, lmbda2, check=False) else: if existence: return Unknown - raise NotImplementedError("I don't know how to build a ({},{},{})-Difference Matrix!".format(g,k,lmbda)) + raise NotImplementedError("I don't know how to build a ({},{},{})-Difference Matrix!".format(g, k, lmbda)) if check and not is_difference_matrix(M, G, k, lmbda, 1): raise RuntimeError("Sage built something which is not a ({},{},{})-DM!".format(g, k, lmbda)) diff --git a/src/sage/combinat/designs/ext_rep.py b/src/sage/combinat/designs/ext_rep.py index 733c5bf2c18..f3004273277 100644 --- a/src/sage/combinat/designs/ext_rep.py +++ b/src/sage/combinat/designs/ext_rep.py @@ -48,8 +48,7 @@ # http://designtheory.org/database/v-b-k/v2-b2-k2.icgsa.txt.bz2 # We use this for doctests to make sure that the parsing works. -v2_b2_k2_icgsa = \ -""" +v2_b2_k2_icgsa = """ `` and ````. ''' + def _init(self): """ Internal initialisation for the processor of XTrees. @@ -887,8 +885,7 @@ def _end_element(self, name): if self.in_item: children = self.current_node[2] if len(children) > 0 and isinstance(children[0], tuple): - if children[0][0] == 'z' or children[0][0] == 'd' \ - or children[0][0] == 'q': + if children[0][0] == 'z' or children[0][0] == 'd' or children[0][0] == 'q': if children[0][0] == 'z': convert = int elif children[0][0] == 'd': @@ -899,9 +896,7 @@ def _end_element(self, name): for x in children: ps.append(convert(''.join(x[2]))) del children[:] - if name == 'block' or name == 'permutation' \ - or name == 'preimage' or name == 'ksubset' \ - or name == 'cycle_type' or name == 'row': + if name == 'block' or name == 'permutation' or name == 'preimage' or name == 'ksubset' or name == 'cycle_type' or name == 'row': # these enclose lists of numbers children.append(ps) else: diff --git a/src/sage/combinat/designs/group_divisible_designs.py b/src/sage/combinat/designs/group_divisible_designs.py index aed9bda8a93..113ebf2725c 100644 --- a/src/sage/combinat/designs/group_divisible_designs.py +++ b/src/sage/combinat/designs/group_divisible_designs.py @@ -92,6 +92,7 @@ def group_divisible_design(v, K, G, existence=False, check=False): # from a (v+1,k,1)-BIBD if len(G) == 1 == len(K) and G[0] + 1 in K: from .bibd import balanced_incomplete_block_design + k = K[0] if existence: return balanced_incomplete_block_design(v + 1, k, existence=True) @@ -100,13 +101,11 @@ def group_divisible_design(v, K, G, existence=False, check=False): d = {p: i for i, p in enumerate(sum(groups, []))} d[v] = v BIBD.relabel(d) - groups = [list(range((k - 1) * i, (k - 1) * (i + 1))) - for i in range(v // (k - 1))] + groups = [list(range((k - 1) * i, (k - 1) * (i + 1))) for i in range(v // (k - 1))] blocks = [S for S in BIBD if v not in S] # (v,{4},{2})-GDD - elif (v % 2 == 0 and K == [4] and - G == [2] and GDD_4_2(v // 2, existence=True)): + elif v % 2 == 0 and K == [4] and G == [2] and GDD_4_2(v // 2, existence=True): if existence: return True return GDD_4_2(v // 2, check=check) @@ -114,16 +113,11 @@ def group_divisible_design(v, K, G, existence=False, check=False): # From a TD(k,g) elif len(G) == 1 == len(K) and K[0] * G[0] == v: from .orthogonal_arrays import transversal_design + return transversal_design(k=K[0], n=G[0], existence=existence) if blocks: - return GroupDivisibleDesign(v, - groups=groups, - blocks=blocks, - G=G, - K=K, - check=check, - copy=True) + return GroupDivisibleDesign(v, groups=groups, blocks=blocks, G=G, K=K, check=check, copy=True) if existence: return Unknown @@ -175,26 +169,18 @@ def GDD_4_2(q, existence=False, check=True): return True from sage.rings.finite_rings.finite_field_constructor import FiniteField + G = FiniteField(q, 'x') w = G.primitive_element() - e = w**((q - 1) // 3) + e = w ** ((q - 1) // 3) # A first parallel class is defined. G acts on it, which yields all others. - first_class = [[(0, 0), (1, w**i), (1, e * w**i), (1, e * e * w**i)] - for i in range((q - 1) // 6)] + first_class = [[(0, 0), (1, w**i), (1, e * w**i), (1, e * e * w**i)] for i in range((q - 1) // 6)] label = {p: i for i, p in enumerate(G)} - classes = [[[2 * label[x[1] + g] + (x[0] + j) % 2 for x in S] - for S in first_class] - for g in G for j in range(2)] + classes = [[[2 * label[x[1] + g] + (x[0] + j) % 2 for x in S] for S in first_class] for g in G for j in range(2)] - return GroupDivisibleDesign(2 * q, - groups=[[i, i + 1] for i in range(0, 2 * q, 2)], - blocks=sum(classes, []), - K=[4], - G=[2], - check=check, - copy=False) + return GroupDivisibleDesign(2 * q, groups=[[i, i + 1] for i in range(0, 2 * q, 2)], blocks=sum(classes, []), K=[4], G=[2], check=check, copy=False) class GroupDivisibleDesign(IncidenceStructure): @@ -259,8 +245,8 @@ class GroupDivisibleDesign(IncidenceStructure): sage: sorted(GDD.groups()) [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i'], ['k', 'l', 'm']] """ - def __init__(self, points, groups, blocks, G=None, K=None, lambd=1, - check=True, copy=True, **kwds): + + def __init__(self, points, groups, blocks, G=None, K=None, lambd=1, check=True, copy=True, **kwds): r""" Constructor function. @@ -276,12 +262,7 @@ def __init__(self, points, groups, blocks, G=None, K=None, lambd=1, self._lambd = lambd - IncidenceStructure.__init__(self, - points, - blocks, - copy=copy, - check=False, - **kwds) + IncidenceStructure.__init__(self, points, blocks, copy=copy, check=False, **kwds) if groups is None or (copy is False and self._point_to_index is None): self._groups = groups @@ -291,9 +272,7 @@ def __init__(self, points, groups, blocks, G=None, K=None, lambd=1, self._groups = [[self._point_to_index[x] for x in g] for g in groups] if check or groups is None: - is_gdd = is_group_divisible_design(self._groups, self._blocks, - self.n_points(), G, K, - lambd, verbose=1) + is_gdd = is_group_divisible_design(self._groups, self._blocks, self.n_points(), G, K, lambd, verbose=1) assert is_gdd if groups is None: self._groups = is_gdd[1] @@ -347,8 +326,7 @@ def __repr__(self): """ group_sizes = [len(g) for g in self._groups] - gdd_type = ("{}^{}".format(s, group_sizes.count(s)) - for s in sorted(set(group_sizes))) + gdd_type = ("{}^{}".format(s, group_sizes.count(s)) for s in sorted(set(group_sizes))) gdd_type = ".".join(gdd_type) if not gdd_type: diff --git a/src/sage/combinat/designs/incidence_structures.py b/src/sage/combinat/designs/incidence_structures.py index 2f8e5ccd95c..4d59763e7c9 100644 --- a/src/sage/combinat/designs/incidence_structures.py +++ b/src/sage/combinat/designs/incidence_structures.py @@ -26,6 +26,7 @@ Methods ------- """ + # ************************************************************************** # Copyright (C) 2007 # # # @@ -142,8 +143,8 @@ class IncidenceStructure(SageObject): sage: I._blocks is blocks True """ - def __init__(self, points=None, blocks=None, incidence_matrix=None, - name=None, check=True, copy=True) -> None: + + def __init__(self, points=None, blocks=None, incidence_matrix=None, name=None, check=True, copy=True) -> None: r""" TESTS:: @@ -194,6 +195,7 @@ def __init__(self, points=None, blocks=None, incidence_matrix=None, if incidence_matrix: from sage.matrix.constructor import matrix + M = matrix(incidence_matrix) v = M.nrows() self._points = list(range(v)) @@ -271,8 +273,7 @@ def __repr__(self) -> str: sage: BD Incidence structure with 7 points and 7 blocks """ - return 'Incidence structure with {} points and {} blocks'.format( - self.n_points(), self.n_blocks()) + return 'Incidence structure with {} points and {} blocks'.format(self.n_points(), self.n_blocks()) __str__ = __repr__ @@ -309,8 +310,7 @@ def __eq__(self, other) -> bool: if self._points == other._points: return self._blocks == other._blocks - if (self.n_points() != other.n_points() or - self.n_blocks() != other.n_blocks()): + if self.n_points() != other.n_points() or self.n_blocks() != other.n_blocks(): return False p_to_i = self._point_to_index if self._point_to_index else list(range(self.n_points())) @@ -408,10 +408,11 @@ def canonical_label(self): """ if self._canonical_label is None: from sage.graphs.graph import Graph + g = Graph() n = self.n_points() - g.add_edges((i+n, x) for i, b in enumerate(self._blocks) for x in b) - canonical_label = g.canonical_label([list(range(n)), list(range(n, n+self.n_blocks()))], certificate=True)[1] + g.add_edges((i + n, x) for i, b in enumerate(self._blocks) for x in b) + canonical_label = g.canonical_label([list(range(n)), list(range(n, n + self.n_blocks()))], certificate=True)[1] canonical_label = [canonical_label[x] for x in range(n)] self._canonical_label = canonical_label @@ -474,9 +475,7 @@ def is_isomorphic(self, other, certificate=False): sage: IS1._canonical_label is None or IS2._canonical_label is None False """ - if (self.n_points() != other.n_points() or - self.n_blocks() != other.n_blocks() or - sorted(self.block_sizes()) != sorted(other.block_sizes())): + if self.n_points() != other.n_points() or self.n_blocks() != other.n_blocks() or sorted(self.block_sizes()) != sorted(other.block_sizes()): return {} if certificate else False A_canon = self.canonical_label() @@ -559,6 +558,7 @@ def isomorphic_substructures_iterator(self, H2, induced=False): 5616 """ from sage.combinat.designs.subhypergraph_search import SubHypergraphSearch + return SubHypergraphSearch(self, H2, induced=induced) def copy(self): @@ -577,9 +577,7 @@ def copy(self): sage: copy(IS)._name 'Test' """ - IS = IncidenceStructure(self._blocks, - name=self._name, - check=False) + IS = IncidenceStructure(self._blocks, name=self._name, check=False) IS.relabel(dict(zip(range(self.n_points()), self._points))) IS._canonical_label = None if self._canonical_label is None else self._canonical_label[:] @@ -643,10 +641,7 @@ def induced_substructure(self, points): raise ValueError("{} is not a point of the incidence structure".format(bad_pt)) int_points = set(int_points) - return IncidenceStructure(points, - [[self._points[x] for x in S] - for S in self._blocks - if int_points.issuperset(S)]) + return IncidenceStructure(points, [[self._points[x] for x in S] for S in self._blocks if int_points.issuperset(S)]) def trace(self, points, min_size=1, multiset=True): r""" @@ -896,12 +891,13 @@ def degrees(self, size=None): True """ if size is None: - d = [0]*self.n_points() + d = [0] * self.n_points() for b in self._blocks: for x in b: d[x] += 1 return {p: d[i] for i, p in enumerate(self._points)} from itertools import combinations + d = {t: 0 for t in combinations(range(self.n_points()), size)} for b in self._blocks: for s in combinations(b, size): @@ -1032,6 +1028,7 @@ def is_connected(self) -> bool: False """ from sage.sets.disjoint_set import DisjointSet + D = DisjointSet(self.n_points()) for B in self._blocks: x = B[0] @@ -1135,13 +1132,13 @@ def intersection_graph(self, sizes=None, immutable=False): from sage.sets.positive_integers import PositiveIntegers from sage.graphs.graph import Graph from sage.sets.set import Set + if sizes is None: sizes = PositiveIntegers() elif sizes in PositiveIntegers(): sizes = (sizes,) V = [Set(v) for v in self] - return Graph([V, lambda x, y: len(x & y) in sizes], format="rule", - loops=False, immutable=immutable) + return Graph([V, lambda x, y: len(x & y) in sizes], format="rule", loops=False, immutable=immutable) def incidence_matrix(self): r""" @@ -1172,6 +1169,7 @@ def incidence_matrix(self): """ from sage.matrix.constructor import matrix from sage.rings.integer_ring import ZZ + A = matrix(ZZ, self.n_points(), self.n_blocks(), sparse=True) for j, b in enumerate(self._blocks): for i in b: @@ -1224,6 +1222,7 @@ def incidence_graph(self, labels=False): if labels: from sage.graphs.graph import Graph from sage.sets.set import Set + G = Graph() G.add_vertices(self.ground_set()) for b in self.blocks(): @@ -1233,6 +1232,7 @@ def incidence_graph(self, labels=False): return G from sage.graphs.bipartite_graph import BipartiteGraph + A = self.incidence_matrix() return BipartiteGraph(A) @@ -1330,6 +1330,7 @@ def complement(self, uniform=False): n_blocks = self.n_blocks() i = 0 from itertools import combinations + for B in combinations(range(self.n_points()), k): B = list(B) while i < n_blocks and self._blocks[i] < B: @@ -1409,6 +1410,7 @@ def relabel(self, perm=None, inplace=True): """ if not inplace: from copy import copy + G = copy(self) G.relabel(perm=perm, inplace=True) return G @@ -1502,8 +1504,7 @@ def packing(self, solver=None, verbose=0, *, integrality_tolerance=1e-3): p.solve(log=verbose) values = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - return [[self._points[x] for x in self._blocks[i]] - for i, v in values.items() if v] + return [[self._points[x] for x in self._blocks[i]] for i, v in values.items() if v] def is_t_design(self, t=None, v=None, k=None, l=None, return_parameters=False): r""" @@ -1653,19 +1654,18 @@ def is_t_design(self, t=None, v=None, k=None, l=None, return_parameters=False): b = self.n_blocks() # Trivial wrong answers - if (any(len(block) != k for block in self._blocks) or # non k-uniform - v != self.n_points()): + if any(len(block) != k for block in self._blocks) or v != self.n_points(): # non k-uniform return (False, (0, 0, 0, 0)) if return_parameters else False # Trivial case t>k - if (t is not None and t > k): - if (l is None or l == 0): + if t is not None and t > k: + if l is None or l == 0: return (True, (t, v, k, 0)) if return_parameters else True return (False, (0, 0, 0, 0)) if return_parameters else False # Trivial case k=0 if k == 0: - if (l is None or l == 0): + if l is None or l == 0: return (True, (0, v, k, b)) if return_parameters else True return (False, (0, 0, 0, 0)) if return_parameters else False @@ -1684,7 +1684,8 @@ def is_t_design(self, t=None, v=None, k=None, l=None, return_parameters=False): # # We look for the largest t such that self is a t-design from itertools import combinations - for tt in (range(1, k + 1) if t is None else [t]): + + for tt in range(1, k + 1) if t is None else [t]: # is lambda an integer? if (b * binomial(k, tt)) % binomial(v, tt): tt -= 1 @@ -1701,8 +1702,7 @@ def is_t_design(self, t=None, v=None, k=None, l=None, return_parameters=False): ll = (b * binomial(k, tt)) // binomial(v, tt) - if ((t is not None and t != tt) or - (l is not None and l != ll)): + if (t is not None and t != tt) or (l is not None and l != ll): return (False, (0, 0, 0, 0)) if return_parameters else False if tt == 0: ll = b @@ -1853,9 +1853,7 @@ def dual(self, algorithm=None): gB = [[x - 1 for x in b] for b in DD['blocks'].sage()] return IncidenceStructure(list(range(v)), gB, name=None, check=False) - return IncidenceStructure( - incidence_matrix=self.incidence_matrix().transpose(), - check=False) + return IncidenceStructure(incidence_matrix=self.incidence_matrix().transpose(), check=False) def automorphism_group(self): r""" @@ -1894,24 +1892,20 @@ def automorphism_group(self): """ from sage.graphs.graph import Graph from sage.groups.perm_gps.permgroup import PermutationGroup + g = Graph() n = self.n_points() g.add_edges((i + n, x) for i, b in enumerate(self._blocks) for x in b) - ag = g.automorphism_group(partition=[list(range(n)), - list(range(n, n + self.n_blocks()))]) + ag = g.automorphism_group(partition=[list(range(n)), list(range(n, n + self.n_blocks()))]) if self._point_to_index: - gens = [[tuple([self._points[i] for i in cycle if (not cycle or cycle[0] < n)]) - for cycle in g.cycle_tuples()] - for g in ag.gens()] + gens = [[tuple([self._points[i] for i in cycle if (not cycle or cycle[0] < n)]) for cycle in g.cycle_tuples()] for g in ag.gens()] else: - gens = [[tuple(cycle) for cycle in g.cycle_tuples() if (not cycle or cycle[0] < n)] - for g in ag.gens()] + gens = [[tuple(cycle) for cycle in g.cycle_tuples() if (not cycle or cycle[0] < n)] for g in ag.gens()] return PermutationGroup(gens, domain=self._points) - def is_resolvable(self, certificate=False, solver=None, verbose=0, check=True, - *, integrality_tolerance=1e-3): + def is_resolvable(self, certificate=False, solver=None, verbose=0, check=True, *, integrality_tolerance=1e-3): r""" Test whether the hypergraph is resolvable. @@ -2004,6 +1998,7 @@ def is_resolvable(self, certificate=False, solver=None, verbose=0, check=True, else: from sage.numerical.mip import MixedIntegerLinearProgram from sage.numerical.mip import MIPSolverException + n_classes = degrees.pop() p = MixedIntegerLinearProgram(solver=solver) b = p.new_variable(binary=True) @@ -2054,8 +2049,7 @@ def is_resolvable(self, certificate=False, solver=None, verbose=0, check=True, return True - def coloring(self, k=None, solver=None, verbose=0, - *, integrality_tolerance=1e-3) -> list: + def coloring(self, k=None, solver=None, verbose=0, *, integrality_tolerance=1e-3) -> list: r""" Compute a (weak) `k`-coloring of the hypergraph. @@ -2119,15 +2113,14 @@ def coloring(self, k=None, solver=None, verbose=0, raise ValueError("Only empty hypergraphs are 0-chromatic") return [] if any(len(x) == 1 for x in self._blocks): - raise RuntimeError("No coloring can be defined " - "when there is a set of size 1") + raise RuntimeError("No coloring can be defined " "when there is a set of size 1") elif k == 1: if any(self._blocks): - raise ValueError("This hypergraph contains a set. " - "It is not 1-chromatic") + raise ValueError("This hypergraph contains a set. " "It is not 1-chromatic") return [self.ground_set()] from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException + p = MixedIntegerLinearProgram(solver=solver) b = p.new_variable(binary=True) @@ -2173,11 +2166,10 @@ def edge_coloring(self) -> list[list]: True """ from sage.graphs.graph import Graph + blocks = self.blocks() blocks_sets = [frozenset(b) for b in blocks] - g = Graph([list(range(self.n_blocks())), - lambda x, y: len(blocks_sets[x] & blocks_sets[y])], - loops=False) + g = Graph([list(range(self.n_blocks())), lambda x, y: len(blocks_sets[x] & blocks_sets[y])], loops=False) return [[blocks[i] for i in C] for C in g.coloring(algorithm='MILP')] def _spring_layout(self) -> dict: @@ -2227,8 +2219,7 @@ def _spring_layout(self) -> dict: _ = g.plot(iterations=50000, save_pos=True) # The values are rounded as TikZ does not like accuracy. - return {k[1]: (round(x, 3), round(y, 3)) - for k, (x, y) in g.get_pos().items()} + return {k[1]: (round(x, 3), round(y, 3)) for k, (x, y) in g.get_pos().items()} def _latex_(self) -> str: r""" @@ -2268,25 +2259,19 @@ def _latex_(self) -> str: from sage.functions.trig import arctan2 from warnings import warn - warn("\nThe hypergraph is drawn as a set of closed curves. The curve " - "representing a set S goes **THROUGH** the points contained " - "in S.\n A point which is encircled by a curve but is not located " - "on its boundary is **NOT** included in the corresponding set.\n" - "\n" - "The colors are picked for readability and have no other meaning.") + + warn("\nThe hypergraph is drawn as a set of closed curves. The curve " "representing a set S goes **THROUGH** the points contained " "in S.\n A point which is encircled by a curve but is not located " "on its boundary is **NOT** included in the corresponding set.\n" "\n" "The colors are picked for readability and have no other meaning.") latex.add_package_to_preamble_if_available("tikz") if not latex.has_file("tikz.sty"): - raise RuntimeError("You must have TikZ installed in order " - "to draw a hypergraph.") + raise RuntimeError("You must have TikZ installed in order " "to draw a hypergraph.") domain = self.ground_set() pos = self._spring_layout() tex = "\\begin{tikzpicture}[scale=3]\n" - colors = ["black", "red", "green", "blue", "cyan", - "magenta", "yellow", "pink", "brown"] + colors = ["black", "red", "green", "blue", "cyan", "magenta", "yellow", "pink", "brown"] colored_sets = [(s, i) for i, S in enumerate(self.edge_coloring()) for s in S] # Prints each set with its color @@ -2295,16 +2280,10 @@ def _latex_(self) -> str: if len(s) == 2: s = list(s) - tex += ("\\draw[color="+str(current_color)+"," + - "line width=.1cm,opacity = .6] " + - str(pos[s[0]])+" -- "+str(pos[s[1]])+";\n") + tex += "\\draw[color=" + str(current_color) + "," + "line width=.1cm,opacity = .6] " + str(pos[s[0]]) + " -- " + str(pos[s[1]]) + ";\n" continue - tex += ("\\draw[color="+str(current_color)+"," - "line width=.1cm,opacity = .6," - "line cap=round," - "line join=round]" - "plot [smooth cycle,tension=1] coordinates {") + tex += "\\draw[color=" + str(current_color) + "," "line width=.1cm,opacity = .6," "line cap=round," "line join=round]" "plot [smooth cycle,tension=1] coordinates {" # Reorders the vertices of s according to their angle with the # "center", i.e. the vertex representing the set s @@ -2313,12 +2292,12 @@ def _latex_(self) -> str: s = sorted(s, key=lambda x_y: arctan2(x_y[0] - cx, x_y[1] - cy)) for x in s: - tex += str(x)+" " + tex += str(x) + " " tex += "};\n" # Prints each vertex for v in domain: - tex += "\\draw node[fill,circle,scale=.5,label={90:$"+latex(v)+"$}] at "+str(pos[v])+" {};\n" + tex += "\\draw node[fill,circle,scale=.5,label={90:$" + latex(v) + "$}] at " + str(pos[v]) + " {};\n" tex += "\\end{tikzpicture}" return tex @@ -2383,4 +2362,5 @@ def is_spread(self, spread) -> bool: from sage.misc.rest_index_of_methods import gen_rest_table_index + __doc__ = __doc__.format(METHODS_OF_IncidenceStructure=gen_rest_table_index(IncidenceStructure)) diff --git a/src/sage/combinat/designs/latin_squares.py b/src/sage/combinat/designs/latin_squares.py index fe23aaa4f87..9b779c8e632 100644 --- a/src/sage/combinat/designs/latin_squares.py +++ b/src/sage/combinat/designs/latin_squares.py @@ -190,7 +190,7 @@ def are_mutually_orthogonal_latin_squares(l, verbose=False): return False # Check that all matrices are latin squares - for i,M in enumerate(l): + for i, M in enumerate(l): if any(len(set(R)) != n for R in M): if verbose: print("Matrix {} is not row latin".format(i)) @@ -201,7 +201,8 @@ def are_mutually_orthogonal_latin_squares(l, verbose=False): return False from .designs_pyx import is_orthogonal_array - return is_orthogonal_array(list(zip(*[[x for R in M for x in R] for M in l])),k,n, verbose=verbose, terminology='MOLS') + + return is_orthogonal_array(list(zip(*[[x for R in M for x in R] for M in l])), k, n, verbose=verbose, terminology='MOLS') def mutually_orthogonal_latin_squares(k, n, partitions=False, check=True): @@ -393,11 +394,10 @@ def mutually_orthogonal_latin_squares(k, n, partitions=False, check=True): assert F[0] == 0 # This dictionary is used to convert from field elements to integers - conv = {F[i] : i for i in range(n)} + conv = {F[i]: i for i in range(n)} # Make the matrices - matrices = [Matrix([[conv[F[i] + F[r]*F[j]] for i in range(n)] - for j in range(n)]) for r in range(1, k+1)] + matrices = [Matrix([[conv[F[i] + F[r] * F[j]] for i in range(n)] for j in range(n)]) for r in range(1, k + 1)] elif orthogonal_array(k + 2, n, existence=True) is not Unknown: # Forwarding non-existence results @@ -413,10 +413,10 @@ def mutually_orthogonal_latin_squares(k, n, partitions=False, check=True): matrices = [[] for _ in repeat(None, k)] for L in OA: for i in range(2, k + 2): - matrices[i-2].append(L[i]) + matrices[i - 2].append(L[i]) # The real matrices - matrices = [[M[i*n:(i+1)*n] for i in range(n)] for M in matrices] + matrices = [[M[i * n : (i + 1) * n] for i in range(n)] for M in matrices] matrices = [Matrix(M) for M in matrices] else: @@ -427,13 +427,12 @@ def mutually_orthogonal_latin_squares(k, n, partitions=False, check=True): # partitions have been requested but have not been computed yet if partitions is True: - partitions = [[[i*n+j for j in range(n)] for i in range(n)], - [[j*n+i for j in range(n)] for i in range(n)]] + partitions = [[[i * n + j for j in range(n)] for i in range(n)], [[j * n + i for j in range(n)] for i in range(n)]] for m in matrices: partition = [[] for _ in repeat(None, n)] for i in range(n): for j in range(n): - partition[m[i,j]].append(i*n+j) + partition[m[i, j]].append(i * n + j) partitions.append(partition) if partitions: @@ -467,14 +466,11 @@ def latin_square_product(M, N, *others): 64 x 64 sparse matrix over Integer Ring (use the '.str()' method to see the entries) """ from sage.matrix.constructor import Matrix + m = M.nrows() n = N.nrows() - D = {((i,j),(ii,jj)):(M[i,ii],N[j,jj]) - for i in range(m) - for ii in range(m) - for j in range(n) - for jj in range(n)} + D = {((i, j), (ii, jj)): (M[i, ii], N[j, jj]) for i in range(m) for ii in range(m) for j in range(n) for jj in range(n)} L = lambda i_j: i_j[0] * n + i_j[1] D = {(L(c[0]), L(c[1])): L(v) for c, v in D.items()} @@ -540,29 +536,30 @@ def MOLS_table(start, stop=None, compare=False, width=None): 80| """ from .orthogonal_arrays import largest_available_k + if stop is None: - start,stop = 0,start + start, stop = 0, start # make start and stop be congruent to 0 mod 20 start = start - (start % 20) - stop = stop-1 - stop = stop + (20-(stop % 20)) + stop = stop - 1 + stop = stop + (20 - (stop % 20)) assert start % 20 == 0 and stop % 20 == 0 if stop <= start: return # choose an appropriate width (needs to be >= 3 because "+oo" should fit) if width is None: - width = max(3, Integer(stop-1).ndigits(10)) + width = max(3, Integer(stop - 1).ndigits(10)) - print(" " * (width + 2) + " ".join("{i:>{width}}".format(i=i,width=width) - for i in range(20))) + print(" " * (width + 2) + " ".join("{i:>{width}}".format(i=i, width=width) for i in range(20))) print(" " * (width + 1) + "_" * ((width + 1) * 20), end="") - for i in range(start,stop): + for i in range(start, stop): if i % 20 == 0: print("\n{:>{width}}|".format(i, width=width), end="") - k = largest_available_k(i)-2 + k = largest_available_k(i) - 2 if compare: from . import MOLS_handbook_data + lower_bound = MOLS_handbook_data.lower_bound(i) if i < 2 or lower_bound == k: c = "" diff --git a/src/sage/combinat/designs/orthogonal_arrays.py b/src/sage/combinat/designs/orthogonal_arrays.py index d3f31a08ae4..fa99694e264 100644 --- a/src/sage/combinat/designs/orthogonal_arrays.py +++ b/src/sage/combinat/designs/orthogonal_arrays.py @@ -309,13 +309,13 @@ def transversal_design(k, n, resolvable=False, check=True, existence=False): """ if resolvable: if existence: - return orthogonal_array(k,n,resolvable=True,existence=True) - OA = orthogonal_array(k,n,resolvable=True,check=False) + return orthogonal_array(k, n, resolvable=True, existence=True) + OA = orthogonal_array(k, n, resolvable=True, check=False) # the call to TransversalDesign will sort the block so we can not # rely on the order *after* the call - blocks = [[i*n+c for i,c in enumerate(B)] for B in OA] - classes = [blocks[i:i+n] for i in range(0,n*n,n)] - TD = TransversalDesign(blocks,k,n,check=check,copy=False) + blocks = [[i * n + c for i, c in enumerate(B)] for B in OA] + classes = [blocks[i : i + n] for i in range(0, n * n, n)] + TD = TransversalDesign(blocks, k, n, check=check, copy=False) TD._classes = classes return TD @@ -324,22 +324,23 @@ def transversal_design(k, n, resolvable=False, check=True, existence=False): if n == 0 or n == 1: if existence: from sage.rings.infinity import Infinity + return Infinity raise ValueError("there is no upper bound on k when 0<=n<=1") - k = orthogonal_array(None,n,existence=True) + k = orthogonal_array(None, n, existence=True) if existence: return k - if existence and _OA_cache_get(k,n) is not None: - return _OA_cache_get(k,n) + if existence and _OA_cache_get(k, n) is not None: + return _OA_cache_get(k, n) if n == 1: if existence: return True TD = [list(range(k))] - elif k >= n+2: + elif k >= n + 2: if existence: return False raise EmptySetError("No Transversal Design exists when k>=n+2 if n>=2") @@ -354,17 +355,17 @@ def transversal_design(k, n, resolvable=False, check=True, existence=False): else: if existence: return False - raise EmptySetError("There exists no TD({},{})!".format(k,n)) + raise EmptySetError("There exists no TD({},{})!".format(k, n)) - OA = orthogonal_array(k,n, check=False) - TD = [[i*n+c for i,c in enumerate(l)] for l in OA] + OA = orthogonal_array(k, n, check=False) + TD = [[i * n + c for i, c in enumerate(l)] for l in OA] else: if existence: return Unknown - raise NotImplementedError("I don't know how to build a TD({},{})!".format(k,n)) + raise NotImplementedError("I don't know how to build a TD({},{})!".format(k, n)) - return TransversalDesign(TD,k,n,check=check) + return TransversalDesign(TD, k, n, check=check) class TransversalDesign(GroupDivisibleDesign): @@ -391,6 +392,7 @@ class TransversalDesign(GroupDivisibleDesign): sage: designs.transversal_design(None,36) Transversal Design TD(10,36) """ + def __init__(self, blocks, k=None, n=None, check=True, **kwds): r""" Constructor of the class. @@ -401,6 +403,7 @@ def __init__(self, blocks, k=None, n=None, check=True, **kwds): Transversal Design TD(6,5) """ from math import sqrt + if k is None: if blocks: k = len(blocks[0]) @@ -413,14 +416,9 @@ def __init__(self, blocks, k=None, n=None, check=True, **kwds): self._k = k if check: - assert is_transversal_design(blocks,k,n) + assert is_transversal_design(blocks, k, n) - GroupDivisibleDesign.__init__(self, - k*n, - [list(range(i*n,(i+1)*n)) for i in range(k)], - blocks, - check=False, - **kwds) + GroupDivisibleDesign.__init__(self, k * n, [list(range(i * n, (i + 1) * n)) for i in range(k)], blocks, check=False, **kwds) def __repr__(self): r""" @@ -435,7 +433,7 @@ def __repr__(self): sage: designs.transversal_design(None,36) Transversal Design TD(10,36) """ - return "Transversal Design TD({},{})".format(self._k,self._n) + return "Transversal Design TD({},{})".format(self._k, self._n) def is_transversal_design(B, k, n, verbose=False): @@ -469,7 +467,7 @@ def is_transversal_design(B, k, n, verbose=False): sage: is_transversal_design(TD, 4, 4) False """ - return is_orthogonal_array([[x % n for x in R] for R in B],k,n,verbose=verbose) + return is_orthogonal_array([[x % n for x in R] for R in B], k, n, verbose=verbose) def wilson_construction(OA, k, r, m, u, check=True, explain_construction=False): @@ -581,35 +579,30 @@ def wilson_construction(OA, k, r, m, u, check=True, explain_construction=False): except TypeError: pass else: - u = [[(1,uu)] for uu in u] + u = [[(1, uu)] for uu in u] n_trunc = len(u) if explain_construction: if not u: - return ("Product of orthogonal arrays n={}.{}").format(r,m) + return ("Product of orthogonal arrays n={}.{}").format(r, m) if all(len(uu) == 1 and uu[0][0] == 1 for uu in u): - return ("Wilson's construction n={}.{}+{} with master design OA({}+{},{})" - .format(r, m, "+".join(str(x) for ((_,x),) in u), k, n_trunc, r)) - return ("Brouwer-van Rees construction n={}.{}+{} with master design OA({}+{},{})" - .format(r, m, - "+".join("(" + "+".join(str(x)+"."+str(mul) for mul,x in uu) + ")" - for uu in u), - k, n_trunc, r)) + return "Wilson's construction n={}.{}+{} with master design OA({}+{},{})".format(r, m, "+".join(str(x) for ((_, x),) in u), k, n_trunc, r) + return "Brouwer-van Rees construction n={}.{}+{} with master design OA({}+{},{})".format(r, m, "+".join("(" + "+".join(str(x) + "." + str(mul) for mul, x in uu) + ")" for uu in u), k, n_trunc, r) if OA is None: - master_design = orthogonal_array(k+n_trunc,r,check=False) - matrix = [list(range(r))]*k + master_design = orthogonal_array(k + n_trunc, r, check=False) + matrix = [list(range(r))] * k for uu in u: uu = sum(x[1] for x in uu) - matrix.append(list(range(uu))+[None]*(r-uu)) - master_design = OA_relabel(master_design, k+n_trunc, r, matrix=matrix) + matrix.append(list(range(uu)) + [None] * (r - uu)) + master_design = OA_relabel(master_design, k + n_trunc, r, matrix=matrix) else: master_design = OA for c in u: - assert all(m_ij >= 0 and h_size >= 0 for m_ij,h_size in c) - assert sum(h_size for m_ij,h_size in c) <= r + assert all(m_ij >= 0 and h_size >= 0 for m_ij, h_size in c) + assert sum(h_size for m_ij, h_size in c) <= r # Associates a point ij from a truncated column k+i to # @@ -617,28 +610,27 @@ def wilson_construction(OA, k, r, m, u, check=True, explain_construction=False): # - its corresponding set of points in the final design. point_to_mij = [] point_to_point_set = [] - n = r*m - for i,partition in enumerate(u): + n = r * m + for i, partition in enumerate(u): column_i_point_to_mij = [] column_i_point_to_point_set = [] - for mij,h_size in partition: + for mij, h_size in partition: for _ in range(h_size): column_i_point_to_mij.append(mij) - column_i_point_to_point_set.append(list(range(n,n+mij))) + column_i_point_to_point_set.append(list(range(n, n + mij))) n += mij point_to_mij.append(column_i_point_to_mij) point_to_point_set.append(column_i_point_to_point_set) # the set of ij associated with each block - block_to_ij = lambda B: ((i,j) for i,j in enumerate(B[k:]) if j is not None) + block_to_ij = lambda B: ((i, j) for i, j in enumerate(B[k:]) if j is not None) # The different profiles (set of mij associated with each block) - block_profiles = set(tuple(point_to_mij[i][j] for i,j in block_to_ij(B)) for B in master_design) + block_profiles = set(tuple(point_to_mij[i][j] for i, j in block_to_ij(B)) for B in master_design) # For each block meeting multipliers m_ij(0),...,m_ij(s) we need a # OA(k,m+\sum m_{ij(i)})-\sum OA(k,\sum m_{ij(i)}) - OA_incomplete = {profile: incomplete_orthogonal_array(k, m+sum(profile), - profile) for profile in block_profiles} + OA_incomplete = {profile: incomplete_orthogonal_array(k, m + sum(profile), profile) for profile in block_profiles} # For each truncated column k+i partitionned into H_{i0},...,H_{ip_i} we # need a OA(k,\sum_j m_{ij} * |H_{ij}|) @@ -652,26 +644,24 @@ def wilson_construction(OA, k, r, m, u, check=True, explain_construction=False): # We replace the block of profile m_{ij(0)},...,m_{ij(s)} with a # OA(k,m+\sum_i m_ij(i)) properly relabelled - matrix = [list(range(i*m,(i+1)*m)) for i in B[:k]] + matrix = [list(range(i * m, (i + 1) * m)) for i in B[:k]] profile = [] - for i,j in block_to_ij(B): + for i, j in block_to_ij(B): profile.append(point_to_mij[i][j]) for C in matrix: C.extend(point_to_point_set[i][j]) - OA.extend(OA_relabel(OA_incomplete[tuple(profile)],k,m+sum(profile),matrix=matrix)) + OA.extend(OA_relabel(OA_incomplete[tuple(profile)], k, m + sum(profile), matrix=matrix)) # The missing OA(k,uu) for i in range(n_trunc): length = sum(point_to_mij[i]) - OA.extend(OA_relabel(OA_k_u[length], - k, - length, - matrix=[sum(point_to_point_set[i],[])]*k)) + OA.extend(OA_relabel(OA_k_u[length], k, length, matrix=[sum(point_to_point_set[i], [])] * k)) if check: from .designs_pyx import is_orthogonal_array - assert is_orthogonal_array(OA,k,n,2) + + assert is_orthogonal_array(OA, k, n, 2) return OA @@ -713,13 +703,13 @@ def TD_product(k, TD1, n1, TD2, n2, check=True): sage: TD2 = designs.transversal_design(6,12) sage: TD6_84 = TD_product(6,TD1,7,TD2,12) """ - N = n1*n2 + N = n1 * n2 TD = [] for X1 in TD1: for X2 in TD2: TD.append([x1 * n2 + (x2 % n2) for x1, x2 in zip(X1, X2)]) if check: - assert is_transversal_design(TD,k,N) + assert is_transversal_design(TD, k, N) return TD @@ -831,51 +821,51 @@ def orthogonal_array(k, n, t=2, resolvable=False, check=True, existence=False, e if resolvable: assert t == 2, "resolvable designs are only handled when t=2" if existence and k is not None: - return orthogonal_array(k+1,n,existence=True) + return orthogonal_array(k + 1, n, existence=True) if k is None: - k = orthogonal_array(None,n,existence=True)-1 + k = orthogonal_array(None, n, existence=True) - 1 if existence: return k - OA = sorted(orthogonal_array(k+1,n,check=check)) + OA = sorted(orthogonal_array(k + 1, n, check=check)) return [B[1:] for B in OA] # If k is set to None we find the largest value available if k is None: if existence: - return largest_available_k(n,t) + return largest_available_k(n, t) if n == 0 or n == 1: raise ValueError("there is no upper bound on k when 0<=n<=1") else: - k = largest_available_k(n,t) + k = largest_available_k(n, t) if k < t: raise ValueError("undefined for k= n+t: + elif k >= n + t: # When t=2 then k2 the submatrix defined by the rows whose first t-2 elements # are 0s yields a OA with t=2 and k-(t-2) columns. Thus k-(t-2) < n+2, # i.e. k= k and mu <= lmbda and (orthogonal_array(k,u,existence=True) is True) for (_,lmbda,mu,u),(kk,_) in QDM[n,1].items())): - _OA_cache_set(k,n,True) - - for (nn, lmbda, mu, u), (kk, f) in QDM[n,1].items(): - if (kk >= k and - mu <= lmbda and - (orthogonal_array(k,u,existence=True) is True)): + elif may_be_available and (n, 1) in QDM and any(kk >= k and mu <= lmbda and (orthogonal_array(k, u, existence=True) is True) for (_, lmbda, mu, u), (kk, _) in QDM[n, 1].items()): + _OA_cache_set(k, n, True) + + for (nn, lmbda, mu, u), (kk, f) in QDM[n, 1].items(): + if kk >= k and mu <= lmbda and (orthogonal_array(k, u, existence=True) is True): if existence: return True if explain_construction: - return "the database contains a ({},{};{},{};{})-quasi difference matrix".format(nn,k,lmbda,mu,u) - G,M = f() + return "the database contains a ({},{};{},{};{})-quasi difference matrix".format(nn, k, lmbda, mu, u) + G, M = f() M = [R[:k] for R in M] - OA = OA_from_quasi_difference_matrix(M,G,add_col=False) + OA = OA_from_quasi_difference_matrix(M, G, add_col=False) break # From Difference Matrices - elif may_be_available and difference_matrix(n,k-1,existence=True) is True: - _OA_cache_set(k,n,True) + elif may_be_available and difference_matrix(n, k - 1, existence=True) is True: + _OA_cache_set(k, n, True) if existence: return True if explain_construction: - return "from a ({},{})-difference matrix".format(n,k-1) - G,M = difference_matrix(n,k-1) - OA = OA_from_quasi_difference_matrix(M,G,add_col=True) + return "from a ({},{})-difference matrix".format(n, k - 1) + G, M = difference_matrix(n, k - 1) + OA = OA_from_quasi_difference_matrix(M, G, add_col=True) - elif may_be_available and find_recursive_construction(k,n): - _OA_cache_set(k,n,True) + elif may_be_available and find_recursive_construction(k, n): + _OA_cache_set(k, n, True) if existence: return True - f,args = find_recursive_construction(k,n) + f, args = find_recursive_construction(k, n) if explain_construction: - return f(*args,explain_construction=True) + return f(*args, explain_construction=True) OA = f(*args) else: - _OA_cache_set(k,n,Unknown) + _OA_cache_set(k, n, Unknown) if existence: return Unknown if explain_construction: return "No idea" - raise NotImplementedError("I don't know how to build an OA({},{})!".format(k,n)) + raise NotImplementedError("I don't know how to build an OA({},{})!".format(k, n)) if check: - assert is_orthogonal_array(OA,k,n,t,verbose=1), "Sage built an incorrect OA({},{}) O_o".format(k,n) + assert is_orthogonal_array(OA, k, n, t, verbose=1), "Sage built an incorrect OA({},{}) O_o".format(k, n) return OA @@ -1030,23 +1017,25 @@ def largest_available_k(n, t=2): ValueError: n(=-1) was expected to be >=0 """ from .block_design import projective_plane + if n < 0: raise ValueError("n(={}) was expected to be >=0".format(n)) if t < 0: raise ValueError("t(={}) was expected to be >=0".format(t)) if n == 0 or n == 1: from sage.rings.infinity import Infinity + return Infinity if t == 2: - if projective_plane(n,existence=True) is True: - return n+1 + if projective_plane(n, existence=True) is True: + return n + 1 k = 1 - while _OA_cache_construction_available(k+1,n) is True: - k = k+1 + while _OA_cache_construction_available(k + 1, n) is True: + k = k + 1 else: - k = t-1 + k = t - 1 - while orthogonal_array(k+1,n,t,existence=True) is True: + while orthogonal_array(k + 1, n, t, existence=True) is True: k += 1 return k @@ -1212,6 +1201,7 @@ def incomplete_orthogonal_array(k, n, holes, resolvable=False, existence=False): True """ from sage.combinat.designs.database import QDM + for h in holes: if h < 0: raise ValueError("Holes must have size >=0, but {} was in the list").format(h) @@ -1219,7 +1209,7 @@ def incomplete_orthogonal_array(k, n, holes, resolvable=False, existence=False): holes = [h for h in holes if h > 0] if not holes: - return orthogonal_array(k,n,existence=existence,resolvable=resolvable) + return orthogonal_array(k, n, existence=existence, resolvable=resolvable) sum_of_holes = sum(holes) number_of_holes = len(holes) @@ -1231,9 +1221,7 @@ def incomplete_orthogonal_array(k, n, holes, resolvable=False, existence=False): return False raise EmptySetError("The total size of holes must be smaller or equal than the size of the ground set") - if (max_hole == 1 and - resolvable and - sum_of_holes != n): + if max_hole == 1 and resolvable and sum_of_holes != n: if existence: return False raise EmptySetError("There is no resolvable incomplete OA({},{}) whose holes' sizes sum to {} equivalent to OA(k+1,n) if max_hole == 1 and resolvable: if existence: - return orthogonal_array(k+1,n,existence=True) + return orthogonal_array(k + 1, n, existence=True) - OA = sorted(orthogonal_array(k+1,n)) + OA = sorted(orthogonal_array(k + 1, n)) OA = [B[1:] for B in OA] # We now relabel the points so that the last n blocks are the [i,i,...] - relabel = [[0]*n for _ in range(k)] - for i,B in enumerate(OA[-n:]): - for ii,xx in enumerate(B): + relabel = [[0] * n for _ in range(k)] + for i, B in enumerate(OA[-n:]): + for ii, xx in enumerate(B): relabel[ii][xx] = i - OA = [[relabel[i][xx] for i,xx in enumerate(B)] for B in OA] + OA = [[relabel[i][xx] for i, xx in enumerate(B)] for B in OA] # Let's drop the last blocks - assert all(OA[-n+i] == [i]*k for i in range(n)), "The last n blocks should be [i,i,...]" + assert all(OA[-n + i] == [i] * k for i in range(n)), "The last n blocks should be [i,i,...]" return OA[:-n] # Easy case if max_hole == 1 and number_of_holes <= 1: if existence: - return orthogonal_array(k,n,existence=True) - OA = orthogonal_array(k,n) + return orthogonal_array(k, n, existence=True) + OA = orthogonal_array(k, n) independent_set = OA[:number_of_holes] # This is lemma 2.3 from [BvR1982]_ # # If k>3 and n>(k-1)u and there exists an OA(k,n)-OA(k,u), then there exists # an OA(k,n)-OA(k,u)-2.OA(k,1) - elif (k >= 3 and - 2 <= number_of_holes <= 3 and - n > (k-1)*max_hole and - holes.count(1) == number_of_holes-1 and - incomplete_orthogonal_array(k,n,[max_hole],existence=True)): + elif k >= 3 and 2 <= number_of_holes <= 3 and n > (k - 1) * max_hole and holes.count(1) == number_of_holes - 1 and incomplete_orthogonal_array(k, n, [max_hole], existence=True): if existence: return True @@ -1282,16 +1266,16 @@ def incomplete_orthogonal_array(k, n, holes, resolvable=False, existence=False): # # This code is a bit awkward for max_hole may be equal to 1, and the # holes have to be correctly ordered in the output. - IOA = incomplete_orthogonal_array(k,n,[max_hole]) + IOA = incomplete_orthogonal_array(k, n, [max_hole]) # place the big hole where it belongs i = holes.index(max_hole) - holes[i] = [[ii]*k for ii in range(n-max_hole,n)] + holes[i] = [[ii] * k for ii in range(n - max_hole, n)] # place the first hole of size 1 i = holes.index(1) for h1 in IOA: - if all(x < n-max_hole for x in h1): + if all(x < n - max_hole for x in h1): break holes[i] = [h1] IOA.remove(h1) @@ -1300,7 +1284,7 @@ def incomplete_orthogonal_array(k, n, holes, resolvable=False, existence=False): if number_of_holes == 3: i = holes.index(1) for h2 in IOA: - if all(h1[j] != x and x < n-max_hole for j,x in enumerate(h2)): + if all(h1[j] != x and x < n - max_hole for j, x in enumerate(h2)): break holes[i] = [h2] IOA.remove(h2) @@ -1312,90 +1296,80 @@ def incomplete_orthogonal_array(k, n, holes, resolvable=False, existence=False): for l in holes: for i in range(n): if i not in l: - l.insert(0,i) + l.insert(0, i) for i in range(len(holes)): - holes[i] = {v:i for i,v in enumerate(holes[i])} + holes[i] = {v: i for i, v in enumerate(holes[i])} - IOA = OA_relabel(IOA,k,n,matrix=holes) + IOA = OA_relabel(IOA, k, n, matrix=holes) return IOA - elif max_hole == 1 and number_of_holes >= 2 and k == n+1: + elif max_hole == 1 and number_of_holes >= 2 and k == n + 1: if existence: return False - raise EmptySetError(("There is no OA(n+1,n) - {}.OA(n+1,1) as all blocks " - "intersect in a projective plane.").format(number_of_holes)) + raise EmptySetError(("There is no OA(n+1,n) - {}.OA(n+1,1) as all blocks " "intersect in a projective plane.").format(number_of_holes)) # Holes of size 1 from OA(k+1,n) - elif max_hole == 1 and orthogonal_array(k+1,n,existence=True) is True: + elif max_hole == 1 and orthogonal_array(k + 1, n, existence=True) is True: if existence: return True - OA = orthogonal_array(k+1,n) + OA = orthogonal_array(k + 1, n) independent_set = [B[:-1] for B in OA if B[-1] == 0][:number_of_holes] OA = [B[:-1] for B in OA] - elif max_hole == 1 and orthogonal_array(k,n,existence=True) is True: - OA = orthogonal_array(k,n) + elif max_hole == 1 and orthogonal_array(k, n, existence=True) is True: + OA = orthogonal_array(k, n) try: - independent_set = OA_find_disjoint_blocks(OA,k,n,number_of_holes) + independent_set = OA_find_disjoint_blocks(OA, k, n, number_of_holes) except ValueError: if existence: return Unknown - raise NotImplementedError("I was not able to build this OA({},{})-{}.OA({},1)".format(k,n,number_of_holes,k)) + raise NotImplementedError("I was not able to build this OA({},{})-{}.OA({},1)".format(k, n, number_of_holes, k)) if existence: return True - independent_set = OA_find_disjoint_blocks(OA,k,n,number_of_holes) + independent_set = OA_find_disjoint_blocks(OA, k, n, number_of_holes) - elif max_hole == 1 and orthogonal_array(k,n,existence=True) is not True: - return orthogonal_array(k,n,existence=existence) + elif max_hole == 1 and orthogonal_array(k, n, existence=True) is not True: + return orthogonal_array(k, n, existence=existence) # From a quasi-difference matrix - elif (number_of_holes == 1 and - any(uu == sum_of_holes and mu <= 1 and lmbda == 1 and k <= kk + 1 - for (nn,lmbda,mu,uu),(kk,_) in QDM.get((n,1),{}).items())): - for (nn,lmbda,mu,uu),(kk,f) in QDM[n,1].items(): + elif number_of_holes == 1 and any(uu == sum_of_holes and mu <= 1 and lmbda == 1 and k <= kk + 1 for (nn, lmbda, mu, uu), (kk, _) in QDM.get((n, 1), {}).items()): + for (nn, lmbda, mu, uu), (kk, f) in QDM[n, 1].items(): if uu == sum_of_holes and mu <= 1 and lmbda == 1 and k <= kk + 1: break - G,M = f() - OA = OA_from_quasi_difference_matrix(M,G,fill_hole=False) + G, M = f() + OA = OA_from_quasi_difference_matrix(M, G, fill_hole=False) return [B[:k] for B in OA] # Equal holes [h,h,...] with h>1 through OA product construction # # (i.e. OA(k,n1)-x.OA(k,1) and OA(k,n2) ==> OA(k,n1.n2)-x.OA(k,n2) ) - elif (min_hole > 1 and - max_hole == min_hole and - n % min_hole == 0 and # h divides n - orthogonal_array(k,min_hole,existence=True) and # OA(k,h) - incomplete_orthogonal_array(k,n//min_hole,[1]*number_of_holes,existence=True)): # OA(k,n/h)-x.OA(k,1) + elif min_hole > 1 and max_hole == min_hole and n % min_hole == 0 and orthogonal_array(k, min_hole, existence=True) and incomplete_orthogonal_array(k, n // min_hole, [1] * number_of_holes, existence=True): # h divides n # OA(k,h) # OA(k,n/h)-x.OA(k,1) if existence: return True h = min_hole - iOA1 = incomplete_orthogonal_array(k,n//holes[0],[1]*number_of_holes) - iOA2 = orthogonal_array(k,h) + iOA1 = incomplete_orthogonal_array(k, n // holes[0], [1] * number_of_holes) + iOA2 = orthogonal_array(k, h) - return [[B1[i]*h+B2[i] for i in range(k)] - for B1 in iOA1 - for B2 in iOA2] + return [[B1[i] * h + B2[i] for i in range(k)] for B1 in iOA1 for B2 in iOA2] else: if existence: return Unknown # format the list of holes f = lambda x: "" if x == 1 else "{}.".format(x) - holes_string = "".join("-{}OA({},{})".format(f(holes.count(x)),k,x) for x in sorted(set(holes))) - raise NotImplementedError("I was not able to build this OA({},{}){}".format(k,n,holes_string)) + holes_string = "".join("-{}OA({},{})".format(f(holes.count(x)), k, x) for x in sorted(set(holes))) + raise NotImplementedError("I was not able to build this OA({},{}){}".format(k, n, holes_string)) assert number_of_holes == len(independent_set) for B in independent_set: OA.remove(B) - OA = OA_relabel(OA,k,n,blocks=independent_set) + OA = OA_relabel(OA, k, n, blocks=independent_set) return OA -def OA_find_disjoint_blocks(OA, k, n, x, - *, solver=None, integrality_tolerance=1e-3): +def OA_find_disjoint_blocks(OA, k, n, x, *, solver=None, integrality_tolerance=1e-3): r""" Return `x` disjoint blocks contained in a given `OA(k,n)`. @@ -1439,14 +1413,15 @@ def OA_find_disjoint_blocks(OA, k, n, x, """ # Computing an independent set of order x with a Linear Program from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException + p = MixedIntegerLinearProgram(solver=solver) b = p.new_variable(binary=True) p.add_constraint(p.sum(b[i] for i in range(len(OA))) == x) # t[i][j] lists of blocks of the OA whose i'th component is j t = [[[] for _ in range(n)] for _ in range(k)] - for c,B in enumerate(OA): - for i,j in enumerate(B): + for c, B in enumerate(OA): + for i, j in enumerate(B): t[i][j].append(c) for R in t: @@ -1456,10 +1431,10 @@ def OA_find_disjoint_blocks(OA, k, n, x, try: p.solve() except MIPSolverException: - raise ValueError("There does not exist {} disjoint blocks in this OA({},{})".format(x,k,n)) + raise ValueError("There does not exist {} disjoint blocks in this OA({},{})".format(x, k, n)) b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - independent_set = [OA[i] for i,v in b.items() if v] + independent_set = [OA[i] for i, v in b.items() if v] return independent_set @@ -1540,12 +1515,12 @@ def OA_relabel(OA, k, n, blocks=tuple(), matrix=None, symbol_list=None): if len(B) != len(set(B)): raise RuntimeError("Two block have the same coordinate for one of the k dimensions") - l.append(dict(zip([xx for xx in range(n) if xx not in B] + list(B),range(n)))) + l.append(dict(zip([xx for xx in range(n) if xx not in B] + list(B), range(n)))) - OA = [[l[i][x] for i,x in enumerate(R)] for R in OA] + OA = [[l[i][x] for i, x in enumerate(R)] for R in OA] if matrix: - OA = [[matrix[i][j] if j is not None else None for i,j in enumerate(R)] for R in OA] + OA = [[matrix[i][j] if j is not None else None for i, j in enumerate(R)] for R in OA] if symbol_list: mapping = dict(enumerate(symbol_list)) @@ -1682,36 +1657,35 @@ def OA_n_times_2_pow_c_from_matrix(k, c, G, A, Y, check=True): G_card = G.cardinality() - if len(A) != k-1 or any(len(a) != 2*G_card for a in A): + if len(A) != k - 1 or any(len(a) != 2 * G_card for a in A): raise ValueError("A must be a (k-1) x (2|G|) array") - if len(Y) != k-1: + if len(Y) != k - 1: raise ValueError("Y must be a (k-1)-vector") - F = FiniteField(2**c,'w') + F = FiniteField(2**c, 'w') GG = G.cartesian_product(F) # dictionary from integers to elements of GF(2^c): i -> w^i, None -> 0 w = F.multiplicative_generator() - r = {i:w**i for i in range(2**c-1)} + r = {i: w**i for i in range(2**c - 1)} r[None] = F.zero() # check that the first part of the matrix A is a (G,k-1,2)-difference matrix - B = [[G(a) for a,b in R] for R in A] - if check and not is_difference_matrix(list(zip(*B)),G,k-1,2): - raise ValueError("the first part of the matrix A must be a " - "(G,k-1,2)-difference matrix") + B = [[G(a) for a, b in R] for R in A] + if check and not is_difference_matrix(list(zip(*B)), G, k - 1, 2): + raise ValueError("the first part of the matrix A must be a " "(G,k-1,2)-difference matrix") # convert: # the matrix A to a matrix over G \times GF(2^c) # the vector Y to a vector over GF(2^c) - A = [[GG((G(a),r[b])) for a,b in R] for R in A] + A = [[GG((G(a), r[b])) for a, b in R] for R in A] Y = [r[b] for b in Y] # make the list of the elements of GF(2^c) which belong to the # GF(2)-subspace (that is the GF(2)-hyperplane orthogonal # to w^(c-1)) - H = [sum((r[i] for i in S), F.zero()) for s in range(c) for S in combinations(range(c-1),s)] - assert len(H) == 2**(c-1) + H = [sum((r[i] for i in S), F.zero()) for s in range(c) for S in combinations(range(c - 1), s)] + assert len(H) == 2 ** (c - 1) # check that the second part of the matrix A satisfy the conditions if check: @@ -1728,13 +1702,11 @@ def OA_n_times_2_pow_c_from_matrix(k, c, G, A, Y, check=True): v2 = A[i][s2][1] - A[j][s2][1] if (v1 in Hij) == (v2 in Hij): - raise ValueError("B_{},{} - B_{},{} = B_{},{} - B_{},{} but" - " the associated part of the matrix C does not satisfies" - " the required condition".format(i,s1,j,s1,i,s2,j,s2)) + raise ValueError("B_{},{} - B_{},{} = B_{},{} - B_{},{} but" " the associated part of the matrix C does not satisfies" " the required condition".format(i, s1, j, s1, i, s2, j, s2)) # build the quasi difference matrix and return the associated OA - Mb = [[e+GG((G.zero(),x*v)) for v in H for e in R] for x, R in zip(Y, A)] - return OA_from_quasi_difference_matrix(list(zip(*Mb)),GG,add_col=True) + Mb = [[e + GG((G.zero(), x * v)) for v in H for e in R] for x, R in zip(Y, A)] + return OA_from_quasi_difference_matrix(list(zip(*Mb)), GG, add_col=True) def OA_from_quasi_difference_matrix(M, G, add_col=True, fill_hole=True): @@ -1816,9 +1788,9 @@ def OA_from_quasi_difference_matrix(M, G, add_col=True, fill_hole=True): sage: _ = designs.orthogonal_arrays.build(6,20) # indirect doctest """ Gn = int(G.cardinality()) - k = len(M[0])+bool(add_col) + k = len(M[0]) + bool(add_col) - G_to_int = {x:i for i,x in enumerate(G)} + G_to_int = {x: i for i, x in enumerate(G)} # A cache for addition in G G_sum = [[0] * Gn for _ in range(Gn)] @@ -1837,22 +1809,22 @@ def OA_from_quasi_difference_matrix(M, G, add_col=True, fill_hole=True): new_line = [] for x in line: if x is None: - new_line.extend([inf]*Gn) + new_line.extend([inf] * Gn) inf = inf + 1 else: new_line.extend(G_sum[x]) new_M.append(new_line) if add_col: - new_M.append([i//Gn for i in range(len(new_line))]) + new_M.append([i // Gn for i in range(len(new_line))]) # new_M = transpose(new_M) new_M = list(zip(*new_M)) # Filling holes with a smaller orthogonal array if inf > Gn and fill_hole: - for L in orthogonal_array(k,inf-Gn,2): - new_M.append(tuple([x+Gn for x in L])) + for L in orthogonal_array(k, inf - Gn, 2): + new_M.append(tuple([x + Gn for x in L])) return new_M @@ -1877,8 +1849,8 @@ def OA_from_Vmt(m, t, V): sage: _ = designs.orthogonal_arrays.build(6,46) # indirect doctest """ - Fq, M = QDM_from_Vmt(m,t,V) - return OA_from_quasi_difference_matrix(M,Fq,add_col=False) + Fq, M = QDM_from_Vmt(m, t, V) + return OA_from_quasi_difference_matrix(M, Fq, add_col=False) def QDM_from_Vmt(m, t, V): @@ -1927,7 +1899,8 @@ def QDM_from_Vmt(m, t, V): sage: _ = designs.orthogonal_arrays.build(6,46) # indirect doctest """ from sage.rings.finite_rings.finite_field_constructor import FiniteField - q = m*t+1 + + q = m * t + 1 Fq = FiniteField(q, 'x') w = Fq.multiplicative_generator() @@ -1936,11 +1909,11 @@ def QDM_from_Vmt(m, t, V): for i in range(t): L = [None] for e in V: - L.append(e*wm**i) - for ii in range(m+2): - M.append(L[-ii:]+L[:-ii]) # cyclic shift + L.append(e * wm**i) + for ii in range(m + 2): + M.append(L[-ii:] + L[:-ii]) # cyclic shift - M.append([0]*(m+2)) + M.append([0] * (m + 2)) return Fq, M @@ -2001,15 +1974,16 @@ def OA_from_PBD(k, n, PBD, check=True): RuntimeError: PBD is not a valid Pairwise Balanced Design on [0,...,5] """ # Size of the sets of the PBD - K = set(map(len,PBD)) + K = set(map(len, PBD)) if check: from .designs_pyx import is_pairwise_balanced_design + if not is_pairwise_balanced_design(PBD, n, K): - raise RuntimeError("PBD is not a valid Pairwise Balanced Design on [0,...,{}]".format(n-1)) + raise RuntimeError("PBD is not a valid Pairwise Balanced Design on [0,...,{}]".format(n - 1)) # Building the IOA - OAs = {i:incomplete_orthogonal_array(k,i,(1,)*i) for i in K} + OAs = {i: incomplete_orthogonal_array(k, i, (1,) * i) for i in K} OA = [] # For every block B of the PBD we add to the OA rows covering all pairs of @@ -2020,10 +1994,10 @@ def OA_from_PBD(k, n, PBD, check=True): # Adding the 0..0, 1..1, 2..2 .... rows for i in range(n): - OA.append([i]*k) + OA.append([i] * k) if check: - assert is_orthogonal_array(OA,k,n,2) + assert is_orthogonal_array(OA, k, n, 2) return OA @@ -2113,6 +2087,7 @@ class OAMainFunctions: ... NotImplementedError: I don't know how to build an OA(12,20)! """ + def __init__(self, *args, **kwds): r""" There is nothing here. @@ -2144,7 +2119,7 @@ def explain_construction(k, n, t=2): sage: designs.orthogonal_arrays.explain_construction(10,154) 'the database contains a (137,10;1,0;17)-quasi difference matrix' """ - return orthogonal_array(k,n,t,explain_construction=True) + return orthogonal_array(k, n, t, explain_construction=True) @staticmethod def build(k, n, t=2, resolvable=False): @@ -2185,7 +2160,7 @@ def build(k, n, t=2, resolvable=False): [2, 2, 0]] sage: OA_7_50 = designs.orthogonal_arrays.build(7,50) # indirect doctest """ - return orthogonal_array(k,n,t,resolvable=resolvable) + return orthogonal_array(k, n, t, resolvable=resolvable) @staticmethod def exists(k, n, t=2): @@ -2214,7 +2189,7 @@ def exists(k, n, t=2): sage: designs.orthogonal_arrays.exists(7,6) # indirect doctest False """ - return orthogonal_array(k,n,t,existence=True) + return orthogonal_array(k, n, t, existence=True) @staticmethod def is_available(k, n, t=2): @@ -2236,4 +2211,4 @@ def is_available(k, n, t=2): sage: designs.orthogonal_arrays.is_available(4,6) # indirect doctest False """ - return orthogonal_array(k,n,t,existence=True) is True + return orthogonal_array(k, n, t, existence=True) is True diff --git a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py index 2bdbcae6bb7..c3f4c5a1a86 100644 --- a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py +++ b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py @@ -76,24 +76,21 @@ def construction_3_3(k, n, m, i, explain_construction=False): Journal of Combinatorial Designs, 2007 """ from .orthogonal_arrays import wilson_construction, OA_relabel, incomplete_orthogonal_array + if explain_construction: - return (("Construction 3.3 with n={},m={},i={} from:\n" - " Julian R. Abel, Nicholas Cavenagh\n" + - " Concerning eight mutually orthogonal latin squares,\n" + - " Vol. 15, n.3, pp. 255-261,\n" + - " Journal of Combinatorial Designs, 2007").format(n,m,i)) + return ("Construction 3.3 with n={},m={},i={} from:\n" " Julian R. Abel, Nicholas Cavenagh\n" + " Concerning eight mutually orthogonal latin squares,\n" + " Vol. 15, n.3, pp. 255-261,\n" + " Journal of Combinatorial Designs, 2007").format(n, m, i) # Builds an OA(k+i,n) containing a block [0]*(k+i) - OA = incomplete_orthogonal_array(k+i,n,(1,)) - OA = [[(x+1) % n for x in B] for B in OA] + OA = incomplete_orthogonal_array(k + i, n, (1,)) + OA = [[(x + 1) % n for x in B] for B in OA] # Truncated version - OA = [B[:k]+[0 if x == 0 else None for x in B[k:]] for B in OA] + OA = [B[:k] + [0 if x == 0 else None for x in B[k:]] for B in OA] - OA = wilson_construction(OA,k,n,m,[1]*i,check=False)[:-i] - matrix = [list(range(m)) + list(range(n*m, n*m+i))] * k - OA.extend(OA_relabel(orthogonal_array(k,m+i),k,m+i,matrix=matrix)) - assert is_orthogonal_array(OA,k,n*m+i) + OA = wilson_construction(OA, k, n, m, [1] * i, check=False)[:-i] + matrix = [list(range(m)) + list(range(n * m, n * m + i))] * k + OA.extend(OA_relabel(orthogonal_array(k, m + i), k, m + i, matrix=matrix)) + assert is_orthogonal_array(OA, k, n * m + i) return OA @@ -148,35 +145,32 @@ def construction_3_4(k, n, m, r, s, explain_construction=False): Journal of Combinatorial Designs, 2007 """ if explain_construction: - return ("Construction 3.4 with n={},m={},r={},s={} from:\n" + - " Julian R. Abel, Nicholas Cavenagh\n" + - " Concerning eight mutually orthogonal latin squares,\n" + - " Vol. 15, n.3, pp. 255-261,\n" + - " Journal of Combinatorial Designs, 2007").format(n,m,r,s) + return ("Construction 3.4 with n={},m={},r={},s={} from:\n" + " Julian R. Abel, Nicholas Cavenagh\n" + " Concerning eight mutually orthogonal latin squares,\n" + " Vol. 15, n.3, pp. 255-261,\n" + " Journal of Combinatorial Designs, 2007").format(n, m, r, s) from .orthogonal_arrays import wilson_construction, OA_relabel + assert s < n - master_design = orthogonal_array(k+r+1,n) + master_design = orthogonal_array(k + r + 1, n) # Defines the first k+r columns of the matrix of labels - matrix = [list(range(n))] * k + [[None]*n]*(r) + [[None]*n] + matrix = [list(range(n))] * k + [[None] * n] * (r) + [[None] * n] B0 = master_design[0] - for i in range(k,k+r): + for i in range(k, k + r): matrix[i][B0[i]] = 0 # Last column - if orthogonal_array(k, m+r ,existence=True): - last_group = [x for x in range(s+1) if x != B0[-1]][:s] - elif orthogonal_array(k,m+r+1,existence=True): - last_group = [x for x in range(s+1) if x != B0[-1]][:s-1] + [B0[-1]] + if orthogonal_array(k, m + r, existence=True): + last_group = [x for x in range(s + 1) if x != B0[-1]][:s] + elif orthogonal_array(k, m + r + 1, existence=True): + last_group = [x for x in range(s + 1) if x != B0[-1]][: s - 1] + [B0[-1]] else: raise RuntimeError for i, x in enumerate(last_group): matrix[-1][x] = i - OA = OA_relabel(master_design,k+r+1,n, matrix=matrix) - OA = wilson_construction(OA,k,n,m,[1]*r+[s],check=False) + OA = OA_relabel(master_design, k + r + 1, n, matrix=matrix) + OA = wilson_construction(OA, k, n, m, [1] * r + [s], check=False) return OA @@ -224,25 +218,22 @@ def construction_3_5(k, n, m, r, s, t, explain_construction=False): Journal of Combinatorial Designs, 2007 """ from .orthogonal_arrays import wilson_construction, OA_relabel + assert r <= s q = n - assert (q-r-1)*(q-s) >= (q-s-1)*(q-r) + assert (q - r - 1) * (q - s) >= (q - s - 1) * (q - r) if explain_construction: - return (("Construction 3.5 with n={},m={},r={},s={},t={} from:\n" - " Julian R. Abel, Nicholas Cavenagh\n" + - " Concerning eight mutually orthogonal latin squares,\n" + - " Vol. 15, n.3, pp. 255-261,\n" + - " Journal of Combinatorial Designs, 2007").format(n,m,r,s,t)) + return ("Construction 3.5 with n={},m={},r={},s={},t={} from:\n" " Julian R. Abel, Nicholas Cavenagh\n" + " Concerning eight mutually orthogonal latin squares,\n" + " Vol. 15, n.3, pp. 255-261,\n" + " Journal of Combinatorial Designs, 2007").format(n, m, r, s, t) - master_design = orthogonal_array(k+3,q) + master_design = orthogonal_array(k + 3, q) # group k+1 has cardinality r # group k+2 has cardinality s # group k+3 has cardinality t # Taking q-s blocks going through 0 in the last block - blocks_crossing_0 = [B[-3:] for B in master_design if B[-1] == 0][:q-s] + blocks_crossing_0 = [B[-3:] for B in master_design if B[-1] == 0][: q - s] # defining the undeleted points of the groups k+1,k+2 group_k_1 = [x[0] for x in blocks_crossing_0] @@ -260,9 +251,9 @@ def construction_3_5(k, n, m, r, s, t, explain_construction=False): group_k_3 = group_k_3[:t] # Relabelling the OA - r1 = [None]*q - r2 = [None]*q - r3 = [None]*q + r1 = [None] * q + r2 = [None] * q + r3 = [None] * q for i, x in enumerate(group_k_1): r1[x] = i for i, x in enumerate(group_k_2): @@ -270,8 +261,8 @@ def construction_3_5(k, n, m, r, s, t, explain_construction=False): for i, x in enumerate(group_k_3): r3[x] = i - OA = OA_relabel(master_design, k+3,q, matrix=[list(range(q))]*k+[r1,r2,r3]) - OA = wilson_construction(OA,k,q,m,[r,s,t], check=False) + OA = OA_relabel(master_design, k + 3, q, matrix=[list(range(q))] * k + [r1, r2, r3]) + OA = wilson_construction(OA, k, q, m, [r, s, t], check=False) return OA @@ -317,18 +308,15 @@ def construction_3_6(k, n, m, i, explain_construction=False): Journal of Combinatorial Designs, 2007 """ if explain_construction: - return (("Construction 3.6 with n={},m={},i={} from:\n" - " Julian R. Abel, Nicholas Cavenagh\n" + - " Concerning eight mutually orthogonal latin squares,\n" + - " Vol. 15, n.3, pp. 255-261,\n" + - " Journal of Combinatorial Designs, 2007").format(n,m,i)) + return ("Construction 3.6 with n={},m={},i={} from:\n" " Julian R. Abel, Nicholas Cavenagh\n" + " Concerning eight mutually orthogonal latin squares,\n" + " Vol. 15, n.3, pp. 255-261,\n" + " Journal of Combinatorial Designs, 2007").format(n, m, i) from .orthogonal_arrays import wilson_construction + OA = OA_and_oval(n) - OA = [B[:k+i] for B in OA] + OA = [B[: k + i] for B in OA] OA = [B[:k] + [x if x == 0 else None for x in B[k:]] for B in OA] - OA = wilson_construction(OA,k,n,m,[1]*i) - assert is_orthogonal_array(OA,k,n*m+i) + OA = wilson_construction(OA, k, n, m, [1] * i) + assert is_orthogonal_array(OA, k, n * m + i) return OA @@ -379,16 +367,17 @@ def OA_and_oval(q, *, solver=None, integrality_tolerance=1e-3): # We compute the oval with a linear program from sage.numerical.mip import MixedIntegerLinearProgram + p = MixedIntegerLinearProgram(solver=solver) b = p.new_variable(binary=True) V = B.ground_set() - p.add_constraint(p.sum([b[i] for i in V]) == q+1) + p.add_constraint(p.sum([b[i] for i in V]) == q + 1) for bl in B: p.add_constraint(p.sum([b[i] for i in bl]) <= 2) p.solve() b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - oval = [x for x,i in b.items() if i] - assert len(oval) == q+1 + oval = [x for x, i in b.items() if i] + assert len(oval) == q + 1 # We remove one element from the oval x = oval.pop() @@ -412,8 +401,8 @@ def OA_and_oval(q, *, solver=None, integrality_tolerance=1e-3): else: BB.append(b) - assert len(r) == (q+1)*q # all points except x have an image - assert len(set(r.values())) == len(r) # the images are different + assert len(r) == (q + 1) * q # all points except x have an image + assert len(set(r.values())) == len(r) # the images are different # Relabelling/sorting the blocks and the oval BB = [[r[xx] for xx in b] for b in BB] @@ -429,9 +418,9 @@ def OA_and_oval(q, *, solver=None, integrality_tolerance=1e-3): assert len(oval) == q # We relabel the "oval" as relabelled as [0,...,0] - OA = OA_relabel(BB+([[0]+oval]),q+1,q,blocks=[[0]+oval]) - OA = [[(x+1) % q for x in B] for B in OA] - OA.remove([0]*(q+1)) + OA = OA_relabel(BB + ([[0] + oval]), q + 1, q, blocks=[[0] + oval]) + OA = [[(x + 1) % q for x in B] for B in OA] + OA.remove([0] * (q + 1)) assert all(sum([xx == 0 for xx in b[1:]]) <= 2 for b in OA) return OA @@ -522,58 +511,54 @@ def construction_q_x(k, q, x, check=True, explain_construction=False): from sage.combinat.designs.orthogonal_arrays import incomplete_orthogonal_array if explain_construction: - return ("(q-x)-construction with q={},x={} from:\n" + - " Malcolm Greig,\n" + - " Designs from projective planes and PBD bases,\n" + - " vol. 7, num. 5, pp. 341--374,\n" + - " Journal of Combinatorial Designs, 1999").format(q, x) + return ("(q-x)-construction with q={},x={} from:\n" + " Malcolm Greig,\n" + " Designs from projective planes and PBD bases,\n" + " vol. 7, num. 5, pp. 341--374,\n" + " Journal of Combinatorial Designs, 1999").format(q, x) - n = (q-1)*(q-x)+x+2 + n = (q - 1) * (q - x) + x + 2 # We obtain the qxq matrix from a OA(q,q)-q.OA(1,q). We will need to add # blocks corresponding to the rows/columns - OA = incomplete_orthogonal_array(q,q,(1,)*q) - TD = [[i*q+xx for i, xx in enumerate(B)] for B in OA] + OA = incomplete_orthogonal_array(q, q, (1,) * q) + TD = [[i * q + xx for i, xx in enumerate(B)] for B in OA] # Add rows, extended with p1 and p2 p1 = q**2 p2 = p1 + 1 - TD.extend([ii*q + i for ii in range(q)] + [p1] for i in range(1, q)) - TD.append([ii*q for ii in range(q)] + [p1, p2]) + TD.extend([ii * q + i for ii in range(q)] + [p1] for i in range(1, q)) + TD.append([ii * q for ii in range(q)] + [p1, p2]) # Add Columns. We do not add some columns which would have size 1 after we # delete points. # # TD.extend([range(i*q,(i+1)*q) for i in range(x)]) - TD.extend(list(range(i*q,(i+1)*q))+[p2] for i in range(x,q)) + TD.extend(list(range(i * q, (i + 1) * q)) + [p2] for i in range(x, q)) - points_to_delete = set([i*q+j for i in range(x) for j in range(1,q)]+[i*q for i in range(x,q)]) - points_to_keep = set(range(q**2+2))-points_to_delete - relabel = {i:j for j,i in enumerate(points_to_keep)} + points_to_delete = set([i * q + j for i in range(x) for j in range(1, q)] + [i * q for i in range(x, q)]) + points_to_keep = set(range(q**2 + 2)) - points_to_delete + relabel = {i: j for j, i in enumerate(points_to_keep)} # PBD is a (n,[q,q-x-1,q-x+1,x+2])-PBD PBD = [[relabel[xx] for xx in B if xx not in points_to_delete] for B in TD] # Taking the unique block of size x+2 - assert list(map(len,PBD)).count(x+2) == 1 + assert list(map(len, PBD)).count(x + 2) == 1 for B in PBD: - if len(B) == x+2: + if len(B) == x + 2: break # We call OA_from_PBD without the block of size x+2 as there may not exist a # OA(k,x+2)-(x+2).OA(k,1) PBD.remove(B) - OA = OA_from_PBD(k,(q-1)*(q-x)+x+2,PBD,check=False) + OA = OA_from_PBD(k, (q - 1) * (q - x) + x + 2, PBD, check=False) # Filling the hole for xx in B: - OA.remove([xx]*k) + OA.remove([xx] * k) - for BB in orthogonal_array(k, x+2): + for BB in orthogonal_array(k, x + 2): OA.append([B[x] for x in BB]) if check: - assert is_orthogonal_array(OA,k,n,2) + assert is_orthogonal_array(OA, k, n, 2) return OA @@ -693,36 +678,33 @@ def thwart_lemma_3_5(k, n, m, a, b, c, d=0, complement=False, explain_constructi from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF if complement: - a,b,c = n-a,n-b,n-c + a, b, c = n - a, n - b, n - c if explain_construction: - return ("Lemma 3.5 with n={},m={},a={},b={},c={},d={} from:\n" + - " Charles J.Colbourn, Jeffrey H. Dinitz, Mieczyslaw Wojtas,\n" + - " Thwarts in transversal designs,\n" + - " Designs, Codes and Cryptography 5, no. 3 (1995): 189-197.").format(n,m,a,b,c,d) + return ("Lemma 3.5 with n={},m={},a={},b={},c={},d={} from:\n" + " Charles J.Colbourn, Jeffrey H. Dinitz, Mieczyslaw Wojtas,\n" + " Thwarts in transversal designs,\n" + " Designs, Codes and Cryptography 5, no. 3 (1995): 189-197.").format(n, m, a, b, c, d) assert is_prime_power(n), "n(={}) must be a prime power".format(n) - assert a <= n and b <= n and c <= n and d <= n, "a,b,c,d (={},{},{},{}) must be <=n(={})".format(a,b,c,d,n) - assert a+b+c <= n+1, "{}={}+{}+{}=a+b+c>n+1={}+1 violates the assumptions".format(a+b+c,a,b,c,n) - assert k+3+bool(d) <= n+1, "There exists no OA({},{}).".format(k+3+bool(d),n) - G = GF(n,prefix='x') - G_set = sorted(G) # sorted by lexicographic order, G[1] = 1 + assert a <= n and b <= n and c <= n and d <= n, "a,b,c,d (={},{},{},{}) must be <=n(={})".format(a, b, c, d, n) + assert a + b + c <= n + 1, "{}={}+{}+{}=a+b+c>n+1={}+1 violates the assumptions".format(a + b + c, a, b, c, n) + assert k + 3 + bool(d) <= n + 1, "There exists no OA({},{}).".format(k + 3 + bool(d), n) + G = GF(n, prefix='x') + G_set = sorted(G) # sorted by lexicographic order, G[1] = 1 assert G_set[0] == G.zero() and G_set[1] == G.one(), "problem with the ordering of {}".format(G) - G_to_int = {v:i for i,v in enumerate(G_set)} + G_to_int = {v: i for i, v in enumerate(G_set)} # Builds an OA(n+1,n) whose last n-1 columns are # # \forall x \in G and x!=0, C_x(i,j) = i+x*j # # (only the necessary columns are built) - OA = [[G_to_int[i+x*j] for i in G_set for j in G_set] for x in G_set[1:k+2+bool(d)]] + OA = [[G_to_int[i + x * j] for i in G_set for j in G_set] for x in G_set[1 : k + 2 + bool(d)]] # Adding the first two trivial columns - OA.insert(0,[j for i in range(n) for j in range(n)]) - OA.insert(0,[i for i in range(n) for j in range(n)]) + OA.insert(0, [j for i in range(n) for j in range(n)]) + OA.insert(0, [i for i in range(n) for j in range(n)]) OA = sorted(zip(*OA)) # Moves the first three columns to the end - OA = [list(B[3:]+B[:3]) for B in OA] + OA = [list(B[3:] + B[:3]) for B in OA] # Set of values in the axb square third_complement = set(B[-1] for B in OA if B[-3] < a and B[-2] < b) @@ -740,11 +722,11 @@ def thwart_lemma_3_5(k, n, m, a, b, c, d=0, complement=False, explain_constructi last_sets = [set(range(n)).difference(s) for s in last_sets] sizes = [len(_) for _ in last_sets] - last_sets_dict = [{v:i for i,v in enumerate(s)} for s in last_sets] + last_sets_dict = [{v: i for i, v in enumerate(s)} for s in last_sets] # Truncating the OA for i, D in enumerate(last_sets_dict): - kk = len(OA[0])-3+i + kk = len(OA[0]) - 3 + i for R in OA: R[kk] = D.get(R[kk], None) @@ -752,9 +734,9 @@ def thwart_lemma_3_5(k, n, m, a, b, c, d=0, complement=False, explain_constructi for R in OA: if R[-4] >= d: R[-4] = None - sizes.insert(0,d) + sizes.insert(0, d) - return wilson_construction(OA,k,n,m,sizes, check=False) + return wilson_construction(OA, k, n, m, sizes, check=False) def thwart_lemma_4_1(k, n, m, explain_construction=False): @@ -809,24 +791,20 @@ def thwart_lemma_4_1(k, n, m, explain_construction=False): from itertools import chain if explain_construction: - return ("Lemma 4.1 with n={},m={} from:\n" + - " Charles J.Colbourn, Jeffrey H. Dinitz, Mieczyslaw Wojtas,\n" + - " Thwarts in transversal designs,\n" + - " Designs, Codes and Cryptography 5, no. 3 (1995): 189-197.").format(n,m) + return ("Lemma 4.1 with n={},m={} from:\n" + " Charles J.Colbourn, Jeffrey H. Dinitz, Mieczyslaw Wojtas,\n" + " Thwarts in transversal designs,\n" + " Designs, Codes and Cryptography 5, no. 3 (1995): 189-197.").format(n, m) assert is_prime_power(n), "n(={}) must be a prime power" - assert k+4 <= n+1 + assert k + 4 <= n + 1 q = n K = FiniteField(q, 'x') relabel = {x: i for i, x in enumerate(K)} - PG = DesarguesianProjectivePlaneDesign(q, check=False, - point_coordinates=False).blocks() + PG = DesarguesianProjectivePlaneDesign(q, check=False, point_coordinates=False).blocks() if q % 3 == 0: t = K.one() elif q % 3 == 1: - t = K.multiplicative_generator()**((q - 1)//3) + t = K.multiplicative_generator() ** ((q - 1) // 3) else: raise ValueError("q(={}) must be congruent to 0 or 1 mod 3".format(q)) @@ -836,18 +814,18 @@ def thwart_lemma_4_1(k, n, m, explain_construction=False): # # - (1+t,t,1+t), (1,1,1), (1+t,t,t), (1,1,2), (0,0,1), (1,0,1), (0,1,1+t), # (0,1,1), (1,0,-t) - points = [(1+t,t,1+t), (1,1,1), (1+t,t,t), (1,1,2), (0,0,1), (1,0,1), (0,1,1+t), (0,1,1), (1,0,-t)] - points = [[K(c) for c in t] for t in points] # triples of K^3 + points = [(1 + t, t, 1 + t), (1, 1, 1), (1 + t, t, t), (1, 1, 2), (0, 0, 1), (1, 0, 1), (0, 1, 1 + t), (0, 1, 1), (1, 0, -t)] + points = [[K(c) for c in t] for t in points] # triples of K^3 AG_2_3 = [] - for x,y,z in points: + for x, y, z in points: if z != 0: x, y, z = x / z, y / z, K.one() - AG_2_3.append(relabel[x]+n*relabel[y]) + AG_2_3.append(relabel[x] + n * relabel[y]) elif y != 0: x, y = x / y, K.one() - AG_2_3.append(q**2+relabel[x]) + AG_2_3.append(q**2 + relabel[x]) else: - AG_2_3.append(q**2+q) + AG_2_3.append(q**2 + q) AG_2_3 = set(AG_2_3) @@ -868,22 +846,32 @@ def thwart_lemma_4_1(k, n, m, explain_construction=False): # The columns containing elements from the AG are the last ones, and those # elements should be the last two - columns.sort(key=lambda x:len(AG_2_3.intersection(x))) + columns.sort(key=lambda x: len(AG_2_3.intersection(x))) for i in range(4): - columns[-i-1].sort(key=lambda x: int(x in AG_2_3)) + columns[-i - 1].sort(key=lambda x: int(x in AG_2_3)) - relabel = {v:i for i,v in enumerate(chain(columns))} + relabel = {v: i for i, v in enumerate(chain(columns))} TD = [sorted(relabel[x] for x in B) for B in blocks] # We build the OA, removing unnecessary columns - OA = [[x % q for x in B[-k-4:]] for B in TD] + OA = [[x % q for x in B[-k - 4 :]] for B in TD] for B in OA: for i in range(4): - if B[k+i] >= n-2: - B[k+i] = None - - return wilson_construction(OA,k,n,m,[n-2,]*4,check=False) + if B[k + i] >= n - 2: + B[k + i] = None + + return wilson_construction( + OA, + k, + n, + m, + [ + n - 2, + ] + * 4, + check=False, + ) def three_factor_product(k, n1, n2, n3, check=False, explain_construction=False): @@ -1005,10 +993,7 @@ def three_factor_product(k, n1, n2, n3, check=False, explain_construction=False) assert n1 <= n2 <= n3 if explain_construction: - return ("Three-factor product with n={}.{}.{} from:\n" + - " Peter J. Dukes, Alan C.H. Ling,\n" + - " A three-factor product construction for mutually orthogonal latin squares,\n" + - " https://arxiv.org/abs/1401.1466").format(n1, n2, n3) + return ("Three-factor product with n={}.{}.{} from:\n" + " Peter J. Dukes, Alan C.H. Ling,\n" + " A three-factor product construction for mutually orthogonal latin squares,\n" + " https://arxiv.org/abs/1401.1466").format(n1, n2, n3) def assert_c_partition(classs, k, n, c): r""" @@ -1016,10 +1001,10 @@ def assert_c_partition(classs, k, n, c): ``B[i]`` covers `[n]` exactly `c` times for every index `i`. """ c = int(c) - assert all(len(B) == k for B in classs), "A block has length {}!=k(={})".format(len(B),k) - assert len(classs) == n*c, "not the right number of blocks" + assert all(len(B) == k for B in classs), "A block has length {}!=k(={})".format(len(B), k) + assert len(classs) == n * c, "not the right number of blocks" for p in zip(*classs): - assert all(x == i//c for i,x in enumerate(sorted(p))), "A class is not c(={})-parallel".format(c) + assert all(x == i // c for i, x in enumerate(sorted(p))), "A class is not c(={})-parallel".format(c) def product_with_parallel_classes(OA1, k, g1, g2, g1_parall, parall, check=True): r""" @@ -1047,9 +1032,9 @@ def product_with_parallel_classes(OA1, k, g1, g2, g1_parall, parall, check=True) """ if check: for classs in g1_parall: - assert_c_partition(classs,k,g2,g1) + assert_c_partition(classs, k, g2, g1) for classs in parall: - assert_c_partition(classs,k,g2,1) + assert_c_partition(classs, k, g2, 1) # New parallel classes, built from a g1-parallel class with shifted copies # of OA1 @@ -1058,22 +1043,22 @@ def product_with_parallel_classes(OA1, k, g1, g2, g1_parall, parall, check=True) for classs2 in g1_parall: # Keep track of how many times we saw each point of [k]x[g2] - count = [[0]*g2 for _ in range(k)] + count = [[0] * g2 for _ in range(k)] copies_of_OA1 = [] for B2 in classs2: copy_of_OA1 = [] - shift = [count[i][x2] for i,x2 in enumerate(B2)] + shift = [count[i][x2] for i, x2 in enumerate(B2)] assert max(shift) < g1 for B1 in OA1: - copy_of_OA1.append([x2*g1+(x1+sh) % g1 for sh,x1,x2 in zip(shift,B1,B2)]) + copy_of_OA1.append([x2 * g1 + (x1 + sh) % g1 for sh, x1, x2 in zip(shift, B1, B2)]) copies_of_OA1.append(copy_of_OA1) # Update the counts - for i,x2 in enumerate(B2): + for i, x2 in enumerate(B2): count[i][x2] += 1 new_parallel_classes.extend([list(_) for _ in zip(*copies_of_OA1)]) @@ -1086,7 +1071,7 @@ def product_with_parallel_classes(OA1, k, g1, g2, g1_parall, parall, check=True) disjoint_copies_of_OA1 = [] for B2 in classs2: for B1 in OA1: - disjoint_copies_of_OA1.append([x2*g1+x1 for x1,x2 in zip(B1,B2)]) + disjoint_copies_of_OA1.append([x2 * g1 + x1 for x1, x2 in zip(B1, B2)]) new_g1_parallel_classes.append(disjoint_copies_of_OA1) # Check our stuff before we return it @@ -1101,30 +1086,30 @@ def product_with_parallel_classes(OA1, k, g1, g2, g1_parall, parall, check=True) # The three factors product construction begins ! # # OA1 and resolvable OA2 and OA3 - OA1 = orthogonal_array(k,n1) - OA3 = sorted(orthogonal_array(k+1,n3)) + OA1 = orthogonal_array(k, n1) + OA3 = sorted(orthogonal_array(k + 1, n3)) OA3 = [B[1:] for B in OA3] - OA2 = orthogonal_array(k+1,n2) + OA2 = orthogonal_array(k + 1, n2) OA2.sort() OA2 = [B[1:] for B in OA2] # We split OA3 into as many n1-parallel classes as possible, i.e. n3//n1 classes of size n1*n3 - OA3_n1_parall = [OA3[i:i+n1*n3] for i in range(0,(n3-n1)*n3,n1*n3)] + OA3_n1_parall = [OA3[i : i + n1 * n3] for i in range(0, (n3 - n1) * n3, n1 * n3)] # Leftover blocks become parallel classes. We must split them into slices of # length n3 - OA3_parall = [OA3[i:i+n3] for i in range(len(OA3_n1_parall)*n1*n3, len(OA3), n3)] + OA3_parall = [OA3[i : i + n3] for i in range(len(OA3_n1_parall) * n1 * n3, len(OA3), n3)] # First product: OA1 and OA3 - n1_parall, parall = product_with_parallel_classes(OA1,k,n1,n3,OA3_n1_parall,OA3_parall,check=check) + n1_parall, parall = product_with_parallel_classes(OA1, k, n1, n3, OA3_n1_parall, OA3_parall, check=check) if check: - OA_13 = [block for classs in parall+n1_parall for block in classs] - assert is_orthogonal_array(OA_13,k,n1*n3,2,1) + OA_13 = [block for classs in parall + n1_parall for block in classs] + assert is_orthogonal_array(OA_13, k, n1 * n3, 2, 1) # Add parallel classes to turn the n1-parall classes into n2-parallel classes for classs in n1_parall: - for i in range(n2-n1): + for i in range(n2 - n1): classs.extend(parall.pop()) n2_parall = n1_parall @@ -1132,22 +1117,22 @@ def product_with_parallel_classes(OA1, k, g1, g2, g1_parall, parall, check=True) # We compute the product of OA2 with our decomposition of OA1xOA2 into # n2-parallel classes and parallel classes - n2_parall, parall = product_with_parallel_classes(OA2,k,n2,n1*n3,n2_parall,parall,check=check) + n2_parall, parall = product_with_parallel_classes(OA2, k, n2, n1 * n3, n2_parall, parall, check=check) for n2_classs in n2_parall: for i in range(n2): - partition = [B for j in range(n1*n3) for B in n2_classs[j*n2**2+i*n2:j*n2**2+(i+1)*n2]] + partition = [B for j in range(n1 * n3) for B in n2_classs[j * n2**2 + i * n2 : j * n2**2 + (i + 1) * n2]] parall.append(partition) # That's what we fought for: this design is resolvable, so let's add a last # column to them - for i,classs in enumerate(parall): + for i, classs in enumerate(parall): for B in classs: B.append(i) OA = [block for classs in parall for block in classs] if check: - assert is_orthogonal_array(OA,k+1,n1*n2*n3,2,1) + assert is_orthogonal_array(OA, k + 1, n1 * n2 * n3, 2, 1) return OA @@ -1188,15 +1173,15 @@ def _reorder_matrix(matrix): k = len(matrix[0]) g = Graph() - g.add_edges((x,N+i) for i,S in enumerate(matrix) for x in S) + g.add_edges((x, N + i) for i, S in enumerate(matrix) for x in S) matrix = [] for _ in range(k): matching = g.matching(algorithm='LP') - col = [0]*N - for x,i,_ in matching: + col = [0] * N + for x, i, _ in matching: if i < N: - x,i = i,x - col[i-N] = x + x, i = i, x + col[i - N] = x matrix.append(col) g.delete_edges(matching) @@ -1396,31 +1381,27 @@ def brouwer_separable_design(k, t, q, x, check=False, verbose=False, explain_con from sage.arith.misc import is_prime_power if explain_construction: - return ("Brouwer's separable design construction with t={},q={},x={} from:\n" + - " Andries E. Brouwer,\n" + - " A series of separable designs with application to pairwise orthogonal Latin squares\n" + - " Vol. 1, n. 1, pp. 39-41,\n" + - " European Journal of Combinatorics, 1980").format(t,q,x) + return ("Brouwer's separable design construction with t={},q={},x={} from:\n" + " Andries E. Brouwer,\n" + " A series of separable designs with application to pairwise orthogonal Latin squares\n" + " Vol. 1, n. 1, pp. 39-41,\n" + " European Journal of Combinatorics, 1980").format(t, q, x) ########################################################### # Part 1: compute the separable PBD on t(q^2+q+1) points. # ########################################################### - assert t < q**2-q+1 + assert t < q**2 - q + 1 assert x >= 0 assert is_prime_power(q) - N2 = q**4+q**2+1 + N2 = q**4 + q**2 + 1 N1 = q**2 + q + 1 # A projective plane on (q^2-q+1)*(q^2+q+1)=q^4+q^2+1 points - B = difference_family(N2,q**2+1,1)[1][0] - BIBD = [[(xx+i) % N2 for xx in B] for i in range(N2)] + B = difference_family(N2, q**2 + 1, 1)[1][0] + BIBD = [[(xx + i) % N2 for xx in B] for i in range(N2)] # Each congruence class mod q^2-q+1 yields a Baer subplane. Let's check that: - m = q**2-q+1 + m = q**2 - q + 1 for i in range(m): for B in BIBD: - assert sum((xx % m) == i for xx in B) in [1,q+1], sum((xx % m) == i for xx in B) + assert sum((xx % m) == i for xx in B) in [1, q + 1], sum((xx % m) == i for xx in B) # We are only interested by the points of the first t Baer subplanes (each # has size q**2+q+1). Note that each block of the projective plane: @@ -1440,7 +1421,7 @@ def brouwer_separable_design(k, t, q, x, check=False, verbose=False, explain_con blocks_of_size_q_plus_t = [] partition_of_blocks_of_size_t = [[] for _ in repeat(None, m - t)] - relabel = {i+j*m: N1*i+j for i in range(t) for j in range(N1)} + relabel = {i + j * m: N1 * i + j for i in range(t) for j in range(N1)} for B in BIBD: # Find the Baer subplane which B intersects on more than 1 point @@ -1451,7 +1432,7 @@ def brouwer_separable_design(k, t, q, x, check=False, verbose=False, explain_con if plane < t: blocks_of_size_q_plus_t.append([relabel[xx] for xx in B if xx % m < t]) else: - partition_of_blocks_of_size_t[plane-t].append([relabel[xx] for xx in B if xx % m < t]) + partition_of_blocks_of_size_t[plane - t].append([relabel[xx] for xx in B if xx % m < t]) ########################################################################### # Separable design built ! @@ -1472,11 +1453,11 @@ def brouwer_separable_design(k, t, q, x, check=False, verbose=False, explain_con # Part 2: Build an OA on t(q^2+q+1)+x points # ############################################## - e1 = int(x != q**2-q-t) + e1 = int(x != q**2 - q - t) e2 = int(x != 1) e3 = int(x != q**2) - e4 = int(x != t+q+1) - N = t*N1+x + e4 = int(x != t + q + 1) + N = t * N1 + x # i) if x == 0: @@ -1491,16 +1472,14 @@ def brouwer_separable_design(k, t, q, x, check=False, verbose=False, explain_con rOA_N_classes = [] # A resolvable OA(k-1,t)-t.OA(k-1,1) - OA_t = incomplete_orthogonal_array(k-1,t,[1]*t,resolvable=True) - OA_t_classes = [OA_t[i*t:(i+1)*t] for i in range(t-1)] + OA_t = incomplete_orthogonal_array(k - 1, t, [1] * t, resolvable=True) + OA_t_classes = [OA_t[i * t : (i + 1) * t] for i in range(t - 1)] # We can now build (t-1)(q^2-q+1-t) parallel classes of the resolvable # OA(k-1,N) for PBD_parallel_class in partition_of_blocks_of_size_t: for OA_class in OA_t_classes: - rOA_N_classes.append([[B[x] for x in BB] - for BB in OA_class - for B in PBD_parallel_class]) + rOA_N_classes.append([[B[x] for x in BB] for BB in OA_class for B in PBD_parallel_class]) # 2) We build a Nx(q+t) matrix such that: # @@ -1519,26 +1498,23 @@ def brouwer_separable_design(k, t, q, x, check=False, verbose=False, explain_con # Thanks to the ordering of the points in each set of size q+t, the # product of a block B of the incomplete OA with all blocks of size q+t # yields a parallel class of an OA(k-1,N) - OA = incomplete_orthogonal_array(k-1,q+t,[1]*(q+t)) + OA = incomplete_orthogonal_array(k - 1, q + t, [1] * (q + t)) for B in OA: rOA_N_classes.append([[R[x] for x in B] for R in block_of_size_q_plus_t]) # 4) A last parallel class with blocks [0,0,...], [1,1,...],... - rOA_N_classes.append([[i]*(k-1) for i in range(N)]) + rOA_N_classes.append([[i] * (k - 1) for i in range(N)]) # 5) We now build the OA(k,N) from the N parallel classes of our resolvable OA(k-1,N) OA = [B for classs in rOA_N_classes for B in classs] - for i,B in enumerate(OA): - B.append(i//N) + for i, B in enumerate(OA): + B.append(i // N) # ii) - elif (x == t+q and - orthogonal_array(k+e3, t ,existence=True) and - orthogonal_array( k , t+q ,existence=True) and - orthogonal_array( k+1,t+q+1,existence=True)): + elif x == t + q and orthogonal_array(k + e3, t, existence=True) and orthogonal_array(k, t + q, existence=True) and orthogonal_array(k + 1, t + q + 1, existence=True): if verbose: - print("Case ii) with k={},q={},t={},x={},e3={}".format(k,q,t,x,e3)) + print("Case ii) with k={},q={},t={},x={},e3={}".format(k, q, t, x, e3)) # The sets of size t: # @@ -1548,10 +1524,10 @@ def brouwer_separable_design(k, t, q, x, check=False, verbose=False, explain_con if x == q**2: assert e3 == 0, "equivalent to x==q^2" assert len(partition_of_blocks_of_size_t) == 1, "also equivalent to exactly one partition into sets of size t" - OA = [[B[xx] for xx in R] for R in orthogonal_array(k,t) for B in partition_of_blocks_of_size_t[0]] + OA = [[B[xx] for xx in R] for R in orthogonal_array(k, t) for B in partition_of_blocks_of_size_t[0]] else: - OA = OA_from_PBD(k,N,sum(partition_of_blocks_of_size_t,[]),check=False)[:-N] - OA.extend([i]*k for i in range(N-x)) + OA = OA_from_PBD(k, N, sum(partition_of_blocks_of_size_t, []), check=False)[:-N] + OA.extend([i] * k for i in range(N - x)) # The sets of size q+t: # @@ -1561,25 +1537,21 @@ def brouwer_separable_design(k, t, q, x, check=False, verbose=False, explain_con # with one of the new x points). # Resolvable OA(k,t+q+1)-(t+q+1).OA(k,t+q+1) - OA_tq1 = incomplete_orthogonal_array(k,t+q+1,[1]*(t+q+1),resolvable=True) - OA_tq1_classes = [OA_tq1[i*(t+q+1):(i+1)*(t+q+1)] for i in range(t+q)] + OA_tq1 = incomplete_orthogonal_array(k, t + q + 1, [1] * (t + q + 1), resolvable=True) + OA_tq1_classes = [OA_tq1[i * (t + q + 1) : (i + 1) * (t + q + 1)] for i in range(t + q)] blocks_of_size_q_plus_t = _reorder_matrix(blocks_of_size_q_plus_t) - for i,classs in enumerate(OA_tq1_classes): - OA.extend([R[xx] if xx < t+q else N-i-1 for xx in B] - for R in blocks_of_size_q_plus_t for B in classs) + for i, classs in enumerate(OA_tq1_classes): + OA.extend([R[xx] if xx < t + q else N - i - 1 for xx in B] for R in blocks_of_size_q_plus_t for B in classs) # The set of size x - OA.extend([N-1-xx for xx in R] for R in orthogonal_array(k,x)) + OA.extend([N - 1 - xx for xx in R] for R in orthogonal_array(k, x)) # iii) - elif (x == q**2-q+1-t and - orthogonal_array( k , x ,existence=True) and # d0 - orthogonal_array(k+e2, t+1 ,existence=True) and # d2-e2 - orthogonal_array(k+1 , t+q ,existence=True)): # d3-e1 + elif x == q**2 - q + 1 - t and orthogonal_array(k, x, existence=True) and orthogonal_array(k + e2, t + 1, existence=True) and orthogonal_array(k + 1, t + q, existence=True): # d0 # d2-e2 # d3-e1 if verbose: - print("Case iii) with k={},q={},t={},x={},e2={}".format(k,q,t,x,e2)) + print("Case iii) with k={},q={},t={},x={},e2={}".format(k, q, t, x, e2)) OA = [] @@ -1591,31 +1563,26 @@ def brouwer_separable_design(k, t, q, x, check=False, verbose=False, explain_con # There is one partition into blocks of size t, which we extend with # the new vertex. The OA on t+1 points does not have to be resolvable. - OA.extend([B[xx] if xx < t else N-1 for xx in R] - for R in incomplete_orthogonal_array(k,t+1,[1]) - for B in partition_of_blocks_of_size_t[0]) + OA.extend([B[xx] if xx < t else N - 1 for xx in R] for R in incomplete_orthogonal_array(k, t + 1, [1]) for B in partition_of_blocks_of_size_t[0]) else: assert e2 == 1, "equivalent to x!=1" # Extending the x partitions into blocks of size t with # each of the new x points. - for i,partition in enumerate(partition_of_blocks_of_size_t): + for i, partition in enumerate(partition_of_blocks_of_size_t): for B in partition: - B.append(N-i-1) - OA = OA_from_PBD(k,N,sum(partition_of_blocks_of_size_t,[]),check=False)[:-x] + B.append(N - i - 1) + OA = OA_from_PBD(k, N, sum(partition_of_blocks_of_size_t, []), check=False)[:-x] # The blocks of size q+t are covered with a resolvable OA(k,q+t) - OA.extend(OA_from_PBD(k,N,blocks_of_size_q_plus_t,check=False)[:-N]) + OA.extend(OA_from_PBD(k, N, blocks_of_size_q_plus_t, check=False)[:-N]) # The set of size x - OA.extend([N-xx-1 for xx in B] for B in orthogonal_array(k,x)) + OA.extend([N - xx - 1 for xx in B] for B in orthogonal_array(k, x)) # iv) - elif (x == q**2 + 1 and - orthogonal_array(k, x, existence=True) and # d0 - orthogonal_array(k + e4, t + 1, existence=True) and # d2 - e4 - orthogonal_array(k + 1, t + q + 1, existence=True)): # d4 - 1 + elif x == q**2 + 1 and orthogonal_array(k, x, existence=True) and orthogonal_array(k + e4, t + 1, existence=True) and orthogonal_array(k + 1, t + q + 1, existence=True): # d0 # d2 - e4 # d4 - 1 if verbose: print(f"Case iv) with k={k},q={q},t={t},x={x},e4={e4}") @@ -1626,14 +1593,12 @@ def brouwer_separable_design(k, t, q, x, check=False, verbose=False, explain_con if e4 == 0: # Only one partition into t-sets. The OA(k,t+1) needs not be resolvable - OA = [[B[xx] if xx < t else N-x for xx in R] - for R in incomplete_orthogonal_array(k,t+1,[1]) - for B in partition_of_blocks_of_size_t[0]] + OA = [[B[xx] if xx < t else N - x for xx in R] for R in incomplete_orthogonal_array(k, t + 1, [1]) for B in partition_of_blocks_of_size_t[0]] else: - for i,classs in enumerate(partition_of_blocks_of_size_t): + for i, classs in enumerate(partition_of_blocks_of_size_t): for B in classs: - B.append(N-x+i) - OA = OA_from_PBD(k,N,sum(partition_of_blocks_of_size_t,[]),check=False)[:-x] + B.append(N - x + i) + OA = OA_from_PBD(k, N, sum(partition_of_blocks_of_size_t, []), check=False)[:-x] # The sets of size q+t: # @@ -1643,26 +1608,22 @@ def brouwer_separable_design(k, t, q, x, check=False, verbose=False, explain_con # with the last q+t new points). # Resolvable OA(k,t+q+1)-(t+q+1).OA(k,t+q+1) - OA_tq1 = incomplete_orthogonal_array(k,t+q+1,[1]*(t+q+1),resolvable=True) - OA_tq1_classes = [OA_tq1[i*(t+q+1):(i+1)*(t+q+1)] for i in range(t+q)] + OA_tq1 = incomplete_orthogonal_array(k, t + q + 1, [1] * (t + q + 1), resolvable=True) + OA_tq1_classes = [OA_tq1[i * (t + q + 1) : (i + 1) * (t + q + 1)] for i in range(t + q)] blocks_of_size_q_plus_t = _reorder_matrix(blocks_of_size_q_plus_t) - for i,classs in enumerate(OA_tq1_classes): - OA.extend([R[xx] if xx < t+q else N-i-1 for xx in B] for R in blocks_of_size_q_plus_t for B in classs) + for i, classs in enumerate(OA_tq1_classes): + OA.extend([R[xx] if xx < t + q else N - i - 1 for xx in B] for R in blocks_of_size_q_plus_t for B in classs) # Set of size x - OA_k_x = orthogonal_array(k,x) - OA.extend([N-i-1 for i in R] for R in OA_k_x) + OA_k_x = orthogonal_array(k, x) + OA.extend([N - i - 1 for i in R] for R in OA_k_x) # v) - elif (0 < x and x < q**2-q+1-t and (e1 or e2) and # The result is wrong when e1=e2=0 - orthogonal_array(k ,x ,existence=True) and # d0 - orthogonal_array(k+e1,t ,existence=True) and # d1-e1 - orthogonal_array(k+e2,t+1,existence=True) and # d2-e2 - orthogonal_array(k+1,t+q,existence=True)): # d3-1 + elif 0 < x and x < q**2 - q + 1 - t and (e1 or e2) and orthogonal_array(k, x, existence=True) and orthogonal_array(k + e1, t, existence=True) and orthogonal_array(k + e2, t + 1, existence=True) and orthogonal_array(k + 1, t + q, existence=True): # The result is wrong when e1=e2=0 # d0 # d1-e1 # d2-e2 # d3-1 if verbose: - print("Case v) with k={},q={},t={},x={},e1={},e2={}".format(k,q,t,x,e1,e2)) + print("Case v) with k={},q={},t={},x={},e1={},e2={}".format(k, q, t, x, e1, e2)) OA = [] @@ -1671,47 +1632,41 @@ def brouwer_separable_design(k, t, q, x, check=False, verbose=False, explain_con # We extend x partitions into blocks of size t with the new x elements if e2: assert x != 1, "equivalent to e2==1" - for i,classs in enumerate(partition_of_blocks_of_size_t[:x]): + for i, classs in enumerate(partition_of_blocks_of_size_t[:x]): for B in classs: - B.append(N-1-i) - OA.extend(OA_from_PBD(k,N,sum(partition_of_blocks_of_size_t[:x],[]),check=False)[:-N]) + B.append(N - 1 - i) + OA.extend(OA_from_PBD(k, N, sum(partition_of_blocks_of_size_t[:x], []), check=False)[:-N]) else: assert x == 1, "equivalent to e2==0" # Only one class, the OA(k,t+1) need not be resolvable. - OA.extend([B[xx] if xx < t else N-1 for xx in R] - for R in incomplete_orthogonal_array(k,t+1,[1]) - for B in partition_of_blocks_of_size_t[0]) + OA.extend([B[xx] if xx < t else N - 1 for xx in R] for R in incomplete_orthogonal_array(k, t + 1, [1]) for B in partition_of_blocks_of_size_t[0]) # Sets of size t if e1: - assert x != q**2-q-t, "equivalent to e1=1" - OA.extend(OA_from_PBD(k,N,sum(partition_of_blocks_of_size_t[x:],[]),check=False)[:-N]) + assert x != q**2 - q - t, "equivalent to e1=1" + OA.extend(OA_from_PBD(k, N, sum(partition_of_blocks_of_size_t[x:], []), check=False)[:-N]) else: - assert x == q**2-q-t, "equivalent to e1=0" + assert x == q**2 - q - t, "equivalent to e1=0" # Only one class. The OA(k,t) needs not be resolvable - OA.extend([B[xx] for xx in R] for R in orthogonal_array(k,t) for B in partition_of_blocks_of_size_t[-1]) + OA.extend([B[xx] for xx in R] for R in orthogonal_array(k, t) for B in partition_of_blocks_of_size_t[-1]) if e1 and e2: - OA.extend([i]*k for i in range(N-x)) + OA.extend([i] * k for i in range(N - x)) if e1 == 0 and e2 == 0: raise RuntimeError("Brouwer's construction does not work for case v) with e2=e1=0") # Sets of size q+t - OA.extend(OA_from_PBD(k,N,blocks_of_size_q_plus_t,check=False)[:-N]) + OA.extend(OA_from_PBD(k, N, blocks_of_size_q_plus_t, check=False)[:-N]) # Set of size x - OA.extend([N-i-1 for i in R] for R in orthogonal_array(k,x)) + OA.extend([N - i - 1 for i in R] for R in orthogonal_array(k, x)) # vi) - elif (t+q < x and x < q**2+1 and (e3 or e4) and # The result is wrong when e3=e4=0 - orthogonal_array(k ,x ,existence=True) and # d0 - orthogonal_array(k+e3,t ,existence=True) and # d1-e3 - orthogonal_array(k+e4,t+1 ,existence=True) and # d2-e4 - orthogonal_array(k+1,t+q+1,existence=True)): # d4-1 + elif t + q < x and x < q**2 + 1 and (e3 or e4) and orthogonal_array(k, x, existence=True) and orthogonal_array(k + e3, t, existence=True) and orthogonal_array(k + e4, t + 1, existence=True) and orthogonal_array(k + 1, t + q + 1, existence=True): # The result is wrong when e3=e4=0 # d0 # d1-e3 # d2-e4 # d4-1 if verbose: - print("Case vi) with k={},q={},t={},x={},e3={},e4={}".format(k,q,t,x,e3,e4)) + print("Case vi) with k={},q={},t={},x={},e3={},e4={}".format(k, q, t, x, e3, e4)) OA = [] @@ -1720,31 +1675,27 @@ def brouwer_separable_design(k, t, q, x, check=False, verbose=False, explain_con # All x-(q+t) parallel classes with blocks of size t are extended with # x-(q+t) of the new points. if e4: - assert x != q+t+1, "equivalent to e4=1" - for i,classs in enumerate(partition_of_blocks_of_size_t[:x-(q+t)]): + assert x != q + t + 1, "equivalent to e4=1" + for i, classs in enumerate(partition_of_blocks_of_size_t[: x - (q + t)]): for B in classs: - B.append(N-x+i) - OA.extend(OA_from_PBD(k,N,sum(partition_of_blocks_of_size_t[:x-(q+t)],[]),check=False)[:-N]) + B.append(N - x + i) + OA.extend(OA_from_PBD(k, N, sum(partition_of_blocks_of_size_t[: x - (q + t)], []), check=False)[:-N]) else: - assert x == q+t+1, "equivalent to e4=0" + assert x == q + t + 1, "equivalent to e4=0" # Only one class. The OA(k,t+1) needs not be resolvable. - OA.extend([B[xx] if xx < t else N-x for xx in R] - for R in incomplete_orthogonal_array(k,t+1,[1]) - for B in partition_of_blocks_of_size_t[0]) + OA.extend([B[xx] if xx < t else N - x for xx in R] for R in incomplete_orthogonal_array(k, t + 1, [1]) for B in partition_of_blocks_of_size_t[0]) # Sets of size t if e3: assert x != q**2, "equivalent to e3=1" - OA.extend(OA_from_PBD(k,N,sum(partition_of_blocks_of_size_t[x-(q+t):],[]),check=False)[:-N]) + OA.extend(OA_from_PBD(k, N, sum(partition_of_blocks_of_size_t[x - (q + t) :], []), check=False)[:-N]) else: assert x == q**2, "equivalent to e3=0" # Only one class. The OA(k,t) needs not be resolvable. - OA.extend([B[xx] for xx in R] - for R in orthogonal_array(k,t) - for B in partition_of_blocks_of_size_t[-1]) + OA.extend([B[xx] for xx in R] for R in orthogonal_array(k, t) for B in partition_of_blocks_of_size_t[-1]) if e3 and e4: - OA.extend([i]*k for i in range(N-x)) + OA.extend([i] * k for i in range(N - x)) elif e3 == 0 and e4 == 0: raise RuntimeError("Brouwer's construction does not work for case v) with e3=e4=0") @@ -1757,22 +1708,20 @@ def brouwer_separable_design(k, t, q, x, check=False, verbose=False, explain_con # with the last q+t new points). # Resolvable OA(k,t+q+1)-(t+q+1).OA(k,t+q+1) - OA_tq1 = incomplete_orthogonal_array(k,t+q+1,[1]*(t+q+1),resolvable=True) - OA_tq1_classes = [OA_tq1[i*(t+q+1):(i+1)*(t+q+1)] for i in range(t+q)] + OA_tq1 = incomplete_orthogonal_array(k, t + q + 1, [1] * (t + q + 1), resolvable=True) + OA_tq1_classes = [OA_tq1[i * (t + q + 1) : (i + 1) * (t + q + 1)] for i in range(t + q)] blocks_of_size_q_plus_t = _reorder_matrix(blocks_of_size_q_plus_t) - for i,classs in enumerate(OA_tq1_classes): - OA.extend([R[xx] if xx < t+q else N-i-1 for xx in B] - for R in blocks_of_size_q_plus_t - for B in classs) + for i, classs in enumerate(OA_tq1_classes): + OA.extend([R[xx] if xx < t + q else N - i - 1 for xx in B] for R in blocks_of_size_q_plus_t for B in classs) # Set of size x - OA.extend([N-xx-1 for xx in B] for B in orthogonal_array(k,x)) + OA.extend([N - xx - 1 for xx in B] for B in orthogonal_array(k, x)) else: raise ValueError("this input is not handled by Brouwer's result") if check: - assert is_orthogonal_array(OA,k,N,2,1) + assert is_orthogonal_array(OA, k, N, 2, 1) return OA diff --git a/src/sage/combinat/designs/resolvable_bibd.py b/src/sage/combinat/designs/resolvable_bibd.py index a5efedf1594..b97dc90ba37 100644 --- a/src/sage/combinat/designs/resolvable_bibd.py +++ b/src/sage/combinat/designs/resolvable_bibd.py @@ -102,18 +102,22 @@ def resolvable_balanced_incomplete_block_design(v, k, existence=False): return balanced_incomplete_block_design(v, k, existence=existence) # Non-existence of resolvable BIBD - if (v < k or - k < 2 or - v % k != 0 or - (v-1) % (k-1) != 0 or - (v*(v-1)) % (k*(k-1)) != 0 or + if ( + v < k + or k < 2 + or v % k != 0 + or (v - 1) % (k - 1) != 0 + or (v * (v - 1)) % (k * (k - 1)) != 0 + or # From the Handbook of combinatorial designs: # # With lambda>1 the other exceptions is # (15,5,2) - (k == 6 and v == 36) or + (k == 6 and v == 36) + or # Fisher's inequality - (v*(v-1))/(k*(k-1)) < v): + (v * (v - 1)) / (k * (k - 1)) < v + ): if existence: return False raise EmptySetError("There exists no ({},{},{})-RBIBD".format(v, k, 1)) @@ -121,16 +125,11 @@ def resolvable_balanced_incomplete_block_design(v, k, existence=False): if k == 2: if existence: return True - classes = [[[(c+i) % (v-1), (c+v-i) % (v-1)] for i in range(1, v//2)] - for c in range(v-1)] + classes = [[[(c + i) % (v - 1), (c + v - i) % (v - 1)] for i in range(1, v // 2)] for c in range(v - 1)] for i, classs in enumerate(classes): - classs.append([v-1, i]) + classs.append([v - 1, i]) - B = BalancedIncompleteBlockDesign(v, - sum(classes, []), - k=k, - check=True, - copy=False) + B = BalancedIncompleteBlockDesign(v, sum(classes, []), k=k, check=True, copy=False) B._classes = classes return B if k == 3: @@ -198,58 +197,50 @@ def kirkman_triple_system(v, existence=False): return BalancedIncompleteBlockDesign(3, [[0, 1, 2]], k=3, lambd=1) if v == 9: - classes = [[[0, 1, 5], [2, 6, 7], [3, 4, 8]], - [[1, 6, 8], [3, 5, 7], [0, 2, 4]], - [[1, 4, 7], [0, 3, 6], [2, 5, 8]], - [[4, 5, 6], [0, 7, 8], [1, 2, 3]]] - KTS = BalancedIncompleteBlockDesign(v, [tr for cl in classes for tr in cl], - k=3, lambd=1, copy=False) + classes = [[[0, 1, 5], [2, 6, 7], [3, 4, 8]], [[1, 6, 8], [3, 5, 7], [0, 2, 4]], [[1, 4, 7], [0, 3, 6], [2, 5, 8]], [[4, 5, 6], [0, 7, 8], [1, 2, 3]]] + KTS = BalancedIncompleteBlockDesign(v, [tr for cl in classes for tr in cl], k=3, lambd=1, copy=False) KTS._classes = classes return KTS # Construction 1.1 from [Stinson91] (originally Theorem 6 from [RCW71]) # # For all prime powers q=1 mod 6, there exists a KTS(2q+1) - if ((v-1)//2) % 6 == 1 and is_prime_power((v-1)//2): + if ((v - 1) // 2) % 6 == 1 and is_prime_power((v - 1) // 2): from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF - q = (v-1)//2 + + q = (v - 1) // 2 K = GF(q, 'x') a = K.primitive_element() t = (q - 1) // 6 # m is the solution of a^m=(a^t+1)/2 from sage.groups.generic import discrete_log - m = discrete_log((a**t+1)/2, a) - assert 2*a**m == a**t+1 + + m = discrete_log((a**t + 1) / 2, a) + assert 2 * a**m == a**t + 1 # First parallel class first_class = [[(0, 1), (0, 2), 'inf']] b0 = K.one() b1 = a**t b2 = a**m - first_class.extend([(b0*a**i, 1), (b1*a**i, 1), (b2*a**i, 2)] - for i in list(range(t))+list(range(2*t, 3*t))+list(range(4*t, 5*t))) - b0 = a**(m+t) - b1 = a**(m+3*t) - b2 = a**(m+5*t) - first_class.extend([[(b0*a**i, 2), (b1*a**i, 2), (b2*a**i, 2)] - for i in range(t)]) + first_class.extend([(b0 * a**i, 1), (b1 * a**i, 1), (b2 * a**i, 2)] for i in list(range(t)) + list(range(2 * t, 3 * t)) + list(range(4 * t, 5 * t))) + b0 = a ** (m + t) + b1 = a ** (m + 3 * t) + b2 = a ** (m + 5 * t) + first_class.extend([[(b0 * a**i, 2), (b1 * a**i, 2), (b2 * a**i, 2)] for i in range(t)]) # Action of K on the points def action(v, x): return (v + x[0], x[1]) if len(x) == 2 else x # relabel to integer - relabel = {(p, x): i+(x-1)*q - for i, p in enumerate(K) - for x in [1, 2]} - relabel['inf'] = 2*q + relabel = {(p, x): i + (x - 1) * q for i, p in enumerate(K) for x in [1, 2]} + relabel['inf'] = 2 * q - classes = [[[relabel[action(p, x)] for x in tr] for tr in first_class] - for p in K] + classes = [[[relabel[action(p, x)] for x in tr] for tr in first_class] for p in K] - KTS = BalancedIncompleteBlockDesign(v, [tr for cl in classes for tr in cl], - k=3, lambd=1, copy=False) + KTS = BalancedIncompleteBlockDesign(v, [tr for cl in classes for tr in cl], k=3, lambd=1, copy=False) KTS._classes = classes return KTS @@ -257,37 +248,33 @@ def action(v, x): # Construction 1.2 from [Stinson91] (originally Theorem 5 from [RCW71]) # # For all prime powers q=1 mod 6, there exists a KTS(3q) - if (v//3) % 6 == 1 and is_prime_power(v//3): + if (v // 3) % 6 == 1 and is_prime_power(v // 3): from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF - q = v//3 + + q = v // 3 K = GF(q, 'x') a = K.primitive_element() t = (q - 1) // 6 A0 = [(0, 0), (0, 1), (0, 2)] - B = [[(a**i, j), (a**(i+2*t), j), (a**(i+4*t), j)] for j in range(3) - for i in range(t)] - A = [[(a**i, 0), (a**(i+2*t), 1), (a**(i+4*t), 2)] for i in range(6*t)] + B = [[(a**i, j), (a ** (i + 2 * t), j), (a ** (i + 4 * t), j)] for j in range(3) for i in range(t)] + A = [[(a**i, 0), (a ** (i + 2 * t), 1), (a ** (i + 4 * t), 2)] for i in range(6 * t)] # Action of K on the points def action(v, x): return (v + x[0], x[1]) # relabel to integer - relabel = {(p, j): i+j*q - for i, p in enumerate(K) - for j in range(3)} + relabel = {(p, j): i + j * q for i, p in enumerate(K) for j in range(3)} - B0 = [A0] + B + A[t:2*t] + A[3*t:4*t] + A[5*t:6*t] + B0 = [A0] + B + A[t : 2 * t] + A[3 * t : 4 * t] + A[5 * t : 6 * t] # Classes - classes = [[[relabel[action(p, x)] for x in tr] for tr in B0] - for p in K] + classes = [[[relabel[action(p, x)] for x in tr] for tr in B0] for p in K] - for i in list(range(t))+list(range(2*t, 3*t))+list(range(4*t, 5*t)): + for i in list(range(t)) + list(range(2 * t, 3 * t)) + list(range(4 * t, 5 * t)): classes.append([[relabel[action(p, x)] for x in A[i]] for p in K]) - KTS = BalancedIncompleteBlockDesign(v, [tr for cl in classes for tr in cl], - k=3, lambd=1, copy=False) + KTS = BalancedIncompleteBlockDesign(v, [tr for cl in classes for tr in cl], k=3, lambd=1, copy=False) KTS._classes = classes return KTS @@ -354,21 +341,15 @@ def action(v, x): # Pasting the KTS(n') without {x,x',\infty} blocks classes = [[] for _ in repeat(None, (v - 1) // 2)] gdd = {4: gdd4, 7: gdd7} - for B in PBD_4_7((v-1)//2, check=False): + for B in PBD_4_7((v - 1) // 2, check=False): for i, classs in enumerate(gdd[len(B)]): - classes[B[i]].extend([2*B[x//2]+x % 2 for x in BB] - for BB in classs) + classes[B[i]].extend([2 * B[x // 2] + x % 2 for x in BB] for BB in classs) # The {x,x',\infty} blocks for i, classs in enumerate(classes): - classs.append([2*i, 2*i+1, v-1]) - - KTS = BalancedIncompleteBlockDesign(v, - blocks=[tr for cl in classes for tr in cl], - k=3, - lambd=1, - check=True, - copy=False) + classs.append([2 * i, 2 * i + 1, v - 1]) + + KTS = BalancedIncompleteBlockDesign(v, blocks=[tr for cl in classes for tr in cl], k=3, lambd=1, check=True, copy=False) KTS._classes = classes assert KTS.is_resolvable() @@ -413,34 +394,28 @@ def v_4_1_rbibd(v, existence=False): ....: _ = designs.resolvable_balanced_incomplete_block_design(3*q+1,4) """ # Volume 1, VII.7.5.a from [BJL99]_ - if v % 3 != 1 or not is_prime_power((v-1)//3): + if v % 3 != 1 or not is_prime_power((v - 1) // 3): if existence: return Unknown raise NotImplementedError(f"I don't know how to build a ({v},4,1)-RBIBD!") from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF - q = (v-1)//3 - nn = (q-1)//4 + + q = (v - 1) // 3 + nn = (q - 1) // 4 G = GF(q, 'x') w = G.primitive_element() - e = w**(nn) + e = w ** (nn) assert e**2 == -1 - first_class = [[(w**i, j), (-w**i, j), (e*w**i, j+1), (-e*w**i, j+1)] - for i in range(nn) for j in range(3)] + first_class = [[(w**i, j), (-(w**i), j), (e * w**i, j + 1), (-e * w**i, j + 1)] for i in range(nn) for j in range(3)] first_class.append([(0, 0), (0, 1), (0, 2), 'inf']) label = {p: i for i, p in enumerate(G)} - classes = [[[v-1 if x == 'inf' else (x[1] % 3)*q+label[x[0]+g] for x in S] - for S in first_class] - for g in G] + classes = [[[v - 1 if x == 'inf' else (x[1] % 3) * q + label[x[0] + g] for x in S] for S in first_class] for g in G] - BIBD = BalancedIncompleteBlockDesign(v, - blocks=sum(classes, []), - k=4, - check=True, - copy=False) + BIBD = BalancedIncompleteBlockDesign(v, blocks=sum(classes, []), k=4, check=True, copy=False) BIBD._classes = classes assert BIBD.is_resolvable() return BIBD @@ -488,7 +463,7 @@ def PBD_4_7(v, check=True, existence=False): # Beth/Jungnickel/Lenz: take KTS(15) and extend each of the 7 classes # with a new point. Make those new points a 7-set. KTS15 = kirkman_triple_system(15) - blocks = [S+[i+15] for i, classs in enumerate(KTS15._classes) for S in classs] + [list(range(15, 22))] + blocks = [S + [i + 15] for i, classs in enumerate(KTS15._classes) for S in classs] + [list(range(15, 22))] elif v == 34: # [BJL99] (p527,vol1), but originally Brouwer @@ -497,18 +472,12 @@ def PBD_4_7(v, check=True, existence=False): C = [(0, 0), (2, 2), (5, 0)] D = [(0, 0), (0, 1), (0, 2)] - A = [[(x+i, y+j) for x, y in A] - for i in range(9) for j in range(3)] - B = [[(x+i, y+i+j) for x, y in B] + [27+j] - for i in range(9) for j in range(3)] - C = [[(x+i+j, y+2*i+j) for x, y in C] + [30+j] - for i in range(9) for j in range(3)] - D = [[(x+i, y+i) for x, y in D] + [33] - for i in range(9)] - - blocks = [[int(x) if not isinstance(x, tuple) else (x[1] % 3)*9+(x[0] % 9) - for x in S] - for S in A+B+C+D+[list(range(27, 34))]] + A = [[(x + i, y + j) for x, y in A] for i in range(9) for j in range(3)] + B = [[(x + i, y + i + j) for x, y in B] + [27 + j] for i in range(9) for j in range(3)] + C = [[(x + i + j, y + 2 * i + j) for x, y in C] + [30 + j] for i in range(9) for j in range(3)] + D = [[(x + i, y + i) for x, y in D] + [33] for i in range(9)] + + blocks = [[int(x) if not isinstance(x, tuple) else (x[1] % 3) * 9 + (x[0] % 9) for x in S] for S in A + B + C + D + [list(range(27, 34))]] elif v == 46: # [BJL99] (p527,vol1), but originally Brouwer A = [(1, 0), (3, 0), (9, 0), (0, 1)] @@ -517,20 +486,13 @@ def PBD_4_7(v, check=True, existence=False): D = [(0, 0), (2, 1), (7, 2)] E = [(0, 0), (0, 1), (0, 2)] - A = [[(x+i, y+j) for x, y in A] - for i in range(13) for j in range(3)] - B = [[(x+i, y+j) for x, y in B] - for i in range(13) for j in range(3)] - C = [[(x+i, y+j) for x, y in C] + [39+j] - for i in range(13) for j in range(3)] - D = [[(x+i, y+j) for x, y in D] + [42+j] - for i in range(13) for j in range(3)] - E = [[(x+i, y+i) for x, y in E] + [45] - for i in range(13)] - - blocks = [[int(x) if not isinstance(x, tuple) else (x[1] % 3)*13+(x[0] % 13) - for x in S] - for S in A+B+C+D+E+[list(range(39, 46))]] + A = [[(x + i, y + j) for x, y in A] for i in range(13) for j in range(3)] + B = [[(x + i, y + j) for x, y in B] for i in range(13) for j in range(3)] + C = [[(x + i, y + j) for x, y in C] + [39 + j] for i in range(13) for j in range(3)] + D = [[(x + i, y + j) for x, y in D] + [42 + j] for i in range(13) for j in range(3)] + E = [[(x + i, y + i) for x, y in E] + [45] for i in range(13)] + + blocks = [[int(x) if not isinstance(x, tuple) else (x[1] % 3) * 13 + (x[0] % 13) for x in S] for S in A + B + C + D + E + [list(range(39, 46))]] elif v == 58: # [BJL99] (p527,vol1), but originally Brouwer @@ -541,22 +503,14 @@ def PBD_4_7(v, check=True, existence=False): E = [(0, 0), (6, 1), (4, 2)] F = [(0, 0), (0, 1), (0, 2)] - A = [[(x+i, y+j) for x, y in A] - for i in range(17) for j in range(3)] - B = [[(x+i, y+j) for x, y in B] - for i in range(17) for j in range(3)] - C = [[(x+i, y+j) for x, y in C] - for i in range(17) for j in range(3)] - D = [[(x+i, y+j) for x, y in D] + [51+j] - for i in range(17) for j in range(3)] - E = [[(x+i, y+j) for x, y in E] + [54+j] - for i in range(17) for j in range(3)] - F = [[(x+i, y+i) for x, y in F] + [57] - for i in range(17)] - - blocks = [[int(x) if not isinstance(x, tuple) else (x[1] % 3)*17+(x[0] % 17) - for x in S] - for S in A+B+C+D+E+F+[list(range(51, 58))]] + A = [[(x + i, y + j) for x, y in A] for i in range(17) for j in range(3)] + B = [[(x + i, y + j) for x, y in B] for i in range(17) for j in range(3)] + C = [[(x + i, y + j) for x, y in C] for i in range(17) for j in range(3)] + D = [[(x + i, y + j) for x, y in D] + [51 + j] for i in range(17) for j in range(3)] + E = [[(x + i, y + j) for x, y in E] + [54 + j] for i in range(17) for j in range(3)] + F = [[(x + i, y + i) for x, y in F] + [57] for i in range(17)] + + blocks = [[int(x) if not isinstance(x, tuple) else (x[1] % 3) * 17 + (x[0] % 17) for x in S] for S in A + B + C + D + E + F + [list(range(51, 58))]] elif v == 70: # [BJL99] (p527,vol1), but originally Brouwer @@ -568,24 +522,15 @@ def PBD_4_7(v, check=True, existence=False): F = [(0, 0), (7, 0), (14, 1)] H = [(0, 0), (0, 1), (0, 2)] - A = [[(x+i, y+j) for x, y in A] - for i in range(21) for j in range(3)] - B = [[(x+i, y+j) for x, y in B] - for i in range(21) for j in range(3)] - C = [[(x+i, y+j) for x, y in C] - for i in range(21) for j in range(3)] - D = [[(x+i, y+j) for x, y in D] - for i in range(21) for j in range(3)] - E = [[(x+i, y+j) for x, y in E] + [63+j] - for i in range(21) for j in range(3)] - F = [[(x+3*i+j, y+ii+j) for x, y in F] + [66+j] - for i in range(7) for j in range(3) for ii in range(3)] - H = [[(x+i, y+i) for x, y in H] + [69] - for i in range(21)] - - blocks = [[int(x) if not isinstance(x, tuple) else (x[1] % 3)*21+(x[0] % 21) - for x in S] - for S in A+B+C+D+E+F+H+[list(range(63, 70))]] + A = [[(x + i, y + j) for x, y in A] for i in range(21) for j in range(3)] + B = [[(x + i, y + j) for x, y in B] for i in range(21) for j in range(3)] + C = [[(x + i, y + j) for x, y in C] for i in range(21) for j in range(3)] + D = [[(x + i, y + j) for x, y in D] for i in range(21) for j in range(3)] + E = [[(x + i, y + j) for x, y in E] + [63 + j] for i in range(21) for j in range(3)] + F = [[(x + 3 * i + j, y + ii + j) for x, y in F] + [66 + j] for i in range(7) for j in range(3) for ii in range(3)] + H = [[(x + i, y + i) for x, y in H] + [69] for i in range(21)] + + blocks = [[int(x) if not isinstance(x, tuple) else (x[1] % 3) * 21 + (x[0] % 21) for x in S] for S in A + B + C + D + E + F + H + [list(range(63, 70))]] elif v == 82: # This construction is Theorem IX.3.16 from [BJL99] (p.627). @@ -593,27 +538,27 @@ def PBD_4_7(v, check=True, existence=False): # A (15,{4},{3})-GDD from a (16,4)-BIBD from .group_divisible_designs import group_divisible_design from .orthogonal_arrays import transversal_design - GDD = group_divisible_design(3*5, K=[4], G=[3], check=False) + + GDD = group_divisible_design(3 * 5, K=[4], G=[3], check=False) TD = transversal_design(5, 5) # A (75,{4},{15})-GDD - GDD2 = [[3*B[x//3]+x % 3 for x in BB] for B in TD for BB in GDD] + GDD2 = [[3 * B[x // 3] + x % 3 for x in BB] for B in TD for BB in GDD] # We now complete the (75,{4},{15})-GDD into a (82,{4,7})-PBD. For this, # we add 7 new points that are added to all groups of size 15. # # On these groups a (15+7,{4,7})-PBD is pasted, in such a way that the 7 # new points are a set of the final PBD - PBD22 = PBD_4_7(15+7) + PBD22 = PBD_4_7(15 + 7) S = next(SS for SS in PBD22 if len(SS) == 7) # a set of size 7 - PBD22.relabel({v: i for i, v in enumerate([i for i in range(15+7) - if i not in S] + S)}) + PBD22.relabel({v: i for i, v in enumerate([i for i in range(15 + 7) if i not in S] + S)}) for B in PBD22: if B == S: continue for i in range(5): - GDD2.append([x+i*15 if x < 15 else x+60 for x in B]) + GDD2.append([x + i * 15 if x < 15 else x + 60 for x in B]) GDD2.append(list(range(75, 82))) blocks = GDD2 @@ -624,6 +569,7 @@ def PBD_4_7(v, check=True, existence=False): # take 4 parallel lines from an affine plane of order 7, and a 5th # one. This is a (31,{4,5,7})-BIBD. And 94=3*31+1. from sage.combinat.designs.block_design import AffineGeometryDesign + AF = AffineGeometryDesign(2, 1, 7) parall = [] plus_one = None @@ -638,10 +584,7 @@ def PBD_4_7(v, check=True, existence=False): S_4_5_7 = [X.intersection(S) for S in AF] S_4_5_7 = [S for S in S_4_5_7 if len(S) > 1] - S_4_5_7 = PairwiseBalancedDesign(X, - blocks=S_4_5_7, - K=[4, 5, 7], - check=False) + S_4_5_7 = PairwiseBalancedDesign(X, blocks=S_4_5_7, K=[4, 5, 7], check=False) S_4_5_7.relabel() return PBD_4_7_from_Y(S_4_5_7, check=check) @@ -652,21 +595,14 @@ def PBD_4_7(v, check=True, existence=False): # (42,{4,5},{1,2,7})-GDD or a (47,{4,5},{1,2,7})-GDD points_to_add = 2 if v == 127 else 7 rBIBD4 = v_4_1_rbibd(40) - GDD = [S+[40+i] if i < points_to_add else S - for i, classs in enumerate(rBIBD4._classes) - for S in classs] + GDD = [S + [40 + i] if i < points_to_add else S for i, classs in enumerate(rBIBD4._classes) for S in classs] if points_to_add == 7: GDD.append(list(range(40, 40 + points_to_add))) - groups = [[x] for x in range(40+points_to_add)] + groups = [[x] for x in range(40 + points_to_add)] else: groups = [[x] for x in range(40)] - groups.append(list(range(40, 40+points_to_add))) - GDD = GroupDivisibleDesign(40+points_to_add, - groups=groups, - blocks=GDD, - K=[2, 4, 5, 7], - check=False, - copy=False) + groups.append(list(range(40, 40 + points_to_add))) + GDD = GroupDivisibleDesign(40 + points_to_add, groups=groups, blocks=GDD, K=[2, 4, 5, 7], check=False, copy=False) return PBD_4_7_from_Y(GDD, check=check) @@ -687,6 +623,7 @@ def PBD_4_7(v, check=True, existence=False): return balanced_incomplete_block_design(v, 7) else: from sage.combinat.designs.orthogonal_arrays import orthogonal_array + # IX.4.5.m from [BJL99]. # # This construction takes a TD(5,g) and truncates its last column to @@ -697,26 +634,16 @@ def PBD_4_7(v, check=True, existence=False): # We write vv = 4g+u while satisfying the hypotheses. vv = (v - 1) // 3 for g in range((vv + 5 - 1) // 5, vv // 4 + 1): - u = vv-4*g - if (orthogonal_array(5, g, existence=True) is True and - PBD_4_7(3*g+1, existence=True) is True and - PBD_4_7(3*u+1, existence=True) is True): + u = vv - 4 * g + if orthogonal_array(5, g, existence=True) is True and PBD_4_7(3 * g + 1, existence=True) is True and PBD_4_7(3 * u + 1, existence=True) is True: from .orthogonal_arrays import transversal_design + domain = set(range(vv)) GDD = transversal_design(5, g) - GDD = GroupDivisibleDesign(vv, - groups=[[x for x in gr if x in domain] for gr in GDD.groups()], - blocks=[[x for x in B if x in domain] for B in GDD], - G=set([g, u]), - K=[4, 5], - check=False) + GDD = GroupDivisibleDesign(vv, groups=[[x for x in gr if x in domain] for gr in GDD.groups()], blocks=[[x for x in B if x in domain] for B in GDD], G=set([g, u]), K=[4, 5], check=False) return PBD_4_7_from_Y(GDD, check=check) - return PairwiseBalancedDesign(v, - blocks=blocks, - K=[4, 7], - check=check, - copy=False) + return PairwiseBalancedDesign(v, blocks=blocks, K=[4, 7], check=check, copy=False) def PBD_4_7_from_Y(gdd, check=True): @@ -762,25 +689,24 @@ def PBD_4_7_from_Y(gdd, check=True): """ from .group_divisible_designs import group_divisible_design from .bibd import PairwiseBalancedDesign + block_sizes = set(map(len, gdd._blocks)) group_sizes = set(map(len, gdd._groups)) if not block_sizes.issubset([4, 5, 7]): txt = list(block_sizes.difference([4, 5, 7])) - raise ValueError("The GDD should only contain blocks of size {{4,5,7}} " - "but there are other: {}".format(txt)) + raise ValueError("The GDD should only contain blocks of size {{4,5,7}} " "but there are other: {}".format(txt)) for gs in group_sizes: - if PBD_4_7(3*gs+1, existence=True) is not True: - raise RuntimeError("A group has size {} but I do not know how to " - "build a ({},[4,7])-PBD".format(gs, 3*gs+1)) + if PBD_4_7(3 * gs + 1, existence=True) is not True: + raise RuntimeError("A group has size {} but I do not know how to " "build a ({},[4,7])-PBD".format(gs, 3 * gs + 1)) GDD = {} # the GDD we will need if 4 in block_sizes: # GDD[4] = GDD_from_BIBD(3*4,4) - GDD[4] = group_divisible_design(3*4, K=[4], G=[3]) + GDD[4] = group_divisible_design(3 * 4, K=[4], G=[3]) if 5 in block_sizes: # GDD[5] = GDD_from_BIBD(3*5,4) - GDD[5] = group_divisible_design(3*5, K=[4], G=[3]) + GDD[5] = group_divisible_design(3 * 5, K=[4], G=[3]) if 7 in block_sizes: # It is obtained from a PBD_4_7(22) by removing a point only contained # in sets of size 4 @@ -796,18 +722,13 @@ def PBD_4_7_from_Y(gdd, check=True): # The blocks for B in gdd: for B_GDD in GDD[len(B)]: - PBD.append([3*B[x//3]+(x % 3) for x in B_GDD]) + PBD.append([3 * B[x // 3] + (x % 3) for x in B_GDD]) # The groups - group_PBD = {gs: PBD_4_7(3*gs+1) for gs in group_sizes} + group_PBD = {gs: PBD_4_7(3 * gs + 1) for gs in group_sizes} for G in gdd.groups(): gs = len(G) for B in group_PBD[gs]: - PBD.append([3*G[x//3]+(x % 3) if x < 3*gs else 3*gdd.n_points() - for x in B]) - - return PairwiseBalancedDesign(3*gdd.n_points()+1, - blocks=PBD, - K=[4, 7], - check=check, - copy=False) + PBD.append([3 * G[x // 3] + (x % 3) if x < 3 * gs else 3 * gdd.n_points() for x in B]) + + return PairwiseBalancedDesign(3 * gdd.n_points() + 1, blocks=PBD, K=[4, 7], check=check, copy=False) diff --git a/src/sage/combinat/designs/steiner_quadruple_systems.py b/src/sage/combinat/designs/steiner_quadruple_systems.py index aa3355dcda4..48eb33d52e1 100644 --- a/src/sage/combinat/designs/steiner_quadruple_systems.py +++ b/src/sage/combinat/designs/steiner_quadruple_systems.py @@ -59,6 +59,7 @@ Functions --------- """ + from itertools import repeat from sage.misc.cachefunc import cached_function from sage.combinat.designs.incidence_structures import IncidenceStructure @@ -87,19 +88,20 @@ def two_n(B): Y = [] # Line 1 - for x,y,z,t in B._blocks: + for x, y, z, t in B._blocks: for a in range(2): for b in range(2): for c in range(2): - d = (a+b+c) % 2 - Y.append([x+a*n,y+b*n,z+c*n,t+d*n]) + d = (a + b + c) % 2 + Y.append([x + a * n, y + b * n, z + c * n, t + d * n]) # Line 2 for j in range(n): - for jj in range(j+1,n): - Y.append([j,jj,n+j,n+jj]) + for jj in range(j + 1, n): + Y.append([j, jj, n + j, n + jj]) + + return IncidenceStructure(2 * n, Y, check=False, copy=False) - return IncidenceStructure(2*n,Y,check=False,copy=False) # Construction 2 @@ -122,41 +124,42 @@ def three_n_minus_two(B): ....: print("Something is wrong !") """ n = B.n_points() - A = n-1 + A = n - 1 Y = [] # relabel function - r = lambda i,x : (i % 3)*(n-1)+x - for x,y,z,t in B._blocks: + r = lambda i, x: (i % 3) * (n - 1) + x + for x, y, z, t in B._blocks: if t == A: # Line 2. for a in range(3): for b in range(3): - c = -(a+b) % 3 - Y.append([r(a,x),r(b,y),r(c,z),3*n-3]) + c = -(a + b) % 3 + Y.append([r(a, x), r(b, y), r(c, z), 3 * n - 3]) # Line 3. - Y.extend([[r(i,x),r(i,y),r(i+1,z),r(i+2,z)] for i in range(3)]) - Y.extend([[r(i,x),r(i,z),r(i+1,y),r(i+2,y)] for i in range(3)]) - Y.extend([[r(i,y),r(i,z),r(i+1,x),r(i+2,x)] for i in range(3)]) + Y.extend([[r(i, x), r(i, y), r(i + 1, z), r(i + 2, z)] for i in range(3)]) + Y.extend([[r(i, x), r(i, z), r(i + 1, y), r(i + 2, y)] for i in range(3)]) + Y.extend([[r(i, y), r(i, z), r(i + 1, x), r(i + 2, x)] for i in range(3)]) else: # Line 1. for a in range(3): for b in range(3): for c in range(3): - d = -(a+b+c) % 3 - Y.append([r(a,x),r(b,y),r(c,z),r(d,t)]) + d = -(a + b + c) % 3 + Y.append([r(a, x), r(b, y), r(c, z), r(d, t)]) # Line 4. - for j in range(n-1): - for jj in range(j+1,n-1): - Y.extend([[r(i,j),r(i,jj),r(i+1,j),r(i+1,jj)] for i in range(3)]) + for j in range(n - 1): + for jj in range(j + 1, n - 1): + Y.extend([[r(i, j), r(i, jj), r(i + 1, j), r(i + 1, jj)] for i in range(3)]) # Line 5. - for j in range(n-1): - Y.append([r(0,j),r(1,j),r(2,j),3*n-3]) + for j in range(n - 1): + Y.append([r(0, j), r(1, j), r(2, j), 3 * n - 3]) + + return IncidenceStructure(3 * n - 2, Y, check=False, copy=False) - return IncidenceStructure(3*n-2,Y,check=False,copy=False) # Construction 3 @@ -184,40 +187,41 @@ def three_n_minus_eight(B): raise ValueError("n must be equal to 2 mod 12") B = relabel_system(B) - r = lambda i,x : (i % 3)*(n-4)+(x % (n-4)) + r = lambda i, x: (i % 3) * (n - 4) + (x % (n - 4)) # Line 1. - Y = [[x+2*(n-4) for x in B._blocks[-1]]] + Y = [[x + 2 * (n - 4) for x in B._blocks[-1]]] # Line 2. for s in B._blocks[:-1]: for i in range(3): - Y.append([r(i,x) if x <= n-5 else x+2*(n-4) for x in s]) + Y.append([r(i, x) if x <= n - 5 else x + 2 * (n - 4) for x in s]) # Line 3. for a in range(4): - for aa in range(n-4): - for aaa in range(n-4): - aaaa = -(a+aa+aaa) % (n-4) - Y.append([r(0,aa),r(1,aaa), r(2,aaaa),3*(n-4)+a]) + for aa in range(n - 4): + for aaa in range(n - 4): + aaaa = -(a + aa + aaa) % (n - 4) + Y.append([r(0, aa), r(1, aaa), r(2, aaaa), 3 * (n - 4) + a]) # Line 4. - k = (n-14) // 12 + k = (n - 14) // 12 for i in range(3): - for b in range(n-4): - for bb in range(n-4): - bbb = -(b+bb) % (n-4) - for d in range(2*k+1): - Y.append([r(i+2,bbb), r(i, b+2*k+1+i*(4*k+2)-d) , r(i, b+2*k+2+i*(4*k+2)+d), r(i+1,bb)]) + for b in range(n - 4): + for bb in range(n - 4): + bbb = -(b + bb) % (n - 4) + for d in range(2 * k + 1): + Y.append([r(i + 2, bbb), r(i, b + 2 * k + 1 + i * (4 * k + 2) - d), r(i, b + 2 * k + 2 + i * (4 * k + 2) + d), r(i + 1, bb)]) # Line 5. for i in range(3): - for alpha in range(4*k+2, 12*k+9): - for ra,sa in P(alpha,6*k+5): - for raa,saa in P(alpha,6*k+5): - Y.append([r(i,ra),r(i,sa),r(i+1,raa), r(i+1,saa)]) + for alpha in range(4 * k + 2, 12 * k + 9): + for ra, sa in P(alpha, 6 * k + 5): + for raa, saa in P(alpha, 6 * k + 5): + Y.append([r(i, ra), r(i, sa), r(i + 1, raa), r(i + 1, saa)]) + + return IncidenceStructure(3 * n - 8, Y, check=False, copy=False) - return IncidenceStructure(3*n-8,Y,check=False,copy=False) # Construction 4 @@ -246,44 +250,46 @@ def three_n_minus_four(B): raise ValueError("n must be equal to 10 mod 12") B = relabel_system(B) - r = lambda i,x : (i % 3)*(n-2)+(x % (n-2)) + r = lambda i, x: (i % 3) * (n - 2) + (x % (n - 2)) # Line 1/2. Y = [] for s in B._blocks: for i in range(3): - Y.append([r(i,x) if x <= n-3 else x+2*(n-2) for x in s]) + Y.append([r(i, x) if x <= n - 3 else x + 2 * (n - 2) for x in s]) # Line 3. for a in range(2): - for aa in range(n-2): - for aaa in range(n-2): - aaaa = -(a+aa+aaa) % (n-2) - Y.append([r(0,aa),r(1,aaa), r(2,aaaa),3*(n-2)+a]) + for aa in range(n - 2): + for aaa in range(n - 2): + aaaa = -(a + aa + aaa) % (n - 2) + Y.append([r(0, aa), r(1, aaa), r(2, aaaa), 3 * (n - 2) + a]) # Line 4. - k = (n-10) // 12 + k = (n - 10) // 12 for i in range(3): - for b in range(n-2): - for bb in range(n-2): - bbb = -(b+bb) % (n-2) - for d in range(2*k+1): - Y.append([r(i+2,bbb), r(i, b+2*k+1+i*(4*k+2)-d) , r(i, b+2*k+2+i*(4*k+2)+d), r(i+1,bb)]) + for b in range(n - 2): + for bb in range(n - 2): + bbb = -(b + bb) % (n - 2) + for d in range(2 * k + 1): + Y.append([r(i + 2, bbb), r(i, b + 2 * k + 1 + i * (4 * k + 2) - d), r(i, b + 2 * k + 2 + i * (4 * k + 2) + d), r(i + 1, bb)]) # Line 5. from sage.graphs.graph_coloring import round_robin - one_factorization = round_robin(2*(6*k+4)).edges(sort=True) - color_classes = [[] for _ in repeat(None, 2*(6*k+4)-1)] + + one_factorization = round_robin(2 * (6 * k + 4)).edges(sort=True) + color_classes = [[] for _ in repeat(None, 2 * (6 * k + 4) - 1)] for u, v, l in one_factorization: - color_classes[l].append((u,v)) + color_classes[l].append((u, v)) for i in range(3): - for alpha in range(4*k+2, 12*k+6+1): - for ra,sa in P(alpha, 6*k+4): - for raa,saa in P(alpha, 6*k+4): - Y.append([r(i,ra),r(i,sa),r(i+1,raa), r(i+1,saa)]) + for alpha in range(4 * k + 2, 12 * k + 6 + 1): + for ra, sa in P(alpha, 6 * k + 4): + for raa, saa in P(alpha, 6 * k + 4): + Y.append([r(i, ra), r(i, sa), r(i + 1, raa), r(i + 1, saa)]) + + return IncidenceStructure(3 * n - 4, Y, check=False, copy=False) - return IncidenceStructure(3*n-4,Y,check=False,copy=False) # Construction 5 @@ -306,15 +312,15 @@ def four_n_minus_six(B): ....: print("Something is wrong !") """ n = B.n_points() - f = n-2 - r = lambda i,ii,x : (2*(i % 2)+(ii % 2))*(n-2)+(x) % (n-2) + f = n - 2 + r = lambda i, ii, x: (2 * (i % 2) + (ii % 2)) * (n - 2) + (x) % (n - 2) # Line 1. Y = [] for s in B._blocks: for i in range(2): for ii in range(2): - Y.append([r(i,ii,x) if x <= n-3 else x+3*(n-2) for x in s]) + Y.append([r(i, ii, x) if x <= n - 3 else x + 3 * (n - 2) for x in s]) # Line 2/3/4/5 k = f // 2 @@ -322,41 +328,42 @@ def four_n_minus_six(B): for eps in range(2): for c in range(k): for cc in range(k): - ccc = -(c+cc) % k - Y.append([4*(n-2)+l, r(0,0,2*c) , r(0,1,2*cc-eps) , r(1,eps,2*ccc+l) ]) - Y.append([4*(n-2)+l, r(0,0,2*c+1), r(0,1,2*cc-1-eps), r(1,eps,2*ccc+1-l)]) - Y.append([4*(n-2)+l, r(1,0,2*c) , r(1,1,2*cc-eps) , r(0,eps,2*ccc+1-l)]) - Y.append([4*(n-2)+l, r(1,0,2*c+1), r(1,1,2*cc-1-eps), r(0,eps,2*ccc+l) ]) + ccc = -(c + cc) % k + Y.append([4 * (n - 2) + l, r(0, 0, 2 * c), r(0, 1, 2 * cc - eps), r(1, eps, 2 * ccc + l)]) + Y.append([4 * (n - 2) + l, r(0, 0, 2 * c + 1), r(0, 1, 2 * cc - 1 - eps), r(1, eps, 2 * ccc + 1 - l)]) + Y.append([4 * (n - 2) + l, r(1, 0, 2 * c), r(1, 1, 2 * cc - eps), r(0, eps, 2 * ccc + 1 - l)]) + Y.append([4 * (n - 2) + l, r(1, 0, 2 * c + 1), r(1, 1, 2 * cc - 1 - eps), r(0, eps, 2 * ccc + l)]) # Line 6/7 for h in range(2): for eps in range(2): for ccc in range(k): - assert len(barP(ccc,k)) == k-1 - for rc,sc in barP(ccc,k): + assert len(barP(ccc, k)) == k - 1 + for rc, sc in barP(ccc, k): for c in range(k): - cc = -(c+ccc) % k - Y.append([r(h,0,2*c+eps) , r(h,1,2*cc-eps), r(h+1,0,rc), r(h+1,0,sc)]) - Y.append([r(h,0,2*c-1+eps), r(h,1,2*cc-eps), r(h+1,1,rc), r(h+1,1,sc)]) + cc = -(c + ccc) % k + Y.append([r(h, 0, 2 * c + eps), r(h, 1, 2 * cc - eps), r(h + 1, 0, rc), r(h + 1, 0, sc)]) + Y.append([r(h, 0, 2 * c - 1 + eps), r(h, 1, 2 * cc - eps), r(h + 1, 1, rc), r(h + 1, 1, sc)]) # Line 8/9 for h in range(2): for eps in range(2): for ccc in range(k): - for rc,sc in barP(k+ccc,k): + for rc, sc in barP(k + ccc, k): for c in range(k): - cc = -(c+ccc) % k - Y.append([r(h,0,2*c+eps) , r(h,1,2*cc-eps), r(h+1,1,rc), r(h+1,1,sc)]) - Y.append([r(h,0,2*c-1+eps), r(h,1,2*cc-eps), r(h+1,0,rc), r(h+1,0,sc)]) + cc = -(c + ccc) % k + Y.append([r(h, 0, 2 * c + eps), r(h, 1, 2 * cc - eps), r(h + 1, 1, rc), r(h + 1, 1, sc)]) + Y.append([r(h, 0, 2 * c - 1 + eps), r(h, 1, 2 * cc - eps), r(h + 1, 0, rc), r(h + 1, 0, sc)]) # Line 10 for h in range(2): - for alpha in range(n-3): - for ra,sa in P(alpha,k): - for raa,saa in P(alpha,k): - Y.append([r(h,0,ra),r(h,0,sa),r(h,1,raa),r(h,1,saa)]) + for alpha in range(n - 3): + for ra, sa in P(alpha, k): + for raa, saa in P(alpha, k): + Y.append([r(h, 0, ra), r(h, 0, sa), r(h, 1, raa), r(h, 1, saa)]) + + return IncidenceStructure(4 * n - 6, Y, check=False, copy=False) - return IncidenceStructure(4*n-6,Y,check=False,copy=False) # Construction 6 @@ -380,62 +387,62 @@ def twelve_n_minus_ten(B): """ n = B.n_points() B14 = steiner_quadruple_system(14) - r = lambda i,x : i % (n-1)+(x % 12)*(n-1) + r = lambda i, x: i % (n - 1) + (x % 12) * (n - 1) # Line 1. Y = [] for s in B14._blocks: - for i in range(n-1): - Y.append([r(i,x) if x <= 11 else r(n-2,11)+x-11 for x in s]) + for i in range(n - 1): + Y.append([r(i, x) if x <= 11 else r(n - 2, 11) + x - 11 for x in s]) for s in B._blocks: - if s[-1] == n-1: - u,v,w,B = s - dd = {0:u,1:v,2:w} - d = lambda x:dd[x % 3] + if s[-1] == n - 1: + u, v, w, B = s + dd = {0: u, 1: v, 2: w} + d = lambda x: dd[x % 3] for b in range(12): for bb in range(12): - bbb = -(b+bb) % 12 + bbb = -(b + bb) % 12 for h in range(2): # Line 2 - Y.append([r(n-2,11)+1+h,r(u,b),r(v,bb),r(w,bbb+3*h)]) + Y.append([r(n - 2, 11) + 1 + h, r(u, b), r(v, bb), r(w, bbb + 3 * h)]) for i in range(3): # Line 38.3 - Y.append([r(d(i),b+4+i), r(d(i),b+7+i), r(d(i+1),bb), r(d(i+2),bbb)]) + Y.append([r(d(i), b + 4 + i), r(d(i), b + 7 + i), r(d(i + 1), bb), r(d(i + 2), bbb)]) for j in range(12): for eps in range(2): for i in range(3): # Line 38.4-38.7 - Y.append([ r(d(i),j), r(d(i+1),j+6*eps ), r(d(i+2),6*eps-2*j+1), r(d(i+2),6*eps-2*j-1)]) - Y.append([ r(d(i),j), r(d(i+1),j+6*eps ), r(d(i+2),6*eps-2*j+2), r(d(i+2),6*eps-2*j-2)]) - Y.append([ r(d(i),j), r(d(i+1),j+6*eps-3), r(d(i+2),6*eps-2*j+1), r(d(i+2),6*eps-2*j+2)]) - Y.append([ r(d(i),j), r(d(i+1),j+6*eps+3), r(d(i+2),6*eps-2*j-1), r(d(i+2),6*eps-2*j-2)]) + Y.append([r(d(i), j), r(d(i + 1), j + 6 * eps), r(d(i + 2), 6 * eps - 2 * j + 1), r(d(i + 2), 6 * eps - 2 * j - 1)]) + Y.append([r(d(i), j), r(d(i + 1), j + 6 * eps), r(d(i + 2), 6 * eps - 2 * j + 2), r(d(i + 2), 6 * eps - 2 * j - 2)]) + Y.append([r(d(i), j), r(d(i + 1), j + 6 * eps - 3), r(d(i + 2), 6 * eps - 2 * j + 1), r(d(i + 2), 6 * eps - 2 * j + 2)]) + Y.append([r(d(i), j), r(d(i + 1), j + 6 * eps + 3), r(d(i + 2), 6 * eps - 2 * j - 1), r(d(i + 2), 6 * eps - 2 * j - 2)]) for j in range(6): for i in range(3): for eps in range(2): # Line 38.8 - Y.append([ r(d(i),j), r(d(i),j+6), r(d(i+1),j+3*eps), r(d(i+1),j+6+3*eps)]) + Y.append([r(d(i), j), r(d(i), j + 6), r(d(i + 1), j + 3 * eps), r(d(i + 1), j + 6 + 3 * eps)]) for j in range(12): for i in range(3): for eps in range(4): # Line 38.11 - Y.append([ r(d(i),j), r(d(i),j+1), r(d(i+1),j+3*eps), r(d(i+1),j+3*eps+1)]) + Y.append([r(d(i), j), r(d(i), j + 1), r(d(i + 1), j + 3 * eps), r(d(i + 1), j + 3 * eps + 1)]) # Line 38.12 - Y.append([ r(d(i),j), r(d(i),j+2), r(d(i+1),j+3*eps), r(d(i+1),j+3*eps+2)]) + Y.append([r(d(i), j), r(d(i), j + 2), r(d(i + 1), j + 3 * eps), r(d(i + 1), j + 3 * eps + 2)]) # Line 38.13 - Y.append([ r(d(i),j), r(d(i),j+4), r(d(i+1),j+3*eps), r(d(i+1),j+3*eps+4)]) + Y.append([r(d(i), j), r(d(i), j + 4), r(d(i + 1), j + 3 * eps), r(d(i + 1), j + 3 * eps + 4)]) - for alpha in [4,5]: - for ra,sa in P(alpha,6): - for raa,saa in P(alpha,6): + for alpha in [4, 5]: + for ra, sa in P(alpha, 6): + for raa, saa in P(alpha, 6): for i in range(3): - for ii in range(i+1,3): + for ii in range(i + 1, 3): # Line 38.14 - Y.append([ r(d(i),ra), r(d(i),sa), r(d(ii),raa), r(d(ii),saa)]) + Y.append([r(d(i), ra), r(d(i), sa), r(d(ii), raa), r(d(ii), saa)]) for g in range(6): for eps in range(2): @@ -444,19 +451,19 @@ def twelve_n_minus_ten(B): if i == ii: continue # Line 38.9 - Y.append([ r(d(i),2*g+3*eps), r(d(i),2*g+6+3*eps), r(d(ii),2*g+1), r(d(ii),2*g+5)]) + Y.append([r(d(i), 2 * g + 3 * eps), r(d(i), 2 * g + 6 + 3 * eps), r(d(ii), 2 * g + 1), r(d(ii), 2 * g + 5)]) # Line 38.10 - Y.append([ r(d(i),2*g+3*eps), r(d(i),2*g+6+3*eps), r(d(ii),2*g+2), r(d(ii),2*g+4)]) + Y.append([r(d(i), 2 * g + 3 * eps), r(d(i), 2 * g + 6 + 3 * eps), r(d(ii), 2 * g + 2), r(d(ii), 2 * g + 4)]) else: - x,y,z,t = s + x, y, z, t = s for a in range(12): for aa in range(12): for aaa in range(12): - aaaa = -(a+aa+aaa) % 12 + aaaa = -(a + aa + aaa) % 12 # Line 3 - Y.append([r(x,a), r(y,aa), r(z,aaa), r(t,aaaa)]) - return IncidenceStructure(12*n-10,Y,check=False,copy=False) + Y.append([r(x, a), r(y, aa), r(z, aaa), r(t, aaaa)]) + return IncidenceStructure(12 * n - 10, Y, check=False, copy=False) def relabel_system(B): @@ -477,22 +484,17 @@ def relabel_system(B): n = B.n_points() B0 = B._blocks[0] - label = { - B0[0] : n-4, - B0[1] : n-3, - B0[2] : n-2, - B0[3] : n-1 - } + label = {B0[0]: n - 4, B0[1]: n - 3, B0[2]: n - 2, B0[3]: n - 1} def get_label(x): if x in label: return label[x] - total = len(label)-4 + total = len(label) - 4 label[x] = total return total B = [[get_label(_) for _ in s] for s in B] - return IncidenceStructure(n,B) + return IncidenceStructure(n, B) def P(alpha, m): @@ -507,30 +509,30 @@ def P(alpha, m): sage: P(3,4) [(0, 5), (2, 7), (4, 1), (6, 3)] """ - if alpha >= 2*m-1: + if alpha >= 2 * m - 1: raise Exception if m % 2 == 0: if alpha < m: if alpha % 2 == 0: b = alpha // 2 - return [(2*a, (2*a + 2*b + 1) % (2*m)) for a in range(m)] - b = (alpha-1) // 2 - return [(2*a, (2*a - 2*b - 1) % (2*m)) for a in range(m)] + return [(2 * a, (2 * a + 2 * b + 1) % (2 * m)) for a in range(m)] + b = (alpha - 1) // 2 + return [(2 * a, (2 * a - 2 * b - 1) % (2 * m)) for a in range(m)] y = alpha - m - pairs = [(b,(2*y-b) % (2*m)) for b in range(y)] - pairs += [(c,(2*m+2*y-c-2) % (2*m)) for c in range(2*y+1,m+y-1)] - pairs += [(2*m+int(-1.5-.5*(-1)**y),y),(2*m+int(-1.5+.5*(-1)**y),m+y-1)] + pairs = [(b, (2 * y - b) % (2 * m)) for b in range(y)] + pairs += [(c, (2 * m + 2 * y - c - 2) % (2 * m)) for c in range(2 * y + 1, m + y - 1)] + pairs += [(2 * m + int(-1.5 - 0.5 * (-1) ** y), y), (2 * m + int(-1.5 + 0.5 * (-1) ** y), m + y - 1)] return pairs - if alpha < m-1: + if alpha < m - 1: if alpha % 2 == 0: b = alpha // 2 - return [(2*a,(2*a+2*b+1) % (2*m)) for a in range(m)] - b = (alpha-1) // 2 - return [(2*a,(2*a-2*b-1) % (2*m)) for a in range(m)] - y = alpha-m+1 - pairs = [(b,2*y-b) for b in range(y)] - pairs += [(c,2*m+2*y-c) for c in range(2*y+1,m+y)] - pairs += [(y,m+y)] + return [(2 * a, (2 * a + 2 * b + 1) % (2 * m)) for a in range(m)] + b = (alpha - 1) // 2 + return [(2 * a, (2 * a - 2 * b - 1) % (2 * m)) for a in range(m)] + y = alpha - m + 1 + pairs = [(b, 2 * y - b) for b in range(y)] + pairs += [(c, 2 * m + 2 * y - c) for c in range(2 * y + 1, m + y)] + pairs += [(y, m + y)] return pairs @@ -587,7 +589,7 @@ def barP_system(m): [(0, 4), (3, 5), (1, 2)], [(0, 1), (2, 3), (4, 5)]] """ - isequal = lambda e1,e2 : e1 == e2 or e1 == tuple(reversed(e2)) + isequal = lambda e1, e2: e1 == e2 or e1 == tuple(reversed(e2)) pairs = [] last = [] @@ -595,43 +597,43 @@ def barP_system(m): # The first (shorter) collections of pairs, obtained from P by removing # pairs. Those are added to 'last', a new list of pairs last = [] - for n in range(1, (m-2)//2+1): - pairs.append([p for p in P(2*n,m) if not isequal(p,(2*n,(4*n+1) % (2*m)))]) - last.append((2*n,(4*n+1) % (2*m))) - pairs.append([p for p in P(2*n-1,m) if not isequal(p,(2*m-2-2*n,2*m-1-4*n))]) - last.append((2*m-2-2*n,2*m-1-4*n)) - - pairs.append([p for p in P(m,m) if not isequal(p,(2*m-2,0))]) - last.append((2*m-2,0)) - pairs.append([p for p in P(m+1,m) if not isequal(p,(2*m-1,1))]) - last.append((2*m-1,1)) - - assert all(len(pp) == m-1 for pp in pairs) + for n in range(1, (m - 2) // 2 + 1): + pairs.append([p for p in P(2 * n, m) if not isequal(p, (2 * n, (4 * n + 1) % (2 * m)))]) + last.append((2 * n, (4 * n + 1) % (2 * m))) + pairs.append([p for p in P(2 * n - 1, m) if not isequal(p, (2 * m - 2 - 2 * n, 2 * m - 1 - 4 * n))]) + last.append((2 * m - 2 - 2 * n, 2 * m - 1 - 4 * n)) + + pairs.append([p for p in P(m, m) if not isequal(p, (2 * m - 2, 0))]) + last.append((2 * m - 2, 0)) + pairs.append([p for p in P(m + 1, m) if not isequal(p, (2 * m - 1, 1))]) + last.append((2 * m - 1, 1)) + + assert all(len(pp) == m - 1 for pp in pairs) assert len(last) == m # Pairs of normal length - pairs.append(P(0,m)) - pairs.append(P(m-1,m)) + pairs.append(P(0, m)) + pairs.append(P(m - 1, m)) - for alpha in range(m+2,2*m-1): - pairs.append(P(alpha,m)) + for alpha in range(m + 2, 2 * m - 1): + pairs.append(P(alpha, m)) pairs.append(last) - assert len(pairs) == 2*m + assert len(pairs) == 2 * m # Now the points must be relabeled relabel = {} - for n in range(1, (m-2)//2+1): - relabel[2*n] = (4*n) % (2*m) - relabel[4*n+1] = (4*n+1) % (2*m) - relabel[2*m-2-2*n] = (4*n-2) % (2*m) - relabel[2*m-1-4*n] = (4*n-1) % (2*m) + for n in range(1, (m - 2) // 2 + 1): + relabel[2 * n] = (4 * n) % (2 * m) + relabel[4 * n + 1] = (4 * n + 1) % (2 * m) + relabel[2 * m - 2 - 2 * n] = (4 * n - 2) % (2 * m) + relabel[2 * m - 1 - 4 * n] = (4 * n - 1) % (2 * m) - relabel[2*m-2] = (1) % (2*m) + relabel[2 * m - 2] = (1) % (2 * m) relabel[0] = 0 - relabel[2*m-1] = 2*m-1 - relabel[1] = 2*m-2 + relabel[2 * m - 1] = 2 * m - 1 + relabel[1] = 2 * m - 2 else: # The first (shorter) collections of pairs, obtained from P by removing @@ -639,45 +641,45 @@ def barP_system(m): last = [] for n in range((m - 3) // 2 + 1): - pairs.append([p for p in P(2*n,m) if not isequal(p,(2*n,(4*n+1) % (2*m)))]) - last.append((2*n,(4*n+1) % (2*m))) - pairs.append([p for p in P(2*n+1,m) if not isequal(p,(2*m-2-2*n,2*m-3-4*n))]) - last.append((2*m-2-2*n,2*m-3-4*n)) + pairs.append([p for p in P(2 * n, m) if not isequal(p, (2 * n, (4 * n + 1) % (2 * m)))]) + last.append((2 * n, (4 * n + 1) % (2 * m))) + pairs.append([p for p in P(2 * n + 1, m) if not isequal(p, (2 * m - 2 - 2 * n, 2 * m - 3 - 4 * n))]) + last.append((2 * m - 2 - 2 * n, 2 * m - 3 - 4 * n)) - pairs.append([p for p in P(2*m-2,m) if not isequal(p,(m-1,2*m-1))]) - last.append((m-1,2*m-1)) + pairs.append([p for p in P(2 * m - 2, m) if not isequal(p, (m - 1, 2 * m - 1))]) + last.append((m - 1, 2 * m - 1)) - assert all(len(pp) == m-1 for pp in pairs) + assert all(len(pp) == m - 1 for pp in pairs) assert len(pairs) == m # Pairs of normal length - for alpha in range(m-1,2*m-2): - pairs.append(P(alpha,m)) + for alpha in range(m - 1, 2 * m - 2): + pairs.append(P(alpha, m)) pairs.append(last) - assert len(pairs) == 2*m + assert len(pairs) == 2 * m # Now the points must be relabeled relabel = {} for n in range((m - 3) // 2 + 1): - relabel[2*n] = (4*n) % (2*m) - relabel[4*n+1] = (4*n+1) % (2*m) - relabel[2*m-2-2*n] = (4*n+2) % (2*m) - relabel[2*m-3-4*n] = (4*n+3) % (2*m) - relabel[m-1] = (2*m-2) % (2*m) - relabel[2*m-1] = 2*m-1 + relabel[2 * n] = (4 * n) % (2 * m) + relabel[4 * n + 1] = (4 * n + 1) % (2 * m) + relabel[2 * m - 2 - 2 * n] = (4 * n + 2) % (2 * m) + relabel[2 * m - 3 - 4 * n] = (4 * n + 3) % (2 * m) + relabel[m - 1] = (2 * m - 2) % (2 * m) + relabel[2 * m - 1] = 2 * m - 1 - assert len(relabel) == 2*m - assert len(pairs) == 2*m + assert len(relabel) == 2 * m + assert len(pairs) == 2 * m # Relabeling the points - pairs = [[(relabel[x],relabel[y]) for x,y in pp] for pp in pairs] + pairs = [[(relabel[x], relabel[y]) for x, y in pp] for pp in pairs] # Pairs are sorted first according to their cardinality, then using the # number of the smallest point that they do NOT contain. - pairs.sort(key=lambda x: _missing_pair(2*m+1,x)) + pairs.sort(key=lambda x: _missing_pair(2 * m + 1, x)) return pairs @@ -718,7 +720,7 @@ def steiner_quadruple_system(n, check=False): if (n % 6) not in [2, 4]: raise ValueError("n mod 6 must be equal to 2 or 4") elif n == 4: - sqs = IncidenceStructure(4, [[0,1,2,3]], copy=False, check=False) + sqs = IncidenceStructure(4, [[0, 1, 2, 3]], copy=False, check=False) elif n == 14: sqs = IncidenceStructure(14, _SQS14(), copy=False, check=False) elif n == 38: @@ -726,25 +728,25 @@ def steiner_quadruple_system(n, check=False): elif n % 12 in [4, 8]: nn = n // 2 sqs = two_n(steiner_quadruple_system(nn, check=False)) - elif n % 18 in [4,10]: - nn = (n+2) // 3 + elif n % 18 in [4, 10]: + nn = (n + 2) // 3 sqs = three_n_minus_two(steiner_quadruple_system(nn, check=False)) elif (n % 36) == 34: - nn = (n+8) // 3 + nn = (n + 8) // 3 sqs = three_n_minus_eight(steiner_quadruple_system(nn, check=False)) elif (n % 36) == 26: - nn = (n+4) // 3 + nn = (n + 4) // 3 sqs = three_n_minus_four(steiner_quadruple_system(nn, check=False)) elif n % 24 in [2, 10]: - nn = (n+6) // 4 + nn = (n + 6) // 4 sqs = four_n_minus_six(steiner_quadruple_system(nn, check=False)) elif n % 72 in [14, 38]: - nn = (n+10) // 12 + nn = (n + 10) // 12 sqs = twelve_n_minus_ten(steiner_quadruple_system(nn, check=False)) else: raise ValueError("this should never happen") - if check and not sqs.is_t_design(3,n,4,1): + if check and not sqs.is_t_design(3, n, 4, 1): raise RuntimeError("something is very very wrong") return sqs @@ -763,25 +765,99 @@ def _SQS14(): sage: sqs14.is_t_design(3,14,4,1) True """ - return [[0, 1, 2, 5], [0, 1, 3, 6], [0, 1, 4, 13], [0, 1, 7, 10], [0, 1, 8, 9], - [0, 1, 11, 12], [0, 2, 3, 4], [0, 2, 6, 12], [0, 2, 7, 9], [0, 2, 8, 11], - [0, 2, 10, 13], [0, 3, 5, 13], [0, 3, 7, 11], [0, 3, 8, 10], [0, 3, 9, 12], - [0, 4, 5, 9], [0, 4, 6, 11], [0, 4, 7, 8], [0, 4, 10, 12], [0, 5, 6, 8], - [0, 5, 7, 12], [0, 5, 10, 11], [0, 6, 7, 13], [0, 6, 9, 10], [0, 8, 12, 13], - [0, 9, 11, 13], [1, 2, 3, 13], [1, 2, 4, 12], [1, 2, 6, 9], [1, 2, 7, 11], - [1, 2, 8, 10], [1, 3, 4, 5], [1, 3, 7, 8], [1, 3, 9, 11], [1, 3, 10, 12], - [1, 4, 6, 10], [1, 4, 7, 9], [1, 4, 8, 11], [1, 5, 6, 11], [1, 5, 7, 13], - [1, 5, 8, 12], [1, 5, 9, 10], [1, 6, 7, 12], [1, 6, 8, 13], [1, 9, 12, 13], - [1, 10, 11, 13], [2, 3, 5, 11], [2, 3, 6, 7], [2, 3, 8, 12], [2, 3, 9, 10], - [2, 4, 5, 13], [2, 4, 6, 8], [2, 4, 7, 10], [2, 4, 9, 11], [2, 5, 6, 10], - [2, 5, 7, 8], [2, 5, 9, 12], [2, 6, 11, 13], [2, 7, 12, 13], [2, 8, 9, 13], - [2, 10, 11, 12], [3, 4, 6, 9], [3, 4, 7, 12], [3, 4, 8, 13], [3, 4, 10, 11], - [3, 5, 6, 12], [3, 5, 7, 10], [3, 5, 8, 9], [3, 6, 8, 11], [3, 6, 10, 13], - [3, 7, 9, 13], [3, 11, 12, 13], [4, 5, 6, 7], [4, 5, 8, 10], [4, 5, 11, 12], - [4, 6, 12, 13], [4, 7, 11, 13], [4, 8, 9, 12], [4, 9, 10, 13], [5, 6, 9, 13], - [5, 7, 9, 11], [5, 8, 11, 13], [5, 10, 12, 13], [6, 7, 8, 9], [6, 7, 10, 11], - [6, 8, 10, 12], [6, 9, 11, 12], [7, 8, 10, 13], [7, 8, 11, 12], [7, 9, 10, 12], - [8, 9, 10, 11]] + return [ + [0, 1, 2, 5], + [0, 1, 3, 6], + [0, 1, 4, 13], + [0, 1, 7, 10], + [0, 1, 8, 9], + [0, 1, 11, 12], + [0, 2, 3, 4], + [0, 2, 6, 12], + [0, 2, 7, 9], + [0, 2, 8, 11], + [0, 2, 10, 13], + [0, 3, 5, 13], + [0, 3, 7, 11], + [0, 3, 8, 10], + [0, 3, 9, 12], + [0, 4, 5, 9], + [0, 4, 6, 11], + [0, 4, 7, 8], + [0, 4, 10, 12], + [0, 5, 6, 8], + [0, 5, 7, 12], + [0, 5, 10, 11], + [0, 6, 7, 13], + [0, 6, 9, 10], + [0, 8, 12, 13], + [0, 9, 11, 13], + [1, 2, 3, 13], + [1, 2, 4, 12], + [1, 2, 6, 9], + [1, 2, 7, 11], + [1, 2, 8, 10], + [1, 3, 4, 5], + [1, 3, 7, 8], + [1, 3, 9, 11], + [1, 3, 10, 12], + [1, 4, 6, 10], + [1, 4, 7, 9], + [1, 4, 8, 11], + [1, 5, 6, 11], + [1, 5, 7, 13], + [1, 5, 8, 12], + [1, 5, 9, 10], + [1, 6, 7, 12], + [1, 6, 8, 13], + [1, 9, 12, 13], + [1, 10, 11, 13], + [2, 3, 5, 11], + [2, 3, 6, 7], + [2, 3, 8, 12], + [2, 3, 9, 10], + [2, 4, 5, 13], + [2, 4, 6, 8], + [2, 4, 7, 10], + [2, 4, 9, 11], + [2, 5, 6, 10], + [2, 5, 7, 8], + [2, 5, 9, 12], + [2, 6, 11, 13], + [2, 7, 12, 13], + [2, 8, 9, 13], + [2, 10, 11, 12], + [3, 4, 6, 9], + [3, 4, 7, 12], + [3, 4, 8, 13], + [3, 4, 10, 11], + [3, 5, 6, 12], + [3, 5, 7, 10], + [3, 5, 8, 9], + [3, 6, 8, 11], + [3, 6, 10, 13], + [3, 7, 9, 13], + [3, 11, 12, 13], + [4, 5, 6, 7], + [4, 5, 8, 10], + [4, 5, 11, 12], + [4, 6, 12, 13], + [4, 7, 11, 13], + [4, 8, 9, 12], + [4, 9, 10, 13], + [5, 6, 9, 13], + [5, 7, 9, 11], + [5, 8, 11, 13], + [5, 10, 12, 13], + [6, 7, 8, 9], + [6, 7, 10, 11], + [6, 8, 10, 12], + [6, 9, 11, 12], + [7, 8, 10, 13], + [7, 8, 11, 12], + [7, 9, 10, 12], + [8, 9, 10, 11], + ] def _SQS38(): @@ -798,502 +874,2114 @@ def _SQS38(): True """ # From the La Jolla Covering Repository - return [[0, 1, 2, 14], [0, 1, 3, 34], [0, 1, 4, 31], [0, 1, 5, 27], [0, 1, 6, 17], - [0, 1, 7, 12], [0, 1, 8, 36], [0, 1, 9, 10], [0, 1, 11, 18], [0, 1, 13, 37], - [0, 1, 15, 35], [0, 1, 16, 22], [0, 1, 19, 33], [0, 1, 20, 25], [0, 1, 21, 23], - [0, 1, 24, 32], [0, 1, 26, 28], [0, 1, 29, 30], [0, 2, 3, 10], [0, 2, 4, 9], - [0, 2, 5, 28], [0, 2, 6, 15], [0, 2, 7, 36], [0, 2, 8, 23], [0, 2, 11, 22], - [0, 2, 12, 13], [0, 2, 16, 25], [0, 2, 17, 18], [0, 2, 19, 30], [0, 2, 20, 35], - [0, 2, 21, 29], [0, 2, 24, 34], [0, 2, 26, 31], [0, 2, 27, 32], [0, 2, 33, 37], - [0, 3, 4, 18], [0, 3, 5, 23], [0, 3, 6, 32], [0, 3, 7, 19], [0, 3, 8, 20], - [0, 3, 9, 17], [0, 3, 11, 25], [0, 3, 12, 24], [0, 3, 13, 27], [0, 3, 14, 31], - [0, 3, 15, 22], [0, 3, 16, 28], [0, 3, 21, 33], [0, 3, 26, 36], [0, 3, 29, 35], - [0, 3, 30, 37], [0, 4, 5, 7], [0, 4, 6, 28], [0, 4, 8, 25], [0, 4, 10, 30], - [0, 4, 11, 20], [0, 4, 12, 32], [0, 4, 13, 36], [0, 4, 14, 29], [0, 4, 15, 27], - [0, 4, 16, 35], [0, 4, 17, 22], [0, 4, 19, 23], [0, 4, 21, 34], [0, 4, 24, 33], - [0, 4, 26, 37], [0, 5, 6, 24], [0, 5, 8, 26], [0, 5, 9, 29], [0, 5, 10, 20], - [0, 5, 11, 13], [0, 5, 12, 14], [0, 5, 15, 33], [0, 5, 16, 37], [0, 5, 17, 35], - [0, 5, 18, 19], [0, 5, 21, 25], [0, 5, 22, 30], [0, 5, 31, 32], [0, 5, 34, 36], - [0, 6, 7, 30], [0, 6, 8, 33], [0, 6, 9, 12], [0, 6, 10, 18], [0, 6, 11, 37], - [0, 6, 13, 31], [0, 6, 14, 35], [0, 6, 16, 29], [0, 6, 19, 25], [0, 6, 20, 27], - [0, 6, 21, 36], [0, 6, 22, 23], [0, 6, 26, 34], [0, 7, 8, 11], [0, 7, 9, 33], - [0, 7, 10, 21], [0, 7, 13, 20], [0, 7, 14, 22], [0, 7, 15, 31], [0, 7, 16, 34], - [0, 7, 17, 29], [0, 7, 18, 24], [0, 7, 23, 26], [0, 7, 25, 32], [0, 7, 27, 28], - [0, 7, 35, 37], [0, 8, 9, 37], [0, 8, 10, 27], [0, 8, 12, 18], [0, 8, 13, 30], - [0, 8, 14, 15], [0, 8, 16, 21], [0, 8, 17, 19], [0, 8, 22, 35], [0, 8, 24, 31], - [0, 8, 28, 34], [0, 8, 29, 32], [0, 9, 11, 30], [0, 9, 13, 23], [0, 9, 14, 18], - [0, 9, 15, 25], [0, 9, 16, 26], [0, 9, 19, 28], [0, 9, 20, 36], [0, 9, 21, 35], - [0, 9, 22, 24], [0, 9, 27, 31], [0, 9, 32, 34], [0, 10, 11, 36], - [0, 10, 12, 15], [0, 10, 13, 26], [0, 10, 14, 16], [0, 10, 17, 37], - [0, 10, 19, 29], [0, 10, 22, 31], [0, 10, 23, 32], [0, 10, 24, 35], - [0, 10, 25, 34], [0, 10, 28, 33], [0, 11, 12, 16], [0, 11, 14, 24], - [0, 11, 15, 26], [0, 11, 17, 31], [0, 11, 19, 21], [0, 11, 23, 34], - [0, 11, 27, 29], [0, 11, 28, 35], [0, 11, 32, 33], [0, 12, 17, 20], - [0, 12, 19, 35], [0, 12, 21, 28], [0, 12, 22, 25], [0, 12, 23, 27], - [0, 12, 26, 29], [0, 12, 30, 33], [0, 12, 31, 34], [0, 12, 36, 37], - [0, 13, 14, 33], [0, 13, 15, 29], [0, 13, 16, 24], [0, 13, 17, 21], - [0, 13, 18, 34], [0, 13, 19, 32], [0, 13, 22, 28], [0, 13, 25, 35], - [0, 14, 17, 26], [0, 14, 19, 20], [0, 14, 21, 32], [0, 14, 23, 36], - [0, 14, 25, 28], [0, 14, 27, 30], [0, 14, 34, 37], [0, 15, 16, 36], - [0, 15, 17, 23], [0, 15, 18, 20], [0, 15, 19, 34], [0, 15, 21, 37], - [0, 15, 24, 28], [0, 15, 30, 32], [0, 16, 17, 32], [0, 16, 18, 27], - [0, 16, 19, 31], [0, 16, 20, 33], [0, 16, 23, 30], [0, 17, 24, 27], - [0, 17, 25, 33], [0, 17, 28, 36], [0, 17, 30, 34], [0, 18, 21, 26], - [0, 18, 22, 29], [0, 18, 23, 28], [0, 18, 25, 31], [0, 18, 30, 35], - [0, 18, 32, 37], [0, 18, 33, 36], [0, 19, 22, 26], [0, 19, 24, 37], - [0, 19, 27, 36], [0, 20, 21, 31], [0, 20, 22, 37], [0, 20, 23, 24], - [0, 20, 26, 30], [0, 20, 28, 32], [0, 20, 29, 34], [0, 21, 22, 27], - [0, 21, 24, 30], [0, 22, 32, 36], [0, 22, 33, 34], [0, 23, 25, 29], - [0, 23, 31, 37], [0, 23, 33, 35], [0, 24, 25, 26], [0, 24, 29, 36], - [0, 25, 27, 37], [0, 25, 30, 36], [0, 26, 27, 33], [0, 26, 32, 35], - [0, 27, 34, 35], [0, 28, 29, 37], [0, 28, 30, 31], [0, 29, 31, 33], - [0, 31, 35, 36], [1, 2, 3, 15], [1, 2, 4, 35], [1, 2, 5, 32], [1, 2, 6, 28], - [1, 2, 7, 18], [1, 2, 8, 13], [1, 2, 9, 37], [1, 2, 10, 11], [1, 2, 12, 19], - [1, 2, 16, 36], [1, 2, 17, 23], [1, 2, 20, 34], [1, 2, 21, 26], [1, 2, 22, 24], - [1, 2, 25, 33], [1, 2, 27, 29], [1, 2, 30, 31], [1, 3, 4, 11], [1, 3, 5, 10], - [1, 3, 6, 29], [1, 3, 7, 16], [1, 3, 8, 37], [1, 3, 9, 24], [1, 3, 12, 23], - [1, 3, 13, 14], [1, 3, 17, 26], [1, 3, 18, 19], [1, 3, 20, 31], [1, 3, 21, 36], - [1, 3, 22, 30], [1, 3, 25, 35], [1, 3, 27, 32], [1, 3, 28, 33], [1, 4, 5, 19], - [1, 4, 6, 24], [1, 4, 7, 33], [1, 4, 8, 20], [1, 4, 9, 21], [1, 4, 10, 18], - [1, 4, 12, 26], [1, 4, 13, 25], [1, 4, 14, 28], [1, 4, 15, 32], [1, 4, 16, 23], - [1, 4, 17, 29], [1, 4, 22, 34], [1, 4, 27, 37], [1, 4, 30, 36], [1, 5, 6, 8], - [1, 5, 7, 29], [1, 5, 9, 26], [1, 5, 11, 31], [1, 5, 12, 21], [1, 5, 13, 33], - [1, 5, 14, 37], [1, 5, 15, 30], [1, 5, 16, 28], [1, 5, 17, 36], [1, 5, 18, 23], - [1, 5, 20, 24], [1, 5, 22, 35], [1, 5, 25, 34], [1, 6, 7, 25], [1, 6, 9, 27], - [1, 6, 10, 30], [1, 6, 11, 21], [1, 6, 12, 14], [1, 6, 13, 15], [1, 6, 16, 34], - [1, 6, 18, 36], [1, 6, 19, 20], [1, 6, 22, 26], [1, 6, 23, 31], [1, 6, 32, 33], - [1, 6, 35, 37], [1, 7, 8, 31], [1, 7, 9, 34], [1, 7, 10, 13], [1, 7, 11, 19], - [1, 7, 14, 32], [1, 7, 15, 36], [1, 7, 17, 30], [1, 7, 20, 26], [1, 7, 21, 28], - [1, 7, 22, 37], [1, 7, 23, 24], [1, 7, 27, 35], [1, 8, 9, 12], [1, 8, 10, 34], - [1, 8, 11, 22], [1, 8, 14, 21], [1, 8, 15, 23], [1, 8, 16, 32], [1, 8, 17, 35], - [1, 8, 18, 30], [1, 8, 19, 25], [1, 8, 24, 27], [1, 8, 26, 33], [1, 8, 28, 29], - [1, 9, 11, 28], [1, 9, 13, 19], [1, 9, 14, 31], [1, 9, 15, 16], [1, 9, 17, 22], - [1, 9, 18, 20], [1, 9, 23, 36], [1, 9, 25, 32], [1, 9, 29, 35], [1, 9, 30, 33], - [1, 10, 12, 31], [1, 10, 14, 24], [1, 10, 15, 19], [1, 10, 16, 26], - [1, 10, 17, 27], [1, 10, 20, 29], [1, 10, 21, 37], [1, 10, 22, 36], - [1, 10, 23, 25], [1, 10, 28, 32], [1, 10, 33, 35], [1, 11, 12, 37], - [1, 11, 13, 16], [1, 11, 14, 27], [1, 11, 15, 17], [1, 11, 20, 30], - [1, 11, 23, 32], [1, 11, 24, 33], [1, 11, 25, 36], [1, 11, 26, 35], - [1, 11, 29, 34], [1, 12, 13, 17], [1, 12, 15, 25], [1, 12, 16, 27], - [1, 12, 18, 32], [1, 12, 20, 22], [1, 12, 24, 35], [1, 12, 28, 30], - [1, 12, 29, 36], [1, 12, 33, 34], [1, 13, 18, 21], [1, 13, 20, 36], - [1, 13, 22, 29], [1, 13, 23, 26], [1, 13, 24, 28], [1, 13, 27, 30], - [1, 13, 31, 34], [1, 13, 32, 35], [1, 14, 15, 34], [1, 14, 16, 30], - [1, 14, 17, 25], [1, 14, 18, 22], [1, 14, 19, 35], [1, 14, 20, 33], - [1, 14, 23, 29], [1, 14, 26, 36], [1, 15, 18, 27], [1, 15, 20, 21], - [1, 15, 22, 33], [1, 15, 24, 37], [1, 15, 26, 29], [1, 15, 28, 31], - [1, 16, 17, 37], [1, 16, 18, 24], [1, 16, 19, 21], [1, 16, 20, 35], - [1, 16, 25, 29], [1, 16, 31, 33], [1, 17, 18, 33], [1, 17, 19, 28], - [1, 17, 20, 32], [1, 17, 21, 34], [1, 17, 24, 31], [1, 18, 25, 28], - [1, 18, 26, 34], [1, 18, 29, 37], [1, 18, 31, 35], [1, 19, 22, 27], - [1, 19, 23, 30], [1, 19, 24, 29], [1, 19, 26, 32], [1, 19, 31, 36], - [1, 19, 34, 37], [1, 20, 23, 27], [1, 20, 28, 37], [1, 21, 22, 32], - [1, 21, 24, 25], [1, 21, 27, 31], [1, 21, 29, 33], [1, 21, 30, 35], - [1, 22, 23, 28], [1, 22, 25, 31], [1, 23, 33, 37], [1, 23, 34, 35], - [1, 24, 26, 30], [1, 24, 34, 36], [1, 25, 26, 27], [1, 25, 30, 37], - [1, 26, 31, 37], [1, 27, 28, 34], [1, 27, 33, 36], [1, 28, 35, 36], - [1, 29, 31, 32], [1, 30, 32, 34], [1, 32, 36, 37], [2, 3, 4, 16], - [2, 3, 5, 36], [2, 3, 6, 33], [2, 3, 7, 29], [2, 3, 8, 19], [2, 3, 9, 14], - [2, 3, 11, 12], [2, 3, 13, 20], [2, 3, 17, 37], [2, 3, 18, 24], [2, 3, 21, 35], - [2, 3, 22, 27], [2, 3, 23, 25], [2, 3, 26, 34], [2, 3, 28, 30], [2, 3, 31, 32], - [2, 4, 5, 12], [2, 4, 6, 11], [2, 4, 7, 30], [2, 4, 8, 17], [2, 4, 10, 25], - [2, 4, 13, 24], [2, 4, 14, 15], [2, 4, 18, 27], [2, 4, 19, 20], [2, 4, 21, 32], - [2, 4, 22, 37], [2, 4, 23, 31], [2, 4, 26, 36], [2, 4, 28, 33], [2, 4, 29, 34], - [2, 5, 6, 20], [2, 5, 7, 25], [2, 5, 8, 34], [2, 5, 9, 21], [2, 5, 10, 22], - [2, 5, 11, 19], [2, 5, 13, 27], [2, 5, 14, 26], [2, 5, 15, 29], [2, 5, 16, 33], - [2, 5, 17, 24], [2, 5, 18, 30], [2, 5, 23, 35], [2, 5, 31, 37], [2, 6, 7, 9], - [2, 6, 8, 30], [2, 6, 10, 27], [2, 6, 12, 32], [2, 6, 13, 22], [2, 6, 14, 34], - [2, 6, 16, 31], [2, 6, 17, 29], [2, 6, 18, 37], [2, 6, 19, 24], [2, 6, 21, 25], - [2, 6, 23, 36], [2, 6, 26, 35], [2, 7, 8, 26], [2, 7, 10, 28], [2, 7, 11, 31], - [2, 7, 12, 22], [2, 7, 13, 15], [2, 7, 14, 16], [2, 7, 17, 35], [2, 7, 19, 37], - [2, 7, 20, 21], [2, 7, 23, 27], [2, 7, 24, 32], [2, 7, 33, 34], [2, 8, 9, 32], - [2, 8, 10, 35], [2, 8, 11, 14], [2, 8, 12, 20], [2, 8, 15, 33], [2, 8, 16, 37], - [2, 8, 18, 31], [2, 8, 21, 27], [2, 8, 22, 29], [2, 8, 24, 25], [2, 8, 28, 36], - [2, 9, 10, 13], [2, 9, 11, 35], [2, 9, 12, 23], [2, 9, 15, 22], [2, 9, 16, 24], - [2, 9, 17, 33], [2, 9, 18, 36], [2, 9, 19, 31], [2, 9, 20, 26], [2, 9, 25, 28], - [2, 9, 27, 34], [2, 9, 29, 30], [2, 10, 12, 29], [2, 10, 14, 20], - [2, 10, 15, 32], [2, 10, 16, 17], [2, 10, 18, 23], [2, 10, 19, 21], - [2, 10, 24, 37], [2, 10, 26, 33], [2, 10, 30, 36], [2, 10, 31, 34], - [2, 11, 13, 32], [2, 11, 15, 25], [2, 11, 16, 20], [2, 11, 17, 27], - [2, 11, 18, 28], [2, 11, 21, 30], [2, 11, 23, 37], [2, 11, 24, 26], - [2, 11, 29, 33], [2, 11, 34, 36], [2, 12, 14, 17], [2, 12, 15, 28], - [2, 12, 16, 18], [2, 12, 21, 31], [2, 12, 24, 33], [2, 12, 25, 34], - [2, 12, 26, 37], [2, 12, 27, 36], [2, 12, 30, 35], [2, 13, 14, 18], - [2, 13, 16, 26], [2, 13, 17, 28], [2, 13, 19, 33], [2, 13, 21, 23], - [2, 13, 25, 36], [2, 13, 29, 31], [2, 13, 30, 37], [2, 13, 34, 35], - [2, 14, 19, 22], [2, 14, 21, 37], [2, 14, 23, 30], [2, 14, 24, 27], - [2, 14, 25, 29], [2, 14, 28, 31], [2, 14, 32, 35], [2, 14, 33, 36], - [2, 15, 16, 35], [2, 15, 17, 31], [2, 15, 18, 26], [2, 15, 19, 23], - [2, 15, 20, 36], [2, 15, 21, 34], [2, 15, 24, 30], [2, 15, 27, 37], - [2, 16, 19, 28], [2, 16, 21, 22], [2, 16, 23, 34], [2, 16, 27, 30], - [2, 16, 29, 32], [2, 17, 19, 25], [2, 17, 20, 22], [2, 17, 21, 36], - [2, 17, 26, 30], [2, 17, 32, 34], [2, 18, 19, 34], [2, 18, 20, 29], - [2, 18, 21, 33], [2, 18, 22, 35], [2, 18, 25, 32], [2, 19, 26, 29], - [2, 19, 27, 35], [2, 19, 32, 36], [2, 20, 23, 28], [2, 20, 24, 31], - [2, 20, 25, 30], [2, 20, 27, 33], [2, 20, 32, 37], [2, 21, 24, 28], - [2, 22, 23, 33], [2, 22, 25, 26], [2, 22, 28, 32], [2, 22, 30, 34], - [2, 22, 31, 36], [2, 23, 24, 29], [2, 23, 26, 32], [2, 24, 35, 36], - [2, 25, 27, 31], [2, 25, 35, 37], [2, 26, 27, 28], [2, 28, 29, 35], - [2, 28, 34, 37], [2, 29, 36, 37], [2, 30, 32, 33], [2, 31, 33, 35], - [3, 4, 5, 17], [3, 4, 6, 37], [3, 4, 7, 34], [3, 4, 8, 30], [3, 4, 9, 20], - [3, 4, 10, 15], [3, 4, 12, 13], [3, 4, 14, 21], [3, 4, 19, 25], [3, 4, 22, 36], - [3, 4, 23, 28], [3, 4, 24, 26], [3, 4, 27, 35], [3, 4, 29, 31], [3, 4, 32, 33], - [3, 5, 6, 13], [3, 5, 7, 12], [3, 5, 8, 31], [3, 5, 9, 18], [3, 5, 11, 26], - [3, 5, 14, 25], [3, 5, 15, 16], [3, 5, 19, 28], [3, 5, 20, 21], [3, 5, 22, 33], - [3, 5, 24, 32], [3, 5, 27, 37], [3, 5, 29, 34], [3, 5, 30, 35], [3, 6, 7, 21], - [3, 6, 8, 26], [3, 6, 9, 35], [3, 6, 10, 22], [3, 6, 11, 23], [3, 6, 12, 20], - [3, 6, 14, 28], [3, 6, 15, 27], [3, 6, 16, 30], [3, 6, 17, 34], [3, 6, 18, 25], - [3, 6, 19, 31], [3, 6, 24, 36], [3, 7, 8, 10], [3, 7, 9, 31], [3, 7, 11, 28], - [3, 7, 13, 33], [3, 7, 14, 23], [3, 7, 15, 35], [3, 7, 17, 32], [3, 7, 18, 30], - [3, 7, 20, 25], [3, 7, 22, 26], [3, 7, 24, 37], [3, 7, 27, 36], [3, 8, 9, 27], - [3, 8, 11, 29], [3, 8, 12, 32], [3, 8, 13, 23], [3, 8, 14, 16], [3, 8, 15, 17], - [3, 8, 18, 36], [3, 8, 21, 22], [3, 8, 24, 28], [3, 8, 25, 33], [3, 8, 34, 35], - [3, 9, 10, 33], [3, 9, 11, 36], [3, 9, 12, 15], [3, 9, 13, 21], [3, 9, 16, 34], - [3, 9, 19, 32], [3, 9, 22, 28], [3, 9, 23, 30], [3, 9, 25, 26], [3, 9, 29, 37], - [3, 10, 11, 14], [3, 10, 12, 36], [3, 10, 13, 24], [3, 10, 16, 23], - [3, 10, 17, 25], [3, 10, 18, 34], [3, 10, 19, 37], [3, 10, 20, 32], - [3, 10, 21, 27], [3, 10, 26, 29], [3, 10, 28, 35], [3, 10, 30, 31], - [3, 11, 13, 30], [3, 11, 15, 21], [3, 11, 16, 33], [3, 11, 17, 18], - [3, 11, 19, 24], [3, 11, 20, 22], [3, 11, 27, 34], [3, 11, 31, 37], - [3, 11, 32, 35], [3, 12, 14, 33], [3, 12, 16, 26], [3, 12, 17, 21], - [3, 12, 18, 28], [3, 12, 19, 29], [3, 12, 22, 31], [3, 12, 25, 27], - [3, 12, 30, 34], [3, 12, 35, 37], [3, 13, 15, 18], [3, 13, 16, 29], - [3, 13, 17, 19], [3, 13, 22, 32], [3, 13, 25, 34], [3, 13, 26, 35], - [3, 13, 28, 37], [3, 13, 31, 36], [3, 14, 15, 19], [3, 14, 17, 27], - [3, 14, 18, 29], [3, 14, 20, 34], [3, 14, 22, 24], [3, 14, 26, 37], - [3, 14, 30, 32], [3, 14, 35, 36], [3, 15, 20, 23], [3, 15, 24, 31], - [3, 15, 25, 28], [3, 15, 26, 30], [3, 15, 29, 32], [3, 15, 33, 36], - [3, 15, 34, 37], [3, 16, 17, 36], [3, 16, 18, 32], [3, 16, 19, 27], - [3, 16, 20, 24], [3, 16, 21, 37], [3, 16, 22, 35], [3, 16, 25, 31], - [3, 17, 20, 29], [3, 17, 22, 23], [3, 17, 24, 35], [3, 17, 28, 31], - [3, 17, 30, 33], [3, 18, 20, 26], [3, 18, 21, 23], [3, 18, 22, 37], - [3, 18, 27, 31], [3, 18, 33, 35], [3, 19, 20, 35], [3, 19, 21, 30], - [3, 19, 22, 34], [3, 19, 23, 36], [3, 19, 26, 33], [3, 20, 27, 30], - [3, 20, 28, 36], [3, 20, 33, 37], [3, 21, 24, 29], [3, 21, 25, 32], - [3, 21, 26, 31], [3, 21, 28, 34], [3, 22, 25, 29], [3, 23, 24, 34], - [3, 23, 26, 27], [3, 23, 29, 33], [3, 23, 31, 35], [3, 23, 32, 37], - [3, 24, 25, 30], [3, 24, 27, 33], [3, 25, 36, 37], [3, 26, 28, 32], - [3, 27, 28, 29], [3, 29, 30, 36], [3, 31, 33, 34], [3, 32, 34, 36], - [4, 5, 6, 18], [4, 5, 8, 35], [4, 5, 9, 31], [4, 5, 10, 21], [4, 5, 11, 16], - [4, 5, 13, 14], [4, 5, 15, 22], [4, 5, 20, 26], [4, 5, 23, 37], [4, 5, 24, 29], - [4, 5, 25, 27], [4, 5, 28, 36], [4, 5, 30, 32], [4, 5, 33, 34], [4, 6, 7, 14], - [4, 6, 8, 13], [4, 6, 9, 32], [4, 6, 10, 19], [4, 6, 12, 27], [4, 6, 15, 26], - [4, 6, 16, 17], [4, 6, 20, 29], [4, 6, 21, 22], [4, 6, 23, 34], [4, 6, 25, 33], - [4, 6, 30, 35], [4, 6, 31, 36], [4, 7, 8, 22], [4, 7, 9, 27], [4, 7, 10, 36], - [4, 7, 11, 23], [4, 7, 12, 24], [4, 7, 13, 21], [4, 7, 15, 29], [4, 7, 16, 28], - [4, 7, 17, 31], [4, 7, 18, 35], [4, 7, 19, 26], [4, 7, 20, 32], [4, 7, 25, 37], - [4, 8, 9, 11], [4, 8, 10, 32], [4, 8, 12, 29], [4, 8, 14, 34], [4, 8, 15, 24], - [4, 8, 16, 36], [4, 8, 18, 33], [4, 8, 19, 31], [4, 8, 21, 26], [4, 8, 23, 27], - [4, 8, 28, 37], [4, 9, 10, 28], [4, 9, 12, 30], [4, 9, 13, 33], [4, 9, 14, 24], - [4, 9, 15, 17], [4, 9, 16, 18], [4, 9, 19, 37], [4, 9, 22, 23], [4, 9, 25, 29], - [4, 9, 26, 34], [4, 9, 35, 36], [4, 10, 11, 34], [4, 10, 12, 37], - [4, 10, 13, 16], [4, 10, 14, 22], [4, 10, 17, 35], [4, 10, 20, 33], - [4, 10, 23, 29], [4, 10, 24, 31], [4, 10, 26, 27], [4, 11, 12, 15], - [4, 11, 13, 37], [4, 11, 14, 25], [4, 11, 17, 24], [4, 11, 18, 26], - [4, 11, 19, 35], [4, 11, 21, 33], [4, 11, 22, 28], [4, 11, 27, 30], - [4, 11, 29, 36], [4, 11, 31, 32], [4, 12, 14, 31], [4, 12, 16, 22], - [4, 12, 17, 34], [4, 12, 18, 19], [4, 12, 20, 25], [4, 12, 21, 23], - [4, 12, 28, 35], [4, 12, 33, 36], [4, 13, 15, 34], [4, 13, 17, 27], - [4, 13, 18, 22], [4, 13, 19, 29], [4, 13, 20, 30], [4, 13, 23, 32], - [4, 13, 26, 28], [4, 13, 31, 35], [4, 14, 16, 19], [4, 14, 17, 30], - [4, 14, 18, 20], [4, 14, 23, 33], [4, 14, 26, 35], [4, 14, 27, 36], - [4, 14, 32, 37], [4, 15, 16, 20], [4, 15, 18, 28], [4, 15, 19, 30], - [4, 15, 21, 35], [4, 15, 23, 25], [4, 15, 31, 33], [4, 15, 36, 37], - [4, 16, 21, 24], [4, 16, 25, 32], [4, 16, 26, 29], [4, 16, 27, 31], - [4, 16, 30, 33], [4, 16, 34, 37], [4, 17, 18, 37], [4, 17, 19, 33], - [4, 17, 20, 28], [4, 17, 21, 25], [4, 17, 23, 36], [4, 17, 26, 32], - [4, 18, 21, 30], [4, 18, 23, 24], [4, 18, 25, 36], [4, 18, 29, 32], - [4, 18, 31, 34], [4, 19, 21, 27], [4, 19, 22, 24], [4, 19, 28, 32], - [4, 19, 34, 36], [4, 20, 21, 36], [4, 20, 22, 31], [4, 20, 23, 35], - [4, 20, 24, 37], [4, 20, 27, 34], [4, 21, 28, 31], [4, 21, 29, 37], - [4, 22, 25, 30], [4, 22, 26, 33], [4, 22, 27, 32], [4, 22, 29, 35], - [4, 23, 26, 30], [4, 24, 25, 35], [4, 24, 27, 28], [4, 24, 30, 34], - [4, 24, 32, 36], [4, 25, 26, 31], [4, 25, 28, 34], [4, 27, 29, 33], - [4, 28, 29, 30], [4, 30, 31, 37], [4, 32, 34, 35], [4, 33, 35, 37], - [5, 6, 7, 19], [5, 6, 9, 36], [5, 6, 10, 32], [5, 6, 11, 22], [5, 6, 12, 17], - [5, 6, 14, 15], [5, 6, 16, 23], [5, 6, 21, 27], [5, 6, 25, 30], [5, 6, 26, 28], - [5, 6, 29, 37], [5, 6, 31, 33], [5, 6, 34, 35], [5, 7, 8, 15], [5, 7, 9, 14], - [5, 7, 10, 33], [5, 7, 11, 20], [5, 7, 13, 28], [5, 7, 16, 27], [5, 7, 17, 18], - [5, 7, 21, 30], [5, 7, 22, 23], [5, 7, 24, 35], [5, 7, 26, 34], [5, 7, 31, 36], - [5, 7, 32, 37], [5, 8, 9, 23], [5, 8, 10, 28], [5, 8, 11, 37], [5, 8, 12, 24], - [5, 8, 13, 25], [5, 8, 14, 22], [5, 8, 16, 30], [5, 8, 17, 29], [5, 8, 18, 32], - [5, 8, 19, 36], [5, 8, 20, 27], [5, 8, 21, 33], [5, 9, 10, 12], [5, 9, 11, 33], - [5, 9, 13, 30], [5, 9, 15, 35], [5, 9, 16, 25], [5, 9, 17, 37], [5, 9, 19, 34], - [5, 9, 20, 32], [5, 9, 22, 27], [5, 9, 24, 28], [5, 10, 11, 29], - [5, 10, 13, 31], [5, 10, 14, 34], [5, 10, 15, 25], [5, 10, 16, 18], - [5, 10, 17, 19], [5, 10, 23, 24], [5, 10, 26, 30], [5, 10, 27, 35], - [5, 10, 36, 37], [5, 11, 12, 35], [5, 11, 14, 17], [5, 11, 15, 23], - [5, 11, 18, 36], [5, 11, 21, 34], [5, 11, 24, 30], [5, 11, 25, 32], - [5, 11, 27, 28], [5, 12, 13, 16], [5, 12, 15, 26], [5, 12, 18, 25], - [5, 12, 19, 27], [5, 12, 20, 36], [5, 12, 22, 34], [5, 12, 23, 29], - [5, 12, 28, 31], [5, 12, 30, 37], [5, 12, 32, 33], [5, 13, 15, 32], - [5, 13, 17, 23], [5, 13, 18, 35], [5, 13, 19, 20], [5, 13, 21, 26], - [5, 13, 22, 24], [5, 13, 29, 36], [5, 13, 34, 37], [5, 14, 16, 35], - [5, 14, 18, 28], [5, 14, 19, 23], [5, 14, 20, 30], [5, 14, 21, 31], - [5, 14, 24, 33], [5, 14, 27, 29], [5, 14, 32, 36], [5, 15, 17, 20], - [5, 15, 18, 31], [5, 15, 19, 21], [5, 15, 24, 34], [5, 15, 27, 36], - [5, 15, 28, 37], [5, 16, 17, 21], [5, 16, 19, 29], [5, 16, 20, 31], - [5, 16, 22, 36], [5, 16, 24, 26], [5, 16, 32, 34], [5, 17, 22, 25], - [5, 17, 26, 33], [5, 17, 27, 30], [5, 17, 28, 32], [5, 17, 31, 34], - [5, 18, 20, 34], [5, 18, 21, 29], [5, 18, 22, 26], [5, 18, 24, 37], - [5, 18, 27, 33], [5, 19, 22, 31], [5, 19, 24, 25], [5, 19, 26, 37], - [5, 19, 30, 33], [5, 19, 32, 35], [5, 20, 22, 28], [5, 20, 23, 25], - [5, 20, 29, 33], [5, 20, 35, 37], [5, 21, 22, 37], [5, 21, 23, 32], - [5, 21, 24, 36], [5, 21, 28, 35], [5, 22, 29, 32], [5, 23, 26, 31], - [5, 23, 27, 34], [5, 23, 28, 33], [5, 23, 30, 36], [5, 24, 27, 31], - [5, 25, 26, 36], [5, 25, 28, 29], [5, 25, 31, 35], [5, 25, 33, 37], - [5, 26, 27, 32], [5, 26, 29, 35], [5, 28, 30, 34], [5, 29, 30, 31], - [5, 33, 35, 36], [6, 7, 8, 20], [6, 7, 10, 37], [6, 7, 11, 33], [6, 7, 12, 23], - [6, 7, 13, 18], [6, 7, 15, 16], [6, 7, 17, 24], [6, 7, 22, 28], [6, 7, 26, 31], - [6, 7, 27, 29], [6, 7, 32, 34], [6, 7, 35, 36], [6, 8, 9, 16], [6, 8, 10, 15], - [6, 8, 11, 34], [6, 8, 12, 21], [6, 8, 14, 29], [6, 8, 17, 28], [6, 8, 18, 19], - [6, 8, 22, 31], [6, 8, 23, 24], [6, 8, 25, 36], [6, 8, 27, 35], [6, 8, 32, 37], - [6, 9, 10, 24], [6, 9, 11, 29], [6, 9, 13, 25], [6, 9, 14, 26], [6, 9, 15, 23], - [6, 9, 17, 31], [6, 9, 18, 30], [6, 9, 19, 33], [6, 9, 20, 37], [6, 9, 21, 28], - [6, 9, 22, 34], [6, 10, 11, 13], [6, 10, 12, 34], [6, 10, 14, 31], - [6, 10, 16, 36], [6, 10, 17, 26], [6, 10, 20, 35], [6, 10, 21, 33], - [6, 10, 23, 28], [6, 10, 25, 29], [6, 11, 12, 30], [6, 11, 14, 32], - [6, 11, 15, 35], [6, 11, 16, 26], [6, 11, 17, 19], [6, 11, 18, 20], - [6, 11, 24, 25], [6, 11, 27, 31], [6, 11, 28, 36], [6, 12, 13, 36], - [6, 12, 15, 18], [6, 12, 16, 24], [6, 12, 19, 37], [6, 12, 22, 35], - [6, 12, 25, 31], [6, 12, 26, 33], [6, 12, 28, 29], [6, 13, 14, 17], - [6, 13, 16, 27], [6, 13, 19, 26], [6, 13, 20, 28], [6, 13, 21, 37], - [6, 13, 23, 35], [6, 13, 24, 30], [6, 13, 29, 32], [6, 13, 33, 34], - [6, 14, 16, 33], [6, 14, 18, 24], [6, 14, 19, 36], [6, 14, 20, 21], - [6, 14, 22, 27], [6, 14, 23, 25], [6, 14, 30, 37], [6, 15, 17, 36], - [6, 15, 19, 29], [6, 15, 20, 24], [6, 15, 21, 31], [6, 15, 22, 32], - [6, 15, 25, 34], [6, 15, 28, 30], [6, 15, 33, 37], [6, 16, 18, 21], - [6, 16, 19, 32], [6, 16, 20, 22], [6, 16, 25, 35], [6, 16, 28, 37], - [6, 17, 18, 22], [6, 17, 20, 30], [6, 17, 21, 32], [6, 17, 23, 37], - [6, 17, 25, 27], [6, 17, 33, 35], [6, 18, 23, 26], [6, 18, 27, 34], - [6, 18, 28, 31], [6, 18, 29, 33], [6, 18, 32, 35], [6, 19, 21, 35], - [6, 19, 22, 30], [6, 19, 23, 27], [6, 19, 28, 34], [6, 20, 23, 32], - [6, 20, 25, 26], [6, 20, 31, 34], [6, 20, 33, 36], [6, 21, 23, 29], - [6, 21, 24, 26], [6, 21, 30, 34], [6, 22, 24, 33], [6, 22, 25, 37], - [6, 22, 29, 36], [6, 23, 30, 33], [6, 24, 27, 32], [6, 24, 28, 35], - [6, 24, 29, 34], [6, 24, 31, 37], [6, 25, 28, 32], [6, 26, 27, 37], - [6, 26, 29, 30], [6, 26, 32, 36], [6, 27, 28, 33], [6, 27, 30, 36], - [6, 29, 31, 35], [6, 30, 31, 32], [6, 34, 36, 37], [7, 8, 9, 21], - [7, 8, 12, 34], [7, 8, 13, 24], [7, 8, 14, 19], [7, 8, 16, 17], [7, 8, 18, 25], - [7, 8, 23, 29], [7, 8, 27, 32], [7, 8, 28, 30], [7, 8, 33, 35], [7, 8, 36, 37], - [7, 9, 10, 17], [7, 9, 11, 16], [7, 9, 12, 35], [7, 9, 13, 22], [7, 9, 15, 30], - [7, 9, 18, 29], [7, 9, 19, 20], [7, 9, 23, 32], [7, 9, 24, 25], [7, 9, 26, 37], - [7, 9, 28, 36], [7, 10, 11, 25], [7, 10, 12, 30], [7, 10, 14, 26], - [7, 10, 15, 27], [7, 10, 16, 24], [7, 10, 18, 32], [7, 10, 19, 31], - [7, 10, 20, 34], [7, 10, 22, 29], [7, 10, 23, 35], [7, 11, 12, 14], - [7, 11, 13, 35], [7, 11, 15, 32], [7, 11, 17, 37], [7, 11, 18, 27], - [7, 11, 21, 36], [7, 11, 22, 34], [7, 11, 24, 29], [7, 11, 26, 30], - [7, 12, 13, 31], [7, 12, 15, 33], [7, 12, 16, 36], [7, 12, 17, 27], - [7, 12, 18, 20], [7, 12, 19, 21], [7, 12, 25, 26], [7, 12, 28, 32], - [7, 12, 29, 37], [7, 13, 14, 37], [7, 13, 16, 19], [7, 13, 17, 25], - [7, 13, 23, 36], [7, 13, 26, 32], [7, 13, 27, 34], [7, 13, 29, 30], - [7, 14, 15, 18], [7, 14, 17, 28], [7, 14, 20, 27], [7, 14, 21, 29], - [7, 14, 24, 36], [7, 14, 25, 31], [7, 14, 30, 33], [7, 14, 34, 35], - [7, 15, 17, 34], [7, 15, 19, 25], [7, 15, 20, 37], [7, 15, 21, 22], - [7, 15, 23, 28], [7, 15, 24, 26], [7, 16, 18, 37], [7, 16, 20, 30], - [7, 16, 21, 25], [7, 16, 22, 32], [7, 16, 23, 33], [7, 16, 26, 35], - [7, 16, 29, 31], [7, 17, 19, 22], [7, 17, 20, 33], [7, 17, 21, 23], - [7, 17, 26, 36], [7, 18, 19, 23], [7, 18, 21, 31], [7, 18, 22, 33], - [7, 18, 26, 28], [7, 18, 34, 36], [7, 19, 24, 27], [7, 19, 28, 35], - [7, 19, 29, 32], [7, 19, 30, 34], [7, 19, 33, 36], [7, 20, 22, 36], - [7, 20, 23, 31], [7, 20, 24, 28], [7, 20, 29, 35], [7, 21, 24, 33], - [7, 21, 26, 27], [7, 21, 32, 35], [7, 21, 34, 37], [7, 22, 24, 30], - [7, 22, 25, 27], [7, 22, 31, 35], [7, 23, 25, 34], [7, 23, 30, 37], - [7, 24, 31, 34], [7, 25, 28, 33], [7, 25, 29, 36], [7, 25, 30, 35], - [7, 26, 29, 33], [7, 27, 30, 31], [7, 27, 33, 37], [7, 28, 29, 34], - [7, 28, 31, 37], [7, 30, 32, 36], [7, 31, 32, 33], [8, 9, 10, 22], - [8, 9, 13, 35], [8, 9, 14, 25], [8, 9, 15, 20], [8, 9, 17, 18], [8, 9, 19, 26], - [8, 9, 24, 30], [8, 9, 28, 33], [8, 9, 29, 31], [8, 9, 34, 36], [8, 10, 11, 18], - [8, 10, 12, 17], [8, 10, 13, 36], [8, 10, 14, 23], [8, 10, 16, 31], - [8, 10, 19, 30], [8, 10, 20, 21], [8, 10, 24, 33], [8, 10, 25, 26], - [8, 10, 29, 37], [8, 11, 12, 26], [8, 11, 13, 31], [8, 11, 15, 27], - [8, 11, 16, 28], [8, 11, 17, 25], [8, 11, 19, 33], [8, 11, 20, 32], - [8, 11, 21, 35], [8, 11, 23, 30], [8, 11, 24, 36], [8, 12, 13, 15], - [8, 12, 14, 36], [8, 12, 16, 33], [8, 12, 19, 28], [8, 12, 22, 37], - [8, 12, 23, 35], [8, 12, 25, 30], [8, 12, 27, 31], [8, 13, 14, 32], - [8, 13, 16, 34], [8, 13, 17, 37], [8, 13, 18, 28], [8, 13, 19, 21], - [8, 13, 20, 22], [8, 13, 26, 27], [8, 13, 29, 33], [8, 14, 17, 20], - [8, 14, 18, 26], [8, 14, 24, 37], [8, 14, 27, 33], [8, 14, 28, 35], - [8, 14, 30, 31], [8, 15, 16, 19], [8, 15, 18, 29], [8, 15, 21, 28], - [8, 15, 22, 30], [8, 15, 25, 37], [8, 15, 26, 32], [8, 15, 31, 34], - [8, 15, 35, 36], [8, 16, 18, 35], [8, 16, 20, 26], [8, 16, 22, 23], - [8, 16, 24, 29], [8, 16, 25, 27], [8, 17, 21, 31], [8, 17, 22, 26], - [8, 17, 23, 33], [8, 17, 24, 34], [8, 17, 27, 36], [8, 17, 30, 32], - [8, 18, 20, 23], [8, 18, 21, 34], [8, 18, 22, 24], [8, 18, 27, 37], - [8, 19, 20, 24], [8, 19, 22, 32], [8, 19, 23, 34], [8, 19, 27, 29], - [8, 19, 35, 37], [8, 20, 25, 28], [8, 20, 29, 36], [8, 20, 30, 33], - [8, 20, 31, 35], [8, 20, 34, 37], [8, 21, 23, 37], [8, 21, 24, 32], - [8, 21, 25, 29], [8, 21, 30, 36], [8, 22, 25, 34], [8, 22, 27, 28], - [8, 22, 33, 36], [8, 23, 25, 31], [8, 23, 26, 28], [8, 23, 32, 36], - [8, 24, 26, 35], [8, 25, 32, 35], [8, 26, 29, 34], [8, 26, 30, 37], - [8, 26, 31, 36], [8, 27, 30, 34], [8, 28, 31, 32], [8, 29, 30, 35], - [8, 31, 33, 37], [8, 32, 33, 34], [9, 10, 11, 23], [9, 10, 14, 36], - [9, 10, 15, 26], [9, 10, 16, 21], [9, 10, 18, 19], [9, 10, 20, 27], - [9, 10, 25, 31], [9, 10, 29, 34], [9, 10, 30, 32], [9, 10, 35, 37], - [9, 11, 12, 19], [9, 11, 13, 18], [9, 11, 14, 37], [9, 11, 15, 24], - [9, 11, 17, 32], [9, 11, 20, 31], [9, 11, 21, 22], [9, 11, 25, 34], - [9, 11, 26, 27], [9, 12, 13, 27], [9, 12, 14, 32], [9, 12, 16, 28], - [9, 12, 17, 29], [9, 12, 18, 26], [9, 12, 20, 34], [9, 12, 21, 33], - [9, 12, 22, 36], [9, 12, 24, 31], [9, 12, 25, 37], [9, 13, 14, 16], - [9, 13, 15, 37], [9, 13, 17, 34], [9, 13, 20, 29], [9, 13, 24, 36], - [9, 13, 26, 31], [9, 13, 28, 32], [9, 14, 15, 33], [9, 14, 17, 35], - [9, 14, 19, 29], [9, 14, 20, 22], [9, 14, 21, 23], [9, 14, 27, 28], - [9, 14, 30, 34], [9, 15, 18, 21], [9, 15, 19, 27], [9, 15, 28, 34], - [9, 15, 29, 36], [9, 15, 31, 32], [9, 16, 17, 20], [9, 16, 19, 30], - [9, 16, 22, 29], [9, 16, 23, 31], [9, 16, 27, 33], [9, 16, 32, 35], - [9, 16, 36, 37], [9, 17, 19, 36], [9, 17, 21, 27], [9, 17, 23, 24], - [9, 17, 25, 30], [9, 17, 26, 28], [9, 18, 22, 32], [9, 18, 23, 27], - [9, 18, 24, 34], [9, 18, 25, 35], [9, 18, 28, 37], [9, 18, 31, 33], - [9, 19, 21, 24], [9, 19, 22, 35], [9, 19, 23, 25], [9, 20, 21, 25], - [9, 20, 23, 33], [9, 20, 24, 35], [9, 20, 28, 30], [9, 21, 26, 29], - [9, 21, 30, 37], [9, 21, 31, 34], [9, 21, 32, 36], [9, 22, 25, 33], - [9, 22, 26, 30], [9, 22, 31, 37], [9, 23, 26, 35], [9, 23, 28, 29], - [9, 23, 34, 37], [9, 24, 26, 32], [9, 24, 27, 29], [9, 24, 33, 37], - [9, 25, 27, 36], [9, 26, 33, 36], [9, 27, 30, 35], [9, 27, 32, 37], - [9, 28, 31, 35], [9, 29, 32, 33], [9, 30, 31, 36], [9, 33, 34, 35], - [10, 11, 12, 24], [10, 11, 15, 37], [10, 11, 16, 27], [10, 11, 17, 22], - [10, 11, 19, 20], [10, 11, 21, 28], [10, 11, 26, 32], [10, 11, 30, 35], - [10, 11, 31, 33], [10, 12, 13, 20], [10, 12, 14, 19], [10, 12, 16, 25], - [10, 12, 18, 33], [10, 12, 21, 32], [10, 12, 22, 23], [10, 12, 26, 35], - [10, 12, 27, 28], [10, 13, 14, 28], [10, 13, 15, 33], [10, 13, 17, 29], - [10, 13, 18, 30], [10, 13, 19, 27], [10, 13, 21, 35], [10, 13, 22, 34], - [10, 13, 23, 37], [10, 13, 25, 32], [10, 14, 15, 17], [10, 14, 18, 35], - [10, 14, 21, 30], [10, 14, 25, 37], [10, 14, 27, 32], [10, 14, 29, 33], - [10, 15, 16, 34], [10, 15, 18, 36], [10, 15, 20, 30], [10, 15, 21, 23], - [10, 15, 22, 24], [10, 15, 28, 29], [10, 15, 31, 35], [10, 16, 19, 22], - [10, 16, 20, 28], [10, 16, 29, 35], [10, 16, 30, 37], [10, 16, 32, 33], - [10, 17, 18, 21], [10, 17, 20, 31], [10, 17, 23, 30], [10, 17, 24, 32], - [10, 17, 28, 34], [10, 17, 33, 36], [10, 18, 20, 37], [10, 18, 22, 28], - [10, 18, 24, 25], [10, 18, 26, 31], [10, 18, 27, 29], [10, 19, 23, 33], - [10, 19, 24, 28], [10, 19, 25, 35], [10, 19, 26, 36], [10, 19, 32, 34], - [10, 20, 22, 25], [10, 20, 23, 36], [10, 20, 24, 26], [10, 21, 22, 26], - [10, 21, 24, 34], [10, 21, 25, 36], [10, 21, 29, 31], [10, 22, 27, 30], - [10, 22, 32, 35], [10, 22, 33, 37], [10, 23, 26, 34], [10, 23, 27, 31], - [10, 24, 27, 36], [10, 24, 29, 30], [10, 25, 27, 33], [10, 25, 28, 30], - [10, 26, 28, 37], [10, 27, 34, 37], [10, 28, 31, 36], [10, 29, 32, 36], - [10, 30, 33, 34], [10, 31, 32, 37], [10, 34, 35, 36], [11, 12, 13, 25], - [11, 12, 17, 28], [11, 12, 18, 23], [11, 12, 20, 21], [11, 12, 22, 29], - [11, 12, 27, 33], [11, 12, 31, 36], [11, 12, 32, 34], [11, 13, 14, 21], - [11, 13, 15, 20], [11, 13, 17, 26], [11, 13, 19, 34], [11, 13, 22, 33], - [11, 13, 23, 24], [11, 13, 27, 36], [11, 13, 28, 29], [11, 14, 15, 29], - [11, 14, 16, 34], [11, 14, 18, 30], [11, 14, 19, 31], [11, 14, 20, 28], - [11, 14, 22, 36], [11, 14, 23, 35], [11, 14, 26, 33], [11, 15, 16, 18], - [11, 15, 19, 36], [11, 15, 22, 31], [11, 15, 28, 33], [11, 15, 30, 34], - [11, 16, 17, 35], [11, 16, 19, 37], [11, 16, 21, 31], [11, 16, 22, 24], - [11, 16, 23, 25], [11, 16, 29, 30], [11, 16, 32, 36], [11, 17, 20, 23], - [11, 17, 21, 29], [11, 17, 30, 36], [11, 17, 33, 34], [11, 18, 19, 22], - [11, 18, 21, 32], [11, 18, 24, 31], [11, 18, 25, 33], [11, 18, 29, 35], - [11, 18, 34, 37], [11, 19, 23, 29], [11, 19, 25, 26], [11, 19, 27, 32], - [11, 19, 28, 30], [11, 20, 24, 34], [11, 20, 25, 29], [11, 20, 26, 36], - [11, 20, 27, 37], [11, 20, 33, 35], [11, 21, 23, 26], [11, 21, 24, 37], - [11, 21, 25, 27], [11, 22, 23, 27], [11, 22, 25, 35], [11, 22, 26, 37], - [11, 22, 30, 32], [11, 23, 28, 31], [11, 23, 33, 36], [11, 24, 27, 35], - [11, 24, 28, 32], [11, 25, 28, 37], [11, 25, 30, 31], [11, 26, 28, 34], - [11, 26, 29, 31], [11, 29, 32, 37], [11, 30, 33, 37], [11, 31, 34, 35], - [11, 35, 36, 37], [12, 13, 14, 26], [12, 13, 18, 29], [12, 13, 19, 24], - [12, 13, 21, 22], [12, 13, 23, 30], [12, 13, 28, 34], [12, 13, 32, 37], - [12, 13, 33, 35], [12, 14, 15, 22], [12, 14, 16, 21], [12, 14, 18, 27], - [12, 14, 20, 35], [12, 14, 23, 34], [12, 14, 24, 25], [12, 14, 28, 37], - [12, 14, 29, 30], [12, 15, 16, 30], [12, 15, 17, 35], [12, 15, 19, 31], - [12, 15, 20, 32], [12, 15, 21, 29], [12, 15, 23, 37], [12, 15, 24, 36], - [12, 15, 27, 34], [12, 16, 17, 19], [12, 16, 20, 37], [12, 16, 23, 32], - [12, 16, 29, 34], [12, 16, 31, 35], [12, 17, 18, 36], [12, 17, 22, 32], - [12, 17, 23, 25], [12, 17, 24, 26], [12, 17, 30, 31], [12, 17, 33, 37], - [12, 18, 21, 24], [12, 18, 22, 30], [12, 18, 31, 37], [12, 18, 34, 35], - [12, 19, 20, 23], [12, 19, 22, 33], [12, 19, 25, 32], [12, 19, 26, 34], - [12, 19, 30, 36], [12, 20, 24, 30], [12, 20, 26, 27], [12, 20, 28, 33], - [12, 20, 29, 31], [12, 21, 25, 35], [12, 21, 26, 30], [12, 21, 27, 37], - [12, 21, 34, 36], [12, 22, 24, 27], [12, 22, 26, 28], [12, 23, 24, 28], - [12, 23, 26, 36], [12, 23, 31, 33], [12, 24, 29, 32], [12, 24, 34, 37], - [12, 25, 28, 36], [12, 25, 29, 33], [12, 26, 31, 32], [12, 27, 29, 35], - [12, 27, 30, 32], [12, 32, 35, 36], [13, 14, 15, 27], [13, 14, 19, 30], - [13, 14, 20, 25], [13, 14, 22, 23], [13, 14, 24, 31], [13, 14, 29, 35], - [13, 14, 34, 36], [13, 15, 16, 23], [13, 15, 17, 22], [13, 15, 19, 28], - [13, 15, 21, 36], [13, 15, 24, 35], [13, 15, 25, 26], [13, 15, 30, 31], - [13, 16, 17, 31], [13, 16, 18, 36], [13, 16, 20, 32], [13, 16, 21, 33], - [13, 16, 22, 30], [13, 16, 25, 37], [13, 16, 28, 35], [13, 17, 18, 20], - [13, 17, 24, 33], [13, 17, 30, 35], [13, 17, 32, 36], [13, 18, 19, 37], - [13, 18, 23, 33], [13, 18, 24, 26], [13, 18, 25, 27], [13, 18, 31, 32], - [13, 19, 22, 25], [13, 19, 23, 31], [13, 19, 35, 36], [13, 20, 21, 24], - [13, 20, 23, 34], [13, 20, 26, 33], [13, 20, 27, 35], [13, 20, 31, 37], - [13, 21, 25, 31], [13, 21, 27, 28], [13, 21, 29, 34], [13, 21, 30, 32], - [13, 22, 26, 36], [13, 22, 27, 31], [13, 22, 35, 37], [13, 23, 25, 28], - [13, 23, 27, 29], [13, 24, 25, 29], [13, 24, 27, 37], [13, 24, 32, 34], - [13, 25, 30, 33], [13, 26, 29, 37], [13, 26, 30, 34], [13, 27, 32, 33], - [13, 28, 30, 36], [13, 28, 31, 33], [13, 33, 36, 37], [14, 15, 16, 28], - [14, 15, 20, 31], [14, 15, 21, 26], [14, 15, 23, 24], [14, 15, 25, 32], - [14, 15, 30, 36], [14, 15, 35, 37], [14, 16, 17, 24], [14, 16, 18, 23], - [14, 16, 20, 29], [14, 16, 22, 37], [14, 16, 25, 36], [14, 16, 26, 27], - [14, 16, 31, 32], [14, 17, 18, 32], [14, 17, 19, 37], [14, 17, 21, 33], - [14, 17, 22, 34], [14, 17, 23, 31], [14, 17, 29, 36], [14, 18, 19, 21], - [14, 18, 25, 34], [14, 18, 31, 36], [14, 18, 33, 37], [14, 19, 24, 34], - [14, 19, 25, 27], [14, 19, 26, 28], [14, 19, 32, 33], [14, 20, 23, 26], - [14, 20, 24, 32], [14, 20, 36, 37], [14, 21, 22, 25], [14, 21, 24, 35], - [14, 21, 27, 34], [14, 21, 28, 36], [14, 22, 26, 32], [14, 22, 28, 29], - [14, 22, 30, 35], [14, 22, 31, 33], [14, 23, 27, 37], [14, 23, 28, 32], - [14, 24, 26, 29], [14, 24, 28, 30], [14, 25, 26, 30], [14, 25, 33, 35], - [14, 26, 31, 34], [14, 27, 31, 35], [14, 28, 33, 34], [14, 29, 31, 37], - [14, 29, 32, 34], [15, 16, 17, 29], [15, 16, 21, 32], [15, 16, 22, 27], - [15, 16, 24, 25], [15, 16, 26, 33], [15, 16, 31, 37], [15, 17, 18, 25], - [15, 17, 19, 24], [15, 17, 21, 30], [15, 17, 26, 37], [15, 17, 27, 28], - [15, 17, 32, 33], [15, 18, 19, 33], [15, 18, 22, 34], [15, 18, 23, 35], - [15, 18, 24, 32], [15, 18, 30, 37], [15, 19, 20, 22], [15, 19, 26, 35], - [15, 19, 32, 37], [15, 20, 25, 35], [15, 20, 26, 28], [15, 20, 27, 29], - [15, 20, 33, 34], [15, 21, 24, 27], [15, 21, 25, 33], [15, 22, 23, 26], - [15, 22, 25, 36], [15, 22, 28, 35], [15, 22, 29, 37], [15, 23, 27, 33], - [15, 23, 29, 30], [15, 23, 31, 36], [15, 23, 32, 34], [15, 24, 29, 33], - [15, 25, 27, 30], [15, 25, 29, 31], [15, 26, 27, 31], [15, 26, 34, 36], - [15, 27, 32, 35], [15, 28, 32, 36], [15, 29, 34, 35], [15, 30, 33, 35], - [16, 17, 18, 30], [16, 17, 22, 33], [16, 17, 23, 28], [16, 17, 25, 26], - [16, 17, 27, 34], [16, 18, 19, 26], [16, 18, 20, 25], [16, 18, 22, 31], - [16, 18, 28, 29], [16, 18, 33, 34], [16, 19, 20, 34], [16, 19, 23, 35], - [16, 19, 24, 36], [16, 19, 25, 33], [16, 20, 21, 23], [16, 20, 27, 36], - [16, 21, 26, 36], [16, 21, 27, 29], [16, 21, 28, 30], [16, 21, 34, 35], - [16, 22, 25, 28], [16, 22, 26, 34], [16, 23, 24, 27], [16, 23, 26, 37], - [16, 23, 29, 36], [16, 24, 28, 34], [16, 24, 30, 31], [16, 24, 32, 37], - [16, 24, 33, 35], [16, 25, 30, 34], [16, 26, 28, 31], [16, 26, 30, 32], - [16, 27, 28, 32], [16, 27, 35, 37], [16, 28, 33, 36], [16, 29, 33, 37], - [16, 30, 35, 36], [16, 31, 34, 36], [17, 18, 19, 31], [17, 18, 23, 34], - [17, 18, 24, 29], [17, 18, 26, 27], [17, 18, 28, 35], [17, 19, 20, 27], - [17, 19, 21, 26], [17, 19, 23, 32], [17, 19, 29, 30], [17, 19, 34, 35], - [17, 20, 21, 35], [17, 20, 24, 36], [17, 20, 25, 37], [17, 20, 26, 34], - [17, 21, 22, 24], [17, 21, 28, 37], [17, 22, 27, 37], [17, 22, 28, 30], - [17, 22, 29, 31], [17, 22, 35, 36], [17, 23, 26, 29], [17, 23, 27, 35], - [17, 24, 25, 28], [17, 24, 30, 37], [17, 25, 29, 35], [17, 25, 31, 32], - [17, 25, 34, 36], [17, 26, 31, 35], [17, 27, 29, 32], [17, 27, 31, 33], - [17, 28, 29, 33], [17, 29, 34, 37], [17, 31, 36, 37], [17, 32, 35, 37], - [18, 19, 20, 32], [18, 19, 24, 35], [18, 19, 25, 30], [18, 19, 27, 28], - [18, 19, 29, 36], [18, 20, 21, 28], [18, 20, 22, 27], [18, 20, 24, 33], - [18, 20, 30, 31], [18, 20, 35, 36], [18, 21, 22, 36], [18, 21, 25, 37], - [18, 21, 27, 35], [18, 22, 23, 25], [18, 23, 29, 31], [18, 23, 30, 32], - [18, 23, 36, 37], [18, 24, 27, 30], [18, 24, 28, 36], [18, 25, 26, 29], - [18, 26, 30, 36], [18, 26, 32, 33], [18, 26, 35, 37], [18, 27, 32, 36], - [18, 28, 30, 33], [18, 28, 32, 34], [18, 29, 30, 34], [19, 20, 21, 33], - [19, 20, 25, 36], [19, 20, 26, 31], [19, 20, 28, 29], [19, 20, 30, 37], - [19, 21, 22, 29], [19, 21, 23, 28], [19, 21, 25, 34], [19, 21, 31, 32], - [19, 21, 36, 37], [19, 22, 23, 37], [19, 22, 28, 36], [19, 23, 24, 26], - [19, 24, 30, 32], [19, 24, 31, 33], [19, 25, 28, 31], [19, 25, 29, 37], - [19, 26, 27, 30], [19, 27, 31, 37], [19, 27, 33, 34], [19, 28, 33, 37], - [19, 29, 31, 34], [19, 29, 33, 35], [19, 30, 31, 35], [20, 21, 22, 34], - [20, 21, 26, 37], [20, 21, 27, 32], [20, 21, 29, 30], [20, 22, 23, 30], - [20, 22, 24, 29], [20, 22, 26, 35], [20, 22, 32, 33], [20, 23, 29, 37], - [20, 24, 25, 27], [20, 25, 31, 33], [20, 25, 32, 34], [20, 26, 29, 32], - [20, 27, 28, 31], [20, 28, 34, 35], [20, 30, 32, 35], [20, 30, 34, 36], - [20, 31, 32, 36], [21, 22, 23, 35], [21, 22, 28, 33], [21, 22, 30, 31], - [21, 23, 24, 31], [21, 23, 25, 30], [21, 23, 27, 36], [21, 23, 33, 34], - [21, 25, 26, 28], [21, 26, 32, 34], [21, 26, 33, 35], [21, 27, 30, 33], - [21, 28, 29, 32], [21, 29, 35, 36], [21, 31, 33, 36], [21, 31, 35, 37], - [21, 32, 33, 37], [22, 23, 24, 36], [22, 23, 29, 34], [22, 23, 31, 32], - [22, 24, 25, 32], [22, 24, 26, 31], [22, 24, 28, 37], [22, 24, 34, 35], - [22, 26, 27, 29], [22, 27, 33, 35], [22, 27, 34, 36], [22, 28, 31, 34], - [22, 29, 30, 33], [22, 30, 36, 37], [22, 32, 34, 37], [23, 24, 25, 37], - [23, 24, 30, 35], [23, 24, 32, 33], [23, 25, 26, 33], [23, 25, 27, 32], - [23, 25, 35, 36], [23, 27, 28, 30], [23, 28, 34, 36], [23, 28, 35, 37], - [23, 29, 32, 35], [23, 30, 31, 34], [24, 25, 31, 36], [24, 25, 33, 34], - [24, 26, 27, 34], [24, 26, 28, 33], [24, 26, 36, 37], [24, 28, 29, 31], - [24, 29, 35, 37], [24, 30, 33, 36], [24, 31, 32, 35], [25, 26, 32, 37], - [25, 26, 34, 35], [25, 27, 28, 35], [25, 27, 29, 34], [25, 29, 30, 32], - [25, 31, 34, 37], [25, 32, 33, 36], [26, 27, 35, 36], [26, 28, 29, 36], - [26, 28, 30, 35], [26, 30, 31, 33], [26, 33, 34, 37], [27, 28, 36, 37], - [27, 29, 30, 37], [27, 29, 31, 36], [27, 31, 32, 34], [28, 30, 32, 37], - [28, 32, 33, 35], [29, 33, 34, 36], [30, 34, 35, 37]] + return [ + [0, 1, 2, 14], + [0, 1, 3, 34], + [0, 1, 4, 31], + [0, 1, 5, 27], + [0, 1, 6, 17], + [0, 1, 7, 12], + [0, 1, 8, 36], + [0, 1, 9, 10], + [0, 1, 11, 18], + [0, 1, 13, 37], + [0, 1, 15, 35], + [0, 1, 16, 22], + [0, 1, 19, 33], + [0, 1, 20, 25], + [0, 1, 21, 23], + [0, 1, 24, 32], + [0, 1, 26, 28], + [0, 1, 29, 30], + [0, 2, 3, 10], + [0, 2, 4, 9], + [0, 2, 5, 28], + [0, 2, 6, 15], + [0, 2, 7, 36], + [0, 2, 8, 23], + [0, 2, 11, 22], + [0, 2, 12, 13], + [0, 2, 16, 25], + [0, 2, 17, 18], + [0, 2, 19, 30], + [0, 2, 20, 35], + [0, 2, 21, 29], + [0, 2, 24, 34], + [0, 2, 26, 31], + [0, 2, 27, 32], + [0, 2, 33, 37], + [0, 3, 4, 18], + [0, 3, 5, 23], + [0, 3, 6, 32], + [0, 3, 7, 19], + [0, 3, 8, 20], + [0, 3, 9, 17], + [0, 3, 11, 25], + [0, 3, 12, 24], + [0, 3, 13, 27], + [0, 3, 14, 31], + [0, 3, 15, 22], + [0, 3, 16, 28], + [0, 3, 21, 33], + [0, 3, 26, 36], + [0, 3, 29, 35], + [0, 3, 30, 37], + [0, 4, 5, 7], + [0, 4, 6, 28], + [0, 4, 8, 25], + [0, 4, 10, 30], + [0, 4, 11, 20], + [0, 4, 12, 32], + [0, 4, 13, 36], + [0, 4, 14, 29], + [0, 4, 15, 27], + [0, 4, 16, 35], + [0, 4, 17, 22], + [0, 4, 19, 23], + [0, 4, 21, 34], + [0, 4, 24, 33], + [0, 4, 26, 37], + [0, 5, 6, 24], + [0, 5, 8, 26], + [0, 5, 9, 29], + [0, 5, 10, 20], + [0, 5, 11, 13], + [0, 5, 12, 14], + [0, 5, 15, 33], + [0, 5, 16, 37], + [0, 5, 17, 35], + [0, 5, 18, 19], + [0, 5, 21, 25], + [0, 5, 22, 30], + [0, 5, 31, 32], + [0, 5, 34, 36], + [0, 6, 7, 30], + [0, 6, 8, 33], + [0, 6, 9, 12], + [0, 6, 10, 18], + [0, 6, 11, 37], + [0, 6, 13, 31], + [0, 6, 14, 35], + [0, 6, 16, 29], + [0, 6, 19, 25], + [0, 6, 20, 27], + [0, 6, 21, 36], + [0, 6, 22, 23], + [0, 6, 26, 34], + [0, 7, 8, 11], + [0, 7, 9, 33], + [0, 7, 10, 21], + [0, 7, 13, 20], + [0, 7, 14, 22], + [0, 7, 15, 31], + [0, 7, 16, 34], + [0, 7, 17, 29], + [0, 7, 18, 24], + [0, 7, 23, 26], + [0, 7, 25, 32], + [0, 7, 27, 28], + [0, 7, 35, 37], + [0, 8, 9, 37], + [0, 8, 10, 27], + [0, 8, 12, 18], + [0, 8, 13, 30], + [0, 8, 14, 15], + [0, 8, 16, 21], + [0, 8, 17, 19], + [0, 8, 22, 35], + [0, 8, 24, 31], + [0, 8, 28, 34], + [0, 8, 29, 32], + [0, 9, 11, 30], + [0, 9, 13, 23], + [0, 9, 14, 18], + [0, 9, 15, 25], + [0, 9, 16, 26], + [0, 9, 19, 28], + [0, 9, 20, 36], + [0, 9, 21, 35], + [0, 9, 22, 24], + [0, 9, 27, 31], + [0, 9, 32, 34], + [0, 10, 11, 36], + [0, 10, 12, 15], + [0, 10, 13, 26], + [0, 10, 14, 16], + [0, 10, 17, 37], + [0, 10, 19, 29], + [0, 10, 22, 31], + [0, 10, 23, 32], + [0, 10, 24, 35], + [0, 10, 25, 34], + [0, 10, 28, 33], + [0, 11, 12, 16], + [0, 11, 14, 24], + [0, 11, 15, 26], + [0, 11, 17, 31], + [0, 11, 19, 21], + [0, 11, 23, 34], + [0, 11, 27, 29], + [0, 11, 28, 35], + [0, 11, 32, 33], + [0, 12, 17, 20], + [0, 12, 19, 35], + [0, 12, 21, 28], + [0, 12, 22, 25], + [0, 12, 23, 27], + [0, 12, 26, 29], + [0, 12, 30, 33], + [0, 12, 31, 34], + [0, 12, 36, 37], + [0, 13, 14, 33], + [0, 13, 15, 29], + [0, 13, 16, 24], + [0, 13, 17, 21], + [0, 13, 18, 34], + [0, 13, 19, 32], + [0, 13, 22, 28], + [0, 13, 25, 35], + [0, 14, 17, 26], + [0, 14, 19, 20], + [0, 14, 21, 32], + [0, 14, 23, 36], + [0, 14, 25, 28], + [0, 14, 27, 30], + [0, 14, 34, 37], + [0, 15, 16, 36], + [0, 15, 17, 23], + [0, 15, 18, 20], + [0, 15, 19, 34], + [0, 15, 21, 37], + [0, 15, 24, 28], + [0, 15, 30, 32], + [0, 16, 17, 32], + [0, 16, 18, 27], + [0, 16, 19, 31], + [0, 16, 20, 33], + [0, 16, 23, 30], + [0, 17, 24, 27], + [0, 17, 25, 33], + [0, 17, 28, 36], + [0, 17, 30, 34], + [0, 18, 21, 26], + [0, 18, 22, 29], + [0, 18, 23, 28], + [0, 18, 25, 31], + [0, 18, 30, 35], + [0, 18, 32, 37], + [0, 18, 33, 36], + [0, 19, 22, 26], + [0, 19, 24, 37], + [0, 19, 27, 36], + [0, 20, 21, 31], + [0, 20, 22, 37], + [0, 20, 23, 24], + [0, 20, 26, 30], + [0, 20, 28, 32], + [0, 20, 29, 34], + [0, 21, 22, 27], + [0, 21, 24, 30], + [0, 22, 32, 36], + [0, 22, 33, 34], + [0, 23, 25, 29], + [0, 23, 31, 37], + [0, 23, 33, 35], + [0, 24, 25, 26], + [0, 24, 29, 36], + [0, 25, 27, 37], + [0, 25, 30, 36], + [0, 26, 27, 33], + [0, 26, 32, 35], + [0, 27, 34, 35], + [0, 28, 29, 37], + [0, 28, 30, 31], + [0, 29, 31, 33], + [0, 31, 35, 36], + [1, 2, 3, 15], + [1, 2, 4, 35], + [1, 2, 5, 32], + [1, 2, 6, 28], + [1, 2, 7, 18], + [1, 2, 8, 13], + [1, 2, 9, 37], + [1, 2, 10, 11], + [1, 2, 12, 19], + [1, 2, 16, 36], + [1, 2, 17, 23], + [1, 2, 20, 34], + [1, 2, 21, 26], + [1, 2, 22, 24], + [1, 2, 25, 33], + [1, 2, 27, 29], + [1, 2, 30, 31], + [1, 3, 4, 11], + [1, 3, 5, 10], + [1, 3, 6, 29], + [1, 3, 7, 16], + [1, 3, 8, 37], + [1, 3, 9, 24], + [1, 3, 12, 23], + [1, 3, 13, 14], + [1, 3, 17, 26], + [1, 3, 18, 19], + [1, 3, 20, 31], + [1, 3, 21, 36], + [1, 3, 22, 30], + [1, 3, 25, 35], + [1, 3, 27, 32], + [1, 3, 28, 33], + [1, 4, 5, 19], + [1, 4, 6, 24], + [1, 4, 7, 33], + [1, 4, 8, 20], + [1, 4, 9, 21], + [1, 4, 10, 18], + [1, 4, 12, 26], + [1, 4, 13, 25], + [1, 4, 14, 28], + [1, 4, 15, 32], + [1, 4, 16, 23], + [1, 4, 17, 29], + [1, 4, 22, 34], + [1, 4, 27, 37], + [1, 4, 30, 36], + [1, 5, 6, 8], + [1, 5, 7, 29], + [1, 5, 9, 26], + [1, 5, 11, 31], + [1, 5, 12, 21], + [1, 5, 13, 33], + [1, 5, 14, 37], + [1, 5, 15, 30], + [1, 5, 16, 28], + [1, 5, 17, 36], + [1, 5, 18, 23], + [1, 5, 20, 24], + [1, 5, 22, 35], + [1, 5, 25, 34], + [1, 6, 7, 25], + [1, 6, 9, 27], + [1, 6, 10, 30], + [1, 6, 11, 21], + [1, 6, 12, 14], + [1, 6, 13, 15], + [1, 6, 16, 34], + [1, 6, 18, 36], + [1, 6, 19, 20], + [1, 6, 22, 26], + [1, 6, 23, 31], + [1, 6, 32, 33], + [1, 6, 35, 37], + [1, 7, 8, 31], + [1, 7, 9, 34], + [1, 7, 10, 13], + [1, 7, 11, 19], + [1, 7, 14, 32], + [1, 7, 15, 36], + [1, 7, 17, 30], + [1, 7, 20, 26], + [1, 7, 21, 28], + [1, 7, 22, 37], + [1, 7, 23, 24], + [1, 7, 27, 35], + [1, 8, 9, 12], + [1, 8, 10, 34], + [1, 8, 11, 22], + [1, 8, 14, 21], + [1, 8, 15, 23], + [1, 8, 16, 32], + [1, 8, 17, 35], + [1, 8, 18, 30], + [1, 8, 19, 25], + [1, 8, 24, 27], + [1, 8, 26, 33], + [1, 8, 28, 29], + [1, 9, 11, 28], + [1, 9, 13, 19], + [1, 9, 14, 31], + [1, 9, 15, 16], + [1, 9, 17, 22], + [1, 9, 18, 20], + [1, 9, 23, 36], + [1, 9, 25, 32], + [1, 9, 29, 35], + [1, 9, 30, 33], + [1, 10, 12, 31], + [1, 10, 14, 24], + [1, 10, 15, 19], + [1, 10, 16, 26], + [1, 10, 17, 27], + [1, 10, 20, 29], + [1, 10, 21, 37], + [1, 10, 22, 36], + [1, 10, 23, 25], + [1, 10, 28, 32], + [1, 10, 33, 35], + [1, 11, 12, 37], + [1, 11, 13, 16], + [1, 11, 14, 27], + [1, 11, 15, 17], + [1, 11, 20, 30], + [1, 11, 23, 32], + [1, 11, 24, 33], + [1, 11, 25, 36], + [1, 11, 26, 35], + [1, 11, 29, 34], + [1, 12, 13, 17], + [1, 12, 15, 25], + [1, 12, 16, 27], + [1, 12, 18, 32], + [1, 12, 20, 22], + [1, 12, 24, 35], + [1, 12, 28, 30], + [1, 12, 29, 36], + [1, 12, 33, 34], + [1, 13, 18, 21], + [1, 13, 20, 36], + [1, 13, 22, 29], + [1, 13, 23, 26], + [1, 13, 24, 28], + [1, 13, 27, 30], + [1, 13, 31, 34], + [1, 13, 32, 35], + [1, 14, 15, 34], + [1, 14, 16, 30], + [1, 14, 17, 25], + [1, 14, 18, 22], + [1, 14, 19, 35], + [1, 14, 20, 33], + [1, 14, 23, 29], + [1, 14, 26, 36], + [1, 15, 18, 27], + [1, 15, 20, 21], + [1, 15, 22, 33], + [1, 15, 24, 37], + [1, 15, 26, 29], + [1, 15, 28, 31], + [1, 16, 17, 37], + [1, 16, 18, 24], + [1, 16, 19, 21], + [1, 16, 20, 35], + [1, 16, 25, 29], + [1, 16, 31, 33], + [1, 17, 18, 33], + [1, 17, 19, 28], + [1, 17, 20, 32], + [1, 17, 21, 34], + [1, 17, 24, 31], + [1, 18, 25, 28], + [1, 18, 26, 34], + [1, 18, 29, 37], + [1, 18, 31, 35], + [1, 19, 22, 27], + [1, 19, 23, 30], + [1, 19, 24, 29], + [1, 19, 26, 32], + [1, 19, 31, 36], + [1, 19, 34, 37], + [1, 20, 23, 27], + [1, 20, 28, 37], + [1, 21, 22, 32], + [1, 21, 24, 25], + [1, 21, 27, 31], + [1, 21, 29, 33], + [1, 21, 30, 35], + [1, 22, 23, 28], + [1, 22, 25, 31], + [1, 23, 33, 37], + [1, 23, 34, 35], + [1, 24, 26, 30], + [1, 24, 34, 36], + [1, 25, 26, 27], + [1, 25, 30, 37], + [1, 26, 31, 37], + [1, 27, 28, 34], + [1, 27, 33, 36], + [1, 28, 35, 36], + [1, 29, 31, 32], + [1, 30, 32, 34], + [1, 32, 36, 37], + [2, 3, 4, 16], + [2, 3, 5, 36], + [2, 3, 6, 33], + [2, 3, 7, 29], + [2, 3, 8, 19], + [2, 3, 9, 14], + [2, 3, 11, 12], + [2, 3, 13, 20], + [2, 3, 17, 37], + [2, 3, 18, 24], + [2, 3, 21, 35], + [2, 3, 22, 27], + [2, 3, 23, 25], + [2, 3, 26, 34], + [2, 3, 28, 30], + [2, 3, 31, 32], + [2, 4, 5, 12], + [2, 4, 6, 11], + [2, 4, 7, 30], + [2, 4, 8, 17], + [2, 4, 10, 25], + [2, 4, 13, 24], + [2, 4, 14, 15], + [2, 4, 18, 27], + [2, 4, 19, 20], + [2, 4, 21, 32], + [2, 4, 22, 37], + [2, 4, 23, 31], + [2, 4, 26, 36], + [2, 4, 28, 33], + [2, 4, 29, 34], + [2, 5, 6, 20], + [2, 5, 7, 25], + [2, 5, 8, 34], + [2, 5, 9, 21], + [2, 5, 10, 22], + [2, 5, 11, 19], + [2, 5, 13, 27], + [2, 5, 14, 26], + [2, 5, 15, 29], + [2, 5, 16, 33], + [2, 5, 17, 24], + [2, 5, 18, 30], + [2, 5, 23, 35], + [2, 5, 31, 37], + [2, 6, 7, 9], + [2, 6, 8, 30], + [2, 6, 10, 27], + [2, 6, 12, 32], + [2, 6, 13, 22], + [2, 6, 14, 34], + [2, 6, 16, 31], + [2, 6, 17, 29], + [2, 6, 18, 37], + [2, 6, 19, 24], + [2, 6, 21, 25], + [2, 6, 23, 36], + [2, 6, 26, 35], + [2, 7, 8, 26], + [2, 7, 10, 28], + [2, 7, 11, 31], + [2, 7, 12, 22], + [2, 7, 13, 15], + [2, 7, 14, 16], + [2, 7, 17, 35], + [2, 7, 19, 37], + [2, 7, 20, 21], + [2, 7, 23, 27], + [2, 7, 24, 32], + [2, 7, 33, 34], + [2, 8, 9, 32], + [2, 8, 10, 35], + [2, 8, 11, 14], + [2, 8, 12, 20], + [2, 8, 15, 33], + [2, 8, 16, 37], + [2, 8, 18, 31], + [2, 8, 21, 27], + [2, 8, 22, 29], + [2, 8, 24, 25], + [2, 8, 28, 36], + [2, 9, 10, 13], + [2, 9, 11, 35], + [2, 9, 12, 23], + [2, 9, 15, 22], + [2, 9, 16, 24], + [2, 9, 17, 33], + [2, 9, 18, 36], + [2, 9, 19, 31], + [2, 9, 20, 26], + [2, 9, 25, 28], + [2, 9, 27, 34], + [2, 9, 29, 30], + [2, 10, 12, 29], + [2, 10, 14, 20], + [2, 10, 15, 32], + [2, 10, 16, 17], + [2, 10, 18, 23], + [2, 10, 19, 21], + [2, 10, 24, 37], + [2, 10, 26, 33], + [2, 10, 30, 36], + [2, 10, 31, 34], + [2, 11, 13, 32], + [2, 11, 15, 25], + [2, 11, 16, 20], + [2, 11, 17, 27], + [2, 11, 18, 28], + [2, 11, 21, 30], + [2, 11, 23, 37], + [2, 11, 24, 26], + [2, 11, 29, 33], + [2, 11, 34, 36], + [2, 12, 14, 17], + [2, 12, 15, 28], + [2, 12, 16, 18], + [2, 12, 21, 31], + [2, 12, 24, 33], + [2, 12, 25, 34], + [2, 12, 26, 37], + [2, 12, 27, 36], + [2, 12, 30, 35], + [2, 13, 14, 18], + [2, 13, 16, 26], + [2, 13, 17, 28], + [2, 13, 19, 33], + [2, 13, 21, 23], + [2, 13, 25, 36], + [2, 13, 29, 31], + [2, 13, 30, 37], + [2, 13, 34, 35], + [2, 14, 19, 22], + [2, 14, 21, 37], + [2, 14, 23, 30], + [2, 14, 24, 27], + [2, 14, 25, 29], + [2, 14, 28, 31], + [2, 14, 32, 35], + [2, 14, 33, 36], + [2, 15, 16, 35], + [2, 15, 17, 31], + [2, 15, 18, 26], + [2, 15, 19, 23], + [2, 15, 20, 36], + [2, 15, 21, 34], + [2, 15, 24, 30], + [2, 15, 27, 37], + [2, 16, 19, 28], + [2, 16, 21, 22], + [2, 16, 23, 34], + [2, 16, 27, 30], + [2, 16, 29, 32], + [2, 17, 19, 25], + [2, 17, 20, 22], + [2, 17, 21, 36], + [2, 17, 26, 30], + [2, 17, 32, 34], + [2, 18, 19, 34], + [2, 18, 20, 29], + [2, 18, 21, 33], + [2, 18, 22, 35], + [2, 18, 25, 32], + [2, 19, 26, 29], + [2, 19, 27, 35], + [2, 19, 32, 36], + [2, 20, 23, 28], + [2, 20, 24, 31], + [2, 20, 25, 30], + [2, 20, 27, 33], + [2, 20, 32, 37], + [2, 21, 24, 28], + [2, 22, 23, 33], + [2, 22, 25, 26], + [2, 22, 28, 32], + [2, 22, 30, 34], + [2, 22, 31, 36], + [2, 23, 24, 29], + [2, 23, 26, 32], + [2, 24, 35, 36], + [2, 25, 27, 31], + [2, 25, 35, 37], + [2, 26, 27, 28], + [2, 28, 29, 35], + [2, 28, 34, 37], + [2, 29, 36, 37], + [2, 30, 32, 33], + [2, 31, 33, 35], + [3, 4, 5, 17], + [3, 4, 6, 37], + [3, 4, 7, 34], + [3, 4, 8, 30], + [3, 4, 9, 20], + [3, 4, 10, 15], + [3, 4, 12, 13], + [3, 4, 14, 21], + [3, 4, 19, 25], + [3, 4, 22, 36], + [3, 4, 23, 28], + [3, 4, 24, 26], + [3, 4, 27, 35], + [3, 4, 29, 31], + [3, 4, 32, 33], + [3, 5, 6, 13], + [3, 5, 7, 12], + [3, 5, 8, 31], + [3, 5, 9, 18], + [3, 5, 11, 26], + [3, 5, 14, 25], + [3, 5, 15, 16], + [3, 5, 19, 28], + [3, 5, 20, 21], + [3, 5, 22, 33], + [3, 5, 24, 32], + [3, 5, 27, 37], + [3, 5, 29, 34], + [3, 5, 30, 35], + [3, 6, 7, 21], + [3, 6, 8, 26], + [3, 6, 9, 35], + [3, 6, 10, 22], + [3, 6, 11, 23], + [3, 6, 12, 20], + [3, 6, 14, 28], + [3, 6, 15, 27], + [3, 6, 16, 30], + [3, 6, 17, 34], + [3, 6, 18, 25], + [3, 6, 19, 31], + [3, 6, 24, 36], + [3, 7, 8, 10], + [3, 7, 9, 31], + [3, 7, 11, 28], + [3, 7, 13, 33], + [3, 7, 14, 23], + [3, 7, 15, 35], + [3, 7, 17, 32], + [3, 7, 18, 30], + [3, 7, 20, 25], + [3, 7, 22, 26], + [3, 7, 24, 37], + [3, 7, 27, 36], + [3, 8, 9, 27], + [3, 8, 11, 29], + [3, 8, 12, 32], + [3, 8, 13, 23], + [3, 8, 14, 16], + [3, 8, 15, 17], + [3, 8, 18, 36], + [3, 8, 21, 22], + [3, 8, 24, 28], + [3, 8, 25, 33], + [3, 8, 34, 35], + [3, 9, 10, 33], + [3, 9, 11, 36], + [3, 9, 12, 15], + [3, 9, 13, 21], + [3, 9, 16, 34], + [3, 9, 19, 32], + [3, 9, 22, 28], + [3, 9, 23, 30], + [3, 9, 25, 26], + [3, 9, 29, 37], + [3, 10, 11, 14], + [3, 10, 12, 36], + [3, 10, 13, 24], + [3, 10, 16, 23], + [3, 10, 17, 25], + [3, 10, 18, 34], + [3, 10, 19, 37], + [3, 10, 20, 32], + [3, 10, 21, 27], + [3, 10, 26, 29], + [3, 10, 28, 35], + [3, 10, 30, 31], + [3, 11, 13, 30], + [3, 11, 15, 21], + [3, 11, 16, 33], + [3, 11, 17, 18], + [3, 11, 19, 24], + [3, 11, 20, 22], + [3, 11, 27, 34], + [3, 11, 31, 37], + [3, 11, 32, 35], + [3, 12, 14, 33], + [3, 12, 16, 26], + [3, 12, 17, 21], + [3, 12, 18, 28], + [3, 12, 19, 29], + [3, 12, 22, 31], + [3, 12, 25, 27], + [3, 12, 30, 34], + [3, 12, 35, 37], + [3, 13, 15, 18], + [3, 13, 16, 29], + [3, 13, 17, 19], + [3, 13, 22, 32], + [3, 13, 25, 34], + [3, 13, 26, 35], + [3, 13, 28, 37], + [3, 13, 31, 36], + [3, 14, 15, 19], + [3, 14, 17, 27], + [3, 14, 18, 29], + [3, 14, 20, 34], + [3, 14, 22, 24], + [3, 14, 26, 37], + [3, 14, 30, 32], + [3, 14, 35, 36], + [3, 15, 20, 23], + [3, 15, 24, 31], + [3, 15, 25, 28], + [3, 15, 26, 30], + [3, 15, 29, 32], + [3, 15, 33, 36], + [3, 15, 34, 37], + [3, 16, 17, 36], + [3, 16, 18, 32], + [3, 16, 19, 27], + [3, 16, 20, 24], + [3, 16, 21, 37], + [3, 16, 22, 35], + [3, 16, 25, 31], + [3, 17, 20, 29], + [3, 17, 22, 23], + [3, 17, 24, 35], + [3, 17, 28, 31], + [3, 17, 30, 33], + [3, 18, 20, 26], + [3, 18, 21, 23], + [3, 18, 22, 37], + [3, 18, 27, 31], + [3, 18, 33, 35], + [3, 19, 20, 35], + [3, 19, 21, 30], + [3, 19, 22, 34], + [3, 19, 23, 36], + [3, 19, 26, 33], + [3, 20, 27, 30], + [3, 20, 28, 36], + [3, 20, 33, 37], + [3, 21, 24, 29], + [3, 21, 25, 32], + [3, 21, 26, 31], + [3, 21, 28, 34], + [3, 22, 25, 29], + [3, 23, 24, 34], + [3, 23, 26, 27], + [3, 23, 29, 33], + [3, 23, 31, 35], + [3, 23, 32, 37], + [3, 24, 25, 30], + [3, 24, 27, 33], + [3, 25, 36, 37], + [3, 26, 28, 32], + [3, 27, 28, 29], + [3, 29, 30, 36], + [3, 31, 33, 34], + [3, 32, 34, 36], + [4, 5, 6, 18], + [4, 5, 8, 35], + [4, 5, 9, 31], + [4, 5, 10, 21], + [4, 5, 11, 16], + [4, 5, 13, 14], + [4, 5, 15, 22], + [4, 5, 20, 26], + [4, 5, 23, 37], + [4, 5, 24, 29], + [4, 5, 25, 27], + [4, 5, 28, 36], + [4, 5, 30, 32], + [4, 5, 33, 34], + [4, 6, 7, 14], + [4, 6, 8, 13], + [4, 6, 9, 32], + [4, 6, 10, 19], + [4, 6, 12, 27], + [4, 6, 15, 26], + [4, 6, 16, 17], + [4, 6, 20, 29], + [4, 6, 21, 22], + [4, 6, 23, 34], + [4, 6, 25, 33], + [4, 6, 30, 35], + [4, 6, 31, 36], + [4, 7, 8, 22], + [4, 7, 9, 27], + [4, 7, 10, 36], + [4, 7, 11, 23], + [4, 7, 12, 24], + [4, 7, 13, 21], + [4, 7, 15, 29], + [4, 7, 16, 28], + [4, 7, 17, 31], + [4, 7, 18, 35], + [4, 7, 19, 26], + [4, 7, 20, 32], + [4, 7, 25, 37], + [4, 8, 9, 11], + [4, 8, 10, 32], + [4, 8, 12, 29], + [4, 8, 14, 34], + [4, 8, 15, 24], + [4, 8, 16, 36], + [4, 8, 18, 33], + [4, 8, 19, 31], + [4, 8, 21, 26], + [4, 8, 23, 27], + [4, 8, 28, 37], + [4, 9, 10, 28], + [4, 9, 12, 30], + [4, 9, 13, 33], + [4, 9, 14, 24], + [4, 9, 15, 17], + [4, 9, 16, 18], + [4, 9, 19, 37], + [4, 9, 22, 23], + [4, 9, 25, 29], + [4, 9, 26, 34], + [4, 9, 35, 36], + [4, 10, 11, 34], + [4, 10, 12, 37], + [4, 10, 13, 16], + [4, 10, 14, 22], + [4, 10, 17, 35], + [4, 10, 20, 33], + [4, 10, 23, 29], + [4, 10, 24, 31], + [4, 10, 26, 27], + [4, 11, 12, 15], + [4, 11, 13, 37], + [4, 11, 14, 25], + [4, 11, 17, 24], + [4, 11, 18, 26], + [4, 11, 19, 35], + [4, 11, 21, 33], + [4, 11, 22, 28], + [4, 11, 27, 30], + [4, 11, 29, 36], + [4, 11, 31, 32], + [4, 12, 14, 31], + [4, 12, 16, 22], + [4, 12, 17, 34], + [4, 12, 18, 19], + [4, 12, 20, 25], + [4, 12, 21, 23], + [4, 12, 28, 35], + [4, 12, 33, 36], + [4, 13, 15, 34], + [4, 13, 17, 27], + [4, 13, 18, 22], + [4, 13, 19, 29], + [4, 13, 20, 30], + [4, 13, 23, 32], + [4, 13, 26, 28], + [4, 13, 31, 35], + [4, 14, 16, 19], + [4, 14, 17, 30], + [4, 14, 18, 20], + [4, 14, 23, 33], + [4, 14, 26, 35], + [4, 14, 27, 36], + [4, 14, 32, 37], + [4, 15, 16, 20], + [4, 15, 18, 28], + [4, 15, 19, 30], + [4, 15, 21, 35], + [4, 15, 23, 25], + [4, 15, 31, 33], + [4, 15, 36, 37], + [4, 16, 21, 24], + [4, 16, 25, 32], + [4, 16, 26, 29], + [4, 16, 27, 31], + [4, 16, 30, 33], + [4, 16, 34, 37], + [4, 17, 18, 37], + [4, 17, 19, 33], + [4, 17, 20, 28], + [4, 17, 21, 25], + [4, 17, 23, 36], + [4, 17, 26, 32], + [4, 18, 21, 30], + [4, 18, 23, 24], + [4, 18, 25, 36], + [4, 18, 29, 32], + [4, 18, 31, 34], + [4, 19, 21, 27], + [4, 19, 22, 24], + [4, 19, 28, 32], + [4, 19, 34, 36], + [4, 20, 21, 36], + [4, 20, 22, 31], + [4, 20, 23, 35], + [4, 20, 24, 37], + [4, 20, 27, 34], + [4, 21, 28, 31], + [4, 21, 29, 37], + [4, 22, 25, 30], + [4, 22, 26, 33], + [4, 22, 27, 32], + [4, 22, 29, 35], + [4, 23, 26, 30], + [4, 24, 25, 35], + [4, 24, 27, 28], + [4, 24, 30, 34], + [4, 24, 32, 36], + [4, 25, 26, 31], + [4, 25, 28, 34], + [4, 27, 29, 33], + [4, 28, 29, 30], + [4, 30, 31, 37], + [4, 32, 34, 35], + [4, 33, 35, 37], + [5, 6, 7, 19], + [5, 6, 9, 36], + [5, 6, 10, 32], + [5, 6, 11, 22], + [5, 6, 12, 17], + [5, 6, 14, 15], + [5, 6, 16, 23], + [5, 6, 21, 27], + [5, 6, 25, 30], + [5, 6, 26, 28], + [5, 6, 29, 37], + [5, 6, 31, 33], + [5, 6, 34, 35], + [5, 7, 8, 15], + [5, 7, 9, 14], + [5, 7, 10, 33], + [5, 7, 11, 20], + [5, 7, 13, 28], + [5, 7, 16, 27], + [5, 7, 17, 18], + [5, 7, 21, 30], + [5, 7, 22, 23], + [5, 7, 24, 35], + [5, 7, 26, 34], + [5, 7, 31, 36], + [5, 7, 32, 37], + [5, 8, 9, 23], + [5, 8, 10, 28], + [5, 8, 11, 37], + [5, 8, 12, 24], + [5, 8, 13, 25], + [5, 8, 14, 22], + [5, 8, 16, 30], + [5, 8, 17, 29], + [5, 8, 18, 32], + [5, 8, 19, 36], + [5, 8, 20, 27], + [5, 8, 21, 33], + [5, 9, 10, 12], + [5, 9, 11, 33], + [5, 9, 13, 30], + [5, 9, 15, 35], + [5, 9, 16, 25], + [5, 9, 17, 37], + [5, 9, 19, 34], + [5, 9, 20, 32], + [5, 9, 22, 27], + [5, 9, 24, 28], + [5, 10, 11, 29], + [5, 10, 13, 31], + [5, 10, 14, 34], + [5, 10, 15, 25], + [5, 10, 16, 18], + [5, 10, 17, 19], + [5, 10, 23, 24], + [5, 10, 26, 30], + [5, 10, 27, 35], + [5, 10, 36, 37], + [5, 11, 12, 35], + [5, 11, 14, 17], + [5, 11, 15, 23], + [5, 11, 18, 36], + [5, 11, 21, 34], + [5, 11, 24, 30], + [5, 11, 25, 32], + [5, 11, 27, 28], + [5, 12, 13, 16], + [5, 12, 15, 26], + [5, 12, 18, 25], + [5, 12, 19, 27], + [5, 12, 20, 36], + [5, 12, 22, 34], + [5, 12, 23, 29], + [5, 12, 28, 31], + [5, 12, 30, 37], + [5, 12, 32, 33], + [5, 13, 15, 32], + [5, 13, 17, 23], + [5, 13, 18, 35], + [5, 13, 19, 20], + [5, 13, 21, 26], + [5, 13, 22, 24], + [5, 13, 29, 36], + [5, 13, 34, 37], + [5, 14, 16, 35], + [5, 14, 18, 28], + [5, 14, 19, 23], + [5, 14, 20, 30], + [5, 14, 21, 31], + [5, 14, 24, 33], + [5, 14, 27, 29], + [5, 14, 32, 36], + [5, 15, 17, 20], + [5, 15, 18, 31], + [5, 15, 19, 21], + [5, 15, 24, 34], + [5, 15, 27, 36], + [5, 15, 28, 37], + [5, 16, 17, 21], + [5, 16, 19, 29], + [5, 16, 20, 31], + [5, 16, 22, 36], + [5, 16, 24, 26], + [5, 16, 32, 34], + [5, 17, 22, 25], + [5, 17, 26, 33], + [5, 17, 27, 30], + [5, 17, 28, 32], + [5, 17, 31, 34], + [5, 18, 20, 34], + [5, 18, 21, 29], + [5, 18, 22, 26], + [5, 18, 24, 37], + [5, 18, 27, 33], + [5, 19, 22, 31], + [5, 19, 24, 25], + [5, 19, 26, 37], + [5, 19, 30, 33], + [5, 19, 32, 35], + [5, 20, 22, 28], + [5, 20, 23, 25], + [5, 20, 29, 33], + [5, 20, 35, 37], + [5, 21, 22, 37], + [5, 21, 23, 32], + [5, 21, 24, 36], + [5, 21, 28, 35], + [5, 22, 29, 32], + [5, 23, 26, 31], + [5, 23, 27, 34], + [5, 23, 28, 33], + [5, 23, 30, 36], + [5, 24, 27, 31], + [5, 25, 26, 36], + [5, 25, 28, 29], + [5, 25, 31, 35], + [5, 25, 33, 37], + [5, 26, 27, 32], + [5, 26, 29, 35], + [5, 28, 30, 34], + [5, 29, 30, 31], + [5, 33, 35, 36], + [6, 7, 8, 20], + [6, 7, 10, 37], + [6, 7, 11, 33], + [6, 7, 12, 23], + [6, 7, 13, 18], + [6, 7, 15, 16], + [6, 7, 17, 24], + [6, 7, 22, 28], + [6, 7, 26, 31], + [6, 7, 27, 29], + [6, 7, 32, 34], + [6, 7, 35, 36], + [6, 8, 9, 16], + [6, 8, 10, 15], + [6, 8, 11, 34], + [6, 8, 12, 21], + [6, 8, 14, 29], + [6, 8, 17, 28], + [6, 8, 18, 19], + [6, 8, 22, 31], + [6, 8, 23, 24], + [6, 8, 25, 36], + [6, 8, 27, 35], + [6, 8, 32, 37], + [6, 9, 10, 24], + [6, 9, 11, 29], + [6, 9, 13, 25], + [6, 9, 14, 26], + [6, 9, 15, 23], + [6, 9, 17, 31], + [6, 9, 18, 30], + [6, 9, 19, 33], + [6, 9, 20, 37], + [6, 9, 21, 28], + [6, 9, 22, 34], + [6, 10, 11, 13], + [6, 10, 12, 34], + [6, 10, 14, 31], + [6, 10, 16, 36], + [6, 10, 17, 26], + [6, 10, 20, 35], + [6, 10, 21, 33], + [6, 10, 23, 28], + [6, 10, 25, 29], + [6, 11, 12, 30], + [6, 11, 14, 32], + [6, 11, 15, 35], + [6, 11, 16, 26], + [6, 11, 17, 19], + [6, 11, 18, 20], + [6, 11, 24, 25], + [6, 11, 27, 31], + [6, 11, 28, 36], + [6, 12, 13, 36], + [6, 12, 15, 18], + [6, 12, 16, 24], + [6, 12, 19, 37], + [6, 12, 22, 35], + [6, 12, 25, 31], + [6, 12, 26, 33], + [6, 12, 28, 29], + [6, 13, 14, 17], + [6, 13, 16, 27], + [6, 13, 19, 26], + [6, 13, 20, 28], + [6, 13, 21, 37], + [6, 13, 23, 35], + [6, 13, 24, 30], + [6, 13, 29, 32], + [6, 13, 33, 34], + [6, 14, 16, 33], + [6, 14, 18, 24], + [6, 14, 19, 36], + [6, 14, 20, 21], + [6, 14, 22, 27], + [6, 14, 23, 25], + [6, 14, 30, 37], + [6, 15, 17, 36], + [6, 15, 19, 29], + [6, 15, 20, 24], + [6, 15, 21, 31], + [6, 15, 22, 32], + [6, 15, 25, 34], + [6, 15, 28, 30], + [6, 15, 33, 37], + [6, 16, 18, 21], + [6, 16, 19, 32], + [6, 16, 20, 22], + [6, 16, 25, 35], + [6, 16, 28, 37], + [6, 17, 18, 22], + [6, 17, 20, 30], + [6, 17, 21, 32], + [6, 17, 23, 37], + [6, 17, 25, 27], + [6, 17, 33, 35], + [6, 18, 23, 26], + [6, 18, 27, 34], + [6, 18, 28, 31], + [6, 18, 29, 33], + [6, 18, 32, 35], + [6, 19, 21, 35], + [6, 19, 22, 30], + [6, 19, 23, 27], + [6, 19, 28, 34], + [6, 20, 23, 32], + [6, 20, 25, 26], + [6, 20, 31, 34], + [6, 20, 33, 36], + [6, 21, 23, 29], + [6, 21, 24, 26], + [6, 21, 30, 34], + [6, 22, 24, 33], + [6, 22, 25, 37], + [6, 22, 29, 36], + [6, 23, 30, 33], + [6, 24, 27, 32], + [6, 24, 28, 35], + [6, 24, 29, 34], + [6, 24, 31, 37], + [6, 25, 28, 32], + [6, 26, 27, 37], + [6, 26, 29, 30], + [6, 26, 32, 36], + [6, 27, 28, 33], + [6, 27, 30, 36], + [6, 29, 31, 35], + [6, 30, 31, 32], + [6, 34, 36, 37], + [7, 8, 9, 21], + [7, 8, 12, 34], + [7, 8, 13, 24], + [7, 8, 14, 19], + [7, 8, 16, 17], + [7, 8, 18, 25], + [7, 8, 23, 29], + [7, 8, 27, 32], + [7, 8, 28, 30], + [7, 8, 33, 35], + [7, 8, 36, 37], + [7, 9, 10, 17], + [7, 9, 11, 16], + [7, 9, 12, 35], + [7, 9, 13, 22], + [7, 9, 15, 30], + [7, 9, 18, 29], + [7, 9, 19, 20], + [7, 9, 23, 32], + [7, 9, 24, 25], + [7, 9, 26, 37], + [7, 9, 28, 36], + [7, 10, 11, 25], + [7, 10, 12, 30], + [7, 10, 14, 26], + [7, 10, 15, 27], + [7, 10, 16, 24], + [7, 10, 18, 32], + [7, 10, 19, 31], + [7, 10, 20, 34], + [7, 10, 22, 29], + [7, 10, 23, 35], + [7, 11, 12, 14], + [7, 11, 13, 35], + [7, 11, 15, 32], + [7, 11, 17, 37], + [7, 11, 18, 27], + [7, 11, 21, 36], + [7, 11, 22, 34], + [7, 11, 24, 29], + [7, 11, 26, 30], + [7, 12, 13, 31], + [7, 12, 15, 33], + [7, 12, 16, 36], + [7, 12, 17, 27], + [7, 12, 18, 20], + [7, 12, 19, 21], + [7, 12, 25, 26], + [7, 12, 28, 32], + [7, 12, 29, 37], + [7, 13, 14, 37], + [7, 13, 16, 19], + [7, 13, 17, 25], + [7, 13, 23, 36], + [7, 13, 26, 32], + [7, 13, 27, 34], + [7, 13, 29, 30], + [7, 14, 15, 18], + [7, 14, 17, 28], + [7, 14, 20, 27], + [7, 14, 21, 29], + [7, 14, 24, 36], + [7, 14, 25, 31], + [7, 14, 30, 33], + [7, 14, 34, 35], + [7, 15, 17, 34], + [7, 15, 19, 25], + [7, 15, 20, 37], + [7, 15, 21, 22], + [7, 15, 23, 28], + [7, 15, 24, 26], + [7, 16, 18, 37], + [7, 16, 20, 30], + [7, 16, 21, 25], + [7, 16, 22, 32], + [7, 16, 23, 33], + [7, 16, 26, 35], + [7, 16, 29, 31], + [7, 17, 19, 22], + [7, 17, 20, 33], + [7, 17, 21, 23], + [7, 17, 26, 36], + [7, 18, 19, 23], + [7, 18, 21, 31], + [7, 18, 22, 33], + [7, 18, 26, 28], + [7, 18, 34, 36], + [7, 19, 24, 27], + [7, 19, 28, 35], + [7, 19, 29, 32], + [7, 19, 30, 34], + [7, 19, 33, 36], + [7, 20, 22, 36], + [7, 20, 23, 31], + [7, 20, 24, 28], + [7, 20, 29, 35], + [7, 21, 24, 33], + [7, 21, 26, 27], + [7, 21, 32, 35], + [7, 21, 34, 37], + [7, 22, 24, 30], + [7, 22, 25, 27], + [7, 22, 31, 35], + [7, 23, 25, 34], + [7, 23, 30, 37], + [7, 24, 31, 34], + [7, 25, 28, 33], + [7, 25, 29, 36], + [7, 25, 30, 35], + [7, 26, 29, 33], + [7, 27, 30, 31], + [7, 27, 33, 37], + [7, 28, 29, 34], + [7, 28, 31, 37], + [7, 30, 32, 36], + [7, 31, 32, 33], + [8, 9, 10, 22], + [8, 9, 13, 35], + [8, 9, 14, 25], + [8, 9, 15, 20], + [8, 9, 17, 18], + [8, 9, 19, 26], + [8, 9, 24, 30], + [8, 9, 28, 33], + [8, 9, 29, 31], + [8, 9, 34, 36], + [8, 10, 11, 18], + [8, 10, 12, 17], + [8, 10, 13, 36], + [8, 10, 14, 23], + [8, 10, 16, 31], + [8, 10, 19, 30], + [8, 10, 20, 21], + [8, 10, 24, 33], + [8, 10, 25, 26], + [8, 10, 29, 37], + [8, 11, 12, 26], + [8, 11, 13, 31], + [8, 11, 15, 27], + [8, 11, 16, 28], + [8, 11, 17, 25], + [8, 11, 19, 33], + [8, 11, 20, 32], + [8, 11, 21, 35], + [8, 11, 23, 30], + [8, 11, 24, 36], + [8, 12, 13, 15], + [8, 12, 14, 36], + [8, 12, 16, 33], + [8, 12, 19, 28], + [8, 12, 22, 37], + [8, 12, 23, 35], + [8, 12, 25, 30], + [8, 12, 27, 31], + [8, 13, 14, 32], + [8, 13, 16, 34], + [8, 13, 17, 37], + [8, 13, 18, 28], + [8, 13, 19, 21], + [8, 13, 20, 22], + [8, 13, 26, 27], + [8, 13, 29, 33], + [8, 14, 17, 20], + [8, 14, 18, 26], + [8, 14, 24, 37], + [8, 14, 27, 33], + [8, 14, 28, 35], + [8, 14, 30, 31], + [8, 15, 16, 19], + [8, 15, 18, 29], + [8, 15, 21, 28], + [8, 15, 22, 30], + [8, 15, 25, 37], + [8, 15, 26, 32], + [8, 15, 31, 34], + [8, 15, 35, 36], + [8, 16, 18, 35], + [8, 16, 20, 26], + [8, 16, 22, 23], + [8, 16, 24, 29], + [8, 16, 25, 27], + [8, 17, 21, 31], + [8, 17, 22, 26], + [8, 17, 23, 33], + [8, 17, 24, 34], + [8, 17, 27, 36], + [8, 17, 30, 32], + [8, 18, 20, 23], + [8, 18, 21, 34], + [8, 18, 22, 24], + [8, 18, 27, 37], + [8, 19, 20, 24], + [8, 19, 22, 32], + [8, 19, 23, 34], + [8, 19, 27, 29], + [8, 19, 35, 37], + [8, 20, 25, 28], + [8, 20, 29, 36], + [8, 20, 30, 33], + [8, 20, 31, 35], + [8, 20, 34, 37], + [8, 21, 23, 37], + [8, 21, 24, 32], + [8, 21, 25, 29], + [8, 21, 30, 36], + [8, 22, 25, 34], + [8, 22, 27, 28], + [8, 22, 33, 36], + [8, 23, 25, 31], + [8, 23, 26, 28], + [8, 23, 32, 36], + [8, 24, 26, 35], + [8, 25, 32, 35], + [8, 26, 29, 34], + [8, 26, 30, 37], + [8, 26, 31, 36], + [8, 27, 30, 34], + [8, 28, 31, 32], + [8, 29, 30, 35], + [8, 31, 33, 37], + [8, 32, 33, 34], + [9, 10, 11, 23], + [9, 10, 14, 36], + [9, 10, 15, 26], + [9, 10, 16, 21], + [9, 10, 18, 19], + [9, 10, 20, 27], + [9, 10, 25, 31], + [9, 10, 29, 34], + [9, 10, 30, 32], + [9, 10, 35, 37], + [9, 11, 12, 19], + [9, 11, 13, 18], + [9, 11, 14, 37], + [9, 11, 15, 24], + [9, 11, 17, 32], + [9, 11, 20, 31], + [9, 11, 21, 22], + [9, 11, 25, 34], + [9, 11, 26, 27], + [9, 12, 13, 27], + [9, 12, 14, 32], + [9, 12, 16, 28], + [9, 12, 17, 29], + [9, 12, 18, 26], + [9, 12, 20, 34], + [9, 12, 21, 33], + [9, 12, 22, 36], + [9, 12, 24, 31], + [9, 12, 25, 37], + [9, 13, 14, 16], + [9, 13, 15, 37], + [9, 13, 17, 34], + [9, 13, 20, 29], + [9, 13, 24, 36], + [9, 13, 26, 31], + [9, 13, 28, 32], + [9, 14, 15, 33], + [9, 14, 17, 35], + [9, 14, 19, 29], + [9, 14, 20, 22], + [9, 14, 21, 23], + [9, 14, 27, 28], + [9, 14, 30, 34], + [9, 15, 18, 21], + [9, 15, 19, 27], + [9, 15, 28, 34], + [9, 15, 29, 36], + [9, 15, 31, 32], + [9, 16, 17, 20], + [9, 16, 19, 30], + [9, 16, 22, 29], + [9, 16, 23, 31], + [9, 16, 27, 33], + [9, 16, 32, 35], + [9, 16, 36, 37], + [9, 17, 19, 36], + [9, 17, 21, 27], + [9, 17, 23, 24], + [9, 17, 25, 30], + [9, 17, 26, 28], + [9, 18, 22, 32], + [9, 18, 23, 27], + [9, 18, 24, 34], + [9, 18, 25, 35], + [9, 18, 28, 37], + [9, 18, 31, 33], + [9, 19, 21, 24], + [9, 19, 22, 35], + [9, 19, 23, 25], + [9, 20, 21, 25], + [9, 20, 23, 33], + [9, 20, 24, 35], + [9, 20, 28, 30], + [9, 21, 26, 29], + [9, 21, 30, 37], + [9, 21, 31, 34], + [9, 21, 32, 36], + [9, 22, 25, 33], + [9, 22, 26, 30], + [9, 22, 31, 37], + [9, 23, 26, 35], + [9, 23, 28, 29], + [9, 23, 34, 37], + [9, 24, 26, 32], + [9, 24, 27, 29], + [9, 24, 33, 37], + [9, 25, 27, 36], + [9, 26, 33, 36], + [9, 27, 30, 35], + [9, 27, 32, 37], + [9, 28, 31, 35], + [9, 29, 32, 33], + [9, 30, 31, 36], + [9, 33, 34, 35], + [10, 11, 12, 24], + [10, 11, 15, 37], + [10, 11, 16, 27], + [10, 11, 17, 22], + [10, 11, 19, 20], + [10, 11, 21, 28], + [10, 11, 26, 32], + [10, 11, 30, 35], + [10, 11, 31, 33], + [10, 12, 13, 20], + [10, 12, 14, 19], + [10, 12, 16, 25], + [10, 12, 18, 33], + [10, 12, 21, 32], + [10, 12, 22, 23], + [10, 12, 26, 35], + [10, 12, 27, 28], + [10, 13, 14, 28], + [10, 13, 15, 33], + [10, 13, 17, 29], + [10, 13, 18, 30], + [10, 13, 19, 27], + [10, 13, 21, 35], + [10, 13, 22, 34], + [10, 13, 23, 37], + [10, 13, 25, 32], + [10, 14, 15, 17], + [10, 14, 18, 35], + [10, 14, 21, 30], + [10, 14, 25, 37], + [10, 14, 27, 32], + [10, 14, 29, 33], + [10, 15, 16, 34], + [10, 15, 18, 36], + [10, 15, 20, 30], + [10, 15, 21, 23], + [10, 15, 22, 24], + [10, 15, 28, 29], + [10, 15, 31, 35], + [10, 16, 19, 22], + [10, 16, 20, 28], + [10, 16, 29, 35], + [10, 16, 30, 37], + [10, 16, 32, 33], + [10, 17, 18, 21], + [10, 17, 20, 31], + [10, 17, 23, 30], + [10, 17, 24, 32], + [10, 17, 28, 34], + [10, 17, 33, 36], + [10, 18, 20, 37], + [10, 18, 22, 28], + [10, 18, 24, 25], + [10, 18, 26, 31], + [10, 18, 27, 29], + [10, 19, 23, 33], + [10, 19, 24, 28], + [10, 19, 25, 35], + [10, 19, 26, 36], + [10, 19, 32, 34], + [10, 20, 22, 25], + [10, 20, 23, 36], + [10, 20, 24, 26], + [10, 21, 22, 26], + [10, 21, 24, 34], + [10, 21, 25, 36], + [10, 21, 29, 31], + [10, 22, 27, 30], + [10, 22, 32, 35], + [10, 22, 33, 37], + [10, 23, 26, 34], + [10, 23, 27, 31], + [10, 24, 27, 36], + [10, 24, 29, 30], + [10, 25, 27, 33], + [10, 25, 28, 30], + [10, 26, 28, 37], + [10, 27, 34, 37], + [10, 28, 31, 36], + [10, 29, 32, 36], + [10, 30, 33, 34], + [10, 31, 32, 37], + [10, 34, 35, 36], + [11, 12, 13, 25], + [11, 12, 17, 28], + [11, 12, 18, 23], + [11, 12, 20, 21], + [11, 12, 22, 29], + [11, 12, 27, 33], + [11, 12, 31, 36], + [11, 12, 32, 34], + [11, 13, 14, 21], + [11, 13, 15, 20], + [11, 13, 17, 26], + [11, 13, 19, 34], + [11, 13, 22, 33], + [11, 13, 23, 24], + [11, 13, 27, 36], + [11, 13, 28, 29], + [11, 14, 15, 29], + [11, 14, 16, 34], + [11, 14, 18, 30], + [11, 14, 19, 31], + [11, 14, 20, 28], + [11, 14, 22, 36], + [11, 14, 23, 35], + [11, 14, 26, 33], + [11, 15, 16, 18], + [11, 15, 19, 36], + [11, 15, 22, 31], + [11, 15, 28, 33], + [11, 15, 30, 34], + [11, 16, 17, 35], + [11, 16, 19, 37], + [11, 16, 21, 31], + [11, 16, 22, 24], + [11, 16, 23, 25], + [11, 16, 29, 30], + [11, 16, 32, 36], + [11, 17, 20, 23], + [11, 17, 21, 29], + [11, 17, 30, 36], + [11, 17, 33, 34], + [11, 18, 19, 22], + [11, 18, 21, 32], + [11, 18, 24, 31], + [11, 18, 25, 33], + [11, 18, 29, 35], + [11, 18, 34, 37], + [11, 19, 23, 29], + [11, 19, 25, 26], + [11, 19, 27, 32], + [11, 19, 28, 30], + [11, 20, 24, 34], + [11, 20, 25, 29], + [11, 20, 26, 36], + [11, 20, 27, 37], + [11, 20, 33, 35], + [11, 21, 23, 26], + [11, 21, 24, 37], + [11, 21, 25, 27], + [11, 22, 23, 27], + [11, 22, 25, 35], + [11, 22, 26, 37], + [11, 22, 30, 32], + [11, 23, 28, 31], + [11, 23, 33, 36], + [11, 24, 27, 35], + [11, 24, 28, 32], + [11, 25, 28, 37], + [11, 25, 30, 31], + [11, 26, 28, 34], + [11, 26, 29, 31], + [11, 29, 32, 37], + [11, 30, 33, 37], + [11, 31, 34, 35], + [11, 35, 36, 37], + [12, 13, 14, 26], + [12, 13, 18, 29], + [12, 13, 19, 24], + [12, 13, 21, 22], + [12, 13, 23, 30], + [12, 13, 28, 34], + [12, 13, 32, 37], + [12, 13, 33, 35], + [12, 14, 15, 22], + [12, 14, 16, 21], + [12, 14, 18, 27], + [12, 14, 20, 35], + [12, 14, 23, 34], + [12, 14, 24, 25], + [12, 14, 28, 37], + [12, 14, 29, 30], + [12, 15, 16, 30], + [12, 15, 17, 35], + [12, 15, 19, 31], + [12, 15, 20, 32], + [12, 15, 21, 29], + [12, 15, 23, 37], + [12, 15, 24, 36], + [12, 15, 27, 34], + [12, 16, 17, 19], + [12, 16, 20, 37], + [12, 16, 23, 32], + [12, 16, 29, 34], + [12, 16, 31, 35], + [12, 17, 18, 36], + [12, 17, 22, 32], + [12, 17, 23, 25], + [12, 17, 24, 26], + [12, 17, 30, 31], + [12, 17, 33, 37], + [12, 18, 21, 24], + [12, 18, 22, 30], + [12, 18, 31, 37], + [12, 18, 34, 35], + [12, 19, 20, 23], + [12, 19, 22, 33], + [12, 19, 25, 32], + [12, 19, 26, 34], + [12, 19, 30, 36], + [12, 20, 24, 30], + [12, 20, 26, 27], + [12, 20, 28, 33], + [12, 20, 29, 31], + [12, 21, 25, 35], + [12, 21, 26, 30], + [12, 21, 27, 37], + [12, 21, 34, 36], + [12, 22, 24, 27], + [12, 22, 26, 28], + [12, 23, 24, 28], + [12, 23, 26, 36], + [12, 23, 31, 33], + [12, 24, 29, 32], + [12, 24, 34, 37], + [12, 25, 28, 36], + [12, 25, 29, 33], + [12, 26, 31, 32], + [12, 27, 29, 35], + [12, 27, 30, 32], + [12, 32, 35, 36], + [13, 14, 15, 27], + [13, 14, 19, 30], + [13, 14, 20, 25], + [13, 14, 22, 23], + [13, 14, 24, 31], + [13, 14, 29, 35], + [13, 14, 34, 36], + [13, 15, 16, 23], + [13, 15, 17, 22], + [13, 15, 19, 28], + [13, 15, 21, 36], + [13, 15, 24, 35], + [13, 15, 25, 26], + [13, 15, 30, 31], + [13, 16, 17, 31], + [13, 16, 18, 36], + [13, 16, 20, 32], + [13, 16, 21, 33], + [13, 16, 22, 30], + [13, 16, 25, 37], + [13, 16, 28, 35], + [13, 17, 18, 20], + [13, 17, 24, 33], + [13, 17, 30, 35], + [13, 17, 32, 36], + [13, 18, 19, 37], + [13, 18, 23, 33], + [13, 18, 24, 26], + [13, 18, 25, 27], + [13, 18, 31, 32], + [13, 19, 22, 25], + [13, 19, 23, 31], + [13, 19, 35, 36], + [13, 20, 21, 24], + [13, 20, 23, 34], + [13, 20, 26, 33], + [13, 20, 27, 35], + [13, 20, 31, 37], + [13, 21, 25, 31], + [13, 21, 27, 28], + [13, 21, 29, 34], + [13, 21, 30, 32], + [13, 22, 26, 36], + [13, 22, 27, 31], + [13, 22, 35, 37], + [13, 23, 25, 28], + [13, 23, 27, 29], + [13, 24, 25, 29], + [13, 24, 27, 37], + [13, 24, 32, 34], + [13, 25, 30, 33], + [13, 26, 29, 37], + [13, 26, 30, 34], + [13, 27, 32, 33], + [13, 28, 30, 36], + [13, 28, 31, 33], + [13, 33, 36, 37], + [14, 15, 16, 28], + [14, 15, 20, 31], + [14, 15, 21, 26], + [14, 15, 23, 24], + [14, 15, 25, 32], + [14, 15, 30, 36], + [14, 15, 35, 37], + [14, 16, 17, 24], + [14, 16, 18, 23], + [14, 16, 20, 29], + [14, 16, 22, 37], + [14, 16, 25, 36], + [14, 16, 26, 27], + [14, 16, 31, 32], + [14, 17, 18, 32], + [14, 17, 19, 37], + [14, 17, 21, 33], + [14, 17, 22, 34], + [14, 17, 23, 31], + [14, 17, 29, 36], + [14, 18, 19, 21], + [14, 18, 25, 34], + [14, 18, 31, 36], + [14, 18, 33, 37], + [14, 19, 24, 34], + [14, 19, 25, 27], + [14, 19, 26, 28], + [14, 19, 32, 33], + [14, 20, 23, 26], + [14, 20, 24, 32], + [14, 20, 36, 37], + [14, 21, 22, 25], + [14, 21, 24, 35], + [14, 21, 27, 34], + [14, 21, 28, 36], + [14, 22, 26, 32], + [14, 22, 28, 29], + [14, 22, 30, 35], + [14, 22, 31, 33], + [14, 23, 27, 37], + [14, 23, 28, 32], + [14, 24, 26, 29], + [14, 24, 28, 30], + [14, 25, 26, 30], + [14, 25, 33, 35], + [14, 26, 31, 34], + [14, 27, 31, 35], + [14, 28, 33, 34], + [14, 29, 31, 37], + [14, 29, 32, 34], + [15, 16, 17, 29], + [15, 16, 21, 32], + [15, 16, 22, 27], + [15, 16, 24, 25], + [15, 16, 26, 33], + [15, 16, 31, 37], + [15, 17, 18, 25], + [15, 17, 19, 24], + [15, 17, 21, 30], + [15, 17, 26, 37], + [15, 17, 27, 28], + [15, 17, 32, 33], + [15, 18, 19, 33], + [15, 18, 22, 34], + [15, 18, 23, 35], + [15, 18, 24, 32], + [15, 18, 30, 37], + [15, 19, 20, 22], + [15, 19, 26, 35], + [15, 19, 32, 37], + [15, 20, 25, 35], + [15, 20, 26, 28], + [15, 20, 27, 29], + [15, 20, 33, 34], + [15, 21, 24, 27], + [15, 21, 25, 33], + [15, 22, 23, 26], + [15, 22, 25, 36], + [15, 22, 28, 35], + [15, 22, 29, 37], + [15, 23, 27, 33], + [15, 23, 29, 30], + [15, 23, 31, 36], + [15, 23, 32, 34], + [15, 24, 29, 33], + [15, 25, 27, 30], + [15, 25, 29, 31], + [15, 26, 27, 31], + [15, 26, 34, 36], + [15, 27, 32, 35], + [15, 28, 32, 36], + [15, 29, 34, 35], + [15, 30, 33, 35], + [16, 17, 18, 30], + [16, 17, 22, 33], + [16, 17, 23, 28], + [16, 17, 25, 26], + [16, 17, 27, 34], + [16, 18, 19, 26], + [16, 18, 20, 25], + [16, 18, 22, 31], + [16, 18, 28, 29], + [16, 18, 33, 34], + [16, 19, 20, 34], + [16, 19, 23, 35], + [16, 19, 24, 36], + [16, 19, 25, 33], + [16, 20, 21, 23], + [16, 20, 27, 36], + [16, 21, 26, 36], + [16, 21, 27, 29], + [16, 21, 28, 30], + [16, 21, 34, 35], + [16, 22, 25, 28], + [16, 22, 26, 34], + [16, 23, 24, 27], + [16, 23, 26, 37], + [16, 23, 29, 36], + [16, 24, 28, 34], + [16, 24, 30, 31], + [16, 24, 32, 37], + [16, 24, 33, 35], + [16, 25, 30, 34], + [16, 26, 28, 31], + [16, 26, 30, 32], + [16, 27, 28, 32], + [16, 27, 35, 37], + [16, 28, 33, 36], + [16, 29, 33, 37], + [16, 30, 35, 36], + [16, 31, 34, 36], + [17, 18, 19, 31], + [17, 18, 23, 34], + [17, 18, 24, 29], + [17, 18, 26, 27], + [17, 18, 28, 35], + [17, 19, 20, 27], + [17, 19, 21, 26], + [17, 19, 23, 32], + [17, 19, 29, 30], + [17, 19, 34, 35], + [17, 20, 21, 35], + [17, 20, 24, 36], + [17, 20, 25, 37], + [17, 20, 26, 34], + [17, 21, 22, 24], + [17, 21, 28, 37], + [17, 22, 27, 37], + [17, 22, 28, 30], + [17, 22, 29, 31], + [17, 22, 35, 36], + [17, 23, 26, 29], + [17, 23, 27, 35], + [17, 24, 25, 28], + [17, 24, 30, 37], + [17, 25, 29, 35], + [17, 25, 31, 32], + [17, 25, 34, 36], + [17, 26, 31, 35], + [17, 27, 29, 32], + [17, 27, 31, 33], + [17, 28, 29, 33], + [17, 29, 34, 37], + [17, 31, 36, 37], + [17, 32, 35, 37], + [18, 19, 20, 32], + [18, 19, 24, 35], + [18, 19, 25, 30], + [18, 19, 27, 28], + [18, 19, 29, 36], + [18, 20, 21, 28], + [18, 20, 22, 27], + [18, 20, 24, 33], + [18, 20, 30, 31], + [18, 20, 35, 36], + [18, 21, 22, 36], + [18, 21, 25, 37], + [18, 21, 27, 35], + [18, 22, 23, 25], + [18, 23, 29, 31], + [18, 23, 30, 32], + [18, 23, 36, 37], + [18, 24, 27, 30], + [18, 24, 28, 36], + [18, 25, 26, 29], + [18, 26, 30, 36], + [18, 26, 32, 33], + [18, 26, 35, 37], + [18, 27, 32, 36], + [18, 28, 30, 33], + [18, 28, 32, 34], + [18, 29, 30, 34], + [19, 20, 21, 33], + [19, 20, 25, 36], + [19, 20, 26, 31], + [19, 20, 28, 29], + [19, 20, 30, 37], + [19, 21, 22, 29], + [19, 21, 23, 28], + [19, 21, 25, 34], + [19, 21, 31, 32], + [19, 21, 36, 37], + [19, 22, 23, 37], + [19, 22, 28, 36], + [19, 23, 24, 26], + [19, 24, 30, 32], + [19, 24, 31, 33], + [19, 25, 28, 31], + [19, 25, 29, 37], + [19, 26, 27, 30], + [19, 27, 31, 37], + [19, 27, 33, 34], + [19, 28, 33, 37], + [19, 29, 31, 34], + [19, 29, 33, 35], + [19, 30, 31, 35], + [20, 21, 22, 34], + [20, 21, 26, 37], + [20, 21, 27, 32], + [20, 21, 29, 30], + [20, 22, 23, 30], + [20, 22, 24, 29], + [20, 22, 26, 35], + [20, 22, 32, 33], + [20, 23, 29, 37], + [20, 24, 25, 27], + [20, 25, 31, 33], + [20, 25, 32, 34], + [20, 26, 29, 32], + [20, 27, 28, 31], + [20, 28, 34, 35], + [20, 30, 32, 35], + [20, 30, 34, 36], + [20, 31, 32, 36], + [21, 22, 23, 35], + [21, 22, 28, 33], + [21, 22, 30, 31], + [21, 23, 24, 31], + [21, 23, 25, 30], + [21, 23, 27, 36], + [21, 23, 33, 34], + [21, 25, 26, 28], + [21, 26, 32, 34], + [21, 26, 33, 35], + [21, 27, 30, 33], + [21, 28, 29, 32], + [21, 29, 35, 36], + [21, 31, 33, 36], + [21, 31, 35, 37], + [21, 32, 33, 37], + [22, 23, 24, 36], + [22, 23, 29, 34], + [22, 23, 31, 32], + [22, 24, 25, 32], + [22, 24, 26, 31], + [22, 24, 28, 37], + [22, 24, 34, 35], + [22, 26, 27, 29], + [22, 27, 33, 35], + [22, 27, 34, 36], + [22, 28, 31, 34], + [22, 29, 30, 33], + [22, 30, 36, 37], + [22, 32, 34, 37], + [23, 24, 25, 37], + [23, 24, 30, 35], + [23, 24, 32, 33], + [23, 25, 26, 33], + [23, 25, 27, 32], + [23, 25, 35, 36], + [23, 27, 28, 30], + [23, 28, 34, 36], + [23, 28, 35, 37], + [23, 29, 32, 35], + [23, 30, 31, 34], + [24, 25, 31, 36], + [24, 25, 33, 34], + [24, 26, 27, 34], + [24, 26, 28, 33], + [24, 26, 36, 37], + [24, 28, 29, 31], + [24, 29, 35, 37], + [24, 30, 33, 36], + [24, 31, 32, 35], + [25, 26, 32, 37], + [25, 26, 34, 35], + [25, 27, 28, 35], + [25, 27, 29, 34], + [25, 29, 30, 32], + [25, 31, 34, 37], + [25, 32, 33, 36], + [26, 27, 35, 36], + [26, 28, 29, 36], + [26, 28, 30, 35], + [26, 30, 31, 33], + [26, 33, 34, 37], + [27, 28, 36, 37], + [27, 29, 30, 37], + [27, 29, 31, 36], + [27, 31, 32, 34], + [28, 30, 32, 37], + [28, 32, 33, 35], + [29, 33, 34, 36], + [30, 34, 35, 37], + ] diff --git a/src/sage/combinat/designs/twographs.py b/src/sage/combinat/designs/twographs.py index a8b6a83f945..759389c84b4 100644 --- a/src/sage/combinat/designs/twographs.py +++ b/src/sage/combinat/designs/twographs.py @@ -69,8 +69,8 @@ class TwoGraph(IncidenceStructure): information, see the documentation of the :mod:`~sage.combinat.designs.twographs` module. """ - def __init__(self, points=None, blocks=None, incidence_matrix=None, - name=None, check=False, copy=True): + + def __init__(self, points=None, blocks=None, incidence_matrix=None, name=None, check=False, copy=True): r""" Constructor of the class. @@ -87,9 +87,7 @@ def __init__(self, points=None, blocks=None, incidence_matrix=None, sage: TwoGraph(p, check=True) # needs sage.modules Incidence structure with 10 points and 60 blocks """ - IncidenceStructure.__init__(self, points=points, blocks=blocks, - incidence_matrix=incidence_matrix, - name=name, check=False, copy=copy) + IncidenceStructure.__init__(self, points=points, blocks=blocks, incidence_matrix=incidence_matrix, name=name, check=False, copy=copy) if check: # it is a very slow, O(|points|^4), test... assert is_twograph(self), "the structure is not a 2-graph!" @@ -144,8 +142,8 @@ def descendant(self, v): (9, 4, 1, 2) """ from sage.graphs.graph import Graph - return Graph([[z for z in x if z != v] - for x in self.blocks() if v in x]) + + return Graph([[z for z in x if z != v] for x in self.blocks() if v in x]) def complement(self): """ @@ -196,6 +194,7 @@ def taylor_twograph(q): Incidence structure with 28 points and 1260 blocks """ from sage.graphs.generators.classical_geometries import TaylorTwographSRG + return TaylorTwographSRG(q).twograph() @@ -248,8 +247,7 @@ def has_triple(x_y_z) -> bool: return bool(v_to_blocks[x] & v_to_blocks[y] & v_to_blocks[z]) # Check that every quadruple contains an even number of triples - return not any(sum(map(has_triple, combinations(quad, 3))) % 2 - for quad in combinations(range(T.n_points()), 4)) + return not any(sum(map(has_triple, combinations(quad, 3))) % 2 for quad in combinations(range(T.n_points()), 4)) def twograph_descendant(G, v, name=None): diff --git a/src/sage/combinat/diagram.py b/src/sage/combinat/diagram.py index 6df4db7d121..da037c26191 100644 --- a/src/sage/combinat/diagram.py +++ b/src/sage/combinat/diagram.py @@ -104,6 +104,7 @@ class Diagram(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): . . . . . . . . . . . . """ + @staticmethod def __classcall_private__(self, cells, n_rows=None, n_cols=None, check=True): r""" @@ -233,6 +234,7 @@ def _ascii_art_(self): - """ from sage.typeset.ascii_art import ascii_art + if self._n_rows == 0 or self._n_cols == 0: return ascii_art("-") return ascii_art("\n".join(self._pretty_print())) @@ -274,6 +276,7 @@ def _unicode_art_(self): ∅ """ from sage.typeset.unicode_art import unicode_art + if self._n_rows == 0 or self._n_cols == 0: return unicode_art("∅") @@ -281,12 +284,12 @@ def _unicode_art_(self): cell = "│X" empty = "│ " it = self._pretty_print(cell, empty) - ret = "┌─" + "┬─"*ndivs + "┐" + ret = "┌─" + "┬─" * ndivs + "┐" ret += "\n" + next(it) + "│" for row in it: - ret += "\n├─" + "┼─"*ndivs + "┤" + ret += "\n├─" + "┼─" * ndivs + "┤" ret += "\n" + row + "│" - ret += "\n└─" + "┴─"*ndivs + "┘" + ret += "\n└─" + "┴─" * ndivs + "┘" return unicode_art(ret) def _pretty_print(self, cell='O ', empty='. '): @@ -337,30 +340,24 @@ def _latex_(self): lr = r'\def\lr#1{\multicolumn{1}{|@{\hspace{.6ex}}c@{\hspace{.6ex}}|}{\raisebox{-.3ex}{$#1$}}}' - array = [[("\\phantom{x}" if (i, j) in self else None) - for j in range(self._n_cols)] - for i in range(self._n_rows)] + array = [[("\\phantom{x}" if (i, j) in self else None) for j in range(self._n_cols)] for i in range(self._n_rows)] def end_line(r): # give the line ending to row ``r`` if r == 0: - return "".join(r'\cline{%s-%s}' % (i+1, i+1) - for i, j in enumerate(array[0]) if j is not None) + return "".join(r'\cline{%s-%s}' % (i + 1, i + 1) for i, j in enumerate(array[0]) if j is not None) if r == len(array): - return r"\\" + "".join(r'\cline{%s-%s}' % (i+1, i+1) - for i, j in enumerate(array[r-1]) if j is not None) - out = r"\\" + "".join(r'\cline{%s-%s}' % (i+1, i+1) - for i, j in enumerate(array[r-1]) if j is not None) - out += "".join(r'\cline{%s-%s}' % (i+1, i+1) - for i, j in enumerate(array[r]) if j is not None) + return r"\\" + "".join(r'\cline{%s-%s}' % (i + 1, i + 1) for i, j in enumerate(array[r - 1]) if j is not None) + out = r"\\" + "".join(r'\cline{%s-%s}' % (i + 1, i + 1) for i, j in enumerate(array[r - 1]) if j is not None) + out += "".join(r'\cline{%s-%s}' % (i + 1, i + 1) for i, j in enumerate(array[r]) if j is not None) return out tex = r'\raisebox{-.6ex}{$\begin{array}[b]{*{%s}{p{0.6ex}}}' % (max(map(len, array))) - tex += end_line(0)+'\n' + tex += end_line(0) + '\n' for r in range(len(array)): tex += '&'.join('' if c is None else r'\lr{%s}' % (c,) for c in array[r]) - tex += end_line(r+1)+'\n' - return '{%s\n%s\n}' % (lr, tex+r'\end{array}$}') + tex += end_line(r + 1) + '\n' + return '{%s\n%s\n}' % (lr, tex + r'\end{array}$}') def number_of_rows(self): r""" @@ -489,6 +486,7 @@ def check(self): ValueError: diagrams must be indexed by nonnegative integers """ from sage.sets.non_negative_integers import NonNegativeIntegers + NN = NonNegativeIntegers() if not all(i in NN for c in self._cells for i in c): raise ValueError("diagrams must be indexed by nonnegative integers") @@ -508,8 +506,10 @@ def specht_module(self, base_ring=None): """ from sage.combinat.specht_module import SpechtModule from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra + if base_ring is None: from sage.rings.rational_field import QQ + base_ring = QQ R = SymmetricGroupAlgebra(base_ring, len(self)) return SpechtModule(R, self) @@ -532,6 +532,7 @@ def specht_module_dimension(self, base_ring=None): 12 """ from sage.combinat.specht_module import specht_module_rank + return specht_module_rank(self, base_ring) @cached_method @@ -551,8 +552,7 @@ def essential_set(self): sage: D.essential_set() ((0, 0), (2, 3), (3, 2)) """ - ret = [c for c in self._cells if (c[0]+1, c[1]) not in self._cells - and (c[0], c[1]+1) not in self._cells] + ret = [c for c in self._cells if (c[0] + 1, c[1]) not in self._cells and (c[0], c[1] + 1) not in self._cells] ret.sort() return tuple(ret) @@ -641,6 +641,7 @@ def __iter__(self): from sage.sets.non_negative_integers import NonNegativeIntegers from sage.categories.cartesian_product import cartesian_product from sage.combinat.subset import subsets + # the product of positive integers automatically implements an # an enumeration which allows us to get out of the first column N = NonNegativeIntegers() @@ -838,6 +839,7 @@ def from_zero_one_matrix(self, M, check=True): # Northwest diagrams #################### + class NorthwestDiagram(Diagram, metaclass=InheritComparisonClasscallMetaclass): r""" Diagrams with the northwest property. @@ -862,6 +864,7 @@ class NorthwestDiagram(Diagram, metaclass=InheritComparisonClasscallMetaclass): . . . O . . """ + @staticmethod def __classcall_private__(self, cells, n_rows=None, n_cols=None, check=True): """ @@ -912,9 +915,9 @@ def check(self): ValueError: diagrams must be indexed by nonnegative integers """ from itertools import combinations + Diagram.check(self) - if not all((min(i1, i2), min(j1, j2)) in self - for (i1, j1), (i2, j2) in combinations(self._cells, 2)): + if not all((min(i1, i2), min(j1, j2)) in self for (i1, j1), (i2, j2) in combinations(self._cells, 2)): raise ValueError("diagram is not northwest") def peelable_tableaux(self): @@ -1099,7 +1102,7 @@ def peelable_tableaux(self): # if there is a single column in the diagram then there is only # one posslbe peelable tableau. if self._n_nonempty_cols == 1: - return set([Tableau([[i+1] for i, j in self.cells()])]) + return set([Tableau([[i + 1] for i, j in self.cells()])]) first_col = min(j for i, j in self._cells) @@ -1471,6 +1474,7 @@ def from_parallelogram_polyomino(self, p): . O O """ from sage.matrix.constructor import Matrix + M = Matrix(p.get_array()) return self.from_zero_one_matrix(M) @@ -1543,7 +1547,6 @@ def RotheDiagram(w): N = w.size() winv = w.inverse() - cells = [c for c in product(range(N), range(N)) - if c[0] + 1 < winv(c[1] + 1) and c[1] + 1 < w(c[0] + 1)] + cells = [c for c in product(range(N), range(N)) if c[0] + 1 < winv(c[1] + 1) and c[1] + 1 < w(c[0] + 1)] return NorthwestDiagram(cells, n_rows=N, n_cols=N, check=False) diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 1dc3aae3540..05b0c440473 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -98,12 +98,12 @@ def partition_diagrams(k): {{-2, 2}, {-1}, {1}}] """ if k in ZZ: - S = set_partition_iterator(list(range(1, k+1)) + list(range(-k,0))) + S = set_partition_iterator(list(range(1, k + 1)) + list(range(-k, 0))) for p in S: yield p - elif k + ZZ(1)/ZZ(2) in ZZ: # Else k in 1/2 ZZ + elif k + ZZ(1) / ZZ(2) in ZZ: # Else k in 1/2 ZZ k = ZZ(k + ZZ(1) / ZZ(2)) - S = set_partition_iterator(list(range(1, k+1)) + list(range(-k+1,0))) + S = set_partition_iterator(list(range(1, k + 1)) + list(range(-k + 1, 0))) for p in S: yield [b + [-k] if k in b else b for b in p] else: @@ -132,13 +132,13 @@ def brauer_diagrams(k): {{-3, 3}, {-2, 2}, {-1, 1}}] """ if k in ZZ: - s = list(range(1, k+1)) + list(range(-k,0)) + s = list(range(1, k + 1)) + list(range(-k, 0)) for p in perfect_matchings_iterator(k): - yield [(s[a],s[b]) for a,b in p] + yield [(s[a], s[b]) for a, b in p] elif k + ZZ.one() / 2 in ZZ: # Else k in 1/2 ZZ k = ZZ(k + ZZ.one() / 2) - s = list(range(1, k)) + list(range(-k+1,0)) - for p in perfect_matchings_iterator(k-1): + s = list(range(1, k)) + list(range(-k + 1, 0)) + for p in perfect_matchings_iterator(k - 1): yield [(s[a], s[b]) for a, b in p] + [[k, -k]] @@ -195,11 +195,11 @@ def planar_diagrams(k): {{-3, -1, 3}, {-2, 2}, {1}}] """ if k in ZZ: - X = list(range(1,k+1)) + list(range(-k,0)) + X = list(range(1, k + 1)) + list(range(-k, 0)) yield from planar_partitions_rec(X) - elif k + ZZ(1)/ZZ(2) in ZZ: # Else k in 1/2 ZZ + elif k + ZZ(1) / ZZ(2) in ZZ: # Else k in 1/2 ZZ k = ZZ(k + ZZ(1) / ZZ(2)) - X = list(range(1,k+1)) + list(range(-k+1,0)) + X = list(range(1, k + 1)) + list(range(-k + 1, 0)) for Y in planar_partitions_rec(X): Y = list(Y) for part in Y: @@ -241,7 +241,8 @@ def planar_partitions_rec(X): return from sage.combinat.subset import powerset from itertools import product - for S in powerset(range(len(X)-1)): + + for S in powerset(range(len(X) - 1)): if not S: for Y in planar_partitions_rec(X[:-1]): yield Y + ([X[-1]],) @@ -250,16 +251,15 @@ def planar_partitions_rec(X): last.append(X[-1]) pt = [] if S[0] != 0: - pt += [X[:S[0]]] - pt = [X[S[i]+1:S[i+1]] for i in range(len(S)-1) if S[i]+1 != S[i+1]] + pt += [X[: S[0]]] + pt = [X[S[i] + 1 : S[i + 1]] for i in range(len(S) - 1) if S[i] + 1 != S[i + 1]] if S[-1] + 1 != len(X) - 1: - pt += [X[S[-1]+1:-1]] - parts = [planar_partitions_rec(X[S[i]+1:S[i+1]]) for i in range(len(S)-1) - if S[i] + 1 != S[i+1]] + pt += [X[S[-1] + 1 : -1]] + parts = [planar_partitions_rec(X[S[i] + 1 : S[i + 1]]) for i in range(len(S) - 1) if S[i] + 1 != S[i + 1]] if S[0] != 0: - parts.append(planar_partitions_rec(X[:S[0]])) + parts.append(planar_partitions_rec(X[: S[0]])) if S[-1] + 1 != len(X) - 1: - parts.append(planar_partitions_rec(X[S[-1]+1:-1])) + parts.append(planar_partitions_rec(X[S[-1] + 1 : -1])) for Y in product(*parts): yield sum(Y, ()) + (last,) @@ -365,8 +365,7 @@ def check(self): if self._base_diagram: tst = frozenset(e for B in self._base_diagram for e in B) if tst != self.parent()._set: - raise ValueError("{} does not represent two rows of vertices of order {}".format( - self, self.parent().order)) + raise ValueError("{} does not represent two rows of vertices of order {}".format(self, self.parent().order)) def __hash__(self): """ @@ -461,7 +460,7 @@ def base_diagram(self): sage: pd([[1,2],[-1,-2]]).base_diagram() == ((-2,-1),(1,2)) True """ - return self._base_diagram # note, this works because self._base_diagram is immutable + return self._base_diagram # note, this works because self._base_diagram is immutable diagram = base_diagram @@ -630,6 +629,7 @@ class IdealDiagram(AbstractPartitionDiagram): sage: PDs(4).cardinality() == factorial(4) + IDs(4).cardinality() True """ + @staticmethod def __classcall_private__(cls, diag): """ @@ -700,6 +700,7 @@ class PlanarDiagram(AbstractPartitionDiagram): {{-2, -1, 2}, {1}}, {{-2, -1, 1, 2}}] """ + @staticmethod def __classcall_private__(cls, diag): """ @@ -759,6 +760,7 @@ class TemperleyLiebDiagram(AbstractPartitionDiagram): sage: TemperleyLiebDiagrams(2).list() [{{-2, -1}, {1, 2}}, {{-2, 2}, {-1, 1}}] """ + @staticmethod def __classcall_private__(cls, diag): """ @@ -802,7 +804,7 @@ def check(self): """ super().check() if any(len(block) != 2 for block in self): - raise ValueError("all blocks of %s must be of size 2" % self ) + raise ValueError("all blocks of %s must be of size 2" % self) if not self.is_planar(): raise ValueError("the diagram %s must be planar" % self) @@ -826,6 +828,7 @@ class PartitionDiagram(AbstractPartitionDiagram): sage: PartitionDiagram(((1,-2),(2,-1))).parent() Partition diagrams of order 2 """ + @staticmethod def __classcall_private__(cls, diag): """ @@ -870,6 +873,7 @@ class BrauerDiagram(AbstractPartitionDiagram): sage: bd = da.BrauerDiagrams(2)( ((-2,-1),(1,2)) ) sage: TestSuite(bd).run() """ + @staticmethod def __classcall_private__(cls, diag): """ @@ -963,14 +967,11 @@ class options(GlobalOptions): B[24.38.57/35.27.68;21] sage: BrauerAlgebra.options._reset() """ + NAME = 'Brauer diagram' module = 'sage.combinat.diagram_algebras' option_class = 'BrauerDiagram' - display = dict(default='normal', - description='Specifies how the Brauer diagrams should be printed', - values=dict(normal="Using the normal representation", - compact="Using the compact representation"), - case_sensitive=False) + display = dict(default='normal', description='Specifies how the Brauer diagrams should be printed', values=dict(normal="Using the normal representation", compact="Using the compact representation"), case_sensitive=False) def _repr_normal(self): """ @@ -1004,8 +1005,7 @@ def _repr_compact(self): top, bot, thru = self.involution_permutation_triple() bot.reverse() s1 = ".".join("".join(str(b) for b in block) for block in top) - s2 = ".".join("".join(str(abs(k)) for k in sorted(block, reverse=True)) - for block in bot) + s2 = ".".join("".join(str(abs(k)) for k in sorted(block, reverse=True)) for block in bot) s3 = "".join(str(x) for x in thru) return "[{}/{};{}]".format(s1, s2, s3) @@ -1072,8 +1072,7 @@ def bijection_on_free_nodes(self, two_line=False): sage: elm2.bijection_on_free_nodes(two_line=True) [[1, 2, 3], [-2, -3, -1]] """ - terms = sorted(sorted(v, reverse=True) for v in self.diagram() - if max(v) > 0 and min(v) < 0) + terms = sorted(sorted(v, reverse=True) for v in self.diagram() if max(v) > 0 and min(v) < 0) if two_line: terms = [[t[i] for t in terms] for i in range(2)] return terms @@ -1105,7 +1104,7 @@ def perm(self): # probably already defined somewhere in Permutations/Compositions/list/etc. std = list(range(1, len(short_form) + 1)) j = 0 - for i in range(max(short_form)+1): + for i in range(max(short_form) + 1): if i in short_form: j += 1 std[short_form.index(i)] = j @@ -1168,6 +1167,7 @@ class AbstractPartitionDiagrams(Parent, UniqueRepresentation): sage: elm in pd True """ + Element = AbstractPartitionDiagram def __init__(self, order, category=None): @@ -1204,12 +1204,11 @@ def __init__(self, order, category=None): Parent.__init__(self, category=category) if order in ZZ: self.order = ZZ(order) - base_set = frozenset(list(range(1,order+1)) + list(range(-order,0))) + base_set = frozenset(list(range(1, order + 1)) + list(range(-order, 0))) else: # order is a half-integer. self.order = QQ(order) - base_set = frozenset(list(range(1,ZZ(ZZ(1)/ZZ(2) + order)+1)) - + list(range(ZZ(-ZZ(1)/ZZ(2) - order),0))) + base_set = frozenset(list(range(1, ZZ(ZZ(1) / ZZ(2) + order) + 1)) + list(range(ZZ(-ZZ(1) / ZZ(2) - order), 0))) self._set = base_set def _repr_(self): @@ -1396,6 +1395,7 @@ class PartitionDiagrams(AbstractPartitionDiagrams): sage: pd.cardinality() == len(pd.list()) True """ + Element = PartitionDiagram _name = "Partition" _diagram_func = partition_diagrams @@ -1481,6 +1481,7 @@ class BrauerDiagrams(AbstractPartitionDiagrams): [/;123]] sage: bd.options._reset() """ + Element = BrauerDiagram options = BrauerDiagram.options _name = "Brauer" @@ -1505,8 +1506,8 @@ def __contains__(self, obj): if self.order in ZZ: r = ZZ(self.order) else: - r = ZZ(self.order + ZZ(1)/ZZ(2)) - return super().__contains__(obj) and [len(i) for i in obj] == [2]*r + r = ZZ(self.order + ZZ(1) / ZZ(2)) + return super().__contains__(obj) and [len(i) for i in obj] == [2] * r def cardinality(self): r""" @@ -1558,18 +1559,17 @@ def symmetric_diagrams(self, l=None, perm=None): # perm = permutation on free nodes # l = number of arcs if self.order not in ZZ: - raise NotImplementedError("only implemented for integer order," - " not for order %s" % (self.order)) + raise NotImplementedError("only implemented for integer order," " not for order %s" % (self.order)) n = ZZ(self.order) if l is None: l = 0 if perm is None: - perm = list(range(1, n+1-2*l)) + perm = list(range(1, n + 1 - 2 * l)) out = [] - partition_shape = [2]*l + [1]*(n-2*l) + partition_shape = [2] * l + [1] * (n - 2 * l) for sp in SetPartitions(n, partition_shape): sp0 = [block for block in sp if len(block) == 2] - diag = self.from_involution_permutation_triple((sp0,sp0,perm)) + diag = self.from_involution_permutation_triple((sp0, sp0, perm)) out.append(diag) return out @@ -1614,26 +1614,24 @@ def from_involution_permutation_triple(self, D1_D2_pi): NotImplementedError: only implemented for integer order, not for order 5/2 """ if self.order not in ZZ: - raise NotImplementedError("only implemented for integer order," - " not for order %s" % (self.order)) + raise NotImplementedError("only implemented for integer order," " not for order %s" % (self.order)) try: D1, D2, pi = tuple(D1_D2_pi) except ValueError: raise ValueError("argument %s not in correct form; must be a tuple (D1, D2, pi)" % D1_D2_pi) - D1 = [[abs(x) for x in b] for b in D1 if len(b) == 2] # not needed if argument correctly passed at outset. - D2 = [[abs(x) for x in b] for b in D2 if len(b) == 2] # ditto. + D1 = [[abs(x) for x in b] for b in D1 if len(b) == 2] # not needed if argument correctly passed at outset. + D2 = [[abs(x) for x in b] for b in D2 if len(b) == 2] # ditto. nD2 = [[-i for i in b] for b in D2] pi = list(pi) - nn = set(range(1, self.order+1)) + nn = set(range(1, self.order + 1)) dom = sorted(nn.difference(flatten([list(x) for x in D1]))) rng = sorted(nn.difference(flatten([list(x) for x in D2]))) SP0 = D1 + nD2 if len(pi) != len(dom) or pi not in Permutations(): - raise ValueError("in the tuple (D1, D2, pi)={}, pi must be a permutation of {} (indicating a permutation on the free nodes of the diagram)".format( - (D1,D2,pi), self.order-2*len(D1))) - Perm = [[dom[i], -rng[val-1]] for i,val in enumerate(pi)] + raise ValueError("in the tuple (D1, D2, pi)={}, pi must be a permutation of {} (indicating a permutation on the free nodes of the diagram)".format((D1, D2, pi), self.order - 2 * len(D1))) + Perm = [[dom[i], -rng[val - 1]] for i, val in enumerate(pi)] SP = SP0 + Perm - return self(SP) # could pass 'SetPartition' ? + return self(SP) # could pass 'SetPartition' ? class TemperleyLiebDiagrams(AbstractPartitionDiagrams): @@ -1675,6 +1673,7 @@ class TemperleyLiebDiagrams(AbstractPartitionDiagrams): sage: td.cardinality() == len(td.list()) True """ + Element = TemperleyLiebDiagram _name = "Temperley Lieb" _diagram_func = temperley_lieb_diagrams @@ -1695,7 +1694,7 @@ def cardinality(self): """ if self.order in ZZ: return catalan_number(ZZ(self.order)) - return catalan_number(ZZ(self.order - 1/2)) + return catalan_number(ZZ(self.order - 1 / 2)) def __contains__(self, obj): r""" @@ -1755,6 +1754,7 @@ class PlanarDiagrams(AbstractPartitionDiagrams): sage: pld.cardinality() == len(pld.list()) True """ + Element = PlanarDiagram _name = "Planar" _diagram_func = planar_diagrams @@ -1773,7 +1773,7 @@ def cardinality(self): sage: pld.cardinality() 132 """ - return catalan_number(2*self.order) + return catalan_number(2 * self.order) def __contains__(self, obj): r""" @@ -1819,6 +1819,7 @@ class IdealDiagrams(AbstractPartitionDiagrams): {{-2, -1, 2}, {1}}, {{-2, 2}, {-1}, {1}}] """ + Element = IdealDiagram _name = "Ideal" _diagram_func = ideal_diagrams @@ -1902,9 +1903,7 @@ def __init__(self, k, q, base_ring, prefix, diagrams, category=None): if isinstance(self, UnitDiagramMixin): cat = cat.Unital() category = cat.or_subcategory(category) - CombinatorialFreeModule.__init__(self, base_ring, diagrams, - category=category, prefix=prefix, - bracket=False) + CombinatorialFreeModule.__init__(self, base_ring, diagrams, category=category, prefix=prefix, bracket=False) def _element_constructor_(self, set_partition): r""" @@ -1939,7 +1938,7 @@ def _element_constructor_(self, set_partition): return self.basis()[set_partition] if isinstance(set_partition, SymmetricGroupAlgebra_n.Element): return self._apply_module_morphism(set_partition, self._perm_to_Blst, self) - sp = self._base_diagrams(set_partition) # attempt conversion + sp = self._base_diagrams(set_partition) # attempt conversion if sp in self.basis().keys(): return self.basis()[sp] @@ -2164,6 +2163,7 @@ class UnitDiagramMixin: Mixin class for diagram algebras that have the unit indexed by the :func:`identity_set_partition`. """ + @cached_method def one_basis(self): r""" @@ -2510,6 +2510,7 @@ class PartitionAlgebra(DiagramBasis, UnitDiagramMixin): sage: A([2,3,1]) == A(S([2,3,1])) True """ + @staticmethod def __classcall_private__(cls, k, q, base_ring=None, prefix='P'): r""" @@ -2590,14 +2591,12 @@ def _element_constructor_(self, x): return self._diag_to_Blst(x) # conversion from orbit basis - if (isinstance(x, OrbitBasis.Element) - and self.base_ring().has_coerce_map_from(x.parent().base_ring())): + if isinstance(x, OrbitBasis.Element) and self.base_ring().has_coerce_map_from(x.parent().base_ring()): return self(x.parent().to_diagram_basis(x)) # conversion from SubPartitionAlgebra - if (isinstance(x, (PartitionAlgebra.Element, SubPartitionAlgebra.Element)) - and self.has_coerce_map_from(x.parent().base_ring())): - return sum(a * self._diag_to_Blst(d) for (d,a) in x) + if isinstance(x, (PartitionAlgebra.Element, SubPartitionAlgebra.Element)) and self.has_coerce_map_from(x.parent().base_ring()): + return sum(a * self._diag_to_Blst(d) for (d, a) in x) return super()._element_constructor_(x) @@ -2612,8 +2611,7 @@ def _repr_(self): Partition Algebra of rank 2 with parameter q over Univariate Polynomial Ring in q over Rational Field """ - return "Partition Algebra of rank {} with parameter {} over {}".format( - self._k, self._q, self.base_ring()) + return "Partition Algebra of rank {} with parameter {} over {}".format(self._k, self._q, self.base_ring()) def _coerce_map_from_(self, R): """ @@ -2731,9 +2729,7 @@ def _orbit_to_diagram_on_basis(self, d): """ # Moebius inversion in the poset of coarsenings of ``d`` SPd = SetPartitions(len(d)) - return self.sum((-1)**(len(d)-len(sp)) * prod(ZZ(len(p)-1).factorial() for p in sp) - * self([sum((list(d[i-1]) for i in p),[]) for p in sp]) - for sp in SPd) + return self.sum((-1) ** (len(d) - len(sp)) * prod(ZZ(len(p) - 1).factorial() for p in sp) * self([sum((list(d[i - 1]) for i in p), []) for p in sp]) for sp in SPd) @cached_method def a(self, i): @@ -2766,12 +2762,12 @@ def a(self, i): ValueError: i must be an integer between 1 and 1 """ if i <= 0 or i >= floor(self._k): - raise ValueError("i must be an integer between 1 and {}".format(floor(self._k)-1)) + raise ValueError("i must be an integer between 1 and {}".format(floor(self._k) - 1)) B = self.basis() SP = B.keys() - D = [[-j, j] for j in range(1, ceil(self._k)+1)] - D[i-1] = [i,i+1] - D[i] = [-i,-(i+1)] + D = [[-j, j] for j in range(1, ceil(self._k) + 1)] + D[i - 1] = [i, i + 1] + D[i] = [-i, -(i + 1)] return B[SP(D)] generator_a = a @@ -2818,17 +2814,17 @@ def e(self, i): P{{-3, -2, 2, 3}, {-1, 1}}] """ if i <= 0 or i >= self._k: - raise ValueError("i must be an (half) integer between 1/2 and {}".format((2*self._k-1)/2)) + raise ValueError("i must be an (half) integer between 1/2 and {}".format((2 * self._k - 1) / 2)) B = self.basis() SP = B.keys() if i in ZZ: i -= 1 - D = [[-j, j] for j in range(1, ceil(self._k)+1)] - D[i] += D.pop(i+1) + D = [[-j, j] for j in range(1, ceil(self._k) + 1)] + D[i] += D.pop(i + 1) return B[SP(D)] i = ceil(i) - D = [[-j, j] for j in range(1, ceil(self._k)+1)] - D[i-1] = [-i] + D = [[-j, j] for j in range(1, ceil(self._k) + 1)] + D[i - 1] = [-i] D.append([i]) return B[SP(D)] @@ -2862,12 +2858,12 @@ def s(self, i): P{{-3, 3}, {-2, 1}, {-1, 2}} """ if i not in ZZ or i <= 0 or i >= self._k: - raise ValueError("i must be an integer between 1 and {}".format(self._k-1)) + raise ValueError("i must be an integer between 1 and {}".format(self._k - 1)) B = self.basis() SP = B.keys() - D = [[-j, j] for j in range(1, ceil(self._k)+1)] - D[i-1] = [-(i+1), i] - D[i] = [-i, i+1] + D = [[-j, j] for j in range(1, ceil(self._k) + 1)] + D[i - 1] = [-(i + 1), i] + D[i] = [-i, i + 1] return B[SP(D)] generator_s = s @@ -2937,35 +2933,25 @@ def sigma(self, i): True """ if i <= 0 or i >= self._k: - raise ValueError("i must be an (half) integer between 1 and {}".format((2*self._k-1)/2)) + raise ValueError("i must be an (half) integer between 1 and {}".format((2 * self._k - 1) / 2)) half = QQ.one() / 2 if i in ZZ: if i == 1: return self.one() si = self.s(i) - sim = self.s(i-1) - x = self.e(i-1) * self.jucys_murphy_element(i-1) * si * self.e(i-1) - return (sim * si * self.sigma(i-1) * si * sim - + x * si + si * x - - self.e(i-1) * self.jucys_murphy_element(i-1) * sim - * self.e(i) * self.e(i-half) * self.e(i-1) - - si * self.e(i-1) * self.e(i-half) * self.e(i) * sim - * self.jucys_murphy_element(i-1) * self.e(i-1) * si) + sim = self.s(i - 1) + x = self.e(i - 1) * self.jucys_murphy_element(i - 1) * si * self.e(i - 1) + return sim * si * self.sigma(i - 1) * si * sim + x * si + si * x - self.e(i - 1) * self.jucys_murphy_element(i - 1) * sim * self.e(i) * self.e(i - half) * self.e(i - 1) - si * self.e(i - 1) * self.e(i - half) * self.e(i) * sim * self.jucys_murphy_element(i - 1) * self.e(i - 1) * si j = ceil(i) - 1 if j == 0: return self.zero() if j == 1: return self.s(1) si = self.s(j) - sim = self.s(j-1) - x = self.e(j-1) * self.jucys_murphy_element(j-1) * si * self.e(j-1) - return (sim * si * self.sigma(i-1) * si * sim - + si * x * si + x - - si * self.e(j-1) * self.jucys_murphy_element(j-1) * sim - * self.e(j) * self.e(i-1) * self.e(j-1) - - self.e(j-1) * self.e(i-1) * self.e(j) * sim - * self.jucys_murphy_element(j-1) * self.e(j-1) * si) + sim = self.s(j - 1) + x = self.e(j - 1) * self.jucys_murphy_element(j - 1) * si * self.e(j - 1) + return sim * si * self.sigma(i - 1) * si * sim + si * x * si + x - si * self.e(j - 1) * self.jucys_murphy_element(j - 1) * sim * self.e(j) * self.e(i - 1) * self.e(j - 1) - self.e(j - 1) * self.e(i - 1) * self.e(j) * sim * self.jucys_murphy_element(j - 1) * self.e(j - 1) * si @cached_method def jucys_murphy_element(self, i): @@ -3085,17 +3071,12 @@ def jucys_murphy_element(self, i): return self.e(half) i -= 1 L = self.jucys_murphy_element - return ((self.s(i) * L(i)) * (self.s(i) - self.e(i)) - - (self.e(i) * L(i)) * (self.s(i) - self.e(i+half)*self.e(i)) - + self.sigma(i+half)) + return (self.s(i) * L(i)) * (self.s(i) - self.e(i)) - (self.e(i) * L(i)) * (self.s(i) - self.e(i + half) * self.e(i)) + self.sigma(i + half) j = ceil(i) - 1 if j == 0: return self.zero() L = self.jucys_murphy_element - return (self.s(j) * L(i-1) * self.s(j) - - self.e(j)*L(j) - + (self._q*self.one() - L(i-1) - L(j))*self.e(j) - + self.sigma(j)) + return self.s(j) * L(i - 1) * self.s(j) - self.e(j) * L(j) + (self._q * self.one() - L(i - 1) - L(j)) * self.e(j) + self.sigma(j) L = jucys_murphy_element @@ -3170,8 +3151,7 @@ def dual(self): 3*P{{-2, -1, 1}, {2}} + 2*P{{-2, -1, 1, 2}} + 2*P{{-2, -1, 2}, {1}} """ P = self.parent() - return P._from_dict({D.dual(): c for D, c in self._monomial_coefficients.items()}, - remove_zeros=False) + return P._from_dict({D.dual(): c for D, c in self._monomial_coefficients.items()}, remove_zeros=False) class OrbitBasis(DiagramAlgebra): @@ -3251,6 +3231,7 @@ class OrbitBasis(DiagramAlgebra): sage: all(P2(O2(P2(m))) == P2(m) for m in PD) True """ + @staticmethod def __classcall_private__(cls, *args): """ @@ -3384,8 +3365,7 @@ def one(self): PDs = self._base_diagrams base = SetPartitions()(identity_set_partition(self._k)) brone = self.base_ring().one() - return self._from_dict({PDs(d): brone for d in base.coarsenings()}, - coerce=False, remove_zeros=False) + return self._from_dict({PDs(d): brone for d in base.coarsenings()}, coerce=False, remove_zeros=False) def diagram_basis(self): """ @@ -3455,8 +3435,7 @@ def _diagram_to_orbit_on_basis(self, diag): """ PDs = PartitionDiagrams(self._alg._k) one = self.base_ring().one() - return self._from_dict({PDs(d): one for d in diag.set_partition().coarsenings()}, - coerce=False, remove_zeros=False) + return self._from_dict({PDs(d): one for d in diag.set_partition().coarsenings()}, coerce=False, remove_zeros=False) def product_on_basis(self, d1, d2): r""" @@ -3559,16 +3538,11 @@ def matchings(A, B): yield [x.union(y) for x, y in zip(X, sigma)] + restA + restB D, removed = d1.compose(d2, check=False) - only_top = {frozenset(part) for part in d1 - if all(i > 0 for i in part)} - only_bottom = {frozenset(part) for part in d2 - if all(i < 0 for i in part)} + only_top = {frozenset(part) for part in d1 if all(i > 0 for i in part)} + only_bottom = {frozenset(part) for part in d2 if all(i < 0 for i in part)} only_both = only_top.union(only_bottom) restD = [P for P in D if frozenset(P) not in only_both] - term_dict = {PDs(restD + X): - R.prod(q - t for t in range(len(X) + len(restD), - len(X) + len(restD) + removed)) - for X in matchings(only_top, only_bottom)} + term_dict = {PDs(restD + X): R.prod(q - t for t in range(len(X) + len(restD), len(X) + len(restD) + removed)) for X in matchings(only_top, only_bottom)} return self._from_dict(term_dict) class Element(PartitionAlgebra.Element): @@ -3595,7 +3569,7 @@ def to_diagram_basis(self): """ # use _coerce_map_from_ return self.parent()._alg(self) - #return self._alg.coerce_map_from(self) + # return self._alg.coerce_map_from(self) class SubPartitionAlgebra(DiagramBasis): @@ -3617,7 +3591,7 @@ def __init__(self, k, q, base_ring, prefix, diagrams, category=None): """ DiagramBasis.__init__(self, k, q, base_ring, prefix, diagrams, category) - #These methods allow for a subalgebra to be correctly identified in a partition algebra + # These methods allow for a subalgebra to be correctly identified in a partition algebra def ambient(self): r""" Return the partition algebra ``self`` is a sub-algebra of. @@ -3665,8 +3639,7 @@ def retract(self, x): sage: BA.retract(E) in BA True """ - if ( x not in self.ambient() - or any(i not in self._indices for i in x.support()) ): + if x not in self.ambient() or any(i not in self._indices for i in x.support()): raise ValueError("{0} cannot retract to {1}".format(x, self)) return self._from_dict(x._monomial_coefficients, remove_zeros=False) @@ -3792,8 +3765,7 @@ def _repr_(self): Brauer Algebra of rank 2 with parameter q over Univariate Polynomial Ring in q over Rational Field """ - return "Brauer Algebra of rank {} with parameter {} over {}".format( - self._k, self._q, self.base_ring()) + return "Brauer Algebra of rank {} with parameter {} over {}".format(self._k, self._q, self.base_ring()) # TODO: Make a mixin class for diagram algebras that have coercions from SGA? def _coerce_map_from_(self, R): @@ -3881,9 +3853,10 @@ def jucys_murphy(self, j): def convertI(x): return self._indices(to_Brauer_partition(x, k=k)) + R = self.base_ring() one = R.one() - d = {self.one_basis(): R((self._q - 1)/2)} + d = {self.one_basis(): R((self._q - 1) / 2)} for i in range(1, j): d[convertI([[i, -j], [j, -i]])] = one d[convertI([[i, j], [-i, -j]])] = -one @@ -3894,6 +3867,7 @@ class HalfTemperleyLiebDiagrams(UniqueRepresentation, Parent): r""" Half diagrams for the Temperley-Lieb algebra cell modules. """ + def __init__(self, order, defects): r""" Initialize ``self``. @@ -3932,11 +3906,12 @@ def __iter__(self): k = self._defects b = (n - k) // 2 from sage.combinat.dyck_word import DyckWords - for dw in DyckWords(b+k, b): + + for dw in DyckWords(b + k, b): ret = [] offset = 0 for D in dw.catalan_factorization(): - ret.extend((offset+a+1, offset+b) for (a, b) in D.tunnels()) + ret.extend((offset + a + 1, offset + b) for (a, b) in D.tunnels()) offset += len(D) + 1 yield self.element_class(self, ret) @@ -3965,6 +3940,7 @@ def cardinality(self): 14 """ from sage.functions.other import binomial + n = self._order k = self._defects b = (n - k) // 2 @@ -4044,6 +4020,7 @@ def _ascii_art_(self): temp.sort() ret = TL_diagram_ascii_art(temp) from sage.typeset.ascii_art import AsciiArt + return AsciiArt(ret[2:]) def _unicode_art_(self): @@ -4072,6 +4049,7 @@ def _unicode_art_(self): temp.sort() ret = TL_diagram_ascii_art(temp, use_unicode=True) from sage.typeset.unicode_art import UnicodeArt + return UnicodeArt(ret[2:]) def defects(self): @@ -4087,7 +4065,7 @@ def defects(self): frozenset({3, 6, 7}) """ order = self.parent()._order - return frozenset(range(1, order+1)) - frozenset(e for B in self for e in B) + return frozenset(range(1, order + 1)) - frozenset(e for B in self for e in B) def check(self): r""" @@ -4118,9 +4096,8 @@ def check(self): """ tst = frozenset(e for B in self._base_diagram for e in B) P = self.parent() - if not (tst <= frozenset(range(1, P._order+1))): - raise ValueError("{} does not represent a half TL diagram of order {}".format( - self, self.parent()._order)) + if not (tst <= frozenset(range(1, P._order + 1))): + raise ValueError("{} does not represent a half TL diagram of order {}".format(self, self.parent()._order)) if any(len(block) != 2 for block in self): raise ValueError("all blocks of {} must be of size 2".format(self)) if len(tst) != P._order - P._defects: @@ -4232,6 +4209,7 @@ class TemperleyLiebAlgebra(SubPartitionAlgebra, UnitDiagramMixin): 1 5 8 5 1 7 20 21 13 """ + @staticmethod def __classcall_private__(cls, k, q, base_ring=None, prefix='T'): r""" @@ -4277,8 +4255,7 @@ def _repr_(self): Temperley-Lieb Algebra of rank 2 with parameter q over Univariate Polynomial Ring in q over Rational Field """ - return "Temperley-Lieb Algebra of rank {} with parameter {} over {}".format( - self._k, self._q, self.base_ring()) + return "Temperley-Lieb Algebra of rank {} with parameter {} over {}".format(self._k, self._q, self.base_ring()) def _element_constructor_(self, set_partition): r""" @@ -4363,7 +4340,8 @@ def cell_poset(self): [[0, 2], [2, 4], [4, 6], [6, 8]] """ from sage.combinat.posets.posets import Poset - return Poset({k-2: [k] for k in range(self._k, 1, -2)}) + + return Poset({k - 2: [k] for k in range(self._k, 1, -2)}) def cell_module_indices(self, la): r""" @@ -4408,7 +4386,7 @@ def _to_cellular_element(self, d): top = [] bottom = [] defects = ZZ.zero() - for (a, b) in d: + for a, b in d: if b < 0: bottom.append((-b, -a)) elif a > 0: @@ -4463,8 +4441,8 @@ def _from_cellular_index(self, x): """ _, top, bottom = x bottom = [[-b, -a] for (a, b) in bottom] - tmiss = frozenset(range(1, self._k+1)) - frozenset(e for B in top for e in B) - bmiss = frozenset(range(-1, -self._k-1, -1)) - frozenset(e for B in bottom for e in B) + tmiss = frozenset(range(1, self._k + 1)) - frozenset(e for B in top for e in B) + bmiss = frozenset(range(-1, -self._k - 1, -1)) - frozenset(e for B in bottom for e in B) prop = list(zip(sorted(tmiss, reverse=True), sorted(bmiss))) return self.monomial(self._indices(bottom + prop + list(top))) @@ -4489,8 +4467,7 @@ def cellular_involution(self, x): o o o o o o o o o o o o """ M = x.monomial_coefficients(copy=False) - return self._from_dict({d.dual(): c for d, c in M.items()}, - remove_zeros=False) + return self._from_dict({d.dual(): c for d, c in M.items()}, remove_zeros=False) class PlanarAlgebra(SubPartitionAlgebra, UnitDiagramMixin): @@ -4548,6 +4525,7 @@ class PlanarAlgebra(SubPartitionAlgebra, UnitDiagramMixin): sage: E^5 == x^4*E True """ + @staticmethod def __classcall_private__(cls, k, q, base_ring=None, prefix='Pl'): r""" @@ -4637,6 +4615,7 @@ class PropagatingIdeal(SubPartitionAlgebra): sage: E^5 == x^4*E True """ + @staticmethod def __classcall_private__(cls, k, q, base_ring=None, prefix='I'): r""" @@ -4666,8 +4645,7 @@ def __init__(self, k, q, base_ring, prefix): sage: TestSuite(I).run() """ category = AssociativeAlgebras(base_ring.category()).FiniteDimensional().WithBasis() - SubPartitionAlgebra.__init__(self, k, q, base_ring, prefix, - IdealDiagrams(k), category) + SubPartitionAlgebra.__init__(self, k, q, base_ring, prefix, IdealDiagrams(k), category) def _repr_(self): """ @@ -4680,8 +4658,7 @@ def _repr_(self): Propagating Ideal of rank 2 with parameter x over Univariate Polynomial Ring in x over Rational Field """ - return "Propagating Ideal of rank {} with parameter {} over {}".format( - self._k, self._q, self.base_ring()) + return "Propagating Ideal of rank {} with parameter {} over {}".format(self._k, self._q, self.base_ring()) class Element(SubPartitionAlgebra.Element): """ @@ -4780,6 +4757,7 @@ def TL_diagram_ascii_art(diagram, use_unicode=False, blobs=[]): ╭●╮ ╭─╮ │ │ │ │ │ │ │ │ ╭─╮ │ ╭─╮ │ │ │ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ ⚬ """ + def insert_pairing(cur, intervals): """ Helper function to insert a possibly nested interval @@ -4799,6 +4777,7 @@ def insert_pairing(cur, intervals): level.append(cur) return # We have stopped intervals.append([cur]) + # Build a set of intervals that defines where to draw the diagram intervals = [[]] propogating = [] @@ -4819,6 +4798,7 @@ def key_func(P): return (2, -bot, -top) # vertical line return (1, top, bot) + diagram = sorted(diagram, key=key_func) # Since diagram is sorted in lex order, we will first do the matchings # from right-to-left on the bottom, then the propogating lines, and @@ -4858,7 +4838,7 @@ def key_func(P): count_left += 1 for j in range(i): prop_intervals[j].append([bot]) - for j in range(i+1, total_prop): + for j in range(i + 1, total_prop): prop_intervals[j].append([top]) if not left_moving: top, bot = bot, top @@ -4873,13 +4853,15 @@ def key_func(P): # Finally, convert to a picture if use_unicode: from sage.typeset.unicode_art import UnicodeArt + d = ["╭", "╮", "╰", "╯", "─", "│"] - #db = ["┏", "┓", "┗", "┛", "━", "┃"] + # db = ["┏", "┓", "┗", "┛", "━", "┃"] blob = '●' ret = [" ⚬" * n] char_art = UnicodeArt else: from sage.typeset.ascii_art import AsciiArt + d = [".", ".", "`", "`", "-", "|"] # db = [".", ".", "`", "`", "=", "|"] blob = '0' @@ -4888,25 +4870,26 @@ def key_func(P): def signed(val, pos): return val if pos else -val + for level in reversed(intervals): cur = "" for I in sorted(level): - cur += ' '*(2*I[0]-1 - len(cur)) + cur += ' ' * (2 * I[0] - 1 - len(cur)) if len(I) == 1: cur += d[5] + ' ' else: cur += d[2] if I[2] else d[0] if tuple(sorted([signed(I[0], I[2]), signed(I[1], I[3])])) in blobs: - cur += d[4] * (I[1]-I[0]-1) + cur += d[4] * (I[1] - I[0] - 1) cur += blob - cur += d[4] * (I[1]-I[0]-1) + cur += d[4] * (I[1] - I[0] - 1) else: - cur += d[4] * (2*(I[1]-I[0])-1) + cur += d[4] * (2 * (I[1] - I[0]) - 1) cur += d[3] if I[3] else d[1] ret.append(cur) # Note that the top row and bottom row will be the same ret.append(ret[0]) - return char_art(ret, baseline=len(ret)//2) + return char_art(ret, baseline=len(ret) // 2) def diagram_latex(diagram, fill=False, edge_options=None, edge_additions=None): @@ -4958,7 +4941,7 @@ def sgn(x): l2.extend(list(i)) output = "\\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] \n\\tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] \n" # setup beginning of picture for i in l2: # add nodes - output = output + "\\node[vertex] (G-{}) at ({}, {}) [shape = circle, draw{}] {{}}; \n".format(i, (abs(i)-1)*1.5, sgn(i), filled_str) + output = output + "\\node[vertex] (G-{}) at ({}, {}) [shape = circle, draw{}] {{}}; \n".format(i, (abs(i) - 1) * 1.5, sgn(i), filled_str) for i in l1: # add edges if len(i) > 1: l4 = list(i) @@ -4974,26 +4957,25 @@ def sgn(x): l4 = posList + negList l5 = l4[:] # deep copy for j in range(len(l5)): - l5[j-1] = l4[j] # create a permuted list + l5[j - 1] = l4[j] # create a permuted list if len(l4) == 2: l4.pop() l5.pop() # pops to prevent duplicating edges for j in zip(l4, l5): - xdiff = abs(j[1])-abs(j[0]) + xdiff = abs(j[1]) - abs(j[0]) y1 = sgn(j[0]) y2 = sgn(j[1]) - if y2-y1 == 0 and abs(xdiff) < 5: # if nodes are close to each other on same row - diffCo = (0.5+0.1*(abs(xdiff)-1)) # gets bigger as nodes are farther apart; max value of 1; min value of 0.5. - outVec = (sgn(xdiff)*diffCo, -1*diffCo*y1) - inVec = (-1*diffCo*sgn(xdiff), -1*diffCo*y2) - elif y2-y1 != 0 and abs(xdiff) == 1: # if nodes are close enough curviness looks bad. - outVec = (sgn(xdiff)*0.75, -1*y1) - inVec = (-1*sgn(xdiff)*0.75, -1*y2) + if y2 - y1 == 0 and abs(xdiff) < 5: # if nodes are close to each other on same row + diffCo = 0.5 + 0.1 * (abs(xdiff) - 1) # gets bigger as nodes are farther apart; max value of 1; min value of 0.5. + outVec = (sgn(xdiff) * diffCo, -1 * diffCo * y1) + inVec = (-1 * diffCo * sgn(xdiff), -1 * diffCo * y2) + elif y2 - y1 != 0 and abs(xdiff) == 1: # if nodes are close enough curviness looks bad. + outVec = (sgn(xdiff) * 0.75, -1 * y1) + inVec = (-1 * sgn(xdiff) * 0.75, -1 * y2) else: - outVec = (sgn(xdiff)*1, -1*y1) - inVec = (-1*sgn(xdiff), -1*y2) - output = output + "\\draw[{}] (G-{}) .. controls +{} and +{} .. {}(G-{}); \n".format( - edge_options(j), j[0], outVec, inVec, edge_additions(j), j[1]) + outVec = (sgn(xdiff) * 1, -1 * y1) + inVec = (-1 * sgn(xdiff), -1 * y2) + output = output + "\\draw[{}] (G-{}) .. controls +{} and +{} .. {}(G-{}); \n".format(edge_options(j), j[0], outVec, inVec, edge_additions(j), j[1]) output = output + "\\end{tikzpicture}" # end picture return output @@ -5118,6 +5100,7 @@ class PottsRepresentation(CombinatorialFreeModule): - [MR1998]_ """ + def __init__(self, PA, y): r""" Initialize ``self``. @@ -5188,17 +5171,20 @@ def __init__(self, PA, y): # _order is used to define the ordering of the basis elements self._num_factors = ZZ(order) from sage.combinat.words.words import Words + indices = Words(self._d, self._num_factors) R = PA.base_ring() from sage.categories.modules_with_basis import ModulesWithBasis + cat = ModulesWithBasis(R).FiniteDimensional() CombinatorialFreeModule.__init__(self, R, indices, prefix='P', category=cat) from sage.groups.perm_gps.permgroup_named import SymmetricGroup + if self._y is None: self._symgp = SymmetricGroup(self._d) else: - self._symgp = SymmetricGroup([i for i in range(1, self._d+1) if i != self._y]) + self._symgp = SymmetricGroup([i for i in range(1, self._d + 1) if i != self._y]) self._sga = self._symgp.algebra(R) def _repr_(self): @@ -5235,6 +5221,7 @@ def _test_representation(self, **options): S = tester.some_elements() B = self._PA.basis() from sage.misc.misc import some_tuples + for x, y in some_tuples(B, 2, tester._max_runs // len(S)): for v in S: tester.assertEqual((v * x) * y, v * (x * y)) @@ -5392,17 +5379,18 @@ def _basis_action(self, word, diagram): elif -i == order + 1: assert color == self._y else: - fixed[-i-1] = color # convert 1-based to 0-based + fixed[-i - 1] = color # convert 1-based to 0-based if not neg_parts: return self._monomial(fixed) import itertools + ret = [] - for c in itertools.product(range(1, self._d+1), repeat=len(neg_parts)): + for c in itertools.product(range(1, self._d + 1), repeat=len(neg_parts)): temp = list(fixed) # make a copy for color, part in zip(c, neg_parts): for j in part: - temp[-j-1] = color # convert 1-based to 0-based + temp[-j - 1] = color # convert 1-based to 0-based ret.append(self._indices(temp)) return self.sum_of_monomials(ret) @@ -5481,6 +5469,7 @@ def representation_matrix(self, elt): True """ from sage.matrix.constructor import matrix + return matrix([(b * elt).to_vector() for b in self.basis()]) class Element(CombinatorialFreeModule.Element): @@ -5545,18 +5534,14 @@ def _acted_upon_(self, scalar, self_on_left=True): scalar = par._sga(scalar) except (ValueError, TypeError): return None - return par.linear_combination((par._sym_group_action(g, wd), cg * cr) - for (wd, cr) in self._monomial_coefficients.items() - for (g, cg) in scalar.monomial_coefficients(copy=False).items()) + return par.linear_combination((par._sym_group_action(g, wd), cg * cr) for (wd, cr) in self._monomial_coefficients.items() for (g, cg) in scalar.monomial_coefficients(copy=False).items()) # right action, so convert to the partition algebra try: scalar = par._PA(scalar) except (ValueError, TypeError): return None - return par.linear_combination((par._basis_action(wd, diag), cr * ca) - for (wd, cr) in self._monomial_coefficients.items() - for (diag, ca) in scalar.monomial_coefficients(copy=False).items()) + return par.linear_combination((par._basis_action(wd, diag), cr * ca) for (wd, cr) in self._monomial_coefficients.items() for (diag, ca) in scalar.monomial_coefficients(copy=False).items()) ######################################################################### @@ -5614,12 +5599,12 @@ def is_planar(sp) -> bool: for row in [ap, an]: if len(row) > 1: row.sort() - for s in range(len(row)-1): - if row[s] + 1 == row[s+1]: + for s in range(len(row) - 1): + if row[s] + 1 == row[s + 1]: # No gap, continue on continue - rng = list(range(row[s] + 1, row[s+1])) + rng = list(range(row[s] + 1, row[s + 1])) # Go through and make sure any parts that # contain numbers in this range are completely @@ -5666,7 +5651,7 @@ def to_graph(sp): g.add_vertex(part_list[0]) for i in range(1, len(part_list)): g.add_vertex(part_list[i]) - g.add_edge(part_list[i-1], part_list[i]) + g.add_edge(part_list[i - 1], part_list[i]) return g @@ -5711,34 +5696,34 @@ def pair_to_graph(sp1, sp2): """ g = Graph() - #Add the first set partition to the graph + # Add the first set partition to the graph for part in sp1: part_list = list(part) if part_list: - g.add_vertex( (part_list[0], 1) ) + g.add_vertex((part_list[0], 1)) - #Add the edge to the second part of the graph + # Add the edge to the second part of the graph if part_list[0] < 0: - g.add_edge( (part_list[0], 1), (abs(part_list[0]), 2) ) + g.add_edge((part_list[0], 1), (abs(part_list[0]), 2)) for i in range(1, len(part_list)): - g.add_vertex( (part_list[i], 1) ) + g.add_vertex((part_list[i], 1)) - #Add the edge to the second part of the graph + # Add the edge to the second part of the graph if part_list[i] < 0: - g.add_edge( (part_list[i], 1), (abs(part_list[i]), 2) ) + g.add_edge((part_list[i], 1), (abs(part_list[i]), 2)) - #Add the edge between adjacent elements of a part - g.add_edge( (part_list[i-1], 1), (part_list[i], 1) ) + # Add the edge between adjacent elements of a part + g.add_edge((part_list[i - 1], 1), (part_list[i], 1)) - #Add the second set partition to the graph + # Add the second set partition to the graph for part in sp2: part_list = list(part) if part_list: - g.add_vertex( (part_list[0], 2) ) + g.add_vertex((part_list[0], 2)) for i in range(1, len(part_list)): - g.add_vertex( (part_list[i], 2) ) - g.add_edge( (part_list[i-1], 2), (part_list[i], 2) ) + g.add_vertex((part_list[i], 2)) + g.add_edge((part_list[i - 1], 2), (part_list[i], 2)) return g @@ -5798,7 +5783,7 @@ def to_set_partition(l, k=None): return [] k = max(max(map(abs, x)) for x in l) - to_be_added = set(list(range(1, ceil(k+1))) + [-x for x in range(1, ceil(k+1))]) + to_be_added = set(list(range(1, ceil(k + 1))) + [-x for x in range(1, ceil(k + 1))]) sp = [] for part in l: @@ -5847,7 +5832,7 @@ def to_Brauer_partition(l, k=None): paired.append(i) if len(i) == 1: not_paired.append(i) - if any(i[0] in j or -1*i[0] in j for i in not_paired for j in paired): + if any(i[0] in j or -1 * i[0] in j for i in not_paired for j in paired): raise ValueError("unable to convert {} to a Brauer partition due to the invalid block {}".format(l, i)) for i in not_paired: if [-i[0]] in not_paired: @@ -5867,9 +5852,10 @@ def identity_set_partition(k): {{-2, 2}, {-1, 1}} """ if k in ZZ: - return [[i,-i] for i in range(1, k + 1)] + return [[i, -i] for i in range(1, k + 1)] # Else k in 1/2 ZZ - return [[i, -i] for i in range(1, k + ZZ(3)/ZZ(2))] + return [[i, -i] for i in range(1, k + ZZ(3) / ZZ(2))] + ########################################################################## # END BORROWED CODE diff --git a/src/sage/combinat/dlx.py b/src/sage/combinat/dlx.py index 3fdaf839722..9ba33c17063 100644 --- a/src/sage/combinat/dlx.py +++ b/src/sage/combinat/dlx.py @@ -1,6 +1,7 @@ """ Exact cover problem via dancing links """ + # dlx.py # Copyright (c) 2006,2008 Antti Ajanki @@ -481,7 +482,7 @@ def AllExactCovers(M): [(1, 0, 1), (0, 1, 0)] """ ones = [] - r = 1 # damn 1-indexing + r = 1 # damn 1-indexing for R in M.rows(): row = [i for i, Ri in enumerate(R, start=1) if Ri] ones.append([r, row]) diff --git a/src/sage/combinat/dyck_word.py b/src/sage/combinat/dyck_word.py index ec0465b3bff..6507bdcca7f 100644 --- a/src/sage/combinat/dyck_word.py +++ b/src/sage/combinat/dyck_word.py @@ -296,10 +296,9 @@ class DyckWord(CombinatorialElement): _| . | . . """ + @staticmethod - def __classcall_private__(cls, dw=None, noncrossing_partition=None, - area_sequence=None, heights_sequence=None, - catalan_code=None): + def __classcall_private__(cls, dw=None, noncrossing_partition=None, area_sequence=None, heights_sequence=None, catalan_code=None): """ Return an element with the appropriate parent. @@ -547,15 +546,15 @@ def _repr_lattice(self, type=None, labelling=None, underpath=True) -> str: row = " " * (n - alst[-1] - 1) + final_fall + "\n" for i in range(n - 1): c = 0 - row = row + " " * (n-i-2-alst[-i-2]) - c += n-i-2-alst[-i-2] - if alst[-i-2]+1 != alst[-i-1]: + row = row + " " * (n - i - 2 - alst[-i - 2]) + c += n - i - 2 - alst[-i - 2] + if alst[-i - 2] + 1 != alst[-i - 1]: row += " _" - c += alst[-i-2] - alst[-i-1] + c += alst[-i - 2] - alst[-i - 1] if underpath: - row += "__" * (alst[-i-2]-alst[-i-1]) + "|" + labels[-1] + "x "*(n-c-2-i) + " ." * i + "\n" + row += "__" * (alst[-i - 2] - alst[-i - 1]) + "|" + labels[-1] + "x " * (n - c - 2 - i) + " ." * i + "\n" else: - row += "__"*(alst[-i-2]-alst[-i-1])+"| " + "x "*(n-c-2-i) + " ."*i + labels[-1] + "\n" + row += "__" * (alst[-i - 2] - alst[-i - 1]) + "| " + "x " * (n - c - 2 - i) + " ." * i + labels[-1] + "\n" labels.pop() if underpath: row += "|" + labels[-1] + " ." * (n - 1) + "\n" @@ -576,6 +575,7 @@ def _ascii_art_(self): [ /\/\/\, /\/ \, / \/\, / \, / \ ] """ from sage.typeset.ascii_art import AsciiArt + rep = self.parent().options.ascii_art if rep == "path": ret = self.to_path_string() @@ -595,6 +595,7 @@ def _unicode_art_(self): ⎣ ╱╲╱╲╱╲, ╱╲╱ ╲, ╱ ╲╱╲, ╱ ╲, ╱ ╲ ⎦ """ from sage.typeset.unicode_art import UnicodeArt + return UnicodeArt(self.to_path_string(unicode=True).splitlines()) def __str__(self) -> str: @@ -634,6 +635,7 @@ def to_path_string(self, unicode=False) -> str: """ if unicode: import unicodedata + space = ' ' up = unicodedata.lookup('BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT') down = unicodedata.lookup('BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT') @@ -867,8 +869,7 @@ def _latex_(self) -> str: valleys.append(ht[-1]) hti = iter(ht) if diagonal: - grid = [((0, i), (i, i + 1)) - for i in range(self.number_of_open_symbols())] + grid = [((0, i), (i, i + 1)) for i in range(self.number_of_open_symbols())] else: grid = [((0, 0), (len(self), self.height()))] res = "\\vcenter{\\hbox{$\\begin{tikzpicture}[scale=" + str(latex_options['tikz_scale']) + "]\n" @@ -878,14 +879,11 @@ def _latex_(self) -> str: if latex_options['peaks']: mark_points.extend(peaks) for v in mark_points: - res += " \\draw[line width=2,color=red,fill=red] %s circle (%s);\n" % (str(v), 0.15 + .03 * latex_options['line width']) + res += " \\draw[line width=2,color=red,fill=red] %s circle (%s);\n" % (str(v), 0.15 + 0.03 * latex_options['line width']) if latex_options["bounce path"]: D = self.bounce_path() D.set_latex_options(latex_options) - D.set_latex_options({"color": "green", - "line width": 2 * latex_options['line width'], - "bounce path": False, - "peaks": False, "valleys": False}) + D.set_latex_options({"color": "green", "line width": 2 * latex_options['line width'], "bounce path": False, "peaks": False, "valleys": False}) res += D._latex_().split("\n")[-2] + "\n" for v1, v2 in grid: res += " \\draw[dotted] %s grid %s;\n" % (str(v1), str(v2)) @@ -948,8 +946,7 @@ def _repr_svg_(self) -> str: resu3 += "".join(hori_lines) margin = 2 * width - resu += '\"{} {} {} {} \">'.format(-margin, -max_y - margin, - N + 2 * margin, max_y + 2 * margin) + resu += '\"{} {} {} {} \">'.format(-margin, -max_y - margin, N + 2 * margin, max_y + 2 * margin) return resu + resu1 + resu3 @@ -964,6 +961,7 @@ def plot(self, **kwds): Graphics object consisting of 1 graphics primitive """ from sage.plot.plot import list_plot + step = [-1, 1] sigma = 0 list_sigma = [0] @@ -1233,8 +1231,12 @@ def ascent_prime_decomposition(self) -> list[DyckWord]: break j += 1 else: - result.extend([DyckWord([open_symbol] * up), # type:ignore - DyckWord(self[i:j])]) # type:ignore + result.extend( + [ + DyckWord([open_symbol] * up), # type:ignore + DyckWord(self[i:j]), + ] + ) # type:ignore i = j up = 0 @@ -1332,8 +1334,7 @@ def peaks(self) -> list: sage: DyckWord([1,1,0,1,0,1,0,0]).peaks() # Haglund's def gives 2 [1, 3, 5] """ - return [i for i in range(len(self) - 1) - if self[i] == open_symbol and self[i + 1] == close_symbol] + return [i for i in range(len(self) - 1) if self[i] == open_symbol and self[i + 1] == close_symbol] def number_of_peaks(self) -> int: r""" @@ -1371,8 +1372,7 @@ def valleys(self) -> list: sage: DyckWord([1,1,0,1,0,1,0,0]).valleys() [2, 4] """ - return [i for i in range(len(self) - 1) - if self[i] == close_symbol and self[i + 1] == open_symbol] + return [i for i in range(len(self) - 1) if self[i] == close_symbol and self[i + 1] == open_symbol] def number_of_valleys(self) -> int: r""" @@ -1437,8 +1437,7 @@ def positions_of_double_rises(self) -> list: sage: DyckWord([1, 0, 1, 0]).positions_of_double_rises() [] """ - return [i for i in range(len(self) - 1) - if self[i] == self[i + 1] == open_symbol] + return [i for i in range(len(self) - 1) if self[i] == self[i + 1] == open_symbol] def number_of_double_rises(self) -> int: r""" @@ -1532,6 +1531,7 @@ def touch_composition(self): [] """ from sage.combinat.composition import Composition + if not self: return Composition([]) return Composition(descents=[i - 1 for i in self.touch_points()]) @@ -1585,11 +1585,12 @@ def rise_composition(self): [1, 1] """ from sage.combinat.composition import Composition + L = list(self) rise_comp = [] while L: i = L.index(0) - L = L[i + 1:] + L = L[i + 1 :] if i: rise_comp.append(i) return Composition(rise_comp) @@ -1624,6 +1625,7 @@ def to_standard_tableau(self): else: close_positions.append(i + 1) from sage.combinat.tableau import StandardTableau + return StandardTableau([x for x in [open_positions, close_positions] if x]) def to_tamari_sorting_tuple(self) -> list[int]: @@ -1716,6 +1718,7 @@ def to_binary_tree(self, usemap='1L0R'): if usemap not in ["1L0R", "1R0L", "L1R0", "R1L0"]: raise ValueError("%s is not a correct map" % usemap) from sage.combinat.binary_tree import BinaryTree + if not self: return BinaryTree() tp = [0] @@ -1731,8 +1734,7 @@ def to_binary_tree(self, usemap='1L0R'): e0 = tp[len(tp) - 2] s1 = e0 + 1 e1 = l - 1 - trees = [DyckWord(self[s0:e0]).to_binary_tree(usemap), - DyckWord(self[s1:e1]).to_binary_tree(usemap)] + trees = [DyckWord(self[s0:e0]).to_binary_tree(usemap), DyckWord(self[s1:e1]).to_binary_tree(usemap)] if usemap[0] == "R" or usemap[1] == "R": trees.reverse() return BinaryTree(trees) @@ -1757,6 +1759,7 @@ def to_binary_tree_tamari(self): """ # return self.to_binary_tree("L1R0") # slower and recursive from sage.combinat.binary_tree import from_tamari_sorting_tuple + tup = self.to_tamari_sorting_tuple() return from_tamari_sorting_tuple(tup) @@ -1804,6 +1807,7 @@ def tamari_interval(self, other): ValueError: the two Dyck words are not comparable on the Tamari lattice """ from sage.combinat.interval_posets import TamariIntervalPosets + return TamariIntervalPosets.from_dyck_words(self, other) def _area_sequence_iter(self) -> Iterator[int]: @@ -1941,6 +1945,7 @@ def to_partition(self): [1, 1] """ from sage.combinat.partition import Partition + n = len(self) // 2 res = [] for c in reversed(self): @@ -1975,6 +1980,7 @@ def number_of_parking_functions(self) -> int: 6 """ from sage.arith.misc import multinomial + return multinomial(self.rise_composition()) def list_parking_functions(self) -> list: @@ -1998,6 +2004,7 @@ def parking_functions(self): [[1, 1, 2], [1, 2, 1], [2, 1, 1]] """ from sage.combinat.parking_functions import ParkingFunction + alist = self._area_sequence_iter() for pi in Permutations([i - ai + 1 for i, ai in enumerate(alist)]): yield ParkingFunction(pi) @@ -2030,12 +2037,10 @@ def reading_permutation(self) -> Permutation: return Permutation([]) # type:ignore alist = self.to_area_sequence() m = max(alist) - p1 = Word([m - alist[-i - 1] - for i in range(len(alist))]).standard_permutation() + p1 = Word([m - alist[-i - 1] for i in range(len(alist))]).standard_permutation() return p1.inverse().complement() - def characteristic_symmetric_function(self, q=None, - R=QQ['q', 't'].fraction_field()): + def characteristic_symmetric_function(self, q=None, R=QQ['q', 't'].fraction_field()): r""" The characteristic function of ``self`` is the sum of `q^{dinv(D,F)} Q_{ides(read(D,F))}` over all permutation @@ -2068,6 +2073,7 @@ def characteristic_symmetric_function(self, q=None, """ from sage.combinat.ncsf_qsym.qsym import QuasiSymmetricFunctions from sage.combinat.sf.sf import SymmetricFunctions + if q is None: q = R('q') else: @@ -2075,9 +2081,8 @@ def characteristic_symmetric_function(self, q=None, raise ValueError("q=%s must be an element of the base ring %s" % (q, R)) F = QuasiSymmetricFunctions(R).Fundamental() p = self.reading_permutation().inverse() - perms = [Word(perm).standard_permutation() - for perm in self.list_parking_functions()] - QSexpr = sum(q**self.dinv(pv.inverse()) * F(Permutation([p(i) for i in pv]).descents_composition()) for pv in perms) + perms = [Word(perm).standard_permutation() for perm in self.list_parking_functions()] + QSexpr = sum(q ** self.dinv(pv.inverse()) * F(Permutation([p(i) for i in pv]).descents_composition()) for pv in perms) s = SymmetricFunctions(R).s() return s(QSexpr.to_symmetric_function()) @@ -2096,6 +2101,7 @@ def to_pair_of_standard_tableaux(self) -> tuple: ([[1, 2, 4, 7], [3, 5, 6]], [[1, 2, 4, 6], [3, 5, 7]]) """ from sage.combinat.tableau import Tableau + n = self.semilength() if n == 0: return (Tableau([]), Tableau([])) # type:ignore @@ -2250,6 +2256,7 @@ def to_321_avoiding_permutation(self) -> Permutation: True """ from sage.combinat.rsk import RSK_inverse + A, B = self.to_pair_of_standard_tableaux() return RSK_inverse(A, B, output='permutation') @@ -2410,7 +2417,7 @@ def to_noncrossing_partition(self, bijection=None): partition.append(stack[-nz:]) - stack = stack[: -nz] + stack = stack[:-nz] i = j p += 1 @@ -2462,7 +2469,7 @@ def to_Catalan_code(self) -> list: cut = self.associated_parenthesis(0) if cut is None: raise ValueError('not valid for incomplete Dyck words') - recdw = DyckWord(self[1:cut] + self[cut + 1:]) # type:ignore + recdw = DyckWord(self[1:cut] + self[cut + 1 :]) # type:ignore returns = [0] + recdw.returns_to_zero() res = recdw.to_Catalan_code() res.append(returns.index(cut - 1)) @@ -2497,6 +2504,7 @@ def to_ordered_tree(self): True """ from sage.combinat.ordered_tree import OrderedTree + levels = [OrderedTree().clone()] for u in self: if u == 1: @@ -2591,6 +2599,7 @@ def to_triangulation_as_graph(self): n = self.number_of_open_symbols() edges = self.to_triangulation() from sage.graphs.graph import Graph + peri = [(i, i + 1) for i in range(n + 1)] + [(n + 1, 0)] g = Graph(n + 2) g.add_edges(peri) @@ -2627,6 +2636,7 @@ def to_non_decreasing_parking_function(self): True """ from sage.combinat.non_decreasing_parking_function import NonDecreasingParkingFunction + return NonDecreasingParkingFunction.from_dyck_word(self) def major_index(self) -> int: @@ -2690,8 +2700,7 @@ def pyramid_weight(self) -> int: bpeak.append(i) out = 0 for i, apeaki in enumerate(apeak): - out += min(aseq[apeaki] - aseq[apeaki + 1] + 1, - bseq[bpeak[-i - 1]] - bseq[bpeak[-i - 1] + 1] + 1) + out += min(aseq[apeaki] - aseq[apeaki + 1] + 1, bseq[bpeak[-i - 1]] - bseq[bpeak[-i - 1] + 1] + 1) return out def tunnels(self) -> Iterator[tuple[int, int]]: @@ -2711,7 +2720,7 @@ def tunnels(self) -> Iterator[tuple[int, int]]: for i in range(len(heights) - 1): height = heights[i] if height < heights[i + 1]: - yield (i, i + 1 + heights[i + 1:].index(height)) + yield (i, i + 1 + heights[i + 1 :].index(height)) def number_of_tunnels(self, tunnel_type='centered') -> int: r""" @@ -2800,7 +2809,7 @@ def first_return_decomposition(self) -> tuple: ([], [1, 0]) """ k = self.position_of_first_return() * 2 - return DyckWord(self[1:k - 1]), DyckWord(self[k:]) # type:ignore + return DyckWord(self[1 : k - 1]), DyckWord(self[k:]) # type:ignore def decomposition_reverse(self) -> DyckWord: r""" @@ -3182,8 +3191,7 @@ def to_alternating_sign_matrix(self): """ parkfn = self.reverse().to_non_decreasing_parking_function() parkfn2 = [len(parkfn) + 1 - parkfn[i] for i in range(len(parkfn))] - monotone_triangle = [[0] * (len(parkfn2) - j) - for j in range(len(parkfn2))] + monotone_triangle = [[0] * (len(parkfn2) - j) for j in range(len(parkfn2))] for i in range(len(monotone_triangle)): for j in range(len(monotone_triangle[i])): monotone_triangle[i][j] = len(monotone_triangle[i]) - j @@ -3265,6 +3273,7 @@ class DyckWords(UniqueRepresentation, Parent): [1, 1, 0, 1, 0], [1, 1, 1, 0, 0]] """ + @staticmethod def __classcall_private__(cls, k1=None, k2=None, complete=True): """ @@ -3330,46 +3339,27 @@ class options(GlobalOptions): / \ sage: DyckWords.options._reset() """ + NAME = 'DyckWords' module = 'sage.combinat.dyck_word' - display = dict(default='list', - description='Specifies how Dyck words should be printed', - values=dict(list='displayed as a list', - lattice='displayed on the lattice defined by ``diagram_style``'), - case_sensitive=False) - ascii_art = dict(default='path', - description='Specifies how the ascii art of Dyck words should be printed', - values=dict(path="Using the path string", - pretty_output="Using pretty printing"), - alias=dict(pretty_print='pretty_output', path_string='path'), - case_sensitive=False) - diagram_style = dict(default='grid', - values=dict(grid='printing as paths on a grid using N and E steps', - line='printing as paths on a line using NE and SE steps',), + display = dict(default='list', description='Specifies how Dyck words should be printed', values=dict(list='displayed as a list', lattice='displayed on the lattice defined by ``diagram_style``'), case_sensitive=False) + ascii_art = dict(default='path', description='Specifies how the ascii art of Dyck words should be printed', values=dict(path="Using the path string", pretty_output="Using pretty printing"), alias=dict(pretty_print='pretty_output', path_string='path'), case_sensitive=False) + diagram_style = dict( + default='grid', + values=dict( + grid='printing as paths on a grid using N and E steps', + line='printing as paths on a line using NE and SE steps', + ), alias={'N-E': 'grid', 'NE-SE': 'line'}, - case_sensitive=False) - latex_tikz_scale = dict(default=1, - description='The default value for the tikz scale when latexed', - checker=lambda x: True) # More trouble than it's worth to check - latex_diagonal = dict(default=False, - description='The default value for displaying the diagonal when latexed', - checker=lambda x: isinstance(x, bool)) - latex_line_width_scalar = dict(default=2, - description='The default value for the line width as a ' - 'multiple of the tikz scale when latexed', - checker=lambda x: True) # More trouble than it's worth to check - latex_color = dict(default='black', - description='The default value for the color when latexed', - checker=lambda x: isinstance(x, str)) - latex_bounce_path = dict(default=False, - description='The default value for displaying the bounce path when latexed', - checker=lambda x: isinstance(x, bool)) - latex_peaks = dict(default=False, - description='The default value for displaying the peaks when latexed', - checker=lambda x: isinstance(x, bool)) - latex_valleys = dict(default=False, - description='The default value for displaying the valleys when latexed', - checker=lambda x: isinstance(x, bool)) + case_sensitive=False, + ) + latex_tikz_scale = dict(default=1, description='The default value for the tikz scale when latexed', checker=lambda x: True) # More trouble than it's worth to check + latex_diagonal = dict(default=False, description='The default value for displaying the diagonal when latexed', checker=lambda x: isinstance(x, bool)) + latex_line_width_scalar = dict(default=2, description='The default value for the line width as a ' 'multiple of the tikz scale when latexed', checker=lambda x: True) # More trouble than it's worth to check + latex_color = dict(default='black', description='The default value for the color when latexed', checker=lambda x: isinstance(x, str)) + latex_bounce_path = dict(default=False, description='The default value for displaying the bounce path when latexed', checker=lambda x: isinstance(x, bool)) + latex_peaks = dict(default=False, description='The default value for displaying the peaks when latexed', checker=lambda x: isinstance(x, bool)) + latex_valleys = dict(default=False, description='The default value for displaying the valleys when latexed', checker=lambda x: isinstance(x, bool)) def _element_constructor_(self, word): """ @@ -3778,6 +3768,7 @@ def cardinality(self) -> int: """ return (self.k1 - self.k2 + 1) * (self.k1 + self.k2).binomial(self.k2) // (self.k1 + 1) + ################################################################ # Complete Dyck words @@ -3786,6 +3777,7 @@ class CompleteDyckWords(DyckWords): """ Abstract base class for all complete Dyck words. """ + Element = DyckWord_complete def __contains__(self, x) -> bool: @@ -3848,7 +3840,7 @@ def from_Catalan_code(self, code) -> DyckWord: return self.element_class(self, []) res = self.from_Catalan_code(code[:-1]) cuts = [0] + res.returns_to_zero() - lst = [1] + res[:cuts[code[-1]]] + [0] + res[cuts[code[-1]]:] + lst = [1] + res[: cuts[code[-1]]] + [0] + res[cuts[code[-1]] :] return self.element_class(self, lst) def from_area_sequence(self, code) -> DyckWord: @@ -3878,9 +3870,7 @@ def from_area_sequence(self, code) -> DyckWord: [1, 0, 1, 0] """ if not is_area_sequence(code): - raise ValueError("the given sequence is not a sequence giving " - "the number of cells between the Dyck path " - "and the diagonal") + raise ValueError("the given sequence is not a sequence giving " "the number of cells between the Dyck path " "and the diagonal") dyck_word = [] for i in range(len(code)): if i: @@ -4137,6 +4127,7 @@ def random_element(self) -> DyckWord: True """ from sage.misc.prandom import shuffle + n = self.k1 w = [0] * n + [1] * (n + 1) shuffle(w) @@ -4222,8 +4213,7 @@ def is_area_sequence(seq) -> bool: """ if not seq: return True - return seq[0] == 0 and all(0 <= seq[i + 1] <= seq[i] + 1 - for i in range(len(seq) - 1)) + return seq[0] == 0 and all(0 <= seq[i + 1] <= seq[i] + 1 for i in range(len(seq) - 1)) def is_a(obj, k1=None, k2=None) -> bool: @@ -4340,4 +4330,5 @@ def pealing(D, return_touches=False): from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.combinat.dyck_word', 'DyckWord', DyckWord) diff --git a/src/sage/combinat/e_one_star.py b/src/sage/combinat/e_one_star.py index 3aa2d925368..26ec41af542 100644 --- a/src/sage/combinat/e_one_star.py +++ b/src/sage/combinat/e_one_star.py @@ -215,6 +215,7 @@ from sage.structure.sage_object import SageObject from sage.combinat.words.morphism import WordMorphism from sage.misc.lazy_import import lazy_import + lazy_import("sage.plot.all", "Graphics") lazy_import("sage.plot.colors", "Color") lazy_import("sage.plot.polygon", "polygon") @@ -287,7 +288,7 @@ def __init__(self, v, t, color=None): sage: f = Face((0,2,0), int(1)) """ - self._vector = (ZZ**len(v))(v) + self._vector = (ZZ ** len(v))(v) self._vector.set_immutable() if not ((t in ZZ) and 1 <= t <= len(v)): @@ -338,9 +339,7 @@ def _eq(self, other) -> bool: sage: f == g True """ - return (isinstance(other, Face) and - self.vector() == other.vector() and - self.type() == other.type()) + return isinstance(other, Face) and self.vector() == other.vector() and self.type() == other.type() def _lt(self, other) -> bool: r""" @@ -507,9 +506,7 @@ def _plot(self, projmat, face_contour, opacity) -> Graphics: G += line([v, v + vector([1, 0])], rgbcolor=self.color(), thickness=1.5, alpha=opacity) elif len(v) == 3: - G += polygon([projmat * (u + v) - for u in face_contour[t]], alpha=opacity, - thickness=1, rgbcolor=self.color()) + G += polygon([projmat * (u + v) for u in face_contour[t]], alpha=opacity, thickness=1, rgbcolor=self.color()) else: raise NotImplementedError("plotting is implemented only for patches in two or three dimensions.") @@ -617,14 +614,7 @@ def __init__(self, faces, face_contour=None): self._face_contour = face_contour else: - self._face_contour = { - 1: [vector(t) for t in [(0, 0, 0), (0, 1, 0), - (0, 1, 1), (0, 0, 1)]], - 2: [vector(t) for t in [(0, 0, 0), (0, 0, 1), - (1, 0, 1), (1, 0, 0)]], - 3: [vector(t) for t in [(0, 0, 0), (1, 0, 0), - (1, 1, 0), (0, 1, 0)]] - } + self._face_contour = {1: [vector(t) for t in [(0, 0, 0), (0, 1, 0), (0, 1, 1), (0, 0, 1)]], 2: [vector(t) for t in [(0, 0, 0), (0, 0, 1), (1, 0, 1), (1, 0, 0)]], 3: [vector(t) for t in [(0, 0, 0), (1, 0, 0), (1, 1, 0), (0, 1, 0)]]} def __eq__(self, other) -> bool: r""" @@ -656,7 +646,7 @@ def __eq__(self, other) -> bool: sage: E1Star(s*t)(P) == E1Star(t)(E1Star(s)(P)) True """ - return (isinstance(other, Patch) and self._faces == other._faces) + return isinstance(other, Patch) and self._faces == other._faces def __hash__(self) -> int: r""" @@ -1132,9 +1122,7 @@ def plot(self, projmat=None, opacity=0.75) -> Graphics: if self.dimension() == 3: if projmat is None: - projmat = matrix(2, [-1.7320508075688772 * 0.5, - 1.7320508075688772 * 0.5, - 0, -0.5, -0.5, 1]) + projmat = matrix(2, [-1.7320508075688772 * 0.5, 1.7320508075688772 * 0.5, 0, -0.5, -0.5, 1]) G = Graphics() for face in self: @@ -1174,8 +1162,7 @@ def plot3d(self): G = sum(face_list) return G - def plot_tikz(self, projmat=None, print_tikz_env=True, edgecolor='black', - scale=0.25, drawzero=False, extra_code_before='', extra_code_after='') -> str: + def plot_tikz(self, projmat=None, print_tikz_env=True, edgecolor='black', scale=0.25, drawzero=False, extra_code_before='', extra_code_after='') -> str: r""" Return a string containing some TikZ code to be included into a LaTeX document, depicting the patch. @@ -1293,9 +1280,7 @@ def plot_tikz(self, projmat=None, print_tikz_env=True, edgecolor='black', raise NotImplementedError("Tikz plotting is implemented only for patches in three dimensions") if projmat is None: - projmat = matrix(2, [-1.7320508075688772 * 0.5, - 1.7320508075688772 * 0.5, - 0, -0.5, -0.5, 1]) * scale + projmat = matrix(2, [-1.7320508075688772 * 0.5, 1.7320508075688772 * 0.5, 0, -0.5, -0.5, 1]) * scale e1 = projmat * vector([1, 0, 0]) e2 = projmat * vector([0, 1, 0]) @@ -1420,7 +1405,7 @@ def __init__(self, sigma, method='suffix'): subst_im = self._sigma.image(k) for n, letter in enumerate(subst_im): if method == 'suffix': - image_word = subst_im[n + 1:] + image_word = subst_im[n + 1 :] elif method == 'prefix': image_word = subst_im[:n] else: @@ -1452,7 +1437,7 @@ def __eq__(self, other) -> bool: sage: S == S2 False """ - return (isinstance(other, E1Star) and self._base_iter == other._base_iter) + return isinstance(other, E1Star) and self._base_iter == other._base_iter def __call__(self, patch, iterations=1) -> Patch: r""" diff --git a/src/sage/combinat/family.py b/src/sage/combinat/family.py index a7b2c592b3e..044e101c8ac 100644 --- a/src/sage/combinat/family.py +++ b/src/sage/combinat/family.py @@ -6,5 +6,4 @@ # Backward compatibility pointer # Needed for unpickling. -from sage.sets.family import (Family, FiniteFamily, LazyFamily, - FiniteFamilyWithHiddenKeys) +from sage.sets.family import Family, FiniteFamily, LazyFamily, FiniteFamilyWithHiddenKeys diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 4c4935909e3..67808fb0f24 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -933,6 +933,7 @@ from IPython.lib.pretty import pretty import itertools from collections import defaultdict, deque, namedtuple, OrderedDict + # Use isinstance(x, Iterable) to test whether x is iterable, and # use isinstance(x, Mapping) to test whether x is a dict. from collections.abc import Iterator, Iterable, Mapping @@ -1013,8 +1014,7 @@ def full_group_by(l, key=None): s = str(k) if s in original_keys: if original_keys[s] != k: - raise ValueError( - 'two distinct elements with representation {}'.format(s)) + raise ValueError('two distinct elements with representation {}'.format(s)) else: original_keys[s] = k elements[s].append(item) @@ -1087,7 +1087,8 @@ def startswith(list_, prefix): """ if len(prefix) > len(list_): return False - return list_[:len(prefix)] == prefix + return list_[: len(prefix)] == prefix + # **************************************************************************** @@ -1095,10 +1096,7 @@ def startswith(list_, prefix): FSMEmptyWordSymbol = '-' EmptyWordLaTeX = r'\varepsilon' EndOfWordLaTeX = r'\$' -tikz_automata_where = {"right": 0, - "above": 90, - "left": 180, - "below": 270} +tikz_automata_where = {"right": 0, "above": 90, "left": 180, "below": 270} def FSMLetterSymbol(letter): @@ -1319,14 +1317,12 @@ class FSMState(SageObject): sage: S.initial_probability 1/3 """ + is_initial = False # Describes whether the state is initial initial_probability = None # The probability of starting in this state if it is part of a Markov chain - def __init__(self, label, word_out=None, - is_initial=False, is_final=False, final_word_out=None, - initial_probability=None, - hook=None, color=None, allow_label_None=False): + def __init__(self, label, word_out=None, is_initial=False, is_final=False, final_word_out=None, initial_probability=None, hook=None, color=None, allow_label_None=False): """ See :class:`FSMState` for more information. @@ -1380,8 +1376,7 @@ def __init__(self, label, word_out=None, but state A is not final. """ if not allow_label_None and label is None: - raise ValueError("Label None reserved for a special state, " - "choose another label.") + raise ValueError("Label None reserved for a special state, " "choose another label.") self._label_ = label if isinstance(word_out, list): @@ -1505,9 +1500,7 @@ def final_word_out(self, final_word_out): """ if not self.is_final: if final_word_out is not None: - raise ValueError("Only final states can have a " - "final output word, but state %s is not final." - % (self.label(),)) + raise ValueError("Only final states can have a " "final output word, but state %s is not final." % (self.label(),)) else: self._final_word_out_ = None elif isinstance(final_word_out, list): @@ -1603,10 +1596,7 @@ def is_final(self, is_final): if not self.final_word_out: self._final_word_out_ = None else: - raise ValueError("State %s cannot be non-final, because it " - "has a final output word. Only final states " - "can have a final output word. " - % (self.label(),)) + raise ValueError("State %s cannot be non-final, because it " "has a final output word. Only final states " "can have a final output word. " % (self.label(),)) def label(self): """ @@ -1652,11 +1642,7 @@ def __copy__(self): sage: A.initial_probability is B.initial_probability True """ - new = FSMState(self.label(), self.word_out, - self.is_initial, self.is_final, - color=self.color, - final_word_out=self.final_word_out, - initial_probability=self.initial_probability) + new = FSMState(self.label(), self.word_out, self.is_initial, self.is_final, color=self.color, final_word_out=self.final_word_out, initial_probability=self.initial_probability) if hasattr(self, 'hook'): new.hook = self.hook return new @@ -1684,8 +1670,7 @@ def __deepcopy__(self, memo): label = self._deepcopy_relabel_ except AttributeError: label = deepcopy(self.label(), memo) - new = FSMState(label, deepcopy(self.word_out, memo), - self.is_initial, self.is_final) + new = FSMState(label, deepcopy(self.word_out, memo), self.is_initial, self.is_final) if hasattr(self, 'hook'): new.hook = deepcopy(self.hook, memo) new.color = deepcopy(self.color, memo) @@ -1797,7 +1782,7 @@ def __getstate__(self): try: del odict['transitions'] # remove transitions entry except KeyError: - pass # Standalone FSMState has no transitions + pass # Standalone FSMState has no transitions return odict def __hash__(self): @@ -1920,13 +1905,7 @@ def fully_equal(self, other, compare_color=True): True """ color = not compare_color or self.color == other.color - return (self == other and - self.is_initial == other.is_initial and - self.is_final == other.is_final and - self.final_word_out == other.final_word_out and - self.word_out == other.word_out and - color and - self.initial_probability == other.initial_probability) + return self == other and self.is_initial == other.is_initial and self.is_final == other.is_final and self.final_word_out == other.final_word_out and self.word_out == other.word_out and color and self.initial_probability == other.initial_probability def __bool__(self): """ @@ -1988,11 +1967,9 @@ def _epsilon_successors_(self, fsm=None): {0: [['a', 'b', 'c']], 1: [['a']], 2: [['a', 'b']]} """ if not hasattr(self, 'transitions'): - raise ValueError('State %s does not belong to a ' - 'finite state machine.' % (self,)) + raise ValueError('State %s does not belong to a ' 'finite state machine.' % (self,)) - it = _FSMProcessIteratorEpsilon_(fsm, input_tape=[], - initial_state=self) + it = _FSMProcessIteratorEpsilon_(fsm, input_tape=[], initial_state=self) # TODO: optimize the following lines (use already calculated # epsilon successors) for _ in it: @@ -2002,8 +1979,7 @@ def _epsilon_successors_(self, fsm=None): if not _epsilon_successors_dict_[self]: del _epsilon_successors_dict_[self] for s, outputs in _epsilon_successors_dict_.items(): - _epsilon_successors_dict_[s] = [t for t, _ in - itertools.groupby(sorted(outputs))] + _epsilon_successors_dict_[s] = [t for t, _ in itertools.groupby(sorted(outputs))] return _epsilon_successors_dict_ def _in_epsilon_cycle_(self, fsm=None): @@ -2140,9 +2116,7 @@ class FSMTransition(SageObject): word_out = None """Output word of the transition. Read-only.""" - def __init__(self, from_state, to_state, - word_in=None, word_out=None, - hook=None): + def __init__(self, from_state, to_state, word_in=None, word_out=None, hook=None): """ See :class:`FSMTransition` for more information. @@ -2198,8 +2172,7 @@ def __lt__(self, other): sage: FSMTransition(0,1,0,0) < FSMTransition(1,0,0,0) True """ - return (self.from_state, self.word_in, self.to_state, self.word_out) < \ - (other.from_state, other.word_in, other.to_state, other.word_out) + return (self.from_state, self.word_in, self.to_state, self.word_out) < (other.from_state, other.word_in, other.to_state, other.word_out) def __copy__(self): """ @@ -2214,8 +2187,7 @@ def __copy__(self): sage: copy(t) Transition from 'A' to 'B': 0|- """ - new = FSMTransition(self.from_state, self.to_state, - self.word_in, self.word_out) + new = FSMTransition(self.from_state, self.to_state, self.word_in, self.word_out) if hasattr(self, 'hook'): new.hook = self.hook return new @@ -2239,10 +2211,7 @@ def __deepcopy__(self, memo): sage: deepcopy(t) Transition from 'A' to 'B': 0|- """ - new = FSMTransition(deepcopy(self.from_state, memo), - deepcopy(self.to_state, memo), - deepcopy(self.word_in, memo), - deepcopy(self.word_out, memo)) + new = FSMTransition(deepcopy(self.from_state, memo), deepcopy(self.to_state, memo), deepcopy(self.word_in, memo), deepcopy(self.word_out, memo)) if hasattr(self, 'hook'): new.hook = deepcopy(self.hook, memo) return new @@ -2282,9 +2251,7 @@ def _repr_(self): sage: FSMTransition('A', 'B', 0, 0)._repr_() "Transition from 'A' to 'B': 0|0" """ - return "Transition from %s to %s: %s" % (repr(self.from_state), - repr(self.to_state), - self._in_out_label_()) + return "Transition from %s to %s: %s" % (repr(self.from_state), repr(self.to_state), self._in_out_label_()) def _in_out_label_(self): """ @@ -2298,8 +2265,7 @@ def _in_out_label_(self): sage: FSMTransition('A', 'B', 0, 1)._in_out_label_() '0|1' """ - return "%s|%s" % (FSMWordSymbol(self.word_in), - FSMWordSymbol(self.word_out)) + return "%s|%s" % (FSMWordSymbol(self.word_in), FSMWordSymbol(self.word_out)) def __eq__(self, other): """ @@ -2328,10 +2294,7 @@ def __eq__(self, other): """ if not isinstance(other, FSMTransition): return False - return self.from_state == other.from_state \ - and self.to_state == other.to_state \ - and self.word_in == other.word_in \ - and self.word_out == other.word_out + return self.from_state == other.from_state and self.to_state == other.to_state and self.word_in == other.word_in and self.word_out == other.word_out def __ne__(self, other): """ @@ -2474,16 +2437,10 @@ def duplicate_transition_add_input(old_transition, new_transition): "Transition from 'a' to 'a': 1,1|-", but input words are assumed to be lists of length 1 """ - if (isinstance(old_transition.word_in, Iterable) - and len(old_transition.word_in) == 1 - and isinstance(new_transition.word_in, Iterable) - and len(new_transition.word_in) == 1): - old_transition.word_in = [old_transition.word_in[0] - + new_transition.word_in[0]] + if isinstance(old_transition.word_in, Iterable) and len(old_transition.word_in) == 1 and isinstance(new_transition.word_in, Iterable) and len(new_transition.word_in) == 1: + old_transition.word_in = [old_transition.word_in[0] + new_transition.word_in[0]] else: - raise TypeError('Trying to use duplicate_transition_add_input on ' + - '"%s" and "%s", ' % (old_transition, new_transition) + - 'but input words are assumed to be lists of length 1') + raise TypeError('Trying to use duplicate_transition_add_input on ' + '"%s" and "%s", ' % (old_transition, new_transition) + 'but input words are assumed to be lists of length 1') return old_transition @@ -2932,14 +2889,7 @@ class FiniteStateMachine(SageObject): # init # ************************************************************************ - def __init__(self, - data=None, - initial_states=None, final_states=None, - input_alphabet=None, output_alphabet=None, - determine_alphabets=None, - with_final_word_out=None, - store_states_dict=True, - on_duplicate_transition=None): + def __init__(self, data=None, initial_states=None, final_states=None, input_alphabet=None, output_alphabet=None, determine_alphabets=None, with_final_word_out=None, store_states_dict=True, on_duplicate_transition=None): """ See :class:`FiniteStateMachine` for more information. @@ -2959,49 +2909,33 @@ def __init__(self, if isinstance(data, FiniteStateMachine): if initial_states is not None: - raise ValueError( - "initial_states cannot be specified when copying " - "another finite state machine.") + raise ValueError("initial_states cannot be specified when copying " "another finite state machine.") if final_states is not None: - raise ValueError( - "final_states cannot be specified when copying " - "another finite state machine.") + raise ValueError("final_states cannot be specified when copying " "another finite state machine.") if input_alphabet is not None: - raise ValueError( - "input_alphabet cannot be specified when copying " - "another finite state machine.") + raise ValueError("input_alphabet cannot be specified when copying " "another finite state machine.") if output_alphabet is not None: - raise ValueError( - "output_alphabet cannot be specified when copying " - "another finite state machine.") + raise ValueError("output_alphabet cannot be specified when copying " "another finite state machine.") if on_duplicate_transition is not None: - raise ValueError( - "on_duplicate_transition cannot be specified when " - "copying another finite state machine.") + raise ValueError("on_duplicate_transition cannot be specified when " "copying another finite state machine.") if determine_alphabets is not None: - raise ValueError( - "determine_alphabets cannot be specified when " - "copying another finite state machine.") + raise ValueError("determine_alphabets cannot be specified when " "copying another finite state machine.") if with_final_word_out is not None: - raise ValueError( - "with_final_word_out cannot be specified when " - "copying another finite state machine.") + raise ValueError("with_final_word_out cannot be specified when " "copying another finite state machine.") self._copy_from_other_(data) return if initial_states is not None: if not isinstance(initial_states, Iterable): - raise TypeError('Initial states must be iterable ' - '(e.g. a list of states).') + raise TypeError('Initial states must be iterable ' '(e.g. a list of states).') for s in initial_states: state = self.add_state(s) state.is_initial = True if final_states is not None: if not isinstance(final_states, Iterable): - raise TypeError('Final states must be iterable ' - '(e.g. a list of states).') + raise TypeError('Final states must be iterable ' '(e.g. a list of states).') for s in final_states: state = self.add_state(s) state.is_final = True @@ -3021,10 +2955,10 @@ def __init__(self, elif isinstance(data, Mapping): # data is a dict (or something similar), # format: key = from_state, value = iterator of transitions - for (sf, iter_transitions) in data.items(): + for sf, iter_transitions in data.items(): self.add_state(sf) if isinstance(iter_transitions, Mapping): - for (st, transition) in iter_transitions.items(): + for st, transition in iter_transitions.items(): self.add_state(st) if isinstance(transition, FSMTransition): self.add_transition(transition) @@ -3225,14 +3159,11 @@ def _copy_from_other_(self, other, memo=None, empty=False): if other._deepcopy_labels_ is None: state._deepcopy_relabel_ = next(relabel_iter) elif callable(other._deepcopy_labels_): - state._deepcopy_relabel_ = \ - other._deepcopy_labels_(state.label()) + state._deepcopy_relabel_ = other._deepcopy_labels_(state.label()) elif hasattr(other._deepcopy_labels_, '__getitem__'): - state._deepcopy_relabel_ = \ - other._deepcopy_labels_[state.label()] + state._deepcopy_relabel_ = other._deepcopy_labels_[state.label()] else: - raise TypeError("labels must be None, a callable " - "or a dictionary.") + raise TypeError("labels must be None, a callable " "or a dictionary.") s = deepcopy(state, memo) if relabel: del state._deepcopy_relabel_ @@ -3405,8 +3336,7 @@ def __hash__(self): """ if getattr(self, "_immutable", False): return hash((tuple(self.states()), tuple(self.transitions()))) - raise TypeError("Finite state machines are mutable, " - "and thus not hashable.") + raise TypeError("Finite state machines are mutable, " "and thus not hashable.") # ************************************************************************ # operators @@ -3980,6 +3910,7 @@ def is_Markov_chain(self, is_zero=None): sage: F.is_Markov_chain(is_zero_polynomial) # needs sage.libs.singular True """ + def default_is_zero(expression): return expression.is_zero() @@ -3990,17 +3921,13 @@ def default_is_zero(expression): if self.on_duplicate_transition != duplicate_transition_add_input: return False - if any(s.initial_probability is not None for s in self.iter_states()) and \ - any(s.initial_probability is None for s in self.iter_states()): + if any(s.initial_probability is not None for s in self.iter_states()) and any(s.initial_probability is None for s in self.iter_states()): return False - if any(s.initial_probability is not None for s in self.iter_states()) and \ - not is_zero_function(sum(s.initial_probability for s - in self.iter_states()) - 1): + if any(s.initial_probability is not None for s in self.iter_states()) and not is_zero_function(sum(s.initial_probability for s in self.iter_states()) - 1): return False - return all(is_zero_function(sum(t.word_in[0] for t in state.transitions) - 1) - for state in self.iter_states()) + return all(is_zero_function(sum(t.word_in[0] for t in state.transitions) - 1) for state in self.iter_states()) # ************************************************************************ # representations / LaTeX @@ -4202,17 +4129,7 @@ def default_format_transition_label(self, word): format_transition_label = default_format_transition_label - def latex_options(self, - coordinates=None, - format_state_label=None, - format_letter=None, - format_transition_label=None, - loop_where=None, - initial_where=None, - accepting_style=None, - accepting_distance=None, - accepting_where=None, - accepting_show_empty=None): + def latex_options(self, coordinates=None, format_state_label=None, format_letter=None, format_transition_label=None, loop_where=None, initial_where=None, accepting_style=None, accepting_distance=None, accepting_where=None, accepting_show_empty=None): r""" Set options for LaTeX output via :func:`~sage.misc.latex.latex` and therefore @@ -4490,15 +4407,13 @@ def latex_options(self, try: where = loop_where[state.label()] except TypeError: - raise TypeError("loop_where must be a " - "callable or a dictionary.") + raise TypeError("loop_where must be a " "callable or a dictionary.") except KeyError: continue if where in permissible: state.loop_where = where else: - raise ValueError('loop_where for %s must be in %s.' % - (state.label(), sorted(permissible))) + raise ValueError('loop_where for %s must be in %s.' % (state.label(), sorted(permissible))) if initial_where is not None: permissible = list(tikz_automata_where) @@ -4509,24 +4424,20 @@ def latex_options(self, try: where = initial_where[state.label()] except TypeError: - raise TypeError("initial_where must be a " - "callable or a dictionary.") + raise TypeError("initial_where must be a " "callable or a dictionary.") except KeyError: continue if where in permissible: state.initial_where = where else: - raise ValueError('initial_where for %s must be in %s.' % - (state.label(), sorted(permissible))) + raise ValueError('initial_where for %s must be in %s.' % (state.label(), sorted(permissible))) if accepting_style is not None: - permissible = ['accepting by double', - 'accepting by arrow'] + permissible = ['accepting by double', 'accepting by arrow'] if accepting_style in permissible: self.accepting_style = accepting_style else: - raise ValueError('accepting_style must be in %s.' % - sorted(permissible)) + raise ValueError('accepting_style must be in %s.' % sorted(permissible)) if accepting_distance is not None: self.accepting_distance = accepting_distance @@ -4540,24 +4451,19 @@ def latex_options(self, try: where = accepting_where[state.label()] except TypeError: - raise TypeError("accepting_where must be a " - "callable or a dictionary.") + raise TypeError("accepting_where must be a " "callable or a dictionary.") except KeyError: continue if where in permissible: state.accepting_where = where - elif hasattr(state, 'final_word_out') \ - and state.final_word_out: + elif hasattr(state, 'final_word_out') and state.final_word_out: if where in RR: state.accepting_where = where else: - raise ValueError('accepting_where for %s must ' - 'be a real number or be in %s.' % - (state.label(), sorted(permissible))) + raise ValueError('accepting_where for %s must ' 'be a real number or be in %s.' % (state.label(), sorted(permissible))) else: - raise ValueError('accepting_where for %s must be in %s.' % - (state.label(), sorted(permissible))) + raise ValueError('accepting_where for %s must be in %s.' % (state.label(), sorted(permissible))) if accepting_show_empty is not None: self.accepting_show_empty = accepting_show_empty @@ -4649,8 +4555,7 @@ def label_rotation(angle, both_directions): else: accepting_distance = None if accepting_style == "accepting by arrow" and accepting_distance: - options.append("accepting distance=%s" - % accepting_distance) + options.append("accepting distance=%s" % accepting_distance) if hasattr(self, "accepting_show_empty"): accepting_show_empty = self.accepting_show_empty @@ -4660,19 +4565,15 @@ def label_rotation(angle, both_directions): result = "\\begin{tikzpicture}[%s]\n" % ", ".join(options) for j, vertex in enumerate(self.iter_states()): if not hasattr(vertex, "coordinates"): - vertex.coordinates = (3*cos(2*pi*j/len(self.states())), - 3*sin(2*pi*j/len(self.states()))) + vertex.coordinates = (3 * cos(2 * pi * j / len(self.states())), 3 * sin(2 * pi * j / len(self.states()))) options = "" if vertex.is_final: - if not (vertex.final_word_out - and accepting_style == "accepting by arrow") \ - and not accepting_show_empty: + if not (vertex.final_word_out and accepting_style == "accepting by arrow") and not accepting_show_empty: # otherwise, we draw a custom made accepting path # with label below options += ", accepting" if hasattr(vertex, "accepting_where"): - options += ", accepting where=%s" % ( - vertex.accepting_where,) + options += ", accepting where=%s" % (vertex.accepting_where,) if vertex.is_initial: options += ", initial" if hasattr(vertex, "initial_where"): @@ -4683,53 +4584,36 @@ def label_rotation(angle, both_directions): label = self.format_state_label(vertex) else: label = latex(vertex.label()) - result += "\\node[state%s] (v%d) at (%f, %f) {$%s$};\n" % ( - options, j, vertex.coordinates[0], - vertex.coordinates[1], label) + result += "\\node[state%s] (v%d) at (%f, %f) {$%s$};\n" % (options, j, vertex.coordinates[0], vertex.coordinates[1], label) vertex._number_ = j if vertex.is_final and (vertex.final_word_out or accepting_show_empty): angle = 0 if hasattr(vertex, "accepting_where"): - angle = tikz_automata_where.get(vertex.accepting_where, - vertex.accepting_where) - result += "\\path[->] (v%d.%.2f) edge node[%s] {$%s \\mid %s$} ++(%.2f:%s);\n" % ( - j, angle, - label_rotation(angle, False), - EndOfWordLaTeX, - self.format_transition_label(vertex.final_word_out), - angle, accepting_distance) + angle = tikz_automata_where.get(vertex.accepting_where, vertex.accepting_where) + result += "\\path[->] (v%d.%.2f) edge node[%s] {$%s \\mid %s$} ++(%.2f:%s);\n" % (j, angle, label_rotation(angle, False), EndOfWordLaTeX, self.format_transition_label(vertex.final_word_out), angle, accepting_distance) def key_function(s): return (s.from_state, s.to_state) + # We use an OrderedDict instead of a dict in order to have a # defined ordering of the transitions in the output. See # https://github.com/sagemath/sage/issues/16580#comment:3 . As the # transitions have to be sorted anyway, the performance # penalty should be bearable; nevertheless, this is only # required for doctests. - adjacent = OrderedDict( - (pair, list(transitions)) - for pair, transitions in - itertools.groupby( - sorted(self.iter_transitions(), - key=key_function), - key=key_function - )) - - for ((source, target), transitions) in adjacent.items(): + adjacent = OrderedDict((pair, list(transitions)) for pair, transitions in itertools.groupby(sorted(self.iter_transitions(), key=key_function), key=key_function)) + + for (source, target), transitions in adjacent.items(): if transitions: labels = [] for transition in transitions: if hasattr(transition, "format_label"): labels.append(transition.format_label()) else: - labels.append(self._latex_transition_label_( - transition, self.format_transition_label)) + labels.append(self._latex_transition_label_(transition, self.format_transition_label)) label = ", ".join(labels) if source != target: - angle = atan2( - target.coordinates[1] - source.coordinates[1], - target.coordinates[0] - source.coordinates[0]) * 180/pi + angle = atan2(target.coordinates[1] - source.coordinates[1], target.coordinates[0] - source.coordinates[0]) * 180 / pi both_directions = (target, source) in adjacent if both_directions: angle_source = ".%.2f" % (angle + 5) @@ -4737,27 +4621,18 @@ def key_function(s): else: angle_source = "" angle_target = "" - result += "\\path[->] (v%d%s) edge node[%s] {$%s$} (v%d%s);\n" % ( - source._number_, angle_source, - label_rotation(angle, both_directions), - label, - target._number_, angle_target) + result += "\\path[->] (v%d%s) edge node[%s] {$%s$} (v%d%s);\n" % (source._number_, angle_source, label_rotation(angle, both_directions), label, target._number_, angle_target) else: loop_where = "above" if hasattr(source, "loop_where"): loop_where = source.loop_where - rotation = {'left': '[rotate=90, anchor=south]', - 'right': '[rotate=90, anchor=north]'} - result += "\\path[->] (v%d) edge[loop %s] node%s {$%s$} ();\n" % ( - source._number_, - loop_where, rotation.get(loop_where, ''), - label) + rotation = {'left': '[rotate=90, anchor=south]', 'right': '[rotate=90, anchor=north]'} + result += "\\path[->] (v%d) edge[loop %s] node%s {$%s$} ();\n" % (source._number_, loop_where, rotation.get(loop_where, ''), label) result += "\\end{tikzpicture}" return result - def _latex_transition_label_(self, transition, - format_function=None): + def _latex_transition_label_(self, transition, format_function=None): r""" Return the proper transition label. @@ -4829,8 +4704,7 @@ def set_coordinates(self, coordinates, default=True): if default: n = len(states_without_coordinates) for j, state in enumerate(states_without_coordinates): - state.coordinates = (3*cos(2*pi*j/n), - 3*sin(2*pi*j/n)) + state.coordinates = (3 * cos(2 * pi * j / n), 3 * sin(2 * pi * j / n)) # ************************************************************************ # other @@ -4859,8 +4733,7 @@ def _matrix_(self, R=None): """ return self.adjacency_matrix() - def adjacency_matrix(self, input=None, - entry=None): + def adjacency_matrix(self, input=None, entry=None): """ Return the adjacency matrix of the underlying graph. @@ -4937,34 +4810,28 @@ def adjacency_matrix(self, input=None, if entry is None: from sage.symbolic.ring import SR + x = SR.var('x') def default_function(transition): - return x**sum(transition.word_out) + return x ** sum(transition.word_out) entry = default_function relabeledFSM = self l = len(relabeledFSM.states()) for state in self.iter_states(): - if state.label() not in ZZ or state.label() >= l \ - or state.label() < 0: + if state.label() not in ZZ or state.label() >= l or state.label() < 0: relabeledFSM = self.relabeled() break dictionary = {} for transition in relabeledFSM.iter_transitions(): if input is None or transition.word_in == [input]: - if (transition.from_state.label(), - transition.to_state.label()) in dictionary: - dictionary[(transition.from_state.label(), - transition.to_state.label())] \ - += entry(transition) + if (transition.from_state.label(), transition.to_state.label()) in dictionary: + dictionary[(transition.from_state.label(), transition.to_state.label())] += entry(transition) else: - dictionary[(transition.from_state.label(), - transition.to_state.label())] \ - = entry(transition) - return matrix( - len(relabeledFSM.states()), dictionary) + dictionary[(transition.from_state.label(), transition.to_state.label())] = entry(transition) + return matrix(len(relabeledFSM.states()), dictionary) def determine_input_alphabet(self, reset=True): """ @@ -5293,10 +5160,12 @@ def state(self, state): ... LookupError: No state with label xyz found. """ + def what(s, switch): if switch: return s.label() return s + switch = isinstance(state, FSMState) try: @@ -5511,9 +5380,7 @@ def is_deterministic(self): if len(transition.word_in) != 1: return False - transition_classes_by_word_in = full_group_by( - state.transitions, - key=lambda t: t.word_in) + transition_classes_by_word_in = full_group_by(state.transitions, key=lambda t: t.word_in) for _, transition_class in transition_classes_by_word_in: if len(transition_class) > 1: @@ -5555,25 +5422,21 @@ def is_complete(self): False """ if self.input_alphabet is None: - raise ValueError("No input alphabet is given. " - "Try calling determine_alphabets().") + raise ValueError("No input alphabet is given. " "Try calling determine_alphabets().") for state in self.iter_states(): for transition in state.transitions: if len(transition.word_in) != 1: return False - transition_classes_by_word_in = full_group_by( - state.transitions, - key=lambda t: t.word_in) + transition_classes_by_word_in = full_group_by(state.transitions, key=lambda t: t.word_in) for key, transition_class in transition_classes_by_word_in: if len(transition_class) > 1: return False # all input labels are lists, extract the only element - outgoing_alphabet = [key[0] for key, transition_class in - transition_classes_by_word_in] + outgoing_alphabet = [key[0] for key, transition_class in transition_classes_by_word_in] if not sorted(self.input_alphabet) == sorted(outgoing_alphabet): return False @@ -5594,11 +5457,7 @@ def is_connected(self): # let the finite state machine work # ************************************************************************ - _process_default_options_ = {'full_output': True, - 'list_of_outputs': None, - 'only_accepted': False, - 'always_include_output': False, - 'automatic_output_type': False} + _process_default_options_ = {'full_output': True, 'list_of_outputs': None, 'only_accepted': False, 'always_include_output': False, 'automatic_output_type': False} def process(self, *args, **kwargs): """ @@ -5912,25 +5771,18 @@ class is created and is used during the processing. # process output: filtering accepting results only_accepted = options['only_accepted'] - it_output = [result for result in it.result() - if not only_accepted or result[0]] + it_output = [result for result in it.result() if not only_accepted or result[0]] # process output: returning a list output - if (len(it_output) > 1 and options['list_of_outputs'] is None or - options['list_of_outputs']): - return [self._process_convert_output_(out, **options) - for out in sorted(it_output)] + if len(it_output) > 1 and options['list_of_outputs'] is None or options['list_of_outputs']: + return [self._process_convert_output_(out, **options) for out in sorted(it_output)] # process output: cannot return output to due input parameters if options['list_of_outputs'] is False: if not it_output and only_accepted: - raise ValueError('No accepting output was found but according ' - 'to the given options, an accepting output ' - 'should be returned. Change only_accepted ' - 'and/or list_of_outputs options.') + raise ValueError('No accepting output was found but according ' 'to the given options, an accepting output ' 'should be returned. Change only_accepted ' 'and/or list_of_outputs options.') elif len(it_output) > 1: - raise ValueError('Got more than one output, but only allowed ' - 'to show one. Change list_of_outputs option.') + raise ValueError('Got more than one output, but only allowed ' 'to show one. Change list_of_outputs option.') # At this point it_output has length 0 or 1. # process output: create non-accepting output if needed @@ -5972,10 +5824,7 @@ def _process_convert_output_(self, output_data, **kwargs): accept_input, current_state, output = output_data return (accept_input, current_state, output) - def iter_process(self, input_tape=None, initial_state=None, - process_iterator_class=None, - iterator_type=None, - automatic_output_type=False, **kwargs): + def iter_process(self, input_tape=None, initial_state=None, process_iterator_class=None, iterator_type=None, automatic_output_type=False, **kwargs): r""" This function returns an iterator for processing the input. See :meth:`.process` (which runs this iterator until the end) @@ -6108,8 +5957,7 @@ def iter_process(self, input_tape=None, initial_state=None, :class:`FSMProcessIterator`. """ if automatic_output_type and 'format_output' in kwargs: - raise ValueError("Parameter 'automatic_output_type' set, but " - "'format_output' specified as well.") + raise ValueError("Parameter 'automatic_output_type' set, but " "'format_output' specified as well.") if automatic_output_type: try: kwargs['format_output'] = input_tape.parent() @@ -6118,10 +5966,7 @@ def iter_process(self, input_tape=None, initial_state=None, if process_iterator_class is None: process_iterator_class = FSMProcessIterator - it = process_iterator_class(self, - input_tape=input_tape, - initial_state=initial_state, - **kwargs) + it = process_iterator_class(self, input_tape=input_tape, initial_state=initial_state, **kwargs) if iterator_type is None: return it if iterator_type == 'simple': @@ -6193,25 +6038,13 @@ def _iter_process_simple_(self, iterator): return if len(current) > 1: - raise RuntimeError("Process has branched " - "(%s branches exist). The " - "'simple' iterator cannot be used " - "here." % - (len(current),)) + raise RuntimeError("Process has branched " "(%s branches exist). The " "'simple' iterator cannot be used " "here." % (len(current),)) _, states = next(iter(current.items())) if len(states) > 1: - raise RuntimeError("Process has branched " - "(visiting %s states in branch). The " - "'simple' iterator cannot be used " - "here." % - (len(states),)) + raise RuntimeError("Process has branched " "(visiting %s states in branch). The " "'simple' iterator cannot be used " "here." % (len(states),)) _, branch = next(iter(states.items())) if len(branch.outputs) > 1: - raise RuntimeError("Process has branched. " - "(%s different outputs in branch). The " - "'simple' iterator cannot be used " - "here." % - (len(branch.outputs),)) + raise RuntimeError("Process has branched. " "(%s different outputs in branch). The " "'simple' iterator cannot be used " "here." % (len(branch.outputs),)) yield from branch.outputs[0] branch.outputs[0] = [] @@ -6361,9 +6194,7 @@ def add_transition(self, *args, **kwargs): else: raise TypeError("Cannot decide what to do with input.") - data = dict(zip( - ('from_state', 'to_state', 'word_in', 'word_out', 'hook'), - args)) + data = dict(zip(('from_state', 'to_state', 'word_in', 'word_out', 'hook'), args)) data.update(kwargs) data['from_state'] = self.add_state(data['from_state']) @@ -6399,8 +6230,7 @@ def _add_fsm_transition_(self, t): from_state.transitions.append(t) return t - def add_from_transition_function(self, function, initial_states=None, - explore_existing_states=True): + def add_from_transition_function(self, function, initial_states=None, explore_existing_states=True): """ Construct a finite state machine from a transition function. @@ -6493,8 +6323,7 @@ def add_from_transition_function(self, function, initial_states=None, TypeError: ...mutable vectors are unhashable... """ if self.input_alphabet is None: - raise ValueError("No input alphabet is given. " - "Try calling determine_alphabets().") + raise ValueError("No input alphabet is given. " "Try calling determine_alphabets().") if initial_states is None: not_done = self.initial_states() @@ -6505,8 +6334,7 @@ def add_from_transition_function(self, function, initial_states=None, state.is_initial = True not_done.append(state) else: - raise TypeError('Initial states must be iterable ' - '(e.g. a list of states).') + raise TypeError('Initial states must be iterable ' '(e.g. a list of states).') if not not_done: raise ValueError("No state is initial.") if explore_existing_states: @@ -6528,18 +6356,11 @@ def add_from_transition_function(self, function, initial_states=None, if not hasattr(return_value, "pop"): return_value = [return_value] try: - for (st_label, word) in return_value: + for st_label, word in return_value: pass except TypeError: - raise ValueError("The callback function for " - "add_from_transition is expected " - "to return a pair (new_state, " - "output_label) or a list of such pairs. " - "For the state %s and the input " - "letter %s, it however returned %s, " - "which is not acceptable." - % (s.label(), letter, return_value)) - for (st_label, word) in return_value: + raise ValueError("The callback function for " "add_from_transition is expected " "to return a pair (new_state, " "output_label) or a list of such pairs. " "For the state %s and the input " "letter %s, it however returned %s, " "which is not acceptable." % (s.label(), letter, return_value)) + for st_label, word in return_value: if not self.has_state(st_label): not_done.append(self.add_state(st_label)) elif ignore_done: @@ -6547,8 +6368,7 @@ def add_from_transition_function(self, function, initial_states=None, if u in ignore_done: not_done.append(u) ignore_done.remove(u) - self.add_transition(s, st_label, - word_in=letter, word_out=word) + self.add_transition(s, st_label, word_in=letter, word_out=word) def add_transitions_from_function(self, function, labels_as_input=True): """ @@ -6632,14 +6452,7 @@ def add_transitions_from_function(self, function, labels_as_input=True): transitions = return_value for t in transitions: if not hasattr(t, '__getitem__'): - raise ValueError("The callback function for " - "add_transitions_from_function " - "is expected to return a " - "pair (word_in, word_out) or a " - "list of such pairs. For " - "states %s and %s however, it " - "returned %s, which is not " - "acceptable." % (s_from, s_to, return_value)) + raise ValueError("The callback function for " "add_transitions_from_function " "is expected to return a " "pair (word_in, word_out) or a " "list of such pairs. For " "states %s and %s however, it " "returned %s, which is not " "acceptable." % (s_from, s_to, return_value)) label_in = t[0] try: label_out = t[1] @@ -6802,14 +6615,11 @@ def accessible_components(self): memo = {} def accessible(from_state, read): - return [(deepcopy(x.to_state, memo), x.word_out) - for x in self.iter_transitions(from_state) - if x.word_in[0] == read] + return [(deepcopy(x.to_state, memo), x.word_out) for x in self.iter_transitions(from_state) if x.word_in[0] == read] new_initial_states = [deepcopy(x, memo) for x in self.initial_states()] result = self.empty_copy() - result.add_from_transition_function(accessible, - initial_states=new_initial_states) + result.add_from_transition_function(accessible, initial_states=new_initial_states) for final_state in self.iter_final_states(): try: new_final_state = result.state(final_state.label) @@ -6854,10 +6664,8 @@ def coaccessible_components(self): :meth:`induced_sub_finite_state_machine` """ DG = self.digraph().reverse() - coaccessible_states = DG.breadth_first_search( - [_.label() for _ in self.iter_final_states()]) - return self.induced_sub_finite_state_machine( - [self.state(_) for _ in coaccessible_states]) + coaccessible_states = DG.breadth_first_search([_.label() for _ in self.iter_final_states()]) + return self.induced_sub_finite_state_machine([self.state(_) for _ in coaccessible_states]) # ************************************************************************* # creating new finite state machines @@ -7004,18 +6812,11 @@ def disjoint_union(self, other): for s in other.iter_states(): result.add_state(s.relabeled((1, s))) for t in self.iter_transitions(): - result.add_transition((0, t.from_state), - (0, t.to_state), - t.word_in, - t.word_out) + result.add_transition((0, t.from_state), (0, t.to_state), t.word_in, t.word_out) for t in other.iter_transitions(): - result.add_transition((1, t.from_state), - (1, t.to_state), - t.word_in, - t.word_out) + result.add_transition((1, t.from_state), (1, t.to_state), t.word_in, t.word_out) try: - result.input_alphabet = list(set(self.input_alphabet) - | set(other.input_alphabet)) + result.input_alphabet = list(set(self.input_alphabet) | set(other.input_alphabet)) except TypeError: # e.g. None or unhashable letters result.input_alphabet = None @@ -7168,11 +6969,9 @@ def concatenation(self, other): with a another finite state machine. """ if not isinstance(other, FiniteStateMachine): - raise TypeError('A finite state machine can only be concatenated ' - 'with a another finite state machine.') + raise TypeError('A finite state machine can only be concatenated ' 'with a another finite state machine.') if isinstance(other, Automaton) != isinstance(self, Automaton): - raise TypeError('Cannot concatenate finite state machines of ' - 'different types.') + raise TypeError('Cannot concatenate finite state machines of ' 'different types.') result = self.empty_copy() first_states = {} @@ -7191,29 +6990,19 @@ def concatenation(self, other): result.add_state(new_state) for t in self.iter_transitions(): - result.add_transition(first_states[t.from_state], - first_states[t.to_state], - t.word_in, - t.word_out) + result.add_transition(first_states[t.from_state], first_states[t.to_state], t.word_in, t.word_out) for t in other.iter_transitions(): - result.add_transition(second_states[t.from_state], - second_states[t.to_state], - t.word_in, - t.word_out) + result.add_transition(second_states[t.from_state], second_states[t.to_state], t.word_in, t.word_out) for s in self.iter_final_states(): first_state = first_states[s] for t in other.iter_initial_states(): second_state = second_states[t] - result.add_transition(first_state, - second_state, - [], - s.final_word_out) + result.add_transition(first_state, second_state, [], s.final_word_out) try: - result.input_alphabet = list(set(self.input_alphabet) - | set(other.input_alphabet)) + result.input_alphabet = list(set(self.input_alphabet) | set(other.input_alphabet)) except TypeError: # e.g. None or unhashable letters result.input_alphabet = None @@ -7324,11 +7113,7 @@ def intersection(self, other): """ raise NotImplementedError - def product_FiniteStateMachine(self, other, function, - new_input_alphabet=None, - only_accessible_components=True, - final_function=None, - new_class=None): + def product_FiniteStateMachine(self, other, function, new_input_alphabet=None, only_accessible_components=True, final_function=None, new_class=None): r""" Return a new finite state machine whose states are `d`-tuples of states of the original finite state machines. @@ -7529,6 +7314,7 @@ def product_FiniteStateMachine(self, other, function, ....: G, None, only_accessible_components=False).states() [(0, 'A'), (1, 'A')] """ + def default_final_function(*args): if any(s.final_word_out for s in args): raise ValueError("A final function must be given.") @@ -7547,30 +7333,23 @@ def default_final_function(*args): machines = [self] machines.extend(other) if not all(isinstance(m, FiniteStateMachine) for m in machines): - raise ValueError("other must be a finite state machine " - "or a list of finite state machines.") + raise ValueError("other must be a finite state machine " "or a list of finite state machines.") elif isinstance(other, FiniteStateMachine): machines = [self, other] else: - raise ValueError("other must be a finite state machine or " - "a list of finite state machines.") + raise ValueError("other must be a finite state machine or " "a list of finite state machines.") - for transitions in itertools.product( - *(m.iter_transitions() for m in machines)): + for transitions in itertools.product(*(m.iter_transitions() for m in machines)): try: word = function(*transitions) except LookupError: continue - result.add_transition(tuple(t.from_state for t in transitions), - tuple(t.to_state for t in transitions), - word[0], word[1]) + result.add_transition(tuple(t.from_state for t in transitions), tuple(t.to_state for t in transitions), word[0], word[1]) if only_accessible_components: - state_iterator = itertools.product( - *(m.iter_initial_states() for m in machines)) + state_iterator = itertools.product(*(m.iter_initial_states() for m in machines)) else: - state_iterator = itertools.product( - *(m.iter_states() for m in machines)) + state_iterator = itertools.product(*(m.iter_states() for m in machines)) for state in state_iterator: result.add_state(state) @@ -7592,8 +7371,7 @@ def default_final_function(*args): return result.accessible_components() return result - def composition(self, other, algorithm=None, - only_accessible_components=True): + def composition(self, other, algorithm=None, only_accessible_components=True): """ Return a new transducer which is the composition of ``self`` and ``other``. @@ -7884,13 +7662,10 @@ def composition(self, other, algorithm=None, determine_alphabets(). """ if not other._allow_composition_: - raise TypeError("Composition with automaton is not " - "possible.") + raise TypeError("Composition with automaton is not " "possible.") if algorithm is None: - if (any(len(t.word_out) > 1 for t in other.iter_transitions()) - or - any(len(t.word_in) != 1 for t in self.iter_transitions())): + if any(len(t.word_out) > 1 for t in other.iter_transitions()) or any(len(t.word_in) != 1 for t in self.iter_transitions()): algorithm = 'explorative' else: algorithm = 'direct' @@ -7922,23 +7697,18 @@ def _composition_direct_(self, other, only_accessible_components=True): Transition from (2, 'B') to (2, 'A'): 0|1, Transition from (2, 'A') to (2, 'B'): 1|0] """ + def function(transition1, transition2): if transition1.word_out == transition2.word_in: return (transition1.word_in, transition2.word_out) raise LookupError - result = other.product_FiniteStateMachine( - self, function, - only_accessible_components=only_accessible_components, - final_function=lambda s1, s2: [], - new_class=self.__class__) + result = other.product_FiniteStateMachine(self, function, only_accessible_components=only_accessible_components, final_function=lambda s1, s2: [], new_class=self.__class__) for state_result in result.iter_states(): state = state_result.label()[0] if state.is_final: - accept, _, output = self.process( - state.final_word_out, - initial_state=self.state(state_result.label()[1])) + accept, _, output = self.process(state.final_word_out, initial_state=self.state(state_result.label()[1])) if not accept: state_result.is_final = False else: @@ -7983,53 +7753,29 @@ def _composition_explorative_(self, other): sage: B.determinisation() Automaton with 1 state """ + def composition_transition(states, input): state1, state2 = states - return [((new_state1, new_state2), output_second) - for _, new_state1, output_first in - first.process([input], - list_of_outputs=True, - initial_state=state1, - write_final_word_out=False) - for _, new_state2, output_second in - second.process(output_first, - list_of_outputs=True, - initial_state=state2, - write_final_word_out=False, - always_include_output=True)] + return [((new_state1, new_state2), output_second) for _, new_state1, output_first in first.process([input], list_of_outputs=True, initial_state=state1, write_final_word_out=False) for _, new_state2, output_second in second.process(output_first, list_of_outputs=True, initial_state=state2, write_final_word_out=False, always_include_output=True)] first = other - if any(len(t.word_in) > 1 - for t in first.iter_transitions()): + if any(len(t.word_in) > 1 for t in first.iter_transitions()): first = first.split_transitions() second = self - if any(len(t.word_in) > 1 - for t in second.iter_transitions()): + if any(len(t.word_in) > 1 for t in second.iter_transitions()): second = second.split_transitions() F = first.empty_copy(new_class=second.__class__) - new_initial_states = itertools.product( - first.iter_initial_states(), - second.iter_initial_states()) - F.add_from_transition_function(composition_transition, - initial_states=new_initial_states) + new_initial_states = itertools.product(first.iter_initial_states(), second.iter_initial_states()) + F.add_from_transition_function(composition_transition, initial_states=new_initial_states) for state in F.iter_states(): state1, state2 = state.label() if state1.is_final: - final_output_second = second.process( - state1.final_word_out, - list_of_outputs=True, - initial_state=state2, - only_accepted=True, - always_include_output=True) - if (len(final_output_second) > 1 and - not equal(r[2] for r in final_output_second)): - raise NotImplementedError("Stopping in state %s " - "leads to " - "non-deterministic final " - "output." % state) + final_output_second = second.process(state1.final_word_out, list_of_outputs=True, initial_state=state2, only_accepted=True, always_include_output=True) + if len(final_output_second) > 1 and not equal(r[2] for r in final_output_second): + raise NotImplementedError("Stopping in state %s " "leads to " "non-deterministic final " "output." % state) if final_output_second: state.is_final = True state.final_word_out = final_output_second[0][2] @@ -8142,9 +7888,7 @@ def projection(self, what='input'): new_word_in = transition.word_out else: raise NotImplementedError - new.add_transition((state_mapping[transition.from_state], - state_mapping[transition.to_state], - new_word_in, None)) + new.add_transition((state_mapping[transition.from_state], state_mapping[transition.to_state], new_word_in, None)) if what == 'output': states = [s for s in self.iter_final_states() if s.final_word_out] @@ -8237,10 +7981,7 @@ def transposition(self, reverse_output_labels=True): transposition.add_state(deepcopy(state)) for transition in self.iter_transitions(): - transposition.add_transition( - transition.to_state.label(), transition.from_state.label(), - list(reversed(transition.word_in)), - rewrite_output(transition.word_out)) + transposition.add_transition(transition.to_state.label(), transition.from_state.label(), list(reversed(transition.word_in)), rewrite_output(transition.word_out)) for initial in self.iter_initial_states(): state = transposition.state(initial.label()) @@ -8251,9 +7992,7 @@ def transposition(self, reverse_output_labels=True): for final in self.iter_final_states(): state = transposition.state(final.label()) if final.final_word_out: - raise NotImplementedError("Transposition for transducers " - "with final output words is not " - "implemented.") + raise NotImplementedError("Transposition for transducers " "with final output words is not " "implemented.") if not final.is_initial: state.is_final = False state.is_initial = True @@ -8278,20 +8017,11 @@ def split_transitions(self): """ new = self.empty_copy() for state in self.states(): - new.add_state(FSMState((state, ()), is_initial=state.is_initial, - is_final=state.is_final)) + new.add_state(FSMState((state, ()), is_initial=state.is_initial, is_final=state.is_final)) for transition in self.transitions(): - for j in range(len(transition.word_in)-1): - new.add_transition(( - (transition.from_state, tuple(transition.word_in[:j])), - (transition.from_state, tuple(transition.word_in[:j+1])), - transition.word_in[j], - [])) - new.add_transition(( - (transition.from_state, tuple(transition.word_in[:-1])), - (transition.to_state, ()), - transition.word_in[-1:], - transition.word_out)) + for j in range(len(transition.word_in) - 1): + new.add_transition(((transition.from_state, tuple(transition.word_in[:j])), (transition.from_state, tuple(transition.word_in[: j + 1])), transition.word_in[j], [])) + new.add_transition(((transition.from_state, tuple(transition.word_in[:-1])), (transition.to_state, ()), transition.word_in[-1:], transition.word_out)) return new def final_components(self): @@ -8336,9 +8066,7 @@ def final_components(self): """ DG = self.digraph() condensation = DG.strongly_connected_components_digraph() - return [self.induced_sub_finite_state_machine([self.state(_) for _ in component]) - for component in condensation.vertices(sort=True) - if condensation.out_degree(component) == 0] + return [self.induced_sub_finite_state_machine([self.state(_) for _ in component]) for component in condensation.vertices(sort=True) if condensation.out_degree(component) == 0] def completion(self, sink=None): """ @@ -8458,34 +8186,25 @@ def completion(self, sink=None): if result.is_complete(): return result if not result.is_deterministic(): - raise ValueError( - "The finite state machine must be deterministic.") + raise ValueError("The finite state machine must be deterministic.") if sink is not None: try: s = result.state(sink) - raise ValueError("The finite state machine already " - "contains a state '%s'." % s.label()) + raise ValueError("The finite state machine already " "contains a state '%s'." % s.label()) except LookupError: pass else: - sink = 1 + max(itertools.chain( - [-1], - (s.label() for s in result.iter_states() - if s.label() in ZZ))) + sink = 1 + max(itertools.chain([-1], (s.label() for s in result.iter_states() if s.label() in ZZ))) sink_state = result.add_state(sink) for state in result.iter_states(): for transition in state.transitions: if len(transition.word_in) != 1: - raise ValueError( - "Transitions with input labels of length greater " - "than one are not allowed. Try calling " - "split_transitions().") + raise ValueError("Transitions with input labels of length greater " "than one are not allowed. Try calling " "split_transitions().") - existing = set(transition.word_in[0] - for transition in state.transitions) + existing = set(transition.word_in[0] for transition in state.transitions) for missing in set(result.input_alphabet) - existing: result.add_transition(state, sink_state, missing) @@ -8601,13 +8320,11 @@ def prepone_output(self): Transition from 1 to 0: 0|0, Transition from 1 to 1: 1|1,(0, 0)] """ + def find_common_output(state): - if (any(transition for transition in self.transitions(state) - if not transition.word_out) - or state.is_final and not state.final_word_out): + if any(transition for transition in self.transitions(state) if not transition.word_out) or state.is_final and not state.final_word_out: return tuple() - first_letters = [transition.word_out[0] - for transition in self.transitions(state)] + first_letters = [transition.word_out[0] for transition in self.transitions(state)] if state.is_final: first_letters = first_letters + [state.final_word_out[0]] if not first_letters: @@ -8626,10 +8343,7 @@ def find_common_output(state): if state.is_initial: continue if state.word_out: - raise NotImplementedError( - "prepone_output assumes that all states have " - "empty output word, but state %s has output " - "word %s" % (state, state.word_out)) + raise NotImplementedError("prepone_output assumes that all states have " "empty output word, but state %s has output " "word %s" % (state, state.word_out)) common_output = find_common_output(state) if common_output: changed += 1 @@ -8642,20 +8356,10 @@ def find_common_output(state): found_inbound_transition = False for transition in self.iter_transitions(): if transition.to_state == state: - transition.word_out = transition.word_out \ - + [common_output[0]] + transition.word_out = transition.word_out + [common_output[0]] found_inbound_transition = True if not found_inbound_transition: - verbose( - "All transitions leaving state %s have an " - "output label with prefix %s. However, " - "there is no inbound transition and it is " - "not an initial state. This routine " - "(possibly called by simplification) " - "therefore erased this prefix from all " - "outbound transitions." % - (state, common_output[0]), - level=0) + verbose("All transitions leaving state %s have an " "output label with prefix %s. However, " "there is no inbound transition and it is " "not an initial state. This routine " "(possibly called by simplification) " "therefore erased this prefix from all " "outbound transitions." % (state, common_output[0]), level=0) def equivalence_classes(self): r""" @@ -8725,11 +8429,9 @@ def equivalence_classes(self): # initialize with 0-equivalence classes_previous = [] - key_0 = lambda state: (state.is_final, state.color, state.word_out, - state.final_word_out) + key_0 = lambda state: (state.is_final, state.color, state.word_out, state.final_word_out) states_grouped = full_group_by(self.states(), key=key_0) - classes_current = [equivalence_class for - (key, equivalence_class) in states_grouped] + classes_current = [equivalence_class for (key, equivalence_class) in states_grouped] while len(classes_current) != len(classes_previous): class_of = {} @@ -8740,16 +8442,11 @@ def equivalence_classes(self): for state in classes_previous[k]: class_of[state] = k - key_current = lambda state: sorted( - [(transition.word_in, - transition.word_out, - class_of[transition.to_state]) - for transition in state.transitions]) + key_current = lambda state: sorted([(transition.word_in, transition.word_out, class_of[transition.to_state]) for transition in state.transitions]) for class_previous in classes_previous: states_grouped = full_group_by(class_previous, key=key_current) - classes_current.extend([equivalence_class for - (key, equivalence_class) in states_grouped]) + classes_current.extend([equivalence_class for (key, equivalence_class) in states_grouped]) return classes_current @@ -8841,32 +8538,18 @@ def quotient(self, classes): # Copy data from old transducer for c in classes: new_state = state_mapping[c[0]] - sorted_transitions = sorted( - [(state_mapping[t.to_state], t.word_in, t.word_out) - for t in c[0].transitions]) + sorted_transitions = sorted([(state_mapping[t.to_state], t.word_in, t.word_out) for t in c[0].transitions]) for transition in self.iter_transitions(c[0]): - new.add_transition( - from_state=new_state, - to_state=state_mapping[transition.to_state], - word_in=transition.word_in, - word_out=transition.word_out) + new.add_transition(from_state=new_state, to_state=state_mapping[transition.to_state], word_in=transition.word_in, word_out=transition.word_out) # check that all class members have the same information (modulo classes) for state in c: new_state.is_initial = new_state.is_initial or state.is_initial - assert new_state.is_final == state.is_final, \ - "Class %s mixes final and non-final states" % (c,) - assert new_state.word_out == state.word_out, \ - "Class %s mixes different word_out" % (c,) - assert new_state.color == state.color, \ - "Class %s mixes different colors" % (c,) - assert sorted_transitions == sorted( - [(state_mapping[t.to_state], t.word_in, t.word_out) - for t in state.transitions]), \ - "Transitions of state %s and %s are incompatible." % (c[0], state) - assert new_state.final_word_out == state.final_word_out, \ - "Class %s mixes final states with different " \ - "final output words." % (c,) + assert new_state.is_final == state.is_final, "Class %s mixes final and non-final states" % (c,) + assert new_state.word_out == state.word_out, "Class %s mixes different word_out" % (c,) + assert new_state.color == state.color, "Class %s mixes different colors" % (c,) + assert sorted_transitions == sorted([(state_mapping[t.to_state], t.word_in, t.word_out) for t in state.transitions]), "Transitions of state %s and %s are incompatible." % (c[0], state) + assert new_state.final_word_out == state.final_word_out, "Class %s mixes final states with different " "final output words." % (c,) return new def merged_transitions(self): @@ -8905,6 +8588,7 @@ def merged_transitions(self): sage: T2 is T1 True """ + def key(transition): return (transition.to_state, transition.word_out) @@ -9245,8 +8929,7 @@ def construct_final_word_out(self, letters, allow_non_final=True): if not isinstance(letters, list): letters = [letters] elif not letters: - raise ValueError( - "letters is not allowed to be an empty list.") + raise ValueError("letters is not allowed to be an empty list.") in_progress = set() cache = {} @@ -9265,24 +8948,16 @@ def find_final_word_out(state): return cache[state, position] if (state, position) in in_progress: - raise ValueError( - "The finite state machine contains a cycle " - "starting at state %s with input label %s " - "and no final state." % (state, letter)) + raise ValueError("The finite state machine contains a cycle " "starting at state %s with input label %s " "and no final state." % (state, letter)) if any(len(t.word_in) != 1 for t in state.transitions): - raise NotImplementedError( - "All transitions must have input labels of length " - "1. Consider calling split_transitions().") + raise NotImplementedError("All transitions must have input labels of length " "1. Consider calling split_transitions().") - transitions = [t for t in state.transitions - if t.word_in == [letter]] + transitions = [t for t in state.transitions if t.word_in == [letter]] if allow_non_final and not transitions: final_word_out = None elif len(transitions) != 1: - raise ValueError( - "No unique transition leaving state %s with input " - "label %s." % (state, letter)) + raise ValueError("No unique transition leaving state %s with input " "label %s." % (state, letter)) else: in_progress.add((state, position)) next_word = find_final_word_out(transitions[0].to_state) @@ -9362,9 +9037,7 @@ def graph(self, edge_labels='words_in_out'): transitions = state.transitions if not transitions: isolated_vertices.append(state.label()) - graph_data.extend((t.from_state.label(), t.to_state.label(), - label_fct(t)) - for t in transitions) + graph_data.extend((t.from_state.label(), t.to_state.label(), label_fct(t)) for t in transitions) G = DiGraph(graph_data, multiedges=True, loops=True) G.add_vertices(isolated_vertices) @@ -9441,8 +9114,7 @@ def predecessors(self, state, valid_input=None): done.append(s) return done - def number_of_words(self, variable=None, - base_ring=None): + def number_of_words(self, variable=None, base_ring=None): r""" Return the number of successful input words of given length. @@ -9555,6 +9227,7 @@ def number_of_words(self, variable=None, from sage.modules.free_module_element import vector from sage.arith.misc import binomial from sage.symbolic.ring import SR + if base_ring is None: from sage.rings.qqbar import QQbar as base_ring if variable is None: @@ -9562,11 +9235,7 @@ def number_of_words(self, variable=None, def jordan_block_power(block, exponent): eigenvalue = SR(block[0, 0]) - return matrix(block.nrows(), - block.nrows(), - lambda i, j: eigenvalue**(exponent-(j-i)) * - binomial(exponent, j - i) - if j >= i else 0) + return matrix(block.nrows(), block.nrows(), lambda i, j: eigenvalue ** (exponent - (j - i)) * binomial(exponent, j - i) if j >= i else 0) if not self.is_deterministic(): raise NotImplementedError("Finite State Machine must be deterministic.") @@ -9575,9 +9244,7 @@ def jordan_block_power(block, exponent): right = vector(ZZ(s.is_final) for s in self.iter_states()) A = self.adjacency_matrix(entry=lambda t: 1) J, T = A.jordan_form(base_ring, transformation=True) - Jpower = matrix.block_diagonal( - [jordan_block_power(J.subdivision(j, j), variable) - for j in range(len(J.subdivisions()[0]) + 1)]) + Jpower = matrix.block_diagonal([jordan_block_power(J.subdivision(j, j), variable) for j in range(len(J.subdivisions()[0]) + 1)]) T_inv_right = T.solve_right(right).change_ring(SR) left_T = (left * T).change_ring(SR) return left_T * Jpower * T_inv_right @@ -9975,8 +9642,7 @@ def asymptotic_moments(self, variable=None): :doi:`10.1007/s10998-007-3081-z`. """ if self.input_alphabet is None: - raise ValueError("No input alphabet is given. " - "Try calling determine_alphabets().") + raise ValueError("No input alphabet is given. " "Try calling determine_alphabets().") if len(self.initial_states()) != 1: raise ValueError("A unique initial state is required.") @@ -9985,21 +9651,15 @@ def asymptotic_moments(self, variable=None): raise ValueError("Not all states are final.") if not self.is_complete(): - raise NotImplementedError("This finite state machine is " - "not complete.") + raise NotImplementedError("This finite state machine is " "not complete.") final_components = self.final_components() if len(final_components) != 1: - raise NotImplementedError("asymptotic_moments is only " - "implemented for finite state machines " - "with one final component.") + raise NotImplementedError("asymptotic_moments is only " "implemented for finite state machines " "with one final component.") final_component = final_components[0] if not final_component.digraph().is_aperiodic(): - raise NotImplementedError("asymptotic_moments is only " - "implemented for finite state machines " - "whose unique final component is " - "aperiodic.") + raise NotImplementedError("asymptotic_moments is only " "implemented for finite state machines " "whose unique final component is " "aperiodic.") from sage.calculus.functional import derivative from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -10010,10 +9670,7 @@ def asymptotic_moments(self, variable=None): variable = SR.symbol('n') def get_matrix(fsm, x, y): - return fsm.adjacency_matrix( - entry=lambda transition: x**sum(transition.word_in) * - y**(sum(transition.word_out) + - sum(transition.from_state.word_out))) + return fsm.adjacency_matrix(entry=lambda transition: x ** sum(transition.word_in) * y ** (sum(transition.word_out) + sum(transition.from_state.word_out))) K = len(self.input_alphabet) R = PolynomialRing(QQ, ("x", "y", "z")) @@ -10021,9 +9678,7 @@ def get_matrix(fsm, x, y): try: M = get_matrix(self, x, y) except (TypeError, ValueError): - verbose( - "Non-integer output weights lead to " - "significant performance degradation.", level=0) + verbose("Non-integer output weights lead to " "significant performance degradation.", level=0) # fall back to symbolic ring R = SR x = R.symbol() @@ -10033,6 +9688,7 @@ def get_matrix(fsm, x, y): def substitute_one(g): return g.subs({x: 1, y: 1, z: 1}) + else: def substitute_one(g): @@ -10042,7 +9698,7 @@ def substitute_one(g): # Therefore, we need this helper function. return g(1, 1, 1) - f = (M.parent().identity_matrix() - z/K*M).det() + f = (M.parent().identity_matrix() - z / K * M).det() f_x = substitute_one(derivative(f, x)) f_y = substitute_one(derivative(f, y)) f_z = substitute_one(derivative(f, z)) @@ -10053,17 +9709,12 @@ def substitute_one(g): f_zz = substitute_one(derivative(f, z, z)) e_2 = f_y / f_z - v_2 = (f_y**2 * (f_zz+f_z) + f_z**2 * (f_yy+f_y) - - 2*f_y*f_z*f_yz) / f_z**3 - c = (f_x * f_y * (f_zz+f_z) + f_z**2 * f_xy - f_y*f_z*f_xz - - f_x*f_z*f_yz) / f_z**3 + v_2 = (f_y**2 * (f_zz + f_z) + f_z**2 * (f_yy + f_y) - 2 * f_y * f_z * f_yz) / f_z**3 + c = (f_x * f_y * (f_zz + f_z) + f_z**2 * f_xy - f_y * f_z * f_xz - f_x * f_z * f_yz) / f_z**3 - return {'expectation': e_2*variable + SR(1).Order(), - 'variance': v_2*variable + SR(1).Order(), - 'covariance': c*variable + SR(1).Order()} + return {'expectation': e_2 * variable + SR(1).Order(), 'variance': v_2 * variable + SR(1).Order(), 'covariance': c * variable + SR(1).Order()} - def moments_waiting_time(self, test=bool, is_zero=None, - expectation_only=False): + def moments_waiting_time(self, test=bool, is_zero=None, expectation_only=False): r""" If this finite state machine acts as a Markov chain, return the expectation and variance of the number of steps until @@ -10383,8 +10034,7 @@ def moments_waiting_time(self, test=bool, is_zero=None, """ from sage.modules.free_module_element import vector from sage.matrix.constructor import identity_matrix - from sage.rings.polynomial.polynomial_ring_constructor import\ - PolynomialRing + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing def default_is_zero(expression): return expression.is_zero() @@ -10394,8 +10044,7 @@ def default_is_zero(expression): is_zero_function = is_zero if not self.is_Markov_chain(is_zero): - raise ValueError("Only Markov chains can compute " - "moments_waiting_time.") + raise ValueError("Only Markov chains can compute " "moments_waiting_time.") if len(self.initial_states()) != 1: raise ValueError("Unique initial state is required.") @@ -10409,8 +10058,7 @@ def entry(transition): relabeled = self.relabeled() n = len(relabeled.states()) assert [s.label() for s in relabeled.states()] == list(range(n)) - entry_vector = vector(ZZ(s.is_initial) - for s in relabeled.states()) + entry_vector = vector(ZZ(s.is_initial) for s in relabeled.states()) exit_vector = vector([1] * n) transition_matrix = relabeled.adjacency_matrix(entry=entry) # transition_matrix is the probability transition matrix @@ -10420,42 +10068,36 @@ def entry(transition): # because we want to check for "true" input in the sense # of python's boolean conversion. So we cannot give # input=[False] as this might lead to strange phenomena. - if all(map(is_zero_function, - transition_matrix * exit_vector - exit_vector)): + if all(map(is_zero_function, transition_matrix * exit_vector - exit_vector)): import sage.rings.infinity + expectation = sage.rings.infinity.PlusInfinity() variance = sage.rings.infinity.PlusInfinity() else: if expectation_only: system_matrix = identity_matrix(n) - transition_matrix - expectation = entry_vector * \ - system_matrix.solve_right(exit_vector) + expectation = entry_vector * system_matrix.solve_right(exit_vector) else: base_ring = transition_matrix.parent().base_ring() - from sage.rings.polynomial.multi_polynomial_ring \ - import MPolynomialRing_base + from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base + if isinstance(base_ring, MPolynomialRing_base): # if base_ring is already a multivariate polynomial # ring, extend it instead of creating a univariate # polynomial ring over a polynomial ring. This # should improve performance. - R = PolynomialRing(base_ring.base_ring(), - base_ring.variable_names() - + ('Z_waiting_time',)) + R = PolynomialRing(base_ring.base_ring(), base_ring.variable_names() + ('Z_waiting_time',)) else: R = PolynomialRing(base_ring, 'Z_waiting_time') Z = R.gens()[-1] system_matrix = identity_matrix(n) - Z * transition_matrix G = entry_vector * system_matrix.solve_right(exit_vector) expectation = G.subs({Z: 1}) - variance = 2 * G.derivative(Z).subs({Z: 1}) \ - + expectation \ - - expectation**2 + variance = 2 * G.derivative(Z).subs({Z: 1}) + expectation - expectation**2 if expectation_only: return expectation - return {'expectation': expectation, - 'variance': variance} + return {'expectation': expectation, 'variance': variance} def is_monochromatic(self): """ @@ -10658,8 +10300,7 @@ def _repr_(self): return "Automaton with 1 state" return "Automaton with %s states" % len(self._states_) - def _latex_transition_label_(self, transition, - format_function=None): + def _latex_transition_label_(self, transition, format_function=None): r""" Return the proper transition label. @@ -10772,21 +10413,16 @@ def intersection(self, other, only_accessible_components=True): sage: a1.intersection(a2) # not tested """ if not isinstance(other, Automaton): - raise TypeError( - "Only an automaton can be intersected with an automaton.") + raise TypeError("Only an automaton can be intersected with an automaton.") def function(transition1, transition2): if not transition1.word_in or not transition2.word_in: - raise ValueError( - "An epsilon-transition (with empty input) was found.") + raise ValueError("An epsilon-transition (with empty input) was found.") if transition1.word_in == transition2.word_in: return (transition1.word_in, None) raise LookupError - return self.product_FiniteStateMachine( - other, - function, - only_accessible_components=only_accessible_components) + return self.product_FiniteStateMachine(other, function, only_accessible_components=only_accessible_components) cartesian_product = intersection @@ -10924,10 +10560,7 @@ def determinisation(self): epsilon_successors = {} direct_epsilon_successors = {} for state in self.iter_states(): - direct_epsilon_successors[state] = set( - t.to_state - for t in self.iter_transitions(state) - if not t.word_in) + direct_epsilon_successors[state] = set(t.to_state for t in self.iter_transitions(state) if not t.word_in) epsilon_successors[state] = set([state]) old_count_epsilon_successors = 0 @@ -10951,12 +10584,8 @@ def set_transition(states, letter): return (frozenset(result), []) result = self.empty_copy() - new_initial_states = [frozenset(set().union( - *(epsilon_successors[s] - for s in self.iter_initial_states() - )))] - result.add_from_transition_function(set_transition, - initial_states=new_initial_states) + new_initial_states = [frozenset(set().union(*(epsilon_successors[s] for s in self.iter_initial_states())))] + result.add_from_transition_function(set_transition, initial_states=new_initial_states) for state in result.iter_states(): state.is_final = any(s.is_final for s in state.label()) @@ -11076,8 +10705,7 @@ def _minimization_Moore_(self): """ if self.is_deterministic(): return self.quotient(self.equivalence_classes()) - raise NotImplementedError("Minimization via Moore's Algorithm is only " - "implemented for deterministic finite state machines") + raise NotImplementedError("Minimization via Moore's Algorithm is only " "implemented for deterministic finite state machines") def complement(self): r""" @@ -11152,7 +10780,7 @@ def is_equivalent(self, other): False """ A = self.minimization().relabeled() - initial, = A.initial_states() + (initial,) = A.initial_states() address = {initial: ()} for v in A.digraph().breadth_first_search(initial.label()): state = A.state(v) @@ -11162,8 +10790,7 @@ def is_equivalent(self, other): address[t.to_state] = state_address + tuple(t.word_in) B = other.minimization().relabeled() - labels = {B.process(path)[1].label(): state.label() - for (state, path) in address.items()} + labels = {B.process(path)[1].label(): state.label() for (state, path) in address.items()} try: return A == B.relabeled(labels=labels) except KeyError: @@ -11396,8 +11023,7 @@ class is created and is used during the processing. options = copy(self._process_default_options_) options.update(kwargs) - condensed_output = (options['list_of_outputs'] is False and - not options['full_output']) + condensed_output = options['list_of_outputs'] is False and not options['full_output'] if condensed_output: options['list_of_outputs'] = True @@ -11445,8 +11071,7 @@ def _process_convert_output_(self, output_data, **kwargs): (True, 'a', [1, 0, 1]) """ if kwargs['always_include_output']: - return super()._process_convert_output_( - output_data, **kwargs) + return super()._process_convert_output_(output_data, **kwargs) accept_input, current_state, _ = output_data if kwargs['full_output']: return (accept_input, current_state) @@ -11548,6 +11173,7 @@ def shannon_parry_markov_chain(self): :doi:`10.1002/j.1538-7305.1948.tb01338.x`. """ from sage.modules.free_module_element import vector + if not self.is_deterministic(): raise NotImplementedError("Automaton must be deterministic.") if not self.digraph().is_aperiodic(): @@ -11558,30 +11184,21 @@ def shannon_parry_markov_chain(self): raise NotImplementedError("All states must be final.") M = self.adjacency_matrix().change_ring(ZZ) states = {state: i for i, state in enumerate(self.iter_states())} - w_all = sorted(M.eigenvectors_right(), - key=lambda x: abs(x[0]), - reverse=True) + w_all = sorted(M.eigenvectors_right(), key=lambda x: abs(x[0]), reverse=True) w = w_all[0][1][0] mu = w_all[0][0] - u_all = sorted(M.eigenvectors_left(), - key=lambda x: abs(x[0]), - reverse=True) + u_all = sorted(M.eigenvectors_left(), key=lambda x: abs(x[0]), reverse=True) u = u_all[0][1][0] - u = 1/(u*w) * u + u = 1 / (u * w) * u final = vector(int(s.is_final) for s in self.iter_states()) - ff = u*final + ff = u * final - assert u*w == 1 - P = Transducer(initial_states=[s.label() for s in self.iter_initial_states()], - final_states=[s.label() for s in self.iter_final_states()], - on_duplicate_transition=duplicate_transition_add_input) + assert u * w == 1 + P = Transducer(initial_states=[s.label() for s in self.iter_initial_states()], final_states=[s.label() for s in self.iter_final_states()], on_duplicate_transition=duplicate_transition_add_input) for t in self.iter_transitions(): - P.add_transition(t.from_state.label(), - t.to_state.label(), - w[states[t.to_state]]/w[states[t.from_state]]/mu, - t.word_in) + P.add_transition(t.from_state.label(), t.to_state.label(), w[states[t.to_state]] / w[states[t.from_state]] / mu, t.word_in) for s in self.iter_states(): - P.state(s.label()).color = 1/(w[states[s]] * ff) + P.state(s.label()).color = 1 / (w[states[s]] * ff) P.state(s.label()).initial_probability = w[states[s]] * u[states[s]] return P @@ -11799,8 +11416,7 @@ def _repr_(self): return "Transducer with 1 state" return "Transducer with %s states" % len(self._states_) - def _latex_transition_label_(self, transition, - format_function=None): + def _latex_transition_label_(self, transition, format_function=None): r""" Return the proper transition label. @@ -11831,8 +11447,7 @@ def _latex_transition_label_(self, transition, """ if format_function is None: format_function = latex - return (format_function(transition.word_in) + "\\mid " - + format_function(transition.word_out)) + return format_function(transition.word_in) + "\\mid " + format_function(transition.word_out) def intersection(self, other, only_accessible_components=True): """ @@ -11926,24 +11541,16 @@ def intersection(self, other, only_accessible_components=True): Applications*, edited by Jiacun Wang, Chapman and Hall/CRC, 2012. """ if not isinstance(other, Transducer): - raise TypeError( - "Only a transducer can be intersected with a transducer.") + raise TypeError("Only a transducer can be intersected with a transducer.") def function(transition1, transition2): - if not transition1.word_in or not transition2.word_in \ - or not transition1.word_out or not transition2.word_out: - raise ValueError("An epsilon-transition " - "(with empty input or output) was found.") - if transition1.word_in == transition2.word_in \ - and transition1.word_out == transition2.word_out: + if not transition1.word_in or not transition2.word_in or not transition1.word_out or not transition2.word_out: + raise ValueError("An epsilon-transition " "(with empty input or output) was found.") + if transition1.word_in == transition2.word_in and transition1.word_out == transition2.word_out: return (transition1.word_in, transition1.word_out) raise LookupError - new = self.product_FiniteStateMachine( - other, - function, - only_accessible_components=only_accessible_components, - final_function=lambda s1, s2: s1.final_word_out) + new = self.product_FiniteStateMachine(other, function, only_accessible_components=only_accessible_components, final_function=lambda s1, s2: s1.final_word_out) for state in new.iter_final_states(): state0 = self.state(state.label()[0]) @@ -12118,23 +11725,16 @@ def cartesian_product(self, other, only_accessible_components=True): (0, 0, 0), (0, 0, 1)] """ + def function(*transitions): if equal(t.word_in for t in transitions): - return (transitions[0].word_in, - list(itertools.zip_longest( - *(t.word_out for t in transitions) - ))) + return (transitions[0].word_in, list(itertools.zip_longest(*(t.word_out for t in transitions)))) raise LookupError def final_function(*states): - return list(itertools.zip_longest(*(s.final_word_out - for s in states))) + return list(itertools.zip_longest(*(s.final_word_out for s in states))) - return self.product_FiniteStateMachine( - other, - function, - final_function=final_function, - only_accessible_components=only_accessible_components) + return self.product_FiniteStateMachine(other, function, final_function=final_function, only_accessible_components=only_accessible_components) def simplification(self): """ @@ -12520,8 +12120,7 @@ class is created and is used during the processing. options = copy(self._process_default_options_) options.update(kwargs) - condensed_output = (options['list_of_outputs'] is False and - not options['full_output']) + condensed_output = options['list_of_outputs'] is False and not options['full_output'] if condensed_output: options['list_of_outputs'] = True @@ -12529,8 +12128,7 @@ class is created and is used during the processing. result = super().process(*args, **options) - if (condensed_output and not result or - not options['full_output'] and result is None): + if condensed_output and not result or not options['full_output'] and result is None: raise ValueError("Invalid input sequence.") if condensed_output and len(result) >= 2: raise ValueError("Found more than one accepting path.") @@ -12623,8 +12221,7 @@ class _FSMTapeCache_(SageObject): [multi-tape at (0, 0)] """ - def __init__(self, tape_cache_manager, tape, tape_ended, - position, is_multitape): + def __init__(self, tape_cache_manager, tape, tape_ended, position, is_multitape): """ See :class:`_FSMTapeCache_` for more details. @@ -12718,9 +12315,7 @@ def __deepcopy__(self, memo): sage: TC2.tape_cache_manager is TC3.tape_cache_manager True """ - new = type(self)(self.tape_cache_manager, - self.tape, self.tape_ended, - self.position, self.is_multitape) + new = type(self)(self.tape_cache_manager, self.tape, self.tape_ended, self.position, self.is_multitape) new.cache = deepcopy(self.cache, memo) return new @@ -12945,12 +12540,10 @@ def preview_word(self, track_number=None, length=1, return_word=False): cache: (deque([]), deque([])) multi-tape at (5, 4) """ if not return_word and length != 1: - raise ValueError("Should return a letter, but parameter " - "length is not 1.") + raise ValueError("Should return a letter, but parameter " "length is not 1.") if track_number is None: if self.is_multitape: - result = tuple(self.preview_word(n, length, return_word) - for n, _ in enumerate(self.cache)) + result = tuple(self.preview_word(n, length, return_word) for n, _ in enumerate(self.cache)) if len(result) != len(self.cache): raise RuntimeError('tape reached the end') if return_word: @@ -13001,8 +12594,7 @@ def compare_to_tape(self, track_number, word): it_word = iter(word) # check letters in cache - if any(letter_on_track != letter_in_word - for letter_on_track, letter_in_word in zip(track_cache, it_word)): + if any(letter_on_track != letter_in_word for letter_on_track, letter_in_word in zip(track_cache, it_word)): return False # check letters not already cached @@ -13070,24 +12662,22 @@ def forward(self, transition): ... ValueError: forwarding tape is not possible """ + def length(word): return len(tuple(letter for letter in word if letter is not None)) if self.is_multitape: - increments = tuple(length(word) for word in - zip(*transition.word_in)) + increments = tuple(length(word) for word in zip(*transition.word_in)) else: increments = (length(transition.word_in),) - for track_number, (track_cache, inc) in \ - enumerate(zip(self.cache, increments)): + for track_number, (track_cache, inc) in enumerate(zip(self.cache, increments)): for _ in range(inc): if not track_cache: if not self.read(track_number)[0]: raise ValueError('forwarding tape is not possible') track_cache.popleft() - position = [(p + increments[t], t) - for p, t in self.position] + position = [(p + increments[t], t) for p, t in self.position] self.position = tuple(sorted(position)) def transition_possible(self, transition): @@ -13127,9 +12717,7 @@ def transition_possible(self, transition): else: word_in = tupleofwords_to_wordoftuples((transition.word_in,)) if any(len(t) != len(self.cache) for t in word_in): - raise TypeError('%s has bad input word (entries should be ' - 'tuples of size %s).' % (transition, - len(self.cache))) + raise TypeError('%s has bad input word (entries should be ' 'tuples of size %s).' % (transition, len(self.cache))) return self._transition_possible_test_(word_in) def _transition_possible_epsilon_(self, word_in): @@ -13211,8 +12799,7 @@ def _transition_possible_test_(self, word_in): if self._transition_possible_epsilon_(word_in): return False word_in_transposed = wordoftuples_to_tupleofwords(word_in) - return all(self.compare_to_tape(track_number, word) - for track_number, word in enumerate(word_in_transposed)) + return all(self.compare_to_tape(track_number, word) for track_number, word in enumerate(word_in_transposed)) # **************************************************************************** @@ -13395,8 +12982,8 @@ def wordoftuples_to_tupleofwords(wordoftuples): def remove_empty_letters(word): return [letter for letter in word if letter is not None] - return tuple(remove_empty_letters(word) - for word in zip(*wordoftuples)) + + return tuple(remove_empty_letters(word) for word in zip(*wordoftuples)) # **************************************************************************** @@ -13670,10 +13257,7 @@ def __repr__(self): +-- tape at 2, [[0, 0]] process (0 branches) """ - data = sorted( - (state, pos, tape_cache, outputs) - for pos, states in self.items() - for state, (tape_cache, outputs) in states.items()) + data = sorted((state, pos, tape_cache, outputs) for pos, states in self.items() for state, (tape_cache, outputs) in states.items()) branch = "branch" if len(data) == 1 else "branches" result = "process (%s %s)" % (len(data), branch) for s, sdata in itertools.groupby(data, lambda x: x[0]): @@ -13689,15 +13273,7 @@ def __repr__(self): it is fully processed. """ - def __init__(self, fsm, - input_tape=None, - initial_state=None, initial_states=[], - use_multitape_input=False, - check_epsilon_transitions=True, - write_final_word_out=True, - format_output=None, - process_all_prefixes_of_input=False, - **kwargs): + def __init__(self, fsm, input_tape=None, initial_state=None, initial_states=[], use_multitape_input=False, check_epsilon_transitions=True, write_final_word_out=True, format_output=None, process_all_prefixes_of_input=False, **kwargs): """ See :class:`FSMProcessIterator` for more information. @@ -13767,11 +13343,7 @@ def __init__(self, fsm, self.TapeCache = _FSMTapeCache_ for state in initial_states: - tape_cache = self.TapeCache(self._tape_cache_manager_, - self._input_tape_, - self._input_tape_ended_, - position_zero, - self.is_multitape) + tape_cache = self.TapeCache(self._tape_cache_manager_, self._input_tape_, self._input_tape_ended_, position_zero, self.is_multitape) self._push_branches_(state, tape_cache, [[]]) self._finished_ = [] # contains (accept, state, output) @@ -13864,10 +13436,8 @@ def _push_branch_(self, state, tape_cache, outputs): existing = states[state] new_outputs = existing.outputs new_outputs.extend(outputs) - new_outputs = [t for t, _ in - itertools.groupby(sorted(new_outputs))] - states[state] = FSMProcessIterator._branch_( - existing.tape_cache, new_outputs) + new_outputs = [t for t, _ in itertools.groupby(sorted(new_outputs))] + states[state] = FSMProcessIterator._branch_(existing.tape_cache, new_outputs) else: states[state] = FSMProcessIterator._branch_(tape_cache, outputs) @@ -13934,12 +13504,9 @@ def _push_branches_(self, state, tape_cache, outputs): return if state._in_epsilon_cycle_(self.fsm): if not state._epsilon_cycle_output_empty_(self.fsm): - raise RuntimeError( - 'State %s is in an epsilon cycle (no input), ' - 'but output is written.' % (state,)) + raise RuntimeError('State %s is in an epsilon cycle (no input), ' 'but output is written.' % (state,)) - for eps_state, eps_outputs in \ - state._epsilon_successors_(self.fsm).items(): + for eps_state, eps_outputs in state._epsilon_successors_(self.fsm).items(): if eps_state == state: continue # "eps_state == state" means epsilon cycle @@ -14057,33 +13624,25 @@ def step(current_state, input_tape, outputs): else: try: self._current_branch_input_tape_ = input_tape # for preview_word - next_transitions = current_state.hook( - self, current_state, outputs) + next_transitions = current_state.hook(self, current_state, outputs) except StopIteration: next_transitions = [] state_said_finished = True if isinstance(next_transitions, FSMTransition): next_transitions = [next_transitions] - if next_transitions is not None and \ - not isinstance(next_transitions, Iterable): - raise ValueError('hook of state should return a ' - 'transition or ' - 'a list/tuple of transitions.') + if next_transitions is not None and not isinstance(next_transitions, Iterable): + raise ValueError('hook of state should return a ' 'transition or ' 'a list/tuple of transitions.') # write output word of state write_word(outputs, current_state.word_out) # get next if next_transitions is None: - next_transitions = \ - [transition for transition in current_state.transitions - if input_tape.transition_possible(transition)] + next_transitions = [transition for transition in current_state.transitions if input_tape.transition_possible(transition)] if not next_transitions: # this branch has to end here... - if not (input_tape.finished() or - state_said_finished or - self.process_all_prefixes_of_input): + if not (input_tape.finished() or state_said_finished or self.process_all_prefixes_of_input): return if not next_transitions or self.process_all_prefixes_of_input: @@ -14096,11 +13655,7 @@ def step(current_state, input_tape, outputs): if successful and self.write_final_word_out: write_word(write_outputs, current_state.final_word_out) for o in write_outputs: - self._finished_.append( - FSMProcessIterator.FinishedBranch( - accept=successful, - state=current_state, - output=self.format_output(o))) + self._finished_.append(FSMProcessIterator.FinishedBranch(accept=successful, state=current_state, output=self.format_output(o))) if not next_transitions: # this branch has to end here... (continued) @@ -14111,9 +13666,7 @@ def step(current_state, input_tape, outputs): new_currents = [(input_tape, outputs)] if len(next_transitions) > 1: - new_currents.extend( - [deepcopy(new_currents[0]) - for _ in range(len(next_transitions) - 1)]) + new_currents.extend([deepcopy(new_currents[0]) for _ in range(len(next_transitions) - 1)]) # process transitions for transition, (tape, out) in zip(next_transitions, new_currents): @@ -14233,8 +13786,7 @@ def preview_word(self, track_number=None, length=1, return_word=False): sage: it.result() [Branch(accept=True, state='A', output=['one', 'zero', 'zero'])] """ - return self._current_branch_input_tape_.preview_word( - track_number, length, return_word) + return self._current_branch_input_tape_.preview_word(track_number, length, return_word) # **************************************************************************** @@ -14590,16 +14142,14 @@ def _push_branch_(self, state, tape_cache, outputs): """ if state not in self.visited_states: self.visited_states[state] = [] - self.visited_states[state].extend( - self.format_output(o) for o in outputs) + self.visited_states[state].extend(self.format_output(o) for o in outputs) found = state in tape_cache._visited_states_ tape_cache._visited_states_.add(state) if found: return - super()._push_branch_( - state, tape_cache, outputs) + super()._push_branch_(state, tape_cache, outputs) # As tape_cache may have been discarded because current already # contains a branch at the same state, _visited_states_ is diff --git a/src/sage/combinat/finite_state_machine_generators.py b/src/sage/combinat/finite_state_machine_generators.py index 744eca53a45..291f542de06 100644 --- a/src/sage/combinat/finite_state_machine_generators.py +++ b/src/sage/combinat/finite_state_machine_generators.py @@ -142,9 +142,7 @@ def AnyLetter(self, input_alphabet) -> Automaton: """ z = ZZ.zero() o = ZZ.one() - return Automaton([(z, o, _) for _ in input_alphabet], - initial_states=[z], - final_states=[o]) + return Automaton([(z, o, _) for _ in input_alphabet], initial_states=[z], final_states=[o]) def AnyWord(self, input_alphabet) -> Automaton: r""" @@ -183,9 +181,7 @@ def AnyWord(self, input_alphabet) -> Automaton: :meth:`Word`. """ z = ZZ.zero() - return Automaton([(z, z, _) for _ in input_alphabet], - initial_states=[z], - final_states=[z]) + return Automaton([(z, z, _) for _ in input_alphabet], initial_states=[z], final_states=[z]) def EmptyWord(self, input_alphabet=None) -> Automaton: r""" @@ -211,9 +207,7 @@ def EmptyWord(self, input_alphabet=None) -> Automaton: :meth:`AnyWord`. """ z = ZZ.zero() - return Automaton(initial_states=[z], - final_states=[z], - input_alphabet=input_alphabet) + return Automaton(initial_states=[z], final_states=[z], input_alphabet=input_alphabet) def Word(self, word, input_alphabet=None) -> Automaton: r""" @@ -266,11 +260,8 @@ def Word(self, word, input_alphabet=None) -> Automaton: letters = list(word) length = len(letters) from sage.rings.integer_ring import ZZ - return Automaton([(ZZ(i), ZZ(i + 1), letter) - for i, letter in enumerate(letters)], - initial_states=[ZZ.zero()], - final_states=[ZZ(length)], - input_alphabet=input_alphabet) + + return Automaton([(ZZ(i), ZZ(i + 1), letter) for i, letter in enumerate(letters)], initial_states=[ZZ.zero()], final_states=[ZZ(length)], input_alphabet=input_alphabet) def ContainsWord(self, word, input_alphabet) -> Automaton: r""" @@ -315,8 +306,7 @@ def ContainsWord(self, word, input_alphabet) -> Automaton: word = tuple(word) def starts_with(what, pattern): - return len(what) >= len(pattern) \ - and what[:len(pattern)] == pattern + return len(what) >= len(pattern) and what[: len(pattern)] == pattern def transition_function(read, input): if read == word: @@ -327,11 +317,7 @@ def transition_function(read, input): k += 1 return (current[k:], None) - return Automaton( - transition_function, - input_alphabet=input_alphabet, - initial_states=[()], - final_states=[word]) + return Automaton(transition_function, input_alphabet=input_alphabet, initial_states=[()], final_states=[word]) class TransducerGenerators: @@ -385,12 +371,7 @@ def Identity(self, input_alphabet) -> Transducer: sage: T([0, 1, 0, 1, 1]) [0, 1, 0, 1, 1] """ - return Transducer( - [(0, 0, d, d) for d in input_alphabet], - input_alphabet=input_alphabet, - output_alphabet=input_alphabet, - initial_states=[0], - final_states=[0]) + return Transducer([(0, 0, d, d) for d in input_alphabet], input_alphabet=input_alphabet, output_alphabet=input_alphabet, initial_states=[0], final_states=[0]) def CountSubblockOccurrences(self, block, input_alphabet) -> Transducer: r""" @@ -489,24 +470,18 @@ def CountSubblockOccurrences(self, block, input_alphabet) -> Transducer: block_as_tuple = tuple(block) def starts_with(what, pattern): - return len(what) >= len(pattern) \ - and what[:len(pattern)] == pattern + return len(what) >= len(pattern) and what[: len(pattern)] == pattern def transition_function(read, input): - current = read + (input, ) - if starts_with(block_as_tuple, current) \ - and len(block_as_tuple) > len(current): + current = read + (input,) + if starts_with(block_as_tuple, current) and len(block_as_tuple) > len(current): return (current, 0) k = 1 while not starts_with(block_as_tuple, current[k:]): k += 1 return (current[k:], int(block_as_tuple == current)) - T = Transducer( - transition_function, - input_alphabet=input_alphabet, - output_alphabet=[0, 1], - initial_states=[()]) + T = Transducer(transition_function, input_alphabet=input_alphabet, output_alphabet=[0, 1], initial_states=[()]) for s in T.iter_states(): s.is_final = True return T @@ -539,6 +514,7 @@ def Wait(self, input_alphabet, threshold=1) -> Transducer: sage: T2([0, 0, 1, 0, 1, 0]) [False, False, False, False, True, True] """ + def transition(state, input): if state == threshold: return (threshold, True) @@ -546,9 +522,7 @@ def transition(state, input): return (state, False) return (state + 1, state + 1 == threshold) - T = Transducer(transition, - input_alphabet=input_alphabet, - initial_states=[0]) + T = Transducer(transition, input_alphabet=input_alphabet, initial_states=[0]) for s in T.iter_states(): s.is_final = True @@ -594,13 +568,9 @@ def map(self, f, input_alphabet) -> Transducer: :meth:`Automaton.with_output() `. """ - return Transducer(lambda state, input: (0, f(input)), - input_alphabet=input_alphabet, - initial_states=[0], - final_states=[0]) + return Transducer(lambda state, input: (0, f(input)), input_alphabet=input_alphabet, initial_states=[0], final_states=[0]) - def operator(self, operator, input_alphabet, - number_of_operands=2) -> Transducer: + def operator(self, operator, input_alphabet, number_of_operands=2) -> Transducer: r""" Return a transducer which realizes an operation on tuples over the given input alphabet. @@ -676,11 +646,9 @@ def operator(self, operator, input_alphabet, def transition_function(state, operands): return (0, operator(*operands)) + pairs = list(product(input_alphabet, repeat=number_of_operands)) - return Transducer(transition_function, - input_alphabet=pairs, - initial_states=[0], - final_states=[0]) + return Transducer(transition_function, input_alphabet=pairs, initial_states=[0], final_states=[0]) def all(self, input_alphabet, number_of_operands=2) -> Transducer: r""" @@ -730,8 +698,7 @@ def all(self, input_alphabet, number_of_operands=2) -> Transducer: sage: T3([(0, 0, 0), (1, 0, 0), (1, 1, 1)]) [False, False, True] """ - return self.operator(lambda *args: all(args), - input_alphabet, number_of_operands) + return self.operator(lambda *args: all(args), input_alphabet, number_of_operands) def any(self, input_alphabet, number_of_operands=2) -> Transducer: r""" @@ -781,8 +748,7 @@ def any(self, input_alphabet, number_of_operands=2) -> Transducer: sage: T3([(0, 0, 0), (1, 0, 0), (1, 1, 1)]) [False, True, True] """ - return self.operator(lambda *args: any(args), - input_alphabet, number_of_operands) + return self.operator(lambda *args: any(args), input_alphabet, number_of_operands) def add(self, input_alphabet, number_of_operands=2) -> Transducer: r""" @@ -834,9 +800,7 @@ def add(self, input_alphabet, number_of_operands=2) -> Transducer: sage: T3([(0, 0, 0), (0, 1, 0), (0, 1, 1), (1, 1, 1)]) [0, 1, 2, 3] """ - return self.operator(lambda *args: sum(args), - input_alphabet, - number_of_operands=number_of_operands) + return self.operator(lambda *args: sum(args), input_alphabet, number_of_operands=number_of_operands) def sub(self, input_alphabet) -> Transducer: r""" @@ -936,12 +900,12 @@ def weight(self, input_alphabet, zero=0) -> Transducer: sage: add(W(['a', 'b', 'b'])) 2 """ + def weight(state, input): weight = int(input != zero) return (0, weight) - return Transducer(weight, input_alphabet=input_alphabet, - initial_states=[0], - final_states=[0]) + + return Transducer(weight, input_alphabet=input_alphabet, initial_states=[0], final_states=[0]) def abs(self, input_alphabet) -> Transducer: r""" @@ -1012,20 +976,11 @@ def GrayCode(self) -> Transducer: """ z = ZZ.zero() o = ZZ.one() - return Transducer([[0, 1, z, None], - [0, 2, o, None], - [1, 1, z, z], - [1, 2, o, o], - [2, 1, z, o], - [2, 2, o, z]], - initial_states=[0], - final_states=[1], - with_final_word_out=[0]) + return Transducer([[0, 1, z, None], [0, 2, o, None], [1, 1, z, z], [1, 2, o, o], [2, 1, z, o], [2, 2, o, z]], initial_states=[0], final_states=[1], with_final_word_out=[0]) RecursionRule = namedtuple('RecursionRule', ['K', 'r', 'k', 's', 't']) - def _parse_recursion_equation_(self, equation, base, function, var, - word_function=None, output_rings=[ZZ, QQ]): + def _parse_recursion_equation_(self, equation, base, function, var, word_function=None, output_rings=[ZZ, QQ]): """ Parse one equation as admissible in :meth:`~.Recursion`. @@ -1236,30 +1191,24 @@ def to_list(output): base_ring = base.parent() if equation.operator() != operator.eq: - raise ValueError("%s is not an equation with ==." - % equation) - assert len(equation.operands()) == 2, \ - "%s is not an equation with two operands." % equation + raise ValueError("%s is not an equation with ==." % equation) + assert len(equation.operands()) == 2, "%s is not an equation with two operands." % equation left_side, right_side = equation.operands() if left_side.operator() != function: - raise ValueError("%s is not an evaluation of %s." - % (left_side, function)) + raise ValueError("%s is not an evaluation of %s." % (left_side, function)) if len(left_side.operands()) != 1: - raise ValueError("%s does not have one argument." % - (left_side,)) + raise ValueError("%s does not have one argument." % (left_side,)) try: polynomial_left = base_ring[var](left_side.operands()[0]) except Exception: - raise ValueError("%s is not a polynomial " - "in %s." % (left_side.operands()[0], var)) + raise ValueError("%s is not a polynomial " "in %s." % (left_side.operands()[0], var)) if polynomial_left in base_ring and is_scalar(right_side): return {polynomial_left: to_list(right_side)} if polynomial_left.degree() != 1: - raise ValueError("%s is not a polynomial of degree 1." - % (polynomial_left,)) + raise ValueError("%s is not a polynomial of degree 1." % (polynomial_left,)) [r, base_power_K] = list(polynomial_left) try: @@ -1271,47 +1220,36 @@ def to_list(output): except AttributeError: pass if K not in ZZ: - raise ValueError("%s is not a power of %s." - % (base_power_K, base)) + raise ValueError("%s is not a power of %s." % (base_power_K, base)) if K < 1: - raise ValueError("%d is less than %d." - % (base_power_K, base)) + raise ValueError("%d is less than %d." % (base_power_K, base)) from sage.symbolic.operators import add_vararg + if right_side.operator() == add_vararg: - function_calls = [o for o in right_side.operands() - if o.operator() == function] - other_terms = [o for o in right_side.operands() - if o.operator() != function] + function_calls = [o for o in right_side.operands() if o.operator() == function] + other_terms = [o for o in right_side.operands() if o.operator() != function] if len(function_calls) != 1: - raise ValueError( - "%s does not contain exactly one summand which " - "is an evaluation of %s." - % (right_side, function)) + raise ValueError("%s does not contain exactly one summand which " "is an evaluation of %s." % (right_side, function)) next_function = function_calls[0] t = sum(other_terms) if not is_scalar(t): - raise ValueError("%s contains %s." - % (t, var)) + raise ValueError("%s contains %s." % (t, var)) else: next_function = right_side t = 0 if next_function.operator() != function: - raise ValueError("%s is not an evaluation of %s." - % (next_function, function)) + raise ValueError("%s is not an evaluation of %s." % (next_function, function)) if len(next_function.operands()) != 1: - raise ValueError("%s does not have exactly one argument." - % (next_function,)) + raise ValueError("%s does not have exactly one argument." % (next_function,)) try: polynomial_right = base_ring[var](next_function.operands()[0]) except Exception: - raise ValueError("%s is not a polynomial in %s." - % (next_function.operands()[0], var)) + raise ValueError("%s is not a polynomial in %s." % (next_function.operands()[0], var)) if polynomial_right.degree() != 1: - raise ValueError("%s is not a polynomial of degree 1." - % (polynomial_right,)) + raise ValueError("%s is not a polynomial of degree 1." % (polynomial_right,)) [s, base_power_k] = list(polynomial_right) k = log(base_power_k, base=base) try: @@ -1319,26 +1257,19 @@ def to_list(output): except AttributeError: pass if k not in ZZ: - raise ValueError("%s is not a power of %s." - % (base_power_k, base)) + raise ValueError("%s is not a power of %s." % (base_power_k, base)) if k < 0: - raise ValueError("%s is less than 1." - % (base_power_k,)) + raise ValueError("%s is less than 1." % (base_power_k,)) if k >= K: - raise ValueError("%d is greater or equal than %d." - % (base_power_k, base_power_K)) + raise ValueError("%d is greater or equal than %d." % (base_power_k, base_power_K)) - parsed_equation = function(base**K * var + r) == \ - function(base**k * var + s) + t - assert equation == parsed_equation, \ - "Parsing of %s failed for unknown reasons." % (equation,) + parsed_equation = function(base**K * var + r) == function(base**k * var + s) + t + assert equation == parsed_equation, "Parsing of %s failed for unknown reasons." % (equation,) rule = self.RecursionRule(K=K, r=r, k=k, s=s, t=to_list(t)) return rule - def Recursion(self, recursions, base, function=None, var=None, - input_alphabet=None, word_function=None, - is_zero=None, output_rings=[ZZ, QQ]) -> Transducer: + def Recursion(self, recursions, base, function=None, var=None, input_alphabet=None, word_function=None, is_zero=None, output_rings=[ZZ, QQ]) -> Transducer: r""" Return a transducer realizing the given recursion when reading the digit expansion with base ``base``. @@ -1780,8 +1711,7 @@ def Recursion(self, recursions, base, function=None, var=None, elif isinstance(equation, tuple) and len(equation) == 2: initial_values[equation[0]] = equation[1] else: - parsed = self._parse_recursion_equation_( - equation, base, function, var, word_function, output_rings) + parsed = self._parse_recursion_equation_(equation, base, function, var, word_function, output_rings) if isinstance(parsed, dict): initial_values.update(parsed) elif isinstance(parsed, self.RecursionRule): @@ -1791,8 +1721,7 @@ def Recursion(self, recursions, base, function=None, var=None, max_K = max(rule.K for rule in rules) - residues = [[None for r in range(base**k)] - for k in range(max_K + 1)] + residues = [[None for r in range(base**k)] for k in range(max_K + 1)] # Aim: residues[K][R] = RuleRight(k, s, t) # if and only if @@ -1800,29 +1729,17 @@ def Recursion(self, recursions, base, function=None, var=None, for given_rule in rules: q, remainder = given_rule.r.quo_rem(base**given_rule.K) - rule = self.RecursionRule(K=given_rule.K, - r=remainder, - k=given_rule.k, - s=given_rule.s - base**given_rule.k * q, - t=given_rule.t) + rule = self.RecursionRule(K=given_rule.K, r=remainder, k=given_rule.k, s=given_rule.s - base**given_rule.k * q, t=given_rule.t) for m in range(max_K - rule.K + 1): for ell in range(base**m): R = rule.r + base**rule.K * ell if residues[rule.K + m][R] is not None: - raise ValueError( - "Conflicting rules congruent to %d modulo %d." - % (R, base**(rule.K + m))) - residues[rule.K + m][R] = RuleRight(k=rule.k + m, - s=rule.s + ell * base**rule.k, - t=rule.t) - - missing_residues = [R - for R, rule in enumerate(residues[max_K]) - if rule is None] + raise ValueError("Conflicting rules congruent to %d modulo %d." % (R, base ** (rule.K + m))) + residues[rule.K + m][R] = RuleRight(k=rule.k + m, s=rule.s + ell * base**rule.k, t=rule.t) + + missing_residues = [R for R, rule in enumerate(residues[max_K]) if rule is None] if missing_residues: - raise ValueError("Missing recursions for input congruent " - "to %s modulo %s." % (missing_residues, - base**max_K)) + raise ValueError("Missing recursions for input congruent " "to %s modulo %s." % (missing_residues, base**max_K)) required_initial_values = set() @@ -1886,8 +1803,7 @@ def recursion_transitions(carry, level, force_nonnegative_target): c, j = (carry, level) output = [] while True: - transition = recursion_transition( - c, j, force_nonnegative_target) + transition = recursion_transition(c, j, force_nonnegative_target) if transition is None: break c, j = transition[0] @@ -1897,21 +1813,17 @@ def recursion_transitions(carry, level, force_nonnegative_target): def transition_function(states2, input): state_carry, state_level = states2 - (carry, level), output = recursion_transitions( - state_carry, state_level, False) + (carry, level), output = recursion_transitions(state_carry, state_level, False) # no more recursion transition is possible, # so this is now a storing transition carry += input * base**level level += 1 # We now may proceed along recursion transitions # as long as the carries stay nonnegative. - carrylevel, new_output = recursion_transitions( - carry, level, True) + carrylevel, new_output = recursion_transitions(carry, level, True) return (carrylevel, output + new_output) - T = Transducer(transition_function, - initial_states=[(0, 0)], - input_alphabet=input_alphabet) + T = Transducer(transition_function, initial_states=[(0, 0)], input_alphabet=input_alphabet) def edge_recursion_digraph(n): r""" @@ -1943,50 +1855,32 @@ def f(n): carries = set(state.label()[0] for state in T.iter_states()) - recursion_digraph = DiGraph( - {carry: dict(edge_recursion_digraph(carry)) - for carry in carries - if carry >= 0}, - multiedges=False) + recursion_digraph = DiGraph({carry: dict(edge_recursion_digraph(carry)) for carry in carries if carry >= 0}, multiedges=False) initial_values_set = set(initial_values) - missing_initial_values = required_initial_values.difference( - initial_values_set) + missing_initial_values = required_initial_values.difference(initial_values_set) if missing_initial_values: - raise ValueError( - "Missing initial values for %s." % - sorted(missing_initial_values)) + raise ValueError("Missing initial values for %s." % sorted(missing_initial_values)) for cycle in recursion_digraph.all_simple_cycles(algorithm="A"): assert cycle[0] is cycle[-1] cycle_set = set(cycle) intersection = cycle_set.intersection(initial_values_set) if not intersection: - raise ValueError( - "Missing initial condition for one of %s." % - cycle[1:]) + raise ValueError("Missing initial condition for one of %s." % cycle[1:]) if len(intersection) > 1: - raise ValueError( - "Too many initial conditions, only give one of %s." % - cycle[1:]) + raise ValueError("Too many initial conditions, only give one of %s." % cycle[1:]) required_initial_values.update(intersection) - output_sum = sum([e[2] - for e in recursion_digraph.outgoing_edge_iterator(cycle[1:])], - []) + output_sum = sum([e[2] for e in recursion_digraph.outgoing_edge_iterator(cycle[1:])], []) if not is_zero(output_sum): - raise ValueError( - "Conflicting recursion for %s." % - cycle[1:]) + raise ValueError("Conflicting recursion for %s." % cycle[1:]) - superfluous_initial_values = initial_values_set.difference( - required_initial_values) + superfluous_initial_values = initial_values_set.difference(required_initial_values) if superfluous_initial_values: - raise ValueError( - "Superfluous initial values for %s." % - sorted(superfluous_initial_values)) + raise ValueError("Superfluous initial values for %s." % sorted(superfluous_initial_values)) for state in T.iter_states(): state.is_final = True diff --git a/src/sage/combinat/fqsym.py b/src/sage/combinat/fqsym.py index e42ce573e77..180a5b8cf0b 100644 --- a/src/sage/combinat/fqsym.py +++ b/src/sage/combinat/fqsym.py @@ -52,10 +52,7 @@ def __init__(self, alg): sage: TestSuite(algebras.FQSym(QQ).F()).run() # long time """ - CombinatorialFreeModule.__init__(self, alg.base_ring(), - Permutations(), - category=FQSymBases(alg), - bracket='', prefix=self._prefix) + CombinatorialFreeModule.__init__(self, alg.base_ring(), Permutations(), category=FQSymBases(alg), bracket='', prefix=self._prefix) def _coerce_map_from_(self, R): r""" @@ -139,8 +136,10 @@ def _coerce_map_from_(self, R): if not self.base_ring().has_coerce_map_from(R.base_ring()): return False if self._basis_name == R._basis_name: # The same basis + def coerce_base_ring(self, x): return self._from_dict(x.monomial_coefficients()) + return coerce_base_ring # Otherwise lift that basis up and then coerce over target = getattr(self.realization_of(), R._basis_name)() @@ -148,6 +147,7 @@ def coerce_base_ring(self, x): # FSym coerces in: from sage.combinat.chas.fsym import FreeSymmetricFunctions + if isinstance(R, FreeSymmetricFunctions.Fundamental): if not self.base_ring().has_coerce_map_from(R.base_ring()): return False @@ -155,8 +155,8 @@ def coerce_base_ring(self, x): P = G._indices def G_to_G_on_basis(t): - return G.sum_of_monomials(P(sigma) for sigma in Permutations(t.size()) - if sigma.right_tableau() == t) + return G.sum_of_monomials(P(sigma) for sigma in Permutations(t.size()) if sigma.right_tableau() == t) + phi = R.module_morphism(G_to_G_on_basis, codomain=G) if self is G: return phi @@ -376,10 +376,8 @@ def __init__(self, R): F = self.F() G = self.G() - F.module_morphism(G._F_to_G_on_basis, - codomain=G, category=category).register_as_coercion() - G.module_morphism(G._G_to_F_on_basis, - codomain=F, category=category).register_as_coercion() + F.module_morphism(G._F_to_G_on_basis, codomain=G, category=category).register_as_coercion() + G.module_morphism(G._G_to_F_on_basis, codomain=F, category=category).register_as_coercion() def _repr_(self): """ @@ -421,6 +419,7 @@ class F(FQSymBasis_abstract): sage: FQSym.F() Free Quasi-symmetric functions over Rational Field in the F basis """ + _prefix = "F" _basis_name = "F" @@ -570,8 +569,7 @@ def succ_product_on_basis(self, x, y): n = len(x) shy = Word([a + n for a in y]) shy0 = shy[0] - return self.sum_of_monomials(K([shy0] + list(u)) - for u in Word(x).shuffle(Word(shy[1:]))) + return self.sum_of_monomials(K([shy0] + list(u)) for u in Word(x).shuffle(Word(shy[1:]))) def prec_product_on_basis(self, x, y): r""" @@ -621,8 +619,7 @@ def prec_product_on_basis(self, x, y): n = len(x) shy = Word([a + n for a in y]) x0 = x[0] - return self.sum_of_monomials(K([x0] + list(u)) - for u in Word(x[1:]).shuffle(shy)) + return self.sum_of_monomials(K([x0] + list(u)) for u in Word(x[1:]).shuffle(shy)) def coproduct_on_basis(self, x): r""" @@ -648,9 +645,7 @@ def coproduct_on_basis(self, x): """ if not x: return self.one().tensor(self.one()) - return sum(self(Word(x[:i]).standard_permutation()).tensor( - self(Word(x[i:]).standard_permutation())) - for i in range(len(x) + 1)) + return sum(self(Word(x[:i]).standard_permutation()).tensor(self(Word(x[i:]).standard_permutation())) for i in range(len(x) + 1)) class Element(FQSymBasis_abstract.Element): def to_symmetric_group_algebra(self, n=None): @@ -719,6 +714,7 @@ class G(FQSymBasis_abstract): + G[5, 1, 4, 3, 2] + G[5, 2, 3, 4, 1] + G[5, 2, 4, 3, 1] + G[5, 3, 4, 2, 1] """ + _prefix = "G" _basis_name = "G" @@ -895,6 +891,7 @@ class M(FQSymBasis_abstract): sage: M([1, 2]) * M([1]) M[1, 2, 3] + 2*M[1, 3, 2] + M[2, 3, 1] + M[3, 1, 2] """ + _prefix = "M" _basis_name = "Monomial" @@ -910,11 +907,9 @@ def __init__(self, alg): FQSymBasis_abstract.__init__(self, alg) F = self.realization_of().F() - phi = F.module_morphism(self._F_to_M_on_basis, codomain=self, - unitriangular='lower') + phi = F.module_morphism(self._F_to_M_on_basis, codomain=self, unitriangular='lower') phi.register_as_coercion() - phi_i = self.module_morphism(self._M_to_F_on_basis, codomain=F, - unitriangular='lower') + phi_i = self.module_morphism(self._M_to_F_on_basis, codomain=F, unitriangular='lower') phi_i.register_as_coercion() def _element_constructor_(self, x): @@ -1107,8 +1102,7 @@ def _M_to_F_on_basis(self, w): w_i = w.inverse() w_i = w_i[:] n = len(w_i) - des = tuple([0] + [g for g in range(1, n) - if w_i[g - 1] > w_i[g]] + [n]) + des = tuple([0] + [g for g in range(1, n) if w_i[g - 1] > w_i[g]] + [n]) non_des = [g for g in range(1, n) if w_i[g - 1] < w_i[g]] # Now, des is a list of all descents of w_i and also 0 and n, # whereas non_des is a list of all non-descents of w_i. @@ -1121,14 +1115,13 @@ def _M_to_F_on_basis(self, w): dc = {w: one} from itertools import combinations + for k in range(len(non_des)): kk = k + len(des) for extra_des in combinations(non_des, k): breakpoints = sorted(des + extra_des) # so that kk == len(breakpoints) - p = sum([w_i[breakpoints[g]: breakpoints[g + 1]][::-1] - for g in range(kk - 1)], - []) + p = sum([w_i[breakpoints[g] : breakpoints[g + 1]][::-1] for g in range(kk - 1)], []) u = Perms(p).inverse() dc[u] = one if n % 2 != kk % 2 else mine @@ -1185,10 +1178,7 @@ def coproduct_on_basis(self, x): n = len(x) if not n: return self.one().tensor(self.one()) - return sum(self(Word(x[:i]).standard_permutation()).tensor( - self(Word(x[i:]).standard_permutation())) - for i in range(n + 1) - if (i == 0 or i == n or min(x[:i]) > max(x[i:]))) + return sum(self(Word(x[:i]).standard_permutation()).tensor(self(Word(x[i:]).standard_permutation())) for i in range(n + 1) if (i == 0 or i == n or min(x[:i]) > max(x[i:]))) class Element(FQSymBasis_abstract.Element): def star_involution(self): @@ -1223,8 +1213,7 @@ def star_involution(self): # See the FQSymBases.ElementMethods.star_involution doc # for the formula we're using here. M = self.parent() - return M._from_dict({w.complement().reverse(): c for w, c in self}, - remove_zeros=False) + return M._from_dict({w.complement().reverse(): c for w, c in self}, remove_zeros=False) class FQSymBases(Category_realization_of_parent): @@ -1280,10 +1269,11 @@ def super_categories(self): Category of graded connected Hopf algebras with basis over Integer Ring] """ R = self.base().base_ring() - return [self.base().Realizations(), - HopfAlgebras(R).Graded().Realizations(), - HopfAlgebras(R).Graded().WithBasis().Graded().Connected(), - ] + return [ + self.base().Realizations(), + HopfAlgebras(R).Graded().Realizations(), + HopfAlgebras(R).Graded().WithBasis().Graded().Connected(), + ] class ParentMethods: def _repr_(self): @@ -1338,6 +1328,7 @@ def basis(self, degree=None): [G[1, 2, 3], G[1, 3, 2], G[2, 1, 3], G[2, 3, 1], G[3, 1, 2], G[3, 2, 1]] """ from sage.sets.family import Family + if degree is None: return Family(self._indices, self.monomial) return Family(Permutations(degree), self.monomial) @@ -1424,9 +1415,7 @@ def succ(self): suc = self.succ_product_on_basis except AttributeError: return self.succ_by_coercion - return self._module_morphism(self._module_morphism(suc, position=0, - codomain=self), - position=1) + return self._module_morphism(self._module_morphism(suc, position=0, codomain=self), position=1) def succ_by_coercion(self, x, y): r""" @@ -1478,9 +1467,7 @@ def prec(self): pre = self.prec_product_on_basis except AttributeError: return self.prec_by_coercion - return self._module_morphism(self._module_morphism(pre, position=0, - codomain=self), - position=1) + return self._module_morphism(self._module_morphism(pre, position=0, codomain=self), position=1) def prec_by_coercion(self, x, y): r""" @@ -1905,6 +1892,7 @@ def to_wqsym(self): FQSym = parent.realization_of() G = FQSym.G() from sage.combinat.chas.wqsym import WordQuasiSymmetricFunctions + M = WordQuasiSymmetricFunctions(parent.base_ring()).M() OSP = M.basis().keys() from sage.combinat.words.finite_word import word_to_ordered_set_partition @@ -1918,8 +1906,8 @@ def to_wqsym_on_G_basis(w): v = w.destandardize(comp) res += M[OSP(word_to_ordered_set_partition(v))] return res - return M.linear_combination((to_wqsym_on_G_basis(w), coeff) - for w, coeff in G(self)) + + return M.linear_combination((to_wqsym_on_G_basis(w), coeff) for w, coeff in G(self)) def to_qsym(self): r""" @@ -1963,6 +1951,6 @@ def to_qsym(self): FQSym = parent.realization_of() F = FQSym.F() from sage.combinat.ncsf_qsym.qsym import QuasiSymmetricFunctions + QF = QuasiSymmetricFunctions(parent.base_ring()).F() - return QF.sum_of_terms((w.descents_composition(), coeff) - for w, coeff in F(self)) + return QF.sum_of_terms((w.descents_composition(), coeff) for w, coeff in F(self)) diff --git a/src/sage/combinat/free_dendriform_algebra.py b/src/sage/combinat/free_dendriform_algebra.py index 8ce67a412bd..7bc393fc8c5 100644 --- a/src/sage/combinat/free_dendriform_algebra.py +++ b/src/sage/combinat/free_dendriform_algebra.py @@ -18,12 +18,8 @@ from sage.categories.hopf_algebras import HopfAlgebras from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.words.alphabet import Alphabet -from sage.combinat.binary_tree import (BinaryTrees, BinaryTree, - LabelledBinaryTrees, - LabelledBinaryTree) -from sage.categories.pushout import (ConstructionFunctor, - CompositeConstructionFunctor, - IdentityConstructionFunctor) +from sage.combinat.binary_tree import BinaryTrees, BinaryTree, LabelledBinaryTrees, LabelledBinaryTree +from sage.categories.pushout import ConstructionFunctor, CompositeConstructionFunctor, IdentityConstructionFunctor from sage.categories.rings import Rings from sage.categories.functor import Functor from sage.misc.lazy_attribute import lazy_attribute @@ -132,6 +128,7 @@ class FreeDendriformAlgebra(CombinatorialFreeModule): - [LR1998]_ """ + @staticmethod def __classcall_private__(cls, R, names=None): """ @@ -179,10 +176,7 @@ def __init__(self, R, names=None): # so that one can restrict the labels to some fixed set cat = HopfAlgebras(R).WithBasis().Graded().Connected() - CombinatorialFreeModule.__init__(self, R, Trees, - latex_prefix='', - sorting_key=key, - category=cat) + CombinatorialFreeModule.__init__(self, R, Trees, latex_prefix='', sorting_key=key, category=cat) def variable_names(self): r""" @@ -427,19 +421,16 @@ def succ_product_on_basis(self, x, y): """ if y.is_empty(): if x.is_empty(): - raise ValueError("dendriform products | < | and | > | are " - "not defined") + raise ValueError("dendriform products | < | and | > | are " "not defined") else: return [] if x.is_empty(): return [y] K = self.basis().keys() if hasattr(y, 'label'): - return self.sum(self.basis()[K([u, y[1]], y.label())] - for u in x.dendriform_shuffle(y[0])) + return self.sum(self.basis()[K([u, y[1]], y.label())] for u in x.dendriform_shuffle(y[0])) - return self.sum(self.basis()[K([u, y[1]])] - for u in x.dendriform_shuffle(y[0])) + return self.sum(self.basis()[K([u, y[1]])] for u in x.dendriform_shuffle(y[0])) @lazy_attribute def succ(self): @@ -466,9 +457,7 @@ def succ(self): B[[[., .], .]] """ suc = self.succ_product_on_basis - return self._module_morphism(self._module_morphism(suc, position=0, - codomain=self), - position=1) + return self._module_morphism(self._module_morphism(suc, position=0, codomain=self), position=1) def prec_product_on_basis(self, x, y): r""" @@ -502,19 +491,16 @@ def prec_product_on_basis(self, x, y): ValueError: dendriform products | < | and | > | are not defined """ if x.is_empty() and y.is_empty(): - raise ValueError("dendriform products | < | and | > | are " - "not defined") + raise ValueError("dendriform products | < | and | > | are " "not defined") if x.is_empty(): return [] if y.is_empty(): return [x] K = self.basis().keys() if hasattr(y, 'label'): - return self.sum(self.basis()[K([x[0], u], x.label())] - for u in x[1].dendriform_shuffle(y)) + return self.sum(self.basis()[K([x[0], u], x.label())] for u in x[1].dendriform_shuffle(y)) - return self.sum(self.basis()[K([x[0], u])] - for u in x[1].dendriform_shuffle(y)) + return self.sum(self.basis()[K([x[0], u])] for u in x[1].dendriform_shuffle(y)) @lazy_attribute def prec(self): @@ -540,9 +526,7 @@ def prec(self): B[[., [., .]]] """ pre = self.prec_product_on_basis - return self._module_morphism(self._module_morphism(pre, position=0, - codomain=self), - position=1) + return self._module_morphism(self._module_morphism(pre, position=0, codomain=self), position=1) @lazy_attribute def over(self): @@ -566,11 +550,11 @@ def over(self): sage: A.over(x, x) B[[., [., .]]] """ + def ov(x, y): return self._monomial(x.over(y)) - return self._module_morphism(self._module_morphism(ov, position=0, - codomain=self), - position=1) + + return self._module_morphism(self._module_morphism(ov, position=0, codomain=self), position=1) @lazy_attribute def under(self): @@ -594,11 +578,11 @@ def under(self): sage: A.under(x, x) B[[[., .], .]] """ + def und(x, y): return self._monomial(x.under(y)) - return self._module_morphism(self._module_morphism(und, position=0, - codomain=self), - position=1) + + return self._module_morphism(self._module_morphism(und, position=0, codomain=self), position=1) def coproduct_on_basis(self, x): """ @@ -635,11 +619,7 @@ def coproduct_on_basis(self, x): except AttributeError: root = '@' resu = self.one().tensor(self.monomial(x)) - resu += sum(cL * cR * - self.monomial(Trees([LL[0], RR[0]], root)).tensor( - self.monomial(LL[1]) * self.monomial(RR[1])) - for LL, cL in self.coproduct_on_basis(L) - for RR, cR in self.coproduct_on_basis(R)) + resu += sum(cL * cR * self.monomial(Trees([LL[0], RR[0]], root)).tensor(self.monomial(LL[1]) * self.monomial(RR[1])) for LL, cL in self.coproduct_on_basis(L) for RR, cR in self.coproduct_on_basis(R)) return resu # after this line : coercion @@ -792,6 +772,7 @@ class DendriformFunctor(ConstructionFunctor): sage: F(f)(a * F(A)(x)) (a+b)*B[x[., .]] """ + rank = 9 def __init__(self, vars): @@ -839,9 +820,8 @@ def _apply_functor_to_morphism(self, f): codom = self(f.codomain()) def action(x): - return codom._from_dict({a: f(b) - for a, b in - x.monomial_coefficients().items()}) + return codom._from_dict({a: f(b) for a, b in x.monomial_coefficients().items()}) + return dom.module_morphism(function=action, codomain=codom) def __eq__(self, other): @@ -894,13 +874,10 @@ def __mul__(self, other): return self if isinstance(other, DendriformFunctor): if set(self.vars).intersection(other.vars): - raise CoercionException("Overlapping variables (%s,%s)" % - (self.vars, other.vars)) + raise CoercionException("Overlapping variables (%s,%s)" % (self.vars, other.vars)) return DendriformFunctor(other.vars + self.vars) - if (isinstance(other, CompositeConstructionFunctor) and - isinstance(other.all[-1], DendriformFunctor)): - return CompositeConstructionFunctor(other.all[:-1], - self * other.all[-1]) + if isinstance(other, CompositeConstructionFunctor) and isinstance(other.all[-1], DendriformFunctor): + return CompositeConstructionFunctor(other.all[:-1], self * other.all[-1]) return CompositeConstructionFunctor(other, self) def merge(self, other): diff --git a/src/sage/combinat/free_module.py b/src/sage/combinat/free_module.py index 7aa2e62f526..a8ae987f225 100644 --- a/src/sage/combinat/free_module.py +++ b/src/sage/combinat/free_module.py @@ -1,6 +1,7 @@ """ Free modules """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # 2007-2009 Nicolas M. Thiery @@ -269,8 +270,7 @@ class CombinatorialFreeModule(UniqueRepresentation, Module, IndexedGenerators): """ @staticmethod - def __classcall_private__(cls, base_ring, basis_keys=None, category=None, - prefix=None, names=None, **keywords): + def __classcall_private__(cls, base_ring, basis_keys=None, category=None, prefix=None, names=None, **keywords): """ TESTS:: @@ -329,9 +329,7 @@ def __classcall_private__(cls, base_ring, basis_keys=None, category=None, latex_names = tuple(latex_names) keywords['latex_names'] = latex_names - return super().__classcall__(cls, - base_ring, basis_keys, category=category, prefix=prefix, names=names, - **keywords) + return super().__classcall__(cls, base_ring, basis_keys, category=category, prefix=prefix, names=names, **keywords) Element = IndexedFreeModuleElement @@ -365,13 +363,9 @@ def element_class(self): sage: A.__class__.element_class.__module__ # needs sage.combinat 'sage.combinat.free_module' """ - return self.__make_element_class__(self.Element, - name="%s.element_class" % self.__class__.__name__, - module=self.__class__.__module__, - inherit=True) + return self.__make_element_class__(self.Element, name="%s.element_class" % self.__class__.__name__, module=self.__class__.__module__, inherit=True) - def __init__(self, R, basis_keys=None, element_class=None, category=None, - prefix=None, names=None, **kwds): + def __init__(self, R, basis_keys=None, element_class=None, category=None, prefix=None, names=None, **kwds): r""" TESTS:: @@ -429,6 +423,7 @@ def __init__(self, R, basis_keys=None, element_class=None, category=None, """ # Make sure R is a ring with unit element from sage.categories.rings import Rings + if R not in Rings(): raise TypeError("argument R must be a ring") @@ -484,8 +479,8 @@ def construction(self): # The construction is not suitable for subclasses return None from sage.categories.pushout import VectorFunctor - return VectorFunctor(None, True, None, with_basis='standard', - basis_keys=self.basis().keys()), self.base_ring() + + return VectorFunctor(None, True, None, with_basis='standard', basis_keys=self.basis().keys()), self.base_ring() def change_ring(self, R): r""" @@ -522,10 +517,12 @@ def change_ring(self, R): if construction is not None: functor, args = construction from sage.categories.pushout import VectorFunctor + if isinstance(functor, VectorFunctor): return functor(R) from sage.categories.tensor import TensorProductFunctor from sage.categories.cartesian_product import CartesianProductFunctor + if isinstance(functor, (TensorProductFunctor, CartesianProductFunctor)): return functor([f.change_ring(R) for f in args]) raise NotImplementedError('the method change_ring() has not yet been implemented') @@ -755,10 +752,7 @@ def _element_constructor_(self, x): raise TypeError("do not know how to make x (= %s) an element of %s" % (x, self)) # x is an element of the basis enumerated set; # This is a very ugly way of testing this - elif ((hasattr(self._indices, 'element_class') and - isinstance(self._indices.element_class, type) and - isinstance(x, self._indices.element_class)) or - parent(x) == self._indices): + elif (hasattr(self._indices, 'element_class') and isinstance(self._indices.element_class, type) and isinstance(x, self._indices.element_class)) or parent(x) == self._indices: return self.monomial(x) elif x in self._indices: return self.monomial(self._indices(x)) @@ -789,12 +783,11 @@ def _convert_map_from_(self, S): sage: E._convert_map_from_(ZZ) """ from sage.structure.formal_sum import FormalSums + K = self.base_ring() if isinstance(S, FormalSums) and K.has_coerce_map_from(S.base_ring()): G = self.basis().keys() - return SetMorphism(S.Hom(self, category=self.category() | S.category()), - lambda x: self.sum_of_terms((G(g), K(c)) - for c, g in x)) + return SetMorphism(S.Hom(self, category=self.category() | S.category()), lambda x: self.sum_of_terms((G(g), K(c)) for c, g in x)) def _first_ngens(self, n): """ @@ -860,8 +853,7 @@ def _coerce_map_from_(self, R): pass else: if CR == self: - return lambda parent, x: self._from_dict(x._monomial_coefficients, - coerce=True, remove_zeros=True) + return lambda parent, x: self._from_dict(x._monomial_coefficients, coerce=True, remove_zeros=True) return super()._coerce_map_from_(R) def dimension(self): @@ -946,6 +938,7 @@ def set_order(self, order): """ self._order = order from sage.combinat.ranker import rank_from_list + self._rank_basis = rank_from_list(self._order) @cached_method @@ -1023,11 +1016,9 @@ def from_vector(self, vector, order=None, coerce=True): if order is None: order = self.get_order() if not coerce or vector.base_ring() is self.base_ring(): - return self._from_dict({order[i]: c for i, c in vector.items()}, - coerce=False) + return self._from_dict({order[i]: c for i, c in vector.items()}, coerce=False) R = self.base_ring() - return self._from_dict({order[i]: R(c) for i, c in vector.items() if R(c)}, - coerce=False, remove_zeros=False) + return self._from_dict({order[i]: R(c) for i, c in vector.items() if R(c)}, coerce=False, remove_zeros=False) def sum(self, iter_of_elements): """ @@ -1075,10 +1066,7 @@ def linear_combination(self, iter_of_elements_coeff, factor_on_left=True): sage: F.linear_combination( (f,i) for i in range(5) ) 20*B[1] + 20*B[2] """ - return self._from_dict(blas.linear_combination(((element._monomial_coefficients, coeff) - for element, coeff in iter_of_elements_coeff), - factor_on_left=factor_on_left), - remove_zeros=False) + return self._from_dict(blas.linear_combination(((element._monomial_coefficients, coeff) for element, coeff in iter_of_elements_coeff), factor_on_left=factor_on_left), remove_zeros=False) def term(self, index, coeff=None): """ @@ -1135,6 +1123,7 @@ def monomial(self): """ # Should use a real Map, as soon as combinatorial_classes are enumerated sets, and therefore parents from sage.categories.poor_man_map import PoorManMap + return PoorManMap(self._monomial, domain=self._indices, codomain=self, name="Term map") def _sum_of_monomials(self, indices): @@ -1345,6 +1334,7 @@ class CombinatorialFreeModule_Tensor(CombinatorialFreeModule): sage: tensor([F, tensor([G, H])]) == tensor([F, G, H]) True """ + @staticmethod def __classcall_private__(cls, modules, **options): """ @@ -1364,7 +1354,7 @@ def __classcall_private__(cls, modules, **options): sage: T in Modules(ZZ).FiniteDimensional() True """ - assert (len(modules) > 0) + assert len(modules) > 0 R = modules[0].base_ring() assert (all(module in ModulesWithBasis(R)) for module in modules) # should check the base ring @@ -1382,8 +1372,7 @@ def __init__(self, modules, **options): F """ self._sets = modules - indices = CartesianProduct_iters(*[module.basis().keys() - for module in modules]).map(tuple, is_injective=True) + indices = CartesianProduct_iters(*[module.basis().keys() for module in modules]).map(tuple, is_injective=True) CombinatorialFreeModule.__init__(self, modules[0].base_ring(), indices, **options) # the following is not the best option, but it's better than nothing. if 'tensor_symbol' in options: @@ -1412,6 +1401,7 @@ def _repr_(self): sage: T.print_options(tensor_symbol=' # ') """ from sage.categories.tensor import tensor + if hasattr(self, "_print_options"): symb = self._print_options['tensor_symbol'] if symb is None: @@ -1461,9 +1451,7 @@ def _ascii_art_(self, term): symb = tensor.symbol else: symb = tensor.symbol - return ascii_art(*(module._ascii_art_term(t) - for module, t in zip(self._sets, term)), - sep=AsciiArt([symb], breakpoints=[len(symb)])) + return ascii_art(*(module._ascii_art_term(t) for module, t in zip(self._sets, term)), sep=AsciiArt([symb], breakpoints=[len(symb)])) _ascii_art_term = _ascii_art_ @@ -1491,9 +1479,7 @@ def _unicode_art_(self, term): symb = tensor.unicode_symbol else: symb = tensor.unicode_symbol - return unicode_art(*(module._unicode_art_term(t) - for module, t in zip(self._sets, term)), - sep=UnicodeArt([symb], breakpoints=[len(symb)])) + return unicode_art(*(module._unicode_art_term(t) for module, t in zip(self._sets, term)), sep=UnicodeArt([symb], breakpoints=[len(symb)])) _unicode_art_term = _unicode_art_ @@ -1587,15 +1573,14 @@ def tensor_constructor(self, modules): + 2*B[2] # B[4] # B[5] + 2*B[2] # B[4] # B[6] """ assert (module in ModulesWithBasis(self.base_ring()) for module in modules) - assert (tensor(modules) == self) + assert tensor(modules) == self # a list l such that l[i] is True if modules[i] is readily a tensor product is_tensor = [isinstance(module, CombinatorialFreeModule_Tensor) for module in modules] # the tensor_constructor, on basis elements result = self.monomial * CartesianProductWithFlattening(is_tensor) # TODO: make this into an element of Hom( A x B, C ) when those will exist for i in range(len(modules)): - result = modules[i]._module_morphism(result, position=i, - codomain=self) + result = modules[i]._module_morphism(result, position=i, codomain=self) return result def _tensor_of_elements(self, elements): @@ -1678,18 +1663,10 @@ def _coerce_map_from_(self, R): sage: T(tensor((p,p))) 4*B[2] # B[2] + 4*B[2] # B[4] + 4*B[4] # B[2] + 4*B[4] # B[4] """ - if ((R in ModulesWithBasis(self.base_ring()).TensorProducts() or - R in GradedAlgebrasWithBasis(self.base_ring()).SignedTensorProducts()) - and isinstance(R, CombinatorialFreeModule_Tensor) - and len(R._sets) == len(self._sets) - and all(self._sets[i].has_coerce_map_from(M) - for i, M in enumerate(R._sets))): + if (R in ModulesWithBasis(self.base_ring()).TensorProducts() or R in GradedAlgebrasWithBasis(self.base_ring()).SignedTensorProducts()) and isinstance(R, CombinatorialFreeModule_Tensor) and len(R._sets) == len(self._sets) and all(self._sets[i].has_coerce_map_from(M) for i, M in enumerate(R._sets)): modules = R._sets - vector_map = [self._sets[i]._internal_coerce_map_from(M) - for i, M in enumerate(modules)] - return R.module_morphism(lambda x: self._tensor_of_elements( - [vector_map[i](M.monomial(x[i])) - for i, M in enumerate(modules)]), codomain=self) + vector_map = [self._sets[i]._internal_coerce_map_from(M) for i, M in enumerate(modules)] + return R.module_morphism(lambda x: self._tensor_of_elements([vector_map[i](M.monomial(x[i])) for i, M in enumerate(modules)]), codomain=self) return super()._coerce_map_from_(R) @@ -1727,8 +1704,7 @@ def __call__(self, *indices): sage: cp((1,2,3), 4, (5,6), (7,8)) (1, 2, 3, 4, 5, 6, 7, 8) """ - return sum((i if flatten else (i,) - for (i, flatten) in zip(indices, self._flatten)), ()) + return sum((i if flatten else (i,) for (i, flatten) in zip(indices, self._flatten)), ()) # TODO: find a way to avoid this hack to allow for cross references @@ -1777,6 +1753,7 @@ class CombinatorialFreeModule_CartesianProduct(CombinatorialFreeModule): sage: S = cartesian_product([cartesian_product([F, G]), H]) # todo: not implemented F (+) G (+) H """ + @staticmethod def __classcall_private__(cls, modules, category, **options): """ @@ -1794,6 +1771,7 @@ def __classcall_private__(cls, modules, category, **options): Cat = ModulesWithBasis(R) if any(module not in Cat for module in modules): from sage.sets.cartesian_product import CartesianProduct + return CartesianProduct(modules, category, **options) return super().__classcall__(cls, modules, category=category, **options) @@ -1812,10 +1790,7 @@ def __init__(self, modules, **options): assert all(module in ModulesWithBasis(R) for module in modules) # should check the base ring self._sets = modules - CombinatorialFreeModule.__init__(self, R, - DisjointUnionEnumeratedSets( - [module.basis().keys() for module in modules], keepkey=True), - **options) + CombinatorialFreeModule.__init__(self, R, DisjointUnionEnumeratedSets([module.basis().keys() for module in modules], keepkey=True), **options) def _sets_keys(self): """ @@ -1842,8 +1817,8 @@ def _repr_(self): F (+) F """ from sage.categories.cartesian_product import cartesian_product - return cartesian_product.symbol.join("%s" % module - for module in self._sets) + + return cartesian_product.symbol.join("%s" % module for module in self._sets) # TODO: make this overridable by setting _name @cached_method @@ -1875,8 +1850,7 @@ def cartesian_embedding(self, i): AssertionError """ assert i in self._sets_keys() - return self._sets[i]._module_morphism(lambda t: self.monomial((i, t)), - codomain=self) + return self._sets[i]._module_morphism(lambda t: self.monomial((i, t)), codomain=self) summand_embedding = cartesian_embedding @@ -1951,9 +1925,7 @@ def _cartesian_product_of_elements(self, elements): sage: CP.one() B[(0, 0)] + B[(1, 0)] """ - return self.sum(self.summand_embedding(i)(element_i) - for (i, element_i) in zip(self._sets_keys(), - elements)) + return self.sum(self.summand_embedding(i)(element_i) for (i, element_i) in zip(self._sets_keys(), elements)) def cartesian_factors(self): """ diff --git a/src/sage/combinat/free_prelie_algebra.py b/src/sage/combinat/free_prelie_algebra.py index e6e02b047bc..46a8251632a 100644 --- a/src/sage/combinat/free_prelie_algebra.py +++ b/src/sage/combinat/free_prelie_algebra.py @@ -20,18 +20,14 @@ from sage.categories.magmatic_algebras import MagmaticAlgebras from sage.categories.lie_algebras import LieAlgebras from sage.categories.magmas import Magmas -from sage.categories.pushout import (ConstructionFunctor, - CompositeConstructionFunctor, - IdentityConstructionFunctor) +from sage.categories.pushout import ConstructionFunctor, CompositeConstructionFunctor, IdentityConstructionFunctor from sage.categories.rings import Rings from sage.categories.functor import Functor from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.integer_vector import IntegerVectors from sage.combinat.words.alphabet import Alphabet -from sage.combinat.rooted_tree import (RootedTrees, RootedTree, - LabelledRootedTrees, - LabelledRootedTree) +from sage.combinat.rooted_tree import RootedTrees, RootedTree, LabelledRootedTrees, LabelledRootedTree from sage.combinat.grossman_larson_algebras import GrossmanLarsonAlgebra, ROOT from sage.misc.lazy_attribute import lazy_attribute @@ -174,6 +170,7 @@ class FreePreLieAlgebra(CombinatorialFreeModule): - [Liv2006]_ """ + @staticmethod def __classcall_private__(cls, R, names=None): """ @@ -226,10 +223,7 @@ def __init__(self, R, names=None): # so that one can restrict the labels to some fixed set cat = MagmaticAlgebras(R).WithBasis().Graded() & LieAlgebras(R).WithBasis().Graded() - CombinatorialFreeModule.__init__(self, R, Trees, - latex_prefix='', - sorting_key=key, - category=cat) + CombinatorialFreeModule.__init__(self, R, Trees, latex_prefix='', sorting_key=key, category=cat) def variable_names(self): r""" @@ -463,9 +457,7 @@ def pre_Lie_product(self): B[[[[[]]]]] + B[[[], [[]]]] """ plb = self.pre_Lie_product_on_basis - return self._module_morphism(self._module_morphism(plb, position=0, - codomain=self), - position=1) + return self._module_morphism(self._module_morphism(plb, position=0, codomain=self), position=1) def bracket_on_basis(self, x, y): r""" @@ -527,10 +519,7 @@ def nap_product(self): B[[[], [[]]]] """ npb = self.nap_product_on_basis - return self._module_morphism(self._module_morphism(npb, - position=0, - codomain=self), - position=1) + return self._module_morphism(self._module_morphism(npb, position=0, codomain=self), position=1) def corolla(self, x, y, n, N): """ @@ -604,10 +593,9 @@ def corolla(self, x, y, n, N): xx = x.truncate(max_x + 1) yy = y.truncate(max_y + 1) - y_homog = {i: list(yy.homogeneous_component(i)) - for i in range(vy, max_y + 1)} + y_homog = {i: list(yy.homogeneous_component(i)) for i in range(vy, max_y + 1)} resu = self.zero() - for k in range(min_deg, N + 1): # total degree of (x ; y, y, y, y) + for k in range(min_deg, N + 1): # total degree of (x ; y, y, y, y) for mx, coef_x in xx: dx = mx.number_of_nodes() step = self.zero() @@ -615,8 +603,7 @@ def corolla(self, x, y, n, N): for ly in product(*[y_homog[part] for part in pi]): coef_y = basering.prod(mc[1] for mc in ly) arbres_y = [mc[0] for mc in ly] - step += coef_y * self.sum(self(t) - for t in corolla_gen(mx, arbres_y, labels)) + step += coef_y * self.sum(self(t) for t in corolla_gen(mx, arbres_y, labels)) resu += coef_x * step return resu @@ -658,8 +645,7 @@ def group_product(self, x, y, n, N=10): B[@[]] + B[@[O[]]] + 1/2*B[@[O[], O[]]] + 1/6*B[@[O[], O[], O[]]] """ br = self.base_ring() - return x + self.sum(self.corolla(x, y, i, N) * ~br(factorial(i)) - for i in range(1, n + 1)) + return x + self.sum(self.corolla(x, y, i, N) * ~br(factorial(i)) for i in range(1, n + 1)) def _element_constructor_(self, x): r""" @@ -691,8 +677,7 @@ def _element_constructor_(self, x): ... TypeError: not able to convert this to this algebra """ - if (isinstance(x, (RootedTree, LabelledRootedTree)) and - x in self.basis().keys()): + if isinstance(x, (RootedTree, LabelledRootedTree)) and x in self.basis().keys(): return self.monomial(x) try: P = x.parent() @@ -830,8 +815,7 @@ def lift(self): """ UEA = self.parent()._construct_UEA() LRT = UEA.basis().keys() - data = {LRT([x], ROOT): cf - for x, cf in self.monomial_coefficients(copy=False).items()} + data = {LRT([x], ROOT): cf for x, cf in self.monomial_coefficients(copy=False).items()} return UEA.element_class(UEA, data) def valuation(self): @@ -893,6 +877,7 @@ class PreLieFunctor(ConstructionFunctor): sage: F(f)(a * F(A)(x)) (a+b)*B[x[]] """ + rank = 9 def __init__(self, vars): @@ -940,8 +925,8 @@ def _apply_functor_to_morphism(self, f): codom = self(f.codomain()) def action(x): - return codom._from_dict({a: f(b) - for a, b in x.monomial_coefficients().items()}) + return codom._from_dict({a: f(b) for a, b in x.monomial_coefficients().items()}) + return dom.module_morphism(function=action, codomain=codom) def __eq__(self, other): @@ -978,13 +963,10 @@ def __mul__(self, other): return self if isinstance(other, PreLieFunctor): if set(self.vars).intersection(other.vars): - raise CoercionException("Overlapping variables (%s,%s)" % - (self.vars, other.vars)) + raise CoercionException("Overlapping variables (%s,%s)" % (self.vars, other.vars)) return PreLieFunctor(other.vars + self.vars) - if (isinstance(other, CompositeConstructionFunctor) and - isinstance(other.all[-1], PreLieFunctor)): - return CompositeConstructionFunctor(other.all[:-1], - self * other.all[-1]) + if isinstance(other, CompositeConstructionFunctor) and isinstance(other.all[-1], PreLieFunctor): + return CompositeConstructionFunctor(other.all[:-1], self * other.all[-1]) return CompositeConstructionFunctor(other, self) def merge(self, other): @@ -1130,10 +1112,8 @@ def corolla_gen(tx, list_ty, labels=True): for pos_t in sorted_data: if labels: idx, lbl = new_zx[pos_t[0]] - new_zx = (new_zx[:pos_t[0]] + ((idx + 1, lbl),) + - pos_t[1] + new_zx[pos_t[0] + 1:]) + new_zx = new_zx[: pos_t[0]] + ((idx + 1, lbl),) + pos_t[1] + new_zx[pos_t[0] + 1 :] else: idx = new_zx[pos_t[0]] - new_zx = (new_zx[:pos_t[0]] + (idx + 1,) + - pos_t[1] + new_zx[pos_t[0] + 1:]) + new_zx = new_zx[: pos_t[0]] + (idx + 1,) + pos_t[1] + new_zx[pos_t[0] + 1 :] yield tree_from_sortkey(new_zx, labels=labels)[0] diff --git a/src/sage/combinat/fully_commutative_elements.py b/src/sage/combinat/fully_commutative_elements.py index 789ebf8672a..e0cf4eedfbf 100644 --- a/src/sage/combinat/fully_commutative_elements.py +++ b/src/sage/combinat/fully_commutative_elements.py @@ -165,13 +165,13 @@ def is_fully_commutative(self): I = group.index_set() from sage.rings.integer_ring import ZZ + be_careful = any(i not in ZZ for i in I) if be_careful: Iinv = {i: j for j, i in enumerate(I)} word = [Iinv[i] for i in word] - braid_rels = [[[Iinv[i] for i in l], - [Iinv[i] for i in r]] for l, r in braid_rels] + braid_rels = [[[Iinv[i] for i in l], [Iinv[i] for i in r]] for l, r in braid_rels] return is_fully_comm(word, braid_rels) @@ -217,16 +217,14 @@ def heap(self, **kargs): one_index = kargs.get('one_index', False) display_labeling = kargs.get('display_labeling', False) # elements of the poset: - elements = list(range(1, len(self) + 1) - ) if one_index else list(range(len(self))) + elements = list(range(1, len(self) + 1)) if one_index else list(range(len(self))) # get the label of each poset element: def letter(index): return self[index - 1] if one_index else self[index] # specify the partial order: - relations = [(i, j) for i in elements for j in elements - if i < j and m[letter(i), letter(j)] != 2] + relations = [(i, j) for i in elements for j in elements if i < j and m[letter(i), letter(j)] != 2] p = Poset((elements, relations)) if not display_labeling: @@ -276,18 +274,14 @@ def plot_heap(self): x = self[i] # Draw the node - graphics.append(plot.circle( - (x, level), 0.1, fill=True, facecolor='white', edgecolor='blue', zorder=1)) - graphics.append( - plot.text(str(x), (x, level), color='blue', zorder=2)) + graphics.append(plot.circle((x, level), 0.1, fill=True, facecolor='white', edgecolor='blue', zorder=1)) + graphics.append(plot.text(str(x), (x, level), color='blue', zorder=2)) neighbors = {z for z in letters if m[x, z] >= 3} for other in neighbors: - highest_level = max( - (j + 1 for j in range(level_zero_index) if other in letters_at_level[j]), default=None) + highest_level = max((j + 1 for j in range(level_zero_index) if other in letters_at_level[j]), default=None) if highest_level: - graphics.append( - plot.line([(other, highest_level), (x, level)], color='black', zorder=0)) + graphics.append(plot.line([(other, highest_level), (x, level)], color='black', zorder=0)) g = sum(graphics) g.axes(False) @@ -487,8 +481,8 @@ def coset_decomposition(self, J, side='left'): especially simple for FC elements because descents are easier to find for FC elements. """ - string = [] # to record w_J - remaining = self.clone() # to record w^J + string = [] # to record w_J + remaining = self.clone() # to record w^J if side == 'right': remaining._set_list(remaining[::-1]) @@ -867,6 +861,7 @@ class FullyCommutativeElements(UniqueRepresentation, Parent): sage: CoxeterGroup('B4~xE8~').fully_commutative_elements().category() Category of infinite enumerated sets """ + @staticmethod def __classcall_private__(cls, data): r""" @@ -1018,8 +1013,7 @@ def __iter__(self): for w in recent_words: for s in letters: if w._still_reduced_fc_after_prepending(s): - sw = self.element_class( - self, [s] + list(w), check=False) + sw = self.element_class(self, [s] + list(w), check=False) # "Add" sw to the "set" new_words[sw] = True for w in new_words: diff --git a/src/sage/combinat/fully_packed_loop.py b/src/sage/combinat/fully_packed_loop.py index 1e8c626f5d2..49a462ab3fc 100644 --- a/src/sage/combinat/fully_packed_loop.py +++ b/src/sage/combinat/fully_packed_loop.py @@ -32,9 +32,7 @@ from sage.structure.element import parent, Element from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets -from sage.combinat.six_vertex_model import (SquareIceModel, - SixVertexConfiguration, - SixVertexModel) +from sage.combinat.six_vertex_model import SquareIceModel, SixVertexConfiguration, SixVertexModel from sage.combinat.alternating_sign_matrix import AlternatingSignMatrix from sage.misc.decorators import options @@ -52,13 +50,13 @@ FPL_edges = ( # 0 UD 1 RD, 2 UR, 3 LR, 4 LD 5 LU ((D, U), (L, D), (D, R), (R, L), (L, U), (R, U)), # even - ((R, L), (R, U), (L, U), (D, U), (D, R), (L, D)) # odd + ((R, L), (R, U), (L, U), (D, U), (D, R), (L, D)), # odd ) FPL_turns = ( # 0 UD 1 RD 2 UR 3 LR 4 LD 5 LU ({U: U, D: D}, {R: D, U: L}, {U: R, L: D}, {L: L, R: R}, {R: U, D: L}, {L: U, D: R}), # even - ({L: L, R: R}, {L: U, D: R}, {R: U, D: L}, {U: U, D: D}, {U: R, L: D}, {R: D, U: L}) # odd + ({L: L, R: R}, {L: U, D: R}, {R: U, D: L}, {U: U, D: D}, {U: R, L: D}, {R: D, U: L}), # odd ) @@ -93,6 +91,7 @@ def _make_color_list(n, colors=None, color_map=None, randomize=False): elif color_map: from matplotlib import cm + if color_map not in cm.datad: raise ValueError('unknown color map %s' % color_map) cmap = cm.__dict__[color_map] @@ -100,6 +99,7 @@ def _make_color_list(n, colors=None, color_map=None, randomize=False): if colors and randomize: from sage.misc.prandom import shuffle + shuffle(colors) return colors @@ -485,6 +485,7 @@ class FullyPackedLoop(Element, metaclass=InheritComparisonClasscallMetaclass): - [Pro2001]_ - [Str2015]_ """ + @staticmethod def __classcall_private__(cls, generator): """ @@ -529,8 +530,7 @@ def __classcall_private__(cls, generator): SVM = generator elif isinstance(generator, SixVertexConfiguration): # Check that this is an ice square model - generator = SixVertexModel(generator.parent()._nrows, - boundary_conditions='ice')(generator) + generator = SixVertexModel(generator.parent()._nrows, boundary_conditions='ice')(generator) M = generator.to_alternating_sign_matrix().to_matrix() AlternatingSignMatrix(M) SVM = generator @@ -545,8 +545,7 @@ def __classcall_private__(cls, generator): SVM = generator if not SVM: - raise TypeError('generator for FullyPackedLoop must either be an ' - 'AlternatingSignMatrix or a SquareIceModel.Element') + raise TypeError('generator for FullyPackedLoop must either be an ' 'AlternatingSignMatrix or a SquareIceModel.Element') FPLs = FullyPackedLoops(len(SVM)) return FPLs(generator) @@ -610,19 +609,9 @@ def _repr_(self): # List are in the order of URDL # One set of rules for how to draw around even vertex, one set of rules for odd vertex n = len(self._six_vertex_model) - 1 - ascii1 = [[r' ', ' ─', r' ', '─ '], # LR - [r' │ ', ' ', r' ', '─ '], # LU - [r' ', ' ', r' │ ', '─ '], # LD - [r' │ ', ' ', r' │ ', ' '], # UD - [r' │ ', ' ─', r' ', ' '], # UR - [r' ', ' ─', r' │ ', ' ']] # RD - - ascii2 = [[r' │ ', ' ', r' │ ', ' '], # LR - [r' ', ' ─', r' │ ', ' '], # LU - [r' │ ', ' ─', r' ', ' '], # LD - [r' ', ' ─', r' ', '─ '], # UD - [r' ', ' ', r' │ ', '─ '], # UR - [r' │ ', ' ', r' ', '─ ']] # RD + ascii1 = [[r' ', ' ─', r' ', '─ '], [r' │ ', ' ', r' ', '─ '], [r' ', ' ', r' │ ', '─ '], [r' │ ', ' ', r' │ ', ' '], [r' │ ', ' ─', r' ', ' '], [r' ', ' ─', r' │ ', ' ']] # LR # LU # LD # UD # UR # RD + + ascii2 = [[r' │ ', ' ', r' │ ', ' '], [r' ', ' ─', r' │ ', ' '], [r' │ ', ' ─', r' ', ' '], [r' ', ' ─', r' ', '─ '], [r' ', ' ', r' │ ', '─ '], [r' │ ', ' ', r' ', '─ ']] # LR # LU # LD # UD # UR # RD ret = ' ' # Do the top line for i, entry in enumerate(self._six_vertex_model[0]): @@ -871,17 +860,14 @@ def plot(self, **options): # UD boundaries => even sum rank = self.parent()._boundary_index unrank = self.parent()._boundary - seen = [False] * (2*n) + seen = [False] * (2 * n) squares = set((i, j) for i in range(n) for j in range(n)) - colors = _make_color_list(2*n, - colors=link_options.pop('colors', None), - color_map=link_options.pop('color_map', None), - randomize=link_options.pop('color_randomize', False)) + colors = _make_color_list(2 * n, colors=link_options.pop('colors', None), color_map=link_options.pop('color_map', None), randomize=link_options.pop('color_randomize', False)) G = Graphics() - for i in range(2*n): + for i in range(2 * n): if seen[i]: continue orbit = self._link_or_loop_from(unrank(i)) @@ -904,10 +890,7 @@ def plot(self, **options): squares.difference_update(orbit) if loop: - colors = _make_color_list(len(loops), - colors=loop_options.pop('colors', None), - color_map=loop_options.pop('color_map', None), - randomize=loop_options.pop('color_randomize', False)) + colors = _make_color_list(len(loops), colors=loop_options.pop('colors', None), color_map=loop_options.pop('color_map', None), randomize=loop_options.pop('color_randomize', False)) fill = loop_options.pop('fill') @@ -1021,7 +1004,7 @@ def _link_or_loop_from(self, pos, d0=None): if d0 is None and i0 != -1 and i0 != n and j0 != -1 and j0 != n: # only half of a link -> compute the other half i1, j1 = orbit[1] - d = (i0-i1, j0-j1) + d = (i0 - i1, j0 - j1) orbit2 = self._link_or_loop_from(orbit[1], d) assert orbit2[0] == (i1, j1) and orbit2[1] == (i0, j0) return orbit2[:1:-1] + orbit @@ -1136,12 +1119,12 @@ def link_pattern(self): """ link_pattern = [] n = len(self._six_vertex_model) - seen = [False] * (2*n) + seen = [False] * (2 * n) unrank = self.parent()._boundary rank = self.parent()._boundary_index sv = self._six_vertex_model - for k in range(2*n): + for k in range(2 * n): if seen[k]: continue @@ -1171,7 +1154,7 @@ def link_pattern(self): # update seen and link_pattern l = rank((i, j)) seen[k] = seen[l] = True - link_pattern.append((k+1, l+1)) + link_pattern.append((k + 1, l + 1)) return link_pattern @@ -1356,8 +1339,7 @@ def _element_constructor_(self, generator): """ if isinstance(generator, AlternatingSignMatrix): SVM = generator.to_six_vertex_model() - elif isinstance(generator, (SquareIceModel.Element, - SixVertexConfiguration)): + elif isinstance(generator, (SquareIceModel.Element, SixVertexConfiguration)): SVM = generator else: # Not ASM nor SVM try: @@ -1399,8 +1381,7 @@ def cardinality(self): sage: [AlternatingSignMatrices(n).cardinality() for n in range(10)] [1, 1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460] """ - return Integer(prod(factorial(3 * k + 1) / factorial(self._n + k) - for k in range(self._n))) + return Integer(prod(factorial(3 * k + 1) / factorial(self._n + k) for k in range(self._n))) def _an_element_(self): """ @@ -1446,19 +1427,19 @@ def _boundary(self, k): True """ n = self._n - n_LR = n//2 if n % 2 == 0 else (n+1) // 2 - n_TB = n//2 if n % 2 == 0 else (n-1) // 2 + n_LR = n // 2 if n % 2 == 0 else (n + 1) // 2 + n_TB = n // 2 if n % 2 == 0 else (n - 1) // 2 if k < n_LR: - return (-1, 2*k) + return (-1, 2 * k) k -= n_LR if k < n_TB: - return (n % 2 + 2*k, n) + return (n % 2 + 2 * k, n) k -= n_TB if k < n_LR: - return (n, n - 1 - 2*k) + return (n, n - 1 - 2 * k) k -= n_LR if k < n_TB: - return (n - 1 - n % 2 - 2*k, -1) + return (n - 1 - n % 2 - 2 * k, -1) def _boundary_index(self, pos): r""" @@ -1481,7 +1462,7 @@ def _boundary_index(self, pos): n = self._n i, j = pos if i == -1: - return j//2 + return j // 2 if j == n: return (n + 1) // 2 + i // 2 if i == n: diff --git a/src/sage/combinat/gelfand_tsetlin_patterns.py b/src/sage/combinat/gelfand_tsetlin_patterns.py index 6da6d215d57..de05216edb1 100644 --- a/src/sage/combinat/gelfand_tsetlin_patterns.py +++ b/src/sage/combinat/gelfand_tsetlin_patterns.py @@ -5,6 +5,7 @@ - Travis Scrimshaw (2013-15-03): initial version """ + # **************************************************************************** # Copyright (C) 2013 Travis Scrimshaw # @@ -36,8 +37,7 @@ from sage.misc.misc_c import prod -class GelfandTsetlinPattern(ClonableArray, - metaclass=InheritComparisonClasscallMetaclass): +class GelfandTsetlinPattern(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): r""" A Gelfand-Tsetlin (sometimes written as Gelfand-Zetlin or Gelfand-Cetlin) pattern. They were originally defined in [GC50]_. @@ -118,6 +118,7 @@ class GelfandTsetlinPattern(ClonableArray, 2 2 2 2 2 3 3 3 3 3 4 """ + # Note that the width == height, so len(gt) == len(gt[0]) except # we don't have to check if it is the entry GT pattern @staticmethod @@ -143,8 +144,7 @@ def check(self): sage: G = GelfandTsetlinPatterns() sage: G([[3,2,1],[2,1],[1]]).check() """ - assert all(self[i - 1][j] >= self[i][j] >= self[i - 1][j + 1] - for i in range(1, len(self)) for j in range(len(self[i]))) + assert all(self[i - 1][j] >= self[i][j] >= self[i - 1][j + 1] for i in range(1, len(self)) for j in range(len(self[i]))) def _hash_(self) -> int: """ @@ -287,9 +287,7 @@ def boxed_entries(self) -> tuple: sage: G.boxed_entries() ((1, 0),) """ - ret = [(i, j) for i in range(1, len(self)) - for j, selfij in enumerate(self[i]) - if selfij == self[i - 1][j]] + ret = [(i, j) for i in range(1, len(self)) for j, selfij in enumerate(self[i]) if selfij == self[i - 1][j]] return tuple(ret) @cached_method @@ -307,9 +305,7 @@ def circled_entries(self) -> tuple: sage: G.circled_entries() ((1, 1), (2, 0)) """ - ret = [(i, j) for i in range(1, len(self)) - for j, selfij in enumerate(self[i]) - if selfij == self[i - 1][j + 1]] + ret = [(i, j) for i in range(1, len(self)) for j, selfij in enumerate(self[i]) if selfij == self[i - 1][j + 1]] return tuple(ret) @cached_method @@ -330,9 +326,7 @@ def special_entries(self) -> tuple: sage: G.special_entries() ((2, 0),) """ - ret = [(i, j) for i in range(1, len(self)) - for j, selfij in enumerate(self[i]) - if self[i - 1][j] > selfij > self[i - 1][j + 1]] + ret = [(i, j) for i in range(1, len(self)) for j, selfij in enumerate(self[i]) if self[i - 1][j] > selfij > self[i - 1][j + 1]] return tuple(ret) def number_of_boxes(self) -> int: @@ -387,8 +381,7 @@ def is_strict(self) -> bool: sage: GelfandTsetlinPattern([[6,0,0],[3,0],[2]]).is_strict() False """ - return not any(row[i] == row[i + 1] for row in self - for i in range(len(row) - 1)) + return not any(row[i] == row[i + 1] for row in self for i in range(len(row) - 1)) def row_sums(self) -> list: r""" @@ -409,8 +402,7 @@ def row_sums(self) -> list: sage: G.row_sums() [6, 4, 2] """ - return [sum(self[i][j] for j in range(len(self[i]))) - for i in range(len(self))] + return [sum(self[i][j] for j in range(len(self[i]))) for i in range(len(self))] def weight(self) -> tuple: r""" @@ -480,7 +472,7 @@ def Tokuyama_coefficient(self, name='t'): t = R.gen(0) if not self.is_strict(): return R.zero() - return (t + 1)**self.number_of_special_entries() * t**self.number_of_boxes() + return (t + 1) ** self.number_of_special_entries() * t ** self.number_of_boxes() @combinatorial_map(order=2, name='Bender-Knuth involution') def bender_knuth_involution(self, i) -> GelfandTsetlinPattern: @@ -529,23 +521,23 @@ def toggle(i, j): """ Return the toggle of entry 'G[i][j]' in a Gelfand-Tsetlin pattern, 'G'. """ - if i == n-1: - return self[n-2][0]+self[n-2][1]-self[n-1][0] + if i == n - 1: + return self[n - 2][0] + self[n - 2][1] - self[n - 1][0] if j == 0: - left = self[i-1][0] + left = self[i - 1][0] else: - left = min(self[i-1][j], self[i+1][j-1]) - if j == n-i-1: - right = self[i-1][j+1] + left = min(self[i - 1][j], self[i + 1][j - 1]) + if j == n - i - 1: + right = self[i - 1][j + 1] else: - right = max(self[i-1][j+1], self[i+1][j]) + right = max(self[i - 1][j + 1], self[i + 1][j]) return left + right - self[i][j] if not 0 < i < n: raise ValueError(f"must have 0 < {i} < {n}") - r = n-i + r = n - i P = self.parent() data = [list(row) for row in self] data[r] = [toggle(r, s) for s in range(i)] @@ -592,6 +584,7 @@ class GelfandTsetlinPatterns(UniqueRepresentation, Parent): sage: G.cardinality() == S.cardinality() True """ + @staticmethod def __classcall_private__(cls, n=None, k=None, strict=False, top_row=None): """ @@ -614,7 +607,7 @@ def __classcall_private__(cls, n=None, k=None, strict=False, top_row=None): """ if top_row is not None: top_row = tuple(top_row) - if any(top_row[i] < top_row[i+1] for i in range(len(top_row)-1)): + if any(top_row[i] < top_row[i + 1] for i in range(len(top_row) - 1)): raise ValueError("the top row must be weakly decreasing") if n is not None and n != len(top_row): raise ValueError("n must be the length of the specified top row") @@ -681,17 +674,13 @@ def __contains__(self, gt): if self._n is not None and len(gt) != self._n: return False # Check if it has the correct maximum value - if self._k is not None and any(val > self._k for row in gt - for val in row): + if self._k is not None and any(val > self._k for row in gt for val in row): return False # Check if it is a GT pattern - if not all(gt[i-1][j] >= gt[i][j] >= gt[i-1][j+1] - for i in range(1, len(gt)) for j in range(len(gt[i]))): + if not all(gt[i - 1][j] >= gt[i][j] >= gt[i - 1][j + 1] for i in range(1, len(gt)) for j in range(len(gt[i]))): return False # Check if it is strict if applicable - return not (self._strict and any(gt[i][j] == gt[i][j - 1] - for i in range(len(gt)) - for j in range(1, len(gt[i])))) + return not (self._strict and any(gt[i][j] == gt[i][j - 1] for i in range(len(gt)) for j in range(1, len(gt[i])))) def _repr_(self): """ @@ -738,7 +727,7 @@ def _element_constructor_(self, gt): gt = [list(x) for x in reversed(gt.to_chain()[1:])] n = len(gt) for i in range(n): - while len(gt[i]) < n-i: + while len(gt[i]) < n - i: gt[i].append(0) if self._n is not None: if len(gt) == 0: @@ -857,10 +846,10 @@ def __iter__(self): for x in GelfandTsetlinPatterns(top_row=tuple(p), strict=self._strict): yield self.element_class(self, list(x)) n += 1 - for x in range(self._k+1): + for x in range(self._k + 1): yield self.element_class(self, [[x]]) n = 2 - while not self._strict or n <= self._k+1: + while not self._strict or n <= self._k + 1: for x in self._list_iter(n): yield self.element_class(self, x) n += 1 @@ -872,7 +861,7 @@ def __iter__(self): return if self._n == 1: if self._k is not None: - for x in range(self._k+1): + for x in range(self._k + 1): yield self.element_class(self, [[x]]) else: k = 1 @@ -914,7 +903,7 @@ def _list_iter(self, n): yield ret[:] pos -= 1 continue - iters[pos] = self._row_iter(ret[pos-1]) + iters[pos] = self._row_iter(ret[pos - 1]) except StopIteration: pos -= 1 @@ -942,9 +931,7 @@ def _top_row_iter(self, n): pos -= 1 continue # If it would create an invalid entry, backstep - if (pos > 0 and (row[pos] >= row[pos-1] - or (self._strict and row[pos] == row[pos-1]-1))) \ - or (self._k is not None and row[pos] >= self._k): + if (pos > 0 and (row[pos] >= row[pos - 1] or (self._strict and row[pos] == row[pos - 1] - 1))) or (self._k is not None and row[pos] >= self._k): row[pos] = -1 pos -= 1 continue @@ -980,10 +967,7 @@ def _row_iter(self, upper_row): pos -= 1 continue # If it would create an invalid entry, backstep - if (pos > 0 and (row[pos] >= row[pos - 1] - or (self._strict and row[pos] == row[pos - 1] - 1))) \ - or row[pos] >= upper_row[pos] \ - or (self._k is not None and row[pos] >= self._k): + if (pos > 0 and (row[pos] >= row[pos - 1] or (self._strict and row[pos] == row[pos - 1] - 1))) or row[pos] >= upper_row[pos] or (self._k is not None and row[pos] >= self._k): row[pos] = upper_row[pos + 1] - 1 pos -= 1 continue @@ -1120,8 +1104,7 @@ def _cftp(self, start_row): direction = random() % 2 self._toggle_markov_chain(upper, row, col, direction) self._toggle_markov_chain(lower, row, col, direction) - if all(x == y for l1, l2 in zip(upper, lower) - for x, y in zip(l1, l2)): + if all(x == y for l1, l2 in zip(upper, lower) for x, y in zip(l1, l2)): break count = seedlist[0][1] * 2 seedlist.insert(0, (current_randstate().long_seed(), count)) @@ -1336,7 +1319,7 @@ def Tokuyama_formula(self, name='t'): t = R.gen(0) x = R.gens()[1:] GT = GelfandTsetlinPatterns(top_row=self._row, strict=True) - return sum((t + 1)**gt.number_of_special_entries() * t**gt.number_of_boxes() * prod(x[i]**gt.weight()[i] for i in range(n)) for gt in GT) + return sum((t + 1) ** gt.number_of_special_entries() * t ** gt.number_of_boxes() * prod(x[i] ** gt.weight()[i] for i in range(n)) for gt in GT) def _cftp_upper(self) -> list: """ diff --git a/src/sage/combinat/graph_path.py b/src/sage/combinat/graph_path.py index e981dccc2b0..dcf19611e77 100644 --- a/src/sage/combinat/graph_path.py +++ b/src/sage/combinat/graph_path.py @@ -1,6 +1,7 @@ r""" Paths in directed acyclic graphs """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # diff --git a/src/sage/combinat/gray_codes.py b/src/sage/combinat/gray_codes.py index 1944626f2b1..4054c3edb57 100644 --- a/src/sage/combinat/gray_codes.py +++ b/src/sage/combinat/gray_codes.py @@ -71,8 +71,8 @@ def product(m): # n is the length of the element (we ignore sets of size 1) n = 0 - new_m = [] # will be the set of upper bounds m_i different from 1 - mm = [] # index of each set (we skip sets of cardinality 1) + new_m = [] # will be the set of upper bounds m_i different from 1 + mm = [] # index of each set (we skip sets of cardinality 1) for k, i in enumerate(m): i = int(i) if i <= 0: @@ -84,8 +84,8 @@ def product(m): m = new_m f = list(range(n + 1)) # focus pointer - o = [1] * n # switch +1 or -1 - a = [0] * n # current element of the product + o = [1] * n # switch +1 or -1 + a = [0] * n # current element of the product j = f[0] while j != n: @@ -93,8 +93,8 @@ def product(m): oo = o[j] a[j] += oo if a[j] == 0 or a[j] == m[j]: - f[j] = f[j+1] - f[j+1] = j+1 + f[j] = f[j + 1] + f[j + 1] = j + 1 o[j] = -oo yield (mm[j], oo) @@ -194,6 +194,7 @@ def combinations(n, t): AssertionError: t(=6) must be >=0 and <=n(=5) """ from sage.rings.infinity import Infinity + t = int(t) if n != Infinity: n = int(n) @@ -220,12 +221,12 @@ def _revolving_door_odd(n, t): True """ # note: the numbering of the steps below follows Knuth TAOCP - c = list(range(t)) + [n] # the combination (ordered list of numbers of length t+1) + c = list(range(t)) + [n] # the combination (ordered list of numbers of length t+1) while True: # R3 : easy case if c[0] + 1 < c[1]: - yield c[0], c[0]+1 + yield c[0], c[0] + 1 c[0] += 1 continue @@ -234,22 +235,22 @@ def _revolving_door_odd(n, t): # R4 : try to decrease c[j] # at this point c[j] = c[j-1] + 1 if c[j] > j: - yield c[j], j-1 - c[j] = c[j-1] - c[j-1] = j-1 + yield c[j], j - 1 + c[j] = c[j - 1] + c[j - 1] = j - 1 break j += 1 # R5 : try to increase c[j] # at this point c[j-1] = j-1 - if c[j] + 1 < c[j+1]: - yield c[j-1], c[j]+1 - c[j-1] = c[j] + if c[j] + 1 < c[j + 1]: + yield c[j - 1], c[j] + 1 + c[j - 1] = c[j] c[j] += 1 break j += 1 - else: # j == t + else: # j == t break @@ -267,21 +268,21 @@ def _revolving_door_even(n, t): """ # note: the numbering of the steps below follows Knuth TAOCP - c = list(range(t)) + [n] # the combination (ordered list of numbers of length t+1) + c = list(range(t)) + [n] # the combination (ordered list of numbers of length t+1) while True: # R3 : easy case if c[0] > 0: - yield c[0], c[0]-1 + yield c[0], c[0] - 1 c[0] -= 1 continue j = 1 # R5 : try to increase c[j] # at this point c[j-1] = j-1 - if c[j] + 1 < c[j+1]: - yield c[j-1], c[j]+1 - c[j-1] = c[j] + if c[j] + 1 < c[j + 1]: + yield c[j - 1], c[j] + 1 + c[j - 1] = c[j] c[j] += 1 continue j += 1 @@ -290,20 +291,20 @@ def _revolving_door_even(n, t): # R4 : try to decrease c[j] # at this point c[j] = c[j-1] + 1 if c[j] > j: - yield c[j], j-1 - c[j] = c[j-1] - c[j-1] = j-1 + yield c[j], j - 1 + c[j] = c[j - 1] + c[j - 1] = j - 1 break j += 1 # R5 : try to increase c[j] # at this point c[j-1] = j-1 - if c[j] + 1 < c[j+1]: - yield c[j-1], c[j] + 1 - c[j-1] = c[j] + if c[j] + 1 < c[j + 1]: + yield c[j - 1], c[j] + 1 + c[j - 1] = c[j] c[j] += 1 break j += 1 - else: # j == t + else: # j == t break diff --git a/src/sage/combinat/grossman_larson_algebras.py b/src/sage/combinat/grossman_larson_algebras.py index 1071b2dc1d1..ae3318b8170 100644 --- a/src/sage/combinat/grossman_larson_algebras.py +++ b/src/sage/combinat/grossman_larson_algebras.py @@ -19,9 +19,7 @@ from sage.categories.hopf_algebras import HopfAlgebras from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.words.alphabet import Alphabet -from sage.combinat.rooted_tree import (RootedTrees, RootedTree, - LabelledRootedTrees, - LabelledRootedTree) +from sage.combinat.rooted_tree import RootedTrees, RootedTree, LabelledRootedTrees, LabelledRootedTree from sage.categories.rings import Rings from sage.sets.family import Family from sage.rings.integer_ring import ZZ @@ -140,6 +138,7 @@ class GrossmanLarsonAlgebra(CombinatorialFreeModule): - [GroLar1]_ """ + @staticmethod def __classcall_private__(cls, R, names=None): """ @@ -200,10 +199,7 @@ def __init__(self, R, names=None): # so that one can restrict the labels to some fixed set cat = HopfAlgebras(R).WithBasis().Graded() - CombinatorialFreeModule.__init__(self, R, Trees, - latex_prefix='', - sorting_key=key, - category=cat) + CombinatorialFreeModule.__init__(self, R, Trees, latex_prefix='', sorting_key=key, category=cat) def variable_names(self): r""" @@ -310,8 +306,7 @@ def single_vertex_all(self): (B[[[]]],) """ Trees = self.basis().keys() - return tuple(Family(self._alphabet, - lambda a: self.monomial(Trees([Trees([], a)], ROOT)))) + return tuple(Family(self._alphabet, lambda a: self.monomial(Trees([Trees([], a)], ROOT)))) def _first_ngens(self, n): """ @@ -424,9 +419,7 @@ def product_on_basis(self, x, y): sage: A.product_on_basis(Tu, Tv) B[#[u[v[]]]] + B[#[u[], v[]]] """ - return self.sum(self.basis()[x.single_graft(y, graftingFunction)] - for graftingFunction in - product(list(x.paths()), repeat=len(y))) + return self.sum(self.basis()[x.single_graft(y, graftingFunction)] for graftingFunction in product(list(x.paths()), repeat=len(y))) def one_basis(self): """ @@ -487,10 +480,7 @@ def coproduct_on_basis(self, x): subtrees = list(x) num_subtrees = len(subtrees) indx = list(range(num_subtrees)) - return sum(B[Trees([subtrees[i] for i in S], ROOT)].tensor( - B[Trees([subtrees[i] for i in indx if i not in S], ROOT)]) - for k in range(num_subtrees + 1) - for S in combinations(indx, k)) + return sum(B[Trees([subtrees[i] for i in S], ROOT)].tensor(B[Trees([subtrees[i] for i in indx if i not in S], ROOT)]) for k in range(num_subtrees + 1) for S in combinations(indx, k)) def counit_on_basis(self, x): """ @@ -533,10 +523,7 @@ def antipode_on_basis(self, x): return self.one() num_subtrees = len(subtrees) indx = list(range(num_subtrees)) - return sum(- self.antipode_on_basis(Trees([subtrees[i] for i in S], ROOT)) - * B[Trees([subtrees[i] for i in indx if i not in S], ROOT)] - for k in range(num_subtrees) - for S in combinations(indx, k)) + return sum(-self.antipode_on_basis(Trees([subtrees[i] for i in S], ROOT)) * B[Trees([subtrees[i] for i in indx if i not in S], ROOT)] for k in range(num_subtrees) for S in combinations(indx, k)) def _element_constructor_(self, x): r""" @@ -577,8 +564,7 @@ def _element_constructor_(self, x): ... TypeError: not able to convert this to this algebra """ - if (isinstance(x, (RootedTree, LabelledRootedTree)) - and x in self.basis().keys()): + if isinstance(x, (RootedTree, LabelledRootedTree)) and x in self.basis().keys(): if hasattr(x, 'label') and x.label() != ROOT: raise ValueError('incorrect root label') return self.monomial(x) diff --git a/src/sage/combinat/growth.py b/src/sage/combinat/growth.py index c432ddaf9fc..fc6de81b410 100644 --- a/src/sage/combinat/growth.py +++ b/src/sage/combinat/growth.py @@ -693,7 +693,7 @@ def __init__(self, rule, filling=None, shape=None, labels=None): if labels is None: rule = self.rule if rule.has_multiple_edges: - self._in_labels = [rule.zero, rule.zero_edge]*(self.half_perimeter()-1) + [rule.zero] + self._in_labels = [rule.zero, rule.zero_edge] * (self.half_perimeter() - 1) + [rule.zero] else: self._in_labels = [rule.zero] * self.half_perimeter() else: @@ -750,10 +750,7 @@ def conjugate(self): True """ F = {(j, i): v for (i, j), v in self._filling.items()} - return GrowthDiagram(self.rule, - filling=F, - shape=self.shape().conjugate(), - labels=self.in_labels()[::-1]) + return GrowthDiagram(self.rule, filling=F, shape=self.shape().conjugate(), labels=self.in_labels()[::-1]) def rotate(self): r""" @@ -804,10 +801,8 @@ def rotate(self): shape_lambda = [l - p for p in self._mu] + [l] * (h - len(self._mu)) shape_mu = [l - p for p in self._lambda] shape = SkewPartition([shape_lambda[::-1], shape_mu[::-1]]) - F = {(l-i-1, h-j-1): v for (i, j), v in self._filling.items()} - return GrowthDiagram(self.rule, - filling=F, - shape=shape) + F = {(l - i - 1, h - j - 1): v for (i, j), v in self._filling.items()} + return GrowthDiagram(self.rule, filling=F, shape=shape) def half_perimeter(self): r""" @@ -925,7 +920,7 @@ def P_chain(self): raise ValueError("the P symbol is only defined for rectangular shapes") if self._lambda: if self.rule.has_multiple_edges: - r = 2*self._lambda[0] + r = 2 * self._lambda[0] else: r = self._lambda[0] else: @@ -954,9 +949,9 @@ def Q_chain(self): raise ValueError("the Q symbol is only defined for rectangular shapes") if self._lambda: if self.rule.has_multiple_edges: - r = 2*self._lambda[0]+1 + r = 2 * self._lambda[0] + 1 else: - r = self._lambda[0]+1 + r = self._lambda[0] + 1 else: r = 1 return self._out_labels[:r] @@ -973,8 +968,7 @@ def is_rectangular(self): sage: GrowthDiagram(RuleRSK, [[1,0,1],[0,1]]).is_rectangular() False """ - return (all(x == 0 for x in self._mu) - and all(x == self._lambda[0] for x in self._lambda)) + return all(x == 0 for x in self._mu) and all(x == self._lambda[0] for x in self._lambda) def to_word(self): r""" @@ -1001,19 +995,16 @@ def to_word(self): if v != 0: if v == 1: if w[i] == 0: - w[i] = j+1 + w[i] = j + 1 else: - raise ValueError("can only convert fillings with at" - " most one entry per column to words") + raise ValueError("can only convert fillings with at" " most one entry per column to words") elif v == -1: if w[i] == 0: - w[i] = -(j+1) + w[i] = -(j + 1) else: - raise ValueError("can only convert fillings with at" - " most one entry per column to words") + raise ValueError("can only convert fillings with at" " most one entry per column to words") else: - raise ValueError("can only convert 0-1 fillings to words;" - " try 'to_biword'") + raise ValueError("can only convert 0-1 fillings to words;" " try 'to_biword'") return w def to_biword(self): @@ -1047,11 +1038,10 @@ def to_biword(self): w2 = [] for (i, j), v in sorted(self._filling.items()): if v >= 0: - w1.extend([i+1]*v) - w2.extend([j+1]*v) + w1.extend([i + 1] * v) + w2.extend([j + 1] * v) else: - raise ValueError("can only convert fillings with" - " nonnegative entries to words") + raise ValueError("can only convert fillings with" " nonnegative entries to words") return (w1, w2) def __iter__(self): @@ -1075,9 +1065,7 @@ def __iter__(self): [0, 0, 0, 0, 0, 1], [0, 0, 0, 1, 0, 0]] """ - return ([None]*self._mu[r] + [self._filling.get((self._mu[r]+j,r), 0) - for j in range(self._lambda[r]-self._mu[r])] - for r in range(len(self._lambda))) + return ([None] * self._mu[r] + [self._filling.get((self._mu[r] + j, r), 0) for j in range(self._lambda[r] - self._mu[r])] for r in range(len(self._lambda))) def _repr_(self): r""" @@ -1095,10 +1083,7 @@ def _repr_(self): . 0 1 1 """ - return SkewTableau(expr=[self._mu, - [[self._filling.get((self._mu[r]+j,r), 0) - for j in range(self._lambda[r]-self._mu[r])] - for r in range(len(self._lambda))][::-1]])._repr_diagram() + return SkewTableau(expr=[self._mu, [[self._filling.get((self._mu[r] + j, r), 0) for j in range(self._lambda[r] - self._mu[r])] for r in range(len(self._lambda))][::-1]])._repr_diagram() def __eq__(self, other): r""" @@ -1130,11 +1115,7 @@ def __eq__(self, other): sage: G1 == G2 False """ - return (type(self) is type(other) and - self.rule == other.rule and - self._lambda == other._lambda and - self._mu == other._mu and - self._filling == other._filling) + return type(self) is type(other) and self.rule == other.rule and self._lambda == other._lambda and self._mu == other._mu and self._filling == other._filling def __ne__(self, other): r""" @@ -1188,8 +1169,7 @@ def _process_labels(self, labels): """ rule = self.rule if rule.has_multiple_edges: - return [rule.normalize_vertex(val) if i % 2 == 0 else val - for i, val in enumerate(labels)] + return [rule.normalize_vertex(val) if i % 2 == 0 else val for i, val in enumerate(labels)] return [rule.normalize_vertex(la) for la in labels] def _shape_from_labels(self, labels, complement=False): @@ -1236,7 +1216,7 @@ def _shape_from_labels(self, labels, complement=False): seq = [] if rule.has_multiple_edges: for i in range(0, len(labels) - 2, 2): - la, e, mu = labels[i], labels[i+1], labels[i+2] + la, e, mu = labels[i], labels[i + 1], labels[i + 2] if rule.rank(la) < rule.rank(mu): if is_Q_edge is not None and e not in is_Q_edge(la, mu): raise ValueError("%s has smaller rank than %s but there is no edge of color %s in Q" % (la, mu, e)) @@ -1249,7 +1229,7 @@ def _shape_from_labels(self, labels, complement=False): raise ValueError("can only determine the shape of the growth diagram if ranks of successive labels differ") else: for i in range(len(labels) - 1): - la, mu = labels[i], labels[i+1] + la, mu = labels[i], labels[i + 1] if rule.rank(la) < rule.rank(mu): if is_Q_edge is not None and not is_Q_edge(la, mu): raise ValueError("%s has smaller rank than %s but is not covered by it in Q" % (la, mu)) @@ -1303,8 +1283,7 @@ def _check_labels(self, labels): path_length = len(labels) if path_length != half_perimeter: - raise ValueError("the number of labels is %s, but for this shape we need %s" - % (path_length, half_perimeter)) + raise ValueError("the number of labels is %s, but for this shape we need %s" % (path_length, half_perimeter)) def _process_shape(self, shape): r""" @@ -1337,9 +1316,8 @@ def _process_shape(self, shape): shape = SkewPartition(shape) except ValueError: raise ValueError("cannot make sense of shape %s" % shape) - return (list(shape[0]), - list(shape[1]) + [0]*(len(shape[0])-len(shape[1]))) - return list(shape), [0]*len(shape) + return (list(shape[0]), list(shape[1]) + [0] * (len(shape[0]) - len(shape[1]))) + return list(shape), [0] * len(shape) def _process_filling_shape_labels(self, filling, shape, labels): r""" @@ -1436,8 +1414,7 @@ def _process_filling_shape_labels(self, filling, shape, labels): F[(i, j)] = int(v) else: # it is dict of coordinates - F = {(i, j): v for (i, j), v in filling.items() - if v != 0} + F = {(i, j): v for (i, j), v in filling.items() if v != 0} except StopIteration: # it is an empty dict of coordinates F = filling @@ -1459,9 +1436,9 @@ def _process_filling_shape_labels(self, filling, shape, labels): # it is a word - for convenience we allow signed words for i, l in enumerate(filling): if l > 0: - F[i, l-1] = 1 + F[i, l - 1] = 1 else: - F[i, -l-1] = -1 + F[i, -l - 1] = -1 if shape is None: if labels is not None: @@ -1475,8 +1452,8 @@ def _process_filling_shape_labels(self, filling, shape, labels): shape = [] else: # find bounding rectangle of ``filling`` - max_row = max(i for i, _ in F)+1 - max_col = max(j for _, j in F)+1 + max_row = max(i for i, _ in F) + 1 + max_col = max(j for _, j in F) + 1 shape = [max_row] * max_col return F, self._process_shape(shape) @@ -1522,26 +1499,16 @@ def _grow(self): rule = self.rule if rule.has_multiple_edges: for r in range(l): - for c in range(self._mu[r]+l-r, self._lambda[r]+l-r): + for c in range(self._mu[r] + l - r, self._lambda[r] + l - r): j = r - i = c-l+r - (labels[2*c-1], - labels[2*c], - labels[2*c+1]) = rule.forward_rule(labels[2*c-2], - labels[2*c-1], - labels[2*c], - labels[2*c+1], - labels[2*c+2], - self._filling.get((i,j), 0)) + i = c - l + r + (labels[2 * c - 1], labels[2 * c], labels[2 * c + 1]) = rule.forward_rule(labels[2 * c - 2], labels[2 * c - 1], labels[2 * c], labels[2 * c + 1], labels[2 * c + 2], self._filling.get((i, j), 0)) else: for r in range(l): - for c in range(self._mu[r]+l-r, self._lambda[r]+l-r): + for c in range(self._mu[r] + l - r, self._lambda[r] + l - r): j = r - i = c-l+r - labels[c] = rule.forward_rule(labels[c-1], - labels[c], - labels[c+1], - self._filling.get((i,j), 0)) + i = c - l + r + labels[c] = rule.forward_rule(labels[c - 1], labels[c], labels[c + 1], self._filling.get((i, j), 0)) self._out_labels = labels @@ -1610,33 +1577,26 @@ def _shrink(self): rule = self.rule if rule.has_multiple_edges: for r in range(l): - for c in range(self._lambda[l-r-1]+r, self._mu[l-r-1]+r, -1): - j = l-r-1 - i = c-r-1 - (labels[2*c-1], - labels[2*c], - labels[2*c+1], v) = rule.backward_rule(labels[2*c-2], - labels[2*c-1], - labels[2*c], - labels[2*c+1], - labels[2*c+2]) + for c in range(self._lambda[l - r - 1] + r, self._mu[l - r - 1] + r, -1): + j = l - r - 1 + i = c - r - 1 + (labels[2 * c - 1], labels[2 * c], labels[2 * c + 1], v) = rule.backward_rule(labels[2 * c - 2], labels[2 * c - 1], labels[2 * c], labels[2 * c + 1], labels[2 * c + 2]) if v != 0: - F[(i,j)] = v + F[(i, j)] = v else: for r in range(l): - for c in range(self._lambda[l-r-1]+r, self._mu[l-r-1]+r, -1): - j = l-r-1 - i = c-r-1 - labels[c], v = rule.backward_rule(labels[c-1], - labels[c], - labels[c+1]) + for c in range(self._lambda[l - r - 1] + r, self._mu[l - r - 1] + r, -1): + j = l - r - 1 + i = c - r - 1 + labels[c], v = rule.backward_rule(labels[c - 1], labels[c], labels[c + 1]) if v != 0: - F[(i,j)] = v + F[(i, j)] = v self._in_labels = labels self._filling = F + ###################################################################### # ABC for rules of growth diagrams ###################################################################### @@ -1726,11 +1686,12 @@ class Rule(UniqueRepresentation): In particular, this allows to work with dual graded graphs without local rules. """ - has_multiple_edges = False # override when necessary - zero_edge = 0 # override when necessary - r = 1 # override when necessary - def normalize_vertex(self, v): # override when necessary + has_multiple_edges = False # override when necessary + zero_edge = 0 # override when necessary + r = 1 # override when necessary + + def normalize_vertex(self, v): # override when necessary r""" Return ``v`` as a vertex of the dual graded graph. @@ -1807,25 +1768,22 @@ def _check_duality(self, n): U D + 1 I = [[1, 1], [2], [2]] """ if self.has_multiple_edges: + def check_vertex(w, P, Q): DUw = [v[0] for uw in P.outgoing_edges(w) for v in Q.incoming_edges(uw[1])] UDw = [v[1] for lw in Q.incoming_edges(w) for v in P.outgoing_edges(lw[0])] - UDw.extend([w]*self.r) + UDw.extend([w] * self.r) if sorted(DUw) != sorted(UDw): - raise ValueError("D U - U D differs from %s I for vertex %s:\n" - "D U = %s\n" - "U D + %s I = %s" - % (self.r, w, DUw, self.r, UDw)) + raise ValueError("D U - U D differs from %s I for vertex %s:\n" "D U = %s\n" "U D + %s I = %s" % (self.r, w, DUw, self.r, UDw)) + else: + def check_vertex(w, P, Q): DUw = [v for uw in P.upper_covers(w) for v in Q.lower_covers(uw)] UDw = [v for lw in Q.lower_covers(w) for v in P.upper_covers(lw)] - UDw.extend([w]*self.r) + UDw.extend([w] * self.r) if sorted(DUw) != sorted(UDw): - raise ValueError("D U - U D differs from %s I for vertex %s:\n" - "D U = %s\n" - "U D + %s I = %s" - % (self.r, w, DUw, self.r, UDw)) + raise ValueError("D U - U D differs from %s I for vertex %s:\n" "D U = %s\n" "U D + %s I = %s" % (self.r, w, DUw, self.r, UDw)) P = self.P_graph(n + 2) Q = self.Q_graph(n + 2) @@ -1846,16 +1804,12 @@ def P_graph(self, n): Finite poset containing 8 elements """ if self.has_multiple_edges: - D = DiGraph([(x,y,e) for k in range(n-1) - for x in self.vertices(k) - for y in self.vertices(k+1) - for e in self.is_P_edge(x, y)], multiedges=True) + D = DiGraph([(x, y, e) for k in range(n - 1) for x in self.vertices(k) for y in self.vertices(k + 1) for e in self.is_P_edge(x, y)], multiedges=True) # unfortunately, layout_acyclic will not show multiple edges # D.layout_default = D.layout_acyclic return D - return Poset(([w for k in range(n) for w in self.vertices(k)], - self.is_P_edge), cover_relations=True) + return Poset(([w for k in range(n) for w in self.vertices(k)], self.is_P_edge), cover_relations=True) def Q_graph(self, n): r""" @@ -1874,16 +1828,13 @@ def Q_graph(self, n): [[1, 1, 1, 1], [3, 1], [2, 2]] """ if self.has_multiple_edges: - D = DiGraph([(x, y, e) for k in range(n - 1) - for x in self.vertices(k) - for y in self.vertices(k + 1) - for e in self.is_Q_edge(x, y)], multiedges=True) + D = DiGraph([(x, y, e) for k in range(n - 1) for x in self.vertices(k) for y in self.vertices(k + 1) for e in self.is_Q_edge(x, y)], multiedges=True) # unfortunately, layout_acyclic will not show multiple edges # D.layout_default = D.layout_acyclic return D - return Poset(([w for k in range(n) for w in self.vertices(k)], - self.is_Q_edge), cover_relations=True) + return Poset(([w for k in range(n) for w in self.vertices(k)], self.is_Q_edge), cover_relations=True) + ###################################################################### # Specific rules of growth diagrams @@ -1940,6 +1891,7 @@ class RuleShiftedShapes(Rule): sage: list(Shifted(labels=G.out_labels())) == list(G) True """ + zero = _make_partition([]) has_multiple_edges = True @@ -2007,8 +1959,8 @@ def is_Q_edge(self, v, w): return [] if l[0][1] == 0: - return [1] # black - return [2,3] # blue, red + return [1] # black + return [2, 3] # blue, red def is_P_edge(self, v, w): r""" @@ -2067,10 +2019,10 @@ def P_symbol(self, P_chain): chain = P_chain[::2] shape = chain[-1] T = [[None for _ in range(r)] for r in shape] - for i in range(1,len(chain)): + for i in range(1, len(chain)): la = chain[i] - mu = chain[i-1] - mu += [0]*(len(la) - len(mu)) + mu = chain[i - 1] + mu += [0] * (len(la) - len(mu)) for r in range(len(la)): for c in range(mu[r], la[r]): @@ -2119,14 +2071,14 @@ def Q_symbol(self, Q_chain): chain = Q_chain shape = chain[-1] T = [[None for _ in range(r)] for r in shape] - for i in range(1,(len(chain)+1)//2): - la = chain[2*i] - if chain[2*i-1] == 3: + for i in range(1, (len(chain) + 1) // 2): + la = chain[2 * i] + if chain[2 * i - 1] == 3: prime = 0.5 else: prime = 0 - mu = chain[2*(i-1)] - mu += [0]*(len(la) - len(mu)) + mu = chain[2 * (i - 1)] + mu += [0] * (len(la) - len(mu)) for r in range(len(la)): for c in range(mu[r], la[r]): @@ -2199,14 +2151,13 @@ def forward_rule(self, y, e, t, f, x, content): g, z = 0, x elif content == 1: if not x: - g, z = 1, _Partitions(x).add_cell(0) # black + g, z = 1, _Partitions(x).add_cell(0) # black else: - g, z = 2, _make_partition(x).add_cell(0) # blue + g, z = 2, _make_partition(x).add_cell(0) # blue else: raise NotImplementedError elif content != 0: - raise ValueError("for y=%s, t=%s, x=%s, the content should be 0 but is %s" - % (y, t, x, content)) + raise ValueError("for y=%s, t=%s, x=%s, the content should be 0 but is %s" % (y, t, x, content)) elif x != t == y: g, z = f, x elif x == t != y: @@ -2217,18 +2168,18 @@ def forward_rule(self, y, e, t, f, x, content): if x != y: row = SkewPartition([x, t]).cells()[0][0] g, z = f, _make_partition(y).add_cell(row) - elif x == y != t and f == 2: # blue - row = 1+SkewPartition([x, t]).cells()[0][0] + elif x == y != t and f == 2: # blue + row = 1 + SkewPartition([x, t]).cells()[0][0] if row == len(y): - g, z = 1, _make_partition(y).add_cell(row) # black + g, z = 1, _make_partition(y).add_cell(row) # black else: - g, z = 2, _make_partition(y).add_cell(row) # blue + g, z = 2, _make_partition(y).add_cell(row) # blue elif x == y != t and f in [1, 3]: # black or red c = SkewPartition([x, t]).cells()[0] col = c[0] + c[1] + 1 for i in range(len(y)): if i + y[i] == col: - z = y[:i] + [y[i] + 1] + y[i + 1:] + z = y[:i] + [y[i] + 1] + y[i + 1 :] break g = 3 else: @@ -2306,18 +2257,18 @@ def backward_rule(self, y, g, z, h, x): return (0, _make_partition(y).remove_cell(row), g, 0) row, col = SkewPartition([z, x]).cells()[0] - if row > 0 and g in [1, 2]: # black or blue - return (0, _make_partition(y).remove_cell(row-1), 2, 0) - if row == 0 and g in [1, 2]: # black or blue + if row > 0 and g in [1, 2]: # black or blue + return (0, _make_partition(y).remove_cell(row - 1), 2, 0) + if row == 0 and g in [1, 2]: # black or blue return (0, y, 0, 1) # find last cell in column col-1 - for i in range(len(y)-1,-1,-1): + for i in range(len(y) - 1, -1, -1): if i + y[i] == col + row: if y[i] == 1: t = y[:i] return (0, t, 1, 0) - t = y[:i] + [y[i]-1] + y[i+1:] + t = y[:i] + [y[i] - 1] + y[i + 1 :] return (0, t, 3, 0) raise ValueError("this should not happen") @@ -2392,6 +2343,7 @@ class RuleLLMS(Rule): sage: LLMS3.zero [] """ + zero_edge = None # to prevent confusion with the edge labelled with content 0 has_multiple_edges = True @@ -2483,7 +2435,7 @@ def is_P_edge(self, v, w): """ if w in v.strong_covers(): T = SkewPartition([w.to_partition(), v.to_partition()]) - return [max([j-i for i,j in c]) for c in T.cell_poset().connected_components()] + return [max([j - i for i, j in c]) for c in T.cell_poset().connected_components()] return [] def P_symbol(self, P_chain): @@ -2504,11 +2456,11 @@ def P_symbol(self, P_chain): T = SkewTableau(chain=C[::2]) S = T.to_list() for entry, content in enumerate(C[1::2], 1): - for i,j in T.cells_containing(entry): - if j-i == content: + for i, j in T.cells_containing(entry): + if j - i == content: S[i][j] = -S[i][j] break - return StrongTableau(S, self.k-1) + return StrongTableau(S, self.k - 1) def Q_symbol(self, Q_chain): r""" @@ -2524,7 +2476,7 @@ def Q_symbol(self, Q_chain): 1 2 3 4 """ - return WeakTableau(SkewTableau(chain=Q_chain[::2]), self.k-1) + return WeakTableau(SkewTableau(chain=Q_chain[::2]), self.k - 1) def forward_rule(self, y, e, t, f, x, content): r""" @@ -2609,31 +2561,28 @@ def forward_rule(self, y, e, t, f, x, content): else: assert False, "BUG in RuleLLMS" elif content != 0: - raise ValueError("for y=%s, t=%s, x=%s, the content should be 0 but is %s" - % (y, t, x, content)) + raise ValueError("for y=%s, t=%s, x=%s, the content should be 0 but is %s" % (y, t, x, content)) elif x != t == y: if e is not None: raise ValueError("degenerate edge e should have color None") z, h = x, e elif x == t != y: z, h = y, e - else: # x != t and y != t + else: # x != t and y != t qx = SkewPartition([x.to_partition(), t.to_partition()]) qy = SkewPartition([y.to_partition(), t.to_partition()]) if not all(c in qx.cells() for c in qy.cells()): - res = [(j-i) % self.k for i, j in qx.cells()] + res = [(j - i) % self.k for i, j in qx.cells()] assert len(set(res)) == 1 r = res[0] z = y.affine_symmetric_group_simple_action(r) if e % self.k == r: - h = e-1 + h = e - 1 else: h = e elif x == y != t: # the addable cell with largest content at most e - cprime = sorted([c for c in y.to_partition().addable_cells() - if c[1]-c[0] <= e], - key=lambda c: -(c[1]-c[0]))[0] + cprime = sorted([c for c in y.to_partition().addable_cells() if c[1] - c[0] <= e], key=lambda c: -(c[1] - c[0]))[0] h = cprime[1] - cprime[0] z = y.affine_symmetric_group_simple_action(h % self.k) @@ -2720,7 +2669,8 @@ class RuleBinaryWord(Rule): ....: for w in Permutations(r)) True """ - zero = Word([], alphabet=[0,1]) + + zero = Word([], alphabet=[0, 1]) def normalize_vertex(self, v): r""" @@ -2732,7 +2682,7 @@ def normalize_vertex(self, v): sage: BinaryWord.normalize_vertex([0,1]).parent() Finite words over {0, 1} """ - return Word(v, alphabet=[0,1]) + return Word(v, alphabet=[0, 1]) def vertices(self, n): r""" @@ -2746,8 +2696,8 @@ def vertices(self, n): """ if n == 0: return [self.zero] - w1 = Word([1], [0,1]) - return [w1 + w for w in Words([0,1], n-1)] + w1 = Word([1], [0, 1]) + return [w1 + w for w in Words([0, 1], n - 1)] def rank(self, v): r""" @@ -2844,21 +2794,20 @@ def forward_rule(self, y, t, x, content): if content == 0: z = x elif content == 1: - z = Word(list(y) + [1], alphabet=[0,1]) + z = Word(list(y) + [1], alphabet=[0, 1]) else: raise NotImplementedError elif content != 0: - raise ValueError("for y=%s, t=%s, x=%s, the content should be 0 but is %s" - % (y, t, x, content)) + raise ValueError("for y=%s, t=%s, x=%s, the content should be 0 but is %s" % (y, t, x, content)) elif x != t == y: z = x elif x == t != y: z = y else: if x != y: - z = Word(list(y) + [x[-1]], alphabet=[0,1]) + z = Word(list(y) + [x[-1]], alphabet=[0, 1]) elif x == y != t: - z = Word(list(y) + [0], alphabet=[0,1]) + z = Word(list(y) + [0], alphabet=[0, 1]) else: raise NotImplementedError return z @@ -2989,6 +2938,7 @@ class RuleSylvester(Rule): sage: list(Sylvester(labels=G.out_labels())) == list(G) True """ + zero = BinaryTree() # type:ignore def normalize_vertex(self, v): @@ -3050,6 +3000,7 @@ def is_Q_edge(self, v, w): sage: [w for w in Sylvester.vertices(4) if Sylvester.is_Q_edge(v, w)] [] """ + def is_subtree(T1, T2): if T2.is_empty(): return False @@ -3057,8 +3008,8 @@ def is_subtree(T1, T2): return T1.is_empty() if T1.is_empty(): return False - return ((T1[0] == T2[0] and is_subtree(T1[1], T2[1])) or - (T1[1] == T2[1] and is_subtree(T1[0], T2[0]))) + return (T1[0] == T2[0] and is_subtree(T1[1], T2[1])) or (T1[1] == T2[1] and is_subtree(T1[0], T2[0])) + return is_subtree(v, w) def is_P_edge(self, v, w): @@ -3120,6 +3071,7 @@ def P_symbol(self, P_chain): / 2 """ + def add_label(L, S, T, m): if T[0] == S: L = LabelledBinaryTree([L, None], m) @@ -3131,7 +3083,7 @@ def add_label(L, S, T, m): L = LabelledBinaryTree(P_chain[0]) for i in range(1, len(P_chain)): - S, T = P_chain[i-1], P_chain[i] + S, T = P_chain[i - 1], P_chain[i] L = add_label(L, S, T, i) return L @@ -3165,6 +3117,7 @@ def Q_symbol(self, Q_chain): / 2 """ + def add_label(L, S, T, m): if L.is_empty(): assert T.number_of_nodes() == 1 @@ -3176,7 +3129,7 @@ def add_label(L, S, T, m): L = LabelledBinaryTree(Q_chain[0]) for i in range(1, len(Q_chain)): - S, T = Q_chain[i-1], Q_chain[i] + S, T = Q_chain[i - 1], Q_chain[i] L = add_label(L, S, T, i) return L @@ -3291,6 +3244,7 @@ def forward_rule(self, y, t, x, content): / o """ + def successors(b): r""" Return all trees obtained from ``b`` by adding a node. @@ -3311,7 +3265,7 @@ def union(y, x): for t in successors(y): if RuleSylvester._delete_right_most_node(t) == x: return t - raise ValueError("could not find union of %s and %s" % (y,x)) + raise ValueError("could not find union of %s and %s" % (y, x)) if y == t == x: if content == 0: @@ -3444,7 +3398,8 @@ class RuleYoungFibonacci(Rule): sage: list(YF(labels=G.out_labels())) == list(G) True """ - zero = Word([], alphabet=[1,2]) + + zero = Word([], alphabet=[1, 2]) def normalize_vertex(self, v): r""" @@ -3456,7 +3411,7 @@ def normalize_vertex(self, v): sage: YF.normalize_vertex([1,2,1]).parent() Finite words over {1, 2} """ - return Word(v, alphabet=[1,2]) + return Word(v, alphabet=[1, 2]) def vertices(self, n): r""" @@ -3470,7 +3425,7 @@ def vertices(self, n): """ if n == 0: return [self.zero] - return [Word(list(w), [1,2]) for w in Compositions(n, max_part=2)] + return [Word(list(w), [1, 2]) for w in Compositions(n, max_part=2)] def rank(self, v): r""" @@ -3505,7 +3460,7 @@ def is_P_edge(self, v, w): return False ell = len(v) w = list(w) - for i in range(ell+1): + for i in range(ell + 1): d = list(v) d.insert(i, 1) if w == d: @@ -3558,22 +3513,20 @@ def forward_rule(self, y, t, x, content): if content == 0: r = x elif content == 1: - r = Word([1] + list(y), alphabet=[1,2]) + r = Word([1] + list(y), alphabet=[1, 2]) else: raise NotImplementedError elif content != 0: - raise ValueError("for y=%s, t=%s, x=%s, the content should be 0 but is %s" - % (y, t, x, content)) + raise ValueError("for y=%s, t=%s, x=%s, the content should be 0 but is %s" % (y, t, x, content)) elif x == t: r = y elif y == t: r = x else: if x != t != y: - r = Word([2] + list(t), alphabet=[1,2]) + r = Word([2] + list(t), alphabet=[1, 2]) else: - raise NotImplementedError("for y=%s, t=%s, x=%s, content %s we have no rule" - % (y, t, x, content)) + raise NotImplementedError("for y=%s, t=%s, x=%s, content %s we have no rule" % (y, t, x, content)) return r def backward_rule(self, y, z, x): @@ -3630,6 +3583,7 @@ class RulePartitions(Rule): ValueError: can only determine the shape of the growth diagram if ranks of successive labels differ """ + zero = _make_partition([]) def vertices(self, n): @@ -3852,14 +3806,14 @@ def backward_rule(self, y, z, x): if len(x) < i: row1 = 0 else: - row1 = x[i-1] + row1 = x[i - 1] if len(y) < i: row3 = 0 else: - row3 = y[i-1] + row3 = y[i - 1] t = [min(row1, row3) - carry] + t - carry = z[i-1] - max(row1, row3) - i = i-1 + carry = z[i - 1] - max(row1, row3) + i = i - 1 return (_make_partition(t), carry) @@ -3945,10 +3899,10 @@ def forward_rule(self, y, t, x, content): # n is the maximal length of longest decreasing chain by # Kleitman-Greene's theorem n = content + len(x) + len(y) - x += [0]*(n-len(x)) - y += [0]*(n-len(y)) - t += [0]*(n-len(t)) - z = [0]*n + x += [0] * (n - len(x)) + y += [0] * (n - len(y)) + t += [0] * (n - len(t)) + z = [0] * n carry = content for i, (row1, row2, row3) in enumerate(zip(x, t, y)): s = min(int(row1 == row2 == row3), carry) @@ -3994,9 +3948,9 @@ def backward_rule(self, y, z, x): sage: GrowthDiagram(Burge, labels=G._out_labels).to_word() == w # indirect doctest True """ - t = [0]*len(z) # z must be the longest partition - mu = [0]*(len(z)-len(x)) + x[::-1] - nu = [0]*(len(z)-len(y)) + y[::-1] + t = [0] * len(z) # z must be the longest partition + mu = [0] * (len(z) - len(x)) + x[::-1] + nu = [0] * (len(z) - len(y)) + y[::-1] la = z[::-1] carry = 0 for i, (mu_i, la_i, nu_i) in enumerate(zip(mu, la, nu)): @@ -4117,6 +4071,7 @@ class RuleDomino(Rule): ... ValueError: [1] has smaller rank than [2, 1] but is not covered by it in P """ + r = 2 zero = _make_partition([]) @@ -4142,7 +4097,7 @@ def vertices(self, n): sage: Domino.vertices(2) [[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]] """ - return [la for la in Partitions(2*n) if len(la.core(2)) == 0] + return [la for la in Partitions(2 * n) if len(la.core(2)) == 0] def rank(self, v): r""" @@ -4269,6 +4224,7 @@ def forward_rule(self, y, t, x, content): sage: Domino.forward_rule([2,1,1], [2], [4], 0) [4, 1, 1] """ + def union(la, mu): r""" Return the union of the two partitions. @@ -4289,7 +4245,7 @@ def union(la, mu): elif content == -1: if not (x == t == y): raise ValueError("all shapes must be equal") - z = t + [1,1] + z = t + [1, 1] elif content == 0 and (t == x or t == y): z = union(x, y) @@ -4314,12 +4270,12 @@ def union(la, mu): # either (k, l+1) or (k+1, l) must also be added if z[k] <= l + 1: z[k] += 1 - z[k+1] += 1 + z[k + 1] += 1 else: if len(z) <= k + 1: z += [2] else: - z[k+1] += 2 + z[k + 1] += 2 # diff has size 2, that is x == y elif cell1[0] == cell2[0]: @@ -4328,7 +4284,7 @@ def union(la, mu): if len(z) <= cell1[0] + 1: z += [2] else: - z[cell1[0]+1] += 2 + z[cell1[0] + 1] += 2 else: z = copy(x) @@ -4337,14 +4293,14 @@ def union(la, mu): for r, p in enumerate(z): if p <= cell1[1] + 1: z[r] += 1 - z[r+1] += 1 + z[r + 1] += 1 break else: - raise NotImplementedError("domino: cannot call forward rule with shapes %s and content %s" - % ((y, t, x), content)) + raise NotImplementedError("domino: cannot call forward rule with shapes %s and content %s" % ((y, t, x), content)) return z + ##################################################################### ## Set the rules available from GrowthDiagram.rules. ##################################################################### @@ -4354,6 +4310,7 @@ class Rules: """ Catalog of rules for growth diagrams. """ + ShiftedShapes = RuleShiftedShapes LLMS = RuleLLMS BinaryWord = RuleBinaryWord diff --git a/src/sage/combinat/hall_polynomial.py b/src/sage/combinat/hall_polynomial.py index 5b8d60eb7db..edc86a45211 100644 --- a/src/sage/combinat/hall_polynomial.py +++ b/src/sage/combinat/hall_polynomial.py @@ -164,24 +164,23 @@ def hall_polynomial(nu, mu, la, q=None): return R.zero() if all(x == 1 for x in la): - r = [len(la)] # r will be [r_0, r_1, ..., r_n]. + r = [len(la)] # r will be [r_0, r_1, ..., r_n]. exp_nu = nu.to_exp() # exp_nu == [l_1, l_2, ..., l_n]. exp_mu = mu.to_exp() # exp_mu == [m_1, m_2, ..., m_n]. n = max(len(exp_nu), len(exp_mu)) for k in range(n): r.append(r[-1] + sum(exp_mu[k:]) - sum(exp_nu[k:])) # Now, r is [r_0, r_1, ..., r_n]. - exp_nu += [0]*(n - len(exp_nu)) # Pad with 0s until it has length n + exp_nu += [0] * (n - len(exp_nu)) # Pad with 0s until it has length n # Note that all -1 for exp_nu is due to indexing - t = sum((r[k-2] - r[k-1])*(sum(exp_nu[k-1:]) - r[k-1]) for k in range(2,n+1)) + t = sum((r[k - 2] - r[k - 1]) * (sum(exp_nu[k - 1 :]) - r[k - 1]) for k in range(2, n + 1)) if t < 0: # This case needs short-circuiting, since otherwise q**-t # might throw an exception if q is non-invertible. return R.zero() - return q**t * q_binomial(exp_nu[n-1], r[n-1], q) \ - * prod([q_binomial(exp_nu[k-1], r[k-1] - r[k], q) - for k in range(1, n)], R.one()) + return q**t * q_binomial(exp_nu[n - 1], r[n - 1], q) * prod([q_binomial(exp_nu[k - 1], r[k - 1] - r[k], q) for k in range(1, n)], R.one()) from sage.algebras.hall_algebra import HallAlgebra + H = HallAlgebra(R, q) - return (H[mu]*H[la]).coefficient(nu) + return (H[mu] * H[la]).coefficient(nu) diff --git a/src/sage/combinat/hillman_grassl.py b/src/sage/combinat/hillman_grassl.py index f55248030d1..b7a20197011 100644 --- a/src/sage/combinat/hillman_grassl.py +++ b/src/sage/combinat/hillman_grassl.py @@ -142,6 +142,7 @@ class WeakReversePlanePartition(Tableau): sage: x.shape() [3, 3, 3, 3, 1] """ + @staticmethod def __classcall_private__(cls, r): r""" @@ -411,6 +412,7 @@ class WeakReversePlanePartitions(Tableaux): r""" The set of all weak reverse plane partitions. """ + @staticmethod def __classcall_private__(cls, shape=None, **kwds): """ diff --git a/src/sage/combinat/integer_lists/__init__.py b/src/sage/combinat/integer_lists/__init__.py index 4e0c59ff8a6..0e7f199cae3 100644 --- a/src/sage/combinat/integer_lists/__init__.py +++ b/src/sage/combinat/integer_lists/__init__.py @@ -3,4 +3,5 @@ from .invlex import IntegerListsLex from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.combinat.integer_list', 'IntegerListsLex', IntegerListsLex) diff --git a/src/sage/combinat/integer_lists/lists.py b/src/sage/combinat/integer_lists/lists.py index e9019b4ec2e..f0de472dd2b 100644 --- a/src/sage/combinat/integer_lists/lists.py +++ b/src/sage/combinat/integer_lists/lists.py @@ -31,6 +31,7 @@ class IntegerList(ClonableArray): """ Element class for :class:`IntegerLists`. """ + def check(self): """ Check to make sure this is a valid element in its @@ -80,6 +81,7 @@ class IntegerLists(Parent): sage: IntegerListsLex(2, length=3, name="A given name") A given name """ + backend = None backend_class = IntegerListsBackend diff --git a/src/sage/combinat/integer_lists/nn.py b/src/sage/combinat/integer_lists/nn.py index 9b1aafa5078..85f29b96748 100644 --- a/src/sage/combinat/integer_lists/nn.py +++ b/src/sage/combinat/integer_lists/nn.py @@ -1,6 +1,7 @@ """ Lists of nonnegative integers with constraints. """ + from sage.sets.family import Family from sage.combinat.integer_lists import IntegerListsLex from sage.rings.semirings.non_negative_integer_semiring import NN diff --git a/src/sage/combinat/integer_matrices.py b/src/sage/combinat/integer_matrices.py index ba7f2dd90bb..6a0de9ee79b 100644 --- a/src/sage/combinat/integer_matrices.py +++ b/src/sage/combinat/integer_matrices.py @@ -52,6 +52,7 @@ class IntegerMatrices(UniqueRepresentation, Parent): sage: IM.cardinality() 6 """ + @staticmethod def __classcall__(cls, row_sums, column_sums): r""" @@ -73,6 +74,7 @@ def __classcall__(cls, row_sums, column_sums): Non-negative integer matrices with row sums [4, 4, 5] and column sums [3, 7, 1, 2] """ from sage.combinat.composition import Composition + row_sums = Composition(row_sums) column_sums = Composition(column_sums) return super().__classcall__(cls, row_sums, column_sums) @@ -106,8 +108,7 @@ def _repr_(self): sage: IntegerMatrices([3,2,2], [2,5])._repr_() 'Non-negative integer matrices with row sums [3, 2, 2] and column sums [2, 5]' """ - return "Non-negative integer matrices with row sums %s and column sums %s" % \ - (self._row_sums, self._col_sums) + return "Non-negative integer matrices with row sums %s and column sums %s" % (self._row_sums, self._col_sums) def __iter__(self): r""" @@ -165,6 +166,7 @@ def __contains__(self, x): False """ from sage.structure.element import Matrix + if not isinstance(x, Matrix): return False row_sums = [ZZ.zero()] * x.nrows() @@ -216,6 +218,7 @@ def cardinality(self): """ from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.partition import Partition + h = SymmetricFunctions(ZZ).homogeneous() row_partition = Partition(sorted(self._row_sums, reverse=True)) col_partition = Partition(sorted(self._col_sums, reverse=True)) @@ -283,6 +286,7 @@ def to_composition(self, x): [3, 2, 2] """ from sage.combinat.composition import Composition + return Composition([entry for row in x for entry in row if entry != 0]) diff --git a/src/sage/combinat/integer_vector.py b/src/sage/combinat/integer_vector.py index e16c646ac70..10328ea3785 100644 --- a/src/sage/combinat/integer_vector.py +++ b/src/sage/combinat/integer_vector.py @@ -12,6 +12,7 @@ - Federico Poloni (2013): specialized ``rank()`` - Travis Scrimshaw (2013-02-04): refactored to use ``ClonableIntArray`` """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # Copyright (C) 2012 Travis Scrimshaw @@ -110,6 +111,7 @@ def is_gale_ryser(r, s): # builds the corresponding partitions, i.e. # removes the 0 and sorts the sequences from sage.combinat.partition import Partition + r2 = Partition(sorted([x for x in r if x > 0], reverse=True)) s2 = Partition(sorted([x for x in s if x > 0], reverse=True)) @@ -123,8 +125,7 @@ def is_gale_ryser(r, s): return len(rstar) <= len(s2) and sum(r2) == sum(s2) and rstar.dominates(s) -def gale_ryser_theorem(p1, p2, algorithm='gale', - *, solver=None, integrality_tolerance=1e-3): +def gale_ryser_theorem(p1, p2, algorithm='gale', *, solver=None, integrality_tolerance=1e-3): r""" Return the binary matrix given by the Gale-Ryser theorem. @@ -321,12 +322,12 @@ def gale_ryser_theorem(p1, p2, algorithm='gale', # applied tmp = sorted(enumerate(p1), reverse=True, key=lambda x: x[1]) r = [x[1] for x in tmp] - r_permutation = [x-1 for x in Permutation([x[0]+1 for x in tmp]).inverse()] + r_permutation = [x - 1 for x in Permutation([x[0] + 1 for x in tmp]).inverse()] m = len(r) tmp = sorted(enumerate(p2), reverse=True, key=lambda x: x[1]) s = [x[1] for x in tmp] - s_permutation = [x-1 for x in Permutation([x[0]+1 for x in tmp]).inverse()] + s_permutation = [x - 1 for x in Permutation([x[0] + 1 for x in tmp]).inverse()] # This is the partition equivalent to the sliding algorithm cols = [] @@ -343,7 +344,7 @@ def gale_ryser_theorem(p1, p2, algorithm='gale', c[j] = 1 t -= k - i else: # Remove the t last rows of that length - for j in range(k-t, k): + for j in range(k - t, k): r[j] -= 1 c[j] = 1 t = 0 @@ -360,6 +361,7 @@ def gale_ryser_theorem(p1, p2, algorithm='gale', if algorithm == "gale": from sage.numerical.mip import MixedIntegerLinearProgram + k1, k2 = len(p1), len(p2) p = MixedIntegerLinearProgram(solver=solver) b = p.new_variable(binary=True) @@ -436,6 +438,7 @@ def list2func(l, default=None): if default is None: return lambda i: l[i] from functools import partial + return partial(_default_function, l, default) @@ -522,8 +525,10 @@ def specht_module(self, base_ring=None): """ from sage.combinat.specht_module import SpechtModule from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra + if base_ring is None: from sage.rings.rational_field import QQ + base_ring = QQ R = SymmetricGroupAlgebra(base_ring, sum(self)) return SpechtModule(R, self) @@ -544,6 +549,7 @@ def specht_module_dimension(self, base_ring=None): 5 """ from sage.combinat.specht_module import specht_module_rank + return specht_module_rank(self, base_ring) @@ -672,6 +678,7 @@ class IntegerVectors(Parent, metaclass=ClasscallMetaclass): :class:`sage.combinat.integer_lists.invlex.IntegerListsLex` """ + @staticmethod def __classcall_private__(cls, n=None, k=None, **kwargs): """ @@ -801,12 +808,12 @@ def _unrank_helper(self, x, rtn): while True: current_rank = self.rank(rtn) if current_rank < x: - rtn[ptr+1] = rtn[ptr] + rtn[ptr + 1] = rtn[ptr] rtn[ptr] = 0 ptr += 1 elif current_rank > x: rtn[ptr] -= 1 - rtn[ptr-1] += 1 + rtn[ptr - 1] += 1 else: return self._element_constructor_(rtn) @@ -826,6 +833,7 @@ def is_finite(self): True """ from sage.rings.infinity import Infinity + return self.cardinality() < Infinity @@ -1139,7 +1147,7 @@ def unrank(self, x): """ if self.k == 0 and x != 0: raise IndexError(f"Index {x} is out of range for the IntegerVector.") - rtn = [0]*self.k + rtn = [0] * self.k if self.k == 0 and x == 0: return rtn @@ -1255,7 +1263,7 @@ def __iter__(self): yield self.element_class(self, [self.n], check=False) return - for nbar in range(self.n+1): + for nbar in range(self.n + 1): n = self.n - nbar for rest in integer_vectors_nk_fast_iter(nbar, self.k - 1): yield self.element_class(self, [n] + rest, check=False) @@ -1268,8 +1276,7 @@ def _repr_(self): sage: IV Integer vectors of length 3 that sum to 2 """ - return "Integer vectors of length {} that sum to {}".format(self.k, - self.n) + return "Integer vectors of length {} that sum to {}".format(self.k, self.n) def __contains__(self, x): """ @@ -1367,7 +1374,7 @@ def unrank(self, x): """ if x >= self.cardinality(): raise IndexError(f"Index {x} is out of range for the IntegerVector.") - rtn = [0]*self.k + rtn = [0] * self.k rtn[0] = self.n return IntegerVectors._unrank_helper(self, x, rtn) @@ -1427,6 +1434,7 @@ class IntegerVectors_nnondescents(UniqueRepresentation, IntegerVectors): they form a set of orbit representative of integer vectors with respect to this Young subgroup. """ + @staticmethod def __classcall_private__(cls, n, comp): """ @@ -1514,8 +1522,7 @@ def __iter__(self): [[0, 0, 0, 0, 0]] """ for iv in IntegerVectors(self.n, len(self.comp)): - blocks = [IntegerVectors(iv[i], val, max_slope=0).list() - for i, val in enumerate(self.comp)] + blocks = [IntegerVectors(iv[i], val, max_slope=0).list() for i, val in enumerate(self.comp)] for parts in product(*blocks): res = [] for part in parts: @@ -1583,8 +1590,7 @@ def _repr_(self): base = "Integer vectors that sum to {} with constraints: ".format(self.n) else: base = "Integer vectors with constraints: " - return base + ", ".join("{}={}".format(key, self.constraints[key]) - for key in sorted(self.constraints)) + return base + ", ".join("{}={}".format(key, self.constraints[key]) for key in sorted(self.constraints)) def __eq__(self, rhs): """ @@ -1652,6 +1658,7 @@ def __contains__(self, x): return False from sage.combinat.misc import check_integer_list_constraints + return check_integer_list_constraints(x, singleton=True, **self.constraints) def cardinality(self): @@ -1676,16 +1683,12 @@ def cardinality(self): if self.k is None: if self.n is None: return PlusInfinity() - if ('max_length' not in self.constraints - and self.constraints.get('min_part', 0) <= 0): + if 'max_length' not in self.constraints and self.constraints.get('min_part', 0) <= 0: return PlusInfinity() - elif ('max_part' in self.constraints - and self.constraints['max_part'] != PlusInfinity()): - if (self.n is None and len(self.constraints) == 2 - and 'min_part' in self.constraints - and self.constraints['min_part'] >= 0): + elif 'max_part' in self.constraints and self.constraints['max_part'] != PlusInfinity(): + if self.n is None and len(self.constraints) == 2 and 'min_part' in self.constraints and self.constraints['min_part'] >= 0: num = self.constraints['max_part'] - self.constraints['min_part'] + 1 - return Integer(num ** self.k) + return Integer(num**self.k) if len(self.constraints) == 1: m = self.constraints['max_part'] if self.n is None: @@ -1695,9 +1698,7 @@ def cardinality(self): # do by inclusion / exclusion on the number # i of parts greater than m n, k = self.n, self.k - return Integer(sum( - (-1)**i * binomial(n + k - 1 - i * (m + 1), k - 1) - * binomial(k, i) for i in range(self.n // (m + 1) + 1))) + return Integer(sum((-1) ** i * binomial(n + k - 1 - i * (m + 1), k - 1) * binomial(k, i) for i in range(self.n // (m + 1) + 1))) return ZZ.sum(ZZ.one() for x in self) def __iter__(self): @@ -1840,5 +1841,6 @@ def integer_vectors_nk_fast_iter(n, k): # October 2012: fixing outdated pickles which use classes being deprecated from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.combinat.integer_vector', 'IntegerVectors_nconstraints', IntegerVectorsConstraints) register_unpickle_override('sage.combinat.integer_vector', 'IntegerVectors_nkconstraints', IntegerVectorsConstraints) diff --git a/src/sage/combinat/integer_vector_weighted.py b/src/sage/combinat/integer_vector_weighted.py index 79bca8159dc..19b25c1f0c0 100644 --- a/src/sage/combinat/integer_vector_weighted.py +++ b/src/sage/combinat/integer_vector_weighted.py @@ -6,6 +6,7 @@ - Mike Hansen (2007): initial version, ported from MuPAD-Combinat - Nicolas M. Thiery (2010-10-30): WeightedIntegerVectors(weights) + cleanup """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen # 2010 Nicolas M. Thiery @@ -76,6 +77,7 @@ class WeightedIntegerVectors(Parent, UniqueRepresentation): Should the order of the arguments ``n`` and ``weight`` be exchanged to simplify the logic? """ + @staticmethod def __classcall_private__(cls, n=None, weight=None): """ @@ -285,14 +287,15 @@ def __init__(self, weight): self._weights = weight from sage.sets.family import Family from sage.sets.non_negative_integers import NonNegativeIntegers + # Use "partial" to make the basis function (with the weights # argument specified) pickleable. Otherwise, it seems to # cause problems... from functools import partial + F = Family(NonNegativeIntegers(), partial(WeightedIntegerVectors, weight=weight)) cat = (SetsWithGrading(), InfiniteEnumeratedSets()) - DisjointUnionEnumeratedSets.__init__(self, F, facade=True, keepkey=False, - category=cat) + DisjointUnionEnumeratedSets.__init__(self, F, facade=True, keepkey=False, category=cat) def _repr_(self): """ @@ -316,9 +319,7 @@ def __contains__(self, x): sage: [3,-1,0] in WeightedIntegerVectors([2,1,1]) False """ - return (isinstance(x, (list, IntegerVector, Permutation)) - and len(x) == len(self._weights) - and all(i in ZZ and i >= 0 for i in x)) + return isinstance(x, (list, IntegerVector, Permutation)) and len(x) == len(self._weights) and all(i in ZZ and i >= 0 for i in x) def subset(self, size=None): """ @@ -332,7 +333,7 @@ def subset(self, size=None): return self return self._family[size] - def grading(self, x): # or degree / grading + def grading(self, x): # or degree / grading """ EXAMPLES:: @@ -382,7 +383,7 @@ def iterator_fast(n, l): k = 0 cur = [n // l[k] + one] - rem = n - cur[-1] * l[k] # Amount remaining + rem = n - cur[-1] * l[k] # Amount remaining while cur: cur[-1] -= one rem += l[k] @@ -401,4 +402,5 @@ def iterator_fast(n, l): from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.combinat.integer_vector_weighted', 'WeightedIntegerVectors_nweight', WeightedIntegerVectors) diff --git a/src/sage/combinat/integer_vectors_mod_permgroup.py b/src/sage/combinat/integer_vectors_mod_permgroup.py index 29a25b6470f..bbc661354a4 100644 --- a/src/sage/combinat/integer_vectors_mod_permgroup.py +++ b/src/sage/combinat/integer_vectors_mod_permgroup.py @@ -244,6 +244,7 @@ class IntegerVectorsModPermutationGroup(UniqueRepresentation): 1287 2002 """ + @staticmethod def __classcall__(cls, G, sum=None, max_part=None, sgs=None): r""" @@ -264,15 +265,13 @@ def __classcall__(cls, G, sum=None, max_part=None, sgs=None): # Nonempty domain, infinite set. return IntegerVectorsModPermutationGroup_All(G, sgs=sgs) # Empty domain, singleton set. - return IntegerVectorsModPermutationGroup_with_constraints( - G, 0, max_part=-1, sgs=sgs) + return IntegerVectorsModPermutationGroup_with_constraints(G, 0, max_part=-1, sgs=sgs) # Some constraints, either sum or max_part or both. if sum is not None: assert sum == NN(sum) if max_part is not None: assert max_part == NN(max_part) - return IntegerVectorsModPermutationGroup_with_constraints( - G, sum, max_part, sgs=sgs) + return IntegerVectorsModPermutationGroup_with_constraints(G, sum, max_part, sgs=sgs) class IntegerVectorsModPermutationGroup_All(UniqueRepresentation, RecursivelyEnumeratedSet_forest): @@ -424,7 +423,16 @@ def roots(self): sage: I.roots() [[0, 0, 0, 0]] """ - return [self.element_class(self, self.n*[0,], check=False)] + return [ + self.element_class( + self, + self.n + * [ + 0, + ], + check=False, + ) + ] def children(self, x): r""" @@ -477,9 +485,9 @@ def is_canonical(self, v, check=True): """ if check: assert isinstance(v, (ClonableIntArray, list)), '%s should be a list or an integer vector' % v - assert (self.n == len(v)), '%s should be of length %s' % (v, self.n) + assert self.n == len(v), '%s should be of length %s' % (v, self.n) for p in v: - assert (p == NN(p)), 'Elements of %s should be integers' % v + assert p == NN(p), 'Elements of %s should be integers' % v return is_canonical(self._sgs, self.element_class(self, list(v), check=False)) def __contains__(self, v): @@ -680,19 +688,9 @@ def _repr_(self): """ if self._sum is not None: if self._max_part >= 0: - return ("Vectors of length %s and of sum %s" - " whose entries are in {0, ..., %s}" - " enumerated up to the action of %s" - % (self.n, self._sum, self._max_part, - self.permutation_group())) - return ("Integer vectors of length %s" - " and of sum %s" - " enumerated up to the action of %s" - % (self.n, self._sum, self.permutation_group())) - return ("Integer vectors of length %s" - " whose entries are in {0, ..., %s}" - " enumerated up to the action of %s" - % (self.n, self._max_part, self.permutation_group())) + return "Vectors of length %s and of sum %s" " whose entries are in {0, ..., %s}" " enumerated up to the action of %s" % (self.n, self._sum, self._max_part, self.permutation_group()) + return "Integer vectors of length %s" " and of sum %s" " enumerated up to the action of %s" % (self.n, self._sum, self.permutation_group()) + return "Integer vectors of length %s" " whose entries are in {0, ..., %s}" " enumerated up to the action of %s" % (self.n, self._max_part, self.permutation_group()) def roots(self): r""" @@ -709,7 +707,16 @@ def roots(self): sage: I.roots() [[0, 0, 0, 0]] """ - return [self.element_class(self, self.n*[0,], check=False)] + return [ + self.element_class( + self, + self.n + * [ + 0, + ], + check=False, + ) + ] def children(self, x): r""" @@ -838,12 +845,7 @@ def __iter__(self): # General case, nonempty domain. if self._max_part < 0: return self.elements_of_depth_iterator(self._sum) - SF = RecursivelyEnumeratedSet_forest( - (self([0]*(self.n), check=False),), - lambda x: [self(y, check=False) - for y in canonical_children( - self._sgs, x, self._max_part)], - algorithm='breadth') + SF = RecursivelyEnumeratedSet_forest((self([0] * (self.n), check=False),), lambda x: [self(y, check=False) for y in canonical_children(self._sgs, x, self._max_part)], algorithm='breadth') if self._sum is None: return iter(SF) return SF.elements_of_depth_iterator(self._sum) @@ -936,11 +938,11 @@ def cardinality(self): 4263421511271 """ G = self._permgroup - k = G.degree() # Vector length - d = self._sum # Required sum - m = self._max_part # Max of one entry, -1 for no limit + k = G.degree() # Vector length + d = self._sum # Required sum + m = self._max_part # Max of one entry, -1 for no limit if m == -1: - m = d # Any entry cannot exceed total + m = d # Any entry cannot exceed total # Some easy special cases. if k == 0: @@ -972,25 +974,21 @@ def cardinality(self): if d is None: # Case 1. Without a fixed sum, the sum can be up to k*m. - result = sum(coeff * (m+1)**len(cycle_type) - for cycle_type, coeff in Z) + result = sum(coeff * (m + 1) ** len(cycle_type) for cycle_type, coeff in Z) # Computed as Rational, but should have an integer value # by now. return Integer(result) # Case 2. Fixed sum d. Work with power series with enough # precision that x^d is valid. - R = PowerSeriesRing(QQ, 'x', default_prec=d+1) + R = PowerSeriesRing(QQ, 'x', default_prec=d + 1) x = R.gen() # The figure-counting series, for max_part==m, is (1-t**(m+1)) # / (1-t) = 1+t+...+t**m. For the function-counting series, # we substitute x**cycle_length for t. # - funcount = sum( - coeff * prod((1 - x**((m+1)*cycle_len)) / (1 - x**cycle_len) - for cycle_len in cycle_type) - for cycle_type, coeff in Z) + funcount = sum(coeff * prod((1 - x ** ((m + 1) * cycle_len)) / (1 - x**cycle_len) for cycle_len in cycle_type) for cycle_type, coeff in Z) # Extract the d'th degree coefficient. Computed as Rational, # but should have an integer value by now. @@ -1020,9 +1018,9 @@ def is_canonical(self, v, check=True): """ if check: assert isinstance(v, (ClonableIntArray, list)), '%s should be a list or an integer vector' % v - assert (self.n == len(v)), '%s should be of length %s' % (v, self.n) + assert self.n == len(v), '%s should be of length %s' % (v, self.n) for p in v: - assert (p == NN(p)), 'Elements of %s should be integers' % v + assert p == NN(p), 'Elements of %s should be integers' % v return is_canonical(self._sgs, self.element_class(self, list(v), check=False)) def ambient(self): @@ -1146,12 +1144,13 @@ def _an_element_(self): EmptySetError """ if self._max_part < 0: - return self([self._sum]+(self.n-1)*[0], check=False) + return self([self._sum] + (self.n - 1) * [0], check=False) try: v = iter(self) return next(v) except StopIteration: from sage.categories.sets_cat import EmptySetError + raise EmptySetError def orbit(self, v): diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index 065d38db469..e09860b8ce5 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -21,6 +21,7 @@ - Darij Grinberg 2014: review - Travis Scrimshaw 2014: review """ + # **************************************************************************** # Copyright (C) 2013 Viviane Pons , # @@ -64,12 +65,10 @@ lazy_import('sage.combinat.dyck_word', 'DyckWords') -lazy_import('sage.combinat.tamari_blossoming_tree', - ['TamariBlossomingTree', 'TamariBlossomingTrees']) +lazy_import('sage.combinat.tamari_blossoming_tree', ['TamariBlossomingTree', 'TamariBlossomingTrees']) -class TamariIntervalPoset(Element, - metaclass=InheritComparisonClasscallMetaclass): +class TamariIntervalPoset(Element, metaclass=InheritComparisonClasscallMetaclass): r""" The class of Tamari interval-posets. @@ -193,6 +192,7 @@ class TamariIntervalPoset(Element, sage: TIP(Poset({})) The Tamari interval of size 0 induced by relations [] """ + @staticmethod def __classcall_private__(cls, *args, **opts) -> TIP: r""" @@ -404,12 +404,11 @@ def _find_node_positions(self, hspace=1, vspace=1) -> dict[int, list]: for i in range(2, self.size() + 1): decreasing_parent = self.decreasing_parent(i) increasing_parent = self.increasing_parent(i) - while to_draw and (decreasing_parent is None or - decreasing_parent < to_draw[-1][0]): + while to_draw and (decreasing_parent is None or decreasing_parent < to_draw[-1][0]): n = to_draw.pop() node_positions[n[0]] = [x, n[1]] if i != current_parent[-1]: - if (not self.le(i, i - 1) and decreasing_parent is not None): + if not self.le(i, i - 1) and decreasing_parent is not None: x += hspace if current_parent[-1] is not None: y -= vspace @@ -454,8 +453,8 @@ def plot(self, **kwds): sage: ti.plot() # needs sage.plot Graphics object consisting of 6 graphics primitives """ - c0 = 'blue' # self.latex_options()["color_increasing"] - c1 = 'red' # self.latex_options()["color_decreasing"] + c0 = 'blue' # self.latex_options()["color_increasing"] + c1 = 'red' # self.latex_options()["color_decreasing"] G = self.poset().hasse_diagram() G.set_pos(self._find_node_positions()) for a, b in G.edges(sort=False, labels=False): @@ -599,10 +598,8 @@ def _mul_(self, other: TIP) -> TIP: n = self._size m = other.size() relations = self._poset.cover_relations() - relations.extend((i + n, j + n) - for i, j in other._poset.cover_relations_iterator()) - P = FinitePoset(DiGraph([list(range(1, n + m + 1)), relations], - format='vertices_and_edges')) # type:ignore + relations.extend((i + n, j + n) for i, j in other._poset.cover_relations_iterator()) + P = FinitePoset(DiGraph([list(range(1, n + m + 1)), relations], format='vertices_and_edges')) # type:ignore return TamariIntervalPoset(P, check=False) # type:ignore def factor(self) -> list[TamariIntervalPoset]: @@ -633,8 +630,7 @@ def factor(self) -> list[TamariIntervalPoset]: for comp in sorted(cc, key=min): shift = 1 - min(comp) comp.relabel(lambda i: i + shift) - resu.append(TamariIntervalPoset(len(comp), - comp.edges(sort=False, labels=False))) + resu.append(TamariIntervalPoset(len(comp), comp.edges(sort=False, labels=False))) return resu def __hash__(self): @@ -1094,10 +1090,8 @@ def complement(self) -> TIP: True """ N = self._size + 1 - new_covers = [[N - i, N - j] - for i, j in self._poset.cover_relations_iterator()] - P = FinitePoset(DiGraph([list(range(1, N)), new_covers], - format='vertices_and_edges')) # type:ignore + new_covers = [[N - i, N - j] for i, j in self._poset.cover_relations_iterator()] + P = FinitePoset(DiGraph([list(range(1, N)), new_covers], format='vertices_and_edges')) # type:ignore return TamariIntervalPoset(P, check=False) # type:ignore def left_branch_involution(self) -> TIP: @@ -1254,17 +1248,15 @@ def insertion(self, i) -> TIP: """ n = self._size if not 0 < i <= n + 1: - raise ValueError("integer to be inserted not " - "in the appropriate interval") + raise ValueError("integer to be inserted not " "in the appropriate interval") def add1(u): if u >= i: return u + 1 return u - rels = [(add1(a), add1(b)) - for a, b in self.decreasing_cover_relations()] - rels += [(add1(a), add1(b)) - for a, b in self.increasing_cover_relations()] + + rels = [(add1(a), add1(b)) for a, b in self.decreasing_cover_relations()] + rels += [(add1(a), add1(b)) for a, b in self.increasing_cover_relations()] rels += [(k, k - 1) for k in [i] if i > 1] rels += [(k, k + 1) for k in [i] if i <= n] return TamariIntervalPoset(n + 1, rels) @@ -1283,9 +1275,7 @@ def _repr_(self) -> str: The Tamari interval of size 3 induced by relations [(2, 3), (2, 1)] """ msg = "The Tamari interval of size {} induced by relations {}" - return msg.format(self.size(), - self.increasing_cover_relations() + - self.decreasing_cover_relations()) + return msg.format(self.size(), self.increasing_cover_relations() + self.decreasing_cover_relations()) def _ascii_art_(self): """ @@ -1375,6 +1365,7 @@ def superpose_node(i, right=True): superpose(k, j, ' | ') from sage.typeset.ascii_art import AsciiArt + return AsciiArt([''.join(ligne) for ligne in M]) def _unicode_art_(self): @@ -1451,6 +1442,7 @@ def superpose(x, y, b): superpose(k, j, '│') from sage.typeset.unicode_art import UnicodeArt + return UnicodeArt([''.join(ligne) for ligne in M]) def _richcmp_(self, other, op) -> bool: @@ -1490,13 +1482,10 @@ def _richcmp_(self, other, op) -> bool: if not isinstance(other, TamariIntervalPoset): return NotImplemented if op == op_EQ: - return (self.size() == other.size() and - self._cover_relations == other._cover_relations) + return self.size() == other.size() and self._cover_relations == other._cover_relations if op == op_NE: - return not (self.size() == other.size() and - self._cover_relations == other._cover_relations) - return richcmp((self.size(), self.cubical_coordinates()), - (other.size(), other.cubical_coordinates()), op) + return not (self.size() == other.size() and self._cover_relations == other._cover_relations) + return richcmp((self.size(), self.cubical_coordinates()), (other.size(), other.cubical_coordinates()), op) def __iter__(self) -> Iterator[int]: r""" @@ -1577,8 +1566,7 @@ def lower_contains_interval(self, other) -> bool: """ if not self.contains_interval(other): return False - return all(self.le(i, j) - for i, j in other.decreasing_cover_relations()) + return all(self.le(i, j) for i, j in other.decreasing_cover_relations()) def upper_contains_interval(self, other) -> bool: r""" @@ -1618,8 +1606,7 @@ def upper_contains_interval(self, other) -> bool: """ if not self.contains_interval(other): return False - return all(self.le(i, j) - for i, j in other.increasing_cover_relations()) + return all(self.le(i, j) for i, j in other.increasing_cover_relations()) def is_linear_extension(self, perm) -> bool: r""" @@ -1751,8 +1738,7 @@ def initial_forest(self) -> TIP: True """ relations = self.increasing_cover_relations() - P = FinitePoset(DiGraph([list(range(1, self._size + 1)), relations], - format='vertices_and_edges')) # type:ignore + P = FinitePoset(DiGraph([list(range(1, self._size + 1)), relations], format='vertices_and_edges')) # type:ignore return TamariIntervalPoset(P, check=False) # type:ignore def final_forest(self) -> TIP: @@ -1771,8 +1757,7 @@ def final_forest(self) -> TIP: True """ relations = self.decreasing_cover_relations() - P = FinitePoset(DiGraph([list(range(1, self._size + 1)), relations], - format='vertices_and_edges')) # type:ignore + P = FinitePoset(DiGraph([list(range(1, self._size + 1)), relations], format='vertices_and_edges')) # type:ignore return TamariIntervalPoset(P, check=False) # type:ignore def is_initial_interval(self) -> bool: @@ -2004,12 +1989,8 @@ def subposet(self, start, end) -> TIP: raise ValueError("invalid starting or ending value") if start == end: return TamariIntervalPoset(0, []) - relations = [(i - start + 1, j - start + 1) - for i, j in self.increasing_cover_relations() - if i >= start and j < end] - relations.extend((j - start + 1, i - start + 1) - for j, i in self.decreasing_cover_relations() - if i >= start and j < end) + relations = [(i - start + 1, j - start + 1) for i, j in self.increasing_cover_relations() if i >= start and j < end] + relations.extend((j - start + 1, i - start + 1) for j, i in self.decreasing_cover_relations() if i >= start and j < end) return TamariIntervalPoset(end - start, relations, check=False) sub_poset = subposet @@ -2046,9 +2027,7 @@ class of ``self.lower_binary_tree()`` and is a 312-avoiding """ # The min linear extension is built by postfix-reading the # final forest of ``self``. - final_forest = DiGraph([list(self), - self.decreasing_cover_relations()], - format='vertices_and_edges') + final_forest = DiGraph([list(self), self.decreasing_cover_relations()], format='vertices_and_edges') def add(perm: list, i): r""" @@ -2057,6 +2036,7 @@ def add(perm: list, i): for j in sorted(final_forest.neighbors_in(i)): add(perm, j) perm.append(i) + perm: list[int] = [] for i in sorted(final_forest.sinks()): add(perm, i) @@ -2096,9 +2076,7 @@ class of ``self.upper_binary_tree()`` and is a 132-avoiding """ # The max linear extension is built by right-to-left # postfix-reading the initial forest of ``self``. - initial_forest = DiGraph([list(self), - self.increasing_cover_relations()], - format='vertices_and_edges') + initial_forest = DiGraph([list(self), self.increasing_cover_relations()], format='vertices_and_edges') def add(perm: list, i): r""" @@ -2107,6 +2085,7 @@ def add(perm: list, i): for j in sorted(initial_forest.neighbors_in(i), reverse=True): add(perm, j) perm.append(i) + perm: list[int] = [] for i in sorted(initial_forest.sinks(), reverse=True): add(perm, i) @@ -2183,6 +2162,7 @@ def lower_contained_intervals(self) -> Iterator[TIP]: interval-posets, and is the reason why this and other iterators don't yield invalid interval-posets. """ + def add_relations(poset, n, m): r""" Internal recursive method to generate all possible intervals. @@ -2461,14 +2441,10 @@ def tamari_inversions_iter(self) -> Iterator[tuple[int, int]]: sage: list(T.tamari_inversions_iter()) [] """ - final_forest = DiGraph([list(self), - self.decreasing_cover_relations()], - format='vertices_and_edges') - initial_forest = DiGraph([list(self), - self.increasing_cover_relations()], - format='vertices_and_edges') + final_forest = DiGraph([list(self), self.decreasing_cover_relations()], format='vertices_and_edges') + initial_forest = DiGraph([list(self), self.increasing_cover_relations()], format='vertices_and_edges') n1 = self.size() + 1 - for a in range(1, self.size()): # a == n will never work + for a in range(1, self.size()): # a == n will never work try: ipa = next(initial_forest.neighbor_out_iterator(a)) max_b_1 = ipa @@ -2565,6 +2541,7 @@ def new_decomposition(self) -> list[TIP]: True """ from sage.combinat.binary_tree import BinaryTree + t_low = self.lower_binary_tree().to_tilting() t_up = self.upper_binary_tree().to_tilting() common = [p for p in t_low if p in t_up] @@ -2588,9 +2565,7 @@ def extract_tree(x, y, tilt, common): return BinaryTree([left_tree, right_tree], check=False) tip = self.parent() - return [tip.from_binary_trees(extract_tree(cx, cy, t_low, common), - extract_tree(cx, cy, t_up, common)) - for cx, cy in common] + return [tip.from_binary_trees(extract_tree(cx, cy, t_low, common), extract_tree(cx, cy, t_up, common)) for cx, cy in common] def decomposition_to_triple(self) -> tuple[TIP, TIP, int] | None: """ @@ -2661,8 +2636,7 @@ def grafting_tree(self) -> LabelledBinaryTree: triplet = self.decomposition_to_triple() assert triplet is not None left, right, r = triplet - return LabelledBinaryTree([left.grafting_tree(), - right.grafting_tree()], label=r) + return LabelledBinaryTree([left.grafting_tree(), right.grafting_tree()], label=r) def is_new(self) -> bool: """ @@ -2905,6 +2879,7 @@ class TamariIntervalPosets(UniqueRepresentation, Parent): This is a factory class whose constructor returns instances of subclasses. """ + @staticmethod def __classcall_private__(cls, n=None): r""" @@ -2958,35 +2933,15 @@ class options(GlobalOptions): sage: TIP.options.latex_color_decreasing red """ + NAME = 'TamariIntervalPosets' module = 'sage.combinat.interval_posets' - latex_tikz_scale = dict( - default=1, - description='the default value for the tikz scale when latexed', - checker=lambda x: True) # More trouble than it's worth to check - latex_line_width_scalar = dict( - default=0.5, - description='the default value for the line width as a' - 'multiple of the tikz scale when latexed', - checker=lambda x: True) # More trouble than it's worth to check - latex_color_decreasing = dict( - default='red', - description='the default color of decreasing relations when latexed', - checker=lambda x: True) # More trouble than it's worth to check - latex_color_increasing = dict( - default='blue', - description='the default color of increasing relations when latexed', - checker=lambda x: True) # More trouble than it's worth to check - latex_hspace = dict( - default=1, - description='the default difference between horizontal' - ' coordinates of vertices when latexed', - checker=lambda x: True) # More trouble than it's worth to check - latex_vspace = dict( - default=1, - description='the default difference between vertical' - ' coordinates of vertices when latexed', - checker=lambda x: True) # More trouble than it's worth to check + latex_tikz_scale = dict(default=1, description='the default value for the tikz scale when latexed', checker=lambda x: True) # More trouble than it's worth to check + latex_line_width_scalar = dict(default=0.5, description='the default value for the line width as a' 'multiple of the tikz scale when latexed', checker=lambda x: True) # More trouble than it's worth to check + latex_color_decreasing = dict(default='red', description='the default color of decreasing relations when latexed', checker=lambda x: True) # More trouble than it's worth to check + latex_color_increasing = dict(default='blue', description='the default color of increasing relations when latexed', checker=lambda x: True) # More trouble than it's worth to check + latex_hspace = dict(default=1, description='the default difference between horizontal' ' coordinates of vertices when latexed', checker=lambda x: True) # More trouble than it's worth to check + latex_vspace = dict(default=1, description='the default difference between vertical' ' coordinates of vertices when latexed', checker=lambda x: True) # More trouble than it's worth to check @staticmethod def check_poset(poset) -> bool: @@ -3147,8 +3102,7 @@ def get_relations(bt, start=1): return roots, relations, rindex _, relations, index = get_relations(binary_tree) - P = FinitePoset(DiGraph([list(range(1, index)), relations], - format='vertices_and_edges')) # type:ignore + P = FinitePoset(DiGraph([list(range(1, index)), relations], format='vertices_and_edges')) # type:ignore return TamariIntervalPoset(P, check=False) # type:ignore @staticmethod @@ -3261,8 +3215,7 @@ def get_relations(bt, start=1): return roots, relations, rindex _, relations, index = get_relations(binary_tree) - P = FinitePoset(DiGraph([list(range(1, index)), relations], - format='vertices_and_edges')) # type:ignore + P = FinitePoset(DiGraph([list(range(1, index)), relations], format='vertices_and_edges')) # type:ignore return TamariIntervalPoset(P, check=False) # type:ignore @staticmethod @@ -3429,8 +3382,7 @@ def recomposition_from_triple(left: TIP, right: TIP, r) -> TIP: root = left.size() + 1 rel = left.poset().cover_relations() rel.extend((i, root) for i in left) - rel.extend((root + a, root + b) - for a, b in right.poset().cover_relations()) + rel.extend((root + a, root + b) for a, b in right.poset().cover_relations()) decroot = right.decreasing_roots()[:r] rel.extend((root + i, root) for i in decroot) # does this describe only cover relations ? @@ -3552,17 +3504,13 @@ def from_minimal_schnyder_wood(graph) -> TIP: The Tamari interval of size 3 induced by relations [(2, 3), (2, 1)] """ from sage.combinat.dyck_word import DyckWord + color_a = graph.incoming_edges(-1)[0][2] color_b = graph.incoming_edges(-2)[0][2] embedding = graph.get_embedding() - graph0 = DiGraph([e for e in graph.edges(sort=False) - if e[2] == color_a], - format='list_of_edges') - restricted_embedding = {u: [v for v in embedding[u] - if v in graph0.neighbors_in(u) or - v in graph0.neighbors_out(u)] - for u in graph0} + graph0 = DiGraph([e for e in graph.edges(sort=False) if e[2] == color_a], format='list_of_edges') + restricted_embedding = {u: [v for v in embedding[u] if v in graph0.neighbors_in(u) or v in graph0.neighbors_out(u)] for u in graph0} voisins_in = {} for u in graph0: @@ -3604,11 +3552,9 @@ def profil(gr, vertex): dyckword_top = [] for i in range(1, len(graph) - 3): - indegree1 = len([u for u in new_graph.incoming_edges(i) - if u[2] == color_b]) + indegree1 = len([u for u in new_graph.incoming_edges(i) if u[2] == color_b]) dyckword_top += [1] + [0] * indegree1 - indegree1 = len([u for u in new_graph.incoming_edges(-2) - if u[2] == color_b]) + indegree1 = len([u for u in new_graph.incoming_edges(-2) if u[2] == color_b]) dyckword_top += [1] + [0] * indegree1 dyckword_bottom = DyckWord(dyckword_bottom) # type:ignore @@ -3673,6 +3619,7 @@ def le(self, el1, el2) -> bool: cc2 = el2.cubical_coordinates() return all(x1 <= x2 for x1, x2 in zip(cc1, cc2)) + ################################################################# # Enumerated set of all Tamari Interval-posets ################################################################# @@ -3708,10 +3655,7 @@ def __init__(self): True sage: TestSuite(S).run() # long time (7s) """ - DisjointUnionEnumeratedSets.__init__( - self, Family(NonNegativeIntegers(), TamariIntervalPosets_size), - facade=True, keepkey=False, - category=(Posets(), EnumeratedSets(), Monoids())) + DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), TamariIntervalPosets_size), facade=True, keepkey=False, category=(Posets(), EnumeratedSets(), Monoids())) def _repr_(self) -> str: r""" diff --git a/src/sage/combinat/k_tableau.py b/src/sage/combinat/k_tableau.py index 3873731a259..9fa01e50e42 100644 --- a/src/sage/combinat/k_tableau.py +++ b/src/sage/combinat/k_tableau.py @@ -15,7 +15,7 @@ - Anne Schilling and Mike Zabrocki (2013): initial version - Avi Dalal and Nate Gallup (2013): implementation of `k`-charge """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2013 Anne Schilling # Mike Zabrocki # @@ -29,7 +29,7 @@ # The full text of the GPL is available at: # # https://www.gnu.org/licenses/ -#**************************************************************************** +# **************************************************************************** from itertools import repeat from sage.structure.unique_representation import UniqueRepresentation from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets @@ -195,7 +195,7 @@ def WeakTableau(t, k, inner_shape=[], representation='core'): raise NotImplementedError("The representation option needs to be 'core', 'bounded', or 'factorized_permutation'") -def WeakTableaux(k, shape , weight, representation='core'): +def WeakTableaux(k, shape, weight, representation='core'): r""" This is the dispatcher method for the parent class of weak `k`-tableaux. @@ -258,11 +258,11 @@ def WeakTableaux(k, shape , weight, representation='core'): return WeakTableaux_factorized_permutation(k, shape, weight) raise NotImplementedError("The representation option needs to be 'core', 'bounded', or 'factorized_permutation'") -#Abstract class for the elements of weak tableau +# Abstract class for the elements of weak tableau -class WeakTableau_abstract(ClonableList, - metaclass=InheritComparisonClasscallMetaclass): + +class WeakTableau_abstract(ClonableList, metaclass=InheritComparisonClasscallMetaclass): r""" Abstract class for the various element classes of WeakTableau. """ @@ -463,17 +463,20 @@ def _latex_(self): sage: latex(t) [s_{0}s_{3},s_{2}s_{1}] """ + def chi(x): if x is None: return "" if x in ZZ: return x return "%s" % x + if self.parent()._representation in ['core', 'bounded']: t = [[chi(x) for x in row] for row in self] from .output import tex_from_array + return tex_from_array(t) - return "["+"".join(self[i]._latex_()+',' for i in range(len(self)-1))+self[len(self)-1]._latex_()+"]" + return "[" + "".join(self[i]._latex_() + ',' for i in range(len(self) - 1)) + self[len(self) - 1]._latex_() + "]" def representation(self, representation='core'): r""" @@ -520,7 +523,8 @@ def representation(self, representation='core'): return t.to_factorized_permutation_tableau() raise ValueError("The representation must be one of 'core', 'bounded', or 'factorized_permutation'") -#Abstract class for the parents of weak tableaux + +# Abstract class for the parents of weak tableaux class WeakTableaux_abstract(UniqueRepresentation, Parent): @@ -655,11 +659,12 @@ def representation(self, representation='core'): return WeakTableaux(self.k, [outer_shape, inner_shape], weight, representation=representation) -#Weak Tableaux in terms of cores +# Weak Tableaux in terms of cores class WeakTableau_core(WeakTableau_abstract): r""" A (skew) weak `k`-tableau represented in terms of `(k+1)`-cores. """ + @staticmethod def __classcall_private__(cls, t, k): r""" @@ -689,9 +694,9 @@ def __classcall_private__(cls, t, k): if isinstance(t, cls): return t tab = SkewTableau(list(t)) - outer = Core(tab.outer_shape(),k+1) - inner = Core(tab.inner_shape(),k+1) - weight = WeakTableau_bounded.from_core_tableau(t,k).weight() + outer = Core(tab.outer_shape(), k + 1) + inner = Core(tab.inner_shape(), k + 1) + weight = WeakTableau_bounded.from_core_tableau(t, k).weight() return WeakTableaux_core(k, [outer, inner], weight)(t) def __init__(self, parent, t): @@ -813,13 +818,13 @@ def check(self): ... ValueError: The tableau is not semistandard! """ - if not self.parent()._weight == WeakTableau_bounded.from_core_tableau(self,self.k).weight(): + if not self.parent()._weight == WeakTableau_bounded.from_core_tableau(self, self.k).weight(): raise ValueError("The weight of the parent does not agree with the weight of the tableau!") t = SkewTableau(list(self)) if t not in SemistandardSkewTableaux(): raise ValueError("The tableau is not semistandard!") - outer = Core(t.outer_shape(),self.k+1) - inner = Core(t.inner_shape(),self.k+1) + outer = Core(t.outer_shape(), self.k + 1) + inner = Core(t.inner_shape(), self.k + 1) if self.parent()._outer_shape != outer: raise ValueError("The outer shape of the parent does not agree with the outer shape of the tableau!") if self.parent()._inner_shape != inner: @@ -846,18 +851,18 @@ def to_bounded_tableau(self): sage: t.to_bounded_tableau().to_core_tableau() == t True """ - shapes = [ Core(p,self.k+1).to_bounded_partition() for p in self.intermediate_shapes() ] + shapes = [Core(p, self.k + 1).to_bounded_partition() for p in self.intermediate_shapes()] if self.parent()._skew: - l = [[None]*i for i in shapes[0]] + l = [[None] * i for i in shapes[0]] else: l = [] - for i in range(1,len(shapes)): + for i in range(1, len(shapes)): p = shapes[i] if len(l) < len(p): l += [[]] l_new = [] for j in range(len(l)): - l_new += [l[j] + [i]*(p[j]-len(l[j]))] + l_new += [l[j] + [i] * (p[j] - len(l[j]))] l = l_new return WeakTableau_bounded(l, self.k) @@ -893,8 +898,8 @@ def to_factorized_permutation_tableau(self): sage: c.to_core_tableau() == t True """ - shapes = [ Core(p,self.k+1).to_grassmannian() for p in self.intermediate_shapes() ] - perms = [ shapes[i]*(shapes[i-1].inverse()) for i in range(len(shapes)-1,0,-1)] + shapes = [Core(p, self.k + 1).to_grassmannian() for p in self.intermediate_shapes()] + perms = [shapes[i] * (shapes[i - 1].inverse()) for i in range(len(shapes) - 1, 0, -1)] return WeakTableau_factorized_permutation(perms, self.k, inner_shape=self.parent()._inner_shape) def residues_of_entries(self, v): @@ -917,10 +922,7 @@ def residues_of_entries(self, v): sage: t.residues_of_entries(1) [2, 3] """ - S = set((j - i) % (self.k+1) - for i in range(len(self)) - for j in range(len(self[i])) - if self[i][j] == v) + S = set((j - i) % (self.k + 1) for i in range(len(self)) for j in range(len(self[i])) if self[i][j] == v) return sorted(S) def dictionary_of_coordinates_at_residues(self, v): @@ -953,8 +955,8 @@ def dictionary_of_coordinates_at_residues(self, v): d[r] = [] for i in range(len(self)): for j in range(len(self[i])): - if self[i][j] == v and (j - i) % (self.k+1) == r: - d[r] += [(i,j)] + if self[i][j] == v and (j - i) % (self.k + 1) == r: + d[r] += [(i, j)] return d def list_of_standard_cells(self): @@ -1012,13 +1014,12 @@ def list_of_standard_cells(self): already_used = [] out = [] for i in range(self[0].count(1)): - standard_cells = [(0,self[0].count(1) - i - 1)] + standard_cells = [(0, self[0].count(1) - i - 1)] r = self[0].count(1) - i - 1 - for v in range(1,mu[i]): - D = self.dictionary_of_coordinates_at_residues(v+1) - new_D = {a: b for a, b in D.items() - if all(x not in already_used for x in b)} - r = (r - min([self.k+1 - (x-r) % (self.k+1) for x in new_D])) % (self.k+1) + for v in range(1, mu[i]): + D = self.dictionary_of_coordinates_at_residues(v + 1) + new_D = {a: b for a, b in D.items() if all(x not in already_used for x in b)} + r = (r - min([self.k + 1 - (x - r) % (self.k + 1) for x in new_D])) % (self.k + 1) standard_cells.append(new_D[r][-1]) already_used += new_D[r] out.append(standard_cells) @@ -1100,11 +1101,11 @@ def k_charge_I(self): kch = 0 for sw in stt: Ii = 0 - for r in range(len(sw)-1): - if sw[r][1] < sw[r+1][1]: - Ii += 1 + abs(self.parent().diag(sw[r+1],sw[r])) + for r in range(len(sw) - 1): + if sw[r][1] < sw[r + 1][1]: + Ii += 1 + abs(self.parent().diag(sw[r + 1], sw[r])) else: - Ii += - abs(self.parent().diag(sw[r],sw[r+1])) + Ii += -abs(self.parent().diag(sw[r], sw[r + 1])) kch += Ii return kch @@ -1148,13 +1149,13 @@ def k_charge_J(self): kch = 0 for sw in stt: Ji = 0 - for i in range(len(sw)-1): - c = (self._height_of_restricted_subword(sw,i+2)+1,0) - cdi = self.parent().circular_distance((-c[0]) % (self.k+1),(sw[i][1]-sw[i][0]) % (self.k+1)) - cdi1 = self.parent().circular_distance((-c[0]) % (self.k+1),(sw[i+1][1]-sw[i+1][0]) % (self.k+1)) - if (cdi > cdi1): + for i in range(len(sw) - 1): + c = (self._height_of_restricted_subword(sw, i + 2) + 1, 0) + cdi = self.parent().circular_distance((-c[0]) % (self.k + 1), (sw[i][1] - sw[i][0]) % (self.k + 1)) + cdi1 = self.parent().circular_distance((-c[0]) % (self.k + 1), (sw[i + 1][1] - sw[i + 1][0]) % (self.k + 1)) + if cdi > cdi1: Ji += 1 - kch += Ji + self.parent().diag(sw[i+1],c) + kch += Ji + self.parent().diag(sw[i + 1], c) return kch def _height_of_restricted_subword(self, sw, r): @@ -1238,9 +1239,9 @@ def __classcall_private__(cls, k, shape, weight): sage: TestSuite(T).run() """ if shape == [] or shape[0] in ZZ: - shape = (Core(shape, k+1), Core([],k+1)) + shape = (Core(shape, k + 1), Core([], k + 1)) else: - shape = tuple([Core(r,k+1) for r in shape]) + shape = tuple([Core(r, k + 1) for r in shape]) return super().__classcall__(cls, k, shape, tuple(weight)) def __init__(self, k, shape, weight): @@ -1322,7 +1323,7 @@ def diag(self, c, ha): sage: T.diag((1,2),(4,0)) 0 """ - return divmod((c[1]-c[0])-(ha[1]-ha[0])-1, self.k+1)[0] + return divmod((c[1] - c[0]) - (ha[1] - ha[0]) - 1, self.k + 1)[0] def circular_distance(self, cr, r): r""" @@ -1344,16 +1345,17 @@ def circular_distance(self, cr, r): sage: T.circular_distance(8, 9) 10 """ - return self.k - ((r+self.k-cr) % (self.k+1)) + return self.k - ((r + self.k - cr) % (self.k + 1)) Element = WeakTableau_core -#Weak tableaux in terms of `k`-bounded partitions +# Weak tableaux in terms of `k`-bounded partitions class WeakTableau_bounded(WeakTableau_abstract): r""" A (skew) weak `k`-tableau represented in terms of `k`-bounded partitions. """ + @staticmethod def __classcall_private__(cls, t, k): r""" @@ -1554,8 +1556,8 @@ def _is_k_tableau(self): True """ shapes = self.intermediate_shapes() - kshapes = [ la.k_conjugate(self.k) for la in shapes ] - return all( kshapes[i+1].contains(kshapes[i]) for i in range(len(shapes)-1) ) + kshapes = [la.k_conjugate(self.k) for la in shapes] + return all(kshapes[i + 1].contains(kshapes[i]) for i in range(len(shapes) - 1)) def to_core_tableau(self): r""" @@ -1585,18 +1587,18 @@ def to_core_tableau(self): sage: t == WeakTableau_bounded.from_core_tableau(t.to_core_tableau(),3) True """ - shapes = [ p.to_core(self.k) for p in self.intermediate_shapes() ] + shapes = [p.to_core(self.k) for p in self.intermediate_shapes()] if self.parent()._skew: - l = [[None]*i for i in shapes[0]] + l = [[None] * i for i in shapes[0]] else: l = [] - for i in range(1,len(shapes)): + for i in range(1, len(shapes)): p = shapes[i] if len(l) < len(p): l += [[]] l_new = [] for j in range(len(l)): - l_new += [l[j] + [i]*(p[j]-len(l[j]))] + l_new += [l[j] + [i] * (p[j] - len(l[j]))] l = l_new return WeakTableau_core(l, self.k) @@ -1618,18 +1620,18 @@ def from_core_tableau(cls, t, k): [[None, 2], [3]] """ t = SkewTableau(list(t)) - shapes = [ Core(p, k+1).to_bounded_partition() for p in intermediate_shapes(t) ] # .to_chain() ] + shapes = [Core(p, k + 1).to_bounded_partition() for p in intermediate_shapes(t)] # .to_chain() ] if t.inner_shape() == Partition([]): l = [] else: - l = [[None]*i for i in shapes[0]] + l = [[None] * i for i in shapes[0]] for i in range(1, len(shapes)): p = shapes[i] if len(l) < len(p): l += [[]] l_new = [] for j in range(len(l)): - l_new += [l[j] + [i]*(p[j]-len(l[j]))] + l_new += [l[j] + [i] * (p[j] - len(l[j]))] l = l_new return cls(l, k) @@ -1687,6 +1689,7 @@ class WeakTableaux_bounded(WeakTableaux_abstract): [[None, None, 1], [2, 4], [3]], [[None, None, 1], [2, 3], [4]]] """ + @staticmethod def __classcall_private__(cls, k, shape, weight): r""" @@ -1769,7 +1772,8 @@ def __iter__(self): Element = WeakTableau_bounded -#Weak tableaux in terms of factorized permutations + +# Weak tableaux in terms of factorized permutations class WeakTableau_factorized_permutation(WeakTableau_abstract): @@ -1777,6 +1781,7 @@ class WeakTableau_factorized_permutation(WeakTableau_abstract): A weak (skew) `k`-tableau represented in terms of factorizations of affine permutations into cyclically decreasing elements. """ + @staticmethod def straighten_input(t, k): r""" @@ -1846,7 +1851,7 @@ def __classcall_private__(cls, t, k, inner_shape=[]): w = cls.straighten_input(t, k) weight = tuple(w[i].length() for i in range(len(w) - 1, -1, -1)) inner_shape = Core(inner_shape, k + 1) - outer_shape = (W.prod(w)*W(inner_shape.to_grassmannian())).affine_grassmannian_to_core() + outer_shape = (W.prod(w) * W(inner_shape.to_grassmannian())).affine_grassmannian_to_core() return WeakTableaux_factorized_permutation(k, [outer_shape, inner_shape], weight)(w) def __init__(self, parent, t): @@ -1967,10 +1972,9 @@ def check(self): """ weight = tuple(self[i].length() for i in range(len(self) - 1, -1, -1)) if not self.parent()._weight == weight: - raise ValueError("The weight of the parent does not agree " - "with the weight of the tableau!") + raise ValueError("The weight of the parent does not agree " "with the weight of the tableau!") W = self[0].parent() - outer = (W.prod(self)*W((self._inner_shape).to_grassmannian())).affine_grassmannian_to_core() + outer = (W.prod(self) * W((self._inner_shape).to_grassmannian())).affine_grassmannian_to_core() if self.parent()._outer_shape != outer: raise ValueError("The outer shape of the parent does not agree with the outer shape of the tableau!") if not self._is_k_tableau(): @@ -1991,8 +1995,8 @@ def _is_k_tableau(self): True """ W = self[0].parent() - if (W.prod(self)*W(self.parent()._inner_shape.to_grassmannian())).is_affine_grassmannian(): - return all( r.is_pieri_factor() for r in self ) + if (W.prod(self) * W(self.parent()._inner_shape.to_grassmannian())).is_affine_grassmannian(): + return all(r.is_pieri_factor() for r in self) return False def to_core_tableau(self): @@ -2028,20 +2032,20 @@ def to_core_tableau(self): W = self[0].parent() factor = W(self._inner_shape.to_grassmannian()) shapes = [factor] - for i in range(len(self)-1,-1,-1): - factor = self[i]*factor + for i in range(len(self) - 1, -1, -1): + factor = self[i] * factor shapes += [factor.affine_grassmannian_to_core()] if self.parent()._skew: - l = [[None]*i for i in self._inner_shape] + l = [[None] * i for i in self._inner_shape] else: l = [] - for i in range(1,len(shapes)): + for i in range(1, len(shapes)): p = shapes[i] if len(l) < len(p): l += [[]] l_new = [] for j in range(len(l)): - l_new += [l[j] + [i]*(p[j]-len(l[j]))] + l_new += [l[j] + [i] * (p[j] - len(l[j]))] l = l_new return WeakTableau_core(l, self.k) @@ -2061,10 +2065,8 @@ def from_core_tableau(cls, t, k): [s0*s3, s2*s1] """ t = SkewTableau(list(t)) - shapes = [Core(p, k + 1).to_grassmannian() - for p in intermediate_shapes(t)] # t.to_chain() ] - perms = [shapes[i] * (shapes[i - 1].inverse()) - for i in range(len(shapes) - 1, 0, -1)] + shapes = [Core(p, k + 1).to_grassmannian() for p in intermediate_shapes(t)] # t.to_chain() ] + perms = [shapes[i] * (shapes[i - 1].inverse()) for i in range(len(shapes) - 1, 0, -1)] return cls(perms, k, inner_shape=t.inner_shape()) def k_charge(self, algorithm='I'): @@ -2110,6 +2112,7 @@ class WeakTableaux_factorized_permutation(WeakTableaux_abstract): sage: T.list() [[s0, s4, s3, s4*s2], [s0, s3, s4, s3*s2], [s3, s0, s4, s3*s2]] """ + @staticmethod def __classcall_private__(cls, k, shape, weight): r""" @@ -2124,9 +2127,9 @@ def __classcall_private__(cls, k, shape, weight): sage: TestSuite(T).run() # long time """ if shape == [] or shape[0] in ZZ: - shape = (Core(shape, k+1), Core([],k+1)) + shape = (Core(shape, k + 1), Core([], k + 1)) else: - shape = tuple([Core(r,k+1) for r in shape]) + shape = tuple([Core(r, k + 1) for r in shape]) return super().__classcall__(cls, k, shape, tuple(weight)) def __init__(self, k, shape, weight): @@ -2151,8 +2154,8 @@ def __init__(self, k, shape, weight): """ self.k = k self._skew = bool(shape[1]) - self._outer_shape = Core(shape[0], k+1) - self._inner_shape = Core(shape[1], k+1) + self._outer_shape = Core(shape[0], k + 1) + self._inner_shape = Core(shape[1], k + 1) self._shape = (self._outer_shape, self._inner_shape) self._weight = weight self._representation = 'factorized_permutation' @@ -2192,6 +2195,7 @@ def __iter__(self): ######## END weak tableaux BEGIN strong tableaux + class StrongTableau(ClonableList, metaclass=InheritComparisonClasscallMetaclass): r""" A (standard) strong `k`-tableau is a (saturated) chain in Bruhat order. @@ -2361,7 +2365,7 @@ def __classcall_private__(cls, T, k, weight=None): loop = (row.count(None) for row in T) inner_shape = Core([x for x in loop if x], k + 1) Te = [v for row in T for v in row if v is not None] + [0] - count_marks = tuple(Te.count(-(i+1)) for i in range(-min(Te))) + count_marks = tuple(Te.count(-(i + 1)) for i in range(-min(Te))) if not all(v == 1 for v in count_marks): # if T is not standard -> turn into standard if weight is not None and tuple(weight) != count_marks: @@ -2369,11 +2373,11 @@ def __classcall_private__(cls, T, k, weight=None): tijseq = StrongTableaux.marked_CST_to_transposition_sequence(T, k) if tijseq is None or len(tijseq) < sum(list(count_marks)): raise ValueError("Unable to parse strong marked tableau : %s" % T) - T = StrongTableaux.transpositions_to_standard_strong( tijseq, k, [[None]*r for r in inner_shape] ) # build from scratch - T = T.set_weight( count_marks ) + T = StrongTableaux.transpositions_to_standard_strong(tijseq, k, [[None] * r for r in inner_shape]) # build from scratch + T = T.set_weight(count_marks) return T if weight is not None: - count_marks = tuple(weight) # in the case that it is standard + weight + count_marks = tuple(weight) # in the case that it is standard + weight return StrongTableaux.__classcall__(StrongTableaux, k, (outer_shape, inner_shape), count_marks)(T) def check(self): @@ -2420,8 +2424,8 @@ def check(self): ValueError: The weight=(2, 2, 3, 1) and the markings on the standard tableau=[[-1, -2, -4, 7], [-3, 6, -6, 8], [4, -7], [-5, -8]] do not agree. """ T = SkewTableau(self.to_standard_list()) - outer = Core(T.outer_shape(),self.k+1) - inner = Core(T.inner_shape(),self.k+1) + outer = Core(T.outer_shape(), self.k + 1) + inner = Core(T.inner_shape(), self.k + 1) if self.parent()._outer_shape != outer: raise ValueError("The outer shape of the parent does not agree with the outer shape of the tableau!") if self.parent()._inner_shape != inner: @@ -2429,11 +2433,11 @@ def check(self): if not self._is_valid_marked(): raise ValueError("The marks in %s are not correctly placed." % (self.to_standard_list())) if not self._is_valid_standard(): - raise ValueError("At least one shape in %s is not a valid %s-core." % (self.to_standard_list(), self.k+1)) - if not self.outer_shape().length()-self.inner_shape().length() == self.size(): - raise ValueError("The size of the tableau %s and weight %s do not match" % (self.to_standard_list(),self.weight())) - if not self.is_column_strict_with_weight( self.weight() ): - raise ValueError("The weight=%s and the markings on the standard tableau=%s do not agree." % (self.weight(),self.to_standard_list())) + raise ValueError("At least one shape in %s is not a valid %s-core." % (self.to_standard_list(), self.k + 1)) + if not self.outer_shape().length() - self.inner_shape().length() == self.size(): + raise ValueError("The size of the tableau %s and weight %s do not match" % (self.to_standard_list(), self.weight())) + if not self.is_column_strict_with_weight(self.weight()): + raise ValueError("The weight=%s and the markings on the standard tableau=%s do not agree." % (self.weight(), self.to_standard_list())) def __hash__(self): r""" @@ -2447,7 +2451,7 @@ def __hash__(self): """ return hash(tuple(tuple(x) for x in self)) + hash(self.parent().k) - def _is_valid_marked( self ): + def _is_valid_marked(self): r""" Check the validity of marks of a potential tableau ``self``. @@ -2501,18 +2505,18 @@ def _is_valid_marked( self ): True """ T = self.to_standard_list() - size = Core([len(t) for t in T], self.k+1).length() - inner_size = Core([y for y in (len([x for x in row if x is None]) for row in T) if y > 0], self.k+1).length() + size = Core([len(t) for t in T], self.k + 1).length() + inner_size = Core([y for y in (len([x for x in row if x is None]) for row in T) if y > 0], self.k + 1).length() if len(set(v for v in flatten(list(T)) if v in ZZ and v < 0)) != size - inner_size: - return False # TT does not have exactly self.size() marked cells + return False # TT does not have exactly self.size() marked cells for i in range(len(T)): for j in range(len(T[i])): v = T[i][j] - if v is not None and v < 0 and ((i != 0 and T[i-1][j] == abs(v)) or (j < len(T[i])-1 and T[i][j+1] == abs(v))): + if v is not None and v < 0 and ((i != 0 and T[i - 1][j] == abs(v)) or (j < len(T[i]) - 1 and T[i][j + 1] == abs(v))): return False return True - def _is_valid_standard( self ): + def _is_valid_standard(self): r""" Test if ``self`` has a valid strong (un)marked standard part of the tableau. @@ -2555,7 +2559,7 @@ def _is_valid_standard( self ): if not all(Partition(la).is_core(self.k + 1) for la in Tshapes): return False Tsizes = [Core(lam, self.k + 1).length() for lam in Tshapes] - return all(Tsizes[i] == Tsizes[i+1]-1 for i in range(len(Tsizes)-1)) + return all(Tsizes[i] == Tsizes[i + 1] - 1 for i in range(len(Tsizes) - 1)) def is_column_strict_with_weight(self, mu) -> bool: """ @@ -2584,9 +2588,9 @@ def is_column_strict_with_weight(self, mu) -> bool: """ ss = 0 for i in range(len(mu)): - for j in range(mu[i]-1): + for j in range(mu[i] - 1): # the markings should move from left to right - if self.content_of_marked_head( ss+j+1 ) >= self.content_of_marked_head( ss+j+2 ): + if self.content_of_marked_head(ss + j + 1) >= self.content_of_marked_head(ss + j + 2): return False ss += mu[i] return True @@ -2698,12 +2702,12 @@ def cell_of_marked_head(self, v): """ T = self.to_standard_list() if T == []: - return (0,0) + return (0, 0) for i in range(len(T)): for j in range(len(T[i])): if T[i][j] == -v: - return (i,j) - return (0,len(T[0])) + return (i, j) + return (0, len(T[0])) def content_of_marked_head(self, v): r""" @@ -2733,7 +2737,7 @@ def content_of_marked_head(self, v): 0 """ c = self.cell_of_marked_head(v) - return c[1]-c[0] + return c[1] - c[0] def cells_of_marked_ribbon(self, v): r""" @@ -2792,7 +2796,7 @@ def cells_of_marked_ribbon(self, v): cells += adt return cells - def cell_of_highest_head( self, v ): + def cell_of_highest_head(self, v): """ Return the cell of the highest head of label ``v`` in the standard part of ``self``. @@ -2828,15 +2832,15 @@ def cell_of_highest_head( self, v ): return (0, 0) r = len(Tlist[0]) dout = (0, r) - for d in range(-len(Tlist),r+1): + for d in range(-len(Tlist), r + 1): for c in Tlist.cells_by_content(d): if nabs(Tlist[c[0]][c[1]]) == v: dout = c - if dout != (0, r) and dout[1]-dout[0] != d: + if dout != (0, r) and dout[1] - dout[0] != d: return dout return dout - def content_of_highest_head( self, v ): + def content_of_highest_head(self, v): r""" Return the diagonal of the highest head of the cells labeled ``v`` in the standard part of ``self``. @@ -2864,7 +2868,7 @@ def content_of_highest_head( self, v ): 2 """ c = self.cell_of_highest_head(v) - return c[1]-c[0] + return c[1] - c[0] def cells_head_dictionary(self): r""" @@ -2989,7 +2993,7 @@ def contents_of_heads(self, v): sage: StrongTableau([],4).contents_of_heads(1) [] """ - return [c[1]-c[0] for c in self.cells_of_heads(v)] + return [c[1] - c[0] for c in self.cells_of_heads(v)] def entries_by_content(self, diag): r""" @@ -3098,8 +3102,8 @@ def ribbons_above_marked(self, v): """ d = self.content_of_marked_head(v) count = 0 - for i in range(self.k+1, len(self.to_standard_list())+d, self.k+1): - count += int(v in self.entries_by_content_standard(d-i)) + for i in range(self.k + 1, len(self.to_standard_list()) + d, self.k + 1): + count += int(v in self.entries_by_content_standard(d - i)) return count def height_of_ribbon(self, v): @@ -3182,8 +3186,8 @@ def number_of_connected_components(self, v): if sz == 0: return 0 T = self.to_standard_list() - nocells = len([i for i in range(len(T)) for j in range(len(T[i])) if T[i][j] == v])+1 - return ZZ(nocells/sz) + nocells = len([i for i in range(len(T)) for j in range(len(T[i])) if T[i][j] == v]) + 1 + return ZZ(nocells / sz) def intermediate_shapes(self): r""" @@ -3217,7 +3221,7 @@ def intermediate_shapes(self): """ return intermediate_shapes(self.to_unmarked_list()) - def pp( self ): + def pp(self): r""" Print the strong tableau ``self`` in pretty print format. @@ -3253,7 +3257,7 @@ def pp( self ): """ print(self._repr_diagram()) - def outer_shape( self ): + def outer_shape(self): r""" Return the outer shape of ``self``. @@ -3280,7 +3284,7 @@ def outer_shape( self ): """ return self.parent().outer_shape() - def inner_shape( self ): + def inner_shape(self): r""" Return the inner shape of ``self``. @@ -3308,7 +3312,7 @@ def inner_shape( self ): """ return self.parent().inner_shape() - def shape( self ): + def shape(self): r""" Return the shape of ``self``. @@ -3343,7 +3347,7 @@ def shape( self ): """ return self.parent().shape() - def weight( self ): + def weight(self): r""" Return the weight of the tableau. @@ -3370,7 +3374,7 @@ def weight( self ): """ return self.parent()._weight - def size( self ): + def size(self): """ Return the size of the strong tableau. @@ -3398,7 +3402,7 @@ def size( self ): """ return sum(self.weight()) - def to_list( self ): + def to_list(self): """ Return the marked column strict (possibly skew) tableau as a list of lists. @@ -3420,14 +3424,16 @@ def to_list( self ): sage: StrongTableau([],4).to_list() [] """ + def f(v): # f is a function which maps v or -v to the weight value corresponding to the partition mu if v is None: return None - return sgn(v)*min([i for i in range(len(self.weight())+1) if sum(self.weight()[:i]) >= abs(v)]) + return sgn(v) * min([i for i in range(len(self.weight()) + 1) if sum(self.weight()[:i]) >= abs(v)]) + return [[f(v) for v in row] for row in self.to_standard_list()] - def to_unmarked_list( self ): + def to_unmarked_list(self): """ Return the tableau as a list of lists with markings removed. @@ -3510,7 +3516,7 @@ def to_standard_tableau(self): """ return StrongTableau(self._tableau, self.k) - def to_unmarked_standard_list( self ): + def to_unmarked_standard_list(self): """ Return the standard part of the tableau as a list of lists with markings removed. @@ -3559,6 +3565,7 @@ def _latex_(self): \end{array}$} } """ + def chi(x): if x is None: return "" @@ -3568,11 +3575,13 @@ def chi(x): s += "^\\ast" return s return "%s" % x + T = [[chi(x) for x in row] for row in self.to_list()] from .output import tex_from_array + return tex_from_array(T) - def restrict( self, r ): + def restrict(self, r): r""" Restrict the standard part of the tableau to the labels `1, 2, \ldots, r`. @@ -3608,10 +3617,10 @@ def restrict( self, r ): """ rr = sum(self.weight()[:r]) rest_tab = [y for y in ([x for x in row if x is None or abs(x) <= rr] for row in self.to_standard_list()) if y] - new_parent = StrongTableaux( self.k, (Core([len(x) for x in rest_tab], self.k+1), self.inner_shape()), self.weight()[:r] ) + new_parent = StrongTableaux(self.k, (Core([len(x) for x in rest_tab], self.k + 1), self.inner_shape()), self.weight()[:r]) return new_parent(rest_tab) - def set_weight( self, mu ): + def set_weight(self, mu): """ Set a new weight ``mu`` for ``self``. @@ -3643,11 +3652,11 @@ def set_weight( self, mu ): sage: StrongTableau([],4).set_weight([]) [] """ - if sum(mu) != self.size() or self.is_column_strict_with_weight( mu ): + if sum(mu) != self.size() or self.is_column_strict_with_weight(mu): return StrongTableaux.__classcall__(StrongTableaux, self.k, (self.outer_shape(), self.inner_shape()), tuple(mu))(self.to_standard_list()) raise ValueError("%s is not a semistandard strong tableau with respect to the partition %s" % (self, mu)) - def left_action( self, tij ): + def left_action(self, tij): r""" Action of transposition ``tij`` on ``self`` by adding marked ribbons. @@ -3686,10 +3695,10 @@ def left_action( self, tij ): sage: StrongTableau([],4).left_action([0,1]) [[-1]] """ - T = StrongTableaux._left_action_list(copy.deepcopy( self.to_standard_list() ), tij, self.size()+1, self.k) - return StrongTableau( T, self.k, self.weight()+(1,) ) + T = StrongTableaux._left_action_list(copy.deepcopy(self.to_standard_list()), tij, self.size() + 1, self.k) + return StrongTableau(T, self.k, self.weight() + (1,)) - def follows_tableau( self ): + def follows_tableau(self): r""" Return a list of strong marked tableaux with length one longer than ``self``. @@ -3718,16 +3727,16 @@ def follows_tableau( self ): sage: StrongTableau([],4).follows_tableau() [[[-1]]] """ - v = self.size()+1 + v = self.size() + 1 out = [] - for T in StrongTableaux.follows_tableau_unsigned_standard( self.to_standard_list(), self.k ): + for T in StrongTableaux.follows_tableau_unsigned_standard(self.to_standard_list(), self.k): for m in StrongTableaux.cells_head_dictionary(T)[v]: TT = copy.deepcopy(T) TT[m[0]][m[1]] = -v - out.append(StrongTableau(TT, self.k, self.weight()+(1,))) + out.append(StrongTableau(TT, self.k, self.weight() + (1,))) return out - def spin_of_ribbon( self, v ): + def spin_of_ribbon(self, v): r""" Return the spin of the ribbon with label ``v`` in the standard part of ``self``. @@ -3760,9 +3769,9 @@ def spin_of_ribbon( self, v ): sage: StrongTableau([],4).spin_of_ribbon(1) 0 """ - return (self.height_of_ribbon(v)-1)*self.number_of_connected_components(v)+self.ribbons_above_marked(v) + return (self.height_of_ribbon(v) - 1) * self.number_of_connected_components(v) + self.ribbons_above_marked(v) - def spin( self ): + def spin(self): r""" Return the spin statistic of the tableau ``self``. @@ -3812,9 +3821,9 @@ def spin( self ): sage: StrongTableau([],4).spin() 0 """ - return sum(self.spin_of_ribbon(v) for v in range(1,self.size()+1)) + return sum(self.spin_of_ribbon(v) for v in range(1, self.size() + 1)) - def to_transposition_sequence( self ): + def to_transposition_sequence(self): """ Return a list of transpositions corresponding to ``self``. @@ -3843,12 +3852,12 @@ def to_transposition_sequence( self ): sage: StrongTableau([],4).to_transposition_sequence() [] """ - return StrongTableaux.marked_CST_to_transposition_sequence( self.to_standard_list(), self.k ) + return StrongTableaux.marked_CST_to_transposition_sequence(self.to_standard_list(), self.k) class StrongTableaux(UniqueRepresentation, Parent): - def __init__( self, k, shape, weight ): + def __init__(self, k, shape, weight): r""" TESTS:: @@ -3864,7 +3873,7 @@ def __init__( self, k, shape, weight ): self._inner_shape = shape[1] self.k = k if weight is None: - self._weight = (1,)*(self._outer_shape.length()-self._inner_shape.length()) + self._weight = (1,) * (self._outer_shape.length() - self._inner_shape.length()) else: self._weight = weight Parent.__init__(self, category=FiniteEnumeratedSets()) @@ -3882,16 +3891,16 @@ def __classcall_private__(cls, k, shape, weight=None): if k <= 0: raise ValueError("The input k has to be a positive integer") if shape == [] or shape[0] in ZZ: - outer_shape = Core(shape,k+1) - inner_shape = Core([],k+1) + outer_shape = Core(shape, k + 1) + inner_shape = Core([], k + 1) else: - outer_shape = Core(shape[0],k+1) - inner_shape = Core(shape[1],k+1) + outer_shape = Core(shape[0], k + 1) + inner_shape = Core(shape[1], k + 1) if weight is not None: weight = tuple(weight) return super().__classcall__(cls, k, (outer_shape, inner_shape), weight) - def _repr_( self ): + def _repr_(self): r""" Return the representation of ``self``. @@ -3906,13 +3915,13 @@ def _repr_( self ): sage: StrongTableaux(3, [[],[]], weight=[]) Set of strong 3-tableaux of shape [] and of weight () """ - if self._inner_shape == Core([],self.k+1): + if self._inner_shape == Core([], self.k + 1): s = "Set of strong %s-tableaux" % self.k s += " of shape %s" % self._outer_shape else: s = "Set of strong %s-tableaux" % self.k s += " of shape [%s, %s]" % (self._outer_shape, self._inner_shape) - s += "%sand of weight %s" % (" ",self._weight) + s += "%sand of weight %s" % (" ", self._weight) return s options = Tableaux.options @@ -4016,13 +4025,13 @@ def __iter__(self): """ size = sum(self._weight) if size == 0: - yield self([[None]*(row) for row in self._inner_shape]) + yield self([[None] * (row) for row in self._inner_shape]) else: - for unT in StrongTableaux.standard_unmarked_iterator( self.k, size, self._outer_shape, self._inner_shape ): - yield from StrongTableaux.marked_given_unmarked_and_weight_iterator( unT, self.k, self._weight ) + for unT in StrongTableaux.standard_unmarked_iterator(self.k, size, self._outer_shape, self._inner_shape): + yield from StrongTableaux.marked_given_unmarked_and_weight_iterator(unT, self.k, self._weight) @classmethod - def standard_unmarked_iterator( cls, k, size, outer_shape=None, inner_shape=[] ): + def standard_unmarked_iterator(cls, k, size, outer_shape=None, inner_shape=[]): r""" An iterator for standard unmarked strong tableaux. @@ -4069,12 +4078,12 @@ def standard_unmarked_iterator( cls, k, size, outer_shape=None, inner_shape=[] ) [[]] """ if size == 0: - if outer_shape is None or Core(outer_shape,k+1).contains(inner_shape): - yield [[None]*(inner_shape[i]) for i in range(len(inner_shape))] + if outer_shape is None or Core(outer_shape, k + 1).contains(inner_shape): + yield [[None] * (inner_shape[i]) for i in range(len(inner_shape))] else: - for T in cls.standard_unmarked_iterator(k, size-1, outer_shape, inner_shape): + for T in cls.standard_unmarked_iterator(k, size - 1, outer_shape, inner_shape): for TT in cls.follows_tableau_unsigned_standard(T, k): - if outer_shape is None or Core(outer_shape, k+1).contains([len(r) for r in TT]): + if outer_shape is None or Core(outer_shape, k + 1).contains([len(r) for r in TT]): yield TT @classmethod @@ -4127,14 +4136,14 @@ def marked_given_unmarked_and_weight_iterator(cls, unmarkedT, k, weight): yield StrongTableau(unmarkedT, k, []) else: import itertools + dsc = Composition(weight).descents() for m in itertools.product(*[td[key] for key in sorted(td)]): - if all(((m[i][1]-m[i][0] < m[i+1][1]-m[i+1][0]) or (i in dsc)) - for i in range(len(m)-1)): + if all(((m[i][1] - m[i][0] < m[i + 1][1] - m[i + 1][0]) or (i in dsc)) for i in range(len(m) - 1)): yield StrongTableaux.add_marking(unmarkedT, m, k, weight) @classmethod - def add_marking( cls, unmarkedT, marking, k, weight ): + def add_marking(cls, unmarkedT, marking, k, weight): r""" Add markings to a partially marked strong tableau. @@ -4170,14 +4179,16 @@ def add_marking( cls, unmarkedT, marking, k, weight ): sage: StrongTableaux.add_marking([], [], 2, []) [] """ + def msgn(c, v): if c in marking: return -v return v - return StrongTableau([[msgn((i,j),unmarkedT[i][j]) for j in range(len(unmarkedT[i]))] for i in range(len(unmarkedT))], k, weight ) + + return StrongTableau([[msgn((i, j), unmarkedT[i][j]) for j in range(len(unmarkedT[i]))] for i in range(len(unmarkedT))], k, weight) @classmethod - def _left_action_list( cls, Tlist, tij, v, k ): + def _left_action_list(cls, Tlist, tij, v, k): r""" Act by the transposition ``tij`` if it increases the size of the tableau by 1. @@ -4213,18 +4224,18 @@ def _left_action_list( cls, Tlist, tij, v, k ): innershape = Core([len(r) for r in Tlist], k + 1) outershape = innershape.affine_symmetric_group_action(tij, transposition=True) if outershape.length() == innershape.length() + 1: - for c in SkewPartition([outershape.to_partition(),innershape.to_partition()]).cells(): + for c in SkewPartition([outershape.to_partition(), innershape.to_partition()]).cells(): while c[0] >= len(Tlist): Tlist.append([]) Tlist[c[0]].append(v) - if len(Tlist[c[0]])-c[0] == tij[1]: + if len(Tlist[c[0]]) - c[0] == tij[1]: Tlist[c[0]][-1] = -Tlist[c[0]][-1] # mark the cell that is on the j-1 diagonal return Tlist raise ValueError("%s is not a single step up in the strong lattice" % tij) @classmethod - def follows_tableau_unsigned_standard( cls, Tlist, k ): + def follows_tableau_unsigned_standard(cls, Tlist, k): r""" Return a list of strong tableaux one longer in length than ``Tlist``. @@ -4258,8 +4269,7 @@ def follows_tableau_unsigned_standard( cls, Tlist, k ): sage: StrongTableaux.follows_tableau_unsigned_standard([], 4) [[[1]]] """ - v = 1 + max((abs(v) for rows in Tlist for v in rows if v is not None), - default=0) + v = 1 + max((abs(v) for rows in Tlist for v in rows if v is not None), default=0) out = [] sh = Core([len(r) for r in Tlist], k + 1) for ga in sh.strong_covers(): @@ -4271,7 +4281,7 @@ def follows_tableau_unsigned_standard( cls, Tlist, k ): return out @classmethod - def standard_marked_iterator( cls, k, size, outer_shape=None, inner_shape=[] ): + def standard_marked_iterator(cls, k, size, outer_shape=None, inner_shape=[]): r""" An iterator for generating standard strong marked tableaux. @@ -4314,11 +4324,11 @@ def standard_marked_iterator( cls, k, size, outer_shape=None, inner_shape=[] ): sage: list(StrongTableaux.standard_marked_iterator(4,0)) [[]] """ - for T in cls.standard_unmarked_iterator( k, size, outer_shape, inner_shape ): - yield from cls.marked_given_unmarked_and_weight_iterator( T, k, [1]*(size) ) + for T in cls.standard_unmarked_iterator(k, size, outer_shape, inner_shape): + yield from cls.marked_given_unmarked_and_weight_iterator(T, k, [1] * (size)) @classmethod - def cells_head_dictionary( cls, T ): + def cells_head_dictionary(cls, T): r""" Return a dictionary with the locations of the heads of all markings. @@ -4415,17 +4425,16 @@ def marked_CST_to_transposition_sequence(self, T, k): [] """ LL = list(T) - if not LL or all(v is None for v in sum(LL,[])): + if not LL or all(v is None for v in sum(LL, [])): return [] marks = [v for row in T for v in row if v is not None and v < 0] + [0] - m = -min(marks) # the largest marked cell - transeq = [] # start with the empty list and append on the right + m = -min(marks) # the largest marked cell + transeq = [] # start with the empty list and append on the right sh = Core([len(r) for r in T], k + 1) - j = max(c - r for r, row in enumerate(LL) for c, val in enumerate(row) - if val == -m) + j = max(c - r for r, row in enumerate(LL) for c, val in enumerate(row) if val == -m) P = sh.to_partition() for l in range(k): - msh = sh.affine_symmetric_group_action([j-l,j+1], transposition=True) + msh = sh.affine_symmetric_group_action([j - l, j + 1], transposition=True) mP = msh.to_partition() # my worry here is that the affine symmetric group action might apply an invalid # transposition but get something of the right length anyway. How do I test if it is applying @@ -4447,15 +4456,13 @@ def marked_CST_to_transposition_sequence(self, T, k): # if all labels that are not content j are v and the label # with content j = -m mcells = mP.cells() - MM = [[LL[a][b] for b in range(len(LL[a])) - if (a, b) in mcells] - for a in range(len(mP))] + MM = [[LL[a][b] for b in range(len(LL[a])) if (a, b) in mcells] for a in range(len(mP))] transeq = self.marked_CST_to_transposition_sequence(MM, k) if transeq is not None: - return [[j-l, j+1]] + transeq + return [[j - l, j + 1]] + transeq @classmethod - def transpositions_to_standard_strong( self, transeq, k, emptyTableau=[] ): + def transpositions_to_standard_strong(self, transeq, k, emptyTableau=[]): """ Return a strong tableau corresponding to a sequence of transpositions. @@ -4491,12 +4498,13 @@ def transpositions_to_standard_strong( self, transeq, k, emptyTableau=[] ): [] """ out = copy.deepcopy(emptyTableau) - for i in range(1,len(transeq)+1): + for i in range(1, len(transeq) + 1): out = StrongTableaux._left_action_list(out, transeq[-i], i, k) - return StrongTableau(out, k, weight=(1,)*len(transeq)) + return StrongTableau(out, k, weight=(1,) * len(transeq)) Element = StrongTableau + #### common or global functions related to weak/strong tableaux @@ -4546,6 +4554,6 @@ def intermediate_shapes(t): """ shapes = [] t = SkewTableau(list(t)) - for i in range(len(t.weight())+1): - shapes += [ t.restrict(i).outer_shape()] + for i in range(len(t.weight()) + 1): + shapes += [t.restrict(i).outer_shape()] return shapes diff --git a/src/sage/combinat/kazhdan_lusztig.py b/src/sage/combinat/kazhdan_lusztig.py index da25934c809..0bd7ae9eda9 100644 --- a/src/sage/combinat/kazhdan_lusztig.py +++ b/src/sage/combinat/kazhdan_lusztig.py @@ -113,12 +113,12 @@ def R(self, x, y): return self._base_ring.one() return self._base_ring.zero() s = self._coxeter_group.simple_reflection(y.first_descent(side='left')) - if (s*x).length() < x.length(): - ret = self.R(s*x,s*y) + if (s * x).length() < x.length(): + ret = self.R(s * x, s * y) if self._trace: print(" R(%s,%s)=%s" % (x, y, ret)) return ret - ret = (self._q-1)*self.R(s*x,y)+self._q*self.R(s*x,s*y) + ret = (self._q - 1) * self.R(s * x, y) + self._q * self.R(s * x, s * y) if self._trace: print(" R(%s,%s)=%s" % (x, y, ret)) return ret @@ -201,8 +201,7 @@ def P(self, x, y): if x.length() == 0: return self._base_ring.one() return self._base_ring.zero() - p = sum(-self.R(x, t) * self.P(t, y) - for t in self._coxeter_group.bruhat_interval(x, y) if t != x) + p = sum(-self.R(x, t) * self.P(t, y) for t in self._coxeter_group.bruhat_interval(x, y) if t != x) tr = (y.length() - x.length() + 1) // 2 ret = p.truncate(tr) if self._trace: diff --git a/src/sage/combinat/key_polynomial.py b/src/sage/combinat/key_polynomial.py index d75d024f158..e3d68db86c7 100644 --- a/src/sage/combinat/key_polynomial.py +++ b/src/sage/combinat/key_polynomial.py @@ -88,10 +88,10 @@ def sorting_word(alpha): n = len(L) # bubble sort to get the shortest sorting word - for i in range(n-1): - for j in range(n-i-1): + for i in range(n - 1): + for j in range(n - i - 1): if L[j] < L[j + 1]: - w.append(j+1) + w.append(j + 1) L[j], L[j + 1] = L[j + 1], L[j] return reversed(w), L @@ -149,8 +149,8 @@ def divided_difference(f, i): else: z = P.gens() - si_f = f.subs({z[i]: z[i-1], z[i-1]: z[i]}) - return (si_f - f) // (z[i] - z[i-1]) + si_f = f.subs({z[i]: z[i - 1], z[i - 1]: z[i]}) + return (si_f - f) // (z[i] - z[i - 1]) def isobaric_divided_difference(f, w): @@ -193,9 +193,9 @@ def isobaric_divided_difference(f, w): if not hasattr(w, "__iter__"): # this allows us to pass i instead of a word w = [w] for i in w: - fp = z[i-1] * f - si_fp = fp.subs({z[i]: z[i-1], z[i-1]: z[i]}) - f = (si_fp - fp) // (z[i] - z[i-1]) + fp = z[i - 1] * f + si_fp = fp.subs({z[i]: z[i - 1], z[i - 1]: z[i]}) + f = (si_fp - fp) // (z[i] - z[i - 1]) return f @@ -241,8 +241,8 @@ def isobaric_divided_difference_bar(f, w): if not hasattr(w, "__iter__"): # this allows us to pass i instead of a word w = [w] for i in w: - sif = f.subs({z[i]: z[i-1], z[i-1]: z[i]}) - f = z[i] * (f - sif) // (z[i-1] - z[i]) + sif = f.subs({z[i]: z[i - 1], z[i - 1]: z[i]}) + f = z[i] * (f - sif) // (z[i - 1] - z[i]) return f @@ -258,6 +258,7 @@ class OperatorPolynomial(CombinatorialFreeModule.Element): Parents should implement the divided difference operator as a ``staticmethod`` ``_operator``. """ + def _mul_(self, other): r""" Multiply the elements ``self`` and ``other``. @@ -384,6 +385,7 @@ class KeyPolynomial(OperatorPolynomial): sage: f in k True """ + def pi(self, w): r""" Apply the operator `\pi_w` to ``self``. @@ -468,9 +470,9 @@ def pi(self, w): if i == n: m += [0] n += 1 - if m[i-1] <= m[i]: + if m[i - 1] <= m[i]: continue - m[i-1], m[i] = m[i], m[i-1] + m[i - 1], m[i] = m[i], m[i - 1] m = P._indices(m) if P._k is None: m = m.trim() @@ -549,6 +551,7 @@ class AtomPolynomial(OperatorPolynomial): sage: f in a True """ + def pibar(self, w): r""" Apply the operator `\bar{\pi}_w` to ``self``. @@ -632,13 +635,13 @@ def pibar(self, w): if i == n: m += [0] n += 1 - if i > n or m[i-1] == m[i]: + if i > n or m[i - 1] == m[i]: m = None break - if m[i-1] < m[i]: + if m[i - 1] < m[i]: sign = -sign continue - m[i-1], m[i] = m[i], m[i-1] + m[i - 1], m[i] = m[i], m[i - 1] if m is None: continue m = P._indices(m) @@ -707,6 +710,7 @@ class OperatorPolynomialBasis(CombinatorialFreeModule): type operators such that the result is a triangular change of basis with the natural monomial basis. """ + @staticmethod def __classcall__(cls, R=None, k=None, poly_ring=None, poly_coeffs=False): r""" @@ -734,9 +738,7 @@ def __classcall__(cls, R=None, k=None, poly_ring=None, poly_coeffs=False): sage: KeyPolynomials(QQ, 3) Key polynomial basis over Rational Field """ - poly_type = (PolynomialRing_commutative, - MPolynomialRing_base, - InfinitePolynomialRing_sparse) + poly_type = (PolynomialRing_commutative, MPolynomialRing_base, InfinitePolynomialRing_sparse) if isinstance(R, poly_type): # if a polynomial ring is provided, we need to determine @@ -778,9 +780,12 @@ def __init__(self, R=None, k=None, poly_ring=None): self._k = k if self._k is not None: + def build_index(m): return self._indices(m) + else: + def build_index(m): mc = m.monomial_coefficients() v = [0 for _ in range(max(mc, default=-1) + 1)] @@ -803,9 +808,7 @@ def build_index(m): R = poly_ring.base_ring() self._polynomial_ring = poly_ring - CombinatorialFreeModule.__init__(self, R, IntegerVectors(k=k), - category=GradedAlgebrasWithBasis(R), - prefix=self._prefix, bracket=False) + CombinatorialFreeModule.__init__(self, R, IntegerVectors(k=k), category=GradedAlgebrasWithBasis(R), prefix=self._prefix, bracket=False) def _coerce_map_from_(self, R): r""" @@ -984,8 +987,8 @@ def from_polynomial(self, f): if f not in self._polynomial_ring: try: # to accept elements of SymbolicRing from sage.calculus.var import var - f = f.substitute([d == var(f'z_{i}') - for i, d in enumerate(f.variables())]) + + f = f.substitute([d == var(f'z_{i}') for i, d in enumerate(f.variables())]) f = self._polynomial_ring(f) except AttributeError: raise ValueError(f"f must be an element of {self._polynomial_ring}") @@ -1134,6 +1137,7 @@ class KeyPolynomialBasis(OperatorPolynomialBasis): sage: (q^2 + q + 1)*k([0,2,2,0,3,2]) (q^2+q+1)*k[0, 2, 2, 0, 3, 2] """ + Element = KeyPolynomial _name = "Key polynomial basis" _prefix = 'k' @@ -1167,6 +1171,7 @@ def _coerce_map_from_(self, R): return self.from_polynomial from sage.combinat.schubert_polynomial import SchubertPolynomialRing_xbasis + if isinstance(R, SchubertPolynomialRing_xbasis): return self.from_schubert_polynomial @@ -1221,17 +1226,22 @@ def from_schubert_polynomial(self, x): return self(x) from sage.combinat.schubert_polynomial import SchubertPolynomial_class + if not isinstance(x, SchubertPolynomial_class): raise ValueError('not a Schubert polynomial') from sage.combinat.diagram import RotheDiagram + out = self.zero() if self._k is not None: + def build_elt(wt): wt = list(wt) wt += [0] * (self._k - len(wt)) return self[wt] + else: + def build_elt(wt): return self[wt] @@ -1320,6 +1330,7 @@ class AtomPolynomialBasis(OperatorPolynomialBasis): sage: a([10,9,1]) * (z[0] + z[3]) a[10, 9, 1, 1] + a[11, 9, 1] """ + Element = AtomPolynomial _name = "Atom polynomial basis" _prefix = 'a' @@ -1384,7 +1395,7 @@ def on_basis(m): w = list(w) if not w: return dom - sigma = Permutations(max(w)+1).from_reduced_word(w) + sigma = Permutations(max(w) + 1).from_reduced_word(w) return self.sum(dom.pibar(wp.reduced_word()) for wp in sigma.bruhat_smaller()) return self.linear_combination((on_basis(m), c) for m, c in x) @@ -1420,6 +1431,7 @@ def _coerce_map_from_(self, R): return self.from_key_polynomial from sage.combinat.schubert_polynomial import SchubertPolynomialRing_xbasis + if isinstance(R, SchubertPolynomialRing_xbasis): K = KeyPolynomialBasis(self.base_ring(), self._k, self._polynomial_ring) return self._coerce_map_via([K], R) diff --git a/src/sage/combinat/knutson_tao_puzzles.py b/src/sage/combinat/knutson_tao_puzzles.py index eb3f7b6a64d..9d3c4010795 100644 --- a/src/sage/combinat/knutson_tao_puzzles.py +++ b/src/sage/combinat/knutson_tao_puzzles.py @@ -27,6 +27,7 @@ R. Vakil, A geometric Littlewood-Richardson rule, :arxiv:`math/0302294` or K. Purbhoo, Puzzles, Tableaux and Mosaics, :arxiv:`0705.1184`. """ + # **************************************************************************** # Copyright (C) 2013 Franco Saliola , # 2013 Allen Knutson, @@ -41,12 +42,14 @@ from __future__ import annotations from sage.misc.lazy_import import lazy_import + lazy_import("sage.plot.graphics", "Graphics") lazy_import("sage.plot.polygon", "polygon") lazy_import("sage.plot.line", "line") lazy_import("sage.plot.text", "text") from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.finite_rings.integer_mod_ring import Integers + lazy_import("sage.plot.plot", "graphics_array") from sage.misc.cachefunc import cached_method from sage.structure.unique_representation import UniqueRepresentation @@ -127,9 +130,7 @@ def color(self) -> str: sage: delta.color() 'yellow' """ - colors = {('0', '0', '0'): 'red', - ('1', '1', '1'): 'blue', - ('2', '2', '2'): 'green'} + colors = {('0', '0', '0'): 'red', ('1', '1', '1'): 'blue', ('2', '2', '2'): 'green'} border = self.border() if border in colors: color = colors[border] @@ -143,8 +144,7 @@ def color(self) -> str: color = 'white' return color - def _plot_label(self, label, coords, fontcolor=(0.3, 0.3, 0.3), - fontsize=15, rotation=0): + def _plot_label(self, label, coords, fontcolor=(0.3, 0.3, 0.3), fontsize=15, rotation=0): r""" TESTS:: @@ -156,8 +156,7 @@ def _plot_label(self, label, coords, fontcolor=(0.3, 0.3, 0.3), return text(label, coords, color=fontcolor, fontsize=fontsize, rotation=rotation) return Graphics() - def _plot_piece(self, coords, border_color=(0.5, 0.5, 0.5), - border_thickness=1, style='fill'): + def _plot_piece(self, coords, border_color=(0.5, 0.5, 0.5), border_thickness=1, style='fill'): r""" TESTS:: @@ -178,9 +177,7 @@ def _plot_piece(self, coords, border_color=(0.5, 0.5, 0.5), edges = self.edges() P = Graphics() for i, edge in enumerate(edges): - P += line([coords[i], coords[(i + 1) % 3]], - color=self.edge_color(edge), - thickness=border_thickness) + P += line([coords[i], coords[(i + 1) % 3]], color=self.edge_color(edge), thickness=border_thickness) return P return NotImplemented @@ -272,8 +269,7 @@ def __eq__(self, other) -> bool: False """ if isinstance(other, NablaPiece): - return (self.border() == other.border() and - self._edge_labels == other._edge_labels) + return self.border() == other.border() and self._edge_labels == other._edge_labels return False def __hash__(self): @@ -297,9 +293,7 @@ def __repr__(self) -> str: sage: NablaPiece('1','2','3') 3\1/2 """ - return r"%s\%s/%s" % (self['south_west'], - self['north'], - self['south_east']) + return r"%s\%s/%s" % (self['south_west'], self['north'], self['south_east']) def clockwise_rotation(self) -> NablaPiece: r""" @@ -314,9 +308,7 @@ def clockwise_rotation(self) -> NablaPiece: sage: nabla.clockwise_rotation() 2\3/1 """ - return NablaPiece(north=self['south_west'], - south_east=self['north'], - south_west=self['south_east']) + return NablaPiece(north=self['south_west'], south_east=self['north'], south_west=self['south_east']) def half_turn_rotation(self) -> DeltaPiece: r""" @@ -331,9 +323,7 @@ def half_turn_rotation(self) -> DeltaPiece: sage: nabla.half_turn_rotation() 2/1\3 """ - return DeltaPiece(south=self['north'], - north_west=self['south_east'], - north_east=self['south_west']) + return DeltaPiece(south=self['north'], north_west=self['south_east'], north_east=self['south_west']) def edges(self) -> tuple: r""" @@ -389,8 +379,7 @@ def __eq__(self, other) -> bool: False """ if isinstance(other, DeltaPiece): - return (self.border() == other.border() and - self._edge_labels == other._edge_labels) + return self.border() == other.border() and self._edge_labels == other._edge_labels return False def __hash__(self): @@ -414,9 +403,7 @@ def __repr__(self) -> str: sage: DeltaPiece('1','2','3') 2/1\3 """ - return r"%s/%s\%s" % (self['north_west'], - self['south'], - self['north_east']) + return r"%s/%s\%s" % (self['north_west'], self['south'], self['north_east']) def clockwise_rotation(self) -> DeltaPiece: r""" @@ -431,9 +418,7 @@ def clockwise_rotation(self) -> DeltaPiece: sage: delta.clockwise_rotation() 1/3\2 """ - return DeltaPiece(south=self['north_east'], - north_west=self['south'], - north_east=self['north_west']) + return DeltaPiece(south=self['north_east'], north_west=self['south'], north_east=self['north_west']) def half_turn_rotation(self) -> NablaPiece: r""" @@ -448,9 +433,7 @@ def half_turn_rotation(self) -> NablaPiece: sage: delta.half_turn_rotation() 3\1/2 """ - return NablaPiece(north=self['south'], - south_east=self['north_west'], - south_west=self['north_east']) + return NablaPiece(north=self['south'], south_east=self['north_west'], south_west=self['north_east']) def edges(self) -> tuple: r""" @@ -495,10 +478,7 @@ def __init__(self, north_piece, south_piece): """ self._north_piece = north_piece self._south_piece = south_piece - self._edge_labels = dict(north_west=north_piece['north_west'], - north_east=north_piece['north_east'], - south_east=south_piece['south_east'], - south_west=south_piece['south_west']) + self._edge_labels = dict(north_west=north_piece['north_west'], north_east=north_piece['north_east'], south_east=south_piece['south_east'], south_west=south_piece['south_west']) def __eq__(self, other) -> bool: r""" @@ -515,10 +495,7 @@ def __eq__(self, other) -> bool: False """ if isinstance(other, RhombusPiece): - return (self.border() == other.border() and - self._north_piece == other._north_piece and - self._south_piece == other._south_piece and - self._edge_labels == other._edge_labels) + return self.border() == other.border() and self._north_piece == other._north_piece and self._south_piece == other._south_piece and self._edge_labels == other._edge_labels return False def __hash__(self): @@ -590,8 +567,7 @@ def __repr__(self) -> str: sage: RhombusPiece(delta,nabla) 2/\3 6\/5 """ - return r"%s/\%s %s\/%s" % (self['north_west'], self['north_east'], - self['south_west'], self['south_east']) + return r"%s/\%s %s\/%s" % (self['north_west'], self['north_east'], self['south_west'], self['south_east']) def edges(self) -> tuple: r""" @@ -873,8 +849,7 @@ def boundary_deltas(self) -> tuple: sage: sorted([p for p in pieces.boundary_deltas()], key=str) [a/c\b, c/b\a] """ - return tuple(delta for delta in self.delta_pieces() - if delta['south'] not in self._forbidden_border_labels) + return tuple(delta for delta in self.delta_pieces() if delta['south'] not in self._forbidden_border_labels) def H_grassmannian_pieces(): @@ -998,8 +973,7 @@ def HT_two_step_pieces(): 2/2(10)\10, 2/20\0, 2/21\1, 2/2\2, 20/0\2, 21/(21)0\0, 21/1\2] """ pieces = H_two_step_pieces() - for label1, label2 in (('0', '1'), ('0', '2'), ('1', '2'), - ('10', '2'), ('0', '21'), ('10', '21')): + for label1, label2 in (('0', '1'), ('0', '2'), ('1', '2'), ('10', '2'), ('0', '21'), ('10', '21')): pieces.add_T_piece(label1, label2) return pieces @@ -1039,16 +1013,13 @@ def BK_pieces(max_letter): Nablas : [1\1/1, 1\2(1)/2, 1\3(1)/3, 2(1)\2/1, 2\1/2(1), 2\2/2, 2\3(2)/3, 3(1)\3/1, 3(2)\3/2, 3\1/3(1), 3\2/3(2), 3\3/3] Deltas : [1/1\1, 1/2\2(1), 1/3\3(1), 2(1)/1\2, 2/2(1)\1, 2/2\2, 2/3\3(2), 3(1)/1\3, 3(2)/2\3, 3/3(1)\1, 3/3(2)\2, 3/3\3] """ - forbidden_border_labels = ['%s(%s)' % (i, j) - for i in range(1, max_letter + 1) - for j in range(1, i)] + forbidden_border_labels = ['%s(%s)' % (i, j) for i in range(1, max_letter + 1) for j in range(1, i)] pieces = PuzzlePieces(forbidden_border_labels) for i in range(1, max_letter + 1): piece = DeltaPiece('%s' % i, '%s' % i, '%s' % i) pieces.add_piece(piece, rotations=60) for j in range(1, i): - piece = DeltaPiece(north_west='%s' % i, north_east='%s' % j, - south='%s(%s)' % (i, j)) + piece = DeltaPiece(north_west='%s' % i, north_east='%s' % j, south='%s(%s)' % (i, j)) pieces.add_piece(piece, rotations=60) return pieces @@ -1303,6 +1274,7 @@ def __repr__(self): '{}' """ from pprint import pformat + return pformat(self._squares) def __iter__(self): @@ -1396,11 +1368,11 @@ def _latex_(self): sage: view(solns[0], viewer='pdf') # not tested """ from collections import defaultdict + label_colors = defaultdict(lambda: None) label_colors.update({'0': 'red', '1': 'blue', '2': 'green'}) edge_colors = defaultdict(lambda: None) - edge_colors.update({'0': 'red', '1': 'blue', - '2': 'green', 'K': 'orange'}) + edge_colors.update({'0': 'red', '1': 'blue', '2': 'green', 'K': 'orange'}) s = r"""\begin{tikzpicture}[yscale=1.73]""" coords = [(k, -d) for d in range(self._n) for k in range(-d, d + 1, 2)] @@ -2056,9 +2028,7 @@ def _fill_piece(self, nw_label, ne_label, pieces) -> list[PuzzlePiece]: sage: ps._fill_piece('0', '0', ps._bottom_deltas) [0/0\0] """ - return [piece for piece in pieces - if (piece['north_west'] == nw_label and - piece['north_east'] == ne_label)] + return [piece for piece in pieces if (piece['north_west'] == nw_label and piece['north_east'] == ne_label)] @cached_method def _fill_strip(self, nw_labels, ne_label, pieces, final_pieces=None): @@ -2160,8 +2130,7 @@ def _fill_puzzle_by_strips(self, lamda, mu): if i == 1: nw_labels = PP._nw_labels else: - nw_labels = tuple(PP._squares[i - 1, k]['south_east'] - for k in range(i, len(lamda) + 1)) + nw_labels = tuple(PP._squares[i - 1, k]['south_east'] for k in range(i, len(lamda) + 1)) # grab ne labels ne_label = PP._ne_labels[i - 1] @@ -2266,6 +2235,7 @@ def structure_constants(self, lamda, mu, nu=None): (('2', '1', '1', '0', '2'), 1)] """ from collections import defaultdict + R = PolynomialRing(Integers(), 'y', len(lamda) + 1) z = defaultdict(R.zero) for p in self(lamda, mu): diff --git a/src/sage/combinat/lr_tableau.py b/src/sage/combinat/lr_tableau.py index f7476235575..ca2b97071ec 100644 --- a/src/sage/combinat/lr_tableau.py +++ b/src/sage/combinat/lr_tableau.py @@ -12,7 +12,7 @@ - Maria Gillespie, Jake Levinson, Anne Schilling (2016): initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2016 Maria Gillespie # Anne Schilling # @@ -26,7 +26,7 @@ # The full text of the GPL is available at: # # https://www.gnu.org/licenses/ -#**************************************************************************** +# **************************************************************************** from itertools import zip_longest, accumulate @@ -53,6 +53,7 @@ class LittlewoodRichardsonTableau(SemistandardTableau): sage: LittlewoodRichardsonTableau([[1,1,3],[2,3],[4]], [[2,1],[2,1]]) [[1, 1, 3], [2, 3], [4]] """ + @staticmethod def __classcall_private__(cls, t, weight): r""" @@ -130,11 +131,9 @@ def check(self): """ super().check() if not [i for a in self.parent()._weight for i in a] == self.weight(): - raise ValueError("weight of the parent does not agree " - "with the weight of the tableau") + raise ValueError("weight of the parent does not agree " "with the weight of the tableau") if not self.shape() == self.parent()._shape: - raise ValueError("shape of the parent does not agree " - "with the shape of the tableau") + raise ValueError("shape of the parent does not agree " "with the shape of the tableau") class LittlewoodRichardsonTableaux(SemistandardTableaux): @@ -157,6 +156,7 @@ class LittlewoodRichardsonTableaux(SemistandardTableaux): sage: LittlewoodRichardsonTableaux([3,2,1],[[2,1],[2,1]]) Littlewood-Richardson Tableaux of shape [3, 2, 1] and weight ([2, 1], [2, 1]) """ + @staticmethod def __classcall_private__(cls, shape, weight): r""" @@ -214,12 +214,12 @@ def __iter__(self): [[[1, 1, 3], [2, 3], [4]], [[1, 1, 3], [2, 4], [3]]] """ from sage.libs.lrcalc.lrcalc import lrskew + if not self._weight: yield self.element_class(self, []) return - for nu in Partitions(self._shape.size() - self._weight[-1].size(), - outer=self._shape): + for nu in Partitions(self._shape.size() - self._weight[-1].size(), outer=self._shape): for s in lrskew(self._shape, nu, weight=self._weight[-1]): for t in LittlewoodRichardsonTableaux(nu, self._weight[:-1]): shift = sum(a.length() for a in self._weight[:-1]) @@ -243,11 +243,11 @@ def __contains__(self, t): sage: T in LR True """ - return (SemistandardTableaux.__contains__(self, t) - and is_littlewood_richardson(t, self._heights)) + return SemistandardTableaux.__contains__(self, t) and is_littlewood_richardson(t, self._heights) Element = LittlewoodRichardsonTableau + #### common or global functions related to LR tableaux @@ -277,6 +277,7 @@ def is_littlewood_richardson(t, heights): False """ from sage.combinat.words.word import Word + try: w = t.to_word() except AttributeError: # Not an instance of Tableau @@ -284,8 +285,7 @@ def is_littlewood_richardson(t, heights): partial = list(accumulate(heights, initial=0)) for i in range(len(heights)): - subword = Word([j for j in w if partial[i]+1 <= j <= partial[i+1]], - alphabet=list(range(partial[i]+1, partial[i+1]+1))) + subword = Word([j for j in w if partial[i] + 1 <= j <= partial[i + 1]], alphabet=list(range(partial[i] + 1, partial[i + 1] + 1))) if not subword.is_yamanouchi(): return False return True @@ -306,5 +306,4 @@ def _tableau_join(t1, t2, shift=0): sage: _tableau_join([[1,2]],[[None,None,2],[3]],shift=5) [[1, 2, 7], [8]] """ - return [list(row1) + [e2 + shift for e2 in row2 if e2 is not None] - for row1, row2 in zip_longest(t1, t2, fillvalue=[])] + return [list(row1) + [e2 + shift for e2 in row2 if e2 is not None] for row1, row2 in zip_longest(t1, t2, fillvalue=[])] diff --git a/src/sage/combinat/matrices/all.py b/src/sage/combinat/matrices/all.py index 0f6adbb5355..9ca3f55abda 100644 --- a/src/sage/combinat/matrices/all.py +++ b/src/sage/combinat/matrices/all.py @@ -6,14 +6,14 @@ - :ref:`sage.combinat.matrices.hadamard_matrix` - :ref:`sage.combinat.matrices.latin` """ + # install the docstring of this module to the containing package from sage.misc.namespace_package import install_doc + install_doc(__package__, __doc__) from sage.misc.lazy_import import lazy_import -lazy_import('sage.combinat.matrices.latin', - ['LatinSquare', 'LatinSquare_generator']) +lazy_import('sage.combinat.matrices.latin', ['LatinSquare', 'LatinSquare_generator']) lazy_import('sage.combinat.matrices.dlxcpp', 'DLXCPP') -lazy_import('sage.combinat.matrices.hadamard_matrix', - ['hadamard_matrix', 'hadamard_matrix_www']) +lazy_import('sage.combinat.matrices.hadamard_matrix', ['hadamard_matrix', 'hadamard_matrix_www']) diff --git a/src/sage/combinat/matrices/dlxcpp.py b/src/sage/combinat/matrices/dlxcpp.py index 15c6eddbbdc..ea7cac58214 100644 --- a/src/sage/combinat/matrices/dlxcpp.py +++ b/src/sage/combinat/matrices/dlxcpp.py @@ -1,6 +1,7 @@ """ Dancing links C++ wrapper """ + # **************************************************************************** # Copyright (C) 2008 Carlo Hamalainen , # diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index 7b95774202d..c5db1835ad2 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -85,21 +85,11 @@ from urllib.request import urlopen from sage.arith.misc import divisors, is_prime_power, is_square, is_prime -from sage.combinat.designs.difference_family import (get_fixed_relative_difference_set, - relative_difference_set_from_homomorphism, - skew_supplementary_difference_set, - complementary_difference_sets) +from sage.combinat.designs.difference_family import get_fixed_relative_difference_set, relative_difference_set_from_homomorphism, skew_supplementary_difference_set, complementary_difference_sets from sage.combinat.t_sequences import T_sequences_smallcases from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.matrix.constructor import (block_matrix, - block_diagonal_matrix, - diagonal_matrix, - identity_matrix as I, - ones_matrix as J, - matrix, - matrix_method, - zero_matrix) +from sage.matrix.constructor import block_matrix, block_diagonal_matrix, diagonal_matrix, identity_matrix as I, ones_matrix as J, matrix, matrix_method, zero_matrix from sage.misc.unknown import Unknown from sage.modules.free_module_element import vector @@ -134,7 +124,7 @@ def normalise_hadamard(H, skew=False): if skew: dd = diagonal_matrix(H[0]) - return dd*H*dd + return dd * H * dd for i in range(H.ncols()): if H[0, i] < 0: H.rescale_col(i, -1) @@ -194,12 +184,11 @@ def hadamard_matrix_paleyI(n, normalize=True): raise ValueError("The order %s is not covered by the Paley type I construction." % n) from sage.rings.finite_rings.finite_field_constructor import FiniteField + K = FiniteField(p, 'x') K_list = list(K) K_list.insert(0, K.zero()) - H = matrix(ZZ, [[(1 if (x-y).is_square() else -1) - for x in K_list] - for y in K_list]) + H = matrix(ZZ, [[(1 if (x - y).is_square() else -1) for x in K_list] for y in K_list]) for i in range(n): H[i, 0] = -1 H[0, i] = 1 @@ -247,12 +236,11 @@ def symmetric_conference_matrix_paley(n): raise ValueError("The order %s is not covered by Paley construction of symmetric conference matrices." % n) from sage.rings.finite_rings.finite_field_constructor import FiniteField + K = FiniteField(q, 'x') K_list = list(K) K_list.insert(0, K.zero()) - H = matrix(ZZ, [[(1 if (x-y).is_square() else -1) - for x in K_list] - for y in K_list]) + H = matrix(ZZ, [[(1 if (x - y).is_square() else -1) for x in K_list] for y in K_list]) for i in range(n): H[0, i] = 1 H[i, 0] = 1 @@ -303,17 +291,15 @@ def hadamard_matrix_paleyII(n): ....: for n in test_cases) True """ - q = n//2 - 1 + q = n // 2 - 1 if not (n % 2 == 0 and is_prime_power(q) and (q % 4 == 1)): raise ValueError("The order %s is not covered by the Paley type II construction." % n) - H = symmetric_conference_matrix_paley(q+1) + H = symmetric_conference_matrix_paley(q + 1) - tr = { 0: matrix(2, 2, [ 1, -1, -1, -1]), - 1: matrix(2, 2, [ 1, 1, 1, -1]), - -1: matrix(2, 2, [-1, -1, -1, 1])} + tr = {0: matrix(2, 2, [1, -1, -1, -1]), 1: matrix(2, 2, [1, 1, 1, -1]), -1: matrix(2, 2, [-1, -1, -1, 1])} - H = block_matrix(q+1, q+1, [tr[v] for r in H for v in r]) + H = block_matrix(q + 1, q + 1, [tr[v] for r in H for v in r]) return normalise_hadamard(H) @@ -381,7 +367,7 @@ def hadamard_matrix_from_symmetric_conference_matrix(n, existence=False, check=T if n < 0 or n % 4 != 0: raise ValueError(f'No Hadamard matrix of order {n} exists.') - m = n//2 + m = n // 2 exists = symmetric_conference_matrix(m, existence=True) if existence: @@ -392,8 +378,7 @@ def hadamard_matrix_from_symmetric_conference_matrix(n, existence=False, check=T C = symmetric_conference_matrix(m) - H = block_matrix([[C + I(m), C - I(m)], - [C - I(m), -C - I(m)]]) + H = block_matrix([[C + I(m), C - I(m)], [C - I(m), -C - I(m)]]) if check: assert is_hadamard_matrix(H) @@ -462,51 +447,43 @@ def hadamard_matrix_miyamoto_construction(n, existence=False, check=True): q = n // 4 if existence: # return is_prime_power(q) and q % 4 == 1 and hadamard_matrix(q-1, existence=True) is True - return symmetric_conference_matrix(q+1, existence=True) and hadamard_matrix(q-1, existence=True) is True + return symmetric_conference_matrix(q + 1, existence=True) and hadamard_matrix(q - 1, existence=True) is True # if not (is_prime_power(q) and q % 4 == 1 and hadamard_matrix(q-1, existence=True)): - if not (symmetric_conference_matrix(q+1, existence=True) and hadamard_matrix(q-1, existence=True)): + if not (symmetric_conference_matrix(q + 1, existence=True) and hadamard_matrix(q - 1, existence=True)): raise ValueError(f'The order {n} is not covered by Miyamoto construction.') - m = (q-1) // 2 + m = (q - 1) // 2 C = symmetric_conference_matrix(q + 1) - neg = [i for i in range(2, m+2) if C[1, i] == -1] - pos = [i for i in range(m+2, 2*m+2) if C[1, i] == 1] + neg = [i for i in range(2, m + 2) if C[1, i] == -1] + pos = [i for i in range(m + 2, 2 * m + 2) if C[1, i] == 1] for i, j in zip(neg, pos): C.swap_rows(i, j) C.swap_columns(i, j) C1 = -C.submatrix(row=2, col=2, nrows=m, ncols=m) - C2 = C.submatrix(row=2, col=m+2, nrows=m, ncols=m) - C4 = C.submatrix(row=m+2, col=m+2, nrows=m, ncols=m) + C2 = C.submatrix(row=2, col=m + 2, nrows=m, ncols=m) + C4 = C.submatrix(row=m + 2, col=m + 2, nrows=m, ncols=m) K = hadamard_matrix(q - 1) - K1 = K.submatrix(row=0, col=0, nrows=(q-1)//2, ncols=(q-1)//2) - K2 = K.submatrix(row=0, col=(q-1)//2, nrows=(q-1)//2, ncols=(q-1)//2) - K3 = -K.submatrix(row=(q-1)//2, col=0, nrows=(q-1)//2, ncols=(q-1)//2) - K4 = K.submatrix(row=(q-1)//2, col=(q-1)//2, nrows=(q-1)//2, ncols=(q-1)//2) + K1 = K.submatrix(row=0, col=0, nrows=(q - 1) // 2, ncols=(q - 1) // 2) + K2 = K.submatrix(row=0, col=(q - 1) // 2, nrows=(q - 1) // 2, ncols=(q - 1) // 2) + K3 = -K.submatrix(row=(q - 1) // 2, col=0, nrows=(q - 1) // 2, ncols=(q - 1) // 2) + K4 = K.submatrix(row=(q - 1) // 2, col=(q - 1) // 2, nrows=(q - 1) // 2, ncols=(q - 1) // 2) Zr = zero_matrix(m) Us = [[C1, C2, Zr, Zr], [C2.T, C4, Zr, Zr], [Zr, Zr, C1, C2], [Zr, Zr, C2.T, C4]] Vs = [[I(m), Zr, K1, K2], [Zr, I(m), K3, K4], [K1.T, K3.T, I(m), Zr], [K2.T, K4.T, Zr, I(m)]] def T(i, j): - return block_matrix([[Us[i][j]+Vs[i][j], Us[i][j]-Vs[i][j]], - [Us[i][j]-Vs[i][j], Us[i][j]+Vs[i][j]]]) + return block_matrix([[Us[i][j] + Vs[i][j], Us[i][j] - Vs[i][j]], [Us[i][j] - Vs[i][j], Us[i][j] + Vs[i][j]]]) - e = matrix([[1] * (2*m)]) + e = matrix([[1] * (2 * m)]) one = matrix([1]) - H = block_matrix([[ one, -e, one, e, one, e, one, e], - [-e.T, T(0, 0), e.T, T(0, 1), e.T, T(0, 2), e.T, T(0, 3)], - [-one, -e, one, -e, one, e, -one, -e], - [-e.T, -T(1, 0), -e.T, T(1, 1), e.T, T(1, 2), -e.T, -T(1, 3)], - [-one, -e, -one, -e, one, -e, one, e], - [-e.T, -T(2, 0), -e.T, -T(2, 1), -e.T, T(2, 2), e.T, T(2, 3)], - [-one, -e, one, e, -one, -e, one, -e], - [-e.T, -T(3, 0), e.T, T(3, 1), -e.T, -T(3, 2), -e.T, T(3, 3)]]) + H = block_matrix([[one, -e, one, e, one, e, one, e], [-e.T, T(0, 0), e.T, T(0, 1), e.T, T(0, 2), e.T, T(0, 3)], [-one, -e, one, -e, one, e, -one, -e], [-e.T, -T(1, 0), -e.T, T(1, 1), e.T, T(1, 2), -e.T, -T(1, 3)], [-one, -e, -one, -e, one, -e, one, e], [-e.T, -T(2, 0), -e.T, -T(2, 1), -e.T, T(2, 2), e.T, T(2, 3)], [-one, -e, one, e, -one, -e, one, -e], [-e.T, -T(3, 0), e.T, T(3, 1), -e.T, -T(3, 2), -e.T, T(3, 3)]]) if check: assert is_hadamard_matrix(H) @@ -563,12 +540,9 @@ def hadamard_matrix_williamson_type(a, b, c, d, check=True): n = len(a) assert len(a) == len(b) == len(c) == len(d) - assert A*A.T+B*B.T+C*C.T+D*D.T == 4*n*I(n) + assert A * A.T + B * B.T + C * C.T + D * D.T == 4 * n * I(n) - M = block_matrix([[ A, B, C, D], - [-B, A, -D, C], - [-C, D, A, -B], - [-D, -C, B, A]]) + M = block_matrix([[A, B, C, D], [-B, A, -D, C], [-C, D, A, -B], [-D, -C, B, A]]) if check: assert is_hadamard_matrix(M, normalized=False, skew=False) return M @@ -625,48 +599,27 @@ def williamson_type_quadruples_smallcases(n, existence=False): 9: ('+---++---', '+--+--+--', '+-+----+-', '++------+'), 11: ('++--------+', '++-+-++-+-+', '++-++--++-+', '+-++----++-'), 13: ('++++-+--+-+++', '+---+-++-+---', '++---+--+---+', '++---+--+---+'), - 15: ('+-+---++++---+-', '++-++------++-+', - '++-++++--++++-+', '++-++-+--+-++-+'), - 17: ('+---+++----+++---', '++-+---+--+---+-+', - '+--+-++++++++-+--', '+-++-+++--+++-++-'), - 19: ('++--+++-+--+-+++--+', '++-++--+-++-+--++-+', - '+-+---++++++++---+-', '++--+-++++++++-+--+'), - 21: ('+--++++---++---++++--', '++++-+---+--+---+-+++', - '++--+-+-++--++-+-+--+', '++-+++++-+--+-+++++-+'), - 23: ('++---+---+-++-+---+---+', '+-++-++--++++++--++-++-', - '+++---++-+-++-+-++---++', '+++-+++-+------+-+++-++'), - 25: ('++++-+-+-+--++--+-+-+-+++', '++--+--+-++++++++-+--+--+', - '+++--+--++++--++++--+--++', '+-+--+++--++++++--+++--+-'), - 27: ('+--+--+-+++--++--+++-+--+--', '+++-++-+---++--++---+-++-++', - '+---+++++-+-++++-+-+++++---', '+---+++++-+-++++-+-+++++---'), - 29: ('+++---++--+-+----+-+--++---++', '+-+---++--+-++++++-+--++---+-', - '++++-++-+---++++++---+-++-+++', '++--+--+-+++-++++-+++-+--+--+'), - 31: ('++++++-+--+---++++---+--+-+++++', '+--++---+-+-++----++-+-+---++--', - '+--++---+-+-++----++-+-+---++--', '+-----+-++-+++----+++-++-+-----'), - 33: ('++++++-+-+-+++------+++-+-+-+++++', '++-+-++-+----+++--+++----+-++-+-+', - '++--++-+++-+--+-++-+--+-+++-++--+', '+--++--+++++-++----++-+++++--++--'), - 37: ('+--+-+-+-++---+--++++--+---++-+-+-+--', '+---++-++--+-+-++----++-+-+--++-++---', - '+++++-+-----++----++----++-----+-++++', '+--+++-+-----+----++----+-----+-+++--'), - 39: ('+++--+-+-----+--++----++--+-----+-+--++', '+++--++-+---+-+--+----+--+-+---+-++--++', - '++++---+--++----+-+--+-+----++--+---+++', '+---++-+-+-----+++-++-+++-----+-+-++---'), - 41: ('++++--+-++++-++--++----++--++-++++-+--+++', '++++--+-++++-++--++----++--++-++++-+--+++', - '+++-++-+-+-+-----+++--+++-----+-+-+-++-++', '+--+--+-+-+-+++++---++---+++++-+-+-+--+--'), - 43: ('++---++++-+--+--++--------++--+--+-++++---+', '+++-+-++--+-+-++++-+----+-++++-+-+--++-+-++', - '++-++++++----+-+--++-++-++--+-+----++++++-+', '+---++--++++-+-+++-++--++-+++-+-++++--++---'), - 45: ('+++++-++----+-++--++-++-++--++-+----++-++++', '+++---++--+-+-+-++--------++-+-+-+--++---++', - '++-+-++++-+--+--+++--++--+++--+--+-++++-+-+', '+-++-----++++-+-+++-++++-+++-+-++++-----++-'), - 49: ('++++-++-+---++-+++---++-++-++---+++-++---+-++-+++', '++++-++-+---++-+++---++-++-++---+++-++---+-++-+++', - '+----+-++++--+-+++-+-+++--+++-+-+++-+--++++-+----', '+++++-+----++-+---+-+---++---+-+---+-++----+-++++'), - 51: ('+---+++-++-+-+++--+++++--++--+++++--+++-+-++-+++---', '----+++-++-+-+++--+++++--++--+++++--+++-+-++-+++---', - '-+--+----+-+++-+-+++++--+--+--+++++-+-+++-+----+--+', '-+--+----+-+++-+-+++++--+--+--+++++-+-+++-+----+--+'), - 55: ('+-+--+-+-++--+-+++++-+++--++++--+++-+++++-+--++-+-+--+-', '--+--+-+-++--+-+++++-+++--++++--+++-+++++-+--++-+-+--+-', - '+++----++-++--++----+-+-++++++++-+-+----++--++-++----++', '+++----++-++--++----+-+-++++++++-+-+----++--++-++----++'), - 57: ('+---++-+--++++-+++-++---+-++++++-+---++-+++-++++--+-++---', '----++-+--++++-+++-++---+-++++++-+---++-+++-++++--+-++---', - '--+-+-+++--+--+-++---+++++-++++-+++++---++-+--+--+++-+-+-', '--+-+-+++--+--+-++---+++++-++++-+++++---++-+--+--+++-+-+-'), - 61: ('++--+--++--+-+-++++--+-----+------+-----+--++++-+-+--++--+--+', '++--+--++--+-+-++++--+-----+------+-----+--++++-+-+--++--+--+', - '+---+-+-++++---++--+-++-+---++++++---+-++-+--++---++++-+-+---', '++++-+-+----+++--++-+--+-+++------+++-+--+-++--+++----+-+-+++'), - 63: ('++-+++--++-++--+--+-++-+-+++--------+++-+-++-+--+--++-++--+++-+', '-+-+++--++-++--+--+-++-+-+++--------+++-+-++-+--+--++-++--+++-+', - '++++-++-+-++++-+---+---+++---++++++---+++---+---+-++++-+-++-+++', '++++-++-+-++++-+---+---+++---++++++---+++---+---+-++++-+-++-+++'), + 15: ('+-+---++++---+-', '++-++------++-+', '++-++++--++++-+', '++-++-+--+-++-+'), + 17: ('+---+++----+++---', '++-+---+--+---+-+', '+--+-++++++++-+--', '+-++-+++--+++-++-'), + 19: ('++--+++-+--+-+++--+', '++-++--+-++-+--++-+', '+-+---++++++++---+-', '++--+-++++++++-+--+'), + 21: ('+--++++---++---++++--', '++++-+---+--+---+-+++', '++--+-+-++--++-+-+--+', '++-+++++-+--+-+++++-+'), + 23: ('++---+---+-++-+---+---+', '+-++-++--++++++--++-++-', '+++---++-+-++-+-++---++', '+++-+++-+------+-+++-++'), + 25: ('++++-+-+-+--++--+-+-+-+++', '++--+--+-++++++++-+--+--+', '+++--+--++++--++++--+--++', '+-+--+++--++++++--+++--+-'), + 27: ('+--+--+-+++--++--+++-+--+--', '+++-++-+---++--++---+-++-++', '+---+++++-+-++++-+-+++++---', '+---+++++-+-++++-+-+++++---'), + 29: ('+++---++--+-+----+-+--++---++', '+-+---++--+-++++++-+--++---+-', '++++-++-+---++++++---+-++-+++', '++--+--+-+++-++++-+++-+--+--+'), + 31: ('++++++-+--+---++++---+--+-+++++', '+--++---+-+-++----++-+-+---++--', '+--++---+-+-++----++-+-+---++--', '+-----+-++-+++----+++-++-+-----'), + 33: ('++++++-+-+-+++------+++-+-+-+++++', '++-+-++-+----+++--+++----+-++-+-+', '++--++-+++-+--+-++-+--+-+++-++--+', '+--++--+++++-++----++-+++++--++--'), + 37: ('+--+-+-+-++---+--++++--+---++-+-+-+--', '+---++-++--+-+-++----++-+-+--++-++---', '+++++-+-----++----++----++-----+-++++', '+--+++-+-----+----++----+-----+-+++--'), + 39: ('+++--+-+-----+--++----++--+-----+-+--++', '+++--++-+---+-+--+----+--+-+---+-++--++', '++++---+--++----+-+--+-+----++--+---+++', '+---++-+-+-----+++-++-+++-----+-+-++---'), + 41: ('++++--+-++++-++--++----++--++-++++-+--+++', '++++--+-++++-++--++----++--++-++++-+--+++', '+++-++-+-+-+-----+++--+++-----+-+-+-++-++', '+--+--+-+-+-+++++---++---+++++-+-+-+--+--'), + 43: ('++---++++-+--+--++--------++--+--+-++++---+', '+++-+-++--+-+-++++-+----+-++++-+-+--++-+-++', '++-++++++----+-+--++-++-++--+-+----++++++-+', '+---++--++++-+-+++-++--++-+++-+-++++--++---'), + 45: ('+++++-++----+-++--++-++-++--++-+----++-++++', '+++---++--+-+-+-++--------++-+-+-+--++---++', '++-+-++++-+--+--+++--++--+++--+--+-++++-+-+', '+-++-----++++-+-+++-++++-+++-+-++++-----++-'), + 49: ('++++-++-+---++-+++---++-++-++---+++-++---+-++-+++', '++++-++-+---++-+++---++-++-++---+++-++---+-++-+++', '+----+-++++--+-+++-+-+++--+++-+-+++-+--++++-+----', '+++++-+----++-+---+-+---++---+-+---+-++----+-++++'), + 51: ('+---+++-++-+-+++--+++++--++--+++++--+++-+-++-+++---', '----+++-++-+-+++--+++++--++--+++++--+++-+-++-+++---', '-+--+----+-+++-+-+++++--+--+--+++++-+-+++-+----+--+', '-+--+----+-+++-+-+++++--+--+--+++++-+-+++-+----+--+'), + 55: ('+-+--+-+-++--+-+++++-+++--++++--+++-+++++-+--++-+-+--+-', '--+--+-+-++--+-+++++-+++--++++--+++-+++++-+--++-+-+--+-', '+++----++-++--++----+-+-++++++++-+-+----++--++-++----++', '+++----++-++--++----+-+-++++++++-+-+----++--++-++----++'), + 57: ('+---++-+--++++-+++-++---+-++++++-+---++-+++-++++--+-++---', '----++-+--++++-+++-++---+-++++++-+---++-+++-++++--+-++---', '--+-+-+++--+--+-++---+++++-++++-+++++---++-+--+--+++-+-+-', '--+-+-+++--+--+-++---+++++-++++-+++++---++-+--+--+++-+-+-'), + 61: ('++--+--++--+-+-++++--+-----+------+-----+--++++-+-+--++--+--+', '++--+--++--+-+-++++--+-----+------+-----+--++++-+-+--++--+--+', '+---+-+-++++---++--+-++-+---++++++---+-++-+--++---++++-+-+---', '++++-+-+----+++--++-+--+-+++------+++-+--+-++--+++----+-+-+++'), + 63: ('++-+++--++-++--+--+-++-+-+++--------+++-+-++-+--+--++-++--+++-+', '-+-+++--++-++--+--+-++-+-+++--------+++-+-++-+--+--++-++--+++-+', '++++-++-+-++++-+---+---+++---++++++---+++---+---+-++++-+-++-+++', '++++-++-+-++++-+---+---+++---++++++---+++---+---+-++++-+-++-+++'), } def pmtoZ(s): @@ -720,7 +673,7 @@ def williamson_hadamard_matrix_smallcases(n, existence=False, check=True): if existence: return True - a, b, c, d = williamson_type_quadruples_smallcases(n//4) + a, b, c, d = williamson_type_quadruples_smallcases(n // 4) return hadamard_matrix_williamson_type(a, b, c, d, check=check) @@ -747,18 +700,7 @@ def hadamard_matrix_156(): A, B, C, D = map(matrix.circulant, [a, b, c, d]) - return block_matrix([[ A, A, A, B, -B, C, -C, -D, B, C, -D, -D], - [ A, -A, B, -A, -B, -D, D, -C, -B, -D, -C, -C], - [ A, -B, -A, A, -D, D, -B, B, -C, -D, C, -C], - [ B, A, -A, -A, D, D, D, C, C, -B, -B, -C], - [ B, -D, D, D, A, A, A, C, -C, B, -C, B], - [ B, C, -D, D, A, -A, C, -A, -D, C, B, -B], - [ D, -C, B, -B, A, -C, -A, A, B, C, D, -D], - [-C, -D, -C, -D, C, A, -A, -A, -D, B, -B, -B], - [ D, -C, -B, -B, -B, C, C, -D, A, A, A, D], - [-D, -B, C, C, C, B, B, -D, A, -A, D, -A], - [ C, -B, -C, C, D, -B, -D, -B, A, -D, -A, A], - [-C, -D, -D, C, -C, -B, B, B, D, A, -A, -A]]) + return block_matrix([[A, A, A, B, -B, C, -C, -D, B, C, -D, -D], [A, -A, B, -A, -B, -D, D, -C, -B, -D, -C, -C], [A, -B, -A, A, -D, D, -B, B, -C, -D, C, -C], [B, A, -A, -A, D, D, D, C, C, -B, -B, -C], [B, -D, D, D, A, A, A, C, -C, B, -C, B], [B, C, -D, D, A, -A, C, -A, -D, C, B, -B], [D, -C, B, -B, A, -C, -A, A, B, C, D, -D], [-C, -D, -C, -D, C, A, -A, -A, -D, B, -B, -B], [D, -C, -B, -B, -B, C, C, -D, A, A, A, D], [-D, -B, C, C, C, B, B, -D, A, -A, D, -A], [C, -B, -C, C, D, -B, -D, -B, A, -D, -A, A], [-C, -D, -D, C, -C, -B, B, B, D, A, -A, -A]]) def construction_four_symbol_delta_code_I(X, Y, Z, W): @@ -816,10 +758,11 @@ def construction_four_symbol_delta_code_I(X, Y, Z, W): AssertionError """ n = len(X) - assert len(Y) == n and len(Z) == n-1 and len(W) == n-1 + assert len(Y) == n and len(Z) == n - 1 and len(W) == n - 1 def autocorrelation(seq, j): - return sum([seq[i]*seq[i+j] for i in range(len(seq)-j)]) + return sum([seq[i] * seq[i + j] for i in range(len(seq) - j)]) + for j in range(1, n): assert sum(autocorrelation(seq, j) for seq in [X, Y, Z, W]) == 0 @@ -889,16 +832,16 @@ def construction_four_symbol_delta_code_II(X, Y, Z, W): """ n = len(Z) - assert len(X) == n+1 and len(Y) == n+1 and len(W) == n + assert len(X) == n + 1 and len(Y) == n + 1 and len(W) == n def autocorrelation(seq, j): - return sum([seq[i]*seq[i+j] for i in range(len(seq)-j)]) + return sum([seq[i] * seq[i + j] for i in range(len(seq) - j)]) for j in range(1, n): assert sum(autocorrelation(seq, j) for seq in [X, Y, Z, W]) == 0 def alternate(seq1, seq2): - return [seq1[i//2] if i % 2 == 0 else seq2[(i-1)//2] for i in range(len(seq1)+len(seq2))] + return [seq1[i // 2] if i % 2 == 0 else seq2[(i - 1) // 2] for i in range(len(seq1) + len(seq2))] XaltZ = alternate(X, Z) Wneg = [-w for w in W] @@ -942,24 +885,18 @@ def four_symbol_delta_code_smallcases(n, existence=False): sage: four_symbol_delta_code_smallcases(17, existence=True) False """ - db = { - 1: ([1, -1], [1, 1], [1], [1]), - 14: ([1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1], - [1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1], - [1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1], - [1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1]) - } + db = {1: ([1, -1], [1, 1], [1], [1]), 14: ([1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1], [1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1], [1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1], [1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1])} T1, T2, T3, T4 = None, None, None, None - if n % 2 == 1 and (n-1)//2 in db: + if n % 2 == 1 and (n - 1) // 2 in db: if existence: return True - X, Y, Z, W = db[(n-1)//2] + X, Y, Z, W = db[(n - 1) // 2] T1, T2, T3, T4 = construction_four_symbol_delta_code_I(X, Y, Z, W) - elif n % 4 == 3 and (n-3) // 4 in db: + elif n % 4 == 3 and (n - 3) // 4 in db: if existence: return True - X, Y, Z, W = db[(n-3)//4] + X, Y, Z, W = db[(n - 3) // 4] T1, T2, T3, T4 = construction_four_symbol_delta_code_II(X, Y, Z, W) if existence: @@ -1018,11 +955,8 @@ def _construction_goethals_seidel_matrix(A, B, C, D): [-1 1| 1 -1| 1 -1| 1 1] """ n = len(A[0]) - R = matrix(ZZ, n, n, lambda i, j: 1 if i+j == n-1 else 0) - return block_matrix([[ A, B*R, C*R, D*R], - [-B*R, A, -D.T*R, C.T*R], - [-C*R, D.T*R, A, -B.T*R], - [-D*R, -C.T*R, B.T*R, A]]) + R = matrix(ZZ, n, n, lambda i, j: 1 if i + j == n - 1 else 0) + return block_matrix([[A, B * R, C * R, D * R], [-B * R, A, -D.T * R, C.T * R], [-C * R, D.T * R, A, -B.T * R], [-D * R, -C.T * R, B.T * R, A]]) def hadamard_matrix_from_sds(n, existence=False, check=True): @@ -1103,7 +1037,7 @@ def hadamard_matrix_from_sds(n, existence=False, check=True): A, B, C, D = map(matrix.circulant, [a, b, c, d]) if check: - assert A*A.T+B*B.T+C*C.T+D*D.T == 4*t*I(t) + assert A * A.T + B * B.T + C * C.T + D * D.T == 4 * t * I(t) H = _construction_goethals_seidel_matrix(A, B, C, D) if check: @@ -1169,17 +1103,17 @@ def hadamard_matrix_cooper_wallis_construction(x1, x2, x3, x4, A, B, C, D, check matrices = [X1, X2, X3, X4] for i in range(4): - for j in range(i+1, 4): + for j in range(i + 1, 4): assert matrices[i].elementwise_product(matrices[j]) == zero_matrix(n) - assert X1*X1.T + X2*X2.T + X3*X3.T + X4*X4.T == n*I(n) + assert X1 * X1.T + X2 * X2.T + X3 * X3.T + X4 * X4.T == n * I(n) m = len(A[0]) assert m == len(B[0]) == len(C[0]) == len(D[0]) will_matrices = [A, B, C, D] for i in range(4): - for j in range(i+1, 4): - assert will_matrices[i]*will_matrices[j].T == will_matrices[j]*will_matrices[i].T - assert A*A.T + B*B.T + C*C.T + D*D.T == 4*m*I(m) + for j in range(i + 1, 4): + assert will_matrices[i] * will_matrices[j].T == will_matrices[j] * will_matrices[i].T + assert A * A.T + B * B.T + C * C.T + D * D.T == 4 * m * I(m) e1 = _construction_goethals_seidel_matrix(X1, X2, X3, X4) e2 = _construction_goethals_seidel_matrix(X2, -X1, X4, -X3) @@ -1253,17 +1187,10 @@ def hadamard_matrix_cooper_wallis_smallcases(n, check=True, existence=False): """ assert n % 4 == 0 and n > 0 - db = { - 67: ( - [1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, -1, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, -1, 0, 1, -1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], - [0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 1, 0, 0, -1, -1, -1, 0, 0, 0, 0, 0, -1, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0], - [0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, -1, 0, 0, 1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, -1, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -1, 1, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, 1, 0, 0, 0] - ) - } + db = {67: ([1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, -1, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, -1, 0, 1, -1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 1, 0, 0, -1, -1, -1, 0, 0, 0, 0, 0, -1, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, -1, 0, 0, 1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 1, 0, 0, 0, 0, 0, 0], [0, 0, -1, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -1, 1, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, 1, 0, 0, 0])} - for T_seq_len in divisors(n//4): - will_size = n // (4*T_seq_len) + for T_seq_len in divisors(n // 4): + will_size = n // (4 * T_seq_len) if (T_seq_len in db or T_sequences_smallcases(T_seq_len, existence=True)) and williamson_type_quadruples_smallcases(will_size, existence=True): if existence: return True @@ -1334,7 +1261,7 @@ def _get_baumert_hall_units(n, existence=False): """ assert n % 4 == 0 and n > 0 - delta_codes_len = n//4 + delta_codes_len = n // 4 if not four_symbol_delta_code_smallcases(delta_codes_len, existence=True): if existence: return False @@ -1349,10 +1276,10 @@ def _get_baumert_hall_units(n, existence=False): M3 = matrix.circulant(T3) M4 = matrix.circulant(T4) - M1hat = matrix(ZZ, 0.25*(M1+M2+M3+M4)) - M2hat = matrix(ZZ, 0.25*(M1-M2-M3+M4)) - M3hat = matrix(ZZ, 0.25*(M1+M2-M3-M4)) - M4hat = matrix(ZZ, 0.25*(M1-M2+M3-M4)) + M1hat = matrix(ZZ, 0.25 * (M1 + M2 + M3 + M4)) + M2hat = matrix(ZZ, 0.25 * (M1 - M2 - M3 + M4)) + M3hat = matrix(ZZ, 0.25 * (M1 + M2 - M3 - M4)) + M4hat = matrix(ZZ, 0.25 * (M1 - M2 + M3 - M4)) e1 = _construction_goethals_seidel_matrix(M1hat, -M2hat, -M3hat, -M4hat) e2 = _construction_goethals_seidel_matrix(M2hat, M1hat, M4hat, -M3hat) @@ -1409,7 +1336,7 @@ def hadamard_matrix_turyn_type(a, b, c, d, e1, e2, e3, e4, check=True): n = len(a) assert len(a) == len(b) == len(c) == len(d) - assert A*A.T+B*B.T+C*C.T+D*D.T == 4*n*I(n) + assert A * A.T + B * B.T + C * C.T + D * D.T == 4 * n * I(n) t4 = len(e1[0]) assert t4 % 4 == 0 @@ -1420,12 +1347,12 @@ def hadamard_matrix_turyn_type(a, b, c, d, e1, e2, e3, e4, check=True): for j in range(t4): assert abs(e1[i, j]) + abs(e2[i, j]) + abs(e3[i, j]) + abs(e4[i, j]) == 1 - assert e1*e1.T == t*I(t4) and e2*e2.T == t*I(t4) and e3*e3.T == t*I(t4) and e4*e4.T == t*I(t4) + assert e1 * e1.T == t * I(t4) and e2 * e2.T == t * I(t4) and e3 * e3.T == t * I(t4) and e4 * e4.T == t * I(t4) units = [e1, e2, e3, e4] for i in range(len(units)): - for j in range(i+1, len(units)): - assert units[i]*units[j].T + units[j]*units[i].T == 0*I(t4) + for j in range(i + 1, len(units)): + assert units[i] * units[j].T + units[j] * units[i].T == 0 * I(t4) H = e1.tensor_product(A) + e2.tensor_product(B) + e3.tensor_product(C) + e4.tensor_product(D) if check: @@ -1472,9 +1399,9 @@ def turyn_type_hadamard_matrix_smallcases(n, existence=False, check=True): """ assert n % 4 == 0 and n > 0 - for delta_code_len in divisors(n//4): - units_size = delta_code_len*4 - will_size = n//units_size + for delta_code_len in divisors(n // 4): + units_size = delta_code_len * 4 + will_size = n // units_size if _get_baumert_hall_units(units_size, existence=True) and williamson_type_quadruples_smallcases(will_size, existence=True): if existence: return True @@ -1545,7 +1472,7 @@ def hadamard_matrix_spence_construction(n, existence=False, check=True): assert n % 4 == 0 and n > 0 - q = n//4 + q = n // 4 if existence: return supplementary_difference_set_from_rel_diff_set(q, existence=True) @@ -1561,19 +1488,12 @@ def hadamard_matrix_spence_construction(n, existence=False, check=True): A3 = matrix.circulant([1 if j in S3 else -1 for j in Glist]) A4 = matrix.circulant([1 if j in S2 else -1 for j in Glist]) - P = matrix(ZZ, [[1 if (i + j) % (q-1) == 0 else 0 for i in range(1, q)] for j in range(1, q)]) + P = matrix(ZZ, [[1 if (i + j) % (q - 1) == 0 else 0 for i in range(1, q)] for j in range(1, q)]) - e = matrix([1]*(q-1)) + e = matrix([1] * (q - 1)) m1 = matrix([-1]) p1 = matrix([1]) - H = block_matrix([[ p1, m1, p1, p1, e, e, e, e], - [ p1, p1, m1, p1, -e, e, -e, e], - [ m1, p1, p1, p1, -e, e, e, -e], - [ m1, m1, m1, p1, -e, -e, e, e], - [-e.T, e.T, e.T, -e.T, A1, A2*P, A3*P, A4*P], - [-e.T, -e.T, e.T, e.T, -A2*P, A1, -A4.T*P, A3.T*P], - [-e.T, -e.T, -e.T, -e.T, -A3*P, A4.T*P, A1, -A2.T*P], - [ e.T, -e.T, e.T, -e.T, -A4*P, -A3.T*P, A2.T*P, A1]]) + H = block_matrix([[p1, m1, p1, p1, e, e, e, e], [p1, p1, m1, p1, -e, e, -e, e], [m1, p1, p1, p1, -e, e, e, -e], [m1, m1, m1, p1, -e, -e, e, e], [-e.T, e.T, e.T, -e.T, A1, A2 * P, A3 * P, A4 * P], [-e.T, -e.T, e.T, e.T, -A2 * P, A1, -A4.T * P, A3.T * P], [-e.T, -e.T, -e.T, -e.T, -A3 * P, A4.T * P, A1, -A2.T * P], [e.T, -e.T, e.T, -e.T, -A4 * P, -A3.T * P, A2.T * P, A1]]) if check: assert is_hadamard_matrix(H, verbose=True) @@ -1655,13 +1575,13 @@ def is_hadamard_matrix(M, normalized=False, skew=False, verbose=False): for r in M: for v in r: - if v*v != 1: + if v * v != 1: if verbose: print("The matrix does not only contain +1 and -1 entries, e.g. " + str(v)) return False - prod = (M*M.transpose()).dict() - if (len(prod) != n or set(prod.values()) != {n} or any((i, i) not in prod for i in range(n))): + prod = (M * M.transpose()).dict() + if len(prod) != n or set(prod.values()) != {n} or any((i, i) not in prod for i in range(n)): if verbose: print("The product M*M.transpose() is not equal to nI") return False @@ -1677,8 +1597,8 @@ def is_hadamard_matrix(M, normalized=False, skew=False, verbose=False): return False if skew: - for i in range(n-1): - for j in range(i+1, n): + for i in range(n - 1): + for j in range(i + 1, n): if M[i, j] != -M[j, i]: if verbose: print("The matrix is not skew") @@ -1821,9 +1741,12 @@ def hadamard_matrix(n, existence=False, check=True, construction_name=False): """ name = str(n) if construction_name: + def report_name(nam): return nam + else: + def report_name(nam): return True @@ -1839,21 +1762,20 @@ def report_name(nam): if existence: return report_name(name) M = matrix([1]) - elif is_prime_power(n//2 - 1) and (n//2 - 1) % 4 == 1: + elif is_prime_power(n // 2 - 1) and (n // 2 - 1) % 4 == 1: name = "paleyII " + name if existence: return report_name(name) M = hadamard_matrix_paleyII(n) - elif n == 4 or n % 8 == 0 and hadamard_matrix(n//2, existence=True) is True: + elif n == 4 or n % 8 == 0 and hadamard_matrix(n // 2, existence=True) is True: name = "doubling " + name if existence: return report_name(name) - had = hadamard_matrix(n//2, check=False) + had = hadamard_matrix(n // 2, check=False) chad1 = matrix([list(r) + list(r) for r in had.rows()]) mhad = (-1) * had R = len(had.rows()) - chad2 = matrix([list(had.rows()[i]) + list(mhad.rows()[i]) - for i in range(R)]) + chad2 = matrix([list(had.rows()[i]) + list(mhad.rows()[i]) for i in range(R)]) M = chad1.stack(chad2) elif is_prime_power(n - 1) and (n - 1) % 4 == 3: name = "paleyI " + name @@ -2067,63 +1989,54 @@ def true(): if existence: return true() if e == 1: - M = J(4)-2*matrix(4, [[int(i+j == 3) for i in range(4)] for j in range(4)]) + M = J(4) - 2 * matrix(4, [[int(i + j == 3) for i in range(4)] for j in range(4)]) else: - M = -J(4)+2*I(4) + M = -J(4) + 2 * I(4) elif n == 36: if existence: return true() if e == 1: M = strongly_regular_graph(36, 15, 6, 6).adjacency_matrix() - M = J(36) - 2*M + M = J(36) - 2 * M else: M = strongly_regular_graph(36, 14, 4, 6).adjacency_matrix() - M = -J(36) + 2*M + 2*I(36) + M = -J(36) + 2 * M + 2 * I(36) elif n == 100: if existence: return true() if e == -1: M = strongly_regular_graph(100, 44, 18, 20).adjacency_matrix() - M = 2*M - J(100) + 2*I(100) + M = 2 * M - J(100) + 2 * I(100) else: M = strongly_regular_graph(100, 45, 20, 20).adjacency_matrix() - M = J(100) - 2*M + M = J(100) - 2 * M elif n == 196 and e == 1: if existence: return true() M = strongly_regular_graph(196, 91, 42, 42).adjacency_matrix() - M = J(196) - 2*M + M = J(196) - 2 * M elif n == 324: if existence: return true() M = RSHCD_324(e) - elif (e == 1 and - n % 16 == 0 and - sqn is not None and - is_prime_power(sqn - 1) and - is_prime_power(sqn + 1)): + elif e == 1 and n % 16 == 0 and sqn is not None and is_prime_power(sqn - 1) and is_prime_power(sqn + 1): if existence: return true() M = -rshcd_from_close_prime_powers(sqn) - elif (e == 1 and - sqn is not None and - sqn % 4 == 2 and - strongly_regular_graph(sqn-1, (sqn-2)//2, (sqn-6)//4, - existence=True) is True and - is_prime_power(ZZ(sqn + 1))): + elif e == 1 and sqn is not None and sqn % 4 == 2 and strongly_regular_graph(sqn - 1, (sqn - 2) // 2, (sqn - 6) // 4, existence=True) is True and is_prime_power(ZZ(sqn + 1)): if existence: return true() - M = rshcd_from_prime_power_and_conference_matrix(sqn+1) + M = rshcd_from_prime_power_and_conference_matrix(sqn + 1) # Recursive construction: the Kronecker product of two RSHCD is a RSHCD else: from itertools import product + for n1, e1 in product(divisors(n)[1:-1], [-1, 1]): - e2 = e1*e - n2 = n//n1 - if (regular_symmetric_hadamard_matrix_with_constant_diagonal(n1, e1, existence=True) is True and - regular_symmetric_hadamard_matrix_with_constant_diagonal(n2, e2, existence=True)) is True: + e2 = e1 * e + n2 = n // n1 + if (regular_symmetric_hadamard_matrix_with_constant_diagonal(n1, e1, existence=True) is True and regular_symmetric_hadamard_matrix_with_constant_diagonal(n2, e2, existence=True)) is True: if existence: return true() M1 = regular_symmetric_hadamard_matrix_with_constant_diagonal(n1, e1) @@ -2133,13 +2046,14 @@ def true(): if M is None: from sage.misc.unknown import Unknown + _rshcd_cache[n, e] = Unknown if existence: return Unknown raise ValueError("I do not know how to build a {}-RSHCD".format((n, e))) - assert M*M.transpose() == n*I(n) - assert set(map(sum, M)) == {ZZ(e*sqn)} + assert M * M.transpose() == n * I(n) + assert set(map(sum, M)) == {ZZ(e * sqn)} return M @@ -2187,8 +2101,9 @@ def RSHCD_324(e): - [CP2016]_ """ from sage.graphs.generators.smallgraphs import JankoKharaghaniTonchevGraph as JKTG + M = JKTG().adjacency_matrix() - M = J(324) - 2*M + M = J(324) - 2 * M if e == -1: M1 = M[:162].T M2 = M[162:].T @@ -2260,6 +2175,7 @@ def _helper_payley_matrix(n, zero_position=True): [-1 1 -1 -1 -1 1 1 1 -1 1 0] """ from sage.rings.finite_rings.finite_field_constructor import FiniteField + K = FiniteField(n, prefix='x') # Order the elements of K in K_list @@ -2272,8 +2188,7 @@ def _helper_payley_matrix(n, zero_position=True): K_list[i + shift] = x K_list[-i - 1] = y - M = matrix(ZZ, n, n, [(1 if (x - y).is_square() else -1) - for x in K_list for y in K_list]) + M = matrix(ZZ, n, n, [(1 if (x - y).is_square() else -1) for x in K_list for y in K_list]) M -= I(n) assert (M * J(n)).is_zero() assert M * M.transpose() == n * I(n) - J(n) @@ -2327,21 +2242,21 @@ def rshcd_from_close_prime_powers(n): if n % 4: raise ValueError("n(={}) must be congruent to 0 mod 4") - a, b = sorted([n-1, n+1], key=lambda x: -x % 4) + a, b = sorted([n - 1, n + 1], key=lambda x: -x % 4) Sa = _helper_payley_matrix(a) Sb = _helper_payley_matrix(b) - U = matrix(a, [[int(i+j == a-1) for i in range(a)] for j in range(a)]) + U = matrix(a, [[int(i + j == a - 1) for i in range(a)] for j in range(a)]) - K = (U*Sa).tensor_product(Sb) + U.tensor_product(J(b)-I(b)) - J(a).tensor_product(I(b)) + K = (U * Sa).tensor_product(Sb) + U.tensor_product(J(b) - I(b)) - J(a).tensor_product(I(b)) - F = lambda x: diagonal_matrix([-(-1)**i for i in range(x)]) + F = lambda x: diagonal_matrix([-((-1) ** i) for i in range(x)]) G = block_diagonal_matrix([J(1), I(a).tensor_product(F(b))]) - e = matrix(a*b, [1]*(a*b)) + e = matrix(a * b, [1] * (a * b)) H = block_matrix(2, [-J(1), e.transpose(), e, K]) - HH = G*H*G + HH = G * H * G assert len(set(map(sum, HH))) == 1 - assert HH**2 == n**2*I(n**2) + assert HH**2 == n**2 * I(n**2) return HH @@ -2382,8 +2297,8 @@ def williamson_goethals_seidel_skew_hadamard_matrix(a, b, c, d, check=True): n = len(a) A, B, C, D = map(matrix.circulant, [a, b, c, d]) if check: - assert A*A.T+B*B.T+C*C.T+D*D.T == 4*n*I(n) - assert A+A.T == 2*I(n) + assert A * A.T + B * B.T + C * C.T + D * D.T == 4 * n * I(n) + assert A + A.T == 2 * I(n) M = _construction_goethals_seidel_matrix(A, B, C, D) if check: @@ -2432,19 +2347,19 @@ def skew_hadamard_matrix_spence_construction(n, check=True): ... ValueError: The order 16 is not covered by the Spence construction. """ - q = n//2 - 1 - m = (q+1)//2 + q = n // 2 - 1 + m = (q + 1) // 2 if n % 4 != 0 or not is_prime_power(q) or q % 8 != 5: raise ValueError(f'The order {n} is not covered by the Spence construction.') - G, D = relative_difference_set_from_homomorphism(q, 2, (q-1)//4, check=False, return_group=True) + G, D = relative_difference_set_from_homomorphism(q, 2, (q - 1) // 4, check=False, return_group=True) D_fixed = get_fixed_relative_difference_set(G, D) - D_union = D_fixed + [q+1+el for el in D_fixed] - D_union = list({el % (4*(q+1)) for el in D_union}) + D_union = D_fixed + [q + 1 + el for el in D_fixed] + D_union = list({el % (4 * (q + 1)) for el in D_union}) def find_a(i): for a in range(8): - if (a*(q+1)//2+i) % 8 == 0: + if (a * (q + 1) // 2 + i) % 8 == 0: return a ai = [find_a(0), find_a(1), find_a(2), find_a(3)] @@ -2467,7 +2382,7 @@ def find_a(i): for el in Ds[i]: psis[i] += P.monomial(el) - diffs = [(2*psis[i] - Tm).mod(P.monomial(m)-1) for i in range(4)] + diffs = [(2 * psis[i] - Tm).mod(P.monomial(m) - 1) for i in range(4)] a = [-el for el in diffs[1].coefficients()] b = diffs[0].coefficients() c = diffs[2].coefficients() @@ -2553,7 +2468,7 @@ def skew_hadamard_matrix_spence_1975(n, existence=False, check=True): return False raise ValueError('n is not in the form 4*(1+q+q^2)') - is_valid = (is_prime(m) and m % 8 in [3, 5, 7]) or is_prime_power(3 + 2*q + 2*q**2) + is_valid = (is_prime(m) and m % 8 in [3, 5, 7]) or is_prime_power(3 + 2 * q + 2 * q**2) if existence: return is_valid @@ -2580,7 +2495,7 @@ def get_fixed_set(s, G, q): if i in indices: continue indices.add(i) - for j in range(i+1, len(Dnot)): + for j in range(i + 1, len(Dnot)): if j not in indices and Dnot[i] % m == Dnot[j] % m: indices.add(j) D2.append(Dnot[i]) @@ -2648,37 +2563,28 @@ def pmtoZ(s): 36: ['+++-+-+--', '+-++--++-', '--++++++-', '+++-++-++'], 52: ['++++-++--+---', '-+-++----++-+', '--+-+++++-+++', '--+-+++++-+++'], 92: ['+-------++-+-+--+++++++', '++--+--++++--++++--+--+', '++---+-+-+-++-+-+-+---+', '+----+--+--++--+--+----'], - 188: ['+----+----++-+-+---++-++--+--+++-+-+--++++-++++', - '++--+---+------++------++-+-++--+-+-+----+---++', - '+-+-++---++-+---+++---++-++-++-++-+++++-+-+----', - '+++-++-+-+---+-+++++--+-----++---+--+++++--++-+'], - 236: ['+-+---+-+-++-++---+----++-----+++++--++++-+++--+--+-+-+++-+', - '+-+---+-+-++-++---+----++-----+++++--++++-+++--+--+-+-+++-+', - '+++-++----+++-+-+++--+--++------+---+-----+--+-+--+---+----', - '++++++--+++--+---++-+-+-+---+-+----++++-++-+--++-+--+------'], - 276: ['+--+++--+-+++--+---++-+++++-+++-++-+--+---+-----+--+++-++---+-++---++', - '+-++--+-+----++-+---++++-+---+-++++++++-+---+-++++---+-++----+-+--++-', - '--+--+-++---+--++--+-+-+++-+--++---++++-+-+-+--+-++-+++++++--+--+++++', - '-+---+++-----++---+++-+++--+++++--+---+-+-++++-++++-++-++-+-+++++++++'] + 188: ['+----+----++-+-+---++-++--+--+++-+-+--++++-++++', '++--+---+------++------++-+-++--+-+-+----+---++', '+-+-++---++-+---+++---++-++-++-++-+++++-+-+----', '+++-++-+-+---+-+++++--+-----++---+--+++++--++-+'], + 236: ['+-+---+-+-++-++---+----++-----+++++--++++-+++--+--+-+-+++-+', '+-+---+-+-++-++---+----++-----+++++--++++-+++--+--+-+-+++-+', '+++-++----+++-+-+++--+--++------+---+-----+--+-+--+---+----', '++++++--+++--+---++-+-+-+---+-+----++++-++-+--++-+--+------'], + 276: ['+--+++--+-+++--+---++-+++++-+++-++-+--+---+-----+--+++-++---+-++---++', '+-++--+-+----++-+---++++-+---+-++++++++-+---+-++++---+-++----+-+--++-', '--+--+-++---+--++--+-+-+++-+--++---++++-+-+-+--+-++-+++++++--+--+++++', '-+---+++-----++---+++-+++--+++++--+---+-+-++++-++++-++-++-+-+++++++++'], } if existence: - return n in db or skew_supplementary_difference_set(n//4, existence=True) + return n in db or skew_supplementary_difference_set(n // 4, existence=True) if n in db: a, b, c, d = map(pmtoZ, db[n]) return WGS(a, b, c, d, check=check) - if skew_supplementary_difference_set(n//4, existence=True): - t = n//4 + if skew_supplementary_difference_set(n // 4, existence=True): + t = n // 4 G, [S1, S2, S3, S4] = skew_supplementary_difference_set(t, check=False, return_group=True) Glist = list(G) - A = matrix([[-1 if y-x in S1 else +1 for y in Glist] for x in Glist]) - B = matrix([[-1 if y-x in S2 else +1 for y in Glist] for x in Glist]) - C = matrix([[-1 if y-x in S3 else +1 for y in Glist] for x in Glist]) - D = matrix([[-1 if y-x in S4 else +1 for y in Glist] for x in Glist]) + A = matrix([[-1 if y - x in S1 else +1 for y in Glist] for x in Glist]) + B = matrix([[-1 if y - x in S2 else +1 for y in Glist] for x in Glist]) + C = matrix([[-1 if y - x in S3 else +1 for y in Glist] for x in Glist]) + D = matrix([[-1 if y - x in S4 else +1 for y in Glist] for x in Glist]) H = _construction_goethals_seidel_matrix(A, B, C, D) if check: @@ -2743,20 +2649,17 @@ def skew_hadamard_matrix_from_orthogonal_design(n, existence=False, check=True): NotImplementedError: orthogonal designs for matrix of order 16 not yet implemented """ # We use value i to represent entries where variable x_i should be, and -i for -x_i - orthogonal_designs = { - (1, 1, 26): [[1, 3, 3, -3, 3, -3, -3], [2, 3, 3, -3, 3, -3, -3], - [3, 3, 3, -3, 3, 3, 3], [3, 3, -3, -3, -3, 3, -3]] - } + orthogonal_designs = {(1, 1, 26): [[1, 3, 3, -3, 3, -3, -3], [2, 3, 3, -3, 3, -3, -3], [3, 3, 3, -3, 3, 3, 3], [3, 3, -3, -3, -3, 3, -3]]} if n % 4 != 0: raise ValueError('n must be a multiple of 4') m1, m2 = None, None for d in divisors(n)[1:-1]: - if (n//d) % (d-1) != 0: + if (n // d) % (d - 1) != 0: continue - d1 = n // (d*(d - 1)) - if (1, d1, d1*d - d1 - 1) in orthogonal_designs and amicable_hadamard_matrices(d, existence=True): + d1 = n // (d * (d - 1)) + if (1, d1, d1 * d - d1 - 1) in orthogonal_designs and amicable_hadamard_matrices(d, existence=True): m1 = d1 m2 = d @@ -2775,7 +2678,7 @@ def skew_hadamard_matrix_from_orthogonal_design(n, existence=False, check=True): P = M[1:, 1:] - I(m2 - 1) D = N[1:, 1:] - A1, A2, A3, A4 = map(matrix.circulant, orthogonal_designs[(1, m1, m1*m2 - m1 - 1)]) + A1, A2, A3, A4 = map(matrix.circulant, orthogonal_designs[(1, m1, m1 * m2 - m1 - 1)]) OD = _construction_goethals_seidel_matrix(A1, A2, A3, A4) blocks = {1: P, -1: -P, 2: J(m2 - 1), -2: -J(m2 - 1), 3: D, -3: -D} @@ -2842,34 +2745,34 @@ def skew_hadamard_matrix_from_complementary_difference_sets(n, existence=False, if n <= 0 or (n > 2 and n % 4 != 0): raise ValueError('n must be 1, 2 or a multiple of four.') - m = n//4 - 1 + m = n // 4 - 1 if existence: - return complementary_difference_sets(2*m+1, existence=True) + return complementary_difference_sets(2 * m + 1, existence=True) - if not complementary_difference_sets(2*m+1, existence=True): + if not complementary_difference_sets(2 * m + 1, existence=True): raise NotImplementedError(f'hadamard matrix of order {n} from complementary difference sets is not implemented yet') - G, A, B = complementary_difference_sets(2*m+1, check=False) + G, A, B = complementary_difference_sets(2 * m + 1, check=False) - m = n//4 - 1 + m = n // 4 - 1 Glist = list(G) S = [[0 for i in range(n)] for j in range(n)] - for i in range(2*m + 1): - for j in range(2*m + 1): - S[2*m + 1 + i][2*m + 1 + j] = -1 if Glist[j] - Glist[i] in A else 1 - S[i][j] = -S[2*m + 1 + i][2*m + 1 + j] - S[2*m + 1 + j][i] = -1 if Glist[j] - Glist[i] in B else 1 - S[i][2*m + 1 + j] = -S[2*m + 1 + j][i] - S[4*m + 2][i] = -1 - S[4*m + 2][2*m + 1 + i] = 1 - S[i][4*m + 2] = 1 - S[i + 2*m + 1][4*m + 2] = -1 - for i in range(4*m + 3): - S[4*m + 3][i] = 1 - S[i][4*m + 3] = -1 - for i in range(4*m + 4): + for i in range(2 * m + 1): + for j in range(2 * m + 1): + S[2 * m + 1 + i][2 * m + 1 + j] = -1 if Glist[j] - Glist[i] in A else 1 + S[i][j] = -S[2 * m + 1 + i][2 * m + 1 + j] + S[2 * m + 1 + j][i] = -1 if Glist[j] - Glist[i] in B else 1 + S[i][2 * m + 1 + j] = -S[2 * m + 1 + j][i] + S[4 * m + 2][i] = -1 + S[4 * m + 2][2 * m + 1 + i] = 1 + S[i][4 * m + 2] = 1 + S[i + 2 * m + 1][4 * m + 2] = -1 + for i in range(4 * m + 3): + S[4 * m + 3][i] = 1 + S[i][4 * m + 3] = -1 + for i in range(4 * m + 4): S[i][i] = 1 H = matrix(S) @@ -2943,30 +2846,31 @@ def skew_hadamard_matrix_whiteman_construction(n, existence=False, check=True): raise ValueError(f'The order {n} is not covered by the Whiteman construction.') from sage.rings.finite_rings.finite_field_constructor import GF + G = GF(q) - f = (q-1) // 8 - Cs = {i: [G.gen()**(8*s+i) for s in range(f)] for i in [0, 1, 2, 3, 6, 7]} + f = (q - 1) // 8 + Cs = {i: [G.gen() ** (8 * s + i) for s in range(f)] for i in [0, 1, 2, 3, 6, 7]} A = Cs[0] + Cs[1] + Cs[2] + Cs[3] B = Cs[0] + Cs[1] + Cs[6] + Cs[7] - m = n//4 - 1 + m = n // 4 - 1 Glist = list(G) S = [[0 for i in range(n)] for j in range(n)] - for i in range(2*m + 1): - for j in range(2*m + 1): - S[2*m + 1 + i][2*m + 1 + j] = -1 if Glist[j] - Glist[i] in A else 1 - S[i][j] = -S[2*m + 1 + i][2*m + 1 + j] - S[2*m + 1 + j][i] = -1 if Glist[j] - Glist[i] in B else 1 - S[i][2*m + 1 + j] = -S[2*m + 1 + j][i] - S[4*m + 2][i] = -1 - S[4*m + 2][2*m + 1 + i] = 1 - S[i][4*m + 2] = 1 - S[i + 2*m + 1][4*m + 2] = -1 - for i in range(4*m + 3): - S[4*m + 3][i] = 1 - S[i][4*m + 3] = -1 - for i in range(4*m + 4): + for i in range(2 * m + 1): + for j in range(2 * m + 1): + S[2 * m + 1 + i][2 * m + 1 + j] = -1 if Glist[j] - Glist[i] in A else 1 + S[i][j] = -S[2 * m + 1 + i][2 * m + 1 + j] + S[2 * m + 1 + j][i] = -1 if Glist[j] - Glist[i] in B else 1 + S[i][2 * m + 1 + j] = -S[2 * m + 1 + j][i] + S[4 * m + 2][i] = -1 + S[4 * m + 2][2 * m + 1 + i] = 1 + S[i][4 * m + 2] = 1 + S[i + 2 * m + 1][4 * m + 2] = -1 + for i in range(4 * m + 3): + S[4 * m + 3][i] = 1 + S[i][4 * m + 3] = -1 + for i in range(4 * m + 4): S[i][i] = 1 H = matrix(S) @@ -3026,26 +2930,23 @@ def skew_hadamard_matrix_from_good_matrices(a, b, c, d, check=True): AssertionError """ n = len(a) - m = (n-1) // 2 + m = (n - 1) // 2 assert len(a) == len(b) == len(c) == len(d) assert a[0] == 1 and b[0] == 1 and c[0] == 1 and d[0] == 1 - for i in range(1, m+1): - assert a[i] == -a[n-i] and b[i] == b[n-i] and c[i] == c[n-i] and d[i] == d[n-i] + for i in range(1, m + 1): + assert a[i] == -a[n - i] and b[i] == b[n - i] and c[i] == c[n - i] and d[i] == d[n - i] def back_circulant(row): length = len(row) - return matrix([[row[(j+i) % length] for j in range(length)] for i in range(length)]) + return matrix([[row[(j + i) % length] for j in range(length)] for i in range(length)]) A = matrix.circulant(a) B = back_circulant(b) C = back_circulant(c) D = back_circulant(d) - H = block_matrix([[ A, B, C, D], - [-B, A, D, -C], - [-C, -D, A, B], - [-D, C, -B, A]]) + H = block_matrix([[A, B, C, D], [-B, A, D, -C], [-C, -D, A, B], [-D, C, -B, A]]) if check: assert is_hadamard_matrix(H, skew=True) @@ -3119,24 +3020,7 @@ def skew_hadamard_matrix_from_good_matrices_smallcases(n, existence=False, check sage: skew_hadamard_matrix_from_good_matrices_smallcases(14, existence=True) False """ - E_sequences = { - 0: ['', '', '', ''], - 1: ['+', '-', '-', '+'], - 2: ['++', '-+', '--', '--'], - 3: ['++-', '++-', '+-+', '-++'], - 4: ['+++-', '+-+-', '---+', '++-+'], - 5: ['+-+--', '+++--', '-+++-', '---+-'], - 6: ['+-+---', '---+++', '+-+--+', '----+-'], - 7: ['+++++--', '-++--++', '----+-+', '-+---+-'], - 8: ['+--++-+-', '+--+----', '++----+-', '+---+-+-'], - 9: ['-+-----++', '+-+++++--', '-+----++-', '--+-+-++-'], - 10: ['+--+++++++', '++--++++-+', '--++-+-+-+', '---+++-+-+'], - 11: ['++-+-------', '+----+--+--', '+-+--++---+', '--++-+-+-++'], - 12: ['+-----+-+---', '+-++++-+-++-', '---+--++++--', '--+-+++--+--'], - 13: ['+---+-+--++-+', '+++---++-++-+', '+++-+++-++---', '+---++++-+-+-'], - 14: ['+--+----+-+-++', '+---++++-++--+', '+-+----++-+--+', '++++++---+-+-+'], - 15: ['+--++----+---+-', '-++-+---+-+++--', '++---+--+--+++-', '-++++++++--+-+-'] - } + E_sequences = {0: ['', '', '', ''], 1: ['+', '-', '-', '+'], 2: ['++', '-+', '--', '--'], 3: ['++-', '++-', '+-+', '-++'], 4: ['+++-', '+-+-', '---+', '++-+'], 5: ['+-+--', '+++--', '-+++-', '---+-'], 6: ['+-+---', '---+++', '+-+--+', '----+-'], 7: ['+++++--', '-++--++', '----+-+', '-+---+-'], 8: ['+--++-+-', '+--+----', '++----+-', '+---+-+-'], 9: ['-+-----++', '+-+++++--', '-+----++-', '--+-+-++-'], 10: ['+--+++++++', '++--++++-+', '--++-+-+-+', '---+++-+-+'], 11: ['++-+-------', '+----+--+--', '+-+--++---+', '--++-+-+-++'], 12: ['+-----+-+---', '+-++++-+-++-', '---+--++++--', '--+-+++--+--'], 13: ['+---+-+--++-+', '+++---++-++-+', '+++-+++-++---', '+---++++-+-+-'], 14: ['+--+----+-+-++', '+---++++-++--+', '+-+----++-+--+', '++++++---+-+-+'], 15: ['+--++----+---+-', '-++-+---+-+++--', '++---+--+--+++-', '-++++++++--+-+-']} def pm_to_good_matrix(s, sign=1): e1 = [1 if x == '+' else -1 for x in s] @@ -3144,13 +3028,13 @@ def pm_to_good_matrix(s, sign=1): e2.reverse() return [1] + e1 + e2 - if not (n % 4 == 0 and (n//4) % 2 == 1): + if not (n % 4 == 0 and (n // 4) % 2 == 1): if existence: return False raise ValueError("The skew Hadamard matrix of order %s from good matrices does not exist." % n) - m = n//4 - l = (m-1) // 2 + m = n // 4 + l = (m - 1) // 2 if existence: return l in E_sequences @@ -3169,8 +3053,7 @@ def pm_to_good_matrix(s, sign=1): _skew_had_cache = {} -def skew_hadamard_matrix(n, existence=False, skew_normalize=True, check=True, - construction_name=False): +def skew_hadamard_matrix(n, existence=False, skew_normalize=True, check=True, construction_name=False): r""" Try to construct a skew Hadamard matrix. @@ -3260,8 +3143,9 @@ def skew_hadamard_matrix(n, existence=False, skew_normalize=True, check=True, def true(nam): _skew_had_cache[n] = nam if construction_name: - return nam+": "+str(n) + return nam + ": " + str(n) return True + M = None name = '' if existence and n in _skew_had_cache: @@ -3288,7 +3172,7 @@ def true(nam): if existence: return true(name) M = hadamard_matrix_paleyI(n, normalize=False) - elif is_prime_power(n//2 - 1) and (n//2 - 1) % 8 == 5: + elif is_prime_power(n // 2 - 1) and (n // 2 - 1) % 8 == 5: name = "spence" if existence: return true(name) @@ -3309,30 +3193,26 @@ def true(nam): return true(name) M = skew_hadamard_matrix_from_orthogonal_design(n, check=False) elif n % 8 == 0: - if skew_hadamard_matrix(n//2, existence=True) is True: # (Lemma 14.1.6 in [Ha83]_) + if skew_hadamard_matrix(n // 2, existence=True) is True: # (Lemma 14.1.6 in [Ha83]_) name = "doubling" if existence: return true(name) - H = skew_hadamard_matrix(n//2, check=False) + H = skew_hadamard_matrix(n // 2, check=False) M = block_matrix([[H, H], [-H.T, H.T]]) else: # try Williamson construction (Lemma 14.1.5 in [Ha83]_) for d in divisors(n)[2:-2]: # skip 1, 2, n/2, and n - n1 = n//d - if is_prime_power(d - 1) and (d % 4 == 0) and (n1 % 4 == 0)\ - and skew_hadamard_matrix(n1, existence=True) is True: + n1 = n // d + if is_prime_power(d - 1) and (d % 4 == 0) and (n1 % 4 == 0) and skew_hadamard_matrix(n1, existence=True) is True: from sage.arith.misc import factor - name = "williamson - Lemma 14.1.5 [Ha83] ("+str(factor(d-1))+","+str(n1)+") " + + name = "williamson - Lemma 14.1.5 [Ha83] (" + str(factor(d - 1)) + "," + str(n1) + ") " if existence: return true(name) - H = skew_hadamard_matrix(n1, check=False)-I(n1) - U = matrix(ZZ, d, lambda i, j: -1 if i == j == 0 else - 1 if i == j == 1 or (i > 1 and j-1 == d-i) - else 0) - A = block_matrix([[matrix([0]), matrix(ZZ, 1, d-1, [1]*(d-1))], - [matrix(ZZ, d-1, 1, [-1]*(d-1)), - _helper_payley_matrix(d-1, zero_position=0)]])+I(d) - M = A.tensor_product(I(n1))+(U*A).tensor_product(H) + H = skew_hadamard_matrix(n1, check=False) - I(n1) + U = matrix(ZZ, d, lambda i, j: -1 if i == j == 0 else 1 if i == j == 1 or (i > 1 and j - 1 == d - i) else 0) + A = block_matrix([[matrix([0]), matrix(ZZ, 1, d - 1, [1] * (d - 1))], [matrix(ZZ, d - 1, 1, [-1] * (d - 1)), _helper_payley_matrix(d - 1, zero_position=0)]]) + I(d) + M = A.tensor_product(I(n1)) + (U * A).tensor_product(H) break if M is None: # try Williamson-Goethals-Seidel construction if GS_skew_hadamard_smallcases(n, existence=True) is True: @@ -3391,15 +3271,16 @@ def symmetric_conference_matrix(n, check=True, existence=False): True """ from sage.graphs.strongly_regular_db import strongly_regular_graph as srg + try: - m = srg(n-1, (n-2)/2, (n-6)/4, (n-2)/4, existence=existence) + m = srg(n - 1, (n - 2) / 2, (n - 6) / 4, (n - 2) / 4, existence=existence) except ValueError: raise if existence: return m - C = matrix([0]+[1]*(n-1)).stack(matrix([1]*(n-1)).stack(m.seidel_adjacency_matrix()).T) + C = matrix([0] + [1] * (n - 1)).stack(matrix([1] * (n - 1)).stack(m.seidel_adjacency_matrix()).T) if check: - assert (C == C.T and C**2 == (n-1)*I(n)) + assert C == C.T and C**2 == (n - 1) * I(n) return C @@ -3436,20 +3317,21 @@ def szekeres_difference_set_pair(m, check=True): - [Sz1969]_ """ from sage.rings.finite_rings.finite_field_constructor import GF - F = GF(4*m+3) - t = F.multiplicative_generator()**2 + + F = GF(4 * m + 3) + t = F.multiplicative_generator() ** 2 G = F.cyclotomic_cosets(t, cosets=[F.one()])[0] sG = set(G) A = [a for a in G if a - F.one() in sG] B = [b for b in G if b + F.one() in sG] if check: from itertools import product, chain - assert (len(A) == len(B) == m) + + assert len(A) == len(B) == m if m > 1: - assert (sG == {xy[0] / xy[1] - for xy in chain(product(A, A), product(B, B))}) + assert sG == {xy[0] / xy[1] for xy in chain(product(A, A), product(B, B))} assert all(F.one() / b + F.one() in sG for b in B) - assert (not any(F.one() / a - F.one() in sG for a in A)) + assert not any(F.one() / a - F.one() in sG for a in A) return G, A, B @@ -3473,7 +3355,7 @@ def typeI_matrix_difference_set(G, A): [-1 -1 1 1 -1] """ n = len(G) - return matrix(n, n, lambda i, j: 1 if G[i]/G[j] in A else -1) + return matrix(n, n, lambda i, j: 1 if G[i] / G[j] in A else -1) def rshcd_from_prime_power_and_conference_matrix(n): @@ -3527,30 +3409,27 @@ def rshcd_from_prime_power_and_conference_matrix(n): - [WW1972]_ """ from sage.graphs.strongly_regular_db import strongly_regular_graph as srg - if is_prime_power(n) and 2 == (n-1) % 4: + + if is_prime_power(n) and 2 == (n - 1) % 4: try: - M = srg(n-2, (n-3)//2, (n-7)//4) + M = srg(n - 2, (n - 3) // 2, (n - 7) // 4) except ValueError: return - m = (n-3)//4 + m = (n - 3) // 4 Q, X, Y = szekeres_difference_set_pair(m) B = typeI_matrix_difference_set(Q, X) A = -typeI_matrix_difference_set(Q, Y) # must be symmetric W = M.seidel_adjacency_matrix() - f = J(1, 4*m+1) - e = J(1, 2*m+1) - JJ = J(2*m+1, 2*m+1) - II = I(n-2) - Ib = I(2*m+1) - J4m = J(4*m+1, 4*m+1) - H34 = -(B+Ib).tensor_product(W)+Ib.tensor_product(J4m)+(Ib-JJ).tensor_product(II) + f = J(1, 4 * m + 1) + e = J(1, 2 * m + 1) + JJ = J(2 * m + 1, 2 * m + 1) + II = I(n - 2) + Ib = I(2 * m + 1) + J4m = J(4 * m + 1, 4 * m + 1) + H34 = -(B + Ib).tensor_product(W) + Ib.tensor_product(J4m) + (Ib - JJ).tensor_product(II) A_t_W = A.tensor_product(W) e_t_f = e.tensor_product(f) - H = block_matrix([ - [J(1, 1), f, e_t_f, -e_t_f], - [f.T, J4m, e.tensor_product(W-II), e.tensor_product(W+II)], - [ e_t_f.T, (e.T).tensor_product(W-II), A_t_W+JJ.tensor_product(II), H34], - [-e_t_f.T, (e.T).tensor_product(W+II), H34.T, -A_t_W+JJ.tensor_product(II)]]) + H = block_matrix([[J(1, 1), f, e_t_f, -e_t_f], [f.T, J4m, e.tensor_product(W - II), e.tensor_product(W + II)], [e_t_f.T, (e.T).tensor_product(W - II), A_t_W + JJ.tensor_product(II), H34], [-e_t_f.T, (e.T).tensor_product(W + II), H34.T, -A_t_W + JJ.tensor_product(II)]]) return H @@ -3678,7 +3557,7 @@ def amicable_hadamard_matrices_wallis(n, check=True): squares = [] for el in Glist: - squares.append(el*el) + squares.append(el * el) def chi(el): if el == 0: @@ -3688,18 +3567,16 @@ def chi(el): return -1 S = matrix([[chi(Glist[i] - Glist[j]) for j in range(q)] for i in range(q)]) - R = matrix([[1 if (i, j) == (0, 0) else 1 if j == q-i else 0 for j in range(q)] for i in range(q)]) + R = matrix([[1 if (i, j) == (0, 0) else 1 if j == q - i else 0 for j in range(q)] for i in range(q)]) P = S + I(q) - D = R + R*S + D = R + R * S e = matrix([1 for _ in range(q)]) one = matrix([1]) - M = block_matrix([[ one, e], - [-e.T, P]]) - N = block_matrix([[-one, -e], - [-e.T, D]]) + M = block_matrix([[one, e], [-e.T, P]]) + N = block_matrix([[-one, -e], [-e.T, D]]) if check: assert are_amicable_hadamard_matrices(M, N) @@ -3768,7 +3645,7 @@ def amicable_hadamard_matrices(n, existence=False, check=True): return True M = matrix([[1, 1], [-1, 1]]) N = matrix([[1, 1], [1, -1]]) - elif is_prime_power(n-1): + elif is_prime_power(n - 1): if existence: return True M, N = amicable_hadamard_matrices_wallis(n, check=False) diff --git a/src/sage/combinat/matrices/latin.py b/src/sage/combinat/matrices/latin.py index 763d1055176..46149da4713 100644 --- a/src/sage/combinat/matrices/latin.py +++ b/src/sage/combinat/matrices/latin.py @@ -180,8 +180,7 @@ def __init__(self, *args) -> None: if len(args) == 1 and isinstance(args[0], (Integer, int)): self.square = matrix(ZZ, args[0], args[0]) self.clear_cells() - elif len(args) == 2 and all(isinstance(a, (Integer, int)) - for a in args): + elif len(args) == 2 and all(isinstance(a, (Integer, int)) for a in args): self.square = matrix(ZZ, args[0], args[1]) self.clear_cells() elif len(args) == 1 and isinstance(args[0], Matrix_integer_dense): @@ -201,6 +200,7 @@ def dumps(self): True """ from sage.misc.persist import dumps + return dumps(self.square) def __str__(self) -> str: @@ -317,6 +317,7 @@ def __copy__(self): """ C = LatinSquare(self.square.nrows(), self.square.ncols()) from copy import copy + C.square = copy(self.square) return C @@ -405,8 +406,7 @@ def n_filled_cells(self) -> int: sage: LatinSquare(matrix([[0, -1], [-1, 0]])).n_filled_cells() 2 """ - return sum(1 for r in range(self.nrows()) for c in range(self.ncols()) - if self[r, c] >= 0) + return sum(1 for r in range(self.nrows()) for c in range(self.ncols()) if self[r, c] >= 0) nr_filled_cells = n_filled_cells @@ -439,9 +439,9 @@ def actual_row_col_sym_sizes(self) -> tuple: col_max = self.ncols() sym_max = self.n_distinct_symbols() - while self.is_empty_row(row_max-1): + while self.is_empty_row(row_max - 1): row_max -= 1 - while self.is_empty_column(col_max-1): + while self.is_empty_column(col_max - 1): col_max -= 1 return row_max, col_max, sym_max @@ -539,7 +539,7 @@ def apply_isotopism(self, row_perm, col_perm, sym_perm): except IndexError: s2 = self[r, c] # we must be leaving the symbol fixed? - Q[row_perm[r]-1, col_perm[c]-1] = s2 + Q[row_perm[r] - 1, col_perm[c] - 1] = s2 return Q @@ -906,10 +906,11 @@ def gcs(self): n = self.nrows() from copy import copy + G = copy(self) - for r in range(n-1, -1, -1): - for c in range(n-1, -1, -1): + for r in range(n - 1, -1, -1): + for c in range(n - 1, -1, -1): e = G[r, c] G[r, c] = -1 @@ -995,7 +996,7 @@ def latex(self) -> str: """ a = "" - a += r"\begin{array}{" + self.ncols()*"|c" + "|}" + a += r"\begin{array}{" + self.ncols() * "|c" + "|}" for r in range(self.nrows()): a += r"\hline " for c in range(self.ncols()): @@ -1005,7 +1006,7 @@ def latex(self) -> str: else: a += str(s) - if c < self.ncols()-1: + if c < self.ncols() - 1: a += " & " else: a += "\\\\" @@ -1178,9 +1179,9 @@ def disjoint_mate_dlxcpp_rows_and_map(self, allow_subtrade): for e in sorted(set(list(valsrow) + list(valscol))): # These should be constants - c_OFFSET = e + c*n - r_OFFSET = e + r*n + n*n - xy_OFFSET = 2*n*n + r*n + c + c_OFFSET = e + c * n + r_OFFSET = e + r * n + n * n + xy_OFFSET = 2 * n * n + r * n + c cmap[(c_OFFSET, r_OFFSET, xy_OFFSET)] = (r, c, e) @@ -1196,8 +1197,7 @@ def disjoint_mate_dlxcpp_rows_and_map(self, allow_subtrade): dlx_rows.append([c_OFFSET, r_OFFSET, xy_OFFSET]) - max_column_nr = max(max_column_nr, c_OFFSET, - r_OFFSET, xy_OFFSET) + max_column_nr = max(max_column_nr, c_OFFSET, r_OFFSET, xy_OFFSET) # We will have missed some columns. We # have to add 'dummy' rows so that the C++ DLX solver will find @@ -1247,6 +1247,7 @@ def find_disjoint_mates(self, nr_to_find=None, allow_subtrade=False): n_found += 1 from copy import deepcopy + Q = deepcopy(self) for y in x: @@ -1509,12 +1510,12 @@ def isotopism(p): if isinstance(p, list): # We expect a list like [0,3,2,1] which means # that 0 goes to 0, 1 goes to 3, etc. - return Permutation([x+1 for x in p]) + return Permutation([x + 1 for x in p]) if isinstance(p, tuple): # We have a single cycle: if isinstance(p[0], Integer): - return Permutation(tuple(x+1 for x in p)) + return Permutation(tuple(x + 1 for x in p)) # We have a tuple of cycles: if isinstance(p[0], tuple): @@ -1726,7 +1727,7 @@ def tau1(T1, T2, cells_map): # The cells_map has both directions, i.e. integer to # cell and cell to integer, so the size of T1 is # just half of len(cells_map). - x = (int(len(cells_map)/2) + 1) * [-1] + x = (int(len(cells_map) / 2) + 1) * [-1] for r in range(T1.nrows()): for c in range(T1.ncols()): @@ -1780,7 +1781,7 @@ def tau2(T1, T2, cells_map): # The cells_map has both directions, i.e. integer to # cell and cell to integer, so the size of T1 is # just half of len(cells_map). - x = (int(len(cells_map)/2) + 1) * [-1] + x = (int(len(cells_map) / 2) + 1) * [-1] for r in range(T1.nrows()): for c in range(T1.ncols()): @@ -1834,7 +1835,7 @@ def tau3(T1, T2, cells_map): # The cells_map has both directions, i.e. integer to # cell and cell to integer, so the size of T1 is # just half of len(cells_map). - x = (int(len(cells_map)/2) + 1) * [-1] + x = (int(len(cells_map) / 2) + 1) * [-1] for r in range(T1.nrows()): for c in range(T1.ncols()): @@ -1910,7 +1911,7 @@ def forward_circulant(n): for r in range(n): for c in range(n): - L[r, c] = (n-c+r) % n + L[r, c] = (n - c + r) % n return L @@ -1949,14 +1950,14 @@ def direct_product(L1, L2, L3, L4): n = L1.nrows() - D = LatinSquare(2*n, 2*n) + D = LatinSquare(2 * n, 2 * n) for r in range(n): for c in range(n): D[r, c] = L1[r, c] - D[r, c+n] = L2[r, c] + n - D[r+n, c] = L3[r, c] + n - D[r+n, c+n] = L4[r, c] + D[r, c + n] = L2[r, c] + n + D[r + n, c] = L3[r, c] + n + D[r + n, c + n] = L4[r, c] return D @@ -1993,7 +1994,7 @@ def elementary_abelian_2group(s): L[1, 1] = 0 return L - L_prev = elementary_abelian_2group(s-1) + L_prev = elementary_abelian_2group(s - 1) L = LatinSquare(2**s, 2**s) offset = L.nrows() // 2 @@ -2001,9 +2002,9 @@ def elementary_abelian_2group(s): for r in range(L_prev.nrows()): for c in range(L_prev.ncols()): L[r, c] = L_prev[r, c] - L[r+offset, c] = L_prev[r, c] + offset - L[r, c+offset] = L_prev[r, c] + offset - L[r+offset, c+offset] = L_prev[r, c] + L[r + offset, c] = L_prev[r, c] + offset + L[r, c + offset] = L_prev[r, c] + offset + L[r + offset, c + offset] = L_prev[r, c] return L @@ -2182,6 +2183,7 @@ def LatinSquare_generator(L_start, check_assertions=False): proper = True from copy import copy + L = copy(L_start) L_cer = LatinSquare(n, n) @@ -2354,13 +2356,13 @@ def alternating_group_bitrade_generators(m): """ assert m >= 1 - a = tuple(range(1, 2*m+1 + 1)) + a = tuple(range(1, 2 * m + 1 + 1)) - b = tuple(range(m + 1, 0, -1)) + tuple(range(2*m+2, 3*m+1 + 1)) + b = tuple(range(m + 1, 0, -1)) + tuple(range(2 * m + 2, 3 * m + 1 + 1)) a = PermutationConstructor(a) b = PermutationConstructor(b) - c = PermutationConstructor((a*b)**(-1)) + c = PermutationConstructor((a * b) ** (-1)) G = PermutationGroup([a, b]) @@ -2386,12 +2388,12 @@ def pq_group_bitrade_generators(p, q): # congruence x^p = 1 mod q F = FiniteField(q) fgen = F.multiplicative_generator() - beta = fgen**((q-1)/p) + beta = fgen ** ((q - 1) / p) assert beta != 1 assert (beta**p % q) == 1 - Q = tuple(range(1, q+1)) + Q = tuple(range(1, q + 1)) P = [] seenValues = {} @@ -2401,7 +2403,7 @@ def pq_group_bitrade_generators(p, q): cycle = [] for k in range(p): - x = (1 + (i-1)*beta**k) % q + x = (1 + (i - 1) * beta**k) % q if x == 0: x = q @@ -2410,12 +2412,12 @@ def pq_group_bitrade_generators(p, q): P.append(tuple(map(Integer, cycle))) G = PermutationGroup([P, Q]) - assert G.order() == p*q + assert G.order() == p * q assert not G.is_abelian() a = PermutationConstructor(P) b = PermutationConstructor(Q) - c = PermutationConstructor((a*b)**(-1)) + c = PermutationConstructor((a * b) ** (-1)) return (a, b, c, PermutationGroup([P, Q])) @@ -2442,9 +2444,9 @@ def p3_group_bitrade_generators(p): rels.append(a**p) rels.append(b**p) rels.append(c**p) - rels.append(a*b*((b*a*c)**(-1))) - rels.append(c*a*((a*c)**(-1))) - rels.append(c*b*((b*c)**(-1))) + rels.append(a * b * ((b * a * c) ** (-1))) + rels.append(c * a * ((a * c) ** (-1))) + rels.append(c * b * ((b * c) ** (-1))) G = F.FactorGroupFpGroupByRels(rels) u, v, _ = G.GeneratorsOfGroup() @@ -2454,7 +2456,7 @@ def p3_group_bitrade_generators(p): x = PermutationConstructor(libgap.Image(iso, u)) y = PermutationConstructor(libgap.Image(iso, v)) - return (x, y, (x*y)**(-1), PermutationGroup([x, y])) + return (x, y, (x * y) ** (-1), PermutationGroup([x, y])) def check_bitrade_generators(a, b, c) -> bool: @@ -2476,7 +2478,7 @@ def check_bitrade_generators(a, b, c) -> bool: B = PermutationGroup([b]) C = PermutationGroup([c]) - if a*b != c**(-1): + if a * b != c ** (-1): return False X = libgap.Intersection(libgap.Intersection(A, B), C) @@ -2501,8 +2503,7 @@ def is_bitrade(T1, T2) -> bool: sage: is_bitrade(T1, T2) True """ - return (is_disjoint(T1, T2) and is_same_shape(T1, T2) and - is_row_and_col_balanced(T1, T2)) + return is_disjoint(T1, T2) and is_same_shape(T1, T2) and is_row_and_col_balanced(T1, T2) def is_primary_bitrade(a, b, c, G) -> bool: @@ -2578,8 +2579,7 @@ def tau_to_bitrade(t1, t2, t3): for r in range(len(c1)): for c in range(len(c2)): for s in range(len(c3)): - n_common = len(reduce(set.intersection, - [set(c1[r]), set(c2[c]), set(c3[s])])) + n_common = len(reduce(set.intersection, [set(c1[r]), set(c2[c]), set(c3[s])])) assert n_common in [0, 1] if n_common == 1: @@ -2776,9 +2776,9 @@ def dlxcpp_rows_and_map(P): for e in range(n): # These should be constants - c_OFFSET = e + c*n - r_OFFSET = e + r*n + n*n - xy_OFFSET = 2*n*n + r*n + c + c_OFFSET = e + c * n + r_OFFSET = e + r * n + n * n + xy_OFFSET = 2 * n * n + r * n + c cmap[(c_OFFSET, r_OFFSET, xy_OFFSET)] = (r, c, e) @@ -2833,6 +2833,7 @@ def dlxcpp_find_completions(P, nr_to_find=None): soln = list(i) from copy import deepcopy + Q = deepcopy(P) for x in soln: @@ -2882,6 +2883,7 @@ def bitrade(T1, T2): n = T1.nrows() from copy import copy + Q1 = copy(T1) Q2 = copy(T2) diff --git a/src/sage/combinat/misc.py b/src/sage/combinat/misc.py index b697be6986e..d86167cc74c 100644 --- a/src/sage/combinat/misc.py +++ b/src/sage/combinat/misc.py @@ -1,6 +1,7 @@ r""" Miscellaneous """ + # *************************************************************************** # Copyright (C) 2007 Mike Hansen , # @@ -52,15 +53,15 @@ def __init__(self, l): self.l = l self.next_value = {} self.next_value['begin'] = l[0] - self.next_value[l[n-1]] = 'end' - for i in range(n-1): - self.next_value[l[i]] = l[i+1] + self.next_value[l[n - 1]] = 'end' + for i in range(n - 1): + self.next_value[l[i]] = l[i + 1] self.prev_value = {} self.prev_value['end'] = l[-1] self.prev_value[l[0]] = 'begin' - for i in range(1,n): - self.prev_value[l[i]] = l[i-1] + for i in range(1, n): + self.prev_value[l[i]] = l[i - 1] def __eq__(self, other): """ @@ -74,10 +75,7 @@ def __eq__(self, other): sage: dll == dll2 False """ - return (isinstance(other, DoublyLinkedList) and - self.l == other.l and - self.next_value == other.next_value and - self.prev_value == other.prev_value) + return isinstance(other, DoublyLinkedList) and self.l == other.l and self.next_value == other.next_value and self.prev_value == other.prev_value def __ne__(self, other): """ @@ -231,7 +229,7 @@ def umbral_operation(poly): exponents = poly.exponents() coefficients = poly.coefficients() length = len(exponents) - return sum(coefficients[i]*_monomial_exponent_to_lower_factorial(exponents[i], x) for i in range(length)) + return sum(coefficients[i] * _monomial_exponent_to_lower_factorial(exponents[i], x) for i in range(length)) class IterableFunctionCall: @@ -369,7 +367,7 @@ def check_integer_list_constraints(l, **kwargs): max_length = len(outer) for i in range(max_length): if outer[i] == "inf": - outer[i] = n+1 + outer[i] = n + 1 if inner is not None: min_length = len(inner) diff --git a/src/sage/combinat/multiset_partition_into_sets_ordered.py b/src/sage/combinat/multiset_partition_into_sets_ordered.py index 04358589da0..83f1ef1b903 100644 --- a/src/sage/combinat/multiset_partition_into_sets_ordered.py +++ b/src/sage/combinat/multiset_partition_into_sets_ordered.py @@ -93,8 +93,7 @@ lazy_import('sage.combinat.sf.sf', 'SymmetricFunctions') -class OrderedMultisetPartitionIntoSets(ClonableArray, - metaclass=InheritComparisonClasscallMetaclass): +class OrderedMultisetPartitionIntoSets(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): r""" Ordered Multiset Partition into sets. @@ -120,6 +119,7 @@ class OrderedMultisetPartitionIntoSets(ClonableArray, - [HRS2016]_ - [LM2018]_ """ + @staticmethod def __classcall_private__(cls, co): """ @@ -557,6 +557,7 @@ def weight(self, as_weak_comp=False): ValueError: {'a': 2, 'b': 4, 'c': 2} is not a numeric multiset """ from pprint import pformat + w = self._weight if as_weak_comp: if all(v in ZZ for v in w): @@ -599,12 +600,11 @@ def deconcatenate(self, k=2): ....: for k in range(1, 5) ) True """ - P = OrderedMultisetPartitionsIntoSets(alphabet=self.letters(), - max_length=self.length()) + P = OrderedMultisetPartitionsIntoSets(alphabet=self.letters(), max_length=self.length()) out = [] for c in IntegerListsLex(self.length(), length=k): - ps = [sum(c[:i]) for i in range(k+1)] - out.append(tuple([P(self[ps[i]:ps[i+1]]) for i in range(len(ps)-1)])) + ps = [sum(c[:i]) for i in range(k + 1)] + out.append(tuple([P(self[ps[i] : ps[i + 1]]) for i in range(len(ps) - 1)])) return out def split_blocks(self, k=2): @@ -660,12 +660,11 @@ def split_blocks(self, k=2): sage: C.split_blocks(3) == {(C, C, C): 1} True """ - P = OrderedMultisetPartitionsIntoSets(alphabet=self.letters(), - max_length=self.length()) + P = OrderedMultisetPartitionsIntoSets(alphabet=self.letters(), max_length=self.length()) # corner case if not self: - return {tuple([self]*k): 1} + return {tuple([self] * k): 1} out: dict[tuple, int] = {} for t in product(*[_split_block(block, k) for block in self]): @@ -782,13 +781,12 @@ def fatten(self, grouping): ValueError: [{1,4,5,2,1,7}] is not a valid ordered multiset partition into sets """ if sum(list(grouping)) != self.length(): - raise ValueError("%s is not a composition of ``self.length()`` (=%s)" - % (grouping, self.length())) + raise ValueError("%s is not a composition of ``self.length()`` (=%s)" % (grouping, self.length())) valid = True result = [] for i in range(len(grouping)): - result_i = self[sum(grouping[:i]) : sum(grouping[:i+1])] + result_i = self[sum(grouping[:i]) : sum(grouping[: i + 1])] # check that grouping[i] is allowed, i.e., `|A\cup B| = |A| + |B|` strict_size = sum(map(len, result_i)) size = len(_union_of_sets(result_i)) @@ -981,12 +979,12 @@ def to_tableaux_words(self): return [] bb = self.minimaj_blocks() b = [block[0] for block in bb] - beginning = [0]+running_total(self.shape_from_cardinality()) + beginning = [0] + running_total(self.shape_from_cardinality()) w = _concatenate(bb) D = [0] + _descents(w) + [len(w)] pieces = [b] - for i in range(len(D)-1): - p = [w[j] for j in range(D[i]+1,D[i+1]+1) if j not in beginning] + for i in range(len(D) - 1): + p = [w[j] for j in range(D[i] + 1, D[i + 1] + 1) if j not in beginning] pieces = [p[::-1]] + pieces return pieces @@ -1045,7 +1043,7 @@ def major_index(self): vj += 1 v.append(vj) w.append(wj) - maj = [v[j+1] for j in range(len(w)-1) if w[j] > w[j+1]] + maj = [v[j + 1] for j in range(len(w) - 1) if w[j] > w[j + 1]] return sum(maj) def shuffle_product(self, other, overlap=False): @@ -1092,6 +1090,7 @@ def shuffle_product(self, other, overlap=False): if len(_concatenate(map(frozenset, term))) == len(P._Xtup): yield P(term) + ############################################################## @@ -1325,6 +1324,7 @@ class OrderedMultisetPartitionsIntoSets(UniqueRepresentation, Parent): 72 sage: TestSuite(C).run() """ + @staticmethod def __classcall_private__(self, *args, **constraints): """ @@ -1403,7 +1403,7 @@ def __classcall_private__(self, *args, **constraints): if len(w) > 0 and isinstance(w[0], (list, tuple)): w = dict(w) else: - w = {i+1: w[i] for i in range(len(w)) if w[i] > 0} + w = {i + 1: w[i] for i in range(len(w)) if w[i] > 0} if not all((a in ZZ and a > 0) for a in w.values()): raise ValueError("%s must be a dictionary of letter-frequencies or a weak composition" % w) else: @@ -1432,7 +1432,7 @@ def __classcall_private__(self, *args, **constraints): return OrderedMultisetPartitionsIntoSets_alph_d_constraints(frozenset(alph), order, **constraints) raise ValueError("alphabet=%s must be a nonempty set and order=%s must be a nonnegative integer" % (alph, order)) - elif len(args) == 1: # treat as `size` or `multiset` + elif len(args) == 1: # treat as `size` or `multiset` X = args[0] if isinstance(X, (list, tuple)): tmp = {} @@ -1517,7 +1517,7 @@ def __init__(self, is_finite=None, **constraints): # standardize values for certain keywords if "alphabet" in constraints: if constraints["alphabet"] in ZZ: - constraints["alphabet"] = frozenset(range(1, constraints["alphabet"]+1)) + constraints["alphabet"] = frozenset(range(1, constraints["alphabet"] + 1)) else: constraints["alphabet"] = frozenset(constraints["alphabet"]) @@ -1537,8 +1537,7 @@ def __init__(self, is_finite=None, **constraints): max_k = constraints.get("max_length", infinity) assert min_k <= max_k, "min_length=%s <= max_length=%s" % (min_k, max_k) if min_k == max_k: - constraints["length"] = constraints.pop("min_length", - constraints.pop("max_length")) + constraints["length"] = constraints.pop("min_length", constraints.pop("max_length")) if "order" in constraints: constraints.pop("min_order", None) @@ -1547,8 +1546,7 @@ def __init__(self, is_finite=None, **constraints): max_ord = constraints.get("max_order", infinity) assert min_ord <= max_ord, "min_order=%s <= max_order=%s" % (min_ord, max_ord) if min_ord == max_ord: - constraints["order"] = constraints.pop("min_order", - constraints.pop("max_order")) + constraints["order"] = constraints.pop("min_order", constraints.pop("max_order")) # pop keys with empty values, with the exception of 'size' or 'order' self.constraints = {} @@ -1719,23 +1717,23 @@ def _satisfies_constraints(self, x): constr = self.full_constraints tsts = [] if 'size' in constr: - tsts.append( x.size() == constr['size'] ) + tsts.append(x.size() == constr['size']) if 'weight' in constr: - tsts.append( x.weight() == constr['weight'] ) + tsts.append(x.weight() == constr['weight']) if 'alphabet' in constr: - tsts.append( frozenset(x.letters()).issubset(constr['alphabet']) ) + tsts.append(frozenset(x.letters()).issubset(constr['alphabet'])) if 'length' in constr: - tsts.append( x.length() == constr['length'] ) + tsts.append(x.length() == constr['length']) if 'min_length' in constr: - tsts.append( x.length() >= constr['min_length'] ) + tsts.append(x.length() >= constr['min_length']) if 'max_length' in constr: - tsts.append( x.length() <= constr['max_length'] ) + tsts.append(x.length() <= constr['max_length']) if 'order' in constr: - tsts.append( x.order() == constr['order'] ) + tsts.append(x.order() == constr['order']) if 'min_order' in constr: - tsts.append( x.order() >= constr['min_order'] ) + tsts.append(x.order() >= constr['min_order']) if 'max_order' in constr: - tsts.append( x.order() <= constr['max_order'] ) + tsts.append(x.order() <= constr['max_order']) return all(tsts) @@ -1941,13 +1939,13 @@ def subset(self, size): # slice by 'order' if "alphabet" in fc: - no_alpha = {k: v for k, v in self.constraints.items() - if k != "alphabet"} + no_alpha = {k: v for k, v in self.constraints.items() if k != "alphabet"} return OrderedMultisetPartitionsIntoSets(fc["alphabet"], size, **no_alpha) # slice by 'size' return OrderedMultisetPartitionsIntoSets(size, **self.constraints) + ############### @@ -2001,6 +1999,7 @@ def _repr_(self): """ return "Ordered Multiset Partitions into Sets" + self._constraint_repr_() + ############### @@ -2083,17 +2082,17 @@ def _an_element_(self): sage: OrderedMultisetPartitionsIntoSets(14).an_element() [{2,3}, {2,3}, {4}] """ - #output will have at most three blocks, each of size 1, 2, or 3. - alpha = Compositions(self._n, max_part=self._n//3+1).an_element() + # output will have at most three blocks, each of size 1, 2, or 3. + alpha = Compositions(self._n, max_part=self._n // 3 + 1).an_element() out = [] for a in alpha: if a in {1, 2, 4}: out.append([a]) else: if a % 2: - out.append([a//2+1, a//2]) + out.append([a // 2 + 1, a // 2]) else: - out.append([a//2, a//2-1, 1]) + out.append([a // 2, a // 2 - 1, 1]) return self.element_class(self, map(frozenset, out)) def random_element(self): @@ -2122,8 +2121,7 @@ def random_element(self): [72, 73, 162, 78, 135, 75, 109, 65, 135, 134, 62] """ C = Compositions(self._n).random_element() - co = [IntegerListsLex(c, min_part=1, max_part=c, - min_slope=1).random_element() for c in C] + co = [IntegerListsLex(c, min_part=1, max_part=c, min_slope=1).random_element() for c in C] return self.element_class(self, map(frozenset, co)) def __iter__(self): @@ -2180,6 +2178,7 @@ def _repr_(self): base_repr = "Ordered Multiset Partitions into Sets of integer %s" % self._n return base_repr + self._constraint_repr_(cdict) + ############### @@ -2271,7 +2270,7 @@ def cardinality(self): deg = 0 for alpha in Permutations_mset(self._Xtup): fattest = _break_at_descents(alpha) - deg += prod(2**(len(k)-1) for k in fattest) + deg += prod(2 ** (len(k) - 1) for k in fattest) return ZZ(deg) def _an_element_(self): @@ -2297,9 +2296,9 @@ def _an_element_(self): elt.append(co[i]) else: break - elt.append(co[i][:len(co[i])//2 + 1]) - elt.append(co[i][len(co[i])//2 + 1:]) - elt.extend(co[i+1:]) + elt.append(co[i][: len(co[i]) // 2 + 1]) + elt.append(co[i][len(co[i]) // 2 + 1 :]) + elt.extend(co[i + 1 :]) return self.element_class(self, map(frozenset, elt)) def random_element(self): @@ -2333,7 +2332,7 @@ def random_element(self): alpha = Permutations_mset(self._Xtup).random_element() co = _break_at_descents(alpha) - finer = self.element_class(self, map(frozenset,co)).finer() + finer = self.element_class(self, map(frozenset, co)).finer() return FiniteEnumeratedSets()(finer).random_element() def __iter__(self): @@ -2398,6 +2397,7 @@ def _repr_(self): base_repr = "Ordered Multiset Partitions into Sets" + " of multiset %s" % ms_rep return base_repr + self._constraint_repr_(cdict) + ############### @@ -2532,7 +2532,7 @@ def cardinality(self): max_length = self._order deg = 0 - for k in range(min_length, max_length+1): + for k in range(min_length, max_length + 1): for alpha in IntegerListsLex(self._order, length=k, min_part=1, max_part=len(self._alphabet)): deg += prod(binomial(len(self._alphabet), a) for a in alpha) return ZZ(deg) @@ -2565,8 +2565,7 @@ def __init__(self, A, d, **constraints): """ self._alphabet = A self._order = d - OrderedMultisetPartitionsIntoSets.__init__(self, True, alphabet=A, - order=d, **constraints) + OrderedMultisetPartitionsIntoSets.__init__(self, True, alphabet=A, order=d, **constraints) def _repr_(self): """ @@ -2590,6 +2589,7 @@ def _repr_(self): base_repr += " over alphabet {%s}" % (", ".join(map(str, sorted(self._alphabet)))) return base_repr + self._constraint_repr_(cdict) + ############### @@ -2622,7 +2622,7 @@ def _get_weight(lst): """ out = {} for k in lst: - out[k] = out.get(k,0) + 1 + out[k] = out.get(k, 0) + 1 return out @@ -2640,9 +2640,7 @@ def _has_nonempty_sets(x): sage: _has_nonempty_sets([(2,4), (1,1), (1,4)]) False """ - return all((isinstance(block, (list, tuple, set, frozenset, Set_object)) - and block and len(set(block)) == len(block)) - for block in x) + return all((isinstance(block, (list, tuple, set, frozenset, Set_object)) and block and len(set(block)) == len(block)) for block in x) def _union_of_sets(list_of_sets): @@ -2656,8 +2654,7 @@ def _union_of_sets(list_of_sets): sage: _union_of_sets(L) frozenset({1, 2, 3, 5, 6, 7}) """ - return reduce(lambda a, b: frozenset(a) | frozenset(b), - list_of_sets, frozenset()) + return reduce(lambda a, b: frozenset(a) | frozenset(b), list_of_sets, frozenset()) def _concatenate(list_of_iters): @@ -2771,8 +2768,7 @@ def _base_iterator(constraints): if "weight" in constraints: return _iterator_weight(constraints["weight"]) if "size" in constraints: - return _iterator_size(constraints["size"], - constraints.get("length",None), constraints.get("alphabet",None)) + return _iterator_size(constraints["size"], constraints.get("length", None), constraints.get("alphabet", None)) if "alphabet" in constraints: A = constraints["alphabet"] # assumes `alphabet` is finite @@ -2791,8 +2787,7 @@ def _base_iterator(constraints): if min_ord: min_k = max(1, min_k, min_ord // len(A)) if infinity not in (max_k, max_ord): - return chain(*(_iterator_order(A, ord, range(min_k, max_k + 1)) - for ord in range(min_ord, max_ord + 1))) + return chain(*(_iterator_order(A, ord, range(min_k, max_k + 1)) for ord in range(min_ord, max_ord + 1))) # else return None @@ -2840,7 +2835,7 @@ def _iterator_weight(weight): """ # "weight" should be a dict mapping keys to weights if isinstance(weight, (list, tuple)): - weight = {k+1: val for k, val in enumerate(weight) if val} + weight = {k + 1: val for k, val in enumerate(weight) if val} # We first map the arbitrary keys to integers to combat unreliable # sorting behavior. @@ -2894,18 +2889,13 @@ def _iterator_size(size, length=None, alphabet=None): if alphabet: min_p = min(alphabet) max_p = max(alphabet) - for alpha in IntegerListsLex(size, length=length, min_part=1, - max_part=min(size, sum(alphabet))): - for p in product(*[IntegerListsLex(a, min_slope=1, - min_part=min_p, - max_part=min(a, max_p)) - for a in alpha]): + for alpha in IntegerListsLex(size, length=length, min_part=1, max_part=min(size, sum(alphabet))): + for p in product(*[IntegerListsLex(a, min_slope=1, min_part=min_p, max_part=min(a, max_p)) for a in alpha]): if frozenset(_concatenate(p)).issubset(frozenset(alphabet)): yield tuple(frozenset(k) for k in p) else: for alpha in IntegerListsLex(size, length=length, min_part=1, max_part=size): - for p in product(*[IntegerListsLex(a, min_slope=1, - min_part=1) for a in alpha]): + for p in product(*[IntegerListsLex(a, min_slope=1, min_part=1) for a in alpha]): yield tuple(frozenset(k) for k in p) @@ -2962,7 +2952,7 @@ def _iterator_order(A, d, lengths=None): n = len(A) if not lengths: if d: - lengths = range(max(1, d // n), d+1) + lengths = range(max(1, d // n), d + 1) else: lengths = (0,) @@ -3021,8 +3011,8 @@ def _break_at_descents(alpha, weak=True): Blocks = [] block = [alpha[0]] - for i in range(1,len(alpha)): - if (alpha[i-1] > alpha[i]) or (alpha[i-1] == alpha[i] and weak): + for i in range(1, len(alpha)): + if (alpha[i - 1] > alpha[i]) or (alpha[i - 1] == alpha[i] and weak): Blocks.append(block) block = [alpha[i]] else: @@ -3079,13 +3069,13 @@ def _refine_block(S, strong=False): n = len(X) out = [] if not strong: - WordSet = IntegerListsLex(min_part=0, max_part=n-1, length=n) + WordSet = IntegerListsLex(min_part=0, max_part=n - 1, length=n) else: - WordSet = IntegerListsLex(min_part=0, max_part=n-1, length=n, min_slope=0) + WordSet = IntegerListsLex(min_part=0, max_part=n - 1, length=n, min_slope=0) for w in WordSet: if _is_initial_segment(sorted(set(w))): - a = [frozenset() for _ in range(max(w)+1)] + a = [frozenset() for _ in range(max(w) + 1)] for pos in range(n): a[w[pos]] = a[w[pos]].union({X[pos]}) out.append(tuple(a)) @@ -3106,7 +3096,7 @@ def _is_initial_segment(lst): sage: _is_initial_segment([0]) True """ - return list(range(max(lst)+1)) == lst + return list(range(max(lst) + 1)) == lst def _split_block(S, k=2): @@ -3138,7 +3128,7 @@ def _split_block(S, k=2): X = sorted(S, key=str) n = len(X) out = [] - for w in IntegerListsLex(min_part=0, max_part=k-1, length=n): + for w in IntegerListsLex(min_part=0, max_part=k - 1, length=n): a = [frozenset() for _ in range(k)] for pos in range(n): a[w[pos]] = a[w[pos]].union({X[pos]}) @@ -3170,17 +3160,17 @@ def _to_minimaj_blocks(T): True """ mu = [(i,) for i in T[-1]] - breaks = [0] + _descents(T[-1]) + [len(mu)-1] - T = [T[i][::-1] for i in range(len(T)-1)][::-1] - for f in range(len(breaks)-1): - for j in range(breaks[f],breaks[f+1]+1): - mu[j] += tuple(i for i in T[f] if (mu[j][0] < i or j == breaks[f]) - and (j == breaks[f+1] or i <= mu[j+1][0])) + breaks = [0] + _descents(T[-1]) + [len(mu) - 1] + T = [T[i][::-1] for i in range(len(T) - 1)][::-1] + for f in range(len(breaks) - 1): + for j in range(breaks[f], breaks[f + 1] + 1): + mu[j] += tuple(i for i in T[f] if (mu[j][0] < i or j == breaks[f]) and (j == breaks[f + 1] or i <= mu[j + 1][0])) return tuple(mu) ############### + class MinimajCrystal(UniqueRepresentation, Parent): r""" Crystal of ordered multiset partitions into sets with `ell` letters from @@ -3242,9 +3232,9 @@ def __init__(self, n, ell, k): raise TypeError("n (=%s), ell (=%s), and k (=%s) must all be positive integers" % (n, ell, k)) if not all([n > 0, ell >= k, k > 0]): raise ValueError("n (=%s), ell (=%s), and k (=%s) must all be positive integers" % (n, ell, k)) - self._cartan_type = CartanType(['A',n-1]) - B = Letters(['A', n-1]) - T = tensor([B]*ell) + self._cartan_type = CartanType(['A', n - 1]) + B = Letters(['A', n - 1]) + T = tensor([B] * ell) self._BT = (B, T) self._OMPs = OrderedMultisetPartitionsIntoSets(n, ell, length=k) self.module_generators = [] @@ -3252,7 +3242,7 @@ def __init__(self, n, ell, k): t = co.to_tableaux_words() word = T(*[B(a) for a in _concatenate(t)]) blocks = [len(h) for h in t] - breaks = tuple([0]+running_total(blocks)) + breaks = tuple([0] + running_total(blocks)) mu = self.element_class(self, (word, breaks)) self.module_generators.append(mu) @@ -3265,8 +3255,7 @@ def _repr_(self): sage: B = crystals.Minimaj(3,4,2); B # needs sage.modules Minimaj Crystal of type A_2 of words of length 4 into 2 blocks """ - return ("Minimaj Crystal of type A_%s of words of length %s into %s blocks" - % (self.n-1, self.ell, self.k)) + return "Minimaj Crystal of type A_%s of words of length %s into %s blocks" % (self.n - 1, self.ell, self.k) def _an_element_(self): """ @@ -3288,8 +3277,8 @@ def _an_element_(self): EmptySetError """ t = self._OMPs.an_element().to_tableaux_words() - breaks = tuple([0]+running_total([len(h) for h in t])) - B,T = self._BT + breaks = tuple([0] + running_total([len(h) for h in t])) + B, T = self._BT return self.element_class(self, (T(*[B(a) for a in _concatenate(t)]), breaks)) def _element_constructor_(self, x): @@ -3317,8 +3306,8 @@ def _element_constructor_(self, x): x = list(x) if x in self: t = self._OMPs(x).to_tableaux_words() - breaks = tuple([0]+running_total([len(h) for h in t])) - B,T = self._BT + breaks = tuple([0] + running_total([len(h) for h in t])) + B, T = self._BT return self.element_class(self, (T(*[B(a) for a in _concatenate(t)]), breaks)) raise ValueError("cannot convert %s into an element of %s" % (x, self)) @@ -3405,8 +3394,7 @@ def val(self, q='q'): Sym = SymmetricFunctions(ZZ[q]) q = Sym.base_ring().gens()[0] s = Sym.schur() - return sum((q**(t.minimaj()) * s[sorted(t.weight().values(), reverse=True)] - for t in H), Sym.zero()) + return sum((q ** (t.minimaj()) * s[sorted(t.weight().values(), reverse=True)] for t in H), Sym.zero()) class Element(ElementWrapper): r""" @@ -3499,8 +3487,7 @@ def to_tableaux_words(self): [[3, 1], [], [4, 3, 3]] """ w, breaks = self.value - return [[ZZ(w[a].value) for a in range(breaks[j], breaks[j+1])] - for j in range(len(breaks)-1)] + return [[ZZ(w[a].value) for a in range(breaks[j], breaks[j + 1])] for j in range(len(breaks) - 1)] def e(self, i): r""" diff --git a/src/sage/combinat/ncsf_qsym/all.py b/src/sage/combinat/ncsf_qsym/all.py index 4f14f228111..8073b0cd835 100644 --- a/src/sage/combinat/ncsf_qsym/all.py +++ b/src/sage/combinat/ncsf_qsym/all.py @@ -7,8 +7,10 @@ - :ref:`Quasi-Symmetric Functions (QSym) ` - :ref:`sage.combinat.ncsf_qsym.generic_basis_code` """ + # install the docstring of this module to the containing package from sage.misc.namespace_package import install_doc + install_doc(__package__, __doc__) from sage.misc.lazy_import import lazy_import diff --git a/src/sage/combinat/ncsf_qsym/combinatorics.py b/src/sage/combinat/ncsf_qsym/combinatorics.py index f8b1fb4eaa1..9e255696504 100644 --- a/src/sage/combinat/ncsf_qsym/combinatorics.py +++ b/src/sage/combinat/ncsf_qsym/combinatorics.py @@ -16,6 +16,7 @@ Cauchy Identity, and Hall Scalar Product*, :arxiv:`0712.2201v1`. """ + from sage.misc.misc_c import prod from sage.arith.misc import factorial from sage.misc.cachefunc import cached_function @@ -29,6 +30,7 @@ # Complete.module_morphism( coeff = coeff_pi, codomain=Psi, triangularity="finer" ) # the difficulty is how to best describe the support of the output. + def coeff_pi(J, I): r""" Return the coefficient `\pi_{J,I}` as defined in [NCSF]_. @@ -114,7 +116,7 @@ def coeff_sp(J, I): sage: coeff_sp(Composition([2,1]), Composition([3])) 4 """ - return prod(factorial(len(K))*prod(K) for K in J.refinement_splitting(I)) + return prod(factorial(len(K)) * prod(K) for K in J.refinement_splitting(I)) def coeff_dab(I, J): @@ -168,8 +170,10 @@ def compositions_order(n): sage: compositions_order(4) [[4], [3, 1], [1, 3], [2, 2], [2, 1, 1], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]] """ + def _keyfunction(I): return sorted(I, reverse=True), list(I) + return sorted(Compositions(n), key=_keyfunction, reverse=True) @@ -206,8 +210,8 @@ def m_to_s_stat(R, I, K): for J in Compositions(I.size()): if I.is_finer(J) and K.is_finer(J): pvec = [0] + Composition(I).refinement_splitting_lengths(J).partial_sums() - pp = prod( R( len(I) - pvec[i] ) for i in range( len(pvec)-1 ) ) - stat += R((-1)**(len(I)-len(K)) / pp * coeff_lp(K, J)) + pp = prod(R(len(I) - pvec[i]) for i in range(len(pvec) - 1)) + stat += R((-1) ** (len(I) - len(K)) / pp * coeff_lp(K, J)) return stat @@ -240,11 +244,11 @@ def number_of_fCT(content_comp, shape_comp): if shape_comp.to_partition().length() == 1: return 1 return 0 - C = Compositions(content_comp.size()-content_comp[-1], outer=list(shape_comp)) + C = Compositions(content_comp.size() - content_comp[-1], outer=list(shape_comp)) s = 0 for x in C: - if len(x) >= len(shape_comp)-1: - s += number_of_fCT(Composition(content_comp[:-1]),x) + if len(x) >= len(shape_comp) - 1: + s += number_of_fCT(Composition(content_comp[:-1]), x) return s @@ -291,24 +295,15 @@ def number_of_SSRCT(content_comp, shape_comp): return ZZ.one() return ZZ.zero() s = ZZ.zero() - cond = lambda al, be: all(al[j] <= be_val - and not any(al[i] <= k <= be[i] - for k in range(al[j], be_val) - for i in range(j)) - for j, be_val in enumerate(be)) - C = Compositions(content_comp.size()-content_comp[0], - inner=[1]*len(shape_comp), - outer=list(shape_comp)) + cond = lambda al, be: all(al[j] <= be_val and not any(al[i] <= k <= be[i] for k in range(al[j], be_val) for i in range(j)) for j, be_val in enumerate(be)) + C = Compositions(content_comp.size() - content_comp[0], inner=[1] * len(shape_comp), outer=list(shape_comp)) for x in C: if cond(x, shape_comp): s += number_of_SSRCT(Composition(content_comp[1:]), x) if shape_comp[0] <= content_comp[0]: - C = Compositions(content_comp.size()-content_comp[0], - inner=[min(val, shape_comp[0]+1) - for val in shape_comp[1:]], - outer=shape_comp[1:]) + C = Compositions(content_comp.size() - content_comp[0], inner=[min(val, shape_comp[0] + 1) for val in shape_comp[1:]], outer=shape_comp[1:]) Comps = Compositions() for x in C: - if cond([shape_comp[0]]+list(x), shape_comp): + if cond([shape_comp[0]] + list(x), shape_comp): s += number_of_SSRCT(Comps(content_comp[1:]), x) return s diff --git a/src/sage/combinat/ncsf_qsym/generic_basis_code.py b/src/sage/combinat/ncsf_qsym/generic_basis_code.py index f1c657b8728..f3dca7ca55a 100644 --- a/src/sage/combinat/ncsf_qsym/generic_basis_code.py +++ b/src/sage/combinat/ncsf_qsym/generic_basis_code.py @@ -76,9 +76,8 @@ def super_categories(self): R = self.base().base_ring() from sage.categories.graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis from sage.categories.graded_hopf_algebras import GradedHopfAlgebras - return [self.base().Realizations(), - GradedHopfAlgebrasWithBasis(R), - GradedHopfAlgebras(R).Realizations()] + + return [self.base().Realizations(), GradedHopfAlgebrasWithBasis(R), GradedHopfAlgebras(R).Realizations()] class ParentMethods: @@ -168,7 +167,7 @@ def sum_of_finer_compositions(self, composition): R[1, 1, 1, 1] + R[1, 1, 2] + R[1, 2, 1] + R[1, 3] """ - return self.sum_of_monomials( compo for compo in composition.finer() ) + return self.sum_of_monomials(compo for compo in composition.finer()) def sum_of_fatter_compositions(self, composition): r""" @@ -192,7 +191,7 @@ def sum_of_fatter_compositions(self, composition): sage: R.sum_of_fatter_compositions(Composition([1,3])) R[1, 3] + R[4] """ - return self.sum_of_monomials( compo for compo in composition.fatter() ) + return self.sum_of_monomials(compo for compo in composition.fatter()) def alternating_sum_of_compositions(self, n): r""" @@ -229,8 +228,7 @@ def alternating_sum_of_compositions(self, n): S[1, 1, 1] - S[1, 2] - S[2, 1] + S[3] """ ring = self.base_ring() - return (-ring.one())**(n)*self.sum_of_terms( - (compo, ring((-1)**(len(compo)))) for compo in Compositions(n) ) + return (-ring.one()) ** (n) * self.sum_of_terms((compo, ring((-1) ** (len(compo)))) for compo in Compositions(n)) def alternating_sum_of_finer_compositions(self, composition, conjugate=False): """ @@ -272,7 +270,7 @@ def alternating_sum_of_finer_compositions(self, composition, conjugate=False): composition = composition.conjugate() l = len(composition) ring = self.base_ring() - return self.sum_of_terms( (compo, ring((-1)**(len(compo)-l))) for compo in composition.finer() ) + return self.sum_of_terms((compo, ring((-1) ** (len(compo) - l))) for compo in composition.finer()) def alternating_sum_of_fatter_compositions(self, composition): """ @@ -309,7 +307,7 @@ def alternating_sum_of_fatter_compositions(self, composition): """ l = len(composition) ring = self.base_ring() - return self.sum_of_terms( (compo, ring((-1)**(len(compo)-l))) for compo in composition.fatter() ) + return self.sum_of_terms((compo, ring((-1) ** (len(compo) - l))) for compo in composition.fatter()) def sum_of_partition_rearrangements(self, par): """ @@ -336,7 +334,7 @@ def sum_of_partition_rearrangements(self, par): sage: elementary.sum_of_partition_rearrangements(Partition([])) L[] """ - return self.sum_of_monomials( self._indices(comp) for comp in Permutations(par) ) + return self.sum_of_monomials(self._indices(comp) for comp in Permutations(par)) def _comp_to_par(self, comp): """ @@ -470,9 +468,7 @@ def skew(self, x, y, side='left'): x = self(x) y = self.dual()(y) v = 1 if side == 'left' else 0 - return self.sum(coeff * y[IJ[1-v]] * self[IJ[v]] - for (IJ, coeff) in x.coproduct() - if IJ[1-v] in y.support()) + return self.sum(coeff * y[IJ[1 - v]] * self[IJ[v]] for (IJ, coeff) in x.coproduct() if IJ[1 - v] in y.support()) return self._skew_by_coercion(x, y, side=side) def _skew_by_coercion(self, x, y, side='left'): @@ -704,12 +700,11 @@ def duality_pairing_matrix(self, basis, degree): [1] """ from sage.matrix.constructor import matrix + # TODO: generalize to keys indexing the basis of the graded component from sage.combinat.composition import Compositions - return matrix(self.base_ring(), - [[self.duality_pairing(self[I], basis[J]) - for J in Compositions(degree)] - for I in Compositions(degree)]) + + return matrix(self.base_ring(), [[self.duality_pairing(self[I], basis[J]) for J in Compositions(degree)] for I in Compositions(degree)]) def counit_on_basis(self, I): r""" @@ -791,9 +786,7 @@ def degree_negation(self, element): Generalize this to all graded vector spaces? """ - return self.sum_of_terms([ (lam, (-1)**(sum(lam) % 2) * a) - for lam, a in self(element) ], - distinct=True) + return self.sum_of_terms([(lam, (-1) ** (sum(lam) % 2) * a) for lam, a in self(element)], distinct=True) class ElementMethods: @@ -835,9 +828,7 @@ def degree_negation(self): Generalize this to all graded vector spaces? """ - return self.parent().sum_of_terms([ (lam, (-1)**(sum(lam) % 2) * a) - for lam, a in self ], - distinct=True) + return self.parent().sum_of_terms([(lam, (-1) ** (sum(lam) % 2) * a) for lam, a in self], distinct=True) def duality_pairing(self, y): r""" @@ -981,7 +972,7 @@ def degree(self): return self.maximal_degree() -class AlgebraMorphism(ModuleMorphismByLinearity): # Find a better name +class AlgebraMorphism(ModuleMorphismByLinearity): # Find a better name """ A class for algebra morphism defined on a free algebra from the image of the generators """ @@ -1072,10 +1063,7 @@ def __init__(self, domain, on_generators, position=0, codomain=None, category=No category = AlgebrasWithBasis(domain.base_ring()) self._anti = anti self._on_generators = on_generators - ModuleMorphismByLinearity.__init__(self, domain=domain, - codomain=codomain, - position=position, - category=category) + ModuleMorphismByLinearity.__init__(self, domain=domain, codomain=codomain, position=position, category=category) def __eq__(self, other): """ @@ -1092,12 +1080,7 @@ def __eq__(self, other): sage: f is g False """ - return (self.__class__ is other.__class__ and self.parent() == other.parent() - and self._zero == other._zero - and self._on_generators == other._on_generators - and self._position == other._position - and self._is_module_with_basis_over_same_base_ring - == other._is_module_with_basis_over_same_base_ring) + return self.__class__ is other.__class__ and self.parent() == other.parent() and self._zero == other._zero and self._on_generators == other._on_generators and self._position == other._position and self._is_module_with_basis_over_same_base_ring == other._is_module_with_basis_over_same_base_ring def __ne__(self, other): """ @@ -1156,6 +1139,7 @@ class GradedModulesWithInternalProduct(Category_over_base_ring): sage: R in GradedModulesWithInternalProduct(QQ) True """ + @cached_method def super_categories(self): """ @@ -1166,6 +1150,7 @@ def super_categories(self): [Category of graded modules over Integer Ring] """ from sage.categories.graded_modules import GradedModules + R = self.base_ring() return [GradedModules(R)] @@ -1233,11 +1218,7 @@ def internal_product(self): 0 """ if self.internal_product_on_basis is not NotImplemented: - return self.module_morphism( - self.module_morphism(self.internal_product_on_basis, - position=0, - codomain=self), - position=1) + return self.module_morphism(self.module_morphism(self.internal_product_on_basis, position=0, codomain=self), position=1) return self.internal_product_by_coercion itensor = internal_product diff --git a/src/sage/combinat/ncsf_qsym/ncsf.py b/src/sage/combinat/ncsf_qsym/ncsf.py index 551f9f56879..b9ada306095 100644 --- a/src/sage/combinat/ncsf_qsym/ncsf.py +++ b/src/sage/combinat/ncsf_qsym/ncsf.py @@ -35,8 +35,7 @@ from sage.combinat.composition import Compositions from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.ncsf_qsym.generic_basis_code import BasesOfQSymOrNCSF -from sage.combinat.ncsf_qsym.combinatorics import (coeff_pi, coeff_lp, - coeff_sp, coeff_ell, m_to_s_stat, number_of_fCT, number_of_SSRCT, compositions_order) +from sage.combinat.ncsf_qsym.combinatorics import coeff_pi, coeff_lp, coeff_sp, coeff_ell, m_to_s_stat, number_of_fCT, number_of_SSRCT, compositions_order from sage.combinat.partition import Partition from sage.combinat.permutation import Permutations from sage.matrix.constructor import matrix @@ -422,25 +421,17 @@ def __init__(self, R) -> None: ribbon = self.ribbon() # complete to ribbon, and back - complete.module_morphism(ribbon.sum_of_fatter_compositions, - codomain=ribbon).register_as_coercion() - ribbon.module_morphism(complete.alternating_sum_of_fatter_compositions, - codomain=complete).register_as_coercion() - - complete.algebra_morphism(elementary.alternating_sum_of_compositions, - codomain=elementary).register_as_coercion() - elementary.algebra_morphism(complete.alternating_sum_of_compositions, - codomain=complete).register_as_coercion() - - complete.algebra_morphism(Psi._from_complete_on_generators, - codomain=Psi).register_as_coercion() - Psi.algebra_morphism(Psi._to_complete_on_generators, - codomain=complete).register_as_coercion() - - complete.algebra_morphism(Phi._from_complete_on_generators, - codomain=Phi).register_as_coercion() - Phi.algebra_morphism(Phi._to_complete_on_generators, - codomain=complete).register_as_coercion() + complete.module_morphism(ribbon.sum_of_fatter_compositions, codomain=ribbon).register_as_coercion() + ribbon.module_morphism(complete.alternating_sum_of_fatter_compositions, codomain=complete).register_as_coercion() + + complete.algebra_morphism(elementary.alternating_sum_of_compositions, codomain=elementary).register_as_coercion() + elementary.algebra_morphism(complete.alternating_sum_of_compositions, codomain=complete).register_as_coercion() + + complete.algebra_morphism(Psi._from_complete_on_generators, codomain=Psi).register_as_coercion() + Psi.algebra_morphism(Psi._to_complete_on_generators, codomain=complete).register_as_coercion() + + complete.algebra_morphism(Phi._from_complete_on_generators, codomain=Phi).register_as_coercion() + Phi.algebra_morphism(Phi._to_complete_on_generators, codomain=complete).register_as_coercion() def _repr_(self) -> str: # could be taken care of by the category r""" @@ -469,8 +460,7 @@ def a_realization(self): """ return self.complete() - _shorthands = ('S', 'R', 'L', 'Phi', 'Psi', 'nM', 'I', - 'dQS', 'dYQS', 'ZL', 'ZR') + _shorthands = ('S', 'R', 'L', 'Phi', 'Psi', 'nM', 'I', 'dQS', 'dYQS', 'ZL', 'ZR') def dual(self): r""" @@ -488,6 +478,7 @@ def dual(self): Quasisymmetric functions over the Rational Field """ from sage.combinat.ncsf_qsym.qsym import QuasiSymmetricFunctions + return QuasiSymmetricFunctions(self.base_ring()) class Bases(Category_realization_of_parent): @@ -520,8 +511,8 @@ def super_categories(self): """ R = self.base().base_ring() from .generic_basis_code import GradedModulesWithInternalProduct - return [BasesOfQSymOrNCSF(self.base()), - GradedModulesWithInternalProduct(R).Realizations()] + + return [BasesOfQSymOrNCSF(self.base()), GradedModulesWithInternalProduct(R).Realizations()] class ParentMethods: @@ -833,8 +824,7 @@ def verschiebung(self, n): parent = self.parent() S = parent.realization_of().S() C = parent._indices - dct = {C([i // n for i in I]): coeff - for (I, coeff) in S(self) if all(i % n == 0 for i in I)} + dct = {C([i // n for i in I]): coeff for (I, coeff) in S(self) if all(i % n == 0 for i in I)} return parent(S._from_dict(dct)) def bernstein_creation_operator(self, n): @@ -1619,6 +1609,7 @@ def to_descent_algebra(self, n=None): else: n = self.degree() from sage.combinat.descent_algebra import DescentAlgebra + S = NonCommutativeSymmetricFunctions(self.base_ring()).S() S_expansion = S(self) B = DescentAlgebra(self.base_ring(), n).B() @@ -1665,7 +1656,7 @@ def to_symmetric_group_algebra(self): """ S = NonCommutativeSymmetricFunctions(self.base_ring()).S() S_expansion = S(self) - return sum(S_expansion.coefficient(I)*S._to_symmetric_group_algebra_on_basis(I) for I in S_expansion.support()) + return sum(S_expansion.coefficient(I) * S._to_symmetric_group_algebra_on_basis(I) for I in S_expansion.support()) # TODO: # This is ugly (uses global sum function) and undefined if self # is not homogeneous. Improve? @@ -1785,6 +1776,7 @@ def to_ncsym(self): """ from sage.combinat.ncsym.ncsym import SymmetricFunctionsNonCommutingVariables from sage.combinat.set_partition import SetPartitions + P = self.parent() S = P.realization_of().complete() R = P.base_ring() @@ -1797,12 +1789,10 @@ def on_basis(I): def c_num(A): return R(prod(factorial(i) for i in A.shape())) - return prod(m.sum_of_terms([(SP(A), R(c_num(A) / factorial(n))) - for A in SetPartitions(n)], distinct=True) - for n in I) - return m.linear_combination((on_basis(I), coeff) - for I, coeff in S(self)) + return prod(m.sum_of_terms([(SP(A), R(c_num(A) / factorial(n))) for A in SetPartitions(n)], distinct=True) for n in I) + + return m.linear_combination((on_basis(I), coeff) for I, coeff in S(self)) def to_fqsym(self): r""" @@ -1854,14 +1844,15 @@ def to_fqsym(self): + F[4, 1, 2, 3] + F[4, 2, 1, 3] + F[4, 2, 3, 1] """ from sage.combinat.fqsym import FreeQuasisymmetricFunctions + P = self.parent() S = P.realization_of().complete() F = FreeQuasisymmetricFunctions(P.base_ring()).F() def on_basis(I): - return F.prod(F[Permutations(i)(range(1, i+1))] for i in I) - return F.linear_combination((on_basis(I), coeff) - for I, coeff in S(self)) + return F.prod(F[Permutations(i)(range(1, i + 1))] for i in I) + + return F.linear_combination((on_basis(I), coeff) for I, coeff in S(self)) def to_fsym(self): r""" @@ -1908,6 +1899,7 @@ def to_fsym(self): G[12|3] + G[123] """ from sage.combinat.chas.fsym import FreeSymmetricFunctions + G = FreeSymmetricFunctions(self.base_ring()).G() return G(self) @@ -1979,6 +1971,7 @@ def expand(self, n, alphabet='x'): NSym = self.parent().realization_of() L = NSym.L() from sage.algebras.free_algebra import FreeAlgebra + P = FreeAlgebra(NSym.base_ring(), n, alphabet) x = P.gens() @@ -1989,10 +1982,11 @@ def image_of_L_k(k, i): return P.one() if k > i: return P.zero() - return x[i-1] * image_of_L_k(k - 1, i - 1) + image_of_L_k(k, i - 1) + return x[i - 1] * image_of_L_k(k - 1, i - 1) + image_of_L_k(k, i - 1) def on_basis(comp): return P.prod(image_of_L_k(k, n) for k in comp) + return L._apply_module_morphism(L(self), on_basis, codomain=P) class MultiplicativeBases(Category_realization_of_parent): @@ -2049,6 +2043,7 @@ def algebra_generators(self): """ from sage.sets.family import Family from sage.sets.positive_integers import PositiveIntegers + return Family(PositiveIntegers(), lambda i: self.monomial(self._indices([i]))) def product_on_basis(self, composition1, composition2): @@ -2135,9 +2130,10 @@ def algebra_morphism(self, on_generators, **keywords): Category of endsets of modules with basis over Rational Field """ from sage.combinat.ncsf_qsym.generic_basis_code import AlgebraMorphism + return AlgebraMorphism(self, on_generators, **keywords) - def to_symmetric_function_on_generators( self, i ): + def to_symmetric_function_on_generators(self, i): r""" Morphism of the generators to symmetric functions. @@ -2242,6 +2238,7 @@ def coproduct(self): To: Non-Commutative Symmetric Functions over the Rational Field in the Complete basis # Non-Commutative Symmetric Functions over the Rational Field in the Complete basis """ from sage.categories.tensor import tensor + if hasattr(self, "coproduct_on_generators"): return self.algebra_morphism(self.coproduct_on_generators, codomain=tensor([self, self])) return NotImplemented @@ -2327,7 +2324,7 @@ def antipode_on_basis(self, composition): sage: S[2,3].coproduct().apply_multilinear_morphism(lambda be,ga: S(be).antipode()*S(ga)) 0 """ - return (-1)**len(composition) * self.alternating_sum_of_finer_compositions(composition.reversed()) + return (-1) ** len(composition) * self.alternating_sum_of_finer_compositions(composition.reversed()) # @cached_method? def coproduct_on_generators(self, i): @@ -2360,8 +2357,9 @@ def coproduct_on_generators(self, i): def C(i): return self._indices([i]) if i else self._indices([]) + T = self.tensor_square() - return T.sum_of_monomials( (C(j), C(i-j)) for j in range(i+1) ) + return T.sum_of_monomials((C(j), C(i - j)) for j in range(i + 1)) class MultiplicativeBasesOnPrimitiveElements(Category_realization_of_parent): r""" @@ -2448,7 +2446,7 @@ def antipode_on_generators(self, i): """ if i < 1: raise ValueError("Not a positive integer: {}".format(i)) - return - self.algebra_generators()[i] + return -self.algebra_generators()[i] def coproduct_on_generators(self, i): r""" @@ -2479,6 +2477,7 @@ def coproduct_on_generators(self, i): raise ValueError("Not a positive integer: {}".format(i)) x = self.algebra_generators()[i] from sage.categories.tensor import tensor + return tensor([self.one(), x]) + tensor([x, self.one()]) class Ribbon(CombinatorialFreeModule, BindableClass): @@ -2553,9 +2552,7 @@ def __init__(self, NCSF): sage: all(R(L(R[comp])) == R[comp] for comp in Compositions(5)) True """ - CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), - prefix='R', bracket=False, - category=NCSF.Bases()) + CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), prefix='R', bracket=False, category=NCSF.Bases()) def dual(self): r""" @@ -2604,8 +2601,7 @@ def product_on_basis(self, I, J): return self.monomial(J) if not J._list: return self.monomial(I) - return self.monomial(self._indices(I[:] + J[:])) + \ - self.monomial(self._indices(I[:-1] + [I[-1]+J[0]] + J[1:])) + return self.monomial(self._indices(I[:] + J[:])) + self.monomial(self._indices(I[:-1] + [I[-1] + J[0]] + J[1:])) def antipode_on_basis(self, composition): """ @@ -2641,7 +2637,7 @@ def antipode_on_basis(self, composition): """ if composition.size() % 2 == 0: return self[composition.conjugate()] - return - self[composition.conjugate()] + return -self[composition.conjugate()] def to_symmetric_function_on_basis(self, I): r""" @@ -2809,11 +2805,10 @@ def ribbon_mapper(I, coeff): J = I.meet([n] * m) Jn = C([j // n for j in J]) if (len(I) - len(J)) % 2: - return (Jn, - coeff) + return (Jn, -coeff) return (Jn, coeff) - return parent.sum_of_terms([ribbon_mapper(I, coeff) - for (I, coeff) in self - if sum(I) % n == 0]) + + return parent.sum_of_terms([ribbon_mapper(I, coeff) for (I, coeff) in self if sum(I) % n == 0]) def star_involution(self): r""" @@ -2944,9 +2939,7 @@ def __init__(self, NCSF): sage: S = NonCommutativeSymmetricFunctions(QQ).complete() sage: TestSuite(S).run() """ - CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), - prefix='S', bracket=False, - category=NCSF.MultiplicativeBasesOnGroupLikeElements()) + CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), prefix='S', bracket=False, category=NCSF.MultiplicativeBasesOnGroupLikeElements()) def dual(self): r""" @@ -2991,6 +2984,7 @@ def internal_product_on_basis(self, I, J): 0 """ from sage.combinat.integer_matrices import IntegerMatrices + IM = IntegerMatrices(I, J) return self.sum_of_monomials(IM.to_composition(m) for m in IM) @@ -3021,7 +3015,7 @@ def to_symmetric_function_on_basis(self, I): h[] """ h = SymmetricFunctions(self.base_ring()).complete() - return h[Partition(sorted(I,reverse=True))] + return h[Partition(sorted(I, reverse=True))] @lazy_attribute def to_symmetric_function(self): @@ -3083,12 +3077,12 @@ def _to_symmetric_group_algebra_on_basis(self, I): n = sum(I) from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra from sage.sets.set import Set + if n == 0: - return SymmetricGroupAlgebra(self.base_ring(),n).one() - sga = SymmetricGroupAlgebra(self.base_ring(),n) - J = [j-1 for j in I.to_subset()] - return sga.sum_of_monomials( p for K in Set(J).subsets() - for p in Permutations(descents=(K,n)) ) + return SymmetricGroupAlgebra(self.base_ring(), n).one() + sga = SymmetricGroupAlgebra(self.base_ring(), n) + J = [j - 1 for j in I.to_subset()] + return sga.sum_of_monomials(p for K in Set(J).subsets() for p in Permutations(descents=(K, n))) class Element(CombinatorialFreeModule.Element): """ @@ -3168,9 +3162,7 @@ def psi_involution(self): True """ parent = self.parent() - return parent.sum( (-1) ** (I.size() - len(I)) * coeff - * parent.alternating_sum_of_finer_compositions(I) - for I, coeff in self._monomial_coefficients.items() ) + return parent.sum((-1) ** (I.size() - len(I)) * coeff * parent.alternating_sum_of_finer_compositions(I) for I, coeff in self._monomial_coefficients.items()) S = complete = Complete @@ -3242,9 +3234,7 @@ def __init__(self, NCSF): sage: all(L(S(L[comp])) == L[comp] for comp in Compositions(5)) True """ - CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), - prefix='L', bracket=False, - category=NCSF.MultiplicativeBasesOnGroupLikeElements()) + CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), prefix='L', bracket=False, category=NCSF.MultiplicativeBasesOnGroupLikeElements()) class Element(CombinatorialFreeModule.Element): @@ -3379,11 +3369,7 @@ def verschiebung(self, n): """ parent = self.parent() C = parent._indices - return parent.sum_of_terms([(C([i // n for i in I]), - coeff * (-1) ** (sum(I) * (n-1) // n)) - for (I, coeff) in self - if all(i % n == 0 for i in I)], - distinct=True) + return parent.sum_of_terms([(C([i // n for i in I]), coeff * (-1) ** (sum(I) * (n - 1) // n)) for (I, coeff) in self if all(i % n == 0 for i in I)], distinct=True) def star_involution(self): r""" @@ -3543,10 +3529,7 @@ def psi_involution(self): True """ parent = self.parent() - return parent.sum( (-1) ** (I.size() - len(I)) * coeff - * parent.alternating_sum_of_finer_compositions(I) - for I, coeff in - self._monomial_coefficients.items() ) + return parent.sum((-1) ** (I.size() - len(I)) * coeff * parent.alternating_sum_of_finer_compositions(I) for I, coeff in self._monomial_coefficients.items()) L = elementary = Elementary @@ -3635,9 +3618,7 @@ def __init__(self, NCSF): sage: all(Psi(S(Psi[comp])) == Psi[comp] for comp in Compositions(5)) True """ - CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), - prefix='Psi', bracket=False, - category=NCSF.MultiplicativeBasesOnPrimitiveElements()) + CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), prefix='Psi', bracket=False, category=NCSF.MultiplicativeBasesOnPrimitiveElements()) def _from_complete_on_generators(self, n): r""" @@ -3665,8 +3646,7 @@ def _from_complete_on_generators(self, n): # Equation (58) of NCSF I article one = self.base_ring().one() I = self._indices([n]) - return self.sum_of_terms( ( (J, one/coeff_pi(J,I)) for J in Compositions(n) ), - distinct=True ) + return self.sum_of_terms(((J, one / coeff_pi(J, I)) for J in Compositions(n)), distinct=True) def _to_complete_on_generators(self, n): r""" @@ -3701,8 +3681,7 @@ def _to_complete_on_generators(self, n): """ minus_one = -self.base_ring().one() complete = self.realization_of().complete() - return complete.sum_of_terms( ((J, minus_one**(len(J)+1)*coeff_lp(J,[n])) - for J in Compositions(n)), distinct=True ) + return complete.sum_of_terms(((J, minus_one ** (len(J) + 1) * coeff_lp(J, [n])) for J in Compositions(n)), distinct=True) def internal_product_on_basis_by_bracketing(self, I, J): r""" @@ -3846,8 +3825,8 @@ def Gamma(K): # part is now the last part of K. # Find a part `K_k` such that `|J_{K_k}| = I_k` - Ik = I[len(K) - 1] # -1 for indexing - cur_sum = sum(J[j] for j in part[:-1]) # The last entry hasn't been added yet + Ik = I[len(K) - 1] # -1 for indexing + cur_sum = sum(J[j] for j in part[:-1]) # The last entry hasn't been added yet while cur_sum != Ik: part[-1] += 1 @@ -3862,7 +3841,7 @@ def Gamma(K): elif part[-1] in base and cur_sum + J[part[-1]] <= Ik: cur_sum += J[part[-1]] base.remove(part[-1]) - if cur_sum < Ik: # Still more work to do + if cur_sum < Ik: # Still more work to do part.append(part[-1]) # If the last part is empty (i.e. we didn't find a part): backtrack @@ -4016,11 +3995,7 @@ def verschiebung(self, n): """ parent = self.parent() C = parent._indices - return parent.sum_of_terms([(C([i // n for i in I]), - coeff * (n ** len(I))) - for (I, coeff) in self - if all(i % n == 0 for i in I)], - distinct=True) + return parent.sum_of_terms([(C([i // n for i in I]), coeff * (n ** len(I))) for (I, coeff) in self if all(i % n == 0 for i in I)], distinct=True) class Phi(CombinatorialFreeModule, BindableClass): r""" @@ -4077,9 +4052,7 @@ def __init__(self, NCSF): sage: all(Phi(S(Phi[comp])) == Phi[comp] for comp in Compositions(5)) True """ - CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), - prefix='Phi', bracket=False, - category=NCSF.MultiplicativeBasesOnPrimitiveElements()) + CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), prefix='Phi', bracket=False, category=NCSF.MultiplicativeBasesOnPrimitiveElements()) def _from_complete_on_generators(self, n): r""" @@ -4106,8 +4079,7 @@ def _from_complete_on_generators(self, n): """ # Proposition 4.9 of NCSF I article one = self.base_ring().one() - return self.sum_of_terms( ( (J, one / coeff_sp(J,[n])) for J in Compositions(n) ), - distinct=True ) + return self.sum_of_terms(((J, one / coeff_sp(J, [n])) for J in Compositions(n)), distinct=True) def _to_complete_on_generators(self, n): r""" @@ -4135,9 +4107,7 @@ def _to_complete_on_generators(self, n): # Proposition 4.9 of NCSF I article minus_one = -self.base_ring().one() complete = self.realization_of().complete() - return complete.sum_of_terms( ( (J, minus_one**(len(J)+1) * n / coeff_ell(J,[n])) - for J in Compositions(n) ), - distinct=True ) + return complete.sum_of_terms(((J, minus_one ** (len(J) + 1) * n / coeff_ell(J, [n])) for J in Compositions(n)), distinct=True) class Element(CombinatorialFreeModule.Element): @@ -4274,11 +4244,7 @@ def verschiebung(self, n): """ parent = self.parent() C = parent._indices - return parent.sum_of_terms([(C([i // n for i in I]), - coeff * (n ** len(I))) - for (I, coeff) in self - if all(i % n == 0 for i in I)], - distinct=True) + return parent.sum_of_terms([(C([i // n for i in I]), coeff * (n ** len(I))) for (I, coeff) in self if all(i % n == 0 for i in I)], distinct=True) def star_involution(self): r""" @@ -4471,24 +4437,16 @@ def __init__(self, NCSF): sage: all(nM(S(nM[comp])) == nM[comp] for comp in Compositions(5)) True """ - CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), - prefix='nM', bracket=False, - category=NCSF.Bases()) + CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), prefix='nM', bracket=False, category=NCSF.Bases()) category = self.category() NCSF = NonCommutativeSymmetricFunctions(self.base_ring()) S = NCSF.complete() Psi = NCSF.Psi() - to_S = self.module_morphism( - on_basis=self._to_complete_on_basis, - codomain=S, - category=category) + to_S = self.module_morphism(on_basis=self._to_complete_on_basis, codomain=S, category=category) to_S.register_as_coercion() - from_psi = Psi.module_morphism( - on_basis=self._from_psi_on_basis, - codomain=self, - category=category) + from_psi = Psi.module_morphism(on_basis=self._from_psi_on_basis, codomain=self, category=category) from_psi.register_as_coercion() def _to_complete_on_basis(self, I): @@ -4519,9 +4477,7 @@ def _to_complete_on_basis(self, I): S[1, 1, 1] - 2*S[1, 2] - S[2, 1] + 3*S[3] """ S = NonCommutativeSymmetricFunctions(self.base_ring()).S() - return S.sum_of_terms( ( (K, m_to_s_stat(self.base_ring(),I,K)) - for K in Compositions(sum(I)) ), - distinct=True ) + return S.sum_of_terms(((K, m_to_s_stat(self.base_ring(), I, K)) for K in Compositions(sum(I))), distinct=True) # Note: sum(I) works both if I is a list and if I is a composition # (although the latter case doesn't work in IPython, cf. # trac #15163). @@ -4559,7 +4515,7 @@ def _from_psi_on_basis(self, I): if I.is_finer(J): len_of_J = len(J) p = [0] + self._indices(I).refinement_splitting_lengths(J).partial_sums() - sum_of_elements += prod( (len_of_J - k)**(p[k+1]-p[k]) for k in range(len_of_J) ) * M(J) + sum_of_elements += prod((len_of_J - k) ** (p[k + 1] - p[k]) for k in range(len_of_J)) * M(J) return sum_of_elements nM = monomial = Monomial @@ -4632,21 +4588,13 @@ def __init__(self, NCSF): sage: all(I(S(I[comp])) == I[comp] for comp in Compositions(5)) True """ - CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), - prefix='I', bracket=False, - category=NCSF.Bases()) + CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), prefix='I', bracket=False, category=NCSF.Bases()) category = self.category() S = self.realization_of().complete() - to_S = self.module_morphism( - on_basis=self._to_complete_on_basis, - codomain=S, - category=category) + to_S = self.module_morphism(on_basis=self._to_complete_on_basis, codomain=S, category=category) to_S.register_as_coercion() - from_S = S.module_morphism( - on_basis=self._from_complete_on_basis, - codomain=self, - category=category) + from_S = S.module_morphism(on_basis=self._from_complete_on_basis, codomain=self, category=category) from_S.register_as_coercion() def _realization_name(self): @@ -4687,9 +4635,9 @@ def _H(self, alpha): S[1, 2] """ S = NonCommutativeSymmetricFunctions(self.base_ring()).complete() - if any( d < 0 for d in alpha ): + if any(d < 0 for d in alpha): return S.zero() - return S( [ d for d in alpha if d > 0 ] ) + return S([d for d in alpha if d > 0]) @cached_method def _to_complete_on_basis(self, alpha): @@ -4722,8 +4670,7 @@ def _to_complete_on_basis(self, alpha): return self._H([1]) la = len(alpha_list) S = NonCommutativeSymmetricFunctions(self.base_ring()).complete() - return S.sum( sigma.signature()*self._H( [alpha_list[i]+sigma[i]-(i+1) for i in range(la)] ) - for sigma in Permutations(la) ) + return S.sum(sigma.signature() * self._H([alpha_list[i] + sigma[i] - (i + 1) for i in range(la)]) for sigma in Permutations(la)) @cached_method def _from_complete_on_basis(self, comp_content): @@ -4752,9 +4699,7 @@ def _from_complete_on_basis(self, comp_content): I = NonCommutativeSymmetricFunctions(self.base_ring()).I() if not comp_content._list: return I([]) - return I.sum_of_terms( ( (comp_shape, number_of_fCT(comp_content, comp_shape)) - for comp_shape in Compositions(sum(comp_content)) ), - distinct=True ) + return I.sum_of_terms(((comp_shape, number_of_fCT(comp_content, comp_shape)) for comp_shape in Compositions(sum(comp_content))), distinct=True) def dual(self): r""" @@ -4837,7 +4782,7 @@ def bernstein_creation_operator(self, n): C = Compositions() P = self.parent() - return P.sum_of_terms( (C([n] + list(m)), c) for m,c in self ) + return P.sum_of_terms((C([n] + list(m)), c) for m, c in self) I = Immaculate @@ -4918,21 +4863,13 @@ def __init__(self, NCSF): True sage: TestSuite(dQS).run() # long time """ - CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), - prefix='dQS', bracket=False, - category=NCSF.Bases()) + CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), prefix='dQS', bracket=False, category=NCSF.Bases()) category = self.category() self._S = self.realization_of().complete() - to_S = self.module_morphism( - on_basis=self._to_complete_on_basis, - codomain=self._S, - category=category) + to_S = self.module_morphism(on_basis=self._to_complete_on_basis, codomain=self._S, category=category) to_S.register_as_coercion() - from_S = self._S.module_morphism( - on_basis=self._from_complete_on_basis, - codomain=self, - category=category) + from_S = self._S.module_morphism(on_basis=self._from_complete_on_basis, codomain=self, category=category) from_S.register_as_coercion() def _realization_name(self): @@ -4977,9 +4914,9 @@ def _to_complete_transition_matrix(self, n): CO = compositions_order(n) # ZZ is faster than over QQ for inverting a matrix from sage.rings.integer_ring import ZZ + MS = MatrixSpace(ZZ, len(CO)) - return (MS([[number_of_SSRCT(al,be) for be in CO] for al in CO]).inverse(), - CO) + return (MS([[number_of_SSRCT(al, be) for be in CO] for al in CO]).inverse(), CO) @cached_method def _to_complete_on_basis(self, comp): @@ -5004,9 +4941,7 @@ def _to_complete_on_basis(self, comp): return self.one() T, comps = self._to_complete_transition_matrix(comp.size()) i = comps.index(comp) - return self._S._from_dict({c: T[i,j] for j,c in enumerate(comps) - if T[i,j] != 0}, - remove_zeros=False) + return self._S._from_dict({c: T[i, j] for j, c in enumerate(comps) if T[i, j] != 0}, remove_zeros=False) @cached_method def _from_complete_on_basis(self, comp_content): @@ -5034,9 +4969,7 @@ def _from_complete_on_basis(self, comp_content): """ if not comp_content._list: return self([]) - return self.sum_of_terms( ( (comp_shape, number_of_SSRCT(comp_content, comp_shape)) - for comp_shape in Compositions(sum(comp_content)) ), - distinct=True ) + return self.sum_of_terms(((comp_shape, number_of_SSRCT(comp_content, comp_shape)) for comp_shape in Compositions(sum(comp_content))), distinct=True) def dual(self): r""" @@ -5088,7 +5021,7 @@ def to_symmetric_function_on_basis(self, I): s[] """ s = SymmetricFunctions(self.base_ring()).s() - return s[Partition(sorted(I,reverse=True))] + return s[Partition(sorted(I, reverse=True))] dQS = dualQuasisymmetric_Schur @@ -5149,19 +5082,13 @@ def __init__(self, NCSF): sage: TestSuite(dYQS).run() # long time """ category = NCSF.Bases() - CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), - prefix='dYQS', bracket=False, - category=category) + CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), prefix='dYQS', bracket=False, category=category) self._S = NCSF.complete() self._dQS = NCSF.dualQuasisymmetric_Schur() - self.module_morphism(on_basis=self._to_complete_on_basis, - codomain=self._S, - category=category).register_as_coercion() + self.module_morphism(on_basis=self._to_complete_on_basis, codomain=self._S, category=category).register_as_coercion() - self._S.module_morphism(on_basis=self._from_complete_on_basis, - codomain=self, - category=category).register_as_coercion() + self._S.module_morphism(on_basis=self._from_complete_on_basis, codomain=self, category=category).register_as_coercion() def _realization_name(self): r""" @@ -5193,8 +5120,7 @@ def _to_complete_on_basis(self, comp): S[1, 3, 1] - S[1, 4] - S[2, 3] + S[5] """ elt = self._dQS._to_complete_on_basis(comp.reversed()) - return self._S._from_dict({al.reversed(): c for al, c in elt}, - coerce=False, remove_zeros=False) + return self._S._from_dict({al.reversed(): c for al, c in elt}, coerce=False, remove_zeros=False) def _from_complete_on_basis(self, comp): r""" @@ -5220,8 +5146,7 @@ def _from_complete_on_basis(self, comp): dYQS[2, 1, 1] + dYQS[2, 2] + 2*dYQS[3, 1] + dYQS[4] """ elt = self._dQS._from_complete_on_basis(comp.reversed()) - return self._from_dict({al.reversed(): c for al, c in elt}, - coerce=False, remove_zeros=False) + return self._from_dict({al.reversed(): c for al, c in elt}, coerce=False, remove_zeros=False) def dual(self): r""" @@ -5274,7 +5199,7 @@ def to_symmetric_function_on_basis(self, I): s[] """ s = SymmetricFunctions(self.base_ring()).s() - return s[Partition(sorted(I,reverse=True))] + return s[Partition(sorted(I, reverse=True))] dYQS = dualYoungQuasisymmetric_Schur @@ -5349,19 +5274,15 @@ def __init__(self, NCSF): True """ cat = NCSF.MultiplicativeBasesOnPrimitiveElements() - CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), - prefix='ZL', bracket=False, - category=cat) + CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), prefix='ZL', bracket=False, category=cat) # Register coercions S = self.realization_of().S() - to_complete = self.algebra_morphism(self._to_complete_on_generator, - codomain=S) + to_complete = self.algebra_morphism(self._to_complete_on_generator, codomain=S) to_complete.register_as_coercion() - from_complete = S.module_morphism(on_basis=self._from_complete_on_basis, - codomain=self) + from_complete = S.module_morphism(on_basis=self._from_complete_on_basis, codomain=self) from_complete.register_as_coercion() def _to_complete_on_generator(self, n): @@ -5392,8 +5313,9 @@ def _to_complete_on_generator(self, n): from sage.combinat.partitions import ZS1_iterator from sage.rings.integer_ring import ZZ + it = ZS1_iterator(n) - next(it) # Skip the unique length 1 partition + next(it) # Skip the unique length 1 partition res = S[n] for p in it: d = {} @@ -5418,6 +5340,7 @@ def _complete_to_zassenhaus_transition_matrix_inverse(self, n): [1/6 0 1 1] """ from sage.matrix.constructor import matrix + S = self.realization_of().S() m = [] for I in Compositions(n): @@ -5443,7 +5366,7 @@ def _from_complete_on_basis(self, I): m = self._complete_to_zassenhaus_transition_matrix_inverse(n) C = Compositions(n) coeffs = m[C.rank(I)] - return self._from_dict({J: coeffs[i] for i,J in enumerate(C)}) + return self._from_dict({J: coeffs[i] for i, J in enumerate(C)}) ZL = Zassenhaus_left @@ -5526,18 +5449,14 @@ def __init__(self, NCSF): True """ cat = NCSF.MultiplicativeBasesOnPrimitiveElements() - CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), - prefix='ZR', bracket=False, - category=cat) + CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), prefix='ZR', bracket=False, category=cat) # Register coercions S = self.realization_of().S() - to_complete = self.algebra_morphism(self._to_complete_on_generator, - codomain=S) + to_complete = self.algebra_morphism(self._to_complete_on_generator, codomain=S) to_complete.register_as_coercion() - from_complete = S.module_morphism(on_basis=self._from_complete_on_basis, - codomain=self) + from_complete = S.module_morphism(on_basis=self._from_complete_on_basis, codomain=self) from_complete.register_as_coercion() def _to_complete_on_generator(self, n): @@ -5569,8 +5488,9 @@ def _to_complete_on_generator(self, n): from sage.combinat.partitions import ZS1_iterator from sage.rings.integer_ring import ZZ + it = ZS1_iterator(n) - next(it) # Skip the unique length 1 partition + next(it) # Skip the unique length 1 partition res = S[n] for p in it: d = {} @@ -5595,6 +5515,7 @@ def _complete_to_zassenhaus_transition_matrix_inverse(self, n): [1/6 1 0 1] """ from sage.matrix.constructor import matrix + S = self.realization_of().S() m = [] for I in Compositions(n): @@ -5620,6 +5541,6 @@ def _from_complete_on_basis(self, I): m = self._complete_to_zassenhaus_transition_matrix_inverse(n) C = Compositions(n) coeffs = m[C.rank(I)] - return self._from_dict({J: coeffs[i] for i,J in enumerate(C)}) + return self._from_dict({J: coeffs[i] for i, J in enumerate(C)}) ZR = Zassenhaus_right diff --git a/src/sage/combinat/ncsf_qsym/qsym.py b/src/sage/combinat/ncsf_qsym/qsym.py index 71d5a57ddb4..8599f050dae 100644 --- a/src/sage/combinat/ncsf_qsym/qsym.py +++ b/src/sage/combinat/ncsf_qsym/qsym.py @@ -25,9 +25,7 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.ncsf_qsym.generic_basis_code import BasesOfQSymOrNCSF -from sage.combinat.ncsf_qsym.combinatorics import ( - number_of_fCT, number_of_SSRCT, - compositions_order, coeff_pi, coeff_lp, coeff_sp, coeff_ell) +from sage.combinat.ncsf_qsym.combinatorics import number_of_fCT, number_of_SSRCT, compositions_order, coeff_pi, coeff_lp, coeff_sp, coeff_ell from sage.combinat.ncsf_qsym.ncsf import NonCommutativeSymmetricFunctions from sage.combinat.words.word import Word from sage.combinat.tableau import StandardTableaux @@ -507,42 +505,24 @@ def __init__(self, R) -> None: QS = self.Quasisymmetric_Schur() # Change of bases - Fundamental.module_morphism(Monomial.sum_of_finer_compositions, - codomain=Monomial, category=category - ).register_as_coercion() - Monomial .module_morphism(Fundamental.alternating_sum_of_finer_compositions, - codomain=Fundamental, category=category - ).register_as_coercion() + Fundamental.module_morphism(Monomial.sum_of_finer_compositions, codomain=Monomial, category=category).register_as_coercion() + Monomial.module_morphism(Fundamental.alternating_sum_of_finer_compositions, codomain=Fundamental, category=category).register_as_coercion() # This changes dualImmaculate into Monomial - dualImmaculate.module_morphism(dualImmaculate._to_Monomial_on_basis, - codomain=Monomial, category=category - ).register_as_coercion() + dualImmaculate.module_morphism(dualImmaculate._to_Monomial_on_basis, codomain=Monomial, category=category).register_as_coercion() # This changes Monomial into dualImmaculate - Monomial.module_morphism(dualImmaculate._from_Monomial_on_basis, - codomain=dualImmaculate, category=category - ).register_as_coercion() + Monomial.module_morphism(dualImmaculate._from_Monomial_on_basis, codomain=dualImmaculate, category=category).register_as_coercion() # This changes Quasisymmetric Schur into Monomial - QS .module_morphism(QS._to_monomial_on_basis, - codomain=Monomial, category=category - ).register_as_coercion() + QS.module_morphism(QS._to_monomial_on_basis, codomain=Monomial, category=category).register_as_coercion() # This changes Monomial into Quasisymmetric Schur - Monomial.module_morphism(QS._from_monomial_on_basis, - codomain=QS, category=category - ).register_as_coercion() + Monomial.module_morphism(QS._from_monomial_on_basis, codomain=QS, category=category).register_as_coercion() # Embedding of Sym into QSym in the monomial bases Sym = SymmetricFunctions(self.base_ring()) - Sym_m_to_M = Sym.m().module_morphism(Monomial.sum_of_partition_rearrangements, - triangular='upper', - inverse_on_support=Monomial._comp_to_par, - codomain=Monomial, - category=category) + Sym_m_to_M = Sym.m().module_morphism(Monomial.sum_of_partition_rearrangements, triangular='upper', inverse_on_support=Monomial._comp_to_par, codomain=Monomial, category=category) Sym_m_to_M.register_as_coercion() self.to_symmetric_function = Sym_m_to_M.section() - Sym_s_to_F = Sym.s().module_morphism(Fundamental._from_schur_on_basis, - unitriangular='upper', - codomain=Fundamental, category=category) + Sym_s_to_F = Sym.s().module_morphism(Fundamental._from_schur_on_basis, unitriangular='upper', codomain=Fundamental, category=category) Sym_s_to_F.register_as_coercion() def _repr_(self) -> str: @@ -985,6 +965,7 @@ def internal_coproduct(self): parent = self.parent() F = parent.realization_of().F() from sage.categories.tensor import tensor + result = tensor([parent.zero(), parent.zero()]) for lam, a in F(self).internal_coproduct(): (I, J) = lam @@ -1422,8 +1403,7 @@ def dendriform_less(self, other): I_tail = Composition(I[1:]) for J, J_coeff in b: shufpro = I_tail.shuffle_product(J, overlap=True) - res += J_coeff * M.sum_of_monomials(Composition([i_head] + list(K)) - for K in shufpro) + res += J_coeff * M.sum_of_monomials(Composition([i_head] + list(K)) for K in shufpro) return P(res) def dendriform_leq(self, other): @@ -1634,9 +1614,7 @@ def __init__(self, QSym): Quasisymmetric functions over the Rational Field in the Monomial basis sage: TestSuite(M).run() """ - CombinatorialFreeModule.__init__(self, QSym.base_ring(), Compositions(), - prefix='M', bracket=False, - category=QSym.Bases()) + CombinatorialFreeModule.__init__(self, QSym.base_ring(), Compositions(), prefix='M', bracket=False, category=QSym.Bases()) def dual(self): r""" @@ -1705,7 +1683,7 @@ def antipode_on_basis(self, compo): sage: M.antipode_on_basis(Composition([])) M[] """ - return (-1)**(len(compo)) * self.sum_of_fatter_compositions(compo.reversed()) + return (-1) ** (len(compo)) * self.sum_of_fatter_compositions(compo.reversed()) def coproduct_on_basis(self, compo): r""" @@ -1730,9 +1708,7 @@ def coproduct_on_basis(self, compo): sage: M.coproduct_on_basis(Composition([])) M[] # M[] """ - return self.tensor_square().sum_of_monomials((self._indices(compo[:i]), - self._indices(compo[i:])) - for i in range(len(compo) + 1)) + return self.tensor_square().sum_of_monomials((self._indices(compo[:i]), self._indices(compo[i:])) for i in range(len(compo) + 1)) def lambda_of_monomial(self, I, n): r""" @@ -1836,16 +1812,15 @@ def lambda_of_monomial(self, I, n): # immediately cancel. from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ + QQM = QuasiSymmetricFunctions(QQ).M() QQ_result = QQM.zero() for lam in Partitions(n): coeff = QQ((-1) ** len(lam)) / lam.centralizer_size() - QQ_result += coeff * QQM.prod([QQM(self._indices([k * i for i in I])) - for k in lam]) + QQ_result += coeff * QQM.prod([QQM(self._indices([k * i for i in I])) for k in lam]) QQ_result *= (-1) ** n # QQ_result is now \lambda^n(M_I) over QQ. - return self.sum_of_terms([(J, ZZ(coeff)) for J, coeff in QQ_result], - distinct=True) + return self.sum_of_terms([(J, ZZ(coeff)) for J, coeff in QQ_result], distinct=True) class Element(CombinatorialFreeModule.Element): r""" @@ -1916,10 +1891,7 @@ def psi_involution(self): True """ parent = self.parent() - return parent.sum((-1) ** (I.size() - len(I)) * coeff - * parent.sum_of_fatter_compositions(I) - for I, coeff in - self._monomial_coefficients.items()) + return parent.sum((-1) ** (I.size() - len(I)) * coeff * parent.sum_of_fatter_compositions(I) for I, coeff in self._monomial_coefficients.items()) def expand(self, n, alphabet='x'): r""" @@ -1959,6 +1931,7 @@ def expand(self, n, alphabet='x'): 1 """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + M = self.parent() P = PolynomialRing(M.base_ring(), n, alphabet) x = P.gens() @@ -1968,12 +1941,9 @@ def on_basis(comp, i): return P.one() if len(comp) > i: return P.zero() - return x[i - 1]**comp[-1] * on_basis(comp[:-1], i - 1) + \ - on_basis(comp, i - 1) + return x[i - 1] ** comp[-1] * on_basis(comp[:-1], i - 1) + on_basis(comp, i - 1) - return M._apply_module_morphism(self, - lambda comp: on_basis(comp, n), - codomain=P) + return M._apply_module_morphism(self, lambda comp: on_basis(comp, n), codomain=P) def is_symmetric(self) -> bool: r""" @@ -2007,6 +1977,7 @@ def is_symmetric(self) -> bool: # We use a dictionary to keep track of the coefficient # and how many rearrangements of the composition we've seen. from sage.combinat.permutation import Permutations_mset + d = {} for I, coeff in self: partition = I.to_partition() @@ -2017,8 +1988,7 @@ def is_symmetric(self) -> bool: return False d[partition][1] += 1 # make sure we've seen each rearrangement of the composition - return all(d[partition][1] == Permutations_mset(partition).cardinality() - for partition in d) + return all(d[partition][1] == Permutations_mset(partition).cardinality() for partition in d) def to_symmetric_function(self): r""" @@ -2064,10 +2034,7 @@ def to_symmetric_function(self): """ m = SymmetricFunctions(self.parent().base_ring()).monomial() if self.is_symmetric(): - return m._from_dict({_Partitions(list(I)): coeff - for I, coeff in self - if list(I) in _Partitions}, - remove_zeros=False) + return m._from_dict({_Partitions(list(I)): coeff for I, coeff in self if list(I) in _Partitions}, remove_zeros=False) raise ValueError("%s is not a symmetric function" % self) M = Monomial @@ -2116,9 +2083,7 @@ def __init__(self, QSym): Quasisymmetric functions over the Rational Field in the Fundamental basis sage: TestSuite(F).run() """ - CombinatorialFreeModule.__init__(self, QSym.base_ring(), Compositions(), - prefix='F', bracket=False, - category=QSym.Bases()) + CombinatorialFreeModule.__init__(self, QSym.base_ring(), Compositions(), prefix='F', bracket=False, category=QSym.Bases()) def _from_schur_on_basis(self, la): r""" @@ -2181,7 +2146,7 @@ def antipode_on_basis(self, compo): sage: F.antipode_on_basis(Composition([2,1])) -F[2, 1] """ - return (-1)**(compo.size()) * self.monomial(compo.conjugate()) + return (-1) ** (compo.size()) * self.monomial(compo.conjugate()) def coproduct_on_basis(self, compo): r""" @@ -2215,12 +2180,8 @@ def coproduct_on_basis(self, compo): """ T = self.tensor_square() C = Composition - resu = T.sum_of_monomials((C(compo[:i]), C(compo[i:])) - for i in range(len(compo) + 1)) - resu += T.sum_of_monomials((C(compo[:i] + [j]), - C([compo[i] - j] + compo[i + 1:])) - for i in range(len(compo)) - for j in range(1, compo[i])) + resu = T.sum_of_monomials((C(compo[:i]), C(compo[i:])) for i in range(len(compo) + 1)) + resu += T.sum_of_monomials((C(compo[:i] + [j]), C([compo[i] - j] + compo[i + 1 :])) for i in range(len(compo)) for j in range(1, compo[i])) return resu @cached_method @@ -2315,6 +2276,7 @@ def Eulerian(self, n, j, k=None): ValueError: invalid input, k cannot be specified """ from sage.combinat.partition import _Partitions + if n in _Partitions: if k is not None: raise ValueError("invalid input, k cannot be specified") @@ -2337,8 +2299,7 @@ def Eulerian(self, n, j, k=None): for i in range(n - 1): if p[i] > i + 1: exc += 1 - if (p[i] > p[i + 1] or (p[i] <= i + 1 and p[i + 1] > i + 2)) \ - and not (p[i] > i + 1 and p[i + 1] <= i + 2): + if (p[i] > p[i + 1] or (p[i] <= i + 1 and p[i + 1] > i + 2)) and not (p[i] > i + 1 and p[i + 1] <= i + 2): dex.append(i) if exc != j: @@ -2350,8 +2311,7 @@ def Eulerian(self, n, j, k=None): # Converting to a composition d = [-1] + dex + [n - 1] - monomials.append(Compositions()([d[i + 1] - d[i] - for i in range(len(d) - 1)])) + monomials.append(Compositions()([d[i + 1] - d[i] for i in range(len(d) - 1)])) return self.sum_of_monomials(monomials) @@ -2461,9 +2421,11 @@ def internal_coproduct(self): result = F2.zero() from sage.categories.tensor import tensor from sage.combinat.permutation import Permutation + for I, a in self: # We must add a * \Delta^\times(F_I) to result. from sage.combinat.permutation import descents_composition_last + pi = descents_composition_last(I) n = I.size() for sigma in Permutations(n): @@ -2472,8 +2434,7 @@ def internal_coproduct(self): # the next line could be as simple as # tau = pi * sigma_inverse. tau = Permutation([pi(i) for i in sigma_inverse]) - result += a * tensor([F(sigma.descents_composition()), - F(tau.descents_composition())]) + result += a * tensor([F(sigma.descents_composition()), F(tau.descents_composition())]) return result kronecker_coproduct = internal_coproduct @@ -2610,20 +2571,14 @@ def __init__(self, QSym): ....: for c in Compositions(n)) True """ - CombinatorialFreeModule.__init__(self, QSym.base_ring(), Compositions(), - prefix='E', bracket=False, - category=QSym.Bases()) + CombinatorialFreeModule.__init__(self, QSym.base_ring(), Compositions(), prefix='E', bracket=False, category=QSym.Bases()) M = QSym.M() category = self.realization_of()._category # This changes Monomial into Essential - M.module_morphism(self.alternating_sum_of_fatter_compositions, - codomain=self, category=category - ).register_as_coercion() + M.module_morphism(self.alternating_sum_of_fatter_compositions, codomain=self, category=category).register_as_coercion() # This changes Essential into Monomial - self.module_morphism(M.sum_of_fatter_compositions, - codomain=M, category=category - ).register_as_coercion() + self.module_morphism(M.sum_of_fatter_compositions, codomain=M, category=category).register_as_coercion() def antipode_on_basis(self, compo): r""" @@ -2659,7 +2614,7 @@ def antipode_on_basis(self, compo): ....: for k in [3,4] for I in Compositions(k)) True """ - return (-1)**len(compo) * self.alternating_sum_of_fatter_compositions(compo.reversed()) + return (-1) ** len(compo) * self.alternating_sum_of_fatter_compositions(compo.reversed()) def coproduct_on_basis(self, compo): r""" @@ -2684,9 +2639,7 @@ def coproduct_on_basis(self, compo): sage: E.coproduct_on_basis(Composition([])) E[] # E[] """ - return self.tensor_square().sum_of_monomials((self._indices(compo[:i]), - self._indices(compo[i:])) - for i in range(len(compo) + 1)) + return self.tensor_square().sum_of_monomials((self._indices(compo[:i]), self._indices(compo[i:])) for i in range(len(compo) + 1)) def product_on_basis(self, I, J): r""" @@ -2729,8 +2682,7 @@ def product_on_basis(self, I, J): True """ n = len(I) + len(J) - return self.sum_of_terms((K, (-1)**(n - len(K))) - for K in I.shuffle_product(J, overlap=True)) + return self.sum_of_terms((K, (-1) ** (n - len(K))) for K in I.shuffle_product(J, overlap=True)) E = Essential @@ -2777,9 +2729,7 @@ def __init__(self, QSym): True sage: TestSuite(QS).run() # long time """ - CombinatorialFreeModule.__init__(self, QSym.base_ring(), Compositions(), - prefix='QS', bracket=False, - category=QSym.Bases()) + CombinatorialFreeModule.__init__(self, QSym.base_ring(), Compositions(), prefix='QS', bracket=False, category=QSym.Bases()) def _realization_name(self): r""" @@ -2825,6 +2775,7 @@ def _from_monomial_transition_matrix(self, n): CO = compositions_order(n) # ZZ is faster than over QQ for inverting a matrix from sage.rings.integer_ring import ZZ + MS = MatrixSpace(ZZ, len(CO)) M = MS([[number_of_SSRCT(al, be) for al in CO] for be in CO]) return (M.inverse_of_unit(), CO) @@ -2856,8 +2807,7 @@ def _from_monomial_on_basis(self, comp): return self.one() T, comps = self._from_monomial_transition_matrix(comp.size()) i = comps.index(comp) - return self._from_dict({c: T[i, j] for j, c in enumerate(comps) - if T[i, j] != 0}, remove_zeros=False) + return self._from_dict({c: T[i, j] for j, c in enumerate(comps) if T[i, j] != 0}, remove_zeros=False) @cached_method def _to_monomial_on_basis(self, comp_shape): @@ -2884,10 +2834,7 @@ def _to_monomial_on_basis(self, comp_shape): M = self.realization_of().Monomial() if not comp_shape: return M([]) - return M.sum_of_terms( - ((comp_content, number_of_SSRCT(comp_content, comp_shape)) - for comp_content in Compositions(sum(comp_shape))), - distinct=True) + return M.sum_of_terms(((comp_content, number_of_SSRCT(comp_content, comp_shape)) for comp_content in Compositions(sum(comp_shape))), distinct=True) def dual(self): r""" @@ -2960,13 +2907,9 @@ def __init__(self, QSym): """ self._QS = QSym.QS() self._M = QSym.M() - CombinatorialFreeModule.__init__(self, QSym.base_ring(), - Compositions(), prefix='YQS', - bracket=False, category=QSym.Bases()) - self.module_morphism(self._to_monomial_on_basis, - codomain=self._M, category=QSym.Bases()).register_as_coercion() - self._M.module_morphism(self._from_monomial_on_basis, - codomain=self, category=QSym.Bases()).register_as_coercion() + CombinatorialFreeModule.__init__(self, QSym.base_ring(), Compositions(), prefix='YQS', bracket=False, category=QSym.Bases()) + self.module_morphism(self._to_monomial_on_basis, codomain=self._M, category=QSym.Bases()).register_as_coercion() + self._M.module_morphism(self._from_monomial_on_basis, codomain=self, category=QSym.Bases()).register_as_coercion() def _realization_name(self): r""" @@ -3028,8 +2971,7 @@ def _from_monomial_on_basis(self, comp): YQS[1, 1, 1, 1, 1] - YQS[1, 2, 1, 1] - YQS[1, 2, 2] + YQS[1, 3, 1] """ elt = self._QS(self._M.monomial(comp.reversed())) - return self._from_dict({al.reversed(): c for al, c in elt}, - coerce=False, remove_zeros=False) + return self._from_dict({al.reversed(): c for al, c in elt}, coerce=False, remove_zeros=False) YQS = Young_Quasisymmetric_Schur @@ -3056,9 +2998,7 @@ def __init__(self, QSym): sage: F(dI(F([2,1,3]))) F[2, 1, 3] """ - CombinatorialFreeModule.__init__(self, QSym.base_ring(), Compositions(), - prefix='dI', bracket=False, - category=QSym.Bases()) + CombinatorialFreeModule.__init__(self, QSym.base_ring(), Compositions(), prefix='dI', bracket=False, category=QSym.Bases()) def _to_Monomial_on_basis(self, J): r""" @@ -3086,8 +3026,7 @@ def _to_Monomial_on_basis(self, J): return M([]) C = Compositions() C_size = Compositions(J.size()) - return M.sum_of_terms(((C(I), number_of_fCT(C(I), J)) - for I in C_size), distinct=True) + return M.sum_of_terms(((C(I), number_of_fCT(C(I), J)) for I in C_size), distinct=True) @cached_method def _matrix_monomial_to_dual_immaculate(self, n): @@ -3152,8 +3091,7 @@ def _from_Monomial_on_basis(self, J): C_n = Compositions(n) mat = self._matrix_monomial_to_dual_immaculate(n) column = C_n.list().index(J) - return self.sum_of_terms(((C(I), mat[C_n.list().index(I)][column]) - for I in C_n), distinct=True) + return self.sum_of_terms(((C(I), mat[C_n.list().index(I)][column]) for I in C_n), distinct=True) dI = dualImmaculate @@ -3256,9 +3194,7 @@ def __init__(self, QSym): sage: HWL = QuasiSymmetricFunctions(QQ).HazewinkelLambda() sage: TestSuite(HWL).run() """ - CombinatorialFreeModule.__init__(self, QSym.base_ring(), Compositions(), - prefix='HWL', bracket=False, - category=QSym.Bases()) + CombinatorialFreeModule.__init__(self, QSym.base_ring(), Compositions(), prefix='HWL', bracket=False, category=QSym.Bases()) def __init_extra__(self): """ @@ -3285,13 +3221,9 @@ def __init_extra__(self): M = self.realization_of().M() category = self.realization_of()._category # This changes Monomial into Hazewinkel Lambda - M.module_morphism(self._from_Monomial_on_basis, - codomain=self, category=category - ).register_as_coercion() + M.module_morphism(self._from_Monomial_on_basis, codomain=self, category=category).register_as_coercion() # This changes Hazewinkel Lambda into Monomial - self.module_morphism(self._to_Monomial_on_basis, - codomain=M, category=category - ).register_as_coercion() + self.module_morphism(self._to_Monomial_on_basis, codomain=M, category=category).register_as_coercion() # cache for the coordinates of the elements # of the monomial basis with respect to the HWL basis @@ -3454,7 +3386,7 @@ def _precompute_cache(self, n, to_self_cache, from_self_cache, transition_matric return compositions_n = Compositions(n).list() - len_compositions_n = 2 ** (n - 1) # since n > 0 by now. + len_compositions_n = 2 ** (n - 1) # since n > 0 by now. M = self.realization_of().M() # The monomial basis will be called M from now on. @@ -3473,8 +3405,7 @@ def _precompute_cache(self, n, to_self_cache, from_self_cache, transition_matric # M_coeffs will be M(self[I])._monomial_coefficients M_coeffs = {} - self_I_in_M_basis = M.prod([from_self_gen_function(self._indices(list(J))) - for J in Word(I).lyndon_factorization()]) + self_I_in_M_basis = M.prod([from_self_gen_function(self._indices(list(J))) for J in Word(I).lyndon_factorization()]) for j, J in enumerate(compositions_n): if J in self_I_in_M_basis._monomial_coefficients: @@ -3597,12 +3528,9 @@ def monolambda(I): g = gcd(I) I_reduced = [i // g for i in I] return M.lambda_of_monomial(I_reduced, g) + for i in range(l, n + 1): - self._precompute_cache(i, self._M_to_self_cache, - self._M_from_self_cache, - self._M_transition_matrices, - self._M_inverse_transition_matrices, - monolambda) + self._precompute_cache(i, self._M_to_self_cache, self._M_from_self_cache, self._M_transition_matrices, self._M_inverse_transition_matrices, monolambda) def _to_Monomial_on_basis(self, J): r""" @@ -3689,6 +3617,7 @@ def product_on_basis(self, I, J): True """ from sage.misc.flatten import flatten + I_factors = [list(i) for i in Word(I).lyndon_factorization()] J_factors = [list(j) for j in Word(J).lyndon_factorization()] # This uses the convenient fact that comparison of lists in @@ -3776,18 +3705,12 @@ def __init__(self, QSym): ....: for c in Compositions(n)) True """ - CombinatorialFreeModule.__init__(self, QSym.base_ring(), Compositions(), - prefix='psi', bracket=False, - category=QSym.Bases()) + CombinatorialFreeModule.__init__(self, QSym.base_ring(), Compositions(), prefix='psi', bracket=False, category=QSym.Bases()) category = self.realization_of()._category Monomial = self.realization_of().Monomial() - self.module_morphism(self._to_Monomial_on_basis, - codomain=Monomial, category=category - ).register_as_coercion() - Monomial.module_morphism(self._from_Monomial_on_basis, - codomain=self, category=category - ).register_as_coercion() + self.module_morphism(self._to_Monomial_on_basis, codomain=Monomial, category=category).register_as_coercion() + Monomial.module_morphism(self._from_Monomial_on_basis, codomain=self, category=category).register_as_coercion() def _from_Monomial_on_basis(self, I): r""" @@ -3812,8 +3735,8 @@ def _from_Monomial_on_basis(self, I): def z(J): return R(J.to_partition().centralizer_size()) - return self._from_dict({J: minus_one**(len(I) - len(J)) / z(J) * coeff_lp(I, J) - for J in I.fatter()}) + + return self._from_dict({J: minus_one ** (len(I) - len(J)) / z(J) * coeff_lp(I, J) for J in I.fatter()}) def _to_Monomial_on_basis(self, I): r""" @@ -3836,8 +3759,7 @@ def _to_Monomial_on_basis(self, I): R = self.base_ring() z = R(I.to_partition().centralizer_size()) Monomial = self.realization_of().Monomial() - return Monomial._from_dict({J: z / coeff_pi(I, J) - for J in I.fatter()}) + return Monomial._from_dict({J: z / coeff_pi(I, J) for J in I.fatter()}) class phi(CombinatorialFreeModule, BindableClass): r""" @@ -3916,18 +3838,12 @@ def __init__(self, QSym): ....: for c in Compositions(n)) True """ - CombinatorialFreeModule.__init__(self, QSym.base_ring(), Compositions(), - prefix='phi', bracket=False, - category=QSym.Bases()) + CombinatorialFreeModule.__init__(self, QSym.base_ring(), Compositions(), prefix='phi', bracket=False, category=QSym.Bases()) category = self.realization_of()._category Monomial = self.realization_of().Monomial() - self.module_morphism(self._to_Monomial_on_basis, - codomain=Monomial, category=category - ).register_as_coercion() - Monomial.module_morphism(self._from_Monomial_on_basis, - codomain=self, category=category - ).register_as_coercion() + self.module_morphism(self._to_Monomial_on_basis, codomain=Monomial, category=category).register_as_coercion() + Monomial.module_morphism(self._from_Monomial_on_basis, codomain=self, category=category).register_as_coercion() def _from_Monomial_on_basis(self, I): r""" @@ -3952,8 +3868,8 @@ def _from_Monomial_on_basis(self, I): def z(J): return R(J.to_partition().centralizer_size()) - return self._from_dict({J: minus_one**(len(I) - len(J)) * R.prod(J) / (coeff_ell(I, J) * z(J)) - for J in I.fatter()}) + + return self._from_dict({J: minus_one ** (len(I) - len(J)) * R.prod(J) / (coeff_ell(I, J) * z(J)) for J in I.fatter()}) def _to_Monomial_on_basis(self, I): r""" @@ -3976,5 +3892,4 @@ def _to_Monomial_on_basis(self, I): R = self.base_ring() z = R(I.to_partition().centralizer_size()) Monomial = self.realization_of().Monomial() - return Monomial._from_dict({J: z / coeff_sp(I, J) - for J in I.fatter()}) + return Monomial._from_dict({J: z / coeff_sp(I, J) for J in I.fatter()}) diff --git a/src/sage/combinat/ncsym/all.py b/src/sage/combinat/ncsym/all.py index 864a6ac6960..0f4a88d8aab 100644 --- a/src/sage/combinat/ncsym/all.py +++ b/src/sage/combinat/ncsym/all.py @@ -7,8 +7,10 @@ - :ref:`sage.combinat.ncsym.dual` - :ref:`sage.combinat.ncsym.ncsym` """ + # install the docstring of this module to the containing package from sage.misc.namespace_package import install_doc + install_doc(__package__, __doc__) from sage.misc.lazy_import import lazy_import diff --git a/src/sage/combinat/ncsym/bases.py b/src/sage/combinat/ncsym/bases.py index 4be5f84de11..34bdd97f145 100644 --- a/src/sage/combinat/ncsym/bases.py +++ b/src/sage/combinat/ncsym/bases.py @@ -79,9 +79,8 @@ def super_categories(self): """ R = self.base().base_ring() from sage.categories.graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis - return [self.base().Realizations(), - GradedHopfAlgebrasWithBasis(R), - GradedHopfAlgebras(R).Realizations()] + + return [self.base().Realizations(), GradedHopfAlgebrasWithBasis(R), GradedHopfAlgebras(R).Realizations()] def _repr_(self): r""" @@ -296,11 +295,9 @@ def duality_pairing_matrix(self, basis, degree): [1] """ from sage.matrix.constructor import matrix + # TODO: generalize to keys indexing the basis of the graded component - return matrix(self.base_ring(), - [[self.duality_pairing(self[I], basis[J]) - for J in SetPartitions(degree)] - for I in SetPartitions(degree)]) + return matrix(self.base_ring(), [[self.duality_pairing(self[I], basis[J]) for J in SetPartitions(degree)] for I in SetPartitions(degree)]) class ElementMethods: def duality_pairing(self, other): @@ -365,8 +362,7 @@ def _repr_(self): sage: NCSymBases(NCSym) Category of bases of symmetric functions in non-commuting variables over the Rational Field """ - return "Category of bases of symmetric functions in non-commuting"\ - " variables over the {}".format(self.base().base_ring()) + return "Category of bases of symmetric functions in non-commuting" " variables over the {}".format(self.base().base_ring()) class ParentMethods: def from_symmetric_function(self, f): @@ -486,8 +482,7 @@ def internal_coproduct(self): + cp{{1, 3}, {2}} # cp{{1, 3}, {2}} """ if self.internal_coproduct_on_basis is not NotImplemented: - return Hom(self, tensor([self, self]), - ModulesWithBasis(self.base_ring()))(on_basis=self.internal_coproduct_on_basis) + return Hom(self, tensor([self, self]), ModulesWithBasis(self.base_ring()))(on_basis=self.internal_coproduct_on_basis) if hasattr(self, "internal_coproduct_by_coercion"): return self.internal_coproduct_by_coercion @@ -509,8 +504,7 @@ def internal_coproduct_by_coercion(self, x): - h{{1, 3}, {2}} # h{{1}, {2}, {3}} + h{{1, 3}, {2}} # h{{1, 3}, {2}} """ R = self.realization_of().a_realization() - return self.tensor_square().sum(coeff * tensor([self(R[A]), self(R[B])]) - for ((A, B), coeff) in R(x).internal_coproduct()) + return self.tensor_square().sum(coeff * tensor([self(R[A]), self(R[B])]) for ((A, B), coeff) in R(x).internal_coproduct()) class ElementMethods: def expand(self, n, alphabet='x'): @@ -633,19 +627,19 @@ def to_wqsym(self): R = parent.base_ring() m = NCSym.monomial() from sage.combinat.chas.wqsym import WordQuasiSymmetricFunctions + M = WordQuasiSymmetricFunctions(R).M() from itertools import permutations + OSP = M.basis().keys() def to_wqsym_on_m_basis(A): # Return the image of `\mathbf{m}_A` under the inclusion # map `NCSym \to WQSym`. l = len(A) - return M.sum_of_terms(((OSP([A[ui] for ui in u]), 1) - for u in permutations(range(l))), - distinct=True) - return M.linear_combination((to_wqsym_on_m_basis(A), coeff) - for A, coeff in m(self)) + return M.sum_of_terms(((OSP([A[ui] for ui in u]), 1) for u in permutations(range(l))), distinct=True) + + return M.linear_combination((to_wqsym_on_m_basis(A), coeff) for A, coeff in m(self)) def internal_coproduct(self): r""" @@ -749,8 +743,7 @@ def _repr_(self): sage: MultiplicativeNCSymBases(NCSym) Category of multiplicative bases of symmetric functions in non-commuting variables over the Rational Field """ - return "Category of multiplicative bases of symmetric functions in non-commuting"\ - " variables over the {}".format(self.base().base_ring()) + return "Category of multiplicative bases of symmetric functions in non-commuting" " variables over the {}".format(self.base().base_ring()) class ParentMethods: def product_on_basis(self, A, B): @@ -850,5 +843,4 @@ def _repr_(self): sage: NCSymDualBases(DNCSym) Category of bases of dual symmetric functions in non-commuting variables over the Rational Field """ - return "Category of bases of dual symmetric functions in non-commuting"\ - " variables over the {}".format(self.base().base_ring()) + return "Category of bases of dual symmetric functions in non-commuting" " variables over the {}".format(self.base().base_ring()) diff --git a/src/sage/combinat/ncsym/dual.py b/src/sage/combinat/ncsym/dual.py index 3f44b9c1b11..b8d28ed0640 100644 --- a/src/sage/combinat/ncsym/dual.py +++ b/src/sage/combinat/ncsym/dual.py @@ -57,10 +57,7 @@ def __init__(self, R): # Embedding of Sym in the homogeneous bases into DNCSym in the w basis Sym = SymmetricFunctions(self.base_ring()) - Sym_h_to_w = Sym.h().module_morphism(w.sum_of_partitions, - triangular='lower', - inverse_on_support=w._set_par_to_par, - codomain=w, category=category) + Sym_h_to_w = Sym.h().module_morphism(w.sum_of_partitions, triangular='lower', inverse_on_support=w._set_par_to_par, codomain=w, category=category) Sym_h_to_w.register_as_coercion() self.to_symmetric_function = Sym_h_to_w.section() @@ -98,6 +95,7 @@ def dual(self): Symmetric functions in non-commuting variables over the Rational Field """ from sage.combinat.ncsym.ncsym import SymmetricFunctionsNonCommutingVariables + return SymmetricFunctionsNonCommutingVariables(self.base_ring()) class w(NCSymBasis_abstract): @@ -131,16 +129,14 @@ def __init__(self, NCSymD): sage: w = SymmetricFunctionsNonCommutingVariables(QQ).dual().w() sage: TestSuite(w).run() """ + def key_func_set_part(A): return sorted(map(sorted, A)) R = NCSymD.base_ring() category = GradedHopfAlgebras(R).Commutative() category &= NCSymDualBases(NCSymD) - CombinatorialFreeModule.__init__(self, R, SetPartitions(), - prefix='w', bracket=False, - sorting_key=key_func_set_part, - category=category) + CombinatorialFreeModule.__init__(self, R, SetPartitions(), prefix='w', bracket=False, sorting_key=key_func_set_part, category=category) @lazy_attribute def to_symmetric_function(self): @@ -240,8 +236,7 @@ def unions(s): ret.extend([b[i - 1] for i in sorted(part)] for part in B) return P(ret) - return self.sum_of_terms([(unions(s), 1) - for s in Subsets(m, n)]) + return self.sum_of_terms([(unions(s), 1) for s in Subsets(m, n)]) def coproduct_on_basis(self, A): r""" @@ -272,10 +267,7 @@ def coproduct_on_basis(self, A): w{} # w{} """ n = A.size() - return self.tensor_square().sum_of_terms([ - ((A.restriction(range(1, i + 1)).standardization(), - A.restriction(range(i + 1, n + 1)).standardization()), 1) - for i in range(n + 1)], distinct=True) + return self.tensor_square().sum_of_terms([((A.restriction(range(1, i + 1)).standardization(), A.restriction(range(i + 1, n + 1)).standardization()), 1) for i in range(n + 1)], distinct=True) def antipode_on_basis(self, A): r""" @@ -301,8 +293,7 @@ def antipode_on_basis(self, A): if A.size() == 1: return -self(A) cpr = self.coproduct_on_basis(A) - return -sum(c * self.monomial(B1) * self.antipode_on_basis(B2) - for (B1, B2), c in cpr if B2 != A) + return -sum(c * self.monomial(B1) * self.antipode_on_basis(B2) for (B1, B2), c in cpr if B2 != A) def duality_pairing(self, x, y): r""" @@ -468,13 +459,10 @@ def expand(self, n, letter='x'): m = self.parent() names = [f'{letter}{i}{j}' for i in range(n) for j in range(n)] R = PolynomialRing(m.base_ring(), n * n, names) - x = [[R.gens()[i * n + j] - for j in range(n)] for i in range(n)] - I = R.ideal([x[i][j] * x[i][k] - for j in range(n) for k in range(n) for i in range(n)]) + x = [[R.gens()[i * n + j] for j in range(n)] for i in range(n)] + I = R.ideal([x[i][j] * x[i][k] for j in range(n) for k in range(n) for i in range(n)]) Q = R.quotient(I, names) - x = [[Q.gens()[i * n + j] - for j in range(n)] for i in range(n)] + x = [[Q.gens()[i * n + j] for j in range(n)] for i in range(n)] P = SetPartitions() def on_basis(A): @@ -486,9 +474,7 @@ def on_basis(A): for p in Permutations(k): if P(p.to_cycles()) == A: # -1 for indexing - ret += R.sum(prod(x[I[i]][I[p[i] - 1]] - for i in range(k)) - for I in Subsets(range(n), k)) + ret += R.sum(prod(x[I[i]][I[p[i] - 1]] for i in range(k)) for I in Subsets(range(n), k)) return ret return m._apply_module_morphism(self, on_basis, codomain=R) @@ -588,5 +574,4 @@ def to_symmetric_function(self): raise ValueError("not a symmetric function") h = SymmetricFunctions(self.parent().base_ring()).homogeneous() d = {A.shape(): c for A, c in self} - return h.sum_of_terms([(AA, cc / prod(factorial(i) for i in AA.to_exp())) - for AA, cc in d.items()], distinct=True) + return h.sum_of_terms([(AA, cc / prod(factorial(i) for i in AA.to_exp())) for AA, cc in d.items()], distinct=True) diff --git a/src/sage/combinat/ncsym/ncsym.py b/src/sage/combinat/ncsym/ncsym.py index 13f659d1eae..a59ce33e9f6 100644 --- a/src/sage/combinat/ncsym/ncsym.py +++ b/src/sage/combinat/ncsym/ncsym.py @@ -138,15 +138,15 @@ def nesting(la, nu): arcs = [] for p in nu: p = sorted(p) - arcs += [(p[i], p[i+1]) for i in range(len(p)-1)] + arcs += [(p[i], p[i + 1]) for i in range(len(p) - 1)] nst = 0 for p in la: p = sorted(p) for a in arcs: if p[-1] < a[0]: continue - for i in range(len(p)-1): - if a[1] <= p[i+1]: + for i in range(len(p) - 1): + if a[1] <= p[i + 1]: break if a[0] < p[i]: nst += 1 @@ -344,6 +344,7 @@ def dual(self): Dual symmetric functions in non-commuting variables over the Rational Field """ from sage.combinat.ncsym.dual import SymmetricFunctionsNonCommutingVariablesDual + return SymmetricFunctionsNonCommutingVariablesDual(self.base_ring()) class monomial(NCSymBasis_abstract): @@ -373,9 +374,7 @@ def __init__(self, NCSym): category = GradedHopfAlgebras(R).Cocommutative() category &= NCSymBases(NCSym) - CombinatorialFreeModule.__init__(self, R, SetPartitions(), - prefix='m', bracket=False, - category=category) + CombinatorialFreeModule.__init__(self, R, SetPartitions(), prefix='m', bracket=False, category=category) @cached_method def _m_to_p_on_basis(self, A): @@ -396,11 +395,11 @@ def _m_to_p_on_basis(self, A): ....: for A in SetPartitions(i)) True """ + def lt(s, t): if s == t: return False - return all(len([1 for z in t if z.intersection(p)]) == 1 - for p in s) + return all(len([1 for z in t if z.intersection(p)]) == 1 for p in s) p = self.realization_of().p() P = Poset((A.coarsenings(), lt)) @@ -429,9 +428,7 @@ def _m_to_cp_on_basis(self, A): cp = self.realization_of().cp() arcs = set(A.arcs()) R = self.base_ring() - return cp._from_dict({B: R((-1)**len(set(B.arcs()).difference(A.arcs()))) - for B in A.coarsenings() if arcs.issubset(B.arcs())}, - remove_zeros=False) + return cp._from_dict({B: R((-1) ** len(set(B.arcs()).difference(A.arcs()))) for B in A.coarsenings() if arcs.issubset(B.arcs())}, remove_zeros=False) def from_symmetric_function(self, f): r""" @@ -484,7 +481,7 @@ def from_symmetric_function(self, f): True """ m = SymmetricFunctions(self.base_ring()).m() - return self.sum([c * self.sum_of_partitions(i) for i,c in m(f)]) + return self.sum([c * self.sum_of_partitions(i) for i, c in m(f)]) def dual_basis(self): r""" @@ -593,11 +590,10 @@ def product_on_basis(self, A, B): P = SetPartitions() n = A.size() - B = [Set([y+n for y in b]) for b in B] # Shift B by n - unions = lambda m: [reduce(lambda a,b: a.union(b), x) for x in m] + B = [Set([y + n for y in b]) for b in B] # Shift B by n + unions = lambda m: [reduce(lambda a, b: a.union(b), x) for x in m] one = self.base_ring().one() - return self._from_dict({P(unions(m)): one for m in matchings(A, B)}, - remove_zeros=False) + return self._from_dict({P(unions(m)): one for m in matchings(A, B)}, remove_zeros=False) def coproduct_on_basis(self, A): r""" @@ -633,7 +629,7 @@ def coproduct_on_basis(self, A): P = SetPartitions() # Handle corner cases if not A: - return self.tensor_square().monomial(( P([]), P([]) )) + return self.tensor_square().monomial((P([]), P([]))) if len(A) == 1: return self.tensor_square().sum_of_monomials([(P([]), A), (A, P([]))]) @@ -643,7 +639,7 @@ def coproduct_on_basis(self, A): def to_basis(S): if not S: return P([]) - sub_parts = [list(A[i-1]) for i in S] # -1 for indexing + sub_parts = [list(A[i - 1]) for i in S] # -1 for indexing mins = [min(p) for p in sub_parts] over_max = max([max(p) for p in sub_parts]) + 1 ret = [[] for _ in repeat(None, len(S))] @@ -659,8 +655,9 @@ def to_basis(S): else: mins[i] = over_max return P(ret) - L1 = [(to_basis(S), to_basis(C)) for S,C in L] - L2 = [(M, N) for N,M in L1] + + L1 = [(to_basis(S), to_basis(C)) for S, C in L] + L2 = [(M, N) for N, M in L1] return self.tensor_square().sum_of_monomials(L1 + L2) def internal_coproduct_on_basis(self, A): @@ -691,15 +688,15 @@ def internal_coproduct_on_basis(self, A): """ P = SetPartitions() SP = SetPartitions(A.size()) - ret = [[A,A]] + ret = [[A, A]] for i, B in enumerate(SP): - for C in SP[i+1:]: + for C in SP[i + 1 :]: if B.inf(C) == A: B_std = P(list(B.standardization())) C_std = P(list(C.standardization())) ret.append([B_std, C_std]) ret.append([C_std, B_std]) - return self.tensor_square().sum_of_monomials((B, C) for B,C in ret) + return self.tensor_square().sum_of_monomials((B, C) for B, C in ret) def sum_of_partitions(self, la): r""" @@ -750,12 +747,12 @@ def sum_of_partitions(self, la): True """ from sage.combinat.partition import Partition - la = Partition(la) # Make sure it is a partition + + la = Partition(la) # Make sure it is a partition R = self.base_ring() P = SetPartitions() - c = R( prod(factorial(i) for i in la) / ZZ(factorial(la.size())) ) - return self._from_dict({P(m): c for m in SetPartitions(sum(la), la)}, - remove_zeros=False) + c = R(prod(factorial(i) for i in la) / ZZ(factorial(la.size()))) + return self._from_dict({P(m): c for m in SetPartitions(sum(la), la)}, remove_zeros=False) class Element(CombinatorialFreeModule.Element): """ @@ -792,6 +789,7 @@ def expand(self, n, alphabet='x'): """ from sage.algebras.free_algebra import FreeAlgebra from sage.combinat.permutation import Permutations + m = self.parent() F = FreeAlgebra(m.base_ring(), n, alphabet) @@ -801,9 +799,9 @@ def on_basis(A): basic_term = [0] * A.size() for index, part in enumerate(A): for i in part: - basic_term[i-1] = index # -1 for indexing - return sum( prod(x[p[i]-1] for i in basic_term) # -1 for indexing - for p in Permutations(n, len(A)) ) + basic_term[i - 1] = index # -1 for indexing + return sum(prod(x[p[i] - 1] for i in basic_term) for p in Permutations(n, len(A))) # -1 for indexing + return m._apply_module_morphism(self, on_basis, codomain=F) def to_symmetric_function(self): @@ -837,8 +835,7 @@ def to_symmetric_function(self): """ m = SymmetricFunctions(self.parent().base_ring()).monomial() c = lambda la: prod(factorial(i) for i in la.to_exp()) - return m.sum_of_terms((i.shape(), coeff*c(i.shape())) - for (i, coeff) in self) + return m.sum_of_terms((i.shape(), coeff * c(i.shape())) for (i, coeff) in self) m = monomial @@ -860,9 +857,7 @@ def __init__(self, NCSym): sage: NCSym = SymmetricFunctionsNonCommutingVariables(QQ) sage: TestSuite(NCSym.e()).run() """ - CombinatorialFreeModule.__init__(self, NCSym.base_ring(), SetPartitions(), - prefix='e', bracket=False, - category=MultiplicativeNCSymBases(NCSym)) + CombinatorialFreeModule.__init__(self, NCSym.base_ring(), SetPartitions(), prefix='e', bracket=False, category=MultiplicativeNCSymBases(NCSym)) ## Register coercions # monomials m = NCSym.m() @@ -871,16 +866,12 @@ def __init__(self, NCSym): # NOTE: Keep this ahead of creating the homogeneous basis to # get the coercion path m -> p -> e p = NCSym.p() - self.module_morphism(self._e_to_p_on_basis, codomain=p, - triangular='upper').register_as_coercion() - p.module_morphism(p._p_to_e_on_basis, codomain=self, - triangular='upper').register_as_coercion() + self.module_morphism(self._e_to_p_on_basis, codomain=p, triangular='upper').register_as_coercion() + p.module_morphism(p._p_to_e_on_basis, codomain=self, triangular='upper').register_as_coercion() # homogeneous h = NCSym.h() - self.module_morphism(self._e_to_h_on_basis, codomain=h, - triangular='upper').register_as_coercion() - h.module_morphism(h._h_to_e_on_basis, codomain=self, - triangular='upper').register_as_coercion() + self.module_morphism(self._e_to_h_on_basis, codomain=h, triangular='upper').register_as_coercion() + h.module_morphism(h._h_to_e_on_basis, codomain=self, triangular='upper').register_as_coercion() @cached_method def _e_to_m_on_basis(self, A): @@ -904,10 +895,9 @@ def _e_to_m_on_basis(self, A): m = self.realization_of().m() n = A.size() P = SetPartitions(n) - min_elt = P([[i] for i in range(1, n+1)]) + min_elt = P([[i] for i in range(1, n + 1)]) one = self.base_ring().one() - return m._from_dict({B: one for B in P if A.inf(B) == min_elt}, - remove_zeros=False) + return m._from_dict({B: one for B in P if A.inf(B) == min_elt}, remove_zeros=False) @cached_method def _e_to_h_on_basis(self, A): @@ -929,11 +919,10 @@ def _e_to_h_on_basis(self, A): True """ h = self.realization_of().h() - sign = lambda B: (-1)**(B.size() - len(B)) - coeff = lambda B: sign(B) * prod(factorial(sum( 1 for part in B if part.issubset(big) )) for big in A) + sign = lambda B: (-1) ** (B.size() - len(B)) + coeff = lambda B: sign(B) * prod(factorial(sum(1 for part in B if part.issubset(big))) for big in A) R = self.base_ring() - return h._from_dict({B: R(coeff(B)) for B in A.refinements()}, - remove_zeros=False) + return h._from_dict({B: R(coeff(B)) for B in A.refinements()}, remove_zeros=False) @cached_method def _e_to_p_on_basis(self, A): @@ -955,10 +944,9 @@ def _e_to_p_on_basis(self, A): True """ p = self.realization_of().p() - coeff = lambda B: prod([(-1)**(i-1) * factorial(i-1) for i in B.shape()]) + coeff = lambda B: prod([(-1) ** (i - 1) * factorial(i - 1) for i in B.shape()]) R = self.base_ring() - return p._from_dict({B: R(coeff(B)) for B in A.refinements()}, - remove_zeros=False) + return p._from_dict({B: R(coeff(B)) for B in A.refinements()}, remove_zeros=False) class Element(CombinatorialFreeModule.Element): """ @@ -1020,8 +1008,7 @@ def to_symmetric_function(self): """ e = SymmetricFunctions(self.parent().base_ring()).e() c = lambda la: prod(factorial(i) for i in la) - return e.sum_of_terms((i.shape(), coeff*c(i.shape())) - for (i, coeff) in self) + return e.sum_of_terms((i.shape(), coeff * c(i.shape())) for (i, coeff) in self) e = elementary @@ -1047,9 +1034,7 @@ def __init__(self, NCSym): sage: NCSym = SymmetricFunctionsNonCommutingVariables(QQ) sage: TestSuite(NCSym.h()).run() """ - CombinatorialFreeModule.__init__(self, NCSym.base_ring(), SetPartitions(), - prefix='h', bracket=False, - category=MultiplicativeNCSymBases(NCSym)) + CombinatorialFreeModule.__init__(self, NCSym.base_ring(), SetPartitions(), prefix='h', bracket=False, category=MultiplicativeNCSymBases(NCSym)) # Register coercions m = NCSym.m() self.module_morphism(self._h_to_m_on_basis, codomain=m).register_as_coercion() @@ -1080,8 +1065,7 @@ def _h_to_m_on_basis(self, A): m = self.realization_of().m() coeff = lambda B: prod(factorial(i) for i in B.shape()) R = self.base_ring() - return m._from_dict({P(B): R( coeff(A.inf(B)) ) - for B in SetPartitions(A.size())}, remove_zeros=False) + return m._from_dict({P(B): R(coeff(A.inf(B))) for B in SetPartitions(A.size())}, remove_zeros=False) @cached_method def _h_to_e_on_basis(self, A): @@ -1103,12 +1087,10 @@ def _h_to_e_on_basis(self, A): True """ e = self.realization_of().e() - sign = lambda B: (-1)**(B.size() - len(B)) - coeff = lambda B: (sign(B) * prod(factorial(sum( 1 for part in B if part.issubset(big) )) - for big in A)) + sign = lambda B: (-1) ** (B.size() - len(B)) + coeff = lambda B: (sign(B) * prod(factorial(sum(1 for part in B if part.issubset(big))) for big in A)) R = self.base_ring() - return e._from_dict({B: R(coeff(B)) for B in A.refinements()}, - remove_zeros=False) + return e._from_dict({B: R(coeff(B)) for B in A.refinements()}, remove_zeros=False) @cached_method def _h_to_p_on_basis(self, A): @@ -1130,10 +1112,9 @@ def _h_to_p_on_basis(self, A): True """ p = self.realization_of().p() - coeff = lambda B: abs( prod([(-1)**(i-1) * factorial(i-1) for i in B.shape()]) ) + coeff = lambda B: abs(prod([(-1) ** (i - 1) * factorial(i - 1) for i in B.shape()])) R = self.base_ring() - return p._from_dict({B: R(coeff(B)) for B in A.refinements()}, - remove_zeros=False) + return p._from_dict({B: R(coeff(B)) for B in A.refinements()}, remove_zeros=False) class Element(CombinatorialFreeModule.Element): """ @@ -1195,8 +1176,7 @@ def to_symmetric_function(self): """ h = SymmetricFunctions(self.parent().base_ring()).h() c = lambda la: prod(factorial(i) for i in la) - return h.sum_of_terms((i.shape(), coeff*c(i.shape())) - for (i, coeff) in self) + return h.sum_of_terms((i.shape(), coeff * c(i.shape())) for (i, coeff) in self) h = homogeneous @@ -1235,20 +1215,14 @@ def __init__(self, NCSym): sage: NCSym = SymmetricFunctionsNonCommutingVariables(QQ) sage: TestSuite(NCSym.p()).run() """ - CombinatorialFreeModule.__init__(self, NCSym.base_ring(), SetPartitions(), - prefix='p', bracket=False, - category=MultiplicativeNCSymBases(NCSym)) + CombinatorialFreeModule.__init__(self, NCSym.base_ring(), SetPartitions(), prefix='p', bracket=False, category=MultiplicativeNCSymBases(NCSym)) # Register coercions m = NCSym.m() - self.module_morphism(self._p_to_m_on_basis, codomain=m, - unitriangular='lower').register_as_coercion() - m.module_morphism(m._m_to_p_on_basis, codomain=self, - unitriangular='lower').register_as_coercion() + self.module_morphism(self._p_to_m_on_basis, codomain=m, unitriangular='lower').register_as_coercion() + m.module_morphism(m._m_to_p_on_basis, codomain=self, unitriangular='lower').register_as_coercion() x = NCSym.x() - self.module_morphism(self._p_to_x_on_basis, codomain=x, - unitriangular='upper').register_as_coercion() - x.module_morphism(x._x_to_p_on_basis, codomain=self, - unitriangular='upper').register_as_coercion() + self.module_morphism(self._p_to_x_on_basis, codomain=x, unitriangular='upper').register_as_coercion() + x.module_morphism(x._x_to_p_on_basis, codomain=self, unitriangular='upper').register_as_coercion() @cached_method def _p_to_m_on_basis(self, A): @@ -1294,10 +1268,9 @@ def _p_to_e_on_basis(self, A): """ e = self.realization_of().e() P_refine = Poset((A.refinements(), A.parent().lt)) - c = prod((-1)**(i-1) * factorial(i-1) for i in A.shape()) + c = prod((-1) ** (i - 1) * factorial(i - 1) for i in A.shape()) R = self.base_ring() - return e._from_dict({B: R(P_refine.moebius_function(B, A) / ZZ(c)) - for B in P_refine}, remove_zeros=False) + return e._from_dict({B: R(P_refine.moebius_function(B, A) / ZZ(c)) for B in P_refine}, remove_zeros=False) @cached_method def _p_to_h_on_basis(self, A): @@ -1320,10 +1293,9 @@ def _p_to_h_on_basis(self, A): """ h = self.realization_of().h() P_refine = Poset((A.refinements(), A.parent().lt)) - c = abs(prod((-1)**(i-1) * factorial(i-1) for i in A.shape())) + c = abs(prod((-1) ** (i - 1) * factorial(i - 1) for i in A.shape())) R = self.base_ring() - return h._from_dict({B: R(P_refine.moebius_function(B, A) / ZZ(c)) - for B in P_refine}, remove_zeros=False) + return h._from_dict({B: R(P_refine.moebius_function(B, A) / ZZ(c)) for B in P_refine}, remove_zeros=False) @cached_method def _p_to_x_on_basis(self, A): @@ -1376,7 +1348,7 @@ def coproduct_on_basis(self, A): P = SetPartitions() # Handle corner cases if not A: - return self.tensor_square().monomial(( P([]), P([]) )) + return self.tensor_square().monomial((P([]), P([]))) if len(A) == 1: return self.tensor_square().sum_of_monomials([(P([]), A), (A, P([]))]) @@ -1386,7 +1358,7 @@ def coproduct_on_basis(self, A): def to_basis(S): if not S: return P([]) - sub_parts = [list(A[i-1]) for i in S] # -1 for indexing + sub_parts = [list(A[i - 1]) for i in S] # -1 for indexing mins = [min(p) for p in sub_parts] over_max = max([max(p) for p in sub_parts]) + 1 ret = [[] for _ in repeat(None, len(S))] @@ -1402,8 +1374,9 @@ def to_basis(S): else: mins[i] = over_max return P(ret) - L1 = [(to_basis(S), to_basis(C)) for S,C in L] - L2 = [(M, N) for N,M in L1] + + L1 = [(to_basis(S), to_basis(C)) for S, C in L] + L2 = [(M, N) for N, M in L1] return self.tensor_square().sum_of_monomials(L1 + L2) def internal_coproduct_on_basis(self, A): @@ -1492,8 +1465,8 @@ def action(gamma): mins[i] = over_max ret += temp return P(ret) - return self.sum_of_terms( (A.ordered_set_partition_action(gamma), (-1)**len(gamma)) - for gamma in OrderedSetPartitions(len(A)) ) + + return self.sum_of_terms((A.ordered_set_partition_action(gamma), (-1) ** len(gamma)) for gamma in OrderedSetPartitions(len(A))) def primitive(self, A, i=1): r""" @@ -1537,11 +1510,10 @@ def primitive(self, A, i=1): """ if not A: return self.one() - A = SetPartitions()(A) # Make sure it's a set partition + A = SetPartitions()(A) # Make sure it's a set partition if not A.is_atomic(): return self.zero() - return self.sum_of_terms( (A.ordered_set_partition_action(gamma), (-1)**(len(gamma)-1)) - for gamma in OrderedSetPartitions(len(A)) if i in gamma[0] ) + return self.sum_of_terms((A.ordered_set_partition_action(gamma), (-1) ** (len(gamma) - 1)) for gamma in OrderedSetPartitions(len(A)) if i in gamma[0]) class Element(CombinatorialFreeModule.Element): """ @@ -1632,15 +1604,11 @@ def __init__(self, NCSym): sage: NCSym = SymmetricFunctionsNonCommutingVariables(QQ) sage: TestSuite(NCSym.cp()).run() """ - CombinatorialFreeModule.__init__(self, NCSym.base_ring(), SetPartitions(), - prefix='cp', bracket=False, - category=MultiplicativeNCSymBases(NCSym)) + CombinatorialFreeModule.__init__(self, NCSym.base_ring(), SetPartitions(), prefix='cp', bracket=False, category=MultiplicativeNCSymBases(NCSym)) # Register coercions m = NCSym.m() - self.module_morphism(self._cp_to_m_on_basis, codomain=m, - unitriangular='lower').register_as_coercion() - m.module_morphism(m._m_to_cp_on_basis, codomain=self, - unitriangular='lower').register_as_coercion() + self.module_morphism(self._cp_to_m_on_basis, codomain=m, unitriangular='lower').register_as_coercion() + m.module_morphism(m._m_to_cp_on_basis, codomain=self, unitriangular='lower').register_as_coercion() @cached_method def _cp_to_m_on_basis(self, A): @@ -1663,8 +1631,7 @@ def _cp_to_m_on_basis(self, A): """ m = self.realization_of().m() one = self.base_ring().one() - return m._from_dict({B: one for B in A.strict_coarsenings()}, - remove_zeros=False) + return m._from_dict({B: one for B in A.strict_coarsenings()}, remove_zeros=False) cp = coarse_powersum @@ -1705,9 +1672,7 @@ def __init__(self, NCSym): sage: NCSym = SymmetricFunctionsNonCommutingVariables(QQ) sage: TestSuite(NCSym.x()).run() """ - CombinatorialFreeModule.__init__(self, NCSym.base_ring(), SetPartitions(), - prefix='x', bracket=False, - category=MultiplicativeNCSymBases(NCSym)) + CombinatorialFreeModule.__init__(self, NCSym.base_ring(), SetPartitions(), prefix='x', bracket=False, category=MultiplicativeNCSymBases(NCSym)) @cached_method def _x_to_p_on_basis(self, A): @@ -1728,17 +1693,16 @@ def _x_to_p_on_basis(self, A): ....: for A in SetPartitions(i)) True """ + def lt(s, t): if s == t: return False - return all(len([1 for z in t if z.intersection(p)]) == 1 - for p in s) + return all(len([1 for z in t if z.intersection(p)]) == 1 for p in s) p = self.realization_of().p() P_refine = Poset((A.refinements(), lt)) R = self.base_ring() - return p._from_dict({B: R(P_refine.moebius_function(B, A)) - for B in P_refine}) + return p._from_dict({B: R(P_refine.moebius_function(B, A)) for B in P_refine}) x = x_basis @@ -1805,9 +1769,7 @@ def __init__(self, NCSym, q=2): """ R = NCSym.base_ring() self._q = R(q) - CombinatorialFreeModule.__init__(self, R, SetPartitions(), - prefix='rho', bracket=False, - category=MultiplicativeNCSymBases(NCSym)) + CombinatorialFreeModule.__init__(self, R, SetPartitions(), prefix='rho', bracket=False, category=MultiplicativeNCSymBases(NCSym)) # Register coercions m = NCSym.m() self.module_morphism(self._rho_to_m_on_basis, codomain=m).register_as_coercion() @@ -1856,9 +1818,7 @@ def _rho_to_m_on_basis(self, A): """ m = self.realization_of().m() arcs = set(A.arcs()) - return m._from_dict({B: self._q**-nesting(set(B).difference(A), A) - for B in A.coarsenings() if arcs.issubset(B.arcs())}, - remove_zeros=False) + return m._from_dict({B: self._q ** -nesting(set(B).difference(A), A) for B in A.coarsenings() if arcs.issubset(B.arcs())}, remove_zeros=False) @cached_method def _m_to_rho_on_basis(self, A): @@ -1882,12 +1842,9 @@ def _m_to_rho_on_basis(self, A): ....: for A in SetPartitions(i)) True """ - coeff = lambda A,B: ((-1)**len(set(B.arcs()).difference(A.arcs())) - / self._q**nesting(set(B).difference(A), B)) + coeff = lambda A, B: ((-1) ** len(set(B.arcs()).difference(A.arcs())) / self._q ** nesting(set(B).difference(A), B)) arcs = set(A.arcs()) - return self._from_dict({B: coeff(A,B) for B in A.coarsenings() - if arcs.issubset(B.arcs())}, - remove_zeros=False) + return self._from_dict({B: coeff(A, B) for B in A.coarsenings() if arcs.issubset(B.arcs())}, remove_zeros=False) rho = deformed_coarse_powersum @@ -1947,9 +1904,7 @@ def __init__(self, NCSym, q=2): """ R = NCSym.base_ring() self._q = R(q) - CombinatorialFreeModule.__init__(self, R, SetPartitions(), - prefix='chi', bracket=False, - category=MultiplicativeNCSymBases(NCSym)) + CombinatorialFreeModule.__init__(self, R, SetPartitions(), prefix='chi', bracket=False, category=MultiplicativeNCSymBases(NCSym)) # Register coercions m = NCSym.m() self.module_morphism(self._chi_to_m_on_basis, codomain=m).register_as_coercion() @@ -2002,14 +1957,9 @@ def _chi_to_m_on_basis(self, A): ret = {} for B in SetPartitions(A.size()): Barcs = B.arcs() - if any((a[0] == b[0] and b[1] < a[1]) - or (b[0] > a[0] and a[1] == b[1]) - for a in arcs for b in Barcs): + if any((a[0] == b[0] and b[1] < a[1]) or (b[0] > a[0] and a[1] == b[1]) for a in arcs for b in Barcs): continue - ret[B] = ((-1)**len(arcs.intersection(Barcs)) - * (q - 1)**(len(arcs) - len(arcs.intersection(Barcs))) - * q**(sum(a[1] - a[0] for a in arcs) - len(arcs)) - / q**nesting(B, A)) + ret[B] = (-1) ** len(arcs.intersection(Barcs)) * (q - 1) ** (len(arcs) - len(arcs.intersection(Barcs))) * q ** (sum(a[1] - a[0] for a in arcs) - len(arcs)) / q ** nesting(B, A) return m._from_dict(ret, remove_zeros=False) @cached_method @@ -2066,6 +2016,6 @@ def _m_to_chi_on_basis(self, A): lst = list(SetPartitions(n)) m = self._graded_inverse_matrix(n) i = lst.index(A) - return self._from_dict({B: m[j,i] for j,B in enumerate(lst)}) + return self._from_dict({B: m[j, i] for j, B in enumerate(lst)}) chi = supercharacter diff --git a/src/sage/combinat/necklace.py b/src/sage/combinat/necklace.py index a46c4a9e415..371819e8a57 100644 --- a/src/sage/combinat/necklace.py +++ b/src/sage/combinat/necklace.py @@ -7,6 +7,7 @@ Theoretical Computer Science archive Volume 301, Issue 1-3 (May 2003) :doi:`10.1016/S0304-3975(03)00049-5` """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # @@ -77,6 +78,7 @@ class Necklaces_evaluation(UniqueRepresentation, Parent): - ``content`` -- list or tuple of nonnegative integers """ + @staticmethod def __classcall_private__(cls, content): """ @@ -222,9 +224,7 @@ def cardinality(self) -> Integer: n = sum(le) - return ZZ.sum(euler_phi(j) * factorial(n // j) // - prod(factorial(ni // j) for ni in evaluation) - for j in divisors(gcd(le))) // n + return ZZ.sum(euler_phi(j) * factorial(n // j) // prod(factorial(ni // j) for ni in evaluation) for j in divisors(gcd(le))) // n def __iter__(self): r""" @@ -346,13 +346,9 @@ def _fast_fixed_content(a, content, t, p, k, r, s, dll, equality=False): sp = t + 1 if j == a[t - p - 1]: - yield from _fast_fixed_content(a[:], content, t + 1, p, - k, r, sp, dll, - equality=equality) + yield from _fast_fixed_content(a[:], content, t + 1, p, k, r, sp, dll, equality=equality) else: - yield from _fast_fixed_content(a[:], content, t + 1, t, - k, r, sp, dll, - equality=equality) + yield from _fast_fixed_content(a[:], content, t + 1, t, k, r, sp, dll, equality=equality) if not content[j]: # == 0 dll.unhide(j) @@ -431,11 +427,9 @@ def _list_fixed_content(a, content, t, p, k, dll, equality=False): dll.hide(j) if j == a[t - p - 1]: - yield from _list_fixed_content(a[:], content[:], t + 1, p, - k, dll, equality=equality) + yield from _list_fixed_content(a[:], content[:], t + 1, p, k, dll, equality=equality) else: - yield from _list_fixed_content(a[:], content[:], t + 1, t, - k, dll, equality=equality) + yield from _list_fixed_content(a[:], content[:], t + 1, t, k, dll, equality=equality) if not content[j]: # == 0 dll.unhide(j) @@ -514,11 +508,9 @@ def _simple_fixed_content(a, content, t, p, k, equality=False): a[t - 1] = j content[j] -= 1 if j == a[t - p - 1]: - yield from _simple_fixed_content(a[:], content, t + 1, p, - k, equality=equality) + yield from _simple_fixed_content(a[:], content, t + 1, p, k, equality=equality) else: - yield from _simple_fixed_content(a[:], content, t + 1, t, - k, equality=equality) + yield from _simple_fixed_content(a[:], content, t + 1, t, k, equality=equality) content[j] += 1 diff --git a/src/sage/combinat/non_decreasing_parking_function.py b/src/sage/combinat/non_decreasing_parking_function.py index 000b87c550d..3eb50946841 100644 --- a/src/sage/combinat/non_decreasing_parking_function.py +++ b/src/sage/combinat/non_decreasing_parking_function.py @@ -16,6 +16,7 @@ - Florent Hivert (2009-04) - Christian Stump (2012-11) added pretty printing """ + # **************************************************************************** # Copyright (C) 2007 Florent Hivert , # @@ -277,6 +278,7 @@ def to_dyck_word(self): True """ from sage.combinat.dyck_word import CompleteDyckWords_all + return CompleteDyckWords_all().from_non_decreasing_parking_function(self) def __len__(self) -> int: @@ -551,6 +553,7 @@ def random_element(self) -> NonDecreasingParkingFunction: True """ from sage.combinat.dyck_word import DyckWords + n = self.n dw = DyckWords(n).random_element() return NonDecreasingParkingFunction.from_dyck_word(dw) @@ -606,6 +609,7 @@ def __iter__(self): Complexity: constant amortized time. """ + def iterator_rec(n): """ TESTS:: @@ -626,6 +630,7 @@ def iterator_rec(n): res.append(i) yield res return + for res in iterator_rec(self.n): yield NonDecreasingParkingFunction(res) diff --git a/src/sage/combinat/nu_dyck_word.py b/src/sage/combinat/nu_dyck_word.py index 2e34e975915..3d4e62bdeec 100644 --- a/src/sage/combinat/nu_dyck_word.py +++ b/src/sage/combinat/nu_dyck_word.py @@ -212,6 +212,7 @@ class NuDyckWord(CombinatorialElement): | . . . sage: update_ndw_symbols(1,0) """ + @staticmethod def __classcall_private__(cls, dw=None, nu=None, **kwargs): """ @@ -227,6 +228,7 @@ def __classcall_private__(cls, dw=None, nu=None, **kwargs): # if dw is none, then we might have a normal Dyck word if dw is None: from sage.combinat.dyck_word import DyckWord + return DyckWord(dw, kwargs) if isinstance(dw, NuDyckWord): @@ -667,6 +669,7 @@ def _ascii_art_(self): ______| . . . . . . . """ from sage.typeset.ascii_art import AsciiArt + rep = self.parent().options.ascii_art if rep == "pretty_output": ret = self._repr_lattice() @@ -830,7 +833,7 @@ def _latex_(self): # Add points if wanted if latex_options['show_points']: pt_color = latex_options['points_color'] - radius = 0.15 + .03 * latex_options['line width'] + radius = 0.15 + 0.03 * latex_options['line width'] for v in self.points(): res += " \\draw[line width=2," res += f"color={pt_color},fill={pt_color}]" @@ -848,10 +851,7 @@ def _latex_(self): res += ";\n" # setup Path - res += " \\draw[rounded corners=1, color={}, line width={}]".format( - latex_options['color'], - str(latex_options['line width']) - ) + res += " \\draw[rounded corners=1, color={}, line width={}]".format(latex_options['color'], str(latex_options['line width'])) for k, p in enumerate(self._path.points()): if k == 0: res += " %s" % (str(p)) @@ -872,6 +872,7 @@ def plot(self, **kwds): Graphics object consisting of 1 graphics primitive """ from sage.plot.plot import list_plot + return list_plot(list(self.points()), plotjoined=True, **kwds) def path(self): @@ -1033,8 +1034,7 @@ def horizontal_distance(self): """ # Grab furthest east point at each height of nu nu_points = list(self._nu.points()) - nu_easts = [max(i for i, j in nu_points if j == k) - for k in range(self._nu.height() + 1)] + nu_easts = [max(i for i, j in nu_points if j == k) for k in range(self._nu.height() + 1)] points = list(self._path.points()) return [nu_easts[j] - i for i, j in points] @@ -1116,7 +1116,7 @@ def mutate(self, i) -> NuDyckWord | None: other_index = i break ndw = self._list - d = ndw[0:mutation_index - 1] + d = ndw[0 : mutation_index - 1] e = ndw[mutation_index:other_index] f = ndw[other_index:] return NuDyckWord(d + e + [ndw_close_symbol] + f, self._nu) @@ -1201,48 +1201,20 @@ class options(GlobalOptions): - latex_show_points: False - latex_tikz_scale: 1 """ + NAME = 'NuDyckWords' module = 'sage.combinat.nu_dyck_path' - display = {'default': "list", - 'description': 'Specifies how nu Dyck words should be printed', - 'values': {'list': 'displayed as a list', - 'lattice': 'displayed on the lattice defined by ``diagram_style``'}, - 'case_sensitive': False} - ascii_art = {'default': "pretty_output", - 'description': 'Specifies how the ascii art of nu Dyck words should be printed', - 'values': {'pretty_output': "Using pretty printing"}, - 'alias': {'pretty_print': "pretty_output"}, - 'case_sensitive': False} - diagram_style = {'default': "grid", - 'values': { - 'grid': 'printing as paths on a grid using N and E steps'}, - 'alias': {'N-E': 'grid'}, - 'case_sensitive': False} - latex_tikz_scale = {'default': 1, - 'description': 'The default value for the tikz scale when latexed', - 'checker': lambda x: True} # More trouble than it's worth to check - latex_line_width_scalar = {'default': 2, - 'description': 'The default value for the line width as a ' - 'multiple of the tikz scale when latexed', - 'checker': lambda x: True} # More trouble than it's worth to check - latex_color = {'default': "black", - 'description': 'The default value for the color when latexed', - 'checker': lambda x: isinstance(x, str)} - latex_show_points = {'default': False, - 'description': 'The default value for showing points', - 'checker': lambda x: isinstance(x, bool)} - latex_points_color = {'default': 'black', - 'description': 'The default value for path color.', - 'checker': lambda x: isinstance(x, str)} - latex_show_grid = {'default': True, - 'description': 'The default value for showing grid', - 'checker': lambda x: isinstance(x, bool)} - latex_show_nu = {'default': True, - 'description': 'The default value for showing nu', - 'checker': lambda x: isinstance(x, bool)} - latex_nu_options = {'default': 'rounded corners=1, color=red, line width=1', - 'description': 'The default value for options for nu path', - 'checker': lambda x: isinstance(x, str)} + display = {'default': "list", 'description': 'Specifies how nu Dyck words should be printed', 'values': {'list': 'displayed as a list', 'lattice': 'displayed on the lattice defined by ``diagram_style``'}, 'case_sensitive': False} + ascii_art = {'default': "pretty_output", 'description': 'Specifies how the ascii art of nu Dyck words should be printed', 'values': {'pretty_output': "Using pretty printing"}, 'alias': {'pretty_print': "pretty_output"}, 'case_sensitive': False} + diagram_style = {'default': "grid", 'values': {'grid': 'printing as paths on a grid using N and E steps'}, 'alias': {'N-E': 'grid'}, 'case_sensitive': False} + latex_tikz_scale = {'default': 1, 'description': 'The default value for the tikz scale when latexed', 'checker': lambda x: True} # More trouble than it's worth to check + latex_line_width_scalar = {'default': 2, 'description': 'The default value for the line width as a ' 'multiple of the tikz scale when latexed', 'checker': lambda x: True} # More trouble than it's worth to check + latex_color = {'default': "black", 'description': 'The default value for the color when latexed', 'checker': lambda x: isinstance(x, str)} + latex_show_points = {'default': False, 'description': 'The default value for showing points', 'checker': lambda x: isinstance(x, bool)} + latex_points_color = {'default': 'black', 'description': 'The default value for path color.', 'checker': lambda x: isinstance(x, str)} + latex_show_grid = {'default': True, 'description': 'The default value for showing grid', 'checker': lambda x: isinstance(x, bool)} + latex_show_nu = {'default': True, 'description': 'The default value for showing nu', 'checker': lambda x: isinstance(x, bool)} + latex_nu_options = {'default': 'rounded corners=1, color=red, line width=1', 'description': 'The default value for options for nu path', 'checker': lambda x: isinstance(x, str)} def _element_constructor_(self, word): """ @@ -1359,17 +1331,17 @@ def __iter__(self, N=[], D=[], i=None, X=None): [1, 1, 0, 1, 0, 0], [1, 1, 1, 0, 0, 0]] """ + # Define successor function for recursion def transpose_close_open(N): for k, v in enumerate(N._list): if k > 0 and v == ndw_open_symbol: w = N._list[k - 1] if w == ndw_close_symbol: - new = N._list[:k - 1] + [v, w] + N._list[k + 1:] + new = N._list[: k - 1] + [v, w] + N._list[k + 1 :] yield self.element_class(self, new) - RES = RecursivelyEnumeratedSet([self.element_class(self, self._nu)], - transpose_close_open) + RES = RecursivelyEnumeratedSet([self.element_class(self, self._nu)], transpose_close_open) return RES.breadth_first_search_iterator() def cardinality(self): diff --git a/src/sage/combinat/nu_tamari_lattice.py b/src/sage/combinat/nu_tamari_lattice.py index a4dfd1b93c7..07275ee6706 100644 --- a/src/sage/combinat/nu_tamari_lattice.py +++ b/src/sage/combinat/nu_tamari_lattice.py @@ -186,7 +186,7 @@ def delta_swap(p, k, delta): if alt == 0: found = True j += 1 - q = p[:k - 1] + p[k:j] + [p[k - 1]] + p[j:] + q = p[: k - 1] + p[k:j] + [p[k - 1]] + p[j:] return NuDyckWord(q, p._nu) @@ -250,8 +250,7 @@ def AltNuTamariLattice(nu, delta=None): - [CC2023]_ """ - if not ((isinstance(nu, (list, tuple)) and all(x in [0, 1] for x in nu)) or - (isinstance(nu, str) and all(x in ['0', '1'] for x in nu))): + if not ((isinstance(nu, (list, tuple)) and all(x in [0, 1] for x in nu)) or (isinstance(nu, str) and all(x in ['0', '1'] for x in nu))): raise ValueError("nu must be a list or a string of 0s and 1s") nu = [int(a) for a in nu] # transforms nu in a sequence of 0s and 1s if it is a list @@ -264,7 +263,6 @@ def AltNuTamariLattice(nu, delta=None): raise ValueError("delta is not a valid increment vector") def covers(p): - return [delta_swap(p, k, delta=delta) for k in range(1, p.length()) - if not p[k - 1] and p[k]] - return LatticePoset({p: covers(p) for p in NuDyckWords(nu)}, - check=False) + return [delta_swap(p, k, delta=delta) for k in range(1, p.length()) if not p[k - 1] and p[k]] + + return LatticePoset({p: covers(p) for p in NuDyckWords(nu)}, check=False) diff --git a/src/sage/combinat/ordered_tree.py b/src/sage/combinat/ordered_tree.py index b2bebef9367..548b1ba259b 100644 --- a/src/sage/combinat/ordered_tree.py +++ b/src/sage/combinat/ordered_tree.py @@ -6,6 +6,7 @@ - Florent Hivert (2010-2011): initial revision - Frédéric Chapoton (2010): contributed some methods """ + # **************************************************************************** # Copyright (C) 2010 Florent Hivert , # @@ -23,8 +24,7 @@ from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.misc.lazy_attribute import lazy_class_attribute from sage.misc.lazy_import import lazy_import -from sage.combinat.abstract_tree import (AbstractClonableTree, - AbstractLabelledClonableTree) +from sage.combinat.abstract_tree import AbstractClonableTree, AbstractLabelledClonableTree from sage.combinat.combinatorial_map import combinatorial_map from sage.misc.cachefunc import cached_method from sage.categories.sets_cat import Sets, EmptySetError @@ -37,8 +37,7 @@ lazy_import('sage.combinat.dyck_word', 'CompleteDyckWords_size') -class OrderedTree(AbstractClonableTree, ClonableList, - metaclass=InheritComparisonClasscallMetaclass): +class OrderedTree(AbstractClonableTree, ClonableList, metaclass=InheritComparisonClasscallMetaclass): """ The class of (ordered rooted) trees. @@ -178,6 +177,7 @@ class OrderedTree(AbstractClonableTree, ClonableList, sage: tt1.__hash__() == tt2.__hash__() False """ + @staticmethod def __classcall_private__(cls, *args, **opts): """ @@ -251,8 +251,7 @@ def __init__(self, parent=None, children=None, check=True): children = [] if isinstance(children, str): children = eval(children) - if (children.__class__ is self.__class__ and - children.parent() == parent): + if children.__class__ is self.__class__ and children.parent() == parent: children = list(children) else: children = [self.__class__(parent, x) for x in children] @@ -299,6 +298,7 @@ def _to_binary_tree_rec(self, bijection='left'): [., [[., [., .]], [[., [[., .], .]], .]]] """ from sage.combinat.binary_tree import BinaryTree + root = BinaryTree() if bijection == "left": for child in self: @@ -309,8 +309,7 @@ def _to_binary_tree_rec(self, bijection='left'): for child in children: root = BinaryTree([child._to_binary_tree_rec(bijection), root]) else: - raise ValueError("the bijection argument should be either " - "left or right") + raise ValueError("the bijection argument should be either " "left or right") return root @combinatorial_map(name="To binary tree, left brother = left child") @@ -411,6 +410,7 @@ def _to_parallelogram_polyomino_Boussicault_Socci(self): [[0, 0, 1], [1, 0, 0]] """ from sage.combinat.parallelogram_polyomino import ParallelogramPolyomino + if self.number_of_nodes() == 1: return ParallelogramPolyomino([[1], [1]]) upper_nodes = [] @@ -517,6 +517,7 @@ def to_dyck_word(self): word.extend(child.to_dyck_word()) word.append(0) from sage.combinat.dyck_word import DyckWord + return DyckWord(word) @combinatorial_map(name="To graph") @@ -557,6 +558,7 @@ def to_undirected_graph(self): False """ from sage.graphs.graph import Graph + g = Graph() if self in LabelledOrderedTrees(): relabel = False @@ -620,11 +622,10 @@ def to_poset(self, root_to_leaf=False): node = roots.pop() for child in node: elements.append(child.label()) - relations.append((node.label(), child.label()) - if root_to_leaf else (child.label(), - node.label())) + relations.append((node.label(), child.label()) if root_to_leaf else (child.label(), node.label())) roots.append(child) from sage.combinat.posets.posets import Poset + p = Poset([elements, relations]) if relabel: p = p.canonical_label() @@ -856,6 +857,7 @@ class OrderedTrees(UniqueRepresentation, Parent): is an implementation detail. It could be changed in the future and one should not rely on it. """ + @staticmethod def __classcall_private__(cls, n=None): """ @@ -931,9 +933,7 @@ def __init__(self): True sage: TestSuite(B).run() # long time """ - DisjointUnionEnumeratedSets.__init__( - self, Family(NonNegativeIntegers(), OrderedTrees_size), - facade=True, keepkey=False) + DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), OrderedTrees_size), facade=True, keepkey=False) def _repr_(self): """ @@ -994,6 +994,7 @@ def _element_constructor_(self, *args, **keywords): from sage.misc.lazy_attribute import lazy_attribute from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.combinat.composition import Compositions + ################################################################# # Enumerated set of binary trees of a given size ################################################################# @@ -1074,6 +1075,7 @@ def cardinality(self): if self._size == 0: return Integer(0) from .combinat import catalan_number + return catalan_number(self._size - 1) def random_element(self): @@ -1201,6 +1203,7 @@ class LabelledOrderedTree(AbstractLabelledClonableTree, OrderedTree): sage: LabelledOrderedTree([[],[[], []]], label = 3) 3[None[], None[None[], None[]]] """ + @staticmethod def __classcall_private__(cls, *args, **opts): """ diff --git a/src/sage/combinat/output.py b/src/sage/combinat/output.py index 944500e7c35..7ac6bd4b4b4 100644 --- a/src/sage/combinat/output.py +++ b/src/sage/combinat/output.py @@ -13,7 +13,6 @@ - Travis Scrimshaw (2020-08): Added support for ascii/unicode art """ - from string import Template from sage.combinat.tableau import Tableaux @@ -238,8 +237,7 @@ def tex_from_array(array, with_lines=True) -> str: lr = lr_macro.substitute(bar='|' if with_lines else '') if Tableaux.options.convention == "English": return '{%s\n%s\n}' % (lr, tex_from_skew_array(array, with_lines)) - return '{%s\n%s\n}' % (lr, tex_from_skew_array(array[::-1], with_lines, - align='t')) + return '{%s\n%s\n}' % (lr, tex_from_skew_array(array[::-1], with_lines, align='t')) def svg_from_array(array, with_lines=True) -> str: @@ -346,10 +344,8 @@ def tex_from_array_tuple(a_tuple, with_lines=True) -> str: """ lr = lr_macro.substitute(bar='|' if with_lines else '') if Tableaux.options.convention == "English": - return '{%s\n%s\n}' % (lr, ','.join( - r'\emptyset' if not comp else tex_from_skew_array(comp, with_lines) for comp in a_tuple)) - return '{%s\n%s\n}' % (lr, ','.join( - r'\emptyset' if not comp else tex_from_skew_array(comp[::-1], with_lines, align='t') for comp in a_tuple)) + return '{%s\n%s\n}' % (lr, ','.join(r'\emptyset' if not comp else tex_from_skew_array(comp, with_lines) for comp in a_tuple)) + return '{%s\n%s\n}' % (lr, ','.join(r'\emptyset' if not comp else tex_from_skew_array(comp[::-1], with_lines, align='t') for comp in a_tuple)) def tex_from_skew_array(array, with_lines=False, align='b') -> str: @@ -393,21 +389,22 @@ def tex_from_skew_array(array, with_lines=False, align='b') -> str: # function end_line which puts in the required \cline's. if with_lines: # last position of None in each row - nones = [1 if None not in row else 1 + len(row) - row[::-1].index(None) - for row in array] + nones = [1 if None not in row else 1 + len(row) - row[::-1].index(None) for row in array] def end_line(r): # in a slightly unpythonic way, we label the lines as 0, 1, ..., len(array) if r == 0: return r'\cline{%s-%s}' % (nones[0], len(array[0])) if r == len(array): - start = nones[r-1] - finish = len(array[r-1]) + start = nones[r - 1] + finish = len(array[r - 1]) else: - start = min(nones[r], nones[r-1]) - finish = max(len(array[r]), len(array[r-1])) + start = min(nones[r], nones[r - 1]) + finish = max(len(array[r]), len(array[r - 1])) return r'\\' if start > finish else r'\\\cline{%s-%s}' % (start, finish) + else: + def end_line(r): return r'\\' @@ -423,11 +420,10 @@ def end_line(r): lr_end += r'}' tex = r'%s$\begin{array}[%s]{*{%s}c}' % (raisebox_start, align, max(map(len, array))) - tex += end_line(0)+'\n' + tex += end_line(0) + '\n' for r in range(len(array)): - tex += '&'.join('' if c is None else r'%s%s%s' % (lr_start, c, lr_end) - for c in array[r]) - tex += end_line(r+1)+'\n' + tex += '&'.join('' if c is None else r'%s%s%s' % (lr_start, c, lr_end) for c in array[r]) + tex += end_line(r + 1) + '\n' return tex + r'\end{array}$' + raisebox_end @@ -452,8 +448,7 @@ def svg_from_skew_array(array, with_lines=False, align='b') -> str: Nx = max((len(line) for line in array), default=0) Ny = len(array) # viewBox - resu += '\"%.3f %.3f %.3f %.3f \">' % (-5, -5, - 10 * Nx + 10, 10 * Ny + 10) + resu += '\"%.3f %.3f %.3f %.3f \">' % (-5, -5, 10 * Nx + 10, 10 * Ny + 10) resu += resu1 for i, line in enumerate(array): @@ -524,6 +519,7 @@ def ascii_art_table(data, use_unicode=False, convention='English'): if use_unicode: import unicodedata + v = unicodedata.lookup('BOX DRAWINGS LIGHT VERTICAL') h = unicodedata.lookup('BOX DRAWINGS LIGHT HORIZONTAL') dl = unicodedata.lookup('BOX DRAWINGS LIGHT DOWN AND LEFT') @@ -549,22 +545,24 @@ def ascii_art_table(data, use_unicode=False, convention='English'): # Convert the input into a rectangular array with the top and bottom row # being all None's for ease later on. ncols = max(len(row) for row in data) - str_tab = [[None]*ncols] + [[art(val) if val is not None else None for val in row] + [None]*(ncols-len(row)) - for row in data] - str_tab.append([None]*ncols) + str_tab = [[None] * ncols] + [[art(val) if val is not None else None for val in row] + [None] * (ncols - len(row)) for row in data] + str_tab.append([None] * ncols) # Get the widths of the columns - col_widths = [1]*len(str_tab[0]) + col_widths = [1] * len(str_tab[0]) if use_unicode: # Special handling of overline not adding to printed length def get_len(e): if e is None: return 0 return len(e) - list(str(e)).count("\u0304") + else: + def get_len(e): if e is None: return 0 return len(e) + for row in str_tab: for i, e in enumerate(row): col_widths[i] = max(col_widths[i], get_len(e)) @@ -577,60 +575,60 @@ def get_len(e): l1 = "" l2 = "" for i, (e, w) in enumerate(zip(row, col_widths)): - prev_row = str_tab[nrow-1] + prev_row = str_tab[nrow - 1] if i == 0: if e is None: if prev_row[i] is None: - l1 += " "*(3+w) + l1 += " " * (3 + w) else: - l1 += ur + h*(2+w) - l2 += " "*(3+w) + l1 += ur + h * (2 + w) + l2 += " " * (3 + w) else: if prev_row[i] is None: - l1 += dr + h*(2+w) + l1 += dr + h * (2 + w) else: - l1 += vr + h*(2+w) + l1 += vr + h * (2 + w) l2 += "{} {:^{width}} ".format(v, e, width=w) else: if e is None: - if row[i-1] is None: - if prev_row[i-1] is None: + if row[i - 1] is None: + if prev_row[i - 1] is None: if prev_row[i] is None: - l1 += " "*(3+w) + l1 += " " * (3 + w) else: - l1 += ur + h*(2+w) + l1 += ur + h * (2 + w) else: if prev_row[i] is None: - l1 += ul + " "*(2+w) + l1 += ul + " " * (2 + w) else: - l1 += uh + h*(2+w) - l2 += " "*(3+w) + l1 += uh + h * (2 + w) + l2 += " " * (3 + w) else: - if prev_row[i-1] is None: + if prev_row[i - 1] is None: if prev_row[i] is None: - l1 += dl + " "*(2+w) + l1 += dl + " " * (2 + w) else: - l1 += vh + h*(2+w) + l1 += vh + h * (2 + w) else: if prev_row[i] is None: - l1 += vl + " "*(2+w) + l1 += vl + " " * (2 + w) else: - l1 += vh + h*(2+w) - l2 += v + " "*(2+w) + l1 += vh + h * (2 + w) + l2 += v + " " * (2 + w) else: - if row[i-1] is None: - if prev_row[i-1] is None: + if row[i - 1] is None: + if prev_row[i - 1] is None: if prev_row[i] is None: - l1 += dr + h*(2+w) + l1 += dr + h * (2 + w) else: - l1 += vr + h*(2+w) + l1 += vr + h * (2 + w) else: - l1 += vh + h*(2+w) + l1 += vh + h * (2 + w) else: - if prev_row[i-1] is None and prev_row[i] is None: - l1 += dh + h*(2+w) + if prev_row[i - 1] is None and prev_row[i] is None: + l1 += dh + h * (2 + w) else: - l1 += vh + h*(2+w) + l1 += vh + h * (2 + w) l2 += "{} {:^{width}} ".format(v, e, width=w) if row[-1] is None: @@ -655,10 +653,7 @@ def get_len(e): return "\n".join(matr) output = "\n".join(reversed(matr)) if use_unicode: - tr = { - ord(dl): ul, ord(dr): ur, - ord(ul): dl, ord(ur): dr, - ord(dh): uh, ord(uh): dh} + tr = {ord(dl): ul, ord(dr): ur, ord(ul): dl, ord(ur): dr, ord(dh): uh, ord(uh): dh} return output.translate(tr) return output @@ -727,6 +722,7 @@ def ascii_art_table_russian(data, use_unicode=False, compact=False): """ if use_unicode: import unicodedata + urdl = unicodedata.lookup('BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT') uldr = unicodedata.lookup('BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT') x = unicodedata.lookup('BOX DRAWINGS LIGHT DIAGONAL CROSS') @@ -745,7 +741,9 @@ def get_len(e): if e is None: return 0 return len(e) - list(str(e)).count("\u0304") + else: + def get_len(e): if e is None: return 0 @@ -770,11 +768,11 @@ def get_len(e): continue st = ' ' * ((max_height - k) * row_height) for j in range(k + 1): - N_box = box_exists(str_tab, k-j+1, j) - S_box = box_exists(str_tab, k-j, j-1) - SE_box = box_exists(str_tab, k-j-1, j) - E_box = box_exists(str_tab, k-j, j) - W_box = box_exists(str_tab, k-j+1, j-1) + N_box = box_exists(str_tab, k - j + 1, j) + S_box = box_exists(str_tab, k - j, j - 1) + SE_box = box_exists(str_tab, k - j - 1, j) + E_box = box_exists(str_tab, k - j, j) + W_box = box_exists(str_tab, k - j + 1, j - 1) if i == 0: if (N_box and S_box) or (W_box and E_box): st += x @@ -789,7 +787,7 @@ def get_len(e): else: st += ' ' if E_box: - st_num = str_tab[k-j][j] + st_num = str_tab[k - j][j] ln_left = len(st_num) // 2 st += st_num.rjust(row_height - 1 - ln_left + len(st_num), ' ').ljust(diag_length, ' ') else: @@ -807,10 +805,11 @@ def get_len(e): st += lstr st += ' ' * (2 * (row_height - i) - 1) st += rstr - st += ' ' * (i-1) + st += ' ' * (i - 1) str_list.append(st) import re + mm = min(len(re.search('^ +', ell)[0]) for ell in str_list) - 1 str_list = [ell[mm:].rstrip() for ell in str_list] while not str_list[-1]: diff --git a/src/sage/combinat/parallelogram_polyomino.py b/src/sage/combinat/parallelogram_polyomino.py index cf0c0762290..6f2641ab906 100644 --- a/src/sage/combinat/parallelogram_polyomino.py +++ b/src/sage/combinat/parallelogram_polyomino.py @@ -19,15 +19,12 @@ from sage.structure.list_clone import ClonableList from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.set_factories import (SetFactory, ParentWithSetFactory, - TopMostParentPolicy) +from sage.structure.set_factories import SetFactory, ParentWithSetFactory, TopMostParentPolicy from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.sets.set import Set from sage.misc.lazy_attribute import lazy_class_attribute from sage.misc.lazy_attribute import lazy_attribute -from sage.sets.disjoint_union_enumerated_sets import ( - DisjointUnionEnumeratedSets -) +from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.rings.integer import Integer from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.sets.family import Family @@ -42,6 +39,7 @@ from sage.misc.functional import sqrt from sage.misc.lazy_import import lazy_import + lazy_import("sage.plot.graphics", "Graphics") lazy_import("sage.plot.line", "line") lazy_import("sage.plot.text", "text") @@ -192,8 +190,7 @@ def __repr__(self) -> str: options.sort() width = 1 + max(len(key) for key in options) - txt = '\n'.join(' - {:{}} {}'.format(key + ':', width, pprint.pformat(self[key])) - for key in options) + txt = '\n'.join(' - {:{}} {}'.format(key + ':', width, pprint.pformat(self[key])) for key in options) return 'Current options for {}\n{}'.format(self._name, txt) def __setitem__(self, key, value): @@ -251,7 +248,7 @@ def __setitem__(self, key, value): 3 sage: o["size"]=-6 """ - assert (key in self._available_options) + assert key in self._available_options if value == "?": res = "Current value : " + str(self._options[key]) option_key = self._available_options[key] @@ -261,9 +258,9 @@ def __setitem__(self, key, value): else: available_options = self._available_options if "values" in available_options: - assert (value in self._available_options[key]["values"]) + assert value in self._available_options[key]["values"] if "checker" in available_options: - assert (available_options["checker"](value)) + assert available_options["checker"](value) self._options[key] = value def __call__(self, *get_values, **options): @@ -446,18 +443,14 @@ def _dispatch(self, obj, dispatch_to, option, *get_values, **set_values): sage: e.options(delim='p'); e p """ - assert (option in self._available_options) + assert option in self._available_options if dispatch_to[-1] == "_": dispatch_to = dispatch_to[:-1] f = getattr(obj, dispatch_to + "_" + str(self._options[option])) return f(*get_values, **set_values) -default_tikz_options = dict( - scale=1, line_size=1, point_size=3.5, color_line='black', - color_point='black', color_bounce_0='red', color_bounce_1='blue', - translation=[0, 0], rotation=0, mirror=None -) +default_tikz_options = dict(scale=1, line_size=1, point_size=3.5, color_line='black', color_point='black', color_bounce_0='red', color_bounce_1='blue', translation=[0, 0], rotation=0, mirror=None) r""" This is the default TIKZ options. @@ -478,34 +471,49 @@ def _dispatch(self, obj, dispatch_to, option, *get_values, **set_values): checker=lambda x: Set(x.keys()).issubset( Set( [ - 'scale', 'line_size', 'point_size', - 'color_line', 'color_point', 'translation', 'mirror', - 'rotation', 'color_bounce_0', 'color_bounce_1', + 'scale', + 'line_size', + 'point_size', + 'color_line', + 'color_point', + 'translation', + 'mirror', + 'rotation', + 'color_bounce_0', + 'color_bounce_1', ] ) - ) + ), ), drawing_components=dict( default=dict(diagram=True, tree=False, bounce_0=False, bounce_1=False, bounce_values=False), description='Different tree-like tableaux components to draw', checker=lambda x: Set(x.keys()).issubset( - Set(['diagram', 'tree', 'bounce_0', 'bounce_1', 'bounce_values', ]) - ) + Set( + [ + 'diagram', + 'tree', + 'bounce_0', + 'bounce_1', + 'bounce_values', + ] + ) + ), ), display=dict( default='list', values=dict( list='displayed as list', drawing='as a drawing', - ) + ), ), latex=dict( default='drawing', values=dict( list='displayed as list', drawing='as a drawing', - ) - ) + ), + ), ) r""" This global option contains all the data needed by the Parallelogram classes @@ -664,6 +672,7 @@ def XY(self, v): sage: dt.XY([1, 1]) [-1.0, 1.0] """ + def translate(pos, v): r""" Translate a position with a vector. @@ -695,7 +704,7 @@ def rotate(pos, angle): The rotated position. """ x, y = pos - return [x*cos(angle) - y*sin(angle), x*sin(angle) + y*cos(angle)] + return [x * cos(angle) - y * sin(angle), x * sin(angle) + y * cos(angle)] def mirror(pos, axe): r""" @@ -714,25 +723,15 @@ def mirror(pos, axe): if axe is None: return pos if not isinstance(axe, (list, tuple)): - raise ValueError( - "mirror option should be None or a list of two real" + - " encoding a 2D vector." - ) - n = float(sqrt(axe[0]**2 + axe[1]**2)) - axe[0] = float(axe[0]/n) - axe[1] = float(axe[1]/n) - sp = (pos[0]*axe[0] + pos[1]*axe[1]) - sn = (- pos[0]*axe[1] + pos[1]*axe[0]) - return [ - sp*axe[0] + sn*axe[1], - sp*axe[1] - sn*axe[0] - ] - return rotate( - mirror( - translate(self._XY(v), self._translation), - self._mirror - ), self._rotation - ) + raise ValueError("mirror option should be None or a list of two real" + " encoding a 2D vector.") + n = float(sqrt(axe[0] ** 2 + axe[1] ** 2)) + axe[0] = float(axe[0] / n) + axe[1] = float(axe[1] / n) + sp = pos[0] * axe[0] + pos[1] * axe[1] + sn = -pos[0] * axe[1] + pos[1] * axe[0] + return [sp * axe[0] + sn * axe[1], sp * axe[1] - sn * axe[0]] + + return rotate(mirror(translate(self._XY(v), self._translation), self._mirror), self._rotation) def draw_line(self, v1, v2, color=None, size=None): r""" @@ -771,9 +770,7 @@ def draw_line(self, v1, v2, color=None, size=None): size = self._line_size x1, y1 = self.XY(v1) x2, y2 = self.XY(v2) - return "\n \\draw[color=%s, line width=%s] (%f, %f) -- (%f, %f);" % ( - color, size, float(x1), float(y1), float(x2), float(y2) - ) + return "\n \\draw[color=%s, line width=%s] (%f, %f) -- (%f, %f);" % (color, size, float(x1), float(y1), float(x2), float(y2)) def draw_polyline(self, list_of_vertices, color=None, size=None): r""" @@ -806,9 +803,8 @@ def draw_polyline(self, list_of_vertices, color=None, size=None): (-1.000000, -1.000000) -- (0.000000, 0.000000);' """ res = "" - for i in range(len(list_of_vertices)-1): - res += self.draw_line( - list_of_vertices[i], list_of_vertices[i+1], color, size) + for i in range(len(list_of_vertices) - 1): + res += self.draw_line(list_of_vertices[i], list_of_vertices[i + 1], color, size) return res def draw_point(self, p1, color=None, size=None): @@ -844,13 +840,10 @@ def draw_point(self, p1, color=None, size=None): if size is None: size = self._point_size x1, y1 = self.XY(p1) - return "\n \\filldraw[color=%s] (%f, %f) circle (%spt);" % ( - color, float(x1), float(y1), size - ) + return "\n \\filldraw[color=%s] (%f, %f) circle (%spt);" % (color, float(x1), float(y1), size) -class ParallelogramPolyomino(ClonableList, - metaclass=InheritComparisonClasscallMetaclass): +class ParallelogramPolyomino(ClonableList, metaclass=InheritComparisonClasscallMetaclass): r""" Parallelogram Polyominoes. @@ -867,6 +860,7 @@ class ParallelogramPolyomino(ClonableList, sage: pp [[0, 1], [1, 0]] """ + @staticmethod def __classcall_private__(cls, *args, **opts): r""" @@ -945,7 +939,7 @@ def _ascii_art_(self): data = zip(self.lower_widths(), self.upper_widths()) txt = [] - for x,y in data: + for x, y in data: txt += [' ' * x + '*' * (y - x)] return AsciiArt(txt) @@ -977,7 +971,7 @@ def _unicode_art_(self): txt = ['┌' + '┬' * (data[0][1] - 1) + '┐'] for i in range(1, len(data)): - x1, y1 = data[i-1] + x1, y1 = data[i - 1] x2, y2 = data[i] line = [' ' * x1] if x1 == x2: @@ -1055,29 +1049,21 @@ def check(self): lower_path = self.lower_path() upper_path = self.upper_path() if lower_path == [0] and upper_path == [0]: - raise ValueError( - "the lower or the upper path can't be equal to [0]" - ) + raise ValueError("the lower or the upper path can't be equal to [0]") if lower_path == [] or upper_path == []: - raise ValueError( - "the lower or the upper path can't be equal to []" - ) + raise ValueError("the lower or the upper path can't be equal to []") if len(upper_path) != len(lower_path): - raise ValueError( - "the lower and upper paths have different sizes (%s != %s)" % ( - len(upper_path), len(lower_path) - ) - ) + raise ValueError("the lower and upper paths have different sizes (%s != %s)" % (len(upper_path), len(lower_path))) p_up = [0, 0] p_down = [0, 0] - for i in range(len(upper_path)-1): - p_up[1-upper_path[i]] += 1 - p_down[1-lower_path[i]] += 1 - if (p_up[0] <= p_down[0] or p_down[1] <= p_up[1]): + for i in range(len(upper_path) - 1): + p_up[1 - upper_path[i]] += 1 + p_down[1 - lower_path[i]] += 1 + if p_up[0] <= p_down[0] or p_down[1] <= p_up[1]: raise ValueError("the lower and upper paths are crossing") p_up[1 - upper_path[-1]] += 1 p_down[1 - lower_path[-1]] += 1 - if (p_up[0] != p_down[0] or p_up[1] != p_down[1]): + if p_up[0] != p_down[0] or p_up[1] != p_down[1]: raise ValueError("the two paths have distinct ends") def __hash__(self): @@ -1158,8 +1144,7 @@ def __init__(self, parent, value, check=True): ClonableList.__init__(self, parent, value) if check: if not isinstance(value, (list, tuple)): - raise ValueError( - "value %s must be a list or a tuple" % value) + raise ValueError("value %s must be a list or a tuple" % value) self.check() self._options = None @@ -1195,8 +1180,7 @@ def reflect(self) -> ParallelogramPolyomino: if self.size() == 1: return self a, b = self - return ParallelogramPolyomino([[1 - v for v in b], - [1 - v for v in a]]) + return ParallelogramPolyomino([[1 - v for v in b], [1 - v for v in a]]) def rotate(self) -> ParallelogramPolyomino: r""" @@ -1238,6 +1222,7 @@ def _to_dyck_delest_viennot(self): [] """ from sage.combinat.dyck_word import DyckWord + dyck = [] dick_size = self.size() - 1 if not dick_size: @@ -1275,9 +1260,10 @@ def _to_dyck_delest_viennot_peaks_valleys(self): [] """ from sage.combinat.dyck_word import DyckWord + a = self.heights() u = self.upper_heights() - b = [0] + [a[i]-u[i+1]+u[i]-1 for i in range(len(a)-1)] + [0] + b = [0] + [a[i] - u[i + 1] + u[i] - 1 for i in range(len(a) - 1)] + [0] dyck = [] for i in range(len(a)): dyck.extend([1] * (a[i] - b[i])) @@ -1389,21 +1375,21 @@ def _from_dyck_word_delest_viennot_peaks_valleys(dyck): a = [] b = [0] h = 0 - for i in range(len(dyck)-1): + for i in range(len(dyck) - 1): if dyck[i] == 1: h += 1 - if dyck[i+1] == 0: + if dyck[i + 1] == 0: a.append(h) else: - if dyck[i+1] == 1: + if dyck[i + 1] == 1: b.append(h) h -= 1 b.append(0) word_down = [] word_up = [] for i in range(len(a)): - word_down.extend([0]*(a[i]-b[i]) + [1]) - word_up.extend([1]+[0]*(a[i]-b[i+1])) + word_down.extend([0] * (a[i] - b[i]) + [1]) + word_up.extend([1] + [0] * (a[i] - b[i + 1])) return ParallelogramPolyomino([word_down, word_up]) @staticmethod @@ -1472,6 +1458,7 @@ def _to_binary_tree_Aval_Boussicault(self, position=None): . """ from sage.combinat.binary_tree import BinaryTree + if position is None: position = [0, 0] if self.size() == 1: @@ -1483,16 +1470,14 @@ def _to_binary_tree_Aval_Boussicault(self, position=None): h = left_son[0] + 1 while w < self.width(): if self[right_son[0]][w] == 1: - if self[right_son[0]-1][w] == 0: + if self[right_son[0] - 1][w] == 0: right_son[1] = w - result[1] = self._to_binary_tree_Aval_Boussicault( - right_son - ) + result[1] = self._to_binary_tree_Aval_Boussicault(right_son) break w += 1 while h < self.height(): if self[h][left_son[1]] == 1: - if self[h][left_son[1]-1] == 0: + if self[h][left_son[1] - 1] == 0: left_son[0] = h result[0] = self._to_binary_tree_Aval_Boussicault(left_son) break @@ -1678,8 +1663,8 @@ def make_tree(b_tree, d): res.append(make_tree(b_tree[1 - d], 1 - d)) res += make_tree(b_tree[d], d) return OrderedTree(res) - return make_tree( - self.to_binary_tree(bijection='Aval-Boussicault'), 1) + + return make_tree(self.to_binary_tree(bijection='Aval-Boussicault'), 1) @combinatorial_map(name="To ordered tree") def to_ordered_tree(self, bijection=None): @@ -2253,10 +2238,7 @@ def get_array(self): """ width = self.width() height = self.height() - return [ - [self.cell_is_inside(w, h) for w in range(width)] - for h in range(height) - ] + return [[self.cell_is_inside(w, h) for w in range(width)] for h in range(height)] class _polyomino_row: r""" @@ -2318,8 +2300,7 @@ def __getitem__(self, column): sage: [row[-1], row[0], row[1], row[2], row[3]] [0, 0, 1, 1, 0] """ - if (self.is_inside() and - 0 <= column and column < self.polyomino.width()): + if self.is_inside() and 0 <= column and column < self.polyomino.width(): return self.polyomino.get_array()[self.row][column] return 0 @@ -2533,7 +2514,7 @@ def bounce_path(self, direction=1): while self[pos] == 1: pos[direction] += 1 pos[direction] -= 1 - result.append(pos[direction]-old[direction]) + result.append(pos[direction] - old[direction]) direction = 1 - direction old[0], old[1] = pos ne[0], ne[1] = pos @@ -2587,8 +2568,7 @@ def bounce(self, direction=1): sage: PP.bounce(direction=0) 0 """ - return sum((1 + i//2) * pi - for i, pi in enumerate(self.bounce_path(direction))) + return sum((1 + i // 2) * pi for i, pi in enumerate(self.bounce_path(direction))) def area(self): r""" @@ -2730,30 +2710,21 @@ def _to_tikz_diagram(self): tikz_options = self.get_tikz_options() grid_width = self.width() + 1 grid_height = self.height() + 1 - drawing_tool = _drawing_tool( - tikz_options, - XY=lambda v: [v[0], grid_height-1-v[1]] - ) + drawing_tool = _drawing_tool(tikz_options, XY=lambda v: [v[0], grid_height - 1 - v[1]]) res = "" if self.size() == 1: res += drawing_tool.draw_line([0, 0], [1, 0]) return res res += drawing_tool.draw_line([0, 0], [0, self.lower_heights()[0]]) - res += drawing_tool.draw_line( - [grid_width-1, self.upper_heights()[grid_width-2]], - [grid_width-1, self.lower_heights()[grid_width-2]] - ) + res += drawing_tool.draw_line([grid_width - 1, self.upper_heights()[grid_width - 2]], [grid_width - 1, self.lower_heights()[grid_width - 2]]) res += drawing_tool.draw_line([0, 0], [self.upper_widths()[0], 0]) - res += drawing_tool.draw_line( - [self.lower_widths()[grid_height-2], grid_height-1], - [self.upper_widths()[grid_height-2], grid_height-1] - ) - for w in range(1, grid_width-1): - h1 = self.upper_heights()[w-1] + res += drawing_tool.draw_line([self.lower_widths()[grid_height - 2], grid_height - 1], [self.upper_widths()[grid_height - 2], grid_height - 1]) + for w in range(1, grid_width - 1): + h1 = self.upper_heights()[w - 1] h2 = self.lower_heights()[w] res += drawing_tool.draw_line([w, h1], [w, h2]) - for h in range(1, grid_height-1): - w1 = self.lower_widths()[h-1] + for h in range(1, grid_height - 1): + w1 = self.lower_widths()[h - 1] w2 = self.upper_widths()[h] res += drawing_tool.draw_line([w1, h], [w2, h]) return res @@ -2828,10 +2799,7 @@ def _to_tikz_bounce(self, directions=None): res = "" tikz_options = self.get_tikz_options() grid_height = self.height() + 1 - drawing_tool = _drawing_tool( - tikz_options, - XY=lambda v: [v[0], grid_height-1-v[1]] - ) + drawing_tool = _drawing_tool(tikz_options, XY=lambda v: [v[0], grid_height - 1 - v[1]]) def draw_bounce(direction, color): r""" @@ -2840,26 +2808,27 @@ def draw_bounce(direction, color): See :meth:`ParallelogramPolyomino.bounce_path` for more information about the bounce. """ - if (len(self.bounce_path(direction)) > - len(self.bounce_path(1 - direction))): + if len(self.bounce_path(direction)) > len(self.bounce_path(1 - direction)): increase_size_line = 1 else: increase_size_line = 0 res = "" bp = self.bounce_path(direction) pos = [0, 0] - pos[1-direction] += 1 + pos[1 - direction] += 1 old = list(pos) for e in bp: pos[direction] += e res += drawing_tool.draw_line( - [old[1], old[0]], [pos[1], pos[0]], + [old[1], old[0]], + [pos[1], pos[0]], color=color, - size=2*tikz_options['line_size'] + increase_size_line, + size=2 * tikz_options['line_size'] + increase_size_line, ) old[0], old[1] = pos - direction = 1-direction + direction = 1 - direction return res + if len(self.bounce_path(0)) > len(self.bounce_path(1)): if 0 in directions: res += draw_bounce(0, tikz_options['color_bounce_0']) @@ -2928,10 +2897,7 @@ def _to_tikz_tree(self): if self.size() == 1: return res grid_height = self.height() + 1 - drawing_tool = _drawing_tool( - tikz_options, - XY=lambda v: [v[0] + .5, grid_height-1-v[1] - .5] - ) + drawing_tool = _drawing_tool(tikz_options, XY=lambda v: [v[0] + 0.5, grid_height - 1 - v[1] - 0.5]) for node in self.get_BS_nodes(): res += drawing_tool.draw_point([node[1], node[0]]) res += drawing_tool.draw_point([0, 0]) @@ -3379,10 +3345,8 @@ def get_BS_nodes(self): sage: pp.set_options(drawing_components=dict(tree=True)) sage: view(pp) # not tested """ - result = [self._get_node_position_at_row(h) - for h in range(1, self.height())] - result.extend(self._get_node_position_at_column(w) - for w in range(1, self.width())) + result = [self._get_node_position_at_row(h) for h in range(1, self.height())] + result.extend(self._get_node_position_at_column(w) for w in range(1, self.width())) return result def get_right_BS_nodes(self): @@ -3660,29 +3624,29 @@ def _plot_diagram(self): G = Graphics() # Draw the inner grid - for i,u,v in zip(range(self.height()-1), self.upper_widths()[1:], self.lower_widths()): - G += line([(u,-i-1),(v,-i-1)],rgbcolor=(0,0,0)) - for i,u,v in zip(range(self.width()-1), self.upper_heights()[1:], self.lower_heights()): - G += line([(i+1,-u),(i+1,-v)],rgbcolor=(0,0,0)) + for i, u, v in zip(range(self.height() - 1), self.upper_widths()[1:], self.lower_widths()): + G += line([(u, -i - 1), (v, -i - 1)], rgbcolor=(0, 0, 0)) + for i, u, v in zip(range(self.width() - 1), self.upper_heights()[1:], self.lower_heights()): + G += line([(i + 1, -u), (i + 1, -v)], rgbcolor=(0, 0, 0)) # Draw the outer border lower_heights = [0] + self.lower_heights() for i in range(self.width()): - if lower_heights[i] != lower_heights[i+1]: - G += line([(i,-lower_heights[i]),(i,-lower_heights[i+1])],rgbcolor=(0,0,0),thickness=2) + if lower_heights[i] != lower_heights[i + 1]: + G += line([(i, -lower_heights[i]), (i, -lower_heights[i + 1])], rgbcolor=(0, 0, 0), thickness=2) upper_heights = self.upper_heights() + [self.height()] for i in range(self.width()): - if upper_heights[i] != upper_heights[i+1]: - G += line([(i+1,-upper_heights[i]),(i+1,-upper_heights[i+1])],rgbcolor=(0,0,0),thickness=2) + if upper_heights[i] != upper_heights[i + 1]: + G += line([(i + 1, -upper_heights[i]), (i + 1, -upper_heights[i + 1])], rgbcolor=(0, 0, 0), thickness=2) lower_widths = self.lower_widths() + [self.width()] for i in range(self.height()): - if lower_widths[i] != lower_widths[i+1]: - G += line([(lower_widths[i],-i-1),(lower_widths[i+1],-i-1)],rgbcolor=(0,0,0),thickness=2) + if lower_widths[i] != lower_widths[i + 1]: + G += line([(lower_widths[i], -i - 1), (lower_widths[i + 1], -i - 1)], rgbcolor=(0, 0, 0), thickness=2) upper_widths = [0] + self.upper_widths() for i in range(self.height()): - if upper_widths[i] != upper_widths[i+1]: - G += line([(upper_widths[i],-i),(upper_widths[i+1],-i)],rgbcolor=(0,0,0),thickness=2) + if upper_widths[i] != upper_widths[i + 1]: + G += line([(upper_widths[i], -i), (upper_widths[i + 1], -i)], rgbcolor=(0, 0, 0), thickness=2) return G @@ -3713,23 +3677,23 @@ def _plot_bounce(self, directions=None): directions = [0, 1] G = Graphics() if 0 in directions: - a,b = (1,0) - for bounce,u in enumerate(self.bounce_path(direction=0)): + a, b = (1, 0) + for bounce, u in enumerate(self.bounce_path(direction=0)): if bounce & 1: - u,v = a+u,b + u, v = a + u, b else: - u,v = a,b+u - G += line([(a-.1,-b),(u-.1,-v)], rgbcolor=(1,0,0), thickness=1.5) - a,b = u,v + u, v = a, b + u + G += line([(a - 0.1, -b), (u - 0.1, -v)], rgbcolor=(1, 0, 0), thickness=1.5) + a, b = u, v if 1 in directions: - a,b = (0,1) - for bounce,u in enumerate(self.bounce_path(direction=1)): + a, b = (0, 1) + for bounce, u in enumerate(self.bounce_path(direction=1)): if bounce & 1: - u,v = a,b+u + u, v = a, b + u else: - u,v = a+u,b - G += line([(a,-b+.1),(u,-v+.1)], rgbcolor=(0,0,1), thickness=1.5) - a,b = u,v + u, v = a + u, b + G += line([(a, -b + 0.1), (u, -v + 0.1)], rgbcolor=(0, 0, 1), thickness=1.5) + a, b = u, v return G def _plot_bounce_values(self, bounce=0): @@ -3755,30 +3719,30 @@ def _plot_bounce_values(self, bounce=0): # Bounce path from the top if bounce == 0: - a,b = (0,-1) - for bounce,u in enumerate(self.bounce_path(direction=0)): + a, b = (0, -1) + for bounce, u in enumerate(self.bounce_path(direction=0)): if bounce & 1: - u,v = a+u,b + u, v = a + u, b else: - u,v = a,b+u - for i in range(a,u+1): - for j in range(b,v+1): - if (i,j) != (a,b): - G += text(str(bounce//2 + 1), (i+.5,-j-.5),rgbcolor=(0,0,0)) - a,b = u,v - #Bounce path from the left + u, v = a, b + u + for i in range(a, u + 1): + for j in range(b, v + 1): + if (i, j) != (a, b): + G += text(str(bounce // 2 + 1), (i + 0.5, -j - 0.5), rgbcolor=(0, 0, 0)) + a, b = u, v + # Bounce path from the left else: - a,b = (-1,0) - for bounce,u in enumerate(self.bounce_path(direction=1)): + a, b = (-1, 0) + for bounce, u in enumerate(self.bounce_path(direction=1)): if bounce & 1: - u,v = a,b+u + u, v = a, b + u else: - u,v = a+u,b - for i in range(a,u+1): - for j in range(b,v+1): - if (i,j) != (a,b): - G += text(str(bounce//2 + 1), (i+.5,-j-.5),rgbcolor=(0,0,0)) - a,b = u,v + u, v = a + u, b + for i in range(a, u + 1): + for j in range(b, v + 1): + if (i, j) != (a, b): + G += text(str(bounce // 2 + 1), (i + 0.5, -j - 0.5), rgbcolor=(0, 0, 0)) + a, b = u, v return G def _plot_tree(self): @@ -3801,8 +3765,8 @@ def _plot_tree(self): Graphics object consisting of 2 graphics primitives """ G = Graphics() - G += point(points=((v+.5,-u-.5) for u,v in self.get_BS_nodes()),size=20) - G += point([.5, -.5],size=20) + G += point(points=((v + 0.5, -u - 0.5) for u, v in self.get_BS_nodes()), size=20) + G += point([0.5, -0.5], size=20) return G def plot(self): @@ -3988,8 +3952,7 @@ def __call__(self, size=None, policy=None): return ParallelogramPolyominoes_size(size, policy) if size is None: return ParallelogramPolyominoes_all(policy) - raise ValueError("invalid argument for Parallelogram Polyominoes " - "Factory") + raise ValueError("invalid argument for Parallelogram Polyominoes " "Factory") @lazy_attribute def _default_policy(self): @@ -4023,13 +3986,10 @@ def _repr_(self) -> str: ParallelogramPolyominoes = ParallelogramPolyominoesFactory() -ParallelogramPolyominoes.__doc__ = \ - ParallelogramPolyominoesFactory.__call__.__doc__ +ParallelogramPolyominoes.__doc__ = ParallelogramPolyominoesFactory.__call__.__doc__ -class ParallelogramPolyominoes_size( - ParentWithSetFactory, UniqueRepresentation -): +class ParallelogramPolyominoes_size(ParentWithSetFactory, UniqueRepresentation): r""" The parallelogram polyominoes of size `n`. @@ -4056,9 +4016,7 @@ def __init__(self, size, policy): Parallelogram polyominoes of size 4 """ self._size = size - ParentWithSetFactory.__init__( - self, (size, ), policy, category=FiniteEnumeratedSets() - ) + ParentWithSetFactory.__init__(self, (size,), policy, category=FiniteEnumeratedSets()) def _repr_(self) -> str: r""" @@ -4098,8 +4056,7 @@ def check_element(self, el, check): True """ if el.size() != self.size(): - raise ValueError( - "the parallelogram polyomino has a wrong size: %s" % el.size()) + raise ValueError("the parallelogram polyomino has a wrong size: %s" % el.size()) def cardinality(self): r""" @@ -4143,6 +4100,7 @@ def __iter__(self): True """ from sage.combinat.dyck_word import DyckWords + for dyck in DyckWords(self.size() - 1): yield ParallelogramPolyomino.from_dyck_word(dyck) @@ -4202,9 +4160,7 @@ def set_options(self, *get_value, **set_value): """ -class ParallelogramPolyominoes_all( - ParentWithSetFactory, DisjointUnionEnumeratedSets -): +class ParallelogramPolyominoes_all(ParentWithSetFactory, DisjointUnionEnumeratedSets): r""" This class enumerates all the parallelogram polyominoes. @@ -4232,18 +4188,8 @@ def __init__(self, policy): sage: next(PPS.__iter__()) in PPS True """ - ParentWithSetFactory.__init__( - self, (), policy, category=FiniteEnumeratedSets() - ) - DisjointUnionEnumeratedSets.__init__( - self, Family( - PositiveIntegers(), - lambda n: ParallelogramPolyominoes_size( - n, policy=self.facade_policy() - ) - ), - facade=True, keepkey=False, category=self.category() - ) + ParentWithSetFactory.__init__(self, (), policy, category=FiniteEnumeratedSets()) + DisjointUnionEnumeratedSets.__init__(self, Family(PositiveIntegers(), lambda n: ParallelogramPolyominoes_size(n, policy=self.facade_policy())), facade=True, keepkey=False, category=self.category()) def _repr_(self) -> str: r""" diff --git a/src/sage/combinat/parking_functions.py b/src/sage/combinat/parking_functions.py index d75e54534ca..297497fb437 100644 --- a/src/sage/combinat/parking_functions.py +++ b/src/sage/combinat/parking_functions.py @@ -38,6 +38,7 @@ - used non-decreasing_parking_functions code by Florent Hivert (2009 - 04) - Dorota Mazur (2012 - 09) """ + # **************************************************************************** # Copyright (C) 2012 Dorota Mazur # @@ -153,9 +154,9 @@ class ParkingFunction(ClonableArray, metaclass=InheritComparisonClasscallMetacla ... ValueError: [3, 1, 2] is not a valid labeling of area sequence [0, 1, 1] """ + @staticmethod - def __classcall_private__(cls, pf=None, labelling=None, area_sequence=None, - labelled_dyck_word=None): + def __classcall_private__(cls, pf=None, labelling=None, area_sequence=None, labelled_dyck_word=None): """ Construct a parking function based on the input. @@ -171,9 +172,9 @@ def __classcall_private__(cls, pf=None, labelling=None, area_sequence=None, PF = ParkingFunctions() return PF.element_class(PF, pf) if labelling is not None: - if (area_sequence is None): + if area_sequence is None: raise ValueError("must also provide area sequence along with labelling") - if (len(area_sequence) != len(labelling)): + if len(area_sequence) != len(labelling): raise ValueError("%s must be the same size as the labelling %s" % (area_sequence, labelling)) if any(area_sequence[i] < area_sequence[i + 1] and labelling[i] > labelling[i + 1] for i in range(len(labelling) - 1)): raise ValueError("%s is not a valid labeling of area sequence %s" % (labelling, area_sequence)) @@ -182,8 +183,7 @@ def __classcall_private__(cls, pf=None, labelling=None, area_sequence=None, return from_labelled_dyck_word(labelled_dyck_word) if area_sequence is not None: DW = DyckWord(area_sequence) - return ParkingFunction(labelling=list(range(1, DW.size() + 1)), - area_sequence=DW) + return ParkingFunction(labelling=list(range(1, DW.size() + 1)), area_sequence=DW) raise ValueError("did not manage to make this into a parking function") @@ -298,8 +298,7 @@ def diagonal_reading_word(self) -> Permutation: L = self.to_labelling_permutation() D = self.to_area_sequence() m = max(D) - data = [L[-j - 1] for i in range(m + 1) - for j in range(len(L)) if D[-j - 1] == m - i] + data = [L[-j - 1] for i in range(m + 1) for j in range(len(L)) if D[-j - 1] == m - i] return Permutation(data) # type:ignore diagonal_word = diagonal_reading_word @@ -439,7 +438,7 @@ def jump(self) -> Integer: # sum of all jumps, sum of all displacements """ return sum(self.jump_list()) - def lucky_cars(self): # the set of cars that can park in their preferred spots + def lucky_cars(self): # the set of cars that can park in their preferred spots r""" Return the cars that can park in their preferred spots. For example, ``lucky_cars(PF) = [1, 2, 7]`` means that cars 1, 2 and 7 parked in @@ -516,8 +515,7 @@ def primary_dinversion_pairs(self) -> list[tuple[int, int]]: """ L = self.to_labelling_permutation() D = self.to_area_sequence() - return [(i, j) for j in range(len(D)) for i in range(j) - if D[i] == D[j] and L[i] < L[j]] + return [(i, j) for j in range(len(D)) for i in range(j) if D[i] == D[j] and L[i] < L[j]] def secondary_dinversion_pairs(self) -> list[tuple[int, int]]: r""" @@ -546,8 +544,7 @@ def secondary_dinversion_pairs(self) -> list[tuple[int, int]]: """ L = self.to_labelling_permutation() D = self.to_area_sequence() - return [(i, j) for j in range(len(D)) for i in range(j) - if D[i] == D[j] + 1 and L[i] > L[j]] + return [(i, j) for j in range(len(D)) for i in range(j) if D[i] == D[j] + 1 and L[i] > L[j]] def dinversion_pairs(self) -> list[tuple[int, int]]: r""" @@ -787,6 +784,7 @@ def to_labelling_permutation(self) -> Permutation: [2, 4, 1, 3] """ from sage.combinat.words.word import Word + return Word(self).standard_permutation().inverse() def to_area_sequence(self) -> list: @@ -963,8 +961,7 @@ def to_NonDecreasingParkingFunction(self) -> PF: """ return ParkingFunction(sorted(self)) # type:ignore - def characteristic_quasisymmetric_function(self, q=None, - R=QQ['q', 't'].fraction_field()): + def characteristic_quasisymmetric_function(self, q=None, R=QQ['q', 't'].fraction_field()): r""" Return the characteristic quasisymmetric function of ``self``. @@ -1009,13 +1006,14 @@ def characteristic_quasisymmetric_function(self, q=None, q^2*F[1, 1, 1, 2, 1, 3] """ from sage.combinat.ncsf_qsym.qsym import QuasiSymmetricFunctions + if q is None: q = R('q') else: if q not in R: raise ValueError("q=%s must be an element of the base ring %s" % (q, R)) F = QuasiSymmetricFunctions(R).Fundamental() - return q**self.dinv() * F(self.ides_composition()) + return q ** self.dinv() * F(self.ides_composition()) def pretty_print(self, underpath=True): r""" @@ -1160,9 +1158,7 @@ def from_labelling_and_area_sequence(L, D) -> PF: True """ PF = ParkingFunctions_all() - return PF.element_class(PF, - [L.index(i) + 1 - D[L.index(i)] - for i in range(1, len(L) + 1)]) + return PF.element_class(PF, [L.index(i) + 1 - D[L.index(i)] for i in range(1, len(L) + 1)]) def from_labelled_dyck_word(LDW) -> PF: @@ -1278,6 +1274,7 @@ class ParkingFunctions(UniqueRepresentation, Parent): sage: len(PF.list()) == PF.cardinality() True """ + @staticmethod def __classcall_private__(cls, n=None): """ @@ -1495,7 +1492,7 @@ def cardinality(self) -> Integer: sage: [ParkingFunctions(i).cardinality() for i in range(6)] [1, 1, 3, 16, 125, 1296] """ - return Integer((self.n + 1)**(self.n - 1)) + return Integer((self.n + 1) ** (self.n - 1)) def __iter__(self) -> Iterator: """ @@ -1532,6 +1529,7 @@ def __iter__(self) -> Iterator: sage: [e for e in PF] == PF.list() True """ + def iterator_rec(n): """ TESTS:: @@ -1550,6 +1548,7 @@ def iterator_rec(n): for i in range(res1[-1], n + 1): yield res1 + [i] return + for res in iterator_rec(self.n): for pi in Permutations(res): yield self.element_class(self, list(pi)) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index af750da7f3e..94cc3a1d174 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -273,6 +273,7 @@ sage: pl > ql True """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # @@ -460,6 +461,7 @@ class Partition(CombinatorialElement): ... ValueError: [0, 7, 3] is not an element of Partitions """ + @staticmethod def __classcall_private__(cls, mu=None, **keyword): """ @@ -509,7 +511,7 @@ def __setstate__(self, state): sage: loads(dumps( Partition([3,2,1]) )) # indirect doctest [3, 2, 1] """ - if isinstance(state, dict): # for old pickles from Partition_class + if isinstance(state, dict): # for old pickles from Partition_class self._set_parent(_Partitions) self.__dict__ = state else: @@ -639,6 +641,7 @@ def _ascii_art_(self): [ *****, * , ** , * , * , * , * ] """ from sage.typeset.ascii_art import AsciiArt + return AsciiArt(self._repr_diagram().splitlines(), baseline=0) def _unicode_art_(self): @@ -711,8 +714,7 @@ def _repr_exp_low(self): if not self._list: return '-' exp = self.to_exp() - return ', '.join('{}{}'.format(m, '' if e == 1 else '^%s' % e) - for m, e in enumerate(exp, start=1) if e) + return ', '.join('{}{}'.format(m, '' if e == 1 else '^%s' % e) for m, e in enumerate(exp, start=1) if e) def _repr_exp_high(self): """ @@ -729,10 +731,9 @@ def _repr_exp_high(self): """ if not self._list: return '-' - exp = self.to_exp()[::-1] # reversed list of exponents + exp = self.to_exp()[::-1] # reversed list of exponents M = max(self) - return ', '.join('{}{}'.format(M - m, '' if e == 1 else '^%s' % e) - for m, e in enumerate(exp) if e) + return ', '.join('{}{}'.format(M - m, '' if e == 1 else '^%s' % e) for m, e in enumerate(exp) if e) def _repr_compact_low(self): """ @@ -749,8 +750,7 @@ def _repr_compact_low(self): if not self._list: return '-' exp = self.to_exp() - return ','.join('{}{}'.format(m, '' if e == 1 else '^%s' % e) - for m, e in enumerate(exp, start=1) if e) + return ','.join('{}{}'.format(m, '' if e == 1 else '^%s' % e) for m, e in enumerate(exp, start=1) if e) def _repr_compact_high(self): """ @@ -766,10 +766,9 @@ def _repr_compact_high(self): """ if not self._list: return '-' - exp = self.to_exp()[::-1] # reversed list of exponents + exp = self.to_exp()[::-1] # reversed list of exponents M = max(self) - return ','.join('{}{}'.format(M - m, '' if e == 1 else '^%s' % e) - for m, e in enumerate(exp) if e) + return ','.join('{}{}'.format(M - m, '' if e == 1 else '^%s' % e) for m, e in enumerate(exp) if e) def _repr_diagram(self): r""" @@ -891,8 +890,8 @@ def _latex_young_diagram(self) -> str: return "{\\emptyset}" from sage.combinat.output import tex_from_array - return tex_from_array([["\\phantom{x}"] * row_size - for row_size in self._list]) + + return tex_from_array([["\\phantom{x}"] * row_size for row_size in self._list]) def _latex_diagram(self) -> str: r""" @@ -915,8 +914,8 @@ def _latex_diagram(self) -> str: entry = self.parent().options("latex_diagram_str") from sage.combinat.output import tex_from_array - return tex_from_array([[entry] * row_size - for row_size in self._list], False) + + return tex_from_array([[entry] * row_size for row_size in self._list], False) def _latex_list(self) -> str: r""" @@ -945,8 +944,7 @@ def _latex_exp_low(self) -> str: if not self._list: return "{\\emptyset}" exp = self.to_exp() - return '%s' % ','.join('{}{}'.format(m + 1, '' if e == 1 else '^{%s}' % e) - for m, e in enumerate(exp) if e > 0) + return '%s' % ','.join('{}{}'.format(m + 1, '' if e == 1 else '^{%s}' % e) for m, e in enumerate(exp) if e > 0) def _latex_exp_high(self): r""" @@ -963,8 +961,7 @@ def _latex_exp_high(self): return "{\\emptyset}" exp = self.to_exp()[::-1] # reversed list of exponents M = max(self) - return ','.join('{}{}'.format(M - m, '' if e == 1 else '^{%s}' % e) - for m, e in enumerate(exp) if e) + return ','.join('{}{}'.format(M - m, '' if e == 1 else '^{%s}' % e) for m, e in enumerate(exp) if e) def ferrers_diagram(self) -> str: r""" @@ -1128,7 +1125,7 @@ def __next__(self): n += i m += 1 - next_p = p[:] + [1]*(n - len(p)) + next_p = p[:] + [1] * (n - len(p)) # Check to see if we are at the last (all ones) partition if p == [1] * n: @@ -1145,18 +1142,18 @@ def __next__(self): if i != 1: h += 1 - if next_p[h-1] == 2: + if next_p[h - 1] == 2: m += 1 - next_p[h-1] = 1 + next_p[h - 1] = 1 h -= 1 else: - r = next_p[h-1] - 1 + r = next_p[h - 1] - 1 t = m - h + 1 - next_p[h-1] = r + next_p[h - 1] = r while t >= r: h += 1 - next_p[h-1] = r + next_p[h - 1] = r t -= r if t == 0: @@ -1165,7 +1162,7 @@ def __next__(self): m = h + 1 if t > 1: h += 1 - next_p[h-1] = t + next_p[h - 1] = t return self.parent()(next_p[:m]) @@ -1253,7 +1250,7 @@ def sign(self): - :wikipedia:`Zolotarev%27s_lemma` """ - return (-1)**(self.size() - self.length()) + return (-1) ** (self.size() - self.length()) def k_size(self, k): r""" @@ -1332,6 +1329,7 @@ def boundary(self): :meth:`k_rim`. You might have been looking for :meth:`k_boundary` instead. """ + def horizontal_piece(xy, bdy): start_x, start_y = xy if not bdy: @@ -1341,6 +1339,7 @@ def horizontal_piece(xy, bdy): y = start_y # y never changes h_piece = [(x, y) for x in range(start_x, stop_x)] return list(reversed(h_piece)) + bdy = [] for i, part in enumerate(self): cell_x, cell_y = (part - 1, i) @@ -1398,15 +1397,14 @@ def k_rim(self, k): interior_rim = self.k_interior(k).boundary() # get leftmost vertical line interior_top_left_y = interior_rim[-1][1] - v_piece = [(0, y) for y in range(interior_top_left_y+1, len(self)+1)] + v_piece = [(0, y) for y in range(interior_top_left_y + 1, len(self) + 1)] # get bottommost horizontal line interior_bottom_right_x = interior_rim[0][0] if self: ptn_bottom_right_x = self[0] else: ptn_bottom_right_x = 0 - h_piece = [(x, 0) for x in - range(ptn_bottom_right_x, interior_bottom_right_x, -1)] + h_piece = [(x, 0) for x in range(ptn_bottom_right_x, interior_bottom_right_x, -1)] # glue together with boundary rim = h_piece + interior_rim + v_piece return rim @@ -1552,8 +1550,7 @@ def has_k_rectangle(self, k) -> bool: :meth:`is_k_irreducible`, :meth:`is_k_reducible`, :meth:`has_rectangle` """ - return any(self.has_rectangle(k - i + 1, i) - for i in range(1, k + 1)) + return any(self.has_rectangle(k - i + 1, i) for i in range(1, k + 1)) def is_k_bounded(self, k) -> bool: r""" @@ -1726,7 +1723,7 @@ def condition(a, b): next_p[r] += 1 break return None - if (max is None or p[r] < max[r]) and condition(p[r], p[r-1]): + if (max is None or p[r] < max[r]) and condition(p[r], p[r - 1]): next_p[r] += 1 break next_p[r] = min[r] @@ -1776,7 +1773,7 @@ def up(self): previous = p.get_part(0) + 1 for i, current in enumerate(p): if current < previous: - yield Partition(p[:i] + [current + 1] + p[i + 1:]) + yield Partition(p[:i] + [current + 1] + p[i + 1 :]) previous = current yield Partition(p + [1]) @@ -1819,9 +1816,9 @@ def down(self): """ p = self l = len(p) - for i in range(l-1): - if p[i] > p[i+1]: - yield Partition(p[:i] + [p[i]-1] + p[i+1:]) + for i in range(l - 1): + if p[i] > p[i + 1]: + yield Partition(p[:i] + [p[i] - 1] + p[i + 1 :]) if l >= 1: last = p[-1] if last == 1: @@ -1986,6 +1983,7 @@ def cell_poset(self, orientation='SE'): False """ from sage.combinat.posets.posets import Poset + covers = {} if orientation == "NW": for i, row in enumerate(self): @@ -2062,7 +2060,7 @@ def frobenius_coordinates(self) -> tuple[list, list]: ([8], [6]) """ mu = self - muconj = mu.conjugate() # Naive implementation + muconj = mu.conjugate() # Naive implementation if len(mu) <= len(muconj): a = [x for i, val in enumerate(mu) if (x := val - i - 1) >= 0] b = [x for i in range(len(a)) if (x := muconj[i] - i - 1) >= 0] @@ -2209,7 +2207,7 @@ def crank(self): if self[-1] > 1: return self[0] ind_1 = self.index(1) - w = l - ind_1 # w is omega(self). + w = l - ind_1 # w is omega(self). m = len([x for x in self if x > w]) return m - w @@ -2347,7 +2345,7 @@ def generalized_pochhammer_symbol(self, a, alpha): """ res = 1 for i, j in self.cells(): - res *= (a - (i - 1) / alpha + j - 1) + res *= a - (i - 1) / alpha + j - 1 return res def get_part(self, i, default=Integer(0)): @@ -2419,6 +2417,7 @@ def to_dyck_word(self, n=None): True """ from sage.combinat.dyck_word import DyckWord + if not self._list: if n is None: return DyckWord([]) @@ -2529,10 +2528,10 @@ def glaisher_franklin(self, s): mu = [] for p, m in enumerate(self.to_exp(), 1): if not p % s: - mu.extend([p // s] * (m*s)) + mu.extend([p // s] * (m * s)) else: for i, v in enumerate(m.digits(s)): - mu.extend([p * s**i]*v) + mu.extend([p * s**i] * v) P = self.parent() return P.element_class(P, sorted(mu, reverse=True)) @@ -2705,7 +2704,7 @@ def suter_diagonal_slide(self, n, exp=1): leng = len(ret) if exp > 0: # Suter's map \sigma_n - if leng == 0: # Taking extra care about the empty partition. + if leng == 0: # Taking extra care about the empty partition. ret = Partition([1] * (n - 1)) exp -= 1 continue @@ -2715,7 +2714,7 @@ def suter_diagonal_slide(self, n, exp=1): exp -= 1 else: # exp < 0 since if exp == 0, we would exit the while loop # inverse map \sigma_n^{-1} - if leng == 0: # Taking extra care about the empty partition. + if leng == 0: # Taking extra care about the empty partition. ret = Partition([n - 1]) exp += 1 continue @@ -2763,8 +2762,7 @@ def initial_tableau(self): [[1, 2, 3], [4, 5], [6, 7]] """ sigma = list(accumulate([1] + self._list)) - tab = [list(range(sigma[i], sigma[i + 1])) - for i in range(len(sigma) - 1)] + tab = [list(range(sigma[i], sigma[i + 1])) for i in range(len(sigma) - 1)] return tableau.StandardTableau(tab) def initial_column_tableau(self): @@ -2844,12 +2842,12 @@ def garnir_tableau(self, *cell): except ValueError: row, col = cell[0] - if row + 1 >= len(self) or col >= self[row+1]: + if row + 1 >= len(self) or col >= self[row + 1]: raise ValueError('(row+1, col) must be inside the diagram') g = self.initial_tableau().to_list() a = g[row][col] - g[row][col:] = list(range(a+col+1, g[row+1][col]+1)) - g[row+1][:col+1] = list(range(a, a+col+1)) + g[row][col:] = list(range(a + col + 1, g[row + 1][col] + 1)) + g[row + 1][: col + 1] = list(range(a, a + col + 1)) g = tableau.Tableau(g) g._garnir_cell = (row, col) return g @@ -2913,25 +2911,25 @@ def top_garnir_tableau(self, e, cell): - [KMR2012]_ """ row, col = cell - if row+1 >= len(self) or col >= self[row+1]: + if row + 1 >= len(self) or col >= self[row + 1]: raise ValueError(f'({row+1},{col})=(row+1,col) must be inside the diagram') - g = self.garnir_tableau(cell) # start with the Garnir tableau and modify + g = self.garnir_tableau(cell) # start with the Garnir tableau and modify if e == 0: - return g # no more dominant tableau of the same residue + return g # no more dominant tableau of the same residue - a = e*int((self[row]-col)/e) # number of cells in the e-bricks in row `row` - b = e*int((col+1)/e) # number of cells in the e-bricks in row `row+1` + a = e * int((self[row] - col) / e) # number of cells in the e-bricks in row `row` + b = e * int((col + 1) / e) # number of cells in the e-bricks in row `row+1` if a == 0 or b == 0: return g t = g.to_list() - m = g[row+1][0] # smallest number in 0-Garnir belt + m = g[row + 1][0] # smallest number in 0-Garnir belt # now we will put the number m,m+1,...,t[row+1][col] in order into t - t[row][col:a+col] = [m+col-b+1+i for i in range(a)] - t[row+1][col-b+1:col+1] = [m+a+col-b+1+i for i in range(b)] + t[row][col : a + col] = [m + col - b + 1 + i for i in range(a)] + t[row + 1][col - b + 1 : col + 1] = [m + a + col - b + 1 + i for i in range(b)] return tableau.StandardTableau(t) def ladder_tableau(self, e, ladder_lengths=False): @@ -3233,7 +3231,7 @@ def arm_length(self, i, j): """ p = self if i < len(p) and j < p[i]: - return p[i]-(j+1) + return p[i] - (j + 1) raise ValueError("the cell is not in the diagram") def arm_lengths(self, flat=False): @@ -3346,10 +3344,8 @@ def leg_lengths(self, flat=False): p = self conj = p.conjugate() if not flat: - return [[conj[j] - (i + 1) for j in range(pi)] - for i, pi in enumerate(p)] - return [conj[j] - (i + 1) for i, pi in enumerate(p) - for j in range(pi)] + return [[conj[j] - (i + 1) for j in range(pi)] for i, pi in enumerate(p)] + return [conj[j] - (i + 1) for i, pi in enumerate(p) for j in range(pi)] def leg_cells(self, i, j): r""" @@ -3418,14 +3414,12 @@ def attacking_pairs(self): for j in range(r): # c is in position (i,j) # Find the d that satisfy condition 1 - attacking_pairs.extend(((i, j), (i, k)) - for k in range(j + 1, r)) + attacking_pairs.extend(((i, j), (i, k)) for k in range(j + 1, r)) # Find the d that satisfy condition 2 if i == 0: continue - attacking_pairs.extend(((i, j), (i - 1, k)) - for k in range(j)) + attacking_pairs.extend(((i, j), (i - 1, k)) for k in range(j)) return attacking_pairs @@ -3482,7 +3476,7 @@ def hook_product(self, a): res = 1 for i in range(len(self)): for j in range(self[i]): - res *= a*(self[i]-j-1)+nu[j]-i + res *= a * (self[i] - j - 1) + nu[j] - i return res def hook_polynomial(self, q, t): @@ -3503,7 +3497,7 @@ def hook_polynomial(self, q, t): res = 1 for i in range(len(self)): for j in range(self[i]): - res *= 1-q**(self[i]-j-1)*t**(nu[j]-i) + res *= 1 - q ** (self[i] - j - 1) * t ** (nu[j] - i) return res def hook_length(self, i, j): @@ -3594,7 +3588,7 @@ def hook_lengths(self): """ p = self conj = p.conjugate() - return [[p[i]-(i+1)+conj[j]-(j+1)+1 for j in range(p[i])] for i in range(len(p))] + return [[p[i] - (i + 1) + conj[j] - (j + 1) + 1 for j in range(p[i])] for i in range(len(p))] def upper_hook(self, i, j, alpha): r""" @@ -3620,7 +3614,7 @@ def upper_hook(self, i, j, alpha): """ p = self conj = self.conjugate() - return conj[j] - (i+1) + alpha*(p[i]-j) + return conj[j] - (i + 1) + alpha * (p[i] - j) def upper_hook_lengths(self, alpha): r""" @@ -3646,7 +3640,7 @@ def upper_hook_lengths(self, alpha): """ p = self conj = p.conjugate() - return [[conj[j] - (i+1) + alpha*(p[i]-j) for j in range(p[i])] for i in range(len(p))] + return [[conj[j] - (i + 1) + alpha * (p[i] - j) for j in range(p[i])] for i in range(len(p))] def lower_hook(self, i, j, alpha): r""" @@ -3672,7 +3666,7 @@ def lower_hook(self, i, j, alpha): """ p = self conj = self.conjugate() - return conj[j] - i + alpha*(p[i] - (j+1)) + return conj[j] - i + alpha * (p[i] - (j + 1)) def lower_hook_lengths(self, alpha): r""" @@ -3698,8 +3692,7 @@ def lower_hook_lengths(self, alpha): """ p = self conj = p.conjugate() - return [[conj[j] - i + alpha*(p[i] - (j + 1)) for j in range(p[i])] - for i in range(len(p))] + return [[conj[j] - i + alpha * (p[i] - (j + 1)) for j in range(p[i])] for i in range(len(p))] def weighted_size(self): r""" @@ -3733,7 +3726,7 @@ def weighted_size(self): 0 """ p = self - return sum([i*p[i] for i in range(len(p))]) + return sum([i * p[i] for i in range(len(p))]) def is_empty(self): """ @@ -3786,7 +3779,7 @@ def to_exp(self, k=0): k = max(k, p[0]) a = [ZZ.zero()] * k for i in p: - a[i-1] += 1 + a[i - 1] += 1 return a def evaluation(self): @@ -3869,11 +3862,9 @@ def centralizer_size(self, t=0, q=0): sage: Partition([2,2,2]).aut() 48 """ - size = prod(i**mi * factorial(mi) - for i, mi in self.to_exp_dict().items()) + size = prod(i**mi * factorial(mi) for i, mi in self.to_exp_dict().items()) if t or q: - size *= prod((ZZ.one() - q ** j) / (ZZ.one() - t ** j) - for j in self) + size *= prod((ZZ.one() - q**j) / (ZZ.one() - t**j) for j in self) return size aut = centralizer_size @@ -4044,8 +4035,7 @@ def defect(self, e, multicharge=(0,)): """ beta = self.block(e, multicharge) Ie = IntegerModRing(e) - return beta.get(multicharge[0], 0) - sum(beta[r]**2 - beta[r] * beta.get(Ie(r+1), 0) - for r in beta) + return beta.get(multicharge[0], 0) - sum(beta[r] ** 2 - beta[r] * beta.get(Ie(r + 1), 0) for r in beta) def contents_tableau(self, multicharge=(0,)): """ @@ -4067,8 +4057,7 @@ def contents_tableau(self, multicharge=(0,)): 1 0 """ - return tableau.Tableau([[multicharge[0]-r+c for c in range(self[r])] - for r in range(len(self))]) + return tableau.Tableau([[multicharge[0] - r + c for c in range(self[r])] for r in range(len(self))]) def is_restricted(self, e, multicharge=(0,)): """ @@ -4091,8 +4080,7 @@ def is_restricted(self, e, multicharge=(0,)): sage: Partition([4]).is_restricted(4) False """ - return (not self - or (self[-1] < e and all(self[r] - self[r+1] < e for r in range(len(self) - 1)))) + return not self or (self[-1] < e and all(self[r] - self[r + 1] < e for r in range(len(self) - 1))) def is_regular(self, e, multicharge=(0,)) -> bool: """ @@ -4110,7 +4098,7 @@ def is_regular(self, e, multicharge=(0,)) -> bool: sage: Partition([4,3,3,3]).is_regular(4) True """ - return all(self[r] > self[r+e-1] for r in range(len(self)-e+1)) + return all(self[r] > self[r + e - 1] for r in range(len(self) - e + 1)) def conjugacy_class_size(self): """ @@ -4157,23 +4145,23 @@ def corners(self) -> list: if p.is_empty(): return [] - lcors = [[0, p[0]-1]] + lcors = [[0, p[0] - 1]] nn = len(p) if nn == 1: return [tuple(c) for c in lcors] lcors_index = 0 for i in range(1, nn): - if p[i] == p[i-1]: + if p[i] == p[i - 1]: lcors[lcors_index][0] += 1 else: - lcors.append([i, p[i]-1]) + lcors.append([i, p[i] - 1]) lcors_index += 1 return [tuple(c) for c in lcors] inside_corners = corners - removable_cells = corners # for compatibility with partition tuples + removable_cells = corners # for compatibility with partition tuples def corners_residue(self, i, l): r""" @@ -4239,7 +4227,7 @@ def outside_corners(self): res.append((len(p), 0)) return res - addable_cells = outside_corners # for compatibility with partition tuples + addable_cells = outside_corners # for compatibility with partition tuples def outside_corners_residue(self, i, l): r""" @@ -4392,8 +4380,7 @@ def zero_one_sequence(self): True """ tmp = {si - i for i, si in enumerate(self)} - return [Integer(i not in tmp) - for i in range(-len(self) + 1, self.get_part(0) + 1)] + return [Integer(i not in tmp) for i in range(-len(self) + 1, self.get_part(0) + 1)] def core(self, length): r""" @@ -4427,22 +4414,22 @@ def core(self, length): p = self # Normalize the length remainder = len(p) % length - part = p[:] + [0]*remainder + part = p[:] + [0] * remainder # Add the canonical vector to the partition - part = [part[i-1] + len(part)-i for i in range(1, len(part)+1)] + part = [part[i - 1] + len(part) - i for i in range(1, len(part) + 1)] for e in range(length): k = e - for i in reversed(range(1, len(part)+1)): - if part[i-1] % length == e: - part[i-1] = k + for i in reversed(range(1, len(part) + 1)): + if part[i - 1] % length == e: + part[i - 1] = k k += length part.sort() part.reverse() # Remove the canonical vector - part = [part[i-1]-len(part)+i for i in range(1, len(part)+1)] + part = [part[i - 1] - len(part) + i for i in range(1, len(part) + 1)] # Select the r-core return Partition([x for x in part if x != 0]) @@ -4493,11 +4480,11 @@ def quotient(self, length): p = self # Normalize the length remainder = len(p) % length - part = p[:] + [0]*(length-remainder) + part = p[:] + [0] * (length - remainder) # Add the canonical vector to the partition - part = [part[i-1] + len(part)-i for i in range(1, len(part)+1)] - result = [None]*length + part = [part[i - 1] + len(part) - i for i in range(1, len(part) + 1)] + result = [None] * length # Reducing vector for e in range(length): @@ -4505,7 +4492,7 @@ def quotient(self, length): tmp = [] for i in reversed(range(len(part))): if part[i] % length == e: - tmp.append(ZZ((part[i]-k)//length)) + tmp.append(ZZ((part[i] - k) // length)) k += length a = [i for i in tmp if i != 0] @@ -4513,6 +4500,7 @@ def quotient(self, length): result[e] = a from .partition_tuple import PartitionTuple + return PartitionTuple(result) # tuple(map(Partition, result)) def is_core(self, k): @@ -4571,8 +4559,7 @@ def k_interior(self, k): sage: p.k_interior(3) [] """ - return Partition([len([i for i in row if i > k]) - for row in self.hook_lengths()]) + return Partition([len([i for i in row if i > k]) for row in self.hook_lengths()]) def k_boundary(self, k): r""" @@ -4653,7 +4640,7 @@ def remove_cell(self, i, j=None): if self[i] == 1: return Partition(self[:-1]) - return Partition(self[:i] + [self[i:i+1][0] - 1] + self[i+1:]) + return Partition(self[:i] + [self[i : i + 1][0] - 1] + self[i + 1 :]) def k_irreducible(self, k): r""" @@ -4681,7 +4668,7 @@ def k_irreducible(self, k): [2, 1] """ pexp = self.to_exp() - return Partition(sum(([r+1] for r in range(len(pexp)-1, -1, -1) for m in range(pexp[r] % (k-r))), [])) + return Partition(sum(([r + 1] for r in range(len(pexp) - 1, -1, -1) for m in range(pexp[r] % (k - r))), [])) def k_skew(self, k): r""" @@ -4761,7 +4748,8 @@ def to_core(self, k): True """ from sage.combinat.core import Core - return Core(self.k_skew(k)[0], k+1) + + return Core(self.k_skew(k)[0], k + 1) def from_kbounded_to_reduced_word(self, k): r""" @@ -4792,9 +4780,9 @@ def from_kbounded_to_reduced_word(self, k): result = [] while not p.is_empty(): corners = p.corners() - c = p.content(corners[0][0], corners[0][1]) % (k+1) + c = p.content(corners[0][0], corners[0][1]) % (k + 1) result.append(Integer(c)) - list = [x for x in corners if p.content(x[0], x[1]) % (k+1) == c] + list = [x for x in corners if p.content(x[0], x[1]) % (k + 1) == c] for x in list: p = p.remove_cell(x[0]) return result @@ -4869,10 +4857,10 @@ def add_vertical_border_strip(self, k): ell = len(self._list) while i < ell: tmp = 1 - while i+1 < ell and self._list[i] == self._list[i+1]: + while i + 1 < ell and self._list[i] == self._list[i + 1]: tmp += 1 i += 1 - if i == ell-1 and i > 0 and self._list[i] != self._list[i-1]: + if i == ell - 1 and i > 0 and self._list[i] != self._list[i - 1]: tmp = 1 shelf.append(tmp) i += 1 @@ -4884,13 +4872,13 @@ def add_vertical_border_strip(self, k): # list all of the positions for cells # filling each self from the left to the right for iv in IntegerListsBackend_invlex(k, length=len(shelf), ceiling=shelf, check=False)._iter(): - tmp = self._list + [0]*k + tmp = self._list + [0] * k j = 0 for t in range(len(iv)): for _ in range(iv[t]): tmp[j] += 1 j += 1 - j = sum(shelf[:t+1]) + j = sum(shelf[: t + 1]) # This should never return the empty partition. # So tmp should never be [0, ..., 0]. while not tmp[-1]: @@ -4923,11 +4911,11 @@ def add_horizontal_border_strip(self, k): res = [] mapping = [0] shelf = [k] - for i in range(len(L)-1): - val = L[i] - L[i+1] + for i in range(len(L) - 1): + val = L[i] - L[i + 1] if not val: continue - mapping.append(i+1) + mapping.append(i + 1) shelf.append(val) # add the last shelf @@ -4981,10 +4969,10 @@ def vertical_border_strip_cells(self, k): ell = len(self._list) while i < ell: tmp = 1 - while i+1 < ell and self._list[i] == self._list[i+1]: + while i + 1 < ell and self._list[i] == self._list[i + 1]: tmp += 1 i += 1 - if i == ell-1 and i > 0 and self._list[i] != self._list[i-1]: + if i == ell - 1 and i > 0 and self._list[i] != self._list[i - 1]: tmp = 1 shelf.append(tmp) i += 1 @@ -4993,17 +4981,15 @@ def vertical_border_strip_cells(self, k): # the first line shelf.append(k) # list all of the positions for cells - tmp = self._list + [0]*k - for iv in IntegerListsBackend_invlex(k, length=len(shelf), - ceiling=shelf, - check=False)._iter(): + tmp = self._list + [0] * k + for iv in IntegerListsBackend_invlex(k, length=len(shelf), ceiling=shelf, check=False)._iter(): j = 0 current_strip = [] for t in range(len(iv)): for _ in range(iv[t]): current_strip.append((j, tmp[j])) j += 1 - j = sum(shelf[:t+1]) + j = sum(shelf[: t + 1]) yield current_strip def horizontal_border_strip_cells(self, k): @@ -5035,11 +5021,11 @@ def horizontal_border_strip_cells(self, k): L = self._list shelf = [k] # the number of boxes which will fit in a row mapping = [0] # a record of the rows - for i in range(len(L)-1): - val = L[i] - L[i+1] + for i in range(len(L) - 1): + val = L[i] - L[i + 1] if not val: continue - mapping.append(i+1) + mapping.append(i + 1) shelf.append(val) # add the last shelf @@ -5096,13 +5082,7 @@ def remove_horizontal_border_strip(self, k): sage: Partition([]).remove_horizontal_border_strip(6).list() [] """ - return Partitions_with_constraints(n=self.size() - k, - min_length=len(self) - 1, - max_length=len(self), - floor=self[1:] + [0], - ceiling=self[:], - max_slope=0, - name=f"The subpartitions of {self} obtained by removing a horizontal border strip of length {k}") + return Partitions_with_constraints(n=self.size() - k, min_length=len(self) - 1, max_length=len(self), floor=self[1:] + [0], ceiling=self[:], max_slope=0, name=f"The subpartitions of {self} obtained by removing a horizontal border strip of length {k}") def k_conjugate(self, k): r""" @@ -5154,8 +5134,8 @@ def arms_legs_coeff(self, i, j): QQqt = PolynomialRing(QQ, ['q', 't']) q, t = QQqt.gens() if i < len(self) and j < self[i]: - res = 1 - q**self.arm_length(i, j) * t**(self.leg_length(i, j)+1) - res /= 1 - q**(self.arm_length(i, j)+1) * t**self.leg_length(i, j) + res = 1 - q ** self.arm_length(i, j) * t ** (self.leg_length(i, j) + 1) + res /= 1 - q ** (self.arm_length(i, j) + 1) * t ** self.leg_length(i, j) return res return ZZ.one() @@ -5171,8 +5151,7 @@ def atom(self): sage: Partition([3,2,1]).atom() [[[1, 2, 3, 6], [4, 5]], [[1, 2, 3], [4, 5], [6]]] """ - return [tab for tab in tableau.StandardTableaux_size(self.size()) - if tab.atom() == self] + return [tab for tab in tableau.StandardTableaux_size(self.size()) if tab.atom() == self] def k_atom(self, k): r""" @@ -5205,8 +5184,7 @@ def k_atom(self, k): for i in range(len(self)): res = (x.promotion_operator(self[-i - 1]) for x in res) res = sum(res, []) - res = (y.catabolism_projector(Partition(self[-i - 1:]).k_split(k)) - for y in res) + res = (y.catabolism_projector(Partition(self[-i - 1 :]).k_split(k)) for y in res) res = [i for i in res if i] return res @@ -5237,8 +5215,8 @@ def k_split(self, k): part = list(self) while part and part[0] + len(part) - 1 >= k: p = k - part[0] - res.append(part[:p + 1]) - part = part[p + 1:] + res.append(part[: p + 1]) + part = part[p + 1 :] if part: res.append(part) return res @@ -5306,6 +5284,7 @@ def character_polynomial(self): # Expand s_mu in the power sum basis from sage.combinat.sf.sf import SymmetricFunctions + Sym = SymmetricFunctions(QQ) s = Sym.schur() p = Sym.power() @@ -5315,7 +5294,7 @@ def character_polynomial(self): items = ps_mu.monomial_coefficients().items() # items contains a list of (partition, coeff) pairs def partition_to_monomial(part): - return prod([i*x[i-1] - 1 for i in part]) + return prod([i * x[i - 1] - 1 for i in part]) res = [[partition_to_monomial(mc[0]), mc[1]] for mc in items] @@ -5325,6 +5304,7 @@ def partition_to_monomial(part): # Apply the umbral operator and return the result from sage.combinat.misc import umbral_operation + return umbral_operation(res) def dimension(self, smaller=None, k=1): @@ -5416,9 +5396,9 @@ def dimension(self, smaller=None, k=1): if smaller is None: smaller = Partition([]) if k == 1: - if smaller == Partition([]): # In this case, use the hook dimension formula + if smaller == Partition([]): # In this case, use the hook dimension formula return factorial(larger.size()) / prod(larger.hooks()) - if not larger.contains(smaller): # easy case + if not larger.contains(smaller): # easy case return 0 # relative dimension @@ -5430,8 +5410,8 @@ def inv_factorial(i): len_range = range(larger.length()) from sage.matrix.constructor import matrix - M = matrix(QQ, [[inv_factorial(larger.get_part(i) - smaller.get_part(j) - i + j) - for i in len_range] for j in len_range]) + + M = matrix(QQ, [[inv_factorial(larger.get_part(i) - smaller.get_part(j) - i + j) for i in len_range] for j in len_range]) return factorial(larger.size() - smaller.size()) * M.determinant() larger_core = larger.core(k) @@ -5481,7 +5461,7 @@ def plancherel_measure(self): sage: all(sum(mu.plancherel_measure() for mu in Partitions(n))==1 for n in range(10)) True """ - return self.dimension()**2 / factorial(self.size()) + return self.dimension() ** 2 / factorial(self.size()) def outline(self, variable=None): r""" @@ -5517,8 +5497,7 @@ def outline(self, variable=None): variable = var('x') outside_contents = [self.content(*c) for c in self.outside_corners()] inside_contents = [self.content(*c) for c in self.corners()] - return sum(abs(variable+c) for c in outside_contents)\ - - sum(abs(variable+c) for c in inside_contents) + return sum(abs(variable + c) for c in outside_contents) - sum(abs(variable + c) for c in inside_contents) def dual_equivalence_graph(self, directed=False, coloring=None): r""" @@ -5619,25 +5598,24 @@ def dual_equivalence_graph(self, directed=False, coloring=None): try: from sage.graphs.dot2tex_utils import have_dot2tex + have = have_dot2tex() except ImportError: have = False if have: if coloring is None: - d = {2: 'red', 3: 'blue', 4: 'green', 5: 'purple', - 6: 'brown', 7: 'orange', 8: 'yellow'} + d = {2: 'red', 3: 'blue', 4: 'green', 5: 'purple', 6: 'brown', 7: 'orange', 8: 'yellow'} def coloring(i): if i in d: return d[i] return 'black' + elif isinstance(coloring, dict): d = coloring coloring = lambda x: d[x] - G.set_latex_options(format='dot2tex', - edge_labels=True, - color_by_label=coloring) + G.set_latex_options(format='dot2tex', edge_labels=True, color_by_label=coloring) return G except AttributeError: pass @@ -5652,8 +5630,8 @@ def coloring(i): pt = list(to_perms[t]) for i in range(2, n): ii = pt.index(i) - iip = pt.index(i+1) - iim = pt.index(i-1) + iip = pt.index(i + 1) + iim = pt.index(i - 1) l = sorted([iim, ii, iip]) if l[0] != ii: continue @@ -5668,12 +5646,12 @@ def coloring(i): if directed: from sage.graphs.digraph import DiGraph - self._DDEG = DiGraph([T, edges], format='vertices_and_edges', - immutable=True, multiedges=True) + + self._DDEG = DiGraph([T, edges], format='vertices_and_edges', immutable=True, multiedges=True) else: from sage.graphs.graph import Graph - self._DEG = Graph([T, edges], format='vertices_and_edges', - immutable=True, multiedges=True) + + self._DEG = Graph([T, edges], format='vertices_and_edges', immutable=True, multiedges=True) return self.dual_equivalence_graph(directed, coloring) def specht_module(self, base_ring=None): @@ -5689,8 +5667,10 @@ def specht_module(self, base_ring=None): """ from sage.combinat.specht_module import SpechtModule from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra + if base_ring is None: from sage.rings.rational_field import QQ + base_ring = QQ R = SymmetricGroupAlgebra(base_ring, sum(self)) return SpechtModule(R, self) @@ -5718,8 +5698,10 @@ def garsia_procesi_module(self, base_ring=None): """ from sage.combinat.symmetric_group_representations import GarsiaProcesiModule from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra + if base_ring is None: from sage.rings.rational_field import QQ + base_ring = QQ R = SymmetricGroupAlgebra(base_ring, sum(self)) return GarsiaProcesiModule(R, self) @@ -5743,10 +5725,13 @@ def specht_module_dimension(self, base_ring=None): 5 """ from sage.categories.fields import Fields + if base_ring is None or (base_ring in Fields() and base_ring.characteristic() == 0): from sage.combinat.tableau import StandardTableaux + return StandardTableaux(self).cardinality() from sage.combinat.specht_module import specht_module_rank + return specht_module_rank(self, base_ring) def simple_module_dimension(self, base_ring=None): @@ -5780,10 +5765,13 @@ def simple_module_dimension(self, base_ring=None): [2, 2, 1, 1] 9 9 """ from sage.categories.fields import Fields + if base_ring is None or (base_ring in Fields() and base_ring.characteristic() == 0): from sage.combinat.tableau import StandardTableaux + return StandardTableaux(self).cardinality() from sage.combinat.specht_module import simple_module_rank + return simple_module_rank(self, base_ring) def tabloid_module(self, base_ring=None): @@ -5799,8 +5787,10 @@ def tabloid_module(self, base_ring=None): """ from sage.combinat.specht_module import TabloidModule from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra + if base_ring is None: from sage.rings.rational_field import QQ + base_ring = QQ R = SymmetricGroupAlgebra(base_ring, sum(self)) return TabloidModule(R, self) @@ -5810,6 +5800,7 @@ def tabloid_module(self, base_ring=None): # Partitions # ############## + class Partitions(UniqueRepresentation, Parent): r""" ``Partitions(n, **kwargs)`` returns the combinatorial class of @@ -6133,6 +6124,7 @@ class Partitions(UniqueRepresentation, Parent): sage: Partitions(40, max_length=10).cardinality() 16928 """ + @staticmethod def __classcall_private__(cls, n=None, **kwargs): """ @@ -6170,16 +6162,14 @@ def __classcall_private__(cls, n=None, **kwargs): # preprocess for UniqueRepresentation if 'outer' in kwargs and not isinstance(kwargs['outer'], Partition): m = infinity - kwargs['outer'] = [m for e in kwargs['outer'] - if (m := min(m, e if e is infinity else ZZ(e))) > 0] + kwargs['outer'] = [m for e in kwargs['outer'] if (m := min(m, e if e is infinity else ZZ(e))) > 0] if kwargs['outer'] and kwargs['outer'][0] is infinity: kwargs['outer'] = tuple(kwargs['outer']) else: kwargs['outer'] = Partition(kwargs['outer']) if 'inner' in kwargs and not isinstance(kwargs['inner'], Partition): m = ZZ.zero() - kwargs['inner'] = Partition(reversed([(m := max(m, e)) - for e in reversed(kwargs['inner'])])) + kwargs['inner'] = Partition(reversed([(m := max(m, e)) for e in reversed(kwargs['inner'])])) if isinstance(n, (int, Integer)): if not kwargs: @@ -6216,17 +6206,10 @@ def __classcall_private__(cls, n=None, **kwargs): return RestrictedPartitions_n(n, kwargs['restricted']) else: - if ('parts_in' in kwargs or - 'starting' in kwargs or - 'ending' in kwargs or - 'regular' in kwargs or - 'restricted' in kwargs): - raise ValueError("the parameters 'parts_in', 'starting', " - + "'ending', 'regular' and 'restricted' " - + "cannot be combined with anything else") - - if set(kwargs).issubset(['length', 'min_part', 'max_part', - 'min_length', 'max_length']): + if 'parts_in' in kwargs or 'starting' in kwargs or 'ending' in kwargs or 'regular' in kwargs or 'restricted' in kwargs: + raise ValueError("the parameters 'parts_in', 'starting', " + "'ending', 'regular' and 'restricted' " + "cannot be combined with anything else") + + if set(kwargs).issubset(['length', 'min_part', 'max_part', 'min_length', 'max_length']): if 'length' in kwargs: min_length = max_length = kwargs['length'] if not n: @@ -6268,14 +6251,12 @@ def __classcall_private__(cls, n=None, **kwargs): if 'outer' in kwargs: kwargs['ceiling'] = tuple(kwargs['outer']) - kwargs['max_length'] = min(len(kwargs['outer']), - kwargs.get('max_length', infinity)) + kwargs['max_length'] = min(len(kwargs['outer']), kwargs.get('max_length', infinity)) del kwargs['outer'] if 'inner' in kwargs: kwargs['floor'] = tuple(kwargs['inner']) - kwargs['min_length'] = max(len(kwargs['inner']), - kwargs.get('min_length', 0)) + kwargs['min_length'] = max(len(kwargs['inner']), kwargs.get('min_length', 0)) del kwargs['inner'] return Partitions_with_constraints(n, **kwargs) @@ -6306,8 +6287,7 @@ def __classcall_private__(cls, n=None, **kwargs): # so we use a class inheriting from Partitions return Partitions_all_constrained(**kwargs) - raise ValueError("n must be an integer or be equal to one of " - "None, NN, NonNegativeIntegers()") + raise ValueError("n must be an integer or be equal to one of " "None, NN, NonNegativeIntegers()") def __init__(self, is_infinite=False): """ @@ -6395,34 +6375,13 @@ class options(GlobalOptions): 4 5 sage: Partitions.options._reset() """ + NAME = 'Partitions' module = 'sage.combinat.partition' - display = {'default': "list", - 'description': 'Specifies how partitions should be printed', - 'values': {'list': 'displayed as a list', - 'exp_low': 'in exponential form (lowest first)', - 'exp_high': 'in exponential form (highest first)', - 'diagram': 'as a Ferrers diagram', - 'compact_low': 'compact form of ``exp_low``', - 'compact_high': 'compact form of ``exp_high``'}, - 'alias': {'exp': "exp_low", 'compact': "compact_low", 'array': "diagram", - 'ferrers_diagram': "diagram", 'young_diagram': "diagram"}, - 'case_sensitive': False} - latex = {'default': "young_diagram", - 'description': 'Specifies how partitions should be latexed', - 'values': {'diagram': 'latex as a Ferrers diagram', - 'young_diagram': 'latex as a Young diagram', - 'list': 'latex as a list', - 'exp_high': 'latex as a list in exponential notation (highest first)', - 'exp_low': 'as a list latex in exponential notation (lowest first)'}, - 'alias': {'exp': "exp_low", 'array': "diagram", 'ferrers_diagram': "diagram"}, - 'case_sensitive': False} - diagram_str = {'default': "*", - 'description': 'The character used for the cells when printing Ferrers diagrams', - 'checker': lambda char: isinstance(char, str)} - latex_diagram_str = {'default': "\\ast", - 'description': 'The character used for the cells when latexing Ferrers diagrams', - 'checker': lambda char: isinstance(char, str)} + display = {'default': "list", 'description': 'Specifies how partitions should be printed', 'values': {'list': 'displayed as a list', 'exp_low': 'in exponential form (lowest first)', 'exp_high': 'in exponential form (highest first)', 'diagram': 'as a Ferrers diagram', 'compact_low': 'compact form of ``exp_low``', 'compact_high': 'compact form of ``exp_high``'}, 'alias': {'exp': "exp_low", 'compact': "compact_low", 'array': "diagram", 'ferrers_diagram': "diagram", 'young_diagram': "diagram"}, 'case_sensitive': False} + latex = {'default': "young_diagram", 'description': 'Specifies how partitions should be latexed', 'values': {'diagram': 'latex as a Ferrers diagram', 'young_diagram': 'latex as a Young diagram', 'list': 'latex as a list', 'exp_high': 'latex as a list in exponential notation (highest first)', 'exp_low': 'as a list latex in exponential notation (lowest first)'}, 'alias': {'exp': "exp_low", 'array': "diagram", 'ferrers_diagram': "diagram"}, 'case_sensitive': False} + diagram_str = {'default': "*", 'description': 'The character used for the cells when printing Ferrers diagrams', 'checker': lambda char: isinstance(char, str)} + latex_diagram_str = {'default': "\\ast", 'description': 'The character used for the cells when latexing Ferrers diagrams', 'checker': lambda char: isinstance(char, str)} convention = {'link_to': (tableau.Tableaux.options, 'convention')} notation = {'alt_name': 'convention'} @@ -6525,8 +6484,7 @@ def __contains__(self, x): if isinstance(x, Partition): return True if isinstance(x, (list, tuple)): - return not x or (all((a in ZZ) and (a >= b) for a, b in zip(x, x[1:])) - and (x[-1] in ZZ) and (x[-1] >= 0)) + return not x or (all((a in ZZ) and (a >= b) for a, b in zip(x, x[1:])) and (x[-1] in ZZ) and (x[-1] >= 0)) return False def subset(self, *args, **kwargs): @@ -6664,17 +6622,17 @@ def from_frobenius_coordinates(self, frobenius_coordinates): r = len(a) if r == 0: return self.element_class(self, []) - tmp = [a[i]+i+1 for i in range(r)] + tmp = [a[i] + i + 1 for i in range(r)] # should check that a is strictly decreasing if a[-1] < 0: raise ValueError('%s is not a partition, no coordinate can be negative' % str(frobenius_coordinates)) if b[-1] >= 0: - tmp.extend([r]*b[r-1]) + tmp.extend([r] * b[r - 1]) else: raise ValueError('%s is not a partition, no coordinate can be negative' % str(frobenius_coordinates)) for i in range(r - 1, 0, -1): - if b[i-1]-b[i] > 0: - tmp.extend([i]*(b[i-1]-b[i]-1)) + if b[i - 1] - b[i] > 0: + tmp.extend([i] * (b[i - 1] - b[i] - 1)) else: raise ValueError('%s is not a partition, the coordinates need to be strictly decreasing' % str(frobenius_coordinates)) return self.element_class(self, tmp) @@ -6700,10 +6658,10 @@ def from_beta_numbers(self, beta): """ beta.sort() # put them into increasing order just in case offset = 0 - while offset < len(beta)-1 and beta[offset] == offset: + while offset < len(beta) - 1 and beta[offset] == offset: offset += 1 beta = beta[offset:] - mu = [beta[i]-offset-i for i in range(len(beta))] + mu = [beta[i] - offset - i for i in range(len(beta))] return self.element_class(self, list(reversed(mu))) def from_exp(self, exp): @@ -6717,7 +6675,7 @@ def from_exp(self, exp): """ p = [] for i in reversed(range(len(exp))): - p += [i+1]*exp[i] + p += [i + 1] * exp[i] return self.element_class(self, p) def from_zero_one(self, seq): @@ -6762,7 +6720,7 @@ def from_zero_one(self, seq): True """ tmp = [i for i in range(len(seq)) if seq[i] == 0] - return self.element_class(self, [tmp[i]-i for i in range(len(tmp)-1, -1, -1)]) + return self.element_class(self, [tmp[i] - i for i in range(len(tmp) - 1, -1, -1)]) def from_core_and_quotient(self, core, quotient): """ @@ -6803,23 +6761,24 @@ def from_core_and_quotient(self, core, quotient): True """ from .partition_tuple import PartitionTuple, PartitionTuples + if quotient not in PartitionTuples(): raise ValueError('the quotient %s must be a tuple of partitions' % quotient) components = PartitionTuple(quotient).components() length = len(components) - k = length*max(len(q) for q in components) + len(core) + k = length * max(len(q) for q in components) + len(core) # k needs to be large enough. this seems to me like the smallest it can be - v = [core[i]-i for i in range(len(core))] + [-i for i in range(len(core), k)] - w = [[x for x in v if (x-i) % length == 0] for i in range(1, length+1)] + v = [core[i] - i for i in range(len(core))] + [-i for i in range(len(core), k)] + w = [[x for x in v if (x - i) % length == 0] for i in range(1, length + 1)] new_w = [] for i in range(length): lw = len(w[i]) lq = len(components[i]) # k needs to be chosen so lw >= lq - new_w += [w[i][j] + length*components[i][j] for j in range(lq)] + new_w += [w[i][j] + length * components[i][j] for j in range(lq)] new_w += [w[i][j] for j in range(lq, lw)] new_w.sort(reverse=True) - return self.element_class(self, [new_w[i]+i for i in range(len(new_w))]) + return self.element_class(self, [new_w[i] + i for i in range(len(new_w))]) class Partitions_all_constrained(Partitions): @@ -6893,8 +6852,7 @@ def _repr_(self): sage: Partitions(max_part=3, max_length=4, min_length=2) Partitions satisfying constraints max_length=4, max_part=3, min_length=2 """ - return "Partitions satisfying constraints " + ", ".join(["{}={}".format(key, value) - for key, value in sorted(self._constraints.items())]) + return "Partitions satisfying constraints " + ", ".join(["{}={}".format(key, value) for key, value in sorted(self._constraints.items())]) def __iter__(self): """ @@ -6922,6 +6880,7 @@ class Partitions_all_bounded(Partitions): """ Partitions whose parts do not exceed a given bound. """ + def __init__(self, k): """ TESTS:: @@ -7148,6 +7107,7 @@ def cardinality(self, algorithm='flint'): if algorithm == 'gap': from sage.libs.gap.libgap import libgap + return ZZ(libgap.NrPartitions(ZZ(self.n))) if algorithm == 'pari': @@ -7231,13 +7191,13 @@ def random_element_uniform(self): # equiprobable. # The following could be made faster by a clever use of floats - rand = randrange(0, n*cached_number_of_partitions(n)) # cached number_of_partition + rand = randrange(0, n * cached_number_of_partitions(n)) # cached number_of_partition # It is better to start by the j = 1 pairs because they are the # most probable. Maybe there is an even more clever order. - for j in range(1, n+1): + for j in range(1, n + 1): d = 1 - r = n-j # n - d*j + r = n - j # n - d*j while r >= 0: rand -= d * cached_number_of_partitions(r) if rand < 0: @@ -7247,7 +7207,7 @@ def random_element_uniform(self): else: continue break - res.extend([d]*j) + res.extend([d] * j) n = r res.sort(reverse=True) return self.element_class(self, res) @@ -7354,7 +7314,7 @@ def last(self): sage: Partitions(4).last() [1, 1, 1, 1] """ - return self.element_class(self, [1]*self.n) + return self.element_class(self, [1] * self.n) def __iter__(self): """ @@ -7482,11 +7442,13 @@ def _an_element_(self): lst = [] else: from sage.categories.sets_cat import EmptySetError + raise EmptySetError elif self.n >= self.k > 0: - lst = [self.n - self.k + 1] + [1] * (self.k-1) + lst = [self.n - self.k + 1] + [1] * (self.k - 1) else: from sage.categories.sets_cat import EmptySetError + raise EmptySetError return self.element_class(self, lst) @@ -7739,6 +7701,7 @@ def cardinality(self): # GAP complains if you give it an empty list if self.parts: from sage.libs.gap.libgap import libgap + return ZZ(libgap.NrRestrictedPartitions(ZZ(self.n), self.parts)) return Integer(self.n == 0) @@ -7857,7 +7820,7 @@ def _findlast(self, n, parts): # If the smallest part doesn't divide n, try using the next # largest part for i, p in enumerate(parts[1:]): - rest = self._findlast(n - p, parts[:i + 2]) + rest = self._findlast(n - p, parts[: i + 2]) if rest is not None: return [p] + rest # If we get to here, nothing ever worked, so there's no such @@ -7946,8 +7909,7 @@ def _other_iterator(self, n, parts): """ sorted_parts = sorted(parts, reverse=True) for vec in weighted_iterator_fast(n, sorted_parts): - yield sum(([pi] * multi - for pi, multi in zip(sorted_parts, vec)), []) + yield sum(([pi] * multi for pi, multi in zip(sorted_parts, vec)), []) class Partitions_starting(Partitions): @@ -7968,8 +7930,7 @@ def __classcall_private__(cls, n, starting_partition): True """ starting_partition = Partition(starting_partition) - return super().__classcall__(cls, Integer(n), - starting_partition) + return super().__classcall__(cls, Integer(n), starting_partition) def __init__(self, n, starting_partition): """ @@ -8105,8 +8066,7 @@ def __classcall_private__(cls, n, ending_partition): True """ ending_partition = Partition(ending_partition) - return super().__classcall__(cls, Integer(n), - ending_partition) + return super().__classcall__(cls, Integer(n), ending_partition) def __init__(self, n, ending_partition): """ @@ -8131,7 +8091,7 @@ def __init__(self, n, ending_partition): Partitions.__init__(self) self.n = n self._ending = ending_partition - self._ending_size_is_not_same = (n != sum(self._ending)) + self._ending_size_is_not_same = n != sum(self._ending) def _repr_(self): """ @@ -8228,6 +8188,7 @@ class PartitionsInBox(Partitions): sage: Partitions(max_part=2, max_length=3) Integer partitions which fit in a 3 x 2 box """ + def __init__(self, h, w): """ Initialize ``self``. @@ -8275,10 +8236,7 @@ def __contains__(self, x): sage: [3,1,0] in PartitionsInBox(2, 3) True """ - return (x in _Partitions - and (not x or not x[0] - or (x[0] <= self.w - and len(x) <= next(i for i, e in enumerate(reversed(x), self.h) if e)))) + return x in _Partitions and (not x or not x[0] or (x[0] <= self.w and len(x) <= next(i for i, e in enumerate(reversed(x), self.h) if e))) def list(self): """ @@ -8308,7 +8266,7 @@ def list(self): def add(x): return [x + [i] for i in range(x[-1] + 1)] - for i in range(h-1): + for i in range(h - 1): new_list = [] for element in l: new_list += add(element) @@ -8361,8 +8319,7 @@ def __setstate__(self, data): """ n = data['n'] self.__class__ = Partitions_with_constraints - constraints = {'max_slope': 0, - 'min_part': 1} + constraints = {'max_slope': 0, 'min_part': 1} constraints.update(data['constraints']) self.__init__(n, **constraints) @@ -8387,11 +8344,12 @@ class Partitions_with_constraints(IntegerListsLex): sage: loads(dumps(P)) == P True """ -# def __init__(self, n, **kwargs): -# """ -# Initialize ``self``. -# """ -# IntegerListsLex.__init__(self, n, **kwargs) + + # def __init__(self, n, **kwargs): + # """ + # Initialize ``self``. + # """ + # IntegerListsLex.__init__(self, n, **kwargs) Element = Partition options = Partitions.options @@ -8416,9 +8374,9 @@ def __contains__(self, x): False """ # strip off trailing 0s - for i in range(len(x)-1, -1, -1): + for i in range(len(x) - 1, -1, -1): if x[i] != 0: - x = x[:i+1] + x = x[: i + 1] break else: x = [] @@ -8429,6 +8387,7 @@ def __contains__(self, x): # Regular Partitions # ###################### + class RegularPartitions(Partitions): r""" Base class for `\ell`-regular partitions. @@ -8654,9 +8613,7 @@ def __contains__(self, x): sage: [0, 0, 0, 0] in P True """ - return (RegularPartitions.__contains__(self, x) - and (not x or not x[0] or - len(x) <= next(i for i, e in enumerate(reversed(x), self._max_len) if e))) + return RegularPartitions.__contains__(self, x) and (not x or not x[0] or len(x) <= next(i for i, e in enumerate(reversed(x), self._max_len) if e)) def _repr_(self): """ @@ -8778,8 +8735,7 @@ def __contains__(self, x): sage: [0, 0, 0, 0, 0] in P True """ - return (RegularPartitions.__contains__(self, x) - and (not x or x[0] <= self.k)) + return RegularPartitions.__contains__(self, x) and (not x or x[0] <= self.k) def _repr_(self): """ @@ -8808,7 +8764,7 @@ def __iter__(self): [[]] """ k = self.k - for n in reversed(range(k*(k+1)/2 * self._ell)): + for n in reversed(range(k * (k + 1) / 2 * self._ell)): for p in self._fast_iterator(n, k): yield self.element_class(self, p) @@ -8940,6 +8896,7 @@ def _an_element_(self): """ if self._ell == 1 and self.n > 0: from sage.categories.sets_cat import EmptySetError + raise EmptySetError return Partitions_n._an_element_(self) @@ -8948,6 +8905,7 @@ def _an_element_(self): # Ordered Partitions # ###################### + class OrderedPartitions(Partitions): """ The class of ordered partitions of `n`. If `k` is specified, then this @@ -8978,6 +8936,7 @@ class OrderedPartitions(Partitions): sage: OrderedPartitions(4).list() # needs sage.libs.gap [[4], [3, 1], [2, 2], [2, 1, 1], [1, 3], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]] """ + @staticmethod def __classcall_private__(cls, n, k=None): """ @@ -9055,6 +9014,7 @@ def list(self): [[2, 1], [1, 2]] """ from sage.libs.gap.libgap import libgap + n = self.n k = self.k if k is None: @@ -9082,6 +9042,7 @@ def cardinality(self): 16384 """ from sage.libs.gap.libgap import libgap + n = self.n k = self.k if k is None: @@ -9095,6 +9056,7 @@ def cardinality(self): # Partitions_length_and_parts_constrained # ########################################### + class Partitions_length_and_parts_constrained(Partitions): r""" The class of all integer partitions having parts and length in a @@ -9140,6 +9102,7 @@ class Partitions_length_and_parts_constrained(Partitions): sage: Partitions_length_and_parts_constrained(9, 1, 9, 1, 9) == Partitions(9) False """ + def __init__(self, n, min_length, max_length, min_part, max_part): """ Initialize ``self``. @@ -9236,10 +9199,7 @@ def __contains__(self, x): x = x[:-1] while x and not x[-1]: x.pop() - return (not x - or (x[-1] >= self._min_part - and x[0] <= self._max_part - and self._min_length <= len(x) <= self._max_length)) + return not x or (x[-1] >= self._min_part and x[0] <= self._max_part and self._min_length <= len(x) <= self._max_length) def __iter__(self): """ @@ -9250,12 +9210,7 @@ def __iter__(self): sage: list(Partitions(9, min_part=2, max_part=4, min_length=3, max_length=4)) [[4, 3, 2], [3, 3, 3], [3, 2, 2, 2]] """ - yield from IntegerListsLex(self._n, max_slope=0, - min_part=self._min_part, - max_part=self._max_part, - min_length=self._min_length, - max_length=self._max_length, - element_constructor=lambda x: self.element_class(self, x)) + yield from IntegerListsLex(self._n, max_slope=0, min_part=self._min_part, max_part=self._max_part, min_length=self._min_length, max_length=self._max_length, element_constructor=lambda x: self.element_class(self, x)) def cardinality(self): """ @@ -9292,18 +9247,17 @@ def cardinality(self): return number_of_partitions_max_length_max_part(n, m, b) - return (number_of_partitions_max_length_max_part(n, m, b) - - number_of_partitions_max_length_max_part(n, k - 1, b)) + return number_of_partitions_max_length_max_part(n, m, b) - number_of_partitions_max_length_max_part(n, k - 1, b) d = b - a - return ZZ.sum(number_of_partitions_max_length_max_part(n1, min(ell, n1), min(d, n1)) - for ell in range(k, min(m, n // a) + 1) if (n1 := n - a * ell) is not None) + return ZZ.sum(number_of_partitions_max_length_max_part(n1, min(ell, n1), min(d, n1)) for ell in range(k, min(m, n // a) + 1) if (n1 := n - a * ell) is not None) ########################## # Partitions Greatest LE # ########################## + class PartitionsGreatestLE(UniqueRepresentation, IntegerListsLex): r""" The class of all (unordered) "restricted" partitions of the @@ -9328,6 +9282,7 @@ class PartitionsGreatestLE(UniqueRepresentation, IntegerListsLex): sage: PartitionsGreatestLE(10, 2).first().parent() Partitions... """ + def __init__(self, n, k): """ Initialize ``self``. @@ -9380,6 +9335,7 @@ def cardinality(self): # Partitions Greatest EQ # ########################## + class PartitionsGreatestEQ(UniqueRepresentation, IntegerListsLex): """ The class of all (unordered) "restricted" partitions of the integer `n` @@ -9470,6 +9426,7 @@ def cardinality(self): # Restricted Partitions # ######################### + class RestrictedPartitions_generic(Partitions): r""" Base class for `\ell`-restricted partitions. @@ -9553,8 +9510,7 @@ def __contains__(self, x): return False if not x: return True - return (all(x[i] - x[i+1] < self._ell for i in range(len(x)-1)) - and x[-1] < self._ell) + return all(x[i] - x[i + 1] < self._ell for i in range(len(x) - 1)) and x[-1] < self._ell def _fast_iterator(self, n, max_part): """ @@ -9583,7 +9539,7 @@ def _fast_iterator(self, n, max_part): max_part = min(n, max_part) for i in range(max_part, 0, -1): - for p in self._fast_iterator(n-i, i): + for p in self._fast_iterator(n - i, i): if (p and i - p[0] >= self._ell) or (not p and i >= self._ell): break yield [i] + p @@ -9749,6 +9705,7 @@ def _an_element_(self): # partitions + def number_of_partitions(n, algorithm='default'): r""" Return the number of partitions of `n` with, optionally, at most `k` @@ -9919,11 +9876,12 @@ def number_of_partitions_length(n, k, algorithm='hybrid'): # We have one column of length `k` and all (inner) partitions of # size `n-k` can't have length more than `k` - if n <= k*2: + if n <= k * 2: return number_of_partitions(n - k) # Fall back to GAP from sage.libs.gap.libgap import libgap + return ZZ(libgap.NrPartitions(ZZ(n), ZZ(k))) @@ -9982,8 +9940,7 @@ def number_of_partitions_max_length_max_part(n, k, b): # than the third # since k >= b > 0 we have so min(k - 1, n1) >= min(m, n1) # except maybe for m == k == b - return sum(number_of_partitions_max_length_max_part(n1, min(k - 1, n1), min(m, n1)) - for m in range(1, b + 1) if (n1 := n - m) is not None) + return sum(number_of_partitions_max_length_max_part(n1, min(k - 1, n1), min(m, n1)) for m in range(1, b + 1) if (n1 := n - m) is not None) ########## @@ -9997,6 +9954,7 @@ def number_of_partitions_max_length_max_part(n, k, b): # AM issue #13072 try: from sage.libs.flint.arith_sage import number_of_partitions as flint_number_of_partitions + cached_number_of_partitions = cached_function(flint_number_of_partitions) except ImportError: pass @@ -10004,6 +9962,7 @@ def number_of_partitions_max_length_max_part(n, k, b): # October 2012: fixing outdated pickles which use classes being deprecated from sage.misc.persist import register_unpickle_override from sage.combinat.partition_tuple import PartitionTuples_level_size + register_unpickle_override('sage.combinat.partition', 'PartitionTuples_nk', PartitionTuples_level_size) register_unpickle_override('sage.combinat.partition', 'Partition_class', Partition) register_unpickle_override('sage.combinat.partition', 'OrderedPartitions_nk', OrderedPartitions) diff --git a/src/sage/combinat/partition_algebra.py b/src/sage/combinat/partition_algebra.py index ccc024dc504..f46c2ddae70 100644 --- a/src/sage/combinat/partition_algebra.py +++ b/src/sage/combinat/partition_algebra.py @@ -101,6 +101,7 @@ def check(self): # A_k # ####### + def SetPartitionsAk(k): r""" Return the combinatorial class of set partitions of type `A_k`. @@ -149,8 +150,7 @@ def __init__(self, k): True """ self.k = k - set_k = frozenset(list(range(1, k + 1)) + - [-x for x in range(1, k + 1)]) + set_k = frozenset(list(range(1, k + 1)) + [-x for x in range(1, k + 1)]) SetPartitions_set.__init__(self, set_k) Element = SetPartitionsXkElement @@ -207,8 +207,7 @@ def __contains__(self, x) -> bool: if x not in SetPartitionsAk_k(self.k + 1): return False - return all(self.k + 1 not in part or -self.k - 1 in part - for part in x) + return all(self.k + 1 not in part or -self.k - 1 in part for part in x) def __iter__(self): """ @@ -243,6 +242,7 @@ def __iter__(self): # S_k # ####### + def SetPartitionsSk(k): r""" Return the combinatorial class of set partitions of type `S_k`. @@ -432,6 +432,7 @@ def __iter__(self): # I_k # ####### + def SetPartitionsIk(k): r""" Return the combinatorial class of set partitions of type `I_k`. @@ -592,6 +593,7 @@ def __iter__(self): # B_k # ####### + def SetPartitionsBk(k): r""" Return the combinatorial class of set partitions of type `B_k`. @@ -796,6 +798,7 @@ def __iter__(self): # P_k # ####### + def SetPartitionsPk(k): r""" Return the combinatorial class of set partitions of type `P_k`. @@ -958,6 +961,7 @@ def __iter__(self): # T_k # ####### + def SetPartitionsTk(k): r""" Return the combinatorial class of set partitions of type `T_k`. @@ -1193,8 +1197,7 @@ def cardinality(self): sage: SetPartitionsRk(5).cardinality() 1546 """ - return sum(binomial(self.k, l)**2 * factorial(l) - for l in range(self.k + 1)) + return sum(binomial(self.k, l) ** 2 * factorial(l) for l in range(self.k + 1)) def __iter__(self): """ @@ -1272,8 +1275,7 @@ def cardinality(self): sage: SetPartitionsRk(4.5).cardinality() 209 """ - return sum(binomial(self.k, l)**2 * factorial(l) - for l in range(self.k + 1)) + return sum(binomial(self.k, l) ** 2 * factorial(l) for l in range(self.k + 1)) def __iter__(self): """ @@ -1451,9 +1453,7 @@ def __iter__(self): positives = Set(range(1, self.k + 1)) negatives = Set(-i for i in positives) - yield self.element_class(self, - to_set_partition([[self.k + 1, -self.k - 1]], - k=self.k + 1)) + yield self.element_class(self, to_set_partition([[self.k + 1, -self.k - 1]], k=self.k + 1)) for n in range(1, self.k + 1): for top in Subsets(positives, n): t = sorted(top) @@ -1461,13 +1461,13 @@ def __iter__(self): b = list(bottom) b.sort(reverse=True) l = [[t[i], b[i]] for i in range(n)] + [[self.k + 1, -self.k - 1]] - yield self.element_class(self, - to_set_partition(l, k=self.k + 1)) + yield self.element_class(self, to_set_partition(l, k=self.k + 1)) ######################################################### # Algebras + class PartitionAlgebra_generic(CombinatorialFreeModule): def __init__(self, R, cclass, n, k, name=None, prefix=None): """ @@ -1667,6 +1667,7 @@ def __init__(self, R, k, n, name=None): ########################################################## + def is_planar(sp): """ Return ``True`` if the diagram corresponding to the set partition is @@ -1897,8 +1898,7 @@ def to_set_partition(l, k=None): to_be_added -= spart sp.append(spart) - sp.extend(Set([singleton]) - for singleton in to_be_added) + sp.extend(Set([singleton]) for singleton in to_be_added) return Set(sp) @@ -1937,8 +1937,7 @@ def set_partition_composition(sp1, sp2): total_removed = 0 for cc in connected_components: # Remove the vertices that live in the middle two rows - new_cc = [x for x in cc if not ((x[0] < 0 and x[1] == 1) or - (x[0] > 0 and x[1] == 2))] + new_cc = [x for x in cc if not ((x[0] < 0 and x[1] == 1) or (x[0] > 0 and x[1] == 2))] if not new_cc: if len(cc) > 1: diff --git a/src/sage/combinat/partition_kleshchev.py b/src/sage/combinat/partition_kleshchev.py index a17fc293c8b..cdba87ded87 100644 --- a/src/sage/combinat/partition_kleshchev.py +++ b/src/sage/combinat/partition_kleshchev.py @@ -91,9 +91,9 @@ from collections import defaultdict -#-------------------------------------------------- +# -------------------------------------------------- # Kleshchev partition - element classes -#-------------------------------------------------- +# -------------------------------------------------- class KleshchevPartition(Partition): @@ -143,18 +143,18 @@ def conormal_cells(self, i=None): {0: [(1, 4), (3, 3)], 2: [(0, 5)]} """ # We use a dictionary for the conormal nodes as the indexing set is Z when e=0 - conormals = defaultdict(list) # the conormal cells of each residue - carry = defaultdict(int) # a tally of #(removable cells) - #(addable cells) + conormals = defaultdict(list) # the conormal cells of each residue + carry = defaultdict(int) # a tally of #(removable cells) - #(addable cells) # determine if we read up or down the partition KP = self.parent() - rows = list(range(len(self)+1)) + rows = list(range(len(self) + 1)) if KP._convention[1] == 'G': rows.reverse() # work through the rows for row in rows: - if row == len(self): # addable cell at bottom of partition + if row == len(self): # addable cell at bottom of partition res = KP._multicharge[0] - row if carry[res] == 0: conormals[res].append((row, 0)) @@ -162,13 +162,13 @@ def conormal_cells(self, i=None): carry[res] += 1 else: res = KP._multicharge[0] + self[row] - row - 1 - if row == len(self)-1 or self[row] > self[row+1]: # removable cell + if row == len(self) - 1 or self[row] > self[row + 1]: # removable cell carry[res] -= 1 - if row == 0 or self[row-1] > self[row]: # addable cell - if carry[res+1] >= 0: - conormals[res+1].append((row, self[row])) + if row == 0 or self[row - 1] > self[row]: # addable cell + if carry[res + 1] >= 0: + conormals[res + 1].append((row, self[row])) else: - carry[res+1] += 1 + carry[res + 1] += 1 # finally return the result return dict(conormals) if i is None else conormals[i] @@ -256,28 +256,28 @@ def normal_cells(self, i=None): [(3, 2)] """ # We use a dictionary for the normal nodes as the indexing set is Z when e=0 - normals = defaultdict(list) # the normal cells of each residue - carry = defaultdict(int) # a tally of #(removable cells)-#(addable cells) + normals = defaultdict(list) # the normal cells of each residue + carry = defaultdict(int) # a tally of #(removable cells)-#(addable cells) # determine if we read up or down the partition KP = self.parent() - rows = list(range(len(self)+1)) + rows = list(range(len(self) + 1)) if KP._convention[1] == 'S': rows.reverse() # work through the rows for row in rows: - if row == len(self): # addable cell at bottom of partition - carry[KP._multicharge[0]-row] += 1 + if row == len(self): # addable cell at bottom of partition + carry[KP._multicharge[0] - row] += 1 else: res = KP._multicharge[0] + self[row] - row - 1 - if row == len(self) - 1 or self[row] > self[row+1]: # removable cell + if row == len(self) - 1 or self[row] > self[row + 1]: # removable cell if carry[res] == 0: - normals[res].insert(0, (row, self[row]-1)) + normals[res].insert(0, (row, self[row] - 1)) else: carry[res] -= 1 - if row == 0 or self[row-1] > self[row]: # addable cell - carry[res+1] += 1 + if row == 0 or self[row - 1] > self[row]: # addable cell + carry[res + 1] += 1 # finally return the result return dict(normals) if i is None else normals[i] @@ -343,7 +343,7 @@ def good_residue_sequence(self): res = sorted(good_cells)[0] r, c = good_cells[res] - good_seq = type(self)(self.parent(), self.remove_cell(r,c)).good_residue_sequence() + good_seq = type(self)(self.parent(), self.remove_cell(r, c)).good_residue_sequence() good_seq.append(self.parent()._index_set(res)) return good_seq @@ -411,8 +411,7 @@ def mullineux_conjugate(self): size = None if isinstance(P, KleshchevPartitions_size): size = P._size - KP = KleshchevPartitions(P._e, [-c for c in P._multicharge], - size=size, convention=P._convention) + KP = KleshchevPartitions(P._e, [-c for c in P._multicharge], size=size, convention=P._convention) return KP.element_class(KP, []) good_cells = self.good_cells() @@ -426,9 +425,7 @@ def mullineux_conjugate(self): mu = P.element_class(P, self.remove_cell(r, c)).mullineux_conjugate() # add back on a cogood cell of residue -residue(k,r,c) KP = mu.parent() - return KP.element_class( - KP, - mu.add_cell(*mu.cogood_cells(r-c-self.parent()._multicharge[0]))) + return KP.element_class(KP, mu.add_cell(*mu.cogood_cells(r - c - self.parent()._multicharge[0]))) def is_regular(self) -> bool: r""" @@ -531,22 +528,22 @@ def conormal_cells(self, i=None): [(1, 0, 5), (1, 1, 3), (1, 2, 1)] """ # We use a dictionary for the conormal nodes as the indexing set is Z when e=0 - conormals = defaultdict(list) # the conormal cells of each residue - carry = defaultdict(int) # a tally of #(removable cells)-#(addable cells) + conormals = defaultdict(list) # the conormal cells of each residue + carry = defaultdict(int) # a tally of #(removable cells)-#(addable cells) part_lens = [len(part) for part in self] # so we don't repeatedly call these # the indices for the rows ending in addable nodes KP = self.parent() if KP._convention[0] == 'L': - rows = [(k,r) for k,ell in enumerate(part_lens) for r in range(ell+1)] + rows = [(k, r) for k, ell in enumerate(part_lens) for r in range(ell + 1)] else: - rows = [(k,r) for k,ell in reversed(list(enumerate(part_lens))) for r in range(ell+1)] + rows = [(k, r) for k, ell in reversed(list(enumerate(part_lens))) for r in range(ell + 1)] if KP._convention[1] == 'G': rows.reverse() for row in rows: - k,r = row - if r == part_lens[k]: # addable cell at bottom of a component + k, r = row + if r == part_lens[k]: # addable cell at bottom of a component res = KP._multicharge[k] - r if carry[res] == 0: conormals[res].append((k, r, 0)) @@ -555,13 +552,13 @@ def conormal_cells(self, i=None): else: part = self[k] res = KP._multicharge[k] + (part[r] - r - 1) - if r == part_lens[k] - 1 or part[r] > part[r+1]: # removable cell + if r == part_lens[k] - 1 or part[r] > part[r + 1]: # removable cell carry[res] -= 1 - if r == 0 or part[r-1] > part[r]: # addable cell - if carry[res+1] == 0: - conormals[res+1].append((k, r, part[r])) + if r == 0 or part[r - 1] > part[r]: # addable cell + if carry[res + 1] == 0: + conormals[res + 1].append((k, r, part[r])) else: - carry[res+1] += 1 + carry[res + 1] += 1 # finally return the result if i is None: @@ -657,36 +654,36 @@ def normal_cells(self, i=None): {0: [(0, 0, 3), (0, 1, 1)], 2: [(1, 0, 4), (1, 1, 2), (1, 2, 0)]} """ # We use a dictionary for the normal nodes as the indexing set is Z when e=0 - normals = defaultdict(list) # the normal cells of each residue - carry = defaultdict(int) # a tally of #(removable cells)-#(addable cells) + normals = defaultdict(list) # the normal cells of each residue + carry = defaultdict(int) # a tally of #(removable cells)-#(addable cells) part_lens = [len(part) for part in self] # so we don't repeatedly call these KP = self.parent() if KP._convention[0] == 'L': - rows = [(k, r) for k, ell in enumerate(part_lens) for r in range(ell+1)] + rows = [(k, r) for k, ell in enumerate(part_lens) for r in range(ell + 1)] else: - rows = [(k, r) for k, ell in reversed(list(enumerate(part_lens))) for r in range(ell+1)] + rows = [(k, r) for k, ell in reversed(list(enumerate(part_lens))) for r in range(ell + 1)] if KP._convention[1] == 'S': rows.reverse() for row in rows: k, r = row if r == part_lens[k]: # addable cell at bottom of a component - carry[KP._multicharge[k]-r] += 1 + carry[KP._multicharge[k] - r] += 1 else: part = self[k] res = KP._multicharge[k] + (part[r] - r - 1) - if r == part_lens[k]-1 or part[r] > part[r+1]: # removable cell + if r == part_lens[k] - 1 or part[r] > part[r + 1]: # removable cell if carry[res] == 0: - normals[res].insert(0, (k, r, part[r]-1)) + normals[res].insert(0, (k, r, part[r] - 1)) else: carry[res] -= 1 - if r == 0 or part[r-1] > part[r]: # addable cell - carry[res+1] += 1 + if r == 0 or part[r - 1] > part[r]: # addable cell + carry[res + 1] += 1 # finally return the result if i is None: - return dict(normals) # change the defaultdict into a dict + return dict(normals) # change the defaultdict into a dict return normals[i] @@ -796,22 +793,21 @@ def mullineux_conjugate(self): size = None if isinstance(P, KleshchevPartitions_size): size = P._size - KP = KleshchevPartitions(P._e, [-c for c in P._multicharge], - size=size, convention=P._convention) - return KP.element_class(KP, [[]]*P._level) + KP = KleshchevPartitions(P._e, [-c for c in P._multicharge], size=size, convention=P._convention) + return KP.element_class(KP, [[]] * P._level) good_cells = self.good_cells() assert good_cells - k,r,c = sorted(good_cells.values())[0] + k, r, c = sorted(good_cells.values())[0] # This is technically wrong when the parent has a fixed size because # the resulting Kleshchev partition after removing a cell has abs # smaller size. However, this is useful to avoid constructing # transient parents. - mu = P.element_class(P, self.remove_cell(k,r,c)).mullineux_conjugate() + mu = P.element_class(P, self.remove_cell(k, r, c)).mullineux_conjugate() # add back on a cogood cell of residue -residue(k,r,c) KP = mu.parent() - return KP.element_class(KP, mu.add_cell(*mu.cogood_cells( r-c-self.parent()._multicharge[k]))) + return KP.element_class(KP, mu.add_cell(*mu.cogood_cells(r - c - self.parent()._multicharge[k]))) def is_regular(self) -> bool: r""" @@ -916,7 +912,7 @@ def Epsilon(self): WLR = P.weight_lattice_realization() La = WLR.fundamental_weights() n = self.normal_cells() - return WLR.sum(len(n[i])*La[i] for i in P.index_set() if i in n) + return WLR.sum(len(n[i]) * La[i] for i in P.index_set() if i in n) def Phi(self): r""" @@ -933,7 +929,7 @@ def Phi(self): WLR = P.weight_lattice_realization() La = WLR.fundamental_weights() c = self.conormal_cells() - return WLR.sum(len(c[i])*La[i] for i in P.index_set() if i in c) + return WLR.sum(len(c[i]) * La[i] for i in P.index_set() if i in c) def weight(self): r""" @@ -967,8 +963,7 @@ def weight(self): La = WLR.fundamental_weights() r = self.parent()._multicharge wt = WLR.sum(La[ZZ(x)] for x in r) - return wt - WLR.sum(alpha[self.content(*c, multicharge=r)] - for c in self.cells()) + return wt - WLR.sum(alpha[self.content(*c, multicharge=r)] for c in self.cells()) class KleshchevPartitionCrystal(KleshchevPartition, KleshchevCrystalMixin): @@ -1023,7 +1018,7 @@ def f(self, i): cell = self.cogood_cells(i) if cell is None: return None - r,c = cell + r, c = cell mu = list(self) if c == 0: mu.append(1) @@ -1084,7 +1079,7 @@ def f(self, i): cell = self.cogood_cells(i) if cell is None: return None - k,r,c = cell + k, r, c = cell mu = self.to_list() if c == 0: mu[k].append(1) @@ -1092,9 +1087,10 @@ def f(self, i): mu[k][r] += 1 return type(self)(P, mu) -#-------------------------------------------------- + +# -------------------------------------------------- # Kleshchev partitions - parent classes -#-------------------------------------------------- +# -------------------------------------------------- class KleshchevPartitions(PartitionTuples): @@ -1184,9 +1180,9 @@ class KleshchevPartitions(PartitionTuples): - [BK2009]_ - [Kle2009]_ """ + @staticmethod - def __classcall_private__(cls, e, multicharge=(0,), size=None, - convention="left restricted"): + def __classcall_private__(cls, e, multicharge=(0,), size=None, convention="left restricted"): r""" This is a factory class which returns the appropriate parent based on the values of `level` and `size`. @@ -1210,7 +1206,7 @@ def __classcall_private__(cls, e, multicharge=(0,), size=None, convention = convention[0] + 'S' elif 'G' in convention: convention = convention[0] + 'G' - if convention not in ['RG','LG', 'RS', 'LS']: + if convention not in ['RG', 'LG', 'RS', 'LS']: raise ValueError('invalid convention') if size is None: @@ -1446,7 +1442,8 @@ def __init__(self, e, multicharge, convention): from sage.combinat.root_system.cartan_type import CartanType from sage.categories.highest_weight_crystals import HighestWeightCrystals from sage.categories.regular_crystals import RegularCrystals - self._cartan_type = CartanType(['A', e-1, 1]) + + self._cartan_type = CartanType(['A', e - 1, 1]) cat = (HighestWeightCrystals(), RegularCrystals().Infinite()) else: cat = InfiniteEnumeratedSets() @@ -1459,7 +1456,7 @@ def __init__(self, e, multicharge, convention): self.Element = KleshchevPartitionTupleCrystal super().__init__(category=cat) - self._e = e # for printing + self._e = e # for printing self._index_set = IntegerModRing(e) self._multicharge = multicharge self._convention = convention @@ -1467,7 +1464,7 @@ def __init__(self, e, multicharge, convention): if self._level == 1: self.module_generators = (self.element_class(self, []),) else: - self.module_generators = (self.element_class(self, [[]]*self._level),) + self.module_generators = (self.element_class(self, [[]] * self._level),) def _repr_(self): """ @@ -1483,8 +1480,7 @@ def _repr_(self): if self._level == 1: return 'Kleshchev partitions with e=%s' % (self._e) - return 'Kleshchev partitions with e=%s and multicharge=(%s)' % ( - self._e,','.join('%s' % m for m in self._multicharge)) + return 'Kleshchev partitions with e=%s and multicharge=(%s)' % (self._e, ','.join('%s' % m for m in self._multicharge)) def __contains__(self, mu): """ @@ -1599,7 +1595,7 @@ def __iter__(self): for mu in P: yield self.element_class(self, list(mu)) else: - next_level = [self.element_class(self, [[]]*len(self._multicharge))] + next_level = [self.element_class(self, [[]] * len(self._multicharge))] while True: cur = next_level next_level = [] @@ -1707,9 +1703,7 @@ def _repr_(self): if self._level == 1: return 'Kleshchev partitions with e=%s and size %s' % (self._e, self._size) - return 'Kleshchev partitions with e=%s and multicharge=(%s) and size %s' % ( - self._e,','.join('%s' % m for m in self._multicharge), self._size - ) + return 'Kleshchev partitions with e=%s and multicharge=(%s) and size %s' % (self._e, ','.join('%s' % m for m in self._multicharge), self._size) def __contains__(self, mu): """ @@ -1786,20 +1780,18 @@ def __iter__higher_levels(self): [([1], [1]), ([], [2]), ([], [1, 1])] """ if self._size == 0: - yield self.element_class(self, [[]]*len(self._multicharge)) + yield self.element_class(self, [[]] * len(self._multicharge)) return # For higher levels we have to recursively construct the restricted partitions # by adding on co-good nodes to smaller restricted partition. To avoid over # counting we return a new restricted partition only if we added on its lowest # good node. - for mu in KleshchevPartitions_size(self._e, self._multicharge, - size=self._size-1, - convention=self._convention): + for mu in KleshchevPartitions_size(self._e, self._multicharge, size=self._size - 1, convention=self._convention): mu_list = mu.to_list() for cell in mu.cogood_cells().values(): data = [list(p) for p in mu_list] - k,r,c = cell + k, r, c = cell if c == 0: data[k].append(1) else: @@ -1860,9 +1852,10 @@ def _an_element_(self): Element = KleshchevPartitionTuple -#-------------------------------------------------- + +# -------------------------------------------------- # helper functions -#-------------------------------------------------- +# -------------------------------------------------- def _a_good_cell(kpt, multicharge, convention): @@ -1889,29 +1882,29 @@ def _a_good_cell(kpt, multicharge, convention): True """ # We use a dictionary for the normal nodes as the indexing set is Z when e=0 - carry = defaultdict(int) # a tally of #(removable cells)-#(addable cells) + carry = defaultdict(int) # a tally of #(removable cells)-#(addable cells) ret = None if convention[0] == 'L': - rows = [(k,r) for k,part in enumerate(kpt) for r in range(len(part)+1)] + rows = [(k, r) for k, part in enumerate(kpt) for r in range(len(part) + 1)] else: - rows = [(k,r) for k,part in reversed(list(enumerate(kpt))) for r in range(len(part)+1)] + rows = [(k, r) for k, part in reversed(list(enumerate(kpt))) for r in range(len(part) + 1)] if convention[1] == 'S': rows.reverse() for row in rows: - k,r = row - if r == len(kpt[k]): # addable cell at bottom of a component - carry[multicharge[k]-r] += 1 + k, r = row + if r == len(kpt[k]): # addable cell at bottom of a component + carry[multicharge[k] - r] += 1 else: res = multicharge[k] + kpt[k][r] - r - 1 - if r == len(kpt[k])-1 or kpt[k][r] > kpt[k][r+1]: # removable cell + if r == len(kpt[k]) - 1 or kpt[k][r] > kpt[k][r + 1]: # removable cell if carry[res] == 0: - ret = (k, r, kpt[k][r]-1) + ret = (k, r, kpt[k][r] - 1) else: carry[res] -= 1 - if r == 0 or kpt[k][r-1] > kpt[k][r]: # addable cell - carry[res+1] += 1 + if r == 0 or kpt[k][r - 1] > kpt[k][r]: # addable cell + carry[res + 1] += 1 # finally return the result return ret diff --git a/src/sage/combinat/partition_shifting_algebras.py b/src/sage/combinat/partition_shifting_algebras.py index 84270ca5538..d7681029feb 100644 --- a/src/sage/combinat/partition_shifting_algebras.py +++ b/src/sage/combinat/partition_shifting_algebras.py @@ -61,8 +61,7 @@ def __init__(self): sage: from sage.combinat.partition_shifting_algebras import ShiftingSequenceSpace sage: S = ShiftingSequenceSpace() """ - Parent.__init__(self, facade=(tuple,), - category=Sets().Infinite().Facade()) + Parent.__init__(self, facade=(tuple,), category=Sets().Infinite().Facade()) def __contains__(self, seq): r""" @@ -85,8 +84,7 @@ def __contains__(self, seq): sage: (0.5, 1) in S False """ - return (isinstance(seq, tuple) and all(i in ZZ for i in seq) - and (not seq or seq[-1])) + return isinstance(seq, tuple) and all(i in ZZ for i in seq) and (not seq or seq[-1]) def check(self, seq): r""" @@ -246,9 +244,7 @@ def __init__(self, base_ring=QQ['t'], prefix='S'): """ indices = ShiftingSequenceSpace() cat = Algebras(base_ring).WithBasis() - CombinatorialFreeModule.__init__(self, base_ring, indices, - prefix=prefix, - bracket=False, category=cat) + CombinatorialFreeModule.__init__(self, base_ring, indices, prefix=prefix, bracket=False, category=cat) # Setup default conversions sym = SymmetricFunctions(base_ring) @@ -311,7 +307,7 @@ def _prepare_seq(self, seq): index = len(seq) - 1 while index >= 0 and seq[index] == 0: index -= 1 - seq = seq[:index + 1] + seq = seq[: index + 1] self._indices.check(seq) return seq @@ -357,7 +353,7 @@ def product_on_basis(self, x, y): index = len(x) - 1 while index >= 0 and x[index] == 0: index -= 1 - return self.monomial(tuple(x[:index + 1])) + return self.monomial(tuple(x[: index + 1])) @cached_method def one_basis(self): @@ -425,15 +421,13 @@ def _supp_to_s(self, gamma): sage: S._supp_to_s(S([3,2,0]).support_of_term()) s[3, 2] """ + def number_of_noninversions(lis): - return sum(1 for i, val in enumerate(lis) - for j in range(i + 1, len(lis)) - if val < lis[j]) # i < j is already enforced + return sum(1 for i, val in enumerate(lis) for j in range(i + 1, len(lis)) if val < lis[j]) # i < j is already enforced rho = list(range(len(gamma) - 1, -1, -1)) combined = [g + r for g, r in zip(gamma, rho)] - if len(set(combined)) == len(combined) and all(e >= 0 - for e in combined): + if len(set(combined)) == len(combined) and all(e >= 0 for e in combined): sign = (-1) ** number_of_noninversions(combined) sort_combined = sorted(combined, reverse=True) new_gamma = [sc - r for sc, r in zip(sort_combined, rho)] @@ -496,8 +490,7 @@ def build_and_register_conversion(self, support_map, codomain): sage: op(2*m[4,3] + 5*m[2,2] + 7*m[2]) == 2*m[5, 2] + 5*m[3, 1] True """ - module_morphism = self.module_morphism(support_map, - codomain=codomain) + module_morphism = self.module_morphism(support_map, codomain=codomain) codomain.register_conversion(module_morphism) def ij(self, i, j): @@ -559,6 +552,7 @@ def __call__(self, operand): """ P = self.parent() if isinstance(operand, (list, tuple, Composition, Partition)): + def add_lists(x, y): # Make x have the longer length if len(x) < len(y): @@ -567,12 +561,11 @@ def add_lists(x, y): for i, val in enumerate(y): x[i] += val return x - return [(add_lists(index, operand), coeff) - for index, coeff in self] + + return [(add_lists(index, operand), coeff) for index, coeff in self] R = self.base_ring() - lift_operand = P._from_dict({P._prepare_seq(p): R(c) - for p, c in operand}, coerce=False) + lift_operand = P._from_dict({P._prepare_seq(p): R(c) for p, c in operand}, coerce=False) result = self * lift_operand operand_parent = operand.parent() try: diff --git a/src/sage/combinat/partition_tuple.py b/src/sage/combinat/partition_tuple.py index f8f2175f73d..4afce243d31 100644 --- a/src/sage/combinat/partition_tuple.py +++ b/src/sage/combinat/partition_tuple.py @@ -260,8 +260,7 @@ class of modules for the algebras, which are generalisations of the Specht from .combinat import CombinatorialElement from .integer_vector import IntegerVectors -from .partition import (Partition, Partitions, Partitions_n, _Partitions, - RegularPartitions_all, RegularPartitions_n) +from .partition import Partition, Partitions, Partitions_n, _Partitions, RegularPartitions_all, RegularPartitions_n from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.misc.cachefunc import cached_method @@ -406,6 +405,7 @@ class of modules for the algebras which are generalisations of the Specht - :class:`PartitionTuples` - :class:`Partitions` """ + Element = Partition @staticmethod @@ -688,8 +688,8 @@ def _latex_young_diagram(self): sage: mu = PartitionTuple([[2, 1],[1,1,1]])._latex_young_diagram() """ from sage.combinat.output import tex_from_array_tuple - return tex_from_array_tuple([[["\\phantom{x}"] * row for row in mu] - for mu in self._list]) + + return tex_from_array_tuple([[["\\phantom{x}"] * row for row in mu] for mu in self._list]) def _latex_diagram(self): """ @@ -701,8 +701,8 @@ def _latex_diagram(self): """ entry = self.parent().options("latex_diagram_str") from sage.combinat.output import tex_from_array_tuple - return tex_from_array_tuple([[[entry] * row for row in mu] - for mu in self._list], with_lines=False) + + return tex_from_array_tuple([[[entry] * row for row in mu] for mu in self._list], with_lines=False) def _latex_list(self): """ @@ -722,9 +722,7 @@ def _latex_exp_low(self): sage: mu = PartitionTuple([[2, 1],[1,1,1,1,1,1,1,1,1,1]])._latex_exp_low() """ - txt = '|'.join(','.join('%s%s' % (a + 1, '' if e == 1 else '^{%s}' % e) - for a, e in enumerate(mu)) - for mu in self.to_exp()) + txt = '|'.join(','.join('%s%s' % (a + 1, '' if e == 1 else '^{%s}' % e) for a, e in enumerate(mu)) for mu in self.to_exp()) return '(' + txt + ')' def _latex_exp_high(self): @@ -735,9 +733,7 @@ def _latex_exp_high(self): sage: mu = PartitionTuple([[2, 1],[1,1,1,1,1,1,1,1,1,1]])._latex_exp_high() """ - txt = '|'.join(','.join(['%s%s' % (a + 1, '' if e == 1 else '^{%s}' % e) - for a, e in enumerate(mu)][::-1]) - for mu in self.to_exp()) + txt = '|'.join(','.join(['%s%s' % (a + 1, '' if e == 1 else '^{%s}' % e) for a, e in enumerate(mu)][::-1]) for mu in self.to_exp()) return '(' + txt + ')' def components(self): @@ -791,7 +787,7 @@ def diagram(self): sage: PartitionTuples.options._reset() """ col_len = [mu and mu[0] or 1 for mu in self] # columns per component - row_max = max(len(mu) for mu in self) # maximum row length + row_max = max(len(mu) for mu in self) # maximum row length # There should be a fancier list compression for this but I couldn't get # one to work in the cases where a component was the empty partition diag = [] @@ -802,9 +798,9 @@ def diagram(self): if row == 0 and self[c] == []: line += ' -' elif row < len(self[c]): - line += ' {:{}}'.format(diag_str*self[c][row],col_len[c]) + line += ' {:{}}'.format(diag_str * self[c][row], col_len[c]) else: - line += ' {:{}}'.format('',col_len[c]) + line += ' {:{}}'.format('', col_len[c]) diag.append(line.rstrip()) if PartitionTuples.options('convention') == "English": return '\n'.join(map(str, diag)) @@ -851,6 +847,7 @@ def row_standard_tableaux(self): Row standard tableau tuples of shape ([], [3, 2, 2, 1], [2, 2, 1], [3]) """ from .tableau_tuple import RowStandardTableauTuples + return RowStandardTableauTuples(shape=self) def standard_tableaux(self): @@ -864,6 +861,7 @@ def standard_tableaux(self): Standard tableau tuples of shape ([], [3, 2, 2, 1], [2, 2, 1], [3]) """ from .tableau_tuple import StandardTableauTuples + return StandardTableauTuples(shape=self) def up(self): @@ -973,7 +971,7 @@ def content(self, k, r, c, multicharge): sage: PartitionTuple([[2,1],[2],[1,1,1]]).content(0,1,0, multicharge) 2 """ - return multicharge[k]-r+c + return multicharge[k] - r + c def content_tableau(self, multicharge): """ @@ -1002,10 +1000,8 @@ def content_tableau(self, multicharge): 2 """ from sage.combinat.tableau_tuple import TableauTuple - return TableauTuple([[[multicharge[k] - r + c - for c in range(self[k][r])] - for r in range(len(self[k]))] - for k in range(len(self))]) + + return TableauTuple([[[multicharge[k] - r + c for c in range(self[k][r])] for r in range(len(self[k]))] for k in range(len(self))]) def conjugate(self): """ @@ -1091,6 +1087,7 @@ def initial_tableau(self): ([[1, 2], [3]], [[4, 5, 6], [7, 8]]) """ from .tableau_tuple import StandardTableauTuples + return StandardTableauTuples(self).first() @cached_method @@ -1178,15 +1175,16 @@ def garnir_tableau(self, *cell): except ValueError: comp, row, col = cell[0] - if comp >= len(self) or row+1 >= len(self[comp]) or col >= self[comp][row+1]: + if comp >= len(self) or row + 1 >= len(self[comp]) or col >= self[comp][row + 1]: raise ValueError('(comp, row+1, col) must be inside the diagram') g = self.initial_tableau().to_list() a = g[comp][row][col] - g[comp][row][col:] = list(range(a+col+1, g[comp][row+1][col]+1)) - g[comp][row+1][:col+1] = list(range(a, a+col+1)) + g[comp][row][col:] = list(range(a + col + 1, g[comp][row + 1][col] + 1)) + g[comp][row + 1][: col + 1] = list(range(a, a + col + 1)) from .tableau_tuple import TableauTuple + g = TableauTuple(g) - g._garnir_cell = (comp,row,col) + g._garnir_cell = (comp, row, col) return g def top_garnir_tableau(self, e, cell): @@ -1244,26 +1242,27 @@ def top_garnir_tableau(self, e, cell): - :meth:`~sage.combinat.partition.Partition_tuple.garnir_tableau` """ comp, row, col = cell - if comp >= len(self) or row+1 >= len(self[comp]) or col >= self[comp][row+1]: + if comp >= len(self) or row + 1 >= len(self[comp]) or col >= self[comp][row + 1]: raise ValueError('(comp, row+1, col) must be inside the diagram') g = self.garnir_tableau(cell) if e == 0: - return # no more dominant tableau of the same residue + return # no more dominant tableau of the same residue - a = e*int((self[comp][row]-col)/e) # number of cells in the e-bricks in row `row` - b = e*int((col+1)/e) # number of cells in the e-bricks in row `row+1` + a = e * int((self[comp][row] - col) / e) # number of cells in the e-bricks in row `row` + b = e * int((col + 1) / e) # number of cells in the e-bricks in row `row+1` if a == 0 or b == 0: return self.garnir_tableau(cell) t = g.to_list() - m = t[comp][row+1][0] # smallest number of 0-Garnir belt + m = t[comp][row + 1][0] # smallest number of 0-Garnir belt # now we will put the number m,m+1,...,t[row+1][col] in order into t - t[comp][row][col:a+col] = [m+col-b+1+i for i in range(a)] - t[comp][row+1][col-b+1:col+1] = [m+a+col-b+1+i for i in range(b)] + t[comp][row][col : a + col] = [m + col - b + 1 + i for i in range(a)] + t[comp][row + 1][col - b + 1 : col + 1] = [m + a + col - b + 1 + i for i in range(b)] from .tableau_tuple import StandardTableauTuple + return StandardTableauTuple(t) def arm_length(self, k, r, c): @@ -1292,9 +1291,9 @@ def arm_length(self, k, r, c): 0 """ try: - return self[k][r]-(c+1) + return self[k][r] - (c + 1) except IndexError: - raise ValueError("The cell %s is not in the diagram" % ((k,r,c),)) + raise ValueError("The cell %s is not in the diagram" % ((k, r, c),)) def leg_length(self, k, r, c): """ @@ -1321,7 +1320,7 @@ def leg_length(self, k, r, c): 0 """ try: - return self[k].leg_length(r,c) + return self[k].leg_length(r, c) except IndexError: raise ValueError("The cell is not in the diagram") @@ -1356,7 +1355,7 @@ def hook_length(self, k, r, c): [2, 1, 2, 1, 3, 1, 1] """ try: - return self[k].hook_length(r,c) + return self[k].hook_length(r, c) except IndexError: raise ValueError("The cell is not in the diagram") @@ -1390,8 +1389,7 @@ def removable_cells(self): sage: PartitionTuple([[1,1],[4,3],[2,1,1]]).removable_cells() [(0, 1, 0), (1, 0, 3), (1, 1, 2), (2, 0, 1), (2, 2, 0)] """ - return [(k, r, c) for k in range(len(self)) - for r, c in self[k].removable_cells()] + return [(k, r, c) for k in range(len(self)) for r, c in self[k].removable_cells()] corners = removable_cells # for compatibility with partitions @@ -1409,8 +1407,7 @@ def addable_cells(self): sage: PartitionTuple([[1,1],[4,3],[2,1,1]]).addable_cells() [(0, 0, 1), (0, 2, 0), (1, 0, 4), (1, 1, 3), (1, 2, 0), (2, 0, 2), (2, 1, 1), (2, 3, 0)] """ - return [(k, r, c) for k in range(len(self)) - for r, c in self[k].addable_cells()] + return [(k, r, c) for k in range(len(self)) for r, c in self[k].addable_cells()] outside_corners = addable_cells # for compatibility with partitions @@ -1485,7 +1482,7 @@ def young_subgroup(self): for row in comp: gens.extend((c, c + 1) for c in range(m + 1, m + row)) m += row - gens.append(list(range(1, self.size()+1))) # to ensure we get a subgroup of Sym_n + gens.append(list(range(1, self.size() + 1))) # to ensure we get a subgroup of Sym_n return PermutationGroup(gens) def young_subgroup_generators(self): @@ -1585,7 +1582,7 @@ def degree(self, e): for some integer `N`. Compare with :meth:`prime_degree`. """ - multicharge = tuple([i*self.size() for i in range(self.size())]) + multicharge = tuple([i * self.size() for i in range(self.size())]) return sum(t.degree(e, multicharge) for t in self.standard_tableaux()) def prime_degree(self, p): @@ -1632,9 +1629,9 @@ def prime_degree(self, p): """ ps = [p] - while ps[-1]*p < self.size(): + while ps[-1] * p < self.size(): ps.append(ps[-1] * p) - multicharge = tuple([i*self.size() for i in range(self.size())]) + multicharge = tuple([i * self.size() for i in range(self.size())]) return sum(t.degree(pk, multicharge) for pk in ps for t in self.standard_tableaux()) @cached_method @@ -1747,8 +1744,8 @@ def defect(self, e, multicharge): # We use a dictionary to cover the case when e = 0. beta = self.block(e, multicharge) Ie = IntegerModRing(e) - return (sum(beta.get(r, 0) for r in multicharge) - - sum(beta[r]**2 - beta[r] * beta.get(Ie(r+1), 0) for r in beta)) + return sum(beta.get(r, 0) for r in multicharge) - sum(beta[r] ** 2 - beta[r] * beta.get(Ie(r + 1), 0) for r in beta) + # ------------------------------------------------- # Partition tuples - parent classes @@ -1829,14 +1826,11 @@ def __classcall_private__(klass, level=None, size=None, regular=None): if isinstance(regular, (list, tuple)): if level is None: - raise ValueError("When no level is specified, regular must be " - "a positive integer") + raise ValueError("When no level is specified, regular must be " "a positive integer") if len(regular) != level: - raise ValueError("regular must be a list of length {}, got {}".format( - level, regular)) + raise ValueError("regular must be a list of length {}, got {}".format(level, regular)) if regular == 0: - raise ValueError("regular must be a positive integer or a tuple " - "of nonnegative integers") + raise ValueError("regular must be a positive integer or a tuple " "of nonnegative integers") if level is None: if size is None: if regular is None: @@ -1984,9 +1978,9 @@ def __getitem__(self, r): ([], [], [1]), ([], [], [], [])] """ - if isinstance(r,(int,Integer)): + if isinstance(r, (int, Integer)): return self.unrank(r) - if isinstance(r,slice): + if isinstance(r, slice): start = 0 if r.start is None else r.start stop = r.stop if stop is None and not self.is_finite(): @@ -2101,8 +2095,8 @@ def __iter__(self): ([], [], [], [])] """ for size in NN: - for level in range(size+1): - for mu in PartitionTuples_level_size(level+1,size-level): + for level in range(size + 1): + for mu in PartitionTuples_level_size(level + 1, size - level): yield self._element_constructor_(mu) def _an_element_(self): @@ -2114,7 +2108,7 @@ def _an_element_(self): sage: PartitionTuples().an_element() ([1, 1, 1, 1], [2, 1, 1], [3, 1], [4]) """ - return self.element_class(self,([1,1,1,1],[2,1,1],[3,1],[4])) + return self.element_class(self, ([1, 1, 1, 1], [2, 1, 1], [3, 1], [4])) class PartitionTuples_level(PartitionTuples): @@ -2386,9 +2380,7 @@ def __contains__(self, mu): """ if self._level == 1 and mu in _Partitions: return self._size == sum(mu) - return (PartitionTuples.__contains__(self, mu) - and self._level == len(mu) - and self._size == sum(map(sum,mu))) + return PartitionTuples.__contains__(self, mu) and self._level == len(mu) and self._size == sum(map(sum, mu)) def __iter__(self): r""" @@ -2415,7 +2407,7 @@ def __iter__(self): ([], [], [2]), ([], [], [1, 1])] """ - p = [Partitions_n(i) for i in range(self._size+1)] + p = [Partitions_n(i) for i in range(self._size + 1)] for iv in IntegerVectors(self._size, self._level): for cp in itertools.product(*[p[i] for i in iv]): yield self._element_constructor_(cp) @@ -2432,10 +2424,10 @@ def _an_element_(self): mu = [[] for _ in itertools.repeat(None, self._level)] if self._size > 0: if self._level == 1: - mu = [self._size-1,1] + mu = [self._size - 1, 1] else: mu[0] = [1] - mu[-1] = [self._size-1] + mu[-1] = [self._size - 1] return self.element_class(self, mu) def cardinality(self): @@ -2469,7 +2461,7 @@ def cardinality(self): awful long time for gap to compute). """ eta = pari(f'Ser(x,x,{self.size()})').eta() - return ZZ((1 / eta**self.level()).polcoef(self.size(), pari('x'))) + return ZZ((1 / eta ** self.level()).polcoef(self.size(), pari('x'))) def __setstate__(self, state): r""" @@ -2484,13 +2476,14 @@ def __setstate__(self, state): sage: loads(dumps( PartitionTuples(7,3) )) # indirect doctest for unpickling a Tableau element Partition tuples of level 7 and size 3 """ - if isinstance(state, dict): # for old pickles from Tableau_class + if isinstance(state, dict): # for old pickles from Tableau_class parts = PartitionTuples(state['k'], state['n']) self.__class__ = parts.__class__ self.__dict__ = parts.__dict__ else: super().__setstate__(state) + ############################################################################### # Regular partition tuples @@ -2627,8 +2620,8 @@ def __iter__(self): ([], [], [1], [])] """ for N in NN: - for size in range(N+1): - for mu in RegularPartitionTuples_level_size(N-size+1, size, self._ell): + for size in range(N + 1): + for mu in RegularPartitionTuples_level_size(N - size + 1, size, self._ell): yield self.element_class(self, list(mu)) @@ -2725,10 +2718,8 @@ def _repr_(self): (2, 3, 0, 2)-Regular partition tuples of level 4 """ if self._ell[1:] == self._ell[:-1]: - return '{}-Regular partition tuples of level {}'.format(self._ell[0], - self._level) - return '{}-Regular partition tuples of level {}'.format(self._ell, - self._level) + return '{}-Regular partition tuples of level {}'.format(self._ell[0], self._level) + return '{}-Regular partition tuples of level {}'.format(self._ell, self._level) def __contains__(self, mu): r""" @@ -2786,10 +2777,8 @@ def __contains__(self, mu): if isinstance(mu, Partition): # it is level 1 return False if isinstance(mu, PartitionTuple): - return all(max(p.to_exp() + [0]) < ell for p, ell in zip(mu, self._ell) - if ell > 0) - return all(p in RegularPartitions_all(ell) for p, ell in zip(mu, self._ell) - if ell > 0) + return all(max(p.to_exp() + [0]) < ell for p, ell in zip(mu, self._ell) if ell > 0) + return all(p in RegularPartitions_all(ell) for p, ell in zip(mu, self._ell) if ell > 0) def __iter__(self): r""" @@ -2908,10 +2897,7 @@ def __contains__(self, mu): sage: [4, 3, 2] in RPT True """ - return ((mu in RegularPartitions_all(self._ell) - and self._size == sum(mu)) - or (RegularPartitionTuples.__contains__(self, mu) - and self._size == sum(map(sum, mu)))) + return (mu in RegularPartitions_all(self._ell) and self._size == sum(mu)) or (RegularPartitionTuples.__contains__(self, mu) and self._size == sum(map(sum, mu))) def __iter__(self): r""" @@ -3022,10 +3008,8 @@ def _repr_(self): 3-Regular partition tuples of level 4 and size 2 """ if self._ell[1:] == self._ell[:-1]: - return '{}-Regular partition tuples of level {} and size {}'.format( - self._ell[0], self._level, self._size) - return '{}-Regular partition tuples of level {} and size {}'.format( - self._ell, self._level, self._size) + return '{}-Regular partition tuples of level {} and size {}'.format(self._ell[0], self._level, self._size) + return '{}-Regular partition tuples of level {} and size {}'.format(self._ell, self._level, self._size) def __contains__(self, mu): r""" @@ -3082,8 +3066,7 @@ def __iter__(self): ([], [], [2, 1])] """ for iv in IntegerVectors(self._size, self._level): - p = [RegularPartitions_n(v, ell) if ell > 0 else Partitions_n(v) - for v, ell in zip(iv, self._ell)] + p = [RegularPartitions_n(v, ell) if ell > 0 else Partitions_n(v) for v, ell in zip(iv, self._ell)] for cp in itertools.product(*[p[i] for i in range(self._level)]): yield self._element_constructor_(cp) diff --git a/src/sage/combinat/path_tableaux/all.py b/src/sage/combinat/path_tableaux/all.py index 089fcc6f11b..7bed7f138a5 100644 --- a/src/sage/combinat/path_tableaux/all.py +++ b/src/sage/combinat/path_tableaux/all.py @@ -6,7 +6,9 @@ - :ref:`sage.combinat.path_tableaux.frieze` - :ref:`sage.combinat.path_tableaux.semistandard` """ + # install the docstring of this module to the containing package from sage.misc.namespace_package import install_doc + install_doc(__package__, __doc__) del install_doc diff --git a/src/sage/combinat/path_tableaux/catalog.py b/src/sage/combinat/path_tableaux/catalog.py index 317fcc200bb..6d8fa0618ea 100644 --- a/src/sage/combinat/path_tableaux/catalog.py +++ b/src/sage/combinat/path_tableaux/catalog.py @@ -22,7 +22,7 @@ lazy_import('sage.combinat.path_tableaux.path_tableau', ['CylindricalDiagram']) lazy_import('sage.combinat.path_tableaux.dyck_path', ['DyckPath', 'DyckPaths']) -lazy_import('sage.combinat.path_tableaux.frieze', ['FriezePattern','FriezePatterns']) -lazy_import('sage.combinat.path_tableaux.semistandard', ['SemistandardPathTableau','SemistandardPathTableaux']) +lazy_import('sage.combinat.path_tableaux.frieze', ['FriezePattern', 'FriezePatterns']) +lazy_import('sage.combinat.path_tableaux.semistandard', ['SemistandardPathTableau', 'SemistandardPathTableaux']) del lazy_import diff --git a/src/sage/combinat/path_tableaux/dyck_path.py b/src/sage/combinat/path_tableaux/dyck_path.py index 0fb049be8a8..e38cbf477f0 100644 --- a/src/sage/combinat/path_tableaux/dyck_path.py +++ b/src/sage/combinat/path_tableaux/dyck_path.py @@ -17,7 +17,7 @@ - Bruce Westbury (2018): initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2018 Bruce Westbury , # # This program is free software: you can redistribute it and/or modify @@ -89,6 +89,7 @@ class DyckPath(PathTableau): sage: t.to_perfect_matching() [(0, 5), (1, 4), (2, 3)] """ + @staticmethod def __classcall_private__(cls, ot): r""" @@ -151,9 +152,9 @@ def __init__(self, parent, ot, check=True): elif isinstance(ot, PerfectMatching): if ot.is_noncrossing(): - u = [1]*ot.size() + u = [1] * ot.size() for a in ot.arcs(): - u[a[1]-1] = 0 + u[a[1] - 1] = 0 w = DyckWord(u).heights() else: raise ValueError("the perfect matching must be non crossing") @@ -164,7 +165,7 @@ def __init__(self, parent, ot, check=True): if ot.is_standard(): u = [1] * ot.size() for i in ot[1]: - u[i-1] = 0 + u[i - 1] = 0 w = DyckWord(u).heights() else: raise ValueError("the tableau must be standard") @@ -174,8 +175,8 @@ def __init__(self, parent, ot, check=True): raise ValueError("the skew tableau must have at most two rows") # The check that ot is standard is not implemented c = ot.to_chain() - w = [0]*len(c) - for i,a in enumerate(c): + w = [0] * len(c) + for i, a in enumerate(c): if len(a) == 1: w[i] = a[0] else: @@ -241,17 +242,18 @@ def local_rule(self, i): ... ValueError: 6 is not a valid integer """ + def _rule(x): """ This is the rule on a sequence of three letters. """ - return abs(x[0]-x[1]+x[2]) + return abs(x[0] - x[1] + x[2]) - if not (i > 0 and i < len(self)-1): + if not (i > 0 and i < len(self) - 1): raise ValueError("%d is not a valid integer" % i) with self.clone() as result: - result[i] = _rule(self[i-1:i+2]) + result[i] = _rule(self[i - 1 : i + 2]) return result @@ -293,8 +295,8 @@ def descents(self): """ result = set() - for i in range(1,len(self)-1): - if self[i] < self[i-1] and self[i] < self[i+1]: + for i in range(1, len(self) - 1): + if self[i] < self[i - 1] and self[i] < self[i + 1]: result.add(i) return result @@ -308,7 +310,7 @@ def to_word(self): sage: path_tableaux.DyckPath([1,0,1,2,1]).to_word() [0, 1, 1, 0] """ - return [(self[i+1] - self[i] + 1) // 2 for i in range(self.size()-1)] + return [(self[i + 1] - self[i] + 1) // 2 for i in range(self.size() - 1)] def to_perfect_matching(self): r""" @@ -355,7 +357,7 @@ def to_tableau(self): top = [i + 1 for i, a in enumerate(w) if a == 1] bot = [i + 1 for i, a in enumerate(w) if a == 0] if self.is_skew(): - return SkewTableau([[None]*self[0]+top, bot]) + return SkewTableau([[None] * self[0] + top, bot]) return StandardTableau([top, bot]) @@ -373,6 +375,6 @@ def _an_element_(self): sage: path_tableaux.DyckPaths()._an_element_() [0, 1, 2, 1, 0] """ - return DyckPath([0,1,2,1,0]) + return DyckPath([0, 1, 2, 1, 0]) Element = DyckPath diff --git a/src/sage/combinat/path_tableaux/frieze.py b/src/sage/combinat/path_tableaux/frieze.py index f584c346672..41b19a77a8c 100644 --- a/src/sage/combinat/path_tableaux/frieze.py +++ b/src/sage/combinat/path_tableaux/frieze.py @@ -10,6 +10,7 @@ - Bruce Westbury (2019): initial version """ + # **************************************************************************** # Copyright (C) 2019 Bruce Westbury , # @@ -117,6 +118,7 @@ class FriezePattern(PathTableau, metaclass=InheritComparisonClasscallMetaclass): [ , , , , , , , , , , 0, 1, sqrt2, 1, sqrt2, 3, 2*sqrt2, 5, 3*sqrt2, 1, 0] sage: TestSuite(t).run() """ + @staticmethod def __classcall_private__(cls, fp, field=QQ): r""" @@ -208,6 +210,7 @@ def local_rule(self, i): ... ValueError: 0 is not a valid integer """ + def _rule(x): """ This is the rule on a sequence of three scalars. @@ -218,7 +221,7 @@ def _rule(x): raise ValueError(f"{i} is not a valid integer") with self.clone() as result: - result[i] = _rule(self[i-1:i+2]) + result[i] = _rule(self[i - 1 : i + 2]) return result @@ -298,8 +301,7 @@ def is_integral(self): """ n = len(self) cd = CylindricalDiagram(self).diagram - return all(k in ZZ for i, a in enumerate(cd) - for k in a[i + 1:n + i - 2]) + return all(k in ZZ for i, a in enumerate(cd) for k in a[i + 1 : n + i - 2]) def triangulation(self): r""" @@ -328,20 +330,20 @@ def triangulation(self): ....: field=K).triangulation() Graphics object consisting of 24 graphics primitives """ - n = len(self)-1 + n = len(self) - 1 cd = CylindricalDiagram(self).diagram from sage.plot.plot import Graphics from sage.plot.line import line from sage.plot.text import text from sage.functions.trig import sin, cos from sage.symbolic.constants import pi + G = Graphics() G.set_aspect_ratio(1.0) - vt = [(cos(2*theta*pi/(n)), sin(2*theta*pi/(n))) - for theta in range(n+1)] + vt = [(cos(2 * theta * pi / (n)), sin(2 * theta * pi / (n))) for theta in range(n + 1)] for i, p in enumerate(vt): - G += text(str(i), [1.05*p[0], 1.05*p[1]]) + G += text(str(i), [1.05 * p[0], 1.05 * p[1]]) for i, r in enumerate(cd): for j, a in enumerate(r[:n]): @@ -392,11 +394,12 @@ def plot(self, model='UHP'): """ from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane from sage.plot.plot import Graphics + models = { - 'UHP': HyperbolicPlane().UHP(), - 'PD': HyperbolicPlane().PD(), - 'KM': HyperbolicPlane().KM(), - } + 'UHP': HyperbolicPlane().UHP(), + 'PD': HyperbolicPlane().PD(), + 'KM': HyperbolicPlane().KM(), + } if model not in models: raise ValueError(f"{model} must be one of ``UHP``, ``PD``, ``KM``") M = models[model] @@ -405,8 +408,8 @@ def plot(self, model='UHP'): cd = CylindricalDiagram(self).diagram num = cd[0][:-1] den = cd[1][2:] - vt = [M(U.get_point(x / (x+y))) for x, y in zip(num, den)] - gd = [M.get_geodesic(vt[i-1], vt[i]) for i in range(len(vt))] + vt = [M(U.get_point(x / (x + y))) for x, y in zip(num, den)] + gd = [M.get_geodesic(vt[i - 1], vt[i]) for i in range(len(vt))] return sum([a.plot() for a in gd], Graphics()).plot() def change_ring(self, R): diff --git a/src/sage/combinat/path_tableaux/path_tableau.py b/src/sage/combinat/path_tableaux/path_tableau.py index ec462a266d0..a11c0257913 100644 --- a/src/sage/combinat/path_tableaux/path_tableau.py +++ b/src/sage/combinat/path_tableaux/path_tableau.py @@ -39,18 +39,21 @@ from sage.categories.sets_cat import Sets from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent -#from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_graded + +# from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet_graded from sage.structure.sage_object import SageObject from sage.structure.list_clone import ClonableArray from sage.misc.latex import latex -#from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets -#from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets + +# from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets +# from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets class PathTableau(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): r""" This is the abstract base class for a path tableau. """ + @abstract_method def local_rule(self, i): r""" @@ -119,7 +122,7 @@ def promotion(self): [0, 1, 2, 1, 0, 1, 0] """ with self.clone() as result: - for i in range(1,self.size()-1): + for i in range(1, self.size() - 1): result = result.local_rule(i) return result @@ -202,19 +205,19 @@ def commutor(self, other, verbose=False): row = list(other) col = list(self) if col[-1] != row[0]: - raise ValueError("%s, %s is not a composable pair" % (self,other)) + raise ValueError("%s, %s is not a composable pair" % (self, other)) path = P(col + row[1:]) - for i in range(1,n): + for i in range(1, n): if verbose: - print(path[n-i:n+m-i]) - for j in range(m-1): - path = path.local_rule(n+j-i) + print(path[n - i : n + m - i]) + for j in range(m - 1): + path = path.local_rule(n + j - i) if verbose: print(path[:m]) - return (P(path[:m]), P(path[m-1:])) + return (P(path[:m]), P(path[m - 1 :])) def cactus(self, i, j): r""" @@ -265,7 +268,7 @@ def cactus(self, i, j): L = list(T.evacuation()) + t return self.parent()(L) - return self.cactus(1,j).cactus(1,j-i+1).cactus(1,j) + return self.cactus(1, j).cactus(1, j - i + 1).cactus(1, j) ########################### Visualisation and checking #################### @@ -279,8 +282,8 @@ def _test_involution_rule(self, **options): sage: t._test_involution_rule() """ tester = self._tester(**options) - for i in range(self.size()-2): - tester.assertEqual(self.local_rule(i+1).local_rule(i + 1), self) + for i in range(self.size() - 2): + tester.assertEqual(self.local_rule(i + 1).local_rule(i + 1), self) def _test_involution_cactus(self, **options): """ @@ -292,8 +295,8 @@ def _test_involution_cactus(self, **options): sage: t._test_involution_cactus() """ tester = self._tester(**options) - for i in range(2, self.size()+1): - tester.assertEqual(self.cactus(1,i).cactus(1,i), self) + for i in range(2, self.size() + 1): + tester.assertEqual(self.cactus(1, i).cactus(1, i), self) def _test_promotion(self, **options): """ @@ -306,7 +309,7 @@ def _test_promotion(self, **options): """ tester = self._tester(**options) n = self.size() - tester.assertEqual(self.cactus(1,n-1).cactus(1,n).promotion(), self) + tester.assertEqual(self.cactus(1, n - 1).cactus(1, n).promotion(), self) def _test_commutation(self, **options): """ @@ -318,12 +321,13 @@ def _test_commutation(self, **options): sage: t._test_commutation() """ from itertools import combinations + tester = self._tester(**options) n = self.size() if n < 5: return - for i,j,r,s in combinations(range(1,n+1), 4): + for i, j, r, s in combinations(range(1, n + 1), 4): lhs = self.cactus(i, j).cactus(r, s) rhs = self.cactus(r, s).cactus(i, j) tester.assertEqual(lhs, rhs) @@ -338,14 +342,15 @@ def _test_coboundary(self, **options): sage: t._test_coboundary() """ from itertools import combinations + tester = self._tester(**options) n = self.size() if n < 4: return - for i,j,r,s in combinations(range(1,n+3), 4): - lhs = self.cactus(i, s-2).cactus(j-1, r-1) - rhs = self.cactus(i+s-r-1, i+s-j-1).cactus(i, s-2) + for i, j, r, s in combinations(range(1, n + 3), 4): + lhs = self.cactus(i, s - 2).cactus(j - 1, r - 1) + rhs = self.cactus(i + s - r - 1, i + s - j - 1).cactus(i, s - 2) tester.assertEqual(lhs, rhs) def orbit(self): @@ -423,14 +428,14 @@ def dual_equivalence_graph(self): orb = self.orbit() for a in orb: - for i,j in combinations(range(1,self.size()+1),2): - b = a.cactus(i,j) + for i, j in combinations(range(1, self.size() + 1), 2): + b = a.cactus(i, j) if a != b: - G.add_edge(a,b,"%d,%d" % (i,j)) + G.add_edge(a, b, "%d,%d" % (i, j)) return G -class PathTableaux(UniqueRepresentation,Parent): +class PathTableaux(UniqueRepresentation, Parent): """ The abstract parent class for PathTableau. """ @@ -498,9 +503,9 @@ def __init__(self, T): if not isinstance(T, PathTableau): raise ValueError('{0} must be a path tableau'.format(str(T))) n = len(T) - result = [[None]*(2*n-1)] * n + result = [[None] * (2 * n - 1)] * n for i in range(n): - result[i] = [""]*i + list(T) + result[i] = [""] * i + list(T) T = T.promotion() self.path_tableau = T @@ -537,8 +542,7 @@ def _repr_(self): if not data[0]: data[0] = [''] # Put sometime there max_width = max(max(len(x) for x in row) for row in data if row) - return '\n'.join('[' + ', '.join(' '*(max_width-len(x)) + x for x in row) - + ']' for row in data) + return '\n'.join('[' + ', '.join(' ' * (max_width - len(x)) + x for x in row) + ']' for row in data) def __eq__(self, other): """ @@ -606,7 +610,7 @@ def _latex_(self): """ D = self.diagram m = len(D[-1]) - result = "\\begin{array}{"+"c"*m + "}\n" + result = "\\begin{array}{" + "c" * m + "}\n" result += "\\\\ \n".join(" & ".join(latex(a) for a in x) for x in D) result += "\n \\end{array}\n" return result @@ -651,12 +655,12 @@ def _ascii_art_(self): """ from sage.typeset.ascii_art import ascii_art from sage.misc.misc_c import prod + data = [[ascii_art(x) for x in row] for row in self.diagram] if not data[0]: data[0] = [ascii_art('')] # Put sometime there max_width = max(max(len(x) for x in row) for row in data if row) - return prod((sum((ascii_art(' '*(max_width-len(x)+1)) + x for x in row), ascii_art('')) - for row in data), ascii_art('')) + return prod((sum((ascii_art(' ' * (max_width - len(x) + 1)) + x for x in row), ascii_art('')) for row in data), ascii_art('')) def _unicode_art_(self): r""" @@ -686,12 +690,12 @@ def _unicode_art_(self): """ from sage.typeset.unicode_art import unicode_art from sage.misc.misc_c import prod + data = [[unicode_art(x) for x in row] for row in self.diagram] if not data[0]: data[0] = [unicode_art('')] # Put sometime there max_width = max(max(len(x) for x in row) for row in data if row) - return prod((sum((unicode_art(' '*(max_width-len(x)+1)) + x for x in row), unicode_art('')) - for row in data), unicode_art('')) + return prod((sum((unicode_art(' ' * (max_width - len(x) + 1)) + x for x in row), unicode_art('')) for row in data), unicode_art('')) def pp(self): r""" @@ -723,5 +727,4 @@ def pp(self): if not data[0]: data[0] = [''] # Put sometime there max_width = max(max(len(x) for x in row) for row in data if row) - print('\n'.join(' '.join(' '*(max_width-len(x)) + x for x in row) - for row in data)) + print('\n'.join(' '.join(' ' * (max_width - len(x)) + x for x in row) for row in data)) diff --git a/src/sage/combinat/path_tableaux/semistandard.py b/src/sage/combinat/path_tableaux/semistandard.py index 8fdaaa50e63..d4ea600b131 100644 --- a/src/sage/combinat/path_tableaux/semistandard.py +++ b/src/sage/combinat/path_tableaux/semistandard.py @@ -73,7 +73,7 @@ - Bruce Westbury (2020): initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2020 Bruce Westbury , # # This program is free software: you can redistribute it and/or modify @@ -174,11 +174,11 @@ def __init__(self, parent, st, check=True): w.reverse() w = [(), *w] - elif isinstance(st, (Tableau,SkewTableau)): + elif isinstance(st, (Tableau, SkewTableau)): w = st.to_chain() - elif isinstance(st, (list,tuple)): - if any(not isinstance(a,(list,tuple)) for a in st): + elif isinstance(st, (list, tuple)): + if any(not isinstance(a, (list, tuple)) for a in st): raise ValueError(f"{st} is not a sequence of lists") w = st @@ -186,8 +186,8 @@ def __init__(self, parent, st, check=True): raise ValueError(f"invalid input {st} is of type {type(st)}") # Pad with zeroes, if necessary - m = max(len(a)-i for i,a in enumerate(w)) - w = [list(a)+[0]*(m+i-len(a)) for i,a in enumerate(w)] + m = max(len(a) - i for i, a in enumerate(w)) + w = [list(a) + [0] * (m + i - len(a)) for i, a in enumerate(w)] # Convert to immutable w = tuple([tuple(a) for a in w]) @@ -222,10 +222,10 @@ def check(self): sage: path_tableaux.SemistandardPathTableau([[], [2], [1,2]], check=False) [(), (2,), (1, 2)] """ - for i in range(1,len(self)-1): - if not all(r >= s for r,s in zip(self[i+1],self[i])): + for i in range(1, len(self) - 1): + if not all(r >= s for r, s in zip(self[i + 1], self[i])): raise ValueError(f"{self} does not satisfy the required inequalities in row {i}") - if not all(r >= s for r,s in zip(self[i],self[i+1][1:])): + if not all(r >= s for r, s in zip(self[i], self[i + 1][1:])): raise ValueError(f"{self} does not satisfy the required inequalities in row {i}") def size(self): @@ -299,27 +299,28 @@ def local_rule(self, i): ... ValueError: 4 is not defined on [(), (3,), (3, 2), (3, 3, 1), (3, 3, 2, 1)] """ + def toggle(i, j): """ Return the toggle of entry 'self[i][j]'. """ if j == 0: - left = self[i+1][0] + left = self[i + 1][0] else: - left = min(self[i+1][j], self[i-1][j-1]) - if j == len(self[i])-1: - right = self[i+1][j+1] + left = min(self[i + 1][j], self[i - 1][j - 1]) + if j == len(self[i]) - 1: + right = self[i + 1][j + 1] else: - right = max(self[i+1][j+1], self[i-1][j]) + right = max(self[i + 1][j + 1], self[i - 1][j]) return left + right - self[i][j] - if not 0 < i < self.size()-1: + if not 0 < i < self.size() - 1: raise ValueError(f"{i} is not defined on {self}") with self.clone() as result: - result[i] = tuple([toggle(i,k) for k in range(len(self[i]))]) + result[i] = tuple([toggle(i, k) for k in range(len(self[i]))]) return result @@ -382,10 +383,10 @@ def rectify(self, inner=None, verbose=False): rect = [self] for i in range(r): - for j in range(n-1): - path = path.local_rule(r+j-i) + for j in range(n - 1): + path = path.local_rule(r + j - i) if verbose: - rect.append(P.element_class(P, list(path)[r-i-1:r+n-i-1])) + rect.append(P.element_class(P, list(path)[r - i - 1 : r + n - i - 1])) if verbose: return rect @@ -484,8 +485,8 @@ def _test_jdt_promotion(self, **options): tester = self._tester(**options) LHS = self.promotion().to_tableau() - RHS = self.to_tableau().promotion_inverse(len(self)-2) - tester.assertEqual(LHS,RHS) + RHS = self.to_tableau().promotion_inverse(len(self) - 2) + tester.assertEqual(LHS, RHS) class SemistandardPathTableaux(PathTableaux): @@ -502,6 +503,6 @@ def _an_element_(self): sage: path_tableaux.SemistandardPathTableaux()._an_element_() [(), (2,), (2, 1)] """ - return SemistandardPathTableau([[], [2], [2,1]]) + return SemistandardPathTableau([[], [2], [2, 1]]) Element = SemistandardPathTableau diff --git a/src/sage/combinat/perfect_matching.py b/src/sage/combinat/perfect_matching.py index 1e38937b656..04292070fbf 100644 --- a/src/sage/combinat/perfect_matching.py +++ b/src/sage/combinat/perfect_matching.py @@ -1,4 +1,3 @@ - r""" Perfect matchings @@ -33,6 +32,7 @@ sage: PerfectMatchings(4).list() [[(1, 2), (3, 4)], [(1, 3), (2, 4)], [(1, 4), (2, 3)]] """ + # **************************************************************************** # Copyright (C) 2010 Valentin Feray # @@ -91,6 +91,7 @@ class PerfectMatching(SetPartition): sage: m.parent() Perfect matchings of {} """ + @staticmethod def __classcall_private__(cls, parts): """ @@ -153,13 +154,10 @@ def __classcall_private__(cls, parts): ValueError: permutation p (= [4, 2, 1, 3]) is not a fixed point free involution """ - if ((isinstance(parts, list) and - all(isinstance(x, (int, Integer)) for x in parts)) - or isinstance(parts, Permutation)): + if (isinstance(parts, list) and all(isinstance(x, (int, Integer)) for x in parts)) or isinstance(parts, Permutation): s = Permutation(parts) if not all(e == 2 for e in s.cycle_type()): - raise ValueError("permutation p (= {}) is not a " - "fixed point free involution".format(s)) + raise ValueError("permutation p (= {}) is not a " "fixed point free involution".format(s)) parts = s.to_cycles() base_set = frozenset(e for p in parts for e in p) @@ -403,9 +401,7 @@ def loop_type(self, other=None): sage: m = PerfectMatching([]); m.loop_type() [] """ - return Partition(sorted((len(l) // 2 - for l in self.loops_iterator(other)), - reverse=True)) + return Partition(sorted((len(l) // 2 for l in self.loops_iterator(other)), reverse=True)) def number_of_loops(self, other=None): r""" @@ -472,6 +468,7 @@ def to_graph(self): [] """ from sage.graphs.graph import Graph + return Graph([list(p) for p in self], format='list_of_edges') def to_noncrossing_set_partition(self): @@ -497,8 +494,7 @@ def to_noncrossing_set_partition(self): raise ValueError("matching must be non-crossing") else: perm = self.to_permutation() - perm2 = Permutation([perm[2 * i] // 2 - for i in range(len(perm) // 2)]) + perm2 = Permutation([perm[2 * i] // 2 for i in range(len(perm) // 2)]) return SetPartition(perm2.cycle_tuples()) @@ -569,6 +565,7 @@ class PerfectMatchings(SetPartitions_set): sage: S([]) [] """ + @staticmethod def __classcall_private__(cls, s): """ @@ -618,8 +615,7 @@ def __iter__(self): # The iterator from fixed-point-free involutions has the resulting # list of pairs sorted by their minimal element. for val in perfect_matchings_iterator(len(s) // 2): - yield self.element_class(self, ((s[a], s[b]) for a, b in val), - check=False, sort=False) + yield self.element_class(self, ((s[a], s[b]) for a, b in val), check=False, sort=False) def __contains__(self, x): """ @@ -735,9 +731,7 @@ def random_element(self): k = n // 2 p = Permutations(n).random_element() l = list(self._set) - return self.element_class(self, [(l[p[2 * i] - 1], l[p[2 * i + 1] - 1]) - for i in range(k)], - check=False) + return self.element_class(self, [(l[p[2 * i] - 1], l[p[2 * i + 1] - 1]) for i in range(k)], check=False) @cached_method def Weingarten_matrix(self, N): @@ -756,8 +750,7 @@ def Weingarten_matrix(self, N): [ -1 N + 1 -1] [ -1 -1 N + 1] """ - G = matrix([[N**(p1.number_of_loops(p2)) for p1 in self] - for p2 in self]) - return G**(-1) + G = matrix([[N ** (p1.number_of_loops(p2)) for p1 in self] for p2 in self]) + return G ** (-1) Element = PerfectMatching diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index d0d4e3e00a9..2ede47d88f7 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -254,9 +254,7 @@ from sage.combinat.combinat import CombinatorialElement, catalan_number from sage.combinat.combinatorial_map import combinatorial_map from sage.combinat.composition import Composition -from sage.combinat.permutation_cython import (left_action_product, right_action_product, - left_action_same_n, right_action_same_n, - map_to_list, next_perm) +from sage.combinat.permutation_cython import left_action_product, right_action_product, left_action_same_n, right_action_same_n, map_to_list, next_perm from sage.combinat.tools import transitive_ideal from sage.misc.cachefunc import cached_method from sage.misc.decorators import rename_keyword @@ -476,6 +474,7 @@ class Permutation(CombinatorialElement): sage: Permutation( [[], []] ) # needs sage.combinat [] """ + @staticmethod @rename_keyword(deprecation=35233, check_input='check') def __classcall_private__(cls, l, algorithm='lex', sjt=None, check=True): @@ -504,17 +503,14 @@ def __classcall_private__(cls, l, algorithm='lex', sjt=None, check=True): return from_cycles(max(max(c) for c in cycle_list), cycle_list) # if l is a pair of standard tableaux or a pair of lists - elif isinstance(l, (tuple, list)) and len(l) == 2 and \ - all(isinstance(x, Tableau) for x in l): + elif isinstance(l, (tuple, list)) and len(l) == 2 and all(isinstance(x, Tableau) for x in l): return RSK_inverse(*l, output='permutation') - elif isinstance(l, (tuple, list)) and len(l) == 2 and \ - all(isinstance(x, list) for x in l): + elif isinstance(l, (tuple, list)) and len(l) == 2 and all(isinstance(x, list) for x in l): P, Q = (Tableau(_) for _ in l) return RSK_inverse(P, Q, 'permutation') # if it's a tuple or nonempty list of tuples, also assume cycle # notation - elif isinstance(l, tuple) or (isinstance(l, list) and l and - all(isinstance(x, tuple) for x in l)): + elif isinstance(l, tuple) or (isinstance(l, list) and l and all(isinstance(x, tuple) for x in l)): if l and (isinstance(l[0], (int, Integer)) or len(l[0]) > 0): if isinstance(l[0], tuple): n = max(max(x) for x in l) @@ -593,8 +589,7 @@ def __init__(self, parent, l, algorithm='lex', sjt=None, check=True) -> None: self._algorithm = algorithm.lower() if self._algorithm != "lex" and self._algorithm != "sjt": - raise ValueError("unsupported algorithm %s; expected 'lex' or 'sjt'" - % self._algorithm) + raise ValueError("unsupported algorithm %s; expected 'lex' or 'sjt'" % self._algorithm) if check and l: # Make a copy to sort later @@ -607,19 +602,14 @@ def __init__(self, parent, l, algorithm='lex', sjt=None, check=True) -> None: except TypeError: raise ValueError("the elements must be integer variables") if i < 1: - raise ValueError("the elements must be strictly positive " - "integers") + raise ValueError("the elements must be strictly positive " "integers") lst.sort() # Is the maximum element of the permutation the length of input, # or is some integer missing ? if int(lst[-1]) != len(lst): - raise ValueError(f"the permutation has length {len(lst)} " + - f"but its maximal element is {int(lst[-1])}" + - ". Some element may be " + - "repeated, or an element is missing, but " + - "there is something wrong with its length.") + raise ValueError(f"the permutation has length {len(lst)} " + f"but its maximal element is {int(lst[-1])}" + ". Some element may be " + "repeated, or an element is missing, but " + "there is something wrong with its length.") # Do the elements appear only once ? previous = lst[0] - 1 @@ -649,7 +639,7 @@ def __setstate__(self, state): sage: loads(dumps( Permutation([3,2,1]) )) # indirect doctest [3, 2, 1] """ - if isinstance(state, dict): # for old pickles from Permutation_class + if isinstance(state, dict): # for old pickles from Permutation_class self._set_parent(Permutations()) self.__dict__ = state else: @@ -755,9 +745,7 @@ def _latex_(self) -> str: return self.parent().options.latex_empty_str return " ".join(f"{let}_{{{i}}}" for i in redword) if display == "twoline": - return r"\begin{{pmatrix}} {} \\ {} \end{{pmatrix}}".format( - " & ".join("%s" % i for i in range(1, len(self._list)+1)), - " & ".join("%s" % i for i in self._list)) + return r"\begin{{pmatrix}} {} \\ {} \end{{pmatrix}}".format(" & ".join("%s" % i for i in range(1, len(self._list) + 1)), " & ".join("%s" % i for i in self._list)) if display == "list": return repr(self._list) if display == "cycle": @@ -807,6 +795,7 @@ def order(self) -> Integer: [1, 2, 3, 4, 5] """ from sage.arith.functions import lcm + return lcm(self.cycle_type()) def cycle_string(self, singletons=False) -> str: @@ -829,7 +818,7 @@ def cycle_string(self, singletons=False) -> str: cycles = self.to_cycles(singletons=singletons) if not cycles: return "()" - return "".join("("+",".join(str(l) for l in x)+")" for x in cycles) + return "".join("(" + ",".join(str(l) for l in x) + ")" for x in cycles) def __next__(self): r""" @@ -913,8 +902,8 @@ def __next__(self): (p[j], p[first]) = (p[first], p[j]) # Reverse the list between first and the end - first_half = p[:first+1] - last_half = p[first+1:] + first_half = p[: first + 1] + last_half = p[first + 1 :] last_half.reverse() p = first_half + last_half @@ -962,8 +951,7 @@ def prev(self): algorithm. """ if self._algorithm == "sjt": - raise NotImplementedError("previous permutation for SJT algorithm " - "is not yet implemented") + raise NotImplementedError("previous permutation for SJT algorithm " "is not yet implemented") p = self[:] n = len(self) @@ -990,8 +978,8 @@ def prev(self): (p[j], p[first]) = (p[first], p[j]) # Reverse the list between first+1 and end - first_half = p[:first+1] - last_half = p[first+1:] + first_half = p[: first + 1] + last_half = p[first + 1 :] last_half.reverse() p = first_half + last_half @@ -1261,14 +1249,14 @@ def _to_cycles_list(self, singletons=True) -> list: while L: # take the first remaining element cycleFirst = L.pop(0) - next = p[cycleFirst-1] + next = p[cycleFirst - 1] cycle = [cycleFirst] while next != cycleFirst: cycle.append(next) # remove next from L # we use a binary search to find it L.pop(bisect_left(L, next)) - next = p[next-1] + next = p[next - 1] # add the cycle cycles.append(tuple(cycle)) @@ -1306,7 +1294,7 @@ def signature(self) -> Integer: sage: Permutation([]).sign() 1 """ - return Integer((-1)**(len(self) - len(self.to_cycles()))) + return Integer((-1) ** (len(self) - len(self.to_cycles()))) # one can also use sign as an alias for signature sign = signature @@ -1389,6 +1377,7 @@ def to_alternating_sign_matrix(self): Alternating sign matrices of size 3 """ from sage.combinat.alternating_sign_matrix import AlternatingSignMatrix + return AlternatingSignMatrix(self.to_matrix().rows()) def __mul__(self, rp): @@ -1569,8 +1558,7 @@ def rank(self) -> Integer: """ n = len(self) factoradic = self.to_lehmer_code() - return sum(factoradic[n - 1 - i] * factorial(i) - for i in reversed(range(n))) + return sum(factoradic[n - 1 - i] * factorial(i) for i in reversed(range(n))) ############## # Inversions # @@ -1708,6 +1696,7 @@ def _to_inversion_vector_divide_and_conquer(self) -> list: sage: p._to_inversion_vector_divide_and_conquer() [2, 3, 6, 4, 0, 2, 2, 1, 0] """ + # for big permutations, # we use a divide-and-conquer strategy # it's a merge sort, plus counting inversions @@ -1751,8 +1740,7 @@ def sort_and_countv(L): if len(L) < 250: return base_case(L) l = len(L) // 2 - return merge_and_countv(sort_and_countv(L[:l]), - sort_and_countv(L[l:])) + return merge_and_countv(sort_and_countv(L[:l]), sort_and_countv(L[l:])) return [Integer(a) for a in sort_and_countv(self._list)[0]] @@ -1770,8 +1758,7 @@ def inversions(self) -> list: """ p = self[:] n = len(p) - return [(i+1, j+1) for i in range(n-1) for j in range(i+1, n) - if p[i] > p[j]] + return [(i + 1, j + 1) for i in range(n - 1) for j in range(i + 1, n) if p[i] > p[j]] def stack_sort(self) -> Permutation: """ @@ -1837,8 +1824,7 @@ def to_digraph(self) -> DiGraph: sage: d.edges(sort=True, labels=False) # needs sage.graphs [(1, 1)] """ - return DiGraph([self, enumerate(self, start=1)], - format='vertices_and_edges', loops=True) + return DiGraph([self, enumerate(self, start=1)], format='vertices_and_edges', loops=True) def show(self, representation='cycles', orientation='landscape', **args): r""" @@ -1896,21 +1882,19 @@ def show(self, representation='cycles', orientation='landscape', **args): elif orientation == "portrait": r = lambda x, y: (-y, x) else: - raise ValueError("The value of 'orientation' must be either " + - "'landscape' or 'portrait'.") + raise ValueError("The value of 'orientation' must be either " + "'landscape' or 'portrait'.") p = self[:] L = line([r(1, 1)]) for i in range(len(p)): L += line([r(i, 1.0), r(p[i] - 1, 0)]) - L += text(str(i), r(i, 1.05)) + text(str(i), r(p[i]-1, -.05)) + L += text(str(i), r(i, 1.05)) + text(str(i), r(p[i] - 1, -0.05)) return L.show(axes=False, **args) else: - raise ValueError("The value of 'representation' must be equal to " + - "'cycles', 'chord-diagram' or 'braid'") + raise ValueError("The value of 'representation' must be equal to " + "'cycles', 'chord-diagram' or 'braid'") def number_of_inversions(self) -> Integer: r""" @@ -1967,8 +1951,7 @@ def noninversions(self, k) -> list[list]: """ if k > len(self): return [] - return [list(pos) for pos in itertools.combinations(self, k) - if all(pos[i] < pos[i + 1] for i in range(k - 1))] + return [list(pos) for pos in itertools.combinations(self, k) if all(pos[i] < pos[i + 1] for i in range(k - 1))] def number_of_noninversions(self, k) -> Integer: r""" @@ -2024,8 +2007,7 @@ def number_of_noninversions(self, k) -> Integer: """ if k > len(self): return 0 - return Integer(sum(1 for pos in itertools.combinations(self, k) - if all(pos[i] < pos[i + 1] for i in range(k - 1)))) + return Integer(sum(1 for pos in itertools.combinations(self, k) if all(pos[i] < pos[i + 1] for i in range(k - 1)))) def length(self) -> Integer: r""" @@ -2173,7 +2155,7 @@ def ishift(self, i): state, pos_im1, pos_i, pos_ip1 = full_state l = list(self) - if state == '213': # goes to 132 + if state == '213': # goes to 132 l[pos_i] = i - 1 l[pos_im1] = i + 1 l[pos_ip1] = i @@ -2236,7 +2218,7 @@ def iswitch(self, i): state, pos_im1, pos_i, pos_ip1 = full_state l = list(self) - if state == '213': # goes to 312 + if state == '213': # goes to 312 l[pos_i] = i + 1 l[pos_ip1] = i elif state == '132': # goes to 231 @@ -2366,6 +2348,7 @@ def longest_increasing_subsequence_length(self) -> Integer: 0 """ from bisect import bisect + r: list[int] = [] for x in self._list: # Search for the smallest value y larger than x @@ -2426,7 +2409,7 @@ def longest_increasing_subsequences(self) -> list: first_row_p_tableau[j] = x insort(columns[j], x) if j: - for k in columns[j-1]: + for k in columns[j - 1]: if k > x: break D.add_edge(k, x) @@ -2485,7 +2468,7 @@ def number_of_longest_increasing_subsequences(self): if j == 0: count[x] = 1 else: - for k in columns[j-1]: + for k in columns[j - 1]: if k > x: break count[x] += count[k] @@ -2508,6 +2491,7 @@ def cycle_type(self): cycle_type = [len(c) for c in self.to_cycles()] cycle_type.sort(reverse=True) from sage.combinat.partition import Partition + return Partition(cycle_type) @combinatorial_map(name='forget cycles') @@ -2670,11 +2654,11 @@ def foata_bijection(self) -> Permutation: index_list = [-1] + [i for i, val in enumerate(M) if val < e] for j in range(1, len(index_list)): - start = index_list[j-1] + 1 + start = index_list[j - 1] + 1 end = index_list[j] M_prime[start] = M[end] for x in range(start + 1, end + 1): - M_prime[x] = M[x-1] + M_prime[x] = M[x - 1] M_prime[k] = e M = M_prime return Permutations()(M) @@ -2724,11 +2708,11 @@ def foata_bijection_inverse(self) -> Permutation: index_list.append(k) for j in range(1, len(index_list)): - start = index_list[j-1] + start = index_list[j - 1] end = index_list[j] - 1 L_prime[end] = L[start] for x in range(start, end): - L_prime[x] = L[x+1] + L_prime[x] = L[x + 1] L = L_prime return Permutations()(reversed(Mrev)) @@ -2919,20 +2903,21 @@ def destandardize(self, weight, ordered_alphabet=None): ides = self.idescents() partial = [0] for a in weight: - partial.append(partial[-1]+a) + partial.append(partial[-1] + a) if not set(ides).issubset(set(partial)): raise ValueError(f"Standardization with weight {weight} is not possible!") if ordered_alphabet is None: - ordered_alphabet = list(range(1, len(weight)+1)) + ordered_alphabet = list(range(1, len(weight) + 1)) else: if len(weight) > len(ordered_alphabet): raise ValueError("Not enough letters in the alphabet are specified compared to the weight") q = self.inverse() s = [0] * len(self) - for i in range(len(partial)-1): - for j in range(partial[i], partial[i+1]): - s[q[j]-1] = ordered_alphabet[i] + for i in range(len(partial) - 1): + for j in range(partial[i], partial[i + 1]): + s[q[j] - 1] = ordered_alphabet[i] from sage.combinat.words.word import Word + return Word(s) def to_lehmer_code(self) -> list: @@ -3064,9 +3049,10 @@ def reduced_words_iterator(self) -> Iterator: sage: next(Permutation([5,2,3,4,1]).reduced_words_iterator()) [1, 2, 3, 4, 3, 2, 1] """ + def aux(p): is_identity = True - for d in range(len(p)-1): + for d in range(len(p) - 1): e = d + 1 if p[d] > p[e]: is_identity = False @@ -3192,6 +3178,7 @@ def rothe_diagram(self): . . . . """ from sage.combinat.diagram import RotheDiagram + return RotheDiagram(self) def rank_matrix(self): @@ -3224,12 +3211,12 @@ def rank_matrix(self): ret = self.to_matrix() n = ret.nrows() for j in range(1, n): - ret[0, j] += ret[0, j-1] + ret[0, j] += ret[0, j - 1] for i in range(1, n): - ret[i, 0] += ret[i-1, 0] + ret[i, 0] += ret[i - 1, 0] for j in range(1, n): # Compute by inclusion-exclusion - ret[i, j] += ret[i-1, j] + ret[i, j-1] - ret[i-1, j-1] + ret[i, j] += ret[i - 1, j] + ret[i, j - 1] - ret[i - 1, j - 1] return ret def schubert_determinant_ideal(self): @@ -3278,15 +3265,16 @@ def schubert_determinant_ideal(self): """ from sage.rings.rational_field import QQ from sage.matrix.constructor import matrix + n = len(self) PR = PolynomialRing(QQ, n, var_array='z') z = PR.gens() - Z = matrix(PR, [[z[r*n+c] for c in range(n)] for r in range(n)]) + Z = matrix(PR, [[z[r * n + c] for c in range(n)] for r in range(n)]) rk = self.rank_matrix() gens = [] for i, j in self.rothe_diagram().essential_set(): # we apply the transpose to the rank matrix to match conventions - gens.extend(Z.submatrix(0, 0, i+1, j+1).minors(rk[j, i] + 1)) + gens.extend(Z.submatrix(0, 0, i + 1, j + 1).minors(rk[j, i] + 1)) return PR.ideal(gens) ################ @@ -3426,8 +3414,7 @@ def recoils(self) -> list[int]: sage: Permutation([]).recoils() [] """ - return [i for i, pi in enumerate(self) - if pi != len(self) and self.index(pi + 1) < i] + return [i for i, pi in enumerate(self) if pi != len(self) and self.index(pi + 1) < i] def number_of_recoils(self) -> Integer: r""" @@ -3462,8 +3449,7 @@ def recoils_composition(self) -> Composition: # Descents # ############ - def descents(self, final_descent=False, side='right', positive=False, - from_zero=False, index_set=None) -> list[int]: + def descents(self, final_descent=False, side='right', positive=False, from_zero=False, index_set=None) -> list[int]: r""" Return the list of the descents of ``self``. @@ -3523,7 +3509,7 @@ def descents(self, final_descent=False, side='right', positive=False, p = self.inverse() descents = [] for i in index_set: - if p[i-1] > p[i]: + if p[i - 1] > p[i]: if not positive: descents.append(i) else: @@ -3572,8 +3558,7 @@ def idescents(self, final_descent=False, from_zero=False) -> list[int]: sage: Permutation([1,4,3,2]).idescents(from_zero=True) [1, 2] """ - return self.inverse().descents(final_descent=final_descent, - from_zero=from_zero) + return self.inverse().descents(final_descent=final_descent, from_zero=from_zero) def idescents_signature(self, final_descent=False): """ @@ -3756,12 +3741,13 @@ def multi_major_index(self, composition): partial_sum = [0] + composition.partial_sums() multimajor_index = [] for j in range(1, len(partial_sum)): - a = partial_sum[j-1] + a = partial_sum[j - 1] b = partial_sum[j] from bisect import bisect_right, bisect_left + start = bisect_right(descents, a) end = bisect_left(descents, b) - multimajor_index.append(sum(descents[start: end])-(end-start)*a) + multimajor_index.append(sum(descents[start:end]) - (end - start) * a) return multimajor_index def imajor_index(self, final_descent=False) -> Integer: @@ -3852,8 +3838,7 @@ def peaks(self) -> list[int]: [] """ p = self - return [i for i in range(1, len(p) - 1) - if p[i - 1] <= p[i] and p[i] > p[i + 1]] + return [i for i in range(1, len(p) - 1) if p[i - 1] <= p[i] and p[i] > p[i + 1]] def number_of_peaks(self) -> int: r""" @@ -3977,7 +3962,7 @@ def bruhat_lequal(self, p2) -> bool: if n1 == 0: return True - if p1[0] > p2[0] or p1[n1-1] < p2[n1-1]: + if p1[0] > p2[0] or p1[n1 - 1] < p2[n1 - 1]: return False for i in range(1, n1): @@ -4091,7 +4076,7 @@ def bruhat_succ_iterator(self): n = len(p) P = Permutations() - for z in P([n+1-x for x in p]).bruhat_inversions_iterator(): + for z in P([n + 1 - x for x in p]).bruhat_inversions_iterator(): pp = p[:] pp[z[0]] = p[z[1]] pp[z[1]] = p[z[0]] @@ -4316,18 +4301,18 @@ def permutohedron_succ(self, side='right'): P = Permutations() succ = [] if side == "right": - rise = lambda perm: [i for i in range(n - 1) if perm[i] < perm[i+1]] + rise = lambda perm: [i for i in range(n - 1) if perm[i] < perm[i + 1]] for i in rise(p): pp = p[:] - pp[i] = p[i+1] - pp[i+1] = p[i] + pp[i] = p[i + 1] + pp[i + 1] = p[i] succ.append(P(pp)) else: - advance = lambda perm: [i for i in range(1, n) if perm.index(i) < perm.index(i+1)] + advance = lambda perm: [i for i in range(1, n) if perm.index(i) < perm.index(i + 1)] for i in advance(p): pp = p[:] - pp[p.index(i)] = i+1 - pp[p.index(i+1)] = i + pp[p.index(i)] = i + 1 + pp[p.index(i + 1)] = i succ.append(P(pp)) return succ @@ -4363,11 +4348,11 @@ def permutohedron_pred(self, side='right') -> list: pp[d] = p[d - 1] pred.append(P(pp)) else: - recoil = lambda perm: [i for i in range(1, n) if perm.index(i) > perm.index(i+1)] + recoil = lambda perm: [i for i in range(1, n) if perm.index(i) > perm.index(i + 1)] for i in recoil(p): pp = p[:] - pp[p.index(i)] = i+1 - pp[p.index(i+1)] = i + pp[p.index(i)] = i + 1 + pp[p.index(i + 1)] = i pred.append(P(pp)) return pred @@ -4453,8 +4438,7 @@ def right_permutohedron_interval_iterator(self, other): d = DiGraph() d.add_vertices(range(1, len(self) + 1)) d.add_edges([(j, i) for i, j in self.inverse().inversions()]) - d.add_edges([(other[i], other[j]) for i in range(len(other) - 1) - for j in range(i, len(other)) if other[i] < other[j]]) + d.add_edges([(other[i], other[j]) for i in range(len(other) - 1) for j in range(i, len(other)) if other[i] < other[j]]) return d.topological_sort_generator() def right_permutohedron_interval(self, other): @@ -4606,9 +4590,9 @@ def permutohedron_join(self, other, side='right') -> Permutation: xs: list[int] = [] for i in range(1, n + 1): u = self.index(i) - must_be_right = [f for f in self[u + 1:] if f < i] + must_be_right = [f for f in self[u + 1 :] if f < i] v = other.index(i) - must_be_right += [f for f in other[v + 1:] if f < i] + must_be_right += [f for f in other[v + 1 :] if f < i] must_be_right = sorted(set(must_be_right)) for j, q in enumerate(xs): if q in must_be_right: @@ -4770,8 +4754,7 @@ def pattern_positions(self, patt) -> list: """ p = self - return [list(pos) for pos in itertools.combinations(range(len(p)), len(patt)) - if to_standard([p[z] for z in pos]) == patt] + return [list(pos) for pos in itertools.combinations(range(len(p)), len(patt)) if to_standard([p[z] for z in pos]) == patt] @combinatorial_map(name='Simion-Schmidt map') def simion_schmidt(self, avoid=[1, 2, 3]): @@ -4896,6 +4879,7 @@ def permutation_poset(self): True """ from sage.combinat.posets.posets import Poset + n = len(self) posetdict = {} for i in range(n): @@ -4947,7 +4931,7 @@ def action(self, a): """ if len(a) != len(self): raise ValueError("len(a) must equal len(self)") - return [a[i-1] for i in self] + return [a[i - 1] for i in self] ###################### # Robinson-Schensted # @@ -5040,7 +5024,8 @@ def rec(perm): return LBT(None) mn = compare(perm) k = perm.index(mn) - return LBT([rec(perm[:k]), rec(perm[k + 1:])], label=mn) + return LBT([rec(perm[:k]), rec(perm[k + 1 :])], label=mn) + return rec(self) @combinatorial_map(name="Increasing tree") @@ -5106,6 +5091,7 @@ def binary_search_tree(self, left_to_right=True): . """ from sage.combinat.binary_tree import LabelledBinaryTree as LBT + res = LBT(None) if left_to_right: gen = self @@ -5137,6 +5123,7 @@ def binary_search_tree_shape(self, left_to_right=True): [[., .], [., [., .]]] """ from sage.combinat.binary_tree import binary_search_tree_shape + return binary_search_tree_shape(list(self), left_to_right) def sylvester_class(self, left_to_right=False): @@ -5287,12 +5274,12 @@ def remove_extra_fixed_points(self): return Permutations()([1]) # Strip off all extra fixed points at the end of # the permutation. - i = len(self)-1 + i = len(self) - 1 while i >= 1: if i != self[i] - 1: break i -= 1 - return Permutations()(self[:i+1]) + return Permutations()(self[: i + 1]) def retract_plain(self, m): r""" @@ -5488,10 +5475,11 @@ def hyperoctahedral_double_coset_type(self): ValueError: [3, 1, 2] is a permutation of odd size and has no coset-type """ from sage.combinat.perfect_matching import PerfectMatchings + n = len(self) if n % 2 == 1: raise ValueError("%s is a permutation of odd size and has no coset-type" % self) - S = PerfectMatchings(n)([(2*i+1, 2*i+2) for i in range(n//2)]) + S = PerfectMatchings(n)([(2 * i + 1, 2 * i + 2) for i in range(n // 2)]) return S.loop_type(S.apply_permutation(self)) ##################### @@ -5595,8 +5583,7 @@ def shifted_shuffle(self, other): ....: for p1 in Permutations(2) ) True """ - return self.shifted_concatenation(other, "right").\ - right_permutohedron_interval(self.shifted_concatenation(other, "left")) + return self.shifted_concatenation(other, "right").right_permutohedron_interval(self.shifted_concatenation(other, "left")) def nth_roots(self, n): r""" @@ -5660,16 +5647,16 @@ def merging_cycles(list_of_cycles): """ lC = len(list_of_cycles) lperm = len(list_of_cycles[0]) - l = lC*lperm + l = lC * lperm perm = [0] * l for j in range(lperm): - perm[j*lC] = list_of_cycles[0][j] - for p in Permutations(lC-1): - for indices in product(*[range(lperm) for _ in range(lC-1)]): + perm[j * lC] = list_of_cycles[0][j] + for p in Permutations(lC - 1): + for indices in product(*[range(lperm) for _ in range(lC - 1)]): new_perm = list(perm) - for i in range(lC-1): + for i in range(lC - 1): for j in range(lperm): - new_perm[(p[i] + (indices[i]+j)*lC) % l] = list_of_cycles[i+1][j] + new_perm[(p[i] + (indices[i] + j) * lC) % l] = list_of_cycles[i + 1][j] yield Permutation(tuple(new_perm)) def rewind(L, n): @@ -5699,15 +5686,14 @@ def rewind(L, n): possibilities = [[] for m in cycles] for i, m in enumerate(cycles): N = len(cycles[m]) - parts = [x for x in divisors(n) if gcd(m*x, n) == x] + parts = [x for x in divisors(n) if gcd(m * x, n) == x] b = False for X in Partitions(N, parts_in=parts): for partition in SetPartitions(N, X): b = True poss = [P.identity()] for pa in partition: - poss = [p*q for p in poss - for q in merging_cycles([rewind(cycles[m][i-1], n//len(pa)) for i in pa])] + poss = [p * q for p in poss for q in merging_cycles([rewind(cycles[m][i - 1], n // len(pa)) for i in pa])] possibilities[i] += poss if not b: return @@ -5769,7 +5755,7 @@ def has_nth_root(self, n) -> bool: # for each length m, check if the number of m-cycles can come from a n-th power # (i.e. if you can partition m*Cycles[m] into parts of size l with l = m*gcd(l, n)) for m, N in cycles.items(): - parts = [x for x in divisors(n) if gcd(m*x, n) == x] + parts = [x for x in divisors(n) if gcd(m * x, n) == x] if Partitions(N, parts_in=parts).is_empty(): return False return True @@ -5829,10 +5815,8 @@ def number_of_nth_roots(self, n): cycles = self.cycle_type().to_exp_dict() result = 1 for m, N in cycles.items(): - parts = [x for x in divisors(n) if gcd(m*x, n) == x] - result *= sum(SetPartitions(N, pa).cardinality() * - prod(factorial(x-1) * m**(x-1) for x in pa) - for pa in Partitions(N, parts_in=parts)) + parts = [x for x in divisors(n) if gcd(m * x, n) == x] + result *= sum(SetPartitions(N, pa).cardinality() * prod(factorial(x - 1) * m ** (x - 1) for x in pa) for pa in Partitions(N, parts_in=parts)) if not result: return 0 @@ -5852,7 +5836,9 @@ def _tableau_contribution(T): 3 """ from sage.combinat.tableau import StandardTableaux - return (StandardTableaux(T.shape()).cardinality()) + + return StandardTableaux(T.shape()).cardinality() + ################################################################ # Parent classes @@ -6028,6 +6014,7 @@ class Permutations(UniqueRepresentation, Parent): sage: p.random_element().parent() is p # needs sage.combinat True """ + @staticmethod def __classcall_private__(cls, n=None, k=None, **kwargs): """ @@ -6044,8 +6031,7 @@ def __classcall_private__(cls, n=None, k=None, **kwargs): sage: Permutations([1,2,3,4,5]) Standard permutations of 5 """ - valid_args = ['descents', 'bruhat_smaller', 'bruhat_greater', - 'recoils_finer', 'recoils_fatter', 'recoils', 'avoiding'] + valid_args = ['descents', 'bruhat_smaller', 'bruhat_greater', 'recoils_finer', 'recoils_fatter', 'recoils', 'avoiding'] number_of_arguments = 0 if n is not None: @@ -6186,39 +6172,14 @@ class options(GlobalOptions): [3, 2, 1] sage: Permutations.options._reset() """ + NAME = 'Permutations' module = 'sage.combinat.permutation' - display = {'default': "list", - 'description': "Specifies how the permutations should be printed", - 'values': {'list': "the permutations are displayed in list notation" - " (aka 1-line notation)", - 'cycle': "the permutations are displayed in cycle notation" - " (i. e., as products of disjoint cycles)", - 'singleton': "the permutations are displayed in cycle notation" - " with singleton cycles shown as well", - 'reduced_word': "the permutations are displayed as reduced words"}, - 'alias': {'word': "reduced_word", 'reduced_expression': "reduced_word"}, - 'case_sensitive': False} - latex = {'default': "list", - 'description': "Specifies how the permutations should be latexed", - 'values': {'list': "latex as a list in one-line notation", - 'twoline': "latex in two-line notation", - 'cycle': "latex in cycle notation", - 'singleton': "latex in cycle notation with singleton cycles shown as well", - 'reduced_word': "latex as reduced words"}, - 'alias': {'word': "reduced_word", 'reduced_expression': "reduced_word", 'oneline': "list"}, - 'case_sensitive': False} - latex_empty_str = {'default': "1", - 'description': 'The LaTeX representation of a reduced word when said word is empty', - 'checker': lambda char: isinstance(char, str)} - generator_name = {'default': "s", - 'description': "the letter used in latexing the reduced word", - 'checker': lambda char: isinstance(char, str)} - mult = {'default': "l2r", - 'description': "The multiplication of permutations", - 'values': {'l2r': r"left to right: `(p_1 \cdot p_2)(x) = p_2(p_1(x))`", - 'r2l': r"right to left: `(p_1 \cdot p_2)(x) = p_1(p_2(x))`"}, - 'case_sensitive': False} + display = {'default': "list", 'description': "Specifies how the permutations should be printed", 'values': {'list': "the permutations are displayed in list notation" " (aka 1-line notation)", 'cycle': "the permutations are displayed in cycle notation" " (i. e., as products of disjoint cycles)", 'singleton': "the permutations are displayed in cycle notation" " with singleton cycles shown as well", 'reduced_word': "the permutations are displayed as reduced words"}, 'alias': {'word': "reduced_word", 'reduced_expression': "reduced_word"}, 'case_sensitive': False} + latex = {'default': "list", 'description': "Specifies how the permutations should be latexed", 'values': {'list': "latex as a list in one-line notation", 'twoline': "latex in two-line notation", 'cycle': "latex in cycle notation", 'singleton': "latex in cycle notation with singleton cycles shown as well", 'reduced_word': "latex as reduced words"}, 'alias': {'word': "reduced_word", 'reduced_expression': "reduced_word", 'oneline': "list"}, 'case_sensitive': False} + latex_empty_str = {'default': "1", 'description': 'The LaTeX representation of a reduced word when said word is empty', 'checker': lambda char: isinstance(char, str)} + generator_name = {'default': "s", 'description': "the letter used in latexing the reduced word", 'checker': lambda char: isinstance(char, str)} + mult = {'default': "l2r", 'description': "The multiplication of permutations", 'values': {'l2r': r"left to right: `(p_1 \cdot p_2)(x) = p_2(p_1(x))`", 'r2l': r"right to left: `(p_1 \cdot p_2)(x) = p_1(p_2(x))`"}, 'case_sensitive': False} class Permutations_nk(Permutations): @@ -6301,8 +6262,7 @@ def __iter__(self) -> Iterator[Permutation]: sage: [p for p in Permutations(3,4)] [] """ - for x in itertools.permutations(range(1, self.n + 1), - int(self._k)): + for x in itertools.permutations(range(1, self.n + 1), int(self._k)): yield self.element_class(self, x, check=False) def cardinality(self) -> Integer: @@ -6380,6 +6340,7 @@ class Permutations_mset(Permutations): sage: sorted(P) [[(1, 0), (1, 1)], [(1, 1), (1, 0)]] """ + @staticmethod def __classcall_private__(cls, mset): """ @@ -6479,6 +6440,7 @@ def __iter__(self): mset = self.mset n = len(mset) from array import array + mset_list = array('I', sorted(mset.index(x) for x in mset)) yield self.element_class(self, map_to_list(mset_list, mset, n), check=False) @@ -6583,7 +6545,7 @@ def rank(self, p): self(p).check() m = {} r = 0 - for n in range(1, len(p)+1): + for n in range(1, len(p) + 1): # ``p1`` is the first element of ``p[-n:]`` (i.e., the last ``n`` # elements of ``p``). ``m`` represents the multiset of ``p[-n:]`` in # the form element→count. @@ -6669,7 +6631,7 @@ def unrank(self, r): sage: ps.unrank(5) == ps(pm.unrank(5)) True """ - range_error = ValueError("r must be between %d and %d inclusive" % (0, self.cardinality()-1)) + range_error = ValueError("r must be between %d and %d inclusive" % (0, self.cardinality() - 1)) if r < 0: raise range_error @@ -6741,6 +6703,7 @@ class Permutations_set(Permutations): once. This is not to be confused with bijections from `S` to `S`, which are also often called permutations in literature. """ + @staticmethod def __classcall_private__(cls, s): """ @@ -6869,6 +6832,7 @@ class Permutations_msetk(Permutations_mset): elements of `M`, appearing in the list with a multiplicity not higher than their respective multiplicity in `M`. """ + @staticmethod def __classcall__(cls, mset, k): """ @@ -6949,8 +6913,7 @@ def __iter__(self): mset_list = [lmset.index(x) for x in lmset] indices = libgap.Arrangements(mset_list, self._k).sage() for ktuple in indices: - yield self.element_class(self, [lmset[x] for x in ktuple], - check=False) + yield self.element_class(self, [lmset[x] for x in ktuple], check=False) def rank(self, x): """ @@ -6985,6 +6948,7 @@ class Permutations_setk(Permutations_set): a list of length `k` whose entries are pairwise distinct and all belong to `S`. """ + @staticmethod def __classcall_private__(cls, s, k): """ @@ -7072,6 +7036,7 @@ def random_element(self): x = sample(self._set, self._k) return self.element_class(self, x, check=False) + ################################## # Arrangements @@ -7123,6 +7088,7 @@ class Arrangements(Permutations): ['t', 'c', 'a'], ['t', 'a', 'c']] """ + @staticmethod def __classcall_private__(cls, mset, k): """ @@ -7183,6 +7149,7 @@ def _repr_(self): """ return f"Arrangements of the set {list(self._set)} of length {self._k}" + ############################################################### # Standard permutations @@ -7338,7 +7305,7 @@ def _element_constructor_(self, x, check=True): Standard permutations of 8 """ if isinstance(x, PermutationGroupElement): - return self. _from_permutation_group_element(x) + return self._from_permutation_group_element(x) if len(x) < self.n: x = list(x) + list(range(len(x) + 1, self.n + 1)) return self.element_class(self, x, check=check) @@ -7445,7 +7412,7 @@ def _coerce_map_from_(self, G): """ if isinstance(G, SymmetricGroup): D = G.domain() - if len(D) > self.n or list(D) != list(range(1, len(D)+1)): + if len(D) > self.n or list(D) != list(range(1, len(D) + 1)): return False return self._from_permutation_group_element if isinstance(G, StandardPermutations_n) and G.n <= self.n: @@ -7499,6 +7466,7 @@ def as_permutation_group(self): True """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup + return SymmetricGroup(self.n) def identity(self): @@ -7570,8 +7538,7 @@ def random_element(self): sage: s in Permutations(4) True """ - return self.element_class(self, sample(range(1, self.n + 1), self.n), - check=False) + return self.element_class(self, sample(range(1, self.n + 1), self.n), check=False) def cardinality(self): """ @@ -7645,7 +7612,7 @@ def codegrees(self): sage: Permutations(7).codegrees() (0, 1, 2, 3, 4, 5) """ - return tuple(Integer(i) for i in range(self.n-1)) + return tuple(Integer(i) for i in range(self.n - 1)) def element_in_conjugacy_classes(self, nu): r""" @@ -7665,10 +7632,10 @@ def element_in_conjugacy_classes(self, nu): ValueError: the size of the partition (=10) should be at most the size of the permutations (=5) """ from sage.combinat.partition import Partition + nu = Partition(nu) if nu.size() > self.n: - raise ValueError("the size of the partition (={}) should be at most" - " the size of the permutations (={})".format(nu.size(), self.n)) + raise ValueError("the size of the partition (={}) should be at most" " the size of the permutations (={})".format(nu.size(), self.n)) l = [] i = 0 for nui in nu: @@ -7712,8 +7679,8 @@ def conjugacy_classes_representatives(self): [[1]] """ from sage.combinat.partition import Partitions_n - return [self.element_in_conjugacy_classes(la) - for la in reversed(Partitions_n(self.n))] + + return [self.element_in_conjugacy_classes(la) for la in reversed(Partitions_n(self.n))] def conjugacy_classes_iterator(self): """ @@ -7727,6 +7694,7 @@ def conjugacy_classes_iterator(self): """ from sage.combinat.partition import Partitions_n from sage.groups.perm_gps.symgp_conjugacy_class import PermutationsConjugacyClass + for la in reversed(Partitions_n(self.n)): yield PermutationsConjugacyClass(self, la) @@ -7764,6 +7732,7 @@ def conjugacy_class(self, g): Conjugacy class of cycle type [2, 1, 1, 1] in Standard permutations of 5 """ from sage.groups.perm_gps.symgp_conjugacy_class import PermutationsConjugacyClass + return PermutationsConjugacyClass(self, g) def algebra(self, base_ring, category=None): @@ -7791,6 +7760,7 @@ def algebra(self, base_ring, category=None): Category of finite dimensional cellular monoid algebras over Rational Field """ from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra + return SymmetricGroupAlgebra(base_ring, self, category=category) @cached_method @@ -7822,6 +7792,7 @@ def cartan_type(self): ['A', 0] """ from sage.combinat.root_system.cartan_type import CartanType + return CartanType(['A', max(self.n - 1, 0)]) def simple_reflection(self, i): @@ -7885,8 +7856,8 @@ def reflection(self, i): (3, 4) [1, 2, 4, 3] """ data = list(range(1, self.n + 1)) - data[i[0]-1] = i[1] - data[i[1]-1] = i[0] + data[i[0] - 1] = i[1] + data[i[1] - 1] = i[0] return self.element_class(self, data, check=False) class Element(Permutation): @@ -8082,6 +8053,7 @@ def apply_simple_reflection_right(self, i): p = left_action_same_n(self._list, s._list) return self.__class__(self.parent(), p) + ############################# # Constructing Permutations # ############################# @@ -8245,14 +8217,11 @@ def from_cycles(n, cycles, parent=None): # check that the values are valid if (k < 1) or (pk < 1): - raise ValueError("all elements should be strictly positive " - f"integers, but I found {min(k, pk)}") + raise ValueError("all elements should be strictly positive " f"integers, but I found {min(k, pk)}") if (k > n) or (pk > n): - raise ValueError("you claimed that this is a permutation on " - f"1...{n}, but it contains {max(k, pk)}") + raise ValueError("you claimed that this is a permutation on " f"1...{n}, but it contains {max(k, pk)}") if p[k - 1] is not None: - raise ValueError(f"the element {k} appears more than once" - " in the input") + raise ValueError(f"the element {k} appears more than once" " in the input") p[k - 1] = pk # values that are not in any cycle are fixed points of the permutation @@ -8298,10 +8267,10 @@ def from_lehmer_cocode(lehmer, parent=Permutations()): """ p = [] ell = len(lehmer) - i = ell-1 - open_spots = list(range(1, ell+1)) + i = ell - 1 + open_spots = list(range(1, ell + 1)) for ivi in reversed(lehmer): - p.append(open_spots.pop(i-ivi)) + p.append(open_spots.pop(i - ivi)) i -= 1 p.reverse() return parent(p) @@ -8330,10 +8299,10 @@ def from_reduced_word(rw, parent=None): if not rw: return parent([]) - p = [i+1 for i in range(max(rw)+1)] + p = [i + 1 for i in range(max(rw) + 1)] for i in rw: - (p[i-1], p[i]) = (p[i], p[i-1]) + (p[i - 1], p[i]) = (p[i], p[i - 1]) return parent(p) @@ -8486,7 +8455,7 @@ def bistochastic_as_sum_of_permutations(M, check=True): G.set_edge_label(u, v, l - minimum) matching.sort(key=lambda x: x[0]) - value += minimum * CFM(P([x[1]-n+1 for x in matching])) + value += minimum * CFM(P([x[1] - n + 1 for x in matching])) return value @@ -8526,6 +8495,7 @@ def bounded_affine_permutation(A): R = A.base_ring() from sage.modules.free_module import FreeModule from sage.modules.free_module import span + z = FreeModule(R, A.nrows()).zero() v = A.columns() perm = [] @@ -8550,6 +8520,7 @@ class StandardPermutations_descents(StandardPermutations_n_abstract): r""" Permutations of `\{1, \ldots, n\}` with a fixed set of descents. """ + @staticmethod def __classcall_private__(cls, d, n): """ @@ -8622,6 +8593,7 @@ def cardinality(self): sage: P(D, n).cardinality() 125291047596 """ + def m(l): s = 0 partial_sums = [0] @@ -8637,7 +8609,7 @@ def d(l): if not self._d: return one - l_ops = [1] * (self.n-1) + l_ops = [1] * (self.n - 1) for i in self._d: l_ops[i] = 0 l = [one] @@ -8832,14 +8804,14 @@ def __iter__(self): dag = DiGraph() # Add the nodes - for i in range(1, sum(recoils)+1): + for i in range(1, sum(recoils) + 1): dag.add_vertex(i) # Add the edges to guarantee a finer recoil composition pos = 1 for part in recoils: - for i in range(part-1): - dag.add_edge(pos, pos+1) + for i in range(part - 1): + dag.add_edge(pos, pos + 1) pos += 1 pos += 1 @@ -8906,14 +8878,14 @@ def __iter__(self): dag = DiGraph() # Add the nodes - for i in range(1, sum(recoils)+1): + for i in range(1, sum(recoils) + 1): dag.add_vertex(i) # Add the edges to guarantee a fatter recoil composition pos = 0 - for i in range(len(recoils)-1): + for i in range(len(recoils) - 1): pos += recoils[i] - dag.add_edge(pos+1, pos) + dag.add_edge(pos + 1, pos) for le in dag.topological_sort_generator(): yield self.element_class(self, le, check=False) @@ -8923,6 +8895,7 @@ class StandardPermutations_recoils(Permutations): r""" Permutations of `\{1, \ldots, n\}` with a fixed recoils composition. """ + @staticmethod def __classcall_private__(cls, recoils): """ @@ -8970,22 +8943,22 @@ def __iter__(self): dag = DiGraph() # Add all the nodes - for i in range(1, sum(recoils)+1): + for i in range(1, sum(recoils) + 1): dag.add_vertex(i) # Add the edges which guarantee a finer recoil comp. pos = 1 for part in recoils: - for i in range(part-1): - dag.add_edge(pos, pos+1) + for i in range(part - 1): + dag.add_edge(pos, pos + 1) pos += 1 pos += 1 # Add the edges which guarantee a fatter recoil comp. pos = 0 - for i in range(len(recoils)-1): + for i in range(len(recoils) - 1): pos += recoils[i] - dag.add_edge(pos+1, pos) + dag.add_edge(pos + 1, pos) for le in dag.topological_sort_generator(): yield self.element_class(self, le, check=False) @@ -9059,12 +9032,13 @@ def from_major_code(mc, final_descent=False): # d_k = -1 -- 0 in the lemma, but -1 due to 0-based indexing d.append(0) - l = mc[i-1] + l = mc[i - 1] indices = d + a w.insert(indices[l], i) return Permutation(w, check=False) + ################ # Bruhat Order # ################ @@ -9075,6 +9049,7 @@ class StandardPermutations_bruhat_smaller(Permutations): Permutations of `\{1, \ldots, n\}` that are less than or equal to a permutation `p` in the Bruhat order. """ + @staticmethod def __classcall_private__(cls, p): """ @@ -9133,6 +9108,7 @@ class StandardPermutations_bruhat_greater(Permutations): Permutations of `\{1, \ldots, n\}` that are greater than or equal to a permutation `p` in the Bruhat order. """ + @staticmethod def __classcall_private__(cls, p): """ @@ -9201,15 +9177,15 @@ def bruhat_lequal(p1, p2): if n1 == 0: return True - if p1[0] > p2[0] or p1[n1-1] < p2[n1-1]: + if p1[0] > p2[0] or p1[n1 - 1] < p2[n1 - 1]: return False for i in range(n1): c = 0 for j in range(n1): - if p2[j] > i+1: + if p2[j] > i + 1: c += 1 - if p1[j] > i+1: + if p1[j] > i + 1: c -= 1 if c < 0: return False @@ -9221,6 +9197,7 @@ def bruhat_lequal(p1, p2): # Permutohedron # ################# + def permutohedron_lequal(p1, p2, side='right'): r""" Return ``True`` if ``p1`` is less than or equal to ``p2`` in the @@ -9256,6 +9233,7 @@ def permutohedron_lequal(p1, p2, side='right'): # Patterns # ############ + def to_standard(p, key=None): r""" Return a standard permutation corresponding to the iterable ``p``. @@ -9325,6 +9303,7 @@ def to_standard(p, key=None): ########################################################## + class CyclicPermutations(Permutations_mset): """ Return the class of all cyclic permutations of ``mset`` in cycle notation. @@ -9346,6 +9325,7 @@ class CyclicPermutations(Permutations_mset): sage: CyclicPermutations([1,1,1]).list() # needs sage.combinat [(1, 1, 1)] """ + @staticmethod def __classcall_private__(cls, mset): """ @@ -9399,8 +9379,9 @@ def __iter__(self, distinct=False): content[i] += 1 from .necklace import Necklaces + for necklace in Necklaces(content): - yield tuple(self.mset[x-1] for x in necklace) + yield tuple(self.mset[x - 1] for x in necklace) iterator = __iter__ @@ -9418,6 +9399,7 @@ def list(self, distinct=False): """ return list(self.__iter__(distinct=distinct)) + ################################################# @@ -9466,6 +9448,7 @@ class CyclicPermutationsOfPartition(Permutations): [(1, 2, 3), (4, 4, 4)], [(1, 3, 2), (4, 4, 4)]] """ + @staticmethod def __classcall_private__(cls, partition): """ @@ -9594,10 +9577,12 @@ def list(self, distinct=False): ############################################### # Avoiding + class StandardPermutations_all_avoiding(StandardPermutations_all): """ All standard permutations avoiding a set of patterns. """ + @staticmethod def __classcall_private__(cls, a): """ @@ -9694,6 +9679,7 @@ class StandardPermutations_avoiding_generic(StandardPermutations_n_abstract): """ Generic class for subset of permutations avoiding a set of patterns. """ + @staticmethod def __classcall_private__(cls, n, a): """ @@ -9912,22 +9898,17 @@ def __iter__(self): # Yield all the 132 avoiding permutations to the right. for right in StandardPermutations_avoiding_132(self.n - 1): - yield self.element_class(self, [self.n] + list(right), - check=False) + yield self.element_class(self, [self.n] + list(right), check=False) # yi - for i in range(1, self.n-1): + for i in range(1, self.n - 1): for left in StandardPermutations_avoiding_132(i): - for right in StandardPermutations_avoiding_132(self.n-i-1): - yield self.element_class(self, - [x + (self.n-i-1) for x in left] - + [self.n] + list(right), - check=False) + for right in StandardPermutations_avoiding_132(self.n - i - 1): + yield self.element_class(self, [x + (self.n - i - 1) for x in left] + [self.n] + list(right), check=False) # Yield all the 132 avoiding permutations to the left for left in StandardPermutations_avoiding_132(self.n - 1): - yield self.element_class(self, list(left) + [self.n], - check=False) + yield self.element_class(self, list(left) + [self.n], check=False) class StandardPermutations_avoiding_123(StandardPermutations_avoiding_generic): @@ -10174,10 +10155,8 @@ def _rec(self, obj, state): new_state = None yld = True - for pos in reversed(range(len(obj)+1)): - new_obj = self._parent.element_class(self._parent, - obj[:pos] + [i] + obj[pos:], - check=False) + for pos in reversed(range(len(obj) + 1)): + new_obj = self._parent.element_class(self._parent, obj[:pos] + [i] + obj[pos:], check=False) if all(not new_obj.has_pattern(p) for p in self._patterns): yield new_obj, new_state, yld @@ -10216,6 +10195,7 @@ def __setstate__(self, state): from sage.misc.persist import register_unpickle_override + register_unpickle_override("sage.combinat.permutation", "Permutation_class", Permutation) register_unpickle_override("sage.combinat.permutation", "CyclicPermutationsOfPartition_partition", CyclicPermutationsOfPartition) register_unpickle_override("sage.combinat.permutation", "CyclicPermutations_mset", CyclicPermutations) diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 842d0d41e9b..013ea4573e3 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -7,6 +7,7 @@ - Jessica Striker (2016): added additional methods - Kevin Dilks (2021): added symmetry classes """ + # **************************************************************************** # Copyright (C) 2016 Jang Soo Kim , # 2016 Jessica Striker @@ -50,8 +51,7 @@ @richcmp_method -class PlanePartition(ClonableArray, - metaclass=InheritComparisonClasscallMetaclass): +class PlanePartition(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): r""" A plane partition. @@ -79,6 +79,7 @@ class PlanePartition(ClonableArray, sage: TestSuite(PP).run() sage: hash(PP) # random """ + @staticmethod def __classcall_private__(cls, PP, box_size=None): """ @@ -219,7 +220,7 @@ def check(self): for row in self: if not all(c >= 0 for c in row): raise ValueError("entries not all nonnegative") - if not all(row[i] >= row[i+1] for i in range(len(row)-1)): + if not all(row[i] >= row[i + 1] for i in range(len(row) - 1)): raise ValueError("not weakly decreasing along rows") for row, next in zip(self, self[1:]): if not all(row[c] >= next[c] for c in range(len(next))): @@ -326,10 +327,7 @@ def cells(self) -> list[tuple[int, int, int]]: sage: PP.cells() [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (1, 0, 0), (1, 0, 1)] """ - return [(r, c, h) - for r in range(len(self)) - for c in range(len(self[r])) - for h in range(self[r][c])] + return [(r, c, h) for r in range(len(self)) for c in range(len(self[r])) for h in range(self[r][c])] def number_of_boxes(self) -> Integer: r""" @@ -382,8 +380,7 @@ def _repr_diagram(self, show_box=False, use_unicode=False) -> str: y = self._max_y z = self._max_z - drawing = [[" " for i in range(2 * x + y + z)] - for j in range(y + z + 1)] + drawing = [[" " for i in range(2 * x + y + z)] for j in range(y + z + 1)] hori = "_" if use_unicode else "_" down = "╲" if use_unicode else "\\" @@ -472,6 +469,7 @@ def _ascii_art_(self): \/_/ """ from sage.typeset.ascii_art import AsciiArt + return AsciiArt(self._repr_diagram().splitlines(), baseline=0) def _unicode_art_(self): @@ -493,6 +491,7 @@ def _unicode_art_(self): ╲╱_╱ """ from sage.typeset.unicode_art import UnicodeArt + return UnicodeArt(self._repr_diagram(use_unicode=True).splitlines(), baseline=0) def pp(self, show_box=False): @@ -567,9 +566,7 @@ def _repr_svg_(self) -> str: # use the smallest one possible. Nx, Ny, Nz = self.bounding_box() - resu += '\"%.3f %.3f %.3f %.3f \">' % (-0.866 * Nx, -Nz, - 0.866 * Nx + 0.866 * Ny, - Nz + 0.5 * (Nx + Ny)) + resu += '\"%.3f %.3f %.3f %.3f \">' % (-0.866 * Nx, -Nz, 0.866 * Nx + 0.866 * Ny, Nz + 0.5 * (Nx + Ny)) resu += resu1 mat = self.z_tableau() @@ -597,8 +594,7 @@ def _repr_svg_(self) -> str: resu += '\" xlink:href=\"#cx\" />' return resu + '' - def _latex_(self, show_box=False, - colors=["white", "lightgray", "darkgray"]) -> str: + def _latex_(self, show_box=False, colors=["white", "lightgray", "darkgray"]) -> str: r""" Return latex code for ``self``, which uses TikZ package to draw the plane partition. @@ -626,6 +622,7 @@ def _latex_(self, show_box=False, \end{tikzpicture} """ from sage.graphs.graph_latex import setup_latex_preamble + setup_latex_preamble() ret = "\\begin{tikzpicture}\n" @@ -638,6 +635,7 @@ def add_leftside(j, k, i): def add_rightside(k, i, j): return "\\draw[fill={},shift={{(210:{})}},shift={{(-30:{})}},shift={{(90:{})}}]\n(0,0)--(210:1)--(150:1)--(0,1)--(0,0);\n".format(colors[2], i, j, k) + funcs = [add_topside, add_rightside, add_leftside] tableaux = [self.z_tableau(), self.y_tableau(), self.x_tableau()] for i in range(3): @@ -670,34 +668,28 @@ def plot(self, show_box=False, colors=None): from sage.plot.polygon import polygon from sage.symbolic.constants import pi from sage.plot.plot import plot + if colors is None: colors = ["white", "lightgray", "darkgray"] - Uside = [[0, 0], [cos(-pi / 6), sin(-pi / 6)], - [0, -1], [cos(7 * pi / 6), sin(7 * pi / 6)]] - Lside = [[0, 0], [cos(-pi / 6), sin(-pi / 6)], - [cos(pi / 6), sin(pi / 6)], [0, 1]] - Rside = [[0, 0], [0, 1], [cos(5 * pi / 6), sin(5 * pi / 6)], - [cos(7 * pi / 6), sin(7 * pi / 6)]] + Uside = [[0, 0], [cos(-pi / 6), sin(-pi / 6)], [0, -1], [cos(7 * pi / 6), sin(7 * pi / 6)]] + Lside = [[0, 0], [cos(-pi / 6), sin(-pi / 6)], [cos(pi / 6), sin(pi / 6)], [0, 1]] + Rside = [[0, 0], [0, 1], [cos(5 * pi / 6), sin(5 * pi / 6)], [cos(7 * pi / 6), sin(7 * pi / 6)]] Xdir = [cos(7 * pi / 6), sin(7 * pi / 6)] Ydir = [cos(-pi / 6), sin(-pi / 6)] Zdir = [0, 1] def move(side, i, j, k): - return [[P[0] + i * Xdir[0] + j * Ydir[0] + k * Zdir[0], - P[1] + i * Xdir[1] + j * Ydir[1] + k * Zdir[1]] - for P in side] + return [[P[0] + i * Xdir[0] + j * Ydir[0] + k * Zdir[0], P[1] + i * Xdir[1] + j * Ydir[1] + k * Zdir[1]] for P in side] def add_topside(i, j, k): - return polygon(move(Uside, i, j, k), edgecolor='black', - color=colors[0]) + return polygon(move(Uside, i, j, k), edgecolor='black', color=colors[0]) def add_leftside(i, j, k): - return polygon(move(Lside, i, j, k), edgecolor='black', - color=colors[1]) + return polygon(move(Lside, i, j, k), edgecolor='black', color=colors[1]) def add_rightside(i, j, k): - return polygon(move(Rside, i, j, k), edgecolor='black', - color=colors[2]) + return polygon(move(Rside, i, j, k), edgecolor='black', color=colors[2]) + TP = plot([]) for r in range(len(self.z_tableau())): for c in range(len(self.z_tableau()[r])): @@ -766,9 +758,8 @@ def plot3d(self, colors=None): if colors is None: colors = ["white", "lightgray", "darkgray"] from sage.plot.plot3d.platonic import cube - return sum(cube(c, color=colors, frame_thickness=2, - frame_color='black', frame=False) - for c in self.cells()) + + return sum(cube(c, color=colors, frame_thickness=2, frame_color='black', frame=False) for c in self.cells()) def complement(self, tableau_only=False) -> PP: r""" @@ -799,7 +790,7 @@ def complement(self, tableau_only=False) -> PP: z_tab = self.z_tableau() for r in range(A): for c in range(B): - T[A-1-r][B-1-c] = C - z_tab[r][c] + T[A - 1 - r][B - 1 - c] = C - z_tab[r][c] if tableau_only: return T P = self.parent() @@ -889,9 +880,7 @@ def is_SPP(self) -> bool: for i in range(c1): for j in range(c2): T[i][j] = Z[i][j] - return all(T[r][c] == T[c][r] - for r in range(size) - for c in range(r, size)) + return all(T[r][c] == T[c][r] for r in range(size) for c in range(r, size)) def is_CSPP(self) -> bool: r""" @@ -1100,6 +1089,7 @@ def to_order_ideal(self): [(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (2, 0, 0)] """ from sage.combinat.posets.poset_examples import posets + abc = [self._max_x, self._max_y, self._max_z] Q = posets.ProductOfChains(abc) generate = [] @@ -1126,8 +1116,8 @@ def maximal_boxes(self) -> list: generate = [] for i, row in enumerate(self): for j, entry in enumerate(row): - if (i == len(self)-1 or len(self[i+1])-1 < j or self[i+1][j] < entry) and (j == len(row)-1 or row[j+1] < entry): - generate.append([i, j, entry-1]) + if (i == len(self) - 1 or len(self[i + 1]) - 1 < j or self[i + 1][j] < entry) and (j == len(row) - 1 or row[j + 1] < entry): + generate.append([i, j, entry - 1]) return generate def cyclically_rotate(self, preserve_parent=False) -> PP: @@ -1174,16 +1164,16 @@ def cyclically_rotate(self, preserve_parent=False) -> PP: pp_matrix[y][z] = x + 1 if new_antichain: for i in range(b): - i = b - (i+1) + i = b - (i + 1) for j in range(c): - j = c - (j+1) + j = c - (j + 1) if pp_matrix[i][j] == 0: iValue = 0 jValue = 0 - if i < b-1: - iValue = pp_matrix[i+1][j] - if j < c-1: - jValue = pp_matrix[i][j+1] + if i < b - 1: + iValue = pp_matrix[i + 1][j] + if j < c - 1: + jValue = pp_matrix[i][j + 1] pp_matrix[i][j] = max(iValue, jValue) # Start code for determining correct parent P = self.parent() @@ -1324,6 +1314,7 @@ class PlanePartitions(UniqueRepresentation, Parent): - :class:`PlanePartitions_CSSCPP` - :class:`PlanePartitions_TSSCPP` """ + @staticmethod def __classcall_private__(cls, *args, **kwds): r""" @@ -1424,7 +1415,7 @@ def __contains__(self, pp): for row in pp: if not all(c >= 0 for c in row): return False - if not all(row[i] >= row[i+1] for i in range(len(row)-1)): + if not all(row[i] >= row[i + 1] for i in range(len(row) - 1)): return False for row, nxt in zip(pp, pp[1:]): if not all(row[c] >= nxt[c] for c in range(len(nxt))): @@ -1469,6 +1460,7 @@ class PlanePartitions_all(PlanePartitions, DisjointUnionEnumeratedSets): r""" All plane partitions. """ + def __init__(self): r""" Initialize the class of all plane partitions. @@ -1490,11 +1482,7 @@ def __init__(self): self._symmetry = None # super(PlanePartitions_all, self).__init__(category=InfiniteEnumeratedSets()) - DisjointUnionEnumeratedSets.__init__(self, - Family(NonNegativeIntegers(), - PlanePartitions_n), - facade=True, - keepkey=False) + DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), PlanePartitions_n), facade=True, keepkey=False) def _repr_(self) -> str: """ @@ -1528,6 +1516,7 @@ class PlanePartitions_box(PlanePartitions): will have at most `a` rows, of lengths at most `b`, with entries at most `c`. """ + def __init__(self, box_size): r""" Initialize the class of plane partitions that fit in a box of a @@ -1549,8 +1538,7 @@ def _repr_(self) -> str: sage: PlanePartitions([4,3,2]) Plane partitions inside a 4 x 3 x 2 box """ - return "Plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) + return "Plane partitions inside a {} x {} x {} box".format(self._box[0], self._box[1], self._box[2]) def __contains__(self, x): """ @@ -1583,6 +1571,7 @@ def to_poset(self): b = self._box[1] c = self._box[2] from sage.combinat.posets.poset_examples import posets + return posets.ProductOfChains([a, b, c]) def from_order_ideal(self, I) -> PP: @@ -1633,10 +1622,10 @@ def from_antichain(self, A) -> PP: if pp_matrix[i][j] == 0: iValue = 0 jValue = 0 - if i < a-1: - iValue = pp_matrix[i+1][j] - if j < b-1: - jValue = pp_matrix[i][j+1] + if i < a - 1: + iValue = pp_matrix[i + 1][j] + if j < b - 1: + jValue = pp_matrix[i][j + 1] pp_matrix[i][j] = max(iValue, jValue) return self.element_class(self, pp_matrix) @@ -1663,6 +1652,7 @@ def __iter__(self) -> Iterator: yield self.element_class(self, [], check=False) return from sage.combinat.tableau import SemistandardTableaux as SST + for T in SST([B for i in range(A)], max_entry=C + A): # type:ignore PP = [[0 for _ in range(B)] for _ in range(A)] for r in range(A): @@ -1691,14 +1681,7 @@ def cardinality(self) -> Integer: A = self._box[0] B = self._box[1] C = self._box[2] - return Integer(prod(i + j + k - 1 - for i in range(1, A + 1) - for j in range(1, B + 1) - for k in range(1, C + 1)) // - prod(i + j + k - 2 - for i in range(1, A + 1) - for j in range(1, B + 1) - for k in range(1, C + 1))) + return Integer(prod(i + j + k - 1 for i in range(1, A + 1) for j in range(1, B + 1) for k in range(1, C + 1)) // prod(i + j + k - 2 for i in range(1, A + 1) for j in range(1, B + 1) for k in range(1, C + 1))) def random_element(self) -> PP: r""" @@ -1724,6 +1707,7 @@ class PlanePartitions_n(PlanePartitions): """ Plane partitions with a fixed number of boxes. """ + def __init__(self, n): r""" Initialize the class of plane partitions with ``n`` boxes. @@ -1794,7 +1778,7 @@ def P_in_shape_iter(n, la): return for mu_0 in range(min(n, la[0]), 0, -1): new_la = [min(mu_0, la[i]) for i in range(1, len(la))] - for mu in P_in_shape_iter(n-mu_0, new_la): + for mu in P_in_shape_iter(n - mu_0, new_la): yield [mu_0] + mu def PP_first_row_iter(n, la): @@ -1839,8 +1823,8 @@ def cardinality(self) -> Integer: 18334 """ PPn = [1] - for i in range(1, 1+self._n): - nextPPn = sum(PPn[i-k] * Sigma()(k, 2) for k in range(1, i+1)) / i + for i in range(1, 1 + self._n): + nextPPn = sum(PPn[i - k] * Sigma()(k, 2) for k in range(1, i + 1)) / i PPn.append(nextPPn) return Integer(PPn[-1]) @@ -1848,6 +1832,7 @@ def cardinality(self) -> Integer: # Symmetry classes are enumerated and labelled in order as in Proofs and # Confirmations/Stanley (with all plane partitions being the first class) + # Class 2 # Symmetric Plane Partitions class PlanePartitions_SPP(PlanePartitions): @@ -1855,6 +1840,7 @@ class PlanePartitions_SPP(PlanePartitions): Plane partitions that fit inside a box of a specified size that are symmetric. """ + def __init__(self, box_size): """ Initialize ``self``. @@ -1879,8 +1865,7 @@ def _repr_(self) -> str: sage: PlanePartitions([3,3,2], symmetry='SPP') Symmetric plane partitions inside a 3 x 3 x 2 box """ - return "Symmetric plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) + return "Symmetric plane partitions inside a {} x {} x {} box".format(self._box[0], self._box[1], self._box[2]) def __contains__(self, x) -> bool: """ @@ -1895,9 +1880,7 @@ def __contains__(self, x) -> bool: """ P = PlanePartition(x) max = (P._max_x, P._max_y, P._max_z) - return (PlanePartitions.__contains__(self, x) - and P.is_SPP() - and all(a <= b for a, b in zip(max, self._box))) + return PlanePartitions.__contains__(self, x) and P.is_SPP() and all(a <= b for a, b in zip(max, self._box)) def to_poset(self): r""" @@ -1918,9 +1901,9 @@ def to_poset(self): def comp(x, y): return all(a <= b for a, b in zip(x, y)) - pl = [(x, y, z) for x in range(a) for y in range(x + 1) - for z in range(c)] + pl = [(x, y, z) for x in range(a) for y in range(x + 1) for z in range(c)] from sage.combinat.posets.posets import Poset + return Poset((pl, comp)) def from_order_ideal(self, I) -> PP: @@ -1970,9 +1953,9 @@ def from_antichain(self, A) -> PP: iValue = 0 jValue = 0 if i < a - 1: - iValue = pp_matrix[i+1][j] + iValue = pp_matrix[i + 1][j] if j < b - 1: - jValue = pp_matrix[i][j+1] + jValue = pp_matrix[i][j + 1] pp_matrix[i][j] = max(iValue, jValue) elif j > i: pp_matrix[i][j] = pp_matrix[j][i] @@ -2020,14 +2003,10 @@ def cardinality(self) -> Integer: """ a = self._box[0] c = self._box[2] - left_prod_num = prod(2*i + c - 1 for i in range(1, a+1)) - left_prod_den = prod(2*i - 1 for i in range(1, a+1)) - right_prod_num = prod(i + j + c - 1 - for j in range(1, a+1) - for i in range(1, j)) - right_prod_den = prod(i + j - 1 - for j in range(1, a+1) - for i in range(1, j)) + left_prod_num = prod(2 * i + c - 1 for i in range(1, a + 1)) + left_prod_den = prod(2 * i - 1 for i in range(1, a + 1)) + right_prod_num = prod(i + j + c - 1 for j in range(1, a + 1) for i in range(1, j)) + right_prod_den = prod(i + j - 1 for j in range(1, a + 1) for i in range(1, j)) return Integer(left_prod_num * right_prod_num // left_prod_den // right_prod_den) def random_element(self) -> PP: @@ -2058,6 +2037,7 @@ class PlanePartitions_CSPP(PlanePartitions): Plane partitions that fit inside a box of a specified size that are cyclically symmetric. """ + def __init__(self, box_size): """ Initialize ``self``. @@ -2082,8 +2062,7 @@ def _repr_(self) -> str: sage: PlanePartitions([3,3,3], symmetry='CSPP') Cyclically symmetric plane partitions inside a 3 x 3 x 3 box """ - return "Cyclically symmetric plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) + return "Cyclically symmetric plane partitions inside a {} x {} x {} box".format(self._box[0], self._box[1], self._box[2]) def __contains__(self, x) -> bool: """ @@ -2098,9 +2077,7 @@ def __contains__(self, x) -> bool: """ P = PlanePartition(x) max = (P._max_x, P._max_y, P._max_z) - return (PlanePartitions.__contains__(self, x) - and P.is_CSPP() - and all(a <= b for a, b in zip(max, self._box))) + return PlanePartitions.__contains__(self, x) and P.is_CSPP() and all(a <= b for a, b in zip(max, self._box)) def to_poset(self): """ @@ -2125,9 +2102,9 @@ def comp(x, y): def comp2(x, y): return comp(x, y) or comp(x, (y[2], y[0], y[1])) or comp(x, (y[1], y[2], y[0])) - pl = [(x, y, z) for x in range(a) for y in range(b) for z in range(x, c) - if y <= z and (x != z or y == x)] + pl = [(x, y, z) for x in range(a) for y in range(b) for z in range(x, c) if y <= z and (x != z or y == x)] from sage.combinat.posets.posets import Poset + return Poset((pl, comp2)) def from_antichain(self, acl) -> PP: @@ -2152,9 +2129,9 @@ def from_antichain(self, acl) -> PP: x = ac[0] y = ac[1] z = ac[2] - pp_matrix[y][z] = (x+1) - pp_matrix[z][x] = (y+1) - pp_matrix[x][y] = (z+1) + pp_matrix[y][z] = x + 1 + pp_matrix[z][x] = y + 1 + pp_matrix[x][y] = z + 1 # For each value in current antichain, fill in the rest of the # matrix by rule M[y,z] = Max(M[y+1,z], M[y,z+1]) antichain is @@ -2168,9 +2145,9 @@ def from_antichain(self, acl) -> PP: iValue = 0 jValue = 0 if i < b - 1: - iValue = pp_matrix[i+1][j] + iValue = pp_matrix[i + 1][j] if j < c - 1: - jValue = pp_matrix[i][j+1] + jValue = pp_matrix[i][j + 1] pp_matrix[i][j] = max(iValue, jValue) return self.element_class(self, pp_matrix) @@ -2250,12 +2227,8 @@ def cardinality(self) -> Integer: 132 """ a = self._box[0] - num = (prod(3*i - 1 for i in range(1, a + 1)) - * prod(i + j + a - 1 for j in range(1, a + 1) - for i in range(1, j + 1))) - den = (prod(3*i - 2 for i in range(1, a + 1)) - * prod(2*i + j - 1 for j in range(1, a + 1) - for i in range(1, j + 1))) + num = prod(3 * i - 1 for i in range(1, a + 1)) * prod(i + j + a - 1 for j in range(1, a + 1) for i in range(1, j + 1)) + den = prod(3 * i - 2 for i in range(1, a + 1)) * prod(2 * i + j - 1 for j in range(1, a + 1) for i in range(1, j + 1)) return Integer(num // den) @@ -2266,6 +2239,7 @@ class PlanePartitions_TSPP(PlanePartitions): Plane partitions that fit inside a box of a specified size that are totally symmetric. """ + def __init__(self, box_size): """ Initialize ``self``. @@ -2290,8 +2264,7 @@ def _repr_(self) -> str: sage: PlanePartitions([3,3,3], symmetry='TSPP') Totally symmetric plane partitions inside a 3 x 3 x 3 box """ - return "Totally symmetric plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) + return "Totally symmetric plane partitions inside a {} x {} x {} box".format(self._box[0], self._box[1], self._box[2]) def __contains__(self, x) -> bool: """ @@ -2306,8 +2279,7 @@ def __contains__(self, x) -> bool: """ P = PlanePartition(x) maxval = (P._max_x, P._max_y, P._max_z) - return (PlanePartitions.__contains__(self, x) and P.is_TSPP() - and all(a <= b for a, b in zip(maxval, self._box))) + return PlanePartitions.__contains__(self, x) and P.is_TSPP() and all(a <= b for a, b in zip(maxval, self._box)) def to_poset(self): r""" @@ -2332,6 +2304,7 @@ def comp(x, y): pl = [(x, y, z) for x in range(a) for y in range(x, b) for z in range(y, c)] from sage.combinat.posets.posets import Poset + return Poset((pl, comp)) def from_antichain(self, acl) -> PP: @@ -2374,9 +2347,9 @@ def from_antichain(self, acl) -> PP: iValue = 0 jValue = 0 if i < b - 1: - iValue = pp_matrix[i+1][j] + iValue = pp_matrix[i + 1][j] if j < c - 1: - jValue = pp_matrix[i][j+1] + jValue = pp_matrix[i][j + 1] pp_matrix[i][j] = max(iValue, jValue) return self.element_class(self, pp_matrix) @@ -2434,7 +2407,7 @@ def cardinality(self) -> Integer: """ a = self._box[0] num = prod(i + j + a - 1 for j in range(1, a + 1) for i in range(1, j + 1)) - den = prod(i + 2*j - 2 for j in range(1, a + 1) for i in range(1, j + 1)) + den = prod(i + 2 * j - 2 for j in range(1, a + 1) for i in range(1, j + 1)) return Integer(num // den) @@ -2445,6 +2418,7 @@ class PlanePartitions_SCPP(PlanePartitions): Plane partitions that fit inside a box of a specified size that are self-complementary. """ + def __init__(self, box_size): """ Initialize ``self``. @@ -2458,7 +2432,7 @@ def __init__(self, box_size): ... ValueError: dimensions (5,3,1) cannot all be odd """ - if (box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1): + if box_size[0] % 2 == 1 and box_size[1] % 2 == 1 and box_size[2] % 2 == 1: raise ValueError("dimensions ({},{},{}) cannot all be odd".format(*box_size)) super().__init__(box_size, "SCPP", category=FiniteEnumeratedSets()) @@ -2487,8 +2461,7 @@ def _repr_(self) -> str: sage: PlanePartitions([4,3,2], symmetry='SCPP') Self-complementary plane partitions inside a 4 x 3 x 2 box """ - return "Self-complementary plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) + return "Self-complementary plane partitions inside a {} x {} x {} box".format(self._box[0], self._box[1], self._box[2]) def __iter__(self) -> Iterator: """ @@ -2525,9 +2498,10 @@ def Partitions_inside_lambda(la): of parts including 0s. """ from sage.combinat.partition import Partitions + for k in range(sum(la), -1, -1): for mu in Partitions(k, outer=la): - yield mu + [0]*(len(la)-len(mu)) + yield mu + [0] * (len(la) - len(mu)) def Partitions_inside_lambda_with_smallest_at_least_k(la, k): """ @@ -2546,7 +2520,7 @@ def possible_middle_row_for_b_odd(a, c): yield return for mu in Partitions_inside_lambda([c // 2 for i in range(a // 2)]): - nu = [c - mu[len(mu)-1-i] for i in range(len(mu))] + nu = [c - mu[len(mu) - 1 - i] for i in range(len(mu))] if not a % 2: la = nu + mu else: @@ -2558,11 +2532,11 @@ def possible_middle_row_for_b_even(a, c): Iterate over all possible middle ((b/2)+1)st row for SCPP inside box(a,b,c) when b is even. """ - for mu in Partitions_inside_lambda([c // 2 for i in range((a+1) // 2)]): + for mu in Partitions_inside_lambda([c // 2 for i in range((a + 1) // 2)]): if not mu: yield [] continue - nu = [c - mu[len(mu)-1-i] for i in range(a // 2)] + nu = [c - mu[len(mu) - 1 - i] for i in range(a // 2)] for tau in Partitions_inside_lambda_with_smallest_at_least_k(nu, mu[0]): la = tau + mu yield la @@ -2576,7 +2550,7 @@ def PPs_with_first_row_la_and_with_k_rows(la, k): yield [la] return for mu in Partitions_inside_lambda(la): - for PP in PPs_with_first_row_la_and_with_k_rows(mu, k-1): + for PP in PPs_with_first_row_la_and_with_k_rows(mu, k - 1): yield [la] + PP def complement(PP, c): @@ -2585,12 +2559,12 @@ def complement(PP, c): if not b: return [] a = len(PP[0]) - return [[c - PP[b-1-i][a-1-j] for j in range(a)] for i in range(b)] + return [[c - PP[b - 1 - i][a - 1 - j] for j in range(a)] for i in range(b)] if b % 2 == 1: # la is the middle row of SCPP for la in possible_middle_row_for_b_odd(a, c): - for PP in PPs_with_first_row_la_and_with_k_rows(la, (b+1) // 2): + for PP in PPs_with_first_row_la_and_with_k_rows(la, (b + 1) // 2): PP_below = PP[1:] PP_above = complement(PP_below, c) yield self.element_class(self, PP_above + [la] + PP_below) @@ -2665,50 +2639,29 @@ def cardinality(self) -> Integer: S = s // 2 if t % 2 == 0: T = t // 2 - return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+1)) - * prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+1))) - T = (t-1) // 2 - return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+1)) - * prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+2))) - S = (s-1) // 2 + return Integer(prod(Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1, R + 1) for j in range(1, S + 1) for k in range(1, T + 1)) * prod(Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1, R + 1) for j in range(1, S + 1) for k in range(1, T + 1))) + T = (t - 1) // 2 + return Integer(prod(Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1, R + 1) for j in range(1, S + 1) for k in range(1, T + 1)) * prod(Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1, R + 1) for j in range(1, S + 1) for k in range(1, T + 2))) + S = (s - 1) // 2 if t % 2 == 0: T = t // 2 - return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+1)) - * prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1, R+1) for j in range(1, S+2) for k in range(1, T+1))) - T = (t-1) // 2 - return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1, R+1) for j in range(1, S+2) for k in range(1, T+1)) - * prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+2))) + return Integer(prod(Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1, R + 1) for j in range(1, S + 1) for k in range(1, T + 1)) * prod(Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1, R + 1) for j in range(1, S + 2) for k in range(1, T + 1))) + T = (t - 1) // 2 + return Integer(prod(Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1, R + 1) for j in range(1, S + 2) for k in range(1, T + 1)) * prod(Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1, R + 1) for j in range(1, S + 1) for k in range(1, T + 2))) # r is odd - R = (r-1) // 2 + R = (r - 1) // 2 if s % 2 == 0: S = s // 2 if t % 2 == 0: T = t // 2 - return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+1)) - * prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1, R+2) for j in range(1, S+1) for k in range(1, T+1))) - T = (t-1) // 2 - return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1, R+2) for j in range(1, S+1) for k in range(1, T+1)) - * prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1, R+1) for j in range(1, S+1) for k in range(1, T+2))) + return Integer(prod(Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1, R + 1) for j in range(1, S + 1) for k in range(1, T + 1)) * prod(Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1, R + 2) for j in range(1, S + 1) for k in range(1, T + 1))) + T = (t - 1) // 2 + return Integer(prod(Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1, R + 2) for j in range(1, S + 1) for k in range(1, T + 1)) * prod(Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1, R + 1) for j in range(1, S + 1) for k in range(1, T + 2))) # r and s are both odd - S = (s-1) // 2 + S = (s - 1) // 2 if t % 2 == 0: T = t // 2 - return Integer(prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1, R+2) for j in range(1, S+1) for k in range(1, T+1)) - * prod(Integer(i+j+k-1) / Integer(i+j+k-2) - for i in range(1, R+1) for j in range(1, S+2) for k in range(1, T+1))) + return Integer(prod(Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1, R + 2) for j in range(1, S + 1) for k in range(1, T + 1)) * prod(Integer(i + j + k - 1) / Integer(i + j + k - 2) for i in range(1, R + 1) for j in range(1, S + 2) for k in range(1, T + 1))) # Should never reach here as r, s, t are all odd, which the constructor should reject return Integer(0) @@ -2721,6 +2674,7 @@ class PlanePartitions_TCPP(PlanePartitions): Plane partitions that fit inside a box of a specified size that are transpose-complement. """ + def __init__(self, box_size): """ Initialize ``self``. @@ -2753,8 +2707,7 @@ def _repr_(self) -> str: sage: PlanePartitions([3,3,2], symmetry='TCPP') Transpose complement plane partitions inside a 3 x 3 x 2 box """ - return "Transpose complement plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) + return "Transpose complement plane partitions inside a {} x {} x {} box".format(self._box[0], self._box[1], self._box[2]) def __iter__(self) -> Iterator: r""" @@ -2793,11 +2746,7 @@ def cardinality(self) -> Integer: """ a = self._box[0] c = self._box[2] - return Integer(binomial(c // 2 + a - 1, a - 1) - * prod(c + i + j + 1 - for j in range(1, a - 1) for i in range(1, 1 + j)) - // prod(i + j + 1 - for j in range(1, a - 1) for i in range(1, 1 + j))) + return Integer(binomial(c // 2 + a - 1, a - 1) * prod(c + i + j + 1 for j in range(1, a - 1) for i in range(1, 1 + j)) // prod(i + j + 1 for j in range(1, a - 1) for i in range(1, 1 + j))) # Class 7 @@ -2807,6 +2756,7 @@ class PlanePartitions_SSCPP(PlanePartitions): Plane partitions that fit inside a box of a specified size that are symmetric self-complementary. """ + def __init__(self, box_size): """ Initialize ``self``. @@ -2831,7 +2781,7 @@ def __init__(self, box_size): """ if box_size[0] != box_size[1]: raise ValueError("x and y dimensions ({} and {}) must be equal".format(box_size[0], box_size[1])) - if (box_size[2] % 2 == 1): + if box_size[2] % 2 == 1: raise ValueError("z dimension ({}) must be even".format(box_size[2])) super().__init__(box_size, "SSCPP", category=FiniteEnumeratedSets()) @@ -2842,8 +2792,7 @@ def _repr_(self) -> str: sage: PlanePartitions([4, 4, 2], symmetry='SSCPP') Symmetric self-complementary plane partitions inside a 4 x 4 x 2 box """ - return "Symmetric self-complementary plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) + return "Symmetric self-complementary plane partitions inside a {} x {} x {} box".format(self._box[0], self._box[1], self._box[2]) def __iter__(self) -> Iterator: """ @@ -2900,14 +2849,8 @@ def cardinality(self) -> Integer: """ a = self._box[0] c = self._box[2] - num = prod(i + j + k - 1 - for i in range(1, 1 + a // 2) - for j in range(1, 1 + (a + 1) // 2) - for k in range(1, 1 + c // 2)) - den = prod(i + j + k - 2 - for i in range(1, 1 + a // 2) - for j in range(1, 1 + (a + 1) // 2) - for k in range(1, 1 + c // 2)) + num = prod(i + j + k - 1 for i in range(1, 1 + a // 2) for j in range(1, 1 + (a + 1) // 2) for k in range(1, 1 + c // 2)) + den = prod(i + j + k - 2 for i in range(1, 1 + a // 2) for j in range(1, 1 + (a + 1) // 2) for k in range(1, 1 + c // 2)) return Integer(num // den) @@ -2918,6 +2861,7 @@ class PlanePartitions_CSTCPP(PlanePartitions): Plane partitions that fit inside a box of a specified size that are cyclically symmetric and transpose-complement. """ + def __init__(self, box_size): """ TESTS:: @@ -2948,8 +2892,7 @@ def _repr_(self) -> str: sage: PlanePartitions([4,4,4], symmetry='CSTCPP') Cyclically symmetric transpose complement plane partitions inside a 4 x 4 x 4 box """ - return "Cyclically symmetric transpose complement plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) + return "Cyclically symmetric transpose complement plane partitions inside a {} x {} x {} box".format(self._box[0], self._box[1], self._box[2]) def __iter__(self) -> Iterator: """ @@ -2990,8 +2933,8 @@ def cardinality(self) -> Integer: 11 """ a = self._box[0] // 2 - num = prod((3*i + 1) * factorial(6*i) * factorial(2*i) for i in range(a)) - den = prod((factorial(4*i + 1) * factorial(4*i)) for i in range(a)) + num = prod((3 * i + 1) * factorial(6 * i) * factorial(2 * i) for i in range(a)) + den = prod((factorial(4 * i + 1) * factorial(4 * i)) for i in range(a)) return Integer(num // den) @@ -3002,6 +2945,7 @@ class PlanePartitions_CSSCPP(PlanePartitions): Plane partitions that fit inside a box of a specified size that are cyclically symmetric self-complementary. """ + def __init__(self, box_size): r""" Initialize ``self``. @@ -3032,8 +2976,7 @@ def _repr_(self) -> str: sage: PlanePartitions([4,4,4], symmetry='CSSCPP') Cyclically symmetric self-complementary plane partitions inside a 4 x 4 x 4 box """ - return "Cyclically symmetric self-complementary plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) + return "Cyclically symmetric self-complementary plane partitions inside a {} x {} x {} box".format(self._box[0], self._box[1], self._box[2]) def __iter__(self) -> Iterator: """ @@ -3067,8 +3010,8 @@ def cardinality(self) -> Integer: 49 """ a = self._box[0] // 2 - num = prod(factorial(3*i + 1)**2 for i in range(a)) - den = prod(factorial(a + i)**2 for i in range(a)) + num = prod(factorial(3 * i + 1) ** 2 for i in range(a)) + den = prod(factorial(a + i) ** 2 for i in range(a)) return Integer(num // den) @@ -3079,6 +3022,7 @@ class PlanePartitions_TSSCPP(PlanePartitions): Plane partitions that fit inside a box of a specified size that are totally symmetric self-complementary. """ + def __init__(self, box_size): """ TESTS:: @@ -3107,8 +3051,7 @@ def _repr_(self) -> str: sage: PlanePartitions([4,4,4], symmetry='TSSCPP') Totally symmetric self-complementary plane partitions inside a 4 x 4 x 4 box """ - return "Totally symmetric self-complementary plane partitions inside a {} x {} x {} box".format( - self._box[0], self._box[1], self._box[2]) + return "Totally symmetric self-complementary plane partitions inside a {} x {} x {} box".format(self._box[0], self._box[1], self._box[2]) def to_poset(self): r""" @@ -3124,6 +3067,7 @@ def to_poset(self): True """ from sage.combinat.posets.posets import Poset + a = self._box[0] b = self._box[1] c = self._box[2] @@ -3134,8 +3078,7 @@ def comp(x, y): return all(xx <= yy for xx, yy in zip(x, y)) A = a // 2 - pl = [(x, y, z) for x in range(A-1) for y in range(x, A-1) - for z in range(A-1) if z <= A - 2 - y] + pl = [(x, y, z) for x in range(A - 1) for y in range(x, A - 1) for z in range(A - 1) if z <= A - 2 - y] return Poset((pl, comp)) def from_antichain(self, acl) -> PP: @@ -3170,9 +3113,9 @@ def from_antichain(self, acl) -> PP: for ac in acl: if ac[0] == i and ac[1] == j: zVal = ac[2] - matrixVal = pp_matrix[j+N][i+N] + matrixVal = pp_matrix[j + N][i + N] if zVal + 1 > matrixVal: - pp_matrix[j+N][i+N] = zVal + 1 + pp_matrix[j + N][i + N] = zVal + 1 # fill back for i in range(width): @@ -3186,9 +3129,9 @@ def from_antichain(self, acl) -> PP: iValue = 0 jValue = 0 if i < n: - iValue = pp_matrix[i+1][j] + iValue = pp_matrix[i + 1][j] if j < n: - jValue = pp_matrix[i][j+1] + jValue = pp_matrix[i][j + 1] pp_matrix[i][j] = max(iValue, jValue) # fill half of triangle symmetrically @@ -3202,17 +3145,17 @@ def from_antichain(self, acl) -> PP: # upper left box for i in range(N): for j in range(N): - pp_matrix[i][j] = n - pp_matrix[n-(i+1)][n-(j+1)] + pp_matrix[i][j] = n - pp_matrix[n - (i + 1)][n - (j + 1)] # fill in lower left cube with values n/2 for i in range(N): for j in range(N): x = i y = j - if pp_matrix[x][y+N] == 0: - pp_matrix[x][y+N] = N - if pp_matrix[x+N][y] == 0: - pp_matrix[x+N][y] = N + if pp_matrix[x][y + N] == 0: + pp_matrix[x][y + N] = N + if pp_matrix[x + N][y] == 0: + pp_matrix[x + N][y] = N # add and subtract values from lower left cube to be rotation of lower right cube for i in range(N): @@ -3223,14 +3166,14 @@ def from_antichain(self, acl) -> PP: z = pp_matrix[x][y] for cVal in range(z): # build onto lower left cube - pp_matrix[x][0+cVal] += 1 + pp_matrix[x][0 + cVal] += 1 # carve out of lower left cube - pp_matrix[n-(1+cVal)][N-(j+1)] -= 1 + pp_matrix[n - (1 + cVal)][N - (j + 1)] -= 1 # fill in upper right cube symmetrically with lower left for i in range(N): for j in range(N): - pp_matrix[j][i+N] = pp_matrix[i+N][j] + pp_matrix[j][i + N] = pp_matrix[i + N][j] return self.element_class(self, pp_matrix) def from_order_ideal(self, I) -> PP: @@ -3285,6 +3228,6 @@ def cardinality(self) -> Integer: 7 """ a = self._box[0] // 2 - num = prod(factorial(3*i + 1) for i in range(a)) + num = prod(factorial(3 * i + 1) for i in range(a)) den = prod(factorial(a + i) for i in range(a)) return Integer(num // den) diff --git a/src/sage/combinat/posets/all.py b/src/sage/combinat/posets/all.py index b608b0094d1..b53bfcfd286 100644 --- a/src/sage/combinat/posets/all.py +++ b/src/sage/combinat/posets/all.py @@ -32,8 +32,10 @@ :class:`~sage.categories.lattice_posets.LatticePosets` and :class:`~sage.categories.finite_lattice_posets.FiniteLatticePosets`. """ + # install the docstring of this module to the containing package from sage.misc.namespace_package import install_doc + install_doc(__package__, __doc__) from sage.combinat.posets.posets import Poset diff --git a/src/sage/combinat/posets/bubble_shuffle.py b/src/sage/combinat/posets/bubble_shuffle.py index c728a318596..b04bc9c0970 100644 --- a/src/sage/combinat/posets/bubble_shuffle.py +++ b/src/sage/combinat/posets/bubble_shuffle.py @@ -14,6 +14,7 @@ In the implementation here, the underlying set is the set of all shuffles of subsets of `\{-m,\ldots,-1\}` with subsets of `\{1,\ldots,n\}`. """ + from collections.abc import Iterator from sage.categories.finite_lattice_posets import FiniteLatticePosets @@ -49,8 +50,7 @@ def bubble_cardinality(m, n) -> Integer: sage: bubble_cardinality(2,1) 12 """ - return ZZ.sum(ZZ(i + j).binomial(j) * ZZ(m).binomial(i) * ZZ(n).binomial(j) - for i in range(m + 1) for j in range(n + 1)) + return ZZ.sum(ZZ(i + j).binomial(j) * ZZ(m).binomial(i) * ZZ(n).binomial(j) for i in range(m + 1) for j in range(n + 1)) def bubble_set(m, n) -> Iterator[tuple[int, ...]]: @@ -120,7 +120,7 @@ def bubble_coverings(m, n, mot, transpose=True) -> Iterator[tuple[int, ...]]: # removal of one x for j, letter in enumerate(mot): if letter < 0: - yield tuple(mot[:j] + mot[j + 1:]) + yield tuple(mot[:j] + mot[j + 1 :]) # insertion of one y for j in range(len(mot) + 1): @@ -198,8 +198,7 @@ def ShufflePoset(m, n) -> FiniteLatticePoset: """ bubbles = list(bubble_set(m, n)) - dg = DiGraph([(x, y) for x in bubbles - for y in bubble_coverings(m, n, x, transpose=False)]) + dg = DiGraph([(x, y) for x in bubbles for y in bubble_coverings(m, n, x, transpose=False)]) # here we just have the cover relations cat = FiniteLatticePosets().ChainGraded() return LatticePoset(dg, cover_relations=True, check=False, category=cat) @@ -224,8 +223,7 @@ def noncrossing_bipartite_complex(m, n): """ vertices: list[tuple] = [("x", i) for i in range(1, m + 1)] vertices.extend(("y", i) for i in range(1, n + 1)) - vertices.extend(("xy", i, j) for i in range(m + 1) for j in range(n + 1) - if i or j) + vertices.extend(("xy", i, j) for i in range(m + 1) for j in range(n + 1) if i or j) def compatible(v: tuple, w: tuple) -> bool: if v == w: @@ -233,8 +231,7 @@ def compatible(v: tuple, w: tuple) -> bool: if v[0] != "xy" and w[0] != "xy": return True if v[0] == "xy" and w[0] == "xy": - return not ((w[1] < v[1] and w[2] > v[2]) - or (v[1] < w[1] and v[2] > w[2])) + return not ((w[1] < v[1] and w[2] > v[2]) or (v[1] < w[1] and v[2] > w[2])) if v[0] == "xy": if w[0] == "x": return v[1] != w[1] diff --git a/src/sage/combinat/posets/cartesian_product.py b/src/sage/combinat/posets/cartesian_product.py index 4eec3c6527e..d6727e638aa 100644 --- a/src/sage/combinat/posets/cartesian_product.py +++ b/src/sage/combinat/posets/cartesian_product.py @@ -5,6 +5,7 @@ - Daniel Krenn (2015) """ + # **************************************************************************** # Copyright (C) 2015 Daniel Krenn # @@ -106,6 +107,7 @@ def __init__(self, sets, category, order=None, **kwargs) -> None: from sage.categories.category import Category from sage.categories.posets import Posets + if not isinstance(category, tuple): category = (category,) category = Category.join(category + (Posets(),)) @@ -197,8 +199,7 @@ def le_lex(self, left, right): sage: R(((0, 1), 0)) <= R(((1, 0), 0)) False """ - for l, r, S in \ - zip(left.value, right.value, self.cartesian_factors()): + for l, r, S in zip(left.value, right.value, self.cartesian_factors()): if l == r: continue if S.le(l, r): @@ -250,10 +251,7 @@ def le_product(self, left, right): (1, 0) <= (0, 1) = False (1, 0) <= (1, 0) = True """ - return all( - S.le(l, r) - for l, r, S in - zip(left.value, right.value, self.cartesian_factors())) + return all(S.le(l, r) for l, r, S in zip(left.value, right.value, self.cartesian_factors())) def le_native(self, left, right): r""" @@ -382,11 +380,13 @@ def __le__(self, other): True """ from sage.structure.element import have_same_parent + if have_same_parent(self, other): return self._le_(other) from sage.structure.element import get_coercion_model import operator + try: return get_coercion_model().bin_op(self, other, operator.le) except TypeError: diff --git a/src/sage/combinat/posets/d_complete.py b/src/sage/combinat/posets/d_complete.py index 3fbb28a3878..b4c1415a53c 100644 --- a/src/sage/combinat/posets/d_complete.py +++ b/src/sage/combinat/posets/d_complete.py @@ -42,6 +42,7 @@ class DCompletePoset(FiniteJoinSemilattice): sage: P = Posets.DoubleTailedDiamond(2) sage: TestSuite(P).run() """ + _lin_ext_type = LinearExtensionsOfPosetWithHooks _desc = "Finite d-complete poset" @@ -125,8 +126,7 @@ def _hooks(self) -> dict: queue.append(c) enqueued.add(c) - return {self._vertex_to_element(key): ZZ(value) - for key, value in hooks.items()} + return {self._vertex_to_element(key): ZZ(value) for key, value in hooks.items()} def get_hook(self, elmt): r""" diff --git a/src/sage/combinat/posets/elements.py b/src/sage/combinat/posets/elements.py index b7d48b89437..c28ecfe1db6 100644 --- a/src/sage/combinat/posets/elements.py +++ b/src/sage/combinat/posets/elements.py @@ -125,8 +125,7 @@ def __eq__(self, other): # This should instead exploit unique representation, using # self is other, or best inherit __eq__ from there. But there # are issues around pickling and rich comparison functions. - return have_same_parent(self, other) \ - and self.vertex == other.vertex + return have_same_parent(self, other) and self.vertex == other.vertex def __ne__(self, other): r""" diff --git a/src/sage/combinat/posets/forest.py b/src/sage/combinat/posets/forest.py index 93281bdf73b..a11884afd44 100644 --- a/src/sage/combinat/posets/forest.py +++ b/src/sage/combinat/posets/forest.py @@ -25,5 +25,6 @@ class ForestPoset(FinitePoset): A forest poset is a poset where the underlying Hasse diagram and is directed acyclic graph. """ + _lin_ext_type = LinearExtensionsOfForest _desc = 'Finite forest poset' diff --git a/src/sage/combinat/posets/hasse_diagram.py b/src/sage/combinat/posets/hasse_diagram.py index aae73184871..277bb46b7c5 100644 --- a/src/sage/combinat/posets/hasse_diagram.py +++ b/src/sage/combinat/posets/hasse_diagram.py @@ -3,6 +3,7 @@ {INDEX_OF_FUNCTIONS} """ + # **************************************************************************** # Copyright (C) 2008 Peter Jipsen # Copyright (C) 2008 Franco Saliola @@ -30,9 +31,7 @@ if TYPE_CHECKING: from collections.abc import Iterator -lazy_import('sage.combinat.posets.hasse_cython_flint', - ['moebius_matrix_fast', 'coxeter_matrix_fast', - 'chain_poly']) +lazy_import('sage.combinat.posets.hasse_cython_flint', ['moebius_matrix_fast', 'coxeter_matrix_fast', 'chain_poly']) lazy_import('sage.matrix.constructor', 'matrix') lazy_import('sage.rings.finite_rings.finite_field_constructor', 'GF') @@ -95,6 +94,7 @@ class HasseDiagram(DiGraph): Hasse diagram of a poset containing 4 elements sage: TestSuite(H).run() """ + def _repr_(self) -> str: r""" TESTS:: @@ -132,6 +132,7 @@ def linear_extensions(self) -> Iterator[list[int]]: [[0, 1, 2, 3], [0, 2, 1, 3]] """ from sage.combinat.posets.linear_extension_iterator import linear_extension_iterator + return linear_extension_iterator(self) def greedy_linear_extensions_iterator(self) -> Iterator[list[int]]: @@ -172,13 +173,10 @@ def greedy_rec(H, linext): S = [] if linext: - S = [x for x in H.neighbor_out_iterator(linext[-1]) - if all(low in linext for low in H.neighbor_in_iterator(x))] + S = [x for x in H.neighbor_out_iterator(linext[-1]) if all(low in linext for low in H.neighbor_in_iterator(x))] if not S: S_ = set(self).difference(set(linext)) - S = [x for x in S_ - if not any(low in S_ - for low in self.neighbor_in_iterator(x))] + S = [x for x in S_ if not any(low in S_ for low in self.neighbor_in_iterator(x))] for e in S: yield from greedy_rec(H, linext + [e]) @@ -237,10 +235,7 @@ def supergreedy_rec(H, linext): if not k: # Start from new minimal element S = [x for x in self.sources() if x not in linext] else: - S = [x for x in self.neighbor_out_iterator(linext[k - 1]) - if x not in linext and - all(low in linext - for low in self.neighbor_in_iterator(x))] + S = [x for x in self.neighbor_out_iterator(linext[k - 1]) if x not in linext and all(low in linext for low in self.neighbor_in_iterator(x))] k -= 1 for e in S: @@ -264,8 +259,7 @@ def is_linear_extension(self, lin_ext=None) -> bool: if lin_ext is None or lin_ext == list(range(len(self))): return all(x < y for x, y in self.cover_relations_iterator()) indices = {x: lin_ext.index(x) for x in self} - return all(indices[x] < indices[y] - for x, y in self.cover_relations_iterator()) + return all(indices[x] < indices[y] for x, y in self.cover_relations_iterator()) def cover_relations_iterator(self) -> Iterator[tuple[int, int]]: r""" @@ -541,9 +535,7 @@ def is_chain(self) -> bool: """ if self.cardinality() == 0: return True - return (self.n_edges() + 1 == self.n_vertices() and # tree - all(d <= 1 for d in self.out_degree()) and - all(d <= 1 for d in self.in_degree())) + return self.n_edges() + 1 == self.n_vertices() and all(d <= 1 for d in self.out_degree()) and all(d <= 1 for d in self.in_degree()) # tree def is_antichain_of_poset(self, elms) -> bool: """ @@ -560,9 +552,9 @@ def is_antichain_of_poset(self, elms) -> bool: False """ from itertools import combinations + elms_sorted = sorted(set(elms)) - return not any(self.is_lequal(a, b) for a, b in - combinations(elms_sorted, 2)) + return not any(self.is_lequal(a, b) for a, b in combinations(elms_sorted, 2)) def dual(self): """ @@ -612,10 +604,8 @@ def _precompute_intervals(self) -> None: """ n = self.order() v_up = (frozenset(self.depth_first_search(v)) for v in range(n)) - v_down = [frozenset(self.depth_first_search(v, neighbors=self.neighbor_in_iterator)) - for v in range(n)] - self._intervals = [[sorted(up.intersection(down)) for down in v_down] - for up in v_up] + v_down = [frozenset(self.depth_first_search(v, neighbors=self.neighbor_in_iterator)) for v in range(n)] + self._intervals = [[sorted(up.intersection(down)) for down in v_down] for up in v_up] def interval(self, x, y) -> list[int]: r""" @@ -1116,9 +1106,7 @@ def moebius_function_matrix(self, algorithm='cython'): for k in greater_than[i]: if k != i: available.append(k) - m[(i, k)] = -ZZ.sum(m[(j, k)] - for j in available - if k in greater_than[j]) + m[(i, k)] = -ZZ.sum(m[(j, k)] for j in available if k in greater_than[j]) M = matrix(ZZ, n, n, m, sparse=True) # noqa: F821 elif algorithm == "matrix": M = self.lequal_matrix().inverse_of_unit() @@ -1195,7 +1183,7 @@ def coxeter_transformation(self, algorithm='cython'): ValueError: unknown algorithm """ if algorithm == 'matrix': - return - self.lequal_matrix() * self.moebius_function_matrix().transpose() + return -self.lequal_matrix() * self.moebius_function_matrix().transpose() if algorithm == 'cython': return coxeter_matrix_fast(self._leq_storage) # noqa: F821 raise ValueError("unknown algorithm") @@ -1240,8 +1228,7 @@ def order_ideal(self, elements) -> list[int]: sage: H.order_ideal([7,10]) [0, 1, 2, 3, 4, 5, 6, 7, 8, 10] """ - return sorted(self.depth_first_search(elements, - neighbors=self.neighbor_in_iterator)) + return sorted(self.depth_first_search(elements, neighbors=self.neighbor_in_iterator)) def order_ideal_cardinality(self, elements): r""" @@ -1452,9 +1439,7 @@ def add_elements(e): meet_prime = None for u in upset: for m in self.neighbor_in_iterator(u): - if (m not in upset and - all(u_ in upset for u_ in - self.neighbor_out_iterator(m))): + if m not in upset and all(u_ in upset for u_ in self.neighbor_out_iterator(m)): if meet_prime is not None: return meet_prime = m @@ -2079,10 +2064,7 @@ def orthocomplementations_iterator(self) -> Iterator[list[int]]: items = ((e, dual_isomorphism[e]) for e in range(n)) # Fix following after issue #20727 - comps = [[x for x in range(n) - if mt[e, x] == 0 and jn[e, x] == n - 1 and - x in orbits[orbit_number[dual_e]]] - for e, dual_e in items] + comps = [[x for x in range(n) if mt[e, x] == 0 and jn[e, x] == n - 1 and x in orbits[orbit_number[dual_e]]] for e, dual_e in items] # Fitting is done by this recursive function: def recursive_fit(orthocomplements, unbinded): @@ -2090,8 +2072,7 @@ def recursive_fit(orthocomplements, unbinded): yield orthocomplements else: next_to_fit = unbinded[0] - possible_values = [x for x in comps[next_to_fit] - if x not in orthocomplements] + possible_values = [x for x in comps[next_to_fit] if x not in orthocomplements] for x in self.lower_covers_iterator(next_to_fit): if orthocomplements[x] is not None: possible_values = [y for y in possible_values if self.has_edge(y, orthocomplements[x])] @@ -2230,8 +2211,7 @@ def antichains_iterator(self) -> Iterator[list[int]]: while queue: x = queue.pop() new_antichain = antichain + [x] - new_queue = [t for t in queue - if not (x in leq[t] or t in leq[x])] + new_queue = [t for t in queue if not (x in leq[t] or t in leq[x])] antichains_queues.append((new_antichain, new_queue)) def are_incomparable(self, i, j) -> bool: @@ -2321,9 +2301,8 @@ def antichains(self, element_class=list): sage: TestSuite(A).run() """ from sage.combinat.subsets_pairwise import PairwiseCompatibleSubsets - return PairwiseCompatibleSubsets(self.vertices(sort=True), - self.are_incomparable, - element_class=element_class) + + return PairwiseCompatibleSubsets(self.vertices(sort=True), self.are_incomparable, element_class=element_class) def chains(self, element_class=list, exclude=None, conversion=None): """ @@ -2495,8 +2474,7 @@ def is_linear_interval(self, t_min, t_max) -> bool: return True # fall back to default implementation - it = self.all_paths_iterator([t_min], [t_max], - simple=True, trivial=True) + it = self.all_paths_iterator([t_min], [t_max], simple=True, trivial=True) try: next(it) except StopIteration: # not comparable @@ -2545,7 +2523,7 @@ def diamonds(self) -> tuple[list[tuple[int, int, int, int]], bool]: for w in self.vertices(sort=True): covers = self.neighbors_out(w) for i, x in enumerate(covers): - for y in covers[i + 1:]: + for y in covers[i + 1 :]: zs = self.common_upper_covers([x, y]) if len(zs) != 1: all_diamonds_completed = False @@ -2807,8 +2785,7 @@ def frattini_sublattice(self) -> list[int]: if n == 1: return [0] max_sublats = self.maximal_sublattices() - return [e for e in range(self.cardinality()) if - all(e in ms for ms in max_sublats)] + return [e for e in range(self.cardinality()) if all(e in ms for ms in max_sublats)] def kappa_dual(self, a) -> int | None: r""" @@ -2981,8 +2958,8 @@ def is_convex_subset(self, S) -> bool: # Now b not in S, b > a and a in S. def neighbors(v_): - return [v for v in self.neighbor_out_iterator(v_) - if v <= s_max and v not in ok] + return [v for v in self.neighbor_out_iterator(v_) if v <= s_max and v not in ok] + for c in self.depth_first_search(b, neighbors=neighbors): if c in S: # Now c in S, b not in S, a in S, a < b < c. return False @@ -3046,27 +3023,23 @@ def is_neutral(a) -> bool: meet_ax = mt[a, x] join_ax = jn[a, x] for y in todo: - if (mt[mt[join_ax, jn[a, y]], jn[x, y]] != - jn[jn[meet_ax, mt[a, y]], mt[x, y]]): + if mt[mt[join_ax, jn[a, y]], jn[x, y]] != jn[jn[meet_ax, mt[a, y]], mt[x, y]]: notneutrals.add(x) notneutrals.add(y) return False for y in notneutrals: - if (mt[mt[join_ax, jn[a, y]], jn[x, y]] != - jn[jn[meet_ax, mt[a, y]], mt[x, y]]): + if mt[mt[join_ax, jn[a, y]], jn[x, y]] != jn[jn[meet_ax, mt[a, y]], mt[x, y]]: notneutrals.add(x) return False for x in noncomp.difference(todo): meet_ax = mt[a, x] join_ax = jn[a, x] for y in todo: - if (mt[mt[join_ax, jn[a, y]], jn[x, y]] != - jn[jn[meet_ax, mt[a, y]], mt[x, y]]): + if mt[mt[join_ax, jn[a, y]], jn[x, y]] != jn[jn[meet_ax, mt[a, y]], mt[x, y]]: notneutrals.add(y) return False for y in notneutrals: - if (mt[mt[join_ax, jn[a, y]], jn[x, y]] != - jn[jn[meet_ax, mt[a, y]], mt[x, y]]): + if mt[mt[join_ax, jn[a, y]], jn[x, y]] != jn[jn[meet_ax, mt[a, y]], mt[x, y]]: return False return True diff --git a/src/sage/combinat/posets/hochschild_lattice.py b/src/sage/combinat/posets/hochschild_lattice.py index 4e423e46e17..dd9d12a4428 100644 --- a/src/sage/combinat/posets/hochschild_lattice.py +++ b/src/sage/combinat/posets/hochschild_lattice.py @@ -16,6 +16,7 @@ The underlying set of `H_n` consists of some words in the alphabet `(0,1,2)`, whose precise description can be found in [Com2021]_. """ + from collections.abc import Iterator from sage.categories.finite_lattice_posets import FiniteLatticePosets @@ -100,10 +101,8 @@ def cover_relations(a): yield tb break - dg = DiGraph({a: list(cover_relations(a)) for a in verts}, - format="dict_of_lists") - return LatticePoset(dg.reverse(), cover_relations=True, check=False, - category=FiniteLatticePosets().CongruenceUniform()) + dg = DiGraph({a: list(cover_relations(a)) for a in verts}, format="dict_of_lists") + return LatticePoset(dg.reverse(), cover_relations=True, check=False, category=FiniteLatticePosets().CongruenceUniform()) def hochschild_fan(n): @@ -130,18 +129,16 @@ def hochschild_fan(n): from sage.modules.free_module_element import vector rays = [vector([1] * n)] - rays.extend(vector([0 if j != i else -1 for j in range(n)]) - for i in range(n)) + rays.extend(vector([0 if j != i else -1 for j in range(n)]) for i in range(n)) - cones = [Cone([rays[j] for j in range(n + 1) if j != i]) - for i in range(n + 1)] + cones = [Cone([rays[j] for j in range(n + 1) if j != i]) for i in range(n + 1)] # standard fan of projective space Pn F = Fan(cones, check=False) # double sequence of blowups - subdiv = [sum(r for r in rays[k + 1:]) for k in range(n - 1)] - subdiv.extend(sum(r for r in rays[:n - k]) for k in range(n - 1)) + subdiv = [sum(r for r in rays[k + 1 :]) for k in range(n - 1)] + subdiv.extend(sum(r for r in rays[: n - k]) for k in range(n - 1)) return F.subdivide(subdiv) diff --git a/src/sage/combinat/posets/incidence_algebras.py b/src/sage/combinat/posets/incidence_algebras.py index f464fe52fa3..73e4861bd2b 100644 --- a/src/sage/combinat/posets/incidence_algebras.py +++ b/src/sage/combinat/posets/incidence_algebras.py @@ -52,6 +52,7 @@ class IncidenceAlgebra(CombinatorialFreeModule): - :wikipedia:`Incidence_algebra` """ + def __init__(self, R, P, prefix='I') -> None: """ Initialize ``self``. @@ -66,8 +67,7 @@ def __init__(self, R, P, prefix='I') -> None: if P in FiniteEnumeratedSets(): cat = cat.FiniteDimensional() self._poset = P - CombinatorialFreeModule.__init__(self, R, map(tuple, P.relations()), - prefix=prefix, category=cat) + CombinatorialFreeModule.__init__(self, R, map(tuple, P.relations()), prefix=prefix, category=cat) def _repr_term(self, A) -> str: """ @@ -295,6 +295,7 @@ class Element(CombinatorialFreeModule.Element): """ An element of an incidence algebra. """ + def __call__(self, x, y): """ Return ``self(x, y)``. @@ -424,9 +425,7 @@ def __invert__(self): raise ValueError("element is not invertible") inv = ~M L = self.parent()._linear_extension - return self.parent().sum_of_terms( - ((L[i], L[j]), inv[i, j]) - for i, j in inv.nonzero_positions(copy=False)) + return self.parent().sum_of_terms(((L[i], L[j]), inv[i, j]) for i, j in inv.nonzero_positions(copy=False)) class ReducedIncidenceAlgebra(CombinatorialFreeModule): @@ -438,6 +437,7 @@ class ReducedIncidenceAlgebra(CombinatorialFreeModule): `[x, y]` is isomorphic to `[x', y']` as posets. Thus the delta, Möbius, and zeta functions are all elements of `R_P`. """ + def __init__(self, I, prefix='R') -> None: """ Initialize ``self``. @@ -466,9 +466,7 @@ def __init__(self, I, prefix='R') -> None: equiv_classes = map(sorted, EC.values()) self._equiv_classes = {cls[0]: cls for cls in equiv_classes} cat = Algebras(I.base_ring()).FiniteDimensional().WithBasis() - CombinatorialFreeModule.__init__(self, I.base_ring(), - sorted(self._equiv_classes.keys()), - prefix=prefix, category=cat) + CombinatorialFreeModule.__init__(self, I.base_ring(), sorted(self._equiv_classes.keys()), prefix=prefix, category=cat) def _repr_(self) -> str: r""" @@ -690,6 +688,7 @@ class Element(CombinatorialFreeModule.Element): """ An element of a reduced incidence algebra. """ + def __call__(self, x, y): """ Return ``self(x, y)``. diff --git a/src/sage/combinat/posets/lattices.py b/src/sage/combinat/posets/lattices.py index d891b15e9c5..ef48cb2d16a 100644 --- a/src/sage/combinat/posets/lattices.py +++ b/src/sage/combinat/posets/lattices.py @@ -150,14 +150,13 @@ from itertools import repeat from sage.categories.finite_lattice_posets import FiniteLatticePosets from sage.combinat.posets.posets import Poset, FinitePoset -from sage.combinat.posets.elements import (LatticePosetElement, - MeetSemilatticeElement, - JoinSemilatticeElement) +from sage.combinat.posets.elements import LatticePosetElement, MeetSemilatticeElement, JoinSemilatticeElement from sage.combinat.posets.hasse_diagram import LatticeError ############################################################################ + def MeetSemilattice(data=None, *args, **options): r""" Construct a meet semi-lattice from various forms of input data. @@ -231,6 +230,7 @@ class FiniteMeetSemilattice(FinitePoset): sage: M = MeetSemilattice(P) sage: TestSuite(M).run() """ + Element = MeetSemilatticeElement _desc = 'Finite meet-semilattice' @@ -481,6 +481,7 @@ def pseudocomplement(self, element): return None return self._vertex_to_element(e) + ############################################################################ @@ -556,6 +557,7 @@ class FiniteJoinSemilattice(FinitePoset): sage: J = JoinSemilattice(P) sage: TestSuite(J).run() """ + Element = JoinSemilatticeElement _desc = 'Finite join-semilattice' @@ -662,6 +664,7 @@ def coatoms(self): return [] return self.lower_covers(self.top()) + ############################################################################### @@ -736,6 +739,7 @@ def LatticePoset(data=None, *args, **options): error.y = P._vertex_to_element(error.y) raise from sage.categories.posets import Posets + cat = Posets().or_subcategory(options.get('category', None)) cat = cat & FiniteLatticePosets() return FiniteLatticePoset(P, category=cat, facade=P._is_facade) @@ -758,6 +762,7 @@ class FiniteLatticePoset(FiniteMeetSemilattice, FiniteJoinSemilattice): sage: L = LatticePoset(P) sage: TestSuite(L).run() """ + Element = LatticePosetElement def _repr_(self) -> str: @@ -811,8 +816,7 @@ def double_irreducibles(self) -> list: [] """ H = self._hasse_diagram - return [self._vertex_to_element(e) for e in H - if H.in_degree(e) == 1 and H.out_degree(e) == 1] + return [self._vertex_to_element(e) for e in H if H.in_degree(e) == 1 and H.out_degree(e) == 1] def join_primes(self) -> list: r""" @@ -848,8 +852,7 @@ def join_primes(self) -> list: sage: posets.DiamondPoset(5).join_primes() [] """ - return [self._vertex_to_element(v) for - v in self._hasse_diagram.prime_elements()[0]] + return [self._vertex_to_element(v) for v in self._hasse_diagram.prime_elements()[0]] def meet_primes(self) -> list: r""" @@ -885,8 +888,7 @@ def meet_primes(self) -> list: sage: posets.DiamondPoset(5).meet_primes() [] """ - return [self._vertex_to_element(v) for - v in self._hasse_diagram.prime_elements()[1]] + return [self._vertex_to_element(v) for v in self._hasse_diagram.prime_elements()[1]] def neutral_elements(self) -> list: r""" @@ -992,8 +994,7 @@ def is_join_distributive(self, certificate=False) -> bool | tuple: sage: L.is_join_distributive(certificate=True) (False, 2) """ - if ((self.is_ranked() and len(self.meet_irreducibles()) == self.rank()) or - self.cardinality() == 0): + if (self.is_ranked() and len(self.meet_irreducibles()) == self.rank()) or self.cardinality() == 0: return (True, None) if certificate else True if not certificate: return False @@ -1005,6 +1006,7 @@ def is_join_distributive(self, certificate=False) -> bool | tuple: return (False, self.meet(result[1])) from sage.graphs.digraph import DiGraph + M3 = DiGraph({0: [1, 2, 3], 1: [4], 2: [4], 3: [4]}) diamond = next(self._hasse_diagram.subgraph_search_iterator(M3, return_graphs=False)) return (False, self[diamond[0]]) @@ -1080,8 +1082,7 @@ def is_meet_distributive(self, certificate=False) -> bool | tuple: sage: L.is_meet_distributive(certificate=True) (False, 6) """ - if ((self.is_ranked() and len(self.join_irreducibles()) == self.rank()) or - self.cardinality() == 0): + if (self.is_ranked() and len(self.join_irreducibles()) == self.rank()) or self.cardinality() == 0: return (True, None) if certificate else True if not certificate: return False @@ -1093,6 +1094,7 @@ def is_meet_distributive(self, certificate=False) -> bool | tuple: return (False, self.join(result[1])) from sage.graphs.digraph import DiGraph + M3 = DiGraph({0: [1, 2, 3], 1: [4], 2: [4], 3: [4]}) diamond = next(self._hasse_diagram.subgraph_search_iterator(M3, return_graphs=False)) return (False, self[diamond[4]]) @@ -1162,6 +1164,7 @@ def is_stone(self, certificate=False) -> bool | tuple: return (False, None) if certificate else False from sage.arith.misc import factor + ok = (True, None) if certificate else True # Needed for the empty lattice that has no bottom element. @@ -1252,9 +1255,7 @@ def is_distributive(self, certificate=False) -> bool | tuple: if self.cardinality() == 0: return ok - if (self.is_graded() and - self.rank() == len(self.join_irreducibles()) == - len(self.meet_irreducibles())): + if self.is_graded() and self.rank() == len(self.join_irreducibles()) == len(self.meet_irreducibles()): return ok if not certificate: @@ -1265,9 +1266,7 @@ def is_distributive(self, certificate=False) -> bool | tuple: return (False, (cert[2], cert[1], cert[0])) M3 = DiGraph({0: [1, 2, 3], 1: [4], 2: [4], 3: [4]}) diamond = next(self._hasse_diagram.subgraph_search_iterator(M3, return_graphs=False)) - return (False, (self._vertex_to_element(diamond[1]), - self._vertex_to_element(diamond[2]), - self._vertex_to_element(diamond[3]))) + return (False, (self._vertex_to_element(diamond[1]), self._vertex_to_element(diamond[2]), self._vertex_to_element(diamond[3]))) def is_semidistributive(self) -> bool: """ @@ -1311,9 +1310,7 @@ def is_semidistributive(self) -> bool: """ H = self._hasse_diagram # See trac #21528 for explanation. - return ((H.in_degree_sequence().count(1) == - H.out_degree_sequence().count(1)) and - self.is_meet_semidistributive()) + return (H.in_degree_sequence().count(1) == H.out_degree_sequence().count(1)) and self.is_meet_semidistributive() def is_meet_semidistributive(self, certificate=False) -> bool | tuple: r""" @@ -1399,10 +1396,7 @@ def is_meet_semidistributive(self, certificate=False) -> bool | tuple: x = tmp[0] for y in tmp: if H.are_incomparable(x, y): - return (False, - (self._vertex_to_element(v), - self._vertex_to_element(x), - self._vertex_to_element(y))) + return (False, (self._vertex_to_element(v), self._vertex_to_element(x), self._vertex_to_element(y))) if certificate: return (True, None) return True @@ -1492,16 +1486,12 @@ def is_join_semidistributive(self, certificate=False) -> bool | tuple: x = tmp[0] for y in tmp: if H.are_incomparable(x, y): - return (False, - (self._vertex_to_element(v), - self._vertex_to_element(x), - self._vertex_to_element(y))) + return (False, (self._vertex_to_element(v), self._vertex_to_element(x), self._vertex_to_element(y))) if certificate: return (True, None) return True - return all(H.kappa_dual(v) is not None - for v in H if H.out_degree(v) == 1) + return all(H.kappa_dual(v) is not None for v in H if H.out_degree(v) == 1) def is_extremal(self) -> bool: """ @@ -1897,9 +1887,7 @@ def is_relatively_complemented(self, certificate=False) -> bool | tuple: for e2 in H.neighbor_in_iterator(e3): if e2 in H.neighbor_out_iterator(e1): break - return (False, (self._vertex_to_element(e1), - self._vertex_to_element(e2), - self._vertex_to_element(e3))) + return (False, (self._vertex_to_element(e1), self._vertex_to_element(e2), self._vertex_to_element(e3))) return (True, None) if certificate else True def is_sectionally_complemented(self, certificate=False) -> bool | tuple: @@ -2071,21 +2059,17 @@ def join(L): continue # Get elements more than B levels below it. - too_close = set(H.breadth_first_search(j, - neighbors=H.neighbor_in_iterator, - distance=B - 2)) + too_close = set(H.breadth_first_search(j, neighbors=H.neighbor_in_iterator, distance=B - 2)) elems = [e for e in H.order_ideal([j]) if e not in too_close] - achains = PairwiseCompatibleSubsets(elems, - H.are_incomparable) + achains = PairwiseCompatibleSubsets(elems, H.are_incomparable) achains_n = achains.elements_of_depth_iterator(B) for A in achains_n: if join(A) == j: - if all(join(A[:i] + A[i + 1:]) != j for i in range(B)): + if all(join(A[:i] + A[i + 1 :]) != j for i in range(B)): if certificate: - return (B, [self._vertex_to_element(e) - for e in A]) + return (B, [self._vertex_to_element(e) for e in A]) return B raise RuntimeError("BUG: breadth() in lattices.py have an error") @@ -2162,16 +2146,13 @@ def complements(self, element=None): comps = {} for i in range(n): if c[i]: - comps[self._vertex_to_element(i)] = ( - [self._vertex_to_element(x) for x in c[i]]) + comps[self._vertex_to_element(i)] = [self._vertex_to_element(x) for x in c[i]] return comps # Looking for complements of one element. if element not in self: raise ValueError("element (=%s) not in poset" % element) - return [x for x in self - if self.meet(x, element) == self.bottom() and - self.join(x, element) == self.top()] + return [x for x in self if self.meet(x, element) == self.bottom() and self.join(x, element) == self.top()] def is_pseudocomplemented(self, certificate=False) -> bool | tuple: r""" @@ -2347,10 +2328,8 @@ def skeleton(self): # given linear extension? if self.cardinality() < 3: return self - elms = [self._vertex_to_element(v) for v in - self._hasse_diagram.skeleton()] - return LatticePoset(self.subposet(elms), - category=FiniteLatticePosets().Stone()) + elms = [self._vertex_to_element(v) for v in self._hasse_diagram.skeleton()] + return LatticePoset(self.subposet(elms), category=FiniteLatticePosets().Stone()) def is_orthocomplemented(self, unique=False) -> bool: """ @@ -2457,9 +2436,7 @@ def is_atomic(self, certificate=False) -> bool | tuple: - Mutually exclusive properties: :meth:`is_vertically_decomposable` """ if not certificate: - return (self.cardinality() == 0 or - self._hasse_diagram.out_degree(0) == - self._hasse_diagram.in_degree().count(1)) + return self.cardinality() == 0 or self._hasse_diagram.out_degree(0) == self._hasse_diagram.in_degree().count(1) if self.cardinality() < 3: return (True, None) H = self._hasse_diagram @@ -2515,8 +2492,7 @@ def is_coatomic(self, certificate=False) -> bool | tuple: if not certificate: if n == 0: return True - return (self._hasse_diagram.in_degree(n - 1) == - self._hasse_diagram.out_degree().count(1)) + return self._hasse_diagram.in_degree(n - 1) == self._hasse_diagram.out_degree().count(1) if self.cardinality() < 3: return (True, None) @@ -2733,8 +2709,7 @@ def is_modular(self, L=None, certificate=False) -> bool | tuple: for b in L: for x in self.principal_lower_set(b): for a in self: - if (self.join(x, self.meet(a, b)) != - self.meet(self.join(x, a), b)): + if self.join(x, self.meet(a, b)) != self.meet(self.join(x, a), b): if certificate: return (False, (x, a, b)) return False @@ -2805,9 +2780,7 @@ def is_left_modular_element(self, x) -> bool: - :meth:`is_left_modular` """ - return all(self.meet(self.join(y, x), z) == - self.join(y, self.meet(x, z)) - for y, z in self.cover_relations_iterator()) + return all(self.meet(self.join(y, x), z) == self.join(y, self.meet(x, z)) for y, z in self.cover_relations_iterator()) def is_upper_semimodular(self, certificate=False) -> bool | tuple: r""" @@ -2865,8 +2838,7 @@ def is_upper_semimodular(self, certificate=False) -> bool | tuple: if nonmodular is None: return (True, None) if certificate else True if certificate: - return (False, (self._vertex_to_element(nonmodular[0]), - self._vertex_to_element(nonmodular[1]))) + return (False, (self._vertex_to_element(nonmodular[0]), self._vertex_to_element(nonmodular[1]))) return False def is_lower_semimodular(self, certificate=False) -> bool | tuple: @@ -2920,8 +2892,7 @@ def is_lower_semimodular(self, certificate=False) -> bool | tuple: if nonmodular is None: return (True, None) if certificate else True if certificate: - return (False, (self._vertex_to_element(nonmodular[0]), - self._vertex_to_element(nonmodular[1]))) + return (False, (self._vertex_to_element(nonmodular[0]), self._vertex_to_element(nonmodular[1]))) return False def is_supersolvable(self, certificate=False) -> bool | tuple: @@ -3003,9 +2974,7 @@ def is_supersolvable(self, certificate=False) -> bool | tuple: @cached_function def is_modular_elt(a) -> bool: - return all(H._rank[a] + H._rank[b] == - H._rank[mt[a, b]] + H._rank[jn[a, b]] - for b in range(n)) + return all(H._rank[a] + H._rank[b] == H._rank[mt[a, b]] + H._rank[jn[a, b]] for b in range(n)) if not is_modular_elt(cur): return not_ok @@ -3112,8 +3081,7 @@ def vertical_composition(self, other, labels='pairs'): n = max(g_self.order(), 1) # max() takes care of empty 'self'. g_other.relabel(lambda v: v + n - 1) g_result = g_self.union(g_other) - return FiniteLatticePoset(g_result, elements=range(g_result.order()), - facade=self._is_facade, category=FiniteLatticePosets()) + return FiniteLatticePoset(g_result, elements=range(g_result.order()), facade=self._is_facade, category=FiniteLatticePosets()) if self.cardinality() == 0: return other.relabel(lambda e: (1, e)) @@ -3169,16 +3137,10 @@ def vertical_decomposition(self, elements_only=False): return [self] return [] if elements_only: - return [self[e] for e in - self._hasse_diagram.vertical_decomposition(return_list=True)] - elms = ([0] + - self._hasse_diagram.vertical_decomposition(return_list=True) + - [self.cardinality() - 1]) + return [self[e] for e in self._hasse_diagram.vertical_decomposition(return_list=True)] + elms = [0] + self._hasse_diagram.vertical_decomposition(return_list=True) + [self.cardinality() - 1] n = len(elms) - return [LatticePoset(self.subposet([self[e] - for e in range(elms[i], - elms[i + 1] + 1)])) - for i in range(n - 1)] + return [LatticePoset(self.subposet([self[e] for e in range(elms[i], elms[i + 1] + 1)])) for i in range(n - 1)] def is_vertically_decomposable(self, certificate=False) -> bool | tuple: r""" @@ -3335,7 +3297,7 @@ def is_sublattice(self, other) -> bool: try: o_meet = other.meet o_join = other.join - except (AttributeError): + except AttributeError: raise TypeError('other is not a lattice') if not self.is_induced_subposet(other): return False @@ -3343,8 +3305,7 @@ def is_sublattice(self, other) -> bool: n = self.cardinality() for i in range(n): for j in range(i): - if (o_meet(self[i], self[j]) not in self or - o_join(self[i], self[j]) not in self): + if o_meet(self[i], self[j]) not in self or o_join(self[i], self[j]) not in self: return False return True @@ -3377,8 +3338,7 @@ def sublattices(self): sage: [len(posets.ChainPoset(n).sublattices()) for n in range(4)] [1, 2, 4, 8] """ - return [LatticePoset(self.subposet(map(self._vertex_to_element, elms))) - for elms in self._hasse_diagram.sublattices_iterator(set(), 0)] + return [LatticePoset(self.subposet(map(self._vertex_to_element, elms))) for elms in self._hasse_diagram.sublattices_iterator(set(), 0)] def sublattices_lattice(self, labels='lattice'): """ @@ -3487,6 +3447,7 @@ def isomorphic_sublattices_iterator(self, other): 5 """ from itertools import combinations + if not isinstance(other, FiniteLatticePoset): raise TypeError('the input is not a finite lattice') H = self._hasse_diagram @@ -3546,8 +3507,7 @@ def frattini_sublattice(self): sage: sorted(L.frattini_sublattice().list()) [1, 2, 4, 10, 19, 22, 33] """ - return LatticePoset(self.subposet([self[x] - for x in self._hasse_diagram.frattini_sublattice()])) + return LatticePoset(self.subposet([self[x] for x in self._hasse_diagram.frattini_sublattice()])) def moebius_algebra(self, R): """ @@ -3562,6 +3522,7 @@ def moebius_algebra(self, R): Moebius algebra of Finite lattice containing 16 elements over Rational Field """ from sage.combinat.posets.moebius_algebra import MoebiusAlgebra + return MoebiusAlgebra(R, self) def quantum_moebius_algebra(self, q=None): @@ -3582,6 +3543,7 @@ def quantum_moebius_algebra(self, q=None): with q=q over Univariate Laurent Polynomial Ring in q over Integer Ring """ from sage.combinat.posets.moebius_algebra import QuantumMoebiusAlgebra + return QuantumMoebiusAlgebra(self, q) def day_doubling(self, S): @@ -3770,8 +3732,7 @@ def center(self): """ neutrals = self.neutral_elements() comps = self.complements() - return self.sublattice([e for e in neutrals if e in comps], - category=FiniteLatticePosets().Stone()) + return self.sublattice([e for e in neutrals if e in comps], category=FiniteLatticePosets().Stone()) def is_dismantlable(self, certificate=False) -> bool | tuple: r""" @@ -3877,8 +3838,7 @@ def is_dismantlable(self, certificate=False) -> bool | tuple: return False k = 3 while True: - crown = DiGraph({i: [k + i, k + (i + 1) % k] - for i in range(k)}) + crown = DiGraph({i: [k + i, k + (i + 1) % k] for i in range(k)}) sg = H.transitive_closure().subgraph_search(crown, True) if sg: elms = [self[e] for e in sg] @@ -3949,6 +3909,7 @@ def is_interval_dismantlable(self, certificate=False) -> bool | tuple: sage: LatticePoset().is_interval_dismantlable(certificate=True) (True, []) """ + def minimal_non_int_dismant(L): """ Return a minimally interval non-dismantlable sublattice. @@ -4064,13 +4025,10 @@ def is_sublattice_dismantlable(self) -> bool: continue S1 = self.interval(low, up) S2 = [e for e in self if e not in S1] - if all(self.meet(a, b) in S2 and - self.join(a, b) in S2 - for a, b in Subsets(S2, 2)): + if all(self.meet(a, b) in S2 and self.join(a, b) in S2 for a, b in Subsets(S2, 2)): sub1 = self.sublattice(S1) sub2 = self.sublattice(S2) - return (sub1.is_sublattice_dismantlable() and - sub2.is_sublattice_dismantlable()) + return sub1.is_sublattice_dismantlable() and sub2.is_sublattice_dismantlable() return False @@ -4146,8 +4104,7 @@ def is_subdirectly_reducible(self, certificate=False) -> bool | tuple: for a in A[0]: if len(a) > 1: x, y = min(a), max(a) - return (False, (self._vertex_to_element(x), - self._vertex_to_element(y))) + return (False, (self._vertex_to_element(x), self._vertex_to_element(y))) H_closure = H.transitive_closure() a0 = [min(v) for v in A[0]] @@ -4383,8 +4340,7 @@ def is_constructible_by_doublings(self, type) -> bool: if self.cardinality() < 5: return True - if (type == 'interval' and len(self.join_irreducibles()) != - len(self.meet_irreducibles())): + if type == 'interval' and len(self.join_irreducibles()) != len(self.meet_irreducibles()): return False if type == 'upper' or type == 'interval': @@ -4527,8 +4483,8 @@ def is_isoform(self, certificate=False) -> bool | tuple: if not H.subgraph(part).is_isomorphic(d): if certificate: from sage.combinat.set_partition import SetPartition - return (False, - SetPartition([[self._vertex_to_element(v) for v in p] for p in cong])) + + return (False, SetPartition([[self._vertex_to_element(v) for v in p] for p in cong])) return False return ok @@ -4607,8 +4563,8 @@ def is_uniform(self, certificate=False) -> bool | tuple: if len(part) != n: if certificate: from sage.combinat.set_partition import SetPartition - return (False, - SetPartition([[self._vertex_to_element(v) for v in p] for p in c])) + + return (False, SetPartition([[self._vertex_to_element(v) for v in p] for p in c])) return False return ok @@ -4674,9 +4630,8 @@ def is_regular(self, certificate=False) -> bool | tuple: if H.congruence([part]) != cong: if certificate: from sage.combinat.set_partition import SetPartition - return (False, - (SetPartition([[self._vertex_to_element(v) for v in p] for p in cong]), - [self._vertex_to_element(v) for v in part])) + + return (False, (SetPartition([[self._vertex_to_element(v) for v in p] for p in cong]), [self._vertex_to_element(v) for v in part])) return False return ok @@ -4737,13 +4692,13 @@ def is_simple(self, certificate=False) -> bool | tuple: [True, True, True, False, False] """ from sage.combinat.set_partition import SetPartition + cong = self._hasse_diagram.find_nontrivial_congruence() if cong is None: return (True, None) if certificate else True if not certificate: return False - return (False, SetPartition([[self._vertex_to_element(v) for v in s] - for s in cong])) + return (False, SetPartition([[self._vertex_to_element(v) for v in s] for s in cong])) def subdirect_decomposition(self): r""" @@ -4894,10 +4849,10 @@ def congruence(self, S): {{0, 1, 2, 3, 4, 5, 6, 7}} """ from sage.combinat.set_partition import SetPartition + S = [[self._element_to_vertex(e) for e in s] for s in S] cong = self._hasse_diagram.congruence(S) - return SetPartition([[self._vertex_to_element(v) for v in s] - for s in cong]) + return SetPartition([[self._vertex_to_element(v) for v in s] for s in cong]) def quotient(self, congruence, labels='tuple'): r""" @@ -4964,15 +4919,13 @@ def quotient(self, congruence, labels='tuple'): if labels not in ['lattice', 'tuple', 'integer']: raise ValueError("labels must be one of 'lattice', 'tuple' or 'integer'") - parts_H = [sorted([self._element_to_vertex(e) for e in part]) for - part in congruence] + parts_H = [sorted([self._element_to_vertex(e) for e in part]) for part in congruence] minimal_vertices = [part[0] for part in parts_H] H = self._hasse_diagram.transitive_closure().subgraph(minimal_vertices).transitive_reduction(immutable=False) if labels == 'integer': H.relabel() return LatticePoset(H) - part_dict = {m[0]: [self._vertex_to_element(x) for x in m] for m - in parts_H} + part_dict = {m[0]: [self._vertex_to_element(x) for x in m] for m in parts_H} if labels == 'tuple': H.relabel(lambda m: tuple(part_dict[m])) return LatticePoset(H) @@ -5033,6 +4986,7 @@ def congruences_lattice(self, labels='congruence'): from sage.sets.set import Set from sage.sets.disjoint_set import DisjointSet from sage.combinat.set_partition import SetPartition + if labels not in ['integer', 'congruence']: raise ValueError("'labels' must be 'integer' or 'congruence'") @@ -5060,8 +5014,7 @@ def congruences_lattice(self, labels='congruence'): break C[e] = self._hasse_diagram.congruence([new_pair], start=C[low_0]) - return L.relabel(lambda e: SetPartition([[self._vertex_to_element(v) - for v in p] for p in C[e]])) + return L.relabel(lambda e: SetPartition([[self._vertex_to_element(v) for v in p] for p in C[e]])) def feichtner_yuzvinsky_ring(self, G, use_defining=False, base_ring=None): r""" @@ -5132,6 +5085,7 @@ def feichtner_yuzvinsky_ring(self, G, use_defining=False, base_ring=None): """ if base_ring is None: from sage.rings.rational_field import QQ + base_ring = QQ G = tuple(G) @@ -5141,11 +5095,11 @@ def feichtner_yuzvinsky_ring(self, G, use_defining=False, base_ring=None): GP = self.subposet(G) from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + if use_defining: R = PolynomialRing(base_ring, 'x', len(G)) gens = R.gens() - gens = [R.sum(gens[Gmap[gp]] for gp in GP.order_filter([g])) - for g in G] + gens = [R.sum(gens[Gmap[gp]] for gp in GP.order_filter([g])) for g in G] else: R = PolynomialRing(base_ring, 'h', len(G)) gens = R.gens() @@ -5202,4 +5156,4 @@ def _log_2(n): FiniteMeetSemilattice._dual_class = FiniteJoinSemilattice FiniteJoinSemilattice._dual_class = FiniteMeetSemilattice -FiniteLatticePoset ._dual_class = FiniteLatticePoset +FiniteLatticePoset._dual_class = FiniteLatticePoset diff --git a/src/sage/combinat/posets/linear_extensions.py b/src/sage/combinat/posets/linear_extensions.py index 48ac0a1261c..4eb2f850c02 100644 --- a/src/sage/combinat/posets/linear_extensions.py +++ b/src/sage/combinat/posets/linear_extensions.py @@ -1,6 +1,7 @@ r""" Linear extensions of posets """ + # **************************************************************************** # Copyright (C) 2012 Anne Schilling # @@ -30,8 +31,7 @@ lazy_import('sage.matrix.constructor', 'matrix') -class LinearExtensionOfPoset(ClonableArray, - metaclass=InheritComparisonClasscallMetaclass): +class LinearExtensionOfPoset(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): r""" A linear extension of a finite poset `P` of size `n` is a total ordering `\pi := \pi_0 \pi_1 \ldots \pi_{n-1}` of its elements @@ -80,6 +80,7 @@ class LinearExtensionOfPoset(ClonableArray, sage: Q.cover_relations() [[1, 2], [1, 4], [3, 4]] """ + @staticmethod def __classcall_private__(cls, linear_extension, poset): r""" @@ -242,7 +243,7 @@ def is_greedy(self) -> bool: for i in range(len(self) - 1): if not P.covers(self[i], self[i + 1]): for u in P.upper_covers(self[i]): - if all(l in self[:i + 1] for l in P.lower_covers(u)): + if all(l in self[: i + 1] for l in P.lower_covers(u)): return False return True @@ -296,9 +297,7 @@ def is_supergreedy(self) -> bool: return False linext.append(e) for y in reversed(linext): - L = [x for x in H.neighbor_out_iterator(y) - if x not in linext - and all(low in linext for low in H.neighbor_in_iterator(x))] + L = [x for x in H.neighbor_out_iterator(y) if x not in linext and all(low in linext for low in H.neighbor_in_iterator(x))] if L: break else: @@ -593,9 +592,7 @@ def cardinality(self): # the set {0,...,n-1} with a nice dictionary of edges for i in range(n): - up[n - 1 - i] = sorted(set(up[n - 1 - i] + - [item for x in up[n - 1 - i] - for item in up[x]])) + up[n - 1 - i] = sorted(set(up[n - 1 - i] + [item for x in up[n - 1 - i] for item in up[x]])) # Compute the principal order filter for each element. Jup = {1: []} @@ -664,6 +661,7 @@ def __iter__(self): [[1, 2, 3, 4], [2, 1, 3, 4], [2, 1, 4, 3], [1, 4, 2, 3], [1, 2, 4, 3]] """ from sage.combinat.posets.linear_extension_iterator import linear_extension_iterator + vertex_to_element = self._poset._vertex_to_element for lin_ext in linear_extension_iterator(self._poset._hasse_diagram): yield self._element_constructor_([vertex_to_element(_) for _ in lin_ext]) @@ -696,8 +694,7 @@ def __contains__(self, obj) -> bool: """ if not self._is_facade: return super().__contains__(obj) - return (isinstance(obj, (list, tuple)) and - self.poset().is_linear_extension(obj)) + return isinstance(obj, (list, tuple)) and self.poset().is_linear_extension(obj) def markov_chain_digraph(self, action='promotion', labeling='identity') -> DiGraph: r""" @@ -794,9 +791,7 @@ def markov_chain_digraph(self, action='promotion', labeling='identity') -> DiGra d[x][child] += [i + 1] G = DiGraph(d, format='dict_of_dicts') if have_dot2tex(): - G.set_latex_options(format='dot2tex', edge_labels=True, - color_by_label={1: "blue", 2: "red", - 3: "green", 4: "yellow"}) + G.set_latex_options(format='dot2tex', edge_labels=True, color_by_label={1: "blue", 2: "red", 3: "green", 4: "yellow"}) return G def markov_chain_transition_matrix(self, action='promotion', labeling='identity'): @@ -852,6 +847,7 @@ def markov_chain_transition_matrix(self, action='promotion', labeling='identity' """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.matrix.constructor import matrix + L = sorted(self.list()) n = self.poset().cardinality() R = PolynomialRing(QQ, 'x', n) @@ -985,6 +981,7 @@ def cardinality(self): 361628701868606400 """ import sage.combinat.posets.d_complete as dc + # Find folds if self._poset._anchor: anchor_index = self._poset._ribbon.index(self._poset._anchor[0]) @@ -1009,12 +1006,9 @@ def cardinality(self): elmts = list(self._poset._elements) poset_components = DiGraph([elmts, foldless_cr]) - ordered_poset_components = [poset_components.connected_component_containing_vertex(f[1], sort=False) - for f in folds_up] - ordered_poset_components.extend(poset_components.connected_component_containing_vertex(f[0], sort=False) - for f in folds_down) - ordered_poset_components.append(poset_components.connected_component_containing_vertex( - folds_down[-1][1] if folds_down else folds_up[-1][0], sort=False)) + ordered_poset_components = [poset_components.connected_component_containing_vertex(f[1], sort=False) for f in folds_up] + ordered_poset_components.extend(poset_components.connected_component_containing_vertex(f[0], sort=False) for f in folds_down) + ordered_poset_components.append(poset_components.connected_component_containing_vertex(folds_down[-1][1] if folds_down else folds_up[-1][0], sort=False)) # Return determinant diff --git a/src/sage/combinat/posets/mobile.py b/src/sage/combinat/posets/mobile.py index f529f6b664c..0a69aa9a3fd 100644 --- a/src/sage/combinat/posets/mobile.py +++ b/src/sage/combinat/posets/mobile.py @@ -1,6 +1,7 @@ """ Mobile posets """ + # **************************************************************************** # Copyright (C) 2020 Stefan Grosser # @@ -61,6 +62,7 @@ class MobilePoset(FinitePoset): ... ValueError: the empty poset is not a mobile poset """ + _lin_ext_type = LinearExtensionsOfMobile _desc = 'Finite mobile poset' @@ -74,8 +76,7 @@ def __init__(self, hasse_diagram, elements, category, facade, key, ribbon=None, ....: {}, anchor=(8, 0, posets.ChainPoset(1))) sage: TestSuite(P).run() """ - FinitePoset.__init__(self, hasse_diagram=hasse_diagram, elements=elements, - category=category, facade=facade, key=key) + FinitePoset.__init__(self, hasse_diagram=hasse_diagram, elements=elements, category=category, facade=facade, key=key) if not self._hasse_diagram: raise ValueError("the empty poset is not a mobile poset") @@ -206,8 +207,7 @@ def _ribbon(self): traverse_ribbon = ribbon if end_count == 0 else ribbon[::-1] for ind, p in enumerate(traverse_ribbon): if H_un.is_cut_edge(p, traverse_ribbon[ind + 1]): - return [self._vertex_to_element(r) - for r in G.shortest_path(ends[(end_count + 1) % 2], traverse_ribbon[ind + 1])] + return [self._vertex_to_element(r) for r in G.shortest_path(ends[(end_count + 1) % 2], traverse_ribbon[ind + 1])] return [self._vertex_to_element(r) for r in ribbon] # First check path counts between ends and deg3 vertex diff --git a/src/sage/combinat/posets/moebius_algebra.py b/src/sage/combinat/posets/moebius_algebra.py index 506bc0de366..d8fd6f71d8f 100644 --- a/src/sage/combinat/posets/moebius_algebra.py +++ b/src/sage/combinat/posets/moebius_algebra.py @@ -33,6 +33,7 @@ class BasisAbstract(CombinatorialFreeModule, BindableClass): """ Abstract base class for a basis. """ + def __getitem__(self, x): """ Return the basis element indexed by ``x``. @@ -96,6 +97,7 @@ class MoebiusAlgebra(Parent, UniqueRepresentation): European Journal of Combinatorics, **19**, 1998. :doi:`10.1006/eujc.1998.0227`. """ + def __init__(self, R, L) -> None: """ Initialize ``self``. @@ -161,6 +163,7 @@ class E(BasisAbstract): Let `E_x` and `E_y` be basis elements of `M_L` for some lattice `L`. Multiplication is given by `E_x E_y = E_{x \vee y}`. """ + def __init__(self, M, prefix='E') -> None: """ Initialize ``self``. @@ -172,10 +175,7 @@ def __init__(self, M, prefix='E') -> None: sage: TestSuite(M.E()).run() """ self._basis_name = "natural" - CombinatorialFreeModule.__init__(self, M.base_ring(), - tuple(M._lattice), - prefix=prefix, - category=MoebiusAlgebraBases(M)) + CombinatorialFreeModule.__init__(self, M.base_ring(), tuple(M._lattice), prefix=prefix, category=MoebiusAlgebraBases(M)) @cached_method def _to_idempotent_basis(self, x): @@ -242,6 +242,7 @@ class I(BasisAbstract): Multiplication is given by `I_x I_y = \delta_{xy} I_x` where `\delta_{xy}` is the Kronecker delta. """ + def __init__(self, M, prefix='I') -> None: """ Initialize ``self``. @@ -264,24 +265,13 @@ def __init__(self, M, prefix='I') -> None: ... """ self._basis_name = "idempotent" - CombinatorialFreeModule.__init__(self, M.base_ring(), - tuple(M._lattice), - prefix=prefix, - category=MoebiusAlgebraBases(M)) + CombinatorialFreeModule.__init__(self, M.base_ring(), tuple(M._lattice), prefix=prefix, category=MoebiusAlgebraBases(M)) # Change of basis: E = M.E() - self.module_morphism(self._to_natural_basis, - codomain=E, category=self.category(), - triangular='lower', unitriangular=True, - key=M._lattice._element_to_vertex - ).register_as_coercion() - - E.module_morphism(E._to_idempotent_basis, - codomain=self, category=self.category(), - triangular='lower', unitriangular=True, - key=M._lattice._element_to_vertex - ).register_as_coercion() + self.module_morphism(self._to_natural_basis, codomain=E, category=self.category(), triangular='lower', unitriangular=True, key=M._lattice._element_to_vertex).register_as_coercion() + + E.module_morphism(E._to_idempotent_basis, codomain=self, category=self.category(), triangular='lower', unitriangular=True, key=M._lattice._element_to_vertex).register_as_coercion() @cached_method def _to_natural_basis(self, x): @@ -299,8 +289,7 @@ def _to_natural_basis(self, x): M = self.realization_of() N = M.natural() moebius = M._lattice.moebius_function - return N.sum_of_terms((y, moebius(x, y)) - for y in M._lattice.order_filter([x])) + return N.sum_of_terms((y, moebius(x, y)) for y in M._lattice.order_filter([x])) def product_on_basis(self, x, y): """ @@ -381,6 +370,7 @@ class QuantumMoebiusAlgebra(Parent, UniqueRepresentation): \operatorname{rank} L - \operatorname{rank}` a). At `q = 1`, this reduces to the multiplication formula originally given by Solomon. """ + def __init__(self, L, q=None) -> None: """ Initialize ``self``. @@ -471,6 +461,7 @@ class E(BasisAbstract): is the corank function (i.e., `\operatorname{crk} a = \operatorname{rank} L - \operatorname{rank}` a). """ + def __init__(self, M, prefix='E') -> None: """ Initialize ``self``. @@ -482,10 +473,7 @@ def __init__(self, M, prefix='E') -> None: sage: TestSuite(M.E()).run() # long time """ self._basis_name = "natural" - CombinatorialFreeModule.__init__(self, M.base_ring(), - tuple(M._lattice), - prefix=prefix, - category=MoebiusAlgebraBases(M)) + CombinatorialFreeModule.__init__(self, M.base_ring(), tuple(M._lattice), prefix=prefix, category=MoebiusAlgebraBases(M)) def product_on_basis(self, x, y): """ @@ -506,9 +494,7 @@ def product_on_basis(self, x, y): rank = L.rank_function() R = L.rank() j = L.join(x, y) - return self.sum_of_terms((z, moebius(a, z) * q**(R - rank(a))) - for z in L.order_filter([j]) - for a in L.closed_interval(j, z)) + return self.sum_of_terms((z, moebius(a, z) * q ** (R - rank(a))) for z in L.order_filter([j]) for a in L.closed_interval(j, z)) @cached_method def one(self): @@ -527,8 +513,7 @@ def one(self): moebius = L.moebius_function rank = L.rank_function() R = L.rank() - return self.sum_of_terms((x, moebius(y, x) * q**(rank(y) - R)) - for x in L for y in L.order_ideal([x])) + return self.sum_of_terms((x, moebius(y, x) * q ** (rank(y) - R)) for x in L for y in L.order_ideal([x])) natural = E @@ -547,6 +532,7 @@ class C(BasisAbstract): filter of `x` and `P(F^x; q)` is the characteristic polynomial of the (sub)poset `F^x`. """ + def __init__(self, M, prefix='C') -> None: """ Initialize ``self``. @@ -558,17 +544,11 @@ def __init__(self, M, prefix='C') -> None: sage: TestSuite(M.C()).run() # long time """ self._basis_name = "characteristic" - CombinatorialFreeModule.__init__(self, M.base_ring(), - tuple(M._lattice), - prefix=prefix, - category=MoebiusAlgebraBases(M)) + CombinatorialFreeModule.__init__(self, M.base_ring(), tuple(M._lattice), prefix=prefix, category=MoebiusAlgebraBases(M)) # Change of basis: E = M.E() - phi = self.module_morphism(self._to_natural_basis, - codomain=E, category=self.category(), - triangular='lower', unitriangular=True, - key=M._lattice._element_to_vertex) + phi = self.module_morphism(self._to_natural_basis, codomain=E, category=self.category(), triangular='lower', unitriangular=True, key=M._lattice._element_to_vertex) phi.register_as_coercion() (~phi).register_as_coercion() @@ -593,8 +573,8 @@ def _to_natural_basis(self, x): def poly(x, y): return L.subposet(L.closed_interval(x, y)).characteristic_polynomial() - return N.sum_of_terms((y, poly(x, y)(q=q)) - for y in L.order_filter([x])) + + return N.sum_of_terms((y, poly(x, y)(q=q)) for y in L.order_filter([x])) characteristic_basis = C @@ -626,6 +606,7 @@ class KL(BasisAbstract): sage: KL[4] * KL[10] (q+3*q^2+3*q^3+q^4)*KL[14] + (1+4*q+6*q^2+4*q^3+q^4)*KL[15] """ + def __init__(self, M, prefix='KL') -> None: """ Initialize ``self``. @@ -637,17 +618,11 @@ def __init__(self, M, prefix='KL') -> None: sage: TestSuite(M.KL()).run() # long time """ self._basis_name = "Kazhdan-Lusztig" - CombinatorialFreeModule.__init__(self, M.base_ring(), - tuple(M._lattice), - prefix=prefix, - category=MoebiusAlgebraBases(M)) + CombinatorialFreeModule.__init__(self, M.base_ring(), tuple(M._lattice), prefix=prefix, category=MoebiusAlgebraBases(M)) # Change of basis: E = M.E() - phi = self.module_morphism(self._to_natural_basis, - codomain=E, category=self.category(), - triangular='lower', unitriangular=True, - key=M._lattice._element_to_vertex) + phi = self.module_morphism(self._to_natural_basis, codomain=E, category=self.category(), triangular='lower', unitriangular=True, key=M._lattice._element_to_vertex) phi.register_as_coercion() (~phi).register_as_coercion() @@ -670,9 +645,7 @@ def _to_natural_basis(self, x): E = M.E() q = M._q rank = L.rank_function() - return E.sum_of_terms((y, q**(rank(y) - rank(x)) * - L.kazhdan_lusztig_polynomial(x, y)(q=q**-2)) - for y in L.order_filter([x])) + return E.sum_of_terms((y, q ** (rank(y) - rank(x)) * L.kazhdan_lusztig_polynomial(x, y)(q=q**-2)) for y in L.order_filter([x])) kazhdan_lusztig = KL @@ -693,6 +666,7 @@ class MoebiusAlgebraBases(Category_realization_of_parent): sage: M.E() in bases True """ + def _repr_(self) -> str: r""" Return the representation of ``self``. diff --git a/src/sage/combinat/posets/poset_examples.py b/src/sage/combinat/posets/poset_examples.py index 18529a7b7bd..a71cdffc409 100644 --- a/src/sage/combinat/posets/poset_examples.py +++ b/src/sage/combinat/posets/poset_examples.py @@ -107,8 +107,7 @@ from sage.combinat.posets import bubble_shuffle, hochschild_lattice, sashes from sage.combinat.posets.d_complete import DCompletePoset from sage.combinat.posets.mobile import MobilePoset as Mobile -from sage.combinat.posets.lattices import (LatticePoset, MeetSemilattice, - JoinSemilattice, FiniteLatticePoset) +from sage.combinat.posets.lattices import LatticePoset, MeetSemilattice, JoinSemilattice, FiniteLatticePoset from sage.categories.finite_posets import FinitePosets from sage.categories.finite_lattice_posets import FiniteLatticePosets from sage.graphs.digraph import DiGraph @@ -191,6 +190,7 @@ class Posets(metaclass=ClasscallMetaclass): sage: P = Posets sage: TestSuite(P).run() """ + @staticmethod def __classcall__(cls, n=None): r""" @@ -254,17 +254,20 @@ def BooleanLattice(n, facade=None, use_subsets=False): if n == 0: if use_subsets: from sage.sets.set import Set + return LatticePoset(([Set()], []), facade=facade) return LatticePoset(([0], []), facade=facade) if n == 1: if use_subsets: from sage.sets.set import Set + V = [Set(), Set([1])] return LatticePoset((V, [V]), facade=facade) return LatticePoset(([0, 1], [[0, 1]]), facade=facade) if use_subsets: from sage.sets.set import Set + cur_level = [frozenset(range(1, n + 1))] D = DiGraph() D.add_vertex(Set(cur_level[0])) @@ -276,15 +279,10 @@ def BooleanLattice(n, facade=None, use_subsets=False): D.add_edge(Set(Y), Set(X)) next_level.add(Y) cur_level = next_level - return FiniteLatticePoset(D, category=FiniteLatticePosets(), - facade=facade) + return FiniteLatticePoset(D, category=FiniteLatticePosets(), facade=facade) - D = DiGraph({v: [Integer(v | (1 << y)) - for y in range(n) if v & (1 << y) == 0] - for v in range(2**n)}) - return FiniteLatticePoset(hasse_diagram=D, - category=FiniteLatticePosets().Stone(), - facade=facade) + D = DiGraph({v: [Integer(v | (1 << y)) for y in range(n) if v & (1 << y) == 0] for v in range(2**n)}) + return FiniteLatticePoset(hasse_diagram=D, category=FiniteLatticePosets().Stone(), facade=facade) BubblePoset = staticmethod(bubble_shuffle.BubblePoset) @@ -333,11 +331,8 @@ def ChainPoset(n, facade=None): [[0, 1]] """ n = check_int(n) - D = DiGraph([range(n), [[x, x + 1] for x in range(n - 1)]], - format='vertices_and_edges') - return FiniteLatticePoset(hasse_diagram=D, - category=FiniteLatticePosets().Stone(), - facade=facade) + D = DiGraph([range(n), [[x, x + 1] for x in range(n - 1)]], format='vertices_and_edges') + return FiniteLatticePoset(hasse_diagram=D, category=FiniteLatticePosets().Stone(), facade=facade) @staticmethod def AntichainPoset(n, facade=None): @@ -417,8 +412,7 @@ def PentagonPoset(facade=None): sage: posets.DiamondPoset(5).is_distributive() False """ - return LatticePoset([[1, 2], [4], [3], [4], []], facade=facade, - category=FiniteLatticePosets().CongruenceUniform()) + return LatticePoset([[1, 2], [4], [3], [4], []], facade=facade, category=FiniteLatticePosets().CongruenceUniform()) @staticmethod def DiamondPoset(n, facade=None): @@ -447,8 +441,7 @@ def DiamondPoset(n, facade=None): cat = FiniteLatticePosets().ChainGraded() if n <= 4: cat = cat.Stone() - return FiniteLatticePoset(hasse_diagram=D, category=cat, - facade=facade) + return FiniteLatticePoset(hasse_diagram=D, category=cat, facade=facade) @staticmethod def Crown(n, facade=None): @@ -476,8 +469,7 @@ def Crown(n, facade=None): n = check_int(n, 2) D = {i: [i + n, i + n + 1] for i in range(n - 1)} D[n - 1] = [n, n + n - 1] - return FinitePoset(hasse_diagram=DiGraph(D), category=FinitePosets(), - facade=facade) + return FinitePoset(hasse_diagram=DiGraph(D), category=FinitePosets(), facade=facade) @staticmethod def DivisorLattice(n, facade=None): @@ -511,11 +503,11 @@ def DivisorLattice(n, facade=None): Finite lattice containing 1 elements with distinguished linear extension """ from sage.arith.misc import divisors, is_prime + n = check_int(n, 1) Div_n = divisors(n) hasse = DiGraph([Div_n, lambda a, b: b % a == 0 and is_prime(b // a)]) - return FiniteLatticePoset(hasse, elements=Div_n, facade=facade, - category=FiniteLatticePosets().Stone()) + return FiniteLatticePoset(hasse, elements=Div_n, facade=facade, category=FiniteLatticePosets().Stone()) @staticmethod def HessenbergPoset(H): @@ -573,10 +565,10 @@ def IntegerCompositions(n): 192 """ from sage.combinat.composition import Compositions + C = Compositions(n) cat = FiniteLatticePosets().ChainGraded() - return Poset((C, [[c, d] for c in C for d in C if d.is_finer(c)]), - cover_relations=False, category=cat) + return Poset((C, [[c, d] for c in C for d in C if d.is_finer(c)]), cover_relations=False, category=cat) @staticmethod def IntegerPartitions(n): @@ -596,6 +588,7 @@ def IntegerPartitions(n): sage: len(P.cover_relations()) 28 """ + def lower_covers(partition): r""" Nested function for computing the lower covers @@ -613,7 +606,9 @@ def lower_covers(partition): if tup not in lc: lc.append(tup) return lc + from sage.combinat.partition import Partitions + H = DiGraph({tuple(p): lower_covers(p) for p in Partitions(n)}) cat = FiniteLatticePosets().ChainGraded() return Poset(H.reverse(), cover_relations=True, category=cat) @@ -635,6 +630,7 @@ def RestrictedIntegerPartitions(n): sage: len(P.cover_relations()) 17 """ + def lower_covers(partition): r""" Nested function for computing the lower covers of elements in the @@ -653,7 +649,9 @@ def lower_covers(partition): if tup not in lc: lc.append(tup) return lc + from sage.combinat.partition import Partitions + H = DiGraph({tuple(p): lower_covers(p) for p in Partitions(n)}) return Poset(H.reverse(), cover_relations=True) @@ -691,6 +689,7 @@ def IntegerPartitionsDominanceOrder(n): """ n = check_int(n) from sage.combinat.partition import Partitions, Partition + return LatticePoset((Partitions(n), Partition.dominates)).dual() @staticmethod @@ -734,9 +733,7 @@ def PowerPoset(n): for r in Permutations(P): all_pos_n.add(P.relabel(list(r))) - return MeetSemilattice((all_pos_n, - lambda A, B: all(B.is_lequal(x, y) - for x, y in A.cover_relations_iterator()))) + return MeetSemilattice((all_pos_n, lambda A, B: all(B.is_lequal(x, y) for x, y in A.cover_relations_iterator()))) @staticmethod def ProductOfChains(chain_lengths, facade=None): @@ -782,12 +779,13 @@ def ProductOfChains(chain_lengths, facade=None): if not chain_lengths: return LatticePoset(facade=facade) from sage.categories.cartesian_product import cartesian_product + elements = cartesian_product([range(i) for i in l]) def compare(a, b): return all(x <= y for x, y in zip(a, b)) - return LatticePoset([elements, compare], facade=facade, - category=FiniteLatticePosets().Distributive()) + + return LatticePoset([elements, compare], facade=facade, category=FiniteLatticePosets().Distributive()) @staticmethod def RandomPoset(n, p): @@ -833,6 +831,7 @@ def RandomPoset(n, p): Finite poset containing 0 elements """ from sage.misc.prandom import random + n = check_int(n) try: p = float(p) @@ -1011,6 +1010,7 @@ def SetPartitions(n): Finite lattice containing 15 elements """ from sage.combinat.set_partition import SetPartitions + n = check_int(n) S = SetPartitions(n) @@ -1023,8 +1023,7 @@ def covers(x): yield S(L) cat = FiniteLatticePosets().ChainGraded() - return LatticePoset({x: list(covers(x)) for x in S}, - cover_relations=True, category=cat) + return LatticePoset({x: list(covers(x)) for x in S}, cover_relations=True, category=cat) @staticmethod def SSTPoset(s, f=None): @@ -1118,9 +1117,7 @@ def StandardExample(n, facade=None): (False, False) """ n = check_int(n, 2) - return Poset((range(2 * n), [[i, j + n] for i in range(n) - for j in range(n) if i != j]), - facade=facade) + return Poset((range(2 * n), [[i, j + n] for i in range(n) for j in range(n) if i != j]), facade=facade) @staticmethod def SymmetricGroupBruhatOrderPoset(n): @@ -1133,12 +1130,10 @@ def SymmetricGroupBruhatOrderPoset(n): Finite poset containing 24 elements """ if n < 10: - element_labels = {s: "".join(str(x) for x in s) - for s in Permutations(n)} + element_labels = {s: "".join(str(x) for x in s) for s in Permutations(n)} cat = FiniteLatticePosets().ChainGraded() - return Poset({s: s.bruhat_succ() for s in Permutations(n)}, - element_labels, category=cat) + return Poset({s: s.bruhat_succ() for s in Permutations(n)}, element_labels, category=cat) @staticmethod def SymmetricGroupBruhatIntervalPoset(start, end): @@ -1179,10 +1174,8 @@ def SymmetricGroupBruhatIntervalPoset(start, end): nodes = {} while unseen: perm = unseen.pop(0) - nodes[perm] = [succ_perm for succ_perm in perm.bruhat_succ() - if succ_perm.bruhat_lequal(end)] - unseen.extend(succ_perm for succ_perm in nodes[perm] - if succ_perm not in nodes) + nodes[perm] = [succ_perm for succ_perm in perm.bruhat_succ() if succ_perm.bruhat_lequal(end)] + unseen.extend(succ_perm for succ_perm in nodes[perm] if succ_perm not in nodes) cat = FiniteLatticePosets().ChainGraded() return Poset(nodes, category=cat) @@ -1204,11 +1197,9 @@ def SymmetricGroupWeakOrderPoset(n, labels='permutations', side='right'): Finite lattice containing 24 elements """ if n < 10 and labels == "permutations": - element_labels = {s: "".join(map(str, s)) - for s in Permutations(n)} + element_labels = {s: "".join(map(str, s)) for s in Permutations(n)} if n < 10 and labels == "reduced_words": - element_labels = {s: "".join(map(str, s.reduced_word_lexmin())) - for s in Permutations(n)} + element_labels = {s: "".join(map(str, s.reduced_word_lexmin())) for s in Permutations(n)} if side == "left": def weak_covers(s): @@ -1216,8 +1207,8 @@ def weak_covers(s): Nested function for computing the covers of elements in the poset of left weak order for the symmetric group. """ - return [v for v in s.bruhat_succ() if - s.length() + (s.inverse().right_action_product(v)).length() == v.length()] + return [v for v in s.bruhat_succ() if s.length() + (s.inverse().right_action_product(v)).length() == v.length()] + else: def weak_covers(s): @@ -1225,13 +1216,9 @@ def weak_covers(s): Nested function for computing the covers of elements in the poset of right weak order for the symmetric group. """ - return [v for v in s.bruhat_succ() if - s.length() + (s.inverse().left_action_product(v)).length() == v.length()] - return LatticePoset( - {s: weak_covers(s) for s in Permutations(n)}, - element_labels, check=False, - category=FiniteLatticePosets().ChainGraded().Semidistributive() - ) + return [v for v in s.bruhat_succ() if s.length() + (s.inverse().left_action_product(v)).length() == v.length()] + + return LatticePoset({s: weak_covers(s) for s in Permutations(n)}, element_labels, check=False, category=FiniteLatticePosets().ChainGraded().Semidistributive()) @staticmethod def TetrahedralPoset(n, *colors, **labels): @@ -1294,8 +1281,7 @@ def TetrahedralPoset(n, *colors, **labels): for c in colors: if c not in ('green', 'red', 'yellow', 'orange', 'silver', 'blue'): raise ValueError("color input must be among: 'green', 'red', 'yellow', 'orange', 'silver', and 'blue'") - elem = [(i, j, k) for i in range(n) - for j in range(n - i) for k in range(n - i - j)] + elem = [(i, j, k) for i in range(n) for j in range(n - i) for k in range(n - i - j)] rels = [] elem_labels = {} if 'labels' in labels: @@ -1323,10 +1309,12 @@ def TetrahedralPoset(n, *colors, **labels): # shard intersection order import sage.combinat.shard_order + ShardPoset = staticmethod(sage.combinat.shard_order.shard_poset) # Tamari lattices import sage.combinat.tamari_lattices + TamariLattice = staticmethod(sage.combinat.tamari_lattices.TamariLattice) DexterSemilattice = staticmethod(sage.combinat.tamari_lattices.DexterSemilattice) @@ -1408,14 +1396,14 @@ def SymmetricGroupAbsoluteOrderPoset(n, labels='permutations'): Finite poset containing 6 elements """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup + W = SymmetricGroup(n) if labels == "permutations": element_labels = {s: s.tuple() for s in W} if labels == "reduced_words": element_labels = {s: tuple(s.reduced_word()) for s in W} if labels == "cycles": - element_labels = {s: "".join(x for x in s.cycle_string() if x != ',') - for s in W} + element_labels = {s: "".join(x for x in s.cycle_string() if x != ',') for s in W} return Poset({s: list(s.absolute_covers()) for s in W}, element_labels) @@ -1465,8 +1453,7 @@ def UpDownPoset(n, m=1): if m < 1: raise ValueError(f"parameter m must be positive, not {m}") - covers = [[i, i + 1] if (i + 1) % (m + 1) else [i + 1, i] - for i in range(n - 1)] + covers = [[i, i + 1] if (i + 1) % (m + 1) else [i + 1, i] for i in range(n - 1)] return Poset((range(n), covers), cover_relations=True) @staticmethod @@ -1493,15 +1480,17 @@ def YoungDiagramPoset(lam, dual=False): Finite join-semilattice containing 5 elements """ from sage.combinat.partition import Partition + lam = Partition(lam) if dual: + def cell_geq(a, b): """ Nested function that returns ``True`` if the cell `a` is to the right or below the cell `b` in the (English) Young diagram. """ - return ((a[0] == b[0] + 1 and a[1] == b[1]) or - (a[1] == b[1] + 1 and a[0] == b[0])) + return (a[0] == b[0] + 1 and a[1] == b[1]) or (a[1] == b[1] + 1 and a[0] == b[0]) + return JoinSemilattice((lam.cells(), cell_geq), cover_relations=True) def cell_leq(a, b): @@ -1510,8 +1499,8 @@ def cell_leq(a, b): to the left or above the cell `b` in the (English) Young diagram. """ - return ((a[0] == b[0] - 1 and a[1] == b[1]) or - (a[1] == b[1] - 1 and a[0] == b[0])) + return (a[0] == b[0] - 1 and a[1] == b[1]) or (a[1] == b[1] - 1 and a[0] == b[0]) + return MeetSemilattice((lam.cells(), cell_leq), cover_relations=True) @staticmethod @@ -1541,6 +1530,7 @@ def YoungsLattice(n): """ from sage.combinat.partition import Partitions, Partition from sage.misc.flatten import flatten + partitions = flatten([list(Partitions(i)) for i in range(n + 1)]) return JoinSemilattice((partitions, Partition.contains)).dual() @@ -1623,7 +1613,7 @@ def YoungFibonacci(n): for low in current_level: ind = low.find('1') if ind != -1: # = found a '1' -> change first '1' to '2' - up = low[:ind] + '2' + low[ind + 1:] + up = low[:ind] + '2' + low[ind + 1 :] new_level.add(up) covers.append((low, up)) else: # no '1' in low @@ -1631,7 +1621,7 @@ def YoungFibonacci(n): # add '1' to every position not after first existing '1' for j in range(ind + 1): - up = '2' * j + '1' + low[j:len(low)] + up = '2' * j + '1' + low[j : len(low)] new_level.add(up) covers.append((low, up)) @@ -1752,8 +1742,8 @@ def PermutationPatternInterval(bottom, top): # Make a list of lists of elements in the interval divided by rank. # List will be flattened at the end elem = [[top]] - level = 0 # Consider the top element to be level 0, and then go down from there. - rel = [] # List of covering relations to be fed into poset constructor. + level = 0 # Consider the top element to be level 0, and then go down from there. + rel = [] # List of covering relations to be fed into poset constructor. while len(top) - len(bottom) >= level + 1: elem.append([]) # Add a new empty level for upper in elem[level]: @@ -1832,8 +1822,7 @@ def PermutationPatternOccurrenceInterval(bottom, top, pos): for f in range(len(upper[1])): if upper[1][f] > i: lower_pos[f] = upper[1][f] - 1 - rel += [[(P(lower_perm), tuple(lower_pos)), - (P(upper[0]), upper[1])]] + rel += [[(P(lower_perm), tuple(lower_pos)), (P(upper[0]), upper[1])]] if (P(lower_perm), tuple(lower_pos)) not in elem[level + 1]: elem[level + 1].append((P(lower_perm), tuple(lower_pos))) level += 1 @@ -1857,9 +1846,7 @@ def RibbonPoset(n, descents): [[0, 1], [2, 1], [3, 2], [3, 4]] """ n = check_int(n) - return Mobile(DiGraph([list(range(n)), - [(i + 1, i) if i in descents else (i, i + 1) - for i in range(n - 1)]])) + return Mobile(DiGraph([list(range(n)), [(i + 1, i) if i in descents else (i, i + 1) for i in range(n - 1)]])) @staticmethod def MobilePoset(ribbon, hangers, anchor=None): @@ -1900,8 +1887,7 @@ def MobilePoset(ribbon, hangers, anchor=None): elements.extend(ribbon._elements) if anchor: - cover_relations.extend(((anchor[0], cr[0]), (anchor[0], cr[1])) - for cr in anchor[2].cover_relations()) + cover_relations.extend(((anchor[0], cr[0]), (anchor[0], cr[1])) for cr in anchor[2].cover_relations()) cover_relations.append((anchor[0], (anchor[0], anchor[1]))) elements.extend((anchor[0], elmt) for elmt in anchor[2]._elements) @@ -1909,8 +1895,7 @@ def MobilePoset(ribbon, hangers, anchor=None): for r, hangs in hangers.items(): for i, h in enumerate(hangs): elements.extend((r, i, v) for v in h._elements) - cover_relations.extend(((r, i, cr[0]), (r, i, cr[1])) - for cr in h.cover_relations()) + cover_relations.extend(((r, i, cr[0]), (r, i, cr[1])) for cr in h.cover_relations()) cover_relations.append(((r, i, h.top()), r)) return Mobile(DiGraph([elements, cover_relations])) diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 0ec47c982aa..efa0258c15d 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -691,9 +691,7 @@ def Poset(data=None, element_labels=None, cover_relations=False, linear_extensio """ # Avoiding some errors from the user when data should be a pair if not (element_labels is None or isinstance(element_labels, (dict, list))): - raise TypeError("element_labels should be a dict or a list if " - "different from None. (Did you intend data to be " - "equal to a pair ?)") + raise TypeError("element_labels should be a dict or a list if " "different from None. (Did you intend data to be " "equal to a pair ?)") if isinstance(data, FinitePoset): if element_labels is None and category is None and facade is None and linear_extension == data._with_linear_extension: @@ -719,8 +717,7 @@ def Poset(data=None, element_labels=None, cover_relations=False, linear_extensio if len(data) == 2: # types 1 or 2 if callable(data[1]): # type 2 elements, function = data - relations = ((x, y) for x in elements for y in elements - if function(x, y)) + relations = ((x, y) for x in elements for y in elements if function(x, y)) else: # type 1 elements, relations = data # check that relations are relations @@ -735,9 +732,7 @@ def Poset(data=None, element_labels=None, cover_relations=False, linear_extensio if len(vertices) != len(data): # by default, assuming vertices are the range 0..n vertices = range(len(data)) - D = DiGraph({v: [u for u in cov if u != v] - for v, cov in zip(vertices, data)}, - format='dict_of_lists') + D = DiGraph({v: [u for u in cov if u != v] for v, cov in zip(vertices, data)}, format='dict_of_lists') else: raise ValueError("not valid poset data") @@ -747,6 +742,7 @@ def Poset(data=None, element_labels=None, cover_relations=False, linear_extensio # Determine cover relations, if necessary. if not cover_relations: from sage.graphs.generic_graph_pyx import transitive_reduction_acyclic + D = transitive_reduction_acyclic(D) # Check that the digraph does not contain loops, multiple edges @@ -772,9 +768,7 @@ def Poset(data=None, element_labels=None, cover_relations=False, linear_extensio raise ValueError("Hasse diagram contains cycles") # Check for duplicate elements elif len(elements) != len(set(elements)): - raise ValueError("the provided list of elements is not a linear " - "extension for the poset as it contains " - "duplicate elements") + raise ValueError("the provided list of elements is not a linear " "extension for the poset as it contains " "duplicate elements") else: elements = None return FinitePoset(D, elements=elements, category=category, facade=facade, key=key) @@ -949,6 +943,7 @@ class contains. For example, for this class, ``FinitePoset``, sage: Q == P True """ + _lin_ext_type = LinearExtensionsOfPoset _desc = 'Finite poset' @@ -1009,10 +1004,7 @@ def __classcall__(cls, hasse_diagram, elements=None, category=None, facade=None, if category is not None and category.is_subcategory(Sets().Facade()): category = category._without_axiom("Facade") category = Category.join([FinitePosets().or_subcategory(category), FiniteEnumeratedSets()]) - return super().__classcall__(cls, hasse_diagram=hasse_diagram, - elements=elements, - category=category, facade=facade, - key=key) + return super().__classcall__(cls, hasse_diagram=hasse_diagram, elements=elements, category=category, facade=facade, key=key) def __init__(self, hasse_diagram, elements, category, facade, key) -> None: r""" @@ -1076,13 +1068,11 @@ def __init__(self, hasse_diagram, elements, category, facade, key) -> None: # Work around the fact that, currently, when a DiGraph is # created with Integer's as vertices, those vertices are # converted to plain int's. This is a bit abusive. - self._elements = tuple(Integer(i) if isinstance(i, int) else i - for i in elements) + self._elements = tuple(Integer(i) if isinstance(i, int) else i for i in elements) # Relabel using the linear_extension. # So range(len(D)) becomes a linear extension of the poset. rdict = {element: i for i, element in enumerate(self._elements)} - self._hasse_diagram = HasseDiagram(hasse_diagram.relabel(rdict, inplace=False), - data_structure='static_sparse') + self._hasse_diagram = HasseDiagram(hasse_diagram.relabel(rdict, inplace=False), data_structure='static_sparse') self._element_to_vertex_dict = rdict self._is_facade = facade @@ -1111,8 +1101,7 @@ def _list(self): if self._is_facade: return self._elements - return tuple(self.element_class(self, element, vertex) - for vertex, element in enumerate(self._elements)) + return tuple(self.element_class(self, element, vertex) for vertex, element in enumerate(self._elements)) # This defines the type (class) of elements of poset. Element = PosetElement @@ -1311,8 +1300,7 @@ def _element_constructor_(self, element): try: return self._list[self._element_to_vertex_dict[element]] except KeyError: - raise ValueError("%s is not an element of this poset" - % type(element)) + raise ValueError("%s is not an element of this poset" % type(element)) def __call__(self, element): """ @@ -1375,10 +1363,13 @@ def hasse_diagram(self) -> DiGraph: """ G = DiGraph(self._hasse_diagram).relabel(self._list, inplace=False) from sage.graphs.dot2tex_utils import have_dot2tex + if have_dot2tex(): - G.set_latex_options(format='dot2tex', - prog='dot', - rankdir='up',) + G.set_latex_options( + format='dot2tex', + prog='dot', + rankdir='up', + ) return G def _latex_(self) -> str: @@ -1399,10 +1390,7 @@ def _latex_(self) -> str: """ return self.hasse_diagram()._latex_() - def tikz(self, format=None, edge_labels=False, color_by_label=False, - prog='dot', rankdir='up', standalone_config=None, - usepackage=None, usetikzlibrary=None, macros=None, - use_sage_preamble=None, **kwds): + def tikz(self, format=None, edge_labels=False, color_by_label=False, prog='dot', rankdir='up', standalone_config=None, usepackage=None, usetikzlibrary=None, macros=None, use_sage_preamble=None, **kwds): r""" Return a TikzPicture illustrating the poset. @@ -1463,11 +1451,7 @@ def tikz(self, format=None, edge_labels=False, color_by_label=False, sage: _ = tikz.pdf(view=False) # optional - dot2tex graphviz latex # long time """ G = self.hasse_diagram() - return G.tikz(format=format, edge_labels=edge_labels, - color_by_label=color_by_label, prog=prog, rankdir=rankdir, - standalone_config=standalone_config, usepackage=usepackage, - usetikzlibrary=usetikzlibrary, macros=macros, - use_sage_preamble=use_sage_preamble, **kwds) + return G.tikz(format=format, edge_labels=edge_labels, color_by_label=color_by_label, prog=prog, rankdir=rankdir, standalone_config=standalone_config, usepackage=usepackage, usetikzlibrary=usetikzlibrary, macros=macros, use_sage_preamble=use_sage_preamble, **kwds) def _repr_(self) -> str: r""" @@ -1519,8 +1503,8 @@ def _rich_repr_(self, display_manager, **kwds): sage: dm.preferences.supplemental_plot = 'never' """ prefs = display_manager.preferences - is_small = (0 < self.cardinality() < 20) - can_plot = (prefs.supplemental_plot != 'never') + is_small = 0 < self.cardinality() < 20 + can_plot = prefs.supplemental_plot != 'never' plot_graph = can_plot and (prefs.supplemental_plot == 'always' or is_small) # Under certain circumstances we display the plot as graphics if plot_graph: @@ -1536,7 +1520,7 @@ def _rich_repr_(self, display_manager, **kwds): text = repr(self) # latex() produces huge tikz environment, override tp = display_manager.types - if (prefs.text == 'latex' and tp.OutputLatex in display_manager.supported_output()): + if prefs.text == 'latex' and tp.OutputLatex in display_manager.supported_output(): return tp.OutputLatex(fr'\text{{{text}}}') return tp.OutputPlainText(text) @@ -1944,9 +1928,7 @@ def is_linear_extension(self, l) -> bool: False """ index = {x: i for i, x in enumerate(l)} - return (len(l) == self.cardinality() and - all(x in index for x in self) and - all(index[i] < index[j] for i, j in self.cover_relations())) + return len(l) == self.cardinality() and all(x in index for x in self) and all(index[i] < index[j] for i, j in self.cover_relations()) def list(self): """ @@ -1963,9 +1945,7 @@ def list(self): """ return list(self._list) - def plot(self, label_elements=True, element_labels=None, - layout='acyclic', cover_labels=None, - **kwds): + def plot(self, label_elements=True, element_labels=None, layout='acyclic', cover_labels=None, **kwds): r""" Return a Graphic object for the Hasse diagram of the poset. @@ -2120,15 +2100,7 @@ def plot(self, label_elements=True, element_labels=None, """ graph = self.hasse_diagram() - rename = {'element_color': 'vertex_color', - 'element_colors': 'vertex_colors', - 'element_size': 'vertex_size', - 'element_shape': 'vertex_shape', - 'cover_color': 'edge_color', - 'cover_labels_background': 'edge_labels_background', - 'cover_colors': 'edge_colors', - 'cover_style': 'edge_style', - 'border': 'graph_border'} + rename = {'element_color': 'vertex_color', 'element_colors': 'vertex_colors', 'element_size': 'vertex_size', 'element_shape': 'vertex_shape', 'cover_color': 'edge_color', 'cover_labels_background': 'edge_labels_background', 'cover_colors': 'edge_colors', 'cover_style': 'edge_style', 'border': 'graph_border'} for param, value in rename.items(): tmp = kwds.pop(param, None) if tmp is not None: @@ -2144,8 +2116,8 @@ def plot(self, label_elements=True, element_labels=None, # if relabeling is needed if label_elements and element_labels is not None: from sage.misc.element_with_label import ElementWithLabel - relabeling = {self(element): ElementWithLabel(self(element), label) - for element, label in element_labels.items()} + + relabeling = {self(element): ElementWithLabel(self(element), label) for element, label in element_labels.items()} graph = graph.relabel(relabeling, inplace=False) if heights is not None: for key in heights: @@ -2157,8 +2129,7 @@ def plot(self, label_elements=True, element_labels=None, graph.set_edge_label(v, w, cover_labels(v, w)) elif isinstance(cover_labels, dict): for v, w in cover_labels: - graph.set_edge_label(self(v), self(w), - cover_labels[(v, w)]) + graph.set_edge_label(self(v), self(w), cover_labels[(v, w)]) else: for v, w, l in cover_labels: graph.set_edge_label(self(v), self(w), l) @@ -2166,14 +2137,9 @@ def plot(self, label_elements=True, element_labels=None, else: cover_labels = False - return graph.plot(vertex_labels=label_elements, - edge_labels=cover_labels, - layout=layout, - heights=heights, - **kwds) + return graph.plot(vertex_labels=label_elements, edge_labels=cover_labels, layout=layout, heights=heights, **kwds) - def show(self, label_elements=True, element_labels=None, - cover_labels=None, **kwds): + def show(self, label_elements=True, element_labels=None, cover_labels=None, **kwds): """ Displays the Hasse diagram of the poset. @@ -2219,12 +2185,10 @@ def show(self, label_elements=True, element_labels=None, # The plot_kwds dictionary only contains the options that graphplot # understands. These options are removed from kwds at the same time. from sage.graphs.graph_plot import graphplot_options + plot_kwds = {k: kwds.pop(k) for k in graphplot_options if k in kwds} - self.plot(label_elements=label_elements, - element_labels=element_labels, - cover_labels=cover_labels, - **plot_kwds).show(**kwds) + self.plot(label_elements=label_elements, element_labels=element_labels, cover_labels=cover_labels, **plot_kwds).show(**kwds) def level_sets(self): """ @@ -2253,8 +2217,7 @@ def level_sets(self): :meth:`dilworth_decomposition` to return elements grouped to chains. """ - return [[self._vertex_to_element(_) for _ in level] for level in - self._hasse_diagram.level_sets()] + return [[self._vertex_to_element(_) for _ in level] for level in self._hasse_diagram.level_sets()] def cover_relations(self): """ @@ -2302,6 +2265,7 @@ def cover_relations_graph(self): True """ from sage.graphs.graph import Graph + return Graph(self.hasse_diagram(), immutable=True) def cover_relations_iterator(self): @@ -2646,8 +2610,8 @@ def intervals_poset(self): sage: P.intervals_poset().is_isomorphic(P) True """ - from sage.combinat.posets.lattices import (LatticePoset, - FiniteLatticePoset) + from sage.combinat.posets.lattices import LatticePoset, FiniteLatticePoset + if isinstance(self, FiniteLatticePoset): constructor = LatticePoset else: @@ -2659,8 +2623,7 @@ def intervals_poset(self): for a, b in ints: covers.extend([(a, b), (a, bb)] for bb in self.upper_covers(b)) if a != b: - covers.extend([(a, b), (aa, b)] for aa in self.upper_covers(a) - if self.le(aa, b)) + covers.extend([(a, b), (aa, b)] for aa in self.upper_covers(a) if self.le(aa, b)) dg = DiGraph([ints, covers], format='vertices_and_edges') return constructor(dg, cover_relations=True) @@ -2939,7 +2902,7 @@ def is_lequal(self, x, y) -> bool: """ i = self._element_to_vertex(x) j = self._element_to_vertex(y) - return (self._hasse_diagram.is_lequal(i, j)) + return self._hasse_diagram.is_lequal(i, j) le = is_lequal @@ -2991,7 +2954,7 @@ def is_gequal(self, x, y) -> bool: """ i = self._element_to_vertex(x) j = self._element_to_vertex(y) - return (self._hasse_diagram.is_lequal(j, i)) + return self._hasse_diagram.is_lequal(j, i) ge = is_gequal @@ -3490,8 +3453,7 @@ def is_series_parallel(self) -> bool: if self.cardinality() < 4: return True if not self.is_connected(): - return all(part.is_series_parallel() for part in - self.connected_components()) + return all(part.is_series_parallel() for part in self.connected_components()) parts = self.ordinal_summands() if len(parts) == 1: return False @@ -3536,17 +3498,13 @@ def is_EL_labelling(self, f, return_raising_chains=False) -> bool | dict: ((0, 1), (1, 1)): [0], ((1, 0), (1, 1)): [1]} """ - label_dict = {(a, b): f(a, b) - for a, b in self.cover_relations_iterator()} + label_dict = {(a, b): f(a, b) for a, b in self.cover_relations_iterator()} if return_raising_chains: raising_chains = {} for a, b in self.relations_iterator(strict=True): P = self.subposet(self.interval(a, b)) - max_chains = sorted([[label_dict[(chain[i], chain[i + 1])] - for i in range(len(chain) - 1)] - for chain in P.maximal_chains_iterator()]) - if (max_chains[0] != sorted(max_chains[0]) or - any(max_chains[i] == sorted(max_chains[i]) for i in range(1, len(max_chains)))): + max_chains = sorted([[label_dict[(chain[i], chain[i + 1])] for i in range(len(chain) - 1)] for chain in P.maximal_chains_iterator()]) + if max_chains[0] != sorted(max_chains[0]) or any(max_chains[i] == sorted(max_chains[i]) for i in range(1, len(max_chains))): return False if return_raising_chains: raising_chains[(a, b)] = max_chains[0] @@ -3676,6 +3634,7 @@ def dimension(self, certificate=False, *, solver=None, integrality_tolerance=1e- if not certificate: # polynomial time check for dimension 2 from sage.graphs.comparability import greedy_is_comparability as is_comparability + if is_comparability(self._hasse_diagram.transitive_closure().to_undirected().complement()): return 2 k = 3 @@ -3683,6 +3642,7 @@ def dimension(self, certificate=False, *, solver=None, integrality_tolerance=1e- max_value = max(self.cardinality() // 2, self.width()) from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException + P = Poset(self._hasse_diagram) # work on an int-labelled poset hasse_diagram = P.hasse_diagram() inc_graph = P.incomparability_graph() @@ -3747,8 +3707,7 @@ def init_LP(k, cycles, inc_P): linear_extensions = [g.topological_sort() for g in linear_extensions] if certificate: - return (k, [[self._list[i] for i in l] - for l in linear_extensions]) + return (k, [[self._list[i] for i in l] for l in linear_extensions]) return k def magnitude(self) -> Integer: @@ -3886,16 +3845,14 @@ def greedy_rec(self, linext, jumpcount): S = [] if linext: # S is elements where we can grow the chain without a jump. - S = [x for x in self.upper_covers(linext[-1]) if - all(low in linext for low in self.lower_covers(x))] + S = [x for x in self.upper_covers(linext[-1]) if all(low in linext for low in self.lower_covers(x))] if not S: if jumpcount >= nonlocals[0] - 1: return jumpcount += 1 # S is minimal elements of the poset without elements in linext S_ = self_as_set.difference(set(linext)) - S = [x for x in S_ if - not any(low in S_ for low in self.lower_covers(x))] + S = [x for x in S_ if not any(low in S_ for low in self.lower_covers(x))] for e in S: greedy_rec(self, linext + [e], jumpcount) @@ -4121,7 +4078,7 @@ def is_graded(self) -> bool: hasse = self._hasse_diagram rf = hasse.rank_function() if rf is None: - return False # because every graded poset is ranked. + return False # because every graded poset is ranked. if not all(rf(i) == 0 for i in hasse.minimal_elements()): return False maxes = hasse.maximal_elements() @@ -4429,6 +4386,7 @@ def coxeter_polynomial(self, algorithm="sage"): cox_matrix = self._hasse_diagram.coxeter_transformation() if algorithm == "magma": from sage.interfaces.magma import magma + dense_matrix = magma(cox_matrix).Matrix() return dense_matrix.CharacteristicPolynomial().sage() return cox_matrix.charpoly() @@ -4490,40 +4448,43 @@ def coxeter_smith_form(self, algorithm='singular') -> builtins.list: :meth:`coxeter_transformation`, :meth:`coxeter_matrix` """ c0 = self.coxeter_transformation() - x = polygen(QQ, 'x') # not possible to use ZZ for the moment + x = polygen(QQ, 'x') # not possible to use ZZ for the moment if algorithm == 'singular': # quite faster than sage from sage.interfaces.singular import singular + singular.LIB('jacobson.lib') sing_m = singular(x - c0) L = sing_m.smith().sage().diagonal() - return sorted([u / u.lc() for u in L], - key=lambda p: p.degree()) + return sorted([u / u.lc() for u in L], key=lambda p: p.degree()) if algorithm == 'sage': # *very slow* return (x - c0).smith_form(transformation=False).diagonal() if algorithm == 'magma': # also quite fast from sage.interfaces.magma import magma + elem = magma('ElementaryDivisors') return elem.evaluate(x - c0).sage() if algorithm == 'gap': from sage.libs.gap.libgap import libgap + gap_m = libgap(x - c0) elem = gap_m.ElementaryDivisorsMat() return elem.sage() - if algorithm == 'pari': # maybe fast, at least for small size + if algorithm == 'pari': # maybe fast, at least for small size from sage.libs.pari import pari + pari_m = pari(x - c0) elem = pari_m.matsnf(2) A = x.parent() - return sorted((A(f) for f in elem), - key=lambda p: p.degree()) + return sorted((A(f) for f in elem), key=lambda p: p.degree()) if algorithm == 'maple': from sage.interfaces.maple import maple + maple_m = maple(x - c0) maple.load("MatrixPolynomialAlgebra") maple.load("ArrayTools") @@ -4533,6 +4494,7 @@ def coxeter_smith_form(self, algorithm='singular') -> builtins.list: if algorithm == 'fricas': from sage.interfaces.fricas import fricas + fm = fricas(x - c0) return list(fricas(fm.name() + "::Matrix(UP(x, FRAC INT))").smith().diagonal().sage()) @@ -4588,6 +4550,7 @@ def is_meet_semilattice(self, certificate=False) -> bool | tuple: (False, (3, 1)) """ from sage.combinat.posets.hasse_diagram import LatticeError + try: self._hasse_diagram.meet_matrix() except LatticeError as error: @@ -4659,6 +4622,7 @@ def is_join_semilattice(self, certificate=False) -> bool | tuple: (False, (5, 4)) """ from sage.combinat.posets.hasse_diagram import LatticeError + try: self._hasse_diagram.join_matrix() except LatticeError as error: @@ -4702,8 +4666,7 @@ def is_isomorphic(self, other, **kwds) -> bool | tuple: (True, {1: 4, 2: 5, 3: 6}) """ if hasattr(other, 'hasse_diagram'): - return self.hasse_diagram().is_isomorphic(other.hasse_diagram(), - **kwds) + return self.hasse_diagram().is_isomorphic(other.hasse_diagram(), **kwds) raise TypeError("'other' is not a finite poset") def isomorphic_subposets_iterator(self, other): @@ -4783,8 +4746,7 @@ def isomorphic_subposets(self, other) -> builtins.list: L = self._hasse_diagram.transitive_closure().subgraph_search_iterator(other._hasse_diagram.transitive_closure(), induced=True, return_graphs=False) # Since subgraph_search_iterator returns labelled copies, we # remove duplicates. - return [self.subposet([self._list[i] for i in x]) - for x in sorted({frozenset(y) for y in L})] + return [self.subposet([self._list[i] for i in x]) for x in sorted({frozenset(y) for y in L})] # Caveat: list is overridden by the method list above!!! def antichains(self, element_constructor=None): @@ -4856,6 +4818,7 @@ def antichains(self, element_constructor=None): def f(antichain): return element_constructor(vertex_to_element(x) for x in antichain) + result = self._hasse_diagram.antichains(element_class=f) result.rename("Set of antichains of %s" % self) return result @@ -4920,6 +4883,7 @@ def width(self, certificate=False) -> Integer | tuple: # See the doc of dilworth_decomposition for an explanation of what is # going on. from sage.graphs.graph import Graph + n = self.cardinality() g = Graph() for v, u in self._hasse_diagram.transitive_closure().edge_iterator(labels=False): @@ -4974,6 +4938,7 @@ def dilworth_decomposition(self): True """ from sage.graphs.graph import Graph + n = self.cardinality() g = Graph() for v, u in self._hasse_diagram.transitive_closure().edge_iterator(labels=False): @@ -5049,9 +5014,7 @@ def chains(self, element_constructor=None, exclude=None): if exclude is not None: exclude = [self._element_to_vertex(x) for x in exclude] - result = self._hasse_diagram.chains(element_class=element_constructor, - exclude=exclude, - conversion=self._elements) + result = self._hasse_diagram.chains(element_class=element_constructor, exclude=exclude, conversion=self._elements) result.rename("Set of chains of %s" % self) return result @@ -5092,14 +5055,11 @@ def connected_components(self) -> builtins.list: if self._is_facade: for part in comps: G = part.relabel(self._vertex_to_element, inplace=False) - result.append(Poset(G, cover_relations=True, - facade=True)) + result.append(Poset(G, cover_relations=True, facade=True)) else: for part in comps: - G = part.relabel(lambda v: self._vertex_to_element(v).element, - inplace=False) - result.append(Poset(G, cover_relations=True, - facade=False)) + G = part.relabel(lambda v: self._vertex_to_element(v).element, inplace=False) + result.append(Poset(G, cover_relations=True, facade=False)) return result def ordinal_summands(self) -> builtins.list: @@ -5189,8 +5149,7 @@ def ordinal_summands(self) -> builtins.list: parts = [] for i, j in zip(cut_points, cut_points[1:]): G = self._hasse_diagram.subgraph(range(i + 1, j + 1)) - parts.append(Poset(G.relabel(self._vertex_to_element, - inplace=False))) + parts.append(Poset(G.relabel(self._vertex_to_element, inplace=False))) return parts def product(self, other): @@ -5243,17 +5202,13 @@ def product(self, other): sage: type(L) == type(L.product(L)) True """ - from sage.combinat.posets.lattices import LatticePoset, \ - JoinSemilattice, MeetSemilattice, FiniteLatticePoset, \ - FiniteMeetSemilattice, FiniteJoinSemilattice - if (isinstance(self, FiniteLatticePoset) and - isinstance(other, FiniteLatticePoset)): + from sage.combinat.posets.lattices import LatticePoset, JoinSemilattice, MeetSemilattice, FiniteLatticePoset, FiniteMeetSemilattice, FiniteJoinSemilattice + + if isinstance(self, FiniteLatticePoset) and isinstance(other, FiniteLatticePoset): constructor = LatticePoset - elif (isinstance(self, FiniteMeetSemilattice) and - isinstance(other, FiniteMeetSemilattice)): + elif isinstance(self, FiniteMeetSemilattice) and isinstance(other, FiniteMeetSemilattice): constructor = MeetSemilattice - elif (isinstance(self, FiniteJoinSemilattice) and - isinstance(other, FiniteJoinSemilattice)): + elif isinstance(self, FiniteJoinSemilattice) and isinstance(other, FiniteJoinSemilattice): constructor = JoinSemilattice else: constructor = Poset @@ -5382,6 +5337,7 @@ def factor(self) -> builtins.list: """ from sage.graphs.graph import Graph from sage.misc.flatten import flatten + dg = self._hasse_diagram if not dg.is_connected() or not dg.order(): raise NotImplementedError('the poset is empty or not connected') @@ -5402,8 +5358,7 @@ def factor(self) -> builtins.list: factors_range = range(n) def edge_color(va, vb): - return next(i for i, (vai, vbi) in enumerate(zip(va, vb)) - if vai != vbi) + return next(i for i, (vai, vbi) in enumerate(zip(va, vb)) if vai != vbi) neighbors_table = {} for x in prod_dg: @@ -5432,12 +5387,10 @@ def edge_color(va, vb): fusion_edges.append([i0, i1]) break - fusion = Graph([list(range(n)), fusion_edges], - format="vertices_and_edges") + fusion = Graph([list(range(n)), fusion_edges], format="vertices_and_edges") resu = [] for s in fusion.connected_components(sort=False): - subg = [x for x in prod_dg if all(x[i] == v0[i] for i in factors_range - if i not in s)] + subg = [x for x in prod_dg if all(x[i] == v0[i] for i in factors_range if i not in s)] resu.append(Poset(prod_dg.subgraph(subg))) return resu @@ -5507,8 +5460,7 @@ def disjoint_union(self, other, labels='pairs'): """ if not hasattr(other, 'hasse_diagram'): raise TypeError("'other' is not a finite poset") - return Poset(self.hasse_diagram().disjoint_union(other.hasse_diagram(), - labels=labels)) + return Poset(self.hasse_diagram().disjoint_union(other.hasse_diagram(), labels=labels)) def ordinal_product(self, other, labels='pairs'): r""" @@ -5577,8 +5529,7 @@ def ordinal_product(self, other, labels='pairs'): sage: C3.ordinal_product(C4).is_isomorphic(C12) True """ - from sage.combinat.posets.lattices import LatticePoset, \ - FiniteLatticePoset + from sage.combinat.posets.lattices import LatticePoset, FiniteLatticePoset if not hasattr(other, 'hasse_diagram'): raise TypeError("'other' is not a finite poset") @@ -5587,19 +5538,14 @@ def ordinal_product(self, other, labels='pairs'): dg = DiGraph() dg.add_vertices([(s, t) for s in self for t in other]) - dg.add_edges([((s, t), (s2, t2)) - for s, s2 in self.cover_relations_iterator() - for t in othermax for t2 in othermin]) - dg.add_edges([((s, t), (s, t2)) - for s in self - for t, t2 in other.cover_relations_iterator()]) + dg.add_edges([((s, t), (s2, t2)) for s, s2 in self.cover_relations_iterator() for t in othermax for t2 in othermin]) + dg.add_edges([((s, t), (s, t2)) for s in self for t, t2 in other.cover_relations_iterator()]) if labels == 'integers': dg.relabel() elif labels != 'pairs': raise ValueError("labels must be either 'pairs' or 'integers'") - if (isinstance(self, FiniteLatticePoset) and - isinstance(other, FiniteLatticePoset)): + if isinstance(self, FiniteLatticePoset) and isinstance(other, FiniteLatticePoset): return LatticePoset(dg) return Poset(dg) @@ -5676,9 +5622,7 @@ def ordinal_sum(self, other, labels='pairs'): sage: P0.ordinal_sum(P0) Finite lattice containing 0 elements """ - from sage.combinat.posets.lattices import LatticePoset, \ - JoinSemilattice, MeetSemilattice, FiniteLatticePoset, \ - FiniteMeetSemilattice, FiniteJoinSemilattice + from sage.combinat.posets.lattices import LatticePoset, JoinSemilattice, MeetSemilattice, FiniteLatticePoset, FiniteMeetSemilattice, FiniteJoinSemilattice if not hasattr(other, 'hasse_diagram'): raise TypeError("'other' is not a finite poset") @@ -5693,14 +5637,11 @@ def ordinal_sum(self, other, labels='pairs'): elif labels != 'pairs': raise ValueError("labels must be either 'pairs' or 'integers'") - if (isinstance(self, FiniteLatticePoset) and - isinstance(other, FiniteLatticePoset)): + if isinstance(self, FiniteLatticePoset) and isinstance(other, FiniteLatticePoset): return LatticePoset(G) - if (isinstance(self, FiniteMeetSemilattice) and - isinstance(other, FiniteMeetSemilattice)): + if isinstance(self, FiniteMeetSemilattice) and isinstance(other, FiniteMeetSemilattice): return MeetSemilattice(G) - if (isinstance(self, FiniteJoinSemilattice) and - isinstance(other, FiniteJoinSemilattice)): + if isinstance(self, FiniteJoinSemilattice) and isinstance(other, FiniteJoinSemilattice): return JoinSemilattice(G) return Poset(G) @@ -5935,12 +5876,8 @@ def dual(self): elements = reversed(self._elements) else: elements = None - H = self._hasse_diagram.relabel(dict(enumerate(self._elements)), - inplace=False) - return self._dual_class(H.reverse(), - elements=elements, - category=self.category(), - facade=self._is_facade) + H = self._hasse_diagram.relabel(dict(enumerate(self._elements)), inplace=False) + return self._dual_class(H.reverse(), elements=elements, category=self.category(), facade=self._is_facade) def with_bounds(self, labels=('bottom', 'top')): r""" @@ -6056,12 +5993,9 @@ def with_bounds(self, labels=('bottom', 'top')): if new_max in self: raise ValueError("the poset already has element %s" % new_max) - from sage.combinat.posets.lattices import LatticePoset, \ - JoinSemilattice, MeetSemilattice, FiniteLatticePoset, \ - FiniteMeetSemilattice, FiniteJoinSemilattice - if (isinstance(self, FiniteLatticePoset) or - (isinstance(self, FiniteMeetSemilattice) and new_max is not None) or - (isinstance(self, FiniteJoinSemilattice) and new_min is not None)): + from sage.combinat.posets.lattices import LatticePoset, JoinSemilattice, MeetSemilattice, FiniteLatticePoset, FiniteMeetSemilattice, FiniteJoinSemilattice + + if isinstance(self, FiniteLatticePoset) or (isinstance(self, FiniteMeetSemilattice) and new_max is not None) or (isinstance(self, FiniteJoinSemilattice) and new_min is not None): constructor = LatticePoset elif isinstance(self, FiniteMeetSemilattice): constructor = MeetSemilattice @@ -6255,9 +6189,7 @@ def relabel(self, relabeling=None): sage: p1 == p3 True """ - from sage.combinat.posets.lattices import (FiniteLatticePoset, - FiniteMeetSemilattice, - FiniteJoinSemilattice) + from sage.combinat.posets.lattices import FiniteLatticePoset, FiniteMeetSemilattice, FiniteJoinSemilattice if isinstance(self, FiniteLatticePoset): constructor = FiniteLatticePoset @@ -6269,28 +6201,21 @@ def relabel(self, relabeling=None): constructor = FinitePoset if relabeling is None: - return constructor(self._hasse_diagram, category=self.category(), - facade=self._is_facade) + return constructor(self._hasse_diagram, category=self.category(), facade=self._is_facade) if isinstance(relabeling, (list, tuple)): - relabeling = {i: relabeling[i] - for i in range(len(self._elements))} + relabeling = {i: relabeling[i] for i in range(len(self._elements))} else: if isinstance(relabeling, dict): relabeling = relabeling.__getitem__ - relabeling = {i: relabeling(x) - for i, x in enumerate(self._elements)} + relabeling = {i: relabeling(x) for i, x in enumerate(self._elements)} if not self._with_linear_extension: elements = None else: - elements = tuple(relabeling[self._element_to_vertex(x)] - for x in self._elements) + elements = tuple(relabeling[self._element_to_vertex(x)] for x in self._elements) - return constructor(self._hasse_diagram.relabel(relabeling, - inplace=False), - elements=elements, category=self.category(), - facade=self._is_facade) + return constructor(self._hasse_diagram.relabel(relabeling, inplace=False), elements=elements, category=self.category(), facade=self._is_facade) def canonical_label(self, algorithm=None): r""" @@ -6352,8 +6277,7 @@ def canonical_label(self, algorithm=None): sage: D2 == B2 # optional - bliss True """ - canonical_label = self._hasse_diagram.canonical_label(certificate=True, - algorithm=algorithm)[1] + canonical_label = self._hasse_diagram.canonical_label(certificate=True, algorithm=algorithm)[1] canonical_label = {self._elements[v]: i for v, i in canonical_label.items()} return self.relabel(canonical_label) @@ -6412,10 +6336,7 @@ def with_linear_extension(self, linear_extension): vertex_relabeling = dict(zip(new_vertices, linear_extension)) # Hack to get the actual class, not the categorified class constructor = self.__class__.__base__ - return constructor(self._hasse_diagram.relabel(vertex_relabeling, inplace=False), - elements=linear_extension, - category=self.category(), - facade=self._is_facade) + return constructor(self._hasse_diagram.relabel(vertex_relabeling, inplace=False), elements=linear_extension, category=self.category(), facade=self._is_facade) def graphviz_string(self, graph_string='graph', edge_string='--'): r""" @@ -6527,6 +6448,7 @@ def random_subposet(self, p): ValueError: probability p must be in [0..1] """ from sage.misc.randstate import current_randstate + random = current_randstate().python_random().random p = float(p) if p < 0 or p > 1: @@ -6576,6 +6498,7 @@ def random_order_ideal(self, direction='down'): from sage.misc.randstate import current_randstate from sage.misc.randstate import seed from sage.misc.randstate import random + hd = self._hasse_diagram n = len(hd) lower_covers = [list(hd.lower_covers_iterator(i)) for i in range(n)] @@ -6611,8 +6534,7 @@ def random_order_ideal(self, direction='down'): if direction == 'up': return [self._vertex_to_element(i) for i, x in enumerate(state) if x == 1] if direction == 'antichain': - return [self._vertex_to_element(i) for i, x in enumerate(state) - if x == 0 and all(state[j] == 1 for j in hd.upper_covers_iterator(i))] + return [self._vertex_to_element(i) for i, x in enumerate(state) if x == 0 and all(state[j] == 1 for j in hd.upper_covers_iterator(i))] if direction != 'down': raise ValueError("direction must be 'up', 'down' or 'antichain'") return [self._vertex_to_element(i) for i, x in enumerate(state) if x == 0] @@ -6715,7 +6637,7 @@ def random_linear_extension(self): new_index = randint(0, len(mins) - 1) new = mins[new_index] result.append(new) - mins = mins[:new_index] + mins[new_index + 1:] + mins = mins[:new_index] + mins[new_index + 1 :] for u in H.neighbor_out_iterator(new): indegs[u] -= 1 if indegs[u] == 0: @@ -6862,9 +6784,7 @@ def interval(self, x, y): sage: P.interval("a","d") [a, b, c, d] """ - return [self._vertex_to_element(w) - for w in self._hasse_diagram.interval( - self._element_to_vertex(x), self._element_to_vertex(y))] + return [self._vertex_to_element(w) for w in self._hasse_diagram.interval(self._element_to_vertex(x), self._element_to_vertex(y))] def closed_interval(self, x, y): r""" @@ -6891,8 +6811,7 @@ def closed_interval(self, x, y): sage: A.closed_interval(3, 7) [] """ - return [self._vertex_to_element(_) for _ in self._hasse_diagram.interval( - self._element_to_vertex(x), self._element_to_vertex(y))] + return [self._vertex_to_element(_) for _ in self._hasse_diagram.interval(self._element_to_vertex(x), self._element_to_vertex(y))] def open_interval(self, x, y): """ @@ -6921,8 +6840,7 @@ def open_interval(self, x, y): sage: A.open_interval(3, 7) [] """ - return [self._vertex_to_element(_) for _ in self._hasse_diagram.open_interval( - self._element_to_vertex(x), self._element_to_vertex(y))] + return [self._vertex_to_element(_) for _ in self._hasse_diagram.open_interval(self._element_to_vertex(x), self._element_to_vertex(y))] def comparability_graph(self): r""" @@ -7034,6 +6952,7 @@ def linear_extensions_graph(self): True """ from sage.graphs.graph import Graph + # Direct implementation, no optimizations L = list(self.linear_extensions()) G = Graph() @@ -7212,6 +7131,7 @@ def order_complex(self, on_ints=False): facets {(0, 1, 3), (0, 2, 3)} """ from sage.topology.simplicial_complex import SimplicialComplex + L = self.list() if on_ints: iso = {L[i]: i for i in range(len(L))} @@ -7266,8 +7186,8 @@ def order_polytope(self): True """ from sage.geometry.polyhedron.constructor import Polyhedron - ineqs = [[0] + [Integer(j == v) - Integer(j == u) for j in self] - for u, v in self.hasse_diagram().edges(sort=False, labels=False)] + + ineqs = [[0] + [Integer(j == v) - Integer(j == u) for j in self] for u, v in self.hasse_diagram().edges(sort=False, labels=False)] for i in self.maximal_elements(): ineqs += [[1] + [-Integer(j == i) for j in self]] for i in self.minimal_elements(): @@ -7305,8 +7225,8 @@ def chain_polytope(self): A 5-dimensional polyhedron in ZZ^5 defined as the convex hull of 8 vertices """ from sage.geometry.polyhedron.constructor import Polyhedron - ineqs = [[1] + [-Integer(j in chain) for j in self] - for chain in self.maximal_chains_iterator()] + + ineqs = [[1] + [-Integer(j in chain) for j in self] for chain in self.maximal_chains_iterator()] for i in self: ineqs += [[0] + [Integer(j == i) for j in self]] return Polyhedron(ieqs=ineqs, base_ring=ZZ) @@ -7418,12 +7338,12 @@ def apozeta_polynomial(self): Univariate Polynomial Ring in q over Rational Field """ from sage.functions.other import binomial + R = PolynomialRing(QQ, 'q') q = R.gen() top_level = self.level_sets()[-1] - return sum(binomial(q - 2, len(c) - 1) - for c in self.chains() if c and c[-1] in top_level) + return sum(binomial(q - 2, len(c) - 1) for c in self.chains() if c and c[-1] in top_level) def M_triangle(self): r""" @@ -7454,14 +7374,13 @@ def M_triangle(self): ValueError: the poset is not graded """ from sage.combinat.triangles_FHM import M_triangle + hasse = self._hasse_diagram rk = hasse.rank_function() if rk is None: raise ValueError('the poset is not graded') ring = PolynomialRing(ZZ, 'x,y') - p = ring.sum(hasse.moebius_function(a, b) * ring.monomial(rk(a), rk(b)) - for a in hasse - for b in hasse.principal_order_filter(a)) + p = ring.sum(hasse.moebius_function(a, b) * ring.monomial(rk(a), rk(b)) for a in hasse for b in hasse.principal_order_filter(a)) return M_triangle(p) def f_polynomial(self): @@ -7523,9 +7442,7 @@ def f_polynomial(self): # chains with topmost vertex i (in the labelling of the # Hasse diagram). for i in range(1, hasse_size - 1): - chain_polys[i] = q + sum(q * chain_polys[j] - for j in hasse.principal_order_ideal(i) - if j) + chain_polys[i] = q + sum(q * chain_polys[j] for j in hasse.principal_order_ideal(i) if j) return q + q * sum(chain_polys) def h_polynomial(self): @@ -7578,10 +7495,9 @@ def h_polynomial(self): mini = hasse.bottom() if (mini is None) or (maxi is None): raise ValueError("the poset is not bounded") - f = ring.sum(ring.monomial(len(ch)) - for ch in hasse.chains(exclude=[mini, maxi])) + f = ring.sum(ring.monomial(len(ch)) for ch in hasse.chains(exclude=[mini, maxi])) d = f.degree() - f = (1 - q)**d * q * f(q=q / (1 - q)) + f = (1 - q) ** d * q * f(q=q / (1 - q)) return ring(f) def flag_f_polynomial(self): @@ -7657,8 +7573,7 @@ def flag_f_polynomial(self): return PolynomialRing(ZZ, 'x', 1).one() anneau = PolynomialRing(ZZ, 'x', n + 1) x = anneau.gens() - return x[n] * sum(prod(x[rk(i)] for i in ch) - for ch in hasse.chains(exclude=[mini, maxi])) + return x[n] * sum(prod(x[rk(i)] for i in ch) for ch in hasse.chains(exclude=[mini, maxi])) def flag_h_polynomial(self): r""" @@ -7732,9 +7647,7 @@ def flag_h_polynomial(self): return PolynomialRing(QQ, 'x', 1).one() anneau = PolynomialRing(QQ, 'x', n + 1) x = anneau.gens() - return prod(1 - x[k] for k in range(1, n)) * x[n] \ - * sum(prod(x[rk(i)] / (1 - x[rk(i)]) for i in ch) - for ch in hasse.chains(exclude=[mini, maxi])) + return prod(1 - x[k] for k in range(1, n)) * x[n] * sum(prod(x[rk(i)] / (1 - x[rk(i)]) for i in ch) for ch in hasse.chains(exclude=[mini, maxi])) def characteristic_polynomial(self): r""" @@ -7780,8 +7693,7 @@ def characteristic_polynomial(self): raise ValueError("the poset does not have a bottom element") n = rk(H.maximal_elements()[0]) ring = PolynomialRing(ZZ, 'q') - return ring.sum(H.bottom_moebius_function(x) * ring.monomial(n - rk(x)) - for x in H) + return ring.sum(H.bottom_moebius_function(x) * ring.monomial(n - rk(x)) for x in H) def chain_polynomial(self): """ @@ -8310,8 +8222,7 @@ def is_eulerian(self, k=None, certificate=False) -> bool | tuple: for j in levels[level + rank_diff]: if H.is_lequal(i, j) and M[i, j] != 1: if certificate: - return (False, (self._vertex_to_element(i), - self._vertex_to_element(j))) + return (False, (self._vertex_to_element(i), self._vertex_to_element(j))) return False return (True, None) if certificate else True @@ -8372,9 +8283,7 @@ def is_greedy(self, certificate=False) -> bool | tuple: if certificate: if A_jumps > B_jumps: A, B = B, A - return (False, - (self.linear_extension([self[v] for v in A]), - self.linear_extension([self[v] for v in B]))) + return (False, (self.linear_extension([self[v] for v in A]), self.linear_extension([self[v] for v in B]))) return False return (True, None) if certificate else True @@ -8544,6 +8453,7 @@ def greene_shape(self): - Darij Grinberg (2013-05-09) """ from sage.combinat.partition import Partition + G, a = self.frank_network() n = len(self) chron = _ford_fulkerson_chronicle(G, (-1, 0), (2, 0), a) @@ -8662,6 +8572,7 @@ def p_partition_enumerator(self, tup, R, weights=None, check=False): raise ValueError("the elements of tup are not those of P") from sage.combinat.composition import Composition from sage.combinat.ncsf_qsym.qsym import QuasiSymmetricFunctions + QR = QuasiSymmetricFunctions(R) n = len(tup) res = QR.zero() @@ -8670,15 +8581,13 @@ def p_partition_enumerator(self, tup, R, weights=None, check=False): # The simple case: ``weights == None``. F = QR.Fundamental() for lin in self.linear_extensions(facade=True): - descents = [i + 1 for i in range(n - 1) - if tupdict[lin[i]] > tupdict[lin[i + 1]]] + descents = [i + 1 for i in range(n - 1) if tupdict[lin[i]] > tupdict[lin[i + 1]]] res += F(Composition(from_subset=(descents, n))) return res for lin in self.linear_extensions(facade=True): M = QR.Monomial() lin_weights = Composition([weights.get(lin[i], 1) for i in range(n)]) - descents = [i + 1 for i in range(n - 1) - if tupdict[lin[i]] > tupdict[lin[i + 1]]] + descents = [i + 1 for i in range(n - 1) if tupdict[lin[i]] > tupdict[lin[i + 1]]] d_c = Composition(from_subset=(descents, n)) for comp in d_c.finer(): res += M[lin_weights.fatten(comp)] @@ -8793,6 +8702,7 @@ def completion_by_cuts(self): Finite lattice containing 0 elements """ from sage.combinat.posets.lattices import LatticePoset + if self.cardinality() == 0: return LatticePoset({}) return LatticePoset((self.cuts(), lambda a, b: a.issuperset(b))) @@ -8811,6 +8721,7 @@ def incidence_algebra(self, R, prefix='I'): over Rational Field """ from sage.combinat.posets.incidence_algebras import IncidenceAlgebra + return IncidenceAlgebra(R, self, prefix) @cached_method(key=lambda self, x, y, l: (x, y)) @@ -8862,14 +8773,16 @@ def _kl_poly(self, x=None, y=None, canonical_labels=None): min_elt = self.minimal_elements()[0] if canonical_labels: + def sublat(P): return self.subposet(P).canonical_label() + else: + def sublat(P): return self.subposet(P) - poly = -sum(sublat(self.order_ideal([x])).characteristic_polynomial() * - sublat(self.order_filter([x])).kazhdan_lusztig_polynomial() - for x in self if x != min_elt) + + poly = -sum(sublat(self.order_ideal([x])).characteristic_polynomial() * sublat(self.order_filter([x])).kazhdan_lusztig_polynomial() for x in self if x != min_elt) tr = self.rank() // 2 + 1 ret = poly.truncate(tr) return ret(q=q) @@ -8991,14 +8904,12 @@ def is_induced_subposet(self, other) -> bool: ... AttributeError: 'str' object has no attribute 'subposet'... """ - if (not self._is_facade or (isinstance(other, FinitePoset) and - not other._is_facade)): + if not self._is_facade or (isinstance(other, FinitePoset) and not other._is_facade): raise TypeError("the function is not defined on non-facade posets") # TODO: When we have decided if # Poset({'x':[42]}) == LatticePoset({'x':[42]}) # or not, either remove this note or remove .hasse_diagram() below. - return (set(self).issubset(set(other)) and - other.subposet(self).hasse_diagram() == self.hasse_diagram()) + return set(self).issubset(set(other)) and other.subposet(self).hasse_diagram() == self.hasse_diagram() def _libgap_(self): """ @@ -9017,6 +8928,7 @@ def _libgap_(self): 13 """ from sage.libs.gap.libgap import libgap + libgap.LoadPackage("QPA") L = list(self) return libgap.Poset(L, [self.principal_order_filter(x) for x in L]) @@ -9043,8 +8955,7 @@ def _macaulay2_init_(self, macaulay2=None): H = self._hasse_diagram txt = 'needsPackage "Posets";' txt += "poset({%s},{" % ','.join(str(x) for x in H) - txt += ",".join(f"{{{str(x)},{str(y)}}}" - for x, y in H.cover_relations_iterator()) + txt += ",".join(f"{{{str(x)},{str(y)}}}" for x, y in H.cover_relations_iterator()) return txt + "})" @@ -9164,9 +9075,7 @@ def cardinality(self, from_iterator=False): """ # Obtained from The On-Line Encyclopedia of Integer Sequences; # this is sequence number A000112. - known_values = [1, 1, 2, 5, 16, 63, 318, 2045, 16999, 183231, - 2567284, 46749427, 1104891746, 33823827452, 1338193159771, - 68275077901156, 4483130665195087] + known_values = [1, 1, 2, 5, 16, 63, 318, 2045, 16999, 183231, 2567284, 46749427, 1104891746, 33823827452, 1338193159771, 68275077901156, 4483130665195087] if not from_iterator and self._n < len(known_values): return Integer(known_values[self._n]) return super().cardinality() diff --git a/src/sage/combinat/posets/sashes.py b/src/sage/combinat/posets/sashes.py index d9ee94ad37a..d74a95f03ac 100644 --- a/src/sage/combinat/posets/sashes.py +++ b/src/sage/combinat/posets/sashes.py @@ -100,13 +100,13 @@ def cover_relations(s: tuple[str, ...]) -> Iterator[tuple[str, ...]]: """ for i, letter in enumerate(s): if letter == BB: - yield s[:i] + (B, B) + s[i + 1:] + yield s[:i] + (B, B) + s[i + 1 :] for i, (l1, l2) in enumerate(pairwise(s)): if l1 == N: if l2 == B: - yield s[:i] + (BB,) + s[i + 2:] + yield s[:i] + (BB,) + s[i + 2 :] else: - yield s[:i] + (B,) + s[i + 1:] + yield s[:i] + (B,) + s[i + 1 :] if s[-1] == N: yield s[:-1] + (B,) @@ -136,9 +136,7 @@ def lattice_of_sashes(n: int) -> LatticePoset: if n <= 0: raise ValueError("n must be positive") cat = FiniteLatticePosets().CongruenceUniform() - return LatticePoset({s: list(cover_relations(s)) for s in sashes(n)}, - cover_relations=True, check=False, - category=cat) + return LatticePoset({s: list(cover_relations(s)) for s in sashes(n)}, cover_relations=True, check=False, category=cat) @cached_function @@ -218,6 +216,7 @@ def pellytope(n: int) -> Polyhedron: - [BTTM2024]_ """ from sage.geometry.polyhedron.library import Polytopes + if n <= 0: raise ValueError("n must be positive") M = FreeModule(ZZ, n) @@ -226,5 +225,4 @@ def pellytope(n: int) -> Polyhedron: resu = Polytopes().hypercube(n, intervals='zero_one') - return resu + sum(Polyhedron(vertices=[zero, v[i], v[i] + v[i + 1]]) - for i in range(n - 1)) + return resu + sum(Polyhedron(vertices=[zero, v[i], v[i] + v[i + 1]]) for i in range(n - 1)) diff --git a/src/sage/combinat/positive_integer_semigroup_test.py b/src/sage/combinat/positive_integer_semigroup_test.py index dc5471c4f59..077428fee39 100644 --- a/src/sage/combinat/positive_integer_semigroup_test.py +++ b/src/sage/combinat/positive_integer_semigroup_test.py @@ -8,9 +8,8 @@ def test_positive_integer_semigroup(): """ from sage.misc.sage_unittest import TestSuite from sage.combinat.backtrack import PositiveIntegerSemigroup + PP = PositiveIntegerSemigroup() # fewer max_runs since these are kind of slow - TestSuite(PP).run(verbose=True, - raise_on_failure=True, - max_runs=256) + TestSuite(PP).run(verbose=True, raise_on_failure=True, max_runs=256) diff --git a/src/sage/combinat/q_analogues.py b/src/sage/combinat/q_analogues.py index 7d3d215f7c1..13da2e3a43c 100644 --- a/src/sage/combinat/q_analogues.py +++ b/src/sage/combinat/q_analogues.py @@ -20,6 +20,7 @@ from sage.rings.polynomial.polynomial_ring import polygen from sage.structure.element import parent from sage.misc.lazy_import import lazy_import + lazy_import('sage.symbolic.ring', 'SymbolicRing') @@ -80,7 +81,7 @@ def q_int(n, q=None): return parent(q)(0) if n > 0: return sum(q**i for i in range(n)) - return -q**n * sum(q**i for i in range(-n)) + return -(q**n) * sum(q**i for i in range(-n)) def q_factorial(n, q=None): @@ -337,10 +338,11 @@ def q_binomial(n, k, q=None, algorithm='auto'): q = LaurentPolynomialRing(ZZ, 'q').gen() else: from sage.rings.polynomial.polynomial_element import Polynomial + is_polynomial = isinstance(q, Polynomial) if n < 0: - return (-1)**k * q**(k * n - (k * k - k) // 2) * q_binomial(-n + k - 1, k, q=q) + return (-1) ** k * q ** (k * n - (k * k - k) // 2) * q_binomial(-n + k - 1, k, q=q) k = min(n - k, k) # Pick the smallest k @@ -383,9 +385,8 @@ def q_binomial(n, k, q=None, algorithm='auto'): return q_binomial(n, k)(q) if algorithm == 'cyclotomic': from sage.rings.polynomial.cyclotomic import cyclotomic_value - return prod(cyclotomic_value(d, q) - for d in range(2, n + 1) - if (n//d) != (k//d) + ((n-k)//d)) + + return prod(cyclotomic_value(d, q) for d in range(2, n + 1) if (n // d) != (k // d) + ((n - k) // d)) raise ValueError("unknown algorithm {!r}".format(algorithm)) @@ -511,10 +512,7 @@ def q_catalan_number(n, q=None, m=1): if n in {0, 1}: return q_int(1, q) if n >= 2: - return (prod(q_int(j, q) - for j in range(m * n + 2, (m + 1) * n + 1)) // - prod(q_int(j, q) - for j in range(2, n + 1))) + return prod(q_int(j, q) for j in range(m * n + 2, (m + 1) * n + 1)) // prod(q_int(j, q) for j in range(2, n + 1)) raise ValueError(f"argument ({n}) must be a nonnegative integer") @@ -619,8 +617,8 @@ def q_pochhammer(n, a, q=None): R = parent(q) one = R(1) if n < 0: - return R.prod(one / (one - a/q**k) for k in range(1, -n+1)) - return R.prod((one - a*q**k) for k in range(n)) + return R.prod(one / (one - a / q**k) for k in range(1, -n + 1)) + return R.prod((one - a * q**k) for k in range(n)) @cached_function(key=lambda t, q: (_Partitions(t), q)) @@ -842,17 +840,18 @@ def q_subgroups_of_abelian_group(la, mu, q=None, algorithm='birkhoff'): return parent(q)(0) if algorithm == 'delsarte': + def F(args): - prd = lambda j: prod(args[j]-q**i for i in range(mu_c[j+1], mu_c[j])) - F1 = prod(args[i]**mu_c[i+1] * prd(i) for i in range(k-1)) - return F1 * prod(args[k-1]-q**i for i in range(mu_c[k-1])) + prd = lambda j: prod(args[j] - q**i for i in range(mu_c[j + 1], mu_c[j])) + F1 = prod(args[i] ** mu_c[i + 1] * prd(i) for i in range(k - 1)) + return F1 * prod(args[k - 1] - q**i for i in range(mu_c[k - 1])) - return F([q**ss for ss in la_c[:k]])//F([q**rr for rr in mu_c]) + return F([q**ss for ss in la_c[:k]]) // F([q**rr for rr in mu_c]) if algorithm == 'birkhoff': - fac1 = q**(sum(mu_c[i+1] * (la_c[i]-mu_c[i]) for i in range(k-1))) - fac2 = prod(q_binomial(la_c[i]-mu_c[i+1], mu_c[i]-mu_c[i+1], q=q) for i in range(k-1)) - fac3 = q_binomial(la_c[k-1], mu_c[k-1], q=q) + fac1 = q ** (sum(mu_c[i + 1] * (la_c[i] - mu_c[i]) for i in range(k - 1))) + fac2 = prod(q_binomial(la_c[i] - mu_c[i + 1], mu_c[i] - mu_c[i + 1], q=q) for i in range(k - 1)) + fac3 = q_binomial(la_c[k - 1], mu_c[k - 1], q=q) return prod([fac1, fac2, fac3]) @@ -921,8 +920,7 @@ def q_stirling_number1(n, k, q=None): return parent(q)(1) if k > n or k < 1: return parent(q)(0) - return (q_stirling_number1(n - 1, k - 1, q=q) + - q_int(n - 1, q=q) * q_stirling_number1(n - 1, k, q=q)) + return q_stirling_number1(n - 1, k - 1, q=q) + q_int(n - 1, q=q) * q_stirling_number1(n - 1, k, q=q) @cached_function @@ -983,8 +981,7 @@ def q_stirling_number2(n, k, q=None): return parent(q)(1) if k > n or k <= 0: return parent(q)(0) - return (q**(k-1)*q_stirling_number2(n - 1, k - 1, q=q) + - q_int(k, q=q) * q_stirling_number2(n - 1, k, q=q)) + return q ** (k - 1) * q_stirling_number2(n - 1, k - 1, q=q) + q_int(k, q=q) * q_stirling_number2(n - 1, k, q=q) def number_of_irreducible_polynomials(n, q=None, m=1): @@ -1047,11 +1044,13 @@ def number_of_irreducible_polynomials(n, q=None, m=1): if q is None: from sage.rings.rational_field import QQ + q = QQ['q'].gen() # we produce an integer-valued polynomial in q, but it does not necessarily have integer coefficients if m == 1: from sage.arith.misc import moebius - r = sum((moebius(n//d) * q**d for d in n.divisors()), parent(q).zero()) + + r = sum((moebius(n // d) * q**d for d in n.divisors()), parent(q).zero()) return r // n from sage.functions.other import binomial @@ -1063,13 +1062,13 @@ def monic_reducible(irreducible, d): given the numbers of irreducible polynomials up to degree `d-1`. """ res = 0 - for p in Partitions(d+1, max_part=d): - res += prod(binomial(r+t-1, t) for r, t in zip(irreducible, p.to_exp(d))) + for p in Partitions(d + 1, max_part=d): + res += prod(binomial(r + t - 1, t) for r, t in zip(irreducible, p.to_exp(d))) return res r = [] for d in range(n): - monic = (q**binomial(d + m, m - 1) - 1) * q**binomial(d + m, m) // (q - 1) + monic = (q ** binomial(d + m, m - 1) - 1) * q ** binomial(d + m, m) // (q - 1) reducible = monic_reducible(r, d) r.append(monic - reducible) diff --git a/src/sage/combinat/ranker.py b/src/sage/combinat/ranker.py index 873424268d3..a9713c67b6c 100644 --- a/src/sage/combinat/ranker.py +++ b/src/sage/combinat/ranker.py @@ -1,7 +1,8 @@ r""" Rankers """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2007 Mike Hansen , # Nicolas M. Thiery # Ported from MuPAD-Combinat (combinat::rankers) @@ -102,7 +103,7 @@ def rank_from_list(l): sage: TestSuite(r).run() """ - return CallableDict((x,i) for i,x in enumerate(l)) + return CallableDict((x, i) for i, x in enumerate(l)) def unrank_from_list(l): @@ -153,6 +154,7 @@ def on_fly(): .. TODO:: add tests as in combinat::rankers """ + def count(): i = 0 while True: diff --git a/src/sage/combinat/recognizable_series.py b/src/sage/combinat/recognizable_series.py index e41c54fc758..40f39798e3c 100644 --- a/src/sage/combinat/recognizable_series.py +++ b/src/sage/combinat/recognizable_series.py @@ -56,7 +56,7 @@ class PrefixClosedSet: - def __init__(self, words) -> None: + def __init__(self, words) -> None: r""" A prefix-closed set. @@ -102,6 +102,7 @@ def create_by_alphabet(cls, alphabet): [word: ] """ from sage.combinat.words.words import Words + return cls(Words(alphabet, infinite=False)) def __repr__(self) -> str: @@ -151,11 +152,8 @@ def add(self, w, check=True) -> None: ... ValueError: cannot add as not all prefixes of 11 are included yet """ - if check and any(p not in self.elements - for p in w.prefixes_iterator() - if p != w): - raise ValueError('cannot add as not all prefixes of ' - '{} are included yet'.format(w)) + if check and any(p not in self.elements for p in w.prefixes_iterator() if p != w): + raise ValueError('cannot add as not all prefixes of ' '{} are included yet'.format(w)) self.elements.append(w) def iterate_possible_additions(self): @@ -258,10 +256,7 @@ def prefix_set(self) -> list: [word: 01, word: 11, word: 001, word: 100, word: 101, word: 0000, word: 0001] """ - return [p + a - for p in self.elements - for a in self.words.iterate_by_length(1) - if p + a not in self.elements] + return [p + a for p in self.elements for a in self.words.iterate_by_length(1) if p + a not in self.elements] def minimize_result(operation): @@ -343,6 +338,7 @@ def minimize_result(operation): sage: t.nooperation(minimize=False) is t True """ + @wraps(operation) def minimized(self, *args, **kwds): minimize = kwds.pop('minimize', None) @@ -576,6 +572,7 @@ def _repr_(self, latex=False) -> str: if latex: from sage.misc.latex import latex as latex_repr + fr = latex_repr fs = latex_repr times = ' ' @@ -603,8 +600,7 @@ def all_coefficients(): coefficients = islice(all_coefficients(), 10) - s = ' + '.join(summand(w, c) - for w, c in coefficients) + s = ' + '.join(summand(w, c) for w, c in coefficients) s = s.replace('+ -', '- ') if not s: s = '0' @@ -747,6 +743,7 @@ def _mu_of_word_(self, w): if w not in W: raise ValueError('index {} is not in {}'.format(w, W)) from sage.misc.misc_c import prod + return prod((self.mu[a] for a in w), z=self._mu_of_empty_word_()) def __iter__(self): @@ -847,9 +844,7 @@ def is_trivial_zero(self) -> bool: sage: S.is_zero() True """ - return not self.left or not self.right or \ - (all(not self.mu[a] for a in self.parent().alphabet()) and - not self[self.parent().indices()()]) + return not self.left or not self.right or (all(not self.mu[a] for a in self.parent().alphabet()) and not self[self.parent().indices()()]) def __bool__(self) -> bool: r""" @@ -1021,15 +1016,14 @@ def transposed(self): sage: T.mu[0].is_immutable(), T.mu[1].is_immutable(), T.left.is_immutable(), T.right.is_immutable() (True, True, True, True) """ + def tr(M): T = M.transpose() T.set_immutable() return T P = self.parent() - return P.element_class(P, self.mu.map(tr), - left=self.right, - right=self.left) + return P.element_class(P, self.mu.map(tr), left=self.right, right=self.left) @cached_method def minimized(self): @@ -1175,9 +1169,7 @@ def _minimized_left_(self): return self.parent().zero() Left = [left] for p in pcs.iterate_possible_additions(): - left = self.coefficient_of_word(p, - multiply_left=True, - multiply_right=False) + left = self.coefficient_of_word(p, multiply_left=True, multiply_right=False) try: Matrix(Left).solve_left(left) except ValueError: @@ -1195,8 +1187,7 @@ def alpha(c): mu_prime = [] for a in self.parent().alphabet(): a = self.parent().indices()([a]) - M = Matrix([alpha(c) if c in C else tuple((c == q) for q in P) - for c in (p + a for p in P)]) + M = Matrix([alpha(c) if c in C else tuple((c == q) for q in P) for c in (p + a for p in P)]) mu_prime.append(M) left_prime = vector([ZZ.one()] + (len(P) - 1) * [ZZ.zero()]) @@ -1257,13 +1248,10 @@ def _add_(self, other): (1)) """ from sage.modules.free_module_element import vector + P = self.parent() - result = P.element_class( - P, - {a: self.mu[a].block_sum(other.mu[a]) for a in P.alphabet()}, - vector(tuple(self.left) + tuple(other.left)), - vector(tuple(self.right) + tuple(other.right))) + result = P.element_class(P, {a: self.mu[a].block_sum(other.mu[a]) for a in P.alphabet()}, vector(tuple(self.left) + tuple(other.left)), vector(tuple(self.right) + tuple(other.right))) return result @@ -1502,17 +1490,15 @@ def hadamard_product(self, other): """ from sage.matrix.constructor import Matrix from sage.modules.free_module_element import vector + P = self.parent() def tensor_product(left, right): T = left.tensor_product(right) T.subdivide() return T - result = P.element_class( - P, - {a: tensor_product(self.mu[a], other.mu[a]) for a in P.alphabet()}, - vector(tensor_product(Matrix(self.left), Matrix(other.left))), - vector(tensor_product(Matrix(self.right), Matrix(other.right)))) + + result = P.element_class(P, {a: tensor_product(self.mu[a], other.mu[a]) for a in P.alphabet()}, vector(tensor_product(Matrix(self.left), Matrix(other.left))), vector(tensor_product(Matrix(self.right), Matrix(other.right)))) return result @@ -1583,6 +1569,7 @@ class RecognizableSeriesSpace(UniqueRepresentation, Parent): :doc:`recognizable series `, :class:`RecognizableSeries`. """ + Element = RecognizableSeries @staticmethod @@ -1608,15 +1595,10 @@ def __classcall__(cls, *args, **kwds): sage: Rec1 is Rec2 is Rec3 True """ - return super().__classcall__( - cls, *cls.__normalize__(*args, **kwds)) + return super().__classcall__(cls, *cls.__normalize__(*args, **kwds)) @classmethod - def __normalize__(cls, - coefficient_ring=None, - alphabet=None, indices=None, - category=None, - minimize_results=True): + def __normalize__(cls, coefficient_ring=None, alphabet=None, indices=None, category=None, minimize_results=True): r""" Normalize the input in order to ensure a unique representation. @@ -1658,6 +1640,7 @@ def __normalize__(cls, if indices is None: from sage.combinat.words.words import Words + indices = Words(alphabet, infinite=False) if not indices.alphabet().is_finite(): raise NotImplementedError('alphabet is not finite') @@ -1665,17 +1648,17 @@ def __normalize__(cls, if coefficient_ring is None: raise ValueError('no coefficient ring specified') from sage.categories.semirings import Semirings + if coefficient_ring not in Semirings(): - raise ValueError( - 'coefficient ring {} is not a semiring'.format(coefficient_ring)) + raise ValueError('coefficient ring {} is not a semiring'.format(coefficient_ring)) from sage.categories.modules import Modules + category = category or Modules(coefficient_ring) return (coefficient_ring, indices, category, minimize_results) - def __init__(self, coefficient_ring, indices, - category, minimize_results) -> None: + def __init__(self, coefficient_ring, indices, category, minimize_results) -> None: r""" See :class:`RecognizableSeriesSpace` for details. @@ -1731,8 +1714,7 @@ def __init__(self, coefficient_ring, indices, """ self._indices_ = indices self._minimize_results_ = minimize_results - super().__init__( - category=category, base=coefficient_ring) + super().__init__(category=category, base=coefficient_ring) def __reduce__(self): r""" @@ -1744,8 +1726,7 @@ def __reduce__(self): sage: loads(dumps(Rec)) # indirect doctest Space of recognizable series on {0, 1} with coefficients in Integer Ring """ - return _pickle_RecognizableSeriesSpace, \ - (self.coefficient_ring(), self.indices(), self.category()) + return _pickle_RecognizableSeriesSpace, (self.coefficient_ring(), self.indices(), self.category()) def alphabet(self): r""" @@ -1823,9 +1804,7 @@ def _repr_(self) -> str: sage: repr(RecognizableSeriesSpace(ZZ, [0, 1])) # indirect doctest 'Space of recognizable series on {0, 1} with coefficients in Integer Ring' """ - return 'Space of recognizable series on {} ' \ - 'with coefficients in {}'.format(self.alphabet(), - self.coefficient_ring()) + return 'Space of recognizable series on {} ' 'with coefficients in {}'.format(self.alphabet(), self.coefficient_ring()) def _an_element_(self): r""" @@ -1841,12 +1820,11 @@ def _an_element_(self): """ from sage.matrix.constructor import Matrix from sage.modules.free_module_element import vector + z = self.coefficient_ring().zero() o = self.coefficient_ring().one() e = self.coefficient_ring().an_element() - return self([Matrix([[o, z], [i * o, o]]) - for i, _ in enumerate(self.alphabet())], - vector([z, e]), right=vector([e, z])) + return self([Matrix([[o, z], [i * o, o]]) for i, _ in enumerate(self.alphabet())], vector([z, e]), right=vector([e, z])) def some_elements(self, **kwds): r""" @@ -1880,6 +1858,7 @@ def some_elements(self, **kwds): from itertools import islice from sage.matrix.matrix_space import MatrixSpace from sage.modules.free_module import FreeModule + yield self.an_element() C = self.coefficient_ring() @@ -1912,9 +1891,7 @@ def _zero_(self): from sage.modules.free_module_element import vector from sage.sets.family import Family - return self.element_class( - self, Family(self.alphabet(), lambda a: Matrix()), - vector([]), vector([])) + return self.element_class(self, Family(self.alphabet(), lambda a: Matrix()), vector([]), vector([])) @cached_method def one(self): @@ -1942,10 +1919,7 @@ def one(self): R = self.coefficient_ring() one = R.one() zero = R.zero() - return self.element_class(self, - len(self.alphabet())*[Matrix([[zero]])], - vector([one]), - vector([one])) + return self.element_class(self, len(self.alphabet()) * [Matrix([[zero]])], vector([one]), vector([one])) @cached_method def one_hadamard(self): @@ -1972,11 +1946,9 @@ def one_hadamard(self): from sage.modules.free_module_element import vector one = self.coefficient_ring()(1) - return self({a: Matrix([[one]]) for a in self.alphabet()}, - vector([one]), vector([one])) + return self({a: Matrix([[one]]) for a in self.alphabet()}, vector([one]), vector([one])) - def _element_constructor_(self, data, - left=None, right=None): + def _element_constructor_(self, data, left=None, right=None): r""" Return a recognizable series. diff --git a/src/sage/combinat/regular_sequence.py b/src/sage/combinat/regular_sequence.py index 49fd29fb29d..cc1d1bc8b56 100644 --- a/src/sage/combinat/regular_sequence.py +++ b/src/sage/combinat/regular_sequence.py @@ -168,6 +168,7 @@ class DegeneratedSequenceError(RuntimeError): You can use 'allow_degenerated_sequence=True' followed by a call of method .regenerated() for correcting this. """ + pass @@ -252,11 +253,8 @@ def _repr_(self): '2-regular sequence 0, 1, 3, 5, 9, 11, 15, 19, 27, 29, ...' """ from sage.misc.lazy_list import lazy_list_formatter - return lazy_list_formatter( - self, - name='{}-regular sequence'.format(self.parent().k), - opening_delimiter='', closing_delimiter='', - preview=10) + + return lazy_list_formatter(self, name='{}-regular sequence'.format(self.parent().k), opening_delimiter='', closing_delimiter='', preview=10) @cached_method def coefficient_of_n(self, n, **kwds): @@ -329,6 +327,7 @@ def __iter__(self): True """ from itertools import count + return iter(self[n] for n in count()) @cached_method @@ -363,6 +362,7 @@ def is_degenerated(self) -> bool: False """ from sage.rings.integer_ring import ZZ + return (self.mu[ZZ.zero()] * self.right) != self.right def _error_if_degenerated_(self): @@ -384,12 +384,7 @@ def _error_if_degenerated_(self): by a call of method .regenerated() for correcting this. """ if self.is_degenerated(): - raise DegeneratedSequenceError( - "degenerated sequence: mu[0]*right != right. " - "Using such a sequence might lead to wrong results. " - "You can use 'allow_degenerated_sequence=True' followed by " - "a call of method .regenerated() " - "for correcting this.") + raise DegeneratedSequenceError("degenerated sequence: mu[0]*right != right. " "Using such a sequence might lead to wrong results. " "You can use 'allow_degenerated_sequence=True' followed by " "a call of method .regenerated() " "for correcting this.") @cached_method @minimize_result @@ -476,13 +471,9 @@ def regenerated(self): z = next(itA) W0 = Matrix(dim, 1, (I - self.mu[z]) * self.right) mu = {z: Matrix.block([[self.mu[z], W0], [Zr, 1]])} - mu.update((r, Matrix.block([[self.mu[r], Zc], [Zr, 0]])) - for r in itA) + mu.update((r, Matrix.block([[self.mu[r], Zc], [Zr, 0]])) for r in itA) - return P.element_class( - P, mu, - vector(tuple(self.left) + (0,)), - vector(tuple(self.right) + (1,))) + return P.element_class(P, mu, vector(tuple(self.left) + (0,)), vector(tuple(self.right) + (1,))) def transposed(self, allow_degenerated_sequence=False): r""" @@ -768,8 +759,7 @@ def subsequence(self, a, b): b = {ZZ(b): ZZ(1)} if a == 0: - return sum(c_j * self[b_j] * self.parent().one_hadamard() - for b_j, c_j in b.items()) + return sum(c_j * self[b_j] * self.parent().one_hadamard() for b_j, c_j in b.items()) if a == 1 and len(b) == 1 and zero in b: return b[zero] * self if a < 0: @@ -777,6 +767,7 @@ def subsequence(self, a, b): from sage.matrix.constructor import Matrix from sage.modules.free_module_element import vector + P = self.parent() A = P.alphabet() k = P.k @@ -833,16 +824,7 @@ def matrix_row(r, c): # We explicitly set the ring when creating vectors in order to avoid # problems with the zero sequence, see issue:`37282`. - result = P.element_class( - P, - {r: Matrix.block([matrix_row(r, c) for c in kernel]) - for r in A}, - vector(P.coefficient_ring(), chain.from_iterable( - b.get(c, 0) * self.left - for c in kernel)), - vector(P.coefficient_ring(), chain.from_iterable( - (self.coefficient_of_n(c, multiply_left=False) if c >= 0 else zero_R) - for c in kernel))) + result = P.element_class(P, {r: Matrix.block([matrix_row(r, c) for c in kernel]) for r in A}, vector(P.coefficient_ring(), chain.from_iterable(b.get(c, 0) * self.left for c in kernel)), vector(P.coefficient_ring(), chain.from_iterable((self.coefficient_of_n(c, multiply_left=False) if c >= 0 else zero_R) for c in kernel))) return result @@ -1082,12 +1064,8 @@ def tensor_product(left, right): T.subdivide() return T - matrices_0 = {r: sum(tensor_product(self.mu[s], other.mu[r-s]) - for s in srange(0, r+1)) - for r in P.alphabet()} - matrices_1 = {r: sum(tensor_product(self.mu[s], other.mu[k+r-s]) - for s in srange(r+1, k)) - for r in P.alphabet()} + matrices_0 = {r: sum(tensor_product(self.mu[s], other.mu[r - s]) for s in srange(0, r + 1)) for r in P.alphabet()} + matrices_1 = {r: sum(tensor_product(self.mu[s], other.mu[k + r - s]) for s in srange(r + 1, k)) for r in P.alphabet()} left = vector(tensor_product(Matrix(self.left), Matrix(other.left))) right = vector(tensor_product(Matrix(self.right), Matrix(other.right))) @@ -1100,20 +1078,13 @@ def linear_representation_morphism_recurrence_order_1(C, D): Z = zero_matrix(C[0].dimensions()[0]) def blocks(r): - upper = [[C[s], D[s], Z] - for s in reversed(srange(max(0, r-2), r+1))] - lower = [[Z, C[s], D[s]] - for s in reversed(srange(k-3+len(upper), k))] + upper = [[C[s], D[s], Z] for s in reversed(srange(max(0, r - 2), r + 1))] + lower = [[Z, C[s], D[s]] for s in reversed(srange(k - 3 + len(upper), k))] return upper + lower return {r: Matrix.block(blocks(r)) for r in P.alphabet()} - result = P.element_class( - P, - linear_representation_morphism_recurrence_order_1(matrices_0, - matrices_1), - vector(list(left) + (2*len(list(left)))*[0]), - vector(list(right) + (2*len(list(right)))*[0])) + result = P.element_class(P, linear_representation_morphism_recurrence_order_1(matrices_0, matrices_1), vector(list(left) + (2 * len(list(left))) * [0]), vector(list(right) + (2 * len(list(right))) * [0])) return result @@ -1267,15 +1238,10 @@ def partial_sums(self, include_n=False): assert z == 0 B = {z: Z} for r in A: - B[r+1] = B[r] + self.mu[r] + B[r + 1] = B[r] + self.mu[r] C = B[k] - result = P.element_class( - P, - {r: Matrix.block([[C, B[r]], [Z, self.mu[r]]]) for r in A}, - vector(chain(self.left, - (dim * (0,) if not include_n else self.left))), - vector(chain(dim * (0,), self.right))) + result = P.element_class(P, {r: Matrix.block([[C, B[r]], [Z, self.mu[r]]]) for r in A}, vector(chain(self.left, (dim * (0,) if not include_n else self.left))), vector(chain(dim * (0,), self.right))) return result @@ -1389,6 +1355,7 @@ def is_bounded(self) -> bool: True """ from sage.combinat.regular_sequence_bounded import regular_sequence_is_bounded + return regular_sequence_is_bounded(self) @@ -1432,13 +1399,11 @@ class RegularSequenceRing(RecognizableSeriesSpace): :doc:`k-regular sequence `, :class:`RegularSequence`. """ + Element = RegularSequence @classmethod - def __normalize__(cls, k, - coefficient_ring, - category=None, - **kwds): + def __normalize__(cls, k, coefficient_ring, category=None, **kwds): r""" Normalize the input in order to ensure a unique representation. @@ -1455,11 +1420,9 @@ def __normalize__(cls, k, """ from sage.arith.srange import srange from sage.categories.algebras import Algebras + category = category or Algebras(coefficient_ring) - nargs = super().__normalize__(coefficient_ring, - alphabet=srange(k), - category=category, - **kwds) + nargs = super().__normalize__(coefficient_ring, alphabet=srange(k), category=category, **kwds) return (k,) + nargs def __init__(self, k, *args, **kwds): @@ -1505,8 +1468,7 @@ def __reduce__(self): sage: loads(dumps(Seq2)) # indirect doctest Space of 2-regular sequences over Integer Ring """ - return _pickle_RegularSequenceRing, \ - (self.k, self.coefficient_ring(), self.category()) + return _pickle_RegularSequenceRing, (self.k, self.coefficient_ring(), self.category()) def _repr_(self): r""" @@ -1543,6 +1505,7 @@ def _n_to_index_(self, n): ValueError: value -1 of index is negative """ from sage.rings.integer_ring import ZZ + n = ZZ(n) W = self.indices() try: @@ -1577,11 +1540,7 @@ def one(self): R = self.coefficient_ring() one = R.one() zero = R.zero() - return self.element_class(self, - [Matrix([[one]])] - + (self.k-1)*[Matrix([[zero]])], - vector([one]), - vector([one])) + return self.element_class(self, [Matrix([[one]])] + (self.k - 1) * [Matrix([[zero]])], vector([one]), vector([one])) def some_elements(self): r""" @@ -1604,10 +1563,7 @@ def some_elements(self): ... 2-regular sequence 2210, 170, 0, 0, 0, 0, 0, 0, 0, 0, ...) """ - return iter(element.regenerated() - for element - in super().some_elements( - allow_degenerated_sequence=True)) + return iter(element.regenerated() for element in super().some_elements(allow_degenerated_sequence=True)) def _element_constructor_(self, *args, **kwds): r""" @@ -1935,6 +1891,7 @@ def guess(self, f, n_verify=100, max_exponent=10, sequence=None): RuntimeError: no invertible submatrix found """ import logging + logger = logging.getLogger(__name__) from sage.arith.srange import srange, xsrange @@ -2023,9 +1980,7 @@ def verify_linear_combination(t_L, r_L, linear_combination, lines): be evaluated beyond ``n_verify``, determining an invertible submatrix in ``some_inverse_U_matrix`` might require us to do so. """ - return all(f(k**t_L * m + r_L) == - linear_combination * vector(values(m, lines)) - for m in xsrange(0, (n_verify - r_L) // k**t_L + 1)) + return all(f(k**t_L * m + r_L) == linear_combination * vector(values(m, lines)) for m in xsrange(0, (n_verify - r_L) // k**t_L + 1)) class NoLinearCombination(RuntimeError): pass @@ -2055,13 +2010,12 @@ def include(t, r): if left is None: include(0, 0) # entries (t, r) --> k**t * m + r assert len(lines) == 1 - left = vector(len(seq(0))*(zero,) + (one,)) + left = vector(len(seq(0)) * (zero,) + (one,)) while to_branch: t_R, r_R = to_branch.pop(0) if t_R >= max_exponent: - raise RuntimeError(f'aborting as exponents would be larger ' - f'than max_exponent={max_exponent}') + raise RuntimeError(f'aborting as exponents would be larger ' f'than max_exponent={max_exponent}') t_L = t_R + 1 for s_L in srange(k): @@ -2070,14 +2024,12 @@ def include(t, r): linear_combination = find_linear_combination(t_L, r_L, lines) except NoLinearCombination: include(t_L, r_L) # entries (t, r) --> k**t * m + r - linear_combination = (len(lines)-1)*(zero,) + (one,) - logger.debug('M_%s: f_{%s*m+%s} = %s * F_m', - s_L, k**t_L, r_L, linear_combination) + linear_combination = (len(lines) - 1) * (zero,) + (one,) + logger.debug('M_%s: f_{%s*m+%s} = %s * F_m', s_L, k**t_L, r_L, linear_combination) mu[s_L].append(linear_combination) d = len(seq(0)) + len(lines) - mu = tuple(Matrix(domain, [pad_right(tuple(row), d, zero=zero) for row in M]) - for M in mu) + mu = tuple(Matrix(domain, [pad_right(tuple(row), d, zero=zero) for row in M]) for M in mu) right = vector(values(0, lines)) left = vector(pad_right(tuple(left), d, zero=zero)) return self(mu, left, right) @@ -2878,9 +2830,7 @@ def parse_multiplication(op, eq): return [operands[0], operands[1]] if operands[0].operator() == function: return [operands[1], operands[0]] - raise ValueError('Term %s in the equation %s ' - 'does not contain %s.' - % (op, eq, function)) + raise ValueError('Term %s in the equation %s ' 'does not contain %s.' % (op, eq, function)) def parse_one_summand(summand, eq): if summand.operator() == mul_vararg: @@ -2888,40 +2838,27 @@ def parse_one_summand(summand, eq): elif summand.operator() == function: coeff, op = 1, summand else: - raise ValueError('Term %s in the equation %s is not a valid summand.' - % (summand, eq)) + raise ValueError('Term %s in the equation %s is not a valid summand.' % (summand, eq)) try: coeff = coefficient_ring(coeff) except (TypeError, ValueError): - raise ValueError("Term %s in the equation %s: " - "%s is not a valid coefficient " - "since it is not in %s." - % (summand, eq, coeff, coefficient_ring)) from None + raise ValueError("Term %s in the equation %s: " "%s is not a valid coefficient " "since it is not in %s." % (summand, eq, coeff, coefficient_ring)) from None if len(op.operands()) > 1: - raise ValueError('Term %s in the equation %s has more than one argument.' - % (op, eq)) + raise ValueError('Term %s in the equation %s has more than one argument.' % (op, eq)) elif len(op.operands()) == 0: - raise ValueError('Term %s in the equation %s has no argument.' - % (op, eq)) + raise ValueError('Term %s in the equation %s has no argument.' % (op, eq)) try: poly = ZZ[var](op.operands()[0]) except TypeError: - raise ValueError('Term %s in the equation %s: ' - '%s is not a polynomial in %s with integer coefficients.' - % (op, eq, op.operands()[0], var)) from None + raise ValueError('Term %s in the equation %s: ' '%s is not a polynomial in %s with integer coefficients.' % (op, eq, op.operands()[0], var)) from None if poly.degree() != 1: - raise ValueError("Term %s in the equation %s: " - "polynomial %s does not have degree 1." - % (op, eq, poly)) + raise ValueError("Term %s in the equation %s: " "polynomial %s does not have degree 1." % (op, eq, poly)) d, base_power_m = list(poly) m = log(base_power_m, base=k) try: m = ZZ(m) except (TypeError, ValueError): - raise ValueError("Term %s in the equation %s: " - "%s is not a power of %s." - % (summand, eq, - k**m, k)) from None + raise ValueError("Term %s in the equation %s: " "%s is not a power of %s." % (summand, eq, k**m, k)) from None return [coeff, m, d] if not equations: @@ -2930,42 +2867,27 @@ def parse_one_summand(summand, eq): for eq in equations: try: if eq.operator() != operator.eq: - raise ValueError("%s is not an equation with ==." - % eq) + raise ValueError("%s is not an equation with ==." % eq) except AttributeError: - raise ValueError("%s is not a symbolic expression." - % eq) from None + raise ValueError("%s is not a symbolic expression." % eq) from None left_side, right_side = eq.operands() if left_side.operator() != function: - raise ValueError("Term %s in the equation %s is not an evaluation of %s." - % (left_side, eq, function)) + raise ValueError("Term %s in the equation %s is not an evaluation of %s." % (left_side, eq, function)) if len(left_side.operands()) != 1: - raise ValueError("Term %s in the equation %s does not have " - "one argument." - % (left_side, eq)) + raise ValueError("Term %s in the equation %s does not have " "one argument." % (left_side, eq)) try: polynomial_left = ZZ[var](left_side.operands()[0]) except TypeError: - raise ValueError("Term %s in the equation %s: " - "%s is not a polynomial in %s with " - "integer coefficients." - % (left_side, eq, - left_side.operands()[0], var)) from None + raise ValueError("Term %s in the equation %s: " "%s is not a polynomial in %s with " "integer coefficients." % (left_side, eq, left_side.operands()[0], var)) from None if polynomial_left.degree() > 1: - raise ValueError("Term %s in the equation %s: " - "%s is not a polynomial in %s of degree smaller than 2." - % (left_side, eq, polynomial_left, var)) + raise ValueError("Term %s in the equation %s: " "%s is not a polynomial in %s of degree smaller than 2." % (left_side, eq, polynomial_left, var)) if polynomial_left in ZZ: try: right_side = coefficient_ring(right_side) except (TypeError, ValueError): - raise ValueError("Initial value %s given by the equation %s " - "is not in %s." - % (right_side, eq, coefficient_ring)) from None - if (polynomial_left in initial_values.keys() and - initial_values[polynomial_left] != right_side): - raise ValueError("Initial value %s is given twice." - % (function(polynomial_left))) + raise ValueError("Initial value %s given by the equation %s " "is not in %s." % (right_side, eq, coefficient_ring)) from None + if polynomial_left in initial_values.keys() and initial_values[polynomial_left] != right_side: + raise ValueError("Initial value %s is given twice." % (function(polynomial_left))) initial_values.update({polynomial_left: right_side}) else: [r, base_power_M] = list(polynomial_left) @@ -2973,64 +2895,36 @@ def parse_one_summand(summand, eq): try: M_new = ZZ(M_new) except (TypeError, ValueError): - raise ValueError("Term %s in the equation %s: " - "%s is not a power of %s." - % (left_side, eq, - base_power_M, k)) from None + raise ValueError("Term %s in the equation %s: " "%s is not a power of %s." % (left_side, eq, base_power_M, k)) from None if M is not None and M != M_new: - raise ValueError(("Term {0} in the equation {1}: " - "{2} does not equal {3}. Expected " - "subsequence modulo {3} as in another " - "equation, got subsequence modulo {2}.").format( - left_side, eq, - base_power_M, k**M)) + raise ValueError(("Term {0} in the equation {1}: " "{2} does not equal {3}. Expected " "subsequence modulo {3} as in another " "equation, got subsequence modulo {2}.").format(left_side, eq, base_power_M, k**M)) elif M is None: M = M_new if M < 1: - raise ValueError(("Term {0} in the equation {1}: " - "{2} is less than {3}. Modulus must " - "be at least {3}.").format( - left_side, eq, - base_power_M, k)) + raise ValueError(("Term {0} in the equation {1}: " "{2} is less than {3}. Modulus must " "be at least {3}.").format(left_side, eq, base_power_M, k)) if r in remainders: - raise ValueError("There are more than one recurrence relation for %s." - % (left_side,)) + raise ValueError("There are more than one recurrence relation for %s." % (left_side,)) if r >= k**M: - raise ValueError("Term %s in the equation %s: " - "remainder %s is not smaller than modulus %s." - % (left_side, eq, r, k**M)) + raise ValueError("Term %s in the equation %s: " "remainder %s is not smaller than modulus %s." % (left_side, eq, r, k**M)) elif r < 0: - raise ValueError("Term %s in the equation %s: " - "remainder %s is smaller than 0." - % (left_side, eq, r)) + raise ValueError("Term %s in the equation %s: " "remainder %s is smaller than 0." % (left_side, eq, r)) else: remainders.add(r) if right_side != 0: - if (len(right_side.operands()) == 1 and right_side.operator() == function - or right_side.operator() == mul_vararg and len(right_side.operands()) == 2): + if len(right_side.operands()) == 1 and right_side.operator() == function or right_side.operator() == mul_vararg and len(right_side.operands()) == 2: summands = [right_side] elif right_side.operator() == add_vararg: summands = right_side.operands() else: - raise ValueError("%s is not a valid right hand side." - % (right_side,)) + raise ValueError("%s is not a valid right hand side." % (right_side,)) for summand in summands: coeff, new_m, d = parse_one_summand(summand, eq) if m is not None and m != new_m: - raise ValueError(("Term {0} in the equation {1}: " - "{2} does not equal {3}. Expected " - "subsequence modulo {3} as in another " - "summand or equation, got subsequence " - "modulo {2}.").format( - summand, eq, - k**new_m, k**m)) + raise ValueError(("Term {0} in the equation {1}: " "{2} does not equal {3}. Expected " "subsequence modulo {3} as in another " "summand or equation, got subsequence " "modulo {2}.").format(summand, eq, k**new_m, k**m)) elif m is None: m = new_m if M <= m: - raise ValueError("Term %s in the equation %s: " - "%s is not smaller than %s." - % (summand, eq, - k**m, k**M)) + raise ValueError("Term %s in the equation %s: " "%s is not smaller than %s." % (summand, eq, k**m, k**M)) coeffs.update({(r, d): coeff}) if not M: @@ -3038,12 +2932,9 @@ def parse_one_summand(summand, eq): elif M and m is None: # for the zero sequence m = M - 1 - missing_remainders = [rem for rem in srange(k**M) - if rem not in remainders] + missing_remainders = [rem for rem in srange(k**M) if rem not in remainders] if missing_remainders: - raise ValueError("Recurrence relations for %s are missing." - % ([function(k**M*var + rem) - for rem in missing_remainders],)) + raise ValueError("Recurrence relations for %s are missing." % ([function(k**M * var + rem) for rem in missing_remainders],)) return (M, m, coeffs, initial_values) @@ -3174,53 +3065,35 @@ def parse_direct_arguments(self, M, m, coeffs, initial_values): from sage.rings.integer_ring import ZZ if M not in ZZ or M < 1: - raise ValueError("%s is not a positive integer." - % (M,)) from None + raise ValueError("%s is not a positive integer." % (M,)) from None if m not in ZZ or m < 0: - raise ValueError("%s is not a nonnegative integer." - % (m,)) from None + raise ValueError("%s is not a nonnegative integer." % (m,)) from None if M <= m: - raise ValueError("%s is not larger than %s." - % (M, m)) from None + raise ValueError("%s is not larger than %s." % (M, m)) from None coefficient_ring = self.coefficient_ring k = self.k - invalid_coeffs = [coeff for coeff in coeffs.values() - if coeff not in coefficient_ring] + invalid_coeffs = [coeff for coeff in coeffs.values() if coeff not in coefficient_ring] if invalid_coeffs: - raise ValueError("Coefficients %s are not valid " - "since they are not in %s." - % (invalid_coeffs, coefficient_ring)) from None + raise ValueError("Coefficients %s are not valid " "since they are not in %s." % (invalid_coeffs, coefficient_ring)) from None coeffs_keys = coeffs.keys() - invalid_coeffs_keys = [key for key in coeffs_keys - if key[0] not in ZZ or key[1] not in ZZ] + invalid_coeffs_keys = [key for key in coeffs_keys if key[0] not in ZZ or key[1] not in ZZ] if invalid_coeffs_keys: - raise ValueError("Keys %s for coefficients are not valid " - "since one of their components is no integer." - % (invalid_coeffs_keys,)) from None + raise ValueError("Keys %s for coefficients are not valid " "since one of their components is no integer." % (invalid_coeffs_keys,)) from None invalid_coeffs_keys = [key for key in coeffs_keys if key[0] < 0 or key[0] >= k**M] if invalid_coeffs_keys: - raise ValueError("Keys %s for coefficients are not valid " - "since their first component is either smaller than 0 " - " or larger than or equal to %s." - % (invalid_coeffs_keys, k**M)) from None + raise ValueError("Keys %s for coefficients are not valid " "since their first component is either smaller than 0 " " or larger than or equal to %s." % (invalid_coeffs_keys, k**M)) from None - invalid_initial_values = [value for value in initial_values.values() - if value not in coefficient_ring] + invalid_initial_values = [value for value in initial_values.values() if value not in coefficient_ring] if invalid_initial_values: - raise ValueError("Initial values %s are not valid " - "since they are not in %s." - % (invalid_initial_values, coefficient_ring)) from None + raise ValueError("Initial values %s are not valid " "since they are not in %s." % (invalid_initial_values, coefficient_ring)) from None - invalid_initial_keys = [key for key in initial_values.keys() - if key not in ZZ] + invalid_initial_keys = [key for key in initial_values.keys() if key not in ZZ] if invalid_initial_keys: - raise ValueError("Keys %s for the initial values are not valid " - "since they are no integers." - % (invalid_initial_keys,)) from None + raise ValueError("Keys %s for the initial values are not valid " "since they are no integers." % (invalid_initial_keys,)) from None return (M, m, coeffs, initial_values) @@ -3359,31 +3232,24 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) l = min(indices_right) u = max(indices_right) - if offset < max(0, -l/k**m): - offset = max(0, ceil(-l/k**m)) + if offset < max(0, -l / k**m): + offset = max(0, ceil(-l / k**m)) - ll = (floor((l*k**(M-m) - k**M + 1)/(k**(M-m) - 1)) + 1)*(l < 0) - uu = max([ceil((u*k**(M-m) + k**M - k**m)/(k**(M-m) - 1)) - 1, k**m - 1]) - n1 = offset - floor(ll/k**M) - dim = (k**M - 1)/(k - 1) + (M - m)*(uu - ll - k**m + 1) + n1 + ll = (floor((l * k ** (M - m) - k**M + 1) / (k ** (M - m) - 1)) + 1) * (l < 0) + uu = max([ceil((u * k ** (M - m) + k**M - k**m) / (k ** (M - m) - 1)) - 1, k**m - 1]) + n1 = offset - floor(ll / k**M) + dim = (k**M - 1) / (k - 1) + (M - m) * (uu - ll - k**m + 1) + n1 if inhomogeneities: - invalid_indices = [i for i in inhomogeneities - if i not in srange(k**M)] + invalid_indices = [i for i in inhomogeneities if i not in srange(k**M)] if invalid_indices: - raise ValueError(f"Indices {invalid_indices} for inhomogeneities are no " - f"integers between 0 and {k**M - 1}.") + raise ValueError(f"Indices {invalid_indices} for inhomogeneities are no " f"integers between 0 and {k**M - 1}.") Seq = RegularSequenceRing(k, coefficient_ring) - inhomogeneities.update({i: inhomogeneities[i] * Seq.one_hadamard() - for i in inhomogeneities - if inhomogeneities[i] in coefficient_ring}) - invalid = {i: inhomogeneities[i] for i in inhomogeneities - if not (isinstance(inhomogeneities[i].parent(), RegularSequenceRing) and - inhomogeneities[i].parent().k == k)} + inhomogeneities.update({i: inhomogeneities[i] * Seq.one_hadamard() for i in inhomogeneities if inhomogeneities[i] in coefficient_ring}) + invalid = {i: inhomogeneities[i] for i in inhomogeneities if not (isinstance(inhomogeneities[i].parent(), RegularSequenceRing) and inhomogeneities[i].parent().k == k)} if invalid: - raise ValueError(f"Inhomogeneities {invalid} are neither {k}-regular " - f"sequences nor elements of {coefficient_ring}.") + raise ValueError(f"Inhomogeneities {invalid} are neither {k}-regular " f"sequences nor elements of {coefficient_ring}.") if not initial_values: raise ValueError("No initial values are given.") @@ -3395,32 +3261,20 @@ def converted_value(n, v): return coefficient_ring(v) except (TypeError, ValueError): values_not_in_ring.append(n) - initial_values = {n: converted_value(n, v) - for n, v in initial_values.items()} + + initial_values = {n: converted_value(n, v) for n, v in initial_values.items()} if values_not_in_ring: - raise ValueError("Initial values for arguments in %s are not in %s." - % (values_not_in_ring, coefficient_ring)) + raise ValueError("Initial values for arguments in %s are not in %s." % (values_not_in_ring, coefficient_ring)) max_key = max(keys_initial) - last_value_needed = max( - k**(M-1) - k**m + uu + (n1 > 0) * k**(M-1) * (k * (n1 - 1) + k - 1), # for matrix W - k**m * offset + u, max_key) - initial_values = self.values( - M=M, m=m, l=l, u=u, ll=ll, coeffs=coeffs, - initial_values=initial_values, last_value_needed=last_value_needed, - offset=offset, inhomogeneities=inhomogeneities) - - recurrence_rules = namedtuple('recurrence_rules', - ['M', 'm', 'l', 'u', 'll', 'uu', 'dim', - 'coeffs', 'initial_values', 'offset', 'n1', - 'inhomogeneities']) - - return recurrence_rules(M=M, m=m, l=l, u=u, ll=ll, uu=uu, dim=dim, - coeffs=coeffs, initial_values=initial_values, - offset=offset, n1=n1, inhomogeneities=inhomogeneities) - - def values(self, *, M, m, l, u, ll, coeffs, - initial_values, last_value_needed, offset, inhomogeneities): + last_value_needed = max(k ** (M - 1) - k**m + uu + (n1 > 0) * k ** (M - 1) * (k * (n1 - 1) + k - 1), k**m * offset + u, max_key) # for matrix W + initial_values = self.values(M=M, m=m, l=l, u=u, ll=ll, coeffs=coeffs, initial_values=initial_values, last_value_needed=last_value_needed, offset=offset, inhomogeneities=inhomogeneities) + + recurrence_rules = namedtuple('recurrence_rules', ['M', 'm', 'l', 'u', 'll', 'uu', 'dim', 'coeffs', 'initial_values', 'offset', 'n1', 'inhomogeneities']) + + return recurrence_rules(M=M, m=m, l=l, u=u, ll=ll, uu=uu, dim=dim, coeffs=coeffs, initial_values=initial_values, offset=offset, n1=n1, inhomogeneities=inhomogeneities) + + def values(self, *, M, m, l, u, ll, coeffs, initial_values, last_value_needed, offset, inhomogeneities): r""" Determine enough values of the corresponding recursive sequence by applying the recurrence relations given in :meth:`RegularSequenceRing.from_recurrence` @@ -3562,8 +3416,7 @@ def values(self, *, M, m, l, u, ll, coeffs, k = self.k keys_initial = initial_values.keys() - values = {n: None if n not in keys_initial else initial_values[n] - for n in srange(last_value_needed + 1)} + values = {n: None if n not in keys_initial else initial_values[n] for n in srange(last_value_needed + 1)} missing_values = [] @cached_function @@ -3591,25 +3444,18 @@ def f(n): q, r = ZZ(n).quo_rem(k**M) if q < offset: missing_values.append(n) - return sum([coeff(r, j)*f(k**m*q + j) - for j in srange(l, u + 1) - if coeff(r, j)]) + inhomogeneity(r, q) + return sum([coeff(r, j) * f(k**m * q + j) for j in srange(l, u + 1) if coeff(r, j)]) + inhomogeneity(r, q) for n in srange(last_value_needed + 1): values.update({n: f(n)}) if missing_values: - raise ValueError("Initial values for arguments in %s are missing." - % (list(set(missing_values)),)) + raise ValueError("Initial values for arguments in %s are missing." % (list(set(missing_values)),)) for n in keys_initial: q, r = ZZ(n).quo_rem(k**M) - if (q >= offset and - values[n] != (sum([coeff(r, j)*values[k**m*q + j] - for j in srange(l, u + 1)])) + inhomogeneity(r, q)): - raise ValueError("Initial value for argument %s does not match with " - "the given recurrence relations." - % (n,)) + if q >= offset and values[n] != (sum([coeff(r, j) * values[k**m * q + j] for j in srange(l, u + 1)])) + inhomogeneity(r, q): + raise ValueError("Initial value for argument %s does not match with " "the given recurrence relations." % (n,)) values.update({n: 0 for n in srange(ll, 0)}) @@ -3674,12 +3520,7 @@ def ind(self, M, m, ll, uu): return ind - @cached_method(key=lambda self, recurrence_rules: - (recurrence_rules.M, - recurrence_rules.m, - recurrence_rules.ll, - recurrence_rules.uu, - tuple(recurrence_rules.inhomogeneities.items()))) + @cached_method(key=lambda self, recurrence_rules: (recurrence_rules.M, recurrence_rules.m, recurrence_rules.ll, recurrence_rules.uu, tuple(recurrence_rules.inhomogeneities.items()))) def shifted_inhomogeneities(self, recurrence_rules): r""" Return a dictionary of all needed shifted inhomogeneities as described @@ -3785,12 +3626,10 @@ def shifted_inhomogeneities(self, recurrence_rules): uu = recurrence_rules.uu inhomogeneities = recurrence_rules.inhomogeneities - lower = floor(ll/k**M) - upper = floor((k**(M-1) - k**m + uu)/k**M) + 1 + lower = floor(ll / k**M) + upper = floor((k ** (M - 1) - k**m + uu) / k**M) + 1 - return {i: inhomogeneities[i].subsequence(1, {b: 1 for b in srange(lower, upper + 1)}, - minimize=False) - for i in inhomogeneities} + return {i: inhomogeneities[i].subsequence(1, {b: 1 for b in srange(lower, upper + 1)}, minimize=False) for i in inhomogeneities} def v_eval_n(self, recurrence_rules, n): r""" @@ -3837,14 +3676,13 @@ def v_eval_n(self, recurrence_rules, n): inhomogeneities = recurrence_rules.inhomogeneities ind = self.ind(M, m, ll, uu) - v = vector([initial_values[k**ind[i][0]*n + ind[i][1]] for i in srange(dim)]) + v = vector([initial_values[k ** ind[i][0] * n + ind[i][1]] for i in srange(dim)]) if not all(S.is_trivial_zero() for S in inhomogeneities.values()): Seq = list(inhomogeneities.values())[0].parent() W = Seq.indices() shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules) - vv = [(S.coefficient_of_word(W(ZZ(n).digits(k)), multiply_left=False)) - for S in shifted_inhomogeneities.values()] + vv = [(S.coefficient_of_word(W(ZZ(n).digits(k)), multiply_left=False)) for S in shifted_inhomogeneities.values()] v = vector(chain(v, *vv)) return v @@ -4032,27 +3870,27 @@ def coeff(r, k): def entry(i, kk): j, d = ind[i] if j < M - 1: - return int(kk == ind[(j + 1, k**j*rem + d)]) - rem_d = k**(M-1)*rem + (d % k**M) + return int(kk == ind[(j + 1, k**j * rem + d)]) + rem_d = k ** (M - 1) * rem + (d % k**M) dd = d // k**M if rem_d < k**M: - lambd = l - ind[(m, (k**m)*dd + l)] + lambd = l - ind[(m, (k**m) * dd + l)] return coeff(rem_d, kk + lambd) - lambd = l - ind[(m, k**m*dd + k**m + l)] + lambd = l - ind[(m, k**m * dd + k**m + l)] return coeff(rem_d - k**M, kk + lambd) mat = Matrix(coefficient_ring, dim_without_corr, dim_without_corr, entry) if not all(S.is_trivial_zero() for S in inhomogeneities.values()): shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules) - lower = floor(ll/k**M) - upper = floor((k**(M-1) - k**m + uu)/k**M) + 1 + lower = floor(ll / k**M) + upper = floor((k ** (M - 1) - k**m + uu) / k**M) + 1 def wanted_inhomogeneity(row): j, d = ind[row] if j != M - 1: return (None, None) - rem_d = k**(M-1)*rem + (d % k**M) + rem_d = k ** (M - 1) * rem + (d % k**M) dd = d // k**M if rem_d < k**M: return (rem_d, dd) @@ -4061,22 +3899,16 @@ def wanted_inhomogeneity(row): return (None, None) def left_for_inhomogeneity(wanted): - return list(chain(*[(wanted == (r, i))*inhomogeneity.left - for r, inhomogeneity in inhomogeneities.items() - for i in srange(lower, upper + 1)])) + return list(chain(*[(wanted == (r, i)) * inhomogeneity.left for r, inhomogeneity in inhomogeneities.items() for i in srange(lower, upper + 1)])) def matrix_row(row): wanted = wanted_inhomogeneity(row) return left_for_inhomogeneity(wanted) mat_upper_right = Matrix([matrix_row(row) for row in srange(dim_without_corr)]) - mat_inhomog = block_diagonal_matrix([S.mu[rem] - for S in shifted_inhomogeneities.values()], - subdivide=False) + mat_inhomog = block_diagonal_matrix([S.mu[rem] for S in shifted_inhomogeneities.values()], subdivide=False) - mat = block_matrix([[mat, mat_upper_right], - [zero_matrix(mat_inhomog.nrows(), dim_without_corr), - mat_inhomog]], subdivide=False) + mat = block_matrix([[mat, mat_upper_right], [zero_matrix(mat_inhomog.nrows(), dim_without_corr), mat_inhomog]], subdivide=False) dim_without_corr = mat.ncols() dim = dim_without_corr + n1 @@ -4084,13 +3916,11 @@ def matrix_row(row): if n1 > 0 and correct_offset: W = Matrix(coefficient_ring, dim_without_corr, 0) for i in srange(n1): - W = W.augment( - self.v_eval_n(recurrence_rules, k*i + rem) - - mat*self.v_eval_n(recurrence_rules, i)) + W = W.augment(self.v_eval_n(recurrence_rules, k * i + rem) - mat * self.v_eval_n(recurrence_rules, i)) J = Matrix(coefficient_ring, 0, n1) for i in srange(n1): - J = J.stack(vector([int(j*k == i - rem) for j in srange(n1)])) + J = J.stack(vector([int(j * k == i - rem) for j in srange(n1)])) Z = zero_matrix(coefficient_ring, n1, dim_without_corr) mat = block_matrix([[mat, W], [Z, J]], subdivide=False) @@ -4142,10 +3972,9 @@ def left(self, recurrence_rules): if not all(S.is_trivial_zero() for S in inhomogeneities.values()): shifted_inhomogeneities = self.shifted_inhomogeneities(recurrence_rules) - dim += sum(shifted_inhomogeneities[i].mu[0].ncols() - for i in shifted_inhomogeneities) + dim += sum(shifted_inhomogeneities[i].mu[0].ncols() for i in shifted_inhomogeneities) - return vector([1] + (dim - 1)*[0]) + return vector([1] + (dim - 1) * [0]) def right(self, recurrence_rules): r""" @@ -4206,7 +4035,7 @@ def right(self, recurrence_rules): right = self.v_eval_n(recurrence_rules, 0) if n1 >= 1: - right = vector(list(right) + [1] + (n1 - 1)*[0]) + right = vector(list(right) + [1] + (n1 - 1) * [0]) return right @@ -4284,25 +4113,19 @@ def __call__(self, *args, **kwds): if len(args) == 3: M, m, coeffs, initial_values = self.parse_recurrence(*args) elif len(args) == 0 and all(kwd in kwds for kwd in ['equations', 'function', 'var']): - args = (kwds.pop('equations'), - kwds.pop('function'), - kwds.pop('var')) + args = (kwds.pop('equations'), kwds.pop('function'), kwds.pop('var')) M, m, coeffs, initial_values = self.parse_recurrence(*args) elif len(args) == 4: M, m, coeffs, initial_values = self.parse_direct_arguments(*args) elif len(args) == 0 and all(kwd in kwds for kwd in ['M', 'm', 'coeffs', 'initial_values']): - args = (kwds.pop('M'), - kwds.pop('m'), - kwds.pop('coeffs'), - kwds.pop('initial_values')) + args = (kwds.pop('M'), kwds.pop('m'), kwds.pop('coeffs'), kwds.pop('initial_values')) M, m, coeffs, initial_values = self.parse_direct_arguments(*args) else: raise ValueError("Number of positional arguments must be three or four or all arguments provided as keywords.") recurrence_rules = self.parameters(M, m, coeffs, initial_values, **kwds) - mu = [self.matrix(recurrence_rules, rem) - for rem in srange(k)] + mu = [self.matrix(recurrence_rules, rem) for rem in srange(k)] left = self.left(recurrence_rules) right = self.right(recurrence_rules) diff --git a/src/sage/combinat/regular_sequence_bounded.py b/src/sage/combinat/regular_sequence_bounded.py index f5e2cdf992a..37e45ca65c5 100644 --- a/src/sage/combinat/regular_sequence_bounded.py +++ b/src/sage/combinat/regular_sequence_bounded.py @@ -26,6 +26,7 @@ - Gabriel Lipnik is supported by the Austrian Science Fund (FWF): P 24644-N26. """ + # *************************************************************************** # Copyright (C) 2017 Gabriel Lipnik # @@ -198,6 +199,7 @@ def is_integer_valued(matrices) -> bool: """ from sage.matrix.matrix_space import MatrixSpace from sage.rings.integer_ring import ZZ + M = MatrixSpace(ZZ, matrices[0].nrows(), matrices[0].ncols()) return all(mat in M for mat in matrices) @@ -292,8 +294,7 @@ def is_bounded_via_mandel_simon_algorithm(matrices) -> bool: raise ValueError('not all matrices are integer-valued') phi = construct_phi(matrices) - return not any(multiply_reduce(M, M) == M and not M**2 == M**3 - for M in phi) + return not any(multiply_reduce(M, M) == M and not M**2 == M**3 for M in phi) def has_bounded_matrix_powers(matrices) -> bool: @@ -340,10 +341,7 @@ def has_bounded_matrix_powers(matrices) -> bool: sage: has_bounded_matrix_powers(matrices) True """ - return all(abs(eVn[0]) < 1 or - (abs(eVn[0]) == 1 and len(eVn[1]) == eVn[2]) - for mat in matrices - for eVn in mat.eigenvectors_right()) + return all(abs(eVn[0]) < 1 or (abs(eVn[0]) == 1 and len(eVn[1]) == eVn[2]) for mat in matrices for eVn in mat.eigenvectors_right()) def make_positive(matrices) -> list: @@ -519,8 +517,7 @@ def regular_sequence_is_bounded(S): if not has_bounded_matrix_powers(matrices): return False - matricesProd = [ell * em for ell in matrices for em in matrices - if ell != em] + matricesProd = [ell * em for ell in matrices for em in matrices if ell != em] if not has_bounded_matrix_powers(matricesProd): return False @@ -530,5 +527,4 @@ def regular_sequence_is_bounded(S): except ValueError: pass - raise RuntimeError('It is not decidable with this implementation ' + - 'whether the sequence is bounded or not.') + raise RuntimeError('It is not decidable with this implementation ' + 'whether the sequence is bounded or not.') diff --git a/src/sage/combinat/restricted_growth.py b/src/sage/combinat/restricted_growth.py index f84073a4105..f8dadac9de6 100644 --- a/src/sage/combinat/restricted_growth.py +++ b/src/sage/combinat/restricted_growth.py @@ -3,6 +3,7 @@ These combinatorial objects are in bijection with set partitions. """ + # *************************************************************************** # Copyright (C) 2008 Mike Hansen , # diff --git a/src/sage/combinat/ribbon.py b/src/sage/combinat/ribbon.py index 32a903c666b..2a0f3513a4e 100644 --- a/src/sage/combinat/ribbon.py +++ b/src/sage/combinat/ribbon.py @@ -1,6 +1,7 @@ r""" Ribbons """ + # *************************************************************************** # Copyright (C) 2007 Mike Hansen , # diff --git a/src/sage/combinat/ribbon_shaped_tableau.py b/src/sage/combinat/ribbon_shaped_tableau.py index 1f923df73c0..09f86d69ab9 100644 --- a/src/sage/combinat/ribbon_shaped_tableau.py +++ b/src/sage/combinat/ribbon_shaped_tableau.py @@ -1,6 +1,7 @@ r""" Ribbon shaped tableaux """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # @@ -69,6 +70,7 @@ class RibbonShapedTableau(SkewTableau): sage: RibbonShapedTableau([[1,2],[3,4]]).evaluation() [1, 1, 1, 1] """ + @staticmethod def __classcall_private__(cls, rows): r""" @@ -97,8 +99,7 @@ def __classcall_private__(cls, rows): raise TypeError("rows must be lists of positive integers") if not r: return StandardRibbonShapedTableaux()(r) - if all(j is None or (isinstance(j, (int, Integer)) and j > 0) - for i in r for j in i): + if all(j is None or (isinstance(j, (int, Integer)) and j > 0) for i in r for j in i): return StandardRibbonShapedTableaux()(r) raise TypeError("r must be a list of positive integers") @@ -171,6 +172,7 @@ class RibbonShapedTableaux(SkewTableaux): """ The set of all ribbon shaped tableaux. """ + @staticmethod def __classcall_private__(cls, shape=None, **kwds): """ @@ -231,7 +233,7 @@ def from_shape_and_word(self, shape, word): pos = 0 r = [] for l in shape: - r.append(word[pos:pos + l]) + r.append(word[pos : pos + l]) pos += l return self.element_class(self, r) @@ -244,6 +246,7 @@ class StandardRibbonShapedTableaux(StandardSkewTableaux): - ``shape`` -- (optional) the composition shape of the rows """ + @staticmethod def __classcall_private__(cls, shape=None, **kwds): """ @@ -259,6 +262,7 @@ class based on input. """ if shape is not None: from sage.combinat.partition import Partition + return StandardRibbonShapedTableaux_shape(Partition(shape)) # Otherwise arg0 takes the place of the category in pickling @@ -309,6 +313,7 @@ def __iter__(self): [[None, None, 1], [2, 3, 4]]] """ from sage.combinat.partition import _Partitions + for p in _Partitions: for r in StandardRibbonShapedTableaux_shape(p): yield self.element_class(self, r) @@ -328,7 +333,7 @@ def from_shape_and_word(self, shape, word): pos = 0 r = [] for l in shape: - r.append(word[pos:pos + l]) + r.append(word[pos : pos + l]) pos += l return self.element_class(self, r) @@ -359,8 +364,7 @@ def from_permutation(self, p): return self.element_class(self, [p[:]]) r = [[p[j] for j in range(comp[0])]] - r.extend([p[j] for j in range(comp[i], comp[i + 1])] - for i in range(len(comp) - 1)) + r.extend([p[j] for j in range(comp[i], comp[i + 1])] for i in range(len(comp) - 1)) r.append([p[j] for j in range(comp[-1], len(p))]) r.reverse() return self.element_class(self, r) @@ -391,6 +395,7 @@ class StandardRibbonShapedTableaux_shape(StandardRibbonShapedTableaux): sage: StandardRibbonShapedTableaux([3,2,2]).cardinality() 155 """ + @staticmethod def __classcall_private__(cls, shape): """ @@ -484,5 +489,6 @@ def __setstate__(self, state): from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.combinat.ribbon', 'Ribbon_class', Ribbon_class) register_unpickle_override('sage.combinat.ribbon', 'StandardRibbons_shape', StandardRibbonShapedTableaux) diff --git a/src/sage/combinat/ribbon_tableau.py b/src/sage/combinat/ribbon_tableau.py index 99f4738f8a7..9ca6aea8f43 100644 --- a/src/sage/combinat/ribbon_tableau.py +++ b/src/sage/combinat/ribbon_tableau.py @@ -1,6 +1,7 @@ r""" Ribbon tableaux """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # @@ -26,8 +27,7 @@ from sage.rings.integer import Integer from sage.combinat.combinat import CombinatorialElement from sage.combinat.skew_partition import SkewPartition, SkewPartitions -from sage.combinat.skew_tableau import (SkewTableau, SkewTableaux, - SemistandardSkewTableaux) +from sage.combinat.skew_tableau import SkewTableau, SkewTableaux, SemistandardSkewTableaux from sage.combinat.tableau import Tableaux from sage.combinat.partition import Partition, _Partitions from sage.combinat.permutation import to_standard @@ -76,6 +76,7 @@ class RibbonTableau(SkewTableau): sage: RibbonTableau([[0, 0, 3, 0], [1, 1, 0], [2, 0, 4]]).evaluation() [2, 1, 1, 1] """ + # The following method is private and will only get called # when calling RibbonTableau() directly, and not via element_class @staticmethod @@ -95,8 +96,7 @@ def __classcall_private__(cls, rt=None, expr=None): try: rt = [tuple(row) for row in rt] except TypeError: - raise TypeError("each element of the ribbon tableau " - "must be an iterable") + raise TypeError("each element of the ribbon tableau " "must be an iterable") if not all(row for row in rt): raise TypeError("a ribbon tableau cannot have empty rows") # calls the inherited __init__ method (of SkewTableau ) @@ -144,8 +144,10 @@ def to_word(self): word: 2041100030 """ from sage.combinat.words.word import Word + return Word([letter for row in reversed(self) for letter in row]) + # =================== # Ribbon Tableaux # =================== @@ -194,6 +196,7 @@ class RibbonTableaux(UniqueRepresentation, Parent): 2 0 0 """ + @staticmethod def __classcall_private__(cls, shape=None, weight=None, length=None): """ @@ -269,6 +272,7 @@ class RibbonTableaux_shape_weight_length(RibbonTableaux): """ Ribbon tableaux of a given shape, weight, and length. """ + @staticmethod def __classcall_private__(cls, shape, weight, length): """ @@ -313,8 +317,7 @@ def __iter__(self): sage: RibbonTableaux([[2,2],[]],[1,1],2).list() [[[0, 0], [1, 2]], [[1, 0], [2, 0]]] """ - for x in graph_implementation_rec(self._shape, self._weight, - self._length, list_rec): + for x in graph_implementation_rec(self._shape, self._weight, self._length, list_rec): yield self.from_expr(x) def _repr_(self) -> str: @@ -452,8 +455,7 @@ def insertion_tableau(skp, perm, evaluation, tableau, length): tableau[-(k + 1)] += [0] * (skp[0][k] - partc[k] - len(tableau[-(k + 1)])) # We construct a tableau from the southwest corner to the northeast one - tableau = [[0] * (skp[0][k] - partc[k]) - for k in reversed(range(len(tableau), len(skp[0])))] + tableau + tableau = [[0] * (skp[0][k] - partc[k]) for k in reversed(range(len(tableau), len(skp[0])))] + tableau tableau = SkewTableaux().from_expr([skp[1], tableau]).conjugate() tableau = tableau.to_expr()[1] @@ -550,15 +552,10 @@ def list_rec(nexts, current, part, weight, length): # Test if the current nodes drive us to new solutions if nexts: - return [insertion_tableau(part, curr_i[1], len(weight), - nexts_ij, length) - for nexts_i, curr_i in zip(nexts, current) - for nexts_ij in nexts_i] + return [insertion_tableau(part, curr_i[1], len(weight), nexts_ij, length) for nexts_i, curr_i in zip(nexts, current) for nexts_ij in nexts_i] # The current nodes are at the bottom of the tree - return [insertion_tableau(part, curr_i[1], - len(weight), [[], []], length) - for curr_i in current] + return [insertion_tableau(part, curr_i[1], len(weight), [[], []], length) for curr_i in current] # =============================== @@ -608,8 +605,7 @@ def spin_rec(t, nexts, current, part, weight, length): tmp.append(weight[-1] * (length - 1) - perm.number_of_inversions()) if nexts: - return [sum(sum(t**tval * nval for nval in nexts[i]) - for i, tval in enumerate(tmp))] + return [sum(sum(t**tval * nval for nval in nexts[i]) for i, tval in enumerate(tmp))] return [sum(t**val for val in tmp)] @@ -647,8 +643,7 @@ def spin_polynomial_square(part, weight, length): return R.one() t = R.gen() - return R(graph_implementation_rec(part, weight, length, - functools.partial(spin_rec, t))[0]) + return R(graph_implementation_rec(part, weight, length, functools.partial(spin_rec, t))[0]) def spin_polynomial(part, weight, length): @@ -676,10 +671,11 @@ def spin_polynomial(part, weight, length): 3*t^9 + 5*t^8 + 9*t^7 + 6*t^6 + 3*t^5 """ from sage.symbolic.ring import SR + sp = spin_polynomial_square(part, weight, length) t = SR.var('t') coeffs = sp.list() - return sum(c * t**(ZZ(i) / 2) for i, c in enumerate(coeffs)) + return sum(c * t ** (ZZ(i) / 2) for i, c in enumerate(coeffs)) def cospin_polynomial(part, weight, length): @@ -717,7 +713,7 @@ def cospin_polynomial(part, weight, length): coeffs = [c for c in sp.list() if c] d = len(coeffs) - 1 t = R.gen() - return R(sum(c * t**(d - i) for i, c in enumerate(coeffs))) + return R(sum(c * t ** (d - i) for i, c in enumerate(coeffs))) # ////////////////////////////////////////////////////////////////////////////////////////// @@ -784,8 +780,7 @@ def graph_implementation_rec(skp, weight, length, function): return function([], selection, skp, weight, length) # The recursive calls permit us to construct the list of the sons # of all current nodes in selection - a = [graph_implementation_rec([p[0], outer], weight[:-1], length, function) - for p in selection] + a = [graph_implementation_rec([p[0], outer], weight[:-1], length, function) for p in selection] return function(a, selection, skp, weight, length) @@ -808,6 +803,7 @@ class MultiSkewTableau(CombinatorialElement): sage: mst = MultiSkewTableau([ [[None,1],[2,3]], [[1,2],[2]] ]) sage: TestSuite(mst).run() """ + @staticmethod def __classcall_private__(cls, x): """ @@ -933,8 +929,8 @@ def _inversion_pairs_from_position(self, k, ij): c = pi - pj value = self[pk][pi][pj] pk_cells = self[pk].cells_by_content(c) - same_diagonal = [t.cells_by_content(c) for t in self[pk + 1:]] - above_diagonal = [t.cells_by_content(c + 1) for t in self[pk + 1:]] + same_diagonal = [t.cells_by_content(c) for t in self[pk + 1 :]] + above_diagonal = [t.cells_by_content(c + 1) for t in self[pk + 1 :]] res = [] for i, j in pk_cells: @@ -1016,6 +1012,7 @@ class SemistandardMultiSkewTableaux(MultiSkewTableaux): [[[1, 3], [3]], [[None, 1], [2, 2]]], [[[2, 3], [3]], [[None, 1], [1, 2]]]] """ + @staticmethod def __classcall_private__(cls, shape, weight): """ @@ -1135,11 +1132,11 @@ def __iter__(self): for lk in l: pos = 0 # Double check this lk = list(lk) - w = lk[:s[0]] + w = lk[: s[0]] restmp = [S.from_shape_and_word(parts[0], w)] for i in range(1, len(parts)): - pos += s[i-1] - w = lk[pos: pos + s[i]] + pos += s[i - 1] + w = lk[pos : pos + s[i]] restmp.append(S.from_shape_and_word(parts[i], w)) yield self.element_class(self, restmp) diff --git a/src/sage/combinat/rigged_configurations/all.py b/src/sage/combinat/rigged_configurations/all.py index e068cb4aed6..576a0a4d9e5 100644 --- a/src/sage/combinat/rigged_configurations/all.py +++ b/src/sage/combinat/rigged_configurations/all.py @@ -33,13 +33,14 @@ - :ref:`sage.combinat.rigged_configurations.bij_type_D_tri` - :ref:`sage.combinat.rigged_configurations.bij_infinity` """ + # install the docstring of this module to the containing package from sage.misc.namespace_package import install_doc + install_doc(__package__, __doc__) from sage.misc.lazy_import import lazy_import -lazy_import('sage.combinat.rigged_configurations.rigged_configurations', - 'RiggedConfigurations') +lazy_import('sage.combinat.rigged_configurations.rigged_configurations', 'RiggedConfigurations') del lazy_import del install_doc diff --git a/src/sage/combinat/rigged_configurations/bij_abstract_class.py b/src/sage/combinat/rigged_configurations/bij_abstract_class.py index e22c657d672..f144f40448d 100644 --- a/src/sage/combinat/rigged_configurations/bij_abstract_class.py +++ b/src/sage/combinat/rigged_configurations/bij_abstract_class.py @@ -120,8 +120,7 @@ def run(self, verbose=False): """ if verbose: - from sage.combinat.rigged_configurations.tensor_product_kr_tableaux_element \ - import TensorProductOfKirillovReshetikhinTableauxElement + from sage.combinat.rigged_configurations.tensor_product_kr_tableaux_element import TensorProductOfKirillovReshetikhinTableauxElement for cur_crystal in reversed(self.tp_krt): target = cur_crystal.parent()._r @@ -227,15 +226,13 @@ def _update_vacancy_nums(self, a): # Setup the first block block_len = self.ret_rig_con[a][0] nu = self.ret_rig_con.nu() - vac_num = self.ret_rig_con.parent()._calc_vacancy_number(nu, a, nu[a][0], - dims=self.cur_dims) + vac_num = self.ret_rig_con.parent()._calc_vacancy_number(nu, a, nu[a][0], dims=self.cur_dims) for i, row_len in enumerate(self.ret_rig_con[a]): # If we've gone to a different sized block, then update the # values which change when moving to a new block size if block_len != row_len: - vac_num = self.ret_rig_con.parent()._calc_vacancy_number(nu, a, row_len, - dims=self.cur_dims) + vac_num = self.ret_rig_con.parent()._calc_vacancy_number(nu, a, row_len, dims=self.cur_dims) block_len = row_len self.ret_rig_con[a].vacancy_numbers[i] = vac_num @@ -263,8 +260,7 @@ def _update_partition_values(self, a): for index, value in enumerate(rigged_partition.rigging): if value is None: rigged_partition.rigging[index] = rigged_partition.vacancy_numbers[index] - if index > 0 and rigged_partition[index - 1] == rigged_partition[index] \ - and rigged_partition.rigging[index - 1] < rigged_partition.rigging[index]: + if index > 0 and rigged_partition[index - 1] == rigged_partition[index] and rigged_partition.rigging[index - 1] < rigged_partition.rigging[index]: # If we need to reorder pos = 0 width = rigged_partition[index] @@ -380,6 +376,7 @@ def run(self, verbose=False, build_graph=False): Digraph on 3 vertices """ from sage.combinat.crystals.letters import CrystalOfLetters + letters = CrystalOfLetters(self.rigged_con.parent()._cartan_type.classical()) # This is technically bad, but because the first thing we do is append @@ -440,6 +437,7 @@ def run(self, verbose=False, build_graph=False): self._graph.pop(0) # Remove the dummy at the start from sage.graphs.digraph import DiGraph from sage.graphs.dot2tex_utils import have_dot2tex + self._graph = DiGraph(self._graph, format='list_of_edges') if have_dot2tex(): self._graph.set_latex_options(format='dot2tex', edge_labels=True) @@ -489,17 +487,13 @@ def _update_vacancy_numbers(self, a): # Setup the first block block_len = partition[0] - vac_num = self.rigged_con.parent()._calc_vacancy_number(self.cur_partitions, - a, partition[0], - dims=self.cur_dims) + vac_num = self.rigged_con.parent()._calc_vacancy_number(self.cur_partitions, a, partition[0], dims=self.cur_dims) for i, row_len in enumerate(self.cur_partitions[a]): # If we've gone to a different sized block, then update the # values which change when moving to a new block size if block_len != row_len: - vac_num = self.rigged_con.parent()._calc_vacancy_number(self.cur_partitions, - a, row_len, - dims=self.cur_dims) + vac_num = self.rigged_con.parent()._calc_vacancy_number(self.cur_partitions, a, row_len, dims=self.cur_dims) block_len = row_len partition.vacancy_numbers[i] = vac_num @@ -527,8 +521,7 @@ def _find_singular_string(self, partition, last_size): 0 """ for i in reversed(range(len(partition))): - if (partition[i] >= last_size - and partition.vacancy_numbers[i] == partition.rigging[i]): + if partition[i] >= last_size and partition.vacancy_numbers[i] == partition.rigging[i]: return i def _next_index(self, r): diff --git a/src/sage/combinat/rigged_configurations/bij_infinity.py b/src/sage/combinat/rigged_configurations/bij_infinity.py index 0fd8ee7fdc9..8284a92c05b 100644 --- a/src/sage/combinat/rigged_configurations/bij_infinity.py +++ b/src/sage/combinat/rigged_configurations/bij_infinity.py @@ -30,14 +30,10 @@ from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations -from sage.combinat.rigged_configurations.bij_type_B import (KRTToRCBijectionTypeB, - RCToKRTBijectionTypeB) -from sage.combinat.rigged_configurations.bij_type_D import (KRTToRCBijectionTypeD, - RCToKRTBijectionTypeD) -from sage.combinat.rigged_configurations.bij_type_A import (KRTToRCBijectionTypeA, - RCToKRTBijectionTypeA) -from sage.combinat.rigged_configurations.bij_type_C import (KRTToRCBijectionTypeC, - RCToKRTBijectionTypeC) +from sage.combinat.rigged_configurations.bij_type_B import KRTToRCBijectionTypeB, RCToKRTBijectionTypeB +from sage.combinat.rigged_configurations.bij_type_D import KRTToRCBijectionTypeD, RCToKRTBijectionTypeD +from sage.combinat.rigged_configurations.bij_type_A import KRTToRCBijectionTypeA, RCToKRTBijectionTypeA +from sage.combinat.rigged_configurations.bij_type_C import KRTToRCBijectionTypeC, RCToKRTBijectionTypeC from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux from sage.combinat.crystals.letters import CrystalOfLetters from sage.categories.morphism import Morphism @@ -101,7 +97,7 @@ def _call_(self, x): conj = x.to_tableau().conjugate() ct = self.domain().cartan_type() act = ct.affine() - TP = TensorProductOfKirillovReshetikhinTableaux(act, [[r,1] for r in conj.shape()]) + TP = TensorProductOfKirillovReshetikhinTableaux(act, [[r, 1] for r in conj.shape()]) elt = TP(pathlist=[reversed(row) for row in conj]) if ct.type() == 'A': @@ -170,19 +166,19 @@ def _call_(self, x): sage: (~phi)(y) == x True """ - lam = [sum(nu)+1 for nu in x] + lam = [sum(nu) + 1 for nu in x] ct = self.domain().cartan_type() I = ct.index_set() if ct.type() == 'D': lam[-2] = max(lam[-2], lam[-1]) lam.pop() - l = sum([[[r+1, 1]]*v for r, v in enumerate(lam[:-1])], []) + l = sum([[[r + 1, 1]] * v for r, v in enumerate(lam[:-1])], []) n = len(I) - l = l + sum([[[n,1], [n-1,1]] for k in range(lam[-1])], []) + l = l + sum([[[n, 1], [n - 1, 1]] for k in range(lam[-1])], []) else: if ct.type() == 'B': lam[-1] *= 2 - l = sum([[[r, 1]]*lam[i] for i, r in enumerate(I)], []) + l = sum([[[r, 1]] * lam[i] for i, r in enumerate(I)], []) RC = RiggedConfigurations(ct.affine(), reversed(l)) elt = RC(x) @@ -229,24 +225,24 @@ def run(self): """ for cur_crystal in reversed(self.tp_krt): cur_column = list(cur_crystal) - self.cur_path.insert(0, []) # Prepend an empty list + self.cur_path.insert(0, []) # Prepend an empty list self.cur_dims.insert(0, [0, 1]) for letter in reversed(cur_column): self.cur_dims[0][0] += 1 - val = letter.value # Convert from a CrystalOfLetter to an Integer + val = letter.value # Convert from a CrystalOfLetter to an Integer # Build the next state - self.cur_path[0].insert(0, [letter]) # Prepend the value + self.cur_path[0].insert(0, [letter]) # Prepend the value if self.cur_dims[0][0] == self.n: # Spinor case, we go from \Lambda_{n-1} -> 2\Lambda_n - self.cur_dims.insert(1, [self.n,1]) + self.cur_dims.insert(1, [self.n, 1]) self.cur_path.insert(1, self.cur_path[0]) self.next_state(val) - self.ret_rig_con.set_immutable() # Return it to immutable + self.ret_rig_con.set_immutable() # Return it to immutable return self.ret_rig_con @@ -279,13 +275,13 @@ def run(self): self.cur_dims.pop(1) while dim[0] > 0: - dim[0] -= 1 # This takes care of the indexing + dim[0] -= 1 # This takes care of the indexing b = self.next_state(dim[0]) # Make sure we have a crystal letter - ret_crystal_path[-1].append(letters(b)) # Append the rank + ret_crystal_path[-1].append(letters(b)) # Append the rank - self.cur_dims.pop(0) # Pop off the leading column + self.cur_dims.pop(0) # Pop off the leading column return ret_crystal_path @@ -308,25 +304,25 @@ def run(self): for cur_crystal in reversed(self.tp_krt): # Iterate through the columns cur_column = list(cur_crystal) - self.cur_path.insert(0, []) # Prepend an empty list + self.cur_path.insert(0, []) # Prepend an empty list self.cur_dims.insert(0, [0, 1]) for letter in reversed(cur_column): self.cur_dims[0][0] += 1 - val = letter.value # Convert from a CrystalOfLetter to an Integer + val = letter.value # Convert from a CrystalOfLetter to an Integer # Build the next state - self.cur_path[0].insert(0, [letter]) # Prepend the value + self.cur_path[0].insert(0, [letter]) # Prepend the value self.next_state(val) if self.cur_dims[0][0] == self.n - 1: # Spinor case, we go from \Lambda_{n-2} -> \Lambda_{n-1} + \Lambda_n - self.cur_dims.insert(1, [self.n,1]) + self.cur_dims.insert(1, [self.n, 1]) self.cur_path.insert(1, self.cur_path[0] + [None]) - self.ret_rig_con.set_immutable() # Return it to immutable + self.ret_rig_con.set_immutable() # Return it to immutable return self.ret_rig_con @@ -358,12 +354,12 @@ def run(self): self.cur_dims.pop(1) while dim[0] > 0: - dim[0] -= 1 # This takes care of the indexing + dim[0] -= 1 # This takes care of the indexing b = self.next_state(dim[0]) # Make sure we have a crystal letter - ret_crystal_path[-1].append(letters(b)) # Append the rank + ret_crystal_path[-1].append(letters(b)) # Append the rank - self.cur_dims.pop(0) # Pop off the leading column + self.cur_dims.pop(0) # Pop off the leading column return ret_crystal_path diff --git a/src/sage/combinat/rigged_configurations/bij_type_A2_dual.py b/src/sage/combinat/rigged_configurations/bij_type_A2_dual.py index ceb6ad8f1b8..5a31b4f18af 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_A2_dual.py +++ b/src/sage/combinat/rigged_configurations/bij_type_A2_dual.py @@ -78,28 +78,28 @@ def next_state(self, val): if pos_val == 0: if len(self.ret_rig_con[pos_val - 1]) > 0: - max_width = self.ret_rig_con[n-1][0] + max_width = self.ret_rig_con[n - 1][0] else: max_width = 1 - max_width = self.ret_rig_con[n-1].insert_cell(max_width) + max_width = self.ret_rig_con[n - 1].insert_cell(max_width) width_n = max_width + 1 # Follow regular A_n rules - for a in reversed(range(tableau_height, n-1)): + for a in reversed(range(tableau_height, n - 1)): max_width = self.ret_rig_con[a].insert_cell(max_width) self._update_vacancy_nums(a + 1) self._update_partition_values(a + 1) self._update_vacancy_nums(tableau_height) self._update_partition_values(tableau_height) if tableau_height > 0: - self._update_vacancy_nums(tableau_height-1) - self._update_partition_values(tableau_height-1) + self._update_vacancy_nums(tableau_height - 1) + self._update_partition_values(tableau_height - 1) # Make the new string at n quasi-singular - p = self.ret_rig_con[n-1] + p = self.ret_rig_con[n - 1] for i in range(len(p)): if p._list[i] == width_n: - p.rigging[i] = p.rigging[i] - QQ(1)/QQ(2) + p.rigging[i] = p.rigging[i] - QQ(1) / QQ(2) break return @@ -115,14 +115,14 @@ def next_state(self, val): # Add cells similar to type A_n but we move to the right until we # reach the value of n-1 - for a in range(pos_val - 1, n-1): + for a in range(pos_val - 1, n - 1): max_width = self.ret_rig_con[a].insert_cell(max_width) case_S[a] = max_width # Special case for n # If we find a quasi-singular string first, then we are in case (Q, S) # otherwise we will find a singular string and insert 2 cells - partition = self.ret_rig_con[n-1] + partition = self.ret_rig_con[n - 1] num_rows = len(partition) case_QS = False for i in range(num_rows + 1): @@ -142,9 +142,9 @@ def next_state(self, val): j = len(partition._list) - 1 while j >= 0 and partition._list[j] <= 2: j -= 1 - partition._list.insert(j+1, 2) - partition.vacancy_numbers.insert(j+1, None) - partition.rigging.insert(j+1, None) + partition._list.insert(j + 1, 2) + partition.vacancy_numbers.insert(j + 1, None) + partition.rigging.insert(j + 1, None) break elif partition._list[i] <= max_width: if partition.vacancy_numbers[i] == partition.rigging[i]: @@ -156,20 +156,20 @@ def next_state(self, val): else: j = i - 1 while j >= 0 and partition._list[j] <= max_width + 2: - partition.rigging[j+1] = partition.rigging[j] # Shuffle it along + partition.rigging[j + 1] = partition.rigging[j] # Shuffle it along j -= 1 partition._list.pop(i) - partition._list.insert(j+1, max_width + 2) - partition.rigging[j+1] = None + partition._list.insert(j + 1, max_width + 2) + partition.rigging[j + 1] = None break - elif partition.vacancy_numbers[i] - QQ(1)/QQ(2) == partition.rigging[i] and not case_QS: + elif partition.vacancy_numbers[i] - QQ(1) / QQ(2) == partition.rigging[i] and not case_QS: case_QS = True partition._list[i] += 1 partition.rigging[i] = None # No need to set max_width here since we will find a singular string # Now go back following the regular C_n (ish) rules - for a in reversed(range(tableau_height, n-1)): + for a in reversed(range(tableau_height, n - 1)): if case_S[a] == max_width: self._insert_cell_case_S(self.ret_rig_con[a]) else: @@ -183,7 +183,7 @@ def next_state(self, val): self._update_partition_values(tableau_height) if pos_val <= tableau_height: - for a in range(pos_val-1, tableau_height): + for a in range(pos_val - 1, tableau_height): self._update_vacancy_nums(a) self._update_partition_values(a) if pos_val > 1: @@ -198,7 +198,7 @@ def next_state(self, val): num_rows = len(partition) for i in range(num_rows): if partition._list[i] == width_n: - partition.rigging[i] = partition.rigging[i] - QQ(1)/QQ(2) + partition.rigging[i] = partition.rigging[i] - QQ(1) / QQ(2) break @@ -222,7 +222,7 @@ def next_state(self, height): """ height -= 1 # indexing n = self.n - ell = [None] * (2*n) + ell = [None] * (2 * n) case_S = [False] * n case_Q = False b = None @@ -230,7 +230,7 @@ def next_state(self, height): # Calculate the rank and ell values last_size = 0 - for a in range(height, n-1): + for a in range(height, n - 1): ell[a] = self._find_singular_string(self.cur_partitions[a], last_size) if ell[a] is None: @@ -240,22 +240,22 @@ def next_state(self, height): last_size = self.cur_partitions[a][ell[a]] if b is None: - partition = self.cur_partitions[n-1] + partition = self.cur_partitions[n - 1] # Special case for n for i in reversed(range(len(partition))): if partition[i] >= last_size: if partition.vacancy_numbers[i] == partition.rigging[i]: last_size = partition[i] - case_S[n-1] = True - ell[2*n-1] = i + case_S[n - 1] = True + ell[2 * n - 1] = i break - elif partition.vacancy_numbers[i] - QQ(1)/QQ(2) == partition.rigging[i] and not case_Q: + elif partition.vacancy_numbers[i] - QQ(1) / QQ(2) == partition.rigging[i] and not case_Q: case_Q = True # This will never be singular last_size = partition[i] + 1 - ell[n-1] = i + ell[n - 1] = i - if ell[2*n-1] is None: + if ell[2 * n - 1] is None: if not case_Q: b = n else: @@ -263,12 +263,12 @@ def next_state(self, height): if b is None: # Now go back - for a in reversed(range(n-1)): + for a in reversed(range(n - 1)): if a >= height and self.cur_partitions[a][ell[a]] == last_size: - ell[n+a] = ell[a] + ell[n + a] = ell[a] case_S[a] = True else: - ell[n+a] = self._find_singular_string(self.cur_partitions[a], last_size) + ell[n + a] = self._find_singular_string(self.cur_partitions[a], last_size) if ell[n + a] is None: b = -(a + 2) @@ -288,31 +288,31 @@ def next_state(self, height): else: row_num = self.cur_partitions[0].remove_cell(ell[0]) row_num_bar = self.cur_partitions[0].remove_cell(ell[n]) - for a in range(1, n-1): + for a in range(1, n - 1): if case_S[a]: row_num_next = None - row_num_bar_next = self.cur_partitions[a].remove_cell(ell[n+a], 2) + row_num_bar_next = self.cur_partitions[a].remove_cell(ell[n + a], 2) else: row_num_next = self.cur_partitions[a].remove_cell(ell[a]) - row_num_bar_next = self.cur_partitions[a].remove_cell(ell[n+a]) + row_num_bar_next = self.cur_partitions[a].remove_cell(ell[n + a]) self._update_vacancy_numbers(a - 1) if row_num is not None: - self.cur_partitions[a-1].rigging[row_num] = self.cur_partitions[a-1].vacancy_numbers[row_num] + self.cur_partitions[a - 1].rigging[row_num] = self.cur_partitions[a - 1].vacancy_numbers[row_num] if row_num_bar is not None: - self.cur_partitions[a-1].rigging[row_num_bar] = self.cur_partitions[a-1].vacancy_numbers[row_num_bar] + self.cur_partitions[a - 1].rigging[row_num_bar] = self.cur_partitions[a - 1].vacancy_numbers[row_num_bar] row_num = row_num_next row_num_bar = row_num_bar_next if case_Q: - row_num_next = self.cur_partitions[n-1].remove_cell(ell[n-1]) - if case_S[n-1]: - row_num_bar_next = self.cur_partitions[n-1].remove_cell(ell[2*n-1]) + row_num_next = self.cur_partitions[n - 1].remove_cell(ell[n - 1]) + if case_S[n - 1]: + row_num_bar_next = self.cur_partitions[n - 1].remove_cell(ell[2 * n - 1]) else: row_num_bar_next = None - elif case_S[n-1]: + elif case_S[n - 1]: row_num_next = None - row_num_bar_next = self.cur_partitions[n-1].remove_cell(ell[2*n-1], 2) + row_num_bar_next = self.cur_partitions[n - 1].remove_cell(ell[2 * n - 1], 2) else: row_num_next = None row_num_bar_next = None @@ -320,18 +320,18 @@ def next_state(self, height): if n > 1: self._update_vacancy_numbers(n - 2) if row_num is not None: - self.cur_partitions[n-2].rigging[row_num] = self.cur_partitions[n-2].vacancy_numbers[row_num] + self.cur_partitions[n - 2].rigging[row_num] = self.cur_partitions[n - 2].vacancy_numbers[row_num] if row_num_bar is not None: - self.cur_partitions[n-2].rigging[row_num_bar] = self.cur_partitions[n-2].vacancy_numbers[row_num_bar] + self.cur_partitions[n - 2].rigging[row_num_bar] = self.cur_partitions[n - 2].vacancy_numbers[row_num_bar] self._update_vacancy_numbers(n - 1) if row_num_next is not None: - self.cur_partitions[n-1].rigging[row_num_next] = self.cur_partitions[n-1].vacancy_numbers[row_num_next] + self.cur_partitions[n - 1].rigging[row_num_next] = self.cur_partitions[n - 1].vacancy_numbers[row_num_next] if row_num_bar_next is not None: if case_Q: # This will always be the largest value - self.cur_partitions[n-1].rigging[row_num_bar_next] = self.cur_partitions[n-1].vacancy_numbers[row_num_bar_next] - QQ(1)/QQ(2) + self.cur_partitions[n - 1].rigging[row_num_bar_next] = self.cur_partitions[n - 1].vacancy_numbers[row_num_bar_next] - QQ(1) / QQ(2) else: - self.cur_partitions[n-1].rigging[row_num_bar_next] = self.cur_partitions[n-1].vacancy_numbers[row_num_bar_next] + self.cur_partitions[n - 1].rigging[row_num_bar_next] = self.cur_partitions[n - 1].vacancy_numbers[row_num_bar_next] return b diff --git a/src/sage/combinat/rigged_configurations/bij_type_A2_even.py b/src/sage/combinat/rigged_configurations/bij_type_A2_even.py index 8fa552a1077..c2675d68aee 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_A2_even.py +++ b/src/sage/combinat/rigged_configurations/bij_type_A2_even.py @@ -76,7 +76,7 @@ def next_state(self, val): case_S = [None] * n if val == 'E': pos_val = n - max_width = self.ret_rig_con[n-1].insert_cell(0) + max_width = self.ret_rig_con[n - 1].insert_cell(0) else: pos_val = -val @@ -94,10 +94,10 @@ def next_state(self, val): case_S[a] = max_width # Special case for n - self._insert_cell_case_S(self.ret_rig_con[n-1]) + self._insert_cell_case_S(self.ret_rig_con[n - 1]) # Now go back following the regular C_n (ish) rules - for a in reversed(range(tableau_height, n-1)): + for a in reversed(range(tableau_height, n - 1)): if case_S[a] == max_width: self._insert_cell_case_S(self.ret_rig_con[a]) else: @@ -111,7 +111,7 @@ def next_state(self, val): self._update_partition_values(tableau_height) if pos_val <= tableau_height: - for a in range(pos_val-1, tableau_height): + for a in range(pos_val - 1, tableau_height): self._update_vacancy_nums(a) self._update_partition_values(a) if pos_val > 1: @@ -142,7 +142,7 @@ def next_state(self, height): """ height -= 1 # indexing n = self.n - ell = [None] * (2*n) + ell = [None] * (2 * n) case_S = [False] * n b = None @@ -162,18 +162,18 @@ def next_state(self, height): b = 'E' # This is a slight hack since remove_cell() will just delete the # appropriate row - case_S[n-1] = True + case_S[n - 1] = True if b is None: # Now go back - ell[2*n-1] = ell[n-1] - case_S[n-1] = True - for a in reversed(range(n-1)): + ell[2 * n - 1] = ell[n - 1] + case_S[n - 1] = True + for a in reversed(range(n - 1)): if a >= height and self.cur_partitions[a][ell[a]] == last_size: - ell[n+a] = ell[a] + ell[n + a] = ell[a] case_S[a] = True else: - ell[n+a] = self._find_singular_string(self.cur_partitions[a], last_size) + ell[n + a] = self._find_singular_string(self.cur_partitions[a], last_size) if ell[n + a] is None: b = -(a + 2) @@ -198,20 +198,20 @@ def next_state(self, height): row_num_bar_next = None else: row_num_next = self.cur_partitions[a].remove_cell(ell[a]) - row_num_bar_next = self.cur_partitions[a].remove_cell(ell[n+a]) + row_num_bar_next = self.cur_partitions[a].remove_cell(ell[n + a]) self._update_vacancy_numbers(a - 1) if row_num is not None: - self.cur_partitions[a-1].rigging[row_num] = self.cur_partitions[a-1].vacancy_numbers[row_num] + self.cur_partitions[a - 1].rigging[row_num] = self.cur_partitions[a - 1].vacancy_numbers[row_num] if row_num_bar is not None: - self.cur_partitions[a-1].rigging[row_num_bar] = self.cur_partitions[a-1].vacancy_numbers[row_num_bar] + self.cur_partitions[a - 1].rigging[row_num_bar] = self.cur_partitions[a - 1].vacancy_numbers[row_num_bar] row_num = row_num_next row_num_bar = row_num_bar_next self._update_vacancy_numbers(n - 1) if row_num is not None: - self.cur_partitions[n-1].rigging[row_num] = self.cur_partitions[n-1].vacancy_numbers[row_num] + self.cur_partitions[n - 1].rigging[row_num] = self.cur_partitions[n - 1].vacancy_numbers[row_num] if row_num_bar is not None: - self.cur_partitions[n-1].rigging[row_num_bar] = self.cur_partitions[n-1].vacancy_numbers[row_num_bar] + self.cur_partitions[n - 1].rigging[row_num_bar] = self.cur_partitions[n - 1].vacancy_numbers[row_num_bar] return b diff --git a/src/sage/combinat/rigged_configurations/bij_type_A2_odd.py b/src/sage/combinat/rigged_configurations/bij_type_A2_odd.py index 338beeec32f..6913bc16d05 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_A2_odd.py +++ b/src/sage/combinat/rigged_configurations/bij_type_A2_odd.py @@ -98,7 +98,7 @@ def next_state(self, val): self._update_partition_values(tableau_height) if pos_val <= tableau_height: - for a in range(pos_val-1, tableau_height): + for a in range(pos_val - 1, tableau_height): self._update_vacancy_nums(a) self._update_partition_values(a) if pos_val > 1: @@ -129,7 +129,7 @@ def next_state(self, height): """ height -= 1 # indexing n = self.n - ell = [None] * (2*n) + ell = [None] * (2 * n) b = None # Calculate the rank and ell values @@ -152,8 +152,7 @@ def next_state(self, height): if a < height: end = len(self.cur_partitions[a]) for i in reversed(range(end)): - if self.cur_partitions[a][i] >= last_size and \ - self.cur_partitions[a].vacancy_numbers[i] == self.cur_partitions[a].rigging[i]: + if self.cur_partitions[a][i] >= last_size and self.cur_partitions[a].vacancy_numbers[i] == self.cur_partitions[a].rigging[i]: ell[n + a] = i break @@ -176,23 +175,23 @@ def next_state(self, height): self._update_vacancy_numbers(a - 1) if ret_row is not None: - self.cur_partitions[a-1].rigging[ret_row] = self.cur_partitions[a-1].vacancy_numbers[ret_row] + self.cur_partitions[a - 1].rigging[ret_row] = self.cur_partitions[a - 1].vacancy_numbers[ret_row] if ret_row_bar is not None: - self.cur_partitions[a-1].rigging[ret_row_bar] = self.cur_partitions[a-1].vacancy_numbers[ret_row_bar] + self.cur_partitions[a - 1].rigging[ret_row_bar] = self.cur_partitions[a - 1].vacancy_numbers[ret_row_bar] ret_row = ret_row_next ret_row_bar = ret_row_bar_next - ret_row_next = self.cur_partitions[n-1].remove_cell(ell[n-1]) + ret_row_next = self.cur_partitions[n - 1].remove_cell(ell[n - 1]) self._update_vacancy_numbers(n - 2) if ret_row is not None: - self.cur_partitions[n-2].rigging[ret_row] = self.cur_partitions[n-2].vacancy_numbers[ret_row] + self.cur_partitions[n - 2].rigging[ret_row] = self.cur_partitions[n - 2].vacancy_numbers[ret_row] if ret_row_bar is not None: - self.cur_partitions[n-2].rigging[ret_row_bar] = self.cur_partitions[n-2].vacancy_numbers[ret_row_bar] + self.cur_partitions[n - 2].rigging[ret_row_bar] = self.cur_partitions[n - 2].vacancy_numbers[ret_row_bar] self._update_vacancy_numbers(n - 1) if ret_row_next is not None: - self.cur_partitions[n-1].rigging[ret_row_next] = self.cur_partitions[n-1].vacancy_numbers[ret_row_next] + self.cur_partitions[n - 1].rigging[ret_row_next] = self.cur_partitions[n - 1].vacancy_numbers[ret_row_next] return b diff --git a/src/sage/combinat/rigged_configurations/bij_type_B.py b/src/sage/combinat/rigged_configurations/bij_type_B.py index d511ae76a2e..503d62f31da 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_B.py +++ b/src/sage/combinat/rigged_configurations/bij_type_B.py @@ -92,8 +92,7 @@ def run(self, verbose=False): sage: RC._test_bijection() """ if verbose: - from sage.combinat.rigged_configurations.tensor_product_kr_tableaux_element \ - import TensorProductOfKirillovReshetikhinTableauxElement + from sage.combinat.rigged_configurations.tensor_product_kr_tableaux_element import TensorProductOfKirillovReshetikhinTableauxElement for cur_crystal in reversed(self.tp_krt): r = cur_crystal.parent().r() @@ -120,11 +119,9 @@ def run(self, verbose=False): # Convert to a type A_{2n-1}^{(2)} RC dims = self.cur_dims[:] dims.insert(0, [r, cur_crystal.parent().s()]) - KRT = TensorProductOfKirillovReshetikhinTableaux(['A', 2*self.n-1, 2], dims) + KRT = TensorProductOfKirillovReshetikhinTableaux(['A', 2 * self.n - 1, 2], dims) # Convert the n-th partition into a regular rigged partition - self.ret_rig_con[-1] = RiggedPartition(self.ret_rig_con[-1]._list, - self.ret_rig_con[-1].rigging, - self.ret_rig_con[-1].vacancy_numbers) + self.ret_rig_con[-1] = RiggedPartition(self.ret_rig_con[-1]._list, self.ret_rig_con[-1].rigging, self.ret_rig_con[-1].vacancy_numbers) # Placeholder element elt = KRT(*[C.module_generators[0] for C in KRT.crystals]) bij = KRTToRCBijectionTypeA2Odd(elt) @@ -134,7 +131,7 @@ def run(self, verbose=False): for i in range(len(self.cur_dims)): if bij.cur_dims[i][0] != self.n: bij.cur_dims[i][1] *= 2 - for i in range(self.n-1): + for i in range(self.n - 1): for j in range(len(bij.ret_rig_con[i])): bij.ret_rig_con[i]._list[j] *= 2 bij.ret_rig_con[i].rigging[j] *= 2 @@ -189,7 +186,7 @@ def run(self, verbose=False): for i in range(len(self.cur_dims)): if bij.cur_dims[i][0] != self.n: bij.cur_dims[i][1] //= 2 - for i in range(self.n-1): + for i in range(self.n - 1): for j in range(len(bij.ret_rig_con[i])): bij.ret_rig_con[i]._list[j] //= 2 bij.ret_rig_con[i].rigging[j] //= 2 @@ -272,45 +269,44 @@ def next_state(self, val): # Special case for 0 if pos_val == 0: if len(self.ret_rig_con[pos_val - 1]) > 0: - max_width = self.ret_rig_con[n-1][0] + max_width = self.ret_rig_con[n - 1][0] else: max_width = 1 - max_width = self.ret_rig_con[n-1].insert_cell(max_width) + max_width = self.ret_rig_con[n - 1].insert_cell(max_width) width_n = max_width + 1 max_width = max_width // 2 # Check to see if we need to make the new string quasi-singular - if tableau_height != n-1: - max_width = self.ret_rig_con[n-2].insert_cell(max_width) + if tableau_height != n - 1: + max_width = self.ret_rig_con[n - 2].insert_cell(max_width) else: max_width = -1 self._update_vacancy_nums(n - 1) self._update_partition_values(n - 1) # Check if we need to make the new string at n quasi-singular - p = self.ret_rig_con[n-1] + p = self.ret_rig_con[n - 1] num_rows = len(p) # Note that max width is 1 less than the corresponding string length - if max_width*2 + 1 != width_n: + if max_width * 2 + 1 != width_n: for i in range(num_rows): if p._list[i] == width_n: - j = i+1 - while j < num_rows and p._list[j] == width_n \ - and p.vacancy_numbers[j] == p.rigging[j]: + j = i + 1 + while j < num_rows and p._list[j] == width_n and p.vacancy_numbers[j] == p.rigging[j]: j += 1 - p.rigging[j-1] -= 1 + p.rigging[j - 1] -= 1 break # Follow regular A_n rules - for a in reversed(range(tableau_height, n-2)): + for a in reversed(range(tableau_height, n - 2)): max_width = self.ret_rig_con[a].insert_cell(max_width) self._update_vacancy_nums(a + 1) self._update_partition_values(a + 1) self._update_vacancy_nums(tableau_height) self._update_partition_values(tableau_height) if tableau_height > 0: - self._update_vacancy_nums(tableau_height-1) - self._update_partition_values(tableau_height-1) + self._update_vacancy_nums(tableau_height - 1) + self._update_partition_values(tableau_height - 1) return # Always add a cell to the first singular value in the first @@ -334,7 +330,7 @@ def next_state(self, val): singular_max_width = False case_QS = False # Note, case_QS and singular_max_width will never both be True - p = self.ret_rig_con[n-1] + p = self.ret_rig_con[n - 1] num_rows = len(p) width_n = 0 for i in range(num_rows + 1): @@ -352,9 +348,9 @@ def next_state(self, val): j = len(p._list) - 1 while j >= 0 and p._list[j] <= 2: j -= 1 - p._list.insert(j+1, 2) - p.vacancy_numbers.insert(j+1, None) - p.rigging.insert(j+1, None) + p._list.insert(j + 1, 2) + p.vacancy_numbers.insert(j + 1, None) + p.rigging.insert(j + 1, None) max_width = 0 break elif p.vacancy_numbers[i] == p.rigging[i]: @@ -372,11 +368,11 @@ def next_state(self, val): # Add 2 boxes j = i - 1 while j >= 0 and p._list[j] <= max_width + 2: - p.rigging[j+1] = p.rigging[j] # Shuffle it along + p.rigging[j + 1] = p.rigging[j] # Shuffle it along j -= 1 p._list.pop(i) - p._list.insert(j+1, max_width + 2) - p.rigging[j+1] = None + p._list.insert(j + 1, max_width + 2) + p.rigging[j + 1] = None break if p._list[i] == max_width and not singular_max_width: @@ -411,8 +407,8 @@ def next_state(self, val): max_width = max_width // 2 # We need to do the next partition in order to determine the step at n - if tableau_height != n-1: - max_width = self.ret_rig_con[n-2].insert_cell(max_width) + if tableau_height != n - 1: + max_width = self.ret_rig_con[n - 2].insert_cell(max_width) else: max_width = -1 @@ -421,14 +417,13 @@ def next_state(self, val): # If we need to make the smaller added string quasisingular # Note that max width is 1 less than the corresponding string length - if case_QS and max_width*2 + 1 != width_n: + if case_QS and max_width * 2 + 1 != width_n: for i in range(num_rows): if p._list[i] == width_n: - j = i+1 - while j < num_rows and p._list[j] == width_n \ - and p.vacancy_numbers[j] == p.rigging[j]: + j = i + 1 + while j < num_rows and p._list[j] == width_n and p.vacancy_numbers[j] == p.rigging[j]: j += 1 - p.rigging[j-1] -= 1 + p.rigging[j - 1] -= 1 break # Continue back following the regular A_n rules @@ -444,7 +439,7 @@ def next_state(self, val): assert pos_val > 0 if pos_val <= tableau_height: - for a in range(pos_val-1, tableau_height): + for a in range(pos_val - 1, tableau_height): self._update_vacancy_nums(a) self._update_partition_values(a) if pos_val > 1: @@ -482,11 +477,11 @@ def other_outcome(self, rc, pos_val, width_n): self.ret_rig_con = rc # We need to do the next partition in order to determine the step at n - max_width = self.ret_rig_con[n-2].insert_cell(width_n // 2) + max_width = self.ret_rig_con[n - 2].insert_cell(width_n // 2) # We now attempt case (QS) case_QS = False - p = self.ret_rig_con[n-1] + p = self.ret_rig_con[n - 1] num_rows = len(p) for i in range(len(p._list)): if p._list[i] == width_n: @@ -506,14 +501,13 @@ def other_outcome(self, rc, pos_val, width_n): # If we need to make the smaller added string quasisingular # Note that max width is 1 less than the corresponding string length - if case_QS and max_width*2 + 1 != width_n: + if case_QS and max_width * 2 + 1 != width_n: for i in range(num_rows): if p._list[i] == width_n: - j = i+1 - while j < num_rows and p._list[j] == width_n \ - and p.vacancy_numbers[j] == p.rigging[j]: + j = i + 1 + while j < num_rows and p._list[j] == width_n and p.vacancy_numbers[j] == p.rigging[j]: j += 1 - p.rigging[j-1] -= 1 + p.rigging[j - 1] -= 1 break # Continue back following the regular A_n rules @@ -529,7 +523,7 @@ def other_outcome(self, rc, pos_val, width_n): assert pos_val > 0 if pos_val <= tableau_height: - for a in range(pos_val-1, tableau_height): + for a in range(pos_val - 1, tableau_height): self._update_vacancy_nums(a) self._update_partition_values(a) if pos_val > 1: @@ -576,6 +570,7 @@ def run(self, verbose=False, build_graph=False): Digraph on 6 vertices """ from sage.combinat.crystals.letters import CrystalOfLetters + letters = CrystalOfLetters(self.rigged_con.parent()._cartan_type.classical()) # This is technically bad, but because the first thing we do is append @@ -597,7 +592,7 @@ def run(self, verbose=False, build_graph=False): from sage.combinat.rigged_configurations.rigged_partition import RiggedPartition, RiggedPartitionTypeB # Convert to a type A_{2n-1}^{(2)} RC - RC = RiggedConfigurations(['A', 2*self.n-1, 2], self.cur_dims) + RC = RiggedConfigurations(['A', 2 * self.n - 1, 2], self.cur_dims) if verbose: print("====================") print(repr(RC(*self.cur_partitions, use_vacancy_numbers=True))) @@ -606,15 +601,13 @@ def run(self, verbose=False, build_graph=False): print("--------------------\n") print("Applying doubling map\n") # Convert the n-th partition into a regular rigged partition - self.cur_partitions[-1] = RiggedPartition(self.cur_partitions[-1]._list, - self.cur_partitions[-1].rigging, - self.cur_partitions[-1].vacancy_numbers) + self.cur_partitions[-1] = RiggedPartition(self.cur_partitions[-1]._list, self.cur_partitions[-1].rigging, self.cur_partitions[-1].vacancy_numbers) bij = RCToKRTBijectionTypeA2Odd(RC(*self.cur_partitions, use_vacancy_numbers=True)) for i in range(len(self.cur_dims)): if bij.cur_dims[i][0] != self.n: bij.cur_dims[i][1] *= 2 - for i in range(self.n-1): + for i in range(self.n - 1): for j in range(len(bij.cur_partitions[i])): bij.cur_partitions[i]._list[j] *= 2 bij.cur_partitions[i].rigging[j] *= 2 @@ -677,7 +670,7 @@ def run(self, verbose=False, build_graph=False): print("--------------------\n") print("Applying halving map\n") - for i in range(self.n-1): + for i in range(self.n - 1): for j in range(len(self.cur_partitions[i])): self.cur_partitions[i]._list[j] //= 2 self.cur_partitions[i].rigging[j] //= 2 @@ -737,6 +730,7 @@ def run(self, verbose=False, build_graph=False): self._graph.pop(0) # Remove the dummy at the start from sage.graphs.digraph import DiGraph from sage.graphs.dot2tex_utils import have_dot2tex + self._graph = DiGraph(self._graph) if have_dot2tex(): self._graph.set_latex_options(format='dot2tex', edge_labels=True) @@ -756,7 +750,7 @@ def next_state(self, height): 0 """ n = self.n - ell = [None] * (2*n) + ell = [None] * (2 * n) case_S = False case_Q = False b = None @@ -764,7 +758,7 @@ def next_state(self, height): # Calculate the rank and ell values last_size = 0 - for a in range(height, n-1): + for a in range(height, n - 1): ell[a] = self._find_singular_string(self.cur_partitions[a], last_size) if ell[a] is None: @@ -776,13 +770,12 @@ def next_state(self, height): # Special case for n if b is None: last_size = 2 * last_size - 1 - partition = self.cur_partitions[n-1] + partition = self.cur_partitions[n - 1] # Modified version of _find_singular_string() for i in reversed(range(len(partition))): - if partition[i] == last_size \ - and partition.vacancy_numbers[i] == partition.rigging[i]: + if partition[i] == last_size and partition.vacancy_numbers[i] == partition.rigging[i]: case_Q = True - ell[n-1] = i + ell[n - 1] = i elif partition[i] > last_size: if not case_Q and partition.vacancy_numbers[i] - 1 == partition.rigging[i]: case_Q = True @@ -793,22 +786,22 @@ def next_state(self, height): break elif partition.vacancy_numbers[j] == partition.rigging[j]: case_Q = False - ell[2*n-1] = j + ell[2 * n - 1] = j last_size = partition[j] case_S = True break if not case_Q: # We found a singular string above the quasi-singular one break - ell[n-1] = i + ell[n - 1] = i last_size = partition[i] # Now check for case QS elif partition.vacancy_numbers[i] == partition.rigging[i]: - ell[2*n-1] = i + ell[2 * n - 1] = i last_size = partition[i] case_S = True break - if ell[2*n-1] is None: + if ell[2 * n - 1] is None: if not case_Q: b = n else: @@ -823,8 +816,7 @@ def next_state(self, height): if a < height: end = len(self.cur_partitions[a]) for i in reversed(range(end)): - if self.cur_partitions[a][i] >= last_size and \ - self.cur_partitions[a].vacancy_numbers[i] == self.cur_partitions[a].rigging[i]: + if self.cur_partitions[a][i] >= last_size and self.cur_partitions[a].vacancy_numbers[i] == self.cur_partitions[a].rigging[i]: ell[n + a] = i break @@ -841,34 +833,31 @@ def next_state(self, height): # selected string and then making the new string singular # Determine if we need to make the n-th string quasisingular - make_quasisingular = case_Q and case_S and \ - (ell[2*n-2] is None - or self.cur_partitions[n-1][ell[2*n-1]] - < 2*self.cur_partitions[n-2][ell[2*n-2]]) + make_quasisingular = case_Q and case_S and (ell[2 * n - 2] is None or self.cur_partitions[n - 1][ell[2 * n - 1]] < 2 * self.cur_partitions[n - 2][ell[2 * n - 2]]) row_num = self.cur_partitions[0].remove_cell(ell[0]) row_num_bar = self.cur_partitions[0].remove_cell(ell[n]) - for a in range(1, n-1): + for a in range(1, n - 1): row_num_next = self.cur_partitions[a].remove_cell(ell[a]) - row_num_bar_next = self.cur_partitions[a].remove_cell(ell[n+a]) + row_num_bar_next = self.cur_partitions[a].remove_cell(ell[n + a]) self._update_vacancy_numbers(a - 1) if row_num is not None: - self.cur_partitions[a-1].rigging[row_num] = self.cur_partitions[a-1].vacancy_numbers[row_num] + self.cur_partitions[a - 1].rigging[row_num] = self.cur_partitions[a - 1].vacancy_numbers[row_num] if row_num_bar is not None: - self.cur_partitions[a-1].rigging[row_num_bar] = self.cur_partitions[a-1].vacancy_numbers[row_num_bar] + self.cur_partitions[a - 1].rigging[row_num_bar] = self.cur_partitions[a - 1].vacancy_numbers[row_num_bar] row_num = row_num_next row_num_bar = row_num_bar_next if case_Q: if case_S: - row_num_next = self.cur_partitions[n-1].remove_cell(ell[n-1]) - row_num_bar_next = self.cur_partitions[n-1].remove_cell(ell[2*n-1]) + row_num_next = self.cur_partitions[n - 1].remove_cell(ell[n - 1]) + row_num_bar_next = self.cur_partitions[n - 1].remove_cell(ell[2 * n - 1]) else: - row_num_next = self.cur_partitions[n-1].remove_cell(ell[n-1]) + row_num_next = self.cur_partitions[n - 1].remove_cell(ell[n - 1]) row_num_bar_next = None elif case_S: - row_num_next = self.cur_partitions[n-1].remove_cell(ell[2*n-1], 2) + row_num_next = self.cur_partitions[n - 1].remove_cell(ell[2 * n - 1], 2) row_num_bar_next = None else: row_num_next = None @@ -876,24 +865,23 @@ def next_state(self, height): self._update_vacancy_numbers(n - 2) if row_num is not None: - self.cur_partitions[n-2].rigging[row_num] = self.cur_partitions[n-2].vacancy_numbers[row_num] + self.cur_partitions[n - 2].rigging[row_num] = self.cur_partitions[n - 2].vacancy_numbers[row_num] if row_num_bar is not None: - self.cur_partitions[n-2].rigging[row_num_bar] = self.cur_partitions[n-2].vacancy_numbers[row_num_bar] + self.cur_partitions[n - 2].rigging[row_num_bar] = self.cur_partitions[n - 2].vacancy_numbers[row_num_bar] self._update_vacancy_numbers(n - 1) if row_num_next is not None: - self.cur_partitions[n-1].rigging[row_num_next] = self.cur_partitions[n-1].vacancy_numbers[row_num_next] + self.cur_partitions[n - 1].rigging[row_num_next] = self.cur_partitions[n - 1].vacancy_numbers[row_num_next] if row_num_bar_next is not None: # If we enter here, it means case (Q, S) holds - vac_num = self.cur_partitions[n-1].vacancy_numbers[row_num_bar_next] - self.cur_partitions[n-1].rigging[row_num_bar_next] = vac_num + vac_num = self.cur_partitions[n - 1].vacancy_numbers[row_num_bar_next] + self.cur_partitions[n - 1].rigging[row_num_bar_next] = vac_num if make_quasisingular: - block_len = self.cur_partitions[n-1][row_num_bar_next] + block_len = self.cur_partitions[n - 1][row_num_bar_next] j = row_num_bar_next + 1 - length = len(self.cur_partitions[n-1]) + length = len(self.cur_partitions[n - 1]) # Find the place for the quasisingular rigging - while j < length and self.cur_partitions[n-1][j] == block_len \ - and self.cur_partitions[n-1].rigging[j] == vac_num: + while j < length and self.cur_partitions[n - 1][j] == block_len and self.cur_partitions[n - 1].rigging[j] == vac_num: j += 1 - self.cur_partitions[n-1].rigging[j-1] = vac_num - 1 + self.cur_partitions[n - 1].rigging[j - 1] = vac_num - 1 return b diff --git a/src/sage/combinat/rigged_configurations/bij_type_C.py b/src/sage/combinat/rigged_configurations/bij_type_C.py index 9e0997e1479..8fc5f4c4f47 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_C.py +++ b/src/sage/combinat/rigged_configurations/bij_type_C.py @@ -93,7 +93,7 @@ def next_state(self, val): case_S[a] = max_width # Special case for n - max_width = self.ret_rig_con[n-1].insert_cell(max_width // 2) * 2 + max_width = self.ret_rig_con[n - 1].insert_cell(max_width // 2) * 2 # Now go back following the special C_n rules for a in reversed(range(tableau_height, n - 1)): @@ -110,7 +110,7 @@ def next_state(self, val): self._update_partition_values(tableau_height) if pos_val <= tableau_height: - for a in range(pos_val-1, tableau_height): + for a in range(pos_val - 1, tableau_height): self._update_vacancy_nums(a) self._update_partition_values(a) if pos_val > 1: @@ -152,10 +152,10 @@ def _insert_cell_case_S(self, partition): if partition.rigging[i] is None: j = i - 1 while j >= 0 and partition._list[j] == partition._list[i]: - partition.rigging[j+1] = partition.rigging[j] # Shuffle it along + partition.rigging[j + 1] = partition.rigging[j] # Shuffle it along j -= 1 - partition._list[j+1] += 1 - partition.rigging[j+1] = None + partition._list[j + 1] += 1 + partition.rigging[j + 1] = None return @@ -179,14 +179,14 @@ def next_state(self, height): """ height -= 1 # indexing n = self.n - ell = [None] * (2*n) + ell = [None] * (2 * n) case_S = [False] * n b = None # Calculate the rank and ell values last_size = 0 - for a in range(height, n-1): + for a in range(height, n - 1): ell[a] = self._find_singular_string(self.cur_partitions[a], last_size) if ell[a] is None: @@ -199,24 +199,23 @@ def next_state(self, height): if b is None: # Since we are dividing by 2, we can use the identity of # ceiling = floor + remainder - ell[n-1] = self._find_singular_string(self.cur_partitions[n-1], - (last_size // 2) + (last_size % 2)) + ell[n - 1] = self._find_singular_string(self.cur_partitions[n - 1], (last_size // 2) + (last_size % 2)) - if ell[n-1] is None: + if ell[n - 1] is None: b = n else: - last_size = self.cur_partitions[n-1][ell[n-1]] * 2 + last_size = self.cur_partitions[n - 1][ell[n - 1]] * 2 if b is None: # Now go back - ell[2*n-1] = ell[n-1] - case_S[n-1] = True - for a in reversed(range(n-1)): + ell[2 * n - 1] = ell[n - 1] + case_S[n - 1] = True + for a in reversed(range(n - 1)): if a >= height and self.cur_partitions[a][ell[a]] == last_size: - ell[n+a] = ell[a] + ell[n + a] = ell[a] case_S[a] = True else: # note last_size > 1 - ell[n+a] = self._find_singular_string(self.cur_partitions[a], last_size) + ell[n + a] = self._find_singular_string(self.cur_partitions[a], last_size) if ell[n + a] is None: b = -(a + 2) @@ -235,32 +234,32 @@ def next_state(self, height): else: row_num = self.cur_partitions[0].remove_cell(ell[0]) row_num_bar = self.cur_partitions[0].remove_cell(ell[n]) - for a in range(1, n-1): + for a in range(1, n - 1): if case_S[a]: row_num_next = self.cur_partitions[a].remove_cell(ell[a], 2) row_num_bar_next = None else: row_num_next = self.cur_partitions[a].remove_cell(ell[a]) - row_num_bar_next = self.cur_partitions[a].remove_cell(ell[n+a]) + row_num_bar_next = self.cur_partitions[a].remove_cell(ell[n + a]) self._update_vacancy_numbers(a - 1) if row_num is not None: - self.cur_partitions[a-1].rigging[row_num] = self.cur_partitions[a-1].vacancy_numbers[row_num] + self.cur_partitions[a - 1].rigging[row_num] = self.cur_partitions[a - 1].vacancy_numbers[row_num] if row_num_bar is not None: - self.cur_partitions[a-1].rigging[row_num_bar] = self.cur_partitions[a-1].vacancy_numbers[row_num_bar] + self.cur_partitions[a - 1].rigging[row_num_bar] = self.cur_partitions[a - 1].vacancy_numbers[row_num_bar] row_num = row_num_next row_num_bar = row_num_bar_next - row_num_next = self.cur_partitions[n-1].remove_cell(ell[n-1]) + row_num_next = self.cur_partitions[n - 1].remove_cell(ell[n - 1]) self._update_vacancy_numbers(n - 2) if row_num is not None: - self.cur_partitions[n-2].rigging[row_num] = self.cur_partitions[n-2].vacancy_numbers[row_num] + self.cur_partitions[n - 2].rigging[row_num] = self.cur_partitions[n - 2].vacancy_numbers[row_num] if row_num_bar is not None: - self.cur_partitions[n-2].rigging[row_num_bar] = self.cur_partitions[n-2].vacancy_numbers[row_num_bar] + self.cur_partitions[n - 2].rigging[row_num_bar] = self.cur_partitions[n - 2].vacancy_numbers[row_num_bar] self._update_vacancy_numbers(n - 1) if row_num_next is not None: - self.cur_partitions[n-1].rigging[row_num_next] = self.cur_partitions[n-1].vacancy_numbers[row_num_next] + self.cur_partitions[n - 1].rigging[row_num_next] = self.cur_partitions[n - 1].vacancy_numbers[row_num_next] return b diff --git a/src/sage/combinat/rigged_configurations/bij_type_D.py b/src/sage/combinat/rigged_configurations/bij_type_D.py index a6a5c8316a7..594629d9ba8 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_D.py +++ b/src/sage/combinat/rigged_configurations/bij_type_D.py @@ -77,8 +77,7 @@ def run(self, verbose=False): """ if verbose: - from sage.combinat.rigged_configurations.tensor_product_kr_tableaux_element \ - import TensorProductOfKirillovReshetikhinTableauxElement + from sage.combinat.rigged_configurations.tensor_product_kr_tableaux_element import TensorProductOfKirillovReshetikhinTableauxElement for cur_crystal in reversed(self.tp_krt): r = cur_crystal.parent().r() @@ -87,7 +86,7 @@ def run(self, verbose=False): self.cur_path.insert(0, []) # Prepend an empty list # Check to see if we are a spinor column - if r >= self.n-1: + if r >= self.n - 1: if verbose: print("====================") print(repr(TensorProductOfKirillovReshetikhinTableauxElement(self.tp_krt.parent(), self.cur_path))) @@ -117,7 +116,7 @@ def run(self, verbose=False): self.next_state(val) # Check to see if we are a spinor column - if r >= self.n-1: + if r >= self.n - 1: if verbose: print("====================") print(repr(TensorProductOfKirillovReshetikhinTableauxElement(self.tp_krt.parent(), self.cur_path))) @@ -183,8 +182,8 @@ def next_state(self, val): # where we only update the vacancy numbers # This only occurs with `r = n - 1` if self.cur_dims[0][0] == n - 1 and tableau_height == n - 1: - self._update_vacancy_nums(n-2) - self._update_vacancy_nums(n-1) + self._update_vacancy_nums(n - 2) + self._update_vacancy_nums(n - 1) self._correct_vacancy_nums() return @@ -225,8 +224,7 @@ def next_state(self, val): else: max_width = 1 # Special case for `\overline{n-1}` to take the larger of the last two - if pos_val == n - 1 and len(self.ret_rig_con[n - 1]) > 0 and \ - self.ret_rig_con[n - 1][0] + 1 > max_width: + if pos_val == n - 1 and len(self.ret_rig_con[n - 1]) > 0 and self.ret_rig_con[n - 1][0] + 1 > max_width: max_width = self.ret_rig_con[n - 1][0] + 1 # Add cells similar to type A_n but we move to the right until we reach @@ -269,8 +267,8 @@ def next_state(self, val): self._update_vacancy_nums(a) self._update_partition_values(a) if pos_val > 1: - self._update_vacancy_nums(pos_val-2) - self._update_partition_values(pos_val-2) + self._update_vacancy_nums(pos_val - 2) + self._update_partition_values(pos_val - 2) elif 0 < tableau_height: self._update_vacancy_nums(tableau_height - 1) self._update_partition_values(tableau_height - 1) @@ -279,8 +277,8 @@ def next_state(self, val): self._update_vacancy_nums(a) self._update_partition_values(a) if pos_val > 1: - self._update_vacancy_nums(pos_val-2) - self._update_partition_values(pos_val-2) + self._update_vacancy_nums(pos_val - 2) + self._update_partition_values(pos_val - 2) def _correct_vacancy_nums(self): r""" @@ -443,6 +441,7 @@ def run(self, verbose=False, build_graph=False): Digraph on 3 vertices """ from sage.combinat.crystals.letters import CrystalOfLetters + letters = CrystalOfLetters(self.rigged_con.parent()._cartan_type.classical()) # This is technically bad, but because the first thing we do is append @@ -513,9 +512,8 @@ def run(self, verbose=False, build_graph=False): b = self.next_state(self.cur_dims[0][0]) # Corrections for spinor - if dim[0] == self.n and b == -self.n \ - and self.cur_dims[0][0] == self.n - 1: - b = -(self.n-1) + if dim[0] == self.n and b == -self.n and self.cur_dims[0][0] == self.n - 1: + b = -(self.n - 1) # Make sure we have a crystal letter ret_crystal_path[-1].append(letters(b)) # Append the rank @@ -527,7 +525,7 @@ def run(self, verbose=False, build_graph=False): self.cur_dims.pop(0) # Pop off the leading column # Check to see if we were a spinor - if dim[0] >= self.n-1: + if dim[0] >= self.n - 1: if verbose: print("====================") print(repr(self.rigged_con.parent()(*self.cur_partitions, use_vacancy_numbers=True))) @@ -542,9 +540,10 @@ def run(self, verbose=False, build_graph=False): self._graph.append([self._graph[-1][1], (y, len(self._graph)), '1/2x']) if build_graph: - self._graph.pop(0) # Remove the dummy at the start + self._graph.pop(0) # Remove the dummy at the start from sage.graphs.digraph import DiGraph from sage.graphs.dot2tex_utils import have_dot2tex + self._graph = DiGraph(self._graph, format='list_of_edges') if have_dot2tex(): self._graph.set_latex_options(format='dot2tex', edge_labels=True) @@ -564,7 +563,7 @@ def next_state(self, height): 1 """ n = self.n - ell = [None] * (2 * n - 2) # No `\bar{\ell}^{n-1}` and `\bar{\ell}^n` + ell = [None] * (2 * n - 2) # No `\bar{\ell}^{n-1}` and `\bar{\ell}^n` b = None # Calculate the rank and ell values @@ -619,8 +618,7 @@ def next_state(self, height): if a < height: end = len(self.cur_partitions[a]) for i in reversed(range(end)): - if self.cur_partitions[a][i] >= last_size and \ - self.cur_partitions[a].vacancy_numbers[i] == self.cur_partitions[a].rigging[i]: + if self.cur_partitions[a][i] >= last_size and self.cur_partitions[a].vacancy_numbers[i] == self.cur_partitions[a].rigging[i]: ell[n + a] = i break @@ -643,11 +641,9 @@ def next_state(self, height): self._update_vacancy_numbers(a - 1) if ret_row is not None: - self.cur_partitions[a - 1].rigging[ret_row] = \ - self.cur_partitions[a - 1].vacancy_numbers[ret_row] + self.cur_partitions[a - 1].rigging[ret_row] = self.cur_partitions[a - 1].vacancy_numbers[ret_row] if ret_row_bar is not None: - self.cur_partitions[a - 1].rigging[ret_row_bar] = \ - self.cur_partitions[a - 1].vacancy_numbers[ret_row_bar] + self.cur_partitions[a - 1].rigging[ret_row_bar] = self.cur_partitions[a - 1].vacancy_numbers[ret_row_bar] ret_row = ret_row_next ret_row_bar = ret_row_bar_next @@ -658,23 +654,19 @@ def next_state(self, height): self._update_vacancy_numbers(n - 3) if ret_row is not None: - self.cur_partitions[n - 3].rigging[ret_row] = \ - self.cur_partitions[n - 3].vacancy_numbers[ret_row] + self.cur_partitions[n - 3].rigging[ret_row] = self.cur_partitions[n - 3].vacancy_numbers[ret_row] if ret_row_bar is not None: - self.cur_partitions[n - 3].rigging[ret_row_bar] = \ - self.cur_partitions[n - 3].vacancy_numbers[ret_row_bar] + self.cur_partitions[n - 3].rigging[ret_row_bar] = self.cur_partitions[n - 3].vacancy_numbers[ret_row_bar] self._update_vacancy_numbers(n - 2) if ret_row_next is not None: - self.cur_partitions[n - 2].rigging[ret_row_next] = \ - self.cur_partitions[n - 2].vacancy_numbers[ret_row_next] + self.cur_partitions[n - 2].rigging[ret_row_next] = self.cur_partitions[n - 2].vacancy_numbers[ret_row_next] self._update_vacancy_numbers(n - 1) if height >= n - 1: self._correct_vacancy_nums() if ret_row_bar_next is not None: - self.cur_partitions[n - 1].rigging[ret_row_bar_next] = \ - self.cur_partitions[n - 1].vacancy_numbers[ret_row_bar_next] + self.cur_partitions[n - 1].rigging[ret_row_bar_next] = self.cur_partitions[n - 1].vacancy_numbers[ret_row_bar_next] return b @@ -766,5 +758,5 @@ def _correct_vacancy_nums(self): -4 """ n = self.n - for i in range(len(self.cur_partitions[n-1]._list)): - self.cur_partitions[n-1].vacancy_numbers[i] += 1 + for i in range(len(self.cur_partitions[n - 1]._list)): + self.cur_partitions[n - 1].vacancy_numbers[i] += 1 diff --git a/src/sage/combinat/rigged_configurations/bij_type_D_tri.py b/src/sage/combinat/rigged_configurations/bij_type_D_tri.py index b82ff955642..f39c1e13a78 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_D_tri.py +++ b/src/sage/combinat/rigged_configurations/bij_type_D_tri.py @@ -104,11 +104,10 @@ def next_state(self, val): num_rows = len(p) for i in range(num_rows): if p._list[i] == width_n: - j = i+1 - while j < num_rows and p._list[j] == width_n \ - and p.vacancy_numbers[j] == p.rigging[j]: + j = i + 1 + while j < num_rows and p._list[j] == width_n and p.vacancy_numbers[j] == p.rigging[j]: j += 1 - p.rigging[j-1] -= 1 + p.rigging[j - 1] -= 1 break return @@ -156,9 +155,9 @@ def next_state(self, val): j = len(P._list) - 1 while j >= 0 and P._list[j] <= 2: j -= 1 - P._list.insert(j+1, 2) - P.vacancy_numbers.insert(j+1, None) - P.rigging.insert(j+1, None) + P._list.insert(j + 1, 2) + P.vacancy_numbers.insert(j + 1, None) + P.rigging.insert(j + 1, None) break elif P._list[i] <= max_width: if P.vacancy_numbers[i] == P.rigging[i]: @@ -170,11 +169,11 @@ def next_state(self, val): else: j = i - 1 while j >= 0 and P._list[j] <= max_width + 2: - P.rigging[j+1] = P.rigging[j] # Shuffle it along + P.rigging[j + 1] = P.rigging[j] # Shuffle it along j -= 1 P._list.pop(i) - P._list.insert(j+1, max_width + 2) - P.rigging[j+1] = None + P._list.insert(j + 1, max_width + 2) + P.rigging[j + 1] = None break elif P.vacancy_numbers[i] - 1 == P.rigging[i] and not case_QS: case_QS = True @@ -194,10 +193,10 @@ def next_state(self, val): if P.rigging[i] is None: j = i - 1 while j >= 0 and P._list[j] == P._list[i]: - P.rigging[j+1] = P.rigging[j] # Shuffle it along + P.rigging[j + 1] = P.rigging[j] # Shuffle it along j -= 1 - P._list[j+1] += 1 - P.rigging[j+1] = None + P._list[j + 1] += 1 + P.rigging[j + 1] = None break else: max_width = self.ret_rig_con[1].insert_cell(max_width) @@ -211,10 +210,10 @@ def next_state(self, val): if P.rigging[i] is None: j = i - 1 while j >= 0 and P._list[j] == P._list[i]: - P.rigging[j+1] = P.rigging[j] # Shuffle it along + P.rigging[j + 1] = P.rigging[j] # Shuffle it along j -= 1 - P._list[j+1] += 1 - P.rigging[j+1] = None + P._list[j + 1] += 1 + P.rigging[j + 1] = None break else: max_width = self.ret_rig_con[0].insert_cell(max_width) @@ -229,11 +228,10 @@ def next_state(self, val): num_rows = len(P) for i in range(num_rows): if P._list[i] == width_n: - j = i+1 - while j < num_rows and P._list[j] == width_n \ - and P.vacancy_numbers[j] == P.rigging[j]: + j = i + 1 + while j < num_rows and P._list[j] == width_n and P.vacancy_numbers[j] == P.rigging[j]: j += 1 - P.rigging[j-1] -= 1 + P.rigging[j - 1] -= 1 break @@ -342,8 +340,7 @@ def next_state(self, height): if case_S[1]: row1 = [self.cur_partitions[1].remove_cell(ell[4], 2)] else: - row1 = [self.cur_partitions[1].remove_cell(ell[1]), - self.cur_partitions[1].remove_cell(ell[4])] + row1 = [self.cur_partitions[1].remove_cell(ell[1]), self.cur_partitions[1].remove_cell(ell[4])] if case_S[0]: row0 = [self.cur_partitions[0].remove_cell(ell[5], 2)] @@ -351,11 +348,9 @@ def next_state(self, height): else: if case_Q: if ell[0] is None or ell[0] < ell[2]: - row0 = [self.cur_partitions[0].remove_cell(ell[2]), - self.cur_partitions[0].remove_cell(ell[0])] + row0 = [self.cur_partitions[0].remove_cell(ell[2]), self.cur_partitions[0].remove_cell(ell[0])] else: - row0 = [self.cur_partitions[0].remove_cell(ell[0]), - self.cur_partitions[0].remove_cell(ell[2])] + row0 = [self.cur_partitions[0].remove_cell(ell[0]), self.cur_partitions[0].remove_cell(ell[2])] if case_S[2]: quasi = self.cur_partitions[0].remove_cell(ell[3]) else: @@ -386,6 +381,6 @@ def next_state(self, height): # Find the place for the quasisingular rigging while j < length and P[j] == block_len and P.rigging[j] == vac_num: j += 1 - P.rigging[j-1] = vac_num - 1 + P.rigging[j - 1] = vac_num - 1 return b diff --git a/src/sage/combinat/rigged_configurations/bij_type_D_twisted.py b/src/sage/combinat/rigged_configurations/bij_type_D_twisted.py index 36e63cf6f60..9b8520ac790 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_D_twisted.py +++ b/src/sage/combinat/rigged_configurations/bij_type_D_twisted.py @@ -78,8 +78,7 @@ def run(self, verbose=False): """ if verbose: - from sage.combinat.rigged_configurations.tensor_product_kr_tableaux_element \ - import TensorProductOfKirillovReshetikhinTableauxElement + from sage.combinat.rigged_configurations.tensor_product_kr_tableaux_element import TensorProductOfKirillovReshetikhinTableauxElement for cur_crystal in reversed(self.tp_krt): r = cur_crystal.parent().r() @@ -173,14 +172,14 @@ def next_state(self, val): if pos_val == 0: if len(self.ret_rig_con[pos_val - 1]) > 0: - max_width = self.ret_rig_con[n-1][0] + max_width = self.ret_rig_con[n - 1][0] else: max_width = 1 - max_width = self.ret_rig_con[n-1].insert_cell(max_width) + max_width = self.ret_rig_con[n - 1].insert_cell(max_width) width_n = max_width + 1 # Follow regular A_n rules - for a in reversed(range(tableau_height, n-1)): + for a in reversed(range(tableau_height, n - 1)): max_width = self.ret_rig_con[a].insert_cell(max_width) self._update_vacancy_nums(a + 1) self._update_partition_values(a + 1) @@ -189,19 +188,18 @@ def next_state(self, val): self._correct_vacancy_nums() self._update_partition_values(tableau_height) if tableau_height > 0: - self._update_vacancy_nums(tableau_height-1) - self._update_partition_values(tableau_height-1) + self._update_vacancy_nums(tableau_height - 1) + self._update_partition_values(tableau_height - 1) # Make the new string at n quasi-singular - p = self.ret_rig_con[n-1] + p = self.ret_rig_con[n - 1] num_rows = len(p) for i in range(num_rows): if p._list[i] == width_n: - j = i+1 - while j < num_rows and p._list[j] == width_n \ - and p.vacancy_numbers[j] == p.rigging[j]: + j = i + 1 + while j < num_rows and p._list[j] == width_n and p.vacancy_numbers[j] == p.rigging[j]: j += 1 - p.rigging[j-1] -= 1 + p.rigging[j - 1] -= 1 break return @@ -217,14 +215,14 @@ def next_state(self, val): # Add cells similar to type A_n but we move to the right until we # reach the value of n-1 - for a in range(pos_val - 1, n-1): + for a in range(pos_val - 1, n - 1): max_width = self.ret_rig_con[a].insert_cell(max_width) case_S[a] = max_width # Special case for n # If we find a quasi-singular string first, then we are in case (Q, S) # otherwise we will find a singular string and insert 2 cells - partition = self.ret_rig_con[n-1] + partition = self.ret_rig_con[n - 1] num_rows = len(partition) case_QS = False for i in range(num_rows + 1): @@ -244,9 +242,9 @@ def next_state(self, val): j = len(partition._list) - 1 while j >= 0 and partition._list[j] <= 2: j -= 1 - partition._list.insert(j+1, 2) - partition.vacancy_numbers.insert(j+1, None) - partition.rigging.insert(j+1, None) + partition._list.insert(j + 1, 2) + partition.vacancy_numbers.insert(j + 1, None) + partition.rigging.insert(j + 1, None) break elif partition._list[i] <= max_width: if partition.vacancy_numbers[i] == partition.rigging[i]: @@ -258,11 +256,11 @@ def next_state(self, val): else: j = i - 1 while j >= 0 and partition._list[j] <= max_width + 2: - partition.rigging[j+1] = partition.rigging[j] # Shuffle it along + partition.rigging[j + 1] = partition.rigging[j] # Shuffle it along j -= 1 partition._list.pop(i) - partition._list.insert(j+1, max_width + 2) - partition.rigging[j+1] = None + partition._list.insert(j + 1, max_width + 2) + partition.rigging[j + 1] = None break elif partition.vacancy_numbers[i] - 1 == partition.rigging[i] and not case_QS: case_QS = True @@ -271,7 +269,7 @@ def next_state(self, val): # No need to set max_width here since we will find a singular string # Now go back following the regular C_n (ish) rules - for a in reversed(range(tableau_height, n-1)): + for a in reversed(range(tableau_height, n - 1)): if case_S[a] == max_width: self._insert_cell_case_S(self.ret_rig_con[a]) else: @@ -286,7 +284,7 @@ def next_state(self, val): self._update_partition_values(tableau_height) if pos_val <= tableau_height: - for a in range(pos_val-1, tableau_height): + for a in range(pos_val - 1, tableau_height): self._update_vacancy_nums(a) self._update_partition_values(a) if pos_val > 1: @@ -301,11 +299,10 @@ def next_state(self, val): num_rows = len(partition) for i in range(num_rows): if partition._list[i] == width_n: - j = i+1 - while j < num_rows and partition._list[j] == width_n \ - and partition.vacancy_numbers[j] == partition.rigging[j]: + j = i + 1 + while j < num_rows and partition._list[j] == width_n and partition.vacancy_numbers[j] == partition.rigging[j]: j += 1 - partition.rigging[j-1] -= 1 + partition.rigging[j - 1] -= 1 break @@ -341,6 +338,7 @@ def run(self, verbose=False, build_graph=False): Digraph on 6 vertices """ from sage.combinat.crystals.letters import CrystalOfLetters + letters = CrystalOfLetters(self.rigged_con.parent()._cartan_type.classical()) # This is technically bad, but because the first thing we do is append @@ -391,17 +389,17 @@ def run(self, verbose=False, build_graph=False): print(ret_crystal_path) print("--------------------\n") - self.cur_dims[0][0] -= 1 # This takes care of the indexing + self.cur_dims[0][0] -= 1 # This takes care of the indexing b = self.next_state(self.cur_dims[0][0]) # Make sure we have a crystal letter - ret_crystal_path[-1].append(letters(b)) # Append the rank + ret_crystal_path[-1].append(letters(b)) # Append the rank if build_graph: y = self.rigged_con.parent()(*[x._clone() for x in self.cur_partitions], use_vacancy_numbers=True) self._graph.append([self._graph[-1][1], (y, len(self._graph)), letters(b)]) - self.cur_dims.pop(0) # Pop off the leading column + self.cur_dims.pop(0) # Pop off the leading column # Check to see if we were a spinor if dim[0] == self.n: @@ -419,9 +417,10 @@ def run(self, verbose=False, build_graph=False): self._graph.append([self._graph[-1][1], (y, len(self._graph)), '1/2x']) if build_graph: - self._graph.pop(0) # Remove the dummy at the start + self._graph.pop(0) # Remove the dummy at the start from sage.graphs.digraph import DiGraph from sage.graphs.dot2tex_utils import have_dot2tex + self._graph = DiGraph(self._graph) if have_dot2tex(): self._graph.set_latex_options(format='dot2tex', edge_labels=True) @@ -441,7 +440,7 @@ def next_state(self, height): -1 """ n = self.n - ell = [None] * (2*n) + ell = [None] * (2 * n) case_S = [False] * n case_Q = False b = None @@ -449,7 +448,7 @@ def next_state(self, height): # Calculate the rank and ell values last_size = 0 - for a in range(height, n-1): + for a in range(height, n - 1): ell[a] = self._find_singular_string(self.cur_partitions[a], last_size) if ell[a] is None: @@ -459,7 +458,7 @@ def next_state(self, height): last_size = self.cur_partitions[a][ell[a]] if b is None: - partition = self.cur_partitions[n-1] + partition = self.cur_partitions[n - 1] # Modified version of _find_singular_string() for i in reversed(range(len(partition))): if partition[i] >= last_size: @@ -468,8 +467,8 @@ def next_state(self, height): b = 'E' else: last_size = partition[i] - case_S[n-1] = True - ell[2*n-1] = i + case_S[n - 1] = True + ell[2 * n - 1] = i break elif partition.vacancy_numbers[i] - 1 == partition.rigging[i] and not case_Q: case_Q = True @@ -483,9 +482,9 @@ def next_state(self, height): break if case_Q: last_size = partition[i] + 1 - ell[n-1] = i + ell[n - 1] = i - if ell[2*n-1] is None: + if ell[2 * n - 1] is None: if not case_Q: b = n else: @@ -493,12 +492,12 @@ def next_state(self, height): if b is None: # Now go back - for a in reversed(range(n-1)): + for a in reversed(range(n - 1)): if a >= height and self.cur_partitions[a][ell[a]] == last_size: - ell[n+a] = ell[a] + ell[n + a] = ell[a] case_S[a] = True else: - ell[n+a] = self._find_singular_string(self.cur_partitions[a], last_size) + ell[n + a] = self._find_singular_string(self.cur_partitions[a], last_size) if ell[n + a] is None: b = -(a + 2) @@ -517,59 +516,58 @@ def next_state(self, height): else: row_num = self.cur_partitions[0].remove_cell(ell[0]) row_num_bar = self.cur_partitions[0].remove_cell(ell[n]) - for a in range(1, n-1): + for a in range(1, n - 1): if case_S[a]: row_num_next = None - row_num_bar_next = self.cur_partitions[a].remove_cell(ell[n+a], 2) + row_num_bar_next = self.cur_partitions[a].remove_cell(ell[n + a], 2) else: row_num_next = self.cur_partitions[a].remove_cell(ell[a]) - row_num_bar_next = self.cur_partitions[a].remove_cell(ell[n+a]) + row_num_bar_next = self.cur_partitions[a].remove_cell(ell[n + a]) self._update_vacancy_numbers(a - 1) if row_num is not None: - self.cur_partitions[a-1].rigging[row_num] = self.cur_partitions[a-1].vacancy_numbers[row_num] + self.cur_partitions[a - 1].rigging[row_num] = self.cur_partitions[a - 1].vacancy_numbers[row_num] if row_num_bar is not None: - self.cur_partitions[a-1].rigging[row_num_bar] = self.cur_partitions[a-1].vacancy_numbers[row_num_bar] + self.cur_partitions[a - 1].rigging[row_num_bar] = self.cur_partitions[a - 1].vacancy_numbers[row_num_bar] row_num = row_num_next row_num_bar = row_num_bar_next if case_Q: - row_num_next = self.cur_partitions[n-1].remove_cell(ell[n-1]) - if case_S[n-1]: - row_num_bar_next = self.cur_partitions[n-1].remove_cell(ell[2*n-1]) + row_num_next = self.cur_partitions[n - 1].remove_cell(ell[n - 1]) + if case_S[n - 1]: + row_num_bar_next = self.cur_partitions[n - 1].remove_cell(ell[2 * n - 1]) else: row_num_bar_next = None - elif case_S[n-1]: + elif case_S[n - 1]: row_num_next = None - row_num_bar_next = self.cur_partitions[n-1].remove_cell(ell[2*n-1], 2) + row_num_bar_next = self.cur_partitions[n - 1].remove_cell(ell[2 * n - 1], 2) else: row_num_next = None row_num_bar_next = None self._update_vacancy_numbers(n - 2) if row_num is not None: - self.cur_partitions[n-2].rigging[row_num] = self.cur_partitions[n-2].vacancy_numbers[row_num] + self.cur_partitions[n - 2].rigging[row_num] = self.cur_partitions[n - 2].vacancy_numbers[row_num] if row_num_bar is not None: - self.cur_partitions[n-2].rigging[row_num_bar] = self.cur_partitions[n-2].vacancy_numbers[row_num_bar] + self.cur_partitions[n - 2].rigging[row_num_bar] = self.cur_partitions[n - 2].vacancy_numbers[row_num_bar] self._update_vacancy_numbers(n - 1) if height == n: self._correct_vacancy_nums() if row_num_next is not None: - self.cur_partitions[n-1].rigging[row_num_next] = self.cur_partitions[n-1].vacancy_numbers[row_num_next] + self.cur_partitions[n - 1].rigging[row_num_next] = self.cur_partitions[n - 1].vacancy_numbers[row_num_next] if row_num_bar_next is not None: if case_Q: - vac_num = self.cur_partitions[n-1].vacancy_numbers[row_num_bar_next] - self.cur_partitions[n-1].rigging[row_num_bar_next] = vac_num - block_len = self.cur_partitions[n-1][row_num_bar_next] + vac_num = self.cur_partitions[n - 1].vacancy_numbers[row_num_bar_next] + self.cur_partitions[n - 1].rigging[row_num_bar_next] = vac_num + block_len = self.cur_partitions[n - 1][row_num_bar_next] j = row_num_bar_next + 1 - length = len(self.cur_partitions[n-1]) + length = len(self.cur_partitions[n - 1]) # Find the place for the quasisingular rigging - while j < length and self.cur_partitions[n-1][j] == block_len \ - and self.cur_partitions[n-1].rigging[j] == vac_num: + while j < length and self.cur_partitions[n - 1][j] == block_len and self.cur_partitions[n - 1].rigging[j] == vac_num: j += 1 - self.cur_partitions[n-1].rigging[j-1] = vac_num - 1 + self.cur_partitions[n - 1].rigging[j - 1] = vac_num - 1 else: - self.cur_partitions[n-1].rigging[row_num_bar_next] = self.cur_partitions[n-1].vacancy_numbers[row_num_bar_next] + self.cur_partitions[n - 1].rigging[row_num_bar_next] = self.cur_partitions[n - 1].vacancy_numbers[row_num_bar_next] return b diff --git a/src/sage/combinat/rigged_configurations/bij_type_E67.py b/src/sage/combinat/rigged_configurations/bij_type_E67.py index 95a0ae39943..1ba8df0b9ad 100644 --- a/src/sage/combinat/rigged_configurations/bij_type_E67.py +++ b/src/sage/combinat/rigged_configurations/bij_type_E67.py @@ -63,6 +63,7 @@ def next_state(self, val): sage: bijection.cur_path[0].insert(0, [(-3,4)]) sage: bijection.next_state((-3,4)) """ + def find_singular_string(p, max_width): max_pos = -1 if max_width > 0: @@ -87,23 +88,22 @@ def find_singular_string(p, max_width): found = True while found: found = False - data = [(-a, find_singular_string(self.ret_rig_con[-a-1], max_width)) - for a in b.value if a < 0] + data = [(-a, find_singular_string(self.ret_rig_con[-a - 1], max_width)) for a in b.value if a < 0] if not data: break max_val = max(l for a, l in data) for a, l in data: if l == max_val: - self.ret_rig_con[a-1].insert_cell(max_width) + self.ret_rig_con[a - 1].insert_cell(max_width) max_width = l b = b.e(a) - found = (b != self._top) + found = b != self._top break for a in end.to_highest_weight()[1]: - p = self.ret_rig_con[a-1] - for i in range(len(p)-1, -1, -1): + p = self.ret_rig_con[a - 1] + for i in range(len(p) - 1, -1, -1): if p.rigging[i] is None: assert p[i] == 1 p._list.pop(i) @@ -236,10 +236,8 @@ def next_state(self, r): b = self._endpoint(r) while found: found = False - data = [(a, self._find_singular_string(self.cur_partitions[a-1], last_size)) - for a in b.value if a > 0] - data = [(val, a, self.cur_partitions[a-1][val]) - for a, val in data if val is not None] + data = [(a, self._find_singular_string(self.cur_partitions[a - 1], last_size)) for a in b.value if a > 0] + data = [(val, a, self.cur_partitions[a - 1][val]) for a, val in data if val is not None] if not data: break @@ -248,7 +246,7 @@ def next_state(self, r): if l == min_val: found = True last_size = l - self.cur_partitions[a-1].remove_cell(i) + self.cur_partitions[a - 1].remove_cell(i) b = b.f(a) break diff --git a/src/sage/combinat/rigged_configurations/bijection.py b/src/sage/combinat/rigged_configurations/bijection.py index 9ed764c4318..a51c4b14ed4 100644 --- a/src/sage/combinat/rigged_configurations/bijection.py +++ b/src/sage/combinat/rigged_configurations/bijection.py @@ -82,20 +82,20 @@ def KRTToRCBijection(tp_krt): if typ == 'E': if ct.classical().rank() < 8: return KRTToRCBijectionTypeE67(tp_krt) - #if typ == 'F': - #if typ == 'G': + # if typ == 'F': + # if typ == 'G': else: - if typ == 'BC': # A_{2n}^{(2)} + if typ == 'BC': # A_{2n}^{(2)} return KRTToRCBijectionTypeA2Even(tp_krt) typ = ct.dual().type() - if typ == 'BC': # A_{2n}^{(2)\dagger} + if typ == 'BC': # A_{2n}^{(2)\dagger} return KRTToRCBijectionTypeA2Dual(tp_krt) - if typ == 'B': # A_{2n-1}^{(2)} + if typ == 'B': # A_{2n-1}^{(2)} return KRTToRCBijectionTypeA2Odd(tp_krt) - if typ == 'C': # D_{n+1}^{(2)} + if typ == 'C': # D_{n+1}^{(2)} return KRTToRCBijectionTypeDTwisted(tp_krt) - #if typ == 'F': # E_6^{(2)} - if typ == 'G': # D_4^{(3)} + # if typ == 'F': # E_6^{(2)} + if typ == 'G': # D_4^{(3)} return KRTToRCBijectionTypeDTri(tp_krt) raise NotImplementedError @@ -124,19 +124,19 @@ def RCToKRTBijection(rigged_configuration_elt): if typ == 'E': if ct.classical().rank() < 8: return RCToKRTBijectionTypeE67(rigged_configuration_elt) - #if typ == 'F': - #if typ == 'G': + # if typ == 'F': + # if typ == 'G': else: - if typ == 'BC': # A_{2n}^{(2)} + if typ == 'BC': # A_{2n}^{(2)} return RCToKRTBijectionTypeA2Even(rigged_configuration_elt) typ = ct.dual().type() - if typ == 'BC': # A_{2n}^{(2)\dagger} + if typ == 'BC': # A_{2n}^{(2)\dagger} return RCToKRTBijectionTypeA2Dual(rigged_configuration_elt) - if typ == 'B': # A_{2n-1}^{(2)} + if typ == 'B': # A_{2n-1}^{(2)} return RCToKRTBijectionTypeA2Odd(rigged_configuration_elt) - if typ == 'C': # D_{n+1}^{(2)} + if typ == 'C': # D_{n+1}^{(2)} return RCToKRTBijectionTypeDTwisted(rigged_configuration_elt) - #if typ == 'F': # E_6^{(2)} - if typ == 'G': # D_4^{(3)} + # if typ == 'F': # E_6^{(2)} + if typ == 'G': # D_4^{(3)} return RCToKRTBijectionTypeDTri(rigged_configuration_elt) raise NotImplementedError diff --git a/src/sage/combinat/rigged_configurations/kleber_tree.py b/src/sage/combinat/rigged_configurations/kleber_tree.py index 69f0460d8b1..2067f4440f6 100644 --- a/src/sage/combinat/rigged_configurations/kleber_tree.py +++ b/src/sage/combinat/rigged_configurations/kleber_tree.py @@ -92,9 +92,7 @@ ###################################### -def _draw_tree(tree_node, node_label=True, style_point=None, style_node='fill=white', style_line=None, - hspace=2.5, vspace=-2.5, start=None, rpos=None, node_id=0, node_prefix='T', - edge_labels=True, use_vector_notation=False): +def _draw_tree(tree_node, node_label=True, style_point=None, style_node='fill=white', style_line=None, hspace=2.5, vspace=-2.5, start=None, rpos=None, node_id=0, node_prefix='T', edge_labels=True, use_vector_notation=False): r""" Return the tikz latex for drawing the Kleber tree. @@ -119,9 +117,9 @@ def _draw_tree(tree_node, node_label=True, style_point=None, style_node='fill=wh \end{tikzpicture} """ if start is None: - start = [0., 0.] + start = [0.0, 0.0] if rpos is None: - rpos = [0., 0.] + rpos = [0.0, 0.0] if not tree_node.children: r = '' @@ -158,7 +156,7 @@ def _draw_tree(tree_node, node_label=True, style_point=None, style_node='fill=wh if i == half and nb_children % 2 == 0: pos[0] = start[0] start[0] += hspace - if i == half+1 and nb_children % 2 == 1: + if i == half + 1 and nb_children % 2 == 1: pos[0] = rpos[0] child = tree_node.children[i] children_str += _draw_tree(child, node_label=node_label, style_node=style_node, style_point=style_point, style_line=style_line, hspace=hspace, vspace=vspace, start=start, rpos=rpos, node_id=i, node_prefix=node_name, edge_labels=edge_labels, use_vector_notation=use_vector_notation) @@ -197,6 +195,7 @@ def _draw_tree(tree_node, node_label=True, style_point=None, style_node='fill=wh res += point_str return res + ##################### # Kleber tree nodes # ##################### @@ -430,8 +429,7 @@ def _repr_(self): sage: KT.root Kleber tree node with weight [0, 2, 0, 2, 0] and upwards edge root [0, 0, 0, 0, 0] """ - return "Kleber tree node with weight %s and upwards edge root %s" % ( - list(self.weight.to_vector()), list(self.up_root.to_vector())) + return "Kleber tree node with weight %s and upwards edge root %s" % (list(self.weight.to_vector()), list(self.up_root.to_vector())) def _latex_(self): r""" @@ -486,8 +484,7 @@ def _latex_(self): gamma = max(s_factors) # Subtract 1 for indexing if gamma > 1: - L = [self.parent()._folded_ct.folding_orbit()[a][0] for a in - range(1, len(s_factors)) if s_factors[a] == gamma] + L = [self.parent()._folded_ct.folding_orbit()[a][0] for a in range(1, len(s_factors)) if s_factors[a] == gamma] else: L = [] @@ -495,6 +492,7 @@ def _latex_(self): return "[" + ret_str + "]" return ret_str + ####################### # Kleber tree classes # ####################### @@ -581,6 +579,7 @@ class KleberTree(UniqueRepresentation, Parent): [Kleber tree node with weight [1, 0, 1] and upwards edge root [0, 0, 0], Kleber tree node with weight [0, 0, 0] and upwards edge root [1, 1, 1]] """ + @staticmethod def __classcall_private__(cls, cartan_type, B, classical=None): """ @@ -635,9 +634,7 @@ def __init__(self, cartan_type, B, classical_ct): # version of the Cartan matrix. self._CM = self._classical_ct.cartan_matrix().dense_matrix() self._build_tree() - self._latex_options = dict(edge_labels=True, use_vector_notation=False, - hspace=2.5, - vspace=min(-2.5, -0.75*self._classical_ct.rank())) + self._latex_options = dict(edge_labels=True, use_vector_notation=False, hspace=2.5, vspace=min(-2.5, -0.75 * self._classical_ct.rank())) def latex_options(self, **options): """ @@ -665,6 +662,7 @@ def latex_options(self, **options): """ if not options: from copy import copy + return copy(self._latex_options) for key, value in options.items(): self._latex_options[key] = value @@ -685,11 +683,10 @@ def _latex_(self): '\\begin{tikzpicture}...\\end{tikzpicture}' """ from sage.graphs.graph_latex import setup_latex_preamble + setup_latex_preamble() - return "\\begin{tikzpicture}\n" + \ - _draw_tree(self.root, **self._latex_options) \ - + "\\end{tikzpicture}" + return "\\begin{tikzpicture}\n" + _draw_tree(self.root, **self._latex_options) + "\\end{tikzpicture}" def _build_tree(self): """ @@ -704,8 +701,7 @@ def _build_tree(self): """ P = self._classical_ct.root_system().weight_lattice() # Create an empty node at first step - self.root = KleberTreeNode(self, P.zero(), - self._classical_ct.root_system().root_lattice().zero()) + self.root = KleberTreeNode(self, P.zero(), self._classical_ct.root_system().root_lattice().zero()) full_list = [self.root] # The list of tree nodes n = self._classical_ct.rank() @@ -753,10 +749,7 @@ def _build_tree(self): for i in range(depth - 1, len(L[a])): # Subtract 1 for indexing x.weight += L[a][i] * weight_basis[I[a]] - new_children = [new_child - for x in leaves - for new_child in child_itr(x) - if not self._prune(new_child, depth)] + new_children = [new_child for x in leaves for new_child in child_itr(x) if not self._prune(new_child, depth)] # Connect the new children into the tree if new_children: @@ -809,7 +802,7 @@ def _children_iter(self, node): # The number 500 comes from testing on my machine about where the # tradeoff occurs between the methods. However, this may grow as # the _children_iter_vector is further optimized. - if node != self.root and prod(val+1 for val in node.up_root.coefficients()) < 1000: + if node != self.root and prod(val + 1 for val in node.up_root.coefficients()) < 1000: yield from self._children_iter_vector(node) return @@ -820,22 +813,22 @@ def _children_iter(self, node): # Construct the polytope by inequalities from sage.geometry.polyhedron.constructor import Polyhedron + # Construct the shifted weight cone root_weight = node.weight.to_vector() - ieqs = [[root_weight[i]] + list(col) - for i, col in enumerate(self._CM.columns())] + ieqs = [[root_weight[i]] + list(col) for i, col in enumerate(self._CM.columns())] # Construct the negative weight cone for i in range(n): - v = [0] * (n+1) - v[i+1] = -1 + v = [0] * (n + 1) + v[i + 1] = -1 ieqs.append(v) - ieqs.append([-1]*(n+1)) # For avoiding the origin + ieqs.append([-1] * (n + 1)) # For avoiding the origin # Construct the bounds for the non-root nodes if node != self.root: for i, c in enumerate(node.up_root.to_vector()): - v = [0] * (n+1) + v = [0] * (n + 1) v[0] = c - v[i+1] = 1 + v[i + 1] = 1 ieqs.append(v) try: @@ -848,8 +841,7 @@ def _children_iter(self, node): # Build the nodes from the polytope # Sort for a consistent ordering (it is typically a small list) for pt in sorted(poly.integral_points(), reverse=True): - up_root = Q._from_dict({I[i]: -val for i, val in enumerate(pt) if val != 0}, - remove_zeros=False) + up_root = Q._from_dict({I[i]: -val for i, val in enumerate(pt) if val != 0}, remove_zeros=False) wt = node.weight + sum(val * P.simple_root(I[i]) for i, val in enumerate(pt)) yield KleberTreeNode(self, wt, up_root, node) @@ -891,16 +883,12 @@ def _children_iter_vector(self, node): next(it) # First element is the zero element for root in it: # Convert the list to the weight lattice - converted_root = sum(cols[i] * c for i, c in enumerate(root) - if c != 0) + converted_root = sum(cols[i] * c for i, c in enumerate(root) if c != 0) if all(wt[i] >= val for i, val in enumerate(converted_root)): wd = {I[i]: wt[i] - val for i, val in enumerate(converted_root)} rd = {I[i]: val for i, val in enumerate(root) if val != 0} - yield KleberTreeNode(self, - P._from_dict(wd), - Q._from_dict(rd, remove_zeros=False), - node) + yield KleberTreeNode(self, P._from_dict(wd), Q._from_dict(rd, remove_zeros=False), node) def _prune(self, new_child, depth): r""" @@ -1135,6 +1123,7 @@ class VirtualKleberTree(KleberTree): sage: KT.cardinality() 15 """ + @staticmethod def __classcall_private__(cls, cartan_type, B): """ @@ -1174,8 +1163,7 @@ def __init__(self, cartan_type, B): sigma = self._folded_ct.folding_orbit() gamma = self._folded_ct.scaling_factors() classical_ct = self._folded_ct.folding_of().classical() - virtual_dims = [[i, s * gamma[r]] - for r, s in B for i in sigma[r]] + virtual_dims = [[i, s * gamma[r]] for r, s in B for i in sigma[r]] KleberTree.__init__(self, cartan_type, virtual_dims, classical_ct) @@ -1227,8 +1215,7 @@ def _prune(self, new_child, depth): gamma = self._folded_ct.scaling_factors() for a in range(1, len(gamma)): s = sigma[a][0] - if ((depth - 1) % gamma[a] != 0 and - new_child.up_root[s] != new_child.parent_node.up_root[s]): + if (depth - 1) % gamma[a] != 0 and new_child.up_root[s] != new_child.parent_node.up_root[s]: return True return False @@ -1258,8 +1245,7 @@ def breadth_first_iter(self, all_nodes=False): # Subtract 1 for indexing if gamma > 1: sigma = self._folded_ct.folding_orbit() - L = [sigma[a][0] for a in range(1, len(s_factors)) - if s_factors[a] == gamma] + L = [sigma[a][0] for a in range(1, len(s_factors)) if s_factors[a] == gamma] else: L = [] @@ -1294,8 +1280,7 @@ def depth_first_iter(self, all_nodes=False): # Subtract 1 for indexing if gamma > 1: sigma = self._folded_ct.folding_orbit() - L = [sigma[a][0] for a in range(1, len(s_factors)) - if s_factors[a] == gamma] + L = [sigma[a][0] for a in range(1, len(s_factors)) if s_factors[a] == gamma] else: L = [] @@ -1333,6 +1318,7 @@ class KleberTreeTypeA2Even(VirtualKleberTree): :class:`VirtualKleberTree` """ + @staticmethod def __classcall_private__(cls, cartan_type, B): """ diff --git a/src/sage/combinat/rigged_configurations/kr_tableaux.py b/src/sage/combinat/rigged_configurations/kr_tableaux.py index 14925e8041d..ba834053f31 100644 --- a/src/sage/combinat/rigged_configurations/kr_tableaux.py +++ b/src/sage/combinat/rigged_configurations/kr_tableaux.py @@ -56,11 +56,7 @@ from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.crystals.tensor_product import CrystalOfWords from sage.combinat.crystals.tensor_product import TensorProductOfRegularCrystalsElement -from sage.combinat.crystals.kirillov_reshetikhin import ( - horizontal_dominoes_removed, - KashiwaraNakashimaTableaux, KirillovReshetikhinGenericCrystalElement, - partitions_in_box, vertical_dominoes_removed -) +from sage.combinat.crystals.kirillov_reshetikhin import horizontal_dominoes_removed, KashiwaraNakashimaTableaux, KirillovReshetikhinGenericCrystalElement, partitions_in_box, vertical_dominoes_removed from sage.combinat.partition import Partition from sage.combinat.tableau import Tableau @@ -223,6 +219,7 @@ class KirillovReshetikhinTableaux(CrystalOfWords): sage: all(t.classical_weight() == KRCrys(t).classical_weight() for t in KRTab) True """ + @staticmethod def __classcall_private__(cls, cartan_type, r, s): """ @@ -310,8 +307,7 @@ def _repr_(self): sage: crystals.KirillovReshetikhin(['A', 4, 1], 2, 3, model='KR') Kirillov-Reshetikhin tableaux of type ['A', 4, 1] and shape (2, 3) """ - return "Kirillov-Reshetikhin tableaux of type {} and shape ({}, {})".format( - self._cartan_type, self._r, self._s) + return "Kirillov-Reshetikhin tableaux of type {} and shape ({}, {})".format(self._cartan_type, self._r, self._s) def __iter__(self): """ @@ -326,9 +322,8 @@ def __iter__(self): """ index_set = self._cartan_type.classical().index_set() from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet - rset = RecursivelyEnumeratedSet(self.module_generators, - lambda x: [x.f(i) for i in index_set], - structure='graded') + + rset = RecursivelyEnumeratedSet(self.module_generators, lambda x: [x.f(i) for i in index_set], structure='graded') return rset.breadth_first_search_iterator() def module_generator(self, i=None, **options): @@ -464,8 +459,7 @@ def _element_constructor_(self, *lst, **options): """ if isinstance(lst[0], KirillovReshetikhinGenericCrystalElement): # Check to make sure it can be converted - if lst[0].cartan_type() != self.cartan_type() \ - or lst[0].parent().r() != self._r or lst[0].parent().s() != self._s: + if lst[0].cartan_type() != self.cartan_type() or lst[0].parent().r() != self._r or lst[0].parent().s() != self._s: raise ValueError("the Kirillov-Reshetikhin crystal must have the same Cartan type and (r,s)") return self.from_kirillov_reshetikhin_crystal(lst[0]) @@ -546,10 +540,9 @@ def tensor(self, *crystals, **options): Kirillov-Reshetikhin crystal of type ['A', 3, 1] with (r,s)=(3,1)] """ ct = self._cartan_type - from sage.combinat.rigged_configurations.tensor_product_kr_tableaux \ - import TensorProductOfKirillovReshetikhinTableaux - if all(isinstance(B, (KirillovReshetikhinTableaux, TensorProductOfKirillovReshetikhinTableaux)) - and B.cartan_type() == ct for B in crystals): + from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux + + if all(isinstance(B, (KirillovReshetikhinTableaux, TensorProductOfKirillovReshetikhinTableaux)) and B.cartan_type() == ct for B in crystals): dims = [[self._r, self._s]] for B in crystals: if isinstance(B, TensorProductOfKirillovReshetikhinTableaux): @@ -604,8 +597,7 @@ def _build_module_generators(self): sage: KRT._build_module_generators() ([[1, 1, 1], [2, 2, 2]],) """ - tableau = [[self._r - j for j in range(self._r)] - for i in range(self._s)] + tableau = [[self._r - j for j in range(self._r)] for i in range(self._s)] return (self.element_class(self, [self.letters(x) for x in flatten(tableau)]),) @@ -732,8 +724,7 @@ def _build_module_generators(self): ([[-2, 1, 1], [-1, 2, -1]], [[1, -2, 1], [2, -1, 2]], [[1, 1, 1], [2, 2, -1]], [[1, 1, 1], [2, 2, 2]]) """ - return tuple(self._fill(weight) for weight in - horizontal_dominoes_removed(self._s, self._r)) + return tuple(self._fill(weight) for weight in horizontal_dominoes_removed(self._s, self._r)) def from_kirillov_reshetikhin_crystal(self, krc): """ @@ -1018,8 +1009,7 @@ def _build_module_generators(self): ([[-2, 1], [-1, 2]], [[1, 1], [2, 2]]) """ odd = int(self._s % 2) - shapes = ([int(x * 2 + odd) for x in sh] - for sh in vertical_dominoes_removed(self._r, self._s // 2)) + shapes = ([int(x * 2 + odd) for x in sh] for sh in vertical_dominoes_removed(self._r, self._s // 2)) return tuple(self._fill(sh) for sh in shapes) def from_kirillov_reshetikhin_crystal(self, krc): @@ -1118,6 +1108,7 @@ def _latex_(self): } """ from sage.combinat.output import tex_from_array + return tex_from_array([[val._latex_() for val in row] for row in self.to_array()]) def _ascii_art_(self): @@ -1132,6 +1123,7 @@ def _ascii_art_(self): 2 4 """ from sage.typeset.ascii_art import AsciiArt + return AsciiArt(self._repr_diagram().splitlines()) def _unicode_art_(self): @@ -1439,8 +1431,8 @@ def left_split(self): P = self.parent() if P._s == 1: raise ValueError("cannot split a single column") - from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import \ - TensorProductOfKirillovReshetikhinTableaux + from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux + r = P._r TP = TensorProductOfKirillovReshetikhinTableaux(P._cartan_type, [[r, 1], [r, P._s - 1]]) lf = TP.crystals[0](*(self[:r])) @@ -1636,8 +1628,8 @@ def left_split(self): P = self.parent() if P._s == 1: raise ValueError("cannot split a single column") - from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import \ - TensorProductOfKirillovReshetikhinTableaux + from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux + h = P._cartan_type.classical().rank() TP = TensorProductOfKirillovReshetikhinTableaux(P._cartan_type, [[P._r, 1], [P._r, P._s - 1]]) lf = TP.crystals[0](*(self[:h])) @@ -1682,6 +1674,7 @@ class KRTableauxDTwistedSpin(KRTableauxRectangle): sage: KRT.cardinality() == KRC.cardinality() True """ + Element = KRTableauxSpinElement @@ -1709,6 +1702,7 @@ def e(self, i): if i == self.parent().cartan_type().special_node(): P = self.parent() from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux + K = TensorProductOfKirillovReshetikhinTableaux(P.cartan_type(), [[2, P.s()]]) ret = K(self).to_rigged_configuration() RC = ret.parent() @@ -1738,6 +1732,7 @@ def f(self, i): if i == self.parent().cartan_type().special_node(): P = self.parent() from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux + K = TensorProductOfKirillovReshetikhinTableaux(P.cartan_type(), [[2, P.s()]]) ret = K(self).to_rigged_configuration() RC = ret.parent() @@ -1766,6 +1761,7 @@ def epsilon(self, i): if i == self.parent().cartan_type().special_node(): P = self.parent() from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux + K = TensorProductOfKirillovReshetikhinTableaux(P.cartan_type(), [[2, P.s()]]) rc = K(self).to_rigged_configuration().to_virtual_configuration() return rc.epsilon(0) @@ -1788,6 +1784,7 @@ def phi(self, i): if i == self.parent().cartan_type().special_node(): P = self.parent() from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux + K = TensorProductOfKirillovReshetikhinTableaux(P.cartan_type(), [[2, P.s()]]) rc = K(self).to_rigged_configuration().to_virtual_configuration() return rc.phi(0) @@ -1846,9 +1843,9 @@ def _build_module_generators(self): ([[1], [2]], [[1], [0]], [[1], [E]], [[E], [E]]) """ from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations + RC = RiggedConfigurations(self._cartan_type, [[self._r, self._s]]) - return tuple(mg.to_tensor_product_of_kirillov_reshetikhin_tableaux()[0] - for mg in RC.module_generators) + return tuple(mg.to_tensor_product_of_kirillov_reshetikhin_tableaux()[0] for mg in RC.module_generators) @lazy_attribute def _tableau_height(self): diff --git a/src/sage/combinat/rigged_configurations/rc_crystal.py b/src/sage/combinat/rigged_configurations/rc_crystal.py index 99ba3648126..d4d8be72a70 100644 --- a/src/sage/combinat/rigged_configurations/rc_crystal.py +++ b/src/sage/combinat/rigged_configurations/rc_crystal.py @@ -34,8 +34,7 @@ from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations -from sage.combinat.rigged_configurations.rigged_configuration_element import ( - RiggedConfigurationElement, RCHighestWeightElement, RCHWNonSimplyLacedElement) +from sage.combinat.rigged_configurations.rigged_configuration_element import RiggedConfigurationElement, RCHighestWeightElement, RCHWNonSimplyLacedElement from sage.combinat.rigged_configurations.rigged_partition import RiggedPartition # Note on implementation, this class is used for simply-laced types only @@ -115,6 +114,7 @@ class CrystalOfRiggedConfigurations(UniqueRepresentation, Parent): - [SS2015II]_ - [SS2017]_ """ + @staticmethod def __classcall_private__(cls, cartan_type, wt=None, WLR=None): r""" @@ -172,7 +172,7 @@ def __init__(self, wt, WLR): self._cartan_type = WLR.cartan_type() self._wt = wt self._rc_index = self._cartan_type.index_set() - self._rc_index_inverse = {i: ii for ii,i in enumerate(self._rc_index)} + self._rc_index_inverse = {i: ii for ii, i in enumerate(self._rc_index)} # We store the Cartan matrix for the vacancy number calculations for speed self._cartan_matrix = self._cartan_type.cartan_matrix() if self._cartan_type.is_finite(): @@ -195,8 +195,7 @@ def _repr_(self): sage: crystals.RiggedConfigurations(La[1]) Crystal of rigged configurations of type ['A', 3] and weight Lambda[1] """ - return "Crystal of rigged configurations of type {0} and weight {1}".format( - self._cartan_type, self._wt) + return "Crystal of rigged configurations of type {0} and weight {1}".format(self._cartan_type, self._wt) def _element_constructor_(self, *lst, **options): """ @@ -242,9 +241,9 @@ def _element_constructor_(self, *lst, **options): lst = lst[0] if isinstance(lst[0], RiggedPartition): - lst = [p._clone() for p in lst] # Make a deep copy + lst = [p._clone() for p in lst] # Make a deep copy elif isinstance(lst[0], RiggedConfigurationElement): - lst = [p._clone() for p in lst[0]] # Make a deep copy + lst = [p._clone() for p in lst[0]] # Make a deep copy return self.element_class(self, list(lst), **options) @@ -273,8 +272,8 @@ def _calc_vacancy_number(self, partitions, a, i, **options): """ vac_num = self._wt[self.index_set()[a]] - for b,nu in enumerate(partitions): - val = self._cartan_matrix[a,b] + for b, nu in enumerate(partitions): + val = self._cartan_matrix[a, b] if val: if i == float('inf'): vac_num -= val * sum(nu) @@ -336,7 +335,7 @@ def virtual(self): P = self._folded_ct._folding.root_system().weight_lattice() gamma = self._folded_ct.scaling_factors() sigma = self._folded_ct.folding_orbit() - vwt = P.sum_of_terms((b, gamma[a]*c) for a,c in self._wt for b in sigma[a]) + vwt = P.sum_of_terms((b, gamma[a] * c) for a, c in self._wt for b in sigma[a]) return CrystalOfRiggedConfigurations(vwt) def _calc_vacancy_number(self, partitions, a, i, **options): @@ -367,15 +366,14 @@ def _calc_vacancy_number(self, partitions, a, i, **options): vac_num = self._wt[ia] if i == float('inf'): - return vac_num - sum(self._cartan_matrix[a,b] * sum(nu) - for b,nu in enumerate(partitions)) + return vac_num - sum(self._cartan_matrix[a, b] * sum(nu) for b, nu in enumerate(partitions)) gamma = self._folded_ct.scaling_factors() g = gamma[ia] for b, nu in enumerate(partitions): ib = I[b] - q = nu.get_num_cells_to_column(g*i, gamma[ib]) - vac_num -= self._cartan_matrix[a,b] * q / gamma[ib] + q = nu.get_num_cells_to_column(g * i, gamma[ib]) + vac_num -= self._cartan_matrix[a, b] * q / gamma[ib] return vac_num @@ -422,10 +420,9 @@ def to_virtual(self, rc): for a, rp in enumerate(rc): for i in sigma[a]: k = vindex.index(i) - partitions[k] = [row_len*gamma[a] for row_len in rp._list] - riggings[k] = [rig_val*gamma[a] for rig_val in rp.rigging] - return self.virtual.element_class(self.virtual, partition_list=partitions, - rigging_list=riggings) + partitions[k] = [row_len * gamma[a] for row_len in rp._list] + riggings[k] = [rig_val * gamma[a] for rig_val in rp.rigging] + return self.virtual.element_class(self.virtual, partition_list=partitions, rigging_list=riggings) def from_virtual(self, vrc): """ diff --git a/src/sage/combinat/rigged_configurations/rc_infinity.py b/src/sage/combinat/rigged_configurations/rc_infinity.py index b9d62d74b4f..1f5c1e6a138 100644 --- a/src/sage/combinat/rigged_configurations/rc_infinity.py +++ b/src/sage/combinat/rigged_configurations/rc_infinity.py @@ -28,8 +28,7 @@ from sage.categories.highest_weight_crystals import HighestWeightCrystals from sage.categories.homset import Hom from sage.combinat.root_system.cartan_type import CartanType -from sage.combinat.rigged_configurations.rigged_configuration_element import ( - RiggedConfigurationElement, RCNonSimplyLacedElement) +from sage.combinat.rigged_configurations.rigged_configuration_element import RiggedConfigurationElement, RCNonSimplyLacedElement from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations from sage.combinat.rigged_configurations.rigged_partition import RiggedPartition @@ -130,6 +129,7 @@ class InfinityCrystalOfRiggedConfigurations(UniqueRepresentation, Parent): sage: RiggedConfigurations.options._reset() """ + @staticmethod def __classcall_private__(cls, cartan_type): r""" @@ -143,6 +143,7 @@ def __classcall_private__(cls, cartan_type): True """ from sage.combinat.root_system.type_folded import CartanTypeFolded + if isinstance(cartan_type, CartanTypeFolded): return InfinityCrystalOfNonSimplyLacedRC(cartan_type) @@ -171,7 +172,7 @@ def __init__(self, cartan_type): # We store the Cartan matrix for the vacancy number # calculations for speed self._cartan_matrix = self._cartan_type.cartan_matrix() - self.module_generators = (self.element_class(self, rigging_list=[[]]*cartan_type.rank()),) + self.module_generators = (self.element_class(self, rigging_list=[[]] * cartan_type.rank()),) options = RiggedConfigurations.options @@ -237,9 +238,10 @@ def _coerce_map_from_(self, P): """ if self.cartan_type().is_finite(): from sage.combinat.crystals.infinity_crystals import InfinityCrystalOfTableaux - if (isinstance(P, InfinityCrystalOfTableaux) - and self.cartan_type().is_simply_laced()): + + if isinstance(P, InfinityCrystalOfTableaux) and self.cartan_type().is_simply_laced(): from sage.combinat.rigged_configurations.bij_infinity import FromTableauIsomorphism + return FromTableauIsomorphism(Hom(P, self)) return super()._coerce_map_from_(P) @@ -266,11 +268,9 @@ def _calc_vacancy_number(self, partitions, a, i, **options): -1 """ if i == float('inf'): - return -sum(self._cartan_matrix[a, b] * sum(nu) - for b, nu in enumerate(partitions)) + return -sum(self._cartan_matrix[a, b] * sum(nu) for b, nu in enumerate(partitions)) - return -sum(self._cartan_matrix[a, b] * nu.get_num_cells_to_column(i) - for b, nu in enumerate(partitions)) + return -sum(self._cartan_matrix[a, b] * nu.get_num_cells_to_column(i) for b, nu in enumerate(partitions)) # FIXME: Remove this method!!! def weight_lattice_realization(self): @@ -355,8 +355,10 @@ def _coerce_map_from_(self, P): """ if self.cartan_type().is_finite(): from sage.combinat.crystals.infinity_crystals import InfinityCrystalOfTableaux + if isinstance(P, InfinityCrystalOfTableaux): from sage.combinat.rigged_configurations.bij_infinity import FromTableauIsomorphism + return FromTableauIsomorphism(Hom(P, self)) return super()._coerce_map_from_(P) @@ -388,8 +390,7 @@ def _calc_vacancy_number(self, partitions, a, i): vac_num = 0 if i == float('inf'): - return -sum(self._cartan_matrix[a, b] * sum(nu) - for b, nu in enumerate(partitions)) + return -sum(self._cartan_matrix[a, b] * sum(nu) for b, nu in enumerate(partitions)) gamma = self._folded_ct.scaling_factors() g = gamma[ia] @@ -457,8 +458,7 @@ def to_virtual(self, rc): k = vindex.index(i) partitions[k] = [row_len * gamma[a] for row_len in rp._list] riggings[k] = [rig_val * gamma[a] for rig_val in rp.rigging] - return self.virtual.element_class(self.virtual, partition_list=partitions, - rigging_list=riggings) + return self.virtual.element_class(self.virtual, partition_list=partitions, rigging_list=riggings) def from_virtual(self, vrc): """ @@ -495,8 +495,7 @@ def from_virtual(self, vrc): index = vindex.index(sigma[a][0]) partitions[a] = [row_len // gamma[a] for row_len in vrc[index]._list] riggings[a] = [rig_val / gamma[a] for rig_val in vrc[index].rigging] - return self.element_class(self, partition_list=partitions, - rigging_list=riggings) + return self.element_class(self, partition_list=partitions, rigging_list=riggings) class Element(RCNonSimplyLacedElement): r""" diff --git a/src/sage/combinat/rigged_configurations/rigged_configuration_element.py b/src/sage/combinat/rigged_configurations/rigged_configuration_element.py index 3dded60745f..3e2bdb1fab1 100644 --- a/src/sage/combinat/rigged_configurations/rigged_configuration_element.py +++ b/src/sage/combinat/rigged_configurations/rigged_configuration_element.py @@ -37,6 +37,7 @@ # Base classes for rigged configuration elements # #################################################### + class RiggedConfigurationElement(ClonableArray): """ A rigged configuration for simply-laced types. @@ -212,8 +213,7 @@ def __init__(self, parent, rigged_partitions=[], **options): raise ValueError("incorrect number of riggings") for i in range(n): - nu.append(RiggedPartition(tuple(data[i]), - list(rigging_data[i]))) + nu.append(RiggedPartition(tuple(data[i]), list(rigging_data[i]))) else: for partition_data in data: nu.append(RiggedPartition(tuple(partition_data))) @@ -351,11 +351,11 @@ def _repr_horizontal(self): for i in range(height): if i != 0: ret_str += '\n' - for j,t in enumerate(tab_str): + for j, t in enumerate(tab_str): if j != 0: ret_str += ' ' if i < len(t): - ret_str += t[i] + ' ' * (widths[j]-len(t[i])) + ret_str += t[i] + ' ' * (widths[j] - len(t[i])) else: ret_str += ' ' * widths[j] return ret_str @@ -445,11 +445,13 @@ def _ascii_art_(self): sage: Partitions.options._reset() """ from sage.combinat.partition import Partitions + if Partitions.options.convention == "French": baseline = lambda s: 0 else: baseline = len from sage.typeset.ascii_art import AsciiArt + s = repr(self[0]).splitlines() ret = AsciiArt(s, baseline=baseline(s)) for tableau in self[1:]: @@ -537,10 +539,10 @@ def e(self, a): new_rigging = self[a].rigging[:] # Separate out one of the Borcherds cases - if M[a,a] != 2: + if M[a, a] != 2: k = None set_vac_num = True - if new_rigging[-1] != -M[a,a] // 2: + if new_rigging[-1] != -M[a, a] // 2: return None new_list.pop() new_vac_nums.pop() @@ -570,18 +572,17 @@ def e(self, a): new_rigging.pop() else: new_list[rigging_index] -= 1 - cur_rigging += M[a,a] // 2 + cur_rigging += M[a, a] // 2 # Properly sort the riggings j = rigging_index + 1 # Update the vacancy number if the row lengths are the same if j < num_rows and new_list[j] == new_list[rigging_index]: new_vac_nums[rigging_index] = new_vac_nums[j] set_vac_num = True - while j < num_rows and new_list[j] == new_list[rigging_index] \ - and new_rigging[j] > cur_rigging: - new_rigging[j-1] = new_rigging[j] # Shuffle it along + while j < num_rows and new_list[j] == new_list[rigging_index] and new_rigging[j] > cur_rigging: + new_rigging[j - 1] = new_rigging[j] # Shuffle it along j += 1 - new_rigging[j-1] = cur_rigging + new_rigging[j - 1] = cur_rigging new_partitions = [] for b in range(len(self)): @@ -593,20 +594,19 @@ def e(self, a): if k is not None and new_list[i] < k: break - new_vac_nums[i] += M[a,b] - new_rigging[i] += M[a,b] + new_vac_nums[i] += M[a, b] + new_rigging[i] += M[a, b] - if k != 1 and not set_vac_num: # If we did not remove a row nor found another row of length k-1 + if k != 1 and not set_vac_num: # If we did not remove a row nor found another row of length k-1 new_vac_nums[rigging_index] += 2 new_partitions.append(RiggedPartition(new_list, new_rigging, new_vac_nums)) ret_RC = self.__class__(self.parent(), new_partitions, use_vacancy_numbers=True) nu = ret_RC.nu() - if k != 1 and not set_vac_num: # If we did not remove a row nor found another row of length k-1 + if k != 1 and not set_vac_num: # If we did not remove a row nor found another row of length k-1 # Update that row's vacancy number - ret_RC[a].vacancy_numbers[rigging_index] = \ - self.parent()._calc_vacancy_number(nu, a, nu[a][rigging_index]) + ret_RC[a].vacancy_numbers[rigging_index] = self.parent()._calc_vacancy_number(nu, a, nu[a][rigging_index]) return ret_RC def _generate_partition_e(self, a, b, k): @@ -631,7 +631,7 @@ def _generate_partition_e(self, a, b, k): """ # Check to make sure we will do something - if not self.parent()._cartan_matrix[a,b]: + if not self.parent()._cartan_matrix[a, b]: return self[b] new_list = self[b]._list @@ -639,7 +639,7 @@ def _generate_partition_e(self, a, b, k): new_rigging = self[b].rigging[:] # Update the vacancy numbers and the rigging - value = self.parent()._cartan_matrix[b,a] + value = self.parent()._cartan_matrix[b, a] for i in range(len(new_vac_nums)): if k is not None and new_list[i] < k: break @@ -707,15 +707,15 @@ def f(self, a): # Find k and perform f_a k = None - add_index = -1 # Index where we will add our row too - rigging_index = None # Index which we will pull the rigging from + add_index = -1 # Index where we will add our row too + rigging_index = None # Index which we will pull the rigging from cur_rigging = ZZ.zero() num_rows = len(new_list) for i in reversed(range(num_rows)): # If we need to increment a row, look for when we change rows for # the correct index. if add_index is None and new_list[i] != new_list[rigging_index]: - add_index = i+1 + add_index = i + 1 if new_rigging[i] <= cur_rigging: cur_rigging = new_rigging[i] @@ -726,18 +726,18 @@ def f(self, a): # If we've not found a valid k if k is None: new_list.append(1) - new_rigging.append(-M[a,a] // 2) + new_rigging.append(-M[a, a] // 2) new_vac_nums.append(None) k = 0 add_index = num_rows - num_rows += 1 # We've added a row + num_rows += 1 # We've added a row else: - if add_index is None: # We are adding to the first row in the list + if add_index is None: # We are adding to the first row in the list add_index = 0 new_list[add_index] += 1 - new_rigging.insert(add_index, new_rigging[rigging_index] - M[a,a] // 2) + new_rigging.insert(add_index, new_rigging[rigging_index] - M[a, a] // 2) new_vac_nums.insert(add_index, None) - new_rigging.pop(rigging_index + 1) # add 1 for the insertion + new_rigging.pop(rigging_index + 1) # add 1 for the insertion new_vac_nums.pop(rigging_index + 1) new_partitions = [] @@ -751,14 +751,12 @@ def f(self, a): break if i != add_index: - new_vac_nums[i] -= M[a,b] - new_rigging[i] -= M[a,b] + new_vac_nums[i] -= M[a, b] + new_rigging[i] -= M[a, b] new_partitions.append(RiggedPartition(new_list, new_rigging, new_vac_nums)) - new_partitions[a].vacancy_numbers[add_index] = \ - self.parent()._calc_vacancy_number(new_partitions, a, - new_partitions[a][add_index]) + new_partitions[a].vacancy_numbers[add_index] = self.parent()._calc_vacancy_number(new_partitions, a, new_partitions[a][add_index]) # Note that we do not need to sort the rigging since if there was a # smaller rigging in a larger row, then `k` would be larger. @@ -786,7 +784,7 @@ def _generate_partition_f(self, a, b, k): """ # Check to make sure we will do something - if not self.parent()._cartan_matrix[a,b]: + if not self.parent()._cartan_matrix[a, b]: return self[b] new_list = self[b]._list @@ -794,7 +792,7 @@ def _generate_partition_f(self, a, b, k): new_rigging = self[b].rigging[:] # Update the vacancy numbers and the rigging - value = self.parent()._cartan_matrix[b,a] + value = self.parent()._cartan_matrix[b, a] for i in range(len(new_vac_nums)): if new_list[i] <= k: break @@ -984,7 +982,7 @@ def e(self, a): L = [] gamma = vct.scaling_factors() for i in vct.folding_orbit()[a]: - L.extend([i]*gamma[a]) + L.extend([i] * gamma[a]) virtual_rc = self.parent().to_virtual(self).e_string(L) if virtual_rc is None: return None @@ -1021,12 +1019,13 @@ def f(self, a): L = [] gamma = vct.scaling_factors() for i in vct.folding_orbit()[a]: - L.extend([i]*gamma[a]) + L.extend([i] * gamma[a]) virtual_rc = self.parent().to_virtual(self).f_string(L) if virtual_rc is None: return None return self.parent().from_virtual(virtual_rc) + ########################################################## # Highest weight crystal rigged configuration elements # ########################################################## @@ -1133,7 +1132,7 @@ def weight(self): """ P = self.parent().weight_lattice_realization() alpha = list(P.simple_roots()) - return self.parent()._wt - sum(sum(x) * alpha[i] for i,x in enumerate(self)) + return self.parent()._wt - sum(sum(x) * alpha[i] for i, x in enumerate(self)) class RCHWNonSimplyLacedElement(RCNonSimplyLacedElement): @@ -1213,7 +1212,8 @@ def weight(self): """ P = self.parent().weight_lattice_realization() alpha = list(P.simple_roots()) - return self.parent()._wt - sum(sum(x) * alpha[i] for i,x in enumerate(self)) + return self.parent()._wt - sum(sum(x) * alpha[i] for i, x in enumerate(self)) + ############################################## # KR crystal rigged configuration elements # @@ -1294,8 +1294,7 @@ def __init__(self, parent, rigged_partitions=[], **options): shape_data = data[0] rigging_data = data[1] vac_data = data[2] - nu = [RiggedPartition(a, b, c) - for a, b, c in zip(shape_data, rigging_data, vac_data)] + nu = [RiggedPartition(a, b, c) for a, b, c in zip(shape_data, rigging_data, vac_data)] # Special display case if parent.cartan_type().type() == 'B': nu[-1] = RiggedPartitionTypeB(nu[-1]) @@ -1534,7 +1533,7 @@ def classical_weight(self): else: WLR = F.ambient_space() La = WLR.fundamental_weights() - wt = WLR.sum(La[r] * s for r,s in self.parent().dims) + wt = WLR.sum(La[r] * s for r, s in self.parent().dims) alpha = WLR.simple_roots() rc_index = self.parent()._rc_index @@ -1627,6 +1626,7 @@ def to_tensor_product_of_kirillov_reshetikhin_tableaux(self, display_steps=False sage: view(G) # not tested """ from sage.combinat.rigged_configurations.bijection import RCToKRTBijection + bij = RCToKRTBijection(self) ret = bij.run(display_steps, build_graph) if build_graph: @@ -1714,12 +1714,13 @@ def left_split(self): P = self.parent() if P.dims[0][1] == 1: raise ValueError("cannot split a single column") - r,s = P.dims[0] - B = [[r,1], [r,s-1]] + r, s = P.dims[0] + B = [[r, 1], [r, s - 1]] B.extend(P.dims[1:]) from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations + RC = RiggedConfigurations(P._cartan_type, B) - return RC(*[x._clone() for x in self]) # Make a deep copy + return RC(*[x._clone() for x in self]) # Make a deep copy def right_split(self): r""" @@ -1822,6 +1823,7 @@ def left_box(self, return_b=False): raise ValueError("only for non-spinor cases") from sage.combinat.rigged_configurations.bijection import RCToKRTBijection + rc = self if P.dims[0][1] != 1: rc = self.left_split() @@ -1832,10 +1834,12 @@ def left_box(self, return_b=False): if bij.cur_dims[0][0] == 0: bij.cur_dims.pop(0) from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations + RC = RiggedConfigurations(ct, bij.cur_dims) rc = RC(*bij.cur_partitions) if return_b: from sage.combinat.crystals.letters import CrystalOfLetters + L = CrystalOfLetters(self.parent()._cartan_type.classical()) return (rc, L(b)) return rc @@ -1891,14 +1895,15 @@ def left_column_box(self): if P.dims[0][1] > 1: return self.left_split().left_column_box() - B = [[1,1], [r-1,1]] + B = [[1, 1], [r - 1, 1]] B.extend(P.dims[1:]) from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations + RC = RiggedConfigurations(P._cartan_type, B) - parts = [x._clone() for x in self] # Make a deep copy - for nu in parts[:r-1]: + parts = [x._clone() for x in self] # Make a deep copy + for nu in parts[: r - 1]: nu._list.append(1) - for a, nu in enumerate(parts[:r-1]): + for a, nu in enumerate(parts[: r - 1]): vac_num = RC._calc_vacancy_number(parts, a, 1) i = nu._list.index(1) nu.vacancy_numbers.insert(i, vac_num) @@ -1949,13 +1954,14 @@ def right_column_box(self): rc, e_string = self.to_highest_weight(P._rc_index) - B = P.dims[:-1] + ([r-1,1], [1,1]) + B = P.dims[:-1] + ([r - 1, 1], [1, 1]) from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations + RC = RiggedConfigurations(P._cartan_type, B) - parts = [x._clone() for x in rc] # Make a deep copy - for nu in parts[:r-1]: + parts = [x._clone() for x in rc] # Make a deep copy + for nu in parts[: r - 1]: nu._list.append(1) - for a, nu in enumerate(parts[:r-1]): + for a, nu in enumerate(parts[: r - 1]): vac_num = RC._calc_vacancy_number(parts, a, -1) nu.vacancy_numbers.append(vac_num) nu.rigging.append(0) @@ -2033,17 +2039,18 @@ def complement_rigging(self, reverse_factors=False): P = self.parent() if reverse_factors: from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations + P = RiggedConfigurations(P._cartan_type, reversed(P.dims)) mg, e_str = self.to_highest_weight(P._rc_index) nu = [] rig = [] - for a,p in enumerate(mg): + for a, p in enumerate(mg): nu.append(list(p)) vac_nums = p.vacancy_numbers - riggings = [vac - p.rigging[i] for i,vac in enumerate(vac_nums)] + riggings = [vac - p.rigging[i] for i, vac in enumerate(vac_nums)] block = 0 - for j,i in enumerate(p): + for j, i in enumerate(p): if p[block] != i: riggings[block:j] = sorted(riggings[block:j], reverse=True) block = j @@ -2071,6 +2078,7 @@ class KRRCSimplyLacedElement(KRRiggedConfigurationElement): sage: TestSuite(elt).run() """ + @cached_method def cocharge(self): r""" @@ -2267,7 +2275,7 @@ def cocharge(self): sigma = vct.folding_orbit() gamma = vct.scaling_factors() for a, p in enumerate(self): - t_check = len(sigma[a + 1]) * gamma[a+1] // gamma[0] + t_check = len(sigma[a + 1]) * gamma[a + 1] // gamma[0] for pos, i in enumerate(p._list): # Add the rigging rigging_sum += t_check * p.rigging[pos] @@ -2317,7 +2325,7 @@ def epsilon(self, a): else: epsilon = -min(0, *self[a].rigging) n = len(self.parent()._rc_index) - if a == n-1: # -1 for indexing + if a == n - 1: # -1 for indexing epsilon *= 2 return Integer(epsilon) @@ -2351,7 +2359,7 @@ def phi(self, a): else: phi = p_inf - min(0, *self[a].rigging) n = len(self.parent()._rc_index) - if a == n-1: # -1 for indexing + if a == n - 1: # -1 for indexing phi *= 2 return Integer(phi) diff --git a/src/sage/combinat/rigged_configurations/rigged_configurations.py b/src/sage/combinat/rigged_configurations/rigged_configurations.py index 1e6c2ed1b79..29c6d4254e3 100644 --- a/src/sage/combinat/rigged_configurations/rigged_configurations.py +++ b/src/sage/combinat/rigged_configurations/rigged_configurations.py @@ -35,9 +35,7 @@ from sage.categories.loop_crystals import KirillovReshetikhinCrystals from sage.combinat.root_system.cartan_type import CartanType from sage.combinat.rigged_configurations.kleber_tree import KleberTree, VirtualKleberTree -from sage.combinat.rigged_configurations.rigged_configuration_element import ( - RiggedConfigurationElement, KRRCSimplyLacedElement, KRRCNonSimplyLacedElement, - KRRCTypeA2DualElement) +from sage.combinat.rigged_configurations.rigged_configuration_element import RiggedConfigurationElement, KRRCSimplyLacedElement, KRRCNonSimplyLacedElement, KRRCTypeA2DualElement from sage.combinat.rigged_configurations.rigged_partition import RiggedPartition @@ -327,6 +325,7 @@ class RiggedConfigurations(UniqueRepresentation, Parent): sage: K.cardinality() == c True """ + @staticmethod def __classcall_private__(cls, cartan_type, B): r""" @@ -349,9 +348,9 @@ def __classcall_private__(cls, cartan_type, B): if not B: raise ValueError("must contain at least one factor") - if cartan_type.type() == 'BC': # Type `A_{2n}^{(2)}` + if cartan_type.type() == 'BC': # Type `A_{2n}^{(2)}` return RCTypeA2Even(cartan_type, B) - if cartan_type.dual().type() == 'BC': # Type 'A_{2n}^{(2)\dagger` + if cartan_type.dual().type() == 'BC': # Type 'A_{2n}^{(2)\dagger` return RCTypeA2Dual(cartan_type, B) # We check the classical type to account for A^{(1)}_1 which is not # a virtual rigged configuration. @@ -383,7 +382,7 @@ def __init__(self, cartan_type, B): self.dims = B cl = cartan_type.classical() self._rc_index = cl.index_set() - self._rc_index_inverse = {i: ii for ii,i in enumerate(self._rc_index)} + self._rc_index_inverse = {i: ii for ii, i in enumerate(self._rc_index)} # We store the Cartan matrix for the vacancy number calculations for speed self._cartan_matrix = cl.cartan_matrix() Parent.__init__(self, category=KirillovReshetikhinCrystals().TensorProducts()) @@ -435,20 +434,13 @@ class options(GlobalOptions): 4 5 sage: RiggedConfigurations.options._reset() """ + NAME = 'RiggedConfigurations' module = 'sage.combinat.rigged_configurations.rigged_configurations' - display = dict(default='vertical', - description='Specifies how rigged configurations should be printed', - values=dict(vertical='displayed vertically', - horizontal='displayed horizontally'), - case_sensitive=False) - element_ascii_art = dict(default=True, - description='display using the repr option ``element_ascii_art``', - checker=lambda x: isinstance(x, bool)) - half_width_boxes_type_B = dict(default=True, - description='display the last rigged partition in affine type B as half width boxes', - checker=lambda x: isinstance(x, bool)) - convention = dict(link_to=(tableau.Tableaux.options,'convention')) + display = dict(default='vertical', description='Specifies how rigged configurations should be printed', values=dict(vertical='displayed vertically', horizontal='displayed horizontally'), case_sensitive=False) + element_ascii_art = dict(default=True, description='display using the repr option ``element_ascii_art``', checker=lambda x: isinstance(x, bool)) + half_width_boxes_type_B = dict(default=True, description='display the last rigged partition in affine type B as half width boxes', checker=lambda x: isinstance(x, bool)) + convention = dict(link_to=(tableau.Tableaux.options, 'convention')) notation = dict(alt_name='convention') def _repr_(self): @@ -491,9 +483,8 @@ def __iter__(self): """ index_set = self._rc_index from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet - return RecursivelyEnumeratedSet(self.module_generators, - lambda x: [x.f(i) for i in index_set], - structure='graded').breadth_first_search_iterator() + + return RecursivelyEnumeratedSet(self.module_generators, lambda x: [x.f(i) for i in index_set], structure='graded').breadth_first_search_iterator() @lazy_attribute def module_generators(self): @@ -548,7 +539,7 @@ def module_generators(self): for tree_node in self.kleber_tree(): shapes = [] cur = tree_node - path_lambda = [cur.up_root.to_vector()] # Build the lambda values + path_lambda = [cur.up_root.to_vector()] # Build the lambda values # Note that these are not same lambda as in the paper, # but a less computational version. while cur.parent_node is not None: @@ -597,9 +588,7 @@ def module_generators(self): C = itertools.product(*L) for curBlocks in C: - module_gens.append(self.element_class(self, KT_constructor=[shapes[:], - self._blocks_to_values(curBlocks[:]), - vac_nums[:]])) + module_gens.append(self.element_class(self, KT_constructor=[shapes[:], self._blocks_to_values(curBlocks[:]), vac_nums[:]])) return tuple(module_gens) @@ -666,7 +655,7 @@ def _blocks_to_values(self, blocks): if not part_block: values.append([]) else: - values.append(part_block[0][:]) # Need to make a copy + values.append(part_block[0][:]) # Need to make a copy for block in part_block[1:]: values[-1].extend(block) return values @@ -747,15 +736,18 @@ def _element_constructor_(self, *lst, **options): return self.element_class(self, [], **options) from sage.combinat.rigged_configurations.tensor_product_kr_tableaux_element import TensorProductOfKirillovReshetikhinTableauxElement + if isinstance(lst[0], TensorProductOfKirillovReshetikhinTableauxElement): if self != lst[0].parent().rigged_configurations(): raise ValueError("incorrect bijection image") return lst[0].to_rigged_configuration() from sage.combinat.crystals.tensor_product import TensorProductOfRegularCrystalsElement + if isinstance(lst[0], TensorProductOfRegularCrystalsElement): lst = lst[0] from sage.combinat.crystals.kirillov_reshetikhin import KirillovReshetikhinGenericCrystalElement + if isinstance(lst[0], KirillovReshetikhinGenericCrystalElement): KRT = self.tensor_product_of_kirillov_reshetikhin_tableaux() krt_elt = KRT(*[x.to_kirillov_reshetikhin_tableau() for x in lst]) @@ -765,9 +757,9 @@ def _element_constructor_(self, *lst, **options): lst = lst[0] if isinstance(lst[0], RiggedPartition): - lst = [p._clone() for p in lst] # Make a deep copy + lst = [p._clone() for p in lst] # Make a deep copy elif isinstance(lst[0], RiggedConfigurationElement): - lst = [p._clone() for p in lst[0]] # Make a deep copy + lst = [p._clone() for p in lst[0]] # Make a deep copy return self.element_class(self, list(lst), **options) @@ -813,11 +805,9 @@ def _calc_vacancy_number(self, partitions, a, i, **options): vac_num += min(dim[1], i) if i == float('inf'): - vac_num -= sum(self._cartan_matrix[a,b] * sum(nu) - for b,nu in enumerate(partitions)) + vac_num -= sum(self._cartan_matrix[a, b] * sum(nu) for b, nu in enumerate(partitions)) else: - vac_num -= sum(self._cartan_matrix[a,b] * nu.get_num_cells_to_column(i) - for b,nu in enumerate(partitions)) + vac_num -= sum(self._cartan_matrix[a, b] * nu.get_num_cells_to_column(i) for b, nu in enumerate(partitions)) return vac_num @@ -847,6 +837,7 @@ def tensor_product_of_kirillov_reshetikhin_tableaux(self): Tensor product of Kirillov-Reshetikhin tableaux of type ['A', 3, 1] and factor(s) ((3, 2), (1, 2)) """ from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux + return TensorProductOfKirillovReshetikhinTableaux(self._cartan_type, self.dims) @cached_method @@ -996,6 +987,7 @@ def fermionic_formula(self, q=None, only_highest_weight=False, weight=None): """ if q is None: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + q = PolynomialRing(QQ, 'q').gen(0) if only_highest_weight: @@ -1008,10 +1000,10 @@ def fermionic_formula(self, q=None, only_highest_weight=False, weight=None): if weight is not None: weight = WLR(weight) - return P.sum(q**x.cc() for x in L if WLR(x.weight()) == weight) + return P.sum(q ** x.cc() for x in L if WLR(x.weight()) == weight) B = WLR.algebra(P) - return B.sum(q**x.cc() * B(WLR(x.weight())) for x in L) + return B.sum(q ** x.cc() * B(WLR(x.weight())) for x in L) def _test_bijection(self, **options): r""" @@ -1076,6 +1068,7 @@ class RCNonSimplyLaced(RiggedConfigurations): For more on rigged configurations, see :class:`RiggedConfigurations`. """ + @staticmethod def __classcall_private__(cls, cartan_type, B): r""" @@ -1154,14 +1147,10 @@ def _calc_vacancy_number(self, partitions, a, i, **options): vac_num += min(dim[1], i) if i == float('inf'): - vac_num -= sum(self._cartan_matrix[a,b] * sum(nu) - for b,nu in enumerate(partitions)) + vac_num -= sum(self._cartan_matrix[a, b] * sum(nu) for b, nu in enumerate(partitions)) else: gamma = self._folded_ct.scaling_factors() - vac_num -= sum(self._cartan_matrix[a,b] - * nu.get_num_cells_to_column(gamma[a+1]*i, gamma[b+1]) - // gamma[b+1] - for b,nu in enumerate(partitions)) + vac_num -= sum(self._cartan_matrix[a, b] * nu.get_num_cells_to_column(gamma[a + 1] * i, gamma[b + 1]) // gamma[b + 1] for b, nu in enumerate(partitions)) return vac_num @@ -1211,7 +1200,7 @@ def module_generators(self): for tree_node in self.kleber_tree(): shapes = [] cur = tree_node - path_lambda = [cur.up_root.to_vector()] # Build the lambda values + path_lambda = [cur.up_root.to_vector()] # Build the lambda values # Note that these are not same lambda as in the paper, # but a less computational version. while cur.parent_node is not None: @@ -1231,7 +1220,7 @@ def module_generators(self): shapes = [shapes[vindex.index(sigma[a][0])] for a in self._rc_index] if self._cartan_type.type() != 'BC': gamma = self._folded_ct.scaling_factors() - for a,shape in enumerate(shapes): + for a, shape in enumerate(shapes): for i in range(len(shape)): shape[i] = shape[i] // gamma[self._rc_index[a]] @@ -1271,8 +1260,7 @@ def module_generators(self): C = itertools.product(*L) for cur_blocks in C: - module_gens.append(self.element_class(self, KT_constructor=[shapes[:], - self._blocks_to_values(cur_blocks[:]), vac_nums[:]])) + module_gens.append(self.element_class(self, KT_constructor=[shapes[:], self._blocks_to_values(cur_blocks[:]), vac_nums[:]])) return tuple(module_gens) @@ -1305,9 +1293,9 @@ def virtual(self): gamma = self._folded_ct.scaling_factors() sigma = self._folded_ct.folding_orbit() virtual_dims = [] - for r,s in self.dims: + for r, s in self.dims: for a in sigma[r]: - virtual_dims.append([a, s*gamma[r]]) + virtual_dims.append([a, s * gamma[r]]) return RiggedConfigurations(self._folded_ct._folding, virtual_dims) def to_virtual(self, rc): @@ -1341,12 +1329,10 @@ def to_virtual(self, rc): n = len(self.virtual._rc_index) # +/- 1 for indexing partitions = [None] * n - for a,rp in enumerate(rc): - g = gamma[a+1] - for i in sigma[a+1]: - partitions[i-1] = RiggedPartition([row_len*g for row_len in rp._list], - [rig_val*g for rig_val in rp.rigging], - [vac_num*g for vac_num in rp.vacancy_numbers]) + for a, rp in enumerate(rc): + g = gamma[a + 1] + for i in sigma[a + 1]: + partitions[i - 1] = RiggedPartition([row_len * g for row_len in rp._list], [rig_val * g for rig_val in rp.rigging], [vac_num * g for vac_num in rp.vacancy_numbers]) return self.virtual.element_class(self.virtual, partitions, use_vacancy_numbers=True) def from_virtual(self, vrc): @@ -1377,11 +1363,9 @@ def from_virtual(self, vrc): partitions = [None] * n # +/- 1 for indexing for a in range(n): - rp = vrc[sigma[a+1][0] - 1] - g = gamma[a+1] - partitions[a] = RiggedPartition([row_len//g for row_len in rp._list], - [rig_val//g for rig_val in rp.rigging], - [vac_val//g for vac_val in rp.vacancy_numbers]) + rp = vrc[sigma[a + 1][0] - 1] + g = gamma[a + 1] + partitions[a] = RiggedPartition([row_len // g for row_len in rp._list], [rig_val // g for rig_val in rp.rigging], [vac_val // g for vac_val in rp.vacancy_numbers]) return self.element_class(self, partitions, use_vacancy_numbers=True) def _test_virtual_vacancy_numbers(self, **options): @@ -1401,9 +1385,7 @@ def _test_virtual_vacancy_numbers(self, **options): elt = self.element_class(self, partition_list=parts_list) for i, p in enumerate(elt): for j, vac_num in enumerate(p.vacancy_numbers): - tester.assertEqual(vac_num, x[i].vacancy_numbers[j], - "Incorrect vacancy number: {}\nComputed: {}\nFor: {}".format( - x[i].vacancy_numbers[j], vac_num, x)) + tester.assertEqual(vac_num, x[i].vacancy_numbers[j], "Incorrect vacancy number: {}\nComputed: {}\nFor: {}".format(x[i].vacancy_numbers[j], vac_num, x)) Element = KRRCNonSimplyLacedElement @@ -1456,7 +1438,7 @@ def virtual(self): sigma = self._folded_ct.folding_orbit() n = len(sigma) - 1 virtual_dims = [] - for r,s in self.dims: + for r, s in self.dims: if r == n: virtual_dims.extend([[n, s], [n, s]]) else: @@ -1506,11 +1488,9 @@ def _calc_vacancy_number(self, partitions, a, i, **options): gamma = self._folded_ct.scaling_factors() if i == float('inf'): - vac_num -= sum(self._cartan_matrix[a,b] * sum(nu) // gamma[b+1] - for b, nu in enumerate(partitions)) + vac_num -= sum(self._cartan_matrix[a, b] * sum(nu) // gamma[b + 1] for b, nu in enumerate(partitions)) else: - vac_num -= sum(self._cartan_matrix[a,b] * nu.get_num_cells_to_column(i) // gamma[b+1] - for b, nu in enumerate(partitions)) + vac_num -= sum(self._cartan_matrix[a, b] * nu.get_num_cells_to_column(i) // gamma[b + 1] for b, nu in enumerate(partitions)) return vac_num @@ -1546,12 +1526,10 @@ def to_virtual(self, rc): sigma = self._folded_ct.folding_orbit() n = len(self.virtual._rc_index) partitions = [None] * n - for a,rp in enumerate(rc): - g = gamma[a+1] - for i in sigma[a+1]: - partitions[i-1] = RiggedPartition(list(rp._list), - [rig_val*g for rig_val in rp.rigging], - [vac_num*g for vac_num in rp.vacancy_numbers]) + for a, rp in enumerate(rc): + g = gamma[a + 1] + for i in sigma[a + 1]: + partitions[i - 1] = RiggedPartition(list(rp._list), [rig_val * g for rig_val in rp.rigging], [vac_num * g for vac_num in rp.vacancy_numbers]) return self.virtual.element_class(self.virtual, partitions, use_vacancy_numbers=True) def from_virtual(self, vrc): @@ -1583,11 +1561,9 @@ def from_virtual(self, vrc): partitions = [None] * n # +/- 1 for indexing for a in range(n): - rp = vrc[sigma[a+1][0] - 1] - g = gamma[a+1] - partitions[a] = RiggedPartition(list(rp._list), - [rig_val//g for rig_val in rp.rigging], - [vac_val//g for vac_val in rp.vacancy_numbers]) + rp = vrc[sigma[a + 1][0] - 1] + g = gamma[a + 1] + partitions[a] = RiggedPartition(list(rp._list), [rig_val // g for rig_val in rp.rigging], [vac_val // g for vac_val in rp.vacancy_numbers]) return self.element_class(self, partitions, use_vacancy_numbers=True) @@ -1658,11 +1634,9 @@ def _calc_vacancy_number(self, partitions, a, i, **options): vac_num += min(dim[1], i) if i == float('inf'): - vac_num -= sum(self._cartan_matrix[a,b] * sum(nu) / 2 - for b,nu in enumerate(partitions)) + vac_num -= sum(self._cartan_matrix[a, b] * sum(nu) / 2 for b, nu in enumerate(partitions)) else: - vac_num -= sum(self._cartan_matrix[a,b] * nu.get_num_cells_to_column(i) / 2 - for b,nu in enumerate(partitions)) + vac_num -= sum(self._cartan_matrix[a, b] * nu.get_num_cells_to_column(i) / 2 for b, nu in enumerate(partitions)) return vac_num @@ -1695,7 +1669,7 @@ def module_generators(self): for tree_node in self.kleber_tree(): shapes = [] cur = tree_node - path_lambda = [cur.up_root.to_vector()] # Build the lambda values + path_lambda = [cur.up_root.to_vector()] # Build the lambda values # Note that these are not same lambda as in the paper, # but a less computational version. while cur.parent_node is not None: @@ -1791,8 +1765,7 @@ def module_generators(self): C = itertools.product(*L) for curBlocks in C: - module_gens.append(self.element_class(self, KT_constructor=[shapes[:], - self._blocks_to_values(curBlocks[:]), vac_nums[:]])) + module_gens.append(self.element_class(self, KT_constructor=[shapes[:], self._blocks_to_values(curBlocks[:]), vac_nums[:]])) return tuple(module_gens) @@ -1828,7 +1801,7 @@ def _block_iterator_n_odd(self, container): while pos >= 0: ret_part[pos] += 2 - if ret_part[pos] > container[pos]*2 or (pos != 0 and ret_part[pos] > ret_part[pos - 1]): + if ret_part[pos] > container[pos] * 2 or (pos != 0 and ret_part[pos] > ret_part[pos - 1]): ret_part[pos] = -1 pos -= 1 else: @@ -1871,11 +1844,10 @@ def to_virtual(self, rc): sigma = self._folded_ct.folding_orbit() n = len(self.virtual._rc_index) partitions = [None] * n - for a,rp in enumerate(rc): - g = gammatilde[a+1] - for i in sigma[a+1]: - partitions[i-1] = RiggedPartition(list(rp._list), - [rig_val*g for rig_val in rp.rigging]) + for a, rp in enumerate(rc): + g = gammatilde[a + 1] + for i in sigma[a + 1]: + partitions[i - 1] = RiggedPartition(list(rp._list), [rig_val * g for rig_val in rp.rigging]) return self.virtual.element_class(self.virtual, partitions) def from_virtual(self, vrc): @@ -1908,10 +1880,9 @@ def from_virtual(self, vrc): partitions = [None] * n # +/- 1 for indexing for a in range(n): - rp = vrc[sigma[a+1][0] - 1] - g = gammatilde[a+1] - partitions[a] = RiggedPartition(list(rp._list), - [rig_val/g for rig_val in rp.rigging]) + rp = vrc[sigma[a + 1][0] - 1] + g = gammatilde[a + 1] + partitions[a] = RiggedPartition(list(rp._list), [rig_val / g for rig_val in rp.rigging]) return self.element_class(self, partitions) Element = KRRCTypeA2DualElement diff --git a/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py b/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py index b00e3d71b14..5c9946ee2d9 100644 --- a/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py +++ b/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py @@ -68,10 +68,8 @@ from sage.combinat.crystals.letters import CrystalOfLetters from sage.combinat.root_system.cartan_type import CartanType -from sage.combinat.rigged_configurations.tensor_product_kr_tableaux_element \ - import TensorProductOfKirillovReshetikhinTableauxElement -from sage.combinat.rigged_configurations.kr_tableaux import KirillovReshetikhinTableaux, \ - KirillovReshetikhinTableauxElement +from sage.combinat.rigged_configurations.tensor_product_kr_tableaux_element import TensorProductOfKirillovReshetikhinTableauxElement +from sage.combinat.rigged_configurations.kr_tableaux import KirillovReshetikhinTableaux, KirillovReshetikhinTableauxElement from sage.rings.integer import Integer @@ -114,8 +112,7 @@ def __getitem__(self, i): [[1], [2], [3]] (X) [[1], [2]] """ if self._cache is None: - self._cache = tuple([x.to_tensor_product_of_kirillov_reshetikhin_tableaux() - for x in self.tp_krt.rigged_configurations().module_generators]) + self._cache = tuple([x.to_tensor_product_of_kirillov_reshetikhin_tableaux() for x in self.tp_krt.rigged_configurations().module_generators]) return self._cache[i] def __iter__(self): @@ -131,8 +128,7 @@ def __iter__(self): [[1], [-1]] """ if self._cache is None: - self._cache = tuple([x.to_tensor_product_of_kirillov_reshetikhin_tableaux() - for x in self.tp_krt.rigged_configurations().module_generators]) + self._cache = tuple([x.to_tensor_product_of_kirillov_reshetikhin_tableaux() for x in self.tp_krt.rigged_configurations().module_generators]) yield from self._cache def __repr__(self): @@ -276,6 +272,7 @@ class TensorProductOfKirillovReshetikhinTableaux(FullTensorProductOfRegularCryst sage: eltlong == elt True """ + @staticmethod def __classcall_private__(cls, cartan_type, B): """ @@ -315,13 +312,11 @@ def __init__(self, cartan_type, B): """ self.dims = B self.letters = CrystalOfLetters(cartan_type.classical()) - tensor_prod = tuple(KirillovReshetikhinTableaux(cartan_type, rect_dims[0], rect_dims[1]) - for rect_dims in B) + tensor_prod = tuple(KirillovReshetikhinTableaux(cartan_type, rect_dims[0], rect_dims[1]) for rect_dims in B) FullTensorProductOfRegularCrystals.__init__(self, tensor_prod, cartan_type=cartan_type) # This is needed to override the module_generators set in FullTensorProductOfRegularCrystals self.module_generators = HighestWeightTensorKRT(self) - self.rename("Tensor product of Kirillov-Reshetikhin tableaux " - f"of type {cartan_type} and factor(s) {B}") + self.rename("Tensor product of Kirillov-Reshetikhin tableaux " f"of type {cartan_type} and factor(s) {B}") def __iter__(self): """ @@ -338,9 +333,8 @@ def __iter__(self): """ index_set = self._cartan_type.classical().index_set() from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet - return RecursivelyEnumeratedSet(self.module_generators, - lambda x: [x.f(i) for i in index_set], - structure=None).naive_search_iterator() + + return RecursivelyEnumeratedSet(self.module_generators, lambda x: [x.f(i) for i in index_set], structure=None).naive_search_iterator() def _test_bijection(self, **options): r""" @@ -383,15 +377,17 @@ def _element_constructor_(self, *path, **options): return path[0] from sage.combinat.crystals.kirillov_reshetikhin import KirillovReshetikhinGenericCrystalElement + if isinstance(path[0], KirillovReshetikhinGenericCrystalElement): return self.element_class(self, [x.to_kirillov_reshetikhin_tableau() for x in path]) from sage.combinat.crystals.tensor_product import TensorProductOfRegularCrystalsElement - if isinstance(path[0], TensorProductOfRegularCrystalsElement) and \ - isinstance(path[0][0], KirillovReshetikhinGenericCrystalElement): + + if isinstance(path[0], TensorProductOfRegularCrystalsElement) and isinstance(path[0][0], KirillovReshetikhinGenericCrystalElement): return self.element_class(self, [x.to_kirillov_reshetikhin_tableau() for x in path[0]]) from sage.combinat.rigged_configurations.rigged_configuration_element import RiggedConfigurationElement + if isinstance(path[0], RiggedConfigurationElement): if self.rigged_configurations() != path[0].parent(): raise ValueError("incorrect bijection image") @@ -414,8 +410,7 @@ def _module_generators_brute_force(self): ([[1, 1, 1]] (X) [[1], [2]], [[1, 1, 3]] (X) [[1], [2]]) """ index_set = self.cartan_type().classical().index_set() - return tuple(x for x in FullTensorProductOfRegularCrystals.__iter__(self) - if x.is_highest_weight(index_set)) + return tuple(x for x in FullTensorProductOfRegularCrystals.__iter__(self) if x.is_highest_weight(index_set)) @cached_method def rigged_configurations(self): @@ -429,6 +424,7 @@ def rigged_configurations(self): Rigged configurations of type ['A', 3, 1] and factor(s) ((1, 3), (2, 1)) """ from sage.combinat.rigged_configurations.rigged_configurations import RiggedConfigurations + return RiggedConfigurations(self.cartan_type(), self.dims) @cached_method @@ -455,8 +451,7 @@ def tensor_product_of_kirillov_reshetikhin_crystals(self): sage: T is KRT.tensor_product_of_kirillov_reshetikhin_crystals() True """ - return FullTensorProductOfRegularCrystals(tuple(x.kirillov_reshetikhin_crystal() for x in self.crystals), - cartan_type=self.cartan_type()) + return FullTensorProductOfRegularCrystals(tuple(x.kirillov_reshetikhin_crystal() for x in self.crystals), cartan_type=self.cartan_type()) def tensor(self, *crystals, **options): """ @@ -483,8 +478,8 @@ def tensor(self, *crystals, **options): """ ct = self._cartan_type from sage.combinat.rigged_configurations.kr_tableaux import KirillovReshetikhinTableaux - if all(isinstance(B, (KirillovReshetikhinTableaux, TensorProductOfKirillovReshetikhinTableaux)) - and B.cartan_type() == ct for B in crystals): + + if all(isinstance(B, (KirillovReshetikhinTableaux, TensorProductOfKirillovReshetikhinTableaux)) and B.cartan_type() == ct for B in crystals): dims = list(self.dims) for B in crystals: if isinstance(B, TensorProductOfKirillovReshetikhinTableaux): diff --git a/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux_element.py b/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux_element.py index 48a8364275d..9c1504cdde5 100644 --- a/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux_element.py +++ b/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux_element.py @@ -140,8 +140,7 @@ def __init__(self, parent, list=[[]], **options): """ if "pathlist" in options: pathlist = options["pathlist"] - TensorProductOfRegularCrystalsElement.__init__(self, parent, - [parent.crystals[i](*tab) for i, tab in enumerate(pathlist)]) + TensorProductOfRegularCrystalsElement.__init__(self, parent, [parent.crystals[i](*tab) for i, tab in enumerate(pathlist)]) else: TensorProductOfRegularCrystalsElement.__init__(self, parent, list) @@ -182,7 +181,7 @@ def _repr_diagram(self): comp = [crys._repr_diagram().splitlines() for crys in self] num_comp = len(comp) # number of components col_len = [len(t) > 0 and len(t[0]) or 1 for t in comp] # columns per component - num_rows = max(len(t) for t in comp) # number of rows + num_rows = max(len(t) for t in comp) # number of rows # We take advantage of the fact the components are rectangular diag = '' @@ -244,8 +243,8 @@ def lusztig_involution(self): sage: li.parent() Tensor product of Kirillov-Reshetikhin tableaux of type ['A', 3, 1] and factor(s) ((1, 3), (2, 2)) """ - from sage.combinat.rigged_configurations.tensor_product_kr_tableaux \ - import TensorProductOfKirillovReshetikhinTableaux + from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux + P = self.parent() P = TensorProductOfKirillovReshetikhinTableaux(P._cartan_type, reversed(P.dims)) return P(*[x.lusztig_involution() for x in reversed(self)]) @@ -270,8 +269,8 @@ def left_split(self): r, s = P.dims[0] B = [[r, 1], [r, s - 1]] B.extend(P.dims[1:]) - from sage.combinat.rigged_configurations.tensor_product_kr_tableaux \ - import TensorProductOfKirillovReshetikhinTableaux + from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux + TP = TensorProductOfKirillovReshetikhinTableaux(P._cartan_type, B) x = self[0].left_split() return TP(*(list(x) + self[1:])) @@ -303,8 +302,8 @@ def right_split(self): B = list(P.dims[:-1]) B.append([r, s - 1]) B.append([r, 1]) - from sage.combinat.rigged_configurations.tensor_product_kr_tableaux \ - import TensorProductOfKirillovReshetikhinTableaux + from sage.combinat.rigged_configurations.tensor_product_kr_tableaux import TensorProductOfKirillovReshetikhinTableaux + TP = TensorProductOfKirillovReshetikhinTableaux(P._cartan_type, B) x = self[-1].right_split() return TP(*(self[:-1] + list(x))) @@ -397,6 +396,7 @@ def to_rigged_configuration(self, display_steps=False): True """ from sage.combinat.rigged_configurations.bijection import KRTToRCBijection + return KRTToRCBijection(self).run(display_steps) def to_tensor_product_of_kirillov_reshetikhin_crystals(self): diff --git a/src/sage/combinat/root_system/all.py b/src/sage/combinat/root_system/all.py index 3f5630ebab2..98e2c9a3c9b 100644 --- a/src/sage/combinat/root_system/all.py +++ b/src/sage/combinat/root_system/all.py @@ -115,32 +115,30 @@ - :ref:`sage.combinat.root_system.type_super_A` - :ref:`sage.combinat.root_system.type_A_infinity` """ + # install the docstring of this module to the containing package from sage.misc.namespace_package import install_doc + install_doc(__package__, __doc__) from sage.misc.lazy_import import lazy_import from sage.combinat.root_system.cartan_type import CartanType + lazy_import('sage.combinat.root_system.dynkin_diagram', 'DynkinDiagram') lazy_import('sage.combinat.root_system.cartan_matrix', 'CartanMatrix') lazy_import('sage.combinat.root_system.coxeter_matrix', 'CoxeterMatrix') from sage.combinat.root_system.coxeter_type import CoxeterType from sage.combinat.root_system.root_system import RootSystem, WeylDim -lazy_import('sage.combinat.root_system.weyl_group', ['WeylGroup', - 'WeylGroupElement']) -lazy_import('sage.combinat.root_system.reflection_group_real', - 'ReflectionGroup') -lazy_import('sage.combinat.root_system.extended_affine_weyl_group', - 'ExtendedAffineWeylGroup') + +lazy_import('sage.combinat.root_system.weyl_group', ['WeylGroup', 'WeylGroupElement']) +lazy_import('sage.combinat.root_system.reflection_group_real', 'ReflectionGroup') +lazy_import('sage.combinat.root_system.extended_affine_weyl_group', 'ExtendedAffineWeylGroup') lazy_import('sage.combinat.root_system.coxeter_group', 'CoxeterGroup') -lazy_import('sage.combinat.root_system.weyl_characters', ['WeylCharacterRing', - 'WeightRing']) +lazy_import('sage.combinat.root_system.weyl_characters', ['WeylCharacterRing', 'WeightRing']) from sage.combinat.root_system.branching_rules import BranchingRule, branching_rule_from_plethysm, branching_rule -lazy_import('sage.combinat.root_system.non_symmetric_macdonald_polynomials', - 'NonSymmetricMacdonaldPolynomials') -lazy_import('sage.combinat.root_system.integrable_representations', - 'IntegrableRepresentation') +lazy_import('sage.combinat.root_system.non_symmetric_macdonald_polynomials', 'NonSymmetricMacdonaldPolynomials') +lazy_import('sage.combinat.root_system.integrable_representations', 'IntegrableRepresentation') del lazy_import del install_doc diff --git a/src/sage/combinat/root_system/ambient_space.py b/src/sage/combinat/root_system/ambient_space.py index 03e749eff0f..1ed841a28bb 100644 --- a/src/sage/combinat/root_system/ambient_space.py +++ b/src/sage/combinat/root_system/ambient_space.py @@ -1,6 +1,7 @@ r""" Ambient lattices and ambient spaces """ + # *************************************************************************** # Copyright (C) 2008-2009 Daniel Bump # Copyright (C) 2008-2013 Nicolas M. Thiery @@ -89,10 +90,7 @@ def __init__(self, root_system, base_ring, index_set=None): self.root_system = root_system if index_set is None: index_set = tuple(range(self.dimension())) - CombinatorialFreeModule.__init__(self, base_ring, - index_set, - prefix='e', - category=WeightLatticeRealizations(base_ring)) + CombinatorialFreeModule.__init__(self, base_ring, index_set, prefix='e', category=WeightLatticeRealizations(base_ring)) coroot_lattice = self.root_system.coroot_lattice() coroot_lattice.module_morphism(self.simple_coroot, codomain=self).register_as_coercion() @@ -101,8 +99,8 @@ def __init__(self, root_system, base_ring, index_set=None): self.n = self.dimension() ct = root_system.cartan_type() if ct.is_irreducible() and ct.type() == 'E': - self._v0 = self([0,0,0,0,0, 0,1, 1]) - self._v1 = self([0,0,0,0,0,-2,1,-1]) + self._v0 = self([0, 0, 0, 0, 0, 0, 1, 1]) + self._v1 = self([0, 0, 0, 0, 0, -2, 1, -1]) def _test_norm_of_simple_roots(self, **options): """ @@ -125,7 +123,7 @@ def _test_norm_of_simple_roots(self, **options): except ImportError: # Dynkin diagrams need sage.graphs return for C in DD.connected_components(sort=False): - tester.assertEqual(len( set( alpha[i].scalar(alpha[i]) / D[i] for i in C ) ), 1) + tester.assertEqual(len(set(alpha[i].scalar(alpha[i]) / D[i] for i in C)), 1) # FIXME: attribute or method? def dimension(self): @@ -212,7 +210,7 @@ def __getitem__(self, i): """ if not (i > 0 and i <= self.dimension()): raise IndexError("value out of range") - return self.monomial(i-1) + return self.monomial(i - 1) def coroot_lattice(self): """ @@ -256,7 +254,7 @@ def reflection(self, root, coroot=None): """ # TODO: get rid of this as one can use the generic implementation # (i.e. scalar and associated coroot are implemented) - return lambda v: v - root.base_ring()(2*root.inner_product(v)/root.inner_product(root))*root + return lambda v: v - root.base_ring()(2 * root.inner_product(v) / root.inner_product(root)) * root @cached_method def fundamental_weight(self, i): @@ -400,9 +398,9 @@ def inner_product(self, lambdacheck): lambdacheck_mc = lambdacheck._monomial_coefficients result = self.parent().base_ring().zero() - for t,c in lambdacheck_mc.items(): + for t, c in lambdacheck_mc.items(): if t in self_mc: - result += c*self_mc[t] + result += c * self_mc[t] return result scalar = inner_product @@ -419,7 +417,7 @@ def associated_coroot(self): (1, -1, -1, -1) """ # FIXME: make it work over ZZ! - return self * self.base_ring()(2/self.inner_product(self)) + return self * self.base_ring()(2 / self.inner_product(self)) def is_positive_root(self): """ @@ -456,14 +454,14 @@ def coerce_to_sl(self): x = self if cartan_type.is_atomic(): if cartan_type.type() == 'A': - x = x - self.parent().det(sum(x.to_vector())/(self.parent().dimension())) + x = x - self.parent().det(sum(x.to_vector()) / (self.parent().dimension())) else: xv = x.to_vector() shifts = cartan_type._shifts types = cartan_type.component_types() for i in range(len(types)): if cartan_type.component_types()[i][0] == 'A': - s = self.parent().ambient_spaces()[i].det(sum(xv[shifts[i]:shifts[i+1]])/(types[i][1]+1)) + s = self.parent().ambient_spaces()[i].det(sum(xv[shifts[i] : shifts[i + 1]]) / (types[i][1] + 1)) x = x - self.parent().inject_weights(i, s) return x @@ -483,7 +481,7 @@ def coerce_to_e7(self): """ x = self v0 = self.parent()._v0 - ret = x - (x.inner_product(v0)/2)*v0 + ret = x - (x.inner_product(v0) / 2) * v0 return ret def coerce_to_e6(self): @@ -502,8 +500,8 @@ def coerce_to_e6(self): x = self v0 = self.parent()._v0 v1 = self.parent()._v1 - x = x - (x.inner_product(v0)/2)*v0 - return x - (x.inner_product(v1)/6)*v1 + x = x - (x.inner_product(v0) / 2) * v0 + return x - (x.inner_product(v1) / 6) * v1 def to_ambient(self): r""" diff --git a/src/sage/combinat/root_system/associahedron.py b/src/sage/combinat/root_system/associahedron.py index 5edda5e65d6..cb57168eb71 100644 --- a/src/sage/combinat/root_system/associahedron.py +++ b/src/sage/combinat/root_system/associahedron.py @@ -142,6 +142,7 @@ class Associahedron_class_base: Generalized associahedron of type ['A', 2] with 5 vertices sage: TestSuite(Asso).run() """ + def __new__(typ, parent=None, Vrep=None, Hrep=None, cartan_type=None, **kwds): r""" Return instance of :class:`Assciahedron_class_base`, if ``cartan_type`` is provided @@ -258,8 +259,7 @@ def vertices_in_root_space(self): -alpha[1], -alpha[2]) """ root_space = self._cartan_type.root_system().root_space() - return tuple(root_space.from_vector(vector(V)) - for V in self.vertex_generator()) + return tuple(root_space.from_vector(vector(V)) for V in self.vertex_generator()) class Associahedron_class_ppl(Associahedron_class_base, Polyhedron_QQ_ppl): @@ -372,8 +372,7 @@ def _element_constructor_(self, cartan_type, **kwds): raise ValueError("the Cartan type must be finite") root_space = cartan_type.root_system().root_space() # TODO: generalize this as a method of root lattice realization - rhocheck = sum(beta.associated_coroot() - for beta in root_space.positive_roots()) / 2 + rhocheck = sum(beta.associated_coroot() for beta in root_space.positive_roots()) / 2 I = root_space.index_set() inequalities = [] for orbit in root_space.almost_positive_roots_decomposition(): diff --git a/src/sage/combinat/root_system/braid_move_calculator.py b/src/sage/combinat/root_system/braid_move_calculator.py index d863ebe91a6..4b06e637be8 100644 --- a/src/sage/combinat/root_system/braid_move_calculator.py +++ b/src/sage/combinat/root_system/braid_move_calculator.py @@ -67,16 +67,14 @@ def partial_braid_word(length, swap=False, i=i, k=k): output_word_list = [current_last_word] for counter in range(1, coxeter_matrix_entry): current_word_list = self.put_in_front(current_first_letter, current_last_word[1:]) - output_word_list += [partial_braid_word(counter) + word - for word in current_word_list[1:]] + output_word_list += [partial_braid_word(counter) + word for word in current_word_list[1:]] if current_first_letter == k: current_first_letter = i else: current_first_letter = k current_last_word = current_word_list[-1] if i != k: - output_word_list += [partial_braid_word(coxeter_matrix_entry, swap=True) + - current_last_word[1:]] + output_word_list += [partial_braid_word(coxeter_matrix_entry, swap=True) + current_last_word[1:]] return tuple(output_word_list) def put_in_front(self, k, input_word): @@ -136,7 +134,4 @@ def chain_of_reduced_words(self, start_word, end_word): k = end_word[0] first_word_list = self.put_in_front(k, start_word) first_last_word = first_word_list[-1] - return (first_word_list[:-1] + - tuple([(k,) + word for word in - self.chain_of_reduced_words(first_last_word[1:], - end_word[1:])])) + return first_word_list[:-1] + tuple([(k,) + word for word in self.chain_of_reduced_words(first_last_word[1:], end_word[1:])]) diff --git a/src/sage/combinat/root_system/branching_rules.py b/src/sage/combinat/root_system/branching_rules.py index 5b1a57d037e..348d646e054 100644 --- a/src/sage/combinat/root_system/branching_rules.py +++ b/src/sage/combinat/root_system/branching_rules.py @@ -1010,8 +1010,7 @@ class BranchingRule(SageObject): A class for branching rules. """ - def __init__(self, R, S, f, name='default', intermediate_types=[], - intermediate_names=[]): + def __init__(self, R, S, f, name='default', intermediate_types=[], intermediate_names=[]): """ INPUT: @@ -1138,16 +1137,13 @@ def __mul__(self, other): A5(0,0,0,1,0) + 2*A5(1,0,0,0,0) """ if self._S == other._R: - intermediates = flatten([self._intermediate_types, self._S, - other._intermediate_types]) - internames = flatten([self._intermediate_names, - other._intermediate_names]) + intermediates = flatten([self._intermediate_types, self._S, other._intermediate_types]) + internames = flatten([self._intermediate_names, other._intermediate_names]) def f(x): return other._f(self._f(x)) - return BranchingRule(self._R, other._S, f, "composite", - intermediate_types=intermediates, - intermediate_names=internames) + + return BranchingRule(self._R, other._S, f, "composite", intermediate_types=intermediates, intermediate_names=internames) raise ValueError("unable to define composite: source and target don't agree") def Rtype(self): @@ -1214,16 +1210,12 @@ def describe(self, verbose=False, debug=False, no_r=False): if self._S.is_compound(): for j in range(len(self._S.component_types())): ctype = self._S.component_types()[j] - component_rule = self*branching_rule(self._S, ctype, - "proj%s" % (j + 1)) - print("\nprojection %d on %s " % (j + 1, - ctype._repr_(compact=True)), - component_rule.describe(verbose=verbose, no_r=True)) + component_rule = self * branching_rule(self._S, ctype, "proj%s" % (j + 1)) + print("\nprojection %d on %s " % (j + 1, ctype._repr_(compact=True)), component_rule.describe(verbose=verbose, no_r=True)) if not verbose: print("\nfor more detailed information use verbose=True") else: - print("root restrictions %s => %s:" % (self._R._repr_(compact=True), - self._S._repr_(compact=True))) + print("root restrictions %s => %s:" % (self._R._repr_(compact=True), self._S._repr_(compact=True))) print("\n%r\n" % self._S.dynkin_diagram()) for j in self._R.affine().index_set(): if j == 0: @@ -1254,12 +1246,10 @@ def describe(self, verbose=False, debug=False, no_r=False): if verbose: print("%s => weight %s" % (j, resr)) if verbose: - print("\nfundamental weight restrictions %s => %s:" % (self._R._repr_(compact=True),self._S._repr_(compact=True))) + print("\nfundamental weight restrictions %s => %s:" % (self._R._repr_(compact=True), self._S._repr_(compact=True))) for j in self._R.index_set(): resfw = Sspace(self(list(Rspace.fundamental_weight(j).to_vector()))) - print("%d => %s" % (j, - tuple([resfw.inner_product(a) - for a in Sspace.simple_coroots()]))) + print("%d => %s" % (j, tuple([resfw.inner_product(a) for a in Sspace.simple_coroots()]))) if not no_r and not verbose: print("\nFor more detailed information use verbose=True") @@ -1286,6 +1276,7 @@ def branch(self, chi, style=None): A2(0,1) + A2(1,0) + A2(0,2) + 2*A2(1,1) + A2(2,0) + A2(1,2) + A2(2,1) """ from sage.combinat.root_system.weyl_characters import WeylCharacterRing + if style is None: style = chi.parent()._style S = WeylCharacterRing(self.Stype(), style=style) @@ -1317,7 +1308,7 @@ def branching_rule(Rtype, Stype, rule='default'): if rule == "plethysm": try: S = sage.combinat.root_system.weyl_characters.WeylCharacterRing(Stype.split("(")[0], style='coroots') - chi = S(eval("("+Stype.split("(")[1])) + chi = S(eval("(" + Stype.split("(")[1])) except Exception: S = sage.combinat.root_system.weyl_characters.WeylCharacterRing(Stype.split(".")[0], style='coroots') chi = eval("S." + Stype.split(".")[1]) @@ -1333,7 +1324,7 @@ def branching_rule(Rtype, Stype, rule='default'): if isinstance(rule, str): if rule[:4] == "proj": name = rule - proj = [int(j)-1 for j in rule[4:]] + proj = [int(j) - 1 for j in rule[4:]] rule = [] for j in range(len(Rtypes)): if j in proj: @@ -1344,7 +1335,7 @@ def branching_rule(Rtype, Stype, rule='default'): if not Stype.is_compound(): k = len(Rtypes) n = RootSystem(Stype).ambient_space().dimension() - return BranchingRule(Rtype, Stype, lambda x: [sum(x[i+n*j] for j in range(k)) for i in range(n)], "diagonal") + return BranchingRule(Rtype, Stype, lambda x: [sum(x[i + n * j] for j in range(k)) for i in range(n)], "diagonal") raise ValueError("invalid Cartan types for diagonal branching rule") else: raise ValueError("Rule not found") @@ -1364,40 +1355,43 @@ def branching_rule(Rtype, Stype, rule='default'): Stypes = [CartanType(ru._S) for ru in rules] ntypes = len(Stypes) if Stype.is_compound(): + def br(x): yl = [] for i in range(ntypes): - yl.append(rules[i](x[shifts[stor[i]]:shifts[stor[i]+1]])) + yl.append(rules[i](x[shifts[stor[i]] : shifts[stor[i] + 1]])) return flatten(yl) + else: j = stor[0] rulej = rules[0] def br(x): - return rulej(x[shifts[j]:shifts[j+1]]) + return rulej(x[shifts[j] : shifts[j + 1]]) + return BranchingRule(Rtype, Stype, br, name) if Stype.is_compound(): stypes = Stype.component_types() if rule == "default": if not Rtype.is_compound(): - if Stype.is_compound() and s == r-1: + if Stype.is_compound() and s == r - 1: try: return branching_rule(Rtype, Stype, rule='levi') except Exception: pass if Rtype[0] == "A": - if Stype[0] == "B" and r == 2*s: + if Stype[0] == "B" and r == 2 * s: return branching_rule(Rtype, Stype, rule='symmetric') - if Stype[0] == "C" and r == 2*s-1: + if Stype[0] == "C" and r == 2 * s - 1: return branching_rule(Rtype, Stype, rule='symmetric') - if Stype[0] == "D" and r == 2*s-1: + if Stype[0] == "D" and r == 2 * s - 1: return branching_rule(Rtype, Stype, rule='symmetric') elif Rtype[0] == "B" and Stype[0] == "D" and r == s: return branching_rule(Rtype, Stype, rule='extended') - elif Rtype[0] == "D" and Stype[0] == "B" and r == s+1: + elif Rtype[0] == "D" and Stype[0] == "B" and r == s + 1: return branching_rule(Rtype, Stype, rule='symmetric') - if s == r-1: + if s == r - 1: try: return branching_rule(Rtype, Stype, rule='levi') except Exception: @@ -1408,7 +1402,7 @@ def br(x): raise ValueError("Cartan types must match for identity rule") return BranchingRule(Rtype, Stype, lambda x: x, "identity") elif rule == "levi": - if not s == r-1: + if not s == r - 1: raise ValueError("Incompatible ranks") if Rtype[0] == 'A': if Stype.is_compound(): @@ -1431,45 +1425,45 @@ def br(x): raise ValueError("Rule not found") elif Rtype == CartanType("E6"): if Stype == CartanType("D5"): - return BranchingRule(Rtype, Stype, lambda x: [-x[4],-x[3],-x[2],-x[1],-x[0]], "levi") + return BranchingRule(Rtype, Stype, lambda x: [-x[4], -x[3], -x[2], -x[1], -x[0]], "levi") if Stype == CartanType("A5"): # non-maximal levi - return branching_rule("E6","A5xA1","extended")*branching_rule("A5xA1","A5","proj1") + return branching_rule("E6", "A5xA1", "extended") * branching_rule("A5xA1", "A5", "proj1") if Stype.is_compound(): if Stype[0] == CartanType("A4") and Stype[1] == CartanType("A1"): # non-maximal levi - return branching_rule("E6","A5xA1","extended")*branching_rule("A5xA1","A4xA1",[branching_rule("A5","A4","levi"),"identity"]) + return branching_rule("E6", "A5xA1", "extended") * branching_rule("A5xA1", "A4xA1", [branching_rule("A5", "A4", "levi"), "identity"]) if Stype[0] == CartanType("A1") and Stype[1] == CartanType("A4"): # non-maximal levi - return branching_rule("E6","A1xA5","extended")*branching_rule("A1xA5","A1xA4",["identity",branching_rule("A5","A4","levi")]) + return branching_rule("E6", "A1xA5", "extended") * branching_rule("A1xA5", "A1xA4", ["identity", branching_rule("A5", "A4", "levi")]) if Stype[0] == CartanType("A2") and Stype[1] == CartanType("A2") and Stype[2] == CartanType("A1"): # non-maximal levi - return branching_rule("E6","A2xA2xA2","extended")*branching_rule("A2xA2xA2","A2xA2xA2",["identity","identity",branching_rule("A2","A2","automorphic")*branching_rule("A2","A1","levi")]) + return branching_rule("E6", "A2xA2xA2", "extended") * branching_rule("A2xA2xA2", "A2xA2xA2", ["identity", "identity", branching_rule("A2", "A2", "automorphic") * branching_rule("A2", "A1", "levi")]) if Stype[0] == CartanType("A2") and Stype[1] == CartanType("A1") and Stype[2] == CartanType("A2"): # non-maximal levi raise ValueError("Not implemented: use A2xA2xA1 levi or A2xA2xA2 extended rule. (Non-maximal Levi.)") elif Stype[0] == CartanType("A1") and Stype[1] == CartanType("A2") and Stype[2] == CartanType("A2"): # non-maximal levi raise ValueError("Not implemented: use A2xA2xA1 levi or A2xA2xA2 extended rule. (Non-maximal Levi.)") elif Rtype == CartanType("E7"): if Stype == CartanType("D6"): - return branching_rule("E7","D6xA1","extended")*branching_rule("D6xA1","D6","proj1") # non-maximal levi + return branching_rule("E7", "D6xA1", "extended") * branching_rule("D6xA1", "D6", "proj1") # non-maximal levi if Stype == CartanType("E6"): - return BranchingRule(Rtype, Stype, lambda x: [x[0], x[1], x[2], x[3], x[4], (x[5]+x[6]-x[7])/3, (2*x[5]+5*x[6]+x[7])/6, (-2*x[5]+x[6]+5*x[7])/6], "levi") + return BranchingRule(Rtype, Stype, lambda x: [x[0], x[1], x[2], x[3], x[4], (x[5] + x[6] - x[7]) / 3, (2 * x[5] + 5 * x[6] + x[7]) / 6, (-2 * x[5] + x[6] + 5 * x[7]) / 6], "levi") if Stype == CartanType("A6"): # non-maximal levi - return branching_rule("E7","A7","extended")*branching_rule("A7","A7","automorphic")*branching_rule("A7","A6","levi") + return branching_rule("E7", "A7", "extended") * branching_rule("A7", "A7", "automorphic") * branching_rule("A7", "A6", "levi") if Stype.is_compound(): if Stype[0] == CartanType("A5") and Stype[1] == CartanType("A1"): - return branching_rule("E7","A5xA2","extended")*branching_rule("A5xA2","A5xA1",["identity",branching_rule("A2","A2","automorphic")*branching_rule("A2","A1","levi")]) + return branching_rule("E7", "A5xA2", "extended") * branching_rule("A5xA2", "A5xA1", ["identity", branching_rule("A2", "A2", "automorphic") * branching_rule("A2", "A1", "levi")]) if Stype[0] == CartanType("A1") and Stype[1] == CartanType("A5"): raise NotImplementedError("Not implemented: use A5xA1") elif Rtype == CartanType("E8"): if Stype == CartanType("D7"): - return BranchingRule(Rtype, Stype, lambda x: [-x[6],-x[5],-x[4],-x[3],-x[2],-x[1],-x[0]], "levi") + return BranchingRule(Rtype, Stype, lambda x: [-x[6], -x[5], -x[4], -x[3], -x[2], -x[1], -x[0]], "levi") if Stype == CartanType("E7"): - return BranchingRule(Rtype, Stype, lambda x: [x[0],x[1],x[2],x[3],x[4],x[5],(x[6]-x[7])/2,(x[7]-x[6])/2], "levi") + return BranchingRule(Rtype, Stype, lambda x: [x[0], x[1], x[2], x[3], x[4], x[5], (x[6] - x[7]) / 2, (x[7] - x[6]) / 2], "levi") if Stype == CartanType("A7"): - return branching_rule("E8","A8","extended")*branching_rule("A8","A7","levi") + return branching_rule("E8", "A8", "extended") * branching_rule("A8", "A7", "levi") raise NotImplementedError("Not implemented yet: branch first using extended rule to get non-maximal levis") elif Rtype == CartanType("F4"): if Stype == CartanType("B3"): return BranchingRule(Rtype, Stype, lambda x: x[1:], "levi") if Stype == CartanType("C3"): - return BranchingRule(Rtype, Stype, lambda x: [x[1]-x[0],x[2]+x[3],x[2]-x[3]], "levi") + return BranchingRule(Rtype, Stype, lambda x: [x[1] - x[0], x[2] + x[3], x[2] - x[3]], "levi") raise NotImplementedError("Not implemented yet") elif Rtype == CartanType("G2") and Stype == CartanType("A1"): return BranchingRule(Rtype, Stype, lambda x: list(x)[1:][:2], "levi") @@ -1479,26 +1473,23 @@ def br(x): if not Rtype == Stype: raise ValueError("Cartan types must agree for automorphic branching rule") elif Rtype[0] == 'A': + def rule(x): y = [-i for i in x] y.reverse() return y + return BranchingRule(Rtype, Stype, rule, "automorphic") elif Rtype[0] == 'D': + def rule(x): x[len(x) - 1] = -x[len(x) - 1] return x + return BranchingRule(Rtype, Stype, rule, "automorphic") elif Rtype[0] == 'E' and r == 6: - M = matrix(QQ,[(3, 3, 3, -3, 0, 0, 0, 0), - (3, 3, -3, 3, 0, 0, 0, 0), - (3, -3, 3, 3, 0, 0, 0, 0), - (-3, 3, 3, 3, 0, 0, 0, 0), - (0, 0, 0, 0, -3, -3, -3, 3), - (0, 0, 0, 0, -3, 5, -1, 1), - (0, 0, 0, 0, -3, -1, 5, 1), - (0, 0, 0, 0, 3, 1, 1, 5)])/6 - return BranchingRule(Rtype, Stype, lambda x: tuple(M*vector(x)), "automorphic") + M = matrix(QQ, [(3, 3, 3, -3, 0, 0, 0, 0), (3, 3, -3, 3, 0, 0, 0, 0), (3, -3, 3, 3, 0, 0, 0, 0), (-3, 3, 3, 3, 0, 0, 0, 0), (0, 0, 0, 0, -3, -3, -3, 3), (0, 0, 0, 0, -3, 5, -1, 1), (0, 0, 0, 0, -3, -1, 5, 1), (0, 0, 0, 0, 3, 1, 1, 5)]) / 6 + return BranchingRule(Rtype, Stype, lambda x: tuple(M * vector(x)), "automorphic") else: raise ValueError("No automorphism found") elif rule == "triality": @@ -1507,24 +1498,24 @@ def rule(x): elif not Rtype[0] == 'D' and r == 4: raise ValueError("Triality is for D4 only") else: - return BranchingRule(Rtype, Stype, lambda x: [(x[0]+x[1]+x[2]+x[3])/2,(x[0]+x[1]-x[2]-x[3])/2,(x[0]-x[1]+x[2]-x[3])/2,(-x[0]+x[1]+x[2]-x[3])/2], "triality") + return BranchingRule(Rtype, Stype, lambda x: [(x[0] + x[1] + x[2] + x[3]) / 2, (x[0] + x[1] - x[2] - x[3]) / 2, (x[0] - x[1] + x[2] - x[3]) / 2, (-x[0] + x[1] + x[2] - x[3]) / 2], "triality") elif rule == "symmetric": if Rtype[0] == 'A': - if (Stype[0] == 'C' or Stype[0] == 'D' and r == 2*s-1) or (Stype[0] == 'B' and r == 2*s): - return BranchingRule(Rtype, Stype, lambda x: [x[i]-x[r-i] for i in range(s)], "symmetric") + if (Stype[0] == 'C' or Stype[0] == 'D' and r == 2 * s - 1) or (Stype[0] == 'B' and r == 2 * s): + return BranchingRule(Rtype, Stype, lambda x: [x[i] - x[r - i] for i in range(s)], "symmetric") raise ValueError("Rule not found") - elif Rtype[0] == 'D' and Stype[0] == 'B' and s == r-1: + elif Rtype[0] == 'D' and Stype[0] == 'B' and s == r - 1: return BranchingRule(Rtype, Stype, lambda x: x[:s], "symmetric") elif Rtype == CartanType("D4") and Stype == CartanType("G2"): - return BranchingRule(Rtype, Stype, lambda x: [x[0]+x[1], -x[1]+x[2], -x[0]-x[2]], "symmetric") + return BranchingRule(Rtype, Stype, lambda x: [x[0] + x[1], -x[1] + x[2], -x[0] - x[2]], "symmetric") elif Rtype == CartanType("E6") and Stype == CartanType("F4"): - return BranchingRule(Rtype, Stype, lambda x: [(x[4]-3*x[5])/2,(x[0]+x[1]+x[2]+x[3])/2,(-x[0]-x[1]+x[2]+x[3])/2,(-x[0]+x[1]-x[2]+x[3])/2], "symmetric") + return BranchingRule(Rtype, Stype, lambda x: [(x[4] - 3 * x[5]) / 2, (x[0] + x[1] + x[2] + x[3]) / 2, (-x[0] - x[1] + x[2] + x[3]) / 2, (-x[0] + x[1] - x[2] + x[3]) / 2], "symmetric") elif Rtype == CartanType("E6") and Stype == CartanType("C4"): + def f(x): x0, x1, x2, x3, x4, x5 = x[:6] - return [(x0+x1+x2+x3+x4-3*x5)/2, - (-x0-x1-x2-x3+x4-3*x5)/2, - -x0 + x3, -x1 + x2] + return [(x0 + x1 + x2 + x3 + x4 - 3 * x5) / 2, (-x0 - x1 - x2 - x3 + x4 - 3 * x5) / 2, -x0 + x3, -x1 + x2] + return BranchingRule(Rtype, Stype, f, "symmetric") else: raise ValueError("Rule not found") @@ -1532,17 +1523,17 @@ def f(x): if rule == "extended" and not s == r: raise ValueError('Ranks should be equal for rule="extended"') if Stype.is_compound(): - if Rtype[0] in ['B','D'] and all(t[0] in ['B','D'] for t in stypes): + if Rtype[0] in ['B', 'D'] and all(t[0] in ['B', 'D'] for t in stypes): if Rtype[0] == 'D': - rdeg = 2*r + rdeg = 2 * r else: - rdeg = 2*r+1 + rdeg = 2 * r + 1 sdeg = 0 for t in stypes: if t[0] == 'D': - sdeg += 2*t[1] + sdeg += 2 * t[1] else: - sdeg += 2*t[1]+1 + sdeg += 2 * t[1] + 1 if rdeg == sdeg: return BranchingRule(Rtype, Stype, lambda x: x[:s], "orthogonal_sum") raise ValueError("Rule not found") @@ -1553,78 +1544,30 @@ def f(x): raise ValueError("Rule not found") elif Rtype[0] == 'E': if r == 6: - if stypes == [CartanType("A5"),CartanType("A1")]: - M = matrix(QQ,[(-3, -3, -3, -3, -3, -5, -5, 5), - (-9, 3, 3, 3, 3, 1, 1, -1), - (3, -9, 3, 3, 3, 1, 1, -1), - (3, 3, -9, 3, 3, 1, 1, -1), - (3, 3, 3, -9, 3, 1, 1, -1), - (3, 3, 3, 3, -9, 9, -3, 3), - (-3, -3, -3, -3, -3, -1, 11, 1), - (3, 3, 3, 3, 3, 1, 1, 11)])/12 - return BranchingRule(Rtype, Stype, lambda x: tuple(M*vector(x)), "extended") - if stypes == [CartanType("A1"),CartanType("A5")]: - M = matrix(QQ,[(-3, -3, -3, -3, -3, -1, 11, 1), - (3, 3, 3, 3, 3, 1, 1, 11), - (-3, -3, -3, -3, -3, -5, -5, 5), - (-9, 3, 3, 3, 3, 1, 1, -1), - (3, -9, 3, 3, 3, 1, 1, -1), - (3, 3, -9, 3, 3, 1, 1, -1), - (3, 3, 3, -9, 3, 1, 1, -1), - (3, 3, 3, 3, -9, 9, -3, 3)])/12 - return BranchingRule(Rtype, Stype, lambda x: tuple(M*vector(x)), "extended") - if stypes == [CartanType("A2"),CartanType("A2"),CartanType("A2")]: - M = matrix(QQ,[(0, 0, -2, -2, -2, -2, -2, 2), - (-3, 3, 1, 1, 1, 1, 1, -1), - (3, -3, 1, 1, 1, 1, 1, -1), - (0, 0, -2, -2, 4, 0, 0, 0), - (0, 0, -2, 4, -2, 0, 0, 0), - (0, 0, 4, -2, -2, 0, 0, 0), - (0, 0, -2, -2, -2, 2, 2, -2), - (3, 3, 1, 1, 1, -1, -1, 1), - (-3, -3, 1, 1, 1, -1, -1, 1)])/6 - return BranchingRule(Rtype, Stype, lambda x: tuple(M*vector(x)), "extended") + if stypes == [CartanType("A5"), CartanType("A1")]: + M = matrix(QQ, [(-3, -3, -3, -3, -3, -5, -5, 5), (-9, 3, 3, 3, 3, 1, 1, -1), (3, -9, 3, 3, 3, 1, 1, -1), (3, 3, -9, 3, 3, 1, 1, -1), (3, 3, 3, -9, 3, 1, 1, -1), (3, 3, 3, 3, -9, 9, -3, 3), (-3, -3, -3, -3, -3, -1, 11, 1), (3, 3, 3, 3, 3, 1, 1, 11)]) / 12 + return BranchingRule(Rtype, Stype, lambda x: tuple(M * vector(x)), "extended") + if stypes == [CartanType("A1"), CartanType("A5")]: + M = matrix(QQ, [(-3, -3, -3, -3, -3, -1, 11, 1), (3, 3, 3, 3, 3, 1, 1, 11), (-3, -3, -3, -3, -3, -5, -5, 5), (-9, 3, 3, 3, 3, 1, 1, -1), (3, -9, 3, 3, 3, 1, 1, -1), (3, 3, -9, 3, 3, 1, 1, -1), (3, 3, 3, -9, 3, 1, 1, -1), (3, 3, 3, 3, -9, 9, -3, 3)]) / 12 + return BranchingRule(Rtype, Stype, lambda x: tuple(M * vector(x)), "extended") + if stypes == [CartanType("A2"), CartanType("A2"), CartanType("A2")]: + M = matrix(QQ, [(0, 0, -2, -2, -2, -2, -2, 2), (-3, 3, 1, 1, 1, 1, 1, -1), (3, -3, 1, 1, 1, 1, 1, -1), (0, 0, -2, -2, 4, 0, 0, 0), (0, 0, -2, 4, -2, 0, 0, 0), (0, 0, 4, -2, -2, 0, 0, 0), (0, 0, -2, -2, -2, 2, 2, -2), (3, 3, 1, 1, 1, -1, -1, 1), (-3, -3, 1, 1, 1, -1, -1, 1)]) / 6 + return BranchingRule(Rtype, Stype, lambda x: tuple(M * vector(x)), "extended") elif r == 7: - if stypes == [CartanType("D6"),CartanType("A1")]: - return BranchingRule(Rtype, Stype, lambda x: [x[5],x[4],x[3],x[2],x[1],x[0],x[6],x[7]], "extended") - if stypes == [CartanType("A1"),CartanType("D6")]: - return BranchingRule(Rtype, Stype, lambda x: [x[6],x[7],x[5],x[4],x[3],x[2],x[1],x[0]], "extended") - if stypes == [CartanType("A5"),CartanType("A2")]: - M = matrix(QQ,[(5, 1, 1, 1, 1, 1, 0, 0), - (-1, -5, 1, 1, 1, 1, 0, 0), - (-1, 1, -5, 1, 1, 1, 0, 0), - (-1, 1, 1, -5, 1, 1, 0, 0), - (-1, 1, 1, 1, -5, 1, 0, 0), - (-1, 1, 1, 1, 1, -5, 0, 0), - (1, -1, -1, -1, -1, -1, 0, -6), - (1, -1, -1, -1, -1, -1, -6, 0), - (-2, 2, 2, 2, 2, 2, -3, -3)])/6 - return BranchingRule(Rtype, Stype, lambda x: tuple(M*vector(x)), "extended") - if stypes == [CartanType("A3"),CartanType("A3"),CartanType("A1")]: - M = matrix(QQ, [(0, 0, -1, -1, -1, -1, 2, -2), - (0, 0, -1, -1, -1, -1, -2, 2), - (-2, 2, 1, 1, 1, 1, 0, 0), - (2, -2, 1, 1, 1, 1, 0, 0), - (0, 0, -1, -1, -1, 3, 0, 0), - (0, 0, -1, -1, 3, -1, 0, 0), - (0, 0, -1, 3, -1, -1, 0, 0), - (0, 0, 3, -1, -1, -1, 0, 0), - (2, 2, 0, 0, 0, 0, -2, -2), - (-2, -2, 0, 0, 0, 0, -2, -2)])/4 - return BranchingRule(Rtype, Stype, lambda x: tuple(M*vector(x)), "extended") + if stypes == [CartanType("D6"), CartanType("A1")]: + return BranchingRule(Rtype, Stype, lambda x: [x[5], x[4], x[3], x[2], x[1], x[0], x[6], x[7]], "extended") + if stypes == [CartanType("A1"), CartanType("D6")]: + return BranchingRule(Rtype, Stype, lambda x: [x[6], x[7], x[5], x[4], x[3], x[2], x[1], x[0]], "extended") + if stypes == [CartanType("A5"), CartanType("A2")]: + M = matrix(QQ, [(5, 1, 1, 1, 1, 1, 0, 0), (-1, -5, 1, 1, 1, 1, 0, 0), (-1, 1, -5, 1, 1, 1, 0, 0), (-1, 1, 1, -5, 1, 1, 0, 0), (-1, 1, 1, 1, -5, 1, 0, 0), (-1, 1, 1, 1, 1, -5, 0, 0), (1, -1, -1, -1, -1, -1, 0, -6), (1, -1, -1, -1, -1, -1, -6, 0), (-2, 2, 2, 2, 2, 2, -3, -3)]) / 6 + return BranchingRule(Rtype, Stype, lambda x: tuple(M * vector(x)), "extended") + if stypes == [CartanType("A3"), CartanType("A3"), CartanType("A1")]: + M = matrix(QQ, [(0, 0, -1, -1, -1, -1, 2, -2), (0, 0, -1, -1, -1, -1, -2, 2), (-2, 2, 1, 1, 1, 1, 0, 0), (2, -2, 1, 1, 1, 1, 0, 0), (0, 0, -1, -1, -1, 3, 0, 0), (0, 0, -1, -1, 3, -1, 0, 0), (0, 0, -1, 3, -1, -1, 0, 0), (0, 0, 3, -1, -1, -1, 0, 0), (2, 2, 0, 0, 0, 0, -2, -2), (-2, -2, 0, 0, 0, 0, -2, -2)]) / 4 + return BranchingRule(Rtype, Stype, lambda x: tuple(M * vector(x)), "extended") elif r == 8: - if stypes == [CartanType("A4"),CartanType("A4")]: - M = matrix(QQ,[(0, 0, 0, -4, -4, -4, -4, 4), - (-5, 5, 5, 1, 1, 1, 1, -1), - (5, -5, 5, 1, 1, 1, 1, -1), - (5, 5, -5, 1, 1, 1, 1, -1), - (-5, -5, -5, 1, 1, 1, 1, -1), - (0, 0, 0, -8, 2, 2, 2, -2), - (0, 0, 0, 2, -8, 2, 2, -2), - (0, 0, 0, 2, 2, -8, 2, -2), - (0, 0, 0, 2, 2, 2, -8, -2), - (0, 0, 0, 2, 2, 2, 2, 8)])/10 - return BranchingRule(Rtype, Stype, lambda x: tuple(M*vector(x)), "extended") + if stypes == [CartanType("A4"), CartanType("A4")]: + M = matrix(QQ, [(0, 0, 0, -4, -4, -4, -4, 4), (-5, 5, 5, 1, 1, 1, 1, -1), (5, -5, 5, 1, 1, 1, 1, -1), (5, 5, -5, 1, 1, 1, 1, -1), (-5, -5, -5, 1, 1, 1, 1, -1), (0, 0, 0, -8, 2, 2, 2, -2), (0, 0, 0, 2, -8, 2, 2, -2), (0, 0, 0, 2, 2, -8, 2, -2), (0, 0, 0, 2, 2, 2, -8, -2), (0, 0, 0, 2, 2, 2, 2, 8)]) / 10 + return BranchingRule(Rtype, Stype, lambda x: tuple(M * vector(x)), "extended") if len(stypes) == 3: if 5 in stypes[0][i]: # S is A5xA2xA1 raise NotImplementedError("Not maximal: first branch to A7xA1") @@ -1633,71 +1576,53 @@ def f(x): elif stypes == [CartanType("A3"), CartanType("D5")]: raise NotImplementedError("Not maximal: first branch to D8 then D5xD3=D5xA3") elif stypes == [CartanType("E6"), CartanType("A2")]: + def br(x): - return [x[0], x[1], x[2], x[3], x[4], - (x[5]+x[6]-x[7])/3,(x[5]+x[6]-x[7])/3, - (-x[5]-x[6]+x[7])/3, - (-x[5]-x[6]-2*x[7])/3, - (-x[5]+2*x[6]+x[7])/3, - (2*x[5]-x[6]+x[7])/3] + return [x[0], x[1], x[2], x[3], x[4], (x[5] + x[6] - x[7]) / 3, (x[5] + x[6] - x[7]) / 3, (-x[5] - x[6] + x[7]) / 3, (-x[5] - x[6] - 2 * x[7]) / 3, (-x[5] + 2 * x[6] + x[7]) / 3, (2 * x[5] - x[6] + x[7]) / 3] + return BranchingRule(Rtype, Stype, br, "extended") elif stypes == [CartanType("E7"), CartanType("A1")]: + def br(x): - return [x[0], x[1], x[2], x[3], x[4], x[5], - (x[6]-x[7])/2, (-x[6]+x[7])/2, - (-x[6]-x[7])/2, (x[6]+x[7])/2] + return [x[0], x[1], x[2], x[3], x[4], x[5], (x[6] - x[7]) / 2, (-x[6] + x[7]) / 2, (-x[6] - x[7]) / 2, (x[6] + x[7]) / 2] + return BranchingRule(Rtype, Stype, br, "extended") raise ValueError("Rule not found") elif Rtype[0] == 'F': if stypes == [CartanType("C3"), CartanType("A1")]: - return BranchingRule(Rtype, Stype, lambda x: [x[0]-x[1],x[2]+x[3],x[2]-x[3],(-x[0]-x[1])/2,(x[0]+x[1])/2], "extended") + return BranchingRule(Rtype, Stype, lambda x: [x[0] - x[1], x[2] + x[3], x[2] - x[3], (-x[0] - x[1]) / 2, (x[0] + x[1]) / 2], "extended") if stypes == [CartanType("A1"), CartanType("C3")]: - return BranchingRule(Rtype, Stype, lambda x: [(-x[0]-x[1])/2,(x[0]+x[1])/2,x[0]-x[1],x[2]+x[3],x[2]-x[3]], "extended") + return BranchingRule(Rtype, Stype, lambda x: [(-x[0] - x[1]) / 2, (x[0] + x[1]) / 2, x[0] - x[1], x[2] + x[3], x[2] - x[3]], "extended") if stypes == [CartanType("A2"), CartanType("A2")]: - M = matrix(QQ,[(-2, -1, -1, 0), (1, 2, -1, 0), (1, -1, 2, 0), (1, -1, -1, 3), (1, -1, -1, -3), (-2, 2, 2, 0)])/3 + M = matrix(QQ, [(-2, -1, -1, 0), (1, 2, -1, 0), (1, -1, 2, 0), (1, -1, -1, 3), (1, -1, -1, -3), (-2, 2, 2, 0)]) / 3 elif stypes == [CartanType("A3"), CartanType("A1")]: - M = matrix(QQ,[(-3, -1, -1, -1), (1, 3, -1, -1), (1, -1, 3, -1), (1, -1, -1, 3), (2, -2, -2, -2), (-2, 2, 2, 2)])/4 + M = matrix(QQ, [(-3, -1, -1, -1), (1, 3, -1, -1), (1, -1, 3, -1), (1, -1, -1, 3), (2, -2, -2, -2), (-2, 2, 2, 2)]) / 4 elif stypes == [CartanType("A1"), CartanType("A3")]: - M = matrix(QQ,[(2, -2, -2, -2), (-2, 2, 2, 2), (-3, -1, -1, -1), (1, 3, -1, -1), (1, -1, 3, -1), (1, -1, -1, 3)])/4 + M = matrix(QQ, [(2, -2, -2, -2), (-2, 2, 2, 2), (-3, -1, -1, -1), (1, 3, -1, -1), (1, -1, 3, -1), (1, -1, -1, 3)]) / 4 else: raise ValueError("Rule not found") - return BranchingRule(Rtype, Stype, lambda x: tuple(M*vector(x)), "extended") + return BranchingRule(Rtype, Stype, lambda x: tuple(M * vector(x)), "extended") elif Rtype[0] == 'G': if stypes == [CartanType("A1"), CartanType("A1")]: - return BranchingRule(Rtype, Stype, lambda x: [(x[1]-x[2])/2,-(x[1]-x[2])/2, x[0]/2, -x[0]/2], "extended") + return BranchingRule(Rtype, Stype, lambda x: [(x[1] - x[2]) / 2, -(x[1] - x[2]) / 2, x[0] / 2, -x[0] / 2], "extended") raise ValueError("Rule not found") else: # irreducible Stype if Rtype[0] == 'B' and Stype[0] == 'D': return BranchingRule(Rtype, Stype, lambda x: x, "extended") if Rtype == CartanType("E7"): if Stype == CartanType("A7"): - M = matrix(QQ, [(-1, -1, -1, -1, -1, -1, 2, -2), - (-1, -1, -1, -1, -1, -1, -2, 2), - (-3, 1, 1, 1, 1, 1, 0, 0), - (1, -3, 1, 1, 1, 1, 0, 0), - (1, 1, -3, 1, 1, 1, 0, 0), - (1, 1, 1, -3, 1, 1, 0, 0), - (1, 1, 1, 1, -3, 1, 2, 2), - (1, 1, 1, 1, 1, -3, 2, 2)])/4 - return BranchingRule(Rtype, Stype, lambda x: tuple(M*vector(x)), "extended") + M = matrix(QQ, [(-1, -1, -1, -1, -1, -1, 2, -2), (-1, -1, -1, -1, -1, -1, -2, 2), (-3, 1, 1, 1, 1, 1, 0, 0), (1, -3, 1, 1, 1, 1, 0, 0), (1, 1, -3, 1, 1, 1, 0, 0), (1, 1, 1, -3, 1, 1, 0, 0), (1, 1, 1, 1, -3, 1, 2, 2), (1, 1, 1, 1, 1, -3, 2, 2)]) / 4 + return BranchingRule(Rtype, Stype, lambda x: tuple(M * vector(x)), "extended") elif Rtype == CartanType("E8"): if Stype == CartanType("D8"): - return BranchingRule(Rtype, Stype, lambda x: [-x[7],x[6],x[5],x[4],x[3],x[2],x[1],x[0]], "extended") + return BranchingRule(Rtype, Stype, lambda x: [-x[7], x[6], x[5], x[4], x[3], x[2], x[1], x[0]], "extended") if Stype == CartanType("A8"): - M = matrix([(-2, -2, -2, -2, -2, -2, -2, 2), - (-5, 1, 1, 1, 1, 1, 1, -1), - (1, -5, 1, 1, 1, 1, 1, -1), - (1, 1, -5, 1, 1, 1, 1, -1), - (1, 1, 1, -5, 1, 1, 1, -1), - (1, 1, 1, 1, -5, 1, 1, -1), - (1, 1, 1, 1, 1, -5, 1, -1), - (1, 1, 1, 1, 1, 1, -5, -1), - (1, 1, 1, 1, 1, 1, 1, 5)])/6 - return BranchingRule(Rtype, Stype, lambda x: tuple(M*vector(x)), "extended") + M = matrix([(-2, -2, -2, -2, -2, -2, -2, 2), (-5, 1, 1, 1, 1, 1, 1, -1), (1, -5, 1, 1, 1, 1, 1, -1), (1, 1, -5, 1, 1, 1, 1, -1), (1, 1, 1, -5, 1, 1, 1, -1), (1, 1, 1, 1, -5, 1, 1, -1), (1, 1, 1, 1, 1, -5, 1, -1), (1, 1, 1, 1, 1, 1, -5, -1), (1, 1, 1, 1, 1, 1, 1, 5)]) / 6 + return BranchingRule(Rtype, Stype, lambda x: tuple(M * vector(x)), "extended") elif Rtype == CartanType("F4") and Stype == CartanType("B4"): return BranchingRule(Rtype, Stype, lambda x: [-x[0], x[1], x[2], x[3]], "extended") elif Rtype == CartanType("G2") and Stype == CartanType("A2"): - return BranchingRule(Rtype, Stype, lambda x: [(-x[1]+x[2])/3, (-x[0]+x[1])/3, (x[0]-x[2])/3], "extended") + return BranchingRule(Rtype, Stype, lambda x: [(-x[1] + x[2]) / 3, (-x[0] + x[1]) / 3, (x[0] - x[2]) / 3], "extended") else: raise ValueError("Rule not found") elif rule == "isomorphic": @@ -1706,38 +1631,47 @@ def br(x): if Rtype == Stype: return BranchingRule(Rtype, Stype, lambda x: x, "isomorphic") if Rtype == CartanType("B2") and Stype == CartanType("C2"): + def rule(x): x1, x2 = x return [x1 + x2, x1 - x2] + return BranchingRule(Rtype, Stype, rule, "isomorphic") if Rtype == CartanType("C2") and Stype == CartanType("B2"): + def rule(x): x1, x2 = x return [(x1 + x2) / 2, (x1 - x2) / 2] + return BranchingRule(Rtype, Stype, rule, "isomorphic") if Rtype == CartanType("B1") and Stype == CartanType("A1"): - return BranchingRule(Rtype, Stype, lambda x: [x[0],-x[0]], "isomorphic") + return BranchingRule(Rtype, Stype, lambda x: [x[0], -x[0]], "isomorphic") if Rtype == CartanType("A1") and Stype == CartanType("B1"): - return BranchingRule(Rtype, Stype, lambda x: [(x[0]-x[1])/2], "isomorphic") + return BranchingRule(Rtype, Stype, lambda x: [(x[0] - x[1]) / 2], "isomorphic") if Rtype == CartanType("C1") and Stype == CartanType("A1"): - return BranchingRule(Rtype, Stype, lambda x: [x[0]/2,-x[0]/2], "isomorphic") + return BranchingRule(Rtype, Stype, lambda x: [x[0] / 2, -x[0] / 2], "isomorphic") if Rtype == CartanType("A1") and Stype == CartanType("C1"): - return BranchingRule(Rtype, Stype, lambda x: [x[0]-x[1]], "isomorphic") + return BranchingRule(Rtype, Stype, lambda x: [x[0] - x[1]], "isomorphic") if Rtype == CartanType("A3") and Stype == CartanType("D3"): + def rule(x): x1, x2, x3, x4 = x - return [(x1+x2-x3-x4)/2, (x1-x2+x3-x4)/2, (x1-x2-x3+x4)/2] + return [(x1 + x2 - x3 - x4) / 2, (x1 - x2 + x3 - x4) / 2, (x1 - x2 - x3 + x4) / 2] + return BranchingRule(Rtype, Stype, rule, "isomorphic") if Rtype == CartanType("D3") and Stype == CartanType("A3"): + def rule(x): t1, t2, t3 = x - return [(t1+t2+t3)/2, (t1-t2-t3)/2, - (-t1+t2-t3)/2, (-t1-t2+t3)/2] + return [(t1 + t2 + t3) / 2, (t1 - t2 - t3) / 2, (-t1 + t2 - t3) / 2, (-t1 - t2 + t3) / 2] + return BranchingRule(Rtype, Stype, rule, "isomorphic") if Rtype == CartanType("D2") and Stype == CartanType("A1xA1"): + def rule(x): t1, t2 = x - return [(t1-t2)/2, -(t1-t2)/2, (t1+t2)/2, -(t1+t2)/2] + return [(t1 - t2) / 2, -(t1 - t2) / 2, (t1 + t2) / 2, -(t1 + t2) / 2] + return BranchingRule(Rtype, Stype, rule, "isomorphic") raise ValueError("Rule not found") elif rule == "tensor" or rule == "tensor-debug": @@ -1746,45 +1680,46 @@ def rule(x): if len(stypes) != 2: raise ValueError("Not implemented") if Rtype[0] == 'A': - nr = Rtype[1]+1 + nr = Rtype[1] + 1 elif Rtype[0] == 'B': - nr = 2*Rtype[1]+1 + nr = 2 * Rtype[1] + 1 elif Rtype[0] in ['C', 'D']: - nr = 2*Rtype[1] + nr = 2 * Rtype[1] else: raise ValueError("Rule not found") s1, s2 = (stypes[i][1] for i in range(2)) ns = [s1, s2] for i in range(2): if stypes[i][0] == 'A': - ns[i] = ns[i]+1 + ns[i] = ns[i] + 1 if stypes[i][0] == 'B': - ns[i] = 2*ns[i]+1 - if stypes[i][0] in ['C','D']: - ns[i] = 2*ns[i] - if nr != ns[0]*ns[1]: + ns[i] = 2 * ns[i] + 1 + if stypes[i][0] in ['C', 'D']: + ns[i] = 2 * ns[i] + if nr != ns[0] * ns[1]: raise ValueError("Ranks don't agree with tensor product") if Rtype[0] == 'A': if all(t[0] == 'A' for t in stypes): + def rule(x): - ret = [sum(x[i*ns[1]:(i+1)*ns[1]]) for i in range(ns[0])] - ret.extend(sum(x[ns[1]*j+i] for j in range(ns[0])) - for i in range(ns[1])) + ret = [sum(x[i * ns[1] : (i + 1) * ns[1]]) for i in range(ns[0])] + ret.extend(sum(x[ns[1] * j + i] for j in range(ns[0])) for i in range(ns[1])) return ret + return BranchingRule(Rtype, Stype, rule, "tensor") raise ValueError("Rule not found") elif Rtype[0] == 'B': if not all(t[0] == 'B' for t in stypes): raise ValueError("Rule not found") elif Rtype[0] == 'C': - if stypes[0][0] in ['B','D'] and stypes[1][0] == 'C': + if stypes[0][0] in ['B', 'D'] and stypes[1][0] == 'C': pass - elif stypes[1][0] in ['B','D'] and stypes[0][0] == 'C': + elif stypes[1][0] in ['B', 'D'] and stypes[0][0] == 'C': pass else: raise ValueError("Rule not found") elif Rtype[0] == 'D': - if stypes[0][0] in ['B','D'] and stypes[1][0] == 'D': + if stypes[0][0] in ['B', 'D'] and stypes[1][0] == 'D': pass elif stypes[1][0] == 'B' and stypes[0][0] == 'D': pass @@ -1795,152 +1730,140 @@ def rule(x): rows = [] for i in range(s1): for j in range(s2): - nextrow = (s1+s2)*[0] + nextrow = (s1 + s2) * [0] nextrow[i] = 1 - nextrow[s1+j] = 1 + nextrow[s1 + j] = 1 rows.append(nextrow) if stypes[1][0] == 'B': for i in range(s1): - nextrow = (s1+s2)*[0] + nextrow = (s1 + s2) * [0] nextrow[i] = 1 rows.append(nextrow) for i in range(s1): for j in range(s2): - nextrow = (s1+s2)*[0] + nextrow = (s1 + s2) * [0] nextrow[i] = 1 - nextrow[s1+j] = -1 + nextrow[s1 + j] = -1 rows.append(nextrow) if stypes[0][0] == 'B': for j in range(s2): - nextrow = (s1+s2)*[0] - nextrow[s1+j] = 1 + nextrow = (s1 + s2) * [0] + nextrow[s1 + j] = 1 rows.append(nextrow) mat = matrix(rows).transpose() if rule == "tensor-debug": print(mat) - return BranchingRule(Rtype, Stype, lambda x: tuple(mat*vector(x)), "tensor") + return BranchingRule(Rtype, Stype, lambda x: tuple(mat * vector(x)), "tensor") elif rule == "symmetric_power": if Stype[0] == 'A' and s == 1: if Rtype[0] == 'B': + def rule(x): - a = sum((r-i)*x[i] for i in range(r)) - return [a,-a] + a = sum((r - i) * x[i] for i in range(r)) + return [a, -a] + return BranchingRule(Rtype, Stype, rule, "symmetric_power") if Rtype[0] == 'C': + def rule(x): - a = sum((2*r-2*i-1)*x[i] for i in range(r)) - return [a/2,-a/2] + a = sum((2 * r - 2 * i - 1) * x[i] for i in range(r)) + return [a / 2, -a / 2] + return BranchingRule(Rtype, Stype, rule, "symmetric_power") elif rule == "miscellaneous": if Rtype[0] == 'B' and Stype[0] == 'G' and r == 3: - return BranchingRule(Rtype, Stype, lambda x: [x[0]+x[1], -x[1]+x[2], -x[0]-x[2]], "miscellaneous") + return BranchingRule(Rtype, Stype, lambda x: [x[0] + x[1], -x[1] + x[2], -x[0] - x[2]], "miscellaneous") if Rtype == CartanType("E6"): if Stype.is_compound(): - if stypes == [CartanType("A2"),CartanType("G2")]: - return BranchingRule(Rtype, Stype, lambda x: [-2*x[5],x[5]+x[4],x[5]-x[4],x[2]+x[3],x[1]-x[2],-x[1]-x[3]], "miscellaneous") - if stypes == [CartanType("G2"),CartanType("A2")]: - return BranchingRule(Rtype, Stype, lambda x: [x[2]+x[3],x[1]-x[2],-x[1]-x[3],-2*x[5],x[5]+x[4],x[5]-x[4]], "miscellaneous") + if stypes == [CartanType("A2"), CartanType("G2")]: + return BranchingRule(Rtype, Stype, lambda x: [-2 * x[5], x[5] + x[4], x[5] - x[4], x[2] + x[3], x[1] - x[2], -x[1] - x[3]], "miscellaneous") + if stypes == [CartanType("G2"), CartanType("A2")]: + return BranchingRule(Rtype, Stype, lambda x: [x[2] + x[3], x[1] - x[2], -x[1] - x[3], -2 * x[5], x[5] + x[4], x[5] - x[4]], "miscellaneous") else: if Stype == CartanType("G2"): - return BranchingRule(Rtype, Stype, lambda x: [x[2]+x[3]+x[4]-3*x[5], x[1]-2*x[2]-x[3], -x[1]+x[2]-x[4]+3*x[5]],"miscellaneous") + return BranchingRule(Rtype, Stype, lambda x: [x[2] + x[3] + x[4] - 3 * x[5], x[1] - 2 * x[2] - x[3], -x[1] + x[2] - x[4] + 3 * x[5]], "miscellaneous") if Stype == CartanType("A2"): - return BranchingRule(Rtype, Stype, lambda x: [x[2]+x[3]+x[4]-3*x[5], x[1]-2*x[2]-x[3], -x[1]+x[2]-x[4]+3*x[5]],"miscellaneous") + return BranchingRule(Rtype, Stype, lambda x: [x[2] + x[3] + x[4] - 3 * x[5], x[1] - 2 * x[2] - x[3], -x[1] + x[2] - x[4] + 3 * x[5]], "miscellaneous") elif Rtype == CartanType("E7"): if Stype.is_compound(): if stypes == [CartanType("C3"), CartanType("G2")]: - return BranchingRule(Rtype, Stype, lambda x: [-2*x[6],x[4]+x[5],-x[4]+x[5],x[1]+x[3],x[2]-x[3],-x[1]-x[2]], "miscellaneous") + return BranchingRule(Rtype, Stype, lambda x: [-2 * x[6], x[4] + x[5], -x[4] + x[5], x[1] + x[3], x[2] - x[3], -x[1] - x[2]], "miscellaneous") if stypes == [CartanType("G2"), CartanType("C3")]: - return BranchingRule(Rtype, Stype, lambda x: [x[1]+x[3],x[2]-x[3],-x[1]-x[2],-2*x[6],x[4]+x[5],-x[4]+x[5]], "miscellaneous") + return BranchingRule(Rtype, Stype, lambda x: [x[1] + x[3], x[2] - x[3], -x[1] - x[2], -2 * x[6], x[4] + x[5], -x[4] + x[5]], "miscellaneous") if stypes == [CartanType("F4"), CartanType("A1")]: + def f(x): x0, x1, x2, x3, x4, x5, x6 = x[:7] - return [(x4-x5)/2-x6, (x0+x1+x2+x3)/2, - (-x0-x1+x2+x3)/2, (-x0+x1-x2+x3)/2, - x5-x6, x6-x5] + return [(x4 - x5) / 2 - x6, (x0 + x1 + x2 + x3) / 2, (-x0 - x1 + x2 + x3) / 2, (-x0 + x1 - x2 + x3) / 2, x5 - x6, x6 - x5] + return BranchingRule(Rtype, Stype, f, "miscellaneous") if stypes == [CartanType("A1"), CartanType("F4")]: + def f(x): x0, x1, x2, x3, x4, x5, x6 = x[:7] - return [x5-x6, x6-x5, (x4-x5)/2-x6, - (x0+x1+x2+x3)/2, - (-x0-x1+x2+x3)/2, - (-x0+x1-x2+x3)/2] + return [x5 - x6, x6 - x5, (x4 - x5) / 2 - x6, (x0 + x1 + x2 + x3) / 2, (-x0 - x1 + x2 + x3) / 2, (-x0 + x1 - x2 + x3) / 2] + return BranchingRule(Rtype, Stype, f, "miscellaneous") if stypes == [CartanType("A1"), CartanType("A1")]: - return BranchingRule(Rtype, Stype, - lambda x: [x[1]+2*x[2]-2*x[3]-x[4]-2*x[6], -x[1]-2*x[2]+2*x[3]+x[4]+2*x[6], - (x[3]+x[4]+x[5]-3*x[6]),-(x[3]+x[4]+x[5]-3*x[6])], "miscellaneous") + return BranchingRule(Rtype, Stype, lambda x: [x[1] + 2 * x[2] - 2 * x[3] - x[4] - 2 * x[6], -x[1] - 2 * x[2] + 2 * x[3] + x[4] + 2 * x[6], (x[3] + x[4] + x[5] - 3 * x[6]), -(x[3] + x[4] + x[5] - 3 * x[6])], "miscellaneous") if stypes == [CartanType("G2"), CartanType("A1")]: + def f(x): - return [(x[0]-x[1]+x[2]+3*x[3]+x[4]-x[5]+2*x[6])/2, - (-3*x[0]-x[1]-x[2]-x[3]+x[4]+x[5]-2*x[6])/2, - (2*x[0]+2*x[1]-2*x[3]-2*x[4])/2, - (x[0]+x[1]+x[2]+x[3]+x[4]+x[5]-4*x[6])/2, - -(x[0]+x[1]+x[2]+x[3]+x[4]+x[5]-4*x[6])/2] + return [(x[0] - x[1] + x[2] + 3 * x[3] + x[4] - x[5] + 2 * x[6]) / 2, (-3 * x[0] - x[1] - x[2] - x[3] + x[4] + x[5] - 2 * x[6]) / 2, (2 * x[0] + 2 * x[1] - 2 * x[3] - 2 * x[4]) / 2, (x[0] + x[1] + x[2] + x[3] + x[4] + x[5] - 4 * x[6]) / 2, -(x[0] + x[1] + x[2] + x[3] + x[4] + x[5] - 4 * x[6]) / 2] + return BranchingRule(Rtype, Stype, f, "miscellaneous") if stypes == [CartanType("A1"), CartanType("G2")]: + def f(x): - return [(x[0]+x[1]+x[2]+x[3]+x[4]+x[5]-4*x[6])/2, - -(x[0]+x[1]+x[2]+x[3]+x[4]+x[5]-4*x[6])/2, - (x[0]-x[1]+x[2]+3*x[3]+x[4]-x[5]+2*x[6])/2, - (-3*x[0]-x[1]-x[2]-x[3]+x[4]+x[5]-2*x[6])/2, - (2*x[0]+2*x[1]-2*x[3]-2*x[4])/2] + return [(x[0] + x[1] + x[2] + x[3] + x[4] + x[5] - 4 * x[6]) / 2, -(x[0] + x[1] + x[2] + x[3] + x[4] + x[5] - 4 * x[6]) / 2, (x[0] - x[1] + x[2] + 3 * x[3] + x[4] - x[5] + 2 * x[6]) / 2, (-3 * x[0] - x[1] - x[2] - x[3] + x[4] + x[5] - 2 * x[6]) / 2, (2 * x[0] + 2 * x[1] - 2 * x[3] - 2 * x[4]) / 2] + return BranchingRule(Rtype, Stype, f, "miscellaneous") elif Stype == CartanType("A2"): - return BranchingRule(Rtype, Stype, lambda x: (x[1]+x[2]+2*x[4]-4*x[6],-2*x[1]-x[2]+x[3]-2*x[4]+2*x[5],x[1]-x[3]-2*x[5]+4*x[6]), "miscellaneous") + return BranchingRule(Rtype, Stype, lambda x: (x[1] + x[2] + 2 * x[4] - 4 * x[6], -2 * x[1] - x[2] + x[3] - 2 * x[4] + 2 * x[5], x[1] - x[3] - 2 * x[5] + 4 * x[6]), "miscellaneous") elif Rtype == CartanType("E8"): if Stype.is_compound(): - if stypes == [CartanType("F4"),CartanType("G2")]: - return BranchingRule(Rtype, Stype, lambda x: [x[7], x[6], x[5], x[4], x[1]+x[3], -x[3]+x[2], -x[1]-x[2]], "miscellaneous") - if stypes == [CartanType("G2"),CartanType("F4")]: - return BranchingRule(Rtype, Stype, lambda x: [x[1]+x[3], -x[3]+x[2], -x[1]-x[2], x[7], x[6], x[5], x[4]], "miscellaneous") + if stypes == [CartanType("F4"), CartanType("G2")]: + return BranchingRule(Rtype, Stype, lambda x: [x[7], x[6], x[5], x[4], x[1] + x[3], -x[3] + x[2], -x[1] - x[2]], "miscellaneous") + if stypes == [CartanType("G2"), CartanType("F4")]: + return BranchingRule(Rtype, Stype, lambda x: [x[1] + x[3], -x[3] + x[2], -x[1] - x[2], x[7], x[6], x[5], x[4]], "miscellaneous") if stypes == [CartanType("A2"), CartanType("A1")]: + def f(x): - return [(x[0]-x[1]+x[2]+x[3]+3*x[4]+x[5]-x[6]-x[7])/2, - (-3*x[0]-x[1]-x[2]-x[3]-x[4]+x[5]+x[6]+x[7])/2, - (2*x[0]+2*x[1]-2*x[4]-2*x[5])/2, - (x[0]+x[1]+x[2]+x[3]+x[4]+x[5]+x[6]+5*x[7])/2, - -(x[0]+x[1]+x[2]+x[3]+x[4]+x[5]+x[6]+5*x[7])/2] - return BranchingRule("E8","A2xA1",f,"miscellaneous") + return [(x[0] - x[1] + x[2] + x[3] + 3 * x[4] + x[5] - x[6] - x[7]) / 2, (-3 * x[0] - x[1] - x[2] - x[3] - x[4] + x[5] + x[6] + x[7]) / 2, (2 * x[0] + 2 * x[1] - 2 * x[4] - 2 * x[5]) / 2, (x[0] + x[1] + x[2] + x[3] + x[4] + x[5] + x[6] + 5 * x[7]) / 2, -(x[0] + x[1] + x[2] + x[3] + x[4] + x[5] + x[6] + 5 * x[7]) / 2] + + return BranchingRule("E8", "A2xA1", f, "miscellaneous") if stypes == [CartanType("A1"), CartanType("A2")]: + def f(x): - return [(x[0]+x[1]+x[2]+x[3]+x[4]+x[5]+x[6]+5*x[7])/2, - -(x[0]+x[1]+x[2]+x[3]+x[4]+x[5]+x[6]+5*x[7])/2, - (x[0]-x[1]+x[2]+x[3]+3*x[4]+x[5]-x[6]-x[7])/2, - (-3*x[0]-x[1]-x[2]-x[3]-x[4]+x[5]+x[6]+x[7])/2, - (2*x[0]+2*x[1]-2*x[4]-2*x[5])/2] + return [(x[0] + x[1] + x[2] + x[3] + x[4] + x[5] + x[6] + 5 * x[7]) / 2, -(x[0] + x[1] + x[2] + x[3] + x[4] + x[5] + x[6] + 5 * x[7]) / 2, (x[0] - x[1] + x[2] + x[3] + 3 * x[4] + x[5] - x[6] - x[7]) / 2, (-3 * x[0] - x[1] - x[2] - x[3] - x[4] + x[5] + x[6] + x[7]) / 2, (2 * x[0] + 2 * x[1] - 2 * x[4] - 2 * x[5]) / 2] + return BranchingRule("E8", "A1xA2", f, "miscellaneous") elif Stype == CartanType("B2"): - return BranchingRule("E8", "B2", lambda x: [-x[0] + x[2] + x[5] + 3*x[7], 2*x[0] - x[2] + x[3] + x[4] + 2*x[6] + x[7]], "miscellaneous") + return BranchingRule("E8", "B2", lambda x: [-x[0] + x[2] + x[5] + 3 * x[7], 2 * x[0] - x[2] + x[3] + x[4] + 2 * x[6] + x[7]], "miscellaneous") elif Rtype[0] == 'F': if Stype.is_compound(): if stypes == [CartanType("A1"), CartanType("G2")]: - return BranchingRule("F4", "A1xG2", lambda x: [2*x[0], -2*x[0], x[1]+x[2], -x[2]+x[3], -x[1]-x[3]], "miscellaneous") + return BranchingRule("F4", "A1xG2", lambda x: [2 * x[0], -2 * x[0], x[1] + x[2], -x[2] + x[3], -x[1] - x[3]], "miscellaneous") if stypes == [CartanType("G2"), CartanType("A1")]: - return BranchingRule("F4","G2xA1", lambda x: [x[1]+x[2], -x[2]+x[3], -x[1]-x[3], 2*x[0], -2*x[0]], "miscellaneous") + return BranchingRule("F4", "G2xA1", lambda x: [x[1] + x[2], -x[2] + x[3], -x[1] - x[3], 2 * x[0], -2 * x[0]], "miscellaneous") raise ValueError("Rule not found") elif rule in ["i", "ii", "iii", "iv", "v", "vi", "vii"]: if Stype != CartanType("A1"): raise ValueError("Wrong target Cartan Type for rule %s" % rule) if rule == "i" and Rtype == CartanType("G2"): - return BranchingRule(Rtype, Stype, lambda x: [(5*x[0]-x[1]-4*x[2])/3,-(5*x[0]-x[1]-4*x[2])/3], "i") + return BranchingRule(Rtype, Stype, lambda x: [(5 * x[0] - x[1] - 4 * x[2]) / 3, -(5 * x[0] - x[1] - 4 * x[2]) / 3], "i") if rule == "ii" and Rtype == CartanType("F4"): - return BranchingRule(Rtype, Stype, lambda x: [8*x[0]+3*x[1]+2*x[2]+x[3],-(8*x[0]+3*x[1]+2*x[2]+x[3])], "ii") + return BranchingRule(Rtype, Stype, lambda x: [8 * x[0] + 3 * x[1] + 2 * x[2] + x[3], -(8 * x[0] + 3 * x[1] + 2 * x[2] + x[3])], "ii") if rule == "iii" and Rtype == CartanType("E7"): - return BranchingRule(Rtype, Stype, - lambda x: [x[1]+2*x[2]+3*x[3]+4*x[4]+5*x[5]-17*x[6],-(x[1]+2*x[2]+3*x[3]+4*x[4]+5*x[5]-17*x[6])], "iii") + return BranchingRule(Rtype, Stype, lambda x: [x[1] + 2 * x[2] + 3 * x[3] + 4 * x[4] + 5 * x[5] - 17 * x[6], -(x[1] + 2 * x[2] + 3 * x[3] + 4 * x[4] + 5 * x[5] - 17 * x[6])], "iii") if rule == "iv" and Rtype == CartanType("E7"): - return BranchingRule(Rtype, Stype, - lambda x: [x[1]+x[2]+2*x[3]+3*x[4]+4*x[5]-13*x[6],-(x[1]+x[2]+2*x[3]+3*x[4]+4*x[5]-13*x[6])], "iv") + return BranchingRule(Rtype, Stype, lambda x: [x[1] + x[2] + 2 * x[3] + 3 * x[4] + 4 * x[5] - 13 * x[6], -(x[1] + x[2] + 2 * x[3] + 3 * x[4] + 4 * x[5] - 13 * x[6])], "iv") if rule == "v" and Rtype == CartanType("E8"): - return BranchingRule(Rtype, Stype, - lambda x: [x[1]+2*x[2]+3*x[3]+4*x[4]+5*x[5]+6*x[6]+23*x[7],-(x[1]+2*x[2]+3*x[3]+4*x[4]+5*x[5]+6*x[6]+23*x[7])], "v") + return BranchingRule(Rtype, Stype, lambda x: [x[1] + 2 * x[2] + 3 * x[3] + 4 * x[4] + 5 * x[5] + 6 * x[6] + 23 * x[7], -(x[1] + 2 * x[2] + 3 * x[3] + 4 * x[4] + 5 * x[5] + 6 * x[6] + 23 * x[7])], "v") if rule == "vi" and Rtype == CartanType("E8"): - return BranchingRule(Rtype, Stype, - lambda x: [x[1]+x[2]+2*x[3]+3*x[4]+4*x[5]+5*x[6]+18*x[7],-(x[1]+x[2]+2*x[3]+3*x[4]+4*x[5]+5*x[6]+18*x[7])], "vi") + return BranchingRule(Rtype, Stype, lambda x: [x[1] + x[2] + 2 * x[3] + 3 * x[4] + 4 * x[5] + 5 * x[6] + 18 * x[7], -(x[1] + x[2] + 2 * x[3] + 3 * x[4] + 4 * x[5] + 5 * x[6] + 18 * x[7])], "vi") if rule == "vii" and Rtype == CartanType("E8"): - return BranchingRule(Rtype, Stype, - lambda x: [x[1]+x[2]+2*x[3]+2*x[4]+3*x[5]+4*x[6]+15*x[7],-(x[1]+x[2]+2*x[3]+2*x[4]+3*x[5]+4*x[6]+15*x[7])], "vii") + return BranchingRule(Rtype, Stype, lambda x: [x[1] + x[2] + 2 * x[3] + 2 * x[4] + 3 * x[5] + 4 * x[6] + 15 * x[7], -(x[1] + x[2] + 2 * x[3] + 2 * x[4] + 3 * x[5] + 4 * x[6] + 15 * x[7])], "vii") raise ValueError("Wrong source Cartan Type for rule %s" % rule) raise ValueError("Rule not found") @@ -2000,7 +1923,7 @@ def branching_rule_from_plethysm(chi, cartan_type, return_matrix=False): M = matrix(ret).transpose() if len(M.columns()) != ct[1] + 1: raise ValueError("representation has wrong degree for type {}".format(ct)) - return BranchingRule(ct, chi.parent().cartan_type(), lambda x: tuple(M*vector(x)), "plethysm (along %s)" % chi) + return BranchingRule(ct, chi.parent().cartan_type(), lambda x: tuple(M * vector(x)), "plethysm (along %s)" % chi) if ct[0] in ["B", "D"]: if chi.frobenius_schur_indicator() != 1: raise ValueError("character is not orthogonal") @@ -2020,9 +1943,9 @@ def branching_rule_from_plethysm(chi, cartan_type, return_matrix=False): vec = v.to_vector() if all(x == 0 for x in vec): if ct[0] == "B": - n = (n-1)/2 + n = (n - 1) / 2 else: - n = n/2 + n = n / 2 elif [x for x in vec if x != 0][0] < 0: continue ret.extend(n * [vec]) @@ -2031,7 +1954,7 @@ def branching_rule_from_plethysm(chi, cartan_type, return_matrix=False): raise ValueError("representation has wrong degree for type {}".format(ct)) if return_matrix: return M - return BranchingRule(ct, chi.parent().cartan_type(), lambda x: tuple(M*vector(x)), "plethysm (along %s)" % chi) + return BranchingRule(ct, chi.parent().cartan_type(), lambda x: tuple(M * vector(x)), "plethysm (along %s)" % chi) def maximal_subgroups(ct, mode='print_rules'): @@ -2062,217 +1985,63 @@ def maximal_subgroups(ct, mode='print_rules'): if CartanType(ct) == CartanType("A2"): rul = ["""A1:branching_rule("A2","A1","levi")"""] elif CartanType(ct) == CartanType("A3"): - rul = ["""A2:branching_rule("A3","A2","levi")""", - """A1xA1:branching_rule("A3","A1xA1","tensor")""", - """C2:branching_rule("A3","C2","symmetric")""", - """A1xA1:branching_rule("A3","A1xA1","levi")"""] + rul = ["""A2:branching_rule("A3","A2","levi")""", """A1xA1:branching_rule("A3","A1xA1","tensor")""", """C2:branching_rule("A3","C2","symmetric")""", """A1xA1:branching_rule("A3","A1xA1","levi")"""] elif CartanType(ct) == CartanType("A4"): - rul = ["""A3:branching_rule("A4","A3","levi")""", - """B2:branching_rule("A4","B2","symmetric")""", - """A1xA2:branching_rule("A4","A1xA2","levi")"""] + rul = ["""A3:branching_rule("A4","A3","levi")""", """B2:branching_rule("A4","B2","symmetric")""", """A1xA2:branching_rule("A4","A1xA2","levi")"""] elif CartanType(ct) == CartanType("A5"): - rul = ["""A4:branching_rule("A5","A4","levi")""", - """A3:branching_rule("A5","D3","symmetric")*branching_rule("D3","A3","isomorphic")""", - """A3:branching_rule("A5","A3(0,1,0)","plethysm") # alternative""", - """C3:branching_rule("A5","C3","symmetric")""", - """A2:branching_rule("A5","A2(2,0)","plethysm")""", - """A1xA2:branching_rule("A5","A1xA2","tensor")""", - """A1xA3:branching_rule("A5","A1xA3","levi")""", - """A2xA2:branching_rule("A5","A2xA2","levi")"""] + rul = ["""A4:branching_rule("A5","A4","levi")""", """A3:branching_rule("A5","D3","symmetric")*branching_rule("D3","A3","isomorphic")""", """A3:branching_rule("A5","A3(0,1,0)","plethysm") # alternative""", """C3:branching_rule("A5","C3","symmetric")""", """A2:branching_rule("A5","A2(2,0)","plethysm")""", """A1xA2:branching_rule("A5","A1xA2","tensor")""", """A1xA3:branching_rule("A5","A1xA3","levi")""", """A2xA2:branching_rule("A5","A2xA2","levi")"""] elif CartanType(ct) == CartanType("A6"): - rul = ["""A5:branching_rule("A6","A5","levi")""", - """B3:branching_rule("A6","B3","symmetric")""", - """A1xA4:branching_rule("A6","A1xA4","levi")""", - """A2xA3:branching_rule("A6","A2xA3","levi")"""] + rul = ["""A5:branching_rule("A6","A5","levi")""", """B3:branching_rule("A6","B3","symmetric")""", """A1xA4:branching_rule("A6","A1xA4","levi")""", """A2xA3:branching_rule("A6","A2xA3","levi")"""] elif CartanType(ct) == CartanType("A7"): - rul = ["""A6:branching_rule("A7","A6","levi")""", - """C4:branching_rule("A7","C4","symmetric")""", - """D4:branching_rule("A7","D4","symmetric")""", - """A1xA3:branching_rule("A7","A1xA3","tensor")""", - """A1xA5:branching_rule("A7","A1xA5","levi")""", - """A2xA4:branching_rule("A7","A2xA4","levi")""", - """A3xA3:branching_rule("A7","A3xA3","levi")"""] + rul = ["""A6:branching_rule("A7","A6","levi")""", """C4:branching_rule("A7","C4","symmetric")""", """D4:branching_rule("A7","D4","symmetric")""", """A1xA3:branching_rule("A7","A1xA3","tensor")""", """A1xA5:branching_rule("A7","A1xA5","levi")""", """A2xA4:branching_rule("A7","A2xA4","levi")""", """A3xA3:branching_rule("A7","A3xA3","levi")"""] elif CartanType(ct) == CartanType("A8"): - rul = ["""A7:branching_rule("A8","A7","levi")""", - """B4:branching_rule("A8","B4","symmetric")""", - """A2xA2:branching_rule("A8","A2xA2","tensor")""", - """A1xA6:branching_rule("A8","A1xA6","levi")""", - """A2xA5:branching_rule("A8","A2xA5","levi")""", - """A3xA4:branching_rule("A8","A3xA4","levi")"""] + rul = ["""A7:branching_rule("A8","A7","levi")""", """B4:branching_rule("A8","B4","symmetric")""", """A2xA2:branching_rule("A8","A2xA2","tensor")""", """A1xA6:branching_rule("A8","A1xA6","levi")""", """A2xA5:branching_rule("A8","A2xA5","levi")""", """A3xA4:branching_rule("A8","A3xA4","levi")"""] elif CartanType(ct) == CartanType("B3"): - rul = ["""G2:branching_rule("B3","G2","miscellaneous")""", - """A3:branching_rule("B3","D3","extended")*branching_rule("D3","A3","isomorphic")""", - """A1xA1xA1:branching_rule("B3","D2xB1","orthogonal_sum")*branching_rule("D2xB1","A1xA1xA1",[branching_rule("D2","A1xA1","isomorphic"),branching_rule("B1","A1","isomorphic")])"""] + rul = ["""G2:branching_rule("B3","G2","miscellaneous")""", """A3:branching_rule("B3","D3","extended")*branching_rule("D3","A3","isomorphic")""", """A1xA1xA1:branching_rule("B3","D2xB1","orthogonal_sum")*branching_rule("D2xB1","A1xA1xA1",[branching_rule("D2","A1xA1","isomorphic"),branching_rule("B1","A1","isomorphic")])"""] elif CartanType(ct) == CartanType("B4"): - rul = ["""D4:branching_rule("B4","D4","extended")""", - """A1:branching_rule("B4","A1","symmetric_power")""", - """A1xA1:branching_rule("B4","B1xB1","tensor")*branching_rule("B1xB1","A1xA1",[branching_rule("B1","A1","isomorphic"),branching_rule("B1","A1","isomorphic")])""", - """A1xA1xB2:branching_rule("B4","D2xB2","extended")*branching_rule("D2xB2","A1xA1xB2",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", - """A1xA3:branching_rule("B4","B1xD3","extended")*branching_rule("B1xD3","A1xA3",[branching_rule("B1","A1","isomorphic"),branching_rule("D3","A3","isomorphic")])"""] + rul = ["""D4:branching_rule("B4","D4","extended")""", """A1:branching_rule("B4","A1","symmetric_power")""", """A1xA1:branching_rule("B4","B1xB1","tensor")*branching_rule("B1xB1","A1xA1",[branching_rule("B1","A1","isomorphic"),branching_rule("B1","A1","isomorphic")])""", """A1xA1xB2:branching_rule("B4","D2xB2","extended")*branching_rule("D2xB2","A1xA1xB2",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", """A1xA3:branching_rule("B4","B1xD3","extended")*branching_rule("B1xD3","A1xA3",[branching_rule("B1","A1","isomorphic"),branching_rule("D3","A3","isomorphic")])"""] elif CartanType(ct) == CartanType("B5"): - rul = ["""D5:branching_rule("B5","D5","extended")""", - """A1:branching_rule("B5","A1","symmetric_power")""", - """A1xA2xB3:branching_rule("B5","D2xB3","extended")*branching_rule("D2xB3","A1xA2xB3",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", - """A1xD4:branching_rule("B5","B1xD4","orthogonal_sum")*branching_rule("B1xD4","A1xD4",[branching_rule("B1","A1","isomorphic"),"identity"])""", - """A3xB2:branching_rule("B5","D3xB2","orthogonal_sum")*branching_rule("D3xB2","A3xB2",[branching_rule("D3","A3","isomorphic"),"identity"])"""] + rul = ["""D5:branching_rule("B5","D5","extended")""", """A1:branching_rule("B5","A1","symmetric_power")""", """A1xA2xB3:branching_rule("B5","D2xB3","extended")*branching_rule("D2xB3","A1xA2xB3",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", """A1xD4:branching_rule("B5","B1xD4","orthogonal_sum")*branching_rule("B1xD4","A1xD4",[branching_rule("B1","A1","isomorphic"),"identity"])""", """A3xB2:branching_rule("B5","D3xB2","orthogonal_sum")*branching_rule("D3xB2","A3xB2",[branching_rule("D3","A3","isomorphic"),"identity"])"""] elif CartanType(ct) == CartanType("B6"): - rul = ["""D6:branching_rule("B6","D6","extended")""", - """A1:branching_rule("B6","A1","symmetric_power")""", - """A1xA1xB4:branching_rule("B6","D2xB4","orthogonal_sum")*branching_rule("D2xB4","A1xA1xB4",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", - """A1xD5:branching_rule("B6","B1xD5","orthogonal_sum")*branching_rule("B1xD5","A1xD5",[branching_rule("B1","A1","isomorphic"),"identity"])""", - """A3xB3:branching_rule("B6","D3xB3","orthogonal_sum")*branching_rule("D3xB3","A3xB3",[branching_rule("D3","A3","isomorphic"),"identity"])""", - """B2xD4:branching_rule("B6","B2xD4","orthogonal_sum")"""] + rul = ["""D6:branching_rule("B6","D6","extended")""", """A1:branching_rule("B6","A1","symmetric_power")""", """A1xA1xB4:branching_rule("B6","D2xB4","orthogonal_sum")*branching_rule("D2xB4","A1xA1xB4",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", """A1xD5:branching_rule("B6","B1xD5","orthogonal_sum")*branching_rule("B1xD5","A1xD5",[branching_rule("B1","A1","isomorphic"),"identity"])""", """A3xB3:branching_rule("B6","D3xB3","orthogonal_sum")*branching_rule("D3xB3","A3xB3",[branching_rule("D3","A3","isomorphic"),"identity"])""", """B2xD4:branching_rule("B6","B2xD4","orthogonal_sum")"""] elif CartanType(ct) == CartanType("B7"): - rul = ["""D7:branching_rule("B7","D7","extended")""", - """A3:branching_rule("B7","A3(1,0,1)","plethysm")""", - """A1:branching_rule("B7","A1","symmetric_power")""", - """A1xB2:branching_rule("B7","B1xB2","tensor")*branching_rule("B1xB2","A1xB2",[branching_rule("B1","A1","isomorphic"),"identity"])""", - """A1xD6:branching_rule("B7","B1xD6","extended")*branching_rule("B1xD6","A1xD6",[branching_rule("B1","A1","isomorphic"),"identity"])""", - """A1xA1xB5:branching_rule("B7","D2xB5","extended")*branching_rule("D2xB5","A1xA1xB5",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", - """B2xD5:branching_rule("B7","B2xD5","orthogonal_sum")""", - """A3xB4:branching_rule("B7","D3xB4","orthogonal_sum")*branching_rule("D3xB4","A3xB4",[branching_rule("D3","A3","isomorphic"),"identity"])""", - """B3xD4:branching_rule("B7","B3xD4","orthogonal_sum")"""] + rul = ["""D7:branching_rule("B7","D7","extended")""", """A3:branching_rule("B7","A3(1,0,1)","plethysm")""", """A1:branching_rule("B7","A1","symmetric_power")""", """A1xB2:branching_rule("B7","B1xB2","tensor")*branching_rule("B1xB2","A1xB2",[branching_rule("B1","A1","isomorphic"),"identity"])""", """A1xD6:branching_rule("B7","B1xD6","extended")*branching_rule("B1xD6","A1xD6",[branching_rule("B1","A1","isomorphic"),"identity"])""", """A1xA1xB5:branching_rule("B7","D2xB5","extended")*branching_rule("D2xB5","A1xA1xB5",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", """B2xD5:branching_rule("B7","B2xD5","orthogonal_sum")""", """A3xB4:branching_rule("B7","D3xB4","orthogonal_sum")*branching_rule("D3xB4","A3xB4",[branching_rule("D3","A3","isomorphic"),"identity"])""", """B3xD4:branching_rule("B7","B3xD4","orthogonal_sum")"""] elif CartanType(ct) == CartanType("B8"): - rul = ["""D8:branching_rule("B8","D8","extended")""", - """A1:branching_rule("B8","A1","symmetric_power")""", - """A1xD7:branching_rule("B8","B1xD7","orthogonal_sum")*branching_rule("B1xD7","A1xD7",[branching_rule("B1","A1","isomorphic"),"identity"])""", - """A1xA1xB6:branching_rule("B8","D2xB6","orthogonal_sum")*branching_rule("D2xB6","A1xA1xB6",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", - """B2xD6:branching_rule("B8","B2xD6","orthogonal_sum")""", - """A3xB5:branching_rule("B8","D3xB5","orthogonal_sum")*branching_rule("D3xB5","A3xB5",[branching_rule("D3","A3","isomorphic"),"identity"])""", - """B3xD5:branching_rule("B8","B3xD5","orthogonal_sum")""", - """B4xD4:branching_rule("B8","B4xD4","orthogonal_sum")"""] + rul = ["""D8:branching_rule("B8","D8","extended")""", """A1:branching_rule("B8","A1","symmetric_power")""", """A1xD7:branching_rule("B8","B1xD7","orthogonal_sum")*branching_rule("B1xD7","A1xD7",[branching_rule("B1","A1","isomorphic"),"identity"])""", """A1xA1xB6:branching_rule("B8","D2xB6","orthogonal_sum")*branching_rule("D2xB6","A1xA1xB6",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", """B2xD6:branching_rule("B8","B2xD6","orthogonal_sum")""", """A3xB5:branching_rule("B8","D3xB5","orthogonal_sum")*branching_rule("D3xB5","A3xB5",[branching_rule("D3","A3","isomorphic"),"identity"])""", """B3xD5:branching_rule("B8","B3xD5","orthogonal_sum")""", """B4xD4:branching_rule("B8","B4xD4","orthogonal_sum")"""] elif CartanType(ct) == CartanType("C2"): - rul = ["""A1:branching_rule("C2","A1","symmetric_power")""", - """A1xA1:branching_rule("C2","C1xC1","orthogonal_sum")*branching_rule("C1xC1","A1xA1",[branching_rule("C1","A1","isomorphic"),branching_rule("C1","A1","isomorphic")])"""] + rul = ["""A1:branching_rule("C2","A1","symmetric_power")""", """A1xA1:branching_rule("C2","C1xC1","orthogonal_sum")*branching_rule("C1xC1","A1xA1",[branching_rule("C1","A1","isomorphic"),branching_rule("C1","A1","isomorphic")])"""] elif CartanType(ct) == CartanType("C3"): - rul = ["""A2:branching_rule("C3","A2","levi")""", - """A1:branching_rule("C3","A1","symmetric_power")""", - """A1xA1:branching_rule("C3","B1xC1","tensor")*branching_rule("B1xC1","A1xA1",[branching_rule("B1","A1","isomorphic"),branching_rule("C1","A1","isomorphic")])""", - """A1xC2:branching_rule("C3","C1xC2","orthogonal_sum")*branching_rule("C1xC2","A1xC2",[branching_rule("C1","A1","isomorphic"),"identity"])"""] + rul = ["""A2:branching_rule("C3","A2","levi")""", """A1:branching_rule("C3","A1","symmetric_power")""", """A1xA1:branching_rule("C3","B1xC1","tensor")*branching_rule("B1xC1","A1xA1",[branching_rule("B1","A1","isomorphic"),branching_rule("C1","A1","isomorphic")])""", """A1xC2:branching_rule("C3","C1xC2","orthogonal_sum")*branching_rule("C1xC2","A1xC2",[branching_rule("C1","A1","isomorphic"),"identity"])"""] elif CartanType(ct) == CartanType("C4"): - rul = ["""A3:branching_rule("C4","A3","levi")""", - """A1:branching_rule("C4","A1","symmetric_power")""", - """A1xA3:branching_rule("C4","C1xC3","orthogonal_sum")*branching_rule("C1xC3","A1xA3",[branching_rule("C1","A1","isomorphic"),"identity"])""", - """C2xC2:branching_rule("C4","C2xC2","orthogonal_sum")""", - """A1xA1xA1:branching_rule("C4","C1xD2","tensor")*branching_rule("C1xD2","A1xA1xA1",[branching_rule("C1","A1","isomorphic"),branching_rule("D2","A1xA1","isomorphic")])"""] + rul = ["""A3:branching_rule("C4","A3","levi")""", """A1:branching_rule("C4","A1","symmetric_power")""", """A1xA3:branching_rule("C4","C1xC3","orthogonal_sum")*branching_rule("C1xC3","A1xA3",[branching_rule("C1","A1","isomorphic"),"identity"])""", """C2xC2:branching_rule("C4","C2xC2","orthogonal_sum")""", """A1xA1xA1:branching_rule("C4","C1xD2","tensor")*branching_rule("C1xD2","A1xA1xA1",[branching_rule("C1","A1","isomorphic"),branching_rule("D2","A1xA1","isomorphic")])"""] elif CartanType(ct) == CartanType("C5"): - rul = ["""A4:branching_rule("C5","A4","levi")""", - """A1:branching_rule("C5","A1","symmetric_power")""", - """A1xC4:branching_rule("C5","C1xC4","orthogonal_sum")*branching_rule("C1xC4","A1xC4",[branching_rule("C1","A1","isomorphic"),"identity"])""", - """C2xC3:branching_rule("C5","C2xC3","orthogonal_sum")""", - """A1xB2:branching_rule("C5","C1xB2","tensor")*branching_rule("C1xB2","A1xB2",[branching_rule("C1","A1","isomorphic"),"identity"])"""] + rul = ["""A4:branching_rule("C5","A4","levi")""", """A1:branching_rule("C5","A1","symmetric_power")""", """A1xC4:branching_rule("C5","C1xC4","orthogonal_sum")*branching_rule("C1xC4","A1xC4",[branching_rule("C1","A1","isomorphic"),"identity"])""", """C2xC3:branching_rule("C5","C2xC3","orthogonal_sum")""", """A1xB2:branching_rule("C5","C1xB2","tensor")*branching_rule("C1xB2","A1xB2",[branching_rule("C1","A1","isomorphic"),"identity"])"""] elif CartanType(ct) == CartanType("C6"): - rul = ["""A5:branching_rule("C6","A5","levi")""", - """A1:branching_rule("C6","A1","symmetric_power")""", - """A1xA3:branching_rule("C6","C1xD3","tensor")*branching_rule("C1xD3","A1xA3",[branching_rule("C1","A1","isomorphic"),branching_rule("D3","A3","isomorphic")])""", - """A1xC2:branching_rule("C6","B1xC2","tensor")*branching_rule("B1xC2","A1xC2",[branching_rule("B1","A1","isomorphic"),"identity"])""", - """A1xC5:branching_rule("C6","C1xC5","orthogonal_sum")*branching_rule("C1xC5","A1xC5",[branching_rule("C1","A1","isomorphic"),"identity"])""", - """C2xC4:branching_rule("C6","C2xC4","orthogonal_sum")""", - """C3xC3:branching_rule("C6","C3xC3","orthogonal_sum")"""] + rul = ["""A5:branching_rule("C6","A5","levi")""", """A1:branching_rule("C6","A1","symmetric_power")""", """A1xA3:branching_rule("C6","C1xD3","tensor")*branching_rule("C1xD3","A1xA3",[branching_rule("C1","A1","isomorphic"),branching_rule("D3","A3","isomorphic")])""", """A1xC2:branching_rule("C6","B1xC2","tensor")*branching_rule("B1xC2","A1xC2",[branching_rule("B1","A1","isomorphic"),"identity"])""", """A1xC5:branching_rule("C6","C1xC5","orthogonal_sum")*branching_rule("C1xC5","A1xC5",[branching_rule("C1","A1","isomorphic"),"identity"])""", """C2xC4:branching_rule("C6","C2xC4","orthogonal_sum")""", """C3xC3:branching_rule("C6","C3xC3","orthogonal_sum")"""] elif CartanType(ct) == CartanType("C7"): - rul = ["""A6:branching_rule("C7","A6","levi")""", - """A1:branching_rule("C7","A1","symmetric_power")""", - """A1xB3:branching_rule("C7","C1xB3","tensor")*branching_rule("C1xB3","A1xB3",[branching_rule("C1","A1","isomorphic"),"identity"])""", - """A1xC6:branching_rule("C7","C1xC6","orthogonal_sum")*branching_rule("C1xC6","A1xC6",[branching_rule("C1","A1","isomorphic"),"identity"])""", - """C2xC5:branching_rule("C7","C2xC5","orthogonal_sum")""", - """C3xC4:branching_rule("C7","C3xC4","orthogonal_sum")""", - """C3:branching_rule("C7","C3(0,0,1)","plethysm") # overlooked by Patera and McKay"""] + rul = ["""A6:branching_rule("C7","A6","levi")""", """A1:branching_rule("C7","A1","symmetric_power")""", """A1xB3:branching_rule("C7","C1xB3","tensor")*branching_rule("C1xB3","A1xB3",[branching_rule("C1","A1","isomorphic"),"identity"])""", """A1xC6:branching_rule("C7","C1xC6","orthogonal_sum")*branching_rule("C1xC6","A1xC6",[branching_rule("C1","A1","isomorphic"),"identity"])""", """C2xC5:branching_rule("C7","C2xC5","orthogonal_sum")""", """C3xC4:branching_rule("C7","C3xC4","orthogonal_sum")""", """C3:branching_rule("C7","C3(0,0,1)","plethysm") # overlooked by Patera and McKay"""] elif CartanType(ct) == CartanType("C8"): - rul = ["""A7:branching_rule("C8","A7","levi")""", - """A1:branching_rule("C8","A1","symmetric_power")""", - """C2:branching_rule("C8","C2(1,1)","plethysm")""", - """A1xD4:branching_rule("C8","C1xD4","tensor")*branching_rule("C1xD4","A1xD4",[branching_rule("C1","A1","isomorphic"),"identity"])""", - """A1xC7:branching_rule("C8","C1xC7","orthogonal_sum")*branching_rule("C1xC7","A1xC7",[branching_rule("C1","A1","isomorphic"),"identity"])""", - """C2xC6:branching_rule("C8","C2xC6","orthogonal_sum")""", - """C3xC5:branching_rule("C8","C3xC5","orthogonal_sum")""", - """C4xC4:branching_rule("C8","C4xC4","orthogonal_sum")"""] + rul = ["""A7:branching_rule("C8","A7","levi")""", """A1:branching_rule("C8","A1","symmetric_power")""", """C2:branching_rule("C8","C2(1,1)","plethysm")""", """A1xD4:branching_rule("C8","C1xD4","tensor")*branching_rule("C1xD4","A1xD4",[branching_rule("C1","A1","isomorphic"),"identity"])""", """A1xC7:branching_rule("C8","C1xC7","orthogonal_sum")*branching_rule("C1xC7","A1xC7",[branching_rule("C1","A1","isomorphic"),"identity"])""", """C2xC6:branching_rule("C8","C2xC6","orthogonal_sum")""", """C3xC5:branching_rule("C8","C3xC5","orthogonal_sum")""", """C4xC4:branching_rule("C8","C4xC4","orthogonal_sum")"""] elif CartanType(ct) == CartanType("D4"): - rul = ["""B3:branching_rule("D4","B3","symmetric")""", - """A2:branching_rule("D4","A2(1,1)","plethysm")""", - """A1xC2:branching_rule("D4","C1xC2","tensor")*branching_rule("C1xC2","A1xC2",[branching_rule("C1","A1","isomorphic"),"identity"])""", - """A1xA1xA1xA1:branching_rule("D4","D2xD2","orthogonal_sum")*branching_rule("D2xD2","A1xA1xA1xA1",[branching_rule("D2","A1xA1","isomorphic"),branching_rule("D2","A1xA1","isomorphic")])"""] + rul = ["""B3:branching_rule("D4","B3","symmetric")""", """A2:branching_rule("D4","A2(1,1)","plethysm")""", """A1xC2:branching_rule("D4","C1xC2","tensor")*branching_rule("C1xC2","A1xC2",[branching_rule("C1","A1","isomorphic"),"identity"])""", """A1xA1xA1xA1:branching_rule("D4","D2xD2","orthogonal_sum")*branching_rule("D2xD2","A1xA1xA1xA1",[branching_rule("D2","A1xA1","isomorphic"),branching_rule("D2","A1xA1","isomorphic")])"""] elif CartanType(ct) == CartanType("D5"): - rul = ["""A4:branching_rule("D5","A4","levi")""", - """B4:branching_rule("D5","B4","symmetric")""", - """C2:branching_rule("D5","C2(2,0)","plethysm")""", - """A1xA1xA3:branching_rule("D5","D2xD3","orthogonal_sum")*branching_rule("D2xD3","A1xA1xA3",[branching_rule("D2","A1xA1","isomorphic"),branching_rule("D3","A3","isomorphic")])""", - """A1xA3:branching_rule("D5","B1xB3","orthogonal_sum")*branching_rule("B1xB3","A1xA3",[branching_rule("B1","A1","isomorphic"),"identity"])""", - """B2xB2:branching_rule("D5","B2xB2","orthogonal_sum")"""] + rul = ["""A4:branching_rule("D5","A4","levi")""", """B4:branching_rule("D5","B4","symmetric")""", """C2:branching_rule("D5","C2(2,0)","plethysm")""", """A1xA1xA3:branching_rule("D5","D2xD3","orthogonal_sum")*branching_rule("D2xD3","A1xA1xA3",[branching_rule("D2","A1xA1","isomorphic"),branching_rule("D3","A3","isomorphic")])""", """A1xA3:branching_rule("D5","B1xB3","orthogonal_sum")*branching_rule("B1xB3","A1xA3",[branching_rule("B1","A1","isomorphic"),"identity"])""", """B2xB2:branching_rule("D5","B2xB2","orthogonal_sum")"""] elif CartanType(ct) == CartanType("D6"): - rul = ["""A5:branching_rule("D6","A5","levi")""", - """B5:branching_rule("D6","B5","symmetric")""", - """A1xA3:branching_rule("D6","C1xC3","tensor")*branching_rule("C1xC3","A1xA3",[branching_rule("C1","A1","isomorphic"),"identity"])""", - """A1xA1xD4:branching_rule("D6","D2xD4","orthogonal_sum")*branching_rule("D2xD4","A1xA1xD4",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", - """A3xA3:branching_rule("D6","D3xD3","orthogonal_sum")*branching_rule("D3xD3","A3xA3",[branching_rule("D3","A3","isomorphic"),branching_rule("D3","A3","isomorphic")])""", - """A1xB4:branching_rule("D6","B1xB4","orthogonal_sum")*branching_rule("B1xB4","A1xB4",[branching_rule("B1","A1","isomorphic"),"identity"])""", - """B2xB3:branching_rule("D6","B2xB3","orthogonal_sum")""", - """A1xA1xA1:branching_rule("D6","B1xD2","tensor")*branching_rule("B1xD2","A1xA1xA1",[branching_rule("B1","A1","isomorphic"),branching_rule("D2","A1xA1","isomorphic")])"""] + rul = ["""A5:branching_rule("D6","A5","levi")""", """B5:branching_rule("D6","B5","symmetric")""", """A1xA3:branching_rule("D6","C1xC3","tensor")*branching_rule("C1xC3","A1xA3",[branching_rule("C1","A1","isomorphic"),"identity"])""", """A1xA1xD4:branching_rule("D6","D2xD4","orthogonal_sum")*branching_rule("D2xD4","A1xA1xD4",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", """A3xA3:branching_rule("D6","D3xD3","orthogonal_sum")*branching_rule("D3xD3","A3xA3",[branching_rule("D3","A3","isomorphic"),branching_rule("D3","A3","isomorphic")])""", """A1xB4:branching_rule("D6","B1xB4","orthogonal_sum")*branching_rule("B1xB4","A1xB4",[branching_rule("B1","A1","isomorphic"),"identity"])""", """B2xB3:branching_rule("D6","B2xB3","orthogonal_sum")""", """A1xA1xA1:branching_rule("D6","B1xD2","tensor")*branching_rule("B1xD2","A1xA1xA1",[branching_rule("B1","A1","isomorphic"),branching_rule("D2","A1xA1","isomorphic")])"""] elif CartanType(ct) == CartanType("D7"): - rul = ["""A6:branching_rule("D7","A6","levi")""", - """B6:branching_rule("D7","B6","symmetric")""", - """C3:branching_rule("D7","C3(0,1,0)","plethysm")""", - """C2:branching_rule("D7","C2(0,2)","plethysm")""", - """G2:branching_rule("D7","G2(0,1)","plethysm")""", - """A1xA1xD5:branching_rule("D7","D2xD5","orthogonal_sum")*branching_rule("D2xD5","A1xA1xD5",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", - """A3xD4:branching_rule("D7","D3xD4","orthogonal_sum")*branching_rule("D3xD4","A3xD4",[branching_rule("D3","A3","isomorphic"),"identity"])""", - """A1xB5:branching_rule("D7","B1xB5","orthogonal_sum")*branching_rule("B1xB5","A1xB5",[branching_rule("B1","A1","isomorphic"),"identity"])""", - """B2xB4:branching_rule("D7","B2xB4","orthogonal_sum")""", - """B3xB3:branching_rule("D7","B3xB3","orthogonal_sum")"""] + rul = ["""A6:branching_rule("D7","A6","levi")""", """B6:branching_rule("D7","B6","symmetric")""", """C3:branching_rule("D7","C3(0,1,0)","plethysm")""", """C2:branching_rule("D7","C2(0,2)","plethysm")""", """G2:branching_rule("D7","G2(0,1)","plethysm")""", """A1xA1xD5:branching_rule("D7","D2xD5","orthogonal_sum")*branching_rule("D2xD5","A1xA1xD5",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", """A3xD4:branching_rule("D7","D3xD4","orthogonal_sum")*branching_rule("D3xD4","A3xD4",[branching_rule("D3","A3","isomorphic"),"identity"])""", """A1xB5:branching_rule("D7","B1xB5","orthogonal_sum")*branching_rule("B1xB5","A1xB5",[branching_rule("B1","A1","isomorphic"),"identity"])""", """B2xB4:branching_rule("D7","B2xB4","orthogonal_sum")""", """B3xB3:branching_rule("D7","B3xB3","orthogonal_sum")"""] elif CartanType(ct) == CartanType("D8"): - rul = ["""A7:branching_rule("D8","A7","levi")""", - """B7:branching_rule("D8","B7","symmetric")""", - """B4:branching_rule("D8","B4(0,0,0,1)","plethysm")""", - """A1xC4:branching_rule("D8","C1xC4","tensor")*branching_rule("C1xC4","A1xC4",[branching_rule("C1","A1","isomorphic"),"identity"])""", - """A1xA1xD6:branching_rule("D8","D2xD6","orthogonal_sum")*branching_rule("D2xD6","A1xA1xD6",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", - """A3xD5:branching_rule("D8","D3xD5","orthogonal_sum")*branching_rule("D3xD5","A3xD5",[branching_rule("D3","A3","isomorphic"),"identity"])""", - """D4xD4:branching_rule("D8","D4xD4","orthogonal_sum")""", - """A1xB6:branching_rule("D8","B1xB6","orthogonal_sum")*branching_rule("B1xB6","A1xB6",[branching_rule("B1","A1","isomorphic"),"identity"])""", - """B2xB5:branching_rule("D8","B2xB5","orthogonal_sum")""", - """B3xB4:branching_rule("D8","B3xB4","orthogonal_sum")""", - """C2xC2:branching_rule("D8","C2xC2","tensor")"""] + rul = ["""A7:branching_rule("D8","A7","levi")""", """B7:branching_rule("D8","B7","symmetric")""", """B4:branching_rule("D8","B4(0,0,0,1)","plethysm")""", """A1xC4:branching_rule("D8","C1xC4","tensor")*branching_rule("C1xC4","A1xC4",[branching_rule("C1","A1","isomorphic"),"identity"])""", """A1xA1xD6:branching_rule("D8","D2xD6","orthogonal_sum")*branching_rule("D2xD6","A1xA1xD6",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", """A3xD5:branching_rule("D8","D3xD5","orthogonal_sum")*branching_rule("D3xD5","A3xD5",[branching_rule("D3","A3","isomorphic"),"identity"])""", """D4xD4:branching_rule("D8","D4xD4","orthogonal_sum")""", """A1xB6:branching_rule("D8","B1xB6","orthogonal_sum")*branching_rule("B1xB6","A1xB6",[branching_rule("B1","A1","isomorphic"),"identity"])""", """B2xB5:branching_rule("D8","B2xB5","orthogonal_sum")""", """B3xB4:branching_rule("D8","B3xB4","orthogonal_sum")""", """C2xC2:branching_rule("D8","C2xC2","tensor")"""] elif CartanType(ct) == CartanType("G2"): - rul = ["""A2:branching_rule("G2","A2","extended")""", - """A1:branching_rule("G2","A1","i")""", - """A1xA1:branching_rule("G2","A1xA1","extended")"""] + rul = ["""A2:branching_rule("G2","A2","extended")""", """A1:branching_rule("G2","A1","i")""", """A1xA1:branching_rule("G2","A1xA1","extended")"""] elif CartanType(ct) == CartanType("F4"): - rul = ["""B4:branching_rule("F4","B4","extended")""", - """A1:branching_rule("F4","A1","ii")""", - """A1xG2:branching_rule("F4","A1xG2","miscellaneous")""", - """A1xC3:branching_rule("F4","A1xC3","extended")""", - """A2xA2:branching_rule("F4","A2xA2","extended")"""] + rul = ["""B4:branching_rule("F4","B4","extended")""", """A1:branching_rule("F4","A1","ii")""", """A1xG2:branching_rule("F4","A1xG2","miscellaneous")""", """A1xC3:branching_rule("F4","A1xC3","extended")""", """A2xA2:branching_rule("F4","A2xA2","extended")"""] elif CartanType(ct) == CartanType("E6"): - rul = ["""D5:branching_rule("E6","D5","levi")""", - """C4:branching_rule("E6","C4","symmetric")""", - """F4:branching_rule("E6","F4","symmetric")""", - """A2:branching_rule("E6","A2","miscellaneous")""", - """G2:branching_rule("E6","G2","miscellaneous")""", - """A2xG2:branching_rule("E6","A2xG2","miscellaneous")""", - """A1xA5:branching_rule("E6","A1xA5","extended")""", - """A2xA2xA2:branching_rule("E6","A2xA2xA2","extended")"""] + rul = ["""D5:branching_rule("E6","D5","levi")""", """C4:branching_rule("E6","C4","symmetric")""", """F4:branching_rule("E6","F4","symmetric")""", """A2:branching_rule("E6","A2","miscellaneous")""", """G2:branching_rule("E6","G2","miscellaneous")""", """A2xG2:branching_rule("E6","A2xG2","miscellaneous")""", """A1xA5:branching_rule("E6","A1xA5","extended")""", """A2xA2xA2:branching_rule("E6","A2xA2xA2","extended")"""] elif CartanType(ct) == CartanType("E7"): - rul = ["""A7:branching_rule("E7","A7","extended")""", - """E6:branching_rule("E7","E6","levi")""", - """A2:branching_rule("E7","A2","miscellaneous")""", - """A1:branching_rule("E7","A1","iii")""", - """A1:branching_rule("E7","A1","iv")""", - """A1xF4:branching_rule("E7","A1xF4","miscellaneous")""", - """G2xC3:branching_rule("E7","G2xC3","miscellaneous")""", - """A1xG2:branching_rule("E7","A1xG2","miscellaneous")""", - """A1xA1:branching_rule("E7","A1xA1","miscellaneous")""", - """A1xD6:branching_rule("E7","A1xD6","extended")""", - """A5xA2:branching_rule("E7","A5xA2","extended")"""] + rul = ["""A7:branching_rule("E7","A7","extended")""", """E6:branching_rule("E7","E6","levi")""", """A2:branching_rule("E7","A2","miscellaneous")""", """A1:branching_rule("E7","A1","iii")""", """A1:branching_rule("E7","A1","iv")""", """A1xF4:branching_rule("E7","A1xF4","miscellaneous")""", """G2xC3:branching_rule("E7","G2xC3","miscellaneous")""", """A1xG2:branching_rule("E7","A1xG2","miscellaneous")""", """A1xA1:branching_rule("E7","A1xA1","miscellaneous")""", """A1xD6:branching_rule("E7","A1xD6","extended")""", """A5xA2:branching_rule("E7","A5xA2","extended")"""] elif CartanType(ct) == CartanType("E8"): - rul = ["""A4xA4:branching_rule("E8","A4xA4","extended")""", - """G2xF4:branching_rule("E8","G2xF4","miscellaneous")""", - """E6xA2:branching_rule("E8","E6xA2","extended")""", - """E7xA1:branching_rule("E8","E7xA1","extended")""", - """D8:branching_rule("E8","D8","extended")""", - """A8:branching_rule("E8","A8","extended")""", - """B2:branching_rule("E8","B2","miscellaneous")""", - """A1xA2:branching_rule("E8","A1xA2","miscellaneous")""", - """A1:branching_rule("E8","A1","v")""", - """A1:branching_rule("E8","A1","vi")""", - """A1:branching_rule("E8","A1","vii")"""] + rul = ["""A4xA4:branching_rule("E8","A4xA4","extended")""", """G2xF4:branching_rule("E8","G2xF4","miscellaneous")""", """E6xA2:branching_rule("E8","E6xA2","extended")""", """E7xA1:branching_rule("E8","E7xA1","extended")""", """D8:branching_rule("E8","D8","extended")""", """A8:branching_rule("E8","A8","extended")""", """B2:branching_rule("E8","B2","miscellaneous")""", """A1xA2:branching_rule("E8","A1xA2","miscellaneous")""", """A1:branching_rule("E8","A1","v")""", """A1:branching_rule("E8","A1","vi")""", """A1:branching_rule("E8","A1","vii")"""] else: raise ValueError("Argument must be an irreducible classical Cartan Type with rank less than or equal to 8") if mode == "print_rules": diff --git a/src/sage/combinat/root_system/cartan_matrix.py b/src/sage/combinat/root_system/cartan_matrix.py index e78ad279cbf..57594f526b4 100644 --- a/src/sage/combinat/root_system/cartan_matrix.py +++ b/src/sage/combinat/root_system/cartan_matrix.py @@ -8,6 +8,7 @@ - Christian Stump, Travis Scrimshaw (2013-04-13): Created :class:`CartanMatrix`. - Ben Salisbury (2018-08-07): Added Borcherds-Cartan matrices. """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # Copyright (C) 2012,2013 Travis Scrimshaw , @@ -49,8 +50,7 @@ from sage.matrix.matrix_generic_sparse import Matrix_generic_sparse as Base -class CartanMatrix(Base, CartanType_abstract, - metaclass=InheritComparisonClasscallMetaclass): +class CartanMatrix(Base, CartanType_abstract, metaclass=InheritComparisonClasscallMetaclass): r""" A (generalized) Cartan matrix. @@ -233,10 +233,9 @@ class CartanMatrix(Base, CartanType_abstract, :meth:`row_with_indices()` and :meth:`column_with_indices()` respectively. """ + @staticmethod - def __classcall_private__(cls, data=None, index_set=None, - cartan_type=None, cartan_type_check=True, - borcherds=None): + def __classcall_private__(cls, data=None, index_set=None, cartan_type=None, cartan_type_check=True, borcherds=None): """ Normalize input so we can inherit from sparse integer matrix. @@ -279,7 +278,7 @@ def __classcall_private__(cls, data=None, index_set=None, subdivisions = None elif isinstance(data, CartanMatrix): if index_set is not None: - d = {a: index_set[i] for i,a in enumerate(data.index_set())} + d = {a: index_set[i] for i, a in enumerate(data.index_set())} return data.relabel(d) return data else: @@ -300,19 +299,14 @@ def __classcall_private__(cls, data=None, index_set=None, n = dynkin_diagram.rank() index_set = dynkin_diagram.index_set() oir = dynkin_diagram.odd_isotropic_roots() - reverse = {a: i for i,a in enumerate(index_set)} + reverse = {a: i for i, a in enumerate(index_set)} if isinstance(borcherds, (list, tuple)): - if (len(borcherds) != len(index_set) - and not all(val in ZZ - and (val == 2 or (val % 2 == 0 and val < 0)) - for val in borcherds)): + if len(borcherds) != len(index_set) and not all(val in ZZ and (val == 2 or (val % 2 == 0 and val < 0)) for val in borcherds): raise ValueError("the input data is not a Borcherds-Cartan matrix") - data = {(i, i): val if index_set[i] not in oir else 0 - for i,val in enumerate(borcherds)} + data = {(i, i): val if index_set[i] not in oir else 0 for i, val in enumerate(borcherds)} else: - data = {(i, i): 2 if index_set[i] not in oir else 0 - for i in range(n)} - for (i,j,l) in dynkin_diagram.edge_iterator(): + data = {(i, i): 2 if index_set[i] not in oir else 0 for i in range(n)} + for i, j, l in dynkin_diagram.edge_iterator(): data[(reverse[j], reverse[i])] = -l else: M = matrix(data) @@ -377,6 +371,7 @@ def matrix_space(self, nrows=None, ncols=None, sparse=None): if nrows == self.nrows() and ncols == self.ncols() and sparse: return self.parent() from sage.matrix.matrix_space import MatrixSpace + return MatrixSpace(ZZ, nrows, ncols, sparse is None or bool(sparse)) def _CM_init(self, cartan_type, index_set, cartan_type_check): @@ -475,11 +470,12 @@ def reflection_group(self, type='matrix'): Phi = RS.roots() gens = {} from sage.groups.perm_gps.permgroup_named import SymmetricGroup + S = SymmetricGroup(len(Phi)) for i in self.index_set(): - pi = S([ Phi.index( beta.simple_reflection(i) ) + 1 for beta in Phi ]) + pi = S([Phi.index(beta.simple_reflection(i)) + 1 for beta in Phi]) gens[i] = pi - return S.subgroup( gens[i] for i in gens ) + return S.subgroup(gens[i] for i in gens) raise ValueError("the reflection group is only available as a matrix group or as a permutation group") @@ -512,8 +508,9 @@ def symmetrizer(self): # to integer coefficients from sage.arith.functions import lcm as LCM from sage.rings.rational_field import QQ + scalar = LCM([QQ(x).denominator() for x in sym]) - return Family( {iset[i]: ZZ(val*scalar) for i, val in enumerate(sym)} ) + return Family({iset[i]: ZZ(val * scalar) for i, val in enumerate(sym)}) @cached_method def symmetrized_matrix(self): @@ -657,6 +654,7 @@ def dynkin_diagram(self): Dynkin diagram of rank 2 """ from sage.combinat.root_system.dynkin_diagram import DynkinDiagram + if self._cartan_type is not None: return DynkinDiagram(self._cartan_type) return DynkinDiagram(self) @@ -729,7 +727,7 @@ def is_simply_laced(self): True """ for i in range(self.nrows()): - for j in range(i+1, self.ncols()): + for j in range(i + 1, self.ncols()): if self[i, j] < -1 or self[j, i] < -1: return False return True @@ -829,8 +827,7 @@ def is_affine(self) -> bool: if self.det() != 0: return False for b in self.indecomposable_blocks(): - if b.det() < 0 or not all( - a.det() > 0 for a in b.principal_submatrices(proper=True)): + if b.det() < 0 or not all(a.det() > 0 for a in b.principal_submatrices(proper=True)): return False return True return self._cartan_type.is_affine() @@ -871,7 +868,7 @@ def is_hyperbolic(self, compact=False): D = self.dynkin_diagram() verts = tuple(D.vertex_iterator()) for v in verts: - l = set(verts)-set((v,)) + l = set(verts) - set((v,)) subg = D.subgraph(vertices=l) if compact and not subg.is_finite(): return False @@ -964,15 +961,16 @@ def coxeter_matrix(self): """ scalarproducts_to_order = {0: 2, 1: 3, 2: 4, 3: 6} from sage.combinat.root_system.coxeter_matrix import CoxeterMatrix + I = self.index_set() n = len(I) M = matrix.identity(ZZ, n) for i in range(n): - for j in range(i+1,n): - val = self[i,j] * self[j,i] + for j in range(i + 1, n): + val = self[i, j] * self[j, i] val = scalarproducts_to_order.get(val, -1) - M[i,j] = val - M[j,i] = val + M[i, j] = val + M[j, i] = val return CoxeterMatrix(M, index_set=self.index_set(), cartan_type=self) @cached_method @@ -1021,7 +1019,7 @@ def principal_submatrices(self, proper=False): ret = [] for l in powerset(iset): if not proper or (proper and l != iset): - ret.append(self.matrix_from_rows_and_columns(l,l)) + ret.append(self.matrix_from_rows_and_columns(l, l)) return ret @cached_method @@ -1078,16 +1076,16 @@ def is_borcherds_cartan_matrix(M): return False n = M.ncols() for i in range(n): - if M[i,i] == 0: + if M[i, i] == 0: return False - if M[i,i] % 2 == 1: + if M[i, i] % 2 == 1: return False - for j in range(i+1, n): - if M[i,j] > 0 or M[j,i] > 0: + for j in range(i + 1, n): + if M[i, j] > 0 or M[j, i] > 0: return False - if M[i,j] == 0 and M[j,i] != 0: + if M[i, j] == 0 and M[j, i] != 0: return False - if M[j,i] == 0 and M[i,j] != 0: + if M[j, i] == 0 and M[i, j] != 0: return False return True @@ -1119,7 +1117,7 @@ def is_generalized_cartan_matrix(M): if not is_borcherds_cartan_matrix(M): return False n = M.ncols() - return all(M[i,i] == 2 for i in range(n)) + return all(M[i, i] == 2 for i in range(n)) def find_cartan_type_from_matrix(CM): @@ -1171,7 +1169,7 @@ def find_cartan_type_from_matrix(CM): types = [] relabel = [] for S in CM.dynkin_diagram().connected_components_subgraphs(): - S = DiGraph(S) # We need a simple digraph here + S = DiGraph(S) # We need a simple digraph here n = S.n_vertices() # Build the list to test based upon rank if n == 1: @@ -1182,34 +1180,34 @@ def find_cartan_type_from_matrix(CM): test = [['A', n]] if n >= 2: if n == 2: - test += [['G',2], ['A',2,2]] - test += [['B',n], ['A',n-1,1]] + test += [['G', 2], ['A', 2, 2]] + test += [['B', n], ['A', n - 1, 1]] if n >= 3: if n == 3: - test.append(['G',2,1]) - test += [['C',n], ['BC',n-1,2], ['C',n-1,1]] + test.append(['G', 2, 1]) + test += [['C', n], ['BC', n - 1, 2], ['C', n - 1, 1]] if n >= 4: if n == 4: - test.append(['F',4]) - test += [['D',n], ['B',n-1,1]] + test.append(['F', 4]) + test += [['D', n], ['B', n - 1, 1]] if n >= 5: if n == 5: - test.append(['F',4,1]) - test.append(['D',n-1,1]) + test.append(['F', 4, 1]) + test.append(['D', n - 1, 1]) if n == 6: - test.append(['E',6]) + test.append(['E', 6]) elif n == 7: - test += [['E',7], ['E',6,1]] + test += [['E', 7], ['E', 6, 1]] elif n == 8: - test += [['E',8], ['E',7,1]] + test += [['E', 8], ['E', 7, 1]] elif n == 9: - test.append(['E',8,1]) + test.append(['E', 8, 1]) # Test every possible Cartan type and its dual found = False for x in test: ct = CartanType(x) - T = DiGraph(ct.dynkin_diagram()) # We need a simple digraph here + T = DiGraph(ct.dynkin_diagram()) # We need a simple digraph here iso, match = T.is_isomorphic(S, certificate=True, edge_labels=True) if iso: types.append(ct) @@ -1218,10 +1216,10 @@ def find_cartan_type_from_matrix(CM): break if ct == ct.dual(): - continue # self-dual, so nothing more to test + continue # self-dual, so nothing more to test ct = ct.dual() - T = DiGraph(ct.dynkin_diagram()) # We need a simple digraph here + T = DiGraph(ct.dynkin_diagram()) # We need a simple digraph here iso, match = T.is_isomorphic(S, certificate=True, edge_labels=True) if iso: types.append(ct) diff --git a/src/sage/combinat/root_system/cartan_type.py b/src/sage/combinat/root_system/cartan_type.py index 547e69f1d87..85e9e56236d 100644 --- a/src/sage/combinat/root_system/cartan_type.py +++ b/src/sage/combinat/root_system/cartan_type.py @@ -464,6 +464,7 @@ .. TODO:: Should those indexes come before the introduction? """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # Copyright (C) 2008-2009 Nicolas M. Thiery , @@ -499,6 +500,7 @@ # Implementation: CartanType is the unique instance of this class # CartanTypeFactory. Is there a better/more standard way to do it? + class CartanTypeFactory(SageObject): def __call__(self, *args): @@ -586,7 +588,7 @@ def __call__(self, *args): if hasattr(t, "cartan_type"): return t.cartan_type() - if len(t) == 1: # Fix for trac #13774 + if len(t) == 1: # Fix for trac #13774 t = t[0] # We need to make another check @@ -594,9 +596,11 @@ def __call__(self, *args): return t from sage.rings.semirings.non_negative_integer_semiring import NN + if isinstance(t, str): if "x" in t: from . import type_reducible + return type_reducible.CartanType([CartanType(u) for u in t.split("x")]) if t[-1] == "*": return CartanType(t[:-1]).dual() @@ -606,6 +610,7 @@ def __call__(self, *args): return CartanType(['A', Infinity]) if t == "A+oo": from . import type_A_infinity + return type_A_infinity.CartanType(NN) return CartanType([t[0], eval(t[1:])]) @@ -614,6 +619,7 @@ def __call__(self, *args): letter, n = t[0], t[1] if letter == 'A': from . import type_A_infinity + if t[1] == NN: return type_A_infinity.CartanType(NN) return type_A_infinity.CartanType(ZZ) @@ -624,34 +630,42 @@ def __call__(self, *args): if letter == "A": if n >= 0: from . import type_A + return type_A.CartanType(n) if letter == "B": if n >= 1: from . import type_B + return type_B.CartanType(n) if letter == "C": if n >= 1: from . import type_C + return type_C.CartanType(n) if letter == "D": from . import type_D + if n >= 2: return type_D.CartanType(n) if letter == "E": if n >= 6 and n <= 8: from . import type_E + return type_E.CartanType(n) if letter == "F": if n == 4: from . import type_F + return type_F.CartanType() if letter == "G": if n == 2: from . import type_G + return type_G.CartanType() if letter == "H": if n in [3, 4]: from . import type_H + return type_H.CartanType(n) if letter == "I": if n == 1: @@ -664,56 +678,66 @@ def __call__(self, *args): return CartanType(["G", 2]) if n >= 1: from . import type_I + return type_I.CartanType(n) if letter == "Q": if n >= 1: from . import type_Q + return type_Q.CartanType(n) if len(t) == 3: - if t[2] == 1: # Untwisted affine + if t[2] == 1: # Untwisted affine if letter == "A": if n >= 1: from . import type_A_affine + return type_A_affine.CartanType(n) if letter == "B": if n >= 1: from . import type_B_affine + return type_B_affine.CartanType(n) if letter == "C": if n >= 1: from . import type_C_affine + return type_C_affine.CartanType(n) if letter == "D": from . import type_D_affine + if n >= 3: return type_D_affine.CartanType(n) if letter == "E": if n >= 6 and n <= 8: from . import type_E_affine + return type_E_affine.CartanType(n) if letter == "F": if n == 4: from . import type_F_affine + return type_F_affine.CartanType() if letter == "G": if n == 2: from . import type_G_affine + return type_G_affine.CartanType() - if t[2] in [2,3]: + if t[2] in [2, 3]: if letter == "BC" and t[2] == 2: if n >= 1: from . import type_BC_affine + return type_BC_affine.CartanType(n) if letter == "A" and t[2] == 2: - if n % 2 == 0: # Kac' A_2n^(2) - return CartanType(["BC", ZZ(n//2), 2]) + if n % 2 == 0: # Kac' A_2n^(2) + return CartanType(["BC", ZZ(n // 2), 2]) # Kac' A_2n-1^(2) - return CartanType(["B", ZZ((n+1)//2), 1]).dual() + return CartanType(["B", ZZ((n + 1) // 2), 1]).dual() if letter == "D" and t[2] == 2: - return CartanType(["C", n-1, 1]).dual() + return CartanType(["C", n - 1, 1]).dual() if letter == "D" and t[2] == 3 and n == 4: - return CartanType(["G", 2, 1]).dual().relabel([0,2,1]) + return CartanType(["G", 2, 1]).dual().relabel([0, 2, 1]) if letter == "E" and t[2] == 2 and n == 6: return CartanType(["F", 4, 1]).dual() raise ValueError("%s is not a valid Cartan type" % t) @@ -722,14 +746,16 @@ def __call__(self, *args): letter, n = t[0], t[1] if len(t) == 2 and len(n) == 2: from . import type_super_A + return type_super_A.CartanType(n[0], n[1]) raise ValueError("%s is not a valid super Cartan type" % t) # As the Cartan type has not been recognised try subtypes - but check # for the error noted in trac:??? from . import type_reducible + try: - return type_reducible.CartanType([ CartanType(subtype) for subtype in t ]) + return type_reducible.CartanType([CartanType(subtype) for subtype in t]) except (SyntaxError, ValueError): raise ValueError("%s is not a valid Cartan type" % t) @@ -801,7 +827,7 @@ def samples(self, finite=None, affine=None, crystallographic=None): """ result = self._samples() if crystallographic is not None: - result = [t for t in result if t.is_crystallographic() == crystallographic ] + result = [t for t in result if t.is_crystallographic() == crystallographic] if finite is not None: result = [t for t in result if t.is_finite() == finite] if affine is not None: @@ -825,31 +851,15 @@ def _samples(self): ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['BC', 1, 2], ['BC', 5, 2], ['B', 5, 1]^*, ['C', 4, 1]^*, ['F', 4, 1]^*, ['G', 2, 1]^*, ['BC', 1, 2]^*, ['BC', 5, 2]^*] """ - finite_crystallographic = [CartanType(t) - for t in [['A', 1], ['A', 5], ['B', 1], ['B', 5], - ['C', 1], ['C', 5], ['D', 2], ['D', 3], ['D', 5], - ["E", 6], ["E", 7], ["E", 8], - ["F", 4], - ["G", 2]]] + finite_crystallographic = [CartanType(t) for t in [['A', 1], ['A', 5], ['B', 1], ['B', 5], ['C', 1], ['C', 5], ['D', 2], ['D', 3], ['D', 5], ["E", 6], ["E", 7], ["E", 8], ["F", 4], ["G", 2]]] # Support for hand constructed Dynkin diagrams as Cartan types is not yet ready enough for including an example here. # from sage.combinat.root_system.dynkin_diagram import DynkinDiagram_class # g = DynkinDiagram_class.an_instance() - return finite_crystallographic + \ - [CartanType(t) for t in [["I", 5], ["H", 3], ["H", 4]]] + \ - [t.affine() for t in finite_crystallographic if t.is_irreducible()] + \ - [CartanType(t) for t in [["BC", 1, 2], ["BC", 5, 2]]] + \ - [CartanType(t).dual() for t in [["B", 5, 1], ["C", 4, 1], - ["F", 4, 1], ["G", 2, 1], - ["BC", 1, 2], ["BC", 5, 2]]] # + \ - # [ g ] - - _colors = {1: 'blue', -1: 'blue', - 2: 'red', -2: 'red', - 3: 'green', -3: 'green', - 4: 'cyan', -4: 'cyan', - 5: 'magenta', -5: 'magenta', - 6: 'yellow', -6: 'yellow'} + return finite_crystallographic + [CartanType(t) for t in [["I", 5], ["H", 3], ["H", 4]]] + [t.affine() for t in finite_crystallographic if t.is_irreducible()] + [CartanType(t) for t in [["BC", 1, 2], ["BC", 5, 2]]] + [CartanType(t).dual() for t in [["B", 5, 1], ["C", 4, 1], ["F", 4, 1], ["G", 2, 1], ["BC", 1, 2], ["BC", 5, 2]]] # + \ + # [ g ] + + _colors = {1: 'blue', -1: 'blue', 2: 'red', -2: 'red', 3: 'green', -3: 'green', 4: 'cyan', -4: 'cyan', 5: 'magenta', -5: 'magenta', 6: 'yellow', -6: 'yellow'} @classmethod def color(cls, i): @@ -935,38 +945,18 @@ class options(GlobalOptions): A8^2+ sage: CartanType.options._reset() """ + NAME = 'CartanType' module = 'sage.combinat.root_system.cartan_type' option_class = 'CartanTypeFactory' - notation = dict(default='Stembridge', - description='Specifies which notation Cartan types should use when printed', - values=dict(Stembridge="use Stembridge's notation", - Kac="use Kac's notation"), - case_sensitive=False, - alias=dict(BC='Stembridge', tilde='Stembridge', twisted='Kac')) - dual_str = dict(default='*', - description='The string used for dual Cartan types when printing', - checker=lambda char: isinstance(char, str)) - dual_latex = dict(default='\\vee', - description='The latex used for dual CartanTypes when latexing', - checker=lambda char: isinstance(char, str)) - mark_special_node = dict(default='none', - description="Make the special nodes", - values=dict(none="no markup", latex="only in latex", - printing="only in printing", both="both in latex and printing"), - case_sensitive=False) - special_node_str = dict(default='@', - description="The string used to indicate which node is special when printing", - checker=lambda char: isinstance(char, str)) - marked_node_str = dict(default='X', - description="The string used to indicate a marked node when printing", - checker=lambda char: isinstance(char, str)) - latex_relabel = dict(default=True, - description="Indicate in the latex output if a Cartan type has been relabelled", - checker=lambda x: isinstance(x, bool)) - latex_marked = dict(default=True, - description="Indicate in the latex output if a Cartan type has been marked", - checker=lambda x: isinstance(x, bool)) + notation = dict(default='Stembridge', description='Specifies which notation Cartan types should use when printed', values=dict(Stembridge="use Stembridge's notation", Kac="use Kac's notation"), case_sensitive=False, alias=dict(BC='Stembridge', tilde='Stembridge', twisted='Kac')) + dual_str = dict(default='*', description='The string used for dual Cartan types when printing', checker=lambda char: isinstance(char, str)) + dual_latex = dict(default='\\vee', description='The latex used for dual CartanTypes when latexing', checker=lambda char: isinstance(char, str)) + mark_special_node = dict(default='none', description="Make the special nodes", values=dict(none="no markup", latex="only in latex", printing="only in printing", both="both in latex and printing"), case_sensitive=False) + special_node_str = dict(default='@', description="The string used to indicate which node is special when printing", checker=lambda char: isinstance(char, str)) + marked_node_str = dict(default='X', description="The string used to indicate a marked node when printing", checker=lambda char: isinstance(char, str)) + latex_relabel = dict(default=True, description="Indicate in the latex output if a Cartan type has been relabelled", checker=lambda x: isinstance(x, bool)) + latex_marked = dict(default=True, description="Indicate in the latex output if a Cartan type has been marked", checker=lambda x: isinstance(x, bool)) CartanType = CartanTypeFactory() @@ -1031,11 +1021,12 @@ def _add_abstract_superclass(self, classes): .. TODO:: Generalize to :class:`SageObject`? """ from sage.structure.dynamic_class import dynamic_class + assert isinstance(classes, (tuple, type)) if not isinstance(classes, tuple): classes = (classes,) bases = (self.__class__,) + classes - self.__class__ = dynamic_class(self.__class__.__name__+"_with_superclass", bases) + self.__class__ = dynamic_class(self.__class__.__name__ + "_with_superclass", bases) def _ascii_art_node(self, label): """ @@ -1061,8 +1052,7 @@ def _latex_draw_node(self, x, y, label, position='below=4pt', fill='white'): sage: CartanType(['A',3])._latex_draw_node(0, 0, 1) '\\draw[fill=white] (0 cm, 0 cm) circle (.25cm) node[below=4pt]{$1$};\n' """ - return "\\draw[fill={}] ({} cm, {} cm) circle (.25cm) node[{}]{{${}$}};\n".format( - fill, x, y, position, label) + return "\\draw[fill={}] ({} cm, {} cm) circle (.25cm) node[{}]{{${}$}};\n".format(fill, x, y, position, label) def _latex_draw_arrow_tip(self, x, y, rot=0): r""" @@ -1101,7 +1091,7 @@ def rank(self): sage: CartanType(['I', 8]).rank() 2 """ - #return len(self.index_set()) + # return len(self.index_set()) @abstract_method def index_set(self): @@ -1139,7 +1129,7 @@ def index_set(self): # This coloring scheme is used for crystal graphs and will eventually # be used for Coxeter groups etc. (experimental feature) - _index_set_coloring = {1:"blue", 2:"red", 3:"green"} + _index_set_coloring = {1: "blue", 2: "red", 3: "green"} @abstract_method(optional=True) def coxeter_diagram(self): @@ -1175,6 +1165,7 @@ def coxeter_matrix(self): [2 2 3 1] """ from sage.combinat.root_system.coxeter_matrix import CoxeterMatrix + return CoxeterMatrix(self) def coxeter_type(self): @@ -1187,6 +1178,7 @@ def coxeter_type(self): Coxeter type of ['A', 4] """ from sage.combinat.root_system.coxeter_type import CoxeterType + return CoxeterType(self) def dual(self): @@ -1209,6 +1201,7 @@ def dual(self): ['F', 4] relabelled by {1: 4, 2: 3, 3: 2, 4: 1} """ from . import type_dual + return type_dual.CartanType(self) def relabel(self, relabelling): @@ -1234,6 +1227,7 @@ def relabel(self, relabelling): F4 relabelled by {1: 4, 2: 3, 3: 2, 4: 1} """ from . import type_relabel + return type_relabel.CartanType(self, relabelling) def subtype(self, index_set): @@ -1273,6 +1267,7 @@ def marked_nodes(self, marked_nodes): if not marked_nodes: return self from . import type_marked + return type_marked.CartanType(self, marked_nodes) def is_reducible(self) -> bool: @@ -1458,6 +1453,7 @@ def root_system(self): Root system of type ['A', 4] """ from sage.combinat.root_system.root_system import RootSystem + return RootSystem(self) def as_folding(self, folding_of=None, sigma=None): @@ -1503,6 +1499,7 @@ def as_folding(self, folding_of=None, sigma=None): ['G', 2, 1]^* relabelled by {0: 0, 1: 2, 2: 1} as a folding of ['D', 4, 1] """ from sage.combinat.root_system.type_folded import CartanTypeFolded + if folding_of is None and sigma is None: return self._default_folded_cartan_type() if folding_of is None or sigma is None: @@ -1523,6 +1520,7 @@ def _default_folded_cartan_type(self): Dynkin diagram of rank 2 as a folding of Dynkin diagram of rank 2 """ from sage.combinat.root_system.type_folded import CartanTypeFolded + return CartanTypeFolded(self, self, [[i] for i in self.index_set()]) options = CartanType.options @@ -1532,6 +1530,7 @@ class CartanType_crystallographic(CartanType_abstract): """ An abstract class for crystallographic Cartan types. """ + # The default value should really be lambda x:x, but sphinx does # not like it currently (see #14553); since this is an abstract method # the value won't actually be used, so we put a fake instead. @@ -1574,8 +1573,7 @@ def ascii_art(self, label='lambda x: x', node=None): # not like it currently (see #14553); since this is an abstract method # the value won't actually be used, so we put a fake instead. @abstract_method(optional=True) - def _latex_dynkin_diagram(self, label='lambda i: i', - node=None, node_dist=2): + def _latex_dynkin_diagram(self, label='lambda i: i', node=None, node_dist=2): r""" Return a latex representation of the Dynkin diagram. @@ -1633,6 +1631,7 @@ def cartan_matrix(self): [ 0 0 -1 2] """ from sage.combinat.root_system.cartan_matrix import CartanMatrix + return CartanMatrix(self.dynkin_diagram()) def coxeter_diagram(self): @@ -1735,6 +1734,7 @@ def symmetrizer(self): 2 2 2 2 4 """ from sage.matrix.constructor import matrix, diagonal_matrix + m = self.cartan_matrix() n = m.nrows() M = matrix(ZZ, n, n * n, sparse=True) @@ -1778,6 +1778,7 @@ def index_set_bipartition(self): ValueError: the Dynkin diagram must be bipartite """ from sage.graphs.graph import Graph + G = Graph(self.dynkin_diagram()) if not G.is_bipartite(): raise ValueError("the Dynkin diagram must be bipartite") @@ -1884,8 +1885,7 @@ def _ascii_art_node(self, label): '@' sage: CartanType.options._reset() """ - if (label == self.special_node() - and self.options('mark_special_node') in ['printing', 'both']): + if label == self.special_node() and self.options('mark_special_node') in ['printing', 'both']: return self.options('special_node_str') return super()._ascii_art_node(label) @@ -2127,7 +2127,7 @@ def row_annihilator(self, m=None): annihilator_basis = m.integer_kernel().gens() if len(annihilator_basis) != 1: raise ValueError("the kernel is not 1 dimensional") - assert (all(coef > 0 for coef in annihilator_basis[0])) + assert all(coef > 0 for coef in annihilator_basis[0]) return Family({i: annihilator_basis[0][i] for i in self.index_set()}) @@ -2203,8 +2203,7 @@ def c(self): """ a = self.a() acheck = self.acheck() - return Family({i: max(ZZ.one(), a[i] // acheck[i]) - for i in self.index_set()}) + return Family({i: max(ZZ.one(), a[i] // acheck[i]) for i in self.index_set()}) def translation_factors(self): r""" @@ -2381,8 +2380,7 @@ def translation_factors(self): if ~ZZ(2) in s and 2 in s: # The test above and the formula below are rather meaningless # But they detect properly type BC or dual and return the correct value - return Family({i: min(ZZ.one(), a[i] / acheck[i]) - for i in self.index_set()}) + return Family({i: min(ZZ.one(), a[i] / acheck[i]) for i in self.index_set()}) return self.c() @@ -2425,6 +2423,7 @@ def other_affinization(self): assert result.classical() is self.classical() return result + ############################################################################## # Concrete base classes @@ -2507,20 +2506,20 @@ def __init__(self, letter, n): running ._test_not_implemented_methods() . . . pass running ._test_pickling() . . . pass """ -# assert(t[0] in ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']) -# assert(t[1] in ZZ and t[1] >= 0) -# if t[0] in ['B', 'C']: -# assert(t[1] >= 2) -# if t[0] == 'D': -# assert(t[1] >= 3) -# if t[0] == 'E': -# assert(t[1] <= 8) -# if t[0] == 'F': -# assert(t[1] <= 4) -# if t[0] == 'G': -# assert(t[1] <= 2) -# if t[0] == 'H': -# assert(t[1] <= 4) + # assert(t[0] in ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']) + # assert(t[1] in ZZ and t[1] >= 0) + # if t[0] in ['B', 'C']: + # assert(t[1] >= 2) + # if t[0] == 'D': + # assert(t[1] >= 3) + # if t[0] == 'E': + # assert(t[1] <= 8) + # if t[0] == 'F': + # assert(t[1] <= 4) + # if t[0] == 'G': + # assert(t[1] <= 2) + # if t[0] == 'H': + # assert(t[1] <= 4) self.letter = letter self.n = n @@ -2561,7 +2560,7 @@ def index_set(self): sage: CartanType(['A', 5]).index_set() (1, 2, 3, 4, 5) """ - return tuple(range(1,self.n+1)) + return tuple(range(1, self.n + 1)) def rank(self): """ @@ -2679,6 +2678,7 @@ def opposition_automorphism(self): d = {i: (w0.action(alpha[i])).leading_support() for i in self.index_set()} return Family(d) + ########################################################################## @@ -2706,7 +2706,7 @@ def __init__(self, letter, n, affine=1): sage: ct1 == ct3 False """ - assert (letter in ['A', 'B', 'C', 'BC', 'D', 'E', 'F', 'G']) + assert letter in ['A', 'B', 'C', 'BC', 'D', 'E', 'F', 'G'] self.letter = letter self.n = n self.affine = affine @@ -2805,7 +2805,7 @@ def rank(self): sage: CartanType(['D', 4, 3]).rank() 3 """ - return self.n+1 + return self.n + 1 def index_set(self): r""" @@ -2819,7 +2819,7 @@ def index_set(self): sage: CartanType(['A', 5, 1]).index_set() (0, 1, 2, 3, 4, 5) """ - return tuple(range(self.n+1)) + return tuple(range(self.n + 1)) def special_node(self): r""" @@ -2846,6 +2846,7 @@ def type(self): """ return self.letter + ########################################################################## @@ -2875,7 +2876,7 @@ def classical(self): sage: CartanType(['G', 2, 1]).classical() ['G', 2] """ - return CartanType([self.letter,self.n]) + return CartanType([self.letter, self.n]) def basic_untwisted(self): r""" @@ -2930,7 +2931,8 @@ def _latex_(self): sage: latex(CartanType(['G',2,1])) G_2^{(1)} """ - return self.classical()._latex_()+"^{(1)}" + return self.classical()._latex_() + "^{(1)}" + ########################################################################## @@ -3011,6 +3013,7 @@ def index_set(self): """ return self._type.index_set() + ############################################################################## # Base concrete class for superalgebras diff --git a/src/sage/combinat/root_system/coxeter_group.py b/src/sage/combinat/root_system/coxeter_group.py index 9d671213d1d..684f8e4b0a6 100644 --- a/src/sage/combinat/root_system/coxeter_group.py +++ b/src/sage/combinat/root_system/coxeter_group.py @@ -1,6 +1,7 @@ """ Coxeter groups """ + # *************************************************************************** # Copyright (C) 2010 Nicolas Thiery # @@ -125,7 +126,7 @@ def CoxeterGroup(data, implementation='reflection', base_ring=None, index_set=No try: cartan_type = CartanType(data) - except (TypeError, ValueError): # If it is not a Cartan type, try to see if we can represent it as a matrix group + except (TypeError, ValueError): # If it is not a Cartan type, try to see if we can represent it as a matrix group return CoxeterMatrixGroup(data, base_ring, index_set) if implementation is None: @@ -157,4 +158,5 @@ def CoxeterGroup(data, implementation='reflection', base_ring=None, index_set=No from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.combinat.root_system.coxeter_group', 'CoxeterGroupAsPermutationGroup', ReflectionGroup) diff --git a/src/sage/combinat/root_system/coxeter_matrix.py b/src/sage/combinat/root_system/coxeter_matrix.py index e40c45b2501..f85e7596696 100644 --- a/src/sage/combinat/root_system/coxeter_matrix.py +++ b/src/sage/combinat/root_system/coxeter_matrix.py @@ -115,9 +115,9 @@ class CoxeterMatrix(CoxeterType, metaclass=ClasscallMetaclass): [ 1 -3/2] [-3/2 1] """ + @staticmethod - def __classcall_private__(cls, data=None, index_set=None, coxeter_type=None, - cartan_type=None, coxeter_type_check=True): + def __classcall_private__(cls, data=None, index_set=None, coxeter_type=None, cartan_type=None, coxeter_type_check=True): r""" A Coxeter matrix can we created via a graph, a Coxeter type, or a matrix. @@ -184,6 +184,7 @@ def __classcall_private__(cls, data=None, index_set=None, coxeter_type=None, # Get the Coxeter type coxeter_type = None from sage.combinat.root_system.cartan_type import CartanType_abstract + if isinstance(data, CartanType_abstract): coxeter_type = data.coxeter_type() else: @@ -247,12 +248,10 @@ def __init__(self, parent, data, coxeter_type, index_set): self._index_set = index_set self._rank = self._matrix.nrows() - self._dict = {(self._index_set[i], self._index_set[j]): self._matrix[i, j] - for i in range(self._rank) for j in range(self._rank)} + self._dict = {(self._index_set[i], self._index_set[j]): self._matrix[i, j] for i in range(self._rank) for j in range(self._rank)} for i, key in enumerate(self._index_set): - self._dict[key] = {key2: self._matrix[i, j] - for j, key2 in enumerate(self._index_set)} + self._dict[key] = {key2: self._matrix[i, j] for j, key2 in enumerate(self._index_set)} @classmethod def _from_matrix(cls, data, coxeter_type, index_set, coxeter_type_check): @@ -300,8 +299,7 @@ def _from_matrix(cls, data, coxeter_type, index_set, coxeter_type_check): raw_data = M.list() - mat = typecall(cls, MatrixSpace(base_ring, n, sparse=False), raw_data, - coxeter_type, index_set) + mat = typecall(cls, MatrixSpace(base_ring, n, sparse=False), raw_data, coxeter_type, index_set) mat._subdivisions = M._subdivisions return mat @@ -390,7 +388,7 @@ def _from_coxetertype(cls, coxeter_type): n = len(index_set) reverse = {index_set[i]: i for i in range(n)} data = [[1 if i == j else 2 for j in range(n)] for i in range(n)] - for (i, j, l) in coxeter_type.coxeter_graph().edge_iterator(): + for i, j, l in coxeter_type.coxeter_graph().edge_iterator(): if l == infinity: l = -1 data[reverse[i]][reverse[j]] = l @@ -557,19 +555,11 @@ def _samples(self): [3 7 1], [ 2 3 -8 1] ] """ - finite = [CoxeterMatrix(t) for t in [['A', 1], ['A', 5], ['B', 5], - ['D', 4], ['D', 5], ['E', 6], ['E', 7], - ['E', 8], ['F', 4], ['H', 3], ['H', 4], - ['I', 10]]] + finite = [CoxeterMatrix(t) for t in [['A', 1], ['A', 5], ['B', 5], ['D', 4], ['D', 5], ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['H', 3], ['H', 4], ['I', 10]]] - affine = [CoxeterMatrix(t) for t in [['A', 2, 1], ['B', 5, 1], - ['C', 5, 1], ['D', 5, 1], ['E', 6, 1], - ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], - ['G', 2, 1], ['A', 1, 1]]] + affine = [CoxeterMatrix(t) for t in [['A', 2, 1], ['B', 5, 1], ['C', 5, 1], ['D', 5, 1], ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['A', 1, 1]]] - higher_matrices = [[[1, -1, -1], [-1, 1, -1], [-1, -1, 1]], - [[1, 2, 3], [2, 1, 7], [3, 7, 1]], - [[1, -2, 3, 2], [-2, 1, 2, 3], [3, 2, 1, -8], [2, 3, -8, 1]]] + higher_matrices = [[[1, -1, -1], [-1, 1, -1], [-1, -1, 1]], [[1, 2, 3], [2, 1, 7], [3, 7, 1]], [[1, -2, 3, 2], [-2, 1, 2, 3], [3, 2, 1, -8], [2, 3, -8, 1]]] higher = [CoxeterMatrix(m) for m in higher_matrices] @@ -603,11 +593,9 @@ def relabel(self, relabelling): [3 2 2 1] """ if isinstance(relabelling, dict): - data = [[self[relabelling[i]][relabelling[j]] - for j in self.index_set()] for i in self.index_set()] + data = [[self[relabelling[i]][relabelling[j]] for j in self.index_set()] for i in self.index_set()] else: - data = [[self[relabelling(i)][relabelling(j)] - for j in self.index_set()] for i in self.index_set()] + data = [[self[relabelling(i)][relabelling(j)] for j in self.index_set()] for i in self.index_set()] return CoxeterMatrix(data) @@ -888,10 +876,8 @@ def coxeter_graph(self): def val(x): return infinity if x == -1 else x - G = Graph([(I[i], I[j], val((self._matrix)[i, j])) - for i in range(n) for j in range(i) - if self._matrix[i, j] not in [1, 2]], - format='list_of_edges') + + G = Graph([(I[i], I[j], val((self._matrix)[i, j])) for i in range(n) for j in range(i) if self._matrix[i, j] not in [1, 2]], format='list_of_edges') G.add_vertices(I) return G.copy(immutable=True) @@ -1107,11 +1093,7 @@ def recognize_coxeter_type_from_matrix(coxeter_matrix, index_set): """ # First, we build the Coxeter graph of the group without the edge labels n = ZZ(coxeter_matrix.nrows()) - G = Graph([index_set, - [(index_set[i], index_set[j], coxeter_matrix[i, j]) - for i in range(n) for j in range(i, n) - if coxeter_matrix[i, j] not in [1, 2]]], - format='vertices_and_edges') + G = Graph([index_set, [(index_set[i], index_set[j], coxeter_matrix[i, j]) for i in range(n) for j in range(i, n) if coxeter_matrix[i, j] not in [1, 2]]], format='vertices_and_edges') types = [] for S in G.connected_components_subgraphs(): @@ -1134,11 +1116,9 @@ def recognize_coxeter_type_from_matrix(coxeter_matrix, index_set): ct = CoxeterType(['A', 1, 1]) SV = S.vertices(sort=True) if not ct.is_affine(): - types.append(ct.relabel({1: SV[0], - 2: SV[1]})) + types.append(ct.relabel({1: SV[0], 2: SV[1]})) else: - types.append(ct.relabel({0: SV[0], - 1: SV[1]})) + types.append(ct.relabel({0: SV[0], 1: SV[1]})) continue test = [['A', r], ['B', r], ['A', r - 1, 1]] @@ -1177,6 +1157,7 @@ def recognize_coxeter_type_from_matrix(coxeter_matrix, index_set): return CoxeterType(types) + ##################################################################### # Other functions @@ -1228,7 +1209,7 @@ def check_coxeter_matrix(m): for i, row in enumerate(m): if mat[i, i] != 1: raise ValueError("the matrix diagonal is not all 1") - for j, val in enumerate(row[i + 1:]): + for j, val in enumerate(row[i + 1 :]): if val != m[j + i + 1][i]: raise ValueError("the matrix is not symmetric") if val not in ZZ: diff --git a/src/sage/combinat/root_system/coxeter_type.py b/src/sage/combinat/root_system/coxeter_type.py index e42224fbd4e..7c9a81adbb2 100644 --- a/src/sage/combinat/root_system/coxeter_type.py +++ b/src/sage/combinat/root_system/coxeter_type.py @@ -1,6 +1,7 @@ """ Coxeter types """ + # **************************************************************************** # Copyright (C) 2015 Travis Scrimshaw , # 2015 Jean-Philippe Labbe , @@ -36,6 +37,7 @@ class CoxeterType(SageObject, metaclass=ClasscallMetaclass): """ Abstract class for Coxeter types. """ + @staticmethod def __classcall_private__(cls, *x): """ @@ -176,15 +178,9 @@ def _samples(self): Coxeter type of ['F', 4, 1], Coxeter type of ['G', 2, 1], Coxeter type of ['A', 1, 1]] """ - finite = [CoxeterType(t) for t in [['A', 1], ['A', 5], ['B', 1], ['B', 5], - ['C', 1], ['C', 5], ['D', 4], ['D', 5], - ['E', 6], ['E', 7], ['E', 8], ['F', 4], - ['H', 3], ['H', 4], ['I', 10]]] + finite = [CoxeterType(t) for t in [['A', 1], ['A', 5], ['B', 1], ['B', 5], ['C', 1], ['C', 5], ['D', 4], ['D', 5], ['E', 6], ['E', 7], ['E', 8], ['F', 4], ['H', 3], ['H', 4], ['I', 10]]] - affine = [CoxeterType(t) for t in [['A', 2, 1], ['B', 5, 1], - ['C', 5, 1], ['D', 5, 1], ['E', 6, 1], - ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], - ['G', 2, 1], ['A', 1, 1]]] + affine = [CoxeterType(t) for t in [['A', 2, 1], ['B', 5, 1], ['C', 5, 1], ['D', 5, 1], ['E', 6, 1], ['E', 7, 1], ['E', 8, 1], ['F', 4, 1], ['G', 2, 1], ['A', 1, 1]]] return finite + affine @@ -385,15 +381,17 @@ def bilinear_form(self, R=None): def val(x): if x > -1: - return (E(2*x) + ~E(2*x)) / R(-2) + return (E(2 * x) + ~E(2 * x)) / R(-2) return R(x) + elif isinstance(R, sage.rings.abc.NumberField_quadratic): E = UniversalCyclotomicField().gen def val(x): if x > -1: - return R((E(2*x) + ~E(2*x)).to_cyclotomic_field()) / R(-2) + return R((E(2 * x) + ~E(2 * x)).to_cyclotomic_field()) / R(-2) return R(x) + else: from sage.functions.trig import cos from sage.symbolic.constants import pi @@ -404,9 +402,7 @@ def val(x): return -R(cos(pi / SR(x))) return R(x) - entries = [SparseEntry(i, j, val(mat[i, j])) - for i in range(n) for j in range(n) - if mat[i, j] != 2] + entries = [SparseEntry(i, j, val(mat[i, j])) for i in range(n) for j in range(n) if mat[i, j] != 2] bilinear = Matrix(R, n, entries) bilinear.set_immutable() return bilinear @@ -416,6 +412,7 @@ class CoxeterTypeFromCartanType(UniqueRepresentation, CoxeterType): """ A Coxeter type associated to a Cartan type. """ + @staticmethod def __classcall_private__(cls, cartan_type): """ diff --git a/src/sage/combinat/root_system/dynkin_diagram.py b/src/sage/combinat/root_system/dynkin_diagram.py index ca05bec6e0b..ae172c1a335 100644 --- a/src/sage/combinat/root_system/dynkin_diagram.py +++ b/src/sage/combinat/root_system/dynkin_diagram.py @@ -197,7 +197,7 @@ def DynkinDiagram(*args, **kwds): else: index_set = mat.index_set() D = DynkinDiagram_class(index_set=index_set) - for (i, j) in mat.nonzero_positions(): + for i, j in mat.nonzero_positions(): if i != j: D.add_edge(index_set[i], index_set[j], -mat[j, i]) return D @@ -251,8 +251,7 @@ class DynkinDiagram_class(DiGraph, CartanType_abstract): are initialized from the index set of this Cartan type. """ - def __init__(self, t=None, index_set=None, odd_isotropic_roots=[], - **options): + def __init__(self, t=None, index_set=None, odd_isotropic_roots=[], **options): """ Initialize ``self``. @@ -293,8 +292,8 @@ def _repr_(self, compact=False): result = ct.ascii_art() + "\n" if hasattr(ct, "ascii_art") else "" if ct is None or isinstance(ct, CartanMatrix): - return result+"Dynkin diagram of rank %s" % self.rank() - return result+"%s" % ct._repr_(compact=True) + return result + "Dynkin diagram of rank %s" % self.rank() + return result + "%s" % ct._repr_(compact=True) def _rich_repr_(self, display_manager, **kwds): """ @@ -341,6 +340,7 @@ def _latex_(self, scale=0.5): return "Dynkin diagram of rank {}".format(self.rank()) from sage.graphs.graph_latex import setup_latex_preamble + setup_latex_preamble() ret = "\\begin{{tikzpicture}}[scale={}]\n".format(scale) @@ -377,8 +377,8 @@ def add_edge(self, i, j, label=1): [(2, 3, 1), (3, 2, 1)] """ DiGraph.add_edge(self, i, j, label) - if not self.has_edge(j,i): - self.add_edge(j,i,1) + if not self.has_edge(j, i): + self.add_edge(j, i, 1) def __hash__(self): """ @@ -391,7 +391,7 @@ def __hash__(self): """ # Should assert for immutability! - #return hash(self.cartan_type(), self.vertices(sort=True), tuple(self.edges(sort=True))) + # return hash(self.cartan_type(), self.vertices(sort=True), tuple(self.edges(sort=True))) # FIXME: self.edges() currently tests at some point whether # self is a vertex of itself which causes an infinite # recursion loop. Current workaround: call self.edge_iterator directly @@ -416,10 +416,10 @@ def an_instance(): """ # hyperbolic Dynkin diagram of Exercise 4.9 p. 57 of Kac Infinite Dimensional Lie Algebras. g = DynkinDiagram() - g.add_vertices([1,2,3]) - g.add_edge(1,2,2) - g.add_edge(1,3) - g.add_edge(2,3) + g.add_vertices([1, 2, 3]) + g.add_edge(1, 2, 2) + g.add_edge(1, 3) + g.add_edge(2, 3) return g ########################################################################## @@ -789,7 +789,7 @@ def column(self, j): [(3, 2), (2, -1), (4, -2)] """ val = 2 if j not in self._odd_isotropic_roots else 0 - return [(j,val)] + [(i,-m) for (j1, i, m) in self.outgoing_edges(j)] + return [(j, val)] + [(i, -m) for (j1, i, m) in self.outgoing_edges(j)] def row(self, i): """ @@ -804,7 +804,7 @@ def row(self, i): [(3, 2), (2, -1), (4, -2)] """ val = 2 if i not in self._odd_isotropic_roots else 0 - return [(i,val)] + [(j,-m) for (j, i1, m) in self.incoming_edges(i)] + return [(i, val)] + [(j, -m) for (j, i1, m) in self.incoming_edges(i)] @cached_method def coxeter_diagram(self): @@ -829,17 +829,19 @@ def coxeter_diagram(self): True """ from sage.rings.infinity import infinity + scalarproducts_to_order = {0: 2, 1: 3, 2: 4, 3: 6} from sage.graphs.graph import Graph + coxeter_diagram = Graph(multiedges=False) I = self.index_set() coxeter_diagram.add_vertices(I) for i in I: for j in self.neighbors_out(i): # avoid adding the edge twice - if not coxeter_diagram.has_edge(i,j): - val = scalarproducts_to_order.get(self[i,j]*self[j,i], infinity) - coxeter_diagram.add_edge(i,j, val) + if not coxeter_diagram.has_edge(i, j): + val = scalarproducts_to_order.get(self[i, j] * self[j, i], infinity) + coxeter_diagram.add_edge(i, j, val) return coxeter_diagram.copy(immutable=True) diff --git a/src/sage/combinat/root_system/extended_affine_weyl_group.py b/src/sage/combinat/root_system/extended_affine_weyl_group.py index 29dce5f0c34..b8ab9a5f488 100644 --- a/src/sage/combinat/root_system/extended_affine_weyl_group.py +++ b/src/sage/combinat/root_system/extended_affine_weyl_group.py @@ -435,7 +435,7 @@ def ExtendedAffineWeylGroup(cartan_type, general_linear=None, **print_options): cartan_type = CartanType(cartan_type) if cartan_type.is_reducible(): raise ValueError("Extended affine Weyl groups are only implemented for irreducible affine Cartan types") - if cartan_type.is_finite(): # a finite Cartan type is an abbreviation for its untwisted affinization + if cartan_type.is_finite(): # a finite Cartan type is an abbreviation for its untwisted affinization cartan_type = cartan_type.affine() elif not cartan_type.is_affine(): raise ValueError("Cartan type must be finite or affine") @@ -521,7 +521,7 @@ def __init__(self, cartan_type, general_linear, **print_options): # if there are three root lengths with the special affine node extra long self._type = 'special_extra_long' # this boolean is used to decide which translation lattice to use - self._untwisted = (self._type in ('untwisted', 'special_extra_long')) + self._untwisted = self._type in ('untwisted', 'special_extra_long') # fundamental group self._fundamental_group = FundamentalGroupOfExtendedAffineWeylGroup(cartan_type, prefix=self._prefixf, general_linear=self._general_linear) @@ -563,7 +563,7 @@ def __init__(self, cartan_type, general_linear, **print_options): self._special_root = self._R0.root_lattice().highest_root() node_adjacent_to_special = self._cartan_type.dynkin_diagram().neighbors(self._cartan_type.special_node())[0] self._special_translation = self._lattice.fundamental_weight(node_adjacent_to_special) - self._special_translation_covector = 2*self._special_root.associated_coroot() + self._special_translation_covector = 2 * self._special_root.associated_coroot() else: # dual untwisted case self._special_root = self._R0.coroot_lattice().highest_root().associated_coroot() @@ -628,20 +628,20 @@ def __init__(self, cartan_type, general_linear, **print_options): W0Pv_to_PvW0.register_as_coercion() if self._general_linear: - PW0_to_PvW0 = SetMorphism(Hom(PW0, PvW0, Groups()), lambda x: PvW0((x.cartesian_projection(0),x.cartesian_projection(1)))) - PvW0_to_PW0 = SetMorphism(Hom(PvW0, PW0, Groups()), lambda x: PW0((x.cartesian_projection(0),x.cartesian_projection(1)))) - W0P_to_W0Pv = SetMorphism(Hom(W0P, W0Pv, Groups()), lambda x: W0Pv((x.cartesian_projection(0),x.cartesian_projection(1)))) - W0Pv_to_W0P = SetMorphism(Hom(W0Pv, W0P, Groups()), lambda x: W0P((x.cartesian_projection(0),x.cartesian_projection(1)))) + PW0_to_PvW0 = SetMorphism(Hom(PW0, PvW0, Groups()), lambda x: PvW0((x.cartesian_projection(0), x.cartesian_projection(1)))) + PvW0_to_PW0 = SetMorphism(Hom(PvW0, PW0, Groups()), lambda x: PW0((x.cartesian_projection(0), x.cartesian_projection(1)))) + W0P_to_W0Pv = SetMorphism(Hom(W0P, W0Pv, Groups()), lambda x: W0Pv((x.cartesian_projection(0), x.cartesian_projection(1)))) + W0Pv_to_W0P = SetMorphism(Hom(W0Pv, W0P, Groups()), lambda x: W0P((x.cartesian_projection(0), x.cartesian_projection(1)))) elif self._untwisted: - PW0_to_PvW0 = SetMorphism(Hom(PW0, PvW0, Groups()), lambda x: PvW0((self.exp_dual_lattice()(x.cartesian_projection(0).value.to_dual_type_cospace()),self.dual_classical_weyl().from_reduced_word(x.cartesian_projection(1).reduced_word())))) - PvW0_to_PW0 = SetMorphism(Hom(PvW0, PW0, Groups()), lambda x: PW0((self.exp_lattice()(x.cartesian_projection(0).value.to_dual_type_cospace()),self.classical_weyl().from_reduced_word(x.cartesian_projection(1).reduced_word())))) - W0P_to_W0Pv = SetMorphism(Hom(W0P, W0Pv, Groups()), lambda x: W0Pv((self.dual_classical_weyl().from_reduced_word(x.cartesian_projection(0).reduced_word()),self.exp_dual_lattice()(x.cartesian_projection(1).value.to_dual_type_cospace())))) - W0Pv_to_W0P = SetMorphism(Hom(W0Pv, W0P, Groups()), lambda x: W0P((self.classical_weyl().from_reduced_word(x.cartesian_projection(0).reduced_word()),self.exp_lattice()(x.cartesian_projection(1).value.to_dual_type_cospace())))) + PW0_to_PvW0 = SetMorphism(Hom(PW0, PvW0, Groups()), lambda x: PvW0((self.exp_dual_lattice()(x.cartesian_projection(0).value.to_dual_type_cospace()), self.dual_classical_weyl().from_reduced_word(x.cartesian_projection(1).reduced_word())))) + PvW0_to_PW0 = SetMorphism(Hom(PvW0, PW0, Groups()), lambda x: PW0((self.exp_lattice()(x.cartesian_projection(0).value.to_dual_type_cospace()), self.classical_weyl().from_reduced_word(x.cartesian_projection(1).reduced_word())))) + W0P_to_W0Pv = SetMorphism(Hom(W0P, W0Pv, Groups()), lambda x: W0Pv((self.dual_classical_weyl().from_reduced_word(x.cartesian_projection(0).reduced_word()), self.exp_dual_lattice()(x.cartesian_projection(1).value.to_dual_type_cospace())))) + W0Pv_to_W0P = SetMorphism(Hom(W0Pv, W0P, Groups()), lambda x: W0P((self.classical_weyl().from_reduced_word(x.cartesian_projection(0).reduced_word()), self.exp_lattice()(x.cartesian_projection(1).value.to_dual_type_cospace())))) else: - PW0_to_PvW0 = SetMorphism(Hom(PW0, PvW0, Groups()), lambda x: PvW0((x.cartesian_projection(0),self.dual_classical_weyl().from_reduced_word(x.cartesian_projection(1).reduced_word())))) - PvW0_to_PW0 = SetMorphism(Hom(PvW0, PW0, Groups()), lambda x: PW0((x.cartesian_projection(0),self.classical_weyl().from_reduced_word(x.cartesian_projection(1).reduced_word())))) - W0P_to_W0Pv = SetMorphism(Hom(W0P, W0Pv, Groups()), lambda x: W0Pv((self.dual_classical_weyl().from_reduced_word(x.cartesian_projection(0).reduced_word()),x.cartesian_projection(1)))) - W0Pv_to_W0P = SetMorphism(Hom(W0Pv, W0P, Groups()), lambda x: W0P((self.classical_weyl().from_reduced_word(x.cartesian_projection(0).reduced_word()),x.cartesian_projection(1)))) + PW0_to_PvW0 = SetMorphism(Hom(PW0, PvW0, Groups()), lambda x: PvW0((x.cartesian_projection(0), self.dual_classical_weyl().from_reduced_word(x.cartesian_projection(1).reduced_word())))) + PvW0_to_PW0 = SetMorphism(Hom(PvW0, PW0, Groups()), lambda x: PW0((x.cartesian_projection(0), self.classical_weyl().from_reduced_word(x.cartesian_projection(1).reduced_word())))) + W0P_to_W0Pv = SetMorphism(Hom(W0P, W0Pv, Groups()), lambda x: W0Pv((self.dual_classical_weyl().from_reduced_word(x.cartesian_projection(0).reduced_word()), x.cartesian_projection(1)))) + W0Pv_to_W0P = SetMorphism(Hom(W0Pv, W0P, Groups()), lambda x: W0P((self.classical_weyl().from_reduced_word(x.cartesian_projection(0).reduced_word()), x.cartesian_projection(1)))) PW0_to_PvW0.register_as_coercion() PvW0_to_PW0.register_as_coercion() @@ -1048,7 +1048,7 @@ def WF_to_PW0_func(self, x): W = self.classical_weyl() if self._general_linear: r = ZZ(Mod(ispecial, self._n)) - weight = self.lattice().from_vector(vector([ZZ((ispecial-r)/self._n)]*self._n)) + weight = self.lattice().from_vector(vector([ZZ((ispecial - r) / self._n)] * self._n)) if r != ZZ(0): weight = weight + self.lattice_basis()[r] wo = W.from_reduced_word(self.fundamental_group().reduced_word(r)) @@ -1060,7 +1060,7 @@ def WF_to_PW0_func(self, x): else: weight = self.lattice_basis()[ispecial] wo = W.from_reduced_word(self.fundamental_group().reduced_word(ispecial)) - return PW0((weight,wo)) + return PW0((weight, wo)) class Realizations(Category_realization_of_parent): r""" @@ -1405,8 +1405,8 @@ def apply_simple_reflection(self, i, side='right'): """ s = self.parent().simple_reflection(i) if side == 'right': - return self*s - return s*self + return self * s + return s * self def apply_simple_projection(self, i, side='right', length_increasing=True): r""" @@ -1635,7 +1635,7 @@ def coset_representative(self, index_set, side='right'): i = self.first_descent(index_set=index_set, side=side) if i is None: return self - self = self.apply_simple_reflection(i,side=side) + self = self.apply_simple_reflection(i, side=side) def is_grassmannian(self, index_set, side='right'): r""" @@ -1653,7 +1653,7 @@ def is_grassmannian(self, index_set, side='right'): sage: [(i, x.is_grassmannian(index_set=[i], side='left')) for i in I] [(0, False), (1, True), (2, True), (3, True)] """ - return self == self.coset_representative(index_set=index_set,side=side) + return self == self.coset_representative(index_set=index_set, side=side) def to_affine_grassmannian(self): r""" @@ -1952,7 +1952,7 @@ def has_descent(self, i, side='right', positive=False) -> bool: if ip < 1: return False return E._special_root.weyl_action(w, inverse=True).is_positive_root() - ip = la.scalar(E._simpleR0[i]) # test height versus simple (co)root + ip = la.scalar(E._simpleR0[i]) # test height versus simple (co)root if ip < 0: return True if ip > 0: @@ -1989,7 +1989,7 @@ def to_translation_left(self): sage: s.to_translation_left() Lambdacheck[1] + Lambdacheck[2] """ - return self.cartesian_projection(0).value # undo the GroupExp + return self.cartesian_projection(0).value # undo the GroupExp def to_classical_weyl(self): r""" @@ -2032,6 +2032,7 @@ def __init__(self, E): sage: PW0 = ExtendedAffineWeylGroup(['D',3,2]).PW0() sage: TestSuite(PW0).run() """ + # note that we have to use the multiplicative version of the translation lattice # and change the twist to deal with this def twist(w, l): @@ -2065,7 +2066,7 @@ def from_translation(self, la): (tau[2*Lambdacheck[1] + 2*Lambdacheck[2]], 1) """ E = self.realization_of() - return self((E.exp_lattice()(la),self.cartesian_factors()[1].one())) + return self((E.exp_lattice()(la), self.cartesian_factors()[1].one())) @cached_method def S0(self): @@ -2119,7 +2120,7 @@ def from_classical_weyl(self, w): sage: E.PW0().from_classical_weyl(E.classical_weyl().from_reduced_word([1,2])) (t[0], s1*s2) """ - return self((self.cartesian_factors()[0].one(),w)) + return self((self.cartesian_factors()[0].one(), w)) class ExtendedAffineWeylGroupW0PElement(GroupSemidirectProduct.Element): r""" @@ -2161,7 +2162,7 @@ def has_descent(self, i, side='right', positive=False) -> bool: if ip > -1: return False return E._special_root.weyl_action(w).is_positive_root() - ip = la.scalar(E._simpleR0[i]) # test height versus simple (co)root + ip = la.scalar(E._simpleR0[i]) # test height versus simple (co)root if ip > 0: return True if ip < 0: @@ -2218,6 +2219,7 @@ def __init__(self, E): sage: W0P = ExtendedAffineWeylGroup(['D',3,2]).W0P() sage: TestSuite(W0P).run() """ + def twist(w, l): return E.exp_lattice()(w.action(l.value)) @@ -2245,7 +2247,7 @@ def S0(self): s1*s2*s3*s2*s1 * t[-Lambdacheck[1] - Lambdacheck[3]] """ E = self.realization_of() - return self((E._special_reflection,E.exp_lattice()(E.lattice()(-E._special_translation)))) + return self((E._special_reflection, E.exp_lattice()(E.lattice()(-E._special_translation)))) def simple_reflection(self, i): r""" @@ -2286,7 +2288,7 @@ def from_classical_weyl(self, w): sage: E.W0P().from_classical_weyl(E.classical_weyl().from_reduced_word([2,1])) (s2*s1, t[0]) """ - return self((w,self.cartesian_factors()[1].one())) + return self((w, self.cartesian_factors()[1].one())) def from_translation(self, la): r""" @@ -2298,7 +2300,7 @@ def from_translation(self, la): sage: E.W0P().from_translation(E.lattice().an_element()) (1, t[2*Lambdacheck[1] + 2*Lambdacheck[2]]) """ - return self((self.cartesian_factors()[0].one(),self.realization_of().exp_lattice()(la))) + return self((self.cartesian_factors()[0].one(), self.realization_of().exp_lattice()(la))) class ExtendedAffineWeylGroupWFElement(GroupSemidirectProduct.Element): r""" @@ -2416,6 +2418,7 @@ def __init__(self, E): sage: WF = ExtendedAffineWeylGroup(['D',3,2]).WF() sage: TestSuite(WF).run() """ + def twist(g, w): return g.act_on_affine_weyl(w) @@ -2443,7 +2446,7 @@ def from_affine_weyl(self, w): sage: E.WF().from_affine_weyl(E.affine_weyl().from_reduced_word([1,2,1,0])) (S1*S2*S1*S0, pi[0]) """ - return self((w,self.cartesian_factors()[1].one())) + return self((w, self.cartesian_factors()[1].one())) @cached_method def simple_reflections(self): @@ -2472,7 +2475,7 @@ def from_fundamental(self, f): sage: [(x, WF.from_fundamental(x)) for x in F] [(pi[0], (1, pi[0])), (pi[1], (1, pi[1])), (pi[6], (1, pi[6]))] """ - return self((self.cartesian_factors()[0].one(),f)) + return self((self.cartesian_factors()[0].one(), f)) class ExtendedAffineWeylGroupFWElement(GroupSemidirectProduct.Element): r""" @@ -2577,6 +2580,7 @@ def __init__(self, E): sage: FW = ExtendedAffineWeylGroup(['D',3,2]).FW() sage: TestSuite(FW).run() """ + def twist(g, w): return g.act_on_affine_weyl(w) @@ -2619,7 +2623,7 @@ def from_affine_weyl(self, w): sage: E.FW().from_affine_weyl(E.affine_weyl().from_reduced_word([0,2,1])) (pi[0], S0*S2*S1) """ - return self((self.cartesian_factors()[0].one(),w)) + return self((self.cartesian_factors()[0].one(), w)) @cached_method def from_fundamental(self, f): @@ -2632,7 +2636,7 @@ def from_fundamental(self, f): sage: E.FW().from_fundamental(E.fundamental_group()(2)) (pi[2], 1) """ - return self((f,self.cartesian_factors()[1].one())) + return self((f, self.cartesian_factors()[1].one())) class ExtendedAffineWeylGroupPvW0Element(GroupSemidirectProduct.Element): r""" @@ -2692,7 +2696,7 @@ def to_dual_translation_left(self): sage: s.to_dual_translation_left() Lambda[1] + Lambda[2] """ - return self.cartesian_projection(0).value # undo the GroupExp + return self.cartesian_projection(0).value # undo the GroupExp def to_dual_classical_weyl(self): r""" @@ -2749,6 +2753,7 @@ def __init__(self, E): sage: PvW0 = ExtendedAffineWeylGroup(['D',3,2]).PvW0() sage: TestSuite(PvW0).run() """ + # note that we have to use the multiplicative version of the translation lattice # and change the twist to deal with this def twist(w, l): @@ -2782,7 +2787,7 @@ def from_dual_translation(self, la): (tau[2*Lambda[1] + 2*Lambda[2]], 1) """ E = self.realization_of() - return self((E.exp_dual_lattice()(la),self.cartesian_factors()[1].one())) + return self((E.exp_dual_lattice()(la), self.cartesian_factors()[1].one())) @cached_method def simple_reflections(self): @@ -2809,7 +2814,7 @@ def from_dual_classical_weyl(self, w): ....: E.dual_classical_weyl().from_reduced_word([1,2])) (t[0], s1*s2) """ - return self((self.cartesian_factors()[0].one(),w)) + return self((self.cartesian_factors()[0].one(), w)) class ExtendedAffineWeylGroupW0PvElement(GroupSemidirectProduct.Element): r""" @@ -2868,7 +2873,7 @@ def to_dual_translation_right(self): sage: s.to_dual_translation_right() -Lambda[1] - Lambda[2] """ - return self.cartesian_projection(1).value # undo the GroupExp + return self.cartesian_projection(1).value # undo the GroupExp def to_dual_classical_weyl(self): r""" @@ -2920,6 +2925,7 @@ def __init__(self, E): sage: W0Pv = ExtendedAffineWeylGroup(['D',3,2]).W0Pv() sage: TestSuite(W0Pv).run() """ + # note that we have to use the multiplicative version of the translation lattice # and change the twist to deal with this def twist(w, l): @@ -2953,7 +2959,7 @@ def from_dual_translation(self, la): (1, tau[2*Lambda[1] + 2*Lambda[2]]) """ E = self.realization_of() - return self((self.cartesian_factors()[0].one(),E.exp_dual_lattice()(la))) + return self((self.cartesian_factors()[0].one(), E.exp_dual_lattice()(la))) @cached_method def simple_reflections(self): @@ -2979,7 +2985,7 @@ def from_dual_classical_weyl(self, w): sage: E.W0Pv().from_dual_classical_weyl(E.dual_classical_weyl().from_reduced_word([1,2])) (s1*s2, t[0]) """ - return self((w,self.cartesian_factors()[1].one())) + return self((w, self.cartesian_factors()[1].one())) ExtendedAffineWeylGroup_Class.ExtendedAffineWeylGroupPW0.Element = ExtendedAffineWeylGroup_Class.ExtendedAffineWeylGroupPW0Element diff --git a/src/sage/combinat/root_system/fundamental_group.py b/src/sage/combinat/root_system/fundamental_group.py index 1c54b61a9cb..0106229a089 100644 --- a/src/sage/combinat/root_system/fundamental_group.py +++ b/src/sage/combinat/root_system/fundamental_group.py @@ -30,8 +30,7 @@ from sage.sets.family import LazyFamily -def FundamentalGroupOfExtendedAffineWeylGroup(cartan_type, prefix='pi', - general_linear=None): +def FundamentalGroupOfExtendedAffineWeylGroup(cartan_type, prefix='pi', general_linear=None): r""" Factory for the fundamental group of an extended affine Weyl group. @@ -199,8 +198,7 @@ def FundamentalGroupOfExtendedAffineWeylGroup(cartan_type, prefix='pi', if cartan_type.is_untwisted_affine() and cartan_type.type() == "A": return FundamentalGroupGL(cartan_type, prefix) raise ValueError("General Linear Fundamental group is untwisted type A") - return FundamentalGroupOfExtendedAffineWeylGroup_Class(cartan_type, prefix, - finite=True) + return FundamentalGroupOfExtendedAffineWeylGroup_Class(cartan_type, prefix, finite=True) class FundamentalGroupElement(MultiplicativeGroupElement): @@ -340,11 +338,11 @@ def __hash__(self): return hash(self.value()) -class FundamentalGroupOfExtendedAffineWeylGroup_Class(UniqueRepresentation, - Parent): +class FundamentalGroupOfExtendedAffineWeylGroup_Class(UniqueRepresentation, Parent): r""" The group of length zero elements in the extended affine Weyl group. """ + Element = FundamentalGroupElement def __init__(self, cartan_type, prefix, finite=True): @@ -358,6 +356,7 @@ def __init__(self, cartan_type, prefix, finite=True): True sage: TestSuite(F).run() """ + def leading_support(beta): r""" Given a dictionary with one key, return this key @@ -381,7 +380,7 @@ def leading_support(beta): # permutations of the affine Dynkin nodes auto_dict = {} for i in cartan_type.index_set(): - auto_dict[special_node,i] = i + auto_dict[special_node, i] = i # dictionary for the finite Weyl component of the special automorphisms reduced_words_dict = {} reduced_words_dict[0] = tuple() @@ -405,7 +404,7 @@ def leading_support(beta): w0i = W.from_reduced_word(reduced_word) idual = leading_support(-antidominant_weight) inverse_dict[i] = idual - auto_dict[i,special_node] = i + auto_dict[i, special_node] = i for j in I: if j == idual: auto_dict[i, j] = special_node @@ -417,8 +416,7 @@ def leading_support(beta): self._reduced_words = Family(self._special_nodes, reduced_words_dict.__getitem__) if finite: - cat = Category.join((Groups().Commutative().Finite(), - EnumeratedSets())) + cat = Category.join((Groups().Commutative().Finite(), EnumeratedSets())) else: cat = Groups().Commutative().Infinite() Parent.__init__(self, category=cat) @@ -631,6 +629,7 @@ class FundamentalGroupGL(FundamentalGroupOfExtendedAffineWeylGroup_Class): r""" Fundamental group of `GL_n`. It is just the integers with extra privileges. """ + Element = FundamentalGroupGLElement def __init__(self, cartan_type, prefix='pi'): diff --git a/src/sage/combinat/root_system/hecke_algebra_representation.py b/src/sage/combinat/root_system/hecke_algebra_representation.py index 612fc48a876..bb9826d2015 100644 --- a/src/sage/combinat/root_system/hecke_algebra_representation.py +++ b/src/sage/combinat/root_system/hecke_algebra_representation.py @@ -113,7 +113,7 @@ def _repr_(self): on Algebra of Weyl Group of type ['A', 3] (as a matrix group acting on the ambient space) over Rational Field" """ - return "A representation of the %s-Hecke algebra of type %s on %s" % ((self._q1,self._q2), self.cartan_type(), self.domain()) + return "A representation of the %s-Hecke algebra of type %s on %s" % ((self._q1, self._q2), self.cartan_type(), self.domain()) @cached_method def parameters(self, i): @@ -219,7 +219,7 @@ def Ti_inverse_on_basis(self, x, i): """ q1 = self._q1 q2 = self._q2 - return (self._domain.term(x, q1+q2) - self.Ti_on_basis(x, i))/(q1*q2) + return (self._domain.term(x, q1 + q2) - self.Ti_on_basis(x, i)) / (q1 * q2) @cached_method def on_basis(self, x, word, signs=None, scalar=None): @@ -273,13 +273,12 @@ def on_basis(self, x, word, signs=None, scalar=None): if l == 0: return self._domain.monomial(x) rec = self.on_basis(x, word[:-1], signs) - i = word[l-1] - if signs is not None and signs[l-1] == -1: + i = word[l - 1] + if signs is not None and signs[l - 1] == -1: operator = self.Ti_inverse_on_basis else: operator = self.Ti_on_basis - result = self._domain.linear_combination((operator(l, i), c) - for l,c in rec) + result = self._domain.linear_combination((operator(l, i), c) for l, c in rec) if scalar is None: return result return scalar * result @@ -391,8 +390,7 @@ def Tw(self, word, signs=None, scalar=None): 3 """ word = self.straighten_word(word) - result = self._domain.module_morphism(functools.partial(self.on_basis, word=word, signs=signs, scalar=scalar), - codomain=self._domain) + result = self._domain.module_morphism(functools.partial(self.on_basis, word=word, signs=signs, scalar=scalar), codomain=self._domain) # For debugging purpose, make the parameters easily accessible: result.word = word result.signs = signs @@ -464,18 +462,18 @@ def _test_relations(self, **options): T = self def Ti(x, i, c): - return T[i](x)+c*x + return T[i](x) + c * x try: # Check the quadratic relation for i in cartan_type.index_set(): for x in elements: - tester.assertTrue(Ti(Ti(x,i,-q2),i,-q1).is_zero()) + tester.assertTrue(Ti(Ti(x, i, -q2), i, -q1).is_zero()) G = cartan_type.coxeter_diagram() # Check the braid relation - for (i, j) in Subsets(cartan_type.index_set(), 2): - if G.has_edge(i,j): - o = G.edge_label(i,j) + for i, j in Subsets(cartan_type.index_set(), 2): + if G.has_edge(i, j): + o = G.edge_label(i, j) else: o = 2 if o == infinity: @@ -485,7 +483,7 @@ def Ti(x, i, c): for k in range(o): x = T[i](x) y = T[j](y) - y,x = x,y + y, x = x, y tester.assertEqual(x, y) except ImportError: pass @@ -603,8 +601,8 @@ def Y_lambdacheck(self, lambdacheck): - [HST2008]_ for the formula in terms of `q_1, q_2` """ - #Q_check = self.Y().keys() - #assert Q_check.is_parent_of(lambdacheck) + # Q_check = self.Y().keys() + # assert Q_check.is_parent_of(lambdacheck) Q_check = lambdacheck.parent() # Alcove walks and the like are currently only implemented in @@ -624,7 +622,7 @@ def Y_lambdacheck(self, lambdacheck): assert P_check.has_coerce_map_from(Q_check) alphacheck = P_check.simple_roots() c = Q_check.cartan_type().translation_factors() - t = P_check.linear_combination( (alphacheck[i], c[i] * coeff) for i,coeff in lambdacheck ) + t = P_check.linear_combination((alphacheck[i], c[i] * coeff) for i, coeff in lambdacheck) # In type BC, c[i] may introduce rational coefficients # If we want to work in the lattice we might want to use the # following workaround after the fact ... @@ -647,7 +645,7 @@ def Y_lambdacheck(self, lambdacheck): # so we can ignore this see the discussion in # sage.combinat.root_system.weight_space.WeightSpace). special_node = Q_check.cartan_type().special_node() - scalar = (-self._q1*self._q2)**(-sum(signs)/2) * self._q**(-lambdacheck[special_node]) + scalar = (-self._q1 * self._q2) ** (-sum(signs) / 2) * self._q ** (-lambdacheck[special_node]) return self.Tw(word, signs, scalar) def Y(self, base_ring=ZZ): @@ -701,7 +699,7 @@ def _test_Y(self, **options): I = L.index_set() alpha = L.simple_roots() Yi = Family(I, lambda i: Y[alpha[i]]) - for Y1, Y2 in Subsets(Yi,2): + for Y1, Y2 in Subsets(Yi, 2): for x in elements: tester.assertEqual(Y1(Y2(x)), Y2(Y1(x))) @@ -765,6 +763,7 @@ def Y_eigenvectors(self): raise ValueError("The Cherednik operators are only defined for representations of affine Hecke algebra") return CherednikOperatorsEigenvectors(self) + # TODO: this should probably inherit from family! @@ -1079,7 +1078,7 @@ def eigenvalue(self, mu, l): t = res.leading_support() assert t == Emu.leading_support() c = res[t] / Emu[t] - assert res == Emu*c, "not an eigenvector!!!" + assert res == Emu * c, "not an eigenvector!!!" return c def twist(self, mu, i): @@ -1166,7 +1165,7 @@ def __getitem__(self, mu): else: a = 1 Yi = self.eigenvalue(mui, -coroot) - result = self._T.Tw(i)(E_mui) - (q1+q2)*Yi**(a-1)/(1-Yi**a)*E_mui + result = self._T.Tw(i)(E_mui) - (q1 + q2) * Yi ** (a - 1) / (1 - Yi**a) * E_mui if self._normalized: coeff = result.coefficient(mu) result /= coeff diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 083ea4e8ae9..51d31c753dc 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -211,20 +211,17 @@ def __init__(self, Lam): self._mdict = {tuple(0 for i in self._index_set): 1} # Coerce a classical root into the root lattice Q from_cl_root = lambda h: self._Q._from_dict(h._monomial_coefficients) - self._classical_roots = [from_cl_root(al) - for al in self._Q.classical().roots()] - self._classical_positive_roots = [from_cl_root(al) - for al in self._Q.classical().positive_roots()] - self._a = self._cartan_type.a() # This is not cached - self._ac = self._cartan_type.dual().a() # This is not cached + self._classical_roots = [from_cl_root(al) for al in self._Q.classical().roots()] + self._classical_positive_roots = [from_cl_root(al) for al in self._Q.classical().positive_roots()] + self._a = self._cartan_type.a() # This is not cached + self._ac = self._cartan_type.dual().a() # This is not cached self._eps = {i: self._a[i] / self._ac[i] for i in self._index_set} E = Matrix.diagonal([self._eps[i] for i in self._index_set_classical]) - self._ip = (self._cartan_type.classical().cartan_matrix()*E).inverse() + self._ip = (self._cartan_type.classical().cartan_matrix() * E).inverse() # Extra data for the twisted cases if not self._cartan_type.is_untwisted_affine(): - self._classical_short_roots = frozenset(al for al in self._classical_roots - if self._inner_qq(al,al) == 2) + self._classical_short_roots = frozenset(al for al in self._classical_roots if self._inner_qq(al, al) == 2) def highest_weight(self): """ @@ -380,9 +377,7 @@ def _inner_qq(self, qelt1, qelt2): mc1 = qelt1.monomial_coefficients() mc2 = qelt2.monomial_coefficients() zero = ZZ.zero() - return sum(mc1.get(i, zero) * mc2.get(j, zero) - * self._cartan_matrix[i,j] / self._eps[i] - for i in self._index_set for j in self._index_set) + return sum(mc1.get(i, zero) * mc2.get(j, zero) * self._cartan_matrix[i, j] / self._eps[i] for i in self._index_set for j in self._index_set) def _inner_pq(self, pelt, qelt): """ @@ -449,12 +444,7 @@ def _inner_pp(self, pelt1, pelt2): zero = ZZ.zero() mc1d = mc1.get('delta', zero) mc2d = mc2.get('delta', zero) - return sum(mc1.get(i,zero) * self._ac[i] * mc2d - + mc2.get(i,zero) * self._ac[i] * mc1d - for i in self._index_set) \ - + sum(mc1.get(i,zero) * mc2.get(j,zero) * self._ip[ii,ij] - for ii, i in enumerate(self._index_set_classical) - for ij, j in enumerate(self._index_set_classical)) + return sum(mc1.get(i, zero) * self._ac[i] * mc2d + mc2.get(i, zero) * self._ac[i] * mc1d for i in self._index_set) + sum(mc1.get(i, zero) * mc2.get(j, zero) * self._ip[ii, ij] for ii, i in enumerate(self._index_set_classical) for ij, j in enumerate(self._index_set_classical)) def to_weight(self, n): r""" @@ -477,8 +467,7 @@ def to_weight(self, n): """ alpha = self._P.simple_roots() I = self._index_set - return self._Lam - self._P.sum(val * alpha[I[i]] - for i,val in enumerate(n)) + return self._Lam - self._P.sum(val * alpha[I[i]] for i, val in enumerate(n)) def _from_weight_helper(self, mu, check=False): r""" @@ -511,12 +500,11 @@ def _from_weight_helper(self, mu, check=False): zero = ZZ.zero() n0 = mu.monomial_coefficients().get('delta', zero) mu0 = mu - n0 * self._P.simple_root(self._cartan_type.special_node()) - ret = [n0] # This should be in ZZ because it is in the weight lattice + ret = [n0] # This should be in ZZ because it is in the weight lattice mc_mu0 = mu0.monomial_coefficients() for ii, i in enumerate(self._index_set_classical): # -1 for indexing - ret.append( sum(self._cminv[ii,ij] * mc_mu0.get(j, zero) - for ij, j in enumerate(self._index_set_classical)) ) + ret.append(sum(self._cminv[ii, ij] * mc_mu0.get(j, zero) for ij, j in enumerate(self._index_set_classical))) if check: return all(x in ZZ for x in ret) return tuple(ZZ(x) for x in ret) @@ -550,9 +538,9 @@ def s(self, n, i): sage: [V.s((0,0,0),i) for i in V._index_set] [(1, 0, 0), (0, 0, 0), (0, 0, 0)] """ - ret = list(n) # This makes a copy + ret = list(n) # This makes a copy ret[i] += self._Lam._monomial_coefficients.get(i, ZZ.zero()) - ret[i] -= sum(val * self._cartan_matrix[i,j] for j,val in enumerate(n)) + ret[i] -= sum(val * self._cartan_matrix[i, j] for j, val in enumerate(n)) return tuple(ret) def to_dominant(self, n): @@ -579,7 +567,7 @@ def to_dominant(self, n): while next: if path[-1] in self._ddict: - path.append( self._ddict[path[-1]] ) + path.append(self._ddict[path[-1]]) break next = False @@ -624,7 +612,7 @@ def _freudenthal_roots_imaginary(self, nu): l = self._from_weight_helper(nu) kp = min(l[i] // self._a[i] for i in self._index_set) delta = self._Q.null_root() - for u in range(1, kp+1): + for u in range(1, kp + 1): yield u * delta def _freudenthal_roots_real(self, nu): @@ -653,36 +641,35 @@ def _freudenthal_roots_real(self, nu): alpha[3]] """ for al in self._classical_positive_roots: - if min(self._from_weight_helper(nu-al)) >= 0: + if min(self._from_weight_helper(nu - al)) >= 0: yield al if self._cartan_type.is_untwisted_affine(): # untwisted case for al in self._classical_roots: - for ir in self._freudenthal_roots_imaginary(nu-al): + for ir in self._freudenthal_roots_imaginary(nu - al): yield al + ir elif self._cartan_type.type() == 'BC': - #case A^2_{2l} + # case A^2_{2l} # We have to keep track of the roots we have visited for this case ret = set(self._classical_positive_roots) for al in self._classical_roots: if al in self._classical_short_roots: - for ir in self._freudenthal_roots_imaginary(nu-al): + for ir in self._freudenthal_roots_imaginary(nu - al): ret.add(al + ir) yield al + ir else: - fri = list(self._freudenthal_roots_imaginary(nu-al)) + fri = list(self._freudenthal_roots_imaginary(nu - al)) friset = set(fri) for ir in fri: - if 2*ir in friset: - ret.add(al + 2*ir) - yield al + 2*ir + if 2 * ir in friset: + ret.add(al + 2 * ir) + yield al + 2 * ir alpha = self._Q.simple_roots() - fri = list(self._freudenthal_roots_imaginary(2*nu-al)) + fri = list(self._freudenthal_roots_imaginary(2 * nu - al)) for ir in fri[::2]: - rt = sum( val // 2 * alpha[i] for i,val in - enumerate(self._from_weight_helper(al+ir)) ) + rt = sum(val // 2 * alpha[i] for i, val in enumerate(self._from_weight_helper(al + ir))) if rt not in ret: ret.add(rt) yield rt @@ -691,27 +678,27 @@ def _freudenthal_roots_real(self, nu): # case D^3_4 in the Kac notation for al in self._classical_roots: if al in self._classical_short_roots: - for ir in self._freudenthal_roots_imaginary(nu-al): + for ir in self._freudenthal_roots_imaginary(nu - al): yield al + ir else: - fri = list(self._freudenthal_roots_imaginary(nu-al)) + fri = list(self._freudenthal_roots_imaginary(nu - al)) friset = set(fri) for ir in fri: - if 3*ir in friset: - yield al + 3*ir + if 3 * ir in friset: + yield al + 3 * ir - elif self._cartan_type.dual().type() in ['B','C','F']: - #case A^2_{2l-1} or case D^2_{l+1} or case E^2_6: + elif self._cartan_type.dual().type() in ['B', 'C', 'F']: + # case A^2_{2l-1} or case D^2_{l+1} or case E^2_6: for al in self._classical_roots: if al in self._classical_short_roots: - for ir in self._freudenthal_roots_imaginary(nu-al): + for ir in self._freudenthal_roots_imaginary(nu - al): yield al + ir else: - fri = list(self._freudenthal_roots_imaginary(nu-al)) + fri = list(self._freudenthal_roots_imaginary(nu - al)) friset = set(fri) for ir in fri: - if 2*ir in friset: - yield al + 2*ir + if 2 * ir in friset: + yield al + 2 * ir def _freudenthal_accum(self, nu, al): """ @@ -735,7 +722,7 @@ def _freudenthal_accum(self, nu, al): while min(n) >= 0: # Change in data by adding ``al`` to our current weight ip += ip_shift - for i,val in enumerate(n_shift): + for i, val in enumerate(n_shift): n[i] -= val # Compute the multiplicity ret += 2 * self.m(tuple(n)) * ip @@ -764,50 +751,46 @@ def _m_freudenthal(self, n): return 0 mu = self.to_weight(n) I = self._index_set - al = self._Q._from_dict({I[i]: val for i,val in enumerate(n) if val}, - remove_zeros=False) + al = self._Q._from_dict({I[i]: val for i, val in enumerate(n) if val}, remove_zeros=False) cr = self._classical_rank - num = sum(self._freudenthal_accum(mu, alr) - for alr in self._freudenthal_roots_real(self._Lam - mu)) + num = sum(self._freudenthal_accum(mu, alr) for alr in self._freudenthal_roots_real(self._Lam - mu)) if self._cartan_type.is_untwisted_affine(): - num += sum(cr * self._freudenthal_accum(mu, alr) - for alr in self._freudenthal_roots_imaginary(self._Lam - mu)) + num += sum(cr * self._freudenthal_accum(mu, alr) for alr in self._freudenthal_roots_imaginary(self._Lam - mu)) - elif self._cartan_type.dual().type() == 'B': # A_{2n-1}^{(2)} + elif self._cartan_type.dual().type() == 'B': # A_{2n-1}^{(2)} val = 1 for rt in self._freudenthal_roots_imaginary(self._Lam - mu): # k-th element (starting from 1) is k*delta num += (cr - val) * self._freudenthal_accum(mu, rt) val = 1 - val - elif self._cartan_type.type() == 'BC': # A_{2n}^{(2)} - num += sum(cr * self._freudenthal_accum(mu, alr) - for alr in self._freudenthal_roots_imaginary(self._Lam - mu)) + elif self._cartan_type.type() == 'BC': # A_{2n}^{(2)} + num += sum(cr * self._freudenthal_accum(mu, alr) for alr in self._freudenthal_roots_imaginary(self._Lam - mu)) - elif self._cartan_type.dual() == 'C': # D_{n+1}^{(2)} + elif self._cartan_type.dual() == 'C': # D_{n+1}^{(2)} val = 1 for rt in self._freudenthal_roots_imaginary(self._Lam - mu): # k-th element (starting from 1) is k*delta - num += (cr - (cr - 1)*val) * self._freudenthal_accum(mu, rt) + num += (cr - (cr - 1) * val) * self._freudenthal_accum(mu, rt) val = 1 - val - elif self._cartan_type.dual().type() == 'F': # E_6^{(2)} + elif self._cartan_type.dual().type() == 'F': # E_6^{(2)} val = 1 for rt in self._freudenthal_roots_imaginary(self._Lam - mu): # k-th element (starting from 1) is k*delta - num += (4 - 2*val) * self._freudenthal_accum(mu, rt) + num += (4 - 2 * val) * self._freudenthal_accum(mu, rt) val = 1 - val - elif self._cartan_type.dual().type() == 'G': # D_4^{(3)} (or dual of G_2^{(1)}) - for k,rt in enumerate(self._freudenthal_roots_imaginary(self._Lam - mu)): + elif self._cartan_type.dual().type() == 'G': # D_4^{(3)} (or dual of G_2^{(1)}) + for k, rt in enumerate(self._freudenthal_roots_imaginary(self._Lam - mu)): # k-th element (starting from 1) is k*delta - if (k+1) % 3 == 0: + if (k + 1) % 3 == 0: num += 2 * self._freudenthal_accum(mu, rt) else: num += self._freudenthal_accum(mu, rt) - den = 2*self._inner_pq(self._Lam_rho, al) - self._inner_qq(al, al) + den = 2 * self._inner_pq(self._Lam_rho, al) - self._inner_qq(al, al) try: return ZZ(num / den) except TypeError: @@ -922,18 +905,18 @@ def dominant_maximal_weights(self): Lambda = self._P.fundamental_weights() def next_level(wt): - return [wt + Lambda[i] for i in self._index_set_classical - if (wt + Lambda[i]).level() <= k] + return [wt + Lambda[i] for i in self._index_set_classical if (wt + Lambda[i]).level() <= k] + R = RecursivelyEnumeratedSet([self._P.zero()], next_level) - candidates = [x + (k - x.level())*Lambda[0] for x in list(R)] + candidates = [x + (k - x.level()) * Lambda[0] for x in list(R)] ret = [] delta = self._Q.null_root() for x in candidates: - if self._from_weight_helper(self._Lam-x, check=True): + if self._from_weight_helper(self._Lam - x, check=True): t = 0 - while self.m(self.from_weight(x - t*delta)) == 0: + while self.m(self.from_weight(x - t * delta)) == 0: t += 1 - ret.append(x - t*delta) + ret.append(x - t * delta) return tuple(ret) def string(self, max_weight, depth=12): @@ -960,7 +943,7 @@ def string(self, max_weight, depth=12): delta = self._Q.null_root() cur_weight = max_weight for k in range(depth): - ret.append(self.m( self.from_weight(cur_weight) )) + ret.append(self.m(self.from_weight(cur_weight))) cur_weight -= delta return ret @@ -984,8 +967,7 @@ def strings(self, depth=12): 2*Lambda[0]: 1 1 3 5 10 16 28 43 70 105 161 236 350 501 722 1016 1431 1981 2741 3740 5096 6868 9233 12306 16357 2*Lambda[1] - delta: 1 2 4 7 13 21 35 55 86 130 196 287 420 602 858 1206 1687 2331 3206 4368 5922 7967 10670 14193 18803 """ - return {max_weight: self.string(max_weight, depth) - for max_weight in self.dominant_maximal_weights()} + return {max_weight: self.string(max_weight, depth) for max_weight in self.dominant_maximal_weights()} def print_strings(self, depth=12): """ @@ -1005,7 +987,7 @@ def print_strings(self, depth=12): """ S = self.strings(depth=depth) for mw in self.dominant_maximal_weights(): - print("{}: {}".format(mw, ' '.join(str(x) for x in S[mw])) ) + print("{}: {}".format(mw, ' '.join(str(x) for x in S[mw]))) def modular_characteristic(self, mu=None): r""" @@ -1052,12 +1034,11 @@ def modular_characteristic(self, mu=None): k = self.level() hd = self.dual_coxeter_number() rho = self._P.rho() - m_Lambda = self._inner_pp(self._Lam_rho, self._Lam_rho) / (2*(k+hd)) \ - - self._inner_pp(rho, rho) / (2*hd) + m_Lambda = self._inner_pp(self._Lam_rho, self._Lam_rho) / (2 * (k + hd)) - self._inner_pp(rho, rho) / (2 * hd) if n is None: return m_Lambda mu = self.to_weight(n) - return m_Lambda - self._inner_pp(mu,mu) / (2*k) + return m_Lambda - self._inner_pp(mu, mu) / (2 * k) def branch(self, i=None, weyl_character_ring=None, sequence=None, depth=5): r""" @@ -1189,7 +1170,7 @@ def branch(self, i=None, weyl_character_ring=None, sequence=None, depth=5): sequence = {} for j in self._index_set: if j < i: - sequence[j] = j+1 + sequence[j] = j + 1 elif j > i: sequence[j] = j @@ -1201,20 +1182,20 @@ def next_level(x): t = tuple(t) m = self.m(t) if m > 0 and t[i] <= depth: - ret.append((t,m)) + ret.append((t, m)) return ret + hwv = (tuple([0 for j in self._index_set]), 1) terms = RecursivelyEnumeratedSet([hwv], next_level) fw = weyl_character_ring.fundamental_weights() P = self.weight_lattice() ret = [] - for l in range(depth+1): + for l in range(depth + 1): lterms = [x for x in terms if x[0][i] == l] ldict = {} for x in lterms: mc = P(self.to_weight(x[0])).monomial_coefficients() - contr = sum(fw[sequence[j]]*mc.get(j,0) - for j in self._index_set if j != i).coerce_to_sl() + contr = sum(fw[sequence[j]] * mc.get(j, 0) for j in self._index_set if j != i).coerce_to_sl() if contr in ldict: ldict[contr] += x[1] else: diff --git a/src/sage/combinat/root_system/non_symmetric_macdonald_polynomials.py b/src/sage/combinat/root_system/non_symmetric_macdonald_polynomials.py index c020f919717..fabb75b2d75 100644 --- a/src/sage/combinat/root_system/non_symmetric_macdonald_polynomials.py +++ b/src/sage/combinat/root_system/non_symmetric_macdonald_polynomials.py @@ -1294,14 +1294,16 @@ def __classcall__(cls, KL, q='q', q1='q1', q2='q2', normalized=True): The family of the Macdonald polynomials of type ['B', 2, 1] with parameters q, q1, q2 """ from sage.combinat.root_system.cartan_type import CartanType + K = None - #if KL in Algebras: - if isinstance(KL, CombinatorialFreeModule): # temporary work around C3 issue ... + # if KL in Algebras: + if isinstance(KL, CombinatorialFreeModule): # temporary work around C3 issue ... K = KL.base_ring() else: if q == 'q': from sage.rings.rational_field import QQ - K = QQ['q','q1','q2'].fraction_field() + + K = QQ['q', 'q1', 'q2'].fraction_field() else: K = q.parent() KL = CartanType(KL).root_system().ambient_space().algebra(K) @@ -1358,7 +1360,7 @@ def _repr_(self): sage: NonSymmetricMacdonaldPolynomials(["B", 2, 1]) The family of the Macdonald polynomials of type ['B', 2, 1] with parameters q, q1, q2 """ - return "The family of the Macdonald polynomials of type %s with parameters %s, %s, %s" % (self.cartan_type(),self._q, self._q1, self._q2) + return "The family of the Macdonald polynomials of type %s with parameters %s, %s, %s" % (self.cartan_type(), self._q, self._q1, self._q2) # This is redundant with the cartan_type method of # CherednikOperatorsEigenvectors, but we need it very early in the @@ -1402,9 +1404,10 @@ def L_check(self): """ from sage.combinat.root_system.weight_space import WeightSpace from sage.combinat.root_system.type_affine import AmbientSpace + L = self.L() other_affine_root_system = self.cartan_type().classical().dual().affine().root_system() - if isinstance(L, WeightSpace): # TODO: make a nicer test + if isinstance(L, WeightSpace): # TODO: make a nicer test return other_affine_root_system.coweight_space(L.base_ring(), extended=True) assert isinstance(L, AmbientSpace) return other_affine_root_system.coambient_space(L.base_ring()) @@ -1522,7 +1525,7 @@ def Q_to_Qcheck(self): sage: _.parent() Coroot lattice of the Root system of type ['C', 2, 1] """ - #assert self.cartan_type().is_untwisted_affine() + # assert self.cartan_type().is_untwisted_affine() Qcheck = self._T_Y.Y().keys() Q = Qcheck.cartan_type().other_affinization().root_system().root_lattice() assert Q.classical() is Qcheck.classical() @@ -1548,6 +1551,7 @@ def Y(self): Root lattice of the Root system of type ['B', 3] """ from sage.sets.family import Family + Y = self._T_Y.Y() ct = self.cartan_type() # TODO: improve test @@ -1822,20 +1826,20 @@ def eigenvalue_experimental(self, mu, l): I0 = L0.index_set() assert L0.is_parent_of(mu) # Should we view mu as a translation, and ask for its alcove walk? - muaff = self.affine_lift(mu) # embeds mu at level 1 in L_prime - w = reversed(mu.reduced_word(I0, positive=False)) # the reduced word for w_\mu, Prop. 6.9 of [Haiman06]_ + muaff = self.affine_lift(mu) # embeds mu at level 1 in L_prime + w = reversed(mu.reduced_word(I0, positive=False)) # the reduced word for w_\mu, Prop. 6.9 of [Haiman06]_ # mu should be scaled to make sure it implements a translation - #w = reversed(L.reduced_word_of_translation(L(mu))) - #x = L.embed_at_level(L0.rho(),1) - #x = L.rho() / L.rho().level() + # w = reversed(L.reduced_word_of_translation(L(mu))) + # x = L.embed_at_level(L0.rho(),1) + # x = L.rho() / L.rho().level() x = self.rho_prime() - l = self.L_prime().coroot_lattice()(l) # there might need to be a `nu` here + l = self.L_prime().coroot_lattice()(l) # there might need to be a `nu` here for i in w: x = x.simple_reflection(i) - q1,q2 = self.hecke_parameters(1) # TODO: clean up - t = -q2/q1 # TODO: generalize for any eigenvalue + q1, q2 = self.hecke_parameters(1) # TODO: clean up + t = -q2 / q1 # TODO: generalize for any eigenvalue # In type BC, maybe this should be q^...*a[0] - return self._q**(-muaff.scalar(l)) * t**(-x.scalar(l)) + return self._q ** (-muaff.scalar(l)) * t ** (-x.scalar(l)) def seed(self, mu): r""" @@ -1955,7 +1959,7 @@ def symmetric_macdonald_polynomial(self, mu): for c in mu._orbit_iter(): i = c.first_descent() if i is None: - Torbit[c] = self[mu] # the nonsymmetric Macdonald polynomial of mu + Torbit[c] = self[mu] # the nonsymmetric Macdonald polynomial of mu else: Torbit[c] = v * self._T.Tw([i])(Torbit[c.simple_reflection(i)]) s = s + Torbit[c] diff --git a/src/sage/combinat/root_system/pieri_factors.py b/src/sage/combinat/root_system/pieri_factors.py index 48eba471817..6b7e0a9a7e2 100644 --- a/src/sage/combinat/root_system/pieri_factors.py +++ b/src/sage/combinat/root_system/pieri_factors.py @@ -160,9 +160,7 @@ def elements(self): Possibly remove this method and instead have this class inherit from :class:`RecursivelyEnumeratedSet_generic`. """ - return RecursivelyEnumeratedSet(self.maximal_elements(), - attrcall('bruhat_lower_covers'), structure=None, - enumeration='naive') + return RecursivelyEnumeratedSet(self.maximal_elements(), attrcall('bruhat_lower_covers'), structure=None, enumeration='naive') def __iter__(self): r""" @@ -248,8 +246,7 @@ def _test_maximal_elements(self, **options): sage: WeylGroup(['B',5,1]).pieri_factors()._test_maximal_elements() """ tester = self._tester(**options) - tester.assertEqual(set(self.maximal_elements()), - set(self.maximal_elements_combinatorial())) + tester.assertEqual(set(self.maximal_elements()), set(self.maximal_elements_combinatorial())) @cached_method def max_length(self): @@ -379,8 +376,7 @@ def maximal_elements(self): s = ct.translation_factors()[1] R = RootSystem(ct).weight_space() Lambda = R.fundamental_weights() - orbit = [R.reduced_word_of_translation(x) - for x in (s*(Lambda[1]-Lambda[1].level()*Lambda[0]))._orbit_iter()] + orbit = [R.reduced_word_of_translation(x) for x in (s * (Lambda[1] - Lambda[1].level() * Lambda[0]))._orbit_iter()] return [self.W.from_reduced_word(x) for x in orbit] @@ -518,8 +514,7 @@ class PieriFactors_type_A_affine(PieriFactors_affine_type): """ @staticmethod - def __classcall__(cls, W, min_length=0, max_length=infinity, - min_support=frozenset(), max_support=None): + def __classcall__(cls, W, min_length=0, max_length=infinity, min_support=frozenset(), max_support=None): r""" TESTS:: @@ -589,8 +584,7 @@ def __init__(self, W, min_length, max_length, min_support, max_support): self._max_support = frozenset(max_support) if not self._min_support.issubset(self._max_support): - raise ValueError("the min support must be a subset " - "of the max support") + raise ValueError("the min support must be a subset " "of the max support") self._extra_support = self._max_support.difference(self._min_support) @@ -620,11 +614,7 @@ def subset(self, length): sage: PF.cardinality() 15 """ - return self.__class__(self.W, - min_support=self._min_support, - max_support=self._max_support, - min_length=length, - max_length=length) + return self.__class__(self.W, min_support=self._min_support, max_support=self._max_support, min_length=length, max_length=length) def maximal_elements_combinatorial(self): r""" @@ -654,7 +644,7 @@ def _test_maximal_elements(self, **options): """ tester = self._tester(**options) index_set = self.W.index_set() - if self._min_length > 0 or self._max_length < len(self.W.index_set())-1 or self._max_support != frozenset(index_set): + if self._min_length > 0 or self._max_length < len(self.W.index_set()) - 1 or self._max_support != frozenset(index_set): tester.info("\n Strict subset of the Pieri factors; skipping test") return return super()._test_maximal_elements(**options) @@ -698,10 +688,7 @@ def __contains__(self, w): if len(support) < len(red): # There should be no repetitions return False - if not (self._min_length <= len(support) and - len(support) <= self._max_length and - self._min_support.issubset(support) and - support.issubset(self._max_support)): + if not (self._min_length <= len(support) and len(support) <= self._max_length and self._min_support.issubset(support) and support.issubset(self._max_support)): return False rank, unrank = sage.combinat.ranker.from_list(red) @@ -753,7 +740,7 @@ def cardinality(self): 15 """ if self._min_length == len(self._min_support) and self._max_length == len(self._max_support) - 1: - return Integer(2**(len(self._extra_support)) - 1) + return Integer(2 ** (len(self._extra_support)) - 1) return self.generating_series(weight=ConstantFunction(1)) def generating_series(self, weight=None): @@ -772,8 +759,7 @@ def generating_series(self, weight=None): weight = self.default_weight() l_min = len(self._min_support) l_max = len(self._max_support) - return sum(Integer(l_max - l_min).binomial(l - l_min) * weight(l) - for l in range(self._min_length, self._max_length + 1)) + return sum(Integer(l_max - l_min).binomial(l - l_min) * weight(l) for l in range(self._min_length, self._max_length + 1)) def __iter__(self): r""" @@ -794,9 +780,9 @@ def __iter__(self): [[0], [1], [2], [3], [4], [1, 0]] """ from sage.combinat.subset import Subsets + for l in range(self._min_length, self._max_length + 1): - for extra in Subsets(self._extra_support, - l - len(self._min_support)): + for extra in Subsets(self._extra_support, l - len(self._min_support)): yield self[self._min_support.union(extra)] def stanley_symm_poly_weight(self, w): @@ -856,7 +842,7 @@ def maximal_elements_combinatorial(self): [[0, 1, 2, 3, 2, 1], [1, 0, 1, 2, 3, 2], [2, 1, 0, 1, 2, 3], [3, 2, 1, 0, 1, 2], [2, 3, 2, 1, 0, 1], [1, 2, 3, 2, 1, 0]] """ n = self.W.n - rho = self.W.from_reduced_word(range(1, n-1))*self.W.from_reduced_word(range(n-1,-1,-1)) + rho = self.W.from_reduced_word(range(1, n - 1)) * self.W.from_reduced_word(range(n - 1, -1, -1)) rotations = [] for i in range(2 * (n - 1)): rho = rho.apply_simple_reflections(rho.descents()).apply_simple_reflections(rho.descents(), side='left') @@ -889,8 +875,7 @@ def stanley_symm_poly_weight(self, w): # vertices is empty, in which case subgraph tries another # method which turns out to currently fail with Dynkin diagrams D = DiGraph(DynkinDiagram(w.parent().cartan_type())) - return D.subgraph(set(w.reduced_word()), - algorithm='delete').number_of_connected_components() + return D.subgraph(set(w.reduced_word()), algorithm='delete').number_of_connected_components() class PieriFactors_type_B_affine(PieriFactors_affine_type): @@ -946,13 +931,13 @@ def maximal_elements_combinatorial(self): [[1, 0, 2, 3, 4, 3, 2], [2, 1, 0, 2, 3, 4, 3], [3, 2, 1, 0, 2, 3, 4], [4, 3, 2, 1, 0, 2, 3], [3, 4, 3, 2, 1, 0, 2], [2, 3, 4, 3, 2, 1, 0], [1, 2, 3, 4, 3, 2, 1], [0, 2, 3, 4, 3, 2, 0]] """ n = self.W.n - rho = self.W.from_reduced_word(range(2,n-1))*self.W.from_reduced_word(range(n-1,-1,-1)) + rho = self.W.from_reduced_word(range(2, n - 1)) * self.W.from_reduced_word(range(n - 1, -1, -1)) rotations = [] for i in range(2 * (n - 2)): rho = rho.apply_simple_reflections(rho.descents()).apply_simple_reflections(rho.descents(), side='left') rotations.append(rho) - rotations.append(self.W.from_reduced_word(range(1,n-1))*self.W.from_reduced_word(range(n-1,0,-1))) - rotations.append(self.W.from_reduced_word([0])*self.W.from_reduced_word(range(2,n-1))*self.W.from_reduced_word(range(n-1,1,-1))*self.W.from_reduced_word([0])) + rotations.append(self.W.from_reduced_word(range(1, n - 1)) * self.W.from_reduced_word(range(n - 1, 0, -1))) + rotations.append(self.W.from_reduced_word([0]) * self.W.from_reduced_word(range(2, n - 1)) * self.W.from_reduced_word(range(n - 1, 1, -1)) * self.W.from_reduced_word([0])) return rotations def stanley_symm_poly_weight(self, w): @@ -1061,16 +1046,16 @@ def maximal_elements_combinatorial(self): True """ n = self.W.n - rho = self.W.from_reduced_word(range(2,n))*self.W.from_reduced_word(range(n-3,-1,-1)) + rho = self.W.from_reduced_word(range(2, n)) * self.W.from_reduced_word(range(n - 3, -1, -1)) rotations = [] for i in range(2 * (n - 3)): - rho = rho.apply_simple_reflections(rho.descents()).apply_simple_reflections(rho.descents(),side='left') + rho = rho.apply_simple_reflections(rho.descents()).apply_simple_reflections(rho.descents(), side='left') rotations.append(rho) - rotations.append(self.W.from_reduced_word(range(1,n))*self.W.from_reduced_word(range(n-3,0,-1))) - rotations.append(self.W.from_reduced_word([0])*self.W.from_reduced_word(range(2,n))*self.W.from_reduced_word(range(n-3,1,-1))*self.W.from_reduced_word([0])) - rotations.append(self.W.from_reduced_word(range(n-2,-1,-1))*self.W.from_reduced_word(range(2,n-1))) - rotations.append(self.W.from_reduced_word([n-1])*self.W.from_reduced_word(range(n-3,-1,-1))*self.W.from_reduced_word(range(2,n-2))*self.W.from_reduced_word([n-1])) + rotations.append(self.W.from_reduced_word(range(1, n)) * self.W.from_reduced_word(range(n - 3, 0, -1))) + rotations.append(self.W.from_reduced_word([0]) * self.W.from_reduced_word(range(2, n)) * self.W.from_reduced_word(range(n - 3, 1, -1)) * self.W.from_reduced_word([0])) + rotations.append(self.W.from_reduced_word(range(n - 2, -1, -1)) * self.W.from_reduced_word(range(2, n - 1))) + rotations.append(self.W.from_reduced_word([n - 1]) * self.W.from_reduced_word(range(n - 3, -1, -1)) * self.W.from_reduced_word(range(2, n - 2)) * self.W.from_reduced_word([n - 1])) return rotations def stanley_symm_poly_weight(self, w): @@ -1129,6 +1114,7 @@ def stanley_symm_poly_weight(self, w): # Inserts those classes in CartanTypes from sage.combinat.root_system import type_A_affine, type_B_affine, type_C_affine, type_D_affine, type_A, type_B + type_A_affine.CartanType.PieriFactors = PieriFactors_type_A_affine type_B_affine.CartanType.PieriFactors = PieriFactors_type_B_affine type_C_affine.CartanType.PieriFactors = PieriFactors_type_C_affine @@ -1140,11 +1126,11 @@ def stanley_symm_poly_weight(self, w): # introduced rigorously # # import type_C, type_D, type_E, type_F, type_G, type_E_affine, type_F_affine, type_G_affine -#type_C.CartanType.PieriFactors = PieriFactors_type_C -#type_D.CartanType.PieriFactors = PieriFactors_type_D -#type_E.CartanType.PieriFactors = PieriFactors_type_E -#type_F.CartanType.PieriFactors = PieriFactors_type_F -#type_G.CartanType.PieriFactors = PieriFactors_type_G -#type_E_affine.CartanType.PieriFactors = PieriFactors_type_E_affine -#type_F_affine.CartanType.PieriFactors = PieriFactors_type_F_affine -#type_G_affine.CartanType.PieriFactors = PieriFactors_type_G_affine +# type_C.CartanType.PieriFactors = PieriFactors_type_C +# type_D.CartanType.PieriFactors = PieriFactors_type_D +# type_E.CartanType.PieriFactors = PieriFactors_type_E +# type_F.CartanType.PieriFactors = PieriFactors_type_F +# type_G.CartanType.PieriFactors = PieriFactors_type_G +# type_E_affine.CartanType.PieriFactors = PieriFactors_type_E_affine +# type_F_affine.CartanType.PieriFactors = PieriFactors_type_F_affine +# type_G_affine.CartanType.PieriFactors = PieriFactors_type_G_affine diff --git a/src/sage/combinat/root_system/plot.py b/src/sage/combinat/root_system/plot.py index 97f76c85d14..eda6adc2866 100644 --- a/src/sage/combinat/root_system/plot.py +++ b/src/sage/combinat/root_system/plot.py @@ -826,8 +826,8 @@ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.combinat.root_system.cartan_type import CartanType -lazy_import("sage.combinat.root_system.root_lattice_realizations", - "RootLatticeRealizations") + +lazy_import("sage.combinat.root_system.root_lattice_realizations", "RootLatticeRealizations") class PlotOptions: @@ -843,15 +843,17 @@ class PlotOptions: system plotting """ - def __init__(self, space, - projection=True, - bounding_box=3, - color=CartanType.color, - labels=True, - level=None, - affine=None, - arrowsize=5, - ): + def __init__( + self, + space, + projection=True, + bounding_box=3, + color=CartanType.color, + labels=True, + level=None, + affine=None, + arrowsize=5, + ): r""" TESTS:: @@ -938,8 +940,9 @@ def __init__(self, space, from sage.rings.real_mpfr import RR from sage.geometry.polyhedron.constructor import Polyhedron from itertools import product + if bounding_box in RR: - bounding_box = [[-bounding_box,bounding_box]] * self.dimension + bounding_box = [[-bounding_box, bounding_box]] * self.dimension else: if not len(bounding_box) == self.dimension: raise TypeError("bounding_box argument doesn't match with the plot dimension") @@ -971,7 +974,7 @@ def in_bounding_box(self, x): """ return self.bounding_box.contains(self.projection(x)) - def text(self, label, position, rgbcolor=(0,0,0)): + def text(self, label, position, rgbcolor=(0, 0, 0)): r""" Return text widget with label ``label`` at position ``position``. @@ -1008,16 +1011,18 @@ def text(self, label, position, rgbcolor=(0,0,0)): if self.labels: if self.dimension <= 2: if not isinstance(label, str): - label = "$"+str(latex(label))+"$" + label = "$" + str(latex(label)) + "$" from sage.plot.text import text + return text(label, position, fontsize=15, rgbcolor=rgbcolor) if self.dimension == 3: # LaTeX labels not yet supported in 3D if isinstance(label, str): - label = label.replace("{","").replace("}","").replace("$","").replace("_","") + label = label.replace("{", "").replace("}", "").replace("$", "").replace("_", "") else: label = str(label) from sage.plot.plot3d.shapes2 import text3d + return text3d(label, position, rgbcolor=rgbcolor) raise NotImplementedError("Plots in dimension > 3") else: @@ -1252,6 +1257,7 @@ def finalize(self, G): [] """ from sage.plot.graphics import Graphics + if self.dimension == 2: if G == 0: G = Graphics() @@ -1261,6 +1267,7 @@ def finalize(self, G): elif self.dimension == 3: if G == 0: from sage.plot.plot3d.base import Graphics3dGroup + G = Graphics3dGroup() G.aspect_ratio(1) # TODO: Configuration axes @@ -1316,6 +1323,7 @@ def family_of_vectors(self, vectors): Text '$2$' at the point (-0.525,0.909325744308...)] """ from sage.plot.arrow import arrow + tail = self.origin_projected G = self.empty() for i in vectors.keys(): @@ -1324,11 +1332,10 @@ def family_of_vectors(self, vectors): head = self.projection(vectors[i]) if head != tail: G += arrow(tail, head, rgbcolor=self.color(i), arrowsize=self._arrowsize) - G += self.text(i, 1.05*head) + G += self.text(i, 1.05 * head) return self.finalize(G) - def cone(self, rays=[], lines=[], color='black', thickness=1, alpha=1, wireframe=False, - label=None, draw_degenerate=True, as_polyhedron=False): + def cone(self, rays=[], lines=[], color='black', thickness=1, alpha=1, wireframe=False, label=None, draw_degenerate=True, as_polyhedron=False): r""" Return the cone generated by the given rays and lines. @@ -1400,6 +1407,7 @@ def cone(self, rays=[], lines=[], color='black', thickness=1, alpha=1, wireframe if color is None: return self.empty() from sage.geometry.polyhedron.constructor import Polyhedron + # TODO: we currently convert lines into rays, which simplify a # bit the calculation of the intersection. But it would be # nice to benefit from the new ``lines`` option of Polyhedra @@ -1415,9 +1423,9 @@ def cone(self, rays=[], lines=[], color='black', thickness=1, alpha=1, wireframe vertices = [] # Apply the projection (which is supposed to be affine) - vertices = [ self.projection(vertex) for vertex in vertices ] - rays = [ self.projection(ray)-self.projection(self.space.zero()) for ray in rays ] - rays = [ ray for ray in rays if ray ] # Polyhedron does not accept yet zero rays + vertices = [self.projection(vertex) for vertex in vertices] + rays = [self.projection(ray) - self.projection(self.space.zero()) for ray in rays] + rays = [ray for ray in rays if ray] # Polyhedron does not accept yet zero rays # Build the polyhedron p = Polyhedron(vertices=vertices, rays=rays) @@ -1430,15 +1438,14 @@ def cone(self, rays=[], lines=[], color='black', thickness=1, alpha=1, wireframe if wireframe: options = dict(point=False, line=dict(width=10), polygon=False) center = q.center() - q = q.translation(-center).dilation(ZZ(95)/ZZ(100)).translation(center) + q = q.translation(-center).dilation(ZZ(95) / ZZ(100)).translation(center) else: - options = dict(wireframe=False, line={"thickness":thickness}) + options = dict(wireframe=False, line={"thickness": thickness}) result = q.plot(color=color, alpha=alpha, **options) if label is not None: # Put the label on the vertex having largest z, then y, then x coordinate. - vertices = sorted([vector(v) for v in q.vertices()], - key=lambda x: list(reversed(x))) - result += self.text(label, 1.05*vector(vertices[-1])) + vertices = sorted([vector(v) for v in q.vertices()], key=lambda x: list(reversed(x))) + result += self.text(label, 1.05 * vector(vertices[-1])) return result return self.empty() @@ -1490,6 +1497,7 @@ def reflection_hyperplane(self, coroot, as_polyhedron=False): upon which the hyperplane label is attached. """ from sage.matrix.constructor import matrix + L = self.space label = coroot # scalar currently only handles scalar product with @@ -1501,12 +1509,11 @@ def reflection_hyperplane(self, coroot, as_polyhedron=False): # Compute the kernel of the linear form associated to the coroot vectors = matrix([b.scalar(coroot) for b in L.basis()]).right_kernel().basis() basis = [L.from_vector(v) for v in vectors] - if self.dimension == 3: # LaTeX labels not yet supported in 3D + if self.dimension == 3: # LaTeX labels not yet supported in 3D text_label = "H_%s$" % (str(label)) else: text_label = "$H_{%s}$" % (latex(label)) - return self.cone(lines=basis, color=self.color(label), label=text_label, - as_polyhedron=as_polyhedron) + return self.cone(lines=basis, color=self.color(label), label=text_label, as_polyhedron=as_polyhedron) @cached_function @@ -1591,20 +1598,21 @@ def barycentric_projection_matrix(n, angle=0): """ from sage.matrix.constructor import matrix from sage.misc.functional import sqrt + n = ZZ(n) if n == 0: return matrix(QQ, 0, 1) - a = 1/n - b = sqrt(1-a**2) - result = b * barycentric_projection_matrix(n-1) - result = result.augment(vector([0]*(n-1))) - result = result.stack(matrix([[a]*n+[-1]])) + a = 1 / n + b = sqrt(1 - a**2) + result = b * barycentric_projection_matrix(n - 1) + result = result.augment(vector([0] * (n - 1))) + result = result.stack(matrix([[a] * n + [-1]])) assert sum(result.columns()).is_zero() if angle and n == 2: from sage.functions.trig import sin from sage.functions.trig import cos - rotation = matrix([[sin(angle), cos(angle)], - [-cos(angle), sin(angle)]]) + + rotation = matrix([[sin(angle), cos(angle)], [-cos(angle), sin(angle)]]) result = rotation * result result.set_immutable() return result diff --git a/src/sage/combinat/root_system/reflection_group_complex.py b/src/sage/combinat/root_system/reflection_group_complex.py index 526509de725..4fa33d8db22 100644 --- a/src/sage/combinat/root_system/reflection_group_complex.py +++ b/src/sage/combinat/root_system/reflection_group_complex.py @@ -262,15 +262,15 @@ def __init__(self, W_types, index_set=None, hyperplane_index_set=None, reflectio type_dict["series"] = X.series.sage() type_dict["rank"] = X.rank.sage() type_dict["indices"] = X.indices.sage() - if hasattr(X.ST,"sage"): + if hasattr(X.ST, "sage"): type_dict["ST"] = X.ST.sage() - elif hasattr(X.p,"sage") and hasattr(X.q,"sage"): - type_dict["ST"] = ( X.p.sage(), X.q.sage(), X.rank.sage() ) - elif hasattr(X.bond,"sage"): + elif hasattr(X.p, "sage") and hasattr(X.q, "sage"): + type_dict["ST"] = (X.p.sage(), X.q.sage(), X.rank.sage()) + elif hasattr(X.bond, "sage"): type_dict["bond"] = X.bond.sage() - if type_dict["series"] == "B" and (X.cartanType.sage() == 1 or X.indices.sage() == [2,1]): + if type_dict["series"] == "B" and (X.cartanType.sage() == 1 or X.indices.sage() == [2, 1]): type_dict["series"] = "C" - reflection_type.append( type_dict ) + reflection_type.append(type_dict) self._type = reflection_type self._gap_group = prod(W_components) @@ -287,17 +287,15 @@ def __init__(self, W_types, index_set=None, hyperplane_index_set=None, reflectio if len(generators) == self._rank: category = ComplexReflectionGroups().Finite().WellGenerated() if all(str(W_comp).find('CoxeterGroup') >= 0 for W_comp in W_components): - category = Category.join([category,CoxeterGroups()]) + category = Category.join([category, CoxeterGroups()]) else: category = ComplexReflectionGroups().Finite() if len(self._type) == 1: category = category.Irreducible() - category = Category.join([category,PermutationGroups()]).Finite() + category = Category.join([category, PermutationGroups()]).Finite() - PermutationGroup_generic.__init__(self, gens=generators, - canonicalize=False, - category=category) + PermutationGroup_generic.__init__(self, gens=generators, canonicalize=False, category=category) l_set = list(range(1, len(self.gens()) + 1)) if self._index_set is None: @@ -305,14 +303,14 @@ def __init__(self, W_types, index_set=None, hyperplane_index_set=None, reflectio else: if len(self._index_set) != len(l_set): raise ValueError("the given index set (= %s) does not have the right size" % self._index_set.values()) - self._index_set_inverse = {i: ii for ii,i in enumerate(self._index_set)} + self._index_set_inverse = {i: ii for ii, i in enumerate(self._index_set)} Nstar_set = list(range(1, self.number_of_reflection_hyperplanes() + 1)) if self._hyperplane_index_set is None: self._hyperplane_index_set = tuple(Nstar_set) else: if len(self._hyperplane_index_set) != len(Nstar_set): raise ValueError("the given hyperplane index set (= %s) does not have the right size" % self._index_set.values()) - self._hyperplane_index_set_inverse = {i: ii for ii,i in enumerate(self._hyperplane_index_set)} + self._hyperplane_index_set_inverse = {i: ii for ii, i in enumerate(self._hyperplane_index_set)} N_set = list(range(1, self.number_of_reflections() + 1)) if self._reflection_index_set is None: @@ -320,7 +318,7 @@ def __init__(self, W_types, index_set=None, hyperplane_index_set=None, reflectio else: if len(self._reflection_index_set) != len(N_set): raise ValueError("the given reflection index set (= %s) does not have the right size" % self._index_set.values()) - self._reflection_index_set_inverse = {i: ii for ii,i in enumerate(self._reflection_index_set)} + self._reflection_index_set_inverse = {i: ii for ii, i in enumerate(self._reflection_index_set)} def _irrcomp_repr_(self, W_type): r""" @@ -342,7 +340,7 @@ def _irrcomp_repr_(self, W_type): if W_type["ST"] in ZZ: type_str += "ST" + str(W_type["ST"]) else: - type_str += 'G' + str(W_type["ST"]).replace(' ','') + type_str += 'G' + str(W_type["ST"]).replace(' ', '') else: type_str += str(W_type["series"]) if W_type["series"] == "I": @@ -387,7 +385,8 @@ def iteration_tracking_words(self): (1,5)(2,4)(3,6) """ from sage.combinat.root_system.reflection_group_c import iterator_tracking_words - for w,word in iterator_tracking_words(self): + + for w, word in iterator_tracking_words(self): w._reduced_word = word yield w @@ -505,8 +504,7 @@ def distinguished_reflections(self): t = self(str(r)) if t not in R: R.append(t) - return Family(self._hyperplane_index_set, - lambda i: R[self._hyperplane_index_set_inverse[i]]) + return Family(self._hyperplane_index_set, lambda i: R[self._hyperplane_index_set_inverse[i]]) def distinguished_reflection(self, i): r""" @@ -605,15 +603,14 @@ def reflection_hyperplanes(self, as_linear_functionals=False, with_order=False): """ Hs = [] for r in self.distinguished_reflections(): - mat = (r.to_matrix().transpose() - identity_matrix(self.rank())) + mat = r.to_matrix().transpose() - identity_matrix(self.rank()) if as_linear_functionals: - Hs.append( mat.row_space().gen() ) + Hs.append(mat.row_space().gen()) else: - Hs.append( mat.right_kernel() ) + Hs.append(mat.right_kernel()) if with_order: - Hs[-1] = (Hs[-1],r.order()) - return Family(self._hyperplane_index_set, - lambda i: Hs[self._hyperplane_index_set_inverse[i]]) + Hs[-1] = (Hs[-1], r.order()) + return Family(self._hyperplane_index_set, lambda i: Hs[self._hyperplane_index_set_inverse[i]]) def reflection_hyperplane(self, i, as_linear_functional=False, with_order=False): r""" @@ -698,9 +695,8 @@ def reflections(self): T = self.distinguished_reflections().values() for i in range(self.number_of_reflection_hyperplanes()): for j in range(2, T[i].order()): - T.append(T[i]**j) - return Family(self._reflection_index_set, - lambda i: T[self._reflection_index_set_inverse[i]]) + T.append(T[i] ** j) + return Family(self._reflection_index_set, lambda i: T[self._reflection_index_set_inverse[i]]) def reflection(self, i): r""" @@ -763,12 +759,12 @@ def discriminant(self): x0^6*x1^2 - 6*x0^5*x1^3 + 13*x0^4*x1^4 - 12*x0^3*x1^5 + 4*x0^2*x1^6 """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + n = self.rank() P = PolynomialRing(QQ, 'x', n) x = P.gens() - return prod(sum(x[i] * alpha[i] for i in range(n)) ** o - for alpha,o in self.reflection_hyperplanes(True, True)) + return prod(sum(x[i] * alpha[i] for i in range(n)) ** o for alpha, o in self.reflection_hyperplanes(True, True)) @cached_method def discriminant_in_invariant_ring(self, invariants=None): @@ -806,6 +802,7 @@ def discriminant_in_invariant_ring(self, invariants=None): """ from sage.arith.functions import lcm from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + n = self.rank() if invariants is None: @@ -818,6 +815,7 @@ def discriminant_in_invariant_ring(self, invariants=None): R = QQ else: from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField + R = UniversalCyclotomicField() # TODO: The rest of this could be split off as a general function @@ -834,21 +832,18 @@ def discriminant_in_invariant_ring(self, invariants=None): T = PolynomialRing(R, 't', n) - FsPowers = [prod(power(val, part[j]) for j,val in enumerate(Fs)).change_ring(P) - for part in Ps] + FsPowers = [prod(power(val, part[j]) for j, val in enumerate(Fs)).change_ring(P) for part in Ps] D = D.change_ring(P) - f = D - sum(X[i] * F for i,F in enumerate(FsPowers)) + f = D - sum(X[i] * F for i, F in enumerate(FsPowers)) coeffs = f.coefficients() - lhs = matrix(R, [[coeff.coefficient(X[i]) for i in range(m)] - for coeff in coeffs]) + lhs = matrix(R, [[coeff.coefficient(X[i]) for i in range(m)] for coeff in coeffs]) rhs = vector([coeff.constant_coefficient() for coeff in coeffs]) coeffs = lhs.solve_right(rhs) # Cancel denominators coeffs = lcm(i.denominator() for i in coeffs) * coeffs - mons = vector([prod(tj**part[j] for j,tj in enumerate(T.gens())) - for part in Ps]) + mons = vector([prod(tj ** part[j] for j, tj in enumerate(T.gens())) for part in Ps]) return sum(coeffs[i] * mons[i] for i in range(m)) @cached_method @@ -890,8 +885,7 @@ def is_crystallographic(self) -> bool: sage: W.is_crystallographic() False """ - return self.is_real() and all(t.to_matrix().base_ring() is QQ - for t in self.simple_reflections()) + return self.is_real() and all(t.to_matrix().base_ring() is QQ for t in self.simple_reflections()) def number_of_irreducible_components(self) -> int: r""" @@ -926,10 +920,11 @@ def irreducible_components(self) -> list: Irreducible real reflection group of rank 3 and type B3] """ from sage.combinat.root_system.reflection_group_real import ReflectionGroup + irr_comps = [] for W_type in self._type: - if W_type["series"] in ["A","B","D","E","F","G","H","I"]: - W_str = (W_type["series"],W_type["rank"]) + if W_type["series"] in ["A", "B", "D", "E", "F", "G", "H", "I"]: + W_str = (W_type["series"], W_type["rank"]) elif "ST" in W_type: W_str = W_type["ST"] irr_comps.append(ReflectionGroup(W_str)) @@ -997,8 +992,7 @@ def conjugacy_classes(self): sage: sum(len(C) for C in W.conjugacy_classes()) == W.cardinality() True """ - return Family(self.conjugacy_classes_representatives(), - lambda w: w.conjugacy_class()) + return Family(self.conjugacy_classes_representatives(), lambda w: w.conjugacy_class()) def rank(self): r""" @@ -1068,7 +1062,7 @@ def degrees(self): except AttributeError: return tuple(sorted(self._gap_group.ReflectionDegrees().sage())) else: - return sum([comp.degrees() for comp in self.irreducible_components()],tuple()) + return sum([comp.degrees() for comp in self.irreducible_components()], tuple()) @cached_method def codegrees(self): @@ -1109,10 +1103,9 @@ def codegrees(self): if self.is_irreducible(): if self.is_well_generated(): h = self.coxeter_number() - return tuple([h-d for d in self.degrees()]) - return tuple(sorted(self._gap_group.ReflectionCoDegrees().sage(), - reverse=True)) - return sum([comp.codegrees() for comp in self.irreducible_components()],tuple()) + return tuple([h - d for d in self.degrees()]) + return tuple(sorted(self._gap_group.ReflectionCoDegrees().sage(), reverse=True)) + return sum([comp.codegrees() for comp in self.irreducible_components()], tuple()) @cached_method def reflection_eigenvalues_family(self): @@ -1159,8 +1152,7 @@ def reflection_eigenvalues_family(self): """ class_representatives = self.conjugacy_classes_representatives() Ev_list = self._gap_group.ReflectionEigenvalues().sage() - return Family(class_representatives, - lambda w: Ev_list[class_representatives.index(w)]) + return Family(class_representatives, lambda w: Ev_list[class_representatives.index(w)]) @cached_method def reflection_eigenvalues(self, w, is_class_representative=False): @@ -1216,7 +1208,8 @@ def simple_roots(self): Finite family {1: (1, 0, 0, 0, 0), 2: (0, 1, 0, 0, 0), 3: (0, 0, 1, 0, 0), 4: (0, 0, 0, 1, 0), 5: (0, 0, 0, -1, 1)} """ from sage.sets.family import Family - return Family({ind:self.roots()[i] for i,ind in enumerate(self._index_set)}) + + return Family({ind: self.roots()[i] for i, ind in enumerate(self._index_set)}) def simple_root(self, i): r""" @@ -1267,12 +1260,13 @@ def simple_coroots(self): Finite family {1: (2, -1, 0, 0, 0), 2: (-1, 2, -1, 0, 0), 3: (0, -1, 2, 0, 0), 4: (0, 0, 0, -2*E(3) - E(3)^2, 0), 5: (0, 0, 0, -1, 1)} """ from sage.sets.family import Family + coroots = self._gap_group.simpleCoroots.sage() - for i,coroot in enumerate(coroots): + for i, coroot in enumerate(coroots): coroot = vector(coroot) coroot.set_immutable() coroots[i] = coroot - return Family({ind:coroots[i] for i,ind in enumerate(self.index_set())}) + return Family({ind: coroots[i] for i, ind in enumerate(self.index_set())}) def simple_coroot(self, i): r""" @@ -1313,6 +1307,7 @@ def independent_roots(self): return Delta from sage.sets.family import Family + basis = {} for ind in self._index_set: vec = Delta[ind] @@ -1365,8 +1360,7 @@ def roots(self): (0, 0, 0, -E(3), E(3)^2), (0, 0, 0, E(3)^2, -E(3)^2), (0, 0, 0, -E(3)^2, E(3)^2)] """ - roots = [vector(sage_eval(str(root).replace("^", "**"))) - for root in self._gap_group.roots] + roots = [vector(sage_eval(str(root).replace("^", "**"))) for root in self._gap_group.roots] for v in roots: v.set_immutable() return roots @@ -1413,18 +1407,18 @@ def fundamental_invariants(self): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing if not self.is_irreducible(): - return sum([W.fundamental_invariants() for W in self.irreducible_components() ],tuple()) + return sum([W.fundamental_invariants() for W in self.irreducible_components()], tuple()) - I = [ str(p) for p in gap3('List(Invariants(%s),x->ApplyFunc(x,List([0..%s],i->Mvp(SPrint("x",i)))))' % (self._gap_group._name, self.rank()-1)) ] - P = PolynomialRing(QQ,['x%s' % i for i in range(self.rank())]) + I = [str(p) for p in gap3('List(Invariants(%s),x->ApplyFunc(x,List([0..%s],i->Mvp(SPrint("x",i)))))' % (self._gap_group._name, self.rank() - 1))] + P = PolynomialRing(QQ, ['x%s' % i for i in range(self.rank())]) x = P.gens() for i in range(len(I)): - I[i] = I[i].replace('^','**') + I[i] = I[i].replace('^', '**') I[i] = re.compile(r'E(\d\d*)').sub(r'E(\1)', I[i]) I[i] = re.compile(r'(\d)E\(').sub(r'\1*E(', I[i]) for j in range(len(x)): - I[i] = I[i].replace('x%s' % j,'*x[%s]' % j) - I[i] = I[i].replace("+*","+").replace("-*","-").replace("ER(5)","*(E(5)-E(5)**2-E(5)**3+E(5)**4)").lstrip("*") + I[i] = I[i].replace('x%s' % j, '*x[%s]' % j) + I[i] = I[i].replace("+*", "+").replace("-*", "-").replace("ER(5)", "*(E(5)-E(5)**2-E(5)**3+E(5)**4)").lstrip("*") # sage_eval is used since eval kills the rational entries! I = [sage_eval(p, locals={'x': x}) for p in I] return tuple(sorted(I, key=lambda f: f.degree())) @@ -1454,7 +1448,7 @@ def jacobian_of_fundamental_invariants(self, invs=None): invs = self.fundamental_invariants() P = invs[0].parent() X = P.gens() - return matrix(P, [[ P(g).derivative(x) for x in X ] for g in invs ]) + return matrix(P, [[P(g).derivative(x) for x in X] for g in invs]) @cached_method def primitive_vector_field(self, invs=None): @@ -1482,7 +1476,7 @@ def primitive_vector_field(self, invs=None): h = self.coxeter_number() if invs is None: invs = self.fundamental_invariants() - degs = [ f.degree() for f in invs ] + degs = [f.degree() for f in invs] J = self.jacobian_of_fundamental_invariants(invs) return J.inverse().row(degs.index(h)) @@ -1503,7 +1497,7 @@ def apply_vector_field(self, f, vf=None): """ if vf is None: vf = self.primitive_vector_field() - return sum( vf[i]*f.derivative(gen) for i,gen in enumerate(f.parent().gens()) ) + return sum(vf[i] * f.derivative(gen) for i, gen in enumerate(f.parent().gens())) def cartan_matrix(self): r""" @@ -1650,32 +1644,30 @@ def invariant_form(self, brute_force=False): ring = QQ else: from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField + ring = UniversalCyclotomicField() form = zero_matrix(ring, n, n) C = self.cartan_matrix() if not self.is_well_generated(): - indep_inds = sorted(self._index_set_inverse[key] - for key in self.independent_roots().keys()) - C = C.matrix_from_rows_and_columns(indep_inds,indep_inds) + indep_inds = sorted(self._index_set_inverse[key] for key in self.independent_roots().keys()) + C = C.matrix_from_rows_and_columns(indep_inds, indep_inds) for j in range(n): for i in range(j): - if C[j,i] != 0: - form[j,j] = (form[i,i] - * (C[i,j] * C[j,j].conjugate()) - / (C[j,i].conjugate() * C[i,i])) - if form[j,j] == 0: - form[j,j] = ring.one() + if C[j, i] != 0: + form[j, j] = form[i, i] * (C[i, j] * C[j, j].conjugate()) / (C[j, i].conjugate() * C[i, i]) + if form[j, j] == 0: + form[j, j] = ring.one() for j in range(n): for i in range(j): - form[j, i] = C[i, j] * form[i, i] / C[i,i] + form[j, i] = C[i, j] * form[i, i] / C[i, i] form[i, j] = form[j, i].conjugate() B = self.base_change_matrix() form = B * form * B.conjugate().transpose() - form /= form[0,0] + form /= form[0, 0] # normalization try: @@ -1723,9 +1715,8 @@ def action_on_root(w, beta): @cached_function def invariant_value(i, j): if i > j: - return invariant_value(j,i).conjugate() - val = sum(action_on_root(w, Delta[i]) * action_on_root(w, Delta[j]).conjugate() - for w in self) + return invariant_value(j, i).conjugate() + val = sum(action_on_root(w, Delta[i]) * action_on_root(w, Delta[j]).conjugate() for w in self) if val in QQ: val = QQ(val) return val @@ -1737,8 +1728,7 @@ def invariant_value(i, j): coeff = QQ(coeff) coeffs.append(coeff) - return matrix([[invariant_value(i,j) / self.cardinality() for j in range(n)] - for i in range(n)]) + return matrix([[invariant_value(i, j) / self.cardinality() for j in range(n)] for i in range(n)]) def invariant_form_standardization(self): r""" @@ -1871,13 +1861,14 @@ def fake_degrees(self): 14400 """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(ZZ, 'q') fake_deg_list = [] gap_fak_deg = gap3.FakeDegrees(self._gap_group, 'X(Rationals)') for fake_poly in gap_fak_deg: fake_coef = fake_poly.coefficients.sage() - coeffs = [ZZ.zero()] * (fake_poly.Degree().sage()-len(fake_coef)+1) + coeffs = [ZZ.zero()] * (fake_poly.Degree().sage() - len(fake_coef) + 1) coeffs.extend(fake_coef) fake_deg_list.append(R(coeffs)) @@ -1923,11 +1914,11 @@ def coxeter_number(self, chi=None): # rec.N_s is the size of the orbit for rec in gap_hyp_rec: for k in range(1, int(rec.e_s)): - cox_chi += chi( G[int(rec.s)-1]**k ) * rec.N_s.sage() + cox_chi += chi(G[int(rec.s) - 1] ** k) * rec.N_s.sage() return self.number_of_reflections() - cox_chi // chi.degree() class Element(ComplexReflectionGroupElement): - #@cached_in_parent_method + # @cached_in_parent_method def conjugacy_class_representative(self): r""" Return a representative of the conjugacy class of ``self``. @@ -1948,7 +1939,7 @@ def conjugacy_class_representative(self): for w in W._conjugacy_classes: if self in W._conjugacy_classes[w]: return w - return W.conjugacy_classes_representatives()[ gap3("PositionClass(%s,%s)" % (W._gap_group._name,self)).sage()-1 ] + return W.conjugacy_classes_representatives()[gap3("PositionClass(%s,%s)" % (W._gap_group._name, self)).sage() - 1] def conjugacy_class(self): r""" @@ -1978,7 +1969,7 @@ def conjugacy_class(self): w = orbit[count] count += 1 for s in gens: - w_new = s*w*s**-1 + w_new = s * w * s**-1 if w_new not in orbit_set: orbit.append(w_new) orbit_set.add(w_new) @@ -1986,7 +1977,7 @@ def conjugacy_class(self): W._conjugacy_classes[self] = orbit_set return orbit_set - #@cached_in_parent_method + # @cached_in_parent_method def reflection_length(self, in_unitary_group=False): r""" Return the reflection length of ``self``. @@ -2052,7 +2043,7 @@ class Element(ComplexReflectionGroup.Element): # this method can be defined for well-generated, finite, # irreducible complex reflection group. The current # implementation uses this particular connection to chevie. - #@cached_in_parent_method + # @cached_in_parent_method def is_coxeter_element(self, which_primitive=1, is_class_representative=False): r""" Return ``True`` if ``self`` is a Coxeter element. @@ -2090,10 +2081,9 @@ def is_coxeter_element(self, which_primitive=1, is_class_representative=False): raise ValueError("this method is available for elements in irreducible, well-generated complex reflection groups") h = self.parent().coxeter_number() # to check regularity for a Coxeter number h, we get that an eigenvector is regular for free - return any(QQ(ev).denom() == h and QQ(ev).numer() == which_primitive - for ev in self.reflection_eigenvalues(is_class_representative=is_class_representative)) + return any(QQ(ev).denom() == h and QQ(ev).numer() == which_primitive for ev in self.reflection_eigenvalues(is_class_representative=is_class_representative)) - #@cached_in_parent_method + # @cached_in_parent_method def is_h_regular(self, is_class_representative=False): r""" Return whether ``self`` is regular. @@ -2118,10 +2108,9 @@ def is_h_regular(self, is_class_representative=False): raise ValueError("This method is available for elements in irreducible, well-generated complex reflection groups") h = self.parent().coxeter_number() # to check regularity for a Coxeter number h, we get that an eigenvector is regular for free - return any(QQ(ev).denom() == h - for ev in self.reflection_eigenvalues(is_class_representative=is_class_representative)) + return any(QQ(ev).denom() == h for ev in self.reflection_eigenvalues(is_class_representative=is_class_representative)) - #@cached_in_parent_method + # @cached_in_parent_method def is_regular(self, h, is_class_representative=False): r""" Return whether ``self`` is regular. @@ -2199,8 +2188,7 @@ def is_regular(self, h, is_class_representative=False): ev = QQ(ev) if h == ev.denom(): M = mat - E(ev.denom(), ev.numer()) * I - if all(not M.right_kernel().is_subspace( H.change_ring(UCF) ) - for H in P.reflection_hyperplanes()): + if all(not M.right_kernel().is_subspace(H.change_ring(UCF)) for H in P.reflection_hyperplanes()): return True return False @@ -2228,7 +2216,7 @@ def multi_partitions(n, S, i=None): i = 0 S = sorted(S) if n == 0: - return [[0]*len(S)] + return [[0] * len(S)] if i == len(S): return [] @@ -2236,8 +2224,8 @@ def multi_partitions(n, S, i=None): if k > n: return [] - coeffs1 = multi_partitions(n-k, S, i ) - coeffs2 = multi_partitions(n , S, i+1) + coeffs1 = multi_partitions(n - k, S, i) + coeffs2 = multi_partitions(n, S, i + 1) for coeff in coeffs1: coeff[i] += 1 coeffs = coeffs1 + coeffs2 @@ -2266,5 +2254,5 @@ def power(f, k): if sum(b) == 1: if b[1] == 1: return f**2 - return power(f,2**b.index(1)/2)**2 - return prod(power(f,2**i) for i,a in enumerate(b) if a) + return power(f, 2 ** b.index(1) / 2) ** 2 + return prod(power(f, 2**i) for i, a in enumerate(b) if a) diff --git a/src/sage/combinat/root_system/reflection_group_real.py b/src/sage/combinat/root_system/reflection_group_real.py index c5d6d9caba4..8582a78f740 100644 --- a/src/sage/combinat/root_system/reflection_group_real.py +++ b/src/sage/combinat/root_system/reflection_group_real.py @@ -126,6 +126,7 @@ def ReflectionGroup(*args, **kwds): raise ImportError("the GAP3 package 'chevie' is needed to work with (complex) reflection groups") from sage.interfaces.gap3 import gap3 + gap3.load_package("chevie") error_msg = "the input data (%s) is not valid for reflection groups" @@ -165,7 +166,7 @@ def ReflectionGroup(*args, **kwds): # converting the real types given as complex types # and then checking for real vs complex - for i,W_type in enumerate(W_types): + for i, W_type in enumerate(W_types): if W_type in ZZ: if W_type == 23: W_types[i] = ('H', 3) @@ -179,9 +180,9 @@ def ReflectionGroup(*args, **kwds): W_types[i] = ('E', 7) elif W_type == 37: W_types[i] = ('E', 8) - if isinstance(W_type,tuple) and len(W_type) == 3: + if isinstance(W_type, tuple) and len(W_type) == 3: if W_type[0] == W_type[1] == 1: - W_types[i] = ('A', W_type[2]-1) + W_types[i] = ('A', W_type[2] - 1) elif W_type[0] == 2 and W_type[1] == 1: W_types[i] = ('B', W_type[2]) elif W_type[0] == W_type[1] == 2: @@ -212,10 +213,7 @@ def ReflectionGroup(*args, **kwds): cls = ComplexReflectionGroup else: cls = RealReflectionGroup - return cls(tuple(W_types), - index_set=kwds.get('index_set', None), - hyperplane_index_set=kwds.get('hyperplane_index_set', None), - reflection_index_set=kwds.get('reflection_index_set', None)) + return cls(tuple(W_types), index_set=kwds.get('index_set', None), hyperplane_index_set=kwds.get('hyperplane_index_set', None), reflection_index_set=kwds.get('reflection_index_set', None)) @cached_function @@ -234,12 +232,14 @@ def is_chevie_available(): """ try: from sage.interfaces.gap3 import gap3 + gap3._start() gap3.load_package("chevie") return True except Exception: return False + ##################################################################### ## Classes @@ -262,21 +262,18 @@ def __init__(self, W_types, index_set=None, hyperplane_index_set=None, reflectio sage: W = ReflectionGroup(['A',3]) sage: TestSuite(W).run() """ - W_types = tuple([tuple(W_type) if isinstance(W_type, (list,tuple)) else W_type - for W_type in W_types]) + W_types = tuple([tuple(W_type) if isinstance(W_type, (list, tuple)) else W_type for W_type in W_types]) cartan_types = [] for W_type in W_types: W_type = CartanType(W_type) if not W_type.is_finite() or not W_type.is_irreducible(): raise ValueError("the given Cartan type of a component is not irreducible and finite") - cartan_types.append( W_type ) + cartan_types.append(W_type) if len(W_types) == 1: cls = IrreducibleComplexReflectionGroup else: cls = ComplexReflectionGroup - cls.__init__(self, W_types, index_set=index_set, - hyperplane_index_set=hyperplane_index_set, - reflection_index_set=reflection_index_set) + cls.__init__(self, W_types, index_set=index_set, hyperplane_index_set=hyperplane_index_set, reflection_index_set=reflection_index_set) def _repr_(self): r""" @@ -350,8 +347,8 @@ def iteration(self, algorithm='breadth', tracking_words=True): (1,5)(2,6)(3,7)(4,8) """ from sage.combinat.root_system.reflection_group_c import Iterator - return iter(Iterator(self, N=self.number_of_reflections(), - algorithm=algorithm, tracking_words=tracking_words)) + + return iter(Iterator(self, N=self.number_of_reflections(), algorithm=algorithm, tracking_words=tracking_words)) def __iter__(self): r""" @@ -457,7 +454,7 @@ def positive_roots(self): sage: W.positive_roots() [(1, 0, 0), (0, 1, 0), (0, 0, 1), (1, 1, 0), (0, 1, 1), (1, 1, 1)] """ - return self.roots()[:self.number_of_reflections()] + return self.roots()[: self.number_of_reflections()] def almost_positive_roots(self): r""" @@ -582,14 +579,14 @@ def fundamental_weights(self): 3 3 (1/4, 1/2, 3/4) (1/4, 1/2, -1/4) """ from sage.sets.family import Family + m = self.cartan_matrix().transpose().inverse() Delta = tuple(self.simple_roots()) zero = Delta[0].parent().zero() - weights = [sum([m[i, j] * sj for j, sj in enumerate(Delta)], zero) - for i in range(len(Delta))] + weights = [sum([m[i, j] * sj for j, sj in enumerate(Delta)], zero) for i in range(len(Delta))] for weight in weights: weight.set_immutable() - return Family({ind:weights[i] for i, ind in enumerate(self._index_set)}) + return Family({ind: weights[i] for i, ind in enumerate(self._index_set)}) def fundamental_weight(self, i): r""" @@ -692,6 +689,7 @@ def right_coset_representatives(self, J): [()] """ from sage.combinat.root_system.reflection_group_element import _gap_return + J_inv = [self._index_set_inverse[j] + 1 for j in J] S = str(gap3('ReducedRightCosetRepresentatives(%s,ReflectionSubgroup(%s,%s))' % (self._gap_group._name, self._gap_group._name, J_inv))) return [self(w, check=False) for w in _gap_return(S)] @@ -763,34 +761,25 @@ def bruhat_cone(self, x, y, side='upper', backend='cdd'): - [JS2021]_ """ if side == 'upper': - roots = [self.reflection_to_positive_root(x * r * x.inverse()) - for z, r in x.bruhat_upper_covers_reflections() - if z.bruhat_le(y)] + roots = [self.reflection_to_positive_root(x * r * x.inverse()) for z, r in x.bruhat_upper_covers_reflections() if z.bruhat_le(y)] elif side == 'lower': - roots = [self.reflection_to_positive_root(y * r * y.inverse()) - for z, r in y.bruhat_lower_covers_reflections() - if x.bruhat_le(z)] + roots = [self.reflection_to_positive_root(y * r * y.inverse()) for z, r in y.bruhat_lower_covers_reflections() if x.bruhat_le(z)] else: raise ValueError("side must be either 'upper' or 'lower'") from sage.geometry.polyhedron.constructor import Polyhedron + if self.is_crystallographic(): - return Polyhedron(vertices=[[0] * self.rank()], - rays=roots, - ambient_dim=self.rank(), - backend=backend) + return Polyhedron(vertices=[[0] * self.rank()], rays=roots, ambient_dim=self.rank(), backend=backend) if backend == 'cdd': from warnings import warn + warn("Using floating point numbers for roots of unity. This might cause numerical errors!") from sage.rings.real_double import RDF as base_ring else: from sage.rings.qqbar import AA as base_ring - return Polyhedron(vertices=[[0] * self.rank()], - rays=roots, - ambient_dim=self.rank(), - base_ring=base_ring, - backend=backend) + return Polyhedron(vertices=[[0] * self.rank()], rays=roots, ambient_dim=self.rank(), base_ring=base_ring, backend=backend) class Element(RealReflectionGroupElement, ComplexReflectionGroup.Element): @@ -815,10 +804,10 @@ def right_coset_representatives(self): """ W = self.parent() T = W.reflections() - T_fix = [i + 1 for i in T.keys() - if self.fix_space().is_subspace(T[i].fix_space())] + T_fix = [i + 1 for i in T.keys() if self.fix_space().is_subspace(T[i].fix_space())] S = str(gap3('ReducedRightCosetRepresentatives(%s,ReflectionSubgroup(%s,%s))' % (W._gap_group._name, W._gap_group._name, T_fix))) from sage.combinat.root_system.reflection_group_element import _gap_return + return [W(w, check=False) for w in _gap_return(S)] def left_coset_representatives(self): @@ -841,7 +830,7 @@ def left_coset_representatives(self): [2, 1] [[]] [1, 2, 1] [[], [2], [1, 2]] """ - return [ (~w) for w in self.right_coset_representatives() ] + return [(~w) for w in self.right_coset_representatives()] class IrreducibleRealReflectionGroup(RealReflectionGroup, IrreducibleComplexReflectionGroup): @@ -860,7 +849,7 @@ def _repr_(self): Irreducible real reflection group of rank 2 and type I2(7) """ type_str = self._irrcomp_repr_(self._type[0]) - return 'Irreducible real reflection group of rank %s and type %s' % (self._rank,type_str) + return 'Irreducible real reflection group of rank %s and type %s' % (self._rank, type_str) class Element(RealReflectionGroup.Element, IrreducibleComplexReflectionGroup.Element): pass diff --git a/src/sage/combinat/root_system/root_lattice_realization_algebras.py b/src/sage/combinat/root_system/root_lattice_realization_algebras.py index e07afc9e7f3..83c3bda44ff 100644 --- a/src/sage/combinat/root_system/root_lattice_realization_algebras.py +++ b/src/sage/combinat/root_system/root_lattice_realization_algebras.py @@ -1,6 +1,7 @@ r""" Group algebras of root lattice realizations """ + # **************************************************************************** # Copyright (C) 2013 Nicolas M. Thiery # Anne Schilling @@ -16,6 +17,7 @@ from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.categories.algebra_functor import AlgebrasCategory + lazy_import('sage.rings.integer_ring', 'ZZ') from sage.modules.free_module_element import vector from sage.combinat.root_system.hecke_algebra_representation import HeckeAlgebraRepresentation @@ -120,8 +122,7 @@ def from_polynomial(self, p): .. TODO:: make this work for Laurent polynomials too """ L = self.basis().keys() - return self.sum_of_terms((L.from_vector(vector(t)), c) - for t, c in p.monomial_coefficients().items()) + return self.sum_of_terms((L.from_vector(vector(t)), c) for t, c in p.monomial_coefficients().items()) @cached_method def divided_difference_on_basis(self, weight, i): @@ -206,8 +207,8 @@ def isobaric_divided_difference_on_basis(self, weight, i): raise ValueError("the weight does not have an integral scalar product with the coroot") alphai = P.simple_root(i) if n >= 0: - return self.sum_of_monomials(weight-j*alphai for j in range(n + 1)) - return -self.sum_of_monomials(weight-j*alphai for j in range(n + 1, 0)) + return self.sum_of_monomials(weight - j * alphai for j in range(n + 1)) + return -self.sum_of_monomials(weight - j * alphai for j in range(n + 1, 0)) def demazure_operators(self): r""" @@ -320,8 +321,7 @@ def _test_demazure_operators(self, **options): continue x = self.monomial(weight) result = pi[i](x) - tester.assertEqual(result * (self.one() - emalphai), - x - emalphai * x.map_support(s[i])) + tester.assertEqual(result * (self.one() - emalphai), x - emalphai * x.map_support(s[i])) except ImportError: pass @@ -383,7 +383,7 @@ def demazure_lusztig_operator_on_basis(self, weight, i, q1, q2, convention='anti pi_on_weight = self.isobaric_divided_difference_on_basis(weight, i) if convention == "bar": pi_on_weight = self.monomial(weight) - pi_on_weight - result = (q1+q2) * pi_on_weight - self.term(weight.simple_reflection(i), q2) + result = (q1 + q2) * pi_on_weight - self.term(weight.simple_reflection(i), q2) if convention == "dominant": return result.map_support(operator.neg) return result @@ -590,8 +590,7 @@ def demazure_lusztig_operators(self, q1, q2, convention='antidominant'): ....: T = KL.demazure_lusztig_operators(q1,q2) ....: T._test_relations(elements=elements) """ - T_on_basis = functools.partial(self.demazure_lusztig_operator_on_basis, - q1=q1, q2=q2, convention=convention) + T_on_basis = functools.partial(self.demazure_lusztig_operator_on_basis, q1=q1, q2=q2, convention=convention) return HeckeAlgebraRepresentation(self, T_on_basis, self.cartan_type(), q1, q2, side='left') def demazure_lusztig_operator_on_classical_on_basis(self, weight, i, q, q1, q2, convention='antidominant'): @@ -755,8 +754,7 @@ def demazure_lusztig_operators_on_classical(self, q, q1, q2, convention='antidom # Should this go in q_project instead? ct = self.cartan_type() a0check = ct.acheck()[ct.special_node()] - T_on_basis = functools.partial(self.demazure_lusztig_operator_on_classical_on_basis, - q1=q1, q2=q2, q=q**a0check, convention=convention) + T_on_basis = functools.partial(self.demazure_lusztig_operator_on_classical_on_basis, q1=q1, q2=q2, q=q**a0check, convention=convention) return HeckeAlgebraRepresentation(self.classical(), T_on_basis, self.cartan_type(), q1=q1, q2=q2, q=q, side='left') @cached_method @@ -849,22 +847,23 @@ def T0_check_on_basis(self, q1, q2, convention='antidominant'): # CHECKME: this is not exactly phi, but phi rescaled # appropriately so that it's in the orbit of the # simple classical roots - phi = -a0*L0(L.simple_roots()[0]) + phi = -a0 * L0(L.simple_roots()[0]) else: phi = L0(L0.root_system.coroot_lattice().highest_root().associated_coroot()) # Variant: try to fetch it from the other affinization; something like: # The a0 only has an influence in type BC; it handles the fact that alpha_0 # is not in the orbit of the classical roots - #phi1 = - L0(L'.other_affinization().simple_roots()[special_node]) * a0 - #assert phi == phi1 + # phi1 = - L0(L'.other_affinization().simple_roots()[special_node]) * a0 + # assert phi == phi1 j, v = phi.to_simple_root(reduced_word=True) - translation = A0.monomial(-L0.simple_root(j)/a0) + translation = A0.monomial(-L0.simple_root(j) / a0) Tv = T[v] - Tinv = T.Tw_inverse(v+(j,)) + Tinv = T.Tw_inverse(v + (j,)) def T0_check(weight): - return -q1*q2*Tinv( translation * Tv(A0.monomial(weight))) + return -q1 * q2 * Tinv(translation * Tv(A0.monomial(weight))) + # For debugging purposes T0_check.phi = phi T0_check.j = j @@ -911,7 +910,7 @@ def q_project_on_basis(self, l, q): """ KL0 = self.classical() L0 = KL0.basis().keys() - return KL0.term(L0(l), q**l["delta"]) + return KL0.term(L0(l), q ** l["delta"]) def q_project(self, x, q): r""" @@ -965,7 +964,7 @@ def q_project(self, x, q): q^2*B[(0, 0, 0)] """ L0 = self.classical() - return L0.linear_combination( (self.q_project_on_basis(l, q), c) for l,c in x ) + return L0.linear_combination((self.q_project_on_basis(l, q), c) for l, c in x) def twisted_demazure_lusztig_operator_on_basis(self, weight, i, q1, q2, convention='antidominant'): r""" @@ -1006,7 +1005,7 @@ def twisted_demazure_lusztig_operator_on_basis(self, weight, i, q1, q2, conventi + ((q1^2+2*q1*q2+q2^2)/q1)*B[(2, 2, 1, 0)] + ((q1*q2+q2^2)/q1)*B[(2, 2, 0, 1)] """ - if i == 0: # should use the special node + if i == 0: # should use the special node if convention != "dominant": raise NotImplementedError("The twisted Demazure-Lusztig operator T_0 is only implemented in the dominant convention") return self.T0_check_on_basis(q1, q2, convention=convention)(weight) @@ -1142,13 +1141,8 @@ def twisted_demazure_lusztig_operators(self, q1, q2, convention='antidominant'): sage: T0c(0,0,1) # needs sage.graphs (t^2-t)*B[(1, 0, 0)] + (t^2-t)*B[(1, 1, -1)] + t^2*B[(2, 0, -1)] + (t-1)*B[(0, 0, 1)] """ - T_on_basis = functools.partial(self.twisted_demazure_lusztig_operator_on_basis, - q1=q1, q2=q2, convention=convention) - return HeckeAlgebraRepresentation(self.classical(), - T_on_basis, - self.cartan_type().classical().dual().affine().dual(), - q1, q2, - side='left') + T_on_basis = functools.partial(self.twisted_demazure_lusztig_operator_on_basis, q1=q1, q2=q2, convention=convention) + return HeckeAlgebraRepresentation(self.classical(), T_on_basis, self.cartan_type().classical().dual().affine().dual(), q1, q2, side='left') class ElementMethods: @@ -1206,6 +1200,4 @@ def expand(self, alphabet): """ codomain = alphabet[0].parent() - return codomain.sum(c * prod(X**int(n) - for X, n in zip(alphabet, vector(m))) - for m, c in self) + return codomain.sum(c * prod(X ** int(n) for X, n in zip(alphabet, vector(m))) for m, c in self) diff --git a/src/sage/combinat/root_system/root_lattice_realizations.py b/src/sage/combinat/root_system/root_lattice_realizations.py index aeab7d8766a..9ad8999cb49 100644 --- a/src/sage/combinat/root_system/root_lattice_realizations.py +++ b/src/sage/combinat/root_system/root_lattice_realizations.py @@ -1,6 +1,7 @@ """ Root lattice realizations """ + # **************************************************************************** # Copyright (C) 2007-2013 Nicolas M. Thiery # 2012 Nicolas Borie @@ -186,6 +187,7 @@ def __init_extra__(self): :meth:`_test_root_lattice_realization`. """ from .root_space import RootSpace + K = self.base_ring() # If self is the root lattice or the root space, we don't want # to register its trivial embedding into itself. This builds @@ -197,9 +199,7 @@ def __init_extra__(self): domains.append(self.root_system.root_space(K)) # Build and register the embeddings for domain in domains: - domain.module_morphism(self.simple_root, - codomain=self - ).register_as_coercion() + domain.module_morphism(self.simple_root, codomain=self).register_as_coercion() if self.cartan_type().is_affine(): self._to_classical.register_as_conversion() @@ -329,7 +329,7 @@ def _test_root_lattice_realization(self, **options): except ImportError: return R = self.base_ring() - tester.assertEqual(alpha .keys(), self.index_set()) + tester.assertEqual(alpha.keys(), self.index_set()) tester.assertEqual(alphacheck.keys(), self.index_set()) # Check the consistency between simple_root and simple_roots @@ -344,7 +344,7 @@ def _test_root_lattice_realization(self, **options): for i in self.index_set(): # This embedding maps simple roots to simple roots tester.assertEqual(self(root_lattice.simple_root(i)), alpha[i]) - tester.assertEqual(self(root_space .simple_root(i)), alpha[i]) + tester.assertEqual(self(root_space.simple_root(i)), alpha[i]) # Check that the scalar products match with the Dynkin diagram try: @@ -353,7 +353,7 @@ def _test_root_lattice_realization(self, **options): return for i in self.index_set(): for j in self.index_set(): - tester.assertEqual(alpha[j].scalar(alphacheck[i]), R(dynkin_diagram[i,j])) + tester.assertEqual(alpha[j].scalar(alphacheck[i]), R(dynkin_diagram[i, j])) # Check associated_coroot, if it is implemented if not isinstance(self.element_class.associated_coroot, AbstractMethod): @@ -473,7 +473,7 @@ def simple_roots(self): sage: [alpha[i] for i in [1,2,3]] [alpha[1], alpha[2], alpha[3]] """ - if not hasattr(self,"_simple_roots"): + if not hasattr(self, "_simple_roots"): self._simple_roots = Family(self.index_set(), self.simple_root) # Should we use rename to set a nice name for this family? # self._simple_roots.rename('alpha') @@ -496,9 +496,7 @@ def alpha(self): -alpha[1] - alpha[2] """ if self.root_system.is_finite() and self.root_system.is_irreducible(): - return Family(self.index_set(), self.simple_root, - hidden_keys=[0], - hidden_function=lambda i: - self.highest_root()) + return Family(self.index_set(), self.simple_root, hidden_keys=[0], hidden_function=lambda i: -self.highest_root()) return self.simple_roots() @cached_method @@ -574,8 +572,8 @@ def simple_roots_tilde(self): other_affinization = self.cartan_type().other_affinization() b = other_affinization.col_annihilator() alpha = self.simple_roots() - result = { i: alpha[i] for i in I0 } - result[i0] = (self.null_root() - self.linear_combination( (alpha[i], b[i]) for i in I0)) / b[i0] + result = {i: alpha[i] for i in I0} + result[i0] = (self.null_root() - self.linear_combination((alpha[i], b[i]) for i in I0)) / b[i0] return Family(result) ########################################################################## @@ -617,10 +615,9 @@ def roots(self): infinite root systems. """ if not self.cartan_type().is_finite(): - from sage.sets.disjoint_union_enumerated_sets \ - import DisjointUnionEnumeratedSets - D = DisjointUnionEnumeratedSets([self.positive_roots(), - self.negative_roots()]) + from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets + + D = DisjointUnionEnumeratedSets([self.positive_roots(), self.negative_roots()]) D.rename("All roots of type {}".format(self.cartan_type())) return D @@ -704,19 +701,14 @@ def positive_roots(self, index_set=None): alpha[1] + alpha[2] + alpha[3]] """ if self.cartan_type().is_affine(): - from sage.sets.disjoint_union_enumerated_sets \ - import DisjointUnionEnumeratedSets - return DisjointUnionEnumeratedSets([self.positive_real_roots(), - self.positive_imaginary_roots()]) + from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets + + return DisjointUnionEnumeratedSets([self.positive_real_roots(), self.positive_imaginary_roots()]) if not self.cartan_type().is_finite(): - raise NotImplementedError("Only implemented for finite and" - " affine Cartan types") + raise NotImplementedError("Only implemented for finite and" " affine Cartan types") if index_set is None: index_set = tuple(self.cartan_type().index_set()) - return RecursivelyEnumeratedSet([self.simple_root(i) for i in index_set], - attrcall('pred', index_set=index_set), - structure='graded', enumeration='breadth', - category=EnumeratedSets().Finite()) + return RecursivelyEnumeratedSet([self.simple_root(i) for i in index_set], attrcall('pred', index_set=index_set), structure='graded', enumeration='breadth', category=EnumeratedSets().Finite()) @cached_method def nonparabolic_positive_roots(self, index_set=None): @@ -741,12 +733,10 @@ def nonparabolic_positive_roots(self, index_set=None): alpha[2], alpha[2] + alpha[3], alpha[3]] """ if not self.cartan_type().is_finite(): - raise NotImplementedError("Only implemented for " - "finite Cartan type") + raise NotImplementedError("Only implemented for " "finite Cartan type") if index_set is None: return [] - return [x for x in self.positive_roots() - if x not in self.positive_roots(index_set)] + return [x for x in self.positive_roots() if x not in self.positive_roots(index_set)] @cached_method def nonparabolic_positive_root_sum(self, index_set=None): @@ -812,9 +802,7 @@ def positive_real_roots(self): 2*alpha[0] + 2*alpha[1] + 2*alpha[2]] """ if self.cartan_type().is_finite(): - return tuple(RecursivelyEnumeratedSet(self.simple_roots(), - attrcall('pred'), structure='graded', - enumeration='breadth')) + return tuple(RecursivelyEnumeratedSet(self.simple_roots(), attrcall('pred'), structure='graded', enumeration='breadth')) if not self.cartan_type().is_affine(): raise NotImplementedError("only implemented for finite and affine Cartan types") @@ -832,31 +820,32 @@ def lift(x): """ Lift up the classical element into ``self``. """ - return self.sum(c*alpha[i] for i,c in x) + return self.sum(c * alpha[i] for i, c in x) + P = Family(Q.positive_real_roots(), lift) # Add all of the delta shifts delta = self.null_root() if self.cartan_type().is_untwisted_affine(): C = cartesian_product([PositiveIntegers(), Q.roots()]) - F = Family(C, lambda x: lift(x[1]) + x[0]*delta) + F = Family(C, lambda x: lift(x[1]) + x[0] * delta) D = DisjointUnionEnumeratedSets([P, F]) elif self.cartan_type().type() == 'BC' or self.cartan_type().dual().type() == 'BC': Cs = cartesian_product([PositiveIntegers(), Q.short_roots()]) Cl = cartesian_product([PositiveIntegers(), Q.long_roots()]) - Fs = Family(Cl, lambda x: (lift(x[1]) + (2*x[0]-1)*delta) / 2) - Fm = Family(Cs, lambda x: lift(x[1]) + x[0]*delta) - Fl = Family(Cl, lambda x: lift(x[1]) + 2*x[0]*delta) + Fs = Family(Cl, lambda x: (lift(x[1]) + (2 * x[0] - 1) * delta) / 2) + Fm = Family(Cs, lambda x: lift(x[1]) + x[0] * delta) + Fl = Family(Cl, lambda x: lift(x[1]) + 2 * x[0] * delta) D = DisjointUnionEnumeratedSets([P, Fs, Fm, Fl]) - else: # Other twisted types + else: # Other twisted types Cs = cartesian_product([PositiveIntegers(), Q.short_roots()]) Cl = cartesian_product([PositiveIntegers(), Q.long_roots()]) - Fs = Family(Cs, lambda x: lift(x[1]) + x[0]*delta) - if self.cartan_type().dual() == 'G': # D_4^3 + Fs = Family(Cs, lambda x: lift(x[1]) + x[0] * delta) + if self.cartan_type().dual() == 'G': # D_4^3 k = 3 else: k = 2 - Fl = Family(Cl, lambda x: lift(x[1]) + x[0]*k*delta) + Fl = Family(Cl, lambda x: lift(x[1]) + x[0] * k * delta) D = DisjointUnionEnumeratedSets([P, Fs, Fl]) # Return the final union @@ -888,8 +877,9 @@ def positive_imaginary_roots(self): if not self.cartan_type().is_affine(): raise NotImplementedError("only implemented for finite and affine Cartan types") from sage.sets.positive_integers import PositiveIntegers + delta = self.null_root() - F = Family(PositiveIntegers(), lambda x: x*delta) + F = Family(PositiveIntegers(), lambda x: x * delta) F.rename("Positive imaginary roots of type {}".format(self.cartan_type())) return F @@ -964,8 +954,7 @@ def parabolic_covers(alpha): return [x for x in alpha.pred() if x.is_parabolic_root(index_set)] generators = [x for x in self.simple_roots() if x.is_parabolic_root(index_set)] - return RecursivelyEnumeratedSet(generators, parabolic_covers, - structure='graded', enumeration='breadth') + return RecursivelyEnumeratedSet(generators, parabolic_covers, structure='graded', enumeration='breadth') @cached_method def positive_roots_nonparabolic(self, index_set=None): @@ -1085,6 +1074,7 @@ def root_poset(self, restricted=False, facade=False): Finite poset containing 3 elements """ from sage.combinat.posets.posets import Poset + rels = [] pos_roots = set(self.positive_roots()) simple_roots = self.simple_roots() @@ -1173,10 +1163,9 @@ def is_saturated_chain(chain): for alpha in chain[i - 1]: for beta in chain[j - 1]: gamma = alpha + beta - if gamma in Phi_plus and gamma not in chain[i+j-1]: + if gamma in Phi_plus and gamma not in chain[i + j - 1]: return False - cochain = [[beta for beta in Phi_plus if beta not in ideal] - for ideal in chain] + cochain = [[beta for beta in Phi_plus if beta not in ideal] for ideal in chain] for i in range(1, m + 1): for j in range(1, m + 1): for alpha in cochain[i - 1]: @@ -1187,13 +1176,12 @@ def is_saturated_chain(chain): return True def is_componentwise_subset(chain1, chain2): - return all(chain1[i].issubset(chain2[i]) - for i in range(len(chain1))) + return all(chain1[i].issubset(chain2[i]) for i in range(len(chain1))) + from sage.combinat.posets.lattices import LatticePoset - saturated_chains = [multichain for multichain in multichains - if is_saturated_chain(multichain)] - return LatticePoset((saturated_chains, is_componentwise_subset), - facade=facade) + + saturated_chains = [multichain for multichain in multichains if is_saturated_chain(multichain)] + return LatticePoset((saturated_chains, is_componentwise_subset), facade=facade) def almost_positive_roots(self): r""" @@ -1211,7 +1199,7 @@ def almost_positive_roots(self): """ if not self.cartan_type().is_finite(): raise ValueError("%s is not a finite Cartan type" % (self.cartan_type())) - return sorted([ -beta for beta in self.simple_roots() ] + list(self.positive_roots())) + return sorted([-beta for beta in self.simple_roots()] + list(self.positive_roots())) def negative_roots(self): r""" @@ -1285,7 +1273,7 @@ def simple_coroots(self): sage: [alphacheck[i] for i in [1, 2, 3]] [alphacheck[1], alphacheck[2], alphacheck[3]] """ - if not hasattr(self,"cache_simple_coroots"): + if not hasattr(self, "cache_simple_coroots"): self.cache_simple_coroots = Family(self.index_set(), self.simple_coroot) # Should we use rename to set a nice name for this family? # self.cache_simple_coroots.rename('alphacheck') @@ -1322,8 +1310,7 @@ def alphacheck(self): Finite family {1: (1, -1, 0, 0), 2: (0, 1, -1, 0), 3: (0, 0, 1, -1)} """ if self.root_system.is_finite() and self.root_system.is_irreducible(): - return Family(self.index_set(), self.simple_coroot, - hidden_keys=[0], hidden_function=lambda i: - self.cohighest_root()) + return Family(self.index_set(), self.simple_coroot, hidden_keys=[0], hidden_function=lambda i: -self.cohighest_root()) return self.simple_coroots() @cached_method @@ -1364,7 +1351,7 @@ def null_root(self): """ if self.cartan_type().is_affine(): coef = self.cartan_type().a() - return sum(coef[k]*self.simple_roots()[k] for k in coef.keys()) + return sum(coef[k] * self.simple_roots()[k] for k in coef.keys()) ########################################################################## # null_coroot (Also called CanonicalCentralElement) @@ -1393,7 +1380,7 @@ def null_coroot(self): if not self.cartan_type().is_affine(): raise ValueError("%s is not an affine Cartan type" % (self.cartan_type())) coef = self.cartan_type().acheck() - return sum(coef[k]*self.simple_coroots()[k] for k in coef.keys()) + return sum(coef[k] * self.simple_coroots()[k] for k in coef.keys()) ########################################################################## # fundamental weights @@ -1470,14 +1457,13 @@ def fundamental_weights_from_simple_roots(self): d = M.det() if not d: raise TypeError("The Cartan matrix is not invertible") - M = d*~M - fundamental_weights = [self.linear_combination(zip(self.simple_roots(), column)) - for column in M.columns()] + M = d * ~M + fundamental_weights = [self.linear_combination(zip(self.simple_roots(), column)) for column in M.columns()] try: - fundamental_weights = [x/d for x in fundamental_weights] + fundamental_weights = [x / d for x in fundamental_weights] except ValueError: raise ValueError("The fundamental weights do not live in this realization of the root lattice") - return Family(dict(zip(self.index_set(),fundamental_weights))) + return Family(dict(zip(self.index_set(), fundamental_weights))) ########################################################################## # reflections @@ -1661,6 +1647,7 @@ def weyl_group(self, prefix=None): Weyl Group of type ['F', 4] (as a matrix group acting on the root space) """ from sage.combinat.root_system.weyl_group import WeylGroup + return WeylGroup(self, prefix=prefix) ########################################################################## @@ -1751,6 +1738,7 @@ def tau_epsilon(alpha): if alpha in other_negative_simple_roots: return alpha return t.action(alpha) + return tau_epsilon def tau_plus_minus(self): @@ -1789,7 +1777,7 @@ def tau_plus_minus(self): alpha[2] , alpha[1] + alpha[2] , -alpha[2] """ ct = self.cartan_type() - L,R = ct.index_set_bipartition() + L, R = ct.index_set_bipartition() return self.tau_epsilon_operator_on_almost_positive_roots(L), self.tau_epsilon_operator_on_almost_positive_roots(R) def almost_positive_roots_decomposition(self): @@ -1883,6 +1871,7 @@ def classical(self): """ from .root_space import RootSpace from .weight_space import WeightSpace + R = self.cartan_type().classical().root_system() if isinstance(self, RootSpace): return R.root_space(self.base_ring()) @@ -1943,23 +1932,12 @@ def _classical_alpha_0(self): special_node = cartan_type.special_node() a = self.cartan_type().col_annihilator() classical = self.classical() - return -classical.sum(a[i] * self.simple_root(i) - for i in self.index_set() if i != special_node) \ - / a[special_node] + return -classical.sum(a[i] * self.simple_root(i) for i in self.index_set() if i != special_node) / a[special_node] ###################################################################### # Root system plots - def plot(self, - roots='simple', - coroots=False, - reflection_hyperplanes='simple', - fundamental_weights=None, - fundamental_chamber=None, - alcoves=None, - alcove_labels=False, - alcove_walk=None, - **options): + def plot(self, roots='simple', coroots=False, reflection_hyperplanes='simple', fundamental_weights=None, fundamental_chamber=None, alcoves=None, alcove_labels=False, alcove_walk=None, **options): r""" Return a picture of this root lattice realization. @@ -2210,14 +2188,15 @@ def _plot_projection_barycentric_matrix(self): (0, 0, 0) """ from sage.symbolic.constants import pi - m = matrix(QQ, barycentric_projection_matrix(self.dimension()-1, angle=2*pi/3).n(20)) + + m = matrix(QQ, barycentric_projection_matrix(self.dimension() - 1, angle=2 * pi / 3).n(20)) # We want to guarantee that the sum of the columns of the # result is zero. This is close to be the case for the # original matrix and for the current rational # approximation. We tidy up the work by replacing the # first column by the opposite of the sum of the others. - if self.dimension() > 1: # not needed in the trivial cases - m.set_column(0, -sum(m[:,1:].columns())) + if self.dimension() > 1: # not needed in the trivial cases + m.set_column(0, -sum(m[:, 1:].columns())) m.set_immutable() return m @@ -2246,7 +2225,7 @@ def _plot_projection_barycentric(self, x): - :ref:`sage.combinat.root_system.plot` for a tutorial on root system plotting """ - return self._plot_projection_barycentric_matrix()*vector(x) + return self._plot_projection_barycentric_matrix() * vector(x) def plot_roots(self, collection='simple', **options): r""" @@ -2432,8 +2411,7 @@ def plot_fundamental_weights(self, **options): # the ambient space can define the fundamental weights # slightly differently (the usual GL_n vs SL_n catch). weight_lattice = self.root_system.weight_lattice() - fundamental_weights = Family(dict(zip(weight_lattice.fundamental_weights(), - self.fundamental_weights()))) + fundamental_weights = Family(dict(zip(weight_lattice.fundamental_weights(), self.fundamental_weights()))) return plot_options.family_of_vectors(fundamental_weights) def plot_reflection_hyperplanes(self, collection='simple', **options): @@ -2578,11 +2556,11 @@ def plot_hedron(self, **options): Point set defined by 8 point(s): [(-1.5, -0.5), (-1.5, 0.5), (-0.5, -1.5), (-0.5, 1.5), (0.5, -1.5), (0.5, 1.5), (1.5, -0.5), (1.5, 0.5)] """ from sage.geometry.polyhedron.constructor import Polyhedron + plot_options = self.plot_parse_options(**options) if not self.cartan_type().is_finite(): raise ValueError("the Cartan type must be finite") - vertices = [plot_options.projection(vertex) - for vertex in self.rho().orbit()] + vertices = [plot_options.projection(vertex) for vertex in self.rho().orbit()] return Polyhedron(vertices=vertices).plot() def plot_fundamental_chamber(self, style='normal', **options): @@ -2648,10 +2626,7 @@ def plot_fundamental_chamber(self, style='normal', **options): else: I = cartan_type.index_set() lines = [] - return plot_options.cone(rays=[Lambda[i] for i in I], - lines=lines, - color='lightgrey', - alpha=.3) + return plot_options.cone(rays=[Lambda[i] for i in I], lines=lines, color='lightgrey', alpha=0.3) def plot_alcoves(self, alcoves=True, alcove_labels=False, wireframe=False, **options): r""" @@ -2735,22 +2710,17 @@ def plot_alcoves(self, alcoves=True, alcove_labels=False, wireframe=False, **opt fundamental_alcove_rays = Lambda.map(plot_options.intersection_at_level_1) def alcove_in_bounding_box(w): - return any(plot_options.in_bounding_box(w.action(fundamental_alcove_rays[i])) - for i in I) + return any(plot_options.in_bounding_box(w.action(fundamental_alcove_rays[i])) for i in I) def alcove_facet(w, i): # Alcove facets with degenerate intersection with the # bounding box bring no information; we might as well # not draw them. Besides this avoids ugly fat points # in dimension 2. - return plot_options.cone(rays=[w.action(fundamental_alcove_rays[j]) for j in I if j != i], - color=plot_options.color(i), - thickness=plot_options.thickness(i), - wireframe=wireframe, - draw_degenerate=False) + return plot_options.cone(rays=[w.action(fundamental_alcove_rays[j]) for j in I if j != i], color=plot_options.color(i), thickness=plot_options.thickness(i), wireframe=wireframe, draw_degenerate=False) def alcove_label(w): - label = "$1$" if w.is_one() else "$s_{"+"".join(str(j) for j in w.reduced_word())+"}$" + label = "$1$" if w.is_one() else "$s_{" + "".join(str(j) for j in w.reduced_word()) + "}$" position = plot_options.projection(w.action(rho)) if position in plot_options.bounding_box: return plot_options.text(label, position) @@ -2776,14 +2746,13 @@ def alcove_label(w): raise TypeError("alcoves=list only available in affine type") translation_factors = cartan_type.translation_factors() simple_roots = self.simple_roots() - translation_vectors = Family({i: translation_factors[i]*simple_roots[i] - for i in cartan_type.classical().index_set()}) + translation_vectors = Family({i: translation_factors[i] * simple_roots[i] for i in cartan_type.classical().index_set()}) # The elements of the classical Weyl group, as elements of W W0 = [W.from_reduced_word(w.reduced_word()) for w in self.weyl_group().classical()] for alcove in alcoves: # The translation mapping the center of the # fundamental polygon to polygon indexed by alcove - shift = sum(x*v for x,v in zip(alcove, translation_vectors)) + shift = sum(x * v for x, v in zip(alcove, translation_vectors)) shift = W.from_morphism(shift.translation) for w in W0: for i in w.descents(side='right', positive=True): @@ -2948,6 +2917,7 @@ def plot_alcove_walk(self, word, start=None, foldings=None, color='orange', **op """ from sage.plot.line import line from sage.plot.arrow import arrow + plot_options = self.plot_parse_options(**options) W = self.weyl_group() s = W.simple_reflections() @@ -2958,7 +2928,7 @@ def plot_alcove_walk(self, word, start=None, foldings=None, color='orange', **op w = W.one() source = plot_options.projection(start) G = plot_options.empty() - for (i, folding) in zip(word, foldings): + for i, folding in zip(word, foldings): w = w * s[i] target = plot_options.projection(w.action(start)) if folding: @@ -2994,7 +2964,7 @@ def _maximum_root_length(self): raise NotImplementedError("Implemented only for irreducible finite root systems") if not ct.is_finite(): raise NotImplementedError("Implemented only for irreducible finite root systems") - L = self.root_system.ambient_space() # uses peculiarities of ambient embedding + L = self.root_system.ambient_space() # uses peculiarities of ambient embedding return max([root.scalar(root) for root in L.simple_roots()]) def plot_ls_paths(self, paths, plot_labels=None, colored_labels=True, **options): @@ -3034,6 +3004,7 @@ def plot_ls_paths(self, paths, plot_labels=None, colored_labels=True, **options) if not isinstance(paths, (list, tuple, set)): from sage.combinat.crystals.littelmann_path import CrystalOfLSPaths from sage.categories.finite_crystals import FiniteCrystals + if not isinstance(paths, CrystalOfLSPaths): raise ValueError("the input must be LS paths") if paths not in FiniteCrystals(): @@ -3041,10 +3012,11 @@ def plot_ls_paths(self, paths, plot_labels=None, colored_labels=True, **options) from sage.plot.line import line from sage.plot.colors import rainbow + plot_options = self.plot_parse_options(**options) color = rainbow(len(paths), 'rgbtuple') G = plot_options.empty() - for i,b in enumerate(paths): + for i, b in enumerate(paths): prev = plot_options.projection(self.zero()) for x in b.value: next = prev + plot_options.projection(self(x)) @@ -3052,15 +3024,12 @@ def plot_ls_paths(self, paths, plot_labels=None, colored_labels=True, **options) prev = next if plot_labels is not None: if colored_labels: - G += plot_options.text(b, prev + prev.normalized()*plot_labels, rgbcolor=color[i]) + G += plot_options.text(b, prev + prev.normalized() * plot_labels, rgbcolor=color[i]) else: - G += plot_options.text(b, prev + prev.normalized()*plot_labels) + G += plot_options.text(b, prev + prev.normalized() * plot_labels) return G - def plot_mv_polytope(self, mv_polytope, mark_endpoints=True, - circle_size=0.06, circle_thickness=1.6, - wireframe='blue', fill='green', alpha=1, - **options): + def plot_mv_polytope(self, mv_polytope, mark_endpoints=True, circle_size=0.06, circle_thickness=1.6, wireframe='blue', fill='green', alpha=1, **options): r""" Plot an MV polytope. @@ -3101,39 +3070,29 @@ def plot_mv_polytope(self, mv_polytope, mark_endpoints=True, Graphics3d Object """ from sage.geometry.polyhedron.constructor import Polyhedron + plot_options = self.plot_parse_options(**options) # Setup the shift for plotting pbw_data = mv_polytope._pbw_datum.parent al = self.simple_roots() red = tuple(mv_polytope._pbw_datum.long_word) - roots = [self.sum(c*al[a] for a,c in root) - for root in pbw_data._root_list_from(red)] + roots = [self.sum(c * al[a] for a, c in root) for root in pbw_data._root_list_from(red)] datum = mv_polytope._pbw_datum.lusztig_datum - end_pt = self.sum(roots[i] * c for i,c in enumerate(datum)) + end_pt = self.sum(roots[i] * c for i, c in enumerate(datum)) shift = plot_options.projection(end_pt) - vertices = [plot_options.projection(vertex) - shift - for vertex in mv_polytope._polytope_vertices(self)] - p = Polyhedron(vertices=vertices).plot(wireframe=wireframe, - fill=fill, alpha=alpha) + vertices = [plot_options.projection(vertex) - shift for vertex in mv_polytope._polytope_vertices(self)] + p = Polyhedron(vertices=vertices).plot(wireframe=wireframe, fill=fill, alpha=alpha) if mark_endpoints: from sage.plot.circle import circle - p += circle(plot_options.projection(self.zero()), - circle_size, fill=True, - thickness=circle_thickness, color=wireframe) + p += circle(plot_options.projection(self.zero()), circle_size, fill=True, thickness=circle_thickness, color=wireframe) - p += circle(-shift, - circle_size, fill=True, - thickness=circle_thickness, color=wireframe) + p += circle(-shift, circle_size, fill=True, thickness=circle_thickness, color=wireframe) return p - def plot_crystal(self, crystal, - plot_labels=True, label_color='black', - edge_labels=False, - circle_size=0.06, circle_thickness=1.6, - **options): + def plot_crystal(self, crystal, plot_labels=True, label_color='black', edge_labels=False, circle_size=0.06, circle_thickness=1.6, **options): r""" Plot a finite crystal. @@ -3210,41 +3169,36 @@ def plot_crystal(self, crystal, G = plot_options.empty() if plot_labels == 'circles': - for wt,m in mults.items(): + for wt, m in mults.items(): m = len(m) if m > 4: G += plot_options.text(m, positions[wt], rgbcolor=label_color) continue if m >= 1: - G += circle(positions[wt], circle_size, fill=True, - thickness=circle_thickness, - rgbcolor=label_color) - for i in range(2,m+1): - G += circle(positions[wt], i*circle_size, - thickness=circle_thickness, - rgbcolor=label_color) + G += circle(positions[wt], circle_size, fill=True, thickness=circle_thickness, rgbcolor=label_color) + for i in range(2, m + 1): + G += circle(positions[wt], i * circle_size, thickness=circle_thickness, rgbcolor=label_color) elif plot_labels == 'multiplicities': - for wt,m in mults.items(): + for wt, m in mults.items(): G += plot_options.text(len(m), positions[wt], rgbcolor=label_color) elif plot_labels: - for wt,m in mults.items(): + for wt, m in mults.items(): for elt in m: # TODO: Destack the multiple weights G += plot_options.text(elt, positions[wt], rgbcolor=label_color) - for h,t,i in g.edges(sort=True): - G += arrow(positions[self(h.weight())], positions[self(t.weight())], - zorder=1, rgbcolor=plot_options.color(i), - arrowsize=plot_options._arrowsize) + for h, t, i in g.edges(sort=True): + G += arrow(positions[self(h.weight())], positions[self(t.weight())], zorder=1, rgbcolor=plot_options.color(i), arrowsize=plot_options._arrowsize) if edge_labels: mid = (positions[self(h.weight())] + positions[self(t.weight())]) / QQ(2) if plot_options.dimension >= 2: diff = (positions[self(h.weight())] - positions[self(t.weight())]).normalized() if plot_options.dimension >= 3: from copy import copy + diff2 = copy(diff) diff[0], diff[1] = -diff[1], diff[0] if abs(diff.dot_product(diff2)) > 0.9: @@ -3395,8 +3349,7 @@ def symmetric_form(self, alpha): cm = self.parent().dynkin_diagram().cartan_matrix() sym = cm.symmetrized_matrix() iset = self.parent().index_set() - return sum(cl*sym[iset.index(ml),iset.index(mr)]*cr - for ml,cl in self for mr,cr in alpha) + return sum(cl * sym[iset.index(ml), iset.index(mr)] * cr for ml, cl in self for mr, cr in alpha) def norm_squared(self): """ @@ -3480,8 +3433,7 @@ def _orbit_iter(self): [(1, 2, 0), (1, 0, 2), (2, 1, 0), (2, 0, 1), (0, 1, 2), (0, 2, 1)] """ - R = RecursivelyEnumeratedSet([self], attrcall('simple_reflections'), - structure=None, enumeration='breadth') + R = RecursivelyEnumeratedSet([self], attrcall('simple_reflections'), structure=None, enumeration='breadth') return iter(R) def orbit(self): @@ -3541,8 +3493,8 @@ def _dot_orbit_iter(self): def apply_action(la): return [la.dot_action([i]) for i in I] - R = RecursivelyEnumeratedSet([self], apply_action, structure=None, - enumeration='breadth') + + R = RecursivelyEnumeratedSet([self], apply_action, structure=None, enumeration='breadth') return iter(R) def dot_orbit(self): @@ -3707,7 +3659,7 @@ def descents(self, index_set=None, positive=False): """ if index_set is None: index_set = self.parent().index_set() - return [ i for i in index_set if self.has_descent(i, positive) ] + return [i for i in index_set if self.has_descent(i, positive)] def to_dominant_chamber(self, index_set=None, positive=True, reduced_word=False): r""" @@ -3821,7 +3773,7 @@ def reduced_word(self, index_set=None, positive=True): sage: alpha[1].reduced_word([1,2]) # needs sage.graphs [2] """ - return self.to_dominant_chamber(index_set=index_set,positive=positive,reduced_word=True)[1] + return self.to_dominant_chamber(index_set=index_set, positive=positive, reduced_word=True)[1] def is_dominant(self, index_set=None, positive=True): r""" @@ -3854,7 +3806,7 @@ def is_dominant(self, index_set=None, positive=True): """ return self.first_descent(index_set, not positive) is None - def is_dominant_weight(self): # Or is_dominant_integral_weight? + def is_dominant_weight(self): # Or is_dominant_integral_weight? """ Test whether ``self`` is a dominant element of the weight lattice. @@ -3883,8 +3835,8 @@ def is_dominant_weight(self): # Or is_dominant_integral_weight? """ alphacheck = self.parent().simple_coroots() from sage.rings.semirings.non_negative_integer_semiring import NN - return all(self.inner_product(alphacheck[i]) in NN - for i in self.parent().index_set()) + + return all(self.inner_product(alphacheck[i]) in NN for i in self.parent().index_set()) def is_verma_dominant(self, positive=True): r""" @@ -3971,7 +3923,7 @@ def succ(self, index_set=None): sage: L.rho().succ(index_set=[2]) [2*Lambda[1] - Lambda[2] + 2*Lambda[3]] """ - return [ self.simple_reflection(i) for i in self.descents(index_set=index_set, positive=True) ] + return [self.simple_reflection(i) for i in self.descents(index_set=index_set, positive=True)] def pred(self, index_set=None): r""" @@ -4000,7 +3952,7 @@ def pred(self, index_set=None): sage: (-L.rho()).pred(index_set=[1]) # needs sage.graphs [Lambda[1] - 2*Lambda[2] - Lambda[3]] """ - return [ self.simple_reflection(i) for i in self.descents(index_set) ] + return [self.simple_reflection(i) for i in self.descents(index_set)] def greater(self): r""" @@ -4067,9 +4019,9 @@ def extraspecial_pair(self): r = -self p_roots = self.parent().positive_roots_by_height() # We won't need any roots higher than us - p_roots = p_roots[:p_roots.index(r)] + p_roots = p_roots[: p_roots.index(r)] for i, a in enumerate(p_roots): - for b in p_roots[i + 1:]: + for b in p_roots[i + 1 :]: if a + b == r: return (a, b) raise ValueError("Unable to find an extraspecial pair") @@ -4462,25 +4414,24 @@ def is_short_root(self): if not ct.is_irreducible(): raise ValueError("Cartan type needs to be irreducible!") if not ct.is_finite(): - return self.norm_squared() == min(alpha.norm_squared() - for alpha in self.parent().simple_roots()) - L = self.parent().root_system.ambient_space() # uses peculiarities of ambient embedding + return self.norm_squared() == min(alpha.norm_squared() for alpha in self.parent().simple_roots()) + L = self.parent().root_system.ambient_space() # uses peculiarities of ambient embedding ls = L(self) return ls.scalar(ls) < L._maximum_root_length() - #Alternative implementation - #if ct.is_simply_laced(): + # Alternative implementation + # if ct.is_simply_laced(): # return False - #L = self.parent().root_system.ambient_space() # uses peculiarities of ambient embedding - #ls = L(self) - #lensq = ls.scalar(ls) - #if lensq > 2: + # L = self.parent().root_system.ambient_space() # uses peculiarities of ambient embedding + # ls = L(self) + # lensq = ls.scalar(ls) + # if lensq > 2: # return False - #if lensq == 1: + # if lensq == 1: # return True ## now only types BCFG remain and the square length is 2 - #if ct.type() == 'C' or ct.type() == 'G': + # if ct.type() == 'C' or ct.type() == 'G': # return True - #return False + # return False def to_dual_type_cospace(self): r""" @@ -4565,8 +4516,7 @@ def is_long_root(self): """ alpha = self.parent().simple_roots() norm_sq = self.norm_squared() - return max(sroot.norm_squared() for sroot in alpha) == norm_sq \ - and all(c * alpha[i].norm_squared() / norm_sq in ZZ for i,c in self) + return max(sroot.norm_squared() for sroot in alpha) == norm_sq and all(c * alpha[i].norm_squared() / norm_sq in ZZ for i, c in self) def is_imaginary_root(self): r""" diff --git a/src/sage/combinat/root_system/root_space.py b/src/sage/combinat/root_system/root_space.py index b8242c6c19b..77796a519c5 100644 --- a/src/sage/combinat/root_system/root_space.py +++ b/src/sage/combinat/root_system/root_space.py @@ -1,6 +1,7 @@ """ Root lattices and root spaces """ + # **************************************************************************** # Copyright (C) 2008-2009 Nicolas M. Thiery # @@ -59,19 +60,14 @@ def __init__(self, root_system, base_ring): from sage.categories.morphism import SetMorphism from sage.categories.homset import Hom from sage.categories.sets_with_partial_maps import SetsWithPartialMaps + self.root_system = root_system - CombinatorialFreeModule.__init__(self, base_ring, - root_system.index_set(), - prefix="alphacheck" if root_system.dual_side else "alpha", - latex_prefix="\\alpha^\\vee" if root_system.dual_side else "\\alpha", - category=RootLatticeRealizations(base_ring)) + CombinatorialFreeModule.__init__(self, base_ring, root_system.index_set(), prefix="alphacheck" if root_system.dual_side else "alpha", latex_prefix="\\alpha^\\vee" if root_system.dual_side else "\\alpha", category=RootLatticeRealizations(base_ring)) if base_ring is not ZZ: # Register the partial conversion back from ``self`` to the root lattice # See :meth:`_to_root_lattice` for tests root_lattice = self.root_system.root_lattice() - SetMorphism(Hom(self, root_lattice, SetsWithPartialMaps()), - self._to_root_lattice - ).register_as_conversion() + SetMorphism(Hom(self, root_lattice, SetsWithPartialMaps()), self._to_root_lattice).register_as_conversion() def _repr_(self): """ @@ -137,8 +133,7 @@ def to_coroot_space_morphism(self): """ R = self.base_ring() C = self.cartan_type().symmetrizer().map(R) - return self.module_morphism(diagonal=C.__getitem__, - codomain=self.coroot_space(R)) + return self.module_morphism(diagonal=C.__getitem__, codomain=self.coroot_space(R)) def _to_root_lattice(self, x): """ @@ -224,7 +219,8 @@ def to_ambient_space_morphism(self): def basis_value(basis, i): return basis[i] - return self.module_morphism(on_basis=functools.partial(basis_value, basis) , codomain=L) + + return self.module_morphism(on_basis=functools.partial(basis_value, basis), codomain=L) class RootSpaceElement(CombinatorialFreeModule.Element): @@ -280,7 +276,7 @@ def scalar(self, lambdacheck): # This is the mathematically canonical case, where we use the Cartan matrix to find the scalar product zero = self.parent().base_ring().zero() cartan_matrix = self.parent().dynkin_diagram() - return sum( (sum( (lambdacheck[i]*s for i,s in cartan_matrix.column(j)), zero) * c for j,c in self), zero) + return sum((sum((lambdacheck[i] * s for i, s in cartan_matrix.column(j)), zero) * c for j, c in self), zero) if lambdacheck in self.parent().root_system.ambient_space(): # lambdacheck lives in the ambient space of the root space, so we take the usual dot product in the ambient space diff --git a/src/sage/combinat/root_system/root_system.py b/src/sage/combinat/root_system/root_system.py index 68d2f490c58..4a3cacb1177 100644 --- a/src/sage/combinat/root_system/root_system.py +++ b/src/sage/combinat/root_system/root_system.py @@ -4,6 +4,7 @@ See :ref:`sage.combinat.root_system.all` for an overview. """ + # *************************************************************************** # Copyright (C) 2007 Mike Hansen , # Justin Walker @@ -331,8 +332,7 @@ def __init__(self, cartan_type, as_dual_of=None): self.dual_side = False # still fails for CartanType G2xA1 try: - self.dual = RootSystem(self._cartan_type.dual(), - as_dual_of=self) + self.dual = RootSystem(self._cartan_type.dual(), as_dual_of=self) except Exception: pass else: @@ -352,6 +352,7 @@ def _test_root_lattice_realizations(self, **options): """ options.pop('tester', None) from sage.misc.sage_unittest import TestSuite + TestSuite(self.root_lattice()).run(**options) TestSuite(self.root_space()).run(**options) TestSuite(self.weight_lattice()).run(**options) @@ -748,7 +749,7 @@ def ambient_space(self, base_ring=QQ): ------------------------------------------------------------ The following tests failed: _test_root_lattice_realization """ - if not hasattr(self.cartan_type(),"AmbientSpace"): + if not hasattr(self.cartan_type(), "AmbientSpace"): return None AmbientSpace = self.cartan_type().AmbientSpace if not base_ring.has_coerce_map_from(AmbientSpace.smallest_base_ring(self.cartan_type())): @@ -876,5 +877,5 @@ def WeylDim(ct, coeffs): lattice = RootSystem(ct).ambient_space() rank = ct.rank() fw = lattice.fundamental_weights() - hwv = lattice.sum(coeffs[i]*fw[i+1] for i in range(min(rank, len(coeffs)))) + hwv = lattice.sum(coeffs[i] * fw[i + 1] for i in range(min(rank, len(coeffs)))) return lattice.weyl_dimension(hwv) diff --git a/src/sage/combinat/root_system/type_A.py b/src/sage/combinat/root_system/type_A.py index 91907976f8c..5206f9b4a13 100644 --- a/src/sage/combinat/root_system/type_A.py +++ b/src/sage/combinat/root_system/type_A.py @@ -1,14 +1,15 @@ """ Root system data for type A """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008-2009 Daniel Bump # Copyright (C) 2008-2009 Justin Walker # Copyright (C) 2008-2009 Nicolas M. Thiery , # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.rings.integer_ring import ZZ from sage.combinat.root_system.root_lattice_realizations import RootLatticeRealizations @@ -45,6 +46,7 @@ class AmbientSpace(ambient_space.AmbientSpace): - :meth:`sage.combinat.root_system.root_lattice_realizations.RootLatticeRealizations.ParentMethods._plot_projection` """ + @classmethod def smallest_base_ring(cls, cartan_type=None): """ @@ -68,7 +70,7 @@ def dimension(self): sage: e.dimension() 4 """ - return self.root_system.cartan_type().rank()+1 + return self.root_system.cartan_type().rank() + 1 def root(self, i, j): """ @@ -90,7 +92,7 @@ def simple_root(self, i): sage: e.simple_roots() Finite family {1: (1, -1, 0, 0), 2: (0, 1, -1, 0), 3: (0, 0, 1, -1)} """ - return self.root(i-1, i) + return self.root(i - 1, i) def negative_roots(self): """ @@ -106,9 +108,9 @@ def negative_roots(self): (0, 0, -1, 1)] """ res = [] - for j in range(self.n-1): - for i in range(j+1,self.n): - res.append( self.root(i,j) ) + for j in range(self.n - 1): + for i in range(j + 1, self.n): + res.append(self.root(i, j)) return res def positive_roots(self): @@ -127,7 +129,7 @@ def positive_roots(self): res = [] for j in range(self.n): for i in range(j): - res.append( self.root(i,j) ) + res.append(self.root(i, j)) return res def highest_root(self): @@ -138,7 +140,7 @@ def highest_root(self): sage: e.highest_root() (1, 0, 0, -1) """ - return self.root(0,self.n-1) + return self.root(0, self.n - 1) def fundamental_weight(self, i): """ @@ -164,7 +166,7 @@ def det(self, k=1): sage: e.det(1/2) (1/2, 1/2, 1/2, 1/2) """ - return self.sum(self.monomial(j)*k for j in range(self.n)) + return self.sum(self.monomial(j) * k for j in range(self.n)) _plot_projection = RootLatticeRealizations.ParentMethods.__dict__['_plot_projection_barycentric'] @@ -269,10 +271,11 @@ def dynkin_diagram(self): ([1], []) """ from .dynkin_diagram import DynkinDiagram_class + n = self.n g = DynkinDiagram_class(self) for i in range(1, n): - g.add_edge(i, i+1) + g.add_edge(i, i + 1) return g def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2): @@ -300,11 +303,10 @@ def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2): if node is None: node = self._latex_draw_node if self.n > 1: - ret = "\\draw (0 cm,0) -- ({} cm,0);\n".format((self.n-1)*node_dist) + ret = "\\draw (0 cm,0) -- ({} cm,0);\n".format((self.n - 1) * node_dist) else: ret = "" - return ret + "".join(node((i-1)*node_dist, 0, label(i)) - for i in self.index_set()) + return ret + "".join(node((i - 1) * node_dist, 0, label(i)) for i in self.index_set()) def ascii_art(self, label=None, node=None): """ @@ -343,5 +345,5 @@ def ascii_art(self, label=None, node=None): # For unpickling backward compatibility (Sage <= 4.1) from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.root_system.type_A', - 'ambient_space', AmbientSpace) + +register_unpickle_override('sage.combinat.root_system.type_A', 'ambient_space', AmbientSpace) diff --git a/src/sage/combinat/root_system/type_A_affine.py b/src/sage/combinat/root_system/type_A_affine.py index cf642231967..ed6f5c5c6b1 100644 --- a/src/sage/combinat/root_system/type_A_affine.py +++ b/src/sage/combinat/root_system/type_A_affine.py @@ -1,12 +1,13 @@ """ Root system data for (untwisted) type A affine """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008-2009 Nicolas M. Thiery , # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from .cartan_type import CartanType_standard_untwisted_affine, CartanType_simply_laced @@ -98,6 +99,7 @@ def dynkin_diagram(self): [(0, 1, 2), (1, 0, 2)] """ from .dynkin_diagram import DynkinDiagram_class + n = self.n g = DynkinDiagram_class(self) @@ -106,7 +108,7 @@ def dynkin_diagram(self): g.add_edge(1, 0, 2) else: for i in range(1, n): - g.add_edge(i, i+1) + g.add_edge(i, i + 1) g.add_edge(0, 1) g.add_edge(0, n) return g @@ -135,18 +137,18 @@ def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2): if self.n == 1: ret = "\\draw (0, 0.1 cm) -- +(%s cm,0);\n" % node_dist ret += "\\draw (0, -0.1 cm) -- +(%s cm,0);\n" % node_dist - ret += self._latex_draw_arrow_tip(0.33*node_dist-0.2, 0, 180) - ret += self._latex_draw_arrow_tip(0.66*node_dist+0.2, 0, 0) + ret += self._latex_draw_arrow_tip(0.33 * node_dist - 0.2, 0, 180) + ret += self._latex_draw_arrow_tip(0.66 * node_dist + 0.2, 0, 0) ret += node(0, 0, label(0)) ret += node(node_dist, 0, label(1)) return ret - rt_most = (self.n-1)*node_dist + rt_most = (self.n - 1) * node_dist mid = 0.5 * rt_most ret = "\\draw (0 cm,0) -- (%s cm,0);\n" % rt_most ret += "\\draw (0 cm,0) -- (%s cm, 1.2 cm);\n" % mid ret += "\\draw (%s cm, 1.2 cm) -- (%s cm, 0);\n" % (mid, rt_most) for i in range(self.n): - ret += node(i*node_dist, 0, label(i+1)) + ret += node(i * node_dist, 0, label(i + 1)) ret += node(mid, 1.2, label(0), 'anchor=south east') return ret @@ -190,9 +192,9 @@ def ascii_art(self, label=None, node=None): l1 = label(1) return "{}<=>{}\n{!s:4}{}".format(node(l0), node(l1), l0, l1) ret = "{}\n{}".format(label(0), node(label(0))) - ret += "----"*(n-2) + "---+\n|" + " "*(n-2) + " |\n|" + " "*(n-2) + " |\n" - ret += "---".join(node(label(i)) for i in range(1,n+1)) + "\n" - ret += "".join("{!s:4}".format(label(i)) for i in range(1,n+1)) + ret += "----" * (n - 2) + "---+\n|" + " " * (n - 2) + " |\n|" + " " * (n - 2) + " |\n" + ret += "---".join(node(label(i)) for i in range(1, n + 1)) + "\n" + ret += "".join("{!s:4}".format(label(i)) for i in range(1, n + 1)) return ret def dual(self): @@ -221,6 +223,7 @@ def _default_folded_cartan_type(self): ['A', 3, 1] as a folding of ['A', 3, 1] """ from sage.combinat.root_system.type_folded import CartanTypeFolded + if self.n == 1: - return CartanTypeFolded(self, ['A', 3, 1], [[0,2], [1,3]]) + return CartanTypeFolded(self, ['A', 3, 1], [[0, 2], [1, 3]]) return CartanTypeFolded(self, self, [[i] for i in self.index_set()]) diff --git a/src/sage/combinat/root_system/type_A_infinity.py b/src/sage/combinat/root_system/type_A_infinity.py index 744a1dd4762..0dac31d8453 100644 --- a/src/sage/combinat/root_system/type_A_infinity.py +++ b/src/sage/combinat/root_system/type_A_infinity.py @@ -1,6 +1,7 @@ """ Root system data for type A infinity """ + # *************************************************************************** # Copyright (C) 2016 Andrew Mathas # @@ -20,6 +21,7 @@ class CartanType(CartanType_standard, CartanType_simple): While ``oo`` is the same as ``+Infinity`` in Sage, it is used as an alias for ``ZZ``. """ + # We do not inherit from CartanType_crystallographic because it provides # methods that are not implemented for A_oo. diff --git a/src/sage/combinat/root_system/type_B.py b/src/sage/combinat/root_system/type_B.py index 4d5d6ebc7dc..186bcddf609 100644 --- a/src/sage/combinat/root_system/type_B.py +++ b/src/sage/combinat/root_system/type_B.py @@ -1,6 +1,7 @@ """ Root system data for type B """ + # **************************************************************************** # Copyright (C) 2008-2009 Daniel Bump # Copyright (C) 2008-2009 Justin Walker @@ -64,7 +65,7 @@ def simple_root(self, i): """ if i not in self.index_set(): raise ValueError("{} is not in the index set".format(i)) - return self.root(i-1, i) if i < self.n else self.monomial(self.n-1) + return self.root(i - 1, i) if i < self.n else self.monomial(self.n - 1) def negative_roots(self): """ @@ -99,7 +100,7 @@ def positive_roots(self): (0, 0, 1)] """ res = [] - for i in range(self.n-1): + for i in range(self.n - 1): for j in range(i + 1, self.n): res.append(self.monomial(i) - self.monomial(j)) res.append(self.monomial(i) + self.monomial(j)) @@ -188,7 +189,7 @@ def coxeter_number(self): sage: CartanType(['B',4]).coxeter_number() 8 """ - return 2*self.n + return 2 * self.n def dual_coxeter_number(self): """ @@ -199,7 +200,7 @@ def dual_coxeter_number(self): sage: CartanType(['B',4]).dual_coxeter_number() 7 """ - return 2*self.n - 1 + return 2 * self.n - 1 def dual(self): """ @@ -211,6 +212,7 @@ def dual(self): ['B', 3] """ from . import cartan_type + return cartan_type.CartanType(["C", self.n]) def dynkin_diagram(self): @@ -234,12 +236,13 @@ def dynkin_diagram(self): [] """ from .dynkin_diagram import DynkinDiagram_class + n = self.n g = DynkinDiagram_class(self) for i in range(1, n): - g.add_edge(i, i+1) + g.add_edge(i, i + 1) if n >= 2: - g.set_edge_label(n-1, n, 2) + g.set_edge_label(n - 1, n, 2) return g def ascii_art(self, label=None, node=None): @@ -313,15 +316,15 @@ def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2, dual=False): if self.n == 1: return node(0, 0, label(1)) n = self.n - ret = "\\draw (0 cm,0) -- (%s cm,0);\n" % ((n-2)*node_dist) - ret += "\\draw (%s cm, 0.1 cm) -- +(%s cm,0);\n" % ((n-2)*node_dist, node_dist) - ret += "\\draw (%s cm, -0.1 cm) -- +(%s cm,0);\n" % ((n-2)*node_dist, node_dist) + ret = "\\draw (0 cm,0) -- (%s cm,0);\n" % ((n - 2) * node_dist) + ret += "\\draw (%s cm, 0.1 cm) -- +(%s cm,0);\n" % ((n - 2) * node_dist, node_dist) + ret += "\\draw (%s cm, -0.1 cm) -- +(%s cm,0);\n" % ((n - 2) * node_dist, node_dist) if dual: - ret += self._latex_draw_arrow_tip((n-1.5)*node_dist-0.2, 0, 180) + ret += self._latex_draw_arrow_tip((n - 1.5) * node_dist - 0.2, 0, 180) else: - ret += self._latex_draw_arrow_tip((n-1.5)*node_dist+0.2, 0, 0) + ret += self._latex_draw_arrow_tip((n - 1.5) * node_dist + 0.2, 0, 0) for i in range(self.n): - ret += node(i*node_dist, 0, label(i+1)) + ret += node(i * node_dist, 0, label(i + 1)) return ret def _default_folded_cartan_type(self): @@ -334,12 +337,12 @@ def _default_folded_cartan_type(self): ['B', 3] as a folding of ['D', 4] """ from sage.combinat.root_system.type_folded import CartanTypeFolded + n = self.n - return CartanTypeFolded(self, ['D', n + 1], - [[i] for i in range(1, n)] + [[n, n + 1]]) + return CartanTypeFolded(self, ['D', n + 1], [[i] for i in range(1, n)] + [[n, n + 1]]) # For unpickling backward compatibility (Sage <= 4.1) from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.root_system.type_B', - 'ambient_space', AmbientSpace) + +register_unpickle_override('sage.combinat.root_system.type_B', 'ambient_space', AmbientSpace) diff --git a/src/sage/combinat/root_system/type_BC_affine.py b/src/sage/combinat/root_system/type_BC_affine.py index 675b3fc7701..9de414f5997 100644 --- a/src/sage/combinat/root_system/type_BC_affine.py +++ b/src/sage/combinat/root_system/type_BC_affine.py @@ -1,14 +1,15 @@ """ Root system data for type BC affine """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008-2009 Daniel Bump # Copyright (C) 2008-2009 Justin Walker # Copyright (C) 2008-2009 Nicolas M. Thiery , # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from .cartan_type import CartanType_standard_affine from sage.rings.integer_ring import ZZ @@ -105,15 +106,16 @@ def dynkin_diagram(self): [(0, 1, 1), (1, 0, 4)] """ from .dynkin_diagram import DynkinDiagram_class + n = self.n g = DynkinDiagram_class(self) if n == 1: - g.add_edge(1,0,4) + g.add_edge(1, 0, 4) return g - g.add_edge(1,0,2) - for i in range(1, n-1): - g.add_edge(i, i+1) - g.add_edge(n,n-1,2) + g.add_edge(1, 0, 2) + for i in range(1, n - 1): + g.add_edge(i, i + 1) + g.add_edge(n, n - 1, 2) return g def _latex_(self): @@ -188,9 +190,9 @@ def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2, dual=False): ret += "\\draw (0, 0.15 cm) -- +(%s cm,0);\n" % node_dist ret += "\\draw (0, -0.15 cm) -- +(%s cm,0);\n" % node_dist if dual: - ret += self._latex_draw_arrow_tip(0.5*node_dist+0.2, 0, 0) + ret += self._latex_draw_arrow_tip(0.5 * node_dist + 0.2, 0, 0) else: - ret += self._latex_draw_arrow_tip(0.5*node_dist-0.2, 0, 180) + ret += self._latex_draw_arrow_tip(0.5 * node_dist - 0.2, 0, 180) ret += node(0, 0, label(0)) ret += node(node_dist, 0, label(1)) return ret @@ -198,9 +200,9 @@ def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2, dual=False): ret = "\\draw (0, 0.1 cm) -- +(%s cm,0);\n" % node_dist ret += "\\draw (0, -0.1 cm) -- +(%s cm,0);\n" % node_dist if dual: - ret += self._latex_draw_arrow_tip(0.5*node_dist+0.2, 0, 0) + ret += self._latex_draw_arrow_tip(0.5 * node_dist + 0.2, 0, 0) else: - ret += self._latex_draw_arrow_tip(0.5*node_dist-0.2, 0, 180) + ret += self._latex_draw_arrow_tip(0.5 * node_dist - 0.2, 0, 180) ret += "{\n\\pgftransformxshift{%s cm}\n" % node_dist ret += self.classical()._latex_dynkin_diagram(label, node, node_dist, dual=dual) ret += "}\n" + node(0, 0, label(0)) @@ -234,9 +236,9 @@ def ascii_art(self, label=None, node=None): n = self.n if n == 1: return " 4\n{}=<={}\n{!s:4}{!s:4}".format(node(label(0)), node(label(1)), label(0), label(1)) - ret = node(label(0)) + "=<=" + "---".join(node(label(i)) for i in range(1,n)) + ret = node(label(0)) + "=<=" + "---".join(node(label(i)) for i in range(1, n)) ret += "=<=" + node(label(n)) + '\n' - ret += "".join("{!s:4}".format(label(i)) for i in range(n+1)) + ret += "".join("{!s:4}".format(label(i)) for i in range(n + 1)) return ret def classical(self): @@ -247,6 +249,7 @@ def classical(self): ['C', 3] """ from . import cartan_type + return cartan_type.CartanType(["C", self.n]) def basic_untwisted(self): @@ -268,7 +271,8 @@ def basic_untwisted(self): ['A', 8] """ from . import cartan_type - return cartan_type.CartanType(["A", 2*self.n]) + + return cartan_type.CartanType(["A", 2 * self.n]) def _default_folded_cartan_type(self): """ @@ -280,6 +284,6 @@ def _default_folded_cartan_type(self): ['BC', 3, 2] as a folding of ['A', 5, 1] """ from sage.combinat.root_system.type_folded import CartanTypeFolded + n = self.n - return CartanTypeFolded(self, ['A', 2*n - 1, 1], - [[0]] + [[i, 2*n-i] for i in range(1, n)] + [[n]]) + return CartanTypeFolded(self, ['A', 2 * n - 1, 1], [[0]] + [[i, 2 * n - i] for i in range(1, n)] + [[n]]) diff --git a/src/sage/combinat/root_system/type_B_affine.py b/src/sage/combinat/root_system/type_B_affine.py index 7f2202aac55..a29e5847717 100644 --- a/src/sage/combinat/root_system/type_B_affine.py +++ b/src/sage/combinat/root_system/type_B_affine.py @@ -1,12 +1,13 @@ """ Root system data for (untwisted) type B affine """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008-2009 Nicolas M. Thiery , # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from .cartan_type import CartanType_standard_untwisted_affine @@ -78,21 +79,23 @@ def dynkin_diagram(self): [(0, 1, 2), (1, 0, 2)] """ from . import cartan_type + n = self.n if n == 1: - res = cartan_type.CartanType(["A",1,1]).dynkin_diagram() + res = cartan_type.CartanType(["A", 1, 1]).dynkin_diagram() res._cartan_type = self return res if n == 2: - res = cartan_type.CartanType(["C",2,1]).relabel({0:0, 1:2, 2:1}).dynkin_diagram() + res = cartan_type.CartanType(["C", 2, 1]).relabel({0: 0, 1: 2, 2: 1}).dynkin_diagram() res._cartan_type = self return res from .dynkin_diagram import DynkinDiagram_class + g = DynkinDiagram_class(self) for i in range(1, n): - g.add_edge(i, i+1) - g.set_edge_label(n-1, n, 2) - g.add_edge(0,2) + g.add_edge(i, i + 1) + g.set_edge_label(n - 1, n, 2) + g.add_edge(0, 2) return g def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2, dual=False): @@ -135,25 +138,27 @@ def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2, dual=False): node = self._latex_draw_node if self.n == 1: from . import cartan_type - return cartan_type.CartanType(["A",1,1])._latex_dynkin_diagram(label, node, node_dist) + + return cartan_type.CartanType(["A", 1, 1])._latex_dynkin_diagram(label, node, node_dist) if self.n == 2: from . import cartan_type - return cartan_type.CartanType(["C",2,1])._latex_dynkin_diagram(label, node, node_dist, dual) + + return cartan_type.CartanType(["C", 2, 1])._latex_dynkin_diagram(label, node, node_dist, dual) n = self.n - single_end = (n-2)*node_dist # Where the single line ends + single_end = (n - 2) * node_dist # Where the single line ends ret = "\\draw (0,0.7 cm) -- (%s cm,0);\n" % node_dist ret += "\\draw (0,-0.7 cm) -- (%s cm,0);\n" % node_dist ret += "\\draw (%s cm,0) -- (%s cm,0);\n" % (node_dist, single_end) ret += "\\draw (%s cm, 0.1 cm) -- +(%s cm,0);\n" % (single_end, node_dist) ret += "\\draw (%s cm, -0.1 cm) -- +(%s cm,0);\n" % (single_end, node_dist) if dual: - ret += self._latex_draw_arrow_tip(single_end+0.5*node_dist-0.2, 0, 180) + ret += self._latex_draw_arrow_tip(single_end + 0.5 * node_dist - 0.2, 0, 180) else: - ret += self._latex_draw_arrow_tip(single_end+0.5*node_dist+0.2, 0, 0) + ret += self._latex_draw_arrow_tip(single_end + 0.5 * node_dist + 0.2, 0, 0) ret += node(0, 0.7, label(0), 'left=3pt') ret += node(0, -0.7, label(1), 'left=3pt') for i in range(1, n): - ret += node(i*node_dist, 0, label(i+1)) + ret += node(i * node_dist, 0, label(i + 1)) return ret def ascii_art(self, label=None, node=None): @@ -185,17 +190,18 @@ def ascii_art(self, label=None, node=None): """ n = self.n from .cartan_type import CartanType + if label is None: label = lambda i: i if node is None: node = self._ascii_art_node if n == 1: - return CartanType(["A",1,1]).ascii_art(label, node) + return CartanType(["A", 1, 1]).ascii_art(label, node) if n == 2: - return CartanType(["C",2,1]).relabel({0:0, 1:2, 2:1}).ascii_art(label, node) + return CartanType(["C", 2, 1]).relabel({0: 0, 1: 2, 2: 1}).ascii_art(label, node) ret = " {} {}\n |\n |\n".format(node(label(0)), label(0)) - ret += "---".join(node(label(i)) for i in range(1,n)) + "=>={}\n".format(node(label(n))) - ret += "".join("{!s:4}".format(label(i)) for i in range(1,n+1)) + ret += "---".join(node(label(i)) for i in range(1, n)) + "=>={}\n".format(node(label(n))) + ret += "".join("{!s:4}".format(label(i)) for i in range(1, n + 1)) return ret def _default_folded_cartan_type(self): @@ -208,8 +214,8 @@ def _default_folded_cartan_type(self): ['B', 4, 1] as a folding of ['D', 5, 1] """ from sage.combinat.root_system.type_folded import CartanTypeFolded + n = self.n if n == 1: return CartanTypeFolded(self, ['A', 1, 1], [[0], [1]]) - return CartanTypeFolded(self, ['D', n + 1, 1], - [[i] for i in range(n)] + [[n, n+1]]) + return CartanTypeFolded(self, ['D', n + 1, 1], [[i] for i in range(n)] + [[n, n + 1]]) diff --git a/src/sage/combinat/root_system/type_C.py b/src/sage/combinat/root_system/type_C.py index 7117eea0da2..457fdcb97e9 100644 --- a/src/sage/combinat/root_system/type_C.py +++ b/src/sage/combinat/root_system/type_C.py @@ -1,14 +1,15 @@ """ Root system data for type C """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008-2009 Daniel Bump # Copyright (C) 2008-2009 Justin Walker # Copyright (C) 2008-2013 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from . import ambient_space @@ -54,7 +55,7 @@ def root(self, i, j, p1, p2): sage: e.root(0, 1, 1, 1) (-1, -1, 0) """ - return (-1)**p1 * self.monomial(i) + (-1)**p2 * self.monomial(j) + return (-1) ** p1 * self.monomial(i) + (-1) ** p2 * self.monomial(j) def simple_root(self, i): """ @@ -65,7 +66,7 @@ def simple_root(self, i): """ if i not in self.index_set(): raise ValueError("{} is not in the index set".format(i)) - return self.root(i-1, i,0,1) if i < self.n else self.root(self.n-1, self.n-1, 0, 0) + return self.root(i - 1, i, 0, 1) if i < self.n else self.root(self.n - 1, self.n - 1, 0, 0) def positive_roots(self): """ @@ -185,7 +186,7 @@ def coxeter_number(self): sage: CartanType(['C',4]).coxeter_number() 8 """ - return 2*self.n + return 2 * self.n def dual_coxeter_number(self): """ @@ -208,6 +209,7 @@ def dual(self): ['B', 3] """ from . import cartan_type + return cartan_type.CartanType(["B", self.n]) def dynkin_diagram(self): @@ -305,12 +307,12 @@ def _default_folded_cartan_type(self): ['C', 3] as a folding of ['A', 5] """ from sage.combinat.root_system.type_folded import CartanTypeFolded + n = self.n - return CartanTypeFolded(self, ['A', 2*n - 1], - [[i, 2*n - i] for i in range(1, n)] + [[n]]) + return CartanTypeFolded(self, ['A', 2 * n - 1], [[i, 2 * n - i] for i in range(1, n)] + [[n]]) # For unpickling backward compatibility (Sage <= 4.1) from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.root_system.type_C', - 'ambient_space', AmbientSpace) + +register_unpickle_override('sage.combinat.root_system.type_C', 'ambient_space', AmbientSpace) diff --git a/src/sage/combinat/root_system/type_C_affine.py b/src/sage/combinat/root_system/type_C_affine.py index c26e03f1b10..d5fcf70cb1d 100644 --- a/src/sage/combinat/root_system/type_C_affine.py +++ b/src/sage/combinat/root_system/type_C_affine.py @@ -1,12 +1,13 @@ """ Root system data for (untwisted) type C affine """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008-2009 Nicolas M. Thiery , # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from .cartan_type import CartanType_standard_untwisted_affine @@ -64,15 +65,17 @@ def dynkin_diagram(self): n = self.n if n == 1: from . import cartan_type - res = cartan_type.CartanType(["A",1,1]).dynkin_diagram() + + res = cartan_type.CartanType(["A", 1, 1]).dynkin_diagram() res._cartan_type = self return res from .dynkin_diagram import DynkinDiagram_class + g = DynkinDiagram_class(self) for i in range(1, n): - g.add_edge(i, i+1) - g.set_edge_label(n,n-1,2) - g.add_edge(0,1,2) + g.add_edge(i, i + 1) + g.set_edge_label(n, n - 1, 2) + g.add_edge(0, 1, 2) return g def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2, dual=False): @@ -122,14 +125,15 @@ def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2, dual=False): node = self._latex_draw_node if self.n == 1: from . import cartan_type - return cartan_type.CartanType(["A",1,1])._latex_dynkin_diagram(label, node, node_dist) + + return cartan_type.CartanType(["A", 1, 1])._latex_dynkin_diagram(label, node, node_dist) ret = "\\draw (0, 0.1 cm) -- +(%s cm,0);\n" % node_dist ret += "\\draw (0, -0.1 cm) -- +(%s cm,0);\n" % node_dist if dual: - ret += self._latex_draw_arrow_tip(0.5*node_dist-0.2, 0, 180) + ret += self._latex_draw_arrow_tip(0.5 * node_dist - 0.2, 0, 180) else: - ret += self._latex_draw_arrow_tip(0.5*node_dist+0.2, 0, 0) + ret += self._latex_draw_arrow_tip(0.5 * node_dist + 0.2, 0, 0) ret += "{\n\\pgftransformxshift{%s cm}\n" % node_dist ret += self.classical()._latex_dynkin_diagram(label, node, node_dist, dual) ret += "}\n" + node(0, 0, label(0)) @@ -163,11 +167,12 @@ def ascii_art(self, label=None, node=None): node = self._ascii_art_node n = self.n from .cartan_type import CartanType + if n == 1: - return CartanType(["A",1,1]).ascii_art(label, node) - ret = node(label(0)) + "=>=" + "---".join(node(label(i)) for i in range(1,n)) + return CartanType(["A", 1, 1]).ascii_art(label, node) + ret = node(label(0)) + "=>=" + "---".join(node(label(i)) for i in range(1, n)) ret += "=<=" + node(label(n)) + '\n' - ret += "".join("{!s:4}".format(label(i)) for i in range(n+1)) + ret += "".join("{!s:4}".format(label(i)) for i in range(n + 1)) return ret def _default_folded_cartan_type(self): @@ -180,8 +185,8 @@ def _default_folded_cartan_type(self): ['C', 3, 1] as a folding of ['A', 5, 1] """ from sage.combinat.root_system.type_folded import CartanTypeFolded + n = self.n if n == 1: return CartanTypeFolded(self, ['A', 1, 1], [[0], [1]]) - return CartanTypeFolded(self, ['A', 2*n-1, 1], - [[0]] + [[i, 2*n-i] for i in range(1, n)] + [[n]]) + return CartanTypeFolded(self, ['A', 2 * n - 1, 1], [[0]] + [[i, 2 * n - i] for i in range(1, n)] + [[n]]) diff --git a/src/sage/combinat/root_system/type_D.py b/src/sage/combinat/root_system/type_D.py index c6d3b490d7f..2d31eeb2110 100644 --- a/src/sage/combinat/root_system/type_D.py +++ b/src/sage/combinat/root_system/type_D.py @@ -1,6 +1,7 @@ """ Root system data for type D """ + # **************************************************************************** # Copyright (C) 2008-2009 Daniel Bump # Copyright (C) 2008-2009 Justin Walker @@ -37,8 +38,8 @@ def root(self, i, j, p1, p2): (-1, 0, 0) """ if i != j: - return (-1)**p1 * self.monomial(i) + (-1)**p2 * self.monomial(j) - return (-1)**p1 * self.monomial(i) + return (-1) ** p1 * self.monomial(i) + (-1) ** p2 * self.monomial(j) + return (-1) ** p1 * self.monomial(i) def simple_root(self, i): """ @@ -49,7 +50,7 @@ def simple_root(self, i): """ if i not in self.index_set(): raise ValueError("{} is not in the index set".format(i)) - return self.root(i-1, i, 0, 1) if i < self.n else self.root(self.n-2, self.n-1, 0, 0) + return self.root(i - 1, i, 0, 1) if i < self.n else self.root(self.n - 2, self.n - 1, 0, 0) def positive_roots(self): """ @@ -112,7 +113,7 @@ def fundamental_weight(self, i): if i == n: return self.sum(self.monomial(j) for j in range(n)) / 2 if i == n - 1: - return (self.sum(self.monomial(j) for j in range(n-1)) - self.monomial(n-1)) / 2 + return (self.sum(self.monomial(j) for j in range(n - 1)) - self.monomial(n - 1)) / 2 return self.sum(self.monomial(j) for j in range(i)) @@ -201,7 +202,7 @@ def coxeter_number(self): sage: CartanType(['D',4]).coxeter_number() 6 """ - return 2*self.n - 2 + return 2 * self.n - 2 def dual_coxeter_number(self): """ @@ -212,7 +213,7 @@ def dual_coxeter_number(self): sage: CartanType(['D',4]).dual_coxeter_number() 6 """ - return 2*self.n - 2 + return 2 * self.n - 2 @cached_method def dynkin_diagram(self): @@ -261,12 +262,13 @@ def dynkin_diagram(self): [] """ from .dynkin_diagram import DynkinDiagram_class + g = DynkinDiagram_class(self) n = self.n if n >= 3: - for i in range(1, n-1): - g.add_edge(i, i+1) - g.add_edge(n-2, n) + for i in range(1, n - 1): + g.add_edge(i, i + 1) + g.add_edge(n - 2, n) return g def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2): @@ -293,15 +295,15 @@ def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2): ret = node(0, 0, label(1)) ret += node(node_dist, 0, label(2)) return ret - rt_most = (self.n-2) * node_dist + rt_most = (self.n - 2) * node_dist center_point = rt_most - node_dist ret = "\\draw (0 cm,0) -- (%s cm,0);\n" % center_point ret += "\\draw (%s cm,0) -- (%s cm,0.7 cm);\n" % (center_point, rt_most) ret += "\\draw (%s cm,0) -- (%s cm,-0.7 cm);\n" % (center_point, rt_most) - for i in range(self.n-2): - ret += node(i*node_dist, 0, label(i+1)) + for i in range(self.n - 2): + ret += node(i * node_dist, 0, label(i + 1)) ret += node(rt_most, 0.7, label(self.n), 'right=3pt') - ret += node(rt_most, -0.7, label(self.n-1), 'right=3pt') + ret += node(rt_most, -0.7, label(self.n - 1), 'right=3pt') return ret def ascii_art(self, label=None, node=None): @@ -343,13 +345,12 @@ def ascii_art(self, label=None, node=None): if n == 2: ret = "{} {}\n".format(node(label(1)), node(label(2))) return ret + "{!s:4}{!s:4}".format(label(1), label(2)) - ret = (4*(n-3))*" "+"{} {}\n".format(node(label(n)), label(n)) - ret += ((4*(n-3))*" " + "|\n")*2 + ret = (4 * (n - 3)) * " " + "{} {}\n".format(node(label(n)), label(n)) + ret += ((4 * (n - 3)) * " " + "|\n") * 2 ret += "---".join(node(label(i)) for i in range(1, n)) + "\n" ret += "".join("{!s:4}".format(label(i)) for i in range(1, n)) return ret # For unpickling backward compatibility (Sage <= 4.1) -register_unpickle_override('sage.combinat.root_system.type_D', - 'ambient_space', AmbientSpace) +register_unpickle_override('sage.combinat.root_system.type_D', 'ambient_space', AmbientSpace) diff --git a/src/sage/combinat/root_system/type_D_affine.py b/src/sage/combinat/root_system/type_D_affine.py index 59748fb2ff6..09e801ceeff 100644 --- a/src/sage/combinat/root_system/type_D_affine.py +++ b/src/sage/combinat/root_system/type_D_affine.py @@ -1,14 +1,15 @@ """ Root system data for (untwisted) type D affine """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008-2009 Daniel Bump # Copyright (C) 2008-2009 Justin Walker # Copyright (C) 2008-2009 Nicolas M. Thiery , # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from .cartan_type import CartanType_standard_untwisted_affine, CartanType_simply_laced @@ -97,17 +98,19 @@ def dynkin_diagram(self): (2, 0, 1), (2, 1, 1), (3, 0, 1), (3, 1, 1)] """ from .dynkin_diagram import DynkinDiagram_class + n = self.n if n == 3: from . import cartan_type - res = cartan_type.CartanType(["A",3,1]).relabel({0:0, 1:3, 2:1, 3: 2}).dynkin_diagram() + + res = cartan_type.CartanType(["A", 3, 1]).relabel({0: 0, 1: 3, 2: 1, 3: 2}).dynkin_diagram() res._cartan_type = self return res g = DynkinDiagram_class(self) - for i in range(1, n-1): - g.add_edge(i, i+1) - g.add_edge(n-2,n) - g.add_edge(0,2) + for i in range(1, n - 1): + g.add_edge(i, i + 1) + g.add_edge(n - 2, n) + g.add_edge(0, 2) return g def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2, dual=False): @@ -136,8 +139,9 @@ def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2, dual=False): n = self.n if n == 3: from . import cartan_type - relabel = {0:label(0), 1:label(3), 2:label(1), 3:label(2)} - return cartan_type.CartanType(["A",3,1]).relabel(relabel)._latex_dynkin_diagram(node_dist=node_dist) + + relabel = {0: label(0), 1: label(3), 2: label(1), 3: label(2)} + return cartan_type.CartanType(["A", 3, 1]).relabel(relabel)._latex_dynkin_diagram(node_dist=node_dist) rt_most = (n - 2) * node_dist center_point = rt_most - node_dist ret = "\\draw (0,0.7 cm) -- (%s cm,0);\n" % node_dist @@ -147,10 +151,10 @@ def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2, dual=False): ret += "\\draw (%s cm,0) -- (%s cm,-0.7 cm);\n" % (center_point, rt_most) ret += node(0, 0.7, label(0), "left=3pt") ret += node(0, -0.7, label(1), "left=3pt") - for i in range(1, self.n-2): - ret += node(i*node_dist, 0, label(i+1)) + for i in range(1, self.n - 2): + ret += node(i * node_dist, 0, label(i + 1)) ret += node(rt_most, 0.7, label(n), "right=3pt") - ret += node(rt_most, -0.7, label(n-1), "right=3pt") + ret += node(rt_most, -0.7, label(n - 1), "right=3pt") return ret def ascii_art(self, label=None, node=None): @@ -190,7 +194,8 @@ def ascii_art(self, label=None, node=None): n = self.n if n == 3: from . import cartan_type - return cartan_type.CartanType(["A",3,1]).relabel({0:0, 1:3, 2:1, 3: 2}).ascii_art(label, node) + + return cartan_type.CartanType(["A", 3, 1]).relabel({0: 0, 1: 3, 2: 1, 3: 2}).ascii_art(label, node) if n == 4: ret = " {} {}\n".format(node(label(4)), label(4)) + " |\n |\n" ret += "{}---{}---{}\n".format(node(label(1)), node(label(2)), node(label(3))) @@ -199,9 +204,9 @@ def ascii_art(self, label=None, node=None): return ret ret = "{!s:>3} {}".format(label(0), node(label(0))) - ret += (4*(n-4)-1)*" "+"{} {}\n".format(node(label(n)), label(n)) - ret += " |" + (4*(n-4)-1)*" " + "|\n" - ret += " |" + (4*(n-4)-1)*" " + "|\n" + ret += (4 * (n - 4) - 1) * " " + "{} {}\n".format(node(label(n)), label(n)) + ret += " |" + (4 * (n - 4) - 1) * " " + "|\n" + ret += " |" + (4 * (n - 4) - 1) * " " + "|\n" ret += "---".join(node(label(i)) for i in range(1, n)) - ret += '\n' + "".join("{!s:4}".format(label(i)) for i in range(1,n)) + ret += '\n' + "".join("{!s:4}".format(label(i)) for i in range(1, n)) return ret diff --git a/src/sage/combinat/root_system/type_E.py b/src/sage/combinat/root_system/type_E.py index 0fe7c42a3bd..b6b0648dc4d 100644 --- a/src/sage/combinat/root_system/type_E.py +++ b/src/sage/combinat/root_system/type_E.py @@ -1,6 +1,7 @@ """ Root system data for type E """ + # **************************************************************************** # Copyright (C) 2008-2009 Daniel Bump # Copyright (C) 2008-2009 Justin Walker @@ -41,33 +42,15 @@ def __init__(self, root_system, baseRing): sage: [e.weyl_dimension(v) for v in e.fundamental_weights()] [3875, 147250, 6696000, 6899079264, 146325270, 2450240, 30380, 248] """ - v = ZZ(1)/ZZ(2) + v = ZZ(1) / ZZ(2) self.rank = root_system.cartan_type().rank() ambient_space.AmbientSpace.__init__(self, root_system, baseRing) if self.rank == 6: - self.Base = [v*(self.root(0,7)-self.root(1,2,3,4,5,6)), - self.root(0,1), - self.root(0,1,p1=1), - self.root(1,2,p1=1), - self.root(2,3,p1=1), - self.root(3,4,p1=1)] + self.Base = [v * (self.root(0, 7) - self.root(1, 2, 3, 4, 5, 6)), self.root(0, 1), self.root(0, 1, p1=1), self.root(1, 2, p1=1), self.root(2, 3, p1=1), self.root(3, 4, p1=1)] elif self.rank == 7: - self.Base = [v*(self.root(0,7)-self.root(1,2,3,4,5,6)), - self.root(0,1), - self.root(0,1,p1=1), - self.root(1,2,p1=1), - self.root(2,3,p1=1), - self.root(3,4,p1=1), - self.root(4,5,p1=1)] + self.Base = [v * (self.root(0, 7) - self.root(1, 2, 3, 4, 5, 6)), self.root(0, 1), self.root(0, 1, p1=1), self.root(1, 2, p1=1), self.root(2, 3, p1=1), self.root(3, 4, p1=1), self.root(4, 5, p1=1)] elif self.rank == 8: - self.Base = [v*(self.root(0,7)-self.root(1,2,3,4,5,6)), - self.root(0,1), - self.root(0,1,p1=1), - self.root(1,2,p1=1), - self.root(2,3,p1=1), - self.root(3,4,p1=1), - self.root(4,5,p1=1), - self.root(5,6,p1=1)] + self.Base = [v * (self.root(0, 7) - self.root(1, 2, 3, 4, 5, 6)), self.root(0, 1), self.root(0, 1, p1=1), self.root(1, 2, p1=1), self.root(2, 3, p1=1), self.root(3, 4, p1=1), self.root(4, 5, p1=1), self.root(5, 6, p1=1)] else: raise NotImplementedError("Type \'E\' root systems only come in flavors 6, 7, 8. Please make another choice") @@ -125,20 +108,20 @@ def root(self, i1, i2=None, i3=None, i4=None, i5=None, i6=None, i7=None, i8=None (0, 0, 0, 0, 0, 0, 1, 1)] """ if i1 == i2 or i2 is None: - return (-1)**p1*self.monomial(i1) + return (-1) ** p1 * self.monomial(i1) if i3 is None: - return (-1)**p1*self.monomial(i1) + (-1)**p2*self.monomial(i2) + return (-1) ** p1 * self.monomial(i1) + (-1) ** p2 * self.monomial(i2) if i4 is None: - return (-1)**p1*self.monomial(i1) + (-1)**p2*self.monomial(i2)+(-1)**p3*self.monomial(i3) + return (-1) ** p1 * self.monomial(i1) + (-1) ** p2 * self.monomial(i2) + (-1) ** p3 * self.monomial(i3) if i5 is None: - return (-1)**p1*self.monomial(i1) + (-1)**p2*self.monomial(i2)+(-1)**p3*self.monomial(i3)+(-1)**p4*self.monomial(i4) + return (-1) ** p1 * self.monomial(i1) + (-1) ** p2 * self.monomial(i2) + (-1) ** p3 * self.monomial(i3) + (-1) ** p4 * self.monomial(i4) if i6 is None: - return (-1)**p1*self.monomial(i1) + (-1)**p2*self.monomial(i2)+(-1)**p3*self.monomial(i3)+(-1)**p4*self.monomial(i4)+(-1)**p5*self.monomial(i5) + return (-1) ** p1 * self.monomial(i1) + (-1) ** p2 * self.monomial(i2) + (-1) ** p3 * self.monomial(i3) + (-1) ** p4 * self.monomial(i4) + (-1) ** p5 * self.monomial(i5) if i7 is None: - return (-1)**p1*self.monomial(i1) + (-1)**p2*self.monomial(i2)+(-1)**p3*self.monomial(i3)+(-1)**p4*self.monomial(i4)+(-1)**p5*self.monomial(i5)+(-1)**p6*self.monomial(i6) + return (-1) ** p1 * self.monomial(i1) + (-1) ** p2 * self.monomial(i2) + (-1) ** p3 * self.monomial(i3) + (-1) ** p4 * self.monomial(i4) + (-1) ** p5 * self.monomial(i5) + (-1) ** p6 * self.monomial(i6) if i8 is None: - return (-1)**p1*self.monomial(i1) + (-1)**p2*self.monomial(i2)+(-1)**p3*self.monomial(i3)+(-1)**p4*self.monomial(i4)+(-1)**p5*self.monomial(i5)+(-1)**p6*self.monomial(i6)+(-1)**p7*self.monomial(i7) - return (-1)**p1*self.monomial(i1) + (-1)**p2*self.monomial(i2)+(-1)**p3*self.monomial(i3)+(-1)**p4*self.monomial(i4)+(-1)**p5*self.monomial(i5)+(-1)**p6*self.monomial(i6)+(-1)**p7*self.monomial(i7)+(-1)**p8*self.monomial(i8) + return (-1) ** p1 * self.monomial(i1) + (-1) ** p2 * self.monomial(i2) + (-1) ** p3 * self.monomial(i3) + (-1) ** p4 * self.monomial(i4) + (-1) ** p5 * self.monomial(i5) + (-1) ** p6 * self.monomial(i6) + (-1) ** p7 * self.monomial(i7) + return (-1) ** p1 * self.monomial(i1) + (-1) ** p2 * self.monomial(i2) + (-1) ** p3 * self.monomial(i3) + (-1) ** p4 * self.monomial(i4) + (-1) ** p5 * self.monomial(i5) + (-1) ** p6 * self.monomial(i6) + (-1) ** p7 * self.monomial(i7) + (-1) ** p8 * self.monomial(i8) def simple_root(self, i): """ @@ -153,7 +136,7 @@ def simple_root(self, i): """ if i not in self.index_set(): raise ValueError("{} is not in the index set".format(i)) - return self.Base[i-1] + return self.Base[i - 1] def negative_roots(self): """ @@ -200,7 +183,7 @@ def negative_roots(self): (1/2, 1/2, 1/2, -1/2, 1/2, 1/2, 1/2, -1/2), (1/2, 1/2, 1/2, 1/2, -1/2, 1/2, 1/2, -1/2)] """ - return [ -a for a in self.positive_roots()] + return [-a for a in self.positive_roots()] def positive_roots(self): """ @@ -375,25 +358,15 @@ def positive_roots(self): sage: e.rho() (0, 1, 2, 3, 4, 5, 6, 23) """ - v = ZZ(1)/ZZ(2) + v = ZZ(1) / ZZ(2) # Note that if not hasattr(self, 'PosRoots'): if self.rank == 6: - self.PosRoots = ( [ self.root(i,j) for i in range(self.rank-1) for j in range(i+1,self.rank-1) ] + - [ self.root(i,j,p1=1) for i in range(self.rank-1) for j in range(i+1,self.rank-1) ] + - [ v*(self.root(7)-self.root(6)-self.root(5)+self.root(0,1,2,3,4,p1=p1,p2=p2,p3=p3,p4=p4,p5=p5)) - for p1 in [0,1] for p2 in [0,1] for p3 in [0,1] for p4 in [0,1] for p5 in [0,1] if (p1+p2+p3+p4+p5) % 2 == 0 ]) + self.PosRoots = [self.root(i, j) for i in range(self.rank - 1) for j in range(i + 1, self.rank - 1)] + [self.root(i, j, p1=1) for i in range(self.rank - 1) for j in range(i + 1, self.rank - 1)] + [v * (self.root(7) - self.root(6) - self.root(5) + self.root(0, 1, 2, 3, 4, p1=p1, p2=p2, p3=p3, p4=p4, p5=p5)) for p1 in [0, 1] for p2 in [0, 1] for p3 in [0, 1] for p4 in [0, 1] for p5 in [0, 1] if (p1 + p2 + p3 + p4 + p5) % 2 == 0] elif self.rank == 7: - self.PosRoots = ( [ self.root(i,j) for i in range(self.rank-1) for j in range(i+1,self.rank-1) ] + - [ self.root(i,j,p1=1) for i in range(self.rank-1) for j in range(i+1,self.rank-1) ] + - [ self.root(6,7,p1=1) ] + - [ v*(self.root(7)-self.root(6)+self.root(0,1,2,3,4,5,p1=p1,p2=p2,p3=p3,p4=p4,p5=p5,p6=p6)) - for p1 in [0,1] for p2 in [0,1] for p3 in [0,1] for p4 in [0,1] for p5 in [0,1] for p6 in [0,1] if (p1+p2+p3+p4+p5+p6) % 2 == 1 ]) + self.PosRoots = [self.root(i, j) for i in range(self.rank - 1) for j in range(i + 1, self.rank - 1)] + [self.root(i, j, p1=1) for i in range(self.rank - 1) for j in range(i + 1, self.rank - 1)] + [self.root(6, 7, p1=1)] + [v * (self.root(7) - self.root(6) + self.root(0, 1, 2, 3, 4, 5, p1=p1, p2=p2, p3=p3, p4=p4, p5=p5, p6=p6)) for p1 in [0, 1] for p2 in [0, 1] for p3 in [0, 1] for p4 in [0, 1] for p5 in [0, 1] for p6 in [0, 1] if (p1 + p2 + p3 + p4 + p5 + p6) % 2 == 1] elif self.rank == 8: - self.PosRoots = ( [ self.root(i,j) for i in range(self.rank) for j in range(i+1,self.rank) ] + - [ self.root(i,j,p1=1) for i in range(self.rank) for j in range(i+1,self.rank) ] + - [ v*(self.root(7)+self.root(0,1,2,3,4,5,6,p1=p1,p2=p2,p3=p3,p4=p4,p5=p5,p6=p6,p7=p7)) - for p1 in [0,1] for p2 in [0,1] for p3 in [0,1] for p4 in [0,1] for p5 in [0,1] for p6 in [0,1] for p7 in [0,1] if (p1+p2+p3+p4+p5+p6+p7) % 2 == 0 ]) + self.PosRoots = [self.root(i, j) for i in range(self.rank) for j in range(i + 1, self.rank)] + [self.root(i, j, p1=1) for i in range(self.rank) for j in range(i + 1, self.rank)] + [v * (self.root(7) + self.root(0, 1, 2, 3, 4, 5, 6, p1=p1, p2=p2, p3=p3, p4=p4, p5=p5, p6=p6, p7=p7)) for p1 in [0, 1] for p2 in [0, 1] for p3 in [0, 1] for p4 in [0, 1] for p5 in [0, 1] for p6 in [0, 1] for p7 in [0, 1] if (p1 + p2 + p3 + p4 + p5 + p6 + p7) % 2 == 0] return self.PosRoots @@ -405,32 +378,14 @@ def fundamental_weights(self): sage: e.fundamental_weights() Finite family {1: (0, 0, 0, 0, 0, -2/3, -2/3, 2/3), 2: (1/2, 1/2, 1/2, 1/2, 1/2, -1/2, -1/2, 1/2), 3: (-1/2, 1/2, 1/2, 1/2, 1/2, -5/6, -5/6, 5/6), 4: (0, 0, 1, 1, 1, -1, -1, 1), 5: (0, 0, 0, 1, 1, -2/3, -2/3, 2/3), 6: (0, 0, 0, 0, 1, -1/3, -1/3, 1/3)} """ - v2 = ZZ(1)/ZZ(2) - v3 = ZZ(1)/ZZ(3) + v2 = ZZ(1) / ZZ(2) + v3 = ZZ(1) / ZZ(3) if self.rank == 6: - return Family({ 1: 2*v3*self.root(7,6,5,p2=1,p3=1), - 2: v2*self.root(0,1,2,3,4,5,6,7,p6=1,p7=1), - 3: 5*v2*v3*self.root(7,6,5,p2=1,p3=1)+v2*self.root(0,1,2,3,4,p1=1), - 4: self.root(2,3,4,5,6,7,p4=1,p5=1), - 5: 2*v3*self.root(7,6,5,p2=1,p3=1)+self.root(3,4), - 6: v3*self.root(7,6,5,p2=1,p3=1)+self.root(4)}) + return Family({1: 2 * v3 * self.root(7, 6, 5, p2=1, p3=1), 2: v2 * self.root(0, 1, 2, 3, 4, 5, 6, 7, p6=1, p7=1), 3: 5 * v2 * v3 * self.root(7, 6, 5, p2=1, p3=1) + v2 * self.root(0, 1, 2, 3, 4, p1=1), 4: self.root(2, 3, 4, 5, 6, 7, p4=1, p5=1), 5: 2 * v3 * self.root(7, 6, 5, p2=1, p3=1) + self.root(3, 4), 6: v3 * self.root(7, 6, 5, p2=1, p3=1) + self.root(4)}) if self.rank == 7: - return Family({ 1: self.root(7,6,p2=1), - 2: v2*self.root(0,1,2,3,4,5)+self.root(6,7,p1=1), - 3: v2*(self.root(0,1,2,3,4,5,p1=1)+3*self.root(6,7,p1=1)), - 4: self.root(2,3,4,5)+2*self.root(6,7,p1=1), - 5: 3*v2*self.root(6,7,p1=1)+self.root(3,4,5), - 6: self.root(4,5,6,7,p3=1), - 7: self.root(5)+v2*self.root(6,7,p1=1)}) + return Family({1: self.root(7, 6, p2=1), 2: v2 * self.root(0, 1, 2, 3, 4, 5) + self.root(6, 7, p1=1), 3: v2 * (self.root(0, 1, 2, 3, 4, 5, p1=1) + 3 * self.root(6, 7, p1=1)), 4: self.root(2, 3, 4, 5) + 2 * self.root(6, 7, p1=1), 5: 3 * v2 * self.root(6, 7, p1=1) + self.root(3, 4, 5), 6: self.root(4, 5, 6, 7, p3=1), 7: self.root(5) + v2 * self.root(6, 7, p1=1)}) if self.rank == 8: - return Family({ 1: 2*self.root(7), - 2: v2*(self.root(0,1,2,3,4,5,6)+5*self.root(7)), - 3: v2*(self.root(0,1,2,3,4,5,6,p1=1)+7*self.root(7)), - 4: self.root(2,3,4,5,6)+5*self.root(7), - 5: self.root(3,4,5,6)+4*self.root(7), - 6: self.root(4,5,6)+3*self.root(7), - 7: self.root(5,6)+2*self.root(7), - 8: self.root(6,7)}) + return Family({1: 2 * self.root(7), 2: v2 * (self.root(0, 1, 2, 3, 4, 5, 6) + 5 * self.root(7)), 3: v2 * (self.root(0, 1, 2, 3, 4, 5, 6, p1=1) + 7 * self.root(7)), 4: self.root(2, 3, 4, 5, 6) + 5 * self.root(7), 5: self.root(3, 4, 5, 6) + 4 * self.root(7), 6: self.root(4, 5, 6) + 3 * self.root(7), 7: self.root(5, 6) + 2 * self.root(7), 8: self.root(6, 7)}) from .cartan_type import CartanType_standard_finite, CartanType_simple, CartanType_simply_laced @@ -563,11 +518,12 @@ def dynkin_diagram(self): (6, 7, 1), (7, 6, 1), (7, 8, 1), (8, 7, 1)] """ from .dynkin_diagram import DynkinDiagram_class + g = DynkinDiagram_class(self) - g.add_edge(1,3) - g.add_edge(2,4) + g.add_edge(1, 3) + g.add_edge(2, 4) for i in range(3, self.n): - g.add_edge(i, i+1) + g.add_edge(i, i + 1) return g def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2): @@ -592,12 +548,12 @@ def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2): label = lambda i: i if node is None: node = self._latex_draw_node - ret = "\\draw (0 cm,0) -- (%s cm,0);\n" % ((self.n-2)*node_dist) - ret += "\\draw (%s cm, 0 cm) -- +(0,%s cm);\n" % (2*node_dist, node_dist) + ret = "\\draw (0 cm,0) -- (%s cm,0);\n" % ((self.n - 2) * node_dist) + ret += "\\draw (%s cm, 0 cm) -- +(0,%s cm);\n" % (2 * node_dist, node_dist) ret += node(0, 0, label(1)) - for i in range(1, self.n-1): - ret += node(i*node_dist, 0, label(i+2)) - ret += node(2*node_dist, node_dist, label(2), 'right=3pt') + for i in range(1, self.n - 1): + ret += node(i * node_dist, 0, label(i + 2)) + ret += node(2 * node_dist, node_dist, label(2), 'right=3pt') return ret def ascii_art(self, label=None, node=None): @@ -629,12 +585,12 @@ def ascii_art(self, label=None, node=None): label = lambda i: i if node is None: node = self._ascii_art_node - labels = [label(i) for i in [1,3,4,5,6] + list(range(7, self.n+1))] # We exclude 2 because of the special case + labels = [label(i) for i in [1, 3, 4, 5, 6] + list(range(7, self.n + 1))] # We exclude 2 because of the special case ret = " {} {}\n |\n |\n".format(node(label(2)), label(2)) return ret + '---'.join(node(i) for i in labels) + '\n' + "".join("{!s:4}".format(i) for i in labels) # For unpickling backward compatibility (Sage <= 4.1) from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.root_system.type_E', - 'ambient_space', AmbientSpace) + +register_unpickle_override('sage.combinat.root_system.type_E', 'ambient_space', AmbientSpace) diff --git a/src/sage/combinat/root_system/type_E_affine.py b/src/sage/combinat/root_system/type_E_affine.py index 527d61414b2..5809c945506 100644 --- a/src/sage/combinat/root_system/type_E_affine.py +++ b/src/sage/combinat/root_system/type_E_affine.py @@ -1,14 +1,15 @@ """ Root system data for (untwisted) type E affine """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008-2009 Daniel Bump # Copyright (C) 2008-2009 Justin Walker # Copyright (C) 2008-2009 Nicolas M. Thiery , # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from .cartan_type import CartanType_standard_untwisted_affine, CartanType_simply_laced @@ -115,12 +116,13 @@ def dynkin_diagram(self): (6, 5, 1), (6, 7, 1), (7, 6, 1), (7, 8, 1), (8, 0, 1), (8, 7, 1)] """ from .dynkin_diagram import DynkinDiagram_class + n = self.n g = DynkinDiagram_class(self) - g.add_edge(1,3) - g.add_edge(2,4) - for i in range(3,n): - g.add_edge(i, i+1) + g.add_edge(1, 3) + g.add_edge(2, 4) + for i in range(3, n): + g.add_edge(i, i + 1) if n == 6: g.add_edge(0, 2) elif n == 7: @@ -157,29 +159,29 @@ def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2): node = self._latex_draw_node if n == 7: - ret = "\\draw (0 cm,0) -- (%s cm,0);\n" % ((n-1)*node_dist) - ret += "\\draw (%s cm, 0 cm) -- +(0,%s cm);\n" % (3*node_dist, node_dist) + ret = "\\draw (0 cm,0) -- (%s cm,0);\n" % ((n - 1) * node_dist) + ret += "\\draw (%s cm, 0 cm) -- +(0,%s cm);\n" % (3 * node_dist, node_dist) ret += node(0, 0, label(0)) ret += node(node_dist, 0, label(1)) for i in range(2, n): - ret += node(i*node_dist, 0, label(i+1)) - ret += node(3*node_dist, node_dist, label(2), "right=3pt") + ret += node(i * node_dist, 0, label(i + 1)) + ret += node(3 * node_dist, node_dist, label(2), "right=3pt") return ret - ret = "\\draw (0 cm,0) -- (%s cm,0);\n" % ((n-2)*node_dist) - ret += "\\draw (%s cm, 0 cm) -- +(0,%s cm);\n" % (2*node_dist, node_dist) + ret = "\\draw (0 cm,0) -- (%s cm,0);\n" % ((n - 2) * node_dist) + ret += "\\draw (%s cm, 0 cm) -- +(0,%s cm);\n" % (2 * node_dist, node_dist) if n == 6: - ret += "\\draw (%s cm, %s cm) -- +(0,%s cm);\n" % (2*node_dist, node_dist, node_dist) - ret += node(2*node_dist, 2*node_dist, label(0), "right=3pt") - else: # n == 8 - ret += "\\draw (%s cm,0) -- +(%s cm,0);\n" % ((n-2)*node_dist, node_dist) - ret += node((n-1)*node_dist, 0, label(0)) + ret += "\\draw (%s cm, %s cm) -- +(0,%s cm);\n" % (2 * node_dist, node_dist, node_dist) + ret += node(2 * node_dist, 2 * node_dist, label(0), "right=3pt") + else: # n == 8 + ret += "\\draw (%s cm,0) -- +(%s cm,0);\n" % ((n - 2) * node_dist, node_dist) + ret += node((n - 1) * node_dist, 0, label(0)) ret += node(0, 0, label(1)) - for i in range(1, n-1): - ret += node(i*node_dist, 0, label(i+2)) - ret += node(2*node_dist, node_dist, label(2), "right=3pt") + for i in range(1, n - 1): + ret += node(i * node_dist, 0, label(i + 2)) + ret += node(2 * node_dist, node_dist, label(2), "right=3pt") return ret def ascii_art(self, label=None, node=None): @@ -220,11 +222,11 @@ def ascii_art(self, label=None, node=None): return ret + self.classical().ascii_art(label, node) if n == 7: ret = " {} {}\n |\n |\n".format(node(label(2)), label(2)) - labels = [label(i) for i in [0,1,3,4,5,6,7]] + labels = [label(i) for i in [0, 1, 3, 4, 5, 6, 7]] nodes = [node(i) for i in labels] return ret + '---'.join(n for n in nodes) + '\n' + "".join("{!s:4}".format(i) for i in labels) if n == 8: ret = " {} {}\n |\n |\n".format(node(label(2)), label(2)) - labels = [label(i) for i in [1,3,4,5,6,7,8,0]] + labels = [label(i) for i in [1, 3, 4, 5, 6, 7, 8, 0]] nodes = [node(i) for i in labels] return ret + '---'.join(n for n in nodes) + '\n' + "".join("{!s:4}".format(i) for i in labels) diff --git a/src/sage/combinat/root_system/type_F.py b/src/sage/combinat/root_system/type_F.py index 9a13a2e7a23..c42ea820250 100644 --- a/src/sage/combinat/root_system/type_F.py +++ b/src/sage/combinat/root_system/type_F.py @@ -1,6 +1,7 @@ """ Root system data for type F """ + # **************************************************************************** # Copyright (C) 2008-2009 Daniel Bump # Copyright (C) 2008-2009 Justin Walker @@ -39,11 +40,8 @@ def __init__(self, root_system, base_ring): sage: TestSuite(e).run() # needs sage.graphs """ ambient_space.AmbientSpace.__init__(self, root_system, base_ring) - v = ZZ(1)/ZZ(2) - self.Base = [self.root(1,2,p2=1), - self.root(2,3,p2=1), - self.root(3), - v*(self.root(0)-self.root(1)-self.root(2)-self.root(3))] + v = ZZ(1) / ZZ(2) + self.Base = [self.root(1, 2, p2=1), self.root(2, 3, p2=1), self.root(3), v * (self.root(0) - self.root(1) - self.root(2) - self.root(3))] def dimension(self): """ @@ -71,12 +69,12 @@ def root(self, i, j=None, k=None, l=None, p1=0, p2=0, p3=0, p4=0): [(1, -1, 0, 0), (1, 0, -1, 0), (1, 0, 0, -1), (0, 1, -1, 0), (0, 1, 0, -1), (0, 0, 1, -1)] """ if i == j or j is None: - return (-1)**p1*self.monomial(i) + return (-1) ** p1 * self.monomial(i) if k is None: - return (-1)**p1*self.monomial(i) + (-1)**p2*self.monomial(j) + return (-1) ** p1 * self.monomial(i) + (-1) ** p2 * self.monomial(j) if l is None: - return (-1)**p1*self.monomial(i) + (-1)**p2*self.monomial(j)+(-1)**p3*self.monomial(k) - return (-1)**p1*self.monomial(i) + (-1)**p2*self.monomial(j)+(-1)**p3*self.monomial(k)+(-1)**p4*self.monomial(l) + return (-1) ** p1 * self.monomial(i) + (-1) ** p2 * self.monomial(j) + (-1) ** p3 * self.monomial(k) + return (-1) ** p1 * self.monomial(i) + (-1) ** p2 * self.monomial(j) + (-1) ** p3 * self.monomial(k) + (-1) ** p4 * self.monomial(l) def simple_root(self, i): r""" @@ -97,7 +95,7 @@ def simple_root(self, i): sage: e.simple_roots() Finite family {1: (0, 1, -1, 0), 2: (0, 0, 1, -1), 3: (0, 0, 0, 1), 4: (1/2, -1/2, -1/2, -1/2)} """ - return self.Base[i-1] + return self.Base[i - 1] def negative_roots(self): """ @@ -132,7 +130,7 @@ def negative_roots(self): (-1/2, 1/2, 1/2, -1/2), (-1/2, 1/2, 1/2, 1/2)] """ - return [ -a for a in self.positive_roots()] + return [-a for a in self.positive_roots()] def positive_roots(self): r""" @@ -173,12 +171,9 @@ def positive_roots(self): sage: e.rho() (11/2, 5/2, 3/2, 1/2) """ - v = ZZ(1)/ZZ(2) + v = ZZ(1) / ZZ(2) if not hasattr(self, 'PosRoots'): - self.PosRoots = ([ self.monomial(i) for i in range(self.n) ] + - [ self.root(i,j,p2=0) for i in range(self.n) for j in range(i+1,self.n) ] + - [ self.root(i,j,p2=1) for i in range(self.n) for j in range(i+1,self.n) ] + - [ v*self.root(0,1,2,3,0,p2,p3,p4) for p2 in [0,1] for p3 in [0,1] for p4 in [0,1] ]) + self.PosRoots = [self.monomial(i) for i in range(self.n)] + [self.root(i, j, p2=0) for i in range(self.n) for j in range(i + 1, self.n)] + [self.root(i, j, p2=1) for i in range(self.n) for j in range(i + 1, self.n)] + [v * self.root(0, 1, 2, 3, 0, p2, p3, p4) for p2 in [0, 1] for p3 in [0, 1] for p4 in [0, 1]] return self.PosRoots def fundamental_weights(self): @@ -191,11 +186,8 @@ def fundamental_weights(self): sage: e.fundamental_weights() Finite family {1: (1, 1, 0, 0), 2: (2, 1, 1, 0), 3: (3/2, 1/2, 1/2, 1/2), 4: (1, 0, 0, 0)} """ - v = ZZ(1)/ZZ(2) - return Family({ 1: self.monomial(0)+self.monomial(1), - 2: 2*self.monomial(0)+self.monomial(1)+self.monomial(2), - 3: v*(3*self.monomial(0)+self.monomial(1)+self.monomial(2)+self.monomial(3)), - 4: self.monomial(0)}) + v = ZZ(1) / ZZ(2) + return Family({1: self.monomial(0) + self.monomial(1), 2: 2 * self.monomial(0) + self.monomial(1) + self.monomial(2), 3: v * (3 * self.monomial(0) + self.monomial(1) + self.monomial(2) + self.monomial(3)), 4: self.monomial(0)}) from .cartan_type import CartanType_standard_finite, CartanType_simple, CartanType_crystallographic @@ -282,10 +274,11 @@ def dynkin_diagram(self): [(1, 2, 1), (2, 1, 1), (2, 3, 2), (3, 2, 1), (3, 4, 1), (4, 3, 1)] """ from .dynkin_diagram import DynkinDiagram_class + g = DynkinDiagram_class(self) for i in range(1, 4): - g.add_edge(i, i+1) - g.set_edge_label(2,3,2) + g.add_edge(i, i + 1) + g.set_edge_label(2, 3, 2) return g def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2, dual=False): @@ -313,13 +306,13 @@ def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2, dual=False): ret = "\\draw (0 cm,0) -- (%s cm,0);\n" % node_dist ret += "\\draw (%s cm, 0.1 cm) -- +(%s cm,0);\n" % (node_dist, node_dist) ret += "\\draw (%s cm, -0.1 cm) -- +(%s cm,0);\n" % (node_dist, node_dist) - ret += "\\draw (%s cm,0) -- +(%s cm,0);\n" % (node_dist*2.0, node_dist) + ret += "\\draw (%s cm,0) -- +(%s cm,0);\n" % (node_dist * 2.0, node_dist) if dual: - ret += self._latex_draw_arrow_tip(1.5*node_dist-0.2, 0, 180) + ret += self._latex_draw_arrow_tip(1.5 * node_dist - 0.2, 0, 180) else: - ret += self._latex_draw_arrow_tip(1.5*node_dist+0.2, 0, 0) + ret += self._latex_draw_arrow_tip(1.5 * node_dist + 0.2, 0, 0) for i in range(4): - ret += node(i*node_dist, 0, label(i+1)) + ret += node(i * node_dist, 0, label(i + 1)) return ret def ascii_art(self, label=None, node=None): @@ -339,9 +332,8 @@ def ascii_art(self, label=None, node=None): label = lambda i: i if node is None: node = self._ascii_art_node - ret = "{}---{}=>={}---{}\n".format(node(label(1)), node(label(2)), - node(label(3)), node(label(4))) - ret += ("{!s:4}"*4).format(label(1), label(2), label(3), label(4)) + ret = "{}---{}=>={}---{}\n".format(node(label(1)), node(label(2)), node(label(3)), node(label(4))) + ret += ("{!s:4}" * 4).format(label(1), label(2), label(3), label(4)) return ret def dual(self): @@ -377,10 +369,11 @@ def _default_folded_cartan_type(self): ['F', 4] as a folding of ['E', 6] """ from sage.combinat.root_system.type_folded import CartanTypeFolded + return CartanTypeFolded(self, ['E', 6], [[2], [4], [3, 5], [1, 6]]) # For unpickling backward compatibility (Sage <= 4.1) from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.root_system.type_F', - 'ambient_space', AmbientSpace) + +register_unpickle_override('sage.combinat.root_system.type_F', 'ambient_space', AmbientSpace) diff --git a/src/sage/combinat/root_system/type_F_affine.py b/src/sage/combinat/root_system/type_F_affine.py index 66bbeb574a0..eaef34bacab 100644 --- a/src/sage/combinat/root_system/type_F_affine.py +++ b/src/sage/combinat/root_system/type_F_affine.py @@ -1,14 +1,15 @@ """ Root system data for (untwisted) type F affine """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008-2009 Daniel Bump # Copyright (C) 2008-2009 Justin Walker # Copyright (C) 2008-2009 Nicolas M. Thiery , # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from .cartan_type import CartanType_standard_untwisted_affine @@ -64,10 +65,11 @@ def dynkin_diagram(self): (2, 3, 2), (3, 2, 1), (3, 4, 1), (4, 3, 1)] """ from .dynkin_diagram import DynkinDiagram_class + g = DynkinDiagram_class(self) for i in range(1, 4): - g.add_edge(i, i+1) - g.set_edge_label(2,3,2) + g.add_edge(i, i + 1) + g.set_edge_label(2, 3, 2) g.add_edge(0, 1) return g @@ -118,9 +120,8 @@ def ascii_art(self, label=None, node=None): label = lambda i: i if node is None: node = self._ascii_art_node - ret = "{}---{}---{}=>={}---{}\n".format(node(label(0)), node(label(1)), - node(label(2)), node(label(3)), node(label(4))) - ret += ("{!s:4}"*5 + "\n").format(label(0), label(1), label(2), label(3), label(4)) + ret = "{}---{}---{}=>={}---{}\n".format(node(label(0)), node(label(1)), node(label(2)), node(label(3)), node(label(4))) + ret += ("{!s:4}" * 5 + "\n").format(label(0), label(1), label(2), label(3), label(4)) return ret def _default_folded_cartan_type(self): @@ -133,4 +134,5 @@ def _default_folded_cartan_type(self): ['F', 4, 1] as a folding of ['E', 6, 1] """ from sage.combinat.root_system.type_folded import CartanTypeFolded + return CartanTypeFolded(self, ['E', 6, 1], [[0], [2], [4], [3, 5], [1, 6]]) diff --git a/src/sage/combinat/root_system/type_G.py b/src/sage/combinat/root_system/type_G.py index 057d8d17bd1..826da0ad4ba 100644 --- a/src/sage/combinat/root_system/type_G.py +++ b/src/sage/combinat/root_system/type_G.py @@ -1,14 +1,15 @@ """ Root system data for type G """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008-2009 Daniel Bump # Copyright (C) 2008-2009 Justin Walker # Copyright (C) 2008-2013 Nicolas M. Thiery # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from . import ambient_space from sage.sets.family import Family @@ -75,7 +76,7 @@ def simple_root(self, i): sage: CartanType(['G',2]).root_system().ambient_space().simple_roots() Finite family {1: (0, 1, -1), 2: (1, -2, 1)} """ - return self.monomial(1)-self.monomial(2) if i == 1 else self.monomial(0)-2*self.monomial(1)+self.monomial(2) + return self.monomial(1) - self.monomial(2) if i == 1 else self.monomial(0) - 2 * self.monomial(1) + self.monomial(2) def positive_roots(self): """ @@ -84,8 +85,7 @@ def positive_roots(self): sage: CartanType(['G',2]).root_system().ambient_space().positive_roots() [(0, 1, -1), (1, -2, 1), (1, -1, 0), (1, 0, -1), (1, 1, -2), (2, -1, -1)] """ - return [ self(v) for v in - [[0,1,-1],[1,-2,1],[1,-1,0],[1,0,-1],[1,1,-2],[2,-1,-1]]] + return [self(v) for v in [[0, 1, -1], [1, -2, 1], [1, -1, 0], [1, 0, -1], [1, 1, -2], [2, -1, -1]]] def negative_roots(self): """ @@ -94,8 +94,7 @@ def negative_roots(self): sage: CartanType(['G',2]).root_system().ambient_space().negative_roots() [(0, -1, 1), (-1, 2, -1), (-1, 1, 0), (-1, 0, 1), (-1, -1, 2), (-2, 1, 1)] """ - return [ self(v) for v in - [[0,-1,1],[-1,2,-1],[-1,1,0],[-1,0,1],[-1,-1,2],[-2,1,1]]] + return [self(v) for v in [[0, -1, 1], [-1, 2, -1], [-1, 1, 0], [-1, 0, 1], [-1, -1, 2], [-2, 1, 1]]] def fundamental_weights(self): """ @@ -104,8 +103,7 @@ def fundamental_weights(self): sage: CartanType(['G',2]).root_system().ambient_space().fundamental_weights() Finite family {1: (1, 0, -1), 2: (2, -1, -1)} """ - return Family({ 1: self([1,0,-1]), - 2: self([2,-1,-1])}) + return Family({1: self([1, 0, -1]), 2: self([2, -1, -1])}) _plot_projection = RootLatticeRealizations.ParentMethods.__dict__['_plot_projection_barycentric'] @@ -195,9 +193,10 @@ def dynkin_diagram(self): [(1, 2, 1), (2, 1, 3)] """ from .dynkin_diagram import DynkinDiagram_class + g = DynkinDiagram_class(self) - g.add_edge(1,2) - g.set_edge_label(2,1,3) + g.add_edge(1, 2) + g.set_edge_label(2, 1, 3) return g def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2, dual=False): @@ -223,9 +222,9 @@ def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2, dual=False): ret += "\\draw (0, 0.15 cm) -- +(%s cm,0);\n" % node_dist ret += "\\draw (0, -0.15 cm) -- +(%s cm,0);\n" % node_dist if dual: - ret += self._latex_draw_arrow_tip(0.5*node_dist+0.2, 0, 0) + ret += self._latex_draw_arrow_tip(0.5 * node_dist + 0.2, 0, 0) else: - ret += self._latex_draw_arrow_tip(0.5*node_dist-0.2, 0, 180) + ret += self._latex_draw_arrow_tip(0.5 * node_dist - 0.2, 0, 180) ret += node(0, 0, label(1)) ret += node(node_dist, 0, label(2)) return ret @@ -283,10 +282,11 @@ def _default_folded_cartan_type(self): ['G', 2] as a folding of ['D', 4] """ from sage.combinat.root_system.type_folded import CartanTypeFolded + return CartanTypeFolded(self, ['D', 4], [[1, 3, 4], [2]]) # For unpickling backward compatibility (Sage <= 4.1) from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.root_system.type_G', - 'ambient_space', AmbientSpace) + +register_unpickle_override('sage.combinat.root_system.type_G', 'ambient_space', AmbientSpace) diff --git a/src/sage/combinat/root_system/type_G_affine.py b/src/sage/combinat/root_system/type_G_affine.py index 0cc4f0dc4d7..534757e5055 100644 --- a/src/sage/combinat/root_system/type_G_affine.py +++ b/src/sage/combinat/root_system/type_G_affine.py @@ -1,14 +1,15 @@ """ Root system data for (untwisted) type G affine """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008-2009 Daniel Bump # Copyright (C) 2008-2009 Justin Walker # Copyright (C) 2008-2009 Nicolas M. Thiery , # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from .cartan_type import CartanType_standard_untwisted_affine @@ -47,7 +48,7 @@ def __init__(self): sage: TestSuite(ct).run() """ - CartanType_standard_untwisted_affine.__init__(self, "G",2) + CartanType_standard_untwisted_affine.__init__(self, "G", 2) def dynkin_diagram(self): """ @@ -64,9 +65,10 @@ def dynkin_diagram(self): [(0, 2, 1), (1, 2, 1), (2, 0, 1), (2, 1, 3)] """ from .dynkin_diagram import DynkinDiagram_class + g = DynkinDiagram_class(self) g.add_edge(1, 2) - g.set_edge_label(2,1,3) + g.set_edge_label(2, 1, 3) g.add_edge(0, 2) return g @@ -93,11 +95,11 @@ def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2, dual=False): label = lambda x: x if node is None: node = self._latex_draw_node - ret = "\\draw (%s cm,0) -- (%s cm,0);\n" % (node_dist, node_dist*2.0) + ret = "\\draw (%s cm,0) -- (%s cm,0);\n" % (node_dist, node_dist * 2.0) ret += "\\draw (0, 0.15 cm) -- +(%s cm,0);\n" % node_dist ret += "\\draw (0, -0.15 cm) -- +(%s cm,0);\n" % node_dist ret += self.classical()._latex_dynkin_diagram(label, node, node_dist, dual) - ret += node(2*node_dist, 0, label(0)) + ret += node(2 * node_dist, 0, label(0)) return ret def ascii_art(self, label=None, node=None): @@ -128,4 +130,5 @@ def _default_folded_cartan_type(self): ['G', 2, 1] as a folding of ['D', 4, 1] """ from sage.combinat.root_system.type_folded import CartanTypeFolded + return CartanTypeFolded(self, ['D', 4, 1], [[0], [1, 3, 4], [2]]) diff --git a/src/sage/combinat/root_system/type_H.py b/src/sage/combinat/root_system/type_H.py index 5a7c12c1b69..bd87bc6234b 100644 --- a/src/sage/combinat/root_system/type_H.py +++ b/src/sage/combinat/root_system/type_H.py @@ -1,12 +1,13 @@ """ Root system data for type H """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008-2009 Nicolas M. Thiery , # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from .cartan_type import CartanType_standard_finite, CartanType_simple @@ -81,11 +82,12 @@ def coxeter_diagram(self): [2 2 5 1] """ from sage.graphs.graph import Graph + n = self.n g = Graph(multiedges=False) for i in range(1, n): - g.add_edge(i, i+1, 3) - g.set_edge_label(n-1, n, 5) + g.add_edge(i, i + 1, 3) + g.set_edge_label(n - 1, n, 5) return g def coxeter_number(self): diff --git a/src/sage/combinat/root_system/type_I.py b/src/sage/combinat/root_system/type_I.py index 8f67bd07ee5..50dd6b2227b 100644 --- a/src/sage/combinat/root_system/type_I.py +++ b/src/sage/combinat/root_system/type_I.py @@ -1,12 +1,13 @@ """ Root system data for type I """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008-2009 Nicolas M. Thiery , # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from .cartan_type import CartanType_standard_finite, CartanType_simple @@ -93,7 +94,8 @@ def coxeter_diagram(self): [4 1] """ from sage.graphs.graph import Graph - return Graph([[1,2,self.n]], multiedges=False) + + return Graph([[1, 2, self.n]], multiedges=False) def coxeter_number(self): """ diff --git a/src/sage/combinat/root_system/type_Q.py b/src/sage/combinat/root_system/type_Q.py index 3e0e33b1399..f368079d59b 100644 --- a/src/sage/combinat/root_system/type_Q.py +++ b/src/sage/combinat/root_system/type_Q.py @@ -1,13 +1,14 @@ """ Root system data for type Q """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2018 Wencin Poh # Copyright (C) 2018 Anne Schilling # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from .cartan_type import CartanType_standard_finite @@ -47,7 +48,7 @@ def __init__(self, m): sage: TestSuite(ct).run() """ assert m >= 2 - CartanType_standard_finite.__init__(self, "Q", m-1) + CartanType_standard_finite.__init__(self, "Q", m - 1) def _repr_(self, compact=False): """ @@ -60,7 +61,7 @@ def _repr_(self, compact=False): 'Q4' """ format = '%s%s' if compact else "['%s', %s]" - return format % (self.letter, self.n+1) + return format % (self.letter, self.n + 1) def __reduce__(self): """ @@ -73,7 +74,8 @@ def __reduce__(self): True """ from .cartan_type import CartanType - return (CartanType, (self.letter, self.n+1)) + + return (CartanType, (self.letter, self.n + 1)) def index_set(self): r""" @@ -110,7 +112,7 @@ def root_system(self): sage: Q.root_system() Root system of type ['A', 2] """ - return RootSystem(['A',self.n]) + return RootSystem(['A', self.n]) def is_irreducible(self): """ diff --git a/src/sage/combinat/root_system/type_affine.py b/src/sage/combinat/root_system/type_affine.py index 47a4b266f2f..7ff28104e5e 100644 --- a/src/sage/combinat/root_system/type_affine.py +++ b/src/sage/combinat/root_system/type_affine.py @@ -1,12 +1,13 @@ """ Root system data for affine Cartan types """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2013 Nicolas M. Thiery , # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.cachefunc import cached_method from sage.combinat.free_module import CombinatorialFreeModule @@ -111,6 +112,7 @@ class AmbientSpace(CombinatorialFreeModule): sage: Lambda[1] # needs sage.graphs e[0] + e['deltacheck'] """ + @classmethod def smallest_base_ring(cls, cartan_type): r""" @@ -156,13 +158,9 @@ def __init__(self, root_system, base_ring): def sortkey(x): return (1 if isinstance(x, str) else 0, x) - CombinatorialFreeModule.__init__(self, base_ring, - basis_keys, - prefix='e', - latex_prefix='e', - sorting_key=sortkey, - category=WeightLatticeRealizations(base_ring)) - self._weight_space = self.root_system.weight_space(base_ring=base_ring,extended=True) + + CombinatorialFreeModule.__init__(self, base_ring, basis_keys, prefix='e', latex_prefix='e', sorting_key=sortkey, category=WeightLatticeRealizations(base_ring)) + self._weight_space = self.root_system.weight_space(base_ring=base_ring, extended=True) self.classical().module_morphism(self.monomial, codomain=self).register_as_coercion() # Duplicated from ambient_space.AmbientSpace coroot_lattice = self.root_system.coroot_lattice() @@ -439,10 +437,10 @@ def _plot_projection(self, x): (0, 0, 1) """ from sage.modules.free_module_element import vector + classical = self.classical() # Any better way to concatenate two vectors? - return vector(list(vector(classical._plot_projection(classical(x)))) + - [x["deltacheck"]]) + return vector(list(vector(classical._plot_projection(classical(x)))) + [x["deltacheck"]]) class Element(CombinatorialFreeModule.Element): @@ -474,7 +472,7 @@ def inner_product(self, other): """ if self.parent() is not other.parent(): raise TypeError("the parents must be the same") - return self.base_ring().sum( self[i] * c for (i,c) in other ) + return self.base_ring().sum(self[i] * c for (i, c) in other) scalar = inner_product @@ -503,4 +501,4 @@ def associated_coroot(self): L = self.parent() c = self["delta"] self = self - L.term("delta", c) - return (2*self) / self.inner_product(self) + L.term("deltacheck", c) + return (2 * self) / self.inner_product(self) + L.term("deltacheck", c) diff --git a/src/sage/combinat/root_system/type_dual.py b/src/sage/combinat/root_system/type_dual.py index 85dc78e7ba2..1514bcf1d21 100644 --- a/src/sage/combinat/root_system/type_dual.py +++ b/src/sage/combinat/root_system/type_dual.py @@ -1,6 +1,7 @@ """ Root system data for dual Cartan types """ + # **************************************************************************** # Copyright (C) 2008-2009 Anne Schilling # Copyright (C) 2008-2013 Nicolas M. Thiery @@ -151,17 +152,14 @@ def __init__(self, type): self.__class__ = CartanType_finite elif type.is_affine(): self.__class__ = CartanType_affine - abstract_classes = tuple(cls - for cls in self._stable_abstract_classes - if isinstance(type, cls)) + abstract_classes = tuple(cls for cls in self._stable_abstract_classes if isinstance(type, cls)) if abstract_classes: self._add_abstract_superclass(abstract_classes) # For each class cls in _stable_abstract_classes, if ct is an # instance of A then ct.relabel(...) is put in this class as well. # The order is relevant to avoid MRO issues! - _stable_abstract_classes = [ - cartan_type.CartanType_simple] + _stable_abstract_classes = [cartan_type.CartanType_simple] def _repr_(self, compact=False): """ @@ -177,8 +175,8 @@ def _repr_(self, compact=False): if self.is_affine() and self.options.notation == "Kac": if self._type.type() == 'B': if compact: - return 'A%s^2' % (self.classical().rank()*2-1) - return "['A', %s, 2]" % (self.classical().rank()*2-1) + return 'A%s^2' % (self.classical().rank() * 2 - 1) + return "['A', %s, 2]" % (self.classical().rank() * 2 - 1) if self._type.type() == 'BC': dual_str = '+' elif self._type.type() == 'C': @@ -189,7 +187,7 @@ def _repr_(self, compact=False): if compact: return 'E6^2' return "['E', 6, 2]" - return self.dual()._repr_(compact)+(dual_str if compact else "^"+dual_str) + return self.dual()._repr_(compact) + (dual_str if compact else "^" + dual_str) def _latex_(self): r""" @@ -198,7 +196,7 @@ def _latex_(self): sage: latex(CartanType(['F', 4, 1]).dual()) F_4^{(1)\vee} """ - return self._type._latex_()+"^"+self.options.dual_latex + return self._type._latex_() + "^" + self.options.dual_latex def __reduce__(self): """ @@ -349,6 +347,7 @@ def dynkin_diagram(self): """ return self._type.dynkin_diagram().dual() + ########################################################################### @@ -408,7 +407,7 @@ def _dual_space(self): """ K = self.base_ring() return self.cartan_type().dual().root_system().ambient_space(K) - #return self.root_system.dual.ambient_space() + # return self.root_system.dual.ambient_space() def dimension(self): """ @@ -521,6 +520,7 @@ def _plot_projection(self): class CartanType_finite(CartanType, cartan_type.CartanType_finite): AmbientSpace = AmbientSpace + ########################################################################### @@ -562,12 +562,13 @@ def basic_untwisted(self): ['D', 4] """ from . import cartan_type + if self.dual().type() == 'B': - return cartan_type.CartanType(['A', self.classical().rank()*2-1]) + return cartan_type.CartanType(['A', self.classical().rank() * 2 - 1]) if self.dual().type() == 'BC': - return cartan_type.CartanType(['A', self.classical().rank()*2]) + return cartan_type.CartanType(['A', self.classical().rank() * 2]) if self.dual().type() == 'C': - return cartan_type.CartanType(['D', self.classical().rank()+1]) + return cartan_type.CartanType(['D', self.classical().rank() + 1]) if self.dual().type() == 'F': return cartan_type.CartanType(['E', 6]) if self.dual().type() == 'G': @@ -606,8 +607,8 @@ def _repr_(self, compact=False): if self.options.notation == "Kac": if self._type.type() == 'B': if compact: - return 'A%s^2' % (self.classical().rank()*2-1) - return "['A', %s, 2]" % (self.classical().rank()*2-1) + return 'A%s^2' % (self.classical().rank() * 2 - 1) + return "['A', %s, 2]" % (self.classical().rank() * 2 - 1) if self._type.type() == 'BC': pass elif self._type.type() == 'C': @@ -650,15 +651,16 @@ def _latex_(self): """ if self.options('notation') == "Kac": if self._type.type() == 'B': - return "A_{%s}^{(2)}" % (self.classical().rank()*2-1) + return "A_{%s}^{(2)}" % (self.classical().rank() * 2 - 1) if self._type.type() == 'BC': - return "A_{%s}^{(2)\\dagger}" % (2*self.classical().rank()) + return "A_{%s}^{(2)\\dagger}" % (2 * self.classical().rank()) if self._type.type() == 'C': return "D_{%s}^{(2)}" % (self.rank)() if self._type.type() == 'F': return "E_6^{(2)}" result = self._type._latex_() import re + if re.match(r".*\^{\(\d\)}$", result): return "%s%s}" % (result[:-1], self.options('dual_latex')) return "{%s}^%s" % (result, self.options('dual_latex')) @@ -681,19 +683,17 @@ def _default_folded_cartan_type(self): ['G', 2, 1]^* as a folding of ['D', 4, 1] """ from sage.combinat.root_system.type_folded import CartanTypeFolded + letter = self._type.type() if letter == 'BC': # A_{2n}^{(2)\dagger} n = self._type.classical().rank() - return CartanTypeFolded(self, ['A', 2*n - 1, 1], - [[0]] + [[i, 2*n-i] for i in range(1, n)] + [[n]]) + return CartanTypeFolded(self, ['A', 2 * n - 1, 1], [[0]] + [[i, 2 * n - i] for i in range(1, n)] + [[n]]) if letter == 'B': # A_{2n-1}^{(2)} n = self._type.classical().rank() - return CartanTypeFolded(self, ['D', n + 1, 1], - [[i] for i in range(n)] + [[n, n+1]]) + return CartanTypeFolded(self, ['D', n + 1, 1], [[i] for i in range(n)] + [[n, n + 1]]) if letter == 'C': # D_{n+1}^{(2)} n = self._type.classical().rank() - return CartanTypeFolded(self, ['A', 2*n-1, 1], - [[0]] + [[i, 2*n-i] for i in range(1, n)] + [[n]]) + return CartanTypeFolded(self, ['A', 2 * n - 1, 1], [[0]] + [[i, 2 * n - i] for i in range(1, n)] + [[n]]) if letter == 'F': # E_6^{(2)} return CartanTypeFolded(self, ['E', 6, 1], [[0], [2], [4], [3, 5], [1, 6]]) if letter == 'G': # D_4^{(3)} diff --git a/src/sage/combinat/root_system/type_folded.py b/src/sage/combinat/root_system/type_folded.py index 63880594642..a47bbc12fba 100644 --- a/src/sage/combinat/root_system/type_folded.py +++ b/src/sage/combinat/root_system/type_folded.py @@ -5,13 +5,14 @@ - Travis Scrimshaw (2013-01-12) - Initial version """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2013 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.cachefunc import cached_method from sage.structure.sage_object import SageObject @@ -156,6 +157,7 @@ class CartanTypeFolded(UniqueRepresentation, SageObject): `A_{2n}^{(2)}`, and `C_n^{(1)}`". Representation Theory. **7** (2003). 101-163. :doi:`10.1.1.192.2095`, :arxiv:`0810.5067`. """ + @staticmethod def __classcall_private__(cls, cartan_type, virtual, orbit): """ @@ -260,8 +262,7 @@ def folding_orbit(self): sage: fct.folding_orbit() Finite family {0: (0,), 1: (1, 7), 2: (2, 6), 3: (3, 5), 4: (4,)} """ - return Family({i:tuple(self._orbit[pos]) - for pos,i in enumerate(self._cartan_type.index_set())}) + return Family({i: tuple(self._orbit[pos]) for pos, i in enumerate(self._cartan_type.index_set())}) @cached_method def scaling_factors(self): @@ -290,11 +291,11 @@ def f(i): root = L.simple_root(i) coroot = L.simple_coroot(i) return root.leading_coefficient() / coroot.leading_coefficient() + index_set = self._cartan_type.index_set() min_f = min(f(j) for j in index_set) return Family({i: int(f(i) / min_f) for i in index_set}) if self._cartan_type.is_affine(): c = self._cartan_type.translation_factors() cmax = max(c) - return Family({i: int(cmax / c[i]) - for i in self._cartan_type.index_set()}) + return Family({i: int(cmax / c[i]) for i in self._cartan_type.index_set()}) diff --git a/src/sage/combinat/root_system/type_marked.py b/src/sage/combinat/root_system/type_marked.py index 72217a9710a..082ad68f834 100644 --- a/src/sage/combinat/root_system/type_marked.py +++ b/src/sage/combinat/root_system/type_marked.py @@ -1,12 +1,13 @@ """ Root system data for Cartan types with marked nodes """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2014 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.combinat.root_system import ambient_space, cartan_type from sage.combinat.root_system.root_lattice_realizations import RootLatticeRealizations @@ -58,6 +59,7 @@ class CartanType(cartan_type.CartanType_decorator): 1 2 3 4 B4 """ + @staticmethod def __classcall__(cls, ct, marked_nodes): """ @@ -131,21 +133,14 @@ def __init__(self, ct, marked_nodes): self.__class__ = CartanType_finite elif ct.is_affine(): self.__class__ = CartanType_affine - abstract_classes = tuple(cls - for cls in self._stable_abstract_classes - if isinstance(ct, cls)) + abstract_classes = tuple(cls for cls in self._stable_abstract_classes if isinstance(ct, cls)) if abstract_classes: self._add_abstract_superclass(abstract_classes) # For each class cls in _stable_abstract_classes, if ct is an # instance of A then ct.relabel(...) is put in this class as well. # The order is relevant to avoid MRO issues! - _stable_abstract_classes = [ - cartan_type.CartanType_finite, - cartan_type.CartanType_affine, - cartan_type.CartanType_simple, - cartan_type.CartanType_simply_laced, - cartan_type.CartanType_crystallographic] + _stable_abstract_classes = [cartan_type.CartanType_finite, cartan_type.CartanType_affine, cartan_type.CartanType_simple, cartan_type.CartanType_simply_laced, cartan_type.CartanType_crystallographic] def _repr_(self, compact=False): """ @@ -432,6 +427,7 @@ def _default_folded_cartan_type(self): Finite family {0: 1, 1: 2, 2: 2, 3: 1} """ from sage.combinat.root_system.type_folded import CartanTypeFolded + vct = self._type._default_folded_cartan_type() sigma = vct.folding_orbit() marked_nodes = sum([sigma[i] for i in self._marked_nodes], ()) @@ -450,6 +446,7 @@ def type(self): """ return self._type.type() + ########################################################################### @@ -466,6 +463,7 @@ class AmbientSpace(ambient_space.AmbientSpace): Ambient space of the Root system of type ['F', 4] with nodes (1, 3) marked sage: TestSuite(L).run() # needs sage.graphs """ + @lazy_attribute def _space(self): """ @@ -556,6 +554,7 @@ def _plot_projection(self): return self._plot_projection_barycentric RootLatticeRealizations.ParentMethods.__dict__["_plot_projection"] + ########################################################################### @@ -594,6 +593,7 @@ def affine(self): """ return self._type.affine().marked_nodes(self._marked_nodes) + ########################################################################### @@ -630,8 +630,7 @@ def _latex_draw_node(self, x, y, label, position='below=4pt'): sage: CartanType.options._reset() """ - mark_special = (label == self.special_node() - and self.options('mark_special_node') in ['latex', 'both']) + mark_special = label == self.special_node() and self.options('mark_special_node') in ['latex', 'both'] if mark_special: fill = 'black' else: @@ -659,8 +658,7 @@ def _ascii_art_node(self, label): sage: CartanType.options._reset() """ if label in self._marked_nodes: - if (label == self.special_node() - and self.options('mark_special_node') in ['printing', 'both']): + if label == self.special_node() and self.options('mark_special_node') in ['printing', 'both']: return '#' return self.options('marked_node_str') return 'O' diff --git a/src/sage/combinat/root_system/type_reducible.py b/src/sage/combinat/root_system/type_reducible.py index b58b828d8d5..4079ca9e05a 100644 --- a/src/sage/combinat/root_system/type_reducible.py +++ b/src/sage/combinat/root_system/type_reducible.py @@ -1,6 +1,7 @@ """ Root system data for reducible Cartan types """ + # **************************************************************************** # Copyright (C) 2008-2009 Daniel Bump # Copyright (C) 2008-2009 Justin Walker @@ -116,24 +117,18 @@ def __init__(self, types): """ self._types = types self.affine = False - indices = (None,) + tuple((i, j) - for i in range(len(types)) - for j in types[i].index_set()) + indices = (None,) + tuple((i, j) for i in range(len(types)) for j in types[i].index_set()) self._indices = indices - self._index_relabelling = {indices[i]: i - for i in range(1, len(indices))} + self._index_relabelling = {indices[i]: i for i in range(1, len(indices))} self._spaces = [t.root_system().ambient_space() for t in types] if all(l is not None for l in self._spaces): - self._shifts = [sum(l.dimension() for l in self._spaces[:k]) - for k in range(len(types)+1)] + self._shifts = [sum(l.dimension() for l in self._spaces[:k]) for k in range(len(types) + 1)] self.tools = root_system.type_reducible # a direct product of finite Cartan types is again finite; # idem for simply laced and crystallographic. - super_classes = tuple(cls - for cls in (CartanType_finite, CartanType_simply_laced, CartanType_crystallographic) - if all(isinstance(t, cls) for t in types)) + super_classes = tuple(cls for cls in (CartanType_finite, CartanType_simply_laced, CartanType_crystallographic) if all(isinstance(t, cls) for t in types)) self._add_abstract_superclass(super_classes) def _repr_(self, compact=True): # We should make a consistent choice here @@ -245,7 +240,7 @@ def index_set(self): sage: CartanType("A2","A1").index_set() (1, 2, 3) """ - return tuple(range(1, self.rank()+1)) + return tuple(range(1, self.rank() + 1)) def cartan_matrix(self, subdivide=True): """ @@ -272,8 +267,8 @@ def cartan_matrix(self, subdivide=True): True """ from sage.combinat.root_system.cartan_matrix import CartanMatrix - return CartanMatrix(block_diagonal_matrix([t.cartan_matrix() for t in self._types], subdivide=subdivide), - cartan_type=self, index_set=self.index_set()) + + return CartanMatrix(block_diagonal_matrix([t.cartan_matrix() for t in self._types], subdivide=subdivide), cartan_type=self, index_set=self.index_set()) def dynkin_diagram(self): """ @@ -301,11 +296,12 @@ def dynkin_diagram(self): F4xA2 """ from .dynkin_diagram import DynkinDiagram_class + relabelling = self._index_relabelling g = DynkinDiagram_class(self) for i in range(len(self._types)): for [e1, e2, l] in self._types[i].dynkin_diagram().edges(sort=True): - g.add_edge(relabelling[i,e1], relabelling[i,e2], label=l) + g.add_edge(relabelling[i, e1], relabelling[i, e2], label=l) return g def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2): @@ -337,9 +333,7 @@ def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2): types = self.component_types() relabelling = self._index_relabelling ret = "{\n" - ret += "\\pgftransformyshift{-3 cm}\n".join(types[i]._latex_dynkin_diagram( - lambda x: label(relabelling[i,x]), node, node_dist=node_dist) - for i in range(len(types))) + ret += "\\pgftransformyshift{-3 cm}\n".join(types[i]._latex_dynkin_diagram(lambda x: label(relabelling[i, x]), node, node_dist=node_dist) for i in range(len(types))) ret += "}" return ret @@ -373,8 +367,7 @@ def ascii_art(self, label=None, node=None): label = lambda i: i types = self.component_types() relabelling = self._index_relabelling - return "\n".join(types[i].ascii_art(lambda x: label(relabelling[i,x]), node) - for i in range(len(types))) + return "\n".join(types[i].ascii_art(lambda x: label(relabelling[i, x]), node) for i in range(len(types))) @cached_method def is_finite(self): @@ -450,12 +443,13 @@ def coxeter_diagram(self): [(2, 3, 3), (3, 4, 5)] """ from sage.graphs.graph import Graph + relabelling = self._index_relabelling g = Graph(multiedges=False) g.add_vertices(self.index_set()) - for i,t in enumerate(self._types): + for i, t in enumerate(self._types): for [e1, e2, l] in t.coxeter_diagram().edges(sort=True): - g.add_edge(relabelling[i,e1], relabelling[i,e2], label=l) + g.add_edge(relabelling[i, e1], relabelling[i, e2], label=l) return g @@ -569,8 +563,7 @@ def positive_roots(self) -> list: """ res = [] for i, ambient_sp in enumerate(self.ambient_spaces()): - res.extend(self.inject_weights(i, v) - for v in ambient_sp.positive_roots()) + res.extend(self.inject_weights(i, v) for v in ambient_sp.positive_roots()) return res def negative_roots(self) -> list: @@ -582,8 +575,7 @@ def negative_roots(self) -> list: """ ret = [] for i, ambient_sp in enumerate(self.ambient_spaces()): - ret.extend(self.inject_weights(i, v) - for v in ambient_sp.negative_roots()) + ret.extend(self.inject_weights(i, v) for v in ambient_sp.negative_roots()) return ret def fundamental_weights(self): @@ -595,8 +587,7 @@ def fundamental_weights(self): """ fw = [] for i, ambient_sp in enumerate(self.ambient_spaces()): - fw.extend(self.inject_weights(i, v) - for v in ambient_sp.fundamental_weights()) + fw.extend(self.inject_weights(i, v) for v in ambient_sp.fundamental_weights()) return Family({i: fw[i - 1] for i in range(1, len(fw) + 1)}) diff --git a/src/sage/combinat/root_system/type_relabel.py b/src/sage/combinat/root_system/type_relabel.py index 952c0cf4259..83648069e12 100644 --- a/src/sage/combinat/root_system/type_relabel.py +++ b/src/sage/combinat/root_system/type_relabel.py @@ -1,12 +1,13 @@ """ Root system data for relabelled Cartan types """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008-2013 Nicolas M. Thiery , # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.combinat.root_system import ambient_space, cartan_type from sage.combinat.root_system.root_lattice_realizations import RootLatticeRealizations @@ -20,6 +21,7 @@ class CartanType(cartan_type.CartanType_decorator): r""" A class for relabelled Cartan types. """ + @staticmethod def __classcall__(cls, type, relabelling): """ @@ -46,15 +48,14 @@ def __classcall__(cls, type, relabelling): else: relabelling = {i: relabelling(i) for i in type.index_set()} - if isinstance(type, CartanType): # type is already a relabelled type - relabelling = {i: relabelling[type._relabelling[i]] - for i in type._type.index_set()} + if isinstance(type, CartanType): # type is already a relabelled type + relabelling = {i: relabelling[type._relabelling[i]] for i in type._type.index_set()} type = type._type - if all( relabelling[i] == i for i in type.index_set() ): + if all(relabelling[i] == i for i in type.index_set()): return type - relabelling = FiniteFamily(relabelling) # Hack to emulate a frozendict which would be hashable!!!! + relabelling = FiniteFamily(relabelling) # Hack to emulate a frozendict which would be hashable!!!! return super().__classcall__(cls, type, relabelling) def __init__(self, type, relabelling): @@ -181,8 +182,7 @@ def __init__(self, type, relabelling): # TODO: design an appropriate infrastructure to handle this # automatically? Maybe using categories and axioms? # See also type_dual.CartanType.__init__ - if type.is_finite() and (isinstance(type, cartan_type.SuperCartanType_standard) - or type.is_crystallographic()): + if type.is_finite() and (isinstance(type, cartan_type.SuperCartanType_standard) or type.is_crystallographic()): # FIXME: Remove the is_crystallographic (and the short-circuiting # super) check once the non-crystallographic finite types # (i.e., H_3, H_4, I_2(p)) have an implementation of an @@ -190,21 +190,14 @@ def __init__(self, type, relabelling): self.__class__ = CartanType_finite elif type.is_affine(): self.__class__ = CartanType_affine - abstract_classes = tuple(cls - for cls in self._stable_abstract_classes - if isinstance(type, cls)) + abstract_classes = tuple(cls for cls in self._stable_abstract_classes if isinstance(type, cls)) if abstract_classes: self._add_abstract_superclass(abstract_classes) # For each class cls in _stable_abstract_classes, if ct is an # instance of A then ct.relabel(...) is put in this class as well. # The order is relevant to avoid MRO issues! - _stable_abstract_classes = [ - cartan_type.CartanType_finite, - cartan_type.CartanType_affine, - cartan_type.CartanType_simple, - cartan_type.CartanType_simply_laced, - cartan_type.CartanType_crystallographic] + _stable_abstract_classes = [cartan_type.CartanType_finite, cartan_type.CartanType_affine, cartan_type.CartanType_simple, cartan_type.CartanType_simply_laced, cartan_type.CartanType_crystallographic] def _repr_(self, compact=False): """ @@ -222,9 +215,9 @@ def _repr_(self, compact=False): Coxeter type of ['I', 5] relabelled by {1: 0, 2: 1} """ from pprint import pformat + # Special case for type D_4^3 - if (self._type.is_affine() and self._type.dual().type() == 'G' - and self.options("notation") == "Kac"): + if self._type.is_affine() and self._type.dual().type() == 'G' and self.options("notation") == "Kac": if compact: return 'D4^3' return "['D', 4, 3]" @@ -262,8 +255,7 @@ def _latex_(self): I_2(5) \text{ relabelled by } \left\{1 : 0, 2 : 1\right\} """ # Special case for type D_4^{(3)} - if (self._type.is_affine() and self._type.dual().type() == 'G' - and self.options("notation") == "Kac"): + if self._type.is_affine() and self._type.dual().type() == 'G' and self.options("notation") == "Kac": return 'D_4^{(3)}' ret = self._type._latex_() if self.options('latex_relabel'): @@ -391,10 +383,10 @@ def _default_folded_cartan_type(self): Finite family {0: 1, 1: 2, 2: 2, 3: 1} """ from sage.combinat.root_system.type_folded import CartanTypeFolded + vct = self._type._default_folded_cartan_type() sigma = vct.folding_orbit() - return CartanTypeFolded(self, vct._folding, - {self._relabelling[i]: sigma[i] for i in self._type.index_set()}) + return CartanTypeFolded(self, vct._folding, {self._relabelling[i]: sigma[i] for i in self._type.index_set()}) def type(self): """ @@ -423,6 +415,7 @@ def coxeter_diagram(self): """ return self._type.coxeter_diagram().relabel(self._relabelling, inplace=False, immutable=True) + ########################################################################### @@ -623,6 +616,7 @@ def affine(self): break return self._type.affine().relabel(relabelling) + ########################################################################### diff --git a/src/sage/combinat/root_system/type_super_A.py b/src/sage/combinat/root_system/type_super_A.py index 290c98c08d5..44c0e81cef4 100644 --- a/src/sage/combinat/root_system/type_super_A.py +++ b/src/sage/combinat/root_system/type_super_A.py @@ -1,6 +1,7 @@ """ Root system data for super type A """ + # **************************************************************************** # Copyright (C) 2017 Travis Scrimshaw # @@ -47,10 +48,8 @@ def __init__(self, root_system, base_ring, index_set=None): """ ct = root_system.cartan_type() if index_set is None: - index_set = tuple(list(range(-ct.m - 1, 0)) + - list(range(1, ct.n + 2))) - ambient_space.AmbientSpace.__init__(self, root_system, base_ring, - index_set=index_set) + index_set = tuple(list(range(-ct.m - 1, 0)) + list(range(1, ct.n + 2))) + ambient_space.AmbientSpace.__init__(self, root_system, base_ring, index_set=index_set) @classmethod def smallest_base_ring(cls, cartan_type=None): @@ -94,10 +93,10 @@ def simple_root(self, i): (0, 0, 1, -1, 0), (0, 0, 0, 1, -1)] """ if i < 0: - return self.monomial(i-1) - self.monomial(i) + return self.monomial(i - 1) - self.monomial(i) if i == 0: return self.monomial(-1) - self.monomial(1) - return self.monomial(i) - self.monomial(i+1) + return self.monomial(i) - self.monomial(i + 1) def positive_roots(self): """ @@ -133,12 +132,8 @@ def positive_even_roots(self): """ ct = self.root_system.cartan_type() ret = [] - ret += [self.monomial(-j) - self.monomial(-i) - for i in range(1, ct.m + 2) - for j in range(i + 1, ct.m + 2)] - ret += [self.monomial(i) - self.monomial(j) - for i in range(1, ct.n + 2) - for j in range(i + 1, ct.n + 2)] + ret += [self.monomial(-j) - self.monomial(-i) for i in range(1, ct.m + 2) for j in range(i + 1, ct.m + 2)] + ret += [self.monomial(i) - self.monomial(j) for i in range(1, ct.n + 2) for j in range(i + 1, ct.n + 2)] return ret def positive_odd_roots(self): @@ -157,9 +152,7 @@ def positive_odd_roots(self): (1, 0, 0, 0, -1)] """ ct = self.root_system.cartan_type() - return [self.monomial(-i) - self.monomial(j) - for i in range(1, ct.m + 2) - for j in range(1, ct.n + 2)] + return [self.monomial(-i) - self.monomial(j) for i in range(1, ct.m + 2) for j in range(1, ct.n + 2)] def highest_root(self): """ @@ -172,7 +165,7 @@ def highest_root(self): (1, 0, 0, 0, 0, 0, 0, -1) """ ct = self.root_system.cartan_type() - return self.monomial(-ct.m-1) - self.monomial(ct.n+1) + return self.monomial(-ct.m - 1) - self.monomial(ct.n + 1) def negative_roots(self): """ @@ -208,12 +201,8 @@ def negative_even_roots(self): """ ct = self.root_system.cartan_type() ret = [] - ret += [self.monomial(-i) - self.monomial(-j) - for i in range(1, ct.m + 2) - for j in range(i + 1, ct.m + 2)] - ret += [self.monomial(j) - self.monomial(i) - for i in range(1, ct.n + 2) - for j in range(i + 1, ct.n + 2)] + ret += [self.monomial(-i) - self.monomial(-j) for i in range(1, ct.m + 2) for j in range(i + 1, ct.m + 2)] + ret += [self.monomial(j) - self.monomial(i) for i in range(1, ct.n + 2) for j in range(i + 1, ct.n + 2)] return ret def negative_odd_roots(self): @@ -232,9 +221,7 @@ def negative_odd_roots(self): (-1, 0, 0, 0, 1)] """ ct = self.root_system.cartan_type() - return [self.monomial(j) - self.monomial(-i) - for i in range(1, ct.m + 2) - for j in range(1, ct.n + 2)] + return [self.monomial(j) - self.monomial(-i) for i in range(1, ct.m + 2) for j in range(1, ct.n + 2)] def fundamental_weight(self, i): r""" @@ -274,10 +261,8 @@ def fundamental_weight(self, i): m = self.root_system.cartan_type().m n = self.root_system.cartan_type().n if i <= 0: - return self.sum(self.monomial(j) for j in range(-m-1,i)) - return (self.sum(self.monomial(j) for j in range(-m-1,1)) - - self.sum(self.monomial(j) for j in range(i+1)) - - 2*self.sum(self.monomial(j) for j in range(i+1,n+2))) + return self.sum(self.monomial(j) for j in range(-m - 1, i)) + return self.sum(self.monomial(j) for j in range(-m - 1, 1)) - self.sum(self.monomial(j) for j in range(i + 1)) - 2 * self.sum(self.monomial(j) for j in range(i + 1, n + 2)) def simple_coroot(self, i): """ @@ -324,13 +309,13 @@ def inner_product(self, lambdacheck): lambdacheck_mc = lambdacheck._monomial_coefficients result = self.parent().base_ring().zero() - for t,c in lambdacheck_mc.items(): + for t, c in lambdacheck_mc.items(): if t not in self_mc: continue if t > 0: - result -= c*self_mc[t] + result -= c * self_mc[t] else: - result += c*self_mc[t] + result += c * self_mc[t] return result scalar = inner_product @@ -370,10 +355,9 @@ def associated_coroot(self): except KeyError: pass V = P._dense_free_module() - dep = V.linear_dependence([self._vector_()] + - [al[i]._vector_() for i in P.index_set()])[0] + dep = V.linear_dependence([self._vector_()] + [al[i]._vector_() for i in P.index_set()])[0] I = P.index_set() - return P.sum((-c/dep[0]) * h[I[i]] for i,c in dep[1:].items()) + return P.sum((-c / dep[0]) * h[I[i]] for i, c in dep[1:].items()) def has_descent(self, i, positive=False) -> bool: """ @@ -443,8 +427,8 @@ def is_dominant_weight(self) -> bool: alpha = self.parent().simple_roots() l = self.parent().cartan_type().symmetrizer() from sage.rings.semirings.non_negative_integer_semiring import NN - return all(l[i] * self.inner_product(alpha[i]) in NN - for i in self.parent().index_set()) + + return all(l[i] * self.inner_product(alpha[i]) in NN for i in self.parent().index_set()) class CartanType(SuperCartanType_standard): @@ -574,6 +558,7 @@ def root_system(self): Root system of type ['A', [2, 3]] """ from sage.combinat.root_system.root_system import RootSystem + return RootSystem(self) @cached_method @@ -590,6 +575,7 @@ def symmetrizer(self): def ell(i): return ZZ.one() if i <= 0 else -ZZ.one() + return Family(self.index_set(), ell) def dynkin_diagram(self): @@ -631,11 +617,12 @@ def dynkin_diagram(self): ([0, 1], [(0, 1, 1), (1, 0, -1)]) """ from .dynkin_diagram import DynkinDiagram_class + g = DynkinDiagram_class(self, odd_isotropic_roots=[0]) for i in range(self.m): - g.add_edge(-i-1, -i) + g.add_edge(-i - 1, -i) for i in range(1, self.n): - g.add_edge(i, i+1) + g.add_edge(i, i + 1) g.add_vertex(0) # Usually there, but not when m == n == 0 if self.m > 0: g.add_edge(-1, 0) @@ -707,6 +694,7 @@ def relabel(self, relabelling): A1|2 relabelled by {-1: -1, 0: 0, 1: 2, 2: 1} """ from . import type_relabel + return type_relabel.CartanType(self, relabelling) def _latex_draw_node(self, x, y, label, position='below=4pt'): @@ -727,13 +715,10 @@ def _latex_draw_node(self, x, y, label, position='below=4pt'): sage: print(t._latex_draw_node(0, 0, 1)) \draw[fill=white] (0 cm, 0 cm) circle (.25cm) node[below=4pt]{$1$}; """ - ret = "\\draw[fill={}] ({} cm, {} cm) circle (.25cm) node[{}]{{${}$}};\n".format( - 'white', x, y, position, label) + ret = "\\draw[fill={}] ({} cm, {} cm) circle (.25cm) node[{}]{{${}$}};\n".format('white', x, y, position, label) if label == 0: - ret += "\\draw[-,thick] ({} cm, {} cm) -- ({} cm, {} cm);\n".format( - x+.17, y+.17, x-.17, y-.17) - ret += "\\draw[-,thick] ({} cm, {} cm) -- ({} cm, {} cm);\n".format( - x+.17, y-.17, x-.17, y+.17) + ret += "\\draw[-,thick] ({} cm, {} cm) -- ({} cm, {} cm);\n".format(x + 0.17, y + 0.17, x - 0.17, y - 0.17) + ret += "\\draw[-,thick] ({} cm, {} cm) -- ({} cm, {} cm);\n".format(x + 0.17, y - 0.17, x - 0.17, y + 0.17) return ret def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2): @@ -779,11 +764,10 @@ def _latex_dynkin_diagram(self, label=None, node=None, node_dist=2): if node is None: node = self._latex_draw_node if self.n + self.m > 1: - ret = "\\draw (0 cm, 0 cm) -- ({} cm, 0 cm);\n".format((self.n+self.m)*node_dist) + ret = "\\draw (0 cm, 0 cm) -- ({} cm, 0 cm);\n".format((self.n + self.m) * node_dist) else: ret = "" - return ret + "".join(node((self.m+i)*node_dist, 0, label(i)) - for i in self.index_set()) + return ret + "".join(node((self.m + i) * node_dist, 0, label(i)) for i in self.index_set()) def ascii_art(self, label=None, node=None): """ @@ -817,7 +801,7 @@ def ascii_art(self, label=None, node=None): label = lambda i: i if node is None: node = lambda i: 'O' - ret = "---".join(node(label(i)) for i in range(1,self.m+1)) + ret = "---".join(node(label(i)) for i in range(1, self.m + 1)) if self.m == 0: if self.n == 0: ret = "X" @@ -828,8 +812,8 @@ def ascii_art(self, label=None, node=None): ret += "---X" else: ret += "---X---" - ret += "---".join(node(label(i)) for i in range(1,self.n+1)) + "\n" - ret += "".join("{!s:4}".format(label(-i)) for i in reversed(range(1,self.m+1))) + ret += "---".join(node(label(i)) for i in range(1, self.n + 1)) + "\n" + ret += "".join("{!s:4}".format(label(-i)) for i in reversed(range(1, self.m + 1))) ret += "{!s:4}".format(label(0)) - ret += "".join("{!s:4}".format(label(i)) for i in range(1,self.n+1)) + ret += "".join("{!s:4}".format(label(i)) for i in range(1, self.n + 1)) return ret diff --git a/src/sage/combinat/root_system/weight_lattice_realizations.py b/src/sage/combinat/root_system/weight_lattice_realizations.py index f0daf2ec191..4cd269884ad 100644 --- a/src/sage/combinat/root_system/weight_lattice_realizations.py +++ b/src/sage/combinat/root_system/weight_lattice_realizations.py @@ -1,6 +1,7 @@ """ Weight lattice realizations """ + # **************************************************************************** # Copyright (C) 2007-2012 Nicolas M. Thiery # @@ -219,6 +220,7 @@ def __init_extra__(self): """ from sage.rings.integer_ring import ZZ from .weight_space import WeightSpace + K = self.base_ring() # If self is the root lattice or the root space, we don't want # to register its trivial embedding into itself. This builds @@ -227,12 +229,10 @@ def __init_extra__(self): if not isinstance(self, WeightSpace) or K is not ZZ: domains.append(self.root_system.weight_lattice(extended=self.is_extended())) if not isinstance(self, WeightSpace): - domains.append(self.root_system.weight_space(K,extended=self.is_extended())) + domains.append(self.root_system.weight_space(K, extended=self.is_extended())) # Build and register the embeddings for domain in domains: - domain.module_morphism(self.fundamental_weight, - codomain=self - ).register_as_coercion() + domain.module_morphism(self.fundamental_weight, codomain=self).register_as_coercion() def _test_weight_lattice_realization(self, **options): """ @@ -249,6 +249,7 @@ def _test_weight_lattice_realization(self, **options): sage: RootSystem(['A',3]).weight_lattice()._test_weight_lattice_realization() # needs sage.graphs """ from sage.rings.integer_ring import ZZ + tester = self._tester(**options) try: @@ -270,9 +271,7 @@ def _test_weight_lattice_realization(self, **options): # For an affine root system, this will check the embedding of # the extended ones, and also of the non extended ones if this # realization is not extended - domains = [self.root_system.weight_space(base_ring, extended=extended) - for base_ring in set([ZZ, self.base_ring()]) - for extended in set([self.cartan_type().is_affine(), self.is_extended()])] + domains = [self.root_system.weight_space(base_ring, extended=extended) for base_ring in set([ZZ, self.base_ring()]) for extended in set([self.cartan_type().is_affine(), self.is_extended()])] for domain in domains: tester.assertIsNot(self._internal_coerce_map_from(domain), None) for i in self.index_set(): @@ -293,7 +292,7 @@ def _test_weight_lattice_realization(self, **options): # Check that the fundamental weights form the dual basis of the simple coroots for i in self.index_set(): - assert (Lambda[i].is_dominant()) + assert Lambda[i].is_dominant() for j in self.index_set(): tester.assertEqual(Lambda[j].scalar(alphacheck[i]), (1 if i == j else 0)) @@ -362,7 +361,7 @@ def simple_root(self, i): # after the embedding from the root lattice, and the later # uses the simple roots. So we compute that embedding by hand. Lambda = self.fundamental_weights() - return self.linear_combination( (Lambda[j], c) for j,c in alphai ) + return self.linear_combination((Lambda[j], c) for j, c in alphai) @cached_method def rho(self): @@ -677,7 +676,7 @@ def _test_reduced_word_of_translation(self, elements=None, **options): See the documentation for :class:`TestSuite` for more information. """ tester = self._tester(**options) - if not self.cartan_type().is_affine(): # won't be necessary anymore once root systems are categorified + if not self.cartan_type().is_affine(): # won't be necessary anymore once root systems are categorified return try: alpha = self.simple_roots() @@ -694,8 +693,7 @@ def _test_reduced_word_of_translation(self, elements=None, **options): # preserving the alcoves. if elements is None: c = self.cartan_type().c() - elements = [c[i] * Lambda[i] - for i in self.cartan_type().classical().index_set()] + elements = [c[i] * Lambda[i] for i in self.cartan_type().classical().index_set()] # When the null root is zero in this root lattice realization, # the roots correspond to the classical roots. We use that to @@ -712,11 +710,11 @@ def _test_reduced_word_of_translation(self, elements=None, **options): return for t in elements: - t = t - self.base_ring()(t.level()/Lambda[0].level()) * Lambda[0] + t = t - self.base_ring()(t.level() / Lambda[0].level()) * Lambda[0] w = W.from_reduced_word(self.reduced_word_of_translation(t)) if self.null_root().is_zero(): # The following formula is only valid when the null root is zero - tester.assertEqual(w.action(rho), rho + rho.level()*t) + tester.assertEqual(w.action(rho), rho + rho.level() * t) # TODO: fix this formula to take delta into account, # and remove the above condition if test_automorphism: @@ -729,17 +727,17 @@ def _test_reduced_word_of_translation(self, elements=None, **options): # It could be nicer to test equality of G and its relabelling for i in self.index_set(): for j in self.index_set(): - tester.assertEqual(G[permutation[i],permutation[j]], G[i,j]) + tester.assertEqual(G[permutation[i], permutation[j]], G[i, j]) permutations.append(permutation) - if test_automorphism and elements is None: # note: the test on elements is broken + if test_automorphism and elements is None: # note: the test on elements is broken # Check that, if we start from all fundamental weights, we # get the full automorphism group # Disabled: this should actually check that one gets all special # automorphisms, which are in bijection with the special nodes - #from sage.groups.perm_gps.permgroup import PermutationGroup - #P = PermutationGroup([[i+1 for i in permutation] for permutation in permutations]) - #tester.assertEqual(P, G.automorphism_group()) + # from sage.groups.perm_gps.permgroup import PermutationGroup + # P = PermutationGroup([[i+1 for i in permutation] for permutation in permutations]) + # tester.assertEqual(P, G.automorphism_group()) pass def signs_of_alcovewalk(self, walk): @@ -810,11 +808,11 @@ def signs_of_alcovewalk(self, walk): w = W.one() signs = [] for i in walk: - if (w.action(rho0).scalar(alphacheck[i]) > 0): + if w.action(rho0).scalar(alphacheck[i]) > 0: signs.append(-1) else: signs.append(1) - w = s[i]*w + w = s[i] * w return signs def rho_classical(self): @@ -879,7 +877,7 @@ def embed_at_level(self, x, level=1): raise ValueError("x must be an element of the classical type") Lambda = self.fundamental_weights() result = self.sum_of_terms(x) - result += Lambda[0] * (level-result.level()) / (Lambda[0].level()) + result += Lambda[0] * (level - result.level()) / (Lambda[0].level()) assert result.level() == level return result @@ -906,9 +904,10 @@ def weyl_dimension(self, highest_weight): rho = self.rho() pr = self.coroot_lattice().positive_roots() from sage.rings.integer import Integer - n = prod(((rho+highest_weight).scalar(x) for x in pr), Integer(1)) + + n = prod(((rho + highest_weight).scalar(x) for x in pr), Integer(1)) d = prod((rho.scalar(x) for x in pr), Integer(1)) - return Integer(n/d) + return Integer(n / d) @lazy_attribute def _inverse_cartan_matrix(self): @@ -976,6 +975,7 @@ def _symmetric_form_matrix(self): [1/2 1 1 0] """ from sage.matrix.constructor import matrix + ct = self.cartan_type() cm = ct.cartan_matrix() if cm.det() != 0: @@ -983,24 +983,24 @@ def _symmetric_form_matrix(self): return self._inverse_cartan_matrix.transpose() * diag if not ct.is_affine(): - raise ValueError("only implemented for affine types when the" - " Cartan matrix is singular") + raise ValueError("only implemented for affine types when the" " Cartan matrix is singular") r = ct.rank() a = ct.a() # Determine the change of basis matrix # La[0], ..., La[r], delta -> al[0], ..., al[r], La[0] - M = cm.stack( matrix([1] + [0]*(r-1)) ) - M = matrix.block([[ M, matrix([[1]] + [[0]]*r) ]]) + M = cm.stack(matrix([1] + [0] * (r - 1))) + M = matrix.block([[M, matrix([[1]] + [[0]] * r)]]) M = M.inverse() if a[0] != 1: from sage.rings.rational_field import QQ - S = matrix([~a[0]]+[0]*(r-1)) + + S = matrix([~a[0]] + [0] * (r - 1)) A = cm.symmetrized_matrix().change_ring(QQ).stack(S) else: - A = cm.symmetrized_matrix().stack(matrix([1]+[0]*(r-1))) - A = matrix.block([[A, matrix([[~a[0]]] + [[0]]*r)]]) + A = cm.symmetrized_matrix().stack(matrix([1] + [0] * (r - 1))) + A = matrix.block([[A, matrix([[~a[0]]] + [[0]] * r)]]) return M.transpose() * A * M class ElementMethods: @@ -1110,8 +1110,7 @@ def symmetric_form(self, la): else: iset = P.index_set() + ('delta',) - return sum(cl*sym[iset.index(ml),iset.index(mr)]*cr - for ml, cl in self for mr, cr in la) + return sum(cl * sym[iset.index(ml), iset.index(mr)] * cr for ml, cl in self for mr, cr in la) # # This should be in a method to_weight_lattice() # alphac = self.simple_coroots() @@ -1152,9 +1151,7 @@ def to_weight_space(self, base_ring=None): wt_space = L.root_system.weight_space(base_ring) simple_coroots = L.simple_coroots() - return wt_space.sum_of_terms(((i, base_ring(self.scalar(ac))) - for i, ac in simple_coroots.items()), - distinct=True) + return wt_space.sum_of_terms(((i, base_ring(self.scalar(ac))) for i, ac in simple_coroots.items()), distinct=True) @cached_method def _to_root_vector(self): diff --git a/src/sage/combinat/root_system/weight_space.py b/src/sage/combinat/root_system/weight_space.py index 602b679cf8d..336140e4250 100644 --- a/src/sage/combinat/root_system/weight_space.py +++ b/src/sage/combinat/root_system/weight_space.py @@ -1,6 +1,7 @@ """ Weight lattices and weight spaces """ + # **************************************************************************** # Copyright (C) 2008-2009 Nicolas M. Thiery # @@ -177,31 +178,25 @@ def __init__(self, root_system, base_ring, extended): self._extended = extended if extended: if not root_system.cartan_type().is_affine(): - raise ValueError("extended weight lattices are only" - " implemented for affine root systems") + raise ValueError("extended weight lattices are only" " implemented for affine root systems") basis_keys = tuple(basis_keys) + ("delta",) def sortkey(x): return (1 if isinstance(x, str) else 0, x) + else: + def sortkey(x): return x self.root_system = root_system - CombinatorialFreeModule.__init__(self, base_ring, - basis_keys, - prefix="Lambdacheck" if root_system.dual_side else "Lambda", - latex_prefix="\\Lambda^\\vee" if root_system.dual_side else "\\Lambda", - sorting_key=sortkey, - category=WeightLatticeRealizations(base_ring)) + CombinatorialFreeModule.__init__(self, base_ring, basis_keys, prefix="Lambdacheck" if root_system.dual_side else "Lambda", latex_prefix="\\Lambda^\\vee" if root_system.dual_side else "\\Lambda", sorting_key=sortkey, category=WeightLatticeRealizations(base_ring)) if root_system.cartan_type().is_affine() and not extended: # For an affine type, register the quotient map from the # extended weight lattice/space to the weight lattice/space domain = root_system.weight_space(base_ring, extended=True) - domain.module_morphism(self.fundamental_weight, - codomain=self - ).register_as_coercion() + domain.module_morphism(self.fundamental_weight, codomain=self).register_as_coercion() def is_extended(self): """ @@ -240,9 +235,7 @@ def _name_string(self, capitalize=True, base_ring=True, type=True): sage: RootSystem(['A',4]).weight_lattice()._name_string() "Weight lattice of the Root system of type ['A', 4]" """ - return self._name_string_helper("weight", - capitalize=capitalize, base_ring=base_ring, type=type, - prefix="extended " if self.is_extended() else "") + return self._name_string_helper("weight", capitalize=capitalize, base_ring=base_ring, type=type, prefix="extended " if self.is_extended() else "") @cached_method def fundamental_weight(self, i): @@ -360,7 +353,7 @@ def simple_root(self, j): if j not in self.index_set(): raise ValueError("{} is not in the index set".format(j)) K = self.base_ring() - result = self.sum_of_terms((i,K(c)) for i,c in self.root_system.dynkin_diagram().column(j)) + result = self.sum_of_terms((i, K(c)) for i, c in self.root_system.dynkin_diagram().column(j)) if self._extended and j == self.cartan_type().special_node(): result = result + self.monomial("delta") return result @@ -449,6 +442,7 @@ def to_ambient_space_morphism(self): def basis_value(basis, i): return basis[i] + return self.module_morphism(on_basis=functools.partial(basis_value, basis), codomain=L) @@ -505,8 +499,8 @@ def scalar(self, lambdacheck): raise ValueError("{} is not in the coroot space".format(lambdacheck)) zero = self.parent().base_ring().zero() if len(self) < len(lambdacheck): - return sum( (lambdacheck[i]*c for (i,c) in self), zero) - return sum( (self[i]*c for (i,c) in lambdacheck), zero) + return sum((lambdacheck[i] * c for (i, c) in self), zero) + return sum((self[i] * c for (i, c) in lambdacheck), zero) def is_dominant(self): r""" @@ -570,6 +564,7 @@ def is_dominant_weight(self): """ index_set = set(self.parent().index_set()) from sage.rings.integer_ring import ZZ + return all(c in ZZ and c >= 0 for i, c in self._monomial_coefficients.items() if i in index_set) def to_ambient(self): diff --git a/src/sage/combinat/root_system/weyl_characters.py b/src/sage/combinat/root_system/weyl_characters.py index 8b0b294c534..9cfeeba64be 100644 --- a/src/sage/combinat/root_system/weyl_characters.py +++ b/src/sage/combinat/root_system/weyl_characters.py @@ -92,6 +92,7 @@ class WeylCharacterRing(CombinatorialFreeModule): https://doc.sagemath.org/html/en/thematic_tutorials/lie.html """ + @staticmethod def __classcall__(cls, ct, base_ring=ZZ, prefix=None, style='lattice', k=None, conjugate=False, cyclotomic_order=None, fusion_labels=None, inject_variables=False): """ @@ -151,6 +152,7 @@ def __init__(self, ct, base_ring=ZZ, prefix=None, style='lattice', k=None, conju def next_level(wt): return [wt + la for la in fw if self.level(wt + la) <= k] + B = list(RecursivelyEnumeratedSet([self._space.zero()], next_level)) B = [self._space.from_vector_notation(wt, style='coroots') for wt in B] else: @@ -317,9 +319,7 @@ def lift(self): sage: a2(x) a2(1,3,0) + a2(1,0,3) + a2(3,1,0) + a2(3,0,1) + a2(0,1,3) + a2(0,3,1) """ - return self.module_morphism(self.lift_on_basis, - codomain=self.ambient(), - category=AlgebrasWithBasis(self.base_ring())) + return self.module_morphism(self.lift_on_basis, codomain=self.ambient(), category=AlgebrasWithBasis(self.base_ring())) def _retract(self, chi): """ @@ -392,6 +392,7 @@ def retract(self): """ from sage.categories.homset import Hom from sage.categories.morphism import SetMorphism + category = Algebras(self.base_ring()) return SetMorphism(Hom(self.ambient(), self, category), self._retract) @@ -685,8 +686,7 @@ def _demazure_weights(self, hwv, word='long', debug=False): """ alphacheck = self._space.simple_coroots() dd = {} - h = tuple(int(hwv.inner_product(alphacheck[j])) - for j in self._space.index_set()) + h = tuple(int(hwv.inner_product(alphacheck[j])) for j in self._space.index_set()) dd[h] = 1 return self._demazure_helper(dd, word=word, debug=debug) @@ -759,8 +759,7 @@ def _demazure_helper(self, dd, word='long', debug=False): if debug: print(" mu=%s, next[mu]=%s" % (mu, next[mu])) accum = dict(next) - return {self._space.from_vector_notation(v, style='coroots'): val - for v, val in accum.items() if val} + return {self._space.from_vector_notation(v, style='coroots'): val for v, val in accum.items() if val} @cached_method def _weight_multiplicities(self, x): @@ -1081,12 +1080,12 @@ def _char_from_weights(self, mdict): hdict[highest] = c for k in sdict: if k in ddict: - if ddict[k] == c*sdict[k]: + if ddict[k] == c * sdict[k]: del ddict[k] else: - ddict[k] = ddict[k]-c*sdict[k] + ddict[k] = ddict[k] - c * sdict[k] else: - ddict[k] = -c*sdict[k] + ddict[k] = -c * sdict[k] return hdict def adjoint_representation(self): @@ -1266,8 +1265,7 @@ def dual(self): raise NotImplementedError("dual method is not implemented for reducible types") d = self.monomial_coefficients() WCR = self.parent() - return sum(d[k] * WCR._element_constructor_(self.parent()._dual_helper(k)) - for k in d) + return sum(d[k] * WCR._element_constructor_(self.parent()._dual_helper(k)) for k in d) def highest_weight(self): """ @@ -1367,8 +1365,7 @@ def symmetric_power(self, k): ret = par.zero() for r in range(1, k + 1): adam_r = self._adams_operator_helper(r) - ret += par.linear_combination((par._product_helper(adam_r, l), c) - for l, c in self.symmetric_power(k - r)) + ret += par.linear_combination((par._product_helper(adam_r, l), c) for l, c in self.symmetric_power(k - r)) m = ret.weight_multiplicities() dd = {key: val / k for key, val in m.items()} return self.parent().char_from_weights(dd) @@ -1406,13 +1403,13 @@ def exterior_power(self, k): for r in range(1, k + 1): adam_r = self._adams_operator_helper(r) if is_even(r): - ret -= par.linear_combination((par._product_helper(adam_r, l), c) for (l, c) in self.exterior_power(k-r)) + ret -= par.linear_combination((par._product_helper(adam_r, l), c) for (l, c) in self.exterior_power(k - r)) else: - ret += par.linear_combination((par._product_helper(adam_r, l), c) for (l, c) in self.exterior_power(k-r)) + ret += par.linear_combination((par._product_helper(adam_r, l), c) for (l, c) in self.exterior_power(k - r)) dd = {} m = ret.weight_multiplicities() for l in m: - dd[l] = m[l]/k + dd[l] = m[l] / k return self.parent().char_from_weights(dd) def adams_operator(self, r): @@ -1476,14 +1473,14 @@ def symmetric_square(self): ckeys = list(c) d = {} for j in range(len(ckeys)): - for i in range(j+1): + for i in range(j + 1): ci = ckeys[i] cj = ckeys[j] t = ci + cj if i < j: - coef = c[ci]*c[cj] + coef = c[ci] * c[cj] else: - coef = c[ci]*(c[ci]+1)/2 + coef = c[ci] * (c[ci] + 1) / 2 if t in d: d[t] += coef else: @@ -1507,14 +1504,14 @@ def exterior_square(self): ckeys = list(c) d = {} for j in range(len(ckeys)): - for i in range(j+1): + for i in range(j + 1): ci = ckeys[i] cj = ckeys[j] t = ci + cj if i < j: - coef = c[ci]*c[cj] + coef = c[ci] * c[cj] else: - coef = c[ci]*(c[ci]-1)/2 + coef = c[ci] * (c[ci] - 1) / 2 if t in d: d[t] += coef else: @@ -1602,8 +1599,7 @@ def inner_product(self, other): sage: r1.inner_product(r2) 3 """ - return sum(self.coefficient(x) * other.coefficient(x) - for x in self.monomial_coefficients()) + return sum(self.coefficient(x) * other.coefficient(x) for x in self.monomial_coefficients()) def invariant_degree(self): """ @@ -1740,6 +1736,7 @@ class WeightRing(CombinatorialFreeModule): sage: a2(chi)*wd == sum((-1)^w.length()*a2([6,3,-1]).weyl_group_action(w) for w in a2.space().weyl_group()) True """ + @staticmethod def __classcall__(cls, parent, prefix=None): """ @@ -1785,7 +1782,7 @@ def __init__(self, parent, prefix): prefix = self._parent._prefix.upper() else: # TODO: this only works for irreducible Cartan types! - prefix = (self._cartan_type[0].lower() + str(self._rank)) + prefix = self._cartan_type[0].lower() + str(self._rank) self._prefix = prefix category = AlgebrasWithBasis(self._base_ring).Commutative() CombinatorialFreeModule.__init__(self, self._base_ring, self._space, category=category) @@ -2156,8 +2153,7 @@ def demazure(self, w, debug=False): d = {} alphacheck = self.parent()._space.simple_coroots() for v in d1: - d[tuple(v.inner_product(alphacheck[j]) - for j in self.parent().space().index_set())] = d1[v] + d[tuple(v.inner_product(alphacheck[j]) for j in self.parent().space().index_set())] = d1[v] return self.parent()._from_dict(self.parent().parent()._demazure_helper(d, word, debug=debug)) def demazure_lusztig(self, i, v): diff --git a/src/sage/combinat/root_system/weyl_group.py b/src/sage/combinat/root_system/weyl_group.py index 5ae0f4fff66..ff5595df90b 100644 --- a/src/sage/combinat/root_system/weyl_group.py +++ b/src/sage/combinat/root_system/weyl_group.py @@ -216,8 +216,7 @@ def WeylGroup(x, prefix=None, implementation='matrix'): return WeylGroup_gens(ct.root_system().root_space(), prefix=prefix) -class WeylGroup_gens(UniqueRepresentation, - FinitelyGeneratedMatrixGroup_gap): +class WeylGroup_gens(UniqueRepresentation, FinitelyGeneratedMatrixGroup_gap): @staticmethod def __classcall__(cls, domain, prefix=None): @@ -250,16 +249,14 @@ def __init__(self, domain, prefix): self._prefix = prefix # FinitelyGeneratedMatrixGroup_gap takes plain matrices as input - gens_matrix = [self.morphism_matrix(self.domain().simple_reflection(i)) - for i in self.index_set()] + gens_matrix = [self.morphism_matrix(self.domain().simple_reflection(i)) for i in self.index_set()] if not gens_matrix: libgap_group = libgap.Group([], matrix(ZZ, 1, 1, [1])) else: libgap_group = libgap.Group(gens_matrix) degree = ZZ(self.domain().dimension()) ring = self.domain().base_ring() - FinitelyGeneratedMatrixGroup_gap.__init__( - self, degree, ring, libgap_group, category=category) + FinitelyGeneratedMatrixGroup_gap.__init__(self, degree, ring, libgap_group, category=category) def __hash__(self): r""" @@ -308,9 +305,7 @@ def index_set(self): # Should be implemented in (morphisms of) modules with basis def morphism_matrix(self, f): - return matrix(self.domain().base_ring(), - [f(b).to_vector() - for b in self.domain().basis()]).transpose() + return matrix(self.domain().base_ring(), [f(b).to_vector() for b in self.domain().basis()]).transpose() def from_morphism(self, f): return self._element_constructor_(self.morphism_matrix(f)) @@ -409,6 +404,7 @@ def to_elt(alp): ref = self.domain().reflection(alp) m = Matrix([ref(x).to_vector() for x in self.domain().basis()]) return self(m.transpose()) + return Family(prr, to_elt, name="real root to reflection") def _repr_(self): @@ -420,9 +416,7 @@ def _repr_(self): sage: WeylGroup(['A', 3, 1]) Weyl Group of type ['A', 3, 1] (as a matrix group acting on the root space) """ - domain = self._domain._name_string(capitalize=False, - base_ring=False, - type=False) + domain = self._domain._name_string(capitalize=False, base_ring=False, type=False) return "Weyl Group of type %s (as a matrix group acting on the %s)" % (self.cartan_type(), domain) def character_table(self): @@ -534,30 +528,21 @@ def long_element_hardcoded(self): l.append(1) m = diagonal_matrix(QQ, l) elif typ[0] == 'A': - l = [0 for k in range((self.n)**2)] - for k in range(self.n - 1, (self.n)**2 - 1, self.n - 1): + l = [0 for k in range((self.n) ** 2)] + for k in range(self.n - 1, (self.n) ** 2 - 1, self.n - 1): l[k] = 1 m = matrix(QQ, self.n, l) elif typ[0] == 'E': if typ[1] == 6: half = QQ((1, 2)) - l = [[-half, -half, -half, half, 0, 0, 0, 0], - [-half, -half, half, -half, 0, 0, 0, 0], - [-half, half, -half, -half, 0, 0, 0, 0], - [half, -half, -half, -half, 0, 0, 0, 0], - [0, 0, 0, 0, half, half, half, -half], - [0, 0, 0, 0, half, half, -half, half], - [0, 0, 0, 0, half, -half, half, half], - [0, 0, 0, 0, -half, half, half, half]] + l = [[-half, -half, -half, half, 0, 0, 0, 0], [-half, -half, half, -half, 0, 0, 0, 0], [-half, half, -half, -half, 0, 0, 0, 0], [half, -half, -half, -half, 0, 0, 0, 0], [0, 0, 0, 0, half, half, half, -half], [0, 0, 0, 0, half, half, -half, half], [0, 0, 0, 0, half, -half, half, half], [0, 0, 0, 0, -half, half, half, half]] m = matrix(QQ, 8, l) else: raise NotImplementedError("not implemented yet for this type") elif typ[0] == 'G': third = QQ((1, 3)) twothirds = QQ((2, 3)) - l = [[-third, twothirds, twothirds], - [twothirds, -third, twothirds], - [twothirds, twothirds, -third]] + l = [[-third, twothirds, twothirds], [twothirds, -third, twothirds], [twothirds, twothirds, -third]] m = matrix(QQ, 3, l) else: m = diagonal_matrix([-1] * self.n) @@ -622,6 +607,7 @@ class ClassicalWeylSubgroup(WeylGroup_gens): - Parabolic subrootsystems - Parabolic subgroups with a set of nodes as argument """ + @cached_method def cartan_type(self): """ @@ -650,8 +636,7 @@ def simple_reflections(self): Note: won't be needed, once the lattice will be a parabolic sub root system """ - return Family({i: self.from_morphism(self.domain().simple_reflection(i)) - for i in self.index_set()}) + return Family({i: self.from_morphism(self.domain().simple_reflection(i)) for i in self.index_set()}) def __repr__(self): """ @@ -666,9 +651,7 @@ def __repr__(self): sage: RootSystem(['C',4,1]).coweight_lattice().weyl_group().classical() Parabolic Subgroup of the Weyl Group of type ['C', 4, 1]^* (as a matrix group acting on the coweight lattice) """ - domain = self._domain._name_string(capitalize=False, - base_ring=False, - type=False) + domain = self._domain._name_string(capitalize=False, base_ring=False, type=False) return "Parabolic Subgroup of the Weyl Group of type %s (as a matrix group acting on the %s)" % (self.domain().cartan_type(), domain) def weyl_group(self, prefix='hereditary'): @@ -769,8 +752,7 @@ def _repr_(self): if len(redword) == 0: return "1" - ret = "".join("%s%d*" % (self._parent._prefix, i) - for i in redword[:-1]) + ret = "".join("%s%d*" % (self._parent._prefix, i) for i in redword[:-1]) return ret + "%s%d" % (self._parent._prefix, redword[-1]) def _latex_(self): @@ -817,9 +799,7 @@ def __eq__(self, other): subclasses overriding __cmp__ with something slow for specific purposes. """ - return (self.__class__ == other.__class__ and - self._parent == other._parent and - self.matrix() == other.matrix()) + return self.__class__ == other.__class__ and self._parent == other._parent and self.matrix() == other.matrix() def _richcmp_(self, other, op): """ @@ -833,8 +813,7 @@ def _richcmp_(self, other, op): False """ if self._parent.cartan_type() != other._parent.cartan_type(): - return richcmp_not_equal(self._parent.cartan_type(), - other._parent.cartan_type(), op) + return richcmp_not_equal(self._parent.cartan_type(), other._parent.cartan_type(), op) return richcmp(self.matrix(), other.matrix(), op) def action(self, v): @@ -919,11 +898,11 @@ def has_descent(self, i, positive=False, side='right') -> bool: sage: W.w0.has_descent(0) False """ -# s=self.parent().lattice().rho().scalar(self.action(self.parent().lattice().simple_root(i))) -# if positive: -# return s > 0 -# else: -# return s < 0 + # s=self.parent().lattice().rho().scalar(self.action(self.parent().lattice().simple_root(i))) + # if positive: + # return s > 0 + # else: + # return s < 0 L = self.domain() # Choose the method depending on the side and the availability of rho and is_positive_root if not hasattr(L.element_class, "is_positive_root"): @@ -1001,8 +980,7 @@ def to_permutation(self): """ W = self.parent() e = W.domain().basis() - return tuple(c * (j + 1) for i in e.keys() - for (j, c) in self.action(e[i])) + return tuple(c * (j + 1) for i in e.keys() for (j, c) in self.action(e[i])) def to_permutation_string(self): """ @@ -1023,6 +1001,7 @@ class WeylGroup_permutation(UniqueRepresentation, PermutationGroup_generic): """ A Weyl group given as a permutation group. """ + @staticmethod def __classcall__(cls, cartan_type, prefix=None): """ @@ -1053,8 +1032,7 @@ def __init__(self, cartan_type, prefix): self._prefix = prefix Q = cartan_type.root_system().root_lattice() Phi = list(Q.positive_roots()) + [-x for x in Q.positive_roots()] - p = [[Phi.index(x.weyl_action([i])) + 1 for x in Phi] - for i in self._cartan_type.index_set()] + p = [[Phi.index(x.weyl_action([i])) + 1 for x in Phi] for i in self._cartan_type.index_set()] cat = FiniteWeylGroups() if self._cartan_type.is_irreducible(): cat = cat.Irreducible() @@ -1116,10 +1094,10 @@ def iteration(self, algorithm='breadth', tracking_words=True): () """ from sage.combinat.root_system.reflection_group_c import Iterator + if self.rank() == 0: return iter([self.one()]) - return iter(Iterator(self, N=self.number_of_reflections(), - algorithm=algorithm, tracking_words=tracking_words)) + return iter(Iterator(self, N=self.number_of_reflections(), algorithm=algorithm, tracking_words=tracking_words)) def __iter__(self): r""" @@ -1276,8 +1254,7 @@ def roots(self): (-3, -2)) """ Q = self._cartan_type.root_system().root_lattice() - roots = ([x.to_vector() for x in Q.positive_roots()] - + [-x.to_vector() for x in Q.positive_roots()]) + roots = [x.to_vector() for x in Q.positive_roots()] + [-x.to_vector() for x in Q.positive_roots()] for v in roots: v.set_immutable() return tuple(roots) @@ -1300,7 +1277,7 @@ def positive_roots(self): (2, 2, 1), (1, 2, 1)) """ - return self.roots()[:self.number_of_reflections()] + return self.roots()[: self.number_of_reflections()] @cached_method def number_of_reflections(self): @@ -1335,6 +1312,7 @@ def build_elt(index): r = pos_roots[index] perm = [Phi.index(x.reflection(r)) + 1 for x in Phi] return self.element_class(perm, self, check=False) + return Family(self.reflection_index_set(), lambda i: build_elt(i - 1)) reflections = distinguished_reflections @@ -1372,8 +1350,7 @@ def _repr_(self): redword = self.reduced_word() if not redword: return "1" - return "*".join("%s%d" % (self.parent()._prefix, i) - for i in redword) + return "*".join("%s%d" % (self.parent()._prefix, i) for i in redword) def _latex_(self): """ @@ -1393,5 +1370,4 @@ def _latex_(self): redword = self.reduced_word() if not redword: return "1" - return "".join("%s_{%d}" % (self.parent()._prefix, i) - for i in redword) + return "".join("%s_{%d}" % (self.parent()._prefix, i) for i in redword) diff --git a/src/sage/combinat/rooted_tree.py b/src/sage/combinat/rooted_tree.py index 1b247d2bec1..a6781662cf6 100644 --- a/src/sage/combinat/rooted_tree.py +++ b/src/sage/combinat/rooted_tree.py @@ -8,8 +8,7 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.sets_cat import Sets -from sage.combinat.abstract_tree import (AbstractClonableTree, - AbstractLabelledClonableTree) +from sage.combinat.abstract_tree import AbstractClonableTree, AbstractLabelledClonableTree from sage.misc.cachefunc import cached_function, cached_method from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.misc.lazy_attribute import lazy_attribute, lazy_class_attribute @@ -50,13 +49,10 @@ def number_of_rooted_trees(n): if n == 1: return Integer(1) n = Integer(n) - return sum(sum(d * number_of_rooted_trees(d) for d in k.divisors()) * - number_of_rooted_trees(n - k) - for k in ZZ.range(1, n)) // (n - 1) + return sum(sum(d * number_of_rooted_trees(d) for d in k.divisors()) * number_of_rooted_trees(n - k) for k in ZZ.range(1, n)) // (n - 1) -class RootedTree(AbstractClonableTree, NormalizedClonableList, - metaclass=InheritComparisonClasscallMetaclass): +class RootedTree(AbstractClonableTree, NormalizedClonableList, metaclass=InheritComparisonClasscallMetaclass): r""" The class for unordered rooted trees. @@ -121,6 +117,7 @@ class RootedTree(AbstractClonableTree, NormalizedClonableList, as distinct). Thus, you will have to override the method by one that does distinguish different trees. """ + # Standard auto-parent trick @staticmethod def __classcall_private__(cls, *args, **opts): @@ -446,9 +443,7 @@ def single_graft(self, x, grafting_function, path_prefix=()): a[b[d[]], c[e[]]] """ P = self.parent() - child_grafts = [suby.single_graft(x, grafting_function, - path_prefix + (i,)) - for i, suby in enumerate(self)] + child_grafts = [suby.single_graft(x, grafting_function, path_prefix + (i,)) for i, suby in enumerate(self)] try: y1 = P(child_grafts, label=self.label()) except AttributeError: @@ -482,6 +477,7 @@ class RootedTrees(UniqueRepresentation, Parent): sage: RootedTrees(2) Rooted trees with 2 nodes """ + @staticmethod def __classcall_private__(cls, n=None): """ @@ -530,9 +526,7 @@ def __init__(self): sage: TestSuite(RootedTrees()).run() # long time """ - DisjointUnionEnumeratedSets.__init__( - self, Family(NonNegativeIntegers(), RootedTrees_size), - facade=True, keepkey=False) + DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), RootedTrees_size), facade=True, keepkey=False) def _repr_(self): r""" @@ -694,6 +688,7 @@ def __iter__(self): from sage.combinat.partition import Partitions from itertools import combinations_with_replacement, product + for part in Partitions(self._n - 1): mults = part.to_exp_dict() choices = [] @@ -853,6 +848,7 @@ class LabelledRootedTree(AbstractLabelledClonableTree, RootedTree): sage: xyy2._get_list() == yxy2._get_list() True """ + @staticmethod def __classcall_private__(cls, *args, **opts): """ @@ -988,6 +984,7 @@ class LabelledRootedTrees(UniqueRepresentation, Parent): Add the possibility to restrict the labels to a fixed set. """ + @staticmethod def __classcall_private__(cls, n=None): """ diff --git a/src/sage/combinat/rsk.py b/src/sage/combinat/rsk.py index 1f4ad742c90..3280216c484 100644 --- a/src/sage/combinat/rsk.py +++ b/src/sage/combinat/rsk.py @@ -228,11 +228,11 @@ def to_pairs(self, obj1=None, obj2=None, check=True): for i, row in enumerate(obj1): for j, mult in enumerate(row): if mult > 0: - t.extend([i+1]*mult) - b.extend([j+1]*mult) + t.extend([i + 1] * mult) + b.extend([j + 1] * mult) itr = zip(t, b) except TypeError: - itr = zip(range(1, len(obj1)+1), obj1) + itr = zip(range(1, len(obj1) + 1), obj1) else: if check: if len(obj1) != len(obj2): @@ -299,8 +299,8 @@ def forward_rule(self, obj1, obj2, check_standard=False, check=True): [[[1, 3], [3], [6], [7]], [[1, 4], [2], [3], [5]]] """ itr = self.to_pairs(obj1, obj2, check=check) - p = [] # the "insertion" tableau - q = [] # the "recording" tableau + p = [] # the "insertion" tableau + q = [] # the "recording" tableau for i, j in itr: for r, qr in zip(p, q): j1 = self.insertion(j, r) @@ -357,6 +357,7 @@ def backward_rule(self, p, q, output): [[1, 2, 3, 4, 5], [7, 6, 3, 3, 1]] """ from sage.combinat.tableau import SemistandardTableaux + # Make a copy of p since this is destructive to it p_copy = [list(row) for row in p] @@ -436,8 +437,7 @@ def _forward_format_output(self, p, q, check_standard): return [P, Q] return [SemistandardTableau(p), SemistandardTableau(q)] - def _backward_format_output(self, lower_row, upper_row, output, - p_is_standard, q_is_standard): + def _backward_format_output(self, lower_row, upper_row, output, p_is_standard, q_is_standard): r""" Return the final output of the ``RSK_inverse`` correspondence from the output of the corresponding ``backward_rule``. @@ -478,11 +478,12 @@ def _backward_format_output(self, lower_row, upper_row, output, if q_is_standard: if output == 'word': from sage.combinat.words.word import Word + return Word(reversed(lower_row)) if output == 'matrix': - return to_matrix(list(range(1, len(lower_row)+1)), list(reversed(lower_row))) + return to_matrix(list(range(1, len(lower_row) + 1)), list(reversed(lower_row))) if output == 'array': - return [list(range(1, len(lower_row)+1)), list(reversed(lower_row))] + return [list(range(1, len(lower_row) + 1)), list(reversed(lower_row))] raise ValueError("invalid output option") else: @@ -491,8 +492,7 @@ def _backward_format_output(self, lower_row, upper_row, output, if output == 'array': return [list(reversed(upper_row)), list(reversed(lower_row))] if output in ['permutation', 'word']: - raise TypeError( - "q must be standard to have a %s as valid output" % output) + raise TypeError("q must be standard to have a %s as valid output" % output) raise ValueError("invalid output option") @@ -564,8 +564,7 @@ def reverse_insertion(self, x, row): x, row[y_pos] = row[y_pos], x return x - def _backward_format_output(self, lower_row, upper_row, output, - p_is_standard, q_is_standard): + def _backward_format_output(self, lower_row, upper_row, output, p_is_standard, q_is_standard): r""" Return the final output of the ``RSK_inverse`` correspondence from the output of the corresponding ``backward_rule``. @@ -593,9 +592,9 @@ def _backward_format_output(self, lower_row, upper_row, output, if not p_is_standard: raise TypeError("p must be standard to have a valid permutation as output") from sage.combinat.permutation import Permutation + return Permutation(reversed(lower_row)) - return super()._backward_format_output(lower_row, upper_row, output, - p_is_standard, q_is_standard) + return super()._backward_format_output(lower_row, upper_row, output, p_is_standard, q_is_standard) class RuleEG(Rule): @@ -741,7 +740,7 @@ def reverse_insertion(self, x, row): 2 """ y_pos = bisect_left(row, x) - 1 - if row[y_pos] == x - 1 and y_pos < len(row)-1 and row[y_pos+1] == x: + if row[y_pos] == x - 1 and y_pos < len(row) - 1 and row[y_pos + 1] == x: # Nothing to do except decrement x by 1. # (Case 1 on p. 74 of Edelman-Greene [EG1987]_.) x -= 1 @@ -750,8 +749,7 @@ def reverse_insertion(self, x, row): x, row[y_pos] = row[y_pos], x return x - def _backward_format_output(self, lower_row, upper_row, output, - p_is_standard, q_is_standard): + def _backward_format_output(self, lower_row, upper_row, output, p_is_standard, q_is_standard): r""" Return the final output of the ``RSK_inverse`` correspondence from the output of the corresponding ``backward_rule``. @@ -777,9 +775,9 @@ def _backward_format_output(self, lower_row, upper_row, output, if list(lower_row): n = max(list(lower_row)) + 1 from sage.combinat.permutation import Permutations + return Permutations(n).from_reduced_word(list(lower_row)) - return super()._backward_format_output(lower_row, upper_row, output, - p_is_standard, q_is_standard) + return super()._backward_format_output(lower_row, upper_row, output, p_is_standard, q_is_standard) class RuleHecke(Rule): @@ -890,8 +888,8 @@ def forward_rule(self, obj1, obj2, check_standard=False): obj2 = obj1 obj1 = list(range(1, len(obj1) + 1)) - p = [] # the "insertion" tableau - q = [] # the "recording" tableau + p = [] # the "insertion" tableau + q = [] # the "recording" tableau for i, j in zip(obj1, obj2): for ir, r in enumerate(p): @@ -900,7 +898,7 @@ def forward_rule(self, obj1, obj2, check_standard=False): if j1 is None: # We must have len(p[ir-1]) > len(r), since j is coming # from the previous row. - if r[-1] < j and (ir == 0 or p[ir-1][len(r)] < j): + if r[-1] < j and (ir == 0 or p[ir - 1][len(r)] < j): # We can add a box to the row r.append(j) q[ir].append((i,)) # Values are always inserted to the right @@ -909,7 +907,7 @@ def forward_rule(self, obj1, obj2, check_standard=False): l = len(r) - 1 while ir < len(q) and len(q[ir]) > l: ir += 1 - q[ir-1][-1] = q[ir-1][-1] + (i,) + q[ir - 1][-1] = q[ir - 1][-1] + (i,) break else: j = j1 @@ -957,6 +955,7 @@ def backward_rule(self, p, q, output): if p.shape() != q.shape(): raise ValueError("p(=%s) and q(=%s) must have the same shape" % (p, q)) from sage.combinat.tableau import SemistandardTableaux + if p not in SemistandardTableaux(): raise ValueError("p(=%s) must be a semistandard tableau" % p) @@ -1029,7 +1028,7 @@ def insertion(self, j, ir, r, p): y_pos = bisect_right(r, j) y = r[y_pos] # Check to see if we can swap j for y - if (y_pos == 0 or r[y_pos-1] < j) and (ir == 0 or p[ir-1][y_pos] < j): + if (y_pos == 0 or r[y_pos - 1] < j) and (ir == 0 or p[ir - 1][y_pos] < j): r[y_pos] = j j = y return j @@ -1056,15 +1055,12 @@ def reverse_insertion(self, i, x, row, p): y_pos = bisect_left(row, x) - 1 y = row[y_pos] # Check to see if we can swap x for y - if ((y_pos == len(row) - 1 or x < row[y_pos+1]) - and (i == len(p) - 1 or len(p[i+1]) <= y_pos - or x < p[i+1][y_pos])): + if (y_pos == len(row) - 1 or x < row[y_pos + 1]) and (i == len(p) - 1 or len(p[i + 1]) <= y_pos or x < p[i + 1][y_pos]): row[y_pos] = x x = y return x - def _backward_format_output(self, lower_row, upper_row, output, - p_is_standard, q_is_standard): + def _backward_format_output(self, lower_row, upper_row, output, p_is_standard, q_is_standard): r""" Return the final output of the ``RSK_inverse`` correspondence from the output of the corresponding ``backward_rule``. @@ -1106,17 +1102,16 @@ def _backward_format_output(self, lower_row, upper_row, output, """ if output == 'array': return [list(reversed(upper_row)), list(reversed(lower_row))] - is_standard = (upper_row == list(range(len(upper_row), 0, -1))) + is_standard = upper_row == list(range(len(upper_row), 0, -1)) if output == 'word': if not is_standard: - raise TypeError( - "q must be standard to have a %s as valid output" % output) + raise TypeError("q must be standard to have a %s as valid output" % output) from sage.combinat.words.word import Word + return Word(reversed(lower_row)) if output == 'list': if not is_standard: - raise TypeError( - "q must be standard to have a %s as valid output" % output) + raise TypeError("q must be standard to have a %s as valid output" % output) return list(reversed(lower_row)) raise ValueError("invalid output option") @@ -1347,11 +1342,11 @@ def to_pairs(self, obj1=None, obj2=None, check=True): if mult > 1: raise ValueError("dual RSK requires a {0, 1}-matrix") if mult > 0: - t.append(i+1) - b.append(j+1) + t.append(i + 1) + b.append(j + 1) itr = zip(t, b) except TypeError: - itr = zip(range(1, len(obj1)+1), obj1) + itr = zip(range(1, len(obj1) + 1), obj1) else: if check: if len(obj1) != len(obj2): @@ -1434,8 +1429,7 @@ def reverse_insertion(self, x, row): x, row[y_pos] = row[y_pos], x return x - def _backward_format_output(self, lower_row, upper_row, output, - p_is_standard, q_is_standard): + def _backward_format_output(self, lower_row, upper_row, output, p_is_standard, q_is_standard): r""" Return the final output of the ``RSK_inverse`` correspondence from the output of the corresponding ``backward_rule``. @@ -1463,9 +1457,9 @@ def _backward_format_output(self, lower_row, upper_row, output, if not p_is_standard: raise TypeError("p must be standard to have a valid permutation as output") from sage.combinat.permutation import Permutation + return Permutation(reversed(lower_row)) - return super()._backward_format_output(lower_row, upper_row, output, - p_is_standard, q_is_standard) + return super()._backward_format_output(lower_row, upper_row, output, p_is_standard, q_is_standard) def _forward_format_output(self, p, q, check_standard): r""" @@ -1729,11 +1723,11 @@ def to_pairs(self, obj1=None, obj2=None, check=True): if mult > 1: raise ValueError("coRSK requires a {0, 1}-matrix") if mult > 0: - t.append(i+1) - b.append(j+1) + t.append(i + 1) + b.append(j + 1) itr = zip(t, b) except TypeError: - itr = zip(range(1, len(obj1)+1), obj1) + itr = zip(range(1, len(obj1) + 1), obj1) else: if check: if len(obj1) != len(obj2): @@ -2024,6 +2018,7 @@ def to_pairs(self, obj1=None, obj2=None, check=True): ValueError: invalid restricted superbiword """ from sage.combinat.shifted_primed_tableau import PrimedEntry + # Initializing itr for itr = None case itr = None if obj2 is None: @@ -2173,8 +2168,8 @@ def forward_rule(self, obj1, obj2, check_standard=False, check=True): True """ itr = self.to_pairs(obj1, obj2, check=check) - p = [] # the "insertion" tableau - q = [] # the "recording" tableau + p = [] # the "insertion" tableau + q = [] # the "recording" tableau for i, j in itr: # loop row_index = -1 @@ -2425,8 +2420,7 @@ def reverse_insertion(self, x, row, epsilon=0): x, row[y_pos] = row[y_pos], x return x, y_pos - def _backward_format_output(self, lower_row, upper_row, output, - q_is_standard): + def _backward_format_output(self, lower_row, upper_row, output, q_is_standard): r""" Return the final output of the ``RSK_inverse`` correspondence from the output of the corresponding ``backward_rule``. @@ -2463,9 +2457,9 @@ def _backward_format_output(self, lower_row, upper_row, output, if output == 'word': if q_is_standard: from sage.combinat.words.word import Word + return Word(reversed(lower_row)) - raise TypeError("q must be standard to have a %s as " - "valid output" % output) + raise TypeError("q must be standard to have a %s as " "valid output" % output) raise ValueError("invalid output option") @@ -2700,25 +2694,28 @@ def forward_rule(self, obj1, obj2=None, check_braid=True): """ if obj2 is None and obj1 is not None: from sage.combinat.crystals.fully_commutative_stable_grothendieck import DecreasingHeckeFactorization + if not isinstance(obj1, DecreasingHeckeFactorization): obj2 = obj1 - obj1 = list(range(1, len(obj1)+1)) + obj1 = list(range(1, len(obj1) + 1)) else: h = obj1 - obj1 = sum([[h.factors-i]*len(h.value[i]) for i in reversed(range(h.factors))], []) + obj1 = sum([[h.factors - i] * len(h.value[i]) for i in reversed(range(h.factors))], []) obj2 = [i for f in h.value[::-1] for i in reversed(f)] if len(obj1) != len(obj2): raise ValueError(f"{obj1} and {obj2} have different number of elements") - for i in range(len(obj1)-1): - if obj1[i] > obj1[i+1] or (obj1[i] == obj1[i+1] and obj2[i] >= obj2[i+1]): + for i in range(len(obj1) - 1): + if obj1[i] > obj1[i + 1] or (obj1[i] == obj1[i + 1] and obj2[i] >= obj2[i + 1]): raise ValueError(f"{obj1}, {obj2} is not an increasing factorization") if check_braid: - N = max(obj2)+1 if obj2 else 1 + N = max(obj2) + 1 if obj2 else 1 from sage.monoids.hecke_monoid import HeckeMonoid from sage.groups.perm_gps.permgroup_named import SymmetricGroup + H = HeckeMonoid(SymmetricGroup(N)) h = H.from_reduced_word(obj2) from sage.combinat import permutation + p = permutation.from_reduced_word(h.reduced_word()) if p.has_pattern([3, 2, 1]): raise ValueError("the Star insertion is not defined for non-fully commutative words") @@ -2740,6 +2737,7 @@ def forward_rule(self, obj1, obj2=None, check_braid=True): p.append([j]) q.append([i]) from sage.combinat.tableau import Tableau, SemistandardTableau + p = Tableau(p) q = SemistandardTableau(q) return [p, q] @@ -2797,6 +2795,7 @@ def backward_rule(self, p, q, output='array'): () """ from sage.combinat.tableau import SemistandardTableaux + if p.shape() != q.shape(): raise ValueError("p(=%s) and q(=%s) must have the same shape" % (p, q)) if q not in SemistandardTableaux(): @@ -2808,9 +2807,11 @@ def backward_rule(self, p, q, output='array'): N = max(row_reading + [0]) + 1 from sage.monoids.hecke_monoid import HeckeMonoid from sage.groups.perm_gps.permgroup_named import SymmetricGroup + H = HeckeMonoid(SymmetricGroup(N)) h = H.from_reduced_word(row_reading) from sage.combinat import permutation + w = permutation.from_reduced_word(h.reduced_word()) if w.has_pattern([3, 2, 1]): raise ValueError(f"the row reading word of the insertion tableau {p} is not fully-commutative") @@ -2919,23 +2920,25 @@ def _backward_format_output(self, obj1, obj2, output): if output == 'array': return [obj1, obj2] if output == 'word': - if obj1 == list(range(1, len(obj1)+1)): + if obj1 == list(range(1, len(obj1) + 1)): from sage.combinat.words.word import Word + return Word(obj2) raise TypeError("upper row must be standard") elif output == 'DecreasingHeckeFactorization': from sage.combinat.crystals.fully_commutative_stable_grothendieck import DecreasingHeckeFactorization + obj1.reverse() obj2.reverse() df = [] for j in range(len(obj1)): if j == 0: df.append([]) - if j > 0 and obj1[j] < obj1[j-1]: - df.extend([] for _ in range(obj1[j-1]-obj1[j])) + if j > 0 and obj1[j] < obj1[j - 1]: + df.extend([] for _ in range(obj1[j - 1] - obj1[j])) df[-1].append(obj2[j]) if obj1: - df.extend([] for a in range(obj1[-1]-1)) + df.extend([] for a in range(obj1[-1] - 1)) # If biword is empty, return a decreasing factorization with 1 factor else: df.append([]) @@ -2946,6 +2949,7 @@ class InsertionRules: r""" Catalog of rules for RSK-like insertion algorithms. """ + RSK = RuleRSK EG = RuleEG Hecke = RuleHecke @@ -2954,6 +2958,7 @@ class InsertionRules: superRSK = RuleSuperRSK Star = RuleStar + ##################################################################### @@ -3393,7 +3398,7 @@ def to_matrix(t, b): # is typically (very) sparse entries = {} for i in range(n): - pos = (t[i]-1, b[i]-1) + pos = (t[i] - 1, b[i] - 1) if pos in entries: entries[pos] += 1 else: diff --git a/src/sage/combinat/schubert_polynomial.py b/src/sage/combinat/schubert_polynomial.py index e39b9de51d8..9ef43c690bb 100644 --- a/src/sage/combinat/schubert_polynomial.py +++ b/src/sage/combinat/schubert_polynomial.py @@ -387,9 +387,7 @@ def __init__(self, R): """ self._name = "Schubert polynomial ring with X basis" self._repr_option_bracket = False - CombinatorialFreeModule.__init__(self, R, Permutations(), - category=GradedAlgebrasWithBasis(R), - prefix='X') + CombinatorialFreeModule.__init__(self, R, Permutations(), category=GradedAlgebrasWithBasis(R), prefix='X') @cached_method def one_basis(self): @@ -479,8 +477,7 @@ def _element_constructor_(self, x): if isinstance(x, InfinitePolynomial): R = x.polynomial().parent() # massage the term order to be what symmetrica expects - S = PolynomialRing(R.base_ring(), - names=list(map(repr, reversed(R.gens())))) + S = PolynomialRing(R.base_ring(), names=list(map(repr, reversed(R.gens())))) return symmetrica.t_POLYNOM_SCHUBERT(S(x.polynomial())) if isinstance(x, OperatorPolynomial): return self(x.expand()) @@ -496,8 +493,7 @@ def some_elements(self): sage: X.some_elements() [X[1], X[1] + 2*X[2, 1], -X[3, 2, 1] + X[4, 2, 1, 3]] """ - return [self.one(), self([1]) + 2 * self([2, 1]), - self([4, 2, 1, 3]) - self([3, 2, 1])] + return [self.one(), self([1]) + 2 * self([2, 1]), self([4, 2, 1, 3]) - self([3, 2, 1])] def product_on_basis(self, left, right): """ diff --git a/src/sage/combinat/set_partition.py b/src/sage/combinat/set_partition.py index d792abeae85..da2e0cadcf1 100644 --- a/src/sage/combinat/set_partition.py +++ b/src/sage/combinat/set_partition.py @@ -13,6 +13,7 @@ - Martin Rubey (2017-10-10): Cleanup, add crossings and nestings, add random generation. """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # @@ -58,8 +59,7 @@ lazy_import('sage.probability.probability_distribution', 'GeneralDiscreteDistribution') -class AbstractSetPartition(ClonableArray, - metaclass=InheritComparisonClasscallMetaclass): +class AbstractSetPartition(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): r""" Methods of set partitions which are independent of the base set """ @@ -364,8 +364,7 @@ def sup(self, t): res = list(self) for p in t: # find blocks in res which intersect p - inters = [(i, q) for i, q in enumerate(res) - if any(a in q for a in p)] + inters = [(i, q) for i, q in enumerate(res) if any(a in q for a in p)] # remove these blocks from res for i, _ in reversed(inters): del res[i] @@ -463,6 +462,7 @@ def union(s): cur.extend(self[i - 1]) # -1 for indexing ret.append(cur) return ret + return [self.parent()(union(s)) for s in SP] def max_block_size(self): @@ -505,6 +505,7 @@ def conjugate(self): sage: SetPartition([]).conjugate() {} """ + def next_one(a, support): return support[(support.index(a) + 1) % len(support)] @@ -525,19 +526,15 @@ def pre_conjugate(sp): singletons = [a for S in sp for a in S if len(S) == 1] if not initials and not singletons: return sp - rho = pre_conjugate( - SetPartition([[a for a in S if a not in initials] - for S in sp if len(S) > 1 and any(a not in initials for a in S)])) + rho = pre_conjugate(SetPartition([[a for a in S if a not in initials] for S in sp if len(S) > 1 and any(a not in initials for a in S)])) # add back initials as singletons and singletons as terminals - return SetPartition([addback(S, singletons, support[::-1]) - for S in rho] + [[a] for a in initials]) + return SetPartition([addback(S, singletons, support[::-1]) for S in rho] + [[a] for a in initials]) + support = sorted(a for S in self for a in S) - return SetPartition([[support[-support.index(a) - 1] for a in S] - for S in pre_conjugate(self)]) + return SetPartition([[support[-support.index(a) - 1] for a in S] for S in pre_conjugate(self)]) -class SetPartition(AbstractSetPartition, - metaclass=InheritComparisonClasscallMetaclass): +class SetPartition(AbstractSetPartition, metaclass=InheritComparisonClasscallMetaclass): r""" A partition of a set. @@ -594,6 +591,7 @@ class SetPartition(AbstractSetPartition, sage: s.parent() Set partitions """ + @staticmethod def __classcall_private__(cls, parts, check=True): """ @@ -695,16 +693,13 @@ def set_latex_options(self, **kwargs): 'show_labels': True, 'tikz_scale': 2} """ - valid_args = ['tikz_scale', 'plot', 'color', 'fill', 'show_labels', - 'radius', 'angle'] + valid_args = ['tikz_scale', 'plot', 'color', 'fill', 'show_labels', 'radius', 'angle'] for key in kwargs: if key not in valid_args: raise ValueError(f"unknown keyword argument: {key}") if key == 'plot': - if not (kwargs['plot'] == 'cyclic' - or kwargs['plot'] == 'linear' - or kwargs['plot'] is None): + if not (kwargs['plot'] == 'cyclic' or kwargs['plot'] == 'linear' or kwargs['plot'] is None): raise ValueError("plot must be None, 'cyclic', or 'linear'") self._latex_options.update(kwargs) @@ -801,6 +796,7 @@ def _latex_(self): cardinality = self.base_set_cardinality() from sage.rings.integer_ring import ZZ + if all(x in ZZ for x in self.base_set()): sort_key = ZZ else: @@ -833,8 +829,7 @@ def _latex_(self): else: res += ",fill={},fill opacity=0.1".format(color) res += "] " - res += " -- ".join("({}.center)".format(base_set.index(j)) - for j in sorted(partition, key=sort_key)) + res += " -- ".join("({}.center)".format(base_set.index(j)) for j in sorted(partition, key=sort_key)) res += " -- cycle;\n" # Draw the circles on top @@ -1836,11 +1831,11 @@ def strict_coarsenings(self): while todo: A = todo.pop() for i, part in enumerate(A): - for j, other in enumerate(A[i + 1:]): + for j, other in enumerate(A[i + 1 :]): if max(part) < min(other): next_pi = A[:i] next_pi.append(part.union(other)) - next_pi += A[i + 1:i + 1 + j] + A[i + j + 2:] + next_pi += A[i + 1 : i + 1 + j] + A[i + j + 2 :] next_pi = SetPartition(next_pi) if next_pi not in visited: todo.append(next_pi) @@ -1977,11 +1972,9 @@ def plot(self, angle=None, color='black', base_set_dict=None): for k, j in self.arcs(): pos_k, pos_j = float(vertices_dict[k]), float(vertices_dict[j]) - center = ((pos_k + pos_j) / 2, - -abs(pos_j - pos_k) / (2 * tan(angle))) + center = ((pos_k + pos_j) / 2, -abs(pos_j - pos_k) / (2 * tan(angle))) r1 = abs((pos_j - pos_k) / (2 * sin(angle))) - sector = (sgn(angle) * (pi / 2 - angle), - sgn(angle) * (pi / 2 + angle)) + sector = (sgn(angle) * (pi / 2 - angle), sgn(angle) * (pi / 2 + angle)) diag += arc(center=center, r1=r1, sector=sector, color=color) diag.axes(False) @@ -2039,6 +2032,7 @@ class SetPartitions(UniqueRepresentation, Parent): - :wikipedia:`Partition_of_a_set` """ + @staticmethod def __classcall_private__(cls, s=None, part=None): """ @@ -2444,8 +2438,7 @@ def from_rook_placement_rho(self, rooks, n): cols = [j for j, _ in rooks] R = [j for j in range(1, n + 1) if j not in cols] # the columns of the board, beginning with column n-1 - C = [set(range(n + 1 - j, n + 1)) if n - j not in R else set() - for j in range(1, n)] + C = [set(range(n + 1 - j, n + 1)) if n - j not in R else set() for j in range(1, n)] for j, i in rooks: # column j from right, row i from top # south C[n - j - 1].difference_update(range(i, n + 1)) @@ -2615,9 +2608,7 @@ def is_strict_refinement(self, s, t) -> bool: for p in t: L = [x for x in s if x.issubset(p)] - if sum(len(x) for x in L) != len(p) \ - or any(max(L[i]) > min(L[i + 1]) - for i in range(len(L) - 1)): + if sum(len(x) for x in L) != len(p) or any(max(L[i]) > min(L[i + 1]) for i in range(len(L) - 1)): return False return True @@ -2686,6 +2677,7 @@ class SetPartitions_set(SetPartitions): """ Set partitions of a fixed set `S`. """ + @staticmethod def __classcall_private__(cls, s): """ @@ -2775,10 +2767,11 @@ def random_element(self): base_set = list(self.base_set()) N = len(base_set) from sage.symbolic.constants import e + c = float(e) * bell_number(N) # it would be much better to generate M in the way Knuth # recommends, the following is a waste - G = GeneralDiscreteDistribution([float(m)**N / (c * factorial(m)) for m in range(4 * N)]) + G = GeneralDiscreteDistribution([float(m) ** N / (c * factorial(m)) for m in range(4 * N)]) M = G.get_random_element() - 1 l = (randint(0, M) for i in range(N)) p = {} @@ -2861,6 +2854,7 @@ class SetPartitions_setparts(SetPartitions_set): Set partitions with fixed partition sizes corresponding to an integer partition `\lambda`. """ + @staticmethod def __classcall_private__(cls, s, parts): """ @@ -2958,9 +2952,7 @@ def cardinality(self): cardinal *= remaining_subset_size.binomial(subset_size) remaining_subset_size -= subset_size - repetitions = (Integer(rep).factorial() - for rep in self._parts.to_exp_dict().values() - if rep != 1) + repetitions = (Integer(rep).factorial() for rep in self._parts.to_exp_dict().values() if rep != 1) cardinal /= prod(repetitions) return Integer(cardinal) @@ -3042,8 +3034,7 @@ def __iter__(self): pi = [None] * n for i in range(n): pi[ext[i]] = s[i] - sp = [[pi[j] for j in range(sums[i], sums[i + 1])] - for i in range(k)] + sp = [[pi[j] for j in range(sums[i], sums[i + 1])] for i in range(k)] yield self.element_class(self, sp, check=False) def __contains__(self, x): @@ -3108,6 +3099,7 @@ class SetPartitions_setn(SetPartitions_set): """ Set partitions with a given number of blocks. """ + @staticmethod def __classcall_private__(cls, s, k): """ @@ -3230,6 +3222,7 @@ def random_element(self): True sage: assert s in S, s """ + def re(N, k): if N == 0: return [[]] @@ -3305,6 +3298,7 @@ def cyclic_permutations_of_set_partition_iterator(set_part): [(1, 4, 3, 2), (5, 7, 6)]] """ from sage.combinat.permutation import CyclicPermutations + if len(set_part) == 1: for i in CyclicPermutations(set_part[0]): yield [i] diff --git a/src/sage/combinat/set_partition_ordered.py b/src/sage/combinat/set_partition_ordered.py index 0401f1041c3..629fa2e888a 100644 --- a/src/sage/combinat/set_partition_ordered.py +++ b/src/sage/combinat/set_partition_ordered.py @@ -8,6 +8,7 @@ - Travis Scrimshaw (2013-02-28): Removed ``CombinatorialClass`` and added entry point through :class:`OrderedSetPartition`. """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # @@ -45,8 +46,7 @@ from sage.structure.unique_representation import UniqueRepresentation -class OrderedSetPartition(ClonableArray, - metaclass=InheritComparisonClasscallMetaclass): +class OrderedSetPartition(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): r""" An ordered partition of a set. @@ -153,6 +153,7 @@ class OrderedSetPartition(ClonableArray, :wikipedia:`Ordered_partition_of_a_set` """ + @staticmethod def __classcall_private__(cls, parts=None, from_word=None, check=True): """ @@ -201,8 +202,7 @@ def __init__(self, parent, s, check=True): sage: s = OS([[1, 3], [2, 4]]) sage: TestSuite(s).run() """ - ClonableArray.__init__(self, parent, - [frozenset(part) for part in s], check=check) + ClonableArray.__init__(self, parent, [frozenset(part) for part in s], check=check) def _repr_(self): """ @@ -450,8 +450,7 @@ def finer(self): par = parent(self) if not self: return FiniteEnumeratedSet([self]) - return FiniteEnumeratedSet([par(sum((list(i) for i in C), [])) - for C in product(*[OrderedSetPartitions(X) for X in self])]) + return FiniteEnumeratedSet([par(sum((list(i) for i in C), [])) for C in product(*[OrderedSetPartitions(X) for X in self])]) def is_finer(self, co2) -> bool: """ @@ -547,7 +546,7 @@ def fatten(self, grouping): result = [None] * len(grouping) j = 0 for i in range(len(grouping)): - result[i] = set().union(*self[j:j + grouping[i]]) + result[i] = set().union(*self[j : j + grouping[i]]) j += grouping[i] return parent(self)(result) @@ -635,7 +634,7 @@ def bottom_up_osp(X, comp): result = [None] * len(comp) j = 0 for i in range(len(comp)): - result[i] = set(xs[j:j + comp[i]]) + result[i] = set(xs[j : j + comp[i]]) j += comp[i] return OrderedSetPartitions(X)(result) @@ -669,8 +668,7 @@ def strongly_finer(self): if not self: return FiniteEnumeratedSet([self]) buo = OrderedSetPartition.bottom_up_osp - return FiniteEnumeratedSet([par(sum((list(P) for P in C), [])) - for C in product(*[[buo(X, comp) for comp in Compositions(len(X))] for X in self])]) + return FiniteEnumeratedSet([par(sum((list(P) for P in C), [])) for C in product(*[[buo(X, comp) for comp in Compositions(len(X))] for X in self])]) def is_strongly_finer(self, co2) -> bool: r""" @@ -771,14 +769,12 @@ def strongly_fatter(self): g = [-1] + [i for i in range(l) if c[i][-1] > c[i + 1][0]] + [l] # g lists the positions of the blocks that cannot be merged # with their right neighbors. - subcomps = [OrderedSetPartition(c[g[i] + 1: g[i + 1] + 1]) - for i in range(len(g) - 1)] + subcomps = [OrderedSetPartition(c[g[i] + 1 : g[i + 1] + 1]) for i in range(len(g) - 1)] # Now, self is the concatenation of the entries of subcomps. # We can fatten each of the ordered set partitions setcomps # arbitrarily, and then concatenate the results. fattenings = [list(subcomp.fatter()) for subcomp in subcomps] - return FiniteEnumeratedSet([OrderedSetPartition(sum([list(gg) for gg in fattening], [])) - for fattening in product(*fattenings)]) + return FiniteEnumeratedSet([OrderedSetPartition(sum([list(gg) for gg in fattening], [])) for fattening in product(*fattenings)]) @combinatorial_map(name='to packed word') def to_packed_word(self): @@ -918,6 +914,7 @@ class OrderedSetPartitions(UniqueRepresentation, Parent): sage: x.parent() Ordered set partitions """ + @staticmethod def __classcall_private__(cls, s=None, c=None): """ @@ -1061,8 +1058,7 @@ def from_finite_word(self, w, check=True): except AttributeError: pass return self.element_class(self, W(w).to_ordered_set_partition()) - raise TypeError(f"`from_finite_word` expects an object of type list/tuple/str/Word " - f"representing a finite word, received {w}") + raise TypeError(f"`from_finite_word` expects an object of type list/tuple/str/Word " f"representing a finite word, received {w}") class OrderedSetPartitions_s(OrderedSetPartitions): @@ -1099,8 +1095,7 @@ def cardinality(self): 541 """ N = len(self._set) - return sum(factorial(k) * stirling_number2(N, k) - for k in range(N + 1)) + return sum(factorial(k) * stirling_number2(N, k) for k in range(N + 1)) def __iter__(self): """ @@ -1166,8 +1161,7 @@ def __repr__(self): sage: OrderedSetPartitions([1,2,3,4], 2) Ordered set partitions of {1, 2, 3, 4} into 2 parts """ - return "Ordered set partitions of %s into %s parts" % (Set(self._set), - self.n) + return "Ordered set partitions of %s into %s parts" % (Set(self._set), self.n) def cardinality(self): """ @@ -1409,7 +1403,7 @@ def multiset_permutation_next_lex(l): while l[j] <= l[i]: j -= 1 l[i], l[j] = l[j], l[i] - l[i + 1:] = l[:i:-1] + l[i + 1 :] = l[:i:-1] return 1 @@ -1558,8 +1552,8 @@ def _richcmp_(self, other, op): sage: el1 <= el2, el1 >= el2, el2 <= el1 # indirect doctest (False, True, True) """ - return richcmp([sorted(s) for s in self], - [sorted(s) for s in other], op) + return richcmp([sorted(s) for s in self], [sorted(s) for s in other], op) + ########################################################## # Deprecations diff --git a/src/sage/combinat/sf/abreu_nigro.py b/src/sage/combinat/sf/abreu_nigro.py index b29aa376d46..43eb31126ae 100644 --- a/src/sage/combinat/sf/abreu_nigro.py +++ b/src/sage/combinat/sf/abreu_nigro.py @@ -169,6 +169,7 @@ class SymmetricFunctionAlgebra_AbreuNigro(multiplicative.SymmetricFunctionAlgebr sage: all(P(an[n].antipode()) == -P[n] for n in range(1, 6)) True """ + @staticmethod def __classcall_private__(cls, Sym, q='q'): """ @@ -244,8 +245,7 @@ def _h_to_an_on_basis(self, lam): q = self._q B = self.basis() n = lam[0] - return (self.sum(self._h_to_an_on_basis(P([n-i])) * B[P([i])] - for i in range(1, n+1)) / R.sum(q**k for k in range(n))) + return self.sum(self._h_to_an_on_basis(P([n - i])) * B[P([i])] for i in range(1, n + 1)) / R.sum(q**k for k in range(n)) # Multiply by the smallest part to minimize the number of products return self._h_to_an_on_basis(P(lam[:-1])) * self._h_to_an_on_basis(P([lam[-1]])) @@ -286,8 +286,7 @@ def _an_to_h_on_basis(self, lam): q = self._q B = self._h.basis() n = lam[0] - return (R.sum(q**k for k in range(n)) * self._h[n] - - self._h.sum(B[P([n-i])] * self._an_to_h_on_basis(P([i])) for i in range(1, n))) + return R.sum(q**k for k in range(n)) * self._h[n] - self._h.sum(B[P([n - i])] * self._an_to_h_on_basis(P([i])) for i in range(1, n)) # Multiply by the smallest part to minimize the number of products return self._an_to_h_on_basis(P(lam[:-1])) * self._an_to_h_on_basis(P([lam[-1]])) @@ -341,5 +340,5 @@ def coproduct_on_generators(self, n): coeff = self._q - one if coeff: for k in range(1, n): - d[P([k]), P([n-k])] = coeff + d[P([k]), P([n - k])] = coeff return TS.element_class(TS, d) diff --git a/src/sage/combinat/sf/all.py b/src/sage/combinat/sf/all.py index 204c0b914bb..1d57674e042 100644 --- a/src/sage/combinat/sf/all.py +++ b/src/sage/combinat/sf/all.py @@ -29,6 +29,7 @@ - :ref:`sage.combinat.sf.witt` - :ref:`sage.combinat.sf.abreu_nigro` """ + # install the docstring of this module to the containing package from sage.misc.namespace_package import install_doc @@ -44,6 +45,4 @@ lazy_import('sage.combinat.sf.kfpoly', 'KostkaFoulkesPolynomial') -lazy_import('sage.combinat.sf.ns_macdonald', ['NonattackingFillings', - 'AugmentedLatticeDiagramFilling', - 'LatticeDiagram']) +lazy_import('sage.combinat.sf.ns_macdonald', ['NonattackingFillings', 'AugmentedLatticeDiagramFilling', 'LatticeDiagram']) diff --git a/src/sage/combinat/sf/character.py b/src/sage/combinat/sf/character.py index 31e73a333f6..c1228b9ba87 100644 --- a/src/sage/combinat/sf/character.py +++ b/src/sage/combinat/sf/character.py @@ -67,7 +67,7 @@ def _my_key(self, la): 17 """ if la: - return la.size()**2 + la[0] + return la.size() ** 2 + la[0] return 0 def _other_to_self(self, sexpr): @@ -99,8 +99,7 @@ def _other_to_self(self, sexpr): if sexpr == 0: return self(0) if list(sexpr.support()) == [[]]: - return self._from_dict({self.one_basis(): sexpr.coefficient([])}, - remove_zeros=False) + return self._from_dict({self.one_basis(): sexpr.coefficient([])}, remove_zeros=False) out = self.zero() while sexpr: mup = max(sexpr.support(), key=self._my_key) @@ -137,14 +136,14 @@ def _b_power_k(self, k): if k == 1: return self._p([1]) if k > 0: - return ~k * self._p.linear_combination((self._p([d]),moebius(k//d)) - for d in divisors(k)) + return ~k * self._p.linear_combination((self._p([d]), moebius(k // d)) for d in divisors(k)) class InducedCharacterBases(Character_generic): r""" Character basis with Frobenius image of other times complete. """ + def __init__(self, Sym, other_basis, **kwds): r""" Initialize the basis and register coercions. @@ -157,10 +156,8 @@ def __init__(self, Sym, other_basis, **kwds): SFA_generic.__init__(self, Sym, **kwds) self._other = other_basis self._p = Sym.powersum() - self.module_morphism(self._self_to_power_on_basis, - codomain=Sym.powersum()).register_as_coercion() - self.register_coercion(SetMorphism(Hom(self._other, self), - self._other_to_self)) + self.module_morphism(self._self_to_power_on_basis, codomain=Sym.powersum()).register_as_coercion() + self.register_coercion(SetMorphism(Hom(self._other, self), self._other_to_self)) def _b_bar_power_k_r(self, k, r): r""" @@ -189,7 +186,7 @@ def _b_bar_power_k_r(self, k, r): sage: ht._b_bar_power_k_r(3,2) 3*p[1] + p[1, 1] - 3*p[3] - 2*p[3, 1] + p[3, 3] """ - return k**r * self._p.prod( self._b_power_k(k)-j for j in range(r) ) + return k**r * self._p.prod(self._b_power_k(k) - j for j in range(r)) def _b_bar_power_gamma(self, gamma): r""" @@ -225,8 +222,7 @@ def _b_bar_power_gamma(self, gamma): sage: ht._b_bar_power_gamma(Partition([3,3,1])) 3*p[1, 1] + p[1, 1, 1] - 3*p[3, 1] - 2*p[3, 1, 1] + p[3, 3, 1] """ - return self._p.prod(self._b_bar_power_k_r(Integer(k), Integer(r)) - for k, r in gamma.to_exp_dict().items()) + return self._p.prod(self._b_bar_power_k_r(Integer(k), Integer(r)) for k, r in gamma.to_exp_dict().items()) def _self_to_power_on_basis(self, lam): r""" @@ -276,8 +272,7 @@ def _self_to_power_on_basis(self, lam): sage: xt._self_to_power_on_basis([1,1,1]) 1/6*p[1, 1, 1] - 1/2*p[2, 1] + 1/3*p[3] """ - return self._p.sum( c*self._b_bar_power_gamma(ga) - for (ga, c) in self._p(self._other(lam)) ) + return self._p.sum(c * self._b_bar_power_gamma(ga) for (ga, c) in self._p(self._other(lam))) @cached_method def _self_to_other_on_basis(self, lam): @@ -371,6 +366,7 @@ class InducedTrivialCharacterBasis(InducedCharacterBases): sage: s[4,2].kronecker_product(s[5,1]) s[3, 2, 1] + s[3, 3] + s[4, 1, 1] + s[4, 2] + s[5, 1] """ + def __init__(self, Sym): r""" Initialize the basis and register coercions. @@ -386,9 +382,7 @@ def __init__(self, Sym): sage: ht = SymmetricFunctions(QQ).ht() sage: TestSuite(ht).run() """ - InducedCharacterBases.__init__(self, Sym, Sym.complete(), - basis_name="induced trivial symmetric group character", - prefix='ht', graded=False) + InducedCharacterBases.__init__(self, Sym, Sym.complete(), basis_name="induced trivial symmetric group character", prefix='ht', graded=False) class RookIrreducibleCharacterBasis(InducedCharacterBases): @@ -442,6 +436,7 @@ class RookIrreducibleCharacterBasis(InducedCharacterBases): sage: s(xt[2,1].character_to_frobenius_image(9)) == s[6] * s[2,1] True """ + def __init__(self, Sym): r""" Initialize the basis and register coercions. @@ -461,9 +456,7 @@ def __init__(self, Sym): sage: xt = SymmetricFunctions(QQ).xt() sage: TestSuite(xt).run() """ - InducedCharacterBases.__init__(self, Sym, Sym.Schur(), - basis_name="irreducible rook monoid character", - prefix='xt', graded=False) + InducedCharacterBases.__init__(self, Sym, Sym.Schur(), basis_name="irreducible rook monoid character", prefix='xt', graded=False) class IrreducibleCharacterBasis(Character_generic): @@ -533,16 +526,12 @@ def __init__(self, Sym): Symmetric Functions over Rational Field in the irreducible symmetric group character basis """ - SFA_generic.__init__(self, Sym, - basis_name="irreducible symmetric group character", - prefix='st', graded=False) + SFA_generic.__init__(self, Sym, basis_name="irreducible symmetric group character", prefix='st', graded=False) self._other = Sym.Schur() self._p = Sym.powersum() - self.module_morphism(self._self_to_power_on_basis, - codomain=Sym.powersum()).register_as_coercion() - self.register_coercion(SetMorphism(Hom(self._other, self), - self._other_to_self)) + self.module_morphism(self._self_to_power_on_basis, codomain=Sym.powersum()).register_as_coercion() + self.register_coercion(SetMorphism(Hom(self._other, self), self._other_to_self)) def _b_power_k_r(self, k, r): r""" @@ -572,9 +561,7 @@ def _b_power_k_r(self, k, r): p[] + 5*p[1] + p[1, 1] - 5*p[3] - 2*p[3, 1] + p[3, 3] """ p = self._p - return p.sum( (-1)**(r-j) * k**j * binomial(r,j) - * p.prod(self._b_power_k(k) - i*p.one() for i in range(j)) - for j in range(r+1) ) + return p.sum((-1) ** (r - j) * k**j * binomial(r, j) * p.prod(self._b_power_k(k) - i * p.one() for i in range(j)) for j in range(r + 1)) def _b_power_gamma(self, gamma): r""" @@ -610,8 +597,7 @@ def _b_power_gamma(self, gamma): sage: st._b_power_gamma(Partition([3,1])) p[] - p[1, 1] - p[3] + p[3, 1] """ - return self._p.prod(self._b_power_k_r(Integer(k), Integer(r)) - for k, r in gamma.to_exp_dict().items()) + return self._p.prod(self._b_power_k_r(Integer(k), Integer(r)) for k, r in gamma.to_exp_dict().items()) def _self_to_power_on_basis(self, lam): r""" @@ -645,8 +631,7 @@ def _self_to_power_on_basis(self, lam): sage: st._self_to_power_on_basis([1,1]) p[] - p[1] + 1/2*p[1, 1] - 1/2*p[2] """ - return self._p.sum( c*self._b_power_gamma(ga) - for (ga, c) in self._p(self._other(lam)) ) + return self._p.sum(c * self._b_power_gamma(ga) for (ga, c) in self._p(self._other(lam))) @cached_method def _self_to_other_on_basis(self, lam): diff --git a/src/sage/combinat/sf/classical.py b/src/sage/combinat/sf/classical.py index addbdfc20fa..c1000c40680 100644 --- a/src/sage/combinat/sf/classical.py +++ b/src/sage/combinat/sf/classical.py @@ -24,11 +24,7 @@ from . import hall_littlewood, jack, llt, macdonald, orthotriang, sfa -translate = {'monomial': 'MONOMIAL', - 'homogeneous': 'HOMSYM', - 'powersum': 'POWSYM', - 'elementary': 'ELMSYM', - 'Schur': 'SCHUR'} +translate = {'monomial': 'MONOMIAL', 'homogeneous': 'HOMSYM', 'powersum': 'POWSYM', 'elementary': 'ELMSYM', 'Schur': 'SCHUR'} conversion_functions = {} @@ -53,11 +49,11 @@ def init(): s[1, 1, 1, 1] - s[2, 1, 1] + 2*s[2, 2] - s[3, 1] + s[4] """ import sage.libs.symmetrica.all as symmetrica + for other_basis, other_name in translate.items(): for basis, name in translate.items(): try: - conversion_functions[(other_basis, basis)] = getattr(symmetrica, - f't_{other_name}_{name}') + conversion_functions[(other_basis, basis)] = getattr(symmetrica, f't_{other_name}_{name}') except AttributeError: pass @@ -179,8 +175,7 @@ def _element_constructor_(self, x): if P is self: return x # different base ring - return eclass(self, {la: rc for la, c in x._monomial_coefficients.items() - if (rc := R(c))}) + return eclass(self, {la: rc for la, c in x._monomial_coefficients.items() if (rc := R(c))}) ################################################## # Classical Symmetric Functions, different basis # @@ -194,13 +189,11 @@ def _element_constructor_(self, x): try: t = conversion_functions[(P.basis_name(), self.basis_name())] except AttributeError: - raise TypeError("do not know how to convert from %s to %s" - % (P.basis_name(), self.basis_name())) + raise TypeError("do not know how to convert from %s to %s" % (P.basis_name(), self.basis_name())) if R == QQ and P.base_ring() == QQ: if m: - return self._from_dict(t(m)._monomial_coefficients, - coerce=True) + return self._from_dict(t(m)._monomial_coefficients, coerce=True) return self.zero() f = lambda part: self._from_dict(t({part: ZZ.one()})._monomial_coefficients) return self._apply_module_endomorphism(x, f) @@ -212,8 +205,7 @@ def _element_constructor_(self, x): # # Qp: Convert to Schur basis and then convert to self # - if isinstance(x, (hall_littlewood.HallLittlewood_qp.Element, - hall_littlewood.HallLittlewood_p.Element)): + if isinstance(x, (hall_littlewood.HallLittlewood_qp.Element, hall_littlewood.HallLittlewood_p.Element)): P = x.parent() sx = P._s._from_cache(x, P._s_cache, P._self_to_s_cache, t=P.t) return self(sx) @@ -232,15 +224,14 @@ def _element_constructor_(self, x): Rx = P.base_ring() zero = R.zero() if not R.has_coerce_map_from(Rx): - raise TypeError("no coerce map from x's parent's base ring (= %s) to self's base ring (= %s)" - % (Rx, R)) + raise TypeError("no coerce map from x's parent's base ring (= %s) to self's base ring (= %s)" % (Rx, R)) z_elt = {} for m, c in x._monomial_coefficients.items(): n = sum(m) P._m_cache(n) for part in P._self_to_m_cache[n][m]: - z_elt[part] = z_elt.get(part, zero) + R(c*P._self_to_m_cache[n][m][part].subs(t=P.t)) + z_elt[part] = z_elt.get(part, zero) + R(c * P._self_to_m_cache[n][m][part].subs(t=P.t)) m = P._sym.monomial() return self(m._from_dict(z_elt)) @@ -249,19 +240,16 @@ def _element_constructor_(self, x): # Macdonald Polynomials # ######################### elif isinstance(x, macdonald.MacdonaldPolynomials_generic.Element): - if isinstance(x, (macdonald.MacdonaldPolynomials_j.Element, - macdonald.MacdonaldPolynomials_s.Element)): + if isinstance(x, (macdonald.MacdonaldPolynomials_j.Element, macdonald.MacdonaldPolynomials_s.Element)): P = x.parent() sx = P._s._from_cache(x, P._s_cache, P._self_to_s_cache, q=P.q, t=P.t) return self(sx) - if isinstance(x, (macdonald.MacdonaldPolynomials_q.Element, - macdonald.MacdonaldPolynomials_p.Element)): + if isinstance(x, (macdonald.MacdonaldPolynomials_q.Element, macdonald.MacdonaldPolynomials_p.Element)): J = x.parent()._J jx = J(x) sx = J._s._from_cache(jx, J._s_cache, J._self_to_s_cache, q=J.q, t=J.t) return self(sx) - if isinstance(x, (macdonald.MacdonaldPolynomials_h.Element, - macdonald.MacdonaldPolynomials_ht.Element)): + if isinstance(x, (macdonald.MacdonaldPolynomials_h.Element, macdonald.MacdonaldPolynomials_ht.Element)): P = x.parent() sx = P._self_to_s(x) return self(sx) @@ -275,8 +263,7 @@ def _element_constructor_(self, x): P = x.parent() mx = P._m._from_cache(x, P._m_cache, P._self_to_m_cache, t=P.t) return self(mx) - if isinstance(x, (jack.JackPolynomials_j.Element, - jack.JackPolynomials_q.Element)): + if isinstance(x, (jack.JackPolynomials_j.Element, jack.JackPolynomials_q.Element)): return self(x.parent()._P(x)) raise TypeError @@ -288,7 +275,7 @@ def _element_constructor_(self, x): P = x.parent() if self is P._sf_base: return P._sf_base._from_cache(x, P._base_cache, P._self_to_base_cache) - return self( P._sf_base(x) ) + return self(P._sf_base(x)) ################################# # Last shot -- try calling R(x) # @@ -309,4 +296,5 @@ class Element(sfa.SymmetricFunctionAlgebra_generic.Element): """ A symmetric function. """ + pass diff --git a/src/sage/combinat/sf/dual.py b/src/sage/combinat/sf/dual.py index 4dd7eb25e54..60a76a59e34 100644 --- a/src/sage/combinat/sf/dual.py +++ b/src/sage/combinat/sf/dual.py @@ -2,7 +2,7 @@ """ Generic dual bases symmetric functions """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2007 Mike Hansen # 2012 Mike Zabrocki # @@ -16,7 +16,7 @@ # The full text of the GPL is available at: # # https://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** import sage.combinat.partition import sage.data_structures.blas_dict as blas from sage.categories.homset import Hom @@ -42,7 +42,7 @@ def __classcall__(cls, dual_basis, scalar, scalar_name='', basis_name=None, pref True """ if prefix is None: - prefix = 'd_'+dual_basis.prefix() + prefix = 'd_' + dual_basis.prefix() return super().__classcall__(cls, dual_basis, scalar, scalar_name, basis_name, prefix) def __init__(self, dual_basis, scalar, scalar_name, basis_name, prefix): @@ -158,14 +158,12 @@ def __init__(self, dual_basis, scalar, scalar_name, basis_name, prefix): self._inverse_transition_matrices = {} scalar_target = scalar(sage.combinat.partition.Partition([1])).parent() - scalar_target = (scalar_target.one()*dual_basis.base_ring().one()).parent() + scalar_target = (scalar_target.one() * dual_basis.base_ring().one()).parent() self._sym = sage.combinat.sf.sf.SymmetricFunctions(scalar_target) self._p = self._sym.power() - classical.SymmetricFunctionAlgebra_classical.__init__(self, self._sym, - basis_name=basis_name, - prefix=prefix) + classical.SymmetricFunctionAlgebra_classical.__init__(self, self._sym, basis_name=basis_name, prefix=prefix) # temporary until Hom(GradedHopfAlgebrasWithBasis work better) category = ModulesWithBasis(self.base_ring()) @@ -357,9 +355,9 @@ def _precompute(self, n): # Handle the n == 0 and n == 1 cases separately if n == 0 or n == 1: - part = sage.combinat.partition.Partition([1]*n) - self._to_self_cache[ part ] = { part: base_ring.one() } - self._from_self_cache[ part ] = { part: base_ring.one() } + part = sage.combinat.partition.Partition([1] * n) + self._to_self_cache[part] = {part: base_ring.one()} + self._from_self_cache[part] = {part: base_ring.one()} self._transition_matrices[n] = matrix(base_ring, [[1]]) self._inverse_transition_matrices[n] = matrix(base_ring, [[1]]) return @@ -371,6 +369,7 @@ def _precompute(self, n): # the Schur basis. from sage.rings.rational_field import RationalField + if (not base_ring.has_coerce_map_from(RationalField())) and self._scalar == sage.combinat.sf.sfa.zee: # This is the case when (due to the base ring not being a # \QQ-algebra) we cannot use the power-sum basis, @@ -406,12 +405,12 @@ def _precompute(self, n): sp = zero for ds_part in d[s_part]: if ds_part in d[p_part]: - sp += d[s_part][ds_part]*d[p_part][ds_part] + sp += d[s_part][ds_part] * d[p_part][ds_part] if sp != zero: s_mcs[p_part] = sp - transition_matrix_n[i,j] = sp + transition_matrix_n[i, j] = sp - self._to_self_cache[ s_part ] = s_mcs + self._to_self_cache[s_part] = s_mcs else: # Now the other case. Note that just being in this case doesn't @@ -447,14 +446,14 @@ def _precompute(self, n): sp = zero for ds_part in d[s_part]: if ds_part in d[p_part]: - sp += d[s_part][ds_part]*d[p_part][ds_part]*self._scalar(ds_part) + sp += d[s_part][ds_part] * d[p_part][ds_part] * self._scalar(ds_part) if sp != zero: s_mcs[p_part] = sp - transition_matrix_n[i,j] = sp + transition_matrix_n[i, j] = sp j += 1 - self._to_self_cache[ s_part ] = s_mcs + self._to_self_cache[s_part] = s_mcs i += 1 # Save the transition matrix @@ -468,10 +467,10 @@ def _precompute(self, n): for i in range(len(partitions_n)): d_mcs = {} for j in range(len(partitions_n)): - if inverse_transition[i,j] != zero: - d_mcs[ partitions_n[j] ] = inverse_transition[i,j] + if inverse_transition[i, j] != zero: + d_mcs[partitions_n[j]] = inverse_transition[i, j] - self._from_self_cache[ partitions_n[i] ] = d_mcs + self._from_self_cache[partitions_n[i]] = d_mcs self._inverse_transition_matrices[n] = inverse_transition @@ -523,7 +522,7 @@ def transition_matrix(self, basis, n): if basis is self._dual_basis: return self._inverse_transition_matrices[n] - return self._inverse_transition_matrices[n]*self._dual_basis.transition_matrix(basis, n) + return self._inverse_transition_matrices[n] * self._dual_basis.transition_matrix(basis, n) def product(self, left, right): """ @@ -618,7 +617,7 @@ def __init__(self, A, dictionary=None, dual=None): for s_part in s_mcs: from_dictionary = from_self_cache[s_part] for part in from_dictionary: - dual_dict[ part ] = dual_dict.get(part, zero) + base_ring(s_mcs[s_part]*from_dictionary[part]) + dual_dict[part] = dual_dict.get(part, zero) + base_ring(s_mcs[s_part] * from_dictionary[part]) dual = parent._dual_basis._from_dict(dual_dict) @@ -638,7 +637,7 @@ def __init__(self, A, dictionary=None, dual=None): # Create the monomial coefficient dictionary from the # the monomial coefficient dictionary of dual - dictionary = blas.linear_combination( (to_self_cache[d_part], d_mcs[d_part]) for d_part in d_mcs) + dictionary = blas.linear_combination((to_self_cache[d_part], d_mcs[d_part]) for d_part in d_mcs) # Initialize self self._dual = dual @@ -715,7 +714,7 @@ def omega(self): d_m[1, 1, 1] - d_m[2, 1] """ eclass = self.__class__ - return eclass(self.parent(), dual=self._dual.omega() ) + return eclass(self.parent(), dual=self._dual.omega()) omega_involution = omega @@ -784,7 +783,7 @@ def _add_(self, y): 4*m[1, 1, 1] + 3*m[2, 1] + 2*m[3] """ eclass = self.__class__ - return eclass(self.parent(), dual=(self.dual()+y.dual())) + return eclass(self.parent(), dual=(self.dual() + y.dual())) def _neg_(self): """ @@ -822,7 +821,7 @@ def _sub_(self, y): d_m[2, 1] - d_m[3] """ eclass = self.__class__ - return eclass(self.parent(), dual=(self.dual()-y.dual())) + return eclass(self.parent(), dual=(self.dual() - y.dual())) def _div_(self, y): """ @@ -843,7 +842,7 @@ def _div_(self, y): sage: a/2 # indirect doctest 1/2*d_m[2, 1] + 1/2*d_m[3] """ - return self*(~y) + return self * (~y) def __invert__(self): """ @@ -922,6 +921,7 @@ class DualBasisFunctor(SymmetricFunctionsFunctor): sage: w.dual_basis().construction() (SymmetricFunctionsFunctor[dual Witt], Integer Ring) """ + def __init__(self, basis): r""" Initialize the functor. @@ -962,8 +962,7 @@ def _apply_functor(self, R): Dual basis to Dual basis to Symmetric Functions over Rational Field in the monomial basis """ dual_basis = self._dual_basis.change_ring(R) - return self._basis(dual_basis, self._scalar, self._scalar_name, - self._basis_name, self._prefix) + return self._basis(dual_basis, self._scalar, self._scalar_name, self._basis_name, self._prefix) def _repr_(self): """ @@ -985,6 +984,4 @@ def _repr_(self): # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.sf.dual', - 'SymmetricFunctionAlgebraElement_dual', - SymmetricFunctionAlgebra_dual.Element) +register_unpickle_override('sage.combinat.sf.dual', 'SymmetricFunctionAlgebraElement_dual', SymmetricFunctionAlgebra_dual.Element) diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index fabfa9aa8ce..a96fd296578 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -92,8 +92,10 @@ def coproduct_on_generators(self, i): sage: e.coproduct_on_generators(0) e[] # e[] """ + def P(i): return Partition([i]) if i else Partition([]) + T = self.tensor_square() return T.sum_of_monomials((P(j), P(i - j)) for j in range(i + 1)) @@ -278,10 +280,7 @@ def verschiebung(self, n): """ parent = self.parent() e_coords_of_self = self.monomial_coefficients().items() - dct = {Partition([i // n for i in lam]): - (-1) ** (sum(lam) - (sum(lam) // n)) * coeff - for (lam, coeff) in e_coords_of_self - if all(not i % n for i in lam)} + dct = {Partition([i // n for i in lam]): (-1) ** (sum(lam) - (sum(lam) // n)) * coeff for (lam, coeff) in e_coords_of_self if all(not i % n for i in lam)} result_in_e_basis = parent._from_dict(dct) return parent(result_in_e_basis) @@ -397,8 +396,7 @@ def principal_specialization(self, n=infinity, q=None): if n == 1: R = self.base_ring() mc = self.monomial_coefficients(copy=False).items() - return R.sum(c for partition, c in mc - if not partition or partition[0] == 1) + return R.sum(c for partition, c in mc if not partition or partition[0] == 1) from sage.combinat.q_analogues import q_binomial @@ -409,6 +407,7 @@ def get_variable(ring, name): from sage.rings.polynomial.polynomial_ring_constructor import ( PolynomialRing, ) + return PolynomialRing(ring, name).gen() else: raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) @@ -421,12 +420,9 @@ def get_variable(ring, name): raise ValueError("the stable principal specialization at q=1 is not defined") f = lambda partition: prod(binomial(n, part) for part in partition) elif n == infinity: - f = lambda partition: prod(q**binomial(part, 2)/prod((1-q**i) - for i in range(1, part+1)) - for part in partition) + f = lambda partition: prod(q ** binomial(part, 2) / prod((1 - q**i) for i in range(1, part + 1)) for part in partition) else: - f = lambda partition: prod(q**binomial(part, 2)*q_binomial(n, part, q=q) - for part in partition) + f = lambda partition: prod(q ** binomial(part, 2) * q_binomial(n, part, q=q) for part in partition) return self.parent()._apply_module_morphism(self, f, q.parent()) @@ -508,6 +504,7 @@ def get_variable(ring, name): from sage.rings.polynomial.polynomial_ring_constructor import ( PolynomialRing, ) + return PolynomialRing(ring, name).gen() else: raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) @@ -522,7 +519,7 @@ def f(partition): for part in partition: n += part m *= factorial(part) - return t**n/m + return t**n / m return self.parent()._apply_module_morphism(self, f, t.parent()) @@ -539,7 +536,7 @@ def f(partition): m = 1 for part in partition: n += part - m *= q**binomial(part, 2)/q_factorial(part, q=q) + m *= q ** binomial(part, 2) / q_factorial(part, q=q) return t**n * m @@ -549,6 +546,4 @@ def f(partition): # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.sf.elementary', - 'SymmetricFunctionAlgebraElement_elementary', - SymmetricFunctionAlgebra_elementary.Element) +register_unpickle_override('sage.combinat.sf.elementary', 'SymmetricFunctionAlgebraElement_elementary', SymmetricFunctionAlgebra_elementary.Element) diff --git a/src/sage/combinat/sf/hall_littlewood.py b/src/sage/combinat/sf/hall_littlewood.py index 6bcc6ef8e20..db6364119b4 100644 --- a/src/sage/combinat/sf/hall_littlewood.py +++ b/src/sage/combinat/sf/hall_littlewood.py @@ -111,9 +111,9 @@ def __init__(self, Sym, t): self._name_suffix = "" if str(t) != 't': self._name_suffix += " with t=%s" % t - self._name = "Hall-Littlewood polynomials"+self._name_suffix + self._name = "Hall-Littlewood polynomials" + self._name_suffix - def symmetric_function_ring( self ): + def symmetric_function_ring(self): r""" Return the ring of symmetric functions associated to the class of Hall-Littlewood symmetric functions. @@ -130,7 +130,7 @@ def symmetric_function_ring( self ): """ return self._sym - def base_ring( self ): + def base_ring(self): r""" Return the base ring of the symmetric functions where the Hall-Littlewood symmetric functions live. @@ -374,10 +374,7 @@ def __init__(self, hall_littlewood): Symmetric Functions over Rational Field in the Hall-Littlewood P with t=2 basis """ s = self.__class__.__name__[15:].capitalize() - sfa.SymmetricFunctionAlgebra_generic.__init__( - self, hall_littlewood._sym, - basis_name="Hall-Littlewood " + s + hall_littlewood._name_suffix, - prefix="HL" + s) + sfa.SymmetricFunctionAlgebra_generic.__init__(self, hall_littlewood._sym, basis_name="Hall-Littlewood " + s + hall_littlewood._name_suffix, prefix="HL" + s) self.t = hall_littlewood.t self._sym = hall_littlewood._sym self._hall_littlewood = hall_littlewood @@ -390,7 +387,7 @@ def __init__(self, hall_littlewood): if hasattr(self, "_s_cache"): # temporary until Hom(GradedHopfAlgebrasWithBasis work better) category = ModulesWithBasis(self._sym.base_ring()) - self .register_coercion(SetMorphism(Hom(self._s, self, category), self._s_to_self)) + self.register_coercion(SetMorphism(Hom(self._s, self, category), self._s_to_self)) self._s.register_coercion(SetMorphism(Hom(self, self._s, category), self._self_to_s)) def construction(self): @@ -406,11 +403,7 @@ def construction(self): (SymmetricFunctionsFunctor[Hall-Littlewood P with t=2], Rational Field) """ - return (sfa.SymmetricFunctionsFamilyFunctor(self, - HallLittlewood, - self.basis_name(), - self.t), - self.base_ring()) + return (sfa.SymmetricFunctionsFamilyFunctor(self, HallLittlewood, self.basis_name(), self.t), self.base_ring()) def _s_to_self(self, x): r""" @@ -435,8 +428,7 @@ def _s_to_self(self, x): sage: P(s[2,1]) 6*HLP[1, 1, 1] + HLP[2, 1] """ - return self._from_cache(x, self._s_cache, self._s_to_self_cache, - t=self.t) + return self._from_cache(x, self._s_cache, self._s_to_self_cache, t=self.t) def _self_to_s(self, x): r""" @@ -462,8 +454,7 @@ def _self_to_s(self, x): sage: s(P[2,1]) -6*s[1, 1, 1] + s[2, 1] """ - return self._s._from_cache(x, self._s_cache, self._self_to_s_cache, - t=self.t) + return self._s._from_cache(x, self._s_cache, self._self_to_s_cache, t=self.t) def transition_matrix(self, basis, n): r""" @@ -510,7 +501,7 @@ def transition_matrix(self, basis, n): m = [] for row_part in Plist: z = basis(self(row_part)) - m.append( [z.coefficient(col_part) for col_part in Plist] ) + m.append([z.coefficient(col_part) for col_part in Plist]) return matrix(m) def product(self, left, right): @@ -680,14 +671,14 @@ def scalar_hl(self, x, t=None): t = parent.t p = parent.realization_of().power() f = lambda part1, part2: part1.centralizer_size(t=t) - return parent._apply_multi_module_morphism(p(self), p(x), f, - orthogonal=True) + return parent._apply_multi_module_morphism(p(self), p(x), f, orthogonal=True) ########### # P basis # ########### + class HallLittlewood_p(HallLittlewood_generic): r""" A class representing the Hall-Littlewood `P` basis of symmetric functions @@ -747,10 +738,10 @@ def _q_to_p_normalization(self, m): t^2 - 2*t + 1 """ t = self.t - coeff = (1-t)**len(m) + coeff = (1 - t) ** len(m) for i in m.to_exp(): - for j in range(1,i+1): - coeff *= (1-t**j)/(1-t) + for j in range(1, i + 1): + coeff *= (1 - t**j) / (1 - t) return coeff def _s_to_self_base(self, part): @@ -779,10 +770,11 @@ def _s_to_self_base(self, part): [0, 1, t^2 + t] """ from sage.combinat.sf.kfpoly import schur_to_hl + t = QQt.gen() zero = self.base_ring().zero() res_dict = schur_to_hl(part, t) - f = lambda part2: res_dict.get(part2,zero) + f = lambda part2: res_dict.get(part2, zero) return f def _s_cache(self, n): @@ -813,15 +805,14 @@ def _s_cache(self, n): sage: l(HLP._s_to_self_cache[2]) [([1, 1], [([1, 1], 1)]), ([2], [([1, 1], t), ([2], 1)])] """ - self._invert_morphism(n, QQt, self._self_to_s_cache, - self._s_to_self_cache, to_self_function=self._s_to_self_base, - upper_triangular=True, ones_on_diagonal=True) + self._invert_morphism(n, QQt, self._self_to_s_cache, self._s_to_self_cache, to_self_function=self._s_to_self_base, upper_triangular=True, ones_on_diagonal=True) ########### # Q basis # ########### + class HallLittlewood_q(HallLittlewood_generic): class Element(HallLittlewood_generic.Element): pass @@ -862,8 +853,7 @@ def __init__(self, hall_littlewood): # temporary until Hom(GradedHopfAlgebrasWithBasis work better) category = ModulesWithBasis(self.base_ring()) - phi = self.module_morphism(diagonal=self._P._q_to_p_normalization, - codomain=self._P, category=category) + phi = self.module_morphism(diagonal=self._P._q_to_p_normalization, codomain=self._P, category=category) self._P.register_coercion(phi) self.register_coercion(~phi) @@ -896,10 +886,10 @@ def _p_to_q_normalization(self, m): 1/(t^2 - 2*t + 1) """ t = self.t - coeff = 1/(1-t)**len(m) + coeff = 1 / (1 - t) ** len(m) for i in m.to_exp(): - for j in range(1,i+1): - coeff *= (1-t)/(1-t**j) + for j in range(1, i + 1): + coeff *= (1 - t) / (1 - t**j) return coeff @@ -907,6 +897,7 @@ def _p_to_q_normalization(self, m): # Qp basis # ############ + class HallLittlewood_qp(HallLittlewood_generic): class Element(HallLittlewood_generic.Element): @@ -986,7 +977,7 @@ def _to_s(self, part): if not part: return lambda part2: QQt.one() - res = hall_littlewood(part) # call to symmetrica (returns in variable x) + res = hall_littlewood(part) # call to symmetrica (returns in variable x) f = lambda part2: res.coefficient(part2).subs(x=t) return f @@ -1014,10 +1005,7 @@ def _s_cache(self, n): sage: l(HLQp._self_to_s_cache[2]) [([1, 1], [([1, 1], 1), ([2], t)]), ([2], [([2], 1)])] """ - self._invert_morphism(n, QQt, self._self_to_s_cache, - self._s_to_self_cache, - to_other_function=self._to_s, - lower_triangular=True, ones_on_diagonal=True) + self._invert_morphism(n, QQt, self._self_to_s_cache, self._s_to_self_cache, to_other_function=self._to_s, lower_triangular=True, ones_on_diagonal=True) # Unpickling backward compatibility diff --git a/src/sage/combinat/sf/hecke.py b/src/sage/combinat/sf/hecke.py index faf0c69cc99..749eb5f23b4 100644 --- a/src/sage/combinat/sf/hecke.py +++ b/src/sage/combinat/sf/hecke.py @@ -121,6 +121,7 @@ class HeckeCharacter(SymmetricFunctionAlgebra_multiplicative): - [Ram1991]_ - [RR1997]_ """ + @staticmethod def __classcall__(cls, Sym, q='q'): """ @@ -174,17 +175,13 @@ def __init__(self, sym, q): True """ self.q = q - SymmetricFunctionAlgebra_multiplicative.__init__(self, sym, - basis_name="Hecke character with q={}".format(self.q), - prefix='qbar') + SymmetricFunctionAlgebra_multiplicative.__init__(self, sym, basis_name="Hecke character with q={}".format(self.q), prefix='qbar') self._p = sym.power() # temporary until Hom(GradedHopfAlgebrasWithBasis work better) # category = ModulesWithBasis(self._sym.base_ring()) - self.register_coercion(self._p._module_morphism(self._p_to_qbar_on_basis, - codomain=self)) - self._p.register_coercion(self._module_morphism(self._qbar_to_p_on_basis, - codomain=self._p)) + self.register_coercion(self._p._module_morphism(self._p_to_qbar_on_basis, codomain=self)) + self._p.register_coercion(self._module_morphism(self._qbar_to_p_on_basis, codomain=self._p)) def construction(self): """ @@ -201,8 +198,8 @@ def construction(self): """ from sage.combinat.sf.sfa import SymmetricFunctionsFunctor - return (SymmetricFunctionsFunctor(self, self.basis_name(), self.q), - self.base_ring()) + + return (SymmetricFunctionsFunctor(self, self.basis_name(), self.q), self.base_ring()) def _p_to_qbar_on_generator(self, n): r""" @@ -227,10 +224,9 @@ def _p_to_qbar_on_generator(self, n): return self([1]) q = self.q if q**n == self.base_ring().one(): - raise ValueError("the parameter q=%s must not be a %s root of unity" % (q,n)) - out = n * self([n]) - sum((q**i-1) * self._p_to_qbar_on_generator(i) - * self([n-i]) for i in range(1,n) if q**i != 1) - return out*(q-1) / (q**n-1) + raise ValueError("the parameter q=%s must not be a %s root of unity" % (q, n)) + out = n * self([n]) - sum((q**i - 1) * self._p_to_qbar_on_generator(i) * self([n - i]) for i in range(1, n) if q ** i != 1) + return out * (q - 1) / (q**n - 1) def _p_to_qbar_on_basis(self, mu): r""" @@ -277,11 +273,7 @@ def _qbar_to_p_on_generator(self, n): return self._p([1]) q = self.q BR = self.base_ring() - return q**(n-1) * self._p.sum(sum(q**(-i) for i in range(mu[0])) - * BR.prod(1 - q**(-p) for p in mu[1:]) - * self._p(mu) / mu.centralizer_size() - for mu in Partitions(n) - if not any(q**p == 1 for p in mu[1:])) + return q ** (n - 1) * self._p.sum(sum(q ** (-i) for i in range(mu[0])) * BR.prod(1 - q ** (-p) for p in mu[1:]) * self._p(mu) / mu.centralizer_size() for mu in Partitions(n) if not any(q**p == 1 for p in mu[1:])) def _qbar_to_p_on_basis(self, mu): r""" @@ -326,10 +318,11 @@ def coproduct_on_generators(self, r): sage: qbar[2].coproduct() qbar[] # qbar[2] + (q-1)*qbar[1] # qbar[1] + qbar[2] # qbar[] """ + def P(i): return _Partitions([i]) if i else _Partitions([]) + T = self.tensor_square() one = self.base_ring().one() q = self.q - return T.sum_of_terms(((P(j), P(r-j)), one if j in [0,r] else q-one) - for j in range(r+1)) + return T.sum_of_terms(((P(j), P(r - j)), one if j in [0, r] else q - one) for j in range(r + 1)) diff --git a/src/sage/combinat/sf/homogeneous.py b/src/sage/combinat/sf/homogeneous.py index fa74bb9ae49..3c58e8afd7d 100644 --- a/src/sage/combinat/sf/homogeneous.py +++ b/src/sage/combinat/sf/homogeneous.py @@ -120,10 +120,12 @@ def coproduct_on_generators(self, i): sage: h.coproduct_on_generators(0) h[] # h[] """ + def P(i): return Partition([i]) if i else Partition([]) + T = self.tensor_square() - return T.sum_of_monomials( (P(j), P(i-j)) for j in range(i+1) ) + return T.sum_of_monomials((P(j), P(i - j)) for j in range(i + 1)) def _magma_init_(self, magma): """ @@ -236,7 +238,7 @@ def expand(self, n, alphabet='x'): sage: (3*h([])).expand(0) 3 """ - if n == 0: # Symmetrica crashes otherwise... + if n == 0: # Symmetrica crashes otherwise... return self.counit() condition = lambda part: False return self._expand(condition, n, alphabet) @@ -316,6 +318,7 @@ def get_variable(ring, name): from sage.rings.polynomial.polynomial_ring_constructor import ( PolynomialRing, ) + return PolynomialRing(ring, name).gen() else: raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) @@ -326,11 +329,11 @@ def get_variable(ring, name): if q == 1: if n == infinity: raise ValueError("the stable principal specialization at q=1 is not defined") - f = lambda partition: prod(binomial(n+part-1, part) for part in partition) + f = lambda partition: prod(binomial(n + part - 1, part) for part in partition) elif n == infinity: - f = lambda partition: prod(1/prod((1-q**i) for i in range(1, part+1)) for part in partition) + f = lambda partition: prod(1 / prod((1 - q**i) for i in range(1, part + 1)) for part in partition) else: - f = lambda partition: prod(q_binomial(n+part-1, part, q=q) for part in partition) + f = lambda partition: prod(q_binomial(n + part - 1, part, q=q) for part in partition) return self.parent()._apply_module_morphism(self, f, q.parent()) @@ -421,6 +424,7 @@ def get_variable(ring, name): from sage.rings.polynomial.polynomial_ring_constructor import ( PolynomialRing, ) + return PolynomialRing(ring, name).gen() else: raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) @@ -435,7 +439,7 @@ def f(partition): for part in partition: n += part m *= factorial(part) - return t**n/m + return t**n / m return self.parent()._apply_module_morphism(self, f, t.parent()) @@ -453,7 +457,7 @@ def f(partition): for part in partition: n += part m *= q_factorial(part, q=q) - return t**n/m + return t**n / m return self.parent()._apply_module_morphism(self, f, t.parent()) @@ -461,6 +465,4 @@ def f(partition): # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.sf.homogeneous', - 'SymmetricFunctionAlgebraElement_homogeneous', - SymmetricFunctionAlgebra_homogeneous.Element) +register_unpickle_override('sage.combinat.sf.homogeneous', 'SymmetricFunctionAlgebraElement_homogeneous', SymmetricFunctionAlgebra_homogeneous.Element) diff --git a/src/sage/combinat/sf/jack.py b/src/sage/combinat/sf/jack.py index 1df605a4e74..0ca797acdf8 100644 --- a/src/sage/combinat/sf/jack.py +++ b/src/sage/combinat/sf/jack.py @@ -79,7 +79,7 @@ def __init__(self, Sym, t): self._name_suffix = "" if str(t) != 't': self._name_suffix += " with t=%s" % t - self._name = "Jack polynomials"+self._name_suffix+" over "+repr(Sym.base_ring()) + self._name = "Jack polynomials" + self._name_suffix + " over " + repr(Sym.base_ring()) def __repr__(self): r""" @@ -98,7 +98,7 @@ def __repr__(self): """ return self._name - def base_ring( self ): + def base_ring(self): r""" Return the base ring of the symmetric functions in which the Jack symmetric functions live. @@ -117,7 +117,7 @@ def base_ring( self ): """ return self._sym.base_ring() - def symmetric_function_ring( self ): + def symmetric_function_ring(self): r""" Return the base ring of the symmetric functions of the Jack symmetric function bases @@ -370,6 +370,7 @@ def Qp(self): """ return JackPolynomials_qp(self) + ################################################################### @@ -395,8 +396,7 @@ def c1(part, t): sage: [c1(p,t) for p in Partitions(3)] [2*t^2 + 3*t + 1, t + 2, 6] """ - return prod([1+t*part.arm_lengths(flat=True)[i]+part.leg_lengths(flat=True)[i] for i in range(sum(part))], - t.parent().one()) + return prod([1 + t * part.arm_lengths(flat=True)[i] + part.leg_lengths(flat=True)[i] for i in range(sum(part))], t.parent().one()) def c2(part, t): @@ -422,8 +422,7 @@ def c2(part, t): sage: [c2(p,t) for p in Partitions(3)] [6*t^3, 2*t^3 + t^2, t^3 + 3*t^2 + 2*t] """ - return prod([t+t*part.arm_lengths(flat=True)[i]+part.leg_lengths(flat=True)[i] for i in range(sum(part))], - t.parent().one()) + return prod([t + t * part.arm_lengths(flat=True)[i] + part.leg_lengths(flat=True)[i] for i in range(sum(part))], t.parent().one()) def normalize_coefficients(self, c): @@ -459,14 +458,14 @@ def normalize_coefficients(self, c): denom = c.denominator() numer = c.numerator() - #Clear the denominators + # Clear the denominators a = lcm([i.denominator() for i in denom.coefficients(sparse=False)]) b = lcm([i.denominator() for i in numer.coefficients(sparse=False)]) l = Integer(a).lcm(Integer(b)) denom *= l numer *= l - #Divide through by the gcd of the numerators + # Divide through by the gcd of the numerators a = gcd([i.numerator() for i in denom.coefficients(sparse=False)]) b = gcd([i.numerator() for i in numer.coefficients(sparse=False)]) l = Integer(a).gcd(Integer(b)) @@ -477,6 +476,7 @@ def normalize_coefficients(self, c): return c.parent()(numer, denom) return c + #################################################################### @@ -500,10 +500,7 @@ def __init__(self, jack): Rational Field """ s = self.__class__.__name__[16:].capitalize() - sfa.SymmetricFunctionAlgebra_generic.__init__( - self, jack._sym, - basis_name="Jack " + s + jack._name_suffix, - prefix="Jack" + s) + sfa.SymmetricFunctionAlgebra_generic.__init__(self, jack._sym, basis_name="Jack " + s + jack._name_suffix, prefix="Jack" + s) self.t = jack.t self._sym = jack._sym self._jack = jack @@ -514,13 +511,13 @@ def __init__(self, jack): # temporary until Hom(GradedHopfAlgebrasWithBasis work better) category = ModulesWithBasis(self._sym.base_ring()) self._m = self._sym.monomial() - self .register_coercion(SetMorphism(Hom(self._m, self, category), self._m_to_self)) + self.register_coercion(SetMorphism(Hom(self._m, self, category), self._m_to_self)) self._m.register_coercion(SetMorphism(Hom(self, self._m, category), self._self_to_m)) if hasattr(self, "_h_cache"): # temporary until Hom(GradedHopfAlgebrasWithBasis work better) category = ModulesWithBasis(self._sym.base_ring()) self._h = self._sym.homogeneous() - self .register_coercion(SetMorphism(Hom(self._h, self, category), self._h_to_self)) + self.register_coercion(SetMorphism(Hom(self._h, self, category), self._h_to_self)) self._h.register_coercion(SetMorphism(Hom(self, self._h, category), self._self_to_h)) def construction(self): @@ -537,10 +534,7 @@ def construction(self): (SymmetricFunctionsFunctor[Jack P], Fraction Field of Univariate Polynomial Ring in t over Rational Field) """ - return (sfa.SymmetricFunctionsFamilyFunctor(self, Jack, - self.basis_name(), - self.t), - self.base_ring()) + return (sfa.SymmetricFunctionsFamilyFunctor(self, Jack, self.basis_name(), self.t), self.base_ring()) def _m_to_self(self, x): r""" @@ -566,8 +560,7 @@ def _m_to_self(self, x): sage: JP(m[2,1]) -3/2*JackP[1, 1, 1] + JackP[2, 1] """ - return self._from_cache(x, self._m_cache, self._m_to_self_cache, - t=self.t) + return self._from_cache(x, self._m_cache, self._m_to_self_cache, t=self.t) def _self_to_m(self, x): r""" @@ -593,8 +586,7 @@ def _self_to_m(self, x): sage: m(JP[2,1]) 3/2*m[1, 1, 1] + m[2, 1] """ - return self._m._from_cache(x, self._m_cache, self._self_to_m_cache, - t=self.t) + return self._m._from_cache(x, self._m_cache, self._self_to_m_cache, t=self.t) def c1(self, part): r""" @@ -768,12 +760,11 @@ def coproduct_by_coercion(self, elt): JackP[] # JackP[2, 2] + (2/(t+1))*JackP[1] # JackP[2, 1] + ((8*t+4)/(t^3+4*t^2+5*t+2))*JackP[1, 1] # JackP[1, 1] + JackP[2] # JackP[2] + (2/(t+1))*JackP[2, 1] # JackP[1] + JackP[2, 2] # JackP[] """ from sage.categories.tensor import tensor + s = self.realization_of().schur() - g = self.tensor_square().sum(coeff*tensor([self(s[x]), self(s[y])]) - for ((x,y), coeff) in s(elt).coproduct()) + g = self.tensor_square().sum(coeff * tensor([self(s[x]), self(s[y])]) for ((x, y), coeff) in s(elt).coproduct()) normalize = self._normalize_coefficients - return self.tensor_square().sum(normalize(coeff)*tensor([self(x), self(y)]) - for ((x,y), coeff) in g) + return self.tensor_square().sum(normalize(coeff) * tensor([self(x), self(y)]) for ((x, y), coeff) in g) class Element(sfa.SymmetricFunctionAlgebra_generic.Element): def scalar_jack(self, x, t=None): @@ -833,9 +824,10 @@ def part_scalar_jack(part1, part2, t): """ if part1 != part2: return 0 - return part1.centralizer_size()*t**len(part1) + return part1.centralizer_size() * t ** len(part1) + -#P basis +# P basis class JackPolynomials_p(JackPolynomials_generic): @@ -902,10 +894,8 @@ def _m_cache(self, n): t = QQt.gen() monomial = SymmetricFunctions(QQt).monomial() JP = SymmetricFunctions(QQt).jack().P() - JP._gram_schmidt(n, monomial, lambda p: part_scalar_jack(p, p, t), - self._self_to_m_cache[n], upper_triangular=True) - JP._invert_morphism(n, QQt, self._self_to_m_cache, - self._m_to_self_cache, to_other_function=self._to_m) + JP._gram_schmidt(n, monomial, lambda p: part_scalar_jack(p, p, t), self._self_to_m_cache[n], upper_triangular=True) + JP._invert_morphism(n, QQt, self._self_to_m_cache, self._m_to_self_cache, to_other_function=self._to_m) def _to_m(self, part): r""" @@ -1040,7 +1030,8 @@ def scalar_jack(self, x, t=None): return P._apply_multi_module_morphism(self, x, P.scalar_jack_basis, orthogonal=True) return JackPolynomials_generic.Element.scalar_jack(self, x, t) -#J basis + +# J basis class JackPolynomials_j(JackPolynomials_generic): @@ -1068,17 +1059,16 @@ def __init__(self, jack): self._P = self._jack.P() # temporary until Hom(GradedHopfAlgebrasWithBasis) works better category = ModulesWithBasis(self.base_ring()) - phi = self.module_morphism(diagonal=self.c1, - codomain=self._P, category=category) + phi = self.module_morphism(diagonal=self.c1, codomain=self._P, category=category) # should use module_morphism(on_coeffs = ...) once it exists self._P.register_coercion(self._P._normalize_morphism(category) * phi) - self .register_coercion(self ._normalize_morphism(category) * ~phi) + self.register_coercion(self._normalize_morphism(category) * ~phi) class Element(JackPolynomials_generic.Element): pass -#Q basis +# Q basis class JackPolynomials_q(JackPolynomials_generic): def __init__(self, jack): @@ -1104,8 +1094,7 @@ def __init__(self, jack): self._P = self._jack.P() # temporary until Hom(GradedHopfAlgebrasWithBasis) works better category = ModulesWithBasis(self.base_ring()) - phi = self._P.module_morphism(diagonal=self._P.scalar_jack_basis, - codomain=self, category=category) + phi = self._P.module_morphism(diagonal=self._P.scalar_jack_basis, codomain=self, category=category) self.register_coercion(self._normalize_morphism(category) * phi) self._P.register_coercion(self._P._normalize_morphism(category) * ~phi) @@ -1219,7 +1208,7 @@ def _h_cache(self, n): to_cache_2[la][mu] = from_cache_1[mu][la] to_cache_1[la][mu] = from_cache_2[mu][la] - def _self_to_h( self, x ): + def _self_to_h(self, x): r""" Isomorphism from ``self`` to the homogeneous basis. @@ -1243,8 +1232,7 @@ def _self_to_h( self, x ): sage: h(JQp[2,1]) h[2, 1] - 3/5*h[3] """ - return self._h._from_cache(x, self._h_cache, self._self_to_h_cache, - t=self.t) + return self._h._from_cache(x, self._h_cache, self._self_to_h_cache, t=self.t) def _h_to_self(self, x): r""" @@ -1270,8 +1258,7 @@ def _h_to_self(self, x): sage: JQp(h[2,1]) JackQp[2, 1] + 3/5*JackQp[3] """ - return self._from_cache(x, self._h_cache, self._h_to_self_cache, - t=self.t) + return self._from_cache(x, self._h_cache, self._h_to_self_cache, t=self.t) def coproduct_by_coercion(self, elt): r""" @@ -1296,16 +1283,17 @@ def coproduct_by_coercion(self, elt): h = elt.parent().realization_of().h() parent = elt.parent() from sage.categories.tensor import tensor + cfunc = lambda x, y: tensor([parent(x), parent(y)]) - cprod = h(elt).coproduct().apply_multilinear_morphism( cfunc ) - normalize = lambda c: normalize_coefficients( parent, c ) - return cprod.parent().sum(normalize(coeff)*tensor([parent(x), parent(y)]) - for ((x,y), coeff) in cprod) + cprod = h(elt).coproduct().apply_multilinear_morphism(cfunc) + normalize = lambda c: normalize_coefficients(parent, c) + return cprod.parent().sum(normalize(coeff) * tensor([parent(x), parent(y)]) for ((x, y), coeff) in cprod) class Element(JackPolynomials_generic.Element): pass -#Zonal polynomials ( =P(at t=2) ) + +# Zonal polynomials ( =P(at t=2) ) class SymmetricFunctionAlgebra_zonal(sfa.SymmetricFunctionAlgebra_generic): @@ -1330,12 +1318,11 @@ def __init__(self, Sym): self._sym = Sym self._jack = self._sym.jack(t=2) self._P = self._jack.P() - #self._m_to_self_cache = {} Now that we compute Jacks once, there is a global cache - #self._self_to_m_cache = {} and we don't need to compute it separately for zonals - sfa.SymmetricFunctionAlgebra_generic.__init__(self, self._sym, - prefix='Z', basis_name='zonal') + # self._m_to_self_cache = {} Now that we compute Jacks once, there is a global cache + # self._self_to_m_cache = {} and we don't need to compute it separately for zonals + sfa.SymmetricFunctionAlgebra_generic.__init__(self, self._sym, prefix='Z', basis_name='zonal') category = ModulesWithBasis(self._sym.base_ring()) - self .register_coercion(SetMorphism(Hom(self._P, self, category), self.sum_of_terms)) + self.register_coercion(SetMorphism(Hom(self._P, self, category), self.sum_of_terms)) self._P.register_coercion(SetMorphism(Hom(self, self._P, category), self._P.sum_of_terms)) def product(self, left, right): @@ -1396,7 +1383,7 @@ def scalar_zonal(self, x): [ 0 0 48] """ P = self.parent()._P - return P(self).scalar_jack(P(x),2) + return P(self).scalar_jack(P(x), 2) # Backward compatibility for unpickling @@ -1406,4 +1393,4 @@ def scalar_zonal(self, x): register_unpickle_override('sage.combinat.sf.jack', 'JackPolynomial_j', JackPolynomials_j.Element) register_unpickle_override('sage.combinat.sf.jack', 'JackPolynomial_p', JackPolynomials_p.Element) register_unpickle_override('sage.combinat.sf.jack', 'JackPolynomial_q', JackPolynomials_q.Element) -#register_unpickle_override('sage.combinat.sf.jack', 'SymmetricFunctionAlgebra_zonal', SymmetricFunctionAlgebra_zonal.Element) +# register_unpickle_override('sage.combinat.sf.jack', 'SymmetricFunctionAlgebra_zonal', SymmetricFunctionAlgebra_zonal.Element) diff --git a/src/sage/combinat/sf/k_dual.py b/src/sage/combinat/sf/k_dual.py index 572a3e32301..aea86969799 100644 --- a/src/sage/combinat/sf/k_dual.py +++ b/src/sage/combinat/sf/k_dual.py @@ -130,7 +130,7 @@ def __init__(self, Sym, k, t='t'): R = Sym.base_ring() self.k = k self.t = R(t) - self._base = R # Won't be needed when CategoryObject won't override anymore base_ring + self._base = R # Won't be needed when CategoryObject won't override anymore base_ring self._sym = Sym if t == 1: self._quotient_basis = Sym.m() @@ -186,7 +186,7 @@ def _repr_(self): ending = "" if str(self.t) != 't': ending = ' with t=%s' % (self.t) - return "%s-Bounded Quotient of Symmetric Functions over %s" % (self.k, self.base_ring())+ending + return "%s-Bounded Quotient of Symmetric Functions over %s" % (self.k, self.base_ring()) + ending def kmonomial(self): r""" @@ -277,7 +277,7 @@ def _G_to_km_on_basis_single_level(self, w, m): sage: Q._G_to_km_on_basis_single_level(W.an_element(), 5) -4*m3[1, 1, 1, 1, 1] """ - kB = self._sym.kBoundedSubspace(self.k,t=1) + kB = self._sym.kBoundedSubspace(self.k, t=1) g = kB.K_kschur() mon = self.km() if m < w.length(): @@ -309,7 +309,7 @@ def _AffineGrothendieck(self, w, m): sage: Q._AffineGrothendieck(W.an_element(), 5) m3[1, 1, 1, 1] - 4*m3[1, 1, 1, 1, 1] """ - return sum(self._G_to_km_on_basis_single_level(w,j) for j in range(w.length(),m+1)) + return sum(self._G_to_km_on_basis_single_level(w, j) for j in range(w.length(), m + 1)) @cached_method def _AffineGrothendieckPolynomial(self, la, m): @@ -331,7 +331,7 @@ def _AffineGrothendieckPolynomial(self, la, m): sage: Q._AffineGrothendieckPolynomial(Partition([2,1]),4) 2*m3[1, 1, 1] - 8*m3[1, 1, 1, 1] + m3[2, 1] - 3*m3[2, 1, 1] - m3[2, 2] """ - return self._AffineGrothendieck(la.to_core(self.k).to_grassmannian(),m) + return self._AffineGrothendieck(la.to_core(self.k).to_grassmannian(), m) def AffineGrothendieckPolynomial(self, la, m): r""" @@ -354,7 +354,7 @@ def AffineGrothendieckPolynomial(self, la, m): """ if la == []: return self.a_realization().one() - return self._AffineGrothendieckPolynomial(Partition(la),m) + return self._AffineGrothendieckPolynomial(Partition(la), m) def _an_element_(self): r""" @@ -449,7 +449,7 @@ def realizations(self): sage: all( rzn(m[3,2,1]).lift() == m[3,2,1] for rzn in kQ.realizations()) True """ - return [ self.km(), self.kHLP(), self.affineSchur(), self.dual_k_Schur()] + return [self.km(), self.kHLP(), self.affineSchur(), self.dual_k_Schur()] class KBoundedQuotientBases(Category_realization_of_parent): @@ -543,14 +543,14 @@ def _element_constructor_(self, x): """ R = self.base_ring() - #Coerce ints to Integers + # Coerce ints to Integers if isinstance(x, int): x = Integer(x) if x in R: if x == 0: return self.zero() raise TypeError("do not know how to make x (= %s) an element of %s" % (x, self)) - #x is an element of the basis enumerated set; + # x is an element of the basis enumerated set; elif x in self._indices: return self.monomial(self._indices(x)) raise TypeError("do not know how to make x (= %s) an element of self (=%s)" % (x, self)) @@ -605,7 +605,7 @@ def _repr_term(self, c): sage: F[3,2] # indirect doctest F3[3, 2] """ - return self.prefix()+str(c) + return self.prefix() + str(c) @cached_method def one_basis(self): @@ -758,7 +758,7 @@ def product(self, x, y): sage: km.product(dks[2,1],dks[1,1]) 20*m3[1, 1, 1, 1, 1] + 9*m3[2, 1, 1, 1] + 4*m3[2, 2, 1] + 2*m3[3, 1, 1] + m3[3, 2] """ - return self( x.lift() * y.lift() ) + return self(x.lift() * y.lift()) def antipode(self, element): r""" @@ -840,9 +840,9 @@ def coproduct(self, element): m3[] # m3[3, 2] + m3[2] # m3[3] + m3[3] # m3[2] + m3[3, 2] # m3[] """ from sage.categories.tensor import tensor + base = element.lift().parent() - return self.tensor_square().sum(coeff * tensor([self(base[x]), self(base[y])]) - for ((x,y), coeff) in element.lift().coproduct()) + return self.tensor_square().sum(coeff * tensor([self(base[x]), self(base[y])]) for ((x, y), coeff) in element.lift().coproduct()) def counit(self, element): r""" @@ -892,10 +892,7 @@ def __init__(self, kBoundedRing, prefix): sage: isinstance(km, sage.combinat.sf.k_dual.KBoundedQuotientBasis) True """ - CombinatorialFreeModule.__init__(self, kBoundedRing.base_ring(), - kBoundedRing.indices(), - category=KBoundedQuotientBases(kBoundedRing), - prefix='%s%d' % (prefix, kBoundedRing.k)) + CombinatorialFreeModule.__init__(self, kBoundedRing.base_ring(), kBoundedRing.indices(), category=KBoundedQuotientBases(kBoundedRing), prefix='%s%d' % (prefix, kBoundedRing.k)) self._kBoundedRing = kBoundedRing self.k = kBoundedRing.k @@ -934,7 +931,7 @@ def __init__(self, kBoundedRing): """ KBoundedQuotientBasis.__init__(self, kBoundedRing, 'm') Sym = kBoundedRing.ambient() - Sym.m().module_morphism(self.retract,codomain=self).register_as_coercion() # coercion of monomial to k-bounded monomial + Sym.m().module_morphism(self.retract, codomain=self).register_as_coercion() # coercion of monomial to k-bounded monomial def _repr_(self): """ @@ -1049,10 +1046,10 @@ def __init__(self, kBoundedRing): KBoundedQuotientBasis.__init__(self, kBoundedRing, 'HLP') Sym = kBoundedRing.ambient() - Sym.hall_littlewood(kBoundedRing.t).P().module_morphism(self.retract,codomain=self).register_as_coercion() # morphism from HLP to k-bounded HLP + Sym.hall_littlewood(kBoundedRing.t).P().module_morphism(self.retract, codomain=self).register_as_coercion() # morphism from HLP to k-bounded HLP km = kBoundedRing.km() - self.module_morphism(self._HLP_to_mk_on_basis, codomain=km, triangular='lower', unitriangular=True).register_as_coercion() # morphism from k-bounded-HLP to k-bounded-m - km.module_morphism(self._m_to_kHLP_on_basis, codomain=self, triangular='lower', unitriangular=True).register_as_coercion() # morphism from k-bounded-m to k-bounded-HLP + self.module_morphism(self._HLP_to_mk_on_basis, codomain=km, triangular='lower', unitriangular=True).register_as_coercion() # morphism from k-bounded-HLP to k-bounded-m + km.module_morphism(self._m_to_kHLP_on_basis, codomain=self, triangular='lower', unitriangular=True).register_as_coercion() # morphism from k-bounded-m to k-bounded-HLP def _repr_(self): """ @@ -1108,8 +1105,7 @@ def _m_to_kHLP_on_basis(self, la): return self.zero() HLP = self._kBoundedRing._quotient_basis m = self._kBoundedRing._sym.m() - elt = dict(x for x in dict(HLP(m(la))).items() - if x[0] in self._kbounded_partitions) + elt = dict(x for x in dict(HLP(m(la))).items() if x[0] in self._kbounded_partitions) return self._from_dict(elt) def _HLP_to_mk_on_basis(self, la): @@ -1181,7 +1177,7 @@ def retract(self, la): return self.zero() hlp = self._kBoundedRing.ambient().hall_littlewood(self.t).P() f = hlp(la) - return sum(self(x)*f.coefficient(x) for x in f.support() if x in self._kbounded_partitions) + return sum(self(x) * f.coefficient(x) for x in f.support() if x in self._kbounded_partitions) def lift(self, la): r""" @@ -1245,8 +1241,8 @@ def __init__(self, kBoundedRing): KBoundedQuotientBasis.__init__(self, kBoundedRing, 'dks') kHLP = kBoundedRing.kHallLittlewoodP() - self.module_morphism(self._dks_to_khlp_on_basis,codomain=kHLP).register_as_coercion() # morphism from dual-k-Schurs to k-bounded-HLP - kHLP.module_morphism(self._khlp_to_dks_on_basis,codomain=self).register_as_coercion() # morphism from k-bounded-HLP to dual-k-Schurs + self.module_morphism(self._dks_to_khlp_on_basis, codomain=kHLP).register_as_coercion() # morphism from dual-k-Schurs to k-bounded-HLP + kHLP.module_morphism(self._khlp_to_dks_on_basis, codomain=self).register_as_coercion() # morphism from k-bounded-HLP to dual-k-Schurs def _repr_(self): """ @@ -1287,7 +1283,7 @@ def _dks_to_khlp_on_basis(self, la): Qp = Sym.hall_littlewood(t=self.t).Qp() ks = kB.kschur() kHLP = self._kBoundedRing.kHallLittlewoodP() - return sum( ks(Qp(x)).coefficient(la) * kHLP(x) for x in PartitionsGreatestLE(sum(la), self.k)) + return sum(ks(Qp(x)).coefficient(la) * kHLP(x) for x in PartitionsGreatestLE(sum(la), self.k)) def _khlp_to_dks_on_basis(self, la): r""" @@ -1328,7 +1324,7 @@ def _khlp_to_dks_on_basis(self, la): kB = Sym.kBoundedSubspace(self.k, t=self.t) Qp = Sym.hall_littlewood(t=self.t).Qp() ks = kB.kschur() - return sum( Qp(ks(x)).coefficient(la) * self(x) for x in PartitionsGreatestLE(sum(la), self.k)) + return sum(Qp(ks(x)).coefficient(la) * self(x) for x in PartitionsGreatestLE(sum(la), self.k)) class AffineSchurFunctions(KBoundedQuotientBasis): @@ -1361,11 +1357,12 @@ def __init__(self, kBoundedRing): KBoundedQuotientBasis.__init__(self, kBoundedRing, 'F') from sage.combinat.root_system.weyl_group import WeylGroup + self._weyl = WeylGroup(['A', kBoundedRing.k, 1]) km = kBoundedRing.km() - self.module_morphism(self._F_to_m_on_basis,codomain=km).register_as_coercion() # morphism from affine Schur functions to k-bounded-m - km.module_morphism(self._m_to_F_on_basis,codomain=self).register_as_coercion() # morphism from k-bounded-m basis to affine-Schur basis + self.module_morphism(self._F_to_m_on_basis, codomain=km).register_as_coercion() # morphism from affine Schur functions to k-bounded-m + km.module_morphism(self._m_to_F_on_basis, codomain=self).register_as_coercion() # morphism from k-bounded-m basis to affine-Schur basis def _repr_(self): """ @@ -1435,4 +1432,4 @@ def _m_to_F_on_basis(self, la): kB = Sym.kBoundedSubspace(self.k, t=1) h = kB.khomogeneous() ks = kB.kschur() - return sum( h(ks(x)).coefficient(la) * self(x) for x in PartitionsGreatestLE(sum(la), self.k)) + return sum(h(ks(x)).coefficient(la) * self(x) for x in PartitionsGreatestLE(sum(la), self.k)) diff --git a/src/sage/combinat/sf/kfpoly.py b/src/sage/combinat/sf/kfpoly.py index d97dffacda4..1f00a9c088c 100644 --- a/src/sage/combinat/sf/kfpoly.py +++ b/src/sage/combinat/sf/kfpoly.py @@ -183,8 +183,7 @@ def kfpoly_skew(lamu, nu, t=None): if t is None: t = polygen(ZZ, 't') - return t.parent().sum(t ** T.to_word().charge() - for T in SemistandardSkewTableaux(lamu, nu)) + return t.parent().sum(t ** T.to_word().charge() for T in SemistandardSkewTableaux(lamu, nu)) def schur_to_hl(mu, t=None): @@ -290,7 +289,7 @@ def riggings(part): [[6], [4], [2]]] """ l = len(part) - res = [ [[],[]] ] + res = [[[], []]] sa = 0 for i in sorted(part): sa += i @@ -330,20 +329,20 @@ def compat(n, mu, nu): [[4]] """ l = max(len(mu), len(nu)) - mmu = list(mu) + [0]*(l-len(mu)) - nnu = list(nu) + [0]*(l-len(nu)) + mmu = list(mu) + [0] * (l - len(mu)) + nnu = list(nu) + [0] * (l - len(nu)) bd = [] sa = 0 for i in range(l): - sa += 2*mmu[i] - nnu[i] + sa += 2 * mmu[i] - nnu[i] bd.append(sa) for la in ZS1_iterator(n): if dom(la, bd): return [x.conjugate() for x in _Partitions(la).dominated_partitions()] - return [] # _Partitions([]) + return [] # _Partitions([]) def dom(mup, snu): @@ -375,20 +374,20 @@ def dom(mup, snu): sage: dom([],[]) True """ - if not mup: # mup is empty: - return not snu # True if and only if snu is empty + if not mup: # mup is empty: + return not snu # True if and only if snu is empty l = len(snu) lmup = len(mup) # Special case for the largest columns - if any((k+1)*lmup < snu[k] for k in range(min(mup[-1],l))): + if any((k + 1) * lmup < snu[k] for k in range(min(mup[-1], l))): return False pos = mup[-1] sa = mup[-1] * lmup - for i in range(lmup-1, 0, -1): - for k in range(mup[i-1] - mup[i]): - if pos >= l: # We've reached the end of snu + for i in range(lmup - 1, 0, -1): + for k in range(mup[i - 1] - mup[i]): + if pos >= l: # We've reached the end of snu return True sa += i if sa < snu[pos]: @@ -427,20 +426,21 @@ def weight(rg, t=None): 4 """ from sage.combinat.q_analogues import q_binomial + if t is None: t = polygen(ZZ, 't') - nu = rg + [ [] ] - l = 1 + max( map(len, nu) ) - nu = [ list(mu) + [0]*l for mu in nu ] - res = t**int(sum(i * (i-1) // 2 for i in rg[-1])) - for k in range(1, len(nu)-1): + nu = rg + [[]] + l = 1 + max(map(len, nu)) + nu = [list(mu) + [0] * l for mu in nu] + res = t ** int(sum(i * (i - 1) // 2 for i in rg[-1])) + for k in range(1, len(nu) - 1): sa = 0 mid = nu[k] - for i in range( max(len(rg[k]), len(rg[k-1])) ): - sa += nu[k-1][i] - 2*mid[i] + nu[k+1][i] - if mid[i] - mid[i+1] + sa >= 0: - res *= q_binomial(mid[i]-mid[i+1]+sa, sa, t) - mu = nu[k-1][i] - mid[i] - res *= t**int(mu * (mu-1) // 2) + for i in range(max(len(rg[k]), len(rg[k - 1]))): + sa += nu[k - 1][i] - 2 * mid[i] + nu[k + 1][i] + if mid[i] - mid[i + 1] + sa >= 0: + res *= q_binomial(mid[i] - mid[i + 1] + sa, sa, t) + mu = nu[k - 1][i] - mid[i] + res *= t ** int(mu * (mu - 1) // 2) return res diff --git a/src/sage/combinat/sf/llt.py b/src/sage/combinat/sf/llt.py index b84edaba65d..638cfab2868 100644 --- a/src/sage/combinat/sf/llt.py +++ b/src/sage/combinat/sf/llt.py @@ -79,6 +79,7 @@ class LLT_class(UniqueRepresentation): sage: HS3x(HC3t2[3,1]) 2*HSp3[3, 1] - (2*x-1)*HSp3[4] """ + @staticmethod def __classcall__(cls, Sym, k, t='t'): """ @@ -160,7 +161,7 @@ def __repr__(self): """ return self._name - def symmetric_function_ring( self ): + def symmetric_function_ring(self): r""" The symmetric function algebra associated to the family of LLT symmetric function bases @@ -248,25 +249,24 @@ def _llt_generic(self, skp, stat): if skp in _Partitions: m = (sum(skp) / self.level()).floor() if m == 0: - raise ValueError("level (%s=) must divide %s " % (sum(skp), - self.level())) - mu = Partitions( ZZ(sum(skp) / self.level()) ) + raise ValueError("level (%s=) must divide %s " % (sum(skp), self.level())) + mu = Partitions(ZZ(sum(skp) / self.level())) elif isinstance(skp, list) and skp[0] in sage.combinat.skew_partition.SkewPartitions(): - #skp is a list of skew partitions + # skp is a list of skew partitions skp2 = [Partition(core=[], quotient=[skp[i][0] for i in range(len(skp))])] skp2 += [Partition(core=[], quotient=[skp[i][1] for i in range(len(skp))])] - mu = Partitions(ZZ((skp2[0].size()-skp2[1].size()) / self.level())) + mu = Partitions(ZZ((skp2[0].size() - skp2[1].size()) / self.level())) skp = skp2 elif isinstance(skp, list) and skp[0] in _Partitions: - #skp is a list of partitions + # skp is a list of partitions skp = Partition(core=[], quotient=skp) - mu = Partitions( ZZ(sum(skp) / self.level()) ) + mu = Partitions(ZZ(sum(skp) / self.level())) else: raise ValueError("LLT polynomials not defined for %s" % skp) BR = self.base_ring() - return sum([ BR(stat(skp,nu,self.level()).subs(t=self.t))*self._m(nu) for nu in mu]) + return sum([BR(stat(skp, nu, self.level()).subs(t=self.t)) * self._m(nu) for nu in mu]) def spin_square(self, skp): r""" @@ -331,16 +331,16 @@ def cospin(self, skp): """ return self._llt_generic(skp, ribbon_tableau.cospin_polynomial) -#### Is it safe to delete this function? -## def llt_inv(self, skp): -## """ -## """ -## l = sage.combinat.partitions( sum( [ p.size() for p in skp ] ) ).list() -## res = m(0) -## for p in l: -## inv_p = [ ktuple.inversions() for ktuple in kTupleTableaux(skp, p) ] -## res += sum([t**x for x in inv_p])*m(p) -## return res + #### Is it safe to delete this function? + ## def llt_inv(self, skp): + ## """ + ## """ + ## l = sage.combinat.partitions( sum( [ p.size() for p in skp ] ) ).list() + ## res = m(0) + ## for p in l: + ## inv_p = [ ktuple.inversions() for ktuple in kTupleTableaux(skp, p) ] + ## res += sum([t**x for x in inv_p])*m(p) + ## return res def hcospin(self): r""" @@ -425,10 +425,7 @@ def __init__(self, llt, prefix): Symmetric Functions over Fraction Field of Univariate Polynomial Ring in z over Rational Field in the level 3 LLT spin with t=z basis """ s = self.__class__.__name__[4:] - sfa.SymmetricFunctionAlgebra_generic.__init__( - self, llt._sym, - basis_name="level %s LLT " % llt.level() + s + llt._name_suffix, - prefix=prefix) + sfa.SymmetricFunctionAlgebra_generic.__init__(self, llt._sym, basis_name="level %s LLT " % llt.level() + s + llt._name_suffix, prefix=prefix) self.t = llt.t self._sym = llt._sym @@ -440,7 +437,7 @@ def __init__(self, llt, prefix): # temporary until Hom(GradedHopfAlgebrasWithBasis work better) category = ModulesWithBasis(self._sym.base_ring()) self._m = llt._sym.m() - self .register_coercion(SetMorphism(Hom(self._m, self, category), self._m_to_self)) + self.register_coercion(SetMorphism(Hom(self._m, self, category), self._m_to_self)) self._m.register_coercion(SetMorphism(Hom(self, self._m, category), self._self_to_m)) def construction(self): @@ -458,10 +455,8 @@ def construction(self): Fraction Field of Univariate Polynomial Ring in t over Rational Field) """ from sage.combinat.sf.sfa import SymmetricFunctionsFamilyFunctor - return (SymmetricFunctionsFamilyFunctor(self, LLT_class, - self.basis_name(), - self._k, self.t), - self.base_ring()) + + return (SymmetricFunctionsFamilyFunctor(self, LLT_class, self.basis_name(), self._k, self.t), self.base_ring()) def _m_to_self(self, x): r""" @@ -487,8 +482,7 @@ def _m_to_self(self, x): sage: HSp3(m[2,1]) -2*HSp3[1, 1, 1] + (2*t^2+2*t+1)*HSp3[2, 1] + (-2*t^2-t)*HSp3[3] """ - return self._from_cache(x, self._m_cache, self._m_to_self_cache, - t=self.t) + return self._from_cache(x, self._m_cache, self._m_to_self_cache, t=self.t) def _self_to_m(self, x): r""" @@ -514,8 +508,7 @@ def _self_to_m(self, x): sage: m(HSp3[2,1]) (t+2)*m[1, 1, 1] + (t+1)*m[2, 1] + t*m[3] """ - return self._m._from_cache(x, self._m_cache, self._self_to_m_cache, - t=self.t) + return self._m._from_cache(x, self._m_cache, self._self_to_m_cache, t=self.t) def level(self): r""" @@ -535,7 +528,7 @@ def level(self): """ return self._k - def llt_family( self ): + def llt_family(self): r""" The family of the llt bases of the symmetric functions. @@ -604,9 +597,7 @@ def _m_cache(self, n): [([1, 1], [([1, 1], 1/t), ([2], -1/t)]), ([2], [([1, 1], -1/t), ([2], (t + 1)/t)])] """ - self._invert_morphism(n, QQt, self._self_to_m_cache, - self._m_to_self_cache, - to_other_function=self._to_m) + self._invert_morphism(n, QQt, self._self_to_m_cache, self._m_to_self_cache, to_other_function=self._to_m) class Element(sfa.SymmetricFunctionAlgebra_generic.Element): pass @@ -675,7 +666,7 @@ def _to_m(self, part): (t+2)*m[1, 1, 1] + (t+1)*m[2, 1] + t*m[3] """ level = self.level() - f = lambda part2: QQt(ribbon_tableau.spin_polynomial([level*i for i in part], part2, level)) + f = lambda part2: QQt(ribbon_tableau.spin_polynomial([level * i for i in part], part2, level)) return f class Element(LLT_generic.Element): @@ -743,7 +734,7 @@ def _to_m(self, part): (2*t+1)*m[1, 1, 1] + (t+1)*m[2, 1] + m[3] """ level = self.level() - f = lambda part2: QQt(ribbon_tableau.cospin_polynomial([level*i for i in part], part2, level)) + f = lambda part2: QQt(ribbon_tableau.cospin_polynomial([level * i for i in part], part2, level)) return f class Element(LLT_generic.Element): diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 79bc7a0f4ec..32cf80c31e5 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -45,14 +45,14 @@ # cache in q,t globally and subs locally with q and t values # these caches are stored in self._self_to_s_cache and self._s_to_self_cache -#J basis cache +# J basis cache _j_to_s_cache = {} _s_to_j_cache = {} -#Ht basis cache +# Ht basis cache _ht_to_m_cache = {} -#S basis cache +# S basis cache _S_to_s_cache = {} _s_to_S_cache = {} @@ -129,9 +129,9 @@ def __init__(self, Sym, q, t): if str(q) == 'q': self._name_suffix += " with " self._name_suffix += "t=%s" % t - self._name = "Macdonald polynomials"+self._name_suffix+" over "+repr(Sym.base_ring()) + self._name = "Macdonald polynomials" + self._name_suffix + " over " + repr(Sym.base_ring()) - def base_ring( self ): + def base_ring(self): r""" Return the base ring of the symmetric functions where the Macdonald symmetric functions live. @@ -151,7 +151,7 @@ def base_ring( self ): """ return self._sym.base_ring() - def symmetric_function_ring( self ): + def symmetric_function_ring(self): r""" Return the base ring of the symmetric functions where the Macdonald symmetric functions live. @@ -558,7 +558,7 @@ def c1(part, q, t): R = q.parent() arms = part.arm_lengths(flat=True) legs = part.leg_lengths(flat=True) - return R.prod(1 - q**(a + 1) * t**l for a, l in zip(arms, legs)) + return R.prod(1 - q ** (a + 1) * t**l for a, l in zip(arms, legs)) def c2(part, q, t): @@ -588,7 +588,7 @@ def c2(part, q, t): R = q.parent() arms = part.arm_lengths(flat=True) legs = part.leg_lengths(flat=True) - return R.prod(1 - q**a * t**(l + 1) for a, l in zip(arms, legs)) + return R.prod(1 - q**a * t ** (l + 1) for a, l in zip(arms, legs)) @cached_function @@ -617,22 +617,16 @@ def cmunu1(mu, nu): ....: for nu in Partition([3,2,1]).down_list()) True """ - q,t = QQqt.gens() + q, t = QQqt.gens() # The following for loop is equivalent to getting the cell: # SkewPartition([mu,nu]).cells()[0] for i, val in enumerate(nu._list): if val < mu._list[i]: - A = prod((t**mu.leg_length(i, s) - q**(mu.arm_length(i, s)+1)) - / (t**nu.leg_length(i, s) - q**(nu.arm_length(i, s)+1)) - for s in range(val)) - B = prod((q**mu.arm_length(*s) - t**(mu.leg_length(*s)+1)) - / (q**nu.arm_length(*s) - t**(nu.leg_length(*s)+1)) - for s in nu.cells() if s[1] == val) + A = prod((t ** mu.leg_length(i, s) - q ** (mu.arm_length(i, s) + 1)) / (t ** nu.leg_length(i, s) - q ** (nu.arm_length(i, s) + 1)) for s in range(val)) + B = prod((q ** mu.arm_length(*s) - t ** (mu.leg_length(*s) + 1)) / (q ** nu.arm_length(*s) - t ** (nu.leg_length(*s) + 1)) for s in nu.cells() if s[1] == val) return QQqt(A * B) - return QQqt(prod( (q**mu.arm_length(s, 0) - t**(mu.leg_length(s, 0)+1)) - / (q**nu.arm_length(s, 0) - t**(nu.leg_length(s, 0)+1)) - for s in range(len(nu._list)) )) + return QQqt(prod((q ** mu.arm_length(s, 0) - t ** (mu.leg_length(s, 0) + 1)) / (q ** nu.arm_length(s, 0) - t ** (nu.leg_length(s, 0) + 1)) for s in range(len(nu._list)))) @cached_function @@ -682,9 +676,9 @@ def cmunu(mu, nu): # This is equivalent to: # Bmu(SkewPartition([outer, inner])) def Bmu_skew(outer, inner): - inner = list(inner) # This makes a (shallow) copy of inner - inner += [0]*(len(outer)-len(inner)) - q,t = QQqt.gens() + inner = list(inner) # This makes a (shallow) copy of inner + inner += [0] * (len(outer) - len(inner)) + q, t = QQqt.gens() res = QQqt.zero() for i, val in enumerate(outer): for j in range(inner[i], val): @@ -692,10 +686,10 @@ def Bmu_skew(outer, inner): return res nulist = nu._list - return (sum(cmunu(mu, al) * cmunu1(al, nu) * Bmu_skew(al, nulist) - for al in nu.up()) / Bmu_skew(mu, nulist)) + return sum(cmunu(mu, al) * cmunu1(al, nu) * Bmu_skew(al, nulist) for al in nu.up()) / Bmu_skew(mu, nulist) + -#Generic MacdonaldPolynomials +# Generic MacdonaldPolynomials class MacdonaldPolynomials_generic(sfa.SymmetricFunctionAlgebra_generic): @@ -727,10 +721,7 @@ def __init__(self, macdonald): 'McdHt' """ s = self.__class__.__name__[21:].capitalize() - sfa.SymmetricFunctionAlgebra_generic.__init__( - self, macdonald._sym, - basis_name="Macdonald " + s + macdonald._name_suffix, - prefix="Mcd" + s) + sfa.SymmetricFunctionAlgebra_generic.__init__(self, macdonald._sym, basis_name="Macdonald " + s + macdonald._name_suffix, prefix="Mcd" + s) self.q = macdonald.q self.t = macdonald.t self._macdonald = macdonald @@ -758,10 +749,7 @@ def construction(self): (SymmetricFunctionsFunctor[Macdonald J with t=2], Fraction Field of Univariate Polynomial Ring in q over Rational Field) """ - return (sfa.SymmetricFunctionsFamilyFunctor(self, Macdonald, - self.basis_name(), - self.q, self.t), - self.base_ring()) + return (sfa.SymmetricFunctionsFamilyFunctor(self, Macdonald, self.basis_name(), self.q, self.t), self.base_ring()) def _s_to_self(self, x): r""" @@ -787,8 +775,7 @@ def _s_to_self(self, x): sage: J(s[2,1]) ((-1/28*q+1/14)/(q-1/4))*McdJ[1, 1, 1] - (1/4/(q-1/4))*McdJ[2, 1] """ - return self._from_cache(x, self._s_cache, self._s_to_self_cache, - q=self.q, t=self.t) + return self._from_cache(x, self._s_cache, self._s_to_self_cache, q=self.q, t=self.t) def _self_to_s(self, x): r""" @@ -814,8 +801,7 @@ def _self_to_s(self, x): sage: s(J[2,1]) (3*q-6)*s[1, 1, 1] + (-4*q+1)*s[2, 1] """ - return self._s._from_cache(x, self._s_cache, self._self_to_s_cache, - q=self.q, t=self.t) + return self._s._from_cache(x, self._s_cache, self._self_to_s_cache, q=self.q, t=self.t) def c1(self, part): r""" @@ -966,17 +952,18 @@ def nabla(self, q=None, t=None, power=1): -(t^4/(-q^2))*McdH[2, 2, 1] """ parent = self.parent() - if (q is None and t is None): + if q is None and t is None: Ht = parent._macdonald.Ht() else: if q is None: q = parent.q if t is None: t = parent.t - Ht = parent.realization_of().macdonald(q=q,t=t).Ht() + Ht = parent.realization_of().macdonald(q=q, t=t).Ht() return parent(Ht(self).nabla(power=power)) -#P basis + +# P basis class MacdonaldPolynomials_p(MacdonaldPolynomials_generic): @@ -1002,8 +989,7 @@ def __init__(self, macdonald): self._J = macdonald.J() # temporary until Hom(GradedHopfAlgebrasWithBasis work better) category = ModulesWithBasis(self.base_ring()) - phi = self._J.module_morphism(diagonal=self.c2, - codomain=self, category=category) + phi = self._J.module_morphism(diagonal=self.c2, codomain=self, category=category) self.register_coercion(phi) self._J.register_coercion(~phi) @@ -1047,7 +1033,7 @@ class Element(MacdonaldPolynomials_generic.Element): pass -#Q basis +# Q basis class MacdonaldPolynomials_q(MacdonaldPolynomials_generic): def __init__(self, macdonald): r""" @@ -1073,8 +1059,7 @@ def __init__(self, macdonald): # temporary until Hom(GradedHopfAlgebrasWithBasis) works better category = ModulesWithBasis(self.base_ring()) - phi = self._P.module_morphism(diagonal=self._P.scalar_qt_basis, - codomain=self, category=category) + phi = self._P.module_morphism(diagonal=self._P.scalar_qt_basis, codomain=self, category=category) self.register_coercion(phi) self._P.register_coercion(~phi) @@ -1131,10 +1116,7 @@ def _s_cache(self, n): [([1, 1], [([1, 1], t^3 - t^2 - t + 1)]), ([2], [([1, 1], -q*t + t^2 + q - t), ([2], q*t^2 - q*t - t + 1)])] """ - self._invert_morphism(n, QQqt, self._self_to_s_cache, - self._s_to_self_cache, - to_other_function=self._to_s, - upper_triangular=False) + self._invert_morphism(n, QQqt, self._self_to_s_cache, self._s_to_self_cache, to_other_function=self._to_s, upper_triangular=False) def _to_s(self, part): r""" @@ -1247,7 +1229,7 @@ def _self_to_s(self, x): """ if self.t: return self._s(self._self_to_m(x)) - return sum(cmu*self._s(self._Qp(mu.conjugate())) for mu,cmu in x).omega() + return sum(cmu * self._s(self._Qp(mu.conjugate())) for mu, cmu in x).omega() def _s_to_self(self, x): r""" @@ -1287,7 +1269,7 @@ def _s_to_self(self, x): """ if self.t: return self._m_to_self(self._m(x)) - return self._from_dict({mu.conjugate() : cmu for mu,cmu in self._Qp(x.omega())}) + return self._from_dict({mu.conjugate(): cmu for mu, cmu in self._Qp(x.omega())}) def _self_to_m(self, x): r""" @@ -1322,15 +1304,11 @@ def _self_to_m(self, x): """ if self.t: tinv = ~self.t - part_coeff = lambda x, d: sorted((mu,c) for mu,c in x if sum(mu) == d) - return self._m._from_dict({ part2: - self._base( sum(c * self.t**mu.weighted_size() - * self._Lmunu(part2, mu).subs(q=self.q, t=tinv) - for mu,c in part_coeff(x, d)) ) - for d in range(x.degree()+1) for part2 in Partitions_n(d) }) + part_coeff = lambda x, d: sorted((mu, c) for mu, c in x if sum(mu) == d) + return self._m._from_dict({part2: self._base(sum(c * self.t ** mu.weighted_size() * self._Lmunu(part2, mu).subs(q=self.q, t=tinv) for mu, c in part_coeff(x, d))) for d in range(x.degree() + 1) for part2 in Partitions_n(d)}) return self._m(self._self_to_s(x)) - def _m_to_self( self, f ): + def _m_to_self(self, f): r""" Convert an element ``f`` from the monomial basis to the ``H`` basis. @@ -1442,7 +1420,7 @@ def _self_to_s(self, x): """ return self._s(self._self_to_m(x)) - def _s_to_self( self, x ): + def _s_to_self(self, x): r""" Convert an element of either the Schur basis to the ``Ht`` basis. @@ -1505,18 +1483,16 @@ def _Lmunu(self, nu, mu): if not nu: return QQqt.one() return QQqt.zero() - if (mu,nu) in self._self_to_m_cache: - return self._self_to_m_cache[(mu,nu)] + if (mu, nu) in self._self_to_m_cache: + return self._self_to_m_cache[(mu, nu)] if len(nu) == 1: return QQqt.one() short_nu = _Partitions(nu[:-1]) if nu[-1] == 1: - self._self_to_m_cache[(mu,nu)] = QQqt( sum(cmunu1(mu,ga) * self._Lmunu(short_nu, ga) - for ga in mu.down()) ) + self._self_to_m_cache[(mu, nu)] = QQqt(sum(cmunu1(mu, ga) * self._Lmunu(short_nu, ga) for ga in mu.down())) else: - self._self_to_m_cache[(mu,nu)] = QQqt( sum(cmunu(mu,ga) * self._Lmunu(short_nu, ga) - for ga in Partitions_n(short_nu.size()) if mu.contains(ga) ) ) - return self._self_to_m_cache[(mu,nu)] + self._self_to_m_cache[(mu, nu)] = QQqt(sum(cmunu(mu, ga) * self._Lmunu(short_nu, ga) for ga in Partitions_n(short_nu.size()) if mu.contains(ga))) + return self._self_to_m_cache[(mu, nu)] def _self_to_m(self, x): r""" @@ -1544,13 +1520,10 @@ def _self_to_m(self, x): sage: m(Ht[2,1]) ((2*x^2+2*x+2)/x)*m[1, 1, 1] + ((x^2+x+1)/x)*m[2, 1] + m[3] """ - part_coeff = lambda x, d: sorted((mu,c) for mu,c in x if sum(mu) == d) - return self._m._from_dict({ part2: - self._base( sum(c * self._Lmunu(part2, mu).subs(q=self.q, t=self.t) - for mu,c in part_coeff(x, d)) ) - for d in range(x.degree()+1) for part2 in Partitions_n(d) }) + part_coeff = lambda x, d: sorted((mu, c) for mu, c in x if sum(mu) == d) + return self._m._from_dict({part2: self._base(sum(c * self._Lmunu(part2, mu).subs(q=self.q, t=self.t) for mu, c in part_coeff(x, d))) for d in range(x.degree() + 1) for part2 in Partitions_n(d)}) - def _m_to_self( self, f ): + def _m_to_self(self, f): r""" Convert an element ``f`` from the monomial basis to the ``Ht`` basis. @@ -1661,7 +1634,7 @@ def nabla(self, q=None, t=None, power=1): q = Ht.q if t is None: t = Ht.t - f = lambda part: t**(part.weighted_size()*power)*q**(part.conjugate().weighted_size()*power)*Ht(part) + f = lambda part: t ** (part.weighted_size() * power) * q ** (part.conjugate().weighted_size() * power) * Ht(part) return P(Ht._apply_module_morphism(selfHt, f)) @@ -1778,9 +1751,7 @@ def _s_cache(self, n): sage: l( S._self_to_s_cache[2] ) [([1, 1], [([1, 1], (-q*t^2 + q*t + t - 1)/(-q^3 + q^2 + q - 1)), ([2], (q*t - t^2 - q + t)/(-q^3 + q^2 + q - 1))]), ([2], [([1, 1], (q*t - t^2 - q + t)/(-q^3 + q^2 + q - 1)), ([2], (-q*t^2 + q*t + t - 1)/(-q^3 + q^2 + q - 1))])] """ - self._invert_morphism(n, QQqt, self._self_to_s_cache, - self._s_to_self_cache, - to_other_function=self._to_s) + self._invert_morphism(n, QQqt, self._self_to_s_cache, self._s_to_self_cache, to_other_function=self._to_s) class Element(MacdonaldPolynomials_generic.Element): @@ -1812,30 +1783,31 @@ def _creation_by_determinant_helper(self, k, part): """ q, t = QQqt.gens() from sage.combinat.sf.sf import SymmetricFunctions + S = SymmetricFunctions(QQqt).macdonald().S() - part += [0]*(k-len(part)) + part += [0] * (k - len(part)) if len(part) > k: raise ValueError("the column to add is too small") - #Create the matrix over the homogeneous symmetric - #functions and take its determinant + # Create the matrix over the homogeneous symmetric + # functions and take its determinant h = S._sym.homogeneous() MS = MatrixSpace(h, k, k) m = [] for i in range(k): - row = [0]*max(0, (i+1)-2-part[i]) - for j in range(max(0, (i+1)-2-part[i]),k): - value = part[i]+j-i+1 + row = [0] * max(0, (i + 1) - 2 - part[i]) + for j in range(max(0, (i + 1) - 2 - part[i]), k): + value = part[i] + j - i + 1 p = [value] if value > 0 else [] - row.append( (1-q**(part[i]+j-i+1)*t**(k-(j+1)))*h(p) ) + row.append((1 - q ** (part[i] + j - i + 1) * t ** (k - (j + 1))) * h(p)) m.append(row) M = MS(m) res = M.det() - #Convert to the Schurs - res = S._s( res ) + # Convert to the Schurs + res = S._s(res) return S._from_element(res) def _creation_by_determinant(self, k): @@ -1863,7 +1835,7 @@ def _creation_by_determinant(self, k): McdJ[2, 1, 1] """ S = self.parent() - f = functools.partial(self._creation_by_determinant_helper,k) + f = functools.partial(self._creation_by_determinant_helper, k) return S._apply_module_morphism(self, f) def creation(self, k): @@ -1965,10 +1937,11 @@ def qt_kostka(lam, mu): if lam.size() != mu.size(): return QQqt.zero() - if (lam,mu) in _qt_kostka_cache: - return _qt_kostka_cache[(lam,mu)] + if (lam, mu) in _qt_kostka_cache: + return _qt_kostka_cache[(lam, mu)] from sage.combinat.sf.sf import SymmetricFunctions + Sym = SymmetricFunctions(QQqt) H = Sym.macdonald().H() s = Sym.schur() diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index 9cba44607bf..1229b4b7b4e 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -126,8 +126,7 @@ def product(self, left, right): z_elt[left_m] = left_c * right_c continue - d = symmetrica.mult_monomial_monomial({left_m: Integer(1)}, - {right_m: Integer(1)}).monomial_coefficients() + d = symmetrica.mult_monomial_monomial({left_m: Integer(1)}, {right_m: Integer(1)}).monomial_coefficients() for m in d: if m in z_elt: z_elt[m] += left_c * right_c * d[m] @@ -183,10 +182,7 @@ def from_polynomial(self, f, check=True): assert self.base_ring() == f.base_ring() if check and not f.is_symmetric(): raise ValueError("%s is not a symmetric polynomial" % f) - out = self._from_dict({_Partitions.element_class(_Partitions, list(e)): c - for e, c in f.monomial_coefficients().items() - if all(e[i+1] <= e[i] for i in range(len(e)-1))}, - remove_zeros=False) + out = self._from_dict({_Partitions.element_class(_Partitions, list(e)): c for e, c in f.monomial_coefficients().items() if all(e[i + 1] <= e[i] for i in range(len(e) - 1))}, remove_zeros=False) return out def from_polynomial_exp(self, p): @@ -236,6 +232,7 @@ def from_polynomial_exp(self, p): """ assert self.base_ring() == p.parent().base_ring() from sage.combinat.sf.sfa import _from_polynomial + return _from_polynomial(p, self) def antipode_by_coercion(self, element): @@ -270,6 +267,7 @@ def antipode_by_coercion(self, element): to work over any ring, not just one with coercion from `\QQ`? """ from sage.rings.rational_field import RationalField + if self.has_coerce_map_from(RationalField()): p = self.realization_of().powersum() return self(p.antipode(p(element))) @@ -331,6 +329,7 @@ def expand(self, n, alphabet='x'): def condition(part): return len(part) > n + return self._expand(condition, n, alphabet) def principal_specialization(self, n=infinity, q=None): @@ -401,13 +400,12 @@ def principal_specialization(self, n=infinity, q=None): if n == 1: R = self.base_ring() mc = self.monomial_coefficients(copy=False).items() - return R.sum(c for partition, c in mc - if len(partition) <= 1) + return R.sum(c for partition, c in mc if len(partition) <= 1) if q == 1: if n == infinity: raise ValueError("the stable principal specialization at q=1 is not defined") - f = lambda partition: binomial(n, len(partition))*multinomial(partition.to_exp()) + f = lambda partition: binomial(n, len(partition)) * multinomial(partition.to_exp()) return self.parent()._apply_module_morphism(self, f, q.parent()) # heuristically, it seems fastest to fall back to the @@ -489,6 +487,7 @@ def exponential_specialization(self, t=None, q=1): sage: m.zero().exponential_specialization() 0 """ + def get_variable(ring, name): try: ring(name) @@ -496,6 +495,7 @@ def get_variable(ring, name): from sage.rings.polynomial.polynomial_ring_constructor import ( PolynomialRing, ) + return PolynomialRing(ring, name).gen() else: raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) diff --git a/src/sage/combinat/sf/multiplicative.py b/src/sage/combinat/sf/multiplicative.py index 1284d6852bc..d49b511c2c4 100644 --- a/src/sage/combinat/sf/multiplicative.py +++ b/src/sage/combinat/sf/multiplicative.py @@ -6,7 +6,7 @@ a partition `\lambda = (\lambda_1,\lambda_2,\ldots)` we have `h_\lambda = h_{\lambda_1} h_{\lambda_2} \cdots`. """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2007 Mike Hansen , # # Distributed under the terms of the GNU General Public License (GPL) @@ -19,7 +19,7 @@ # The full text of the GPL is available at: # # https://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** import sage.combinat.partition from . import classical diff --git a/src/sage/combinat/sf/new_kschur.py b/src/sage/combinat/sf/new_kschur.py index 84ac752fcd9..f5150b6a6f3 100644 --- a/src/sage/combinat/sf/new_kschur.py +++ b/src/sage/combinat/sf/new_kschur.py @@ -124,7 +124,7 @@ def __init__(self, Sym, k, t='t'): s_to_h = h._internal_coerce_map_from(s) ks_to_kh = kh.retract * s_to_h * ks.lift kh.register_coercion(ks_to_kh) - # temporary workaround until handled by trac 125959 + # temporary workaround until handled by trac 125959 self.one = ConstantFunction(ks.one()) self.zero = ConstantFunction(ks.zero()) @@ -174,8 +174,7 @@ def realizations(self): 3-bounded Symmetric Functions over Univariate Polynomial Ring in t over Rational Field in the 3-split basis] """ if self.t == 1: - return [self.kschur(), self.ksplit(), self.khomogeneous(), - self.K_kschur()] + return [self.kschur(), self.ksplit(), self.khomogeneous(), self.K_kschur()] return [self.kschur(), self.ksplit()] def kschur(self): @@ -475,8 +474,7 @@ def transition_matrix(self, other, n): # todo: Q should be set by getting the degree n index set for # `other`. Q = Partitions(n) - return matrix([[other(self[row]).coefficient(col) for col in Q] - for row in P]) + return matrix([[other(self[row]).coefficient(col) for col in Q] for row in P]) def _an_element_(self): r""" @@ -547,6 +545,7 @@ def coproduct(self, element): def cpfunc(x, y): return tensor([self(x), self(y)]) + return source_basis(lifted).coproduct().apply_multilinear_morphism(cpfunc) def antipode(self, element): @@ -749,6 +748,7 @@ def omega_t_inverse(self): def invert(x): return s.base_ring()(x.subs(t=1 / t)) + return self.parent()(s(self).map_coefficients(invert).omega()) def is_schur_positive(self, *args, **kwargs): @@ -982,10 +982,7 @@ def __init__(self, kBoundedRing): sage: kSchur(KB) 3-bounded Symmetric Functions over Rational Field with t=1 in the 3-Schur basis """ - CombinatorialFreeModule.__init__(self, kBoundedRing.base_ring(), - kBoundedRing.indices(), - category=KBoundedSubspaceBases(kBoundedRing, kBoundedRing.t), - prefix='ks%d' % kBoundedRing.k) + CombinatorialFreeModule.__init__(self, kBoundedRing.base_ring(), kBoundedRing.indices(), category=KBoundedSubspaceBases(kBoundedRing, kBoundedRing.t), prefix='ks%d' % kBoundedRing.k) self._kBoundedRing = kBoundedRing @@ -996,14 +993,11 @@ def __init__(self, kBoundedRing): self.ambient = ConstantFunction(s) - self.lift = self._module_morphism(self._to_schur_on_basis, - codomain=s, triangular='lower', unitriangular=True, - inverse_on_support=lambda p: p if p.get_part(0) <= self.k else None) + self.lift = self._module_morphism(self._to_schur_on_basis, codomain=s, triangular='lower', unitriangular=True, inverse_on_support=lambda p: p if p.get_part(0) <= self.k else None) self.lift.register_as_coercion() - self.retract = SetMorphism(Hom(s, self, SetsWithPartialMaps()), - self.lift.preimage) + self.retract = SetMorphism(Hom(s, self, SetsWithPartialMaps()), self.lift.preimage) self.register_conversion(self.retract) # The following are meant to be inherited with the category framework, but @@ -1068,8 +1062,7 @@ def _to_schur_on_basis(self, p): katom = p.k_irreducible(self.k).k_atom(self.k) return s.sum_of_monomials(tab.shape() for tab in katom) * prod(s([r + 1] * (self.k - r)) for r in range(self.k) for m in range(pexp[r] // (self.k - r))) katom = p.k_atom(self.k) - return s.sum_of_terms((tab.shape(), self.t**tab.charge()) - for tab in katom) + return s.sum_of_terms((tab.shape(), self.t ** tab.charge()) for tab in katom) def _product_on_basis_via_rectangles(self, left, right): r""" @@ -1111,10 +1104,8 @@ def _product_on_basis_via_rectangles(self, left, right): heart = self.retract(leftir * rightir) leftexp = left.to_exp() rightexp = right.to_exp() - rects = sum(([r + 1] * (self.k - r) for r in range(len(leftexp)) - for m in range(leftexp[r] // (self.k - r))), []) - rects += sum(([r + 1] * (self.k - r) for r in range(len(rightexp)) - for m in range(rightexp[r] // (self.k - r))), []) + rects = sum(([r + 1] * (self.k - r) for r in range(len(leftexp)) for m in range(leftexp[r] // (self.k - r))), []) + rects += sum(([r + 1] * (self.k - r) for r in range(len(rightexp)) for m in range(rightexp[r] // (self.k - r))), []) return heart.map_support(lambda lam: Partition(sorted(lam + rects, reverse=True))) def product_on_basis(self, left, right): @@ -1238,10 +1229,7 @@ def __init__(self, kBoundedRing): sage: ks4(ksp4[3,2,2,1]) ks4[3, 2, 2, 1] + t*ks4[3, 3, 1, 1] + t*ks4[3, 3, 2] """ - CombinatorialFreeModule.__init__(self, kBoundedRing.base_ring(), - kBoundedRing.indices(), - category=KBoundedSubspaceBases(kBoundedRing, kBoundedRing.t), - prefix='ksp%d' % kBoundedRing.k) + CombinatorialFreeModule.__init__(self, kBoundedRing.base_ring(), kBoundedRing.indices(), category=KBoundedSubspaceBases(kBoundedRing, kBoundedRing.t), prefix='ksp%d' % kBoundedRing.k) self._kBoundedRing = kBoundedRing @@ -1252,14 +1240,11 @@ def __init__(self, kBoundedRing): self.ambient = ConstantFunction(s) - self.lift = self._module_morphism(self._to_schur_on_basis, - codomain=s, triangular='lower', unitriangular=True, - inverse_on_support=lambda p: p if p.get_part(0) <= self.k else None) + self.lift = self._module_morphism(self._to_schur_on_basis, codomain=s, triangular='lower', unitriangular=True, inverse_on_support=lambda p: p if p.get_part(0) <= self.k else None) self.lift.register_as_coercion() - self.retract = SetMorphism(Hom(s, self, SetsWithPartialMaps()), - self.lift.preimage) + self.retract = SetMorphism(Hom(s, self, SetsWithPartialMaps()), self.lift.preimage) self.register_conversion(self.retract) # The following are meant to be inherited with the category framework, but @@ -1352,10 +1337,7 @@ def __init__(self, kBoundedRing): sage: kHomogeneous(KB) 3-bounded Symmetric Functions over Rational Field with t=1 in the 3-bounded homogeneous basis """ - CombinatorialFreeModule.__init__(self, kBoundedRing.base_ring(), - kBoundedRing.indices(), - category=KBoundedSubspaceBases(kBoundedRing, kBoundedRing.t), - prefix='h%d' % kBoundedRing.k) + CombinatorialFreeModule.__init__(self, kBoundedRing.base_ring(), kBoundedRing.indices(), category=KBoundedSubspaceBases(kBoundedRing, kBoundedRing.t), prefix='h%d' % kBoundedRing.k) self._kBoundedRing = kBoundedRing @@ -1364,16 +1346,13 @@ def __init__(self, kBoundedRing): h = self.realization_of().ambient().homogeneous() - self.lift = self._module_morphism(lambda x: h[x], - codomain=h, triangular='lower', unitriangular=True, - inverse_on_support=lambda p: p if p.get_part(0) <= self.k else None) + self.lift = self._module_morphism(lambda x: h[x], codomain=h, triangular='lower', unitriangular=True, inverse_on_support=lambda p: p if p.get_part(0) <= self.k else None) self.ambient = ConstantFunction(h) self.lift.register_as_coercion() - self.retract = SetMorphism(Hom(h, self, SetsWithPartialMaps()), - self.lift.preimage) + self.retract = SetMorphism(Hom(h, self, SetsWithPartialMaps()), self.lift.preimage) self.register_conversion(self.retract) # The following are meant to be inherited with the category framework, but @@ -1429,10 +1408,7 @@ def __init__(self, kBoundedRing): sage: g(h[1,1]) -Kks3[1] + Kks3[1, 1] + Kks3[2] """ - CombinatorialFreeModule.__init__(self, kBoundedRing.base_ring(), - kBoundedRing.indices(), - category=KBoundedSubspaceBases(kBoundedRing, kBoundedRing.base_ring().one()), - prefix='Kks%d' % kBoundedRing.k) + CombinatorialFreeModule.__init__(self, kBoundedRing.base_ring(), kBoundedRing.indices(), category=KBoundedSubspaceBases(kBoundedRing, kBoundedRing.base_ring().one()), prefix='Kks%d' % kBoundedRing.k) self._kBoundedRing = kBoundedRing @@ -1496,6 +1472,7 @@ def _homogeneous_generators_noncommutative_variables_zero_Hecke(self, r): """ from sage.algebras.iwahori_hecke_algebra import IwahoriHeckeAlgebra from sage.combinat.root_system.weyl_group import WeylGroup + W = WeylGroup(['A', self.k, 1]) H = IwahoriHeckeAlgebra(W, 0, base_ring=self.base_ring()).T() Hgens = H.algebra_generators() @@ -1579,10 +1556,10 @@ def _DualGrothMatrix(self, m): for i in range(m + 1): for x in Partitions(m - i, max_part=self.k): f = mon(G(x, m)) - vec = [f.coefficient(y) for j in range(m + 1) - for y in Partitions(m - j, max_part=self.k)] + vec = [f.coefficient(y) for j in range(m + 1) for y in Partitions(m - j, max_part=self.k)] new_mat.append(vec) from sage.matrix.constructor import Matrix + return Matrix(new_mat) @cached_method @@ -1618,6 +1595,7 @@ def _DualGrothendieck(self, la): else: vec.append(0) from sage.modules.free_module_element import vector + vec = vector(vec) sol = M.solve_right(vec) new_function = h.zero() @@ -1710,8 +1688,7 @@ def _kh_to_g_on_basis(self, la): return self([]) h = self.realization_of().khomogeneous() f = h(self(la)) - h(la) - return self(la) - sum(self._kh_to_g_on_basis(x) * f.coefficient(x) - for x in f.support()) + return self(la) - sum(self._kh_to_g_on_basis(x) * f.coefficient(x) for x in f.support()) def product(self, x, y): r""" diff --git a/src/sage/combinat/sf/ns_macdonald.py b/src/sage/combinat/sf/ns_macdonald.py index a530ca0b612..d2c980377c4 100644 --- a/src/sage/combinat/sf/ns_macdonald.py +++ b/src/sage/combinat/sf/ns_macdonald.py @@ -92,8 +92,7 @@ def arm_right(self, i, j): sage: a.arm_right(5,2) [(8, 1)] """ - return [(ip, j - 1) for ip in range(i + 1, len(self) + 1) - if j - 1 <= self[ip] < self[i]] + return [(ip, j - 1) for ip in range(i + 1, len(self) + 1) if j - 1 <= self[ip] < self[i]] def arm(self, i, j): """ @@ -241,8 +240,7 @@ def shape(self): sage: a.shape() [2, 1, 3, 0, 0, 2] """ - return LatticeDiagram([max(0, len(self[i]) - 1) - for i in range(1, len(self) + 1)]) + return LatticeDiagram([max(0, len(self[i]) - 1) for i in range(1, len(self) + 1)]) def __contains__(self, ij): r""" @@ -312,8 +310,7 @@ def boxes(self): (5, 0), (6, 0)] """ - return self.shape().boxes() + [(i, 0) - for i in range(1, len(self.shape()) + 1)] + return self.shape().boxes() + [(i, 0) for i in range(1, len(self.shape()) + 1)] def attacking_boxes(self): """ @@ -435,6 +432,7 @@ def reading_order(self): def fn(ij): return (-ij[1], -ij[0]) + boxes.sort(key=fn) return boxes @@ -496,9 +494,8 @@ def _inv_aux(self): res = 0 shape = self.shape() for i in range(1, len(self) + 1): - a = self._list[i-1][0] - res += sum(1 for j in range(i + 1, len(self) + 1) - if shape[i] <= shape[j] and a < self._list[j-1][0]) + a = self._list[i - 1][0] + res += sum(1 for j in range(i + 1, len(self) + 1) if shape[i] <= shape[j] and a < self._list[j - 1][0]) return res def inv(self): @@ -543,8 +540,7 @@ def coeff(self, q, t): (t - 1)^4/((q^2*t^3 - 1)^2*(q*t^2 - 1)^2) """ shape = self.shape() - return prod((1 - t) / (1 - q**(shape.l(i, j) + 1) * t**(shape.a(i, j) + 1)) - for i, j in shape.boxes() if self[i, j] != self[i, j - 1]) + return prod((1 - t) / (1 - q ** (shape.l(i, j) + 1) * t ** (shape.a(i, j) + 1)) for i, j in shape.boxes() if self[i, j] != self[i, j - 1]) def coeff_integral(self, q, t): r""" @@ -563,10 +559,10 @@ def coeff_integral(self, q, t): shape = self.shape() for i, j in shape.boxes(): if self[i, j] != self[i, j - 1]: - res *= (1 - q**(shape.l(i, j) + 1) * t**(shape.a(i, j) + 1)) + res *= 1 - q ** (shape.l(i, j) + 1) * t ** (shape.a(i, j) + 1) for i, j in shape.boxes(): if self[i, j] == self[i, j - 1]: - res *= (1 - t) + res *= 1 - t return res def permuted_filling(self, sigma): @@ -681,8 +677,7 @@ def __iter__(self): 24 """ if sum(self._shape) == 0: - yield AugmentedLatticeDiagramFilling([[] for _ in self._shape], - self.pi) + yield AugmentedLatticeDiagramFilling([[] for _ in self._shape], self.pi) return for z in NonattackingBacktracker(self._shape, self.pi): @@ -745,11 +740,9 @@ def _rec(self, obj, state): for k in range(1, len(self._shape) + 1): # We check to make sure that k does not # violate any of the attacking conditions - if j == 1 and any(self.pi(x + 1) == k - for x in range(i, len(self._shape))): + if j == 1 and any(self.pi(x + 1) == k for x in range(i, len(self._shape))): continue - if any(obj[ii - 1][jj - 1] == k for ii, jj in - self._shape.boxes_same_and_lower_right(i, j) if jj != 0): + if any(obj[ii - 1][jj - 1] == k for ii, jj in self._shape.boxes_same_and_lower_right(i, j) if jj != 0): continue # Fill in the in the i,j box with k+1 @@ -899,7 +892,7 @@ def E(mu, q=None, t=None, pi=None): res = R.zero() for a in n: weight = a.weight() - res += q**a.maj() * t**a.coinv() * a.coeff(q, t) * prod(x[i]**weight[i] for i in range(len(weight))) + res += q ** a.maj() * t ** a.coinv() * a.coeff(q, t) * prod(x[i] ** weight[i] for i in range(len(weight))) return res @@ -958,7 +951,7 @@ def E_integral(mu, q=None, t=None, pi=None): res = R.zero() for a in n: weight = a.weight() - res += q**a.maj() * t**a.coinv() * a.coeff_integral(q, t) * prod(x[i]**weight[i] for i in range(len(weight))) + res += q ** a.maj() * t ** a.coinv() * a.coeff_integral(q, t) * prod(x[i] ** weight[i] for i in range(len(weight))) return res @@ -1000,5 +993,5 @@ def Ht(mu, q=None, t=None, pi=None): res = R.zero() for a in n: weight = a.weight() - res += q**a.maj() * t**a.inv() * prod(x[i]**weight[i] for i in range(len(weight))) + res += q ** a.maj() * t ** a.inv() * prod(x[i] ** weight[i] for i in range(len(weight))) return res diff --git a/src/sage/combinat/sf/orthogonal.py b/src/sage/combinat/sf/orthogonal.py index 62e406e3272..56123ebc9b9 100644 --- a/src/sage/combinat/sf/orthogonal.py +++ b/src/sage/combinat/sf/orthogonal.py @@ -169,8 +169,7 @@ def __init__(self, Sym): sage: o = SymmetricFunctions(QQ).o() sage: TestSuite(o).run() """ - sfa.SymmetricFunctionAlgebra_generic.__init__(self, Sym, "orthogonal", - 'o', graded=False) + sfa.SymmetricFunctionAlgebra_generic.__init__(self, Sym, "orthogonal", 'o', graded=False) # We make a strong reference since we use it for our computations # and so we can define the coercion below (only codomains have @@ -178,11 +177,9 @@ def __init__(self, Sym): self._s = Sym.schur() # Setup the coercions - M = self._s.module_morphism(self._s_to_o_on_basis, codomain=self, - triangular='upper', unitriangular=True) + M = self._s.module_morphism(self._s_to_o_on_basis, codomain=self, triangular='upper', unitriangular=True) M.register_as_coercion() - Mi = self.module_morphism(self._o_to_s_on_basis, codomain=self._s, - triangular='upper', unitriangular=True) + Mi = self.module_morphism(self._o_to_s_on_basis, codomain=self._s, triangular='upper', unitriangular=True) Mi.register_as_coercion() @cached_method @@ -204,13 +201,7 @@ def _o_to_s_on_basis(self, lam): """ R = self.base_ring() n = sum(lam) - return self._s._from_dict({ mu: R.sum( (-1)**j * lrcalc.lrcoef_unsafe(lam, mu, nu) - for nu in Partitions(2*j) - if all(nu.arm_length(i,i) == nu.leg_length(i,i)+1 - for i in range(nu.frobenius_rank())) - ) - for j in range(n//2+1) # // 2 for horizontal dominoes - for mu in Partitions(n-2*j) }) + return self._s._from_dict({mu: R.sum((-1) ** j * lrcalc.lrcoef_unsafe(lam, mu, nu) for nu in Partitions(2 * j) if all(nu.arm_length(i, i) == nu.leg_length(i, i) + 1 for i in range(nu.frobenius_rank()))) for j in range(n // 2 + 1) for mu in Partitions(n - 2 * j)}) # // 2 for horizontal dominoes @cached_method def _s_to_o_on_basis(self, lam): @@ -239,7 +230,4 @@ def _s_to_o_on_basis(self, lam): """ R = self.base_ring() n = sum(lam) - return self._from_dict({ mu: R.sum( lrcalc.lrcoef_unsafe(lam, mu, [2*x for x in nu]) - for nu in Partitions(j) ) - for j in range(n//2+1) # // 2 for horizontal dominoes - for mu in Partitions(n-2*j) }) + return self._from_dict({mu: R.sum(lrcalc.lrcoef_unsafe(lam, mu, [2 * x for x in nu]) for nu in Partitions(j)) for j in range(n // 2 + 1) for mu in Partitions(n - 2 * j)}) # // 2 for horizontal dominoes diff --git a/src/sage/combinat/sf/orthotriang.py b/src/sage/combinat/sf/orthotriang.py index 07d60e6d6dd..b453cad9c7f 100644 --- a/src/sage/combinat/sf/orthotriang.py +++ b/src/sage/combinat/sf/orthotriang.py @@ -213,13 +213,8 @@ def _base_cache(self, n): return self._self_to_base_cache[n] = {} - self._gram_schmidt(n, self._sf_base, self._scalar, - self._self_to_base_cache, - leading_coeff=self._leading_coeff, - upper_triangular=True) - self._invert_morphism(n, self.base_ring(), self._self_to_base_cache, - self._base_to_self_cache, - to_other_function=self._to_base) + self._gram_schmidt(n, self._sf_base, self._scalar, self._self_to_base_cache, leading_coeff=self._leading_coeff, upper_triangular=True) + self._invert_morphism(n, self.base_ring(), self._self_to_base_cache, self._base_to_self_cache, to_other_function=self._to_base) def _to_base(self, part): r""" @@ -300,6 +295,7 @@ class OrthotriangBasisFunctor(SymmetricFunctionsFunctor): sage: s.construction() (SymmetricFunctionsFunctor[Schur], Rational Field) """ + def __init__(self, basis): r""" Initialize the functor. @@ -341,9 +337,8 @@ def _apply_functor(self, R): Symmetric Functions over Algebraic Field in the Schur functions basis """ from sage.combinat.sf.sf import SymmetricFunctions - return self._basis(SymmetricFunctions(R), self._sf_base.change_ring(R), - self._scalar, self._prefix, self._basis_name, - self._leading_coeff) + + return self._basis(SymmetricFunctions(R), self._sf_base.change_ring(R), self._scalar, self._prefix, self._basis_name, self._leading_coeff) # Backward compatibility for unpickling diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index 12a2118f8be..90fd30b0cfd 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -105,7 +105,7 @@ def antipode_on_basis(self, partition): if len(partition) % 2 == 0: return self[partition] return -self[partition] - #This is slightly faster than: return (-1)**len(partition) * self[partition] + # This is slightly faster than: return (-1)**len(partition) * self[partition] def bottom_schur_function(self, partition, degree=None): r""" @@ -160,14 +160,13 @@ def bottom_schur_function(self, partition, degree=None): 1/8*p[2, 2, 1] - 1/6*p[3, 1, 1] """ from sage.combinat.partition import _Partitions + s = self.realization_of().schur() partition = _Partitions(partition) if degree is None: degree = partition.frobenius_rank() s_partition = self(s[partition]) - return self.sum_of_terms([(p, coeff) for p, coeff - in s_partition if len(p) == degree], - distinct=True) + return self.sum_of_terms([(p, coeff) for p, coeff in s_partition if len(p) == degree], distinct=True) def eval_at_permutation_roots_on_generators(self, k, rho): r""" @@ -214,7 +213,7 @@ def eval_at_permutation_roots_on_generators(self, k, rho): sage: p.eval_at_permutation_roots_on_generators(3, [1,1,1,1,1]) 5 """ - return self.base_ring().sum(d*list(rho).count(d) for d in divisors(k)) + return self.base_ring().sum(d * list(rho).count(d) for d in divisors(k)) def _magma_init_(self, magma): """ @@ -288,7 +287,7 @@ def omega(self): sage: (p([3,1,1]) - 2 * p([2,1])).omega() 2*p[2, 1] + p[3, 1, 1] """ - f = lambda part, coeff: (part, (-1)**(sum(part)-len(part)) * coeff) + f = lambda part, coeff: (part, (-1) ** (sum(part) - len(part)) * coeff) return self.map_item(f) omega_involution = omega @@ -490,8 +489,7 @@ def adams_operator(self, n): :meth:`~sage.combinat.sf.sfa.SymmetricFunctionAlgebra_generic_Element.plethysm` """ - dct = {lam.stretch(n): coeff - for lam, coeff in self.monomial_coefficients().items()} + dct = {lam.stretch(n): coeff for lam, coeff in self.monomial_coefficients().items()} return self.parent()._from_dict(dct) def verschiebung(self, n): @@ -611,9 +609,7 @@ def verschiebung(self, n): """ parent = self.parent() p_coords_of_self = self.monomial_coefficients().items() - dct = {Partition([i // n for i in lam]): coeff * (n ** len(lam)) - for (lam, coeff) in p_coords_of_self - if all(i % n == 0 for i in lam)} + dct = {Partition([i // n for i in lam]): coeff * (n ** len(lam)) for (lam, coeff) in p_coords_of_self if all(i % n == 0 for i in lam)} result_in_p_basis = parent._from_dict(dct) return parent(result_in_p_basis) @@ -660,7 +656,7 @@ def expand(self, n, alphabet='x'): sage: (3*p([])).expand(0) 3 """ - if n == 0: # Symmetrica crashes otherwise... + if n == 0: # Symmetrica crashes otherwise... return self.counit() condition = lambda part: False return self._expand(condition, n, alphabet) @@ -712,8 +708,7 @@ def eval_at_permutation_roots(self, rho): """ p = self.parent() R = self.base_ring() - on_basis = lambda lam: R.prod( - p.eval_at_permutation_roots_on_generators(k, rho) for k in lam) + on_basis = lambda lam: R.prod(p.eval_at_permutation_roots_on_generators(k, rho) for k in lam) return p._apply_module_morphism(self, on_basis, R) def principal_specialization(self, n=infinity, q=None): @@ -801,6 +796,7 @@ def get_variable(ring, name): from sage.rings.polynomial.polynomial_ring_constructor import ( PolynomialRing, ) + return PolynomialRing(ring, name).gen() else: raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) @@ -811,11 +807,12 @@ def get_variable(ring, name): if q == 1: if n == infinity: raise ValueError("the stable principal specialization at q=1 is not defined") - f = lambda partition: n**len(partition) + f = lambda partition: n ** len(partition) elif n == infinity: - f = lambda partition: prod(1/(1-q**part) for part in partition) + f = lambda partition: prod(1 / (1 - q**part) for part in partition) else: from sage.rings.integer_ring import ZZ + ZZq = PolynomialRing(ZZ, "q") q_lim = ZZq.gen() @@ -823,12 +820,12 @@ def f(partition): denom = prod((1 - q**part) for part in partition) try: ~denom - rational = prod((1 - q**(n*part)) for part in partition) / denom + rational = prod((1 - q ** (n * part)) for part in partition) / denom return q.parent()(rational) except (ZeroDivisionError, NotImplementedError, TypeError): # If denom is not invertible, we need to do the # computation with universal coefficients instead: - quotient = ZZq(prod((1-q_lim**(n*part))/(1-q_lim**part) for part in partition)) + quotient = ZZq(prod((1 - q_lim ** (n * part)) / (1 - q_lim**part) for part in partition)) return quotient.subs({q_lim: q}) return self.parent()._apply_module_morphism(self, f, q.parent()) @@ -907,6 +904,7 @@ def exponential_specialization(self, t=None, q=1): sage: p.zero().exponential_specialization() 0 """ + def get_variable(ring, name): try: ring(name) @@ -914,6 +912,7 @@ def get_variable(ring, name): from sage.rings.polynomial.polynomial_ring_constructor import ( PolynomialRing, ) + return PolynomialRing(ring, name).gen() else: raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) @@ -925,7 +924,7 @@ def get_variable(ring, name): def f(partition): if partition and partition[0] != 1: return 0 - return t**len(partition) + return t ** len(partition) return self.parent()._apply_module_morphism(self, f, t.parent()) @@ -942,8 +941,8 @@ def f(partition): m = 1 for part in partition: n += part - m *= 1-q**part - return (1-q)**n * t**n / m + m *= 1 - q**part + return (1 - q) ** n * t**n / m return self.parent()._apply_module_morphism(self, f, t.parent()) @@ -951,6 +950,4 @@ def f(partition): # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.sf.powersum', - 'SymmetricFunctionAlgebraElement_power', - SymmetricFunctionAlgebra_power.Element) +register_unpickle_override('sage.combinat.sf.powersum', 'SymmetricFunctionAlgebraElement_power', SymmetricFunctionAlgebra_power.Element) diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index 7a3a039dcc7..fd09fd0e73c 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -132,8 +132,7 @@ def product_on_basis(self, left, right): sage: s[2,1]^2 s[2, 2, 1, 1] + s[2, 2, 2] + s[3, 1, 1, 1] + s[3, 3] + s[4, 1, 1] + s[4, 2] """ - return self.element_class(self, convert_remove_zeroes(lrcalc.mult(left, right), - self.base_ring())) + return self.element_class(self, convert_remove_zeroes(lrcalc.mult(left, right), self.base_ring())) def coproduct_on_basis(self, mu): r""" @@ -166,8 +165,7 @@ def coproduct_on_basis(self, mu): 1/2*s[] # s[2] + 1/2*s[1] # s[1] + 1/2*s[2] # s[] """ T = self.tensor_square() - return T.element_class(T, convert_remove_zeroes(lrcalc.coprod(mu, all=1), - self.base_ring())) + return T.element_class(T, convert_remove_zeroes(lrcalc.coprod(mu, all=1), self.base_ring())) def _element_constructor_(self, x): """ @@ -217,12 +215,11 @@ def _repeated_bernstein_creation_operator_on_basis(self, la, nu): s[] """ r = len(nu) + len(la) - ga = [a-b for (a,b) in zip(nu+la.to_list(), range(-r,0))] + ga = [a - b for (a, b) in zip(nu + la.to_list(), range(-r, 0))] if r == len(set(ga)) and min(ga) > 0: - m = sum(1 for i in range(len(ga)) for j in range(i, len(ga)) - if ga[i] < ga[j]) + m = sum(1 for i in range(len(ga)) for j in range(i, len(ga)) if ga[i] < ga[j]) ga.sort(reverse=True) - return (-1)**m * self([a+b for (a,b) in zip(ga, range(-r,0))]) + return (-1) ** m * self([a + b for (a, b) in zip(ga, range(-r, 0))]) return self.zero() def _magma_init_(self, magma): @@ -409,7 +406,7 @@ def scalar(self, x, zee=None): x = s(x) return s._apply_multi_module_morphism(self, x, f, orthogonal=True) p = self.parent().realization_of().power() - return p(self).scalar( x, zee=zee ) + return p(self).scalar(x, zee=zee) def verschiebung(self, n): r""" @@ -538,26 +535,25 @@ def verschiebung(self, n): s_coords_of_self = self.monomial_coefficients().items() result = parent.zero() from sage.combinat.permutation import Permutation - for (lam, coeff) in s_coords_of_self: + + for lam, coeff in s_coords_of_self: if len(lam.core(n)) == 0: quotient = lam.quotient(n) - quotient_prod = parent.prod(parent(part) - for part in quotient) + quotient_prod = parent.prod(parent(part) for part in quotient) # Now, compute the sign of quotient_prod in the # n-th Verschiebung of lam. len_lam = len(lam) - ns = len_lam + ((- len_lam) % n) - s = ns // n # This is actually ns / n, as we have n | ns. + ns = len_lam + ((-len_lam) % n) + s = ns // n # This is actually ns / n, as we have n | ns. beta_list = lam.beta_numbers(ns) - zipped_beta_list = sorted(zip(beta_list, range(1, ns + 1)), - key=lambda a: (-1 - a[0]) % n) + zipped_beta_list = sorted(zip(beta_list, range(1, ns + 1)), key=lambda a: (-1 - a[0]) % n) # We are using the fact that sort is a stable sort. perm_list = [a[1] for a in zipped_beta_list] if Permutation(perm_list).sign() == 1: minus_sign = False else: minus_sign = True - if (n * s * (n-1) * (s-1)) % 8 == 4: + if (n * s * (n - 1) * (s - 1)) % 8 == 4: minus_sign = not minus_sign if minus_sign: result -= coeff * quotient_prod @@ -687,8 +683,7 @@ def principal_specialization(self, n=infinity, q=None): if n == 1: R = self.base_ring() mc = self.monomial_coefficients(copy=False).items() - return R.sum(c for partition, c in mc - if len(partition) <= 1) + return R.sum(c for partition, c in mc if len(partition) <= 1) def get_variable(ring, name): try: @@ -697,6 +692,7 @@ def get_variable(ring, name): from sage.rings.polynomial.polynomial_ring_constructor import ( PolynomialRing, ) + return PolynomialRing(ring, name).gen() else: raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) @@ -706,34 +702,28 @@ def get_variable(ring, name): if q == 1: if n == infinity: raise ValueError("the stable principal specialization at q=1 is not defined") - f = lambda partition: (prod(n+j-i for (i, j) in partition.cells()) - // prod(h for h in partition.hooks())) + f = lambda partition: (prod(n + j - i for (i, j) in partition.cells()) // prod(h for h in partition.hooks())) elif n == infinity: - f = lambda partition: (q**sum(i*part for i, part in enumerate(partition)) - / prod(1-q**h for h in partition.hooks())) + f = lambda partition: (q ** sum(i * part for i, part in enumerate(partition)) / prod(1 - q**h for h in partition.hooks())) else: from sage.rings.integer_ring import ZZ + ZZq = PolynomialRing(ZZ, "q") q_lim = ZZq.gen() def f(partition): if n < len(partition): return 0 - power = q**sum(i * part for i, part in enumerate(partition)) + power = q ** sum(i * part for i, part in enumerate(partition)) denom = prod(1 - q**h for h in partition.hooks()) try: ~denom - rational = (power - * prod(1-q**(n+j-i) - for (i, j) in partition.cells()) - / denom) + rational = power * prod(1 - q ** (n + j - i) for (i, j) in partition.cells()) / denom return q.parent()(rational) except (ZeroDivisionError, NotImplementedError, TypeError): # If denom is not invertible, we need to do the # computation with universal coefficients instead: - quotient = ZZq((prod(1-q_lim**(n+j-i) - for (i, j) in partition.cells())) - / prod(1-q_lim**h for h in partition.hooks())) + quotient = ZZq((prod(1 - q_lim ** (n + j - i) for (i, j) in partition.cells())) / prod(1 - q_lim**h for h in partition.hooks())) return power * quotient.subs({q_lim: q}) return self.parent()._apply_module_morphism(self, f, q.parent()) @@ -832,6 +822,7 @@ def exponential_specialization(self, t=None, q=1): sage: s.zero().exponential_specialization() 0 """ + def get_variable(ring, name): try: ring(name) @@ -839,6 +830,7 @@ def get_variable(ring, name): from sage.rings.polynomial.polynomial_ring_constructor import ( PolynomialRing, ) + return PolynomialRing(ring, name).gen() else: raise ValueError("the variable %s is in the base ring, pass it explicitly" % name) @@ -849,8 +841,7 @@ def get_variable(ring, name): def f(partition): n = partition.size() - return (StandardTableaux(partition).cardinality() - * t**n / factorial(n)) + return StandardTableaux(partition).cardinality() * t**n / factorial(n) return self.parent()._apply_module_morphism(self, f, t.parent()) @@ -862,9 +853,7 @@ def f(partition): elif t is None: t = get_variable(q.parent(), 't') - f = lambda partition: (t**partition.size() - * q**sum(i*part for i, part in enumerate(partition)) - / prod(sum(q**i for i in range(h)) for h in partition.hooks())) + f = lambda partition: (t ** partition.size() * q ** sum(i * part for i, part in enumerate(partition)) / prod(sum(q**i for i in range(h)) for h in partition.hooks())) return self.parent()._apply_module_morphism(self, f, t.parent()) @@ -872,6 +861,4 @@ def f(partition): # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.combinat.sf.schur', - 'SymmetricFunctionAlgebraElement_schur', - SymmetricFunctionAlgebra_schur.Element) +register_unpickle_override('sage.combinat.sf.schur', 'SymmetricFunctionAlgebraElement_schur', SymmetricFunctionAlgebra_schur.Element) diff --git a/src/sage/combinat/sf/sf.py b/src/sage/combinat/sf/sf.py index 9866752ccda..095fd9d229f 100644 --- a/src/sage/combinat/sf/sf.py +++ b/src/sage/combinat/sf/sf.py @@ -851,6 +851,7 @@ class function on the symmetric group where the elements - Devise a mechanism so that pickling bases of symmetric functions pickles the coercions which have a cache. """ + def __init__(self, R): r""" Initialization of ``self``. @@ -910,6 +911,7 @@ def schur(self): Symmetric Functions over Rational Field in the Schur basis """ return schur.SymmetricFunctionAlgebra_schur(self) + s = schur Schur = schur # Currently needed by SymmetricFunctions.__init_extra__ @@ -923,6 +925,7 @@ def powersum(self): Symmetric Functions over Rational Field in the powersum basis """ return powersum.SymmetricFunctionAlgebra_power(self) + p = powersum power = powersum # Todo: get rid of the line above when it won't be needed anymore @@ -937,6 +940,7 @@ def complete(self): Symmetric Functions over Rational Field in the homogeneous basis """ return homogeneous.SymmetricFunctionAlgebra_homogeneous(self) + h = complete homogeneous = complete @@ -950,6 +954,7 @@ def elementary(self): Symmetric Functions over Rational Field in the elementary basis """ return elementary.SymmetricFunctionAlgebra_elementary(self) + e = elementary def monomial(self): @@ -962,6 +967,7 @@ def monomial(self): Symmetric Functions over Rational Field in the monomial basis """ return monomial.SymmetricFunctionAlgebra_monomial(self) + m = monomial def witt(self): @@ -974,6 +980,7 @@ def witt(self): Symmetric Functions over Rational Field in the Witt basis """ from . import witt + return witt.SymmetricFunctionAlgebra_witt(self) w = witt @@ -1020,6 +1027,7 @@ def irreducible_symmetric_group_character(self): [4, 2, 0, 1, -1, 0, -1] """ from .character import IrreducibleCharacterBasis + return IrreducibleCharacterBasis(self) st = irreducible_symmetric_group_character @@ -1076,6 +1084,7 @@ def induced_trivial_character(self): [0, 1, 0, 2, 1, 3, 5] """ from .character import InducedTrivialCharacterBasis + return InducedTrivialCharacterBasis(self) ht = induced_trivial_character @@ -1138,6 +1147,7 @@ def irreducible_rook_character(self): -s[1] + s[1, 1] - s[1, 1, 1] + 2*s[2] - 2*s[2, 1] - s[3] + s[3, 1] """ from .character import RookIrreducibleCharacterBasis + return RookIrreducibleCharacterBasis(self) xt = irreducible_rook_character @@ -1225,6 +1235,7 @@ def forgotten(self): integral coefficients whenever `\lambda` is a strict partition. """ return self.elementary().dual_basis() + f = forgotten def symplectic(self): @@ -1239,7 +1250,9 @@ def symplectic(self): Symmetric Functions over Rational Field in the symplectic basis """ from . import symplectic + return symplectic.SymmetricFunctionAlgebra_symplectic(self) + sp = symplectic def orthogonal(self): @@ -1254,7 +1267,9 @@ def orthogonal(self): Symmetric Functions over Rational Field in the orthogonal basis """ from . import orthogonal + return orthogonal.SymmetricFunctionAlgebra_orthogonal(self) + o = orthogonal def hecke_character(self, q='q'): @@ -1272,7 +1287,9 @@ def hecke_character(self, q='q'): Symmetric Functions over Rational Field in the Hecke character with q=1/2 basis """ from sage.combinat.sf.hecke import HeckeCharacter + return HeckeCharacter(self, q) + qbar = hecke_character def macdonald(self, q='q', t='t'): @@ -1394,6 +1411,7 @@ def abreu_nigro(self, q='q'): Symmetric Functions over Fraction Field of Univariate Polynomial Ring in q over Integer Ring in the Abreu-Nigro basis """ from sage.combinat.sf.abreu_nigro import SymmetricFunctionAlgebra_AbreuNigro + return SymmetricFunctionAlgebra_AbreuNigro(self, q) def zonal(self): @@ -1527,19 +1545,19 @@ def __init_extra__(self): from sage.combinat.sf.classical import conversion_functions - for (basis1_name, basis2_name) in conversion_functions: + for basis1_name, basis2_name in conversion_functions: basis1 = getattr(self, basis1_name)() basis2 = getattr(self, basis2_name)() on_basis = SymmetricaConversionOnBasis(t=conversion_functions[basis1_name, basis2_name], domain=basis1, codomain=basis2) from sage.rings.rational_field import RationalField + if basis2_name != "powersum" or self._base.has_coerce_map_from(RationalField()): iso(basis1._module_morphism(on_basis, codomain=basis2)) else: # Don't register conversions to powersums as coercions, # unless the base ring is a `\QQ`-algebra # (otherwise the coercion graph loses commutativity). - iso(basis1._module_morphism(on_basis, codomain=basis2), - only_conversion=True) + iso(basis1._module_morphism(on_basis, codomain=basis2), only_conversion=True) # Todo: fill in with other conversion functions on the classical bases @@ -1577,6 +1595,7 @@ def kBoundedSubspace(self, k, t='t'): 3-bounded Symmetric Functions over Univariate Polynomial Ring in z over Rational Field with t=z """ from sage.combinat.sf.new_kschur import KBoundedSubspace + return KBoundedSubspace(self, k, t=t) def kschur(self, k, t='t'): @@ -1660,6 +1679,7 @@ def kBoundedQuotient(self, k, t='t'): 3-Bounded Quotient of Symmetric Functions over Fraction Field of Univariate Polynomial Ring in t over Rational Field """ from sage.combinat.sf.k_dual import KBoundedQuotient + return KBoundedQuotient(self, k, t) diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 28c81a22155..4cea95b7ea0 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -223,11 +223,8 @@ from sage.categories.tensor import tensor from sage.categories.unique_factorization_domains import UniqueFactorizationDomains from sage.combinat.free_module import CombinatorialFreeModule -from sage.combinat.partition import ( - Partition, Partitions, Partitions_n, _Partitions -) -from sage.data_structures.blas_dict import (convert_remove_zeroes, - linear_combination) +from sage.combinat.partition import Partition, Partitions, Partitions_n, _Partitions +from sage.data_structures.blas_dict import convert_remove_zeroes, linear_combination from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method from sage.misc.misc_c import prod @@ -274,6 +271,7 @@ def zee(part) -> Integer: ##################################################################### # Bases categories + class SymmetricFunctionsBases(Category_realization_of_parent): r""" The category of bases of the ring of symmetric functions. @@ -341,9 +339,7 @@ def super_categories(self) -> list: # KeyError when doing the C3 algorithm!!! R = self.base().base_ring() cat = HopfAlgebras(R) - categories = [self.base().Realizations(), - cat.Commutative().WithBasis(), - cat.Graded().Realizations()] + categories = [self.base().Realizations(), cat.Commutative().WithBasis(), cat.Graded().Realizations()] if R in PrincipalIdealDomains: categories.append(UniqueFactorizationDomains()) return categories @@ -386,6 +382,7 @@ def fraction_field(self): if not self.is_integral_domain(): raise TypeError("self must be an integral domain") from sage.rings.fraction_field import FractionField_generic + return FractionField_generic(self) def is_field(self, proof=True) -> bool: @@ -541,8 +538,7 @@ def _repr_(self) -> str: sage: Sym.rename() """ - return "%s in the %s basis" % (self.realization_of(), - self.basis_name()) + return "%s in the %s basis" % (self.realization_of(), self.basis_name()) @cached_method def one_basis(self): @@ -625,9 +621,11 @@ def skew_schur(self, x): s[1, 1, 1] + s[3] """ from sage.combinat.skew_partition import SkewPartitions + if x not in SkewPartitions(): raise ValueError("not a valid skew partition") from sage.libs.lrcalc import lrcalc + s = self.realization_of().schur() R = self.base_ring() skewschur = lrcalc.skew(x[0], x[1]) @@ -677,6 +675,7 @@ def Eulerian(self, n, j, k=None): s[3, 2, 1] + s[3, 3] + 3*s[4, 2] + 3*s[5, 1] + 3*s[6] """ from sage.combinat.ncsf_qsym.qsym import QuasiSymmetricFunctions + F = QuasiSymmetricFunctions(self.base_ring()).F() if n in _Partitions: n = _Partitions(n) @@ -896,13 +895,13 @@ def gessel_reutenauer(self, lam): p = self.realization_of().power() h = self.realization_of().complete() from sage.arith.misc import moebius, squarefree_divisors + mu = moebius def component(i, g): # == h_g[L_i] - L_i = p.sum_of_terms([(_Partitions([d] * (i//d)), R(mu(d))) - for d in squarefree_divisors(i)], - distinct=True) / i + L_i = p.sum_of_terms([(_Partitions([d] * (i // d)), R(mu(d))) for d in squarefree_divisors(i)], distinct=True) / i return p(h[g]).plethysm(L_i) + return self(p.prod(component(i, g) for i, g in m.items())) # The base ring does not coerce into `\QQ` @@ -927,12 +926,12 @@ def component(i, g): # == h_g[L_i] # slow!) instead. comp_parent = self.realization_of().schur() from sage.combinat.sf.sf import SymmetricFunctions + corresponding_parent_over_QQ = SymmetricFunctions(QQ).schur() corresponding_result = corresponding_parent_over_QQ.gessel_reutenauer(lam) comp_base_ring = comp_parent.base_ring() - result = comp_parent.sum_of_terms((nu, comp_base_ring(c)) - for nu, c in corresponding_result) - return self(result) # just in case comp_parent != self. + result = comp_parent.sum_of_terms((nu, comp_base_ring(c)) for nu, c in corresponding_result) + return self(result) # just in case comp_parent != self. higher_lie_character = gessel_reutenauer @@ -1064,12 +1063,11 @@ def lehrer_solomon(self, lam): h = self.realization_of().complete() e = self.realization_of().elementary() from sage.arith.misc import moebius, squarefree_divisors + mu = moebius def component(i, g): # == h_g[L_i] or e_g[L_i] - L_i = p.sum_of_terms(((_Partitions([d] * (i//d)), R(mu(d))) - for d in squarefree_divisors(i)), - distinct=True) / i + L_i = p.sum_of_terms(((_Partitions([d] * (i // d)), R(mu(d))) for d in squarefree_divisors(i)), distinct=True) / i if i % 2: return p(h[g]).plethysm(L_i.omega()) return p(e[g]).plethysm(L_i.omega()) @@ -1098,12 +1096,12 @@ def component(i, g): # == h_g[L_i] or e_g[L_i] # slow!) instead. comp_parent = self.realization_of().schur() from sage.combinat.sf.sf import SymmetricFunctions + corresponding_parent_over_QQ = SymmetricFunctions(QQ).schur() corresponding_result = corresponding_parent_over_QQ.lehrer_solomon(lam) comp_base_ring = comp_parent.base_ring() - result = comp_parent.sum_of_terms((nu, comp_base_ring(c)) - for nu, c in corresponding_result) - return self(result) # just in case comp_parent != self. + result = comp_parent.sum_of_terms((nu, comp_base_ring(c)) for nu, c in corresponding_result) + return self(result) # just in case comp_parent != self. whitney_homology_character = lehrer_solomon @@ -1302,6 +1300,7 @@ def carlitz_shareshian_wachs(self, n, d, s, comparison=None): R = self.base_ring() m = self.realization_of().m() from sage.combinat.permutation import Permutations_mset + # Defining a ``check_word`` function. This function will be used # to check if an `n`-tuple `w` of positive integers belongs to # `W(n, d, s)` and satisfies the additional requirement @@ -1310,43 +1309,48 @@ def carlitz_shareshian_wachs(self, n, d, s, comparison=None): # ``comparison`` needs not be called a myriad of times. Might # be folly. if comparison is None: + def check_word(w): - if sum(1 for i in range(n-1) if w[i] > w[i+1]) != d: + if sum(1 for i in range(n - 1) if w[i] > w[i + 1]) != d: return False return sum(1 for i in range(n - 1) if w[i] == w[i + 1]) == s + elif comparison == -1: + def check_word(w): - if sum(1 for i in range(n-1) if w[i] > w[i+1]) != d: + if sum(1 for i in range(n - 1) if w[i] > w[i + 1]) != d: return False - if sum(1 for i in range(n-1) if w[i] == w[i+1]) != s: + if sum(1 for i in range(n - 1) if w[i] == w[i + 1]) != s: return False return w[0] < w[-1] + elif comparison == 0: + def check_word(w): - if sum(1 for i in range(n-1) if w[i] > w[i+1]) != d: + if sum(1 for i in range(n - 1) if w[i] > w[i + 1]) != d: return False - if sum(1 for i in range(n-1) if w[i] == w[i+1]) != s: + if sum(1 for i in range(n - 1) if w[i] == w[i + 1]) != s: return False return w[0] == w[-1] + elif comparison == 1: + def check_word(w): - if sum(1 for i in range(n-1) if w[i] > w[i+1]) != d: + if sum(1 for i in range(n - 1) if w[i] > w[i + 1]) != d: return False - if sum(1 for i in range(n-1) if w[i] == w[i+1]) != s: + if sum(1 for i in range(n - 1) if w[i] == w[i + 1]) != s: return False return w[0] > w[-1] def coeff_of_m_mu_in_result(mu): # Compute the coefficient of the monomial symmetric # function ``m[mu]`` in the result. - words_to_check = Permutations_mset([i for i, l in enumerate(mu) - for _ in range(l)]) + words_to_check = Permutations_mset([i for i, l in enumerate(mu) for _ in range(l)]) return R(sum(1 for w in words_to_check if check_word(w))) from sage.combinat.partition import Partitions_n - r = m.sum_of_terms([(mu, coeff_of_m_mu_in_result(mu)) - for mu in Partitions_n(n)], - distinct=True) + + r = m.sum_of_terms([(mu, coeff_of_m_mu_in_result(mu)) for mu in Partitions_n(n)], distinct=True) return self(r) def abreu_nigro_g(self, H, k, q='q'): @@ -1462,7 +1466,7 @@ def abreu_nigro_g(self, H, k, q='q'): if not H: return self.one() n = len(H) - if not all(max(i+1, H[i-1]) <= H[i] for i in range(1, n)) or H[-1] > n: + if not all(max(i + 1, H[i - 1]) <= H[i] for i in range(1, n)) or H[-1] > n: raise ValueError(f"{H} is not a Hessenberg function") if k < 0 or k >= n: raise ValueError(f"k must be between 0 and {n}") @@ -1470,6 +1474,7 @@ def abreu_nigro_g(self, H, k, q='q'): h = self.realization_of().h() rho = self.realization_of().abreu_nigro(q) from sage.combinat.permutation import Permutations + for sigma in Permutations(n): # Filter out the permutations not used in the sum if any(sigma[i] > H[i] for i in range(n)): @@ -1479,13 +1484,12 @@ def abreu_nigro_g(self, H, k, q='q'): continue sc = sum(tau, ()) # We use 0-based i and j - sc_pos = {i-1: pos for pos, i in enumerate(sc)} - inv = sum(1 for j in range(1, n) for i in range(j) if j < H[i] - and sc_pos[j] < sc_pos[i]) + sc_pos = {i - 1: pos for pos, i in enumerate(sc)} + inv = sum(1 for j in range(1, n) for i in range(j) if j < H[i] and sc_pos[j] < sc_pos[i]) K = len(tau[0]) - n + k lam = [len(tau[i]) for i in range(1, len(tau))] lam.sort(reverse=True) - ret += (-1)**K * q**inv * self(h[K] * h(rho[lam]).omega()) + ret += (-1) ** K * q**inv * self(h[K] * h(rho[lam]).omega()) return ret def formal_series_ring(self): @@ -1509,6 +1513,7 @@ def formal_series_ring(self): True """ from sage.rings.lazy_series_ring import LazySymmetricFunctions + return LazySymmetricFunctions(self) completion = formal_series_ring @@ -1725,8 +1730,7 @@ def degree_negation(self, element): sage: m.degree_negation(m(e[3])) -m[1, 1, 1] """ - return self.sum_of_terms([(lam, (-1)**(sum(lam) % 2) * a) - for lam, a in self(element)]) + return self.sum_of_terms([(lam, (-1) ** (sum(lam) % 2) * a) for lam, a in self(element)]) class ElementMethods: def degree_negation(self): @@ -1752,8 +1756,7 @@ def degree_negation(self): sage: parent(x) is m True """ - return self.parent().sum_of_terms([(lam, (-1)**(sum(lam) % 2) * a) - for lam, a in self]) + return self.parent().sum_of_terms([(lam, (-1) ** (sum(lam) % 2) * a) for lam, a in self]) def degree_zero_coefficient(self): r""" @@ -1793,6 +1796,7 @@ def is_unit(self) -> bool: ##################################################################### # ABC for bases of the symmetric functions + class SymmetricFunctionAlgebra_generic(CombinatorialFreeModule): r""" Abstract base class for symmetric function algebras. @@ -1809,6 +1813,7 @@ class SymmetricFunctionAlgebra_generic(CombinatorialFreeModule): sage: s(m([2,1])) -2*s[1, 1, 1] + s[2, 1] """ + def __init__(self, Sym, basis_name=None, prefix=None, graded=True) -> None: r""" Initialize the symmetric function algebra. @@ -1831,6 +1836,7 @@ def __init__(self, Sym, basis_name=None, prefix=None, graded=True) -> None: """ R = Sym.base_ring() from sage.categories.commutative_rings import CommutativeRings + if R not in CommutativeRings(): raise TypeError("argument R must be a commutative ring") try: @@ -1846,9 +1852,7 @@ def __init__(self, Sym, basis_name=None, prefix=None, graded=True) -> None: cat = GradedSymmetricFunctionsBases(Sym) else: # Right now, there are no non-filtered bases cat = FilteredSymmetricFunctionsBases(Sym) - CombinatorialFreeModule.__init__(self, Sym.base_ring(), _Partitions, - category=cat, - bracket='', prefix=prefix) + CombinatorialFreeModule.__init__(self, Sym.base_ring(), _Partitions, category=cat, bracket='', prefix=prefix) _print_style = 'lex' @@ -1920,7 +1924,7 @@ def _change_by_proportionality(self, x, function): z_elt = {} for m, c in x._monomial_coefficients.items(): coeff = function(m) - z_elt[m] = BR(c*coeff) + z_elt[m] = BR(c * coeff) return self._from_dict(z_elt) def _change_by_plethysm(self, x, expr, deg_one): @@ -1958,7 +1962,7 @@ def _change_by_plethysm(self, x, expr, deg_one): p = self.realization_of().power() p_x = p(x) expr_k = lambda k: expr.subs(**{str(x): x**k for x in deg_one}) - f = lambda m, c: (m, c*prod([expr_k(k) for k in m])) + f = lambda m, c: (m, c * prod([expr_k(k) for k in m])) return self(p_x.map_item(f)) # TODO: @@ -2114,11 +2118,7 @@ def _from_cache(self, element, cache_function, cache_dict, **subs_dict): z_elt[part2] = z_elt.get(part2, zero) + BR(c3) return self._from_dict(z_elt) - def _invert_morphism(self, n, base_ring, - self_to_other_cache, other_to_self_cache, - to_other_function=None, to_self_function=None, - upper_triangular=False, lower_triangular=False, - ones_on_diagonal=False): + def _invert_morphism(self, n, base_ring, self_to_other_cache, other_to_self_cache, to_other_function=None, to_self_function=None, upper_triangular=False, lower_triangular=False, ones_on_diagonal=False): r""" Compute the inverse of a morphism between ``self`` and ``other`` (more precisely, its `n`-th graded component). @@ -2324,13 +2324,13 @@ def _invert_morphism(self, n, base_ring, value = e(i) if not ones_on_diagonal: value /= known_matrix_n[i, i] - for j in range(i+1, len_pn): + for j in range(i + 1, len_pn): if ones_on_diagonal: - value -= known_matrix_n[i, j]*x[j] + value -= known_matrix_n[i, j] * x[j] else: - value -= known_matrix_n[i, j]*x[j]/known_matrix_n[i, i] + value -= known_matrix_n[i, j] * x[j] / known_matrix_n[i, i] x[i] = value - for j in range(column+1): + for j in range(column + 1): if x[j] != zero: inverse[j, column] = x[j] @@ -2352,9 +2352,9 @@ def _invert_morphism(self, n, base_ring, value /= known_matrix_n[i, i] for j in range(len(x)): if ones_on_diagonal: - value -= known_matrix_n[i, j]*x[j] + value -= known_matrix_n[i, j] * x[j] else: - value -= known_matrix_n[i, j]*x[j]/known_matrix_n[i, i] + value -= known_matrix_n[i, j] * x[j] / known_matrix_n[i, i] x.append(value) for j in range(column, len(x)): if x[j] != zero: @@ -2586,7 +2586,7 @@ def _gram_schmidt(self, n, source, scalar, cache, leading_coeff=None, upper_tria precomputed_elements.append(res) # Now, res == precomputed_elements[i] cache[l[i]] = {} - for j in range(i+1): + for j in range(i + 1): cache[l[i]][l[j]] = res.coefficient(l[j]) def _inner_plethysm_pk_g(self, k, g, cache): @@ -2655,7 +2655,7 @@ def _inner_plethysm_pk_g(self, k, g, cache): for mu in Partitions_n(d): mu_k = mu.power(k) if mu_k in g.support(): - res += g.coefficient(mu_k)*mu_k.centralizer_size()/mu.centralizer_size()*p(mu) + res += g.coefficient(mu_k) * mu_k.centralizer_size() / mu.centralizer_size() * p(mu) cache[(k, g)] = res return res @@ -2814,14 +2814,13 @@ def dual_basis(self, scalar=None, scalar_name='', basis_name=None, prefix=None): 0 """ from . import dual + if scalar is None: if basis_name is None and prefix is None: return self._dual_basis_default() scalar = zee scalar_name = "Hall scalar product" - return dual.SymmetricFunctionAlgebra_dual(self, scalar, scalar_name, - basis_name=basis_name, - prefix=prefix) + return dual.SymmetricFunctionAlgebra_dual(self, scalar, scalar_name, basis_name=basis_name, prefix=prefix) def basis_name(self): r""" @@ -3016,9 +3015,9 @@ def coproduct_by_coercion(self, elt): f[] # f[3, 2, 1] + f[1] # f[3, 2] + f[2] # f[3, 1] + f[2, 1] # f[3] + f[3] # f[2, 1] + f[3, 1] # f[2] + f[3, 2] # f[1] + f[3, 2, 1] # f[] """ from sage.categories.tensor import tensor + s = self.realization_of().schur() - return self.tensor_square().sum(coeff * tensor([self(s[x]), self(s[y])]) - for (x, y), coeff in s(elt).coproduct()) + return self.tensor_square().sum(coeff * tensor([self(s[x]), self(s[y])]) for (x, y), coeff in s(elt).coproduct()) def construction(self): """ @@ -3032,8 +3031,7 @@ def construction(self): sage: s.construction() (SymmetricFunctionsFunctor[Schur], Integer Ring) """ - return (SymmetricFunctionsFunctor(self, self.basis_name()), - self.base_ring()) + return (SymmetricFunctionsFunctor(self, self.basis_name()), self.base_ring()) def change_ring(self, R): r""" @@ -3136,6 +3134,7 @@ class SymmetricFunctionAlgebra_generic_Element(CombinatorialFreeModule.Element): m[1, 1, 1] + m[2, 1] + m[3] sage: m.set_print_style('lex') """ + def __truediv__(self, x): r""" Return the quotient of ``self`` by ``other``. @@ -3155,6 +3154,7 @@ def __truediv__(self, x): Symmetric Functions over Rational Field in the Schur basis """ from sage.categories.modules import _Fields + B = self.base_ring() try: bx = B(x) @@ -3165,8 +3165,7 @@ def __truediv__(self, x): D = self._monomial_coefficients if B not in _Fields: - return type(self)(F, {k: c._divide_if_possible(x) - for k, c in D.items()}) + return type(self)(F, {k: c._divide_if_possible(x) for k, c in D.items()}) return ~bx * self @@ -3217,6 +3216,7 @@ def factor(self): from sage.combinat.sf.multiplicative import ( SymmetricFunctionAlgebra_multiplicative, ) + L = self.parent() if isinstance(L, SymmetricFunctionAlgebra_multiplicative): M = L @@ -3229,8 +3229,7 @@ def factor(self): unit = self.base_ring()(factors.unit()) if factors.universe() == self.base_ring(): return Factorization(factors, unit=unit) - factors = [(_from_polynomial(factor, M), exponent) - for factor, exponent in factors] + factors = [(_from_polynomial(factor, M), exponent) for factor, exponent in factors] if not isinstance(L, SymmetricFunctionAlgebra_multiplicative): factors = [(L(factor), exponent) for factor, exponent in factors] @@ -3264,6 +3263,7 @@ def _floordiv_(self, other): from sage.combinat.sf.multiplicative import ( SymmetricFunctionAlgebra_multiplicative, ) + # we can assume that the parents of self and other are the same L = self.parent() if isinstance(L, SymmetricFunctionAlgebra_multiplicative): @@ -3316,6 +3316,7 @@ def gcd(self, other): from sage.combinat.sf.multiplicative import ( SymmetricFunctionAlgebra_multiplicative, ) + L = self.parent() if isinstance(L, SymmetricFunctionAlgebra_multiplicative): M = L @@ -3513,6 +3514,7 @@ def plethysm(self, x, include=None, exclude=None): to be faster. This should be investigated. """ from sage.structure.element import parent as get_parent + Px = get_parent(x) parent = self.parent() R = parent.base_ring() @@ -3526,11 +3528,12 @@ def plethysm(self, x, include=None, exclude=None): if R.has_coerce_map_from(Px) or x in R: x = R(x) Px = R - elif (not tensorflag or any(not isinstance(factor, SymmetricFunctionAlgebra_generic) - for factor in Px._sets)): + elif not tensorflag or any(not isinstance(factor, SymmetricFunctionAlgebra_generic) for factor in Px._sets): from sage.rings.lazy_series import LazySymmetricFunction + if isinstance(x, LazySymmetricFunction): from sage.rings.lazy_series_ring import LazySymmetricFunctions + L = LazySymmetricFunctions(parent) return L(self)(x) @@ -3539,9 +3542,7 @@ def plethysm(self, x, include=None, exclude=None): if phi is not None: x = phi(x) elif not tensorflag: - raise TypeError("only know how to compute plethysms " - "between symmetric functions or tensors " - "of symmetric functions") + raise TypeError("only know how to compute plethysms " "between symmetric functions or tensors " "of symmetric functions") p = parent.realization_of().power() @@ -3550,13 +3551,7 @@ def plethysm(self, x, include=None, exclude=None): if tensorflag: tparents = Px._sets lincomb = Px.linear_combination - elt = lincomb((prod((lincomb((tensor([p[r].plethysm(base(la)) - for base, la in zip(tparents, trm)]), - _raise_variables(c, r, degree_one)) - for trm, c in x) - for r in mu), tensor([base.one() for base in tparents])), - d) - for mu, d in p(self)) + elt = lincomb((prod((lincomb((tensor([p[r].plethysm(base(la)) for base, la in zip(tparents, trm)]), _raise_variables(c, r, degree_one)) for trm, c in x) for r in mu), tensor([base.one() for base in tparents])), d) for mu, d in p(self)) return Px(elt) # Takes a symmetric function f, and an n and returns the @@ -3569,8 +3564,8 @@ def pn_pleth(f, n): p_x = p(x) def f(part): - return p.prod(pn_pleth(p_x.map_coefficients(lambda c: _raise_variables(c, i, degree_one)), i) - for i in part) + return p.prod(pn_pleth(p_x.map_coefficients(lambda c: _raise_variables(c, i, degree_one)), i) for i in part) + ret = p._apply_module_morphism(p(self), f, codomain=p) if Px is R: # special case for things in the base ring @@ -3763,8 +3758,7 @@ def inner_plethysm(self, x): p = parent.realization_of().power() cache = {} ip_pnu_g = parent._inner_plethysm_pnu_g - return parent.sum(c * ip_pnu_g(p(x), cache, nu) - for nu, c in p(self).monomial_coefficients().items()) + return parent.sum(c * ip_pnu_g(p(x), cache, nu) for nu, c in p(self).monomial_coefficients().items()) def omega(self): r""" @@ -3859,7 +3853,7 @@ def theta(self, a): """ p = self.parent().realization_of().power() p_self = p(self) - res = p_self.map_item(lambda m, c: (m, c * a**len(m))) + res = p_self.map_item(lambda m, c: (m, c * a ** len(m))) return self.parent()(res) def theta_qt(self, q=None, t=None): @@ -3911,11 +3905,9 @@ def theta_qt(self, q=None, t=None): q = BR(QQ['q'].gen()) one = BR.one() if not t: - res = p._from_dict({m: BR(prod(one - q**k for k in m) * c) - for m, c in p_self}) + res = p._from_dict({m: BR(prod(one - q**k for k in m) * c) for m, c in p_self}) else: - res = p._from_dict({m: BR(prod((one-q**k) / (one-t**k) for k in m)*c) - for m, c in p_self}) + res = p._from_dict({m: BR(prod((one - q**k) / (one - t**k) for k in m) * c) for m, c in p_self}) return parent(res) def omega_qt(self, q=None, t=None): @@ -3985,14 +3977,9 @@ def omega_qt(self, q=None, t=None): q = BR(QQ['q'].gen()) one = BR.one() if not t: - res = p._from_dict({m: c * (-one)**(sum(m) - len(m)) - * BR(prod(one-q**i for i in m)) - for m, c in p_self}) + res = p._from_dict({m: c * (-one) ** (sum(m) - len(m)) * BR(prod(one - q**i for i in m)) for m, c in p_self}) else: - res = p._from_dict({m: c * (-one)**(sum(m) - len(m)) - * BR(prod((one-q**i) / (one-t**i) - for i in m)) - for m, c in p_self}) + res = p._from_dict({m: c * (-one) ** (sum(m) - len(m)) * BR(prod((one - q**i) / (one - t**i) for i in m)) for m, c in p_self}) return parent(res) def itensor(self, x): @@ -4217,8 +4204,7 @@ def itensor(self, x): # Convert both self and x to the p basis p = parent.realization_of().power() f = lambda part1, part2: zee(part1) * p(part1) - return parent(p._apply_multi_module_morphism(p(self), p(x), f, - orthogonal=True)) + return parent(p._apply_multi_module_morphism(p(self), p(x), f, orthogonal=True)) # comp_parent is the parent that is going to be used for # computations. In most cases it will just be parent. # Similarly for comp_self and comp_x. @@ -4242,8 +4228,9 @@ def itensor(self, x): comp_parent = parent.realization_of().schur() comp_self = comp_parent(self) from sage.combinat.sf.sf import SymmetricFunctions + corresponding_parent_over_QQ = SymmetricFunctions(QQ).schur() - comp_x = comp_parent(x) # For simplicity, let self and x be in the same basis. + comp_x = comp_parent(x) # For simplicity, let self and x be in the same basis. result = comp_parent.zero() for lam, a in comp_self: # lam is a partition, a is an element of the base ring. @@ -4254,7 +4241,7 @@ def itensor(self, x): for nu, c in lam_star_mu: # nu is a partition, c is an element of QQ. result += a * b * comp_parent.base_ring()(c) * comp_parent(nu) - return parent(result) # just in case comp_parent != parent. + return parent(result) # just in case comp_parent != parent. internal_product = itensor kronecker_product = itensor @@ -4457,8 +4444,7 @@ def reduced_kronecker_product(self, x): for nu, c in lam_star_mu: # nu is a partition of the integer stab, c is an element of QQ. nu_unstabilized = _Partitions(nu[1:]) - result += a * b * comp_parent.base_ring()(c) \ - * comp_parent(nu_unstabilized) + result += a * b * comp_parent.base_ring()(c) * comp_parent(nu_unstabilized) return parent(result) def left_padded_kronecker_product(self, x): @@ -4618,6 +4604,7 @@ def left_padded_kronecker_product(self, x): Symmetric Functions over Integer Ring in the Schur basis """ from sage.combinat.composition import Compositions + _Compositions = Compositions() parent = self.parent() h = parent.realization_of().h() @@ -4627,6 +4614,7 @@ def left_padded_kronecker_product(self, x): # h (=complete homogeneous) basis, which we call h. R = self.base_ring() from sage.combinat.ncsf_qsym.ncsf import NonCommutativeSymmetricFunctions + # We lift to the noncommutative symmetric functions. S = NonCommutativeSymmetricFunctions(R).S() result = h.zero() @@ -4756,14 +4744,15 @@ def internal_coproduct(self): h = parent.realization_of().homogeneous() s = parent.realization_of().schur() from sage.categories.tensor import tensor + result = tensor([parent.zero(), parent.zero()]) result_parent = result.parent() from sage.misc.cachefunc import cached_function @cached_function def hnimage(n): - return result_parent.sum(tensor([parent(s(lam)), parent(s(lam))]) - for lam in Partitions(n)) + return result_parent.sum(tensor([parent(s(lam)), parent(s(lam))]) for lam in Partitions(n)) + for lam, a in h(self): result += a * prod(hnimage(i) for i in lam) return result @@ -4858,15 +4847,16 @@ def arithmetic_product(self, x): from sage.arith.functions import lcm from sage.arith.misc import gcd from sage.combinat.partition import Partition + p = parent.realization_of().power() def f(lam, mu): # This is the map sending two partitions lam and mu to the # arithmetic product p[lam] \boxdot p[mu]. # Code shamelessly stolen from Andrew Gainer-Dewar, trac #14542. - term_iterable = chain.from_iterable(repeat(lcm(pair), gcd(pair)) - for pair in product(lam, mu)) + term_iterable = chain.from_iterable(repeat(lcm(pair), gcd(pair)) for pair in product(lam, mu)) return p(Partition(sorted(term_iterable, reverse=True))) + return parent(p._apply_multi_module_morphism(p(self), p(x), f)) comp_parent = parent comp_self = self @@ -4876,6 +4866,7 @@ def f(lam, mu): comp_parent = parent.realization_of().schur() comp_self = comp_parent(self) from sage.combinat.sf.sf import SymmetricFunctions + corresponding_parent_over_QQ = SymmetricFunctions(QQ).schur() comp_x = comp_parent(x) result = comp_parent.zero() @@ -5031,7 +5022,7 @@ def scalar(self, x, zee=None): p = self.parent().realization_of().power() p_self = p(self) p_x = p(x) - return sum(zee(mu)*p_x.coefficient(mu)*p_self.coefficient(mu) for mu in p_self.support()) + return sum(zee(mu) * p_x.coefficient(mu) * p_self.coefficient(mu) for mu in p_self.support()) def scalar_qt(self, x, q=None, t=None): r""" @@ -5157,7 +5148,7 @@ def scalar_jack(self, x, t=None): t = self.parent().t else: t = QQ['t'].gen() - zee = lambda part: part.centralizer_size()*t**part.length() + zee = lambda part: part.centralizer_size() * t ** part.length() return self.scalar(x, zee) def derivative_with_respect_to_p1(self, n=1): @@ -5483,9 +5474,8 @@ def verschiebung(self, n): parent = self.parent() h = parent.realization_of().homogeneous() from sage.combinat.partition import Partition - dct = {Partition([i // n for i in lam]): coeff - for lam, coeff in h(self) - if all(i % n == 0 for i in lam)} + + dct = {Partition([i // n for i in lam]): coeff for lam, coeff in h(self) if all(i % n == 0 for i in lam)} result_in_h_basis = h._from_dict(dct) return parent(result_in_h_basis) @@ -5584,6 +5574,7 @@ def bernstein_creation_operator(self, n): # We use the formula for the Bernstein creation operator on # a Schur function given in the docstring. from sage.combinat.partition import _Partitions + parent = self.parent() s = parent.realization_of().schur() res = s.zero() @@ -5649,17 +5640,20 @@ def _expand(self, condition, n, alphabet='x'): would require extra work to handle the empty partition. """ from . import classical + parent = self.parent() resPR = PolynomialRing(parent.base_ring(), n, alphabet) if self == parent.zero(): return resPR.zero() import sage.libs.symmetrica.all as symmetrica + e = getattr(symmetrica, 'compute_{}_with_alphabet'.format(classical.translate[parent.basis_name()].lower())) def f(part): if not part: return resPR.one() return resPR.zero() if condition(part) else resPR(e(part, n, alphabet)) + return parent._apply_module_morphism(self, f) def is_schur_positive(self): @@ -5748,8 +5742,7 @@ def degree(self): sage: s(0).degree() 0 """ - return max((sum(cfs) for cfs in self._monomial_coefficients), - default=0) + return max((sum(cfs) for cfs in self._monomial_coefficients), default=0) def restrict_degree(self, d, exact=True): r""" @@ -5838,8 +5831,7 @@ def restrict_parts(self, n): sage: z.restrict_parts(1) s[1] + s[1, 1, 1] """ - res = dict(x for x in self._monomial_coefficients.items() - if _lmax(x[0]) <= n) + res = dict(x for x in self._monomial_coefficients.items() if _lmax(x[0]) <= n) return self.parent()._from_dict(res) def expand(self, n, alphabet='x'): @@ -5936,10 +5928,8 @@ def skew_by(self, x): s = Sym.schur() R = parent.base_ring() from sage.libs.lrcalc import lrcalc - ret = linear_combination((convert_remove_zeroes(lrcalc.skew(p1, p2), R), c1 * c2) - for p1, c1 in s(self)._monomial_coefficients.items() - for p2, c2 in s(x)._monomial_coefficients.items() - if p1.contains(p2)) + + ret = linear_combination((convert_remove_zeroes(lrcalc.skew(p1, p2), R), c1 * c2) for p1, c1 in s(self)._monomial_coefficients.items() for p2, c2 in s(x)._monomial_coefficients.items() if p1.contains(p2)) return parent(s.element_class(s, ret)) def hl_creation_operator(self, nu, t=None): @@ -6014,17 +6004,10 @@ def hl_creation_operator(self, nu, t=None): P = self.parent() if nu in _Partitions: self = s(self) - return P(self*s(nu) + - s.sum(s.sum_of_terms((lam, c) for lam, c in s(mu)*s(nu) if len(lam) <= len(nu)) * - self.skew_by(s(mu).plethysm((t-1)*s([1]))) - for d in range(self.degree()) - for mu in Partitions(d+1, max_length=len(nu)))) + return P(self * s(nu) + s.sum(s.sum_of_terms((lam, c) for lam, c in s(mu) * s(nu) if len(lam) <= len(nu)) * self.skew_by(s(mu).plethysm((t - 1) * s([1]))) for d in range(self.degree()) for mu in Partitions(d + 1, max_length=len(nu)))) if isinstance(nu, list) and all(isinstance(a, (int, Integer)) for a in nu): - return P(s.sum(t**la.size() * c * d * s(la) * - s._repeated_bernstein_creation_operator_on_basis(ga, nu) - for (la, mu), c in s(self).coproduct() - for ga, d in s(mu).plethysm((1-t)*s[1]))) + return P(s.sum(t ** la.size() * c * d * s(la) * s._repeated_bernstein_creation_operator_on_basis(ga, nu) for (la, mu), c in s(self).coproduct() for ga, d in s(mu).plethysm((1 - t) * s[1]))) raise ValueError("nu must be a list of integers") @@ -6116,9 +6099,7 @@ def character_to_frobenius_image(self, n): 2*s[2, 2, 1] + s[3, 1, 1] + 4*s[3, 2] + 3*s[4, 1] + 2*s[5] """ p = self.parent().symmetric_function_ring().p() - return self.parent()(p.sum(self.eval_at_permutation_roots(rho) - * p(rho) / rho.centralizer_size() - for rho in Partitions(n))) + return self.parent()(p.sum(self.eval_at_permutation_roots(rho) * p(rho) / rho.centralizer_size() for rho in Partitions(n))) def principal_specialization(self, n=infinity, q=None): r""" @@ -6526,6 +6507,7 @@ class SymmetricFunctionsFunctor(ConstructionFunctor): sage: s.construction() (SymmetricFunctionsFunctor[Schur], Rational Field) """ + rank = 9 def __init__(self, basis, name, *args) -> None: @@ -6583,6 +6565,7 @@ def _apply_functor(self, R): TypeError: no conversion of this rational to integer """ from sage.combinat.sf.sf import SymmetricFunctions + return self._basis(SymmetricFunctions(R), *self._args) def _apply_functor_to_morphism(self, f): @@ -6615,8 +6598,8 @@ def _apply_functor_to_morphism(self, f): codom = self(f.codomain()) def action(x): - return codom._from_dict({a: f(b) - for a, b in x.monomial_coefficients().items()}) + return codom._from_dict({a: f(b) for a, b in x.monomial_coefficients().items()}) + return dom.module_morphism(function=action, codomain=codom) def __eq__(self, other): @@ -6631,9 +6614,7 @@ def __eq__(self, other): """ if not isinstance(other, type(self)): return False - return (self._basis == other._basis - and self._name == other._name - and self._args == other._args) + return self._basis == other._basis and self._name == other._name and self._args == other._args def __hash__(self): """ @@ -6723,6 +6704,7 @@ def _apply_functor(self, R): TypeError: t is not a constant polynomial """ from sage.combinat.sf.sf import SymmetricFunctions + return self._basis(self._family(SymmetricFunctions(R), *self._args)) def __eq__(self, other): @@ -6875,7 +6857,7 @@ def _raise_variables(c, n, variables): 3*b*t^2 + 2*a^2 """ try: - return c.subs(**{str(g): g ** n for g in variables}) + return c.subs(**{str(g): g**n for g in variables}) except AttributeError: return c @@ -6905,17 +6887,14 @@ def _to_polynomials(lf, R): sage: _to_polynomials([5*e[3] + e[2,1] + e[1]], QQ) [v1*v2 + v1 + 5*v3] """ - n = max(max((part[0] for part in f.support() if part), default=0) - for f in lf) + n = max(max((part[0] for part in f.support() if part), default=0) for f in lf) # the polynomial ring with no variables is not well supported, # eg., gcd does not work n = max(n, 1) P = PolynomialRing(R, ["v%s" % a for a in range(1, n + 1)]) if n == 1: - return [P({part.to_exp(n)[0]: c for part, c in f}) - for f in lf] - return [P({tuple(part.to_exp(n)): c for part, c in f}) - for f in lf] + return [P({part.to_exp(n)[0]: c for part, c in f}) for f in lf] + return [P({tuple(part.to_exp(n)): c for part, c in f}) for f in lf] def _from_polynomial(p, f): @@ -6944,9 +6923,7 @@ def _from_polynomial(p, f): """ n = p.parent().ngens() if n == 1: - d = {_Partitions.from_exp([e]): c - for e, c in p.monomial_coefficients().items()} + d = {_Partitions.from_exp([e]): c for e, c in p.monomial_coefficients().items()} else: - d = {_Partitions.from_exp(e): c - for e, c in p.iterator_exp_coeff(False)} + d = {_Partitions.from_exp(e): c for e, c in p.iterator_exp_coeff(False)} return f.element_class(f, d) diff --git a/src/sage/combinat/sf/symplectic.py b/src/sage/combinat/sf/symplectic.py index eb4b01842d7..0caa9e17b71 100644 --- a/src/sage/combinat/sf/symplectic.py +++ b/src/sage/combinat/sf/symplectic.py @@ -177,8 +177,7 @@ def __init__(self, Sym): sage: sp = SymmetricFunctions(QQ).sp() sage: TestSuite(sp).run() """ - sfa.SymmetricFunctionAlgebra_generic.__init__(self, Sym, "symplectic", - 'sp', graded=False) + sfa.SymmetricFunctionAlgebra_generic.__init__(self, Sym, "symplectic", 'sp', graded=False) # We make a strong reference since we use it for our computations # and so we can define the coercion below (only codomains have @@ -186,11 +185,9 @@ def __init__(self, Sym): self._s = Sym.schur() # Setup the coercions - M = self._s.module_morphism(self._s_to_sp_on_basis, codomain=self, - triangular='upper', unitriangular=True) + M = self._s.module_morphism(self._s_to_sp_on_basis, codomain=self, triangular='upper', unitriangular=True) M.register_as_coercion() - Mi = self.module_morphism(self._sp_to_s_on_basis, codomain=self._s, - triangular='upper', unitriangular=True) + Mi = self.module_morphism(self._sp_to_s_on_basis, codomain=self._s, triangular='upper', unitriangular=True) Mi.register_as_coercion() @cached_method @@ -212,13 +209,7 @@ def _sp_to_s_on_basis(self, lam): """ R = self.base_ring() n = sum(lam) - return self._s._from_dict({ mu: R.sum( (-1)**j * lrcalc.lrcoef_unsafe(lam, mu, nu) - for nu in Partitions(2*j) - if all(nu.leg_length(i,i) == nu.arm_length(i,i)+1 - for i in range(nu.frobenius_rank())) - ) - for j in range(n//2+1) # // 2 for horizontal dominoes - for mu in Partitions(n-2*j) }) + return self._s._from_dict({mu: R.sum((-1) ** j * lrcalc.lrcoef_unsafe(lam, mu, nu) for nu in Partitions(2 * j) if all(nu.leg_length(i, i) == nu.arm_length(i, i) + 1 for i in range(nu.frobenius_rank()))) for j in range(n // 2 + 1) for mu in Partitions(n - 2 * j)}) # // 2 for horizontal dominoes @cached_method def _s_to_sp_on_basis(self, lam): @@ -246,7 +237,4 @@ def _s_to_sp_on_basis(self, lam): """ R = self.base_ring() n = sum(lam) - return self._from_dict({ mu: R.sum( lrcalc.lrcoef_unsafe(lam, mu, sum([[x,x] for x in nu], [])) - for nu in Partitions(j) ) - for j in range(n//2+1) # // 2 for vertical dominoes - for mu in Partitions(n-2*j) }) + return self._from_dict({mu: R.sum(lrcalc.lrcoef_unsafe(lam, mu, sum([[x, x] for x in nu], [])) for nu in Partitions(j)) for j in range(n // 2 + 1) for mu in Partitions(n - 2 * j)}) # // 2 for vertical dominoes diff --git a/src/sage/combinat/sf/witt.py b/src/sage/combinat/sf/witt.py index 7279f9dc501..c2eee9d5b52 100644 --- a/src/sage/combinat/sf/witt.py +++ b/src/sage/combinat/sf/witt.py @@ -206,6 +206,7 @@ class SymmetricFunctionAlgebra_witt(multiplicative.SymmetricFunctionAlgebra_mult Witt symmetric functions pass through the complete homogeneous symmetric functions by default. """ + def __init__(self, Sym): r""" Initialize ``self``. @@ -337,7 +338,7 @@ def _e_to_w_on_basis(self, lam): R = self.base_ring() n = lam[0] index_set = IntegerListsLex(n, min_part=1, max_slope=-1, element_constructor=P) - return self.element_class(self, {mu: R((-1)**(n-len(mu))) for mu in index_set}) + return self.element_class(self, {mu: R((-1) ** (n - len(mu))) for mu in index_set}) # Multiply by the smallest part to minimize the number of products return self._e_to_w_on_basis(P(lam[:-1])) * self._e_to_w_on_basis(P([lam[-1]])) @@ -376,8 +377,7 @@ def _w_to_e_on_basis(self, lam): R = self.base_ring() n = lam[0] index_set = IntegerListsLex(n, min_part=1, min_length=2, max_slope=-1, element_constructor=P) - return R((-1)**(n-1)) * self._e[n] + self._e.linear_combination((self._w_to_e_on_basis(mu), R((-1)**len(mu))) - for mu in index_set) + return R((-1) ** (n - 1)) * self._e[n] + self._e.linear_combination((self._w_to_e_on_basis(mu), R((-1) ** len(mu))) for mu in index_set) # Multiply by the smallest part to minimize the number of products return self._w_to_e_on_basis(P(lam[:-1])) * self._w_to_e_on_basis(P([lam[-1]])) @@ -454,8 +454,7 @@ def _w_to_p_on_basis(self, lam): if len(lam) == 1: R = self.base_ring() n = lam[0] - return ~R(n) * self._p[n] - self._p.linear_combination((self._w_to_p_on_basis(P([d] * (n // d))), R(d) / R(n)) - for d in divisors(n) if d != n) + return ~R(n) * self._p[n] - self._p.linear_combination((self._w_to_p_on_basis(P([d] * (n // d))), R(d) / R(n)) for d in divisors(n) if d != n) # Multiply by the smallest part to minimize the number of products return self._w_to_p_on_basis(P(lam[:-1])) * self._w_to_p_on_basis(P([lam[-1]])) @@ -485,8 +484,8 @@ def coproduct(self, elt): w[] # w[2, 1] - w[1] # w[1, 1] + w[1] # w[2] - w[1, 1] # w[1] + w[2] # w[1] + w[2, 1] # w[] """ from sage.categories.tensor import tensor - return self.tensor_square().sum(coeff * tensor([self(self._h[x]), self(self._h[y])]) - for ((x, y), coeff) in self._h(elt).coproduct()) + + return self.tensor_square().sum(coeff * tensor([self(self._h[x]), self(self._h[y])]) for ((x, y), coeff) in self._h(elt).coproduct()) def verschiebung(self, n): r""" @@ -589,9 +588,7 @@ def verschiebung(self, n): parent = self.parent() w_coords_of_self = self._monomial_coefficients.items() P = self._indices - dct = {P([i // n for i in lam]): coeff - for lam, coeff in w_coords_of_self - if all(i % n == 0 for i in lam)} + dct = {P([i // n for i in lam]): coeff for lam, coeff in w_coords_of_self if all(i % n == 0 for i in lam)} return parent._from_dict(dct) def _omega_on_basis(self, lam): @@ -716,5 +713,4 @@ def omega(self): True """ P = self.parent() - return P.linear_combination((P._omega_on_basis(lam), coeff) - for lam, coeff in self._monomial_coefficients.items()) + return P.linear_combination((P._omega_on_basis(lam), coeff) for lam, coeff in self._monomial_coefficients.items()) diff --git a/src/sage/combinat/shard_order.py b/src/sage/combinat/shard_order.py index cc27adfd509..ffb11c0f641 100644 --- a/src/sage/combinat/shard_order.py +++ b/src/sage/combinat/shard_order.py @@ -21,6 +21,7 @@ A general implementation for all finite Coxeter groups is available as :meth:`~sage.categories.finite_coxeter_groups.FiniteCoxeterGroups.ParentMethods.shard_poset` """ + from sage.combinat.posets.posets import Poset from sage.graphs.digraph import DiGraph from sage.combinat.permutation import Permutations @@ -47,6 +48,7 @@ class ShardPosetElement(tuple): sage: Permutation(list(e0)) == p0 True """ + def __new__(cls, p): r""" Initialization of the underlying tuple. @@ -184,9 +186,7 @@ def shard_preorder_graph(runs): """ N = len(runs) dg = DiGraph(N) - dg.add_edges((i, j) for i in range(N - 1) - for j in range(i + 1, N) - if runs[i][-1] < runs[j][0] and runs[j][-1] < runs[i][0]) + dg.add_edges((i, j) for i in range(N - 1) for j in range(i + 1, N) if runs[i][-1] < runs[j][0] and runs[j][-1] < runs[i][0]) return dg @@ -223,5 +223,6 @@ def shard_poset(n): False """ import operator + Sn = [ShardPosetElement(s) for s in Permutations(n)] return Poset([Sn, operator.le], cover_relations=False, facade=True) diff --git a/src/sage/combinat/shifted_primed_tableau.py b/src/sage/combinat/shifted_primed_tableau.py index 70506334160..38030e913b5 100644 --- a/src/sage/combinat/shifted_primed_tableau.py +++ b/src/sage/combinat/shifted_primed_tableau.py @@ -45,8 +45,7 @@ lazy_import('sage.combinat.root_system.cartan_type', 'CartanType') -class ShiftedPrimedTableau(ClonableArray, - metaclass=InheritComparisonClasscallMetaclass): +class ShiftedPrimedTableau(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): r""" A shifted primed tableau. @@ -96,6 +95,7 @@ class ShiftedPrimedTableau(ClonableArray, sage: ShiftedPrimedTableau([[1,1,2.5],[1.5,2.5]], primed_diagonal=True) [(1, 1, 3'), (2', 3')] """ + @staticmethod def __classcall_private__(cls, T, skew=None, primed_diagonal=False): r""" @@ -130,8 +130,7 @@ def __classcall_private__(cls, T, skew=None, primed_diagonal=False): sage: ShiftedPrimedTableau([tuple()], primed_diagonal=True) [] """ - if (isinstance(T, ShiftedPrimedTableau) and T._skew == skew - and T.parent()._primed_diagonal == primed_diagonal): + if isinstance(T, ShiftedPrimedTableau) and T._skew == skew and T.parent()._primed_diagonal == primed_diagonal: return T skew_ = Partition([row.count(None) for row in T]) @@ -200,17 +199,16 @@ def _preprocess(T, skew=None): if isinstance(T, ShiftedPrimedTableau): return T # Preprocessing list t for primes and other symbols - T = [[PrimedEntry(entry) for entry in row if entry is not None] - for row in T] + T = [[PrimedEntry(entry) for entry in row if entry is not None] for row in T] while T and not T[-1]: T = T[:-1] row_min = min(len(skew), len(T)) if skew else 0 - T_ = [(None,)*skew[i] + tuple(T[i]) for i in range(row_min)] + T_ = [(None,) * skew[i] + tuple(T[i]) for i in range(row_min)] if row_min < len(T): T_ += [tuple(T[i]) for i in range(row_min, len(T))] elif skew: - T_ += [(None,)*skew[i] for i in range(row_min, len(skew))] + T_ += [(None,) * skew[i] for i in range(row_min, len(skew))] return T_ def check(self): @@ -384,7 +382,7 @@ def _repr_tab(self): elif entry.is_primed(): repr_row.append(repr(entry).rjust(max_len)) elif entry.is_unprimed(): - repr_row.append(repr(entry).rjust(max_len-1)+" ") + repr_row.append(repr(entry).rjust(max_len - 1) + " ") repr_tab.append(repr_row) return repr_tab @@ -407,9 +405,8 @@ def _repr_diagram(self): . . 2' 2 3 . 2' """ - max_len = len(str(self.max_entry()))+2 - return "\n".join([" "*max_len*i + "".join(val) - for i, val in enumerate(self._repr_tab())]) + max_len = len(str(self.max_entry())) + 2 + return "\n".join([" " * max_len * i + "".join(val) for i, val in enumerate(self._repr_tab())]) _repr_compact = _repr_diagram @@ -445,6 +442,7 @@ def _ascii_art_(self): +---+ """ from sage.typeset.ascii_art import AsciiArt + return AsciiArt(self._ascii_art_table(unicode=False).splitlines()) def _unicode_art_(self): @@ -478,6 +476,7 @@ def _unicode_art_(self): └───┘ """ from sage.typeset.unicode_art import UnicodeArt + return UnicodeArt(self._ascii_art_table(unicode=True).splitlines()) def _ascii_art_table(self, unicode=False): @@ -520,6 +519,7 @@ def _ascii_art_table(self, unicode=False): """ if unicode: import unicodedata + v = unicodedata.lookup('BOX DRAWINGS LIGHT VERTICAL') h = unicodedata.lookup('BOX DRAWINGS LIGHT HORIZONTAL') dl = unicodedata.lookup('BOX DRAWINGS LIGHT DOWN AND LEFT') @@ -529,8 +529,7 @@ def _ascii_art_table(self, unicode=False): vl = unicodedata.lookup('BOX DRAWINGS LIGHT VERTICAL AND LEFT') uh = unicodedata.lookup('BOX DRAWINGS LIGHT UP AND HORIZONTAL') dh = unicodedata.lookup('BOX DRAWINGS LIGHT DOWN AND HORIZONTAL') - vh = unicodedata.lookup( - 'BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL') + vh = unicodedata.lookup('BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL') else: v = '|' h = '-' @@ -542,18 +541,18 @@ def _ascii_art_table(self, unicode=False): # Get the widths of the columns str_tab = self._repr_tab() width = len(str_tab[0][0]) - str_list = [dr + (h*width + dh)*(len(str_tab[0])-1) + h*width + dl] + str_list = [dr + (h * width + dh) * (len(str_tab[0]) - 1) + h * width + dl] for nrow, row in enumerate(str_tab): - l1 = " " * (width+1) * nrow - l2 = " " * (width+1) * nrow - n = len(str_tab[nrow+1]) if nrow+1 < len(str_tab) else -1 + l1 = " " * (width + 1) * nrow + l2 = " " * (width + 1) * nrow + n = len(str_tab[nrow + 1]) if nrow + 1 < len(str_tab) else -1 for i, e in enumerate(row): if i == 0: - l1 += ur + h*width - elif i <= n+1: - l1 += vh + h*width + l1 += ur + h * width + elif i <= n + 1: + l1 += vh + h * width else: - l1 += uh + h*width + l1 += uh + h * width if unicode: l2 += "{}{:^{width}}".format(v, e, width=width) else: @@ -611,7 +610,8 @@ def _latex_(self): } """ from sage.combinat.output import tex_from_array - L = [[None]*i + row for i, row in enumerate(self._repr_tab())] + + L = [[None] * i + row for i, row in enumerate(self._repr_tab())] return tex_from_array(L) def max_entry(self): @@ -633,8 +633,7 @@ def max_entry(self): sage: Tab.max_entry() 1 """ - flat = [entry.unprimed() for row in self - for entry in row if entry is not None] + flat = [entry.unprimed() for row in self for entry in row if entry is not None] if len(flat) == 0: return 0 return max(flat) @@ -719,8 +718,7 @@ def restriction_outer_shape(self, n): if self._skew is None: res = [len([y for y in row if y <= n]) for row in self] else: - res = [len([y for y in row if y is None or y <= n]) - for i, row in enumerate(self)] + res = [len([y for y in row if y is None or y <= n]) for i, row in enumerate(self)] return Partition(res) @@ -791,8 +789,7 @@ def to_chain(self): skew shifted tableaux without repeated entries """ if any(e not in [0, 1] for e in self.weight()): - raise ValueError("can compute a chain of partitions only for skew" - " shifted tableaux without repeated entries") + raise ValueError("can compute a chain of partitions only for skew" " shifted tableaux without repeated entries") entries = sorted(e for row in self for e in row if e is not None) if self._skew is None: mu = Partition([]) @@ -804,7 +801,7 @@ def to_chain(self): f = 0 for e in entries: n = e.integer() - chain.extend([0, mu]*int(n-f-1)) + chain.extend([0, mu] * int(n - f - 1)) mu = self.restriction_outer_shape(e) if n == e: if any(e == row[0] for i, row in enumerate(self) if i >= m or self._skew[i] == 0): @@ -831,12 +828,11 @@ def weight(self): sage: t.weight() (0, 4, 1) """ - flat = [entry.integer() for row in self - for entry in row if entry is not None] + flat = [entry.integer() for row in self for entry in row if entry is not None] if not flat: return () - weight = tuple([flat.count(i+1) for i in range(max(flat))]) + weight = tuple([flat.count(i + 1) for i in range(max(flat))]) return weight @@ -858,8 +854,7 @@ def _to_matrix(self): [[1, 2', 2, 2], [None, 2, 3', None], [None, None, 3, None]] """ m = len(self[0]) - return [[None]*i + list(row) + [None]*(m-i-len(row)) - for i, row in enumerate(self)] + return [[None] * i + list(row) + [None] * (m - i - len(row)) for i, row in enumerate(self)] def _reading_word_with_positions(self): """ @@ -1057,14 +1052,13 @@ def f(self, ind): T = [tuple(elmt for elmt in row if elmt is not None) for row in T] return type(self)(self.parent(), T, check=False, preprocessed=True) - read_word = [num for num in self._reading_word_with_positions() - if num[1] == ind or num[1] == ind+1] + read_word = [num for num in self._reading_word_with_positions() if num[1] == ind or num[1] == ind + 1] element_to_change = None count = 0 for element in read_word: - if element[1] == ind+1: + if element[1] == ind + 1: count += 1 elif count == 0: element_to_change = element @@ -1080,22 +1074,21 @@ def f(self, ind): ind_plus_half = ind_e.increase_half() if T[r][c].is_primed(): - T = [[elmt.increase_half() if elmt is not None else elmt - for elmt in row] for row in T] + T = [[elmt.increase_half() if elmt is not None else elmt for elmt in row] for row in T] T = [list(z) for z in zip(*T)] r, c = c, r h, l = len(T), len(T[0]) - if (c+1 == l or T[r][c+1] is None or T[r][c+1] >= ind_plus_one): + if c + 1 == l or T[r][c + 1] is None or T[r][c + 1] >= ind_plus_one: tp_r, tp_c = (r, c) while True: - if tp_r+1 == h or T[tp_r+1][tp_c] is None or T[tp_r+1][tp_c] > ind_plus_one: + if tp_r + 1 == h or T[tp_r + 1][tp_c] is None or T[tp_r + 1][tp_c] > ind_plus_one: break - if tp_r <= tp_c and T[tp_r+1][tp_r+1] == ind_plus_one: + if tp_r <= tp_c and T[tp_r + 1][tp_r + 1] == ind_plus_one: tp_r += 1 tp_c = tp_r break - if ind_plus_half not in T[tp_r+1]: + if ind_plus_half not in T[tp_r + 1]: break tp_r += 1 tp_c = T[tp_r].index(ind_plus_half) @@ -1108,13 +1101,12 @@ def f(self, ind): T[r][c] = T[r][c].increase_half() T[tp_r][tp_c] = T[tp_r][tp_c].increase_half() - elif T[r][c+1] == ind_plus_half: - T[r][c+1] = T[r][c+1].increase_half() + elif T[r][c + 1] == ind_plus_half: + T[r][c + 1] = T[r][c + 1].increase_half() T[r][c] = T[r][c].increase_half() if r > c: - T = [[elmt.decrease_half() if elmt is not None else elmt - for elmt in row] for row in T] + T = [[elmt.decrease_half() if elmt is not None else elmt for elmt in row] for row in T] T = [list(z) for z in zip(*T)] T = [tuple(elmt for elmt in row if elmt is not None) for row in T] @@ -1212,10 +1204,7 @@ def e(self, ind): if ind == -1: read_word = [num for num in self._reading_word_with_positions() if num[1] in {1, 2}] - two_primes = sorted( - [pos for pos, elt in read_word if elt == 2 and T[pos[0]][pos[1]].is_primed()], - key=lambda x: x[1] - ) + two_primes = sorted([pos for pos, elt in read_word if elt == 2 and T[pos[0]][pos[1]].is_primed()], key=lambda x: x[1]) # e_{-1} acts as zero if tableau contains no 2' and first diagonal entry is not 2 if len(two_primes) == 0: @@ -1232,8 +1221,7 @@ def e(self, ind): T = [tuple(elmt for elmt in row if elmt is not None) for row in T] return type(self)(self.parent(), T, check=False, preprocessed=True) - read_word = [num for num in self._reading_word_with_positions() - if num[1] == ind or num[1] == ind+1] + read_word = [num for num in self._reading_word_with_positions() if num[1] == ind or num[1] == ind + 1] element_to_change = None count = 0 @@ -1254,17 +1242,16 @@ def e(self, ind): ind_plus_half = ind_e.increase_half() if T[r][c].is_primed(): - T = [[elmt.increase_half() if elmt is not None else elmt - for elmt in row] for row in T] + T = [[elmt.increase_half() if elmt is not None else elmt for elmt in row] for row in T] T = [list(z) for z in zip(*T)] r, c = c, r - if (c == 0 or T[r][c-1] is None or T[r][c-1] <= ind_e): + if c == 0 or T[r][c - 1] is None or T[r][c - 1] <= ind_e: tp_r, tp_c = (r, c) while True: - if tp_r == 0 or T[tp_r-1][tp_c] is None or T[tp_r-1][tp_c] < ind_e: + if tp_r == 0 or T[tp_r - 1][tp_c] is None or T[tp_r - 1][tp_c] < ind_e: break - if ind_plus_half not in T[tp_r-1]: + if ind_plus_half not in T[tp_r - 1]: break tp_r -= 1 tp_c = T[tp_r].index(ind_plus_half) @@ -1277,12 +1264,11 @@ def e(self, ind): T[r][c] = T[r][c].decrease_half() T[tp_r][tp_c] = T[tp_r][tp_c].decrease_half() - elif T[r][c-1] == ind_plus_half: - T[r][c-1] = T[r][c-1].decrease_half() + elif T[r][c - 1] == ind_plus_half: + T[r][c - 1] = T[r][c - 1].decrease_half() T[r][c] = T[r][c].decrease_half() if r > c: - T = [[elmt.decrease_half() if elmt is not None else elmt - for elmt in row] for row in T] + T = [[elmt.decrease_half() if elmt is not None else elmt for elmt in row] for row in T] T = [list(z) for z in zip(*T)] T = [tuple(elmt for elmt in row if elmt is not None) for row in T] @@ -1309,12 +1295,12 @@ def is_highest_weight(self, index_set=None): """ read_w = self.reading_word() max_entry = max(read_w) - count = {i: 0 for i in range(max_entry+1)} + count = {i: 0 for i in range(max_entry + 1)} if index_set is None: index_set = self.parent().index_set() for l in reversed(read_w): count[l] += 1 - if l-1 in index_set and l > 1 and count[l] > count[l-1]: + if l - 1 in index_set and l > 1 and count[l] > count[l - 1]: return False return True @@ -1337,7 +1323,7 @@ def weight(self): max_ind = 0 else: max_ind = max(flat) - weight = tuple([flat.count(i+1) for i in range(max_ind)]) + weight = tuple([flat.count(i + 1) for i in range(max_ind)]) return self.parent().weight_lattice_realization()(weight) @@ -1402,7 +1388,7 @@ def __init__(self, entry=None, double=None): if entry is None: raise ValueError("primed entry must not be None") try: - self._entry = Integer(2*entry) + self._entry = Integer(2 * entry) except (TypeError, ValueError): raise ValueError("primed entries must be half-integers") @@ -1429,7 +1415,7 @@ def __repr__(self): """ if self.is_unprimed(): return repr(self._entry // 2) - return repr((self._entry+1) // 2) + "'" + return repr((self._entry + 1) // 2) + "'" def integer(self): """ @@ -1750,12 +1736,12 @@ class ShiftedPrimedTableaux(UniqueRepresentation, Parent): - :class:`ShiftedPrimedTableau` """ + Element = ShiftedPrimedTableau options = Tableaux.options @staticmethod - def __classcall_private__(cls, shape=None, weight=None, max_entry=None, - skew=None, primed_diagonal=False): + def __classcall_private__(cls, shape=None, weight=None, max_entry=None, skew=None, primed_diagonal=False): r""" Normalize and process input to return the correct parent and ensure a unique representation. @@ -1795,7 +1781,7 @@ def __classcall_private__(cls, shape=None, weight=None, max_entry=None, skew = Partition(skew) except ValueError: raise ValueError('invalid skew argument') - if not all(skew[i] > skew[i+1] for i in range(len(skew)-1)): + if not all(skew[i] > skew[i + 1] for i in range(len(skew) - 1)): raise ValueError('skew shape must be a strict partition') if weight is not None: @@ -1810,11 +1796,10 @@ def __classcall_private__(cls, shape=None, weight=None, max_entry=None, except (ValueError, TypeError): raise ValueError('invalid shape argument') - if not all(shape[i] > shape[i+1] for i in range(len(shape)-1)): + if not all(shape[i] > shape[i + 1] for i in range(len(shape) - 1)): raise ValueError("shape {} is not a strict partition".format(shape)) - if (skew is not None and not all(skew[i] <= shape[i] - for i in range(len(skew)))): + if skew is not None and not all(skew[i] <= shape[i] for i in range(len(skew))): raise ValueError('skew shape must be inside the given tableau shape') if weight is not None: @@ -1834,8 +1819,7 @@ def __classcall_private__(cls, shape=None, weight=None, max_entry=None, if weight is None: return ShiftedPrimedTableaux_shape(shape, max_entry=max_entry, skew=skew, primed_diagonal=primed_diagonal) - if (skew is not None and sum(shape) - sum(skew) != sum(weight) - or skew is None and sum(shape) != sum(weight)): + if skew is not None and sum(shape) - sum(skew) != sum(weight) or skew is None and sum(shape) != sum(weight): raise ValueError("weight and shape are incompatible") return ShiftedPrimedTableaux_weight_shape(weight, shape, skew=skew, primed_diagonal=primed_diagonal) @@ -1951,33 +1935,23 @@ def _contains_tableau(self, T): sage: Tabs._contains_tableau(tab) True """ - if not all(len(T[i]) > len(T[i+1]) for i in range(len(T)-1)): + if not all(len(T[i]) > len(T[i + 1]) for i in range(len(T) - 1)): return False if self._skew is not None: - skew = self._skew + [0]*(len(T)-len(self._skew)) + skew = self._skew + [0] * (len(T) - len(self._skew)) else: skew = [0] * len(T) for i, row in enumerate(T): if i > 0: - if not all(val > T[i-1][j+1] - for j, val in enumerate(row) - if j+1 >= skew[i-1] and val.is_unprimed()): + if not all(val > T[i - 1][j + 1] for j, val in enumerate(row) if j + 1 >= skew[i - 1] and val.is_unprimed()): return False - if not all(val >= T[i-1][j+1] - for j, val in enumerate(row) - if j+1 >= skew[i-1] and val.is_primed()): + if not all(val >= T[i - 1][j + 1] for j, val in enumerate(row) if j + 1 >= skew[i - 1] and val.is_primed()): return False - if not all(row[j] <= row[j+1] - for j in range(skew[i], len(row)-1) - if row[j].is_unprimed()): + if not all(row[j] <= row[j + 1] for j in range(skew[i], len(row) - 1) if row[j].is_unprimed()): return False - if not all(row[j] < row[j+1] - for j in range(skew[i], len(row)-1) - if row[j].is_primed()): + if not all(row[j] < row[j + 1] for j in range(skew[i], len(row) - 1) if row[j].is_primed()): return False - return self._primed_diagonal or all(row[0].is_unprimed() - for i, row in enumerate(T) - if skew[i] == 0) + return self._primed_diagonal or all(row[0].is_unprimed() for i, row in enumerate(T) if skew[i] == 0) class ShiftedPrimedTableaux_all(ShiftedPrimedTableaux): @@ -2049,17 +2023,13 @@ def __iter__(self): max_entry = 1 while True: - for size in range(1, max_entry+1): + for size in range(1, max_entry + 1): for shape in Partitions(size, max_slope=-1): - for weight in OrderedPartitions(size+max_entry-1, - k=max_entry): - weight = [weight[i]-1 for i in range(max_entry)] + for weight in OrderedPartitions(size + max_entry - 1, k=max_entry): + weight = [weight[i] - 1 for i in range(max_entry)] weight[-1] += 1 - for tab in ShiftedPrimedTableaux(shape=shape, - weight=weight, - primed_diagonal=self._primed_diagonal): - yield self.element_class(self, tab, check=False, - preprocessed=True) + for tab in ShiftedPrimedTableaux(shape=shape, weight=weight, primed_diagonal=self._primed_diagonal): + yield self.element_class(self, tab, check=False, preprocessed=True) max_entry += 1 @@ -2135,6 +2105,7 @@ class ShiftedPrimedTableaux_shape(ShiftedPrimedTableaux): sage: SPTC.cardinality() 96 """ + @staticmethod def __classcall_private__(cls, shape, max_entry=None, skew=None, primed_diagonal=False): """ @@ -2152,8 +2123,7 @@ def __classcall_private__(cls, shape, max_entry=None, skew=None, primed_diagonal True """ shape = _Partitions(shape) - return super().__classcall__(cls, - shape=shape, max_entry=max_entry, skew=skew, primed_diagonal=primed_diagonal) + return super().__classcall__(cls, shape=shape, max_entry=max_entry, skew=skew, primed_diagonal=primed_diagonal) def __init__(self, shape, max_entry=None, skew=None, primed_diagonal=False): """ @@ -2294,18 +2264,18 @@ def __iter__(self): return from sage.combinat.permutation import Permutations + list_weights = [] for partition in Partitions(sum(self._shape)): if len(partition) <= self._max_entry: for c in Combinations(range(self._max_entry), len(partition)): for p in Permutations(partition): weight = [0] * self._max_entry - for i,val in enumerate(p): + for i, val in enumerate(p): weight[c[i]] = val list_weights.append(weight) for weight in list_weights: - for T in ShiftedPrimedTableaux(weight=tuple(weight), shape=self._shape, - primed_diagonal=self._primed_diagonal): + for T in ShiftedPrimedTableaux(weight=tuple(weight), shape=self._shape, primed_diagonal=self._primed_diagonal): yield self.element_class(self, T, preprocessed=True, check=False) @lazy_attribute @@ -2326,12 +2296,8 @@ def module_generators(self): max_entry = sum(self._shape) else: max_entry = self._max_entry - for weight in (Partition(self._shape).dominated_partitions(rows=max_entry)): - list_dw.extend([self.element_class(self, T, check=False, - preprocessed=True) - for T in ShiftedPrimedTableaux(weight=tuple(weight), - shape=self._shape, - primed_diagonal=self._primed_diagonal)]) + for weight in Partition(self._shape).dominated_partitions(rows=max_entry): + list_dw.extend([self.element_class(self, T, check=False, preprocessed=True) for T in ShiftedPrimedTableaux(weight=tuple(weight), shape=self._shape, primed_diagonal=self._primed_diagonal)]) return tuple(list_dw) def shape(self): @@ -2430,7 +2396,7 @@ def _contains_tableau(self, T): if not flat: return not self._weight max_ind = max(flat) - weight = tuple([flat.count(i+1) for i in range(max_ind)]) + weight = tuple([flat.count(i + 1) for i in range(max_ind)]) return self._weight == weight def __iter__(self): @@ -2458,11 +2424,8 @@ def __iter__(self): 16 """ for shape_ in ZS1_iterator(sum(self._weight)): - if all(shape_[i] > shape_[i+1] for i in range(len(shape_)-1)): - for tab in ShiftedPrimedTableaux(shape=shape_, weight=self._weight, - skew=self._skew, - primed_diagonal=self._primed_diagonal - ): + if all(shape_[i] > shape_[i + 1] for i in range(len(shape_) - 1)): + for tab in ShiftedPrimedTableaux(shape=shape_, weight=self._weight, skew=self._skew, primed_diagonal=self._primed_diagonal): yield self.element_class(self, tab, check=False, preprocessed=True) @@ -2521,8 +2484,7 @@ def _repr_(self): sage: ShiftedPrimedTableaux([3,2,1], weight=(4,2)) Shifted Primed Tableaux of weight (4, 2) and shape [3, 2, 1] """ - return ("Shifted Primed Tableaux of weight {} and shape {}" - .format(self._weight, self._shape)) + return "Shifted Primed Tableaux of weight {} and shape {}".format(self._weight, self._shape) def _contains_tableau(self, T): """ @@ -2567,7 +2529,7 @@ def _contains_tableau(self, T): return not self._weight max_ind = max(flat) - weight = tuple([flat.count(i+1) for i in range(max_ind)]) + weight = tuple([flat.count(i + 1) for i in range(max_ind)]) if self._weight != weight: return False @@ -2628,16 +2590,14 @@ def __iter__(self): new_tab = [] new_tab1 = None if len(sub_shape) < len(full_shape): - new_tab = [sub_tab[r] + [i+half]*strip[r] + [i+1]*strip[-r-1] - for r in range(l-1)] + new_tab = [sub_tab[r] + [i + half] * strip[r] + [i + 1] * strip[-r - 1] for r in range(l - 1)] if strip[l] != 0: if self._primed_diagonal: new_tab1 = new_tab[:] - new_tab1.append([i+half] + [i+1] * (strip[l]-1)) - new_tab.append([i+1] * strip[l]) + new_tab1.append([i + half] + [i + 1] * (strip[l] - 1)) + new_tab.append([i + 1] * strip[l]) else: - new_tab = [sub_tab[r] + [i+half]*strip[r] + [i+1]*strip[-r-1] - for r in range(l)] + new_tab = [sub_tab[r] + [i + half] * strip[r] + [i + 1] * strip[-r - 1] for r in range(l)] tab_list_new.append(new_tab) if new_tab1: tab_list_new.append(new_tab1) @@ -2681,7 +2641,7 @@ def _add_strip(sub_tab, full_tab, length): for row in range(1, len(sub_tab)): if sub_tab[row] == full_tab[row]: cliff_list.append(0) - elif sub_tab[row-1] - 1 == sub_tab[row]: + elif sub_tab[row - 1] - 1 == sub_tab[row]: cliff_list[-1] += 1 else: cliff_list.append(1) @@ -2690,33 +2650,25 @@ def _add_strip(sub_tab, full_tab, length): cliff_list.append(0) for primes_num in range(min(sum(cliff_list), length) + 1): - for primed_list in IntegerVectors(n=primes_num, k=len(cliff_list), - outer=cliff_list): + for primed_list in IntegerVectors(n=primes_num, k=len(cliff_list), outer=cliff_list): row = 0 primed_strip = [] for i, cliff in enumerate(cliff_list): if cliff == 0: row += 1 primed_strip.append(0) - primed_strip.extend([int(primed_list[i] > j) - for j in range(cliff)]) + primed_strip.extend([int(primed_list[i] > j) for j in range(cliff)]) row += cliff plat_list = [] if sub_tab and len(sub_tab) < len(full_tab): - plat_list.append(min(sub_tab[-1] + primed_strip[-2] - 1, - full_tab[len(sub_tab)])) - plat_list.extend( - min(sub_tab[row-1] + primed_strip[row-1] - 1, full_tab[row]) - - sub_tab[row] - primed_strip[row] - for row in reversed(range(1, len(sub_tab)))) + plat_list.append(min(sub_tab[-1] + primed_strip[-2] - 1, full_tab[len(sub_tab)])) + plat_list.extend(min(sub_tab[row - 1] + primed_strip[row - 1] - 1, full_tab[row]) - sub_tab[row] - primed_strip[row] for row in reversed(range(1, len(sub_tab)))) if sub_tab: plat_list.append(full_tab[0] - sub_tab[0] - primed_strip[0]) else: plat_list.append(full_tab[0]) - for non_primed_strip in IntegerVectors(n=length-primes_num, - k=len(plat_list), - outer=plat_list): + for non_primed_strip in IntegerVectors(n=length - primes_num, k=len(plat_list), outer=plat_list): yield list(primed_strip) + list(non_primed_strip) diff --git a/src/sage/combinat/shuffle.py b/src/sage/combinat/shuffle.py index e20bd032398..c5217765833 100644 --- a/src/sage/combinat/shuffle.py +++ b/src/sage/combinat/shuffle.py @@ -37,6 +37,7 @@ - Jean-Baptiste Priez """ + # **************************************************************************** # Copyright (C) 2014 Jean-Baptiste Priez # @@ -61,6 +62,7 @@ # TODO: Think about Parent/Element for this and the category # sage.categories.finite_enumerated_sets.FiniteEnumeratedSets + class ShuffleProduct_abstract(Parent): """ Abstract base class for shuffle products. @@ -237,8 +239,7 @@ def _repr_(self): sage: SetShuffleProduct([()], [[1,4]]) Shuffle set product of: [()] and [[1, 4]] """ - return "Shuffle set product of: %s and %s" % (self._element_constructor_(self._l1), - self._element_constructor_(self._l2)) + return "Shuffle set product of: %s and %s" % (self._element_constructor_(self._l1), self._element_constructor_(self._l2)) def _ascii_art_(self): r""" @@ -253,9 +254,8 @@ def _ascii_art_(self): [ [ ], [ o o ] ] and [ [ 1, 4 ] ] """ from sage.typeset.ascii_art import ascii_art - return (ascii_art("Set shuffle product of:") * - (ascii_art(self._l1) + ascii_art(" and ") + - ascii_art(self._l2))) + + return ascii_art("Set shuffle product of:") * (ascii_art(self._l1) + ascii_art(" and ") + ascii_art(self._l2)) def __iter__(self): """ @@ -280,10 +280,7 @@ def __iter__(self): {1, 3, 4}, {1, 3, 4}] """ - return itertools.chain.from_iterable( - ShuffleProduct(*pair, - element_constructor=self._element_constructor_) - for pair in itertools.product(self._l1, self._l2)) + return itertools.chain.from_iterable(ShuffleProduct(*pair, element_constructor=self._element_constructor_) for pair in itertools.product(self._l1, self._l2)) def cardinality(self): """ @@ -296,13 +293,13 @@ def cardinality(self): sage: SetShuffleProduct([[1,2],[3,4]], [[1,4]], element_constructor=set).cardinality() 12 """ + def comp_binom(el1, el2): ll1 = Integer(len(el1)) ll2 = Integer(len(el2)) return (ll1 + ll2).binomial(ll2) - return sum(comp_binom(el1, el2) - for el1, el2 in itertools.product(self._l1, self._l2)) + return sum(comp_binom(el1, el2) for el1, el2 in itertools.product(self._l1, self._l2)) class ShuffleProduct(ShuffleProduct_abstract): @@ -390,9 +387,8 @@ def _ascii_art_(self): [ o o ] and [ o o o ] """ from sage.typeset.ascii_art import ascii_art - return ascii_art("Shuffle product of:") * \ - (ascii_art(self._l1) + ascii_art(" and ") + - ascii_art(self._l2)) + + return ascii_art("Shuffle product of:") * (ascii_art(self._l1) + ascii_art(" and ") + ascii_art(self._l2)) def __iter__(self): r""" @@ -504,9 +500,9 @@ def __contains__(self, iterable): else: return False if i_l1 == len_l1: - return iterable[i + 1:] == l2[i_l2:] + return iterable[i + 1 :] == l2[i_l2:] if i_l2 == len_l2: - return iterable[i + 1:] == l1[i_l1:] + return iterable[i + 1 :] == l1[i_l1:] return i_l1 + 1 == len_l1 and i_l2 + 1 == len_l2 def cardinality(self): @@ -792,8 +788,7 @@ def _repr_(self): sage: ShuffleProduct_overlapping(w,u).__repr__() 'Overlapping shuffle product of word: 29 and word: 91' """ - return "Overlapping shuffle product of %s and %s" % (repr(self._l1), - repr(self._l2)) + return "Overlapping shuffle product of %s and %s" % (repr(self._l1), repr(self._l2)) def __iter__(self): """ @@ -817,6 +812,4 @@ def __iter__(self): m = len(self._l1) n = len(self._l2) for r in range(min(m, n) + 1): - yield from ShuffleProduct_overlapping_r(self._l1, self._l2, r, - self._element_constructor_, - add=self._add) + yield from ShuffleProduct_overlapping_r(self._l1, self._l2, r, self._element_constructor_, add=self._add) diff --git a/src/sage/combinat/sidon_sets.py b/src/sage/combinat/sidon_sets.py index 0713427eeec..6db5b442663 100644 --- a/src/sage/combinat/sidon_sets.py +++ b/src/sage/combinat/sidon_sets.py @@ -5,6 +5,7 @@ - Martin Raum (07-25-2011) """ + # **************************************************************************** # Copyright (C) 2011 Martin Raum # diff --git a/src/sage/combinat/similarity_class_type.py b/src/sage/combinat/similarity_class_type.py index 73929d415f6..2684aa70241 100644 --- a/src/sage/combinat/similarity_class_type.py +++ b/src/sage/combinat/similarity_class_type.py @@ -231,7 +231,7 @@ def fq(n, q=None): """ if q is None: q = ZZ['q'].gen() - return prod(1 - q**(-i - 1) for i in range(n)) + return prod(1 - q ** (-i - 1) for i in range(n)) @cached_function @@ -346,7 +346,7 @@ def centralizer_group_cardinality(la, q=None): """ if q is None: q = ZZ['q'].gen() - return q**centralizer_algebra_dim(la)*prod([fq(m, q=q) for m in la.to_exp()]) + return q ** centralizer_algebra_dim(la) * prod([fq(m, q=q) for m in la.to_exp()]) def invariant_subspace_generating_function(la, q=None, t=None): @@ -369,20 +369,19 @@ def invariant_subspace_generating_function(la, q=None, t=None): t^4 + (q + 1)*t^3 + (q^2 + q + 1)*t^2 + (q + 1)*t + 1 """ if q is None: - q = PolynomialRing(QQ,'q').gen() + q = PolynomialRing(QQ, 'q').gen() S = q.parent() if t is None: - t = PolynomialRing(S,'t').gen() + t = PolynomialRing(S, 't').gen() R = t.parent() Rff = R.fraction_field() if not la: return Rff(1) u = invariant_subspace_generating_function(la[1:], q=q, t=t) - return R((t**(la[0]+1) * q**(sum(la[1:])) * u.substitute(t=t/q) - u.substitute(t=t*q)) / (t - 1)) + return R((t ** (la[0] + 1) * q ** (sum(la[1:])) * u.substitute(t=t / q) - u.substitute(t=t * q)) / (t - 1)) -class PrimarySimilarityClassType(Element, - metaclass=InheritComparisonClasscallMetaclass): +class PrimarySimilarityClassType(Element, metaclass=InheritComparisonClasscallMetaclass): r""" A primary similarity class type is a pair consisting of a partition and a positive integer. @@ -399,6 +398,7 @@ class type `(d, \lambda)` represents similarity classes of square matrices for some irreducible polynomial `p(t)` of degree `d`. """ + @staticmethod def __classcall_private__(cls, deg, par): r""" @@ -417,7 +417,7 @@ def __classcall_private__(cls, deg, par): 12 """ par = Partition(par) - P = PrimarySimilarityClassTypes(par.size()*deg) + P = PrimarySimilarityClassTypes(par.size() * deg) return P(deg, par) def __init__(self, parent, deg, par): @@ -482,9 +482,7 @@ def __eq__(self, other): sage: PT1 == PT5 False """ - return isinstance(other, PrimarySimilarityClassType) and \ - self.degree() == other.degree() and \ - self.partition() == other.partition() + return isinstance(other, PrimarySimilarityClassType) and self.degree() == other.degree() and self.partition() == other.partition() def __ne__(self, other): r""" @@ -498,9 +496,7 @@ def __ne__(self, other): sage: PT1 != PT3 True """ - return not isinstance(other, PrimarySimilarityClassType) or \ - self.degree() != other.degree() or \ - self.partition() != other.partition() + return not isinstance(other, PrimarySimilarityClassType) or self.degree() != other.degree() or self.partition() != other.partition() def size(self): """ @@ -552,7 +548,7 @@ def centralizer_algebra_dim(self): sage: PT.centralizer_algebra_dim() 28 """ - return self.degree()*centralizer_algebra_dim(self.partition()) + return self.degree() * centralizer_algebra_dim(self.partition()) @cached_in_parent_method def statistic(self, func, q=None): @@ -569,7 +565,7 @@ def statistic(self, func, q=None): """ if q is None: q = ZZ['q'].gen() - return q.parent()(func(self.partition()).substitute(q=q**self.degree())) + return q.parent()(func(self.partition()).substitute(q=q ** self.degree())) @cached_in_parent_method def centralizer_group_card(self, q=None): @@ -613,7 +609,7 @@ def invariant_subspace_generating_function(self, q=None, t=None): S = q.parent() if t is None: t = PolynomialRing(S, 't').gen() - return invariant_subspace_generating_function(self.partition()).substitute(q=q**self.degree(), t=t**self.degree()) + return invariant_subspace_generating_function(self.partition()).substitute(q=q ** self.degree(), t=t ** self.degree()) class PrimarySimilarityClassTypes(UniqueRepresentation, Parent): @@ -654,6 +650,7 @@ class PrimarySimilarityClassTypes(UniqueRepresentation, Parent): [1, [1, 1]] [2, [1]] """ + @staticmethod def __classcall_private__(cls, n, min=None): r""" @@ -745,6 +742,7 @@ def size(self): """ return self._n + ############################################################################### ############################################################################### @@ -769,6 +767,7 @@ class SimilarityClassType(CombinatorialElement): sage: SimilarityClassType(Matrix(GF(2), [[1,1],[0,1]])) [[1, [2]]] """ + @staticmethod def __classcall_private__(cls, tau): """ @@ -804,7 +803,7 @@ def __classcall_private__(cls, tau): R = PolynomialRing(F, 't') t = R.gen() S = (t - tau).smith_form(transformation=False) - L = [S[i,i] for i in range(n-1, -1, -1) if S[i,i]] + L = [S[i, i] for i in range(n - 1, -1, -1) if S[i, i]] f = [dict(list(p.factor())) for p in L] d = {p: Partition([h[p] for h in f if p in h]) for p in f[0]} return SimilarityClassType([[p.degree(), d[p]] for p in d]) @@ -915,7 +914,7 @@ def number_of_classes(self, invertible=False, q=None): return q.parent().one() list_of_degrees = [PT.degree() for PT in self] maximum_degree = max(list_of_degrees) - numerator = prod([prod([primitives(d+1, invertible=invertible, q=q)-i for i in range(list_of_degrees.count(d+1))]) for d in range(maximum_degree)]) + numerator = prod([prod([primitives(d + 1, invertible=invertible, q=q) - i for i in range(list_of_degrees.count(d + 1))]) for d in range(maximum_degree)]) tau_list = list(self) D = {i: tau_list.count(i) for i in tau_list} denominator = prod(factorial(D[primary_type]) for primary_type in D) @@ -967,12 +966,12 @@ def rcf(self): out_list = list() i = 0 while True: - new_part = sum([PT.partition().get_part(i)*PT.degree() for PT in self]) + new_part = sum([PT.partition().get_part(i) * PT.degree() for PT in self]) if new_part: out_list.append(new_part) else: return Partition(out_list) - i = i+1 + i = i + 1 def class_card(self, q=None): """ @@ -1017,7 +1016,7 @@ def number_of_matrices(self, invertible=False, q=None): """ if q is None: q = ZZ['q'].gen() - return self.class_card(q=q)*self.number_of_classes(invertible=invertible, q=q) + return self.class_card(q=q) * self.number_of_classes(invertible=invertible, q=q) def statistic(self, func, q=None): r""" @@ -1118,6 +1117,7 @@ class types which are multisets of primary matrix types which either have [[1, [1, 1]]] [[2, [1]]] """ + @staticmethod def __classcall_private__(cls, n, min=None): r""" @@ -1287,13 +1287,14 @@ def sum(self, stat, sumover='matrices', invertible=False, q=None): q^2 + q """ if sumover == "matrices": - return sum([tau.statistic(stat, q=q)*tau.number_of_matrices(invertible=invertible, q=q) for tau in self]) + return sum([tau.statistic(stat, q=q) * tau.number_of_matrices(invertible=invertible, q=q) for tau in self]) if sumover == "classes": - return sum([tau.statistic(stat, q=q)*tau.number_of_classes(invertible=invertible, q=q) for tau in self]) + return sum([tau.statistic(stat, q=q) * tau.number_of_classes(invertible=invertible, q=q) for tau in self]) if sumover == "types": return sum([tau.statistic(stat, invertible=invertible, q=q) for tau in self]) raise ValueError("invalid parameter %s" % (sumover)) + ################################################################################ # Similarity over rings of length two # ################################################################################ @@ -1323,8 +1324,7 @@ def dictionary_from_generator(gen): """ L = list(gen) setofkeys = set(item[0] for item in L) - return {key: sum(pair[1] for pair in L if pair[0] == key) - for key in setofkeys} + return {key: sum(pair[1] for pair in L if pair[0] == key) for key in setofkeys} def matrix_similarity_classes(n, q=None, invertible=False): @@ -1349,10 +1349,8 @@ def matrix_similarity_classes(n, q=None, invertible=False): return basering.one() if invertible: tilde = 1 - ~q - return sum(q**max(la) * - tilde ** len([x for x in la.to_exp() if x > 0]) - for la in Partitions(n)) - return sum(q**max(la) for la in Partitions(n)) + return sum(q ** max(la) * tilde ** len([x for x in la.to_exp() if x > 0]) for la in Partitions(n)) + return sum(q ** max(la) for la in Partitions(n)) def matrix_centralizer_cardinalities(n, q=None, invertible=False): @@ -1476,23 +1474,23 @@ def ext_orbits(input_data, q=None, selftranspose=False): if max(la) == 1: return matrix_similarity_classes(len(la), q=q) if len(la) == 1: - return q**la.size() + return q ** la.size() if len(la) == 2 and list(la).count(1) == 1: # see Table 3 m = max(la) - 1 if selftranspose: - return q**(m + 2) + q**(m + 1) - q**m - return q**(m + 2) + q**(m + 1) + q**m + return q ** (m + 2) + q ** (m + 1) - q**m + return q ** (m + 2) + q ** (m + 1) + q**m if len(la) == 3 and list(la).count(1) == 2: # see Table 4 m = max(la) - 1 if not selftranspose: - return q**m*(q**3 + 2*q**2 + 2*q + 2) - return q**m*(q**3 + 2*q**2) + return q**m * (q**3 + 2 * q**2 + 2 * q + 2) + return q**m * (q**3 + 2 * q**2) if min(la) == 2 and max(la) == 2: return matrix_similarity_classes_length_two(len(la), q=q, selftranspose=selftranspose) raise ValueError('partition %s not implemented for ExtOrbitClasses.orbits' % (la)) elif case == 'pri': tau = data - return ext_orbits(tau.partition(), q=q, selftranspose=selftranspose).substitute(q=q**tau.degree()) + return ext_orbits(tau.partition(), q=q, selftranspose=selftranspose).substitute(q=q ** tau.degree()) elif case == 'sim': tau = data return prod([ext_orbits(PT, q=q, selftranspose=selftranspose) for PT in tau]) @@ -1547,7 +1545,7 @@ def matrix_similarity_classes_length_two(n, q=None, selftranspose=False, inverti """ if q is None: q = FractionField(QQ['q']).gen() - return sum([tau.number_of_classes(invertible=invertible, q=q)*ext_orbits(tau, q=q, selftranspose=selftranspose) for tau in SimilarityClassTypes(n)]) + return sum([tau.number_of_classes(invertible=invertible, q=q) * ext_orbits(tau, q=q, selftranspose=selftranspose) for tau in SimilarityClassTypes(n)]) def ext_orbit_centralizers(input_data, q=None, selftranspose=False): @@ -1635,28 +1633,28 @@ def ext_orbit_centralizers(input_data, q=None, selftranspose=False): yield item return elif len(la) == 1: - yield (q**la[0] - q**(la[0]-1), q**la[0]) + yield (q ** la[0] - q ** (la[0] - 1), q ** la[0]) return elif len(la) == 2 and list(la).count(1) == 1: # see Table 3 m = max(la) - 1 - yield (q**(m + 4) - 2*q**(m + 3) + q**(m + 2), q**(m + 1)) # (8.5.1) - yield (q**(m + 2) - 2*q**(m + 1) + q**m, q**(m + 2) - q**(m + 1)) # (8.5.2) + yield (q ** (m + 4) - 2 * q ** (m + 3) + q ** (m + 2), q ** (m + 1)) # (8.5.1) + yield (q ** (m + 2) - 2 * q ** (m + 1) + q**m, q ** (m + 2) - q ** (m + 1)) # (8.5.2) if selftranspose: - yield (q**(m + 2) - q**(m + 1), q**(m+1) - q**m) # (8.5.3) and (8.5.4) + yield (q ** (m + 2) - q ** (m + 1), q ** (m + 1) - q**m) # (8.5.3) and (8.5.4) else: - yield (q**(m + 2) - q**(m + 1), q**(m + 1) + q**m) # (8.5.3) and (8.5.4) + yield (q ** (m + 2) - q ** (m + 1), q ** (m + 1) + q**m) # (8.5.3) and (8.5.4) return elif len(la) == 3 and list(la).count(1) == 2: # see Table 4 m = max(la) - 1 for item in matrix_centralizer_cardinalities(2, q=q): - yield (item[0]*(q**(m + 5) - q**(m + 4)), item[1]*q**m) # (8.6.1) - yield (item[0]*(q**(m + 1) - q**m), item[1]*(q**(m + 1) - q**m)) # (8.6.2) - yield (q**(m + 3) - 2*q**(m + 2) + q**(m+1), q**(m + 2) - q**(m + 1)) # (8.6.3) + yield (item[0] * (q ** (m + 5) - q ** (m + 4)), item[1] * q**m) # (8.6.1) + yield (item[0] * (q ** (m + 1) - q**m), item[1] * (q ** (m + 1) - q**m)) # (8.6.2) + yield (q ** (m + 3) - 2 * q ** (m + 2) + q ** (m + 1), q ** (m + 2) - q ** (m + 1)) # (8.6.3) if selftranspose: - yield (q**(m + 3) - q**(m+2), q**(m+1)) # (8.6.4), (8.6.5) and (8.6.7) + yield (q ** (m + 3) - q ** (m + 2), q ** (m + 1)) # (8.6.4), (8.6.5) and (8.6.7) else: - yield (q**(m + 3) - q**(m+2), q**(m + 1) + 2*q**m) # (8.6.4), (8.6.5) and (8.6.7) - yield (q**(m + 5) - 2*q**(m + 4) + q**(m + 3), 2*q**(m + 1)) # (8.6.6) and (8.6.8) + yield (q ** (m + 3) - q ** (m + 2), q ** (m + 1) + 2 * q**m) # (8.6.4), (8.6.5) and (8.6.7) + yield (q ** (m + 5) - 2 * q ** (m + 4) + q ** (m + 3), 2 * q ** (m + 1)) # (8.6.6) and (8.6.8) return elif max(la) == 2 and min(la) == 2: for item in matrix_centralizer_cardinalities_length_two(len(la), q=q, selftranspose=selftranspose): @@ -1666,7 +1664,7 @@ def ext_orbit_centralizers(input_data, q=None, selftranspose=False): elif case == 'pri': tau = data for item in ext_orbit_centralizers(tau.partition(), selftranspose=selftranspose): - yield (item[0].substitute(q=q**tau.degree()), item[1].substitute(q=q**tau.degree())) + yield (item[0].substitute(q=q ** tau.degree()), item[1].substitute(q=q ** tau.degree())) elif case == 'sim': tau = data for item in product(*[IterableFunctionCall(lambda x: ext_orbit_centralizers(x, q=q, selftranspose=selftranspose), PT) for PT in tau]): @@ -1711,4 +1709,4 @@ def matrix_centralizer_cardinalities_length_two(n, q=None, selftranspose=False, q = FractionField(QQ['q']).gen() for tau in SimilarityClassTypes(n): for pair in ext_orbit_centralizers(tau, q=q, selftranspose=selftranspose): - yield (q**tau.centralizer_algebra_dim()*pair[0], tau.number_of_classes(invertible=invertible, q=q)*pair[1]) + yield (q ** tau.centralizer_algebra_dim() * pair[0], tau.number_of_classes(invertible=invertible, q=q) * pair[1]) diff --git a/src/sage/combinat/sine_gordon.py b/src/sage/combinat/sine_gordon.py index 77d10d6b4d2..6cf378fc822 100644 --- a/src/sage/combinat/sine_gordon.py +++ b/src/sage/combinat/sine_gordon.py @@ -26,6 +26,7 @@ The code for plotting is extremely slow. """ + # **************************************************************************** # Copyright (C) 2014 Salvatore Stella # @@ -50,6 +51,7 @@ from sage.symbolic.ring import SR from sage.functions.other import real_part, imag_part from sage.misc.cachefunc import cached_method + lazy_import("sage.plot.plot", "parametric_plot") lazy_import("sage.plot.graphics", "Graphics") lazy_import("sage.plot.polygon", "polygon2d") @@ -127,15 +129,12 @@ def __init__(self, X, na): raise ValueError("the type must be either 'A' or 'D'") self._type = X if na[0] <= 2: - raise ValueError("the first integer in the defining sequence " - "must be greater than 2") + raise ValueError("the first integer in the defining sequence " "must be greater than 2") if any(x not in NN for x in na): - raise ValueError("the defining sequence must contain only " - "positive integers") + raise ValueError("the defining sequence must contain only " "positive integers") self._na = tuple(na) if self._na == (3,) and self._type == 'A': - raise ValueError("the integer sequence (3,) in type 'A'" - " is not allowed as input") + raise ValueError("the integer sequence (3,) in type 'A'" " is not allowed as input") self._F = len(self._na) def _repr_(self): @@ -471,8 +470,7 @@ def plot(self, **kwds): points_opts['size'] = kwds.get('points_size', 7) triangulation_opts = {} triangulation_opts['color'] = kwds.get('triangulation_color', 'black') - triangulation_opts['thickness'] = kwds.get('triangulation_thickness', - 0.5) + triangulation_opts['thickness'] = kwds.get('triangulation_thickness', 0.5) shading_opts = {} shading_opts['color'] = kwds.get('shading_color', 'lightgray') reflections_opts = {} @@ -495,8 +493,10 @@ def plot_arc(radius, p, q, **opts): q = ZZ(q) t = SR.var('t') if p - q in [1, -1]: + def f(t): return (radius * cos(t), radius * sin(t)) + p, q = sorted([p, q]) angle_p = vertex_to_angle(p) angle_q = vertex_to_angle(q) @@ -513,16 +513,14 @@ def f(t): angle_center = (angle_p + angle_q) / 2 hypotenuse = radius / cos(internal_angle / 2) radius_arc = hypotenuse * sin(internal_angle / 2) - center = (hypotenuse * cos(angle_center), - hypotenuse * sin(angle_center)) + center = (hypotenuse * cos(angle_center), hypotenuse * sin(angle_center)) center_angle_p = angle_p + pi / 2 center_angle_q = angle_q + 3 * pi / 2 def f(t): - return (radius_arc * cos(t) + center[0], - radius_arc * sin(t) + center[1]) - return parametric_plot(f(t), (t, center_angle_p, - center_angle_q), **opts) + return (radius_arc * cos(t) + center[0], radius_arc * sin(t) + center[1]) + + return parametric_plot(f(t), (t, center_angle_p, center_angle_q), **opts) if self.type() == 'D': if p >= q: q += self.r() @@ -532,10 +530,9 @@ def f(t): arc_center = qx + arc_radius def f(t): - return exp(I * ((cos(t) + I * sin(t)) * - arc_radius + arc_center)) * radius - return parametric_plot((real_part(f(t)), imag_part(f(t))), - (t, 0, pi), **opts) + return exp(I * ((cos(t) + I * sin(t)) * arc_radius + arc_center)) * radius + + return parametric_plot((real_part(f(t)), imag_part(f(t))), (t, 0, pi), **opts) def vertex_to_angle(v): # v==0 corresponds to pi/2 @@ -544,9 +541,7 @@ def vertex_to_angle(v): # Begin plotting P = Graphics() # Shade neuter intervals - neuter_intervals = [x for x in flatten(self.intervals()[:-1], - max_level=1) - if x[2] in ["NR", "NL"]] + neuter_intervals = [x for x in flatten(self.intervals()[:-1], max_level=1) if x[2] in ["NR", "NL"]] shaded_triangles = map(triangle, neuter_intervals) for p, q, r in shaded_triangles: points = list(plot_arc(radius, p, q)[0]) @@ -560,30 +555,18 @@ def vertex_to_angle(v): P += plot_arc(radius, p, q, **triangulation_opts) if self.type() == 'D': s = radius / 50.0 - P += polygon2d([(s, 5 * s), (s, 7 * s), - (3 * s, 5 * s), (3 * s, 7 * s)], - color=triangulation_opts['color']) - P += bezier_path([[(0, 0), (2 * s, 1 * s), (2 * s, 6 * s)], - [(2 * s, 10 * s), (s, 20 * s)], - [(0, 30 * s), (0, radius)]], - **triangulation_opts) - P += bezier_path([[(0, 0), (-2 * s, 1 * s), (-2 * s, 6 * s)], - [(-2 * s, 10 * s), (-s, 20 * s)], - [(0, 30 * s), (0, radius)]], - **triangulation_opts) + P += polygon2d([(s, 5 * s), (s, 7 * s), (3 * s, 5 * s), (3 * s, 7 * s)], color=triangulation_opts['color']) + P += bezier_path([[(0, 0), (2 * s, 1 * s), (2 * s, 6 * s)], [(2 * s, 10 * s), (s, 20 * s)], [(0, 30 * s), (0, radius)]], **triangulation_opts) + P += bezier_path([[(0, 0), (-2 * s, 1 * s), (-2 * s, 6 * s)], [(-2 * s, 10 * s), (-s, 20 * s)], [(0, 30 * s), (0, radius)]], **triangulation_opts) P += point((0, 0), zorder=len(P), **points_opts) # Vertices - v_points = [(radius * cos(vertex_to_angle(x)), - radius * sin(vertex_to_angle(x))) - for x in self.vertices()] + v_points = [(radius * cos(vertex_to_angle(x)), radius * sin(vertex_to_angle(x))) for x in self.vertices()] for coords in v_points: P += point(coords, zorder=len(P), **points_opts) # Reflection axes - P += line([(0, 1.1 * radius), (0, -1.1 * radius)], - zorder=len(P), **reflections_opts) + P += line([(0, 1.1 * radius), (0, -1.1 * radius)], zorder=len(P), **reflections_opts) axis_angle = vertex_to_angle(-0.5 * (self.rk() + (1, 1))[1]) - a, b = (1.1 * radius * cos(axis_angle), - 1.1 * radius * sin(axis_angle)) + a, b = (1.1 * radius * cos(axis_angle), 1.1 * radius * sin(axis_angle)) P += line([(a, b), (-a, -b)], zorder=len(P), **reflections_opts) # Wrap up P.set_aspect_ratio(1) diff --git a/src/sage/combinat/six_vertex_model.py b/src/sage/combinat/six_vertex_model.py index 6fe22512703..1c010c7b667 100644 --- a/src/sage/combinat/six_vertex_model.py +++ b/src/sage/combinat/six_vertex_model.py @@ -47,12 +47,7 @@ def _repr_(self): V V V """ # List are in the order of URDL - ascii = [[r' V ', ' -', r' ^ ', '- '], # LR - [r' | ', ' <', r' ^ ', '- '], # LU - [r' V ', ' <', r' | ', '- '], # LD - [r' | ', ' <', r' | ', '> '], # UD - [r' | ', ' -', r' ^ ', '> '], # UR - [r' V ', ' -', r' | ', '> ']] # RD + ascii = [[r' V ', ' -', r' ^ ', '- '], [r' | ', ' <', r' ^ ', '- '], [r' V ', ' <', r' | ', '- '], [r' | ', ' <', r' | ', '> '], [r' | ', ' -', r' ^ ', '> '], [r' V ', ' -', r' | ', '> ']] # LR # LU # LD # UD # UR # RD ret = ' ' # Do the top line for entry in self[0]: @@ -119,6 +114,7 @@ def to_signed_matrix(self): ] """ from sage.matrix.constructor import matrix + # verts = ['LR', 'LU', 'LD', 'UD', 'UR', 'RD'] def matrix_sign(x): @@ -127,6 +123,7 @@ def matrix_sign(x): if x == 3: return 1 return 0 + return matrix([[matrix_sign(r) for r in row] for row in self]) def plot(self, color='sign'): @@ -168,63 +165,63 @@ def plot(self, color='sign'): if color == 4: color_list = ['black', 'red', 'blue', 'green'] - cfunc = lambda d,pm: color_list[d] + cfunc = lambda d, pm: color_list[d] elif color == 2: - cfunc = lambda d,pm: 'red' if d % 2 == 0 else 'blue' + cfunc = lambda d, pm: 'red' if d % 2 == 0 else 'blue' elif color == 1 or color is None: - cfunc = lambda d,pm: 'black' + cfunc = lambda d, pm: 'black' elif color == 'sign': - cfunc = lambda d,pm: 'red' if pm else 'blue' # RD are True + cfunc = lambda d, pm: 'red' if pm else 'blue' # RD are True elif isinstance(color, (list, tuple)): - cfunc = lambda d,pm: color[d] + cfunc = lambda d, pm: color[d] else: cfunc = color G = Graphics() - for j,row in enumerate(reversed(self)): - for i,entry in enumerate(row): - if entry == 0: # LR - G += arrow((i,j+1), (i,j), color=cfunc(2, True)) - G += arrow((i,j), (i+1,j), color=cfunc(1, True)) + for j, row in enumerate(reversed(self)): + for i, entry in enumerate(row): + if entry == 0: # LR + G += arrow((i, j + 1), (i, j), color=cfunc(2, True)) + G += arrow((i, j), (i + 1, j), color=cfunc(1, True)) if j == 0: - G += arrow((i,j-1), (i,j), color=cfunc(0, False)) + G += arrow((i, j - 1), (i, j), color=cfunc(0, False)) if i == 0: - G += arrow((i,j), (i-1,j), color=cfunc(3, False)) - elif entry == 1: # LU - G += arrow((i,j), (i,j+1), color=cfunc(0, False)) - G += arrow((i+1,j), (i,j), color=cfunc(3, False)) + G += arrow((i, j), (i - 1, j), color=cfunc(3, False)) + elif entry == 1: # LU + G += arrow((i, j), (i, j + 1), color=cfunc(0, False)) + G += arrow((i + 1, j), (i, j), color=cfunc(3, False)) if j == 0: - G += arrow((i,j-1), (i,j), color=cfunc(0, False)) + G += arrow((i, j - 1), (i, j), color=cfunc(0, False)) if i == 0: - G += arrow((i,j), (i-1,j), color=cfunc(3, False)) - elif entry == 2: # LD - G += arrow((i,j+1), (i,j), color=cfunc(2, True)) - G += arrow((i+1,j), (i,j), color=cfunc(3, False)) + G += arrow((i, j), (i - 1, j), color=cfunc(3, False)) + elif entry == 2: # LD + G += arrow((i, j + 1), (i, j), color=cfunc(2, True)) + G += arrow((i + 1, j), (i, j), color=cfunc(3, False)) if j == 0: - G += arrow((i,j), (i,j-1), color=cfunc(2, True)) + G += arrow((i, j), (i, j - 1), color=cfunc(2, True)) if i == 0: - G += arrow((i,j), (i-1,j), color=cfunc(3, False)) - elif entry == 3: # UD - G += arrow((i,j), (i,j+1), color=cfunc(0, False)) - G += arrow((i+1,j), (i,j), color=cfunc(3, False)) + G += arrow((i, j), (i - 1, j), color=cfunc(3, False)) + elif entry == 3: # UD + G += arrow((i, j), (i, j + 1), color=cfunc(0, False)) + G += arrow((i + 1, j), (i, j), color=cfunc(3, False)) if j == 0: - G += arrow((i,j), (i,j-1), color=cfunc(2, True)) + G += arrow((i, j), (i, j - 1), color=cfunc(2, True)) if i == 0: - G += arrow((i-1,j), (i,j), color=cfunc(1, True)) - elif entry == 4: # UR - G += arrow((i,j), (i,j+1), color=cfunc(0, False)) - G += arrow((i,j), (i+1,j), color=cfunc(1, True)) + G += arrow((i - 1, j), (i, j), color=cfunc(1, True)) + elif entry == 4: # UR + G += arrow((i, j), (i, j + 1), color=cfunc(0, False)) + G += arrow((i, j), (i + 1, j), color=cfunc(1, True)) if j == 0: - G += arrow((i,j-1), (i,j), color=cfunc(0, False)) + G += arrow((i, j - 1), (i, j), color=cfunc(0, False)) if i == 0: - G += arrow((i-1,j), (i,j), color=cfunc(1, True)) - elif entry == 5: # RD - G += arrow((i,j+1), (i,j), color=cfunc(2, True)) - G += arrow((i,j), (i+1,j), color=cfunc(1, True)) + G += arrow((i - 1, j), (i, j), color=cfunc(1, True)) + elif entry == 5: # RD + G += arrow((i, j + 1), (i, j), color=cfunc(2, True)) + G += arrow((i, j), (i + 1, j), color=cfunc(1, True)) if j == 0: - G += arrow((i,j), (i,j-1), color=cfunc(2, True)) + G += arrow((i, j), (i, j - 1), color=cfunc(2, True)) if i == 0: - G += arrow((i-1,j), (i,j), color=cfunc(1, True)) + G += arrow((i - 1, j), (i, j), color=cfunc(1, True)) G.axes(False) return G @@ -417,6 +414,7 @@ class SixVertexModel(UniqueRepresentation, Parent): - :wikipedia:`Vertex_model` - :wikipedia:`Ice-type_model` """ + @staticmethod def __classcall_private__(cls, n, m=None, boundary_conditions=None): """ @@ -432,7 +430,7 @@ def __classcall_private__(cls, n, m=None, boundary_conditions=None): if m is None: m = n if boundary_conditions is None or boundary_conditions == 'free': - boundary_conditions = ((None,)*m, (None,)*n)*2 + boundary_conditions = ((None,) * m, (None,) * n) * 2 elif boundary_conditions == 'alternating': bdry = True cond = [] @@ -451,7 +449,7 @@ def __classcall_private__(cls, n, m=None, boundary_conditions=None): elif boundary_conditions == 'ice' or boundary_conditions == 'domain wall': if m == n: return SquareIceModel(n) - boundary_conditions = ((False,)*m, (True,)*n)*2 + boundary_conditions = ((False,) * m, (True,) * n) * 2 else: boundary_conditions = tuple(tuple(x) for x in boundary_conditions) return super().__classcall__(cls, n, m, boundary_conditions) @@ -467,7 +465,7 @@ def __init__(self, n, m, boundary_conditions): """ self._nrows = n self._ncols = m - self._bdry_cond = boundary_conditions # Ordered URDL + self._bdry_cond = boundary_conditions # Ordered URDL Parent.__init__(self, category=FiniteEnumeratedSets()) def _repr_(self): @@ -564,7 +562,7 @@ def __iter__(self): check_left = [False, False, False, True, True, True] bdry = [self._bdry_cond[0]] - lbd = list(self._bdry_cond[3]) + [None] # Dummy + lbd = list(self._bdry_cond[3]) + [None] # Dummy left = [[lbd[0]]] cur = [[-1]] n = self._nrows @@ -578,8 +576,7 @@ def __iter__(self): cur.pop() left.pop() # Check if all our bottom boundary conditions are satisfied - if all(x is not self._bdry_cond[2][i] - for i, x in enumerate(bdry[-1])): + if all(x is not self._bdry_cond[2][i] for i, x in enumerate(bdry[-1])): yield self.element_class(self, tuple(tuple(x) for x in cur)) bdry.pop() @@ -595,9 +592,7 @@ def __iter__(self): l.pop() continue # Check to see if we can add the vertex - if (check_left[row[-1]] is l[-1] or l[-1] is None) \ - and (check_top[row[-1]] is bdry[-1][len(row)-1] - or bdry[-1][len(row)-1] is None): + if (check_left[row[-1]] is l[-1] or l[-1] is None) and (check_top[row[-1]] is bdry[-1][len(row) - 1] or bdry[-1][len(row) - 1] is None): if len(row) != m: l.append(next_left[row[-1]]) row.append(-1) @@ -605,7 +600,7 @@ def __iter__(self): elif next_left[row[-1]] is not self._bdry_cond[1][i]: bdry.append([next_top[x] for x in row]) cur.append([-1]) - left.append([lbd[i+1]]) + left.append([lbd[i + 1]]) break # If we've killed this row, backup @@ -658,6 +653,7 @@ def partition_function(self, beta, epsilon): :wikipedia:`Partition_function_(statistical_mechanics)` """ from sage.functions.log import exp + return sum(exp(-beta * nu.energy(epsilon)) for nu in self) @@ -683,7 +679,7 @@ def __init__(self, n): sage: M = SixVertexModel(3, boundary_conditions='ice') sage: TestSuite(M).run() """ - boundary_conditions = ((False,)*n, (True,)*n)*2 + boundary_conditions = ((False,) * n, (True,) * n) * 2 SixVertexModel.__init__(self, n, n, boundary_conditions) def from_alternating_sign_matrix(self, asm): @@ -721,13 +717,13 @@ def from_alternating_sign_matrix(self, asm): if asm.parent().size() != self._nrows: raise ValueError("mismatched size") - #verts = ['LR', 'LU', 'LD', 'UD', 'UR', 'RD'] + # verts = ['LR', 'LU', 'LD', 'UD', 'UR', 'RD'] ret = [] - bdry = [False]*self._nrows # False = up + bdry = [False] * self._nrows # False = up for row in asm.to_matrix(): cur = [] - right = True # True = right - for j,entry in enumerate(row): + right = True # True = right + for j, entry in enumerate(row): if entry == -1: cur.append(0) right = True @@ -736,7 +732,7 @@ def from_alternating_sign_matrix(self, asm): cur.append(3) right = False bdry[j] = True - else: # entry == 0 + else: # entry == 0 if bdry[j]: if right: cur.append(5) @@ -754,6 +750,7 @@ class Element(SixVertexConfiguration): """ An element in the square ice model. """ + @combinatorial_map(name='to alternating sign matrix') def to_alternating_sign_matrix(self): """ @@ -778,6 +775,7 @@ def to_alternating_sign_matrix(self): [ 0 0 1 0] """ from sage.combinat.alternating_sign_matrix import AlternatingSignMatrix # AlternatingSignMatrices + # ASM = AlternatingSignMatrices(self.parent()._nrows) # return ASM(self.to_signed_matrix()) return AlternatingSignMatrix(self.to_signed_matrix()) diff --git a/src/sage/combinat/skew_partition.py b/src/sage/combinat/skew_partition.py index 0cf18dd46c9..6a3f288dfdb 100644 --- a/src/sage/combinat/skew_partition.py +++ b/src/sage/combinat/skew_partition.py @@ -127,6 +127,7 @@ - Travis Scrimshaw (2013-02-11): Factored out ``CombinatorialClass`` - Trevor K. Karn (2022-08-03): Add ``outside_corners`` """ + # *************************************************************************** # Copyright (C) 2007 Mike Hansen , # @@ -170,6 +171,7 @@ class SkewPartition(CombinatorialElement): partition `\lambda` and removing the partition `\mu` from the upper-left corner in English convention. """ + @staticmethod def __classcall_private__(cls, skp): """ @@ -196,8 +198,7 @@ def __init__(self, parent, skp): sage: skp = SkewPartition([[3,2,1],[2,1]]) sage: TestSuite(skp).run() """ - CombinatorialElement.__init__(self, parent, - [_Partitions(skp[0]), _Partitions(skp[1])]) + CombinatorialElement.__init__(self, parent, [_Partitions(skp[0]), _Partitions(skp[1])]) def _repr_(self): """ @@ -284,8 +285,9 @@ def _latex_diagram(self): char = self.parent().options.latex_diagram_str from sage.combinat.output import tex_from_array - arr = [[char]*row_size for row_size in self[0]] - for i, skew_size in enumerate(self[1]): # This is always smaller by containment + + arr = [[char] * row_size for row_size in self[0]] + for i, skew_size in enumerate(self[1]): # This is always smaller by containment for j in range(skew_size): arr[i][j] = None return tex_from_array(arr) @@ -316,8 +318,9 @@ def _latex_young_diagram(self): return "{\\emptyset}" from sage.combinat.output import tex_from_array - arr = [["\\phantom{x}"]*row_size for row_size in self[0]] - for i, skew_size in enumerate(self[1]): # This is always smaller by containment + + arr = [["\\phantom{x}"] * row_size for row_size in self[0]] + for i, skew_size in enumerate(self[1]): # This is always smaller by containment for j in range(skew_size): arr[i][j] = None return tex_from_array(arr) @@ -348,9 +351,10 @@ def _latex_marked(self): return "{\\emptyset}" from sage.combinat.output import tex_from_array + char = self.parent().options.latex_marking_str - arr = [["\\phantom{x}"]*row_size for row_size in self[0]] - for i, skew_size in enumerate(self[1]): # This is always smaller by containment + arr = [["\\phantom{x}"] * row_size for row_size in self[0]] + for i, skew_size in enumerate(self[1]): # This is always smaller by containment for j in range(skew_size): arr[i][j] = char return tex_from_array(arr) @@ -368,7 +372,7 @@ def __setstate__(self, state): sage: loads(dumps( SkewPartition([[3,2,1], [1,1]]) )) [3, 2, 1] / [1, 1] """ - if isinstance(state, dict): # for old pickles from SkewPartition_class + if isinstance(state, dict): # for old pickles from SkewPartition_class self._set_parent(SkewPartitions()) self.__dict__ = state else: @@ -408,10 +412,10 @@ def ferrers_diagram(self): s = "" for i in L: if len(self[1]) > i: - s += " "*self[1][i] - s += char*(self[0][i]-self[1][i]) + s += " " * self[1][i] + s += char * (self[0][i] - self[1][i]) else: - s += char*self[0][i] + s += char * self[0][i] s += "\n" return s[:-1] @@ -448,6 +452,7 @@ def _ascii_art_(self): sage: SkewPartitions.options._reset() """ from sage.typeset.ascii_art import AsciiArt + return AsciiArt(self.diagram().splitlines()) def _unicode_art_(self): @@ -482,6 +487,7 @@ def _unicode_art_(self): ∅ """ from sage.typeset.unicode_art import UnicodeArt + out, inn = self inn = inn + [0] * (len(out) - len(inn)) if not any(self._list): @@ -575,8 +581,8 @@ def row_lengths(self): """ skp = self o = skp[0] - i = skp[1]+[0]*(len(skp[0])-len(skp[1])) - return [x[0]-x[1] for x in zip(o,i)] + i = skp[1] + [0] * (len(skp[0]) - len(skp[1])) + return [x[0] - x[1] for x in zip(o, i)] def size(self): """ @@ -637,6 +643,7 @@ def overlap(self): p, q = self if len(p) <= 1: from sage.rings.infinity import PlusInfinity + return PlusInfinity() if len(q) == 0: return min(p) @@ -718,7 +725,7 @@ def is_ribbon(self) -> bool: mu = self[1] l_out = len(lam) l_in = len(mu) - mu += [0]*(l_out-l_in) + mu += [0] * (l_out - l_in) if l_out == 0: return True @@ -737,7 +744,7 @@ def is_ribbon(self) -> bool: v = u + 1 v_test = True while v_test: - if v >= l_out or lam[v] != mu[v-1] + 1: + if v >= l_out or lam[v] != mu[v - 1] + 1: v_test = False else: v += 1 @@ -803,12 +810,12 @@ def inner_corners(self): if inner == []: if outer == []: return [] - return [(0,0)] + return [(0, 0)] icorners = [(0, inner[0])] nn = len(inner) - for i in range(1,nn): - if inner[i] != inner[i-1]: - icorners += [ (i, inner[i]) ] + for i in range(1, nn): + if inner[i] != inner[i - 1]: + icorners += [(i, inner[i])] icorners += [(nn, 0)] return icorners @@ -929,20 +936,29 @@ def cell_poset(self, orientation='SE'): False """ from sage.combinat.posets.posets import Poset + # Getting the cover relations seems hard, so let's just compute # the comparison function. if orientation == "NW": + def poset_le(u, v): return u[0] >= v[0] and u[1] >= v[1] + elif orientation == "NE": + def poset_le(u, v): return u[0] >= v[0] and u[1] <= v[1] + elif orientation == "SE": + def poset_le(u, v): return u[0] <= v[0] and u[1] <= v[1] + elif orientation == "SW": + def poset_le(u, v): return u[0] <= v[0] and u[1] >= v[1] + return Poset((self.cells(), poset_le)) def frobenius_rank(self): @@ -1007,9 +1023,8 @@ def frobenius_rank(self): """ N = len(self[0]) mu_betas = [x - j for j, x in enumerate(self[1])] - mu_betas.extend(- j for j in range(len(self[1]), N)) - return sum(1 for i, x in enumerate(self[0]) - if (x - i) not in mu_betas) + mu_betas.extend(-j for j in range(len(self[1]), N)) + return sum(1 for i, x in enumerate(self[0]) if (x - i) not in mu_betas) def cells(self): """ @@ -1028,8 +1043,7 @@ def cells(self): outer = self.outer() inner = self.inner()[:] inner += [0] * (len(outer) - len(inner)) - return [(i, j) for i, outi in enumerate(outer) - for j in range(inner[i], outi)] + return [(i, j) for i, outi in enumerate(outer) for j in range(inner[i], outi)] def to_list(self): """ @@ -1090,7 +1104,7 @@ def to_dag(self, format='string'): else: string = (i, j) G.add_vertex(string) - #Check to see if there is a node to the right + # Check to see if there is a node to the right if j != outer_i - 1: if format == "string": newstring = "%d,%d" % (i, j + 1) @@ -1098,9 +1112,9 @@ def to_dag(self, format='string'): newstring = (i, j + 1) G.add_edge(string, newstring) - #Check to see if there is anything below + # Check to see if there is anything below if i != len(outer) - 1: - if outer[i+1] > j: + if outer[i + 1] > j: if format == "string": newstring = "%d,%d" % (i + 1, j) else: @@ -1124,7 +1138,7 @@ def quotient(self, k): if self.inner().core(k) == self.outer().core(k): rqinner = self.inner().quotient(k) rqouter = self.outer().quotient(k) - return [ SkewPartitions()([rqouter[i],rqinner[i]]) for i in range(k) ] + return [SkewPartitions()([rqouter[i], rqinner[i]]) for i in range(k)] raise ValueError("quotient map is only defined for skew partitions with inner and outer partitions having the same core") def rows_intersection_set(self): @@ -1143,9 +1157,7 @@ def rows_intersection_set(self): inner = self.inner() inner += [0] * (len(outer) - len(inner)) - res = [(i, j) for i, outi in enumerate(outer) - for j in range(outi) - if outi != inner[i]] + res = [(i, j) for i, outi in enumerate(outer) for j in range(outi) if outi != inner[i]] return Set(res) def columns_intersection_set(self): @@ -1160,7 +1172,7 @@ def columns_intersection_set(self): sage: skp.columns_intersection_set() == cells True """ - res = [ (x[1], x[0]) for x in self.conjugate().rows_intersection_set()] + res = [(x[1], x[0]) for x in self.conjugate().rows_intersection_set()] return Set(res) def pieri_macdonald_coeffs(self): @@ -1184,8 +1196,8 @@ def pieri_macdonald_coeffs(self): set_prod = self.rows_intersection_set() - self.columns_intersection_set() res = 1 for s in set_prod: - res *= self.inner().arms_legs_coeff(s[0],s[1]) - res /= self.outer().arms_legs_coeff(s[0],s[1]) + res *= self.inner().arms_legs_coeff(s[0], s[1]) + res /= self.outer().arms_legs_coeff(s[0], s[1]) return res def k_conjugate(self, k): @@ -1201,7 +1213,7 @@ def k_conjugate(self, k): sage: SkewPartition([[3,2,1],[2,1]]).k_conjugate(5) [3, 2, 1] / [2, 1] """ - return SkewPartition([ self.outer().k_conjugate(k), self.inner().k_conjugate(k) ]) + return SkewPartition([self.outer().k_conjugate(k), self.inner().k_conjugate(k)]) def jacobi_trudi(self): """ @@ -1221,6 +1233,7 @@ def jacobi_trudi(self): p = self.outer() q = self.inner() from sage.combinat.sf.sf import SymmetricFunctions + nn = len(p) if nn == 0: return MatrixSpace(SymmetricFunctions(QQ).homogeneous(), 0)(0) @@ -1229,10 +1242,10 @@ def jacobi_trudi(self): q = q + [0] * (nn - len(q)) m = [] - for i in range(1,nn+1): + for i in range(1, nn + 1): row = [] - for j in range(1,nn+1): - v = p[j-1]-q[i-1]-j+i + for j in range(1, nn + 1): + v = p[j - 1] - q[i - 1] - j + i if v < 0: row.append(h.zero()) elif v == 0: @@ -1297,8 +1310,10 @@ def specht_module(self, base_ring=None): """ from sage.combinat.specht_module import SpechtModule from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra + if base_ring is None: from sage.rings.rational_field import QQ + base_ring = QQ R = SymmetricGroupAlgebra(base_ring, self.size()) return SpechtModule(R, self.cells()) @@ -1319,10 +1334,13 @@ def specht_module_dimension(self, base_ring=None): 8 """ from sage.categories.fields import Fields + if base_ring is None or (base_ring in Fields() and base_ring.characteristic() == 0): from sage.combinat.skew_tableau import StandardSkewTableaux + return StandardSkewTableaux(self).cardinality() from sage.combinat.specht_module import specht_module_rank + return specht_module_rank(self, base_ring) @@ -1365,6 +1383,7 @@ class SkewPartitions(UniqueRepresentation, Parent): sage: SkewPartitions(4, overlap=2).list() [[4] / [], [2, 2] / []] """ + @staticmethod def __classcall_private__(self, n=None, row_lengths=None, overlap=0): """ @@ -1449,29 +1468,15 @@ class options(GlobalOptions): 4 5 sage: SkewPartitions.options._reset() """ + NAME = 'SkewPartitions' module = 'sage.combinat.skew_partition' - display = dict(default='quotient', - description='Specifies how skew partitions should be printed', - values=dict(lists='displayed as a pair of lists', - quotient='displayed as a quotient of partitions', - diagram='as a skew Ferrers diagram'), - alias=dict(array='diagram', ferrers_diagram='diagram', - young_diagram='diagram', pair='lists'), - case_sensitive=False) - latex = dict(default='young_diagram', - description='Specifies how skew partitions should be latexed', - values=dict(diagram='latex as a skew Ferrers diagram', - young_diagram='latex as a skew Young diagram', - marked='latex as a partition where the skew shape is marked'), - alias=dict(array='diagram', ferrers_diagram='diagram'), - case_sensitive=False) - diagram_str = dict(link_to=(Partitions.options,'diagram_str')) - latex_diagram_str = dict(link_to=(Partitions.options,'latex_diagram_str')) - latex_marking_str = dict(default='X', - description='The character used to marked the deleted cells when latexing marked partitions', - checker=lambda char: isinstance(char, str)) - convention = dict(link_to=(Tableaux.options,'convention')) + display = dict(default='quotient', description='Specifies how skew partitions should be printed', values=dict(lists='displayed as a pair of lists', quotient='displayed as a quotient of partitions', diagram='as a skew Ferrers diagram'), alias=dict(array='diagram', ferrers_diagram='diagram', young_diagram='diagram', pair='lists'), case_sensitive=False) + latex = dict(default='young_diagram', description='Specifies how skew partitions should be latexed', values=dict(diagram='latex as a skew Ferrers diagram', young_diagram='latex as a skew Young diagram', marked='latex as a partition where the skew shape is marked'), alias=dict(array='diagram', ferrers_diagram='diagram'), case_sensitive=False) + diagram_str = dict(link_to=(Partitions.options, 'diagram_str')) + latex_diagram_str = dict(link_to=(Partitions.options, 'latex_diagram_str')) + latex_marking_str = dict(default='X', description='The character used to marked the deleted cells when latexing marked partitions', checker=lambda char: isinstance(char, str)) + convention = dict(link_to=(Tableaux.options, 'convention')) notation = dict(alt_name='convention') Element = SkewPartition @@ -1715,6 +1720,7 @@ class SkewPartitions_n(SkewPartitions): ``SkewPartition(n, row_lengths=...)``, and one would want to "inherit" list and cardinality from this composition. """ + @staticmethod def __classcall_private__(cls, n, overlap=0): """ @@ -1794,9 +1800,7 @@ def __contains__(self, x): sage: [[7, 4, 3, 2], [5, 2, 1]] in SkewPartitions(8, overlap=-2) True """ - return x in SkewPartitions() \ - and sum(x[0])-sum(x[1]) == self.n \ - and self.overlap <= SkewPartition(x).overlap() + return x in SkewPartitions() and sum(x[0]) - sum(x[1]) == self.n and self.overlap <= SkewPartition(x).overlap() def _repr_(self): """ @@ -1918,6 +1922,7 @@ def __iter__(self): for sp in SkewPartitions(row_lengths=co, overlap=self.overlap): yield self.element_class(self, sp) + ###################################### # Skew Partitions (from row lengths) # ###################################### @@ -1927,6 +1932,7 @@ class SkewPartitions_rowlengths(SkewPartitions): """ All skew partitions with given row lengths. """ + @staticmethod def __classcall_private__(cls, co, overlap=0): """ @@ -1970,8 +1976,8 @@ def __contains__(self, x): """ if x in SkewPartitions(): o = x[0] - i = x[1]+[0]*(len(x[0])-len(x[1])) - return [u[0]-u[1] for u in zip(o,i)] == self.co + i = x[1] + [0] * (len(x[0]) - len(x[1])) + return [u[0] - u[1] for u in zip(o, i)] == self.co return False def _repr_(self): @@ -2000,14 +2006,14 @@ def _from_row_lengths_aux(self, sskp, ck_1, ck, overlap=0): [[2, 1] / [], [3, 1] / [1]] """ nn = min(ck_1, ck) - mm = max(0, ck-ck_1) + mm = max(0, ck - ck_1) # nn should be >= 0. In the case of the positive overlap, # the min_part condition insures ck>=overlap for all k nn -= overlap - for i in range(nn+1): + for i in range(nn + 1): skp1, skp2 = sskp - skp2 += [0]*(len(skp1)-len(skp2)) + skp2 += [0] * (len(skp1) - len(skp2)) skp1 = [x + i + mm for x in skp1] skp1 += [ck] skp2 = [x + i + mm for x in skp2] @@ -2027,12 +2033,12 @@ def __iter__(self): [[2, 2] / [], [3, 2] / [1]] """ if self.co == []: - yield self.element_class(self, [[],[]]) + yield self.element_class(self, [[], []]) return nn = len(self.co) if nn == 1: - yield self.element_class(self, [[self.co[0]],[]]) + yield self.element_class(self, [[self.co[0]], []]) return for sskp in SkewPartitions(row_lengths=self.co[:-1], overlap=self.overlap): @@ -2041,4 +2047,5 @@ def __iter__(self): from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.combinat.skew_partition', 'SkewPartition_class', SkewPartition) diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index fe6999707c7..95fd158f359 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -9,6 +9,7 @@ - Trevor K. Karn (2022-08-03): added ``backward_slide`` - Joseph McDonough (2025-04-09): added ``add_entry`` and ``anti_restrict`` """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # Copyright (C) 2013 Travis Scrimshaw @@ -42,8 +43,7 @@ from sage.structure.list_clone import ClonableList from sage.combinat.partition import Partition -from sage.combinat.tableau import (Tableau, Tableaux, - StandardTableau, SemistandardTableau) +from sage.combinat.tableau import Tableau, Tableaux, StandardTableau, SemistandardTableau from sage.combinat.skew_partition import SkewPartition, SkewPartitions from sage.combinat.integer_vector import IntegerVectors from sage.combinat.words.words import Words @@ -54,8 +54,7 @@ lazy_import('sage.groups.perm_gps.permgroup', 'PermutationGroup') -class SkewTableau(ClonableList, - metaclass=InheritComparisonClasscallMetaclass): +class SkewTableau(ClonableList, metaclass=InheritComparisonClasscallMetaclass): r""" A skew tableau. @@ -84,6 +83,7 @@ class SkewTableau(ClonableList, sage: SkewTableau(chain=[[2], [2, 1], [3, 1], [4, 3, 2, 1]]) [[None, None, 2, 3], [1, 3, 3], [3, 3], [3]] """ + @staticmethod def __classcall_private__(cls, st=None, expr=None, chain=None): """ @@ -282,8 +282,10 @@ def _repr_diagram(self): . 4 5 """ + def none_str(x): return " ." if x is None else "%3s" % str(x) + if self.parent().options('convention') == "French": new_rows = ["".join(map(none_str, row)) for row in reversed(self)] else: @@ -306,6 +308,7 @@ def _repr_compact(self): def str_rep(x): return '%s' % x if x is not None else '.' + return '/'.join(','.join(str_rep(r) for r in row) for row in self) def pp(self): @@ -335,6 +338,7 @@ def _ascii_art_(self): [ 5 , 4 5 ] """ from sage.typeset.ascii_art import AsciiArt + return AsciiArt(self._repr_diagram().splitlines()) def _unicode_art_(self): @@ -359,6 +363,7 @@ def _unicode_art_(self): """ from sage.combinat.output import ascii_art_table from sage.typeset.unicode_art import UnicodeArt + return UnicodeArt(ascii_art_table(self, use_unicode=True).splitlines()) def _latex_(self): @@ -377,6 +382,7 @@ def _latex_(self): } """ from sage.combinat.output import tex_from_array + return tex_from_array(self) def outer_shape(self): @@ -556,6 +562,7 @@ def to_permutation(self): [] """ from sage.combinat.permutation import Permutation + perm = [i for row in reversed(self) for i in row if i is not None] return Permutation(perm) @@ -671,8 +678,7 @@ def is_semistandard(self) -> bool: # Is it weakly increasing along the rows? for row in self: - if any(row[c] is not None and row[c] > row[c + 1] - for c in range(len(row) - 1)): + if any(row[c] is not None and row[c] > row[c + 1] for c in range(len(row) - 1)): return False # Is it strictly increasing down columns? @@ -696,6 +702,7 @@ def to_tableau(self): if self.inner_size() != 0: raise ValueError("the inner size of the skew tableau must be 0") from sage.combinat.tableau import Tableau + return Tableau(self[:]) def restrict(self, n): @@ -754,6 +761,7 @@ def restriction_outer_shape(self, n): [4, 3, 1] """ from sage.combinat.partition import _Partitions + one = ZZ.one() res = [sum(one for y in row if y is None or y <= n) for row in self] return _Partitions(res) @@ -1003,8 +1011,7 @@ def backward_slide(self, corner=None): outer_outisde_corners = self.outer_shape().outside_corners() if corner is not None: if tuple(corner) not in outer_outisde_corners: - raise ValueError("corner must be an outside corner" - " of the outer shape") + raise ValueError("corner must be an outside corner" " of the outer shape") else: if not outer_outisde_corners: return self @@ -1023,14 +1030,14 @@ def backward_slide(self, corner=None): # get the value of the cell above the temporarily empty cell (if # it exists) if i > 0: - P_up = new_st[i-1][j] + P_up = new_st[i - 1][j] else: P_up = -1 # a dummy value less than all positive numbers # get the value of the cell to the left of the temp. empty cell # (if it exists) if j > 0: - P_left = new_st[i][j-1] + P_left = new_st[i][j - 1] else: P_left = -1 # a dummy value less than all positive numbers @@ -1097,7 +1104,7 @@ def rectify(self, algorithm=None): if algorithm is None: la = self.outer_shape() la_size = la.size() - if mu_size ** 2 < len(la) * (la_size - mu_size): + if mu_size**2 < len(la) * (la_size - mu_size): algorithm = 'jdt' else: algorithm = 'schensted' @@ -1107,8 +1114,7 @@ def rectify(self, algorithm=None): for _ in range(mu_size): rect = rect.slide() elif algorithm == 'schensted': - w = [x for row in reversed(self) for x in row - if x is not None] + w = [x for row in reversed(self) for x in row if x is not None] rect = Tableau([]).insert_word(w) else: raise ValueError("algorithm must be 'jdt', 'schensted', or None") @@ -1206,8 +1212,8 @@ def add_entry(self, cell, m): except IndexError: if r > len(tab): if c < len(tab[-1]) and tab[-1][c] is None: - tab += [[None]*(c+1) for i in range(r - len(tab))] - tab.append([None]*(c) + [m]) + tab += [[None] * (c + 1) for i in range(r - len(tab))] + tab.append([None] * (c) + [m]) else: raise IndexError('%s is not an addable cell of the tableau' % ((r, c),)) elif r == len(tab): @@ -1215,13 +1221,13 @@ def add_entry(self, cell, m): # c = 0 or the cell directly northwest is empty if c == 0: tab.append([m]) - elif c < len(tab[-1]) and tab[-1][c-1] is None: - tab.append([None]*(c) + [m]) + elif c < len(tab[-1]) and tab[-1][c - 1] is None: + tab.append([None] * (c) + [m]) else: raise IndexError('%s is not an addable cell of the tableau' % ((r, c),)) else: tab_r = tab[r] - if c == len(tab_r) and (r == 0 or len(tab_r) < len(tab[r-1])): + if c == len(tab_r) and (r == 0 or len(tab_r) < len(tab[r - 1])): tab_r.append(m) else: raise IndexError('%s is not an addable cell of the tableau' % ((r, c),)) @@ -1310,10 +1316,7 @@ def row_stabilizer(self): # tableau, by including the identity permutation on the set [1..k]. k = self.size() gens = [list(range(1, k + 1))] - gens.extend((row[j], row[j + 1]) - for row in self - for j in range(len(row) - 1) - if row[j] is not None) + gens.extend((row[j], row[j + 1]) for row in self for j in range(len(row) - 1) if row[j] is not None) return PermutationGroup(gens) def column_stabilizer(self): @@ -1343,7 +1346,7 @@ def column_stabilizer(self): while ell > 1: ell -= 1 for i, val in enumerate(self[ell]): - top_neighbor = self[ell-1][i] + top_neighbor = self[ell - 1][i] if top_neighbor is not None: gens.append((val, top_neighbor)) return PermutationGroup(gens) @@ -1646,7 +1649,7 @@ def bender_knuth_involution(self, k, rows=None, check=True): """ if check and not self.is_semistandard(): raise ValueError("the skew tableau must be semistandard") - l = len(self) # l is the number of rows of self. + l = len(self) # l is the number of rows of self. # Sanitizing the rows input so that it always becomes a list of # nonnegative integers. We also subtract 1 from these integers # because the i-th row of a tableau T is T[i - 1]. @@ -1828,6 +1831,7 @@ def to_ribbon(self, check_input=True): if check_input and not self.is_ribbon(): raise ValueError("self must be a ribbon") from sage.combinat.ribbon_shaped_tableau import RibbonShapedTableau + r = [[i for i in row if i is not None] for row in self] return RibbonShapedTableau(r) @@ -1913,10 +1917,7 @@ def cells(self): sage: s.cells() [(0, 1), (0, 2), (1, 0), (2, 0)] """ - return [(i, j) - for i, selfi in enumerate(self) - for j in range(len(selfi)) - if selfi[j] is not None] + return [(i, j) for i, selfi in enumerate(self) for j in range(len(selfi)) if selfi[j] is not None] def cells_containing(self, i): r""" @@ -1975,8 +1976,7 @@ def is_k_tableau(self, k) -> bool: """ shapes = self.to_chain() kshapes = [la.k_conjugate(k) for la in shapes] - return all(kshapes[i + 1].contains(kshapes[i]) - for i in range(len(shapes) - 1)) + return all(kshapes[i + 1].contains(kshapes[i]) for i in range(len(shapes) - 1)) def _label_skew(list_of_cells, sk): @@ -2085,8 +2085,7 @@ def from_expr(self, expr): outer = expr[1] inner = expr[0] + [0] * (len(outer) - len(expr[0])) - skp = [[None] * (inner[i]) + outer[-(i + 1)] - for i in range(len(outer))] + skp = [[None] * (inner[i]) + outer[-(i + 1)] for i in range(len(outer))] return self.element_class(self, skp) @@ -2100,7 +2099,7 @@ def from_chain(self, chain): [[None, 1, 2], [None, 3, 4], [5]] """ shape = chain[-1] - T = [[None]*r for r in shape] + T = [[None] * r for r in shape] for i in range(1, len(chain)): la = chain[i] mu = chain[i - 1] @@ -2171,6 +2170,7 @@ class StandardSkewTableaux(SkewTableaux): [[None, 1, 3], [None, 2], [4]], [[None, 2, 4], [None, 3], [1]]] """ + @staticmethod def __classcall_private__(cls, skp=None): """ @@ -2338,6 +2338,7 @@ class StandardSkewTableaux_shape(StandardSkewTableaux): r""" Standard skew tableaux of a fixed skew shape `\lambda / \mu`. """ + @staticmethod def __classcall_private__(cls, skp): """ @@ -2528,6 +2529,7 @@ class SemistandardSkewTableaux(SkewTableaux): sage: SkewTableau([[None]]) in SemistandardSkewTableaux(2) True """ + @staticmethod def __classcall_private__(cls, p=None, mu=None, max_entry=None): """ @@ -2735,6 +2737,7 @@ class SemistandardSkewTableaux_size_weight(SemistandardSkewTableaux): r""" Class of semistandard tableaux of a fixed size `n` and weight `\mu`. """ + @staticmethod def __classcall_private__(cls, n, mu): """ @@ -2813,6 +2816,7 @@ class SemistandardSkewTableaux_shape(SemistandardSkewTableaux): Input is not checked; please use :class:`SemistandardSkewTableaux` to ensure the options are properly parsed. """ + @staticmethod def __classcall_private__(cls, p, max_entry=None): """ @@ -2892,6 +2896,7 @@ class SemistandardSkewTableaux_shape_weight(SemistandardSkewTableaux): Class of semistandard skew tableaux of a fixed skew shape `\lambda / \nu` and weight `\mu`. """ + @staticmethod def __classcall_private__(cls, p, mu): """ @@ -2940,6 +2945,7 @@ def __iter__(self): [[[1, 1], [2]]] """ from .ribbon_tableau import RibbonTableaux_shape_weight_length + for x in RibbonTableaux_shape_weight_length(self.p, self.mu, 1): yield self.element_class(self, x) diff --git a/src/sage/combinat/sloane_functions.py b/src/sage/combinat/sloane_functions.py index 94bb10a967b..c4fb1a2c348 100644 --- a/src/sage/combinat/sloane_functions.py +++ b/src/sage/combinat/sloane_functions.py @@ -131,6 +131,7 @@ from sage.rings.integer_ring import ZZ from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer as Integer_class + # You may have to import more here when defining new sequences import sage.arith.all as arith from sage.rings.rational_field import QQ @@ -206,6 +207,7 @@ def _sage_src_(self): 'class A000045(...' """ from sage.misc.sageinspect import sage_getsource + return sage_getsource(self.__class__) def __call__(self, n): @@ -262,7 +264,7 @@ def list(self, n): sage: sloane.A000012.list(4) [1, 1, 1, 1] """ - return [self._eval(i) for i in srange(self.offset, n+self.offset)] + return [self._eval(i) for i in srange(self.offset, n + self.offset)] # The Python default tries repeated __getitem__ calls, which will succeed, # but is probably not what is wanted. @@ -390,6 +392,7 @@ def _eval(self, n): if n <= 50: return self._small[n - 1] from sage.libs.gap.libgap import libgap + return ZZ(libgap.NumberSmallGroups(n)) @@ -427,7 +430,7 @@ def __init__(self): """ SloaneSequence.__init__(self, offset=1) -# is this a good idea to have a link for all sequences? Jaap + # is this a good idea to have a link for all sequences? Jaap link = "http://oeis.org/classic/A000027" def _repr_(self): @@ -601,6 +604,7 @@ def _eval(self, n): [1, 1, 2, 2, 3, 4, 5, 6, 7, 8, 11, 12, 15, 16] """ from sage.combinat.partition import Partitions + return Partitions(n, parts_in=[1, 2, 5, 10]).cardinality() @@ -659,7 +663,7 @@ def cf(self): p = 1 while True: k += 1 - p *= (1+x**k) + p *= 1 + x**k yield ZZ(p.coefficients(sparse=False)[k]) def _precompute(self, how_many=50): @@ -696,7 +700,7 @@ def list(self, n): sage: sloane.A000009.list(14) [1, 1, 1, 2, 2, 3, 4, 5, 6, 8, 10, 12, 15, 18] """ - self._eval(n) # force computation + self._eval(n) # force computation return self._b[:n] @@ -757,13 +761,13 @@ def pi(self): """ k, a, b, a1, b1 = ZZ(2), ZZ(4), ZZ.one(), ZZ(12), ZZ(4) while True: - p, q, k = k*k, 2*k+1, k+1 - a, b, a1, b1 = a1, b1, p*a+q*a1, p*b+q*b1 - d, d1 = a//b, a1//b1 + p, q, k = k * k, 2 * k + 1, k + 1 + a, b, a1, b1 = a1, b1, p * a + q * a1, p * b + q * b1 + d, d1 = a // b, a1 // b1 while d == d1: yield d - a, a1 = 10*(a % b), 10*(a1 % b1) - d, d1 = a//b, a1//b1 + a, a1 = 10 * (a % b), 10 * (a1 % b1) + d, d1 = a // b, a1 // b1 def _precompute(self, how_many=1000): """ @@ -790,7 +794,7 @@ def _eval(self, n): """ while len(self._b) <= n: self._precompute() - return self._b[n-1] + return self._b[n - 1] def list(self, n): """ @@ -799,7 +803,7 @@ def list(self, n): sage: sloane.A000796.list(10) [3, 1, 4, 1, 5, 9, 2, 6, 5, 3] """ - self._eval(n) # force computation + self._eval(n) # force computation return self._b[:n] @@ -908,10 +912,10 @@ def _eval(self, n): [1, 1, 1, 1, 2, 1, 1, 3, 3, 1] """ m = 0 - while m*(m+1)//2 <= n: + while m * (m + 1) // 2 <= n: m += 1 m -= 1 - k = n - m*(m+1)//2 + k = n - m * (m + 1) // 2 return arith.binomial(m, k) @@ -979,7 +983,7 @@ def s(self, n, k): sage: sloane.A008275.s(5,3) 35 """ - return (-1)**(n-k) * combinat.stirling_number1(n, k) + return (-1) ** (n - k) * combinat.stirling_number1(n, k) def _eval(self, n): """ @@ -989,9 +993,9 @@ def _eval(self, n): [1, -1, 1, 2, -3, 1, -6, 11, -6, 1] """ m = 0 - while m*(m+1)//2 < n: + while m * (m + 1) // 2 < n: m += 1 - k = n - m*(m-1)//2 + k = n - m * (m - 1) // 2 return self.s(m, k) # (-1)**(m-k) * combinat.stirling_number1(m,k) @@ -1064,9 +1068,9 @@ def _eval(self, n): [1, 1, 1, 1, 3, 1, 1, 7, 6, 1] """ m = 0 - while m*(m+1)//2 < n: + while m * (m + 1) // 2 < n: m += 1 - k = n - m*(m-1)//2 + k = n - m * (m - 1) // 2 return self.s2(m, k) # combinat.stirling_number2(m,k) @@ -1125,14 +1129,14 @@ def _eval(self, n): [1, 0, 1, -1, 0, 1, 0, -2, 0, 1] """ m = 0 - while m*(m+1)//2 <= n: + while m * (m + 1) // 2 <= n: m += 1 m -= 1 - k = n - m*(m+1)//2 - if (m+k) % 2: + k = n - m * (m + 1) // 2 + if (m + k) % 2: return ZZ(0) - sign = (-1)**((m+k)//2 + k) - return sign * arith.binomial((m+k)//2, k) + sign = (-1) ** ((m + k) // 2 + k) + return sign * arith.binomial((m + k) // 2, k) class A000010(SloaneSequence): @@ -1196,6 +1200,7 @@ def _eval(self, n): """ return arith.euler_phi(n) + # Theme: simple functions @@ -1298,7 +1303,7 @@ def _eval(self, n): sage: [sloane.A005843._eval(n) for n in range(10)] [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] """ - return ZZ(2*n) + return ZZ(2 * n) class A000035(SloaneSequence): @@ -1405,7 +1410,7 @@ def _eval(self, n): sage: [sloane.A000169._eval(n) for n in range(1,11)] [1, 2, 9, 64, 625, 7776, 117649, 2097152, 43046721, 1000000000] """ - return ZZ(n**(n-1)) + return ZZ(n ** (n - 1)) class A000272(SloaneSequence): @@ -1673,7 +1678,7 @@ def _eval(self, n): sage: [sloane.A000326._eval(n) for n in range(10)] [0, 1, 5, 12, 22, 35, 51, 70, 92, 117] """ - return ZZ(n * (3*n-1) // 2) + return ZZ(n * (3 * n - 1) // 2) class A002378(SloaneSequence): @@ -1726,7 +1731,7 @@ def _eval(self, n): sage: [sloane.A002378._eval(n) for n in range(10)] [0, 2, 6, 12, 20, 30, 42, 56, 72, 90] """ - return ZZ(n * (n+1)) + return ZZ(n * (n + 1)) class A002620(SloaneSequence): @@ -1831,7 +1836,7 @@ def _eval(self, n): sage: [sloane.A005408._eval(n) for n in range(10)] [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] """ - return ZZ(2*n + 1) + return ZZ(2 * n + 1) class A000012(SloaneSequence): @@ -2041,7 +2046,7 @@ def _eval(self, n): sage: [sloane.A000069._eval(n) for n in range(10)] [1, 2, 4, 7, 8, 11, 13, 14, 16, 19] """ - return ZZ(2*n + 1) - sloane.A010060(n) + return ZZ(2 * n + 1) - sloane.A010060(n) class A001969(SloaneSequence): @@ -2092,7 +2097,7 @@ def _eval(self, n): sage: [sloane.A001969._eval(n) for n in range(10)] [0, 3, 5, 6, 9, 10, 12, 15, 17, 18] """ - return ZZ(2*n) + sloane.A010060(n) + return ZZ(2 * n) + sloane.A010060(n) class A000290(SloaneSequence): @@ -2143,7 +2148,7 @@ def _eval(self, n): sage: [sloane.A000290._eval(n) for n in range(10)] [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] """ - return ZZ(n ** 2) + return ZZ(n**2) class A000225(SloaneSequence): @@ -2311,8 +2316,7 @@ def _eval(self, n): """ if n == 0: return ZZ.one() - return ZZ(sum((i % 2) * arith.euler_phi(i) * 2**(n//i) / (2*n) - for i in arith.divisors(n))) + return ZZ(sum((i % 2) * arith.euler_phi(i) * 2 ** (n // i) / (2 * n) for i in arith.divisors(n))) class A000032(SloaneSequence): @@ -2371,7 +2375,7 @@ def _eval(self, n): return ZZ(2) if n == 1: return ZZ.one() - return sloane.A000045(n+1) + sloane.A000045(n-1) + return sloane.A000045(n + 1) + sloane.A000045(n - 1) # Theme numbers as strings of digits @@ -2488,8 +2492,7 @@ def _precompute(self, how_many=150): except AttributeError: self._b = [] self._n = self.offset - self._b += [i for i in range(self._n, self._n + how_many) - if sloane.A004086(i) == i] + self._b += [i for i in range(self._n, self._n + how_many) if sloane.A004086(i) == i] self._n += how_many def _eval(self, n): @@ -2578,7 +2581,7 @@ def _eval(self, n): """ if n < 10: return n - return self(n//10) + return self(n // 10) # Theme: primes and factoring @@ -2688,7 +2691,7 @@ def _precompute(self, how_many=150): sage: len(sloane.A002808._b) - initial > 0 True """ - self._b += [i for i in range(self._n, self._n+how_many) if not arith.is_prime(i)] + self._b += [i for i in range(self._n, self._n + how_many) if not arith.is_prime(i)] self._n += how_many def _eval(self, n): @@ -2699,7 +2702,7 @@ def _eval(self, n): [4, 6, 8, 9, 10, 12, 14, 15, 16, 18] """ try: - return self._b[n-1] + return self._b[n - 1] except (AttributeError, IndexError): self._precompute() # try again @@ -2830,12 +2833,10 @@ def _eval(self, n): [2, 3, 5, 7, 13, 17, 19, 31, 61, 89] """ try: - return ZZ(self._b[n-1]) + return ZZ(self._b[n - 1]) except (AttributeError, IndexError): - self._b = [2,3,5,7,13,17,19,31,61,89,107,127,521,607,1279,2203,2281,3217,4253, - 4423,9689,9941,11213,19937,21701,23209,44497,86243,110503,132049, - 216091,756839,859433,1257787,1398269,2976221,3021377,6972593,13466917] - return ZZ(self._b[n-1]) + self._b = [2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127, 521, 607, 1279, 2203, 2281, 3217, 4253, 4423, 9689, 9941, 11213, 19937, 21701, 23209, 44497, 86243, 110503, 132049, 216091, 756839, 859433, 1257787, 1398269, 2976221, 3021377, 6972593, 13466917] + return ZZ(self._b[n - 1]) class A000668(SloaneSequence): @@ -2907,7 +2908,7 @@ def _eval(self, n): 2305843009213693951, 618970019642690137449562111] """ - return ZZ(2**sloane.A000043(n) - 1) + return ZZ(2 ** sloane.A000043(n) - 1) class A000396(SloaneSequence): @@ -2961,7 +2962,7 @@ def _eval(self, n): [6, 28, 496, 8128, 33550336] """ p = sloane.A000043(n) - return ZZ(2**(p-1) * (2**p - 1)) + return ZZ(2 ** (p - 1) * (2**p - 1)) class A005100(SloaneSequence): @@ -3018,7 +3019,7 @@ def _precompute(self, how_many=150): sage: len(sloane.A005100._b) - initial > 0 True """ - self._b += [i for i in range(self._n, self._n+how_many) if arith.sigma(i) < 2*i] + self._b += [i for i in range(self._n, self._n + how_many) if arith.sigma(i) < 2 * i] self._n += how_many def _eval(self, n): @@ -3029,7 +3030,7 @@ def _eval(self, n): [1, 2, 3, 4, 5, 7, 8, 9, 10] """ try: - return self._b[n-1] + return self._b[n - 1] except (AttributeError, IndexError): self._precompute() # try again @@ -3108,7 +3109,7 @@ def _precompute(self, how_many=150): sage: len(sloane.A005101._b) - initial > 0 True """ - self._b += [i for i in range(self._n, self._n+how_many) if arith.sigma(i) > 2*i] + self._b += [i for i in range(self._n, self._n + how_many) if arith.sigma(i) > 2 * i] self._n += how_many def _eval(self, n): @@ -3119,7 +3120,7 @@ def _eval(self, n): [12, 18, 20, 24, 30, 36, 40, 42, 48, 54] """ try: - return self._b[n-1] + return self._b[n - 1] except (AttributeError, IndexError): self._precompute() # try again @@ -3301,7 +3302,7 @@ def _eval(self, n): sage: [sloane.A064553._eval(n) for n in range(1,11)] [1, 2, 3, 4, 4, 6, 5, 8, 9, 8] """ - return prod([(prime_pi(p)+1)**e for p, e in arith.factor(n)]) + return prod([(prime_pi(p) + 1) ** e for p, e in arith.factor(n)]) class A001055(SloaneSequence): @@ -3438,7 +3439,7 @@ def _eval(self, n): """ if n == 1: return ZZ.one() - return max(p for p,_ in arith.factor(n)) + return max(p for p, _ in arith.factor(n)) class A000961(SloaneSequence): @@ -3493,7 +3494,7 @@ def _precompute(self, how_many=150): sage: len(sloane.A000961._b) - initial > 0 True """ - self._b += [i for i in range(self._n, self._n+how_many) if len([p for p,_ in arith.factor(i)]) == 1] + self._b += [i for i in range(self._n, self._n + how_many) if len([p for p, _ in arith.factor(i)]) == 1] self._n += how_many def _eval(self, n): @@ -3504,7 +3505,7 @@ def _eval(self, n): [1, 2, 3, 4, 5, 7, 8, 9, 11, 13] """ try: - return self._b[n-1] + return self._b[n - 1] except (AttributeError, IndexError): self._precompute() # try again @@ -3580,8 +3581,7 @@ def _precompute(self, how_many=150): sage: len(sloane.A005117._b) - initial > 0 True """ - self._b += [i for i in range(self._n, self._n+how_many) - if max(e for _, e in arith.factor(i)) <= 1] + self._b += [i for i in range(self._n, self._n + how_many) if max(e for _, e in arith.factor(i)) <= 1] self._n += how_many def _eval(self, n): @@ -3592,7 +3592,7 @@ def _eval(self, n): [1, 2, 3, 5, 6, 7, 10, 11, 13, 14] """ try: - return self._b[n-1] + return self._b[n - 1] except (AttributeError, IndexError): self._precompute() # try again @@ -3668,7 +3668,7 @@ def _precompute(self, how_many=50): sage: len(sloane.A020639._b) - initial == 10 True """ - self._b += [min(p for p,_ in arith.factor(i)) for i in range(self._n, self._n+how_many)] + self._b += [min(p for p, _ in arith.factor(i)) for i in range(self._n, self._n + how_many)] self._n += how_many def _eval(self, n): @@ -3679,7 +3679,7 @@ def _eval(self, n): [1, 2, 3, 2, 5, 2, 7, 2, 3, 2] """ try: - return self._b[n-self.offset] + return self._b[n - self.offset] except (AttributeError, IndexError): self._precompute() # try again @@ -3753,6 +3753,7 @@ def _eval(self, n): [1, 2, 3, 5, 7, 11, 15, 22, 30, 42] """ from sage.combinat.partition import Partitions + return Partitions(n).cardinality() @@ -3836,7 +3837,7 @@ def fib(self): x, y = ZZ.zero(), ZZ.one() yield x while True: - x, y = y, x+y + x, y = y, x + y yield x def _eval(self, n): @@ -3857,7 +3858,7 @@ def list(self, n): sage: sloane.A000045.list(10) [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] """ - self._eval(n) # force computation + self._eval(n) # force computation return self._b[:n] @@ -3964,7 +3965,7 @@ def _eval(self, n): sage: [sloane.A001006._eval(n) for n in range(10)] [1, 1, 2, 4, 9, 21, 51, 127, 323, 835] """ - return sum((-1)**(n-k)*arith.binomial(n, k)*sloane.A000108(k+1) for k in range(n+1)) + return sum((-1) ** (n - k) * arith.binomial(n, k) * sloane.A000108(k + 1) for k in range(n + 1)) class A000079(SloaneSequence): @@ -4015,7 +4016,7 @@ def _eval(self, n): sage: [sloane.A000079._eval(n) for n in range(10)] [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] """ - return ZZ(2 ** n) + return ZZ(2**n) class A000578(SloaneSequence): @@ -4068,7 +4069,7 @@ def _eval(self, n): sage: [sloane.A000578._eval(n) for n in range(10)] [0, 1, 8, 27, 64, 125, 216, 343, 512, 729] """ - return ZZ(n ** 3) + return ZZ(n**3) class A000244(SloaneSequence): @@ -4172,7 +4173,7 @@ def _eval(self, n): sage: [sloane.A000302._eval(n) for n in range(10)] [1, 4, 16, 64, 256, 1024, 4096, 16384, 65536, 262144] """ - return ZZ(4 ** n) + return ZZ(4**n) class A000583(SloaneSequence): @@ -4225,7 +4226,7 @@ def _eval(self, n): sage: [sloane.A000583._eval(n) for n in range(10)] [0, 1, 16, 81, 256, 625, 1296, 2401, 4096, 6561] """ - return ZZ(n ** 4) + return ZZ(n**4) class A000142(SloaneSequence): @@ -4330,8 +4331,7 @@ def _eval(self, n): sage: [sloane.A000085._eval(n) for n in range(10)] [1, 1, 2, 4, 10, 26, 76, 232, 764, 2620] """ - return sum(arith.factorial(n) // (arith.factorial(n-2*k) * (2**k) * arith.factorial(k)) - for k in range(n//2+1)) + return sum(arith.factorial(n) // (arith.factorial(n - 2 * k) * (2**k) * arith.factorial(k)) for k in range(n // 2 + 1)) class A001189(SloaneSequence): @@ -4440,8 +4440,7 @@ def _eval(self, n): # a(n) = Sum from k=1 to n of k! StirlingS2(n, k) if n == 0: return ZZ.one() - return sum(arith.factorial(k) * combinat.stirling_number2(n, k) - for k in range(1, n+1)) + return sum(arith.factorial(k) * combinat.stirling_number2(n, k) for k in range(1, n + 1)) class A006318(SloaneSequence): @@ -4494,8 +4493,8 @@ def _eval(self, n): """ if n == 0: return ZZ.one() -# (PARI) a(n)=if(n<1, 1, sum(k=0, n, 2^k*binomial(n, k)*binomial(n, k-1))/n) - return ZZ(sum(2**k * arith.binomial(n, k) * arith.binomial(n, k-1) for k in range(n+1)) // n) + # (PARI) a(n)=if(n<1, 1, sum(k=0, n, 2^k*binomial(n, k)*binomial(n, k-1))/n) + return ZZ(sum(2**k * arith.binomial(n, k) * arith.binomial(n, k - 1) for k in range(n + 1)) // n) class A000165(SloaneSequence): @@ -4598,7 +4597,7 @@ def _eval(self, n): sage: [sloane.A001147._eval(n) for n in range(10)] [1, 1, 3, 15, 105, 945, 10395, 135135, 2027025, 34459425] """ - return arith.factorial(2*n) / (arith.factorial(n)*2**n) + return arith.factorial(2 * n) / (arith.factorial(n) * 2**n) class A006882(SloaneSequence): @@ -4675,8 +4674,8 @@ def df(self): y = x yield x while True: - k = k+1 - x, y = y, k*x + k = k + 1 + x, y = y, k * x yield x def _eval(self, n): @@ -4697,7 +4696,7 @@ def list(self, n): sage: sloane.A006882.list(10) [1, 1, 2, 3, 8, 15, 48, 105, 384, 945] """ - self._eval(n) # force computation + self._eval(n) # force computation return self._b[:n] @@ -4798,7 +4797,7 @@ def _eval(self, n): sage: [sloane.A001405._eval(n) for n in range(10)] [1, 1, 2, 3, 6, 10, 20, 35, 70, 126] """ - return arith.binomial(n, n//2) + return arith.binomial(n, n // 2) class A000292(SloaneSequence): @@ -4848,7 +4847,7 @@ def _eval(self, n): sage: [sloane.A000292._eval(n) for n in range(10)] [0, 1, 4, 10, 20, 35, 56, 84, 120, 165] """ - return ZZ(n * (n+1) * (n+2) // 6) # or arith.binomial(n+2,3)) + return ZZ(n * (n + 1) * (n + 2) // 6) # or arith.binomial(n+2,3)) class A000330(SloaneSequence): @@ -4902,12 +4901,13 @@ def _eval(self, n): sage: [sloane.A000330._eval(n) for n in range(10)] [0, 1, 5, 14, 30, 55, 91, 140, 204, 285] """ - return ZZ(n * (n+1) * (2*n+1) // 6) + return ZZ(n * (n + 1) * (2 * n + 1) // 6) # Theme: maximal permanent of an m x n (0,1)- matrix: # Seok-Zun Song et al. Extremes of permanents of (0,1)-matrices, p. 201-202. + class ExtremesOfPermanentsSequence(SloaneSequence): def _precompute(self, how_many=20): """ @@ -4938,8 +4938,8 @@ def gen(self, a0, a1, d): k = self._k yield x while True: - k = k+1 - x, y = y, (k)*y+(k-d)*x + k = k + 1 + x, y = y, (k) * y + (k - d) * x yield x def _eval(self, n): @@ -4960,8 +4960,9 @@ def list(self, n): sage: sloane.A000153.list(8) [0, 1, 2, 7, 32, 181, 1214, 9403] """ - self._eval(n) # force computation + self._eval(n) # force computation return self._b[:n] + _k = 1 @@ -5258,9 +5259,10 @@ def gen(self, a0, a1, d): k = self._k yield x while True: - k = k+1 - x, y = y, (k-self._k1)*x+(k+d-self._k2)*y + k = k + 1 + x, y = y, (k - self._k1) * x + (k + d - self._k2) * y yield x + _k1 = 1 _k2 = 1 @@ -5458,7 +5460,7 @@ def _eval(self, n): """ if n == 1: return ZZ(3) - return sloane.A000153(n+1) + sloane.A000153(n) + return sloane.A000153(n + 1) + sloane.A000153(n) class A090013(SloaneSequence): @@ -5529,7 +5531,7 @@ def _eval(self, n): """ if n == 1: return ZZ(4) - return sloane.A000261(n+2) + sloane.A000261(n+1) + return sloane.A000261(n + 2) + sloane.A000261(n + 1) class A090014(SloaneSequence): @@ -5600,7 +5602,7 @@ def _eval(self, n): """ if n == 1: return ZZ(5) - return sloane.A001909(n+3) + sloane.A001909(n+2) + return sloane.A001909(n + 3) + sloane.A001909(n + 2) class A090015(SloaneSequence): @@ -5671,7 +5673,7 @@ def _eval(self, n): """ if n == 1: return ZZ(6) - return sloane.A001910(n+4) + sloane.A001910(n+3) + return sloane.A001910(n + 4) + sloane.A001910(n + 3) class A090016(SloaneSequence): @@ -5744,7 +5746,7 @@ def _eval(self, n): """ if n == 1: return ZZ(7) - return sloane.A090010(n-1) + sloane.A090010(n) + return sloane.A090010(n - 1) + sloane.A090010(n) class A000166(SloaneSequence): @@ -6030,7 +6032,7 @@ def _eval(self, n): return ZZ.one() if n == 2: return 3 - return sloane.A000045(n+1) + sloane.A000045(n-1) + return sloane.A000045(n + 1) + sloane.A000045(n - 1) class A000217(SloaneSequence): @@ -6081,7 +6083,7 @@ def _eval(self, n): sage: [sloane.A000217._eval(n) for n in range(10)] [0, 1, 3, 6, 10, 15, 21, 28, 36, 45] """ - return ZZ(n*(n+1)//2) + return ZZ(n * (n + 1) // 2) class A000124(SloaneSequence): @@ -6136,7 +6138,7 @@ def _eval(self, n): sage: [sloane.A000124._eval(n) for n in range(10)] [1, 2, 4, 7, 11, 16, 22, 29, 37, 46] """ - return ZZ(n*(n+1)//2 + 1) + return ZZ(n * (n + 1) // 2 + 1) class A002275(SloaneSequence): @@ -6188,7 +6190,7 @@ def _eval(self, n): sage: [sloane.A002275._eval(n) for n in range(10)] [0, 1, 11, 111, 1111, 11111, 111111, 1111111, 11111111, 111111111] """ - return ZZ(10**n-1)//9 + return ZZ(10**n - 1) // 9 # inhomogeneous second order recurrences @@ -6211,8 +6213,8 @@ def recur_gen2b(a0, a1, a2, a3, b): n = 1 yield x while True: - n = n+1 - x, y = y, a3*x+a2*y + b(n) + n = n + 1 + x, y = y, a3 * x + a2 * y + b(n) yield x @@ -6251,7 +6253,7 @@ def list(self, n): sage: sloane.A001110.list(8) [0, 1, 36, 1225, 41616, 1413721, 48024900, 1631432881] """ - self._eval(n) # force computation + self._eval(n) # force computation return self._b[:n] @@ -6347,7 +6349,7 @@ def __init__(self): - Jaap Spies (2007-01-19) """ SloaneSequence.__init__(self, offset=0) - self._params = (1,10,2,1,self.g) + self._params = (1, 10, 2, 1, self.g) self._b = [] self._precompute(2) @@ -6370,7 +6372,7 @@ def g(self, k): 0 """ if k > 1: - return 7*k+1 + return 7 * k + 1 return ZZ.zero() @@ -6490,7 +6492,7 @@ def _eval(self, n): sage: [sloane.A001222._eval(n) for n in range(1,10)] [0, 1, 1, 2, 1, 2, 1, 3, 2] """ - return sum(e for i,e in arith.factor(n)) + return sum(e for i, e in arith.factor(n)) # A046660() = A001222(n) - A001221(n) @@ -6672,8 +6674,7 @@ def _precompute(self, how_many=150): except AttributeError: self._b = [] self._n = 1 - self._b += [i for i in range(self._n, self._n + how_many) - if sum(e for _, e in arith.factor(i)) == 2] + self._b += [i for i in range(self._n, self._n + how_many) if sum(e for _, e in arith.factor(i)) == 2] self._n += how_many def _eval(self, n): @@ -6684,7 +6685,7 @@ def _eval(self, n): [4, 6, 9, 10, 14, 15, 21, 22, 25] """ try: - return self._b[n-1] + return self._b[n - 1] except (AttributeError, IndexError): self._precompute() # try again @@ -6790,6 +6791,7 @@ def _powerful_numbers_in_range(self, n, m): n = max(n, 4) # Use PARI directly -- much faster. from sage.libs.pari import pari + L = pari('v=listcreate(); for(i=%s,%s,if(vecmin(factor(i)[,2])>1,listput(v,i))); v' % (n, m)) return [ZZ(x) for x in L] # not very many, so not much overhead @@ -6801,7 +6803,7 @@ def _eval(self, n): [1, 4, 8, 9, 16, 25, 27, 32, 36] """ try: - return self._b[n-1] + return self._b[n - 1] except AttributeError: self._b = [1] except IndexError: @@ -6931,8 +6933,7 @@ def _precompute(self, how_many=150): except AttributeError: self._b = [] self._n = self.offset - self._b += [i for i in range(self._n, self._n + how_many) - if arith.euler_phi(2 * i - 1) < arith.euler_phi(2 * i)] + self._b += [i for i in range(self._n, self._n + how_many) if arith.euler_phi(2 * i - 1) < arith.euler_phi(2 * i)] self._n += how_many def _eval(self, n): @@ -6943,7 +6944,7 @@ def _eval(self, n): [53, 83, 158, 263, 293, 368, 578, 683, 743] """ try: - return self._b[n-1] + return self._b[n - 1] except (AttributeError, IndexError): self._precompute() # try again @@ -6986,8 +6987,8 @@ def recur_gen2(a0, a1, a2, a3): n = 0 yield x while True: - n = n+1 - x, y = y, a3*x+a2*y + n = n + 1 + x, y = y, a3 * x + a2 * y yield x @@ -7029,7 +7030,7 @@ def list(self, n): sage: sloane.A001906.list(10) [0, 1, 3, 8, 21, 55, 144, 377, 987, 2584] """ - self._eval(n) # force computation + self._eval(n) # force computation return self._b[:n] @@ -7065,7 +7066,7 @@ def __init__(self): - Jaap Spies (2007-01-19) """ SloaneSequence.__init__(self, offset=0) - self._params = (0,1,3,-1) + self._params = (0, 1, 3, -1) self._b = [] self._precompute(2) # force precomputation @@ -7115,7 +7116,7 @@ def __init__(self): """ SloaneSequence.__init__(self, offset=0) self._b = [] - self._params = (1,1,2,1) + self._params = (1, 1, 2, 1) self._precompute(2) # force precomputation def _repr_(self): @@ -7160,7 +7161,7 @@ def __init__(self): - Jaap Spies (2007-01-26) """ SloaneSequence.__init__(self, offset=0) - self._params = (0,1,1,2) + self._params = (0, 1, 1, 2) self._b = [] self._precompute(2) # force precomputation @@ -7210,7 +7211,7 @@ def __init__(self): """ SloaneSequence.__init__(self, offset=0) self._b = [] - self._params = (0,1,2,1) + self._params = (0, 1, 2, 1) self._precompute(2) # force precomputation def _repr_(self): @@ -7260,7 +7261,7 @@ def __init__(self): - Jaap Spies (2007-01-24) """ SloaneSequence.__init__(self, offset=0) - self._params = (0,1,6,-1) + self._params = (0, 1, 6, -1) self._b = [] self._precompute(2) # force precomputation @@ -7306,7 +7307,7 @@ def __init__(self): - Jaap Spies (2007-01-19) """ SloaneSequence.__init__(self, offset=0) - self._params = (0,1,3,4) + self._params = (0, 1, 3, 4) self._b = [] self._precompute(2) @@ -7352,7 +7353,7 @@ def __init__(self): - Jaap Spies (2007-01-19) """ SloaneSequence.__init__(self, offset=0) - self._params = (0,1,3,5) + self._params = (0, 1, 3, 5) self._b = [] self._precompute(2) @@ -7401,7 +7402,7 @@ def __init__(self): """ SloaneSequence.__init__(self, offset=0) self._b = [] - self._params = (0,1,4,3) + self._params = (0, 1, 4, 3) self._precompute(2) def _repr_(self): @@ -7450,7 +7451,7 @@ def __init__(self): - Jaap Spies (2007-01-19) """ SloaneSequence.__init__(self, offset=0) - self._params = (0,1,4,5) + self._params = (0, 1, 4, 5) self._b = [] self._precompute(2) @@ -7501,7 +7502,7 @@ def __init__(self): """ SloaneSequence.__init__(self, offset=0) self._b = [] - self._params = (0,1,6,5) + self._params = (0, 1, 6, 5) self._precompute(2) def _repr_(self): @@ -7577,7 +7578,7 @@ def __init__(self): """ SloaneSequence.__init__(self, offset=0) self._b = [] - self._params = (407389224418,76343678551,1,1) + self._params = (407389224418, 76343678551, 1, 1) self._precompute(2) def _repr_(self): @@ -7634,7 +7635,7 @@ def __init__(self): """ SloaneSequence.__init__(self, offset=0) self._b = [] - self._params = (1786772701928802632268715130455793,1059683225053915111058165141686995,1,1) + self._params = (1786772701928802632268715130455793, 1059683225053915111058165141686995, 1, 1) self._precompute(2) def _repr_(self): @@ -7683,7 +7684,7 @@ def __init__(self): """ SloaneSequence.__init__(self, offset=0) self._b = [] - self._params = (331635635998274737472200656430763,1510028911088401971189590305498785,1,1) + self._params = (331635635998274737472200656430763, 1510028911088401971189590305498785, 1, 1) self._precompute(2) def _repr_(self): @@ -7738,7 +7739,7 @@ def __init__(self): """ SloaneSequence.__init__(self, offset=0) self._b = [] - self._params = (62638280004239857,49463435743205655,1,1) + self._params = (62638280004239857, 49463435743205655, 1, 1) self._precompute(2) def _repr_(self): @@ -7790,7 +7791,7 @@ def __init__(self): """ SloaneSequence.__init__(self, offset=0) self._b = [] - self._params = (20615674205555510, 3794765361567513,1,1) + self._params = (20615674205555510, 3794765361567513, 1, 1) self._precompute(2) def _repr_(self): @@ -7838,7 +7839,7 @@ def __init__(self): """ SloaneSequence.__init__(self, offset=0) - keyword = ["sign", "easy","nice"] + keyword = ["sign", "easy", "nice"] def _repr_(self): """ @@ -7860,7 +7861,7 @@ def _eval(self, n): return ZZ.one() if n == 1: return 2 - return (-1)**(n-1)*sloane.A000204(n-1) + return (-1) ** (n - 1) * sloane.A000204(n - 1) # a group of sequences uses this function: @@ -7882,7 +7883,7 @@ def recur_gen3(a0, a1, a2, a3, a4, a5): x, y, z = ZZ(a0), ZZ(a1), ZZ(a2) yield x while True: - x, y, z = y, z, a5*x+a4*y+a3*z + x, y, z = y, z, a5 * x + a4 * y + a3 * z yield x @@ -7942,7 +7943,7 @@ def _precompute(self, how_many=20): try: f = self._f except AttributeError: - self._f = recur_gen3(1,1,1,1,1,1) + self._f = recur_gen3(1, 1, 1, 1, 1, 1) f = self._f self._b += [next(f) for i in range(how_many)] @@ -7964,7 +7965,7 @@ def list(self, n): sage: sloane.A000213.list(10) [1, 1, 1, 3, 5, 9, 17, 31, 57, 105] """ - self._eval(n) # force computation + self._eval(n) # force computation return self._b[:n] @@ -8024,7 +8025,7 @@ def _precompute(self, how_many=20): try: f = self._f except AttributeError: - self._f = recur_gen3(0,0,1,1,1,1) + self._f = recur_gen3(0, 0, 1, 1, 1, 1) f = self._f self._b += [next(f) for i in range(how_many)] @@ -8046,7 +8047,7 @@ def list(self, n): sage: sloane.A000073.list(10) [0, 0, 1, 1, 2, 4, 7, 13, 24, 44] """ - self._eval(n) # force computation + self._eval(n) # force computation return self._b[:n] @@ -8382,8 +8383,7 @@ def _precompute(self, how_many=150): except AttributeError: self._b = [] self._n = 1 - self._b += [i for i in range(self._n, self._n + how_many) - if self.is_number_of_the_third_kind(i)] + self._b += [i for i in range(self._n, self._n + how_many) if self.is_number_of_the_third_kind(i)] self._n += how_many def _eval(self, n): @@ -8394,7 +8394,7 @@ def _eval(self, n): [6, 9, 10, 12, 14, 15, 18, 20, 21, 22] """ try: - return self._b[n-1] + return self._b[n - 1] except (AttributeError, IndexError): self._precompute() # try again @@ -8615,7 +8615,7 @@ def _eval(self, n): for d in srange(3, n, 2): if n % d == 0: - return min(d, 2*n//d) + return min(d, 2 * n // d) class ExponentialNumbers(SloaneSequence): @@ -8653,6 +8653,7 @@ def _eval(self, n): if n < self.__n: return self.__data[n] from sage.combinat.expnums import expnums + self.__data = expnums(n + 1, self.a) self.__n = n + 1 return self.__data[n] @@ -8816,8 +8817,7 @@ def _eval(self, n): """ if n <= 2: return ZZ.zero() - return sum(sloane.A000045(i + 1) * sloane.A000073(n - i - 1) - for i in range(n - 2)) + return sum(sloane.A000045(i + 1) * sloane.A000073(n - i - 1) for i in range(n - 2)) ############################################################# @@ -8825,6 +8825,7 @@ def _eval(self, n): # objects are members. ############################################################# + class Sloane(SageObject): r""" A collection of Sloane generating functions. @@ -8881,8 +8882,7 @@ def __dir__(self): return self.__stored_dir except AttributeError: xs = inspect.getmembers(sys.modules[__name__], inspect.isclass) - self.__stored_dir = [n for n, c in xs - if n.startswith('A') and issubclass(c, SloaneSequence)] + self.__stored_dir = [n for n, c in xs if n.startswith('A') and issubclass(c, SloaneSequence)] return self.__stored_dir def __getattribute__(self, name): diff --git a/src/sage/combinat/specht_module.py b/src/sage/combinat/specht_module.py index a5e06db60f7..ee38a9b2c64 100644 --- a/src/sage/combinat/specht_module.py +++ b/src/sage/combinat/specht_module.py @@ -45,6 +45,7 @@ class SymmetricGroupRepresentation(Representation_abstract): """ Mixin class for symmetric group (algebra) representations. """ + def __init__(self, SGA): """ Initialize ``self``. @@ -112,13 +113,13 @@ def frobenius_image(self): s[2, 2, 1] + s[3, 1, 1] + 2*s[3, 2] + 2*s[4, 1] + s[5] """ from sage.combinat.sf.sf import SymmetricFunctions + p = SymmetricFunctions(QQ).p() s = SymmetricFunctions(QQ).s() G = self._semigroup CCR = [(elt, elt.cycle_type()) for elt in G.conjugacy_classes_representatives()] B = self.basis() - return s(p.sum(QQ(sum((elt * B[k])[k] for k in B.keys())) / la.centralizer_size() * p[la] - for elt, la in CCR)) + return s(p.sum(QQ(sum((elt * B[k])[k] for k in B.keys())) / la.centralizer_size() * p[la] for elt, la in CCR)) class SpechtModule(SymmetricGroupRepresentation, SubmoduleWithBasis): @@ -192,6 +193,7 @@ class SpechtModule(SymmetricGroupRepresentation, SubmoduleWithBasis): :class:`~sage.combinat.symmetric_group_representations.SpechtRepresentation` for an implementation of the representation by matrices. """ + @staticmethod def __classcall_private__(cls, SGA, D): r""" @@ -243,9 +245,7 @@ def __init__(self, SGA, D): support_order = SGA.get_order() basis = SGA.echelon_form(span_set, False, order=support_order) basis = Family(basis) - SubmoduleWithBasis.__init__(self, basis, support_order, ambient=SGA, - unitriangular=False, category=Mod.Subobjects(), - prefix='S') + SubmoduleWithBasis.__init__(self, basis, support_order, ambient=SGA, unitriangular=False, category=Mod.Subobjects(), prefix='S') def _repr_(self): r""" @@ -311,6 +311,7 @@ def _ascii_art_(self): S """ from sage.typeset.ascii_art import ascii_art + return ascii_art("S", baseline=0) + ascii_art(self._diagram, baseline=-1) def _unicode_art_(self): @@ -339,6 +340,7 @@ def _unicode_art_(self): S """ from sage.typeset.unicode_art import unicode_art + return unicode_art("S", baseline=0) + unicode_art(self._diagram, baseline=-1) class Element(SubmoduleWithBasis.Element): @@ -423,6 +425,7 @@ class TabloidModule(SymmetricGroupRepresentation, CombinatorialFreeModule): sage: IM.basis()[0].lift() == sum(TM.basis()) True """ + @staticmethod def __classcall_private__(cls, SGA, shape): r""" @@ -461,13 +464,13 @@ def __init__(self, SGA, shape): """ from sage.combinat.set_partition_ordered import OrderedSetPartitions from sage.groups.perm_gps.permgroup_named import SymmetricGroup + self._shape = shape n = sum(shape) self._symgp = SymmetricGroup(n) cat = ModulesWithBasis(SGA.base_ring()).FiniteDimensional() tabloids = OrderedSetPartitions(n, shape) - CombinatorialFreeModule.__init__(self, SGA.base_ring(), tabloids, - category=cat, prefix='T', bracket='') + CombinatorialFreeModule.__init__(self, SGA.base_ring(), tabloids, category=cat, prefix='T', bracket='') SymmetricGroupRepresentation.__init__(self, SGA) def _repr_(self): @@ -516,6 +519,7 @@ def _ascii_art_term(self, T): """ # This is basically copied from CombinatorialFreeModule._ascii_art_term from sage.typeset.ascii_art import AsciiArt, ascii_art + pref = AsciiArt([self.prefix()]) tab = "\n".join("{" + ", ".join(str(val) for val in sorted(row)) + "}" for row in T) if not tab: @@ -539,6 +543,7 @@ def _unicode_art_term(self, T): {5} {4} {3} """ from sage.typeset.unicode_art import unicode_art + r = unicode_art(repr(self._ascii_art_term(T))) r._baseline = r._h - 1 return r @@ -576,6 +581,7 @@ def _latex_term(self, T): tab = "\\emptyset" else: from sage.combinat.output import tex_from_array + A = list(map(sorted, T)) tab = str(tex_from_array(A)) tab = tab.replace("|", "") @@ -676,8 +682,7 @@ def _acted_upon_(self, x, self_on_left): if x in P._semigroup_algebra: return P.linear_combination((perm * self, c) for perm, c in x.monomial_coefficients().items()) if x in P._semigroup_algebra.indices(): - return P.element_class(P, {P._symmetric_group_action(T, x): c - for T, c in self._monomial_coefficients.items()}) + return P.element_class(P, {P._symmetric_group_action(T, x): c for T, c in self._monomial_coefficients.items()}) class SpechtModuleTableauxBasis(SpechtModule): @@ -695,6 +700,7 @@ class SpechtModuleTableauxBasis(SpechtModule): - :class:`~sage.combinat.symmetric_group_representations.SpechtRepresentation` for an implementation of the representation by matrices. """ + def __init__(self, ambient): r""" Initialize ``self``. @@ -714,15 +720,11 @@ def __init__(self, ambient): def elt(T): tab = tabloids.element_class(tabloids, list(T), check=False) - return ambient.sum_of_terms((ambient._symmetric_group_action(tab, sigma), sigma.sign()) - for sigma in T.column_stabilizer()) + return ambient.sum_of_terms((ambient._symmetric_group_action(tab, sigma), sigma.sign()) for sigma in T.column_stabilizer()) - basis = Family({T: elt(T) - for T in self._diagram.standard_tableaux()}) + basis = Family({T: elt(T) for T in self._diagram.standard_tableaux()}) cat = ambient.category().Subobjects() - SubmoduleWithBasis.__init__(self, basis, support_order, ambient=ambient, - unitriangular=False, category=cat, - prefix='S', bracket='') + SubmoduleWithBasis.__init__(self, basis, support_order, ambient=ambient, unitriangular=False, category=cat, prefix='S', bracket='') @lazy_attribute def lift(self): @@ -930,6 +932,7 @@ def intrinsic_arrangement(self, base_ring=None): """ from sage.geometry.hyperplane_arrangement.arrangement import HyperplaneArrangements from sage.combinat.set_partition import SetPartitions + if base_ring is None: base_ring = self.base_ring() @@ -953,8 +956,8 @@ def t(i, j): span = [] for a in alpha: a = list(a) - for i in range(len(a)-1): - elt = t(a[i], a[i+1]) + for i in range(len(a) - 1): + elt = t(a[i], a[i + 1]) if elt not in fixed_spaces: fixed_spaces[elt] = self.annihilator_basis([elt - SGA.one()], side='left') span.extend(fixed_spaces[elt]) @@ -991,6 +994,7 @@ class MaximalSpechtSubmodule(SymmetricGroupRepresentation, SubmoduleWithBasis): sage: sum(SGA.basis()) * u 0 """ + def __init__(self, specht_module): r""" Initialize ``self``. @@ -1032,9 +1036,7 @@ def __init__(self, specht_module): unitriangular = all(b.leading_support() == 1 for b in basis) support_order = list(specht_module.basis().keys()) cat = specht_module.category().Subobjects() - SubmoduleWithBasis.__init__(self, basis, support_order, ambient=specht_module, - unitriangular=unitriangular, category=cat, - prefix='U') + SubmoduleWithBasis.__init__(self, basis, support_order, ambient=specht_module, unitriangular=unitriangular, category=cat, prefix='U') def _repr_(self): r""" @@ -1118,6 +1120,7 @@ class SimpleModule(SymmetricGroupRepresentation, QuotientModuleWithBasis): [0 0 2 1] [0 0 1 2] """ + def __init__(self, specht_module): r""" Initialize ``self``. @@ -1198,6 +1201,7 @@ def _to_diagram(D): """ from sage.combinat.integer_vector import IntegerVectors from sage.combinat.skew_partition import SkewPartitions + if isinstance(D, Diagram): return D if D in _Partitions: @@ -1244,6 +1248,7 @@ def specht_module_spanning_set(D, SGA=None): n = len(D) if SGA is None: from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra + SGA = SymmetricGroupAlgebra(QQ, n) elif SGA.group().rank() != n - 1: raise ValueError("the rank does not match the size of the diagram") @@ -1353,6 +1358,7 @@ def tabloid_gram_matrix(la, base_ring): [4 1 1 2 4] """ from sage.combinat.tableau import StandardTableaux + ST = list(StandardTableaux(la)) def bilinear_form(p1, p2): @@ -1392,6 +1398,7 @@ def simple_module_rank(la, base_ring): """ from sage.categories.fields import Fields from sage.combinat.partition import Partition + if base_ring not in Fields(): raise NotImplementedError("the base must be a field") p = base_ring.characteristic() diff --git a/src/sage/combinat/species/all.py b/src/sage/combinat/species/all.py index 4dec3677c5f..a1b3fbd80e6 100644 --- a/src/sage/combinat/species/all.py +++ b/src/sage/combinat/species/all.py @@ -98,15 +98,16 @@ - :ref:`sage.combinat.species.misc` """ + # install the docstring of this module to the containing package from sage.misc.namespace_package import install_doc + install_doc(__package__, __doc__) from sage.misc.lazy_import import lazy_import -lazy_import("sage.combinat.species.recursive_species", "CombinatorialSpecies", - deprecation=(38544, "combinat.species is superseded by LazyCombinatorialSpecies")) -lazy_import("sage.combinat.species", "library", as_='species', - deprecation=(38544, "combinat.species is superseded by LazyCombinatorialSpecies")) +lazy_import("sage.combinat.species.recursive_species", "CombinatorialSpecies", deprecation=(38544, "combinat.species is superseded by LazyCombinatorialSpecies")) + +lazy_import("sage.combinat.species", "library", as_='species', deprecation=(38544, "combinat.species is superseded by LazyCombinatorialSpecies")) del lazy_import del install_doc diff --git a/src/sage/combinat/species/characteristic_species.py b/src/sage/combinat/species/characteristic_species.py index c986e177672..e70537af16e 100644 --- a/src/sage/combinat/species/characteristic_species.py +++ b/src/sage/combinat/species/characteristic_species.py @@ -1,6 +1,7 @@ """ Characteristic species """ + # **************************************************************************** # Copyright (C) 2008 Mike Hansen , # @@ -90,6 +91,7 @@ def automorphism_group(self): Symmetric group of order 3! as a permutation group """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup + return SymmetricGroup(len(self._labels)) @@ -153,7 +155,7 @@ def _structures(self, structure_class, labels): [{1, 2, 3}] """ if len(labels) == self._n: - yield structure_class(self, labels, range(1,self._n+1)) + yield structure_class(self, labels, range(1, self._n + 1)) _isotypes = _structures @@ -227,10 +229,10 @@ def _equation(self, var_mapping): sage: C._equation(var_mapping) z^2 """ - return var_mapping['z']**(self._n) + return var_mapping['z'] ** (self._n) -#Backward compatibility +# Backward compatibility CharacteristicSpecies_class = CharacteristicSpecies @@ -274,7 +276,7 @@ def __init__(self, min=None, max=None, weight=None): self._state_info = [] -#Backward compatibility +# Backward compatibility EmptySetSpecies_class = EmptySetSpecies._cached_constructor = EmptySetSpecies @@ -318,5 +320,5 @@ def __init__(self, min=None, max=None, weight=None): self._state_info = [] -#Backward compatibility +# Backward compatibility SingletonSpecies_class = SingletonSpecies diff --git a/src/sage/combinat/species/composition_species.py b/src/sage/combinat/species/composition_species.py index 7c686a52cea..3e7920ca496 100644 --- a/src/sage/combinat/species/composition_species.py +++ b/src/sage/combinat/species/composition_species.py @@ -1,7 +1,8 @@ """ Composition species """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Mike Hansen , # # Distributed under the terms of the GNU General Public License (GPL) @@ -14,7 +15,7 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from .species import GenericCombinatorialSpecies from .structure import GenericSpeciesStructure from .partition_species import PartitionSpecies @@ -167,6 +168,7 @@ def _structures(self, structure_class, labels): [[1, 2], [1]] """ from itertools import product + P = PartitionSpecies() for pi in P.structures(labels): # The labels of the G-structures will be just be the things diff --git a/src/sage/combinat/species/cycle_species.py b/src/sage/combinat/species/cycle_species.py index f320722d32f..4c723832e79 100644 --- a/src/sage/combinat/species/cycle_species.py +++ b/src/sage/combinat/species/cycle_species.py @@ -33,7 +33,7 @@ def __repr__(self): ('a', 'b', 'c') """ s = GenericSpeciesStructure.__repr__(self) - return "("+s[1:-1]+")" + return "(" + s[1:-1] + ")" def canonical_label(self): """ @@ -44,7 +44,7 @@ def canonical_label(self): ('a', 'b', 'c') """ n = len(self._labels) - return CycleSpeciesStructure(self.parent(), self._labels, range(1, n+1)) + return CycleSpeciesStructure(self.parent(), self._labels, range(1, n + 1)) def permutation_group_element(self): """ @@ -59,6 +59,7 @@ def permutation_group_element(self): (1,2,3) """ from sage.groups.perm_gps.constructor import PermutationGroupElement + return PermutationGroupElement(tuple(self._list)) def transport(self, perm): @@ -101,6 +102,7 @@ def automorphism_group(self): """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup from sage.groups.perm_gps.permgroup import PermutationGroup + S = SymmetricGroup(len(self._labels)) p = self.permutation_group_element() return PermutationGroup(S.centralizer(p).gens()) @@ -165,7 +167,8 @@ def _structures(self, structure_class, labels): [(1, 2, 3), (1, 3, 2)] """ from sage.combinat.permutation import CyclicPermutations - for c in CyclicPermutations(range(1, len(labels)+1)): + + for c in CyclicPermutations(range(1, len(labels) + 1)): yield structure_class(self, labels, c) def _isotypes(self, structure_class, labels): @@ -177,7 +180,7 @@ def _isotypes(self, structure_class, labels): [(1, 2, 3)] """ if len(labels) != 0: - yield structure_class(self, labels, range(1, len(labels)+1)) + yield structure_class(self, labels, range(1, len(labels) + 1)) def _gs_callable(self, base_ring, n): r""" @@ -269,6 +272,7 @@ def _cis_callable(self, base_ring, n): 1/6*p[1, 1, 1, 1, 1, 1] + 1/6*p[2, 2, 2] + 1/3*p[3, 3] + 1/3*p[6]] """ from sage.combinat.sf.sf import SymmetricFunctions + p = SymmetricFunctions(base_ring).power() zero = base_ring.zero() @@ -277,10 +281,10 @@ def _cis_callable(self, base_ring, n): return zero res = zero for k in divisors(n): - res += euler_phi(k)*p([k])**(n//k) + res += euler_phi(k) * p([k]) ** (n // k) res /= n return self._weight * res -#Backward compatibility +# Backward compatibility CycleSpecies_class = CycleSpecies diff --git a/src/sage/combinat/species/empty_species.py b/src/sage/combinat/species/empty_species.py index 992721b4c4b..22631047136 100644 --- a/src/sage/combinat/species/empty_species.py +++ b/src/sage/combinat/species/empty_species.py @@ -1,6 +1,7 @@ """ Empty species """ + # **************************************************************************** # Copyright (C) 2008 Florent Hivert , # diff --git a/src/sage/combinat/species/functorial_composition_species.py b/src/sage/combinat/species/functorial_composition_species.py index 244ac6a2cca..a2038a4fc71 100644 --- a/src/sage/combinat/species/functorial_composition_species.py +++ b/src/sage/combinat/species/functorial_composition_species.py @@ -1,6 +1,7 @@ """ Functorial composition species """ + # **************************************************************************** # Copyright (C) 2008 Mike Hansen , # @@ -138,6 +139,7 @@ def weight_ring(self): Rational Field """ from sage.structure.element import get_coercion_model + cm = get_coercion_model() f_weights = self._F.weight_ring() diff --git a/src/sage/combinat/species/generating_series.py b/src/sage/combinat/species/generating_series.py index 59bf094580d..6af7efaf291 100644 --- a/src/sage/combinat/species/generating_series.py +++ b/src/sage/combinat/species/generating_series.py @@ -339,8 +339,7 @@ def isotype_generating_series(self): """ R = self.base_ring() OGS = OrdinaryGeneratingSeriesRing(R) - return OGS(lambda n: self._ogs_gen(n, self._coeff_stream._approximate_order), - self._coeff_stream._approximate_order) + return OGS(lambda n: self._ogs_gen(n, self._coeff_stream._approximate_order), self._coeff_stream._approximate_order) def _ogs_gen(self, n, ao): """ @@ -372,8 +371,7 @@ def generating_series(self): """ R = self.base_ring() EGS = ExponentialGeneratingSeriesRing(R) - return EGS(lambda n: self._egs_gen(n, self._coeff_stream._approximate_order), - self._coeff_stream._approximate_order) + return EGS(lambda n: self._egs_gen(n, self._coeff_stream._approximate_order), self._coeff_stream._approximate_order) def _egs_gen(self, n, ao): """ @@ -389,7 +387,7 @@ def _egs_gen(self, n, ao): """ if n < ao: return 0 - return self.coefficient(n).coefficient([1]*n) + return self.coefficient(n).coefficient([1] * n) def derivative(self, n=1): r""" @@ -547,6 +545,7 @@ class CycleIndexSeriesRing(LazySymmetricFunctions): sage: R is CycleIndexSeriesRing(QQ) # needs sage.modules True """ + Element = CycleIndexSeries def __init__(self, base_ring, sparse=True): @@ -639,7 +638,7 @@ def _cl_term(n, R=QQ): if n == 1: res = p([1]) elif n > 1: - res = 1/n * ((-1)**(n-1) * p([1])**n - sum(d * p([n // d]).plethysm(_cl_term(d, R)) for d in divisors(n)[:-1])) + res = 1 / n * ((-1) ** (n - 1) * p([1]) ** n - sum(d * p([n // d]).plethysm(_cl_term(d, R)) for d in divisors(n)[:-1])) return res diff --git a/src/sage/combinat/species/library.py b/src/sage/combinat/species/library.py index 292bdd40419..3f1b4df28ce 100644 --- a/src/sage/combinat/species/library.py +++ b/src/sage/combinat/species/library.py @@ -1,6 +1,7 @@ """ Examples of combinatorial species """ + # **************************************************************************** # Copyright (C) 2008 Mike Hansen , # diff --git a/src/sage/combinat/species/linear_order_species.py b/src/sage/combinat/species/linear_order_species.py index 63d85974e11..2b5ce76ffd3 100644 --- a/src/sage/combinat/species/linear_order_species.py +++ b/src/sage/combinat/species/linear_order_species.py @@ -1,6 +1,7 @@ """ Linear-order species """ + # **************************************************************************** # Copyright (C) 2008 Mike Hansen , # @@ -34,7 +35,7 @@ def canonical_label(self): sage: s.canonical_label() ['a', 'b', 'c'] """ - return self.__class__(self.parent(), self._labels, range(1, len(self._labels)+1)) + return self.__class__(self.parent(), self._labels, range(1, len(self._labels) + 1)) def transport(self, perm): """ @@ -67,6 +68,7 @@ def automorphism_group(self): Symmetric group of order 1! as a permutation group """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup + return SymmetricGroup(1) @@ -112,6 +114,7 @@ def _structures(self, structure_class, labels): [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] """ from sage.combinat.permutation import Permutations + for p in Permutations(len(labels)): yield structure_class(self, labels, p._list) @@ -123,7 +126,7 @@ def _isotypes(self, structure_class, labels): sage: L.isotypes([1,2,3]).list() [[1, 2, 3]] """ - yield structure_class(self, labels, range(1, len(labels)+1)) + yield structure_class(self, labels, range(1, len(labels) + 1)) def _gs_list(self, base_ring, n): r""" @@ -163,9 +166,10 @@ def _cis_callable(self, base_ring, n): [p[], p[1], p[1, 1], p[1, 1, 1], p[1, 1, 1, 1]] """ from sage.combinat.sf.sf import SymmetricFunctions + p = SymmetricFunctions(base_ring).power() - return p([1]*n) + return p([1] * n) -#Backward compatibility +# Backward compatibility LinearOrderSpecies_class = LinearOrderSpecies diff --git a/src/sage/combinat/species/misc.py b/src/sage/combinat/species/misc.py index eba85970c9e..173db61f32b 100644 --- a/src/sage/combinat/species/misc.py +++ b/src/sage/combinat/species/misc.py @@ -41,15 +41,12 @@ def change_support(perm, support, change_perm=None): (3,4,5) """ if change_perm is None: - change_perm = prod([PermutationGroupElement((i+1, support[i])) - for i in range(len(support)) - if i+1 != support[i]], - PermutationGroupElement([], SymmetricGroup(support))) + change_perm = prod([PermutationGroupElement((i + 1, support[i])) for i in range(len(support)) if i + 1 != support[i]], PermutationGroupElement([], SymmetricGroup(support))) if isinstance(perm, PermutationGroup_generic): return PermutationGroup([change_support(g, support, change_perm) for g in perm.gens()]) - return change_perm*perm*~change_perm + return change_perm * perm * ~change_perm def accept_size(f): @@ -70,6 +67,7 @@ def accept_size(f): sage: f(size=2) () [('max', 3), ('min', 2)] """ + @wraps(f) def new_func(*args, **kwds): if 'size' in kwds: @@ -79,4 +77,5 @@ def new_func(*args, **kwds): kwds['max'] = kwds['size'] + 1 del kwds['size'] return f(*args, **kwds) + return new_func diff --git a/src/sage/combinat/species/partition_species.py b/src/sage/combinat/species/partition_species.py index 3e0c42d83a2..17b14ac353f 100644 --- a/src/sage/combinat/species/partition_species.py +++ b/src/sage/combinat/species/partition_species.py @@ -42,7 +42,7 @@ def __init__(self, parent, labels, list): True """ list = [SubsetSpeciesStructure(parent, labels, block) if not isinstance(block, SubsetSpeciesStructure) else block for block in list] - list.sort(key=lambda block:(-len(block), block)) + list.sort(key=lambda block: (-len(block), block)) GenericSpeciesStructure.__init__(self, parent, labels, list) def __repr__(self): @@ -54,7 +54,7 @@ def __repr__(self): {{'a', 'b', 'c'}} """ s = GenericSpeciesStructure.__repr__(self) - return "{"+s[1:-1]+"}" + return "{" + s[1:-1] + "}" def canonical_label(self): """ @@ -89,7 +89,7 @@ def transport(self, perm): {{2, 4}, {3}} """ l = [block.transport(perm)._list for block in self._list] - l.sort(key=lambda block:(-len(block), block)) + l.sort(key=lambda block: (-len(block), block)) return PartitionSpeciesStructure(self.parent(), self._labels, l) def automorphism_group(self): @@ -107,8 +107,8 @@ def automorphism_group(self): Permutation Group with generators [(1,2)] """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup - return reduce(lambda a,b: a.direct_product(b, maps=False), - [SymmetricGroup(block._list) for block in self._list]) + + return reduce(lambda a, b: a.direct_product(b, maps=False), [SymmetricGroup(block._list) for block in self._list]) def change_labels(self, labels): """ @@ -179,6 +179,7 @@ def _structures(self, structure_class, labels): [{{1, 2, 3}}, {{1, 3}, {2}}, {{1, 2}, {3}}, {{2, 3}, {1}}, {{1}, {2}, {3}}] """ from sage.combinat.restricted_growth import RestrictedGrowthArrays + n = len(labels) if n == 0: @@ -218,6 +219,7 @@ def _isotypes(self, structure_class, labels): {{1}, {2}, {3}, {4}}] """ from sage.combinat.partition import Partitions + for p in Partitions(len(labels)): yield self._canonical_rep_from_partition(structure_class, labels, p) @@ -233,7 +235,7 @@ def _canonical_rep_from_partition(self, structure_class, labels, p): {{1, 2}, {3}} """ breaks = [sum(p[:i]) for i in range(len(p) + 1)] - return structure_class(self, labels, [list(range(breaks[i]+1, breaks[i+1]+1)) for i in range(len(p))]) + return structure_class(self, labels, [list(range(breaks[i] + 1, breaks[i + 1] + 1)) for i in range(len(p))]) def _gs_callable(self, base_ring, n): r""" @@ -245,6 +247,7 @@ def _gs_callable(self, base_ring, n): [1, 1, 1, 5/6, 5/8] """ from sage.combinat.combinat import bell_number + return self._weight * base_ring(bell_number(n) / factorial(n)) def _itgs_callable(self, base_ring, n): @@ -260,7 +263,8 @@ def _itgs_callable(self, base_ring, n): [1, 1, 2, 3, 5, 7, 11, 15, 22, 30] """ from sage.combinat.partition import number_of_partitions - return self._weight*base_ring(number_of_partitions(n)) + + return self._weight * base_ring(number_of_partitions(n)) def _cis(self, series_ring, base_ring): r""" @@ -288,5 +292,5 @@ def _cis(self, series_ring, base_ring): return res -#Backward compatibility +# Backward compatibility PartitionSpecies_class = PartitionSpecies diff --git a/src/sage/combinat/species/permutation_species.py b/src/sage/combinat/species/permutation_species.py index 1020196bd04..17e60b2a258 100644 --- a/src/sage/combinat/species/permutation_species.py +++ b/src/sage/combinat/species/permutation_species.py @@ -2,7 +2,7 @@ """ Permutation species """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2008 Mike Hansen , # # Distributed under the terms of the GNU General Public License (GPL) @@ -15,7 +15,7 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from .species import GenericCombinatorialSpecies from .structure import GenericSpeciesStructure @@ -76,7 +76,7 @@ def transport(self, perm): ['a', 'd', 'c', 'b'] """ p = self.permutation_group_element() - p = perm*p*~perm + p = perm * p * ~perm return self.__class__(self.parent(), self._labels, p.domain()) def automorphism_group(self): @@ -104,6 +104,7 @@ def automorphism_group(self): """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup from sage.groups.perm_gps.permgroup import PermutationGroup + S = SymmetricGroup(len(self._labels)) p = self.permutation_group_element() return PermutationGroup(S.centralizer(p).gens()) @@ -168,6 +169,7 @@ def _isotypes(self, structure_class, labels): [[2, 3, 1], [2, 1, 3], [1, 2, 3]] """ from sage.combinat.partition import Partitions + if labels == []: yield structure_class(self, labels, []) return @@ -184,8 +186,8 @@ def _canonical_rep_from_partition(self, structure_class, labels, p): ['b', 'a', 'c'] """ indices = list(range(1, len(labels) + 1)) - breaks = [sum(p[:i]) for i in range(len(p)+1)] - cycles = tuple(tuple(indices[breaks[i]:breaks[i+1]]) for i in range(len(p))) + breaks = [sum(p[:i]) for i in range(len(p) + 1)] + cycles = tuple(tuple(indices[breaks[i] : breaks[i + 1]]) for i in range(len(p))) perm = list(Permutation(cycles)) return structure_class(self, labels, perm) @@ -216,6 +218,7 @@ def _itgs_callable(self, base_ring, n): [1, 1, 2, 3, 5, 7, 11, 15, 22, 30] """ from sage.combinat.partition import number_of_partitions + return base_ring(number_of_partitions(n)) def _cis(self, series_ring, base_ring): @@ -239,6 +242,7 @@ def _cis(self, series_ring, base_ring): """ from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.partition import Partitions + p = SymmetricFunctions(base_ring).p() CIS = series_ring return CIS(lambda n: sum(p(la) for la in Partitions(n))) @@ -252,6 +256,7 @@ def _cis_gen(self, base_ring, m, n): [p[], 0, p[2], 0, p[2, 2], 0, p[2, 2, 2], 0, p[2, 2, 2, 2], 0] """ from sage.combinat.sf.sf import SymmetricFunctions + p = SymmetricFunctions(base_ring).power() pn = p([m]) @@ -261,11 +266,11 @@ def _cis_gen(self, base_ring, m, n): if m == 1: if n % 2: return base_ring.zero() - return pn**(n//2) + return pn ** (n // 2) if n % m: return base_ring.zero() - return pn**(n//m) + return pn ** (n // m) -#Backward compatibility +# Backward compatibility PermutationSpecies_class = PermutationSpecies diff --git a/src/sage/combinat/species/product_species.py b/src/sage/combinat/species/product_species.py index ba30ca6d164..3cce2a458da 100644 --- a/src/sage/combinat/species/product_species.py +++ b/src/sage/combinat/species/product_species.py @@ -1,6 +1,7 @@ """ Product species """ + # **************************************************************************** # Copyright (C) 2008 Mike Hansen , # @@ -75,10 +76,7 @@ def transport(self, perm): left_labels = new_subset.label_subset() right_labels = new_subset.complement().label_subset() - return self.__class__(self.parent(), self._labels, - new_subset, - left.change_labels(left_labels), - right.change_labels(right_labels)) + return self.__class__(self.parent(), self._labels, new_subset, left.change_labels(left_labels), right.change_labels(right_labels)) def canonical_label(self): """ @@ -115,10 +113,7 @@ def canonical_label(self): left_labels = new_subset.label_subset() right_labels = new_subset.complement().label_subset() - return self.__class__(self.parent(), self._labels, - new_subset, - left.canonical_label().change_labels(left_labels), - right.canonical_label().change_labels(right_labels)) + return self.__class__(self.parent(), self._labels, new_subset, left.canonical_label().change_labels(left_labels), right.canonical_label().change_labels(right_labels)) def change_labels(self, labels): """ @@ -146,10 +141,7 @@ def change_labels(self, labels): new_subset = self._subset.change_labels(labels) left_labels = new_subset.label_subset() right_labels = new_subset.complement().label_subset() - return self.__class__(self.parent(), labels, - new_subset, - left.change_labels(left_labels), - right.change_labels(right_labels)) + return self.__class__(self.parent(), labels, new_subset, left.change_labels(left_labels), right.change_labels(right_labels)) def automorphism_group(self): """ @@ -311,8 +303,10 @@ def _times_gen(self, structure_class, attr, labels): sage: list(F._times_gen(F._default_structure_class, 'structures',[1,2])) [{}*{1, 2}, {1}*{2}, {2}*{1}, {1, 2}*{}] """ + def c(F, n): return F.generating_series().coefficient(n) + S = SubsetSpecies() for u in getattr(S, attr)(labels): @@ -333,8 +327,7 @@ def _gs(self, series_ring, base_ring): sage: F.generating_series()[0:5] [1, 2, 3, 4, 5] """ - res = (self.left_factor().generating_series(base_ring) * - self.right_factor().generating_series(base_ring)) + res = self.left_factor().generating_series(base_ring) * self.right_factor().generating_series(base_ring) if self.is_weighted(): res = self._weight * res return res @@ -348,8 +341,7 @@ def _itgs(self, series_ring, base_ring): sage: F.isotype_generating_series()[0:5] # needs sage.libs.flint [1, 2, 5, 10, 20] """ - res = (self.left_factor().isotype_generating_series(base_ring) * - self.right_factor().isotype_generating_series(base_ring)) + res = self.left_factor().isotype_generating_series(base_ring) * self.right_factor().isotype_generating_series(base_ring) if self.is_weighted(): res = self._weight * res return res @@ -367,8 +359,7 @@ def _cis(self, series_ring, base_ring): 4*p[1, 1, 1] + 4*p[2, 1] + 2*p[3], 5*p[1, 1, 1, 1] + 6*p[2, 1, 1] + 3*p[2, 2] + 4*p[3, 1] + 2*p[4]] """ - res = (self.left_factor().cycle_index_series(base_ring) * - self.right_factor().cycle_index_series(base_ring)) + res = self.left_factor().cycle_index_series(base_ring) * self.right_factor().cycle_index_series(base_ring) if self.is_weighted(): res = self._weight * res return res @@ -400,9 +391,7 @@ def weight_ring(self): sage: C.weight_ring() Univariate Polynomial Ring in t over Rational Field """ - return self._common_parent([self.left_factor().weight_ring(), - self.right_factor().weight_ring(), - self._weight.parent()]) + return self._common_parent([self.left_factor().weight_ring(), self.right_factor().weight_ring(), self._weight.parent()]) def _equation(self, var_mapping): """ @@ -418,6 +407,7 @@ def _equation(self, var_mapping): [node0 + (-z^2)] """ from sage.misc.misc_c import prod + return prod(var_mapping[operand] for operand in self._state_info) diff --git a/src/sage/combinat/species/recursive_species.py b/src/sage/combinat/species/recursive_species.py index e75d2780f02..5b33a2111a3 100644 --- a/src/sage/combinat/species/recursive_species.py +++ b/src/sage/combinat/species/recursive_species.py @@ -1,6 +1,7 @@ """ Recursive species """ + # **************************************************************************** # Copyright (C) 2008 Mike Hansen , # diff --git a/src/sage/combinat/species/set_species.py b/src/sage/combinat/species/set_species.py index b31522a5ef5..3f207d3c61b 100644 --- a/src/sage/combinat/species/set_species.py +++ b/src/sage/combinat/species/set_species.py @@ -1,6 +1,7 @@ """ Set species """ + # **************************************************************************** # Copyright (C) 2008 Mike Hansen , # @@ -36,7 +37,7 @@ def __repr__(self): {'a', 'b', 'c'} """ s = GenericSpeciesStructure.__repr__(self) - return "{"+s[1:-1]+"}" + return "{" + s[1:-1] + "}" def canonical_label(self): """ @@ -81,7 +82,8 @@ def automorphism_group(self): Symmetric group of order 3! as a permutation group """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup - return SymmetricGroup(max(1,len(self._labels))) + + return SymmetricGroup(max(1, len(self._labels))) class SetSpecies(GenericCombinatorialSpecies, UniqueRepresentation): @@ -129,7 +131,7 @@ def _structures(self, structure_class, labels): [{1, 2, 3}] """ n = len(labels) - yield structure_class(self, labels, range(1,n+1)) + yield structure_class(self, labels, range(1, n + 1)) _isotypes = _structures @@ -182,6 +184,7 @@ def _cis(self, series_ring, base_ring): 1/24*p[1, 1, 1, 1] + 1/4*p[2, 1, 1] + 1/8*p[2, 2] + 1/3*p[3, 1] + 1/4*p[4]] """ from .generating_series import ExponentialCycleIndexSeries + res = ExponentialCycleIndexSeries(base_ring) if self.is_weighted(): @@ -190,5 +193,5 @@ def _cis(self, series_ring, base_ring): return res -#Backward compatibility +# Backward compatibility SetSpecies_class = SetSpecies diff --git a/src/sage/combinat/species/species.py b/src/sage/combinat/species/species.py index e285fb669ef..8b3117ec562 100644 --- a/src/sage/combinat/species/species.py +++ b/src/sage/combinat/species/species.py @@ -39,6 +39,7 @@ single internal node, three have two internal nodes, and one has three internal nodes. """ + # **************************************************************************** # Copyright (C) 2008 Mike Hansen , # @@ -292,6 +293,7 @@ def __add__(self, g): [[1, 2], [2, 1], [1, 2], [2, 1]] """ from .sum_species import SumSpecies + if not isinstance(g, GenericCombinatorialSpecies): raise TypeError("g must be a combinatorial species") return SumSpecies(self, g) @@ -309,6 +311,7 @@ def __mul__(self, g): Product of (Permutation species) and (Permutation species) """ from .product_species import ProductSpecies + if not isinstance(g, GenericCombinatorialSpecies): raise TypeError("g must be a combinatorial species") return ProductSpecies(self, g) @@ -324,6 +327,7 @@ def __call__(self, g): Composition of (Set species) and (Set species) """ from .composition_species import CompositionSpecies + if not isinstance(g, GenericCombinatorialSpecies): raise TypeError("g must be a combinatorial species") return CompositionSpecies(self, g) @@ -345,6 +349,7 @@ def functorial_composition(self, g): [1, 1, 2, 4, 11] """ from .functorial_composition_species import FunctorialCompositionSpecies + if not isinstance(g, GenericCombinatorialSpecies): raise TypeError("g must be a combinatorial species") return FunctorialCompositionSpecies(self, g) @@ -369,9 +374,7 @@ def restricted(self, min=None, max=None): sage: S.generating_series()[0:5] [0, 0, 0, 1/6, 1/24] """ - kwargs = {'min': self._min if min is None else min, - 'max': self._max if max is None else max, - 'weight': self._weight} + kwargs = {'min': self._min if min is None else min, 'max': self._max if max is None else max, 'weight': self._weight} return self.__class__(**kwargs) def structures(self, labels, structure_class=None): @@ -414,8 +417,7 @@ def _check(self, n=5): it = self.isotypes(range(n)) try: - return (len(st.list()) == st.cardinality() and - len(it.list()) == it.cardinality()) + return len(st.list()) == st.cardinality() and len(it.list()) == it.cardinality() except NotImplementedError: return False @@ -466,6 +468,7 @@ def __pow__(self, n): """ from sage.rings.integer import Integer import operator + n = Integer(n) if n <= 0: raise ValueError("only positive exponents are currently supported") @@ -473,8 +476,7 @@ def __pow__(self, n): squares = [self] for i in range(len(digits) - 1): squares.append(squares[-1] * squares[-1]) - return reduce(operator.mul, (s for i, s in zip(digits, squares) - if i != 0)) + return reduce(operator.mul, (s for i, s in zip(digits, squares) if i != 0)) def _get_series(self, series_ring_class, prefix, base_ring=None): """ @@ -495,8 +497,7 @@ def _get_series(self, series_ring_class, prefix, base_ring=None): # method will just return series. if self._min is None and self._max is None: return series - return series.parent()(lambda n: series[n], - valuation=self._min, degree=self._max) + return series.parent()(lambda n: series[n], valuation=self._min, degree=self._max) def _series_helper(self, series_ring_class, prefix, base_ring=None): """ @@ -574,8 +575,7 @@ def _series_helper(self, series_ring_class, prefix, base_ring=None): # This is used when the generating series is just a single # term. try: - return series_ring(getattr(self, prefix + "_term")(base_ring), - self._order()) + return series_ring(getattr(self, prefix + "_term")(base_ring), self._order()) except AttributeError: pass @@ -695,6 +695,7 @@ def _common_parent(self, parents): """ assert parents from sage.structure.element import get_coercion_model + cm = get_coercion_model() common = parents[0] @@ -730,6 +731,7 @@ def digraph(self): [(0, 3, None), (2, 0, None), (2, 0, None), (3, 1, None), (3, 2, None)] """ from sage.graphs.digraph import DiGraph + d = DiGraph(multiedges=True) self._add_to_digraph(d) return d @@ -806,8 +808,7 @@ def algebraic_equation_system(self): # A dictionary mapping the nodes to variables vertices = sorted(d.vertex_iterator(), key=str) - var_mapping = {node: R_gens_dict[name] - for node, name in zip(vertices, var_names)} + var_mapping = {node: R_gens_dict[name] for node, name in zip(vertices, var_names)} var_mapping['z'] = Qz.gen() eqns = [] diff --git a/src/sage/combinat/species/structure.py b/src/sage/combinat/species/structure.py index 87619524b28..71a7559f390 100644 --- a/src/sage/combinat/species/structure.py +++ b/src/sage/combinat/species/structure.py @@ -26,7 +26,8 @@ If we ignore the parentheses, we can read off that the integer compositions are [3], [2, 1], [1, 2], and [1, 1, 1]. """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Mike Hansen , # # Distributed under the terms of the GNU General Public License (GPL) @@ -39,7 +40,7 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.enumerated_sets import EnumeratedSets from sage.combinat.combinat import CombinatorialObject from sage.rings.integer import Integer @@ -206,9 +207,9 @@ def is_isomorphic(self, x) -> bool: return self.canonical_label()._list == x.canonical_label()._list -#For backward compatibility. This should be removed in the near -#future since I doubt that there is any code that depends directly on -#SpeciesStructure. +# For backward compatibility. This should be removed in the near +# future since I doubt that there is any code that depends directly on +# SpeciesStructure. SpeciesStructure = GenericSpeciesStructure @@ -369,11 +370,7 @@ def __eq__(self, other) -> bool: sage: S == SpeciesWrapper(F, [1,2,3], "_structures", "generating_series", 'Structures', None) True """ - return ((self._species, self._labels, - self._iterator, self._generating_series, - self._name, self._structure_class) == (other._species, other._labels, - other._iterator, other._generating_series, - other._name, other._structure_class)) + return (self._species, self._labels, self._iterator, self._generating_series, self._name, self._structure_class) == (other._species, other._labels, other._iterator, other._generating_series, other._name, other._structure_class) def __ne__(self, other) -> bool: r""" @@ -421,17 +418,15 @@ def __iter__(self): sage: F.structures([1,2,3]).list() [{1, 2, 3}] """ - #If the min and max are set, then we want to make sure - #that the iterator respects those bounds. - if (self._species._min is not None and - len(self._labels) < self._species._min): + # If the min and max are set, then we want to make sure + # that the iterator respects those bounds. + if self._species._min is not None and len(self._labels) < self._species._min: return iter([]) - if (self._species._max is not None and - len(self._labels) >= self._species._max): + if self._species._max is not None and len(self._labels) >= self._species._max: return iter([]) - #We check to see if the + # We check to see if the try: if self.cardinality() == 0: return iter([]) @@ -467,11 +462,7 @@ def __init__(self, species, labels, structure_class): sage: S == loads(dumps(S)) True """ - SpeciesWrapper.__init__(self, species, labels, - "_structures", - "generating_series", - "Structures", - structure_class) + SpeciesWrapper.__init__(self, species, labels, "_structures", "generating_series", "Structures", structure_class) class IsotypesWrapper(SpeciesWrapper): @@ -488,11 +479,7 @@ def __init__(self, species, labels, structure_class): sage: S == loads(dumps(S)) True """ - SpeciesWrapper.__init__(self, species, labels, - "_isotypes", - "isotype_generating_series", - "Isomorphism types", - structure_class) + SpeciesWrapper.__init__(self, species, labels, "_isotypes", "isotype_generating_series", "Isomorphism types", structure_class) class SimpleStructuresWrapper(SpeciesWrapper): @@ -509,11 +496,7 @@ def __init__(self, species, labels, structure_class): sage: S == loads(dumps(S)) True """ - SpeciesWrapper.__init__(self, species, labels, - "_simple_structures_selector", - "generating_series", - "Simple structures", - structure_class) + SpeciesWrapper.__init__(self, species, labels, "_simple_structures_selector", "generating_series", "Simple structures", structure_class) class SimpleIsotypesWrapper(SpeciesWrapper): @@ -530,8 +513,4 @@ def __init__(self, species, labels, structure_class): sage: S == loads(dumps(S)) True """ - SpeciesWrapper.__init__(self, species, labels, - "_simple_isotypes_selector", - "isotype_generating_series", - "Simple isomorphism types", - structure_class) + SpeciesWrapper.__init__(self, species, labels, "_simple_isotypes_selector", "isotype_generating_series", "Simple isomorphism types", structure_class) diff --git a/src/sage/combinat/species/subset_species.py b/src/sage/combinat/species/subset_species.py index 37b94c42d42..f2e2399df72 100644 --- a/src/sage/combinat/species/subset_species.py +++ b/src/sage/combinat/species/subset_species.py @@ -39,7 +39,7 @@ def __repr__(self): {} """ s = GenericSpeciesStructure.__repr__(self) - return "{"+s[1:-1]+"}" + return "{" + s[1:-1] + "}" def canonical_label(self): """ @@ -107,6 +107,7 @@ def automorphism_group(self): """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup from sage.groups.perm_gps.permgroup import PermutationGroup + a = SymmetricGroup(self._list) b = SymmetricGroup(self.complement()._list) return PermutationGroup(a.gens() + b.gens()) @@ -123,7 +124,7 @@ def complement(self): sage: a.complement() {'b'} """ - new_list = [i for i in range(1, len(self._labels)+1) if i not in self._list] + new_list = [i for i in range(1, len(self._labels) + 1) if i not in self._list] return SubsetSpeciesStructure(self.parent(), self._labels, new_list) @@ -174,7 +175,8 @@ def _structures(self, structure_class, labels): [{}, {'a'}, {'b'}, {'a', 'b'}] """ from sage.combinat.combination import Combinations - for c in Combinations(range(1, len(labels)+1)): + + for c in Combinations(range(1, len(labels) + 1)): yield structure_class(self, labels, c) def _isotypes(self, structure_class, labels): @@ -187,8 +189,8 @@ def _isotypes(self, structure_class, labels): sage: S.isotypes(['a','b']).list() [{}, {'a'}, {'a', 'b'}] """ - for i in range(len(labels)+1): - yield structure_class(self, labels, range(1, i+1)) + for i in range(len(labels) + 1): + yield structure_class(self, labels, range(1, i + 1)) def _gs_callable(self, base_ring, n): """ @@ -201,7 +203,7 @@ def _gs_callable(self, base_ring, n): sage: [S.generating_series().coefficient(i) for i in range(5)] [1, 2, 2, 4/3, 2/3] """ - return base_ring(2)**n / base_ring(factorial(n)) + return base_ring(2) ** n / base_ring(factorial(n)) def _itgs_callable(self, base_ring, n): r""" @@ -241,5 +243,5 @@ def _cis(self, series_ring, base_ring): return res -#Backward compatibility +# Backward compatibility SubsetSpecies_class = SubsetSpecies diff --git a/src/sage/combinat/species/sum_species.py b/src/sage/combinat/species/sum_species.py index 771ab720bb8..0d627e586c9 100644 --- a/src/sage/combinat/species/sum_species.py +++ b/src/sage/combinat/species/sum_species.py @@ -1,7 +1,8 @@ """ Sum species """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2008 Mike Hansen , # # Distributed under the terms of the GNU General Public License (GPL) @@ -14,7 +15,7 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from .species import GenericCombinatorialSpecies from .structure import SpeciesStructureWrapper from sage.structure.unique_representation import UniqueRepresentation @@ -105,8 +106,7 @@ def _name(self): sage: F._name() 'Sum of (Permutation species) and (Permutation species)' """ - return "Sum of (%s) and (%s)" % (self.left_summand(), - self.right_summand()) + return "Sum of (%s) and (%s)" % (self.left_summand(), self.right_summand()) def _structures(self, structure_class, labels): """ @@ -149,8 +149,7 @@ def _gs(self, series_ring, base_ring): sage: F.generating_series()[:5] [2, 2, 2, 2, 2] """ - return (self.left_summand().generating_series(base_ring) + - self.right_summand().generating_series(base_ring)) + return self.left_summand().generating_series(base_ring) + self.right_summand().generating_series(base_ring) def _itgs(self, series_ring, base_ring): """ @@ -163,8 +162,7 @@ def _itgs(self, series_ring, base_ring): sage: F.isotype_generating_series()[:5] # needs sage.libs.flint [2, 2, 4, 6, 10] """ - return (self.left_summand().isotype_generating_series(base_ring) + - self.right_summand().isotype_generating_series(base_ring)) + return self.left_summand().isotype_generating_series(base_ring) + self.right_summand().isotype_generating_series(base_ring) def _cis(self, series_ring, base_ring): """ @@ -181,8 +179,7 @@ def _cis(self, series_ring, base_ring): 2*p[1, 1, 1] + 2*p[2, 1] + 2*p[3], 2*p[1, 1, 1, 1] + 2*p[2, 1, 1] + 2*p[2, 2] + 2*p[3, 1] + 2*p[4]] """ - return (self.left_summand().cycle_index_series(base_ring) + - self.right_summand().cycle_index_series(base_ring)) + return self.left_summand().cycle_index_series(base_ring) + self.right_summand().cycle_index_series(base_ring) def weight_ring(self): """ @@ -204,8 +201,7 @@ def weight_ring(self): sage: C.weight_ring() Univariate Polynomial Ring in t over Rational Field """ - return self._common_parent([self.left_summand().weight_ring(), - self.right_summand().weight_ring()]) + return self._common_parent([self.left_summand().weight_ring(), self.right_summand().weight_ring()]) def _equation(self, var_mapping): """ @@ -223,5 +219,5 @@ def _equation(self, var_mapping): return sum(var_mapping[operand] for operand in self._state_info) -#Backward compatibility +# Backward compatibility SumSpecies_class = SumSpecies diff --git a/src/sage/combinat/subset.py b/src/sage/combinat/subset.py index f7d1fc6a768..5731c256e47 100644 --- a/src/sage/combinat/subset.py +++ b/src/sage/combinat/subset.py @@ -11,6 +11,7 @@ - Florent Hivert (2009/02/06): doc improvements + new methods """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # 2014 Vincent Delecroix <20100.delecroix@gmail.com>, @@ -155,7 +156,8 @@ def Subsets(s, k=None, submultiset=False): if s < 0: raise ValueError("s must be nonnegative") from sage.sets.integer_range import IntegerRange - s = IntegerRange(1,s+1) + + s = IntegerRange(1, s + 1) if k is None: if submultiset: @@ -192,6 +194,7 @@ class Subsets_s(Parent): {{1, 2}, {0}}, {{0, 1, 2}, {0, 1}, {0, 2}, {1, 2}}} """ + # TODO: Set_object_enumerated does not inherit from Element... so we set # directly element_class as Set_object_enumerated # (see also below the failed test in __init__) @@ -219,6 +222,7 @@ def __init__(self, s): Parent.__init__(self, category=EnumeratedSets().Finite()) if s not in EnumeratedSets(): from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + L = list(uniq(s)) s = FiniteEnumeratedSet(L) self._s = s @@ -450,13 +454,12 @@ def rank(self, sub): try: index_list = sorted(self._s.rank(x) for x in sub) - except (ValueError,IndexError): - raise ValueError("{} is not a subset of {}".format( - Set(sub), self._s)) + except (ValueError, IndexError): + raise ValueError("{} is not a subset of {}".format(Set(sub), self._s)) n = self._s.cardinality() - r = sum(binomial(n,i) for i in range(len(index_list))) - return r + combination.rank(index_list,n) + r = sum(binomial(n, i) for i in range(len(index_list))) + return r + combination.rank(index_list, n) def unrank(self, r): """ @@ -483,7 +486,7 @@ def unrank(self, r): while r >= bin: r -= bin k += 1 - bin = binomial(n,k) + bin = binomial(n, k) return self.element_class([self._s.unrank(i) for i in combination.from_rank(r, n, k)]) def __call__(self, el): @@ -515,7 +518,7 @@ def _element_constructor_(self, X): """ e = self.element_class(X) if e not in self: - raise ValueError("{} not in {}".format(e,self)) + raise ValueError("{} not in {}".format(e, self)) return e def _an_element_(self): @@ -623,7 +626,7 @@ def __contains__(self, value): sage: Set([]) in S False """ - return len(value) == self._k and Subsets_s.__contains__(self,value) + return len(value) == self._k and Subsets_s.__contains__(self, value) def __eq__(self, other): r""" @@ -713,8 +716,7 @@ def first(self): if self._k < 0 or self._k > self._s.cardinality(): raise EmptySetError else: - return self.element_class(list(itertools.islice(self._s, - int(self._k)))) + return self.element_class(list(itertools.islice(self._s, int(self._k)))) def last(self): """ @@ -736,8 +738,7 @@ def last(self): if self._k > self._s.cardinality(): raise EmptySetError - return self.element_class(list(itertools.islice(reversed(self._s), - int(self._k)))) + return self.element_class(list(itertools.islice(reversed(self._s), int(self._k)))) def _fast_iterator(self): r""" @@ -817,14 +818,12 @@ def rank(self, sub): n = self._s.cardinality() if self._k != sub.cardinality() or self._k > n: - raise ValueError("{} is not a subset of length {} of {}".format( - sub, self._k, self._s)) + raise ValueError("{} is not a subset of length {} of {}".format(sub, self._k, self._s)) try: index_list = sorted(self._s.rank(x) for x in sub) except ValueError: - raise ValueError("{} is not a subset of length {} of {}".format( - sub, self._k, self._s)) + raise ValueError("{} is not a subset of length {} of {}".format(sub, self._k, self._s)) return combination.rank(index_list, n) @@ -938,6 +937,7 @@ class SubMultiset_s(Parent): sage: S.last() [1, 2, 2, 3] """ + # TODO: list does not inherit from Element... so we set # directly element_class as list element_class = list @@ -1058,6 +1058,7 @@ def cardinality(self): 24 """ from sage.misc.misc_c import prod + return Integer(prod(k + 1 for k in self._d.values())) def random_element(self): @@ -1155,7 +1156,7 @@ def _element_constructor_(self, X): """ e = self.element_class(X) if e not in self: - raise ValueError("{} not in {}".format(e,self)) + raise ValueError("{} not in {}".format(e, self)) return e @@ -1319,9 +1320,9 @@ def __iter__(self): [[], [3], [2], [3, 2], [2, 2], [3, 2, 2]] """ from sage.combinat.integer_vector import IntegerVectors + elts = self._keys - for iv in IntegerVectors(self._k, len(self._d), - outer=[self._d[k] for k in elts]): + for iv in IntegerVectors(self._k, len(self._d), outer=[self._d[k] for k in elts]): yield sum([[elts[i]] * iv[i] for i in range(len(iv))], []) @@ -1334,6 +1335,7 @@ class SubsetsSorted(Subsets_s): have to explicitly build all `2^n` subsets in memory). For example, :class:`CliffordAlgebra`. """ + element_class = tuple def __contains__(self, value): @@ -1434,7 +1436,7 @@ def unrank(self, r): while r >= binom: r -= binom k += 1 - binom = binomial(n,k) + binom = binomial(n, k) C = combination.from_rank(r, n, k) return self.element_class(sorted([self._s.unrank(i) for i in C])) diff --git a/src/sage/combinat/subsets_hereditary.py b/src/sage/combinat/subsets_hereditary.py index b02cf538f42..747f122fd95 100644 --- a/src/sage/combinat/subsets_hereditary.py +++ b/src/sage/combinat/subsets_hereditary.py @@ -1,6 +1,7 @@ r""" Subsets satisfying a hereditary property """ + # **************************************************************************** # Copyright (C) 2014 Nathann Cohen # @@ -102,6 +103,7 @@ def subsets_with_hereditary_property(f, X, max_obstruction_size=None, ncpus=1): [[], [0], [1], [0, 1]] """ from sage.data_structures.bitset import Bitset + # About the implementation: # # 1) We work on X={0,...,n-1} but remember X to return correctly @@ -122,8 +124,8 @@ def subsets_with_hereditary_property(f, X, max_obstruction_size=None, ncpus=1): max_obstruction_size = n bs = [Bitset([], 1) for _ in range(n)] # collection of no-set - nforb = 1 # number of no-sets stored - current_layer = [[]] # all yes-sets of size 'current_size' + nforb = 1 # number of no-sets stored + current_layer = [[]] # all yes-sets of size 'current_size' current_size = 0 def explore_neighbors(s): @@ -135,8 +137,8 @@ def explore_neighbors(s): """ new_yes_sets = [] new_no_sets = [] - for i in range((s[-1] + 1 if s else 0), n): # all ways to extend it - s_plus_i = s + [i] # the extended set + for i in range((s[-1] + 1 if s else 0), n): # all ways to extend it + s_plus_i = s + [i] # the extended set s_plus_i_c = Bitset(s_plus_i, n).complement() # .. and its complement # Filter a no-set using the data collected so far. @@ -160,6 +162,7 @@ def explore_neighbors(s): if ncpus != 1: from sage.parallel.decorate import parallel + explore_neighbors_paral = parallel(ncpus=ncpus)(explore_neighbors) # All sets of size 0, then size 1, then ... @@ -197,5 +200,5 @@ def explore_neighbors(s): # # If we did, this was probably the worst choice of algorithm for we computed # f(X) for all 2^n sets X, but well... - if (current_size == len(X) and nforb == 1 and f(X_labels)): + if current_size == len(X) and nforb == 1 and f(X_labels): yield X_labels diff --git a/src/sage/combinat/subsets_pairwise.py b/src/sage/combinat/subsets_pairwise.py index 67b10c6067c..076c45c393d 100644 --- a/src/sage/combinat/subsets_pairwise.py +++ b/src/sage/combinat/subsets_pairwise.py @@ -1,6 +1,7 @@ r""" Subsets whose elements satisfy a predicate pairwise """ + # *************************************************************************** # Copyright (C) 2011 Nicolas M. Thiery # @@ -98,7 +99,7 @@ def __init__(self, ambient, predicate, maximal=False, element_class=Set_object_e sage: TestSuite(P).run() """ self._ambient = set(ambient) - self._roots = ( ((), tuple(reversed(ambient))), ) + self._roots = (((), tuple(reversed(ambient))),) self._predicate = predicate self._maximal = maximal # TODO: use self.element_class for consistency @@ -141,9 +142,7 @@ def __contains__(self, subset): sage: Set([4,6]) in P False """ - return isinstance(subset, self._element_class ) and \ - set(subset).issubset(self._ambient) and \ - all( self._predicate(x,y) for x,y in Subsets(subset,2) ) + return isinstance(subset, self._element_class) and set(subset).issubset(self._ambient) and all(self._predicate(x, y) for x, y in Subsets(subset, 2)) def post_process(self, subset_rest): """ @@ -179,6 +178,5 @@ def children(self, subset_rest) -> list: rest = list(rest) while rest: x = rest.pop() - result.append((subset + (x,), - tuple(y for y in rest if predicate(x, y)))) + result.append((subset + (x,), tuple(y for y in rest if predicate(x, y)))) return result diff --git a/src/sage/combinat/subword.py b/src/sage/combinat/subword.py index 2919657b899..e4bc56ac441 100644 --- a/src/sage/combinat/subword.py +++ b/src/sage/combinat/subword.py @@ -39,6 +39,7 @@ - Florent Hivert (2009/02/06): doc improvements + new methods + bug fixes """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # 2014 Vincent Delecroix <20100.delecroix@gmail.com>, @@ -146,6 +147,7 @@ def Subwords(w, k=None, element_constructor=None): element_constructor = _stringification else: from sage.combinat.words.words import Words + try: alphabet = w.parent().alphabet() element_constructor = Words(alphabet) @@ -314,8 +316,7 @@ def __iter__(self) -> Iterator: sage: Subwords('123').list() ['', '1', '2', '3', '12', '13', '23', '123'] """ - return itertools.chain(*[Subwords_wk(self._w, i, self._build) - for i in range(len(self._w) + 1)]) + return itertools.chain(*[Subwords_wk(self._w, i, self._build) for i in range(len(self._w) + 1)]) class Subwords_wk(Subwords_w): diff --git a/src/sage/combinat/subword_complex.py b/src/sage/combinat/subword_complex.py index c117e7a0183..d59e2978fa4 100644 --- a/src/sage/combinat/subword_complex.py +++ b/src/sage/combinat/subword_complex.py @@ -394,9 +394,7 @@ def kappa_preimage(self) -> list: W = self.parent().group() N = len(W.long_element(as_word=True)) root_conf = self._root_configuration_indices() - return [~w for w in W - if all(w.action_on_root_indices(i, side='left') < N - for i in root_conf)] + return [~w for w in W if all(w.action_on_root_indices(i, side='left') < N for i in root_conf)] def is_vertex(self) -> bool: r""" @@ -553,8 +551,7 @@ def extended_weight_configuration(self, coefficients=None): I = W.index_set() Lambda = W.fundamental_weights() if coefficients is not None: - coeff = {I[i]: coefficients[i] - for i in range(len(coefficients))} + coeff = {I[i]: coefficients[i] for i in range(len(coefficients))} Lambda = {li: coeff[li] * Lambda[li] for li in Lambda.keys()} Q = self.parent().word() V_weights = [] @@ -733,8 +730,7 @@ def flip(self, i, return_position=False): # plot and show - def plot(self, list_colors=None, labels=[], thickness=3, fontsize=14, - shift=(0, 0), compact=False, roots=True, **args): + def plot(self, list_colors=None, labels=[], thickness=3, fontsize=14, shift=(0, 0), compact=False, roots=True, **args): r""" In type `A` or `B`, plot a pseudoline arrangement representing the facet ``self``. @@ -854,18 +850,16 @@ def plot(self, list_colors=None, labels=[], thickness=3, fontsize=14, else: last = n - 1 permutation = Permutation(range(1, last + 2)) - x_max = .5 + x_max = 0.5 # list the pseudolines to be drawn - pseudolines = [[(shift[0], shift[1] + i), .5] for i in range(last + 1)] + pseudolines = [[(shift[0], shift[1] + i), 0.5] for i in range(last + 1)] pseudolines_type_B = [[] for _ in repeat(None, last + 1)] contact_points = [] root_labels = [] pseudoline_labels = [] if labels is not False: - pseudoline_labels += [(pseudoline, - (shift[0] - .1, shift[1] + pseudoline), - "center") for pseudoline in range(last + 1)] + pseudoline_labels += [(pseudoline, (shift[0] - 0.1, shift[1] + pseudoline), "center") for pseudoline in range(last + 1)] if roots: extended_root_conf = self.extended_root_configuration() for position in range(len(Q)): @@ -879,56 +873,36 @@ def plot(self, list_colors=None, labels=[], thickness=3, fontsize=14, x = x_max x_max += 1 if position in self: - pseudolines[pseudoline] += [(shift[0] + x + 1, - shift[1]), x + 1] - contact_points += [[(shift[0] + x + .5, shift[1] - .2), - (shift[0] + x + .5, shift[1])]] + pseudolines[pseudoline] += [(shift[0] + x + 1, shift[1]), x + 1] + contact_points += [[(shift[0] + x + 0.5, shift[1] - 0.2), (shift[0] + x + 0.5, shift[1])]] else: - pseudolines_type_B[pseudoline] = pseudolines[pseudoline] + [(shift[0] + x + .5, shift[1]), (shift[0] + x + .5, shift[1] - .2)] - pseudolines[pseudoline] = [(shift[0] + x + .6, shift[1] - .2), (shift[0] + x + .6, shift[1]), .5] + pseudolines_type_B[pseudoline] = pseudolines[pseudoline] + [(shift[0] + x + 0.5, shift[1]), (shift[0] + x + 0.5, shift[1] - 0.2)] + pseudolines[pseudoline] = [(shift[0] + x + 0.6, shift[1] - 0.2), (shift[0] + x + 0.6, shift[1]), 0.5] if roots: - root_labels.append((extended_root_conf[position], - (shift[0] + x + .25, shift[1] - .2))) + root_labels.append((extended_root_conf[position], (shift[0] + x + 0.25, shift[1] - 0.2))) else: if type in ['B', 'C']: y -= 1 pseudoline1 = permutation(y + 1) - 1 pseudoline2 = permutation(y + 2) - 1 - x = max(pseudolines[pseudoline1].pop(), - pseudolines[pseudoline2].pop()) + x = max(pseudolines[pseudoline1].pop(), pseudolines[pseudoline2].pop()) if compact: x_max = max(x + 1, x_max) else: x = x_max x_max += 1 if position in self: - pseudolines[pseudoline1] += [(shift[0] + x + 1, - shift[1] + y), x + 1] - pseudolines[pseudoline2] += [(shift[0] + x + 1, - shift[1] + y + 1), x + 1] - contact_points += [[(shift[0] + x + .5, shift[1] + y), - (shift[0] + x + .5, shift[1] + y + 1)]] + pseudolines[pseudoline1] += [(shift[0] + x + 1, shift[1] + y), x + 1] + pseudolines[pseudoline2] += [(shift[0] + x + 1, shift[1] + y + 1), x + 1] + contact_points += [[(shift[0] + x + 0.5, shift[1] + y), (shift[0] + x + 0.5, shift[1] + y + 1)]] else: - pseudolines[pseudoline1] += [(shift[0] + x + .6, - shift[1] + y), - (shift[0] + x + .6, - shift[1] + y + 1), x + 1] - pseudolines[pseudoline2] += [(shift[0] + x + .5, - shift[1] + y + 1), - (shift[0] + x + .5, - shift[1] + y), x + 1] + pseudolines[pseudoline1] += [(shift[0] + x + 0.6, shift[1] + y), (shift[0] + x + 0.6, shift[1] + y + 1), x + 1] + pseudolines[pseudoline2] += [(shift[0] + x + 0.5, shift[1] + y + 1), (shift[0] + x + 0.5, shift[1] + y), x + 1] permutation = permutation._left_to_right_multiply_on_left(Permutation((y + 1, y + 2))) if roots: - root_labels.append((extended_root_conf[position], - (shift[0] + x + .35, - shift[1] + y + .5))) + root_labels.append((extended_root_conf[position], (shift[0] + x + 0.35, shift[1] + y + 0.5))) if labels is not False: - pseudoline_labels += [(pseudoline1, (shift[0] + x + .35, - shift[1] + y + .05), - "bottom"), - (pseudoline2, (shift[0] + x + .35, - shift[1] + y + .95), - "top")] + pseudoline_labels += [(pseudoline1, (shift[0] + x + 0.35, shift[1] + y + 0.05), "bottom"), (pseudoline2, (shift[0] + x + 0.35, shift[1] + y + 0.95), "top")] # transform list to real lines if list_colors is None: @@ -938,38 +912,22 @@ def plot(self, list_colors=None, labels=[], thickness=3, fontsize=14, thickness = max(thickness, 2) L = line([(1, 1)]) for contact_point in contact_points: - L += line(contact_point, rgbcolor=[0, 0, 0], - thickness=thickness - 1) + L += line(contact_point, rgbcolor=[0, 0, 0], thickness=thickness - 1) for pseudoline in range(last + 1): pseudolines[pseudoline].pop() - pseudolines[pseudoline].append((shift[0] + x_max, - shift[1] + permutation.inverse()(pseudoline + 1) - 1)) - L += line(pseudolines[pseudoline], color=list_colors[pseudoline], - thickness=thickness) + pseudolines[pseudoline].append((shift[0] + x_max, shift[1] + permutation.inverse()(pseudoline + 1) - 1)) + L += line(pseudolines[pseudoline], color=list_colors[pseudoline], thickness=thickness) if type in ['B', 'C']: - L += line(pseudolines_type_B[pseudoline], - color=list_colors[pseudoline], - thickness=thickness, linestyle='--') + L += line(pseudolines_type_B[pseudoline], color=list_colors[pseudoline], thickness=thickness, linestyle='--') for root_label in root_labels: - L += text(root_label[0], root_label[1], rgbcolor=[0, 0, 0], - fontsize=fontsize, vertical_alignment='center', - horizontal_alignment='right') + L += text(root_label[0], root_label[1], rgbcolor=[0, 0, 0], fontsize=fontsize, vertical_alignment='center', horizontal_alignment='right') if len(labels) < last + 1: labels = list(range(1, last + 2)) for pseudoline_label in pseudoline_labels: - L += text(labels[pseudoline_label[0]], pseudoline_label[1], - color=list_colors[pseudoline_label[0]], - fontsize=fontsize, - vertical_alignment=pseudoline_label[2], - horizontal_alignment='right') + L += text(labels[pseudoline_label[0]], pseudoline_label[1], color=list_colors[pseudoline_label[0]], fontsize=fontsize, vertical_alignment=pseudoline_label[2], horizontal_alignment='right') if labels is not False: for pseudoline in range(last): - L += text(labels[pseudoline], - (shift[0] + x_max + .1, - shift[1] + permutation.inverse()(pseudoline + 1) - 1), - color=list_colors[pseudoline], fontsize=fontsize, - vertical_alignment='center', - horizontal_alignment='left') + L += text(labels[pseudoline], (shift[0] + x_max + 0.1, shift[1] + permutation.inverse()(pseudoline + 1) - 1), color=list_colors[pseudoline], fontsize=fontsize, vertical_alignment='center', horizontal_alignment='left') L.axes(False) return L @@ -1142,14 +1100,11 @@ def __init__(self, Q, w, algorithm='inductive'): elif algorithm == "greedy": Fs, Rs = _greedy_flip_algorithm(Q, w) else: - raise ValueError("the optional argument algorithm can be " - "either inductive or greedy") + raise ValueError("the optional argument algorithm can be " "either inductive or greedy") if not Fs: raise ValueError("the word %s does not contain a reduced expression for %s" % (Q, w.reduced_word())) cat = SimplicialComplexes().Finite().Enumerated() - SimplicialComplex.__init__(self, maximal_faces=Fs, - maximality_check=False, - category=cat) + SimplicialComplex.__init__(self, maximal_faces=Fs, maximality_check=False, category=cat) self._W = W try: T = W.coxeter_matrix().coxeter_type() @@ -1431,8 +1386,7 @@ def greedy_facet(self, side='positive'): sage: SC.greedy_facet(side='negative') (3, 4) """ - return self.element_class(self, _greedy_facet(self.word(), - self.pi(), side=side)) + return self.element_class(self, _greedy_facet(self.word(), self.pi(), side=side)) # topological properties @@ -1556,6 +1510,7 @@ def is_root_independent(self) -> bool: True """ from sage.matrix.constructor import matrix + M = matrix(self.greedy_facet(side='negative').root_configuration()) return M.rank() == max(M.ncols(), M.nrows()) @@ -1662,6 +1617,7 @@ def brick_fan(self): Rational polyhedral fan in 2-d lattice N """ from sage.geometry.fan import Fan + return Fan([F.weight_cone() for F in self]) # brick polytope @@ -1720,11 +1676,13 @@ def minkowski_summand(self, i): """ G = self.group() from sage.rings.rational_field import QQ + if G.coxeter_matrix().is_crystallographic(): min_sum = [[QQ(v) for v in F.extended_weight_configuration()[i]] for F in self] else: from sage.rings.cc import CC from warnings import warn + warn("the polytope is built with rational vertices", RuntimeWarning) min_sum = [[QQ(CC(v)) for v in F.extended_weight_configuration()[i]] for F in self] return Polyhedron(min_sum) @@ -1774,11 +1732,13 @@ def brick_polytope(self, coefficients=None): BV = self.brick_vectors(coefficients=coefficients) G = self.group() from sage.rings.rational_field import QQ + if G.coxeter_matrix().is_crystallographic(): BV = [[QQ(v) for v in V] for V in BV] else: from sage.rings.cc import CC from warnings import warn + warn("the polytope is built with rational vertices", RuntimeWarning) BV = [[QQ(CC(v).real()) for v in V] for V in BV] return Polyhedron(BV) @@ -1880,6 +1840,7 @@ def increasing_flip_graph(self, label=True): Digraph on 5 vertices """ from sage.graphs.digraph import DiGraph + return DiGraph(self.cover_relations(label=label)) def interval(self, I, J) -> set: @@ -1930,6 +1891,7 @@ def increasing_flip_poset(self): Finite poset containing 5 elements """ from sage.combinat.posets.posets import Poset + cov = self.cover_relations() if not self.is_root_independent(): Fs = [F for F in self if F.is_vertex()] @@ -1977,8 +1939,7 @@ def _greedy_facet(Q, w, side='negative', n=None, pos=0, l=None, elems=[]): Q = Q[::-1] w = w.inverse() else: - raise ValueError("the optional argument side is not positive " - "or negative") + raise ValueError("the optional argument side is not positive " "or negative") if n is None: n = len(Q) @@ -1993,8 +1954,7 @@ def _greedy_facet(Q, w, side='negative', n=None, pos=0, l=None, elems=[]): s = Q[pos] if w.has_left_descent(s): - X = _greedy_facet(Q, w.apply_simple_reflection_left(s), - n=n, pos=pos + 1, l=l - 1, elems=elems) + X = _greedy_facet(Q, w.apply_simple_reflection_left(s), n=n, pos=pos + 1, l=l - 1, elems=elems) else: X = [] @@ -2043,8 +2003,7 @@ def _extended_root_configuration_indices(W, Q, F): V_roots = [] pi = W.one() for i, wi in enumerate(Q): - V_roots.append(pi.action_on_root_indices(W.simple_root_index(wi), - side='left')) + V_roots.append(pi.action_on_root_indices(W.simple_root_index(wi), side='left')) if i not in F: pi = pi.apply_simple_reflection_right(wi) return V_roots diff --git a/src/sage/combinat/super_tableau.py b/src/sage/combinat/super_tableau.py index a21e1f5284e..ba426c14537 100644 --- a/src/sage/combinat/super_tableau.py +++ b/src/sage/combinat/super_tableau.py @@ -29,8 +29,7 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.combinat.shifted_primed_tableau import PrimedEntry -from sage.combinat.tableau import (Tableau, Tableaux, SemistandardTableaux, - StandardTableaux) +from sage.combinat.tableau import Tableau, Tableaux, SemistandardTableaux, StandardTableaux class SemistandardSuperTableau(Tableau): @@ -84,6 +83,7 @@ class SemistandardSuperTableau(Tableau): sage: s2.parent() Semistandard super tableaux """ + @staticmethod def __classcall_private__(cls, t): r""" @@ -155,8 +155,7 @@ def _preprocess(t): if isinstance(t, SemistandardSuperTableau): return t # Preprocessing list t for primes and other symbols - t = [[PrimedEntry(entry) if entry is not None else entry for entry in row] - for row in t] + t = [[PrimedEntry(entry) if entry is not None else entry for entry in row] for row in t] while t and not t[-1]: t = t[:-1] return t @@ -188,33 +187,23 @@ def check(self): super().check() for row in self: if not all(isinstance(c, PrimedEntry) and c > 0 for c in row): - raise ValueError("the entries of a semistandard super tableau" - " must be nonnegative primed integers") + raise ValueError("the entries of a semistandard super tableau" " must be nonnegative primed integers") if any(row[c] > row[c + 1] for c in range(len(row) - 1)): - raise ValueError("the entries in each row of a semistandard" - " super tableau must be weakly increasing") + raise ValueError("the entries in each row of a semistandard" " super tableau must be weakly increasing") if self: for row, next in zip(self, self[1:]): # Check that letters are weakly increasing down columns if any(row[c] > next[c] for c in range(len(next))): - raise ValueError("the entries of each column of a " - "semistandard super tableau must be " - "weakly increasing") + raise ValueError("the entries of each column of a " "semistandard super tableau must be " "weakly increasing") # Check that unprimed letters are column strict - if not all(row[c] < next[c] - for c in range(len(next)) - if (row[c].is_unprimed() or next[c].is_unprimed())): - raise ValueError("the unprimed entries of each column" - " must be strictly increasing") + if not all(row[c] < next[c] for c in range(len(next)) if (row[c].is_unprimed() or next[c].is_unprimed())): + raise ValueError("the unprimed entries of each column" " must be strictly increasing") # Check that primed letters are row strict for row in self: - if not all(row[c] < row[c + 1] - for c in range(len(row) - 1) - if (row[c].is_primed() or row[c + 1].is_primed())): - raise ValueError("the primed entries in each row must be" - " strictly increasing") + if not all(row[c] < row[c + 1] for c in range(len(row) - 1) if (row[c].is_primed() or row[c + 1].is_primed())): + raise ValueError("the primed entries in each row must be" " strictly increasing") class StandardSuperTableau(SemistandardSuperTableau): @@ -259,6 +248,7 @@ class StandardSuperTableau(SemistandardSuperTableau): sage: isinstance(r, Tableau) True """ + @staticmethod def __classcall_private__(self, t): r""" @@ -309,8 +299,7 @@ def check(self): a = a.increase_half() if sorted(flattened_list) != primed_list: - raise ValueError("the entries in a standard tableau must be in" - " bijection with 1',1,2',2,...,n") + raise ValueError("the entries in a standard tableau must be in" " bijection with 1',1,2',2,...,n") def is_standard(self) -> bool: """ @@ -343,6 +332,7 @@ class SemistandardSuperTableaux(SemistandardTableaux): sage: SST = SemistandardSuperTableaux(); SST Semistandard super tableaux """ + @staticmethod def __classcall_private__(cls): r""" @@ -395,16 +385,12 @@ def __contains__(self, x) -> bool: for row in x: if any(row[c] > row[c + 1] for c in range(len(row) - 1)): return False - if not all(row[c] < row[c + 1] - for c in range(len(row) - 1) - if (row[c].is_primed() or row[c + 1].is_primed())): + if not all(row[c] < row[c + 1] for c in range(len(row) - 1) if (row[c].is_primed() or row[c + 1].is_primed())): return False for row, next in zip(x, x[1:]): if any(row[c] > next[c] for c in range(len(next))): return False - if not all(row[c] < next[c] - for c in range(len(next)) - if (row[c].is_unprimed() or next[c].is_unprimed())): + if not all(row[c] < next[c] for c in range(len(next)) if (row[c].is_unprimed() or next[c].is_unprimed())): return False return True return False @@ -499,6 +485,7 @@ class StandardSuperTableaux(SemistandardSuperTableaux, Parent): [[1', 1, 2'], [2, 3']]] sage: TestSuite(SST).run() """ + @staticmethod def __classcall_private__(cls, n=None): r""" @@ -535,12 +522,10 @@ def __classcall_private__(cls, n=None): return StandardSuperTableaux_shape(_Partitions(n)) if n in SkewPartitions(): - raise NotImplementedError("standard super tableau for skew " - "partitions is not implemented yet") + raise NotImplementedError("standard super tableau for skew " "partitions is not implemented yet") if not isinstance(n, (int, Integer)) or n < 0: - raise ValueError("the argument must be a nonnegative integer" - " or a partition") + raise ValueError("the argument must be a nonnegative integer" " or a partition") return StandardSuperTableaux_size(n) @@ -583,15 +568,11 @@ def __contains__(self, x) -> bool: primed_list.append(a) a = a.increase_half() # return True - return sorted(flattened_list) == primed_list and (x or - (all(row[i] < row[i + 1] for row in x for i in range(len(row) - 1)) and - all(x[r][c] < x[r + 1][c] for r in range(len(x) - 1) - for c in range(len(x[r + 1]))))) + return sorted(flattened_list) == primed_list and (x or (all(row[i] < row[i + 1] for row in x for i in range(len(row) - 1)) and all(x[r][c] < x[r + 1][c] for r in range(len(x) - 1) for c in range(len(x[r + 1]))))) return False -class StandardSuperTableaux_all(StandardSuperTableaux, - DisjointUnionEnumeratedSets): +class StandardSuperTableaux_all(StandardSuperTableaux, DisjointUnionEnumeratedSets): """ All standard super tableaux. """ @@ -608,10 +589,7 @@ def __init__(self): sage: TestSuite(SST).run() """ StandardSuperTableaux.__init__(self) - DisjointUnionEnumeratedSets.__init__(self, - Family(NonNegativeIntegers(), - StandardSuperTableaux_size), - facade=True, keepkey=False) + DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), StandardSuperTableaux_size), facade=True, keepkey=False) def _repr_(self) -> str: """ @@ -623,8 +601,7 @@ def _repr_(self) -> str: return "Standard super tableaux" -class StandardSuperTableaux_size(StandardSuperTableaux, - DisjointUnionEnumeratedSets): +class StandardSuperTableaux_size(StandardSuperTableaux, DisjointUnionEnumeratedSets): """ Standard super tableaux of fixed size `n`. @@ -659,11 +636,8 @@ def __init__(self, n): """ StandardSuperTableaux.__init__(self) from sage.combinat.partition import Partitions_n - DisjointUnionEnumeratedSets.__init__(self, - Family(Partitions_n(n), - StandardSuperTableaux_shape), - category=FiniteEnumeratedSets(), - facade=True, keepkey=False) + + DisjointUnionEnumeratedSets.__init__(self, Family(Partitions_n(n), StandardSuperTableaux_shape), category=FiniteEnumeratedSets(), facade=True, keepkey=False) self.size = Integer(n) def _repr_(self) -> str: @@ -688,8 +662,7 @@ def __contains__(self, x) -> bool: sage: 1 in StandardSuperTableaux(4) False """ - return (StandardSuperTableaux.__contains__(self, x) and - sum(map(len, x)) == self.size) + return StandardSuperTableaux.__contains__(self, x) and sum(map(len, x)) == self.size def cardinality(self): r""" @@ -756,8 +729,7 @@ def __contains__(self, x) -> bool: sage: 1 in StandardSuperTableaux([2,1,1]) False """ - return (StandardSuperTableaux.__contains__(self, x) and - [len(w) for w in x] == self.shape) + return StandardSuperTableaux.__contains__(self, x) and [len(w) for w in x] == self.shape def _repr_(self) -> str: """ @@ -814,5 +786,4 @@ def __iter__(self): """ pi = self.shape for tableau in StandardTableaux(pi): - yield self.element_class(self, [[PrimedEntry(ZZ(val) / 2) for val in row] - for row in tableau]) + yield self.element_class(self, [[PrimedEntry(ZZ(val) / 2) for val in row] for row in tableau]) diff --git a/src/sage/combinat/superpartition.py b/src/sage/combinat/superpartition.py index 4a12725301b..7a721329aa0 100644 --- a/src/sage/combinat/superpartition.py +++ b/src/sage/combinat/superpartition.py @@ -91,8 +91,7 @@ @richcmp_method -class SuperPartition(ClonableArray, - metaclass=InheritComparisonClasscallMetaclass): +class SuperPartition(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): r""" A super partition. @@ -118,6 +117,7 @@ class SuperPartition(ClonableArray, sage: sp.conjugate() [4, 2; ] """ + @staticmethod def __classcall_private__(cls, lst): r""" @@ -150,10 +150,8 @@ def __classcall_private__(cls, lst): if not lst: return SPs([[], []]) if isinstance(lst[0], (list, tuple)): - return SPs([[Integer(a) for a in lst[0]], - [Integer(a) for a in lst[1]]]) - return SPs([[-a for a in lst if a <= 0], - [a for a in lst if a > 0]]) + return SPs([[Integer(a) for a in lst[0]], [Integer(a) for a in lst[1]]]) + return SPs([[-a for a in lst if a <= 0], [a for a in lst if a > 0]]) def __init__(self, parent, lst, check=True, immutable=True): """ @@ -290,8 +288,7 @@ def _latex_(self) -> str: sage: latex(SuperPartition([[],[1]])) (; 1) """ - return ('(' + ','.join(str(a) for a in self.antisymmetric_part()) - + '; ' + ', '.join(str(a) for a in self.symmetric_part()) + ')') + return '(' + ','.join(str(a) for a in self.antisymmetric_part()) + '; ' + ', '.join(str(a) for a in self.symmetric_part()) + ')' def to_list(self) -> list: r""" @@ -476,8 +473,7 @@ def shape_circled_diagram(self) -> Partition: sage: SuperPartition([[2,1,0],[3,3]]).shape_circled_diagram() [3, 3, 3, 2, 1] """ - pi = sorted([a + 1 for a in self.antisymmetric_part()] + - self.symmetric_part(), reverse=True) + pi = sorted([a + 1 for a in self.antisymmetric_part()] + self.symmetric_part(), reverse=True) return Partition(pi) # type:ignore @staticmethod @@ -506,9 +502,7 @@ def from_circled_diagram(shape, corners) -> SuperPartition: sage: all(sp == from_cd(*sp.to_circled_diagram()) for sp in SuperPartitions(4)) True """ - data = [sorted([c[1] for c in corners], reverse=True), - [shape[i] for i in range(len(shape)) - if i not in [c[0] for c in corners]]] + data = [sorted([c[1] for c in corners], reverse=True), [shape[i] for i in range(len(shape)) if i not in [c[0] for c in corners]]] return SuperPartition(data) # type:ignore def to_circled_diagram(self) -> list: @@ -554,8 +548,7 @@ def conjugate(self) -> SuperPartition: True """ sd = self.to_circled_diagram() - return SuperPartition.from_circled_diagram(sd[0].conjugate(), - [(j, i) for i, j in sd[1]]) + return SuperPartition.from_circled_diagram(sd[0].conjugate(), [(j, i) for i, j in sd[1]]) def zee(self) -> Integer: r""" @@ -591,7 +584,7 @@ def sign(self) -> int: sage: sum(sp.sign()/sp.zee() for sp in SuperPartitions(6,0)) 0 """ - return (-1)**(self.degree() - len(self.symmetric_part())) + return (-1) ** (self.degree() - len(self.symmetric_part())) def dominates(self, other) -> bool: r""" @@ -612,9 +605,7 @@ def dominates(self, other) -> bool: sage: LA.dominates([[1],[1]*6]) False """ - return (self.degree() == sum(other[0]) + sum(other[1]) and - Partition(self.antisymmetric_part()).dominates(other[0]) and - Partition(self.symmetric_part()).dominates(other[1])) + return self.degree() == sum(other[0]) + sum(other[1]) and Partition(self.antisymmetric_part()).dominates(other[0]) and Partition(self.symmetric_part()).dominates(other[1]) def add_horizontal_border_strip_star(self, h) -> list: r""" @@ -654,11 +645,13 @@ def add_horizontal_border_strip_star(self, h) -> list: out = [] for elt in nsp: row_changed = [row1 - row2 for row1, row2 in zip(elt, sp1)] - new_sp = [elt, [(i[0] + 1, elt[i[0] + 1]) for i in circ_list - if row_changed[i[0]] != 0] - # TODO: Check that this is not supposed to be - # a tuple of size 1 - + [(i) for i in circ_list if row_changed[i[0]] == 0]] + new_sp = [ + elt, + [(i[0] + 1, elt[i[0] + 1]) for i in circ_list if row_changed[i[0]] != 0] + # TODO: Check that this is not supposed to be + # a tuple of size 1 + + [(i) for i in circ_list if row_changed[i[0]] == 0], + ] if len({k for j, k in new_sp[1]}) == len(new_sp[1]): out += [SuperPartition.from_circled_diagram(*new_sp)] return out @@ -734,8 +727,7 @@ def add_horizontal_border_strip_star_bar(self, h) -> list: x = reduce(lambda a, b: [item_a + item_b for item_a in a for item_b in b], ti[0]) for j in x: result += [[ti[1], list(zip(j, j[1:]))[::2]]] - return [SuperPartition.from_circled_diagram(*ti) - for ti in result if len(ti[1]) == len(self[0])] + return [SuperPartition.from_circled_diagram(*ti) for ti in result if len(ti[1]) == len(self[0])] class SuperPartitions(UniqueRepresentation, Parent): @@ -778,6 +770,7 @@ class SuperPartitions(UniqueRepresentation, Parent): sage: [[1,1],[2,1]] in SuperPartitions() False """ + @staticmethod def __classcall_private__(self, n=None, m=None, **kwargs): r""" @@ -865,18 +858,10 @@ class options(GlobalOptions): [-1, 0, 2, 2, 1] sage: SuperPartitions.options._reset() """, + NAME = 'SuperPartition' module = 'sage.combinat.superpartition' - display = dict(default='default', - description="Specifies how the super partitions should " - "be printed", - values=dict(list="the super partitions are displayed in " - "a list of two lists", - pair="the super partition is displayed as a " - "list of integers", - default="the super partition is displayed in " - "a form [fermionic part; bosonic part]"), - case_sensitive=False) + display = dict(default='default', description="Specifies how the super partitions should " "be printed", values=dict(list="the super partitions are displayed in " "a list of two lists", pair="the super partition is displayed as a " "list of integers", default="the super partition is displayed in " "a form [fermionic part; bosonic part]"), case_sensitive=False) def _element_constructor_(self, lst, check=True): """ @@ -905,11 +890,8 @@ def _element_constructor_(self, lst, check=True): if isinstance(lst, SuperPartition): lst = list(lst) if isinstance(lst[0], (list, tuple)): - return self.element_class(self, [lst[0], [a for a in lst[1] if a > 0]], - check=check) - return self.element_class(self, [[-a for a in lst if a <= 0], - [a for a in lst if a > 0]], - check=check) + return self.element_class(self, [lst[0], [a for a in lst[1] if a > 0]], check=check) + return self.element_class(self, [[-a for a in lst if a <= 0], [a for a in lst if a > 0]], check=check) def __contains__(self, x) -> bool: """ @@ -940,19 +922,14 @@ def __contains__(self, x) -> bool: return False if all(isinstance(i, (int, Integer)) or i in ZZ for i in x): sp = [a for a in x if a <= 0] - return (all(sp[i] > sp[i - 1] for i in range(1, len(sp))) - and [a for a in x if a > 0] in _Partitions) - if (len(x) == 2 and - isinstance(x[0], (list, tuple)) and - isinstance(x[1], (list, tuple))): + return all(sp[i] > sp[i - 1] for i in range(1, len(sp))) and [a for a in x if a > 0] in _Partitions + if len(x) == 2 and isinstance(x[0], (list, tuple)) and isinstance(x[1], (list, tuple)): for i in chain(x[0], x[1]): if i not in ZZ: return False if i < 0: return False - return (all(x[0][i] > x[0][i + 1] for i in range(len(x[0]) - 1)) - and all(x[1][i] >= x[1][i + 1] for i in range(len(x[1]) - 1)) - and ((not x[0]) or x[0][-1] >= 0) and ((not x[1]) or x[1][-1] >= 0)) + return all(x[0][i] > x[0][i + 1] for i in range(len(x[0]) - 1)) and all(x[1][i] >= x[1][i + 1] for i in range(len(x[1]) - 1)) and ((not x[0]) or x[0][-1] >= 0) and ((not x[1]) or x[1][-1] >= 0) return False diff --git a/src/sage/combinat/symmetric_group_algebra.py b/src/sage/combinat/symmetric_group_algebra.py index d86999fd83c..d273d21ccc3 100644 --- a/src/sage/combinat/symmetric_group_algebra.py +++ b/src/sage/combinat/symmetric_group_algebra.py @@ -39,8 +39,7 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ -lazy_import('sage.groups.perm_gps.permgroup_element', - 'PermutationGroupElement') +lazy_import('sage.groups.perm_gps.permgroup_element', 'PermutationGroupElement') # TODO: Remove this function and replace it with the class @@ -235,6 +234,7 @@ def SymmetricGroupAlgebra(R, W, category=None): [(), (1,2), (1,2,3)] """ from sage.rings.semirings.non_negative_integer_semiring import NN + if W in NN: W = Permutations(W) if category is None: @@ -296,7 +296,7 @@ def __init__(self, R, W, category): if W not in WeylGroups or W.cartan_type().type() != 'A': raise ValueError("W (=%s) should be a symmetric group or a nonnegative integer") rank = W.cartan_type().rank() - if rank == 0: # Ambiguous: n=0 or n=1? + if rank == 0: # Ambiguous: n=0 or n=1? # The following trick works for both SymmetricGroup(n) and # Permutations(n) and it's currently not possible to # construct the WeylGroup for n=0 @@ -305,11 +305,11 @@ def __init__(self, R, W, category): self.n = W.cartan_type().rank() + 1 self._idempotent_cache = {} category = category.Unital().FiniteDimensional().WithBasis().Cellular() - GroupAlgebra_class.__init__(self, R, W, prefix='', - latex_prefix='', category=category) + GroupAlgebra_class.__init__(self, R, W, prefix='', latex_prefix='', category=category) # Mixin class for extra methods for representations from sage.combinat.specht_module import SymmetricGroupRepresentation + self._representation_mixin_class = SymmetricGroupRepresentation def _repr_(self): @@ -370,24 +370,21 @@ def _coerce_map_from_(self, S): + (1,3,2) + (1,3,4,2) + (1,3,4) + (1,4,3,2) + (1,4,2) + (1,4) """ # Symmetric group algebras of smaller rank - if (isinstance(S, SymmetricGroupAlgebra_n) and S.n <= self.n and - self.base_ring().has_coerce_map_from(S.base_ring())): + if isinstance(S, SymmetricGroupAlgebra_n) and S.n <= self.n and self.base_ring().has_coerce_map_from(S.base_ring()): return S.canonical_embedding(self) # Descent algebras from sage.combinat.descent_algebra import DescentAlgebra + # TODO: A better way to handle all of the bases if isinstance(S, (DescentAlgebra.D, DescentAlgebra.B, DescentAlgebra.I)): # Same rank and base ring, just the natural morphism - if (S.realization_of()._n == self.n and - self.base_ring() == S.base_ring() and - self._indices == Permutations(self.n)): + if S.realization_of()._n == self.n and self.base_ring() == S.base_ring() and self._indices == Permutations(self.n): return S.to_symmetric_group_algebra # Otherwise compose with the canonical embedding in order to ensure # that the right base ring and the right index set are being used. # Slightly hacky! - if (S.realization_of()._n <= self.n and - self.base_ring().has_coerce_map_from(S.base_ring())): + if S.realization_of()._n <= self.n and self.base_ring().has_coerce_map_from(S.base_ring()): phi = S.to_symmetric_group_algebra return phi.codomain().canonical_embedding(self) * phi @@ -412,8 +409,7 @@ def _element_constructor_(self, x): if isinstance(x, Permutation): return self.monomial_from_smaller_permutation(x) if isinstance(x, PermutationGroupElement): - return self.monomial_from_smaller_permutation( - from_permutation_group_element(x)) + return self.monomial_from_smaller_permutation(from_permutation_group_element(x)) return super()._element_constructor_(x) @@ -442,8 +438,7 @@ def _sibling(self, n): try: W = self.basis().keys().__class__(n) except (AttributeError, TypeError, ValueError): - raise NotImplementedError("Constructing the sibling algebra of a different order " - "only implemented for PermutationGroup and SymmetricGroup") + raise NotImplementedError("Constructing the sibling algebra of a different order " "only implemented for PermutationGroup and SymmetricGroup") return SymmetricGroupAlgebra(self.base_ring(), W) # _repr_ customization: output the basis element indexed by [1,2,3] as [1,2,3] @@ -502,8 +497,7 @@ def left_action_product(self, left, right): if not isinstance(self._indices, Permutations): return b * a P = Permutations(self.n) - return self.sum_of_terms([(P(left_action_same_n(p._list, q._list)), x * y) - for (p, x) in a for (q, y) in b]) + return self.sum_of_terms([(P(left_action_same_n(p._list, q._list)), x * y) for (p, x) in a for (q, y) in b]) # Why did we use left_action_same_n instead of # left_action_product? # Because having cast a and b into self, we already know that @@ -564,8 +558,7 @@ def right_action_product(self, left, right): if not isinstance(self._indices, Permutations): return a * b P = Permutations(self.n) - return self.sum_of_terms([(P(right_action_same_n(p._list, q._list)), x * y) - for (p, x) in a for (q, y) in b]) + return self.sum_of_terms([(P(right_action_same_n(p._list, q._list)), x * y) for (p, x) in a for (q, y) in b]) # Why did we use right_action_same_n instead of # right_action_product? # Because having cast a and b into self, we already know that @@ -691,9 +684,7 @@ def antipode(self, x): sage: ZS3.antipode(-ZS3(Permutation([2, 3, 1]))) -[3, 1, 2] """ - return self.sum_of_terms([(p.inverse(), coeff) for - (p, coeff) in self(x)], - distinct=True) + return self.sum_of_terms([(p.inverse(), coeff) for (p, coeff) in self(x)], distinct=True) @cached_method def cell_poset(self): @@ -707,6 +698,7 @@ def cell_poset(self): Finite poset containing 5 elements """ from sage.combinat.posets.posets import Poset + return Poset([Partitions_n(self.n), lambda x, y: y.dominates(x)]) def cell_module_indices(self, la): @@ -766,6 +758,7 @@ def _from_cellular_index(self, x): if SGA.basis().keys() is P: # Indexed by permutations return func(x[1], x[2]) from sage.groups.perm_gps.permgroup_named import SymmetricGroup + if P == SymmetricGroup(self.n): return func(x[1], x[2]) ret = func(x[1], x[2], mult='r2l') @@ -773,8 +766,7 @@ def _from_cellular_index(self, x): return self(ret) except TypeError: P = self.basis().keys() - return self._from_dict({P(i.to_matrix()): c for i, c in ret}, - remove_zeros=False) + return self._from_dict({P(i.to_matrix()): c for i, c in ret}, remove_zeros=False) def cell_module(self, la, **kwds): """ @@ -857,7 +849,7 @@ def retract_plain(self, f, m): I = RSm.group() pairs = [] P = Permutations(self.n) - for (p, coeff) in f.monomial_coefficients().items(): + for p, coeff in f.monomial_coefficients().items(): p_ret = P(p).retract_plain(m) if p_ret is not None: pairs.append((I(p_ret), coeff)) @@ -923,7 +915,7 @@ def retract_direct_product(self, f, m): I = RSm.group() dct = {} P = Permutations(self.n) - for (p, coeff) in f.monomial_coefficients().items(): + for p, coeff in f.monomial_coefficients().items(): p_ret = P(p).retract_direct_product(m) if p_ret is not None: p_ret = I(p_ret) @@ -986,7 +978,7 @@ def retract_okounkov_vershik(self, f, m): I = RSm.group() dct = {} P = Permutations(self.n) - for (p, coeff) in f.monomial_coefficients().items(): + for p, coeff in f.monomial_coefficients().items(): p_ret = I(P(p).retract_okounkov_vershik(m)) if p_ret not in dct: dct[p_ret] = coeff @@ -1056,8 +1048,7 @@ def central_orthogonal_idempotents(self): - :meth:`central_orthogonal_idempotent` """ - return [self.central_orthogonal_idempotent(key) - for key in sorted(self._blocks_dictionary, reverse=True)] + return [self.central_orthogonal_idempotent(key) for key in sorted(self._blocks_dictionary, reverse=True)] def central_orthogonal_idempotent(self, la, block=True): r""" @@ -1170,6 +1161,7 @@ def central_orthogonal_idempotent(self, la, block=True): from sage.data_structures.blas_dict import iaxpy from sage.libs.gap.libgap import libgap + G = self._indices character_table = [c.sage() for c in libgap.Irr(libgap.SymmetricGroup(self.n))] Pn = Partitions_n(self.n) @@ -1182,8 +1174,7 @@ def central_orthogonal_idempotent(self, la, block=True): la_index = indices[la] big_coeff = character_table[la_index][0] / factorial(self.n) character_row = character_table[la_index] - cpi = {g: big_coeff * character_row[indices[g.cycle_type()]] - for g in G} + cpi = {g: big_coeff * character_row[indices[g.cycle_type()]] for g in G} else: # We compute the cycle types of the permutations cycles = {} @@ -1200,10 +1191,7 @@ def central_orthogonal_idempotent(self, la, block=True): lam_index = indices[lam] big_coeff = character_table[lam_index][0] / denom character_row = character_table[lam_index] - iaxpy(1, - {g: big_coeff * character_row[ind] - for ind in cycles for g in cycles[ind]}, - cpi) + iaxpy(1, {g: big_coeff * character_row[ind] for ind in cycles for g in cycles[ind]}, cpi) if not all(R(cpi[g].denominator()) for g in cpi): return None @@ -1344,14 +1332,13 @@ def ladder_idempotent(self, la): raise ValueError(f"{la} is not {p}-ladder restricted") Tclass = Tlad.residue_sequence(p).standard_tableaux() Elad = sum(epsilon_ik(T, T) for T in Tclass) - Elad = self.element_class(self, {sigma: R(c) - for sigma, c in Elad._monomial_coefficients.items()}) + Elad = self.element_class(self, {sigma: R(c) for sigma, c in Elad._monomial_coefficients.items()}) from sage.groups.perm_gps.permgroup_named import SymmetricGroup + YG = SymmetricGroup(n).young_subgroup(alpha) coeff = ~R.prod(factorial(val) for val in alpha) G = self.group() - eprod = self.element_class(self, {G(list(elt.tuple())): coeff - for elt in YG}) + eprod = self.element_class(self, {G(list(elt.tuple())): coeff for elt in YG}) return Elad * eprod @cached_method @@ -1387,6 +1374,7 @@ def algebra_generators(self): sage: M.register_as_coercion() """ from sage.sets.family import Family + if self.n <= 1: return Family([]) a = list(range(1, self.n + 1)) @@ -1490,8 +1478,7 @@ def rsw_shuffling_element(self, k): """ P = self.basis().keys() I = Permutations(self.n) - return self.sum_of_terms([(p, I(p).number_of_noninversions(k)) for p in P], - distinct=True) + return self.sum_of_terms([(p, I(p).number_of_noninversions(k)) for p in P], distinct=True) def semi_rsw_element(self, k): r""" @@ -1576,10 +1563,10 @@ def complement(xs): for x in xs: res.remove(x) return res + P = Permutations(n) I = self._indices - return self.sum_of_monomials([I(P(complement(q) + list(q))) - for q in itertools.permutations(range(1, n + 1), int(n - k))]) + return self.sum_of_monomials([I(P(complement(q) + list(q))) for q in itertools.permutations(range(1, n + 1), int(n - k))]) def binary_unshuffle_sum(self, k): r""" @@ -1669,9 +1656,9 @@ def complement(xs): for x in xs: res.remove(x) return res + P = Permutations(n) - return self.sum_of_monomials([self._indices(P(list(q) + complement(q))) - for q in itertools.combinations(range(1, n + 1), int(k))]) + return self.sum_of_monomials([self._indices(P(list(q) + complement(q))) for q in itertools.combinations(range(1, n + 1), int(k))]) def specht_module(self, D): r""" @@ -1693,6 +1680,7 @@ def specht_module(self, D): s[2, 2, 1] + s[3, 1, 1] + s[3, 2] """ from sage.combinat.specht_module import SpechtModule + return SpechtModule(self, D) def tabloid_module(self, D): @@ -1714,6 +1702,7 @@ def tabloid_module(self, D): s[3, 1, 1] + s[3, 2] + 2*s[4, 1] + s[5] """ from sage.combinat.specht_module import TabloidModule + return TabloidModule(self, D) def specht_module_dimension(self, D): @@ -1729,6 +1718,7 @@ def specht_module_dimension(self, D): 16 """ from sage.combinat.specht_module import _to_diagram, specht_module_spanning_set + D = _to_diagram(D) span_set = specht_module_spanning_set(D, self) return matrix(self.base_ring(), [v.to_vector() for v in span_set]).rank() @@ -1776,6 +1766,7 @@ def simple_module(self, la): (6, 0, -2, 0, 1) """ from sage.combinat.specht_module import SpechtModule + return SpechtModule(self, la).simple_module() def simple_module_dimension(self, la): @@ -1800,6 +1791,7 @@ def simple_module_dimension(self, la): if sum(la) != self.n: raise ValueError(f"{la} is not a partition of {self.n}") from sage.combinat.specht_module import simple_module_rank + return simple_module_rank(la, self.base_ring()) def garsia_procesi_module(self, la): @@ -1815,6 +1807,7 @@ def garsia_procesi_module(self, la): Garsia-Procesi module of shape [2, 2, 1, 1] over Finite Field of size 2 """ from sage.combinat.symmetric_group_representations import GarsiaProcesiModule + return GarsiaProcesiModule(self, la) def jucys_murphy(self, k): @@ -2027,9 +2020,7 @@ def seminormal_basis(self, mult='l2r'): basis = [] for part in Partitions_n(self.n): stp = StandardTableaux_shape(part) - basis.extend(self.epsilon_ik(t1, t2, mult=mult) - for t1 in stp - for t2 in stp) + basis.extend(self.epsilon_ik(t1, t2, mult=mult) for t1 in stp for t2 in stp) return basis def dft(self, form=None, mult='l2r'): @@ -2182,10 +2173,10 @@ def _dft_unitary(self): if F.characteristic() == 0: from sage.misc.functional import sqrt from sage.rings.number_field.number_field import NumberField + dft_matrix = self.dft() n = dft_matrix.nrows() - diag = [sum(dft_matrix[i, j] * dft_matrix[i, j].conjugate() for j in range(n)) - for i in range(n)] + diag = [sum(dft_matrix[i, j] * dft_matrix[i, j].conjugate() for j in range(n)) for i in range(n)] primes_needed = {factor for d in diag for factor, _ in d.squarefree_part().factor()} names = [f"sqrt{factor}" for factor in primes_needed] x = PolynomialRing(QQ, 'x').gen() @@ -2539,8 +2530,7 @@ def _column_antistabilizer(self, la): T = Tableau(T) G = self.group() R = self.base_ring() - return self._from_dict({G(list(w.tuple())): R(w.sign()) for w in T.column_stabilizer()}, - remove_zeros=False) + return self._from_dict({G(list(w.tuple())): R(w.sign()) for w in T.column_stabilizer()}, remove_zeros=False) @cached_method def _young_symmetrizer(self, la): @@ -2617,13 +2607,16 @@ def kazhdan_lusztig_basis_element(self, w): [3, 2, 1] [1, 2, 3] + [1, 3, 2] + [2, 1, 3] + [2, 3, 1] + [3, 1, 2] + [3, 2, 1] """ from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet + G = self.basis().keys() R = self.base_ring() one = R.one() # check if the KL polynomials can be computed using ``coxeter3`` from sage.features.coxeter3 import Coxeter3 + if Coxeter3().is_present(): from sage.libs.coxeter3.coxeter_group import CoxeterGroup as Coxeter3Group + self._cellular_KL = Coxeter3Group(['A', self.n + 1]) self._KLG = self._cellular_KL polyfunc = self._cellular_KL.kazhdan_lusztig_polynomial @@ -2631,6 +2624,7 @@ def kazhdan_lusztig_basis_element(self, w): # Fallback to using the KL polynomial from sage.combinat.kazhdan_lusztig import KazhdanLusztigPolynomial from sage.groups.perm_gps.permgroup_named import SymmetricGroup + q = PolynomialRing(R, 'q').gen() self._KLG = SymmetricGroup(self.n) self._cellular_KL = KazhdanLusztigPolynomial(self._KLG, q) @@ -2639,8 +2633,7 @@ def kazhdan_lusztig_basis_element(self, w): if w.parent() is not self._KLG: w = self._KLG.from_reduced_word(w.reduced_word()) bruhat = RecursivelyEnumeratedSet([w], lambda u: u.bruhat_lower_covers(), structure='graded') - return self.element_class(self, {G.from_reduced_word(v.reduced_word()): R(c(q=one)) - for v in bruhat if (c := polyfunc(v, w))}) + return self.element_class(self, {G.from_reduced_word(v.reduced_word()): R(c(q=one)) for v in bruhat if (c := polyfunc(v, w))}) epsilon_ik_cache = {} @@ -2695,8 +2688,7 @@ def epsilon_ik(itab, ktab, star=0): eik = e_ik(it, kt, star) QSn = eik.parent() mul = QSn.right_action_product - epsilon_ik_cache[(it, kt)] = mul(mul(epsilon(it, star + 1), eik), - epsilon(kt, star + 1)) * (1 / kappa(it.shape())) + epsilon_ik_cache[(it, kt)] = mul(mul(epsilon(it, star + 1), eik), epsilon(kt, star + 1)) * (1 / kappa(it.shape())) res = epsilon_ik_cache[(it, kt)] return res @@ -2742,8 +2734,7 @@ def epsilon(tab, star=0): et = e(t) QSn = et.parent() mul = QSn.right_action_product - epsilon_cache[t] = mul(mul(epsilon(t, 1), e(t)), - epsilon(t, 1)) * (1 / kappa(t.shape())) + epsilon_cache[t] = mul(mul(epsilon(t, 1), e(t)), epsilon(t, 1)) * (1 / kappa(t.shape())) res = epsilon_cache[t] return res @@ -3229,6 +3220,7 @@ class SGACellularBasis(CellularBasis): r""" A cellular basis of the symmetric group algebra. """ + def __init__(self, SGA): r""" Initialize ``self``. @@ -3327,6 +3319,7 @@ class MurphyBasis(SGACellularBasis): - [DJM1998]_ - [Mathas2004]_ """ + _name = "Murphy" def _to_sga(self, ind): @@ -3368,6 +3361,7 @@ class KLCellularBasis(SGACellularBasis): [4, 1] 4 4 [5] 1 1 """ + _name = "Kazhdan-Lusztig" def _to_sga(self, ind): @@ -3388,6 +3382,7 @@ def _to_sga(self, ind): ([3], [[1, 2, 3]], [[1, 2, 3]]) [1, 2, 3] """ from sage.combinat.rsk import RSK_inverse + S = ind[1] T = ind[2] w = RSK_inverse(T, S, output='permutation') @@ -3510,9 +3505,7 @@ def __init__(self, R, n, q=None): self._q = q - CombinatorialFreeModule.__init__(self, R, self._indices, - category=AlgebrasWithBasis(R), - prefix="") + CombinatorialFreeModule.__init__(self, R, self._indices, category=AlgebrasWithBasis(R), prefix="") _repr_option_bracket = False @@ -3562,11 +3555,9 @@ def _element_constructor_(self, x): return self.one() if x in Permutations(): if len(x) < self.n: - return self.monomial(self._indices( - list(x) + list(range(len(x) + 1, self.n + 1)) - )) + return self.monomial(self._indices(list(x) + list(range(len(x) + 1, self.n + 1)))) if all(x[i] == i + 1 for i in range(self.n, len(x))): - return self.monomial(self._indices(x[:self.n])) + return self.monomial(self._indices(x[: self.n])) return self._indices(x) @@ -3634,8 +3625,10 @@ def t_action(self, a, i): sage: H3.t(1)*a q*T[1, 2, 3] + (q+1)*T[2, 1, 3] """ + def t_i(x): return self.t_action_on_basis(x, i) + return self._apply_module_endomorphism(a, t_i) def product_on_basis(self, perm1, perm2): @@ -3680,8 +3673,7 @@ def t(self, i): raise ValueError(f"i (= {i}) must be between 1 and n-1 (= {self.n - 1})") P = self.basis().keys() - return self.monomial(P(list(range(1, i)) + [i + 1, i] + - list(range(i + 2, self.n + 1)))) + return self.monomial(P(list(range(1, i)) + [i + 1, i] + list(range(i + 2, self.n + 1)))) # The permutation here is simply the transposition (i, i+1). def algebra_generators(self): @@ -3745,12 +3737,8 @@ def jucys_murphy(self, k): q = self.q() P = self._indices - v = self.sum_of_terms(((P(list(range(1, l)) + [k] + - list(range(l + 1, k)) + [l]), - q**l - q**(l - 1)) - for l in range(1, k)), - distinct=True) - v += q**(k - 1) * self.one() + v = self.sum_of_terms(((P(list(range(1, l)) + [k] + list(range(l + 1, k)) + [l]), q**l - q ** (l - 1)) for l in range(1, k)), distinct=True) + v += q ** (k - 1) * self.one() return v # old algorithm: @@ -3763,9 +3751,5 @@ def jucys_murphy(self, k): # For unpickling backward compatibility (Sage <= 4.1) -register_unpickle_override('sage.combinat.symmetric_group_algebra', - 'HeckeAlgebraSymmetricGroupElement_t', - CombinatorialFreeModule.Element) -register_unpickle_override('sage.combinat.symmetric_group_algebra', - 'SymmetricGroupAlgebraElement_n', - CombinatorialFreeModule.Element) +register_unpickle_override('sage.combinat.symmetric_group_algebra', 'HeckeAlgebraSymmetricGroupElement_t', CombinatorialFreeModule.Element) +register_unpickle_override('sage.combinat.symmetric_group_algebra', 'SymmetricGroupAlgebraElement_n', CombinatorialFreeModule.Element) diff --git a/src/sage/combinat/symmetric_group_representations.py b/src/sage/combinat/symmetric_group_representations.py index 59a04947afc..5cfef103457 100644 --- a/src/sage/combinat/symmetric_group_representations.py +++ b/src/sage/combinat/symmetric_group_representations.py @@ -52,8 +52,7 @@ # #### Constructor function ################################################ -def SymmetricGroupRepresentation(partition, implementation='specht', - ring=None, cache_matrices=True): +def SymmetricGroupRepresentation(partition, implementation='specht', ring=None, cache_matrices=True): r""" The irreducible representation of the symmetric group corresponding to ``partition``. @@ -192,13 +191,11 @@ def SymmetricGroupRepresentation(partition, implementation='specht', - Franco Saliola (2009-04-23) """ partition = Partition(partition) - Rep = SymmetricGroupRepresentations(sum(partition), implementation=implementation, - ring=ring, cache_matrices=cache_matrices) + Rep = SymmetricGroupRepresentations(sum(partition), implementation=implementation, ring=ring, cache_matrices=cache_matrices) return Rep(partition) -def SymmetricGroupRepresentations(n, implementation='specht', ring=None, - cache_matrices=True): +def SymmetricGroupRepresentations(n, implementation='specht', ring=None, cache_matrices=True): r""" Irreducible representations of the symmetric group. @@ -293,6 +290,7 @@ def SymmetricGroupRepresentations(n, implementation='specht', ring=None, return UnitaryRepresentations(n, ring=ring, cache_matrices=cache_matrices) raise NotImplementedError("only seminormal, orthogonal and specht are implemented") + # #### Generic classes for symmetric group representations ################# @@ -300,6 +298,7 @@ class SymmetricGroupRepresentation_generic_class(Element): r""" Generic methods for a representation of the symmetric group. """ + _default_ring = None def __init__(self, parent, partition): @@ -492,12 +491,13 @@ def to_character(self): [4, 2, 2, 1, 1, 2, 2, 0, 1, 0, 0, 1, 1, 0, 2, 1, 0, 0, 0, 1, 1, 2, 0, 0] """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup + Sym = SymmetricGroup(sum(self._partition)) values = [self(g).trace() for g in Sym.conjugacy_classes_representatives()] return Sym.character(values) -class SymmetricGroupRepresentations_class(UniqueRepresentation,Parent): +class SymmetricGroupRepresentations_class(UniqueRepresentation, Parent): r""" Generic methods for the CombinatorialClass of irreducible representations of the symmetric group. @@ -567,6 +567,7 @@ def __iter__(self): for partition in Partitions(self._n): yield self.element_class(self, partition) + # #### Young's Seminormal Representation ################################### @@ -574,6 +575,7 @@ class YoungRepresentation_generic(SymmetricGroupRepresentation_generic_class): r""" Generic methods for Young's representations of the symmetric group. """ + @lazy_attribute def _yang_baxter_graph(self): r""" @@ -589,8 +591,7 @@ def _yang_baxter_graph(self): Y = YangBaxterGraph_partition(self._partition) n = self._n # relabel vertices with "vector of contents" - Y.relabel_vertices(partition_to_vector_of_contents(self._partition, - reverse=True)) + Y.relabel_vertices(partition_to_vector_of_contents(self._partition, reverse=True)) # relabel edges with "differences" edge_relabel_dict = {} for u, v, op in Y.edges(): @@ -621,8 +622,7 @@ def _tableau_dict(self): for u, w, (i, _) in self._yang_baxter_graph._edges_in_bfs(): # TODO: improve the following si = PermutationConstructor((i, i + 1)) - tableau_dict[w] = Tableau([[si(b) for b in row] - for row in tableau_dict[u]]) + tableau_dict[w] = Tableau([[si(b) for b in row] for row in tableau_dict[u]]) return tableau_dict @lazy_attribute @@ -641,8 +641,7 @@ def _word_dict(self): (2, 0, -1, 1, 0): (3, 4, 1, 2, 5), (2, 0, 1, -1, 0): (2, 4, 1, 3, 5)} """ - return {v: sum(reversed(t), ()) - for v, t in self._tableau_dict.items()} + return {v: sum(reversed(t), ()) for v, t in self._tableau_dict.items()} @cached_method def representation_matrix_for_simple_transposition(self, i): @@ -669,17 +668,17 @@ def representation_matrix_for_simple_transposition(self, i): [ 1/2 1/2] """ from copy import copy + if not (1 <= i < sum(self._partition)): raise TypeError Y = self._yang_baxter_graph index_lookup = {b: a for a, b in enumerate(list(Y))} digraph = copy(Y._digraph) - digraph.delete_edges((u, v) for (u, v, (j, beta)) in digraph.edges(sort=True) - if j != i) + digraph.delete_edges((u, v) for (u, v, (j, beta)) in digraph.edges(sort=True) if j != i) M = matrix(self._ring, digraph.n_vertices()) for g in digraph.connected_components_subgraphs(): if g.n_vertices() == 1: - v, = g.vertices(sort=True) + (v,) = g.vertices(sort=True) w = self._word_dict[v] trivial = None for j, a in enumerate(w): @@ -692,11 +691,10 @@ def representation_matrix_for_simple_transposition(self, i): j = index_lookup[v] M[j, j] = 1 if trivial is True else -1 else: - (u, v, (j, beta)), = g.edges(sort=True) + ((u, v, (j, beta)),) = g.edges(sort=True) iu = index_lookup[u] iv = index_lookup[v] - M[iu, iu], M[iu, iv], M[iv, iu], M[iv, iv] = \ - self._2x2_matrix_entries(self._ring(beta)) + M[iu, iu], M[iu, iv], M[iv, iu], M[iv, iv] = self._2x2_matrix_entries(self._ring(beta)) return M def _representation_matrix_uncached(self, permutation): @@ -811,6 +809,7 @@ def _repr_(self): """ return "Seminormal representations of the symmetric group of order %s! over %s" % (self._n, self._ring) + # #### Young's Orthogonal Representation ################################### @@ -862,6 +861,7 @@ def _repr_(self): """ return "Orthogonal representations of the symmetric group of order %s! over %s" % (self._n, self._ring) + # #### Specht Representation ############################################### @@ -1035,6 +1035,7 @@ def _repr_(self): """ return "Specht representations of the symmetric group of order %s! over %s" % (self._n, self._ring) + # #### Unitary Representation ############################################### @@ -1050,6 +1051,7 @@ class UnitaryRepresentation(SymmetricGroupRepresentation_generic_class): Cholesky decomposition of the unique solution `U` to the equation `\rho(g)^T U \rho(g) = U` for all `g` in `G`. """ + def __init__(self, parent, partition): r""" Initialize ``self``. @@ -1070,11 +1072,10 @@ def __init__(self, parent, partition): self.representation_matrix = orth.representation_matrix self._representation_matrix_uncached = orth._representation_matrix_uncached else: - if not (parent._ring.is_field() - and parent._ring.is_finite() - and parent._ring.order().is_square()): + if not (parent._ring.is_field() and parent._ring.is_finite() and parent._ring.order().is_square()): raise ValueError("the base ring must be a finite field of square order") from sage.arith.misc import factorial + if parent._ring.characteristic().divides(factorial(parent._n)): raise NotImplementedError("not implemented when p|n!; dimension of invariant forms may be greater than one") self._q = parent._ring.order().sqrt() @@ -1146,6 +1147,7 @@ def _unitary_change_basis_matrix(self): [ 0 2*z2 + 2] """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + G = Permutations(self._n) F = self._ring rho = self._specht.representation_matrix @@ -1227,6 +1229,7 @@ def _repr_(self): """ return "Unitary representations of the symmetric group of order %s! over %s" % (self._n, self._ring) + # ##### Miscellaneous functions ############################################ @@ -1324,6 +1327,7 @@ class GarsiaProcesiModule(UniqueRepresentation, QuotientRing_generic, SymmetricG sage: set(top_deg) == set(yamanouchi) True """ + @staticmethod def __classcall_private__(cls, SGA, shape): """ @@ -1368,26 +1372,26 @@ def __init__(self, SGA, shape): from sage.combinat.sf.sf import SymmetricFunctions from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from itertools import combinations + n = SGA.n conj = list(shape.conjugate()) - conj += [0]*(n - len(conj)) + conj += [0] * (n - len(conj)) def p(k): - return sum(conj[i] for i in range(n-k, n)) + return sum(conj[i] for i in range(n - k, n)) BR = SGA.base_ring() R = PolynomialRing(BR, 'x', n) gens = R.gens() e = SymmetricFunctions(BR).e() - I = R.ideal([e[d].expand(k)(*S) - for k in range(n+1) for d in range(k-p(k)+1, k+1) - for S in combinations(gens, k)]) + I = R.ideal([e[d].expand(k)(*S) for k in range(n + 1) for d in range(k - p(k) + 1, k + 1) for S in combinations(gens, k)]) # Finalize the initialization names = tuple([f"gp{i}" for i in range(n)]) from sage.categories.commutative_rings import CommutativeRings from sage.categories.algebras import Algebras + cat = CommutativeRings().Quotients() & Algebras(SGA.base_ring()).Graded().WithBasis().FiniteDimensional() QuotientRing_generic.__init__(self, R, I, names=names, category=cat) @@ -1420,6 +1424,7 @@ def _latex_(self): }}^{\Bold{Q}} """ from sage.misc.latex import latex + return "R_{{{}}}^{{{}}}".format(latex(self._shape), latex(self.base_ring())) def _coerce_map_from_base_ring(self): @@ -1462,6 +1467,7 @@ def basis(self): Family (gp2*gp3, gp1*gp3, gp3, gp2, gp1, 1) """ from sage.sets.family import Family + B = self.defining_ideal().normal_basis() return Family([self.retract(b) for b in B]) @@ -1536,6 +1542,7 @@ def graded_frobenius_image(self): ....: assert f.map_coefficients(lambda c: R(c(~q)*q^d)) == s(Qp[la]) """ from sage.combinat.sf.sf import SymmetricFunctions + R = QQ['q'] q = R.gen() Sym = SymmetricFunctions(R) @@ -1544,10 +1551,7 @@ def graded_frobenius_image(self): G = self._semigroup CCR = [(elt, elt.cycle_type()) for elt in G.conjugacy_classes_representatives()] B = self.basis() - return s(p._from_dict({la: coeff / la.centralizer_size() for elt, la in CCR - if (coeff := sum(q**b.degree() * (elt * b).lift().monomial_coefficient(b.lift()) - for b in B))}, - remove_zeros=False)) + return s(p._from_dict({la: coeff / la.centralizer_size() for elt, la in CCR if (coeff := sum(q ** b.degree() * (elt * b).lift().monomial_coefficient(b.lift()) for b in B))}, remove_zeros=False)) @cached_method def graded_character(self): @@ -1571,9 +1575,8 @@ def graded_character(self): G = self._semigroup B = self.basis() from sage.modules.free_module_element import vector - return vector([sum(q**b.degree() * (g * b).lift().monomial_coefficient(b.lift()) for b in B) - for g in G.conjugacy_classes_representatives()], - immutable=True) + + return vector([sum(q ** b.degree() * (g * b).lift().monomial_coefficient(b.lift()) for b in B) for g in G.conjugacy_classes_representatives()], immutable=True) @lazy_attribute def _graded_decomposition(self): @@ -1597,8 +1600,7 @@ def _graded_decomposition(self): d[deg] = [b] else: d[deg].append(b) - return {deg: self.subrepresentation(gens, is_closed=True) - for deg, gens in sorted(d.items())} + return {deg: self.subrepresentation(gens, is_closed=True) for deg, gens in sorted(d.items())} def graded_decomposition(self, k=None): r""" @@ -1664,8 +1666,7 @@ def graded_representation_matrix(self, elt, q=None): if q is None: q = self.base_ring()['q'].gen() R = q.parent() - return matrix(R, [q**b.degree() * (elt * b).to_vector().change_ring(R) - for b in self.basis()]) + return matrix(R, [q ** b.degree() * (elt * b).to_vector().change_ring(R) for b in self.basis()]) def graded_brauer_character(self): r""" @@ -1708,12 +1709,11 @@ def _acted_upon_(self, scalar, self_on_left=True): return super()._acted_upon_(scalar, self_on_left) if scalar in P._semigroup: gens = P.ambient().gens() - return P.retract(self.lift().subs({g: gens[scalar(i+1)-1] for i, g in enumerate(gens)})) + return P.retract(self.lift().subs({g: gens[scalar(i + 1) - 1] for i, g in enumerate(gens)})) if not self_on_left and scalar in P._semigroup_algebra: scalar = P._semigroup_algebra(scalar) gens = P.ambient().gens() - return P.sum(c * P.retract(self.lift().subs({g: gens[sigma(i+1)-1] for i, g in enumerate(gens)})) - for sigma, c in scalar.monomial_coefficients(copy=False).items()) + return P.sum(c * P.retract(self.lift().subs({g: gens[sigma(i + 1) - 1] for i, g in enumerate(gens)})) for sigma, c in scalar.monomial_coefficients(copy=False).items()) return super()._acted_upon_(scalar, self_on_left) def to_vector(self, order=None): diff --git a/src/sage/combinat/t_sequences.py b/src/sage/combinat/t_sequences.py index c0ee67434f4..8a5f57b62f3 100644 --- a/src/sage/combinat/t_sequences.py +++ b/src/sage/combinat/t_sequences.py @@ -111,7 +111,7 @@ def is_skew(seq, verbose=False): return False for i in range(n): - if seq[i] != -seq[n-i-1]: + if seq[i] != -seq[n - i - 1]: if verbose: print(f'Constraint not satisfied at index {i}') return False @@ -157,7 +157,7 @@ def is_symmetric(seq, verbose=False) -> bool: return False for i in range(n): - if seq[i] != seq[n-i-1]: + if seq[i] != seq[n - i - 1]: if verbose: print(f'Constraint not satisfied at index {i}') return False @@ -284,10 +284,8 @@ def turyn_sequences_smallcases(l, existence=False): 6: [[1, 1, 1, -1, -1, -1], [1, 1, -1, 1, -1, 1], [1, 1, -1, 1, 1], [1, 1, -1, 1, 1]], 7: [[1, 1, 1, -1, 1, 1, 1], [1, 1, -1, -1, -1, 1, -1], [1, 1, -1, 1, -1, -1], [1, 1, -1, 1, -1, -1]], 8: [[1, 1, -1, 1, -1, 1, -1, -1], [1, 1, 1, 1, -1, -1, -1, 1], [1, 1, 1, -1, 1, 1, 1], [1, -1, -1, 1, -1, -1, 1]], - 13: [[1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, 1], [1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1], - [1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1], [1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1]], - 15: [[1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1], [1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1], - [1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1], [1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1]], + 13: [[1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, 1], [1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1], [1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1], [1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1]], + 15: [[1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1], [1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1], [1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1], [1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1]], } if existence: @@ -371,8 +369,8 @@ def zero_seq(n): X1 = Sequence(seq_sum(A, B) + zero_seq(n)) X2 = Sequence(seq_subtract(A, B) + zero_seq(n)) - X3 = Sequence(zero_seq(n+p) + seq_sum(C, D)) - X4 = Sequence(zero_seq(n+p) + seq_subtract(C, D)) + X3 = Sequence(zero_seq(n + p) + seq_sum(C, D)) + X4 = Sequence(zero_seq(n + p) + seq_subtract(C, D)) res = [X1, X2, X3, X4] if check: @@ -430,7 +428,7 @@ def T_sequences_construction_from_turyn_sequences(turyn_sequences, check=True): X, U, Y, V = turyn_sequences l = len(X) - assert len(X) == len(U) == len(Y)+1 == len(V)+1 + assert len(X) == len(U) == len(Y) + 1 == len(V) + 1 def zero_seq(n): return [0 for _ in range(n)] @@ -439,15 +437,15 @@ def interleave(seq1, seq2): res = [] for i in range(len(seq1) + len(seq2)): if i % 2 == 0: - res.append(seq1[i//2]) + res.append(seq1[i // 2]) else: - res.append(seq2[i//2]) + res.append(seq2[i // 2]) return res - X1 = Sequence([1] + zero_seq(4*l-2)) - X2 = Sequence([0] + interleave(X, Y) + zero_seq(2*l-1)) - X3 = Sequence(zero_seq(2*l) + interleave(U, zero_seq(l-1))) - X4 = Sequence(zero_seq(2*l) + interleave(zero_seq(l), V)) + X1 = Sequence([1] + zero_seq(4 * l - 2)) + X2 = Sequence([0] + interleave(X, Y) + zero_seq(2 * l - 1)) + X3 = Sequence(zero_seq(2 * l) + interleave(U, zero_seq(l - 1))) + X4 = Sequence(zero_seq(2 * l) + interleave(zero_seq(l), V)) res = [X1, X2, X3, X4] if check: @@ -507,24 +505,9 @@ def T_sequences_smallcases(t, existence=False, check=True): False """ db = { - 47: [ - [1,-1,-1,0,0,-1,1,-1]+[0]*8+[1,-1,-1,0,0,-1,-1]+[0]*24, - [0,0,0,-1,1,0,0,0,-1,-1,-1,1,1,1,1,1,0,0,0,1,-1,0,0,1]+[0]*23, - [0]*26+[-1,0,1,0,0,0,0,1,-1,1,1,1,0,0,0,0,1,0,-1,0,0], - [0]*24 + [1,1,0,-1,0,-1,1,1,-1,0,0,0,0,0,-1,1,-1,-1,0,-1,0,-1,1] - ], - 65: [ - [0]*33+[1,1,1,1,1,-1,-1,1,1,-1,1,-1,1,1,-1,-1,1,1,1,1,1,-1,-1,1,-1,1,-1,1,-1,-1,1,1], - [0]*32+[1]+[0]*32, - [1]*5+[-1,-1,1,1,-1,1,-1,1,1]+[-1]*7+[1,1,-1,1,-1,1,-1,1,1,-1,-1]+[0]*33, - [0]*65 - ], - 93: [ - [0,-1,0,0,-1,1,0,-1,1,0,1,1,0,0,1,1,1,0,0,-1,0,-1,1,1,1,-1,0,1,0,0,1]+[0]*33+[1,1,0,0,1,0,0,-1,0,0,-1,1,0,1]+[0]*15, - [-1,0,-1,1,0,0,1,0,0,-1,0,0,-1,-1,0,0,0,-1,1,0,1]+[0]*5+[-1,0,1,1]+[0]*32+[1,1,0,0,1,1,0,1,-1,0,1,-1,0,0,-1]+[0]*16, - [0]*32+[1,0,0,1,-1,0,1,-1,0,-1,-1,0,0,-1,-1,1,0,0,-1,0,-1,1,1,1,-1,0,1,0,0,1]+[0]*17+[1,1,0,-1]+[0]*5+[1,0,1,-1,0], - [0]*31+[1,0,1,-1,0,0,-1,0,0,1,0,0,1,1,0,0,0,-1,1,0,1]+[0]*5+[-1,0,1,1]+[0]*17+[-1,0,0,-1,0,1,-1,-1,-1,1,0,1,0,0,-1] - ] + 47: [[1, -1, -1, 0, 0, -1, 1, -1] + [0] * 8 + [1, -1, -1, 0, 0, -1, -1] + [0] * 24, [0, 0, 0, -1, 1, 0, 0, 0, -1, -1, -1, 1, 1, 1, 1, 1, 0, 0, 0, 1, -1, 0, 0, 1] + [0] * 23, [0] * 26 + [-1, 0, 1, 0, 0, 0, 0, 1, -1, 1, 1, 1, 0, 0, 0, 0, 1, 0, -1, 0, 0], [0] * 24 + [1, 1, 0, -1, 0, -1, 1, 1, -1, 0, 0, 0, 0, 0, -1, 1, -1, -1, 0, -1, 0, -1, 1]], + 65: [[0] * 33 + [1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1], [0] * 32 + [1] + [0] * 32, [1] * 5 + [-1, -1, 1, 1, -1, 1, -1, 1, 1] + [-1] * 7 + [1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1] + [0] * 33, [0] * 65], + 93: [[0, -1, 0, 0, -1, 1, 0, -1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, -1, 0, -1, 1, 1, 1, -1, 0, 1, 0, 0, 1] + [0] * 33 + [1, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 1, 0, 1] + [0] * 15, [-1, 0, -1, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, -1, 0, 0, 0, -1, 1, 0, 1] + [0] * 5 + [-1, 0, 1, 1] + [0] * 32 + [1, 1, 0, 0, 1, 1, 0, 1, -1, 0, 1, -1, 0, 0, -1] + [0] * 16, [0] * 32 + [1, 0, 0, 1, -1, 0, 1, -1, 0, -1, -1, 0, 0, -1, -1, 1, 0, 0, -1, 0, -1, 1, 1, 1, -1, 0, 1, 0, 0, 1] + [0] * 17 + [1, 1, 0, -1] + [0] * 5 + [1, 0, 1, -1, 0], [0] * 31 + [1, 0, 1, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, -1, 1, 0, 1] + [0] * 5 + [-1, 0, 1, 1] + [0] * 17 + [-1, 0, 0, -1, 0, 1, -1, -1, -1, 1, 0, 1, 0, 0, -1]], } if t in db: @@ -534,21 +517,21 @@ def T_sequences_smallcases(t, existence=False, check=True): if check: assert is_T_sequences_set(sequences) return sequences - if (t+1) % 2 == 0 and turyn_sequences_smallcases((t+1)//2, existence=True): + if (t + 1) % 2 == 0 and turyn_sequences_smallcases((t + 1) // 2, existence=True): if existence: return True - turyn_seqs = turyn_sequences_smallcases((t+1)//2) + turyn_seqs = turyn_sequences_smallcases((t + 1) // 2) return T_sequences_construction_from_base_sequences(turyn_seqs, check=check) - if (t+1) % 4 == 0 and turyn_sequences_smallcases((t+1)//4, existence=True): + if (t + 1) % 4 == 0 and turyn_sequences_smallcases((t + 1) // 4, existence=True): if existence: return True - turyn_seqs = turyn_sequences_smallcases((t+1)//4) + turyn_seqs = turyn_sequences_smallcases((t + 1) // 4) return T_sequences_construction_from_turyn_sequences(turyn_seqs, check=check) for p in range(1, t): - n = (t-p)//2 - if (t-p) % 2 == 0 and base_sequences_smallcases(n, p, existence=True): + n = (t - p) // 2 + if (t - p) % 2 == 0 and base_sequences_smallcases(n, p, existence=True): if existence: return True base_seqs = base_sequences_smallcases(n, p, check=False) @@ -614,7 +597,7 @@ def base_sequences_construction(turyn_type_seqs, check=True): assert len(turyn_type_seqs) == 4 X, Y, Z, W = turyn_type_seqs - assert len(X) == len(Y) == len(Z) == len(W)+1 + assert len(X) == len(Y) == len(Z) == len(W) + 1 A = Sequence(Z + W) B = Sequence(Z + [-el for el in W]) @@ -685,7 +668,7 @@ def is_base_sequences_tuple(base_sequences, verbose=False): A, B, C, D = base_sequences n = len(C) p = len(A) - len(C) - if not (len(A) == len(B) == len(C)+p == len(D)+p): + if not (len(A) == len(B) == len(C) + p == len(D) + p): if verbose: print(f'Base sequences should have length n+p, n+p, n, n, found {len(A)}, {len(B)}, {len(C)}, {len(D)}') return False @@ -697,7 +680,7 @@ def is_base_sequences_tuple(base_sequences, verbose=False): print(f'Base sequences should only contain -1, +1, found {el}') return False - for j in range(1, n+p): + for j in range(1, n + p): autocorr = _nonperiodic_autocorrelation(A, j) + _nonperiodic_autocorrelation(B, j) + _nonperiodic_autocorrelation(C, j) + _nonperiodic_autocorrelation(D, j) if autocorr != 0: if verbose: @@ -754,6 +737,7 @@ def turyn_type_sequences_smallcases(n, existence=False): For the `n`-th digit, it should be converted to a 3 digits binary number, and then the same mapping as before can be used (see also [BDKR2013]_). """ + def convertLists(hexstring): seqs = [Sequence([]), Sequence([]), Sequence([]), Sequence([])] for c in hexstring[:-1]: @@ -861,9 +845,9 @@ def base_sequences_smallcases(n, p, existence=False, check=True): """ if existence: - return p == n-1 and turyn_type_sequences_smallcases(n, existence=True) + return p == n - 1 and turyn_type_sequences_smallcases(n, existence=True) - if p == n-1 and turyn_type_sequences_smallcases(n, existence=True): + if p == n - 1 and turyn_type_sequences_smallcases(n, existence=True): if existence: return True turyn_type_seqs = turyn_type_sequences_smallcases(n) diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index f9d25a971c1..b02e291ae11 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -180,6 +180,7 @@ class Tableau(ClonableList, metaclass=InheritComparisonClasscallMetaclass): ... ValueError: a tableau must be a list of iterables """ + @staticmethod def __classcall_private__(cls, t): r""" @@ -330,7 +331,7 @@ def check(self): # Check that it has partition shape. That's all we require from a # general tableau. lens = [len(row) for row in self] - for (a, b) in zip(lens, lens[1:]): + for a, b in zip(lens, lens[1:]): if a < b: raise ValueError("a tableau must be a list of iterables of weakly decreasing length") if lens and lens[-1] == 0: @@ -408,7 +409,7 @@ def _repr_diagram(self) -> str: # Get the widths of the columns str_tab = [[str(data) for data in row] for row in self] - col_widths = [2]*len(str_tab[0]) + col_widths = [2] * len(str_tab[0]) for row in str_tab: for i, e in enumerate(row): col_widths[i] = max(col_widths[i], len(e)) @@ -427,6 +428,7 @@ def _repr_diagram(self) -> str: st += ' ' * (col_width * 2 - 1) str_list.append(st) import re + mm = min(len(re.search('^ +', sline)[0]) for sline in str_list) - 1 str_list = [sline[mm:] for sline in str_list] str_list.reverse() @@ -435,10 +437,7 @@ def _repr_diagram(self) -> str: if self.parent().options('convention') == "French": str_tab = reversed(str_tab) - return "\n".join(" " - + " ".join("{:>{width}}".format(e, width=col_widths[i]) - for i, e in enumerate(row)) - for row in str_tab) + return "\n".join(" " + " ".join("{:>{width}}".format(e, width=col_widths[i]) for i, e in enumerate(row)) for row in str_tab) def _repr_compact(self) -> str: """ @@ -500,6 +499,7 @@ def _ascii_art_(self): """ ascii = self.parent().options._dispatch(self, '_ascii_art_', 'ascii_art') from sage.typeset.ascii_art import AsciiArt + return AsciiArt(ascii.splitlines()) def _unicode_art_(self): @@ -518,6 +518,7 @@ def _unicode_art_(self): """ from sage.typeset.unicode_art import UnicodeArt + return UnicodeArt(self._ascii_art_table(use_unicode=True).splitlines()) _ascii_art_repr = _repr_diagram @@ -652,9 +653,9 @@ def _ascii_art_table(self, use_unicode=False): sage: Tableaux.options._reset() """ from sage.combinat.output import ascii_art_table + self.parent().options('convention') - return ascii_art_table(self, use_unicode=use_unicode, - convention=self.parent().options('convention')) + return ascii_art_table(self, use_unicode=use_unicode, convention=self.parent().options('convention')) def _ascii_art_compact(self) -> str: r""" @@ -691,6 +692,7 @@ def _ascii_art_compact(self) -> str: if self.parent().options('convention') == "Russian": from sage.combinat.output import ascii_art_table_russian + return ascii_art_table_russian(self, compact=True) if self.parent().options('convention') == "English": T = self @@ -699,15 +701,12 @@ def _ascii_art_compact(self) -> str: # Get the widths of the columns str_tab = [[str(_) for _ in row] for row in T] - col_widths = [1]*len(self[0]) + col_widths = [1] * len(self[0]) for row in str_tab: for i, e in enumerate(row): col_widths[i] = max(col_widths[i], len(e)) - return "\n".join("|" - + "|".join("{:^{width}}".format(e, width=col_widths[i]) - for i, e in enumerate(row)) - + "|" for row in str_tab) + return "\n".join("|" + "|".join("{:^{width}}".format(e, width=col_widths[i]) for i, e in enumerate(row)) + "|" for row in str_tab) def _latex_(self) -> str: r""" @@ -768,6 +767,7 @@ def _latex_diagram(self) -> str: if len(self) == 0: return "{\\emptyset}" from sage.combinat.output import tex_from_array + return tex_from_array(self) def _repr_svg_(self) -> str: @@ -783,6 +783,7 @@ def _repr_svg_(self) -> str: '' """ from sage.combinat.output import svg_from_array + return svg_from_array(self) def __truediv__(self, t): @@ -803,6 +804,7 @@ def __truediv__(self, t): ValueError: the shape of the tableau must contain the partition """ from sage.combinat.partition import _Partitions + # if t is a list, convert it to a partition first if isinstance(t, list): t = _Partitions(t) @@ -811,7 +813,7 @@ def __truediv__(self, t): if not self.shape().contains(t): raise ValueError("the shape of the tableau must contain the partition") - st = [list(row) for row in self] # create deep copy of t + st = [list(row) for row in self] # create deep copy of t for i, t_i in enumerate(t): st_i = st[i] @@ -819,6 +821,7 @@ def __truediv__(self, t): st_i[j] = None from sage.combinat.skew_tableau import SkewTableau + return SkewTableau(st) def __call__(self, *cell): @@ -892,6 +895,7 @@ def shape(self): [3, 2, 1] """ from sage.combinat.partition import Partition + return Partition([len(row) for row in self]) def size(self): @@ -1047,8 +1051,8 @@ def plot(self, descents=False): if self.parent().options('convention') == "Russian": pp = p # h rr = r - h = [-i-1 for i in range(len(p))] - v = [i+1 for i in range(len(r))] + h = [-i - 1 for i in range(len(p))] + v = [i + 1 for i in range(len(r))] else: pp = [0] * len(p) @@ -1058,38 +1062,27 @@ def plot(self, descents=False): G = line([(0, 0), (p[0], pp[0])], axes=False, figsize=1.5) for i in range(len(p)): - G += line([(h[i], m*(-i-1)), (h[i]+p[i], pp[i]+m*(-i-1))]) + G += line([(h[i], m * (-i - 1)), (h[i] + p[i], pp[i] + m * (-i - 1))]) - G += line([(0, 0), (-rr[0], m*-r[0])]) + G += line([(0, 0), (-rr[0], m * -r[0])]) for i in range(len(r)): - G += line([(i+1, v[i]), (i+1-rr[i], v[i]+m*-r[i])]) + G += line([(i + 1, v[i]), (i + 1 - rr[i], v[i] + m * -r[i])]) if descents: t = StandardTableau(self) for i in t.standard_descents(): c = t.cells_containing(i)[0] if self.parent().options('convention') == "Russian": - G += polygon([(c[1]+1-v[c[0]], m*(-c[1]-c[0])), - (c[1]+2-v[c[0]], m*(-c[1]-c[0]-1)), - (c[1]+1-v[c[0]], m*(-c[1]-c[0]-2)), - (c[1]-v[c[0]], m*(-c[1]-c[0]-1)) - ], - rgbcolor=(1, 0, 1) - ) + G += polygon([(c[1] + 1 - v[c[0]], m * (-c[1] - c[0])), (c[1] + 2 - v[c[0]], m * (-c[1] - c[0] - 1)), (c[1] + 1 - v[c[0]], m * (-c[1] - c[0] - 2)), (c[1] - v[c[0]], m * (-c[1] - c[0] - 1))], rgbcolor=(1, 0, 1)) else: - G += polygon([(c[1], m*-c[0]), - (c[1]+1, m*-c[0]), - (c[1]+1, m*(-c[0]-1)), - (c[1], m*(-c[0]-1)) - ], - rgbcolor=(1, 0, 1)) + G += polygon([(c[1], m * -c[0]), (c[1] + 1, m * -c[0]), (c[1] + 1, m * (-c[0] - 1)), (c[1], m * (-c[0] - 1))], rgbcolor=(1, 0, 1)) if self.parent().options('convention') == "Russian": for c in self.cells(): - G += text(str(self.entry(c)), (c[1]+1-v[c[0]], m*(-c[1]-c[0]-1))) + G += text(str(self.entry(c)), (c[1] + 1 - v[c[0]], m * (-c[1] - c[0] - 1))) else: for c in self.cells(): - G += text(str(self.entry(c)), (c[1]+0.5, m*(-c[0]-0.5))) + G += text(str(self.entry(c)), (c[1] + 0.5, m * (-c[0] - 0.5))) return G @@ -1107,6 +1100,7 @@ def to_word_by_row(self): word: 325146 """ from sage.combinat.words.word import Word + w = [] for row in reversed(self): w += row @@ -1126,6 +1120,7 @@ def to_word_by_column(self): word: 321546 """ from sage.combinat.words.word import Word + w = [] for row in self.conjugate(): w += row[::-1] @@ -1162,10 +1157,7 @@ def descents(self): sage: Tableau( [[1,2,3],[4,5]] ).descents() [(1, 0), (1, 1)] """ - return [(i, j) - for i in range(1, len(self)) - for j, selfij in enumerate(self[i]) - if selfij > self[i-1][j]] + return [(i, j) for i in range(1, len(self)) for j, selfij in enumerate(self[i]) if selfij > self[i - 1][j]] def major_index(self): """ @@ -1226,15 +1218,11 @@ def inversions(self): for j, entry in enumerate(row): # c is in position (i,j) # find the d that satisfy condition 1 - inversions.extend(((i, j), (i, k)) - for k in range(j + 1, len(row)) - if entry > row[k]) + inversions.extend(((i, j), (i, k)) for k in range(j + 1, len(row)) if entry > row[k]) # find the d that satisfy condition 2 if i == 0: continue - inversions.extend(((i, j), (i - 1, k)) - for k in range(j) - if entry > previous_row[k]) + inversions.extend(((i, j), (i - 1, k)) for k in range(j) if entry > previous_row[k]) previous_row = row return inversions @@ -1262,8 +1250,7 @@ def inversion_number(self): 0 """ p = self.shape() - return len(self.inversions()) - sum(p.arm_length(*cell) - for cell in self.descents()) + return len(self.inversions()) - sum(p.arm_length(*cell) for cell in self.descents()) def to_sign_matrix(self, max_entry=None): r""" @@ -1306,25 +1293,28 @@ def to_sign_matrix(self, max_entry=None): """ from sage.rings.integer_ring import ZZ from sage.sets.positive_integers import PositiveIntegers + PI = PositiveIntegers() for row in self: if any(c not in PI for c in row): raise ValueError("the entries must be nonnegative integers") from sage.matrix.matrix_space import MatrixSpace + if max_entry is None: max_entry = max(max(c) for c in self) MS = MatrixSpace(ZZ, len(self[0]), max_entry) Tconj = self.conjugate() conj_len = len(Tconj) - d = {(conj_len-i-1, elem-1): 1 for i, row in enumerate(Tconj) for elem in row} + d = {(conj_len - i - 1, elem - 1): 1 for i, row in enumerate(Tconj) for elem in row} partial_sum_matrix = MS(d) from copy import copy + sign_matrix = copy(MS.zero()) for j in range(max_entry): sign_matrix[0, j] = partial_sum_matrix[0, j] for i in range(1, conj_len): for j in range(max_entry): - sign_matrix[i, j] = partial_sum_matrix[i, j] - partial_sum_matrix[i-1, j] + sign_matrix[i, j] = partial_sum_matrix[i, j] - partial_sum_matrix[i - 1, j] return sign_matrix def schuetzenberger_involution(self, n=None, check=True): @@ -1604,6 +1594,7 @@ def bender_knuth_involution(self, k, rows=None, check=True): if check and self not in SemistandardTableaux(): raise ValueError("the tableau must be semistandard") from sage.combinat.skew_tableau import SkewTableau + sk = SkewTableau(self).bender_knuth_involution(k, rows, False) return SemistandardTableaux()(list(sk)) @@ -1727,7 +1718,7 @@ def is_row_strict(self) -> bool: sage: Tableau([[5, 3], [2, 4]]).is_row_strict() False """ - return all(row[i] < row[i+1] for row in self for i in range(len(row)-1)) + return all(row[i] < row[i + 1] for row in self for i in range(len(row) - 1)) def is_row_increasing(self, weak=False) -> bool: r""" @@ -1748,11 +1739,15 @@ def is_row_increasing(self, weak=False) -> bool: False """ if weak: + def test(a, b): return a <= b + else: + def test(a, b): return a < b + return all(test(a, b) for row in self for (a, b) in zip(row, row[1:])) def is_column_increasing(self, weak=False) -> bool: @@ -1774,14 +1769,18 @@ def is_column_increasing(self, weak=False) -> bool: False """ if weak: + def test(a, b): return a <= b + else: + def test(a, b): return a < b def tworow(a, b): return all(test(a[i], b_i) for i, b_i in enumerate(b)) + return all(tworow(self[r], self[r + 1]) for r in range(len(self) - 1)) def is_column_strict(self) -> bool: @@ -1811,9 +1810,11 @@ def is_column_strict(self) -> bool: sage: Tableau([[1, 4, 2], [2, 3]]).is_column_strict() False """ + def tworow(a, b): return all(a[i] < b_i for i, b_i in enumerate(b)) - return all(tworow(self[r], self[r+1]) for r in range(len(self)-1)) + + return all(tworow(self[r], self[r + 1]) for r in range(len(self) - 1)) def is_semistandard(self) -> bool: r""" @@ -1979,7 +1980,7 @@ def cells_containing(self, i): [] """ cell_list = [] - for r in range(len(self)-1, -1, -1): + for r in range(len(self) - 1, -1, -1): rth_row = self[r] for c, val in enumerate(rth_row): if val == i: @@ -2032,9 +2033,7 @@ def leq(self, secondtab): sh = self.shape() if sh != secondtab.shape(): raise TypeError("the tableaux must be the same shape") - return all(self[a][b] <= secondtab[a][b] - for a in range(len(self)) - for b in range(len(self[a]))) + return all(self[a][b] <= secondtab[a][b] for a in range(len(self)) for b in range(len(self[a]))) def k_weight(self, k): r""" @@ -2096,7 +2095,7 @@ def is_k_tableau(self, k) -> bool: """ shapes = self.to_chain() kshapes = [la.k_conjugate(k) for la in shapes] - return all(kshapes[i+1].contains(kshapes[i]) for i in range(len(shapes)-1)) + return all(kshapes[i + 1].contains(kshapes[i]) for i in range(len(shapes) - 1)) def restrict(self, n): """ @@ -2195,6 +2194,7 @@ def restriction_shape(self, n): True """ from sage.combinat.partition import Partition + res = [len([y for y in row if y <= n]) for row in self] return Partition(res) @@ -2233,7 +2233,7 @@ def to_chain(self, max_entry=None): max_entry = 0 else: max_entry = max(max(row) for row in self) - return [self.restriction_shape(k) for k in range(max_entry+1)] + return [self.restriction_shape(k) for k in range(max_entry + 1)] @combinatorial_map(name='to Gelfand-Tsetlin pattern') def to_Gelfand_Tsetlin_pattern(self): @@ -2253,6 +2253,7 @@ def to_Gelfand_Tsetlin_pattern(self): [[2, 1, 0], [1, 1], [1]] """ from sage.combinat.gelfand_tsetlin_patterns import GelfandTsetlinPatterns + return GelfandTsetlinPatterns()(self) def anti_restrict(self, n): @@ -2277,6 +2278,7 @@ def anti_restrict(self, n): """ t_new = [[None if g <= n else g for g in row] for row in self] from sage.combinat.skew_tableau import SkewTableau + return SkewTableau(t_new) def to_list(self): @@ -2390,30 +2392,30 @@ def _left_schensted_insert(self, letter): rep = self.to_list() rep.reverse() - width = len(rep[h-1]) + width = len(rep[h - 1]) heights = self._heights() + [h1] - for j in range(1, width+2): - i = heights[j-1] - while i != h1 and rep[i-1][j-1] >= letter: + for j in range(1, width + 2): + i = heights[j - 1] + while i != h1 and rep[i - 1][j - 1] >= letter: i += 1 - if i == heights[j-1]: # add on top of column j + if i == heights[j - 1]: # add on top of column j if j == 1: rep = [[letter]] + rep else: - rep[i-2].append(letter) + rep[i - 2].append(letter) break elif i == h1 and j == width: # add on right of line i - if rep[i-2][j-1] < letter: - rep[i-2].append(letter) + if rep[i - 2][j - 1] < letter: + rep[i - 2].append(letter) else: - new_letter = rep[i-2][j-1] - rep[i-2][j-1] = letter - rep[i-2].append(new_letter) + new_letter = rep[i - 2][j - 1] + rep[i - 2][j - 1] = letter + rep[i - 2].append(new_letter) break else: - new_letter = rep[i-2][j-1] - rep[i-2][j-1] = letter + new_letter = rep[i - 2][j - 1] + rep[i - 2][j - 1] = letter letter = new_letter rep.reverse() @@ -2619,6 +2621,7 @@ def slide_multiply(self, other): st.extend(self) from sage.combinat.skew_tableau import SkewTableau + return SkewTableau(st).rectify() def _slide_up(self, c): @@ -2646,24 +2649,24 @@ def _slide_up(self, c): # once moving box is in first column, just move letters up # (French notation!) if spotc == 0: - new_st[spotl][spotc] = new_st[spotl-1][spotc] + new_st[spotl][spotc] = new_st[spotl - 1][spotc] spotl -= 1 continue # once moving box is in first row, just move letters up if spotl == 0: - new_st[spotl][spotc] = new_st[spotl][spotc-1] + new_st[spotl][spotc] = new_st[spotl][spotc - 1] spotc -= 1 continue # If we get to this stage, we need to compare - below = new_st[spotl-1][spotc] - left = new_st[spotl][spotc-1] + below = new_st[spotl - 1][spotc] + left = new_st[spotl][spotc - 1] if below >= left: # Swap with the cell below - new_st[spotl][spotc] = new_st[spotl-1][spotc] + new_st[spotl][spotc] = new_st[spotl - 1][spotc] spotl -= 1 continue # Swap with the cell to the left - new_st[spotl][spotc] = new_st[spotl][spotc-1] + new_st[spotl][spotc] = new_st[spotl][spotc - 1] spotc -= 1 continue # set box in position (0,0) to 0 @@ -2807,21 +2810,21 @@ def promotion_inverse(self, n): return self s = self.shape()[0] l = self.weight()[0] - word = [i-1 for row in reversed(self) for i in row if i > 1] + word = [i - 1 for row in reversed(self) for i in row if i > 1] t = Tableau([]) t = t.insert_word(word) t = t.to_list() if l < s: for i in range(l): - t[len(t)-1].append(n+1) + t[len(t) - 1].append(n + 1) else: - t.append([n+1 for i in range(s)]) + t.append([n + 1 for i in range(s)]) return Tableau(t) # Now, the non-rectangular case. p = self for c in reversed(self.cells_containing(1)): p = p._slide_down(c, n) - return Tableau([[i-1 for i in row] for row in p]) + return Tableau([[i - 1 for i in row] for row in p]) def promotion(self, n): r""" @@ -2920,14 +2923,14 @@ def promotion(self, n): """ if self.is_rectangular(): t = self.rotate_180() - t = [tuple(n+2-i for i in row) for row in t] + t = [tuple(n + 2 - i for i in row) for row in t] t = Tableau(t).promotion_inverse(n) - t = [tuple(n+2-i for i in row) for row in t] + t = [tuple(n + 2 - i for i in row) for row in t] return Tableau(t).rotate_180() p = self - for c in self.cells_containing(n+1): + for c in self.cells_containing(n + 1): p = p._slide_up(c) - return Tableau([[i+1 for i in row] for row in p]) + return Tableau([[i + 1 for i in row] for row in p]) def row_stabilizer(self): """ @@ -2966,8 +2969,7 @@ def row_stabilizer(self): # tableau, by including the identity permutation on the set [1..k]. k = self.size() gens = [list(range(1, k + 1))] - gens.extend((row[j], row[j + 1]) - for row in self for j in range(len(row) - 1)) + gens.extend((row[j], row[j + 1]) for row in self for j in range(len(row) - 1)) return PermutationGroup(gens) def column_stabilizer(self): @@ -2997,7 +2999,7 @@ def column_stabilizer(self): while ell > 1: ell -= 1 for i, val in enumerate(self[ell]): - gens.append((val, self[ell-1][i])) + gens.append((val, self[ell - 1][i])) return PermutationGroup(gens) def height(self): @@ -3037,9 +3039,9 @@ def _heights(self): k = len(self) cor = [[k - i, j + 1] for i, j in reversed(cor)] - heights = [1]*(cor[0][1]) + heights = [1] * (cor[0][1]) for i in range(1, ncor): - heights += [cor[i][0]]*(cor[i][1]-cor[i-1][1]) + heights += [cor[i][0]] * (cor[i][1] - cor[i - 1][1]) return heights @@ -3190,7 +3192,7 @@ def add_entry(self, cell, m): tab = self.to_list() r, c = cell try: - tab[r][c] = m # will work if we are replacing an entry + tab[r][c] = m # will work if we are replacing an entry except IndexError: # Only add a new row if (r,c) is an addable cell (previous code # added m to the end of row r independently of the value of c) @@ -3201,7 +3203,7 @@ def add_entry(self, cell, m): raise IndexError('%s is not an addable cell of the tableau' % ((r, c),)) else: tab_r = tab[r] - if c == len(tab_r) and (r == 0 or len(tab_r) < len(tab[r-1])): + if c == len(tab_r) and (r == 0 or len(tab_r) < len(tab[r - 1])): tab_r.append(m) else: raise IndexError('%s is not an addable cell of the tableau' % ((r, c),)) @@ -3306,8 +3308,7 @@ def lambda_catabolism(self, part): [[3, 3]] """ # Reduce the partition if it is too big for the tableau - part = [min(part[i], len(self[i])) - for i in range(min(len(self), len(part)))] + part = [min(part[i], len(self[i])) for i in range(min(len(self), len(part)))] if self.shape() == part: return Tableau([]) @@ -3317,7 +3318,7 @@ def lambda_catabolism(self, part): w2 = [] for i, row in enumerate(reversed(self[:m])): - w2 += row[part[-1 - i]:] + w2 += row[part[-1 - i] :] return Tableau([]).insert_word(w2 + w1) @@ -3357,7 +3358,7 @@ def reduced_lambda_catabolism(self, part): a = self[0][0] part = [min(part1[i], len(self[i])) for i in range(min(len(part1), len(self)))] - tt_part = Tableau([[a+i]*part[i] for i in range(len(part))]) + tt_part = Tableau([[a + i] * part[i] for i in range(len(part))]) t_part = Tableau([[self[i][j] for j in range(part[i])] for i in range(len(part))]) if t_part == tt_part: @@ -3446,7 +3447,7 @@ def promotion_operator(self, i): chain = self.to_chain() part = self.shape() weight = self.weight() - perm = permutation.from_reduced_word(range(1, len(weight)+1)) + perm = permutation.from_reduced_word(range(1, len(weight) + 1)) l = part.add_horizontal_border_strip(i) ltab = [from_chain(chain + [next]) for next in l] return [x.symmetric_group_action_on_values(perm) for x in ltab] @@ -3564,11 +3565,11 @@ def socle(self): return 0 w1row = self[0] i = 0 - while i < len(w1row)-1: - if w1row[i+1] != w1row[i] + 1: + while i < len(w1row) - 1: + if w1row[i + 1] != w1row[i] + 1: break i += 1 - return i+1 + return i + 1 def atom(self): """ @@ -3582,7 +3583,7 @@ def atom(self): ll = [t.socle() for t in self.catabolism_sequence()] lres = ll[:] for i in range(1, len(ll)): - lres[i] = ll[i] - ll[i-1] + lres[i] = ll[i] - ll[i - 1] return lres def symmetric_group_action_on_entries(self, w): @@ -3619,9 +3620,9 @@ def symmetric_group_action_on_entries(self, w): """ w = w + [i + 1 for i in range(len(w), self.size())] # need to ensure that it belongs to Sym_size try: - return self.parent()([[w[entry-1] for entry in row] for row in self]) + return self.parent()([[w[entry - 1] for entry in row] for row in self]) except Exception: - return Tableau([[w[entry-1] for entry in row] for row in self]) + return Tableau([[w[entry - 1] for entry in row] for row in self]) def is_key_tableau(self) -> bool: r""" @@ -3647,7 +3648,7 @@ def is_key_tableau(self) -> bool: False """ T_conj = self.conjugate() - return all(x in T_conj[i-1] for i in range(1, len(T_conj)) for x in T_conj[i]) + return all(x in T_conj[i - 1] for i in range(1, len(T_conj)) for x in T_conj[i]) def right_key_tableau(self): """ @@ -3704,7 +3705,7 @@ def right_key_tableau(self): key = [[] for _ in cols_list] for i, col_a in enumerate(cols_list): - right_cols = cols_list[i+1:] + right_cols = cols_list[i + 1 :] for elem in reversed(col_a): key_val = elem update = [] @@ -3773,6 +3774,7 @@ def left_key_tableau(self): key[0] = list(cols_list[0]) from bisect import bisect_right + for i, col_a in enumerate(cols_list[1:], 1): left_cols = cols_list[:i] for elem in reversed(col_a): @@ -3871,21 +3873,17 @@ def flush(self): sage: t.flush() # needs sage.modules 4 """ - for i in range(len(self)-1): - if len(self[i]) <= len(self[i+1]): + for i in range(len(self) - 1): + if len(self[i]) <= len(self[i + 1]): raise ValueError('only defined for tableaux with strictly decreasing parts') f = 0 S = self._segments().items() for s in S: - if (s[0][0] != len(self)-1 and s[1] == len(self[s[0][0]+1]) - and self[s[0][0]+1][-1] <= s[0][1]) \ - or (s[0][0] == len(self)-1 and s[1] == 0): + if (s[0][0] != len(self) - 1 and s[1] == len(self[s[0][0] + 1]) and self[s[0][0] + 1][-1] <= s[0][1]) or (s[0][0] == len(self) - 1 and s[1] == 0): f += 1 else: for t in S: - if s[0][0]+1 == t[0][0] and s[1] == t[1] and ( - (s[1] >= 1 and self[s[0][0]+1][s[1]-1] <= self[s[0][0]][s[1]]) - or (s[1] < 1 and self[s[0][0]+1][s[1]] != s[0][0]+2)): + if s[0][0] + 1 == t[0][0] and s[1] == t[1] and ((s[1] >= 1 and self[s[0][0] + 1][s[1] - 1] <= self[s[0][0]][s[1]]) or (s[1] < 1 and self[s[0][0] + 1][s[1]] != s[0][0] + 2)): f += 1 return f @@ -3999,8 +3997,9 @@ def residue_sequence(self, e, multicharge=(0,)): res = [0] * self.size() for r, row in enumerate(self): for c, entry in enumerate(row): - res[entry-1] = multicharge[0] - r + c + res[entry - 1] = multicharge[0] - r + c from sage.combinat.tableau_residues import ResidueSequence + return ResidueSequence(e, multicharge, res, check=False) def degree(self, e, multicharge=(0,)): @@ -4037,11 +4036,11 @@ def degree(self, e, multicharge=(0,)): deg = self.shape()._initial_degree(e, multicharge) res = self.shape().initial_tableau().residue_sequence(e, multicharge) for r in self.reduced_row_word(): - if res[r] == res[r+1]: + if res[r] == res[r + 1]: deg -= 2 - elif res[r] == res[r+1] + 1 or res[r] == res[r+1] - 1: - deg += (e == 2 and 2 or 1) - res = res.swap_residues(r, r+1) + elif res[r] == res[r + 1] + 1 or res[r] == res[r + 1] - 1: + deg += e == 2 and 2 or 1 + res = res.swap_residues(r, r + 1) return deg def codegree(self, e, multicharge=(0,)): @@ -4082,11 +4081,11 @@ def codegree(self, e, multicharge=(0,)): codeg = conj_shape._initial_degree(e) res = conj_shape.initial_tableau().residue_sequence(e) for r in self.reduced_column_word(): - if res[r] == res[r+1]: + if res[r] == res[r + 1]: codeg -= 2 - elif res[r] == res[r+1] + 1 or res[r] == res[r+1] - 1: - codeg += (e == 2 and 2 or 1) - res = res.swap_residues(r, r+1) + elif res[r] == res[r + 1] + 1 or res[r] == res[r + 1] - 1: + codeg += e == 2 and 2 or 1 + res = res.swap_residues(r, r + 1) return codeg def first_row_descent(self): @@ -4112,8 +4111,8 @@ def first_row_descent(self): True """ for row in range(len(self)): - for col in range(len(self[row])-1): - if self[row][col] > self[row][col+1]: + for col in range(len(self[row]) - 1): + if self[row][col] > self[row][col + 1]: return (row, col) return None @@ -4139,10 +4138,10 @@ def first_column_descent(self): sage: Tableau([[1,2,3],[4]]).first_column_descent() is None True """ - for row in range(len(self)-1): + for row in range(len(self) - 1): col = 0 - while col < len(self[row+1]): - if self[row][col] > self[row+1][col]: + while col < len(self[row + 1]): + if self[row][col] > self[row + 1][col]: return (row, col) col += 1 return None @@ -4268,8 +4267,8 @@ def hillman_grassl(self): sage: A.parent(), a.parent() (Weak Reverse Plane Partitions, Tableaux) """ - from sage.combinat.hillman_grassl import (hillman_grassl, - WeakReversePlanePartition) + from sage.combinat.hillman_grassl import hillman_grassl, WeakReversePlanePartition + return WeakReversePlanePartition(hillman_grassl(list(self))) def sulzgruber_correspondence(self): @@ -4384,8 +4383,8 @@ def sulzgruber_correspondence(self): sage: a.sulzgruber_correspondence() [[0, 4], [1, 5]] """ - from sage.combinat.hillman_grassl import (sulzgruber_correspondence, - WeakReversePlanePartition) + from sage.combinat.hillman_grassl import sulzgruber_correspondence, WeakReversePlanePartition + return WeakReversePlanePartition(sulzgruber_correspondence(list(self))) @@ -4451,6 +4450,7 @@ class SemistandardTableau(Tableau): sage: s2.parent() Semistandard tableaux of size 3 and maximum entry 3 """ + @staticmethod def __classcall_private__(self, t): r""" @@ -4478,22 +4478,22 @@ def __classcall_private__(self, t): if t not in Tableaux(): raise ValueError('%s is not a tableau' % t) - for (rix, row) in enumerate(t): - for (cix, v) in enumerate(row): + for rix, row in enumerate(t): + for cix, v in enumerate(row): if not isinstance(v, (int, Integer)): raise ValueError("expected entry to be an integer at (row=%s, col=%s)" % (rix, cix)) if v <= 0: raise ValueError("expected entry to be a positive integer at (row=%s, col=%s). Found (%s)" % (rix, cix, v)) - for (rix, row) in enumerate(t): - for cix in range(len(row)-1): - if row[cix] > row[cix+1]: - raise ValueError("row (%s) is not weakly increasing between columns (%s, %s)" % (rix, cix, cix+1)) + for rix, row in enumerate(t): + for cix in range(len(row) - 1): + if row[cix] > row[cix + 1]: + raise ValueError("row (%s) is not weakly increasing between columns (%s, %s)" % (rix, cix, cix + 1)) # If we're still here ``t`` cannot be column strict - for rix in range(len(t)-1): + for rix in range(len(t) - 1): rcur = t[rix] - rnext = t[rix+1] + rnext = t[rix + 1] # check that SST is strictly increasing in columns # we know that len(rnext) <= len(rcur) as the SST cannot have @@ -4502,7 +4502,7 @@ def __classcall_private__(self, t): for cix in range(len(rnext)): if rnext[cix] <= rcur[cix]: - raise ValueError("column (%s) is not strictly increasing between rows (%s, %s)" % (cix, rix, rix+1)) + raise ValueError("column (%s) is not strictly increasing between rows (%s, %s)" % (cix, rix, rix + 1)) # we should have found an error by now. raise ValueError('we should have found an error by now in tableau %s' % t) @@ -4534,12 +4534,13 @@ def check(self): # the entries of t are positive integers which are weakly increasing # along rows from sage.sets.positive_integers import PositiveIntegers + PI = PositiveIntegers() for row in self: if any(c not in PI for c in row): raise ValueError("the entries of a semistandard tableau must be nonnegative integers") - if any(row[c] > row[c+1] for c in range(len(row)-1)): + if any(row[c] > row[c + 1] for c in range(len(row) - 1)): raise ValueError("the entries in each row of a semistandard tableau must be weakly increasing") # and strictly increasing down columns @@ -4613,6 +4614,7 @@ class RowStandardTableau(Tableau): sage: isinstance(u, Tableau) True """ + @staticmethod def __classcall_private__(self, t): r""" @@ -4657,10 +4659,8 @@ def check(self): # We have checked that t is tableau, so it remains to check that # the entries of t are positive integers that increase along rows. flatx = sorted(c for row in self for c in row) - if (flatx != list(range(1, len(flatx)+1)) - or any(row[i] >= row[i+1] for row in self for i in range(len(row)-1))): - raise ValueError("the entries in a row standard tableau must increase" - " along rows and contain the numbers 1,2,...,n") + if flatx != list(range(1, len(flatx) + 1)) or any(row[i] >= row[i + 1] for row in self for i in range(len(row) - 1)): + raise ValueError("the entries in a row standard tableau must increase" " along rows and contain the numbers 1,2,...,n") class StandardTableau(SemistandardTableau): @@ -4719,6 +4719,7 @@ class StandardTableau(SemistandardTableau): sage: isinstance(r, Tableau) True """ + @staticmethod def __classcall_private__(self, t): r""" @@ -4792,8 +4793,7 @@ def dominates(self, t): False """ t = StandardTableau(t) - return all(self.restrict(m).shape().dominates(t.restrict(m).shape()) - for m in range(1, 1 + self.size())) + return all(self.restrict(m).shape().dominates(t.restrict(m).shape()) for m in range(1, 1 + self.size())) def is_standard(self) -> bool: """ @@ -4829,9 +4829,9 @@ def up(self): for row, _ in outside_corners: new_t = [list(_) for _ in self] if row != len(self): - new_t[row] += [n+1] + new_t[row] += [n + 1] else: - new_t.append([n+1]) + new_t.append([n + 1]) yield StandardTableau(new_t) def up_list(self): @@ -5093,7 +5093,7 @@ def from_shape_and_word(shape, w, convention='French'): if convention == "French": shape = reversed(shape) for l in shape: - res.append(tuple(w[j:j+l])) + res.append(tuple(w[j : j + l])) j += l if convention == "French": res.reverse() @@ -5163,6 +5163,7 @@ class IncreasingTableau(Tableau): sage: s2.parent() Increasing tableaux of size 3 and maximum entry 3 """ + @staticmethod def __classcall_private__(self, t): r""" @@ -5216,21 +5217,19 @@ def check(self): # the entries of t are positive integers which are weakly increasing # along rows from sage.sets.positive_integers import PositiveIntegers + PI = PositiveIntegers() for row in self: if any(c not in PI for c in row): - raise ValueError("the entries of an increasing tableau" - " must be nonnegative integers") - if any(row[c] >= row[c+1] for c in range(len(row)-1)): - raise ValueError("the entries in each row of an increasing" - " tableau must be strictly increasing") + raise ValueError("the entries of an increasing tableau" " must be nonnegative integers") + if any(row[c] >= row[c + 1] for c in range(len(row) - 1)): + raise ValueError("the entries in each row of an increasing" " tableau must be strictly increasing") # and strictly increasing down columns for row, next in zip(self, self[1:]): if not all(row[c] < next[c] for c in range(len(next))): - raise ValueError("the entries of each column of an increasing" - " tableau must be strictly increasing") + raise ValueError("the entries of each column of an increasing" " tableau must be strictly increasing") def descent_set(self): r""" @@ -5262,7 +5261,7 @@ def descent_set(self): ell = len(self) for r1, row in enumerate(self): for val in row: - for r2 in range(r1+1, ell): + for r2 in range(r1 + 1, ell): if val + 1 in self[r2]: ans.add(val) return sorted(ans) @@ -5288,16 +5287,16 @@ def K_bender_knuth(self, i): for r, row in enumerate(self): for c, val in enumerate(row): if val == i: - if (c + 1 < len(row) and row[c+1] == i + 1): + if c + 1 < len(row) and row[c + 1] == i + 1: newtab[r][c] = i - elif (r + 1 < len(self) and c < len(self[r+1]) and self[r+1][c] == i + 1): + elif r + 1 < len(self) and c < len(self[r + 1]) and self[r + 1][c] == i + 1: newtab[r][c] = i else: newtab[r][c] = i + 1 elif val == i + 1: - if c > 0 and row[c-1] == i: + if c > 0 and row[c - 1] == i: newtab[r][c] = i + 1 - elif r > 0 and self[r-1][c] == i: + elif r > 0 and self[r - 1][c] == i: newtab[r][c] = i + 1 else: newtab[r][c] = i @@ -5387,7 +5386,7 @@ def K_evacuation(self, ceiling=None): ceiling = max(self.entries()) ans = self for j in reversed(range(1, ceiling)): - for i in range(1, j+1): + for i in range(1, j + 1): ans = ans.K_bender_knuth(i) return ans @@ -5515,6 +5514,7 @@ class Tableaux(UniqueRepresentation, Parent): sage: 1 in Tableaux() False """ + @staticmethod def __classcall_private__(cls, *args, **kwargs): r""" @@ -5614,34 +5614,22 @@ class options(GlobalOptions): |4|5| sage: Tableaux.options._reset() """ + NAME = 'Tableaux' module = 'sage.combinat.tableau' - display = dict(default='list', - description='Controls the way in which tableaux are printed', - values=dict(list='print tableaux as lists', - diagram='display as Young diagram (similar to :meth:`~sage.combinat.tableau.Tableau.pp()`', - compact='minimal length string representation'), - alias=dict(array='diagram', ferrers_diagram='diagram', young_diagram='diagram'), - case_sensitive=False) - ascii_art = dict(default='repr', - description='Controls the ascii art output for tableaux', - values=dict(repr='display using the diagram string representation', - table='display as a table', - compact='minimal length ascii art'), - case_sensitive=False) - latex = dict(default='diagram', - description='Controls the way in which tableaux are latexed', - values=dict(list='as a list', diagram='as a Young diagram'), - alias=dict(array='diagram', ferrers_diagram='diagram', young_diagram='diagram'), - case_sensitive=False) - convention = dict(default='English', - description='Sets the convention used for displaying tableaux and partitions', - values=dict( - English='use the English convention', - French='use the French convention', - Russian='use the Russian convention', - ), - case_sensitive=False) + display = dict(default='list', description='Controls the way in which tableaux are printed', values=dict(list='print tableaux as lists', diagram='display as Young diagram (similar to :meth:`~sage.combinat.tableau.Tableau.pp()`', compact='minimal length string representation'), alias=dict(array='diagram', ferrers_diagram='diagram', young_diagram='diagram'), case_sensitive=False) + ascii_art = dict(default='repr', description='Controls the ascii art output for tableaux', values=dict(repr='display using the diagram string representation', table='display as a table', compact='minimal length ascii art'), case_sensitive=False) + latex = dict(default='diagram', description='Controls the way in which tableaux are latexed', values=dict(list='as a list', diagram='as a Young diagram'), alias=dict(array='diagram', ferrers_diagram='diagram', young_diagram='diagram'), case_sensitive=False) + convention = dict( + default='English', + description='Sets the convention used for displaying tableaux and partitions', + values=dict( + English='use the English convention', + French='use the French convention', + Russian='use the Russian convention', + ), + case_sensitive=False, + ) notation = dict(alt_name='convention') def _element_constructor_(self, t): @@ -5700,6 +5688,7 @@ def __contains__(self, x): False """ from sage.combinat.partition import _Partitions + if isinstance(x, Tableau): return True if isinstance(x, list): @@ -5814,7 +5803,7 @@ def _an_element_(self): if self.size == 1: return self.element_class(self, [[1]]) - return self.element_class(self, [[1]*(self.size-1), [1]]) + return self.element_class(self, [[1] * (self.size - 1), [1]]) ########################## @@ -5922,6 +5911,7 @@ class SemistandardTableaux(Tableaux): - :class:`StandardTableaux` - :class:`StandardTableau` """ + @staticmethod def __classcall_private__(cls, *args, **kwargs): r""" @@ -6000,6 +5990,7 @@ def __classcall_private__(cls, *args, **kwargs): ValueError: shape must be a (skew) partition """ from sage.combinat.partition import Partition, _Partitions + # Process the keyword arguments -- allow for original syntax where # n == size, p== shape and mu == eval n = kwargs.get('n', None) @@ -6042,12 +6033,14 @@ def __classcall_private__(cls, *args, **kwargs): if shape is not None: from sage.combinat.skew_partition import SkewPartitions + # use in (and not isinstance) below so that lists can be used as # shorthand if shape in _Partitions: shape = Partition(shape) elif shape in SkewPartitions(): from sage.combinat.skew_tableau import SemistandardSkewTableaux + return SemistandardSkewTableaux(shape, mu) else: raise ValueError("shape must be a (skew) partition") @@ -6087,15 +6080,15 @@ def __classcall_private__(cls, *args, **kwargs): else: return SemistandardTableaux_shape_weight(shape, mu) - if (shape is not None): + if shape is not None: if is_inf: return SemistandardTableaux_shape_inf(shape) return SemistandardTableaux_shape(shape, max_entry) - if (mu is not None): + if mu is not None: return SemistandardTableaux_size_weight(sum(mu), mu) - if (size is not None): + if size is not None: if is_inf: return SemistandardTableaux_size_inf(size) return SemistandardTableaux_size(size, max_entry) @@ -6241,16 +6234,14 @@ def __contains__(self, t): False """ if isinstance(t, SemistandardTableau): - return (self.max_entry is None or - len(t) == 0 or - max(max(row) for row in t) <= self.max_entry) + return self.max_entry is None or len(t) == 0 or max(max(row) for row in t) <= self.max_entry if not t: return True if Tableaux.__contains__(self, t): for row in t: if not all(c > 0 for c in row): return False - if not all(row[i] <= row[i+1] for i in range(len(row)-1)): + if not all(row[i] <= row[i + 1] for i in range(len(row) - 1)): return False for row, next in zip(t, t[1:]): if not all(row[c] < next[c] for c in range(len(next))): @@ -6286,9 +6277,8 @@ def __init__(self, max_entry=None): def SST_n(n): return SemistandardTableaux_size(n, max_entry) - DisjointUnionEnumeratedSets.__init__(self, - Family(NonNegativeIntegers(), SST_n), - facade=True, keepkey=False) + + DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), SST_n), facade=True, keepkey=False) else: self.max_entry = None @@ -6392,13 +6382,14 @@ def __iter__(self): True """ from sage.combinat.partition import Partitions + # Iterates through with maximum entry as order i = 1 while True: for part in Partitions(self.size): if i != 1: - for k in range(1, self.size+1): - for c in integer_vectors_nk_fast_iter(self.size - k, i-1): + for k in range(1, self.size + 1): + for c in integer_vectors_nk_fast_iter(self.size - k, i - 1): c.append(k) for sst in SemistandardTableaux_shape_weight(part, Composition(c)): yield self.element_class(self, sst) @@ -6496,8 +6487,8 @@ def __iter__(self): n = sum(self.shape) while True: if i != 1: - for k in range(1, n+1): - for c in integer_vectors_nk_fast_iter(n - k, i-1): + for k in range(1, n + 1): + for c in integer_vectors_nk_fast_iter(n - k, i - 1): c.append(k) for sst in SemistandardTableaux_shape_weight(self.shape, Composition(c)): yield self.element_class(self, sst) @@ -6537,8 +6528,7 @@ def __init__(self, n, max_entry=None): if max_entry is None: max_entry = n - super().__init__(max_entry=max_entry, - category=FiniteEnumeratedSets()) + super().__init__(max_entry=max_entry, category=FiniteEnumeratedSets()) self.size = n def _repr_(self): @@ -6576,9 +6566,7 @@ def __contains__(self, x): if self.size == 0: return x == [] - return (SemistandardTableaux.__contains__(self, x) - and sum(map(len, x)) == self.size - and max(max(row) for row in x) <= self.max_entry) + return SemistandardTableaux.__contains__(self, x) and sum(map(len, x)) == self.size and max(max(row) for row in x) <= self.max_entry def random_element(self): r""" @@ -6610,10 +6598,10 @@ def random_element(self): from sage.rings.integer_ring import ZZ from sage.matrix.constructor import diagonal_matrix from sage.combinat.rsk import RSK + kchoose2m1 = self.max_entry * (self.max_entry - 1) // 2 - 1 km1 = self.max_entry - 1 - weights = [binomial(self.size - i + km1, km1) * binomial((i//2) + kchoose2m1, kchoose2m1) - for i in range(0, self.size + 1, 2)] + weights = [binomial(self.size - i + km1, km1) * binomial((i // 2) + kchoose2m1, kchoose2m1) for i in range(0, self.size + 1, 2)] randpos = ZZ.random_element(sum(weights)) tot = weights[0] pos = 0 @@ -6621,8 +6609,7 @@ def random_element(self): pos += 1 tot += weights[pos] # we now have pos elements over the diagonal and n - 2 * pos on it - m = diagonal_matrix(list(IntegerVectors(self.size - 2 * pos, - self.max_entry).random_element())) + m = diagonal_matrix(list(IntegerVectors(self.size - 2 * pos, self.max_entry).random_element())) above_diagonal = list(IntegerVectors(pos, kchoose2m1 + 1).random_element()) index = 0 for i in range(self.max_entry - 1): @@ -6652,6 +6639,7 @@ def cardinality(self): True """ from sage.combinat.partition import Partitions + c = 0 for part in Partitions(self.size): c += SemistandardTableaux_shape(part, self.max_entry).cardinality() @@ -6697,6 +6685,7 @@ def __iter__(self): True """ from sage.combinat.partition import Partitions + for part in Partitions(self.size): for sst in SemistandardTableaux_shape(part, self.max_entry): yield self.element_class(self, sst) @@ -6736,8 +6725,7 @@ def __init__(self, p, max_entry=None): """ if max_entry is None: max_entry = sum(p) - super().__init__(max_entry=max_entry, - category=FiniteEnumeratedSets()) + super().__init__(max_entry=max_entry, category=FiniteEnumeratedSets()) self.shape = p def __iter__(self): @@ -6833,8 +6821,9 @@ def random_element(self): True """ from sage.misc.prandom import randint - with_sentinels = [max(i, j) for i, j in zip([0]+list(self.shape), [k+1 for k in self.shape]+[0])] - t = [[self.max_entry+1]*i for i in with_sentinels] + + with_sentinels = [max(i, j) for i, j in zip([0] + list(self.shape), [k + 1 for k in self.shape] + [0])] + t = [[self.max_entry + 1] * i for i in with_sentinels] for i, l in enumerate(self.shape): for j in range(l): content = j - i @@ -7058,8 +7047,7 @@ def __init__(self, n, mu): sage: SST = SemistandardTableaux(3, [2,1]) sage: TestSuite(SST).run() # needs sage.modules """ - super().__init__(max_entry=len(mu), - category=FiniteEnumeratedSets()) + super().__init__(max_entry=len(mu), category=FiniteEnumeratedSets()) self.size = n self.weight = mu @@ -7086,6 +7074,7 @@ def __iter__(self): True """ from sage.combinat.partition import Partitions + for p in Partitions(self.size): for sst in SemistandardTableaux_shape_weight(p, self.weight): yield self.element_class(self, sst) @@ -7102,6 +7091,7 @@ def cardinality(self): 3 """ from sage.combinat.partition import Partitions + c = 0 for p in Partitions(self.size): c += SemistandardTableaux_shape_weight(p, self.weight).cardinality() @@ -7118,14 +7108,15 @@ def __contains__(self, x): True """ from sage.combinat.partition import Partition - return x in SemistandardTableaux_shape_weight(Partition( - [len(_) for _ in x]), self.weight) + + return x in SemistandardTableaux_shape_weight(Partition([len(_) for _ in x]), self.weight) ######################### # Row standard Tableaux # ######################### + class RowStandardTableaux(Tableaux): r""" A factory for the various classes of row standard tableaux. @@ -7201,6 +7192,7 @@ class RowStandardTableaux(Tableaux): sage: RowStandardTableau([[3,4,5],[1,2]]).residue_sequence(3).standard_tableaux() Standard tableaux with 3-residue sequence (2,0,0,1,2) and multicharge (0) """ + @staticmethod def __classcall_private__(cls, *args, **kwargs): r""" @@ -7281,8 +7273,7 @@ def __contains__(self, x): return True if Tableaux.__contains__(self, x): flatx = sorted(c for row in x for c in row) - return (flatx == list(range(1, len(flatx)+1)) - and all(row[i] < row[i+1] for row in x for i in range(len(row)-1))) + return flatx == list(range(1, len(flatx) + 1)) and all(row[i] < row[i + 1] for row in x for i in range(len(row) - 1)) return False @@ -7306,9 +7297,7 @@ def __init__(self): sage: TestSuite(ST).run() # needs sage.graphs """ RowStandardTableaux.__init__(self) - DisjointUnionEnumeratedSets.__init__(self, - Family(NonNegativeIntegers(), RowStandardTableaux_size), - facade=True, keepkey=False) + DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), RowStandardTableaux_size), facade=True, keepkey=False) def _repr_(self): """ @@ -7372,9 +7361,8 @@ def __init__(self, n): """ RowStandardTableaux.__init__(self) from sage.combinat.partition import Partitions_n - DisjointUnionEnumeratedSets.__init__(self, - Family(Partitions_n(n), RowStandardTableaux_shape), - facade=True, keepkey=False) + + DisjointUnionEnumeratedSets.__init__(self, Family(Partitions_n(n), RowStandardTableaux_shape), facade=True, keepkey=False) self._size = Integer(n) def _repr_(self): @@ -7493,21 +7481,20 @@ def __iter__(self): sage: st[0].parent() is st # needs sage.graphs True """ - partial_sums = [sum(self.shape[:i]) for i in range(len(self.shape)+1)] + partial_sums = [sum(self.shape[:i]) for i in range(len(self.shape) + 1)] # convert self.shape into a poset relations = [] m = 1 for row in self.shape: - relations += [(m+i, m+i+1) for i in range(row-1)] + relations += [(m + i, m + i + 1) for i in range(row - 1)] m += row - P = Poset((range(1, self.shape.size()+1), relations)) + P = Poset((range(1, self.shape.size() + 1), relations)) L = P.linear_extensions() # now run through the linear extensions and return the corresponding tableau for lin in L: linear_tab = list(permutation.Permutation(lin).inverse()) - tab = [linear_tab[partial_sums[i]:partial_sums[i+1]] - for i in range(len(self.shape))] + tab = [linear_tab[partial_sums[i] : partial_sums[i + 1]] for i in range(len(self.shape))] yield self.element_class(self, tab) def cardinality(self): @@ -7537,6 +7524,7 @@ def cardinality(self): # Standard Tableaux # ######################## + class StandardTableaux(SemistandardTableaux): """ A factory for the various classes of standard tableaux. @@ -7598,6 +7586,7 @@ class StandardTableaux(SemistandardTableaux): sage: StandardTableau([[1,2,3],[4,5]]).residue_sequence(3).standard_tableaux() # needs sage.groups Standard tableaux with 3-residue sequence (0,1,2,2,0) and multicharge (0) """ + @staticmethod def __classcall_private__(cls, *args, **kwargs): r""" @@ -7645,6 +7634,7 @@ def __classcall_private__(cls, *args, **kwargs): if n in SkewPartitions(): from sage.combinat.skew_tableau import StandardSkewTableaux + return StandardSkewTableaux(n) if not isinstance(n, (int, Integer)) or n < 0: @@ -7678,11 +7668,7 @@ def __contains__(self, x): return True if Tableaux.__contains__(self, x): flatx = sorted(c for row in x for c in row) - return all(i == fi for i, fi in enumerate(flatx, start=1)) and (len(x) == 0 or - (all(row[i] < row[i+1] for row in x for i in range(len(row)-1)) and - all(x[r][c] < x[r+1][c] for r in range(len(x)-1) - for c in range(len(x[r+1]))) - )) + return all(i == fi for i, fi in enumerate(flatx, start=1)) and (len(x) == 0 or (all(row[i] < row[i + 1] for row in x for i in range(len(row) - 1)) and all(x[r][c] < x[r + 1][c] for r in range(len(x) - 1) for c in range(len(x[r + 1]))))) return False @@ -7700,9 +7686,7 @@ def __init__(self): sage: ST = StandardTableaux() sage: TestSuite(ST).run() """ - DisjointUnionEnumeratedSets.__init__(self, - Family(NonNegativeIntegers(), StandardTableaux_size), - facade=True, keepkey=False) + DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), StandardTableaux_size), facade=True, keepkey=False) def _repr_(self): """ @@ -7759,10 +7743,8 @@ def __init__(self, n): """ StandardTableaux.__init__(self) from sage.combinat.partition import Partitions_n - DisjointUnionEnumeratedSets.__init__(self, - Family(Partitions_n(n), StandardTableaux_shape), - category=FiniteEnumeratedSets(), - facade=True, keepkey=False) + + DisjointUnionEnumeratedSets.__init__(self, Family(Partitions_n(n), StandardTableaux_shape), category=FiniteEnumeratedSets(), facade=True, keepkey=False) self.size = Integer(n) def _repr_(self): @@ -7845,8 +7827,7 @@ def cardinality(self): # number of involutions without fixed point of size # "size" - "fixed_point_number") for fixed_point_number in fixed_point_numbers: - tableaux_number += (self.size.binomial(fixed_point_number) * - prod(range(1, self.size - fixed_point_number, 2))) + tableaux_number += self.size.binomial(fixed_point_number) * prod(range(1, self.size - fixed_point_number, 2)) return tableaux_number @@ -7893,6 +7874,7 @@ def random_element(self): from sage.misc.prandom import sample from sage.combinat.perfect_matching import PerfectMatchings from sage.combinat.permutation import from_cycles + # We compute the number of involutions of size ``size``. involution_index = randrange(0, StandardTableaux(self.size).cardinality()) # ``involution_index`` is our random integer `r`. @@ -7902,8 +7884,7 @@ def random_element(self): while True: # We add the number of involutions with ``fixed_point_number`` # fixed points. - partial_sum += binomial(self.size, fixed_point_number) * \ - prod(range(1, self.size - fixed_point_number, 2)) + partial_sum += binomial(self.size, fixed_point_number) * prod(range(1, self.size - fixed_point_number, 2)) # If the partial sum is greater than the involution index, # then the random involution that we want to generate has # ``fixed_point_number`` fixed points. @@ -7918,10 +7899,8 @@ def random_element(self): # singletons (corresponding to the fixed points of the # involution) and pairs (forming a perfect matching on the # remaining values). - matching = PerfectMatchings(set(range(1, self.size + 1)) - - set(fixed_point_positions)).random_element() - permutation_cycle_rep = ([(fixed_point,) for fixed_point in fixed_point_positions] - + [tuple(ab) for ab in matching]) + matching = PerfectMatchings(set(range(1, self.size + 1)) - set(fixed_point_positions)).random_element() + permutation_cycle_rep = [(fixed_point,) for fixed_point in fixed_point_positions] + [tuple(ab) for ab in matching] return from_cycles(self.size, permutation_cycle_rep).robinson_schensted()[0] @@ -8054,16 +8033,16 @@ def __iter__(self): pi = self.shape # Set the initial tableau by filling it in going down the columns - tableau = [[None]*n for n in pi] + tableau = [[None] * n for n in pi] size = sum(pi) row = 0 col = 0 for i in range(size): - tableau[row][col] = i+1 + tableau[row][col] = i + 1 # If we can move down, then do it; # otherwise, move to the next column over - if (row + 1 < len(pi) and col < pi[row+1]): + if row + 1 < len(pi) and col < pi[row + 1]: row += 1 else: row = 0 @@ -8073,15 +8052,15 @@ def __iter__(self): # iterate until we reach the last tableau which is # filled with the row indices. - last_tableau = sum([[row]*l for (row, l) in enumerate(pi)], []) + last_tableau = sum([[row] * l for (row, l) in enumerate(pi)], []) # Convert the tableau to "vector format" # tableau_vector[i] is the row that number i # is in - tableau_vector = [None]*size + tableau_vector = [None] * size for row in range(len(pi)): for col in range(pi[row]): - tableau_vector[tableau[row][col]-1] = row + tableau_vector[tableau[row][col] - 1] = row while tableau_vector != last_tableau: # Locate the smallest integer j such that j is not @@ -8089,12 +8068,12 @@ def __iter__(self): # 1,...,j. This happens to be first j such that # ntableau_vector[j] c1) + hooks.extend((k, c1) for k in range(c0 + 1, len(p)) if p[k] > c1) cell = random.choice(hooks) # Assign m to cell @@ -8306,7 +8284,7 @@ def symmetric_group_action_on_values(word, perm): for i in places_l[:dif]: w[i] = r else: - for i in places_r[nbr-dif:]: + for i in places_r[nbr - dif :]: w[i] = l return w @@ -8335,6 +8313,7 @@ def __setstate__(self, state): # Increasing tableaux # ########################## + class IncreasingTableaux(Tableaux): """ A factory class for the various classes of increasing tableaux. @@ -8441,6 +8420,7 @@ class IncreasingTableaux(Tableaux): - :class:`StandardTableau` - :class:`IncreasingTableau` """ + @staticmethod def __classcall_private__(cls, *args, **kwargs): r""" @@ -8518,6 +8498,7 @@ def __classcall_private__(cls, *args, **kwargs): ValueError: shape must be a (skew) partition """ from sage.combinat.partition import Partition, _Partitions + # Process the keyword arguments -- allow for original syntax where # n == size, p== shape and mu == eval n = kwargs.get('n', None) @@ -8560,13 +8541,13 @@ def __classcall_private__(cls, *args, **kwargs): if shape is not None: from sage.combinat.skew_partition import SkewPartitions + # use in (and not isinstance) below so that lists can be used as # shorthand if shape in _Partitions: shape = Partition(shape) elif shape in SkewPartitions(): - raise NotImplementedError("skew increasing tableaux are not" - " currently implemented") + raise NotImplementedError("skew increasing tableaux are not" " currently implemented") # from sage.combinat.skew_tableau import IncreasingSkewTableaux # return IncreasingSkewTableaux(shape, wt) else: @@ -8577,7 +8558,7 @@ def __classcall_private__(cls, *args, **kwargs): k = len(wt) - 1 while k >= 0 and wt[k] == 0: k -= 1 - wt = tuple(wt[:k+1]) + wt = tuple(wt[: k + 1]) if not all(k in [0, 1] for k in wt): raise ValueError("wt must be a binary vector") if max_entry is not None and max_entry != len(wt): @@ -8768,8 +8749,7 @@ def __contains__(self, t): return isinstance(t, (IncreasingTableau, list)) if isinstance(t, IncreasingTableau): - return (self.max_entry is None - or max(max(row) for row in t) <= self.max_entry) + return self.max_entry is None or max(max(row) for row in t) <= self.max_entry if not Tableaux.__contains__(self, t): return False @@ -8777,7 +8757,7 @@ def __contains__(self, t): for row in t: if not all(c > 0 for c in row): return False - if not all(row[i] < row[i+1] for i in range(len(row)-1)): + if not all(row[i] < row[i + 1] for i in range(len(row) - 1)): return False for row, next in zip(t, t[1:]): if not all(row[c] < next[c] for c in range(len(next))): @@ -8846,16 +8826,13 @@ def __init__(self, max_entry=None): def SST_n(n): return IncreasingTableaux_size(n, max_entry) + if max_entry is None or max_entry == PlusInfinity(): self.max_entry = None - DisjointUnionEnumeratedSets.__init__(self, - Family(NonNegativeIntegers(), SST_n), - facade=True, keepkey=False) + DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), SST_n), facade=True, keepkey=False) else: self.max_entry = max_entry - DisjointUnionEnumeratedSets.__init__(self, - Family(list(range(max_entry + 1)), SST_n), - facade=True, keepkey=False) + DisjointUnionEnumeratedSets.__init__(self, Family(list(range(max_entry + 1)), SST_n), facade=True, keepkey=False) def _repr_(self): """ @@ -8937,13 +8914,14 @@ def __iter__(self): True """ from sage.combinat.partition import Partitions + # Iterates through with maximum entry as order i = 1 while True: for part in Partitions(self.size): if i != 1: - for k in range(1, self.size+1): - for c in integer_vectors_nk_fast_iter(self.size - k, i-1): + for k in range(1, self.size + 1): + for c in integer_vectors_nk_fast_iter(self.size - k, i - 1): c.append(k) for sst in IncreasingTableaux_shape_weight(part, tuple(c)): yield self.element_class(self, sst) @@ -9024,8 +9002,8 @@ def __iter__(self): n = sum(self.shape) while True: if i != 1: - for k in range(1, n+1): - for c in integer_vectors_nk_fast_iter(n - k, i-1): + for k in range(1, n + 1): + for c in integer_vectors_nk_fast_iter(n - k, i - 1): c.append(k) for sst in IncreasingTableaux_shape_weight(self.shape, tuple(c)): yield self.element_class(self, sst) @@ -9064,8 +9042,7 @@ def __init__(self, n, max_entry=None): """ if max_entry is None: max_entry = n - super().__init__(max_entry=max_entry, - category=FiniteEnumeratedSets()) + super().__init__(max_entry=max_entry, category=FiniteEnumeratedSets()) self.size = n def _repr_(self): @@ -9097,9 +9074,7 @@ def __contains__(self, x): if self.size == 0: return x == [] - return (IncreasingTableaux.__contains__(self, x) - and sum(map(len, x)) == self.size - and max(max(row) for row in x) <= self.max_entry) + return IncreasingTableaux.__contains__(self, x) and sum(map(len, x)) == self.size and max(max(row) for row in x) <= self.max_entry def __iter__(self): """ @@ -9141,6 +9116,7 @@ def __iter__(self): return from sage.combinat.partition import Partitions + for part in Partitions(self.size): for sst in IncreasingTableaux_shape(part, self.max_entry): yield self.element_class(self, sst) @@ -9180,8 +9156,7 @@ def __init__(self, p, max_entry=None): """ if max_entry is None: max_entry = sum(p) - super().__init__(max_entry=max_entry, - category=FiniteEnumeratedSets()) + super().__init__(max_entry=max_entry, category=FiniteEnumeratedSets()) self.shape = p def __iter__(self): @@ -9258,8 +9233,7 @@ def __contains__(self, x): sage: IT.cardinality() 14 """ - return (IncreasingTableaux.__contains__(self, x) - and [len(row) for row in x] == self.shape) + return IncreasingTableaux.__contains__(self, x) and [len(row) for row in x] == self.shape def _repr_(self): """ @@ -9338,7 +9312,7 @@ def __contains__(self, x): content_list = [0] * int(self.max_entry) for row in x: for i in row: - content_list[i-1] = 1 + content_list[i - 1] = 1 return tuple(content_list) == self.weight @@ -9386,7 +9360,7 @@ def __iter__(self): while list_of_partial_inc_tabs: active_tab = list_of_partial_inc_tabs.pop() unfilled_spots = [] - for (r, c) in active_tab.cells(): + for r, c in active_tab.cells(): if active_tab[r][c] == 0: unfilled_spots.append((r, c)) if not unfilled_spots: @@ -9395,9 +9369,9 @@ def __iter__(self): list_of_inc_tabs.append(self.element_class(self, active_tab)) continue growth_spots = [] - for (r, c) in unfilled_spots: - if (r-1, c) not in active_tab.cells() or active_tab[r-1][c] != 0: - if (r, c-1) not in active_tab.cells() or active_tab[r][c-1] != 0: + for r, c in unfilled_spots: + if (r - 1, c) not in active_tab.cells() or active_tab[r - 1][c] != 0: + if (r, c - 1) not in active_tab.cells() or active_tab[r][c - 1] != 0: growth_spots.append((r, c)) growth_choices = list(powerset(growth_spots)) top_value = max(active_tab.entries()) @@ -9407,9 +9381,9 @@ def __iter__(self): continue for growth_choice in growth_choices[1:]: new_tab = [[0] * k for k in self.shape] - for (r, c) in active_tab.cells(): + for r, c in active_tab.cells(): new_tab[r][c] = active_tab[r][c] - for (r, c) in growth_choice: + for r, c in growth_choice: new_tab[r][c] = growth_num list_of_partial_inc_tabs.append(Tableau(new_tab)) yield from list_of_inc_tabs @@ -9435,8 +9409,7 @@ def __init__(self, n, wt): sage: IT = IncreasingTableaux(3, (1,0,1)) sage: TestSuite(IT).run() """ - super().__init__(max_entry=len(wt), - category=FiniteEnumeratedSets()) + super().__init__(max_entry=len(wt), category=FiniteEnumeratedSets()) self.size = n self.weight = wt @@ -9466,6 +9439,7 @@ def __iter__(self): True """ from sage.combinat.partition import Partitions + for p in Partitions(self.size): for sst in IncreasingTableaux_shape_weight(p, self.weight): yield self.element_class(self, sst) @@ -9481,6 +9455,7 @@ def __contains__(self, x): True """ from sage.combinat.partition import _Partitions + shape = [len(row) for row in x] if shape not in _Partitions: return False diff --git a/src/sage/combinat/tableau_residues.py b/src/sage/combinat/tableau_residues.py index a1c51d46931..c2186dd6ef0 100644 --- a/src/sage/combinat/tableau_residues.py +++ b/src/sage/combinat/tableau_residues.py @@ -128,10 +128,7 @@ from sage.structure.unique_representation import UniqueRepresentation from .partition_tuple import PartitionTuple -from .tableau_tuple import (StandardTableaux_residue, - StandardTableaux_residue_shape, - RowStandardTableauTuples_residue, - RowStandardTableauTuples_residue_shape) +from .tableau_tuple import StandardTableaux_residue, StandardTableaux_residue_shape, RowStandardTableauTuples_residue, RowStandardTableauTuples_residue_shape # ------------------------------------------------- # Residue sequences @@ -139,8 +136,7 @@ # needed for __classcall_private__ -class ResidueSequence(ClonableArray, - metaclass=InheritComparisonClasscallMetaclass): +class ResidueSequence(ClonableArray, metaclass=InheritComparisonClasscallMetaclass): r""" A residue sequence. @@ -211,6 +207,7 @@ class ResidueSequence(ClonableArray, sage: from sage.combinat.tableau_residues import ResidueSequence sage: TestSuite( ResidueSequence(3,(0,0,1), [0,1,2])).run(skip='_test_pickling') """ + @staticmethod def __classcall_private__(cls, e, multicharge, residues=None, check=True): r""" @@ -303,9 +300,7 @@ def __str__(self, join='with'): '3-residue sequence (0,0,1,1,2,2,0,0) and multicharge (0,0,1)' """ string = '{e}-residue sequence ({res}) {join} multicharge ({charge})' - return string.format(e=self.quantum_characteristic(), - res=','.join('%s' % r for r in self), join=join, - charge=','.join('%s' % r for r in self.multicharge())) + return string.format(e=self.quantum_characteristic(), res=','.join('%s' % r for r in self), join=join, charge=','.join('%s' % r for r in self.multicharge())) def __getitem__(self, k): r""" @@ -370,8 +365,7 @@ def restrict(self, m): sage: ResidueSequence(3,(0,0,1),[0,0,1,1,2,2,3,3]).restrict(4) 3-residue sequence (0,0,1,1) with multicharge (0,0,1) """ - return ResidueSequence(self.quantum_characteristic(), - self.multicharge(), self.residues()[:m]) + return ResidueSequence(self.quantum_characteristic(), self.multicharge(), self.residues()[:m]) def restrict_row(self, cell, row): r""" @@ -392,7 +386,7 @@ def restrict_row(self, cell, row): 3-residue sequence (2,0,1,0,1) with multicharge (1,0) """ residues = self.residues() # residue sequence - residues.reverse() # reversed residue sequence + residues.reverse() # reversed residue sequence if residues[0] + row == residues[0]: # if the residues in the two rows are the same we do not @@ -402,20 +396,17 @@ def restrict_row(self, cell, row): # determine the sets of residues, one_res and two_res, that need to be # interchanged in order to swap the corresponding rows row_len = cell[-1] # length of the row being swapped - one_res = [0] # last row of tableau will move - two_res = [0] # will prune this entry later + one_res = [0] # last row of tableau will move + two_res = [0] # will prune this entry later try: for c in range(1, row_len + 1): # residues decrease by 1 from right to left in each row - one_res.append(residues.index(residues[0] - c, - one_res[c - 1] + 1)) + one_res.append(residues.index(residues[0] - c, one_res[c - 1] + 1)) for c in range(row_len + 1): - two_res.append(residues.index(residues[0] - c + row, - two_res[c] + 1)) + two_res.append(residues.index(residues[0] - c + row, two_res[c] + 1)) while two_res[-1] in one_res: # entries in one_res and two_res must be disjoint - two_res[-1] = residues.index(residues[0] - c + row, - two_res[-1] + 1) + two_res[-1] = residues.index(residues[0] - c + row, two_res[-1] + 1) except ValueError: return None @@ -426,9 +417,7 @@ def restrict_row(self, cell, row): residues[two_res[c + 1]] -= row # jump over two_res[0] # remove the first residue, reverse the order and return - return ResidueSequence(self.quantum_characteristic(), - self.multicharge(), - residues[1:][::-1]) + return ResidueSequence(self.quantum_characteristic(), self.multicharge(), residues[1:][::-1]) def swap_residues(self, i, j): r""" @@ -500,8 +489,7 @@ def standard_tableaux(self, shape=None): """ if shape is None: return StandardTableaux_residue(residue=self) - return StandardTableaux_residue_shape(residue=self, - shape=PartitionTuple(shape)) + return StandardTableaux_residue_shape(residue=self, shape=PartitionTuple(shape)) def row_standard_tableaux(self, shape=None): r""" @@ -549,8 +537,7 @@ def negative(self): sage: ResidueSequence(3,[0,0,1],[0,0,1,1,2,2,3,3]).negative() 3-residue sequence (0,0,2,2,1,1,0,0) with multicharge (0,0,1) """ - return ResidueSequence(self.quantum_characteristic(), self.multicharge(), - (self.base_ring()(-i) for i in self)) + return ResidueSequence(self.quantum_characteristic(), self.multicharge(), (self.base_ring()(-i) for i in self)) def block(self): r""" @@ -741,8 +728,7 @@ def _repr_(self): sage: ResidueSequences(2, (0,1,2,3)) 2-residue sequences with multicharge (0, 1, 0, 1) """ - return '{}-residue sequences with multicharge {}'.format(self._quantum_characteristic, - self._multicharge) + return '{}-residue sequences with multicharge {}'.format(self._quantum_characteristic, self._multicharge) def _an_element_(self): r""" diff --git a/src/sage/combinat/tableau_tuple.py b/src/sage/combinat/tableau_tuple.py index 7cc2306a4b1..c5e17b10b57 100644 --- a/src/sage/combinat/tableau_tuple.py +++ b/src/sage/combinat/tableau_tuple.py @@ -213,12 +213,7 @@ from sage.arith.misc import factorial from sage.combinat.combinat import CombinatorialElement from sage.combinat.words.word import Word -from sage.combinat.tableau import (Tableau, Tableaux, Tableaux_size, Tableaux_all, - StandardTableau, RowStandardTableau, - StandardTableaux, StandardTableaux_size, - StandardTableaux_all, StandardTableaux_shape, - RowStandardTableaux, RowStandardTableaux_size, - RowStandardTableaux_all, RowStandardTableaux_shape) +from sage.combinat.tableau import Tableau, Tableaux, Tableaux_size, Tableaux_all, StandardTableau, RowStandardTableau, StandardTableaux, StandardTableaux_size, StandardTableaux_all, StandardTableaux_shape, RowStandardTableaux, RowStandardTableaux_size, RowStandardTableaux_all, RowStandardTableaux_shape from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.sets_cat import Sets from sage.misc.classcall_metaclass import ClasscallMetaclass @@ -352,6 +347,7 @@ class TableauTuple(CombinatorialElement): sage: TestSuite( TableauTuple([ [[1,2],[3,4]], [], [[1,2],[3,4]] ]) ).run() sage: TestSuite( TableauTuple([[[1,1],[1]],[[1,1,1]],[[1],[1],[1]],[[1]]]) ).run() """ + Element = Tableau @staticmethod @@ -498,10 +494,7 @@ def _repr_diagram(self): widths = [len(T_str[0]) for T_str in str_tt] num_cols = max(len(T_str) for T_str in str_tt) - diag = [' '.join(' ' * widths[j] if i >= len(T_str) else - "{:<{width}}".format(T_str[i], width=widths[j]) - for j, T_str in enumerate(str_tt)) - for i in range(num_cols)] + diag = [' '.join(' ' * widths[j] if i >= len(T_str) else "{:<{width}}".format(T_str[i], width=widths[j]) for j, T_str in enumerate(str_tt)) for i in range(num_cols)] if TableauTuples.options('convention') == "English": return '\n'.join(diag) @@ -516,6 +509,7 @@ def _ascii_art_(self): 5 """ from sage.typeset.ascii_art import AsciiArt + return AsciiArt(self._repr_diagram().splitlines()) def _latex_(self): @@ -571,6 +565,7 @@ def _latex_diagram(self): } \Bigg) """ from sage.combinat.output import tex_from_array_tuple + return r'\Bigg( %s \Bigg)' % tex_from_array_tuple(self) def components(self): @@ -666,6 +661,7 @@ def shape(self): ([3], [], [3, 2, 1]) """ from sage.combinat.partition_tuple import PartitionTuples + P = PartitionTuples() return P.element_class(P, [t.shape() for t in self]) @@ -975,6 +971,7 @@ def reduced_row_word(self): [2, 3, 2, 1, 4, 3, 2, 5, 4, 3, 6, 5, 4, 3, 2, 7, 6, 5, 8, 7, 6, 5, 4] """ from sage.combinat.permutation import Permutation + return Permutation(list(self.entries())).inverse().reduced_word_lexmin() def reduced_column_word(self): @@ -1001,6 +998,7 @@ def reduced_column_word(self): [3, 6, 5, 8] """ from sage.combinat.permutation import Permutation + return Permutation(list(self.conjugate().entries())).inverse().reduced_word_lexmin() def cells_containing(self, m): @@ -1024,8 +1022,7 @@ def cells_containing(self, m): sage: t.cells_containing(6) [] """ - return [(k, r, c) for k in range(len(self)) - for (r, c) in self[k].cells_containing(m)] + return [(k, r, c) for k in range(len(self)) for (r, c) in self[k].cells_containing(m)] def up(self, n=None): """ @@ -1083,8 +1080,7 @@ def row_stabilizer(self): # tableau, by including the identity permutation on the set [1..n]. n = max(self.entries()) gens = [list(range(1, n + 1))] - gens.extend((ti[j], ti[j + 1]) for t in self - for ti in t for j in range(len(ti) - 1)) + gens.extend((ti[j], ti[j + 1]) for t in self for ti in t for j in range(len(ti) - 1)) return PermutationGroup(gens) def column_stabilizer(self): @@ -1483,6 +1479,7 @@ class RowStandardTableauTuple(TableauTuple, metaclass=ClasscallMetaclass): sage: TestSuite( RowStandardTableauTuple([[[3,4,6],[1]],[], [[2],[5]]]) ).run() sage: TestSuite( RowStandardTableauTuple([[[3,4,6],[1]],[[7]], [[2],[5]]]) ).run() """ + @staticmethod def __classcall_private__(self, t): r""" @@ -1629,9 +1626,10 @@ def residue_sequence(self, e, multicharge): 3-residue sequence (2,0,1,2,0) with multicharge (0,2) """ res = [0] * self.size() - for (k, r, c) in self.shape().cells(): + for k, r, c in self.shape().cells(): res[self[k][r][c] - 1] = multicharge[k] - r + c from sage.combinat.tableau_residues import ResidueSequence + return ResidueSequence(e, multicharge, res, check=False) def degree(self, e, multicharge): @@ -1686,7 +1684,7 @@ def degree(self, e, multicharge): if res[r] == res[r + 1]: deg -= 2 elif res[r] == res[r + 1] + 1 or res[r] == res[r + 1] - 1: - deg += (e == 2 and 2 or 1) + deg += e == 2 and 2 or 1 res = res.swap_residues(r, r + 1) return deg @@ -1742,7 +1740,7 @@ def codegree(self, e, multicharge): if res[r] == res[r + 1]: codeg -= 2 elif res[r] == res[r + 1] + 1 or res[r] == res[r + 1] - 1: - codeg += (e == 2 and 2 or 1) + codeg += e == 2 and 2 or 1 res = res.swap_residues(r, r + 1) return codeg @@ -1863,6 +1861,7 @@ class StandardTableauTuple(RowStandardTableauTuple): sage: TestSuite( StandardTableauTuple([[[1,3,4],[6]],[], [[2],[5]]]) ).run() sage: TestSuite( StandardTableauTuple([[[1,3,4],[6]],[[7]], [[2],[5]]]) ).run() """ + @staticmethod def __classcall_private__(self, t): r""" @@ -1951,8 +1950,7 @@ def dominates(self, t): sage: t.dominates(s) False """ - return all(self.restrict(m).shape().dominates(t.restrict(m).shape()) - for m in range(1, 1 + self.size())) + return all(self.restrict(m).shape().dominates(t.restrict(m).shape()) for m in range(1, 1 + self.size())) def to_chain(self): """ @@ -2143,6 +2141,7 @@ class TableauTuples(UniqueRepresentation, Parent): sage: 1 in TableauTuples() False """ + Element = TableauTuple level_one_parent_class = Tableaux_all # used in element_constructor options = Tableaux.options @@ -2388,8 +2387,7 @@ def an_element(self): sage: TableauTuples().an_element() ([[1]], [[2]], [[3]], [[4]], [[5]], [[6]], [[7]]) """ - return self.element_class(self, [[[1]], [[2]], [[3]], [[4]], - [[5]], [[6]], [[7]]]) + return self.element_class(self, [[[1]], [[2]], [[3]], [[4]], [[5]], [[6]], [[7]]]) class TableauTuples_level(TableauTuples): @@ -2545,8 +2543,7 @@ def an_element(self): """ if self.size() == 0: return self.element_class(self, [[], [], []]) - return self.element_class(self, [[], - [range(1, self.size() + 1)], []]) + return self.element_class(self, [[], [range(1, self.size() + 1)], []]) class TableauTuples_level_size(TableauTuples): @@ -2724,6 +2721,7 @@ class RowStandardTableauTuples(TableauTuples): - :class:`RowStandardTableau` - :class:`RowStandardTableauTuples` """ + Element = RowStandardTableauTuple level_one_parent_class = RowStandardTableaux_all # used in element_constructor @@ -2781,7 +2779,7 @@ def __classcall_private__(cls, *args, **kwargs): if shape is not None: raise ValueError('the shape was specified more than once') else: - shape = args[0] # we check that it is a PartitionTuple below + shape = args[0] # we check that it is a PartitionTuple below if len(args) == 2: # both the level and size were specified if level is not None and size is not None: @@ -2816,6 +2814,7 @@ def __classcall_private__(cls, *args, **kwargs): # now that the inputs appear to make sense, return the appropriate class if level is not None and level <= 1: from sage.combinat.partition_tuple import PartitionTuple + if isinstance(shape, PartitionTuple): shape = shape[0] if shape is not None: @@ -2912,10 +2911,7 @@ def __contains__(self, t): if TableauTuples.__contains__(self, t) or isinstance(t, (list, tuple)): if all(s in Tableaux() for s in t): flatt = sorted(sum((list(row) for s in t for row in s), [])) - return (flatt == list(range(1, len(flatt) + 1)) - and all(len(s) == 0 or all(row[i] < row[i + 1] - for row in s for i in range(len(row) - 1)) - for s in t)) + return flatt == list(range(1, len(flatt) + 1)) and all(len(s) == 0 or all(row[i] < row[i + 1] for row in s for i in range(len(row) - 1)) for s in t) return t in RowStandardTableaux() return False @@ -2961,9 +2957,8 @@ def __init__(self): """ RowStandardTableauTuples.__init__(self) from sage.combinat.partition_tuple import PartitionTuples - DisjointUnionEnumeratedSets.__init__(self, - Family(PartitionTuples(), RowStandardTableauTuples_shape), - facade=True, keepkey=False) + + DisjointUnionEnumeratedSets.__init__(self, Family(PartitionTuples(), RowStandardTableauTuples_shape), facade=True, keepkey=False) def _repr_(self): """ @@ -2986,8 +2981,7 @@ def an_element(self): sage: RowStandardTableauTuples().an_element() ([[4, 5, 6, 7]], [[2, 3]], [[1]]) """ - return self.element_class(self, reversed([[range(2**(i - 1), 2**i)] - for i in range(1, 4)])) + return self.element_class(self, reversed([[range(2 ** (i - 1), 2**i)] for i in range(1, 4)])) class RowStandardTableauTuples_level(RowStandardTableauTuples, DisjointUnionEnumeratedSets): @@ -3026,9 +3020,8 @@ def __init__(self, level): """ RowStandardTableauTuples.__init__(self) from sage.combinat.partition_tuple import PartitionTuples_level - DisjointUnionEnumeratedSets.__init__(self, - Family(PartitionTuples_level(level), RowStandardTableauTuples_shape), - facade=True, keepkey=False) + + DisjointUnionEnumeratedSets.__init__(self, Family(PartitionTuples_level(level), RowStandardTableauTuples_shape), facade=True, keepkey=False) self._level = level def _repr_(self): @@ -3082,8 +3075,7 @@ def an_element(self): sage: RowStandardTableauTuples(3).an_element() ([[1]], [[2, 3]], [[4, 5, 6, 7]]) """ - return self.element_class(self, [[range(2**(i - 1), 2**i)] - for i in range(1, self.level() + 1)]) + return self.element_class(self, [[range(2 ** (i - 1), 2**i)] for i in range(1, self.level() + 1)]) class RowStandardTableauTuples_size(RowStandardTableauTuples, DisjointUnionEnumeratedSets): @@ -3122,9 +3114,8 @@ def __init__(self, size): """ RowStandardTableauTuples.__init__(self) from sage.combinat.partition_tuple import PartitionTuples_size - DisjointUnionEnumeratedSets.__init__(self, - Family(PartitionTuples_size(size), RowStandardTableauTuples_shape), - facade=True, keepkey=False) + + DisjointUnionEnumeratedSets.__init__(self, Family(PartitionTuples_size(size), RowStandardTableauTuples_shape), facade=True, keepkey=False) self._size = size def _repr_(self): @@ -3180,8 +3171,7 @@ def an_element(self): return self.element_class(self, [[], [], [], []]) if self.size() == 1: return self.element_class(self, [[[1]], [], [], []]) - return self.element_class(self, [[[1]], [range(2, self.size() + 1)], - [], []]) + return self.element_class(self, [[[1]], [range(2, self.size() + 1)], [], []]) class RowStandardTableauTuples_level_size(RowStandardTableauTuples, DisjointUnionEnumeratedSets): @@ -3228,10 +3218,8 @@ def __init__(self, level, size): """ RowStandardTableauTuples.__init__(self) from sage.combinat.partition_tuple import PartitionTuples_level_size - DisjointUnionEnumeratedSets.__init__(self, - Family(PartitionTuples_level_size(level, size), - RowStandardTableauTuples_shape), - facade=True, keepkey=False) + + DisjointUnionEnumeratedSets.__init__(self, Family(PartitionTuples_level_size(level, size), RowStandardTableauTuples_shape), facade=True, keepkey=False) self._level = level self._size = size @@ -3294,9 +3282,7 @@ def an_element(self): return self.element_class(self, sum([[[[1]]]], [[] for _ in range(self.level() - 1)])) if self.size() == 2: return self.element_class(self, sum([[[[1], [2]]]], [[] for _ in range(self.level() - 1)])) - return self.element_class(self, sum([[[[1]]], - [[range(2, self.size()), - [self.size()]]]], [[] for _ in range(self.level() - 2)])) + return self.element_class(self, sum([[[[1]]], [[range(2, self.size()), [self.size()]]]], [[] for _ in range(self.level() - 2)])) class RowStandardTableauTuples_shape(RowStandardTableauTuples): @@ -3324,6 +3310,7 @@ def __init__(self, shape): """ super().__init__(category=FiniteEnumeratedSets()) from sage.combinat.partition_tuple import PartitionTuple + self._shape = PartitionTuple(shape) self._level = len(shape) self._size = shape.size() @@ -3443,8 +3430,7 @@ def __iter__(self): for c in range(len(mu)): for r in range(len(mu[c])): cclen[c][r + 1] = cclen[c][r] + mu[c][r] - relations += [(clen[c]+cclen[c][r]+i+1, clen[c]+cclen[c][r]+i+2) - for i in range(mu[c][r]-1)] + relations += [(clen[c] + cclen[c][r] + i + 1, clen[c] + cclen[c][r] + i + 2) for i in range(mu[c][r] - 1)] clen[c + 1] = clen[c] + cclen[c][-1] # To generate the row standard tableau tuples we are going to generate @@ -3457,14 +3443,10 @@ def tableau_from_list(tab): inserting t_1,..,t_n in order into the rows of mu, from left to right in each component and then left to right along the components. """ - return self.element_class(self, - [[tab[clen[c]:clen[c+1]][cclen[c][r]:cclen[c][r+1]] - for r in range(len(mu[c]))] - for c in range(len(mu))], - check=False) + return self.element_class(self, [[tab[clen[c] : clen[c + 1]][cclen[c][r] : cclen[c][r + 1]] for r in range(len(mu[c]))] for c in range(len(mu))], check=False) # now run through the linear extensions and return the corresponding tableau - for lin in Poset((range(1, mu.size()+1), relations)).linear_extensions(): + for lin in Poset((range(1, mu.size() + 1), relations)).linear_extensions(): linear_tab = list(permutation.Permutation(lin).inverse()) yield tableau_from_list(linear_tab) @@ -3586,8 +3568,7 @@ def __contains__(self, t): except ValueError: return False - return (t.residue_sequence(self._quantum_characteristic, - self._multicharge) == self._residue) + return t.residue_sequence(self._quantum_characteristic, self._multicharge) == self._residue def __iter__(self): r""" @@ -3629,6 +3610,7 @@ def __iter__(self): # the only way that I know to generate these tableaux is to test all # possible shapes in the same block, which is cheap to test from sage.combinat.partition_tuple import PartitionTuples + for mu in PartitionTuples(self._level, self._size): if mu.block(self._quantum_characteristic, self._multicharge) == self._residue.block(): for t in RowStandardTableauTuples_residue_shape(self._residue, mu): @@ -3800,10 +3782,10 @@ def __init__(self, residue, shape): charge = [multicharge[0] - r for r in range(len(shape))] else: standard_shape = [[r] for mu in shape for r in mu] - charge = [multicharge[c] - r for c in range(len(shape)) - for r in range(len(shape[c]))] + charge = [multicharge[c] - r for c in range(len(shape)) for r in range(len(shape[c]))] from sage.combinat.tableau_residues import ResidueSequence + res = ResidueSequence(residue.quantum_characteristic(), charge, residue.residues()) self._standard_tableaux = res.standard_tableaux(standard_shape) @@ -3813,9 +3795,9 @@ def __init__(self, residue, shape): if shape.level() == 1: self._cumulative_lengths = [0, len(shape)] else: - self._cumulative_lengths = [0]*(shape.level()+1) + self._cumulative_lengths = [0] * (shape.level() + 1) for c in range(len(shape)): - self._cumulative_lengths[c+1] = self._cumulative_lengths[c] + len(shape[c]) + self._cumulative_lengths[c + 1] = self._cumulative_lengths[c] + len(shape[c]) def __contains__(self, t): """ @@ -3834,9 +3816,7 @@ def __contains__(self, t): t = RowStandardTableauTuple(t) except ValueError: return False - return (t.shape() == self._shape - and t.residue_sequence(self._quantum_characteristic, - self._multicharge) == self._residue) + return t.shape() == self._shape and t.residue_sequence(self._quantum_characteristic, self._multicharge) == self._residue def _repr_(self): """ @@ -3847,8 +3827,7 @@ def _repr_(self): sage: RowStandardTableau([[1,3],[2,4]]).residue_sequence(3).row_standard_tableaux([2,2]) Row standard (2^2)-tableaux with 3-residue sequence (0,2,1,0) and multicharge (0) """ - return 'Row standard ({})-tableaux with {}'.format(self._shape._repr_compact_high(), - self._residue.__str__('and')) + return 'Row standard ({})-tableaux with {}'.format(self._shape._repr_compact_high(), self._residue.__str__('and')) def __iter__level_one(self): r""" @@ -3884,16 +3863,11 @@ def __iter__higher_levels(self): ([[1, 3]], [[4, 5], [2]])] """ if self._size == 0: - yield self.element_class(self, [[] for _ in range(self._level)], - check=False) # the empty tableau + yield self.element_class(self, [[] for _ in range(self._level)], check=False) # the empty tableau return for t in self._standard_tableaux: - yield self.element_class(self, - [[t[r][0] for r in range(self._cumulative_lengths[c], - self._cumulative_lengths[c + 1])] - for c in range(self._level)], - check=False) + yield self.element_class(self, [[t[r][0] for r in range(self._cumulative_lengths[c], self._cumulative_lengths[c + 1])] for c in range(self._level)], check=False) @lazy_attribute def __iter__(self): @@ -3999,6 +3973,7 @@ class StandardTableauTuples(RowStandardTableauTuples): - :class:`StandardTableau` - :class:`StandardTableauTuples` """ + Element = StandardTableauTuple level_one_parent_class = StandardTableaux_all # used in element_constructor @@ -4058,7 +4033,7 @@ def __classcall_private__(cls, *args, **kwargs): if shape is not None: raise ValueError('the shape was specified more than once') else: - shape = args[0] # we check that it is a PartitionTuple below + shape = args[0] # we check that it is a PartitionTuple below if len(args) == 2: # both the level and size were specified if level is not None and size is not None: @@ -4188,10 +4163,7 @@ def __contains__(self, t): if TableauTuples.__contains__(self, t) or isinstance(t, (list, tuple)): if all(s in Tableaux() for s in t): flatt = sorted(sum((list(row) for s in t for row in s), [])) - return flatt == list(range(1, len(flatt)+1)) and all(len(x) == 0 or - (all(row[i] < row[i+1] for row in x for i in range(len(row)-1)) - and all(x[r][c] < x[r+1][c] for c in range(len(x[0])) - for r in range(len(x)-1) if len(x[r+1]) > c)) for x in t) + return flatt == list(range(1, len(flatt) + 1)) and all(len(x) == 0 or (all(row[i] < row[i + 1] for row in x for i in range(len(row) - 1)) and all(x[r][c] < x[r + 1][c] for c in range(len(x[0])) for r in range(len(x) - 1) if len(x[r + 1]) > c)) for x in t) return t in StandardTableaux() return False @@ -4234,9 +4206,8 @@ def __init__(self): """ StandardTableauTuples.__init__(self) from sage.combinat.partition_tuple import PartitionTuples - DisjointUnionEnumeratedSets.__init__(self, - Family(PartitionTuples(), StandardTableauTuples_shape), - facade=True, keepkey=False) + + DisjointUnionEnumeratedSets.__init__(self, Family(PartitionTuples(), StandardTableauTuples_shape), facade=True, keepkey=False) def _repr_(self): """ @@ -4286,6 +4257,7 @@ def __iter__(self): True """ from sage.combinat.partition_tuple import PartitionTuples + for shape in PartitionTuples(): # We use StandardTableauTuples(shape) to correctly deal with the # case when the shape is of level 1. @@ -4315,9 +4287,8 @@ def __init__(self, level): """ StandardTableauTuples.__init__(self) from sage.combinat.partition_tuple import PartitionTuples_level - DisjointUnionEnumeratedSets.__init__(self, - Family(PartitionTuples_level(level), StandardTableauTuples_shape), - facade=True, keepkey=False) + + DisjointUnionEnumeratedSets.__init__(self, Family(PartitionTuples_level(level), StandardTableauTuples_shape), facade=True, keepkey=False) self._level = level def _repr_(self): @@ -4386,6 +4357,7 @@ def __iter__(self): # Note that the level is greater than one so we do not have to treat # StandardTableaux separately from sage.combinat.partition_tuple import PartitionTuples + for shape in PartitionTuples(self.level()): for t in StandardTableauTuples_shape(shape): yield self.element_class(self, t, check=False) @@ -4401,8 +4373,7 @@ def an_element(self): sage: StandardTableauTuples(size=4).an_element() ([[1]], [[2, 3, 4]], [], []) """ - return self.element_class(self, [[list(range(2**(i - 1), 2**i))] - for i in range(1, self.level() + 1)]) + return self.element_class(self, [[list(range(2 ** (i - 1), 2**i))] for i in range(1, self.level() + 1)]) class StandardTableauTuples_size(StandardTableauTuples, DisjointUnionEnumeratedSets): @@ -4425,9 +4396,8 @@ def __init__(self, size): """ StandardTableauTuples.__init__(self) from sage.combinat.partition_tuple import PartitionTuples_size - DisjointUnionEnumeratedSets.__init__(self, - Family(PartitionTuples_size(size), StandardTableauTuples_shape), - facade=True, keepkey=False) + + DisjointUnionEnumeratedSets.__init__(self, Family(PartitionTuples_size(size), StandardTableauTuples_shape), facade=True, keepkey=False) self._size = size def _repr_(self): @@ -4504,6 +4474,7 @@ def __iter__(self): """ # Iterate through the PartitionTuples and then the tableaux from sage.combinat.partition_tuple import PartitionTuples + for shape in PartitionTuples(size=self.size()): # We use StandardTableauTuples(shape) to correctly deal with the # case when the shape is of level 1. @@ -4525,9 +4496,7 @@ def an_element(self): return self.element_class(self, [[], [], [], []]) if self.size() == 1: return self.element_class(self, [[[1]], [], [], []]) - return self.element_class(self, [[[1]], - [list(range(2, self.size() + 1))], - [], []]) + return self.element_class(self, [[[1]], [list(range(2, self.size() + 1))], [], []]) class StandardTableauTuples_level_size(StandardTableauTuples, DisjointUnionEnumeratedSets): @@ -4552,9 +4521,8 @@ def __init__(self, level, size): """ StandardTableauTuples.__init__(self) from sage.combinat.partition_tuple import PartitionTuples_level_size - DisjointUnionEnumeratedSets.__init__(self, - Family(PartitionTuples_level_size(level, size), StandardTableauTuples_shape), - facade=True, keepkey=False) + + DisjointUnionEnumeratedSets.__init__(self, Family(PartitionTuples_level_size(level, size), StandardTableauTuples_shape), facade=True, keepkey=False) self._level = level self._size = size @@ -4614,8 +4582,8 @@ def cardinality(self): 31936 """ from sage.combinat.partition_tuple import PartitionTuples - return sum(StandardTableauTuples_shape(shape).cardinality() - for shape in PartitionTuples(self.level(), self.size())) + + return sum(StandardTableauTuples_shape(shape).cardinality() for shape in PartitionTuples(self.level(), self.size())) def __iter__(self): """ @@ -4645,6 +4613,7 @@ def __iter__(self): """ # Iterate through the PartitionTuples and then the tableaux from sage.combinat.partition_tuple import PartitionTuples + for shape in PartitionTuples(level=self.level(), size=self.size()): for t in StandardTableauTuples_shape(shape): yield self.element_class(self, t, check=False) @@ -4667,9 +4636,7 @@ def an_element(self): if self.size() == 2: return self.element_class(self, sum([[[[1], [2]]]], [[] for _ in range(self.level() - 1)])) - return self.element_class(self, sum([[[[1]]], - [[list(range(2, self.size())), - [self.size()]]]], [[] for _ in range(self.level() - 2)])) + return self.element_class(self, sum([[[[1]]], [[list(range(2, self.size())), [self.size()]]]], [[] for _ in range(self.level() - 2)])) class StandardTableauTuples_shape(StandardTableauTuples): @@ -4693,6 +4660,7 @@ def __init__(self, shape): """ super().__init__(category=FiniteEnumeratedSets()) from sage.combinat.partition_tuple import PartitionTuple + self._shape = PartitionTuple(shape) self._level = len(shape) self._size = shape.size() @@ -4793,12 +4761,12 @@ def __iter__(self): # and the numbers contained in row r of component c are # tab[ clen[c]:clen[c+1] ][ cclen[c][r]: cclen[c][r+1] ] # where tab=[1,2,...,n] as above - clen = [0]*(len(mu)+1) - cclen = [[0]*(len(mu[c])+1) for c in range(len(mu))] + clen = [0] * (len(mu) + 1) + cclen = [[0] * (len(mu[c]) + 1) for c in range(len(mu))] for c in range(len(mu)): for r in range(len(mu[c])): - cclen[c][r+1] = cclen[c][r]+mu[c][r] - clen[c+1] = clen[c] + cclen[c][-1] + cclen[c][r + 1] = cclen[c][r] + mu[c][r] + clen[c + 1] = clen[c] + cclen[c][-1] # now use clen and cclen to "inflate" tab into a tableau def tableau_from_list(tab): @@ -4807,10 +4775,7 @@ def tableau_from_list(tab): inserting t_1,..,t_n in order into the rows of mu, from left to right in each component and then left to right along the components. """ - return self.element_class(self, [[tab[clen[c]:clen[c+1]][cclen[c][r]:cclen[c][r+1]] - for r in range(len(mu[c]))] - for c in range(len(mu))], - check=False) + return self.element_class(self, [[tab[clen[c] : clen[c + 1]][cclen[c][r] : cclen[c][r + 1]] for r in range(len(mu[c]))] for c in range(len(mu))], check=False) # We're now ready to start generating the tableaux. Here's the first one: initial_tableau = tableau_from_list(tab) @@ -4822,14 +4787,14 @@ def tableau_from_list(tab): # define cols to be the list with cols[r] the cols index of r in # the tableau tab, for 1\le i\le n. We initialise this for tab, # corresponding to the initial tableau. - cols = [0]*(n+1) # cols[m] is the column index of m in tab - mins = [0]*n # the kth position of tab is always larger than mins[k] + cols = [0] * (n + 1) # cols[m] is the column index of m in tab + mins = [0] * n # the kth position of tab is always larger than mins[k] offset = 0 for t in initial_tableau[::-1]: for row in range(len(t)): for col in range(len(t[row])): cols[t[row][col]] = col + offset - mins[t[row][col]-1] = row + col + mins[t[row][col] - 1] = row + col if t: offset += len(t[0]) @@ -4854,23 +4819,23 @@ def max_row_in_component(tab, r): # find the numbers less than r in same component as r-1 c = component[tab.index(r)] while c > 0: - comp = [m for m in tab[clen[c-1]:clen[c]] if m < r and cols[m] > cols[r]] + comp = [m for m in tab[clen[c - 1] : clen[c]] if m < r and cols[m] > cols[r]] if not comp: c -= 1 else: return comp[-1] - while True: # loop until we drop! We'll break out of the loop when done - r = 1 # find the smallest r with cols[r] tuple[list[int], list[int]]: - Legs are represented by the label of both its ends, and 1, 2 as the order of legs of the same node. """ + def aux(tree, budleg, budcnt): """ This auxiliary function computes recursively a list of buds and legs @@ -308,6 +307,7 @@ def __init__(self, parent, tree: OrderedTree) -> None: ... ValueError: not a blossoming tree, bad matching """ + def matching_word(tree): """ Internal function. Return an iterator of the matching word with @@ -514,6 +514,7 @@ def to_tamari(self) -> tuple[BinaryTree, BinaryTree]: sage: B4 [[., [[., [., .]], .]], [., [[., .], .]]] """ + def from_dual_bracket_vector(dvec): """ This function converts dual bracket vectors to binary trees @@ -524,7 +525,7 @@ def from_dual_bracket_vector(dvec): while ridx != dvec[ridx]: ridx -= 1 ltree = from_dual_bracket_vector(dvec[:ridx]) - rtree = from_dual_bracket_vector(dvec[ridx + 1:]) + rtree = from_dual_bracket_vector(dvec[ridx + 1 :]) return BinaryTree([ltree, rtree]) # get the orders of nodes and edges @@ -577,6 +578,7 @@ def from_tamari(ltree, htree) -> Self: ... ValueError: not a Tamari interval """ + def traversal(node, parent, cycord): # internal function, which go through the tree given by cycord # we provide parent to know where to cut @@ -585,7 +587,7 @@ def traversal(node, parent, cycord): children = cycord[node] if parent in cycord[node]: pidx = children.index(parent) - children = children[pidx + 1:] + children[:pidx] + children = children[pidx + 1 :] + children[:pidx] return [traversal(x, node, cycord) for x in children] # initialization and verification @@ -700,6 +702,7 @@ def binary_tree_plot(btree) -> Graphics: g = TamariBlossomingTree.binary_tree_plot(B3) sphinx_plot(g) """ + # auxiliary function to compute coordinates of internal nodes def aux(t, a, b, points): if t.is_empty(): @@ -797,21 +800,19 @@ def plot_meandric(self, semicircle=True, arrow=True) -> Graphics: g = TamariBlossomingTree(Tl).plot_meandric() sphinx_plot(g) """ + def sqnode(x, y): """ Draw a white square node (middle of segments) at position (x, y). """ diam = 0.1 - return polygon2d([[x - diam, y - diam], [x + diam, y - diam], - [x + diam, y + diam], [x - diam, y + diam]], - edgecolor='black', rgbcolor='white', zorder=2) + return polygon2d([[x - diam, y - diam], [x + diam, y - diam], [x + diam, y + diam], [x - diam, y + diam]], edgecolor='black', rgbcolor='white', zorder=2) def cirnode(x, y): """ Draw a black circle node at position (x, y). """ - return circle([x, y], 0.15, fill=True, edgecolor='black', - facecolor='black', zorder=2) + return circle([x, y], 0.15, fill=True, edgecolor='black', facecolor='black', zorder=2) def semicir(x1, x2, isupper): """ @@ -820,8 +821,7 @@ def semicir(x1, x2, isupper): """ sec = (0, pi) if isupper else (pi, 2 * pi) color = 'blue' if isupper else 'red' - return arc([(x1 + x2) / 2, 0], (x2 - x1) / 2, sector=sec, zorder=1, - rgbcolor=color) + return arc([(x1 + x2) / 2, 0], (x2 - x1) / 2, sector=sec, zorder=1, rgbcolor=color) def bezierarc(x1, x2, isupper): """ @@ -835,8 +835,7 @@ def bezierarc(x1, x2, isupper): cp1 = tuple(cp1) cp2 = tuple(cp2) color = 'blue' if isupper else 'red' - return bezier_path([[(x1, 0), cp1, cp2, (x2, 0)]], zorder=1, - rgbcolor=color) + return bezier_path([[(x1, 0), cp1, cp2, (x2, 0)]], zorder=1, rgbcolor=color) # initialization G = Graphics() @@ -849,10 +848,8 @@ def bezierarc(x1, x2, isupper): if i % 2 == 0: G += cirnode(i, 0) if arrow: - G += arrow2d((i, 0), (i + 0.6, 0), rgbcolor='black', - width=1, arrowsize=2) - G += arrow2d((i, 0), (i - 0.6, 0), rgbcolor='black', - width=1, arrowsize=2) + G += arrow2d((i, 0), (i + 0.6, 0), rgbcolor='black', width=1, arrowsize=2) + G += arrow2d((i, 0), (i - 0.6, 0), rgbcolor='black', width=1, arrowsize=2) else: G += line([(i, 0), (i + 0.6, 0)], rgbcolor='black') G += line([(i, 0), (i - 0.6, 0)], rgbcolor='black') @@ -864,7 +861,7 @@ def bezierarc(x1, x2, isupper): for i in range(n): nidx1, nidx2 = eorder[i] k, m = sorted((norder.index(nidx1), norder.index(nidx2))) - G += arcfct(k * 2, i * 2 + 1, True) # upper arc + G += arcfct(k * 2, i * 2 + 1, True) # upper arc G += arcfct(i * 2 + 1, m * 2, False) # lower arc G.axes(show=False) return G @@ -888,10 +885,8 @@ def _latex_(self) -> str: tikz.append('\\begin{tikzpicture}\n') # zorder=0 # arrows - tikz.append(f'\\foreach \\x in {{0, 2, ..., {2 * n}}} ' - '\\draw[-latex, thick] (\\x, 0) -- ++(-0.6, 0);\n') - tikz.append(f'\\foreach \\x in {{0, 2, ..., {2 * n}}} ' - '\\draw[-latex, thick] (\\x, 0) -- ++(0.6, 0);\n') + tikz.append(f'\\foreach \\x in {{0, 2, ..., {2 * n}}} ' '\\draw[-latex, thick] (\\x, 0) -- ++(-0.6, 0);\n') + tikz.append(f'\\foreach \\x in {{0, 2, ..., {2 * n}}} ' '\\draw[-latex, thick] (\\x, 0) -- ++(0.6, 0);\n') # zorder=1 # tree edges norder, eorder = self._node_order, self._edge_order @@ -899,20 +894,14 @@ def _latex_(self) -> str: nidx1, nidx2 = eorder[i] k, m = sorted((norder.index(nidx1), norder.index(nidx2))) # upper arc - tikz.append(f'\\draw[blue, very thick] ({k * 2}, 0) arc ' - f'(180:0:{i - k + 0.5});\n') + tikz.append(f'\\draw[blue, very thick] ({k * 2}, 0) arc ' f'(180:0:{i - k + 0.5});\n') # lower arc - tikz.append(f'\\draw[red, very thick] ({m * 2}, 0) arc ' - f'(0:-180:{m - i - 0.5});\n') + tikz.append(f'\\draw[red, very thick] ({m * 2}, 0) arc ' f'(0:-180:{m - i - 0.5});\n') # zorder=2 # trees nodes, which are circles - tikz.append(f'\\foreach \\x in {{0, 2, ..., {2 * n}}} \\filldraw[black]' - ' (\\x, 0) circle (0.15);\n') + tikz.append(f'\\foreach \\x in {{0, 2, ..., {2 * n}}} \\filldraw[black]' ' (\\x, 0) circle (0.15);\n') # square nodes for edges, which are squares - tikz.append(f'\\foreach \\x in {{1, 3, ..., {2 * n - 1}}}' - '\\node[draw=black, fill=white, ' - 'very thick, minimum size=0.2] ' - '(square) at (\\x, 0) {};\n') + tikz.append(f'\\foreach \\x in {{1, 3, ..., {2 * n - 1}}}' '\\node[draw=black, fill=white, ' 'very thick, minimum size=0.2] ' '(square) at (\\x, 0) {};\n') # ending tikz.append('\\end{tikzpicture}\n') return ''.join(tikz) @@ -936,6 +925,7 @@ def __find_dangling_bud(tree: LabelledOrderedTree) -> list[int]: sage: T1 == T2 True """ + def aux(t, buds, dyck): for st in t: if not st: # bud @@ -982,6 +972,7 @@ def __get_cycle_order(t: LabelledOrderedTree) -> list[int]: counterclockwise order. The root bud is labeled 0, under the assumption that 0 is not present in the canonical labeling. """ + def aux(tree, parent, cycord): cycord[tree.label()] = [parent] + [st.label() for st in tree] for st in tree: @@ -1103,13 +1094,14 @@ def _from_plane_tree(tree, skip_check=False, random_bud=False) -> Self: sage: len(res) 2 """ + def traverse(node, parent, cycord): """ Internal function, construct a plane tree out of the cycle order. The parameter ``parent`` is for knowing where to cut. """ pidx = cycord[node].index(parent) - stnodes = cycord[node][pidx + 1:] + cycord[node][:pidx] + stnodes = cycord[node][pidx + 1 :] + cycord[node][:pidx] return [traverse(stn, node, cycord) for stn in stnodes] # check buds @@ -1136,7 +1128,7 @@ def traverse(node, parent, cycord): prevpos = curpos curpos = cycord[curpos][0] pidx = cycord[curpos].index(prevpos) - for sibling in cycord[curpos][pidx + 1:]: + for sibling in cycord[curpos][pidx + 1 :]: if len(cycord[sibling]) == 1: # a bud color = 1 - color color = 1 - color # going to the opposite half-edge @@ -1208,6 +1200,7 @@ def plot_blossoming(self, aspect=1.0, layout='tree') -> Graphics: g = TamariBlossomingTree(Tl).plot_blossoming() sphinx_plot(g) """ + def euclid_dist(p1, p2): return sum([(p1[i] - p2[i]) ** 2 for i in range(2)]) ** 0.5 @@ -1301,8 +1294,7 @@ def plot_bud(origp, rad, m, bud, dbuds): # trisection of angle rbuds = [rad1 + (rad2 - rad1) / 3 * (1 + i) for i in range(2)] for i in range(2): - G += plot_bud(pos[rn], rbuds[i], budlen, - cycord[rn][budidx[i]], dbuds) + G += plot_bud(pos[rn], rbuds[i], budlen, cycord[rn][budidx[i]], dbuds) else: # two non-consecutive buds, we put each one in the middle for i in range(2): rad1 = rad_dir(pos[rn], pos[cycord[rn][budidx[i] - 1]]) @@ -1311,8 +1303,7 @@ def plot_bud(origp, rad, m, bud, dbuds): if rad2 <= rad1: rad2 += pi * 2 rbud = (rad1 + rad2) / 2 - G += plot_bud(pos[rn], rbud, budlen, - cycord[rn][budidx[i]], dbuds) + G += plot_bud(pos[rn], rbud, budlen, cycord[rn][budidx[i]], dbuds) # output G.axes(show=False) @@ -1341,6 +1332,7 @@ def _binary_tree_arcs(btree: BinaryTree) -> list[tuple[int]]: sage: sorted(TamariBlossomingTree._binary_tree_arcs(B)) [(0, 3), (0, 4), (0, 7), (0, 8), (1, 3), (2, 3), (5, 6), (5, 7)] """ + def aux(bt, offset, arcs): if not bt: return @@ -1389,8 +1381,7 @@ def binary_tree_smooth_drawing(btree, color='blue') -> Graphics: # plot the arcs for e in TamariBlossomingTree._binary_tree_arcs(bt): - G += arc([(e[0] + e[1]) / 2, 0], (e[1] - e[0]) / 2, sector=(0, pi), - rgbcolor=color) + G += arc([(e[0] + e[1]) / 2, 0], (e[1] - e[0]) / 2, sector=(0, pi), rgbcolor=color) G.axes(show=False) return G @@ -1418,15 +1409,14 @@ def smooth_drawing(self) -> Graphics: g = TamariBlossomingTree(Tl).smooth_drawing() sphinx_plot(g) """ + def cirnode(x, y): - return circle([x, y], 0.1, fill=True, edgecolor='black', - facecolor='black', zorder=2) + return circle([x, y], 0.1, fill=True, edgecolor='black', facecolor='black', zorder=2) def semicir(x1, x2, isupper): sec = (0, pi) if isupper else (pi, 2 * pi) color = 'blue' if isupper else 'red' - return arc([(x1 + x2) / 2, 0], (x2 - x1) / 2, sector=sec, zorder=1, - rgbcolor=color) + return arc([(x1 + x2) / 2, 0], (x2 - x1) / 2, sector=sec, zorder=1, rgbcolor=color) # initialization G = Graphics() @@ -1463,6 +1453,7 @@ def is_synchronized(self) -> bool: sage: TamariBlossomingTree.from_plane_tree(T2).is_synchronized() False """ + def aux(tree, isroot=False): """ Check synchronized condition on subtree @@ -1482,6 +1473,7 @@ def aux(tree, isroot=False): if st and not aux(st): # an internal node failing the test return False return True + return aux(self._tree, isroot=True) def is_modern(self) -> bool: @@ -1553,7 +1545,7 @@ def gen_comb(n: int, k: int) -> list[int]: # get a random set with each element appearing with prob 1/k # the size of the set is close to n, with sqrt(n) standard deviation # better than unranking in terms of performance - s: list[int] = [] # the random set + s: list[int] = [] # the random set cs: list[int] = [] # its complement for i in range(k * n + 1): if randrange(k) == 1: @@ -1796,8 +1788,7 @@ def __classcall_private__(cls, size=None): return TamariBlossomingTrees_size(size) -class TamariBlossomingTrees_all(DisjointUnionEnumeratedSets, - TamariBlossomingTrees): +class TamariBlossomingTrees_all(DisjointUnionEnumeratedSets, TamariBlossomingTrees): """ The enumerated set of all Tamari blossoming trees. """ @@ -1823,10 +1814,7 @@ def __init__(self): Tamari blossoming trees sage: TestSuite(TBTA).run() # long time (5s) """ - DisjointUnionEnumeratedSets.__init__( - self, Family(PositiveIntegers(), TamariBlossomingTrees_size), - facade=True, keepkey=False - ) + DisjointUnionEnumeratedSets.__init__(self, Family(PositiveIntegers(), TamariBlossomingTrees_size), facade=True, keepkey=False) def _repr_(self) -> str: """ @@ -1946,8 +1934,7 @@ def __contains__(self, elem) -> bool: sage: TBT4.random_element() in TamariBlossomingTrees(5) False """ - return (isinstance(elem, self.element_class) - and elem.size() == self._size) + return isinstance(elem, self.element_class) and elem.size() == self._size def cardinality(self) -> Integer: r""" @@ -2090,8 +2077,7 @@ def random_element(self) -> TamariBlossomingTree: path = [3] + p1 + [-1] + p2 + [-1, -1] # convert lattice path to blossoming tree tree = TamariBlossomingTrees_size.__path_to_tree(path) - return TamariBlossomingTree._from_plane_tree(tree, skip_check=True, - random_bud=True) + return TamariBlossomingTree._from_plane_tree(tree, skip_check=True, random_bud=True) def __iter__(self) -> Iterator[TamariBlossomingTree]: """ @@ -2120,13 +2106,12 @@ def __iter__(self) -> Iterator[TamariBlossomingTree]: ....: for n in range(1, 6)) True """ + def ballot(m): if m == 0: yield [] return - for ss in IntegerListsLex(length=m * 3, floor=lambda x: x // 3 + 1, - ceiling=lambda x: m, min_slope=0, - check=False): + for ss in IntegerListsLex(length=m * 3, floor=lambda x: x // 3 + 1, ceiling=lambda x: m, min_slope=0, check=False): accu = [3] * ss[0] + [-1] for i in range(1, len(ss)): accu.extend([3] * (ss[i] - ss[i - 1])) @@ -2322,8 +2307,7 @@ def random_element(self) -> TamariBlossomingTree: stack[-1][1].append(subtree) tree = stack[-1][1] tree.append([]) # add the extra bud besides the root - return TamariBlossomingTree._from_plane_tree(tree, skip_check=True, - random_bud=True) + return TamariBlossomingTree._from_plane_tree(tree, skip_check=True, random_bud=True) class ModernBlossomingTreeFactory(SageObject, UniqueRepresentation): @@ -2397,8 +2381,7 @@ def _repr_(self) -> str: sage: ModernBlossomingTreeFactory(16) Random generator of modern blossoming trees of size 16 """ - return (f'Random generator of modern blossoming trees' - f' of size {self._size}') + return f'Random generator of modern blossoming trees' f' of size {self._size}' def random_element(self) -> TamariBlossomingTree: r""" @@ -2446,6 +2429,7 @@ def random_element(self) -> TamariBlossomingTree: sage: B.is_modern() True """ + def genC(dtree: OrderedTree) -> list[OrderedTree]: r""" Generate a forest counted by the series `1 + C(z)`, which @@ -2524,5 +2508,4 @@ def genA(dtree: OrderedTree) -> OrderedTree: l2 = genC(DyckWords(s2).random_element().to_ordered_tree()) l1.extend(l2) tree = OrderedTree(l1) - return TamariBlossomingTree._from_plane_tree(tree, skip_check=True, - random_bud=True) + return TamariBlossomingTree._from_plane_tree(tree, skip_check=True, random_bud=True) diff --git a/src/sage/combinat/tamari_lattices.py b/src/sage/combinat/tamari_lattices.py index 50fc3611820..458161d1384 100644 --- a/src/sage/combinat/tamari_lattices.py +++ b/src/sage/combinat/tamari_lattices.py @@ -224,8 +224,7 @@ def GeneralizedTamariLattice(a, b, m=1): raise ValueError("the condition a>=b*m does not hold") def covers(p): - return [swap(p, i, m) for i in range(len(p) - 1) - if not p[i] and p[i + 1]] + return [swap(p, i, m) for i in range(len(p) - 1) if not p[i] and p[i + 1]] # TODO check the exact best categories to use if m == 0: # generalized Dyck lattices @@ -235,9 +234,7 @@ def covers(p): else: cat = FiniteLatticePosets() - return LatticePoset({p: covers(p) - for p in paths_in_triangle(a, b, a, b)}, - check=False, category=cat) + return LatticePoset({p: covers(p) for p in paths_in_triangle(a, b, a, b)}, check=False, category=cat) def TamariLattice(n, m=1): @@ -344,7 +341,7 @@ def swap_dexter(p, i) -> list[tuple[int, ...]]: tp = tuple(p) for deb in range(i, 0, -1): if not p[deb]: - q = tp[:deb] + tp[i + 1: j + 1] + tp[deb: i + 1] + tp[j + 1:] + q = tp[:deb] + tp[i + 1 : j + 1] + tp[deb : i + 1] + tp[j + 1 :] resu.append(q) else: break @@ -387,9 +384,7 @@ def DexterSemilattice(n): b = n def covers_dexter(p): - data = [swap_dexter(p, i) for i in range(len(p) - 1) - if not p[i] and p[i + 1]] + data = [swap_dexter(p, i) for i in range(len(p) - 1) if not p[i] and p[i + 1]] return [cov for L in data for cov in L] - return MeetSemilattice({p: covers_dexter(p) - for p in paths_in_triangle(a, b, a, b)}, - check=False) + + return MeetSemilattice({p: covers_dexter(p) for p in paths_in_triangle(a, b, a, b)}, check=False) diff --git a/src/sage/combinat/tiling.py b/src/sage/combinat/tiling.py index 087b50a0920..247fbc4ca34 100644 --- a/src/sage/combinat/tiling.py +++ b/src/sage/combinat/tiling.py @@ -350,6 +350,7 @@ def ncube_isometry_group(n, orientation_preserving=True): ValueError: ['B', 0] is not a valid Cartan type """ from sage.combinat.root_system.weyl_group import WeylGroup + L = [w.matrix() for w in WeylGroup(['B', n])] if orientation_preserving: return [m for m in L if m.det() == 1] @@ -431,6 +432,7 @@ def ncube_isometry_group_cosets(n, orientation_preserving=True): """ from sage.misc.misc_c import prod from sage.matrix.constructor import diagonal_matrix + G = ncube_isometry_group(n, orientation_preserving) # Construct the subgroup H of G of diagonal matrices @@ -451,8 +453,8 @@ def ncube_isometry_group_cosets(n, orientation_preserving=True): for g in G: if g not in G_todo: continue - left_coset = sorted(h*g for h in H) - right_coset = sorted(g*h for h in H) + left_coset = sorted(h * g for h in H) + right_coset = sorted(g * h for h in H) assert left_coset == right_coset, "H must be a normal subgroup of G" for c in left_coset: c.set_immutable() @@ -460,6 +462,7 @@ def ncube_isometry_group_cosets(n, orientation_preserving=True): cosets.append(left_coset) return cosets + ############################## # Class Polyomino ############################## @@ -517,15 +520,14 @@ def __init__(self, coords, color='gray', dimension=None): raise TypeError("color = ({!r}) must be a string".format(color)) self._color = color - if not isinstance(coords, (tuple,list)): + if not isinstance(coords, (tuple, list)): coords = list(coords) if dimension is None: if coords: self._dimension = ZZ(len(coords[0])) else: - raise ValueError("dimension(={}) must be provided for" - " the empty polyomino".format(dimension)) + raise ValueError("dimension(={}) must be provided for" " the empty polyomino".format(dimension)) else: self._dimension = dimension self._free_module = FreeModule(ZZ, self._dimension) @@ -633,8 +635,7 @@ def bounding_box(self): sage: p.bounding_box() [[0, 0, 0], [1, 2, 1]] """ - return [[min(w) for w in zip(*self)], - [max(w) for w in zip(*self)]] + return [[min(w) for w in zip(*self)], [max(w) for w in zip(*self)]] def __hash__(self): r""" @@ -803,8 +804,7 @@ def intersection(self, other): """ if not isinstance(other, Polyomino): raise TypeError("other(={}) must be a polyomino".format(other)) - return Polyomino(self.frozenset() & other.frozenset(), - color=self._color, dimension=self._dimension) + return Polyomino(self.frozenset() & other.frozenset(), color=self._color, dimension=self._dimension) def __sub__(self, v): r""" @@ -825,7 +825,7 @@ def __sub__(self, v): Polyomino: [(-2, -2, -2), (-1, -2, -2), (-1, -1, -2), (-1, -1, -1), (-1, 0, -2)], Color: deeppink """ v = self._free_module(v) - return Polyomino([p-v for p in self], color=self._color) + return Polyomino([p - v for p in self], color=self._color) def __add__(self, v): r""" @@ -845,7 +845,7 @@ def __add__(self, v): Polyomino: [(2, 2, 2), (3, 2, 2), (3, 3, 2), (3, 3, 3), (3, 4, 2)], Color: deeppink """ v = self._free_module(v) - return Polyomino([p+v for p in self], color=self._color) + return Polyomino([p + v for p in self], color=self._color) def __rmul__(self, m): r""" @@ -878,8 +878,7 @@ def __rmul__(self, m): ValueError: Dimension of input matrix must match the dimension of the polyomino """ if not m.nrows() == m.ncols() == self._dimension: - raise ValueError("Dimension of input matrix must match the " - "dimension of the polyomino") + raise ValueError("Dimension of input matrix must match the " "dimension of the polyomino") return Polyomino([m * p for p in self], color=self._color) def canonical(self): @@ -908,8 +907,7 @@ def canonical(self): minxyz, _ = self.bounding_box() return self - minxyz - def canonical_isometric_copies(self, orientation_preserving=True, - mod_box_isometries=False): + def canonical_isometric_copies(self, orientation_preserving=True, mod_box_isometries=False): r""" Return the list of image of ``self`` under isometries of the `n`-cube where the coordinates are all nonnegative and minimal. @@ -957,8 +955,7 @@ def canonical_isometric_copies(self, orientation_preserving=True, """ if mod_box_isometries: L = ncube_isometry_group_cosets(self._dimension, orientation_preserving) - P_cosets = {frozenset((m * self).canonical() for m in coset) - for coset in L} + P_cosets = {frozenset((m * self).canonical() for m in coset) for coset in L} P_cosets_representents = [min(s, key=lambda a: a.sorted_list()) for s in P_cosets] return sorted(P_cosets_representents, key=lambda a: a.sorted_list()) L = ncube_isometry_group(self._dimension, orientation_preserving) @@ -1053,14 +1050,12 @@ def translated_copies(self, box): ranges = [range(a) for a in box] box = Polyomino(itertools.product(*ranges)) if not box._dimension == self._dimension: - raise ValueError("Dimension of input box must match the " - "dimension of the polyomino") + raise ValueError("Dimension of input box must match the " "dimension of the polyomino") minxyz, maxxyz = self.bounding_box() minxyz, maxxyz = vector(minxyz), vector(maxxyz) size = maxxyz - minxyz boxminxyz, boxmaxxyz = box.bounding_box() - ranges = [range(a, b - c + 1) - for a, b, c in zip(boxminxyz, boxmaxxyz, size)] + ranges = [range(a, b - c + 1) for a, b, c in zip(boxminxyz, boxmaxxyz, size)] cano = self.canonical() for v in itertools.product(*ranges): translated = cano + v @@ -1106,14 +1101,12 @@ def translated_copies_intersection(self, box): ranges = [range(a) for a in box] box = Polyomino(itertools.product(*ranges)) if not box._dimension == self._dimension: - raise ValueError("Dimension of input box must match the " - "dimension of the polyomino") + raise ValueError("Dimension of input box must match the " "dimension of the polyomino") minxyz, maxxyz = self.bounding_box() minxyz, maxxyz = vector(minxyz), vector(maxxyz) size = maxxyz - minxyz boxminxyz, boxmaxxyz = box.bounding_box() - ranges = [range(a - c, b + 1) - for a, b, c in zip(boxminxyz, boxmaxxyz, size)] + ranges = [range(a - c, b + 1) for a, b, c in zip(boxminxyz, boxmaxxyz, size)] S = set() cano = self.canonical() for v in itertools.product(*ranges): @@ -1123,8 +1116,7 @@ def translated_copies_intersection(self, box): S.add(intersected) return S - def isometric_copies(self, box, orientation_preserving=True, - mod_box_isometries=False): + def isometric_copies(self, box, orientation_preserving=True, mod_box_isometries=False): r""" Return the translated and isometric images of ``self`` that lies in the box. @@ -1178,16 +1170,11 @@ def isometric_copies(self, box, orientation_preserving=True, ranges = [range(a) for a in box] box = Polyomino(itertools.product(*ranges)) if not box._dimension == self._dimension: - raise ValueError("Dimension of input box must match the " - "dimension of the polyomino") + raise ValueError("Dimension of input box must match the " "dimension of the polyomino") box_min_coords, box_max_coords = box.bounding_box() - if mod_box_isometries and len({b - a for a, b in zip(box_min_coords, - box_max_coords)}) < box._dimension: - raise NotImplementedError("The code below assumes that the" - " sizes of the box (={}) are all distinct when" - " argument `mod_box_isometries` is True.".format(box)) - all_distinct_cano = self.canonical_isometric_copies(orientation_preserving, - mod_box_isometries) + if mod_box_isometries and len({b - a for a, b in zip(box_min_coords, box_max_coords)}) < box._dimension: + raise NotImplementedError("The code below assumes that the" " sizes of the box (={}) are all distinct when" " argument `mod_box_isometries` is True.".format(box)) + all_distinct_cano = self.canonical_isometric_copies(orientation_preserving, mod_box_isometries) for cano in all_distinct_cano: yield from cano.translated_copies(box=box) @@ -1223,10 +1210,8 @@ def isometric_copies_intersection(self, box, orientation_preserving=True): [(1, 1), (1, 2)], [(1, 2)]] """ - all_distinct_cano = self.canonical_isometric_copies(orientation_preserving, - mod_box_isometries=False) - return {t for cano in all_distinct_cano - for t in cano.translated_copies_intersection(box=box)} + all_distinct_cano = self.canonical_isometric_copies(orientation_preserving, mod_box_isometries=False) + return {t for cano in all_distinct_cano for t in cano.translated_copies_intersection(box=box)} def neighbor_edges(self): r""" @@ -1263,7 +1248,7 @@ def neighbor_edges(self): [(1, 1), (1, 2)] """ for P, Q in itertools.combinations(self, 2): - s = sorted(map(abs, Q-P)) + s = sorted(map(abs, Q - P)) firsts = s[:-1] last = s[-1] if last == 1 and all(f == 0 for f in firsts): @@ -1323,26 +1308,25 @@ def boundary(self): ((4.5, 5.5), (5.5, 5.5)), ((5.5, 4.5), (5.5, 5.5))] """ if self._dimension != 2: - raise NotImplementedError("The method boundary is currently " - "implemented " - "only for dimension 2") + raise NotImplementedError("The method boundary is currently " "implemented " "only for dimension 2") from collections import defaultdict + horizontal = defaultdict(int) vertical = defaultdict(int) for a in self: x, y = a = tuple(a) horizontal[a] += 1 vertical[a] += 1 - horizontal[(x, y+1)] -= 1 - vertical[(x+1, y)] -= 1 + horizontal[(x, y + 1)] -= 1 + vertical[(x + 1, y)] -= 1 edges = [] h = 0.5 for (x, y), coeff in horizontal.items(): if coeff: - edges.append(((x-h, y-h), (x+h, y-h))) + edges.append(((x - h, y - h), (x + h, y - h))) for (x, y), coeff in vertical.items(): if coeff: - edges.append(((x-h, y-h), (x-h, y+h))) + edges.append(((x - h, y - h), (x - h, y + h))) return edges def show3d(self, size=1): @@ -1366,6 +1350,7 @@ def show3d(self, size=1): assert self._dimension == 3, "Dimension of the polyomino must be 3." from sage.plot.graphics import Graphics from sage.plot.plot3d.platonic import cube + G = Graphics() for p in self: G += cube(p, color=self._color) @@ -1398,6 +1383,7 @@ def show2d(self, size=0.7, color='black', thickness=1): from sage.plot.circle import circle from sage.plot.line import line from sage.plot.polygon import polygon + h = size / 2.0 G = Graphics() for a, b in self: @@ -1405,14 +1391,12 @@ def show2d(self, size=0.7, color='black', thickness=1): k = h / 2.0 for P, Q in self.neighbor_edges(): a, b = (P + Q) / 2.0 - G += polygon([(a-k, b-k), (a+k, b-k), (a+k, b+k), (a-k, b+k), - (a-k, b-k)], color=self._color) + G += polygon([(a - k, b - k), (a + k, b - k), (a + k, b + k), (a - k, b + k), (a - k, b - k)], color=self._color) for edge in self.boundary(): G += line(edge, color=color, thickness=thickness) return G - def self_surrounding(self, radius, remove_incomplete_copies=True, - ncpus=None): + def self_surrounding(self, radius, remove_incomplete_copies=True, ncpus=None): r""" Return a list of isometric copies of ``self`` surrounding it with an annulus of given radius. @@ -1451,12 +1435,11 @@ def self_surrounding(self, radius, remove_incomplete_copies=True, minxyz, maxxyz = self.bounding_box() minxyz, maxxyz = vector(minxyz), vector(maxxyz) v = vector([radius for _ in range(self._dimension)]) - ranges = [range(a,b) for a,b in zip(minxyz-v, maxxyz+v)] + ranges = [range(a, b) for a, b in zip(minxyz - v, maxxyz + v)] box = Polyomino(itertools.product(*ranges)) # Get the rows for this problem - T = TilingSolver([self], box=box, reusable=True, - reflection=True, rotation=True, outside=True) + T = TilingSolver([self], box=box, reusable=True, reflection=True, rotation=True, outside=True) rows = T.rows() # Add one row to force the placement of the central tile @@ -1468,13 +1451,13 @@ def self_surrounding(self, radius, remove_incomplete_copies=True, # Construct the dancing links solver from sage.combinat.matrices.dancing_links import dlx_solver + d = dlx_solver(rows) # Solve solution = d.one_solution(ncpus=ncpus) if solution is None: - raise ValueError('No solution was found with radius={}, ' - 'this tile can not be surrounded by itself'.format(radius)) + raise ValueError('No solution was found with radius={}, ' 'this tile can not be surrounded by itself'.format(radius)) # Recover the polyominoes assert forced_row_number in solution @@ -1486,6 +1469,7 @@ def self_surrounding(self, radius, remove_incomplete_copies=True, # Recolor randomly the polyominoes from sage.plot.colors import Color from random import random + for p in polyominoes: random_color = Color(tuple(random() for _ in range(3))) p.color(random_color) @@ -1563,8 +1547,7 @@ class TilingSolver(SageObject): NotImplementedError: When reflection is allowed and rotation is not allowed """ - def __init__(self, pieces, box, rotation=True, - reflection=False, reusable=False, outside=False): + def __init__(self, pieces, box, rotation=True, reflection=False, reusable=False, outside=False): r""" Constructor. @@ -1591,8 +1574,7 @@ def __init__(self, pieces, box, rotation=True, self._rotation = rotation self._reflection = reflection if not self._rotation and self._reflection: - raise NotImplementedError("When reflection is allowed and " - "rotation is not allowed") + raise NotImplementedError("When reflection is allowed and " "rotation is not allowed") self._reusable = reusable self._outside = outside @@ -1643,8 +1625,7 @@ def is_suitable(self) -> bool: """ if self._reusable: return len(self.rows()) != 0 - return (sum(len(p) for p in self.pieces()) == len(self._box) - and len(self.rows()) != 0) + return sum(len(p) for p in self.pieces()) == len(self._box) and len(self.rows()) != 0 def pieces(self): r""" @@ -1817,16 +1798,12 @@ def rows_for_piece(self, i, mod_box_isometries=False): else: orientation_preserving = True if self._outside: - it = p.isometric_copies_intersection(self._box, - orientation_preserving=orientation_preserving) + it = p.isometric_copies_intersection(self._box, orientation_preserving=orientation_preserving) else: - it = p.isometric_copies(self._box, - orientation_preserving=orientation_preserving, - mod_box_isometries=mod_box_isometries) + it = p.isometric_copies(self._box, orientation_preserving=orientation_preserving, mod_box_isometries=mod_box_isometries) else: if self._reflection: - raise NotImplementedError("Reflection allowed, Rotation not " - "allowed is not implemented") + raise NotImplementedError("Reflection allowed, Rotation not " "allowed is not implemented") else: if self._outside: it = p.translated_copies_intersection(self._box) @@ -1939,10 +1916,10 @@ def _rows_mod_box_isometries(self, i): sage: dlx_solver(T._rows_mod_box_isometries(0)) # long time (10s) Dancing links solver for 96 columns and 5214 rows """ - assert not self._reusable, ("this code assumes the pieces are not reusable") + assert not self._reusable, "this code assumes the pieces are not reusable" len_pieces = len(self._pieces) if not 0 <= i < len_pieces: - raise ValueError("i(={}) must be 0 <= i < {}".format(i,len_pieces)) + raise ValueError("i(={}) must be 0 <= i < {}".format(i, len_pieces)) rows = [] for j in range(len_pieces): if j == i: @@ -2038,6 +2015,7 @@ def row_to_polyomino(self, row_number): if row_number < 0: row_number += len(rows) from bisect import bisect + no = bisect(self.starting_rows(), row_number) - 1 indices = row else: @@ -2065,6 +2043,7 @@ def dlx_solver(self): Dancing links solver for 9 columns and 15 rows """ from sage.combinat.matrices.dancing_links import dlx_solver + return dlx_solver(self.rows()) def _dlx_solutions_iterator(self): @@ -2211,7 +2190,7 @@ def _dlx_incremental_solutions_iterator(self): common_prefix += 1 else: break - for i in range(1, len(A)-common_prefix): + for i in range(1, len(A) - common_prefix): yield A[:-i] for j in range(common_prefix, len(B)): yield B[:j] @@ -2402,19 +2381,16 @@ def animate(self, partial=None, stop=None, size=0.75, axes=False): """ from sage.plot.graphics import Graphics from sage.plot.animate import Animation + dimension = self._box._dimension if dimension == 2: it = self.solve(partial=partial) it = itertools.islice(it, stop) - L = [sum([piece.show2d(size) for piece in solution], Graphics()) - for solution in it] + L = [sum([piece.show2d(size) for piece in solution], Graphics()) for solution in it] (xmin, ymin), (xmax, ymax) = self._box.bounding_box() xmax = xmax + 0.5 ymax = ymax + 0.5 - return Animation(L, xmin=xmin - 0.5, ymin=ymin - 0.5, - xmax=xmax, ymax=ymax, aspect_ratio=1, axes=axes) + return Animation(L, xmin=xmin - 0.5, ymin=ymin - 0.5, xmax=xmax, ymax=ymax, aspect_ratio=1, axes=axes) if dimension == 3: - raise NotImplementedError("3d Animation must be implemented " - "in Jmol first") - raise NotImplementedError("Dimension must be 2 or 3 in order " - "to make an animation") + raise NotImplementedError("3d Animation must be implemented " "in Jmol first") + raise NotImplementedError("Dimension must be 2 or 3 in order " "to make an animation") diff --git a/src/sage/combinat/tools.py b/src/sage/combinat/tools.py index 63c611581c8..1019fc16ed7 100644 --- a/src/sage/combinat/tools.py +++ b/src/sage/combinat/tools.py @@ -1,6 +1,7 @@ r""" Transitive ideal closure tool """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # diff --git a/src/sage/combinat/triangles_FHM.py b/src/sage/combinat/triangles_FHM.py index 8269a33325d..5f6c599921d 100644 --- a/src/sage/combinat/triangles_FHM.py +++ b/src/sage/combinat/triangles_FHM.py @@ -46,6 +46,7 @@ analog of the relationship between gamma-vectors and h-vectors of flag simplicial complexes. """ + from __future__ import annotations from sage.misc.lazy_import import lazy_import @@ -362,8 +363,7 @@ def factor(self) -> list: [M: x*y - y + 1, M: 3*x^2*y^2 - 4*x*y^2 + 2*x*y + y^2 - 2*y + 1] """ p = self._poly - return [self.__class__(fac, self._vars) - for fac, exp in p.factor() for _ in range(exp)] + return [self.__class__(fac, self._vars) for fac, exp in p.factor() for _ in range(exp)] class M_triangle(Triangle): @@ -379,6 +379,7 @@ class M_triangle(Triangle): sage: P.M_triangle() # needs sage.graphs M: x*y - y + 1 """ + _prefix = 'M' def dual(self) -> M_triangle: @@ -402,8 +403,7 @@ def dual(self) -> M_triangle: n = self._n A = self._poly.parent() - dict_dual = {(n - dy, n - dx): coeff - for (dx, dy), coeff in self._poly.monomial_coefficients().items()} + dict_dual = {(n - dy, n - dx): coeff for (dx, dy), coeff in self._poly.monomial_coefficients().items()} return M_triangle(A(dict_dual), variables=(x, y)) def transmute(self) -> M_triangle: @@ -449,9 +449,8 @@ def h(self) -> H_triangle: """ x, y = self._vars n = self._n - step = self._poly.subs({x: y / (y - 1), - y: (y - 1) * x / (1 + (y - 1) * x)}) - step *= (1 + (y - 1) * x)**n + step = self._poly.subs({x: y / (y - 1), y: (y - 1) * x / (1 + (y - 1) * x)}) + step *= (1 + (y - 1) * x) ** n polyh = step.numerator() return H_triangle(polyh, variables=(x, y)) @@ -481,6 +480,7 @@ class H_triangle(Triangle): """ Class for the H-triangles. """ + _prefix = 'H' def transpose(self) -> H_triangle: @@ -506,8 +506,7 @@ def transpose(self) -> H_triangle: n = self._n A = self._poly.parent() - dict_dual = {(n - dy, n - dx): coeff - for (dx, dy), coeff in self._poly.monomial_coefficients().items()} + dict_dual = {(n - dy, n - dx): coeff for (dx, dy), coeff in self._poly.monomial_coefficients().items()} return H_triangle(A(dict_dual), variables=(x, y)) def m(self) -> M_triangle: @@ -526,8 +525,7 @@ def m(self) -> M_triangle: """ x, y = self._vars n = self._n - step = self._poly.subs({x: (x - 1) * y / (1 - y), - y: x / (x - 1)}) * (1 - y)**n + step = self._poly.subs({x: (x - 1) * y / (1 - y), y: x / (x - 1)}) * (1 - y) ** n polym = step.numerator() return M_triangle(polym, variables=(x, y)) @@ -560,7 +558,7 @@ def f(self) -> F_triangle: """ x, y = self._vars n = self._n - step1 = self._poly.subs({x: x / (1 + x), y: y}) * (x + 1)**n + step1 = self._poly.subs({x: x / (1 + x), y: y}) * (x + 1) ** n step2 = step1.subs({x: x, y: y / x}) polyf = step2.numerator() return F_triangle(polyf, variables=(x, y)) @@ -591,8 +589,8 @@ def gamma(self) -> Gamma_triangle: gamma = x.parent().zero() for k in range(n, -1, -1): step = remain.coefficient({x: k}) - gamma += x**(n - k) * step - remain -= x**(n - k) * step.homogenize(x)(x=1 + x, y=1 + x * y) + gamma += x ** (n - k) * step + remain -= x ** (n - k) * step.homogenize(x)(x=1 + x, y=1 + x * y) return Gamma_triangle(gamma, variables=(x, y)) def vector(self): @@ -618,6 +616,7 @@ class F_triangle(Triangle): """ Class for the F-triangles. """ + _prefix = 'F' def h(self) -> H_triangle: @@ -642,8 +641,7 @@ def h(self) -> H_triangle: """ x, y = self._vars n = self._n - step = (1 - x)**n * self._poly.subs({x: x / (1 - x), - y: x * y / (1 - x)}) + step = (1 - x) ** n * self._poly.subs({x: x / (1 - x), y: x * y / (1 - x)}) polyh = step.numerator() return H_triangle(polyh, variables=(x, y)) @@ -688,9 +686,8 @@ def m(self) -> M_triangle: """ x, y = self._vars n = self._n - step = self._poly.subs({x: y * (x - 1) / (1 - x * y), - y: x * y / (1 - x * y)}) - step *= (1 - x * y)**n + step = self._poly.subs({x: y * (x - 1) / (1 - x * y), y: x * y / (1 - x * y)}) + step *= (1 - x * y) ** n polym = step.numerator() return M_triangle(polym, variables=(x, y)) @@ -745,6 +742,7 @@ class Gamma_triangle(Triangle): """ Class for the Gamma-triangles. """ + _prefix = 'Γ' def h(self) -> H_triangle: @@ -775,8 +773,7 @@ def h(self) -> H_triangle: """ x, y = self._vars n = self._n - resu = (1 + x)**n * self._poly(x=x / (1 + x)**2, - y=(1 + x * y) / (1 + x)) + resu = (1 + x) ** n * self._poly(x=x / (1 + x) ** 2, y=(1 + x * y) / (1 + x)) polyh = resu.numerator() return H_triangle(polyh, variables=(x, y)) diff --git a/src/sage/combinat/tuple.py b/src/sage/combinat/tuple.py index 17b8043cf0c..0534d0aa484 100644 --- a/src/sage/combinat/tuple.py +++ b/src/sage/combinat/tuple.py @@ -1,6 +1,7 @@ r""" Tuples """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # @@ -55,6 +56,7 @@ class Tuples(Parent, UniqueRepresentation): (1, a), (a, a), (a + 1, a), (1, a + 1), (a, a + 1), (a + 1, a + 1)] """ + @staticmethod def __classcall_private__(cls, S, k): """ @@ -219,8 +221,7 @@ def unrank(self, i): if i < 0: raise IndexError("index out of range") if i >= self.cardinality(): - raise IndexError("index i (={}) is greater than or equal to the cardinality" - .format(i)) + raise IndexError("index i (={}) is greater than or equal to the cardinality".format(i)) ts = len(self.S) if ts <= 1: return tuple(self.S[0] for _ in range(self.k)) @@ -282,6 +283,7 @@ class UnorderedTuples(Parent, UniqueRepresentation): [('a', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'b'), ('b', 'c'), ('c', 'c')] """ + @staticmethod def __classcall_private__(cls, S, k): """ diff --git a/src/sage/combinat/vector_partition.py b/src/sage/combinat/vector_partition.py index ce93ebb4e9d..491b2d4f12d 100644 --- a/src/sage/combinat/vector_partition.py +++ b/src/sage/combinat/vector_partition.py @@ -7,6 +7,7 @@ - Shriya M (2022): added new parameters such as ``distinct``, ``parts`` and ``is_repeatable`` """ + # **************************************************************************** # Copyright (C) 2013 Amritanshu Prasad # 2022 Shriya M <25shriya@gmail.com> @@ -115,6 +116,7 @@ class VectorPartition(CombinatorialElement): r""" A vector partition is a multiset of integer vectors. """ + @staticmethod def __classcall_private__(cls, vecpar): """ @@ -250,6 +252,7 @@ class VectorPartitions(UniqueRepresentation, Parent): sage: list(Vector_Partitions) [[[0, 1], [0, 1], [1, 0], [1, 0]], [[0, 1], [1, 0], [1, 1]]] """ + @staticmethod def __classcall_private__(cls, vec, min=None, parts=None, distinct=False, is_repeatable=None): r""" @@ -276,11 +279,9 @@ def __classcall_private__(cls, vec, min=None, parts=None, distinct=False, is_rep parts = list(parts) for part_index in range(len(parts)): parts[part_index] = tuple(parts[part_index]) - return super().__classcall__(cls, tuple(vec), tuple(min), tuple(parts), - distinct, is_repeatable) + return super().__classcall__(cls, tuple(vec), tuple(min), tuple(parts), distinct, is_repeatable) - def __init__(self, vec, min=None, parts=None, distinct=False, - is_repeatable=None) -> None: + def __init__(self, vec, min=None, parts=None, distinct=False, is_repeatable=None) -> None: r""" Initialize ``self``. @@ -331,18 +332,17 @@ def __iter__(self): elif any(part[i] > self._vec[i] for i in range(len(self._vec))): pass else: # recursively find all possibilities for the rest of the vector partition - new_vec = tuple(self._vec[i] - part[i] - for i in range(len(self._vec))) + new_vec = tuple(self._vec[i] - part[i] for i in range(len(self._vec))) i = self._parts.index(part) if self._is_repeatable is None: if self._distinct: - new_parts = self._parts[i + 1:] + new_parts = self._parts[i + 1 :] else: new_parts = self._parts[i:] else: if self._is_repeatable(part): new_parts = self._parts[i:] else: - new_parts = self._parts[i + 1:] + new_parts = self._parts[i + 1 :] for vecpar in VectorPartitions(new_vec, min=self._min, parts=new_parts, distinct=self._distinct, is_repeatable=self._is_repeatable): yield self.element_class(self, [list(part)] + list(vecpar)) diff --git a/src/sage/combinat/words/abstract_word.py b/src/sage/combinat/words/abstract_word.py index 125aaa551cd..1836c4b0d82 100644 --- a/src/sage/combinat/words/abstract_word.py +++ b/src/sage/combinat/words/abstract_word.py @@ -20,6 +20,7 @@ sage: p.length() 231 """ + # **************************************************************************** # Copyright (C) 2008-2010 Sebastien Labbe , # 2008-2010 Franco Saliola @@ -390,7 +391,7 @@ def _longest_common_prefix_iterator(self, other): sage: w = Word(it, length='finite'); w word: 0100101001 """ - for (b, c) in zip(self, other): + for b, c in zip(self, other): if b == c: yield b else: @@ -479,13 +480,13 @@ def longest_common_prefix(self, other, length='unknown'): """ it = self._longest_common_prefix_iterator(other) - if length == "finite" or \ - (length == "unknown" and (self.is_finite() or other.is_finite())): + if length == "finite" or (length == "unknown" and (self.is_finite() or other.is_finite())): parent = self._parent.factors() elif length == "infinite": parent = self._parent.shift() elif length == "unknown": from sage.combinat.words.words import FiniteOrInfiniteWords + parent = FiniteOrInfiniteWords(self._parent.alphabet()) else: raise ValueError("invalid argument length (={})".format(length)) @@ -557,6 +558,7 @@ def longest_periodic_prefix(self, period=1): parent = self._parent.factors() else: from sage.combinat.words.words import FiniteOrInfiniteWords + parent = FiniteOrInfiniteWords(self._parent.alphabet()) return parent(self._longest_periodic_prefix_iterator(period)) @@ -620,8 +622,8 @@ def _to_integer_iterator(self, use_parent_alphabet=False): [1, 2, 2, 3, 3, 3] """ from sage.combinat.words.words import FiniteWords, InfiniteWords - if use_parent_alphabet and\ - isinstance(self.parent(), (FiniteWords, InfiniteWords)): + + if use_parent_alphabet and isinstance(self.parent(), (FiniteWords, InfiniteWords)): A = self.parent().alphabet() for letter in self: yield A.rank(letter) @@ -658,6 +660,7 @@ def to_integer_word(self): """ length = "unknown" if self._len is None else self._len from sage.combinat.words.word import Word + return Word(self._to_integer_iterator(), length=length) def lex_less(self, other): @@ -755,6 +758,7 @@ def apply_morphism(self, morphism): word: 8998988998898998988989988998988998898998... """ from sage.combinat.words.morphism import WordMorphism + if not isinstance(morphism, WordMorphism): morphism = WordMorphism(morphism) return morphism(self) @@ -819,6 +823,7 @@ def delta(self): """ from sage.combinat.words.word import Word from sage.rings.semirings.non_negative_integer_semiring import NN + return Word(self._delta_iterator(), alphabet=NN) def _iterated_right_palindromic_closure_iterator(self, f=None): @@ -880,7 +885,7 @@ def _iterated_right_palindromic_closure_iterator(self, f=None): w = self[:0] for letter in self: length_before = w.length() - w = (w*par([letter])).palindromic_closure(f=f) + w = (w * par([letter])).palindromic_closure(f=f) length_after = w.length() d = length_after - length_before yield from w[-d:] @@ -969,7 +974,7 @@ def _iterated_right_palindromic_closure_recursive_iterator(self, f=None): if pos == -1: to_append = parent([letter]).palindromic_closure(f=f) + ipcw else: - to_append = ipcw[lengths[pos]:] + to_append = ipcw[lengths[pos] :] ipcw += to_append yield from to_append @@ -1084,6 +1089,7 @@ def iterated_right_palindromic_closure(self, f=None, algorithm='recursive'): if self.is_finite(): return self._parent(it) from sage.combinat.words.words import Words + parent = Words(self._parent.alphabet()) return parent(it) @@ -1136,8 +1142,8 @@ def prefixes_iterator(self, max_length=None): """ to_consider = self if max_length is None else self[:max_length] yield self[:0] - for (i, a) in enumerate(to_consider): - yield self[:i + 1] + for i, a in enumerate(to_consider): + yield self[: i + 1] def palindrome_prefixes_iterator(self, max_length=None): r""" @@ -1282,6 +1288,7 @@ def partial_sums(self, start, mod=None): else: length = "unknown" from sage.combinat.words.word import Word + return Word(it, alphabet=alphabet, length=length) def _finite_differences_iterator(self, mod=None): @@ -1419,6 +1426,7 @@ def finite_differences(self, mod=None): else: length = "unknown" from sage.combinat.words.word import Word + return Word(it, alphabet=alphabet, length=length) def sum_digits(self, base=2, mod=None): @@ -1514,6 +1522,7 @@ def sum_digits(self, base=2, mod=None): length = "unknown" from sage.combinat.words.word import Word + return Word(it, alphabet=alphabet, length=length, datatype='iter') def first_occurrence(self, other, start=0): @@ -1574,8 +1583,8 @@ def first_occurrence(self, other, start=0): suff = other.good_suffix_table() s = start while s <= lm - lf: - for j in range(lf-1, -1, -1): - a = self[s+j] + for j in range(lf - 1, -1, -1): + a = self[s + j] if other[j] != a: s += max(suff[j + 1], j - occ.get(a, -1)) break @@ -1620,7 +1629,7 @@ def factor_occurrences_iterator(self, fact): p = self.first_occurrence(fact, start=0) while p is not None: yield p - p = self.first_occurrence(fact, start=p+1) + p = self.first_occurrence(fact, start=p + 1) def return_words_iterator(self, fact): r""" @@ -1712,7 +1721,7 @@ def complete_return_words_iterator(self, fact): i = next(it) while True: j = next(it) - yield self[i:j+L] + yield self[i : j + L] i = j except StopIteration: return diff --git a/src/sage/combinat/words/all.py b/src/sage/combinat/words/all.py index 0119d1b579f..cbae3b363be 100644 --- a/src/sage/combinat/words/all.py +++ b/src/sage/combinat/words/all.py @@ -39,14 +39,17 @@ See :func:`~sage.combinat.words.word_options.WordOptions`. """ + # install the docstring of this module to the containing package from sage.misc.namespace_package import install_doc + install_doc(__package__, __doc__) from sage.misc.lazy_import import lazy_import from sage.combinat.words.alphabet import Alphabet, build_alphabet from sage.combinat.words.morphism import WordMorphism + lazy_import('sage.combinat.words.paths', 'WordPaths') from sage.combinat.words.word import Word from sage.combinat.words.word_options import WordOptions diff --git a/src/sage/combinat/words/alphabet.py b/src/sage/combinat/words/alphabet.py index e377a2970c4..c78a4ef8c07 100644 --- a/src/sage/combinat/words/alphabet.py +++ b/src/sage/combinat/words/alphabet.py @@ -21,6 +21,7 @@ sage: build_alphabet(name='lower') {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'} """ + # **************************************************************************** # Copyright (C) 2008 Franco Saliola # @@ -41,18 +42,7 @@ from sage.sets.totally_ordered_finite_set import TotallyOrderedFiniteSet -set_of_letters = { - 'lower': "abcdefghijklmnopqrstuvwxyz", - 'upper': "ABCDEFGHIJKLMNOPQRSTUVWXYZ", - 'space': " ", - 'underscore': "_", - 'punctuation': " ,.;:!?", - 'printable': "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", - 'binary': "01", - 'octal': "01234567", - 'decimal': "0123456789", - 'hexadecimal': "0123456789abcdef", - 'radix64': "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"} +set_of_letters = {'lower': "abcdefghijklmnopqrstuvwxyz", 'upper': "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 'space': " ", 'underscore': "_", 'punctuation': " ,.;:!?", 'printable': "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", 'binary': "01", 'octal': "01234567", 'decimal': "0123456789", 'hexadecimal': "0123456789abcdef", 'radix64': "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"} def build_alphabet(data=None, names=None, name=None): @@ -209,14 +199,14 @@ def build_alphabet(data=None, names=None, name=None): raise ValueError("name cannot be specified with any other argument") # Swap arguments if we need to try and make sure we have "good" user input - if isinstance(names, (int, Integer)) or names == Infinity \ - or (data is None and names is not None): + if isinstance(names, (int, Integer)) or names == Infinity or (data is None and names is not None): data, names = names, data # data is an integer if isinstance(data, (int, Integer)): if names is None: from sage.sets.integer_range import IntegerRange + return IntegerRange(Integer(data)) if isinstance(names, str): return TotallyOrderedFiniteSet([names + '%d' % i for i in range(data)]) @@ -243,6 +233,7 @@ def build_alphabet(data=None, names=None, name=None): raise TypeError("name must be a string") if name == "positive integers" or name == "PP": from sage.sets.positive_integers import PositiveIntegers + return PositiveIntegers() if name == "natural numbers" or name == "NN": return NonNegativeIntegers() @@ -258,6 +249,7 @@ def build_alphabet(data=None, names=None, name=None): # Alphabet(**nothing**) if data is None: # name is also None from sage.sets.pythonclass import Set_PythonType + return Set_PythonType(object) raise ValueError("unable to construct an alphabet from the given parameters") diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index 37c47778f75..578afb4c975 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -201,6 +201,7 @@ sage: f.bispecial_factors() [word: , word: 0, word: 010, word: 010010, word: 01001010010] """ + # **************************************************************************** # Copyright (C) 2008 Arnaud Bergeron , # 2008 Amy Glen , @@ -290,8 +291,7 @@ def _repr_(self): 'word: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,...' """ if word_options['old_repr']: - if word_options['truncate'] and \ - self.length() > word_options['truncate_length']: + if word_options['truncate'] and self.length() > word_options['truncate_length']: return "Finite word of length {} over {}".format(self.length(), str(self.parent().alphabet())[17:]) return word_options['identifier'] + self.string_rep() @@ -510,9 +510,7 @@ def fcn(n): if length in ZZ and length >= 0: return self._parent(fcn, length=length) - raise ValueError("Power of the word is not defined on the exponent {}: " - "the length of the word ({}) times the exponent ({}) must " - "be a positive integer".format(exp, self.length(), exp)) + raise ValueError("Power of the word is not defined on the exponent {}: " "the length of the word ({}) times the exponent ({}) must " "be a positive integer".format(exp, self.length(), exp)) def length(self): r""" @@ -570,6 +568,7 @@ def content(self, n=None): [0, 1, 0, 1] """ from collections import Counter + c = Counter(self) if n is not None: alphabet = range(1, n + 1) @@ -613,6 +612,7 @@ def is_yamanouchi(self, n=None): False """ from sage.combinat.words.word import Word + if n is not None: w = Word(self, alphabet=list(range(1, n + 1))) elif not self.parent().alphabet().cardinality() == +Infinity: @@ -622,7 +622,7 @@ def is_yamanouchi(self, n=None): l = w.length() for a in range(l - 1, -1, -1): mu = w.parent()(self[a:]).content() - if not all(mu[i] >= mu[i+1] for i in range(len(mu)-1)): + if not all(mu[i] >= mu[i + 1] for i in range(len(mu) - 1)): return False return True @@ -685,7 +685,7 @@ def schuetzenberger_involution(self, n=None): elif r.length() > 0: n = max(w) for k in range(r.length()): - w[k] = n+1 - w[k] + w[k] = n + 1 - w[k] return parent(w, check=False) def foata_bijection(self): @@ -746,8 +746,7 @@ def foata_bijection(self): word: 3113a1 """ s = self.standard_permutation() - ordered_alphabet = sorted(self.letters(), - key=self.parent().sortkey_letters) + ordered_alphabet = sorted(self.letters(), key=self.parent().sortkey_letters) eval_dict = self.evaluation_dict() weight = [eval_dict[a] for a in ordered_alphabet] return (s.foata_bijection()).destandardize(weight, ordered_alphabet=ordered_alphabet) @@ -843,6 +842,7 @@ def to_integer_word(self): word: 1002 """ from sage.combinat.words.word import Word + return Word(self.to_integer_list()) def to_integer_list(self): @@ -891,6 +891,7 @@ def to_ordered_set_partition(self): [{1, 2, 3, 4, 5}] """ from sage.combinat.set_partition_ordered import OrderedSetPartition + return OrderedSetPartition(word_to_ordered_set_partition(self)) # To fix : do not slice here ! (quite expensive in copy) @@ -915,7 +916,7 @@ def is_suffix(self, other): sage: Word().is_suffix(Word()) True """ - return self.is_empty() or self == other[-self.length():] + return self.is_empty() or self == other[-self.length() :] def is_proper_suffix(self, other): r""" @@ -972,6 +973,7 @@ def has_suffix(self, other) -> bool: True """ from sage.combinat.words.word import Word + w = Word(other) return w.is_suffix(self) @@ -994,7 +996,7 @@ def is_prefix(self, other): sage: Word().is_prefix(Word()) True """ - return self == other[:self.length()] + return self == other[: self.length()] def is_proper_prefix(self, other): r""" @@ -1048,6 +1050,7 @@ def has_prefix(self, other) -> bool: True """ from sage.combinat.words.word import Word + w = Word(other) return w.is_prefix(self) @@ -1078,10 +1081,10 @@ def prefix_function_table(self): [] """ k = 0 - res = [0]*self.length() + res = [0] * self.length() for q in range(1, self.length()): while k > 0 and self[k] != self[q]: - k = res[k-1] + k = res[k - 1] if self[k] == self[q]: k += 1 res[q] = k @@ -1105,10 +1108,10 @@ def good_suffix_table(self): """ l = self.length() p = self.reversal().prefix_function_table() - res = [l - p[-1]]*(l+1) - for i in range(1, l+1): + res = [l - p[-1]] * (l + 1) + for i in range(1, l + 1): j = l - p[i - 1] - res[j] = min(res[j], i - p[i-1]) + res[j] = min(res[j], i - p[i - 1]) return res @cached_method @@ -1136,6 +1139,7 @@ def suffix_trie(self): Suffix Trie of the word: 01011 """ from sage.combinat.words.suffix_trees import SuffixTrie + return SuffixTrie(self) def implicit_suffix_tree(self): @@ -1164,6 +1168,7 @@ def implicit_suffix_tree(self): Implicit Suffix Tree of the word: 01011 """ from sage.combinat.words.suffix_trees import ImplicitSuffixTree + return ImplicitSuffixTree(self) @cached_method @@ -1410,13 +1415,13 @@ def factor_set(self, n=None, algorithm='suffix tree'): if algorithm == 'naive': if n is None: S = {self[0:0]} - for n in range(1, self.length()+1): - for i in range(self.length()-n+1): - S.add(self[i:i+n]) + for n in range(1, self.length() + 1): + for i in range(self.length() - n + 1): + S.add(self[i : i + n]) return Set(S) S = set() - for i in range(self.length()-n+1): - S.add(self[i:i+n]) + for i in range(self.length() - n + 1): + S.add(self[i : i + n]) return Set(S) raise ValueError(f'unknown algorithm (={algorithm})') @@ -1485,7 +1490,8 @@ def topological_entropy(self, n): return 1 pn = self.number_of_factors(n) from sage.functions.log import log - return log(pn, base=d)/n + + return log(pn, base=d) / n def rauzy_graph(self, n): r""" @@ -1553,12 +1559,13 @@ def rauzy_graph(self, n): (word: , word: , word: c)] """ from sage.graphs.digraph import DiGraph + multiedges = n == 0 g = DiGraph(loops=True, multiedges=multiedges) if n == self.length(): g.add_vertex(self) else: - for w in self.factor_iterator(n+1): + for w in self.factor_iterator(n + 1): u = w[:-1] v = w[1:] a = w[-1:] @@ -1666,6 +1673,7 @@ def reduced_rauzy_graph(self, n): """ from sage.graphs.digraph import DiGraph from copy import copy + g = copy(self.rauzy_graph(n)) # Otherwise it changes the rauzy_graph function. l = [v for v in g if g.in_degree(v) == 1 == g.out_degree(v)] @@ -1674,7 +1682,7 @@ def reduced_rauzy_graph(self, n): g = DiGraph() g.allow_loops(True) g.add_vertex(self[:n]) - g.add_edge(self[:n], self[:n], self[n:n + len(l)]) + g.add_edge(self[:n], self[:n], self[n : n + len(l)]) else: g.allow_loops(True) g.allow_multiple_edges(True) @@ -1714,7 +1722,7 @@ def left_special_factors_iterator(self, n=None): yield from self.left_special_factors_iterator(i) else: left_extensions = defaultdict(set) - for w in self.factor_iterator(n+1): + for w in self.factor_iterator(n + 1): v = w[1:] left_extensions[v].add(w[0]) for v in left_extensions: @@ -1779,7 +1787,7 @@ def right_special_factors_iterator(self, n=None): yield from self.right_special_factors_iterator(i) else: right_extensions = defaultdict(set) - for w in self.factor_iterator(n+1): + for w in self.factor_iterator(n + 1): v = w[:-1] right_extensions[v].add(w[-1]) for v in right_extensions: @@ -1873,8 +1881,7 @@ def bispecial_factors_iterator(self, n=None): left_extensions[v].add(w[0]) right_extensions[v].add(w[-1]) for v in left_extensions: - if (len(left_extensions[v]) > 1 and - len(right_extensions[v]) > 1): + if len(left_extensions[v]) > 1 and len(right_extensions[v]) > 1: yield v def bispecial_factors(self, n=None): @@ -2362,7 +2369,7 @@ def longest_common_suffix(self, other): for i, (b, c) in iter: if b != c: return self[-i:] - return self[-i-1:] + return self[-i - 1 :] def is_palindrome(self, f=None): r""" @@ -2468,13 +2475,14 @@ def is_palindrome(self, f=None): """ l = self.length() if f is None: - return self[:l//2] == self[l//2 + l % 2:].reversal() + return self[: l // 2] == self[l // 2 + l % 2 :].reversal() from sage.combinat.words.morphism import WordMorphism + if not isinstance(f, WordMorphism): f = WordMorphism(f) if not f.is_involution(): raise ValueError("f must be an involution") - return self[:l//2 + l % 2] == f(self[l//2:].reversal()) + return self[: l // 2 + l % 2] == f(self[l // 2 :].reversal()) def lps(self, f=None, l=None): r""" @@ -2551,7 +2559,7 @@ def lps(self, f=None, l=None): # If the length of the lps of self[:-1] is not known: if l is None: l = self.lps_lengths(f)[-1] - return self[len(self)-l:] + return self[len(self) - l :] # If l == w[:-1].length(), there is no shortcut if self.length() == l + 1: @@ -2559,20 +2567,21 @@ def lps(self, f=None, l=None): # Obtain the letter to the left (g) and to the right (d) of the # precedent lps of self - g = self[-l-2] + g = self[-l - 2] d = self[-1] # If the word g*d is a `f`-palindrome, the result follows if f is None: if g == d: - return self[-l-2:] + return self[-l - 2 :] # Otherwise, the length of the lps of self is smallest than l+2 - return self[-l-1:].lps() + return self[-l - 1 :].lps() from sage.combinat.words.morphism import WordMorphism + f = WordMorphism(f) if f(g)[0] == d: - return self[-l-2:] - return self[-l-1:].lps(f=f) + return self[-l - 2 :] + return self[-l - 1 :].lps(f=f) @cached_method def palindromic_lacunas_study(self, f=None): @@ -2637,7 +2646,7 @@ def palindromic_lacunas_study(self, f=None): for i in range(self.length()): # Compute its longest `f`-palindromic suffix using the preceding lps (pal) - pal = self[:i+1].lps(l=pal.length(), f=f) + pal = self[: i + 1].lps(l=pal.length(), f=f) lengths_lps[i] = pal.length() @@ -2785,13 +2794,14 @@ def length_maximal_palindrome(self, j, m=None, f=None): # Ensure `f` is an involutory word morphism if f is not None: from sage.combinat.words.morphism import WordMorphism + if not isinstance(f, WordMorphism): f = WordMorphism(f) if not f.is_involution(): raise ValueError("f must be an involution") # Ensure j is a valid entry - jj = 2*j + jj = 2 * j if not jj.is_integer() or j < 0 or j >= len(self): raise ValueError("j must be positive, inferior to length of self") jj = Integer(jj) @@ -2803,17 +2813,15 @@ def length_maximal_palindrome(self, j, m=None, f=None): # Initialize the next (left) position to check i = (jj - m - 1) / 2 if not i.is_integer(): - raise ValueError(f"(2*j-m-1)/2(={i}) must be an integer, i.e., " - f"2*j(={jj}) and m(={m}) can't " - "have the same parity") + raise ValueError(f"(2*j-m-1)/2(={i}) must be an integer, i.e., " f"2*j(={jj}) and m(={m}) can't " "have the same parity") i = Integer(i) # Compute if f is None: - while i >= 0 and jj-i < len(self) and self[i] == self[jj-i]: + while i >= 0 and jj - i < len(self) and self[i] == self[jj - i]: i -= 1 else: - while i >= 0 and jj-i < len(self) and self[i] == f(self[jj-i])[0]: + while i >= 0 and jj - i < len(self) and self[i] == f(self[jj - i])[0]: i -= 1 if jj == 2 * i: return 0 @@ -2850,6 +2858,7 @@ def lengths_maximal_palindromes(self, f=None): """ if f is not None: from sage.combinat.words.morphism import WordMorphism + if not isinstance(f, WordMorphism): f = WordMorphism(f) if not f.is_involution(): @@ -2862,7 +2871,7 @@ def lengths_maximal_palindromes(self, f=None): for j in range(1, 2 * len(self) + 1): if j >= k + LPC[k]: - p = self.length_maximal_palindrome((j - 1)*0.5, -(j % 2), f) + p = self.length_maximal_palindrome((j - 1) * 0.5, -(j % 2), f) LPC.append(p) if j + p > k + LPC[k]: k = j @@ -2872,12 +2881,12 @@ def lengths_maximal_palindromes(self, f=None): # If the `f`-palindrome centered at position j is not the # longest proper `f`-palindromic suffix of the maximal # `f`-palindrome centered at k - if LPC[k] + k - j != LPC[2*k - j]: - LPC.append(min(LPC[k] + k - j, LPC[2*k - j])) + if LPC[k] + k - j != LPC[2 * k - j]: + LPC.append(min(LPC[k] + k - j, LPC[2 * k - j])) else: mp = LPC[k] + k - j - p = self.length_maximal_palindrome((j-1)*0.5, mp, f) + p = self.length_maximal_palindrome((j - 1) * 0.5, mp, f) LPC.append(p) k = j return LPC @@ -2952,7 +2961,7 @@ def palindromes(self, f=None): [word: , word: ab, word: abbabaab, word: ba, word: baba, word: bbabaa] """ LPS = self.lps_lengths(f) - return {self[i - LPS[i]: i] for i in range(len(self) + 1)} + return {self[i - LPS[i] : i] for i in range(len(self) + 1)} def palindromic_complexity(self, n): r""" @@ -3095,6 +3104,7 @@ def defect(self, f=None): g_w = 0 if f is not None: from sage.combinat.words.morphism import WordMorphism + if not isinstance(f, WordMorphism): f = WordMorphism(f) if not f.is_involution(): @@ -3108,7 +3118,7 @@ def defect(self, f=None): A.remove(f(x)) g_w += 1 - return self.length()+1-g_w-len(self.palindromes(f=f)) + return self.length() + 1 - g_w - len(self.palindromes(f=f)) def is_full(self, f=None): r""" @@ -3232,22 +3242,23 @@ def palindromic_closure(self, side='right', f=None): if side == 'right': l = self.lps().length() # return self * self[-(l+1)::-1] - return self * self[:self.length() - l].reversal() + return self * self[: self.length() - l].reversal() if side == 'left': l = self.reversal().lps().length() - return self[:l-1:-1] * self + return self[: l - 1 : -1] * self raise ValueError("side must be either 'left' or 'right' (not %s) " % side) else: from sage.combinat.words.morphism import WordMorphism + f = WordMorphism(f) if not f.is_involution(): raise ValueError("f must be an involution") if side == 'right': l = self.lps(f=f).length() - return self * f(self[-(l+1)::-1]) + return self * f(self[-(l + 1) :: -1]) if side == 'left': l = self.reversal().lps(f=f).length() - return f(self[:l-1:-1]) * self + return f(self[: l - 1 : -1]) * self raise ValueError("side must be either 'left' or 'right' (not %s) " % side) def is_symmetric(self, f=None): @@ -3321,7 +3332,7 @@ def border(self): """ if self.is_empty(): return None - return self[:self.length_border()] + return self[: self.length_border()] def minimal_period(self): r""" @@ -3378,6 +3389,7 @@ def order(self): 0 """ from sage.rings.rational import Rational + return Rational((self.length(), self.minimal_period())) def critical_exponent(self): @@ -3426,27 +3438,27 @@ def critical_exponent(self): else: st = self.suffix_tree() pft = [0] * self.length() # the prefix function table - queue = [(0, 0, -1, 0)] # suffix tree vertices to visit for Depth First Search - best_exp = 1 # best exponent so far + queue = [(0, 0, -1, 0)] # suffix tree vertices to visit for Depth First Search + best_exp = 1 # best exponent so far while queue: v, i, j, l = queue.pop() - for k in range(i, j+1): - if l-j+k-1 != 0: - m = pft[l-j+k-2] - while m > 0 and self[j-l+m] != self[k-1]: - m = pft[m-1] - if self[j-l+m] == self[k-1]: + for k in range(i, j + 1): + if l - j + k - 1 != 0: + m = pft[l - j + k - 2] + while m > 0 and self[j - l + m] != self[k - 1]: + m = pft[m - 1] + if self[j - l + m] == self[k - 1]: m += 1 else: m = 0 - current_pos = k-j+l-1 + current_pos = k - j + l - 1 pft[current_pos] = m - current_exp = QQ((current_pos+1, current_pos+1-m)) + current_exp = QQ((current_pos + 1, current_pos + 1 - m)) best_exp = max(current_exp, best_exp) - for ((i, j), u) in st._transition_function[v].items(): + for (i, j), u in st._transition_function[v].items(): if j is None: j = self.length() - queue.append((u, i, j, l+j-i+1)) + queue.append((u, i, j, l + j - i + 1)) return best_exp def is_overlap(self): @@ -3470,7 +3482,7 @@ def is_overlap(self): """ if self.length() == 0: return False - return self.length_border() > self.length()//2 + return self.length_border() > self.length() // 2 def primitive_length(self): r""" @@ -3516,7 +3528,7 @@ def primitive(self): sage: Word('121212').primitive() word: 12 """ - return self[:self.primitive_length()] + return self[: self.primitive_length()] def exponent(self): r""" @@ -3656,6 +3668,7 @@ def longest_common_subword(self, other): :meth:`is_subword_of` """ from sage.combinat.words.word import Word + if len(self) == 0 or len(other) == 0: return Word() @@ -3672,8 +3685,7 @@ def longest_common_subword(self, other): for i, l1 in enumerate(self): for j, l2 in enumerate(other): - lcs[0][j] = max(lcs[0][j-1], lcs[1][j], - lcs[1][j-1] + ([l1] if l1 == l2 else []), key=len) + lcs[0][j] = max(lcs[0][j - 1], lcs[1][j], lcs[1][j - 1] + ([l1] if l1 == l2 else []), key=len) # Maintaining the meaning of lcs for the next loop lcs.pop(1) @@ -3771,17 +3783,17 @@ def subword_complementaries(self, other): # Create a matrix that tells the positions of subwords of the suffixes Mpos = [[[] for _ in repeat(None, lo)] for i in range(ls)] for j in range(lo): - if Eq[ls-1][j]: - Mpos[ls-1][j] = [[j]] - for i in range(ls-2, -1, -1): + if Eq[ls - 1][j]: + Mpos[ls - 1][j] = [[j]] + for i in range(ls - 2, -1, -1): for j in range(lo): if Eq[i][j]: temp = [] - for k in range(j+1, lo): - if Eq[i+1][k]: - m = Mpos[i+1][k] + for k in range(j + 1, lo): + if Eq[i + 1][k]: + m = Mpos[i + 1][k] if len(m) == 1: - temp.append([j]+m[0]) + temp.append([j] + m[0]) if len(m) > 1: temp.extend([j] + sw for sw in m) Mpos[i][j] = temp @@ -3793,6 +3805,7 @@ def subword_complementaries(self, other): # Create the list of the complementaries of `self` from sage.combinat.words.word import Word + comp_words = [] for sp in selfpos: # list with positions of one occurrence of `self` comp_pos = (i for i in range(lo) if i not in set(sp)) @@ -3915,14 +3928,14 @@ def lyndon_factorization(self): n = self.length() k = -1 F = [0] - while k < n-1: - i = k+1 - j = k+2 + while k < n - 1: + i = k + 1 + j = k + 2 while j < n: ki = key(self[i]) kj = key(self[j]) if ki < kj: - i = k+1 + i = k + 1 j += 1 elif ki == kj: i += 1 @@ -3932,7 +3945,7 @@ def lyndon_factorization(self): while k < i: F.append(k + j - i + 1) k = k + j - i - return Factorization([self[F[l]:F[l+1]] for l in range(len(F)-1)]) + return Factorization([self[F[l] : F[l + 1]] for l in range(len(F) - 1)]) def inversions(self): r""" @@ -3954,7 +3967,7 @@ def inversions(self): cmp_key = self._parent.sortkey_letters for i1, letter1 in enumerate(self): k1 = cmp_key(letter1) - for i2, letter2 in enumerate(self[i1 + 1:]): + for i2, letter2 in enumerate(self[i1 + 1 :]): k2 = cmp_key(letter2) if k1 > k2: inversion_list.append([i1, i1 + i2 + 1]) @@ -4214,7 +4227,7 @@ def find(self, sub, start=0, end=None): except (ValueError, TypeError): return -1 p = self[start:end].first_occurrence(sub) - return -1 if p is None else p+start + return -1 if p is None else p + start def rfind(self, sub, start=0, end=None): r""" @@ -4295,7 +4308,7 @@ def rfind(self, sub, start=0, end=None): else: i = min(end, len(self)) - L while i >= start: - if self[i:i + L] == sub: + if self[i : i + L] == sub: return i i -= 1 return -1 @@ -4423,11 +4436,11 @@ def number_of_subword_occurrences(self, other): pos[a].reverse() # compute the occurrences of all prefixes of other as subwords in self - occ = [ZZ.zero()] * (len(other)+1) + occ = [ZZ.zero()] * (len(other) + 1) occ[0] = ZZ.one() for a in self: for i in pos[a]: - occ[i+1] += occ[i] + occ[i + 1] += occ[i] # return only the number of occurrences of other return occ[-1] @@ -4475,6 +4488,7 @@ def number_of_letter_occurrences(self, letter): :meth:`sage.combinat.words.finite_word.FiniteWord_class.number_of_factor_occurrences` """ return Integer(sum(1 for a in self if a == letter)) + count = number_of_letter_occurrences def _return_words_list(self, fact): @@ -4565,6 +4579,7 @@ def return_words_derivate(self, fact): tab = {} ret = [tab.setdefault(w, len(tab)) + 1 for w in self._return_words_list(fact)] from sage.combinat.words.word import Word + return Word(ret) def is_quasiperiodic(self): @@ -4595,7 +4610,7 @@ def is_quasiperiodic(self): for i in range(1, l - 1): return_lengths = [x.length() for x in self.return_words(self[:i])] if return_lengths: - if max(return_lengths) <= i and self[l - i:l] == self[:i]: + if max(return_lengths) <= i and self[l - i : l] == self[:i]: return True return False @@ -4626,7 +4641,7 @@ def quasiperiods(self): for i in range(1, l - 1): return_lengths = [x.length() for x in self.return_words(self[:i])] if return_lengths: - if max(return_lengths) <= i and self[l - i:l] == self[:i]: + if max(return_lengths) <= i and self[l - i : l] == self[:i]: Q.append(self[:i]) return Q @@ -4662,7 +4677,7 @@ def crochemore_factorization(self): """ T = self.implicit_suffix_tree() cuts = T.LZ_decomposition() - c = Factorization([self[cuts[i]:cuts[i+1]] for i in range(len(cuts)-1)]) + c = Factorization([self[cuts[i] : cuts[i + 1]] for i in range(len(cuts) - 1)]) return c LZ_decomposition = crochemore_factorization @@ -4726,8 +4741,9 @@ def evaluation_partition(self): """ p = sorted(self.evaluation_dict().values(), reverse=True) from sage.combinat.partition import Partition + if 0 in p: - return Partition(p[:p.index(0)]) + return Partition(p[: p.index(0)]) return Partition(p) def overlap_partition(self, other, delay=0, p=None, involution=None): @@ -4892,16 +4908,19 @@ def overlap_partition(self, other, delay=0, p=None, involution=None): return other.overlap_partition(self, -delay, p) from sage.sets.disjoint_set import DisjointSet_class + if p is None: if self.parent().alphabet().cardinality() is Infinity: raise ValueError("the alphabet of the parent must be finite") from sage.sets.disjoint_set import DisjointSet + p = DisjointSet(self.parent().alphabet()) elif not isinstance(p, DisjointSet_class): raise TypeError("p(=%s) is not a DisjointSet" % p) # Join the classes of each pair of letters that are one above the other from sage.combinat.words.morphism import WordMorphism + S = zip(islice(self, int(delay), None), other) if involution is None: for a, b in S: @@ -4978,6 +4997,7 @@ def standard_permutation(self): word: bbbaaa """ from sage.combinat.permutation import to_standard + return to_standard(self, key=self.parent().sortkey_letters) def _s(self, i): @@ -5042,6 +5062,7 @@ def _to_partition_content(self): return self from sage.combinat.words.word import Word + n = max(self) ev = Word(Words(n)(self).evaluation()) sig = ev.reversal().standard_permutation().reduced_word() @@ -5052,7 +5073,7 @@ def _to_partition_content(self): out = self for i in reversed(sig): - out = out._s(n-i) + out = out._s(n - i) return out def cocharge(self): @@ -5160,10 +5181,10 @@ def charge(self, check=True): """ if check: ev_dict = self.evaluation_dict() - ordered_alphabet = sorted(ev_dict, - key=self.parent().sortkey_letters) + ordered_alphabet = sorted(ev_dict, key=self.parent().sortkey_letters) evaluation = [ev_dict[a] for a in ordered_alphabet] from sage.combinat.partition import Partitions + if evaluation not in Partitions(): return self._to_partition_content().charge() res = 0 @@ -5214,8 +5235,7 @@ def BWT(self): if self.is_empty(): return self conjugates = sorted(self._conjugates_list()) - return self.parent()([x[x.length() - 1] for x in conjugates], - check=False) + return self.parent()([x[x.length() - 1] for x in conjugates], check=False) def iterated_left_palindromic_closure(self, f=None): r""" @@ -5253,6 +5273,7 @@ def iterated_left_palindromic_closure(self, f=None): if f is None: return self.reversal().iterated_right_palindromic_closure(f=f) from sage.combinat.words.morphism import WordMorphism + f = WordMorphism(f) return f(self).reversal().iterated_right_palindromic_closure(f=f) @@ -5385,7 +5406,7 @@ def is_balanced(self, q=1): for a in alphabet: tab[a].add(evaluation_dict.get(a, 0)) for t in tab.values(): - if len(t) > q+1: + if len(t) > q + 1: return False return True @@ -5456,8 +5477,7 @@ def abelian_vectors(self, n): alphabet = self.parent().alphabet() size = alphabet.cardinality() if size == float('inf'): - raise TypeError("The alphabet of the parent is infinite; define" - " the word with a parent on a finite alphabet") + raise TypeError("The alphabet of the parent is infinite; define" " the word with a parent on a finite alphabet") S = set() if n > self.length(): return S @@ -5788,10 +5808,11 @@ def swap(self, i, j=None): word: aabb """ if j is None: - j = i+1 + j = i + 1 new = list(self) (new[i], new[j]) = (new[j], new[i]) from sage.combinat.words.word import Word + return Word(new) def swap_increase(self, i): @@ -5883,9 +5904,7 @@ def abelian_vector(self): """ alphabet = self.parent().alphabet() if alphabet.cardinality() is Infinity: - raise TypeError("The alphabet of the parent is infinite; define " - "the word with a parent on a finite alphabet " - "or use evaluation_dict() instead") + raise TypeError("The alphabet of the parent is infinite; define " "the word with a parent on a finite alphabet " "or use evaluation_dict() instead") ev_dict = self.evaluation_dict() return [ev_dict.get(a, 0) for a in alphabet] @@ -5905,6 +5924,7 @@ def robinson_schensted(self): [[[1, 1, 1, 1, 3], [2], [3]], [[1, 2, 3, 5, 6], [4], [7]]] """ from sage.combinat.rsk import RSK + return RSK(self) def _rsk_iter(self): @@ -5971,14 +5991,17 @@ def shuffle(self, other, overlap=0): """ if overlap == 0: from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 + return ShuffleProduct_w1w2(self, other) if any(a not in ZZ for a in self) or any(a not in ZZ for a in other): raise ValueError("for a nonzero overlap, words must contain integers as letters") if overlap is True: from sage.combinat.shuffle import ShuffleProduct_overlapping + return ShuffleProduct_overlapping(self, other, self.parent()) if isinstance(overlap, (int, Integer)): from sage.combinat.shuffle import ShuffleProduct_overlapping_r + return ShuffleProduct_overlapping_r(self, other, overlap, self.parent()) raise ValueError('overlapping must be True or an integer') @@ -6020,6 +6043,7 @@ def shifted_shuffle(self, other, shift=None): raise ValueError("for shifted shuffle, words must only contain integers as letters") if shift is None: from sage.combinat.words.shuffle_product import ShuffleProduct_shifted + return ShuffleProduct_shifted(self, other) return self.shuffle(self._parent([x + shift for x in other], check=False)) @@ -6256,7 +6280,7 @@ def phi_inv(self, W=None): if self.is_empty(): return W() v = self.parent()((self[-1],), check=False) - for i in range(self.length()-2, -1, -1): + for i in range(self.length() - 2, -1, -1): v = v.delta_inv(W, self[i]) return v @@ -6392,8 +6416,7 @@ def standard_factorization(self): """ selflen = self.length() if selflen < 2: - raise ValueError("standard factorization not defined on" - " words of length less than 2") + raise ValueError("standard factorization not defined on" " words of length less than 2") for l in range(1, selflen): suff = self[l:] if suff.is_lyndon(): @@ -6420,6 +6443,7 @@ def apply_permutation_to_positions(self, permutation): word: 3421 """ from sage.combinat.permutation import Permutation + if not isinstance(permutation, Permutation): if isinstance(permutation, PermutationGroupElement): permutation = Permutation(permutation.domain()) @@ -6448,6 +6472,7 @@ def apply_permutation_to_letters(self, permutation): word: badc """ from sage.combinat.permutation import Permutation + if not isinstance(permutation, Permutation): if isinstance(permutation, PermutationGroupElement): permutation = Permutation(permutation.domain()) @@ -6534,6 +6559,7 @@ def colored_vector(self, x=0, y=0, width='default', height=1, cmap='hsv', thickn # Recognize the color map from matplotlib import cm from matplotlib.colors import LinearSegmentedColormap as C + key_error = False try: mpl_cmap = cm.__dict__[cmap] @@ -6541,9 +6567,9 @@ def colored_vector(self, x=0, y=0, width='default', height=1, cmap='hsv', thickn key_error = True if key_error or not isinstance(mpl_cmap, C): - possibilities = ', '.join(str(x) for x, val in cm.__dict__.items() - if isinstance(val, C)) + possibilities = ', '.join(str(x) for x, val in cm.__dict__.items() if isinstance(val, C)) import sage.misc.verbose + sage.misc.verbose.verbose("The possible color maps include: %s" % possibilities, level=0) raise RuntimeError(f"color map {cmap} not known") @@ -6558,15 +6584,15 @@ def colored_vector(self, x=0, y=0, width='default', height=1, cmap='hsv', thickn # The black frame of the vector ymax = y + height - L = [(x, y), (x+width, y), (x+width, ymax), (x, ymax), (x, y)] + L = [(x, y), (x + width, y), (x + width, ymax), (x, ymax), (x, y)] rep = line(L, rgbcolor=(0, 0, 0), thickness=thickness) # The label if label is not None: - hl = height/2.0 # height of the label rectangle + hl = height / 2.0 # height of the label rectangle ymax2 = ymax + hl - rep += text(str(label), (x+width/2.0, ymax + hl/2.0), rgbcolor=(1, 0, 0)) - L = [(x, ymax), (x+width, ymax), (x+width, ymax2), (x, ymax2), (x, ymax)] + rep += text(str(label), (x + width / 2.0, ymax + hl / 2.0), rgbcolor=(1, 0, 0)) + L = [(x, ymax), (x + width, ymax), (x + width, ymax2), (x, ymax2), (x, ymax)] rep += line(L, rgbcolor=(0, 0, 0), thickness=thickness) # base : the width of each rectangle @@ -6575,14 +6601,12 @@ def colored_vector(self, x=0, y=0, width='default', height=1, cmap='hsv', thickn # A colored rectangle for each letter dim = self.parent().alphabet().cardinality() if dim is Infinity: - ordered_alphabet = sorted(self.letters(), - key=self.parent().sortkey_letters) + ordered_alphabet = sorted(self.letters(), key=self.parent().sortkey_letters) dim = float(len(ordered_alphabet)) else: ordered_alphabet = self.parent().alphabet() dim = float(self.parent().alphabet().cardinality()) - letter_to_integer_dict = {a: i - for i, a in enumerate(ordered_alphabet)} + letter_to_integer_dict = {a: i for i, a in enumerate(ordered_alphabet)} xp = x for a in self: i = letter_to_integer_dict[a] @@ -6642,6 +6666,7 @@ def is_square_free(self) -> bool: False """ from sage.combinat.words.suffix_trees import DecoratedSuffixTree + T = DecoratedSuffixTree(self) return T.square_vocabulary() == [(0, 0)] @@ -6660,6 +6685,7 @@ def squares(self): [word: , word: 00, word: 00110011, word: 01100110, word: 1010, word: 11] """ from sage.combinat.words.suffix_trees import DecoratedSuffixTree + T = DecoratedSuffixTree(self) return set(T.square_vocabulary(output='word')) @@ -6681,7 +6707,7 @@ def is_cube(self) -> bool: if self.length() % 3 != 0: return False l = self.length() // 3 - return self[:l] == self[l:2*l] == self[2*l:] + return self[:l] == self[l : 2 * l] == self[2 * l :] def is_cube_free(self) -> bool: r""" @@ -6739,6 +6765,7 @@ def to_monoid_element(self): True """ from sage.monoids.free_monoid import FreeMonoid + try: l = list(self.parent().alphabet()) except AttributeError: @@ -6796,7 +6823,7 @@ def is_christoffel(self) -> bool: """ if len(self) == 0 or len(self.letters()) > 2 or (self.is_palindrome() and len(self) > 1): return False - return self.is_symmetric() and self[1:len(self) - 1].is_palindrome() + return self.is_symmetric() and self[1 : len(self) - 1].is_palindrome() def minimal_conjugate(self): r""" @@ -6826,10 +6853,10 @@ def minimal_conjugate(self): p = self.primitive() q = self.length() // p.length() end = 0 - for factor in (p ** 2).lyndon_factorization(): + for factor in (p**2).lyndon_factorization(): end += factor.length() if end >= p.length(): - return factor ** q + return factor**q class CallableFromListOfWords(tuple): @@ -6837,6 +6864,7 @@ class CallableFromListOfWords(tuple): A class to create a callable from a list of words. The concatenation of a list of words is obtained by creating a word from this callable. """ + def __new__(cls, words): r""" TESTS:: @@ -6851,8 +6879,8 @@ def __new__(cls, words): l = [] for w in words: from .word_infinite_datatypes import WordDatatype_callable - if isinstance(w, WordDatatype_callable) and \ - isinstance(w._func, CallableFromListOfWords): + + if isinstance(w, WordDatatype_callable) and isinstance(w._func, CallableFromListOfWords): l.extend(w._func) else: l.append(w) @@ -6888,6 +6916,7 @@ class Factorization(list): sage: f == loads(dumps(f)) True """ + def __repr__(self): r""" Return a string representation of the object. @@ -6904,6 +6933,7 @@ def __repr__(self): ####################################################################### + def evaluation_dict(w): r""" Return a dictionary keyed by the letters occurring in ``w`` with diff --git a/src/sage/combinat/words/infinite_word.py b/src/sage/combinat/words/infinite_word.py index f07d1c8692b..fe6af5c0837 100644 --- a/src/sage/combinat/words/infinite_word.py +++ b/src/sage/combinat/words/infinite_word.py @@ -63,6 +63,7 @@ sage: W(f) word: babababababababababababababababababababa... """ + # **************************************************************************** # Copyright (C) 2008 Sebastien Labbe , # Franco Saliola diff --git a/src/sage/combinat/words/lyndon_word.py b/src/sage/combinat/words/lyndon_word.py index 7de58856d6d..ef9940ce7ff 100644 --- a/src/sage/combinat/words/lyndon_word.py +++ b/src/sage/combinat/words/lyndon_word.py @@ -1,6 +1,7 @@ """ Lyndon words """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen # @@ -126,6 +127,7 @@ class LyndonWords_class(UniqueRepresentation, Parent): r""" The set of all Lyndon words. """ + def __init__(self, alphabet=None): r""" INPUT: @@ -138,6 +140,7 @@ def __init__(self, alphabet=None): True """ from sage.categories.sets_cat import Sets + self._words = FiniteWords() Parent.__init__(self, category=Sets().Infinite(), facade=(self._words)) @@ -194,6 +197,7 @@ class LyndonWords_evaluation(UniqueRepresentation, Parent): sage: L.list() [word: 1223, word: 1232, word: 1322] """ + def __init__(self, e): """ TESTS:: @@ -207,10 +211,8 @@ def __init__(self, e): self._words = FiniteWords(len(e)) from sage.categories.enumerated_sets import EnumeratedSets - Parent.__init__(self, - category=EnumeratedSets().Finite(), - facade=(self._words,) - ) + + Parent.__init__(self, category=EnumeratedSets().Finite(), facade=(self._words,)) def __repr__(self): """ @@ -289,8 +291,7 @@ def cardinality(self): if not evaluation: return Integer(0) n = sum(evaluation) - return sum(moebius(j) * multinomial([ni // j for ni in evaluation]) - for j in divisors(gcd(le))) // n + return sum(moebius(j) * multinomial([ni // j for ni in evaluation]) for j in divisors(gcd(le))) // n def __iter__(self): """ @@ -358,6 +359,7 @@ class LyndonWords_nk(UniqueRepresentation, Parent): word: 2233, word: 2333] """ + def __init__(self, n, k): """ Initialize ``self``. @@ -374,10 +376,8 @@ def __init__(self, n, k): self._words = FiniteWords(self._n) from sage.categories.enumerated_sets import EnumeratedSets - Parent.__init__(self, - category=EnumeratedSets().Finite(), - facade=(self._words,) - ) + + Parent.__init__(self, category=EnumeratedSets().Finite(), facade=(self._words,)) def __repr__(self): """ @@ -430,8 +430,7 @@ def __contains__(self, w): """ if isinstance(w, list): w = self._words(w, check=False) - return isinstance(w, FiniteWord_class) and w.length() == self._k \ - and all(x in self._words.alphabet() for x in w) and w.is_lyndon() + return isinstance(w, FiniteWord_class) and w.length() == self._k and all(x in self._words.alphabet() for x in w) and w.is_lyndon() def cardinality(self): """ @@ -444,7 +443,7 @@ def cardinality(self): return Integer(1) s = Integer(0) for d in divisors(self._k): - s += moebius(d) * self._n**(self._k // d) + s += moebius(d) * self._n ** (self._k // d) return s // self._k def __iter__(self): @@ -510,6 +509,7 @@ def __init__(self, n, k): self._lyndon = LyndonWords(self._n, self._k) from sage.categories.enumerated_sets import EnumeratedSets + Parent.__init__(self, category=EnumeratedSets().Finite()) def __repr__(self): @@ -629,6 +629,7 @@ def standard_unbracketing(sblw): ... ValueError: not a standard bracketing of a Lyndon word """ + # Nested helper function that not only returns (flattened) w, but also its # right factor in the standard Lyndon factorization. def standard_unbracketing_rec(w): @@ -644,5 +645,6 @@ def standard_unbracketing_rec(w): x += y return x, y raise ValueError("not a standard bracketing of a Lyndon word") + lw, _ = standard_unbracketing_rec(sblw) return FiniteWords(list(set(lw)))(lw, datatype='list', check=False) diff --git a/src/sage/combinat/words/morphic.py b/src/sage/combinat/words/morphic.py index f6e0899fdfe..222e582ef12 100644 --- a/src/sage/combinat/words/morphic.py +++ b/src/sage/combinat/words/morphic.py @@ -25,6 +25,7 @@ sage: w[10000000] # needs sage.modules 'b' """ + from collections.abc import Iterator from itertools import chain @@ -40,8 +41,8 @@ class WordDatatype_morphic(WordDatatype_callable): Datatype for a morphic word defined by a morphism, a starting letter and a coding. """ - def __init__(self, parent, morphism, letter, - coding=None, length=Infinity) -> None: + + def __init__(self, parent, morphism, letter, coding=None, length=Infinity) -> None: r""" INPUT: @@ -156,8 +157,7 @@ def __reduce__(self) -> tuple: {'a': 'a', 'b': 'b'}, 2)) """ - return self.__class__, (self._parent, self._morphism, self._letter, - self._coding, self._len) + return self.__class__, (self._parent, self._morphism, self._letter, self._coding, self._len) def representation(self, n) -> list: r""" diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index 60853a3fda4..ab020d4c8f8 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -77,6 +77,7 @@ sage: m.is_endomorphism() True """ + # **************************************************************************** # Copyright (C) 2008 Sebastien Labbe # 2018 Vincent Delecroix <20100.delecroix@gmail.com> @@ -144,7 +145,7 @@ def get_cycles(f, domain): cycle.append(b) b = f(b) if b in cycle: - cycles.append(tuple(cycle[cycle.index(b):])) + cycles.append(tuple(cycle[cycle.index(b) :])) return cycles @@ -168,6 +169,7 @@ class PeriodicPointIterator: sage: p._cache[2] lazy list ['c', 'b', 'a', ...] """ + def __init__(self, m, cycle): r""" INPUT: @@ -185,7 +187,7 @@ def __init__(self, m, cycle): sage: pp._cache[0] lazy list ['a', 'a', 'b', ...] """ - self._m = m # for pickling only + self._m = m # for pickling only self._image = m.image self._cycle = tuple(cycle) self._cache = [lazy_list(self.get_iterator(i)) for i in range(len(cycle))] @@ -287,6 +289,7 @@ class WordMorphism(SageObject): sage: wm == loads(dumps(wm)) True """ + def __init__(self, data, domain=None, codomain=None): r""" Construction of the morphism. @@ -621,8 +624,7 @@ def __str__(self) -> str: sage: str(s) 'a->ab, b->ba' """ - L = [str(lettre) + '->' + image.string_rep() - for lettre, image in self._morph.items()] + L = [str(lettre) + '->' + image.string_rep() for lettre, image in self._morph.items()] return ', '.join(sorted(L)) def __call__(self, w, order=1): @@ -874,6 +876,7 @@ def _latex_(self): ValueError: unknown latex_layout(=tabular) """ from sage.misc.latex import LatexExpr + A = self.domain().alphabet() latex_layout = self.latex_layout() if latex_layout == 'oneliner': @@ -949,12 +952,9 @@ def __mul__(self, other): """ # Check that other's codomain alphabet is included in self's domain # alphabet with the correct ordering. - if not self._is_alphabet_included_with_order( - other.codomain().alphabet(), self.domain().alphabet()): - raise ValueError( - "codomain alphabet not in domain (same order required)") - return WordMorphism({key: self(w) for key, w in other._morph.items()}, - codomain=self.codomain()) + if not self._is_alphabet_included_with_order(other.codomain().alphabet(), self.domain().alphabet()): + raise ValueError("codomain alphabet not in domain (same order required)") + return WordMorphism({key: self(w) for key, w in other._morph.items()}, codomain=self.codomain()) def __pow__(self, exp): r""" @@ -1008,7 +1008,7 @@ def __pow__(self, exp): else: nexp = int(exp // 2) over = exp % 2 - res = (self * self)**nexp + res = (self * self) ** nexp if over == 1: res *= self return res @@ -1089,8 +1089,7 @@ def restrict_domain(self, alphabet): ... TypeError: 'sage.rings.integer.Integer' object is not iterable """ - return WordMorphism({a: self(a) for a in alphabet - if a in self.domain().alphabet()}) + return WordMorphism({a: self(a) for a in alphabet if a in self.domain().alphabet()}) def _matrix_(self, R=None): r""" @@ -1211,8 +1210,7 @@ def is_endomorphism(self): """ return self.codomain() == self.domain() - def _is_alphabet_included_with_order(self, source_alphabet, - target_alphabet): + def _is_alphabet_included_with_order(self, source_alphabet, target_alphabet): """Check if ``source_alphabet`` is included in ``target_alphabet`` with the correct ordering. @@ -1268,8 +1266,7 @@ def _is_alphabet_included_with_order(self, source_alphabet, return False if target_alphabet.cardinality() == Infinity: - raise NotImplementedError( - "cannot check alphabet inclusion for infinite alphabets") + raise NotImplementedError("cannot check alphabet inclusion for infinite alphabets") targets = list(target_alphabet) n_targets = len(targets) @@ -1374,9 +1371,7 @@ def reversal(self): sage: WordMorphism('a->ab,b->a').reversal() WordMorphism: a->ba, b->a """ - return WordMorphism({key: w.reversal() - for key, w in self._morph.items()}, - codomain=self._codomain) + return WordMorphism({key: w.reversal() for key, w in self._morph.items()}, codomain=self._codomain) def is_empty(self): r""" @@ -1899,11 +1894,11 @@ def fixed_point(self, letter): parent = self.codomain() if self.is_growing(letter): from sage.combinat.words.word import InfiniteWord_morphic - return InfiniteWord_morphic(parent.shift(), self, letter, - coding=None, length=Infinity) + + return InfiniteWord_morphic(parent.shift(), self, letter, coding=None, length=Infinity) from sage.combinat.words.word import FiniteWord_morphic - w = FiniteWord_morphic(parent, self, letter, - coding=None, length='finite') + + w = FiniteWord_morphic(parent, self, letter, coding=None, length='finite') # since FiniteWord_morphic uses the method __getitem__ # from FiniteWord_callable, the length must be precomputed # for __getitem__ to work properly @@ -1947,9 +1942,7 @@ def fixed_points(self): sage: (s^2).fixed_points() [] """ - return [self.fixed_point(letter=letter) - for letter in self.domain().alphabet() - if self.is_prolongable(letter=letter)] + return [self.fixed_point(letter=letter) for letter in self.domain().alphabet() if self.is_prolongable(letter=letter)] def periodic_point(self, letter): r""" @@ -2209,7 +2202,7 @@ def language(self, n, u=None): for u in L2: v = im[u[0]] + im[u[1]] for k in range(len(v) - n + 1): - L.add(v[k:k + n]) + L.add(v[k : k + n]) return L def conjugate(self, pos): @@ -2236,8 +2229,7 @@ def conjugate(self, pos): sage: m.conjugate(2) WordMorphism: a->cdeab, b->zxy """ - return WordMorphism({key: w.conjugate(pos) - for (key, w) in self._morph.items()}) + return WordMorphism({key: w.conjugate(pos) for (key, w) in self._morph.items()}) def has_left_conjugate(self) -> bool: r""" @@ -2538,10 +2530,10 @@ def dual_map(self, k=1): """ if k == 1: from sage.combinat.e_one_star import E1Star + return E1Star(self) - raise NotImplementedError("the dual map E_k^* is implemented only " - "for k = 1 (not %s)" % k) + raise NotImplementedError("the dual map E_k^* is implemented only " "for k = 1 (not %s)" % k) @cached_method def rauzy_fractal_projection(self, eig=None, prec=53): @@ -2622,6 +2614,7 @@ def rauzy_fractal_projection(self, eig=None, prec=53): # Algebraic conjugates of beta from sage.rings.qqbar import QQbar + beta_conjugates = beta.minpoly().roots(QQbar, multiplicities=False) if not beta.imag(): beta_conjugates.remove(beta) @@ -2631,15 +2624,18 @@ def rauzy_fractal_projection(self, eig=None, prec=53): # Left eigenvector vb in the number field Q(beta) from sage.rings.number_field.number_field import NumberField + K = NumberField(beta.minpoly(), 'b') vb = (self.incidence_matrix() - K.gen()).kernel().basis()[0] # Projections of canonical base vectors from R^size_alphabet to C, using vb from sage.modules.free_module import VectorSpace + canonical_basis = VectorSpace(K, size_alphabet).basis() canonical_basis_proj = {} from sage.rings.real_mpfr import RealField + RealField_prec = RealField(prec) for a, x in zip(alphabet, canonical_basis): v = [] @@ -2702,7 +2698,7 @@ def rauzy_fractal_points(self, n=None, exchange=False, eig=None, translate=None, # if exchange, set the projection to its opposite if exchange: for a in canonical_basis_proj: - canonical_basis_proj[a] = - canonical_basis_proj[a] + canonical_basis_proj[a] = -canonical_basis_proj[a] # Compute a fixed point u if exchange: @@ -2732,6 +2728,7 @@ def rauzy_fractal_points(self, n=None, exchange=False, eig=None, translate=None, # Manage translated copies from sage.rings.real_mpfr import RealField + RealField_prec = RealField(prec) if translate is not None: @@ -2764,10 +2761,7 @@ def rauzy_fractal_points(self, n=None, exchange=False, eig=None, translate=None, return orbit_points - def rauzy_fractal_plot(self, n=None, exchange=False, eig=None, - translate=None, prec=53, - colormap='hsv', opacity=None, plot_origin=None, - plot_basis=False, point_size=None): + def rauzy_fractal_plot(self, n=None, exchange=False, eig=None, translate=None, prec=53, colormap='hsv', opacity=None, plot_origin=None, plot_basis=False, point_size=None): r""" Return a plot of the Rauzy fractal associated with a substitution. @@ -3024,6 +3018,7 @@ def rauzy_fractal_plot(self, n=None, exchange=False, eig=None, # Make graphics from sage.plot.plot import Graphics + G = Graphics() from sage.plot.point import points @@ -3031,6 +3026,7 @@ def rauzy_fractal_plot(self, n=None, exchange=False, eig=None, # 1D plots if dim_fractal == 1: from sage.plot.plot import plot + for a in col_dict: # We plot only the points with a color in col_dict and with positive opacity if (a in col_dict) and (opacity[a] > 0): @@ -3038,11 +3034,11 @@ def rauzy_fractal_plot(self, n=None, exchange=False, eig=None, if plot_basis: from matplotlib import cm from sage.plot.arrow import arrow + canonical_basis_proj = self.rauzy_fractal_projection(eig=eig, prec=prec) for i, a in enumerate(alphabet): x = canonical_basis_proj[a] - G += arrow((-1.1, 0), (-1.1, x[0]), - color=cm.__dict__["gist_gray"](0.75 * float(i) / float(size_alphabet))[:3]) + G += arrow((-1.1, 0), (-1.1, x[0]), color=cm.__dict__["gist_gray"](0.75 * float(i) / float(size_alphabet))[:3]) # 2D or 3D plots else: @@ -3059,11 +3055,11 @@ def rauzy_fractal_plot(self, n=None, exchange=False, eig=None, if plot_basis: from matplotlib import cm from sage.plot.arrow import arrow + canonical_basis_proj = self.rauzy_fractal_projection(eig=eig, prec=prec) for i, a in enumerate(alphabet): x = canonical_basis_proj[a] - G += arrow([0] * dim_fractal, x, - color=cm.__dict__["gist_gray"](0.75 * float(i) / float(size_alphabet))[:3]) + G += arrow([0] * dim_fractal, x, color=cm.__dict__["gist_gray"](0.75 * float(i) / float(size_alphabet))[:3]) if plot_origin: G += points([(0, 0)], size=plot_origin[0], color=plot_origin[1]) @@ -3323,8 +3319,7 @@ def letter_growth_types(self): (['a'], [], []) """ immortal = set(self.immortal_letters()) - mortal = [a for a in self.domain().alphabet() - if a not in immortal] + mortal = [a for a in self.domain().alphabet() if a not in immortal] # Starting with degree d=0, search for letters with polynomial # growth of degree d. @@ -3333,8 +3328,7 @@ def letter_growth_types(self): while True: # Construct the permutation of letters containing all letters whose # iterated images under morphism m is always of length 1. - not_growing = {a: image_a[0] for a, image_a in m.items() - if len(image_a) == 1} + not_growing = {a: image_a[0] for a, image_a in m.items() if len(image_a) == 1} preimages = {} roots = [] for k, v in not_growing.items(): @@ -3360,8 +3354,7 @@ def letter_growth_types(self): # clean the morphism m for the next iteration by removing the # letters with polynomial growth degree d - m = {a: [b for b in L if b not in not_growing] for a, L in m.items() - if a not in not_growing} + m = {a: [b for b in L if b not in not_growing] for a, L in m.items() if a not in not_growing} exponential = list(m) @@ -3450,9 +3443,10 @@ def is_injective(self): sage: WordMorphism('a->00,b->01,c->012,d->20001').is_injective() False """ + def check(u, v): if u.is_prefix(v): - tail = v[u.length():] + tail = v[u.length() :] if tail not in tails: tails.add(tail) todo.append(tail) @@ -3668,6 +3662,7 @@ def infinite_repetitions_primitive_roots(self, w=None, allow_growing=None): sage: sorted(m.infinite_repetitions_primitive_roots()) [word: ababcd] """ + def impl_no_growing(g, k): U = {} for x in unbounded: @@ -3675,11 +3670,11 @@ def impl_no_growing(g, k): for i, y in enumerate(reversed(xg)): if y in unbounded: break - U[x] = y, xg[xg.length() - i:] + U[x] = y, xg[xg.length() - i :] for cycle in get_cycles(lambda x: U[x][0], domain=unbounded): if all(not U[x][1] for x in cycle): continue - gq = gb**len(cycle) + gq = gb ** len(cycle) for cyc in g.domain()(cycle).conjugates_iterator(): u = g.domain()() for x in cyc: @@ -3711,7 +3706,7 @@ def impl_no_growing(g, k): if allow_growing is not False: for periodic_orbit in g.periodic_points(): - gq = g**len(periodic_orbit) + gq = g ** len(periodic_orbit) for periodic_point in periodic_orbit: # Check if this periodic point is a periodic infinite word. periodic_point = periodic_point[:1] @@ -3730,10 +3725,10 @@ def impl_no_growing(g, k): break if not one_unbounded_twice or letter != periodic_point[0]: break - v = periodic_point[:previous_length + i] + v = periodic_point[: previous_length + i] vq = gq(v) m = 0 - while vq[m * v.length(): (m + 1) * v.length()] == v: + while vq[m * v.length() : (m + 1) * v.length()] == v: m += 1 if m * v.length() != vq.length(): break @@ -3816,6 +3811,7 @@ def simplify_alphabet_size(self, Z=None): sage: len(k.domain().alphabet()) < len(f.domain().alphabet()) True """ + def try_create_h(f, k): h = {} for letter1, image1 in f.items(): @@ -3823,7 +3819,7 @@ def try_create_h(f, k): while image1: for letter2, image2 in k.items(): if image2.is_prefix(image1): - image1 = image1[image2.length():] + image1 = image1[image2.length() :] image3.append(letter2) break else: # nobreak @@ -3858,10 +3854,10 @@ def try_create_h(f, k): to_remove.append(letter2) to_do.discard(letter2) elif image1.is_prefix(image2): - k[letter2] = image2[image1.length():] + k[letter2] = image2[image1.length() :] to_do.add(letter2) elif image2.is_prefix(image1): - k[letter1] = image1[image2.length():] + k[letter1] = image1[image2.length() :] to_do.add(letter1) break for letter in to_remove: @@ -3874,6 +3870,7 @@ def try_create_h(f, k): factors.remove(self.codomain()()) factors = sorted(factors) # For deterministic output. from itertools import combinations + for comb in combinations(factors, len(X) - 1): if any(x.is_proper_prefix(y) for x in comb for y in comb): continue diff --git a/src/sage/combinat/words/paths.py b/src/sage/combinat/words/paths.py index 861c0ec264d..7d3ed33a92b 100644 --- a/src/sage/combinat/words/paths.py +++ b/src/sage/combinat/words/paths.py @@ -187,16 +187,11 @@ from sage.modules.free_module_element import vector from sage.rings.integer_ring import ZZ from sage.rings.real_mpfr import RR -from .word_datatypes import (WordDatatype_str, - WordDatatype_list, - WordDatatype_tuple) +from .word_datatypes import WordDatatype_str, WordDatatype_list, WordDatatype_tuple + # WordDatatype_cpp_basic_string) -from .word_infinite_datatypes import ( - WordDatatype_iter_with_caching, - WordDatatype_iter, - WordDatatype_callable_with_caching, - WordDatatype_callable) +from .word_infinite_datatypes import WordDatatype_iter_with_caching, WordDatatype_iter, WordDatatype_callable_with_caching, WordDatatype_callable from sage.matrix.constructor import vector_on_axis_rotation_matrix lazy_import("sage.plot.all", ["arrow", "line", "polygon", "point", "Graphics"]) @@ -209,6 +204,7 @@ # # ####################################################################### + def WordPaths(alphabet, steps=None): r""" Return the combinatorial class of paths of the given type of steps. @@ -357,11 +353,13 @@ def WordPaths(alphabet, steps=None): # # ####################################################################### + class WordPaths_all(FiniteWords): r""" The combinatorial class of all paths, i.e of all words over an alphabet where each letter is mapped to a step (a vector). """ + def __init__(self, alphabet, steps): r""" INPUT: @@ -421,12 +419,13 @@ def __init__(self, alphabet, steps): # Construction of the steps from sage.structure.element import Vector + if all(isinstance(x, Vector) for x in steps): vsteps = steps else: try: vsteps = [vector(s) for s in steps] - except (TypeError): + except TypeError: raise ValueError("cannot make vectors from steps") try: s = sum(vsteps) @@ -452,10 +451,7 @@ def __eq__(self, other): sage: W1 == W3 False """ - return self is other or (type(self) is type(other) and - self.alphabet() == other.alphabet() and - self.vector_space() == other.vector_space() and - self.letters_to_steps() == other.letters_to_steps()) + return self is other or (type(self) is type(other) and self.alphabet() == other.alphabet() and self.vector_space() == other.vector_space() and self.letters_to_steps() == other.letters_to_steps()) def __ne__(self, other): r""" @@ -610,6 +606,7 @@ class WordPaths_square_grid(WordPaths_all): r""" The combinatorial class of all paths on the square grid. """ + def __init__(self, alphabet): r""" The combinatorial class of all finite paths on the square grid. @@ -678,6 +675,7 @@ class WordPaths_triangle_grid(WordPaths_all): r""" The combinatorial class of all paths on the triangle grid. """ + def __init__(self, alphabet): r""" The combinatorial class of all finite paths on the triangle grid. @@ -699,12 +697,7 @@ def __init__(self, alphabet): sqrt3 = K.gen() # Construction of the steps - d = (vector(K, (1, 0)), - vector(K, (ZZ(1) / ZZ(2), sqrt3 / 2)), - vector(K, (ZZ(-1) / ZZ(2), sqrt3 / 2)), - vector(K, (-1, 0)), - vector(K, (ZZ(-1) / ZZ(2), -sqrt3 / 2)), - vector(K, (ZZ(1) / ZZ(2), -sqrt3 / 2))) + d = (vector(K, (1, 0)), vector(K, (ZZ(1) / ZZ(2), sqrt3 / 2)), vector(K, (ZZ(-1) / ZZ(2), sqrt3 / 2)), vector(K, (-1, 0)), vector(K, (ZZ(-1) / ZZ(2), -sqrt3 / 2)), vector(K, (ZZ(1) / ZZ(2), -sqrt3 / 2))) # Construction of the class super().__init__(alphabet, steps=d) @@ -757,6 +750,7 @@ class WordPaths_hexagonal_grid(WordPaths_triangle_grid): r""" The combinatorial class of all paths on the hexagonal grid. """ + def __init__(self, alphabet): r""" The combinatorial class of all finite paths on the hexagonal grid. @@ -825,6 +819,7 @@ class WordPaths_cube_grid(WordPaths_all): r""" The combinatorial class of all paths on the cube grid. """ + def __init__(self, alphabet): r""" The combinatorial class of all finite paths on the cube grid. @@ -844,8 +839,7 @@ def __init__(self, alphabet): True """ # Construction of the class - d = [(1, 0, 0), (0, 1, 0), (0, 0, 1), - (-1, 0, 0), (0, -1, 0), (0, 0, -1)] + d = [(1, 0, 0), (0, 1, 0), (0, 0, 1), (-1, 0, 0), (0, -1, 0), (0, 0, -1)] super().__init__(alphabet, steps=d) self._infinite_word_class = None self._finite_word_class = FiniteWordPath_cube_grid @@ -870,14 +864,15 @@ def _element_classes(self): sage: d['tuple'] """ - return {'list': FiniteWordPath_cube_grid_list, - 'str': FiniteWordPath_cube_grid_str, - 'tuple': FiniteWordPath_cube_grid_tuple, - 'callable_with_caching': FiniteWordPath_cube_grid_callable_with_caching, - 'callable': FiniteWordPath_cube_grid_callable, - 'iter_with_caching': FiniteWordPath_cube_grid_iter_with_caching, - 'iter': FiniteWordPath_cube_grid_iter, - } + return { + 'list': FiniteWordPath_cube_grid_list, + 'str': FiniteWordPath_cube_grid_str, + 'tuple': FiniteWordPath_cube_grid_tuple, + 'callable_with_caching': FiniteWordPath_cube_grid_callable_with_caching, + 'callable': FiniteWordPath_cube_grid_callable, + 'iter_with_caching': FiniteWordPath_cube_grid_iter_with_caching, + 'iter': FiniteWordPath_cube_grid_iter, + } def __repr__(self) -> str: r""" @@ -894,6 +889,7 @@ class WordPaths_dyck(WordPaths_all): r""" The combinatorial class of all Dyck paths. """ + def __init__(self, alphabet): r""" The combinatorial class of all finite Dyck paths. @@ -938,14 +934,15 @@ def _element_classes(self): sage: d['tuple'] """ - return {'list': FiniteWordPath_dyck_list, - 'str': FiniteWordPath_dyck_str, - 'tuple': FiniteWordPath_dyck_tuple, - 'callable_with_caching': FiniteWordPath_dyck_callable_with_caching, - 'callable': FiniteWordPath_dyck_callable, - 'iter_with_caching': FiniteWordPath_dyck_iter_with_caching, - 'iter': FiniteWordPath_dyck_iter, - } + return { + 'list': FiniteWordPath_dyck_list, + 'str': FiniteWordPath_dyck_str, + 'tuple': FiniteWordPath_dyck_tuple, + 'callable_with_caching': FiniteWordPath_dyck_callable_with_caching, + 'callable': FiniteWordPath_dyck_callable, + 'iter_with_caching': FiniteWordPath_dyck_iter_with_caching, + 'iter': FiniteWordPath_dyck_iter, + } def __repr__(self) -> str: r""" @@ -962,6 +959,7 @@ class WordPaths_north_east(WordPaths_all): r""" The combinatorial class of all paths using North and East directions. """ + def __init__(self, alphabet): r""" The combinatorial class of all finite paths using only north and east @@ -1006,14 +1004,15 @@ def _element_classes(self): sage: d['tuple'] """ - return {'list': FiniteWordPath_north_east_list, - 'str': FiniteWordPath_north_east_str, - 'tuple': FiniteWordPath_north_east_tuple, - 'callable_with_caching': FiniteWordPath_north_east_callable_with_caching, - 'callable': FiniteWordPath_north_east_callable, - 'iter_with_caching': FiniteWordPath_north_east_iter_with_caching, - 'iter': FiniteWordPath_north_east_iter, - } + return { + 'list': FiniteWordPath_north_east_list, + 'str': FiniteWordPath_north_east_str, + 'tuple': FiniteWordPath_north_east_tuple, + 'callable_with_caching': FiniteWordPath_north_east_callable_with_caching, + 'callable': FiniteWordPath_north_east_callable, + 'iter_with_caching': FiniteWordPath_north_east_iter_with_caching, + 'iter': FiniteWordPath_north_east_iter, + } def __repr__(self) -> str: r""" @@ -1033,6 +1032,7 @@ def __repr__(self) -> str: # # ####################################################################### + class FiniteWordPath_all(SageObject): def _repr_(self) -> str: r""" @@ -1219,6 +1219,7 @@ def tikz_trajectory(self) -> str: '(0.000, 0.000) -- (1.00, 0.000) -- (1.50, 0.866) -- (1.00, 1.73) -- (0.000, 1.73) -- (-0.500, 0.866)' """ from sage.misc.functional import N as n + l = (str(tuple(n(x, digits=3) for x in pt)) for pt in self.points()) return ' -- '.join(l) @@ -1279,8 +1280,7 @@ def projected_point_iterator(self, v=None, ring=None): for q in self.points(): yield R * q - def plot_projection(self, v=None, letters=None, color=None, ring=None, - size=12, kind='right'): + def plot_projection(self, v=None, letters=None, color=None, ring=None, size=12, kind='right'): r""" Return an image of the projection of the successive points of the path into the space orthogonal to the given vector. @@ -1390,6 +1390,7 @@ def plot_projection(self, v=None, letters=None, color=None, ring=None, letters = self.parent().alphabet() if color is None: from sage.plot.colors import hue + A = self.parent().alphabet() color = {a: hue(A.rank(a) / float(A.cardinality())) for a in A} it = self.projected_point_iterator(v, ring=ring) @@ -1397,8 +1398,7 @@ def plot_projection(self, v=None, letters=None, color=None, ring=None, next(it) elif kind != 'left': raise ValueError('unknown value for kind (=%s)' % kind) - tout = [point([c], color=color[a], size=size) - for a, c in zip(self, it) if a in letters] + tout = [point([c], color=color[a], size=size) for a, c in zip(self, it) if a in letters] return sum(tout) def projected_path(self, v=None, ring=None): @@ -1472,11 +1472,7 @@ def is_tangent(self): class FiniteWordPath_2d(FiniteWordPath_all): - def plot(self, pathoptions={"rgbcolor": 'red', "thickness": 3}, - fill=True, filloptions={"rgbcolor": 'red', "alpha": 0.2}, - startpoint=True, startoptions={"rgbcolor": 'red', "pointsize": 100}, - endarrow=True, arrowoptions={"rgbcolor": 'red', "arrowsize": 20, "width": 3}, - gridlines=False, gridoptions={}): + def plot(self, pathoptions={"rgbcolor": 'red', "thickness": 3}, fill=True, filloptions={"rgbcolor": 'red', "alpha": 0.2}, startpoint=True, startoptions={"rgbcolor": 'red', "pointsize": 100}, endarrow=True, arrowoptions={"rgbcolor": 'red', "arrowsize": 20, "width": 3}, gridlines=False, gridoptions={}): r""" Return a 2d Graphics illustrating the path. @@ -1714,7 +1710,7 @@ def plot_directive_vector(self, options={"rgbcolor": 'blue'}): """ start = self.start_point() end = self.end_point() - if (start == end): + if start == end: G = point(start, pointsize=10, **options) else: G = arrow(start, end, **options) @@ -1977,8 +1973,7 @@ def ymax(self): class FiniteWordPath_3d(FiniteWordPath_all): - def plot(self, pathoptions={"rgbcolor": 'red', "arrow_head": True, "thickness": 3}, - startpoint=True, startoptions={"rgbcolor": 'red', "size": 10}): + def plot(self, pathoptions={"rgbcolor": 'red', "arrow_head": True, "thickness": 3}, startpoint=True, startoptions={"rgbcolor": 'red', "size": 10}): r""" INPUT: @@ -2023,6 +2018,7 @@ def plot(self, pathoptions={"rgbcolor": 'red', "arrow_head": True, "thickness": # # ####################################################################### + class FiniteWordPath_square_grid(FiniteWordPath_2d): def is_closed(self) -> bool: r""" @@ -2330,6 +2326,7 @@ class FiniteWordPath_dyck(FiniteWordPath_2d): # #### Finite paths #### + class FiniteWordPath_all_list(WordDatatype_list, FiniteWordPath_all, FiniteWord_class): r""" TESTS:: @@ -2342,6 +2339,7 @@ class FiniteWordPath_all_list(WordDatatype_list, FiniteWordPath_all, FiniteWord_ sage: p == loads(dumps(p)) True """ + pass @@ -2357,6 +2355,7 @@ class FiniteWordPath_all_str(WordDatatype_str, FiniteWordPath_all, FiniteWord_cl sage: p == loads(dumps(p)) True """ + pass @@ -2372,6 +2371,7 @@ class FiniteWordPath_all_tuple(WordDatatype_tuple, FiniteWordPath_all, FiniteWor sage: p == loads(dumps(p)) True """ + pass @@ -2393,6 +2393,7 @@ class FiniteWordPath_all_callable(WordDatatype_callable, FiniteWordPath_all, Fin # #### Finite paths on 2d #### + class FiniteWordPath_2d_list(WordDatatype_list, FiniteWordPath_2d, FiniteWord_class): r""" TESTS:: @@ -2405,6 +2406,7 @@ class FiniteWordPath_2d_list(WordDatatype_list, FiniteWordPath_2d, FiniteWord_cl sage: p == loads(dumps(p)) True """ + pass @@ -2420,6 +2422,7 @@ class FiniteWordPath_2d_str(WordDatatype_str, FiniteWordPath_2d, FiniteWord_clas sage: p == loads(dumps(p)) True """ + pass @@ -2435,6 +2438,7 @@ class FiniteWordPath_2d_tuple(WordDatatype_tuple, FiniteWordPath_2d, FiniteWord_ sage: p == loads(dumps(p)) True """ + pass @@ -2456,6 +2460,7 @@ class FiniteWordPath_2d_callable(WordDatatype_callable, FiniteWordPath_2d, Finit # #### Finite paths on 3d #### + class FiniteWordPath_3d_list(WordDatatype_list, FiniteWordPath_3d, FiniteWord_class): r""" TESTS:: @@ -2468,6 +2473,7 @@ class FiniteWordPath_3d_list(WordDatatype_list, FiniteWordPath_3d, FiniteWord_cl sage: p == loads(dumps(p)) True """ + pass @@ -2483,6 +2489,7 @@ class FiniteWordPath_3d_str(WordDatatype_str, FiniteWordPath_3d, FiniteWord_clas sage: p == loads(dumps(p)) True """ + pass @@ -2498,6 +2505,7 @@ class FiniteWordPath_3d_tuple(WordDatatype_tuple, FiniteWordPath_3d, FiniteWord_ sage: p == loads(dumps(p)) True """ + pass @@ -2519,6 +2527,7 @@ class FiniteWordPath_3d_callable(WordDatatype_callable, FiniteWordPath_3d, Finit # #### Finite paths on square grid #### + class FiniteWordPath_square_grid_list(WordDatatype_list, FiniteWordPath_square_grid, FiniteWord_class): r""" TESTS:: @@ -2531,6 +2540,7 @@ class FiniteWordPath_square_grid_list(WordDatatype_list, FiniteWordPath_square_g sage: p == loads(dumps(p)) True """ + pass @@ -2546,6 +2556,7 @@ class FiniteWordPath_square_grid_str(WordDatatype_str, FiniteWordPath_square_gri sage: p == loads(dumps(p)) True """ + pass @@ -2561,6 +2572,7 @@ class FiniteWordPath_square_grid_tuple(WordDatatype_tuple, FiniteWordPath_square sage: p == loads(dumps(p)) True """ + pass @@ -2587,6 +2599,7 @@ class FiniteWordPath_square_grid_callable(WordDatatype_callable, FiniteWordPath_ # #### Finite paths on triangle grid #### + class FiniteWordPath_triangle_grid_list(WordDatatype_list, FiniteWordPath_triangle_grid, FiniteWord_class): r""" TESTS:: @@ -2599,6 +2612,7 @@ class FiniteWordPath_triangle_grid_list(WordDatatype_list, FiniteWordPath_triang sage: p == loads(dumps(p)) True """ + pass @@ -2614,6 +2628,7 @@ class FiniteWordPath_triangle_grid_str(WordDatatype_str, FiniteWordPath_triangle sage: p == loads(dumps(p)) True """ + pass @@ -2629,6 +2644,7 @@ class FiniteWordPath_triangle_grid_tuple(WordDatatype_tuple, FiniteWordPath_tria sage: p == loads(dumps(p)) True """ + pass @@ -2650,6 +2666,7 @@ class FiniteWordPath_triangle_grid_callable(WordDatatype_callable, FiniteWordPat # #### Finite paths on hexagonal grid #### + class FiniteWordPath_hexagonal_grid_list(WordDatatype_list, FiniteWordPath_hexagonal_grid, FiniteWord_class): r""" TESTS:: @@ -2662,6 +2679,7 @@ class FiniteWordPath_hexagonal_grid_list(WordDatatype_list, FiniteWordPath_hexag sage: p == loads(dumps(p)) True """ + pass @@ -2677,6 +2695,7 @@ class FiniteWordPath_hexagonal_grid_str(WordDatatype_str, FiniteWordPath_hexagon sage: p == loads(dumps(p)) True """ + pass @@ -2692,6 +2711,7 @@ class FiniteWordPath_hexagonal_grid_tuple(WordDatatype_tuple, FiniteWordPath_hex sage: p == loads(dumps(p)) True """ + pass @@ -2713,6 +2733,7 @@ class FiniteWordPath_hexagonal_grid_callable(WordDatatype_callable, FiniteWordPa # #### Finite paths on cube grid #### + class FiniteWordPath_cube_grid_list(WordDatatype_list, FiniteWordPath_cube_grid, FiniteWord_class): r""" TESTS:: @@ -2725,6 +2746,7 @@ class FiniteWordPath_cube_grid_list(WordDatatype_list, FiniteWordPath_cube_grid, sage: p == loads(dumps(p)) True """ + pass @@ -2740,6 +2762,7 @@ class FiniteWordPath_cube_grid_str(WordDatatype_str, FiniteWordPath_cube_grid, F sage: p == loads(dumps(p)) True """ + pass @@ -2755,6 +2778,7 @@ class FiniteWordPath_cube_grid_tuple(WordDatatype_tuple, FiniteWordPath_cube_gri sage: p == loads(dumps(p)) True """ + pass @@ -2776,6 +2800,7 @@ class FiniteWordPath_cube_grid_callable(WordDatatype_callable, FiniteWordPath_cu # #### Finite paths on north_east #### + class FiniteWordPath_north_east_list(WordDatatype_list, FiniteWordPath_north_east, FiniteWord_class): r""" TESTS:: @@ -2788,6 +2813,7 @@ class FiniteWordPath_north_east_list(WordDatatype_list, FiniteWordPath_north_eas sage: p == loads(dumps(p)) True """ + pass @@ -2803,6 +2829,7 @@ class FiniteWordPath_north_east_str(WordDatatype_str, FiniteWordPath_north_east, sage: p == loads(dumps(p)) True """ + pass @@ -2818,6 +2845,7 @@ class FiniteWordPath_north_east_tuple(WordDatatype_tuple, FiniteWordPath_north_e sage: p == loads(dumps(p)) True """ + pass @@ -2839,6 +2867,7 @@ class FiniteWordPath_north_east_callable(WordDatatype_callable, FiniteWordPath_n # #### Finite paths on dyck #### + class FiniteWordPath_dyck_list(WordDatatype_list, FiniteWordPath_dyck, FiniteWord_class): r""" TESTS:: @@ -2851,6 +2880,7 @@ class FiniteWordPath_dyck_list(WordDatatype_list, FiniteWordPath_dyck, FiniteWor sage: p == loads(dumps(p)) True """ + pass @@ -2866,6 +2896,7 @@ class FiniteWordPath_dyck_str(WordDatatype_str, FiniteWordPath_dyck, FiniteWord_ sage: p == loads(dumps(p)) True """ + pass @@ -2881,6 +2912,7 @@ class FiniteWordPath_dyck_tuple(WordDatatype_tuple, FiniteWordPath_dyck, FiniteW sage: p == loads(dumps(p)) True """ + pass diff --git a/src/sage/combinat/words/shuffle_product.py b/src/sage/combinat/words/shuffle_product.py index 9d5c43dd73b..7fafeef327f 100644 --- a/src/sage/combinat/words/shuffle_product.py +++ b/src/sage/combinat/words/shuffle_product.py @@ -6,6 +6,7 @@ The module :mod:`sage.combinat.shuffle` contains a more general implementation of shuffle product. """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # Copyright (C) 2008 Franco Saliola @@ -138,8 +139,7 @@ def __contains__(self, x): except IndexError: return False if w1 and w2 and letter == w1[0] == w2[0]: - return (Word(wx) in self._w1[1:].shuffle(self._w2) or - Word(wx) in self._w1.shuffle(self._w2[1:])) + return Word(wx) in self._w1[1:].shuffle(self._w2) or Word(wx) in self._w1.shuffle(self._w2[1:]) if w1 and letter == w1[0]: w1.pop(0) elif w2 and letter == w2[0]: diff --git a/src/sage/combinat/words/suffix_trees.py b/src/sage/combinat/words/suffix_trees.py index ebd2065319f..a1fb9ef63bb 100644 --- a/src/sage/combinat/words/suffix_trees.py +++ b/src/sage/combinat/words/suffix_trees.py @@ -1,6 +1,7 @@ r""" Suffix tries and suffix trees """ + # **************************************************************************** # Copyright (C) 2008 Franco Saliola # @@ -135,8 +136,7 @@ def _process_letter(self, letter): else: self._suffix_link[old_s] = self._transition_function[(r, letter)] # update the active state - self._active_state = \ - self._transition_function[(self._active_state, letter)] + self._active_state = self._transition_function[(self._active_state, letter)] def process_letter(self, letter): r""" @@ -261,9 +261,7 @@ def __eq__(self, other) -> bool: """ if not isinstance(other, SuffixTrie): return False - return self._transition_function == other._transition_function \ - and self._suffix_link == other._suffix_link \ - and self.word() == other.word() + return self._transition_function == other._transition_function and self._suffix_link == other._suffix_link and self.word() == other.word() def transition_function(self, node, word): r""" @@ -290,8 +288,7 @@ def transition_function(self, node, word): return 0 if word.length() == 1: return self._transition_function[(node, word)] - return self.transition_function( - self._transition_function[(node, word[0:1])], word[1:]) + return self.transition_function(self._transition_function[(node, word[0:1])], word[1:]) def states(self): r""" @@ -459,8 +456,7 @@ def to_digraph(self): dag.setdefault(u, {})[v] = letter return DiGraph(dag) - def plot(self, layout='tree', tree_root=0, tree_orientation='up', - vertex_colors=None, edge_labels=True, *args, **kwds): + def plot(self, layout='tree', tree_root=0, tree_orientation='up', vertex_colors=None, edge_labels=True, *args, **kwds): r""" Return a Graphics object corresponding to the transition graph of the suffix trie. @@ -484,10 +480,7 @@ def plot(self, layout='tree', tree_root=0, tree_orientation='up', suffix_nodes = self.final_states() non_suffix_nodes = list(set(self.states()) - set(suffix_nodes)) vertex_colors = {'#fec7b8': suffix_nodes, '#ffffff': non_suffix_nodes} - return tree.plot(layout=layout, tree_root=tree_root, - tree_orientation=tree_orientation, - vertex_colors=vertex_colors, edge_labels=edge_labels, - *args, **kwds) + return tree.plot(layout=layout, tree_root=tree_root, tree_orientation=tree_orientation, vertex_colors=vertex_colors, edge_labels=edge_labels, *args, **kwds) def show(self, *args, **kwds): r""" @@ -637,7 +630,7 @@ def _process_letter(self, letter): """ s, (k, i) = self._active_state old_r = 0 - end_state, r = self._test_and_split(s, (k, i-1), letter) + end_state, r = self._test_and_split(s, (k, i - 1), letter) while not end_state: # adjoin a new state rr and create a transition from r to rr rr = len(self._transition_function) @@ -648,14 +641,14 @@ def _process_letter(self, letter): self._suffix_link[old_r] = r old_r = r # follow the suffix link to the next state - s, k = self._canonize(self._suffix_link[s], (k, i-1)) - end_state, r = self._test_and_split(s, (k, i-1), letter) + s, k = self._canonize(self._suffix_link[s], (k, i - 1)) + end_state, r = self._test_and_split(s, (k, i - 1), letter) # update the suffix link, if necessary if old_r != 0: self._suffix_link[old_r] = s # set the active state s, k = self._canonize(s, (k, i)) - self._active_state = (s, (k, i+1)) + self._active_state = (s, (k, i + 1)) def _test_and_split(self, s, k_p, letter): r""" @@ -686,8 +679,8 @@ def _test_and_split(self, s, k_p, letter): del self._transition_function[s][(kk, pp)] r = len(self._transition_function) self._transition_function[r] = {} - self._transition_function[s][(kk, kk+p-k)] = r - self._transition_function[r][(kk+p-k+1, pp)] = ss + self._transition_function[s][(kk, kk + p - k)] = r + self._transition_function[r][(kk + p - k + 1, pp)] = ss return (False, r) transition = self._find_transition(s, letter) if transition is None: @@ -721,7 +714,7 @@ def _canonize(self, s, k_p): k = k + pp - kk + 1 s = ss if k <= p: - (kk, pp), ss = self._find_transition(s, self._letters[k-1]) + (kk, pp), ss = self._find_transition(s, self._letters[k - 1]) return (s, k) def _find_transition(self, state, letter): @@ -849,9 +842,7 @@ def to_digraph(self, word_labels=False): d[u][v] = (i, len(self._letters)) return DiGraph(d) - def plot(self, word_labels=False, layout='tree', tree_root=0, - tree_orientation='up', vertex_colors=None, edge_labels=True, - *args, **kwds): + def plot(self, word_labels=False, layout='tree', tree_root=0, tree_orientation='up', vertex_colors=None, edge_labels=True, *args, **kwds): r""" Return a Graphics object corresponding to the transition graph of the suffix tree. @@ -888,10 +879,7 @@ def plot(self, word_labels=False, layout='tree', tree_root=0, tree.set_edge_label(u, v, label.string_rep()) if vertex_colors is None: vertex_colors = {'#fec7b8': tree.vertices(sort=True)} - return tree.plot(layout=layout, tree_root=tree_root, - tree_orientation=tree_orientation, - vertex_colors=vertex_colors, edge_labels=edge_labels, - *args, **kwds) + return tree.plot(layout=layout, tree_root=tree_root, tree_orientation=tree_orientation, vertex_colors=vertex_colors, edge_labels=edge_labels, *args, **kwds) def show(self, word_labels=None, *args, **kwds): r""" @@ -931,8 +919,7 @@ def __eq__(self, other) -> bool: """ if not isinstance(other, ImplicitSuffixTree): return False - return self._transition_function == other._transition_function \ - and self._letters == other._letters + return self._transition_function == other._transition_function and self._letters == other._letters def transition_function(self, word, node=0): r""" @@ -968,19 +955,19 @@ def transition_function(self, word, node=0): (k, p), s = self._find_transition(node, word[0]) if p is None: # test that word is a prefix of self._letters[k-1:] - if word == self._word[k-1:(k-1)+word.length()]: + if word == self._word[k - 1 : (k - 1) + word.length()]: if word.length() == len(self._letters) - k + 1: return "explicit", s edge = (node, s) return "implicit", edge, word.length() else: # find longest common prefix - m = min(p-k+1, word.length()) + m = min(p - k + 1, word.length()) i = 0 - while i < m and self._word[k-1+i] == word[i]: + while i < m and self._word[k - 1 + i] == word[i]: i += 1 - if i == p-k+1: - return self.transition_function(word[p-k+1:], s) + if i == p - k + 1: + return self.transition_function(word[p - k + 1 :], s) edge = (node, s) return "implicit", edge, i return "explicit", node @@ -1099,10 +1086,10 @@ def to_explicit_suffix_tree(self): end_of_string = object() self._letters.append(end_of_string) s, (k, i) = self._active_state - end_state, r = self._test_and_split(s, (k, i-1), end_of_string) + end_state, r = self._test_and_split(s, (k, i - 1), end_of_string) while not end_state: - s, k = self._canonize(self._suffix_link[s], (k, i-1)) - end_state, r = self._test_and_split(s, (k, i-1), end_of_string) + s, k = self._canonize(self._suffix_link[s], (k, i - 1)) + end_state, r = self._test_and_split(s, (k, i - 1), end_of_string) # remove the end of string symbol from the word self._letters.pop() @@ -1259,26 +1246,26 @@ def factor_iterator(self, n=None): yield w[0:0] while queue: v, i, j, l = queue.pop() - for k in range(i, j+1): - yield w[j-l:k] + for k in range(i, j + 1): + yield w[j - l : k] for (i, j), u in self._transition_function[v].items(): if j is None: j = wlen - queue.append((u, i, j, l+j-i+1)) + queue.append((u, i, j, l + j - i + 1)) elif isinstance(n, (int, Integer)): queue = [(0, 0, -1, 0)] while queue: v, i, j, l = queue.pop() if l == n: - yield w[j-l:j] + yield w[j - l : j] if l < n: for (i, j), u in self._transition_function[v].items(): if j is None: j = wlen if j - i >= n - l: - yield w[i-l-1:i-l+n-1] + yield w[i - l - 1 : i - l + n - 1] else: - queue.append((u, i, j, l+j-i+1)) + queue.append((u, i, j, l + j - i + 1)) else: raise TypeError("not an integer or None: %s" % n) @@ -1322,17 +1309,17 @@ def LZ_decomposition(self): while i < len(w): l = 0 (x, y), successor = self._find_transition(0, w[i]) - x = x-1 - while x < i+l: + x = x - 1 + while x < i + l: if y is None: - l = len(w)-i + l = len(w) - i else: - l += y-x - if i+l >= len(w): - l = len(w)-i + l += y - x + if i + l >= len(w): + l = len(w) - i break - (x, y), successor = self._find_transition(successor, w[i+l]) - x = x-1 + (x, y), successor = self._find_transition(successor, w[i + l]) + x = x - 1 i += max(1, l) iB.append(i) return iB @@ -1409,8 +1396,7 @@ def suffix_walk(self, edge, l): """ start, end = edge # Select the transition that corresponds to edge - ij = next(ij for ij, target in self._transition_function[start].items() - if target == end) + ij = next(ij for ij, target in self._transition_function[start].items() if target == end) # self.word()[i-1:j] is the word on the edges i = ij[0] - 1 @@ -1457,13 +1443,13 @@ def condition1_square_pairs(i): LZ-decomposition and that start in the `i`-th block and end in the `(i+1)`-th. """ - for k in range(1, B[i+1]-B[i]+1): - q = B[i+1]-k - k1 = w.longest_forward_extension(B[i+1], q) if B[i+1] < len(w) else 0 - k2 = w.longest_backward_extension(B[i+1]-1, q-1) if q > 0 else 0 - start = max(q-k2, q-k+1) - if k1+k2 >= k and k1 > 0 and start >= B[i]: - yield (start, 2*k) + for k in range(1, B[i + 1] - B[i] + 1): + q = B[i + 1] - k + k1 = w.longest_forward_extension(B[i + 1], q) if B[i + 1] < len(w) else 0 + k2 = w.longest_backward_extension(B[i + 1] - 1, q - 1) if q > 0 else 0 + start = max(q - k2, q - k + 1) + if k1 + k2 >= k and k1 > 0 and start >= B[i]: + yield (start, 2 * k) def condition2_square_pairs(i): r""" @@ -1472,17 +1458,17 @@ def condition2_square_pairs(i): LZ-decomposition and that starts in the `(i-1)`-th block or before. Their end is either in the `i`-th or the `(i+1)`-th block. """ - if i+2 < len(B): - end = B[i+2] - B[i] + 1 + if i + 2 < len(B): + end = B[i + 2] - B[i] + 1 else: - end = B[i+1] - B[i] + 1 + end = B[i + 1] - B[i] + 1 for k in range(2, end): q = B[i] + k k1 = w.longest_forward_extension(B[i], q) if q < len(w) else 0 - k2 = w.longest_backward_extension(B[i]-1, q-1) if B[i] > 0 else 0 - start = max(B[i]-k2, B[i]-k+1) - if k1+k2 >= k and k1 > 0 and start+k <= B[i+1] and k2 > 0: - yield (start, 2*k) + k2 = w.longest_backward_extension(B[i] - 1, q - 1) if B[i] > 0 else 0 + start = max(B[i] - k2, B[i] - k + 1) + if k1 + k2 >= k and k1 > 0 and start + k <= B[i + 1] and k2 > 0: + yield (start, 2 * k) w = self.word() B = self.LZ_decomposition() @@ -1524,7 +1510,7 @@ def uncompactify(self): else: newtree.add_edge(u, new_node, label[0]) for w in label[1:-1]: - newtree.add_edge(new_node, new_node+1, w) + newtree.add_edge(new_node, new_node + 1, w) new_node += 1 newtree.add_edge(new_node, v, label[-1]) new_node += 1 @@ -1550,13 +1536,13 @@ def trie_type_dict(self): new_node = len(self._transition_function) for u, dd in self._transition_function.items(): for sl, v in dd.items(): - w = self._word[sl[0]-1:sl[1]] + w = self._word[sl[0] - 1 : sl[1]] if w.length() == 1: d[u, w] = v else: d[u, w[0:1]] = new_node - for i in range(1, w.length()-1): - d[new_node, w[i:i+1]] = new_node + 1 + for i in range(1, w.length() - 1): + d[new_node, w[i : i + 1]] = new_node + 1 new_node += 1 d[new_node, w[-1:]] = v new_node += 1 @@ -1598,6 +1584,7 @@ class DecoratedSuffixTree(ImplicitSuffixTree): time. The algorithm is an implementation of the one proposed in [DS2004]_. """ + def __init__(self, w): """ Initialize ``self``. @@ -1660,6 +1647,7 @@ def _partial_labeling(self): sage: T._partial_labeling() {(3, 4): [1], (5, 1): [3], (5, 6): [1], (11, 17): [1], (13, 8): [1], (15, 10): [2]} """ + def node_processing(node, parent, head): r""" Marks points along the edge ``(parent, node)`` if the string depth @@ -1774,7 +1762,7 @@ def walk_chain(u, v, l, start): parent = final_state[1][0] child = final_state[1][1] depth = final_state[2] - next_letter = self._letters[D[parent][child][0]+depth] + next_letter = self._letters[D[parent][child][0] + depth] if next_letter == self._letters[start]: successful = True depth += 1 @@ -1782,9 +1770,9 @@ def walk_chain(u, v, l, start): if successful: if (parent, child) in prelabeling: if depth not in prelabeling[(parent, child)]: - walk_chain(parent, child, depth, start+1) + walk_chain(parent, child, depth, start + 1) else: - walk_chain(parent, child, depth, start+1) + walk_chain(parent, child, depth, start + 1) def treat_node(current_node, i, j): r""" @@ -1805,7 +1793,7 @@ def treat_node(current_node, i, j): for child in D[current_node]: edge = (current_node, child) edge_label = D[edge[0]][edge[1]] - treat_node(child, edge_label[0]-(j-i), edge_label[1]) + treat_node(child, edge_label[0] - (j - i), edge_label[1]) if (current_node, child) in prelabeling: for l in prelabeling[edge]: square_start = edge_label[0] - (j - i) @@ -1840,16 +1828,17 @@ def square_vocabulary(self, output='pair'): sage: sorted(DecoratedSuffixTree(w).square_vocabulary(output='word')) [word: , word: 00, word: 00110011, word: 01100110, word: 1010, word: 11] """ + def treat_node(current_node, i, j): if current_node in D: for child in D[current_node]: edge = (current_node, child) - edge_label = (D[edge[0]][edge[1]]) - treat_node(child, edge_label[0]-(j-i), edge_label[1]) + edge_label = D[edge[0]][edge[1]] + treat_node(child, edge_label[0] - (j - i), edge_label[1]) if (current_node, child) in Q: for l in Q[(current_node, child)]: - square_start = edge_label[0]-(j-i) - pair = (square_start, edge_label[0]+l-square_start) + square_start = edge_label[0] - (j - i) + pair = (square_start, edge_label[0] + l - square_start) squares.append(pair) if output not in ["pair", "word"]: @@ -1861,4 +1850,4 @@ def treat_node(current_node, i, j): treat_node(0, 0, 0) if output == "pair": return squares - return [self.word()[i:i + l] for i, l in squares] + return [self.word()[i : i + l] for i, l in squares] diff --git a/src/sage/combinat/words/word.py b/src/sage/combinat/words/word.py index 1ef0ea5c887..a26eec29207 100644 --- a/src/sage/combinat/words/word.py +++ b/src/sage/combinat/words/word.py @@ -8,6 +8,7 @@ - Sébastien Labbé - Franco Saliola """ + # *************************************************************************** # Copyright (C) 2008 Arnaud Bergeron , # Amy Glen , @@ -25,14 +26,8 @@ from sage.combinat.words.abstract_word import Word_class from sage.combinat.words.finite_word import FiniteWord_class from sage.combinat.words.infinite_word import InfiniteWord_class -from .word_datatypes import (WordDatatype_str, - WordDatatype_list, - WordDatatype_tuple) -from .word_infinite_datatypes import ( - WordDatatype_iter_with_caching, - WordDatatype_iter, - WordDatatype_callable_with_caching, - WordDatatype_callable) +from .word_datatypes import WordDatatype_str, WordDatatype_list, WordDatatype_tuple +from .word_infinite_datatypes import WordDatatype_iter_with_caching, WordDatatype_iter, WordDatatype_callable_with_caching, WordDatatype_callable from .morphic import WordDatatype_morphic lazy_import('sage.monoids.free_monoid_element', 'FreeMonoidElement') @@ -41,8 +36,7 @@ # Word_class to Word and imbedding Word as its __call__ method. -def Word(data=None, alphabet=None, length=None, datatype=None, - caching=True, RSK_data=None): +def Word(data=None, alphabet=None, length=None, datatype=None, caching=True, RSK_data=None): r""" Construct a word. @@ -194,23 +188,26 @@ def Word(data=None, alphabet=None, length=None, datatype=None, if RSK_data is not None: # if a list of a semistandard and a standard tableau or a pair of lists from sage.combinat.tableau import Tableau - if isinstance(RSK_data, (tuple, list)) and len(RSK_data) == 2 and \ - all(isinstance(x, Tableau) for x in RSK_data): + + if isinstance(RSK_data, (tuple, list)) and len(RSK_data) == 2 and all(isinstance(x, Tableau) for x in RSK_data): from sage.combinat.rsk import RSK_inverse + return RSK_inverse(*RSK_data, output='word') - if isinstance(RSK_data, (tuple, list)) and len(RSK_data) == 2 and \ - all(isinstance(x, (list, tuple)) for x in RSK_data): + if isinstance(RSK_data, (tuple, list)) and len(RSK_data) == 2 and all(isinstance(x, (list, tuple)) for x in RSK_data): from sage.combinat.rsk import RSK_inverse + P, Q = map(Tableau, RSK_data) return RSK_inverse(P, Q, 'word') raise ValueError("input must be a pair of tableaux") # Create the parent object from .words import Words + parent = Words(alphabet) return parent(data=data, length=length, datatype=datatype, caching=caching) + ####################################################################### # # # Concrete word classes # @@ -279,6 +276,7 @@ class FiniteWord_char(WordDatatype_char, FiniteWord_class): sage: w == loads(dumps(w)) True """ + pass @@ -301,6 +299,7 @@ class FiniteWord_list(WordDatatype_list, FiniteWord_class): sage: w == loads(dumps(w)) True """ + pass @@ -323,6 +322,7 @@ class FiniteWord_str(WordDatatype_str, FiniteWord_class): sage: w == loads(dumps(w)) True """ + pass @@ -345,6 +345,7 @@ class FiniteWord_tuple(WordDatatype_tuple, FiniteWord_class): sage: w == loads(dumps(w)) True """ + pass @@ -372,6 +373,7 @@ class FiniteWord_iter_with_caching(WordDatatype_iter_with_caching, FiniteWord_cl sage: type(z) """ + pass @@ -401,6 +403,7 @@ class FiniteWord_iter(WordDatatype_iter, FiniteWord_class): sage: type(z) """ + pass @@ -453,6 +456,7 @@ class FiniteWord_callable_with_caching(WordDatatype_callable_with_caching, Finit sage: type(z) """ + pass @@ -483,11 +487,13 @@ class FiniteWord_callable(WordDatatype_callable, FiniteWord_class): sage: type(z) """ + pass # #### Infinite Words #### + class InfiniteWord_iter_with_caching(WordDatatype_iter_with_caching, InfiniteWord_class): r""" Infinite word represented by an iterable (with caching). @@ -530,6 +536,7 @@ class InfiniteWord_iter_with_caching(WordDatatype_iter_with_caching, InfiniteWor ....: print("No exception raised, unexpected") TypeError raised in dumps() as expected """ + pass @@ -575,6 +582,7 @@ class InfiniteWord_iter(WordDatatype_iter, InfiniteWord_class): ....: print("No exception raised, unexpected") TypeError raised in dumps() as expected """ + pass @@ -606,6 +614,7 @@ class InfiniteWord_callable_with_caching(WordDatatype_callable_with_caching, Inf sage: type(z) """ + pass @@ -638,11 +647,13 @@ class InfiniteWord_callable(WordDatatype_callable, InfiniteWord_class): sage: type(z) """ + pass # #### Words of unknown length #### + class Word_iter_with_caching(WordDatatype_iter_with_caching, Word_class): r""" Word of unknown length (finite or infinite) represented by an @@ -683,6 +694,7 @@ class Word_iter_with_caching(WordDatatype_iter_with_caching, Word_class): ....: print("No exception raised, unexpected") TypeError raised in dumps() as expected """ + pass @@ -726,11 +738,13 @@ class Word_iter(WordDatatype_iter, Word_class): ....: print("No exception raised, unexpected") TypeError raised in dumps() as expected """ + pass # #### Morphic Words #### + class FiniteWord_morphic(WordDatatype_morphic, FiniteWord_class): r""" Finite morphic word. @@ -755,6 +769,7 @@ class FiniteWord_morphic(WordDatatype_morphic, FiniteWord_class): sage: loads(dumps(w)) word: ab """ + pass @@ -782,4 +797,5 @@ class InfiniteWord_morphic(WordDatatype_morphic, InfiniteWord_class): sage: loads(dumps(w)) word: abaababaabaababaababaabaababaabaababaaba... """ + pass diff --git a/src/sage/combinat/words/word_generators.py b/src/sage/combinat/words/word_generators.py index 45614e4989b..99e56dd253b 100644 --- a/src/sage/combinat/words/word_generators.py +++ b/src/sage/combinat/words/word_generators.py @@ -40,6 +40,7 @@ sage: t = words.ThueMorseWord(); t word: 0110100110010110100101100110100110010110... """ + # **************************************************************************** # Copyright (C) 2008 Franco Saliola , # Sebastien Labbe , @@ -206,21 +207,22 @@ def __init__(self, p, q, alphabet=(0, 1), algorithm='cf'): w = [alphabet[1]] else: from sage.rings.rational_field import QQ + cf = QQ((p, q)).continued_fraction_list() u = [alphabet[0]] v = [alphabet[1]] # do not consider the first zero if p < q start = 1 if p < q else 0 - for i in range(start, len(cf)-1): + for i in range(start, len(cf) - 1): if i % 2 == 0: u = u + v * cf[i] else: v = u * cf[i] + v - i = len(cf)-1 + i = len(cf) - 1 if i % 2 == 0: - u = u + v * (cf[i]-1) + u = u + v * (cf[i] - 1) else: - v = u * (cf[i]-1) + v + v = u * (cf[i] - 1) + v w = u + v else: raise ValueError(f'unknown algorithm (={algorithm})') @@ -249,6 +251,7 @@ def markoff_number(self): True """ from sage.matrix.constructor import matrix + eta = {0: matrix(2, [2, 1, 1, 1]), 1: matrix(2, [5, 2, 2, 1])} M = matrix(2, [1, 0, 0, 1]) for a in self: @@ -288,18 +291,17 @@ def standard_factorization(self): index = 0 u = 0 for i in range(p + q): - v = (u+p) % (p+q) + v = (u + p) % (p + q) if v == 1: index = i break u = v - w1, w2 = self[:index+1], self[index+1:] + w1, w2 = self[: index + 1], self[index + 1 :] w10 = w1.number_of_letter_occurrences(0) w11 = w1.number_of_letter_occurrences(1) w20 = w2.number_of_letter_occurrences(0) w21 = w2.number_of_letter_occurrences(1) - return Factorization([LowerChristoffelWord(w11, w10), - LowerChristoffelWord(w21, w20)]) + return Factorization([LowerChristoffelWord(w11, w10), LowerChristoffelWord(w21, w20)]) def __reduce__(self): r""" @@ -365,6 +367,7 @@ class WordGenerator: sage: type(loads(dumps(words2))) """ + def ThueMorseWord(self, alphabet=(0, 1), base=2): r""" Return the (Generalized) Thue-Morse word over the given alphabet. @@ -430,6 +433,7 @@ def ThueMorseWord(self, alphabet=(0, 1), base=2): if base < 2 or m < 2: raise ValueError("base (=%s) and len(alphabet) (=%s) must be at least 2" % (base, m)) from functools import partial + f = partial(self._ThueMorseWord_nth_digit, alphabet=alphabet, base=base) return W(f, datatype='callable') @@ -570,8 +574,7 @@ def FibonacciWord(self, alphabet=(0, 1), construction_method='recursive'): a, b = alphabet if construction_method == "recursive": - w = W(self._FibonacciWord_RecursiveConstructionIterator(alphabet), - datatype='iter') + w = W(self._FibonacciWord_RecursiveConstructionIterator(alphabet), datatype='iter') return w if construction_method in ("fixed point", "fixed_point"): @@ -582,10 +585,12 @@ def FibonacciWord(self, alphabet=(0, 1), construction_method='recursive'): if construction_method == "function": from sage.functions.other import floor from sage.misc.functional import sqrt - phi = (1 + sqrt(5))/2 # the golden ratio + + phi = (1 + sqrt(5)) / 2 # the golden ratio def f(n): - return a if floor((n+2)*phi) - floor((n+1)*phi) == 2 else b + return a if floor((n + 2) * phi) - floor((n + 1) * phi) == 2 else b + return W(f) raise NotImplementedError @@ -691,8 +696,8 @@ def CodingOfRotationWord(self, alpha, beta, x=0, alphabet=(0, 1)): if len(set(alphabet)) != 2: raise TypeError("alphabet does not contain two distinct elements") from functools import partial - f = partial(self._CodingOfRotationWord_function, - alpha=alpha, beta=beta, x=x, alphabet=alphabet) + + f = partial(self._CodingOfRotationWord_function, alpha=alpha, beta=beta, x=x, alphabet=alphabet) return InfiniteWords(alphabet)(f, datatype='callable') def _CodingOfRotationWord_function(self, n, alpha, beta, x=0, alphabet=(0, 1)): @@ -884,6 +889,7 @@ def CharacteristicSturmianWord(self, slope, alphabet=(0, 1), bits=None): msg = "the argument slope (=%s) must be in ]0,1[" % slope raise ValueError(msg) from sage.rings.continued_fraction import continued_fraction + cf = continued_fraction(slope) if cf.length() == Infinity: parent = InfiniteWords(alphabet) @@ -894,10 +900,8 @@ def CharacteristicSturmianWord(self, slope, alphabet=(0, 1), bits=None): cf = iter(slope) parent = InfiniteWords(alphabet) else: - raise TypeError("slope (=%s) must be a real number" % slope + - "or an iterable") - w = parent(self._CharacteristicSturmianWord_LetterIterator(cf, alphabet), - datatype='iter') + raise TypeError("slope (=%s) must be a real number" % slope + "or an iterable") + w = parent(self._CharacteristicSturmianWord_LetterIterator(cf, alphabet), datatype='iter') return w def _CharacteristicSturmianWord_LetterIterator(self, cf, alphabet=(0, 1)): @@ -954,14 +958,14 @@ def _CharacteristicSturmianWord_LetterIterator(self, cf, alphabet=(0, 1)): if not e >= 1: raise ValueError("the second term of the continued fraction expansion must be larger or equal to 1") - s1, s0 = s1*(e-1) + s0, s1 + s1, s0 = s1 * (e - 1) + s0, s1 n = 0 while True: try: for i in s1[n:]: n += 1 yield alphabet[i] - s1, s0 = s1*next(cf) + s0, s1 + s1, s0 = s1 * next(cf) + s0, s1 except StopIteration: return @@ -1147,15 +1151,16 @@ def LowerMechanicalWord(self, alpha, rho=0, alphabet=None): from sage.functions.other import floor from sage.combinat.words.alphabet import build_alphabet + if alphabet is None or alphabet in ((0, 1), [0, 1]): alphabet = build_alphabet([0, 1]) - s = lambda n: floor(alpha*(n+1) + rho) - floor(alpha*n + rho) + s = lambda n: floor(alpha * (n + 1) + rho) - floor(alpha * n + rho) else: alphabet = build_alphabet(alphabet) card = alphabet.cardinality() if card != 2: raise TypeError("size of alphabet (=%s) must be two" % card) - s = lambda n: alphabet[floor(alpha*(n+1) + rho) - floor(alpha*n + rho)] + s = lambda n: alphabet[floor(alpha * (n + 1) + rho) - floor(alpha * n + rho)] return InfiniteWords(alphabet)(s) def UpperMechanicalWord(self, alpha, rho=0, alphabet=None): @@ -1205,15 +1210,16 @@ def UpperMechanicalWord(self, alpha, rho=0, alphabet=None): from sage.functions.other import ceil from sage.combinat.words.alphabet import build_alphabet + if alphabet is None or alphabet in ((0, 1), [0, 1]): alphabet = build_alphabet([0, 1]) - s = lambda n: ceil(alpha*(n+1) + rho) - ceil(alpha*n + rho) + s = lambda n: ceil(alpha * (n + 1) + rho) - ceil(alpha * n + rho) else: alphabet = build_alphabet(alphabet) card = alphabet.cardinality() if card != 2: raise TypeError("size of alphabet (=%s) must be two" % card) - s = lambda n: alphabet[ceil(alpha*(n+1) + rho) - ceil(alpha*n + rho)] + s = lambda n: alphabet[ceil(alpha * (n + 1) + rho) - ceil(alpha * n + rho)] return InfiniteWords(alphabet)(s) def StandardEpisturmianWord(self, directive_word): @@ -1264,9 +1270,7 @@ def StandardEpisturmianWord(self, directive_word): """ if not isinstance(directive_word, Word_class): raise TypeError("directive_word is not a word, so it cannot be used to build an episturmian word") - epistandard = directive_word.parent()( - self._StandardEpisturmianWord_LetterIterator(directive_word), - datatype='iter') + epistandard = directive_word.parent()(self._StandardEpisturmianWord_LetterIterator(directive_word), datatype='iter') return epistandard def _StandardEpisturmianWord_LetterIterator(self, directive_word): @@ -1481,6 +1485,7 @@ def _fibonacci_tile(self, n, q_0=None, q_1=3): [BmBGL09]_ """ from sage.combinat.words.morphism import WordMorphism + W = FiniteWords([0, 1, 2, 3]) bar = WordMorphism({0: 0, 1: 3, 3: 1, 2: 2}, codomain=W) if n == 0: @@ -1508,9 +1513,10 @@ def fibonacci_tile(self, n): Path: 323030101212 Path: 3230301030323212323032321210121232121010... """ - w = self._fibonacci_tile(3*n+1) + w = self._fibonacci_tile(3 * n + 1) w = w**4 from sage.combinat.words.paths import WordPaths + P = WordPaths([0, 1, 2, 3]) l = list(w.partial_sums(start=3, mod=4)) return P(l)[:-1] @@ -1527,9 +1533,10 @@ def dual_fibonacci_tile(self, n): Path: 3212303230103230321232101232123032123210... Path: 3212303230103230321232101232123032123210... """ - w = self._fibonacci_tile(3*n+1, 3, 3) + w = self._fibonacci_tile(3 * n + 1, 3, 3) w = w**4 from sage.combinat.words.paths import WordPaths + P = WordPaths([0, 1, 2, 3]) l = list(w.partial_sums(start=3, mod=4)) return P(l)[:-1] @@ -1620,6 +1627,7 @@ def _s_adic_iterator(self, sequence, letters): - Sébastien Labbé (2009-12-18): initial version """ from itertools import tee + sequence_it, sequence = tee(sequence) m = next(sequence_it) codomain = m.codomain() @@ -1628,9 +1636,9 @@ def _s_adic_iterator(self, sequence, letters): precedent_letter = m(next(letters_it))[0] yield precedent_letter - for (i, (m, a)) in enumerate(zip(sequence, letters)): + for i, (m, a) in enumerate(zip(sequence, letters)): if not precedent_letter == m(a)[0]: - raise ValueError("the hypothesis of the algorithm used is not satisfied; the image of the %s-th letter (=%s) under the %s-th morphism (=%s) should start with the %s-th letter (=%s)" % (i+1, a, i+1, m, i, precedent_letter)) + raise ValueError("the hypothesis of the algorithm used is not satisfied; the image of the %s-th letter (=%s) under the %s-th morphism (=%s) should start with the %s-th letter (=%s)" % (i + 1, a, i + 1, m, i, precedent_letter)) w = p(m(a)[1:]) yield from w p = p * m @@ -1879,12 +1887,14 @@ def s_adic(self, sequence, letters, morphisms=None): raise TypeError("morphisms (=%s) must be None, callable or provide a __getitem__ method" % morphisms) from sage.combinat.words.word import FiniteWord_class - if isinstance(sequence, (tuple, list, str, FiniteWord_class)) \ - and hasattr(letters, "__len__") and len(letters) == 1: + + if isinstance(sequence, (tuple, list, str, FiniteWord_class)) and hasattr(letters, "__len__") and len(letters) == 1: from sage.misc.misc_c import prod + return prod(seq)(letters) from itertools import tee + seq_it, seq = tee(seq) m = next(seq_it) W = m.codomain() @@ -1949,11 +1959,11 @@ def PalindromicDefectWord(self, k=1, alphabet='ab'): sage: words.PalindromicDefectWord(-3) word: aaaaaa """ - kk = k-1 + kk = k - 1 a, b = alphabet if not (isinstance(a, str) and isinstance(b, str)): a, b = (a,), (b,) - w = a + b*k + a + b*kk + a + a + b*kk + a + b*k + a + w = a + b * k + a + b * kk + a + a + b * kk + a + b * k + a return FiniteWords(alphabet)(w) def BaumSweetWord(self): diff --git a/src/sage/combinat/words/word_infinite_datatypes.py b/src/sage/combinat/words/word_infinite_datatypes.py index b5f74f87b80..94b43698546 100644 --- a/src/sage/combinat/words/word_infinite_datatypes.py +++ b/src/sage/combinat/words/word_infinite_datatypes.py @@ -1,6 +1,7 @@ r""" Datatypes for words defined by iterators and callables """ + # **************************************************************************** # Copyright (C) 2009 Franco Saliola # Vincent Delecroix <20100.delecroix@gmail.com> @@ -22,6 +23,7 @@ class WordDatatype_callable(WordDatatype): r""" Datatype for a word defined by a callable. """ + def __init__(self, parent, callable, length=None): r""" INPUT: @@ -237,21 +239,19 @@ def __getitem__(self, key): if isinstance(key, slice): # Infinite words if self._len is Infinity or self._len is None: - if key.start is not None and key.start < 0 or \ - key.stop is not None and key.stop < 0: + if key.start is not None and key.start < 0 or key.stop is not None and key.stop < 0: raise ValueError("for infinite words, start and stop values cannot be negative") step = 1 if key.step is None else key.step if step > 0: start = 0 if key.start is None else key.start - length = self._len if key.stop is None else \ - int(max(0, ceil((key.stop-start)/float(step)))) + length = self._len if key.stop is None else int(max(0, ceil((key.stop - start) / float(step)))) else: if key.start is None or key.start < 0: raise ValueError("start value must be nonnegative for negative step values") start = key.start stop = 0 if key.stop is None else key.stop - length = int(max(0, ceil((key.stop-start)/float(step)))) - fcn = lambda x: self._func(start + x*step) + length = int(max(0, ceil((key.stop - start) / float(step)))) + fcn = lambda x: self._func(start + x * step) if length is None: return self._parent(fcn, length=length) if length is Infinity: @@ -259,17 +259,15 @@ def __getitem__(self, key): return self._parent.factors()(fcn, length=length) # Finite words ## For testing: expand as a list and slice it - #return self._parent(map(self._func, range(self._len))[key]) + # return self._parent(map(self._func, range(self._len))[key]) step = 1 if key.step is None else key.step if step > 0: - start, stop, step = slice(key.start, key.stop, - step).indices(self._len) - length = int((stop-start)/float(step)) + start, stop, step = slice(key.start, key.stop, step).indices(self._len) + length = int((stop - start) / float(step)) else: - start, stop, step = slice(key.start, key.stop, - step).indices(self._len) - length = int(max(0, ceil((stop-start)/float(step)))) - fcn = lambda x: self._func(start + x*step) + start, stop, step = slice(key.start, key.stop, step).indices(self._len) + length = int(max(0, ceil((stop - start) / float(step)))) + fcn = lambda x: self._func(start + x * step) return self._parent(fcn, length=length) if key < 0: if self._len is Infinity: @@ -297,6 +295,7 @@ def __reduce__(self): (...sage.misc.fpickle......, 8, 'pickled_function', False)) """ from sage.misc.fpickle import pickle_function + try: s = pickle_function(self._func) except Exception: @@ -313,6 +312,7 @@ class WordDatatype_callable_with_caching(WordDatatype_callable): r""" Datatype for a word defined by a callable. """ + def __init__(self, parent, callable, length=None): r""" INPUT: @@ -513,8 +513,7 @@ def __getitem__(self, key): if isinstance(key, slice): return super().__getitem__(key) if key not in self._letter_cache: - self._letter_cache[key] = \ - super().__getitem__(key) + self._letter_cache[key] = super().__getitem__(key) return self._letter_cache[key] def __reduce__(self): @@ -541,6 +540,7 @@ def __reduce__(self): (Finite words over Set of Python objects of class 'object', ([0, 1, 2, 3, 4, 'a', 'b', 'c', 'd', 'e'],)) """ from sage.misc.fpickle import pickle_function + try: s = pickle_function(self._func) except Exception: @@ -824,8 +824,7 @@ def __getitem__(self, key): """ if isinstance(key, slice): if self._len is Infinity or self._len is None: - if key.start is not None and key.start < 0 or \ - key.stop is not None and key.stop < 0: + if key.start is not None and key.start < 0 or key.stop is not None and key.stop < 0: raise ValueError("for infinite words, start and stop values cannot be negative") step = 1 if key.step is None else int(key.step) if step >= 0: @@ -834,7 +833,7 @@ def __getitem__(self, key): length = Infinity stop = None else: # key.stop > 0 - length = int(max(0, ceil((key.stop-start)/float(step)))) + length = int(max(0, ceil((key.stop - start) / float(step)))) stop = int(key.stop) data = itertools.islice(self, start, stop, step) else: @@ -842,8 +841,8 @@ def __getitem__(self, key): raise ValueError("start value must be nonnegative for negative step values") start = int(key.start) stop = 0 if key.stop is None else int(key.stop) - length = int(max(0, ceil((stop-start)/float(step)))) - data = list(itertools.islice(self, start+1))[key] + length = int(max(0, ceil((stop - start) / float(step)))) + data = list(itertools.islice(self, start + 1))[key] if length is None or length is Infinity: return self._parent(data) @@ -861,11 +860,11 @@ def __getitem__(self, key): if key.start is None: data = list(self)[key] else: - data = list(itertools.islice(self, int(start+1)))[start:stop:step] + data = list(itertools.islice(self, int(start + 1)))[start:stop:step] length = None - else: # start >= 0, step >= 1, stop >= 0 or None + else: # start >= 0, step >= 1, stop >= 0 or None data = itertools.islice(self, start, stop, step) - length = "unknown" if stop is None else int(max(0, ((stop-start)/float(step)))) + length = "unknown" if stop is None else int(max(0, ((stop - start) / float(step)))) return self._parent.factors()(data, length=length) if key < 0: diff --git a/src/sage/combinat/words/word_options.py b/src/sage/combinat/words/word_options.py index f4ad56c9fe9..a98da080721 100644 --- a/src/sage/combinat/words/word_options.py +++ b/src/sage/combinat/words/word_options.py @@ -1,6 +1,7 @@ r""" User-customizable options for words """ + # **************************************************************************** # Copyright (C) 2009 Franco Saliola # @@ -13,13 +14,7 @@ import copy from sage.rings.integer import Integer -word_options = {'identifier': 'word: ', - 'display': 'string', - 'truncate': True, - 'truncate_length': 40, - 'letter_separator': ',', - 'cache': True, - 'old_repr': False} +word_options = {'identifier': 'word: ', 'display': 'string', 'truncate': True, 'truncate_length': 40, 'letter_separator': ',', 'cache': True, 'old_repr': False} def WordOptions(**kwargs): diff --git a/src/sage/combinat/words/words.py b/src/sage/combinat/words/words.py index 6c0fb0b6940..204d044042b 100644 --- a/src/sage/combinat/words/words.py +++ b/src/sage/combinat/words/words.py @@ -26,6 +26,7 @@ sage: InfiniteWords('natural numbers') Infinite words over Non negative integers """ + # **************************************************************************** # Copyright (C) 2008 Arnaud Bergeron , # Sébastien Labbé , @@ -90,10 +91,7 @@ def Words(alphabet=None, length=None, finite=True, infinite=True): sage: Words('natural numbers') Finite and infinite words over Non negative integers """ - if isinstance(alphabet, (FiniteWords, - InfiniteWords, - FiniteOrInfiniteWords, - Words_n)): + if isinstance(alphabet, (FiniteWords, InfiniteWords, FiniteOrInfiniteWords, Words_n)): return alphabet if length is None: @@ -120,6 +118,7 @@ class AbstractLanguage(Parent): simply disappear or become a common base class for all languages. In the latter case, its name would possibly change to ``Language``. """ + def __init__(self, alphabet=None, category=None): r""" INPUT: @@ -140,10 +139,9 @@ def __init__(self, alphabet=None, category=None): """ if isinstance(alphabet, (int, Integer)): from sage.sets.integer_range import IntegerRange + alphabet = IntegerRange(1, alphabet + 1) - elif (alphabet == "integers" or - alphabet == "positive integers" or - alphabet == "natural numbers"): + elif alphabet == "integers" or alphabet == "positive integers" or alphabet == "natural numbers": alphabet = build_alphabet(name=alphabet) else: alphabet = build_alphabet(alphabet) @@ -159,8 +157,7 @@ def __init__(self, alphabet=None, category=None): self.sortkey_letters = self._sortkey_trivial elif N < 36: try: - if all(alphabet.unrank(i) > alphabet.unrank(j) - for i in range(N) for j in range(i)): + if all(alphabet.unrank(i) > alphabet.unrank(j) for i in range(N) for j in range(i)): self.sortkey_letters = self._sortkey_trivial except TypeError: pass @@ -218,6 +215,7 @@ def identity_morphism(self): if self.alphabet().cardinality() not in ZZ: raise NotImplementedError('size of alphabet must be finite') from sage.combinat.words.morphism import WordMorphism + return WordMorphism({a: a for a in self.alphabet()}) def _check(self, w, length=40): @@ -305,8 +303,7 @@ def __eq__(self, other) -> bool: sage: FiniteWords([0,1]) == FiniteWords([0,1,2,3]) False """ - return self is other or (type(self) is type(other) and - self.alphabet() == other.alphabet()) + return self is other or (type(self) is type(other) and self.alphabet() == other.alphabet()) def __ne__(self, other) -> bool: r""" @@ -464,23 +461,14 @@ def _element_classes(self): True """ from sage.combinat.words import word - classes = { - 'list': word.FiniteWord_list, - 'str': word.FiniteWord_str, - 'tuple': word.FiniteWord_tuple, - 'callable_with_caching': word.FiniteWord_callable_with_caching, - 'callable': word.FiniteWord_callable, - 'iter_with_caching': word.FiniteWord_iter_with_caching, - 'iter': word.FiniteWord_iter} + + classes = {'list': word.FiniteWord_list, 'str': word.FiniteWord_str, 'tuple': word.FiniteWord_tuple, 'callable_with_caching': word.FiniteWord_callable_with_caching, 'callable': word.FiniteWord_callable, 'iter_with_caching': word.FiniteWord_iter_with_caching, 'iter': word.FiniteWord_iter} # test whether or not we can use the class Finiteword_char - if (self.alphabet().cardinality() <= 256 and - all(isinstance(i, (int, Integer)) and - 0 <= i < 256 for i in self.alphabet())): + if self.alphabet().cardinality() <= 256 and all(isinstance(i, (int, Integer)) and 0 <= i < 256 for i in self.alphabet()): L = self.alphabet().list() key = self.sortkey_letters - if (all(L[i] < L[i + 1] for i in range(len(L) - 1)) and - all(key(L[i]) < key(L[i + 1]) for i in range(len(L) - 1))): + if all(L[i] < L[i + 1] for i in range(len(L) - 1)) and all(key(L[i]) < key(L[i + 1]) for i in range(len(L) - 1)): classes['char'] = word.FiniteWord_char return classes @@ -519,15 +507,15 @@ def _word_from_word(self, data): # are needed ########################### from sage.combinat.words.word_char import WordDatatype_char + if isinstance(data, WordDatatype_char): data = list(data) if 'char' in self._element_classes: return self._element_classes['char'](self, data) return self._element_classes['list'](self, data) - from sage.combinat.words.word_datatypes import (WordDatatype_str, - WordDatatype_list, - WordDatatype_tuple) + from sage.combinat.words.word_datatypes import WordDatatype_str, WordDatatype_list, WordDatatype_tuple + if isinstance(data, WordDatatype_str): return self._element_classes['str'](self, data._data) if isinstance(data, WordDatatype_tuple): @@ -535,8 +523,8 @@ def _word_from_word(self, data): if isinstance(data, WordDatatype_list): return self._element_classes['list'](self, data._data) - from sage.combinat.words.word_infinite_datatypes import \ - (WordDatatype_callable, WordDatatype_iter) + from sage.combinat.words.word_infinite_datatypes import WordDatatype_callable, WordDatatype_iter + if isinstance(data, WordDatatype_callable): length = data.length() data = data._func @@ -851,6 +839,7 @@ def __call__(self, data=None, length=None, datatype=None, caching=True, check=Tr w = self._word_from_iter(data, length, caching) elif datatype == 'pickled_function': from sage.misc.fpickle import unpickle_function + data = unpickle_function(data) w = self._word_from_callable(data, length, caching) else: @@ -885,6 +874,7 @@ def __call__(self, data=None, length=None, datatype=None, caching=True, check=Tr elif isinstance(data, Iterable): from sage.combinat.words.abstract_word import Word_class + if isinstance(data, Word_class): w = self._word_from_word(data) else: @@ -1048,6 +1038,7 @@ def __contains__(self, x) -> bool: False """ from sage.combinat.words.finite_word import FiniteWord_class + return isinstance(x, FiniteWord_class) and x.parent().alphabet() == self.alphabet() def random_element(self, length=None, *args, **kwds): @@ -1080,8 +1071,7 @@ def random_element(self, length=None, *args, **kwds): """ if length is None: length = ZZ.random_element(0, 10) - return self([self.alphabet().random_element(*args, **kwds) - for x in range(length)]) + return self([self.alphabet().random_element(*args, **kwds) for x in range(length)]) def iter_morphisms(self, arg=None, codomain=None, min_length=1): r""" @@ -1281,18 +1271,17 @@ def iter_morphisms(self, arg=None, codomain=None, min_length=1): # None, or [arg] otherwise) if arg is None: from sage.combinat.integer_lists.nn import IntegerListsNN + compositions = IntegerListsNN(length=n, min_part=min_length) elif isinstance(arg, tuple): from sage.combinat.integer_lists import IntegerListsLex + a, b = arg - compositions = IntegerListsLex(min_sum=a, max_sum=b - 1, - length=n, min_part=min_length) + compositions = IntegerListsLex(min_sum=a, max_sum=b - 1, length=n, min_part=min_length) else: arg = list(arg) - if (not len(arg) == n or not - all(isinstance(a, (int, Integer)) for a in arg)): - raise TypeError( - "arg (=%s) must be an iterable of %s integers" % (arg, n)) + if not len(arg) == n or not all(isinstance(a, (int, Integer)) for a in arg): + raise TypeError("arg (=%s) must be an iterable of %s integers" % (arg, n)) compositions = [arg] # set the codomain @@ -1305,6 +1294,7 @@ def iter_morphisms(self, arg=None, codomain=None, min_length=1): # iterate through the morphisms from sage.combinat.words.morphism import WordMorphism + for composition in compositions: cuts = [0] + list(composition) for i in range(1, len(cuts)): @@ -1314,7 +1304,7 @@ def iter_morphisms(self, arg=None, codomain=None, min_length=1): d = {} i = 0 for a in self.alphabet(): - d[a] = big_word[cuts[i]:cuts[i + 1]] + d[a] = big_word[cuts[i] : cuts[i + 1]] i += 1 yield WordMorphism(d, codomain=codomain) @@ -1407,11 +1397,8 @@ def _element_classes(self): True """ from sage.combinat.words import word - return { - 'callable_with_caching': word.InfiniteWord_callable_with_caching, - 'callable': word.InfiniteWord_callable, - 'iter_with_caching': word.InfiniteWord_iter_with_caching, - 'iter': word.InfiniteWord_iter} + + return {'callable_with_caching': word.InfiniteWord_callable_with_caching, 'callable': word.InfiniteWord_callable, 'iter_with_caching': word.InfiniteWord_iter_with_caching, 'iter': word.InfiniteWord_iter} def random_element(self, *args, **kwds): r""" @@ -1429,6 +1416,7 @@ def random_element(self, *args, **kwds): """ rd = self.alphabet().random_element from itertools import count + return self._word_from_iter(rd(*args, **kwds) for i in count()) def _word_from_word(self, data): @@ -1466,8 +1454,8 @@ def _word_from_word(self, data): # Otherwise, if self is not the parent of `data`, then we try to # recover the data, the length and the datatype of the input `data` ########################### - from sage.combinat.words.word_infinite_datatypes import (WordDatatype_callable, - WordDatatype_iter) + from sage.combinat.words.word_infinite_datatypes import WordDatatype_callable, WordDatatype_iter + if isinstance(data, WordDatatype_callable): data = data._func return self._word_from_callable(data, caching=False) @@ -1605,6 +1593,7 @@ def __call__(self, data=None, datatype=None, caching=True, check=True): w = self._word_from_iter(data, caching) elif datatype == 'pickled_function': from sage.misc.fpickle import unpickle_function + data = unpickle_function(data) w = self._word_from_callable(data, caching) else: @@ -1615,6 +1604,7 @@ def __call__(self, data=None, datatype=None, caching=True, check=True): elif isinstance(data, Iterable): from sage.combinat.words.abstract_word import Word_class + if isinstance(data, Word_class): w = self._word_from_word(data) else: @@ -1662,6 +1652,7 @@ def _an_element_(self): some_letters = list(self.alphabet().some_elements()) if len(some_letters) > 1: from sage.combinat.words.word_generators import words + letters = some_letters[:2] return self(words.ThueMorseWord(alphabet=letters)) letter = some_letters[0] @@ -1724,8 +1715,8 @@ def _element_classes(self): 'iter_with_caching': } """ from sage.combinat.words import word - return {'iter_with_caching': word.Word_iter_with_caching, - 'iter': word.Word_iter} + + return {'iter_with_caching': word.Word_iter_with_caching, 'iter': word.Word_iter} def __hash__(self): r""" @@ -1793,8 +1784,7 @@ def _word_from_word(self, data): Infinite words over {'a', 'b'} """ P = data.parent() - if P is self or P is self.finite_words() or P is self.infinite_words() or \ - P == self or P == self.finite_words() or P == self.infinite_words(): + if P is self or P is self.finite_words() or P is self.infinite_words() or P == self or P == self.finite_words() or P == self.infinite_words(): return data if data.is_finite(): return self.finite_words()._word_from_word(data) @@ -2094,6 +2084,7 @@ def __call__(self, data=None, length=None, datatype=None, caching=True, check=Tr if length == 'unknown' or length is None: from sage.combinat.words.abstract_word import Word_class + if isinstance(data, Word_class): w = self._word_from_word(data) elif isinstance(data, Iterable): @@ -2123,6 +2114,7 @@ class Words_n(Parent): r""" The set of words of fixed length on a given alphabet. """ + def __init__(self, words, n): r""" INPUT: @@ -2284,6 +2276,7 @@ def _repr_(self): Words of length 5 over {1, 2, 3} """ from sage.combinat.words.word_options import word_options + if word_options['old_repr']: return "Words over {} of length {}".format(self.alphabet(), self._n) return "Words of length {} over {}".format(self._n, self.alphabet()) diff --git a/src/sage/combinat/yang_baxter_graph.py b/src/sage/combinat/yang_baxter_graph.py index afafad0237a..dfe4b3c3302 100644 --- a/src/sage/combinat/yang_baxter_graph.py +++ b/src/sage/combinat/yang_baxter_graph.py @@ -1,6 +1,7 @@ r""" Yang-Baxter Graphs """ + # **************************************************************************** # Copyright (C) 2009 Franco Saliola # @@ -111,6 +112,7 @@ def YangBaxterGraph(partition=None, root=None, operators=None): return YangBaxterGraph_generic(root=root, operators=operators) return YangBaxterGraph_partition(partition=Partition(partition)) + # *********** General class for Yang-Baxter Graphs *********** @@ -546,6 +548,7 @@ def relabel_edges(self, edge_dict, inplace=True): # *********** Yang-Baxter Graphs defined by a partition *********** + class YangBaxterGraph_partition(YangBaxterGraph_generic): def __init__(self, partition): r""" @@ -576,8 +579,7 @@ def __init__(self, partition): self._partition = partition beta = sorted(self._partition, reverse=True) root = sum((tuple(range(b)) for b in beta), ())[::-1] - operators = [SwapIncreasingOperator(i) - for i in range(sum(partition) - 1)] + operators = [SwapIncreasingOperator(i) for i in range(sum(partition) - 1)] super().__init__(root, operators) def __repr__(self) -> str: @@ -750,6 +752,7 @@ def relabel_vertices(self, v, inplace=True): Y._root = relabelling[Y._root] return Y._digraph.relabel(relabelling, inplace=inplace) + # ------------- Some Yang-Baxter operators ------------------ @@ -856,8 +859,8 @@ def __call__(self, u): """ i = self._position if isinstance(u, Permutation): - return Permutation(u[:i] + u[i:i + 2][::-1] + u[i + 2:]) - return type(u)(u[:i] + u[i:i + 2][::-1] + u[i + 2:]) + return Permutation(u[:i] + u[i : i + 2][::-1] + u[i + 2 :]) + return type(u)(u[:i] + u[i : i + 2][::-1] + u[i + 2 :]) def position(self): r""" diff --git a/src/sage/config_test.py b/src/sage/config_test.py index 6b2512c5ba8..30f3d15fe98 100644 --- a/src/sage/config_test.py +++ b/src/sage/config_test.py @@ -3,9 +3,7 @@ def test_cython_metaclass_header_found(): dirs = get_include_dirs() - assert any( - (dir / "sage" / "cpython" / "cython_metaclass.h").is_file() for dir in dirs - ) + assert any((dir / "sage" / "cpython" / "cython_metaclass.h").is_file() for dir in dirs) def test_get_include_dirs_returns_existing_dirs(): diff --git a/src/sage/cpython/__init__.py b/src/sage/cpython/__init__.py index a7b0e210c44..3180e63117c 100644 --- a/src/sage/cpython/__init__.py +++ b/src/sage/cpython/__init__.py @@ -6,6 +6,7 @@ # Monkey-patch ExtensionFileLoader to allow IPython to find the sources # of Cython files. See https://github.com/sagemath/sage/issues/24681 from importlib.machinery import ExtensionFileLoader as _ExtensionFileLoader + if hasattr(_ExtensionFileLoader, 'get_source'): del _ExtensionFileLoader.get_source del _ExtensionFileLoader diff --git a/src/sage/crypto/__init__.py b/src/sage/crypto/__init__.py index 107a9733a62..9ac0f1a4805 100644 --- a/src/sage/crypto/__init__.py +++ b/src/sage/crypto/__init__.py @@ -1,2 +1,3 @@ from sage.misc.lazy_import import lazy_import + lazy_import('sage.crypto.lattice', 'gen_lattice') diff --git a/src/sage/crypto/all.py b/src/sage/crypto/all.py index faaae4c6156..cd9a79c561f 100644 --- a/src/sage/crypto/all.py +++ b/src/sage/crypto/all.py @@ -1,25 +1,38 @@ import sage.crypto.sbox from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.crypto.mq.sbox', 'SBox', sage.crypto.sbox.SBox) from sage.misc.lazy_import import lazy_import -lazy_import('sage.crypto.classical', ['AffineCryptosystem', - 'HillCryptosystem', - 'SubstitutionCryptosystem', - 'ShiftCryptosystem', - 'TranspositionCryptosystem', - 'VigenereCryptosystem', - ]) +lazy_import( + 'sage.crypto.classical', + [ + 'AffineCryptosystem', + 'HillCryptosystem', + 'SubstitutionCryptosystem', + 'ShiftCryptosystem', + 'TranspositionCryptosystem', + 'VigenereCryptosystem', + ], +) -lazy_import('sage.crypto.stream', ['LFSRCryptosystem', - 'ShrinkingGeneratorCryptosystem', - ]) +lazy_import( + 'sage.crypto.stream', + [ + 'LFSRCryptosystem', + 'ShrinkingGeneratorCryptosystem', + ], +) -lazy_import('sage.crypto.lfsr', ['lfsr_sequence', - 'lfsr_autocorrelation', - 'lfsr_connection_polynomial', - ]) +lazy_import( + 'sage.crypto.lfsr', + [ + 'lfsr_sequence', + 'lfsr_autocorrelation', + 'lfsr_connection_polynomial', + ], +) lazy_import('sage.crypto.public_key.key_exchange', 'all', 'key_exchange') diff --git a/src/sage/crypto/block_cipher/des.py b/src/sage/crypto/block_cipher/des.py index 2dc4789460a..1b9c1ca8845 100644 --- a/src/sage/crypto/block_cipher/des.py +++ b/src/sage/crypto/block_cipher/des.py @@ -91,14 +91,7 @@ from itertools import chain -sboxes = [[DES_S1_1, DES_S1_2, DES_S1_3, DES_S1_4], - [DES_S2_1, DES_S2_2, DES_S2_3, DES_S2_4], - [DES_S3_1, DES_S3_2, DES_S3_3, DES_S3_4], - [DES_S4_1, DES_S4_2, DES_S4_3, DES_S4_4], - [DES_S5_1, DES_S5_2, DES_S5_3, DES_S5_4], - [DES_S6_1, DES_S6_2, DES_S6_3, DES_S6_4], - [DES_S7_1, DES_S7_2, DES_S7_3, DES_S7_4], - [DES_S8_1, DES_S8_2, DES_S8_3, DES_S8_4]] +sboxes = [[DES_S1_1, DES_S1_2, DES_S1_3, DES_S1_4], [DES_S2_1, DES_S2_2, DES_S2_3, DES_S2_4], [DES_S3_1, DES_S3_2, DES_S3_3, DES_S3_4], [DES_S4_1, DES_S4_2, DES_S4_3, DES_S4_4], [DES_S5_1, DES_S5_2, DES_S5_3, DES_S5_4], [DES_S6_1, DES_S6_2, DES_S6_3, DES_S6_4], [DES_S7_1, DES_S7_2, DES_S7_3, DES_S7_4], [DES_S8_1, DES_S8_2, DES_S8_3, DES_S8_4]] class DES(SageObject): @@ -391,8 +384,7 @@ def __init__(self, rounds=None, keySchedule='DES_KS', keySize=64, doFinalRound=T self.keySchedule = DES_KS() if keySchedule == 'DES_KS' else keySchedule self._rounds = self.keySchedule._rounds if rounds is None else rounds if self._rounds > self.keySchedule._rounds: - raise ValueError('number of rounds must be less or equal to the ' - 'number of rounds of the key schedule') + raise ValueError('number of rounds must be less or equal to the ' 'number of rounds of the key schedule') self._keySize = keySize if keySize not in (56, 64): raise ValueError('key size must be 56 or 64') @@ -435,8 +427,7 @@ def __call__(self, block, key, algorithm='encrypt'): return self.encrypt(block, key) if algorithm == 'decrypt': return self.decrypt(block, key) - raise ValueError('Algorithm must be \'encrypt\' or \'decrypt\' and' - ' not \'%s\'' % algorithm) + raise ValueError('Algorithm must be \'encrypt\' or \'decrypt\' and' ' not \'%s\'' % algorithm) def __eq__(self, other): r""" @@ -472,8 +463,7 @@ def __repr__(self): DES block cipher with 16 rounds and the following key schedule: Original DES key schedule with 16 rounds """ - return ('DES block cipher with %s rounds and the following key ' - 'schedule:\n%s' % (self._rounds, self.keySchedule.__repr__())) + return 'DES block cipher with %s rounds and the following key ' 'schedule:\n%s' % (self._rounds, self.keySchedule.__repr__()) def encrypt(self, plaintext, key): r""" @@ -525,10 +515,10 @@ def encrypt(self, plaintext, key): key = vector(GF(2), 64, key) roundKeys = self.keySchedule(key) state = self._ip(state) - for k in roundKeys[:self._rounds]: + for k in roundKeys[: self._rounds]: state = self.round(state, k) if self._doFinalRound: - state = vector(GF(2), 64, list(state[32:64])+list(state[0:32])) + state = vector(GF(2), 64, list(state[32:64]) + list(state[0:32])) state = self._inv_ip(state) return state if inputType == 'vector' else ZZ(list(state)[::-1], 2) @@ -582,9 +572,9 @@ def decrypt(self, ciphertext, key): key = vector(GF(2), 64, key) roundKeys = self.keySchedule(key) state = self._ip(state) - for k in roundKeys[:self._rounds][::-1]: + for k in roundKeys[: self._rounds][::-1]: state = self.round(state, k) - state = vector(GF(2), 64, list(state[32:64])+list(state[0:32])) + state = vector(GF(2), 64, list(state[32:64]) + list(state[0:32])) state = self._inv_ip(state) return state if inputType == 'vector' else ZZ(list(state)[::-1], 2) @@ -605,15 +595,8 @@ def _ip(self, block): 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0) """ - IP = [58, 50, 42, 34, 26, 18, 10, 2, - 60, 52, 44, 36, 28, 20, 12, 4, - 62, 54, 46, 38, 30, 22, 14, 6, - 64, 56, 48, 40, 32, 24, 16, 8, - 57, 49, 41, 33, 25, 17, 9, 1, - 59, 51, 43, 35, 27, 19, 11, 3, - 61, 53, 45, 37, 29, 21, 13, 5, - 63, 55, 47, 39, 31, 23, 15, 7] - return vector(GF(2), 64, [block[i-1] for i in IP]) + IP = [58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7] + return vector(GF(2), 64, [block[i - 1] for i in IP]) def round(self, state, round_key): r""" @@ -631,7 +614,7 @@ def round(self, state, round_key): """ L, R = state[0:32], state[32:64] L, R = R, L + self._f(R, round_key) - state = vector(GF(2), 64, list(L)+list(R)) + state = vector(GF(2), 64, list(L) + list(R)) return state def _f(self, right, subkey): @@ -651,7 +634,7 @@ def _f(self, right, subkey): (0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1) """ - return self._permutation(self.sbox_layer(self._expand(right)+subkey)) + return self._permutation(self.sbox_layer(self._expand(right) + subkey)) def _expand(self, right): r""" @@ -668,15 +651,8 @@ def _expand(self, right): 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1) """ - E = [32, 1, 2, 3, 4, 5, - 4, 5, 6, 7, 8, 9, - 8, 9, 10, 11, 12, 13, - 12, 13, 14, 15, 16, 17, - 16, 17, 18, 19, 20, 21, - 20, 21, 22, 23, 24, 25, - 24, 25, 26, 27, 28, 29, - 28, 29, 30, 31, 32, 1] - return vector(GF(2), 48, [right[i-1] for i in E]) + E = [32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1] + return vector(GF(2), 48, [right[i - 1] for i in E]) def sbox_layer(self, block): r""" @@ -698,9 +674,8 @@ def sbox_layer(self, block): :mod:`sage.crypto.sboxes` """ s = self.sboxes - block = [block[i:i+6] for i in range(0, 48, 6)] - block = list(chain.from_iterable([s[i][ZZ([b[5], b[0]], 2)](b[1:5]) - for i, b in enumerate(block)])) + block = [block[i : i + 6] for i in range(0, 48, 6)] + block = list(chain.from_iterable([s[i][ZZ([b[5], b[0]], 2)](b[1:5]) for i, b in enumerate(block)])) return vector(GF(2), 32, block) def _permutation(self, block): @@ -717,15 +692,8 @@ def _permutation(self, block): (0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1) """ - P = [16, 7, 20, 21, - 29, 12, 28, 17, - 1, 15, 23, 26, - 5, 18, 31, 10, - 2, 8, 24, 14, - 32, 27, 3, 9, - 19, 13, 30, 6, - 22, 11, 4, 25] - return vector(GF(2), 32, [block[i-1] for i in P]) + P = [16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25] + return vector(GF(2), 32, [block[i - 1] for i in P]) def _inv_ip(self, block): r""" @@ -744,15 +712,8 @@ def _inv_ip(self, block): 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1) """ - invIP = [40, 8, 48, 16, 56, 24, 64, 32, - 39, 7, 47, 15, 55, 23, 63, 31, - 38, 6, 46, 14, 54, 22, 62, 30, - 37, 5, 45, 13, 53, 21, 61, 29, - 36, 4, 44, 12, 52, 20, 60, 28, - 35, 3, 43, 11, 51, 19, 59, 27, - 34, 2, 42, 10, 50, 18, 58, 26, - 33, 1, 41, 9, 49, 17, 57, 25] - return vector(GF(2), 64, [block[i-1] for i in invIP]) + invIP = [40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25] + return vector(GF(2), 64, [block[i - 1] for i in invIP]) class DES_KS(SageObject): @@ -877,9 +838,8 @@ def __call__(self, key): C, D = self._pc1(key) for i in range(16): C, D = self._left_shift(C, i), self._left_shift(D, i) - roundKeys.append(self._pc2(list(C)+list(D))) - return roundKeys if inputType == 'vector' else [ZZ(list(k)[::-1], 2) - for k in roundKeys] + roundKeys.append(self._pc2(list(C) + list(D))) + return roundKeys if inputType == 'vector' else [ZZ(list(k)[::-1], 2) for k in roundKeys] def __eq__(self, other): r""" @@ -909,7 +869,7 @@ def __repr__(self): sage: DES_KS() # indirect doctest Original DES key schedule with 16 rounds """ - return ('Original DES key schedule with %s rounds' % (self._rounds)) + return 'Original DES key schedule with %s rounds' % (self._rounds) def __getitem__(self, r): r""" @@ -971,16 +931,10 @@ def _pc1(self, key): (0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1) """ - PC1_C = [57, 49, 41, 33, 25, 17, 9, - 1, 58, 50, 42, 34, 26, 18, - 10, 2, 59, 51, 43, 35, 27, - 19, 11, 3, 60, 52, 44, 36] - PC1_D = [63, 55, 47, 39, 31, 23, 15, - 7, 62, 54, 46, 38, 30, 22, - 14, 6, 61, 53, 45, 37, 29, - 21, 13, 5, 28, 20, 12, 4] - C = vector(GF(2), 28, [key[i-1] for i in PC1_C]) - D = vector(GF(2), 28, [key[i-1] for i in PC1_D]) + PC1_C = [57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36] + PC1_D = [63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4] + C = vector(GF(2), 28, [key[i - 1] for i in PC1_C]) + D = vector(GF(2), 28, [key[i - 1] for i in PC1_D]) return C, D def _pc2(self, key): @@ -999,15 +953,8 @@ def _pc2(self, key): 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0) """ - PC2 = [14, 17, 11, 24, 1, 5, - 3, 28, 15, 6, 21, 10, - 23, 19, 12, 4, 26, 8, - 16, 7, 27, 20, 13, 2, - 41, 52, 31, 37, 47, 55, - 30, 40, 51, 45, 33, 48, - 44, 49, 39, 56, 34, 53, - 46, 42, 50, 36, 29, 32] - return vector(GF(2), 48, [key[i-1] for i in PC2]) + PC2 = [14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32] + return vector(GF(2), 48, [key[i - 1] for i in PC2]) def _left_shift(self, half, i): r""" @@ -1027,8 +974,7 @@ def _left_shift(self, half, i): (1, 0, 1, 0, 1, 0) """ amount = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1] - return vector(GF(2), - list(half[amount[i]:]) + list(half[0:amount[i]])) + return vector(GF(2), list(half[amount[i] :]) + list(half[0 : amount[i]])) def convert_to_vector(I, L): @@ -1058,5 +1004,5 @@ def convert_to_vector(I, L): except TypeError: # ignore the error and try list-like types pass - state = vector(GF(2), L, [0]*(L-len(I))+list(I)) + state = vector(GF(2), L, [0] * (L - len(I)) + list(I)) return state diff --git a/src/sage/crypto/block_cipher/miniaes.py b/src/sage/crypto/block_cipher/miniaes.py index caeaea9996b..47845b781c9 100644 --- a/src/sage/crypto/block_cipher/miniaes.py +++ b/src/sage/crypto/block_cipher/miniaes.py @@ -149,6 +149,7 @@ def __init__(self): True """ from sage.crypto.sbox import SBox + self._key_size = 16 # the number of bits in a secret key B = BinaryStrings() K = FiniteField(self._key_size, "x") @@ -157,107 +158,17 @@ def __init__(self): # the S-box for decryption self._sboxD = SBox(14, 3, 4, 8, 1, 12, 10, 15, 7, 13, 9, 6, 11, 2, 0, 5) # nibble to finite field element - self._bin_to_GF = { B("0000"): K("0"), - B("0001"): K("1"), - B("0010"): K("x"), - B("0011"): K("x + 1"), - B("0100"): K("x^2"), - B("0101"): K("x^2 + 1"), - B("0110"): K("x^2 + x"), - B("0111"): K("x^2 + x + 1"), - B("1000"): K("x^3"), - B("1001"): K("x^3 + 1"), - B("1010"): K("x^3 + x"), - B("1011"): K("x^3 + x + 1"), - B("1100"): K("x^3 + x^2"), - B("1101"): K("x^3 + x^2 + 1"), - B("1110"): K("x^3 + x^2 + x"), - B("1111"): K("x^3 + x^2 + x+ 1") } + self._bin_to_GF = {B("0000"): K("0"), B("0001"): K("1"), B("0010"): K("x"), B("0011"): K("x + 1"), B("0100"): K("x^2"), B("0101"): K("x^2 + 1"), B("0110"): K("x^2 + x"), B("0111"): K("x^2 + x + 1"), B("1000"): K("x^3"), B("1001"): K("x^3 + 1"), B("1010"): K("x^3 + x"), B("1011"): K("x^3 + x + 1"), B("1100"): K("x^3 + x^2"), B("1101"): K("x^3 + x^2 + 1"), B("1110"): K("x^3 + x^2 + x"), B("1111"): K("x^3 + x^2 + x+ 1")} # nibble to integer - self._bin_to_int = { B("0000"): Integer(0), - B("0001"): Integer(1), - B("0010"): Integer(2), - B("0011"): Integer(3), - B("0100"): Integer(4), - B("0101"): Integer(5), - B("0110"): Integer(6), - B("0111"): Integer(7), - B("1000"): Integer(8), - B("1001"): Integer(9), - B("1010"): Integer(10), - B("1011"): Integer(11), - B("1100"): Integer(12), - B("1101"): Integer(13), - B("1110"): Integer(14), - B("1111"): Integer(15) } + self._bin_to_int = {B("0000"): Integer(0), B("0001"): Integer(1), B("0010"): Integer(2), B("0011"): Integer(3), B("0100"): Integer(4), B("0101"): Integer(5), B("0110"): Integer(6), B("0111"): Integer(7), B("1000"): Integer(8), B("1001"): Integer(9), B("1010"): Integer(10), B("1011"): Integer(11), B("1100"): Integer(12), B("1101"): Integer(13), B("1110"): Integer(14), B("1111"): Integer(15)} # finite field element to nibble - self._GF_to_bin = { K("0"): B("0000"), - K("1"): B("0001"), - K("x"): B("0010"), - K("x + 1"): B("0011"), - K("x^2"): B("0100"), - K("x^2 + 1"): B("0101"), - K("x^2 + x"): B("0110"), - K("x^2 + x + 1"): B("0111"), - K("x^3"): B("1000"), - K("x^3 + 1"): B("1001"), - K("x^3 + x"): B("1010"), - K("x^3 + x + 1"): B("1011"), - K("x^3 + x^2"): B("1100"), - K("x^3 + x^2 + 1"): B("1101"), - K("x^3 + x^2 + x"): B("1110"), - K("x^3 + x^2 + x+ 1"): B("1111") } + self._GF_to_bin = {K("0"): B("0000"), K("1"): B("0001"), K("x"): B("0010"), K("x + 1"): B("0011"), K("x^2"): B("0100"), K("x^2 + 1"): B("0101"), K("x^2 + x"): B("0110"), K("x^2 + x + 1"): B("0111"), K("x^3"): B("1000"), K("x^3 + 1"): B("1001"), K("x^3 + x"): B("1010"), K("x^3 + x + 1"): B("1011"), K("x^3 + x^2"): B("1100"), K("x^3 + x^2 + 1"): B("1101"), K("x^3 + x^2 + x"): B("1110"), K("x^3 + x^2 + x+ 1"): B("1111")} # finite field element to integer - self._GF_to_int = { K("0"): Integer(0), - K("1"): Integer(1), - K("x"): Integer(2), - K("x + 1"): Integer(3), - K("x^2"): Integer(4), - K("x^2 + 1"): Integer(5), - K("x^2 + x"): Integer(6), - K("x^2 + x + 1"): Integer(7), - K("x^3"): Integer(8), - K("x^3 + 1"): Integer(9), - K("x^3 + x"): Integer(10), - K("x^3 + x + 1"): Integer(11), - K("x^3 + x^2"): Integer(12), - K("x^3 + x^2 + 1"): Integer(13), - K("x^3 + x^2 + x"): Integer(14), - K("x^3 + x^2 + x+ 1"): Integer(15) } + self._GF_to_int = {K("0"): Integer(0), K("1"): Integer(1), K("x"): Integer(2), K("x + 1"): Integer(3), K("x^2"): Integer(4), K("x^2 + 1"): Integer(5), K("x^2 + x"): Integer(6), K("x^2 + x + 1"): Integer(7), K("x^3"): Integer(8), K("x^3 + 1"): Integer(9), K("x^3 + x"): Integer(10), K("x^3 + x + 1"): Integer(11), K("x^3 + x^2"): Integer(12), K("x^3 + x^2 + 1"): Integer(13), K("x^3 + x^2 + x"): Integer(14), K("x^3 + x^2 + x+ 1"): Integer(15)} # integer to nibble - self._int_to_bin = { Integer(0): B("0000"), - Integer(1): B("0001"), - Integer(2): B("0010"), - Integer(3): B("0011"), - Integer(4): B("0100"), - Integer(5): B("0101"), - Integer(6): B("0110"), - Integer(7): B("0111"), - Integer(8): B("1000"), - Integer(9): B("1001"), - Integer(10): B("1010"), - Integer(11): B("1011"), - Integer(12): B("1100"), - Integer(13): B("1101"), - Integer(14): B("1110"), - Integer(15): B("1111") } + self._int_to_bin = {Integer(0): B("0000"), Integer(1): B("0001"), Integer(2): B("0010"), Integer(3): B("0011"), Integer(4): B("0100"), Integer(5): B("0101"), Integer(6): B("0110"), Integer(7): B("0111"), Integer(8): B("1000"), Integer(9): B("1001"), Integer(10): B("1010"), Integer(11): B("1011"), Integer(12): B("1100"), Integer(13): B("1101"), Integer(14): B("1110"), Integer(15): B("1111")} # integer to finite field element - self._int_to_GF = { Integer(0): K("0"), - Integer(1): K("1"), - Integer(2): K("x"), - Integer(3): K("x + 1"), - Integer(4): K("x^2"), - Integer(5): K("x^2 + 1"), - Integer(6): K("x^2 + x"), - Integer(7): K("x^2 + x + 1"), - Integer(8): K("x^3"), - Integer(9): K("x^3 + 1"), - Integer(10): K("x^3 + x"), - Integer(11): K("x^3 + x + 1"), - Integer(12): K("x^3 + x^2"), - Integer(13): K("x^3 + x^2 + 1"), - Integer(14): K("x^3 + x^2 + x"), - Integer(15): K("x^3 + x^2 + x+ 1") } + self._int_to_GF = {Integer(0): K("0"), Integer(1): K("1"), Integer(2): K("x"), Integer(3): K("x + 1"), Integer(4): K("x^2"), Integer(5): K("x^2 + 1"), Integer(6): K("x^2 + x"), Integer(7): K("x^2 + x + 1"), Integer(8): K("x^3"), Integer(9): K("x^3 + 1"), Integer(10): K("x^3 + x"), Integer(11): K("x^3 + x + 1"), Integer(12): K("x^3 + x^2"), Integer(13): K("x^3 + x^2 + 1"), Integer(14): K("x^3 + x^2 + x"), Integer(15): K("x^3 + x^2 + x+ 1")} def __call__(self, B, key, algorithm='encrypt'): r""" @@ -349,6 +260,7 @@ def __call__(self, B, key, algorithm='encrypt'): ValueError: algorithm must be either 'encrypt' or 'decrypt' """ from sage.rings.finite_rings.integer_mod import Mod + if not isinstance(B, StringMonoidElement): raise TypeError("input B must be a non-empty binary string with number of bits a multiple of 16") if (len(B) == 0) or (Mod(len(B), self._key_size).lift() != 0): @@ -366,7 +278,7 @@ def __call__(self, B, key, algorithm='encrypt'): # encrypt each 16-bit block in succession for i in range(N): # here 16 is the number of bits per encryption block - block = B[i*16 : (i+1)*16] + block = B[i * 16 : (i + 1) * 16] matB = MS(self.binary_to_GF(block)) matK = MS(self.binary_to_GF(key)) e = self.encrypt(matB, matK) @@ -377,7 +289,7 @@ def __call__(self, B, key, algorithm='encrypt'): # decrypt each 16-bit block in succession for i in range(N): # here 16 is the number of bits per encryption block - block = B[i*16 : (i+1)*16] + block = B[i * 16 : (i + 1) * 16] matB = MS(self.binary_to_GF(block)) matK = MS(self.binary_to_GF(key)) e = self.decrypt(matB, matK) @@ -400,9 +312,7 @@ def __eq__(self, other): sage: m == loads(dumps(m)) True """ - return ( (self._key_size == other._key_size) and - (self._sboxE == other._sboxE) and - (self._sboxD == other._sboxD) ) + return (self._key_size == other._key_size) and (self._sboxE == other._sboxE) and (self._sboxD == other._sboxD) def __repr__(self): r""" @@ -529,14 +439,12 @@ def add_key(self, block, rkey): ... TypeError: round key must be a 2 x 2 matrix over GF(16) """ - if not isinstance(block, Matrix_dense) or \ - not (block.base_ring().order() == 16 and block.base_ring().is_field()): + if not isinstance(block, Matrix_dense) or not (block.base_ring().order() == 16 and block.base_ring().is_field()): raise TypeError("input block must be a 2 x 2 matrix over GF(16)") if not (block.nrows() == block.ncols() == 2): raise TypeError("input block must be a 2 x 2 matrix over GF(16)") - if not isinstance(rkey, Matrix_dense) or \ - not (rkey.base_ring().order() == 16 and rkey.base_ring().is_field()): + if not isinstance(rkey, Matrix_dense) or not (rkey.base_ring().order() == 16 and rkey.base_ring().is_field()): raise TypeError("round key must be a 2 x 2 matrix over GF(16)") if not (rkey.nrows() == rkey.ncols() == 2): raise TypeError("round key must be a 2 x 2 matrix over GF(16)") @@ -698,13 +606,11 @@ def decrypt(self, C, key): ... TypeError: secret key must be a 2 x 2 matrix over GF(16) """ - if not isinstance(C, Matrix_dense) or \ - not (C.base_ring().order() == 16 and C.base_ring().is_field()): + if not isinstance(C, Matrix_dense) or not (C.base_ring().order() == 16 and C.base_ring().is_field()): raise TypeError("ciphertext block must be a 2 x 2 matrix over GF(16)") if not (C.nrows() == C.ncols() == 2): raise TypeError("ciphertext block must be a 2 x 2 matrix over GF(16)") - if not isinstance(key, Matrix_dense) or \ - not (key.base_ring().order() == 16 and key.base_ring().is_field()): + if not isinstance(key, Matrix_dense) or not (key.base_ring().order() == 16 and key.base_ring().is_field()): raise TypeError("secret key must be a 2 x 2 matrix over GF(16)") if not (key.nrows() == key.ncols() == 2): raise TypeError("secret key must be a 2 x 2 matrix over GF(16)") @@ -856,13 +762,11 @@ def encrypt(self, P, key): ... TypeError: secret key must be a 2 x 2 matrix over GF(16) """ - if not isinstance(P, Matrix_dense) or \ - not (P.base_ring().order() == 16 and P.base_ring().is_field()): + if not isinstance(P, Matrix_dense) or not (P.base_ring().order() == 16 and P.base_ring().is_field()): raise TypeError("plaintext block must be a 2 x 2 matrix over GF(16)") if not (P.nrows() == P.ncols() == 2): raise TypeError("plaintext block must be a 2 x 2 matrix over GF(16)") - if not isinstance(key, Matrix_dense) or \ - not (key.base_ring().order() == 16 and key.base_ring().is_field()): + if not isinstance(key, Matrix_dense) or not (key.base_ring().order() == 16 and key.base_ring().is_field()): raise TypeError("secret key must be a 2 x 2 matrix over GF(16)") if not (key.nrows() == key.ncols() == 2): raise TypeError("secret key must be a 2 x 2 matrix over GF(16)") @@ -1010,16 +914,14 @@ def mix_column(self, block): ... TypeError: input block must be a 2 x 2 matrix over GF(16) """ - if not isinstance(block, Matrix_dense) or \ - not (block.base_ring().order() == 16 and block.base_ring().is_field()): + if not isinstance(block, Matrix_dense) or not (block.base_ring().order() == 16 and block.base_ring().is_field()): raise TypeError("input block must be a 2 x 2 matrix over GF(16)") if not (block.nrows() == block.ncols() == 2): raise TypeError("input block must be a 2 x 2 matrix over GF(16)") K = FiniteField(self._key_size, "x") MS = MatrixSpace(K, 2, 2) - M = MS( [ [K("x + 1"), K("x")], - [K("x"), K("x + 1")] ] ) + M = MS([[K("x + 1"), K("x")], [K("x"), K("x + 1")]]) return M * block def nibble_sub(self, block, algorithm='encrypt'): @@ -1199,8 +1101,7 @@ def nibble_sub(self, block, algorithm='encrypt'): ... ValueError: the algorithm for nibble-sub must be either 'encrypt' or 'decrypt' """ - if not isinstance(block, Matrix_dense) or \ - not (block.base_ring().order() == 16 and block.base_ring().is_field()): + if not isinstance(block, Matrix_dense) or not (block.base_ring().order() == 16 and block.base_ring().is_field()): raise TypeError("input block must be a 2 x 2 matrix over GF(16)") if not (block.nrows() == block.ncols() == 2): raise TypeError("input block must be a 2 x 2 matrix over GF(16)") @@ -1339,8 +1240,7 @@ def round_key(self, key, n): ... TypeError: secret key must be a 2 x 2 matrix over GF(16) """ - if not isinstance(key, Matrix_dense) or \ - not (key.base_ring().order() == 16 and key.base_ring().is_field()): + if not isinstance(key, Matrix_dense) or not (key.base_ring().order() == 16 and key.base_ring().is_field()): raise TypeError("secret key must be a 2 x 2 matrix over GF(16)") if not (key.nrows() == key.ncols() == 2): raise TypeError("secret key must be a 2 x 2 matrix over GF(16)") @@ -1357,7 +1257,7 @@ def round_key(self, key, n): w5 = key[1][0] + w4 w6 = key[0][1] + w5 w7 = key[1][1] + w6 - return MS([ [w4, w6], [w5, w7] ]) + return MS([[w4, w6], [w5, w7]]) # round 2 if n == 2: round_constant_2 = K("x") @@ -1366,7 +1266,7 @@ def round_key(self, key, n): w9 = key1[1][0] + w8 w10 = key1[0][1] + w9 w11 = key1[1][1] + w10 - return MS([ [w8, w10], [w9, w11] ]) + return MS([[w8, w10], [w9, w11]]) # unsupported round number if (n < 0) or (n > 2): raise ValueError("Mini-AES only defines two rounds") @@ -1487,15 +1387,13 @@ def shift_row(self, block): ... TypeError: input block must be a 2 x 2 matrix over GF(16) """ - if not isinstance(block, Matrix_dense) or \ - not (block.base_ring().order() == 16 and block.base_ring().is_field()): + if not isinstance(block, Matrix_dense) or not (block.base_ring().order() == 16 and block.base_ring().is_field()): raise TypeError("input block must be a 2 x 2 matrix over GF(16)") if not (block.nrows() == block.ncols() == 2): raise TypeError("input block must be a 2 x 2 matrix over GF(16)") MS = MatrixSpace(FiniteField(self._key_size, "x"), 2, 2) - mat = MS([ [block[0][0], block[0][1]], - [block[1][1], block[1][0]] ] ) + mat = MS([[block[0][0], block[0][1]], [block[1][1], block[1][0]]]) return mat ### conversion functions to convert between different data formats @@ -1642,8 +1540,7 @@ def GF_to_binary(self, G): if isinstance(G, Matrix_dense): if G.base_ring() is not K: raise TypeError("input G must be an element of GF(16), a list of elements of GF(16), or a matrix over GF(16)") - S = "".join(str(self._GF_to_bin[G[i][j]]) - for i in range(G.nrows()) for j in range(G.ncols())) + S = "".join(str(self._GF_to_bin[G[i][j]]) for i in range(G.nrows()) for j in range(G.ncols())) return B(S) # the type of G doesn't match the supported types raise TypeError("input G must be an element of GF(16), a list of elements of GF(16), or a matrix over GF(16)") @@ -1851,6 +1748,7 @@ def binary_to_GF(self, B): ValueError: the number of bits in the binary string B must be positive and a multiple of 4 """ from sage.rings.finite_rings.integer_mod import Mod + bin = BinaryStrings() b = bin(B) # an empty string @@ -1859,7 +1757,7 @@ def binary_to_GF(self, B): # a string with number of bits that is a multiple of 4 if Mod(len(b), 4).lift() == 0: M = len(b) // 4 # the number of nibbles - return [self._bin_to_GF[b[i*4 : (i+1)*4]] for i in range(M)] + return [self._bin_to_GF[b[i * 4 : (i + 1) * 4]] for i in range(M)] raise ValueError("the number of bits in the binary string B must be positive and a multiple of 4") def binary_to_integer(self, B): @@ -1918,6 +1816,7 @@ def binary_to_integer(self, B): ValueError: the number of bits in the binary string B must be positive and a multiple of 4 """ from sage.rings.finite_rings.integer_mod import Mod + bin = BinaryStrings() b = bin(B) # an empty string @@ -1926,7 +1825,7 @@ def binary_to_integer(self, B): # a string with number of bits that is a multiple of 4 if Mod(len(b), 4).lift() == 0: M = len(b) // 4 # the number of nibbles - return [self._bin_to_int[b[i*4 : (i+1)*4]] for i in range(M)] + return [self._bin_to_int[b[i * 4 : (i + 1) * 4]] for i in range(M)] raise ValueError("the number of bits in the binary string B must be positive and a multiple of 4") def integer_to_binary(self, N): diff --git a/src/sage/crypto/block_cipher/present.py b/src/sage/crypto/block_cipher/present.py index 1420f297c08..427d77c4e4d 100644 --- a/src/sage/crypto/block_cipher/present.py +++ b/src/sage/crypto/block_cipher/present.py @@ -102,15 +102,14 @@ def _smallscale_present_linearlayer(nsboxes=16): from sage.rings.finite_rings.finite_field_constructor import GF def present_llayer(n, x): - dim = 4*n - y = [0]*dim - for i in range(dim-1): + dim = 4 * n + y = [0] * dim + for i in range(dim - 1): y[i] = x[(n * i) % (dim - 1)] - y[dim-1] = x[dim-1] + y[dim - 1] = x[dim - 1] return vector(GF(2), y) - m = Matrix(GF(2), [present_llayer(nsboxes, ei) - for ei in VectorSpace(GF(2), 4*nsboxes).basis()]) + m = Matrix(GF(2), [present_llayer(nsboxes, ei) for ei in VectorSpace(GF(2), 4 * nsboxes).basis()]) return m @@ -257,8 +256,7 @@ def __init__(self, keySchedule=80, rounds=None, doFinalRound=False): elif rounds <= self.keySchedule._rounds: self._rounds = rounds else: - raise ValueError('number of rounds must be less or equal to the ' - 'number of rounds of the key schedule') + raise ValueError('number of rounds must be less or equal to the ' 'number of rounds of the key schedule') self._blocksize = 64 self.sbox = PRESENTSBOX self._permutationMatrix = _smallscale_present_linearlayer() @@ -301,8 +299,7 @@ def __call__(self, block, key, algorithm='encrypt'): return self.encrypt(block, key) if algorithm == 'decrypt': return self.decrypt(block, key) - raise ValueError('Algorithm must be \'encrypt\' or \'decrypt\' and' - ' not \'%s\'' % algorithm) + raise ValueError('Algorithm must be \'encrypt\' or \'decrypt\' and' ' not \'%s\'' % algorithm) def __eq__(self, other): r""" @@ -340,10 +337,7 @@ def __repr__(self): last round and the following key schedule: Original PRESENT key schedule with 80-bit keys and 31 rounds """ - return ('PRESENT block cipher with %s rounds, %s linear layer in last ' - 'round and the following key schedule:\n%s' - % (self._rounds, 'activated' if self._doFinalRound else - 'deactivated', self.keySchedule.__repr__())) + return 'PRESENT block cipher with %s rounds, %s linear layer in last ' 'round and the following key schedule:\n%s' % (self._rounds, 'activated' if self._doFinalRound else 'deactivated', self.keySchedule.__repr__()) def encrypt(self, plaintext, key): r""" @@ -423,7 +417,7 @@ def encrypt(self, plaintext, key): state = convert_to_vector(plaintext, 64) key = convert_to_vector(key, self._keysize) roundKeys = self.keySchedule(key) - for r, K in enumerate(roundKeys[:self._rounds]): + for r, K in enumerate(roundKeys[: self._rounds]): state = self.round(state, r, K) state = state + roundKeys[self._rounds] return state if inputType == 'vector' else ZZ(list(state), 2) @@ -480,7 +474,7 @@ def decrypt(self, ciphertext, key): key = convert_to_vector(key, self._keysize) roundKeys = self.keySchedule(key) state = state + roundKeys[self._rounds] - for r, K in enumerate(roundKeys[:self._rounds][::-1]): + for r, K in enumerate(roundKeys[: self._rounds][::-1]): state = self.round(state, r, K, inverse=True) return state if inputType == 'vector' else ZZ(list(state), 2) @@ -556,7 +550,7 @@ def sbox_layer(self, state, inverse=False): """ sbox = self.sbox if not inverse else self.sbox.inverse() out = vector(GF(2), 64) - for nibble in [slice(4*j, 4*j+4) for j in range(16)]: + for nibble in [slice(4 * j, 4 * j + 4) for j in range(16)]: out[nibble] = sbox(state[nibble][::-1])[::-1] return out @@ -736,8 +730,7 @@ def __init__(self, keysize=80, rounds=31, master_key=None): omit ``master_key`` and pass a key when you call the object. """ if keysize != 80 and keysize != 128: - raise ValueError('keysize must bei either 80 or 128 and not %s' - % keysize) + raise ValueError('keysize must bei either 80 or 128 and not %s' % keysize) self._keysize = keysize self._rounds = rounds self.sbox = PRESENTSBOX @@ -779,7 +772,7 @@ def __call__(self, K): K = convert_to_vector(K, self._keysize) roundKeys = [] if self._keysize == 80: - for i in range(1, self._rounds+1): + for i in range(1, self._rounds + 1): roundKeys.append(K[16:]) K[0:] = list(K[19:]) + list(K[:19]) K[76:] = self.sbox(K[76:][::-1])[::-1] @@ -787,7 +780,7 @@ def __call__(self, K): K[15:20] = K[15:20] + rc roundKeys.append(K[16:]) elif self._keysize == 128: - for i in range(1, self._rounds+1): + for i in range(1, self._rounds + 1): roundKeys.append(K[64:]) K[0:] = list(K[67:]) + list(K[:67]) K[124:] = self.sbox(K[124:][::-1])[::-1] @@ -795,8 +788,7 @@ def __call__(self, K): rc = vector(GF(2), ZZ(i).digits(2, padto=5)) K[62:67] = K[62:67] + rc roundKeys.append(K[64:]) - return roundKeys if inputType == 'vector' else [ZZ(list(k), 2) for k in - roundKeys] + return roundKeys if inputType == 'vector' else [ZZ(list(k), 2) for k in roundKeys] def __eq__(self, other): r""" @@ -828,8 +820,7 @@ def __repr__(self): sage: PRESENT_KS() # indirect doctest Original PRESENT key schedule with 80-bit keys and 31 rounds """ - return ('Original PRESENT key schedule with %s-bit keys and %s rounds' - % (self._keysize, self._rounds)) + return 'Original PRESENT key schedule with %s-bit keys and %s rounds' % (self._keysize, self._rounds) def __getitem__(self, r): r""" diff --git a/src/sage/crypto/block_cipher/sdes.py b/src/sage/crypto/block_cipher/sdes.py index acb0159bebe..3978016baf7 100644 --- a/src/sage/crypto/block_cipher/sdes.py +++ b/src/sage/crypto/block_cipher/sdes.py @@ -95,6 +95,7 @@ def __init__(self): True """ from sage.crypto.sbox import SBox + # the number of bits in a secret key self._key_size = 10 # the S-box S_0 @@ -192,6 +193,7 @@ def __call__(self, B, K, algorithm='encrypt'): """ from sage.monoids.string_monoid_element import StringMonoidElement from sage.rings.finite_rings.integer_mod import Mod + # S-DES operates on 8-bit ciphertext/plaintext blocks Blength = 8 @@ -211,7 +213,7 @@ def __call__(self, B, K, algorithm='encrypt'): if algorithm == "encrypt": for i in range(N): # get an 8-bit block - block = B[i*Blength : (i+1)*Blength] + block = B[i * Blength : (i + 1) * Blength] block = self.string_to_list(str(block)) key = self.string_to_list(str(K)) # encrypt the block using key @@ -224,7 +226,7 @@ def __call__(self, B, K, algorithm='encrypt'): if algorithm == "decrypt": for i in range(N): # get an 8-bit block - block = B[i*Blength : (i+1)*Blength] + block = B[i * Blength : (i + 1) * Blength] block = self.string_to_list(str(block)) key = self.string_to_list(str(K)) # decrypt the block using key @@ -250,9 +252,7 @@ def __eq__(self, other): sage: s == loads(dumps(s)) True """ - return ( (self._key_size == other._key_size) and - (self._sbox0 == other._sbox0) and - (self._sbox1 == other._sbox1) ) + return (self._key_size == other._key_size) and (self._sbox0 == other._sbox0) and (self._sbox1 == other._sbox1) def __repr__(self): r""" @@ -613,17 +613,11 @@ def initial_permutation(self, B, inverse=False): # use the initial permutation P if not inverse: - return [ bin(str(B[1])), bin(str(B[5])), - bin(str(B[2])), bin(str(B[0])), - bin(str(B[3])), bin(str(B[7])), - bin(str(B[4])), bin(str(B[6])) ] + return [bin(str(B[1])), bin(str(B[5])), bin(str(B[2])), bin(str(B[0])), bin(str(B[3])), bin(str(B[7])), bin(str(B[4])), bin(str(B[6]))] # use the inverse permutation P^-1 if inverse: - return [ bin(str(B[3])), bin(str(B[0])), - bin(str(B[2])), bin(str(B[4])), - bin(str(B[6])), bin(str(B[1])), - bin(str(B[7])), bin(str(B[5])) ] + return [bin(str(B[3])), bin(str(B[0])), bin(str(B[2])), bin(str(B[4])), bin(str(B[6])), bin(str(B[1])), bin(str(B[7])), bin(str(B[5]))] def left_shift(self, B, n=1): r""" @@ -737,18 +731,10 @@ def left_shift(self, B, n=1): bin = BinaryStrings() # circular left shift by 1 position if n == 1: - return [ bin(str(B[1])), bin(str(B[2])), - bin(str(B[3])), bin(str(B[4])), - bin(str(B[0])), bin(str(B[6])), - bin(str(B[7])), bin(str(B[8])), - bin(str(B[9])), bin(str(B[5])) ] + return [bin(str(B[1])), bin(str(B[2])), bin(str(B[3])), bin(str(B[4])), bin(str(B[0])), bin(str(B[6])), bin(str(B[7])), bin(str(B[8])), bin(str(B[9])), bin(str(B[5]))] # circular left shift by 2 positions if n == 2: - return [ bin(str(B[2])), bin(str(B[3])), - bin(str(B[4])), bin(str(B[0])), - bin(str(B[1])), bin(str(B[7])), - bin(str(B[8])), bin(str(B[9])), - bin(str(B[5])), bin(str(B[6])) ] + return [bin(str(B[2])), bin(str(B[3])), bin(str(B[4])), bin(str(B[0])), bin(str(B[1])), bin(str(B[7])), bin(str(B[8])), bin(str(B[9])), bin(str(B[5])), bin(str(B[6]))] # an invalid number of shift positions raise ValueError("input n must be either 1 or 2") @@ -800,6 +786,7 @@ def list_to_string(self, B): # perform the conversion from list to binary string from sage.rings.integer import Integer + bin = BinaryStrings() return bin([Integer(str(b)) for b in B]) @@ -882,8 +869,7 @@ def permutation4(self, B): # perform the permutation bin = BinaryStrings() - return [ bin(str(B[1])), bin(str(B[3])), - bin(str(B[2])), bin(str(B[0])) ] + return [bin(str(B[1])), bin(str(B[3])), bin(str(B[2])), bin(str(B[0]))] def permutation8(self, B): r""" @@ -969,10 +955,7 @@ def permutation8(self, B): # perform the permutation bin = BinaryStrings() - return [ bin(str(B[5])), bin(str(B[2])), - bin(str(B[6])), bin(str(B[3])), - bin(str(B[7])), bin(str(B[4])), - bin(str(B[9])), bin(str(B[8])) ] + return [bin(str(B[5])), bin(str(B[2])), bin(str(B[6])), bin(str(B[3])), bin(str(B[7])), bin(str(B[4])), bin(str(B[9])), bin(str(B[8]))] def permutation10(self, B): r""" @@ -1057,11 +1040,7 @@ def permutation10(self, B): # perform the permutation bin = BinaryStrings() - return [ bin(str(B[2])), bin(str(B[4])), - bin(str(B[1])), bin(str(B[6])), - bin(str(B[3])), bin(str(B[9])), - bin(str(B[0])), bin(str(B[8])), - bin(str(B[7])), bin(str(B[5])) ] + return [bin(str(B[2])), bin(str(B[4])), bin(str(B[1])), bin(str(B[6])), bin(str(B[3])), bin(str(B[9])), bin(str(B[0])), bin(str(B[8])), bin(str(B[7])), bin(str(B[5]))] def permute_substitute(self, B, key): r""" @@ -1236,30 +1215,31 @@ def permute_substitute(self, B, key): raise ValueError("input key must be an 8-bit subkey") from sage.rings.finite_rings.finite_field_constructor import FiniteField + GF = FiniteField(2, "x") bin = BinaryStrings() bin_to_GF2 = {bin("0"): GF(0), bin("1"): GF(1)} # the leftmost 4 bits of B - L = [ bin_to_GF2[bin(str(B[i]))] for i in range(4) ] + L = [bin_to_GF2[bin(str(B[i]))] for i in range(4)] # the rightmost 4 bits of B - R = [ bin_to_GF2[bin(str(B[i]))] for i in range(4, len(B)) ] + R = [bin_to_GF2[bin(str(B[i]))] for i in range(4, len(B))] # get the GF(2) representation of the subkey - K = [ bin_to_GF2[bin(str(key[i]))] for i in range(len(key)) ] + K = [bin_to_GF2[bin(str(key[i]))] for i in range(len(key))] # expand the rightmost 4 bits into an 8-bit block - RX = [ R[3], R[0], R[1], R[2], R[1], R[2], R[3], R[0] ] + RX = [R[3], R[0], R[1], R[2], R[1], R[2], R[3], R[0]] # add the subkey to the expanded 8-bit block using exclusive-OR - P = [ RX[i] + K[i] for i in range(len(K)) ] + P = [RX[i] + K[i] for i in range(len(K))] # run each half of P separately through the S-boxes - left = self._sbox0([ P[0], P[3], P[1], P[2] ]) - right = self._sbox1([ P[4], P[7], P[5], P[6] ]) + left = self._sbox0([P[0], P[3], P[1], P[2]]) + right = self._sbox1([P[4], P[7], P[5], P[6]]) # First concatenate the left and right parts, then get the # output of the function F. F = self.permutation4(left + right) - F = [ bin_to_GF2[F[i]] for i in range(len(F)) ] + F = [bin_to_GF2[F[i]] for i in range(len(F))] # Add L to F using exclusive-OR. Then concatenate the result with # the rightmost 4 bits of B. This is the output of the function Pi_F. - L = [ L[i] + F[i] for i in range(len(F)) ] + L = [L[i] + F[i] for i in range(len(F))] return L + R def random_key(self): @@ -1277,6 +1257,7 @@ def random_key(self): True """ from sage.misc.prandom import randint + bin = BinaryStrings() return [bin(str(randint(0, 1))) for i in range(self._key_size)] @@ -1517,7 +1498,4 @@ def switch(self, B): # perform the switch bin = BinaryStrings() - return [ bin(str(B[4])), bin(str(B[5])), - bin(str(B[6])), bin(str(B[7])), - bin(str(B[0])), bin(str(B[1])), - bin(str(B[2])), bin(str(B[3])) ] + return [bin(str(B[4])), bin(str(B[5])), bin(str(B[6])), bin(str(B[7])), bin(str(B[0])), bin(str(B[1])), bin(str(B[2])), bin(str(B[3]))] diff --git a/src/sage/crypto/cipher.py b/src/sage/crypto/cipher.py index 98a00db47dc..47878a35d60 100644 --- a/src/sage/crypto/cipher.py +++ b/src/sage/crypto/cipher.py @@ -3,13 +3,13 @@ Ciphers """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2007 David Kohel # # Distributed under the terms of the GNU General Public License (GPL) # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** # Ciphers should inherit from morphisms (of sets). # Specific cipher types will implement their functions in terms of the key @@ -21,6 +21,7 @@ class Cipher(Element): """ Cipher class """ + def __init__(self, parent, key): """ Create a cipher. @@ -45,7 +46,7 @@ def _repr_(self): return "Cipher on %s" % self.parent().cipher_domain() def key(self): - return self._key # was str(self._key) + return self._key # was str(self._key) def domain(self): return self.parent().cipher_domain() @@ -58,6 +59,7 @@ class SymmetricKeyCipher(Cipher): """ Symmetric key cipher class """ + def __init__(self, parent, key): """ Create a symmetric cipher. @@ -69,6 +71,7 @@ class PublicKeyCipher(Cipher): """ Public key cipher class """ + def __init__(self, parent, key, public=True): """ Create a public key cipher. diff --git a/src/sage/crypto/classical.py b/src/sage/crypto/classical.py index 6006451ce5c..150b91e21a7 100644 --- a/src/sage/crypto/classical.py +++ b/src/sage/crypto/classical.py @@ -32,7 +32,7 @@ - Minh Van Nguyen (2009-08): shift cipher, affine cipher """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2007 David Kohel # # This program is free software: you can redistribute it and/or modify @@ -40,7 +40,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** # TODO: check off this todo list: # - methods to cryptanalyze the Hill, substitution, transposition, and @@ -50,9 +50,7 @@ from sage.arith.misc import inverse_mod, xgcd from sage.misc.lazy_import import lazy_import -from sage.monoids.string_monoid import ( - StringMonoid_class, - AlphabeticStringMonoid) +from sage.monoids.string_monoid import StringMonoid_class, AlphabeticStringMonoid from sage.monoids.string_monoid_element import StringMonoidElement from sage.monoids.string_ops import strip_encoding from sage.rings.integer import Integer @@ -64,13 +62,7 @@ lazy_import('sage.matrix.matrix_space', 'MatrixSpace') from .cryptosystem import SymmetricKeyCryptosystem -from .classical_cipher import ( - AffineCipher, - HillCipher, - ShiftCipher, - SubstitutionCipher, - TranspositionCipher, - VigenereCipher) +from .classical_cipher import AffineCipher, HillCipher, ShiftCipher, SubstitutionCipher, TranspositionCipher, VigenereCipher class AffineCryptosystem(SymmetricKeyCryptosystem): @@ -281,9 +273,7 @@ def __init__(self, A): self._invertible_A = n.coprime_integers(n) # Initialize the affine cryptosystem with the plaintext, ciphertext, # and key spaces. - SymmetricKeyCryptosystem.__init__( - self, A, A, - key_space=(IntegerModRing(A.ngens()), IntegerModRing(A.ngens()))) + SymmetricKeyCryptosystem.__init__(self, A, A, key_space=(IntegerModRing(A.ngens()), IntegerModRing(A.ngens()))) def __call__(self, a, b): r""" @@ -346,7 +336,7 @@ def __call__(self, a, b): # a is coprime to n since we assume that the list # self._invertible_A contains all the elements of G. if (a in self._invertible_A) and (0 <= b < n): - return AffineCipher(self, key=(a,b)) + return AffineCipher(self, key=(a, b)) raise ValueError except Exception: raise ValueError("(a, b) = (%s, %s) is outside the range of acceptable values for a key of this affine cryptosystem." % (a, b)) @@ -531,6 +521,7 @@ def rank_by_chi_square(self, C, pdict): # sanity check from sage.monoids.string_monoid import AlphabeticStrings + if not isinstance(C.parent(), AlphabeticStringMonoid): raise TypeError("The ciphertext must be capital letters of the English alphabet.") if str(C) == "": @@ -559,7 +550,7 @@ def rank_by_chi_square(self, C, pdict): else: OM.setdefault(e, 0.0) # the rank R_{chi^2}(M) of M with secret key (a,b) - RMab = [(OM[AS(e)] - EA[e])**2 / EA[e] for e in StrAlph] + RMab = [(OM[AS(e)] - EA[e]) ** 2 / EA[e] for e in StrAlph] Rank.append((sum(RMab), (a, b))) # Sort in non-decreasing order of chi-square statistic. It's # possible that two different keys share the same chi-square @@ -570,8 +561,7 @@ def rank_by_chi_square(self, C, pdict): # and key[1] indexes b. The value of val is not used at all, making # it redundant to access val in the first place. The following line # of code is written with readability in mind. - [RankedList.append((key, pdict[(key[0], key[1])])) - for val, key in Rank] + [RankedList.append((key, pdict[(key[0], key[1])])) for val, key in Rank] return RankedList def rank_by_squared_differences(self, C, pdict): @@ -740,6 +730,7 @@ def rank_by_squared_differences(self, C, pdict): # sanity check from sage.monoids.string_monoid import AlphabeticStrings + if not isinstance(C.parent(), AlphabeticStringMonoid): raise TypeError("The ciphertext must be capital letters of the English alphabet.") if str(C) == "": @@ -768,7 +759,7 @@ def rank_by_squared_differences(self, C, pdict): else: OM.setdefault(e, 0.0) # the rank R_{RSS}(M) of M with secret key (a,b) - RMab = [(OM[AS(e)] - EA[e])**2 for e in StrAlph] + RMab = [(OM[AS(e)] - EA[e]) ** 2 for e in StrAlph] Rank.append((sum(RMab), (a, b))) # Sort in non-decreasing order of squared-differences statistic. It's # possible that two different keys share the same squared-differences @@ -779,8 +770,7 @@ def rank_by_squared_differences(self, C, pdict): # and key[1] indexes b. The value of val is not used at all, making # it redundant to access val in the first place. The following line # of code is written with readability in mind. - [RankedList.append((key, pdict[(key[0], key[1])])) - for val, key in Rank] + [RankedList.append((key, pdict[(key[0], key[1])])) for val, key in Rank] return RankedList def brute_force(self, C, ranking='none'): @@ -961,9 +951,7 @@ def brute_force(self, C, ranking='none'): # further optimization. Unless we can justify that this block of # code is a bottleneck on the runtime of the method, we should # leave it as is. - [D.setdefault((a, b), self.deciphering(a, b, C)) - for a in self._invertible_A - for b in range(self.alphabet_size())] + [D.setdefault((a, b), self.deciphering(a, b, C)) for a in self._invertible_A for b in range(self.alphabet_size())] if ranking == "none": return D @@ -1233,6 +1221,7 @@ def inverse_key(self, a, b): """ try: from sage.rings.finite_rings.integer_mod import Mod + n = self.alphabet_size() aInv = inverse_mod(a, n) bInv = Mod(-b * aInv, n).lift() @@ -1271,6 +1260,7 @@ def random_key(self): # Return a random element in ZZ/nZZ x ZZ/nZZ where n is the number # of elements in the plaintext/ciphertext alphabet. from sage.misc.prandom import randint + n = self.alphabet_size() L = len(self._invertible_A) a = Integer(self._invertible_A[randint(0, L - 1)]) @@ -1396,8 +1386,7 @@ def _repr_(self): sage: H._repr_() # needs sage.modules 'Hill cryptosystem on Free alphabetic string monoid on A-Z of block length 3' """ - return "Hill cryptosystem on %s of block length %s" % ( - self.cipher_domain(), self.block_length()) + return "Hill cryptosystem on %s of block length %s" % (self.cipher_domain(), self.block_length()) def block_length(self): """ @@ -1449,7 +1438,7 @@ def random_key(self): m = M.nrows() N = Integer(self.cipher_domain().ngens()) while True: - A = M([randint(0, N-1) for i in range(m**2)]) + A = M([randint(0, N - 1) for i in range(m**2)]) if N.gcd(A.det().lift()) == 1: break return A @@ -1817,13 +1806,9 @@ def __init__(self, A): # is processed. # sanity check - from sage.monoids.string_monoid import ( - AlphabeticStringMonoid, - BinaryStringMonoid, - HexadecimalStringMonoid) - if not isinstance(A, ( AlphabeticStringMonoid, - BinaryStringMonoid, - HexadecimalStringMonoid )): + from sage.monoids.string_monoid import AlphabeticStringMonoid, BinaryStringMonoid, HexadecimalStringMonoid + + if not isinstance(A, (AlphabeticStringMonoid, BinaryStringMonoid, HexadecimalStringMonoid)): raise TypeError("A (= %s) is not supported as a cipher domain of this shift cryptosystem." % A) # Initialize the shift cryptosystem with the plaintext, ciphertext, # and key spaces. @@ -2125,6 +2110,7 @@ def rank_by_chi_square(self, C, pdict): # sanity check from sage.monoids.string_monoid import AlphabeticStrings + if not isinstance(C.parent(), AlphabeticStringMonoid): raise TypeError("The ciphertext must be capital letters of the English alphabet.") if str(C) == "": @@ -2152,7 +2138,7 @@ def rank_by_chi_square(self, C, pdict): else: OM.setdefault(e, 0.0) # the rank R(M, K) of M with shift key k - RMk = [(OM[AS(e)] - EA[e])**2 / EA[e] for e in StrAlph] + RMk = [(OM[AS(e)] - EA[e]) ** 2 / EA[e] for e in StrAlph] Rank.append((sum(RMk), key)) # Sort in non-decreasing order of squared-differences statistic. It's # possible that two different keys share the same squared-differences @@ -2358,9 +2344,8 @@ def rank_by_squared_differences(self, C, pdict): # line that computes the list RMk. # sanity check - from sage.monoids.string_monoid import ( - AlphabeticStringMonoid, - AlphabeticStrings) + from sage.monoids.string_monoid import AlphabeticStringMonoid, AlphabeticStrings + if not isinstance(C.parent(), AlphabeticStringMonoid): raise TypeError("The ciphertext must be capital letters of the English alphabet.") if str(C) == "": @@ -2388,7 +2373,7 @@ def rank_by_squared_differences(self, C, pdict): else: OM.setdefault(e, 0.0) # the rank R(M, K) of M with shift key k - RMk = [(OM[AS(e)] - EA[e])**2 for e in StrAlph] + RMk = [(OM[AS(e)] - EA[e]) ** 2 for e in StrAlph] Rank.append((sum(RMk), key)) # Sort in non-decreasing order of squared-differences statistic. It's # possible that two different keys share the same squared-differences @@ -2593,14 +2578,9 @@ def brute_force(self, C, ranking='none'): """ # Sanity check: ensure that C is encoded using one of the # supported alphabets of this shift cryptosystem. - from sage.monoids.string_monoid import ( - AlphabeticStringMonoid, - BinaryStringMonoid, - HexadecimalStringMonoid) - if not isinstance(C.parent(), ( - AlphabeticStringMonoid, - BinaryStringMonoid, - HexadecimalStringMonoid)): + from sage.monoids.string_monoid import AlphabeticStringMonoid, BinaryStringMonoid, HexadecimalStringMonoid + + if not isinstance(C.parent(), (AlphabeticStringMonoid, BinaryStringMonoid, HexadecimalStringMonoid)): raise TypeError("ciphertext must be encoded using one of the supported cipher domains of this shift cryptosystem.") ranking_functions = ["none", "chisquare", "squared_differences"] if ranking not in ranking_functions: @@ -2964,6 +2944,7 @@ def random_key(self): # Return a random element in ZZ/nZZ where n is the number of elements # in the plaintext/ciphertext alphabet and key space. from sage.misc.prandom import randint + return Integer(randint(0, self.alphabet_size() - 1)) @@ -3079,10 +3060,11 @@ def random_key(self): True """ from sage.combinat.permutation import Permutations + S = self.cipher_domain() n = S.ngens() I = Permutations(n).random_element() - return S([ i-1 for i in I ]) + return S([i - 1 for i in I]) def inverse_key(self, K): """ @@ -3110,7 +3092,7 @@ def inverse_key(self, K): I = K._element_list S = self.cipher_domain() n = S.ngens() - return S([ I.index(i) for i in range(n) ]) + return S([I.index(i) for i in range(n)]) def encoding(self, M): """ @@ -3284,8 +3266,7 @@ def _repr_(self): sage: T._repr_() # needs sage.groups 'Transposition cryptosystem on Free alphabetic string monoid on A-Z of block length 14' """ - return "Transposition cryptosystem on %s of block length %s" % ( - self.cipher_domain(), self.block_length()) + return "Transposition cryptosystem on %s of block length %s" % (self.cipher_domain(), self.block_length()) def random_key(self): """ @@ -3529,8 +3510,7 @@ def _repr_(self): sage: V._repr_() 'Vigenere cryptosystem on Free alphabetic string monoid on A-Z of period 14' """ - return "Vigenere cryptosystem on %s of period %s" % ( - self.cipher_domain(), self.period()) + return "Vigenere cryptosystem on %s of period %s" % (self.cipher_domain(), self.period()) def random_key(self): """ @@ -3556,7 +3536,7 @@ def random_key(self): S = self.key_space() n = S.ngens() m = self.period() - return S([ randint(0, n-1) for i in range(m) ]) + return S([randint(0, n - 1) for i in range(m)]) def inverse_key(self, K): """ @@ -3582,7 +3562,7 @@ def inverse_key(self, K): """ S = self.key_space() n = S.ngens() - return S([ (-i) % (n) for i in K._element_list ]) + return S([(-i) % (n) for i in K._element_list]) def encoding(self, M): """ diff --git a/src/sage/crypto/classical_cipher.py b/src/sage/crypto/classical_cipher.py index cb2a03ede29..f65ca9db3bc 100644 --- a/src/sage/crypto/classical_cipher.py +++ b/src/sage/crypto/classical_cipher.py @@ -123,9 +123,10 @@ def __call__(self, M): raise TypeError("Argument M must be a string in the plaintext/ciphertext space.") from sage.rings.finite_rings.integer_mod import Mod - A = list(D.alphabet()) # plaintext/ciphertext alphabet as a list + + A = list(D.alphabet()) # plaintext/ciphertext alphabet as a list N = self.domain().ngens() # number of elements in this alphabet - a, b = self.key() # encryption/decryption key (a,b) + a, b = self.key() # encryption/decryption key (a,b) # Let I be the index list of M. That is, the i-th element of M has # index k in the cipher domain D. We store this cipher domain index # as the i-th element of I. @@ -135,7 +136,7 @@ def __call__(self, M): # corresponding to i is ai + b (mod N). This can also be used for # decryption, in which case (a, b) is the inverse key corresponding # to a secret key. - return D([ A.index(A[Mod(a*i + b, N).lift()]) for i in I ]) + return D([A.index(A[Mod(a * i + b, N).lift()]) for i in I]) def _repr_(self): r""" @@ -157,6 +158,7 @@ class HillCipher(SymmetricKeyCipher): """ Hill cipher class """ + def __init__(self, parent, key): """ Create a Hill cipher. @@ -191,22 +193,22 @@ def __eq__(self, right): return type(self) is type(right) and self.parent() == right.parent() and self.key() == right.key() def __call__(self, M): - S = self.domain() # = plaintext_space = ciphertext_space + S = self.domain() # = plaintext_space = ciphertext_space if not isinstance(M, StringMonoidElement) and M.parent() == S: raise TypeError("Argument M (= %s) must be a string in the plaintext space." % M) m = self.parent().block_length() if len(M) % m != 0: - raise TypeError("The length of M (= %s) must be a multiple of %s." % (M, m )) + raise TypeError("The length of M (= %s) must be a multiple of %s." % (M, m)) Alph = list(S.alphabet()) - A = self.key() # A is an m x m matrix + A = self.key() # A is an m x m matrix R = A.parent().base_ring() - V = FreeModule(R,m) + V = FreeModule(R, m) Mstr = str(M) C = [] - for i in range(len(M)//m): - v = V([ Alph.index(Mstr[m*i+j]) for j in range(m) ]) + for i in range(len(M) // m): + v = V([Alph.index(Mstr[m * i + j]) for j in range(m)]) C += (v * A).list() - return S([ k.lift() for k in C ]) + return S([k.lift() for k in C]) def _repr_(self): r""" @@ -221,8 +223,7 @@ def _repr_(self): sage: e = H(A); e Hill cipher on Free alphabetic string monoid on A-Z of block length 3 """ - return "Hill cipher on %s of block length %s" % ( - self.parent().cipher_domain(), self.parent().block_length() ) + return "Hill cipher on %s of block length %s" % (self.parent().cipher_domain(), self.parent().block_length()) def inverse(self): E = self.parent() @@ -333,9 +334,10 @@ def __call__(self, M): if not isinstance(M, StringMonoidElement) and M.parent() == dom: raise TypeError("Argument M (= %s) must be a string in the plaintext/ciphertext space." % M) from sage.rings.finite_rings.integer_mod import Mod - A = list(dom.alphabet()) # plaintext/ciphertext alphabet as a list + + A = list(dom.alphabet()) # plaintext/ciphertext alphabet as a list N = self.domain().ngens() # number of elements in this alphabet - K = self.key() # encryption/decryption key + K = self.key() # encryption/decryption key # Here, M is a message encoded within the ciphertext/plaintext # alphabet of this shift cryptosystem. The list A above is a list of # all elements of this alphabet, each element being associated with @@ -352,7 +354,7 @@ def __call__(self, M): I = [A.index(str(e)) for e in M] # Perform encryption/decryption on the whole message M, returning # the result as a string encoded in the alphabet A. - return dom([ A.index(A[Mod(i + K, N).lift()]) for i in I ]) + return dom([A.index(A[Mod(i + K, N).lift()]) for i in I]) def _repr_(self): r""" @@ -380,6 +382,7 @@ class SubstitutionCipher(SymmetricKeyCipher): """ Substitution cipher class """ + def __init__(self, parent, key): """ Create a substitution cipher. @@ -411,14 +414,14 @@ def __eq__(self, right): return type(self) is type(right) and self.parent() == right.parent() and self.key() == right.key() def __call__(self, M): - S = self.domain() # = plaintext_space = ciphertext_space + S = self.domain() # = plaintext_space = ciphertext_space if not isinstance(M, StringMonoidElement) and M.parent() == S: raise TypeError("Argument M (= %s) must be a string in the plaintext space." % M) A = list(S.alphabet()) - K = str(self.key()) # K is a string, while we want the indices: - I = [ A.index(K[i]) for i in range(len(K)) ] + K = str(self.key()) # K is a string, while we want the indices: + I = [A.index(K[i]) for i in range(len(K))] Mstr = str(M) - return S([ I[A.index(Mstr[i])] for i in range(len(Mstr)) ]) + return S([I[A.index(Mstr[i])] for i in range(len(Mstr))]) def _repr_(self): r""" @@ -454,6 +457,7 @@ class TranspositionCipher(SymmetricKeyCipher): """ Transition cipher class """ + def __init__(self, parent, key): """ Create a transposition cipher. @@ -498,7 +502,7 @@ def __init__(self, parent, key): SymmetricKeyCipher.__init__(self, parent, key) def __call__(self, M, mode='ECB'): - S = self.domain() # = plaintext_space = ciphertext_space + S = self.domain() # = plaintext_space = ciphertext_space if not isinstance(M, StringMonoidElement) and M.parent() == S: raise TypeError("Argument M (= %s) must be a string in the plaintext space." % M) if not mode == "ECB": @@ -508,12 +512,12 @@ def __call__(self, M, mode='ECB'): m = self.parent().block_length() if not N % m == 0: raise TypeError("Argument M (= %s) must be a string of length k*%s." % (M, m)) - Melt = M._element_list # this uses the internal structure of string monoids + Melt = M._element_list # this uses the internal structure of string monoids # Caution: this is parsed as an outer loop in k and an inner loop in i: # for k in range(N//m): # for i in range(m): # S([ Melt[g(i+1)-1+k*m] - return S([ Melt[g(i+1)-1+k*m] for k in range(N//m) for i in range(m) ]) + return S([Melt[g(i + 1) - 1 + k * m] for k in range(N // m) for i in range(m)]) def inverse(self): E = self.parent() @@ -525,6 +529,7 @@ class VigenereCipher(SymmetricKeyCipher): """ Vigenere cipher class """ + def __init__(self, parent, key): """ Create a Vigenere cipher. @@ -549,7 +554,7 @@ def __init__(self, parent, key): SymmetricKeyCipher.__init__(self, parent, key) def __call__(self, M, mode='ECB'): - S = self.domain() # = plaintext_space = ciphertext_space + S = self.domain() # = plaintext_space = ciphertext_space if not isinstance(M, StringMonoidElement) and M.parent() == S: raise TypeError("Argument M (= %s) must be a string in the plaintext space." % M) if not mode == "ECB": @@ -560,7 +565,7 @@ def __call__(self, M, mode='ECB'): # This uses the internal structure of string monoids Melt = M._element_list Kelt = K._element_list - return S([ (Melt[i]+Kelt[i % m]) % n for i in range(len(M)) ]) + return S([(Melt[i] + Kelt[i % m]) % n for i in range(len(M))]) def inverse(self): E = self.parent() diff --git a/src/sage/crypto/cryptosystem.py b/src/sage/crypto/cryptosystem.py index 82fb0e553ad..1938094c679 100644 --- a/src/sage/crypto/cryptosystem.py +++ b/src/sage/crypto/cryptosystem.py @@ -103,8 +103,8 @@ class Cryptosystem(Set_generic): sage: VigenereCryptosystem(Radix64Strings(), 7) Vigenere cryptosystem on Free radix 64 string monoid of period 7 """ - def __init__(self, plaintext_space, ciphertext_space, key_space, - block_length=1, period=None): + + def __init__(self, plaintext_space, ciphertext_space, key_space, block_length=1, period=None): r""" Create a ``Cryptosystem`` object. See the class ``Cryptosystem`` for detailed documentation. @@ -208,12 +208,7 @@ def __eq__(self, right): sage: vig1 == vig2 False """ - return (type(self) is type(right) and - self._cipher_domain == right._cipher_domain and - self._cipher_codomain == right._cipher_codomain and - self._key_space == right._key_space and - self._block_length == right._block_length and - self._period == right._period) + return type(self) is type(right) and self._cipher_domain == right._cipher_domain and self._cipher_codomain == right._cipher_codomain and self._key_space == right._key_space and self._block_length == right._block_length and self._period == right._period def plaintext_space(self): r""" @@ -358,6 +353,7 @@ class SymmetricKeyCryptosystem(Cryptosystem): r""" The base class for symmetric key, or secret key, cryptosystems. """ + def alphabet_size(self): r""" Return the number of elements in the alphabet of this diff --git a/src/sage/crypto/lattice.py b/src/sage/crypto/lattice.py index c1c6b6a83cf..7a7531b856d 100644 --- a/src/sage/crypto/lattice.py +++ b/src/sage/crypto/lattice.py @@ -14,19 +14,18 @@ - Michael Schneider """ -#***************************************************************************** +# ***************************************************************************** # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic -def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, - quotient=None, dual=False, ntl=False, lattice=False): +def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, quotient=None, dual=False, ntl=False, lattice=False): r""" This function generates different types of integral lattice bases of row vectors relevant in cryptography. @@ -228,8 +227,10 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, from sage.matrix.constructor import identity_matrix, block_matrix from sage.matrix.matrix_space import MatrixSpace from sage.rings.integer_ring import ZZ + if seed is not None: from sage.misc.randstate import set_random_seed + set_random_seed(seed) if type == 'random': @@ -240,7 +241,7 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, A = identity_matrix(ZZ_q, n) if type == 'random' or type == 'modular': - R = MatrixSpace(ZZ_q, m-n, n) + R = MatrixSpace(ZZ_q, m - n, n) A = A.stack(R.random_element()) elif type == 'ideal': @@ -260,7 +261,7 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, if quotient.degree() != n: raise ValueError('ideal basis requires n = quotient.degree()') R = P.quotient(quotient) - for i in range(m//n): + for i in range(m // n): A = A.stack(R.random_element().matrix()) elif type == 'cyclotomic': @@ -269,41 +270,39 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, # we assume that n+1 <= min( euler_phi^{-1}(n) ) <= 2*n found = False - for k in range(2*n,n,-1): + for k in range(2 * n, n, -1): if euler_phi(k) == n: found = True break if not found: - raise ValueError("cyclotomic bases require that n " - "is an image of Euler's totient function") + raise ValueError("cyclotomic bases require that n " "is an image of Euler's totient function") R = ZZ_q['x'].quotient(cyclotomic_polynomial(k, 'x'), 'x') - for i in range(m//n): + for i in range(m // n): A = A.stack(R.random_element().matrix()) # switch from representatives 0,...,(q-1) to (1-q)/2,....,(q-1)/2 def minrep(a): - if abs(a-q) < abs(a): - return a-q + if abs(a - q) < abs(a): + return a - q return a + A_prime = A[n:m].lift().apply_map(minrep) if not dual: - B = block_matrix([[ZZ(q), ZZ.zero()], [A_prime, ZZ.one()] ], - subdivide=False) + B = block_matrix([[ZZ(q), ZZ.zero()], [A_prime, ZZ.one()]], subdivide=False) else: - B = block_matrix([[ZZ.one(), -A_prime.transpose()], - [ZZ.zero(), ZZ(q)]], subdivide=False) - for i in range(m//2): - B.swap_rows(i,m-i-1) + B = block_matrix([[ZZ.one(), -A_prime.transpose()], [ZZ.zero(), ZZ(q)]], subdivide=False) + for i in range(m // 2): + B.swap_rows(i, m - i - 1) if ntl and lattice: - raise ValueError("Cannot specify ntl=True and lattice=True " - "at the same time") + raise ValueError("Cannot specify ntl=True and lattice=True " "at the same time") if ntl: return B._ntl_() if lattice: from sage.modules.free_module_integer import IntegerLattice + return IntegerLattice(B) return B diff --git a/src/sage/crypto/lfsr.py b/src/sage/crypto/lfsr.py index dfd56a43383..f0f7403e6dc 100644 --- a/src/sage/crypto/lfsr.py +++ b/src/sage/crypto/lfsr.py @@ -222,7 +222,7 @@ def lfsr_autocorrelation(L, p, k): p = Integer(p) _p = int(p) k = int(k) - L0 = L[:_p] # slices makes a copy + L0 = L[:_p] # slices makes a copy L0 = L0 + L0[:k] return sum([int(L0[i]) * int(L0[i + k]) / p for i in range(_p)]) @@ -280,12 +280,12 @@ def lfsr_connection_polynomial(s): N += 1 if d > 0: if 2 * L > N: - C = C - d*b**(-1)*x**m*B + C = C - d * b ** (-1) * x**m * B m += 1 N += 1 else: T = C - C = C - d*b**(-1)*x**m*B + C = C - d * b ** (-1) * x**m * B L = N + 1 - L m = 1 b = d diff --git a/src/sage/crypto/lwe.py b/src/sage/crypto/lwe.py index 47a3568fdcf..d8adb5382f2 100644 --- a/src/sage/crypto/lwe.py +++ b/src/sage/crypto/lwe.py @@ -128,6 +128,7 @@ class UniformSampler(SageObject): .. automethod:: __init__ .. automethod:: __call__ """ + def __init__(self, lower_bound, upper_bound): """ Construct a uniform sampler with bounds ``lower_bound`` and @@ -186,6 +187,7 @@ class UniformPolynomialSampler(SageObject): .. automethod:: __init__ .. automethod:: __call__ """ + def __init__(self, P, n, lower_bound, upper_bound): """ Construct a sampler for univariate polynomials of degree ``n-1`` where @@ -246,6 +248,7 @@ class LWE(SageObject): .. automethod:: __init__ .. automethod:: __call__ """ + def __init__(self, n, q, D, secret_dist='uniform', m=None): r""" Construct an LWE oracle in dimension ``n`` over a ring of order @@ -328,7 +331,7 @@ def __init__(self, n, q, D, secret_dist='uniform', m=None): else: try: lb, ub = map(ZZ, secret_dist) - self.__s = vector(self.K, self.n, [randint(lb,ub) for _ in range(n)]) + self.__s = vector(self.K, self.n, [randint(lb, ub) for _ in range(n)]) except (IndexError, TypeError): raise TypeError("Parameter secret_dist=%s not understood." % (secret_dist)) @@ -346,8 +349,8 @@ def _repr_(self): LWE(20, 401, Discrete Gaussian sampler over the Integers with sigma = 3.000000 and c = 0.000000, (-3, 3), None) """ if isinstance(self.secret_dist, str): - return "LWE(%d, %d, %s, '%s', %s)" % (self.n,self.K.order(),self.D,self.secret_dist, self.m) - return "LWE(%d, %d, %s, %s, %s)" % (self.n,self.K.order(),self.D,self.secret_dist, self.m) + return "LWE(%d, %d, %s, '%s', %s)" % (self.n, self.K.order(), self.D, self.secret_dist, self.m) + return "LWE(%d, %d, %s, %s, %s)" % (self.n, self.K.order(), self.D, self.secret_dist, self.m) def __call__(self): """ @@ -373,6 +376,7 @@ class Regev(LWE): .. automethod:: __init__ """ + def __init__(self, n, secret_dist='uniform', m=None): """ Construct LWE instance parameterised by security parameter ``n`` where @@ -394,8 +398,8 @@ def __init__(self, n, secret_dist='uniform', m=None): LWE(20, 401, Discrete Gaussian sampler over the Integers with sigma = 1.915069 and c = 401.000000, 'uniform', None) """ q = ZZ(next_prime(n**2)) - s = RR(1/(RR(n).sqrt() * log(n, 2)**2) * q) - D = DiscreteGaussianDistributionIntegerSampler(s/sqrt(2*pi.n()), q) + s = RR(1 / (RR(n).sqrt() * log(n, 2) ** 2) * q) + D = DiscreteGaussianDistributionIntegerSampler(s / sqrt(2 * pi.n()), q) LWE.__init__(self, n=n, q=q, D=D, secret_dist=secret_dist, m=m) @@ -405,6 +409,7 @@ class LindnerPeikert(LWE): .. automethod:: __init__ """ + def __init__(self, n, delta=0.01, m=None): """ Construct LWE instance parameterised by security parameter ``n`` where @@ -425,7 +430,7 @@ def __init__(self, n, delta=0.01, m=None): LWE(20, 2053, Discrete Gaussian sampler over the Integers with sigma = 3.600954 and c = 0.000000, 'noise', 168) """ if m is None: - m = 2*n + 128 + m = 2 * n + 128 # Find c>=1 such that c*exp((1-c**2)/2))**(2*n) == 2**-40 # (c*exp((1-c**2)/2))**(2*n) == 2**-40 # log((c*exp((1-c**2)/2))**(2*n)) == -40*log(2) @@ -435,15 +440,15 @@ def __init__(self, n, delta=0.01, m=None): # 2*n*log(c)+n*(1-c**2) == -40*log(2) # 2*n*log(c)+n*(1-c**2) + 40*log(2) == 0 c = SR.var('c') - c = find_root(2*n*log(c)+n*(1-c**2) + 40*log(2) == 0, 1, 10) + c = find_root(2 * n * log(c) + n * (1 - c**2) + 40 * log(2) == 0, 1, 10) # Upper bound on s**2/t - s_t_bound = (sqrt(2) * pi / c / sqrt(2*n*log(2/delta))).n() + s_t_bound = (sqrt(2) * pi / c / sqrt(2 * n * log(2 / delta))).n() # Interpretation of "choose q just large enough to allow for a Gaussian parameter s>=8" in [LP2011]_ - q = next_prime(floor(2**round(log(256 / s_t_bound, 2)))) + q = next_prime(floor(2 ** round(log(256 / s_t_bound, 2)))) # Gaussian parameter as defined in [LP2011]_ - s = sqrt(s_t_bound*floor(q/4)) + s = sqrt(s_t_bound * floor(q / 4)) # Transform s into stddev - stddev = s/sqrt(2*pi.n()) + stddev = s / sqrt(2 * pi.n()) D = DiscreteGaussianDistributionIntegerSampler(stddev) LWE.__init__(self, n=n, q=q, D=D, secret_dist='noise', m=m) @@ -454,6 +459,7 @@ class UniformNoiseLWE(LWE): .. automethod:: __init__ """ + def __init__(self, n, instance='key', m=None): """ Construct LWE instance parameterised by security parameter ``n`` where @@ -485,29 +491,27 @@ def __init__(self, n, instance='key', m=None): raise TypeError("Parameter too small") n2 = n - C = 4/sqrt(2*pi) - kk = floor((n2-2*log(n2, 2)**2)/5) - n1 = (3*n2-5*kk) // 2 - ke = floor((n1-2*log(n1, 2)**2)/5) - l = (3*n1-5*ke) // 2 - n2 - sk = ceil((C*(n1+n2))**(ZZ(3)/2)) - se = ceil((C*(n1+n2+l))**(ZZ(3)/2)) - q = next_prime(max(ceil((4*sk)**(ZZ(n1+n2)/n1)), - ceil((4*se)**(ZZ(n1+n2+l)/(n2+l))), - ceil(4*(n1+n2)*se*sk+4*se+1))) + C = 4 / sqrt(2 * pi) + kk = floor((n2 - 2 * log(n2, 2) ** 2) / 5) + n1 = (3 * n2 - 5 * kk) // 2 + ke = floor((n1 - 2 * log(n1, 2) ** 2) / 5) + l = (3 * n1 - 5 * ke) // 2 - n2 + sk = ceil((C * (n1 + n2)) ** (ZZ(3) / 2)) + se = ceil((C * (n1 + n2 + l)) ** (ZZ(3) / 2)) + q = next_prime(max(ceil((4 * sk) ** (ZZ(n1 + n2) / n1)), ceil((4 * se) ** (ZZ(n1 + n2 + l) / (n2 + l))), ceil(4 * (n1 + n2) * se * sk + 4 * se + 1))) if kk <= 0: raise TypeError("Parameter too small") if instance == 'key': - D = UniformSampler(0, sk-1) + D = UniformSampler(0, sk - 1) if m is None: m = n1 LWE.__init__(self, n=n2, q=q, D=D, secret_dist='noise', m=m) elif instance == 'encrypt': - D = UniformSampler(0, se-1) + D = UniformSampler(0, se - 1) if m is None: - m = n2+l + m = n2 + l LWE.__init__(self, n=n1, q=q, D=D, secret_dist='noise', m=m) else: raise TypeError("Parameter instance=%s not understood." % (instance)) @@ -520,6 +524,7 @@ class RingLWE(SageObject): .. automethod:: __init__ .. automethod:: __call__ """ + def __init__(self, N, q, D, poly=None, secret_dist='uniform', m=None): """ Construct a Ring-LWE oracle in dimension ``n=phi(N)`` over a ring of order @@ -614,6 +619,7 @@ class RingLindnerPeikert(RingLWE): .. automethod:: __init__ """ + def __init__(self, N, delta=0.01, m=None): """ Construct a Ring-LWE oracle in dimension ``n=phi(N)`` where @@ -635,19 +641,19 @@ def __init__(self, N, delta=0.01, m=None): """ n = euler_phi(N) if m is None: - m = 3*n + m = 3 * n # Find c>=1 such that c*exp((1-c**2)/2))**(2*n) == 2**-40 # i.e c>=1 such that 2*n*log(c)+n*(1-c**2) + 40*log(2) == 0 c = SR.var('c') - c = find_root(2*n*log(c)+n*(1-c**2) + 40*log(2) == 0, 1, 10) + c = find_root(2 * n * log(c) + n * (1 - c**2) + 40 * log(2) == 0, 1, 10) # Upper bound on s**2/t - s_t_bound = (sqrt(2) * pi / c / sqrt(2*n*log(2/delta))).n() + s_t_bound = (sqrt(2) * pi / c / sqrt(2 * n * log(2 / delta))).n() # Interpretation of "choose q just large enough to allow for a Gaussian parameter s>=8" in [LP2011]_ - q = next_prime(floor(2**round(log(256 / s_t_bound, 2)))) + q = next_prime(floor(2 ** round(log(256 / s_t_bound, 2)))) # Gaussian parameter as defined in [LP2011]_ - s = sqrt(s_t_bound*floor(q/4)) + s = sqrt(s_t_bound * floor(q / 4)) # Transform s into stddev - stddev = s/sqrt(2*pi.n()) + stddev = s / sqrt(2 * pi.n()) D = DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], n, stddev) RingLWE.__init__(self, N=N, q=q, D=D, poly=None, secret_dist='noise', m=m) @@ -660,6 +666,7 @@ class RingLWEConverter(SageObject): .. automethod:: __init__ .. automethod:: __call__ """ + def __init__(self, ringlwe): """ INPUT: @@ -698,7 +705,7 @@ def __call__(self): self._ac = self.ringlwe() a, c = self._ac x = R_q.gen() - r = vector((x**(self._i % self.n) * R_q(a.list())).list()), c[self._i % self.n] + r = vector((x ** (self._i % self.n) * R_q(a.list())).list()), c[self._i % self.n] self._i += 1 return r @@ -818,7 +825,7 @@ def balance_sample(s, q=None): c[0] scalar = False except TypeError: - c = vector(c.parent(),[c]) + c = vector(c.parent(), [c]) scalar = True if q is None: @@ -830,8 +837,8 @@ def balance_sample(s, q=None): a = a.change_ring(K).change_ring(ZZ) c = c.change_ring(K).change_ring(ZZ) - q2 = q//2 + q2 = q // 2 if scalar: - return vector(ZZ, len(a), [e if e <= q2 else e-q for e in a]), c[0] if c[0] <= q2 else c[0]-q - return vector(ZZ, len(a), [e if e <= q2 else e-q for e in a]), vector(ZZ, len(c), [e if e <= q2 else e-q for e in c]) + return vector(ZZ, len(a), [e if e <= q2 else e - q for e in a]), c[0] if c[0] <= q2 else c[0] - q + return vector(ZZ, len(a), [e if e <= q2 else e - q for e in a]), vector(ZZ, len(c), [e if e <= q2 else e - q for e in c]) diff --git a/src/sage/crypto/mq/__init__.py b/src/sage/crypto/mq/__init__.py index bc96f8eb607..603103af2c9 100644 --- a/src/sage/crypto/mq/__init__.py +++ b/src/sage/crypto/mq/__init__.py @@ -1,3 +1,4 @@ from sage.misc.lazy_import import lazy_import + lazy_import('sage.crypto.mq.rijndael_gf', 'RijndaelGF') lazy_import('sage.crypto.mq.sr', 'SR') diff --git a/src/sage/crypto/mq/mpolynomialsystemgenerator.py b/src/sage/crypto/mq/mpolynomialsystemgenerator.py index 864e9ab1ea1..5981aa0c05f 100644 --- a/src/sage/crypto/mq/mpolynomialsystemgenerator.py +++ b/src/sage/crypto/mq/mpolynomialsystemgenerator.py @@ -5,6 +5,7 @@ Martin Albrecht """ + from sage.structure.sage_object import SageObject @@ -27,7 +28,7 @@ def __getattr__(self, attr): if attr == "R": self.R = self.ring() return self.R - raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__,attr)) + raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__, attr)) def varformatstr(self, name): """ diff --git a/src/sage/crypto/mq/rijndael_gf.py b/src/sage/crypto/mq/rijndael_gf.py index 2247c813a7e..d87f5eea29e 100644 --- a/src/sage/crypto/mq/rijndael_gf.py +++ b/src/sage/crypto/mq/rijndael_gf.py @@ -498,76 +498,38 @@ def __init__(self, Nb, Nk, state_chr='a', key_chr='k'): self._Nb = Nb self._Nk = Nk - round_num_table = matrix([[10,11,12,13,14], [11,11,12,13,14], - [12,12,12,13,14], [13,13,13,13,14], - [14,14,14,14,14]]) + round_num_table = matrix([[10, 11, 12, 13, 14], [11, 11, 12, 13, 14], [12, 12, 12, 13, 14], [13, 13, 13, 13, 14], [14, 14, 14, 14, 14]]) self._Nr = round_num_table[self._Nb - 4, self._Nk - 4] from sage.rings.polynomial.polynomial_ring import polygen # Build framework for polynomial creation. from sage.rings.finite_rings.integer_mod_ring import Integers + pgen = polygen(Integers(2)) mod = pgen**8 + pgen**4 + pgen**3 + pgen + 1 self._F = FiniteField(2**8, 'x', modulus=mod) - state_names = [state_chr + str(i) + str(j) - for i in range(4) for j in range(self._Nb)] - subkey_names = [key_chr + str(r) + str(i) + str(j) - for r in range(self._Nr + 1) for i in range(4) - for j in range(self._Nb)] + state_names = [state_chr + str(i) + str(j) for i in range(4) for j in range(self._Nb)] + subkey_names = [key_chr + str(r) + str(i) + str(j) for r in range(self._Nr + 1) for i in range(4) for j in range(self._Nb)] self._state_PR = PolynomialRing(self._F, len(state_names), state_names) - self._all_PR = PolynomialRing(self._F, len(state_names + subkey_names), - state_names + subkey_names) + self._all_PR = PolynomialRing(self._F, len(state_names + subkey_names), state_names + subkey_names) self.state_vrs = matrix(4, self._Nb, self._state_PR.gens()) fNb = 4 * self._Nb self.subkey_vrs_list = list(self._all_PR.gens()[fNb:]) - self.subkey_vrs = [matrix(4, self._Nb, - self.subkey_vrs_list[fNb * i: fNb * (i + 1)]) - for i in range(self._Nr)] - self.key_vrs = column_matrix([ - self.subkey_vrs[int(i / self._Nb)].column(i % 4) - for i in range(self._Nk)]) - self._shiftrows_offsets_E = matrix([[0,1,2,3], [0,1,2,3], [0,1,2,3], - [0,1,2,4], [0,1,3,4]]) - self._shiftrows_offsets_D = matrix([[0,-1,-2,-3], [0,-1,-2,-3], - [0,-1,-2,-3], [0,-1,-2,-4], - [0,-1,-3,-4]]) - self._sb_E_coeffs = [self._F("x^2 + 1"), - self._F("x^3 + 1"), - self._F("x^7 + x^6 + x^5 + x^4 + x^3 + 1"), - self._F("x^5 + x^2 + 1"), - self._F("x^7 + x^6 + x^5 + x^4 + x^2"), - self._F("1"), - self._F("x^7 + x^5 + x^4 + x^2 + 1"), - self._F("x^7 + x^3 + x^2 + x + 1")] - self._sb_D_coeffs = [self._F("x^2 + 1"), - self._F("x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x"), - self._F("x^6 + x^5 + x^4 + x^3 + x^2 + x + 1"), - self._F("x^6 + x^4 + x^3 + x"), - self._F("x^6 + x^5 + x^4 + x^3"), - self._F("x^6 + x^4 + x^3 + 1"), - self._F("x^7 + x^6 + x^4 + x^3 + x + 1"), - self._F("x^6 + x^5 + x^3 + x^2 + x")] - mixcols_E_row = [self._F('x'), self._F('x+1'), self._F('1'), - self._F('1')] - self._mixcols_E = matrix([mixcols_E_row[-i:] + mixcols_E_row[:-i] - for i in range(4)]) - mixcols_D_row = [self._F('x^3 + x^2 + x'), self._F('x^3 + x + 1'), - self._F('x^3 + x^2 + 1'), self._F('x^3 + 1')] - self._mixcols_D = matrix([mixcols_D_row[-i:] + mixcols_D_row[:-i] - for i in range(4)]) + self.subkey_vrs = [matrix(4, self._Nb, self.subkey_vrs_list[fNb * i : fNb * (i + 1)]) for i in range(self._Nr)] + self.key_vrs = column_matrix([self.subkey_vrs[int(i / self._Nb)].column(i % 4) for i in range(self._Nk)]) + self._shiftrows_offsets_E = matrix([[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 4], [0, 1, 3, 4]]) + self._shiftrows_offsets_D = matrix([[0, -1, -2, -3], [0, -1, -2, -3], [0, -1, -2, -3], [0, -1, -2, -4], [0, -1, -3, -4]]) + self._sb_E_coeffs = [self._F("x^2 + 1"), self._F("x^3 + 1"), self._F("x^7 + x^6 + x^5 + x^4 + x^3 + 1"), self._F("x^5 + x^2 + 1"), self._F("x^7 + x^6 + x^5 + x^4 + x^2"), self._F("1"), self._F("x^7 + x^5 + x^4 + x^2 + 1"), self._F("x^7 + x^3 + x^2 + x + 1")] + self._sb_D_coeffs = [self._F("x^2 + 1"), self._F("x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x"), self._F("x^6 + x^5 + x^4 + x^3 + x^2 + x + 1"), self._F("x^6 + x^4 + x^3 + x"), self._F("x^6 + x^5 + x^4 + x^3"), self._F("x^6 + x^4 + x^3 + 1"), self._F("x^7 + x^6 + x^4 + x^3 + x + 1"), self._F("x^6 + x^5 + x^3 + x^2 + x")] + mixcols_E_row = [self._F('x'), self._F('x+1'), self._F('1'), self._F('1')] + self._mixcols_E = matrix([mixcols_E_row[-i:] + mixcols_E_row[:-i] for i in range(4)]) + mixcols_D_row = [self._F('x^3 + x^2 + x'), self._F('x^3 + x + 1'), self._F('x^3 + x^2 + 1'), self._F('x^3 + 1')] + self._mixcols_D = matrix([mixcols_D_row[-i:] + mixcols_D_row[:-i] for i in range(4)]) # Build the Round_Component_Poly_Constr objects - self._add_round_key_rcpc = \ - RijndaelGF.Round_Component_Poly_Constr(self._add_round_key_pc, self, - "Add Round Key") - self._sub_bytes_rcpc = \ - RijndaelGF.Round_Component_Poly_Constr(self._sub_bytes_pc, self, - "SubBytes") - self._mix_columns_rcpc = \ - RijndaelGF.Round_Component_Poly_Constr(self._mix_columns_pc, self, - "Mix Columns") - self._shift_rows_rcpc = \ - RijndaelGF.Round_Component_Poly_Constr(self._shift_rows_pc, self, - "Shift Rows") + self._add_round_key_rcpc = RijndaelGF.Round_Component_Poly_Constr(self._add_round_key_pc, self, "Add Round Key") + self._sub_bytes_rcpc = RijndaelGF.Round_Component_Poly_Constr(self._sub_bytes_pc, self, "SubBytes") + self._mix_columns_rcpc = RijndaelGF.Round_Component_Poly_Constr(self._mix_columns_pc, self, "Mix Columns") + self._shift_rows_rcpc = RijndaelGF.Round_Component_Poly_Constr(self._shift_rows_pc, self, "Shift Rows") def __call__(self, text, key, algorithm='encrypt', format='hex'): r""" @@ -612,8 +574,7 @@ def __call__(self, text, key, algorithm='encrypt', format='hex'): return self.encrypt(text, key, format) if algorithm == 'decrypt': return self.decrypt(text, key, format) - raise ValueError("keyword 'algorithm' must be either 'encrypt' " - "or 'decrypt'") + raise ValueError("keyword 'algorithm' must be either 'encrypt' " "or 'decrypt'") def __repr__(self): r""" @@ -627,8 +588,7 @@ def __repr__(self): Rijndael-GF block cipher with block length 5, key length 8, and 14 rounds. """ - msg = ("Rijndael-GF block cipher with block length {0}, key length " - "{1}, and {2} rounds.") + msg = "Rijndael-GF block cipher with block length {0}, key length " "{1}, and {2} rounds." return msg.format(self._Nb, self._Nk, self._Nr) def block_length(self): @@ -706,12 +666,12 @@ def _hex_to_GF(self, H, matrix=True): sage: rgf._hex_to_GF('1a2b0f', matrix=False) [x^4 + x^3 + x, x^5 + x^3 + x + 1, x^3 + x^2 + x + 1] """ - if not isinstance(H, str) or \ - any(c not in '0123456789abcdefABCDEF' for c in H): + if not isinstance(H, str) or any(c not in '0123456789abcdefABCDEF' for c in H): raise TypeError("keyword 'H' must be a hex string") def hx_to_gf(h): return self._F([int(_) for _ in bin(int(h, 16))[2:].zfill(8)][::-1]) + hexes = [H[2 * i] + H[2 * i + 1] for i in range(len(H) // 2)] result = [hx_to_gf(h) for h in hexes] if matrix: @@ -756,30 +716,21 @@ def _GF_to_hex(self, GF): sage: rgf._GF_to_hex(output) 'e142cd5fcd9d6d94a3340793034391b5' """ - if not isinstance(GF, Matrix) and \ - not isinstance(GF, list) and \ - not (isinstance(GF, Element) and isinstance(GF.parent(), FiniteField_base)): - msg = ("keyword 'GF' must be a matrix over {0}, a list of " - "elements from {0}, or a single element from {0}") + if not isinstance(GF, Matrix) and not isinstance(GF, list) and not (isinstance(GF, Element) and isinstance(GF.parent(), FiniteField_base)): + msg = "keyword 'GF' must be a matrix over {0}, a list of " "elements from {0}, or a single element from {0}" raise TypeError(msg.format(self._F)) if isinstance(GF, Matrix): - if not GF.base_ring().is_field() or \ - not GF.base_ring().is_finite() or \ - not GF.base_ring().order() == 2**8: + if not GF.base_ring().is_field() or not GF.base_ring().is_finite() or not GF.base_ring().order() == 2**8: msg = "The elements of keyword 'GF' must all be from {0}" raise TypeError(msg.format(self._F)) - return ''.join([self._GF_to_hex(el) - for col in GF.columns() for el in col]) + return ''.join([self._GF_to_hex(el) for col in GF.columns() for el in col]) if isinstance(GF, list): - if not all(g.parent().is_field() and g.parent().is_finite() and - g.parent().order() == 2**8 for g in GF): + if not all(g.parent().is_field() and g.parent().is_finite() and g.parent().order() == 2**8 for g in GF): msg = "The elements of keyword 'GF' must all be from {0}" raise TypeError(msg.format(self._F)) return ''.join([self._GF_to_hex(el) for el in GF]) - if not GF.parent().is_field() or \ - not GF.parent().is_finite() or \ - not GF.parent().order() == 2**8: + if not GF.parent().is_field() or not GF.parent().is_finite() or not GF.parent().order() == 2**8: msg = "keyword 'GF' must be in" raise TypeError(msg.format(self._F)) return hex(GF.to_integer())[2:].zfill(2) @@ -879,30 +830,21 @@ def _GF_to_bin(self, GF): sage: rgf._GF_to_bin(output) '11011000000111111111100000011011110110000001111111111000000110111101100000011111111110000001101111011000000111111111100000011011' """ - if not isinstance(GF, Matrix) and \ - not isinstance(GF, list) and \ - not (isinstance(GF, Element) and isinstance(GF.parent(), FiniteField_base)): - msg = ("keyword 'GF' must be a matrix over {0}, a list of " - "elements from {0}, or a single element from {0}") + if not isinstance(GF, Matrix) and not isinstance(GF, list) and not (isinstance(GF, Element) and isinstance(GF.parent(), FiniteField_base)): + msg = "keyword 'GF' must be a matrix over {0}, a list of " "elements from {0}, or a single element from {0}" raise TypeError(msg.format(self)) if isinstance(GF, Matrix): - if not GF.base_ring().is_field() or \ - not GF.base_ring().is_finite() or \ - not GF.base_ring().order() == 2**8: + if not GF.base_ring().is_field() or not GF.base_ring().is_finite() or not GF.base_ring().order() == 2**8: msg = "The elements of keyword 'GF' must all be from {0}" raise TypeError(msg.format(self._F)) - return ''.join([self._GF_to_bin(el) - for col in GF.columns() for el in col]) + return ''.join([self._GF_to_bin(el) for col in GF.columns() for el in col]) if isinstance(GF, list): - if not all(g.parent().is_field() and g.parent().is_finite() and - g.parent().order() == 2**8 for g in GF): + if not all(g.parent().is_field() and g.parent().is_finite() and g.parent().order() == 2**8 for g in GF): msg = "The elements of keyword 'GF' must all be from {0}" raise TypeError(msg.format(self._F)) return ''.join([self._GF_to_bin(el) for el in GF]) - if not GF.parent().is_field() or \ - not GF.parent().is_finite() or \ - not GF.parent().order() == 2**8: + if not GF.parent().is_field() or not GF.parent().is_finite() or not GF.parent().order() == 2**8: msg = "keyword 'GF' must be in" raise TypeError(msg.format(self._F)) return bin(GF.to_integer())[2:].zfill(8) @@ -944,14 +886,12 @@ def encrypt(self, plain, key, format='hex'): True """ if format == 'hex': - if not isinstance(plain, str) or \ - any(c not in '0123456789abcdefABCDEF' for c in plain): + if not isinstance(plain, str) or any(c not in '0123456789abcdefABCDEF' for c in plain): raise TypeError("'plain' keyword must be a hex string") if len(plain) != 8 * self._Nb: msg = "'plain' keyword\'s length must be {0}, not{1}" raise ValueError(msg.format(8 * self._Nb, len(plain))) - if not isinstance(key, str) or \ - any(c not in '0123456789abcdefABCDEF' for c in key): + if not isinstance(key, str) or any(c not in '0123456789abcdefABCDEF' for c in key): raise TypeError("'key' keyword must be a hex string") if len(key) != 8 * self._Nk: msg = "'key' keyword's length must be {0}, not {1}" @@ -960,14 +900,12 @@ def encrypt(self, plain, key, format='hex'): key_state = self._hex_to_GF(key) roundKeys = self.expand_key(key_state) elif format == 'binary': - if not isinstance(plain, str) or \ - any(c not in '01' for c in plain): + if not isinstance(plain, str) or any(c not in '01' for c in plain): raise TypeError("'plain' keyword must be a binary string") if len(plain) != 32 * self._Nb: msg = "'plain' keyword's length must be {0}, not {1}" raise ValueError(msg.format(32 * self._Nb, len(plain))) - if not isinstance(key, str) or \ - any(c not in '01' for c in key): + if not isinstance(key, str) or any(c not in '01' for c in key): raise TypeError("'key' keyword must be a binary string") if len(key) != 32 * self._Nk: msg = "'key' keyword's length must be {0}, not {1}" @@ -976,15 +914,14 @@ def encrypt(self, plain, key, format='hex'): key_state = self._bin_to_GF(key) roundKeys = self.expand_key(key_state) else: - raise ValueError("'format' keyword must be either 'hex' or " - "'binary'") + raise ValueError("'format' keyword must be either 'hex' or " "'binary'") state = self.add_round_key(state, roundKeys[0]) - for r in range(self._Nr-1): + for r in range(self._Nr - 1): state = self.sub_bytes(state, algorithm='encrypt') state = self.shift_rows(state, algorithm='encrypt') state = self.mix_columns(state, algorithm='encrypt') - state = self.add_round_key(state, roundKeys[r+1]) + state = self.add_round_key(state, roundKeys[r + 1]) state = self.sub_bytes(state, algorithm='encrypt') state = self.shift_rows(state, algorithm='encrypt') state = self.add_round_key(state, roundKeys[self._Nr]) @@ -1033,14 +970,12 @@ def decrypt(self, ciphertext, key, format='hex'): True """ if format == 'hex': - if not isinstance(ciphertext, str) or \ - any(c not in '0123456789abcdefABCDEF' for c in ciphertext): + if not isinstance(ciphertext, str) or any(c not in '0123456789abcdefABCDEF' for c in ciphertext): raise TypeError("'ciphertext' keyword must be a hex string") if len(ciphertext) != 8 * self._Nb: msg = "'ciphertext' keyword's length must be {0}, not{1}" raise ValueError(msg.format(8 * self._Nb, len(ciphertext))) - if not isinstance(key, str) or \ - any(c not in '0123456789abcdefABCDEF' for c in key): + if not isinstance(key, str) or any(c not in '0123456789abcdefABCDEF' for c in key): raise TypeError("'key' keyword must be a hex string") if len(key) != 8 * self._Nk: msg = "'key' keyword's length must be {0}, not {1}" @@ -1049,15 +984,12 @@ def decrypt(self, ciphertext, key, format='hex'): key_state = self._hex_to_GF(key) roundKeys = self.expand_key(key_state) elif format == 'binary': - if not isinstance(ciphertext, str) or \ - any(c not in '01' for c in ciphertext): - raise TypeError("'ciphertext' keyword must be a binary " - "string") + if not isinstance(ciphertext, str) or any(c not in '01' for c in ciphertext): + raise TypeError("'ciphertext' keyword must be a binary " "string") if len(ciphertext) != 32 * self._Nb: msg = "'ciphertext' keyword's length must be {0}, not {1}" raise ValueError(msg.format(32 * self._Nb, len(ciphertext))) - if not isinstance(key, str) or \ - any(c not in '01' for c in key): + if not isinstance(key, str) or any(c not in '01' for c in key): raise TypeError("'key' keyword must be a binary string") if len(key) != 32 * self._Nk: msg = "'key' keyword\'s length must be {0}, not {1}" @@ -1066,13 +998,12 @@ def decrypt(self, ciphertext, key, format='hex'): key_state = self._bin_to_GF(key) roundKeys = self.expand_key(key_state) else: - raise ValueError("'format' keyword must be either \'hex\' or " - "'binary'") + raise ValueError("'format' keyword must be either \'hex\' or " "'binary'") state = self.add_round_key(state, roundKeys[self._Nr]) state = self.shift_rows(state, algorithm='decrypt') state = self.sub_bytes(state, algorithm='decrypt') - for r in range(self._Nr-1): + for r in range(self._Nr - 1): state = self.add_round_key(state, roundKeys[self._Nr - r - 1]) state = self.mix_columns(state, algorithm='decrypt') state = self.shift_rows(state, algorithm='decrypt') @@ -1129,22 +1060,11 @@ def _check_valid_PRmatrix(self, PRm, keyword): TypeError: keyword 'state' must be a 4 x 4 matrix with entries from a multivariate PolynomialRing over Finite Field in x of size 2^8 """ - from sage.rings.polynomial.multi_polynomial_ring_base import \ - MPolynomialRing_base - msg = ("keyword '{0}' must be a {1} x {2} matrix with entries from a " - "multivariate PolynomialRing over {3}") + from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base + + msg = "keyword '{0}' must be a {1} x {2} matrix with entries from a " "multivariate PolynomialRing over {3}" msg = msg.format(keyword, 4, self._Nb, self._F) - if (not isinstance(PRm, Matrix) or - not (PRm.base_ring().is_field() and - PRm.base_ring().is_finite() and - PRm.base_ring().order() == 256 and - PRm.dimensions() == (4, self._Nb))) and \ - (not isinstance(PRm, Matrix) or - not isinstance(PRm.base_ring(), MPolynomialRing_base) or - not (PRm.base_ring().base_ring().is_field() and - PRm.base_ring().base_ring().is_finite() and - PRm.base_ring().base_ring().order() == 256) or - not PRm.dimensions() == (4, self._Nb)): + if (not isinstance(PRm, Matrix) or not (PRm.base_ring().is_field() and PRm.base_ring().is_finite() and PRm.base_ring().order() == 256 and PRm.dimensions() == (4, self._Nb))) and (not isinstance(PRm, Matrix) or not isinstance(PRm.base_ring(), MPolynomialRing_base) or not (PRm.base_ring().base_ring().is_field() and PRm.base_ring().base_ring().is_finite() and PRm.base_ring().base_ring().order() == 256) or not PRm.dimensions() == (4, self._Nb)): raise TypeError(msg) def expand_key(self, key): @@ -1176,11 +1096,7 @@ def expand_key(self, key): """ msg = "keyword '{0}' must be a {1} x {2} matrix over GF({3})" msg = msg.format(key, 4, self._Nk, self._F.order()) - if not isinstance(key, Matrix) or \ - not (key.base_ring().is_field() and - key.base_ring().is_finite() and - key.base_ring().order() == self._F.order()) or \ - not key.dimensions() == (4, self._Nk): + if not isinstance(key, Matrix) or not (key.base_ring().is_field() and key.base_ring().is_finite() and key.base_ring().order() == self._F.order()) or not key.dimensions() == (4, self._Nk): raise TypeError(msg) def add_cols(col1, col2): @@ -1209,8 +1125,7 @@ def add_cols(col1, col2): # Copy the expanded columns into 4xNb blocks round_keys = [] for r in range(self._Nr + 1): - rk = column_matrix([key_cols[r*self._Nb + i] - for i in range(self._Nb)]) + rk = column_matrix([key_cols[r * self._Nb + i] for i in range(self._Nb)]) round_keys.append(rk) return round_keys @@ -1280,31 +1195,27 @@ def expand_key_poly(self, row, col, round): key_col = round * self._Nb + col if key_col < self._Nk: return self.key_vrs[row, key_col] - if key_col % self._Nk == 0 or \ - (self._Nk > 6 and col % self._Nk == 4): + if key_col % self._Nk == 0 or (self._Nk > 6 and col % self._Nk == 4): # Apply non-linear transformation to key_col - 1 - recur_r = int((key_col - 1)/self._Nb) + recur_r = int((key_col - 1) / self._Nb) recur_j = (key_col - 1) - (recur_r * self._Nb) - non_linear = self.expand_key_poly((row+1) % 4, - recur_j, recur_r) + non_linear = self.expand_key_poly((row + 1) % 4, recur_j, recur_r) non_linear = self._srd(non_linear) non_linear += self._F.gen() ** (int(key_col / self._Nk) - 1) # Identify key_col - Nk - recur_r = int((key_col - self._Nk)/self._Nb) + recur_r = int((key_col - self._Nk) / self._Nb) recur_j = (key_col - self._Nk) - (recur_r * self._Nb) return self.expand_key_poly(row, recur_j, recur_r) + non_linear # Identify key_col - Nk - recur_r = int((key_col - self._Nk)/self._Nb) + recur_r = int((key_col - self._Nk) / self._Nb) recur_j = (key_col - self._Nk) - (recur_r * self._Nb) result = self.expand_key_poly(row, recur_j, recur_r) # Identify key_col - 1 - recur_r = int((key_col - 1)/self._Nb) + recur_r = int((key_col - 1) / self._Nb) recur_j = (key_col - 1) - (recur_r * self._Nb) - return result + \ - self.expand_key_poly(row, recur_j, recur_r) + return result + self.expand_key_poly(row, recur_j, recur_r) - def apply_poly(self, state, poly_constr, algorithm='encrypt', keys=None, - poly_constr_attr=None): + def apply_poly(self, state, poly_constr, algorithm='encrypt', keys=None, poly_constr_attr=None): r""" Return a state matrix where ``poly_method`` is applied to each entry. @@ -1390,14 +1301,8 @@ def apply_poly(self, state, poly_constr, algorithm='encrypt', keys=None, if not isinstance(poly_constr, RijndaelGF.Round_Component_Poly_Constr): msg = "keyword 'poly_constr' must be a Round_Component_Poly_Constr" raise TypeError(msg) - if keys is not None and (not isinstance(keys, list) or - len(keys) != self._Nr + 1 or - not all(isinstance(k, Matrix) for k in keys) or - not all(k.dimensions() == (4, self._Nb) for k in keys) or - not all(k.base_ring().is_finite() and k.base_ring().is_field() - and k.base_ring().order() == 256 for k in keys)): - msg = ("keys must be a length {0} array of 4 by {1} matrices" - " over {2}") + if keys is not None and (not isinstance(keys, list) or len(keys) != self._Nr + 1 or not all(isinstance(k, Matrix) for k in keys) or not all(k.dimensions() == (4, self._Nb) for k in keys) or not all(k.base_ring().is_finite() and k.base_ring().is_field() and k.base_ring().order() == 256 for k in keys)): + msg = "keys must be a length {0} array of 4 by {1} matrices" " over {2}" raise TypeError(msg.format(self._Nr, self._Nb, self._F)) output = [] @@ -1407,8 +1312,7 @@ def apply_poly(self, state, poly_constr, algorithm='encrypt', keys=None, for j in range(self._Nb): # this is to combat a major performance issue caused by # subbytes' inversion transformation. - if poly_constr == self.sub_bytes_poly_constr() and \ - algorithm == 'decrypt': + if poly_constr == self.sub_bytes_poly_constr() and algorithm == 'decrypt': p = poly_constr(i, j, algorithm, no_inversion=True) p = p(state.list()) ** 254 else: @@ -1544,10 +1448,9 @@ def compose(self, f, g, algorithm='encrypt', f_attr=None, g_attr=None): msg = "keyword 'f' must be a Round_Component_Poly_Constr" raise TypeError(msg) from sage.rings.polynomial.multi_polynomial import MPolynomial - if not isinstance(g, RijndaelGF.Round_Component_Poly_Constr) and \ - not isinstance(g, MPolynomial): - msg = ("keyword 'g' must be a Round_Component_Poly_Constr or a " - "polynomial over {0}") + + if not isinstance(g, RijndaelGF.Round_Component_Poly_Constr) and not isinstance(g, MPolynomial): + msg = "keyword 'g' must be a Round_Component_Poly_Constr or a " "polynomial over {0}" raise TypeError(msg.format(self._F)) if f_attr is not None and not isinstance(f_attr, dict): raise TypeError("f_attr must be a dictionary of keywords for f") @@ -1556,20 +1459,16 @@ def compose(self, f, g, algorithm='encrypt', f_attr=None, g_attr=None): if g in self._all_PR: if isinstance(f_attr, dict): - f_vals = [f(i, j, algorithm, **f_attr) - for i in range(4) for j in range(self._Nb)] + f_vals = [f(i, j, algorithm, **f_attr) for i in range(4) for j in range(self._Nb)] else: - f_vals = [f(i, j, algorithm) - for i in range(4) for j in range(self._Nb)] + f_vals = [f(i, j, algorithm) for i in range(4) for j in range(self._Nb)] if g in self._state_PR: return g(f_vals) return g(f_vals + self.subkey_vrs_list) if isinstance(g_attr, dict): - lm = lambda i, j, alg='encrypt': \ - self.compose(f, g(i, j, alg, **g_attr), alg, f_attr, g_attr) + lm = lambda i, j, alg='encrypt': self.compose(f, g(i, j, alg, **g_attr), alg, f_attr, g_attr) else: - lm = lambda i, j, alg='encrypt': \ - self.compose(f, g(i, j, alg), alg, f_attr, g_attr) + lm = lambda i, j, alg='encrypt': self.compose(f, g(i, j, alg), alg, f_attr, g_attr) return RijndaelGF.Round_Component_Poly_Constr(lm, self) def add_round_key_poly_constr(self): @@ -1848,20 +1747,16 @@ def _sub_bytes_pc(self, row, col, algorithm='encrypt', no_inversion=False): var = self.state_vrs[row, col] coeffs = self._sb_E_coeffs if no_inversion: - return sum([coeffs[i] * (var**(2**i)) - for i in range(8)]) + self._F("x^6 + x^5 + x + 1") - return sum([coeffs[i] * (var**(255 - 2**i)) - for i in range(8)]) + self._F("x^6 + x^5 + x + 1") + return sum([coeffs[i] * (var ** (2**i)) for i in range(8)]) + self._F("x^6 + x^5 + x + 1") + return sum([coeffs[i] * (var ** (255 - 2**i)) for i in range(8)]) + self._F("x^6 + x^5 + x + 1") if algorithm == 'decrypt': var = self.state_vrs[row, col] coeffs = self._sb_D_coeffs - result = (sum([coeffs[i] * var**(2**i) for i in range(8)]) + - self._F("x^2 + 1")) + result = sum([coeffs[i] * var ** (2**i) for i in range(8)]) + self._F("x^2 + 1") if no_inversion: return result - return result ** 254 - raise ValueError("keyword 'algorithm' must be either 'encrypt' " - "or 'decrypt'") + return result**254 + raise ValueError("keyword 'algorithm' must be either 'encrypt' " "or 'decrypt'") def _srd(self, el, algorithm='encrypt'): r""" @@ -1889,14 +1784,13 @@ def _srd(self, el, algorithm='encrypt'): """ if algorithm == 'encrypt': p = self._sub_bytes_rcpc(0, 0, algorithm) - state = [el] + [self._F.zero()]*((4 * self._Nb)-1) + state = [el] + [self._F.zero()] * ((4 * self._Nb) - 1) return p(state) if algorithm == 'decrypt': p = self._sub_bytes_rcpc(0, 0, algorithm, no_inversion=True) - state = [el] + [self._F.zero()]*((4 * self._Nb)-1) + state = [el] + [self._F.zero()] * ((4 * self._Nb) - 1) return p(state) ** 254 - raise ValueError("keyword 'algorithm' must be either 'encrypt' " - "or 'decrypt'") + raise ValueError("keyword 'algorithm' must be either 'encrypt' " "or 'decrypt'") def sub_bytes(self, state, algorithm='encrypt'): r""" @@ -1995,9 +1889,8 @@ def _mix_columns_pc(self, row, col, algorithm='encrypt'): elif algorithm == 'decrypt': coeffs = self._mixcols_D else: - raise ValueError("keyword 'algorithm' must be either 'encrypt' " - "or 'decrypt'") - return sum([coeffs[row,k] * self.state_vrs[k,col] for k in range(4)]) + raise ValueError("keyword 'algorithm' must be either 'encrypt' " "or 'decrypt'") + return sum([coeffs[row, k] * self.state_vrs[k, col] for k in range(4)]) def mix_columns(self, state, algorithm='encrypt'): r""" @@ -2094,8 +1987,7 @@ def _shift_rows_pc(self, row, col, algorithm='encrypt'): elif algorithm == 'decrypt': offs = self._shiftrows_offsets_D else: - raise ValueError("keyword 'algorithm' must be either 'encrypt' " - "or 'decrypt'") + raise ValueError("keyword 'algorithm' must be either 'encrypt' " "or 'decrypt'") return self.state_vrs[row, (col + offs[4 - self._Nb][row]) % 4] def shift_rows(self, state, algorithm='encrypt'): @@ -2239,19 +2131,16 @@ def __init__(self, polynomial_constr, rgf, round_component_name=None): if pc_args[0][0] == 'self': # Check number of defaulted arguments if len(pc_args[3]) != len(pc_args[0]) - 3: - msg = ("keyword 'polynomial_constr' must be callable as: " - "polynomial_constr(row, col, algorithm='encrypt')") + msg = "keyword 'polynomial_constr' must be callable as: " "polynomial_constr(row, col, algorithm='encrypt')" raise TypeError(msg) else: if len(pc_args[3]) != len(pc_args[0]) - 2: - msg = ("keyword 'polynomial_constr' must be callable as: " - "polynomial_constr(row, col, algorithm='encrypt')") + msg = "keyword 'polynomial_constr' must be callable as: " "polynomial_constr(row, col, algorithm='encrypt')" raise TypeError(msg) self._polynomial_constr = polynomial_constr self._Nb = rgf.block_length() self._rgf_name = rgf.__repr__() - if round_component_name is not None and \ - not isinstance(round_component_name, str): + if round_component_name is not None and not isinstance(round_component_name, str): msg = "round_component_name must be None or a string" raise TypeError(msg) self._rc_name = round_component_name @@ -2297,8 +2186,7 @@ def __call__(self, row, col, algorithm='encrypt', **kwargs): msg = "keyword 'col' must be in range 0 - {0}" raise ValueError(msg.format(self._Nb - 1)) if algorithm not in ['encrypt', 'decrypt']: - msg = ("keyword 'algorithm' must be either 'encrypt' or " - "'decrypt'") + msg = "keyword 'algorithm' must be either 'encrypt' or " "'decrypt'" print(algorithm) raise ValueError(msg) return self._polynomial_constr(row, col, algorithm, **kwargs) diff --git a/src/sage/crypto/mq/sbox.py b/src/sage/crypto/mq/sbox.py index b05411fe0d3..411af9a4c28 100644 --- a/src/sage/crypto/mq/sbox.py +++ b/src/sage/crypto/mq/sbox.py @@ -1,6 +1,3 @@ from sage.misc.lazy_import import lazy_import -lazy_import('sage.crypto.sbox', ['SBox', - 'feistel_construction', - 'misty_construction'], - deprecation=22986) +lazy_import('sage.crypto.sbox', ['SBox', 'feistel_construction', 'misty_construction'], deprecation=22986) diff --git a/src/sage/crypto/mq/sr.py b/src/sage/crypto/mq/sr.py index cc2e634f6f3..21de1dbacb4 100644 --- a/src/sage/crypto/mq/sr.py +++ b/src/sage/crypto/mq/sr.py @@ -316,8 +316,7 @@ from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF from sage.rings.integer_ring import ZZ from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence -from sage.rings.polynomial.polynomial_ring_constructor import \ - BooleanPolynomialRing_constructor as BooleanPolynomialRing +from sage.rings.polynomial.polynomial_ring_constructor import BooleanPolynomialRing_constructor as BooleanPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.term_order import TermOrder from sage.structure.element import Matrix @@ -433,7 +432,7 @@ def __init__(self, n=1, r=1, c=1, e=4, star=False, **kwargs): A 4 4 1 1 8 3 3 """ - if n-1 not in range(10): + if n - 1 not in range(10): raise TypeError("n must be between 1 and 10 (inclusive)") self._n = n @@ -638,8 +637,7 @@ def __eq__(self, other): sage: sr1 == sr2 False """ - for name in ['n', 'r', 'c', 'e', '_postfix', '_order', - '_allow_zero_inversions', '_aes_mode', '_gf2', '_star']: + for name in ['n', 'r', 'c', 'e', '_postfix', '_order', '_allow_zero_inversions', '_aes_mode', '_gf2', '_star']: lx = getattr(self, name) rx = getattr(other, name) if lx != rx: @@ -731,26 +729,16 @@ def sub_byte(self, b): k = self.k # inversion - b = b ** ( 2**e - 2 ) + b = b ** (2**e - 2) # GF(2) linear map if e == 4: if not hasattr(self, "_L"): - self._L = matrix(GF(2), 4, 4, [[1, 1, 1, 0], - [0, 1, 1, 1], - [1, 0, 1, 1], - [1, 1, 0, 1]]) + self._L = matrix(GF(2), 4, 4, [[1, 1, 1, 0], [0, 1, 1, 1], [1, 0, 1, 1], [1, 1, 0, 1]]) elif e == 8: if not hasattr(self, "_L"): - self._L = matrix(GF(2), 8, 8, [[1, 0, 0, 0, 1, 1, 1, 1], - [1, 1, 0, 0, 0, 1, 1, 1], - [1, 1, 1, 0, 0, 0, 1, 1], - [1, 1, 1, 1, 0, 0, 0, 1], - [1, 1, 1, 1, 1, 0, 0, 0], - [0, 1, 1, 1, 1, 1, 0, 0], - [0, 0, 1, 1, 1, 1, 1, 0], - [0, 0, 0, 1, 1, 1, 1, 1]]) + self._L = matrix(GF(2), 8, 8, [[1, 0, 0, 0, 1, 1, 1, 1], [1, 1, 0, 0, 0, 1, 1, 1], [1, 1, 1, 0, 0, 0, 1, 1], [1, 1, 1, 1, 0, 0, 0, 1], [1, 1, 1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1, 1]]) b = k(self._L * b._vector_()) @@ -902,7 +890,7 @@ def shift_rows(self, d): d = self.state_array(d) ret = [] for i in range(d.nrows()): - ret += list(d.row(i)[i % d.ncols():]) + list(d.row(i)[:i % d.ncols()]) + ret += list(d.row(i)[i % d.ncols() :]) + list(d.row(i)[: i % d.ncols()]) return matrix(self.base_ring(), self._r, self._c, ret) def mix_columns(self, d): @@ -938,14 +926,10 @@ def mix_columns(self, d): if r == 1: M = matrix(self.base_ring(), 1, 1, [[1]]) elif r == 2: - M = matrix(self.base_ring(), 2, 2, [[a + 1, a], - [a, a + 1]]) + M = matrix(self.base_ring(), 2, 2, [[a + 1, a], [a, a + 1]]) elif r == 4: - M = matrix(self.base_ring(), 4, 4, [[a, a+1, 1, 1], - [1, a, a+1, 1], - [1, 1, a, a+1], - [a+1, 1, 1, a]]) + M = matrix(self.base_ring(), 4, 4, [[a, a + 1, 1, 1], [1, a, a + 1, 1], [1, 1, a, a + 1], [a + 1, 1, 1, a]]) ret = [] for column in d.columns(): ret.append(M * column) @@ -974,7 +958,7 @@ def add_round_key(self, d, key): d = self.state_array(d) key = self.state_array(key) - return d+key + return d + key def state_array(self, d=None): """ @@ -1013,7 +997,7 @@ def state_array(self, d=None): return matrix(k, r, c) if isinstance(d, Matrix): - if d.nrows() == r*c*e: + if d.nrows() == r * c * e: return matrix(k, c, r, self.antiphi(d).list()).transpose() if d.ncols() == c and d.nrows() == r and d.base_ring() == k: return d @@ -1040,10 +1024,7 @@ def is_state_array(self, d): sage: sr.is_state_array( matrix(k, 4, 4) ) False """ - return isinstance(d, Matrix) and \ - d.nrows() == self.r and \ - d.ncols() == self.c and \ - d.base_ring() == self.base_ring() + return isinstance(d, Matrix) and d.nrows() == self.r and d.ncols() == self.c and d.base_ring() == self.base_ring() def random_state_array(self, *args, **kwds): r""" @@ -1134,26 +1115,26 @@ def key_schedule(self, kj, i): a = F.gen() SubByte = self.sub_byte - rc = matrix(F, r, c, ([a**(i-1)] * c) + [F(0)]*((r-1)*c) ) + rc = matrix(F, r, c, ([a ** (i - 1)] * c) + [F(0)] * ((r - 1) * c)) ki = matrix(F, r, c) if r == 1: - s0 = SubByte(kj[0, c-1]) + s0 = SubByte(kj[0, c - 1]) if c > 1: for q in range(c): - ki[0, q] = s0 + sum([kj[0, t] for t in range(q+1) ]) + ki[0, q] = s0 + sum([kj[0, t] for t in range(q + 1)]) else: ki[0, 0] = s0 elif r == 2: - s0 = SubByte(kj[1, c-1]) - s1 = SubByte(kj[0, c-1]) + s0 = SubByte(kj[1, c - 1]) + s1 = SubByte(kj[0, c - 1]) if c > 1: for q in range(c): - ki[0, q] = s0 + sum([ kj[0, t] for t in range(q+1) ]) - ki[1, q] = s1 + sum([ kj[1, t] for t in range(q+1) ]) + ki[0, q] = s0 + sum([kj[0, t] for t in range(q + 1)]) + ki[1, q] = s1 + sum([kj[1, t] for t in range(q + 1)]) else: ki[0, 0] = s0 ki[1, 0] = s1 @@ -1161,22 +1142,22 @@ def key_schedule(self, kj, i): elif r == 4: if self._aes_mode: - s0 = SubByte(kj[1, c-1]) - s1 = SubByte(kj[2, c-1]) - s2 = SubByte(kj[3, c-1]) - s3 = SubByte(kj[0, c-1]) + s0 = SubByte(kj[1, c - 1]) + s1 = SubByte(kj[2, c - 1]) + s2 = SubByte(kj[3, c - 1]) + s3 = SubByte(kj[0, c - 1]) else: - s0 = SubByte(kj[3, c-1]) - s1 = SubByte(kj[2, c-1]) - s2 = SubByte(kj[1, c-1]) - s3 = SubByte(kj[0, c-1]) + s0 = SubByte(kj[3, c - 1]) + s1 = SubByte(kj[2, c - 1]) + s2 = SubByte(kj[1, c - 1]) + s3 = SubByte(kj[0, c - 1]) if c > 1: for q in range(c): - ki[0, q] = s0 + sum([ kj[0, t] for t in range(q+1) ]) - ki[1, q] = s1 + sum([ kj[1, t] for t in range(q+1) ]) - ki[2, q] = s2 + sum([ kj[2, t] for t in range(q+1) ]) - ki[3, q] = s3 + sum([ kj[3, t] for t in range(q+1) ]) + ki[0, q] = s0 + sum([kj[0, t] for t in range(q + 1)]) + ki[1, q] = s1 + sum([kj[1, t] for t in range(q + 1)]) + ki[2, q] = s2 + sum([kj[2, t] for t in range(q + 1)]) + ki[3, q] = s3 + sum([kj[3, t] for t in range(q + 1)]) else: ki[0, 0] = s0 @@ -1279,21 +1260,21 @@ def __call__(self, P, K): F = self.base_ring() if isinstance(P, str): - P = self.state_array([F.from_integer(ZZ(P[i: i + 2], 16)) for i in range(0, len(P), 2)]) + P = self.state_array([F.from_integer(ZZ(P[i : i + 2], 16)) for i in range(0, len(P), 2)]) if isinstance(K, str): - K = self.state_array([F.from_integer(ZZ(K[i: i + 2], 16)) for i in range(0, len(K), 2)]) + K = self.state_array([F.from_integer(ZZ(K[i : i + 2], 16)) for i in range(0, len(K), 2)]) if self.is_state_array(P) and self.is_state_array(K): _type = self.state_array elif self.is_vector(P) and self.is_vector(K): _type = self.vector - elif isinstance(P, (list,tuple)) and isinstance(K, (list,tuple)): - if len(P) == len(K) == r*c: + elif isinstance(P, (list, tuple)) and isinstance(K, (list, tuple)): + if len(P) == len(K) == r * c: _type = self.state_array - elif len(P) == len(K) == r*c*e: + elif len(P) == len(K) == r * c * e: _type = self.vector else: - raise TypeError("length %d or %d doesn't match either %d or %d" % (len(P),len(K),r*c,r*c*e)) + raise TypeError("length %d or %d doesn't match either %d or %d" % (len(P), len(K), r * c, r * c * e)) else: raise TypeError("plaintext or key parameter not understood") @@ -1308,25 +1289,25 @@ def __call__(self, P, K): P = AddRoundKey(P, K) - for r in range(self._n-1): + for r in range(self._n - 1): if get_verbose() >= 2: - print("R[%02d].start %s" % (r+1, self.hex_str_vector(P))) + print("R[%02d].start %s" % (r + 1, self.hex_str_vector(P))) P = SubBytes(P) if get_verbose() >= 2: - print("R[%02d].s_box %s" % (r+1, self.hex_str_vector(P))) + print("R[%02d].s_box %s" % (r + 1, self.hex_str_vector(P))) P = ShiftRows(P) if get_verbose() >= 2: - print("R[%02d].s_row %s" % (r+1, self.hex_str_vector(P))) + print("R[%02d].s_row %s" % (r + 1, self.hex_str_vector(P))) P = MixColumns(P) if get_verbose() >= 2: - print("R[%02d].m_col %s" % (r+1, self.hex_str_vector(P))) + print("R[%02d].m_col %s" % (r + 1, self.hex_str_vector(P))) - K = KeyExpansion(K, r+1) + K = KeyExpansion(K, r + 1) if get_verbose() >= 2: - print("R[%02d].k_sch %s" % (r+1, self.hex_str_vector(K))) + print("R[%02d].k_sch %s" % (r + 1, self.hex_str_vector(K))) P = AddRoundKey(P, K) @@ -1438,7 +1419,7 @@ def hex_str_vector(self, M): st.append("%02X" % M[x, y].to_integer()) else: st.append("%X" % M[x, y].to_integer()) - #st.append("\n") + # st.append("\n") return "".join(st) def _insert_matrix_into_matrix(self, dst, src, row, col): @@ -1475,7 +1456,7 @@ def _insert_matrix_into_matrix(self, dst, src, row, col): """ for i in range(src.nrows()): for j in range(src.ncols()): - dst[row+i, col+j] = src[i, j] + dst[row + i, col + j] = src[i, j] return dst def varformatstr(self, name, n=None, rc=None, e=None): @@ -1509,7 +1490,7 @@ def varformatstr(self, name, n=None, rc=None, e=None): if e is None: e = self.e - l = str(max([ len(str(rc-1)), len(str(n-1)), len(str(e-1)) ] )) + l = str(max([len(str(rc - 1)), len(str(n - 1)), len(str(e - 1))])) if name not in ("k", "s"): pf = self._postfix else: @@ -1535,7 +1516,7 @@ def varstr(self, name, nr, rc, e): sage: sr.varstr('x', 2, 1, 1) 'x211' """ - format_string = self.varformatstr(name, self.n, self.r*self.c, self.e) + format_string = self.varformatstr(name, self.n, self.r * self.c, self.e) return format_string % (nr, rc, e) def varstrs(self, name, nr, rc=None, e=None): @@ -1641,7 +1622,7 @@ def variable_dict(self): 'x103': x103} """ try: - R,gd = self._variable_dict + R, gd = self._variable_dict if R is self.R: return gd pass @@ -1649,7 +1630,7 @@ def variable_dict(self): pass gd = self.R.gens_dict() - self._variable_dict = self.R,gd + self._variable_dict = self.R, gd return gd def block_order(self): @@ -1686,9 +1667,9 @@ def block_order(self): T = None for _n in range(n): - T = TermOrder('deglex', r*e + 3*r*c*e ) + T + T = TermOrder('deglex', r * e + 3 * r * c * e) + T - T += TermOrder('deglex', r*c*e) + T += TermOrder('deglex', r * c * e) return T @@ -1760,22 +1741,22 @@ def ring(self, order=None, reverse_variables=None): if reverse_variables: names = [] else: - names = self.varstrs("k", 0, r*c, e) + names = self.varstrs("k", 0, r * c, e) for _n in process(list(range(n))): - names += self.varstrs("k", _n+1, r*c, e) - names += self.varstrs("x", _n+1, r*c, e) - names += self.varstrs("w", _n+1, r*c, e) + names += self.varstrs("k", _n + 1, r * c, e) + names += self.varstrs("x", _n + 1, r * c, e) + names += self.varstrs("w", _n + 1, r * c, e) names += self.varstrs("s", _n, r, e) if reverse_variables: - names += self.varstrs("k", 0, r*c, e) + names += self.varstrs("k", 0, r * c, e) - #from sage.rings.polynomial.pbori.pbori import BooleanPolynomialRing + # from sage.rings.polynomial.pbori.pbori import BooleanPolynomialRing if self._gf2 and self._polybori: - return BooleanPolynomialRing(2*n*r*c*e + (n+1)*r*c*e + n*r*e, names, order=self._order) - return PolynomialRing(k, 2*n*r*c*e + (n+1)*r*c*e + n*r*e, names, order=self._order) + return BooleanPolynomialRing(2 * n * r * c * e + (n + 1) * r * c * e + n * r * e, names, order=self._order) + return PolynomialRing(k, 2 * n * r * c * e + (n + 1) * r * c * e + n * r * e, names, order=self._order) def round_polynomials(self, i, plaintext=None, ciphertext=None): r""" @@ -1813,10 +1794,10 @@ def round_polynomials(self, i, plaintext=None, ciphertext=None): _vars = self.vars if i == 0: - w1 = matrix(R, r*c*e, 1, _vars("w", 1, r*c, e)) - k0 = matrix(R, r*c*e, 1, _vars("k", 0, r*c, e)) - if isinstance(plaintext, (tuple, list)) and len(plaintext) == r*c: - plaintext = matrix(R, r*c*e, 1, self.phi(plaintext)) + w1 = matrix(R, r * c * e, 1, _vars("w", 1, r * c, e)) + k0 = matrix(R, r * c * e, 1, _vars("k", 0, r * c, e)) + if isinstance(plaintext, (tuple, list)) and len(plaintext) == r * c: + plaintext = matrix(R, r * c * e, 1, self.phi(plaintext)) return tuple((w1 + k0 + plaintext).list()) if i > 0 and i <= n: @@ -1824,23 +1805,23 @@ def round_polynomials(self, i, plaintext=None, ciphertext=None): if self._star and i == n: M = self.Mstar - xj = matrix(R, r*c*e, 1, _vars("x", i, r*c, e)) - ki = matrix(R, r*c*e, 1, _vars("k", i, r*c, e)) - rcon = matrix(R, r*c*e, 1, self.phi([self.sbox_constant()]*r*c)) + xj = matrix(R, r * c * e, 1, _vars("x", i, r * c, e)) + ki = matrix(R, r * c * e, 1, _vars("k", i, r * c, e)) + rcon = matrix(R, r * c * e, 1, self.phi([self.sbox_constant()] * r * c)) if i < n: - wj = matrix(R, r*c*e, 1, _vars("w", i+1, r*c, e)) + wj = matrix(R, r * c * e, 1, _vars("w", i + 1, r * c, e)) if i == n: - if isinstance(ciphertext, (tuple, list)) and len(ciphertext) == r*c: - ciphertext = matrix(R, r*c*e, 1, self.phi(ciphertext)) + if isinstance(ciphertext, (tuple, list)) and len(ciphertext) == r * c: + ciphertext = matrix(R, r * c * e, 1, self.phi(ciphertext)) wj = ciphertext lin = (wj + ki + M * xj + rcon).list() - wi = matrix(R, r*c*e, 1, _vars("w", i, r*c, e)) - xi = matrix(R, r*c*e, 1, _vars("x", i, r*c, e)) + wi = matrix(R, r * c * e, 1, _vars("w", i, r * c, e)) + xi = matrix(R, r * c * e, 1, _vars("x", i, r * c, e)) sbox = [] - sbox += self.inversion_polynomials(xi, wi, r*c*e) + sbox += self.inversion_polynomials(xi, wi, r * c * e) sbox += self.field_polynomials("x", i) sbox += self.field_polynomials("w", i) return tuple(lin + sbox) @@ -1898,43 +1879,43 @@ def key_schedule_polynomials(self, i): raise TypeError("i must by >= 0") if i == 0: - return tuple(self.field_polynomials("k", i, r*c)) + return tuple(self.field_polynomials("k", i, r * c)) L = self.lin_matrix(r) - ki = matrix(R, r*c*e, 1, self.vars("k", i , r*c, e)) - kj = matrix(R, r*c*e, 1, self.vars("k", i-1, r*c, e)) - si = matrix(R, r*e, 1, self.vars("s", i-1, r, e)) + ki = matrix(R, r * c * e, 1, self.vars("k", i, r * c, e)) + kj = matrix(R, r * c * e, 1, self.vars("k", i - 1, r * c, e)) + si = matrix(R, r * e, 1, self.vars("s", i - 1, r, e)) - rc = matrix(R, r*e, 1, self.phi([a**(i-1)] + [k(0)]*(r-1)) ) - d = matrix(R, r*e, 1, self.phi([self.sbox_constant()]*r) ) + rc = matrix(R, r * e, 1, self.phi([a ** (i - 1)] + [k(0)] * (r - 1))) + d = matrix(R, r * e, 1, self.phi([self.sbox_constant()] * r)) sbox = [] sbox += self.field_polynomials("k", i) - sbox += self.field_polynomials("s", i-1, r) + sbox += self.field_polynomials("s", i - 1, r) if r == 1: - sbox += self.inversion_polynomials(kj[(c - 1)*e:(c - 1)*e + e], si[0:e], e) + sbox += self.inversion_polynomials(kj[(c - 1) * e : (c - 1) * e + e], si[0:e], e) if r == 2: - sbox += self.inversion_polynomials( kj[(2*c - 1)*e : (2*c - 1)*e + e] , si[0:1*e], e ) - sbox += self.inversion_polynomials( kj[(2*c - 2)*e : (2*c - 2)*e + e] , si[e:2*e], e ) + sbox += self.inversion_polynomials(kj[(2 * c - 1) * e : (2 * c - 1) * e + e], si[0 : 1 * e], e) + sbox += self.inversion_polynomials(kj[(2 * c - 2) * e : (2 * c - 2) * e + e], si[e : 2 * e], e) if r == 4: if self._aes_mode: - sbox += self.inversion_polynomials( kj[(4*c-3)*e : (4*c-3)*e + e] , si[0*e : 1*e] , e ) - sbox += self.inversion_polynomials( kj[(4*c-2)*e : (4*c-2)*e + e] , si[1*e : 2*e] , e ) - sbox += self.inversion_polynomials( kj[(4*c-1)*e : (4*c-1)*e + e] , si[2*e : 3*e] , e ) - sbox += self.inversion_polynomials( kj[(4*c-4)*e : (4*c-4)*e + e] , si[3*e : 4*e] , e ) + sbox += self.inversion_polynomials(kj[(4 * c - 3) * e : (4 * c - 3) * e + e], si[0 * e : 1 * e], e) + sbox += self.inversion_polynomials(kj[(4 * c - 2) * e : (4 * c - 2) * e + e], si[1 * e : 2 * e], e) + sbox += self.inversion_polynomials(kj[(4 * c - 1) * e : (4 * c - 1) * e + e], si[2 * e : 3 * e], e) + sbox += self.inversion_polynomials(kj[(4 * c - 4) * e : (4 * c - 4) * e + e], si[3 * e : 4 * e], e) else: - sbox += self.inversion_polynomials( kj[(4*c-1)*e : (4*c-1)*e + e] , si[0*e : 1*e] , e ) - sbox += self.inversion_polynomials( kj[(4*c-2)*e : (4*c-2)*e + e] , si[1*e : 2*e] , e ) - sbox += self.inversion_polynomials( kj[(4*c-3)*e : (4*c-3)*e + e] , si[2*e : 3*e] , e ) - sbox += self.inversion_polynomials( kj[(4*c-4)*e : (4*c-4)*e + e] , si[3*e : 4*e] , e ) + sbox += self.inversion_polynomials(kj[(4 * c - 1) * e : (4 * c - 1) * e + e], si[0 * e : 1 * e], e) + sbox += self.inversion_polynomials(kj[(4 * c - 2) * e : (4 * c - 2) * e + e], si[1 * e : 2 * e], e) + sbox += self.inversion_polynomials(kj[(4 * c - 3) * e : (4 * c - 3) * e + e], si[2 * e : 3 * e], e) + sbox += self.inversion_polynomials(kj[(4 * c - 4) * e : (4 * c - 4) * e + e], si[3 * e : 4 * e], e) si = L * si + d + rc - Sum = matrix(R, r*e, 1) + Sum = matrix(R, r * e, 1) lin = [] if c > 1: for q in range(c): - t = list(range(r*e*(q) , r*e*(q+1))) + t = list(range(r * e * (q), r * e * (q + 1))) Sum += kj.matrix_from_rows(t) lin += (ki.matrix_from_rows(t) + si + Sum).list() @@ -2041,27 +2022,27 @@ def polynomial_system(self, P=None, K=None, C=None): data = [] R = self.R - r,c,e = self.r,self.c,self.e + r, c, e = self.r, self.c, self.e for d in (plaintext, key, ciphertext): if d is None: - data.append( None ) + data.append(None) elif isinstance(d, (tuple, list)): if isinstance(d[0], int): d = [GF(2)(_) for _ in d] - if len(d) == r*c*e and (d[0].parent() is R or d[0].parent() == R): - data.append( matrix(R,r*c*e,1,d) ) + if len(d) == r * c * e and (d[0].parent() is R or d[0].parent() == R): + data.append(matrix(R, r * c * e, 1, d)) continue try: - data.append( self.phi(self.state_array(d)) ) - except ValueError: # GF2 vectors maybe? - data.append( self.vector(d) ) + data.append(self.phi(self.state_array(d))) + except ValueError: # GF2 vectors maybe? + data.append(self.vector(d)) elif self.is_state_array(d): - data.append( self.phi(d) ) + data.append(self.phi(d)) elif self.is_vector(d): - data.append( d ) + data.append(d) else: - data.append( False ) + data.append(False) plaintext, key, ciphertext = data @@ -2080,9 +2061,9 @@ def polynomial_system(self, P=None, K=None, C=None): elif ciphertext is False: raise TypeError("type %s of C not understood" % (type(ciphertext))) - for i in range(n+1): - system.append( self.round_polynomials(i, plaintext, ciphertext) ) - system.append( self.key_schedule_polynomials(i) ) + for i in range(n + 1): + system.append(self.round_polynomials(i, plaintext, ciphertext)) + system.append(self.key_schedule_polynomials(i)) if key is not None: K = dict(zip(self.vars("k", 0), key.list())) @@ -2096,6 +2077,7 @@ class SR_gf2n(SR_generic): Small Scale Variants of the AES polynomial system constructor over `\GF{2^n}`. """ + def vector(self, d=None): """ Construct a vector suitable for the algebraic representation of @@ -2125,9 +2107,9 @@ def vector(self, d=None): k = self.base_ring() if d is None: - return matrix(k, r*c*e, 1) + return matrix(k, r * c * e, 1) if d.ncols() == c and d.nrows() == r and d.base_ring() == k: - return matrix(k, r*c*e, 1, self.phi(d).transpose().list()) + return matrix(k, r * c * e, 1, self.phi(d).transpose().list()) def is_vector(self, d): """ @@ -2146,10 +2128,7 @@ def is_vector(self, d): sage: sr.is_vector(B) True """ - return isinstance(d, Matrix) and \ - d.nrows() == self.r*self.c*self.e and \ - d.ncols() == 1 and \ - d.base_ring() == self.base_ring() + return isinstance(d, Matrix) and d.nrows() == self.r * self.c * self.e and d.ncols() == 1 and d.base_ring() == self.base_ring() def phi(self, l): r""" @@ -2175,16 +2154,16 @@ def phi(self, l): ret = [] if isinstance(l, Matrix): for e in l.transpose().list(): - ret += [e**(2**i) for i in range(self.e)] + ret += [e ** (2**i) for i in range(self.e)] else: for e in l: - ret += [e**(2**i) for i in range(self.e)] + ret += [e ** (2**i) for i in range(self.e)] if isinstance(l, list): return ret if isinstance(l, tuple): return tuple(ret) if isinstance(l, Matrix): - return matrix(l.base_ring(), l.ncols(), l.nrows()*self.e, ret).transpose() + return matrix(l.base_ring(), l.ncols(), l.nrows() * self.e, ret).transpose() raise TypeError def antiphi(self, l): @@ -2203,17 +2182,16 @@ def antiphi(self, l): True """ if isinstance(l, Matrix): - ret = l.transpose().list()[0:-1:self.e] + ret = l.transpose().list()[0 : -1 : self.e] else: - ret = l[0:-1:self.e] + ret = l[0 : -1 : self.e] if isinstance(l, list): return ret if isinstance(l, tuple): return tuple(ret) if isinstance(l, Matrix): - return matrix(self.base_ring(), l.ncols(), l.nrows() // self.e, - ret).transpose() + return matrix(self.base_ring(), l.ncols(), l.nrows() // self.e, ret).transpose() raise TypeError def shift_rows_matrix(self): @@ -2233,13 +2211,13 @@ def shift_rows_matrix(self): r = self.r c = self.c k = self.base_ring() - bs = r*c*e + bs = r * c * e shift_rows = matrix(k, bs, bs) I = MatrixSpace(k, e, e)(1) for x in range(c): for y in range(r): - _r = ((x*r)+y) * e - _c = (((x*r)+((r+1)*y)) * e) % bs + _r = ((x * r) + y) * e + _c = (((x * r) + ((r + 1) * y)) * e) % bs self._insert_matrix_into_matrix(shift_rows, I, _r, _c) return shift_rows @@ -2272,21 +2250,21 @@ def lin_matrix(self, length=None): k = self.k if length is None: - length = r*c + length = r * c - lin = matrix(self.base_ring(), length*e, length*e) + lin = matrix(self.base_ring(), length * e, length * e) if e == 4: l = [k.from_integer(x) for x in (5, 1, 12, 5)] for k in range(length): for i in range(4): for j in range(4): - lin[k*4+j, k*4+i] = l[(i-j) % 4] ** (2**j) + lin[k * 4 + j, k * 4 + i] = l[(i - j) % 4] ** (2**j) elif e == 8: l = [k.from_integer(x) for x in (5, 9, 249, 37, 244, 1, 181, 143)] for k in range(length): for i in range(8): for j in range(8): - lin[k*8+j, k*8+i] = l[(i-j) % 8] ** (2**j) + lin[k * 8 + j, k * 8 + i] = l[(i - j) % 8] ** (2**j) return lin @@ -2324,7 +2302,7 @@ def D(b): """ D = matrix(self.base_ring(), self._e, self._e) for i in range(self._e): - D[i, i] = b**(2**i) + D[i, i] = b ** (2**i) return D r = self.r @@ -2333,42 +2311,42 @@ def D(b): k = self.k a = k.gen() - M = matrix(k, r*e, r*e) + M = matrix(k, r * e, r * e) if r == 1: - self._insert_matrix_into_matrix(M, D(1), 0, 0) + self._insert_matrix_into_matrix(M, D(1), 0, 0) elif r == 2: - self._insert_matrix_into_matrix(M, D(a+1), 0, 0) - self._insert_matrix_into_matrix(M, D(a+1), e, e) - self._insert_matrix_into_matrix(M, D(a), e, 0) - self._insert_matrix_into_matrix(M, D(a), 0, e) + self._insert_matrix_into_matrix(M, D(a + 1), 0, 0) + self._insert_matrix_into_matrix(M, D(a + 1), e, e) + self._insert_matrix_into_matrix(M, D(a), e, 0) + self._insert_matrix_into_matrix(M, D(a), 0, e) elif r == 4: - self._insert_matrix_into_matrix(M, D(a), 0, 0) - self._insert_matrix_into_matrix(M, D(a), e, e) - self._insert_matrix_into_matrix(M, D(a), 2*e, 2*e) - self._insert_matrix_into_matrix(M, D(a), 3*e, 3*e) + self._insert_matrix_into_matrix(M, D(a), 0, 0) + self._insert_matrix_into_matrix(M, D(a), e, e) + self._insert_matrix_into_matrix(M, D(a), 2 * e, 2 * e) + self._insert_matrix_into_matrix(M, D(a), 3 * e, 3 * e) - self._insert_matrix_into_matrix(M, D(a+1), 0, e) - self._insert_matrix_into_matrix(M, D(a+1), e, 2*e) - self._insert_matrix_into_matrix(M, D(a+1), 2*e, 3*e) - self._insert_matrix_into_matrix(M, D(a+1), 3*e, 0) + self._insert_matrix_into_matrix(M, D(a + 1), 0, e) + self._insert_matrix_into_matrix(M, D(a + 1), e, 2 * e) + self._insert_matrix_into_matrix(M, D(a + 1), 2 * e, 3 * e) + self._insert_matrix_into_matrix(M, D(a + 1), 3 * e, 0) - self._insert_matrix_into_matrix(M, D(1), 0, 2*e) - self._insert_matrix_into_matrix(M, D(1), e, 3*e) - self._insert_matrix_into_matrix(M, D(1), 2*e, 0) - self._insert_matrix_into_matrix(M, D(1), 3*e, 1*e) + self._insert_matrix_into_matrix(M, D(1), 0, 2 * e) + self._insert_matrix_into_matrix(M, D(1), e, 3 * e) + self._insert_matrix_into_matrix(M, D(1), 2 * e, 0) + self._insert_matrix_into_matrix(M, D(1), 3 * e, 1 * e) - self._insert_matrix_into_matrix(M, D(1), 0, 3*e) - self._insert_matrix_into_matrix(M, D(1), e, 0) - self._insert_matrix_into_matrix(M, D(1), 2*e, 1*e) - self._insert_matrix_into_matrix(M, D(1), 3*e, 2*e) + self._insert_matrix_into_matrix(M, D(1), 0, 3 * e) + self._insert_matrix_into_matrix(M, D(1), e, 0) + self._insert_matrix_into_matrix(M, D(1), 2 * e, 1 * e) + self._insert_matrix_into_matrix(M, D(1), 3 * e, 2 * e) - mix_columns = matrix(k, r*c*e, r*c*e) + mix_columns = matrix(k, r * c * e, r * c * e) for i in range(c): - self._insert_matrix_into_matrix(mix_columns, M, r*e*i, r*e*i) + self._insert_matrix_into_matrix(mix_columns, M, r * e * i, r * e * i) return mix_columns @@ -2400,7 +2378,7 @@ def inversion_polynomials(self, xi, wi, length): x106*w106 + 1, x107*w107 + 1] """ - return [xi[j, 0]*wi[j, 0] + 1 for j in range(length)] + return [xi[j, 0] * wi[j, 0] + 1 for j in range(length)] def field_polynomials(self, name, i, l=None): r""" @@ -2431,10 +2409,10 @@ def field_polynomials(self, name, i, l=None): e = self._e if l is None: - l = r*c + l = r * c _vars = self.vars(name, i, l, e) - return [_vars[e*j+k]**2 - _vars[e*j+(k+1) % e] for j in range(l) for k in range(e)] + return [_vars[e * j + k] ** 2 - _vars[e * j + (k + 1) % e] for j in range(l) for k in range(e)] class SR_gf2(SR_generic): @@ -2481,16 +2459,16 @@ def vector(self, d=None): k = GF(2) if d is None: - return matrix(k, r*c*e, 1) + return matrix(k, r * c * e, 1) if isinstance(d, Matrix) and d.ncols() == c and d.nrows() == r and d.base_ring() == self.k: - l = flatten([self.phi(x) for x in d.transpose().list()], (Vector_modn_dense,list,tuple)) - return matrix(k, r*c*e, 1, l) + l = flatten([self.phi(x) for x in d.transpose().list()], (Vector_modn_dense, list, tuple)) + return matrix(k, r * c * e, 1, l) if isinstance(d, (list, tuple)): - if len(d) == self.r*self.c: - l = flatten([self.phi(x) for x in d], (Vector_modn_dense,list,tuple)) - return matrix(k, r*c*e, 1, l) - if len(d) == self.r*self.c*self.e: - return matrix(k, r*c*e, 1, d) + if len(d) == self.r * self.c: + l = flatten([self.phi(x) for x in d], (Vector_modn_dense, list, tuple)) + return matrix(k, r * c * e, 1, l) + if len(d) == self.r * self.c * self.e: + return matrix(k, r * c * e, 1, d) raise TypeError else: raise TypeError @@ -2518,10 +2496,7 @@ def is_vector(self, d): sage: sr.is_vector(B) True """ - return isinstance(d, Matrix) and \ - d.nrows() == self.r*self.c*self.e and \ - d.ncols() == 1 and \ - d.base_ring() == GF(2) + return isinstance(d, Matrix) and d.nrows() == self.r * self.c * self.e and d.ncols() == 1 and d.base_ring() == GF(2) def phi(self, l, diffusion_matrix=False): r""" @@ -2552,14 +2527,12 @@ def phi(self, l, diffusion_matrix=False): r, c, e = self.r, self.c, self.e # handle diffusion layer matrices first - if isinstance(l, Matrix) and diffusion_matrix and \ - l.nrows() == r*c and l.ncols() == r*c and \ - l.base_ring() == self.k: - B = matrix(GF(2), r*c*e, r*c*e) - for x in range(r*c): - for y in range(r*c): + if isinstance(l, Matrix) and diffusion_matrix and l.nrows() == r * c and l.ncols() == r * c and l.base_ring() == self.k: + B = matrix(GF(2), r * c * e, r * c * e) + for x in range(r * c): + for y in range(r * c): T = self._mul_matrix(l[x, y]) - self._insert_matrix_into_matrix(B, T, x*e, y*e) + self._insert_matrix_into_matrix(B, T, x * e, y * e) return B # ground field elements @@ -2580,7 +2553,7 @@ def phi(self, l, diffusion_matrix=False): if isinstance(l, tuple): return tuple(ret) if isinstance(l, Matrix): - return matrix(GF(2), l.ncols(), l.nrows()*self.e, ret).transpose() + return matrix(GF(2), l.ncols(), l.nrows() * self.e, ret).transpose() raise TypeError def antiphi(self, l): @@ -2608,7 +2581,7 @@ def antiphi(self, l): ret = [] for i in range(0, len(l2), e): - ret.append( self.k(V(list(reversed(l2[i:i+e])))) ) + ret.append(self.k(V(list(reversed(l2[i : i + e]))))) if isinstance(l, list): return ret @@ -2634,12 +2607,12 @@ def shift_rows_matrix(self): r = self.r c = self.c k = self.k - bs = r*c - shift_rows = matrix(k, r*c, r*c) + bs = r * c + shift_rows = matrix(k, r * c, r * c) for x in range(c): for y in range(r): - _r = ((x*r)+y) - _c = ((x*r)+((r+1)*y)) % bs + _r = (x * r) + y + _c = ((x * r) + ((r + 1) * y)) % bs shift_rows[_r, _c] = 1 return self.phi(shift_rows, diffusion_matrix=True) @@ -2665,18 +2638,15 @@ def mix_columns_matrix(self): M = matrix(k, r, r, 1) elif r == 2: - M = matrix(k, r, r, [a+1, a, a, a+1]) + M = matrix(k, r, r, [a + 1, a, a, a + 1]) elif r == 4: - M = matrix(k, r, [a, a+1, 1, 1, - 1, a, a+1, 1, - 1, 1, a, a+1, - a+1, 1, 1, a]) + M = matrix(k, r, [a, a + 1, 1, 1, 1, a, a + 1, 1, 1, 1, a, a + 1, a + 1, 1, 1, a]) - mix_columns = matrix(k, r*c, r*c) + mix_columns = matrix(k, r * c, r * c) for i in range(c): - self._insert_matrix_into_matrix(mix_columns, M, r*i, r*i) + self._insert_matrix_into_matrix(mix_columns, M, r * i, r * i) return self.phi(mix_columns, diffusion_matrix=True) @@ -2705,29 +2675,19 @@ def lin_matrix(self, length=None): r, c, e = self.r, self.c, self.e if length is None: - length = r*c + length = r * c if e == 8: - Z = matrix(GF(2), 8, 8, [1, 0, 0, 0, 1, 1, 1, 1, - 1, 1, 0, 0, 0, 1, 1, 1, - 1, 1, 1, 0, 0, 0, 1, 1, - 1, 1, 1, 1, 0, 0, 0, 1, - 1, 1, 1, 1, 1, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 0, 0, - 0, 0, 1, 1, 1, 1, 1, 0, - 0, 0, 0, 1, 1, 1, 1, 1]) + Z = matrix(GF(2), 8, 8, [1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1]) else: - Z = matrix(GF(2), 4, 4, [1, 1, 1, 0, - 0, 1, 1, 1, - 1, 0, 1, 1, - 1, 1, 0, 1]) + Z = matrix(GF(2), 4, 4, [1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1]) - Z = Z.transpose() # account for endianess mismatch + Z = Z.transpose() # account for endianess mismatch - lin = matrix(GF(2), length*e, length*e) + lin = matrix(GF(2), length * e, length * e) for i in range(length): - self._insert_matrix_into_matrix(lin, Z, i*e, i*e) + self._insert_matrix_into_matrix(lin, Z, i * e, i * e) return lin def _mul_matrix(self, x): @@ -2757,8 +2717,7 @@ def _mul_matrix(self, x): e = self.e a = k.gen() - columns = [list(reversed((x * a**i)._vector_())) - for i in reversed(range(e))] + columns = [list(reversed((x * a**i)._vector_())) for i in reversed(range(e))] return matrix(GF(2), e, e, columns).transpose() def _square_matrix(self): @@ -2784,8 +2743,8 @@ def _square_matrix(self): columns = [] for i in reversed(range(e)): - columns.append( list(reversed(((a**i)**2)._vector_())) ) - return matrix(GF(2), e , e, columns).transpose() + columns.append(list(reversed(((a**i) ** 2)._vector_()))) + return matrix(GF(2), e, e, columns).transpose() def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, correct_only=None): """ @@ -2858,7 +2817,7 @@ def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, if x is None and w is None: # make sure it prints like in the book. names = ["w%d" % i for i in reversed(range(e))] + ["x%d" % i for i in reversed(range(e))] - P = PolynomialRing(GF(2), e*2, names, order='lex') + P = PolynomialRing(GF(2), e * 2, names, order='lex') x = P.gens()[e:] w = P.gens()[:e] else: @@ -2875,127 +2834,82 @@ def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, w = w.column(0).list() if e == 4: - w3,w2,w1,w0 = w - x3,x2,x1,x0 = x - - l = [w3*x3 + w3*x0 + w2*x1 + w1*x2 + w0*x3, - w3*x3 + w3*x2 + w2*x3 + w2*x0 + w1*x1 + w0*x2, - w3*x2 + w3*x1 + w2*x3 + w2*x2 + w1*x3 + w1*x0 + w0*x1, - w3*x3 + w3*x2 + w3*x0 + w2*x2 + w1*x3 + w1*x1 + w0*x3 + x3, - w3*x1 + w2*x3 + w2*x2 + w2*x0 + w1*x2 + w0*x3 + w0*x1 + x2, - w3*x3 + w3*x2 + w3*x1 + w2*x1 + w1*x3 + w1*x2 + w1*x0 + w0*x2 + x1, - w3*x2 + w2*x3 + w2*x1 + w1*x3 + w0*x2 + w0*x0 + x0, - w3*x3 + w3*x1 + w3*x0 + w3 + w2*x3 + w2*x2 + w1*x1 + w0*x3, - w3*x2 + w3*x0 + w2*x2 + w2*x1 + w2 + w1*x3 + w1*x0 + w0*x2, - w3*x3 + w3*x1 + w2*x3 + w2*x1 + w2*x0 + w1*x3 + w1*x2 + w1 + w0*x1, - w3*x2 + w3*x1 + w2*x3 + w2*x0 + w1*x2 + w0*x0 + w0] + w3, w2, w1, w0 = w + x3, x2, x1, x0 = x + + l = [w3 * x3 + w3 * x0 + w2 * x1 + w1 * x2 + w0 * x3, w3 * x3 + w3 * x2 + w2 * x3 + w2 * x0 + w1 * x1 + w0 * x2, w3 * x2 + w3 * x1 + w2 * x3 + w2 * x2 + w1 * x3 + w1 * x0 + w0 * x1, w3 * x3 + w3 * x2 + w3 * x0 + w2 * x2 + w1 * x3 + w1 * x1 + w0 * x3 + x3, w3 * x1 + w2 * x3 + w2 * x2 + w2 * x0 + w1 * x2 + w0 * x3 + w0 * x1 + x2, w3 * x3 + w3 * x2 + w3 * x1 + w2 * x1 + w1 * x3 + w1 * x2 + w1 * x0 + w0 * x2 + x1, w3 * x2 + w2 * x3 + w2 * x1 + w1 * x3 + w0 * x2 + w0 * x0 + x0, w3 * x3 + w3 * x1 + w3 * x0 + w3 + w2 * x3 + w2 * x2 + w1 * x1 + w0 * x3, w3 * x2 + w3 * x0 + w2 * x2 + w2 * x1 + w2 + w1 * x3 + w1 * x0 + w0 * x2, w3 * x3 + w3 * x1 + w2 * x3 + w2 * x1 + w2 * x0 + w1 * x3 + w1 * x2 + w1 + w0 * x1, w3 * x2 + w3 * x1 + w2 * x3 + w2 * x0 + w1 * x2 + w0 * x0 + w0] if not correct_only: - l.append(w3*x1 + w2*x2 + w1*x3 + w0*x0 + 1) + l.append(w3 * x1 + w2 * x2 + w1 * x3 + w0 * x0 + 1) if not biaffine_only: - l.extend([w3*x2 + w3*x1 + w3*x0 + w2*x3 + w2*x1 + w1*x3 + w1*x2 + w0*x3 + x3**2 + x3*x2 + x3*x1 + x2**2 + x1**2, - w3*x2 + w2*x2 + w2*x1 + w2*x0 + w1*x3 + w1*x1 + w0*x3 + w0*x2 + x3*x2 + x3*x1 + x3*x0 + x2**2 + x2*x1 + x2*x0 + x1*x0, - w3*x2 + w3*x1 + w2*x2 + w1*x2 + w1*x1 + w1*x0 + w0*x3 + w0*x1 + x3**2 + x3*x2 + x2*x0 + x1*x0, - w3*x3 + w3*x1 + w2*x3 + w2*x2 + w1*x3 + w0*x3 + w0*x2 + w0*x1 + w0*x0 + x3*x1 + x2*x1 + x2*x0 + x0**2, - w3**2 + w3*w2 + w3*w1 + w3*x2 + w3*x1 + w3*x0 + w2**2 + w2*x3 + w2*x1 + w1**2 + w1*x3 + w1*x2 + w0*x3, - w3*w2 + w3*w1 + w3*w0 + w3*x1 + w3*x0 + w2**2 + w2*w1 + w2*w0 + w2*x3 + w2*x2 + w2*x0 + w1*w0 + w1*x2 + w1*x1 + w0*x2, - w3**2 + w3*w2 + w3*x0 + w2*w0 + w2*x3 + w2*x2 + w2*x1 + w1*w0 + w1*x3 + w1*x1 + w1*x0 + w0*x1, - w3*w1 + w3*x3 + w3*x2 + w3*x1 + w3*x0 + w2*w1 + w2*w0 + w2*x2 + w2*x0 + w1*x3 + w1*x0 + w0**2 + w0*x0]) + l.extend( + [ + w3 * x2 + w3 * x1 + w3 * x0 + w2 * x3 + w2 * x1 + w1 * x3 + w1 * x2 + w0 * x3 + x3**2 + x3 * x2 + x3 * x1 + x2**2 + x1**2, + w3 * x2 + w2 * x2 + w2 * x1 + w2 * x0 + w1 * x3 + w1 * x1 + w0 * x3 + w0 * x2 + x3 * x2 + x3 * x1 + x3 * x0 + x2**2 + x2 * x1 + x2 * x0 + x1 * x0, + w3 * x2 + w3 * x1 + w2 * x2 + w1 * x2 + w1 * x1 + w1 * x0 + w0 * x3 + w0 * x1 + x3**2 + x3 * x2 + x2 * x0 + x1 * x0, + w3 * x3 + w3 * x1 + w2 * x3 + w2 * x2 + w1 * x3 + w0 * x3 + w0 * x2 + w0 * x1 + w0 * x0 + x3 * x1 + x2 * x1 + x2 * x0 + x0**2, + w3**2 + w3 * w2 + w3 * w1 + w3 * x2 + w3 * x1 + w3 * x0 + w2**2 + w2 * x3 + w2 * x1 + w1**2 + w1 * x3 + w1 * x2 + w0 * x3, + w3 * w2 + w3 * w1 + w3 * w0 + w3 * x1 + w3 * x0 + w2**2 + w2 * w1 + w2 * w0 + w2 * x3 + w2 * x2 + w2 * x0 + w1 * w0 + w1 * x2 + w1 * x1 + w0 * x2, + w3**2 + w3 * w2 + w3 * x0 + w2 * w0 + w2 * x3 + w2 * x2 + w2 * x1 + w1 * w0 + w1 * x3 + w1 * x1 + w1 * x0 + w0 * x1, + w3 * w1 + w3 * x3 + w3 * x2 + w3 * x1 + w3 * x0 + w2 * w1 + w2 * w0 + w2 * x2 + w2 * x0 + w1 * x3 + w1 * x0 + w0**2 + w0 * x0, + ] + ) return l - w7,w6,w5,w4,w3,w2,w1,w0 = w - x7,x6,x5,x4,x3,x2,x1,x0 = x - - l = [w7*x7 + w7*x5 + w7*x4 + w7*x0 + w6*x6 + w6*x5 + w6*x1 + w5*x7 + w5*x6 + w5*x2 + w4*x7 + w4*x3 + w3*x4 + w2*x5 + w1*x6 + w0*x7, - w7*x6 + w7*x4 + w7*x3 + w6*x7 + w6*x5 + w6*x4 + w6*x0 + w5*x6 + w5*x5 + w5*x1 + w4*x7 + w4*x6 + w4*x2 + w3*x7 + w3*x3 + w2*x4 + w1*x5 + w0*x6, - w7*x5 + w7*x3 + w7*x2 + w6*x6 + w6*x4 + w6*x3 + w5*x7 + w5*x5 + w5*x4 + w5*x0 + w4*x6 + w4*x5 + w4*x1 + w3*x7 + w3*x6 + w3*x2 + w2*x7 + w2*x3 + w1*x4 + w0*x5, - w7*x7 + w7*x4 + w7*x2 + w7*x1 + w6*x5 + w6*x3 + w6*x2 + w5*x6 + w5*x4 + w5*x3 + w4*x7 + w4*x5 + w4*x4 + w4*x0 + w3*x6 + w3*x5 + w3*x1 + w2*x7 + w2*x6 + w2*x2 + w1*x7 + w1*x3 + w0*x4, - w7*x7 + w7*x6 + w7*x5 + w7*x4 + w7*x3 + w7*x1 + w6*x7 + w6*x6 + w6*x5 + w6*x4 + w6*x2 + w5*x7 + w5*x6 + w5*x5 + w5*x3 + w4*x7 + w4*x6 + w4*x4 + w3*x7 + w3*x5 + w3*x0 + w2*x6 + w2*x1 - + w1*x7 + w1*x2 + w0*x3, - w7*x6 + w7*x3 + w7*x2 + w6*x7 + w6*x4 + w6*x3 + w5*x5 + w5*x4 + w4*x6 + w4*x5 + w3*x7 + w3*x6 + w2*x7 + w2*x0 + w1*x1 + w0*x2, - w7*x7 + w7*x5 + w7*x2 + w7*x1 + w6*x6 + w6*x3 + w6*x2 + w5*x7 + w5*x4 + w5*x3 + w4*x5 + w4*x4 + w3*x6 + w3*x5 + w2*x7 + w2*x6 + w1*x7 + w1*x0 + w0*x1, - w7*x6 + w7*x5 + w7*x2 + w7*x0 + w6*x7 + w6*x4 + w6*x3 + w5*x7 + w5*x6 + w5*x3 + w5*x1 + w4*x5 + w4*x4 + w3*x7 + w3*x4 + w3*x2 + w2*x6 + w2*x5 + w1*x5 + w1*x3 + w0*x7 + w0*x6 + x7, - w7*x6 + w7*x3 + w7*x2 + w6*x6 + w6*x5 + w6*x2 + w6*x0 + w5*x7 + w5*x4 + w5*x3 + w4*x7 + w4*x6 + w4*x3 + w4*x1 + w3*x5 + w3*x4 + w2*x7 + w2*x4 + w2*x2 + w1*x6 + w1*x5 + w0*x5 + w0*x3 - + x6, - w7*x7 + w7*x5 + w7*x4 + w7*x1 + w6*x6 + w6*x3 + w6*x2 + w5*x6 + w5*x5 + w5*x2 + w5*x0 + w4*x7 + w4*x4 + w4*x3 + w3*x7 + w3*x6 + w3*x3 + w3*x1 + w2*x5 + w2*x4 + w1*x7 + w1*x4 + w1*x2 - + w0*x6 + w0*x5 + x5, - w7*x7 + w7*x5 + w7*x2 + w7*x1 + w6*x7 + w6*x5 + w6*x4 + w6*x1 + w5*x6 + w5*x3 + w5*x2 + w4*x6 + w4*x5 + w4*x2 + w4*x0 + w3*x7 + w3*x4 + w3*x3 + w2*x7 + w2*x6 + w2*x3 + w2*x1 + w1*x5 - + w1*x4 + w0*x7 + w0*x4 + w0*x2 + x4, - w7*x5 + w7*x4 + w7*x3 + w7*x2 + w6*x5 + w6*x4 + w6*x3 + w6*x2 + w6*x1 + w5*x6 + w5*x5 + w5*x4 + w5*x3 + w4*x6 + w4*x5 + w4*x4 + w4*x3 + w4*x2 + w3*x7 + w3*x6 + w3*x5 + w3*x4 + w3*x0 - + w2*x7 + w2*x6 + w2*x5 + w2*x4 + w2*x3 + w1*x7 + w1*x6 + w1*x5 + w1*x1 + w0*x7 + w0*x6 + w0*x5 + w0*x4 + x3, - w7*x7 + w7*x6 + w7*x5 + w7*x4 + w7*x3 + w7*x1 + w6*x7 + w6*x5 + w6*x2 + w5*x7 + w5*x6 + w5*x5 + w5*x4 + w5*x2 + w4*x6 + w4*x3 + w3*x7 + w3*x6 + w3*x5 + w3*x3 + w2*x7 + w2*x4 + w2*x0 - + w1*x7 + w1*x6 + w1*x4 + w0*x5 + w0*x1 + x2, - w7*x6 + w7*x4 + w7*x1 + w6*x7 + w6*x6 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w5*x7 + w5*x5 + w5*x2 + w4*x7 + w4*x6 + w4*x5 + w4*x4 + w4*x2 + w3*x6 + w3*x3 + w2*x7 + w2*x6 + w2*x5 + w2*x3 - + w1*x7 + w1*x4 + w1*x0 + w0*x7 + w0*x6 + w0*x4 + x1, - w7*x7 + w7*x4 + w7*x3 + w6*x7 + w6*x6 + w6*x3 + w6*x1 + w5*x5 + w5*x4 + w4*x7 + w4*x4 + w4*x2 + w3*x6 + w3*x5 + w2*x5 + w2*x3 + w1*x7 + w1*x6 + w0*x6 + w0*x4 + w0*x0 + x0, - w7*x6 + w7*x5 + w7*x3 + w7*x0 + w7 + w6*x7 + w6*x5 + w6*x2 + w6*x0 + w5*x7 + w5*x4 + w5*x2 + w5*x1 + w4*x6 + w4*x4 + w4*x3 + w3*x6 + w3*x5 + w3*x1 + w2*x7 + w2*x3 + w1*x5 + w0*x7, - w7*x5 + w7*x4 + w7*x2 + w6*x7 + w6*x6 + w6*x4 + w6*x1 + w6 + w5*x6 + w5*x3 + w5*x1 + w5*x0 + w4*x5 + w4*x3 + w4*x2 + w3*x7 + w3*x5 + w3*x4 + w3*x0 + w2*x7 + w2*x6 + w2*x2 + w1*x4 - + w0*x6, - w7*x7 + w7*x4 + w7*x3 + w7*x1 + w6*x6 + w6*x5 + w6*x3 + w6*x0 + w5*x7 + w5*x5 + w5*x2 + w5*x0 + w5 + w4*x7 + w4*x4 + w4*x2 + w4*x1 + w3*x6 + w3*x4 + w3*x3 + w2*x6 + w2*x5 + w2*x1 - + w1*x7 + w1*x3 + w0*x5, - w7*x7 + w7*x6 + w7*x3 + w7*x2 + w7*x0 + w6*x5 + w6*x4 + w6*x2 + w5*x7 + w5*x6 + w5*x4 + w5*x1 + w4*x6 + w4*x3 + w4*x1 + w4*x0 + w4 + w3*x5 + w3*x3 + w3*x2 + w2*x7 + w2*x5 + w2*x4 - + w2*x0 + w1*x7 + w1*x6 + w1*x2 + w0*x4, - w7*x3 + w7*x2 + w7*x1 + w7*x0 + w6*x5 + w6*x4 + w6*x3 + w6*x2 + w6*x1 + w6*x0 + w5*x7 + w5*x6 + w5*x5 + w5*x4 + w5*x3 + w5*x2 + w5*x1 + w5*x0 + w4*x7 + w4*x6 + w4*x5 + w4*x4 - + w4*x3 + w4*x2 + w4*x0 + w3*x7 + w3*x6 + w3*x5 + w3*x4 + w3*x2 + w3 + w2*x7 + w2*x6 + w2*x4 + w1*x6 + w1*x1 + w0*x3, - w7*x7 + w7*x6 + w7*x5 + w7*x3 + w7*x2 + w7*x1 + w6*x7 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w5*x7 + w5*x6 + w5*x5 + w5*x3 + w5*x0 + w4*x7 + w4*x5 + w4*x2 + w4*x1 + w3*x7 + w3*x4 - + w3*x3 + w2*x6 + w2*x5 + w2 + w1*x7 + w1*x0 + w0*x2, - w7*x6 + w7*x5 + w7*x4 + w7*x2 + w7*x1 + w7*x0 + w6*x7 + w6*x6 + w6*x4 + w6*x3 + w6*x2 + w6*x0 + w5*x6 + w5*x5 + w5*x4 + w5*x2 + w4*x7 + w4*x6 + w4*x4 + w4*x1 + w4*x0 + w3*x6 - + w3*x3 + w3*x2 + w2*x5 + w2*x4 + w1*x7 + w1*x6 + w1 + w0*x1, - w7*x7 + w7*x6 + w7*x4 + w7*x1 + w6*x6 + w6*x3 + w6*x1 + w6*x0 + w5*x5 + w5*x3 + w5*x2 + w4*x7 + w4*x5 + w4*x4 + w4*x0 + w3*x7 + w3*x6 + w3*x2 + w2*x4 + w1*x6 + w0*x0 + w0] + w7, w6, w5, w4, w3, w2, w1, w0 = w + x7, x6, x5, x4, x3, x2, x1, x0 = x + + l = [ + w7 * x7 + w7 * x5 + w7 * x4 + w7 * x0 + w6 * x6 + w6 * x5 + w6 * x1 + w5 * x7 + w5 * x6 + w5 * x2 + w4 * x7 + w4 * x3 + w3 * x4 + w2 * x5 + w1 * x6 + w0 * x7, + w7 * x6 + w7 * x4 + w7 * x3 + w6 * x7 + w6 * x5 + w6 * x4 + w6 * x0 + w5 * x6 + w5 * x5 + w5 * x1 + w4 * x7 + w4 * x6 + w4 * x2 + w3 * x7 + w3 * x3 + w2 * x4 + w1 * x5 + w0 * x6, + w7 * x5 + w7 * x3 + w7 * x2 + w6 * x6 + w6 * x4 + w6 * x3 + w5 * x7 + w5 * x5 + w5 * x4 + w5 * x0 + w4 * x6 + w4 * x5 + w4 * x1 + w3 * x7 + w3 * x6 + w3 * x2 + w2 * x7 + w2 * x3 + w1 * x4 + w0 * x5, + w7 * x7 + w7 * x4 + w7 * x2 + w7 * x1 + w6 * x5 + w6 * x3 + w6 * x2 + w5 * x6 + w5 * x4 + w5 * x3 + w4 * x7 + w4 * x5 + w4 * x4 + w4 * x0 + w3 * x6 + w3 * x5 + w3 * x1 + w2 * x7 + w2 * x6 + w2 * x2 + w1 * x7 + w1 * x3 + w0 * x4, + w7 * x7 + w7 * x6 + w7 * x5 + w7 * x4 + w7 * x3 + w7 * x1 + w6 * x7 + w6 * x6 + w6 * x5 + w6 * x4 + w6 * x2 + w5 * x7 + w5 * x6 + w5 * x5 + w5 * x3 + w4 * x7 + w4 * x6 + w4 * x4 + w3 * x7 + w3 * x5 + w3 * x0 + w2 * x6 + w2 * x1 + w1 * x7 + w1 * x2 + w0 * x3, + w7 * x6 + w7 * x3 + w7 * x2 + w6 * x7 + w6 * x4 + w6 * x3 + w5 * x5 + w5 * x4 + w4 * x6 + w4 * x5 + w3 * x7 + w3 * x6 + w2 * x7 + w2 * x0 + w1 * x1 + w0 * x2, + w7 * x7 + w7 * x5 + w7 * x2 + w7 * x1 + w6 * x6 + w6 * x3 + w6 * x2 + w5 * x7 + w5 * x4 + w5 * x3 + w4 * x5 + w4 * x4 + w3 * x6 + w3 * x5 + w2 * x7 + w2 * x6 + w1 * x7 + w1 * x0 + w0 * x1, + w7 * x6 + w7 * x5 + w7 * x2 + w7 * x0 + w6 * x7 + w6 * x4 + w6 * x3 + w5 * x7 + w5 * x6 + w5 * x3 + w5 * x1 + w4 * x5 + w4 * x4 + w3 * x7 + w3 * x4 + w3 * x2 + w2 * x6 + w2 * x5 + w1 * x5 + w1 * x3 + w0 * x7 + w0 * x6 + x7, + w7 * x6 + w7 * x3 + w7 * x2 + w6 * x6 + w6 * x5 + w6 * x2 + w6 * x0 + w5 * x7 + w5 * x4 + w5 * x3 + w4 * x7 + w4 * x6 + w4 * x3 + w4 * x1 + w3 * x5 + w3 * x4 + w2 * x7 + w2 * x4 + w2 * x2 + w1 * x6 + w1 * x5 + w0 * x5 + w0 * x3 + x6, + w7 * x7 + w7 * x5 + w7 * x4 + w7 * x1 + w6 * x6 + w6 * x3 + w6 * x2 + w5 * x6 + w5 * x5 + w5 * x2 + w5 * x0 + w4 * x7 + w4 * x4 + w4 * x3 + w3 * x7 + w3 * x6 + w3 * x3 + w3 * x1 + w2 * x5 + w2 * x4 + w1 * x7 + w1 * x4 + w1 * x2 + w0 * x6 + w0 * x5 + x5, + w7 * x7 + w7 * x5 + w7 * x2 + w7 * x1 + w6 * x7 + w6 * x5 + w6 * x4 + w6 * x1 + w5 * x6 + w5 * x3 + w5 * x2 + w4 * x6 + w4 * x5 + w4 * x2 + w4 * x0 + w3 * x7 + w3 * x4 + w3 * x3 + w2 * x7 + w2 * x6 + w2 * x3 + w2 * x1 + w1 * x5 + w1 * x4 + w0 * x7 + w0 * x4 + w0 * x2 + x4, + w7 * x5 + w7 * x4 + w7 * x3 + w7 * x2 + w6 * x5 + w6 * x4 + w6 * x3 + w6 * x2 + w6 * x1 + w5 * x6 + w5 * x5 + w5 * x4 + w5 * x3 + w4 * x6 + w4 * x5 + w4 * x4 + w4 * x3 + w4 * x2 + w3 * x7 + w3 * x6 + w3 * x5 + w3 * x4 + w3 * x0 + w2 * x7 + w2 * x6 + w2 * x5 + w2 * x4 + w2 * x3 + w1 * x7 + w1 * x6 + w1 * x5 + w1 * x1 + w0 * x7 + w0 * x6 + w0 * x5 + w0 * x4 + x3, + w7 * x7 + w7 * x6 + w7 * x5 + w7 * x4 + w7 * x3 + w7 * x1 + w6 * x7 + w6 * x5 + w6 * x2 + w5 * x7 + w5 * x6 + w5 * x5 + w5 * x4 + w5 * x2 + w4 * x6 + w4 * x3 + w3 * x7 + w3 * x6 + w3 * x5 + w3 * x3 + w2 * x7 + w2 * x4 + w2 * x0 + w1 * x7 + w1 * x6 + w1 * x4 + w0 * x5 + w0 * x1 + x2, + w7 * x6 + w7 * x4 + w7 * x1 + w6 * x7 + w6 * x6 + w6 * x5 + w6 * x4 + w6 * x3 + w6 * x1 + w5 * x7 + w5 * x5 + w5 * x2 + w4 * x7 + w4 * x6 + w4 * x5 + w4 * x4 + w4 * x2 + w3 * x6 + w3 * x3 + w2 * x7 + w2 * x6 + w2 * x5 + w2 * x3 + w1 * x7 + w1 * x4 + w1 * x0 + w0 * x7 + w0 * x6 + w0 * x4 + x1, + w7 * x7 + w7 * x4 + w7 * x3 + w6 * x7 + w6 * x6 + w6 * x3 + w6 * x1 + w5 * x5 + w5 * x4 + w4 * x7 + w4 * x4 + w4 * x2 + w3 * x6 + w3 * x5 + w2 * x5 + w2 * x3 + w1 * x7 + w1 * x6 + w0 * x6 + w0 * x4 + w0 * x0 + x0, + w7 * x6 + w7 * x5 + w7 * x3 + w7 * x0 + w7 + w6 * x7 + w6 * x5 + w6 * x2 + w6 * x0 + w5 * x7 + w5 * x4 + w5 * x2 + w5 * x1 + w4 * x6 + w4 * x4 + w4 * x3 + w3 * x6 + w3 * x5 + w3 * x1 + w2 * x7 + w2 * x3 + w1 * x5 + w0 * x7, + w7 * x5 + w7 * x4 + w7 * x2 + w6 * x7 + w6 * x6 + w6 * x4 + w6 * x1 + w6 + w5 * x6 + w5 * x3 + w5 * x1 + w5 * x0 + w4 * x5 + w4 * x3 + w4 * x2 + w3 * x7 + w3 * x5 + w3 * x4 + w3 * x0 + w2 * x7 + w2 * x6 + w2 * x2 + w1 * x4 + w0 * x6, + w7 * x7 + w7 * x4 + w7 * x3 + w7 * x1 + w6 * x6 + w6 * x5 + w6 * x3 + w6 * x0 + w5 * x7 + w5 * x5 + w5 * x2 + w5 * x0 + w5 + w4 * x7 + w4 * x4 + w4 * x2 + w4 * x1 + w3 * x6 + w3 * x4 + w3 * x3 + w2 * x6 + w2 * x5 + w2 * x1 + w1 * x7 + w1 * x3 + w0 * x5, + w7 * x7 + w7 * x6 + w7 * x3 + w7 * x2 + w7 * x0 + w6 * x5 + w6 * x4 + w6 * x2 + w5 * x7 + w5 * x6 + w5 * x4 + w5 * x1 + w4 * x6 + w4 * x3 + w4 * x1 + w4 * x0 + w4 + w3 * x5 + w3 * x3 + w3 * x2 + w2 * x7 + w2 * x5 + w2 * x4 + w2 * x0 + w1 * x7 + w1 * x6 + w1 * x2 + w0 * x4, + w7 * x3 + w7 * x2 + w7 * x1 + w7 * x0 + w6 * x5 + w6 * x4 + w6 * x3 + w6 * x2 + w6 * x1 + w6 * x0 + w5 * x7 + w5 * x6 + w5 * x5 + w5 * x4 + w5 * x3 + w5 * x2 + w5 * x1 + w5 * x0 + w4 * x7 + w4 * x6 + w4 * x5 + w4 * x4 + w4 * x3 + w4 * x2 + w4 * x0 + w3 * x7 + w3 * x6 + w3 * x5 + w3 * x4 + w3 * x2 + w3 + w2 * x7 + w2 * x6 + w2 * x4 + w1 * x6 + w1 * x1 + w0 * x3, + w7 * x7 + w7 * x6 + w7 * x5 + w7 * x3 + w7 * x2 + w7 * x1 + w6 * x7 + w6 * x5 + w6 * x4 + w6 * x3 + w6 * x1 + w5 * x7 + w5 * x6 + w5 * x5 + w5 * x3 + w5 * x0 + w4 * x7 + w4 * x5 + w4 * x2 + w4 * x1 + w3 * x7 + w3 * x4 + w3 * x3 + w2 * x6 + w2 * x5 + w2 + w1 * x7 + w1 * x0 + w0 * x2, + w7 * x6 + w7 * x5 + w7 * x4 + w7 * x2 + w7 * x1 + w7 * x0 + w6 * x7 + w6 * x6 + w6 * x4 + w6 * x3 + w6 * x2 + w6 * x0 + w5 * x6 + w5 * x5 + w5 * x4 + w5 * x2 + w4 * x7 + w4 * x6 + w4 * x4 + w4 * x1 + w4 * x0 + w3 * x6 + w3 * x3 + w3 * x2 + w2 * x5 + w2 * x4 + w1 * x7 + w1 * x6 + w1 + w0 * x1, + w7 * x7 + w7 * x6 + w7 * x4 + w7 * x1 + w6 * x6 + w6 * x3 + w6 * x1 + w6 * x0 + w5 * x5 + w5 * x3 + w5 * x2 + w4 * x7 + w4 * x5 + w4 * x4 + w4 * x0 + w3 * x7 + w3 * x6 + w3 * x2 + w2 * x4 + w1 * x6 + w0 * x0 + w0, + ] if not correct_only: - l.append(w7*x6 + w7*x5 + w7*x1 + w6*x7 + w6*x6 + w6*x2 + w5*x7 + w5*x3 + w4*x4 + w3*x5 + w2*x6 + w1*x7 + w0*x0 + 1) + l.append(w7 * x6 + w7 * x5 + w7 * x1 + w6 * x7 + w6 * x6 + w6 * x2 + w5 * x7 + w5 * x3 + w4 * x4 + w3 * x5 + w2 * x6 + w1 * x7 + w0 * x0 + 1) if not biaffine_only: - l.extend([w7**2 + w7*w6 + w7*w3 + w7*w1 + w7*x7 + w7*x6 + w7*x5 + w7*x2 + w7*x1 + w7*x0 + w6**2 + w6*w0 + w6*x6 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w6*x0 + w5**2 + w5*w4 + w5*w3 - + w5*w2 + w5*x7 + w5*x5 + w5*x4 + w5*x1 + w5*x0 + w4**2 + w4*w2 + w4*w0 + w4*x5 + w4*x4 + w4*x2 + w3*w2 + w3*x6 + w3*x3 + w3*x1 + w3*x0 + w2*x7 + w2*x5 + w2*x4 - + w2*x0 + w1*x4 + w0**2 + w0*x0, - w7*x6 + w7*x4 + w7*x1 + w6*x7 + w6*x6 + w6*x5 + w6*x2 + w5*x7 + w5*x6 + w5*x5 + w5*x4 + w5*x3 + w5*x1 + w4*x5 + w4*x4 + w4*x3 + w4*x1 + w4*x0 + w3*x7 + w3*x5 + w3*x2 - + w2*x7 + w2*x6 + w2*x3 + w1*x7 + w1*x6 + w1*x5 + w1*x4 + w1*x2 + w0*x6 + w0*x5 + w0*x4 + w0*x2 + w0*x1 + x7**2 + x7*x6 + x7*x5 + x7*x3 + x7*x1 + x7*x0 + x6*x2 - + x6*x1 + x5*x4 + x5*x3 + x5*x2 + x5*x1 + x4*x3 + x4*x2 + x4*x1 + x3**2 + x3*x2 + x2*x1 + x2*x0, - w7*x5 + w7*x4 + w7*x3 + w7*x1 + w7*x0 + w6*x7 + w6*x5 + w6*x2 + w5*x7 + w5*x6 + w5*x3 + w4*x7 + w4*x6 + w4*x5 + w4*x4 + w4*x2 + w3*x6 + w3*x5 + w3*x4 + w3*x2 + w3*x1 - + w2*x6 + w2*x3 + w1*x7 + w1*x4 + w0*x7 + w0*x6 + w0*x5 + w0*x3 + x7*x3 + x7*x2 + x6*x5 + x6*x4 + x6*x3 + x6*x2 + x6*x0 + x5*x4 + x5*x3 + x5*x2 + x4**2 + x4*x3 - + x3*x2 + x3*x1, - w7*w3 + w7*w2 + w7*x6 + w7*x5 + w7*x4 + w7*x1 + w7*x0 + w6*w5 + w6*w4 + w6*w3 + w6*w2 + w6*w0 + w6*x5 + w6*x4 + w6*x3 + w6*x2 + w6*x0 + w5*w4 + w5*w3 + w5*w2 + w5*x7 - + w5*x6 + w5*x4 + w5*x3 + w5*x0 + w4**2 + w4*w3 + w4*x7 + w4*x4 + w4*x3 + w4*x1 + w3*w2 + w3*w1 + w3*x7 + w3*x5 + w3*x2 + w3*x0 + w2*x6 + w2*x4 + w2*x3 + w1*x7 - + w1*x3 + w0*x7, - w7*x5 + w7*x2 + w7*x1 + w6*x7 + w6*x6 + w6*x5 + w6*x4 + w6*x2 + w6*x1 + w5*x5 + w5*x3 + w5*x2 + w4*x3 + w4*x2 + w4*x1 + w3*x6 + w3*x3 + w3*x2 + w3*x0 + w2*x7 + w2*x6 - + w2*x5 + w2*x3 + w2*x2 + w1*x6 + w1*x4 + w1*x3 + w0*x4 + w0*x3 + w0*x2 + x7*x5 + x7*x4 + x7*x1 + x7*x0 + x6*x0 + x5**2 + x5*x2 + x5*x1 + x5*x0 + x4**2 + x4*x0 - + x3*x2 + x3*x0 + x1**2, - w7*w6 + w7*w5 + w7*w4 + w7*w3 + w7*x7 + w7*x5 + w7*x4 + w7*x3 + w7*x0 + w6**2 + w6*w5 + w6*w4 + w6*w2 + w6*w1 + w6*w0 + w6*x7 + w6*x4 + w6*x3 + w6*x2 + w6*x1 + w5*w4 - + w5*w1 + w5*w0 + w5*x7 + w5*x6 + w5*x5 + w5*x3 + w5*x2 + w4*w2 + w4*w1 + w4*x7 + w4*x6 + w4*x3 + w4*x2 + w4*x0 + w3*w0 + w3*x7 + w3*x6 + w3*x4 + w3*x1 + w2**2 - + w2*x5 + w2*x3 + w2*x2 + w1*x7 + w1*x6 + w1*x2 + w0*x6, - w7*w5 + w7*w4 + w7*w1 + w7*w0 + w7*x6 + w7*x2 + w6*w0 + w6*x6 + w6*x3 + w6*x2 + w6*x1 + w5**2 + w5*w2 + w5*w1 + w5*w0 + w5*x7 + w5*x6 + w5*x5 + w5*x2 + w4**2 + w4*w0 - + w4*x6 + w4*x1 + w4*x0 + w3*w2 + w3*w0 + w3*x5 + w3*x4 + w3*x3 + w3*x2 + w3*x1 + w3*x0 + w2*x7 + w2*x6 + w2*x5 + w2*x4 + w2*x3 + w2*x2 + w2*x0 + w1**2 + w1*x7 - + w1*x6 + w1*x4 + w0*x3, - w7*x7 + w7*x6 + w7*x5 + w7*x2 + w6*x7 + w6*x6 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w5*x5 + w5*x4 + w5*x3 + w5*x1 + w5*x0 + w4*x7 + w4*x5 + w4*x2 + w3*x7 + w3*x6 + w3*x3 - + w2*x7 + w2*x6 + w2*x5 + w2*x4 + w2*x2 + w1*x6 + w1*x5 + w1*x4 + w1*x2 + w1*x1 + w0*x6 + w0*x3 + x7**2 + x7*x5 + x7*x3 + x6**2 + x6*x5 + x6*x2 + x6*x0 + x5**2 - + x4**2 + x4*x3 + x4*x2 + x4*x1 + x3**2 + x3*x1 + x2*x1, - w7**2 + w7*w6 + w7*w5 + w7*w3 + w7*w1 + w7*w0 + w7*x6 + w7*x5 + w7*x3 + w7*x2 + w7*x1 + w6*w2 + w6*w1 + w6*x7 + w6*x6 + w6*x5 + w6*x2 + w6*x1 + w6*x0 + w5*w4 + w5*w3 - + w5*w2 + w5*w1 + w5*x6 + w5*x5 + w5*x4 + w5*x3 + w5*x1 + w5*x0 + w4*w3 + w4*w2 + w4*w1 + w4*x7 + w4*x5 + w4*x4 + w4*x1 + w4*x0 + w3**2 + w3*w2 + w3*x5 + w3*x4 - + w3*x2 + w2*w1 + w2*w0 + w2*x6 + w2*x3 + w2*x1 + w2*x0 + w1*x7 + w1*x5 + w1*x4 + w1*x0 + w0*x4, - w7*x7 + w7*x5 + w7*x2 + w6*x7 + w6*x6 + w6*x3 + w5*x7 + w5*x6 + w5*x5 + w5*x4 + w5*x2 + w4*x6 + w4*x5 + w4*x4 + w4*x2 + w4*x1 + w3*x6 + w3*x3 + w2*x7 + w2*x4 + w1*x7 - + w1*x6 + w1*x5 + w1*x3 + w0*x7 + w0*x6 + w0*x5 + w0*x3 + w0*x2 + w0*x0 + x7**2 + x7*x6 + x7*x3 + x7*x1 + x6**2 + x6*x0 + x5**2 + x5*x4 + x5*x3 + x5*x2 + x4**2 - + x4*x2 + x4*x0 + x3*x2 + x0**2, - w7*x7 + w7*x6 + w7*x5 + w7*x4 + w7*x3 + w7*x1 + w6*x5 + w6*x4 + w6*x3 + w6*x1 + w6*x0 + w5*x7 + w5*x5 + w5*x2 + w4*x7 + w4*x6 + w4*x3 + w3*x7 + w3*x6 + w3*x5 + w3*x4 - + w3*x2 + w2*x6 + w2*x5 + w2*x4 + w2*x2 + w2*x1 + w1*x6 + w1*x3 + w0*x7 + w0*x4 + x7*x6 + x7*x5 + x7*x4 + x7*x3 + x6**2 + x6*x5 + x6*x4 + x6*x2 + x6*x1 + x6*x0 - + x5*x4 + x5*x1 + x5*x0 + x4*x2 + x4*x1 + x3*x0 + x2**2, - w7*x5 + w7*x4 + w7*x3 + w7*x2 + w6*x7 + w6*x1 + w5*x5 + w5*x4 + w5*x3 + w5*x2 + w5*x1 + w4*x7 + w4*x6 + w4*x4 + w4*x3 + w3*x6 + w3*x5 + w3*x4 + w3*x3 + w2*x2 + w2*x0 - + w1*x6 + w1*x5 + w1*x4 + w1*x3 + w1*x2 + w0*x7 + w0*x5 + w0*x4 + x7**2 + x7*x4 + x7*x2 + x6*x4 + x6*x3 + x6*x2 + x6*x1 + x5**2 + x5*x4 + x5*x3 + x5*x2 + x5*x0 - + x4*x3 + x4*x2 + x4*x1 + x3**2 + x2*x0 + x1*x0, - w7*x6 + w7*x5 + w7*x3 + w7*x2 + w6*x5 + w6*x4 + w6*x3 + w6*x2 + w5*x7 + w5*x1 + w4*x5 + w4*x4 + w4*x3 + w4*x2 + w4*x1 + w3*x7 + w3*x6 + w3*x4 + w3*x3 + w2*x6 + w2*x5 - + w2*x4 + w2*x3 + w1*x2 + w1*x0 + w0*x6 + w0*x5 + w0*x4 + w0*x3 + w0*x2 + x7*x5 + x7*x2 + x7*x0 + x6**2 + x6*x5 + x6*x2 + x6*x1 + x6*x0 + x5**2 + x5*x4 + x4**2 - + x4*x2 + x4*x1 + x4*x0 + x3**2 + x3*x2 + x1*x0, - w7**2 + w7*w5 + w7*w3 + w7*x7 + w7*x6 + w7*x4 + w7*x3 + w7*x2 + w6**2 + w6*w5 + w6*w2 + w6*w0 + w6*x7 + w6*x6 + w6*x3 + w6*x2 + w6*x1 + w6*x0 + w5**2 + w5*x7 + w5*x6 - + w5*x5 + w5*x4 + w5*x2 + w5*x1 + w4**2 + w4*w3 + w4*w2 + w4*w1 + w4*x6 + w4*x5 + w4*x2 + w4*x1 + w3**2 + w3*w1 + w3*x6 + w3*x5 + w3*x3 + w3*x0 + w2*w1 + w2*x7 - + w2*x4 + w2*x2 + w2*x1 + w1*x6 + w1*x5 + w1*x1 + w0*x5, - w7*w5 + w7*w2 + w7*w0 + w7*x5 + w7*x3 + w6**2 + w6*w5 + w6*w2 + w6*w1 + w6*w0 + w6*x7 + w6*x3 + w6*x2 + w6*x0 + w5**2 + w5*w4 + w5*x7 + w5*x6 + w5*x4 + w5*x2 + w5*x0 - + w4**2 + w4*w2 + w4*w1 + w4*w0 + w4*x6 + w4*x4 + w4*x3 + w4*x2 + w4*x0 + w3**2 + w3*w2 + w3*x7 + w3*x6 + w3*x4 + w3*x3 + w3*x2 + w3*x0 + w2*x7 + w2*x6 + w2*x4 - + w2*x1 + w2*x0 + w1*w0 + w1*x5 + w1*x4 + w0*x1, - w7**2 + w7*w4 + w7*w2 + w7*x6 + w7*x4 + w7*x0 + w6*w4 + w6*w3 + w6*w2 + w6*w1 + w6*x4 + w6*x3 + w6*x1 + w5**2 + w5*w4 + w5*w3 + w5*w2 + w5*w0 + w5*x7 + w5*x5 + w5*x3 - + w5*x1 + w5*x0 + w4*w3 + w4*w2 + w4*w1 + w4*x7 + w4*x5 + w4*x4 + w4*x3 + w4*x1 + w4*x0 + w3**2 + w3*x7 + w3*x5 + w3*x4 + w3*x3 + w3*x1 + w2*w0 + w2*x7 + w2*x5 - + w2*x2 + w2*x1 + w1*w0 + w1*x6 + w1*x5 + w0*x2]) + l.extend( + [ + w7**2 + w7 * w6 + w7 * w3 + w7 * w1 + w7 * x7 + w7 * x6 + w7 * x5 + w7 * x2 + w7 * x1 + w7 * x0 + w6**2 + w6 * w0 + w6 * x6 + w6 * x5 + w6 * x4 + w6 * x3 + w6 * x1 + w6 * x0 + w5**2 + w5 * w4 + w5 * w3 + w5 * w2 + w5 * x7 + w5 * x5 + w5 * x4 + w5 * x1 + w5 * x0 + w4**2 + w4 * w2 + w4 * w0 + w4 * x5 + w4 * x4 + w4 * x2 + w3 * w2 + w3 * x6 + w3 * x3 + w3 * x1 + w3 * x0 + w2 * x7 + w2 * x5 + w2 * x4 + w2 * x0 + w1 * x4 + w0**2 + w0 * x0, + w7 * x6 + w7 * x4 + w7 * x1 + w6 * x7 + w6 * x6 + w6 * x5 + w6 * x2 + w5 * x7 + w5 * x6 + w5 * x5 + w5 * x4 + w5 * x3 + w5 * x1 + w4 * x5 + w4 * x4 + w4 * x3 + w4 * x1 + w4 * x0 + w3 * x7 + w3 * x5 + w3 * x2 + w2 * x7 + w2 * x6 + w2 * x3 + w1 * x7 + w1 * x6 + w1 * x5 + w1 * x4 + w1 * x2 + w0 * x6 + w0 * x5 + w0 * x4 + w0 * x2 + w0 * x1 + x7**2 + x7 * x6 + x7 * x5 + x7 * x3 + x7 * x1 + x7 * x0 + x6 * x2 + x6 * x1 + x5 * x4 + x5 * x3 + x5 * x2 + x5 * x1 + x4 * x3 + x4 * x2 + x4 * x1 + x3**2 + x3 * x2 + x2 * x1 + x2 * x0, + w7 * x5 + w7 * x4 + w7 * x3 + w7 * x1 + w7 * x0 + w6 * x7 + w6 * x5 + w6 * x2 + w5 * x7 + w5 * x6 + w5 * x3 + w4 * x7 + w4 * x6 + w4 * x5 + w4 * x4 + w4 * x2 + w3 * x6 + w3 * x5 + w3 * x4 + w3 * x2 + w3 * x1 + w2 * x6 + w2 * x3 + w1 * x7 + w1 * x4 + w0 * x7 + w0 * x6 + w0 * x5 + w0 * x3 + x7 * x3 + x7 * x2 + x6 * x5 + x6 * x4 + x6 * x3 + x6 * x2 + x6 * x0 + x5 * x4 + x5 * x3 + x5 * x2 + x4**2 + x4 * x3 + x3 * x2 + x3 * x1, + w7 * w3 + w7 * w2 + w7 * x6 + w7 * x5 + w7 * x4 + w7 * x1 + w7 * x0 + w6 * w5 + w6 * w4 + w6 * w3 + w6 * w2 + w6 * w0 + w6 * x5 + w6 * x4 + w6 * x3 + w6 * x2 + w6 * x0 + w5 * w4 + w5 * w3 + w5 * w2 + w5 * x7 + w5 * x6 + w5 * x4 + w5 * x3 + w5 * x0 + w4**2 + w4 * w3 + w4 * x7 + w4 * x4 + w4 * x3 + w4 * x1 + w3 * w2 + w3 * w1 + w3 * x7 + w3 * x5 + w3 * x2 + w3 * x0 + w2 * x6 + w2 * x4 + w2 * x3 + w1 * x7 + w1 * x3 + w0 * x7, + w7 * x5 + w7 * x2 + w7 * x1 + w6 * x7 + w6 * x6 + w6 * x5 + w6 * x4 + w6 * x2 + w6 * x1 + w5 * x5 + w5 * x3 + w5 * x2 + w4 * x3 + w4 * x2 + w4 * x1 + w3 * x6 + w3 * x3 + w3 * x2 + w3 * x0 + w2 * x7 + w2 * x6 + w2 * x5 + w2 * x3 + w2 * x2 + w1 * x6 + w1 * x4 + w1 * x3 + w0 * x4 + w0 * x3 + w0 * x2 + x7 * x5 + x7 * x4 + x7 * x1 + x7 * x0 + x6 * x0 + x5**2 + x5 * x2 + x5 * x1 + x5 * x0 + x4**2 + x4 * x0 + x3 * x2 + x3 * x0 + x1**2, + w7 * w6 + w7 * w5 + w7 * w4 + w7 * w3 + w7 * x7 + w7 * x5 + w7 * x4 + w7 * x3 + w7 * x0 + w6**2 + w6 * w5 + w6 * w4 + w6 * w2 + w6 * w1 + w6 * w0 + w6 * x7 + w6 * x4 + w6 * x3 + w6 * x2 + w6 * x1 + w5 * w4 + w5 * w1 + w5 * w0 + w5 * x7 + w5 * x6 + w5 * x5 + w5 * x3 + w5 * x2 + w4 * w2 + w4 * w1 + w4 * x7 + w4 * x6 + w4 * x3 + w4 * x2 + w4 * x0 + w3 * w0 + w3 * x7 + w3 * x6 + w3 * x4 + w3 * x1 + w2**2 + w2 * x5 + w2 * x3 + w2 * x2 + w1 * x7 + w1 * x6 + w1 * x2 + w0 * x6, + w7 * w5 + w7 * w4 + w7 * w1 + w7 * w0 + w7 * x6 + w7 * x2 + w6 * w0 + w6 * x6 + w6 * x3 + w6 * x2 + w6 * x1 + w5**2 + w5 * w2 + w5 * w1 + w5 * w0 + w5 * x7 + w5 * x6 + w5 * x5 + w5 * x2 + w4**2 + w4 * w0 + w4 * x6 + w4 * x1 + w4 * x0 + w3 * w2 + w3 * w0 + w3 * x5 + w3 * x4 + w3 * x3 + w3 * x2 + w3 * x1 + w3 * x0 + w2 * x7 + w2 * x6 + w2 * x5 + w2 * x4 + w2 * x3 + w2 * x2 + w2 * x0 + w1**2 + w1 * x7 + w1 * x6 + w1 * x4 + w0 * x3, + w7 * x7 + w7 * x6 + w7 * x5 + w7 * x2 + w6 * x7 + w6 * x6 + w6 * x5 + w6 * x4 + w6 * x3 + w6 * x1 + w5 * x5 + w5 * x4 + w5 * x3 + w5 * x1 + w5 * x0 + w4 * x7 + w4 * x5 + w4 * x2 + w3 * x7 + w3 * x6 + w3 * x3 + w2 * x7 + w2 * x6 + w2 * x5 + w2 * x4 + w2 * x2 + w1 * x6 + w1 * x5 + w1 * x4 + w1 * x2 + w1 * x1 + w0 * x6 + w0 * x3 + x7**2 + x7 * x5 + x7 * x3 + x6**2 + x6 * x5 + x6 * x2 + x6 * x0 + x5**2 + x4**2 + x4 * x3 + x4 * x2 + x4 * x1 + x3**2 + x3 * x1 + x2 * x1, + w7**2 + w7 * w6 + w7 * w5 + w7 * w3 + w7 * w1 + w7 * w0 + w7 * x6 + w7 * x5 + w7 * x3 + w7 * x2 + w7 * x1 + w6 * w2 + w6 * w1 + w6 * x7 + w6 * x6 + w6 * x5 + w6 * x2 + w6 * x1 + w6 * x0 + w5 * w4 + w5 * w3 + w5 * w2 + w5 * w1 + w5 * x6 + w5 * x5 + w5 * x4 + w5 * x3 + w5 * x1 + w5 * x0 + w4 * w3 + w4 * w2 + w4 * w1 + w4 * x7 + w4 * x5 + w4 * x4 + w4 * x1 + w4 * x0 + w3**2 + w3 * w2 + w3 * x5 + w3 * x4 + w3 * x2 + w2 * w1 + w2 * w0 + w2 * x6 + w2 * x3 + w2 * x1 + w2 * x0 + w1 * x7 + w1 * x5 + w1 * x4 + w1 * x0 + w0 * x4, + w7 * x7 + w7 * x5 + w7 * x2 + w6 * x7 + w6 * x6 + w6 * x3 + w5 * x7 + w5 * x6 + w5 * x5 + w5 * x4 + w5 * x2 + w4 * x6 + w4 * x5 + w4 * x4 + w4 * x2 + w4 * x1 + w3 * x6 + w3 * x3 + w2 * x7 + w2 * x4 + w1 * x7 + w1 * x6 + w1 * x5 + w1 * x3 + w0 * x7 + w0 * x6 + w0 * x5 + w0 * x3 + w0 * x2 + w0 * x0 + x7**2 + x7 * x6 + x7 * x3 + x7 * x1 + x6**2 + x6 * x0 + x5**2 + x5 * x4 + x5 * x3 + x5 * x2 + x4**2 + x4 * x2 + x4 * x0 + x3 * x2 + x0**2, + w7 * x7 + w7 * x6 + w7 * x5 + w7 * x4 + w7 * x3 + w7 * x1 + w6 * x5 + w6 * x4 + w6 * x3 + w6 * x1 + w6 * x0 + w5 * x7 + w5 * x5 + w5 * x2 + w4 * x7 + w4 * x6 + w4 * x3 + w3 * x7 + w3 * x6 + w3 * x5 + w3 * x4 + w3 * x2 + w2 * x6 + w2 * x5 + w2 * x4 + w2 * x2 + w2 * x1 + w1 * x6 + w1 * x3 + w0 * x7 + w0 * x4 + x7 * x6 + x7 * x5 + x7 * x4 + x7 * x3 + x6**2 + x6 * x5 + x6 * x4 + x6 * x2 + x6 * x1 + x6 * x0 + x5 * x4 + x5 * x1 + x5 * x0 + x4 * x2 + x4 * x1 + x3 * x0 + x2**2, + w7 * x5 + w7 * x4 + w7 * x3 + w7 * x2 + w6 * x7 + w6 * x1 + w5 * x5 + w5 * x4 + w5 * x3 + w5 * x2 + w5 * x1 + w4 * x7 + w4 * x6 + w4 * x4 + w4 * x3 + w3 * x6 + w3 * x5 + w3 * x4 + w3 * x3 + w2 * x2 + w2 * x0 + w1 * x6 + w1 * x5 + w1 * x4 + w1 * x3 + w1 * x2 + w0 * x7 + w0 * x5 + w0 * x4 + x7**2 + x7 * x4 + x7 * x2 + x6 * x4 + x6 * x3 + x6 * x2 + x6 * x1 + x5**2 + x5 * x4 + x5 * x3 + x5 * x2 + x5 * x0 + x4 * x3 + x4 * x2 + x4 * x1 + x3**2 + x2 * x0 + x1 * x0, + w7 * x6 + w7 * x5 + w7 * x3 + w7 * x2 + w6 * x5 + w6 * x4 + w6 * x3 + w6 * x2 + w5 * x7 + w5 * x1 + w4 * x5 + w4 * x4 + w4 * x3 + w4 * x2 + w4 * x1 + w3 * x7 + w3 * x6 + w3 * x4 + w3 * x3 + w2 * x6 + w2 * x5 + w2 * x4 + w2 * x3 + w1 * x2 + w1 * x0 + w0 * x6 + w0 * x5 + w0 * x4 + w0 * x3 + w0 * x2 + x7 * x5 + x7 * x2 + x7 * x0 + x6**2 + x6 * x5 + x6 * x2 + x6 * x1 + x6 * x0 + x5**2 + x5 * x4 + x4**2 + x4 * x2 + x4 * x1 + x4 * x0 + x3**2 + x3 * x2 + x1 * x0, + w7**2 + w7 * w5 + w7 * w3 + w7 * x7 + w7 * x6 + w7 * x4 + w7 * x3 + w7 * x2 + w6**2 + w6 * w5 + w6 * w2 + w6 * w0 + w6 * x7 + w6 * x6 + w6 * x3 + w6 * x2 + w6 * x1 + w6 * x0 + w5**2 + w5 * x7 + w5 * x6 + w5 * x5 + w5 * x4 + w5 * x2 + w5 * x1 + w4**2 + w4 * w3 + w4 * w2 + w4 * w1 + w4 * x6 + w4 * x5 + w4 * x2 + w4 * x1 + w3**2 + w3 * w1 + w3 * x6 + w3 * x5 + w3 * x3 + w3 * x0 + w2 * w1 + w2 * x7 + w2 * x4 + w2 * x2 + w2 * x1 + w1 * x6 + w1 * x5 + w1 * x1 + w0 * x5, + w7 * w5 + w7 * w2 + w7 * w0 + w7 * x5 + w7 * x3 + w6**2 + w6 * w5 + w6 * w2 + w6 * w1 + w6 * w0 + w6 * x7 + w6 * x3 + w6 * x2 + w6 * x0 + w5**2 + w5 * w4 + w5 * x7 + w5 * x6 + w5 * x4 + w5 * x2 + w5 * x0 + w4**2 + w4 * w2 + w4 * w1 + w4 * w0 + w4 * x6 + w4 * x4 + w4 * x3 + w4 * x2 + w4 * x0 + w3**2 + w3 * w2 + w3 * x7 + w3 * x6 + w3 * x4 + w3 * x3 + w3 * x2 + w3 * x0 + w2 * x7 + w2 * x6 + w2 * x4 + w2 * x1 + w2 * x0 + w1 * w0 + w1 * x5 + w1 * x4 + w0 * x1, + w7**2 + w7 * w4 + w7 * w2 + w7 * x6 + w7 * x4 + w7 * x0 + w6 * w4 + w6 * w3 + w6 * w2 + w6 * w1 + w6 * x4 + w6 * x3 + w6 * x1 + w5**2 + w5 * w4 + w5 * w3 + w5 * w2 + w5 * w0 + w5 * x7 + w5 * x5 + w5 * x3 + w5 * x1 + w5 * x0 + w4 * w3 + w4 * w2 + w4 * w1 + w4 * x7 + w4 * x5 + w4 * x4 + w4 * x3 + w4 * x1 + w4 * x0 + w3**2 + w3 * x7 + w3 * x5 + w3 * x4 + w3 * x3 + w3 * x1 + w2 * w0 + w2 * x7 + w2 * x5 + w2 * x2 + w2 * x1 + w1 * w0 + w1 * x6 + w1 * x5 + w0 * x2, + ] + ) return l @@ -3032,7 +2946,7 @@ def _inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, if x is None and w is None: # make sure it prints like in the book. names = ["w%d" % i for i in reversed(range(e))] + ["x%d" % i for i in reversed(range(e))] - P = PolynomialRing(GF(2), e*2, names, order='lex') + P = PolynomialRing(GF(2), e * 2, names, order='lex') x = matrix(P, e, 1, P.gens()[e:]) w = matrix(P, e, 1, P.gens()[:e]) else: @@ -3049,7 +2963,7 @@ def _inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, w = matrix(P, e, 1, w) T = self._mul_matrix(self.k.gen()) - o = matrix(P, e, 1, [0]*(e-1) + [1]) + o = matrix(P, e, 1, [0] * (e - 1) + [1]) columns = [] for i in reversed(range(e)): @@ -3065,14 +2979,14 @@ def _inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, l = [] if correct_only: - l.append( (Cw * x + o).list()[:-1] ) + l.append((Cw * x + o).list()[:-1]) else: - l.append( (Cw * x + o).list() ) - l.append( (Cw * S * x + x).list() ) - l.append( (Cx * S * w + w).list() ) + l.append((Cw * x + o).list()) + l.append((Cw * S * x + x).list()) + l.append((Cx * S * w + w).list()) if not biaffine_only: - l.append( ((Cw * S**2 + Cx*S)*x).list() ) - l.append( ((Cx * S**2 + Cw*S)*w).list() ) + l.append(((Cw * S**2 + Cx * S) * x).list()) + l.append(((Cx * S**2 + Cw * S) * w).list()) return sum(l, []) @@ -3106,7 +3020,7 @@ def inversion_polynomials(self, xi, wi, length): e = self.e l = [] for j in range(0, length, e): - l += self.inversion_polynomials_single_sbox(xi[j:j+e], wi[j:j+e]) + l += self.inversion_polynomials_single_sbox(xi[j : j + e], wi[j : j + e]) return l def field_polynomials(self, name, i, l=None): @@ -3140,12 +3054,12 @@ def field_polynomials(self, name, i, l=None): e = self._e if l is None: - l = r*c + l = r * c if self._polybori: return [] _vars = self.vars(name, i, l, e) - return [_vars[e*j+k]**2 - _vars[e*j+k] for j in range(l) for k in range(e)] + return [_vars[e * j + k] ** 2 - _vars[e * j + k] for j in range(l) for k in range(e)] class SR_gf2_2(SR_gf2): @@ -3155,6 +3069,7 @@ class SR_gf2_2(SR_gf2): In this example, we replace the S-Box inversion polynomials by the polynomials generated by the S-Box class. """ + def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, correct_only=None, groebner=False): """ Return inversion polynomials of a single S-Box. @@ -3224,12 +3139,12 @@ def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, if x is None and w is None: # make sure it prints like in the book. names = ["w%d" % i for i in reversed(range(e))] + ["x%d" % i for i in reversed(range(e))] - P = PolynomialRing(GF(2), e*2, names, order='lex') + P = PolynomialRing(GF(2), e * 2, names, order='lex') x = P.gens()[e:] w = P.gens()[:e] S = self.sbox(inversion_only=True) - F = S.polynomials(w, x, degree=e-2, groebner=groebner) + F = S.polynomials(w, x, degree=e - 2, groebner=groebner) return F @@ -3237,6 +3152,7 @@ class AllowZeroInversionsContext: """ Temporarily allow zero inversion. """ + def __init__(self, sr): """ EXAMPLES:: @@ -3309,7 +3225,7 @@ def check_consistency(max_n=2, **kwargs): for r in (1, 2, 4): for c in (1, 2, 4): for e in (4, 8): - for n in range(1, max_n+1): + for n in range(1, max_n + 1): for gf2 in (True, False): zero_division = True while zero_division: @@ -3317,7 +3233,7 @@ def check_consistency(max_n=2, **kwargs): try: F, s = sr.polynomial_system() F = F.subs(s) - consistent &= (F.groebner_basis()[0] != 1) + consistent &= F.groebner_basis()[0] != 1 if not consistent: print(str(sr) + " is not consistent") zero_division = False diff --git a/src/sage/crypto/public_key/blum_goldwasser.py b/src/sage/crypto/public_key/blum_goldwasser.py index a7f5aa03c21..32b6e95acc1 100644 --- a/src/sage/crypto/public_key/blum_goldwasser.py +++ b/src/sage/crypto/public_key/blum_goldwasser.py @@ -328,7 +328,7 @@ def decrypt(self, C, K): # sanity checks if p == q: raise ValueError("p and q must be distinct Blum primes.") - if (a*p + b*q) != 1: + if (a * p + b * q) != 1: raise ValueError("a and b must satisfy gcd(p, q) = ap + bq = 1.") if (not is_blum_prime(p)) or (not is_blum_prime(q)): raise ValueError("p and q must be distinct Blum primes.") @@ -337,7 +337,7 @@ def decrypt(self, C, K): d2 = power_mod((q + 1) // 4, t + 1, q - 1) u = power_mod(xt1, d1, p) v = power_mod(xt1, d2, q) - x0 = mod(v*a*p + u*b*q, n).lift() + x0 = mod(v * a * p + u * b * q, n).lift() # perform the decryption M = [] for i in range(t): @@ -524,7 +524,7 @@ def encrypt(self, P, K, seed=None): p = least_significant_bits(x1, h) # xor p with a sub-block of length h. There are t sub-blocks of # length h each. - C.append(list(map(xor, p, [to_int(_) for _ in M[i*h : (i+1)*h]]))) + C.append(list(map(xor, p, [to_int(_) for _ in M[i * h : (i + 1) * h]]))) x0 = x1 x1 = power_mod(x0, 2, n) return (C, x1) diff --git a/src/sage/crypto/public_key/key_exchange/sidh.py b/src/sage/crypto/public_key/key_exchange/sidh.py index 1a1acd17068..db5a96595be 100644 --- a/src/sage/crypto/public_key/key_exchange/sidh.py +++ b/src/sage/crypto/public_key/key_exchange/sidh.py @@ -177,9 +177,7 @@ def trial_points(): if 2 ** (e_A - 1) * PA in PA_mults: break else: - raise ValueError( - 'failed to find PA, try using SIDH constructor directly and specify all parameters' - ) + raise ValueError('failed to find PA, try using SIDH constructor directly and specify all parameters') E_00 = E(0, 0) for R in trial_points(): @@ -187,9 +185,7 @@ def trial_points(): if 2 ** (e_A - 1) * QA == E_00: break else: - raise ValueError( - 'failed to find QA, try using SIDH constructor directly and specify all parameters' - ) + raise ValueError('failed to find QA, try using SIDH constructor directly and specify all parameters') for c in range(p): fc = f.subs(x=c) @@ -199,9 +195,7 @@ def trial_points(): if PB.order() == 3**e_B: break else: - raise ValueError( - 'failed to find PB, try using SIDH constructor directly and specify all parameters' - ) + raise ValueError('failed to find PB, try using SIDH constructor directly and specify all parameters') for c in range(p): fc = f.subs(x=c) @@ -211,9 +205,7 @@ def trial_points(): if QB.order() == 3**e_B: break else: - raise ValueError( - 'failed to find QB, try using SIDH constructor directly and specify all parameters' - ) + raise ValueError('failed to find QB, try using SIDH constructor directly and specify all parameters') return cls(E, PA, QA, PB, QB) @classmethod @@ -378,9 +370,7 @@ def alice_public_key(self, alice_secret_key: SecretKeySIDH) -> PublicKeySIDH: Alice's public key as a tuple `(E_A, P'_B, Q'_B)`. """ - phi_A, _ = self.secret_isogeny_path( - self._E, alice_secret_key, self._PA, self._QA - ) + phi_A, _ = self.secret_isogeny_path(self._E, alice_secret_key, self._PA, self._QA) return phi_A.codomain(), phi_A(self._PB), phi_A(self._QB) def bob_public_key(self, bob_secret_key: SecretKeySIDH) -> PublicKeySIDH: @@ -399,9 +389,7 @@ def bob_public_key(self, bob_secret_key: SecretKeySIDH) -> PublicKeySIDH: phi_B, _ = self.secret_isogeny_path(self._E, bob_secret_key, self._PB, self._QB) return phi_B.codomain(), phi_B(self._PA), phi_B(self._QA) - def alice_compute_shared_secret( - self, alice_secret_key: SecretKeySIDH, bob_public_key: PublicKeySIDH - ) -> Integer: + def alice_compute_shared_secret(self, alice_secret_key: SecretKeySIDH, bob_public_key: PublicKeySIDH) -> Integer: r""" Compute the shared secret using Alice's secret key and Bob's public key. """ @@ -410,9 +398,7 @@ def alice_compute_shared_secret( E_AB = phi_A1.codomain() return E_AB.j_invariant() - def bob_compute_shared_secret( - self, bob_secret_key: SecretKeySIDH, alice_public_key: PublicKeySIDH - ) -> Integer: + def bob_compute_shared_secret(self, bob_secret_key: SecretKeySIDH, alice_public_key: PublicKeySIDH) -> Integer: r""" Compute the shared secret using Bob's secret key and Alice's public key. """ diff --git a/src/sage/crypto/sboxes.py b/src/sage/crypto/sboxes.py index 5504f1d31de..ed02bfeaceb 100644 --- a/src/sage/crypto/sboxes.py +++ b/src/sage/crypto/sboxes.py @@ -191,7 +191,7 @@ def bracken_leander(n): raise TypeError("Bracken-Leander functions are only defined for n = 4k with k odd") k = n / 4 - e = 2**(2*k) + 2**k + 1 + e = 2 ** (2 * k) + 2**k + 1 return monomial_function(n, e) @@ -226,42 +226,43 @@ def carlet_tang_tang_liao(n, c=None, bf=None): if c is None: c = K.random_element() - while c.trace() == 0 or (1/c).trace() == 0: + while c.trace() == 0 or (1 / c).trace() == 0: c = K.random_element() - elif c.trace() == 0 or (1/c).trace() == 0: + elif c.trace() == 0 or (1 / c).trace() == 0: raise TypeError("c.trace() and (1/c).trace() have to be 1") if bf is None: + def bf(x): if x == 1: return 0 - return (1/(x+1)).trace() + return (1 / (x + 1)).trace() elif isinstance(bf, (BooleanFunction,)): bf_f2 = bf def bf(x): xprime = map(int, x.polynomial().list()) - xprime += [0]*(n-1 - len(xprime)) + xprime += [0] * (n - 1 - len(xprime)) return int(bf_f2(xprime)) def f(x): xs = x.polynomial().list() - xs += [0]*(n - len(xs)) - xprime = K(xs[:n-1]) + xs += [0] * (n - len(xs)) + xprime = K(xs[: n - 1]) if xprime == 0: - res = [0]*(n-1), bf(xprime/c) + xs[-1] + res = [0] * (n - 1), bf(xprime / c) + xs[-1] elif xs[-1] == 0: - res = (1/xprime).polynomial().list(), bf(xprime) + res = (1 / xprime).polynomial().list(), bf(xprime) else: - res = (c/xprime).polynomial().list(), bf(xprime/c) + 1 + res = (c / xprime).polynomial().list(), bf(xprime / c) + 1 - res = res[0] + [0]*(n-1-len(res[0])) + [res[1]] + res = res[0] + [0] * (n - 1 - len(res[0])) + [res[1]] return L(res) - return SBox([f(L(x)) for x in GF(2)**n]) + return SBox([f(L(x)) for x in GF(2) ** n]) def gold(n, i): @@ -309,7 +310,7 @@ def kasami(n, i): sage: kasami(4, 2) != gold(4, 2) True """ - e = 2**(2*i) - 2**i + 1 + e = 2 ** (2 * i) - 2**i + 1 return monomial_function(n, e) @@ -339,9 +340,9 @@ def niho(n): t = (n - 1) / 2 if is_even(t): - e = 2**t + 2**(t/2) - 1 + e = 2**t + 2 ** (t / 2) - 1 else: - e = 2**t + 2**((3*t+1)/2) - 1 + e = 2**t + 2 ** ((3 * t + 1) / 2) - 1 return monomial_function(n, e) @@ -447,11 +448,11 @@ def chi(n): from sage.rings.finite_rings.finite_field_constructor import GF from sage.modules.free_module_element import vector - table = [0]*(1 << n) + table = [0] * (1 << n) for x in range(1 << n): vx = vector(GF(2), ZZ(x).digits(base=2, padto=n)) - vy = [vx[i] + (vx[(i+1) % n] + 1)*vx[(i+2) % n] for i in range(n)] + vy = [vx[i] + (vx[(i + 1) % n] + 1) * vx[(i + 2) % n] for i in range(n)] y = ZZ(vy, base=2) table[x] = y @@ -463,1151 +464,13989 @@ def chi(n): # https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/round-2/spec-doc-rnd2/drygascon-spec-round2.pdf Page 34, Table 24 # https://github.com/sebastien-riou/DryGASCON/blob/master/Implementations/lwc/crypto_hash/drygascon256hash/ref/drygascon_ref.h#L118 -DryGASCON256 = SBox([ - 0x10, 0x93, 0x11f, 0x9d, 0x1f, 0x9c, 0x113, 0x91, 0x2a, 0xa9, 0x127, 0xa5, 0x27, 0xa4, 0x129, 0xab, - 0x2c, 0xaf, 0x123, 0xa1, 0x23, 0xa0, 0x12f, 0xad, 0x1a, 0x99, 0x117, 0x95, 0x17, 0x94, 0x119, 0x9b, - 0xf8, 0x7b, 0x1f7, 0x75, 0xf7, 0x74, 0x1fb, 0x79, 0xca, 0x49, 0x1c7, 0x45, 0xc7, 0x44, 0x1c9, 0x4b, - 0xcc, 0x4f, 0x1c3, 0x41, 0xc3, 0x40, 0x1cf, 0x4d, 0xf2, 0x71, 0x1ff, 0x7d, 0xff, 0x7c, 0x1f1, 0x73, - 0xe0, 0x63, 0x1ef, 0x6d, 0xef, 0x6c, 0x1e3, 0x61, 0xda, 0x59, 0x1d7, 0x55, 0xd7, 0x54, 0x1d9, 0x5b, - 0xdc, 0x5f, 0x1d3, 0x51, 0xd3, 0x50, 0x1df, 0x5d, 0xea, 0x69, 0x1e7, 0x65, 0xe7, 0x64, 0x1e9, 0x6b, - 0x38, 0xbb, 0x137, 0xb5, 0x37, 0xb4, 0x13b, 0xb9, 0x0a, 0x89, 0x107, 0x85, 0x07, 0x84, 0x109, 0x8b, - 0x0c, 0x8f, 0x103, 0x81, 0x03, 0x80, 0x10f, 0x8d, 0x32, 0xb1, 0x13f, 0xbd, 0x3f, 0xbc, 0x131, 0xb3, - 0x1b1, 0x1b2, 0xbe, 0x1bc, 0x1be, 0x1bd, 0xb2, 0x1b0, 0x18b, 0x188, 0x86, 0x184, 0x186, 0x185, 0x88, 0x18a, - 0x18d, 0x18e, 0x82, 0x180, 0x182, 0x181, 0x8e, 0x18c, 0x1bb, 0x1b8, 0xb6, 0x1b4, 0x1b6, 0x1b5, 0xb8, 0x1ba, - 0x179, 0x17a, 0x76, 0x174, 0x176, 0x175, 0x7a, 0x178, 0x14b, 0x148, 0x46, 0x144, 0x146, 0x145, 0x48, 0x14a, - 0x14d, 0x14e, 0x42, 0x140, 0x142, 0x141, 0x4e, 0x14c, 0x173, 0x170, 0x7e, 0x17c, 0x17e, 0x17d, 0x70, 0x172, - 0x161, 0x162, 0x6e, 0x16c, 0x16e, 0x16d, 0x62, 0x160, 0x15b, 0x158, 0x56, 0x154, 0x156, 0x155, 0x58, 0x15a, - 0x15d, 0x15e, 0x52, 0x150, 0x152, 0x151, 0x5e, 0x15c, 0x16b, 0x168, 0x66, 0x164, 0x166, 0x165, 0x68, 0x16a, - 0x199, 0x19a, 0x96, 0x194, 0x196, 0x195, 0x9a, 0x198, 0x1ab, 0x1a8, 0xa6, 0x1a4, 0x1a6, 0x1a5, 0xa8, 0x1aa, - 0x1ad, 0x1ae, 0xa2, 0x1a0, 0x1a2, 0x1a1, 0xae, 0x1ac, 0x193, 0x190, 0x9e, 0x19c, 0x19e, 0x19d, 0x90, 0x192, - 0x1d2, 0x1d1, 0x1dc, 0xde, 0x1dd, 0x1de, 0x1d0, 0xd2, 0x1e8, 0x1eb, 0x1e4, 0xe6, 0x1e5, 0x1e6, 0x1ea, 0xe8, - 0x1ee, 0x1ed, 0x1e0, 0xe2, 0x1e1, 0x1e2, 0x1ec, 0xee, 0x1d8, 0x1db, 0x1d4, 0xd6, 0x1d5, 0x1d6, 0x1da, 0xd8, - 0x13a, 0x139, 0x134, 0x36, 0x135, 0x136, 0x138, 0x3a, 0x108, 0x10b, 0x104, 0x06, 0x105, 0x106, 0x10a, 0x08, - 0x10e, 0x10d, 0x100, 0x02, 0x101, 0x102, 0x10c, 0x0e, 0x130, 0x133, 0x13c, 0x3e, 0x13d, 0x13e, 0x132, 0x30, - 0x122, 0x121, 0x12c, 0x2e, 0x12d, 0x12e, 0x120, 0x22, 0x118, 0x11b, 0x114, 0x16, 0x115, 0x116, 0x11a, 0x18, - 0x11e, 0x11d, 0x110, 0x12, 0x111, 0x112, 0x11c, 0x1e, 0x128, 0x12b, 0x124, 0x26, 0x125, 0x126, 0x12a, 0x28, - 0x1fa, 0x1f9, 0x1f4, 0xf6, 0x1f5, 0x1f6, 0x1f8, 0xfa, 0x1c8, 0x1cb, 0x1c4, 0xc6, 0x1c5, 0x1c6, 0x1ca, 0xc8, - 0x1ce, 0x1cd, 0x1c0, 0xc2, 0x1c1, 0x1c2, 0x1cc, 0xce, 0x1f0, 0x1f3, 0x1fc, 0xfe, 0x1fd, 0x1fe, 0x1f2, 0xf0, - 0x33, 0xb0, 0x3d, 0x1bf, 0x3c, 0xbf, 0x31, 0x1b3, 0x09, 0x8a, 0x05, 0x187, 0x04, 0x87, 0x0b, 0x189, - 0x0f, 0x8c, 0x01, 0x183, 0x00, 0x83, 0x0d, 0x18f, 0x39, 0xba, 0x35, 0x1b7, 0x34, 0xb7, 0x3b, 0x1b9, - 0xfb, 0x78, 0xf5, 0x177, 0xf4, 0x77, 0xf9, 0x17b, 0xc9, 0x4a, 0xc5, 0x147, 0xc4, 0x47, 0xcb, 0x149, - 0xcf, 0x4c, 0xc1, 0x143, 0xc0, 0x43, 0xcd, 0x14f, 0xf1, 0x72, 0xfd, 0x17f, 0xfc, 0x7f, 0xf3, 0x171, - 0xe3, 0x60, 0xed, 0x16f, 0xec, 0x6f, 0xe1, 0x163, 0xd9, 0x5a, 0xd5, 0x157, 0xd4, 0x57, 0xdb, 0x159, - 0xdf, 0x5c, 0xd1, 0x153, 0xd0, 0x53, 0xdd, 0x15f, 0xe9, 0x6a, 0xe5, 0x167, 0xe4, 0x67, 0xeb, 0x169, - 0x1b, 0x98, 0x15, 0x197, 0x14, 0x97, 0x19, 0x19b, 0x29, 0xaa, 0x25, 0x1a7, 0x24, 0xa7, 0x2b, 0x1a9, - 0x2f, 0xac, 0x21, 0x1a3, 0x20, 0xa3, 0x2d, 0x1af, 0x11, 0x92, 0x1d, 0x19f, 0x1c, 0x9f, 0x13, 0x191]) +DryGASCON256 = SBox( + [ + 0x10, + 0x93, + 0x11F, + 0x9D, + 0x1F, + 0x9C, + 0x113, + 0x91, + 0x2A, + 0xA9, + 0x127, + 0xA5, + 0x27, + 0xA4, + 0x129, + 0xAB, + 0x2C, + 0xAF, + 0x123, + 0xA1, + 0x23, + 0xA0, + 0x12F, + 0xAD, + 0x1A, + 0x99, + 0x117, + 0x95, + 0x17, + 0x94, + 0x119, + 0x9B, + 0xF8, + 0x7B, + 0x1F7, + 0x75, + 0xF7, + 0x74, + 0x1FB, + 0x79, + 0xCA, + 0x49, + 0x1C7, + 0x45, + 0xC7, + 0x44, + 0x1C9, + 0x4B, + 0xCC, + 0x4F, + 0x1C3, + 0x41, + 0xC3, + 0x40, + 0x1CF, + 0x4D, + 0xF2, + 0x71, + 0x1FF, + 0x7D, + 0xFF, + 0x7C, + 0x1F1, + 0x73, + 0xE0, + 0x63, + 0x1EF, + 0x6D, + 0xEF, + 0x6C, + 0x1E3, + 0x61, + 0xDA, + 0x59, + 0x1D7, + 0x55, + 0xD7, + 0x54, + 0x1D9, + 0x5B, + 0xDC, + 0x5F, + 0x1D3, + 0x51, + 0xD3, + 0x50, + 0x1DF, + 0x5D, + 0xEA, + 0x69, + 0x1E7, + 0x65, + 0xE7, + 0x64, + 0x1E9, + 0x6B, + 0x38, + 0xBB, + 0x137, + 0xB5, + 0x37, + 0xB4, + 0x13B, + 0xB9, + 0x0A, + 0x89, + 0x107, + 0x85, + 0x07, + 0x84, + 0x109, + 0x8B, + 0x0C, + 0x8F, + 0x103, + 0x81, + 0x03, + 0x80, + 0x10F, + 0x8D, + 0x32, + 0xB1, + 0x13F, + 0xBD, + 0x3F, + 0xBC, + 0x131, + 0xB3, + 0x1B1, + 0x1B2, + 0xBE, + 0x1BC, + 0x1BE, + 0x1BD, + 0xB2, + 0x1B0, + 0x18B, + 0x188, + 0x86, + 0x184, + 0x186, + 0x185, + 0x88, + 0x18A, + 0x18D, + 0x18E, + 0x82, + 0x180, + 0x182, + 0x181, + 0x8E, + 0x18C, + 0x1BB, + 0x1B8, + 0xB6, + 0x1B4, + 0x1B6, + 0x1B5, + 0xB8, + 0x1BA, + 0x179, + 0x17A, + 0x76, + 0x174, + 0x176, + 0x175, + 0x7A, + 0x178, + 0x14B, + 0x148, + 0x46, + 0x144, + 0x146, + 0x145, + 0x48, + 0x14A, + 0x14D, + 0x14E, + 0x42, + 0x140, + 0x142, + 0x141, + 0x4E, + 0x14C, + 0x173, + 0x170, + 0x7E, + 0x17C, + 0x17E, + 0x17D, + 0x70, + 0x172, + 0x161, + 0x162, + 0x6E, + 0x16C, + 0x16E, + 0x16D, + 0x62, + 0x160, + 0x15B, + 0x158, + 0x56, + 0x154, + 0x156, + 0x155, + 0x58, + 0x15A, + 0x15D, + 0x15E, + 0x52, + 0x150, + 0x152, + 0x151, + 0x5E, + 0x15C, + 0x16B, + 0x168, + 0x66, + 0x164, + 0x166, + 0x165, + 0x68, + 0x16A, + 0x199, + 0x19A, + 0x96, + 0x194, + 0x196, + 0x195, + 0x9A, + 0x198, + 0x1AB, + 0x1A8, + 0xA6, + 0x1A4, + 0x1A6, + 0x1A5, + 0xA8, + 0x1AA, + 0x1AD, + 0x1AE, + 0xA2, + 0x1A0, + 0x1A2, + 0x1A1, + 0xAE, + 0x1AC, + 0x193, + 0x190, + 0x9E, + 0x19C, + 0x19E, + 0x19D, + 0x90, + 0x192, + 0x1D2, + 0x1D1, + 0x1DC, + 0xDE, + 0x1DD, + 0x1DE, + 0x1D0, + 0xD2, + 0x1E8, + 0x1EB, + 0x1E4, + 0xE6, + 0x1E5, + 0x1E6, + 0x1EA, + 0xE8, + 0x1EE, + 0x1ED, + 0x1E0, + 0xE2, + 0x1E1, + 0x1E2, + 0x1EC, + 0xEE, + 0x1D8, + 0x1DB, + 0x1D4, + 0xD6, + 0x1D5, + 0x1D6, + 0x1DA, + 0xD8, + 0x13A, + 0x139, + 0x134, + 0x36, + 0x135, + 0x136, + 0x138, + 0x3A, + 0x108, + 0x10B, + 0x104, + 0x06, + 0x105, + 0x106, + 0x10A, + 0x08, + 0x10E, + 0x10D, + 0x100, + 0x02, + 0x101, + 0x102, + 0x10C, + 0x0E, + 0x130, + 0x133, + 0x13C, + 0x3E, + 0x13D, + 0x13E, + 0x132, + 0x30, + 0x122, + 0x121, + 0x12C, + 0x2E, + 0x12D, + 0x12E, + 0x120, + 0x22, + 0x118, + 0x11B, + 0x114, + 0x16, + 0x115, + 0x116, + 0x11A, + 0x18, + 0x11E, + 0x11D, + 0x110, + 0x12, + 0x111, + 0x112, + 0x11C, + 0x1E, + 0x128, + 0x12B, + 0x124, + 0x26, + 0x125, + 0x126, + 0x12A, + 0x28, + 0x1FA, + 0x1F9, + 0x1F4, + 0xF6, + 0x1F5, + 0x1F6, + 0x1F8, + 0xFA, + 0x1C8, + 0x1CB, + 0x1C4, + 0xC6, + 0x1C5, + 0x1C6, + 0x1CA, + 0xC8, + 0x1CE, + 0x1CD, + 0x1C0, + 0xC2, + 0x1C1, + 0x1C2, + 0x1CC, + 0xCE, + 0x1F0, + 0x1F3, + 0x1FC, + 0xFE, + 0x1FD, + 0x1FE, + 0x1F2, + 0xF0, + 0x33, + 0xB0, + 0x3D, + 0x1BF, + 0x3C, + 0xBF, + 0x31, + 0x1B3, + 0x09, + 0x8A, + 0x05, + 0x187, + 0x04, + 0x87, + 0x0B, + 0x189, + 0x0F, + 0x8C, + 0x01, + 0x183, + 0x00, + 0x83, + 0x0D, + 0x18F, + 0x39, + 0xBA, + 0x35, + 0x1B7, + 0x34, + 0xB7, + 0x3B, + 0x1B9, + 0xFB, + 0x78, + 0xF5, + 0x177, + 0xF4, + 0x77, + 0xF9, + 0x17B, + 0xC9, + 0x4A, + 0xC5, + 0x147, + 0xC4, + 0x47, + 0xCB, + 0x149, + 0xCF, + 0x4C, + 0xC1, + 0x143, + 0xC0, + 0x43, + 0xCD, + 0x14F, + 0xF1, + 0x72, + 0xFD, + 0x17F, + 0xFC, + 0x7F, + 0xF3, + 0x171, + 0xE3, + 0x60, + 0xED, + 0x16F, + 0xEC, + 0x6F, + 0xE1, + 0x163, + 0xD9, + 0x5A, + 0xD5, + 0x157, + 0xD4, + 0x57, + 0xDB, + 0x159, + 0xDF, + 0x5C, + 0xD1, + 0x153, + 0xD0, + 0x53, + 0xDD, + 0x15F, + 0xE9, + 0x6A, + 0xE5, + 0x167, + 0xE4, + 0x67, + 0xEB, + 0x169, + 0x1B, + 0x98, + 0x15, + 0x197, + 0x14, + 0x97, + 0x19, + 0x19B, + 0x29, + 0xAA, + 0x25, + 0x1A7, + 0x24, + 0xA7, + 0x2B, + 0x1A9, + 0x2F, + 0xAC, + 0x21, + 0x1A3, + 0x20, + 0xA3, + 0x2D, + 0x1AF, + 0x11, + 0x92, + 0x1D, + 0x19F, + 0x1C, + 0x9F, + 0x13, + 0x191, + ] +) # Bijective S-Boxes mapping 8 bits to 8 # ===================================== -AES = SBox([ - 0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, - 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, - 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, - 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, - 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, - 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, - 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, - 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, - 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, - 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, - 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, - 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, - 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, - 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, - 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, - 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16]) +AES = SBox( + [ + 0x63, + 0x7C, + 0x77, + 0x7B, + 0xF2, + 0x6B, + 0x6F, + 0xC5, + 0x30, + 0x01, + 0x67, + 0x2B, + 0xFE, + 0xD7, + 0xAB, + 0x76, + 0xCA, + 0x82, + 0xC9, + 0x7D, + 0xFA, + 0x59, + 0x47, + 0xF0, + 0xAD, + 0xD4, + 0xA2, + 0xAF, + 0x9C, + 0xA4, + 0x72, + 0xC0, + 0xB7, + 0xFD, + 0x93, + 0x26, + 0x36, + 0x3F, + 0xF7, + 0xCC, + 0x34, + 0xA5, + 0xE5, + 0xF1, + 0x71, + 0xD8, + 0x31, + 0x15, + 0x04, + 0xC7, + 0x23, + 0xC3, + 0x18, + 0x96, + 0x05, + 0x9A, + 0x07, + 0x12, + 0x80, + 0xE2, + 0xEB, + 0x27, + 0xB2, + 0x75, + 0x09, + 0x83, + 0x2C, + 0x1A, + 0x1B, + 0x6E, + 0x5A, + 0xA0, + 0x52, + 0x3B, + 0xD6, + 0xB3, + 0x29, + 0xE3, + 0x2F, + 0x84, + 0x53, + 0xD1, + 0x00, + 0xED, + 0x20, + 0xFC, + 0xB1, + 0x5B, + 0x6A, + 0xCB, + 0xBE, + 0x39, + 0x4A, + 0x4C, + 0x58, + 0xCF, + 0xD0, + 0xEF, + 0xAA, + 0xFB, + 0x43, + 0x4D, + 0x33, + 0x85, + 0x45, + 0xF9, + 0x02, + 0x7F, + 0x50, + 0x3C, + 0x9F, + 0xA8, + 0x51, + 0xA3, + 0x40, + 0x8F, + 0x92, + 0x9D, + 0x38, + 0xF5, + 0xBC, + 0xB6, + 0xDA, + 0x21, + 0x10, + 0xFF, + 0xF3, + 0xD2, + 0xCD, + 0x0C, + 0x13, + 0xEC, + 0x5F, + 0x97, + 0x44, + 0x17, + 0xC4, + 0xA7, + 0x7E, + 0x3D, + 0x64, + 0x5D, + 0x19, + 0x73, + 0x60, + 0x81, + 0x4F, + 0xDC, + 0x22, + 0x2A, + 0x90, + 0x88, + 0x46, + 0xEE, + 0xB8, + 0x14, + 0xDE, + 0x5E, + 0x0B, + 0xDB, + 0xE0, + 0x32, + 0x3A, + 0x0A, + 0x49, + 0x06, + 0x24, + 0x5C, + 0xC2, + 0xD3, + 0xAC, + 0x62, + 0x91, + 0x95, + 0xE4, + 0x79, + 0xE7, + 0xC8, + 0x37, + 0x6D, + 0x8D, + 0xD5, + 0x4E, + 0xA9, + 0x6C, + 0x56, + 0xF4, + 0xEA, + 0x65, + 0x7A, + 0xAE, + 0x08, + 0xBA, + 0x78, + 0x25, + 0x2E, + 0x1C, + 0xA6, + 0xB4, + 0xC6, + 0xE8, + 0xDD, + 0x74, + 0x1F, + 0x4B, + 0xBD, + 0x8B, + 0x8A, + 0x70, + 0x3E, + 0xB5, + 0x66, + 0x48, + 0x03, + 0xF6, + 0x0E, + 0x61, + 0x35, + 0x57, + 0xB9, + 0x86, + 0xC1, + 0x1D, + 0x9E, + 0xE1, + 0xF8, + 0x98, + 0x11, + 0x69, + 0xD9, + 0x8E, + 0x94, + 0x9B, + 0x1E, + 0x87, + 0xE9, + 0xCE, + 0x55, + 0x28, + 0xDF, + 0x8C, + 0xA1, + 0x89, + 0x0D, + 0xBF, + 0xE6, + 0x42, + 0x68, + 0x41, + 0x99, + 0x2D, + 0x0F, + 0xB0, + 0x54, + 0xBB, + 0x16, + ] +) FlexAEAD = AES -Anubis = SBox([ - 0xa7,0xd3,0xe6,0x71,0xd0,0xac,0x4d,0x79,0x3a,0xc9,0x91,0xfc,0x1e,0x47,0x54,0xbd, - 0x8c,0xa5,0x7a,0xfb,0x63,0xb8,0xdd,0xd4,0xe5,0xb3,0xc5,0xbe,0xa9,0x88,0x0c,0xa2, - 0x39,0xdf,0x29,0xda,0x2b,0xa8,0xcb,0x4c,0x4b,0x22,0xaa,0x24,0x41,0x70,0xa6,0xf9, - 0x5a,0xe2,0xb0,0x36,0x7d,0xe4,0x33,0xff,0x60,0x20,0x08,0x8b,0x5e,0xab,0x7f,0x78, - 0x7c,0x2c,0x57,0xd2,0xdc,0x6d,0x7e,0x0d,0x53,0x94,0xc3,0x28,0x27,0x06,0x5f,0xad, - 0x67,0x5c,0x55,0x48,0x0e,0x52,0xea,0x42,0x5b,0x5d,0x30,0x58,0x51,0x59,0x3c,0x4e, - 0x38,0x8a,0x72,0x14,0xe7,0xc6,0xde,0x50,0x8e,0x92,0xd1,0x77,0x93,0x45,0x9a,0xce, - 0x2d,0x03,0x62,0xb6,0xb9,0xbf,0x96,0x6b,0x3f,0x07,0x12,0xae,0x40,0x34,0x46,0x3e, - 0xdb,0xcf,0xec,0xcc,0xc1,0xa1,0xc0,0xd6,0x1d,0xf4,0x61,0x3b,0x10,0xd8,0x68,0xa0, - 0xb1,0x0a,0x69,0x6c,0x49,0xfa,0x76,0xc4,0x9e,0x9b,0x6e,0x99,0xc2,0xb7,0x98,0xbc, - 0x8f,0x85,0x1f,0xb4,0xf8,0x11,0x2e,0x00,0x25,0x1c,0x2a,0x3d,0x05,0x4f,0x7b,0xb2, - 0x32,0x90,0xaf,0x19,0xa3,0xf7,0x73,0x9d,0x15,0x74,0xee,0xca,0x9f,0x0f,0x1b,0x75, - 0x86,0x84,0x9c,0x4a,0x97,0x1a,0x65,0xf6,0xed,0x09,0xbb,0x26,0x83,0xeb,0x6f,0x81, - 0x04,0x6a,0x43,0x01,0x17,0xe1,0x87,0xf5,0x8d,0xe3,0x23,0x80,0x44,0x16,0x66,0x21, - 0xfe,0xd5,0x31,0xd9,0x35,0x18,0x02,0x64,0xf2,0xf1,0x56,0xcd,0x82,0xc8,0xba,0xf0, - 0xef,0xe9,0xe8,0xfd,0x89,0xd7,0xc7,0xb5,0xa4,0x2f,0x95,0x13,0x0b,0xf3,0xe0,0x37]) - -ARIA_s2 = SBox([ - 0xe2,0x4e,0x54,0xfc,0x94,0xc2,0x4a,0xcc,0x62,0x0d,0x6a,0x46,0x3c,0x4d,0x8b,0xd1, - 0x5e,0xfa,0x64,0xcb,0xb4,0x97,0xbe,0x2b,0xbc,0x77,0x2e,0x03,0xd3,0x19,0x59,0xc1, - 0x1d,0x06,0x41,0x6b,0x55,0xf0,0x99,0x69,0xea,0x9c,0x18,0xae,0x63,0xdf,0xe7,0xbb, - 0x00,0x73,0x66,0xfb,0x96,0x4c,0x85,0xe4,0x3a,0x09,0x45,0xaa,0x0f,0xee,0x10,0xeb, - 0x2d,0x7f,0xf4,0x29,0xac,0xcf,0xad,0x91,0x8d,0x78,0xc8,0x95,0xf9,0x2f,0xce,0xcd, - 0x08,0x7a,0x88,0x38,0x5c,0x83,0x2a,0x28,0x47,0xdb,0xb8,0xc7,0x93,0xa4,0x12,0x53, - 0xff,0x87,0x0e,0x31,0x36,0x21,0x58,0x48,0x01,0x8e,0x37,0x74,0x32,0xca,0xe9,0xb1, - 0xb7,0xab,0x0c,0xd7,0xc4,0x56,0x42,0x26,0x07,0x98,0x60,0xd9,0xb6,0xb9,0x11,0x40, - 0xec,0x20,0x8c,0xbd,0xa0,0xc9,0x84,0x04,0x49,0x23,0xf1,0x4f,0x50,0x1f,0x13,0xdc, - 0xd8,0xc0,0x9e,0x57,0xe3,0xc3,0x7b,0x65,0x3b,0x02,0x8f,0x3e,0xe8,0x25,0x92,0xe5, - 0x15,0xdd,0xfd,0x17,0xa9,0xbf,0xd4,0x9a,0x7e,0xc5,0x39,0x67,0xfe,0x76,0x9d,0x43, - 0xa7,0xe1,0xd0,0xf5,0x68,0xf2,0x1b,0x34,0x70,0x05,0xa3,0x8a,0xd5,0x79,0x86,0xa8, - 0x30,0xc6,0x51,0x4b,0x1e,0xa6,0x27,0xf6,0x35,0xd2,0x6e,0x24,0x16,0x82,0x5f,0xda, - 0xe6,0x75,0xa2,0xef,0x2c,0xb2,0x1c,0x9f,0x5d,0x6f,0x80,0x0a,0x72,0x44,0x9b,0x6c, - 0x90,0x0b,0x5b,0x33,0x7d,0x5a,0x52,0xf3,0x61,0xa1,0xf7,0xb0,0xd6,0x3f,0x7c,0x6d, - 0xed,0x14,0xe0,0xa5,0x3d,0x22,0xb3,0xf8,0x89,0xde,0x71,0x1a,0xaf,0xba,0xb5,0x81]) - -BelT = SBox([ - 0xb1,0x94,0xba,0xc8,0x0a,0x08,0xf5,0x3b,0x36,0x6d,0x00,0x8e,0x58,0x4a,0x5d,0xe4, - 0x85,0x04,0xfa,0x9d,0x1b,0xb6,0xc7,0xac,0x25,0x2e,0x72,0xc2,0x02,0xfd,0xce,0x0d, - 0x5b,0xe3,0xd6,0x12,0x17,0xb9,0x61,0x81,0xfe,0x67,0x86,0xad,0x71,0x6b,0x89,0x0b, - 0x5c,0xb0,0xc0,0xff,0x33,0xc3,0x56,0xb8,0x35,0xc4,0x05,0xae,0xd8,0xe0,0x7f,0x99, - 0xe1,0x2b,0xdc,0x1a,0xe2,0x82,0x57,0xec,0x70,0x3f,0xcc,0xf0,0x95,0xee,0x8d,0xf1, - 0xc1,0xab,0x76,0x38,0x9f,0xe6,0x78,0xca,0xf7,0xc6,0xf8,0x60,0xd5,0xbb,0x9c,0x4f, - 0xf3,0x3c,0x65,0x7b,0x63,0x7c,0x30,0x6a,0xdd,0x4e,0xa7,0x79,0x9e,0xb2,0x3d,0x31, - 0x3e,0x98,0xb5,0x6e,0x27,0xd3,0xbc,0xcf,0x59,0x1e,0x18,0x1f,0x4c,0x5a,0xb7,0x93, - 0xe9,0xde,0xe7,0x2c,0x8f,0x0c,0x0f,0xa6,0x2d,0xdb,0x49,0xf4,0x6f,0x73,0x96,0x47, - 0x06,0x07,0x53,0x16,0xed,0x24,0x7a,0x37,0x39,0xcb,0xa3,0x83,0x03,0xa9,0x8b,0xf6, - 0x92,0xbd,0x9b,0x1c,0xe5,0xd1,0x41,0x01,0x54,0x45,0xfb,0xc9,0x5e,0x4d,0x0e,0xf2, - 0x68,0x20,0x80,0xaa,0x22,0x7d,0x64,0x2f,0x26,0x87,0xf9,0x34,0x90,0x40,0x55,0x11, - 0xbe,0x32,0x97,0x13,0x43,0xfc,0x9a,0x48,0xa0,0x2a,0x88,0x5f,0x19,0x4b,0x09,0xa1, - 0x7e,0xcd,0xa4,0xd0,0x15,0x44,0xaf,0x8c,0xa5,0x84,0x50,0xbf,0x66,0xd2,0xe8,0x8a, - 0xa2,0xd7,0x46,0x52,0x42,0xa8,0xdf,0xb3,0x69,0x74,0xc5,0x51,0xeb,0x23,0x29,0x21, - 0xd4,0xef,0xd9,0xb4,0x3a,0x62,0x28,0x75,0x91,0x14,0x10,0xea,0x77,0x6c,0xda,0x1d]) - -Camellia = SBox([ - 112,130, 44,236,179, 39,192,229,228,133, 87, 53,234, 12,174, 65, - 35,239,107,147, 69, 25,165, 33,237, 14, 79, 78, 29,101,146,189, - 134,184,175,143,124,235, 31,206, 62, 48,220, 95, 94,197, 11, 26, - 166,225, 57,202,213, 71, 93, 61,217, 1, 90,214, 81, 86,108, 77, - 139, 13,154,102,251,204,176, 45,116, 18, 43, 32,240,177,132,153, - 223, 76,203,194, 52,126,118, 5,109,183,169, 49,209, 23, 4,215, - 20, 88, 58, 97,222, 27, 17, 28, 50, 15,156, 22, 83, 24,242, 34, - 254, 68,207,178,195,181,122,145, 36, 8,232,168, 96,252,105, 80, - 170,208,160,125,161,137, 98,151, 84, 91, 30,149,224,255,100,210, - 16,196, 0, 72,163,247,117,219,138, 3,230,218, 9, 63,221,148, - 135, 92,131, 2,205, 74,144, 51,115,103,246,243,157,127,191,226, - 82,155,216, 38,200, 55,198, 59,129,150,111, 75, 19,190, 99, 46, - 233,121,167,140,159,110,188,142, 41,245,249,182, 47,253,180, 89, - 120,152, 6,106,231, 70,113,186,212, 37,171, 66,136,162,141,250, - 114, 7,185, 85,248,238,172, 10, 54, 73, 42,104, 60, 56,241,164, - 64, 40,211,123,187,201, 67,193, 21,227,173,244,119,199,128,158]) +Anubis = SBox( + [ + 0xA7, + 0xD3, + 0xE6, + 0x71, + 0xD0, + 0xAC, + 0x4D, + 0x79, + 0x3A, + 0xC9, + 0x91, + 0xFC, + 0x1E, + 0x47, + 0x54, + 0xBD, + 0x8C, + 0xA5, + 0x7A, + 0xFB, + 0x63, + 0xB8, + 0xDD, + 0xD4, + 0xE5, + 0xB3, + 0xC5, + 0xBE, + 0xA9, + 0x88, + 0x0C, + 0xA2, + 0x39, + 0xDF, + 0x29, + 0xDA, + 0x2B, + 0xA8, + 0xCB, + 0x4C, + 0x4B, + 0x22, + 0xAA, + 0x24, + 0x41, + 0x70, + 0xA6, + 0xF9, + 0x5A, + 0xE2, + 0xB0, + 0x36, + 0x7D, + 0xE4, + 0x33, + 0xFF, + 0x60, + 0x20, + 0x08, + 0x8B, + 0x5E, + 0xAB, + 0x7F, + 0x78, + 0x7C, + 0x2C, + 0x57, + 0xD2, + 0xDC, + 0x6D, + 0x7E, + 0x0D, + 0x53, + 0x94, + 0xC3, + 0x28, + 0x27, + 0x06, + 0x5F, + 0xAD, + 0x67, + 0x5C, + 0x55, + 0x48, + 0x0E, + 0x52, + 0xEA, + 0x42, + 0x5B, + 0x5D, + 0x30, + 0x58, + 0x51, + 0x59, + 0x3C, + 0x4E, + 0x38, + 0x8A, + 0x72, + 0x14, + 0xE7, + 0xC6, + 0xDE, + 0x50, + 0x8E, + 0x92, + 0xD1, + 0x77, + 0x93, + 0x45, + 0x9A, + 0xCE, + 0x2D, + 0x03, + 0x62, + 0xB6, + 0xB9, + 0xBF, + 0x96, + 0x6B, + 0x3F, + 0x07, + 0x12, + 0xAE, + 0x40, + 0x34, + 0x46, + 0x3E, + 0xDB, + 0xCF, + 0xEC, + 0xCC, + 0xC1, + 0xA1, + 0xC0, + 0xD6, + 0x1D, + 0xF4, + 0x61, + 0x3B, + 0x10, + 0xD8, + 0x68, + 0xA0, + 0xB1, + 0x0A, + 0x69, + 0x6C, + 0x49, + 0xFA, + 0x76, + 0xC4, + 0x9E, + 0x9B, + 0x6E, + 0x99, + 0xC2, + 0xB7, + 0x98, + 0xBC, + 0x8F, + 0x85, + 0x1F, + 0xB4, + 0xF8, + 0x11, + 0x2E, + 0x00, + 0x25, + 0x1C, + 0x2A, + 0x3D, + 0x05, + 0x4F, + 0x7B, + 0xB2, + 0x32, + 0x90, + 0xAF, + 0x19, + 0xA3, + 0xF7, + 0x73, + 0x9D, + 0x15, + 0x74, + 0xEE, + 0xCA, + 0x9F, + 0x0F, + 0x1B, + 0x75, + 0x86, + 0x84, + 0x9C, + 0x4A, + 0x97, + 0x1A, + 0x65, + 0xF6, + 0xED, + 0x09, + 0xBB, + 0x26, + 0x83, + 0xEB, + 0x6F, + 0x81, + 0x04, + 0x6A, + 0x43, + 0x01, + 0x17, + 0xE1, + 0x87, + 0xF5, + 0x8D, + 0xE3, + 0x23, + 0x80, + 0x44, + 0x16, + 0x66, + 0x21, + 0xFE, + 0xD5, + 0x31, + 0xD9, + 0x35, + 0x18, + 0x02, + 0x64, + 0xF2, + 0xF1, + 0x56, + 0xCD, + 0x82, + 0xC8, + 0xBA, + 0xF0, + 0xEF, + 0xE9, + 0xE8, + 0xFD, + 0x89, + 0xD7, + 0xC7, + 0xB5, + 0xA4, + 0x2F, + 0x95, + 0x13, + 0x0B, + 0xF3, + 0xE0, + 0x37, + ] +) + +ARIA_s2 = SBox( + [ + 0xE2, + 0x4E, + 0x54, + 0xFC, + 0x94, + 0xC2, + 0x4A, + 0xCC, + 0x62, + 0x0D, + 0x6A, + 0x46, + 0x3C, + 0x4D, + 0x8B, + 0xD1, + 0x5E, + 0xFA, + 0x64, + 0xCB, + 0xB4, + 0x97, + 0xBE, + 0x2B, + 0xBC, + 0x77, + 0x2E, + 0x03, + 0xD3, + 0x19, + 0x59, + 0xC1, + 0x1D, + 0x06, + 0x41, + 0x6B, + 0x55, + 0xF0, + 0x99, + 0x69, + 0xEA, + 0x9C, + 0x18, + 0xAE, + 0x63, + 0xDF, + 0xE7, + 0xBB, + 0x00, + 0x73, + 0x66, + 0xFB, + 0x96, + 0x4C, + 0x85, + 0xE4, + 0x3A, + 0x09, + 0x45, + 0xAA, + 0x0F, + 0xEE, + 0x10, + 0xEB, + 0x2D, + 0x7F, + 0xF4, + 0x29, + 0xAC, + 0xCF, + 0xAD, + 0x91, + 0x8D, + 0x78, + 0xC8, + 0x95, + 0xF9, + 0x2F, + 0xCE, + 0xCD, + 0x08, + 0x7A, + 0x88, + 0x38, + 0x5C, + 0x83, + 0x2A, + 0x28, + 0x47, + 0xDB, + 0xB8, + 0xC7, + 0x93, + 0xA4, + 0x12, + 0x53, + 0xFF, + 0x87, + 0x0E, + 0x31, + 0x36, + 0x21, + 0x58, + 0x48, + 0x01, + 0x8E, + 0x37, + 0x74, + 0x32, + 0xCA, + 0xE9, + 0xB1, + 0xB7, + 0xAB, + 0x0C, + 0xD7, + 0xC4, + 0x56, + 0x42, + 0x26, + 0x07, + 0x98, + 0x60, + 0xD9, + 0xB6, + 0xB9, + 0x11, + 0x40, + 0xEC, + 0x20, + 0x8C, + 0xBD, + 0xA0, + 0xC9, + 0x84, + 0x04, + 0x49, + 0x23, + 0xF1, + 0x4F, + 0x50, + 0x1F, + 0x13, + 0xDC, + 0xD8, + 0xC0, + 0x9E, + 0x57, + 0xE3, + 0xC3, + 0x7B, + 0x65, + 0x3B, + 0x02, + 0x8F, + 0x3E, + 0xE8, + 0x25, + 0x92, + 0xE5, + 0x15, + 0xDD, + 0xFD, + 0x17, + 0xA9, + 0xBF, + 0xD4, + 0x9A, + 0x7E, + 0xC5, + 0x39, + 0x67, + 0xFE, + 0x76, + 0x9D, + 0x43, + 0xA7, + 0xE1, + 0xD0, + 0xF5, + 0x68, + 0xF2, + 0x1B, + 0x34, + 0x70, + 0x05, + 0xA3, + 0x8A, + 0xD5, + 0x79, + 0x86, + 0xA8, + 0x30, + 0xC6, + 0x51, + 0x4B, + 0x1E, + 0xA6, + 0x27, + 0xF6, + 0x35, + 0xD2, + 0x6E, + 0x24, + 0x16, + 0x82, + 0x5F, + 0xDA, + 0xE6, + 0x75, + 0xA2, + 0xEF, + 0x2C, + 0xB2, + 0x1C, + 0x9F, + 0x5D, + 0x6F, + 0x80, + 0x0A, + 0x72, + 0x44, + 0x9B, + 0x6C, + 0x90, + 0x0B, + 0x5B, + 0x33, + 0x7D, + 0x5A, + 0x52, + 0xF3, + 0x61, + 0xA1, + 0xF7, + 0xB0, + 0xD6, + 0x3F, + 0x7C, + 0x6D, + 0xED, + 0x14, + 0xE0, + 0xA5, + 0x3D, + 0x22, + 0xB3, + 0xF8, + 0x89, + 0xDE, + 0x71, + 0x1A, + 0xAF, + 0xBA, + 0xB5, + 0x81, + ] +) + +BelT = SBox( + [ + 0xB1, + 0x94, + 0xBA, + 0xC8, + 0x0A, + 0x08, + 0xF5, + 0x3B, + 0x36, + 0x6D, + 0x00, + 0x8E, + 0x58, + 0x4A, + 0x5D, + 0xE4, + 0x85, + 0x04, + 0xFA, + 0x9D, + 0x1B, + 0xB6, + 0xC7, + 0xAC, + 0x25, + 0x2E, + 0x72, + 0xC2, + 0x02, + 0xFD, + 0xCE, + 0x0D, + 0x5B, + 0xE3, + 0xD6, + 0x12, + 0x17, + 0xB9, + 0x61, + 0x81, + 0xFE, + 0x67, + 0x86, + 0xAD, + 0x71, + 0x6B, + 0x89, + 0x0B, + 0x5C, + 0xB0, + 0xC0, + 0xFF, + 0x33, + 0xC3, + 0x56, + 0xB8, + 0x35, + 0xC4, + 0x05, + 0xAE, + 0xD8, + 0xE0, + 0x7F, + 0x99, + 0xE1, + 0x2B, + 0xDC, + 0x1A, + 0xE2, + 0x82, + 0x57, + 0xEC, + 0x70, + 0x3F, + 0xCC, + 0xF0, + 0x95, + 0xEE, + 0x8D, + 0xF1, + 0xC1, + 0xAB, + 0x76, + 0x38, + 0x9F, + 0xE6, + 0x78, + 0xCA, + 0xF7, + 0xC6, + 0xF8, + 0x60, + 0xD5, + 0xBB, + 0x9C, + 0x4F, + 0xF3, + 0x3C, + 0x65, + 0x7B, + 0x63, + 0x7C, + 0x30, + 0x6A, + 0xDD, + 0x4E, + 0xA7, + 0x79, + 0x9E, + 0xB2, + 0x3D, + 0x31, + 0x3E, + 0x98, + 0xB5, + 0x6E, + 0x27, + 0xD3, + 0xBC, + 0xCF, + 0x59, + 0x1E, + 0x18, + 0x1F, + 0x4C, + 0x5A, + 0xB7, + 0x93, + 0xE9, + 0xDE, + 0xE7, + 0x2C, + 0x8F, + 0x0C, + 0x0F, + 0xA6, + 0x2D, + 0xDB, + 0x49, + 0xF4, + 0x6F, + 0x73, + 0x96, + 0x47, + 0x06, + 0x07, + 0x53, + 0x16, + 0xED, + 0x24, + 0x7A, + 0x37, + 0x39, + 0xCB, + 0xA3, + 0x83, + 0x03, + 0xA9, + 0x8B, + 0xF6, + 0x92, + 0xBD, + 0x9B, + 0x1C, + 0xE5, + 0xD1, + 0x41, + 0x01, + 0x54, + 0x45, + 0xFB, + 0xC9, + 0x5E, + 0x4D, + 0x0E, + 0xF2, + 0x68, + 0x20, + 0x80, + 0xAA, + 0x22, + 0x7D, + 0x64, + 0x2F, + 0x26, + 0x87, + 0xF9, + 0x34, + 0x90, + 0x40, + 0x55, + 0x11, + 0xBE, + 0x32, + 0x97, + 0x13, + 0x43, + 0xFC, + 0x9A, + 0x48, + 0xA0, + 0x2A, + 0x88, + 0x5F, + 0x19, + 0x4B, + 0x09, + 0xA1, + 0x7E, + 0xCD, + 0xA4, + 0xD0, + 0x15, + 0x44, + 0xAF, + 0x8C, + 0xA5, + 0x84, + 0x50, + 0xBF, + 0x66, + 0xD2, + 0xE8, + 0x8A, + 0xA2, + 0xD7, + 0x46, + 0x52, + 0x42, + 0xA8, + 0xDF, + 0xB3, + 0x69, + 0x74, + 0xC5, + 0x51, + 0xEB, + 0x23, + 0x29, + 0x21, + 0xD4, + 0xEF, + 0xD9, + 0xB4, + 0x3A, + 0x62, + 0x28, + 0x75, + 0x91, + 0x14, + 0x10, + 0xEA, + 0x77, + 0x6C, + 0xDA, + 0x1D, + ] +) + +Camellia = SBox( + [ + 112, + 130, + 44, + 236, + 179, + 39, + 192, + 229, + 228, + 133, + 87, + 53, + 234, + 12, + 174, + 65, + 35, + 239, + 107, + 147, + 69, + 25, + 165, + 33, + 237, + 14, + 79, + 78, + 29, + 101, + 146, + 189, + 134, + 184, + 175, + 143, + 124, + 235, + 31, + 206, + 62, + 48, + 220, + 95, + 94, + 197, + 11, + 26, + 166, + 225, + 57, + 202, + 213, + 71, + 93, + 61, + 217, + 1, + 90, + 214, + 81, + 86, + 108, + 77, + 139, + 13, + 154, + 102, + 251, + 204, + 176, + 45, + 116, + 18, + 43, + 32, + 240, + 177, + 132, + 153, + 223, + 76, + 203, + 194, + 52, + 126, + 118, + 5, + 109, + 183, + 169, + 49, + 209, + 23, + 4, + 215, + 20, + 88, + 58, + 97, + 222, + 27, + 17, + 28, + 50, + 15, + 156, + 22, + 83, + 24, + 242, + 34, + 254, + 68, + 207, + 178, + 195, + 181, + 122, + 145, + 36, + 8, + 232, + 168, + 96, + 252, + 105, + 80, + 170, + 208, + 160, + 125, + 161, + 137, + 98, + 151, + 84, + 91, + 30, + 149, + 224, + 255, + 100, + 210, + 16, + 196, + 0, + 72, + 163, + 247, + 117, + 219, + 138, + 3, + 230, + 218, + 9, + 63, + 221, + 148, + 135, + 92, + 131, + 2, + 205, + 74, + 144, + 51, + 115, + 103, + 246, + 243, + 157, + 127, + 191, + 226, + 82, + 155, + 216, + 38, + 200, + 55, + 198, + 59, + 129, + 150, + 111, + 75, + 19, + 190, + 99, + 46, + 233, + 121, + 167, + 140, + 159, + 110, + 188, + 142, + 41, + 245, + 249, + 182, + 47, + 253, + 180, + 89, + 120, + 152, + 6, + 106, + 231, + 70, + 113, + 186, + 212, + 37, + 171, + 66, + 136, + 162, + 141, + 250, + 114, + 7, + 185, + 85, + 248, + 238, + 172, + 10, + 54, + 73, + 42, + 104, + 60, + 56, + 241, + 164, + 64, + 40, + 211, + 123, + 187, + 201, + 67, + 193, + 21, + 227, + 173, + 244, + 119, + 199, + 128, + 158, + ] +) # source: https://www.schneier.com/academic/paperfiles/paper-cmea.pdf -CMEA = SBox([ - 0xd9,0x23,0x5f,0xe6,0xca,0x68,0x97,0xb0,0x7b,0xf2,0x0c,0x34,0x11,0xa5,0x8d,0x4e, - 0x0a,0x46,0x77,0x8d,0x10,0x9f,0x5e,0x62,0xf1,0x34,0xec,0xa5,0xc9,0xb3,0xd8,0x2b, - 0x59,0x47,0xe3,0xd2,0xff,0xae,0x64,0xca,0x15,0x8b,0x7d,0x38,0x21,0xbc,0x96,0x00, - 0x49,0x56,0x23,0x15,0x97,0xe4,0xcb,0x6f,0xf2,0x70,0x3c,0x88,0xba,0xd1,0x0d,0xae, - 0xe2,0x38,0xba,0x44,0x9f,0x83,0x5d,0x1c,0xde,0xab,0xc7,0x65,0xf1,0x76,0x09,0x20, - 0x86,0xbd,0x0a,0xf1,0x3c,0xa7,0x29,0x93,0xcb,0x45,0x5f,0xe8,0x10,0x74,0x62,0xde, - 0xb8,0x77,0x80,0xd1,0x12,0x26,0xac,0x6d,0xe9,0xcf,0xf3,0x54,0x3a,0x0b,0x95,0x4e, - 0xb1,0x30,0xa4,0x96,0xf8,0x57,0x49,0x8e,0x05,0x1f,0x62,0x7c,0xc3,0x2b,0xda,0xed, - 0xbb,0x86,0x0d,0x7a,0x97,0x13,0x6c,0x4e,0x51,0x30,0xe5,0xf2,0x2f,0xd8,0xc4,0xa9, - 0x91,0x76,0xf0,0x17,0x43,0x38,0x29,0x84,0xa2,0xdb,0xef,0x65,0x5e,0xca,0x0d,0xbc, - 0xe7,0xfa,0xd8,0x81,0x6f,0x00,0x14,0x42,0x25,0x7c,0x5d,0xc9,0x9e,0xb6,0x33,0xab, - 0x5a,0x6f,0x9b,0xd9,0xfe,0x71,0x44,0xc5,0x37,0xa2,0x88,0x2d,0x00,0xb6,0x13,0xec, - 0x4e,0x96,0xa8,0x5a,0xb5,0xd7,0xc3,0x8d,0x3f,0xf2,0xec,0x04,0x60,0x71,0x1b,0x29, - 0x04,0x79,0xe3,0xc7,0x1b,0x66,0x81,0x4a,0x25,0x9d,0xdc,0x5f,0x3e,0xb0,0xf8,0xa2, - 0x91,0x34,0xf6,0x5c,0x67,0x89,0x73,0x05,0x22,0xaa,0xcb,0xee,0xbf,0x18,0xd0,0x4d, - 0xf5,0x36,0xae,0x01,0x2f,0x94,0xc3,0x49,0x8b,0xbd,0x58,0x12,0xe0,0x77,0x6c,0xda]) - -Chiasmus = SBox([ - 0x65,0x33,0xcf,0xb9,0x37,0x64,0xcd,0xf3,0x26,0x3a,0xc1,0xa2,0x72,0x8a,0x8f,0xe3, - 0xfd,0x56,0xb3,0x0f,0x10,0x2b,0x3e,0xa0,0xbd,0x1e,0xab,0x1d,0x9c,0xe2,0x87,0x98, - 0xa8,0xd3,0xb4,0xdf,0x92,0x75,0x3b,0x39,0x20,0xa5,0xfa,0x1b,0xbe,0x90,0xf6,0x09, - 0xe5,0x61,0xc4,0xc9,0x06,0xc2,0xa6,0x1c,0xf9,0x94,0x7b,0x53,0x73,0x01,0x25,0x9a, - 0x1a,0xff,0xe9,0x5a,0x76,0x13,0x4b,0x95,0xac,0x0b,0xc7,0xb2,0xb8,0xd6,0x17,0xa9, - 0x27,0xeb,0xd1,0x5C,0xc3,0x9b,0x22,0x15,0x8e,0x40,0x11,0x5e,0x57,0x16,0xd0,0xb0, - 0x5d,0x79,0x31,0xbb,0xea,0x4f,0xd9,0xde,0x00,0x0a,0xd7,0xad,0x3f,0x99,0x68,0x34, - 0x66,0xf0,0x44,0x35,0x89,0x54,0x81,0xb1,0x84,0x2a,0x8b,0x6f,0xc0,0x43,0xfe,0x96, - 0x48,0x82,0x0c,0xda,0x74,0xbc,0x21,0xf1,0x67,0x2e,0xdb,0x49,0xe4,0xd5,0x71,0x59, - 0x29,0xe0,0xa1,0x30,0xdd,0x91,0x6b,0xb7,0xb6,0x69,0xc5,0x80,0xaa,0x6d,0xa3,0x2c, - 0x05,0x78,0xba,0x51,0x14,0x07,0xd4,0xec,0x7e,0xcc,0x24,0x62,0x9e,0xdc,0x8c,0xd8, - 0x1f,0x46,0xe8,0x9f,0x4e,0xa4,0x85,0x32,0xce,0xa7,0xfc,0xe1,0x97,0xae,0x2d,0x52, - 0x7d,0x0e,0x6c,0x83,0x5f,0xbf,0x18,0x7c,0x36,0x63,0x0d,0xef,0xc8,0x5b,0x55,0x12, - 0x4a,0xf2,0x70,0x38,0xf8,0xaf,0x86,0x77,0x47,0x04,0x23,0x02,0x6e,0x4c,0x58,0x03, - 0x50,0x7a,0x3d,0x28,0xf5,0xe7,0x41,0xf4,0x45,0x60,0x6a,0x08,0x88,0x7f,0x9d,0x93, - 0x4d,0xd2,0x2f,0xee,0xe6,0xcb,0xed,0xfb,0xca,0xf7,0x19,0xb5,0x42,0x8d,0xc6,0x3c]) - -CLEFIA_S0 = SBox([ - 0x57,0x49,0xd1,0xc6,0x2f,0x33,0x74,0xfb,0x95,0x6d,0x82,0xea,0x0e,0xb0,0xa8,0x1c, - 0x28,0xd0,0x4b,0x92,0x5c,0xee,0x85,0xb1,0xc4,0x0a,0x76,0x3d,0x63,0xf9,0x17,0xaf, - 0xbf,0xa1,0x19,0x65,0xf7,0x7a,0x32,0x20,0x06,0xce,0xe4,0x83,0x9d,0x5b,0x4c,0xd8, - 0x42,0x5d,0x2e,0xe8,0xd4,0x9b,0x0f,0x13,0x3c,0x89,0x67,0xc0,0x71,0xaa,0xb6,0xf5, - 0xa4,0xbe,0xfd,0x8c,0x12,0x00,0x97,0xda,0x78,0xe1,0xcf,0x6b,0x39,0x43,0x55,0x26, - 0x30,0x98,0xcc,0xdd,0xeb,0x54,0xb3,0x8f,0x4e,0x16,0xfa,0x22,0xa5,0x77,0x09,0x61, - 0xd6,0x2a,0x53,0x37,0x45,0xc1,0x6c,0xae,0xef,0x70,0x08,0x99,0x8b,0x1d,0xf2,0xb4, - 0xe9,0xc7,0x9f,0x4a,0x31,0x25,0xfe,0x7c,0xd3,0xa2,0xbd,0x56,0x14,0x88,0x60,0x0b, - 0xcd,0xe2,0x34,0x50,0x9e,0xdc,0x11,0x05,0x2b,0xb7,0xa9,0x48,0xff,0x66,0x8a,0x73, - 0x03,0x75,0x86,0xf1,0x6a,0xa7,0x40,0xc2,0xb9,0x2c,0xdb,0x1f,0x58,0x94,0x3e,0xed, - 0xfc,0x1b,0xa0,0x04,0xb8,0x8d,0xe6,0x59,0x62,0x93,0x35,0x7e,0xca,0x21,0xdf,0x47, - 0x15,0xf3,0xba,0x7f,0xa6,0x69,0xc8,0x4d,0x87,0x3b,0x9c,0x01,0xe0,0xde,0x24,0x52, - 0x7b,0x0c,0x68,0x1e,0x80,0xb2,0x5a,0xe7,0xad,0xd5,0x23,0xf4,0x46,0x3f,0x91,0xc9, - 0x6e,0x84,0x72,0xbb,0x0d,0x18,0xd9,0x96,0xf0,0x5f,0x41,0xac,0x27,0xc5,0xe3,0x3a, - 0x81,0x6f,0x07,0xa3,0x79,0xf6,0x2d,0x38,0x1a,0x44,0x5e,0xb5,0xd2,0xec,0xcb,0x90, - 0x9a,0x36,0xe5,0x29,0xc3,0x4f,0xab,0x64,0x51,0xf8,0x10,0xd7,0xbc,0x02,0x7d,0x8e]) - -CLEFIA_S1 = SBox([ - 0x6c,0xda,0xc3,0xe9,0x4e,0x9d,0x0a,0x3d,0xb8,0x36,0xb4,0x38,0x13,0x34,0x0c,0xd9, - 0xbf,0x74,0x94,0x8f,0xb7,0x9c,0xe5,0xdc,0x9e,0x07,0x49,0x4f,0x98,0x2c,0xb0,0x93, - 0x12,0xeb,0xcd,0xb3,0x92,0xe7,0x41,0x60,0xe3,0x21,0x27,0x3b,0xe6,0x19,0xd2,0x0e, - 0x91,0x11,0xc7,0x3f,0x2a,0x8e,0xa1,0xbc,0x2b,0xc8,0xc5,0x0f,0x5b,0xf3,0x87,0x8b, - 0xfb,0xf5,0xde,0x20,0xc6,0xa7,0x84,0xce,0xd8,0x65,0x51,0xc9,0xa4,0xef,0x43,0x53, - 0x25,0x5d,0x9b,0x31,0xe8,0x3e,0x0d,0xd7,0x80,0xff,0x69,0x8a,0xba,0x0b,0x73,0x5c, - 0x6e,0x54,0x15,0x62,0xf6,0x35,0x30,0x52,0xa3,0x16,0xd3,0x28,0x32,0xfa,0xaa,0x5e, - 0xcf,0xea,0xed,0x78,0x33,0x58,0x09,0x7b,0x63,0xc0,0xc1,0x46,0x1e,0xdf,0xa9,0x99, - 0x55,0x04,0xc4,0x86,0x39,0x77,0x82,0xec,0x40,0x18,0x90,0x97,0x59,0xdd,0x83,0x1f, - 0x9a,0x37,0x06,0x24,0x64,0x7c,0xa5,0x56,0x48,0x08,0x85,0xd0,0x61,0x26,0xca,0x6f, - 0x7e,0x6a,0xb6,0x71,0xa0,0x70,0x05,0xd1,0x45,0x8c,0x23,0x1c,0xf0,0xee,0x89,0xad, - 0x7a,0x4b,0xc2,0x2f,0xdb,0x5a,0x4d,0x76,0x67,0x17,0x2d,0xf4,0xcb,0xb1,0x4a,0xa8, - 0xb5,0x22,0x47,0x3a,0xd5,0x10,0x4c,0x72,0xcc,0x00,0xf9,0xe0,0xfd,0xe2,0xfe,0xae, - 0xf8,0x5f,0xab,0xf1,0x1b,0x42,0x81,0xd6,0xbe,0x44,0x29,0xa6,0x57,0xb9,0xaf,0xf2, - 0xd4,0x75,0x66,0xbb,0x68,0x9f,0x50,0x02,0x01,0x3c,0x7f,0x8d,0x1a,0x88,0xbd,0xac, - 0xf7,0xe4,0x79,0x96,0xa2,0xfc,0x6d,0xb2,0x6b,0x03,0xe1,0x2e,0x7d,0x14,0x95,0x1d]) - -Crypton_0_5 = SBox([ - 0xf0,0x12,0x4c,0x7a,0x47,0x16,0x03,0x3a,0xe6,0x9d,0x44,0x77,0x53,0xca,0x3b,0x0f, - 0x9b,0x98,0x54,0x90,0x3d,0xac,0x74,0x56,0x9e,0xde,0x5c,0xf3,0x86,0x39,0x7c,0xc4, - 0x91,0xa9,0x97,0x5f,0x9c,0x0d,0x78,0xcc,0xfd,0x43,0xbf,0x02,0x4b,0x92,0x60,0x3e, - 0x7d,0x1d,0x50,0xcb,0xb8,0xb9,0x70,0x27,0xaa,0x96,0x48,0x88,0x38,0xd7,0x68,0x42, - 0xa8,0xd0,0xa6,0x2e,0x25,0xf4,0x2c,0x6e,0x0c,0xb7,0xce,0xe0,0xbe,0x0b,0x24,0x67, - 0x8c,0xec,0xc5,0x52,0xd9,0xd8,0x09,0xb4,0xcf,0x8f,0x8d,0x8b,0x59,0x23,0x51,0xe3, - 0xd3,0xb1,0x18,0xf8,0xd4,0x05,0xa2,0xdb,0x82,0x6c,0x00,0x46,0x8a,0xaf,0xda,0xbc, - 0x99,0x1a,0xad,0xb3,0x1f,0x0e,0x71,0x4f,0xc7,0x2b,0xe5,0x2a,0xe2,0x58,0x29,0x06, - 0xf6,0xfe,0xf9,0x19,0x6b,0xea,0xbb,0xc2,0xa3,0x55,0xa1,0xdf,0x6f,0x45,0x83,0x69, - 0x8e,0x7b,0x72,0x3c,0xee,0xff,0x07,0xa5,0xe8,0xf1,0x0a,0x1c,0x75,0xe1,0x2f,0x21, - 0xd2,0xb6,0x3f,0xf7,0x73,0xb2,0x5d,0x79,0x35,0x80,0x17,0x41,0x94,0x7e,0x15,0xed, - 0xb5,0xd5,0x93,0x14,0x20,0x61,0x76,0x31,0xc9,0x6a,0xab,0x34,0xa0,0xa4,0x1e,0xba, - 0xe7,0x13,0x4e,0xc6,0xd6,0x87,0x7f,0xbd,0x84,0x62,0x26,0x95,0x6d,0x4d,0x57,0x28, - 0x04,0x64,0x4a,0x11,0x01,0x40,0x65,0x08,0xb0,0xe9,0x32,0xcd,0x81,0x66,0x2d,0x5b, - 0xef,0xa7,0xfb,0xdd,0xf2,0x33,0x5a,0x63,0xc1,0xe4,0xc3,0xae,0xdc,0xfc,0x22,0x10, - 0xfa,0x9f,0xd1,0x85,0x9a,0x1b,0x5e,0x30,0xeb,0xc8,0x89,0x49,0x37,0xc0,0x36,0xf5]) - -Crypton_1_0_S0 = SBox([ - 0x63,0xec,0x59,0xaa,0xdb,0x8e,0x66,0xc0,0x37,0x3c,0x14,0xff,0x13,0x44,0xa9,0x91, - 0x3b,0x78,0x8d,0xef,0xc2,0x2a,0xf0,0xd7,0x61,0x9e,0xa5,0xbc,0x48,0x15,0x12,0x47, - 0xed,0x42,0x1a,0x33,0x38,0xc8,0x17,0x90,0xa6,0xd5,0x5d,0x65,0x6a,0xfe,0x8f,0xa1, - 0x93,0xca,0x2f,0x0c,0x68,0x58,0xdf,0xf4,0x45,0x11,0xa0,0xa7,0x22,0x96,0xfb,0x7d, - 0x1d,0xb4,0x84,0xe0,0xbf,0x57,0xe9,0x0a,0x4e,0x83,0xcc,0x7a,0x71,0x39,0xc7,0x32, - 0x74,0x3d,0xde,0x50,0x85,0x06,0x6f,0x53,0xe8,0xad,0x82,0x19,0xe1,0xba,0x36,0xcb, - 0x0e,0x28,0xf3,0x9b,0x4a,0x62,0x94,0x1f,0xbd,0xf6,0x67,0x41,0xd8,0xd1,0x2d,0xa4, - 0x86,0xb7,0x01,0xc5,0xb0,0x75,0x02,0xf9,0x2c,0x29,0x6e,0xd2,0x5f,0x8b,0xfc,0x5a, - 0xe4,0x7f,0xdd,0x07,0x55,0xb1,0x2b,0x89,0x72,0x18,0x3a,0x4c,0xb6,0xe3,0x80,0xce, - 0x49,0xcf,0x6b,0xb9,0xf2,0x0d,0xdc,0x64,0x95,0x46,0xf7,0x10,0x9a,0x20,0xa2,0x3f, - 0xd6,0x87,0x70,0x3e,0x21,0xfd,0x4d,0x7b,0xc3,0xae,0x09,0x8a,0x04,0xb3,0x54,0xf8, - 0x30,0x00,0x56,0xd4,0xe7,0x25,0xbb,0xac,0x98,0x73,0xea,0xc9,0x9d,0x4f,0x7e,0x03, - 0xab,0x92,0xa8,0x43,0x0f,0xfa,0x24,0x5c,0x1e,0x60,0x31,0x97,0xcd,0xc6,0x79,0xf5, - 0x5e,0xe5,0x34,0x76,0x1c,0x81,0xb2,0xaf,0x0b,0x5b,0xd9,0xe2,0x27,0x6d,0xd0,0x88, - 0xc1,0x51,0xe6,0x9c,0x77,0xbe,0x99,0x23,0xda,0xeb,0x52,0x2e,0xb5,0x08,0x05,0x6c, - 0xb8,0x1b,0xa3,0x69,0x8c,0xd3,0x40,0x26,0xf1,0xc4,0x9f,0x35,0xee,0x7c,0x4b,0x16]) - -Crypton_1_0_S1 = SBox([ - 0x8d,0xb3,0x65,0xaa,0x6f,0x3a,0x99,0x03,0xdc,0xf0,0x50,0xff,0x4c,0x11,0xa6,0x46, - 0xec,0xe1,0x36,0xbf,0x0b,0xa8,0xc3,0x5f,0x85,0x7a,0x96,0xf2,0x21,0x54,0x48,0x1d, - 0xb7,0x09,0x68,0xcc,0xe0,0x23,0x5c,0x42,0x9a,0x57,0x75,0x95,0xa9,0xfb,0x3e,0x86, - 0x4e,0x2b,0xbc,0x30,0xa1,0x61,0x7f,0xd3,0x15,0x44,0x82,0x9e,0x88,0x5a,0xef,0xf5, - 0x74,0xd2,0x12,0x83,0xfe,0x5d,0xa7,0x28,0x39,0x0e,0x33,0xe9,0xc5,0xe4,0x1f,0xc8, - 0xd1,0xf4,0x7b,0x41,0x16,0x18,0xbd,0x4d,0xa3,0xb6,0x0a,0x64,0x87,0xea,0xd8,0x2f, - 0x38,0xa0,0xcf,0x6e,0x29,0x89,0x52,0x7c,0xf6,0xdb,0x9d,0x05,0x63,0x47,0xb4,0x92, - 0x1a,0xde,0x04,0x17,0xc2,0xd5,0x08,0xe7,0xb0,0xa4,0xb9,0x4b,0x7d,0x2e,0xf3,0x69, - 0x93,0xfd,0x77,0x1c,0x55,0xc6,0xac,0x26,0xc9,0x60,0xe8,0x31,0xda,0x8f,0x02,0x3b, - 0x25,0x3f,0xad,0xe6,0xcb,0x34,0x73,0x91,0x56,0x19,0xdf,0x40,0x6a,0x80,0x8a,0xfc, - 0x5b,0x1e,0xc1,0xf8,0x84,0xf7,0x35,0xed,0x0f,0xba,0x24,0x2a,0x10,0xce,0x51,0xe3, - 0xc0,0x00,0x59,0x53,0x9f,0x94,0xee,0xb2,0x62,0xcd,0xab,0x27,0x76,0x3d,0xf9,0x0c, - 0xae,0x4a,0xa2,0x0d,0x3c,0xeb,0x90,0x71,0x78,0x81,0xc4,0x5e,0x37,0x1b,0xe5,0xd7, - 0x79,0x97,0xd0,0xd9,0x70,0x06,0xca,0xbe,0x2c,0x6d,0x67,0x8b,0x9c,0xb5,0x43,0x22, - 0x07,0x45,0x9b,0x72,0xdd,0xfa,0x66,0x8c,0x6b,0xaf,0x49,0xb8,0xd6,0x20,0x14,0xb1, - 0xe2,0x6c,0x8e,0xa5,0x32,0x4f,0x01,0x98,0xc7,0x13,0x7e,0xd4,0xbb,0xf1,0x2d,0x58]) - -Crypton_1_0_S2 = SBox([ - 0xb1,0x72,0x76,0xbf,0xac,0xee,0x55,0x83,0xed,0xaa,0x47,0xd8,0x33,0x95,0x60,0xc4, - 0x9b,0x39,0x1e,0x0c,0x0a,0x1d,0xff,0x26,0x89,0x5b,0x22,0xf1,0xd4,0x40,0xc8,0x67, - 0x9d,0xa4,0x3c,0xe7,0xc6,0xb5,0xf7,0xdc,0x61,0x79,0x15,0x86,0x78,0x6e,0xeb,0x32, - 0xb0,0xca,0x4f,0x23,0xd2,0xfb,0x5e,0x08,0x24,0x4d,0x8a,0x10,0x09,0x51,0xa3,0x9f, - 0xf6,0x6b,0x21,0xc3,0x0d,0x38,0x99,0x1f,0x1c,0x90,0x64,0xfe,0x8b,0xa6,0x48,0xbd, - 0x53,0xe1,0xea,0x57,0xae,0x84,0xb2,0x45,0x35,0x02,0x7f,0xd9,0xc7,0x2a,0xd0,0x7c, - 0xc9,0x18,0x65,0x00,0x97,0x2b,0x06,0x6a,0x34,0xf3,0x2c,0x92,0xef,0xdd,0x7a,0x56, - 0xa2,0x4c,0x88,0xb9,0x50,0x75,0xd3,0xe4,0x11,0xce,0x4b,0xa7,0xfd,0x3f,0xbe,0x81, - 0x8e,0xd5,0x5a,0x49,0x42,0x54,0x70,0xa1,0xdf,0x87,0xab,0x7d,0xf4,0x12,0x05,0x2e, - 0x27,0x0f,0xc1,0x30,0x66,0x98,0x3d,0xcb,0xb8,0xe6,0x9c,0x63,0xe3,0xbc,0x19,0xfa, - 0x3a,0x2f,0x9e,0xf2,0x6f,0x1a,0x28,0x3b,0xc2,0x0e,0x03,0xc0,0xb7,0x59,0xa9,0xd7, - 0x74,0x85,0xd6,0xad,0x41,0xec,0x8c,0x71,0xf0,0x93,0x5d,0xb6,0x1b,0x68,0xe5,0x44, - 0x07,0xe0,0x14,0xa8,0xf9,0x73,0xcd,0x4e,0x25,0xbb,0x31,0x5f,0x4a,0xcc,0x8f,0x91, - 0xde,0x6d,0x7b,0xf5,0xb3,0x29,0xa0,0x17,0x6c,0xda,0xe8,0x04,0x96,0x82,0x52,0x36, - 0x43,0x5c,0xdb,0x8d,0x80,0xd1,0xe2,0xb4,0x58,0x46,0xba,0xe9,0x01,0x20,0xfc,0x13, - 0x16,0xf8,0x94,0x62,0x37,0xcf,0x69,0x9a,0xaf,0x77,0xc5,0x3e,0x7e,0xa5,0x2d,0x0b]) - -Crypton_1_0_S3 = SBox([ - 0xb1,0xf6,0x8e,0x07,0x72,0x6b,0xd5,0xe0,0x76,0x21,0x5a,0x14,0xbf,0xc3,0x49,0xa8, - 0xac,0x0d,0x42,0xf9,0xee,0x38,0x54,0x73,0x55,0x99,0x70,0xcd,0x83,0x1f,0xa1,0x4e, - 0xed,0x1c,0xdf,0x25,0xaa,0x90,0x87,0xbb,0x47,0x64,0xab,0x31,0xd8,0xfe,0x7d,0x5f, - 0x33,0x8b,0xf4,0x4a,0x95,0xa6,0x12,0xcc,0x60,0x48,0x05,0x8f,0xc4,0xbd,0x2e,0x91, - 0x9b,0x53,0x27,0xde,0x39,0xe1,0x0f,0x6d,0x1e,0xea,0xc1,0x7b,0x0c,0x57,0x30,0xf5, - 0x0a,0xae,0x66,0xb3,0x1d,0x84,0x98,0x29,0xff,0xb2,0x3d,0xa0,0x26,0x45,0xcb,0x17, - 0x89,0x35,0xb8,0x6c,0x5b,0x02,0xe6,0xda,0x22,0x7f,0x9c,0xe8,0xf1,0xd9,0x63,0x04, - 0xd4,0xc7,0xe3,0x96,0x40,0x2a,0xbc,0x82,0xc8,0xd0,0x19,0x52,0x67,0x7c,0xfa,0x36, - 0x9d,0xc9,0x3a,0x43,0xa4,0x18,0x2f,0x5c,0x3c,0x65,0x9e,0xdb,0xe7,0x00,0xf2,0x8d, - 0xc6,0x97,0x6f,0x80,0xb5,0x2b,0x1a,0xd1,0xf7,0x06,0x28,0xe2,0xdc,0x6a,0x3b,0xb4, - 0x61,0x34,0xc2,0x58,0x79,0xf3,0x0e,0x46,0x15,0x2c,0x03,0xba,0x86,0x92,0xc0,0xe9, - 0x78,0xef,0xb7,0x01,0x6e,0xdd,0x59,0x20,0xeb,0x7a,0xa9,0xfc,0x32,0x56,0xd7,0x13, - 0xb0,0xa2,0x74,0x16,0xca,0x4c,0x85,0xf8,0x4f,0x88,0xd6,0x94,0x23,0xb9,0xad,0x62, - 0xd2,0x50,0x41,0x37,0xfb,0x75,0xec,0xcf,0x5e,0xd3,0x8c,0x69,0x08,0xe4,0x71,0x9a, - 0x24,0x11,0xf0,0xaf,0x4d,0xce,0x93,0x77,0x8a,0x4b,0x5d,0xc5,0x10,0xa7,0xb6,0x3e, - 0x09,0xfd,0x1b,0x7e,0x51,0x3f,0x68,0xa5,0xa3,0xbe,0xe5,0x2d,0x9f,0x81,0x44,0x0b]) - -CS_cipher = SBox([ - 0x29,0xd,0x61,0x40,0x9c,0xeb,0x9e,0x8f,0x1f,0x85,0x5f,0x58,0x5b,0x1,0x39,0x86, - 0x97,0x2e,0xd7,0xd6,0x35,0xae,0x17,0x16,0x21,0xb6,0x69,0x4e,0xa5,0x72,0x87,0x8, - 0x3c,0x18,0xe6,0xe7,0xfa,0xad,0xb8,0x89,0xb7,0x0,0xf7,0x6f,0x73,0x84,0x11,0x63, - 0x3f,0x96,0x7f,0x6e,0xbf,0x14,0x9d,0xac,0xa4,0xe,0x7e,0xf6,0x20,0x4a,0x62,0x30, - 0x3,0xc5,0x4b,0x5a,0x46,0xa3,0x44,0x65,0x7d,0x4d,0x3d,0x42,0x79,0x49,0x1b,0x5c, - 0xf5,0x6c,0xb5,0x94,0x54,0xff,0x56,0x57,0xb,0xf4,0x43,0xc,0x4f,0x70,0x6d,0xa, - 0xe4,0x2,0x3e,0x2f,0xa2,0x47,0xe0,0xc1,0xd5,0x1a,0x95,0xa7,0x51,0x5e,0x33,0x2b, - 0x5d,0xd4,0x1d,0x2c,0xee,0x75,0xec,0xdd,0x7c,0x4c,0xa6,0xb4,0x78,0x48,0x3a,0x32, - 0x98,0xaf,0xc0,0xe1,0x2d,0x9,0xf,0x1e,0xb9,0x27,0x8a,0xe9,0xbd,0xe3,0x9f,0x7, - 0xb1,0xea,0x92,0x93,0x53,0x6a,0x31,0x10,0x80,0xf2,0xd8,0x9b,0x4,0x36,0x6,0x8e, - 0xbe,0xa9,0x64,0x45,0x38,0x1c,0x7a,0x6b,0xf3,0xa1,0xf0,0xcd,0x37,0x25,0x15,0x81, - 0xfb,0x90,0xe8,0xd9,0x7b,0x52,0x19,0x28,0x26,0x88,0xfc,0xd1,0xe2,0x8c,0xa0,0x34, - 0x82,0x67,0xda,0xcb,0xc7,0x41,0xe5,0xc4,0xc8,0xef,0xdb,0xc3,0xcc,0xab,0xce,0xed, - 0xd0,0xbb,0xd3,0xd2,0x71,0x68,0x13,0x12,0x9a,0xb3,0xc2,0xca,0xde,0x77,0xdc,0xdf, - 0x66,0x83,0xbc,0x8d,0x60,0xc6,0x22,0x23,0xb2,0x8b,0x91,0x5,0x76,0xcf,0x74,0xc9, - 0xaa,0xf1,0x99,0xa8,0x59,0x50,0x3b,0x2a,0xfe,0xf9,0x24,0xb0,0xba,0xfd,0xf8,0x55]) - - -CSA = SBox([ - 0x3a,0xea,0x68,0xfe,0x33,0xe9,0x88,0x1a,0x83,0xcf,0xe1,0x7f,0xba,0xe2,0x38,0x12, - 0xe8,0x27,0x61,0x95,0x0c,0x36,0xe5,0x70,0xa2,0x06,0x82,0x7c,0x17,0xa3,0x26,0x49, - 0xbe,0x7a,0x6d,0x47,0xc1,0x51,0x8f,0xf3,0xcc,0x5b,0x67,0xbd,0xcd,0x18,0x08,0xc9, - 0xff,0x69,0xef,0x03,0x4e,0x48,0x4a,0x84,0x3f,0xb4,0x10,0x04,0xdc,0xf5,0x5c,0xc6, - 0x16,0xab,0xac,0x4c,0xf1,0x6a,0x2f,0x3c,0x3b,0xd4,0xd5,0x94,0xd0,0xc4,0x63,0x62, - 0x71,0xa1,0xf9,0x4f,0x2e,0xaa,0xc5,0x56,0xe3,0x39,0x93,0xce,0x65,0x64,0xe4,0x58, - 0x6c,0x19,0x42,0x79,0xdd,0xee,0x96,0xf6,0x8a,0xec,0x1e,0x85,0x53,0x45,0xde,0xbb, - 0x7e,0x0a,0x9a,0x13,0x2a,0x9d,0xc2,0x5e,0x5a,0x1f,0x32,0x35,0x9c,0xa8,0x73,0x30, - 0x29,0x3d,0xe7,0x92,0x87,0x1b,0x2b,0x4b,0xa5,0x57,0x97,0x40,0x15,0xe6,0xbc,0x0e, - 0xeb,0xc3,0x34,0x2d,0xb8,0x44,0x25,0xa4,0x1c,0xc7,0x23,0xed,0x90,0x6e,0x50,0x00, - 0x99,0x9e,0x4d,0xd9,0xda,0x8d,0x6f,0x5f,0x3e,0xd7,0x21,0x74,0x86,0xdf,0x6b,0x05, - 0x8e,0x5d,0x37,0x11,0xd2,0x28,0x75,0xd6,0xa7,0x77,0x24,0xbf,0xf0,0xb0,0x02,0xb7, - 0xf8,0xfc,0x81,0x09,0xb1,0x01,0x76,0x91,0x7d,0x0f,0xc8,0xa0,0xf2,0xcb,0x78,0x60, - 0xd1,0xf7,0xe0,0xb5,0x98,0x22,0xb3,0x20,0x1d,0xa6,0xdb,0x7b,0x59,0x9f,0xae,0x31, - 0xfb,0xd3,0xb6,0xca,0x43,0x72,0x07,0xf4,0xd8,0x41,0x14,0x55,0x0d,0x54,0x8b,0xb9, - 0xad,0x46,0x0b,0xaf,0x80,0x52,0x2c,0xfa,0x8c,0x89,0x66,0xfd,0xb2,0xa9,0x9b,0xc0]) +CMEA = SBox( + [ + 0xD9, + 0x23, + 0x5F, + 0xE6, + 0xCA, + 0x68, + 0x97, + 0xB0, + 0x7B, + 0xF2, + 0x0C, + 0x34, + 0x11, + 0xA5, + 0x8D, + 0x4E, + 0x0A, + 0x46, + 0x77, + 0x8D, + 0x10, + 0x9F, + 0x5E, + 0x62, + 0xF1, + 0x34, + 0xEC, + 0xA5, + 0xC9, + 0xB3, + 0xD8, + 0x2B, + 0x59, + 0x47, + 0xE3, + 0xD2, + 0xFF, + 0xAE, + 0x64, + 0xCA, + 0x15, + 0x8B, + 0x7D, + 0x38, + 0x21, + 0xBC, + 0x96, + 0x00, + 0x49, + 0x56, + 0x23, + 0x15, + 0x97, + 0xE4, + 0xCB, + 0x6F, + 0xF2, + 0x70, + 0x3C, + 0x88, + 0xBA, + 0xD1, + 0x0D, + 0xAE, + 0xE2, + 0x38, + 0xBA, + 0x44, + 0x9F, + 0x83, + 0x5D, + 0x1C, + 0xDE, + 0xAB, + 0xC7, + 0x65, + 0xF1, + 0x76, + 0x09, + 0x20, + 0x86, + 0xBD, + 0x0A, + 0xF1, + 0x3C, + 0xA7, + 0x29, + 0x93, + 0xCB, + 0x45, + 0x5F, + 0xE8, + 0x10, + 0x74, + 0x62, + 0xDE, + 0xB8, + 0x77, + 0x80, + 0xD1, + 0x12, + 0x26, + 0xAC, + 0x6D, + 0xE9, + 0xCF, + 0xF3, + 0x54, + 0x3A, + 0x0B, + 0x95, + 0x4E, + 0xB1, + 0x30, + 0xA4, + 0x96, + 0xF8, + 0x57, + 0x49, + 0x8E, + 0x05, + 0x1F, + 0x62, + 0x7C, + 0xC3, + 0x2B, + 0xDA, + 0xED, + 0xBB, + 0x86, + 0x0D, + 0x7A, + 0x97, + 0x13, + 0x6C, + 0x4E, + 0x51, + 0x30, + 0xE5, + 0xF2, + 0x2F, + 0xD8, + 0xC4, + 0xA9, + 0x91, + 0x76, + 0xF0, + 0x17, + 0x43, + 0x38, + 0x29, + 0x84, + 0xA2, + 0xDB, + 0xEF, + 0x65, + 0x5E, + 0xCA, + 0x0D, + 0xBC, + 0xE7, + 0xFA, + 0xD8, + 0x81, + 0x6F, + 0x00, + 0x14, + 0x42, + 0x25, + 0x7C, + 0x5D, + 0xC9, + 0x9E, + 0xB6, + 0x33, + 0xAB, + 0x5A, + 0x6F, + 0x9B, + 0xD9, + 0xFE, + 0x71, + 0x44, + 0xC5, + 0x37, + 0xA2, + 0x88, + 0x2D, + 0x00, + 0xB6, + 0x13, + 0xEC, + 0x4E, + 0x96, + 0xA8, + 0x5A, + 0xB5, + 0xD7, + 0xC3, + 0x8D, + 0x3F, + 0xF2, + 0xEC, + 0x04, + 0x60, + 0x71, + 0x1B, + 0x29, + 0x04, + 0x79, + 0xE3, + 0xC7, + 0x1B, + 0x66, + 0x81, + 0x4A, + 0x25, + 0x9D, + 0xDC, + 0x5F, + 0x3E, + 0xB0, + 0xF8, + 0xA2, + 0x91, + 0x34, + 0xF6, + 0x5C, + 0x67, + 0x89, + 0x73, + 0x05, + 0x22, + 0xAA, + 0xCB, + 0xEE, + 0xBF, + 0x18, + 0xD0, + 0x4D, + 0xF5, + 0x36, + 0xAE, + 0x01, + 0x2F, + 0x94, + 0xC3, + 0x49, + 0x8B, + 0xBD, + 0x58, + 0x12, + 0xE0, + 0x77, + 0x6C, + 0xDA, + ] +) + +Chiasmus = SBox( + [ + 0x65, + 0x33, + 0xCF, + 0xB9, + 0x37, + 0x64, + 0xCD, + 0xF3, + 0x26, + 0x3A, + 0xC1, + 0xA2, + 0x72, + 0x8A, + 0x8F, + 0xE3, + 0xFD, + 0x56, + 0xB3, + 0x0F, + 0x10, + 0x2B, + 0x3E, + 0xA0, + 0xBD, + 0x1E, + 0xAB, + 0x1D, + 0x9C, + 0xE2, + 0x87, + 0x98, + 0xA8, + 0xD3, + 0xB4, + 0xDF, + 0x92, + 0x75, + 0x3B, + 0x39, + 0x20, + 0xA5, + 0xFA, + 0x1B, + 0xBE, + 0x90, + 0xF6, + 0x09, + 0xE5, + 0x61, + 0xC4, + 0xC9, + 0x06, + 0xC2, + 0xA6, + 0x1C, + 0xF9, + 0x94, + 0x7B, + 0x53, + 0x73, + 0x01, + 0x25, + 0x9A, + 0x1A, + 0xFF, + 0xE9, + 0x5A, + 0x76, + 0x13, + 0x4B, + 0x95, + 0xAC, + 0x0B, + 0xC7, + 0xB2, + 0xB8, + 0xD6, + 0x17, + 0xA9, + 0x27, + 0xEB, + 0xD1, + 0x5C, + 0xC3, + 0x9B, + 0x22, + 0x15, + 0x8E, + 0x40, + 0x11, + 0x5E, + 0x57, + 0x16, + 0xD0, + 0xB0, + 0x5D, + 0x79, + 0x31, + 0xBB, + 0xEA, + 0x4F, + 0xD9, + 0xDE, + 0x00, + 0x0A, + 0xD7, + 0xAD, + 0x3F, + 0x99, + 0x68, + 0x34, + 0x66, + 0xF0, + 0x44, + 0x35, + 0x89, + 0x54, + 0x81, + 0xB1, + 0x84, + 0x2A, + 0x8B, + 0x6F, + 0xC0, + 0x43, + 0xFE, + 0x96, + 0x48, + 0x82, + 0x0C, + 0xDA, + 0x74, + 0xBC, + 0x21, + 0xF1, + 0x67, + 0x2E, + 0xDB, + 0x49, + 0xE4, + 0xD5, + 0x71, + 0x59, + 0x29, + 0xE0, + 0xA1, + 0x30, + 0xDD, + 0x91, + 0x6B, + 0xB7, + 0xB6, + 0x69, + 0xC5, + 0x80, + 0xAA, + 0x6D, + 0xA3, + 0x2C, + 0x05, + 0x78, + 0xBA, + 0x51, + 0x14, + 0x07, + 0xD4, + 0xEC, + 0x7E, + 0xCC, + 0x24, + 0x62, + 0x9E, + 0xDC, + 0x8C, + 0xD8, + 0x1F, + 0x46, + 0xE8, + 0x9F, + 0x4E, + 0xA4, + 0x85, + 0x32, + 0xCE, + 0xA7, + 0xFC, + 0xE1, + 0x97, + 0xAE, + 0x2D, + 0x52, + 0x7D, + 0x0E, + 0x6C, + 0x83, + 0x5F, + 0xBF, + 0x18, + 0x7C, + 0x36, + 0x63, + 0x0D, + 0xEF, + 0xC8, + 0x5B, + 0x55, + 0x12, + 0x4A, + 0xF2, + 0x70, + 0x38, + 0xF8, + 0xAF, + 0x86, + 0x77, + 0x47, + 0x04, + 0x23, + 0x02, + 0x6E, + 0x4C, + 0x58, + 0x03, + 0x50, + 0x7A, + 0x3D, + 0x28, + 0xF5, + 0xE7, + 0x41, + 0xF4, + 0x45, + 0x60, + 0x6A, + 0x08, + 0x88, + 0x7F, + 0x9D, + 0x93, + 0x4D, + 0xD2, + 0x2F, + 0xEE, + 0xE6, + 0xCB, + 0xED, + 0xFB, + 0xCA, + 0xF7, + 0x19, + 0xB5, + 0x42, + 0x8D, + 0xC6, + 0x3C, + ] +) + +CLEFIA_S0 = SBox( + [ + 0x57, + 0x49, + 0xD1, + 0xC6, + 0x2F, + 0x33, + 0x74, + 0xFB, + 0x95, + 0x6D, + 0x82, + 0xEA, + 0x0E, + 0xB0, + 0xA8, + 0x1C, + 0x28, + 0xD0, + 0x4B, + 0x92, + 0x5C, + 0xEE, + 0x85, + 0xB1, + 0xC4, + 0x0A, + 0x76, + 0x3D, + 0x63, + 0xF9, + 0x17, + 0xAF, + 0xBF, + 0xA1, + 0x19, + 0x65, + 0xF7, + 0x7A, + 0x32, + 0x20, + 0x06, + 0xCE, + 0xE4, + 0x83, + 0x9D, + 0x5B, + 0x4C, + 0xD8, + 0x42, + 0x5D, + 0x2E, + 0xE8, + 0xD4, + 0x9B, + 0x0F, + 0x13, + 0x3C, + 0x89, + 0x67, + 0xC0, + 0x71, + 0xAA, + 0xB6, + 0xF5, + 0xA4, + 0xBE, + 0xFD, + 0x8C, + 0x12, + 0x00, + 0x97, + 0xDA, + 0x78, + 0xE1, + 0xCF, + 0x6B, + 0x39, + 0x43, + 0x55, + 0x26, + 0x30, + 0x98, + 0xCC, + 0xDD, + 0xEB, + 0x54, + 0xB3, + 0x8F, + 0x4E, + 0x16, + 0xFA, + 0x22, + 0xA5, + 0x77, + 0x09, + 0x61, + 0xD6, + 0x2A, + 0x53, + 0x37, + 0x45, + 0xC1, + 0x6C, + 0xAE, + 0xEF, + 0x70, + 0x08, + 0x99, + 0x8B, + 0x1D, + 0xF2, + 0xB4, + 0xE9, + 0xC7, + 0x9F, + 0x4A, + 0x31, + 0x25, + 0xFE, + 0x7C, + 0xD3, + 0xA2, + 0xBD, + 0x56, + 0x14, + 0x88, + 0x60, + 0x0B, + 0xCD, + 0xE2, + 0x34, + 0x50, + 0x9E, + 0xDC, + 0x11, + 0x05, + 0x2B, + 0xB7, + 0xA9, + 0x48, + 0xFF, + 0x66, + 0x8A, + 0x73, + 0x03, + 0x75, + 0x86, + 0xF1, + 0x6A, + 0xA7, + 0x40, + 0xC2, + 0xB9, + 0x2C, + 0xDB, + 0x1F, + 0x58, + 0x94, + 0x3E, + 0xED, + 0xFC, + 0x1B, + 0xA0, + 0x04, + 0xB8, + 0x8D, + 0xE6, + 0x59, + 0x62, + 0x93, + 0x35, + 0x7E, + 0xCA, + 0x21, + 0xDF, + 0x47, + 0x15, + 0xF3, + 0xBA, + 0x7F, + 0xA6, + 0x69, + 0xC8, + 0x4D, + 0x87, + 0x3B, + 0x9C, + 0x01, + 0xE0, + 0xDE, + 0x24, + 0x52, + 0x7B, + 0x0C, + 0x68, + 0x1E, + 0x80, + 0xB2, + 0x5A, + 0xE7, + 0xAD, + 0xD5, + 0x23, + 0xF4, + 0x46, + 0x3F, + 0x91, + 0xC9, + 0x6E, + 0x84, + 0x72, + 0xBB, + 0x0D, + 0x18, + 0xD9, + 0x96, + 0xF0, + 0x5F, + 0x41, + 0xAC, + 0x27, + 0xC5, + 0xE3, + 0x3A, + 0x81, + 0x6F, + 0x07, + 0xA3, + 0x79, + 0xF6, + 0x2D, + 0x38, + 0x1A, + 0x44, + 0x5E, + 0xB5, + 0xD2, + 0xEC, + 0xCB, + 0x90, + 0x9A, + 0x36, + 0xE5, + 0x29, + 0xC3, + 0x4F, + 0xAB, + 0x64, + 0x51, + 0xF8, + 0x10, + 0xD7, + 0xBC, + 0x02, + 0x7D, + 0x8E, + ] +) + +CLEFIA_S1 = SBox( + [ + 0x6C, + 0xDA, + 0xC3, + 0xE9, + 0x4E, + 0x9D, + 0x0A, + 0x3D, + 0xB8, + 0x36, + 0xB4, + 0x38, + 0x13, + 0x34, + 0x0C, + 0xD9, + 0xBF, + 0x74, + 0x94, + 0x8F, + 0xB7, + 0x9C, + 0xE5, + 0xDC, + 0x9E, + 0x07, + 0x49, + 0x4F, + 0x98, + 0x2C, + 0xB0, + 0x93, + 0x12, + 0xEB, + 0xCD, + 0xB3, + 0x92, + 0xE7, + 0x41, + 0x60, + 0xE3, + 0x21, + 0x27, + 0x3B, + 0xE6, + 0x19, + 0xD2, + 0x0E, + 0x91, + 0x11, + 0xC7, + 0x3F, + 0x2A, + 0x8E, + 0xA1, + 0xBC, + 0x2B, + 0xC8, + 0xC5, + 0x0F, + 0x5B, + 0xF3, + 0x87, + 0x8B, + 0xFB, + 0xF5, + 0xDE, + 0x20, + 0xC6, + 0xA7, + 0x84, + 0xCE, + 0xD8, + 0x65, + 0x51, + 0xC9, + 0xA4, + 0xEF, + 0x43, + 0x53, + 0x25, + 0x5D, + 0x9B, + 0x31, + 0xE8, + 0x3E, + 0x0D, + 0xD7, + 0x80, + 0xFF, + 0x69, + 0x8A, + 0xBA, + 0x0B, + 0x73, + 0x5C, + 0x6E, + 0x54, + 0x15, + 0x62, + 0xF6, + 0x35, + 0x30, + 0x52, + 0xA3, + 0x16, + 0xD3, + 0x28, + 0x32, + 0xFA, + 0xAA, + 0x5E, + 0xCF, + 0xEA, + 0xED, + 0x78, + 0x33, + 0x58, + 0x09, + 0x7B, + 0x63, + 0xC0, + 0xC1, + 0x46, + 0x1E, + 0xDF, + 0xA9, + 0x99, + 0x55, + 0x04, + 0xC4, + 0x86, + 0x39, + 0x77, + 0x82, + 0xEC, + 0x40, + 0x18, + 0x90, + 0x97, + 0x59, + 0xDD, + 0x83, + 0x1F, + 0x9A, + 0x37, + 0x06, + 0x24, + 0x64, + 0x7C, + 0xA5, + 0x56, + 0x48, + 0x08, + 0x85, + 0xD0, + 0x61, + 0x26, + 0xCA, + 0x6F, + 0x7E, + 0x6A, + 0xB6, + 0x71, + 0xA0, + 0x70, + 0x05, + 0xD1, + 0x45, + 0x8C, + 0x23, + 0x1C, + 0xF0, + 0xEE, + 0x89, + 0xAD, + 0x7A, + 0x4B, + 0xC2, + 0x2F, + 0xDB, + 0x5A, + 0x4D, + 0x76, + 0x67, + 0x17, + 0x2D, + 0xF4, + 0xCB, + 0xB1, + 0x4A, + 0xA8, + 0xB5, + 0x22, + 0x47, + 0x3A, + 0xD5, + 0x10, + 0x4C, + 0x72, + 0xCC, + 0x00, + 0xF9, + 0xE0, + 0xFD, + 0xE2, + 0xFE, + 0xAE, + 0xF8, + 0x5F, + 0xAB, + 0xF1, + 0x1B, + 0x42, + 0x81, + 0xD6, + 0xBE, + 0x44, + 0x29, + 0xA6, + 0x57, + 0xB9, + 0xAF, + 0xF2, + 0xD4, + 0x75, + 0x66, + 0xBB, + 0x68, + 0x9F, + 0x50, + 0x02, + 0x01, + 0x3C, + 0x7F, + 0x8D, + 0x1A, + 0x88, + 0xBD, + 0xAC, + 0xF7, + 0xE4, + 0x79, + 0x96, + 0xA2, + 0xFC, + 0x6D, + 0xB2, + 0x6B, + 0x03, + 0xE1, + 0x2E, + 0x7D, + 0x14, + 0x95, + 0x1D, + ] +) + +Crypton_0_5 = SBox( + [ + 0xF0, + 0x12, + 0x4C, + 0x7A, + 0x47, + 0x16, + 0x03, + 0x3A, + 0xE6, + 0x9D, + 0x44, + 0x77, + 0x53, + 0xCA, + 0x3B, + 0x0F, + 0x9B, + 0x98, + 0x54, + 0x90, + 0x3D, + 0xAC, + 0x74, + 0x56, + 0x9E, + 0xDE, + 0x5C, + 0xF3, + 0x86, + 0x39, + 0x7C, + 0xC4, + 0x91, + 0xA9, + 0x97, + 0x5F, + 0x9C, + 0x0D, + 0x78, + 0xCC, + 0xFD, + 0x43, + 0xBF, + 0x02, + 0x4B, + 0x92, + 0x60, + 0x3E, + 0x7D, + 0x1D, + 0x50, + 0xCB, + 0xB8, + 0xB9, + 0x70, + 0x27, + 0xAA, + 0x96, + 0x48, + 0x88, + 0x38, + 0xD7, + 0x68, + 0x42, + 0xA8, + 0xD0, + 0xA6, + 0x2E, + 0x25, + 0xF4, + 0x2C, + 0x6E, + 0x0C, + 0xB7, + 0xCE, + 0xE0, + 0xBE, + 0x0B, + 0x24, + 0x67, + 0x8C, + 0xEC, + 0xC5, + 0x52, + 0xD9, + 0xD8, + 0x09, + 0xB4, + 0xCF, + 0x8F, + 0x8D, + 0x8B, + 0x59, + 0x23, + 0x51, + 0xE3, + 0xD3, + 0xB1, + 0x18, + 0xF8, + 0xD4, + 0x05, + 0xA2, + 0xDB, + 0x82, + 0x6C, + 0x00, + 0x46, + 0x8A, + 0xAF, + 0xDA, + 0xBC, + 0x99, + 0x1A, + 0xAD, + 0xB3, + 0x1F, + 0x0E, + 0x71, + 0x4F, + 0xC7, + 0x2B, + 0xE5, + 0x2A, + 0xE2, + 0x58, + 0x29, + 0x06, + 0xF6, + 0xFE, + 0xF9, + 0x19, + 0x6B, + 0xEA, + 0xBB, + 0xC2, + 0xA3, + 0x55, + 0xA1, + 0xDF, + 0x6F, + 0x45, + 0x83, + 0x69, + 0x8E, + 0x7B, + 0x72, + 0x3C, + 0xEE, + 0xFF, + 0x07, + 0xA5, + 0xE8, + 0xF1, + 0x0A, + 0x1C, + 0x75, + 0xE1, + 0x2F, + 0x21, + 0xD2, + 0xB6, + 0x3F, + 0xF7, + 0x73, + 0xB2, + 0x5D, + 0x79, + 0x35, + 0x80, + 0x17, + 0x41, + 0x94, + 0x7E, + 0x15, + 0xED, + 0xB5, + 0xD5, + 0x93, + 0x14, + 0x20, + 0x61, + 0x76, + 0x31, + 0xC9, + 0x6A, + 0xAB, + 0x34, + 0xA0, + 0xA4, + 0x1E, + 0xBA, + 0xE7, + 0x13, + 0x4E, + 0xC6, + 0xD6, + 0x87, + 0x7F, + 0xBD, + 0x84, + 0x62, + 0x26, + 0x95, + 0x6D, + 0x4D, + 0x57, + 0x28, + 0x04, + 0x64, + 0x4A, + 0x11, + 0x01, + 0x40, + 0x65, + 0x08, + 0xB0, + 0xE9, + 0x32, + 0xCD, + 0x81, + 0x66, + 0x2D, + 0x5B, + 0xEF, + 0xA7, + 0xFB, + 0xDD, + 0xF2, + 0x33, + 0x5A, + 0x63, + 0xC1, + 0xE4, + 0xC3, + 0xAE, + 0xDC, + 0xFC, + 0x22, + 0x10, + 0xFA, + 0x9F, + 0xD1, + 0x85, + 0x9A, + 0x1B, + 0x5E, + 0x30, + 0xEB, + 0xC8, + 0x89, + 0x49, + 0x37, + 0xC0, + 0x36, + 0xF5, + ] +) + +Crypton_1_0_S0 = SBox( + [ + 0x63, + 0xEC, + 0x59, + 0xAA, + 0xDB, + 0x8E, + 0x66, + 0xC0, + 0x37, + 0x3C, + 0x14, + 0xFF, + 0x13, + 0x44, + 0xA9, + 0x91, + 0x3B, + 0x78, + 0x8D, + 0xEF, + 0xC2, + 0x2A, + 0xF0, + 0xD7, + 0x61, + 0x9E, + 0xA5, + 0xBC, + 0x48, + 0x15, + 0x12, + 0x47, + 0xED, + 0x42, + 0x1A, + 0x33, + 0x38, + 0xC8, + 0x17, + 0x90, + 0xA6, + 0xD5, + 0x5D, + 0x65, + 0x6A, + 0xFE, + 0x8F, + 0xA1, + 0x93, + 0xCA, + 0x2F, + 0x0C, + 0x68, + 0x58, + 0xDF, + 0xF4, + 0x45, + 0x11, + 0xA0, + 0xA7, + 0x22, + 0x96, + 0xFB, + 0x7D, + 0x1D, + 0xB4, + 0x84, + 0xE0, + 0xBF, + 0x57, + 0xE9, + 0x0A, + 0x4E, + 0x83, + 0xCC, + 0x7A, + 0x71, + 0x39, + 0xC7, + 0x32, + 0x74, + 0x3D, + 0xDE, + 0x50, + 0x85, + 0x06, + 0x6F, + 0x53, + 0xE8, + 0xAD, + 0x82, + 0x19, + 0xE1, + 0xBA, + 0x36, + 0xCB, + 0x0E, + 0x28, + 0xF3, + 0x9B, + 0x4A, + 0x62, + 0x94, + 0x1F, + 0xBD, + 0xF6, + 0x67, + 0x41, + 0xD8, + 0xD1, + 0x2D, + 0xA4, + 0x86, + 0xB7, + 0x01, + 0xC5, + 0xB0, + 0x75, + 0x02, + 0xF9, + 0x2C, + 0x29, + 0x6E, + 0xD2, + 0x5F, + 0x8B, + 0xFC, + 0x5A, + 0xE4, + 0x7F, + 0xDD, + 0x07, + 0x55, + 0xB1, + 0x2B, + 0x89, + 0x72, + 0x18, + 0x3A, + 0x4C, + 0xB6, + 0xE3, + 0x80, + 0xCE, + 0x49, + 0xCF, + 0x6B, + 0xB9, + 0xF2, + 0x0D, + 0xDC, + 0x64, + 0x95, + 0x46, + 0xF7, + 0x10, + 0x9A, + 0x20, + 0xA2, + 0x3F, + 0xD6, + 0x87, + 0x70, + 0x3E, + 0x21, + 0xFD, + 0x4D, + 0x7B, + 0xC3, + 0xAE, + 0x09, + 0x8A, + 0x04, + 0xB3, + 0x54, + 0xF8, + 0x30, + 0x00, + 0x56, + 0xD4, + 0xE7, + 0x25, + 0xBB, + 0xAC, + 0x98, + 0x73, + 0xEA, + 0xC9, + 0x9D, + 0x4F, + 0x7E, + 0x03, + 0xAB, + 0x92, + 0xA8, + 0x43, + 0x0F, + 0xFA, + 0x24, + 0x5C, + 0x1E, + 0x60, + 0x31, + 0x97, + 0xCD, + 0xC6, + 0x79, + 0xF5, + 0x5E, + 0xE5, + 0x34, + 0x76, + 0x1C, + 0x81, + 0xB2, + 0xAF, + 0x0B, + 0x5B, + 0xD9, + 0xE2, + 0x27, + 0x6D, + 0xD0, + 0x88, + 0xC1, + 0x51, + 0xE6, + 0x9C, + 0x77, + 0xBE, + 0x99, + 0x23, + 0xDA, + 0xEB, + 0x52, + 0x2E, + 0xB5, + 0x08, + 0x05, + 0x6C, + 0xB8, + 0x1B, + 0xA3, + 0x69, + 0x8C, + 0xD3, + 0x40, + 0x26, + 0xF1, + 0xC4, + 0x9F, + 0x35, + 0xEE, + 0x7C, + 0x4B, + 0x16, + ] +) + +Crypton_1_0_S1 = SBox( + [ + 0x8D, + 0xB3, + 0x65, + 0xAA, + 0x6F, + 0x3A, + 0x99, + 0x03, + 0xDC, + 0xF0, + 0x50, + 0xFF, + 0x4C, + 0x11, + 0xA6, + 0x46, + 0xEC, + 0xE1, + 0x36, + 0xBF, + 0x0B, + 0xA8, + 0xC3, + 0x5F, + 0x85, + 0x7A, + 0x96, + 0xF2, + 0x21, + 0x54, + 0x48, + 0x1D, + 0xB7, + 0x09, + 0x68, + 0xCC, + 0xE0, + 0x23, + 0x5C, + 0x42, + 0x9A, + 0x57, + 0x75, + 0x95, + 0xA9, + 0xFB, + 0x3E, + 0x86, + 0x4E, + 0x2B, + 0xBC, + 0x30, + 0xA1, + 0x61, + 0x7F, + 0xD3, + 0x15, + 0x44, + 0x82, + 0x9E, + 0x88, + 0x5A, + 0xEF, + 0xF5, + 0x74, + 0xD2, + 0x12, + 0x83, + 0xFE, + 0x5D, + 0xA7, + 0x28, + 0x39, + 0x0E, + 0x33, + 0xE9, + 0xC5, + 0xE4, + 0x1F, + 0xC8, + 0xD1, + 0xF4, + 0x7B, + 0x41, + 0x16, + 0x18, + 0xBD, + 0x4D, + 0xA3, + 0xB6, + 0x0A, + 0x64, + 0x87, + 0xEA, + 0xD8, + 0x2F, + 0x38, + 0xA0, + 0xCF, + 0x6E, + 0x29, + 0x89, + 0x52, + 0x7C, + 0xF6, + 0xDB, + 0x9D, + 0x05, + 0x63, + 0x47, + 0xB4, + 0x92, + 0x1A, + 0xDE, + 0x04, + 0x17, + 0xC2, + 0xD5, + 0x08, + 0xE7, + 0xB0, + 0xA4, + 0xB9, + 0x4B, + 0x7D, + 0x2E, + 0xF3, + 0x69, + 0x93, + 0xFD, + 0x77, + 0x1C, + 0x55, + 0xC6, + 0xAC, + 0x26, + 0xC9, + 0x60, + 0xE8, + 0x31, + 0xDA, + 0x8F, + 0x02, + 0x3B, + 0x25, + 0x3F, + 0xAD, + 0xE6, + 0xCB, + 0x34, + 0x73, + 0x91, + 0x56, + 0x19, + 0xDF, + 0x40, + 0x6A, + 0x80, + 0x8A, + 0xFC, + 0x5B, + 0x1E, + 0xC1, + 0xF8, + 0x84, + 0xF7, + 0x35, + 0xED, + 0x0F, + 0xBA, + 0x24, + 0x2A, + 0x10, + 0xCE, + 0x51, + 0xE3, + 0xC0, + 0x00, + 0x59, + 0x53, + 0x9F, + 0x94, + 0xEE, + 0xB2, + 0x62, + 0xCD, + 0xAB, + 0x27, + 0x76, + 0x3D, + 0xF9, + 0x0C, + 0xAE, + 0x4A, + 0xA2, + 0x0D, + 0x3C, + 0xEB, + 0x90, + 0x71, + 0x78, + 0x81, + 0xC4, + 0x5E, + 0x37, + 0x1B, + 0xE5, + 0xD7, + 0x79, + 0x97, + 0xD0, + 0xD9, + 0x70, + 0x06, + 0xCA, + 0xBE, + 0x2C, + 0x6D, + 0x67, + 0x8B, + 0x9C, + 0xB5, + 0x43, + 0x22, + 0x07, + 0x45, + 0x9B, + 0x72, + 0xDD, + 0xFA, + 0x66, + 0x8C, + 0x6B, + 0xAF, + 0x49, + 0xB8, + 0xD6, + 0x20, + 0x14, + 0xB1, + 0xE2, + 0x6C, + 0x8E, + 0xA5, + 0x32, + 0x4F, + 0x01, + 0x98, + 0xC7, + 0x13, + 0x7E, + 0xD4, + 0xBB, + 0xF1, + 0x2D, + 0x58, + ] +) + +Crypton_1_0_S2 = SBox( + [ + 0xB1, + 0x72, + 0x76, + 0xBF, + 0xAC, + 0xEE, + 0x55, + 0x83, + 0xED, + 0xAA, + 0x47, + 0xD8, + 0x33, + 0x95, + 0x60, + 0xC4, + 0x9B, + 0x39, + 0x1E, + 0x0C, + 0x0A, + 0x1D, + 0xFF, + 0x26, + 0x89, + 0x5B, + 0x22, + 0xF1, + 0xD4, + 0x40, + 0xC8, + 0x67, + 0x9D, + 0xA4, + 0x3C, + 0xE7, + 0xC6, + 0xB5, + 0xF7, + 0xDC, + 0x61, + 0x79, + 0x15, + 0x86, + 0x78, + 0x6E, + 0xEB, + 0x32, + 0xB0, + 0xCA, + 0x4F, + 0x23, + 0xD2, + 0xFB, + 0x5E, + 0x08, + 0x24, + 0x4D, + 0x8A, + 0x10, + 0x09, + 0x51, + 0xA3, + 0x9F, + 0xF6, + 0x6B, + 0x21, + 0xC3, + 0x0D, + 0x38, + 0x99, + 0x1F, + 0x1C, + 0x90, + 0x64, + 0xFE, + 0x8B, + 0xA6, + 0x48, + 0xBD, + 0x53, + 0xE1, + 0xEA, + 0x57, + 0xAE, + 0x84, + 0xB2, + 0x45, + 0x35, + 0x02, + 0x7F, + 0xD9, + 0xC7, + 0x2A, + 0xD0, + 0x7C, + 0xC9, + 0x18, + 0x65, + 0x00, + 0x97, + 0x2B, + 0x06, + 0x6A, + 0x34, + 0xF3, + 0x2C, + 0x92, + 0xEF, + 0xDD, + 0x7A, + 0x56, + 0xA2, + 0x4C, + 0x88, + 0xB9, + 0x50, + 0x75, + 0xD3, + 0xE4, + 0x11, + 0xCE, + 0x4B, + 0xA7, + 0xFD, + 0x3F, + 0xBE, + 0x81, + 0x8E, + 0xD5, + 0x5A, + 0x49, + 0x42, + 0x54, + 0x70, + 0xA1, + 0xDF, + 0x87, + 0xAB, + 0x7D, + 0xF4, + 0x12, + 0x05, + 0x2E, + 0x27, + 0x0F, + 0xC1, + 0x30, + 0x66, + 0x98, + 0x3D, + 0xCB, + 0xB8, + 0xE6, + 0x9C, + 0x63, + 0xE3, + 0xBC, + 0x19, + 0xFA, + 0x3A, + 0x2F, + 0x9E, + 0xF2, + 0x6F, + 0x1A, + 0x28, + 0x3B, + 0xC2, + 0x0E, + 0x03, + 0xC0, + 0xB7, + 0x59, + 0xA9, + 0xD7, + 0x74, + 0x85, + 0xD6, + 0xAD, + 0x41, + 0xEC, + 0x8C, + 0x71, + 0xF0, + 0x93, + 0x5D, + 0xB6, + 0x1B, + 0x68, + 0xE5, + 0x44, + 0x07, + 0xE0, + 0x14, + 0xA8, + 0xF9, + 0x73, + 0xCD, + 0x4E, + 0x25, + 0xBB, + 0x31, + 0x5F, + 0x4A, + 0xCC, + 0x8F, + 0x91, + 0xDE, + 0x6D, + 0x7B, + 0xF5, + 0xB3, + 0x29, + 0xA0, + 0x17, + 0x6C, + 0xDA, + 0xE8, + 0x04, + 0x96, + 0x82, + 0x52, + 0x36, + 0x43, + 0x5C, + 0xDB, + 0x8D, + 0x80, + 0xD1, + 0xE2, + 0xB4, + 0x58, + 0x46, + 0xBA, + 0xE9, + 0x01, + 0x20, + 0xFC, + 0x13, + 0x16, + 0xF8, + 0x94, + 0x62, + 0x37, + 0xCF, + 0x69, + 0x9A, + 0xAF, + 0x77, + 0xC5, + 0x3E, + 0x7E, + 0xA5, + 0x2D, + 0x0B, + ] +) + +Crypton_1_0_S3 = SBox( + [ + 0xB1, + 0xF6, + 0x8E, + 0x07, + 0x72, + 0x6B, + 0xD5, + 0xE0, + 0x76, + 0x21, + 0x5A, + 0x14, + 0xBF, + 0xC3, + 0x49, + 0xA8, + 0xAC, + 0x0D, + 0x42, + 0xF9, + 0xEE, + 0x38, + 0x54, + 0x73, + 0x55, + 0x99, + 0x70, + 0xCD, + 0x83, + 0x1F, + 0xA1, + 0x4E, + 0xED, + 0x1C, + 0xDF, + 0x25, + 0xAA, + 0x90, + 0x87, + 0xBB, + 0x47, + 0x64, + 0xAB, + 0x31, + 0xD8, + 0xFE, + 0x7D, + 0x5F, + 0x33, + 0x8B, + 0xF4, + 0x4A, + 0x95, + 0xA6, + 0x12, + 0xCC, + 0x60, + 0x48, + 0x05, + 0x8F, + 0xC4, + 0xBD, + 0x2E, + 0x91, + 0x9B, + 0x53, + 0x27, + 0xDE, + 0x39, + 0xE1, + 0x0F, + 0x6D, + 0x1E, + 0xEA, + 0xC1, + 0x7B, + 0x0C, + 0x57, + 0x30, + 0xF5, + 0x0A, + 0xAE, + 0x66, + 0xB3, + 0x1D, + 0x84, + 0x98, + 0x29, + 0xFF, + 0xB2, + 0x3D, + 0xA0, + 0x26, + 0x45, + 0xCB, + 0x17, + 0x89, + 0x35, + 0xB8, + 0x6C, + 0x5B, + 0x02, + 0xE6, + 0xDA, + 0x22, + 0x7F, + 0x9C, + 0xE8, + 0xF1, + 0xD9, + 0x63, + 0x04, + 0xD4, + 0xC7, + 0xE3, + 0x96, + 0x40, + 0x2A, + 0xBC, + 0x82, + 0xC8, + 0xD0, + 0x19, + 0x52, + 0x67, + 0x7C, + 0xFA, + 0x36, + 0x9D, + 0xC9, + 0x3A, + 0x43, + 0xA4, + 0x18, + 0x2F, + 0x5C, + 0x3C, + 0x65, + 0x9E, + 0xDB, + 0xE7, + 0x00, + 0xF2, + 0x8D, + 0xC6, + 0x97, + 0x6F, + 0x80, + 0xB5, + 0x2B, + 0x1A, + 0xD1, + 0xF7, + 0x06, + 0x28, + 0xE2, + 0xDC, + 0x6A, + 0x3B, + 0xB4, + 0x61, + 0x34, + 0xC2, + 0x58, + 0x79, + 0xF3, + 0x0E, + 0x46, + 0x15, + 0x2C, + 0x03, + 0xBA, + 0x86, + 0x92, + 0xC0, + 0xE9, + 0x78, + 0xEF, + 0xB7, + 0x01, + 0x6E, + 0xDD, + 0x59, + 0x20, + 0xEB, + 0x7A, + 0xA9, + 0xFC, + 0x32, + 0x56, + 0xD7, + 0x13, + 0xB0, + 0xA2, + 0x74, + 0x16, + 0xCA, + 0x4C, + 0x85, + 0xF8, + 0x4F, + 0x88, + 0xD6, + 0x94, + 0x23, + 0xB9, + 0xAD, + 0x62, + 0xD2, + 0x50, + 0x41, + 0x37, + 0xFB, + 0x75, + 0xEC, + 0xCF, + 0x5E, + 0xD3, + 0x8C, + 0x69, + 0x08, + 0xE4, + 0x71, + 0x9A, + 0x24, + 0x11, + 0xF0, + 0xAF, + 0x4D, + 0xCE, + 0x93, + 0x77, + 0x8A, + 0x4B, + 0x5D, + 0xC5, + 0x10, + 0xA7, + 0xB6, + 0x3E, + 0x09, + 0xFD, + 0x1B, + 0x7E, + 0x51, + 0x3F, + 0x68, + 0xA5, + 0xA3, + 0xBE, + 0xE5, + 0x2D, + 0x9F, + 0x81, + 0x44, + 0x0B, + ] +) + +CS_cipher = SBox( + [ + 0x29, + 0xD, + 0x61, + 0x40, + 0x9C, + 0xEB, + 0x9E, + 0x8F, + 0x1F, + 0x85, + 0x5F, + 0x58, + 0x5B, + 0x1, + 0x39, + 0x86, + 0x97, + 0x2E, + 0xD7, + 0xD6, + 0x35, + 0xAE, + 0x17, + 0x16, + 0x21, + 0xB6, + 0x69, + 0x4E, + 0xA5, + 0x72, + 0x87, + 0x8, + 0x3C, + 0x18, + 0xE6, + 0xE7, + 0xFA, + 0xAD, + 0xB8, + 0x89, + 0xB7, + 0x0, + 0xF7, + 0x6F, + 0x73, + 0x84, + 0x11, + 0x63, + 0x3F, + 0x96, + 0x7F, + 0x6E, + 0xBF, + 0x14, + 0x9D, + 0xAC, + 0xA4, + 0xE, + 0x7E, + 0xF6, + 0x20, + 0x4A, + 0x62, + 0x30, + 0x3, + 0xC5, + 0x4B, + 0x5A, + 0x46, + 0xA3, + 0x44, + 0x65, + 0x7D, + 0x4D, + 0x3D, + 0x42, + 0x79, + 0x49, + 0x1B, + 0x5C, + 0xF5, + 0x6C, + 0xB5, + 0x94, + 0x54, + 0xFF, + 0x56, + 0x57, + 0xB, + 0xF4, + 0x43, + 0xC, + 0x4F, + 0x70, + 0x6D, + 0xA, + 0xE4, + 0x2, + 0x3E, + 0x2F, + 0xA2, + 0x47, + 0xE0, + 0xC1, + 0xD5, + 0x1A, + 0x95, + 0xA7, + 0x51, + 0x5E, + 0x33, + 0x2B, + 0x5D, + 0xD4, + 0x1D, + 0x2C, + 0xEE, + 0x75, + 0xEC, + 0xDD, + 0x7C, + 0x4C, + 0xA6, + 0xB4, + 0x78, + 0x48, + 0x3A, + 0x32, + 0x98, + 0xAF, + 0xC0, + 0xE1, + 0x2D, + 0x9, + 0xF, + 0x1E, + 0xB9, + 0x27, + 0x8A, + 0xE9, + 0xBD, + 0xE3, + 0x9F, + 0x7, + 0xB1, + 0xEA, + 0x92, + 0x93, + 0x53, + 0x6A, + 0x31, + 0x10, + 0x80, + 0xF2, + 0xD8, + 0x9B, + 0x4, + 0x36, + 0x6, + 0x8E, + 0xBE, + 0xA9, + 0x64, + 0x45, + 0x38, + 0x1C, + 0x7A, + 0x6B, + 0xF3, + 0xA1, + 0xF0, + 0xCD, + 0x37, + 0x25, + 0x15, + 0x81, + 0xFB, + 0x90, + 0xE8, + 0xD9, + 0x7B, + 0x52, + 0x19, + 0x28, + 0x26, + 0x88, + 0xFC, + 0xD1, + 0xE2, + 0x8C, + 0xA0, + 0x34, + 0x82, + 0x67, + 0xDA, + 0xCB, + 0xC7, + 0x41, + 0xE5, + 0xC4, + 0xC8, + 0xEF, + 0xDB, + 0xC3, + 0xCC, + 0xAB, + 0xCE, + 0xED, + 0xD0, + 0xBB, + 0xD3, + 0xD2, + 0x71, + 0x68, + 0x13, + 0x12, + 0x9A, + 0xB3, + 0xC2, + 0xCA, + 0xDE, + 0x77, + 0xDC, + 0xDF, + 0x66, + 0x83, + 0xBC, + 0x8D, + 0x60, + 0xC6, + 0x22, + 0x23, + 0xB2, + 0x8B, + 0x91, + 0x5, + 0x76, + 0xCF, + 0x74, + 0xC9, + 0xAA, + 0xF1, + 0x99, + 0xA8, + 0x59, + 0x50, + 0x3B, + 0x2A, + 0xFE, + 0xF9, + 0x24, + 0xB0, + 0xBA, + 0xFD, + 0xF8, + 0x55, + ] +) + + +CSA = SBox( + [ + 0x3A, + 0xEA, + 0x68, + 0xFE, + 0x33, + 0xE9, + 0x88, + 0x1A, + 0x83, + 0xCF, + 0xE1, + 0x7F, + 0xBA, + 0xE2, + 0x38, + 0x12, + 0xE8, + 0x27, + 0x61, + 0x95, + 0x0C, + 0x36, + 0xE5, + 0x70, + 0xA2, + 0x06, + 0x82, + 0x7C, + 0x17, + 0xA3, + 0x26, + 0x49, + 0xBE, + 0x7A, + 0x6D, + 0x47, + 0xC1, + 0x51, + 0x8F, + 0xF3, + 0xCC, + 0x5B, + 0x67, + 0xBD, + 0xCD, + 0x18, + 0x08, + 0xC9, + 0xFF, + 0x69, + 0xEF, + 0x03, + 0x4E, + 0x48, + 0x4A, + 0x84, + 0x3F, + 0xB4, + 0x10, + 0x04, + 0xDC, + 0xF5, + 0x5C, + 0xC6, + 0x16, + 0xAB, + 0xAC, + 0x4C, + 0xF1, + 0x6A, + 0x2F, + 0x3C, + 0x3B, + 0xD4, + 0xD5, + 0x94, + 0xD0, + 0xC4, + 0x63, + 0x62, + 0x71, + 0xA1, + 0xF9, + 0x4F, + 0x2E, + 0xAA, + 0xC5, + 0x56, + 0xE3, + 0x39, + 0x93, + 0xCE, + 0x65, + 0x64, + 0xE4, + 0x58, + 0x6C, + 0x19, + 0x42, + 0x79, + 0xDD, + 0xEE, + 0x96, + 0xF6, + 0x8A, + 0xEC, + 0x1E, + 0x85, + 0x53, + 0x45, + 0xDE, + 0xBB, + 0x7E, + 0x0A, + 0x9A, + 0x13, + 0x2A, + 0x9D, + 0xC2, + 0x5E, + 0x5A, + 0x1F, + 0x32, + 0x35, + 0x9C, + 0xA8, + 0x73, + 0x30, + 0x29, + 0x3D, + 0xE7, + 0x92, + 0x87, + 0x1B, + 0x2B, + 0x4B, + 0xA5, + 0x57, + 0x97, + 0x40, + 0x15, + 0xE6, + 0xBC, + 0x0E, + 0xEB, + 0xC3, + 0x34, + 0x2D, + 0xB8, + 0x44, + 0x25, + 0xA4, + 0x1C, + 0xC7, + 0x23, + 0xED, + 0x90, + 0x6E, + 0x50, + 0x00, + 0x99, + 0x9E, + 0x4D, + 0xD9, + 0xDA, + 0x8D, + 0x6F, + 0x5F, + 0x3E, + 0xD7, + 0x21, + 0x74, + 0x86, + 0xDF, + 0x6B, + 0x05, + 0x8E, + 0x5D, + 0x37, + 0x11, + 0xD2, + 0x28, + 0x75, + 0xD6, + 0xA7, + 0x77, + 0x24, + 0xBF, + 0xF0, + 0xB0, + 0x02, + 0xB7, + 0xF8, + 0xFC, + 0x81, + 0x09, + 0xB1, + 0x01, + 0x76, + 0x91, + 0x7D, + 0x0F, + 0xC8, + 0xA0, + 0xF2, + 0xCB, + 0x78, + 0x60, + 0xD1, + 0xF7, + 0xE0, + 0xB5, + 0x98, + 0x22, + 0xB3, + 0x20, + 0x1D, + 0xA6, + 0xDB, + 0x7B, + 0x59, + 0x9F, + 0xAE, + 0x31, + 0xFB, + 0xD3, + 0xB6, + 0xCA, + 0x43, + 0x72, + 0x07, + 0xF4, + 0xD8, + 0x41, + 0x14, + 0x55, + 0x0D, + 0x54, + 0x8B, + 0xB9, + 0xAD, + 0x46, + 0x0B, + 0xAF, + 0x80, + 0x52, + 0x2C, + 0xFA, + 0x8C, + 0x89, + 0x66, + 0xFD, + 0xB2, + 0xA9, + 0x9B, + 0xC0, + ] +) # source: http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=3672D97255B2446765DA47DA97960CDF?doi=10.1.1.118.6103&rep=rep1&type=pdf -CSS = SBox([ - 0x33,0x73,0x3b,0x26,0x63,0x23,0x6b,0x76,0x3e,0x7e,0x36,0x2b,0x6e,0x2e,0x66,0x7b, - 0xd3,0x93,0xdb,0x06,0x43,0x03,0x4b,0x96,0xde,0x9e,0xd6,0x0b,0x4e,0x0e,0x46,0x9b, - 0x57,0x17,0x5f,0x82,0xc7,0x87,0xcf,0x12,0x5a,0x1a,0x52,0x8f,0xca,0x8a,0xc2,0x1f, - 0xd9,0x99,0xd1,0x00,0x49,0x09,0x41,0x90,0xd8,0x98,0xd0,0x01,0x48,0x08,0x40,0x91, - 0x3d,0x7d,0x35,0x24,0x6d,0x2d,0x65,0x74,0x3c,0x7c,0x34,0x25,0x6c,0x2c,0x64,0x75, - 0xdd,0x9d,0xd5,0x04,0x4d,0x0d,0x45,0x94,0xdc,0x9c,0xd4,0x05,0x4c,0x0c,0x44,0x95, - 0x59,0x19,0x51,0x80,0xc9,0x89,0xc1,0x10,0x58,0x18,0x50,0x81,0xc8,0x88,0xc0,0x11, - 0xd7,0x97,0xdf,0x02,0x47,0x07,0x4f,0x92,0xda,0x9a,0xd2,0x0f,0x4a,0x0a,0x42,0x9f, - 0x53,0x13,0x5b,0x86,0xc3,0x83,0xcb,0x16,0x5e,0x1e,0x56,0x8b,0xce,0x8e,0xc6,0x1b, - 0xb3,0xf3,0xbb,0xa6,0xe3,0xa3,0xeb,0xf6,0xbe,0xfe,0xb6,0xab,0xee,0xae,0xe6,0xfb, - 0x37,0x77,0x3f,0x22,0x67,0x27,0x6f,0x72,0x3a,0x7a,0x32,0x2f,0x6a,0x2a,0x62,0x7f, - 0xb9,0xf9,0xb1,0xa0,0xe9,0xa9,0xe1,0xf0,0xb8,0xf8,0xb0,0xa1,0xe8,0xa8,0xe0,0xf1, - 0x5d,0x1d,0x55,0x84,0xcd,0x8d,0xc5,0x14,0x5c,0x1c,0x54,0x85,0xcc,0x8c,0xc4,0x15, - 0xbd,0xfd,0xb5,0xa4,0xed,0xad,0xe5,0xf4,0xbc,0xfc,0xb4,0xa5,0xec,0xac,0xe4,0xf5, - 0x39,0x79,0x31,0x20,0x69,0x29,0x61,0x70,0x38,0x78,0x30,0x21,0x68,0x28,0x60,0x71, - 0xb7,0xf7,0xbf,0xa2,0xe7,0xa7,0xef,0xf2,0xba,0xfa,0xb2,0xaf,0xea,0xaa,0xe2,0xff]) - -DBlock = SBox([ - 0x51,0x36,0x93,0x53,0xd9,0x4a,0xfc,0x58,0xe4,0x2e,0x0d,0x14,0xda,0x9d,0x91,0x69, - 0xef,0x72,0x03,0xc6,0x15,0x8d,0x5c,0x62,0x3f,0xb9,0x45,0x70,0x13,0xa3,0x95,0x6f, - 0x84,0xdb,0xb8,0x89,0x8a,0x6e,0xd4,0x7b,0x40,0xdc,0x9b,0x0c,0x50,0x8e,0xee,0x6a, - 0x88,0x3b,0x0f,0x6b,0x85,0xd3,0x54,0xa8,0x20,0xdf,0xb5,0x1b,0x32,0x7c,0x56,0x64, - 0x74,0xfa,0xc7,0x2d,0x96,0x17,0xae,0xcd,0xb4,0xf5,0x57,0x8c,0xf1,0xbc,0xd8,0xfe, - 0x27,0x06,0xe1,0xa9,0x1a,0x0e,0x5b,0x08,0xf4,0x9f,0x4b,0xed,0x73,0xb7,0xac,0x76, - 0x23,0xca,0x16,0xba,0xa7,0x00,0x8b,0x46,0x41,0xd5,0x7e,0xf2,0x05,0xf6,0x63,0x67, - 0x61,0x8f,0x3d,0xc8,0x1c,0x5a,0xb0,0x79,0x38,0x81,0xaa,0x33,0x97,0xe6,0x2c,0x01, - 0x22,0x87,0x4f,0xbe,0x24,0x71,0x35,0x9c,0xb1,0xad,0xc5,0x1d,0x80,0x3e,0x75,0xb3, - 0x28,0x68,0x2a,0xa0,0xbf,0x2f,0xb2,0xc4,0xce,0x19,0xd7,0xcf,0xaf,0x02,0xa4,0xa5, - 0x7a,0x39,0xd2,0x04,0xab,0xf7,0x60,0x2b,0x4c,0xec,0x4d,0x10,0x90,0x12,0xfb,0x78, - 0x82,0x4e,0x37,0x47,0xd6,0xa2,0xd1,0x86,0xb6,0xc1,0xe9,0xdd,0xa1,0xf8,0x55,0xde, - 0x98,0x7d,0xe5,0x30,0xfd,0xe2,0xcc,0x3a,0xea,0xd0,0x0a,0x29,0xe8,0xe3,0xeb,0xf0, - 0x9a,0x5d,0x3c,0x21,0xc0,0x48,0x6d,0x1e,0xe7,0x1f,0xc9,0x44,0x34,0x18,0x83,0xf9, - 0x59,0x5f,0x42,0x92,0x6c,0x11,0xa6,0x52,0xff,0x9e,0x49,0x26,0x07,0x43,0xbd,0xc3, - 0x99,0xf3,0x77,0x0b,0x5e,0xcb,0x09,0x31,0xe0,0xc2,0x65,0x7f,0x25,0x94,0xbb,0x66]) - -E2 = SBox([ - 0xe1,0x42,0x3e,0x81,0x4e,0x17,0x9e,0xfd,0xb4,0x3f,0x2c,0xda,0x31,0x1e,0xe0,0x41, - 0xcc,0xf3,0x82,0x7d,0x7c,0x12,0x8e,0xbb,0xe4,0x58,0x15,0xd5,0x6f,0xe9,0x4c,0x4b, - 0x35,0x7b,0x5a,0x9a,0x90,0x45,0xbc,0xf8,0x79,0xd6,0x1b,0x88,0x02,0xab,0xcf,0x64, - 0x09,0x0c,0xf0,0x01,0xa4,0xb0,0xf6,0x93,0x43,0x63,0x86,0xdc,0x11,0xa5,0x83,0x8b, - 0xc9,0xd0,0x19,0x95,0x6a,0xa1,0x5c,0x24,0x6e,0x50,0x21,0x80,0x2f,0xe7,0x53,0x0f, - 0x91,0x22,0x04,0xed,0xa6,0x48,0x49,0x67,0xec,0xf7,0xc0,0x39,0xce,0xf2,0x2d,0xbe, - 0x5d,0x1c,0xe3,0x87,0x07,0x0d,0x7a,0xf4,0xfb,0x32,0xf5,0x8c,0xdb,0x8f,0x25,0x96, - 0xa8,0xea,0xcd,0x33,0x65,0x54,0x06,0x8d,0x89,0x0a,0x5e,0xd9,0x16,0x0e,0x71,0x6c, - 0x0b,0xff,0x60,0xd2,0x2e,0xd3,0xc8,0x55,0xc2,0x23,0xb7,0x74,0xe2,0x9b,0xdf,0x77, - 0x2b,0xb9,0x3c,0x62,0x13,0xe5,0x94,0x34,0xb1,0x27,0x84,0x9f,0xd7,0x51,0x00,0x61, - 0xad,0x85,0x73,0x03,0x08,0x40,0xef,0x68,0xfe,0x97,0x1f,0xde,0xaf,0x66,0xe8,0xb8, - 0xae,0xbd,0xb3,0xeb,0xc6,0x6b,0x47,0xa9,0xd8,0xa7,0x72,0xee,0x1d,0x7e,0xaa,0xb6, - 0x75,0xcb,0xd4,0x30,0x69,0x20,0x7f,0x37,0x5b,0x9d,0x78,0xa3,0xf1,0x76,0xfa,0x05, - 0x3d,0x3a,0x44,0x57,0x3b,0xca,0xc7,0x8a,0x18,0x46,0x9c,0xbf,0xba,0x38,0x56,0x1a, - 0x92,0x4d,0x26,0x29,0xa2,0x98,0x10,0x99,0x70,0xa0,0xc5,0x28,0xc1,0x6d,0x14,0xac, - 0xf9,0x5f,0x4f,0xc4,0xc3,0xd1,0xfc,0xdd,0xb2,0x59,0xe6,0xb5,0x36,0x52,0x4a,0x2a]) - -Enocoro = SBox([ - 99,82,26,223,138,246,174,85,137,231,208,45,189,1,36,120, - 27,217,227,84,200,164,236,126,171,0,156,46,145,103,55,83, - 78,107,108,17,178,192,130,253,57,69,254,155,52,215,167,8, - 184,154,51,198,76,29,105,161,110,62,197,10,87,244,241,131, - 245,71,31,122,165,41,60,66,214,115,141,240,142,24,170,193, - 32,191,230,147,81,14,247,152,221,186,106,5,72,35,109,212, - 30,96,117,67,151,42,49,219,132,25,175,188,204,243,232,70, - 136,172,139,228,123,213,88,54,2,177,7,114,225,220,95,47, - 93,229,209,12,38,153,181,111,224,74,59,222,162,104,146,23, - 202,238,169,182,3,94,211,37,251,157,97,89,6,144,116,44, - 39,149,160,185,124,237,4,210,80,226,73,119,203,58,15,158, - 112,22,92,239,33,179,159,13,166,201,34,148,250,75,216,101, - 133,61,150,40,20,91,102,234,127,206,249,64,19,173,195,176, - 242,194,56,128,207,113,11,135,77,53,86,233,100,190,28,187, - 183,48,196,43,255,98,65,168,21,140,18,199,121,143,90,252, - 205,9,79,125,248,134,218,16,50,118,180,163,63,68,129,235]) - -Fantomas = SBox([ - 0x1e,0x75,0x5f,0xe1,0x99,0xfc,0x89,0x2f,0x86,0xee,0xf1,0x7b,0x23,0x52,0x10,0x94, - 0x0c,0xb7,0x4d,0x67,0xd8,0x42,0xc8,0xd6,0xc4,0x6b,0xaa,0xba,0x3d,0xa5,0x00,0x33, - 0x53,0x2d,0x0b,0xb8,0xda,0xa8,0xc5,0x6c,0xca,0xb6,0xa4,0x22,0x60,0x07,0x5d,0xd7, - 0x4f,0xf4,0x15,0x32,0x81,0x1b,0x9c,0x8e,0x91,0x3f,0xe6,0xf9,0x70,0xe9,0x43,0x7e, - 0x8d,0xf3,0xcc,0x65,0x08,0x7a,0x18,0xab,0x16,0x6a,0x77,0xfd,0xa7,0xc0,0x82,0x04, - 0x9f,0x31,0xde,0xe3,0x49,0xd0,0x59,0x46,0x54,0xef,0x2e,0x3c,0xbb,0x21,0x92,0xb5, - 0x55,0x3e,0x0f,0xa9,0xdc,0xb9,0xc1,0x7f,0xce,0xa6,0xb4,0x30,0x72,0x03,0x5b,0xd1, - 0x4b,0xe4,0x13,0x20,0x85,0x1d,0x9a,0x8a,0x97,0x2c,0xf6,0xe8,0x62,0xf8,0x47,0x6d, - 0x29,0x41,0x68,0xd5,0xac,0xcb,0xbe,0x1a,0xb0,0xdb,0xc7,0x4e,0x17,0x64,0x26,0xa0, - 0x39,0x83,0x78,0x51,0xed,0x76,0xff,0xe2,0xf2,0x5c,0x9d,0x8f,0x0a,0x93,0x34,0x05, - 0x25,0x58,0x7c,0xcd,0xaf,0xdf,0xb3,0x19,0xbd,0xc2,0xd2,0x56,0x14,0x71,0x2a,0xa3, - 0x3a,0x80,0x61,0x44,0xf5,0x6e,0xeb,0xfb,0xe7,0x48,0x90,0x8c,0x06,0x9e,0x37,0x09, - 0x98,0xe5,0xd9,0x73,0x1f,0x6f,0x0d,0xbc,0x02,0x7d,0x63,0xea,0xb1,0xd4,0x96,0x12, - 0x88,0x27,0xc9,0xf7,0x5e,0xc6,0x4c,0x50,0x40,0xfa,0x3b,0x2b,0xae,0x35,0x84,0xa1, - 0x01,0x69,0x5a,0xfe,0x8b,0xec,0x95,0x28,0x9b,0xf0,0xe0,0x66,0x24,0x57,0x0e,0x87, - 0x1c,0xb2,0x45,0x74,0xd3,0x4a,0xcf,0xdd,0xc3,0x79,0xa2,0xbf,0x36,0xad,0x11,0x38]) - - -FLY = SBox([ - 0x00,0x9b,0xc2,0x15,0x5d,0x84,0x4c,0xd1,0x67,0x38,0xef,0xb0,0x7e,0x2b,0xf6,0xa3, - 0xb9,0xaa,0x36,0x78,0x2f,0x6e,0xe3,0xf7,0x12,0x5c,0x9a,0xd4,0x89,0xcd,0x01,0x45, - 0x2c,0x63,0x44,0xde,0x02,0x96,0x39,0x70,0xba,0xe4,0x18,0x57,0xa1,0xf5,0x8b,0xce, - 0x51,0x87,0xed,0xff,0xb5,0xa8,0xca,0x1b,0xdf,0x90,0x6c,0x32,0x46,0x03,0x7d,0x29, - 0xd5,0xf2,0x20,0x5b,0xcc,0x31,0x04,0xbd,0xa6,0x41,0x8e,0x79,0xea,0x9f,0x68,0x1c, - 0x48,0xe6,0x69,0x8a,0x13,0x77,0x9e,0xaf,0xf3,0x05,0xcb,0x2d,0xb4,0xd0,0x37,0x52, - 0xc4,0x3e,0x93,0xac,0x40,0xe9,0x22,0x56,0x7b,0x8d,0xf1,0x06,0x17,0x62,0xbf,0xda, - 0x1d,0x7f,0x07,0xb1,0xdb,0xfa,0x65,0x88,0x2e,0xc9,0xa5,0x43,0x58,0x3c,0xe0,0x94, - 0x76,0x21,0xab,0xfd,0x6a,0x3f,0xb7,0xe2,0xdd,0x4f,0x53,0x8c,0xc0,0x19,0x95,0x08, - 0x83,0xc5,0x4e,0x09,0x14,0x50,0xd8,0x9c,0xf4,0xee,0x27,0x61,0x3b,0x7a,0xa2,0xb6, - 0xfe,0xa9,0x81,0xc6,0xe8,0xbc,0x1f,0x5a,0x35,0x72,0x99,0x0a,0xd3,0x47,0x24,0x6d, - 0x0b,0x4d,0x75,0x23,0x97,0xd2,0x60,0x34,0xc8,0x16,0xa0,0xbb,0xfc,0xe1,0x5e,0x8f, - 0xe7,0x98,0x1a,0x64,0xae,0x4b,0x71,0x85,0x0c,0xb3,0x3d,0xcf,0x55,0x28,0xd9,0xf0, - 0xb2,0xdc,0x5f,0x30,0xf9,0x0d,0x26,0xc3,0x91,0xa7,0x74,0x1e,0x82,0x66,0x4a,0xeb, - 0x6f,0x10,0xb8,0xd7,0x86,0x73,0xfb,0x0e,0x59,0x2a,0x42,0xe5,0x9d,0xa4,0x33,0xc7, - 0x3a,0x54,0xec,0x92,0xc1,0x25,0xad,0x49,0x80,0x6b,0xd6,0xf8,0x0f,0xbe,0x7c,0x11]) - -Fox = SBox([ - 0x5D,0xDE,0x00,0xB7,0xD3,0xCA,0x3C,0x0D,0xC3,0xF8,0xCB,0x8D,0x76,0x89,0xAA,0x12, - 0x88,0x22,0x4F,0xDB,0x6D,0x47,0xE4,0x4C,0x78,0x9A,0x49,0x93,0xC4,0xC0,0x86,0x13, - 0xA9,0x20,0x53,0x1C,0x4E,0xCF,0x35,0x39,0xB4,0xA1,0x54,0x64,0x03,0xC7,0x85,0x5C, - 0x5B,0xCD,0xD8,0x72,0x96,0x42,0xB8,0xE1,0xA2,0x60,0xEF,0xBD,0x02,0xAF,0x8C,0x73, - 0x7C,0x7F,0x5E,0xF9,0x65,0xE6,0xEB,0xAD,0x5A,0xA5,0x79,0x8E,0x15,0x30,0xEC,0xA4, - 0xC2,0x3E,0xE0,0x74,0x51,0xFB,0x2D,0x6E,0x94,0x4D,0x55,0x34,0xAE,0x52,0x7E,0x9D, - 0x4A,0xF7,0x80,0xF0,0xD0,0x90,0xA7,0xE8,0x9F,0x50,0xD5,0xD1,0x98,0xCC,0xA0,0x17, - 0xF4,0xB6,0xC1,0x28,0x5F,0x26,0x01,0xAB,0x25,0x38,0x82,0x7D,0x48,0xFC,0x1B,0xCE, - 0x3F,0x6B,0xE2,0x67,0x66,0x43,0x59,0x19,0x84,0x3D,0xF5,0x2F,0xC9,0xBC,0xD9,0x95, - 0x29,0x41,0xDA,0x1A,0xB0,0xE9,0x69,0xD2,0x7B,0xD7,0x11,0x9B,0x33,0x8A,0x23,0x09, - 0xD4,0x71,0x44,0x68,0x6F,0xF2,0x0E,0xDF,0x87,0xDC,0x83,0x18,0x6A,0xEE,0x99,0x81, - 0x62,0x36,0x2E,0x7A,0xFE,0x45,0x9C,0x75,0x91,0x0C,0x0F,0xE7,0xF6,0x14,0x63,0x1D, - 0x0B,0x8B,0xB3,0xF3,0xB2,0x3B,0x08,0x4B,0x10,0xA6,0x32,0xB9,0xA8,0x92,0xF1,0x56, - 0xDD,0x21,0xBF,0x04,0xBE,0xD6,0xFD,0x77,0xEA,0x3A,0xC8,0x8F,0x57,0x1E,0xFA,0x2B, - 0x58,0xC5,0x27,0xAC,0xE3,0xED,0x97,0xBB,0x46,0x05,0x40,0x31,0xE5,0x37,0x2C,0x9E, - 0x0A,0xB1,0xB5,0x06,0x6C,0x1F,0xA3,0x2A,0x70,0xFF,0xBA,0x07,0x24,0x16,0xC6,0x61]) - -Iceberg = SBox([ - 0x24,0xc1,0x38,0x30,0xe7,0x57,0xdf,0x20,0x3e,0x99,0x1a,0x34,0xca,0xd6,0x52,0xfd, - 0x40,0x6c,0xd3,0x3d,0x4a,0x59,0xf8,0x77,0xfb,0x61,0x0a,0x56,0xb9,0xd2,0xfc,0xf1, - 0x07,0xf5,0x93,0xcd,0x00,0xb6,0x62,0xa7,0x63,0xfe,0x44,0xbd,0x5f,0x92,0x6b,0x68, - 0x03,0x4e,0xa2,0x97,0x0b,0x60,0x83,0xa3,0x02,0xe5,0x45,0x67,0xf4,0x13,0x08,0x8b, - 0x10,0xce,0xbe,0xb4,0x2a,0x3a,0x96,0x84,0xc8,0x9f,0x14,0xc0,0xc4,0x6f,0x31,0xd9, - 0xab,0xae,0x0e,0x64,0x7c,0xda,0x1b,0x05,0xa8,0x15,0xa5,0x90,0x94,0x85,0x71,0x2c, - 0x35,0x19,0x26,0x28,0x53,0xe2,0x7f,0x3b,0x2f,0xa9,0xcc,0x2e,0x11,0x76,0xed,0x4d, - 0x87,0x5e,0xc2,0xc7,0x80,0xb0,0x6d,0x17,0xb2,0xff,0xe4,0xb7,0x54,0x9d,0xb8,0x66, - 0x74,0x9c,0xdb,0x36,0x47,0x5d,0xde,0x70,0xd5,0x91,0xaa,0x3f,0xc9,0xd8,0xf3,0xf2, - 0x5b,0x89,0x2d,0x22,0x5c,0xe1,0x46,0x33,0xe6,0x09,0xbc,0xe8,0x81,0x7d,0xe9,0x49, - 0xe0,0xb1,0x32,0x37,0xea,0x5a,0xf6,0x27,0x58,0x69,0x8a,0x50,0xba,0xdd,0x51,0xf9, - 0x75,0xa1,0x78,0xd0,0x43,0xf7,0x25,0x7b,0x7e,0x1c,0xac,0xd4,0x9a,0x2b,0x42,0xe3, - 0x4b,0x01,0x72,0xd7,0x4c,0xfa,0xeb,0x73,0x48,0x8c,0x0c,0xf0,0x6a,0x23,0x41,0xec, - 0xb3,0xef,0x1d,0x12,0xbb,0x88,0x0d,0xc3,0x8d,0x4f,0x55,0x82,0xee,0xad,0x86,0x06, - 0xa0,0x95,0x65,0xbf,0x7a,0x39,0x98,0x04,0x9b,0x9e,0xa4,0xc6,0xcf,0x6e,0xdc,0xd1, - 0xcb,0x1f,0x8f,0x8e,0x3c,0x21,0xa6,0xb5,0x16,0xaf,0xc5,0x18,0x1e,0x0f,0x29,0x79]) - -Iraqi = SBox([ - 173,84,240,67,1,53,254,36,41,172,115,109,223,199,152,189,90,46, - 149,193,218,130,250,40,203,4,35,237,236,246,213,143,169,176,48, - 23,61,206,69,34,97,155,4,109,183,220,42,64,21,123,29,233,253, - 105,183,209,1,191,113,12,46,7,8,183,166,199,166,7,78,37,135, - 252,174,84,140,164,152,94,22,185,59,68,181,60,176,67,51,25,28, - 190,138,198,44,90,92,221,149,175,186,25,49,210,50,237,41,207, - 31,226,114,121,230,15,58,25,142,58,98,232,59,3,189,28,8,116, - 131,185,78,250,239,33,116,173,94,45,104,62,122,179,18,150,246, - 250,17,8,79,157,225,238,47,10,133,58,8,126,82,68,153,141,2,158, - 204,50,130,53,59,32,243,160,172,35,24,107,35,115,228,143,28, - 224,77,55,25,28,120,89,186,152,49,84,117,180,30,138,134,77,182, - 157,61,230,22,149,54,15,110,32,213,155,106,78,16,23,89,140,158, - 169,96,136,186,104,30,199,67,35,218,159,210,109,28,238,33,150, - 173,180,247,201,83,150,105,164,228,59,207,101,221,99,52,120, - 199,31,6,144,202,215,209,49,42,195]) - -iScream = SBox([ - 0x00,0x85,0x65,0xD2,0x5B,0xFF,0x7A,0xCE,0x4D,0xE2,0x2C,0x36,0x92,0x15,0xBD,0xAD, - 0x57,0xF3,0x37,0x2D,0x88,0x0D,0xAC,0xBC,0x18,0x9F,0x7E,0xCA,0x41,0xEE,0x61,0xD6, - 0x59,0xEC,0x78,0xD4,0x47,0xF9,0x26,0xA3,0x90,0x8B,0xBF,0x30,0x0A,0x13,0x6F,0xC0, - 0x2B,0xAE,0x91,0x8A,0xD8,0x74,0x0B,0x12,0xCC,0x63,0xFD,0x43,0xB2,0x3D,0xE8,0x5D, - 0xB6,0x1C,0x83,0x3B,0xC8,0x45,0x9D,0x24,0x52,0xDD,0xE4,0xF4,0xAB,0x08,0x77,0x6D, - 0xF5,0xE5,0x48,0xC5,0x6C,0x76,0xBA,0x10,0x99,0x20,0xA7,0x04,0x87,0x3F,0xD0,0x5F, - 0xA5,0x1E,0x9B,0x39,0xB0,0x02,0xEA,0x67,0xC6,0xDF,0x71,0xF6,0x54,0x4F,0x8D,0x2E, - 0xE7,0x6A,0xC7,0xDE,0x35,0x97,0x55,0x4E,0x22,0x81,0x06,0xB4,0x7C,0xFB,0x1A,0xA1, - 0xD5,0x79,0xFC,0x42,0x84,0x01,0xE9,0x5C,0x14,0x93,0x33,0x29,0xC1,0x6E,0xA8,0xB8, - 0x28,0x32,0x0C,0x89,0xB9,0xA9,0xD9,0x75,0xED,0x58,0xCD,0x62,0xF8,0x46,0x9E,0x19, - 0xCB,0x7F,0xA2,0x27,0xD7,0x60,0xFE,0x5A,0x8E,0x95,0xE3,0x4C,0x16,0x0F,0x31,0xBE, - 0x64,0xD3,0x3C,0xB3,0x7B,0xCF,0x40,0xEF,0x8F,0x94,0x56,0xF2,0x17,0x0E,0xAF,0x2A, - 0x2F,0x8C,0xF1,0xE1,0xDC,0x53,0x68,0x72,0x44,0xC9,0x1B,0xA0,0x38,0x9A,0x07,0xB5, - 0x5E,0xD1,0x03,0xB1,0x23,0x80,0x1F,0xA4,0x34,0x96,0xE0,0xF0,0xC4,0x49,0x73,0x69, - 0xDA,0xC3,0x09,0xAA,0x4A,0x51,0xF7,0x70,0x3E,0x86,0x66,0xEB,0x21,0x98,0x1D,0xB7, - 0xDB,0xC2,0xBB,0x11,0x4B,0x50,0x6B,0xE6,0x9C,0x25,0xFA,0x7D,0x82,0x3A,0xA6,0x05]) - -Kalyna_pi0 = SBox([ - 0xa8,0x43,0x5f,0x6,0x6b,0x75,0x6c,0x59,0x71,0xdf,0x87,0x95,0x17,0xf0,0xd8,0x9, - 0x6d,0xf3,0x1d,0xcb,0xc9,0x4d,0x2c,0xaf,0x79,0xe0,0x97,0xfd,0x6f,0x4b,0x45,0x39, - 0x3e,0xdd,0xa3,0x4f,0xb4,0xb6,0x9a,0xe,0x1f,0xbf,0x15,0xe1,0x49,0xd2,0x93,0xc6, - 0x92,0x72,0x9e,0x61,0xd1,0x63,0xfa,0xee,0xf4,0x19,0xd5,0xad,0x58,0xa4,0xbb,0xa1, - 0xdc,0xf2,0x83,0x37,0x42,0xe4,0x7a,0x32,0x9c,0xcc,0xab,0x4a,0x8f,0x6e,0x4,0x27, - 0x2e,0xe7,0xe2,0x5a,0x96,0x16,0x23,0x2b,0xc2,0x65,0x66,0xf,0xbc,0xa9,0x47,0x41, - 0x34,0x48,0xfc,0xb7,0x6a,0x88,0xa5,0x53,0x86,0xf9,0x5b,0xdb,0x38,0x7b,0xc3,0x1e, - 0x22,0x33,0x24,0x28,0x36,0xc7,0xb2,0x3b,0x8e,0x77,0xba,0xf5,0x14,0x9f,0x8,0x55, - 0x9b,0x4c,0xfe,0x60,0x5c,0xda,0x18,0x46,0xcd,0x7d,0x21,0xb0,0x3f,0x1b,0x89,0xff, - 0xeb,0x84,0x69,0x3a,0x9d,0xd7,0xd3,0x70,0x67,0x40,0xb5,0xde,0x5d,0x30,0x91,0xb1, - 0x78,0x11,0x1,0xe5,0x0,0x68,0x98,0xa0,0xc5,0x2,0xa6,0x74,0x2d,0xb,0xa2,0x76, - 0xb3,0xbe,0xce,0xbd,0xae,0xe9,0x8a,0x31,0x1c,0xec,0xf1,0x99,0x94,0xaa,0xf6,0x26, - 0x2f,0xef,0xe8,0x8c,0x35,0x3,0xd4,0x7f,0xfb,0x5,0xc1,0x5e,0x90,0x20,0x3d,0x82, - 0xf7,0xea,0xa,0xd,0x7e,0xf8,0x50,0x1a,0xc4,0x7,0x57,0xb8,0x3c,0x62,0xe3,0xc8, - 0xac,0x52,0x64,0x10,0xd0,0xd9,0x13,0xc,0x12,0x29,0x51,0xb9,0xcf,0xd6,0x73,0x8d, - 0x81,0x54,0xc0,0xed,0x4e,0x44,0xa7,0x2a,0x85,0x25,0xe6,0xca,0x7c,0x8b,0x56,0x80]) - -Kalyna_pi1 = SBox([ - 0xce,0xbb,0xeb,0x92,0xea,0xcb,0x13,0xc1,0xe9,0x3a,0xd6,0xb2,0xd2,0x90,0x17,0xf8, - 0x42,0x15,0x56,0xb4,0x65,0x1c,0x88,0x43,0xc5,0x5c,0x36,0xba,0xf5,0x57,0x67,0x8d, - 0x31,0xf6,0x64,0x58,0x9e,0xf4,0x22,0xaa,0x75,0xf,0x2,0xb1,0xdf,0x6d,0x73,0x4d, - 0x7c,0x26,0x2e,0xf7,0x8,0x5d,0x44,0x3e,0x9f,0x14,0xc8,0xae,0x54,0x10,0xd8,0xbc, - 0x1a,0x6b,0x69,0xf3,0xbd,0x33,0xab,0xfa,0xd1,0x9b,0x68,0x4e,0x16,0x95,0x91,0xee, - 0x4c,0x63,0x8e,0x5b,0xcc,0x3c,0x19,0xa1,0x81,0x49,0x7b,0xd9,0x6f,0x37,0x60,0xca, - 0xe7,0x2b,0x48,0xfd,0x96,0x45,0xfc,0x41,0x12,0xd,0x79,0xe5,0x89,0x8c,0xe3,0x20, - 0x30,0xdc,0xb7,0x6c,0x4a,0xb5,0x3f,0x97,0xd4,0x62,0x2d,0x6,0xa4,0xa5,0x83,0x5f, - 0x2a,0xda,0xc9,0x0,0x7e,0xa2,0x55,0xbf,0x11,0xd5,0x9c,0xcf,0xe,0xa,0x3d,0x51, - 0x7d,0x93,0x1b,0xfe,0xc4,0x47,0x9,0x86,0xb,0x8f,0x9d,0x6a,0x7,0xb9,0xb0,0x98, - 0x18,0x32,0x71,0x4b,0xef,0x3b,0x70,0xa0,0xe4,0x40,0xff,0xc3,0xa9,0xe6,0x78,0xf9, - 0x8b,0x46,0x80,0x1e,0x38,0xe1,0xb8,0xa8,0xe0,0xc,0x23,0x76,0x1d,0x25,0x24,0x5, - 0xf1,0x6e,0x94,0x28,0x9a,0x84,0xe8,0xa3,0x4f,0x77,0xd3,0x85,0xe2,0x52,0xf2,0x82, - 0x50,0x7a,0x2f,0x74,0x53,0xb3,0x61,0xaf,0x39,0x35,0xde,0xcd,0x1f,0x99,0xac,0xad, - 0x72,0x2c,0xdd,0xd0,0x87,0xbe,0x5e,0xa6,0xec,0x4,0xc6,0x3,0x34,0xfb,0xdb,0x59, - 0xb6,0xc2,0x1,0xf0,0x5a,0xed,0xa7,0x66,0x21,0x7f,0x8a,0x27,0xc7,0xc0,0x29,0xd7]) - -Kalyna_pi2 = SBox([ - 0x93,0xd9,0x9a,0xb5,0x98,0x22,0x45,0xfc,0xba,0x6a,0xdf,0x2,0x9f,0xdc,0x51,0x59, - 0x4a,0x17,0x2b,0xc2,0x94,0xf4,0xbb,0xa3,0x62,0xe4,0x71,0xd4,0xcd,0x70,0x16,0xe1, - 0x49,0x3c,0xc0,0xd8,0x5c,0x9b,0xad,0x85,0x53,0xa1,0x7a,0xc8,0x2d,0xe0,0xd1,0x72, - 0xa6,0x2c,0xc4,0xe3,0x76,0x78,0xb7,0xb4,0x9,0x3b,0xe,0x41,0x4c,0xde,0xb2,0x90, - 0x25,0xa5,0xd7,0x3,0x11,0x0,0xc3,0x2e,0x92,0xef,0x4e,0x12,0x9d,0x7d,0xcb,0x35, - 0x10,0xd5,0x4f,0x9e,0x4d,0xa9,0x55,0xc6,0xd0,0x7b,0x18,0x97,0xd3,0x36,0xe6,0x48, - 0x56,0x81,0x8f,0x77,0xcc,0x9c,0xb9,0xe2,0xac,0xb8,0x2f,0x15,0xa4,0x7c,0xda,0x38, - 0x1e,0xb,0x5,0xd6,0x14,0x6e,0x6c,0x7e,0x66,0xfd,0xb1,0xe5,0x60,0xaf,0x5e,0x33, - 0x87,0xc9,0xf0,0x5d,0x6d,0x3f,0x88,0x8d,0xc7,0xf7,0x1d,0xe9,0xec,0xed,0x80,0x29, - 0x27,0xcf,0x99,0xa8,0x50,0xf,0x37,0x24,0x28,0x30,0x95,0xd2,0x3e,0x5b,0x40,0x83, - 0xb3,0x69,0x57,0x1f,0x7,0x1c,0x8a,0xbc,0x20,0xeb,0xce,0x8e,0xab,0xee,0x31,0xa2, - 0x73,0xf9,0xca,0x3a,0x1a,0xfb,0xd,0xc1,0xfe,0xfa,0xf2,0x6f,0xbd,0x96,0xdd,0x43, - 0x52,0xb6,0x8,0xf3,0xae,0xbe,0x19,0x89,0x32,0x26,0xb0,0xea,0x4b,0x64,0x84,0x82, - 0x6b,0xf5,0x79,0xbf,0x1,0x5f,0x75,0x63,0x1b,0x23,0x3d,0x68,0x2a,0x65,0xe8,0x91, - 0xf6,0xff,0x13,0x58,0xf1,0x47,0xa,0x7f,0xc5,0xa7,0xe7,0x61,0x5a,0x6,0x46,0x44, - 0x42,0x4,0xa0,0xdb,0x39,0x86,0x54,0xaa,0x8c,0x34,0x21,0x8b,0xf8,0xc,0x74,0x67]) - -Kalyna_pi3 = SBox([ - 0x68,0x8d,0xca,0x4d,0x73,0x4b,0x4e,0x2a,0xd4,0x52,0x26,0xb3,0x54,0x1e,0x19,0x1f, - 0x22,0x3,0x46,0x3d,0x2d,0x4a,0x53,0x83,0x13,0x8a,0xb7,0xd5,0x25,0x79,0xf5,0xbd, - 0x58,0x2f,0xd,0x2,0xed,0x51,0x9e,0x11,0xf2,0x3e,0x55,0x5e,0xd1,0x16,0x3c,0x66, - 0x70,0x5d,0xf3,0x45,0x40,0xcc,0xe8,0x94,0x56,0x8,0xce,0x1a,0x3a,0xd2,0xe1,0xdf, - 0xb5,0x38,0x6e,0xe,0xe5,0xf4,0xf9,0x86,0xe9,0x4f,0xd6,0x85,0x23,0xcf,0x32,0x99, - 0x31,0x14,0xae,0xee,0xc8,0x48,0xd3,0x30,0xa1,0x92,0x41,0xb1,0x18,0xc4,0x2c,0x71, - 0x72,0x44,0x15,0xfd,0x37,0xbe,0x5f,0xaa,0x9b,0x88,0xd8,0xab,0x89,0x9c,0xfa,0x60, - 0xea,0xbc,0x62,0xc,0x24,0xa6,0xa8,0xec,0x67,0x20,0xdb,0x7c,0x28,0xdd,0xac,0x5b, - 0x34,0x7e,0x10,0xf1,0x7b,0x8f,0x63,0xa0,0x5,0x9a,0x43,0x77,0x21,0xbf,0x27,0x9, - 0xc3,0x9f,0xb6,0xd7,0x29,0xc2,0xeb,0xc0,0xa4,0x8b,0x8c,0x1d,0xfb,0xff,0xc1,0xb2, - 0x97,0x2e,0xf8,0x65,0xf6,0x75,0x7,0x4,0x49,0x33,0xe4,0xd9,0xb9,0xd0,0x42,0xc7, - 0x6c,0x90,0x0,0x8e,0x6f,0x50,0x1,0xc5,0xda,0x47,0x3f,0xcd,0x69,0xa2,0xe2,0x7a, - 0xa7,0xc6,0x93,0xf,0xa,0x6,0xe6,0x2b,0x96,0xa3,0x1c,0xaf,0x6a,0x12,0x84,0x39, - 0xe7,0xb0,0x82,0xf7,0xfe,0x9d,0x87,0x5c,0x81,0x35,0xde,0xb4,0xa5,0xfc,0x80,0xef, - 0xcb,0xbb,0x6b,0x76,0xba,0x5a,0x7d,0x78,0xb,0x95,0xe3,0xad,0x74,0x98,0x3b,0x36, - 0x64,0x6d,0xdc,0xf0,0x59,0xa9,0x4c,0x17,0x7f,0x91,0xb8,0xc9,0x57,0x1b,0xe0,0x61]) - -Khazad = SBox([ - 0xba,0x54,0x2f,0x74,0x53,0xd3,0xd2,0x4d,0x50,0xac,0x8d,0xbf,0x70,0x52,0x9a,0x4c, - 0xea,0xd5,0x97,0xd1,0x33,0x51,0x5b,0xa6,0xde,0x48,0xa8,0x99,0xdb,0x32,0xb7,0xfc, - 0xe3,0x9e,0x91,0x9b,0xe2,0xbb,0x41,0x6e,0xa5,0xcb,0x6b,0x95,0xa1,0xf3,0xb1,0x02, - 0xcc,0xc4,0x1d,0x14,0xc3,0x63,0xda,0x5d,0x5f,0xdc,0x7d,0xcd,0x7f,0x5a,0x6c,0x5c, - 0xf7,0x26,0xff,0xed,0xe8,0x9d,0x6f,0x8e,0x19,0xa0,0xf0,0x89,0x0f,0x07,0xaf,0xfb, - 0x08,0x15,0x0d,0x04,0x01,0x64,0xdf,0x76,0x79,0xdd,0x3d,0x16,0x3f,0x37,0x6d,0x38, - 0xb9,0x73,0xe9,0x35,0x55,0x71,0x7b,0x8c,0x72,0x88,0xf6,0x2a,0x3e,0x5e,0x27,0x46, - 0x0c,0x65,0x68,0x61,0x03,0xc1,0x57,0xd6,0xd9,0x58,0xd8,0x66,0xd7,0x3a,0xc8,0x3c, - 0xfa,0x96,0xa7,0x98,0xec,0xb8,0xc7,0xae,0x69,0x4b,0xab,0xa9,0x67,0x0a,0x47,0xf2, - 0xb5,0x22,0xe5,0xee,0xbe,0x2b,0x81,0x12,0x83,0x1b,0x0e,0x23,0xf5,0x45,0x21,0xce, - 0x49,0x2c,0xf9,0xe6,0xb6,0x28,0x17,0x82,0x1a,0x8b,0xfe,0x8a,0x09,0xc9,0x87,0x4e, - 0xe1,0x2e,0xe4,0xe0,0xeb,0x90,0xa4,0x1e,0x85,0x60,0x00,0x25,0xf4,0xf1,0x94,0x0b, - 0xe7,0x75,0xef,0x34,0x31,0xd4,0xd0,0x86,0x7e,0xad,0xfd,0x29,0x30,0x3b,0x9f,0xf8, - 0xc6,0x13,0x06,0x05,0xc5,0x11,0x77,0x7c,0x7a,0x78,0x36,0x1c,0x39,0x59,0x18,0x56, - 0xb3,0xb0,0x24,0x20,0xb2,0x92,0xa3,0xc0,0x44,0x62,0x10,0xb4,0x84,0x43,0x93,0xc2, - 0x4a,0xbd,0x8f,0x2d,0xbc,0x9c,0x6a,0x40,0xcf,0xa2,0x80,0x4f,0x1f,0xca,0xaa,0x42]) - -Kuznyechik = SBox([ - 0xFC,0xEE,0xDD,0x11,0xCF,0x6E,0x31,0x16,0xFB,0xC4,0xFA,0xDA,0x23,0xC5,0x04,0x4D, - 0xE9,0x77,0xF0,0xDB,0x93,0x2E,0x99,0xBA,0x17,0x36,0xF1,0xBB,0x14,0xCD,0x5F,0xC1, - 0xF9,0x18,0x65,0x5A,0xE2,0x5C,0xEF,0x21,0x81,0x1C,0x3C,0x42,0x8B,0x01,0x8E,0x4F, - 0x05,0x84,0x02,0xAE,0xE3,0x6A,0x8F,0xA0,0x06,0x0B,0xED,0x98,0x7F,0xD4,0xD3,0x1F, - 0xEB,0x34,0x2C,0x51,0xEA,0xC8,0x48,0xAB,0xF2,0x2A,0x68,0xA2,0xFD,0x3A,0xCE,0xCC, - 0xB5,0x70,0x0E,0x56,0x08,0x0C,0x76,0x12,0xBF,0x72,0x13,0x47,0x9C,0xB7,0x5D,0x87, - 0x15,0xA1,0x96,0x29,0x10,0x7B,0x9A,0xC7,0xF3,0x91,0x78,0x6F,0x9D,0x9E,0xB2,0xB1, - 0x32,0x75,0x19,0x3D,0xFF,0x35,0x8A,0x7E,0x6D,0x54,0xC6,0x80,0xC3,0xBD,0x0D,0x57, - 0xDF,0xF5,0x24,0xA9,0x3E,0xA8,0x43,0xC9,0xD7,0x79,0xD6,0xF6,0x7C,0x22,0xB9,0x03, - 0xE0,0x0F,0xEC,0xDE,0x7A,0x94,0xB0,0xBC,0xDC,0xE8,0x28,0x50,0x4E,0x33,0x0A,0x4A, - 0xA7,0x97,0x60,0x73,0x1E,0x00,0x62,0x44,0x1A,0xB8,0x38,0x82,0x64,0x9F,0x26,0x41, - 0xAD,0x45,0x46,0x92,0x27,0x5E,0x55,0x2F,0x8C,0xA3,0xA5,0x7D,0x69,0xD5,0x95,0x3B, - 0x07,0x58,0xB3,0x40,0x86,0xAC,0x1D,0xF7,0x30,0x37,0x6B,0xE4,0x88,0xD9,0xE7,0x89, - 0xE1,0x1B,0x83,0x49,0x4C,0x3F,0xF8,0xFE,0x8D,0x53,0xAA,0x90,0xCA,0xD8,0x85,0x61, - 0x20,0x71,0x67,0xA4,0x2D,0x2B,0x09,0x5B,0xCB,0x9B,0x25,0xD0,0xBE,0xE5,0x6C,0x52, - 0x59,0xA6,0x74,0xD2,0xE6,0xF4,0xB4,0xC0,0xD1,0x66,0xAF,0xC2,0x39,0x4B,0x63,0xB6]) +CSS = SBox( + [ + 0x33, + 0x73, + 0x3B, + 0x26, + 0x63, + 0x23, + 0x6B, + 0x76, + 0x3E, + 0x7E, + 0x36, + 0x2B, + 0x6E, + 0x2E, + 0x66, + 0x7B, + 0xD3, + 0x93, + 0xDB, + 0x06, + 0x43, + 0x03, + 0x4B, + 0x96, + 0xDE, + 0x9E, + 0xD6, + 0x0B, + 0x4E, + 0x0E, + 0x46, + 0x9B, + 0x57, + 0x17, + 0x5F, + 0x82, + 0xC7, + 0x87, + 0xCF, + 0x12, + 0x5A, + 0x1A, + 0x52, + 0x8F, + 0xCA, + 0x8A, + 0xC2, + 0x1F, + 0xD9, + 0x99, + 0xD1, + 0x00, + 0x49, + 0x09, + 0x41, + 0x90, + 0xD8, + 0x98, + 0xD0, + 0x01, + 0x48, + 0x08, + 0x40, + 0x91, + 0x3D, + 0x7D, + 0x35, + 0x24, + 0x6D, + 0x2D, + 0x65, + 0x74, + 0x3C, + 0x7C, + 0x34, + 0x25, + 0x6C, + 0x2C, + 0x64, + 0x75, + 0xDD, + 0x9D, + 0xD5, + 0x04, + 0x4D, + 0x0D, + 0x45, + 0x94, + 0xDC, + 0x9C, + 0xD4, + 0x05, + 0x4C, + 0x0C, + 0x44, + 0x95, + 0x59, + 0x19, + 0x51, + 0x80, + 0xC9, + 0x89, + 0xC1, + 0x10, + 0x58, + 0x18, + 0x50, + 0x81, + 0xC8, + 0x88, + 0xC0, + 0x11, + 0xD7, + 0x97, + 0xDF, + 0x02, + 0x47, + 0x07, + 0x4F, + 0x92, + 0xDA, + 0x9A, + 0xD2, + 0x0F, + 0x4A, + 0x0A, + 0x42, + 0x9F, + 0x53, + 0x13, + 0x5B, + 0x86, + 0xC3, + 0x83, + 0xCB, + 0x16, + 0x5E, + 0x1E, + 0x56, + 0x8B, + 0xCE, + 0x8E, + 0xC6, + 0x1B, + 0xB3, + 0xF3, + 0xBB, + 0xA6, + 0xE3, + 0xA3, + 0xEB, + 0xF6, + 0xBE, + 0xFE, + 0xB6, + 0xAB, + 0xEE, + 0xAE, + 0xE6, + 0xFB, + 0x37, + 0x77, + 0x3F, + 0x22, + 0x67, + 0x27, + 0x6F, + 0x72, + 0x3A, + 0x7A, + 0x32, + 0x2F, + 0x6A, + 0x2A, + 0x62, + 0x7F, + 0xB9, + 0xF9, + 0xB1, + 0xA0, + 0xE9, + 0xA9, + 0xE1, + 0xF0, + 0xB8, + 0xF8, + 0xB0, + 0xA1, + 0xE8, + 0xA8, + 0xE0, + 0xF1, + 0x5D, + 0x1D, + 0x55, + 0x84, + 0xCD, + 0x8D, + 0xC5, + 0x14, + 0x5C, + 0x1C, + 0x54, + 0x85, + 0xCC, + 0x8C, + 0xC4, + 0x15, + 0xBD, + 0xFD, + 0xB5, + 0xA4, + 0xED, + 0xAD, + 0xE5, + 0xF4, + 0xBC, + 0xFC, + 0xB4, + 0xA5, + 0xEC, + 0xAC, + 0xE4, + 0xF5, + 0x39, + 0x79, + 0x31, + 0x20, + 0x69, + 0x29, + 0x61, + 0x70, + 0x38, + 0x78, + 0x30, + 0x21, + 0x68, + 0x28, + 0x60, + 0x71, + 0xB7, + 0xF7, + 0xBF, + 0xA2, + 0xE7, + 0xA7, + 0xEF, + 0xF2, + 0xBA, + 0xFA, + 0xB2, + 0xAF, + 0xEA, + 0xAA, + 0xE2, + 0xFF, + ] +) + +DBlock = SBox( + [ + 0x51, + 0x36, + 0x93, + 0x53, + 0xD9, + 0x4A, + 0xFC, + 0x58, + 0xE4, + 0x2E, + 0x0D, + 0x14, + 0xDA, + 0x9D, + 0x91, + 0x69, + 0xEF, + 0x72, + 0x03, + 0xC6, + 0x15, + 0x8D, + 0x5C, + 0x62, + 0x3F, + 0xB9, + 0x45, + 0x70, + 0x13, + 0xA3, + 0x95, + 0x6F, + 0x84, + 0xDB, + 0xB8, + 0x89, + 0x8A, + 0x6E, + 0xD4, + 0x7B, + 0x40, + 0xDC, + 0x9B, + 0x0C, + 0x50, + 0x8E, + 0xEE, + 0x6A, + 0x88, + 0x3B, + 0x0F, + 0x6B, + 0x85, + 0xD3, + 0x54, + 0xA8, + 0x20, + 0xDF, + 0xB5, + 0x1B, + 0x32, + 0x7C, + 0x56, + 0x64, + 0x74, + 0xFA, + 0xC7, + 0x2D, + 0x96, + 0x17, + 0xAE, + 0xCD, + 0xB4, + 0xF5, + 0x57, + 0x8C, + 0xF1, + 0xBC, + 0xD8, + 0xFE, + 0x27, + 0x06, + 0xE1, + 0xA9, + 0x1A, + 0x0E, + 0x5B, + 0x08, + 0xF4, + 0x9F, + 0x4B, + 0xED, + 0x73, + 0xB7, + 0xAC, + 0x76, + 0x23, + 0xCA, + 0x16, + 0xBA, + 0xA7, + 0x00, + 0x8B, + 0x46, + 0x41, + 0xD5, + 0x7E, + 0xF2, + 0x05, + 0xF6, + 0x63, + 0x67, + 0x61, + 0x8F, + 0x3D, + 0xC8, + 0x1C, + 0x5A, + 0xB0, + 0x79, + 0x38, + 0x81, + 0xAA, + 0x33, + 0x97, + 0xE6, + 0x2C, + 0x01, + 0x22, + 0x87, + 0x4F, + 0xBE, + 0x24, + 0x71, + 0x35, + 0x9C, + 0xB1, + 0xAD, + 0xC5, + 0x1D, + 0x80, + 0x3E, + 0x75, + 0xB3, + 0x28, + 0x68, + 0x2A, + 0xA0, + 0xBF, + 0x2F, + 0xB2, + 0xC4, + 0xCE, + 0x19, + 0xD7, + 0xCF, + 0xAF, + 0x02, + 0xA4, + 0xA5, + 0x7A, + 0x39, + 0xD2, + 0x04, + 0xAB, + 0xF7, + 0x60, + 0x2B, + 0x4C, + 0xEC, + 0x4D, + 0x10, + 0x90, + 0x12, + 0xFB, + 0x78, + 0x82, + 0x4E, + 0x37, + 0x47, + 0xD6, + 0xA2, + 0xD1, + 0x86, + 0xB6, + 0xC1, + 0xE9, + 0xDD, + 0xA1, + 0xF8, + 0x55, + 0xDE, + 0x98, + 0x7D, + 0xE5, + 0x30, + 0xFD, + 0xE2, + 0xCC, + 0x3A, + 0xEA, + 0xD0, + 0x0A, + 0x29, + 0xE8, + 0xE3, + 0xEB, + 0xF0, + 0x9A, + 0x5D, + 0x3C, + 0x21, + 0xC0, + 0x48, + 0x6D, + 0x1E, + 0xE7, + 0x1F, + 0xC9, + 0x44, + 0x34, + 0x18, + 0x83, + 0xF9, + 0x59, + 0x5F, + 0x42, + 0x92, + 0x6C, + 0x11, + 0xA6, + 0x52, + 0xFF, + 0x9E, + 0x49, + 0x26, + 0x07, + 0x43, + 0xBD, + 0xC3, + 0x99, + 0xF3, + 0x77, + 0x0B, + 0x5E, + 0xCB, + 0x09, + 0x31, + 0xE0, + 0xC2, + 0x65, + 0x7F, + 0x25, + 0x94, + 0xBB, + 0x66, + ] +) + +E2 = SBox( + [ + 0xE1, + 0x42, + 0x3E, + 0x81, + 0x4E, + 0x17, + 0x9E, + 0xFD, + 0xB4, + 0x3F, + 0x2C, + 0xDA, + 0x31, + 0x1E, + 0xE0, + 0x41, + 0xCC, + 0xF3, + 0x82, + 0x7D, + 0x7C, + 0x12, + 0x8E, + 0xBB, + 0xE4, + 0x58, + 0x15, + 0xD5, + 0x6F, + 0xE9, + 0x4C, + 0x4B, + 0x35, + 0x7B, + 0x5A, + 0x9A, + 0x90, + 0x45, + 0xBC, + 0xF8, + 0x79, + 0xD6, + 0x1B, + 0x88, + 0x02, + 0xAB, + 0xCF, + 0x64, + 0x09, + 0x0C, + 0xF0, + 0x01, + 0xA4, + 0xB0, + 0xF6, + 0x93, + 0x43, + 0x63, + 0x86, + 0xDC, + 0x11, + 0xA5, + 0x83, + 0x8B, + 0xC9, + 0xD0, + 0x19, + 0x95, + 0x6A, + 0xA1, + 0x5C, + 0x24, + 0x6E, + 0x50, + 0x21, + 0x80, + 0x2F, + 0xE7, + 0x53, + 0x0F, + 0x91, + 0x22, + 0x04, + 0xED, + 0xA6, + 0x48, + 0x49, + 0x67, + 0xEC, + 0xF7, + 0xC0, + 0x39, + 0xCE, + 0xF2, + 0x2D, + 0xBE, + 0x5D, + 0x1C, + 0xE3, + 0x87, + 0x07, + 0x0D, + 0x7A, + 0xF4, + 0xFB, + 0x32, + 0xF5, + 0x8C, + 0xDB, + 0x8F, + 0x25, + 0x96, + 0xA8, + 0xEA, + 0xCD, + 0x33, + 0x65, + 0x54, + 0x06, + 0x8D, + 0x89, + 0x0A, + 0x5E, + 0xD9, + 0x16, + 0x0E, + 0x71, + 0x6C, + 0x0B, + 0xFF, + 0x60, + 0xD2, + 0x2E, + 0xD3, + 0xC8, + 0x55, + 0xC2, + 0x23, + 0xB7, + 0x74, + 0xE2, + 0x9B, + 0xDF, + 0x77, + 0x2B, + 0xB9, + 0x3C, + 0x62, + 0x13, + 0xE5, + 0x94, + 0x34, + 0xB1, + 0x27, + 0x84, + 0x9F, + 0xD7, + 0x51, + 0x00, + 0x61, + 0xAD, + 0x85, + 0x73, + 0x03, + 0x08, + 0x40, + 0xEF, + 0x68, + 0xFE, + 0x97, + 0x1F, + 0xDE, + 0xAF, + 0x66, + 0xE8, + 0xB8, + 0xAE, + 0xBD, + 0xB3, + 0xEB, + 0xC6, + 0x6B, + 0x47, + 0xA9, + 0xD8, + 0xA7, + 0x72, + 0xEE, + 0x1D, + 0x7E, + 0xAA, + 0xB6, + 0x75, + 0xCB, + 0xD4, + 0x30, + 0x69, + 0x20, + 0x7F, + 0x37, + 0x5B, + 0x9D, + 0x78, + 0xA3, + 0xF1, + 0x76, + 0xFA, + 0x05, + 0x3D, + 0x3A, + 0x44, + 0x57, + 0x3B, + 0xCA, + 0xC7, + 0x8A, + 0x18, + 0x46, + 0x9C, + 0xBF, + 0xBA, + 0x38, + 0x56, + 0x1A, + 0x92, + 0x4D, + 0x26, + 0x29, + 0xA2, + 0x98, + 0x10, + 0x99, + 0x70, + 0xA0, + 0xC5, + 0x28, + 0xC1, + 0x6D, + 0x14, + 0xAC, + 0xF9, + 0x5F, + 0x4F, + 0xC4, + 0xC3, + 0xD1, + 0xFC, + 0xDD, + 0xB2, + 0x59, + 0xE6, + 0xB5, + 0x36, + 0x52, + 0x4A, + 0x2A, + ] +) + +Enocoro = SBox( + [ + 99, + 82, + 26, + 223, + 138, + 246, + 174, + 85, + 137, + 231, + 208, + 45, + 189, + 1, + 36, + 120, + 27, + 217, + 227, + 84, + 200, + 164, + 236, + 126, + 171, + 0, + 156, + 46, + 145, + 103, + 55, + 83, + 78, + 107, + 108, + 17, + 178, + 192, + 130, + 253, + 57, + 69, + 254, + 155, + 52, + 215, + 167, + 8, + 184, + 154, + 51, + 198, + 76, + 29, + 105, + 161, + 110, + 62, + 197, + 10, + 87, + 244, + 241, + 131, + 245, + 71, + 31, + 122, + 165, + 41, + 60, + 66, + 214, + 115, + 141, + 240, + 142, + 24, + 170, + 193, + 32, + 191, + 230, + 147, + 81, + 14, + 247, + 152, + 221, + 186, + 106, + 5, + 72, + 35, + 109, + 212, + 30, + 96, + 117, + 67, + 151, + 42, + 49, + 219, + 132, + 25, + 175, + 188, + 204, + 243, + 232, + 70, + 136, + 172, + 139, + 228, + 123, + 213, + 88, + 54, + 2, + 177, + 7, + 114, + 225, + 220, + 95, + 47, + 93, + 229, + 209, + 12, + 38, + 153, + 181, + 111, + 224, + 74, + 59, + 222, + 162, + 104, + 146, + 23, + 202, + 238, + 169, + 182, + 3, + 94, + 211, + 37, + 251, + 157, + 97, + 89, + 6, + 144, + 116, + 44, + 39, + 149, + 160, + 185, + 124, + 237, + 4, + 210, + 80, + 226, + 73, + 119, + 203, + 58, + 15, + 158, + 112, + 22, + 92, + 239, + 33, + 179, + 159, + 13, + 166, + 201, + 34, + 148, + 250, + 75, + 216, + 101, + 133, + 61, + 150, + 40, + 20, + 91, + 102, + 234, + 127, + 206, + 249, + 64, + 19, + 173, + 195, + 176, + 242, + 194, + 56, + 128, + 207, + 113, + 11, + 135, + 77, + 53, + 86, + 233, + 100, + 190, + 28, + 187, + 183, + 48, + 196, + 43, + 255, + 98, + 65, + 168, + 21, + 140, + 18, + 199, + 121, + 143, + 90, + 252, + 205, + 9, + 79, + 125, + 248, + 134, + 218, + 16, + 50, + 118, + 180, + 163, + 63, + 68, + 129, + 235, + ] +) + +Fantomas = SBox( + [ + 0x1E, + 0x75, + 0x5F, + 0xE1, + 0x99, + 0xFC, + 0x89, + 0x2F, + 0x86, + 0xEE, + 0xF1, + 0x7B, + 0x23, + 0x52, + 0x10, + 0x94, + 0x0C, + 0xB7, + 0x4D, + 0x67, + 0xD8, + 0x42, + 0xC8, + 0xD6, + 0xC4, + 0x6B, + 0xAA, + 0xBA, + 0x3D, + 0xA5, + 0x00, + 0x33, + 0x53, + 0x2D, + 0x0B, + 0xB8, + 0xDA, + 0xA8, + 0xC5, + 0x6C, + 0xCA, + 0xB6, + 0xA4, + 0x22, + 0x60, + 0x07, + 0x5D, + 0xD7, + 0x4F, + 0xF4, + 0x15, + 0x32, + 0x81, + 0x1B, + 0x9C, + 0x8E, + 0x91, + 0x3F, + 0xE6, + 0xF9, + 0x70, + 0xE9, + 0x43, + 0x7E, + 0x8D, + 0xF3, + 0xCC, + 0x65, + 0x08, + 0x7A, + 0x18, + 0xAB, + 0x16, + 0x6A, + 0x77, + 0xFD, + 0xA7, + 0xC0, + 0x82, + 0x04, + 0x9F, + 0x31, + 0xDE, + 0xE3, + 0x49, + 0xD0, + 0x59, + 0x46, + 0x54, + 0xEF, + 0x2E, + 0x3C, + 0xBB, + 0x21, + 0x92, + 0xB5, + 0x55, + 0x3E, + 0x0F, + 0xA9, + 0xDC, + 0xB9, + 0xC1, + 0x7F, + 0xCE, + 0xA6, + 0xB4, + 0x30, + 0x72, + 0x03, + 0x5B, + 0xD1, + 0x4B, + 0xE4, + 0x13, + 0x20, + 0x85, + 0x1D, + 0x9A, + 0x8A, + 0x97, + 0x2C, + 0xF6, + 0xE8, + 0x62, + 0xF8, + 0x47, + 0x6D, + 0x29, + 0x41, + 0x68, + 0xD5, + 0xAC, + 0xCB, + 0xBE, + 0x1A, + 0xB0, + 0xDB, + 0xC7, + 0x4E, + 0x17, + 0x64, + 0x26, + 0xA0, + 0x39, + 0x83, + 0x78, + 0x51, + 0xED, + 0x76, + 0xFF, + 0xE2, + 0xF2, + 0x5C, + 0x9D, + 0x8F, + 0x0A, + 0x93, + 0x34, + 0x05, + 0x25, + 0x58, + 0x7C, + 0xCD, + 0xAF, + 0xDF, + 0xB3, + 0x19, + 0xBD, + 0xC2, + 0xD2, + 0x56, + 0x14, + 0x71, + 0x2A, + 0xA3, + 0x3A, + 0x80, + 0x61, + 0x44, + 0xF5, + 0x6E, + 0xEB, + 0xFB, + 0xE7, + 0x48, + 0x90, + 0x8C, + 0x06, + 0x9E, + 0x37, + 0x09, + 0x98, + 0xE5, + 0xD9, + 0x73, + 0x1F, + 0x6F, + 0x0D, + 0xBC, + 0x02, + 0x7D, + 0x63, + 0xEA, + 0xB1, + 0xD4, + 0x96, + 0x12, + 0x88, + 0x27, + 0xC9, + 0xF7, + 0x5E, + 0xC6, + 0x4C, + 0x50, + 0x40, + 0xFA, + 0x3B, + 0x2B, + 0xAE, + 0x35, + 0x84, + 0xA1, + 0x01, + 0x69, + 0x5A, + 0xFE, + 0x8B, + 0xEC, + 0x95, + 0x28, + 0x9B, + 0xF0, + 0xE0, + 0x66, + 0x24, + 0x57, + 0x0E, + 0x87, + 0x1C, + 0xB2, + 0x45, + 0x74, + 0xD3, + 0x4A, + 0xCF, + 0xDD, + 0xC3, + 0x79, + 0xA2, + 0xBF, + 0x36, + 0xAD, + 0x11, + 0x38, + ] +) + + +FLY = SBox( + [ + 0x00, + 0x9B, + 0xC2, + 0x15, + 0x5D, + 0x84, + 0x4C, + 0xD1, + 0x67, + 0x38, + 0xEF, + 0xB0, + 0x7E, + 0x2B, + 0xF6, + 0xA3, + 0xB9, + 0xAA, + 0x36, + 0x78, + 0x2F, + 0x6E, + 0xE3, + 0xF7, + 0x12, + 0x5C, + 0x9A, + 0xD4, + 0x89, + 0xCD, + 0x01, + 0x45, + 0x2C, + 0x63, + 0x44, + 0xDE, + 0x02, + 0x96, + 0x39, + 0x70, + 0xBA, + 0xE4, + 0x18, + 0x57, + 0xA1, + 0xF5, + 0x8B, + 0xCE, + 0x51, + 0x87, + 0xED, + 0xFF, + 0xB5, + 0xA8, + 0xCA, + 0x1B, + 0xDF, + 0x90, + 0x6C, + 0x32, + 0x46, + 0x03, + 0x7D, + 0x29, + 0xD5, + 0xF2, + 0x20, + 0x5B, + 0xCC, + 0x31, + 0x04, + 0xBD, + 0xA6, + 0x41, + 0x8E, + 0x79, + 0xEA, + 0x9F, + 0x68, + 0x1C, + 0x48, + 0xE6, + 0x69, + 0x8A, + 0x13, + 0x77, + 0x9E, + 0xAF, + 0xF3, + 0x05, + 0xCB, + 0x2D, + 0xB4, + 0xD0, + 0x37, + 0x52, + 0xC4, + 0x3E, + 0x93, + 0xAC, + 0x40, + 0xE9, + 0x22, + 0x56, + 0x7B, + 0x8D, + 0xF1, + 0x06, + 0x17, + 0x62, + 0xBF, + 0xDA, + 0x1D, + 0x7F, + 0x07, + 0xB1, + 0xDB, + 0xFA, + 0x65, + 0x88, + 0x2E, + 0xC9, + 0xA5, + 0x43, + 0x58, + 0x3C, + 0xE0, + 0x94, + 0x76, + 0x21, + 0xAB, + 0xFD, + 0x6A, + 0x3F, + 0xB7, + 0xE2, + 0xDD, + 0x4F, + 0x53, + 0x8C, + 0xC0, + 0x19, + 0x95, + 0x08, + 0x83, + 0xC5, + 0x4E, + 0x09, + 0x14, + 0x50, + 0xD8, + 0x9C, + 0xF4, + 0xEE, + 0x27, + 0x61, + 0x3B, + 0x7A, + 0xA2, + 0xB6, + 0xFE, + 0xA9, + 0x81, + 0xC6, + 0xE8, + 0xBC, + 0x1F, + 0x5A, + 0x35, + 0x72, + 0x99, + 0x0A, + 0xD3, + 0x47, + 0x24, + 0x6D, + 0x0B, + 0x4D, + 0x75, + 0x23, + 0x97, + 0xD2, + 0x60, + 0x34, + 0xC8, + 0x16, + 0xA0, + 0xBB, + 0xFC, + 0xE1, + 0x5E, + 0x8F, + 0xE7, + 0x98, + 0x1A, + 0x64, + 0xAE, + 0x4B, + 0x71, + 0x85, + 0x0C, + 0xB3, + 0x3D, + 0xCF, + 0x55, + 0x28, + 0xD9, + 0xF0, + 0xB2, + 0xDC, + 0x5F, + 0x30, + 0xF9, + 0x0D, + 0x26, + 0xC3, + 0x91, + 0xA7, + 0x74, + 0x1E, + 0x82, + 0x66, + 0x4A, + 0xEB, + 0x6F, + 0x10, + 0xB8, + 0xD7, + 0x86, + 0x73, + 0xFB, + 0x0E, + 0x59, + 0x2A, + 0x42, + 0xE5, + 0x9D, + 0xA4, + 0x33, + 0xC7, + 0x3A, + 0x54, + 0xEC, + 0x92, + 0xC1, + 0x25, + 0xAD, + 0x49, + 0x80, + 0x6B, + 0xD6, + 0xF8, + 0x0F, + 0xBE, + 0x7C, + 0x11, + ] +) + +Fox = SBox( + [ + 0x5D, + 0xDE, + 0x00, + 0xB7, + 0xD3, + 0xCA, + 0x3C, + 0x0D, + 0xC3, + 0xF8, + 0xCB, + 0x8D, + 0x76, + 0x89, + 0xAA, + 0x12, + 0x88, + 0x22, + 0x4F, + 0xDB, + 0x6D, + 0x47, + 0xE4, + 0x4C, + 0x78, + 0x9A, + 0x49, + 0x93, + 0xC4, + 0xC0, + 0x86, + 0x13, + 0xA9, + 0x20, + 0x53, + 0x1C, + 0x4E, + 0xCF, + 0x35, + 0x39, + 0xB4, + 0xA1, + 0x54, + 0x64, + 0x03, + 0xC7, + 0x85, + 0x5C, + 0x5B, + 0xCD, + 0xD8, + 0x72, + 0x96, + 0x42, + 0xB8, + 0xE1, + 0xA2, + 0x60, + 0xEF, + 0xBD, + 0x02, + 0xAF, + 0x8C, + 0x73, + 0x7C, + 0x7F, + 0x5E, + 0xF9, + 0x65, + 0xE6, + 0xEB, + 0xAD, + 0x5A, + 0xA5, + 0x79, + 0x8E, + 0x15, + 0x30, + 0xEC, + 0xA4, + 0xC2, + 0x3E, + 0xE0, + 0x74, + 0x51, + 0xFB, + 0x2D, + 0x6E, + 0x94, + 0x4D, + 0x55, + 0x34, + 0xAE, + 0x52, + 0x7E, + 0x9D, + 0x4A, + 0xF7, + 0x80, + 0xF0, + 0xD0, + 0x90, + 0xA7, + 0xE8, + 0x9F, + 0x50, + 0xD5, + 0xD1, + 0x98, + 0xCC, + 0xA0, + 0x17, + 0xF4, + 0xB6, + 0xC1, + 0x28, + 0x5F, + 0x26, + 0x01, + 0xAB, + 0x25, + 0x38, + 0x82, + 0x7D, + 0x48, + 0xFC, + 0x1B, + 0xCE, + 0x3F, + 0x6B, + 0xE2, + 0x67, + 0x66, + 0x43, + 0x59, + 0x19, + 0x84, + 0x3D, + 0xF5, + 0x2F, + 0xC9, + 0xBC, + 0xD9, + 0x95, + 0x29, + 0x41, + 0xDA, + 0x1A, + 0xB0, + 0xE9, + 0x69, + 0xD2, + 0x7B, + 0xD7, + 0x11, + 0x9B, + 0x33, + 0x8A, + 0x23, + 0x09, + 0xD4, + 0x71, + 0x44, + 0x68, + 0x6F, + 0xF2, + 0x0E, + 0xDF, + 0x87, + 0xDC, + 0x83, + 0x18, + 0x6A, + 0xEE, + 0x99, + 0x81, + 0x62, + 0x36, + 0x2E, + 0x7A, + 0xFE, + 0x45, + 0x9C, + 0x75, + 0x91, + 0x0C, + 0x0F, + 0xE7, + 0xF6, + 0x14, + 0x63, + 0x1D, + 0x0B, + 0x8B, + 0xB3, + 0xF3, + 0xB2, + 0x3B, + 0x08, + 0x4B, + 0x10, + 0xA6, + 0x32, + 0xB9, + 0xA8, + 0x92, + 0xF1, + 0x56, + 0xDD, + 0x21, + 0xBF, + 0x04, + 0xBE, + 0xD6, + 0xFD, + 0x77, + 0xEA, + 0x3A, + 0xC8, + 0x8F, + 0x57, + 0x1E, + 0xFA, + 0x2B, + 0x58, + 0xC5, + 0x27, + 0xAC, + 0xE3, + 0xED, + 0x97, + 0xBB, + 0x46, + 0x05, + 0x40, + 0x31, + 0xE5, + 0x37, + 0x2C, + 0x9E, + 0x0A, + 0xB1, + 0xB5, + 0x06, + 0x6C, + 0x1F, + 0xA3, + 0x2A, + 0x70, + 0xFF, + 0xBA, + 0x07, + 0x24, + 0x16, + 0xC6, + 0x61, + ] +) + +Iceberg = SBox( + [ + 0x24, + 0xC1, + 0x38, + 0x30, + 0xE7, + 0x57, + 0xDF, + 0x20, + 0x3E, + 0x99, + 0x1A, + 0x34, + 0xCA, + 0xD6, + 0x52, + 0xFD, + 0x40, + 0x6C, + 0xD3, + 0x3D, + 0x4A, + 0x59, + 0xF8, + 0x77, + 0xFB, + 0x61, + 0x0A, + 0x56, + 0xB9, + 0xD2, + 0xFC, + 0xF1, + 0x07, + 0xF5, + 0x93, + 0xCD, + 0x00, + 0xB6, + 0x62, + 0xA7, + 0x63, + 0xFE, + 0x44, + 0xBD, + 0x5F, + 0x92, + 0x6B, + 0x68, + 0x03, + 0x4E, + 0xA2, + 0x97, + 0x0B, + 0x60, + 0x83, + 0xA3, + 0x02, + 0xE5, + 0x45, + 0x67, + 0xF4, + 0x13, + 0x08, + 0x8B, + 0x10, + 0xCE, + 0xBE, + 0xB4, + 0x2A, + 0x3A, + 0x96, + 0x84, + 0xC8, + 0x9F, + 0x14, + 0xC0, + 0xC4, + 0x6F, + 0x31, + 0xD9, + 0xAB, + 0xAE, + 0x0E, + 0x64, + 0x7C, + 0xDA, + 0x1B, + 0x05, + 0xA8, + 0x15, + 0xA5, + 0x90, + 0x94, + 0x85, + 0x71, + 0x2C, + 0x35, + 0x19, + 0x26, + 0x28, + 0x53, + 0xE2, + 0x7F, + 0x3B, + 0x2F, + 0xA9, + 0xCC, + 0x2E, + 0x11, + 0x76, + 0xED, + 0x4D, + 0x87, + 0x5E, + 0xC2, + 0xC7, + 0x80, + 0xB0, + 0x6D, + 0x17, + 0xB2, + 0xFF, + 0xE4, + 0xB7, + 0x54, + 0x9D, + 0xB8, + 0x66, + 0x74, + 0x9C, + 0xDB, + 0x36, + 0x47, + 0x5D, + 0xDE, + 0x70, + 0xD5, + 0x91, + 0xAA, + 0x3F, + 0xC9, + 0xD8, + 0xF3, + 0xF2, + 0x5B, + 0x89, + 0x2D, + 0x22, + 0x5C, + 0xE1, + 0x46, + 0x33, + 0xE6, + 0x09, + 0xBC, + 0xE8, + 0x81, + 0x7D, + 0xE9, + 0x49, + 0xE0, + 0xB1, + 0x32, + 0x37, + 0xEA, + 0x5A, + 0xF6, + 0x27, + 0x58, + 0x69, + 0x8A, + 0x50, + 0xBA, + 0xDD, + 0x51, + 0xF9, + 0x75, + 0xA1, + 0x78, + 0xD0, + 0x43, + 0xF7, + 0x25, + 0x7B, + 0x7E, + 0x1C, + 0xAC, + 0xD4, + 0x9A, + 0x2B, + 0x42, + 0xE3, + 0x4B, + 0x01, + 0x72, + 0xD7, + 0x4C, + 0xFA, + 0xEB, + 0x73, + 0x48, + 0x8C, + 0x0C, + 0xF0, + 0x6A, + 0x23, + 0x41, + 0xEC, + 0xB3, + 0xEF, + 0x1D, + 0x12, + 0xBB, + 0x88, + 0x0D, + 0xC3, + 0x8D, + 0x4F, + 0x55, + 0x82, + 0xEE, + 0xAD, + 0x86, + 0x06, + 0xA0, + 0x95, + 0x65, + 0xBF, + 0x7A, + 0x39, + 0x98, + 0x04, + 0x9B, + 0x9E, + 0xA4, + 0xC6, + 0xCF, + 0x6E, + 0xDC, + 0xD1, + 0xCB, + 0x1F, + 0x8F, + 0x8E, + 0x3C, + 0x21, + 0xA6, + 0xB5, + 0x16, + 0xAF, + 0xC5, + 0x18, + 0x1E, + 0x0F, + 0x29, + 0x79, + ] +) + +Iraqi = SBox( + [ + 173, + 84, + 240, + 67, + 1, + 53, + 254, + 36, + 41, + 172, + 115, + 109, + 223, + 199, + 152, + 189, + 90, + 46, + 149, + 193, + 218, + 130, + 250, + 40, + 203, + 4, + 35, + 237, + 236, + 246, + 213, + 143, + 169, + 176, + 48, + 23, + 61, + 206, + 69, + 34, + 97, + 155, + 4, + 109, + 183, + 220, + 42, + 64, + 21, + 123, + 29, + 233, + 253, + 105, + 183, + 209, + 1, + 191, + 113, + 12, + 46, + 7, + 8, + 183, + 166, + 199, + 166, + 7, + 78, + 37, + 135, + 252, + 174, + 84, + 140, + 164, + 152, + 94, + 22, + 185, + 59, + 68, + 181, + 60, + 176, + 67, + 51, + 25, + 28, + 190, + 138, + 198, + 44, + 90, + 92, + 221, + 149, + 175, + 186, + 25, + 49, + 210, + 50, + 237, + 41, + 207, + 31, + 226, + 114, + 121, + 230, + 15, + 58, + 25, + 142, + 58, + 98, + 232, + 59, + 3, + 189, + 28, + 8, + 116, + 131, + 185, + 78, + 250, + 239, + 33, + 116, + 173, + 94, + 45, + 104, + 62, + 122, + 179, + 18, + 150, + 246, + 250, + 17, + 8, + 79, + 157, + 225, + 238, + 47, + 10, + 133, + 58, + 8, + 126, + 82, + 68, + 153, + 141, + 2, + 158, + 204, + 50, + 130, + 53, + 59, + 32, + 243, + 160, + 172, + 35, + 24, + 107, + 35, + 115, + 228, + 143, + 28, + 224, + 77, + 55, + 25, + 28, + 120, + 89, + 186, + 152, + 49, + 84, + 117, + 180, + 30, + 138, + 134, + 77, + 182, + 157, + 61, + 230, + 22, + 149, + 54, + 15, + 110, + 32, + 213, + 155, + 106, + 78, + 16, + 23, + 89, + 140, + 158, + 169, + 96, + 136, + 186, + 104, + 30, + 199, + 67, + 35, + 218, + 159, + 210, + 109, + 28, + 238, + 33, + 150, + 173, + 180, + 247, + 201, + 83, + 150, + 105, + 164, + 228, + 59, + 207, + 101, + 221, + 99, + 52, + 120, + 199, + 31, + 6, + 144, + 202, + 215, + 209, + 49, + 42, + 195, + ] +) + +iScream = SBox( + [ + 0x00, + 0x85, + 0x65, + 0xD2, + 0x5B, + 0xFF, + 0x7A, + 0xCE, + 0x4D, + 0xE2, + 0x2C, + 0x36, + 0x92, + 0x15, + 0xBD, + 0xAD, + 0x57, + 0xF3, + 0x37, + 0x2D, + 0x88, + 0x0D, + 0xAC, + 0xBC, + 0x18, + 0x9F, + 0x7E, + 0xCA, + 0x41, + 0xEE, + 0x61, + 0xD6, + 0x59, + 0xEC, + 0x78, + 0xD4, + 0x47, + 0xF9, + 0x26, + 0xA3, + 0x90, + 0x8B, + 0xBF, + 0x30, + 0x0A, + 0x13, + 0x6F, + 0xC0, + 0x2B, + 0xAE, + 0x91, + 0x8A, + 0xD8, + 0x74, + 0x0B, + 0x12, + 0xCC, + 0x63, + 0xFD, + 0x43, + 0xB2, + 0x3D, + 0xE8, + 0x5D, + 0xB6, + 0x1C, + 0x83, + 0x3B, + 0xC8, + 0x45, + 0x9D, + 0x24, + 0x52, + 0xDD, + 0xE4, + 0xF4, + 0xAB, + 0x08, + 0x77, + 0x6D, + 0xF5, + 0xE5, + 0x48, + 0xC5, + 0x6C, + 0x76, + 0xBA, + 0x10, + 0x99, + 0x20, + 0xA7, + 0x04, + 0x87, + 0x3F, + 0xD0, + 0x5F, + 0xA5, + 0x1E, + 0x9B, + 0x39, + 0xB0, + 0x02, + 0xEA, + 0x67, + 0xC6, + 0xDF, + 0x71, + 0xF6, + 0x54, + 0x4F, + 0x8D, + 0x2E, + 0xE7, + 0x6A, + 0xC7, + 0xDE, + 0x35, + 0x97, + 0x55, + 0x4E, + 0x22, + 0x81, + 0x06, + 0xB4, + 0x7C, + 0xFB, + 0x1A, + 0xA1, + 0xD5, + 0x79, + 0xFC, + 0x42, + 0x84, + 0x01, + 0xE9, + 0x5C, + 0x14, + 0x93, + 0x33, + 0x29, + 0xC1, + 0x6E, + 0xA8, + 0xB8, + 0x28, + 0x32, + 0x0C, + 0x89, + 0xB9, + 0xA9, + 0xD9, + 0x75, + 0xED, + 0x58, + 0xCD, + 0x62, + 0xF8, + 0x46, + 0x9E, + 0x19, + 0xCB, + 0x7F, + 0xA2, + 0x27, + 0xD7, + 0x60, + 0xFE, + 0x5A, + 0x8E, + 0x95, + 0xE3, + 0x4C, + 0x16, + 0x0F, + 0x31, + 0xBE, + 0x64, + 0xD3, + 0x3C, + 0xB3, + 0x7B, + 0xCF, + 0x40, + 0xEF, + 0x8F, + 0x94, + 0x56, + 0xF2, + 0x17, + 0x0E, + 0xAF, + 0x2A, + 0x2F, + 0x8C, + 0xF1, + 0xE1, + 0xDC, + 0x53, + 0x68, + 0x72, + 0x44, + 0xC9, + 0x1B, + 0xA0, + 0x38, + 0x9A, + 0x07, + 0xB5, + 0x5E, + 0xD1, + 0x03, + 0xB1, + 0x23, + 0x80, + 0x1F, + 0xA4, + 0x34, + 0x96, + 0xE0, + 0xF0, + 0xC4, + 0x49, + 0x73, + 0x69, + 0xDA, + 0xC3, + 0x09, + 0xAA, + 0x4A, + 0x51, + 0xF7, + 0x70, + 0x3E, + 0x86, + 0x66, + 0xEB, + 0x21, + 0x98, + 0x1D, + 0xB7, + 0xDB, + 0xC2, + 0xBB, + 0x11, + 0x4B, + 0x50, + 0x6B, + 0xE6, + 0x9C, + 0x25, + 0xFA, + 0x7D, + 0x82, + 0x3A, + 0xA6, + 0x05, + ] +) + +Kalyna_pi0 = SBox( + [ + 0xA8, + 0x43, + 0x5F, + 0x6, + 0x6B, + 0x75, + 0x6C, + 0x59, + 0x71, + 0xDF, + 0x87, + 0x95, + 0x17, + 0xF0, + 0xD8, + 0x9, + 0x6D, + 0xF3, + 0x1D, + 0xCB, + 0xC9, + 0x4D, + 0x2C, + 0xAF, + 0x79, + 0xE0, + 0x97, + 0xFD, + 0x6F, + 0x4B, + 0x45, + 0x39, + 0x3E, + 0xDD, + 0xA3, + 0x4F, + 0xB4, + 0xB6, + 0x9A, + 0xE, + 0x1F, + 0xBF, + 0x15, + 0xE1, + 0x49, + 0xD2, + 0x93, + 0xC6, + 0x92, + 0x72, + 0x9E, + 0x61, + 0xD1, + 0x63, + 0xFA, + 0xEE, + 0xF4, + 0x19, + 0xD5, + 0xAD, + 0x58, + 0xA4, + 0xBB, + 0xA1, + 0xDC, + 0xF2, + 0x83, + 0x37, + 0x42, + 0xE4, + 0x7A, + 0x32, + 0x9C, + 0xCC, + 0xAB, + 0x4A, + 0x8F, + 0x6E, + 0x4, + 0x27, + 0x2E, + 0xE7, + 0xE2, + 0x5A, + 0x96, + 0x16, + 0x23, + 0x2B, + 0xC2, + 0x65, + 0x66, + 0xF, + 0xBC, + 0xA9, + 0x47, + 0x41, + 0x34, + 0x48, + 0xFC, + 0xB7, + 0x6A, + 0x88, + 0xA5, + 0x53, + 0x86, + 0xF9, + 0x5B, + 0xDB, + 0x38, + 0x7B, + 0xC3, + 0x1E, + 0x22, + 0x33, + 0x24, + 0x28, + 0x36, + 0xC7, + 0xB2, + 0x3B, + 0x8E, + 0x77, + 0xBA, + 0xF5, + 0x14, + 0x9F, + 0x8, + 0x55, + 0x9B, + 0x4C, + 0xFE, + 0x60, + 0x5C, + 0xDA, + 0x18, + 0x46, + 0xCD, + 0x7D, + 0x21, + 0xB0, + 0x3F, + 0x1B, + 0x89, + 0xFF, + 0xEB, + 0x84, + 0x69, + 0x3A, + 0x9D, + 0xD7, + 0xD3, + 0x70, + 0x67, + 0x40, + 0xB5, + 0xDE, + 0x5D, + 0x30, + 0x91, + 0xB1, + 0x78, + 0x11, + 0x1, + 0xE5, + 0x0, + 0x68, + 0x98, + 0xA0, + 0xC5, + 0x2, + 0xA6, + 0x74, + 0x2D, + 0xB, + 0xA2, + 0x76, + 0xB3, + 0xBE, + 0xCE, + 0xBD, + 0xAE, + 0xE9, + 0x8A, + 0x31, + 0x1C, + 0xEC, + 0xF1, + 0x99, + 0x94, + 0xAA, + 0xF6, + 0x26, + 0x2F, + 0xEF, + 0xE8, + 0x8C, + 0x35, + 0x3, + 0xD4, + 0x7F, + 0xFB, + 0x5, + 0xC1, + 0x5E, + 0x90, + 0x20, + 0x3D, + 0x82, + 0xF7, + 0xEA, + 0xA, + 0xD, + 0x7E, + 0xF8, + 0x50, + 0x1A, + 0xC4, + 0x7, + 0x57, + 0xB8, + 0x3C, + 0x62, + 0xE3, + 0xC8, + 0xAC, + 0x52, + 0x64, + 0x10, + 0xD0, + 0xD9, + 0x13, + 0xC, + 0x12, + 0x29, + 0x51, + 0xB9, + 0xCF, + 0xD6, + 0x73, + 0x8D, + 0x81, + 0x54, + 0xC0, + 0xED, + 0x4E, + 0x44, + 0xA7, + 0x2A, + 0x85, + 0x25, + 0xE6, + 0xCA, + 0x7C, + 0x8B, + 0x56, + 0x80, + ] +) + +Kalyna_pi1 = SBox( + [ + 0xCE, + 0xBB, + 0xEB, + 0x92, + 0xEA, + 0xCB, + 0x13, + 0xC1, + 0xE9, + 0x3A, + 0xD6, + 0xB2, + 0xD2, + 0x90, + 0x17, + 0xF8, + 0x42, + 0x15, + 0x56, + 0xB4, + 0x65, + 0x1C, + 0x88, + 0x43, + 0xC5, + 0x5C, + 0x36, + 0xBA, + 0xF5, + 0x57, + 0x67, + 0x8D, + 0x31, + 0xF6, + 0x64, + 0x58, + 0x9E, + 0xF4, + 0x22, + 0xAA, + 0x75, + 0xF, + 0x2, + 0xB1, + 0xDF, + 0x6D, + 0x73, + 0x4D, + 0x7C, + 0x26, + 0x2E, + 0xF7, + 0x8, + 0x5D, + 0x44, + 0x3E, + 0x9F, + 0x14, + 0xC8, + 0xAE, + 0x54, + 0x10, + 0xD8, + 0xBC, + 0x1A, + 0x6B, + 0x69, + 0xF3, + 0xBD, + 0x33, + 0xAB, + 0xFA, + 0xD1, + 0x9B, + 0x68, + 0x4E, + 0x16, + 0x95, + 0x91, + 0xEE, + 0x4C, + 0x63, + 0x8E, + 0x5B, + 0xCC, + 0x3C, + 0x19, + 0xA1, + 0x81, + 0x49, + 0x7B, + 0xD9, + 0x6F, + 0x37, + 0x60, + 0xCA, + 0xE7, + 0x2B, + 0x48, + 0xFD, + 0x96, + 0x45, + 0xFC, + 0x41, + 0x12, + 0xD, + 0x79, + 0xE5, + 0x89, + 0x8C, + 0xE3, + 0x20, + 0x30, + 0xDC, + 0xB7, + 0x6C, + 0x4A, + 0xB5, + 0x3F, + 0x97, + 0xD4, + 0x62, + 0x2D, + 0x6, + 0xA4, + 0xA5, + 0x83, + 0x5F, + 0x2A, + 0xDA, + 0xC9, + 0x0, + 0x7E, + 0xA2, + 0x55, + 0xBF, + 0x11, + 0xD5, + 0x9C, + 0xCF, + 0xE, + 0xA, + 0x3D, + 0x51, + 0x7D, + 0x93, + 0x1B, + 0xFE, + 0xC4, + 0x47, + 0x9, + 0x86, + 0xB, + 0x8F, + 0x9D, + 0x6A, + 0x7, + 0xB9, + 0xB0, + 0x98, + 0x18, + 0x32, + 0x71, + 0x4B, + 0xEF, + 0x3B, + 0x70, + 0xA0, + 0xE4, + 0x40, + 0xFF, + 0xC3, + 0xA9, + 0xE6, + 0x78, + 0xF9, + 0x8B, + 0x46, + 0x80, + 0x1E, + 0x38, + 0xE1, + 0xB8, + 0xA8, + 0xE0, + 0xC, + 0x23, + 0x76, + 0x1D, + 0x25, + 0x24, + 0x5, + 0xF1, + 0x6E, + 0x94, + 0x28, + 0x9A, + 0x84, + 0xE8, + 0xA3, + 0x4F, + 0x77, + 0xD3, + 0x85, + 0xE2, + 0x52, + 0xF2, + 0x82, + 0x50, + 0x7A, + 0x2F, + 0x74, + 0x53, + 0xB3, + 0x61, + 0xAF, + 0x39, + 0x35, + 0xDE, + 0xCD, + 0x1F, + 0x99, + 0xAC, + 0xAD, + 0x72, + 0x2C, + 0xDD, + 0xD0, + 0x87, + 0xBE, + 0x5E, + 0xA6, + 0xEC, + 0x4, + 0xC6, + 0x3, + 0x34, + 0xFB, + 0xDB, + 0x59, + 0xB6, + 0xC2, + 0x1, + 0xF0, + 0x5A, + 0xED, + 0xA7, + 0x66, + 0x21, + 0x7F, + 0x8A, + 0x27, + 0xC7, + 0xC0, + 0x29, + 0xD7, + ] +) + +Kalyna_pi2 = SBox( + [ + 0x93, + 0xD9, + 0x9A, + 0xB5, + 0x98, + 0x22, + 0x45, + 0xFC, + 0xBA, + 0x6A, + 0xDF, + 0x2, + 0x9F, + 0xDC, + 0x51, + 0x59, + 0x4A, + 0x17, + 0x2B, + 0xC2, + 0x94, + 0xF4, + 0xBB, + 0xA3, + 0x62, + 0xE4, + 0x71, + 0xD4, + 0xCD, + 0x70, + 0x16, + 0xE1, + 0x49, + 0x3C, + 0xC0, + 0xD8, + 0x5C, + 0x9B, + 0xAD, + 0x85, + 0x53, + 0xA1, + 0x7A, + 0xC8, + 0x2D, + 0xE0, + 0xD1, + 0x72, + 0xA6, + 0x2C, + 0xC4, + 0xE3, + 0x76, + 0x78, + 0xB7, + 0xB4, + 0x9, + 0x3B, + 0xE, + 0x41, + 0x4C, + 0xDE, + 0xB2, + 0x90, + 0x25, + 0xA5, + 0xD7, + 0x3, + 0x11, + 0x0, + 0xC3, + 0x2E, + 0x92, + 0xEF, + 0x4E, + 0x12, + 0x9D, + 0x7D, + 0xCB, + 0x35, + 0x10, + 0xD5, + 0x4F, + 0x9E, + 0x4D, + 0xA9, + 0x55, + 0xC6, + 0xD0, + 0x7B, + 0x18, + 0x97, + 0xD3, + 0x36, + 0xE6, + 0x48, + 0x56, + 0x81, + 0x8F, + 0x77, + 0xCC, + 0x9C, + 0xB9, + 0xE2, + 0xAC, + 0xB8, + 0x2F, + 0x15, + 0xA4, + 0x7C, + 0xDA, + 0x38, + 0x1E, + 0xB, + 0x5, + 0xD6, + 0x14, + 0x6E, + 0x6C, + 0x7E, + 0x66, + 0xFD, + 0xB1, + 0xE5, + 0x60, + 0xAF, + 0x5E, + 0x33, + 0x87, + 0xC9, + 0xF0, + 0x5D, + 0x6D, + 0x3F, + 0x88, + 0x8D, + 0xC7, + 0xF7, + 0x1D, + 0xE9, + 0xEC, + 0xED, + 0x80, + 0x29, + 0x27, + 0xCF, + 0x99, + 0xA8, + 0x50, + 0xF, + 0x37, + 0x24, + 0x28, + 0x30, + 0x95, + 0xD2, + 0x3E, + 0x5B, + 0x40, + 0x83, + 0xB3, + 0x69, + 0x57, + 0x1F, + 0x7, + 0x1C, + 0x8A, + 0xBC, + 0x20, + 0xEB, + 0xCE, + 0x8E, + 0xAB, + 0xEE, + 0x31, + 0xA2, + 0x73, + 0xF9, + 0xCA, + 0x3A, + 0x1A, + 0xFB, + 0xD, + 0xC1, + 0xFE, + 0xFA, + 0xF2, + 0x6F, + 0xBD, + 0x96, + 0xDD, + 0x43, + 0x52, + 0xB6, + 0x8, + 0xF3, + 0xAE, + 0xBE, + 0x19, + 0x89, + 0x32, + 0x26, + 0xB0, + 0xEA, + 0x4B, + 0x64, + 0x84, + 0x82, + 0x6B, + 0xF5, + 0x79, + 0xBF, + 0x1, + 0x5F, + 0x75, + 0x63, + 0x1B, + 0x23, + 0x3D, + 0x68, + 0x2A, + 0x65, + 0xE8, + 0x91, + 0xF6, + 0xFF, + 0x13, + 0x58, + 0xF1, + 0x47, + 0xA, + 0x7F, + 0xC5, + 0xA7, + 0xE7, + 0x61, + 0x5A, + 0x6, + 0x46, + 0x44, + 0x42, + 0x4, + 0xA0, + 0xDB, + 0x39, + 0x86, + 0x54, + 0xAA, + 0x8C, + 0x34, + 0x21, + 0x8B, + 0xF8, + 0xC, + 0x74, + 0x67, + ] +) + +Kalyna_pi3 = SBox( + [ + 0x68, + 0x8D, + 0xCA, + 0x4D, + 0x73, + 0x4B, + 0x4E, + 0x2A, + 0xD4, + 0x52, + 0x26, + 0xB3, + 0x54, + 0x1E, + 0x19, + 0x1F, + 0x22, + 0x3, + 0x46, + 0x3D, + 0x2D, + 0x4A, + 0x53, + 0x83, + 0x13, + 0x8A, + 0xB7, + 0xD5, + 0x25, + 0x79, + 0xF5, + 0xBD, + 0x58, + 0x2F, + 0xD, + 0x2, + 0xED, + 0x51, + 0x9E, + 0x11, + 0xF2, + 0x3E, + 0x55, + 0x5E, + 0xD1, + 0x16, + 0x3C, + 0x66, + 0x70, + 0x5D, + 0xF3, + 0x45, + 0x40, + 0xCC, + 0xE8, + 0x94, + 0x56, + 0x8, + 0xCE, + 0x1A, + 0x3A, + 0xD2, + 0xE1, + 0xDF, + 0xB5, + 0x38, + 0x6E, + 0xE, + 0xE5, + 0xF4, + 0xF9, + 0x86, + 0xE9, + 0x4F, + 0xD6, + 0x85, + 0x23, + 0xCF, + 0x32, + 0x99, + 0x31, + 0x14, + 0xAE, + 0xEE, + 0xC8, + 0x48, + 0xD3, + 0x30, + 0xA1, + 0x92, + 0x41, + 0xB1, + 0x18, + 0xC4, + 0x2C, + 0x71, + 0x72, + 0x44, + 0x15, + 0xFD, + 0x37, + 0xBE, + 0x5F, + 0xAA, + 0x9B, + 0x88, + 0xD8, + 0xAB, + 0x89, + 0x9C, + 0xFA, + 0x60, + 0xEA, + 0xBC, + 0x62, + 0xC, + 0x24, + 0xA6, + 0xA8, + 0xEC, + 0x67, + 0x20, + 0xDB, + 0x7C, + 0x28, + 0xDD, + 0xAC, + 0x5B, + 0x34, + 0x7E, + 0x10, + 0xF1, + 0x7B, + 0x8F, + 0x63, + 0xA0, + 0x5, + 0x9A, + 0x43, + 0x77, + 0x21, + 0xBF, + 0x27, + 0x9, + 0xC3, + 0x9F, + 0xB6, + 0xD7, + 0x29, + 0xC2, + 0xEB, + 0xC0, + 0xA4, + 0x8B, + 0x8C, + 0x1D, + 0xFB, + 0xFF, + 0xC1, + 0xB2, + 0x97, + 0x2E, + 0xF8, + 0x65, + 0xF6, + 0x75, + 0x7, + 0x4, + 0x49, + 0x33, + 0xE4, + 0xD9, + 0xB9, + 0xD0, + 0x42, + 0xC7, + 0x6C, + 0x90, + 0x0, + 0x8E, + 0x6F, + 0x50, + 0x1, + 0xC5, + 0xDA, + 0x47, + 0x3F, + 0xCD, + 0x69, + 0xA2, + 0xE2, + 0x7A, + 0xA7, + 0xC6, + 0x93, + 0xF, + 0xA, + 0x6, + 0xE6, + 0x2B, + 0x96, + 0xA3, + 0x1C, + 0xAF, + 0x6A, + 0x12, + 0x84, + 0x39, + 0xE7, + 0xB0, + 0x82, + 0xF7, + 0xFE, + 0x9D, + 0x87, + 0x5C, + 0x81, + 0x35, + 0xDE, + 0xB4, + 0xA5, + 0xFC, + 0x80, + 0xEF, + 0xCB, + 0xBB, + 0x6B, + 0x76, + 0xBA, + 0x5A, + 0x7D, + 0x78, + 0xB, + 0x95, + 0xE3, + 0xAD, + 0x74, + 0x98, + 0x3B, + 0x36, + 0x64, + 0x6D, + 0xDC, + 0xF0, + 0x59, + 0xA9, + 0x4C, + 0x17, + 0x7F, + 0x91, + 0xB8, + 0xC9, + 0x57, + 0x1B, + 0xE0, + 0x61, + ] +) + +Khazad = SBox( + [ + 0xBA, + 0x54, + 0x2F, + 0x74, + 0x53, + 0xD3, + 0xD2, + 0x4D, + 0x50, + 0xAC, + 0x8D, + 0xBF, + 0x70, + 0x52, + 0x9A, + 0x4C, + 0xEA, + 0xD5, + 0x97, + 0xD1, + 0x33, + 0x51, + 0x5B, + 0xA6, + 0xDE, + 0x48, + 0xA8, + 0x99, + 0xDB, + 0x32, + 0xB7, + 0xFC, + 0xE3, + 0x9E, + 0x91, + 0x9B, + 0xE2, + 0xBB, + 0x41, + 0x6E, + 0xA5, + 0xCB, + 0x6B, + 0x95, + 0xA1, + 0xF3, + 0xB1, + 0x02, + 0xCC, + 0xC4, + 0x1D, + 0x14, + 0xC3, + 0x63, + 0xDA, + 0x5D, + 0x5F, + 0xDC, + 0x7D, + 0xCD, + 0x7F, + 0x5A, + 0x6C, + 0x5C, + 0xF7, + 0x26, + 0xFF, + 0xED, + 0xE8, + 0x9D, + 0x6F, + 0x8E, + 0x19, + 0xA0, + 0xF0, + 0x89, + 0x0F, + 0x07, + 0xAF, + 0xFB, + 0x08, + 0x15, + 0x0D, + 0x04, + 0x01, + 0x64, + 0xDF, + 0x76, + 0x79, + 0xDD, + 0x3D, + 0x16, + 0x3F, + 0x37, + 0x6D, + 0x38, + 0xB9, + 0x73, + 0xE9, + 0x35, + 0x55, + 0x71, + 0x7B, + 0x8C, + 0x72, + 0x88, + 0xF6, + 0x2A, + 0x3E, + 0x5E, + 0x27, + 0x46, + 0x0C, + 0x65, + 0x68, + 0x61, + 0x03, + 0xC1, + 0x57, + 0xD6, + 0xD9, + 0x58, + 0xD8, + 0x66, + 0xD7, + 0x3A, + 0xC8, + 0x3C, + 0xFA, + 0x96, + 0xA7, + 0x98, + 0xEC, + 0xB8, + 0xC7, + 0xAE, + 0x69, + 0x4B, + 0xAB, + 0xA9, + 0x67, + 0x0A, + 0x47, + 0xF2, + 0xB5, + 0x22, + 0xE5, + 0xEE, + 0xBE, + 0x2B, + 0x81, + 0x12, + 0x83, + 0x1B, + 0x0E, + 0x23, + 0xF5, + 0x45, + 0x21, + 0xCE, + 0x49, + 0x2C, + 0xF9, + 0xE6, + 0xB6, + 0x28, + 0x17, + 0x82, + 0x1A, + 0x8B, + 0xFE, + 0x8A, + 0x09, + 0xC9, + 0x87, + 0x4E, + 0xE1, + 0x2E, + 0xE4, + 0xE0, + 0xEB, + 0x90, + 0xA4, + 0x1E, + 0x85, + 0x60, + 0x00, + 0x25, + 0xF4, + 0xF1, + 0x94, + 0x0B, + 0xE7, + 0x75, + 0xEF, + 0x34, + 0x31, + 0xD4, + 0xD0, + 0x86, + 0x7E, + 0xAD, + 0xFD, + 0x29, + 0x30, + 0x3B, + 0x9F, + 0xF8, + 0xC6, + 0x13, + 0x06, + 0x05, + 0xC5, + 0x11, + 0x77, + 0x7C, + 0x7A, + 0x78, + 0x36, + 0x1C, + 0x39, + 0x59, + 0x18, + 0x56, + 0xB3, + 0xB0, + 0x24, + 0x20, + 0xB2, + 0x92, + 0xA3, + 0xC0, + 0x44, + 0x62, + 0x10, + 0xB4, + 0x84, + 0x43, + 0x93, + 0xC2, + 0x4A, + 0xBD, + 0x8F, + 0x2D, + 0xBC, + 0x9C, + 0x6A, + 0x40, + 0xCF, + 0xA2, + 0x80, + 0x4F, + 0x1F, + 0xCA, + 0xAA, + 0x42, + ] +) + +Kuznyechik = SBox( + [ + 0xFC, + 0xEE, + 0xDD, + 0x11, + 0xCF, + 0x6E, + 0x31, + 0x16, + 0xFB, + 0xC4, + 0xFA, + 0xDA, + 0x23, + 0xC5, + 0x04, + 0x4D, + 0xE9, + 0x77, + 0xF0, + 0xDB, + 0x93, + 0x2E, + 0x99, + 0xBA, + 0x17, + 0x36, + 0xF1, + 0xBB, + 0x14, + 0xCD, + 0x5F, + 0xC1, + 0xF9, + 0x18, + 0x65, + 0x5A, + 0xE2, + 0x5C, + 0xEF, + 0x21, + 0x81, + 0x1C, + 0x3C, + 0x42, + 0x8B, + 0x01, + 0x8E, + 0x4F, + 0x05, + 0x84, + 0x02, + 0xAE, + 0xE3, + 0x6A, + 0x8F, + 0xA0, + 0x06, + 0x0B, + 0xED, + 0x98, + 0x7F, + 0xD4, + 0xD3, + 0x1F, + 0xEB, + 0x34, + 0x2C, + 0x51, + 0xEA, + 0xC8, + 0x48, + 0xAB, + 0xF2, + 0x2A, + 0x68, + 0xA2, + 0xFD, + 0x3A, + 0xCE, + 0xCC, + 0xB5, + 0x70, + 0x0E, + 0x56, + 0x08, + 0x0C, + 0x76, + 0x12, + 0xBF, + 0x72, + 0x13, + 0x47, + 0x9C, + 0xB7, + 0x5D, + 0x87, + 0x15, + 0xA1, + 0x96, + 0x29, + 0x10, + 0x7B, + 0x9A, + 0xC7, + 0xF3, + 0x91, + 0x78, + 0x6F, + 0x9D, + 0x9E, + 0xB2, + 0xB1, + 0x32, + 0x75, + 0x19, + 0x3D, + 0xFF, + 0x35, + 0x8A, + 0x7E, + 0x6D, + 0x54, + 0xC6, + 0x80, + 0xC3, + 0xBD, + 0x0D, + 0x57, + 0xDF, + 0xF5, + 0x24, + 0xA9, + 0x3E, + 0xA8, + 0x43, + 0xC9, + 0xD7, + 0x79, + 0xD6, + 0xF6, + 0x7C, + 0x22, + 0xB9, + 0x03, + 0xE0, + 0x0F, + 0xEC, + 0xDE, + 0x7A, + 0x94, + 0xB0, + 0xBC, + 0xDC, + 0xE8, + 0x28, + 0x50, + 0x4E, + 0x33, + 0x0A, + 0x4A, + 0xA7, + 0x97, + 0x60, + 0x73, + 0x1E, + 0x00, + 0x62, + 0x44, + 0x1A, + 0xB8, + 0x38, + 0x82, + 0x64, + 0x9F, + 0x26, + 0x41, + 0xAD, + 0x45, + 0x46, + 0x92, + 0x27, + 0x5E, + 0x55, + 0x2F, + 0x8C, + 0xA3, + 0xA5, + 0x7D, + 0x69, + 0xD5, + 0x95, + 0x3B, + 0x07, + 0x58, + 0xB3, + 0x40, + 0x86, + 0xAC, + 0x1D, + 0xF7, + 0x30, + 0x37, + 0x6B, + 0xE4, + 0x88, + 0xD9, + 0xE7, + 0x89, + 0xE1, + 0x1B, + 0x83, + 0x49, + 0x4C, + 0x3F, + 0xF8, + 0xFE, + 0x8D, + 0x53, + 0xAA, + 0x90, + 0xCA, + 0xD8, + 0x85, + 0x61, + 0x20, + 0x71, + 0x67, + 0xA4, + 0x2D, + 0x2B, + 0x09, + 0x5B, + 0xCB, + 0x9B, + 0x25, + 0xD0, + 0xBE, + 0xE5, + 0x6C, + 0x52, + 0x59, + 0xA6, + 0x74, + 0xD2, + 0xE6, + 0xF4, + 0xB4, + 0xC0, + 0xD1, + 0x66, + 0xAF, + 0xC2, + 0x39, + 0x4B, + 0x63, + 0xB6, + ] +) Kuznechik = Kuznyechik Streebog = Kuznyechik Stribog = Kuznyechik -Lilliput_AE = SBox([ - 0x20, 0x00, 0xB2, 0x85, 0x3B, 0x35, 0xA6, 0xA4, 0x30, 0xE4, 0x6A, 0x2C, 0xFF, 0x59, 0xE2, 0x0E, - 0xF8, 0x1E, 0x7A, 0x80, 0x15, 0xBD, 0x3E, 0xB1, 0xE8, 0xF3, 0xA2, 0xC2, 0xDA, 0x51, 0x2A, 0x10, - 0x21, 0x01, 0x23, 0x78, 0x5C, 0x24, 0x27, 0xB5, 0x37, 0xC7, 0x2B, 0x1F, 0xAE, 0x0A, 0x77, 0x5F, - 0x6F, 0x09, 0x9D, 0x81, 0x04, 0x5A, 0x29, 0xDC, 0x39, 0x9C, 0x05, 0x57, 0x97, 0x74, 0x79, 0x17, - 0x44, 0xC6, 0xE6, 0xE9, 0xDD, 0x41, 0xF2, 0x8A, 0x54, 0xCA, 0x6E, 0x4A, 0xE1, 0xAD, 0xB6, 0x88, - 0x1C, 0x98, 0x7E, 0xCE, 0x63, 0x49, 0x3A, 0x5D, 0x0C, 0xEF, 0xF6, 0x34, 0x56, 0x25, 0x2E, 0xD6, - 0x67, 0x75, 0x55, 0x76, 0xB8, 0xD2, 0x61, 0xD9, 0x71, 0x8B, 0xCD, 0x0B, 0x72, 0x6C, 0x31, 0x4B, - 0x69, 0xFD, 0x7B, 0x6D, 0x60, 0x3C, 0x2F, 0x62, 0x3F, 0x22, 0x73, 0x13, 0xC9, 0x82, 0x7F, 0x53, - 0x32, 0x12, 0xA0, 0x7C, 0x02, 0x87, 0x84, 0x86, 0x93, 0x4E, 0x68, 0x46, 0x8D, 0xC3, 0xDB, 0xEC, - 0x9B, 0xB7, 0x89, 0x92, 0xA7, 0xBE, 0x3D, 0xD8, 0xEA, 0x50, 0x91, 0xF1, 0x33, 0x38, 0xE0, 0xA9, - 0xA3, 0x83, 0xA1, 0x1B, 0xCF, 0x06, 0x95, 0x07, 0x9E, 0xED, 0xB9, 0xF5, 0x4C, 0xC0, 0xF4, 0x2D, - 0x16, 0xFA, 0xB4, 0x03, 0x26, 0xB3, 0x90, 0x4F, 0xAB, 0x65, 0xFC, 0xFE, 0x14, 0xF7, 0xE3, 0x94, - 0xEE, 0xAC, 0x8C, 0x1A, 0xDE, 0xCB, 0x28, 0x40, 0x7D, 0xC8, 0xC4, 0x48, 0x6B, 0xDF, 0xA5, 0x52, - 0xE5, 0xFB, 0xD7, 0x64, 0xF9, 0xF0, 0xD3, 0x5E, 0x66, 0x96, 0x8F, 0x1D, 0x45, 0x36, 0xCC, 0xC5, - 0x4D, 0x9F, 0xBF, 0x0F, 0xD1, 0x08, 0xEB, 0x43, 0x42, 0x19, 0xE7, 0x99, 0xA8, 0x8E, 0x58, 0xC1, - 0x9A, 0xD4, 0x18, 0x47, 0xAA, 0xAF, 0xBC, 0x5B, 0xD5, 0x11, 0xD0, 0xB0, 0x70, 0xBB, 0x0D, 0xBA]) - -#source: https://crypto.stackexchange.com/questions/11935/how-is-the-md2-hash-function-s-table-constructed-from-pi +Lilliput_AE = SBox( + [ + 0x20, + 0x00, + 0xB2, + 0x85, + 0x3B, + 0x35, + 0xA6, + 0xA4, + 0x30, + 0xE4, + 0x6A, + 0x2C, + 0xFF, + 0x59, + 0xE2, + 0x0E, + 0xF8, + 0x1E, + 0x7A, + 0x80, + 0x15, + 0xBD, + 0x3E, + 0xB1, + 0xE8, + 0xF3, + 0xA2, + 0xC2, + 0xDA, + 0x51, + 0x2A, + 0x10, + 0x21, + 0x01, + 0x23, + 0x78, + 0x5C, + 0x24, + 0x27, + 0xB5, + 0x37, + 0xC7, + 0x2B, + 0x1F, + 0xAE, + 0x0A, + 0x77, + 0x5F, + 0x6F, + 0x09, + 0x9D, + 0x81, + 0x04, + 0x5A, + 0x29, + 0xDC, + 0x39, + 0x9C, + 0x05, + 0x57, + 0x97, + 0x74, + 0x79, + 0x17, + 0x44, + 0xC6, + 0xE6, + 0xE9, + 0xDD, + 0x41, + 0xF2, + 0x8A, + 0x54, + 0xCA, + 0x6E, + 0x4A, + 0xE1, + 0xAD, + 0xB6, + 0x88, + 0x1C, + 0x98, + 0x7E, + 0xCE, + 0x63, + 0x49, + 0x3A, + 0x5D, + 0x0C, + 0xEF, + 0xF6, + 0x34, + 0x56, + 0x25, + 0x2E, + 0xD6, + 0x67, + 0x75, + 0x55, + 0x76, + 0xB8, + 0xD2, + 0x61, + 0xD9, + 0x71, + 0x8B, + 0xCD, + 0x0B, + 0x72, + 0x6C, + 0x31, + 0x4B, + 0x69, + 0xFD, + 0x7B, + 0x6D, + 0x60, + 0x3C, + 0x2F, + 0x62, + 0x3F, + 0x22, + 0x73, + 0x13, + 0xC9, + 0x82, + 0x7F, + 0x53, + 0x32, + 0x12, + 0xA0, + 0x7C, + 0x02, + 0x87, + 0x84, + 0x86, + 0x93, + 0x4E, + 0x68, + 0x46, + 0x8D, + 0xC3, + 0xDB, + 0xEC, + 0x9B, + 0xB7, + 0x89, + 0x92, + 0xA7, + 0xBE, + 0x3D, + 0xD8, + 0xEA, + 0x50, + 0x91, + 0xF1, + 0x33, + 0x38, + 0xE0, + 0xA9, + 0xA3, + 0x83, + 0xA1, + 0x1B, + 0xCF, + 0x06, + 0x95, + 0x07, + 0x9E, + 0xED, + 0xB9, + 0xF5, + 0x4C, + 0xC0, + 0xF4, + 0x2D, + 0x16, + 0xFA, + 0xB4, + 0x03, + 0x26, + 0xB3, + 0x90, + 0x4F, + 0xAB, + 0x65, + 0xFC, + 0xFE, + 0x14, + 0xF7, + 0xE3, + 0x94, + 0xEE, + 0xAC, + 0x8C, + 0x1A, + 0xDE, + 0xCB, + 0x28, + 0x40, + 0x7D, + 0xC8, + 0xC4, + 0x48, + 0x6B, + 0xDF, + 0xA5, + 0x52, + 0xE5, + 0xFB, + 0xD7, + 0x64, + 0xF9, + 0xF0, + 0xD3, + 0x5E, + 0x66, + 0x96, + 0x8F, + 0x1D, + 0x45, + 0x36, + 0xCC, + 0xC5, + 0x4D, + 0x9F, + 0xBF, + 0x0F, + 0xD1, + 0x08, + 0xEB, + 0x43, + 0x42, + 0x19, + 0xE7, + 0x99, + 0xA8, + 0x8E, + 0x58, + 0xC1, + 0x9A, + 0xD4, + 0x18, + 0x47, + 0xAA, + 0xAF, + 0xBC, + 0x5B, + 0xD5, + 0x11, + 0xD0, + 0xB0, + 0x70, + 0xBB, + 0x0D, + 0xBA, + ] +) + +# source: https://crypto.stackexchange.com/questions/11935/how-is-the-md2-hash-function-s-table-constructed-from-pi # structure: pseudo-random, derived from the digits of pi -MD2 = SBox([ - 0x29,0x2E,0x43,0xC9,0xA2,0xD8,0x7C,0x01,0x3D,0x36,0x54,0xA1,0xEC,0xF0,0x06,0x13, - 0x62,0xA7,0x05,0xF3,0xC0,0xC7,0x73,0x8C,0x98,0x93,0x2B,0xD9,0xBC,0x4C,0x82,0xCA, - 0x1E,0x9B,0x57,0x3C,0xFD,0xD4,0xE0,0x16,0x67,0x42,0x6F,0x18,0x8A,0x17,0xE5,0x12, - 0xBE,0x4E,0xC4,0xD6,0xDA,0x9E,0xDE,0x49,0xA0,0xFB,0xF5,0x8E,0xBB,0x2F,0xEE,0x7A, - 0xA9,0x68,0x79,0x91,0x15,0xB2,0x07,0x3F,0x94,0xC2,0x10,0x89,0x0B,0x22,0x5F,0x21, - 0x80,0x7F,0x5D,0x9A,0x5A,0x90,0x32,0x27,0x35,0x3E,0xCC,0xE7,0xBF,0xF7,0x97,0x03, - 0xFF,0x19,0x30,0xB3,0x48,0xA5,0xB5,0xD1,0xD7,0x5E,0x92,0x2A,0xAC,0x56,0xAA,0xC6, - 0x4F,0xB8,0x38,0xD2,0x96,0xA4,0x7D,0xB6,0x76,0xFC,0x6B,0xE2,0x9C,0x74,0x04,0xF1, - 0x45,0x9D,0x70,0x59,0x64,0x71,0x87,0x20,0x86,0x5B,0xCF,0x65,0xE6,0x2D,0xA8,0x02, - 0x1B,0x60,0x25,0xAD,0xAE,0xB0,0xB9,0xF6,0x1C,0x46,0x61,0x69,0x34,0x40,0x7E,0x0F, - 0x55,0x47,0xA3,0x23,0xDD,0x51,0xAF,0x3A,0xC3,0x5C,0xF9,0xCE,0xBA,0xC5,0xEA,0x26, - 0x2C,0x53,0x0D,0x6E,0x85,0x28,0x84,0x09,0xD3,0xDF,0xCD,0xF4,0x41,0x81,0x4D,0x52, - 0x6A,0xDC,0x37,0xC8,0x6C,0xC1,0xAB,0xFA,0x24,0xE1,0x7B,0x08,0x0C,0xBD,0xB1,0x4A, - 0x78,0x88,0x95,0x8B,0xE3,0x63,0xE8,0x6D,0xE9,0xCB,0xD5,0xFE,0x3B,0x00,0x1D,0x39, - 0xF2,0xEF,0xB7,0x0E,0x66,0x58,0xD0,0xE4,0xA6,0x77,0x72,0xF8,0xEB,0x75,0x4B,0x0A, - 0x31,0x44,0x50,0xB4,0x8F,0xED,0x1F,0x1A,0xDB,0x99,0x8D,0x33,0x9F,0x11,0x83,0x14]) - -newDES = SBox([ - 32,137,239,188,102,125,221, 72,212, 68, 81, 37, 86,237,147,149, - 70,229, 17,124,115,207, 33, 20,122,143, 25,215, 51,183,138,142, - 146,211,110,173, 1,228,189, 14,103, 78,162, 36,253,167,116,255, - 158, 45,185, 50, 98,168,250,235, 54,141,195,247,240, 63,148, 2, - 224,169,214,180, 62, 22,117,108, 19,172,161,159,160, 47, 43,171, - 194,175,178, 56,196,112, 23,220, 89, 21,164,130,157, 8, 85,251, - 216, 44, 94,179,226, 38, 90,119, 40,202, 34,206, 35, 69,231,246, - 29,109, 74, 71,176, 6, 60,145, 65, 13, 77,151, 12,127, 95,199, - 57,101, 5,232,150,210,129, 24,181, 10,121,187, 48,193,139,252, - 219, 64, 88,233, 96,128, 80, 53,191,144,218, 11,106,132,155,104, - 91,136, 31, 42,243, 66,126,135, 30, 26, 87,186,182,154,242,123, - 82,166,208, 39,152,190,113,205,114,105,225, 84, 73,163, 99,111, - 204, 61,200,217,170, 15,198, 28,192,254,134,234,222, 7,236,248, - 201, 41,177,156, 92,131, 67,249,245,184,203, 9,241, 0, 27, 46, - 133,174, 75, 18, 93,209,100,120, 76,213, 16, 83, 4,107,140, 52, - 58, 55, 3,244, 97,197,238,227,118, 49, 79,230,223,165,153, 59]) - -Picaro = SBox([ - 0x08,0x0c,0x03,0x06,0x06,0x04,0x05,0x06,0x05,0x04,0x0c,0x0c,0x04,0x03,0x05,0x03, - 0x0a,0x1f,0x29,0x3b,0x4b,0x55,0x62,0x7b,0x82,0x95,0xaf,0xbf,0xc5,0xd9,0xe2,0xf9, - 0x01,0x2d,0x45,0x6a,0x8a,0xac,0xcf,0xea,0x9f,0xbc,0xdd,0xfd,0x1c,0x35,0x5f,0x75, - 0x0f,0x34,0x61,0x52,0xc2,0xfb,0xa3,0x92,0x13,0x2b,0x74,0x44,0xdb,0xe1,0xb3,0x81, - 0x0f,0x44,0x81,0xc2,0x92,0xdb,0x13,0x52,0xb3,0xfb,0x34,0x74,0x2b,0x61,0xa3,0xe1, - 0x0e,0x59,0xa4,0xf8,0xd8,0x87,0x7c,0x28,0x3c,0x67,0x99,0xc9,0xe7,0xb4,0x4c,0x14, - 0x02,0x63,0xca,0xad,0x1d,0x71,0xd7,0xbd,0x27,0x41,0xe3,0x83,0x31,0x5a,0xf7,0x9a, - 0x0f,0x74,0xe1,0x92,0x52,0x2b,0xb3,0xc2,0xa3,0xdb,0x44,0x34,0xfb,0x81,0x13,0x61, - 0x02,0x83,0x9a,0x1d,0xbd,0x31,0x27,0xad,0xf7,0x71,0x63,0xe3,0x41,0xca,0xd7,0x5a, - 0x0e,0x99,0xb4,0x28,0xf8,0x67,0x4c,0xd8,0x7c,0xe7,0xc9,0x59,0x87,0x14,0x3c,0xa4, - 0x0a,0xaf,0xd9,0x7b,0x3b,0x95,0xe2,0x4b,0x62,0xc5,0xbf,0x1f,0x55,0xf9,0x82,0x29, - 0x0a,0xbf,0xf9,0x4b,0x7b,0xc5,0x82,0x3b,0xe2,0x55,0x1f,0xaf,0x95,0x29,0x62,0xd9, - 0x0e,0xc9,0x14,0xd8,0x28,0xe7,0x3c,0xf8,0x4c,0x87,0x59,0x99,0x67,0xa4,0x7c,0xb4, - 0x01,0xdd,0x35,0xea,0x6a,0xbc,0x5f,0x8a,0xcf,0x1c,0xfd,0x2d,0xac,0x75,0x9f,0x45, - 0x02,0xe3,0x5a,0xbd,0xad,0x41,0xf7,0x1d,0xd7,0x31,0x83,0x63,0x71,0x9a,0x27,0xca, - 0x01,0xfd,0x75,0x8a,0xea,0x1c,0x9f,0x6a,0x5f,0xac,0x2d,0xdd,0xbc,0x45,0xcf,0x35]) - -Safer = SBox([ - 1, 45, 226, 147, 190, 69, 21, 174, 120, 3, 135, 164, 184, 56, 207, 63, - 8, 103, 9, 148, 235, 38, 168, 107, 189, 24, 52, 27, 187, 191, 114, 247, - 64, 53, 72, 156, 81, 47, 59, 85, 227, 192, 159, 216, 211, 243, 141, 177, - 255, 167, 62, 220, 134, 119, 215, 166, 17, 251, 244, 186, 146, 145, 100, 131, - 241, 51, 239, 218, 44, 181, 178, 43, 136, 209, 153, 203, 140, 132, 29, 20, - 129, 151, 113, 202, 95, 163, 139, 87, 60, 130, 196, 82, 92, 28, 232, 160, - 4, 180, 133, 74, 246, 19, 84, 182, 223, 12, 26, 142, 222, 224, 57, 252, - 32, 155, 36, 78, 169, 152, 158, 171, 242, 96, 208, 108, 234, 250, 199, 217, - 0, 212, 31, 110, 67, 188, 236, 83, 137, 254, 122, 93, 73, 201, 50, 194, - 249, 154, 248, 109, 22, 219, 89, 150, 68, 233, 205, 230, 70, 66, 143, 10, - 193, 204, 185, 101, 176, 210, 198, 172, 30, 65, 98, 41, 46, 14, 116, 80, - 2, 90, 195, 37, 123, 138, 42, 91, 240, 6, 13, 71, 111, 112, 157, 126, - 16, 206, 18, 39, 213, 76, 79, 214, 121, 48, 104, 54, 117, 125, 228, 237, - 128, 106, 144, 55, 162, 94, 118, 170, 197, 127, 61, 175, 165, 229, 25, 97, - 253, 77, 124, 183, 11, 238, 173, 75, 34, 245, 231, 115, 35, 33, 200, 5, - 225, 102, 221, 179, 88, 105, 99, 86, 15, 161, 49, 149, 23, 7, 58, 40]) - -Scream = SBox([ - 0x20,0x8D,0xB2,0xDA,0x33,0x35,0xA6,0xFF,0x7A,0x52,0x6A,0xC6,0xA4,0xA8,0x51,0x23, - 0xA2,0x96,0x30,0xAB,0xC8,0x17,0x14,0x9E,0xE8,0xF3,0xF8,0xDD,0x85,0xE2,0x4B,0xD8, - 0x6C,0x01,0x0E,0x3D,0xB6,0x39,0x4A,0x83,0x6F,0xAA,0x86,0x6E,0x68,0x40,0x98,0x5F, - 0x37,0x13,0x05,0x87,0x04,0x82,0x31,0x89,0x24,0x38,0x9D,0x54,0x22,0x7B,0x63,0xBD, - 0x75,0x2C,0x47,0xE9,0xC2,0x60,0x43,0xAC,0x57,0xA1,0x1F,0x27,0xE7,0xAD,0x5C,0xD2, - 0x0F,0x77,0xFD,0x08,0x79,0x3A,0x49,0x5D,0xED,0x90,0x65,0x7C,0x56,0x4F,0x2E,0x69, - 0xCD,0x44,0x3F,0x62,0x5B,0x88,0x6B,0xC4,0x5E,0x2D,0x67,0x0B,0x9F,0x21,0x29,0x2A, - 0xD6,0x7E,0x74,0xE0,0x41,0x73,0x50,0x76,0x55,0x97,0x3C,0x09,0x7D,0x5A,0x92,0x70, - 0x84,0xB9,0x26,0x34,0x1D,0x81,0x32,0x2B,0x36,0x64,0xAE,0xC0,0x00,0xEE,0x8F,0xA7, - 0xBE,0x58,0xDC,0x7F,0xEC,0x9B,0x78,0x10,0xCC,0x2F,0x94,0xF1,0x3B,0x9C,0x6D,0x16, - 0x48,0xB5,0xCA,0x11,0xFA,0x0D,0x8E,0x07,0xB1,0x0C,0x12,0x28,0x4C,0x46,0xF4,0x8B, - 0xA9,0xCF,0xBB,0x03,0xA0,0xFC,0xEF,0x25,0x80,0xF6,0xB3,0xBA,0x3E,0xF7,0xD5,0x91, - 0xC3,0x8A,0xC1,0x45,0xDE,0x66,0xF5,0x0A,0xC9,0x15,0xD9,0xA3,0x61,0x99,0xB0,0xE4, - 0xD1,0xFB,0xD3,0x4E,0xBF,0xD4,0xD7,0x71,0xCB,0x1E,0xDB,0x02,0x1A,0x93,0xEA,0xC5, - 0xEB,0x72,0xF9,0x1C,0xE5,0xCE,0x4D,0xF2,0x42,0x19,0xE1,0xDF,0x59,0x95,0xB7,0x8C, - 0x9A,0xF0,0x18,0xE6,0xC7,0xAF,0xBC,0xB8,0xE3,0x1B,0xD0,0xA5,0x53,0xB4,0x06,0xFE]) +MD2 = SBox( + [ + 0x29, + 0x2E, + 0x43, + 0xC9, + 0xA2, + 0xD8, + 0x7C, + 0x01, + 0x3D, + 0x36, + 0x54, + 0xA1, + 0xEC, + 0xF0, + 0x06, + 0x13, + 0x62, + 0xA7, + 0x05, + 0xF3, + 0xC0, + 0xC7, + 0x73, + 0x8C, + 0x98, + 0x93, + 0x2B, + 0xD9, + 0xBC, + 0x4C, + 0x82, + 0xCA, + 0x1E, + 0x9B, + 0x57, + 0x3C, + 0xFD, + 0xD4, + 0xE0, + 0x16, + 0x67, + 0x42, + 0x6F, + 0x18, + 0x8A, + 0x17, + 0xE5, + 0x12, + 0xBE, + 0x4E, + 0xC4, + 0xD6, + 0xDA, + 0x9E, + 0xDE, + 0x49, + 0xA0, + 0xFB, + 0xF5, + 0x8E, + 0xBB, + 0x2F, + 0xEE, + 0x7A, + 0xA9, + 0x68, + 0x79, + 0x91, + 0x15, + 0xB2, + 0x07, + 0x3F, + 0x94, + 0xC2, + 0x10, + 0x89, + 0x0B, + 0x22, + 0x5F, + 0x21, + 0x80, + 0x7F, + 0x5D, + 0x9A, + 0x5A, + 0x90, + 0x32, + 0x27, + 0x35, + 0x3E, + 0xCC, + 0xE7, + 0xBF, + 0xF7, + 0x97, + 0x03, + 0xFF, + 0x19, + 0x30, + 0xB3, + 0x48, + 0xA5, + 0xB5, + 0xD1, + 0xD7, + 0x5E, + 0x92, + 0x2A, + 0xAC, + 0x56, + 0xAA, + 0xC6, + 0x4F, + 0xB8, + 0x38, + 0xD2, + 0x96, + 0xA4, + 0x7D, + 0xB6, + 0x76, + 0xFC, + 0x6B, + 0xE2, + 0x9C, + 0x74, + 0x04, + 0xF1, + 0x45, + 0x9D, + 0x70, + 0x59, + 0x64, + 0x71, + 0x87, + 0x20, + 0x86, + 0x5B, + 0xCF, + 0x65, + 0xE6, + 0x2D, + 0xA8, + 0x02, + 0x1B, + 0x60, + 0x25, + 0xAD, + 0xAE, + 0xB0, + 0xB9, + 0xF6, + 0x1C, + 0x46, + 0x61, + 0x69, + 0x34, + 0x40, + 0x7E, + 0x0F, + 0x55, + 0x47, + 0xA3, + 0x23, + 0xDD, + 0x51, + 0xAF, + 0x3A, + 0xC3, + 0x5C, + 0xF9, + 0xCE, + 0xBA, + 0xC5, + 0xEA, + 0x26, + 0x2C, + 0x53, + 0x0D, + 0x6E, + 0x85, + 0x28, + 0x84, + 0x09, + 0xD3, + 0xDF, + 0xCD, + 0xF4, + 0x41, + 0x81, + 0x4D, + 0x52, + 0x6A, + 0xDC, + 0x37, + 0xC8, + 0x6C, + 0xC1, + 0xAB, + 0xFA, + 0x24, + 0xE1, + 0x7B, + 0x08, + 0x0C, + 0xBD, + 0xB1, + 0x4A, + 0x78, + 0x88, + 0x95, + 0x8B, + 0xE3, + 0x63, + 0xE8, + 0x6D, + 0xE9, + 0xCB, + 0xD5, + 0xFE, + 0x3B, + 0x00, + 0x1D, + 0x39, + 0xF2, + 0xEF, + 0xB7, + 0x0E, + 0x66, + 0x58, + 0xD0, + 0xE4, + 0xA6, + 0x77, + 0x72, + 0xF8, + 0xEB, + 0x75, + 0x4B, + 0x0A, + 0x31, + 0x44, + 0x50, + 0xB4, + 0x8F, + 0xED, + 0x1F, + 0x1A, + 0xDB, + 0x99, + 0x8D, + 0x33, + 0x9F, + 0x11, + 0x83, + 0x14, + ] +) + +newDES = SBox( + [ + 32, + 137, + 239, + 188, + 102, + 125, + 221, + 72, + 212, + 68, + 81, + 37, + 86, + 237, + 147, + 149, + 70, + 229, + 17, + 124, + 115, + 207, + 33, + 20, + 122, + 143, + 25, + 215, + 51, + 183, + 138, + 142, + 146, + 211, + 110, + 173, + 1, + 228, + 189, + 14, + 103, + 78, + 162, + 36, + 253, + 167, + 116, + 255, + 158, + 45, + 185, + 50, + 98, + 168, + 250, + 235, + 54, + 141, + 195, + 247, + 240, + 63, + 148, + 2, + 224, + 169, + 214, + 180, + 62, + 22, + 117, + 108, + 19, + 172, + 161, + 159, + 160, + 47, + 43, + 171, + 194, + 175, + 178, + 56, + 196, + 112, + 23, + 220, + 89, + 21, + 164, + 130, + 157, + 8, + 85, + 251, + 216, + 44, + 94, + 179, + 226, + 38, + 90, + 119, + 40, + 202, + 34, + 206, + 35, + 69, + 231, + 246, + 29, + 109, + 74, + 71, + 176, + 6, + 60, + 145, + 65, + 13, + 77, + 151, + 12, + 127, + 95, + 199, + 57, + 101, + 5, + 232, + 150, + 210, + 129, + 24, + 181, + 10, + 121, + 187, + 48, + 193, + 139, + 252, + 219, + 64, + 88, + 233, + 96, + 128, + 80, + 53, + 191, + 144, + 218, + 11, + 106, + 132, + 155, + 104, + 91, + 136, + 31, + 42, + 243, + 66, + 126, + 135, + 30, + 26, + 87, + 186, + 182, + 154, + 242, + 123, + 82, + 166, + 208, + 39, + 152, + 190, + 113, + 205, + 114, + 105, + 225, + 84, + 73, + 163, + 99, + 111, + 204, + 61, + 200, + 217, + 170, + 15, + 198, + 28, + 192, + 254, + 134, + 234, + 222, + 7, + 236, + 248, + 201, + 41, + 177, + 156, + 92, + 131, + 67, + 249, + 245, + 184, + 203, + 9, + 241, + 0, + 27, + 46, + 133, + 174, + 75, + 18, + 93, + 209, + 100, + 120, + 76, + 213, + 16, + 83, + 4, + 107, + 140, + 52, + 58, + 55, + 3, + 244, + 97, + 197, + 238, + 227, + 118, + 49, + 79, + 230, + 223, + 165, + 153, + 59, + ] +) + +Picaro = SBox( + [ + 0x08, + 0x0C, + 0x03, + 0x06, + 0x06, + 0x04, + 0x05, + 0x06, + 0x05, + 0x04, + 0x0C, + 0x0C, + 0x04, + 0x03, + 0x05, + 0x03, + 0x0A, + 0x1F, + 0x29, + 0x3B, + 0x4B, + 0x55, + 0x62, + 0x7B, + 0x82, + 0x95, + 0xAF, + 0xBF, + 0xC5, + 0xD9, + 0xE2, + 0xF9, + 0x01, + 0x2D, + 0x45, + 0x6A, + 0x8A, + 0xAC, + 0xCF, + 0xEA, + 0x9F, + 0xBC, + 0xDD, + 0xFD, + 0x1C, + 0x35, + 0x5F, + 0x75, + 0x0F, + 0x34, + 0x61, + 0x52, + 0xC2, + 0xFB, + 0xA3, + 0x92, + 0x13, + 0x2B, + 0x74, + 0x44, + 0xDB, + 0xE1, + 0xB3, + 0x81, + 0x0F, + 0x44, + 0x81, + 0xC2, + 0x92, + 0xDB, + 0x13, + 0x52, + 0xB3, + 0xFB, + 0x34, + 0x74, + 0x2B, + 0x61, + 0xA3, + 0xE1, + 0x0E, + 0x59, + 0xA4, + 0xF8, + 0xD8, + 0x87, + 0x7C, + 0x28, + 0x3C, + 0x67, + 0x99, + 0xC9, + 0xE7, + 0xB4, + 0x4C, + 0x14, + 0x02, + 0x63, + 0xCA, + 0xAD, + 0x1D, + 0x71, + 0xD7, + 0xBD, + 0x27, + 0x41, + 0xE3, + 0x83, + 0x31, + 0x5A, + 0xF7, + 0x9A, + 0x0F, + 0x74, + 0xE1, + 0x92, + 0x52, + 0x2B, + 0xB3, + 0xC2, + 0xA3, + 0xDB, + 0x44, + 0x34, + 0xFB, + 0x81, + 0x13, + 0x61, + 0x02, + 0x83, + 0x9A, + 0x1D, + 0xBD, + 0x31, + 0x27, + 0xAD, + 0xF7, + 0x71, + 0x63, + 0xE3, + 0x41, + 0xCA, + 0xD7, + 0x5A, + 0x0E, + 0x99, + 0xB4, + 0x28, + 0xF8, + 0x67, + 0x4C, + 0xD8, + 0x7C, + 0xE7, + 0xC9, + 0x59, + 0x87, + 0x14, + 0x3C, + 0xA4, + 0x0A, + 0xAF, + 0xD9, + 0x7B, + 0x3B, + 0x95, + 0xE2, + 0x4B, + 0x62, + 0xC5, + 0xBF, + 0x1F, + 0x55, + 0xF9, + 0x82, + 0x29, + 0x0A, + 0xBF, + 0xF9, + 0x4B, + 0x7B, + 0xC5, + 0x82, + 0x3B, + 0xE2, + 0x55, + 0x1F, + 0xAF, + 0x95, + 0x29, + 0x62, + 0xD9, + 0x0E, + 0xC9, + 0x14, + 0xD8, + 0x28, + 0xE7, + 0x3C, + 0xF8, + 0x4C, + 0x87, + 0x59, + 0x99, + 0x67, + 0xA4, + 0x7C, + 0xB4, + 0x01, + 0xDD, + 0x35, + 0xEA, + 0x6A, + 0xBC, + 0x5F, + 0x8A, + 0xCF, + 0x1C, + 0xFD, + 0x2D, + 0xAC, + 0x75, + 0x9F, + 0x45, + 0x02, + 0xE3, + 0x5A, + 0xBD, + 0xAD, + 0x41, + 0xF7, + 0x1D, + 0xD7, + 0x31, + 0x83, + 0x63, + 0x71, + 0x9A, + 0x27, + 0xCA, + 0x01, + 0xFD, + 0x75, + 0x8A, + 0xEA, + 0x1C, + 0x9F, + 0x6A, + 0x5F, + 0xAC, + 0x2D, + 0xDD, + 0xBC, + 0x45, + 0xCF, + 0x35, + ] +) + +Safer = SBox( + [ + 1, + 45, + 226, + 147, + 190, + 69, + 21, + 174, + 120, + 3, + 135, + 164, + 184, + 56, + 207, + 63, + 8, + 103, + 9, + 148, + 235, + 38, + 168, + 107, + 189, + 24, + 52, + 27, + 187, + 191, + 114, + 247, + 64, + 53, + 72, + 156, + 81, + 47, + 59, + 85, + 227, + 192, + 159, + 216, + 211, + 243, + 141, + 177, + 255, + 167, + 62, + 220, + 134, + 119, + 215, + 166, + 17, + 251, + 244, + 186, + 146, + 145, + 100, + 131, + 241, + 51, + 239, + 218, + 44, + 181, + 178, + 43, + 136, + 209, + 153, + 203, + 140, + 132, + 29, + 20, + 129, + 151, + 113, + 202, + 95, + 163, + 139, + 87, + 60, + 130, + 196, + 82, + 92, + 28, + 232, + 160, + 4, + 180, + 133, + 74, + 246, + 19, + 84, + 182, + 223, + 12, + 26, + 142, + 222, + 224, + 57, + 252, + 32, + 155, + 36, + 78, + 169, + 152, + 158, + 171, + 242, + 96, + 208, + 108, + 234, + 250, + 199, + 217, + 0, + 212, + 31, + 110, + 67, + 188, + 236, + 83, + 137, + 254, + 122, + 93, + 73, + 201, + 50, + 194, + 249, + 154, + 248, + 109, + 22, + 219, + 89, + 150, + 68, + 233, + 205, + 230, + 70, + 66, + 143, + 10, + 193, + 204, + 185, + 101, + 176, + 210, + 198, + 172, + 30, + 65, + 98, + 41, + 46, + 14, + 116, + 80, + 2, + 90, + 195, + 37, + 123, + 138, + 42, + 91, + 240, + 6, + 13, + 71, + 111, + 112, + 157, + 126, + 16, + 206, + 18, + 39, + 213, + 76, + 79, + 214, + 121, + 48, + 104, + 54, + 117, + 125, + 228, + 237, + 128, + 106, + 144, + 55, + 162, + 94, + 118, + 170, + 197, + 127, + 61, + 175, + 165, + 229, + 25, + 97, + 253, + 77, + 124, + 183, + 11, + 238, + 173, + 75, + 34, + 245, + 231, + 115, + 35, + 33, + 200, + 5, + 225, + 102, + 221, + 179, + 88, + 105, + 99, + 86, + 15, + 161, + 49, + 149, + 23, + 7, + 58, + 40, + ] +) + +Scream = SBox( + [ + 0x20, + 0x8D, + 0xB2, + 0xDA, + 0x33, + 0x35, + 0xA6, + 0xFF, + 0x7A, + 0x52, + 0x6A, + 0xC6, + 0xA4, + 0xA8, + 0x51, + 0x23, + 0xA2, + 0x96, + 0x30, + 0xAB, + 0xC8, + 0x17, + 0x14, + 0x9E, + 0xE8, + 0xF3, + 0xF8, + 0xDD, + 0x85, + 0xE2, + 0x4B, + 0xD8, + 0x6C, + 0x01, + 0x0E, + 0x3D, + 0xB6, + 0x39, + 0x4A, + 0x83, + 0x6F, + 0xAA, + 0x86, + 0x6E, + 0x68, + 0x40, + 0x98, + 0x5F, + 0x37, + 0x13, + 0x05, + 0x87, + 0x04, + 0x82, + 0x31, + 0x89, + 0x24, + 0x38, + 0x9D, + 0x54, + 0x22, + 0x7B, + 0x63, + 0xBD, + 0x75, + 0x2C, + 0x47, + 0xE9, + 0xC2, + 0x60, + 0x43, + 0xAC, + 0x57, + 0xA1, + 0x1F, + 0x27, + 0xE7, + 0xAD, + 0x5C, + 0xD2, + 0x0F, + 0x77, + 0xFD, + 0x08, + 0x79, + 0x3A, + 0x49, + 0x5D, + 0xED, + 0x90, + 0x65, + 0x7C, + 0x56, + 0x4F, + 0x2E, + 0x69, + 0xCD, + 0x44, + 0x3F, + 0x62, + 0x5B, + 0x88, + 0x6B, + 0xC4, + 0x5E, + 0x2D, + 0x67, + 0x0B, + 0x9F, + 0x21, + 0x29, + 0x2A, + 0xD6, + 0x7E, + 0x74, + 0xE0, + 0x41, + 0x73, + 0x50, + 0x76, + 0x55, + 0x97, + 0x3C, + 0x09, + 0x7D, + 0x5A, + 0x92, + 0x70, + 0x84, + 0xB9, + 0x26, + 0x34, + 0x1D, + 0x81, + 0x32, + 0x2B, + 0x36, + 0x64, + 0xAE, + 0xC0, + 0x00, + 0xEE, + 0x8F, + 0xA7, + 0xBE, + 0x58, + 0xDC, + 0x7F, + 0xEC, + 0x9B, + 0x78, + 0x10, + 0xCC, + 0x2F, + 0x94, + 0xF1, + 0x3B, + 0x9C, + 0x6D, + 0x16, + 0x48, + 0xB5, + 0xCA, + 0x11, + 0xFA, + 0x0D, + 0x8E, + 0x07, + 0xB1, + 0x0C, + 0x12, + 0x28, + 0x4C, + 0x46, + 0xF4, + 0x8B, + 0xA9, + 0xCF, + 0xBB, + 0x03, + 0xA0, + 0xFC, + 0xEF, + 0x25, + 0x80, + 0xF6, + 0xB3, + 0xBA, + 0x3E, + 0xF7, + 0xD5, + 0x91, + 0xC3, + 0x8A, + 0xC1, + 0x45, + 0xDE, + 0x66, + 0xF5, + 0x0A, + 0xC9, + 0x15, + 0xD9, + 0xA3, + 0x61, + 0x99, + 0xB0, + 0xE4, + 0xD1, + 0xFB, + 0xD3, + 0x4E, + 0xBF, + 0xD4, + 0xD7, + 0x71, + 0xCB, + 0x1E, + 0xDB, + 0x02, + 0x1A, + 0x93, + 0xEA, + 0xC5, + 0xEB, + 0x72, + 0xF9, + 0x1C, + 0xE5, + 0xCE, + 0x4D, + 0xF2, + 0x42, + 0x19, + 0xE1, + 0xDF, + 0x59, + 0x95, + 0xB7, + 0x8C, + 0x9A, + 0xF0, + 0x18, + 0xE6, + 0xC7, + 0xAF, + 0xBC, + 0xB8, + 0xE3, + 0x1B, + 0xD0, + 0xA5, + 0x53, + 0xB4, + 0x06, + 0xFE, + ] +) # Source: https://tools.ietf.org/html/rfc4269 -SEED_S0 = SBox([ - 0xA9,0x85,0xD6,0xD3,0x54,0x1D,0xAC,0x25,0x5D,0x43,0x18,0x1E,0x51,0xFC,0xCA,0x63, - 0x28,0x44,0x20,0x9D,0xE0,0xE2,0xC8,0x17,0xA5,0x8F,0x03,0x7B,0xBB,0x13,0xD2,0xEE, - 0x70,0x8C,0x3F,0xA8,0x32,0xDD,0xF6,0x74,0xEC,0x95,0x0B,0x57,0x5C,0x5B,0xBD,0x01, - 0x24,0x1C,0x73,0x98,0x10,0xCC,0xF2,0xD9,0x2C,0xE7,0x72,0x83,0x9B,0xD1,0x86,0xC9, - 0x60,0x50,0xA3,0xEB,0x0D,0xB6,0x9E,0x4F,0xB7,0x5A,0xC6,0x78,0xA6,0x12,0xAF,0xD5, - 0x61,0xC3,0xB4,0x41,0x52,0x7D,0x8D,0x08,0x1F,0x99,0x00,0x19,0x04,0x53,0xF7,0xE1, - 0xFD,0x76,0x2F,0x27,0xB0,0x8B,0x0E,0xAB,0xA2,0x6E,0x93,0x4D,0x69,0x7C,0x09,0x0A, - 0xBF,0xEF,0xF3,0xC5,0x87,0x14,0xFE,0x64,0xDE,0x2E,0x4B,0x1A,0x06,0x21,0x6B,0x66, - 0x02,0xF5,0x92,0x8A,0x0C,0xB3,0x7E,0xD0,0x7A,0x47,0x96,0xE5,0x26,0x80,0xAD,0xDF, - 0xA1,0x30,0x37,0xAE,0x36,0x15,0x22,0x38,0xF4,0xA7,0x45,0x4C,0x81,0xE9,0x84,0x97, - 0x35,0xCB,0xCE,0x3C,0x71,0x11,0xC7,0x89,0x75,0xFB,0xDA,0xF8,0x94,0x59,0x82,0xC4, - 0xFF,0x49,0x39,0x67,0xC0,0xCF,0xD7,0xB8,0x0F,0x8E,0x42,0x23,0x91,0x6C,0xDB,0xA4, - 0x34,0xF1,0x48,0xC2,0x6F,0x3D,0x2D,0x40,0xBE,0x3E,0xBC,0xC1,0xAA,0xBA,0x4E,0x55, - 0x3B,0xDC,0x68,0x7F,0x9C,0xD8,0x4A,0x56,0x77,0xA0,0xED,0x46,0xB5,0x2B,0x65,0xFA, - 0xE3,0xB9,0xB1,0x9F,0x5E,0xF9,0xE6,0xB2,0x31,0xEA,0x6D,0x5F,0xE4,0xF0,0xCD,0x88, - 0x16,0x3A,0x58,0xD4,0x62,0x29,0x07,0x33,0xE8,0x1B,0x05,0x79,0x90,0x6A,0x2A,0x9A]) - -SEED_S1 = SBox([ - 0x38,0xE8,0x2D,0xA6,0xCF,0xDE,0xB3,0xB8,0xAF,0x60,0x55,0xC7,0x44,0x6F,0x6B,0x5B, - 0xC3,0x62,0x33,0xB5,0x29,0xA0,0xE2,0xA7,0xD3,0x91,0x11,0x06,0x1C,0xBC,0x36,0x4B, - 0xEF,0x88,0x6C,0xA8,0x17,0xC4,0x16,0xF4,0xC2,0x45,0xE1,0xD6,0x3F,0x3D,0x8E,0x98, - 0x28,0x4E,0xF6,0x3E,0xA5,0xF9,0x0D,0xDF,0xD8,0x2B,0x66,0x7A,0x27,0x2F,0xF1,0x72, - 0x42,0xD4,0x41,0xC0,0x73,0x67,0xAC,0x8B,0xF7,0xAD,0x80,0x1F,0xCA,0x2C,0xAA,0x34, - 0xD2,0x0B,0xEE,0xE9,0x5D,0x94,0x18,0xF8,0x57,0xAE,0x08,0xC5,0x13,0xCD,0x86,0xB9, - 0xFF,0x7D,0xC1,0x31,0xF5,0x8A,0x6A,0xB1,0xD1,0x20,0xD7,0x02,0x22,0x04,0x68,0x71, - 0x07,0xDB,0x9D,0x99,0x61,0xBE,0xE6,0x59,0xDD,0x51,0x90,0xDC,0x9A,0xA3,0xAB,0xD0, - 0x81,0x0F,0x47,0x1A,0xE3,0xEC,0x8D,0xBF,0x96,0x7B,0x5C,0xA2,0xA1,0x63,0x23,0x4D, - 0xC8,0x9E,0x9C,0x3A,0x0C,0x2E,0xBA,0x6E,0x9F,0x5A,0xF2,0x92,0xF3,0x49,0x78,0xCC, - 0x15,0xFB,0x70,0x75,0x7F,0x35,0x10,0x03,0x64,0x6D,0xC6,0x74,0xD5,0xB4,0xEA,0x09, - 0x76,0x19,0xFE,0x40,0x12,0xE0,0xBD,0x05,0xFA,0x01,0xF0,0x2A,0x5E,0xA9,0x56,0x43, - 0x85,0x14,0x89,0x9B,0xB0,0xE5,0x48,0x79,0x97,0xFC,0x1E,0x82,0x21,0x8C,0x1B,0x5F, - 0x77,0x54,0xB2,0x1D,0x25,0x4F,0x00,0x46,0xED,0x58,0x52,0xEB,0x7E,0xDA,0xC9,0xFD, - 0x30,0x95,0x65,0x3C,0xB6,0xE4,0xBB,0x7C,0x0E,0x50,0x39,0x26,0x32,0x84,0x69,0x93, - 0x37,0xE7,0x24,0xA4,0xCB,0x53,0x0A,0x87,0xD9,0x4C,0x83,0x8F,0xCE,0x3B,0x4A,0xB7]) - -SKINNY_8 = SBox([ - 0x65,0x4c,0x6a,0x42,0x4b,0x63,0x43,0x6b,0x55,0x75,0x5a,0x7a,0x53,0x73,0x5b,0x7b, - 0x35,0x8c,0x3a,0x81,0x89,0x33,0x80,0x3b,0x95,0x25,0x98,0x2a,0x90,0x23,0x99,0x2b, - 0xe5,0xcc,0xe8,0xc1,0xc9,0xe0,0xc0,0xe9,0xd5,0xf5,0xd8,0xf8,0xd0,0xf0,0xd9,0xf9, - 0xa5,0x1c,0xa8,0x12,0x1b,0xa0,0x13,0xa9,0x05,0xb5,0x0a,0xb8,0x03,0xb0,0x0b,0xb9, - 0x32,0x88,0x3c,0x85,0x8d,0x34,0x84,0x3d,0x91,0x22,0x9c,0x2c,0x94,0x24,0x9d,0x2d, - 0x62,0x4a,0x6c,0x45,0x4d,0x64,0x44,0x6d,0x52,0x72,0x5c,0x7c,0x54,0x74,0x5d,0x7d, - 0xa1,0x1a,0xac,0x15,0x1d,0xa4,0x14,0xad,0x02,0xb1,0x0c,0xbc,0x04,0xb4,0x0d,0xbd, - 0xe1,0xc8,0xec,0xc5,0xcd,0xe4,0xc4,0xed,0xd1,0xf1,0xdc,0xfc,0xd4,0xf4,0xdd,0xfd, - 0x36,0x8e,0x38,0x82,0x8b,0x30,0x83,0x39,0x96,0x26,0x9a,0x28,0x93,0x20,0x9b,0x29, - 0x66,0x4e,0x68,0x41,0x49,0x60,0x40,0x69,0x56,0x76,0x58,0x78,0x50,0x70,0x59,0x79, - 0xa6,0x1e,0xaa,0x11,0x19,0xa3,0x10,0xab,0x06,0xb6,0x08,0xba,0x00,0xb3,0x09,0xbb, - 0xe6,0xce,0xea,0xc2,0xcb,0xe3,0xc3,0xeb,0xd6,0xf6,0xda,0xfa,0xd3,0xf3,0xdb,0xfb, - 0x31,0x8a,0x3e,0x86,0x8f,0x37,0x87,0x3f,0x92,0x21,0x9e,0x2e,0x97,0x27,0x9f,0x2f, - 0x61,0x48,0x6e,0x46,0x4f,0x67,0x47,0x6f,0x51,0x71,0x5e,0x7e,0x57,0x77,0x5f,0x7f, - 0xa2,0x18,0xae,0x16,0x1f,0xa7,0x17,0xaf,0x01,0xb2,0x0e,0xbe,0x07,0xb7,0x0f,0xbf, - 0xe2,0xca,0xee,0xc6,0xcf,0xe7,0xc7,0xef,0xd2,0xf2,0xde,0xfe,0xd7,0xf7,0xdf,0xff]) +SEED_S0 = SBox( + [ + 0xA9, + 0x85, + 0xD6, + 0xD3, + 0x54, + 0x1D, + 0xAC, + 0x25, + 0x5D, + 0x43, + 0x18, + 0x1E, + 0x51, + 0xFC, + 0xCA, + 0x63, + 0x28, + 0x44, + 0x20, + 0x9D, + 0xE0, + 0xE2, + 0xC8, + 0x17, + 0xA5, + 0x8F, + 0x03, + 0x7B, + 0xBB, + 0x13, + 0xD2, + 0xEE, + 0x70, + 0x8C, + 0x3F, + 0xA8, + 0x32, + 0xDD, + 0xF6, + 0x74, + 0xEC, + 0x95, + 0x0B, + 0x57, + 0x5C, + 0x5B, + 0xBD, + 0x01, + 0x24, + 0x1C, + 0x73, + 0x98, + 0x10, + 0xCC, + 0xF2, + 0xD9, + 0x2C, + 0xE7, + 0x72, + 0x83, + 0x9B, + 0xD1, + 0x86, + 0xC9, + 0x60, + 0x50, + 0xA3, + 0xEB, + 0x0D, + 0xB6, + 0x9E, + 0x4F, + 0xB7, + 0x5A, + 0xC6, + 0x78, + 0xA6, + 0x12, + 0xAF, + 0xD5, + 0x61, + 0xC3, + 0xB4, + 0x41, + 0x52, + 0x7D, + 0x8D, + 0x08, + 0x1F, + 0x99, + 0x00, + 0x19, + 0x04, + 0x53, + 0xF7, + 0xE1, + 0xFD, + 0x76, + 0x2F, + 0x27, + 0xB0, + 0x8B, + 0x0E, + 0xAB, + 0xA2, + 0x6E, + 0x93, + 0x4D, + 0x69, + 0x7C, + 0x09, + 0x0A, + 0xBF, + 0xEF, + 0xF3, + 0xC5, + 0x87, + 0x14, + 0xFE, + 0x64, + 0xDE, + 0x2E, + 0x4B, + 0x1A, + 0x06, + 0x21, + 0x6B, + 0x66, + 0x02, + 0xF5, + 0x92, + 0x8A, + 0x0C, + 0xB3, + 0x7E, + 0xD0, + 0x7A, + 0x47, + 0x96, + 0xE5, + 0x26, + 0x80, + 0xAD, + 0xDF, + 0xA1, + 0x30, + 0x37, + 0xAE, + 0x36, + 0x15, + 0x22, + 0x38, + 0xF4, + 0xA7, + 0x45, + 0x4C, + 0x81, + 0xE9, + 0x84, + 0x97, + 0x35, + 0xCB, + 0xCE, + 0x3C, + 0x71, + 0x11, + 0xC7, + 0x89, + 0x75, + 0xFB, + 0xDA, + 0xF8, + 0x94, + 0x59, + 0x82, + 0xC4, + 0xFF, + 0x49, + 0x39, + 0x67, + 0xC0, + 0xCF, + 0xD7, + 0xB8, + 0x0F, + 0x8E, + 0x42, + 0x23, + 0x91, + 0x6C, + 0xDB, + 0xA4, + 0x34, + 0xF1, + 0x48, + 0xC2, + 0x6F, + 0x3D, + 0x2D, + 0x40, + 0xBE, + 0x3E, + 0xBC, + 0xC1, + 0xAA, + 0xBA, + 0x4E, + 0x55, + 0x3B, + 0xDC, + 0x68, + 0x7F, + 0x9C, + 0xD8, + 0x4A, + 0x56, + 0x77, + 0xA0, + 0xED, + 0x46, + 0xB5, + 0x2B, + 0x65, + 0xFA, + 0xE3, + 0xB9, + 0xB1, + 0x9F, + 0x5E, + 0xF9, + 0xE6, + 0xB2, + 0x31, + 0xEA, + 0x6D, + 0x5F, + 0xE4, + 0xF0, + 0xCD, + 0x88, + 0x16, + 0x3A, + 0x58, + 0xD4, + 0x62, + 0x29, + 0x07, + 0x33, + 0xE8, + 0x1B, + 0x05, + 0x79, + 0x90, + 0x6A, + 0x2A, + 0x9A, + ] +) + +SEED_S1 = SBox( + [ + 0x38, + 0xE8, + 0x2D, + 0xA6, + 0xCF, + 0xDE, + 0xB3, + 0xB8, + 0xAF, + 0x60, + 0x55, + 0xC7, + 0x44, + 0x6F, + 0x6B, + 0x5B, + 0xC3, + 0x62, + 0x33, + 0xB5, + 0x29, + 0xA0, + 0xE2, + 0xA7, + 0xD3, + 0x91, + 0x11, + 0x06, + 0x1C, + 0xBC, + 0x36, + 0x4B, + 0xEF, + 0x88, + 0x6C, + 0xA8, + 0x17, + 0xC4, + 0x16, + 0xF4, + 0xC2, + 0x45, + 0xE1, + 0xD6, + 0x3F, + 0x3D, + 0x8E, + 0x98, + 0x28, + 0x4E, + 0xF6, + 0x3E, + 0xA5, + 0xF9, + 0x0D, + 0xDF, + 0xD8, + 0x2B, + 0x66, + 0x7A, + 0x27, + 0x2F, + 0xF1, + 0x72, + 0x42, + 0xD4, + 0x41, + 0xC0, + 0x73, + 0x67, + 0xAC, + 0x8B, + 0xF7, + 0xAD, + 0x80, + 0x1F, + 0xCA, + 0x2C, + 0xAA, + 0x34, + 0xD2, + 0x0B, + 0xEE, + 0xE9, + 0x5D, + 0x94, + 0x18, + 0xF8, + 0x57, + 0xAE, + 0x08, + 0xC5, + 0x13, + 0xCD, + 0x86, + 0xB9, + 0xFF, + 0x7D, + 0xC1, + 0x31, + 0xF5, + 0x8A, + 0x6A, + 0xB1, + 0xD1, + 0x20, + 0xD7, + 0x02, + 0x22, + 0x04, + 0x68, + 0x71, + 0x07, + 0xDB, + 0x9D, + 0x99, + 0x61, + 0xBE, + 0xE6, + 0x59, + 0xDD, + 0x51, + 0x90, + 0xDC, + 0x9A, + 0xA3, + 0xAB, + 0xD0, + 0x81, + 0x0F, + 0x47, + 0x1A, + 0xE3, + 0xEC, + 0x8D, + 0xBF, + 0x96, + 0x7B, + 0x5C, + 0xA2, + 0xA1, + 0x63, + 0x23, + 0x4D, + 0xC8, + 0x9E, + 0x9C, + 0x3A, + 0x0C, + 0x2E, + 0xBA, + 0x6E, + 0x9F, + 0x5A, + 0xF2, + 0x92, + 0xF3, + 0x49, + 0x78, + 0xCC, + 0x15, + 0xFB, + 0x70, + 0x75, + 0x7F, + 0x35, + 0x10, + 0x03, + 0x64, + 0x6D, + 0xC6, + 0x74, + 0xD5, + 0xB4, + 0xEA, + 0x09, + 0x76, + 0x19, + 0xFE, + 0x40, + 0x12, + 0xE0, + 0xBD, + 0x05, + 0xFA, + 0x01, + 0xF0, + 0x2A, + 0x5E, + 0xA9, + 0x56, + 0x43, + 0x85, + 0x14, + 0x89, + 0x9B, + 0xB0, + 0xE5, + 0x48, + 0x79, + 0x97, + 0xFC, + 0x1E, + 0x82, + 0x21, + 0x8C, + 0x1B, + 0x5F, + 0x77, + 0x54, + 0xB2, + 0x1D, + 0x25, + 0x4F, + 0x00, + 0x46, + 0xED, + 0x58, + 0x52, + 0xEB, + 0x7E, + 0xDA, + 0xC9, + 0xFD, + 0x30, + 0x95, + 0x65, + 0x3C, + 0xB6, + 0xE4, + 0xBB, + 0x7C, + 0x0E, + 0x50, + 0x39, + 0x26, + 0x32, + 0x84, + 0x69, + 0x93, + 0x37, + 0xE7, + 0x24, + 0xA4, + 0xCB, + 0x53, + 0x0A, + 0x87, + 0xD9, + 0x4C, + 0x83, + 0x8F, + 0xCE, + 0x3B, + 0x4A, + 0xB7, + ] +) + +SKINNY_8 = SBox( + [ + 0x65, + 0x4C, + 0x6A, + 0x42, + 0x4B, + 0x63, + 0x43, + 0x6B, + 0x55, + 0x75, + 0x5A, + 0x7A, + 0x53, + 0x73, + 0x5B, + 0x7B, + 0x35, + 0x8C, + 0x3A, + 0x81, + 0x89, + 0x33, + 0x80, + 0x3B, + 0x95, + 0x25, + 0x98, + 0x2A, + 0x90, + 0x23, + 0x99, + 0x2B, + 0xE5, + 0xCC, + 0xE8, + 0xC1, + 0xC9, + 0xE0, + 0xC0, + 0xE9, + 0xD5, + 0xF5, + 0xD8, + 0xF8, + 0xD0, + 0xF0, + 0xD9, + 0xF9, + 0xA5, + 0x1C, + 0xA8, + 0x12, + 0x1B, + 0xA0, + 0x13, + 0xA9, + 0x05, + 0xB5, + 0x0A, + 0xB8, + 0x03, + 0xB0, + 0x0B, + 0xB9, + 0x32, + 0x88, + 0x3C, + 0x85, + 0x8D, + 0x34, + 0x84, + 0x3D, + 0x91, + 0x22, + 0x9C, + 0x2C, + 0x94, + 0x24, + 0x9D, + 0x2D, + 0x62, + 0x4A, + 0x6C, + 0x45, + 0x4D, + 0x64, + 0x44, + 0x6D, + 0x52, + 0x72, + 0x5C, + 0x7C, + 0x54, + 0x74, + 0x5D, + 0x7D, + 0xA1, + 0x1A, + 0xAC, + 0x15, + 0x1D, + 0xA4, + 0x14, + 0xAD, + 0x02, + 0xB1, + 0x0C, + 0xBC, + 0x04, + 0xB4, + 0x0D, + 0xBD, + 0xE1, + 0xC8, + 0xEC, + 0xC5, + 0xCD, + 0xE4, + 0xC4, + 0xED, + 0xD1, + 0xF1, + 0xDC, + 0xFC, + 0xD4, + 0xF4, + 0xDD, + 0xFD, + 0x36, + 0x8E, + 0x38, + 0x82, + 0x8B, + 0x30, + 0x83, + 0x39, + 0x96, + 0x26, + 0x9A, + 0x28, + 0x93, + 0x20, + 0x9B, + 0x29, + 0x66, + 0x4E, + 0x68, + 0x41, + 0x49, + 0x60, + 0x40, + 0x69, + 0x56, + 0x76, + 0x58, + 0x78, + 0x50, + 0x70, + 0x59, + 0x79, + 0xA6, + 0x1E, + 0xAA, + 0x11, + 0x19, + 0xA3, + 0x10, + 0xAB, + 0x06, + 0xB6, + 0x08, + 0xBA, + 0x00, + 0xB3, + 0x09, + 0xBB, + 0xE6, + 0xCE, + 0xEA, + 0xC2, + 0xCB, + 0xE3, + 0xC3, + 0xEB, + 0xD6, + 0xF6, + 0xDA, + 0xFA, + 0xD3, + 0xF3, + 0xDB, + 0xFB, + 0x31, + 0x8A, + 0x3E, + 0x86, + 0x8F, + 0x37, + 0x87, + 0x3F, + 0x92, + 0x21, + 0x9E, + 0x2E, + 0x97, + 0x27, + 0x9F, + 0x2F, + 0x61, + 0x48, + 0x6E, + 0x46, + 0x4F, + 0x67, + 0x47, + 0x6F, + 0x51, + 0x71, + 0x5E, + 0x7E, + 0x57, + 0x77, + 0x5F, + 0x7F, + 0xA2, + 0x18, + 0xAE, + 0x16, + 0x1F, + 0xA7, + 0x17, + 0xAF, + 0x01, + 0xB2, + 0x0E, + 0xBE, + 0x07, + 0xB7, + 0x0F, + 0xBF, + 0xE2, + 0xCA, + 0xEE, + 0xC6, + 0xCF, + 0xE7, + 0xC7, + 0xEF, + 0xD2, + 0xF2, + 0xDE, + 0xFE, + 0xD7, + 0xF7, + 0xDF, + 0xFF, + ] +) ForkSkinny_8 = SKINNY_8 Remus_8 = SKINNY_8 Romulus = SKINNY_8 -Skipjack = SBox([ - 0xa3,0xd7,0x09,0x83,0xf8,0x48,0xf6,0xf4,0xb3,0x21,0x15,0x78,0x99,0xb1,0xaf,0xf9, - 0xe7,0x2d,0x4d,0x8a,0xce,0x4c,0xca,0x2e,0x52,0x95,0xd9,0x1e,0x4e,0x38,0x44,0x28, - 0x0a,0xdf,0x02,0xa0,0x17,0xf1,0x60,0x68,0x12,0xb7,0x7a,0xc3,0xe9,0xfa,0x3d,0x53, - 0x96,0x84,0x6b,0xba,0xf2,0x63,0x9a,0x19,0x7c,0xae,0xe5,0xf5,0xf7,0x16,0x6a,0xa2, - 0x39,0xb6,0x7b,0x0f,0xc1,0x93,0x81,0x1b,0xee,0xb4,0x1a,0xea,0xd0,0x91,0x2f,0xb8, - 0x55,0xb9,0xda,0x85,0x3f,0x41,0xbf,0xe0,0x5a,0x58,0x80,0x5f,0x66,0x0b,0xd8,0x90, - 0x35,0xd5,0xc0,0xa7,0x33,0x06,0x65,0x69,0x45,0x00,0x94,0x56,0x6d,0x98,0x9b,0x76, - 0x97,0xfc,0xb2,0xc2,0xb0,0xfe,0xdb,0x20,0xe1,0xeb,0xd6,0xe4,0xdd,0x47,0x4a,0x1d, - 0x42,0xed,0x9e,0x6e,0x49,0x3c,0xcd,0x43,0x27,0xd2,0x07,0xd4,0xde,0xc7,0x67,0x18, - 0x89,0xcb,0x30,0x1f,0x8d,0xc6,0x8f,0xaa,0xc8,0x74,0xdc,0xc9,0x5d,0x5c,0x31,0xa4, - 0x70,0x88,0x61,0x2c,0x9f,0x0d,0x2b,0x87,0x50,0x82,0x54,0x64,0x26,0x7d,0x03,0x40, - 0x34,0x4b,0x1c,0x73,0xd1,0xc4,0xfd,0x3b,0xcc,0xfb,0x7f,0xab,0xe6,0x3e,0x5b,0xa5, - 0xad,0x04,0x23,0x9c,0x14,0x51,0x22,0xf0,0x29,0x79,0x71,0x7e,0xff,0x8c,0x0e,0xe2, - 0x0c,0xef,0xbc,0x72,0x75,0x6f,0x37,0xa1,0xec,0xd3,0x8e,0x62,0x8b,0x86,0x10,0xe8, - 0x08,0x77,0x11,0xbe,0x92,0x4f,0x24,0xc5,0x32,0x36,0x9d,0xcf,0xf3,0xa6,0xbb,0xac, - 0x5e,0x6c,0xa9,0x13,0x57,0x25,0xb5,0xe3,0xbd,0xa8,0x3a,0x01,0x05,0x59,0x2a,0x46]) +Skipjack = SBox( + [ + 0xA3, + 0xD7, + 0x09, + 0x83, + 0xF8, + 0x48, + 0xF6, + 0xF4, + 0xB3, + 0x21, + 0x15, + 0x78, + 0x99, + 0xB1, + 0xAF, + 0xF9, + 0xE7, + 0x2D, + 0x4D, + 0x8A, + 0xCE, + 0x4C, + 0xCA, + 0x2E, + 0x52, + 0x95, + 0xD9, + 0x1E, + 0x4E, + 0x38, + 0x44, + 0x28, + 0x0A, + 0xDF, + 0x02, + 0xA0, + 0x17, + 0xF1, + 0x60, + 0x68, + 0x12, + 0xB7, + 0x7A, + 0xC3, + 0xE9, + 0xFA, + 0x3D, + 0x53, + 0x96, + 0x84, + 0x6B, + 0xBA, + 0xF2, + 0x63, + 0x9A, + 0x19, + 0x7C, + 0xAE, + 0xE5, + 0xF5, + 0xF7, + 0x16, + 0x6A, + 0xA2, + 0x39, + 0xB6, + 0x7B, + 0x0F, + 0xC1, + 0x93, + 0x81, + 0x1B, + 0xEE, + 0xB4, + 0x1A, + 0xEA, + 0xD0, + 0x91, + 0x2F, + 0xB8, + 0x55, + 0xB9, + 0xDA, + 0x85, + 0x3F, + 0x41, + 0xBF, + 0xE0, + 0x5A, + 0x58, + 0x80, + 0x5F, + 0x66, + 0x0B, + 0xD8, + 0x90, + 0x35, + 0xD5, + 0xC0, + 0xA7, + 0x33, + 0x06, + 0x65, + 0x69, + 0x45, + 0x00, + 0x94, + 0x56, + 0x6D, + 0x98, + 0x9B, + 0x76, + 0x97, + 0xFC, + 0xB2, + 0xC2, + 0xB0, + 0xFE, + 0xDB, + 0x20, + 0xE1, + 0xEB, + 0xD6, + 0xE4, + 0xDD, + 0x47, + 0x4A, + 0x1D, + 0x42, + 0xED, + 0x9E, + 0x6E, + 0x49, + 0x3C, + 0xCD, + 0x43, + 0x27, + 0xD2, + 0x07, + 0xD4, + 0xDE, + 0xC7, + 0x67, + 0x18, + 0x89, + 0xCB, + 0x30, + 0x1F, + 0x8D, + 0xC6, + 0x8F, + 0xAA, + 0xC8, + 0x74, + 0xDC, + 0xC9, + 0x5D, + 0x5C, + 0x31, + 0xA4, + 0x70, + 0x88, + 0x61, + 0x2C, + 0x9F, + 0x0D, + 0x2B, + 0x87, + 0x50, + 0x82, + 0x54, + 0x64, + 0x26, + 0x7D, + 0x03, + 0x40, + 0x34, + 0x4B, + 0x1C, + 0x73, + 0xD1, + 0xC4, + 0xFD, + 0x3B, + 0xCC, + 0xFB, + 0x7F, + 0xAB, + 0xE6, + 0x3E, + 0x5B, + 0xA5, + 0xAD, + 0x04, + 0x23, + 0x9C, + 0x14, + 0x51, + 0x22, + 0xF0, + 0x29, + 0x79, + 0x71, + 0x7E, + 0xFF, + 0x8C, + 0x0E, + 0xE2, + 0x0C, + 0xEF, + 0xBC, + 0x72, + 0x75, + 0x6F, + 0x37, + 0xA1, + 0xEC, + 0xD3, + 0x8E, + 0x62, + 0x8B, + 0x86, + 0x10, + 0xE8, + 0x08, + 0x77, + 0x11, + 0xBE, + 0x92, + 0x4F, + 0x24, + 0xC5, + 0x32, + 0x36, + 0x9D, + 0xCF, + 0xF3, + 0xA6, + 0xBB, + 0xAC, + 0x5E, + 0x6C, + 0xA9, + 0x13, + 0x57, + 0x25, + 0xB5, + 0xE3, + 0xBD, + 0xA8, + 0x3A, + 0x01, + 0x05, + 0x59, + 0x2A, + 0x46, + ] +) # source: www.gsma.com/aboutus/wp-content/uploads/2014/12/snow3gspec.doc -SNOW_3G_sq = SBox([ - 0x25,0x24,0x73,0x67,0xD7,0xAE,0x5C,0x30,0xA4,0xEE,0x6E,0xCB,0x7D,0xB5,0x82,0xDB, - 0xE4,0x8E,0x48,0x49,0x4F,0x5D,0x6A,0x78,0x70,0x88,0xE8,0x5F,0x5E,0x84,0x65,0xE2, - 0xD8,0xE9,0xCC,0xED,0x40,0x2F,0x11,0x28,0x57,0xD2,0xAC,0xE3,0x4A,0x15,0x1B,0xB9, - 0xB2,0x80,0x85,0xA6,0x2E,0x02,0x47,0x29,0x07,0x4B,0x0E,0xC1,0x51,0xAA,0x89,0xD4, - 0xCA,0x01,0x46,0xB3,0xEF,0xDD,0x44,0x7B,0xC2,0x7F,0xBE,0xC3,0x9F,0x20,0x4C,0x64, - 0x83,0xA2,0x68,0x42,0x13,0xB4,0x41,0xCD,0xBA,0xC6,0xBB,0x6D,0x4D,0x71,0x21,0xF4, - 0x8D,0xB0,0xE5,0x93,0xFE,0x8F,0xE6,0xCF,0x43,0x45,0x31,0x22,0x37,0x36,0x96,0xFA, - 0xBC,0x0F,0x08,0x52,0x1D,0x55,0x1A,0xC5,0x4E,0x23,0x69,0x7A,0x92,0xFF,0x5B,0x5A, - 0xEB,0x9A,0x1C,0xA9,0xD1,0x7E,0x0D,0xFC,0x50,0x8A,0xB6,0x62,0xF5,0x0A,0xF8,0xDC, - 0x03,0x3C,0x0C,0x39,0xF1,0xB8,0xF3,0x3D,0xF2,0xD5,0x97,0x66,0x81,0x32,0xA0,0x00, - 0x06,0xCE,0xF6,0xEA,0xB7,0x17,0xF7,0x8C,0x79,0xD6,0xA7,0xBF,0x8B,0x3F,0x1F,0x53, - 0x63,0x75,0x35,0x2C,0x60,0xFD,0x27,0xD3,0x94,0xA5,0x7C,0xA1,0x05,0x58,0x2D,0xBD, - 0xD9,0xC7,0xAF,0x6B,0x54,0x0B,0xE0,0x38,0x04,0xC8,0x9D,0xE7,0x14,0xB1,0x87,0x9C, - 0xDF,0x6F,0xF9,0xDA,0x2A,0xC4,0x59,0x16,0x74,0x91,0xAB,0x26,0x61,0x76,0x34,0x2B, - 0xAD,0x99,0xFB,0x72,0xEC,0x33,0x12,0xDE,0x98,0x3B,0xC0,0x9B,0x3E,0x18,0x10,0x3A, - 0x56,0xE1,0x77,0xC9,0x1E,0x9E,0x95,0xA3,0x90,0x19,0xA8,0x6C,0x09,0xD0,0xF0,0x86]) - -SMS4 = SBox([ - 0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05, - 0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99, - 0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62, - 0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6, - 0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8, - 0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35, - 0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87, - 0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e, - 0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1, - 0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3, - 0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f, - 0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51, - 0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8, - 0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0, - 0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84, - 0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48]) +SNOW_3G_sq = SBox( + [ + 0x25, + 0x24, + 0x73, + 0x67, + 0xD7, + 0xAE, + 0x5C, + 0x30, + 0xA4, + 0xEE, + 0x6E, + 0xCB, + 0x7D, + 0xB5, + 0x82, + 0xDB, + 0xE4, + 0x8E, + 0x48, + 0x49, + 0x4F, + 0x5D, + 0x6A, + 0x78, + 0x70, + 0x88, + 0xE8, + 0x5F, + 0x5E, + 0x84, + 0x65, + 0xE2, + 0xD8, + 0xE9, + 0xCC, + 0xED, + 0x40, + 0x2F, + 0x11, + 0x28, + 0x57, + 0xD2, + 0xAC, + 0xE3, + 0x4A, + 0x15, + 0x1B, + 0xB9, + 0xB2, + 0x80, + 0x85, + 0xA6, + 0x2E, + 0x02, + 0x47, + 0x29, + 0x07, + 0x4B, + 0x0E, + 0xC1, + 0x51, + 0xAA, + 0x89, + 0xD4, + 0xCA, + 0x01, + 0x46, + 0xB3, + 0xEF, + 0xDD, + 0x44, + 0x7B, + 0xC2, + 0x7F, + 0xBE, + 0xC3, + 0x9F, + 0x20, + 0x4C, + 0x64, + 0x83, + 0xA2, + 0x68, + 0x42, + 0x13, + 0xB4, + 0x41, + 0xCD, + 0xBA, + 0xC6, + 0xBB, + 0x6D, + 0x4D, + 0x71, + 0x21, + 0xF4, + 0x8D, + 0xB0, + 0xE5, + 0x93, + 0xFE, + 0x8F, + 0xE6, + 0xCF, + 0x43, + 0x45, + 0x31, + 0x22, + 0x37, + 0x36, + 0x96, + 0xFA, + 0xBC, + 0x0F, + 0x08, + 0x52, + 0x1D, + 0x55, + 0x1A, + 0xC5, + 0x4E, + 0x23, + 0x69, + 0x7A, + 0x92, + 0xFF, + 0x5B, + 0x5A, + 0xEB, + 0x9A, + 0x1C, + 0xA9, + 0xD1, + 0x7E, + 0x0D, + 0xFC, + 0x50, + 0x8A, + 0xB6, + 0x62, + 0xF5, + 0x0A, + 0xF8, + 0xDC, + 0x03, + 0x3C, + 0x0C, + 0x39, + 0xF1, + 0xB8, + 0xF3, + 0x3D, + 0xF2, + 0xD5, + 0x97, + 0x66, + 0x81, + 0x32, + 0xA0, + 0x00, + 0x06, + 0xCE, + 0xF6, + 0xEA, + 0xB7, + 0x17, + 0xF7, + 0x8C, + 0x79, + 0xD6, + 0xA7, + 0xBF, + 0x8B, + 0x3F, + 0x1F, + 0x53, + 0x63, + 0x75, + 0x35, + 0x2C, + 0x60, + 0xFD, + 0x27, + 0xD3, + 0x94, + 0xA5, + 0x7C, + 0xA1, + 0x05, + 0x58, + 0x2D, + 0xBD, + 0xD9, + 0xC7, + 0xAF, + 0x6B, + 0x54, + 0x0B, + 0xE0, + 0x38, + 0x04, + 0xC8, + 0x9D, + 0xE7, + 0x14, + 0xB1, + 0x87, + 0x9C, + 0xDF, + 0x6F, + 0xF9, + 0xDA, + 0x2A, + 0xC4, + 0x59, + 0x16, + 0x74, + 0x91, + 0xAB, + 0x26, + 0x61, + 0x76, + 0x34, + 0x2B, + 0xAD, + 0x99, + 0xFB, + 0x72, + 0xEC, + 0x33, + 0x12, + 0xDE, + 0x98, + 0x3B, + 0xC0, + 0x9B, + 0x3E, + 0x18, + 0x10, + 0x3A, + 0x56, + 0xE1, + 0x77, + 0xC9, + 0x1E, + 0x9E, + 0x95, + 0xA3, + 0x90, + 0x19, + 0xA8, + 0x6C, + 0x09, + 0xD0, + 0xF0, + 0x86, + ] +) + +SMS4 = SBox( + [ + 0xD6, + 0x90, + 0xE9, + 0xFE, + 0xCC, + 0xE1, + 0x3D, + 0xB7, + 0x16, + 0xB6, + 0x14, + 0xC2, + 0x28, + 0xFB, + 0x2C, + 0x05, + 0x2B, + 0x67, + 0x9A, + 0x76, + 0x2A, + 0xBE, + 0x04, + 0xC3, + 0xAA, + 0x44, + 0x13, + 0x26, + 0x49, + 0x86, + 0x06, + 0x99, + 0x9C, + 0x42, + 0x50, + 0xF4, + 0x91, + 0xEF, + 0x98, + 0x7A, + 0x33, + 0x54, + 0x0B, + 0x43, + 0xED, + 0xCF, + 0xAC, + 0x62, + 0xE4, + 0xB3, + 0x1C, + 0xA9, + 0xC9, + 0x08, + 0xE8, + 0x95, + 0x80, + 0xDF, + 0x94, + 0xFA, + 0x75, + 0x8F, + 0x3F, + 0xA6, + 0x47, + 0x07, + 0xA7, + 0xFC, + 0xF3, + 0x73, + 0x17, + 0xBA, + 0x83, + 0x59, + 0x3C, + 0x19, + 0xE6, + 0x85, + 0x4F, + 0xA8, + 0x68, + 0x6B, + 0x81, + 0xB2, + 0x71, + 0x64, + 0xDA, + 0x8B, + 0xF8, + 0xEB, + 0x0F, + 0x4B, + 0x70, + 0x56, + 0x9D, + 0x35, + 0x1E, + 0x24, + 0x0E, + 0x5E, + 0x63, + 0x58, + 0xD1, + 0xA2, + 0x25, + 0x22, + 0x7C, + 0x3B, + 0x01, + 0x21, + 0x78, + 0x87, + 0xD4, + 0x00, + 0x46, + 0x57, + 0x9F, + 0xD3, + 0x27, + 0x52, + 0x4C, + 0x36, + 0x02, + 0xE7, + 0xA0, + 0xC4, + 0xC8, + 0x9E, + 0xEA, + 0xBF, + 0x8A, + 0xD2, + 0x40, + 0xC7, + 0x38, + 0xB5, + 0xA3, + 0xF7, + 0xF2, + 0xCE, + 0xF9, + 0x61, + 0x15, + 0xA1, + 0xE0, + 0xAE, + 0x5D, + 0xA4, + 0x9B, + 0x34, + 0x1A, + 0x55, + 0xAD, + 0x93, + 0x32, + 0x30, + 0xF5, + 0x8C, + 0xB1, + 0xE3, + 0x1D, + 0xF6, + 0xE2, + 0x2E, + 0x82, + 0x66, + 0xCA, + 0x60, + 0xC0, + 0x29, + 0x23, + 0xAB, + 0x0D, + 0x53, + 0x4E, + 0x6F, + 0xD5, + 0xDB, + 0x37, + 0x45, + 0xDE, + 0xFD, + 0x8E, + 0x2F, + 0x03, + 0xFF, + 0x6A, + 0x72, + 0x6D, + 0x6C, + 0x5B, + 0x51, + 0x8D, + 0x1B, + 0xAF, + 0x92, + 0xBB, + 0xDD, + 0xBC, + 0x7F, + 0x11, + 0xD9, + 0x5C, + 0x41, + 0x1F, + 0x10, + 0x5A, + 0xD8, + 0x0A, + 0xC1, + 0x31, + 0x88, + 0xA5, + 0xCD, + 0x7B, + 0xBD, + 0x2D, + 0x74, + 0xD0, + 0x12, + 0xB8, + 0xE5, + 0xB4, + 0xB0, + 0x89, + 0x69, + 0x97, + 0x4A, + 0x0C, + 0x96, + 0x77, + 0x7E, + 0x65, + 0xB9, + 0xF1, + 0x09, + 0xC5, + 0x6E, + 0xC6, + 0x84, + 0x18, + 0xF0, + 0x7D, + 0xEC, + 0x3A, + 0xDC, + 0x4D, + 0x20, + 0x79, + 0xEE, + 0x5F, + 0x3E, + 0xD7, + 0xCB, + 0x39, + 0x48, + ] +) # source: https://www.iacr.org/archive/fse2003/28870306/28870306.pdf # structure: random, obtained from RC4 -Turing = SBox([ - 0x61,0x51,0xeb,0x19,0xb9,0x5d,0x60,0x38,0x7c,0xb2,0x06,0x12,0xc4,0x5b,0x16,0x3b, - 0x2b,0x18,0x83,0xb0,0x7f,0x75,0xfa,0xa0,0xe9,0xdd,0x6d,0x7a,0x6b,0x68,0x2d,0x49, - 0xb5,0x1c,0x90,0xf7,0xed,0x9f,0xe8,0xce,0xae,0x77,0xc2,0x13,0xfd,0xcd,0x3e,0xcf, - 0x37,0x6a,0xd4,0xdb,0x8e,0x65,0x1f,0x1a,0x87,0xcb,0x40,0x15,0x88,0x0d,0x35,0xb3, - 0x11,0x0f,0xd0,0x30,0x48,0xf9,0xa8,0xac,0x85,0x27,0x0e,0x8a,0xe0,0x50,0x64,0xa7, - 0xcc,0xe4,0xf1,0x98,0xff,0xa1,0x04,0xda,0xd5,0xbc,0x1b,0xbb,0xd1,0xfe,0x31,0xca, - 0xba,0xd9,0x2e,0xf3,0x1d,0x47,0x4a,0x3d,0x71,0x4c,0xab,0x7d,0x8d,0xc7,0x59,0xb8, - 0xc1,0x96,0x1e,0xfc,0x44,0xc8,0x7b,0xdc,0x5c,0x78,0x2a,0x9d,0xa5,0xf0,0x73,0x22, - 0x89,0x05,0xf4,0x07,0x21,0x52,0xa6,0x28,0x9a,0x92,0x69,0x8f,0xc5,0xc3,0xf5,0xe1, - 0xde,0xec,0x09,0xf2,0xd3,0xaf,0x34,0x23,0xaa,0xdf,0x7e,0x82,0x29,0xc0,0x24,0x14, - 0x03,0x32,0x4e,0x39,0x6f,0xc6,0xb1,0x9b,0xea,0x72,0x79,0x41,0xd8,0x26,0x6c,0x5e, - 0x2c,0xb4,0xa2,0x53,0x57,0xe2,0x9c,0x86,0x54,0x95,0xb6,0x80,0x8c,0x36,0x67,0xbd, - 0x08,0x93,0x2f,0x99,0x5a,0xf8,0x3a,0xd7,0x56,0x84,0xd2,0x01,0xf6,0x66,0x4d,0x55, - 0x8b,0x0c,0x0b,0x46,0xb7,0x3c,0x45,0x91,0xa4,0xe3,0x70,0xd6,0xfb,0xe6,0x10,0xa9, - 0xc9,0x00,0x9e,0xe7,0x4f,0x76,0x25,0x3f,0x5f,0xa3,0x33,0x20,0x02,0xef,0x62,0x74, - 0xee,0x17,0x81,0x42,0x58,0x0a,0x4b,0x63,0xe5,0xbe,0x6e,0xad,0xbf,0x43,0x94,0x97]) +Turing = SBox( + [ + 0x61, + 0x51, + 0xEB, + 0x19, + 0xB9, + 0x5D, + 0x60, + 0x38, + 0x7C, + 0xB2, + 0x06, + 0x12, + 0xC4, + 0x5B, + 0x16, + 0x3B, + 0x2B, + 0x18, + 0x83, + 0xB0, + 0x7F, + 0x75, + 0xFA, + 0xA0, + 0xE9, + 0xDD, + 0x6D, + 0x7A, + 0x6B, + 0x68, + 0x2D, + 0x49, + 0xB5, + 0x1C, + 0x90, + 0xF7, + 0xED, + 0x9F, + 0xE8, + 0xCE, + 0xAE, + 0x77, + 0xC2, + 0x13, + 0xFD, + 0xCD, + 0x3E, + 0xCF, + 0x37, + 0x6A, + 0xD4, + 0xDB, + 0x8E, + 0x65, + 0x1F, + 0x1A, + 0x87, + 0xCB, + 0x40, + 0x15, + 0x88, + 0x0D, + 0x35, + 0xB3, + 0x11, + 0x0F, + 0xD0, + 0x30, + 0x48, + 0xF9, + 0xA8, + 0xAC, + 0x85, + 0x27, + 0x0E, + 0x8A, + 0xE0, + 0x50, + 0x64, + 0xA7, + 0xCC, + 0xE4, + 0xF1, + 0x98, + 0xFF, + 0xA1, + 0x04, + 0xDA, + 0xD5, + 0xBC, + 0x1B, + 0xBB, + 0xD1, + 0xFE, + 0x31, + 0xCA, + 0xBA, + 0xD9, + 0x2E, + 0xF3, + 0x1D, + 0x47, + 0x4A, + 0x3D, + 0x71, + 0x4C, + 0xAB, + 0x7D, + 0x8D, + 0xC7, + 0x59, + 0xB8, + 0xC1, + 0x96, + 0x1E, + 0xFC, + 0x44, + 0xC8, + 0x7B, + 0xDC, + 0x5C, + 0x78, + 0x2A, + 0x9D, + 0xA5, + 0xF0, + 0x73, + 0x22, + 0x89, + 0x05, + 0xF4, + 0x07, + 0x21, + 0x52, + 0xA6, + 0x28, + 0x9A, + 0x92, + 0x69, + 0x8F, + 0xC5, + 0xC3, + 0xF5, + 0xE1, + 0xDE, + 0xEC, + 0x09, + 0xF2, + 0xD3, + 0xAF, + 0x34, + 0x23, + 0xAA, + 0xDF, + 0x7E, + 0x82, + 0x29, + 0xC0, + 0x24, + 0x14, + 0x03, + 0x32, + 0x4E, + 0x39, + 0x6F, + 0xC6, + 0xB1, + 0x9B, + 0xEA, + 0x72, + 0x79, + 0x41, + 0xD8, + 0x26, + 0x6C, + 0x5E, + 0x2C, + 0xB4, + 0xA2, + 0x53, + 0x57, + 0xE2, + 0x9C, + 0x86, + 0x54, + 0x95, + 0xB6, + 0x80, + 0x8C, + 0x36, + 0x67, + 0xBD, + 0x08, + 0x93, + 0x2F, + 0x99, + 0x5A, + 0xF8, + 0x3A, + 0xD7, + 0x56, + 0x84, + 0xD2, + 0x01, + 0xF6, + 0x66, + 0x4D, + 0x55, + 0x8B, + 0x0C, + 0x0B, + 0x46, + 0xB7, + 0x3C, + 0x45, + 0x91, + 0xA4, + 0xE3, + 0x70, + 0xD6, + 0xFB, + 0xE6, + 0x10, + 0xA9, + 0xC9, + 0x00, + 0x9E, + 0xE7, + 0x4F, + 0x76, + 0x25, + 0x3F, + 0x5F, + 0xA3, + 0x33, + 0x20, + 0x02, + 0xEF, + 0x62, + 0x74, + 0xEE, + 0x17, + 0x81, + 0x42, + 0x58, + 0x0A, + 0x4B, + 0x63, + 0xE5, + 0xBE, + 0x6E, + 0xAD, + 0xBF, + 0x43, + 0x94, + 0x97, + ] +) # source: https://www.schneier.com/cryptography/paperfiles/paper-twofish-paper.pdf # structure: ASAS, the 4 bit S-Boxes q0 ti for i=0..3 are provided below -Twofish_p0 = SBox([ - 0xA9,0x67,0xB3,0xE8,0x04,0xFD,0xA3,0x76,0x9A,0x92,0x80,0x78,0xE4,0xDD,0xD1,0x38, - 0x0D,0xC6,0x35,0x98,0x18,0xF7,0xEC,0x6C,0x43,0x75,0x37,0x26,0xFA,0x13,0x94,0x48, - 0xF2,0xD0,0x8B,0x30,0x84,0x54,0xDF,0x23,0x19,0x5B,0x3D,0x59,0xF3,0xAE,0xA2,0x82, - 0x63,0x01,0x83,0x2E,0xD9,0x51,0x9B,0x7C,0xA6,0xEB,0xA5,0xBE,0x16,0x0C,0xE3,0x61, - 0xC0,0x8C,0x3A,0xF5,0x73,0x2C,0x25,0x0B,0xBB,0x4E,0x89,0x6B,0x53,0x6A,0xB4,0xF1, - 0xE1,0xE6,0xBD,0x45,0xE2,0xF4,0xB6,0x66,0xCC,0x95,0x03,0x56,0xD4,0x1C,0x1E,0xD7, - 0xFB,0xC3,0x8E,0xB5,0xE9,0xCF,0xBF,0xBA,0xEA,0x77,0x39,0xAF,0x33,0xC9,0x62,0x71, - 0x81,0x79,0x09,0xAD,0x24,0xCD,0xF9,0xD8,0xE5,0xC5,0xB9,0x4D,0x44,0x08,0x86,0xE7, - 0xA1,0x1D,0xAA,0xED,0x06,0x70,0xB2,0xD2,0x41,0x7B,0xA0,0x11,0x31,0xC2,0x27,0x90, - 0x20,0xF6,0x60,0xFF,0x96,0x5C,0xB1,0xAB,0x9E,0x9C,0x52,0x1B,0x5F,0x93,0x0A,0xEF, - 0x91,0x85,0x49,0xEE,0x2D,0x4F,0x8F,0x3B,0x47,0x87,0x6D,0x46,0xD6,0x3E,0x69,0x64, - 0x2A,0xCE,0xCB,0x2F,0xFC,0x97,0x05,0x7A,0xAC,0x7F,0xD5,0x1A,0x4B,0x0E,0xA7,0x5A, - 0x28,0x14,0x3F,0x29,0x88,0x3C,0x4C,0x02,0xB8,0xDA,0xB0,0x17,0x55,0x1F,0x8A,0x7D, - 0x57,0xC7,0x8D,0x74,0xB7,0xC4,0x9F,0x72,0x7E,0x15,0x22,0x12,0x58,0x07,0x99,0x34, - 0x6E,0x50,0xDE,0x68,0x65,0xBC,0xDB,0xF8,0xC8,0xA8,0x2B,0x40,0xDC,0xFE,0x32,0xA4, - 0xCA,0x10,0x21,0xF0,0xD3,0x5D,0x0F,0x00,0x6F,0x9D,0x36,0x42,0x4A,0x5E,0xC1,0xE0]) +Twofish_p0 = SBox( + [ + 0xA9, + 0x67, + 0xB3, + 0xE8, + 0x04, + 0xFD, + 0xA3, + 0x76, + 0x9A, + 0x92, + 0x80, + 0x78, + 0xE4, + 0xDD, + 0xD1, + 0x38, + 0x0D, + 0xC6, + 0x35, + 0x98, + 0x18, + 0xF7, + 0xEC, + 0x6C, + 0x43, + 0x75, + 0x37, + 0x26, + 0xFA, + 0x13, + 0x94, + 0x48, + 0xF2, + 0xD0, + 0x8B, + 0x30, + 0x84, + 0x54, + 0xDF, + 0x23, + 0x19, + 0x5B, + 0x3D, + 0x59, + 0xF3, + 0xAE, + 0xA2, + 0x82, + 0x63, + 0x01, + 0x83, + 0x2E, + 0xD9, + 0x51, + 0x9B, + 0x7C, + 0xA6, + 0xEB, + 0xA5, + 0xBE, + 0x16, + 0x0C, + 0xE3, + 0x61, + 0xC0, + 0x8C, + 0x3A, + 0xF5, + 0x73, + 0x2C, + 0x25, + 0x0B, + 0xBB, + 0x4E, + 0x89, + 0x6B, + 0x53, + 0x6A, + 0xB4, + 0xF1, + 0xE1, + 0xE6, + 0xBD, + 0x45, + 0xE2, + 0xF4, + 0xB6, + 0x66, + 0xCC, + 0x95, + 0x03, + 0x56, + 0xD4, + 0x1C, + 0x1E, + 0xD7, + 0xFB, + 0xC3, + 0x8E, + 0xB5, + 0xE9, + 0xCF, + 0xBF, + 0xBA, + 0xEA, + 0x77, + 0x39, + 0xAF, + 0x33, + 0xC9, + 0x62, + 0x71, + 0x81, + 0x79, + 0x09, + 0xAD, + 0x24, + 0xCD, + 0xF9, + 0xD8, + 0xE5, + 0xC5, + 0xB9, + 0x4D, + 0x44, + 0x08, + 0x86, + 0xE7, + 0xA1, + 0x1D, + 0xAA, + 0xED, + 0x06, + 0x70, + 0xB2, + 0xD2, + 0x41, + 0x7B, + 0xA0, + 0x11, + 0x31, + 0xC2, + 0x27, + 0x90, + 0x20, + 0xF6, + 0x60, + 0xFF, + 0x96, + 0x5C, + 0xB1, + 0xAB, + 0x9E, + 0x9C, + 0x52, + 0x1B, + 0x5F, + 0x93, + 0x0A, + 0xEF, + 0x91, + 0x85, + 0x49, + 0xEE, + 0x2D, + 0x4F, + 0x8F, + 0x3B, + 0x47, + 0x87, + 0x6D, + 0x46, + 0xD6, + 0x3E, + 0x69, + 0x64, + 0x2A, + 0xCE, + 0xCB, + 0x2F, + 0xFC, + 0x97, + 0x05, + 0x7A, + 0xAC, + 0x7F, + 0xD5, + 0x1A, + 0x4B, + 0x0E, + 0xA7, + 0x5A, + 0x28, + 0x14, + 0x3F, + 0x29, + 0x88, + 0x3C, + 0x4C, + 0x02, + 0xB8, + 0xDA, + 0xB0, + 0x17, + 0x55, + 0x1F, + 0x8A, + 0x7D, + 0x57, + 0xC7, + 0x8D, + 0x74, + 0xB7, + 0xC4, + 0x9F, + 0x72, + 0x7E, + 0x15, + 0x22, + 0x12, + 0x58, + 0x07, + 0x99, + 0x34, + 0x6E, + 0x50, + 0xDE, + 0x68, + 0x65, + 0xBC, + 0xDB, + 0xF8, + 0xC8, + 0xA8, + 0x2B, + 0x40, + 0xDC, + 0xFE, + 0x32, + 0xA4, + 0xCA, + 0x10, + 0x21, + 0xF0, + 0xD3, + 0x5D, + 0x0F, + 0x00, + 0x6F, + 0x9D, + 0x36, + 0x42, + 0x4A, + 0x5E, + 0xC1, + 0xE0, + ] +) # source: https://www.schneier.com/cryptography/paperfiles/paper-twofish-paper.pdf # structure: ASAS, the 4 bit S-Boxes q1 ti for i=0..3 are provided below -Twofish_p1 = SBox([ - 0x75,0xF3,0xC6,0xF4,0xDB,0x7B,0xFB,0xC8,0x4A,0xD3,0xE6,0x6B,0x45,0x7D,0xE8,0x4B, - 0xD6,0x32,0xD8,0xFD,0x37,0x71,0xF1,0xE1,0x30,0x0F,0xF8,0x1B,0x87,0xFA,0x06,0x3F, - 0x5E,0xBA,0xAE,0x5B,0x8A,0x00,0xBC,0x9D,0x6D,0xC1,0xB1,0x0E,0x80,0x5D,0xD2,0xD5, - 0xA0,0x84,0x07,0x14,0xB5,0x90,0x2C,0xA3,0xB2,0x73,0x4C,0x54,0x92,0x74,0x36,0x51, - 0x38,0xB0,0xBD,0x5A,0xFC,0x60,0x62,0x96,0x6C,0x42,0xF7,0x10,0x7C,0x28,0x27,0x8C, - 0x13,0x95,0x9C,0xC7,0x24,0x46,0x3B,0x70,0xCA,0xE3,0x85,0xCB,0x11,0xD0,0x93,0xB8, - 0xA6,0x83,0x20,0xFF,0x9F,0x77,0xC3,0xCC,0x03,0x6F,0x08,0xBF,0x40,0xE7,0x2B,0xE2, - 0x79,0x0C,0xAA,0x82,0x41,0x3A,0xEA,0xB9,0xE4,0x9A,0xA4,0x97,0x7E,0xDA,0x7A,0x17, - 0x66,0x94,0xA1,0x1D,0x3D,0xF0,0xDE,0xB3,0x0B,0x72,0xA7,0x1C,0xEF,0xD1,0x53,0x3E, - 0x8F,0x33,0x26,0x5F,0xEC,0x76,0x2A,0x49,0x81,0x88,0xEE,0x21,0xC4,0x1A,0xEB,0xD9, - 0xC5,0x39,0x99,0xCD,0xAD,0x31,0x8B,0x01,0x18,0x23,0xDD,0x1F,0x4E,0x2D,0xF9,0x48, - 0x4F,0xF2,0x65,0x8E,0x78,0x5C,0x58,0x19,0x8D,0xE5,0x98,0x57,0x67,0x7F,0x05,0x64, - 0xAF,0x63,0xB6,0xFE,0xF5,0xB7,0x3C,0xA5,0xCE,0xE9,0x68,0x44,0xE0,0x4D,0x43,0x69, - 0x29,0x2E,0xAC,0x15,0x59,0xA8,0x0A,0x9E,0x6E,0x47,0xDF,0x34,0x35,0x6A,0xCF,0xDC, - 0x22,0xC9,0xC0,0x9B,0x89,0xD4,0xED,0xAB,0x12,0xA2,0x0D,0x52,0xBB,0x02,0x2F,0xA9, - 0xD7,0x61,0x1E,0xB4,0x50,0x04,0xF6,0xC2,0x16,0x25,0x86,0x56,0x55,0x09,0xBE,0x91]) - -Whirlpool = SBox([ - 0x18,0x23,0xc6,0xE8,0x87,0xB8,0x01,0x4F,0x36,0xA6,0xd2,0xF5,0x79,0x6F,0x91,0x52, - 0x60,0xBc,0x9B,0x8E,0xA3,0x0c,0x7B,0x35,0x1d,0xE0,0xd7,0xc2,0x2E,0x4B,0xFE,0x57, - 0x15,0x77,0x37,0xE5,0x9F,0xF0,0x4A,0xdA,0x58,0xc9,0x29,0x0A,0xB1,0xA0,0x6B,0x85, - 0xBd,0x5d,0x10,0xF4,0xcB,0x3E,0x05,0x67,0xE4,0x27,0x41,0x8B,0xA7,0x7d,0x95,0xd8, - 0xFB,0xEE,0x7c,0x66,0xdd,0x17,0x47,0x9E,0xcA,0x2d,0xBF,0x07,0xAd,0x5A,0x83,0x33, - 0x63,0x02,0xAA,0x71,0xc8,0x19,0x49,0xd9,0xF2,0xE3,0x5B,0x88,0x9A,0x26,0x32,0xB0, - 0xE9,0x0F,0xd5,0x80,0xBE,0xcd,0x34,0x48,0xFF,0x7A,0x90,0x5F,0x20,0x68,0x1A,0xAE, - 0xB4,0x54,0x93,0x22,0x64,0xF1,0x73,0x12,0x40,0x08,0xc3,0xEc,0xdB,0xA1,0x8d,0x3d, - 0x97,0x00,0xcF,0x2B,0x76,0x82,0xd6,0x1B,0xB5,0xAF,0x6A,0x50,0x45,0xF3,0x30,0xEF, - 0x3F,0x55,0xA2,0xEA,0x65,0xBA,0x2F,0xc0,0xdE,0x1c,0xFd,0x4d,0x92,0x75,0x06,0x8A, - 0xB2,0xE6,0x0E,0x1F,0x62,0xd4,0xA8,0x96,0xF9,0xc5,0x25,0x59,0x84,0x72,0x39,0x4c, - 0x5E,0x78,0x38,0x8c,0xd1,0xA5,0xE2,0x61,0xB3,0x21,0x9c,0x1E,0x43,0xc7,0xFc,0x04, - 0x51,0x99,0x6d,0x0d,0xFA,0xdF,0x7E,0x24,0x3B,0xAB,0xcE,0x11,0x8F,0x4E,0xB7,0xEB, - 0x3c,0x81,0x94,0xF7,0xB9,0x13,0x2c,0xd3,0xE7,0x6E,0xc4,0x03,0x56,0x44,0x7F,0xA9, - 0x2A,0xBB,0xc1,0x53,0xdc,0x0B,0x9d,0x6c,0x31,0x74,0xF6,0x46,0xAc,0x89,0x14,0xE1, - 0x16,0x3A,0x69,0x09,0x70,0xB6,0xd0,0xEd,0xcc,0x42,0x98,0xA4,0x28,0x5c,0xF8,0x86]) - -Zorro = SBox([ - 0xB2,0xE5,0x5E,0xFD,0x5F,0xC5,0x50,0xBC,0xDC,0x4A,0xFA,0x88,0x28,0xD8,0xE0,0xD1, - 0xB5,0xD0,0x3C,0xB0,0x99,0xC1,0xE8,0xE2,0x13,0x59,0xA7,0xFB,0x71,0x34,0x31,0xF1, - 0x9F,0x3A,0xCE,0x6E,0xA8,0xA4,0xB4,0x7E,0x1F,0xB7,0x51,0x1D,0x38,0x9D,0x46,0x69, - 0x53,0xE,0x42,0x1B,0xF,0x11,0x68,0xCA,0xAA,0x6,0xF0,0xBD,0x26,0x6F,0x0,0xD9, - 0x62,0xF3,0x15,0x60,0xF2,0x3D,0x7F,0x35,0x63,0x2D,0x67,0x93,0x1C,0x91,0xF9,0x9C, - 0x66,0x2A,0x81,0x20,0x95,0xF8,0xE3,0x4D,0x5A,0x6D,0x24,0x7B,0xB9,0xEF,0xDF,0xDA, - 0x58,0xA9,0x92,0x76,0x2E,0xB3,0x39,0xC,0x29,0xCD,0x43,0xFE,0xAB,0xF5,0x94,0x23, - 0x16,0x80,0xC0,0x12,0x4C,0xE9,0x48,0x19,0x8,0xAE,0x41,0x70,0x84,0x14,0xA2,0xD5, - 0xB8,0x33,0x65,0xBA,0xED,0x17,0xCF,0x96,0x1E,0x3B,0xB,0xC2,0xC8,0xB6,0xBB,0x8B, - 0xA1,0x54,0x75,0xC4,0x10,0x5D,0xD6,0x25,0x97,0xE6,0xFC,0x49,0xF7,0x52,0x18,0x86, - 0x8D,0xCB,0xE1,0xBF,0xD7,0x8E,0x37,0xBE,0x82,0xCC,0x64,0x90,0x7C,0x32,0x8F,0x4B, - 0xAC,0x1A,0xEA,0xD3,0xF4,0x6B,0x2C,0xFF,0x55,0xA,0x45,0x9,0x89,0x1,0x30,0x2B, - 0xD2,0x77,0x87,0x72,0xEB,0x36,0xDE,0x9E,0x8C,0xDB,0x6C,0x9B,0x5,0x2,0x4E,0xAF, - 0x4,0xAD,0x74,0xC3,0xEE,0xA6,0xF6,0xC7,0x7D,0x40,0xD4,0xD,0x3E,0x5B,0xEC,0x78, - 0xA0,0xB1,0x44,0x73,0x47,0x5C,0x98,0x21,0x22,0x61,0x3F,0xC6,0x7A,0x56,0xDD,0xE7, - 0x85,0xC9,0x8A,0x57,0x27,0x7,0x9A,0x3,0xA3,0x83,0xE4,0x6A,0xA5,0x2F,0x79,0x4F]) - -ZUC_S0 = SBox([ - 0x3e,0x72,0x5b,0x47,0xca,0xe0,0x00,0x33,0x04,0xd1,0x54,0x98,0x09,0xb9,0x6d,0xcb, - 0x7b,0x1b,0xf9,0x32,0xaf,0x9d,0x6a,0xa5,0xb8,0x2d,0xfc,0x1d,0x08,0x53,0x03,0x90, - 0x4d,0x4e,0x84,0x99,0xe4,0xce,0xd9,0x91,0xdd,0xb6,0x85,0x48,0x8b,0x29,0x6e,0xac, - 0xcd,0xc1,0xf8,0x1e,0x73,0x43,0x69,0xc6,0xb5,0xbd,0xfd,0x39,0x63,0x20,0xd4,0x38, - 0x76,0x7d,0xb2,0xa7,0xcf,0xed,0x57,0xc5,0xf3,0x2c,0xbb,0x14,0x21,0x06,0x55,0x9b, - 0xe3,0xef,0x5e,0x31,0x4f,0x7f,0x5a,0xa4,0x0d,0x82,0x51,0x49,0x5f,0xba,0x58,0x1c, - 0x4a,0x16,0xd5,0x17,0xa8,0x92,0x24,0x1f,0x8c,0xff,0xd8,0xae,0x2e,0x01,0xd3,0xad, - 0x3b,0x4b,0xda,0x46,0xeb,0xc9,0xde,0x9a,0x8f,0x87,0xd7,0x3a,0x80,0x6f,0x2f,0xc8, - 0xb1,0xb4,0x37,0xf7,0x0a,0x22,0x13,0x28,0x7c,0xcc,0x3c,0x89,0xc7,0xc3,0x96,0x56, - 0x07,0xbf,0x7e,0xf0,0x0b,0x2b,0x97,0x52,0x35,0x41,0x79,0x61,0xa6,0x4c,0x10,0xfe, - 0xbc,0x26,0x95,0x88,0x8a,0xb0,0xa3,0xfb,0xc0,0x18,0x94,0xf2,0xe1,0xe5,0xe9,0x5d, - 0xd0,0xdc,0x11,0x66,0x64,0x5c,0xec,0x59,0x42,0x75,0x12,0xf5,0x74,0x9c,0xaa,0x23, - 0x0e,0x86,0xab,0xbe,0x2a,0x02,0xe7,0x67,0xe6,0x44,0xa2,0x6c,0xc2,0x93,0x9f,0xf1, - 0xf6,0xfa,0x36,0xd2,0x50,0x68,0x9e,0x62,0x71,0x15,0x3d,0xd6,0x40,0xc4,0xe2,0x0f, - 0x8e,0x83,0x77,0x6b,0x25,0x05,0x3f,0x0c,0x30,0xea,0x70,0xb7,0xa1,0xe8,0xa9,0x65, - 0x8d,0x27,0x1a,0xdb,0x81,0xb3,0xa0,0xf4,0x45,0x7a,0x19,0xdf,0xee,0x78,0x34,0x60]) - -ZUC_S1 = SBox([ - 0x55,0xc2,0x63,0x71,0x3b,0xc8,0x47,0x86,0x9f,0x3c,0xda,0x5b,0x29,0xaa,0xfd,0x77, - 0x8c,0xc5,0x94,0x0c,0xa6,0x1a,0x13,0x00,0xe3,0xa8,0x16,0x72,0x40,0xf9,0xf8,0x42, - 0x44,0x26,0x68,0x96,0x81,0xd9,0x45,0x3e,0x10,0x76,0xc6,0xa7,0x8b,0x39,0x43,0xe1, - 0x3a,0xb5,0x56,0x2a,0xc0,0x6d,0xb3,0x05,0x22,0x66,0xbf,0xdc,0x0b,0xfa,0x62,0x48, - 0xdd,0x20,0x11,0x06,0x36,0xc9,0xc1,0xcf,0xf6,0x27,0x52,0xbb,0x69,0xf5,0xd4,0x87, - 0x7f,0x84,0x4c,0xd2,0x9c,0x57,0xa4,0xbc,0x4f,0x9a,0xdf,0xfe,0xd6,0x8d,0x7a,0xeb, - 0x2b,0x53,0xd8,0x5c,0xa1,0x14,0x17,0xfb,0x23,0xd5,0x7d,0x30,0x67,0x73,0x08,0x09, - 0xee,0xb7,0x70,0x3f,0x61,0xb2,0x19,0x8e,0x4e,0xe5,0x4b,0x93,0x8f,0x5d,0xdb,0xa9, - 0xad,0xf1,0xae,0x2e,0xcb,0x0d,0xfc,0xf4,0x2d,0x46,0x6e,0x1d,0x97,0xe8,0xd1,0xe9, - 0x4d,0x37,0xa5,0x75,0x5e,0x83,0x9e,0xab,0x82,0x9d,0xb9,0x1c,0xe0,0xcd,0x49,0x89, - 0x01,0xb6,0xbd,0x58,0x24,0xa2,0x5f,0x38,0x78,0x99,0x15,0x90,0x50,0xb8,0x95,0xe4, - 0xd0,0x91,0xc7,0xce,0xed,0x0f,0xb4,0x6f,0xa0,0xcc,0xf0,0x02,0x4a,0x79,0xc3,0xde, - 0xa3,0xef,0xea,0x51,0xe6,0x6b,0x18,0xec,0x1b,0x2c,0x80,0xf7,0x74,0xe7,0xff,0x21, - 0x5a,0x6a,0x54,0x1e,0x41,0x31,0x92,0x35,0xc4,0x33,0x07,0x0a,0xba,0x7e,0x0e,0x34, - 0x88,0xb1,0x98,0x7c,0xf3,0x3d,0x60,0x6c,0x7b,0xca,0xd3,0x1f,0x32,0x65,0x04,0x28, - 0x64,0xbe,0x85,0x9b,0x2f,0x59,0x8a,0xd7,0xb0,0x25,0xac,0xaf,0x12,0x03,0xe2,0xf2]) +Twofish_p1 = SBox( + [ + 0x75, + 0xF3, + 0xC6, + 0xF4, + 0xDB, + 0x7B, + 0xFB, + 0xC8, + 0x4A, + 0xD3, + 0xE6, + 0x6B, + 0x45, + 0x7D, + 0xE8, + 0x4B, + 0xD6, + 0x32, + 0xD8, + 0xFD, + 0x37, + 0x71, + 0xF1, + 0xE1, + 0x30, + 0x0F, + 0xF8, + 0x1B, + 0x87, + 0xFA, + 0x06, + 0x3F, + 0x5E, + 0xBA, + 0xAE, + 0x5B, + 0x8A, + 0x00, + 0xBC, + 0x9D, + 0x6D, + 0xC1, + 0xB1, + 0x0E, + 0x80, + 0x5D, + 0xD2, + 0xD5, + 0xA0, + 0x84, + 0x07, + 0x14, + 0xB5, + 0x90, + 0x2C, + 0xA3, + 0xB2, + 0x73, + 0x4C, + 0x54, + 0x92, + 0x74, + 0x36, + 0x51, + 0x38, + 0xB0, + 0xBD, + 0x5A, + 0xFC, + 0x60, + 0x62, + 0x96, + 0x6C, + 0x42, + 0xF7, + 0x10, + 0x7C, + 0x28, + 0x27, + 0x8C, + 0x13, + 0x95, + 0x9C, + 0xC7, + 0x24, + 0x46, + 0x3B, + 0x70, + 0xCA, + 0xE3, + 0x85, + 0xCB, + 0x11, + 0xD0, + 0x93, + 0xB8, + 0xA6, + 0x83, + 0x20, + 0xFF, + 0x9F, + 0x77, + 0xC3, + 0xCC, + 0x03, + 0x6F, + 0x08, + 0xBF, + 0x40, + 0xE7, + 0x2B, + 0xE2, + 0x79, + 0x0C, + 0xAA, + 0x82, + 0x41, + 0x3A, + 0xEA, + 0xB9, + 0xE4, + 0x9A, + 0xA4, + 0x97, + 0x7E, + 0xDA, + 0x7A, + 0x17, + 0x66, + 0x94, + 0xA1, + 0x1D, + 0x3D, + 0xF0, + 0xDE, + 0xB3, + 0x0B, + 0x72, + 0xA7, + 0x1C, + 0xEF, + 0xD1, + 0x53, + 0x3E, + 0x8F, + 0x33, + 0x26, + 0x5F, + 0xEC, + 0x76, + 0x2A, + 0x49, + 0x81, + 0x88, + 0xEE, + 0x21, + 0xC4, + 0x1A, + 0xEB, + 0xD9, + 0xC5, + 0x39, + 0x99, + 0xCD, + 0xAD, + 0x31, + 0x8B, + 0x01, + 0x18, + 0x23, + 0xDD, + 0x1F, + 0x4E, + 0x2D, + 0xF9, + 0x48, + 0x4F, + 0xF2, + 0x65, + 0x8E, + 0x78, + 0x5C, + 0x58, + 0x19, + 0x8D, + 0xE5, + 0x98, + 0x57, + 0x67, + 0x7F, + 0x05, + 0x64, + 0xAF, + 0x63, + 0xB6, + 0xFE, + 0xF5, + 0xB7, + 0x3C, + 0xA5, + 0xCE, + 0xE9, + 0x68, + 0x44, + 0xE0, + 0x4D, + 0x43, + 0x69, + 0x29, + 0x2E, + 0xAC, + 0x15, + 0x59, + 0xA8, + 0x0A, + 0x9E, + 0x6E, + 0x47, + 0xDF, + 0x34, + 0x35, + 0x6A, + 0xCF, + 0xDC, + 0x22, + 0xC9, + 0xC0, + 0x9B, + 0x89, + 0xD4, + 0xED, + 0xAB, + 0x12, + 0xA2, + 0x0D, + 0x52, + 0xBB, + 0x02, + 0x2F, + 0xA9, + 0xD7, + 0x61, + 0x1E, + 0xB4, + 0x50, + 0x04, + 0xF6, + 0xC2, + 0x16, + 0x25, + 0x86, + 0x56, + 0x55, + 0x09, + 0xBE, + 0x91, + ] +) + +Whirlpool = SBox( + [ + 0x18, + 0x23, + 0xC6, + 0xE8, + 0x87, + 0xB8, + 0x01, + 0x4F, + 0x36, + 0xA6, + 0xD2, + 0xF5, + 0x79, + 0x6F, + 0x91, + 0x52, + 0x60, + 0xBC, + 0x9B, + 0x8E, + 0xA3, + 0x0C, + 0x7B, + 0x35, + 0x1D, + 0xE0, + 0xD7, + 0xC2, + 0x2E, + 0x4B, + 0xFE, + 0x57, + 0x15, + 0x77, + 0x37, + 0xE5, + 0x9F, + 0xF0, + 0x4A, + 0xDA, + 0x58, + 0xC9, + 0x29, + 0x0A, + 0xB1, + 0xA0, + 0x6B, + 0x85, + 0xBD, + 0x5D, + 0x10, + 0xF4, + 0xCB, + 0x3E, + 0x05, + 0x67, + 0xE4, + 0x27, + 0x41, + 0x8B, + 0xA7, + 0x7D, + 0x95, + 0xD8, + 0xFB, + 0xEE, + 0x7C, + 0x66, + 0xDD, + 0x17, + 0x47, + 0x9E, + 0xCA, + 0x2D, + 0xBF, + 0x07, + 0xAD, + 0x5A, + 0x83, + 0x33, + 0x63, + 0x02, + 0xAA, + 0x71, + 0xC8, + 0x19, + 0x49, + 0xD9, + 0xF2, + 0xE3, + 0x5B, + 0x88, + 0x9A, + 0x26, + 0x32, + 0xB0, + 0xE9, + 0x0F, + 0xD5, + 0x80, + 0xBE, + 0xCD, + 0x34, + 0x48, + 0xFF, + 0x7A, + 0x90, + 0x5F, + 0x20, + 0x68, + 0x1A, + 0xAE, + 0xB4, + 0x54, + 0x93, + 0x22, + 0x64, + 0xF1, + 0x73, + 0x12, + 0x40, + 0x08, + 0xC3, + 0xEC, + 0xDB, + 0xA1, + 0x8D, + 0x3D, + 0x97, + 0x00, + 0xCF, + 0x2B, + 0x76, + 0x82, + 0xD6, + 0x1B, + 0xB5, + 0xAF, + 0x6A, + 0x50, + 0x45, + 0xF3, + 0x30, + 0xEF, + 0x3F, + 0x55, + 0xA2, + 0xEA, + 0x65, + 0xBA, + 0x2F, + 0xC0, + 0xDE, + 0x1C, + 0xFD, + 0x4D, + 0x92, + 0x75, + 0x06, + 0x8A, + 0xB2, + 0xE6, + 0x0E, + 0x1F, + 0x62, + 0xD4, + 0xA8, + 0x96, + 0xF9, + 0xC5, + 0x25, + 0x59, + 0x84, + 0x72, + 0x39, + 0x4C, + 0x5E, + 0x78, + 0x38, + 0x8C, + 0xD1, + 0xA5, + 0xE2, + 0x61, + 0xB3, + 0x21, + 0x9C, + 0x1E, + 0x43, + 0xC7, + 0xFC, + 0x04, + 0x51, + 0x99, + 0x6D, + 0x0D, + 0xFA, + 0xDF, + 0x7E, + 0x24, + 0x3B, + 0xAB, + 0xCE, + 0x11, + 0x8F, + 0x4E, + 0xB7, + 0xEB, + 0x3C, + 0x81, + 0x94, + 0xF7, + 0xB9, + 0x13, + 0x2C, + 0xD3, + 0xE7, + 0x6E, + 0xC4, + 0x03, + 0x56, + 0x44, + 0x7F, + 0xA9, + 0x2A, + 0xBB, + 0xC1, + 0x53, + 0xDC, + 0x0B, + 0x9D, + 0x6C, + 0x31, + 0x74, + 0xF6, + 0x46, + 0xAC, + 0x89, + 0x14, + 0xE1, + 0x16, + 0x3A, + 0x69, + 0x09, + 0x70, + 0xB6, + 0xD0, + 0xED, + 0xCC, + 0x42, + 0x98, + 0xA4, + 0x28, + 0x5C, + 0xF8, + 0x86, + ] +) + +Zorro = SBox( + [ + 0xB2, + 0xE5, + 0x5E, + 0xFD, + 0x5F, + 0xC5, + 0x50, + 0xBC, + 0xDC, + 0x4A, + 0xFA, + 0x88, + 0x28, + 0xD8, + 0xE0, + 0xD1, + 0xB5, + 0xD0, + 0x3C, + 0xB0, + 0x99, + 0xC1, + 0xE8, + 0xE2, + 0x13, + 0x59, + 0xA7, + 0xFB, + 0x71, + 0x34, + 0x31, + 0xF1, + 0x9F, + 0x3A, + 0xCE, + 0x6E, + 0xA8, + 0xA4, + 0xB4, + 0x7E, + 0x1F, + 0xB7, + 0x51, + 0x1D, + 0x38, + 0x9D, + 0x46, + 0x69, + 0x53, + 0xE, + 0x42, + 0x1B, + 0xF, + 0x11, + 0x68, + 0xCA, + 0xAA, + 0x6, + 0xF0, + 0xBD, + 0x26, + 0x6F, + 0x0, + 0xD9, + 0x62, + 0xF3, + 0x15, + 0x60, + 0xF2, + 0x3D, + 0x7F, + 0x35, + 0x63, + 0x2D, + 0x67, + 0x93, + 0x1C, + 0x91, + 0xF9, + 0x9C, + 0x66, + 0x2A, + 0x81, + 0x20, + 0x95, + 0xF8, + 0xE3, + 0x4D, + 0x5A, + 0x6D, + 0x24, + 0x7B, + 0xB9, + 0xEF, + 0xDF, + 0xDA, + 0x58, + 0xA9, + 0x92, + 0x76, + 0x2E, + 0xB3, + 0x39, + 0xC, + 0x29, + 0xCD, + 0x43, + 0xFE, + 0xAB, + 0xF5, + 0x94, + 0x23, + 0x16, + 0x80, + 0xC0, + 0x12, + 0x4C, + 0xE9, + 0x48, + 0x19, + 0x8, + 0xAE, + 0x41, + 0x70, + 0x84, + 0x14, + 0xA2, + 0xD5, + 0xB8, + 0x33, + 0x65, + 0xBA, + 0xED, + 0x17, + 0xCF, + 0x96, + 0x1E, + 0x3B, + 0xB, + 0xC2, + 0xC8, + 0xB6, + 0xBB, + 0x8B, + 0xA1, + 0x54, + 0x75, + 0xC4, + 0x10, + 0x5D, + 0xD6, + 0x25, + 0x97, + 0xE6, + 0xFC, + 0x49, + 0xF7, + 0x52, + 0x18, + 0x86, + 0x8D, + 0xCB, + 0xE1, + 0xBF, + 0xD7, + 0x8E, + 0x37, + 0xBE, + 0x82, + 0xCC, + 0x64, + 0x90, + 0x7C, + 0x32, + 0x8F, + 0x4B, + 0xAC, + 0x1A, + 0xEA, + 0xD3, + 0xF4, + 0x6B, + 0x2C, + 0xFF, + 0x55, + 0xA, + 0x45, + 0x9, + 0x89, + 0x1, + 0x30, + 0x2B, + 0xD2, + 0x77, + 0x87, + 0x72, + 0xEB, + 0x36, + 0xDE, + 0x9E, + 0x8C, + 0xDB, + 0x6C, + 0x9B, + 0x5, + 0x2, + 0x4E, + 0xAF, + 0x4, + 0xAD, + 0x74, + 0xC3, + 0xEE, + 0xA6, + 0xF6, + 0xC7, + 0x7D, + 0x40, + 0xD4, + 0xD, + 0x3E, + 0x5B, + 0xEC, + 0x78, + 0xA0, + 0xB1, + 0x44, + 0x73, + 0x47, + 0x5C, + 0x98, + 0x21, + 0x22, + 0x61, + 0x3F, + 0xC6, + 0x7A, + 0x56, + 0xDD, + 0xE7, + 0x85, + 0xC9, + 0x8A, + 0x57, + 0x27, + 0x7, + 0x9A, + 0x3, + 0xA3, + 0x83, + 0xE4, + 0x6A, + 0xA5, + 0x2F, + 0x79, + 0x4F, + ] +) + +ZUC_S0 = SBox( + [ + 0x3E, + 0x72, + 0x5B, + 0x47, + 0xCA, + 0xE0, + 0x00, + 0x33, + 0x04, + 0xD1, + 0x54, + 0x98, + 0x09, + 0xB9, + 0x6D, + 0xCB, + 0x7B, + 0x1B, + 0xF9, + 0x32, + 0xAF, + 0x9D, + 0x6A, + 0xA5, + 0xB8, + 0x2D, + 0xFC, + 0x1D, + 0x08, + 0x53, + 0x03, + 0x90, + 0x4D, + 0x4E, + 0x84, + 0x99, + 0xE4, + 0xCE, + 0xD9, + 0x91, + 0xDD, + 0xB6, + 0x85, + 0x48, + 0x8B, + 0x29, + 0x6E, + 0xAC, + 0xCD, + 0xC1, + 0xF8, + 0x1E, + 0x73, + 0x43, + 0x69, + 0xC6, + 0xB5, + 0xBD, + 0xFD, + 0x39, + 0x63, + 0x20, + 0xD4, + 0x38, + 0x76, + 0x7D, + 0xB2, + 0xA7, + 0xCF, + 0xED, + 0x57, + 0xC5, + 0xF3, + 0x2C, + 0xBB, + 0x14, + 0x21, + 0x06, + 0x55, + 0x9B, + 0xE3, + 0xEF, + 0x5E, + 0x31, + 0x4F, + 0x7F, + 0x5A, + 0xA4, + 0x0D, + 0x82, + 0x51, + 0x49, + 0x5F, + 0xBA, + 0x58, + 0x1C, + 0x4A, + 0x16, + 0xD5, + 0x17, + 0xA8, + 0x92, + 0x24, + 0x1F, + 0x8C, + 0xFF, + 0xD8, + 0xAE, + 0x2E, + 0x01, + 0xD3, + 0xAD, + 0x3B, + 0x4B, + 0xDA, + 0x46, + 0xEB, + 0xC9, + 0xDE, + 0x9A, + 0x8F, + 0x87, + 0xD7, + 0x3A, + 0x80, + 0x6F, + 0x2F, + 0xC8, + 0xB1, + 0xB4, + 0x37, + 0xF7, + 0x0A, + 0x22, + 0x13, + 0x28, + 0x7C, + 0xCC, + 0x3C, + 0x89, + 0xC7, + 0xC3, + 0x96, + 0x56, + 0x07, + 0xBF, + 0x7E, + 0xF0, + 0x0B, + 0x2B, + 0x97, + 0x52, + 0x35, + 0x41, + 0x79, + 0x61, + 0xA6, + 0x4C, + 0x10, + 0xFE, + 0xBC, + 0x26, + 0x95, + 0x88, + 0x8A, + 0xB0, + 0xA3, + 0xFB, + 0xC0, + 0x18, + 0x94, + 0xF2, + 0xE1, + 0xE5, + 0xE9, + 0x5D, + 0xD0, + 0xDC, + 0x11, + 0x66, + 0x64, + 0x5C, + 0xEC, + 0x59, + 0x42, + 0x75, + 0x12, + 0xF5, + 0x74, + 0x9C, + 0xAA, + 0x23, + 0x0E, + 0x86, + 0xAB, + 0xBE, + 0x2A, + 0x02, + 0xE7, + 0x67, + 0xE6, + 0x44, + 0xA2, + 0x6C, + 0xC2, + 0x93, + 0x9F, + 0xF1, + 0xF6, + 0xFA, + 0x36, + 0xD2, + 0x50, + 0x68, + 0x9E, + 0x62, + 0x71, + 0x15, + 0x3D, + 0xD6, + 0x40, + 0xC4, + 0xE2, + 0x0F, + 0x8E, + 0x83, + 0x77, + 0x6B, + 0x25, + 0x05, + 0x3F, + 0x0C, + 0x30, + 0xEA, + 0x70, + 0xB7, + 0xA1, + 0xE8, + 0xA9, + 0x65, + 0x8D, + 0x27, + 0x1A, + 0xDB, + 0x81, + 0xB3, + 0xA0, + 0xF4, + 0x45, + 0x7A, + 0x19, + 0xDF, + 0xEE, + 0x78, + 0x34, + 0x60, + ] +) + +ZUC_S1 = SBox( + [ + 0x55, + 0xC2, + 0x63, + 0x71, + 0x3B, + 0xC8, + 0x47, + 0x86, + 0x9F, + 0x3C, + 0xDA, + 0x5B, + 0x29, + 0xAA, + 0xFD, + 0x77, + 0x8C, + 0xC5, + 0x94, + 0x0C, + 0xA6, + 0x1A, + 0x13, + 0x00, + 0xE3, + 0xA8, + 0x16, + 0x72, + 0x40, + 0xF9, + 0xF8, + 0x42, + 0x44, + 0x26, + 0x68, + 0x96, + 0x81, + 0xD9, + 0x45, + 0x3E, + 0x10, + 0x76, + 0xC6, + 0xA7, + 0x8B, + 0x39, + 0x43, + 0xE1, + 0x3A, + 0xB5, + 0x56, + 0x2A, + 0xC0, + 0x6D, + 0xB3, + 0x05, + 0x22, + 0x66, + 0xBF, + 0xDC, + 0x0B, + 0xFA, + 0x62, + 0x48, + 0xDD, + 0x20, + 0x11, + 0x06, + 0x36, + 0xC9, + 0xC1, + 0xCF, + 0xF6, + 0x27, + 0x52, + 0xBB, + 0x69, + 0xF5, + 0xD4, + 0x87, + 0x7F, + 0x84, + 0x4C, + 0xD2, + 0x9C, + 0x57, + 0xA4, + 0xBC, + 0x4F, + 0x9A, + 0xDF, + 0xFE, + 0xD6, + 0x8D, + 0x7A, + 0xEB, + 0x2B, + 0x53, + 0xD8, + 0x5C, + 0xA1, + 0x14, + 0x17, + 0xFB, + 0x23, + 0xD5, + 0x7D, + 0x30, + 0x67, + 0x73, + 0x08, + 0x09, + 0xEE, + 0xB7, + 0x70, + 0x3F, + 0x61, + 0xB2, + 0x19, + 0x8E, + 0x4E, + 0xE5, + 0x4B, + 0x93, + 0x8F, + 0x5D, + 0xDB, + 0xA9, + 0xAD, + 0xF1, + 0xAE, + 0x2E, + 0xCB, + 0x0D, + 0xFC, + 0xF4, + 0x2D, + 0x46, + 0x6E, + 0x1D, + 0x97, + 0xE8, + 0xD1, + 0xE9, + 0x4D, + 0x37, + 0xA5, + 0x75, + 0x5E, + 0x83, + 0x9E, + 0xAB, + 0x82, + 0x9D, + 0xB9, + 0x1C, + 0xE0, + 0xCD, + 0x49, + 0x89, + 0x01, + 0xB6, + 0xBD, + 0x58, + 0x24, + 0xA2, + 0x5F, + 0x38, + 0x78, + 0x99, + 0x15, + 0x90, + 0x50, + 0xB8, + 0x95, + 0xE4, + 0xD0, + 0x91, + 0xC7, + 0xCE, + 0xED, + 0x0F, + 0xB4, + 0x6F, + 0xA0, + 0xCC, + 0xF0, + 0x02, + 0x4A, + 0x79, + 0xC3, + 0xDE, + 0xA3, + 0xEF, + 0xEA, + 0x51, + 0xE6, + 0x6B, + 0x18, + 0xEC, + 0x1B, + 0x2C, + 0x80, + 0xF7, + 0x74, + 0xE7, + 0xFF, + 0x21, + 0x5A, + 0x6A, + 0x54, + 0x1E, + 0x41, + 0x31, + 0x92, + 0x35, + 0xC4, + 0x33, + 0x07, + 0x0A, + 0xBA, + 0x7E, + 0x0E, + 0x34, + 0x88, + 0xB1, + 0x98, + 0x7C, + 0xF3, + 0x3D, + 0x60, + 0x6C, + 0x7B, + 0xCA, + 0xD3, + 0x1F, + 0x32, + 0x65, + 0x04, + 0x28, + 0x64, + 0xBE, + 0x85, + 0x9B, + 0x2F, + 0x59, + 0x8A, + 0xD7, + 0xB0, + 0x25, + 0xAC, + 0xAF, + 0x12, + 0x03, + 0xE2, + 0xF2, + ] +) # Bijective S-Boxes mapping 7 bits to 7 # ===================================== -WAGE = SBox([ - 0x2e, 0x1c, 0x6d, 0x2b, 0x35, 0x07, 0x7f, 0x3b, 0x28, 0x08, 0x0b, 0x5f, 0x31, 0x11, 0x1b, 0x4d, - 0x6e, 0x54, 0x0d, 0x09, 0x1f, 0x45, 0x75, 0x53, 0x6a, 0x5d, 0x61, 0x00, 0x04, 0x78, 0x06, 0x1e, - 0x37, 0x6f, 0x2f, 0x49, 0x64, 0x34, 0x7d, 0x19, 0x39, 0x33, 0x43, 0x57, 0x60, 0x62, 0x13, 0x05, - 0x77, 0x47, 0x4f, 0x4b, 0x1d, 0x2d, 0x24, 0x48, 0x74, 0x58, 0x25, 0x5e, 0x5a, 0x76, 0x41, 0x42, - 0x27, 0x3e, 0x6c, 0x01, 0x2c, 0x3c, 0x4e, 0x1a, 0x21, 0x2a, 0x0a, 0x55, 0x3a, 0x38, 0x18, 0x7e, - 0x0c, 0x63, 0x67, 0x56, 0x50, 0x7c, 0x32, 0x7a, 0x68, 0x02, 0x6b, 0x17, 0x7b, 0x59, 0x71, 0x0f, - 0x30, 0x10, 0x22, 0x3d, 0x40, 0x69, 0x52, 0x14, 0x36, 0x44, 0x46, 0x03, 0x16, 0x65, 0x66, 0x72, - 0x12, 0x0e, 0x29, 0x4a, 0x4c, 0x70, 0x15, 0x26, 0x79, 0x51, 0x23, 0x3f, 0x73, 0x5b, 0x20, 0x5c]) +WAGE = SBox([0x2E, 0x1C, 0x6D, 0x2B, 0x35, 0x07, 0x7F, 0x3B, 0x28, 0x08, 0x0B, 0x5F, 0x31, 0x11, 0x1B, 0x4D, 0x6E, 0x54, 0x0D, 0x09, 0x1F, 0x45, 0x75, 0x53, 0x6A, 0x5D, 0x61, 0x00, 0x04, 0x78, 0x06, 0x1E, 0x37, 0x6F, 0x2F, 0x49, 0x64, 0x34, 0x7D, 0x19, 0x39, 0x33, 0x43, 0x57, 0x60, 0x62, 0x13, 0x05, 0x77, 0x47, 0x4F, 0x4B, 0x1D, 0x2D, 0x24, 0x48, 0x74, 0x58, 0x25, 0x5E, 0x5A, 0x76, 0x41, 0x42, 0x27, 0x3E, 0x6C, 0x01, 0x2C, 0x3C, 0x4E, 0x1A, 0x21, 0x2A, 0x0A, 0x55, 0x3A, 0x38, 0x18, 0x7E, 0x0C, 0x63, 0x67, 0x56, 0x50, 0x7C, 0x32, 0x7A, 0x68, 0x02, 0x6B, 0x17, 0x7B, 0x59, 0x71, 0x0F, 0x30, 0x10, 0x22, 0x3D, 0x40, 0x69, 0x52, 0x14, 0x36, 0x44, 0x46, 0x03, 0x16, 0x65, 0x66, 0x72, 0x12, 0x0E, 0x29, 0x4A, 0x4C, 0x70, 0x15, 0x26, 0x79, 0x51, 0x23, 0x3F, 0x73, 0x5B, 0x20, 0x5C]) # Bijective S-Boxes mapping 6 bits to 6 # ===================================== -Fides_6 = SBox([ - 0x36,0x00,0x30,0x0d,0x0f,0x12,0x23,0x35,0x3f,0x19,0x2d,0x34,0x03,0x14,0x21,0x29, - 0x08,0x0a,0x39,0x25,0x3b,0x24,0x22,0x02,0x1a,0x32,0x3a,0x18,0x3c,0x13,0x0e,0x2a, - 0x2e,0x3d,0x05,0x31,0x1f,0x0b,0x1c,0x04,0x0c,0x1e,0x37,0x16,0x09,0x06,0x20,0x17, - 0x1b,0x27,0x15,0x11,0x10,0x1d,0x3e,0x01,0x28,0x2f,0x33,0x38,0x07,0x2b,0x26,0x2c]) +Fides_6 = SBox([0x36, 0x00, 0x30, 0x0D, 0x0F, 0x12, 0x23, 0x35, 0x3F, 0x19, 0x2D, 0x34, 0x03, 0x14, 0x21, 0x29, 0x08, 0x0A, 0x39, 0x25, 0x3B, 0x24, 0x22, 0x02, 0x1A, 0x32, 0x3A, 0x18, 0x3C, 0x13, 0x0E, 0x2A, 0x2E, 0x3D, 0x05, 0x31, 0x1F, 0x0B, 0x1C, 0x04, 0x0C, 0x1E, 0x37, 0x16, 0x09, 0x06, 0x20, 0x17, 0x1B, 0x27, 0x15, 0x11, 0x10, 0x1D, 0x3E, 0x01, 0x28, 0x2F, 0x33, 0x38, 0x07, 0x2B, 0x26, 0x2C]) -APN_6 = SBox([ - 0x0,0x36,0x30,0xd,0xf,0x12,0x35,0x23,0x19,0x3f,0x2d,0x34,0x3,0x14,0x29,0x21, - 0x3b,0x24,0x2,0x22,0xa,0x8,0x39,0x25,0x3c,0x13,0x2a,0xe,0x32,0x1a,0x3a,0x18, - 0x27,0x1b,0x15,0x11,0x10,0x1d,0x1,0x3e,0x2f,0x28,0x33,0x38,0x7,0x2b,0x2c,0x26, - 0x1f,0xb,0x4,0x1c,0x3d,0x2e,0x5,0x31,0x9,0x6,0x17,0x20,0x1e,0xc,0x37,0x16]) +APN_6 = SBox([0x0, 0x36, 0x30, 0xD, 0xF, 0x12, 0x35, 0x23, 0x19, 0x3F, 0x2D, 0x34, 0x3, 0x14, 0x29, 0x21, 0x3B, 0x24, 0x2, 0x22, 0xA, 0x8, 0x39, 0x25, 0x3C, 0x13, 0x2A, 0xE, 0x32, 0x1A, 0x3A, 0x18, 0x27, 0x1B, 0x15, 0x11, 0x10, 0x1D, 0x1, 0x3E, 0x2F, 0x28, 0x33, 0x38, 0x7, 0x2B, 0x2C, 0x26, 0x1F, 0xB, 0x4, 0x1C, 0x3D, 0x2E, 0x5, 0x31, 0x9, 0x6, 0x17, 0x20, 0x1E, 0xC, 0x37, 0x16]) -SC2000_6 = SBox([ - 47,59,25,42,15,23,28,39,26,38,36,19,60,24,29,56, - 37,63,20,61,55,2,30,44,9,10,6,22,53,48,51,11, - 62,52,35,18,14,46,0,54,17,40,27,4,31,8,5,12, - 3,16,41,34,33,7,45,49,50,58,1,21,43,57,32,13]) +SC2000_6 = SBox([47, 59, 25, 42, 15, 23, 28, 39, 26, 38, 36, 19, 60, 24, 29, 56, 37, 63, 20, 61, 55, 2, 30, 44, 9, 10, 6, 22, 53, 48, 51, 11, 62, 52, 35, 18, 14, 46, 0, 54, 17, 40, 27, 4, 31, 8, 5, 12, 3, 16, 41, 34, 33, 7, 45, 49, 50, 58, 1, 21, 43, 57, 32, 13]) # Bijective S-Boxes mapping 5 bits to 5 # ===================================== -Ascon = SBox([ - 0x04,0x0b,0x1f,0x14,0x1a,0x15,0x09,0x02,0x1b,0x05,0x08,0x12,0x1d,0x03,0x06,0x1c, - 0x1e,0x13,0x07,0x0e,0x00,0x0d,0x11,0x18,0x10,0x0c,0x01,0x19,0x16,0x0a,0x0f,0x17]) +Ascon = SBox([0x04, 0x0B, 0x1F, 0x14, 0x1A, 0x15, 0x09, 0x02, 0x1B, 0x05, 0x08, 0x12, 0x1D, 0x03, 0x06, 0x1C, 0x1E, 0x13, 0x07, 0x0E, 0x00, 0x0D, 0x11, 0x18, 0x10, 0x0C, 0x01, 0x19, 0x16, 0x0A, 0x0F, 0x17]) ISAP = Ascon -DryGASCON128 = SBox([0x04, 0x0f, 0x1b, 0x01, 0x0b, 0x00, 0x17, 0x0d, 0x1f, - 0x1c, 0x02, 0x10, 0x12, 0x11, 0x0c, 0x1e, 0x1a, 0x19, - 0x14, 0x06, 0x15, 0x16, 0x18, 0x0a, 0x05, 0x0e, 0x09, - 0x13, 0x08, 0x03, 0x07, 0x1d]) +DryGASCON128 = SBox([0x04, 0x0F, 0x1B, 0x01, 0x0B, 0x00, 0x17, 0x0D, 0x1F, 0x1C, 0x02, 0x10, 0x12, 0x11, 0x0C, 0x1E, 0x1A, 0x19, 0x14, 0x06, 0x15, 0x16, 0x18, 0x0A, 0x05, 0x0E, 0x09, 0x13, 0x08, 0x03, 0x07, 0x1D]) -Fides_5 = SBox([ - 0x01,0x00,0x19,0x1a,0x11,0x1d,0x15,0x1b,0x14,0x05,0x04,0x17,0x0e,0x12,0x02,0x1c, - 0x0f,0x08,0x06,0x03,0x0d,0x07,0x18,0x10,0x1e,0x09,0x1f,0x0a,0x16,0x0c,0x0b,0x13]) +Fides_5 = SBox([0x01, 0x00, 0x19, 0x1A, 0x11, 0x1D, 0x15, 0x1B, 0x14, 0x05, 0x04, 0x17, 0x0E, 0x12, 0x02, 0x1C, 0x0F, 0x08, 0x06, 0x03, 0x0D, 0x07, 0x18, 0x10, 0x1E, 0x09, 0x1F, 0x0A, 0x16, 0x0C, 0x0B, 0x13]) -SC2000_5 = SBox([ - 20,26,7,31,19,12,10,15,22,30,13,14,4,24,9, - 18,27,11,1,21,6,16,2,28,23,5,8,3,0,17,29,25]) +SC2000_5 = SBox([20, 26, 7, 31, 19, 12, 10, 15, 22, 30, 13, 14, 4, 24, 9, 18, 27, 11, 1, 21, 6, 16, 2, 28, 23, 5, 8, 3, 0, 17, 29, 25]) -Shamash = SBox([16, 14, 13, 2, 11, 17, 21, 30, 7, 24, 18, 28, 26, 1, 12, 6, - 31, 25, 0, 23, 20, 22, 8, 27, 4, 3, 19, 5, 9, 10, 29, 15]) +Shamash = SBox([16, 14, 13, 2, 11, 17, 21, 30, 7, 24, 18, 28, 26, 1, 12, 6, 31, 25, 0, 23, 20, 22, 8, 27, 4, 3, 19, 5, 9, 10, 29, 15]) -SYCON = SBox([8, 19, 30, 7, 6, 25, 16, 13, 22, 15, 3, 24, 17, 12, 4, 27, 11, 0, - 29, 20, 1, 14, 23, 26, 28, 21, 9, 2, 31, 18, 10, 5]) +SYCON = SBox([8, 19, 30, 7, 6, 25, 16, 13, 22, 15, 3, 24, 17, 12, 4, 27, 11, 0, 29, 20, 1, 14, 23, 26, 28, 21, 9, 2, 31, 18, 10, 5]) # Bijective S-Boxes mapping 4 bits to 4 # ===================================== -Elephant = SBox([0xE, 0xD, 0xB, 0x0, 0x2, 0x1, 0x4, 0xF, 0x7, 0xA, 0x8, 0x5, - 0x9, 0xC, 0x3, 0x6]) -KNOT = SBox([0x4, 0x0, 0xA, 0x7, 0xB, 0xE, 0x1, 0xD, 0x9, 0xF, 0x6, 0x8, - 0x5, 0x2, 0xC, 0x3]) -Pyjamask_4 = SBox([0x2, 0xd, 0x3, 0x9, 0x7, 0xb, 0xa, 0x6, 0xe, 0x0, 0xf, 0x4, - 0x8, 0x5, 0x1, 0xc]) -SATURNIN_0 = SBox([0x0, 0x6, 0xE, 0x1, 0xF, 0x4, 0x7, 0xD, 0x9, 0x8, 0xC, 0x5, - 0x2, 0xA, 0x3, 0xB]) -SATURNIN_1 = SBox([0x0, 0x9, 0xD, 0x2, 0xF, 0x1, 0xB, 0x7, 0x6, 0x4, 0x5, 0x3, - 0x8, 0xC, 0xA, 0xE]) -Spook = SBox([0x0, 0x8, 0x1, 0xF, 0x2, 0xA, 0x7, 0x9, 0x4, 0xD, 0x5, 0x6, 0xE, - 0x3, 0xB, 0xC]) +Elephant = SBox([0xE, 0xD, 0xB, 0x0, 0x2, 0x1, 0x4, 0xF, 0x7, 0xA, 0x8, 0x5, 0x9, 0xC, 0x3, 0x6]) +KNOT = SBox([0x4, 0x0, 0xA, 0x7, 0xB, 0xE, 0x1, 0xD, 0x9, 0xF, 0x6, 0x8, 0x5, 0x2, 0xC, 0x3]) +Pyjamask_4 = SBox([0x2, 0xD, 0x3, 0x9, 0x7, 0xB, 0xA, 0x6, 0xE, 0x0, 0xF, 0x4, 0x8, 0x5, 0x1, 0xC]) +SATURNIN_0 = SBox([0x0, 0x6, 0xE, 0x1, 0xF, 0x4, 0x7, 0xD, 0x9, 0x8, 0xC, 0x5, 0x2, 0xA, 0x3, 0xB]) +SATURNIN_1 = SBox([0x0, 0x9, 0xD, 0x2, 0xF, 0x1, 0xB, 0x7, 0x6, 0x4, 0x5, 0x3, 0x8, 0xC, 0xA, 0xE]) +Spook = SBox([0x0, 0x8, 0x1, 0xF, 0x2, 0xA, 0x7, 0x9, 0x4, 0xD, 0x5, 0x6, 0xE, 0x3, 0xB, 0xC]) Clyde = Spook Shadow = Spook -TRIFLE = SBox([0x0, 0xC, 0x9, 0x7, 0x3, 0x5, 0xE, 0x4, 0x6, 0xB, 0xA, 0x2, - 0xD, 0x1, 0x8, 0xF]) -Yarara = SBox([0x4, 0x7, 0x1, 0xC, 0x2, 0x8, 0xF, 0x3, 0xD, 0xA, 0xe, 0x9, 0xB, - 0x6, 0x5, 0x0]) +TRIFLE = SBox([0x0, 0xC, 0x9, 0x7, 0x3, 0x5, 0xE, 0x4, 0x6, 0xB, 0xA, 0x2, 0xD, 0x1, 0x8, 0xF]) +Yarara = SBox([0x4, 0x7, 0x1, 0xC, 0x2, 0x8, 0xF, 0x3, 0xD, 0xA, 0xE, 0x9, 0xB, 0x6, 0x5, 0x0]) Coral = Yarara # DES -DES_S1_1 = SBox([14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7]) -DES_S1_2 = SBox([0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8]) -DES_S1_3 = SBox([4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0]) -DES_S1_4 = SBox([15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13]) - -DES_S2_1 = SBox([15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10]) -DES_S2_2 = SBox([3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5]) -DES_S2_3 = SBox([0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15]) -DES_S2_4 = SBox([13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9]) - -DES_S3_1 = SBox([10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8]) -DES_S3_2 = SBox([13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1]) -DES_S3_3 = SBox([13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7]) -DES_S3_4 = SBox([1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12]) - -DES_S4_1 = SBox([7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15]) -DES_S4_2 = SBox([13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9]) -DES_S4_3 = SBox([10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4]) -DES_S4_4 = SBox([3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14]) - -DES_S5_1 = SBox([2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9]) -DES_S5_2 = SBox([14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6]) -DES_S5_3 = SBox([4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14]) -DES_S5_4 = SBox([11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3]) - -DES_S6_1 = SBox([12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11]) -DES_S6_2 = SBox([10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8]) -DES_S6_3 = SBox([9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6]) -DES_S6_4 = SBox([4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13]) - -DES_S7_1 = SBox([4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1]) -DES_S7_2 = SBox([13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6]) -DES_S7_3 = SBox([1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2]) -DES_S7_4 = SBox([6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12]) - -DES_S8_1 = SBox([13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7]) -DES_S8_2 = SBox([1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2]) -DES_S8_3 = SBox([7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8]) -DES_S8_4 = SBox([2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11]) +DES_S1_1 = SBox([14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7]) +DES_S1_2 = SBox([0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8]) +DES_S1_3 = SBox([4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0]) +DES_S1_4 = SBox([15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13]) + +DES_S2_1 = SBox([15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10]) +DES_S2_2 = SBox([3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5]) +DES_S2_3 = SBox([0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15]) +DES_S2_4 = SBox([13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9]) + +DES_S3_1 = SBox([10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8]) +DES_S3_2 = SBox([13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1]) +DES_S3_3 = SBox([13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7]) +DES_S3_4 = SBox([1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12]) + +DES_S4_1 = SBox([7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15]) +DES_S4_2 = SBox([13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9]) +DES_S4_3 = SBox([10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4]) +DES_S4_4 = SBox([3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14]) + +DES_S5_1 = SBox([2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9]) +DES_S5_2 = SBox([14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6]) +DES_S5_3 = SBox([4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14]) +DES_S5_4 = SBox([11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3]) + +DES_S6_1 = SBox([12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11]) +DES_S6_2 = SBox([10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8]) +DES_S6_3 = SBox([9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6]) +DES_S6_4 = SBox([4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13]) + +DES_S7_1 = SBox([4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1]) +DES_S7_2 = SBox([13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6]) +DES_S7_3 = SBox([1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2]) +DES_S7_4 = SBox([6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12]) + +DES_S8_1 = SBox([13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7]) +DES_S8_2 = SBox([1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2]) +DES_S8_3 = SBox([7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8]) +DES_S8_4 = SBox([2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11]) # source: http://www.quadibloc.com/crypto/co0401.htm -Lucifer_S0 = SBox([12,15,7,10,14,13,11,0,2,6,3,1,9,4,5,8]) -Lucifer_S1 = SBox([7,2,14,9,3,11,0,4,12,13,1,10,6,15,8,5]) +Lucifer_S0 = SBox([12, 15, 7, 10, 14, 13, 11, 0, 2, 6, 3, 1, 9, 4, 5, 8]) +Lucifer_S1 = SBox([7, 2, 14, 9, 3, 11, 0, 4, 12, 13, 1, 10, 6, 15, 8, 5]) # First GOST block cipher and its modification. # ref: https://en.wikipedia.org/wiki/GOST_28147-89 -GOST_1 = SBox([0x4,0xa,0x9,0x2,0xd,0x8,0x0,0xe,0x6,0xb,0x1,0xc,0x7,0xf,0x5,0x3]) -GOST_2 = SBox([0xe,0xb,0x4,0xc,0x6,0xd,0xf,0xa,0x2,0x3,0x8,0x1,0x0,0x7,0x5,0x9]) -GOST_3 = SBox([0x5,0x8,0x1,0xd,0xa,0x3,0x4,0x2,0xe,0xf,0xc,0x7,0x6,0x0,0x9,0xb]) -GOST_4 = SBox([0x7,0xd,0xa,0x1,0x0,0x8,0x9,0xf,0xe,0x4,0x6,0xc,0xb,0x2,0x5,0x3]) -GOST_5 = SBox([0x6,0xc,0x7,0x1,0x5,0xf,0xd,0x8,0x4,0xa,0x9,0xe,0x0,0x3,0xb,0x2]) -GOST_6 = SBox([0x4,0xb,0xa,0x0,0x7,0x2,0x1,0xd,0x3,0x6,0x8,0x5,0x9,0xc,0xf,0xe]) -GOST_7 = SBox([0xd,0xb,0x4,0x1,0x3,0xf,0x5,0x9,0x0,0xa,0xe,0x7,0x6,0x8,0x2,0xc]) -GOST_8 = SBox([0x1,0xf,0xd,0x0,0x5,0x7,0xa,0x4,0x9,0x2,0x3,0xe,0x6,0xb,0x8,0xc]) +GOST_1 = SBox([0x4, 0xA, 0x9, 0x2, 0xD, 0x8, 0x0, 0xE, 0x6, 0xB, 0x1, 0xC, 0x7, 0xF, 0x5, 0x3]) +GOST_2 = SBox([0xE, 0xB, 0x4, 0xC, 0x6, 0xD, 0xF, 0xA, 0x2, 0x3, 0x8, 0x1, 0x0, 0x7, 0x5, 0x9]) +GOST_3 = SBox([0x5, 0x8, 0x1, 0xD, 0xA, 0x3, 0x4, 0x2, 0xE, 0xF, 0xC, 0x7, 0x6, 0x0, 0x9, 0xB]) +GOST_4 = SBox([0x7, 0xD, 0xA, 0x1, 0x0, 0x8, 0x9, 0xF, 0xE, 0x4, 0x6, 0xC, 0xB, 0x2, 0x5, 0x3]) +GOST_5 = SBox([0x6, 0xC, 0x7, 0x1, 0x5, 0xF, 0xD, 0x8, 0x4, 0xA, 0x9, 0xE, 0x0, 0x3, 0xB, 0x2]) +GOST_6 = SBox([0x4, 0xB, 0xA, 0x0, 0x7, 0x2, 0x1, 0xD, 0x3, 0x6, 0x8, 0x5, 0x9, 0xC, 0xF, 0xE]) +GOST_7 = SBox([0xD, 0xB, 0x4, 0x1, 0x3, 0xF, 0x5, 0x9, 0x0, 0xA, 0xE, 0x7, 0x6, 0x8, 0x2, 0xC]) +GOST_8 = SBox([0x1, 0xF, 0xD, 0x0, 0x5, 0x7, 0xA, 0x4, 0x9, 0x2, 0x3, 0xE, 0x6, 0xB, 0x8, 0xC]) # ref: https://eprint.iacr.org/2015/065.pdf -GOST2_1 = SBox([0x6,0xA,0xF,0x4,0x3,0x8,0x5,0x0,0xD,0xE,0x7,0x1,0x2,0xB,0xC,0x9]) -GOST2_2 = SBox([0xE,0x0,0x8,0x1,0x7,0xA,0x5,0x6,0xD,0x2,0x4,0x9,0x3,0xF,0xC,0xB]) - -Magma_1 = SBox([0xC,0x4,0x6,0x2,0xA,0x5,0xB,0x9,0xE,0x8,0xD,0x7,0x0,0x3,0xF,0x1]) -Magma_2 = SBox([0x6,0x8,0x2,0x3,0x9,0xA,0x5,0xC,0x1,0xE,0x4,0x7,0xB,0xD,0x0,0xF]) -Magma_3 = SBox([0xB,0x3,0x5,0x8,0x2,0xF,0xA,0xD,0xE,0x1,0x7,0x4,0xC,0x9,0x6,0x0]) -Magma_4 = SBox([0xC,0x8,0x2,0x1,0xD,0x4,0xF,0x6,0x7,0x0,0xA,0x5,0x3,0xE,0x9,0xB]) -Magma_5 = SBox([0x7,0xF,0x5,0xA,0x8,0x1,0x6,0xD,0x0,0x9,0x3,0xE,0xB,0x4,0x2,0xC]) -Magma_6 = SBox([0x5,0xD,0xF,0x6,0x9,0x2,0xC,0xA,0xB,0x7,0x8,0x1,0x4,0x3,0xE,0x0]) -Magma_7 = SBox([0x8,0xE,0x2,0x5,0x6,0x9,0x1,0xC,0xF,0x4,0xB,0x0,0xD,0xA,0x3,0x7]) -Magma_8 = SBox([0x1,0x7,0xE,0xD,0x0,0x5,0x8,0x3,0x4,0xF,0xA,0x6,0x9,0xC,0xB,0x2]) - -GOST_IETF_1 = SBox([0x9,0x6,0x3,0x2,0x8,0xb,0x1,0x7,0xa,0x4,0xe,0xf,0xc,0x0,0xd,0x5]) -GOST_IETF_2 = SBox([0x3,0x7,0xe,0x9,0x8,0xa,0xf,0x0,0x5,0x2,0x6,0xc,0xb,0x4,0xd,0x1]) -GOST_IETF_3 = SBox([0xe,0x4,0x6,0x2,0xb,0x3,0xd,0x8,0xc,0xf,0x5,0xa,0x0,0x7,0x1,0x9]) -GOST_IETF_4 = SBox([0xe,0x7,0xa,0xc,0xd,0x1,0x3,0x9,0x0,0x2,0xb,0x4,0xf,0x8,0x5,0x6]) -GOST_IETF_5 = SBox([0xb,0x5,0x1,0x9,0x8,0xd,0xf,0x0,0xe,0x4,0x2,0x3,0xc,0x7,0xa,0x6]) -GOST_IETF_6 = SBox([0x3,0xa,0xd,0xc,0x1,0x2,0x0,0xb,0x7,0x5,0x9,0x4,0x8,0xf,0xe,0x6]) -GOST_IETF_7 = SBox([0x1,0xd,0x2,0x9,0x7,0xa,0x6,0x0,0x8,0xc,0x4,0x5,0xf,0x3,0xb,0xe]) -GOST_IETF_8 = SBox([0xb,0xa,0xf,0x5,0x0,0xc,0xe,0x8,0x6,0x2,0x3,0x9,0x1,0x7,0xd,0x4]) +GOST2_1 = SBox([0x6, 0xA, 0xF, 0x4, 0x3, 0x8, 0x5, 0x0, 0xD, 0xE, 0x7, 0x1, 0x2, 0xB, 0xC, 0x9]) +GOST2_2 = SBox([0xE, 0x0, 0x8, 0x1, 0x7, 0xA, 0x5, 0x6, 0xD, 0x2, 0x4, 0x9, 0x3, 0xF, 0xC, 0xB]) + +Magma_1 = SBox([0xC, 0x4, 0x6, 0x2, 0xA, 0x5, 0xB, 0x9, 0xE, 0x8, 0xD, 0x7, 0x0, 0x3, 0xF, 0x1]) +Magma_2 = SBox([0x6, 0x8, 0x2, 0x3, 0x9, 0xA, 0x5, 0xC, 0x1, 0xE, 0x4, 0x7, 0xB, 0xD, 0x0, 0xF]) +Magma_3 = SBox([0xB, 0x3, 0x5, 0x8, 0x2, 0xF, 0xA, 0xD, 0xE, 0x1, 0x7, 0x4, 0xC, 0x9, 0x6, 0x0]) +Magma_4 = SBox([0xC, 0x8, 0x2, 0x1, 0xD, 0x4, 0xF, 0x6, 0x7, 0x0, 0xA, 0x5, 0x3, 0xE, 0x9, 0xB]) +Magma_5 = SBox([0x7, 0xF, 0x5, 0xA, 0x8, 0x1, 0x6, 0xD, 0x0, 0x9, 0x3, 0xE, 0xB, 0x4, 0x2, 0xC]) +Magma_6 = SBox([0x5, 0xD, 0xF, 0x6, 0x9, 0x2, 0xC, 0xA, 0xB, 0x7, 0x8, 0x1, 0x4, 0x3, 0xE, 0x0]) +Magma_7 = SBox([0x8, 0xE, 0x2, 0x5, 0x6, 0x9, 0x1, 0xC, 0xF, 0x4, 0xB, 0x0, 0xD, 0xA, 0x3, 0x7]) +Magma_8 = SBox([0x1, 0x7, 0xE, 0xD, 0x0, 0x5, 0x8, 0x3, 0x4, 0xF, 0xA, 0x6, 0x9, 0xC, 0xB, 0x2]) + +GOST_IETF_1 = SBox([0x9, 0x6, 0x3, 0x2, 0x8, 0xB, 0x1, 0x7, 0xA, 0x4, 0xE, 0xF, 0xC, 0x0, 0xD, 0x5]) +GOST_IETF_2 = SBox([0x3, 0x7, 0xE, 0x9, 0x8, 0xA, 0xF, 0x0, 0x5, 0x2, 0x6, 0xC, 0xB, 0x4, 0xD, 0x1]) +GOST_IETF_3 = SBox([0xE, 0x4, 0x6, 0x2, 0xB, 0x3, 0xD, 0x8, 0xC, 0xF, 0x5, 0xA, 0x0, 0x7, 0x1, 0x9]) +GOST_IETF_4 = SBox([0xE, 0x7, 0xA, 0xC, 0xD, 0x1, 0x3, 0x9, 0x0, 0x2, 0xB, 0x4, 0xF, 0x8, 0x5, 0x6]) +GOST_IETF_5 = SBox([0xB, 0x5, 0x1, 0x9, 0x8, 0xD, 0xF, 0x0, 0xE, 0x4, 0x2, 0x3, 0xC, 0x7, 0xA, 0x6]) +GOST_IETF_6 = SBox([0x3, 0xA, 0xD, 0xC, 0x1, 0x2, 0x0, 0xB, 0x7, 0x5, 0x9, 0x4, 0x8, 0xF, 0xE, 0x6]) +GOST_IETF_7 = SBox([0x1, 0xD, 0x2, 0x9, 0x7, 0xA, 0x6, 0x0, 0x8, 0xC, 0x4, 0x5, 0xF, 0x3, 0xB, 0xE]) +GOST_IETF_8 = SBox([0xB, 0xA, 0xF, 0x5, 0x0, 0xC, 0xE, 0x8, 0x6, 0x2, 0x3, 0x9, 0x1, 0x7, 0xD, 0x4]) # Hummingbird-2 -Hummingbird_2_S1 = SBox([7,12,14,9,2,1,5,15,11,6,13,0,4,8,10,3]) -Hummingbird_2_S2 = SBox([4,10,1,6,8,15,7,12,3,0,14,13,5,9,11,2]) -Hummingbird_2_S3 = SBox([2,15,12,1,5,6,10,13,14,8,3,4,0,11,9,7]) -Hummingbird_2_S4 = SBox([15,4,5,8,9,7,2,1,10,3,0,14,6,12,13,11]) +Hummingbird_2_S1 = SBox([7, 12, 14, 9, 2, 1, 5, 15, 11, 6, 13, 0, 4, 8, 10, 3]) +Hummingbird_2_S2 = SBox([4, 10, 1, 6, 8, 15, 7, 12, 3, 0, 14, 13, 5, 9, 11, 2]) +Hummingbird_2_S3 = SBox([2, 15, 12, 1, 5, 6, 10, 13, 14, 8, 3, 4, 0, 11, 9, 7]) +Hummingbird_2_S4 = SBox([15, 4, 5, 8, 9, 7, 2, 1, 10, 3, 0, 14, 6, 12, 13, 11]) # LBlock LBlock_0 = SBox([14, 9, 15, 0, 13, 4, 10, 11, 1, 2, 8, 3, 7, 6, 12, 5]) @@ -1622,105 +14461,102 @@ def chi(n): LBlock_9 = SBox([11, 5, 15, 0, 7, 2, 9, 13, 4, 8, 1, 12, 14, 10, 3, 6]) # SERPENT -SERPENT_S0 = SBox([3,8,15,1,10,6,5,11,14,13,4,2,7,0,9,12]) -SERPENT_S1 = SBox([15,12,2,7,9,0,5,10,1,11,14,8,6,13,3,4]) -SERPENT_S2 = SBox([8,6,7,9,3,12,10,15,13,1,14,4,0,11,5,2]) -SERPENT_S3 = SBox([0,15,11,8,12,9,6,3,13,1,2,4,10,7,5,14]) -SERPENT_S4 = SBox([1,15,8,3,12,0,11,6,2,5,4,10,9,14,7,13]) -SERPENT_S5 = SBox([15,5,2,11,4,10,9,12,0,3,14,8,13,6,7,1]) -SERPENT_S6 = SBox([7,2,12,5,8,4,6,11,14,9,1,15,13,3,10,0]) -SERPENT_S7 = SBox([1,13,15,0,14,8,2,11,7,4,12,10,9,3,5,6]) +SERPENT_S0 = SBox([3, 8, 15, 1, 10, 6, 5, 11, 14, 13, 4, 2, 7, 0, 9, 12]) +SERPENT_S1 = SBox([15, 12, 2, 7, 9, 0, 5, 10, 1, 11, 14, 8, 6, 13, 3, 4]) +SERPENT_S2 = SBox([8, 6, 7, 9, 3, 12, 10, 15, 13, 1, 14, 4, 0, 11, 5, 2]) +SERPENT_S3 = SBox([0, 15, 11, 8, 12, 9, 6, 3, 13, 1, 2, 4, 10, 7, 5, 14]) +SERPENT_S4 = SBox([1, 15, 8, 3, 12, 0, 11, 6, 2, 5, 4, 10, 9, 14, 7, 13]) +SERPENT_S5 = SBox([15, 5, 2, 11, 4, 10, 9, 12, 0, 3, 14, 8, 13, 6, 7, 1]) +SERPENT_S6 = SBox([7, 2, 12, 5, 8, 4, 6, 11, 14, 9, 1, 15, 13, 3, 10, 0]) +SERPENT_S7 = SBox([1, 13, 15, 0, 14, 8, 2, 11, 7, 4, 12, 10, 9, 3, 5, 6]) # Other Block ciphers -KLEIN = SBox([0x7,0x4,0xA,0x9,0x1,0xF,0xB,0x0,0xC,0x3,0x2,0x6,0x8,0xE,0xD,0x5]) -MIBS = SBox([4,15,3,8,13,10,12,0,11,5,7,14,2,6,1,9]) -Midori_Sb0 = SBox([0xc,0xa,0xd,0x3,0xe,0xb,0xf,0x7,0x8,0x9,0x1,0x5,0x0,0x2,0x4,0x6]) +KLEIN = SBox([0x7, 0x4, 0xA, 0x9, 0x1, 0xF, 0xB, 0x0, 0xC, 0x3, 0x2, 0x6, 0x8, 0xE, 0xD, 0x5]) +MIBS = SBox([4, 15, 3, 8, 13, 10, 12, 0, 11, 5, 7, 14, 2, 6, 1, 9]) +Midori_Sb0 = SBox([0xC, 0xA, 0xD, 0x3, 0xE, 0xB, 0xF, 0x7, 0x8, 0x9, 0x1, 0x5, 0x0, 0x2, 0x4, 0x6]) MANTIS = Midori_Sb0 WARP = Midori_Sb0 CRAFT = Midori_Sb0 -Midori_Sb1 = SBox([0x1,0x0,0x5,0x3,0xe,0x2,0xf,0x7,0xd,0xa,0x9,0xb,0xc,0x8,0x4,0x6]) -Noekeon = SBox([0x7,0xA,0x2,0xC,0x4,0x8,0xF,0x0,0x5,0x9,0x1,0xE,0x3,0xD,0xB,0x6]) -Piccolo = SBox([0xe,0x4,0xb,0x2,0x3,0x8,0x0,0x9,0x1,0xa,0x7,0xf,0x6,0xc,0x5,0xd]) -Panda = SBox([0x0,0x1,0x3,0x2,0xf,0xc,0x9,0xb,0xa,0x6,0x8,0x7,0x5,0xe,0xd,0x4]) -PRESENT = SBox([0xC,0x5,0x6,0xB,0x9,0x0,0xA,0xD,0x3,0xE,0xF,0x8,0x4,0x7,0x1,0x2]) +Midori_Sb1 = SBox([0x1, 0x0, 0x5, 0x3, 0xE, 0x2, 0xF, 0x7, 0xD, 0xA, 0x9, 0xB, 0xC, 0x8, 0x4, 0x6]) +Noekeon = SBox([0x7, 0xA, 0x2, 0xC, 0x4, 0x8, 0xF, 0x0, 0x5, 0x9, 0x1, 0xE, 0x3, 0xD, 0xB, 0x6]) +Piccolo = SBox([0xE, 0x4, 0xB, 0x2, 0x3, 0x8, 0x0, 0x9, 0x1, 0xA, 0x7, 0xF, 0x6, 0xC, 0x5, 0xD]) +Panda = SBox([0x0, 0x1, 0x3, 0x2, 0xF, 0xC, 0x9, 0xB, 0xA, 0x6, 0x8, 0x7, 0x5, 0xE, 0xD, 0x4]) +PRESENT = SBox([0xC, 0x5, 0x6, 0xB, 0x9, 0x0, 0xA, 0xD, 0x3, 0xE, 0xF, 0x8, 0x4, 0x7, 0x1, 0x2]) CiliPadi = PRESENT PHOTON = PRESENT ORANGE = PHOTON -GIFT = SBox([0x1,0xa,0x4,0xc,0x6,0xf,0x3,0x9,0x2,0xd,0xb,0x7,0x5,0x0,0x8,0xe]) +GIFT = SBox([0x1, 0xA, 0x4, 0xC, 0x6, 0xF, 0x3, 0x9, 0x2, 0xD, 0xB, 0x7, 0x5, 0x0, 0x8, 0xE]) HYENA = GIFT Fountain_1 = GIFT TGIF = GIFT -Fountain_2 = SBox([0x9, 0x5, 0x6, 0xD, 0x8, 0xA, 0x7, 0x2, 0xE, 0x4, 0xC, - 0x1, 0xF, 0x0, 0xB, 0x3]) -Fountain_3 = SBox([0x9, 0xD, 0xE, 0x5, 0x8, 0xA, 0xF, 0x2, 0x6, 0xC, 0x4, - 0x1, 0x7, 0x0, 0xB, 0x3]) -Fountain_4 = SBox([0xB, 0xF, 0xE, 0x8, 0x7, 0xA, 0x2, 0xD, 0x9, 0x3, 0x4, - 0xC, 0x5, 0x0, 0x6, 0x1]) -Pride = SBox([0x0,0x4,0x8,0xf,0x1,0x5,0xe,0x9,0x2,0x7,0xa,0xc,0xb,0xd,0x6,0x3]) -PRINCE = SBox([0xB,0xF,0x3,0x2,0xA,0xC,0x9,0x1,0x6,0x7,0x8,0x0,0xE,0x5,0xD,0x4]) +Fountain_2 = SBox([0x9, 0x5, 0x6, 0xD, 0x8, 0xA, 0x7, 0x2, 0xE, 0x4, 0xC, 0x1, 0xF, 0x0, 0xB, 0x3]) +Fountain_3 = SBox([0x9, 0xD, 0xE, 0x5, 0x8, 0xA, 0xF, 0x2, 0x6, 0xC, 0x4, 0x1, 0x7, 0x0, 0xB, 0x3]) +Fountain_4 = SBox([0xB, 0xF, 0xE, 0x8, 0x7, 0xA, 0x2, 0xD, 0x9, 0x3, 0x4, 0xC, 0x5, 0x0, 0x6, 0x1]) +Pride = SBox([0x0, 0x4, 0x8, 0xF, 0x1, 0x5, 0xE, 0x9, 0x2, 0x7, 0xA, 0xC, 0xB, 0xD, 0x6, 0x3]) +PRINCE = SBox([0xB, 0xF, 0x3, 0x2, 0xA, 0xC, 0x9, 0x1, 0x6, 0x7, 0x8, 0x0, 0xE, 0x5, 0xD, 0x4]) Prost = Pride Qarma_sigma0 = SBox([0, 14, 2, 10, 9, 15, 8, 11, 6, 4, 3, 7, 13, 12, 1, 5]) Qarma_sigma1 = SBox([10, 13, 14, 6, 15, 7, 3, 5, 9, 8, 0, 12, 11, 1, 2, 4]) Qameleon = Qarma_sigma1 Qarma_sigma2 = SBox([11, 6, 8, 15, 12, 0, 9, 14, 3, 7, 4, 5, 13, 2, 1, 10]) -REC_0 = SBox([0x9,0x4,0xF,0xA,0xE,0x1,0x0,0x6,0xC,0x7,0x3,0x8,0x2,0xB,0x5,0xD]) -Rectangle = SBox([0x6,0x5,0xC,0xA,0x1,0xE,0x7,0x9,0xB,0x0,0x3,0xD,0x8,0xF,0x4,0x2]) -SC2000_4 = SBox([2,5,10,12,7,15,1,11,13,6,0,9,4,8,3,14]) -SKINNY_4 = SBox([0xc,0x6,0x9,0x0,0x1,0xa,0x2,0xb,0x3,0x8,0x5,0xd,0x4,0xe,0x7,0xf]) +REC_0 = SBox([0x9, 0x4, 0xF, 0xA, 0xE, 0x1, 0x0, 0x6, 0xC, 0x7, 0x3, 0x8, 0x2, 0xB, 0x5, 0xD]) +Rectangle = SBox([0x6, 0x5, 0xC, 0xA, 0x1, 0xE, 0x7, 0x9, 0xB, 0x0, 0x3, 0xD, 0x8, 0xF, 0x4, 0x2]) +SC2000_4 = SBox([2, 5, 10, 12, 7, 15, 1, 11, 13, 6, 0, 9, 4, 8, 3, 14]) +SKINNY_4 = SBox([0xC, 0x6, 0x9, 0x0, 0x1, 0xA, 0x2, 0xB, 0x3, 0x8, 0x5, 0xD, 0x4, 0xE, 0x7, 0xF]) ForkSkinny_4 = SKINNY_4 Remus_4 = SKINNY_4 -TWINE = SBox([0xC,0x0,0xF,0xA,0x2,0xB,0x9,0x5,0x8,0x3,0xD,0x7,0x1,0xE,0x6,0x4]) +TWINE = SBox([0xC, 0x0, 0xF, 0xA, 0x2, 0xB, 0x9, 0x5, 0x8, 0x3, 0xD, 0x7, 0x1, 0xE, 0x6, 0x4]) # Sub-components of hash functions -Luffa_v1 = SBox([0x7,0xd,0xb,0xa,0xc,0x4,0x8,0x3,0x5,0xf,0x6,0x0,0x9,0x1,0x2,0xe]) -Luffa = SBox([0xd,0xe,0x0,0x1,0x5,0xa,0x7,0x6,0xb,0x3,0x9,0xc,0xf,0x8,0x2,0x4]) -BLAKE_1 = SBox([14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3]) -BLAKE_2 = SBox([11,8,12,0,5,2,15,13,10,14,3,6,7,1,9,4]) -BLAKE_3 = SBox([7,9,3,1,13,12,11,14,2,6,5,10,4,0,15,8]) -BLAKE_4 = SBox([9,0,5,7,2,4,10,15,14,1,11,12,6,8,3,13]) -BLAKE_5 = SBox([2,12,6,10,0,11,8,3,4,13,7,5,15,14,1,9]) -BLAKE_6 = SBox([12,5,1,15,14,13,4,10,0,7,6,3,9,2,8,11]) -BLAKE_7 = SBox([13,11,7,14,12,1,3,9,5,0,15,4,8,6,2,10]) -BLAKE_8 = SBox([6,15,14,9,11,3,0,8,12,2,13,7,1,4,10,5]) -BLAKE_9 = SBox([10,2,8,4,7,6,1,5,15,11,9,14,3,12,13,0]) -JH_S0 = SBox([9,0,4,11,13,12,3,15,1,10,2,6,7,5,8,14]) -JH_S1 = SBox([3,12,6,13,5,7,1,9,15,2,0,4,11,10,14,8]) -SMASH_256_S1 = SBox([6,13,12,7,15,1,3,10,8,11,5,0,2,4,14,9]) -SMASH_256_S2 = SBox([1,11,6,0,14,13,5,10,12,2,9,7,3,8,15,4]) -SMASH_256_S3 = SBox([4,2,9,12,8,1,14,7,15,5,0,11,6,10,3,13]) +Luffa_v1 = SBox([0x7, 0xD, 0xB, 0xA, 0xC, 0x4, 0x8, 0x3, 0x5, 0xF, 0x6, 0x0, 0x9, 0x1, 0x2, 0xE]) +Luffa = SBox([0xD, 0xE, 0x0, 0x1, 0x5, 0xA, 0x7, 0x6, 0xB, 0x3, 0x9, 0xC, 0xF, 0x8, 0x2, 0x4]) +BLAKE_1 = SBox([14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3]) +BLAKE_2 = SBox([11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4]) +BLAKE_3 = SBox([7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8]) +BLAKE_4 = SBox([9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13]) +BLAKE_5 = SBox([2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9]) +BLAKE_6 = SBox([12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11]) +BLAKE_7 = SBox([13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10]) +BLAKE_8 = SBox([6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5]) +BLAKE_9 = SBox([10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0]) +JH_S0 = SBox([9, 0, 4, 11, 13, 12, 3, 15, 1, 10, 2, 6, 7, 5, 8, 14]) +JH_S1 = SBox([3, 12, 6, 13, 5, 7, 1, 9, 15, 2, 0, 4, 11, 10, 14, 8]) +SMASH_256_S1 = SBox([6, 13, 12, 7, 15, 1, 3, 10, 8, 11, 5, 0, 2, 4, 14, 9]) +SMASH_256_S2 = SBox([1, 11, 6, 0, 14, 13, 5, 10, 12, 2, 9, 7, 3, 8, 15, 4]) +SMASH_256_S3 = SBox([4, 2, 9, 12, 8, 1, 14, 7, 15, 5, 0, 11, 6, 10, 3, 13]) # Sub-components of larger S-Boxes -Anubis_S0 = SBox([0xd,0x7,0x3,0x2,0x9,0xa,0xc,0x1,0xf,0x4,0x5,0xe,0x6,0x0,0xb,0x8]) -Anubis_S1 = SBox([0x4,0xa,0xf,0xc,0x0,0xd,0x9,0xb,0xe,0x6,0x1,0x7,0x3,0x5,0x8,0x2]) -CLEFIA_SS0 = SBox([0xe,0x6,0xc,0xa,0x8,0x7,0x2,0xf,0xb,0x1,0x4,0x0,0x5,0x9,0xd,0x3]) -CLEFIA_SS1 = SBox([0x6,0x4,0x0,0xd,0x2,0xb,0xa,0x3,0x9,0xc,0xe,0xf,0x8,0x7,0x5,0x1]) -CLEFIA_SS2 = SBox([0xb,0x8,0x5,0xe,0xa,0x6,0x4,0xc,0xf,0x7,0x2,0x3,0x1,0x0,0xd,0x9]) -CLEFIA_SS3 = SBox([0xa,0x2,0x6,0xd,0x3,0x4,0x5,0xe,0x0,0x7,0x8,0x9,0xb,0xf,0xc,0x1]) -Enocoro_S4 = SBox([1,3,9,10,5,14,7,2,13,0,12,15,4,8,6,11]) +Anubis_S0 = SBox([0xD, 0x7, 0x3, 0x2, 0x9, 0xA, 0xC, 0x1, 0xF, 0x4, 0x5, 0xE, 0x6, 0x0, 0xB, 0x8]) +Anubis_S1 = SBox([0x4, 0xA, 0xF, 0xC, 0x0, 0xD, 0x9, 0xB, 0xE, 0x6, 0x1, 0x7, 0x3, 0x5, 0x8, 0x2]) +CLEFIA_SS0 = SBox([0xE, 0x6, 0xC, 0xA, 0x8, 0x7, 0x2, 0xF, 0xB, 0x1, 0x4, 0x0, 0x5, 0x9, 0xD, 0x3]) +CLEFIA_SS1 = SBox([0x6, 0x4, 0x0, 0xD, 0x2, 0xB, 0xA, 0x3, 0x9, 0xC, 0xE, 0xF, 0x8, 0x7, 0x5, 0x1]) +CLEFIA_SS2 = SBox([0xB, 0x8, 0x5, 0xE, 0xA, 0x6, 0x4, 0xC, 0xF, 0x7, 0x2, 0x3, 0x1, 0x0, 0xD, 0x9]) +CLEFIA_SS3 = SBox([0xA, 0x2, 0x6, 0xD, 0x3, 0x4, 0x5, 0xE, 0x0, 0x7, 0x8, 0x9, 0xB, 0xF, 0xC, 0x1]) +Enocoro_S4 = SBox([1, 3, 9, 10, 5, 14, 7, 2, 13, 0, 12, 15, 4, 8, 6, 11]) Iceberg_S0 = Anubis_S0 Iceberg_S1 = Anubis_S1 -Khazad_P = SBox([0x3,0xF,0xE,0x0,0x5,0x4,0xB,0xC,0xD,0xA,0x9,0x6,0x7,0x8,0x2,0x1]) -Khazad_Q = SBox([0x9,0xE,0x5,0x6,0xA,0x2,0x3,0xC,0xF,0x0,0x4,0xD,0x7,0xB,0x1,0x8]) -Whirlpool_E = SBox([0x1,0xB,0x9,0xC,0xD,0x6,0xF,0x3,0xE,0x8,0x7,0x4,0xA,0x2,0x5,0x0]) -Whirlpool_R = SBox([0x7,0xC,0xB,0xD,0xE,0x4,0x9,0xF,0x6,0x3,0x8,0xA,0x2,0x5,0x1,0x0]) -CS_cipher_F = SBox([0xf,0xd,0xb,0xb,0x7,0x5,0x7,0x7,0xe,0xd,0xa,0xb,0xe,0xd,0xe,0xf]) -CS_cipher_G = SBox([0xa,0x6,0x0,0x2,0xb,0xe,0x1,0x8,0xd,0x4,0x5,0x3,0xf,0xc,0x7,0x9]) -Fox_S1 = SBox([0x2,0x5,0x1,0x9,0xE,0xA,0xC,0x8,0x6,0x4,0x7,0xF,0xD,0xB,0x0,0x3]) -Fox_S2 = SBox([0xB,0x4,0x1,0xF,0x0,0x3,0xE,0xD,0xA,0x8,0x7,0x5,0xC,0x2,0x9,0x6]) -Fox_S3 = SBox([0xD,0xA,0xB,0x1,0x4,0x3,0x8,0x9,0x5,0x7,0x2,0xC,0xF,0x0,0x6,0xE]) -Twofish_Q0_T0 = SBox([0x8,0x1,0x7,0xD,0x6,0xF,0x3,0x2,0x0,0xB,0x5,0x9,0xE,0xC,0xA,0x4]) -Twofish_Q0_T1 = SBox([0xE,0xC,0xB,0x8,0x1,0x2,0x3,0x5,0xF,0x4,0xA,0x6,0x7,0x0,0x9,0xD]) -Twofish_Q0_T2 = SBox([0xB,0xA,0x5,0xE,0x6,0xD,0x9,0x0,0xC,0x8,0xF,0x3,0x2,0x4,0x7,0x1]) -Twofish_Q0_T3 = SBox([0xD,0x7,0xF,0x4,0x1,0x2,0x6,0xE,0x9,0xB,0x3,0x0,0x8,0x5,0xC,0xA]) -Twofish_Q1_T0 = SBox([0x2,0x8,0xB,0xD,0xF,0x7,0x6,0xE,0x3,0x1,0x9,0x4,0x0,0xA,0xC,0x5]) -Twofish_Q1_T1 = SBox([0x1,0xE,0x2,0xB,0x4,0xC,0x3,0x7,0x6,0xD,0xA,0x5,0xF,0x9,0x0,0x8]) -Twofish_Q1_T2 = SBox([0x4,0xC,0x7,0x5,0x1,0x6,0x9,0xA,0x0,0xE,0xD,0x8,0x2,0xB,0x3,0xF]) -Twofish_Q1_T3 = SBox([0xB,0x9,0x5,0x1,0xC,0x3,0xD,0xE,0x6,0x4,0x7,0xF,0x2,0x0,0x8,0xA]) -Kuznyechik_nu0 = SBox([0x2,0x5,0x3,0xb,0x6,0x9,0xe,0xa,0x0,0x4,0xf,0x1,0x8,0xd,0xc,0x7]) -Kuznyechik_nu1 = SBox([0x7,0x6,0xc,0x9,0x0,0xf,0x8,0x1,0x4,0x5,0xb,0xe,0xd,0x2,0x3,0xa]) -Kuznyechik_sigma = SBox([0xc,0xd,0x0,0x4,0x8,0xb,0xa,0xe,0x3,0x9,0x5,0x2,0xf,0x1,0x6,0x7]) -Kuznyechik_phi = SBox([0xb,0x2,0xb,0x8,0xc,0x4,0x1,0xc,0x6,0x3,0x5,0x8,0xe,0x3,0x6,0xb]) +Khazad_P = SBox([0x3, 0xF, 0xE, 0x0, 0x5, 0x4, 0xB, 0xC, 0xD, 0xA, 0x9, 0x6, 0x7, 0x8, 0x2, 0x1]) +Khazad_Q = SBox([0x9, 0xE, 0x5, 0x6, 0xA, 0x2, 0x3, 0xC, 0xF, 0x0, 0x4, 0xD, 0x7, 0xB, 0x1, 0x8]) +Whirlpool_E = SBox([0x1, 0xB, 0x9, 0xC, 0xD, 0x6, 0xF, 0x3, 0xE, 0x8, 0x7, 0x4, 0xA, 0x2, 0x5, 0x0]) +Whirlpool_R = SBox([0x7, 0xC, 0xB, 0xD, 0xE, 0x4, 0x9, 0xF, 0x6, 0x3, 0x8, 0xA, 0x2, 0x5, 0x1, 0x0]) +CS_cipher_F = SBox([0xF, 0xD, 0xB, 0xB, 0x7, 0x5, 0x7, 0x7, 0xE, 0xD, 0xA, 0xB, 0xE, 0xD, 0xE, 0xF]) +CS_cipher_G = SBox([0xA, 0x6, 0x0, 0x2, 0xB, 0xE, 0x1, 0x8, 0xD, 0x4, 0x5, 0x3, 0xF, 0xC, 0x7, 0x9]) +Fox_S1 = SBox([0x2, 0x5, 0x1, 0x9, 0xE, 0xA, 0xC, 0x8, 0x6, 0x4, 0x7, 0xF, 0xD, 0xB, 0x0, 0x3]) +Fox_S2 = SBox([0xB, 0x4, 0x1, 0xF, 0x0, 0x3, 0xE, 0xD, 0xA, 0x8, 0x7, 0x5, 0xC, 0x2, 0x9, 0x6]) +Fox_S3 = SBox([0xD, 0xA, 0xB, 0x1, 0x4, 0x3, 0x8, 0x9, 0x5, 0x7, 0x2, 0xC, 0xF, 0x0, 0x6, 0xE]) +Twofish_Q0_T0 = SBox([0x8, 0x1, 0x7, 0xD, 0x6, 0xF, 0x3, 0x2, 0x0, 0xB, 0x5, 0x9, 0xE, 0xC, 0xA, 0x4]) +Twofish_Q0_T1 = SBox([0xE, 0xC, 0xB, 0x8, 0x1, 0x2, 0x3, 0x5, 0xF, 0x4, 0xA, 0x6, 0x7, 0x0, 0x9, 0xD]) +Twofish_Q0_T2 = SBox([0xB, 0xA, 0x5, 0xE, 0x6, 0xD, 0x9, 0x0, 0xC, 0x8, 0xF, 0x3, 0x2, 0x4, 0x7, 0x1]) +Twofish_Q0_T3 = SBox([0xD, 0x7, 0xF, 0x4, 0x1, 0x2, 0x6, 0xE, 0x9, 0xB, 0x3, 0x0, 0x8, 0x5, 0xC, 0xA]) +Twofish_Q1_T0 = SBox([0x2, 0x8, 0xB, 0xD, 0xF, 0x7, 0x6, 0xE, 0x3, 0x1, 0x9, 0x4, 0x0, 0xA, 0xC, 0x5]) +Twofish_Q1_T1 = SBox([0x1, 0xE, 0x2, 0xB, 0x4, 0xC, 0x3, 0x7, 0x6, 0xD, 0xA, 0x5, 0xF, 0x9, 0x0, 0x8]) +Twofish_Q1_T2 = SBox([0x4, 0xC, 0x7, 0x5, 0x1, 0x6, 0x9, 0xA, 0x0, 0xE, 0xD, 0x8, 0x2, 0xB, 0x3, 0xF]) +Twofish_Q1_T3 = SBox([0xB, 0x9, 0x5, 0x1, 0xC, 0x3, 0xD, 0xE, 0x6, 0x4, 0x7, 0xF, 0x2, 0x0, 0x8, 0xA]) +Kuznyechik_nu0 = SBox([0x2, 0x5, 0x3, 0xB, 0x6, 0x9, 0xE, 0xA, 0x0, 0x4, 0xF, 0x1, 0x8, 0xD, 0xC, 0x7]) +Kuznyechik_nu1 = SBox([0x7, 0x6, 0xC, 0x9, 0x0, 0xF, 0x8, 0x1, 0x4, 0x5, 0xB, 0xE, 0xD, 0x2, 0x3, 0xA]) +Kuznyechik_sigma = SBox([0xC, 0xD, 0x0, 0x4, 0x8, 0xB, 0xA, 0xE, 0x3, 0x9, 0x5, 0x2, 0xF, 0x1, 0x6, 0x7]) +Kuznyechik_phi = SBox([0xB, 0x2, 0xB, 0x8, 0xC, 0x4, 0x1, 0xC, 0x6, 0x3, 0x5, 0x8, 0xE, 0x3, 0x6, 0xB]) Optimal_S0 = SBox([0, 1, 2, 13, 4, 7, 15, 6, 8, 11, 12, 9, 3, 14, 10, 5]) Optimal_S1 = SBox([0, 1, 2, 13, 4, 7, 15, 6, 8, 11, 14, 3, 5, 9, 10, 12]) Optimal_S2 = SBox([0, 1, 2, 13, 4, 7, 15, 6, 8, 11, 14, 3, 10, 12, 5, 9]) @@ -1767,12 +14603,12 @@ def chi(n): # Ullrich, Markus, et al. "Finding optimal bitsliced implementations # of 4x4-bit S-boxes." SKEW 2011 Symmetric Key Encryption Workshop, # Copenhagen, Denmark. 2011. -UDCIKMP11 = SBox([0x0,0x8,0x6,0xD,0x5,0xF,0x7,0xC,0x4,0xE,0x2,0x3,0x9,0x1,0xB,0xA]) +UDCIKMP11 = SBox([0x0, 0x8, 0x6, 0xD, 0x5, 0xF, 0x7, 0xC, 0x4, 0xE, 0x2, 0x3, 0x9, 0x1, 0xB, 0xA]) # Bijective S-Boxes mapping 3 bits to 3 # ===================================== -SEA = SBox([0x0,0x5,0x6,0x7,0x4,0x3,0x1,0x2]) +SEA = SBox([0x0, 0x5, 0x6, 0x7, 0x4, 0x3, 0x1, 0x2]) PRINTcipher = SBox([0x0, 0x1, 0x3, 0x6, 0x7, 0x4, 0x5, 0x2]) Pyjamask_3 = SBox([0x1, 0x3, 0x6, 0x5, 0x2, 0x4, 0x7, 0x0]) @@ -2080,7 +14916,7 @@ def chi(n): SBox([0x3, 0x0, 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF]), SBox([0x1, 0x0, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF]), SBox([0x1, 0x0, 0x3, 0x2, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF]), - SBox([0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF]) + SBox([0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF]), ] # Dictionary of all available SBoxes diff --git a/src/sage/crypto/stream.py b/src/sage/crypto/stream.py index 1462295774e..17c587fed29 100644 --- a/src/sage/crypto/stream.py +++ b/src/sage/crypto/stream.py @@ -3,7 +3,7 @@ Stream Cryptosystems """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2007 David Kohel # # This program is free software: you can redistribute it and/or modify @@ -11,7 +11,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.arith.misc import gcd, power_mod from sage.crypto.cryptosystem import SymmetricKeyCryptosystem @@ -30,6 +30,7 @@ class LFSRCryptosystem(SymmetricKeyCryptosystem): """ Linear feedback shift register cryptosystem class """ + def __init__(self, field=None): """ Create a linear feedback shift cryptosystem. @@ -107,6 +108,7 @@ class ShrinkingGeneratorCryptosystem(SymmetricKeyCryptosystem): """ Shrinking generator cryptosystem class """ + def __init__(self, field=None): """ Create a shrinking generator cryptosystem. @@ -168,8 +170,7 @@ def encoding(self, M): raise TypeError("Argument M = %s does not encode in the cipher domain" % M) -def blum_blum_shub(length, seed=None, p=None, q=None, - lbound=None, ubound=None, ntries=100): +def blum_blum_shub(length, seed=None, p=None, q=None, lbound=None, ubound=None, ntries=100): r""" The Blum-Blum-Shub (BBS) pseudorandom bit generator. diff --git a/src/sage/crypto/stream_cipher.py b/src/sage/crypto/stream_cipher.py index 4b6d36ad925..7ad741e9ec4 100644 --- a/src/sage/crypto/stream_cipher.py +++ b/src/sage/crypto/stream_cipher.py @@ -2,13 +2,13 @@ """ Stream Ciphers """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2007 David Kohel # # Distributed under the terms of the GNU General Public License (GPL) # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from .lfsr import lfsr_sequence from .cipher import SymmetricKeyCipher @@ -84,15 +84,15 @@ def __call__(self, M, mode='ECB'): sage: e(m) 00111001110111101011111001001101110101011011101000011001100101101011001000000011100101101010111100000101110100111111101100000101110101111010111101000011 """ - B = self.domain() # = plaintext_space = ciphertext_space + B = self.domain() # = plaintext_space = ciphertext_space if not isinstance(M, StringMonoidElement) and M.parent() == B: raise TypeError("Argument M (= %s) must be a string in the plaintext space." % M) (poly, IS) = self.key() - n = B.ngens() # two for binary strings + n = B.ngens() # two for binary strings N = len(M) Melt = M._element_list Kelt = lfsr_sequence(poly.list(), IS, N) - return B([ (Melt[i]+int(Kelt[i])) % n for i in range(N) ]) + return B([(Melt[i] + int(Kelt[i])) % n for i in range(N)]) def _repr_(self): r""" @@ -247,7 +247,7 @@ def __call__(self, M, mode='ECB'): sage: m.decoding() 'THECATINTHEHAT' """ - B = self.domain() # = plaintext_space = ciphertext_space + B = self.domain() # = plaintext_space = ciphertext_space if not isinstance(M, StringMonoidElement) and M.parent() == B: raise TypeError("Argument M (= %s) must be a string in the plaintext space." % M) (e1, e2) = self.key() @@ -263,7 +263,7 @@ def __call__(self, M, mode='ECB'): n = max(n1, n2) CStream = [] while k < N: - r = max(N-k,2*n) + r = max(N - k, 2 * n) KStream = lfsr_sequence(g1.list(), IS_1, r) DStream = lfsr_sequence(g2.list(), IS_2, r) for i in range(r - n): @@ -272,8 +272,8 @@ def __call__(self, M, mode='ECB'): k += 1 if k == N: break - IS_1 = KStream[r-n-1:r-n+n1] - IS_2 = DStream[r-n-1:r-n+n2] + IS_1 = KStream[r - n - 1 : r - n + n1] + IS_2 = DStream[r - n - 1 : r - n + n2] return B(CStream) def _repr_(self): diff --git a/src/sage/crypto/util.py b/src/sage/crypto/util.py index b6264963d97..c346eb0a408 100644 --- a/src/sage/crypto/util.py +++ b/src/sage/crypto/util.py @@ -88,8 +88,7 @@ def ascii_integer(B): if len(B) != 8: raise ValueError("B must consist of 8 bits.") L = [int(str(x)) for x in list(B)] - return sum([L[7], L[6]*2, L[5]*4, L[4]*8, - L[3]*16, L[2]*32, L[1]*64, L[0]*128]) + return sum([L[7], L[6] * 2, L[5] * 4, L[4] * 8, L[3] * 16, L[2] * 32, L[1] * 64, L[0] * 128]) def ascii_to_bin(A): @@ -252,7 +251,7 @@ def bin_to_ascii(B): for i in range(k): # Convert from 8-bit string to ASCII integer. Then convert the # ASCII integer to the corresponding ASCII character. - A.append(chr(ascii_integer(b[8*i: 8*(i+1)]))) + A.append(chr(ascii_integer(b[8 * i : 8 * (i + 1)]))) return "".join(A) diff --git a/src/sage/data_structures/all.py b/src/sage/data_structures/all.py index eac1b4b8931..fe98668667d 100644 --- a/src/sage/data_structures/all.py +++ b/src/sage/data_structures/all.py @@ -1,2 +1 @@ - from sage.data_structures.bitset import Bitset, FrozenBitset diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index bd1f68a57cd..5e7dabcd552 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -140,6 +140,7 @@ Classes and their Methods ========================= """ + # **************************************************************************** # Copyright (C) 2015 Daniel Krenn # @@ -191,6 +192,7 @@ class MutablePosetShell(SageObject): :class:`MutablePoset` """ + def __init__(self, poset, element) -> None: r""" See :class:`MutablePosetShell` for details. @@ -683,8 +685,7 @@ def _copy_all_linked_(self, memo, poset, mapping): except KeyError: pass - new = self.__class__(poset, mapping(self.element) - if self.element is not None else None) + new = self.__class__(poset, mapping(self.element) if self.element is not None else None) memo[id(self)] = new for reverse in (False, True): @@ -766,9 +767,7 @@ def lower_covers(self, shell, reverse=False): """ if self == shell: return set() - covers = set().union(*(e.lower_covers(shell, reverse) - for e in self.successors(reverse) - if e.le(shell, reverse))) + covers = set().union(*(e.lower_covers(shell, reverse) for e in self.successors(reverse) if e.le(shell, reverse))) return covers or set([self]) def upper_covers(self, shell, reverse=False): @@ -843,9 +842,7 @@ def upper_covers(self, shell, reverse=False): """ return self.lower_covers(shell, not reverse) - def _iter_depth_first_visit_(self, marked, - reverse=False, key=None, - condition=None): + def _iter_depth_first_visit_(self, marked, reverse=False, key=None, condition=None): r""" Return an iterator over all shells in depth first order. @@ -891,8 +888,7 @@ def _iter_depth_first_visit_(self, marked, sage: list(P.oo._iter_depth_first_visit_(marked, reverse=True)) [oo, 42, 5, null] """ - if (condition is not None and - not self.is_special() and not condition(self)): + if condition is not None and not self.is_special() and not condition(self): return if self in marked: return @@ -902,8 +898,7 @@ def _iter_depth_first_visit_(self, marked, if key is not None: S = sorted(S, key=key) for shell in S: - yield from shell._iter_depth_first_visit_(marked, reverse, - key, condition) + yield from shell._iter_depth_first_visit_(marked, reverse, key, condition) def iter_depth_first(self, reverse=False, key=None, condition=None): r""" @@ -959,9 +954,7 @@ def iter_depth_first(self, reverse=False, key=None, condition=None): marked = set() return self._iter_depth_first_visit_(marked, reverse, key, condition) - def _iter_topological_visit_(self, marked, - reverse=False, key=None, - condition=None): + def _iter_topological_visit_(self, marked, reverse=False, key=None, condition=None): r""" Return an iterator over all shells in topological order. @@ -1010,8 +1003,7 @@ def _iter_topological_visit_(self, marked, sage: list(P.null._iter_topological_visit_(marked, reverse=True, key=repr)) [oo, 42, 5, null] """ - if (condition is not None and - not self.is_special() and not condition(self)): + if condition is not None and not self.is_special() and not condition(self): return if self in marked: return @@ -1020,8 +1012,7 @@ def _iter_topological_visit_(self, marked, if key is not None and len(S) > 1: S = sorted(S, key=key) for shell in S: - yield from shell._iter_topological_visit_(marked, reverse, - key, condition) + yield from shell._iter_topological_visit_(marked, reverse, key, condition) yield self def iter_topological(self, reverse=False, key=None, condition=None): @@ -1199,8 +1190,7 @@ def merge(self, element, check=True, delete=True): self_element = self.element if check: if not poset._can_merge_(self_element, element): - raise RuntimeError('Cannot merge %s with %s.' % - (self_element, element)) + raise RuntimeError('Cannot merge %s with %s.' % (self_element, element)) new = poset._merge_(self_element, element) if new is None: poset.discard(poset.get_key(self.element)) @@ -1297,6 +1287,7 @@ class MutablePoset(SageObject): :class:`MutablePosetShell`. """ + def __init__(self, data=None, key=None, merge=None, can_merge=None) -> None: r""" See :class:`MutablePoset` for details. @@ -1349,8 +1340,7 @@ def __init__(self, data=None, key=None, merge=None, can_merge=None) -> None: try: it = iter(data) except TypeError: - raise TypeError('%s is not iterable; do not know what to ' - 'do with it.' % (data,)) + raise TypeError('%s is not iterable; do not know what to ' 'do with it.' % (data,)) self.union_update(it) super().__init__() @@ -1582,14 +1572,14 @@ def _copy_shells_(self, other, mapping): True """ from copy import copy + self._key_ = copy(other._key_) self._merge_ = copy(other._merge_) self._can_merge_ = copy(other._can_merge_) memo = {} self._null_ = other._null_._copy_all_linked_(memo, self, mapping) self._oo_ = memo[id(other._oo_)] - self._shells_ = {f.key: f for f in iter(memo[id(e)] for e in - other._shells_.values())} + self._shells_ = {f.key: f for f in iter(memo[id(e)] for e in other._shells_.values())} def copy(self, mapping=None): r""" @@ -1622,6 +1612,7 @@ def copy(self, mapping=None): def mapping(element): return element + new = self.__class__() new._copy_shells_(self, mapping) return new @@ -1670,8 +1661,7 @@ def shells(self, include_special=False): if include_special: yield self.oo - def shells_topological(self, include_special=False, - reverse=False, key=None): + def shells_topological(self, include_special=False, reverse=False, key=None): r""" Return an iterator over all shells in topological order. @@ -1725,8 +1715,7 @@ def shells_topological(self, include_special=False, :meth:`MutablePosetShell.iter_topological`. """ shell = self.oo if not reverse else self.null - return iter(e for e in shell.iter_topological(reverse, key) - if include_special or not e.is_special()) + return iter(e for e in shell.iter_topological(reverse, key) if include_special or not e.is_special()) def elements(self, **kwargs): r""" @@ -1913,9 +1902,7 @@ def repr(self, include_special=False, reverse=False) -> str: poset() """ s = 'poset(' - s += ', '.join(repr(shell) for shell in - self.shells_topological(include_special, reverse, - key=repr)) + s += ', '.join(repr(shell) for shell in self.shells_topological(include_special, reverse, key=repr)) s += ')' return s @@ -1946,10 +1933,7 @@ def repr_full(self, reverse=False) -> str: | +-- successors: oo | +-- no predecessors """ - sortedshells = tuple( - self.shells_topological(include_special=True, - reverse=reverse, - key=repr)) + sortedshells = tuple(self.shells_topological(include_special=True, reverse=reverse, key=repr)) strings = [self.repr(include_special=False, reverse=reverse)] for shell in sortedshells: strings.append('+-- ' + repr(shell)) @@ -1957,8 +1941,7 @@ def repr_full(self, reverse=False) -> str: what = 'successors' if not rev else 'predecessors' if shell.successors(rev): s = '| +-- ' + what + ': ' - s += ', '.join(repr(e) for e in - sortedshells if e in shell.successors(rev)) + s += ', '.join(repr(e) for e in sortedshells if e in shell.successors(rev)) else: s = '| +-- no ' + what strings.append(s) @@ -2335,8 +2318,7 @@ def remove(self, key, raise_key_error=True): for p in shell.predecessors(reverse): S = p.successors(reverse) S.remove(shell) - D = set(s for s in p.iter_depth_first(reverse) - if s in shell.successors(reverse)) + D = set(s for s in p.iter_depth_first(reverse) if s in shell.successors(reverse)) S.update(shell.successors(reverse)) S.difference_update(D) del self._shells_[key] @@ -3113,14 +3095,13 @@ def merge(self, key=None, reverse=False): def can_merge(other): return self._can_merge_(shell.element, other.element) + for rev in (reverse, not reverse): - to_merge = shell.iter_depth_first( - reverse=rev, condition=can_merge) + to_merge = shell.iter_depth_first(reverse=rev, condition=can_merge) try: next(to_merge) except StopIteration: - raise RuntimeError('Stopping merge before started; the ' - 'can_merge-function is not reflexive.') + raise RuntimeError('Stopping merge before started; the ' 'can_merge-function is not reflexive.') for m in tuple(to_merge): if m.is_special(): continue @@ -3147,9 +3128,7 @@ def maximal_elements(self): :meth:`minimal_elements` """ - return iter(shell.element - for shell in self.oo.predecessors() - if not shell.is_special()) + return iter(shell.element for shell in self.oo.predecessors() if not shell.is_special()) def minimal_elements(self): r""" @@ -3172,9 +3151,7 @@ def minimal_elements(self): :meth:`maximal_elements` """ - return iter(shell.element - for shell in self.null.successors() - if not shell.is_special()) + return iter(shell.element for shell in self.null.successors() if not shell.is_special()) def map(self, function, topological=False, reverse=False): r""" @@ -3225,8 +3202,7 @@ def map(self, function, topological=False, reverse=False): :meth:`copy`, :meth:`mapped`. """ - shells = self.shells_topological(reverse=reverse) \ - if topological else self.shells() + shells = self.shells_topological(reverse=reverse) if topological else self.shells() remove = [] for shell in shells: image = function(shell._element_) diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index dfa3c22b196..1e28acb05d6 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -111,6 +111,7 @@ from sage.rings.fraction_field import FractionField_generic from sage.rings.fraction_field_element import FractionFieldElement from sage.misc.cachefunc import cached_method + lazy_import('sage.combinat.sf.sfa', ['_variables_recursive', '_raise_variables']) @@ -141,6 +142,7 @@ class Stream: code is not executed if ``_approximate_order`` is set to a value before it is accessed. """ + def __init__(self, true_order): """ Initialize ``self``. @@ -281,6 +283,7 @@ class Stream_inexact(Stream): If the cache is dense, it begins with the first nonzero term. """ + def __init__(self, is_sparse, true_order): """ Initialize the stream class for a stream whose @@ -466,8 +469,7 @@ def __getitem__(self, n): # self._iter might recurse, and thereby extend the # cache itself, too. i = n - self._approximate_order - self._cache.extend(next(self._iter) - for _ in range(i - len(self._cache) + 1)) + self._cache.extend(next(self._iter) for _ in range(i - len(self._cache) + 1)) return self._cache[i] return ZZ.zero() @@ -569,7 +571,7 @@ def __ne__(self, other): # TODO: more cases, in particular mixed implementations, # could be detected if not isinstance(other, Stream_inexact): - return (other != self) + return other != self if self.is_uninitialized() != other.is_uninitialized(): return True @@ -580,10 +582,7 @@ def __ne__(self, other): return True elif not self._is_sparse and not other._is_sparse: - if ((self._true_order - and other._approximate_order > self._approximate_order) - or (other._true_order - and self._approximate_order > other._approximate_order)): + if (self._true_order and other._approximate_order > self._approximate_order) or (other._true_order and self._approximate_order > other._approximate_order): return True if not self._true_order or not other._true_order: @@ -616,6 +615,7 @@ class Stream_exact(Stream): :class:`sage.rings.lazy_series_ring.LazySeriesRing`, where the input is shifted to have the prescribed order. """ + def __init__(self, initial_coefficients, constant=None, degree=None, order=None): """ Initialize a stream with eventually constant coefficients. @@ -671,9 +671,7 @@ def __init__(self, initial_coefficients, constant=None, degree=None, order=None) if order is None: order = 0 - if (degree is None - or (not self._constant - and degree > order + len(initial_coefficients))): + if degree is None or (not self._constant and degree > order + len(initial_coefficients)): self._degree = order + len(initial_coefficients) else: self._degree = degree @@ -828,11 +826,7 @@ def __eq__(self, other): sage: s == t False """ - return (isinstance(other, type(self)) - and self._degree == other._degree - and self._approximate_order == other._approximate_order - and self._initial_coefficients == other._initial_coefficients - and self._constant == other._constant) + return isinstance(other, type(self)) and self._degree == other._degree and self._approximate_order == other._approximate_order and self._initial_coefficients == other._initial_coefficients and self._constant == other._constant def __ne__(self, other): """ @@ -872,10 +866,7 @@ def __ne__(self, other): [0, 0, 0, 2, 1, 1, 1, 1] """ if isinstance(other, type(self)): - return (self._degree != other._degree - or self._approximate_order != other._approximate_order - or self._initial_coefficients != other._initial_coefficients - or self._constant != other._constant) + return self._degree != other._degree or self._approximate_order != other._approximate_order or self._initial_coefficients != other._initial_coefficients or self._constant != other._constant if other.is_uninitialized(): return True if isinstance(other, Stream_zero): @@ -889,9 +880,7 @@ def __ne__(self, other): return True else: if other._true_order: - return any(self[i] != c - for i, c in enumerate(other._cache, - other._approximate_order)) + return any(self[i] != c for i, c in enumerate(other._cache, other._approximate_order)) if other._approximate_order > self._approximate_order: return True @@ -953,6 +942,7 @@ class Stream_iterator(Stream_inexact): sage: [f[i] for i in range(10)] [0, 0, 1, 2, 3, 4, 5, 6, 7, 8] """ + def __init__(self, iter, approximate_order, true_order=False): """ Initialize. @@ -1011,6 +1001,7 @@ class Stream_function(Stream_inexact): sage: f[4] 4 """ + def __init__(self, function, is_sparse, approximate_order, true_order=False): """ Initialize. @@ -1050,8 +1041,7 @@ def input_streams(self): closure = self.get_coefficient.__closure__ if closure is None: return [] - return [cell.cell_contents for cell in closure - if isinstance(cell.cell_contents, Stream)] + return [cell.cell_contents for cell in closure if isinstance(cell.cell_contents, Stream)] def __hash__(self): """ @@ -1122,6 +1112,7 @@ class Stream_taylor(Stream_inexact): sage: [f[i] for i in range(4)] [1, 2, 4, 8] """ + def __init__(self, function, is_sparse): """ Initialize. @@ -1134,6 +1125,7 @@ def __init__(self, function, is_sparse): """ from sage.symbolic.ring import SR from sage.structure.element import parent + if parent(function) is SR: self._is_symbolic = True if function.number_of_arguments() != 1: @@ -1222,6 +1214,7 @@ def get_coefficient(self, n): return self._func(ZZ.zero()) from sage.functions.other import factorial + if self._is_symbolic: num = self._func.derivative(n).subs({self._arg: ZZ.zero()}) else: @@ -1269,6 +1262,7 @@ class VariablePool(UniqueRepresentation): - ``ring`` -- :class:`InfinitePolynomialRing` """ + def __init__(self, ring): """ Initialize the pool. @@ -1281,7 +1275,7 @@ def __init__(self, ring): sage: TestSuite(P).run() """ self._gen = ring.gen(0) # alternatively, make :class:`InfinitePolynomialGen` inherit from `UniqueRepresentation`. - self._pool = dict() # dict of variables actually used to names + self._pool = dict() # dict of variables actually used to names def new_variable(self, data=None): """ @@ -1356,6 +1350,7 @@ class DominatingAction(Action): of the function solver. This is not a mathematically defined action of ``G`` on ``S`` since the result might not be in ``S``. """ + def _act_(self, g, x): """ Return the action of ``g`` on ``x``. @@ -1401,6 +1396,7 @@ class CoefficientRing(UniqueRepresentation, FractionField_generic): r""" The class of unknown coefficients in a stream. """ + def __init__(self, base_ring): """ Initialize ``self``. @@ -1458,9 +1454,7 @@ def __init__(self, base_ring): over Rational Field in the homogeneous basis """ B = InfinitePolynomialRing(base_ring, names=["FESDUMMY"]) - FractionField_generic.__init__(self, B, - element_class=FractionFieldElement, - category=QuotientFields()) + FractionField_generic.__init__(self, B, element_class=FractionFieldElement, category=QuotientFields()) def _repr_(self): r""" @@ -1541,6 +1535,7 @@ class Stream_uninitialized(Stream): sage: C[4] 0 """ + def __init__(self, approximate_order, true_order=False, name=None): """ Initialize ``self``. @@ -1591,11 +1586,11 @@ def __del__(self): if hasattr(self, '_pool'): # self._good_cache[0] is a lower bound if self._coefficient_ring == self._base_ring: - for c in self._cache[self._good_cache[0]:]: + for c in self._cache[self._good_cache[0] :]: if c.parent() is self._PF: self._pool.del_variable(c.numerator()) else: - for c in self._cache[self._good_cache[0]:]: + for c in self._cache[self._good_cache[0] :]: for c0 in c.coefficients(): if c0.parent() is self._PF: self._pool.del_variable(c0.numerator()) @@ -1647,9 +1642,7 @@ def define(self, target): self._cache = [] self._iter = self.iterate_coefficients() - def define_implicitly(self, series, initial_values, equations, - base_ring, coefficient_ring, terms_of_degree, - max_lookahead=1): + def define_implicitly(self, series, initial_values, equations, base_ring, coefficient_ring, terms_of_degree, max_lookahead=1): r""" Define ``self`` via ``equations == 0``. @@ -1873,8 +1866,7 @@ def __getitem__(self, n): # self._iter might recurse, and thereby extend the # cache itself, too. i = n - self._approximate_order - self._cache.extend(next(self._iter) - for _ in range(i - len(self._cache) + 1)) + self._cache.extend(next(self._iter) for _ in range(i - len(self._cache) + 1)) return self._cache[i] return ZZ.zero() @@ -1900,15 +1892,13 @@ def __getitem__(self, n): # it may happen, that a variable for a coefficient of higher # degree is requested, so we have to fill in all the degrees - for n0 in range(len(self._cache) + self._approximate_order, n+1): + for n0 in range(len(self._cache) + self._approximate_order, n + 1): # WARNING: coercing the new variable to self._PF slows # down the multiplication enormously if self._coefficient_ring == self._base_ring: - x = (self._pool.new_variable(self._name + "[%s]" % n0) - * self._terms_of_degree(n0, self._P)[0]) + x = self._pool.new_variable(self._name + "[%s]" % n0) * self._terms_of_degree(n0, self._P)[0] else: - x = sum(self._pool.new_variable(self._name + "[%s]" % m) * m - for m in self._terms_of_degree(n0, self._P)) + x = sum(self._pool.new_variable(self._name + "[%s]" % m) * m for m in self._terms_of_degree(n0, self._P)) x = self._U(x) self._cache.append(x) @@ -1936,12 +1926,12 @@ def _subs_in_caches(self, var, val): sage: C[3] # indirect doctest 2 """ + def subs(c, var, val): P = self._P.polynomial_ring() num = P(c.numerator()._p).subs({P(var._p): val}) den = P(c.denominator()._p).subs({P(var._p): val}) - return self._PF(InfinitePolynomial(self._P, num), - InfinitePolynomial(self._P, den)) + return self._PF(InfinitePolynomial(self._P, num), InfinitePolynomial(self._P, den)) def retract(c): num = c.numerator() @@ -1972,7 +1962,7 @@ def fix_cache(j, s, ao): # added can contain variables indices = reversed(s._cache) else: - indices = range(-1, -m-1, -1) + indices = range(-1, -m - 1, -1) # substitute variable and determine last good element good = m for i0, i in enumerate(indices): @@ -2030,7 +2020,7 @@ def _collect_equations(self, offset): # it may or may not be the case that the # _approximate_order is advanced by __getitem__ # still, the following might be unnecessary - for d in range(eq._approximate_order, deg+1): + for d in range(eq._approximate_order, deg + 1): if not eq[d]: eq._approximate_order += 1 @@ -2040,8 +2030,7 @@ def _collect_equations(self, offset): # TODO: it is a coincidence that `coefficients` # currently exists in all examples; # the monomials are only needed for the error messages - elt_coeffs = [(self._coefficient_ring.monomial(idx), coeff) - for idx, coeff in elt.monomial_coefficients().items()] + elt_coeffs = [(self._coefficient_ring.monomial(idx), coeff) for idx, coeff in elt.monomial_coefficients().items()] all_coeffs.append(elt_coeffs) for idx, coeff in elt_coeffs: @@ -2091,6 +2080,7 @@ def _solve_linear_equations_and_subs(self, lin_coeffs): [1] """ from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence + eqs = PolynomialSequence(lin_coeffs) m1, v1 = eqs.coefficients_monomials() # there should be at most one entry in v1 of degree 0 @@ -2102,6 +2092,7 @@ def _solve_linear_equations_and_subs(self, lin_coeffs): break else: from sage.modules.free_module_element import zero_vector + b = zero_vector(m1.nrows()) m = m1 v = list(v1) @@ -2152,23 +2143,15 @@ def _compute(self): return if len(self._eqs) == 1: - eq_str = "\n ".join(self._eq_str(idx, eq) - for idx, eq in all_coeffs[0]) + eq_str = "\n ".join(self._eq_str(idx, eq) for idx, eq in all_coeffs[0]) if lin_coeffs: - raise ValueError("could not determine any coefficients:\n " - + eq_str) - raise ValueError("there are no linear equations:\n " - + eq_str) - - eqs_str = "\n".join(f"equation {i}:\n " - + "\n ".join(self._eq_str(idx, eq) - for idx, eq in eqs) - for i, eqs in enumerate(all_coeffs)) + raise ValueError("could not determine any coefficients:\n " + eq_str) + raise ValueError("there are no linear equations:\n " + eq_str) + + eqs_str = "\n".join(f"equation {i}:\n " + "\n ".join(self._eq_str(idx, eq) for idx, eq in eqs) for i, eqs in enumerate(all_coeffs)) if lin_coeffs: - raise ValueError("could not determine any coefficients:\n" - + eqs_str) - raise ValueError("there are no linear equations:\n" - + eqs_str) + raise ValueError("could not determine any coefficients:\n" + eqs_str) + raise ValueError("there are no linear equations:\n" + eqs_str) def _eq_str(self, idx, eq): """ @@ -2272,6 +2255,7 @@ class Stream_unary(Stream_inexact): sage: [g[i] for i in range(10)] [0, 4, 8, 12, 16, 20, 24, 28, 32, 36] """ + def __init__(self, series, is_sparse, true_order=False): """ Initialize ``self``. @@ -2378,6 +2362,7 @@ class Stream_binary(Stream_inexact): sage: [h[i] for i in range(10)] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] """ + def __init__(self, left, right, is_sparse): """ Initialize ``self``. @@ -2497,6 +2482,7 @@ class Stream_binaryCommutative(Stream_binary): sage: h == u True """ + def __hash__(self): """ Return the hash of ``self``. @@ -2553,6 +2539,7 @@ class Stream_zero(Stream): sage: s[5] 0 """ + def __init__(self): """ Initialize ``self``. @@ -2658,6 +2645,7 @@ def __hash__(self): ##################################################################### # Binary operations + class Stream_add(Stream_binaryCommutative): """ Operator for addition of two coefficient streams. @@ -2680,6 +2668,7 @@ class Stream_add(Stream_binaryCommutative): sage: [u[i] for i in range(10)] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] """ + @lazy_attribute def _approximate_order(self): """ @@ -2739,6 +2728,7 @@ class Stream_sub(Stream_binary): sage: [u[i] for i in range(10)] [1, 0, -1, -2, -3, -4, -5, -6, -7, -8] """ + @lazy_attribute def _approximate_order(self): """ @@ -2806,6 +2796,7 @@ class Stream_cauchy_mul(Stream_binary): sage: [u[i] for i in range(10)] [0, 1, 3, 6, 10, 15, 21, 28, 36, 45] """ + @lazy_attribute def _approximate_order(self): """ @@ -2844,10 +2835,7 @@ def get_coefficient(self, n): sage: [h.get_coefficient(i) for i in range(10)] [0, 0, 1, 6, 20, 50, 105, 196, 336, 540] """ - return ZZ.sum(l * self._right[n - k] - for k in range(self._left._approximate_order, - n - self._right._approximate_order + 1) - if (l := self._left[k])) + return ZZ.sum(l * self._right[n - k] for k in range(self._left._approximate_order, n - self._right._approximate_order + 1) if (l := self._left[k])) def is_nonzero(self): r""" @@ -2875,6 +2863,7 @@ class Stream_cauchy_mul_commutative(Stream_cauchy_mul, Stream_binaryCommutative) Operator for multiplication of two coefficient streams using the Cauchy product for commutative multiplication of coefficients. """ + pass @@ -2905,6 +2894,7 @@ class Stream_dirichlet_convolve(Stream_binary): sage: [u[i] for i in range(1, 10)] [1, 3, 4, 7, 6, 12, 8, 15, 13] """ + @lazy_attribute def _approximate_order(self): """ @@ -2922,11 +2912,8 @@ def _approximate_order(self): [0, 6, 12, 18, 24] """ # this is not the true order, unless we have an integral domain - if (self._left._approximate_order <= 0 - or self._right._approximate_order <= 0): - raise ValueError("Dirichlet convolution is only defined for " - "coefficient streams with minimal index of " - "nonzero coefficient at least 1") + if self._left._approximate_order <= 0 or self._right._approximate_order <= 0: + raise ValueError("Dirichlet convolution is only defined for " "coefficient streams with minimal index of " "nonzero coefficient at least 1") return self._left._approximate_order * self._right._approximate_order def get_coefficient(self, n): @@ -2948,10 +2935,7 @@ def get_coefficient(self, n): sage: [h[i] for i in range(1, 10)] [1, 3, 4, 7, 6, 12, 8, 15, 13] """ - return ZZ.sum(l * self._right[n//k] for k in divisors(n) - if (k >= self._left._approximate_order - and n // k >= self._right._approximate_order - and (l := self._left[k]))) + return ZZ.sum(l * self._right[n // k] for k in divisors(n) if (k >= self._left._approximate_order and n // k >= self._right._approximate_order and (l := self._left[k]))) class Stream_pseudo_diff_mul(Stream_binary): @@ -2993,6 +2977,7 @@ class Stream_pseudo_diff_mul(Stream_binary): -2*t^-11 + 23*t^-10 - 74*t^-9 + t^-8 + 5*t^-7 + 22*t^-6 + 31*t^-5, -2*t^-13 + 27*t^-12 - 78*t^-11 - 28*t^-10 + 6*t^-9 + 27*t^-8 + 88*t^-7 + 129*t^-6] """ + def __init__(self, left, right, variable, is_sparse): """ Initialize ``self``. @@ -3055,12 +3040,11 @@ def right_der(self, j, k): if k == 0: elt = self._right[j] - if (not isinstance(elt.parent(), CoefficientRing) - or (elt.numerator().is_constant() and elt.denominator().is_constant())): + if not isinstance(elt.parent(), CoefficientRing) or (elt.numerator().is_constant() and elt.denominator().is_constant()): self._right_der_cache[j, k] = elt return elt - base = self.right_der(j, k-1) + base = self.right_der(j, k - 1) x = self._variable R = self._ring if not isinstance(base.parent(), CoefficientRing): @@ -3077,16 +3061,14 @@ def right_der(self, j, k): else: num = base.numerator() den = base.denominator() - if (len(set(num.variables()).update(den.variables())) > 1 - or num.degree() > 1 or den.degree() > 1): + if len(set(num.variables()).update(den.variables())) > 1 or num.degree() > 1 or den.degree() > 1: raise NotImplementedError("taking derivatives of unknowns not yet implemented") numder = num.map_coefficients(lambda c: R(c).derivative(x)) dender = den.map_coefficients(lambda c: R(c).derivative(x)) elt = PF(numder * den - num * dender, den**2) assert elt.parent() is PF # Check to see if there are any undefined coefficients; if not, cache it - if ((j, k-1) in self._right_der_cache and elt.numerator().is_constant() - and elt.denominator().is_constant()): + if (j, k - 1) in self._right_der_cache and elt.numerator().is_constant() and elt.denominator().is_constant(): self._right_der_cache[j, k] = elt return elt @@ -3123,10 +3105,7 @@ def get_coefficient(self, n): # The upper bound on k is suboptimal when i > 0 and mj + n > 0 # as the binomial will be zero for all k in range(i+1, i+mj+n+1). mj = -self._right._approximate_order # max j value - return R.sum(binomial(i, k) * l * self.right_der(i-k+n, k) - for i in range(-n-mj, -self._left._approximate_order+1) - if (l := self._left[-i]) - for k in range(max(i, i+mj+n) + 1)) + return R.sum(binomial(i, k) * l * self.right_der(i - k + n, k) for i in range(-n - mj, -self._left._approximate_order + 1) if (l := self._left[-i]) for k in range(max(i, i + mj + n) + 1)) def is_nonzero(self): r""" @@ -3168,6 +3147,7 @@ class Stream_compose(Stream_inexact): sage: [c[i] for i in range(5)] [0, a, 2*a^2 + b, 3*a^3 + 4*a*b - a, 4*a^4 + 9*a^2*b - 5*a^2 + 2*b^2 - 3*b] """ + def __init__(self, f, g, is_sparse): """ Initialize ``self``. @@ -3245,9 +3225,7 @@ def __eq__(self, other): sage: c == d True """ - return (isinstance(other, type(self)) - and self._stream == other._stream - and self._input == other._input) + return isinstance(other, type(self)) and self._stream == other._stream and self._input == other._input @lazy_attribute def _approximate_order(self): @@ -3331,18 +3309,14 @@ def get_coefficient(self, n): fv = self._stream._approximate_order gv = self._input._coeff_stream._approximate_order if n < 0: - return sum(l * self._neg_powers[-k][n] - for k in range(fv, n // gv + 1) - if (l := self._stream[k])) + return sum(l * self._neg_powers[-k][n] for k in range(fv, n // gv + 1) if (l := self._stream[k])) # n > 0 while len(self._pos_powers) <= n // gv: # TODO: possibly we always want a dense cache here? self._pos_powers.append(self._pos_powers[-1] * self._input) - ret = sum(l * self._neg_powers[-k][n] for k in range(fv, 0) - if (l := self._stream[k])) + ret = sum(l * self._neg_powers[-k][n] for k in range(fv, 0) if (l := self._stream[k])) - return ret + sum(l * self._pos_powers[k][n] for k in range(n // gv + 1) - if (l := self._stream[k])) + return ret + sum(l * self._pos_powers[k][n] for k in range(n // gv + 1) if (l := self._stream[k])) class Stream_cauchy_compose(Stream_binary): @@ -3369,6 +3343,7 @@ class Stream_cauchy_compose(Stream_binary): sage: [u[i] for i in range(10)] [0, 1, 3, 8, 21, 55, 144, 377, 987, 2584] """ + def __init__(self, f, g, is_sparse): """ Initialize ``self``. @@ -3440,23 +3415,17 @@ def get_coefficient(self, n): fv = self._left._approximate_order gv = self._right._approximate_order if n < 0: - return ZZ.sum(l * self._neg_powers[-k][n] - for k in range(fv, n // gv + 1) - if (l := self._left[k])) + return ZZ.sum(l * self._neg_powers[-k][n] for k in range(fv, n // gv + 1) if (l := self._left[k])) # n > 0 while len(self._pos_powers) <= n // gv: # TODO: possibly we always want a dense cache here? - self._pos_powers.append(Stream_cauchy_mul(self._pos_powers[-1], - self._right, - self._is_sparse)) - ret = ZZ.sum(l * self._neg_powers[-k][n] for k in range(fv, 0) - if (l := self._left[k])) + self._pos_powers.append(Stream_cauchy_mul(self._pos_powers[-1], self._right, self._is_sparse)) + ret = ZZ.sum(l * self._neg_powers[-k][n] for k in range(fv, 0) if (l := self._left[k])) if not n: ret += self._left[0] - return ret + ZZ.sum(l * self._pos_powers[k][n] for k in range(1, n // gv + 1) - if (l := self._left[k])) + return ret + ZZ.sum(l * self._pos_powers[k][n] for k in range(1, n // gv + 1) if (l := self._left[k])) class Stream_plethysm(Stream_binary): @@ -3551,6 +3520,7 @@ class Stream_plethysm(Stream_binary): sage: r_s - sum(r2[n] for n in range(2*(r_s.degree()+1))) # needs sage.modules (a2*b1^2-a2*b1)*p[2] + (a2*b111^2-a2*b111)*p[2, 2, 2] + (a2*b21^2-a2*b21)*p[4, 2] """ + def __init__(self, f, g, is_sparse, p, ring=None, include=None, exclude=None): r""" Initialize ``self``. @@ -3610,10 +3580,10 @@ def _approximate_order(self): [0, p[1], 2*p[2], 2*p[3], 3*p[4]] """ # this is very likely not the true order -# if self._right._approximate_order == 0 and self._degree_f is None: -# raise ValueError("can only compute plethysm with a series of " -# " valuation 0 for symmetric functions of finite " -# " support") + # if self._right._approximate_order == 0 and self._degree_f is None: + # raise ValueError("can only compute plethysm with a series of " + # " valuation 0 for symmetric functions of finite " + # " support") return self._left._approximate_order * self._right._approximate_order def get_coefficient(self, n): @@ -3652,11 +3622,7 @@ def get_coefficient(self, n): else: K = n + 1 - return sum((c * self.compute_product(n, la) - for k in range(self._left._approximate_order, K) - if self._left[k] # necessary, because it might be int(0) - for la, c in self._left[k]), - self._basis.zero()) + return sum((c * self.compute_product(n, la) for k in range(self._left._approximate_order, K) if self._left[k] for la, c in self._left[k]), self._basis.zero()) # necessary, because it might be int(0) def compute_product(self, n, la): r""" @@ -3769,23 +3735,17 @@ def stretched_power_restrict_degree(self, i, m, d): # TODO: we should do lazy binary powering here while len(self._powers) < m: # TODO: possibly we always want a dense cache here? - self._powers.append(Stream_cauchy_mul(self._powers[-1], - self._powers[0], - self._is_sparse)) - power_d = self._powers[m-1][d] + self._powers.append(Stream_cauchy_mul(self._powers[-1], self._powers[0], self._is_sparse)) + power_d = self._powers[m - 1][d] # we have to check power_d for zero because it might be an # integer and not a symmetric function if power_d: # _raise_variables(c, i, self._degree_one) cannot vanish # because i is positive and c is nonzero if self._tensor_power is None: - terms = {mon.stretch(i): - _raise_variables(c, i, self._degree_one) - for mon, c in power_d} + terms = {mon.stretch(i): _raise_variables(c, i, self._degree_one) for mon, c in power_d} else: - terms = {tuple(mu.stretch(i) for mu in mon): - _raise_variables(c, i, self._degree_one) - for mon, c in power_d} + terms = {tuple(mu.stretch(i) for mu in mon): _raise_variables(c, i, self._degree_one) for mon, c in power_d} return self._basis(self._p.element_class(self._p, terms)) return self._basis.zero() @@ -3820,6 +3780,7 @@ def input_streams(self): ##################################################################### # Unary operations + class Stream_scalar(Stream_unary): """ Base class for operators multiplying a coefficient stream by a @@ -3831,6 +3792,7 @@ class Stream_scalar(Stream_unary): - ``scalar`` -- a nonzero, non-one scalar - ``is_sparse`` -- boolean """ + def __init__(self, series, scalar, is_sparse): """ Initialize ``self``. @@ -3903,8 +3865,7 @@ def __eq__(self, other): sage: f == Stream_lmul(a, 3, True) False """ - return (isinstance(other, type(self)) and self._series == other._series - and self._scalar == other._scalar) + return isinstance(other, type(self)) and self._series == other._series and self._scalar == other._scalar def is_nonzero(self): r""" @@ -3949,6 +3910,7 @@ class Stream_rmul(Stream_scalar): sage: [g[i] for i in range(5)] [0, x*dx + 1, x^2*dx + 2*x, x^3*dx + 3*x^2, x^4*dx + 4*x^3] """ + def get_coefficient(self, n): """ Return the ``n``-th coefficient of ``self``. @@ -3991,6 +3953,7 @@ class Stream_lmul(Stream_scalar): sage: [g[i] for i in range(5)] [0, x*dx, x^2*dx, x^3*dx, x^4*dx] """ + def get_coefficient(self, n): """ Return the ``n``-th coefficient of ``self``. @@ -4028,6 +3991,7 @@ class Stream_neg(Stream_unary): sage: [g[i] for i in range(10)] [0, -1, -1, -1, -1, -1, -1, -1, -1, -1] """ + # TODO: maybe we should just inherit from `Stream` instead of # inheriting from `Stream_unary` and do not create a copy of the # cache @@ -4125,6 +4089,7 @@ class Stream_cauchy_invert(Stream_unary): sage: [g[i] for i in range(10)] [-1, 0, 0, 0, 0, 0, 0, 0, 0, 0] """ + def __init__(self, series, approximate_order=None): """ Initialize ``self``. @@ -4214,7 +4179,7 @@ def iterate_coefficients(self): l = self._cache[k] if l: c += l * self._series[n - v - k] - for k in range(v+m, v+n): + for k in range(v + m, v + n): l = self[k] if l: c += l * self._series[n - k] @@ -4256,6 +4221,7 @@ class Stream_dirichlet_invert(Stream_unary): sage: [moebius(i) for i in range(10)] # needs sage.libs.pari [0, 1, -1, -1, 0, -1, 1, -1, 0, 0] """ + def __init__(self, series, is_sparse): """ Initialize. @@ -4290,8 +4256,7 @@ def _approximate_order(self): """ # this is the true order, but we want to check first if self._series._approximate_order > 1: - raise ZeroDivisionError("the Dirichlet inverse only exists if the " - "coefficient with index 1 is nonzero") + raise ZeroDivisionError("the Dirichlet inverse only exists if the " "coefficient with index 1 is nonzero") self._true_order = True return 1 @@ -4339,9 +4304,7 @@ def get_coefficient(self, n): if n == 1: return self._ainv # TODO: isn't self[k] * l and l * self[k] the same here? - c = ZZ.sum(self[k] * l for k in divisors(n) - if (k < n - and (l := self._series[n // k]))) + c = ZZ.sum(self[k] * l for k in divisors(n) if (k < n and (l := self._series[n // k]))) return -c * self._ainv @@ -4368,6 +4331,7 @@ class Stream_map_coefficients(Stream_unary): sage: [g[i] for i in range(10)] [0, -1, -1, -1, -1, -1, -1, -1, -1, -1] """ + def __init__(self, series, function, is_sparse, approximate_order=None, true_order=False): """ Initialize ``self``. @@ -4465,8 +4429,7 @@ def __eq__(self, other): sage: g == Stream_map_coefficients(f, lambda n: n + 1, True) False """ - return (isinstance(other, type(self)) and self._series == other._series - and self._function == other._function) + return isinstance(other, type(self)) and self._series == other._series and self._function == other._function class Stream_shift(Stream): @@ -4480,6 +4443,7 @@ class Stream_shift(Stream): - ``series`` -- a :class:`Stream` - ``shift`` -- integer """ + def __init__(self, series, shift): """ Initialize ``self``. @@ -4580,9 +4544,7 @@ def __eq__(self, other): sage: M2 == Stream_shift(F, 2) True """ - return (isinstance(other, type(self)) - and self._shift == other._shift - and self._series == other._series) + return isinstance(other, type(self)) and self._shift == other._shift and self._series == other._series def is_nonzero(self): r""" @@ -4629,6 +4591,7 @@ class Stream_truncated(Stream_unary): - ``shift`` -- integer - ``minimal_valuation`` -- integer; this is also the approximate order """ + def __init__(self, series, shift, minimal_valuation): """ Initialize ``self``. @@ -4716,7 +4679,7 @@ def __getitem__(self, n): """ if n < self._approximate_order: return ZZ.zero() - ret = self._series[n-self._shift] + ret = self._series[n - self._shift] if not self._true_order: if self._is_sparse: ao = self._approximate_order - self._shift @@ -4772,8 +4735,7 @@ def __eq__(self, other): """ # We assume that comparisons of this class are done only by elements in # a common ring; in particular, the minimum order will be the same. - return (isinstance(other, type(self)) and self._shift == other._shift - and self._series == other._series) + return isinstance(other, type(self)) and self._shift == other._shift and self._series == other._series def order(self): """ @@ -4811,7 +4773,7 @@ def order(self): cache = self._series._cache while True: if n - self._shift in cache: - if cache[n-self._shift]: + if cache[n - self._shift]: self._approximate_order = n self._true_order = True return n @@ -4857,8 +4819,7 @@ def is_nonzero(self): True """ if self._is_sparse: - return any(c for n, c in self._series._cache.items() - if n + self._shift >= self._approximate_order) + return any(c for n, c in self._series._cache.items() if n + self._shift >= self._approximate_order) offset = self._series._approximate_order + self._shift start = self._approximate_order - offset return any(self._cache[start:]) @@ -4876,6 +4837,7 @@ class Stream_derivative(Stream_unary): - ``shift`` -- positive integer - ``is_sparse`` -- boolean """ + def __init__(self, series, shift, is_sparse): """ Initialize ``self``. @@ -4932,8 +4894,7 @@ def __getitem__(self, n): sage: [f2[i] for i in range(-1, 4)] [0, 2, 6, 12, 20] """ - return (ZZ.prod(range(n + 1, n + self._shift + 1)) - * self._series[n + self._shift]) + return ZZ.prod(range(n + 1, n + self._shift + 1)) * self._series[n + self._shift] def __hash__(self): """ @@ -4973,9 +4934,7 @@ def __eq__(self, other): sage: f == Stream_derivative(a, 1, True) True """ - return (isinstance(other, type(self)) - and self._shift == other._shift - and self._series == other._series) + return isinstance(other, type(self)) and self._shift == other._shift and self._series == other._series def is_nonzero(self): r""" @@ -5004,6 +4963,7 @@ class Stream_integral(Stream_unary): - ``integration_constants`` -- list of integration constants - ``is_sparse`` -- boolean """ + def __init__(self, series, integration_constants, is_sparse): """ Initialize ``self``. @@ -5061,9 +5021,8 @@ def get_coefficient(self, n): [0, -1, -1, -1/2, 0, 0, 1/5, 1/6] """ if 0 <= n < self._shift: - return (self._integration_constants[n] / ZZ.prod(range(2, n + 1))) - return (self._series[n - self._shift] / - ZZ.prod(range(n - self._shift + 1, n + 1))) + return self._integration_constants[n] / ZZ.prod(range(2, n + 1)) + return self._series[n - self._shift] / ZZ.prod(range(n - self._shift + 1, n + 1)) def __hash__(self): """ @@ -5101,8 +5060,7 @@ def __eq__(self, other): sage: f == Stream_integral(a, [1], True) True """ - return (isinstance(other, type(self)) - and self._integration_constants == other._integration_constants) + return isinstance(other, type(self)) and self._integration_constants == other._integration_constants def is_nonzero(self): r""" @@ -5145,6 +5103,7 @@ class Stream_infinite_operator(Stream): - ``iterator`` -- the iterator for the factors """ + def __init__(self, iterator): r""" Initialize ``self``. @@ -5375,8 +5334,7 @@ def __ne__(self, other): deg = infinity elif isinstance(other, Stream_inexact): if other._is_sparse: - return any(self[i] != other[i] for i in other._cache - if self._approximate_order <= i < self._cur_order) + return any(self[i] != other[i] for i in other._cache if self._approximate_order <= i < self._cur_order) else: deg = other._approximate_order + len(other._cache) elif isinstance(other, Stream_infinite_operator): @@ -5385,7 +5343,7 @@ def __ne__(self, other): return False ao = min(self._approximate_order, other._approximate_order) cur_order = min(self._cur_order, deg) - if cur_order == -infinity: # no coefficients computed for one of the series + if cur_order == -infinity: # no coefficients computed for one of the series return False return any(self[i] != other[i] for i in range(ao, cur_order)) @@ -5418,6 +5376,7 @@ class Stream_infinite_sum(Stream_infinite_operator): - ``iterator`` -- the iterator for the factors """ + def initial(self, obj): r""" Set the initial data. @@ -5466,6 +5425,7 @@ class Stream_infinite_product(Stream_infinite_operator): - ``iterator`` -- the iterator for the factors """ + def initial(self, obj): r""" Set the initial data. diff --git a/src/sage/databases/all.py b/src/sage/databases/all.py index 106820386d4..c8b9b7da8d5 100644 --- a/src/sage/databases/all.py +++ b/src/sage/databases/all.py @@ -56,8 +56,7 @@ lazy_import('sage.databases.jones', 'JonesDatabase') -lazy_import('sage.databases.stein_watkins', - ['SteinWatkinsAllData', 'SteinWatkinsPrimeData']) +lazy_import('sage.databases.stein_watkins', ['SteinWatkinsAllData', 'SteinWatkinsPrimeData']) lazy_import('sage.databases.sloane', 'SloaneEncyclopedia') @@ -67,15 +66,9 @@ lazy_import('sage.databases.odlyzko', 'zeta_zeros') -from sage.databases.db_modular_polynomials import \ - ClassicalModularPolynomialDatabase, \ - DedekindEtaModularPolynomialDatabase, \ - DedekindEtaModularCorrespondenceDatabase, \ - AtkinModularPolynomialDatabase, \ - AtkinModularCorrespondenceDatabase +from sage.databases.db_modular_polynomials import ClassicalModularPolynomialDatabase, DedekindEtaModularPolynomialDatabase, DedekindEtaModularCorrespondenceDatabase, AtkinModularPolynomialDatabase, AtkinModularCorrespondenceDatabase -from sage.databases.db_class_polynomials import \ - HilbertClassPolynomialDatabase +from sage.databases.db_class_polynomials import HilbertClassPolynomialDatabase lazy_import('sage.databases.cunningham_tables', 'cunningham_prime_factors') diff --git a/src/sage/databases/conway.py b/src/sage/databases/conway.py index 9a025436488..ddf22c120b7 100644 --- a/src/sage/databases/conway.py +++ b/src/sage/databases/conway.py @@ -1,6 +1,7 @@ r""" Frank Lübeck's tables of Conway polynomials over finite fields """ + # **************************************************************************** # # Copyright (C) 2005-2006 William Stein @@ -92,6 +93,7 @@ def __init__(self): Frank Lübeck's database of Conway polynomials """ import conway_polynomials + self._store = conway_polynomials.database() def __repr__(self): diff --git a/src/sage/databases/cremona.py b/src/sage/databases/cremona.py index 21f54c70122..2945d43a310 100644 --- a/src/sage/databases/cremona.py +++ b/src/sage/databases/cremona.py @@ -35,6 +35,7 @@ CREATE INDEX i_t_class_conductor ON t_class(conductor); CREATE INDEX i_t_curve_class ON t_curve(class); """ + # **************************************************************************** # Copyright (C) 2014 John Cremona # Copyright (C) 2011 R. Andrew Ohana @@ -57,39 +58,8 @@ import re import string -_cremonaSkeleton = { - 't_class': { - 'conductor': {'sql':'INTEGER', 'index':True}, - 'class': {'sql':'TEXT', 'primary_key':True}, - 'rank': {'sql':'INTEGER'}, - 'L': {'sql':'REAL'}, - 'deg': {'sql':'INTEGER'} - }, - 't_curve': { - 'class': {'sql':'TEXT', 'index':True}, - 'curve': {'sql':'TEXT', 'primary_key':True}, - 'eqn': {'sql':'TEXT', 'unique':True}, - 'gens': {'sql':'TEXT'}, - 'tors': {'sql':'INTEGER'}, - 'cp': {'sql':'INTEGER'}, - 'om': {'sql':'REAL'}, - 'reg': {'sql':'REAL'}, - 'sha': {'sql':'NOTYPE'} - } -} -_miniCremonaSkeleton = { - 't_class': { - 'conductor': {'sql':'INTEGER', 'index':True}, - 'class': {'sql':'TEXT', 'primary_key':True}, - 'rank': {'sql':'INTEGER'} - }, - 't_curve': { - 'class': {'sql':'TEXT', 'index':True}, - 'curve': {'sql':'TEXT', 'primary_key':True}, - 'eqn': {'sql':'TEXT', 'unique':True}, - 'tors': {'sql':'INTEGER'} - } -} +_cremonaSkeleton = {'t_class': {'conductor': {'sql': 'INTEGER', 'index': True}, 'class': {'sql': 'TEXT', 'primary_key': True}, 'rank': {'sql': 'INTEGER'}, 'L': {'sql': 'REAL'}, 'deg': {'sql': 'INTEGER'}}, 't_curve': {'class': {'sql': 'TEXT', 'index': True}, 'curve': {'sql': 'TEXT', 'primary_key': True}, 'eqn': {'sql': 'TEXT', 'unique': True}, 'gens': {'sql': 'TEXT'}, 'tors': {'sql': 'INTEGER'}, 'cp': {'sql': 'INTEGER'}, 'om': {'sql': 'REAL'}, 'reg': {'sql': 'REAL'}, 'sha': {'sql': 'NOTYPE'}}} +_miniCremonaSkeleton = {'t_class': {'conductor': {'sql': 'INTEGER', 'index': True}, 'class': {'sql': 'TEXT', 'primary_key': True}, 'rank': {'sql': 'INTEGER'}}, 't_curve': {'class': {'sql': 'TEXT', 'index': True}, 'curve': {'sql': 'TEXT', 'primary_key': True}, 'eqn': {'sql': 'TEXT', 'unique': True}, 'tors': {'sql': 'INTEGER'}}} for t in _cremonaSkeleton: for c in _cremonaSkeleton[t]: @@ -116,10 +86,10 @@ def build(name, data_tgz, largest_conductor=0, mini=False, decompress=True): sage: d = sage.databases.cremona.build('cremona','ecdata.tgz') # not tested """ from sage.env import DOT_SAGE - db_path = os.path.join(DOT_SAGE, 'db', 'cremona', name.replace(' ','_')+'.db') + + db_path = os.path.join(DOT_SAGE, 'db', 'cremona', name.replace(' ', '_') + '.db') if os.path.exists(db_path): - raise RuntimeError('Please (re)move %s before building ' % db_path - + 'database') + raise RuntimeError('Please (re)move %s before building ' % db_path + 'database') if not os.path.exists(data_tgz): raise OSError("The data file is not at %s" % data_tgz) t = walltime() @@ -133,9 +103,9 @@ def build(name, data_tgz, largest_conductor=0, mini=False, decompress=True): else: print("...finished file extraction") if mini: - c = MiniCremonaDatabase(name,False,True) + c = MiniCremonaDatabase(name, False, True) else: - c = LargeCremonaDatabase(name,False,True) + c = LargeCremonaDatabase(name, False, True) # The following line assumes that the tarball extracts to a # directory called 'ecdata' c._init_from_ftpdata('ecdata', largest_conductor) @@ -247,7 +217,7 @@ def cremona_letter_code(n) -> str: return "a" s = "" while n != 0: - s = chr(n % 26+97) + s + s = chr(n % 26 + 97) + s n //= 26 return s @@ -289,7 +259,7 @@ def old_cremona_letter_code(n) -> str: """ n -= 1 k = n % 26 + 65 - label = chr(k)*int(n//26 + 1) + label = chr(k) * int(n // 26 + 1) return label @@ -378,8 +348,8 @@ def parse_cremona_label(label, numerical_class_code=False): num = "1" # convert old cremona labels to new ones - if iso.upper() == iso and iso[0]*len(iso) == iso: - iso = cremona_letter_code((len(iso)-1)*26+ord(iso[0])-ord('A')) + if iso.upper() == iso and iso[0] * len(iso) == iso: + iso = cremona_letter_code((len(iso) - 1) * 26 + ord(iso[0]) - ord('A')) # verify cremona label is valid if iso.lower() != iso: @@ -507,7 +477,7 @@ def class_to_int(k): """ kk = [string.ascii_lowercase.index(ch) for ch in list(k)] kk.reverse() - return sum(kk[i] * 26 ** i for i in range(len(kk))) + return sum(kk[i] * 26**i for i in range(len(kk))) def sort_key(key1): @@ -560,6 +530,7 @@ def cremona_to_lmfdb(cremona_label, CDB=None): ....: assert(cremona_to_lmfdb(lmfdb_to_cremona(label)) == label) """ from sage.libs.pari import pari + m = cremona_label_regex.match(cremona_label) if m is None: raise ValueError("Invalid Cremona label") @@ -568,7 +539,7 @@ def cremona_to_lmfdb(cremona_label, CDB=None): CDB = CremonaDatabase() classes = CDB.isogeny_classes(N) ft = 53 - tff = 255 # This should be enough to distinguish between curves (using heuristics from Sato-Tate for example) + tff = 255 # This should be enough to distinguish between curves (using heuristics from Sato-Tate for example) isos = [] for i, iso in enumerate(classes): alist = iso[0][0] @@ -578,9 +549,9 @@ def cremona_to_lmfdb(cremona_label, CDB=None): sorted_letters = [iso[1] for iso in isos] lmfdb_iso = cremona_letter_code(sorted_letters.index(cremona_iso)) if len(cremona_number) > 0: - iso_class = sorted([(curve[0],str(i+1)) for i,curve in enumerate(classes[class_to_int(cremona_iso)])]) + iso_class = sorted([(curve[0], str(i + 1)) for i, curve in enumerate(classes[class_to_int(cremona_iso)])]) sorted_numbers = [curve[1] for curve in iso_class] - lmfdb_number = str(sorted_numbers.index(cremona_number)+1) + lmfdb_number = str(sorted_numbers.index(cremona_number) + 1) return N + '.' + lmfdb_iso + lmfdb_number return N + '.' + lmfdb_iso @@ -609,6 +580,7 @@ def lmfdb_to_cremona(lmfdb_label, CDB=None): '990.h3' """ from sage.libs.pari import pari + m = lmfdb_label_regex.match(lmfdb_label) if m is None: raise ValueError("Invalid LMFDB label") @@ -617,7 +589,7 @@ def lmfdb_to_cremona(lmfdb_label, CDB=None): CDB = CremonaDatabase() classes = CDB.isogeny_classes(N) ft = 53 - tff = 255 # This should be enough to distinguish between curves (using heuristics from Sato-Tate for example) + tff = 255 # This should be enough to distinguish between curves (using heuristics from Sato-Tate for example) isos = [] for i, iso in enumerate(classes): alist = iso[0][0] @@ -626,8 +598,8 @@ def lmfdb_to_cremona(lmfdb_label, CDB=None): isos.sort() cremona_iso = isos[class_to_int(lmfdb_iso)][1] if len(lmfdb_number) > 0: - iso_class = sorted([(curve[0],i+1) for i,curve in enumerate(classes[class_to_int(cremona_iso)])]) - cremona_number = str(iso_class[int(lmfdb_number)-1][1]) + iso_class = sorted([(curve[0], i + 1) for i, curve in enumerate(classes[class_to_int(cremona_iso)])]) + cremona_number = str(iso_class[int(lmfdb_number) - 1][1]) return N + cremona_iso + cremona_number return N + cremona_iso @@ -644,6 +616,7 @@ class MiniCremonaDatabase(SQLDatabase): 'a2': [[0, -1, 1, -7820, -263580], 0, 1], 'a3': [[0, -1, 1, 0, 0], 0, 5]} """ + _expected_skeleton = _miniCremonaSkeleton def __init__(self, name, read_only=True, build=False): @@ -665,13 +638,11 @@ def __init__(self, name, read_only=True, build=False): if build: if read_only: raise RuntimeError('The database must not be read_only.') - SQLDatabase.__init__(self, db_path, read_only=read_only, - skeleton=self._expected_skeleton) + SQLDatabase.__init__(self, db_path, read_only=read_only, skeleton=self._expected_skeleton) return SQLDatabase.__init__(self, db_path, read_only=read_only) if self.get_skeleton() != self._expected_skeleton: - raise RuntimeError('Database at %s does ' % (self.__dblocation__) - + 'not appear to be a valid SQL Cremona database.') + raise RuntimeError('Database at %s does ' % (self.__dblocation__) + 'not appear to be a valid SQL Cremona database.') def __iter__(self): """ @@ -748,8 +719,7 @@ def __repr__(self): sage: c.__repr__() "Cremona's database of elliptic curves with conductor at most 9999" """ - return "Cremona's database of elliptic curves with conductor at most "\ - + str(self.largest_conductor()) + return "Cremona's database of elliptic curves with conductor at most " + str(self.largest_conductor()) def allcurves(self, N): """ @@ -772,11 +742,9 @@ def allcurves(self, N): [[1, 0, 0, -101, 382], 1, 1] """ ret = {} - for c in self.__connection__.cursor().execute('SELECT curve,eqn,' - + 'rank,tors FROM t_curve,t_class USING(class) WHERE ' - + 'conductor=?', (int(N),)): - N,iso,num = parse_cremona_label(c[0]) - ret[iso+str(num)] = [eval(c[1]), c[2], c[3]] + for c in self.__connection__.cursor().execute('SELECT curve,eqn,' + 'rank,tors FROM t_curve,t_class USING(class) WHERE ' + 'conductor=?', (int(N),)): + N, iso, num = parse_cremona_label(c[0]) + ret[iso + str(num)] = [eval(c[1]), c[2], c[3]] return ret def curves(self, N): @@ -809,14 +777,12 @@ def curves(self, N): [[1, 0, 0, -101, 382], 1, 1] """ ret = {} - for c in self.__connection__.cursor().execute('SELECT curve,eqn,' - + 'rank,tors FROM t_curve,t_class USING(class) WHERE ' - + 'curve=class||1 AND conductor=?',(int(N),)): - N,iso,num = parse_cremona_label(c[0]) - ret[iso+str(num)] = [eval(c[1]),c[2],c[3]] + for c in self.__connection__.cursor().execute('SELECT curve,eqn,' + 'rank,tors FROM t_curve,t_class USING(class) WHERE ' + 'curve=class||1 AND conductor=?', (int(N),)): + N, iso, num = parse_cremona_label(c[0]) + ret[iso + str(num)] = [eval(c[1]), c[2], c[3]] if N == 990: del ret['h1'] - ret['h3'] = [[1,-1,1,-1568,-4669],1,6] + ret['h3'] = [[1, -1, 1, -1568, -4669], 1, 6] return ret def coefficients_and_data(self, label): @@ -853,38 +819,27 @@ def coefficients_and_data(self, label): lmfdb_label = label N, iso, num = parse_cremona_label(cremona_label) - label = str(N)+iso+str(num) + label = str(N) + iso + str(num) if self.get_skeleton() == _miniCremonaSkeleton: - q = self.__connection__.cursor().execute("SELECT eqn,rank,tors " - + 'FROM t_curve,t_class USING(class) WHERE curve=?', (label,)) + q = self.__connection__.cursor().execute("SELECT eqn,rank,tors " + 'FROM t_curve,t_class USING(class) WHERE curve=?', (label,)) else: - q = self.__connection__.cursor().execute("SELECT eqn,rank,tors," - + "deg,gens,cp,om,L,reg,sha FROM t_curve,t_class " - + "USING(class) WHERE curve=?",(label,)) + q = self.__connection__.cursor().execute("SELECT eqn,rank,tors," + "deg,gens,cp,om,L,reg,sha FROM t_curve,t_class " + "USING(class) WHERE curve=?", (label,)) try: c = next(q) except StopIteration: if N < self.largest_conductor(): - message = "There is no elliptic curve with label " + label \ - + " in the database" + message = "There is no elliptic curve with label " + label + " in the database" elif DatabaseCremona().is_present(): - message = "There is no elliptic curve with label " + label \ - + " in the currently available databases" + message = "There is no elliptic curve with label " + label + " in the currently available databases" else: - message = "There is no elliptic curve with label " \ - + label + " in the default database; try installing " \ - + "the optional package database_cremona_ellcurve which " \ - + "contains the complete Cremona database" + message = "There is no elliptic curve with label " + label + " in the default database; try installing " + "the optional package database_cremona_ellcurve which " + "contains the complete Cremona database" raise ValueError(message) ainvs = eval(c[0]) - data = {'cremona_label': label, - 'rank': c[1], - 'torsion_order': c[2], - 'conductor': N} + data = {'cremona_label': label, 'rank': c[1], 'torsion_order': c[2], 'conductor': N} if lmfdb_label: data['lmfdb_label'] = lmfdb_label if len(c) > 3: - data['modular_degree'] = (c[3]) + data['modular_degree'] = c[3] data['gens'] = eval(c[4]) data['db_extra'] = list(c[5:]) return ainvs, data @@ -914,27 +869,18 @@ def data_from_coefficients(self, ainvs): """ ainvs = str(list(ainvs)) if self.get_skeleton() == _miniCremonaSkeleton: - q = self.__connection__.cursor().execute("SELECT curve,rank,tors " - + 'FROM t_curve,t_class USING(class) WHERE eqn=?', - (ainvs.replace(' ', ''),)) + q = self.__connection__.cursor().execute("SELECT curve,rank,tors " + 'FROM t_curve,t_class USING(class) WHERE eqn=?', (ainvs.replace(' ', ''),)) else: - q = self.__connection__.cursor().execute("SELECT curve,rank,tors," - + "deg,gens,cp,om,L,reg,sha FROM t_curve,t_class " - + "USING(class) WHERE eqn=?", - (ainvs.replace(' ', ''),)) + q = self.__connection__.cursor().execute("SELECT curve,rank,tors," + "deg,gens,cp,om,L,reg,sha FROM t_curve,t_class " + "USING(class) WHERE eqn=?", (ainvs.replace(' ', ''),)) try: c = next(q) except StopIteration: - raise RuntimeError("There is no elliptic curve with coefficients " - + ainvs + " in the database") + raise RuntimeError("There is no elliptic curve with coefficients " + ainvs + " in the database") label = str(c[0]) N, iso, num = parse_cremona_label(label) - data = {'cremona_label': label, - 'rank': c[1], - 'torsion_order': c[2], - 'conductor': N} + data = {'cremona_label': label, 'rank': c[1], 'torsion_order': c[2], 'conductor': N} if len(c) > 3: - data['modular_degree'] = (c[3]) + data['modular_degree'] = c[3] data['gens'] = eval(c[4]) data['db_extra'] = list(c[5:]) return data @@ -1029,9 +975,7 @@ def iter(self, conductors): '14a6', '15a1', '15a2', '15a3', '15a4', '15a5', '15a6', '15a7', '15a8'] """ for N in conductors: - for c in self.__connection__.cursor().execute('SELECT curve ' - + 'FROM t_curve,t_class USING(class) WHERE conductor=?', - (int(N),)): + for c in self.__connection__.cursor().execute('SELECT curve ' + 'FROM t_curve,t_class USING(class) WHERE conductor=?', (int(N),)): yield self.elliptic_curve(c[0]) def isogeny_classes(self, conductor): @@ -1062,7 +1006,7 @@ def isogeny_classes(self, conductor): v = A[k] # test if not first curve in class if not (k[-1] == '1' and k[-2].isalpha()): - classes[len(classes)-1].append(v) + classes[len(classes) - 1].append(v) else: classes.append([v]) return classes @@ -1089,8 +1033,7 @@ def isogeny_class(self, label): [Elliptic Curve defined by y^2 + x*y = x^3 - 101*x + 382 over Rational Field] """ conductor, iso, num = parse_cremona_label(label) - q = self.__connection__.cursor().execute("SELECT curve FROM t_curve " - + "WHERE class=?",(str(conductor)+iso,)) + q = self.__connection__.cursor().execute("SELECT curve FROM t_curve " + "WHERE class=?", (str(conductor) + iso,)) return [self.elliptic_curve(c[0]) for c in q] def iter_optimal(self, conductors): @@ -1118,16 +1061,13 @@ def iter_optimal(self, conductors): """ for N in conductors: if N == 990: - for c in self.__connection__.cursor().execute('SELECT class ' - + 'FROM t_class WHERE conductor=990'): + for c in self.__connection__.cursor().execute('SELECT class ' + 'FROM t_class WHERE conductor=990'): if c[0][-1] == 'h': - yield self.elliptic_curve(c[0]+'3') + yield self.elliptic_curve(c[0] + '3') else: - yield self.elliptic_curve(c[0]+'1') + yield self.elliptic_curve(c[0] + '1') continue - for c in self.__connection__.cursor().execute('SELECT curve ' - + 'FROM t_curve,t_class USING(class) WHERE curve=class||1 ' - + 'AND conductor=?',(int(N),)): + for c in self.__connection__.cursor().execute('SELECT curve ' + 'FROM t_curve,t_class USING(class) WHERE curve=class||1 ' + 'AND conductor=?', (int(N),)): yield self.elliptic_curve(c[0]) def list(self, conductors): @@ -1183,8 +1123,7 @@ def largest_conductor(self): """ if hasattr(self, '__largest_conductor__'): return self.__largest_conductor__ - q = self.__connection__.cursor().execute('SELECT conductor FROM ' - + 't_class ORDER BY conductor DESC LIMIT 1') + q = self.__connection__.cursor().execute('SELECT conductor FROM ' + 't_class ORDER BY conductor DESC LIMIT 1') self.__largest_conductor__ = next(q)[0] return self.__largest_conductor__ @@ -1221,9 +1160,9 @@ def conductor_range(self): sage: c.conductor_range() (1, 10000) """ - return 1, self.largest_conductor()+1 + return 1, self.largest_conductor() + 1 - def number_of_curves(self, N=0, i=0): + def number_of_curves(self, N=0, i=0): """ Return the number of curves stored in the database with conductor `N`. If `N = 0`, returns the total number of curves in the database. @@ -1253,19 +1192,15 @@ def number_of_curves(self, N=0, i=0): if N == 0: if hasattr(self, '__number_of_curves__'): return self.__number_of_curves__ - q = self.__connection__.cursor().execute('SELECT COUNT(curve) ' - + 'FROM t_curve') + q = self.__connection__.cursor().execute('SELECT COUNT(curve) ' + 'FROM t_curve') self.__number_of_curves__ = next(q)[0] return self.__number_of_curves__ if i == 0: - q = self.__connection__.cursor().execute('SELECT COUNT(curve) ' - + 'FROM t_curve,t_class USING(class) WHERE conductor=?', - (int(N),)) + q = self.__connection__.cursor().execute('SELECT COUNT(curve) ' + 'FROM t_curve,t_class USING(class) WHERE conductor=?', (int(N),)) return next(q)[0] if not isinstance(i, str): i = cremona_letter_code(i) - q = self.__connection__.cursor().execute('SELECT COUNT(curve) FROM ' - + 't_curve WHERE class=?',(str(N)+i,)) + q = self.__connection__.cursor().execute('SELECT COUNT(curve) FROM ' + 't_curve WHERE class=?', (str(N) + i,)) return next(q)[0] def number_of_isogeny_classes(self, N=0): @@ -1292,12 +1227,10 @@ def number_of_isogeny_classes(self, N=0): if N == 0: if hasattr(self, '__number_of_isogeny_classes__'): return self.__number_of_isogeny_classes__ - q = self.__connection__.cursor().execute('SELECT COUNT(class) ' - + 'FROM t_class') + q = self.__connection__.cursor().execute('SELECT COUNT(class) ' + 'FROM t_class') self.__number_of_isogeny_classes__ = next(q)[0] return self.__number_of_isogeny_classes__ - q = self.__connection__.cursor().execute('SELECT COUNT(class) FROM ' - + 't_class WHERE conductor=?',(int(N),)) + q = self.__connection__.cursor().execute('SELECT COUNT(class) FROM ' + 't_class WHERE conductor=?', (int(N),)) return next(q)[0] def random(self): @@ -1310,16 +1243,15 @@ def random(self): Elliptic Curve defined by y^2 + x*y = x^3 - x^2 - 224*x + 3072 over Rational Field """ N = randint(11, self.largest_conductor()) - q = self.__connection__.cursor().execute('SELECT conductor FROM ' - + 't_class WHERE conductor>=? ORDER BY conductor',(int(N),)) + q = self.__connection__.cursor().execute('SELECT conductor FROM ' + 't_class WHERE conductor>=? ORDER BY conductor', (int(N),)) try: N = next(q)[0] except StopIteration: N = 11 - iso = randint(0, self.number_of_isogeny_classes(N)-1) + iso = randint(0, self.number_of_isogeny_classes(N) - 1) iso = cremona_letter_code(iso) - num = randint(1, self.number_of_curves(N,iso)) - return self.elliptic_curve(str(N)+iso+str(num)) + num = randint(1, self.number_of_curves(N, iso)) + return self.elliptic_curve(str(N) + iso + str(num)) ############################################################################### # Functions for loading data from Cremona's ftpdata directory. @@ -1347,8 +1279,7 @@ def _init_from_ftpdata(self, ftpdata, largest_conductor=0): raise RuntimeError("The database must not be read_only.") if not os.path.exists(ftpdata): - raise RuntimeError("The cremona ftpdata directory '" + ftpdata - + "' does not exist.") + raise RuntimeError("The cremona ftpdata directory '" + ftpdata + "' does not exist.") if largest_conductor: print("largest conductor =", largest_conductor) @@ -1356,10 +1287,10 @@ def _init_from_ftpdata(self, ftpdata, largest_conductor=0): # Since July 2014 the data files have been arranged in # subdirectories (see trac #16903). - allcurves_dir = os.path.join(ftpdata,'allcurves') - allbsd_dir = os.path.join(ftpdata,'allbsd') - allgens_dir = os.path.join(ftpdata,'allgens') - degphi_dir = os.path.join(ftpdata,'degphi') + allcurves_dir = os.path.join(ftpdata, 'allcurves') + allbsd_dir = os.path.join(ftpdata, 'allbsd') + allgens_dir = os.path.join(ftpdata, 'allgens') + degphi_dir = os.path.join(ftpdata, 'degphi') num_curves, num_iso_classes = self._init_allcurves(allcurves_dir, largest_conductor) self.__number_of_curves__ = num_curves self.__number_of_isogeny_classes__ = num_iso_classes @@ -1405,7 +1336,7 @@ def _init_allcurves(self, ftpdata, largest_conductor=0): num_iso_classes = 0 con = self.get_connection() for F in files: - if not F[:len(name)] == name: + if not F[: len(name)] == name: continue print("Inserting", F) class_data = [] @@ -1414,17 +1345,15 @@ def _init_allcurves(self, ftpdata, largest_conductor=0): N, iso, num, ainvs, r, tor = L.split() if largest_conductor and int(N) > largest_conductor: break - cls = N+iso - cur = cls+num + cls = N + iso + cur = cls + num if num == "1": - class_data.append((N,cls,r)) + class_data.append((N, cls, r)) num_iso_classes += 1 - curve_data.append((cur,cls,ainvs,tor)) + curve_data.append((cur, cls, ainvs, tor)) num_curves += 1 - con.executemany('INSERT INTO t_class (conductor,class,rank) ' - + 'VALUES (?,?,?)', class_data) - con.executemany('INSERT INTO t_curve (curve,class,eqn,tors) ' - + 'VALUES (?,?,?,?)', curve_data) + con.executemany('INSERT INTO t_class (conductor,class,rank) ' + 'VALUES (?,?,?)', class_data) + con.executemany('INSERT INTO t_curve (curve,class,eqn,tors) ' + 'VALUES (?,?,?,?)', curve_data) print("Committing...") print("num_iso_classes =", num_iso_classes) self.commit() @@ -1445,6 +1374,7 @@ class LargeCremonaDatabase(MiniCremonaDatabase): 'a2': [[0, -1, 1, -7820, -263580], 0, 1], 'a3': [[0, -1, 1, 0, 0], 0, 5]} """ + _expected_skeleton = _cremonaSkeleton def allbsd(self, N): @@ -1474,11 +1404,9 @@ def allbsd(self, N): [2, 3.27608135248722, 1.54910143090506, 0.236425971187952, 1.0] """ ret = {} - for c in self.__connection__.cursor().execute('SELECT curve,cp,om,L,' - + 'reg,sha FROM t_curve,t_class USING(class) WHERE conductor=?', - (int(N),)): - N,iso,num = parse_cremona_label(c[0]) - ret[iso+str(num)] = list(c[1:]) + for c in self.__connection__.cursor().execute('SELECT curve,cp,om,L,' + 'reg,sha FROM t_curve,t_class USING(class) WHERE conductor=?', (int(N),)): + N, iso, num = parse_cremona_label(c[0]) + ret[iso + str(num)] = list(c[1:]) return ret def allgens(self, N): @@ -1502,10 +1430,9 @@ def allgens(self, N): [[7, 2, 1]] """ ret = {} - for c in self.__connection__.cursor().execute('SELECT curve,gens ' - + 'FROM t_curve,t_class USING(class) WHERE conductor=?',(int(N),)): - N,iso,num = parse_cremona_label(c[0]) - ret[iso+str(num)] = eval(c[1]) + for c in self.__connection__.cursor().execute('SELECT curve,gens ' + 'FROM t_curve,t_class USING(class) WHERE conductor=?', (int(N),)): + N, iso, num = parse_cremona_label(c[0]) + ret[iso + str(num)] = eval(c[1]) return ret def degphi(self, N): @@ -1527,11 +1454,9 @@ def degphi(self, N): 1640 """ ret = {} - for c in self.__connection__.cursor().execute('SELECT curve,deg FROM' - + ' t_curve,t_class USING(class) WHERE curve=class||1 AND ' - + 'conductor=?', (int(N),)): - N,iso,num = parse_cremona_label(c[0]) - ret[iso+str(num)] = c[1] + for c in self.__connection__.cursor().execute('SELECT curve,deg FROM' + ' t_curve,t_class USING(class) WHERE curve=class||1 AND ' + 'conductor=?', (int(N),)): + N, iso, num = parse_cremona_label(c[0]) + ret[iso + str(num)] = c[1] return ret def _init_degphi(self, ftpdata, largest_conductor=0): @@ -1553,7 +1478,7 @@ def _init_degphi(self, ftpdata, largest_conductor=0): name = "degphi" con = self.get_connection() for F in files: - if not F[:len(name)] == name: + if not F[: len(name)] == name: continue print("Inserting", F) class_data = [] @@ -1561,9 +1486,8 @@ def _init_degphi(self, ftpdata, largest_conductor=0): N, iso, num, degree, primes, curve = L.split() if largest_conductor and int(N) > largest_conductor: break - class_data.append((degree,N+iso)) - con.executemany('UPDATE t_class SET deg=? WHERE class=?', - class_data) + class_data.append((degree, N + iso)) + con.executemany('UPDATE t_class SET deg=? WHERE class=?', class_data) print("Committing...") self.commit() if largest_conductor and int(N) > largest_conductor: @@ -1588,7 +1512,7 @@ def _init_allbsd(self, ftpdata, largest_conductor=0): name = "allbsd" con = self.get_connection() for F in files: - if not F[:len(name)] == name: + if not F[: len(name)] == name: continue print("Inserting", F) curve_data = [] @@ -1597,13 +1521,12 @@ def _init_allbsd(self, ftpdata, largest_conductor=0): N, iso, num, eqn, rank, tor, cp, om, L, reg, sha = L.split() if largest_conductor and int(N) > largest_conductor: break - cls = N+iso + cls = N + iso if num == "1": - class_data.append((L,cls)) - curve_data.append((cp,om,reg,eval(sha),cls+num)) + class_data.append((L, cls)) + curve_data.append((cp, om, reg, eval(sha), cls + num)) con.executemany("UPDATE t_class SET L=? WHERE class=?", class_data) - con.executemany("UPDATE t_curve SET cp=?,om=?,reg=?,sha=? WHERE " - + "curve=?", curve_data) + con.executemany("UPDATE t_curve SET cp=?,om=?,reg=?,sha=? WHERE " + "curve=?", curve_data) print("Committing...") self.commit() if largest_conductor and int(N) > largest_conductor: @@ -1628,7 +1551,7 @@ def _init_allgens(self, ftpdata, largest_conductor=0): name = "allgens" con = self.get_connection() for F in files: - if not F[:len(name)] == name: + if not F[: len(name)] == name: continue print("Inserting", F) curve_data = [] @@ -1636,10 +1559,9 @@ def _init_allgens(self, ftpdata, largest_conductor=0): v = L.split() if largest_conductor and int(v[0]) > largest_conductor: break - gens = '['+','.join(v[6:6+int(v[4])]).replace(':',',')+']' - curve_data.append((gens,''.join(v[:3]))) - con.executemany("UPDATE t_curve SET gens=? WHERE curve=?", - curve_data) + gens = '[' + ','.join(v[6 : 6 + int(v[4])]).replace(':', ',') + ']' + curve_data.append((gens, ''.join(v[:3]))) + con.executemany("UPDATE t_curve SET gens=? WHERE curve=?", curve_data) print("Committing...") self.commit() if largest_conductor and int(v[0]) > largest_conductor: @@ -1702,8 +1624,7 @@ def CremonaDatabase(name=None, mini=None): name = 'cremona mini' else: if not DatabaseCremona().is_present(): - raise ValueError('the full Cremona database is not available; ' - 'consider using the mini Cremona database by setting mini=True') + raise ValueError('the full Cremona database is not available; ' 'consider using the mini Cremona database by setting mini=True') name = 'cremona' elif name == 'cremona mini': mini = True diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py index 56372ce900c..6c660cf1907 100644 --- a/src/sage/databases/cubic_hecke_db.py +++ b/src/sage/databases/cubic_hecke_db.py @@ -117,9 +117,7 @@ def simplify(mat): d = mat.dict() if isinstance(B, CubicHeckeExtensionRing): # Laurent polynomial cannot be reconstructed from string - res = {k: {tuple(j): u.monomial_coefficients() - for j, u in v.monomial_coefficients().items()} - for k, v in d.items()} + res = {k: {tuple(j): u.monomial_coefficients() for j, u in v.monomial_coefficients().items()} for k, v in d.items()} else: res = {k: str(v) for k, v in d.items()} return res @@ -144,6 +142,7 @@ class CubicHeckeDataSection(Enum): sage: cha_db.section """ + basis = 'basis' regular_left = 'regular_left' regular_right = 'regular_right' @@ -177,6 +176,7 @@ class CubicHeckeDataBase(SageObject): sage: cha_db._feature Feature('database_cubic_hecke') """ + section = CubicHeckeDataSection def __init__(self): @@ -191,6 +191,7 @@ def __init__(self): {} """ from sage.features.databases import DatabaseCubicHecke + self._feature = DatabaseCubicHecke() self._data_library = {} self._demo = None @@ -208,6 +209,7 @@ def version(self): """ self._feature.require() from database_cubic_hecke import version + return version() def demo_version(self): @@ -326,6 +328,7 @@ def read_matrix_representation(self, representation_type, gen_ind, nstrands, rin (24, 24) """ from sage.algebras.hecke_algebras.cubic_hecke_matrix_rep import RepresentationType, GenSign + if not isinstance(representation_type, RepresentationType): raise TypeError('representation_type must be an instance of enum %s' % RepresentationType) @@ -339,11 +342,11 @@ def read_matrix_representation(self, representation_type, gen_ind, nstrands, rin rep_list = self.read(representation_type.data_section(), variables=v, nstrands=nstrands) if gen_ind > 0: rep_list = [rep_list[GenSign.pos][i] for i in range(num_rep)] - matrix_list = [matrix(ring_of_definition, rep[gen_ind-1], sparse=True) for rep in rep_list] + matrix_list = [matrix(ring_of_definition, rep[gen_ind - 1], sparse=True) for rep in rep_list] else: # data of inverse of generators is stored under negative strand-index rep_list = [rep_list[GenSign.neg][i] for i in range(num_rep)] - matrix_list = [matrix(ring_of_definition, rep[-gen_ind-1], sparse=True) for rep in rep_list] + matrix_list = [matrix(ring_of_definition, rep[-gen_ind - 1], sparse=True) for rep in rep_list] for m in matrix_list: m.set_immutable() return matrix_list @@ -365,6 +368,7 @@ class MarkovTraceModuleBasis(Enum): sage: MarkovTraceModuleBasis.K92.description() 'knot 9_34' """ + def __repr__(self): r""" Return a string representation of ``self``. @@ -430,7 +434,7 @@ def braid_tietze(self, strands_embed=None): strands_embed = self.strands() if strands_embed > self.strands(): - last_gen = strands_embed-1 + last_gen = strands_embed - 1 return self.braid_tietze(strands_embed=last_gen) + (last_gen,) return self.value[2] @@ -448,6 +452,7 @@ def writhe(self): 1 """ from sage.functions.generalized import sign + return sum(sign(t) for t in self.braid_tietze()) def description(self): @@ -478,12 +483,14 @@ def link(self): Link with 1 component represented by 4 crossings """ from sage.knots.link import Link + pd_code = self.value[3] if pd_code is not None: # since :class:`Link` does not construct disjoint union of unlinks # from the braid representation, we need a pd_code here return Link(pd_code) from sage.groups.braid import BraidGroup + B = BraidGroup(self.strands()) return Link(B(self.braid_tietze())) @@ -509,7 +516,7 @@ def regular_homfly_polynomial(self): """ H = self.link().homfly_polynomial() L, M = H.parent().gens() - return H * L**self.writhe() + return H * L ** self.writhe() def regular_kauffman_polynomial(self): r""" @@ -532,11 +539,12 @@ def regular_kauffman_polynomial(self): True """ from sage.knots.knotinfo import KnotInfo + K = KnotInfo.L2a1_1.kauffman_polynomial().parent() a, z = K.gens() d = kauffman[self.name] if d: - return K(d)*a**self.writhe() + return K(d) * a ** self.writhe() U2rkp = MarkovTraceModuleBasis.U2.regular_kauffman_polynomial() if self.name == 'K4U': K4rkp = MarkovTraceModuleBasis.K4.regular_kauffman_polynomial() @@ -561,86 +569,48 @@ def links_gould_polynomial(self): - 3*t1^-1 - 3*t0^-1 + 2*t0^-1*t1^-1 """ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + R = LaurentPolynomialRing(ZZ, 't0, t1') return R(links_gould[self.name]) - U1 = ['one unlink', 1, (), []] - U2 = ['two unlinks', 2, (), [[3, 1, 4, 2], [4, 1, 3, 2]]] - U3 = ['three unlinks', 3, (), [[3, 7, 4, 8], [4, 7, 5, 8], - [5, 1, 6, 2], [6, 1, 3, 2]]] - U4 = ['four unlinks', 4, (), [[3, 9, 4, 10], [4, 9, 5, 10], [5, 11, 6, 12], - [6, 11, 7, 12], [7, 1, 8, 2], [8, 1, 3, 2]]] - K4U = ['knot 4_1 plus one unlink', 4, (1, -2, 1, -2), - [[3, 8, 4, 9], [9, 7, 10, 6], [7, 4, 8, 5], [5, 11, 6, 10], - [11, 1, 12, 2], [12, 1, 3, 2]]] - K4 = ['knot 4_1', 3, (1, -2, 1, -2), None] - K6 = ['knot 6_1', 4, (1, 1, 2, -1, -3, 2, -3), None] - K7 = ['knot 7_4', 4, (1, 1, 2, -1, 2, 2, 3, -2, 3), None] + U1 = ['one unlink', 1, (), []] + U2 = ['two unlinks', 2, (), [[3, 1, 4, 2], [4, 1, 3, 2]]] + U3 = ['three unlinks', 3, (), [[3, 7, 4, 8], [4, 7, 5, 8], [5, 1, 6, 2], [6, 1, 3, 2]]] + U4 = ['four unlinks', 4, (), [[3, 9, 4, 10], [4, 9, 5, 10], [5, 11, 6, 12], [6, 11, 7, 12], [7, 1, 8, 2], [8, 1, 3, 2]]] + K4U = ['knot 4_1 plus one unlink', 4, (1, -2, 1, -2), [[3, 8, 4, 9], [9, 7, 10, 6], [7, 4, 8, 5], [5, 11, 6, 10], [11, 1, 12, 2], [12, 1, 3, 2]]] + K4 = ['knot 4_1', 3, (1, -2, 1, -2), None] + K6 = ['knot 6_1', 4, (1, 1, 2, -1, -3, 2, -3), None] + K7 = ['knot 7_4', 4, (1, 1, 2, -1, 2, 2, 3, -2, 3), None] K91 = ['knot 9_29', 4, (1, -2, -2, 3, -2, 1, -2, 3, -2), None] K92 = ['knot 9_34', 4, (-1, 2, -1, 2, -3, 2, -1, 2, -3), None] kauffman = { - 'U1': 1, - 'U2': {(1, -1): 1, (0, 0): -1, (-1, -1): 1}, - 'U3': None, - 'U4': None, - 'K4U': None, - 'K4': {(2, 2): 1, (1, 3): 1, (2, 0): -1, (1, 1): -1, (0, 2): 2, (-1, 3): 1, - (0, 0): -1, (-1, 1): -1, (-2, 2): 1, (-2, 0): -1}, - 'K6': {(2, 2): 1, (1, 3): 1, (0, 4): 1, (-1, 5): 1, (2, 0): -1, (-1, 3): -2, - (-2, 4): 2, (-3, 5): 1, (-1, 1): 2, (-2, 2): -4, (-3, 3): -3, (-4, 4): 1, - (-2, 0): 1, (-3, 1): 2, (-4, 2): -3, (-4, 0): 1}, - 'K7': {(-2, 2): 1, (-3, 3): 2, (-4, 4): 3, (-5, 5): 2, (-6, 6): 1, (-4, 2): -4, - (-5, 3): -2, (-7, 5): 3, (-8, 6): 1, (-4, 0): 2, (-6, 2): -3, (-7, 3): -8, - (-8, 4): -3, (-9, 5): 1, (-7, 1): 4, (-8, 2): 2, (-9, 3): -4, (-8, 0): -1, - (-9, 1): 4}, - 'K91': {(7, 3): 1, (6, 4): 3, (5, 5): 6, (4, 6): 8, (3, 7): 6, (2, 8): 2, - (5, 3): -5, (4, 4): -13, (3, 5): -8, (2, 6): 6, (1, 7): 9, (0, 8): 2, - (5, 1): 2, (4, 2): 8, (3, 3): -1, (2, 4): -24, (1, 5): -24, (0, 6): -1, - (-1, 7): 3, (4, 0): -2, (3, 1): 2, (2, 2): 17, (1, 3): 14, (0, 4): -11, - (-1, 5): -10, (-2, 6): 1, (2, 0): -5, (1, 1): -1, (0, 2): 12, (-1, 3): 9, - (-2, 4): -3, (0, 0): -3, (-1, 1): -1, (-2, 2): 3, (-2, 0): -1}, - 'K92': {(5, 5): 1, (4, 6): 4, (3, 7): 6, (2, 8): 3, (5, 3): -1, (4, 4): -7, - (3, 5): -11, (2, 6): 5, (1, 7): 14, (0, 8): 3, (4, 2): 3, (3, 3): 5, - (2, 4): -19, (1, 5): -26, (0, 6): 9, (-1, 7): 8, (2, 2): 10, (1, 3): 12, - (0, 4): -23, (-1, 5): -10, (-2, 6): 8, (2, 0): -1, (1, 1): -1, - (0, 2): 11, (-1, 3): 4, (-2, 4): -10, (-3, 5): 4, (0, 0): -1, - (-1, 1): -1, (-2, 2): 4, (-3, 3): -2, (-4, 4): 1, (-2, 0): -1}} + 'U1': 1, + 'U2': {(1, -1): 1, (0, 0): -1, (-1, -1): 1}, + 'U3': None, + 'U4': None, + 'K4U': None, + 'K4': {(2, 2): 1, (1, 3): 1, (2, 0): -1, (1, 1): -1, (0, 2): 2, (-1, 3): 1, (0, 0): -1, (-1, 1): -1, (-2, 2): 1, (-2, 0): -1}, + 'K6': {(2, 2): 1, (1, 3): 1, (0, 4): 1, (-1, 5): 1, (2, 0): -1, (-1, 3): -2, (-2, 4): 2, (-3, 5): 1, (-1, 1): 2, (-2, 2): -4, (-3, 3): -3, (-4, 4): 1, (-2, 0): 1, (-3, 1): 2, (-4, 2): -3, (-4, 0): 1}, + 'K7': {(-2, 2): 1, (-3, 3): 2, (-4, 4): 3, (-5, 5): 2, (-6, 6): 1, (-4, 2): -4, (-5, 3): -2, (-7, 5): 3, (-8, 6): 1, (-4, 0): 2, (-6, 2): -3, (-7, 3): -8, (-8, 4): -3, (-9, 5): 1, (-7, 1): 4, (-8, 2): 2, (-9, 3): -4, (-8, 0): -1, (-9, 1): 4}, + 'K91': {(7, 3): 1, (6, 4): 3, (5, 5): 6, (4, 6): 8, (3, 7): 6, (2, 8): 2, (5, 3): -5, (4, 4): -13, (3, 5): -8, (2, 6): 6, (1, 7): 9, (0, 8): 2, (5, 1): 2, (4, 2): 8, (3, 3): -1, (2, 4): -24, (1, 5): -24, (0, 6): -1, (-1, 7): 3, (4, 0): -2, (3, 1): 2, (2, 2): 17, (1, 3): 14, (0, 4): -11, (-1, 5): -10, (-2, 6): 1, (2, 0): -5, (1, 1): -1, (0, 2): 12, (-1, 3): 9, (-2, 4): -3, (0, 0): -3, (-1, 1): -1, (-2, 2): 3, (-2, 0): -1}, + 'K92': {(5, 5): 1, (4, 6): 4, (3, 7): 6, (2, 8): 3, (5, 3): -1, (4, 4): -7, (3, 5): -11, (2, 6): 5, (1, 7): 14, (0, 8): 3, (4, 2): 3, (3, 3): 5, (2, 4): -19, (1, 5): -26, (0, 6): 9, (-1, 7): 8, (2, 2): 10, (1, 3): 12, (0, 4): -23, (-1, 5): -10, (-2, 6): 8, (2, 0): -1, (1, 1): -1, (0, 2): 11, (-1, 3): 4, (-2, 4): -10, (-3, 5): 4, (0, 0): -1, (-1, 1): -1, (-2, 2): 4, (-3, 3): -2, (-4, 4): 1, (-2, 0): -1}, +} links_gould = { - 'U1': 1, - 'U2': 0, - 'U3': 0, - 'U4': 0, - 'K4U': 0, - 'K4': {(1, 1): 2, (1, 0): -3, (0, 1): -3, (1, -1): 1, (0, 0): 7, (-1, 1): 1, - (0, -1): -3, (-1, 0): -3, (-1, -1): 2}, - 'K6': {(2, 2): 2, (2, 1): -3, (1, 2): -3, (2, 0): 1, (1, 1): 10, (0, 2): 1, - (1, 0): -10, (0, 1): -10, (1, -1): 3, (0, 0): 17, (-1, 1): 3, (0, -1): -7, - (-1, 0): -7, (-1, -1): 4}, - 'K7': {(4, 3): -1, (3, 4): -1, (4, 2): 1, (3, 3): 6, (2, 4): 1, (3, 2): -11, - (2, 3): -11, (3, 1): 6, (2, 2): 28, (1, 3): 6, (2, 1): -27, (1, 2): -27, - (2, 0): 9, (1, 1): 38, (0, 2): 9, (1, 0): -17, (0, 1): -17, (0, 0): 9}, - 'K91': {(2, 2): 6, (2, 1): -20, (1, 2): -20, (2, 0): 29, (1, 1): 76, (0, 2): 29, - (2, -1): -25, (1, 0): -123, (0, 1): -123, (-1, 2): -25, (2, -2): 14, - (1, -1): 116, (0, 0): 217, (-1, 1): 116, (-2, 2): 14, (2, -3): -5, - (1, -2): -71, (0, -1): -216, (-1, 0): -216, (-2, 1): -71, (-3, 2): -5, - (2, -4): 1, (1, -3): 27, (0, -2): 136, (-1, -1): 214, (-2, 0): 136, - (-3, 1): 27, (-4, 2): 1, (1, -4): -5, (0, -3): -50, (-1, -2): -122, - (-2, -1): -122, (-3, 0): -50, (-4, 1): -5, (0, -4): 8, (-1, -3): 37, - (-2, -2): 52, (-3, -1): 37, (-4, 0): 8, (-1, -4): -4, (-2, -3): -9, - (-3, -2): -9, (-4, -1): -4}, - 'K92': {(3, 1): 6, (2, 2): 12, (1, 3): 6, (3, 0): -15, (2, 1): -63, (1, 2): -63, - (0, 3): -15, (3, -1): 14, (2, 0): 112, (1, 1): 216, (0, 2): 112, - (-1, 3): 14, (3, -2): -6, (2, -1): -92, (1, 0): -334, (0, 1): -334, - (-1, 2): -92, (-2, 3): -6, (3, -3): 1, (2, -2): 37, (1, -1): 262, - (0, 0): 503, (-1, 1): 262, (-2, 2): 37, (-3, 3): 1, (2, -3): -6, - (1, -2): -104, (0, -1): -400, (-1, 0): -400, (-2, 1): -104, (-3, 2): -6, - (1, -3): 17, (0, -2): 162, (-1, -1): 330, (-2, 0): 162, (-3, 1): 17, - (0, -3): -27, (-1, -2): -136, (-2, -1): -136, (-3, 0): -27, (-1, -3): 22, - (-2, -2): 54, (-3, -1): 22, (-2, -3): -7, (-3, -2): -7}} + 'U1': 1, + 'U2': 0, + 'U3': 0, + 'U4': 0, + 'K4U': 0, + 'K4': {(1, 1): 2, (1, 0): -3, (0, 1): -3, (1, -1): 1, (0, 0): 7, (-1, 1): 1, (0, -1): -3, (-1, 0): -3, (-1, -1): 2}, + 'K6': {(2, 2): 2, (2, 1): -3, (1, 2): -3, (2, 0): 1, (1, 1): 10, (0, 2): 1, (1, 0): -10, (0, 1): -10, (1, -1): 3, (0, 0): 17, (-1, 1): 3, (0, -1): -7, (-1, 0): -7, (-1, -1): 4}, + 'K7': {(4, 3): -1, (3, 4): -1, (4, 2): 1, (3, 3): 6, (2, 4): 1, (3, 2): -11, (2, 3): -11, (3, 1): 6, (2, 2): 28, (1, 3): 6, (2, 1): -27, (1, 2): -27, (2, 0): 9, (1, 1): 38, (0, 2): 9, (1, 0): -17, (0, 1): -17, (0, 0): 9}, + 'K91': {(2, 2): 6, (2, 1): -20, (1, 2): -20, (2, 0): 29, (1, 1): 76, (0, 2): 29, (2, -1): -25, (1, 0): -123, (0, 1): -123, (-1, 2): -25, (2, -2): 14, (1, -1): 116, (0, 0): 217, (-1, 1): 116, (-2, 2): 14, (2, -3): -5, (1, -2): -71, (0, -1): -216, (-1, 0): -216, (-2, 1): -71, (-3, 2): -5, (2, -4): 1, (1, -3): 27, (0, -2): 136, (-1, -1): 214, (-2, 0): 136, (-3, 1): 27, (-4, 2): 1, (1, -4): -5, (0, -3): -50, (-1, -2): -122, (-2, -1): -122, (-3, 0): -50, (-4, 1): -5, (0, -4): 8, (-1, -3): 37, (-2, -2): 52, (-3, -1): 37, (-4, 0): 8, (-1, -4): -4, (-2, -3): -9, (-3, -2): -9, (-4, -1): -4}, + 'K92': {(3, 1): 6, (2, 2): 12, (1, 3): 6, (3, 0): -15, (2, 1): -63, (1, 2): -63, (0, 3): -15, (3, -1): 14, (2, 0): 112, (1, 1): 216, (0, 2): 112, (-1, 3): 14, (3, -2): -6, (2, -1): -92, (1, 0): -334, (0, 1): -334, (-1, 2): -92, (-2, 3): -6, (3, -3): 1, (2, -2): 37, (1, -1): 262, (0, 0): 503, (-1, 1): 262, (-2, 2): 37, (-3, 3): 1, (2, -3): -6, (1, -2): -104, (0, -1): -400, (-1, 0): -400, (-2, 1): -104, (-3, 2): -6, (1, -3): 17, (0, -2): 162, (-1, -1): 330, (-2, 0): 162, (-3, 1): 17, (0, -3): -27, (-1, -2): -136, (-2, -1): -136, (-3, 0): -27, (-1, -3): 22, (-2, -2): 54, (-3, -1): 22, (-2, -3): -7, (-3, -2): -7}, +} class CubicHeckeFileCache(SageObject): @@ -674,6 +644,7 @@ class section(Enum): sage: cha_fc.section """ + def filename(self, nstrands=None): r""" Return the file name under which the data of this file cache section @@ -722,6 +693,7 @@ def __init__(self, num_strands): self._nstrands = num_strands from sage.env import DOT_SAGE + self._file_cache_path = os.path.join(DOT_SAGE, 'cubic_hecke') self._data_library = {} os.makedirs(self._file_cache_path, exist_ok=True) @@ -745,6 +717,7 @@ def _warn_incompatibility(self, fname): """ from warnings import warn from datetime import date + today = date.today() new_fname = '%s_%s' % (fname, today) os.rename(fname, new_fname) @@ -782,6 +755,7 @@ def reset_library(self, section=None): raise TypeError('section must be an instance of enum %s' % CubicHeckeFileCache.section) from sage.algebras.hecke_algebras.cubic_hecke_matrix_rep import RepresentationType + data_lib = self._data_library empty_dict = {} if section == self.section.matrix_representations: @@ -819,6 +793,7 @@ def is_empty(self, section=None): self.read(section) data_lib = self._data_library[section] from sage.algebras.hecke_algebras.cubic_hecke_matrix_rep import RepresentationType + if section == self.section.matrix_representations: for rep_type in RepresentationType: if len(data_lib[rep_type.name]) > 0: @@ -828,7 +803,7 @@ def is_empty(self, section=None): if section == self.section.basis_extensions and self._nstrands > 4: # the new generators and their inverses are not counted # since they are added during initialization - return len(data_lib) <= 2*(self._nstrands - 4) + return len(data_lib) <= 2 * (self._nstrands - 4) return not data_lib # -------------------------------------------------------------------------- @@ -964,6 +939,7 @@ def read_matrix_representation(self, representation_type, monomial_tietze, ring_ True """ from sage.algebras.hecke_algebras.cubic_hecke_matrix_rep import RepresentationType + if not isinstance(representation_type, RepresentationType): raise TypeError('representation_type must be an instance of enum %s' % RepresentationType) @@ -1014,6 +990,7 @@ def write_matrix_representation(self, representation_type, monomial_tietze, matr True """ from sage.algebras.hecke_algebras.cubic_hecke_matrix_rep import RepresentationType + if not isinstance(representation_type, RepresentationType): raise TypeError('representation_type must be an instance of enum %s' % RepresentationType) @@ -1076,6 +1053,7 @@ def read_braid_image(self, braid_tietze, ring_of_definition): braid_image = braid_images[braid_tietze] result_list = [ring_of_definition(cf) for cf in list(braid_image)] from sage.modules.free_module_element import vector + return vector(ring_of_definition, result_list) return None @@ -1187,7 +1165,9 @@ def update_basis_extensions(self, new_basis_extensions): {}age: from sage.databases.cubic_hecke_db import %s%s {}age: %s(%s2) {} -""".format('r"""', 's', 's', '"""') # s in the middle to hide these lines from _test_enough_doctests +""".format( + 'r"""', 's', 's', '"""' +) # s in the middle to hide these lines from _test_enough_doctests def create_demo_data(filename='demo_data.py'): @@ -1203,6 +1183,7 @@ def create_demo_data(filename='demo_data.py'): sage: from sage.databases.cubic_hecke_db import create_demo_data sage: create_demo_data() # not tested """ + # --------------------------------------------------------------- # preparations # --------------------------------------------------------------- @@ -1212,12 +1193,12 @@ def create_repr_func(name, variables, data2, data3): v = str(variables) vars2 = v + ', ' decl = var_decl % v - doc_dec = var_doc_decl % v[1: len(v)-1] - doc_str = doc % (var_doc_input, fname, doc_dec, fname, vars2) - res = template % (fname, 'variables, ', doc_str, decl, data2, data3) + doc_dec = var_doc_decl % v[1 : len(v) - 1] + doc_str = doc % (var_doc_input, fname, doc_dec, fname, vars2) + res = template % (fname, 'variables, ', doc_str, decl, data2, data3) else: doc_str = doc % ('', fname, '', fname, '') - res = template % (fname, '', doc_str, '', data2, data3) + res = template % (fname, '', doc_str, '', data2, data3) return res from textwrap import fill @@ -1249,10 +1230,10 @@ def fl(s): # --------------------------------------------------------------- # create functions and write them to file # --------------------------------------------------------------- - bas = create_repr_func('basis', '', bas2, bas3) - irr = create_repr_func('irr', vari, irr2, irr3) - regl = create_repr_func('regl', varr, regl2, regl3) - regr = create_repr_func('regr', varr, regr2, regr3) + bas = create_repr_func('basis', '', bas2, bas3) + irr = create_repr_func('irr', vari, irr2, irr3) + regl = create_repr_func('regl', varr, regl2, regl3) + regr = create_repr_func('regr', varr, regr2, regr3) with open(filename, 'w') as f: f.write(bas) @@ -1279,10 +1260,7 @@ def read_basis(num_strands=3): """ data = {} data[2] = [[], [1], [-1]] - data[3] = [[], [1], [-1], [2], [-2], [1, 2], [1, -2], [-1, 2], [-1, -2], [1, 2, - 1], [1, 2, -1], [-1, 2, 1], [-1, 2, -1], [1, -2, 1], [-1, -2, - 1], [2, 1], [-2, 1], [2, -1], [-2, -1], [1, -2, -1], [-1, -2, - -1], [2, -1, 2], [1, 2, -1, 2], [-1, 2, -1, 2]] + data[3] = [[], [1], [-1], [2], [-2], [1, 2], [1, -2], [-1, 2], [-1, -2], [1, 2, 1], [1, 2, -1], [-1, 2, 1], [-1, 2, -1], [1, -2, 1], [-1, -2, 1], [2, 1], [-2, 1], [2, -1], [-2, -1], [1, -2, -1], [-1, -2, -1], [2, -1, 2], [1, 2, -1, 2], [-1, 2, -1, 2]] return data[num_strands] @@ -1308,25 +1286,12 @@ def read_irr(variables, num_strands=3): """ (a, b, c, j) = variables data = {} - data[2] = ([1, 1, 1], [[{(0, 0): a}], [{(0, 0): c}], [{(0, 0): b}]], [[{(0, 0): - 1/a}], [{(0, 0): 1/c}], [{(0, 0): 1/b}]]) - data[3] = ([1, 1, 1, 2, 2, 2, 3], [[{(0, 0): a}, {(0, 0): a}], [{(0, 0): c}, - {(0, 0): c}], [{(0, 0): b}, {(0, 0): b}], [{(0, 0): b, (1, 0): - b*c, (1, 1): c}, {(0, 0): c, (0, 1): -1, (1, 1): b}], [{(0, - 0): a, (1, 0): a*b, (1, 1): b}, {(0, 0): b, (0, 1): -1, (1, - 1): a}], [{(0, 0): a, (1, 0): a*c, (1, 1): c}, {(0, 0): c, (0, - 1): -1, (1, 1): a}], [{(0, 0): c, (1, 0): a*c + b**2, (1, 1): - b, (2, 0): b, (2, 1): 1, (2, 2): a}, {(0, 0): a, (0, 1): -1, - (0, 2): b, (1, 1): b, (1, 2): -a*c - b**2, (2, 2): c}]], - [[{(0, 0): 1/a}, {(0, 0): 1/a}], [{(0, 0): 1/c}, {(0, 0): - 1/c}], [{(0, 0): 1/b}, {(0, 0): 1/b}], [{(0, 0): 1/b, (1, 0): - -1, (1, 1): 1/c}, {(0, 0): 1/c, (0, 1): 1/(b*c), (1, 1): - 1/b}], [{(0, 0): 1/a, (1, 0): -1, (1, 1): 1/b}, {(0, 0): 1/b, - (0, 1): 1/(a*b), (1, 1): 1/a}], [{(0, 0): 1/a, (1, 0): -1, (1, - 1): 1/c}, {(0, 0): 1/c, (0, 1): 1/(a*c), (1, 1): 1/a}], [{(0, - 0): 1/c, (1, 0): -a/b - b/c, (1, 1): 1/b, (2, 0): 1/b, (2, 1): - -1/(a*b), (2, 2): 1/a}, {(0, 0): 1/a, (0, 1): 1/(a*b), (0, 2): - 1/b, (1, 1): 1/b, (1, 2): a/b + b/c, (2, 2): 1/c}]]) + data[2] = ([1, 1, 1], [[{(0, 0): a}], [{(0, 0): c}], [{(0, 0): b}]], [[{(0, 0): 1 / a}], [{(0, 0): 1 / c}], [{(0, 0): 1 / b}]]) + data[3] = ( + [1, 1, 1, 2, 2, 2, 3], + [[{(0, 0): a}, {(0, 0): a}], [{(0, 0): c}, {(0, 0): c}], [{(0, 0): b}, {(0, 0): b}], [{(0, 0): b, (1, 0): b * c, (1, 1): c}, {(0, 0): c, (0, 1): -1, (1, 1): b}], [{(0, 0): a, (1, 0): a * b, (1, 1): b}, {(0, 0): b, (0, 1): -1, (1, 1): a}], [{(0, 0): a, (1, 0): a * c, (1, 1): c}, {(0, 0): c, (0, 1): -1, (1, 1): a}], [{(0, 0): c, (1, 0): a * c + b**2, (1, 1): b, (2, 0): b, (2, 1): 1, (2, 2): a}, {(0, 0): a, (0, 1): -1, (0, 2): b, (1, 1): b, (1, 2): -a * c - b**2, (2, 2): c}]], + [[{(0, 0): 1 / a}, {(0, 0): 1 / a}], [{(0, 0): 1 / c}, {(0, 0): 1 / c}], [{(0, 0): 1 / b}, {(0, 0): 1 / b}], [{(0, 0): 1 / b, (1, 0): -1, (1, 1): 1 / c}, {(0, 0): 1 / c, (0, 1): 1 / (b * c), (1, 1): 1 / b}], [{(0, 0): 1 / a, (1, 0): -1, (1, 1): 1 / b}, {(0, 0): 1 / b, (0, 1): 1 / (a * b), (1, 1): 1 / a}], [{(0, 0): 1 / a, (1, 0): -1, (1, 1): 1 / c}, {(0, 0): 1 / c, (0, 1): 1 / (a * c), (1, 1): 1 / a}], [{(0, 0): 1 / c, (1, 0): -a / b - b / c, (1, 1): 1 / b, (2, 0): 1 / b, (2, 1): -1 / (a * b), (2, 2): 1 / a}, {(0, 0): 1 / a, (0, 1): 1 / (a * b), (0, 2): 1 / b, (1, 1): 1 / b, (1, 2): a / b + b / c, (2, 2): 1 / c}]], + ) return data[num_strands] @@ -1352,55 +1317,87 @@ def read_regl(variables, num_strands=3): """ (u, v, w) = variables data = {} - data[2] = ([3], [[{(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w}]], - [[{(0, 1): 1, (0, 2): -u/w, (1, 2): 1/w, (2, 0): 1, (2, 2): - v/w}]]) - data[3] = ([24], [[{(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w, (3, - 5): -v, (3, 7): 1, (4, 6): -v, (4, 8): 1, (5, 3): 1, (5, 5): - u, (6, 4): 1, (6, 6): u, (7, 5): w, (8, 6): w, (9, 9): u, (9, - 15): 1, (10, 10): u, (10, 17): 1, (11, 9): w, (12, 10): w, - (13, 13): u, (13, 16): 1, (14, 13): w, (15, 9): -v, (15, 11): - 1, (16, 13): -v, (16, 14): 1, (17, 10): -v, (17, 12): 1, (18, - 19): -v, (18, 20): 1, (19, 18): 1, (19, 19): u, (20, 19): w, - (21, 22): -v, (21, 23): 1, (22, 21): 1, (22, 22): u, (23, 22): - w}, {(0, 3): -v, (0, 4): 1, (1, 15): -v, (1, 16): 1, (1, 22): - -v, (1, 23): u*v/w, (2, 17): -v, (2, 18): 1, (2, 23): v*(u*v - - w)/w, (3, 0): 1, (3, 3): u, (4, 3): w, (5, 9): -v, (5, 10): 1, - (5, 12): -u/w, (5, 22): u, (5, 23): -u**2/w, (6, 11): -v, (6, - 22): w, (6, 23): -u, (7, 12): -u*v/w, (7, 13): -v, (7, 19): 1, - (7, 21): -v, (7, 23): -u**2*v/w, (8, 12): -v, (8, 14): -v, (8, - 20): 1, (8, 23): -u*v, (9, 5): 1, (9, 9): u, (9, 23): u/w, - (10, 9): w, (10, 11): -u, (11, 6): 1, (11, 11): u, (11, 13): - u, (12, 13): w, (12, 23): -v, (13, 23): 1, (14, 8): 1, (14, - 14): u, (14, 23): v, (15, 1): 1, (15, 12): u/w, (15, 15): u, - (16, 11): v, (16, 15): w, (16, 23): -u, (17, 2): 1, (17, 12): - u*v/w, (17, 17): u, (18, 12): v, (18, 17): w, (19, 21): w, - (19, 23): v, (20, 14): w, (21, 7): 1, (21, 21): u, (21, 23): - u*v/w, (22, 11): 1, (23, 12): 1, (23, 23): u}]], [[{(0, 1): 1, - (0, 2): -u/w, (1, 2): 1/w, (2, 0): 1, (2, 2): v/w, (3, 5): 1, - (3, 7): -u/w, (4, 6): 1, (4, 8): -u/w, (5, 7): 1/w, (6, 8): - 1/w, (7, 3): 1, (7, 7): v/w, (8, 4): 1, (8, 8): v/w, (9, 11): - 1/w, (10, 12): 1/w, (11, 11): v/w, (11, 15): 1, (12, 12): v/w, - (12, 17): 1, (13, 14): 1/w, (14, 14): v/w, (14, 16): 1, (15, - 9): 1, (15, 11): -u/w, (16, 13): 1, (16, 14): -u/w, (17, 10): - 1, (17, 12): -u/w, (18, 19): 1, (18, 20): -u/w, (19, 20): 1/w, - (20, 18): 1, (20, 20): v/w, (21, 22): 1, (21, 23): -u/w, (22, - 23): 1/w, (23, 21): 1, (23, 23): v/w}, {(0, 3): 1, (0, 4): - -u/w, (1, 15): 1, (1, 16): -u/w, (1, 22): u*v/w, (1, 23): - -u/w, (2, 17): 1, (2, 18): -u/w, (3, 4): 1/w, (4, 0): 1, (4, - 4): v/w, (5, 9): 1, (5, 10): -u/w, (5, 13): -u/w, (5, 22): - -u**2/w, (6, 11): 1, (6, 12): -u/w, (6, 13): -u*v/w, (6, 22): - -u, (7, 19): -u/w, (7, 21): 1, (8, 13): -v, (8, 14): 1, (8, - 20): -u/w, (9, 10): 1/w, (9, 22): u/w, (10, 5): 1, (10, 6): - -u/w, (10, 10): v/w, (10, 13): -u**2/w, (10, 23): u/w, (11, - 22): 1, (12, 13): -u, (12, 23): 1, (13, 12): 1/w, (13, 13): - v/w, (14, 20): 1/w, (15, 13): u/w, (15, 16): 1/w, (15, 22): - -v/w, (16, 1): 1, (16, 6): v/w, (16, 13): u*v/w, (16, 16): - v/w, (17, 13): u*v/w, (17, 18): 1/w, (17, 23): -v/w, (18, 2): - 1, (18, 13): v, (18, 18): v/w, (18, 23): -v**2/w, (19, 7): 1, - (19, 12): v/w, (19, 19): v/w, (19, 23): u*v/w, (20, 8): 1, - (20, 20): v/w, (20, 23): v, (21, 13): -v/w, (21, 19): 1/w, - (22, 6): 1/w, (22, 13): u/w, (22, 22): v/w, (23, 13): 1}]]) + data[2] = ([3], [[{(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w}]], [[{(0, 1): 1, (0, 2): -u / w, (1, 2): 1 / w, (2, 0): 1, (2, 2): v / w}]]) + data[3] = ( + [24], + [ + [ + {(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w, (3, 5): -v, (3, 7): 1, (4, 6): -v, (4, 8): 1, (5, 3): 1, (5, 5): u, (6, 4): 1, (6, 6): u, (7, 5): w, (8, 6): w, (9, 9): u, (9, 15): 1, (10, 10): u, (10, 17): 1, (11, 9): w, (12, 10): w, (13, 13): u, (13, 16): 1, (14, 13): w, (15, 9): -v, (15, 11): 1, (16, 13): -v, (16, 14): 1, (17, 10): -v, (17, 12): 1, (18, 19): -v, (18, 20): 1, (19, 18): 1, (19, 19): u, (20, 19): w, (21, 22): -v, (21, 23): 1, (22, 21): 1, (22, 22): u, (23, 22): w}, + {(0, 3): -v, (0, 4): 1, (1, 15): -v, (1, 16): 1, (1, 22): -v, (1, 23): u * v / w, (2, 17): -v, (2, 18): 1, (2, 23): v * (u * v - w) / w, (3, 0): 1, (3, 3): u, (4, 3): w, (5, 9): -v, (5, 10): 1, (5, 12): -u / w, (5, 22): u, (5, 23): -(u**2) / w, (6, 11): -v, (6, 22): w, (6, 23): -u, (7, 12): -u * v / w, (7, 13): -v, (7, 19): 1, (7, 21): -v, (7, 23): -(u**2) * v / w, (8, 12): -v, (8, 14): -v, (8, 20): 1, (8, 23): -u * v, (9, 5): 1, (9, 9): u, (9, 23): u / w, (10, 9): w, (10, 11): -u, (11, 6): 1, (11, 11): u, (11, 13): u, (12, 13): w, (12, 23): -v, (13, 23): 1, (14, 8): 1, (14, 14): u, (14, 23): v, (15, 1): 1, (15, 12): u / w, (15, 15): u, (16, 11): v, (16, 15): w, (16, 23): -u, (17, 2): 1, (17, 12): u * v / w, (17, 17): u, (18, 12): v, (18, 17): w, (19, 21): w, (19, 23): v, (20, 14): w, (21, 7): 1, (21, 21): u, (21, 23): u * v / w, (22, 11): 1, (23, 12): 1, (23, 23): u}, + ] + ], + [ + [ + {(0, 1): 1, (0, 2): -u / w, (1, 2): 1 / w, (2, 0): 1, (2, 2): v / w, (3, 5): 1, (3, 7): -u / w, (4, 6): 1, (4, 8): -u / w, (5, 7): 1 / w, (6, 8): 1 / w, (7, 3): 1, (7, 7): v / w, (8, 4): 1, (8, 8): v / w, (9, 11): 1 / w, (10, 12): 1 / w, (11, 11): v / w, (11, 15): 1, (12, 12): v / w, (12, 17): 1, (13, 14): 1 / w, (14, 14): v / w, (14, 16): 1, (15, 9): 1, (15, 11): -u / w, (16, 13): 1, (16, 14): -u / w, (17, 10): 1, (17, 12): -u / w, (18, 19): 1, (18, 20): -u / w, (19, 20): 1 / w, (20, 18): 1, (20, 20): v / w, (21, 22): 1, (21, 23): -u / w, (22, 23): 1 / w, (23, 21): 1, (23, 23): v / w}, + { + (0, 3): 1, + (0, 4): -u / w, + (1, 15): 1, + (1, 16): -u / w, + (1, 22): u * v / w, + (1, 23): -u / w, + (2, 17): 1, + (2, 18): -u / w, + (3, 4): 1 / w, + (4, 0): 1, + (4, 4): v / w, + (5, 9): 1, + (5, 10): -u / w, + (5, 13): -u / w, + (5, 22): -(u**2) / w, + (6, 11): 1, + (6, 12): -u / w, + (6, 13): -u * v / w, + (6, 22): -u, + (7, 19): -u / w, + (7, 21): 1, + (8, 13): -v, + (8, 14): 1, + (8, 20): -u / w, + (9, 10): 1 / w, + (9, 22): u / w, + (10, 5): 1, + (10, 6): -u / w, + (10, 10): v / w, + (10, 13): -(u**2) / w, + (10, 23): u / w, + (11, 22): 1, + (12, 13): -u, + (12, 23): 1, + (13, 12): 1 / w, + (13, 13): v / w, + (14, 20): 1 / w, + (15, 13): u / w, + (15, 16): 1 / w, + (15, 22): -v / w, + (16, 1): 1, + (16, 6): v / w, + (16, 13): u * v / w, + (16, 16): v / w, + (17, 13): u * v / w, + (17, 18): 1 / w, + (17, 23): -v / w, + (18, 2): 1, + (18, 13): v, + (18, 18): v / w, + (18, 23): -(v**2) / w, + (19, 7): 1, + (19, 12): v / w, + (19, 19): v / w, + (19, 23): u * v / w, + (20, 8): 1, + (20, 20): v / w, + (20, 23): v, + (21, 13): -v / w, + (21, 19): 1 / w, + (22, 6): 1 / w, + (22, 13): u / w, + (22, 22): v / w, + (23, 13): 1, + }, + ] + ], + ) return data[num_strands] @@ -1426,56 +1423,84 @@ def read_regr(variables, num_strands=3): """ (u, v, w) = variables data = {} - data[2] = ([3], [[{(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w}]], - [[{(0, 1): 1, (0, 2): -u/w, (1, 2): 1/w, (2, 0): 1, (2, 2): - v/w}]]) - data[3] = ([24], [[{(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w, (3, - 15): -v, (3, 17): 1, (4, 16): -v, (4, 18): 1, (4, 22): v**2, - (4, 23): -v, (5, 9): -v, (5, 10): 1, (6, 13): -v, (6, 19): 1, - (6, 21): -v, (6, 22): -u*v, (7, 11): -v, (7, 12): 1, (8, 14): - -v, (8, 20): 1, (8, 22): -v*w, (9, 5): 1, (9, 9): u, (9, 23): - u/w, (10, 9): w, (10, 21): -u, (10, 22): -u**2, (11, 7): 1, - (11, 11): u, (11, 21): u, (11, 23): u*v/w, (12, 11): w, (12, - 22): -u*w, (13, 6): 1, (13, 13): u, (13, 22): v, (14, 8): 1, - (14, 14): u, (14, 23): v, (15, 3): 1, (15, 15): u, (15, 22): - u, (15, 23): -u**2/w, (16, 4): 1, (16, 16): u, (16, 21): v, - (17, 15): w, (17, 22): u*v, (17, 23): -u, (18, 16): w, (19, - 13): w, (20, 14): w, (21, 22): -v, (21, 23): 1, (22, 21): 1, - (22, 22): u, (23, 22): w}, {(0, 3): -v, (0, 4): 1, (1, 5): -v, - (1, 6): 1, (2, 7): -v, (2, 8): 1, (3, 0): 1, (3, 3): u, (4, - 3): w, (5, 1): 1, (5, 5): u, (6, 5): w, (7, 2): 1, (7, 7): u, - (8, 7): w, (9, 9): u, (9, 15): 1, (10, 13): u, (10, 16): 1, - (10, 22): -v, (11, 9): w, (12, 13): w, (12, 23): -v, (13, 23): - 1, (14, 21): w, (14, 23): v, (15, 9): -v, (15, 11): 1, (16, - 22): w, (16, 23): -u, (17, 13): -v, (17, 14): 1, (17, 21): -v, - (18, 19): -v, (18, 20): 1, (19, 18): 1, (19, 19): u, (20, 19): - w, (21, 17): 1, (21, 21): u, (22, 10): 1, (22, 22): u, (23, - 12): 1, (23, 23): u}]], [[{(0, 1): 1, (0, 2): -u/w, (1, 2): - 1/w, (2, 0): 1, (2, 2): v/w, (3, 15): 1, (3, 17): -u/w, (3, - 23): u*(u*v - w)/w**2, (4, 16): 1, (4, 18): -u/w, (4, 22): -v, - (4, 23): u*v/w, (5, 9): 1, (5, 10): -u/w, (5, 21): -u/w, (5, - 22): -u**2/w, (5, 23): -u*v/w**2, (6, 13): 1, (6, 19): -u/w, - (6, 23): -v/w, (7, 11): 1, (7, 12): -u/w, (7, 21): -u*v/w, (7, - 22): -u, (7, 23): -u*v**2/w**2, (8, 14): 1, (8, 20): -u/w, (8, - 21): -v, (8, 23): -v**2/w, (9, 10): 1/w, (9, 22): u/w, (10, - 5): 1, (10, 10): v/w, (10, 22): u*v/w, (11, 12): 1/w, (11, - 23): u/w, (12, 7): 1, (12, 12): v/w, (12, 23): u*v/w, (13, - 19): 1/w, (14, 20): 1/w, (15, 17): 1/w, (15, 21): u/w, (16, - 18): 1/w, (17, 3): 1, (17, 17): v/w, (17, 21): u*v/w, (18, 4): - 1, (18, 18): v/w, (18, 21): v, (19, 6): 1, (19, 19): v/w, (19, - 22): v, (20, 8): 1, (20, 20): v/w, (20, 23): v, (21, 22): 1, - (21, 23): -u/w, (22, 23): 1/w, (23, 21): 1, (23, 23): v/w}, - {(0, 3): 1, (0, 4): -u/w, (1, 5): 1, (1, 6): -u/w, (2, 7): 1, - (2, 8): -u/w, (3, 4): 1/w, (4, 0): 1, (4, 4): v/w, (5, 6): - 1/w, (6, 1): 1, (6, 6): v/w, (7, 8): 1/w, (8, 2): 1, (8, 8): - v/w, (9, 11): 1/w, (10, 13): -u**2/w, (10, 16): -u/w, (10, - 22): 1, (11, 11): v/w, (11, 15): 1, (12, 13): -u, (12, 23): 1, - (13, 12): 1/w, (13, 13): v/w, (14, 12): v/w, (14, 14): v/w, - (14, 17): 1, (15, 9): 1, (15, 11): -u/w, (16, 10): 1, (16, - 12): -u/w, (16, 16): v/w, (17, 13): u*v/w, (17, 14): -u/w, - (17, 21): 1, (18, 19): 1, (18, 20): -u/w, (19, 20): 1/w, (20, - 18): 1, (20, 20): v/w, (21, 13): -v/w, (21, 14): 1/w, (22, - 13): u/w, (22, 16): 1/w, (23, 13): 1}]]) + data[2] = ([3], [[{(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w}]], [[{(0, 1): 1, (0, 2): -u / w, (1, 2): 1 / w, (2, 0): 1, (2, 2): v / w}]]) + data[3] = ( + [24], + [ + [ + {(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w, (3, 15): -v, (3, 17): 1, (4, 16): -v, (4, 18): 1, (4, 22): v**2, (4, 23): -v, (5, 9): -v, (5, 10): 1, (6, 13): -v, (6, 19): 1, (6, 21): -v, (6, 22): -u * v, (7, 11): -v, (7, 12): 1, (8, 14): -v, (8, 20): 1, (8, 22): -v * w, (9, 5): 1, (9, 9): u, (9, 23): u / w, (10, 9): w, (10, 21): -u, (10, 22): -(u**2), (11, 7): 1, (11, 11): u, (11, 21): u, (11, 23): u * v / w, (12, 11): w, (12, 22): -u * w, (13, 6): 1, (13, 13): u, (13, 22): v, (14, 8): 1, (14, 14): u, (14, 23): v, (15, 3): 1, (15, 15): u, (15, 22): u, (15, 23): -(u**2) / w, (16, 4): 1, (16, 16): u, (16, 21): v, (17, 15): w, (17, 22): u * v, (17, 23): -u, (18, 16): w, (19, 13): w, (20, 14): w, (21, 22): -v, (21, 23): 1, (22, 21): 1, (22, 22): u, (23, 22): w}, + {(0, 3): -v, (0, 4): 1, (1, 5): -v, (1, 6): 1, (2, 7): -v, (2, 8): 1, (3, 0): 1, (3, 3): u, (4, 3): w, (5, 1): 1, (5, 5): u, (6, 5): w, (7, 2): 1, (7, 7): u, (8, 7): w, (9, 9): u, (9, 15): 1, (10, 13): u, (10, 16): 1, (10, 22): -v, (11, 9): w, (12, 13): w, (12, 23): -v, (13, 23): 1, (14, 21): w, (14, 23): v, (15, 9): -v, (15, 11): 1, (16, 22): w, (16, 23): -u, (17, 13): -v, (17, 14): 1, (17, 21): -v, (18, 19): -v, (18, 20): 1, (19, 18): 1, (19, 19): u, (20, 19): w, (21, 17): 1, (21, 21): u, (22, 10): 1, (22, 22): u, (23, 12): 1, (23, 23): u}, + ] + ], + [ + [ + { + (0, 1): 1, + (0, 2): -u / w, + (1, 2): 1 / w, + (2, 0): 1, + (2, 2): v / w, + (3, 15): 1, + (3, 17): -u / w, + (3, 23): u * (u * v - w) / w**2, + (4, 16): 1, + (4, 18): -u / w, + (4, 22): -v, + (4, 23): u * v / w, + (5, 9): 1, + (5, 10): -u / w, + (5, 21): -u / w, + (5, 22): -(u**2) / w, + (5, 23): -u * v / w**2, + (6, 13): 1, + (6, 19): -u / w, + (6, 23): -v / w, + (7, 11): 1, + (7, 12): -u / w, + (7, 21): -u * v / w, + (7, 22): -u, + (7, 23): -u * v**2 / w**2, + (8, 14): 1, + (8, 20): -u / w, + (8, 21): -v, + (8, 23): -(v**2) / w, + (9, 10): 1 / w, + (9, 22): u / w, + (10, 5): 1, + (10, 10): v / w, + (10, 22): u * v / w, + (11, 12): 1 / w, + (11, 23): u / w, + (12, 7): 1, + (12, 12): v / w, + (12, 23): u * v / w, + (13, 19): 1 / w, + (14, 20): 1 / w, + (15, 17): 1 / w, + (15, 21): u / w, + (16, 18): 1 / w, + (17, 3): 1, + (17, 17): v / w, + (17, 21): u * v / w, + (18, 4): 1, + (18, 18): v / w, + (18, 21): v, + (19, 6): 1, + (19, 19): v / w, + (19, 22): v, + (20, 8): 1, + (20, 20): v / w, + (20, 23): v, + (21, 22): 1, + (21, 23): -u / w, + (22, 23): 1 / w, + (23, 21): 1, + (23, 23): v / w, + }, + {(0, 3): 1, (0, 4): -u / w, (1, 5): 1, (1, 6): -u / w, (2, 7): 1, (2, 8): -u / w, (3, 4): 1 / w, (4, 0): 1, (4, 4): v / w, (5, 6): 1 / w, (6, 1): 1, (6, 6): v / w, (7, 8): 1 / w, (8, 2): 1, (8, 8): v / w, (9, 11): 1 / w, (10, 13): -(u**2) / w, (10, 16): -u / w, (10, 22): 1, (11, 11): v / w, (11, 15): 1, (12, 13): -u, (12, 23): 1, (13, 12): 1 / w, (13, 13): v / w, (14, 12): v / w, (14, 14): v / w, (14, 17): 1, (15, 9): 1, (15, 11): -u / w, (16, 10): 1, (16, 12): -u / w, (16, 16): v / w, (17, 13): u * v / w, (17, 14): -u / w, (17, 21): 1, (18, 19): 1, (18, 20): -u / w, (19, 20): 1 / w, (20, 18): 1, (20, 20): v / w, (21, 13): -v / w, (21, 14): 1 / w, (22, 13): u / w, (22, 16): 1 / w, (23, 13): 1}, + ] + ], + ) return data[num_strands] @@ -1512,14 +1537,7 @@ def read_markov(bas_ele, variables, num_strands=4): """ u, v, w, s = variables data = {} - data[2] = {'U1': [0, s, 1/s], 'U2': [1, 0, 0]} - data[3] = {'U1': [0, 0, 0, 0, 0, s**2, 1, 1, 1/s**2, u*s**2 + w, 0, 0, (s**2 + - v)/w, (u*s**2 + w)/s**2, 0, s**2, 1, 1, 1/s**2, 0, (s**2 + - v)/(w*s**2), (u*s**2 + w)/s**2, s**2, 0], 'U2': [0, s, 1/s, s, - 1/s, 0, 0, 0, 0, -v*s, s, s, (-u*s)/w, (-v)/s, 1/s, 0, 0, 0, - 0, 1/s, (-u)/(w*s), (-v)/s, 0, 0], 'U3': [1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'K4': [0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1]} + data[2] = {'U1': [0, s, 1 / s], 'U2': [1, 0, 0]} + data[3] = {'U1': [0, 0, 0, 0, 0, s**2, 1, 1, 1 / s**2, u * s**2 + w, 0, 0, (s**2 + v) / w, (u * s**2 + w) / s**2, 0, s**2, 1, 1, 1 / s**2, 0, (s**2 + v) / (w * s**2), (u * s**2 + w) / s**2, s**2, 0], 'U2': [0, s, 1 / s, s, 1 / s, 0, 0, 0, 0, -v * s, s, s, (-u * s) / w, (-v) / s, 1 / s, 0, 0, 0, 0, 1 / s, (-u) / (w * s), (-v) / s, 0, 0], 'U3': [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'K4': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]} return data[num_strands][bas_ele] diff --git a/src/sage/databases/cunningham_tables.py b/src/sage/databases/cunningham_tables.py index 2b8d5cccf81..44f8583c5f5 100644 --- a/src/sage/databases/cunningham_tables.py +++ b/src/sage/databases/cunningham_tables.py @@ -49,5 +49,6 @@ def cunningham_prime_factors(): return [Integer(_) for _ in load(file)] from warnings import warn + warn("The optional cunningham_tables package for factoring Cunningham numbers is not installed") return [] diff --git a/src/sage/databases/db_class_polynomials.py b/src/sage/databases/db_class_polynomials.py index 4362df56837..0aaad28ec82 100644 --- a/src/sage/databases/db_class_polynomials.py +++ b/src/sage/databases/db_class_polynomials.py @@ -18,6 +18,7 @@ - David Kohel (2006-08-04): initial version """ + # **************************************************************************** # Copyright (C) 2006 David Kohel # Copyright (C) 2016 Vincent Delecroix @@ -30,7 +31,7 @@ from .db_modular_polynomials import _dbz_to_integers -disc_format = "%07d" # disc_length = 7 +disc_format = "%07d" # disc_length = 7 level_format = "%03d" # level_length = 3 @@ -51,9 +52,9 @@ def _dbpath(self, disc, level=1): """ if level != 1: raise NotImplementedError("Level (= %s) > 1 not yet implemented" % level) - n1 = 5000*((abs(disc)-1)//5000) - s1 = disc_format % (n1+1) # _pad_int(n1+1, disc_length) - s2 = disc_format % (n1+5000) + n1 = 5000 * ((abs(disc) - 1) // 5000) + s1 = disc_format % (n1 + 1) # _pad_int(n1+1, disc_length) + s2 = disc_format % (n1 + 5000) subdir = "%s-%s" % (s1, s2) discstr = disc_format % abs(disc) return "PolHeeg/%s/%s/pol.%s.dbz" % (self.model, subdir, discstr) @@ -73,6 +74,7 @@ def __getitem__(self, disc): """ from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + classpol = self._dbpath(disc) coeff_list = _dbz_to_integers(classpol) return PolynomialRing(ZZ, 'x')(coeff_list) @@ -97,11 +99,13 @@ class HilbertClassPolynomialDatabase(ClassPolynomialDatabase): sage: db[-23] x^3 + 3491750*x^2 - 5151296875*x + 12771880859375 """ + model = "Cls" def __repr__(self): return "Hilbert class polynomial database" + ###################################################### # None of the following are implemented yet. ###################################################### @@ -111,6 +115,7 @@ class AtkinClassPolynomialDatabase(ClassPolynomialDatabase): """ The database of Atkin class polynomials. """ + model = "Atk" def __repr__(self): @@ -121,6 +126,7 @@ class WeberClassPolynomialDatabase(ClassPolynomialDatabase): """ The database of Weber class polynomials. """ + def __repr__(self): return "Weber class polynomial database" @@ -129,6 +135,7 @@ class DedekindEtaClassPolynomialDatabase(ClassPolynomialDatabase): """ The database of Dedekind eta class polynomials. """ + model = "Eta" def __repr__(self): diff --git a/src/sage/databases/db_modular_polynomials.py b/src/sage/databases/db_modular_polynomials.py index 45609c03607..74e99f9e192 100644 --- a/src/sage/databases/db_modular_polynomials.py +++ b/src/sage/databases/db_modular_polynomials.py @@ -21,6 +21,7 @@ - David Kohel (2006-08-04): initial version """ + # **************************************************************************** # Copyright (C) 2006 William Stein # Copyright (C) 2006 David Kohel @@ -54,6 +55,7 @@ def _dbz_to_string(name) -> str: '0\n1\n' """ from sage.env import sage_data_paths + for path in sage_data_paths('kohel'): filename = Path(path) / name if os.path.exists(filename): @@ -84,9 +86,9 @@ def _dbz_to_integer_list(name) -> list[list]: [[3, 0, 1], [2, 0, 48], [1, 1, -1], [1, 0, 768], [0, 0, 4096]] """ from sage.rings.integer import Integer + data = _dbz_to_string(name) - return [[Integer(v) for v in row.strip().split(" ")] - for row in data.split("\n")[:-1]] + return [[Integer(v) for v in row.strip().split(" ")] for row in data.split("\n")[:-1]] def _dbz_to_integers(name) -> list: @@ -98,6 +100,7 @@ def _dbz_to_integers(name) -> list: [0, 1] """ from sage.rings.integer import Integer + return [Integer(i) for i in _dbz_to_string(name).split()] @@ -215,6 +218,7 @@ class ClassicalModularPolynomialDatabase(ModularPolynomialDatabase): The database of classical modular polynomials, i.e. the polynomials Phi_N(X,Y) relating the j-functions j(q) and j(q^N). """ + model = "Cls" @@ -224,6 +228,7 @@ class DedekindEtaModularPolynomialDatabase(ModularPolynomialDatabase): of Dedekind eta functions, well-defined on X_0(N), relating x(q) and the j-function j(q). """ + model = "Eta" @@ -233,6 +238,7 @@ class DedekindEtaModularCorrespondenceDatabase(ModularCorrespondenceDatabase): the model of the curves `X_0(p) = \Bold{P}^1` are specified by quotients of Dedekind's eta function. """ + model = "EtaCrr" @@ -242,6 +248,7 @@ class AtkinModularPolynomialDatabase(ModularPolynomialDatabase): x is a function on invariant under the Atkin-Lehner invariant, with pole of minimal order at infinity. """ + model = "Atk" diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index 9efe0218962..d8f496ef54c 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -189,6 +189,7 @@ def mapping(sigma): - Martin Rubey (2015): initial version - Martin Rubey (2020): rewrite, adapt to new FindStat API """ + # **************************************************************************** # Copyright (C) 2015 Martin Rubey , # @@ -317,6 +318,7 @@ class FindStat(UniqueRepresentation, SageObject): :class:`FindStat` is a class preserving user information. """ + def __init__(self): r""" Initialize the database. @@ -552,15 +554,10 @@ def _data_to_str(data, domain, codomain=None): else: to_str_codom = codomain.to_string() - return "\n".join("\n".join(to_str_dom(element) for element in elements) - + "\n====> " - + FINDSTAT_VALUE_SEPARATOR.join(to_str_codom(value) - for value in values) - for elements, values in data) + return "\n".join("\n".join(to_str_dom(element) for element in elements) + "\n====> " + FINDSTAT_VALUE_SEPARATOR.join(to_str_codom(value) for value in values) for elements, values in data) -def _data_from_iterable(iterable, mapping=False, domain=None, - codomain=None, check=True): +def _data_from_iterable(iterable, mapping=False, domain=None, codomain=None, check=True): """ Return a list of pairs of lists of the same size, domain, and if applicable, codomain. @@ -671,10 +668,7 @@ def sanitize_pair(elts, vals): return elts, vals - lazy_data = lazy_list((sanitize_pair(elts, vals) - for elts, vals in iterator), - initial_values=[sanitize_pair(elts, vals) - for elts, vals in pre_data]) + lazy_data = lazy_list((sanitize_pair(elts, vals) for elts, vals in iterator), initial_values=[sanitize_pair(elts, vals) for elts, vals in pre_data]) if mapping: return lazy_data, domain, codomain return lazy_data, domain @@ -699,9 +693,7 @@ def _data_from_function(function, domain): sage: _data_from_function(lambda pi: pi[0], domain) # optional -- internet lazy list [([[1]], [1]), ([[1, 2]], [1]), ([[2, 1]], [2]), ...] """ - return lazy_list(([elt], [value]) - for elt, value in domain.first_terms(function) - if value is not None) + return lazy_list(([elt], [value]) for elt, value in domain.first_terms(function) if value is not None) def _data_from_data(data, max_values): @@ -741,7 +733,7 @@ def _data_from_data(data, max_values): query.append((elts, vals)) max_values -= len(elts) else: - break # assuming that the next pair is even larger + break # assuming that the next pair is even larger return query @@ -771,7 +763,7 @@ def _distribution_from_data(data, domain, max_values, generating_functions=False [([[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]], [1, 1, 2, 2, 3, 3])] """ - lvl_dict = {} # lvl: elts, vals + lvl_dict = {} # lvl: elts, vals total = max_values iterator = iter(data) levels_with_sizes = domain.levels_with_sizes() @@ -796,12 +788,9 @@ def _distribution_from_data(data, domain, max_values, generating_functions=False total -= levels_with_sizes[lvl] if generating_functions: - return {lvl: {val: vals.count(val) for val in set(vals)} - for lvl, (elts, vals) in lvl_dict.items() - if levels_with_sizes[lvl] == len(vals)} + return {lvl: {val: vals.count(val) for val in set(vals)} for lvl, (elts, vals) in lvl_dict.items() if levels_with_sizes[lvl] == len(vals)} - return [(elts, vals) for lvl, (elts, vals) in lvl_dict.items() - if levels_with_sizes[lvl] == len(elts)] + return [(elts, vals) for lvl, (elts, vals) in lvl_dict.items() if levels_with_sizes[lvl] == len(elts)] def _generating_functions_from_dict(gfs, style): @@ -836,18 +825,14 @@ def _generating_functions_from_dict(gfs, style): if style == "dictionary": return gfs if style == "list": - return {level: [gen_dict.get(deg, 0) - for deg in range(min(gen_dict), - max(gen_dict)+1)] - for level, gen_dict in gfs.items() if gen_dict} + return {level: [gen_dict.get(deg, 0) for deg in range(min(gen_dict), max(gen_dict) + 1)] for level, gen_dict in gfs.items() if gen_dict} if style == "polynomial": from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.integer_ring import ZZ + P = PolynomialRing(ZZ, "q", sparse=True) q = P.gen() - return {level: sum(coefficient * q**exponent - for exponent, coefficient in gen_dict.items()) - for level, gen_dict in gfs.items()} + return {level: sum(coefficient * q**exponent for exponent, coefficient in gen_dict.items()) for level, gen_dict in gfs.items()} raise ValueError("the argument 'style' (='%s') must be 'dictionary', 'polynomial', or 'list'" % style) @@ -878,19 +863,18 @@ def statistic(pi): code = "" if function is not None: from sage.misc.cachefunc import CachedFunction + try: if isinstance(function, CachedFunction): code = inspect.getsource(function.f) else: code = inspect.getsource(function) except (OSError, TypeError): - verbose("inspect.getsource could not get code from function provided", - caller_name='FindStat') + verbose("inspect.getsource could not get code from function provided", caller_name='FindStat') return code -def findstat(query=None, values=None, distribution=None, domain=None, - depth=FINDSTAT_DEFAULT_DEPTH, max_values=FINDSTAT_MAX_VALUES): +def findstat(query=None, values=None, distribution=None, domain=None, depth=FINDSTAT_DEFAULT_DEPTH, max_values=FINDSTAT_MAX_VALUES): r""" Return matching statistics. @@ -1053,9 +1037,7 @@ def get_values(raw, domain=None): known_terms = _data_from_function(raw, domain) function = raw else: - known_terms, domain = _data_from_iterable(raw, domain=domain, - mapping=False, - check=check_collection) + known_terms, domain = _data_from_iterable(raw, domain=domain, mapping=False, check=check_collection) function = None data = _data_from_data(known_terms, max_values) return known_terms, data, domain, function @@ -1065,9 +1047,7 @@ def get_distribution(raw, domain=None): known_terms = _data_from_function(raw, domain) function = raw else: - known_terms, domain = _data_from_iterable(raw, domain=domain, - mapping=False, - check=check_collection) + known_terms, domain = _data_from_iterable(raw, domain=domain, mapping=False, check=check_collection) function = None data = _distribution_from_data(known_terms, domain, max_values) return known_terms, data, domain, function @@ -1111,8 +1091,7 @@ def get_distribution(raw, domain=None): return FindStatStatisticQuery(values_of=values, depth=depth) known_terms, data, domain, function = get_values(values, domain) - return FindStatStatisticQuery(data=data, domain=domain, depth=depth, - known_terms=known_terms, function=function) + return FindStatStatisticQuery(data=data, domain=domain, depth=depth, known_terms=known_terms, function=function) if distribution is not None: if isinstance(distribution, (int, Integer, str, FindStatCombinatorialStatistic)): @@ -1121,8 +1100,7 @@ def get_distribution(raw, domain=None): return FindStatStatisticQuery(distribution_of=distribution, depth=depth) known_terms, data, domain, function = get_distribution(distribution, domain) - return FindStatStatisticQuery(data=data, domain=domain, depth=depth, - known_terms=known_terms, function=function) + return FindStatStatisticQuery(data=data, domain=domain, depth=depth, known_terms=known_terms, function=function) raise ValueError("the given arguments cannot be used for a FindStat search") @@ -1249,9 +1227,7 @@ def findmap(*args, **kwargs): if len(args) > 3: raise TypeError("findmap takes at most 3 positional arguments (%s given)" % len(args)) - bad_args = set(kwargs).difference(["values", "distribution", - "domain", "codomain", - "depth", "max_values"]) + bad_args = set(kwargs).difference(["values", "distribution", "domain", "codomain", "depth", "max_values"]) if bad_args: raise TypeError("findmap got unexpected keyword arguments '%s'" % bad_args) @@ -1277,10 +1253,7 @@ def get_values(raw, domain=None, codomain=None): codomain = FindStatCollection(known_terms[0][1][0]) function = raw else: - known_terms, domain, codomain = _data_from_iterable(raw, domain=domain, - codomain=codomain, - mapping=True, - check=check_collection) + known_terms, domain, codomain = _data_from_iterable(raw, domain=domain, codomain=codomain, mapping=True, check=check_collection) function = None data = _data_from_data(known_terms, max_values) return known_terms, data, domain, codomain, function @@ -1290,10 +1263,7 @@ def get_distribution(raw, domain=None, codomain=None): known_terms = _data_from_function(raw, domain) function = raw else: - known_terms, domain, codomain = _data_from_iterable(raw, domain=domain, - codomain=codomain, - mapping=True, - check=check_collection) + known_terms, domain, codomain = _data_from_iterable(raw, domain=domain, codomain=codomain, mapping=True, check=check_collection) function = None data = _distribution_from_data(known_terms, domain, max_values) return known_terms, data, domain, codomain, function @@ -1325,15 +1295,10 @@ def check_values(arg, values): raise ValueError("not both of `values` and `distribution` may be given for a FindStat query") if len(args) == 1: - if (values is None and distribution is None - and domain is None and codomain is None - and (isinstance(args[0], (int, Integer, FindStatCombinatorialMap)) - or (isinstance(args[0], str) - and not is_collection(args[0])))): + if values is None and distribution is None and domain is None and codomain is None and (isinstance(args[0], (int, Integer, FindStatCombinatorialMap)) or (isinstance(args[0], str) and not is_collection(args[0]))): return FindStatMap(args[0]) - if (isinstance(args[0], str) and - is_collection(args[0])): + if isinstance(args[0], str) and is_collection(args[0]): domain = check_domain(args[0], domain) else: @@ -1356,8 +1321,7 @@ def check_values(arg, values): if codomain is not None: codomain = FindStatCollection(codomain) - if (values is None and distribution is None - and (domain is not None or codomain is not None)): + if values is None and distribution is None and (domain is not None or codomain is not None): return FindStatMaps(domain=domain, codomain=codomain) if values is not None: @@ -1367,8 +1331,7 @@ def check_values(arg, values): return FindStatMapQuery(values_of=values, depth=depth) known_terms, data, domain, codomain, function = get_values(values, domain, codomain) - return FindStatMapQuery(data=data, domain=domain, codomain=codomain, depth=depth, - known_terms=known_terms, function=function) + return FindStatMapQuery(data=data, domain=domain, codomain=codomain, depth=depth, known_terms=known_terms, function=function) if distribution is not None: if isinstance(distribution, (int, Integer, str, FindStatCombinatorialMap)): @@ -1377,8 +1340,7 @@ def check_values(arg, values): return FindStatMapQuery(distribution_of=distribution, depth=depth) known_terms, data, domain, function = get_distribution(distribution, domain) - return FindStatMapQuery(data=data, domain=domain, codomain=codomain, depth=depth, - known_terms=known_terms, function=function) + return FindStatMapQuery(data=data, domain=domain, codomain=codomain, depth=depth, known_terms=known_terms, function=function) raise ValueError("the given arguments cannot be used for a FindStat search") @@ -1394,6 +1356,7 @@ class FindStatFunction(SageObject): This class provides methods to access and modify properties of a single statistic or map of the FindStat database. """ + def __init__(self, id, data=None, function=None): """ Initialize a statistic or map. @@ -1424,18 +1387,15 @@ def __init__(self, id, data=None, function=None): ....: "SageCode": ""}) St000000: a new statistic """ - self._id = id # as padded identifier, with number 0 reserved for new statistics or maps - self._modified = False # set in every method modifying the data + self._id = id # as padded identifier, with number 0 reserved for new statistics or maps + self._modified = False # set in every method modifying the data if callable(function): self._function = function else: self._function = False # determines that FindStat code may not be executed if self.id() != 0 and data is not None: - raise ValueError("data (%s) may be provided if and only if id (%s) is %s or %s" % - (data, id, - FINDSTAT_STATISTIC_PADDED_IDENTIFIER % 0, - FINDSTAT_MAP_PADDED_IDENTIFIER % 0)) - self._data_cache = data # a dictionary with "Description", "Code", etc. + raise ValueError("data (%s) may be provided if and only if id (%s) is %s or %s" % (data, id, FINDSTAT_STATISTIC_PADDED_IDENTIFIER % 0, FINDSTAT_MAP_PADDED_IDENTIFIER % 0)) + self._data_cache = data # a dictionary with "Description", "Code", etc. def _data(self): """ @@ -1489,6 +1449,7 @@ def __call__(self, elt): if not self.sage_code(): raise ValueError("there is no verified code available for %s" % self) from sage.repl.preparse import preparse + try: l = {} environment = 'sage.all' @@ -1700,8 +1661,7 @@ def references(self): # this means that the link is unhandled result.append(ref) else: - author_title = ", ".join(e for e in [bibitem["Author"], bibitem["Title"]] - if e) + author_title = ", ".join(e for e in [bibitem["Author"], bibitem["Title"]] if e) result.append(comment + author_title + " " + "".join(parts[1:])) return FancyTuple(result) @@ -1795,6 +1755,7 @@ def statistic(x): self._modified = True self._data_cache["SageCode"] = value + ###################################################################### # statistics ###################################################################### @@ -1808,6 +1769,7 @@ class FindStatCombinatorialStatistic(SageObject): :class:`FindStatStatistic`, :class:`FindStatCompoundStatistic` and :class:`FindStatStatisticQuery`. """ + def __init__(self): """ Initialize the combinatorial statistic. @@ -1914,8 +1876,7 @@ def first_terms_str(self, max_values=FINDSTAT_MAX_SUBMISSION_VALUES): sage: len(st.cache) # optional -- internet 100 """ - return "\n".join(key + " => " + str(val) - for key, val in self._first_terms_raw(max_values=max_values)) + return "\n".join(key + " => " + str(val) for key, val in self._first_terms_raw(max_values=max_values)) def _fetch_first_terms(self): r""" @@ -1933,11 +1894,9 @@ def _fetch_first_terms(self): from_str = self.domain().from_string() if self._first_terms_raw_cache is None: self._first_terms_raw_cache = self._fetch_first_terms_raw() - return [(from_str(obj), Integer(val)) - for obj, val in self._first_terms_raw_cache] + return [(from_str(obj), Integer(val)) for obj, val in self._first_terms_raw_cache] - def _generating_functions_dict(self, - max_values=FINDSTAT_MAX_SUBMISSION_VALUES): + def _generating_functions_dict(self, max_values=FINDSTAT_MAX_SUBMISSION_VALUES): r""" Return the generating functions of ``self`` as dictionary of dictionaries, computed from ``self.first_terms``. @@ -1970,8 +1929,7 @@ def _generating_functions_dict(self, del gfs[lvl] return gfs - def generating_functions(self, style='polynomial', - max_values=FINDSTAT_MAX_SUBMISSION_VALUES): + def generating_functions(self, style='polynomial', max_values=FINDSTAT_MAX_SUBMISSION_VALUES): r""" Return the generating functions of the statistic as a dictionary. @@ -2068,6 +2026,7 @@ def oeis_search(self, search_size=32, verbose=True): 0: A067311: Triangle read by rows: T(n,k) gives number of ways of arranging n chords on a circle with k simple intersections ... """ from sage.databases.oeis import oeis + gen_funcs = self.generating_functions(style='list') OEIS_string = "" @@ -2094,10 +2053,7 @@ def oeis_search(self, search_size=32, verbose=True): print("Too little information to search the OEIS for this statistic (only %s values given)." % counter) -class FindStatStatistic(Element, - FindStatFunction, - FindStatCombinatorialStatistic, - metaclass=InheritComparisonClasscallMetaclass): +class FindStatStatistic(Element, FindStatFunction, FindStatCombinatorialStatistic, metaclass=InheritComparisonClasscallMetaclass): r""" A FindStat statistic. @@ -2117,6 +2073,7 @@ class FindStatStatistic(Element, :class:`FindStatStatistics` """ + @staticmethod def __classcall_private__(cls, entry): """ @@ -2215,9 +2172,7 @@ def _fetch_data(self): """ fields = "Bibliography,Code,Description,Domain,Name,References,SageCode" fields_Bibliography = "Author,Title" - url = (FINDSTAT_API_STATISTICS + self.id_str() - + "?fields=" + fields - + "&fields[Bibliography]=" + fields_Bibliography) + url = FINDSTAT_API_STATISTICS + self.id_str() + "?fields=" + fields + "&fields[Bibliography]=" + fields_Bibliography verbose("fetching statistic data %s" % url, caller_name='FindStatStatistic') included = _get_json(url)["included"] @@ -2440,6 +2395,7 @@ class FindStatStatistics(UniqueRepresentation, Parent): The number of crossings of a perfect matching. The number of crossings plus two-nestings of a perfect matching. """ + def __init__(self, domain=None): """ TESTS:: @@ -2540,6 +2496,7 @@ def _an_element_(self): return next(iter(self)) except StopIteration: from sage.categories.sets_cat import EmptySetError + raise EmptySetError Element = FindStatStatistic @@ -2549,10 +2506,8 @@ class FindStatStatisticQuery(FindStatStatistic): """ A class representing a query for FindStat (compound) statistics. """ - def __init__(self, data=None, values_of=None, distribution_of=None, - domain=None, known_terms=None, function=None, - depth=FINDSTAT_DEFAULT_DEPTH, - debug=False): + + def __init__(self, data=None, values_of=None, distribution_of=None, domain=None, known_terms=None, function=None, depth=FINDSTAT_DEFAULT_DEPTH, debug=False): """ Initialize a query for FindStat (compound) statistics. @@ -2612,8 +2567,7 @@ def __init__(self, data=None, values_of=None, distribution_of=None, assert all(param is None for param in [distribution_of, values_of]) domain = FindStatCollection(domain) - query = {"Domain": domain.id_str(), - "Data": _data_to_str(self._first_terms, domain)} + query = {"Domain": domain.id_str(), "Data": _data_to_str(self._first_terms, domain)} elif distribution_of is not None: assert all(param is None for param in [data, known_terms, values_of]) @@ -2649,23 +2603,12 @@ def __init__(self, data=None, values_of=None, distribution_of=None, result = [] for match in response["data"]: entry = response["included"]["MatchingStatistics"][match] - result.append(FindStatMatchingStatistic(entry["MatchingStatistic"], - entry["Offset"], - entry["Quality"], - domain=domain)) + result.append(FindStatMatchingStatistic(entry["MatchingStatistic"], entry["Offset"], entry["Quality"], domain=domain)) self._result = FancyTuple(result) - FindStatFunction.__init__(self, FINDSTAT_STATISTIC_PADDED_IDENTIFIER % 0, - data={"Bibliography": {}, - "Code": _get_code_from_callable(function), - "Description": "", - "Domain": domain, - "Name": "a new statistic on %s" % domain.name("plural"), - "References": "", - "SageCode": ""}, - function=function) - Element.__init__(self, FindStatStatistics()) # this is not completely correct, but it works + FindStatFunction.__init__(self, FINDSTAT_STATISTIC_PADDED_IDENTIFIER % 0, data={"Bibliography": {}, "Code": _get_code_from_callable(function), "Description": "", "Domain": domain, "Name": "a new statistic on %s" % domain.name("plural"), "References": "", "SageCode": ""}, function=function) + Element.__init__(self, FindStatStatistics()) # this is not completely correct, but it works @lazy_attribute def _first_terms_cache(self): @@ -2699,10 +2642,8 @@ def first_terms(self, max_values=FINDSTAT_MAX_SUBMISSION_VALUES): {[]: 0, [(1, 2)]: 0} """ - new_terms = self._known_terms[self._known_terms_number:max_values] - self._first_terms_cache.update((objs[0], vals[0]) - for objs, vals in new_terms - if len(vals) == 1) + new_terms = self._known_terms[self._known_terms_number : max_values] + self._first_terms_cache.update((objs[0], vals[0]) for objs, vals in new_terms if len(vals) == 1) self._known_terms_number = max(max_values, self._known_terms_number) return dict(self._first_terms_cache) @@ -2721,11 +2662,9 @@ def _first_terms_raw(self, max_values): [('[]', 0), ('[(1, 2)]', 0)] """ to_str = self.domain().to_string() - return [(to_str(obj), val) - for obj, val in self.first_terms(max_values=max_values).items()] + return [(to_str(obj), val) for obj, val in self.first_terms(max_values=max_values).items()] - def _generating_functions_dict(self, - max_values=FINDSTAT_MAX_SUBMISSION_VALUES): + def _generating_functions_dict(self, max_values=FINDSTAT_MAX_SUBMISSION_VALUES): """ Return the generating functions of the levels where all values can be determined. @@ -2742,10 +2681,7 @@ def _generating_functions_dict(self, sage: q.generating_functions() # optional -- internet, indirect doctest {3: 2*q^3 + 2*q^2 + 2*q} """ - return _distribution_from_data(self._known_terms, - self.domain(), - max_values, - generating_functions=True) + return _distribution_from_data(self._known_terms, self.domain(), max_values, generating_functions=True) def __repr__(self): """ @@ -2836,12 +2772,11 @@ def __init__(self, id, domain=None, check=True): self._domain = self._statistic.domain() self._maps = FindStatCompoundMap("", domain=self._domain, codomain=self._domain) self._id = self._statistic.id_str() - if (check - and self._maps.codomain() != self._statistic.domain()): + if check and self._maps.codomain() != self._statistic.domain(): raise ValueError("the statistic %s cannot be composed with the map %s" % (self._statistic, self._maps)) FindStatCombinatorialStatistic.__init__(self) - Element.__init__(self, FindStatStatistics()) # this is not completely correct, but it works + Element.__init__(self, FindStatStatistics()) # this is not completely correct, but it works def _fetch_first_terms_raw(self) -> list: r""" @@ -3084,6 +3019,7 @@ def info(self): print("among the values you sent, %s percent are actually in the database," % self.quality()[0]) print("among the distinct values you sent, %s percent are actually in the database" % self.quality()[1]) + ###################################################################### # maps ###################################################################### @@ -3094,13 +3030,11 @@ class FindStatCombinatorialMap(SageObject): A class serving as common ancestor of :class:`FindStatStatistic` and :class:`FindStatCompoundStatistic`. """ + pass -class FindStatMap(Element, - FindStatFunction, - FindStatCombinatorialMap, - metaclass=InheritComparisonClasscallMetaclass): +class FindStatMap(Element, FindStatFunction, FindStatCombinatorialMap, metaclass=InheritComparisonClasscallMetaclass): r""" A FindStat map. @@ -3120,6 +3054,7 @@ class FindStatMap(Element, :class:`FindStatMaps` """ + @staticmethod def __classcall_private__(cls, entry): """ @@ -3203,9 +3138,7 @@ def _fetch_data(self): """ fields = "Bibliography,Codomain,Description,Domain,Name,Properties,References,SageCode" fields_Bibliography = "Author,Title" - url = (FINDSTAT_API_MAPS + self.id_str() - + "?fields=" + fields - + "&fields[Bibliography]=" + fields_Bibliography) + url = FINDSTAT_API_MAPS + self.id_str() + "?fields=" + fields + "&fields[Bibliography]=" + fields_Bibliography verbose("fetching map data %s" % url, caller_name='FindStatMap') included = _get_json(url)["included"] # slightly simplify the representation @@ -3353,9 +3286,7 @@ def info(self): sage: findmap("Mp00116").info() # optional -- internet Mp00116: Kasraoui-Zeng: Perfect matchings -> Perfect matchings """ - print(" %s: %s -> %s" % (self, - self.domain().name("plural"), - self.codomain().name("plural"))) + print(" %s: %s -> %s" % (self, self.domain().name("plural"), self.codomain().name("plural"))) _all_maps = {} @@ -3399,6 +3330,7 @@ class FindStatMaps(UniqueRepresentation, Parent): Dyck paths -> Dyck paths reverse """ + def __init__(self, domain=None, codomain=None): """ TESTS:: @@ -3511,6 +3443,7 @@ def _an_element_(self): return next(iter(self)) except StopIteration: from sage.categories.sets_cat import EmptySetError + raise EmptySetError Element = FindStatMap @@ -3520,10 +3453,8 @@ class FindStatMapQuery(FindStatMap): """ A class representing a query for FindStat (compound) maps. """ - def __init__(self, data=None, values_of=None, distribution_of=None, - domain=None, codomain=None, known_terms=None, function=None, - depth=FINDSTAT_DEFAULT_DEPTH, - debug=False): + + def __init__(self, data=None, values_of=None, distribution_of=None, domain=None, codomain=None, known_terms=None, function=None, depth=FINDSTAT_DEFAULT_DEPTH, debug=False): """ Initialize a query for FindStat (compound) maps. @@ -3581,9 +3512,7 @@ def __init__(self, data=None, values_of=None, distribution_of=None, domain = FindStatCollection(domain) codomain = FindStatCollection(codomain) - query = {"Domain": domain.id_str(), - "Codomain": codomain.id_str(), - "Data": _data_to_str(self._first_terms, domain, codomain)} + query = {"Domain": domain.id_str(), "Codomain": codomain.id_str(), "Data": _data_to_str(self._first_terms, domain, codomain)} elif distribution_of is not None: assert all(param is None for param in [data, known_terms, values_of]) @@ -3621,22 +3550,11 @@ def __init__(self, data=None, values_of=None, distribution_of=None, result = [] for match in response["data"]: entry = response["included"]["MatchingMaps"][match] - result.append(FindStatMatchingMap(entry["MatchingMap"], - entry["Quality"])) + result.append(FindStatMatchingMap(entry["MatchingMap"], entry["Quality"])) self._result = FancyTuple(result) - FindStatFunction.__init__(self, FINDSTAT_MAP_PADDED_IDENTIFIER % 0, - data={"Bibliography": {}, - "Code": _get_code_from_callable(function), - "Description": "", - "Domain": domain, - "Codomain": codomain, - "Name": "a new map from %s to %s" % (domain.name("plural"), codomain.name("plural")), - "References": "", - "Properties": "", - "SageCode": ""}, - function=function) - Element.__init__(self, FindStatMaps()) # this is not completely correct, but it works + FindStatFunction.__init__(self, FINDSTAT_MAP_PADDED_IDENTIFIER % 0, data={"Bibliography": {}, "Code": _get_code_from_callable(function), "Description": "", "Domain": domain, "Codomain": codomain, "Name": "a new map from %s to %s" % (domain.name("plural"), codomain.name("plural")), "References": "", "Properties": "", "SageCode": ""}, function=function) + Element.__init__(self, FindStatMaps()) # this is not completely correct, but it works def __repr__(self): """ @@ -3725,9 +3643,7 @@ def __init__(self, id, domain=None, codomain=None, check=True): self._codomain = self._domain else: self._maps = [FindStatMap(m) for m in id.split(FINDSTAT_MAP_SEPARATOR)][::-1] - if (check - and not all(self._maps[i].codomain() == self._maps[i+1].domain() - for i in range(len(self._maps)-1))): + if check and not all(self._maps[i].codomain() == self._maps[i + 1].domain() for i in range(len(self._maps) - 1)): raise ValueError("the sequence of maps %s cannot be composed" % self._maps) if domain is None: self._domain = self._maps[0].domain() @@ -3739,7 +3655,7 @@ def __init__(self, id, domain=None, codomain=None, check=True): self._codomain = FindStatCollection(codomain) self._id = FINDSTAT_MAP_SEPARATOR.join(m.id_str() for m in reversed(self._maps)) - Element.__init__(self, FindStatMaps()) # this is not completely correct, but it works + Element.__init__(self, FindStatMaps()) # this is not completely correct, but it works def domain(self): """ @@ -3938,6 +3854,7 @@ def info(self): # collections ###################################################################### + # helper for generation of CartanTypes def _finite_irreducible_cartan_types_by_rank(n): """ @@ -3955,21 +3872,22 @@ def _finite_irreducible_cartan_types_by_rank(n): sage: _finite_irreducible_cartan_types_by_rank(2) [['A', 2], ['B', 2], ['G', 2]] """ - cartan_types = [CartanType(['A',n])] + cartan_types = [CartanType(['A', n])] if n >= 2: - cartan_types += [CartanType(['B',n])] + cartan_types += [CartanType(['B', n])] if n >= 3: - cartan_types += [CartanType(['C',n])] + cartan_types += [CartanType(['C', n])] if n >= 4: - cartan_types += [CartanType(['D',n])] + cartan_types += [CartanType(['D', n])] if 6 <= n <= 8: - cartan_types += [CartanType(['E',n])] + cartan_types += [CartanType(['E', n])] if n == 4: - cartan_types += [CartanType(['F',n])] + cartan_types += [CartanType(['F', n])] if n == 2: - cartan_types += [CartanType(['G',n])] + cartan_types += [CartanType(['G', n])] return cartan_types + # helper for generation of PlanePartitions @@ -3993,10 +3911,10 @@ def _plane_partitions_by_size_aux(n, outer=None): yield [] return if outer is None: - outer = [n]*n - for k in range(1, n+1): + outer = [n] * n + for k in range(1, n + 1): for la in Partitions(k, outer=outer): - for pp in _plane_partitions_by_size_aux(n-k, outer=la): + for pp in _plane_partitions_by_size_aux(n - k, outer=la): pp = [la] + pp yield pp @@ -4029,6 +3947,7 @@ def _plane_partitions_by_size(n): for pp in _plane_partitions_by_size_aux(n): yield PlanePartition(pp) + # helper for generation of Lattices @@ -4061,8 +3980,7 @@ def _finite_lattices(n): yield LatticePoset(Q) -class FindStatCollection(Element, - metaclass=InheritComparisonClasscallMetaclass): +class FindStatCollection(Element, metaclass=InheritComparisonClasscallMetaclass): r""" A FindStat collection. @@ -4109,6 +4027,7 @@ class FindStatCollection(Element, :class:`FindStatCollections` """ + @staticmethod def __classcall_private__(cls, entry): """ @@ -4383,17 +4302,14 @@ def first_terms(self, function, level=None): """ if self._sageconstructor_overridden is None: if level is None: - g = (x - for level in self._data["LevelsWithSizes"] - for x in self._data["Code"].elements_on_level(level)) + g = (x for level in self._data["LevelsWithSizes"] for x in self._data["Code"].elements_on_level(level)) else: g = (x for x in self._data["Code"].elements_on_level(level)) else: if level is None: g = self._sageconstructor_overridden else: - g = (x for x in self._sageconstructor_overridden - if self.element_level(x) == level) + g = (x for x in self._sageconstructor_overridden if self.element_level(x) == level) return lazy_list((x, function(x)) for x in g) @@ -4531,170 +4447,37 @@ def name(self, style='singular'): from collections import namedtuple -_SupportedFindStatCollection = namedtuple("SupportedFindStatCollection", - ["string_to_element", - "element_to_string", - "elements_on_level", # return all elements on given level - "element_level", # return level of a given element - "is_element"]) # return whether element is member of this collection + +_SupportedFindStatCollection = namedtuple("SupportedFindStatCollection", ["string_to_element", "element_to_string", "elements_on_level", "element_level", "is_element"]) # return all elements on given level # return level of a given element # return whether element is member of this collection # this dictionary must be sorted so that subclasses come before # superclasses, eg., "StandardTableaux" before "SemistandardTableaux" _SupportedFindStatCollections = { - "Permutations": - _SupportedFindStatCollection(lambda x: Permutation(literal_eval(x)), - str, - Permutations, - lambda x: x.size(), - lambda x: isinstance(x, Permutation)), - "BinaryWords": - _SupportedFindStatCollection(lambda x: Word((int(e) for e in str(x)), alphabet=[0,1]), - str, - lambda x: Words([0,1], length=x), - lambda x: x.length(), - lambda x: isinstance(x, Word_class)), - "AlternatingSignMatrices": - _SupportedFindStatCollection(lambda x: AlternatingSignMatrix(literal_eval(x)), - lambda x: str(list(map(list, x.to_matrix().rows()))), - AlternatingSignMatrices, - lambda x: x.to_matrix().nrows(), - lambda x: isinstance(x, AlternatingSignMatrix)), - "BinaryTrees": - _SupportedFindStatCollection(lambda x: BinaryTree(str(x)), - str, - BinaryTrees, - lambda x: x.number_of_nodes(), - lambda x: isinstance(x, BinaryTree)), - "Cores": - _SupportedFindStatCollection(lambda x: Core(*literal_eval(x)), - lambda X: "( " + X._repr_() + ", " + str(X.k()) + " )", - lambda x: Cores(x[1], x[0]), - lambda x: (x.length(), x.k()), - lambda x: isinstance(x, Core)), - "DyckPaths": - _SupportedFindStatCollection(lambda x: DyckWord(literal_eval(x)), - lambda x: str(list(DyckWord(x))), - DyckWords, - lambda x: x.semilength(), - lambda x: isinstance(x, DyckWord)), - "FiniteCartanTypes": - _SupportedFindStatCollection(lambda x: CartanType(*literal_eval(str(x))), - str, - _finite_irreducible_cartan_types_by_rank, - lambda x: x.rank(), - lambda x: isinstance(x, CartanType_abstract)), - "GelfandTsetlinPatterns": - _SupportedFindStatCollection(lambda x: GelfandTsetlinPattern(literal_eval(x)), - str, - lambda x: (P - for la in Partitions(x[1], max_length=x[0]) - for P in GelfandTsetlinPatterns(top_row=la + [0]*(x[0]-len(la)))), - lambda x: (len(x[0]), sum(x[0])), - lambda x: (x == GelfandTsetlinPatterns - or isinstance(x, GelfandTsetlinPattern))), - "Graphs": - _SupportedFindStatCollection(lambda x: (lambda E, V: Graph([list(range(V)), - lambda i,j: (i,j) in E or (j,i) in E], - immutable=True))(*literal_eval(x)), - lambda X: str((X.edges(labels=False, sort=True), X.n_vertices())), - lambda x: (g.copy(immutable=True) for g in graphs(x, copy=False)), - lambda x: x.n_vertices(), - lambda x: isinstance(x, Graph)), - "IntegerPartitions": - _SupportedFindStatCollection(lambda x: Partition(literal_eval(x)), - str, - Partitions, - lambda x: x.size(), - lambda x: isinstance(x, Partition)), - "IntegerCompositions": - _SupportedFindStatCollection(lambda x: Composition(literal_eval(x)), - str, - Compositions, - lambda x: x.size(), - lambda x: isinstance(x, Composition)), - "OrderedTrees": - _SupportedFindStatCollection(lambda x: OrderedTree(literal_eval(x)), - str, - OrderedTrees, - lambda x: x.number_of_nodes(), - lambda x: isinstance(x, OrderedTree)), - "ParkingFunctions": - _SupportedFindStatCollection(lambda x: ParkingFunction(literal_eval(x)), - str, - ParkingFunctions, - len, - lambda x: isinstance(x, ParkingFunction)), - "Lattices": - _SupportedFindStatCollection(lambda x: (lambda R, E: LatticePoset((list(range(E)), R)))(*literal_eval(x)), - lambda X: str((sorted(X._hasse_diagram.cover_relations()), - len(X._hasse_diagram.vertices(sort=False)))), - _finite_lattices, - lambda x: x.cardinality(), - lambda x: isinstance(x, FiniteLatticePoset)), - "Posets": - _SupportedFindStatCollection(lambda x: (lambda R, E: Poset((list(range(E)), R)))(*literal_eval(x)), - lambda X: str((sorted(X._hasse_diagram.cover_relations()), - len(X._hasse_diagram.vertices(sort=False)))), - Posets, - lambda x: x.cardinality(), - lambda x: isinstance(x, FinitePoset)), - "StandardTableaux": - _SupportedFindStatCollection(lambda x: StandardTableau(literal_eval(x)), - str, - StandardTableaux, - lambda x: x.size(), - lambda x: isinstance(x, StandardTableau)), - "SemistandardTableaux": - _SupportedFindStatCollection(lambda x: SemistandardTableau(literal_eval(x)), - str, - lambda x: (T for T in SemistandardTableaux(size=x[0], max_entry=x[1]) - if max(T.entries()) == x[1]), - lambda x: (x.size(), max(x.entries())), - lambda x: isinstance(x, SemistandardTableau)), - "PerfectMatchings": - _SupportedFindStatCollection(lambda x: PerfectMatching(literal_eval(x)), - str, - PerfectMatchings, - lambda x: x.size(), - lambda x: isinstance(x, PerfectMatching)), - "SetPartitions": - _SupportedFindStatCollection(lambda x: SetPartition(literal_eval(x.replace('{','[').replace('}',']'))), - str, - SetPartitions, - lambda x: x.size(), - lambda x: isinstance(x, SetPartition)), - "SkewPartitions": - _SupportedFindStatCollection(lambda x: SkewPartition(literal_eval(x)), - str, - SkewPartitions, - lambda x: x.size(), - lambda x: isinstance(x, SkewPartition)), - "SignedPermutations": - _SupportedFindStatCollection(lambda x: SignedPermutations(len(literal_eval(x)))(list(literal_eval(x))), - str, - SignedPermutations, - lambda x: len(list(x)), - lambda x: isinstance(x, SignedPermutation)), - "PlanePartitions": - _SupportedFindStatCollection(lambda x: PlanePartition(literal_eval(x)), - lambda X: str(list(X)).replace(" ",""), - _plane_partitions_by_size, - lambda x: sum(sum(la) for la in x), - lambda x: isinstance(x, PlanePartition)), - "DecoratedPermutations": - _SupportedFindStatCollection(lambda x: DecoratedPermutation([v if v > 0 else (i if v == 0 else -i) - for i, v in enumerate(literal_eval(x.replace("+","0").replace("-","-1")), 1)]), - lambda x: "[" + ",".join((str(v) if abs(v) != i else ("+" if v > 0 else "-") - for i, v in enumerate(x, 1))) + "]", - DecoratedPermutations, - lambda x: x.size(), - lambda x: isinstance(x, DecoratedPermutation)), - "OrderedSetPartitions": - _SupportedFindStatCollection(lambda x: OrderedSetPartition(literal_eval(x.replace('{','[').replace('}',']'))), - str, - OrderedSetPartitions, - lambda x: x.size(), - lambda x: isinstance(x, OrderedSetPartition))} + "Permutations": _SupportedFindStatCollection(lambda x: Permutation(literal_eval(x)), str, Permutations, lambda x: x.size(), lambda x: isinstance(x, Permutation)), + "BinaryWords": _SupportedFindStatCollection(lambda x: Word((int(e) for e in str(x)), alphabet=[0, 1]), str, lambda x: Words([0, 1], length=x), lambda x: x.length(), lambda x: isinstance(x, Word_class)), + "AlternatingSignMatrices": _SupportedFindStatCollection(lambda x: AlternatingSignMatrix(literal_eval(x)), lambda x: str(list(map(list, x.to_matrix().rows()))), AlternatingSignMatrices, lambda x: x.to_matrix().nrows(), lambda x: isinstance(x, AlternatingSignMatrix)), + "BinaryTrees": _SupportedFindStatCollection(lambda x: BinaryTree(str(x)), str, BinaryTrees, lambda x: x.number_of_nodes(), lambda x: isinstance(x, BinaryTree)), + "Cores": _SupportedFindStatCollection(lambda x: Core(*literal_eval(x)), lambda X: "( " + X._repr_() + ", " + str(X.k()) + " )", lambda x: Cores(x[1], x[0]), lambda x: (x.length(), x.k()), lambda x: isinstance(x, Core)), + "DyckPaths": _SupportedFindStatCollection(lambda x: DyckWord(literal_eval(x)), lambda x: str(list(DyckWord(x))), DyckWords, lambda x: x.semilength(), lambda x: isinstance(x, DyckWord)), + "FiniteCartanTypes": _SupportedFindStatCollection(lambda x: CartanType(*literal_eval(str(x))), str, _finite_irreducible_cartan_types_by_rank, lambda x: x.rank(), lambda x: isinstance(x, CartanType_abstract)), + "GelfandTsetlinPatterns": _SupportedFindStatCollection(lambda x: GelfandTsetlinPattern(literal_eval(x)), str, lambda x: (P for la in Partitions(x[1], max_length=x[0]) for P in GelfandTsetlinPatterns(top_row=la + [0] * (x[0] - len(la)))), lambda x: (len(x[0]), sum(x[0])), lambda x: (x == GelfandTsetlinPatterns or isinstance(x, GelfandTsetlinPattern))), + "Graphs": _SupportedFindStatCollection(lambda x: (lambda E, V: Graph([list(range(V)), lambda i, j: (i, j) in E or (j, i) in E], immutable=True))(*literal_eval(x)), lambda X: str((X.edges(labels=False, sort=True), X.n_vertices())), lambda x: (g.copy(immutable=True) for g in graphs(x, copy=False)), lambda x: x.n_vertices(), lambda x: isinstance(x, Graph)), + "IntegerPartitions": _SupportedFindStatCollection(lambda x: Partition(literal_eval(x)), str, Partitions, lambda x: x.size(), lambda x: isinstance(x, Partition)), + "IntegerCompositions": _SupportedFindStatCollection(lambda x: Composition(literal_eval(x)), str, Compositions, lambda x: x.size(), lambda x: isinstance(x, Composition)), + "OrderedTrees": _SupportedFindStatCollection(lambda x: OrderedTree(literal_eval(x)), str, OrderedTrees, lambda x: x.number_of_nodes(), lambda x: isinstance(x, OrderedTree)), + "ParkingFunctions": _SupportedFindStatCollection(lambda x: ParkingFunction(literal_eval(x)), str, ParkingFunctions, len, lambda x: isinstance(x, ParkingFunction)), + "Lattices": _SupportedFindStatCollection(lambda x: (lambda R, E: LatticePoset((list(range(E)), R)))(*literal_eval(x)), lambda X: str((sorted(X._hasse_diagram.cover_relations()), len(X._hasse_diagram.vertices(sort=False)))), _finite_lattices, lambda x: x.cardinality(), lambda x: isinstance(x, FiniteLatticePoset)), + "Posets": _SupportedFindStatCollection(lambda x: (lambda R, E: Poset((list(range(E)), R)))(*literal_eval(x)), lambda X: str((sorted(X._hasse_diagram.cover_relations()), len(X._hasse_diagram.vertices(sort=False)))), Posets, lambda x: x.cardinality(), lambda x: isinstance(x, FinitePoset)), + "StandardTableaux": _SupportedFindStatCollection(lambda x: StandardTableau(literal_eval(x)), str, StandardTableaux, lambda x: x.size(), lambda x: isinstance(x, StandardTableau)), + "SemistandardTableaux": _SupportedFindStatCollection(lambda x: SemistandardTableau(literal_eval(x)), str, lambda x: (T for T in SemistandardTableaux(size=x[0], max_entry=x[1]) if max(T.entries()) == x[1]), lambda x: (x.size(), max(x.entries())), lambda x: isinstance(x, SemistandardTableau)), + "PerfectMatchings": _SupportedFindStatCollection(lambda x: PerfectMatching(literal_eval(x)), str, PerfectMatchings, lambda x: x.size(), lambda x: isinstance(x, PerfectMatching)), + "SetPartitions": _SupportedFindStatCollection(lambda x: SetPartition(literal_eval(x.replace('{', '[').replace('}', ']'))), str, SetPartitions, lambda x: x.size(), lambda x: isinstance(x, SetPartition)), + "SkewPartitions": _SupportedFindStatCollection(lambda x: SkewPartition(literal_eval(x)), str, SkewPartitions, lambda x: x.size(), lambda x: isinstance(x, SkewPartition)), + "SignedPermutations": _SupportedFindStatCollection(lambda x: SignedPermutations(len(literal_eval(x)))(list(literal_eval(x))), str, SignedPermutations, lambda x: len(list(x)), lambda x: isinstance(x, SignedPermutation)), + "PlanePartitions": _SupportedFindStatCollection(lambda x: PlanePartition(literal_eval(x)), lambda X: str(list(X)).replace(" ", ""), _plane_partitions_by_size, lambda x: sum(sum(la) for la in x), lambda x: isinstance(x, PlanePartition)), + "DecoratedPermutations": _SupportedFindStatCollection(lambda x: DecoratedPermutation([v if v > 0 else (i if v == 0 else -i) for i, v in enumerate(literal_eval(x.replace("+", "0").replace("-", "-1")), 1)]), lambda x: "[" + ",".join((str(v) if abs(v) != i else ("+" if v > 0 else "-") for i, v in enumerate(x, 1))) + "]", DecoratedPermutations, lambda x: x.size(), lambda x: isinstance(x, DecoratedPermutation)), + "OrderedSetPartitions": _SupportedFindStatCollection(lambda x: OrderedSetPartition(literal_eval(x.replace('{', '[').replace('}', ']'))), str, OrderedSetPartitions, lambda x: x.size(), lambda x: isinstance(x, OrderedSetPartition)), +} class FindStatCollections(UniqueRepresentation, Parent): @@ -4735,6 +4518,7 @@ class FindStatCollections(UniqueRepresentation, Parent): Cc0029: Lattices, Cc0030: Ordered set partitions] """ + def __init__(self): """ Fetch the collections from FindStat. @@ -4749,8 +4533,7 @@ def __init__(self): url = FINDSTAT_API_COLLECTIONS + "?fields=" + fields d = _get_json(url, object_pairs_hook=dict)["included"]["Collections"] for id, data in d.items(): - data["LevelsWithSizes"] = {literal_eval(level): size - for level, size in data["LevelsWithSizes"].items()} + data["LevelsWithSizes"] = {literal_eval(level): size for level, size in data["LevelsWithSizes"].items()} if data["NameWiki"] in _SupportedFindStatCollections: data["Code"] = _SupportedFindStatCollections[data["NameWiki"]] else: @@ -4759,10 +4542,10 @@ def __init__(self): print("To use it with this interface, it has to be added to the dictionary") print(" _SupportedFindStatCollections in src/sage/databases/findstat.py") print("of the SageMath distribution. Please open an issue on github!") -# print("Very likely, the following code would work:") -# fields = "SageCodeElementToString,SageCodeElementsOnLevel,SageCodeStringToElement" -# url = FINDSTAT_API_COLLECTIONS + id + "?fields=" + fields -# print(json.load(urlopen(url))["included"]["Collections"][id]) + # print("Very likely, the following code would work:") + # fields = "SageCodeElementToString,SageCodeElementsOnLevel,SageCodeStringToElement" + # url = FINDSTAT_API_COLLECTIONS + id + "?fields=" + fields + # print(json.load(urlopen(url))["included"]["Collections"][id]) def position(item): try: @@ -4857,10 +4640,7 @@ def normalize(e): return "".join(e.split()).upper() for id, data in self._findstat_collections.items(): - if normalize(entry) in (normalize(id), - normalize(data["NameWiki"]), - normalize(data["NamePlural"]), - normalize(data["Name"])): + if normalize(entry) in (normalize(id), normalize(data["NameWiki"]), normalize(data["NamePlural"]), normalize(data["Name"])): return self.element_class(self, id, data, None) elif isinstance(entry, (int, Integer)): @@ -4879,12 +4659,13 @@ def normalize(e): # first check whether the class fits: for id, data in self._findstat_collections.items(): - if ("Code" in data - and (data["Code"].is_element(entry) - # elements_on_level is rarely equal to entry - # (it may be a function), but it is - # convenient for some types - or data["Code"].elements_on_level == entry)): + if "Code" in data and ( + data["Code"].is_element(entry) + # elements_on_level is rarely equal to entry + # (it may be a function), but it is + # convenient for some types + or data["Code"].elements_on_level == entry + ): return self.element_class(self, id, data, None) # check whether entry is iterable (it's not a string!) diff --git a/src/sage/databases/jones.py b/src/sage/databases/jones.py index 1e6524092d3..577df18ca19 100644 --- a/src/sage/databases/jones.py +++ b/src/sage/databases/jones.py @@ -107,7 +107,7 @@ def _load(self, path, filename): j = len(filename) - 1 while filename[j].isalpha() or filename[j] in [".", "_"]: j -= 1 - S = sorted([eval(z) for z in filename[i:j + 1].split("-")]) + S = sorted([eval(z) for z in filename[i : j + 1].split("-")]) with open(path + "/" + filename) as f: data = f.read() data = data.replace("^", "**") diff --git a/src/sage/databases/knotinfo_db.py b/src/sage/databases/knotinfo_db.py index a57da7f74a9..cf44b7cbc7d 100644 --- a/src/sage/databases/knotinfo_db.py +++ b/src/sage/databases/knotinfo_db.py @@ -23,6 +23,7 @@ - Sebastian Oehms (2020-08): initial version """ + ############################################################################## # Copyright (C) 2020 Sebastian Oehms # @@ -60,9 +61,10 @@ class KnotInfoColumnTypes(Enum): , ] """ - OnlyKnots = 'K' # column that is only used in the KnotInfo table - OnlyLinks = 'L' # column that is only used in the LinkInfo table - KnotsAndLinks = 'B' # column that is only used in both tables + + OnlyKnots = 'K' # column that is only used in the KnotInfo table + OnlyLinks = 'L' # column that is only used in the LinkInfo table + KnotsAndLinks = 'B' # column that is only used in both tables class KnotInfoColumns(Enum): @@ -108,6 +110,7 @@ class KnotInfoColumns(Enum): 'unoriented_name_rank': 'Unoriented Rank', 'weak_splitting_number': 'Weak Splitting Number'} """ + @property def types(self): r""" @@ -171,6 +174,7 @@ def description_webpage(self, new=0, autoraise=True): True """ import webbrowser + if self.column_type() == self.types.OnlyLinks: url = KnotInfoFilename.links.description_url(self) else: @@ -329,9 +333,9 @@ def diagram_url(self, fname, single=False): links = ['https://link-info-repo.onrender.com/', 'linkinfo_data_complete'] -#---------------------------------------------------------------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------------- # Class to provide data for knots and links from the KnotInfo web-page -#---------------------------------------------------------------------------------------------------------------------------- +# ---------------------------------------------------------------------------------------------------------------------------- class KnotInfoDataBase(SageObject, UniqueRepresentation): r""" Database interface to KnotInfo. @@ -376,6 +380,7 @@ def __init__(self, install=False): from sage.features.databases import DatabaseKnotInfo from sage.env import DOT_SAGE + self._feature = DatabaseKnotInfo() self._sobj_path = os.path.join(DOT_SAGE, 'knotinfo') @@ -403,9 +408,11 @@ def create_filecache(self, force=False): test_version = os.path.join(self._sobj_path, self.filename.knots.num_knots(self.version())) if force or not os.path.isfile(test_version): import shutil + shutil.rmtree(self._sobj_path) from sage.misc.temporary_file import atomic_dir + with atomic_dir(self._sobj_path) as d: sobj_path = d.name num_knots_file = os.path.join(sobj_path, self.filename.knots.num_knots(self.version())) @@ -447,6 +454,7 @@ def version(self): """ self._feature.require() from database_knotinfo import version + return version() def demo_version(self): @@ -465,6 +473,7 @@ def demo_version(self): if self._feature.is_present(): num_knots_file = os.path.join(self._sobj_path, self.filename.knots.num_knots(self.version())) from builtins import FileNotFoundError + try: self._num_knots = load(num_knots_file) except FileNotFoundError: @@ -489,6 +498,7 @@ def knot_list(self): return self._knot_list from database_knotinfo import link_list + self._knot_list = link_list() return self._knot_list @@ -506,6 +516,7 @@ def link_list(self): return self._link_list from database_knotinfo import link_list + self._link_list = link_list(proper_links=True) return self._link_list @@ -634,7 +645,7 @@ def _create_data_sobj(self, sobj_path=None): if val_list: save(val_list, '%s/%s' % (sobj_path, self.filename.knots.sobj_data(col))) - save(row_dict, '%s/%s' % (sobj_path, self.filename.knots.sobj_row())) + save(row_dict, '%s/%s' % (sobj_path, self.filename.knots.sobj_row())) @cached_method def columns(self): @@ -724,7 +735,7 @@ def row_names(self): """ row_dict = self.read_row_dict() names = self.read(self.columns().name) - return {k:names[v[0]] for k, v in row_dict.items()} + return {k: names[v[0]] for k, v in row_dict.items()} # ------------------------------------------------------------------------------------------------------------- # read the number of knots contained in the database (without proper links) from the according sobj-file. @@ -797,6 +808,7 @@ def _test_database(self, **options): """ from sage.knots.knotinfo import KnotInfo from sage.misc.misc import some_tuples + tester = options['tester'] max_samples = tester._max_samples if not max_samples: @@ -807,25 +819,25 @@ def _test_database(self, **options): column_demo_sample = { - 'name': ['Name', KnotInfoColumnTypes.KnotsAndLinks], - 'name_unoriented': ['Name - Unoriented', KnotInfoColumnTypes.OnlyLinks], - 'dt_notation': ['DT Notation', KnotInfoColumnTypes.OnlyKnots], - 'gauss_notation': ['Gauss Notation', KnotInfoColumnTypes.KnotsAndLinks], - 'pd_notation': ['PD Notation', KnotInfoColumnTypes.OnlyKnots], - 'pd_notation_vector': ['PD Notation (vector)', KnotInfoColumnTypes.OnlyLinks], - 'crossing_number': ['Crossing Number', KnotInfoColumnTypes.KnotsAndLinks], - 'braid_index': ['Braid Index', KnotInfoColumnTypes.OnlyKnots], - 'braid_length': ['Braid Length', KnotInfoColumnTypes.OnlyKnots], - 'braid_notation': ['Braid Notation', KnotInfoColumnTypes.KnotsAndLinks], - 'braid_notation_old': ['Braid Notation', KnotInfoColumnTypes.OnlyLinks], - 'alternating': ['Alternating', KnotInfoColumnTypes.KnotsAndLinks], - 'alexander_polynomial': ['Alexander', KnotInfoColumnTypes.OnlyKnots], - 'jones_polynomial': ['Jones', KnotInfoColumnTypes.KnotsAndLinks], - 'conway_polynomial': ['Conway', KnotInfoColumnTypes.KnotsAndLinks], - 'homfly_polynomial': ['HOMFLY', KnotInfoColumnTypes.OnlyKnots], - 'homflypt_polynomial': ['HOMFLYPT Polynomial', KnotInfoColumnTypes.OnlyLinks], - 'kauffman_polynomial': ['Kauffman', KnotInfoColumnTypes.KnotsAndLinks], - 'khovanov_polynomial': ['Khovanov', KnotInfoColumnTypes.OnlyLinks], + 'name': ['Name', KnotInfoColumnTypes.KnotsAndLinks], + 'name_unoriented': ['Name - Unoriented', KnotInfoColumnTypes.OnlyLinks], + 'dt_notation': ['DT Notation', KnotInfoColumnTypes.OnlyKnots], + 'gauss_notation': ['Gauss Notation', KnotInfoColumnTypes.KnotsAndLinks], + 'pd_notation': ['PD Notation', KnotInfoColumnTypes.OnlyKnots], + 'pd_notation_vector': ['PD Notation (vector)', KnotInfoColumnTypes.OnlyLinks], + 'crossing_number': ['Crossing Number', KnotInfoColumnTypes.KnotsAndLinks], + 'braid_index': ['Braid Index', KnotInfoColumnTypes.OnlyKnots], + 'braid_length': ['Braid Length', KnotInfoColumnTypes.OnlyKnots], + 'braid_notation': ['Braid Notation', KnotInfoColumnTypes.KnotsAndLinks], + 'braid_notation_old': ['Braid Notation', KnotInfoColumnTypes.OnlyLinks], + 'alternating': ['Alternating', KnotInfoColumnTypes.KnotsAndLinks], + 'alexander_polynomial': ['Alexander', KnotInfoColumnTypes.OnlyKnots], + 'jones_polynomial': ['Jones', KnotInfoColumnTypes.KnotsAndLinks], + 'conway_polynomial': ['Conway', KnotInfoColumnTypes.KnotsAndLinks], + 'homfly_polynomial': ['HOMFLY', KnotInfoColumnTypes.OnlyKnots], + 'homflypt_polynomial': ['HOMFLYPT Polynomial', KnotInfoColumnTypes.OnlyLinks], + 'kauffman_polynomial': ['Kauffman', KnotInfoColumnTypes.KnotsAndLinks], + 'khovanov_polynomial': ['Khovanov', KnotInfoColumnTypes.OnlyLinks], 'khovanov_unreduced_integral_polynomial': ['KH Unred Z Poly', KnotInfoColumnTypes.OnlyKnots], 'khovanov_reduced_integral_polynomial': ['KH Red Z Poly', KnotInfoColumnTypes.OnlyKnots], 'khovanov_reduced_rational_polynomial': ['KH Red Q Poly', KnotInfoColumnTypes.OnlyKnots], @@ -833,89 +845,31 @@ def _test_database(self, **options): 'khovanov_odd_integral_polynomial': ['KH Odd Red Z Poly', KnotInfoColumnTypes.OnlyKnots], 'khovanov_odd_rational_polynomial': ['KH Odd Red Q Poly', KnotInfoColumnTypes.OnlyKnots], 'khovanov_odd_mod2_polynomial': ['KH Red Odd Mod2 Poly', KnotInfoColumnTypes.OnlyKnots], - 'determinant': ['Determinant', KnotInfoColumnTypes.KnotsAndLinks], - 'positive': ['Positive', KnotInfoColumnTypes.OnlyKnots], - 'fibered': ['Fibered', KnotInfoColumnTypes.OnlyKnots], - 'unoriented': ['Unoriented', KnotInfoColumnTypes.OnlyLinks], - 'symmetry_type': ['Symmetry Type', KnotInfoColumnTypes.OnlyKnots], - 'geometric_type': ['Geometric Type', KnotInfoColumnTypes.OnlyKnots], - 'cosmetic_crossing': ['Cosmetic Crossing', KnotInfoColumnTypes.OnlyKnots], - 'width': ['Width', KnotInfoColumnTypes.OnlyKnots], - 'arc_notation': ['Arc Notation', KnotInfoColumnTypes.OnlyLinks], - 'dt_code': ['DT code', KnotInfoColumnTypes.OnlyLinks] + 'determinant': ['Determinant', KnotInfoColumnTypes.KnotsAndLinks], + 'positive': ['Positive', KnotInfoColumnTypes.OnlyKnots], + 'fibered': ['Fibered', KnotInfoColumnTypes.OnlyKnots], + 'unoriented': ['Unoriented', KnotInfoColumnTypes.OnlyLinks], + 'symmetry_type': ['Symmetry Type', KnotInfoColumnTypes.OnlyKnots], + 'geometric_type': ['Geometric Type', KnotInfoColumnTypes.OnlyKnots], + 'cosmetic_crossing': ['Cosmetic Crossing', KnotInfoColumnTypes.OnlyKnots], + 'width': ['Width', KnotInfoColumnTypes.OnlyKnots], + 'arc_notation': ['Arc Notation', KnotInfoColumnTypes.OnlyLinks], + 'dt_code': ['DT code', KnotInfoColumnTypes.OnlyLinks], } -row_demo_sample = { - 'K0_1': [0, 1], - 'K3_1': [1, 1], - 'K4_1': [2, 1], - 'K5_1': [3, 1], - 'K5_2': [4, 1], - 'K6_1': [5, 1], - 'K6_2': [6, 1], - 'K6_3': [7, 1], - 'K7_1': [8, 1], - 'K7_2': [9, 1], - 'L2a1_0': [10, 2], - 'L2a1_1': [11, 2], - 'L4a1_0': [12, 2], - 'L4a1_1': [13, 2], - 'L5a1_0': [14, 2], - 'L5a1_1': [15, 2], - 'L6a1_0': [16, 2], - 'L6a1_1': [17, 2], - 'L6a2_0': [18, 2], - 'L6a2_1': [19, 2] -} +row_demo_sample = {'K0_1': [0, 1], 'K3_1': [1, 1], 'K4_1': [2, 1], 'K5_1': [3, 1], 'K5_2': [4, 1], 'K6_1': [5, 1], 'K6_2': [6, 1], 'K6_3': [7, 1], 'K7_1': [8, 1], 'K7_2': [9, 1], 'L2a1_0': [10, 2], 'L2a1_1': [11, 2], 'L4a1_0': [12, 2], 'L4a1_1': [13, 2], 'L5a1_0': [14, 2], 'L5a1_1': [15, 2], 'L6a1_0': [16, 2], 'L6a1_1': [17, 2], 'L6a2_0': [18, 2], 'L6a2_1': [19, 2]} db = KnotInfoDataBase() dc = db.columns() data_demo_sample = { - dc.name: ['0_1', '3_1', '4_1', '5_1', '5_2', '6_1', '6_2', '6_3', '7_1', '7_2', - 'L2a1{0}', 'L2a1{1}', 'L4a1{0}', 'L4a1{1}', 'L5a1{0}', 'L5a1{1}', - 'L6a1{0}', 'L6a1{1}', 'L6a2{0}', 'L6a2{1}', 'L6a3{0}' - ], + dc.name: ['0_1', '3_1', '4_1', '5_1', '5_2', '6_1', '6_2', '6_3', '7_1', '7_2', 'L2a1{0}', 'L2a1{1}', 'L4a1{0}', 'L4a1{1}', 'L5a1{0}', 'L5a1{1}', 'L6a1{0}', 'L6a1{1}', 'L6a2{0}', 'L6a2{1}', 'L6a3{0}'], dc.name_unoriented: ['L2a1', 'L2a1', 'L4a1', 'L4a1', 'L5a1', 'L5a1', 'L6a1', 'L6a1', 'L6a2', 'L6a2', 'L6a3'], dc.crossing_number: ['0', '3', '4', '5', '5', '6', '6', '6', '7', '7', '2', '2', '4', '4', '5', '5', '6', '6', '6', '6', '6'], - dc.braid_notation: [ - '', - '[1,1,1]', - '[1,-2,1,-2]', - '[1,1,1,1,1]', - '[1,1,1,2,-1,2]', - '[1,1,2,-1,-3,2,-3]', - '[1,1,1,-2,1,-2]', - '[1,1,-2,1,-2,-2]', - '[1,1,1,1,1,1,1]', - '[1,1,1,2,-1,2,3,-2,3]', - '{2, {-1, -1}}', - '{2, {1, 1}}', - '{3, {-2, -2, -1, 2, -1}}', - '{2, {1, 1, 1, 1}}', - '{3, {-1, 2, -1, 2, -1}}', - '{3, {-1, 2, -1, 2, -1}}', - '{4, {1, -2, 3, -2, 1, -2, -3, -2}}', - '{3, {2, 2, 2, 1, 1, -2, 1}}', - '{3, {-1, 2, -1, -2, -2, -1, -1}}', - '{3, {1, -2, 1, 2, 2, 1, 1}}', - '{2, {-1, -1, -1, -1, -1, -1}}' - ], - dc.braid_notation_old: [ - '{2, {-1, -1}}', - '{2, {1, 1}}', - '{4, {1, -2, 3, -2, -1, -2, -3, -2}}', - '{2, {1, 1, 1, 1}}', - '{3, {-1, 2, -1, 2, -1}}', - '{3, {-1, 2, -1, 2, -1}}', - '{4, {1, -2, 3, -2, 1, -2, -3, -2}}', - '{4, {1, 2, 3, 2, 2, -1, 2, 2, -3, 2}}', - '{4, {1, -2, -2, -2, 3, -2, -1, -2, -3, -2}}', - '{4, {1, 2, -3, 2, -1, 2, 3, 2, 2, 2}}', - '{2, {-1, -1, -1, -1, -1, -1}}' - ], + dc.braid_notation: ['', '[1,1,1]', '[1,-2,1,-2]', '[1,1,1,1,1]', '[1,1,1,2,-1,2]', '[1,1,2,-1,-3,2,-3]', '[1,1,1,-2,1,-2]', '[1,1,-2,1,-2,-2]', '[1,1,1,1,1,1,1]', '[1,1,1,2,-1,2,3,-2,3]', '{2, {-1, -1}}', '{2, {1, 1}}', '{3, {-2, -2, -1, 2, -1}}', '{2, {1, 1, 1, 1}}', '{3, {-1, 2, -1, 2, -1}}', '{3, {-1, 2, -1, 2, -1}}', '{4, {1, -2, 3, -2, 1, -2, -3, -2}}', '{3, {2, 2, 2, 1, 1, -2, 1}}', '{3, {-1, 2, -1, -2, -2, -1, -1}}', '{3, {1, -2, 1, 2, 2, 1, 1}}', '{2, {-1, -1, -1, -1, -1, -1}}'], + dc.braid_notation_old: ['{2, {-1, -1}}', '{2, {1, 1}}', '{4, {1, -2, 3, -2, -1, -2, -3, -2}}', '{2, {1, 1, 1, 1}}', '{3, {-1, 2, -1, 2, -1}}', '{3, {-1, 2, -1, 2, -1}}', '{4, {1, -2, 3, -2, 1, -2, -3, -2}}', '{4, {1, 2, 3, 2, 2, -1, 2, 2, -3, 2}}', '{4, {1, -2, -2, -2, 3, -2, -1, -2, -3, -2}}', '{4, {1, 2, -3, 2, -1, 2, 3, 2, 2, 2}}', '{2, {-1, -1, -1, -1, -1, -1}}'], dc.braid_index: ['1', '2', '3', '2', '3', '4', '3', '3', '2', '4'], dc.braid_length: ['', '3', '4', '5', '6', '7', '6', '6', '7', '9'], dc.determinant: ['0', '3', '5', '5', '7', '9', '11', '13', '7', '11', '2', '2', '4', '4', '8', '8', '12', '12', '10', '10', '6'], @@ -933,131 +887,18 @@ def _test_database(self, **options): '[[4,2,5,1],[8,4,9,3],[12,9,1,10],[10,5,11,6],[6,11,7,12],[2,8,3,7]]', '[[1,9,2,8],[3,11,4,10],[5,13,6,12],[7,1,8,14],[9,3,10,2],[11,5,12,4],[13,7,14,6]]', '[[2,10,3,9],[4,14,5,13],[6,12,7,11],[8,2,9,1],[10,8,11,7],[12,6,13,5],[14,4,1,3]]', - ], - dc.pd_notation_vector: [ - '{{4, 1, 3, 2}, {2, 3, 1, 4}}', - '{{4, 2, 3, 1}, {2, 4, 1, 3}}', - '{{6, 1, 7, 2}, {8, 3, 5, 4}, {2, 5, 3, 6}, {4, 7, 1, 8}}', - '{{6, 2, 7, 1}, {8, 4, 5, 3}, {2, 8, 3, 7}, {4, 6, 1, 5}}', - '{{6, 1, 7, 2}, {10, 7, 5, 8}, {4, 5, 1, 6}, {2, 10, 3, 9}, {8, 4, 9, 3}}', - '{{8, 2, 9, 1}, {10, 7, 5, 8}, {4, 10, 1, 9}, {2, 5, 3, 6}, {6, 3, 7, 4}}', - '{{6, 1, 7, 2}, {10, 3, 11, 4}, {12, 8, 5, 7}, {8, 12, 9, 11}, {2, 5, 3, 6}, {4, 9, 1, 10}}', - '{{10, 2, 11, 1}, {6, 4, 7, 3}, {12, 10, 5, 9}, {8, 6, 9, 5}, {2, 12, 3, 11}, {4, 8, 1, 7}}', - '{{8, 1, 9, 2}, {12, 5, 7, 6}, {10, 3, 11, 4}, {4, 11, 5, 12}, {2, 7, 3, 8}, {6, 9, 1, 10}}', - '{{10, 2, 11, 1}, {12, 6, 7, 5}, {8, 4, 9, 3}, {4, 8, 5, 7}, {2, 12, 3, 11}, {6, 10, 1, 9}}', - '{{8, 1, 9, 2}, {2, 9, 3, 10}, {10, 3, 11, 4}, {12, 5, 7, 6}, {6, 7, 1, 8}, {4, 11, 5, 12}}' - ], - dc.dt_notation: [ - '', - '[4, 6, 2]', - '[4, 6, 8, 2]', - '[6, 8, 10, 2, 4]', - '[4, 8, 10, 2, 6]', - '[4, 8, 12, 10, 2, 6]', - '[4, 8, 10, 12, 2, 6]', - '[4, 8, 10, 2, 12, 6]', - '[8, 10, 12, 14, 2, 4, 6]', - '[4, 10, 14, 12, 2, 8, 6]' - ], - dc.dt_code: [ - '[{4}, {2}]', - '[{4}, {2}]', - '[{6, 8}, {2, 4}]', - '[{6, 8}, {4, 2}]', - '[{6, 8}, {4, 10, 2}]', - '[{8, 6}, {2, 10, 4}]', - '[{6, 10}, {2, 12, 4, 8}]', - '[{10, 6}, {8, 4, 12, 2}]', - '[{8, 10, 12}, {2, 6, 4}]', - '[{10, 8, 12}, {4, 6, 2}]', - '[{8, 10, 12}, {6, 2, 4}]' - ], - dc.gauss_notation: [ - '', - '{1, -2, 3, -1, 2, -3}', - '{-1, 2, -3, 1, -4, 3, -2, 4}', - '{-1, 2, -3, 4, -5, 1, -2, 3, -4, 5}', - '{1, -2, 3, -1, 4, -5, 2, -3, 5, -4}', - '{1, -2, 3, -4, 2, -1, 5, -6, 4, -3, 6, -5}', - '{1, -2, 3, -4, 5, -6, 2, -1, 6, -3, 4, -5}', - '{-1, 2, -3, 1, -4, 5, -2, 3, -6, 4, -5, 6}', - '{1, -2, 3, -4, 5, -6, 7, -1, 2, -3, 4, -5, 6, -7}', - '{-1, 2, -3, 4, -5, 6, -7, 1, -2, 7, -6, 5, -4, 3}', - '{{1, -2}, {2, -1}}', - '{{1, -2}, {2, -1}}', - '{{1, -3, 2, -4}, {3, -1, 4, -2}}', - '{{1, -3, 2, -4}, {4, -1, 3, -2}}', - '{{1, -4, 5, -3}, {3, -1, 2, -5, 4, -2}}', - '{{1, -4, 5, -3}, {4, -5, 2, -1, 3, -2}}', - '{{1, -5, 2, -6}, {5, -1, 3, -4, 6, -2, 4, -3}}', - '{{1, -5, 2, -6}, {4, -2, 6, -4, 3, -1, 5, -3}}', - '{{1, -5, 3, -4, 2, -6}, {5, -1, 6, -3, 4, -2}}', - '{{1, -5, 3, -4, 2, -6}, {4, -3, 6, -1, 5, -2}}', - '{{1, -2, 3, -6, 4, -5}, {5, -1, 2, -3, 6, -4}}' - ], - dc.arc_notation: [ - '{{4, 2}, {3, 1}, {4, 2}, {1, 3}}', - '{{2, 4}, {3, 1}, {2, 4}, {3, 1}}', - '{{6, 4}, {3, 5}, {4, 2}, {1, 3}, {2, 6}, {5, 1}}', - '{{3, 6}, {2, 5}, {6, 4}, {1, 3}, {5, 2}, {4, 1}}', - '{{6, 2}, {1, 4}, {3, 5}, {4, 7}, {2, 6}, {7, 3}, {5, 1}}', - '{{3, 5}, {6, 4}, {5, 2}, {7, 3}, {1, 6}, {2, 7}, {4, 1}}', - '{{8, 4}, {3, 5}, {4, 2}, {6, 3}, {5, 7}, {1, 6}, {2, 8}, {7, 1}}', - '{{2, 8}, {1, 7}, {8, 4}, {5, 3}, {4, 2}, {3, 6}, {7, 5}, {6, 1}}', - '{{8, 3}, {2, 7}, {3, 1}, {4, 8}, {5, 2}, {6, 4}, {7, 5}, {1, 6}}', - '{{3, 8}, {2, 7}, {8, 4}, {1, 3}, {5, 2}, {4, 6}, {7, 5}, {6, 1}}', - '{{8, 2}, {1, 3}, {2, 4}, {3, 5}, {4, 6}, {5, 7}, {6, 8}, {7, 1}}' - ], + ], + dc.pd_notation_vector: ['{{4, 1, 3, 2}, {2, 3, 1, 4}}', '{{4, 2, 3, 1}, {2, 4, 1, 3}}', '{{6, 1, 7, 2}, {8, 3, 5, 4}, {2, 5, 3, 6}, {4, 7, 1, 8}}', '{{6, 2, 7, 1}, {8, 4, 5, 3}, {2, 8, 3, 7}, {4, 6, 1, 5}}', '{{6, 1, 7, 2}, {10, 7, 5, 8}, {4, 5, 1, 6}, {2, 10, 3, 9}, {8, 4, 9, 3}}', '{{8, 2, 9, 1}, {10, 7, 5, 8}, {4, 10, 1, 9}, {2, 5, 3, 6}, {6, 3, 7, 4}}', '{{6, 1, 7, 2}, {10, 3, 11, 4}, {12, 8, 5, 7}, {8, 12, 9, 11}, {2, 5, 3, 6}, {4, 9, 1, 10}}', '{{10, 2, 11, 1}, {6, 4, 7, 3}, {12, 10, 5, 9}, {8, 6, 9, 5}, {2, 12, 3, 11}, {4, 8, 1, 7}}', '{{8, 1, 9, 2}, {12, 5, 7, 6}, {10, 3, 11, 4}, {4, 11, 5, 12}, {2, 7, 3, 8}, {6, 9, 1, 10}}', '{{10, 2, 11, 1}, {12, 6, 7, 5}, {8, 4, 9, 3}, {4, 8, 5, 7}, {2, 12, 3, 11}, {6, 10, 1, 9}}', '{{8, 1, 9, 2}, {2, 9, 3, 10}, {10, 3, 11, 4}, {12, 5, 7, 6}, {6, 7, 1, 8}, {4, 11, 5, 12}}'], + dc.dt_notation: ['', '[4, 6, 2]', '[4, 6, 8, 2]', '[6, 8, 10, 2, 4]', '[4, 8, 10, 2, 6]', '[4, 8, 12, 10, 2, 6]', '[4, 8, 10, 12, 2, 6]', '[4, 8, 10, 2, 12, 6]', '[8, 10, 12, 14, 2, 4, 6]', '[4, 10, 14, 12, 2, 8, 6]'], + dc.dt_code: ['[{4}, {2}]', '[{4}, {2}]', '[{6, 8}, {2, 4}]', '[{6, 8}, {4, 2}]', '[{6, 8}, {4, 10, 2}]', '[{8, 6}, {2, 10, 4}]', '[{6, 10}, {2, 12, 4, 8}]', '[{10, 6}, {8, 4, 12, 2}]', '[{8, 10, 12}, {2, 6, 4}]', '[{10, 8, 12}, {4, 6, 2}]', '[{8, 10, 12}, {6, 2, 4}]'], + dc.gauss_notation: ['', '{1, -2, 3, -1, 2, -3}', '{-1, 2, -3, 1, -4, 3, -2, 4}', '{-1, 2, -3, 4, -5, 1, -2, 3, -4, 5}', '{1, -2, 3, -1, 4, -5, 2, -3, 5, -4}', '{1, -2, 3, -4, 2, -1, 5, -6, 4, -3, 6, -5}', '{1, -2, 3, -4, 5, -6, 2, -1, 6, -3, 4, -5}', '{-1, 2, -3, 1, -4, 5, -2, 3, -6, 4, -5, 6}', '{1, -2, 3, -4, 5, -6, 7, -1, 2, -3, 4, -5, 6, -7}', '{-1, 2, -3, 4, -5, 6, -7, 1, -2, 7, -6, 5, -4, 3}', '{{1, -2}, {2, -1}}', '{{1, -2}, {2, -1}}', '{{1, -3, 2, -4}, {3, -1, 4, -2}}', '{{1, -3, 2, -4}, {4, -1, 3, -2}}', '{{1, -4, 5, -3}, {3, -1, 2, -5, 4, -2}}', '{{1, -4, 5, -3}, {4, -5, 2, -1, 3, -2}}', '{{1, -5, 2, -6}, {5, -1, 3, -4, 6, -2, 4, -3}}', '{{1, -5, 2, -6}, {4, -2, 6, -4, 3, -1, 5, -3}}', '{{1, -5, 3, -4, 2, -6}, {5, -1, 6, -3, 4, -2}}', '{{1, -5, 3, -4, 2, -6}, {4, -3, 6, -1, 5, -2}}', '{{1, -2, 3, -6, 4, -5}, {5, -1, 2, -3, 6, -4}}'], + dc.arc_notation: ['{{4, 2}, {3, 1}, {4, 2}, {1, 3}}', '{{2, 4}, {3, 1}, {2, 4}, {3, 1}}', '{{6, 4}, {3, 5}, {4, 2}, {1, 3}, {2, 6}, {5, 1}}', '{{3, 6}, {2, 5}, {6, 4}, {1, 3}, {5, 2}, {4, 1}}', '{{6, 2}, {1, 4}, {3, 5}, {4, 7}, {2, 6}, {7, 3}, {5, 1}}', '{{3, 5}, {6, 4}, {5, 2}, {7, 3}, {1, 6}, {2, 7}, {4, 1}}', '{{8, 4}, {3, 5}, {4, 2}, {6, 3}, {5, 7}, {1, 6}, {2, 8}, {7, 1}}', '{{2, 8}, {1, 7}, {8, 4}, {5, 3}, {4, 2}, {3, 6}, {7, 5}, {6, 1}}', '{{8, 3}, {2, 7}, {3, 1}, {4, 8}, {5, 2}, {6, 4}, {7, 5}, {1, 6}}', '{{3, 8}, {2, 7}, {8, 4}, {1, 3}, {5, 2}, {4, 6}, {7, 5}, {6, 1}}', '{{8, 2}, {1, 3}, {2, 4}, {3, 5}, {4, 6}, {5, 7}, {6, 8}, {7, 1}}'], dc.alternating: ['Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y'], - dc.symmetry_type: [ - '', - 'reversible', - 'fully amphicheiral', - 'reversible', - 'reversible', - 'reversible', - 'reversible', - 'fully amphicheiral', - 'reversible', - 'reversible' - ], - dc.geometric_type: [ - '', - 'torus knot T(2,3)', - 'hyperbolic', - 'torus knot T(2,5)', - 'hyperbolic', - 'hyperbolic', - 'hyperbolic', - 'hyperbolic', - 'torus knot T(2,7)', - 'hyperbolic'], + dc.symmetry_type: ['', 'reversible', 'fully amphicheiral', 'reversible', 'reversible', 'reversible', 'reversible', 'fully amphicheiral', 'reversible', 'reversible'], + dc.geometric_type: ['', 'torus knot T(2,3)', 'hyperbolic', 'torus knot T(2,5)', 'hyperbolic', 'hyperbolic', 'hyperbolic', 'hyperbolic', 'torus knot T(2,7)', 'hyperbolic'], dc.cosmetic_crossing: ['', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'], - dc.homfly_polynomial: [ - '', - '(2*v^2-v^4)+ v^2*z^2', - '(v^(-2)-1+ v^2)-z^2', - '(3*v^4-2*v^6)+ (4*v^4-v^6)*z^2+ v^4*z^4', - '(v^2+ v^4-v^6)+ (v^2+ v^4)*z^2', - '(v^(-2)-v^2+ v^4)+ (-1-v^2)*z^2', - '(2-2*v^2+ v^4)+ (1-3*v^2+ v^4)*z^2-v^2*z^4', - '(-v^(-2)+ 3-v^2)+ (-v^(-2)+ 3-v^2)*z^2+ z^4', - '(4*v^6-3*v^8)+ (10*v^6-4*v^8)*z^2+ (6*v^6-v^8)*z^4+ v^6*z^6', - '(v^2+ v^6-v^8)+ (v^2+ v^4+ v^6)*z^2' - ], - dc.homflypt_polynomial: [ - '1/(v^3*z)-1/(v*z)-z/v', - 'v/z-v^3/z + v*z', - '1/(v^5*z)-1/(v^3*z)-z/v^3-z/v', - 'v^3/z-v^5/z + 3*v^3*z-v^5*z + v^3*z^3', - '1/(v*z)-v/z-z/v^3 + (2*z)/v-v*z + z^3/v', - '1/(v*z)-v/z-z/v^3 + (2*z)/v-v*z + z^3/v', - '1/(v^5*z)-1/(v^3*z)-(2*z)/v^3 + z/v-v*z + z^3/v', - 'v^3/z-v^5/z + 2*v^3*z + v^5*z-v^7*z + v^3*z^3 + v^5*z^3', - '1/(v^7*z)-1/(v^5*z) + z/v^7-(2*z)/v^5-(2*z)/v^3-z^3/v^5-z^3/v^3', - 'v^5/z-v^7/z + 2*v^3*z + 2*v^5*z-v^7*z + v^3*z^3 + v^5*z^3', - '1/(v^7*z)-1/(v^5*z) + (3*z)/v^7-(6*z)/v^5 + z^3/v^7-(5*z^3)/v^5-z^5/v^5' - ], + dc.homfly_polynomial: ['', '(2*v^2-v^4)+ v^2*z^2', '(v^(-2)-1+ v^2)-z^2', '(3*v^4-2*v^6)+ (4*v^4-v^6)*z^2+ v^4*z^4', '(v^2+ v^4-v^6)+ (v^2+ v^4)*z^2', '(v^(-2)-v^2+ v^4)+ (-1-v^2)*z^2', '(2-2*v^2+ v^4)+ (1-3*v^2+ v^4)*z^2-v^2*z^4', '(-v^(-2)+ 3-v^2)+ (-v^(-2)+ 3-v^2)*z^2+ z^4', '(4*v^6-3*v^8)+ (10*v^6-4*v^8)*z^2+ (6*v^6-v^8)*z^4+ v^6*z^6', '(v^2+ v^6-v^8)+ (v^2+ v^4+ v^6)*z^2'], + dc.homflypt_polynomial: ['1/(v^3*z)-1/(v*z)-z/v', 'v/z-v^3/z + v*z', '1/(v^5*z)-1/(v^3*z)-z/v^3-z/v', 'v^3/z-v^5/z + 3*v^3*z-v^5*z + v^3*z^3', '1/(v*z)-v/z-z/v^3 + (2*z)/v-v*z + z^3/v', '1/(v*z)-v/z-z/v^3 + (2*z)/v-v*z + z^3/v', '1/(v^5*z)-1/(v^3*z)-(2*z)/v^3 + z/v-v*z + z^3/v', 'v^3/z-v^5/z + 2*v^3*z + v^5*z-v^7*z + v^3*z^3 + v^5*z^3', '1/(v^7*z)-1/(v^5*z) + z/v^7-(2*z)/v^5-(2*z)/v^3-z^3/v^5-z^3/v^3', 'v^5/z-v^7/z + 2*v^3*z + 2*v^5*z-v^7*z + v^3*z^3 + v^5*z^3', '1/(v^7*z)-1/(v^5*z) + (3*z)/v^7-(6*z)/v^5 + z^3/v^7-(5*z^3)/v^5-z^5/v^5'], dc.kauffman_polynomial: [ '', '(-a^(-4)-2*a^(-2))*z^(0)+ (a^(-5)+ a^(-3))*z^(1)+ (a^(-4)+ a^(-2))*z^(2)', @@ -1079,64 +920,11 @@ def _test_database(self, **options): '-a^(-4) + 1/(a^5*z) + 1/(a^3*z)-z/a^9-z/a^5-(2*z)/a^3-(3*z^2)/a^8-(3*z^2)/a^6 + z^3/a^9 + z^3/a^3 + (2*z^4)/a^8 + (3*z^4)/a^6 + z^4/a^4 + z^5/a^7 + z^5/a^5', 'a^6-a^5/z-a^7/z-2*a^3*z + 3*a^5*z + 3*a^7*z-2*a^9*z-a^4*z^2-2*a^6*z^2-a^8*z^2 + a^3*z^3-2*a^5*z^3-2*a^7*z^3 + a^9*z^3 + a^4*z^4 + 2*a^6*z^4 + a^8*z^4 + a^5*z^5 + a^7*z^5', 'a^(-6)-1/(a^7*z)-1/(a^5*z)-(2*z)/a^9 + (3*z)/a^7 + (3*z)/a^5-(2*z)/a^3-z^2/a^8-(2*z^2)/a^6-z^2/a^4 + z^3/a^9-(2*z^3)/a^7-(2*z^3)/a^5 + z^3/a^3 + z^4/a^8 + (2*z^4)/a^6 + z^4/a^4 + z^5/a^7 + z^5/a^5', - 'a^6-a^5/z-a^7/z + 6*a^5*z + 4*a^7*z-a^9*z + a^11*z-3*a^6*z^2-2*a^8*z^2 + a^10*z^2-5*a^5*z^3-4*a^7*z^3 + a^9*z^3 + a^6*z^4 + a^8*z^4 + a^5*z^5 + a^7*z^5' - ], - dc.jones_polynomial: [ - '1', - 't+ t^3-t^4', - 't^(-2)-t^(-1)+ 1-t+ t^2', - 't^2+ t^4-t^5+ t^6-t^7', - 't-t^2+ 2*t^3-t^4+ t^5-t^6', - 't^(-2)-t^(-1)+ 2-2*t+ t^2-t^3+ t^4', - 't^(-1)-1+ 2*t-2*t^2+ 2*t^3-2*t^4+ t^5', - '-t^(-3)+ 2*t^(-2)-2*t^(-1)+ 3-2*t+ 2*t^2-t^3', - 't^3+ t^5-t^6+ t^7-t^8+ t^9-t^10', - 't-t^2+ 2*t^3-2*t^4+ 2*t^5-t^6+ t^7-t^8', - '-x^(-5)-x^(-1)', - '-x-x^5', - '-x^(-9)-x^(-5) + x^(-3)-x^(-1)', - '-x^3-x^7 + x^9-x^11', - 'x^(-7)-2/x^5 + x^(-3)-2/x + x-x^3', - 'x^(-7)-2/x^5 + x^(-3)-2/x + x-x^3', - '-x^(-9) + x^(-7)-3/x^5 + 2/x^3-2/x + 2*x-x^3', - '-x^3 + x^5-3*x^7 + 2*x^9-2*x^11 + 2*x^13-x^15', - '-x^(-15) + x^(-13)-2/x^11 + 2/x^9-2/x^7 + x^(-5)-x^(-3)', - '-x^3 + x^5-2*x^7 + 2*x^9-2*x^11 + x^13-x^15', - '-x^(-17) + x^(-15)-x^(-13) + x^(-11)-x^(-9)-x^(-5)' - ], - dc.alexander_polynomial: [ - '1', - '1-t+ t^2', - '1-3*t+ t^2', - '1-t+ t^2-t^3+ t^4', - '2-3*t+ 2*t^2', - '2-5*t+ 2*t^2', - '1-3*t+ 3*t^2-3*t^3+ t^4', - '1-3*t+ 5*t^2-3*t^3+ t^4', - '1-t+ t^2-t^3+ t^4-t^5+ t^6', - '3-5*t+ 3*t^2'], - dc.conway_polynomial: [ - '1', - '1+z^2', - '1-z^2', - '1+3*z^2+z^4', - '1+2*z^2', - '1-2*z^2', - '1-z^2-z^4', - '1+z^2+z^4', - '1+6*z^2+5*z^4+z^6', - '1+3*z^2', - '-z', - 'z', - '-2*z', - '2*z + z^3', - 'z^3', - 'z^3', - '-2*z + z^3', - '2*z + 2*z^3', - '-3*z-2*z^3', - '3*z + 2*z^3', - '-3*z-4*z^3-z^5'], + 'a^6-a^5/z-a^7/z + 6*a^5*z + 4*a^7*z-a^9*z + a^11*z-3*a^6*z^2-2*a^8*z^2 + a^10*z^2-5*a^5*z^3-4*a^7*z^3 + a^9*z^3 + a^6*z^4 + a^8*z^4 + a^5*z^5 + a^7*z^5', + ], + dc.jones_polynomial: ['1', 't+ t^3-t^4', 't^(-2)-t^(-1)+ 1-t+ t^2', 't^2+ t^4-t^5+ t^6-t^7', 't-t^2+ 2*t^3-t^4+ t^5-t^6', 't^(-2)-t^(-1)+ 2-2*t+ t^2-t^3+ t^4', 't^(-1)-1+ 2*t-2*t^2+ 2*t^3-2*t^4+ t^5', '-t^(-3)+ 2*t^(-2)-2*t^(-1)+ 3-2*t+ 2*t^2-t^3', 't^3+ t^5-t^6+ t^7-t^8+ t^9-t^10', 't-t^2+ 2*t^3-2*t^4+ 2*t^5-t^6+ t^7-t^8', '-x^(-5)-x^(-1)', '-x-x^5', '-x^(-9)-x^(-5) + x^(-3)-x^(-1)', '-x^3-x^7 + x^9-x^11', 'x^(-7)-2/x^5 + x^(-3)-2/x + x-x^3', 'x^(-7)-2/x^5 + x^(-3)-2/x + x-x^3', '-x^(-9) + x^(-7)-3/x^5 + 2/x^3-2/x + 2*x-x^3', '-x^3 + x^5-3*x^7 + 2*x^9-2*x^11 + 2*x^13-x^15', '-x^(-15) + x^(-13)-2/x^11 + 2/x^9-2/x^7 + x^(-5)-x^(-3)', '-x^3 + x^5-2*x^7 + 2*x^9-2*x^11 + x^13-x^15', '-x^(-17) + x^(-15)-x^(-13) + x^(-11)-x^(-9)-x^(-5)'], + dc.alexander_polynomial: ['1', '1-t+ t^2', '1-3*t+ t^2', '1-t+ t^2-t^3+ t^4', '2-3*t+ 2*t^2', '2-5*t+ 2*t^2', '1-3*t+ 3*t^2-3*t^3+ t^4', '1-3*t+ 5*t^2-3*t^3+ t^4', '1-t+ t^2-t^3+ t^4-t^5+ t^6', '3-5*t+ 3*t^2'], + dc.conway_polynomial: ['1', '1+z^2', '1-z^2', '1+3*z^2+z^4', '1+2*z^2', '1-2*z^2', '1-z^2-z^4', '1+z^2+z^4', '1+6*z^2+5*z^4+z^6', '1+3*z^2', '-z', 'z', '-2*z', '2*z + z^3', 'z^3', 'z^3', '-2*z + z^3', '2*z + 2*z^3', '-3*z-2*z^3', '3*z + 2*z^3', '-3*z-4*z^3-z^5'], dc.khovanov_polynomial: [ '1 + q^(-2) + 1/(q^6*t^2) + 1/(q^4*t^2)', '1 + q^2 + q^4*t^2 + q^6*t^2', @@ -1148,7 +936,8 @@ def _test_database(self, **options): 'q^2 + q^4 + q^4*t + 2*q^6*t^2 + q^8*t^2 + 2*q^10*t^3 + 2*q^10*t^4 + q^12*t^4 + q^12*t^5 + q^14*t^5 + q^16*t^6', 'q^(-4) + q^(-2) + 1/(q^16*t^6) + 1/(q^14*t^6) + 1/(q^14*t^5) + 1/(q^12*t^4) + 1/(q^10*t^4) + 1/(q^10*t^3) + 1/(q^8*t^3) + 1/(q^8*t^2) + 1/(q^6*t^2) + 1/(q^4*t)', 'q^2 + q^4 + q^4*t + q^6*t^2 + q^8*t^2 + q^8*t^3 + q^10*t^3 + q^10*t^4 + q^12*t^4 + q^14*t^5 + q^14*t^6 + q^16*t^6', - 'q^(-6) + q^(-4) + 1/(q^18*t^6) + 1/(q^16*t^6) + 1/(q^16*t^5) + 1/(q^12*t^4) + 1/(q^12*t^3) + 1/(q^8*t^2)'], + 'q^(-6) + q^(-4) + 1/(q^18*t^6) + 1/(q^16*t^6) + 1/(q^16*t^5) + 1/(q^12*t^4) + 1/(q^12*t^3) + 1/(q^8*t^2)', + ], dc.khovanov_unreduced_integral_polynomial: [ '', 'q + q^(3) + t^(2) q^(5) + t^(3) q^(9) + t^(3) q^(7) T^(2)', @@ -1159,71 +948,12 @@ def _test_database(self, **options): 't^(-2) q^(-3) + t^(-1) q + 2 q + q^(3) + t q^(3) + t q^(5) + t^(2) q^(5) + t^(2) q^(7) + t^(3) q^(7) + t^(3) q^(9) + t^(4) q^(11) + t^(-1) q^(-1) T^(2) + t q^(3) T^(2) + t^(2) q^(5) T^(2) + t^(3) q^(7) T^(2) + t^(4) q^(9) T^(2)', 't^(-3) q^(-7) + t^(-2) q^(-5) + t^(-2) q^(-3) + t^(-1) q^(-3) + t^(-1) q^(-1) + 2 q^(-1) + 2 q + t q + t q^(3) + t^(2) q^(3) + t^(2) q^(5) + t^(3) q^(7) + t^(-2) q^(-5) T^(2) + t^(-1) q^(-3) T^(2) + q^(-1) T^(2) + t q T^(2) + t^(2) q^(3) T^(2) + t^(3) q^(5) T^(2)', 'q^(5) + q^(7) + t^(2) q^(9) + t^(3) q^(13) + t^(4) q^(13) + t^(5) q^(17) + t^(6) q^(17) + t^(7) q^(21) + t^(3) q^(11) T^(2) + t^(5) q^(15) T^(2) + t^(7) q^(19) T^(2)', - 'q + q^(3) + t q^(3) + t^(2) q^(5) + t^(2) q^(7) + t^(3) q^(7) + t^(3) q^(9) + t^(4) q^(9) + t^(4) q^(11) + t^(5) q^(13) + t^(6) q^(13) + t^(7) q^(17) + t^(2) q^(5) T^(2) + t^(3) q^(7) T^(2) + t^(4) q^(9) T^(2) + t^(5) q^(11) T^(2) + t^(7) q^(15) T^(2)'], - dc.khovanov_reduced_integral_polynomial: [ - '', - 'q^(2) + t^(2) q^(6) + t^(3) q^(8)', - 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', - 'q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', - 'q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', - 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', - 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', - 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', - 'q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', - 'q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], - dc.khovanov_reduced_rational_polynomial: [ - '', - ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', - 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', - ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', - ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', - 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', - 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', - 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', - ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', - ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], - dc.khovanov_reduced_mod2_polynomial: [ - '', - ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', - 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', - ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', - ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', - 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', - 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', - 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', - ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', - ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], - dc.khovanov_odd_integral_polynomial: [ - '', - 'q^(2) + t^(2) q^(6) + t^(3) q^(8)', - 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', - 'q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', - 'q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', - 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', - 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', - 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', - 'q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', - 'q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], - dc.khovanov_odd_rational_polynomial: [ - '', - ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', - 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', - ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', - ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', - 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', - 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', - 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', - ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', - ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], - dc.khovanov_odd_mod2_polynomial: [ - '', - ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', - 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', - ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', - ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', - 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', - 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', - 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', - ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', - ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'] + 'q + q^(3) + t q^(3) + t^(2) q^(5) + t^(2) q^(7) + t^(3) q^(7) + t^(3) q^(9) + t^(4) q^(9) + t^(4) q^(11) + t^(5) q^(13) + t^(6) q^(13) + t^(7) q^(17) + t^(2) q^(5) T^(2) + t^(3) q^(7) T^(2) + t^(4) q^(9) T^(2) + t^(5) q^(11) T^(2) + t^(7) q^(15) T^(2)', + ], + dc.khovanov_reduced_integral_polynomial: ['', 'q^(2) + t^(2) q^(6) + t^(3) q^(8)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', 'q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', 'q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', 'q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', 'q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], + dc.khovanov_reduced_rational_polynomial: ['', ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], + dc.khovanov_reduced_mod2_polynomial: ['', ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], + dc.khovanov_odd_integral_polynomial: ['', 'q^(2) + t^(2) q^(6) + t^(3) q^(8)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', 'q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', 'q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', 'q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', 'q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], + dc.khovanov_odd_rational_polynomial: ['', ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], + dc.khovanov_odd_mod2_polynomial: ['', ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], } diff --git a/src/sage/databases/odlyzko.py b/src/sage/databases/odlyzko.py index c96ddf8fab2..044b17ba5a2 100644 --- a/src/sage/databases/odlyzko.py +++ b/src/sage/databases/odlyzko.py @@ -54,6 +54,7 @@ def zeta_zeros(): 2001052 """ from sage.misc.verbose import verbose + for path in sage_data_paths('odlyzko'): sobj = os.path.join(path, 'zeros.sobj') if os.path.exists(sobj): diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index f1eee05038e..f65194c2ba0 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -134,6 +134,7 @@ import re from collections import defaultdict from urllib.parse import urlencode + # **************************************************************************** # Copyright (C) 2012 Thierry Monteil # @@ -215,6 +216,7 @@ def handle_starttag(self, tag, attrs): for attr in attrs: if attr[0] == 'href': urls.append(attr[1]) + MyHTMLParser().feed(html_string) return urls @@ -364,6 +366,7 @@ class OEIS: sage: oeis('A000045') # optional -- internet A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. """ + def __call__(self, query, max_results=None, first_result=0): r""" See the documentation of :class:`OEIS`. @@ -415,14 +418,11 @@ class options(GlobalOptions): sage: oeis.options.max_results 3 """ + NAME = 'OEIS' module = 'sage.databases.oeis' - max_results = dict(default=3, - description='the maximum number of results to return', - checker=lambda x: x in ZZ and x > 0) - fetch_b_file = dict(default=False, - description='whether to fetch terms from the b-file by default', - checker=lambda x: isinstance(x, bool)) + max_results = dict(default=3, description='the maximum number of results to return', checker=lambda x: x in ZZ and x > 0) + fetch_b_file = dict(default=False, description='whether to fetch terms from the b-file by default', checker=lambda x: isinstance(x, bool)) def __repr__(self) -> str: r""" @@ -537,10 +537,7 @@ def find_by_description(self, description, max_results=None, first_result=0): """ if max_results is None: max_results = self.options['max_results'] - options = {'q': description, - 'n': str(max_results), - 'fmt': 'text', - 'start': str(first_result)} + options = {'q': description, 'n': str(max_results), 'fmt': 'text', 'start': str(first_result)} url = oeis_url + "search?" + urlencode(options) sequence_list = _fetch(url).split('\n\n')[2:-1] T = [self.find_by_entry(entry=s) for s in sequence_list] @@ -589,6 +586,7 @@ def browse(self): sage: oeis.browse() # optional -- webbrowser """ import webbrowser + webbrowser.open(oeis_url) def _imaginary_entry(self, ident='A999999', keywords=''): @@ -614,38 +612,40 @@ def _imaginary_entry(self, ident='A999999', keywords=''): sage: ','.join(s.keywords()) == keywords True """ - return ('%I ' + ident + ' M9999 N9999\n' - '%S ' + ident + ' 1,1,1,1,2,1,1,1,\n' - '%T ' + ident + ' 1,1,1,1,1,1,1,1,1,\n' - '%U ' + ident + ' 1,1,1,1,1,1,1,1,1\n' - '%N ' + ident + ' The characteristic sequence of 42 plus one, starting from 38.\n' - '%D ' + ident + ' Lewis Carroll, Alice\'s Adventures in Wonderland.\n' - '%D ' + ident + ' Lewis Carroll, The Hunting of the Snark.\n' - '%D ' + ident + ' Deep Thought, The Answer to the Ultimate Question of Life, The Universe, and Everything.\n' - '%H ' + ident + ' Wikipedia, 42 (number)\n' - '%H ' + ident + ' See. also github issue #42\n' - '%H ' + ident + ' Do not confuse with the sequence A000042 or the sequence A000024\n' - '%H ' + ident + ' The string http://42.com is not a link.\n' - '%F ' + ident + ' For n big enough, s(n+1) - s(n) = 0.\n' - '%Y ' + ident + ' Related sequences are A000042 and its friend A000024.\n' - '%A ' + ident + ' Anonymous.\n' - '%O ' + ident + ' 38,4\n' - '%E ' + ident + ' This sequence does not contain errors.\n' - '%e ' + ident + ' s(42) + s(43) = 0.\n' - '%p ' + ident + ' Do not even try, Maple is not able to produce such a sequence.\n' - '%t ' + ident + ' Mathematica neither.\n' - '%o ' + ident + ' (Python)\n' - '%o ' + ident + ' def ' + ident + '(n):\n' - '%o ' + ident + ' assert(isinstance(n, (int, Integer))), "n must be an integer."\n' - '%o ' + ident + ' if n < 38:\n' - '%o ' + ident + ' raise ValueError("the value %s is not accepted" % str(n))\n' - '%o ' + ident + ' elif n == 42:\n' - '%o ' + ident + ' return 2\n' - '%o ' + ident + ' else:\n' - '%o ' + ident + ' return 1\n' - '%K ' + ident + ' ' + keywords + '\n' - '%C ' + ident + ' 42 is the product of the first 4 prime numbers, except 5 and perhaps 1.\n' - '%C ' + ident + ' Apart from that, i have no comment.') + return ( + '%I ' + ident + ' M9999 N9999\n' + '%S ' + ident + ' 1,1,1,1,2,1,1,1,\n' + '%T ' + ident + ' 1,1,1,1,1,1,1,1,1,\n' + '%U ' + ident + ' 1,1,1,1,1,1,1,1,1\n' + '%N ' + ident + ' The characteristic sequence of 42 plus one, starting from 38.\n' + '%D ' + ident + ' Lewis Carroll, Alice\'s Adventures in Wonderland.\n' + '%D ' + ident + ' Lewis Carroll, The Hunting of the Snark.\n' + '%D ' + ident + ' Deep Thought, The Answer to the Ultimate Question of Life, The Universe, and Everything.\n' + '%H ' + ident + ' Wikipedia, 42 (number)\n' + '%H ' + ident + ' See. also github issue #42\n' + '%H ' + ident + ' Do not confuse with the sequence A000042 or the sequence A000024\n' + '%H ' + ident + ' The string http://42.com is not a link.\n' + '%F ' + ident + ' For n big enough, s(n+1) - s(n) = 0.\n' + '%Y ' + ident + ' Related sequences are A000042 and its friend A000024.\n' + '%A ' + ident + ' Anonymous.\n' + '%O ' + ident + ' 38,4\n' + '%E ' + ident + ' This sequence does not contain errors.\n' + '%e ' + ident + ' s(42) + s(43) = 0.\n' + '%p ' + ident + ' Do not even try, Maple is not able to produce such a sequence.\n' + '%t ' + ident + ' Mathematica neither.\n' + '%o ' + ident + ' (Python)\n' + '%o ' + ident + ' def ' + ident + '(n):\n' + '%o ' + ident + ' assert(isinstance(n, (int, Integer))), "n must be an integer."\n' + '%o ' + ident + ' if n < 38:\n' + '%o ' + ident + ' raise ValueError("the value %s is not accepted" % str(n))\n' + '%o ' + ident + ' elif n == 42:\n' + '%o ' + ident + ' return 2\n' + '%o ' + ident + ' else:\n' + '%o ' + ident + ' return 1\n' + '%K ' + ident + ' ' + keywords + '\n' + '%C ' + ident + ' 42 is the product of the first 4 prime numbers, except 5 and perhaps 1.\n' + '%C ' + ident + ' Apart from that, i have no comment.' + ) def _imaginary_sequence(self, ident='A999999', keywords='sign,easy'): r""" @@ -705,6 +705,7 @@ class OEISSequence(SageObject, UniqueRepresentation): .. automethod:: __call__ """ + @staticmethod def __classcall__(cls, ident): r""" @@ -717,7 +718,7 @@ def __classcall__(cls, ident): """ if not isinstance(ident, str): ident = str(ident) - ident = 'A000000'[:-len(ident)] + ident + ident = 'A000000'[: -len(ident)] + ident return super().__classcall__(cls, ident) def __init__(self, ident): @@ -1118,18 +1119,22 @@ def natural_object(self): """ if 'cofr' in self.keywords() and 'frac' not in self.keywords(): from sage.rings.continued_fraction import continued_fraction + return continued_fraction(self.first_terms()) if 'cons' in self.keywords(): offset = self.offsets()[0] terms = self.first_terms() + tuple([0] * abs(offset)) from sage.rings.real_lazy import RealLazyField + return RealLazyField()('0' + ''.join(map(str, terms[:offset])) + '.' + ''.join(map(str, terms[offset:]))) if 'nonn' in self.keywords(): from sage.rings.semirings.non_negative_integer_semiring import NN from sage.structure.sequence import Sequence + return Sequence(self.first_terms(), NN) from sage.rings.integer_ring import ZZ from sage.structure.sequence import Sequence + return Sequence(self.first_terms(), ZZ) def is_dead(self, warn_only=False) -> bool: @@ -1303,6 +1308,7 @@ def first_terms(self, number=None): 2048 sage: oeis.options._reset() """ + def fetch_b_file(): url = oeis_url + f"b{self.id(format='int')}.txt" terms = _fetch(url) @@ -1318,8 +1324,7 @@ def fetch_b_file(): first_terms += (v,) self._first_terms = True, first_terms - if ((number is infinity or oeis.options['fetch_b_file']) - and self is not oeis._imaginary_sequence()): # all other sequences have a b-file + if (number is infinity or oeis.options['fetch_b_file']) and self is not oeis._imaginary_sequence(): # all other sequences have a b-file # self._first_terms is a pair (all?, first_terms) if not hasattr(self, "_first_terms") or not self._first_terms[0]: fetch_b_file() @@ -1411,7 +1416,7 @@ def __call__(self, k): """ offset = self.offsets()[0] if 'cons' in self.keywords(): - offset = - offset + offset = -offset n = k - offset if not 0 <= n < len(self.first_terms()): raise ValueError("sequence %s is not defined (or known) for index %s" % (self.id(), k)) @@ -1602,6 +1607,7 @@ def links(self, browse=None, format='guess'): sage: type(HTML) """ + def url_absolute(s): return re.sub(r'\"\/', '\"' + oeis_url, s) @@ -1617,6 +1623,7 @@ def url_absolute(s): return FancyTuple(url_list) else: import webbrowser + url_list = flatten([_urls(url_absolute(string)) for string in self._field('H')]) if isinstance(browse, (int, Integer)): webbrowser.open(url_list[browse]) @@ -1821,6 +1828,7 @@ def browse(self): sage: s.browse() # optional -- webbrowser """ import webbrowser + webbrowser.open(self.url()) def show(self): @@ -1871,10 +1879,7 @@ def show(self): 1: Apart from that, i have no comment. ... """ - for s in ['id', 'name', 'first_terms', 'comments', 'references', - 'links', 'formulas', 'examples', 'cross_references', - 'programs', 'keywords', 'offsets', 'url', 'old_IDs', - 'author', 'extensions_or_errors']: + for s in ['id', 'name', 'first_terms', 'comments', 'references', 'links', 'formulas', 'examples', 'cross_references', 'programs', 'keywords', 'offsets', 'url', 'old_IDs', 'author', 'extensions_or_errors']: result = getattr(self, s)() if result != '' and result != ('',) and result != (): print(re.sub('_', ' ', s).upper()) @@ -1949,8 +1954,7 @@ def programs(self, language='all', preparsing=True, keep_comments=False): if language == 'sagemath': language = 'sage' if language == 'all': - table = (('maple', FancyTuple(self._field('p'))), - ('mathematica', FancyTuple(self._field('t')))) + table = (('maple', FancyTuple(self._field('p'))), ('mathematica', FancyTuple(self._field('t')))) table = [(lang, code) for lang, code in table if code] else: table = [] @@ -2016,7 +2020,7 @@ def flush_to_table(language, code_lines): flush_to_table(old_language, code_lines) # start new stock of code lines old_language, end = new_language - rest = line[end + 1:].strip() + rest = line[end + 1 :].strip() code_lines = [rest] if rest else [] else: code_lines.append(line) @@ -2079,6 +2083,7 @@ class FancyTuple(tuple): sage: t[2] 'two' """ + def __repr__(self): r""" Print the tuple with one value per line, where each line diff --git a/src/sage/databases/sloane.py b/src/sage/databases/sloane.py index 0ff0818cded..da0e54f8456 100644 --- a/src/sage/databases/sloane.py +++ b/src/sage/databases/sloane.py @@ -98,6 +98,7 @@ class SloaneEncyclopediaClass: that contains only the sequence numbers and the sequences themselves. """ + def __init__(self): """ Initialize the database but do not load any of the data. @@ -194,8 +195,7 @@ def find(self, seq, maxresults=30): return answer - def install(self, oeis_url='https://oeis.org/stripped.gz', - names_url='https://oeis.org/names.gz', overwrite=False): + def install(self, oeis_url='https://oeis.org/stripped.gz', names_url='https://oeis.org/names.gz', overwrite=False): """ Download and install the online encyclopedia, raising an IOError if either step fails. @@ -281,8 +281,7 @@ def load(self): try: file_seq = bz2.BZ2File(self.__file__, 'r') except OSError: - raise OSError("The Sloane Encyclopedia database must be installed." - " Use e.g. 'SloaneEncyclopedia.install()' to download and install it.") + raise OSError("The Sloane Encyclopedia database must be installed." " Use e.g. 'SloaneEncyclopedia.install()' to download and install it.") self.__data__ = {} @@ -315,8 +314,7 @@ def load(self): self.__loaded_names__ = True except KeyError: # Some sequence in the names file is not in the database - raise KeyError("Sloane OEIS sequence and name files do not match." - " Try reinstalling, e.g. SloaneEncyclopedia.install(overwrite=True).") + raise KeyError("Sloane OEIS sequence and name files do not match." " Try reinstalling, e.g. SloaneEncyclopedia.install(overwrite=True).") except OSError: # The names database is not installed self.__loaded_names__ = False @@ -344,8 +342,7 @@ def sequence_name(self, N): """ self.load() if not self.__loaded_names__: - raise OSError("The Sloane OEIS names file is not installed." - " Try reinstalling, e.g. SloaneEncyclopedia.install(overwrite=True).") + raise OSError("The Sloane OEIS names file is not installed." " Try reinstalling, e.g. SloaneEncyclopedia.install(overwrite=True).") if N not in self.__data__: # sequence N does not exist return '' diff --git a/src/sage/databases/sql_db.py b/src/sage/databases/sql_db.py index f3548810be9..d0c7cd7ddbc 100644 --- a/src/sage/databases/sql_db.py +++ b/src/sage/databases/sql_db.py @@ -55,6 +55,7 @@ - Emily A. Kirkman and Robert L. Miller (2007-06-17): initial version """ + # FUTURE TODOs (Ignore for now): # - order by clause in query strings # - delete from query containing joins @@ -81,22 +82,129 @@ from sage.misc.temporary_file import tmp_filename from sage.structure.sage_object import SageObject -sqlite_keywords = ['ABORT','ACTION','ADD','AFTER','ALL','ALTER','ANALYZE', - 'AND','AS','ASC','ATTACH','AUTOINCREMENT','BEFORE','BEGIN','BETWEEN','BY', - 'CASCADE','CASE','CAST','CHECK','COLLATE','COLUMN','COMMIT','CONFLICT', - 'CONSTRAINT','CREATE','CROSS','CURRENT_DATE','CURRENT_TIME', - 'CURRENT_TIMESTAMP','DATABASE','DEFAULT','DEFERRABLE','DEFERRED','DELETE', - 'DESC','DETACH','DISTINCT','DROP','EACH','ELSE','END','ESCAPE','EXCEPT', - 'EXCLUSIVE','EXISTS','EXPLAIN','FAIL','FOR','FOREIGN','FROM','FULL', - 'GLOB','GROUP','HAVING','IF','IGNORE','IMMEDIATE','IN','INDEX','INDEXED', - 'INITIALLY','INNER','INSERT','INSTEAD','INTERSECT','INTO','IS','ISNULL', - 'JOIN','KEY','LEFT','LIKE','LIMIT','MATCH','NATURAL','NO','NOT','NOTNULL', - 'NULL','OF','OFFSET','ON','OR','ORDER','OUTER','PLAN','PRAGMA','PRIMARY', - 'QUERY','RAISE','REFERENCES','REGEXP','REINDEX','RELEASE','RENAME', - 'REPLACE','RESTRICT','RIGHT','ROLLBACK','ROW','SAVEPOINT','SELECT','SET', - 'TABLE','TEMP','TEMPORARY','THEN','TO','TRANSACTION','TRIGGER','UNION', - 'UNIQUE','UPDATE','USING','VACUUM','VALUES','VIEW','VIRTUAL','WHEN', - 'WHERE'] +sqlite_keywords = [ + 'ABORT', + 'ACTION', + 'ADD', + 'AFTER', + 'ALL', + 'ALTER', + 'ANALYZE', + 'AND', + 'AS', + 'ASC', + 'ATTACH', + 'AUTOINCREMENT', + 'BEFORE', + 'BEGIN', + 'BETWEEN', + 'BY', + 'CASCADE', + 'CASE', + 'CAST', + 'CHECK', + 'COLLATE', + 'COLUMN', + 'COMMIT', + 'CONFLICT', + 'CONSTRAINT', + 'CREATE', + 'CROSS', + 'CURRENT_DATE', + 'CURRENT_TIME', + 'CURRENT_TIMESTAMP', + 'DATABASE', + 'DEFAULT', + 'DEFERRABLE', + 'DEFERRED', + 'DELETE', + 'DESC', + 'DETACH', + 'DISTINCT', + 'DROP', + 'EACH', + 'ELSE', + 'END', + 'ESCAPE', + 'EXCEPT', + 'EXCLUSIVE', + 'EXISTS', + 'EXPLAIN', + 'FAIL', + 'FOR', + 'FOREIGN', + 'FROM', + 'FULL', + 'GLOB', + 'GROUP', + 'HAVING', + 'IF', + 'IGNORE', + 'IMMEDIATE', + 'IN', + 'INDEX', + 'INDEXED', + 'INITIALLY', + 'INNER', + 'INSERT', + 'INSTEAD', + 'INTERSECT', + 'INTO', + 'IS', + 'ISNULL', + 'JOIN', + 'KEY', + 'LEFT', + 'LIKE', + 'LIMIT', + 'MATCH', + 'NATURAL', + 'NO', + 'NOT', + 'NOTNULL', + 'NULL', + 'OF', + 'OFFSET', + 'ON', + 'OR', + 'ORDER', + 'OUTER', + 'PLAN', + 'PRAGMA', + 'PRIMARY', + 'QUERY', + 'RAISE', + 'REFERENCES', + 'REGEXP', + 'REINDEX', + 'RELEASE', + 'RENAME', + 'REPLACE', + 'RESTRICT', + 'RIGHT', + 'ROLLBACK', + 'ROW', + 'SAVEPOINT', + 'SELECT', + 'SET', + 'TABLE', + 'TEMP', + 'TEMPORARY', + 'THEN', + 'TO', + 'TRANSACTION', + 'TRIGGER', + 'UNION', + 'UNIQUE', + 'UPDATE', + 'USING', + 'VACUUM', + 'VALUES', + 'VIEW', + 'VIRTUAL', + 'WHEN', + 'WHERE', +] def regexp(expr, item): @@ -143,7 +251,7 @@ def verify_type(type): ... TypeError: float is not a legal type. """ - types = ['INTEGER','INT','BOOLEAN','REAL','TEXT','BOOL','BLOB','NOTYPE'] + types = ['INTEGER', 'INT', 'BOOLEAN', 'REAL', 'TEXT', 'BOOL', 'BLOB', 'NOTYPE'] if type.upper() not in types: raise TypeError('%s is not a legal type.' % type) return True @@ -211,8 +319,8 @@ def verify_operator(operator): ... TypeError: not_an_operator is not a legal operator. """ - binaries = ['=','<=','>=','like','<','>','<>','regexp'] - unaries = ['is null','is not null'] + binaries = ['=', '<=', '>=', 'like', '<', '>', '<>', 'regexp'] + unaries = ['is null', 'is not null'] if operator not in binaries and operator not in unaries: raise TypeError('%s is not a legal operator.' % operator) return True @@ -257,15 +365,14 @@ def construct_skeleton(database): typ = 'NOTYPE' else: typ = col[2] - skeleton[table[0]][col[1]] = {'sql':typ, - 'primary_key':(col[5] != 0), 'index':(col[5] != 0), 'unique': False} + skeleton[table[0]][col[1]] = {'sql': typ, 'primary_key': (col[5] != 0), 'index': (col[5] != 0), 'unique': False} exe2 = cur.execute("PRAGMA index_list(%s)" % table[0]) for col in exe2.fetchall(): if col[1].find('sqlite') == -1: if os.path.basename(database.__dblocation__) == 'graphs.db': name = col[1] else: - name = col[1][len(table[0])+3:] + name = col[1][len(table[0]) + 3 :] skeleton[table[0]][name]['index'] = True skeleton[table[0]][name]['unique'] = bool(col[2]) else: @@ -336,8 +443,7 @@ def _create_print_table(cur, col_titles, **kwds): pcol_index.append(col_titles.index(col)) max_field_size = kwds.get('max_field_size', 20) - id_col_index = col_titles.index(kwds['id_col']) if 'id_col' in kwds \ - else None + id_col_index = col_titles.index(kwds['id_col']) if 'id_col' in kwds else None if 'relabel_cols' in kwds: relabel_cols = kwds['relabel_cols'] @@ -357,14 +463,11 @@ def row_str(row, html): if index in pcol_index: if html: plot = pcol_map[p % len(pcol_map)](row[index]) - plot.save('%d.png' % p, figsize=[1,1]) - field_val = ' ' \ - + '%s
' % (row[index],p) \ - + '\n' + plot.save('%d.png' % p, figsize=[1, 1]) + field_val = ' ' + '%s
' % (row[index], p) + '\n' p += 1 else: - raise NotImplementedError('Cannot display plot on ' - 'command line.') + raise NotImplementedError('Cannot display plot on ' 'command line.') else: if index in fcol_index: if id_col_index is None: @@ -375,8 +478,7 @@ def row_str(row, html): else: field_val = row[index] if html: - field_val = ' ' \ - + str(field_val) + ' \n' + field_val = ' ' + str(field_val) + ' \n' else: field_val = str(field_val).ljust(max_field_size) cur_str.append(field_val) @@ -387,11 +489,9 @@ def row_str(row, html): ret = '\n' ret += ' \n' ret += ' \n \n \n \n \n' - ret += '\n'.join([' \n ' + row_str(row, True) + ' ' - for row in cur]) + ret += '\n'.join([' \n ' + row_str(row, True) + ' ' for row in cur]) ret += '\n
' - ret += (' ').join(col_titles) + ret += (' ').join(col_titles) ret += '
\n' else: # Command Prompt Version @@ -461,7 +561,7 @@ def __init__(self, database, *args, **kwds): self.__query_dict__ = {} return for x in args: - if isinstance(x,dict): + if isinstance(x, dict): if 'query_dict' not in kwds: kwds['query_dict'] = x elif isinstance(x, str): @@ -470,11 +570,8 @@ def __init__(self, database, *args, **kwds): elif isinstance(x, tuple): if 'param_tuple' not in kwds: kwds['param_tuple'] = x - if total_args > 2 or not ('query_dict' in kwds or - 'query_string' in kwds) or ('query_dict' in kwds and - ('param_tuple' in kwds or 'query_string' in kwds)): - raise ValueError('Query must be constructed with either a ' - + 'dictionary or a string and tuple') + if total_args > 2 or not ('query_dict' in kwds or 'query_string' in kwds) or ('query_dict' in kwds and ('param_tuple' in kwds or 'query_string' in kwds)): + raise ValueError('Query must be constructed with either a ' + 'dictionary or a string and tuple') if 'query_dict' in kwds: query_dict = kwds['query_dict'] @@ -488,32 +585,23 @@ def __init__(self, database, *args, **kwds): if query_dict: skel = database.__skeleton__ if query_dict['table_name'] not in skel: - raise ValueError("Database has no table %s" - % query_dict['table_name']) + raise ValueError("Database has no table %s" % query_dict['table_name']) table_name = query_dict['table_name'] if query_dict['display_cols'] is not None: for column in query_dict['display_cols']: if column not in skel[table_name]: raise ValueError("Table has no column %s" % column) if query_dict['expression'][0] not in skel[table_name]: - raise ValueError("Table has no column %s" - % query_dict['expression'][0]) + raise ValueError("Table has no column %s" % query_dict['expression'][0]) self.__query_dict__ = query_dict self.__param_tuple__ = (str(query_dict['expression'][2]),) verify_operator(query_dict['expression'][1]) if query_dict['display_cols'] is None: - self.__query_string__ = 'SELECT , FROM %s WHERE ' % table_name \ - + '%s.%s ' % (table_name, query_dict['expression'][0]) \ - + '%s ?' % query_dict['expression'][1] + self.__query_string__ = 'SELECT , FROM %s WHERE ' % table_name + '%s.%s ' % (table_name, query_dict['expression'][0]) + '%s ?' % query_dict['expression'][1] else: - query_dict['display_cols'] = ['%s.%s' % (table_name, x) - for x in query_dict['display_cols']] - self.__query_string__ = 'SELECT ' \ - + ', '.join(query_dict['display_cols']) + ' FROM ' \ - + '%s WHERE %s.' % (table_name, table_name) \ - + '%s ' % query_dict['expression'][0] \ - + '%s ?' % query_dict['expression'][1] + query_dict['display_cols'] = ['%s.%s' % (table_name, x) for x in query_dict['display_cols']] + self.__query_string__ = 'SELECT ' + ', '.join(query_dict['display_cols']) + ' FROM ' + '%s WHERE %s.' % (table_name, table_name) + '%s ' % query_dict['expression'][0] + '%s ?' % query_dict['expression'][1] else: self.__query_dict__ = {} self.__param_tuple__ = tuple() @@ -541,10 +629,7 @@ def __repr__(self): """ if not self.__query_string__: return 'Empty query on %s.' % self.__database__.__dblocation__ - return "Query for sql database: %s" % self.__database__.__dblocation__ \ - + "\nQuery string: %s" % self.__query_string__ \ - + ("\nParameter tuple: %s" % str(self.__param_tuple__) if - self.__param_tuple__ else "") + return "Query for sql database: %s" % self.__database__.__dblocation__ + "\nQuery string: %s" % self.__query_string__ + ("\nParameter tuple: %s" % str(self.__param_tuple__) if self.__param_tuple__ else "") def get_query_string(self): """ @@ -563,6 +648,7 @@ def get_query_string(self): 'SELECT graph6 FROM graph_data WHERE num_vertices<=3' """ from copy import copy + return copy(self.__query_string__) def __iter__(self): @@ -680,8 +766,7 @@ def show(self, **kwds): except Exception: raise RuntimeError('Failure to fetch query.') - print(_create_print_table(cur, [des[0] for des in cur.description], - **kwds)) + print(_create_print_table(cur, [des[0] for des in cur.description], **kwds)) def __copy__(self): """ @@ -702,8 +787,7 @@ def __copy__(self): d.__param_tuple__ = self.__param_tuple__ return d - def intersect(self, other, join_table=None, join_dict=None, - in_place=False): + def intersect(self, other, join_table=None, join_dict=None, in_place=False): """ Return a new ``SQLQuery`` that is the intersection of ``self`` and ``other``. ``join_table`` and ``join_dict`` can be ``None`` iff the @@ -751,11 +835,9 @@ def intersect(self, other, join_table=None, join_dict=None, True """ if self.__query_dict__ is None or other.__query_dict__ is None: - raise RuntimeError('Queries must be constructed using a ' - + 'dictionary in order to be intersected.') + raise RuntimeError('Queries must be constructed using a ' + 'dictionary in order to be intersected.') if self.__database__ != other.__database__: - raise TypeError('Queries %s and %s must be ' % (self, other) - + 'attached to the same database.') + raise TypeError('Queries %s and %s must be ' % (self, other) + 'attached to the same database.') if in_place: if not self.__query_string__: @@ -767,12 +849,12 @@ def intersect(self, other, join_table=None, join_dict=None, self._merge_queries(other, self, join_table, join_dict, 'AND') else: from copy import copy + if not self.__query_string__: return copy(other) if not other.__query_string__: return copy(self) - return self._merge_queries(other, copy(self), join_table, - join_dict, 'AND') + return self._merge_queries(other, copy(self), join_table, join_dict, 'AND') def _merge_queries(self, other, ret, join_table, join_dict, operator): """ @@ -798,27 +880,21 @@ def _merge_queries(self, other, ret, join_table, join_dict, operator): """ if join_table is None or join_dict is None: pattern = ' JOIN ' - if re.search(pattern, self.__query_string__) \ - or re.search(pattern, other.__query_string__): - raise TypeError('Input queries have joins but join ' - + 'parameters are NoneType') + if re.search(pattern, self.__query_string__) or re.search(pattern, other.__query_string__): + raise TypeError('Input queries have joins but join ' + 'parameters are NoneType') s = ((self.__query_string__).upper()).split('FROM ') o = ((other.__query_string__).upper()).split('FROM ') s = s[1].split(' WHERE ') o = o[1].split(' WHERE ') if s[0] != o[0]: - raise ValueError('Input queries query different tables but ' - + 'join parameters are NoneType') + raise ValueError('Input queries query different tables but ' + 'join parameters are NoneType') # inner join clause if join_dict is not None: joins = join_table for table in join_dict: - joins += ' INNER JOIN %s ON %s.' % (table, join_table) \ - + '%s=%s.' % (join_dict[table][0], table) \ - + '%s ' % join_dict[table][1] - ret.__query_string__ = re.sub(' FROM .* WHERE ', ' FROM ' + joins - + 'WHERE ', self.__query_string__) + joins += ' INNER JOIN %s ON %s.' % (table, join_table) + '%s=%s.' % (join_dict[table][0], table) + '%s ' % join_dict[table][1] + ret.__query_string__ = re.sub(' FROM .* WHERE ', ' FROM ' + joins + 'WHERE ', self.__query_string__) # concatenate display cols disp1 = ret.__query_string__.split(' FROM') @@ -827,10 +903,8 @@ def _merge_queries(self, other, ret, join_table, join_dict, operator): new_query = ''.join(disp1) # concatenate where clause - new_query = re.sub(' WHERE ', ' WHERE ( ', - new_query) - new_query += re.sub('^.* WHERE ', f' ) {operator} ( ', - other.__query_string__) + new_query = re.sub(' WHERE ', ' WHERE ( ', new_query) + new_query += re.sub('^.* WHERE ', f' ) {operator} ( ', other.__query_string__) ret.__query_string__ = new_query + ' )' ret.__param_tuple__ = self.__param_tuple__ + other.__param_tuple__ @@ -875,23 +949,21 @@ def union(self, other, join_table=None, join_dict=None, in_place=False): [(1, 1), (4, 1)] """ if self.__query_dict__ is None or other.__query_dict__ is None: - raise RuntimeError('Queries must be constructed using a ' - + 'dictionary in order to be unioned.') + raise RuntimeError('Queries must be constructed using a ' + 'dictionary in order to be unioned.') if self.__database__ != other.__database__: - raise TypeError('Queries %s and %s must be ' % (self, other) - + 'attached to the same database.') + raise TypeError('Queries %s and %s must be ' % (self, other) + 'attached to the same database.') if in_place: if self.__query_string__ and other.__query_string__: self._merge_queries(other, self, join_table, join_dict, 'OR') else: from copy import copy + if not self.__query_string__: return copy(self) if not other.__query_string__: return copy(other) - return self._merge_queries(other, copy(self), join_table, - join_dict, 'OR') + return self._merge_queries(other, copy(self), join_table, join_dict, 'OR') class SQLDatabase(SageObject): @@ -1072,17 +1144,15 @@ def __init__(self, filename=None, read_only=None, skeleton=None): if read_only is None: read_only = False filename = tmp_filename() + '.db' - elif (filename[-3:] != '.db'): - raise ValueError('Please enter a valid database path (file name ' - + '%s does not end in .db).' % filename) + elif filename[-3:] != '.db': + raise ValueError('Please enter a valid database path (file name ' + '%s does not end in .db).' % filename) if read_only is None: read_only = True self.__read_only__ = read_only self.ignore_warnings = False self.__dblocation__ = filename - self.__connection__ = sqlite.connect(self.__dblocation__, - check_same_thread=False) + self.__connection__ = sqlite.connect(self.__dblocation__, check_same_thread=False) # this is to avoid the multiple thread problem with dsage: # pysqlite does not trust multiple threads for the same connection self.__connection__.create_function("regexp", 2, regexp) @@ -1099,15 +1169,11 @@ def __init__(self, filename=None, read_only=None, skeleton=None): else: for column in skeleton[table]: if column not in self.__skeleton__[table]: - self.add_column(table, column, - skeleton[table][column]) + self.add_column(table, column, skeleton[table][column]) else: - print('Column attributes were ignored for ' - 'table {}, column {} -- column is ' - 'already in table.'.format(table, column)) + print('Column attributes were ignored for ' 'table {}, column {} -- column is ' 'already in table.'.format(table, column)) elif skeleton is not None: - raise RuntimeError('Cannot update skeleton of a read only ' - + 'database.') + raise RuntimeError('Cannot update skeleton of a read only ' + 'database.') def __enter__(self): return self @@ -1138,8 +1204,7 @@ def __repr__(self): for column in self.__skeleton__[table]: s += ' column ' + column + ': ' for data in sorted(self.__skeleton__[table][column]): - s += data + ': ' \ - + str(self.__skeleton__[table][column][data]) + '; ' + s += data + ': ' + str(self.__skeleton__[table][column][data]) + '; ' s += '\n' return s @@ -1321,8 +1386,7 @@ def show(self, table_name, **kwds): cur.execute('SELECT * FROM ' + table_name) except Exception: raise RuntimeError('Failure to fetch data.') - print(_create_print_table(cur, [des[0] for des in cur.description], - **kwds)) + print(_create_print_table(cur, [des[0] for des in cur.description], **kwds)) def get_cursor(self, ignore_warning=None): """ @@ -1349,9 +1413,8 @@ def get_cursor(self, ignore_warning=None): ignore_warning = self.ignore_warnings if not ignore_warning: import warnings - warnings.warn('Database is read only, using the cursor can ' - + 'alter the stored data. Set self.ignore_warnings to ' - + 'True in order to mute future warnings.', RuntimeWarning) + + warnings.warn('Database is read only, using the cursor can ' + 'alter the stored data. Set self.ignore_warnings to ' + 'True in order to mute future warnings.', RuntimeWarning) return self.__connection__.cursor() def get_connection(self, ignore_warning=None): @@ -1393,10 +1456,8 @@ def get_connection(self, ignore_warning=None): ignore_warning = self.ignore_warnings if not ignore_warning: import warnings - warnings.warn('Database is read only, using the connection ' - 'can alter the stored data. Set self.ignore_warnings ' - 'to True in order to mute future warnings.', - RuntimeWarning) + + warnings.warn('Database is read only, using the connection ' 'can alter the stored data. Set self.ignore_warnings ' 'to True in order to mute future warnings.', RuntimeWarning) return self.__connection__ def create_table(self, table_name, table_skeleton): @@ -1448,8 +1509,7 @@ def create_table(self, table_name, table_skeleton): if self.__read_only__: raise RuntimeError('Cannot add table to a read only database.') if table_name in self.__skeleton__: - raise ValueError('Database already has a table named %s' - % table_name) + raise ValueError('Database already has a table named %s' % table_name) if table_name.find(' ') != -1: raise ValueError('Table names cannot contain spaces.') if table_name.upper() in sqlite_keywords: @@ -1474,8 +1534,7 @@ def create_table(self, table_name, table_skeleton): else: statement.append(col + ' ' + typ) if table_skeleton[col]['index']: - index_statement += 'CREATE INDEX i_%s_%s' % (table_name, - col) + ' ON %s(%s);\n' % (table_name, col) + index_statement += 'CREATE INDEX i_%s_%s' % (table_name, col) + ' ON %s(%s);\n' % (table_name, col) create_statement += ', '.join(statement) + ') ' self.__connection__.execute(create_statement) @@ -1549,7 +1608,7 @@ def add_column(self, table_name, col_name, col_dict, default='NULL'): if table_name not in self.__skeleton__: raise ValueError("Database has no table %s." % table_name) if col_name in self.__skeleton__[table_name]: - raise ValueError("Table %s already has column %s." % (table_name,col_name)) + raise ValueError("Table %s already has column %s." % (table_name, col_name)) # Update the skeleton: self.__skeleton__[table_name][col_name] = verify_column(col_dict) @@ -1650,27 +1709,29 @@ def _rebuild_table(self, table_name, col_name=None, default=''): cols_attr = ', '.join(cols_attr) # Silly SQLite -- we have to make a temp table to hold info... - self.__connection__.executescript(""" + self.__connection__.executescript( + """ CREATE TEMPORARY TABLE spam(%s); INSERT INTO spam SELECT %s FROM %s; DROP TABLE %s; CREATE TABLE %s (%s); - """ % (cols_attr, original, table_name, table_name, table_name, cols_attr)) + """ + % (cols_attr, original, table_name, table_name, table_name, cols_attr) + ) # Update indices in new table skeleton = self.__skeleton__[table_name] - index_statement = ''.join(f'CREATE INDEX i_{table_name}_{col} ON ' - + f'{table_name}({col});\n' - for col in skeleton - if skeleton[col]['index'] - and not skeleton[col]['primary_key']) + index_statement = ''.join(f'CREATE INDEX i_{table_name}_{col} ON ' + f'{table_name}({col});\n' for col in skeleton if skeleton[col]['index'] and not skeleton[col]['primary_key']) if index_statement: self.__connection__.executescript(index_statement) # Now we can plop our data into the *new* table: - self.__connection__.executescript(""" + self.__connection__.executescript( + """ INSERT INTO %s SELECT %s FROM spam; DROP TABLE spam; - """ % (table_name, cols)) + """ + % (table_name, cols) + ) self.vacuum() @@ -1715,7 +1776,7 @@ def drop_column(self, table_name, col_name): if table_name not in self.__skeleton__: raise ValueError("Database has no table %s." % table_name) if col_name not in self.__skeleton__[table_name]: - raise ValueError("Table %s has no column %s." % (table_name,col_name)) + raise ValueError("Table %s has no column %s." % (table_name, col_name)) # Update the skeleton: self.__skeleton__[table_name].pop(col_name) @@ -1750,8 +1811,7 @@ def rename_table(self, table_name, new_name): if new_name in self.__skeleton__: raise ValueError('Database already has table %s.' % new_name) - self.__connection__.execute('ALTER TABLE %s RENAME TO ' % table_name - + new_name) + self.__connection__.execute('ALTER TABLE %s RENAME TO ' % table_name + new_name) # Update skeleton: self.__skeleton__[new_name] = self.__skeleton__.pop(table_name) @@ -1776,8 +1836,7 @@ def drop_table(self, table_name): {} """ if self.__read_only__: - raise RuntimeError('Cannot drop tables from a read only ' - + 'database.') + raise RuntimeError('Cannot drop tables from a read only ' + 'database.') if table_name not in self.__skeleton__: raise ValueError("Database has no table %s." % table_name) @@ -1842,14 +1901,12 @@ def make_index(self, col_name, table_name, unique=False): if table_name not in self.__skeleton__: raise ValueError("Database has no table %s." % table_name) if col_name not in self.__skeleton__[table_name]: - raise ValueError("Table %s has no column %s." % (table_name,col_name)) + raise ValueError("Table %s has no column %s." % (table_name, col_name)) if unique: - index_string = 'CREATE UNIQUE INDEX ' + col_name + ' ON ' \ - + table_name + ' (' + col_name + ')' + index_string = 'CREATE UNIQUE INDEX ' + col_name + ' ON ' + table_name + ' (' + col_name + ')' else: - index_string = 'CREATE INDEX ' + col_name + ' ON ' + table_name \ - + ' (' + col_name + ')' + index_string = 'CREATE INDEX ' + col_name + ' ON ' + table_name + ' (' + col_name + ')' cur = self.__connection__.cursor() cur.execute(index_string) @@ -1883,10 +1940,9 @@ def drop_index(self, table_name, index_name): if table_name not in self.__skeleton__: raise ValueError("Database has no table %s." % table_name) if index_name not in self.__skeleton__[table_name]: - raise ValueError("Table %s has no column %s." % (table_name, - index_name)) + raise ValueError("Table %s has no column %s." % (table_name, index_name)) if not self.__skeleton__[table_name][index_name]['index']: - return # silently + return # silently cur = self.__connection__.cursor() cur.execute('DROP INDEX i_' + table_name + '_' + index_name) @@ -2049,9 +2105,9 @@ def drop_primary_key(self, table_name, col_name): if table_name not in self.__skeleton__: raise ValueError("Database has no table %s." % table_name) if col_name not in self.__skeleton__[table_name]: - raise ValueError("Table %s has no column %s." % (table_name,col_name)) + raise ValueError("Table %s has no column %s." % (table_name, col_name)) if not self.__skeleton__[table_name][col_name]['primary_key']: - return # silently + return # silently # Update the skeleton: self.__skeleton__[table_name][col_name]['primary_key'] = False @@ -2135,11 +2191,9 @@ def delete_rows(self, query): if query.__database__ is not self: raise ValueError('%s is not associated to this database.' % query) if (query.__query_string__).find(' JOIN ') != -1: - raise ValueError(f'{query} is not a valid query. Can only ' - 'delete from one table at a time.') + raise ValueError(f'{query} is not a valid query. Can only ' 'delete from one table at a time.') - delete_statement = re.sub('SELECT .* FROM', 'DELETE FROM', - query.__query_string__) + delete_statement = re.sub('SELECT .* FROM', 'DELETE FROM', query.__query_string__) try: cur = self.get_cursor() @@ -2172,11 +2226,9 @@ def add_rows(self, table_name, rows, entry_order=None): strows = [tuple(str(entry) for entry in row) for row in rows] if entry_order is not None: - self.__connection__.executemany('INSERT INTO ' + table_name - + str(tuple(entry_order)) + ' VALUES ' + quest, strows) + self.__connection__.executemany('INSERT INTO ' + table_name + str(tuple(entry_order)) + ' VALUES ' + quest, strows) else: - self.__connection__.executemany('INSERT INTO ' + table_name - + ' VALUES ' + quest, strows) + self.__connection__.executemany('INSERT INTO ' + table_name + ' VALUES ' + quest, strows) add_data = add_rows diff --git a/src/sage/databases/stein_watkins.py b/src/sage/databases/stein_watkins.py index 30972efa6f1..0549c85aea8 100644 --- a/src/sage/databases/stein_watkins.py +++ b/src/sage/databases/stein_watkins.py @@ -165,7 +165,7 @@ def _lines(s): yield "" return line = s[:i] - s = s[i + 1:] + s = s[i + 1 :] yield line @@ -174,6 +174,7 @@ class SteinWatkinsAllData: Class for iterating through one of the Stein-Watkins database files for all conductors. """ + def __init__(self, num): num = int(num) self.num = num diff --git a/src/sage/databases/symbolic_data.py b/src/sage/databases/symbolic_data.py index 81807c3098b..0a7b02f468e 100644 --- a/src/sage/databases/symbolic_data.py +++ b/src/sage/databases/symbolic_data.py @@ -84,6 +84,7 @@ class SymbolicData: This class needs the optional ``database_symbolic_data`` package to be installed. """ + def __init__(self): """ EXAMPLES:: @@ -92,6 +93,7 @@ def __init__(self): SymbolicData with 372 ideals """ from sage.env import sage_data_paths + self.__intpath = self.__genpath = None for path in sage_data_paths('symbolic_data'): intpath = path + "/Data/XMLResources/INTPS/" diff --git a/src/sage/doctest/__main__.py b/src/sage/doctest/__main__.py index bae4a7b6718..740f2f68c59 100644 --- a/src/sage/doctest/__main__.py +++ b/src/sage/doctest/__main__.py @@ -6,8 +6,7 @@ import pytest # Note: the DOT_SAGE and SAGE_STARTUP_FILE environment variables have already been set by sage-env -DOT_SAGE = os.environ.get('DOT_SAGE', os.path.join(os.environ.get('HOME'), - '.sage')) +DOT_SAGE = os.environ.get('DOT_SAGE', os.path.join(os.environ.get('HOME'), '.sage')) # Override to not pick up user configuration, see Issue #20270 os.environ['SAGE_STARTUP_FILE'] = os.path.join(DOT_SAGE, 'init-doctests.sage') @@ -45,54 +44,27 @@ def _make_parser(): optional='sage,optional', random_seed=None, stats_path='.../timings2.json') """ - parser = argparse.ArgumentParser(usage="sage -t [options] filenames", - description="Run all tests in a file or a list of files whose extensions " - "are one of the following: " - ".py, .pyx, .pxd, .pxi, .sage, .spyx, .tex, .rst.") - parser.add_argument("-p", "--nthreads", dest="nthreads", - type=int, nargs='?', const=0, default=1, metavar="N", - help="test in parallel using N threads, with 0 interpreted as max(2, min(8, cpu_count())); " - "when run under the control of the GNU make jobserver (make -j), request as most N job slots") + parser = argparse.ArgumentParser(usage="sage -t [options] filenames", description="Run all tests in a file or a list of files whose extensions " "are one of the following: " ".py, .pyx, .pxd, .pxi, .sage, .spyx, .tex, .rst.") + parser.add_argument("-p", "--nthreads", dest="nthreads", type=int, nargs='?', const=0, default=1, metavar="N", help="test in parallel using N threads, with 0 interpreted as max(2, min(8, cpu_count())); " "when run under the control of the GNU make jobserver (make -j), request as most N job slots") parser.add_argument("-T", "--timeout", type=int, default=-1, help="timeout (in seconds) for doctesting one file, 0 for no timeout") what = parser.add_mutually_exclusive_group() what.add_argument("-a", "--all", action="store_true", default=False, help="test all files in the Sage library") - what.add_argument("--all-except", type=shlex.split, default=None, - help="test all files in the Sage library except the specified space-separated list " - "(backslash or quote are needed to escape spaces or backslashes or quotes)") + what.add_argument("--all-except", type=shlex.split, default=None, help="test all files in the Sage library except the specified space-separated list " "(backslash or quote are needed to escape spaces or backslashes or quotes)") what.add_argument("--installed", action="store_true", default=False, help="test all installed modules of the Sage library") parser.add_argument("--logfile", type=argparse.FileType('a'), metavar="FILE", help="log all output to FILE") - parser.add_argument("--format", choices=["sage", "github"], default="sage", - help="set format of error messages and warnings") + parser.add_argument("--format", choices=["sage", "github"], default="sage", help="set format of error messages and warnings") parser.add_argument("-l", "--long", action="store_true", default=False, help="include lines with the phrase 'long time'") - parser.add_argument("-s", "--short", dest="target_walltime", nargs='?', - type=int, default=-1, const=300, metavar="SECONDS", - help="run as many doctests as possible in about 300 seconds (or the number of seconds given as an optional argument)") - parser.add_argument("--warn-long", dest="warn_long", nargs='?', - type=float, default=-1.0, const=1.0, metavar="SECONDS", - help="warn if tests take more CPU time than SECONDS") + parser.add_argument("-s", "--short", dest="target_walltime", nargs='?', type=int, default=-1, const=300, metavar="SECONDS", help="run as many doctests as possible in about 300 seconds (or the number of seconds given as an optional argument)") + parser.add_argument("--warn-long", dest="warn_long", nargs='?', type=float, default=-1.0, const=1.0, metavar="SECONDS", help="warn if tests take more CPU time than SECONDS") # By default, include all tests marked 'sagemath_doc_html' -- see # https://github.com/sagemath/sage/issues/25345 and # https://github.com/sagemath/sage/issues/26110: - parser.add_argument("--optional", metavar="FEATURES", default=_get_optional_defaults(), - help='only run tests including one of the "# optional" tags listed in FEATURES (separated by commas); ' - 'if "sage" is listed, will also run the standard doctests; ' - 'if "sagemath_doc_html" is listed, will also run the tests relying on the HTML documentation; ' - 'if "optional" is listed, will also run tests for installed optional packages or detected features; ' - 'if "external" is listed, will also run tests for available external software; ' - 'if set to "all", then all tests will be run; ' - 'use "!FEATURE" to disable tests marked "# optional - FEATURE". ' - 'Note that "!" needs to be quoted or escaped in the shell.') - parser.add_argument("--hide", metavar="FEATURES", default="", - help='run tests pretending that the software listed in FEATURES (separated by commas) is not installed; ' - 'if "all" is listed, will also hide features corresponding to all optional or experimental packages; ' - 'if "optional" is listed, will also hide features corresponding to optional packages.') - parser.add_argument("--probe", metavar="FEATURES", default="", - help='run tests that would not be run because one of the given FEATURES (separated by commas) is not installed; ' - 'report the tests that pass nevertheless') + parser.add_argument("--optional", metavar="FEATURES", default=_get_optional_defaults(), help='only run tests including one of the "# optional" tags listed in FEATURES (separated by commas); ' 'if "sage" is listed, will also run the standard doctests; ' 'if "sagemath_doc_html" is listed, will also run the tests relying on the HTML documentation; ' 'if "optional" is listed, will also run tests for installed optional packages or detected features; ' 'if "external" is listed, will also run tests for available external software; ' 'if set to "all", then all tests will be run; ' 'use "!FEATURE" to disable tests marked "# optional - FEATURE". ' 'Note that "!" needs to be quoted or escaped in the shell.') + parser.add_argument("--hide", metavar="FEATURES", default="", help='run tests pretending that the software listed in FEATURES (separated by commas) is not installed; ' 'if "all" is listed, will also hide features corresponding to all optional or experimental packages; ' 'if "optional" is listed, will also hide features corresponding to optional packages.') + parser.add_argument("--probe", metavar="FEATURES", default="", help='run tests that would not be run because one of the given FEATURES (separated by commas) is not installed; ' 'report the tests that pass nevertheless') parser.add_argument("--randorder", type=int, metavar="SEED", help="randomize order of tests") - parser.add_argument("--random-seed", dest="random_seed", type=int, metavar="SEED", help="random seed (integer) for fuzzing doctests", - default=os.environ.get("SAGE_DOCTEST_RANDOM_SEED")) + parser.add_argument("--random-seed", dest="random_seed", type=int, metavar="SEED", help="random seed (integer) for fuzzing doctests", default=os.environ.get("SAGE_DOCTEST_RANDOM_SEED")) parser.add_argument("--global-iterations", "--global_iterations", type=int, default=0, help="repeat the whole testing process this many times") parser.add_argument("--file-iterations", "--file_iterations", type=int, default=0, help="repeat each file this many times, stopping on the first failure") parser.add_argument("--environment", type=str, default="sage.repl.ipython_kernel.all_jupyter", help="name of a module that provides the global environment for tests") @@ -108,34 +80,17 @@ def _make_parser(): parser.add_argument("--gdb", action="store_true", default=False, help="run doctests under the control of gdb") parser.add_argument("--lldb", action="store_true", default=False, help="run doctests under the control of lldb") - parser.add_argument("--valgrind", "--memcheck", action="store_true", default=False, - help="run doctests using Valgrind's memcheck tool. The log " - "files are named sage-memcheck.PID and can be found in " + - os.path.join(DOT_SAGE, "valgrind")) - parser.add_argument("--massif", action="store_true", default=False, - help="run doctests using Valgrind's massif tool. The log " - "files are named sage-massif.PID and can be found in " + - os.path.join(DOT_SAGE, "valgrind")) - parser.add_argument("--cachegrind", action="store_true", default=False, - help="run doctests using Valgrind's cachegrind tool. The log " - "files are named sage-cachegrind.PID and can be found in " + - os.path.join(DOT_SAGE, "valgrind")) - parser.add_argument("--omega", action="store_true", default=False, - help="run doctests using Valgrind's omega tool. The log " - "files are named sage-omega.PID and can be found in " + - os.path.join(DOT_SAGE, "valgrind")) - - parser.add_argument("-f", "--failed", action="store_true", default=False, - help="doctest only those files that failed in the previous run") - what.add_argument("-n", "--new", action="store_true", default=False, - help="doctest only those files that have been changed in the repository and not yet been committed") - parser.add_argument("--show-skipped", "--show_skipped", action="store_true", default=False, - help="print a summary at the end of each file of optional tests that were skipped") - - parser.add_argument("--stats_path", "--stats-path", default=os.path.join(DOT_SAGE, "timings2.json"), - help="path to a json dictionary for timings and failure status for each file from previous runs; it will be updated in this run") - parser.add_argument("--baseline_stats_path", "--baseline-stats-path", default=None, - help="path to a json dictionary for timings and failure status for each file, to be used as a baseline; it will not be updated") + parser.add_argument("--valgrind", "--memcheck", action="store_true", default=False, help="run doctests using Valgrind's memcheck tool. The log " "files are named sage-memcheck.PID and can be found in " + os.path.join(DOT_SAGE, "valgrind")) + parser.add_argument("--massif", action="store_true", default=False, help="run doctests using Valgrind's massif tool. The log " "files are named sage-massif.PID and can be found in " + os.path.join(DOT_SAGE, "valgrind")) + parser.add_argument("--cachegrind", action="store_true", default=False, help="run doctests using Valgrind's cachegrind tool. The log " "files are named sage-cachegrind.PID and can be found in " + os.path.join(DOT_SAGE, "valgrind")) + parser.add_argument("--omega", action="store_true", default=False, help="run doctests using Valgrind's omega tool. The log " "files are named sage-omega.PID and can be found in " + os.path.join(DOT_SAGE, "valgrind")) + + parser.add_argument("-f", "--failed", action="store_true", default=False, help="doctest only those files that failed in the previous run") + what.add_argument("-n", "--new", action="store_true", default=False, help="doctest only those files that have been changed in the repository and not yet been committed") + parser.add_argument("--show-skipped", "--show_skipped", action="store_true", default=False, help="print a summary at the end of each file of optional tests that were skipped") + + parser.add_argument("--stats_path", "--stats-path", default=os.path.join(DOT_SAGE, "timings2.json"), help="path to a json dictionary for timings and failure status for each file from previous runs; it will be updated in this run") + parser.add_argument("--baseline_stats_path", "--baseline-stats-path", default=None, help="path to a json dictionary for timings and failure status for each file, to be used as a baseline; it will not be updated") class GCAction(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): @@ -143,12 +98,7 @@ def __call__(self, parser, namespace, values, option_string=None): new_value = gcopts[values] setattr(namespace, self.dest, new_value) - parser.add_argument("--gc", - choices=["DEFAULT", "ALWAYS", "NEVER"], - default=0, - action=GCAction, - help="control garbage collection " - "(ALWAYS: collect garbage before every test; NEVER: disable gc; DEFAULT: Python default)") + parser.add_argument("--gc", choices=["DEFAULT", "ALWAYS", "NEVER"], default=0, action=GCAction, help="control garbage collection " "(ALWAYS: collect garbage before every test; NEVER: disable gc; DEFAULT: Python default)") # The --serial option is only really for internal use, better not # document it. @@ -178,8 +128,7 @@ def main(): in_filenames = True new_arguments.append('--') new_arguments.append(arg) - afterlog = arg in ['--logfile', '--stats_path', '--stats-path', - '--baseline_stats_path', '--baseline-stats-path'] + afterlog = arg in ['--logfile', '--stats_path', '--stats-path', '--baseline_stats_path', '--baseline-stats-path'] args = parser.parse_args(new_arguments) @@ -212,11 +161,7 @@ def main(): # they match the pytest file pattern. However, pass names # of directories. We use 'not os.path.exists(f)' for this so that # we do not silently hide typos. - filenames = [ - f - for f in args.filenames - if f.endswith("_test.py") or os.path.isdir(f) or not os.path.exists(f) - ] + filenames = [f for f in args.filenames if f.endswith("_test.py") or os.path.isdir(f) or not os.path.exists(f)] if filenames: print(f"Running pytest on {filenames} with options {pytest_options}") exit_code_pytest = pytest.main(filenames + pytest_options) diff --git a/src/sage/doctest/all.py b/src/sage/doctest/all.py index 136452e0c28..5e77b5c9fe6 100644 --- a/src/sage/doctest/all.py +++ b/src/sage/doctest/all.py @@ -1,3 +1,4 @@ from sage.misc.lazy_import import lazy_import + lazy_import('sage.doctest.control', 'run_doctests') del lazy_import diff --git a/src/sage/doctest/check_tolerance.py b/src/sage/doctest/check_tolerance.py index 0f37a395dbb..0a4b05d52d0 100644 --- a/src/sage/doctest/check_tolerance.py +++ b/src/sage/doctest/check_tolerance.py @@ -91,36 +91,44 @@ def check_tolerance_real_domain(want: MarkedOutput, got: str) -> tuple[str, str] # match 1.0 or 1.0 + I or 1.0 + 2.0*I -real_plus_optional_imag = ''.join([ - r'\s*(?P[+-]?\s*', - float_without_sign, - r')(\s*(?P[+-]\s*', - float_without_sign, - r')\*I|\s*(?P[+-])\s*I)?', -]) +real_plus_optional_imag = ''.join( + [ + r'\s*(?P[+-]?\s*', + float_without_sign, + r')(\s*(?P[+-]\s*', + float_without_sign, + r')\*I|\s*(?P[+-])\s*I)?', + ] +) # match - 2.0*I -only_imag = ''.join([ - r'\s*(?P[+-]?\s*', - float_without_sign, - r')\*I', -]) +only_imag = ''.join( + [ + r'\s*(?P[+-]?\s*', + float_without_sign, + r')\*I', + ] +) # match I or -I (no digits), require a non-word part before and after for specificity imaginary_unit = r'(?P^|\W)(?P[+-]?)I(?P$|\W)' -complex_regex = re.compile(''.join([ - '(', - only_imag, - '|', - imaginary_unit, - '|', - real_plus_optional_imag, - ')', -])) +complex_regex = re.compile( + ''.join( + [ + '(', + only_imag, + '|', + imaginary_unit, + '|', + real_plus_optional_imag, + ')', + ] + ) +) def complex_match_to_real_and_imag(m: re.Match) -> tuple[str, str]: @@ -189,11 +197,13 @@ def complex_star_repl(m: re.Match): """ if m.group('unit_imag') is not None: # preserve the matched non-word part - return ''.join([ - (m.group('unit_imag_pre') or '').strip(), - '*', - (m.group('unit_imag_post') or '').strip(), - ]) + return ''.join( + [ + (m.group('unit_imag_pre') or '').strip(), + '*', + (m.group('unit_imag_post') or '').strip(), + ] + ) return '*' diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index 4124c7c6b48..22ce1cc3c3f 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -7,6 +7,7 @@ - David Roe (2012-03-27) -- initial version, based on Robert Bradshaw's code. """ + # **************************************************************************** # Copyright (C) 2012-2013 David Roe # 2012-2013 Robert Bradshaw @@ -109,6 +110,7 @@ class DocTestDefaults(SageObject): optional='sage,optional', random_seed=None, stats_path='.../timings2.json') """ + def __init__(self, runtest_default=False, **kwds): """ Edit these parameters after creating an instance. @@ -178,8 +180,7 @@ def __init__(self, runtest_default=False, **kwds): # We don't want to use the real stats file by default so that # we don't overwrite timings for the actual running doctests. - self.stats_path = os.path.join( - DOT_SAGE, "timings2.json" if runtest_default else "timings_dt_test.json") + self.stats_path = os.path.join(DOT_SAGE, "timings2.json" if runtest_default else "timings_dt_test.json") self.__dict__.update(kwds) def _repr_(self): @@ -244,12 +245,10 @@ def skipdir(dirname) -> bool: sage: skipdir(os.path.join(sage.env.SAGE_SRC, "sage", "doctest", "tests")) True """ - return (os.path.exists(os.path.join(dirname, "nodoctest.py")) or - os.path.exists(os.path.join(dirname, "nodoctest"))) + return os.path.exists(os.path.join(dirname, "nodoctest.py")) or os.path.exists(os.path.join(dirname, "nodoctest")) -def skipfile(filename, tested_optional_tags=False, *, - if_installed=False, log=None): +def skipfile(filename, tested_optional_tags=False, *, if_installed=False, log=None): """ Return ``True`` if and only if the file ``filename`` should not be doctested. @@ -345,8 +344,7 @@ def skipfile(filename, tested_optional_tags=False, *, return file_tag_string elif tested_optional_tags is not True: - extra = {tag for tag in file_optional_tags - if tag not in tested_optional_tags} + extra = {tag for tag in file_optional_tags if tag not in tested_optional_tags} if extra: file_tag_string = unparse_optional_tags(file_optional_tags, prefix='') if log: @@ -372,6 +370,7 @@ class Logger: hello world 'hello world\n' """ + def __init__(self, *files): r""" Initialize the logger for writing to all files in ``files``. @@ -415,6 +414,7 @@ class DocTestController(SageObject): After creating it with appropriate options, call the :meth:`run` method to run the doctests. """ + def __init__(self, options, args): """ Initialization. @@ -485,11 +485,13 @@ def __init__(self, options, args): if 'all' in options.hide: options.hide.discard('all') from sage.features.all import all_features + feature_names = {f.name for f in all_features() if not f.is_standard()} options.hide = options.hide.union(feature_names) if 'optional' in options.hide: options.hide.discard('optional') from sage.features.all import all_features + feature_names = {f.name for f in all_features() if f.is_optional()} options.hide = options.hide.union(feature_names) @@ -508,6 +510,7 @@ def __init__(self, options, args): if 'optional' in options.optional: options.optional.discard('optional') from sage.misc.package import list_packages + for pkg in list_packages('optional', local=True).values(): if pkg.name in options.hide: continue @@ -518,8 +521,8 @@ def __init__(self, options, args): options.optional.add(pkg.name) from sage.features import package_systems - options.optional.update(system.name - for system in package_systems()) + + options.optional.update(system.name for system in package_systems()) # Check that all tags are valid for o in options.optional: if o.startswith('!'): @@ -631,7 +634,7 @@ def _init_warn_long(self): 5.00000000000000 """ # default is -1.0 - if self.options.warn_long >= 0: # Specified on the command line + if self.options.warn_long >= 0: # Specified on the command line return # The developer's guide says that even a "long time" test @@ -671,6 +674,7 @@ def load_environment(self): True """ from importlib import import_module + return import_module(self.options.environment) def load_baseline_stats(self, filename): @@ -772,6 +776,7 @@ def save_stats(self, filename): {'walltime': 1.0} """ from sage.misc.temporary_file import atomic_write + with atomic_write(filename) as stats_file: json.dump(self.stats, stats_file, sort_keys=True, indent=4) @@ -869,6 +874,7 @@ def add_files(self): """ opj = os.path.join from sage.env import SAGE_DOC, SAGE_DOC_SRC, SAGE_ROOT, SAGE_ROOT_GIT, SAGE_SRC + # SAGE_ROOT_GIT can be None on distributions which typically # only have the SAGE_LOCAL install tree but not SAGE_ROOT if SAGE_ROOT_GIT is not None: @@ -879,14 +885,17 @@ def add_files(self): def all_installed_modules(): self.log("Doctesting all installed modules of the Sage library.") import sage + self.files.extend(sage.__path__) try: import sage_setup + self.files.extend(sage_setup.__path__) except ImportError: pass try: import sage_docbuild + self.files.extend(sage_docbuild.__path__) except ImportError: pass @@ -907,11 +916,13 @@ def all_files(): # disabled. try: import sage_setup + self.files.append(opj(SAGE_SRC, 'sage_setup')) except ImportError: pass try: import sage_docbuild + self.files.append(opj(SAGE_SRC, 'sage_docbuild')) except ImportError: pass @@ -935,25 +946,15 @@ def all_doc_sources(): # Get all files changed in the working repo. self.log("Doctesting files changed since last git commit") import subprocess - change = subprocess.check_output(["git", - "--git-dir=" + SAGE_ROOT_GIT, - "--work-tree=" + SAGE_ROOT, - "status", - "--porcelain"]) + + change = subprocess.check_output(["git", "--git-dir=" + SAGE_ROOT_GIT, "--work-tree=" + SAGE_ROOT, "status", "--porcelain"]) change = change.decode('utf-8') for line in change.split("\n"): if not line: continue data = line.strip().split(' ') status, filename = data[0], data[-1] - if (set(status).issubset("MARCU") - and filename.startswith("src/sage") - and (filename.endswith(".py") or - filename.endswith(".pyx") or - filename.endswith(".rst")) - and not skipfile(opj(SAGE_ROOT, filename), - bool(self.options.optional), - if_installed=self.options.if_installed)): + if set(status).issubset("MARCU") and filename.startswith("src/sage") and (filename.endswith(".py") or filename.endswith(".pyx") or filename.endswith(".rst")) and not skipfile(opj(SAGE_ROOT, filename), bool(self.options.optional), if_installed=self.options.if_installed): self.files.append(os.path.relpath(opj(SAGE_ROOT, filename))) def expand_files_into_sources(self): @@ -1005,6 +1006,7 @@ def expand_files_into_sources(self): sage: len(DC.sources) >= 10 True """ + def expand(): for path in self.files: if os.path.isdir(path): @@ -1013,20 +1015,16 @@ def expand(): if dir[0] == "." or skipdir(os.path.join(root, dir)): dirs.remove(dir) for file in files: - if not skipfile(os.path.join(root, file), - bool(self.options.optional), - if_installed=self.options.if_installed): + if not skipfile(os.path.join(root, file), bool(self.options.optional), if_installed=self.options.if_installed): yield os.path.join(root, file) - elif not skipfile(path, bool(self.options.optional), - if_installed=self.options.if_installed, - log=self.log): # log when directly specified filenames are skipped + elif not skipfile(path, bool(self.options.optional), if_installed=self.options.if_installed, log=self.log): # log when directly specified filenames are skipped yield path + paths = list(expand()) if self.options.all_except is not None: paths_to_remove = set(os.path.abspath(x) for x in self.options.all_except) if not paths_to_remove.issubset(paths): - raise ValueError(f"--all-except includes {paths_to_remove - set(paths)}, " - f"which are not found in {paths}") + raise ValueError(f"--all-except includes {paths_to_remove - set(paths)}, " f"which are not found in {paths}") paths = [path for path in paths if path not in paths_to_remove] # keep duplicates self.sources = [FileDocTestSource(path, self.options) for path in paths] @@ -1057,6 +1055,7 @@ def filter_sources(self): def is_failure(source): basename = source.basename return basename not in self.stats or self.stats[basename].get('failed') + self.sources = [x for x in self.sources if is_failure(x)] def sort_sources(self): @@ -1101,6 +1100,7 @@ def sort_sources(self): def sort_key(source): basename = source.basename return -self.stats.get(basename, default).get('walltime', 0), basename + self.sources = sorted(self.sources, key=sort_key) def source_baseline(self, source): @@ -1162,8 +1162,7 @@ def run_doctests(self): else: nother += 1 if self.sources: - filestr = ", ".join(([count_noun(nfiles, "file")] if nfiles else []) + - ([count_noun(nother, "other source")] if nother else [])) + filestr = ", ".join(([count_noun(nfiles, "file")] if nfiles else []) + ([count_noun(nother, "other source")] if nother else [])) threads = " using %s threads" % (self.options.nthreads) if self.options.nthreads > 1 else "" iterations = [] if self.options.global_iterations > 1: @@ -1280,16 +1279,11 @@ def _assemble_cmd(self): cmd = f"{shlex.quote(sys.executable)} -m sage.doctest --serial " opt = dict_difference(self.options.__dict__, DocTestDefaults(runtest_default=True).__dict__) # Options with no argument - for o in ("all", "installed", "long", "initial", "exitfirst", - "force_lib", "if_installed", "abspath", "verbose", - "debug", "only_errors", "failed", "new", - "show_skipped"): + for o in ("all", "installed", "long", "initial", "exitfirst", "force_lib", "if_installed", "abspath", "verbose", "debug", "only_errors", "failed", "new", "show_skipped"): if o in opt: cmd += "--%s " % o.replace('_', '-') # Options with one argument - for o in ("timeout", "die_timeout", "logfile", "warn_long", "randorder", - "random_seed", "global_iterations", "file_iterations", - "environment", "baseline_stats_path", "stats_path"): + for o in ("timeout", "die_timeout", "logfile", "warn_long", "randorder", "random_seed", "global_iterations", "file_iterations", "environment", "baseline_stats_path", "stats_path"): if o in opt: cmd += "--%s=%s " % (o.replace('_', '-'), opt[o]) # One with a different dest @@ -1391,6 +1385,7 @@ def run_val_gdb(self, testing=False): import signal import subprocess + p = subprocess.Popen(cmd, shell=True) if opt.timeout > 0: @@ -1533,22 +1528,15 @@ def run(self): # only have the SAGE_LOCAL install tree but not SAGE_ROOT if (SAGE_ROOT_GIT is not None) and os.path.isdir(SAGE_ROOT_GIT): import subprocess + try: - branch = subprocess.check_output(["git", - "--git-dir=" + SAGE_ROOT_GIT, - "rev-parse", - "--abbrev-ref", - "HEAD"]) + branch = subprocess.check_output(["git", "--git-dir=" + SAGE_ROOT_GIT, "rev-parse", "--abbrev-ref", "HEAD"]) branch = branch.decode('utf-8') self.log("Git branch: " + branch, end="") except subprocess.CalledProcessError: pass try: - ref = subprocess.check_output(["git", - "--git-dir=" + SAGE_ROOT_GIT, - "describe", - "--always", - "--dirty"]) + ref = subprocess.check_output(["git", "--git-dir=" + SAGE_ROOT_GIT, "describe", "--always", "--dirty"]) ref = ref.decode('utf-8') self.log("Git ref: " + ref, end="") except subprocess.CalledProcessError: @@ -1582,16 +1570,14 @@ def run(self): self.log("Features to be detected: " + ','.join(available_software.detectable())) if self.options.probe: - self.log("Features to be probed: " + ('all' if self.options.probe is True - else ','.join(self.options.probe))) + self.log("Features to be probed: " + ('all' if self.options.probe is True else ','.join(self.options.probe))) self.add_files() self.expand_files_into_sources() self.filter_sources() self.sort_sources() self.run_doctests() - self.log("Features detected for doctesting: " - + ','.join(available_software.seen())) + self.log("Features detected for doctesting: " + ','.join(available_software.seen())) if self.options.hidden_features: for f in self.options.hidden_features: f.unhide() @@ -1626,6 +1612,7 @@ def run_doctests(module, options=None): Features detected... """ import sys + sys.stdout.flush() def stringify(x): @@ -1645,6 +1632,7 @@ def stringify(x): return [os.path.join(base, file) + ext] if isinstance(x, str): return [os.path.abspath(x)] + F = stringify(module) if options is None: options = DocTestDefaults() @@ -1659,6 +1647,7 @@ def stringify(x): if options.debug: raise ValueError("You should not try to run doctests with a debugger from within Sage: IPython objects to embedded shells") from IPython.core.getipython import get_ipython + IP = get_ipython() if IP is not None: old_color = IP.colors @@ -1703,4 +1692,6 @@ def stringify(x): {prompt}: get_matrix_class(GF(25,'x'), 4, 4, False, 'meataxe') # optional - meataxe {quotmark} -""".format(quotmark='"""', prompt='sage') # using prompt to hide these lines from _test_enough_doctests +""".format( + quotmark='"""', prompt='sage' +) # using prompt to hide these lines from _test_enough_doctests diff --git a/src/sage/doctest/external.py b/src/sage/doctest/external.py index 7ab24ae6f9b..23775d6b519 100644 --- a/src/sage/doctest/external.py +++ b/src/sage/doctest/external.py @@ -60,6 +60,7 @@ def has_internet() -> bool: FeatureTestResult('internet', True) """ from sage.features.internet import Internet + return Internet().is_present() @@ -74,6 +75,7 @@ def has_latex() -> bool: FeatureTestResult('latex', True) """ from sage.features.latex import latex + return latex().is_present() @@ -88,6 +90,7 @@ def has_xelatex() -> bool: FeatureTestResult('xelatex', True) """ from sage.features.latex import xelatex + return xelatex().is_present() @@ -102,6 +105,7 @@ def has_pdflatex() -> bool: FeatureTestResult('pdflatex', True) """ from sage.features.latex import pdflatex + return pdflatex().is_present() @@ -116,6 +120,7 @@ def has_lualatex() -> bool: FeatureTestResult('lualatex', True) """ from sage.features.latex import lualatex + return lualatex().is_present() @@ -130,6 +135,7 @@ def has_magma() -> bool: True """ from sage.features.interfaces import Magma + return Magma().is_present() @@ -144,6 +150,7 @@ def has_matlab() -> bool: True """ from sage.features.interfaces import Matlab + return Matlab().is_present() @@ -158,6 +165,7 @@ def has_mathematica() -> bool: True """ from sage.features.interfaces import Mathematica + return Mathematica().is_present() @@ -172,6 +180,7 @@ def has_maple() -> bool: True """ from sage.features.interfaces import Maple + return Maple().is_present() @@ -186,6 +195,7 @@ def has_macaulay2() -> bool: True """ from sage.features.interfaces import Macaulay2 + return Macaulay2().is_present() @@ -200,6 +210,7 @@ def has_octave() -> bool: True """ from sage.features.interfaces import Octave + return Octave().is_present() @@ -214,6 +225,7 @@ def has_pandoc() -> bool: FeatureTestResult('pandoc', True) """ from sage.features.pandoc import Pandoc + return Pandoc().is_present() @@ -228,6 +240,7 @@ def has_scilab() -> bool: True """ from sage.interfaces.scilab import scilab + try: scilab('2+3') return True @@ -246,6 +259,7 @@ def has_cplex() -> bool: FeatureTestResult('cplex', True) """ from sage.features.mip_backends import CPLEX + return CPLEX().is_present() @@ -260,6 +274,7 @@ def has_gurobi() -> bool: FeatureTestResult('gurobi', True) """ from sage.features.mip_backends import Gurobi + return Gurobi().is_present() @@ -274,6 +289,7 @@ def has_graphviz() -> bool: FeatureTestResult('graphviz', True) """ from sage.features.graphviz import Graphviz + return Graphviz().is_present() @@ -288,6 +304,7 @@ def has_ffmpeg() -> bool: FeatureTestResult('ffmpeg', True) """ from sage.features.ffmpeg import FFmpeg + return FFmpeg().is_present() @@ -302,6 +319,7 @@ def has_imagemagick() -> bool: FeatureTestResult('imagemagick', True) """ from sage.features.imagemagick import ImageMagick + return ImageMagick().is_present() @@ -316,6 +334,7 @@ def has_dvipng() -> bool: FeatureTestResult('dvipng', True) """ from sage.features.dvipng import dvipng + return dvipng().is_present() @@ -330,6 +349,7 @@ def has_pdf2svg() -> bool: FeatureTestResult('pdf2svg', True) """ from sage.features.pdf2svg import pdf2svg + return pdf2svg().is_present() @@ -345,6 +365,7 @@ def has_rubiks() -> bool: FeatureTestResult('rubiks', True) """ from sage.features.rubiks import Rubiks + return Rubiks().is_present() @@ -359,6 +380,7 @@ def has_4ti2() -> bool: FeatureTestResult('4ti2', True) """ from sage.features.four_ti_2 import FourTi2 + return FourTi2().is_present() @@ -377,16 +399,21 @@ def external_features(): Feature('internet') """ from sage.features.internet import Internet + yield Internet() import sage.features.latex + yield from sage.features.latex.all_features() import sage.features.ffmpeg + yield from sage.features.ffmpeg.all_features() import sage.features.interfaces + for feature in sage.features.interfaces.all_features(): if feature.name not in ('mathics', 'regina'): yield feature from sage.features.mip_backends import CPLEX, Gurobi + yield CPLEX() yield Gurobi() @@ -438,6 +465,7 @@ class AvailableSoftware: sage: available_software.issuperset(set(['internet','latex'])) # random, optional - internet latex True """ + def __init__(self): """ Initialization. @@ -454,13 +482,14 @@ def __init__(self): # shared among subprocesses. Thus we use Array class from the # multiprocessing module. from sage.features.all import all_features + self._external_features = set(external_features()) features = set(self._external_features) features.update(all_features()) self._features = sorted(features, key=lambda feature: feature.name) self._indices = {feature.name: idx for idx, feature in enumerate(self._features)} - self._seen = Array('i', len(self._features)) # initialized to zeroes - self._hidden = Array('i', len(self._features)) # initialized to zeroes + self._seen = Array('i', len(self._features)) # initialized to zeroes + self._hidden = Array('i', len(self._features)) # initialized to zeroes def __contains__(self, item): """ @@ -512,9 +541,7 @@ def detectable(self): """ Return the list of names of those features for which testing their presence is allowed. """ - return [feature.name - for feature, seen in zip(self._features, self._seen) - if seen >= 0 and (self._allow_external or feature not in self._external_features)] + return [feature.name for feature, seen in zip(self._features, self._seen) if seen >= 0 and (self._allow_external or feature not in self._external_features)] def seen(self): """ @@ -526,9 +553,7 @@ def seen(self): sage: available_software.seen() # random ['internet', 'latex', 'magma'] """ - return [feature.name - for feature, seen in zip(self._features, self._seen) - if seen > 0] + return [feature.name for feature, seen in zip(self._features, self._seen) if seen > 0] def hidden(self): """ @@ -550,9 +575,7 @@ def hidden(self): 'database_ellcurves',... 'database_graphs'...] """ - return [feature.name - for feature, hidden in zip(self._features, self._hidden) - if hidden > 0] + return [feature.name for feature, hidden in zip(self._features, self._hidden) if hidden > 0] available_software = AvailableSoftware() diff --git a/src/sage/doctest/fixtures.py b/src/sage/doctest/fixtures.py index 37fc8cad956..49910a51913 100644 --- a/src/sage/doctest/fixtures.py +++ b/src/sage/doctest/fixtures.py @@ -107,6 +107,7 @@ def reproducible_repr(val): set(['a', 'b', 'c', 'd']) """ from sage.misc.superseded import deprecation + deprecation(39420, 'reproducible_repr is deprecated, see its documentation for details') def sorted_pairs(iterable, pairs=False): @@ -127,10 +128,10 @@ def sorted_pairs(iterable, pairs=False): if isinstance(val, dict): keys = sorted_pairs(val.keys(), True) itms = ["{}: {}".format(r, reproducible_repr(val[k])) for r, k in keys] - return ("{{{}}}".format(", ".join(itms))) + return "{{{}}}".format(", ".join(itms)) if isinstance(val, list): itms = map(reproducible_repr, val) - return ("[{}]".format(", ".join(itms))) + return "[{}]".format(", ".join(itms)) return repr(val) @@ -204,21 +205,20 @@ def get(self, name): """ val = getattr(self.delegate, name) from IPython.lib.pretty import pretty + if callable(val) and name not in self.delegate.__dict__: + @wraps(val) def wrapper(*args, **kwds): arglst = [pretty(arg) for arg in args] - arglst.extend("{}={}".format(k, pretty(v)) - for k, v in sorted(kwds.items())) + arglst.extend("{}={}".format(k, pretty(v)) for k, v in sorted(kwds.items())) res = val(*args, **kwds) - print("{}call {}({}) -> {}" - .format(self.prefix, name, ", ".join(arglst), - pretty(res))) + print("{}call {}({}) -> {}".format(self.prefix, name, ", ".join(arglst), pretty(res))) return res + return wrapper if self.reads: - print("{}read {} = {}".format(self.prefix, name, - pretty(val))) + print("{}read {} = {}".format(self.prefix, name, pretty(val))) return val def set(self, name, val): @@ -241,8 +241,8 @@ def set(self, name, val): 2 """ from IPython.lib.pretty import pretty - print("{}write {} = {}".format(self.prefix, name, - pretty(val))) + + print("{}write {} = {}".format(self.prefix, name, pretty(val))) setattr(self.delegate, name, val) @@ -391,17 +391,19 @@ def trace_method(obj, meth, **kwds): 9 """ from sage.cpython.getattr import raw_getattr + f = raw_getattr(obj, meth) t = AttributeAccessTracerProxy(obj, **kwds) @wraps(f) def g(*args, **kwds): from IPython.lib.pretty import pretty + arglst = [pretty(arg) for arg in args] - arglst.extend("{}={}".format(k, pretty(v)) - for k, v in sorted(kwds.items())) + arglst.extend("{}={}".format(k, pretty(v)) for k, v in sorted(kwds.items())) print("enter {}({})".format(meth, ", ".join(arglst))) res = f(t, *args, **kwds) print("exit {} -> {}".format(meth, pretty(res))) return res + setattr(obj, meth, g) diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index 96c7fd08bfc..15901a15004 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -105,6 +105,7 @@ def _sorted_dict_pprinter_factory(start, end): sage: {2: 0, 1: 0} # indirect doctest {1: 0, 2: 0} """ + def inner(obj, p, cycle): if cycle: return p.text('{...}') @@ -120,6 +121,7 @@ def inner(obj, p, cycle): p.text(': ') p.pretty(obj[key]) p.end_group(step, end) + return inner @@ -191,6 +193,7 @@ def init_sage(controller: DocTestController | None = None) -> None: # This is more efficient because we only need to wait once for the # Sage imports. import sage.doctest + sage.doctest.DOCTEST_MODE = True # IPython's pretty printer sorts the repr of dicts by their keys by default @@ -209,6 +212,7 @@ def init_sage(controller: DocTestController | None = None) -> None: try: from sage.interfaces.quit import invalidate_all + invalidate_all() except ModuleNotFoundError: pass @@ -216,16 +220,20 @@ def init_sage(controller: DocTestController | None = None) -> None: # Disable cysignals debug messages in doctests: this is needed to # make doctests pass when cysignals was built with debugging enabled from cysignals.signals import set_debug_level + set_debug_level(0) # Use the rich output backend for doctest from sage.repl.rich_output import get_display_manager + dm = get_display_manager() from sage.repl.rich_output.backend_doctest import BackendDoctest + dm.switch_backend(BackendDoctest()) # Switch on extra debugging from sage.structure.debug_options import debug + debug.refine_category_hash_check = True # We import readline before forking, otherwise Pdb doesn't work @@ -244,6 +252,7 @@ def init_sage(controller: DocTestController | None = None) -> None: else: # Disable SymPy terminal width detection from sympy.printing.pretty.stringpict import stringPict + stringPict.terminal_width = lambda self: 0 @@ -274,13 +283,13 @@ def showwarning_with_traceback(message, category, filename, lineno, file=None, l tb = tb[:-1] # Drop this stack frame for showwarning_with_traceback() for i, frame_summary in enumerate(tb): if frame_summary.filename.endswith('sage/doctest/forker.py') and frame_summary.name == 'compile_and_execute': - tb = tb[i + 1:] + tb = tb[i + 1 :] break # Format warning lines = ["doctest:warning\n"] # Match historical warning messages in doctests lines.extend(traceback.format_list(tb)) - lines.append(":\n") # Match historical warning messages in doctests + lines.append(":\n") # Match historical warning messages in doctests lines.extend(traceback.format_exception_only(category, category(message))) if file is None: @@ -338,6 +347,7 @@ class SageSpoofInOut(SageObject): hello world sage: O.close() """ + def __init__(self, outfile=None, infile=None): """ Initialization. @@ -555,7 +565,7 @@ def __init__(self, *args, **kwds): self.total_walltime_skips = 0 self.total_performed_tests = 0 self.total_walltime = 0 - if sys.version_info < (3,13): + if sys.version_info < (3, 13): self._stats = self._name2ft def _run(self, test, compileflags, out): @@ -632,12 +642,12 @@ def _run(self, test, compileflags, out): # If REPORT_ONLY_FIRST_FAILURE is set, then suppress # reporting after the first failure (but continue # running the tests). - quiet |= (self.optionflags & doctest.REPORT_ONLY_FIRST_FAILURE) + quiet |= self.optionflags & doctest.REPORT_ONLY_FIRST_FAILURE # Merge in the example's options. self.optionflags = original_optionflags if example.options: - for (optionflag, val) in example.options.items(): + for optionflag, val in example.options.items(): if val: self.optionflags |= optionflag else: @@ -687,24 +697,20 @@ def compiler(example): # Compile mode "single" is meant for running a single # statement like on the Python command line. It implies # in particular that the resulting value will be printed. - code = compile(example.source, filename, "single", - compileflags, 1) + code = compile(example.source, filename, "single", compileflags, 1) # Python 2 ignores everything after the first complete # statement in the source code. To verify that we really # have just a single statement and nothing more, we also # compile in "exec" mode and verify that the line # numbers are the same. - execcode = compile(example.source, filename, "exec", - compileflags, 1) + execcode = compile(example.source, filename, "exec", compileflags, 1) # findlinestarts() returns pairs (index, lineno) where # "index" is the index in the bytecode where the line # number changes to "lineno". - linenumbers1 = {lineno for (index, lineno) - in findlinestarts(code)} - linenumbers2 = {lineno for (index, lineno) - in findlinestarts(execcode)} + linenumbers1 = {lineno for (index, lineno) in findlinestarts(code)} + linenumbers2 = {lineno for (index, lineno) in findlinestarts(execcode)} if linenumbers1 != linenumbers2: raise SyntaxError("doctest is not a single statement") @@ -719,6 +725,7 @@ def compiler(example): gc.disable() from cysignals.signals import SignalError + try: # Don't blink! This is where the user's code gets run. self.compile_and_execute(example, compiler, test.globs) @@ -733,7 +740,7 @@ def compiler(example): check_timer = Timer().start() got = self._fakeout.getvalue() - outcome = FAILURE # guilty until proved innocent or insane + outcome = FAILURE # guilty until proved innocent or insane probed_tags = getattr(example, 'probed_tags', False) @@ -742,11 +749,7 @@ def compiler(example): if exception is None: if check(example.want, got, self.optionflags): if probed_tags and probed_tags is not True: - example.warnings.append( - f"The tag '{unparse_optional_tags(probed_tags)}' " - f"may no longer be needed; these features are not present, " - f"but we ran the doctest anyway as requested by --probe, " - f"and it succeeded.") + example.warnings.append(f"The tag '{unparse_optional_tags(probed_tags)}' " f"may no longer be needed; these features are not present, " f"but we ran the doctest anyway as requested by --probe, " f"and it succeeded.") outcome = SUCCESS # The example raised an exception: check if it was expected. @@ -763,13 +766,11 @@ def compiler(example): exc_cls = exception[0] exc_name = exc_cls.__name__ if exc_cls.__module__: - exc_fullname = (exc_cls.__module__ + '.' + - exc_cls.__qualname__) + exc_fullname = exc_cls.__module__ + '.' + exc_cls.__qualname__ else: exc_fullname = exc_cls.__qualname__ - if (example.exc_msg.startswith(exc_name) and - exc_msg.startswith(exc_fullname)): + if example.exc_msg.startswith(exc_name) and exc_msg.startswith(exc_fullname): exc_msg = exc_msg.replace(exc_fullname, exc_name, 1) if not quiet: @@ -783,25 +784,16 @@ def compiler(example): # We expected an exception: see whether it matches. elif check(example.exc_msg, exc_msg, self.optionflags): if probed_tags and probed_tags is not True: - example.warnings.append( - f"The tag '{unparse_optional_tags(example.probed_tags)}' " - f"may no longer be needed; these features are not present, " - f"but we ran the doctest anyway as requested by --probe, " - f"and it succeeded (raised the expected exception).") + example.warnings.append(f"The tag '{unparse_optional_tags(example.probed_tags)}' " f"may no longer be needed; these features are not present, " f"but we ran the doctest anyway as requested by --probe, " f"and it succeeded (raised the expected exception).") outcome = SUCCESS # Another chance if they didn't care about the detail. elif self.optionflags & doctest.IGNORE_EXCEPTION_DETAIL: m1 = re.match(r'(?:[^:]*\.)?([^:]*:)', example.exc_msg) m2 = re.match(r'(?:[^:]*\.)?([^:]*:)', exc_msg) - if m1 and m2 and check(m1.group(1), m2.group(1), - self.optionflags): + if m1 and m2 and check(m1.group(1), m2.group(1), self.optionflags): if probed_tags and probed_tags is not True: - example.warnings.append( - f"The tag '{unparse_optional_tags(example.probed_tags)}' " - f"may no longer be needed; these features are not present, " - f"but we ran the doctest anyway as requested by --probe, " - f"and it succeeded (raised an exception as expected).") + example.warnings.append(f"The tag '{unparse_optional_tags(example.probed_tags)}' " f"may no longer be needed; these features are not present, " f"but we ran the doctest anyway as requested by --probe, " f"and it succeeded (raised an exception as expected).") outcome = SUCCESS check_timer.stop() @@ -813,13 +805,11 @@ def compiler(example): out(self._failure_header(test, example, f'Warning: {warning}')) if outcome is SUCCESS: if self.options.warn_long > 0 and example.cputime + check_timer.cputime > self.options.warn_long: - self.report_overtime(out, test, example, got, - check_timer=check_timer) + self.report_overtime(out, test, example, got, check_timer=check_timer) elif example.warnings: pass elif not quiet: - self.report_success(out, test, example, got, - check_timer=check_timer) + self.report_success(out, test, example, got, check_timer=check_timer) elif probed_tags: pass elif outcome is FAILURE: @@ -828,8 +818,7 @@ def compiler(example): failures += 1 elif outcome is BOOM: if not quiet: - self.report_unexpected_exception(out, test, example, - exception) + self.report_unexpected_exception(out, test, example, exception) failures += 1 else: assert False, ("unknown outcome", outcome) @@ -838,7 +827,7 @@ def compiler(example): self.optionflags = original_optionflags # Record and return the number of failures and tries. - if sys.version_info < (3,13): + if sys.version_info < (3, 13): self._DocTestRunner__record_outcome(test, failures, tries) else: self._DocTestRunner__record_outcome(test, failures, tries, walltime_skips) @@ -905,6 +894,7 @@ def run(self, test, compileflags=0, out=None, clear_globs=True): self.save_linecache_getlines = linecache.getlines linecache.getlines = self._DocTestRunner__patched_linecache_getlines if out is None: + def out(s): self.msgfile.write(s) self.msgfile.flush() @@ -1144,7 +1134,7 @@ def compile_and_execute(self, example, compiler, globs): timer = Timer().start() try: compiled = compiler(example) - timer.start() # reset timer + timer.start() # reset timer exec(compiled, globs) finally: timer.stop().annotate(example) @@ -1165,12 +1155,8 @@ def compile_and_execute(self, example, compiler, globs): # and also do not issue the "may no longer be needed" notice example.probed_tags = True else: - f_setter_optional_tags = "; ".join("'" - + unparse_optional_tags(setter_optional_tags) - + "'" - for setter_optional_tags in setters_dict) - example.warnings.append(f"Variable '{name}' referenced here " - f"was set only in doctest marked {f_setter_optional_tags}") + f_setter_optional_tags = "; ".join("'" + unparse_optional_tags(setter_optional_tags) + "'" for setter_optional_tags in setters_dict) + example.warnings.append(f"Variable '{name}' referenced here " f"was set only in doctest marked {f_setter_optional_tags}") for name in globs.set: self.setters[name][example.optional_tags] = example else: @@ -1258,8 +1244,7 @@ def _failure_header(self, test, example, message='Failed example:', extra=None): lineno = test.lineno + example.lineno + 1 else: lineno = '?' - out.append('File "%s", line %s, in %s' % - (test.filename, lineno, test.name)) + out.append('File "%s", line %s, in %s' % (test.filename, lineno, test.name)) else: out.append('Line %s, in %s' % (example.lineno + 1, test.name)) out.append(message) @@ -1267,7 +1252,7 @@ def _failure_header(self, test, example, message='Failed example:', extra=None): # https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#using-workflow-commands-to-access-toolkit-functions if message.startswith('Warning: '): command = f'::warning title={message}' - message = message[len('Warning: '):] + message = message[len('Warning: ') :] elif self.baseline.get('failed', False): command = f'::notice title={message}' message += ' [failed in baseline]' @@ -1343,8 +1328,7 @@ def report_start(self, out, test, example): # We completely replace doctest.DocTestRunner.report_start so that we can include line numbers with OriginalSource(example): if self._verbose: - start_txt = ('Trying (line %s):' % (test.lineno + example.lineno + 1) - + doctest._indent(example.source)) + start_txt = 'Trying (line %s):' % (test.lineno + example.lineno + 1) + doctest._indent(example.source) if example.want: start_txt += 'Expecting:\n' + doctest._indent(example.want) else: @@ -1397,8 +1381,7 @@ def report_success(self, out, test, example, got, *, check_timer=None): # We completely replace doctest.DocTestRunner.report_success # so that we can include time taken for the test if self._verbose: - out("ok [%.2fs wall]\n" % - (example.walltime + check_timer.walltime)) + out("ok [%.2fs wall]\n" % (example.walltime + check_timer.walltime)) def report_failure(self, out, test, example, got, globs): r""" @@ -1506,6 +1489,7 @@ def report_failure(self, out, test, example, got, globs): from IPython.terminal.embed import InteractiveShellEmbed from sage.repl.configuration import sage_ipython_config + cfg = sage_ipython_config.default() cfg.InteractiveShell.enable_tip = False # Currently this doesn't work: prompts only work in pty @@ -1577,11 +1561,7 @@ def report_overtime(self, out, test, example, got, *, check_timer=None): Test ran for 1.23s cpu, 2.50s wall Check ran for 2.34s cpu, 3.12s wall """ - time_info = ('Test ran for %.2fs cpu, %.2fs wall\nCheck ran for %.2fs cpu, %.2fs wall\n' - % (example.cputime, - example.walltime, - check_timer.cputime, - check_timer.walltime)) + time_info = 'Test ran for %.2fs cpu, %.2fs wall\nCheck ran for %.2fs cpu, %.2fs wall\n' % (example.cputime, example.walltime, check_timer.cputime, check_timer.walltime) out(self._failure_header(test, example, 'Warning: slow doctest:', time_info) + time_info) def report_unexpected_exception(self, out, test, example, exc_info): @@ -1652,10 +1632,7 @@ def report_unexpected_exception(self, out, test, example, exc_info): exc_type, exc_val, exc_tb = exc_info if exc_tb is None: - raise RuntimeError( - "could not start the debugger for an unexpected " - "exception, probably due to an unhandled error " - "in a C extension module") + raise RuntimeError("could not start the debugger for an unexpected " "exception, probably due to an unhandled error " "in a C extension module") self.debugger.reset() self.debugger.interaction(None, exc_tb) except KeyboardInterrupt: @@ -1743,6 +1720,7 @@ class DocTestDispatcher(SageObject): Create parallel :class:`DocTestWorker` processes and dispatches doctesting tasks. """ + def __init__(self, controller: DocTestController): """ INPUT: @@ -1795,9 +1773,7 @@ def serial_dispatch(self): self.controller.log(heading) with tempfile.TemporaryFile() as outtmpfile: - result = DocTestTask(source)(self.controller.options, - outtmpfile, self.controller.logger, - baseline=baseline) + result = DocTestTask(source)(self.controller.options, outtmpfile, self.controller.logger, baseline=baseline) outtmpfile.seek(0) output = bytes_to_str(outtmpfile.read()) @@ -1934,6 +1910,7 @@ def parallel_dispatch(self): log = self.controller.log from cysignals.pselect import PSelecter + try: # Block SIGCHLD and SIGINT except during the pselect() call with PSelecter([signal.SIGCHLD, signal.SIGINT]) as sel: @@ -2022,14 +1999,7 @@ def sel_exit(): # Report the completion of this worker log(w.messages, end="") - self.controller.reporter.report( - w.source, - w.killed, - w.copied_exitcode, - w.result, - w.output, - pid=w.copied_pid, - process_tree_before_kill=w.process_tree_before_kill) + self.controller.reporter.report(w.source, w.killed, w.copied_exitcode, w.result, w.output, pid=w.copied_pid, process_tree_before_kill=w.process_tree_before_kill) pending_tests -= 1 @@ -2042,8 +2012,7 @@ def sel_exit(): break # Start new workers if possible - while (source_iter is not None and len(workers) < opt.nthreads - and (not job_client or job_client.acquire())): + while source_iter is not None and len(workers) < opt.nthreads and (not job_client or job_client.acquire()): try: source = next(source_iter) except StopIteration: @@ -2053,6 +2022,7 @@ def sel_exit(): else: # Start a new worker. import copy + worker_options = copy.copy(opt) baseline = self.controller.source_baseline(source) if target_endtime is not None: @@ -2123,6 +2093,7 @@ def sel_exit(): with PSelecter([signal.SIGQUIT, signal.SIGINT]): try: from time import sleep + sleep(die_timeout) for w in workers: w.kill() @@ -2217,6 +2188,7 @@ class should be accessed by the child process. sage: reporter.report(FDS, False, W.exitcode, result, "") [... tests, ...s wall] """ + def __init__(self, source, options, funclist=[], baseline=None): """ Initialization. @@ -2314,8 +2286,7 @@ def run(self): os.close(self.rmessages) msgpipe = os.fdopen(self.wmessages, "w") try: - task(self.options, self.outtmpfile, msgpipe, self.result_queue, - baseline=self.baseline) + task(self.options, self.outtmpfile, msgpipe, self.result_queue, baseline=self.baseline) finally: msgpipe.close() self.outtmpfile.close() @@ -2495,15 +2466,12 @@ def kill(self): """ try: import subprocess - self.process_tree_before_kill = subprocess.run(["ps", "-ef", "--cols", "1000", "--forest"], - stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, - text=True, errors="ignore").stdout + + self.process_tree_before_kill = subprocess.run(["ps", "-ef", "--cols", "1000", "--forest"], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True, errors="ignore").stdout except FileNotFoundError: # ps not available? Unlikely pass except subprocess.CalledProcessError: - self.process_tree_before_kill = subprocess.run(["ps", "-efwww"], - stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, - text=True, errors="ignore").stdout + self.process_tree_before_kill = subprocess.run(["ps", "-efwww"], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True, errors="ignore").stdout if self.rmessages is not None: os.close(self.rmessages) @@ -2576,8 +2544,7 @@ def __init__(self, source): """ self.source = source - def __call__(self, options, outtmpfile=None, msgfile=None, result_queue=None, *, - baseline=None): + def __call__(self, options, outtmpfile=None, msgfile=None, result_queue=None, *, baseline=None): """ Calling the task does the actual work of running the doctests. @@ -2624,19 +2591,11 @@ def __call__(self, options, outtmpfile=None, msgfile=None, result_queue=None, *, """ result = None try: - runner = SageDocTestRunner( - SageOutputChecker(), - verbose=options.verbose, - outtmpfile=outtmpfile, - msgfile=msgfile, - sage_options=options, - optionflags=doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS, - baseline=baseline) + runner = SageDocTestRunner(SageOutputChecker(), verbose=options.verbose, outtmpfile=outtmpfile, msgfile=msgfile, sage_options=options, optionflags=doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS, baseline=baseline) runner.basename = self.source.basename runner.filename = self.source.path N = options.file_iterations - results = DictAsObject({'walltime': [], 'cputime': [], - 'err': None, 'walltime_skips': 0}) + results = DictAsObject({'walltime': [], 'cputime': [], 'err': None, 'walltime_skips': 0}) # multiprocessing.Process instances don't run exit # functions, so we run the functions added by doctests @@ -2655,8 +2614,7 @@ def __call__(self, options, outtmpfile=None, msgfile=None, result_queue=None, *, results.err = 'line_number' results.optionals = extras['optionals'] # We subtract 1 to remove the sig_on_count() tests - result = (sum(max(0, len(test.examples) - 1) for test in doctests), - results) + result = (sum(max(0, len(test.examples) - 1) for test in doctests), results) except BaseException: exc_info = sys.exc_info() @@ -2675,12 +2633,14 @@ def _run(self, runner, options, results): # Import Jupyter globals to doctest the Jupyter # implementation of widgets and interacts from importlib import import_module + sage_all = import_module(options.environment) dict_all = sage_all.__dict__ # When using global environments other than sage.all, # make sure startup is finished so we don't get "Resolving lazy import" # warnings. from sage.misc.lazy_import import ensure_startup_finished + ensure_startup_finished() # Remove '__package__' item from the globals since it is not # always in the globals in an actual Sage session. diff --git a/src/sage/doctest/marked_output.py b/src/sage/doctest/marked_output.py index 06b22f9cee2..933f17a618c 100644 --- a/src/sage/doctest/marked_output.py +++ b/src/sage/doctest/marked_output.py @@ -43,6 +43,7 @@ class MarkedOutput(str): sage: MarkedOutput("56 µs") '56 \xb5s' """ + random = False rel_tol = 0 abs_tol = 0 diff --git a/src/sage/doctest/parsing.py b/src/sage/doctest/parsing.py index b5bd7970a25..17ba3876437 100644 --- a/src/sage/doctest/parsing.py +++ b/src/sage/doctest/parsing.py @@ -54,30 +54,20 @@ from sage.repl.preparse import preparse, strip_string_literals # This is the correct pattern to match ISO/IEC 6429 ANSI escape sequences: -ansi_escape_sequence: Pattern[str] = re.compile( - r"(\x1b[@-Z\\-~]|\x1b\[.*?[@-~]|\x9b.*?[@-~])" -) +ansi_escape_sequence: Pattern[str] = re.compile(r"(\x1b[@-Z\\-~]|\x1b\[.*?[@-~]|\x9b.*?[@-~])") -special_optional_regex_raw = ( - "py2|long time|not implemented|not tested|optional|needs|known bug" -) +special_optional_regex_raw = "py2|long time|not implemented|not tested|optional|needs|known bug" tag_with_explanation_regex_raw = r"((?:!?\w|[.])*)\s*(?:\((?P.*?)\))?" optional_regex: Pattern[str] = re.compile( rf"[^ a-z]\s*(?P{special_optional_regex_raw})(?:\s|[:-])*(?P(?:(?:{tag_with_explanation_regex_raw})\s*)*)", re.IGNORECASE, ) -special_optional_regex: Pattern[str] = re.compile( - special_optional_regex_raw, re.IGNORECASE -) -tag_with_explanation_regex: Pattern[str] = re.compile( - tag_with_explanation_regex_raw, re.IGNORECASE -) +special_optional_regex: Pattern[str] = re.compile(special_optional_regex_raw, re.IGNORECASE) +tag_with_explanation_regex: Pattern[str] = re.compile(tag_with_explanation_regex_raw, re.IGNORECASE) no_doctest_regex: Pattern[str] = re.compile(r'\s*(#+|%+|r"+|"+|\.\.)\s*nodoctest') optional_tag_regex: Pattern[str] = re.compile(r"^(\w|[.])+$") -optional_file_directive_regex: Pattern[str] = re.compile( - r'\s*(#+|%+|r"+|"+|\.\.)\s*sage\.doctest: (.*)' -) +optional_file_directive_regex: Pattern[str] = re.compile(r'\s*(#+|%+|r"+|"+|\.\.)\s*sage\.doctest: (.*)') @overload @@ -86,15 +76,11 @@ def parse_optional_tags(string: str) -> dict[str, Union[str, None]]: @overload -def parse_optional_tags( - string: str, *, return_string_sans_tags: Literal[True] -) -> tuple[dict[str, Union[str, None]], str, bool]: +def parse_optional_tags(string: str, *, return_string_sans_tags: Literal[True]) -> tuple[dict[str, Union[str, None]], str, bool]: pass -def parse_optional_tags( - string: str, *, return_string_sans_tags: bool = False -) -> Union[tuple[dict[str, Union[str, None]], str, bool], dict[str, Union[str, None]]]: +def parse_optional_tags(string: str, *, return_string_sans_tags: bool = False) -> Union[tuple[dict[str, Union[str, None]], str, bool], dict[str, Union[str, None]]]: r""" Return a dictionary whose keys are optional tags from the following set that occur in a comment on the first line of the input string. @@ -182,7 +168,7 @@ def parse_optional_tags( first_line, rest = split[0], None sharp_index = first_line.find('#') - if sharp_index < 0: # no comment + if sharp_index < 0: # no comment if return_string_sans_tags: return {}, string, False return {} @@ -195,7 +181,7 @@ def parse_optional_tags( if return_string_sans_tags: # skip non-tag comments that precede the first tag comment if m := optional_regex.search(comment): - sharp_index = comment[:m.start(0) + 1].rfind('#') + sharp_index = comment[: m.start(0) + 1].rfind('#') if sharp_index >= 0: first_line = first_line_sans_comments + comment[:sharp_index] comment = comment[sharp_index:] @@ -222,17 +208,13 @@ def parse_optional_tags( tags[cmd] = m.group("cmd_explanation") or None else: # other tags with additional values - tags_with_value = { - m.group(1).lower().strip(): m.group(2) or None - for m in tag_with_explanation_regex.finditer(m.group("tags")) - } + tags_with_value = {m.group(1).lower().strip(): m.group(2) or None for m in tag_with_explanation_regex.finditer(m.group("tags"))} tags_with_value.pop("", None) tags.update(tags_with_value) if return_string_sans_tags: is_persistent = tags and first_line_sans_comments.strip() == 'sage:' and not rest # persistent (block-scoped) tag - return tags, (first_line + '\n' + rest % literals if rest is not None - else first_line), is_persistent + return tags, (first_line + '\n' + rest % literals if rest is not None else first_line), is_persistent return tags @@ -290,8 +272,8 @@ def _standard_tags() -> frozenset[str]: [..., 'numpy', ..., 'sage.rings.finite_rings', ...] """ from sage.features.all import all_features - return frozenset(feature.name for feature in all_features() - if feature._spkg_type() == 'standard') + + return frozenset(feature.name for feature in all_features() if feature._spkg_type() == 'standard') def _tag_group(tag): @@ -367,8 +349,7 @@ def unparse_optional_tags(tags, prefix='# ') -> str: if 'optional' in group: tags.append('optional - ' + " ".join(sorted(group.pop('optional')))) if 'standard' in group or 'sage' in group: - tags.append('needs ' + " ".join(sorted(group.pop('standard', [])) - + sorted(group.pop('sage', [])))) + tags.append('needs ' + " ".join(sorted(group.pop('standard', [])) + sorted(group.pop('sage', [])))) assert not group if tags: return prefix + ', '.join(tags) @@ -492,10 +473,7 @@ def update_optional_tags(line, tags=None, *, add_tags=None, remove_tags=None, fo if not new_tags: return line_sans_tags.rstrip() - if (force_rewrite == 'standard' - and new_tags == current_tags - and not any(_tag_group(tag) in ['standard', 'sage'] - for tag in new_tags)): + if force_rewrite == 'standard' and new_tags == current_tags and not any(_tag_group(tag) in ['standard', 'sage'] for tag in new_tags): return line if is_persistent: @@ -504,8 +482,7 @@ def update_optional_tags(line, tags=None, *, add_tags=None, remove_tags=None, fo group = defaultdict(set) for tag in new_tags: group[_tag_group(tag)].add(tag) - tag_columns = (optional_tag_columns if group['optional'] or group['special'] - else standard_tag_columns) + tag_columns = optional_tag_columns if group['optional'] or group['special'] else standard_tag_columns if len(line_sans_tags) in tag_columns and line_sans_tags[-2:] == ' ': # keep alignment @@ -522,18 +499,12 @@ def update_optional_tags(line, tags=None, *, add_tags=None, remove_tags=None, fo if (group['optional'] or group['special']) and (group['standard'] or group['sage']): # Try if two-column mode works better - first_part = unparse_optional_tags({tag: explanation - for tag, explanation in new_tags.items() - if (tag in group['optional'] - or tag in group['special'])}) + first_part = unparse_optional_tags({tag: explanation for tag, explanation in new_tags.items() if (tag in group['optional'] or tag in group['special'])}) column = standard_tag_columns[0] if len(line + first_part) + 8 <= column: line += first_part line += ' ' * (column - len(line)) - line += unparse_optional_tags({tag: explanation - for tag, explanation in new_tags.items() - if not (tag in group['optional'] - or tag in group['special'])}) + line += unparse_optional_tags({tag: explanation for tag, explanation in new_tags.items() if not (tag in group['optional'] or tag in group['special'])}) return line.rstrip() line += unparse_optional_tags(new_tags) @@ -575,8 +546,8 @@ def parse_tolerance(source, want): first_line = safe.split('\n', 1)[0] if '#' not in first_line: return want - comment = first_line[first_line.find('#') + 1:] - comment = comment[comment.index('(') + 1: comment.rindex(')')] + comment = first_line[first_line.find('#') + 1 :] + comment = comment[comment.index('(') + 1 : comment.rindex(')')] # strip_string_literals replaces comments comment = literals[comment] if random_marker.search(comment): @@ -650,6 +621,7 @@ def reduce_hex(fingerprints): '0000000000000000000000012399a463' """ from operator import xor + res = reduce(xor, (int(x, 16) for x in fingerprints), 0) if res < 0: res += 1 << 128 @@ -678,6 +650,7 @@ class OriginalSource: ....: ex.source 'doctest_var = 42; doctest_var^2\n' """ + def __init__(self, example): """ Swaps out the source for the sage_source of a doctest example. @@ -1028,8 +1001,7 @@ def update_tag_counts(optional_tags): def check_and_clear_tag_counts(): if (num_examples := tag_count_within_block['']) >= 4: - if overused_tags := {tag for tag, count in tag_count_within_block.items() - if tag and count >= num_examples}: + if overused_tags := {tag for tag, count in tag_count_within_block.items() if tag and count >= num_examples}: overused_tags.update(persistent_optional_tags) overused_tags.difference_update(self.file_optional_tags) suggested = unparse_optional_tags(overused_tags, prefix='sage: # ') @@ -1037,14 +1009,11 @@ def check_and_clear_tag_counts(): if persistent_optional_tag_setter: warning_example = persistent_optional_tag_setter index = persistent_optional_tag_setter_index - warning = (f"Consider updating this block-scoped tag to '{suggested}' " - f"to avoid repeating the tag {num_examples} times") + warning = f"Consider updating this block-scoped tag to '{suggested}' " f"to avoid repeating the tag {num_examples} times" else: warning_example = first_example_in_block index = first_example_in_block_index - warning = (f"Consider using a block-scoped tag by " - f"inserting the line '{suggested}' just before this line " - f"to avoid repeating the tag {num_examples} times") + warning = f"Consider using a block-scoped tag by " f"inserting the line '{suggested}' just before this line " f"to avoid repeating the tag {num_examples} times" if not (index < len(filtered) and filtered[index] == warning_example): # The example to which we want to attach our warning is @@ -1087,8 +1056,7 @@ def check_and_clear_tag_counts(): if optional_tags: for tag in optional_tags: self.optionals[tag] += 1 - if (('not implemented' in optional_tags) or - ('not tested' in optional_tags)): + if ('not implemented' in optional_tags) or ('not tested' in optional_tags): continue if 'long time' in optional_tags: @@ -1110,9 +1078,7 @@ def check_and_clear_tag_counts(): # Bug only occurs on a specific platform? bug_platform = optional_tags_with_values.get("bug") # System platform as either linux or macos - system_platform = ( - platform.system().lower().replace("darwin", "macos") - ) + system_platform = platform.system().lower().replace("darwin", "macos") if not bug_platform or bug_platform == system_platform: continue elif extra: @@ -1193,6 +1159,7 @@ class SageOutputChecker(doctest.OutputChecker): sage: OC.check_output(ex.want, 'x + 0.8935153492877', optflag) False """ + def human_readable_escape_sequences(self, string): r""" Make ANSI escape sequences human readable. @@ -1213,12 +1180,14 @@ def human_readable_escape_sequences(self, string): sage: OC.human_readable_escape_sequences(teststr) 'bold-red-oscmd' """ + def human_readable(match): ansi_escape = match.group(1) assert len(ansi_escape) >= 2 if len(ansi_escape) == 2: return '' return '' + return ansi_escape_sequence.subn(human_readable, string)[0] def check_output(self, want, got, optionflags): @@ -1658,10 +1627,7 @@ def output_difference(self, example, got, optionflags): failures = [] def fail(x, y, actual, desired): - failstr = " {} vs {}, tolerance {} > {}".format(x, y, - RIFtol(actual).upper().str(digits=1, no_sci=False), - RIFtol(desired).center().str(digits=15, skip_zeroes=True, no_sci=False) - ) + failstr = " {} vs {}, tolerance {} > {}".format(x, y, RIFtol(actual).upper().str(digits=1, no_sci=False), RIFtol(desired).center().str(digits=15, skip_zeroes=True, no_sci=False)) failures.append(failstr) for wstr, gstr in zip(want_str, got_str): diff --git a/src/sage/doctest/reporting.py b/src/sage/doctest/reporting.py index e4b5ac86ec2..4e9e348dbf1 100644 --- a/src/sage/doctest/reporting.py +++ b/src/sage/doctest/reporting.py @@ -101,6 +101,7 @@ class DocTestReporter(SageObject): """ This class reports to the users on the results of doctests. """ + def __init__(self, controller): """ Initialize the reporter. @@ -531,7 +532,7 @@ def report(self, source, timeout, return_code, results, output, pid=None, *, pro postscript['lines'].append(self.report_head(source, fail_msg)) stats[basename] = {"failed": True, "walltime": 1e6, "ntests": ntests} if not baseline.get('failed', False): - self.error_status |= (8 if return_code > 0 else 16) + self.error_status |= 8 if return_code > 0 else 16 else: if hasattr(result_dict, 'walltime') and hasattr(result_dict.walltime, '__len__') and len(result_dict.walltime) > 0: wall = sum(result_dict.walltime) / len(result_dict.walltime) @@ -639,7 +640,7 @@ def report(self, source, timeout, return_code, results, output, pid=None, *, pro # tests multiple times, and some other unclear mangling # of these numbers that was not clear to the author. ntests_run = result_dict.tests - total = "%d%% of tests run" % (round(100*ntests_run/float(ntests_run + nskipped))) + total = "%d%% of tests run" % (round(100 * ntests_run / float(ntests_run + nskipped))) else: total = count_noun(ntests, "test") if not (self.controller.options.only_errors and not f): @@ -649,6 +650,7 @@ def report(self, source, timeout, return_code, results, output, pid=None, *, pro except Exception: import traceback + log(traceback.format_exc(), end="") def finalize(self): diff --git a/src/sage/doctest/sources.py b/src/sage/doctest/sources.py index 205a096f8a6..e3c7ee225ba 100644 --- a/src/sage/doctest/sources.py +++ b/src/sage/doctest/sources.py @@ -115,13 +115,13 @@ def get_basename(path): return path root = path[:i] elif path.startswith(sp): - root = path[:len(sp)] + root = path[: len(sp)] else: # If this file is in some python package we can see how deep # it goes. while is_package_or_sage_namespace_package_dir(root): root = os.path.dirname(root) - fully_qualified_path, ext = os.path.splitext(path[len(root) + 1:]) + fully_qualified_path, ext = os.path.splitext(path[len(root) + 1 :]) if os.path.split(path)[1] == '__init__.py': fully_qualified_path = fully_qualified_path[:-9] basename = fully_qualified_path.replace(os.path.sep, '.') @@ -140,6 +140,7 @@ class DocTestSource: - ``options`` -- a :class:`sage.doctest.control.DocTestDefaults` instance or equivalent """ + def __init__(self, options): """ Initialization. @@ -234,8 +235,7 @@ def _process_doc(self, doctests: list[doctest.DocTest], doc, namespace, start): new_doctests = self.parse_docstring(docstring, namespace, start) sig_on_count_doc_doctest = "sig_on_count() # check sig_on/off pairings (virtual doctest)\n" for dt in new_doctests: - if len(dt.examples) > 0 and not (hasattr(dt.examples[-1], 'sage_source') - and dt.examples[-1].sage_source == sig_on_count_doc_doctest): + if len(dt.examples) > 0 and not (hasattr(dt.examples[-1], 'sage_source') and dt.examples[-1].sage_source == sig_on_count_doc_doctest): # Line number refers to the end of the docstring sigon = doctest.Example(sig_on_count_doc_doctest, "0\n", lineno=docstring.count("\n")) sigon.sage_source = sig_on_count_doc_doctest @@ -307,10 +307,7 @@ def _create_doctests(self, namespace, tab_okay=None) -> tuple[list[doctest.DocTe tab_okay = isinstance(self, TexSource) self._init() self.line_shift = 0 - self.parser = SageDocTestParser(self.options.optional, - self.options.long, - probed_tags=self.options.probe, - file_optional_tags=self.file_optional_tags) + self.parser = SageDocTestParser(self.options.optional, self.options.long, probed_tags=self.options.probe, file_optional_tags=self.file_optional_tags) self.linking = False doctests: list[doctest.DocTest] = [] in_docstring = False @@ -323,7 +320,7 @@ def _create_doctests(self, namespace, tab_okay=None) -> tuple[list[doctest.DocTe if doctest_line_number.search(line) is not None: contains_line_number = True if "\t" in line: - tab_locations.append(str(lineno+1)) + tab_locations.append(str(lineno + 1)) if "SAGE_DOCTEST_ALLOW_TABS" in line: tab_okay = True just_finished = False @@ -337,8 +334,7 @@ def _create_doctests(self, namespace, tab_okay=None) -> tuple[list[doctest.DocTe if self.line_shift and (m := sagestart.match(line)): # We insert empty doctest lines to make up for the removed lines indent_and_prompt = m.group(1) - doc.extend([indent_and_prompt + "# inserted to compensate for removed conditional doctest output\n"] - * self.line_shift) + doc.extend([indent_and_prompt + "# inserted to compensate for removed conditional doctest output\n"] * self.line_shift) self.line_shift = 0 doc.append(line) unparsed_doc = True @@ -365,9 +361,7 @@ def _create_doctests(self, namespace, tab_okay=None) -> tuple[list[doctest.DocTe if unparsed_doc: self._process_doc(doctests, doc, namespace, start) - extras = {"tab": not tab_okay and tab_locations, - "line_number": contains_line_number, - "optionals": self.parser.optionals} + extras = {"tab": not tab_okay and tab_locations, "line_number": contains_line_number, "optionals": self.parser.optionals} if self.options.randorder is not None and self.options.randorder is not False: # we want to randomize even when self.randorder = 0 random.seed(self.options.randorder) @@ -428,6 +422,7 @@ class StringDocTestSource(DocTestSource): sage: extras['line_number'] True """ + def __init__(self, basename, source, options, printpath, lineno_shift=0): r""" Initialization. @@ -538,6 +533,7 @@ class FileDocTestSource(DocTestSource): ValueError: unknown extension for the file to test (=...txtt), valid extensions are: .py, .pyx, .pxd, .pxi, .sage, .spyx, .tex, .rst, .rst.txt """ + def __init__(self, path, options): """ Initialization. @@ -569,8 +565,7 @@ def __init__(self, path, options): self.encoding = "utf-8" else: valid_ext = ", ".join(valid_code_ext + ('.tex', '.rst', '.rst.txt')) - raise ValueError("unknown extension for the file to test (={})," - " valid extensions are: {}".format(path, valid_ext)) + raise ValueError("unknown extension for the file to test (={})," " valid extensions are: {}".format(path, valid_ext)) def __iter__(self): r""" @@ -706,8 +701,7 @@ def in_lib(self): sage: FDS.in_lib True """ - return (self.options.force_lib - or is_package_or_sage_namespace_package_dir(os.path.dirname(self.path))) + return self.options.force_lib or is_package_or_sage_namespace_package_dir(os.path.dirname(self.path)) @lazy_attribute def file_optional_tags(self): @@ -724,6 +718,7 @@ def file_optional_tags(self): {'sage.modules': None} """ from .parsing import parse_file_optional_tags + return parse_file_optional_tags(self) def create_doctests(self, namespace) -> tuple[list[doctest.DocTest], dict]: @@ -767,6 +762,7 @@ def create_doctests(self, namespace) -> tuple[list[doctest.DocTest], dict]: """ if not os.path.exists(self.path): import errno + raise OSError(errno.ENOENT, "File does not exist", self.path) base, filename = os.path.split(self.path) _, ext = os.path.splitext(filename) @@ -775,7 +771,7 @@ def create_doctests(self, namespace) -> tuple[list[doctest.DocTest], dict]: if base: os.chdir(base) try: - load(filename, namespace) # errors raised here will be caught in DocTestTask + load(filename, namespace) # errors raised here will be caught in DocTestTask finally: os.chdir(cwd) self.qualified_name = NestedName(self.basename) @@ -849,12 +845,12 @@ def _test_enough_doctests(self, check_extras=True, verbose=True): starting_indent = whitespace.match(line).end() last_line = line if (not rest or in_block) and sagestart.match(line) and not ((rest and skipping) or untested.search(line.lower())): - expected.append(lineno+1) + expected.append(lineno + 1) actual = [] tests, _ = self.create_doctests({}) for dt in tests: if dt.examples: - for ex in dt.examples[:-1]: # the last entry is a sig_on_count() + for ex in dt.examples[:-1]: # the last entry is a sig_on_count() actual.append(dt.lineno + ex.lineno + 1) shortfall = sorted(set(expected).difference(set(actual))) extras = sorted(set(actual).difference(set(expected))) @@ -862,7 +858,7 @@ def _test_enough_doctests(self, check_extras=True, verbose=True): if not shortfall: return dif = extras[0] - shortfall[0] - for e, s in zip(extras[1:],shortfall[1:]): + for e, s in zip(extras[1:], shortfall[1:]): if dif != e - s: break else: @@ -887,6 +883,7 @@ class SourceLanguage: Currently supported languages include Python, ReST and LaTeX. """ + def parse_docstring(self, docstring, namespace, start) -> list[doctest.DocTest]: """ Return a list of doctest defined in this docstring. @@ -919,8 +916,7 @@ def parse_docstring(self, docstring, namespace, start) -> list[doctest.DocTest]: ....: dt.examples = dt.examples[:-1] # strip off the sig_on() test ....: assert(FDS.parse_docstring(dt.docstring,{},dt.lineno-1)[0] == dt) """ - return [self.parser.get_doctest(docstring, namespace, str(self.qualified_name), - self.printpath, start + 1)] + return [self.parser.get_doctest(docstring, namespace, str(self.qualified_name), self.printpath, start + 1)] class PythonSource(SourceLanguage): @@ -936,6 +932,7 @@ class PythonSource(SourceLanguage): sage: type(FDS) """ + # The same line can't both start and end a docstring start_finish_can_overlap = False @@ -1001,21 +998,23 @@ def _update_quotetype(self, line): sage: print(FDS.quotetype) None """ + def _update_parens(start, end=None): - self.paren_count += line.count("(",start,end) - line.count(")",start,end) - self.bracket_count += line.count("[",start,end) - line.count("]",start,end) - self.curly_count += line.count("{",start,end) - line.count("}",start,end) + self.paren_count += line.count("(", start, end) - line.count(")", start, end) + self.bracket_count += line.count("[", start, end) - line.count("]", start, end) + self.curly_count += line.count("{", start, end) - line.count("}", start, end) + pos = 0 while pos < len(line): if self.quotetype is None: - next_single = line.find("'",pos) - next_double = line.find('"',pos) + next_single = line.find("'", pos) + next_double = line.find('"', pos) if next_single == -1 and next_double == -1: - next_comment = line.find("#",pos) + next_comment = line.find("#", pos) if next_comment == -1: _update_parens(pos) else: - _update_parens(pos,next_comment) + _update_parens(pos, next_comment) break elif next_single == -1: m = next_double @@ -1023,22 +1022,22 @@ def _update_parens(start, end=None): m = next_single else: m = min(next_single, next_double) - next_comment = line.find('#',pos,m) + next_comment = line.find('#', pos, m) if next_comment != -1: - _update_parens(pos,next_comment) + _update_parens(pos, next_comment) break - _update_parens(pos,m) - if m+2 < len(line) and line[m] == line[m+1] == line[m+2]: - self.quotetype = line[m:m+3] - pos = m+3 + _update_parens(pos, m) + if m + 2 < len(line) and line[m] == line[m + 1] == line[m + 2]: + self.quotetype = line[m : m + 3] + pos = m + 3 else: self.quotetype = line[m] - pos = m+1 + pos = m + 1 else: - next = line.find(self.quotetype,pos) + next = line.find(self.quotetype, pos) if next == -1: break - elif next == 0 or line[next-1] != '\\': + elif next == 0 or line[next - 1] != '\\': pos = next + len(self.quotetype) self.quotetype = None else: @@ -1200,11 +1199,11 @@ def _neutralize_doctests(self, reindent): elif in_docstring: if self.ending_docstring(line): in_docstring = False - neutralized.append(" "*reindent + find_prompt.sub(r"\1safe:\3",line)) + neutralized.append(" " * reindent + find_prompt.sub(r"\1safe:\3", line)) else: if self.starting_docstring(line): in_docstring = True - neutralized.append(" "*reindent + line) + neutralized.append(" " * reindent + line) return "".join(neutralized) @@ -1222,6 +1221,7 @@ class TexSource(SourceLanguage): sage: type(FDS) """ + # The same line can't both start and end a docstring start_finish_can_overlap = False @@ -1397,6 +1397,7 @@ class RestSource(SourceLanguage): sage: type(FDS) """ + # The same line can both start and end a docstring start_finish_can_overlap = True @@ -1562,19 +1563,13 @@ def parse_docstring(self, docstring, namespace, start): test2() sig_on_count() # check sig_on/off pairings (virtual doctest) """ - PythonStringSource = dynamic_class("sage.doctest.sources.PythonStringSource", - (StringDocTestSource, PythonSource)) + PythonStringSource = dynamic_class("sage.doctest.sources.PythonStringSource", (StringDocTestSource, PythonSource)) min_indent = self.parser._min_indent(docstring) pysource = '\n'.join(l[min_indent:] for l in docstring.split('\n')) - inner_source = PythonStringSource(self.basename, pysource, - self.options, - self.printpath, - lineno_shift=start + 1) + inner_source = PythonStringSource(self.basename, pysource, self.options, self.printpath, lineno_shift=start + 1) inner_doctests, _ = inner_source._create_doctests(namespace, True) safe_docstring = inner_source._neutralize_doctests(min_indent) - outer_doctest = self.parser.get_doctest(safe_docstring, namespace, - str(self.qualified_name), - self.printpath, start + 1) + outer_doctest = self.parser.get_doctest(safe_docstring, namespace, str(self.qualified_name), self.printpath, start + 1) return [outer_doctest] + inner_doctests @@ -1589,6 +1584,7 @@ class DictAsObject(dict): sage: D.a 2 """ + def __init__(self, attrs): """ Initialization. diff --git a/src/sage/doctest/util.py b/src/sage/doctest/util.py index f6295a7098c..702bdc67b03 100644 --- a/src/sage/doctest/util.py +++ b/src/sage/doctest/util.py @@ -196,7 +196,7 @@ def _proc_stat_cpu_seconds(self, path): # documentation (Documentation/filesystems/proc.rst). The # intent is to sum the user- and kernel-mode "jiffies" for # both the given process and its children. - cputicks = sum( float(s) for s in stats[13:17] ) + cputicks = sum(float(s) for s in stats[13:17]) except (ArithmeticError, TypeError, ValueError) as e: # ArithmeticError: unexpected (non-numeric?) values in fields # TypeError/ValueError: fields can't be converted to float @@ -206,7 +206,7 @@ def _proc_stat_cpu_seconds(self, path): from os import sysconf hertz = sysconf("SC_CLK_TCK") - except (ValueError) as e: + except ValueError as e: # ValueError: SC_CLK_TCK doesn't exist raise OSError("SC_CLK_TCK sysconf not found") from e @@ -220,7 +220,7 @@ def _proc_stat_cpu_seconds(self, path): # about to divide by it. raise OSError("SC_CLK_TCK sysconf is nonpositive") - return (cputicks / hertz) + return cputicks / hertz def _quick_cputime(self, expect_objects): r""" @@ -283,7 +283,7 @@ def _quick_cputime(self, expect_objects): # Start by using os.times() to get the cputime for sage itself # and any subprocesses that have been wait()ed for and that # have terminated. - cputime = sum( times()[:4] ) + cputime = sum(times()[:4]) # Now try to get the times for any pexpect interfaces, since # they do not fall into the category above. @@ -304,9 +304,8 @@ def _quick_cputime(self, expect_objects): # needs it), but it isn't explicitly listed as # a dependency of sagelib. try: - from psutil import (NoSuchProcess, - Process, - ZombieProcess) + from psutil import NoSuchProcess, Process, ZombieProcess + try: cputime += sum(Process(S.pid()).cpu_times()[0:2]) except (ValueError, NoSuchProcess, ZombieProcess): @@ -332,6 +331,7 @@ def start(self): {'cputime': ..., 'walltime': ...} """ from sage.interfaces.quit import expect_objects + self.cputime = self._quick_cputime(expect_objects) self.walltime = walltime() return self @@ -351,6 +351,7 @@ def stop(self): {'cputime': ..., 'walltime': ...} """ from sage.interfaces.quit import expect_objects + self.cputime = self._quick_cputime(expect_objects) - self.cputime self.walltime = walltime() - self.walltime return self @@ -462,6 +463,7 @@ class RecordingDict(dict): sage: TestSuite(D).run() """ + def __init__(self, *args, **kwds): """ Initialization arguments are the same as for a normal dictionary. @@ -637,6 +639,7 @@ class NestedName: sage: TestSuite(qname).run() """ + def __init__(self, base): """ INPUT: @@ -677,7 +680,7 @@ def __setitem__(self, index, value): raise ValueError while len(self.all) <= index: self.all.append(None) - self.all[index+1:] = [value] + self.all[index + 1 :] = [value] def __str__(self): """ @@ -894,9 +897,7 @@ def ensure_interruptible_after(seconds: float, max_wait_after_interrupt: float = data["alarm_raised"] = alarm_raised if elapsed > seconds + max_wait_after_interrupt: - raise RuntimeError( - f"Function is not interruptible within {seconds:.4f} seconds, only after {elapsed:.4f} seconds" - + ("" if alarm_raised else " (__exit__ called before interrupt check)")) + raise RuntimeError(f"Function is not interruptible within {seconds:.4f} seconds, only after {elapsed:.4f} seconds" + ("" if alarm_raised else " (__exit__ called before interrupt check)")) if alarm_raised: if elapsed < seconds - inaccuracy_tolerance: diff --git a/src/sage/dynamics/all.py b/src/sage/dynamics/all.py index e5c553a3d54..8ea4ffc77f6 100644 --- a/src/sage/dynamics/all.py +++ b/src/sage/dynamics/all.py @@ -16,8 +16,10 @@ sage -pip install surface_dynamics --user """ + # install the docstring of this module to the containing package from sage.misc.namespace_package import install_doc + install_doc(__package__, __doc__) from sage.misc.lazy_import import lazy_import @@ -27,7 +29,6 @@ from sage.dynamics.cellular_automata.all import * # Discrete dynamical systems -lazy_import('sage.dynamics.finite_dynamical_system', - ['DiscreteDynamicalSystem']) +lazy_import('sage.dynamics.finite_dynamical_system', ['DiscreteDynamicalSystem']) lazy_import('sage.dynamics', 'finite_dynamical_system_catalog', 'finite_dynamical_systems') diff --git a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py index 37a55a63d50..ad775b9c430 100644 --- a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py @@ -60,8 +60,7 @@ class initialization directly. lazy_import('sage.symbolic.ring', 'SymbolicRing') -class DynamicalSystem_affine(SchemeMorphism_polynomial_affine_space, - DynamicalSystem): +class DynamicalSystem_affine(SchemeMorphism_polynomial_affine_space, DynamicalSystem): r""" An endomorphism of affine schemes determined by rational functions. @@ -525,6 +524,7 @@ def dynatomic_polynomial(self, period): (1/4*c + 1/4)*x^2 + (-c - 1/2)*x + c + 1 """ from sage.schemes.affine.affine_space import AffineSpace_generic + if not isinstance(self.domain(), AffineSpace_generic): raise NotImplementedError("not implemented for subschemes") if self.domain().dimension_relative() > 1: @@ -535,6 +535,7 @@ def dynatomic_polynomial(self, period): S = self.domain().coordinate_ring() if isinstance(F.parent(), SymbolicRing): from sage.symbolic.ring import var + u = var(self.domain().coordinate_ring().variable_name()) return F.subs({F.variables()[0]: u, F.variables()[1]: 1}) if T(F.denominator()).degree() == 0: @@ -885,8 +886,7 @@ def degree(self): return self.as_scheme_morphism().degree() -class DynamicalSystem_affine_field(DynamicalSystem_affine, - SchemeMorphism_polynomial_affine_space_field): +class DynamicalSystem_affine_field(DynamicalSystem_affine, SchemeMorphism_polynomial_affine_space_field): @cached_method def weil_restriction(self): r""" @@ -987,8 +987,7 @@ def reduce_base_field(self): return self.as_scheme_morphism().reduce_base_field().as_dynamical_system() -class DynamicalSystem_affine_finite_field(DynamicalSystem_affine_field, - SchemeMorphism_polynomial_affine_space_finite_field): +class DynamicalSystem_affine_finite_field(DynamicalSystem_affine_field, SchemeMorphism_polynomial_affine_space_finite_field): def orbit_structure(self, P): r""" @@ -1063,6 +1062,7 @@ def cyclegraph(self): V = [] E = [] from sage.schemes.affine.affine_space import AffineSpace_generic + if isinstance(self.domain(), AffineSpace_generic): for P in self.domain(): V.append(str(P)) @@ -1079,4 +1079,5 @@ def cyclegraph(self): except TypeError: # not on the scheme pass from sage.graphs.digraph import DiGraph + return DiGraph(dict(zip(V, E)), loops=True) diff --git a/src/sage/dynamics/arithmetic_dynamics/all.py b/src/sage/dynamics/arithmetic_dynamics/all.py index 66773e29d76..78ba78ccfc1 100644 --- a/src/sage/dynamics/arithmetic_dynamics/all.py +++ b/src/sage/dynamics/arithmetic_dynamics/all.py @@ -8,6 +8,7 @@ from sage.dynamics.arithmetic_dynamics.dynamical_semigroup import DynamicalSemigroup from sage.dynamics.arithmetic_dynamics.dynamical_semigroup import DynamicalSemigroup_affine from sage.dynamics.arithmetic_dynamics.dynamical_semigroup import DynamicalSemigroup_projective + lazy_import('sage.dynamics.arithmetic_dynamics.wehlerK3', 'WehlerK3Surface') lazy_import('sage.dynamics.arithmetic_dynamics.wehlerK3', 'random_WehlerK3Surface') del lazy_import diff --git a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py index e7bc69a0ab4..15296bde79a 100644 --- a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py @@ -35,9 +35,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.schemes.affine.affine_space import AffineSpace_generic -from sage.schemes.berkovich.berkovich_space import (Berkovich_Cp_Affine, - Berkovich_Cp_Projective, Berkovich_Cp, - Berkovich_Element_Cp_Affine) +from sage.schemes.berkovich.berkovich_space import Berkovich_Cp_Affine, Berkovich_Cp_Projective, Berkovich_Cp, Berkovich_Element_Cp_Affine from sage.schemes.projective.projective_space import ProjectiveSpace_ring from sage.structure.element import Element @@ -249,15 +247,13 @@ def __classcall_private__(cls, dynamical_system, domain=None, ideal=None): try: dynamical_system = DynamicalSystem_affine(dynamical_system) except (TypeError, ValueError): - raise TypeError('domain was affine Berkovich space, but dynamical_system did not ' - 'convert to an affine dynamical system') + raise TypeError('domain was affine Berkovich space, but dynamical_system did not ' 'convert to an affine dynamical system') if isinstance(domain, Berkovich_Cp_Projective): if not isinstance(dynamical_system, DynamicalSystem_projective): try: dynamical_system = DynamicalSystem_projective(dynamical_system) except (TypeError, ValueError): - raise TypeError('domain was projective Berkovich space, but dynamical_system did not convert ' - 'to a projective dynamical system') + raise TypeError('domain was projective Berkovich space, but dynamical_system did not convert ' 'to a projective dynamical system') if not isinstance(dynamical_system, DynamicalSystem): try: @@ -278,8 +274,7 @@ def __classcall_private__(cls, dynamical_system, domain=None, ideal=None): if ideal != domain.ideal(): raise ValueError('conflicting inputs for ideal and domain') else: - raise ValueError('base ring of domain of dynamical_system must be p-adic or a number field ' - 'not %s' % morphism_domain.base_ring()) + raise ValueError('base ring of domain of dynamical_system must be p-adic or a number field ' 'not %s' % morphism_domain.base_ring()) if isinstance(morphism_domain, AffineSpace_generic): return DynamicalSystem_Berkovich_affine(dynamical_system, domain) @@ -454,8 +449,7 @@ def _repr_(self): Defn: Defined on coordinates by sending (x : y) to\n ((3 + O(3^21))*x^2 : (2 + O(3^20))*y^2)' """ domain_str = self._domain._repr_() - return "Dynamical system of " + domain_str + " induced by the map" + \ - "\n Defn: %s" % ('\n '.join(self._system._repr_defn().split('\n'))) + return "Dynamical system of " + domain_str + " induced by the map" + "\n Defn: %s" % ('\n '.join(self._system._repr_defn().split('\n'))) class DynamicalSystem_Berkovich_projective(DynamicalSystem_Berkovich): @@ -510,6 +504,7 @@ class DynamicalSystem_Berkovich_projective(DynamicalSystem_Berkovich): induced by the map Defn: Defined on coordinates by sending (x : y) to (x^2 + y^2 : y^2) """ + @staticmethod def __classcall_private__(cls, dynamical_system, domain=None): """ @@ -537,14 +532,11 @@ def __classcall_private__(cls, dynamical_system, domain=None): raise ValueError('domain was not relative dimension 1') if not isinstance(R, pAdicBaseGeneric): if domain is None: - raise TypeError('dynamical system defined over %s, not p-adic, ' % morphism_domain.base_ring() + - 'and domain is None') + raise TypeError('dynamical system defined over %s, not p-adic, ' % morphism_domain.base_ring() + 'and domain is None') if not isinstance(domain, Berkovich_Cp_Projective): raise TypeError('domain was %s, not a projective Berkovich space over Cp' % domain) if domain.base() != morphism_domain: - raise ValueError('base of domain was %s, with coordinate ring %s ' % (domain.base(), - domain.base().coordinate_ring()) + 'while dynamical_system acts on %s, ' % morphism_domain + - 'with coordinate ring %s' % morphism_domain.coordinate_ring()) + raise ValueError('base of domain was %s, with coordinate ring %s ' % (domain.base(), domain.base().coordinate_ring()) + 'while dynamical_system acts on %s, ' % morphism_domain + 'with coordinate ring %s' % morphism_domain.coordinate_ring()) else: domain = Berkovich_Cp_Projective(morphism_domain) return typecall(cls, dynamical_system, domain) @@ -699,6 +691,7 @@ def conjugate(self, M, adjugate=False, new_ideal=None): if self.domain().is_padic_base(): return DynamicalSystem_Berkovich(self._system.conjugate(M, adjugate=adjugate)) from sage.rings.number_field.number_field_ideal import NumberFieldFractionalIdeal + if not (isinstance(new_ideal, NumberFieldFractionalIdeal) or new_ideal is None or new_ideal in ZZ): raise TypeError('new_ideal must be an ideal of a number field, not %s' % new_ideal) new_system = self._system.conjugate(M, adjugate=adjugate) @@ -836,8 +829,8 @@ def __call__(self, x, type_3_pole_check=True): ideal = self.domain().ideal() ring_of_integers = self.domain().base_ring().ring_of_integers() field = f.domain().base_ring() - M = Matrix([[field(x.prime()**(-1 * x.power())), x.center()[0]], [field(0), field(1)]]) - F = list(f*M) + M = Matrix([[field(x.prime() ** (-1 * x.power())), x.center()[0]], [field(0), field(1)]]) + F = list(f * M) R = field['z'] S = f.domain().coordinate_ring() z = R.gen(0) @@ -886,18 +879,18 @@ def __call__(self, x, type_3_pole_check=True): reduced_value = field(num * dem.inverse_of_unit()).lift_to_precision(field.precision_cap()) else: reduced_value = field(num * dem.inverse_of_unit()) - new_num = F[0]-reduced_value*F[1] + new_num = F[0] - reduced_value * F[1] if self.domain().is_padic_base(): power_of_p = min([i.valuation() for i in new_num]) else: power_of_p = min([i.valuation(ideal) for i in new_num]) - inverse_map = field(x.prime()**power_of_p) * z + reduced_value + inverse_map = field(x.prime() ** power_of_p) * z + reduced_value if self.domain().is_padic_base(): return self.domain()(inverse_map(0), (inverse_map(1) - inverse_map(0)).abs()) val = (inverse_map(1) - inverse_map(0)).valuation(ideal) if val == Infinity: return self.domain()(inverse_map(0), 0) - return self.domain()(inverse_map(0), x.prime()**(-1 * val)) + return self.domain()(inverse_map(0), x.prime() ** (-1 * val)) # point is now type III, so we compute using Proposition 7.6 [of Benedetto] affine_system = f.dehomogenize(1) dem = affine_system.defining_polynomials()[0].denominator().univariate_polynomial() @@ -930,7 +923,7 @@ def __call__(self, x, type_3_pole_check=True): if valuation == Infinity: no_poles = False break - elif x.prime()**(-1 * valuation/prime.absolute_ramification_index()) <= x.radius(): + elif x.prime() ** (-1 * valuation / prime.absolute_ramification_index()) <= x.radius(): no_poles = False break if not no_poles: @@ -942,13 +935,14 @@ def __call__(self, x, type_3_pole_check=True): a = x.center()[0] Taylor_expansion = [] from sage.arith.misc import factorial + for i in range(f.degree() + 1): - Taylor_expansion.append(nth_derivative(a) * 1/factorial(i)) + Taylor_expansion.append(nth_derivative(a) * 1 / factorial(i)) nth_derivative = nth_derivative.derivative(variable) r = x.radius() new_center = f(a) if self.domain().is_padic_base(): - new_radius = max([Taylor_expansion[i].abs()*r**i for i in range(1, len(Taylor_expansion))]) + new_radius = max([Taylor_expansion[i].abs() * r**i for i in range(1, len(Taylor_expansion))]) else: if prime is None: prime = x.parent().ideal() @@ -957,7 +951,7 @@ def __call__(self, x, type_3_pole_check=True): new_radius = 0 for i in range(1, len(Taylor_expansion)): valuation = dem_splitting_field(Taylor_expansion[i]).valuation(prime) - new_radius = max(new_radius, p**(-valuation/prime.absolute_ramification_index())*r**i) + new_radius = max(new_radius, p ** (-valuation / prime.absolute_ramification_index()) * r**i) return self.domain()(new_center, new_radius) @@ -995,6 +989,7 @@ class DynamicalSystem_Berkovich_affine(DynamicalSystem_Berkovich): Dynamical system of Affine Berkovich line over Cp(5) of precision 20 induced by the map Defn: Defined on coordinates by sending (x) to (x + 3 + O(5^20)) """ + @staticmethod def __classcall_private__(cls, dynamical_system, domain=None): """ @@ -1022,8 +1017,7 @@ def __classcall_private__(cls, dynamical_system, domain=None): raise ValueError('domain not relative dimension 1') if not isinstance(R, pAdicBaseGeneric): if domain is None: - raise TypeError('dynamical system defined over %s, not padic, ' % morphism_domain.base_ring() + - 'and domain was not specified') + raise TypeError('dynamical system defined over %s, not padic, ' % morphism_domain.base_ring() + 'and domain was not specified') if not isinstance(domain, Berkovich_Cp_Affine): raise TypeError('domain was %s, not an affine Berkovich space over Cp' % domain) else: diff --git a/src/sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py b/src/sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py index 642d49bcb6b..8dedd2c343c 100644 --- a/src/sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py +++ b/src/sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py @@ -1124,7 +1124,7 @@ def _repr_(self): (x^2 : y^2) """ header = "Dynamical semigroup over %s defined by %d dynamical system" - if (len(self.defining_systems()) > 1): + if len(self.defining_systems()) > 1: header += "s" header += ":" header = header % (str(self.domain()), len(self.defining_systems())) @@ -1193,11 +1193,9 @@ def __eq__(self, other): NotImplementedError: cannot compare dynamical semigroups with at least one generator of degree 1 """ if isinstance(other, DynamicalSemigroup): - if any(ds.degree() == 1 for ds in self.defining_systems()) or \ - any(ds.degree() == 1 for ds in other.defining_systems()): + if any(ds.degree() == 1 for ds in self.defining_systems()) or any(ds.degree() == 1 for ds in other.defining_systems()): raise NotImplementedError("cannot compare dynamical semigroups with at least one generator of degree 1") - return all(ds in other.defining_systems() for ds in self.defining_systems()) and \ - all(ds in self.defining_systems() for ds in other.defining_systems()) + return all(ds in other.defining_systems() for ds in self.defining_systems()) and all(ds in self.defining_systems() for ds in other.defining_systems()) return False @@ -1497,8 +1495,10 @@ def _standardize_domains_of_(systems): elif biggest_ring.has_coerce_map_from(ds.base_ring()): pass else: - raise ValueError("given dynamical systems are not automorphic \ - under global composition") + raise ValueError( + "given dynamical systems are not automorphic \ + under global composition" + ) for i in range(len(systems)): if systems[i].base_ring() != biggest_ring: diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py index f3f17995835..26748570b14 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py @@ -11,6 +11,7 @@ - Alexander Galarraga (7-2021): Added helper functions for conjugating set """ + # **************************************************************************** # Copyright (C) 2012 # @@ -112,171 +113,164 @@ def automorphism_group_QQ_fixedpoints(rational_function, return_functions=False, f = phi.numerator() g = phi.denominator() - #scale f,g so both have integer coefficients - N = lcm(f.denominator(),g.denominator()) - f = f*N - g = g*N + # scale f,g so both have integer coefficients + N = lcm(f.denominator(), g.denominator()) + f = f * N + g = g * N N = gcd(gcd(f.coefficients()), gcd(g.coefficients())) - f = f/N - g = g/N + f = f / N + g = g / N d = max(f.degree(), g.degree()) - h = f - g*z + h = f - g * z if return_functions: elements = [z] else: - elements = [matrix(F, 2, [1,0,0,1])] + elements = [matrix(F, 2, [1, 0, 0, 1])] rational_roots = h.roots(multiplicities=False) min_poly = 1 - #check if infinity is a fixed point - if g.degree() < d: #then infinity is a fixed point - #find elements in W of the form (infinity, y) - #where W is the set of F-rational points (x,y) such that - #x is fixed by phi and phi(y)=x + # check if infinity is a fixed point + if g.degree() < d: # then infinity is a fixed point + # find elements in W of the form (infinity, y) + # where W is the set of F-rational points (x,y) such that + # x is fixed by phi and phi(y)=x for T in g.roots(multiplicities=False): alpha = T zeta = -1 - s = (zeta*z + alpha*(1 - zeta)) + s = zeta * z + alpha * (1 - zeta) if s(phi(z)) == phi(s(z)): if return_functions: elements.append(s) else: - elements.append(matrix(F, 2, [zeta, alpha*(1-zeta), 0, 1])) + elements.append(matrix(F, 2, [zeta, alpha * (1 - zeta), 0, 1])) for S in h.roots(): - min_poly = min_poly*(z - S[0])**(S[1]) + min_poly = min_poly * (z - S[0]) ** (S[1]) - if g.degree() < d: #then infinity is a fixed point so (infinity, S[0]) + if g.degree() < d: # then infinity is a fixed point so (infinity, S[0]) alpha = S[0] # is in Z_(1,1)**2 zeta = -1 - s = (zeta*z + alpha*(1 - zeta)) + s = zeta * z + alpha * (1 - zeta) if s(phi(z)) == phi(s(z)): if return_functions: elements.append(s) else: - elements.append(matrix(F, 2, [zeta, alpha*(1-zeta), 0, 1])) + elements.append(matrix(F, 2, [zeta, alpha * (1 - zeta), 0, 1])) - #now compute points in W - preimage = f - g*S[0] - if preimage.degree() < d: #infinity is in W + # now compute points in W + preimage = f - g * S[0] + if preimage.degree() < d: # infinity is in W zeta = -1 alpha = S[0] - s = (zeta*z + alpha*(1 - zeta)) + s = zeta * z + alpha * (1 - zeta) if s(phi(z)) == phi(s(z)): if return_functions: elements.append(s) else: - elements.append(matrix(F, 2, [zeta, alpha*(1-zeta), 0, 1])) + elements.append(matrix(F, 2, [zeta, alpha * (1 - zeta), 0, 1])) for T in preimage.roots(multiplicities=False): if T != S[0]: zeta = -1 alpha = S[0] beta = T - s = ( (alpha - zeta*beta)*z - (alpha*beta)*(1 - zeta))/((1 - zeta)*z + (alpha*zeta - beta)) + s = ((alpha - zeta * beta) * z - (alpha * beta) * (1 - zeta)) / ((1 - zeta) * z + (alpha * zeta - beta)) if s(phi(z)) == phi(s(z)): if return_functions: elements.append(s) else: - elements.append(matrix(F, 2, - [(alpha - zeta*beta), - (alpha*beta)*(1 - zeta), - (1 - zeta), (alpha*zeta - beta)])) + elements.append(matrix(F, 2, [(alpha - zeta * beta), -(alpha * beta) * (1 - zeta), (1 - zeta), (alpha * zeta - beta)])) - #first look at rational fixed points - #Subsets is ok since we just needed unordered pairs + # first look at rational fixed points + # Subsets is ok since we just needed unordered pairs for S in Subsets(rational_roots, 2): zeta = -1 alpha = S[0] beta = S[1] - s = ( (alpha - zeta*beta)*z - (alpha*beta)*(1 - zeta))/((1 - zeta)*z + (alpha*zeta - beta)) + s = ((alpha - zeta * beta) * z - (alpha * beta) * (1 - zeta)) / ((1 - zeta) * z + (alpha * zeta - beta)) if s(phi(z)) == phi(s(z)): if return_functions: elements.append(s) else: - elements.append(matrix(F, 2, - [(alpha - zeta*beta), - (alpha*beta)*(1 - zeta), - (1 - zeta), (alpha*zeta - beta)])) + elements.append(matrix(F, 2, [(alpha - zeta * beta), -(alpha * beta) * (1 - zeta), (1 - zeta), (alpha * zeta - beta)])) # now consider 2-periodic points psi = phi(phi(z)) f2 = psi.numerator() g2 = psi.denominator() - period2_points = [x for x in (f2 - z*g2).roots(multiplicities=False) - if x not in rational_roots] + period2_points = [x for x in (f2 - z * g2).roots(multiplicities=False) if x not in rational_roots] for S in Subsets(period2_points, 2): zeta = -1 alpha = S[0] beta = S[1] - s = ( (alpha - zeta*beta)*z - (alpha*beta)*(1 - zeta))/((1 - zeta)*z + (alpha*zeta - beta)) + s = ((alpha - zeta * beta) * z - (alpha * beta) * (1 - zeta)) / ((1 - zeta) * z + (alpha * zeta - beta)) if s(phi(z)) == phi(s(z)): if return_functions: elements.append(s) else: - elements.append(matrix(F, 2, - [(alpha - zeta*beta), - (alpha*beta)*(1 - zeta), - (1 - zeta), (alpha*zeta - beta)])) - if g2.degree() < f2.degree() and g.degree() == d: #infinity has period 2 + elements.append(matrix(F, 2, [(alpha - zeta * beta), -(alpha * beta) * (1 - zeta), (1 - zeta), (alpha * zeta - beta)])) + if g2.degree() < f2.degree() and g.degree() == d: # infinity has period 2 for alpha in period2_points: zeta = -1 - s = (zeta*z + alpha*(1 - zeta)) + s = zeta * z + alpha * (1 - zeta) if s(phi(z)) == phi(s(z)): if return_functions: elements.append(s) else: - elements.append(matrix(F, 2, [zeta, alpha*(1-zeta), 0, 1])) - factors = (f2 - z*g2).factor() - L1 = NumberField(z**2 + 1,'i') + elements.append(matrix(F, 2, [zeta, alpha * (1 - zeta), 0, 1])) + factors = (f2 - z * g2).factor() + L1 = NumberField(z**2 + 1, 'i') i = L1.gen(0) - L2 = NumberField(z**2 + 3,'isqrt3') + L2 = NumberField(z**2 + 3, 'isqrt3') isqrt3 = L2.gen(0) for psi in factors: if psi[0].degree() == 2: a = psi[0][2] b = psi[0][1] c = psi[0][0] - disc = b**2 - 4*a*c - s = (-b*z - 2*c)/(2*a*z + b) + disc = b**2 - 4 * a * c + s = (-b * z - 2 * c) / (2 * a * z + b) if s(phi(z)) == phi(s(z)): if return_functions: elements.append(K(s)) else: - elements.append(matrix(F, 2, [-b,-2*c, 2*a, b])) - if is_square(-disc): #psi[0] generates Q(i) + elements.append(matrix(F, 2, [-b, -2 * c, 2 * a, b])) + if is_square(-disc): # psi[0] generates Q(i) alpha = psi[0].change_ring(L1).roots()[0][0] beta = alpha.trace() - alpha for zeta in [i, -i]: - a = (alpha - zeta*beta)/(1 - zeta) - d = (alpha*zeta - beta)/(1 - zeta) + a = (alpha - zeta * beta) / (1 - zeta) + d = (alpha * zeta - beta) / (1 - zeta) if a in F and d in F: a = F(a) d = F(d) - b = F(-alpha*beta) + b = F(-alpha * beta) s = (a * z + b) / (z + d) if s(phi(z)) == phi(s(z)): if return_functions: elements.append(K(s)) else: - elements.append(matrix(F, 2, [a,b, 1, d])) - elif is_square(-3*disc): #psi[0] generates Q(zeta_3) + elements.append(matrix(F, 2, [a, b, 1, d])) + elif is_square(-3 * disc): # psi[0] generates Q(zeta_3) alpha = psi[0].change_ring(L2).roots()[0][0] beta = alpha.trace() - alpha - for zeta in [F(1)/F(2)*(1 + isqrt3), F(1)/F(2)*(1 - isqrt3),F(1)/F(2)*(-1 + isqrt3), F(1)/F(2)*(-1 - isqrt3)]: - a = (alpha - zeta*beta)/(1 - zeta) - d = (alpha*zeta - beta)/(1 - zeta) + for zeta in [F(1) / F(2) * (1 + isqrt3), F(1) / F(2) * (1 - isqrt3), F(1) / F(2) * (-1 + isqrt3), F(1) / F(2) * (-1 - isqrt3)]: + a = (alpha - zeta * beta) / (1 - zeta) + d = (alpha * zeta - beta) / (1 - zeta) if a in F and d in F: a = F(a) d = F(d) - b = F(-alpha*beta) + b = F(-alpha * beta) s = (a * z + b) / (z + d) if s(phi(z)) == phi(s(z)): if return_functions: elements.append(K(s)) else: - elements.append(matrix(F, 2, [a,b, 1, d])) + elements.append(matrix(F, 2, [a, b, 1, d])) if iso_type: return elements, which_group(elements) @@ -327,13 +321,13 @@ def height_bound(polynomial): # scale polynomial so that it has integer coefficients with gcd 1 # this ensures that H(f) = H_infinity(f) f = R(polynomial) - f = f*f.denominator() - f = f/(gcd(f.coefficients())) + f = f * f.denominator() + f = f / (gcd(f.coefficients())) # compute the infinite height L2norm_sq = sum([a**2 for a in f.coefficients()]) - return (6*(L2norm_sq)**3) + return 6 * (L2norm_sq) ** 3 def PGL_repn(rational_function): @@ -399,7 +393,7 @@ def PGL_order(A): B = copy(AA) while B[0][0] != B[1][1] or B[0][1] != 0 or B[1][0] != 0: n = n + 1 - B = AA*B + B = AA * B return n @@ -430,9 +424,7 @@ def CRT_helper(automorphisms, moduli): ], 5) """ if len(automorphisms) > 2: - temp, modulus = CRT_helper( - [automorphisms[i] for i in range(len(automorphisms)) if i != 0], - [moduli[i] for i in range(len(moduli)) if i != 0]) + temp, modulus = CRT_helper([automorphisms[i] for i in range(len(automorphisms)) if i != 0], [moduli[i] for i in range(len(moduli)) if i != 0]) elif len(automorphisms) == 2: temp = automorphisms[1] modulus = moduli[1] @@ -442,14 +434,10 @@ def CRT_helper(automorphisms, moduli): autos = [] for B in temp: for C in automorphisms[0]: - A = matrix(Integers(modulus*moduli[0]), 2, - [CRT(B[0][0].lift(), C[0][0].lift(), modulus, moduli[0]), - CRT(B[0][1].lift(), C[0][1].lift(), modulus, moduli[0]), - CRT(B[1][0].lift(), C[1][0].lift(), modulus, moduli[0]), - CRT(B[1][1].lift(), C[1][1].lift(), modulus, moduli[0])]) + A = matrix(Integers(modulus * moduli[0]), 2, [CRT(B[0][0].lift(), C[0][0].lift(), modulus, moduli[0]), CRT(B[0][1].lift(), C[0][1].lift(), modulus, moduli[0]), CRT(B[1][0].lift(), C[1][0].lift(), modulus, moduli[0]), CRT(B[1][1].lift(), C[1][1].lift(), modulus, moduli[0])]) autos.append(A) - return autos, modulus*moduli[0] + return autos, modulus * moduli[0] def CRT_automorphisms(automorphisms, order_elts, degree, moduli): @@ -492,15 +480,13 @@ def CRT_automorphisms(automorphisms, order_elts, degree, moduli): degree_d_autos = [] for j in range(len(automorphisms)): L = automorphisms[j] - degree_d_autos.append( - [L[i] for i in range(len(L)) if order_elts[j][i] == degree]) + degree_d_autos.append([L[i] for i in range(len(L)) if order_elts[j][i] == degree]) # get list of CRT'ed automorphisms return CRT_helper(degree_d_autos, moduli) -def valid_automorphisms(automorphisms_CRT, rational_function, ht_bound, M, - return_functions=False): +def valid_automorphisms(automorphisms_CRT, rational_function, ht_bound, M, return_functions=False): r""" Check if automorphism mod `p^k` lifts to automorphism over `\ZZ`. @@ -539,18 +525,17 @@ def valid_automorphisms(automorphisms_CRT, rational_function, ht_bound, M, # to find an element of minimal height. These will have # coefficients in [-M/2, M/2) for scalar in M.coprime_integers(M): - new_lift = [scalar*x - (scalar*x/M).round()*M - for x in init_lift] + new_lift = [scalar * x - (scalar * x / M).round() * M for x in init_lift] g = gcd(new_lift) new_lift = [x // g for x in new_lift] if all(abs(x) <= ht_bound for x in new_lift): a, b, c, d = new_lift - f = (a*z + b) / (c*z + d) + f = (a * z + b) / (c * z + d) if rational_function(f(z)) == f(rational_function(z)): if return_functions: valid_auto.append(f) else: - valid_auto.append(matrix(ZZ,2,2,new_lift)) + valid_auto.append(matrix(ZZ, 2, 2, new_lift)) break return valid_auto @@ -597,15 +582,15 @@ def remove_redundant_automorphisms(automorphisms, order_elts, moduli, integral_a p = moduli[i] to_del_temp = [] for psi in integral_autos: - #The return_functions boolean determines if the automorphisms - #are matrices or linear fractional transformations + # The return_functions boolean determines if the automorphisms + # are matrices or linear fractional transformations if isinstance(psi, Matrix): ppsi = psi.change_ring(GF(p)) - B = [ppsi[0,0], ppsi[0,1], ppsi[1,0], psi[1,1]] + B = [ppsi[0, 0], ppsi[0, 1], ppsi[1, 0], psi[1, 1]] else: ff = psi.numerator().change_ring(GF(p)) gg = psi.denominator().change_ring(GF(p)) - B = [ff[1],ff[0],gg[1],gg[0]] + B = [ff[1], ff[0], gg[1], gg[0]] for j in range(len(automorphisms[i])): A = automorphisms[i][j] M = matrix(GF(p), [B, [A[0][0], A[0][1], A[1][0], A[1][1]]]) @@ -690,42 +675,42 @@ def automorphism_group_QQ_CRT(rational_function, prime_lower_bound=4, return_fun f = phi.numerator() g = phi.denominator() - #scale f,g so both have integer coefficients - N = lcm(f.denominator(),g.denominator()) - f = f*N - g = g*N + # scale f,g so both have integer coefficients + N = lcm(f.denominator(), g.denominator()) + f = f * N + g = g * N N = gcd(gcd(f.coefficients()), gcd(g.coefficients())) - f = f/N - g = g/N + f = f / N + g = g / N d = max(f.degree(), g.degree()) if d == 1: raise ValueError("rational function has degree 1") - #badprimes is an integer divisible by every prime p such that either + # badprimes is an integer divisible by every prime p such that either # 1) phi has bad reduction at p or # 2) the reduction map fails to be injective - badprimes = (gcd(f[d],g[d])*f.resultant(g)*6) - #6 is because over Q, Aut(phi) has order dividing 12 - #when generalizing to a number field K, 6 should be replaced with + badprimes = gcd(f[d], g[d]) * f.resultant(g) * 6 + # 6 is because over Q, Aut(phi) has order dividing 12 + # when generalizing to a number field K, 6 should be replaced with # 2*gcd(2*[K:Q] + 1, d^3 - d) - #Determining the set that is used to obtain the height bound - h = R(prod(x[0] for x in (R(f - g*z)).factor()))# take minimal polynomial of fixed points - if h.degree() == 2: #if there are only 2 finite fixed points, take preimage of fixed points - h = h[2]*f**2 + h[1]*f*g + h[0]*g**2 - elif h.degree() == 1: #if there is just 1 finite fixed point, take preimages under phi^2 + # Determining the set that is used to obtain the height bound + h = R(prod(x[0] for x in (R(f - g * z)).factor())) # take minimal polynomial of fixed points + if h.degree() == 2: # if there are only 2 finite fixed points, take preimage of fixed points + h = h[2] * f**2 + h[1] * f * g + h[0] * g**2 + elif h.degree() == 1: # if there is just 1 finite fixed point, take preimages under phi^2 psi = phi(phi(z)) f2 = psi.numerator() g2 = psi.denominator() - N = lcm(f2.denominator(),g2.denominator()) - f2 = f2*N - g2 = g2*N + N = lcm(f2.denominator(), g2.denominator()) + f2 = f2 * N + g2 = g2 * N N = gcd(gcd(f2.coefficients()), gcd(g2.coefficients())) - f2 = f2/N - g2 = g2/N - h = h[1]*f2 + h[0]*g2 + f2 = f2 / N + g2 = g2 / N + h = h[1] * f2 + h[0] * g2 MaxH = height_bound(h) congruence = 1 @@ -739,18 +724,18 @@ def automorphism_group_QQ_CRT(rational_function, prime_lower_bound=4, return_fun if return_functions: elements = [z] else: - elements = [matrix(ZZ, 2, [1,0,0,1])] + elements = [matrix(ZZ, 2, [1, 0, 0, 1])] - badorders = [1, 12]# order 12 not possible over Q, even though 4 and 6 are + badorders = [1, 12] # order 12 not possible over Q, even though 4 and 6 are - #over QQ, elts of PGL_2 of finite order can only have order dividing 6 or 4, + # over QQ, elts of PGL_2 of finite order can only have order dividing 6 or 4, # and the finite subgroups can only be cyclic or dihedral (Beauville) so # the only possible groups are C_n, D_2n for n|6 or n|4 # all of these groups have order dividing 24 - while (congruence < (2*MaxH**2)) and len(elements) < gcd(orderaut + [24]): - if badprimes % p != 0: #prime of good reduction + while (congruence < (2 * MaxH**2)) and len(elements) < gcd(orderaut + [24]): + if badprimes % p != 0: # prime of good reduction # compute automorphisms mod p - phi_p = f.change_ring(GF(p))/g.change_ring(GF(p)) + phi_p = f.change_ring(GF(p)) / g.change_ring(GF(p)) sorted_automorphisms = automorphism_group_FF(phi_p) sorted_automorphisms.sort(key=PGL_order) orders = [PGL_order(A) for A in sorted_automorphisms] @@ -763,9 +748,7 @@ def automorphism_group_QQ_CRT(rational_function, prime_lower_bound=4, return_fun # check if we already found 8 or 12 automorphisms # and the gcd of orders over Fp and 24 is 24 # or if the gcd is equal to the number of automorphisms we have - if (len(elements) == gcd(orderaut + [24])) or \ - (gcd(orderaut + [24]) == 24 and - (len(elements) == 12 or len(elements) == 8)): + if (len(elements) == gcd(orderaut + [24])) or (gcd(orderaut + [24]) == 24 and (len(elements) == 12 or len(elements) == 8)): if iso_type: return elements, which_group(elements) return elements @@ -786,13 +769,11 @@ def automorphism_group_QQ_CRT(rational_function, prime_lower_bound=4, return_fun if numelts != 0: # CRT order d elements together and check if # they are an automorphism - autos, M = CRT_automorphisms(automorphisms, - orderelts, order, primepowers) - temp = valid_automorphisms(autos, phi, MaxH, M, - return_functions) + autos, M = CRT_automorphisms(automorphisms, orderelts, order, primepowers) + temp = valid_automorphisms(autos, phi, MaxH, M, return_functions) elements.extend(temp) - if (len(elements) == gcd(orderaut + [24])): + if len(elements) == gcd(orderaut + [24]): # found enough automorphisms if iso_type: return elements, which_group(elements) @@ -805,12 +786,11 @@ def automorphism_group_QQ_CRT(rational_function, prime_lower_bound=4, return_fun # if an element of Aut_{F_p} has been lifted to QQ # remove that element from Aut_{F_p} so we don't # attempt to lift that element again unnecessarily - automorphisms = remove_redundant_automorphisms(automorphisms, - orderelts, primepowers, temp) + automorphisms = remove_redundant_automorphisms(automorphisms, orderelts, primepowers, temp) if order == 4: # have some elements of order 4 # so possible aut group is Z/4 or D_4 badorders.extend([3, 6]) - elif order == 3 or order == 6:#have some elements of + elif order == 3 or order == 6: # have some elements of # order 3 or 6 so possible aut groups are Z/3, # D_3, Z/6, or D_6 badorders.append(4) @@ -818,7 +798,7 @@ def automorphism_group_QQ_CRT(rational_function, prime_lower_bound=4, return_fun for m in divisors(N): if m % order == 0: badorders.append(m) - #no elements of that order or any order that + # no elements of that order or any order that # is a multiple of it if all(order in badorders for order in divisors(N)): # found all elements of every possible order @@ -893,12 +873,12 @@ def automorphism_group_FF(rational_function, absolute=False, iso_type=False, ret R = G[1][0].parent() if R.is_field(): R = R.ring() - G[1] = [matrix(R.base_ring(),[[R(g.numerator())[1],R(g.numerator())[0]],[R(g.denominator())[1],R(g.denominator())[0]]]) for g in G[1]] + G[1] = [matrix(R.base_ring(), [[R(g.numerator())[1], R(g.numerator())[0]], [R(g.denominator())[1], R(g.denominator())[0]]]) for g in G[1]] else: R = G[0].parent() if R.is_field(): R = R.ring() - G = [matrix(R.base_ring(),[[R(g.numerator())[1],R(g.numerator())[0]],[R(g.denominator())[1],R(g.denominator())[0]]]) for g in G] + G = [matrix(R.base_ring(), [[R(g.numerator())[1], R(g.numerator())[0]], [R(g.denominator())[1], R(g.denominator())[0]]]) for g in G] if not iso_type: return G @@ -938,11 +918,11 @@ def field_descent(sigma, y): p = F.characteristic() r = F.degree() - if p != 0 and y**(p**r) != y: + if p != 0 and y ** (p**r) != y: return K = F.prime_subfield() - R = PolynomialRing(K,'X') + R = PolynomialRing(K, 'X') f = R(sigma(a).polynomial().coefficients(sparse=False)) g = R(y.polynomial().coefficients(sparse=False)) @@ -957,10 +937,10 @@ def field_descent(sigma, y): quotient, remainder = quotient.quo_rem(f) if not remainder.is_constant(): return - x = x + F(remainder)*a**(steps) + x = x + F(remainder) * a ** (steps) steps += 1 - return x + F(quotient)*a**(steps) + return x + F(quotient) * a ** (steps) def rational_function_coefficient_descent(rational_function, sigma, poly_ring): @@ -1009,15 +989,15 @@ def rational_function_coefficient_descent(rational_function, sigma, poly_ring): fe = num.exponents() g = denom.coefficients() ge = denom.exponents() - #force the cancellation of common coefficient factors by scaling by f[-1] - ff = [ field_descent(sigma, x/f[-1]) for x in f] - gg = [ field_descent(sigma, x/f[-1]) for x in g] + # force the cancellation of common coefficient factors by scaling by f[-1] + ff = [field_descent(sigma, x / f[-1]) for x in f] + gg = [field_descent(sigma, x / f[-1]) for x in g] if None in ff or None in gg: return z = poly_ring.gen(0) - numer = sum(poly_ring(ff[i]) * z**fe[i] for i in range(len(ff))) - denom = sum(poly_ring(gg[i]) * z**ge[i] for i in range(len(gg))) + numer = sum(poly_ring(ff[i]) * z ** fe[i] for i in range(len(ff))) + denom = sum(poly_ring(gg[i]) * z ** ge[i] for i in range(len(gg))) return numer / denom @@ -1057,7 +1037,7 @@ def rational_function_coerce(rational_function, sigma, S_polys): g = R(rational_function.denominator()).coefficients(sparse=False) if g == [R(1)]: - return S_polys([sigma(a) for a in f]) # allows for coercion of polynomials + return S_polys([sigma(a) for a in f]) # allows for coercion of polynomials return S_polys([sigma(a) for a in f]) / S_polys([sigma(b) for b in g]) @@ -1083,7 +1063,7 @@ def rational_function_reduce(rational_function): phi = rational_function F = phi.numerator() G = phi.denominator() - comm_factor = gcd(F,G) + comm_factor = gcd(F, G) return (F.quo_rem(comm_factor)[0]) / (G.quo_rem(comm_factor)[0]) @@ -1125,37 +1105,17 @@ def three_stable_points(rational_function, invariant_list): T = invariant_list automorphisms = [] - for t in permutations(range(len(T)),3): - a = (T[0][0]*T[1][1]*T[2][1]*T[t[0]][0]*T[t[1]][0]*T[t[2]][1] - - T[0][0]*T[1][1]*T[2][1]*T[t[0]][0]*T[t[1]][1]*T[t[2]][0] - - T[0][1]*T[1][0]*T[2][1]*T[t[0]][0]*T[t[1]][0]*T[t[2]][1] + - T[0][1]*T[1][0]*T[2][1]*T[t[0]][1]*T[t[1]][0]*T[t[2]][0] + - T[0][1]*T[1][1]*T[2][0]*T[t[0]][0]*T[t[1]][1]*T[t[2]][0] - - T[0][1]*T[1][1]*T[2][0]*T[t[0]][1]*T[t[1]][0]*T[t[2]][0]) - - b = (T[0][0]*T[1][0]*T[2][1]*T[t[0]][0]*T[t[1]][1]*T[t[2]][0] - - T[0][0]*T[1][0]*T[2][1]*T[t[0]][1]*T[t[1]][0]*T[t[2]][0] - - T[0][0]*T[1][1]*T[2][0]*T[t[0]][0]*T[t[1]][0] * T[t[2]][1] + - T[0][0]*T[1][1]*T[2][0]*T[t[0]][1]*T[t[1]][0]*T[t[2]][0] + - T[0][1]*T[1][0]*T[2][0]*T[t[0]][0]*T[t[1]][0]*T[t[2]][1] - - T[0][1]*T[1][0]*T[2][0]*T[t[0]][0]*T[t[1]][1]*T[t[2]][0]) - - c = (T[0][0]*T[1][1]*T[2][1]*T[t[0]][1]*T[t[1]][0] * T[t[2]][1] - - T[0][0]*T[1][1]*T[2][1]*T[t[0]][1]*T[t[1]][1]*T[t[2]][0] - - T[0][1]*T[1][0]*T[2][1]*T[t[0]][0]*T[t[1]][1]*T[t[2]][1] + - T[0][1]*T[1][0]*T[2][1]*T[t[0]][1]*T[t[1]][1]*T[t[2]][0] + - T[0][1]*T[1][1]*T[2][0]*T[t[0]][0]*T[t[1]][1]*T[t[2]][1] - - T[0][1]*T[1][1]*T[2][0]*T[t[0]][1]*T[t[1]][0]*T[t[2]][1]) - - d = (T[0][0]*T[1][0]*T[2][1]*T[t[0]][0]*T[t[1]][1]*T[t[2]][1] - - T[0][0]*T[1][0]*T[2][1]*T[t[0]][1]*T[t[1]][0] * T[t[2]][1] - - T[0][0]*T[1][1]*T[2][0]*T[t[0]][0]*T[t[1]][1]*T[t[2]][1] + - T[0][0]*T[1][1]*T[2][0]*T[t[0]][1]*T[t[1]][1]*T[t[2]][0] + - T[0][1]*T[1][0]*T[2][0]*T[t[0]][1]*T[t[1]][0] * T[t[2]][1] - - T[0][1]*T[1][0]*T[2][0]*T[t[0]][1]*T[t[1]][1]*T[t[2]][0]) - - if a*d - b*c != 0: - s = K(a*z + b) / K(c*z + d) + for t in permutations(range(len(T)), 3): + a = T[0][0] * T[1][1] * T[2][1] * T[t[0]][0] * T[t[1]][0] * T[t[2]][1] - T[0][0] * T[1][1] * T[2][1] * T[t[0]][0] * T[t[1]][1] * T[t[2]][0] - T[0][1] * T[1][0] * T[2][1] * T[t[0]][0] * T[t[1]][0] * T[t[2]][1] + T[0][1] * T[1][0] * T[2][1] * T[t[0]][1] * T[t[1]][0] * T[t[2]][0] + T[0][1] * T[1][1] * T[2][0] * T[t[0]][0] * T[t[1]][1] * T[t[2]][0] - T[0][1] * T[1][1] * T[2][0] * T[t[0]][1] * T[t[1]][0] * T[t[2]][0] + + b = T[0][0] * T[1][0] * T[2][1] * T[t[0]][0] * T[t[1]][1] * T[t[2]][0] - T[0][0] * T[1][0] * T[2][1] * T[t[0]][1] * T[t[1]][0] * T[t[2]][0] - T[0][0] * T[1][1] * T[2][0] * T[t[0]][0] * T[t[1]][0] * T[t[2]][1] + T[0][0] * T[1][1] * T[2][0] * T[t[0]][1] * T[t[1]][0] * T[t[2]][0] + T[0][1] * T[1][0] * T[2][0] * T[t[0]][0] * T[t[1]][0] * T[t[2]][1] - T[0][1] * T[1][0] * T[2][0] * T[t[0]][0] * T[t[1]][1] * T[t[2]][0] + + c = T[0][0] * T[1][1] * T[2][1] * T[t[0]][1] * T[t[1]][0] * T[t[2]][1] - T[0][0] * T[1][1] * T[2][1] * T[t[0]][1] * T[t[1]][1] * T[t[2]][0] - T[0][1] * T[1][0] * T[2][1] * T[t[0]][0] * T[t[1]][1] * T[t[2]][1] + T[0][1] * T[1][0] * T[2][1] * T[t[0]][1] * T[t[1]][1] * T[t[2]][0] + T[0][1] * T[1][1] * T[2][0] * T[t[0]][0] * T[t[1]][1] * T[t[2]][1] - T[0][1] * T[1][1] * T[2][0] * T[t[0]][1] * T[t[1]][0] * T[t[2]][1] + + d = T[0][0] * T[1][0] * T[2][1] * T[t[0]][0] * T[t[1]][1] * T[t[2]][1] - T[0][0] * T[1][0] * T[2][1] * T[t[0]][1] * T[t[1]][0] * T[t[2]][1] - T[0][0] * T[1][1] * T[2][0] * T[t[0]][0] * T[t[1]][1] * T[t[2]][1] + T[0][0] * T[1][1] * T[2][0] * T[t[0]][1] * T[t[1]][1] * T[t[2]][0] + T[0][1] * T[1][0] * T[2][0] * T[t[0]][1] * T[t[1]][0] * T[t[2]][1] - T[0][1] * T[1][0] * T[2][0] * T[t[0]][1] * T[t[1]][1] * T[t[2]][0] + + if a * d - b * c != 0: + s = K(a * z + b) / K(c * z + d) if s(phi(z)) == phi(s(z)) and s not in automorphisms: automorphisms.append(s) return automorphisms @@ -1213,62 +1173,62 @@ def automorphism_group_FF_alg2(rational_function): D = max(f.degree(), g.degree()) # Build an invariant set for phi - fix = f(z) - z*g(z) + fix = f(z) - z * g(z) factor_list = fix.factor() minimal_fix_poly = R(prod(x[0] for x in factor_list)) - n = sum(x[0].degree() for x in factor_list) + bool(fix.degree() < D+1) + n = sum(x[0].degree() for x in factor_list) + bool(fix.degree() < D + 1) if n >= 3: T_poly = minimal_fix_poly - infinity_check = bool(fix.degree() < D+1) + infinity_check = bool(fix.degree() < D + 1) elif n == 2: # Infinity is a fixed point - if bool(fix.degree() < D+1): + if bool(fix.degree() < D + 1): y = fix.roots(multiplicities=False)[0] - preimage = g*(f(z) - y*g(z)) + preimage = g * (f(z) - y * g(z)) infinity_check = 1 # Infinity is not a fixed point else: C = minimal_fix_poly.coefficients(sparse=False) - preimage = C[2]*f(z)**2 + C[1]*f(z)*g(z) + C[0]*g(z)**2 - infinity_check = bool(preimage.degree() < 2*D) + preimage = C[2] * f(z) ** 2 + C[1] * f(z) * g(z) + C[0] * g(z) ** 2 + infinity_check = bool(preimage.degree() < 2 * D) T_poly = R(prod(x[0] for x in preimage.factor())) - else: #case n=1 + else: # case n=1 # Infinity is the fixed point - if bool(fix.degree() < D+1): + if bool(fix.degree() < D + 1): minimal_preimage = R(prod(x[0] for x in g.factor())) if minimal_preimage.degree() + 1 >= 3: T_poly = minimal_preimage infinity_check = 1 else: - T_poly = R(prod(x[0] for x in phi(phi(z)).denominator().factor() ) ) + T_poly = R(prod(x[0] for x in phi(phi(z)).denominator().factor())) infinity_check = 1 # Infinity is not a fixed point else: y = fix.roots(multiplicities=False)[0] - preimage = R(f(z) - y*g(z)) + preimage = R(f(z) - y * g(z)) minimal_preimage = R(prod(x[0] for x in preimage.factor())) if minimal_preimage.degree() + bool(preimage.degree() < D) >= 3: T_poly = minimal_preimage infinity_check = bool(preimage.degree() < D) else: - preimage2 = R(phi(phi(z)).numerator() - y*phi(phi(z)).denominator()) - T_poly = R(prod(x[0] for x in preimage2.factor() ) ) + preimage2 = R(phi(phi(z)).numerator() - y * phi(phi(z)).denominator()) + T_poly = R(prod(x[0] for x in preimage2.factor())) infinity_check = bool(preimage2.degree() < D**2) # Define a field of definition for the absolute automorphism group - r = lcm([x[0].degree() for x in T_poly.factor()])*F.degree() - E = GF(p**r,'b') + r = lcm([x[0].degree() for x in T_poly.factor()]) * F.degree() + E = GF(p**r, 'b') sigma = F.Hom(E)[0] S = PolynomialRing(E, 'w') E_poly = rational_function_coerce(T_poly, sigma, S) - T = [ [alpha, E(1)] for alpha in E_poly.roots(ring=E, multiplicities=False)] + T = [[alpha, E(1)] for alpha in E_poly.roots(ring=E, multiplicities=False)] if infinity_check == 1: - T.append([E(1),E(0)]) + T.append([E(1), E(0)]) # Coerce phi into the larger ring and call Algorithm 1 Phi = rational_function_coerce(phi, sigma, S) @@ -1344,7 +1304,7 @@ def order_p_automorphisms(rational_function, pre_image): F = R.base_ring() q = F.cardinality() p = F.characteristic() - r = (q-1) / (p-1) # index of F_p^\times inside F^\times + r = (q - 1) / (p - 1) # index of F_p^\times inside F^\times # Compute the threshold r2 for determining which algorithm to use if len(pre_image) > 1: @@ -1370,21 +1330,21 @@ def order_p_automorphisms(rational_function, pre_image): zeta = F.multiplicative_generator() alpha = zeta**r - if pt == [F(1),F(0)]: + if pt == [F(1), F(0)]: for j in range(r): s = z + zeta**j if s(phi(z)) == phi(s(z)): - for i in range(p-1): - automorphisms_p.append(z+alpha**i*zeta**j) + for i in range(p - 1): + automorphisms_p.append(z + alpha**i * zeta**j) else: u = F(1) / (z - pt[0]) - u_inv = pt[0] + F(1)/z + u_inv = pt[0] + F(1) / z for j in range(r): - s = u_inv( u(z) + zeta**j ) + s = u_inv(u(z) + zeta**j) if s(phi(z)) == phi(s(z)): - for i in range(p-1): - automorphisms_p.append(u_inv( u(z) + alpha**i*zeta**j) ) + for i in range(p - 1): + automorphisms_p.append(u_inv(u(z) + alpha**i * zeta**j)) elif r2 < r: @@ -1410,23 +1370,23 @@ def order_p_automorphisms(rational_function, pre_image): automorphisms_p.append(s) else: u = F(1) / (z - pt[0]) - u_inv = pt[0] + F(1)/z + u_inv = pt[0] + F(1) / z for i in range(1, m): if M[0] == [F(1), F(0)]: uy1 = 0 else: uy1 = u(M[0][0]) - if M[i] == [F(1),F(0)]: + if M[i] == [F(1), F(0)]: uy2 = 0 else: uy2 = u(M[i][0]) - s = u_inv( u(z) + uy2 - uy1 ) + s = u_inv(u(z) + uy2 - uy1) if s(phi(z)) == phi(s(z)): automorphisms_p.append(s) elif not T: # create the extension field generated by pre-images of the unique fixed point T_poly = pre_image[0][2] - e = lcm([x[0].degree() for x in T_poly.factor()])*F.degree() + e = lcm([x[0].degree() for x in T_poly.factor()]) * F.degree() E = GF(p**e, 'b') sigma = F.Hom(E)[0] S = PolynomialRing(E, 'w') @@ -1434,28 +1394,28 @@ def order_p_automorphisms(rational_function, pre_image): E_poly = rational_function_coerce(T_poly, sigma, S) # List of roots permuted by elements of order p # Since infinity is F-rational, it won't appear in this list - T = [ [alpha, E(1)] for alpha in E_poly.roots(ring=E, multiplicities=False)] + T = [[alpha, E(1)] for alpha in E_poly.roots(ring=E, multiplicities=False)] # coerce the rational function and fixed point into E Phi = rational_function_coerce(phi, sigma, S) Pt = [sigma(pt[0]), sigma(pt[1])] m = len(T) - if Pt == [E(1),E(0)]: + if Pt == [E(1), E(0)]: for i in range(1, m): s = w + T[i][0] - T[0][0] if s(Phi(w)) == Phi(s(w)): automorphisms_p.append(rational_function_coefficient_descent(s, sigma, R)) else: u = E(1) / (w - Pt[0]) - u_inv = Pt[0] + E(1)/w - for i in range(1,m): + u_inv = Pt[0] + E(1) / w + for i in range(1, m): uy1 = u(T[0][0]) uy2 = u(T[i][0]) - s = u_inv( u(w) + uy2 - uy1 ) + s = u_inv(u(w) + uy2 - uy1) if s(Phi(w)) == Phi(s(w)): s = rational_function_reduce(s) - automorphisms_p.append(rational_function_coefficient_descent(s,sigma,R)) + automorphisms_p.append(rational_function_coefficient_descent(s, sigma, R)) return automorphisms_p @@ -1500,29 +1460,29 @@ def automorphisms_fixing_pair(rational_function, pair, quad): g = phi.denominator() D = max(f.degree(), g.degree()) - #assumes the second coordinate of the point is 1 - if pair[0] == [1,0]: + # assumes the second coordinate of the point is 1 + if pair[0] == [1, 0]: u = K(z - pair[1][0]) u_inv = K(z + pair[1][0]) - elif pair[1] == [1,0]: + elif pair[1] == [1, 0]: u = K(E(1) / (z - pair[0][0])) - u_inv = K( (pair[0][0]*z + 1) / z ) + u_inv = K((pair[0][0] * z + 1) / z) else: - u = K( (z - pair[1][0]) / (z - pair[0][0]) ) - u_inv = K( (pair[0][0]*z - pair[1][0] ) / (z - 1) ) + u = K((z - pair[1][0]) / (z - pair[0][0])) + u_inv = K((pair[0][0] * z - pair[1][0]) / (z - 1)) automorphisms_prime_to_p = [] # Quadratic automorphisms have order dividing q+1 and D, D-1, or D+1 if quad: - #need sqrt to get the cardinality of the base field and not the - #degree 2 extension + # need sqrt to get the cardinality of the base field and not the + # degree 2 extension q = sqrt(E.cardinality()) - zeta = (E.multiplicative_generator())**(q-1) - for j in [-1,0,1]: - g = gcd(q+1, D + j) - xi = zeta**( (q+1) / g ) - for i in range(1,g): - s = u_inv(xi**i*u(z)) + zeta = (E.multiplicative_generator()) ** (q - 1) + for j in [-1, 0, 1]: + g = gcd(q + 1, D + j) + xi = zeta ** ((q + 1) / g) + for i in range(1, g): + s = u_inv(xi**i * u(z)) if s(phi(z)) == phi(s(z)): automorphisms_prime_to_p.append(rational_function_reduce(s)) @@ -1530,11 +1490,11 @@ def automorphisms_fixing_pair(rational_function, pair, quad): else: q = E.cardinality() zeta = E.multiplicative_generator() - for j in [-1,0,1]: - g = gcd(q-1, D + j) - xi = zeta**( (q-1) / g ) - for i in range(1,g): - s = u_inv(xi**i*u(z)) + for j in [-1, 0, 1]: + g = gcd(q - 1, D + j) + xi = zeta ** ((q - 1) / g) + for i in range(1, g): + s = u_inv(xi**i * u(z)) if s(phi(z)) == phi(s(z)): automorphisms_prime_to_p.append(rational_function_reduce(s)) @@ -1580,52 +1540,52 @@ def automorphism_group_FF_alg3(rational_function): D = max(f.degree(), g.degree()) # For use in the quadratic extension parts of the algorithm - E = GF(p**(2 * F.degree()), 'b') + E = GF(p ** (2 * F.degree()), 'b') sigma = F.Hom(E)[0] S = PolynomialRing(E, 'w') Phi = rational_function_coerce(phi, sigma, S) # Compute the set of distinct F-rational and F-quadratic # factors of the fixed point polynomial - fix = R(f(z) - z*g(z)) + fix = R(f(z) - z * g(z)) linear_fix = gcd(fix, z**q - z) quad_temp = fix.quo_rem(linear_fix)[0] residual = gcd(quad_temp, z**q - z) while residual.degree() > 0: quad_temp = quad_temp.quo_rem(residual)[0] residual = gcd(quad_temp, z**q - z) - quadratic_fix = gcd(quad_temp, z**(q**2) - z).factor() + quadratic_fix = gcd(quad_temp, z ** (q**2) - z).factor() # Compute the set of distinct F-rational fixed points - linear_fix_pts = [[ x, F(1)] for x in linear_fix.roots(multiplicities=False)] - if bool(fix.degree() < D+1): - linear_fix_pts.append( [F(1),F(0)] ) + linear_fix_pts = [[x, F(1)] for x in linear_fix.roots(multiplicities=False)] + if bool(fix.degree() < D + 1): + linear_fix_pts.append([F(1), F(0)]) n1 = len(linear_fix_pts) # Coerce quadratic factors into a quadratic extension - quad_fix_factors = [ rational_function_coerce(poly[0], sigma, S) for poly in quadratic_fix] - n2 = 2*len(quad_fix_factors) + quad_fix_factors = [rational_function_coerce(poly[0], sigma, S) for poly in quadratic_fix] + n2 = 2 * len(quad_fix_factors) # Collect pre-image data as a list L with entries in the form # [fixed point y, F-rational pre-images z != y, polynomial defining the pre-images] # Note that we remove the fixed point from its pre-image set and its polynomial pre_images = [] for y in linear_fix_pts: - if y == [F(1),F(0)]: - Fpre = [ [x,F(1)] for x in g.roots(multiplicities=False) ] + if y == [F(1), F(0)]: + Fpre = [[x, F(1)] for x in g.roots(multiplicities=False)] pre_images.append([y, Fpre, g]) else: - Fpre = [ [x,F(1)] for x in (f - y[0]*g).roots(multiplicities=False) if x != y[0]] + Fpre = [[x, F(1)] for x in (f - y[0] * g).roots(multiplicities=False) if x != y[0]] if y[0] == 0 and f.degree() < g.degree(): - Fpre.append([F(1), F(0)]) # infinity is a pre-image of 0 - elif f.degree() == g.degree() and f.leading_coefficient() == y[0]*g.leading_coefficient(): - Fpre.append([F(1), F(0)]) # infinity is a pre-image of y[0] + Fpre.append([F(1), F(0)]) # infinity is a pre-image of 0 + elif f.degree() == g.degree() and f.leading_coefficient() == y[0] * g.leading_coefficient(): + Fpre.append([F(1), F(0)]) # infinity is a pre-image of y[0] # remove y[0] as a root of pre-image polynomial - h = (f - y[0]*g).quo_rem(z-y[0])[0] - h_common = gcd(h, z-y[0]) + h = (f - y[0] * g).quo_rem(z - y[0])[0] + h_common = gcd(h, z - y[0]) while h_common.degree() > 0: - h = h.quo_rem(z-y[0])[0] - h_common = gcd(h,z-y[0]) + h = h.quo_rem(z - y[0])[0] + h_common = gcd(h, z - y[0]) pre_images.append([y, Fpre, h]) # Initialize the set of automorphisms to contain the identity @@ -1639,7 +1599,7 @@ def automorphism_group_FF_alg3(rational_function): if n1 % p == 1 and n2 % p == 0 and sum(len(x[1]) for x in pre_images) % p == 0: # Compute total number of distinct fixed points as a final check for order p auts factor_list = fix.factor() - n = sum(x[0].degree() for x in factor_list) + bool(fix.degree() < D+1) + n = sum(x[0].degree() for x in factor_list) + bool(fix.degree() < D + 1) if n % p == 1: automorphisms = automorphisms + order_p_automorphisms(phi, pre_images) @@ -1648,27 +1608,27 @@ def automorphism_group_FF_alg3(rational_function): for pt_pair in combinations(linear_fix_pts, 2): x = pt_pair[0] y = pt_pair[1] - automorphisms = automorphisms + automorphisms_fixing_pair(phi, [x,y], False) + automorphisms = automorphisms + automorphisms_fixing_pair(phi, [x, y], False) # case of 1 F-rational fixed point and an F-rational pre-image for y in pre_images: for x in y[1]: - automorphisms = automorphisms + automorphisms_fixing_pair(phi, [x,y[0]], False) + automorphisms = automorphisms + automorphisms_fixing_pair(phi, [x, y[0]], False) # case of a pair of quadratic fixed points for h in quad_fix_factors: - quad_fix_pts = [ [x,E(1)] for x in h.roots(multiplicities=False)] + quad_fix_pts = [[x, E(1)] for x in h.roots(multiplicities=False)] automorphisms_quad = automorphisms_quad + automorphisms_fixing_pair(Phi, quad_fix_pts, True) phi_2 = phi(phi(z)) f_2 = phi_2.numerator() g_2 = phi_2.denominator() - period_2 = (f_2(z) - z*g_2(z)).quo_rem(fix)[0] + period_2 = (f_2(z) - z * g_2(z)).quo_rem(fix)[0] factor_list_2 = period_2.factor() - linear_period_2_pts = [[ x, F(1)] for x in period_2.roots(multiplicities=False)] - if bool(period_2.degree() < D**2-D): - linear_period_2_pts.append( [F(1),F(0)] ) + linear_period_2_pts = [[x, F(1)] for x in period_2.roots(multiplicities=False)] + if bool(period_2.degree() < D**2 - D): + linear_period_2_pts.append([F(1), F(0)]) quad_period_2_factors = [rational_function_coerce(poly[0], sigma, S) for poly in factor_list_2 if poly[0].degree() == 2] # n2 = n1 + 2*len(quad_fix_factors) @@ -1687,14 +1647,14 @@ def automorphism_group_FF_alg3(rational_function): if x != y: linear_period_2_pts.remove(y) - linear_period_2_pairs.append([x,y]) + linear_period_2_pairs.append([x, y]) for pt_pair in linear_period_2_pairs: automorphisms = automorphisms + automorphisms_fixing_pair(phi, pt_pair, False) # case of a pair of quadratic period 2 points for h in quad_period_2_factors: - pt_pair = [ [x,E(1)] for x in h.roots(multiplicities=False)] + pt_pair = [[x, E(1)] for x in h.roots(multiplicities=False)] if Phi(pt_pair[0][0]) == pt_pair[1][0]: automorphisms_quad = automorphisms_quad + automorphisms_fixing_pair(Phi, pt_pair, True) @@ -1727,9 +1687,9 @@ def which_group(list_of_elements): 'Dihedral of order 6' """ if isinstance(list_of_elements[-1], Matrix): - R = PolynomialRing(list_of_elements[-1].base_ring(),'z') + R = PolynomialRing(list_of_elements[-1].base_ring(), 'z') z = R.gen(0) - G = [(t[0,0]*z+t[0,1])/(t[1,0]*z+t[1,1]) for t in list_of_elements] + G = [(t[0, 0] * z + t[0, 1]) / (t[1, 0] * z + t[1, 1]) for t in list_of_elements] else: G = list_of_elements @@ -1755,7 +1715,7 @@ def which_group(list_of_elements): # factor n = mp^e; set e = 0 and m = n if p = 0 (Sage sets 0^0 = 1) if p > 0: m = n.prime_to_m_part(p) - e = ZZ(n/m).exact_log(p) + e = ZZ(n / m).exact_log(p) else: m = n e = 0 @@ -1764,13 +1724,13 @@ def which_group(list_of_elements): # This determines the maximal cyclic subgroup and the maximal cyclic # p-regular subgroup. Algorithm terminates if the order of this subgroup agrees with # the order of the group. - max_reg_cyclic = [1, z, [z]] # initialize order of cyclic p-regular subgroup and generator - discard = [] # list of elements already considered + max_reg_cyclic = [1, z, [z]] # initialize order of cyclic p-regular subgroup and generator + discard = [] # list of elements already considered for g in G: if g not in discard: H = [g] - for i in range(n-1): + for i in range(n - 1): h = g(H[-1]) H.append(h) H = list(set(H)) @@ -1778,14 +1738,14 @@ def which_group(list_of_elements): return 'Cyclic of order {0}'.format(n) if len(H) > max_reg_cyclic[0] and gcd(len(H), p) != p: max_reg_cyclic = [len(H), g, H] - discard = list(set(discard + H)) # adjoin all new elements to discard + discard = list(set(discard + H)) # adjoin all new elements to discard n_reg = max_reg_cyclic[0] # Test for dihedral subgroup. A subgroup of index 2 is always normal, so the # presence of a cyclic subgroup H of index 2 indicates the group is either # H x Z/2Z or dihedral. The former occurs only if H has order 1 or 2, both of # which are dihedral. - if 2*n_reg == n: + if 2 * n_reg == n: for g in G: if g not in max_reg_cyclic[2]: return 'Dihedral of order {0}'.format(n) @@ -1794,11 +1754,11 @@ def which_group(list_of_elements): # these are either p-semi-elementary, PGL(2,q), PSL(2,q), or A_5 when p=3. The latter # case is already covered by the remaining sporadic cases below. if e > 0: - if n_reg == m: # p-semi-elementary + if n_reg == m: # p-semi-elementary return '{0}-semi-elementary of order {1}'.format(p, n) - if n_reg == m / (p**e - 1) and m == p**(2*e) - 1: # PGL(2) + if n_reg == m / (p**e - 1) and m == p ** (2 * e) - 1: # PGL(2) return 'PGL(2,{0})'.format(p**e) - if n_reg == m / (p**e - 1) and m == (1/2)*(p**(2*e) - 1): # PSL(2) + if n_reg == m / (p**e - 1) and m == (1 / 2) * (p ** (2 * e) - 1): # PSL(2) return 'PSL(2,{0})'.format(p**e) # Treat sporadic cases @@ -2015,11 +1975,11 @@ def conjugating_set_initializer(f, g): # first subset with the desired property. There is, # however, no guarantee that the subset we found minimizes # the combinatorics when checking conjugations - for subset in Subsets(range(len(all_points)), n+2): + for subset in Subsets(range(len(all_points)), n + 2): source = [] for i in subset: source.append(all_points[i]) - if P.is_linearly_independent(source, n+1): + if P.is_linearly_independent(source, n + 1): more = False corresponding = [] mult_only = [] @@ -2111,8 +2071,8 @@ def greedy_independence_check(P, repeated_mult, point_to_mult): for r in sorted(repeated_mult.keys()): for point_lst in repeated_mult[r]: for point in point_lst: - if len(source) == n+1: - independent = P.is_linearly_independent(source + [point], n+1) + if len(source) == n + 1: + independent = P.is_linearly_independent(source + [point], n + 1) else: independent = P.is_linearly_independent(source + [point]) if independent: @@ -2127,7 +2087,7 @@ def greedy_independence_check(P, repeated_mult, point_to_mult): corresponding.append([mult, 1]) else: corresponding.append([mult, 1]) - if len(source) == n+2: + if len(source) == n + 2: return source, corresponding @@ -2196,7 +2156,7 @@ def find_conjugations_subset(tuples): # if there is a subset of n+1 points which is linearly dependent, # we don't need to check any of these arrangements - if P.is_linearly_independent(target_set, n+1): + if P.is_linearly_independent(target_set, n + 1): subset_arrangements = [] for subset in tup: subset_arrangements.append(Arrangements(subset, len(subset))) @@ -2236,7 +2196,7 @@ def find_conjugations_arrangement(tuples): if len(all_subsets) > num_cpus: for i in range(num_cpus): start = (len(all_subsets) * i) // num_cpus - end = (len(all_subsets) * (i+1)) // num_cpus + end = (len(all_subsets) * (i + 1)) // num_cpus tuples = all_subsets[start:end] parallel_data.append(([tuples], {})) @@ -2254,7 +2214,7 @@ def find_conjugations_arrangement(tuples): for i in range(len(tup)): for j in tup[i]: target_set.append(possible_targets[i][0][j]) - if P.is_linearly_independent(target_set, n+1): + if P.is_linearly_independent(target_set, n + 1): good_targets.append(tup) all_arrangements = [] for tup in good_targets: @@ -2265,7 +2225,7 @@ def find_conjugations_arrangement(tuples): parallel_data = [] for i in range(num_cpus): start = (len(all_arrangements) * i) // num_cpus - end = (len(all_arrangements) * (i+1)) // num_cpus + end = (len(all_arrangements) * (i + 1)) // num_cpus tuples = all_arrangements[start:end] parallel_data.append(([tuples], {})) X = p_iter_fork(num_cpus) @@ -2337,7 +2297,7 @@ def find_conjugations_subset(tuples): # if there is a subset of n+1 points which is linearly dependent, # we don't need to check any of these arrangements - if P.is_linearly_independent(target_set, n+1): + if P.is_linearly_independent(target_set, n + 1): subset_arrangements = [] for subset in tup: subset_arrangements.append(Arrangements(subset, len(subset))) @@ -2375,7 +2335,7 @@ def find_conjugations_arrangement(tuples): if len(all_subsets) > num_cpus: for i in range(num_cpus): start = (len(all_subsets) * i) // num_cpus - end = (len(all_subsets) * (i+1)) // num_cpus + end = (len(all_subsets) * (i + 1)) // num_cpus tuples = all_subsets[start:end] parallel_data.append(([tuples], {})) @@ -2394,7 +2354,7 @@ def find_conjugations_arrangement(tuples): for i in range(len(tup)): for j in tup[i]: target_set.append(possible_targets[i][0][j]) - if P.is_linearly_independent(target_set, n+1): + if P.is_linearly_independent(target_set, n + 1): good_targets.append(tup) all_arrangements = [] for tup in good_targets: @@ -2405,7 +2365,7 @@ def find_conjugations_arrangement(tuples): parallel_data = [] for i in range(num_cpus): start = (len(all_arrangements) * i) // num_cpus - end = (len(all_arrangements) * (i+1)) // num_cpus + end = (len(all_arrangements) * (i + 1)) // num_cpus tuples = all_arrangements[start:end] parallel_data.append(([tuples], {})) X = p_iter_fork(num_cpus) diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py b/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py index 1c190541a51..4c5feaf0458 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py @@ -71,9 +71,8 @@ def bCheck(c, v, p, b): coeffs = c.coefficients(sparse=False) lcoeff = coeffs[deg] coeffs.remove(lcoeff) - check1 = [(coeffs[i].valuation(p) - lcoeff.valuation(p))/(deg - i) - for i in range(len(coeffs)) if coeffs[i] != 0] - check2 = (val - lcoeff.valuation(p))/deg + check1 = [(coeffs[i].valuation(p) - lcoeff.valuation(p)) / (deg - i) for i in range(len(coeffs)) if coeffs[i] != 0] + check2 = (val - lcoeff.valuation(p)) / deg check1.append(check2) bval = min(check1) return (bval).ceil() @@ -112,7 +111,7 @@ def scale(c, v, p): """ scaleval = min([coeff.valuation(p) for coeff in c.coefficients()]) if scaleval > 0: - c = c/(p**scaleval) + c = c / (p**scaleval) v = v - scaleval if v <= 0: flag = False @@ -159,53 +158,53 @@ def blift(LF, Li, p, k, S=None, all_orbits=False): """ P = LF[0].parent() - #Determine which inequalities are trivial, and scale the rest, so that we only lift - #as many times as needed. - keepScaledIneqs = [scale(P(coeff),Li,p) for coeff in LF if coeff != 0] + # Determine which inequalities are trivial, and scale the rest, so that we only lift + # as many times as needed. + keepScaledIneqs = [scale(P(coeff), Li, p) for coeff in LF if coeff != 0] keptVals = [i[2] for i in keepScaledIneqs if i[0]] if keptVals: # Determine the valuation to lift until. # liftval = max(keptVals) pass else: - #All inequalities are satisfied. + # All inequalities are satisfied. if all_orbits: return [[True, t] for t in range(p)] return [[True, 1]] if S is None: S = PolynomialRing(Zmod(p), 'b') keptScaledIneqs = [S(i[1]) for i in keepScaledIneqs if i[0]] - #We need a solution for each polynomial on the left hand side of the inequalities, - #so we need only find a solution for their gcd. + # We need a solution for each polynomial on the left hand side of the inequalities, + # so we need only find a solution for their gcd. g = gcd(keptScaledIneqs) rts = g.roots(multiplicities=False) good = [] for r in rts: - #Recursively try to lift each root + # Recursively try to lift each root r_initial = QQ(r) newInput = P([r_initial, p]) LG = [F(newInput) for F in LF] new_good = blift(LG, Li, p, k, S=S) - for lift,lifted in new_good: + for lift, lifted in new_good: if lift: - #Lift successful. + # Lift successful. if not all_orbits: - return [[True, r_initial + p*lifted]] + return [[True, r_initial + p * lifted]] - #only need up to SL(2,ZZ) equivalence - #this helps control the size of the resulting coefficients - if r_initial + p*lifted < p**k: - good.append([True, r_initial + p*lifted]) + # only need up to SL(2,ZZ) equivalence + # this helps control the size of the resulting coefficients + if r_initial + p * lifted < p**k: + good.append([True, r_initial + p * lifted]) else: - new_r = r_initial + p*lifted - p**k + new_r = r_initial + p * lifted - p**k while new_r > p**k: new_r -= p**k if [True, new_r] not in good: good.append([True, new_r]) if good: return good - #Lift non successful. - return [[False,0]] + # Lift non successful. + return [[False, 0]] def affine_minimal(vp, return_transformation=False, D=None, quick=False): @@ -251,6 +250,7 @@ def affine_minimal(vp, return_transformation=False, D=None, quick=False): ) """ from sage.dynamics.arithmetic_dynamics.affine_ds import DynamicalSystem_affine + BR = vp.domain().base_ring() conj = matrix(BR, 2, 2, 1) flag = True @@ -260,7 +260,7 @@ def affine_minimal(vp, return_transformation=False, D=None, quick=False): Affvp = vp.dehomogenize(1) R = Affvp.coordinate_ring() if R.is_field(): - #want the polynomial ring not the fraction field + # want the polynomial ring not the fraction field R = R.ring() F = R(Affvp[0].numerator()) G = R(Affvp[0].denominator()) @@ -269,36 +269,36 @@ def affine_minimal(vp, return_transformation=False, D=None, quick=False): z = F.parent().gen(0) minG = G - #If the valuation of a prime in the resultant is small enough, we can say the - #map is affine minimal at that prime without using the local minimality loop. See - #Theorem 3.2.2 in [Molnar, M.Sc. thesis] + # If the valuation of a prime in the resultant is small enough, we can say the + # map is affine minimal at that prime without using the local minimality loop. See + # Theorem 3.2.2 in [Molnar, M.Sc. thesis] if d % 2 == 0: g = d else: - g = 2*d + g = 2 * d Res = vp.resultant() - #Some quantities needed for the local minimization loop, but we compute now - #since the value is constant, so we do not wish to compute in every local loop. - #See Theorem 3.3.3 in [Molnar, M.Sc thesis] + # Some quantities needed for the local minimization loop, but we compute now + # since the value is constant, so we do not wish to compute in every local loop. + # See Theorem 3.3.3 in [Molnar, M.Sc thesis] H = F - z * minG A = AffineSpace(BR, 1, H.parent().variable_name()) - ubRes = DynamicalSystem_affine([H/minG], domain=A).homogenize(1).resultant() - #Set the primes to check minimality at, if not already prescribed + ubRes = DynamicalSystem_affine([H / minG], domain=A).homogenize(1).resultant() + # Set the primes to check minimality at, if not already prescribed if D is None: D = ZZ(Res).prime_divisors() - #Check minimality at all primes in D. If D is all primes dividing - #Res(minF/minG), this is enough to show whether minF/minG is minimal or not. See - #Propositions 3.2.1 and 3.3.7 in [Molnar, M.Sc. thesis]. + # Check minimality at all primes in D. If D is all primes dividing + # Res(minF/minG), this is enough to show whether minF/minG is minimal or not. See + # Propositions 3.2.1 and 3.3.7 in [Molnar, M.Sc. thesis]. for p in D: while True: if Res.valuation(p) < g: - #The model is minimal at p + # The model is minimal at p min = True else: - #The model may not be minimal at p. - newvp,conj = Min(vp, p, ubRes, conj, all_orbits=False) + # The model may not be minimal at p. + newvp, conj = Min(vp, p, ubRes, conj, all_orbits=False) if newvp == vp: min = True else: @@ -306,20 +306,20 @@ def affine_minimal(vp, return_transformation=False, D=None, quick=False): Affvp = vp.dehomogenize(1) min = False if min: - #The model is minimal at p + # The model is minimal at p break elif F == Affvp[0].numerator() and G == Affvp[0].denominator(): - #The model is minimal at p + # The model is minimal at p break else: - #The model is not minimal at p + # The model is not minimal at p flag = False if quick: break if quick and not flag: break - if quick: #only return whether the model is minimal + if quick: # only return whether the model is minimal return flag if return_transformation: @@ -373,17 +373,17 @@ def Min(Fun, p, ubRes, conj, all_orbits=False): AffFun = Fun.dehomogenize(1) R = AffFun.coordinate_ring() if R.is_field(): - #want the polynomial ring not the fraction field + # want the polynomial ring not the fraction field R = R.ring() F = R(AffFun[0].numerator()) G = R(AffFun[0].denominator()) dG = G.degree() # all_orbits scales bounds for >= and <= if searching for orbits instead of min model - if dG > (d+1)/2: - lowerBound = (-2*(G[dG]).valuation(p)/(2*dG - d + 1) + 1).floor() - int(all_orbits) + if dG > (d + 1) / 2: + lowerBound = (-2 * (G[dG]).valuation(p) / (2 * dG - d + 1) + 1).floor() - int(all_orbits) else: - lowerBound = (-2*(F[d]).valuation(p)/(d-1) + 1).floor() - int(all_orbits) - upperBound = 2*(ubRes.valuation(p)) + int(all_orbits) + lowerBound = (-2 * (F[d]).valuation(p) / (d - 1) + 1).floor() - int(all_orbits) + upperBound = 2 * (ubRes.valuation(p)) + int(all_orbits) if upperBound < lowerBound: # There are no possible transformations to reduce the resultant. @@ -394,14 +394,14 @@ def Min(Fun, p, ubRes, conj, all_orbits=False): # the resultant of F/G all_found = [] k = lowerBound - Qb = PolynomialRing(QQ,'b') + Qb = PolynomialRing(QQ, 'b') b = Qb.gen(0) - Q = PolynomialRing(Qb,'z') + Q = PolynomialRing(Qb, 'z') z = Q.gen(0) while k <= upperBound: - A = (p**k)*z + b - Ft = Q(F(A) - b*G(A)) - Gt = Q((p**k)*G(A)) + A = (p**k) * z + b + Ft = Q(F(A) - b * G(A)) + Gt = Q((p**k) * G(A)) Fcoeffs = Ft.coefficients(sparse=False) Gcoeffs = Gt.coefficients(sparse=False) coeffs = Fcoeffs + Gcoeffs @@ -409,8 +409,7 @@ def Min(Fun, p, ubRes, conj, all_orbits=False): # If there is some b such that Res(phi^A) < Res(phi), we must have # ord_p(c) > RHS for each c in coeffs. # Make sure constant coefficients in coeffs satisfy the inequality. - if all(QQ(c).valuation(p) > RHS - int(all_orbits) - for c in coeffs if c.degree() == 0): + if all(QQ(c).valuation(p) > RHS - int(all_orbits) for c in coeffs if c.degree() == 0): # Constant coefficients in coeffs have large enough valuation, so # check the rest. We start by checking if simply picking b=0 works. if all(c(0).valuation(p) > RHS - int(all_orbits) for c in coeffs): @@ -420,7 +419,7 @@ def Min(Fun, p, ubRes, conj, all_orbits=False): minFun = Fun.conjugate(newconj) minFun.normalize_coordinates() if not all_orbits: - return [minFun, conj*newconj] + return [minFun, conj * newconj] all_found.append([p, k, 0]) # Otherwise we search if any value of b will work. We start by @@ -430,7 +429,7 @@ def Min(Fun, p, ubRes, conj, all_orbits=False): # We scale the coefficients in coeffs, so that we may assume # ord_p(b) is at least 0 - scaledCoeffs = [coeff(b*(p**bval)) for coeff in coeffs] + scaledCoeffs = [coeff(b * (p**bval)) for coeff in coeffs] # We now scale the inequalities, ord_p(coeff) > RHS, so that # coeff is in ZZ[b] @@ -447,33 +446,34 @@ def Min(Fun, p, ubRes, conj, all_orbits=False): # is not minimal. for boolval, sol in all_blift: if boolval: - #Rescale, conjugate and return new map + # Rescale, conjugate and return new map bsol = QQ(sol * (p**bval)) - #only add 'minimal orbit element' + # only add 'minimal orbit element' while bsol.abs() >= p**k: if bsol < 0: bsol += p**k else: bsol -= p**k - #"Conjugating by ", p,"^", k, "*z +", bsol + # "Conjugating by ", p,"^", k, "*z +", bsol newconj = matrix(QQ, 2, 2, [p**k, bsol, 0, 1]) minFun = Fun.conjugate(newconj) minFun.normalize_coordinates() if not all_orbits: - return [minFun, conj*newconj] - if [p,k,bsol] not in all_found: + return [minFun, conj * newconj] + if [p, k, bsol] not in all_found: all_found.append([p, k, bsol]) k = k + 1 if not all_orbits: return [Fun, conj] return all_found + ################################################### # algorithms from Hutz-Stoll ################################################### -#modification of Bruin-Molnar for all representatives +# modification of Bruin-Molnar for all representatives def BM_all_minimal(vp, return_transformation=False, D=None): @@ -544,7 +544,7 @@ def BM_all_minimal(vp, return_transformation=False, D=None): BR = mp.domain().base_ring() MS = MatrixSpace(QQ, 2) M_Id = MS.one() - F, G = list(mp) #coordinate polys + F, G = list(mp) # coordinate polys aff_map = mp.dehomogenize(1) f, g = aff_map[0].numerator(), aff_map[0].denominator() z = aff_map.domain().gen(0) @@ -552,9 +552,10 @@ def BM_all_minimal(vp, return_transformation=False, D=None): # because of how the bound is compute in lemma 3.3 from sage.dynamics.arithmetic_dynamics.affine_ds import DynamicalSystem_affine - h = f - z*g + + h = f - z * g A = AffineSpace(BR, 1, h.parent().variable_name()) - res = DynamicalSystem_affine([h/g], domain=A).homogenize(1).resultant() + res = DynamicalSystem_affine([h / g], domain=A).homogenize(1).resultant() if D is None: D = ZZ(Res).prime_divisors() @@ -569,26 +570,24 @@ def BM_all_minimal(vp, return_transformation=False, D=None): if [p, 0, 0] not in all_pM[-1]: all_pM[-1].append([p, 0, 0]) - #combine conjugations for all primes + # combine conjugations for all primes all_M = [M_Id] for prime_data in all_pM: - #these are (p,k,b) so that the matrix is [p^k,b,0,1] + # these are (p,k,b) so that the matrix is [p^k,b,0,1] new_M = [] if prime_data: p = prime_data[0][0] for m in prime_data: - mat = MS([m[0]**m[1], m[2], 0, 1]) + mat = MS([m[0] ** m[1], m[2], 0, 1]) new_map = mp.conjugate(mat) new_map.normalize_coordinates() # make sure the resultant didn't change and that it is a different SL(2,ZZ) orbit - if (mat == M_Id) or (new_map.resultant().valuation(p) == Res.valuation(p) - and mat.det() not in [1,-1]): + if (mat == M_Id) or (new_map.resultant().valuation(p) == Res.valuation(p) and mat.det() not in [1, -1]): new_M.append(m) if new_M: - all_M = [m1 * MS([m[0]**m[1], m[2], 0, 1]) - for m1 in all_M for m in new_M] + all_M = [m1 * MS([m[0] ** m[1], m[2], 0, 1]) for m1 in all_M for m in new_M] - #get all models with same resultant + # get all models with same resultant all_maps = [] for M in all_M: new_map = mp.conjugate(M) @@ -596,9 +595,9 @@ def BM_all_minimal(vp, return_transformation=False, D=None): if [new_map, M] not in all_maps: all_maps.append([new_map, M]) - #Split into conjugacy classes - #We just keep track of the two matrices that come from - #the original to get the conjugation that goes between these!! + # Split into conjugacy classes + # We just keep track of the two matrices that come from + # the original to get the conjugation that goes between these!! classes = [] for funct, mat in all_maps: if not classes: @@ -606,11 +605,11 @@ def BM_all_minimal(vp, return_transformation=False, D=None): else: found = False for Func, Mat in classes: - #get conjugation + # get conjugation M = mat.inverse() * Mat assert funct.conjugate(M) == Func - if M.det() in [1,-1]: - #same SL(2,Z) orbit + if M.det() in [1, -1]: + # same SL(2,Z) orbit found = True break if found is False: @@ -620,11 +619,12 @@ def BM_all_minimal(vp, return_transformation=False, D=None): return classes return [funct for funct, matr in classes] + ################################################### # enumerative algorithms from Hutz-Stoll ################################################### -#find minimal model +# find minimal model def HS_minimal(f, return_transformation=False, D=None): @@ -693,30 +693,31 @@ def HS_minimal(f, return_transformation=False, D=None): F1.normalize_coordinates() res1 = F1.resultant() vp1 = res1.valuation(p) - if vp1 < vp: # check if smaller + if vp1 < vp: # check if smaller F = F1 vp = vp1 - m = m * t # keep track of conjugation + m = m * t # keep track of conjugation minimal = False else: # still search for smaller for b in range(p): - t = matrix(ZZ,2,2,[p, b, 0, 1]) + t = matrix(ZZ, 2, 2, [p, b, 0, 1]) F1 = F.conjugate(t) F1.normalize_coordinates() res1 = ZZ(F1.resultant()) vp1 = res1.valuation(p) - if vp1 < vp: # check if smaller + if vp1 < vp: # check if smaller F = F1 - m = m * t # keep track of transformation + m = m * t # keep track of transformation minimal = False vp = vp1 - break # exit for loop + break # exit for loop if return_transformation: return F, m return F -#find all representatives of orbits for one prime + +# find all representatives of orbits for one prime def HS_all_minimal_p(p, f, m=None, return_transformation=False): @@ -763,7 +764,7 @@ def HS_all_minimal_p(p, f, m=None, return_transformation=False): True """ count = 0 - prev = 0 # no exclusions + prev = 0 # no exclusions F = copy(f) res = ZZ(F.resultant()) vp = res.valuation(p) @@ -776,8 +777,8 @@ def HS_all_minimal_p(p, f, m=None, return_transformation=False): if return_transformation: return [[f, m]] return [f] - to_do = [[F, m, prev]] # repns left to check - reps = [[F, m]] # orbit representatives for f + to_do = [[F, m, prev]] # repns left to check + reps = [[F, m]] # orbit representatives for f while to_do: F, m, prev = to_do.pop() # there are at most two directions preserving the resultant @@ -785,7 +786,7 @@ def HS_all_minimal_p(p, f, m=None, return_transformation=False): count = 0 else: count = 1 - if prev != 2: # [p,a,0,1] + if prev != 2: # [p,a,0,1] t = MS([1, 0, 0, p]) F1 = F.conjugate(t) F1.normalize_coordinates() @@ -794,9 +795,9 @@ def HS_all_minimal_p(p, f, m=None, return_transformation=False): if vp1 == vp: count += 1 # we have a new representative - reps.append([F1, m*t]) + reps.append([F1, m * t]) # need to check if it has any neighbors - to_do.append([F1, m*t, 1]) + to_do.append([F1, m * t, 1]) for b in range(p): if not (b == 0 and prev == 1): t = MS([p, b, 0, 1]) @@ -807,17 +808,18 @@ def HS_all_minimal_p(p, f, m=None, return_transformation=False): if vp1 == vp: count += 1 # we have a new representative - reps.append([F1, m*t]) + reps.append([F1, m * t]) # need to check if it has any neighbors - to_do.append([F1, m*t, 2]) - if count >= 2: # at most two neighbors + to_do.append([F1, m * t, 2]) + if count >= 2: # at most two neighbors break if return_transformation: return reps return [funct for funct, matr in reps] -#find all representatives of orbits + +# find all representatives of orbits def HS_all_minimal(f, return_transformation=False, D=None): @@ -886,7 +888,7 @@ def HS_all_minimal(f, return_transformation=False, D=None): if F.degree() == 1: raise ValueError("function must be degree at least 2") if f.degree() % 2 == 0: - #there is only one orbit for even degree + # there is only one orbit for even degree if return_transformation: return [[f, m]] return [f] @@ -898,14 +900,15 @@ def HS_all_minimal(f, return_transformation=False, D=None): # get p-orbits Mp = HS_all_minimal_p(p, F, m, return_transformation=True) # combine with previous orbits representatives - M = [[g.conjugate(t), t*s] for g,s in M for G,t in Mp] + M = [[g.conjugate(t), t * s] for g, s in M for G, t in Mp] if return_transformation: return M return [funct for funct, matr in M] + ####################### -#functionality for smallest coefficients +# functionality for smallest coefficients # # Ben Hutz July 2018 #####################################3 @@ -948,8 +951,9 @@ def get_bound_dynamical(F, f, m=1, dynatomic=True, prec=53, emb=None): from sage.symbolic.constants import e def coshdelta(z): - #The cosh of the hyperbolic distance from z = t+uj to j - return (z.norm() + 1)/(2*z.imag()) + # The cosh of the hyperbolic distance from z = t+uj to j + return (z.norm() + 1) / (2 * z.imag()) + if F.base_ring() != ComplexField(prec=prec): if emb is None: compF = F.change_ring(ComplexField(prec=prec)) @@ -961,27 +965,22 @@ def coshdelta(z): z0F, thetaF = covariant_z0(compF, prec=prec, emb=emb) d = f.degree() - hF = e**f.global_height(prec=prec) - #get precomputed constants C,k + hF = e ** f.global_height(prec=prec) + # get precomputed constants C,k if m == 1: - C = 4*d+2 + C = 4 * d + 2 k = 2 else: - Ck_values = {(False, 2, 2): (322, 6), (False, 2, 3): (385034, 14), - (False, 2, 4): (4088003923454, 30), (False, 3, 2): (18044, 8), - (False, 4, 2): (1761410, 10), (False, 5, 2): (269283820, 12), - (True, 2, 2): (43, 4), (True, 2, 3): (106459, 12), - (True, 2, 4): (39216735905, 24), (True, 3, 2): (1604, 6), - (True, 4, 2): (114675, 8), (True, 5, 2): (14158456, 10)} + Ck_values = {(False, 2, 2): (322, 6), (False, 2, 3): (385034, 14), (False, 2, 4): (4088003923454, 30), (False, 3, 2): (18044, 8), (False, 4, 2): (1761410, 10), (False, 5, 2): (269283820, 12), (True, 2, 2): (43, 4), (True, 2, 3): (106459, 12), (True, 2, 4): (39216735905, 24), (True, 3, 2): (1604, 6), (True, 4, 2): (114675, 8), (True, 5, 2): (14158456, 10)} try: - C, k = Ck_values[(dynatomic,d,m)] + C, k = Ck_values[(dynatomic, d, m)] except KeyError: raise ValueError("constants not computed for this (m,d) pair") if n == 2 and d == 2: - #bound with epsilonF = 1 - bound = 2*((2*C*(hF**k))/(thetaF)) + # bound with epsilonF = 1 + bound = 2 * ((2 * C * (hF**k)) / (thetaF)) else: - bound = cosh(epsinv(F, (2**(n-1))*C*(hF**k)/thetaF, prec=prec)) + bound = cosh(epsinv(F, (2 ** (n - 1)) * C * (hF**k) / thetaF, prec=prec)) return bound @@ -1053,76 +1052,77 @@ def insert_item(pts, item, index): left = 1 right = N mid = (left + right) // 2 # these are ints so this is .floor() - if item[index] > pts[mid][index]: # item goes into first half + if item[index] > pts[mid][index]: # item goes into first half return insert_item(pts[:mid], item, index) + pts[mid:N] # item goes into second half return pts[:mid] + insert_item(pts[mid:N], item, index) def coshdelta(z): # The cosh of the hyperbolic distance from z = t+uj to j - return (z.norm() + 1)/(2*z.imag()) + return (z.norm() + 1) / (2 * z.imag()) # can't be smaller if height 0 f.normalize_coordinates() if f.global_height(prec=prec) == 0: - return [f, matrix(ZZ,2,2,[1,0,0,1])] + return [f, matrix(ZZ, 2, 2, [1, 0, 0, 1])] all_min = f.all_minimal_models(return_transformation=True, algorithm=algorithm, check_minimal=check_minimal) current_min = None current_size = None # search for minimum over all orbits - for g,M in all_min: + for g, M in all_min: PS = g.domain() CR = PS.coordinate_ring() - x,y = CR.gens() - n = start_n # sometimes you get a problem later with 0,infty as roots + x, y = CR.gens() + n = start_n # sometimes you get a problem later with 0,infty as roots if dynatomic: pts_poly = g.dynatomic_polynomial(n) else: gn = g.nth_iterate_map(n) - pts_poly = y*gn[0] - x*gn[1] + pts_poly = y * gn[0] - x * gn[1] d = ZZ(pts_poly.degree()) - max_mult = max([ex for p,ex in pts_poly.factor()]) - while ((d < 3) or (max_mult >= d/2) and (n < 5)): - n = n+1 + max_mult = max([ex for p, ex in pts_poly.factor()]) + while (d < 3) or (max_mult >= d / 2) and (n < 5): + n = n + 1 if dynatomic: pts_poly = g.dynatomic_polynomial(n) else: gn = g.nth_iterate_map(n) - pts_poly = y*gn[0] - x*gn[1] + pts_poly = y * gn[0] - x * gn[1] d = ZZ(pts_poly.degree()) max_mult = max([ex for _, ex in pts_poly.factor()]) - assert (n <= 4), "n > 4, failed to find usable poly" + assert n <= 4, "n > 4, failed to find usable poly" R = get_bound_dynamical(pts_poly, g, m=n, dynatomic=dynatomic, prec=prec, emb=emb) # search starts in fundamental domain - G,MG = pts_poly.reduced_form(prec=prec, emb=emb, smallest_coeffs=False) - red_g = f.conjugate(M*MG) + G, MG = pts_poly.reduced_form(prec=prec, emb=emb, smallest_coeffs=False) + red_g = f.conjugate(M * MG) if G != pts_poly: R2 = get_bound_dynamical(G, red_g, m=n, dynatomic=dynatomic, prec=prec, emb=emb) R = min(R2, R) red_g.normalize_coordinates() if red_g.global_height(prec=prec) == 0: - return [red_g, M*MG] + return [red_g, M * MG] # height if current_size is None: - current_size = e**red_g.global_height(prec=prec) + current_size = e ** red_g.global_height(prec=prec) v0, th = covariant_z0(G, prec=prec, emb=emb) - rep = 2*CC.gen(0) + rep = 2 * CC.gen(0) from math import isnan + if isnan(v0.abs()): raise ValueError("invalid covariant: %s" % v0) # get orbit - S = matrix(ZZ,2,2,[0,-1,1,0]) - T = matrix(ZZ,2,2,[1,1,0,1]) - TI = matrix(ZZ,2,2,[1,-1,0,1]) + S = matrix(ZZ, 2, 2, [0, -1, 1, 0]) + T = matrix(ZZ, 2, 2, [1, 1, 0, 1]) + TI = matrix(ZZ, 2, 2, [1, -1, 0, 1]) count = 0 - pts = [[G, red_g, v0, rep, M*MG, coshdelta(v0), 0]] # label - 0:None, 1:S, 2:T, 3:T^(-1) + pts = [[G, red_g, v0, rep, M * MG, coshdelta(v0), 0]] # label - 0:None, 1:S, 2:T, 3:T^(-1) if current_min is None: - current_min = [G, red_g, v0, rep, M*MG, coshdelta(v0)] + current_min = [G, red_g, v0, rep, M * MG, coshdelta(v0)] while pts != []: G, g, v, rep, M, D, label = pts.pop() # apply ST and keep z, Sz @@ -1130,7 +1130,7 @@ def coshdelta(z): break # all remaining pts are too far away # check if it is smaller. If so, we can improve the bound count += 1 - new_size = e**g.global_height(prec=prec) + new_size = e ** g.global_height(prec=prec) if new_size < current_size: current_min = [G, g, v, rep, M, coshdelta(v)] current_size = new_size @@ -1140,24 +1140,24 @@ def coshdelta(z): R = min(new_R, R) # add new points to check - if label != 1 and min((rep+1).norm(), (rep-1).norm()) >= 1: # don't undo S + if label != 1 and min((rep + 1).norm(), (rep - 1).norm()) >= 1: # don't undo S # the 2nd condition is equivalent to |\Re(-1/rep)| <= 1/2 # this means that rep can have resulted from an inversion step in # the shift-and-invert procedure, so don't invert # do inversion - z = -1/v - new_pt = [G.subs({x:-y, y:x}), g.conjugate(S), z, -1/rep, M*S, coshdelta(z), 1] + z = -1 / v + new_pt = [G.subs({x: -y, y: x}), g.conjugate(S), z, -1 / rep, M * S, coshdelta(z), 1] pts = insert_item(pts, new_pt, 5) if label != 3: # don't undo T on g # do right shift - z = v-1 - new_pt = [G.subs({x:x+y}), g.conjugate(TI), z, rep-1, M*TI, coshdelta(z), 2] + z = v - 1 + new_pt = [G.subs({x: x + y}), g.conjugate(TI), z, rep - 1, M * TI, coshdelta(z), 2] pts = insert_item(pts, new_pt, 5) if label != 2: # don't undo TI on g # do left shift - z = v+1 - new_pt = [G.subs({x:x-y}), g.conjugate(T), z, rep+1, M*T, coshdelta(z), 3] + z = v + 1 + new_pt = [G.subs({x: x - y}), g.conjugate(T), z, rep + 1, M * T, coshdelta(z), 3] pts = insert_item(pts, new_pt, 5) return [current_min[1], current_min[4]] diff --git a/src/sage/dynamics/arithmetic_dynamics/generic_ds.py b/src/sage/dynamics/arithmetic_dynamics/generic_ds.py index d5ecbab406e..449a14bb8a8 100644 --- a/src/sage/dynamics/arithmetic_dynamics/generic_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/generic_ds.py @@ -43,8 +43,7 @@ class initialization directly. lazy_import('sage.rings.qqbar', 'AlgebraicField_common') -class DynamicalSystem(SchemeMorphism_polynomial, - metaclass=InheritComparisonClasscallMetaclass): +class DynamicalSystem(SchemeMorphism_polynomial, metaclass=InheritComparisonClasscallMetaclass): r""" Base class for dynamical systems of schemes. @@ -165,15 +164,17 @@ def __classcall_private__(cls, morphism_or_polys, domain=None, names=None): if isinstance(morphism_or_polys, SchemeMorphism_polynomial): domain = morphism_or_polys.domain() if domain is not None: - if isinstance(domain, (AffineSpace_generic, - AlgebraicScheme_subscheme_affine)): + if isinstance(domain, (AffineSpace_generic, AlgebraicScheme_subscheme_affine)): from sage.dynamics.arithmetic_dynamics.affine_ds import DynamicalSystem_affine + return DynamicalSystem_affine(morphism_or_polys, domain) if isinstance(domain, Berkovich_Cp): from sage.dynamics.arithmetic_dynamics.berkovich_ds import DynamicalSystem_Berkovich - return DynamicalSystem_Berkovich(morphism_or_polys,domain) + + return DynamicalSystem_Berkovich(morphism_or_polys, domain) from sage.dynamics.arithmetic_dynamics.projective_ds import DynamicalSystem_projective + return DynamicalSystem_projective(morphism_or_polys, domain, names) def __init__(self, polys_or_rat_fncts, domain): @@ -415,13 +416,13 @@ def field_of_definition_critical(self, return_embedding=False, simplify_all=Fals return K if space.is_projective(): ds = ds.dehomogenize(1) - f,g = ds[0].numerator(), ds[0].denominator() + f, g = ds[0].numerator(), ds[0].denominator() CR = space.coordinate_ring() if CR.is_field(): - #want the polynomial ring not the fraction field + # want the polynomial ring not the fraction field CR = CR.ring() x = CR.gen(0) - poly = (g*CR(f).derivative(x) - f*CR(g).derivative(x)).univariate_polynomial() + poly = (g * CR(f).derivative(x) - f * CR(g).derivative(x)).univariate_polynomial() if isinstance(ds.base_ring(), FiniteField): return poly.splitting_field(names, map=return_embedding) K = poly.splitting_field(names, map=return_embedding, simplify_all=simplify_all) @@ -431,7 +432,7 @@ def field_of_definition_critical(self, return_embedding=False, simplify_all=Fals N = K if N.absolute_degree() == 1: if return_embedding: - return (QQ,ds.base_ring().embeddings(QQ)[0]) + return (QQ, ds.base_ring().embeddings(QQ)[0]) return QQ return K @@ -532,7 +533,7 @@ def field_of_definition_periodic(self, n, formal=False, return_embedding=False, ds = ds.dehomogenize(1) CR = space.coordinate_ring() if CR.is_field(): - #want the polynomial ring not the fraction field + # want the polynomial ring not the fraction field CR = CR.ring() x = CR.gen(0) if formal: @@ -540,8 +541,8 @@ def field_of_definition_periodic(self, n, formal=False, return_embedding=False, poly = CR(poly).univariate_polynomial() else: fn = ds.nth_iterate_map(n) - f,g = fn[0].numerator(), fn[0].denominator() - poly = (f - g*x).univariate_polynomial() + f, g = fn[0].numerator(), fn[0].denominator() + poly = (f - g * x).univariate_polynomial() if isinstance(ds.base_ring(), FiniteField): return poly.splitting_field(names, map=return_embedding) K = poly.splitting_field(names, map=return_embedding, simplify_all=simplify_all) @@ -551,7 +552,7 @@ def field_of_definition_periodic(self, n, formal=False, return_embedding=False, N = K if N.absolute_degree() == 1: if return_embedding: - return (QQ,ds.base_ring().embeddings(QQ)[0]) + return (QQ, ds.base_ring().embeddings(QQ)[0]) return QQ return K @@ -629,14 +630,14 @@ def field_of_definition_preimage(self, point, n, return_embedding=False, simplif if space.is_projective(): ds = ds.dehomogenize(1) else: - point = (point[0],1) + point = (point[0], 1) fn = ds.nth_iterate_map(n) f, g = fn[0].numerator(), fn[0].denominator() CR = space.coordinate_ring() if CR.is_field(): - #want the polynomial ring not the fraction field + # want the polynomial ring not the fraction field CR = CR.ring() - poly = (f*point[1] - g*CR(point[0])).univariate_polynomial() + poly = (f * point[1] - g * CR(point[0])).univariate_polynomial() if isinstance(ds.base_ring(), FiniteField): return poly.splitting_field(names, map=return_embedding) K = poly.splitting_field(names, map=return_embedding, simplify_all=simplify_all) diff --git a/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py index 338df23a183..18bb960f64a 100644 --- a/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py @@ -16,6 +16,7 @@ Defn: Defined by sending (x : y , u : v) to (x^2*u : y^2*v , x*v^2 : y*u^2). """ + # **************************************************************************** # Copyright (C) 2014 Ben Hutz # @@ -32,8 +33,7 @@ from sage.schemes.product_projective.morphism import ProductProjectiveSpaces_morphism_ring -class DynamicalSystem_product_projective(DynamicalSystem, - ProductProjectiveSpaces_morphism_ring): +class DynamicalSystem_product_projective(DynamicalSystem, ProductProjectiveSpaces_morphism_ring): r""" The class of dynamical systems on products of projective spaces. @@ -99,6 +99,7 @@ def _call_with_args(self, P, check=True): """ if check: from sage.schemes.product_projective.point import ProductProjectiveSpaces_point_ring + if not isinstance(P, ProductProjectiveSpaces_point_ring): try: P = self.domain()(P) @@ -158,7 +159,7 @@ def nth_iterate(self, P, n, normalize=False): Q = self(P) if normalize: Q.normalize_coordinates() - for i in range(2,n+1): + for i in range(2, n + 1): Q = self(Q) if normalize: Q.normalize_coordinates() @@ -210,7 +211,7 @@ def orbit(self, P, N, **kwds): """ if P.codomain() != self.domain(): raise TypeError("point is not defined over domain of function") - if not isinstance(N, (list,tuple)): + if not isinstance(N, (list, tuple)): N = [0, N] try: N[0] = ZZ(N[0]) @@ -228,12 +229,12 @@ def orbit(self, P, N, **kwds): if normalize: Q.normalize_coordinates() - for i in range(1, N[0]+1): + for i in range(1, N[0] + 1): Q = self(Q, check) if normalize: Q.normalize_coordinates() orb = [Q] - for i in range(N[0]+1, N[1]+1): + for i in range(N[0] + 1, N[1] + 1): Q = self(Q, check) if normalize: Q.normalize_coordinates() @@ -326,6 +327,7 @@ def cyclegraph(self): V = [] E = [] from sage.schemes.product_projective.space import ProductProjectiveSpaces_ring + if isinstance(self.domain(), ProductProjectiveSpaces_ring): for P in self.domain(): V.append(str(P)) @@ -334,4 +336,5 @@ def cyclegraph(self): else: raise NotImplementedError("cyclegraph for product projective spaces not implemented for subschemes") from sage.graphs.digraph import DiGraph + return DiGraph(dict(zip(V, E)), loops=True) diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index b0f40a5eeff..07331951748 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -63,17 +63,10 @@ class initialization directly. from sage.categories.function_fields import FunctionFields from sage.categories.homset import End from sage.categories.number_fields import NumberFields -from sage.dynamics.arithmetic_dynamics.endPN_automorphism_group import ( - automorphism_group_QQ_CRT, - automorphism_group_QQ_fixedpoints, - conjugating_set_helper, - conjugating_set_initializer, - is_conjugate_helper) +from sage.dynamics.arithmetic_dynamics.endPN_automorphism_group import automorphism_group_QQ_CRT, automorphism_group_QQ_fixedpoints, conjugating_set_helper, conjugating_set_initializer, is_conjugate_helper from sage.dynamics.arithmetic_dynamics.endPN_automorphism_group import automorphism_group_FF from sage.dynamics.arithmetic_dynamics.generic_ds import DynamicalSystem -from sage.dynamics.arithmetic_dynamics.projective_ds_helper import ( - _fast_possible_periods, - _all_periodic_points) +from sage.dynamics.arithmetic_dynamics.projective_ds_helper import _fast_possible_periods, _all_periodic_points from sage.matrix.constructor import matrix, identity_matrix from sage.misc.cachefunc import cached_method from sage.misc.classcall_metaclass import typecall @@ -101,10 +94,7 @@ class initialization directly. from sage.rings.real_mpfr import RealField from sage.schemes.generic.morphism import SchemeMorphism_polynomial from sage.schemes.product_projective.space import ProductProjectiveSpaces_ring -from sage.schemes.projective.projective_morphism import ( - SchemeMorphism_polynomial_projective_space, - SchemeMorphism_polynomial_projective_space_field, - SchemeMorphism_polynomial_projective_space_finite_field) +from sage.schemes.projective.projective_morphism import SchemeMorphism_polynomial_projective_space, SchemeMorphism_polynomial_projective_space_field, SchemeMorphism_polynomial_projective_space_finite_field from sage.schemes.projective.projective_space import ProjectiveSpace, ProjectiveSpace_ring from sage.schemes.projective.projective_subscheme import AlgebraicScheme_subscheme_projective from sage.structure.element import get_coercion_model @@ -120,8 +110,7 @@ class initialization directly. from cypari2.handle_error import PariError -class DynamicalSystem_projective(SchemeMorphism_polynomial_projective_space, - DynamicalSystem): +class DynamicalSystem_projective(SchemeMorphism_polynomial_projective_space, DynamicalSystem): r"""A dynamical system of projective schemes determined by homogeneous polynomials that define what the morphism does on points in the ambient projective space. @@ -396,22 +385,21 @@ def __classcall_private__(cls, morphism_or_polys, domain=None, names=None): # homogenize! f = morphism_or_polys aff_CR = f.parent() - if (not isinstance(aff_CR, (PolynomialRing_generic, FractionField_generic)) - and not (isinstance(aff_CR, MPolynomialRing_base) and aff_CR.ngens() == 1)): + if not isinstance(aff_CR, (PolynomialRing_generic, FractionField_generic)) and not (isinstance(aff_CR, MPolynomialRing_base) and aff_CR.ngens() == 1): msg = '{} is not a single variable polynomial or rational function' raise ValueError(msg.format(f)) if isinstance(aff_CR, FractionField_generic): - polys = [f.numerator(),f.denominator()] + polys = [f.numerator(), f.denominator()] else: polys = [f, aff_CR(1)] d = max(poly.degree() for poly in polys) if names is None: - names = ('X','Y') + names = ('X', 'Y') elif len(names) != 2: raise ValueError('specify 2 variable names') proj_CR = PolynomialRing(aff_CR.base_ring(), names=names) - X,Y = proj_CR.gens() - polys = [proj_CR(Y**d * poly(X/Y)) for poly in polys] + X, Y = proj_CR.gens() + polys = [proj_CR(Y**d * poly(X / Y)) for poly in polys] if domain is None: PR = get_coercion_model().common_parent(*polys) @@ -439,6 +427,7 @@ def __classcall_private__(cls, morphism_or_polys, domain=None, names=None): raise TypeError(msg.format(polys)) if isinstance(R, FiniteField): from sage.dynamics.arithmetic_dynamics.product_projective_ds import DynamicalSystem_product_projective_finite_field + return DynamicalSystem_product_projective_finite_field(polys, domain) return DynamicalSystem_product_projective(polys, domain) @@ -451,8 +440,7 @@ def __classcall_private__(cls, morphism_or_polys, domain=None, names=None): msg = 'polys (={}) must be of the same degree' raise ValueError(msg.format(polys)) - if not isinstance(domain, (ProjectiveSpace_ring, - AlgebraicScheme_subscheme_projective)): + if not isinstance(domain, (ProjectiveSpace_ring, AlgebraicScheme_subscheme_projective)): raise ValueError('"domain" must be a projective scheme') if R not in Fields(): return typecall(cls, polys, domain) @@ -858,12 +846,12 @@ def dynatomic_polynomial(self, period): if n == 0: return self[0].parent().zero() if m == 0 and n == 1: - return y*F0 - x*F1 + return y * F0 - x * F1 for d in range(1, n): if n % d == 0: - PHI = PHI * ((y*F0 - x*F1)**moebius(n//d)) + PHI = PHI * ((y * F0 - x * F1) ** moebius(n // d)) F0, F1 = f0(F0, F1), f1(F0, F1) - PHI = PHI * (y*F0 - x*F1) + PHI = PHI * (y * F0 - x * F1) if m != 0: fm = self.nth_iterate_map(m) fm1 = self.nth_iterate_map(m - 1) @@ -872,17 +860,17 @@ def dynatomic_polynomial(self, period): if not QR[1]: PHI = QR[0] if m != 0: - PHI = PHI(fm._polys)/(PHI(fm1._polys)) + PHI = PHI(fm._polys) / (PHI(fm1._polys)) QR = PHI.numerator().quo_rem(PHI.denominator()) if QR[1] == 0: PHI = QR[0] return PHI - except (TypeError, NotImplementedError): # something Singular can't handle + except (TypeError, NotImplementedError): # something Singular can't handle if m != 0: PHI = PHI(fm._polys) / PHI(fm1._polys) - #even when the ring can be passed to singular in quo_rem, - #it can't always do the division, so we call Maxima - if period != [0,1]: #period==[0,1] we don't need to do any division + # even when the ring can be passed to singular in quo_rem, + # it can't always do the division, so we call Maxima + if period != [0, 1]: # period==[0,1] we don't need to do any division BR = self.domain().base_ring().base_ring() if not isinstance(BR, (sage.rings.abc.pAdicRing, sage.rings.abc.pAdicField)): try: @@ -893,8 +881,9 @@ def dynatomic_polynomial(self, period): PHI = PHI.numerator()._maxima_().divide(PHI.denominator())[0].sage() if not isinstance(PHI, FractionFieldElement): from sage.symbolic.expression_conversions import polynomial + PHI = polynomial(PHI, ring=self.coordinate_ring()) - except (TypeError, NotImplementedError): #something Maxima, or the conversion, can't handle + except (TypeError, NotImplementedError): # something Maxima, or the conversion, can't handle pass return PHI @@ -978,16 +967,16 @@ def nth_iterate_map(self, n, normalize=False): F = copy(self) Coord_ring = self.codomain().coordinate_ring() if isinstance(Coord_ring, QuotientRing_generic): - PHI = H([Coord_ring.gen(i).lift() for i in range(N)])#makes a mapping + PHI = H([Coord_ring.gen(i).lift() for i in range(N)]) # makes a mapping else: PHI = H([Coord_ring.gen(i) for i in range(N)]) while D: if D & 1: - PHI = PHI*F + PHI = PHI * F if normalize: PHI.normalize_coordinates() - if D > 1: #avoid extra iterate - F = F*F + if D > 1: # avoid extra iterate + F = F * F if normalize: F.normalize_coordinates() D >>= 1 @@ -1110,7 +1099,7 @@ def nth_iterate(self, P, n, **kwds): n = Integer(n) if n < 0: raise TypeError("must be a forward orbit") - return self.orbit(P, [n,n+1], **kwds)[0] + return self.orbit(P, [n, n + 1], **kwds)[0] def arakelov_zhang_pairing(self, g, **kwds): r""" @@ -1299,8 +1288,10 @@ def arakelov_zhang_pairing(self, g, **kwds): if f_poly.degree() <= 2 or g_poly.degree() <= 2: # f_point or g_point is exceptional - raise ValueError("One of the starting points is exceptional. \ - Please specify a non-exceptional initial point.") + raise ValueError( + "One of the starting points is exceptional. \ + Please specify a non-exceptional initial point." + ) if gcd(f_poly, g_poly).degree() > 0: if f_poly.degree() > g_poly.degree(): @@ -1309,10 +1300,12 @@ def arakelov_zhang_pairing(self, g, **kwds): g_poly = g_poly.quo_rem(gcd(f_poly, g_poly))[0] if f_poly.degree() <= 2 or g_poly.degree() <= 2: - raise ValueError("After removing common factors, the n-th \ + raise ValueError( + "After removing common factors, the n-th \ iterates of 'self' and 'g' have too many \ roots in common. Try another 'n' or starting \ - values.") + values." + ) # We want higher precision here temporarily, since resultants are # usually very large. This is not to say that the computation is @@ -1325,8 +1318,7 @@ def arakelov_zhang_pairing(self, g, **kwds): prec = 512 Real = RealField(prec) - bad_primes = list(set(self.primes_of_bad_reduction(check=check_primes_of_bad_reduction)) - .union(g.primes_of_bad_reduction(check=check_primes_of_bad_reduction))) + bad_primes = list(set(self.primes_of_bad_reduction(check=check_primes_of_bad_reduction)).union(g.primes_of_bad_reduction(check=check_primes_of_bad_reduction))) f_deg = f_poly.degree() g_deg = g_poly.degree() @@ -1341,21 +1333,21 @@ def arakelov_zhang_pairing(self, g, **kwds): AZ_pairing = Real(0) if R is QQ: for p in bad_primes: - temp = (ZZ(1)/2) * (-f_disc.ord(p)) * Real(p).log() / (f_deg**2) + temp = (ZZ(1) / 2) * (-f_disc.ord(p)) * Real(p).log() / (f_deg**2) if abs(temp) > noise_multiplier * Real(f_deg).log() / Real(f_deg): AZ_pairing += temp - temp = (ZZ(1)/2) * (-g_disc.ord(p)) * Real(p).log() / (g_deg**2) + temp = (ZZ(1) / 2) * (-g_disc.ord(p)) * Real(p).log() / (g_deg**2) if abs(temp) > noise_multiplier * Real(g_deg).log() / Real(g_deg): AZ_pairing += temp AZ_pairing -= (-res.ord(p)) * Real(p).log() / (f_deg * g_deg) - temp = (ZZ(1)/2) * (Real(f_disc).abs().log()) / (f_deg**2) + temp = (ZZ(1) / 2) * (Real(f_disc).abs().log()) / (f_deg**2) if abs(temp) > noise_multiplier * Real(f_deg).log() / Real(f_deg): AZ_pairing += temp - temp = (ZZ(1)/2) * (Real(g_disc).abs().log()) / (g_deg**2) + temp = (ZZ(1) / 2) * (Real(g_disc).abs().log()) / (g_deg**2) if abs(temp) > noise_multiplier * Real(g_deg).log() / Real(g_deg): AZ_pairing += temp @@ -1369,11 +1361,11 @@ def arakelov_zhang_pairing(self, g, **kwds): for v in bad_primes: Nv = v.absolute_ramification_index() * v.residue_class_degree() / d - temp = Nv * ((ZZ(1)/2) * K(f_disc).abs_non_arch(v, prec=prec).log() / (f_deg**2)) + temp = Nv * ((ZZ(1) / 2) * K(f_disc).abs_non_arch(v, prec=prec).log() / (f_deg**2)) if abs(temp) > noise_multiplier * Real(f_deg).log() / Real(f_deg): AZ_pairing += temp - temp = Nv * ((ZZ(1)/2) * K(g_disc).abs_non_arch(v, prec=prec).log() / (g_deg**2)) + temp = Nv * ((ZZ(1) / 2) * K(g_disc).abs_non_arch(v, prec=prec).log() / (g_deg**2)) if abs(temp) > noise_multiplier * Real(g_deg).log() / Real(g_deg): AZ_pairing += temp @@ -1381,28 +1373,28 @@ def arakelov_zhang_pairing(self, g, **kwds): if f_disc.is_rational(): f_disc = QQ(f_disc) - temp = (ZZ(1)/2) * (Real(f_disc).abs().log()) / (f_deg**2) + temp = (ZZ(1) / 2) * (Real(f_disc).abs().log()) / (f_deg**2) if abs(temp) > noise_multiplier * Real(f_deg).log() / Real(f_deg): AZ_pairing += temp else: - temp = (ZZ(1)/d) * (ZZ(1)/2) * (Real(K(f_disc).norm()).abs().log()) / (f_deg**2) + temp = (ZZ(1) / d) * (ZZ(1) / 2) * (Real(K(f_disc).norm()).abs().log()) / (f_deg**2) if abs(temp) > noise_multiplier * Real(f_deg).log() / Real(f_deg): AZ_pairing += temp if g_disc.is_rational(): g_disc = QQ(g_disc) - temp = (ZZ(1)/2) * (Real(g_disc).abs().log()) / (g_deg**2) + temp = (ZZ(1) / 2) * (Real(g_disc).abs().log()) / (g_deg**2) if abs(temp) > noise_multiplier * Real(g_deg).log() / Real(g_deg): AZ_pairing += temp else: - temp = (ZZ(1)/d) * (ZZ(1)/2) * (Real(K(g_disc).norm()).abs().log()) / (g_deg**2) + temp = (ZZ(1) / d) * (ZZ(1) / 2) * (Real(K(g_disc).norm()).abs().log()) / (g_deg**2) if abs(temp) > noise_multiplier * Real(g_deg).log() / Real(g_deg): AZ_pairing += temp if res.is_rational(): AZ_pairing -= (Real(res).abs().log()) / (f_deg * g_deg) else: - AZ_pairing -= (ZZ(1)/d) * (Real(K(res).norm()).abs().log()) / (f_deg * g_deg) + AZ_pairing -= (ZZ(1) / d) * (Real(K(res).norm()).abs().log()) / (f_deg * g_deg) if old_prec is None: Real = RealField() @@ -1456,13 +1448,13 @@ def degree_sequence(self, iterates=2): if self.is_morphism(): d = self.degree() - D = [d**t for t in range(1, iterates+1)] + D = [d**t for t in range(1, iterates + 1)] else: F = self F.normalize_coordinates() D = [F.degree()] - for n in range(2, iterates+1): - F = F*self + for n in range(2, iterates + 1): + F = F * self F.normalize_coordinates() D.append(F.degree()) return D @@ -1629,8 +1621,8 @@ def orbit(self, P, N, **kwds): sage: f.orbit(0,2) [(0 : 1), (-1 : 1), (0 : 1)] """ - if not isinstance(N,(list,tuple)): - N = [0,N] + if not isinstance(N, (list, tuple)): + N = [0, N] N[0] = Integer(N[0]) N[1] = Integer(N[1]) if N[0] < 0 or N[1] < 0: @@ -1643,16 +1635,16 @@ def orbit(self, P, N, **kwds): Q = R else: Q = P - check = kwds.pop("check",True) - normalize = kwds.pop("normalize",False) + check = kwds.pop("check", True) + normalize = kwds.pop("normalize", False) if normalize: Q.normalize_coordinates() - for i in range(1, N[0]+1): + for i in range(1, N[0] + 1): Q = self(Q, check) if normalize: Q.normalize_coordinates() orb = [Q] - for i in range(N[0]+1, N[1]+1): + for i in range(N[0] + 1, N[1] + 1): Q = self(Q, check) if normalize: Q.normalize_coordinates() @@ -1723,21 +1715,20 @@ def resultant(self, normalize=False): x = self.domain().gen(0) y = self.domain().gen(1) d = self.degree() - f = F[0].substitute({y:1}) - g = F[1].substitute({y:1}) - #Try to use pari first, as it is faster for one dimensional case - #however the coercion from a Pari object to a sage object breaks - #in the case of QQbar, so we just pass it into the macaulay resultant + f = F[0].substitute({y: 1}) + g = F[1].substitute({y: 1}) + # Try to use pari first, as it is faster for one dimensional case + # however the coercion from a Pari object to a sage object breaks + # in the case of QQbar, so we just pass it into the macaulay resultant try: - res = (f.lc() ** (d - g.degree()) * g.lc() ** (d - f.degree()) - * f.__pari__().polresultant(g, x)) + res = f.lc() ** (d - g.degree()) * g.lc() ** (d - f.degree()) * f.__pari__().polresultant(g, x) return self.domain().base_ring()(res) except (TypeError, PariError): pass - #Otherwise, use Macaulay + # Otherwise, use Macaulay R = F[0].parent() res = R.macaulay_resultant(list(F._polys)) - return res #Coercion here is not necessary as it is already done in Macaulay Resultant + return res # Coercion here is not necessary as it is already done in Macaulay Resultant @cached_method def primes_of_bad_reduction(self, check=True): @@ -1806,14 +1797,14 @@ def primes_of_bad_reduction(self, check=True): if (not isinstance(self.domain(), ProjectiveSpace_ring)) or (not isinstance(self.codomain(), ProjectiveSpace_ring)): raise NotImplementedError("not implemented for subschemes") K = FractionField(self.codomain().base_ring()) - #The primes of bad reduction are the support of the resultant for number fields + # The primes of bad reduction are the support of the resultant for number fields if K in NumberFields(): if K != QQ: F = copy(self) F.normalize_coordinates() - return (K(F.resultant()).support()) - #For the rationals, we can use groebner basis, as it is quicker in practice + return K(F.resultant()).support() + # For the rationals, we can use groebner basis, as it is quicker in practice R = self.coordinate_ring() F = self._polys @@ -1824,10 +1815,10 @@ def primes_of_bad_reduction(self, check=True): J = S.ideal([S.coerce(F[i]) for i in range(R.ngens())]) if J.dimension() > 0: raise TypeError("not a morphism") - #normalize to coefficients in the ring not the fraction field. + # normalize to coefficients in the ring not the fraction field. F = [F[i] * lcm([F[j].denominator() for j in range(len(F))]) for i in range(len(F))] - #move the ideal to the ring of integers + # move the ideal to the ring of integers if R.base_ring().is_field(): S = PolynomialRing(R.base_ring().ring_of_integers(), R.gens(), R.ngens()) F = [F[i].change_ring(R.base_ring().ring_of_integers()) for i in range(len(F))] @@ -1837,7 +1828,7 @@ def primes_of_bad_reduction(self, check=True): GB = J.groebner_basis() badprimes = [] - #get the primes dividing the coefficients of the monomials x_i^k_i + # get the primes dividing the coefficients of the monomials x_i^k_i for i in range(len(GB)): LT = GB[i].lt().degrees() power = 0 @@ -1848,10 +1839,10 @@ def primes_of_bad_reduction(self, check=True): badprimes = badprimes + GB[i].lt().coefficients()[0].support() badprimes = sorted(set(badprimes)) - #check to return only the truly bad primes + # check to return only the truly bad primes if check: index = 0 - while index < len(badprimes): #figure out which primes are really bad primes... + while index < len(badprimes): # figure out which primes are really bad primes... S = PolynomialRing(GF(badprimes[index]), R.gens(), R.ngens()) J = S.ideal([S.coerce(F[j]) for j in range(R.ngens())]) if J.dimension() == 0: @@ -1953,8 +1944,7 @@ def conjugate(self, M, adjugate=False, normalize=False): #return DynamicalSystem_projective(M.inverse()*self*M, domain=self.codomain()) once there is a function to pass to the smallest field of definition. """ - if not (M.is_square() == 1 and M.determinant() != 0 - and M.ncols() == self.domain().ambient_space().dimension_relative() + 1): + if not (M.is_square() == 1 and M.determinant() != 0 and M.ncols() == self.domain().ambient_space().dimension_relative() + 1): raise TypeError("matrix must be invertible and size dimension + 1") X = M * vector(self[0].parent().gens()) F = vector(self._polys) @@ -1968,7 +1958,7 @@ def conjugate(self, M, adjugate=False, normalize=False): try: F = [R(f) for f in F] PS = self.codomain() - except TypeError: #no longer defined over same ring + except TypeError: # no longer defined over same ring R = R.change_ring(N.base_ring()) F = [R(f) for f in F] PS = self.codomain().change_ring(N.base_ring()) @@ -2053,20 +2043,20 @@ def green_function(self, P, v, **kwds): sage: f.green_function(P.point([1,1], False), 0, N=30) 0.43288629610862338612700146098 """ - N = kwds.get('N', 10) #Get number of iterates (if entered) - err = kwds.get('error_bound', None) #Get error bound (if entered) - prec = kwds.get('prec', 100) #Get precision (if entered) + N = kwds.get('N', 10) # Get number of iterates (if entered) + err = kwds.get('error_bound', None) # Get error bound (if entered) + prec = kwds.get('prec', 100) # Get precision (if entered) R = RealField(prec) localht = R(0) BR = FractionField(P.codomain().base_ring()) - GBR = self.change_ring(BR) #so the heights work + GBR = self.change_ring(BR) # so the heights work if BR not in NumberFields(): raise NotImplementedError("must be over a number field or a number field order") if not BR.is_absolute(): raise TypeError("must be an absolute field") - #For QQ the 'flip-trick' works better over RR or Qp + # For QQ the 'flip-trick' works better over RR or Qp if isinstance(v, (NumberFieldFractionalIdeal, RingHomomorphism_im_gens)): K = BR elif is_prime(v): @@ -2077,7 +2067,7 @@ def green_function(self, P, v, **kwds): else: raise ValueError("invalid valuation (=%s) entered" % v) - #Coerce all polynomials in F into polynomials with coefficients in K + # Coerce all polynomials in F into polynomials with coefficients in K F = self.change_ring(K, check=False) d = F.degree() dim = F.codomain().ambient_space().dimension_relative() @@ -2088,18 +2078,18 @@ def green_function(self, P, v, **kwds): if not err > 0: raise ValueError("error bound (=%s) must be positive" % err) - #if doing error estimates, compute needed number of iterates + # if doing error estimates, compute needed number of iterates D = (dim + 1) * (d - 1) + 1 # compute upper bound - if isinstance(v, RingHomomorphism_im_gens): #archimedean + if isinstance(v, RingHomomorphism_im_gens): # archimedean vindex = BR.places(prec=prec).index(v) emb = BR.places(prec=prec)[vindex] U = GBR.local_height_arch(vindex, prec=prec) + R(binomial(dim + d, d)).log() - else: #non-archimedean + else: # non-archimedean U = GBR.local_height(v, prec=prec) - #compute lower bound - from explicit polynomials of Nullstellensatz - CR = GBR.codomain().ambient_space().coordinate_ring() #.lift() only works over fields + # compute lower bound - from explicit polynomials of Nullstellensatz + CR = GBR.codomain().ambient_space().coordinate_ring() # .lift() only works over fields I = CR.ideal(GBR.defining_polynomials()) maxh = 0 for k in range(dim + 1): @@ -2107,65 +2097,65 @@ def green_function(self, P, v, **kwds): h = 1 for poly in CoeffPolys: if poly != 0: - if isinstance(v, RingHomomorphism_im_gens): #archimedean + if isinstance(v, RingHomomorphism_im_gens): # archimedean if BR == QQ: h = max([R(K(c).abs()) for c in poly.coefficients()]) else: h = max([R(emb(c).abs()) for c in poly.coefficients()]) - else: #non-archimedean + else: # non-archimedean if BR == QQ: - h = max(R(v)**(-R(c.valuation(v))) for c in poly.coefficients()) + h = max(R(v) ** (-R(c.valuation(v))) for c in poly.coefficients()) else: h = max(R(c.abs_non_arch(v, prec=prec)) for c in poly.coefficients()) maxh = max(h, maxh) if maxh == 0: - maxh = 1 #avoid division by 0 - if isinstance(v, RingHomomorphism_im_gens): #archimedean + maxh = 1 # avoid division by 0 + if isinstance(v, RingHomomorphism_im_gens): # archimedean L = R(1 / ((dim + 1) * binomial(dim + D - d, D - d) * maxh)).log().abs() - else: #non-archimedean + else: # non-archimedean if BR == QQ: - L = ((-self.resultant().valuation(v))*R(v).log()).abs() + L = ((-self.resultant().valuation(v)) * R(v).log()).abs() else: L = (self.resultant().abs_non_arch(v, prec=prec)).log().abs() C = max([U, L]) if C != 0: - N = R(C / (err*(d-1))).log(d).abs().ceil() - else: #we just need log||P||_v + N = R(C / (err * (d - 1))).log(d).abs().ceil() + else: # we just need log||P||_v N = 1 - #START GREEN FUNCTION CALCULATION - if isinstance(v, RingHomomorphism_im_gens): #embedding for archimedean local height - for i in range(N+1): - Qv = [ (v(t).abs()) for t in Q ] + # START GREEN FUNCTION CALCULATION + if isinstance(v, RingHomomorphism_im_gens): # embedding for archimedean local height + for i in range(N + 1): + Qv = [(v(t).abs()) for t in Q] m = -1 - #compute the maximum absolute value of entries of a, and where it occurs + # compute the maximum absolute value of entries of a, and where it occurs for n in range(dim + 1): if Qv[n] > m: j = n m = Qv[n] # add to sum for the Green's function - localht += ((1/R(d))**R(i)) * (R(m).log()) - #get the next iterate + localht += ((1 / R(d)) ** R(i)) * (R(m).log()) + # get the next iterate if i < N: - Q.scale_by(1/Q[j]) + Q.scale_by(1 / Q[j]) Q = F(Q, False) - return (1/BR.absolute_degree()) * localht + return (1 / BR.absolute_degree()) * localht - #else - prime or prime ideal for non-archimedean + # else - prime or prime ideal for non-archimedean for i in range(N + 1): if BR == QQ: - Qv = [ R(K(t).abs()) for t in Q ] + Qv = [R(K(t).abs()) for t in Q] else: - Qv = [ R(t.abs_non_arch(v)) for t in Q ] + Qv = [R(t.abs_non_arch(v)) for t in Q] m = -1 - #compute the maximum absolute value of entries of a, and where it occurs + # compute the maximum absolute value of entries of a, and where it occurs for n in range(dim + 1): if Qv[n] > m: j = n m = Qv[n] # add to sum for the Green's function - localht += (1/R(d))**R(i) * (R(m).log()) - #get the next iterate + localht += (1 / R(d)) ** R(i) * (R(m).log()) + # get the next iterate if i < N: Q.scale_by(1 / Q[j]) Q = F(Q, False) @@ -2282,8 +2272,8 @@ def canonical_height(self, P, **kwds): if not isinstance(K, sage.rings.abc.AlgebraicField): raise NotImplementedError("must be over a number field or a number field order or QQbar") else: - #since this an absolute height, we can compute the height of a QQbar point - #by choosing any number field it is defined over. + # since this an absolute height, we can compute the height of a QQbar point + # by choosing any number field it is defined over. Q = P._number_field_from_algebraics() K = Q.codomain().base_ring() f = self._number_field_from_algebraics().as_dynamical_system() @@ -2332,15 +2322,15 @@ def canonical_height(self, P, **kwds): if Res > 1: if err is not None: err = err / 2 - N = ceil((R(Res).log().log() - R(d-1).log() - R(err).log())/(R(d).log())) + N = ceil((R(Res).log().log() - R(d - 1).log() - R(err).log()) / (R(d).log())) N = max(N, 1) kwds.update({'error_bound': err}) kwds.update({'N': N}) for n in range(N): - x = A(x_i,y_i) % Res**(N-n) - y = B(x_i,y_i) % Res**(N-n) + x = A(x_i, y_i) % Res ** (N - n) + y = B(x_i, y_i) % Res ** (N - n) g = gcd([x, y, Res]) - H = H + R(g).abs().log() / (d**(n+1)) + H = H + R(g).abs().log() / (d ** (n + 1)) x_i = x / g y_i = y / g # this looks different than Wells' Algorithm because of the difference @@ -2350,11 +2340,10 @@ def canonical_height(self, P, **kwds): # The value returned by Well's algorithm may be negative. As the canonical height # is always nonnegative, so if this value is within -err of 0, return 0. if h < 0: - assert h > -err, "A negative height less than -error_bound was computed. " + \ - "This should be impossible, please report bug on https://github.com/sagemath/sage/issues" - # This should be impossible. The error bound for Wells' is rigorous - # and the actual height is always >= 0. If we see something less than -err, - # something has g one very wrong. + assert h > -err, "A negative height less than -error_bound was computed. " + "This should be impossible, please report bug on https://github.com/sagemath/sage/issues" + # This should be impossible. The error bound for Wells' is rigorous + # and the actual height is always >= 0. If we see something less than -err, + # something has g one very wrong. h = R(0) return h @@ -2388,7 +2377,7 @@ def canonical_height(self, P, **kwds): dv = R.one() else: dv = R(2) - h += dv * f.green_function(Q, v, **kwds) #arch Green function + h += dv * f.green_function(Q, v, **kwds) # arch Green function # Non-Archimedean local heights for v in bad_primes: @@ -2396,7 +2385,7 @@ def canonical_height(self, P, **kwds): dv = R.one() else: dv = R(v.residue_class_degree() * v.absolute_ramification_index()) - h += dv * f.green_function(Q, v, **kwds) #non-arch Green functions + h += dv * f.green_function(Q, v, **kwds) # non-arch Green functions return h def height_difference_bound(self, prec=None): @@ -2457,11 +2446,11 @@ def height_difference_bound(self, prec=None): sage: f.height_difference_bound(prec=100) # needs sage.symbolic 5.3375380797013179737224159274 """ - FF = FractionField(self.domain().base_ring()) #lift will only work over fields, so coercing into FF + FF = FractionField(self.domain().base_ring()) # lift will only work over fields, so coercing into FF if FF not in NumberFields(): if isinstance(FF, sage.rings.abc.AlgebraicField): - #since this is absolute height, we can choose any number field over which the - #function is defined. + # since this is absolute height, we can choose any number field over which the + # function is defined. f = self._number_field_from_algebraics() else: raise NotImplementedError("fraction field of the base ring must be a number field or QQbar") @@ -2474,9 +2463,9 @@ def height_difference_bound(self, prec=None): N = f.domain().dimension_relative() d = f.degree() D = (N + 1) * (d - 1) + 1 - #compute upper bound + # compute upper bound U = f.global_height(prec) + R(binomial(N + d, d)).log() - #compute lower bound - from explicit polynomials of Nullstellensatz + # compute lower bound - from explicit polynomials of Nullstellensatz CR = f.domain().coordinate_ring() I = CR.ideal(f.defining_polynomials()) maxh = 0 @@ -2485,7 +2474,7 @@ def height_difference_bound(self, prec=None): h = max([g.global_height(prec) for g in CoeffPolys]) maxh = max(maxh, h) L = R((N + 1) * binomial(N + D - d, D - d)).log() + maxh - C = max(U, L) #height difference dh(P) - L <= h(f(P)) <= dh(P) +U + C = max(U, L) # height difference dh(P) - L <= h(f(P)) <= dh(P) +U return C / (d - 1) def multiplier(self, P, n, check=True): @@ -2565,7 +2554,7 @@ def multiplier(self, P, n, check=True): Q = P Q.normalize_coordinates() index = N - indexlist = [] #keep track of which dehomogenizations are needed + indexlist = [] # keep track of which dehomogenizations are needed while Q[index] == 0: index -= 1 indexlist.append(index) @@ -2577,10 +2566,10 @@ def multiplier(self, P, n, check=True): while R[index] == 0: index -= 1 indexlist.append(index) - #dehomogenize and compute multiplier - F = self.dehomogenize((indexlist[i],indexlist[i+1])) - #get the correct order for chain rule matrix multiplication - l = F.jacobian()(tuple(Q.dehomogenize(indexlist[i])))*l + # dehomogenize and compute multiplier + F = self.dehomogenize((indexlist[i], indexlist[i + 1])) + # get the correct order for chain rule matrix multiplication + l = F.jacobian()(tuple(Q.dehomogenize(indexlist[i]))) * l Q = R return l @@ -2627,10 +2616,10 @@ def _multipliermod(self, P, n, p, k): BR = FractionField(self.codomain().base_ring()) l = identity_matrix(BR, N, N) Q = copy(P) - g = gcd(Q._coords) #we can't use normalize_coordinates since it can cause denominators + g = gcd(Q._coords) # we can't use normalize_coordinates since it can cause denominators Q.scale_by(1 / g) index = N - indexlist = [] #keep track of which dehomogenizations are needed + indexlist = [] # keep track of which dehomogenizations are needed while Q[index] % p == 0: index -= 1 indexlist.append(index) @@ -2641,15 +2630,15 @@ def _multipliermod(self, P, n, p, k): R.scale_by(1 / g) R_list = list(R) for index in range(N + 1): - R_list[index] = R_list[index] % (p ** k) + R_list[index] = R_list[index] % (p**k) R._coords = tuple(R_list) index = N while R[index] % p == 0: index -= 1 indexlist.append(index) - #dehomogenize and compute multiplier - F = self.dehomogenize((indexlist[i],indexlist[i+1])) - l = (F.jacobian()(tuple(Q.dehomogenize(indexlist[i])))*l) % (p ** k) + # dehomogenize and compute multiplier + F = self.dehomogenize((indexlist[i], indexlist[i + 1])) + l = (F.jacobian()(tuple(Q.dehomogenize(indexlist[i]))) * l) % (p**k) Q = R return l @@ -2674,22 +2663,22 @@ def _nth_preimage_tree_helper(self, Q, n, m, **kwds): # Solve for preimages numerically CR = self.domain().ambient_space().coordinate_ring() fn = self.dehomogenize(1) - poly = (fn[0].numerator()*CR(Q[1]) - fn[0].denominator()*CR(Q[0])).univariate_polynomial() + poly = (fn[0].numerator() * CR(Q[1]) - fn[0].denominator() * CR(Q[0])).univariate_polynomial() K = ComplexField(prec=prec) - pre = [ProjectiveSpace(K,1)(r) for r in poly.roots(ring=K)] + pre = [ProjectiveSpace(K, 1)(r) for r in poly.roots(ring=K)] else: # Solve for preimages algebraically - pre = self.rational_preimages(Q,1) + pre = self.rational_preimages(Q, 1) for pt in pre: # Fill in dictionary entries of preimage points to Q if display_complex: pt1 = "(" + str(embed(pt[0]).n(digits=digits)) + ": 1)" Q1 = "(" + str(embed(Q[0]).n(digits=digits)) + ": 1)" key = pt1 + ", " + str(m) - D[key] = [Q1 + ", " + str(m-1)] + D[key] = [Q1 + ", " + str(m - 1)] else: key = str(pt) + ", " + str(m) - D[key] = [str(Q) + ", " + str(m-1)] + D[key] = [str(Q) + ", " + str(m - 1)] if return_points: # Fill in m-th level preimage points in points list kwds["points"][m].append(pt) @@ -2702,7 +2691,7 @@ def _nth_preimage_tree_helper(self, Q, n, m, **kwds): # For each preimage point of Q, use recursion to find that point's preimages # and update the dictionary for pt in pre: - D.update(self._nth_preimage_tree_helper(pt, n-1, m+1, **kwds)[0]) + D.update(self._nth_preimage_tree_helper(pt, n - 1, m + 1, **kwds)[0]) return D, points if n == 1: # Base case of recursion @@ -2710,7 +2699,7 @@ def _nth_preimage_tree_helper(self, Q, n, m, **kwds): # For each preimage point of Q, use recursion to find that point's preimages # and update the dictionary for pt in pre: - D.update(self._nth_preimage_tree_helper(pt, n-1, m+1, **kwds)) + D.update(self._nth_preimage_tree_helper(pt, n - 1, m + 1, **kwds)) return D def nth_preimage_tree(self, Q, n, **kwds): @@ -2827,7 +2816,7 @@ def nth_preimage_tree(self, Q, n, **kwds): Q = fbar.codomain()(Q) if return_points: # n+1 since we have n levels with root as 0th level - points = [[] for i in range(n+1)] + points = [[] for i in range(n + 1)] points[0].append(Q) kwds["points"] = points V, points = fbar._nth_preimage_tree_helper(Q, n, 1, **kwds) @@ -2835,13 +2824,14 @@ def nth_preimage_tree(self, Q, n, **kwds): V = fbar._nth_preimage_tree_helper(Q, n, 1, **kwds) from sage.graphs.digraph import DiGraph from sage.graphs.graph_plot import GraphPlot + G = DiGraph(V) if display_complex: Q = "(" + str(embed(Q[0]).n(digits=digits)) + ": 1)" root = Q + ", " + str(0) else: root = str(Q) + ", " + str(0) - options = {'layout':'tree', 'tree_orientation':'up', 'tree_root':root, 'vertex_labels':display_labels} + options = {'layout': 'tree', 'tree_orientation': 'up', 'tree_root': root, 'vertex_labels': display_labels} if return_points: return GraphPlot(G, options), points @@ -2980,9 +2970,9 @@ def _preperiodic_points_to_cyclegraph(self, preper): """ V = [] E = [] - #We store the points we encounter is a list, D. Each new point is checked to - #see if it is in that list (which uses ==) so that equal points with different - #representations only appear once in the graph. + # We store the points we encounter is a list, D. Each new point is checked to + # see if it is in that list (which uses ==) so that equal points with different + # representations only appear once in the graph. D = [] for val in preper: try: @@ -2998,6 +2988,7 @@ def _preperiodic_points_to_cyclegraph(self, preper): D.append(Q) E.append([Q]) from sage.graphs.digraph import DiGraph + g = DiGraph(dict(zip(V, E)), loops=True) return g @@ -3049,12 +3040,14 @@ def is_PGL_minimal(self, prime_list=None): F = R(f[0].numerator()) G = R(f[0].denominator()) if G.degree() == 0 or F.degree() == 0: - #can't use BM for polynomial + # can't use BM for polynomial from .endPN_minimal_model import HS_minimal + g, m = HS_minimal(self, return_transformation=True, D=prime_list) return m == m.parent().one() from .endPN_minimal_model import affine_minimal + return affine_minimal(self, return_transformation=False, D=prime_list, quick=True) def minimal_model(self, return_transformation=False, prime_list=None, algorithm=None, check_primes=True): @@ -3213,9 +3206,11 @@ def minimal_model(self, return_transformation=False, prime_list=None, algorithm= if algorithm == 'BM': from .endPN_minimal_model import affine_minimal + return affine_minimal(self, return_transformation=return_transformation, D=prime_list, quick=False) if algorithm == 'HS': from .endPN_minimal_model import HS_minimal + return HS_minimal(self, return_transformation=return_transformation, D=prime_list) # algorithm not specified f = copy(self) @@ -3225,19 +3220,19 @@ def minimal_model(self, return_transformation=False, prime_list=None, algorithm= G = R(f[0].denominator()) if G.degree() == 0 or F.degree() == 0: - #can use BM for polynomial + # can use BM for polynomial from .endPN_minimal_model import HS_minimal + return HS_minimal(self, return_transformation=return_transformation, D=prime_list) if prime_list is None: prime_list = ZZ(F.resultant().prime_divisors()) if max(prime_list) > 500: from .endPN_minimal_model import affine_minimal - return affine_minimal(self, return_transformation=return_transformation, - D=prime_list, quick=False) - def all_minimal_models(self, return_transformation=False, prime_list=None, - algorithm=None, check_minimal=True): + return affine_minimal(self, return_transformation=return_transformation, D=prime_list, quick=False) + + def all_minimal_models(self, return_transformation=False, prime_list=None, algorithm=None, check_minimal=True): r""" Determine a representative in each `SL(2,\ZZ)`-orbit of this map. @@ -3330,44 +3325,47 @@ def all_minimal_models(self, return_transformation=False, prime_list=None, raise NotImplementedError("minimality is only for degree 2 or higher") if check_minimal: - f, m = self.minimal_model(return_transformation=True, - prime_list=prime_list, - algorithm=algorithm) + f, m = self.minimal_model(return_transformation=True, prime_list=prime_list, algorithm=algorithm) else: f = self - m = matrix(ZZ, 2, 2, [1,0,0,1]) + m = matrix(ZZ, 2, 2, [1, 0, 0, 1]) if algorithm == 'BM': from .endPN_minimal_model import BM_all_minimal + models = BM_all_minimal(f, return_transformation=True, D=prime_list) elif algorithm == 'HS': from .endPN_minimal_model import HS_all_minimal + models = HS_all_minimal(f, return_transformation=True, D=prime_list) - else: # algorithm not specified + else: # algorithm not specified f.normalize_coordinates() Aff_f = f.dehomogenize(1) R = Aff_f.domain().coordinate_ring() F = R(Aff_f[0].numerator()) G = R(Aff_f[0].denominator()) if G.degree() == 0 or F.degree() == 0: - #can use BM for polynomial + # can use BM for polynomial from .endPN_minimal_model import HS_all_minimal + models = HS_all_minimal(f, return_transformation=True, D=prime_list) elif prime_list is None: prime_list = ZZ(f.resultant()).prime_divisors() if prime_list == []: - models = [[f,m]] + models = [[f, m]] elif max(prime_list) > 500: from .endPN_minimal_model import BM_all_minimal + models = BM_all_minimal(f, return_transformation=True, D=prime_list) else: from .endPN_minimal_model import HS_all_minimal + models = HS_all_minimal(f, return_transformation=True, D=prime_list) if return_transformation: - models = [[g, t*m] for g,t in models] + models = [[g, t * m] for g, t in models] else: - models = [g for g,t in models] + models = [g for g, t in models] return models def affine_preperiodic_model(self, m, n, return_conjugation=False): @@ -3485,10 +3483,9 @@ def affine_preperiodic_model(self, m, n, return_conjugation=False): PS = f.codomain().ambient_space() N = PS.dimension_relative() + 1 R = f.base_ring() - F_1 = f.nth_iterate_map(n+m) + F_1 = f.nth_iterate_map(n + m) F_2 = f.nth_iterate_map(m) - L = [F_1[i]*F_2[j] - F_1[j]*F_2[i] for i in range(N) - for j in range(i+1, N)] + L = [F_1[i] * F_2[j] - F_1[j] * F_2[i] for i in range(N) for j in range(i + 1, N)] X = PS.subscheme(L + list(dom.defining_polynomials())) hyperplane_at_infinity = PS.subscheme(CR.gens()[-1]) if R.is_field(): @@ -3503,9 +3500,9 @@ def affine_preperiodic_model(self, m, n, return_conjugation=False): if R.is_finite(): # when R is finite, we try all hyperplanes for tup in product(R, repeat=N): - if list(tup) != [0]*N: + if list(tup) != [0] * N: if PS(tup) not in attempted_combinations: - hyperplane = PS.subscheme(sum([tup[i]*PS.gens()[i] for i in range(N)])) + hyperplane = PS.subscheme(sum([tup[i] * PS.gens()[i] for i in range(N)])) if X.intersection(hyperplane).change_ring(F).dimension() < 0: hyperplane_found = True break @@ -3517,18 +3514,16 @@ def affine_preperiodic_model(self, m, n, return_conjugation=False): for height_bound in count(1): terms = ZZ.range(height_bound) for tup in product(terms, repeat=N): - if list(tup) != [0]*N: + if list(tup) != [0] * N: if PS(tup) not in attempted_combinations: - hyperplane = PS.subscheme(sum([tup[i]*PS.gens()[i] for i in range(N)])) + hyperplane = PS.subscheme(sum([tup[i] * PS.gens()[i] for i in range(N)])) if X.intersection(hyperplane).change_ring(F).dimension() < 0: hyperplane_found = True break if hyperplane_found: break else: - if isinstance(R, (PolynomialRing_generic, - MPolynomialRing_base, - FractionField_generic)): + if isinstance(R, (PolynomialRing_generic, MPolynomialRing_base, FractionField_generic)): # for polynomial rings, we can get an infinite family of hyperplanes # by increasing the degree var = R.gen() @@ -3536,11 +3531,11 @@ def affine_preperiodic_model(self, m, n, return_conjugation=False): ZZ_terms = ZZ.range(R.characteristic()) terms = ZZ_terms[:] for i in ZZ_terms: - terms.append(i*var**degree) + terms.append(i * var**degree) for tup in product(terms, repeat=N): - if list(tup) != [0]*N: + if list(tup) != [0] * N: if PS(tup) not in attempted_combinations: - hyperplane = PS.subscheme(sum([tup[i]*PS.gens()[i] for i in range(N)])) + hyperplane = PS.subscheme(sum([tup[i] * PS.gens()[i] for i in range(N)])) if X.intersection(hyperplane).change_ring(F).dimension() < 0: hyperplane_found = True break @@ -3696,9 +3691,9 @@ def automorphism_group(self, **kwds): if (self.degree() == 1) or (self.degree() == 0): raise NotImplementedError("rational function of degree 1 not implemented") f = self.dehomogenize(1) - R = PolynomialRing(f.base_ring(),'x') + R = PolynomialRing(f.base_ring(), 'x') if isinstance(f[0], FractionFieldElement): - F = (f[0].numerator().univariate_polynomial(R))/f[0].denominator().univariate_polynomial(R) + F = (f[0].numerator().univariate_polynomial(R)) / f[0].denominator().univariate_polynomial(R) else: F = f[0].univariate_polynomial(R) if alg is None: @@ -3874,7 +3869,7 @@ def ramification_type(self, R=None, stable=True): # Change base ring if specified. if R is None: if stable: - L,phi = self.field_of_definition_critical(return_embedding=True) + L, phi = self.field_of_definition_critical(return_embedding=True) F = self.change_ring(phi) else: F = self @@ -3977,7 +3972,7 @@ def is_postcritically_finite(self, err=0.01, use_algebraic_closure=True): sage: f.is_postcritically_finite() False """ - #iteration of subschemes not yet implemented + # iteration of subschemes not yet implemented if self.domain().dimension_relative() > 1: raise NotImplementedError("only implemented in dimension 1") @@ -4168,7 +4163,7 @@ def critical_point_portrait(self, check=True, use_algebraic_closure=True): sage: f.critical_point_portrait() #long time Looped digraph on 6 vertices """ - #input checking done in is_postcritically_finite + # input checking done in is_postcritically_finite if check: if not self.is_postcritically_finite(): raise TypeError("map must be post-critically finite") @@ -4528,10 +4523,9 @@ def preperiodic_points(self, m, n, **kwds): R = self.base_ring() else: f_sub = self.change_ring(R) - R = f_sub.base_ring() #in the case when R is an embedding + R = f_sub.base_ring() # in the case when R is an embedding if isinstance(R, FractionField_1poly_field) or R in FunctionFields(): - raise NotImplementedError('Periodic points not implemented for function fields; ' - 'clear denominators and use the polynomial ring instead') + raise NotImplementedError('Periodic points not implemented for function fields; ' 'clear denominators and use the polynomial ring instead') CR = f_sub.coordinate_ring() dom = f_sub.domain() PS = f_sub.codomain().ambient_space() @@ -4544,12 +4538,11 @@ def preperiodic_points(self, m, n, **kwds): minimal = kwds.pop('minimal', True) return_scheme = kwds.pop('return_scheme', False) if formal and N == 2 and dom == PS: - X = PS.subscheme([f.dynatomic_polynomial([m,n])]) + X = PS.subscheme([f.dynatomic_polynomial([m, n])]) else: - F_1 = f.nth_iterate_map(n+m) + F_1 = f.nth_iterate_map(n + m) F_2 = f.nth_iterate_map(m) - L = [F_1[i]*F_2[j] - F_1[j]*F_2[i] for i in range(N) - for j in range(i+1, N)] + L = [F_1[i] * F_2[j] - F_1[j] * F_2[i] for i in range(N) for j in range(i + 1, N)] X = PS.subscheme(L + list(dom.defining_polynomials())) if (minimal or formal) and (n != 1 or m != 0): if not f_sub.is_morphism(): @@ -4562,8 +4555,8 @@ def preperiodic_points(self, m, n, **kwds): # we now deform by a parameter t T = R['t'] t = T.gens()[0] - Pt = ProjectiveSpace(N-1, R=T, names=[str(i) for i in CR.gens()]) - deformed_polys = [poly + t*Pt.gens()[-1]**d for poly in new_f.defining_polynomials()[:-1]] + Pt = ProjectiveSpace(N - 1, R=T, names=[str(i) for i in CR.gens()]) + deformed_polys = [poly + t * Pt.gens()[-1] ** d for poly in new_f.defining_polynomials()[:-1]] deformed_polys += [new_f.defining_polynomials()[-1]] f_deformed = DynamicalSystem(deformed_polys) @@ -4571,9 +4564,9 @@ def preperiodic_points(self, m, n, **kwds): # will separate into different points. we can now calculate the minimal preperiodic # points with the parameter, and then specialize to get the formal preperiodic points ideal = f_deformed.preperiodic_points(m, n, return_scheme=True).defining_ideal() - L = [poly.specialization({t:0}) for poly in ideal.gens()] + L = [poly.specialization({t: 0}) for poly in ideal.gens()] X = PS.subscheme(L) - subs_list = mat.inverse()*vector(CR.gens()) + subs_list = mat.inverse() * vector(CR.gens()) subs = {} for i in range(len(subs_list)): subs[PS.gens()[i]] = subs_list[i] @@ -4581,22 +4574,21 @@ def preperiodic_points(self, m, n, **kwds): X = PS.subscheme([poly.subs(subs) for poly in L]) else: K = [poly.subs(subs) for poly in L] - K = [poly*poly.denominator() for poly in K] + K = [poly * poly.denominator() for poly in K] X = PS.subscheme(K) elif minimal: Sn = [] for k in ZZ(n).divisors(): - if ZZ(n/k).is_prime(): + if ZZ(n / k).is_prime(): Sn.append(k) - if isinstance(R, (PolynomialRing_generic, - MPolynomialRing_base)): + if isinstance(R, (PolynomialRing_generic, MPolynomialRing_base)): phi = FlatteningMorphism(CR) flatCR = phi.codomain() Ik = flatCR.ideal(1) for k in Sn: Ik *= f.preperiodic_points(m, k, return_scheme=True, minimal=False).defining_ideal() if m != 0: - Ik *= f.preperiodic_points(m-1, n, return_scheme=True, minimal=False).defining_ideal() + Ik *= f.preperiodic_points(m - 1, n, return_scheme=True, minimal=False).defining_ideal() psi = UnflatteningMorphism(flatCR, CR) In = flatCR.ideal([phi(i) for i in X.defining_polynomials()]) X = PS.subscheme([psi(i) for i in In.saturation(Ik)[0].gens()]) @@ -4605,7 +4597,7 @@ def preperiodic_points(self, m, n, **kwds): for k in Sn: Ik *= f.preperiodic_points(m, k, return_scheme=True, minimal=False).defining_ideal() if m != 0: - Ik *= f.preperiodic_points(m-1, n, return_scheme=True, minimal=False).defining_ideal() + Ik *= f.preperiodic_points(m - 1, n, return_scheme=True, minimal=False).defining_ideal() In = X.defining_ideal() X = PS.subscheme(In.saturation(Ik)[0]) if dom != PS: @@ -4625,11 +4617,10 @@ def preperiodic_points(self, m, n, **kwds): good_points.sort() return good_points raise NotImplementedError("ring must a number field or finite field") - else: #a higher dimensional scheme + else: # a higher dimensional scheme raise TypeError("use return_scheme=True") - def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='variety', - return_scheme=False): + def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='variety', return_scheme=False): r""" Compute the periodic points of period ``n`` of this dynamical system defined over the ring ``R`` or the base ring of the map. @@ -4866,14 +4857,12 @@ def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='vari R = self.base_ring() else: f_sub = self.change_ring(R) - R = f_sub.base_ring() #in the case when R is an embedding + R = f_sub.base_ring() # in the case when R is an embedding if isinstance(R, FractionField_1poly_field) or R in FunctionFields(): - raise NotImplementedError('periodic points not implemented for fraction function fields; ' - 'clear denominators and use the polynomial ring instead') + raise NotImplementedError('periodic points not implemented for fraction function fields; ' 'clear denominators and use the polynomial ring instead') if isinstance(R, FractionField_generic): if isinstance(R.ring(), MPolynomialRing_base): - raise NotImplementedError('periodic points not implemented for fraction function fields; ' - 'clear denominators and use the polynomial ring instead') + raise NotImplementedError('periodic points not implemented for fraction function fields; ' 'clear denominators and use the polynomial ring instead') CR = f_sub.coordinate_ring() dom = f_sub.domain() PS = f_sub.codomain().ambient_space() @@ -4888,7 +4877,7 @@ def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='vari g = f.cyclegraph() points = [] for cycle in g.all_simple_cycles(algorithm="A"): - m = len(cycle)-1 + m = len(cycle) - 1 if minimal: if m == n: points = points + cycle[:-1] @@ -4902,8 +4891,7 @@ def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='vari X = PS.subscheme([f.dynatomic_polynomial(n)]) else: F = f.nth_iterate_map(n) - L = [F[i]*CR.gen(j) - F[j]*CR.gen(i) for i in range(N) - for j in range(i+1, N)] + L = [F[i] * CR.gen(j) - F[j] * CR.gen(i) for i in range(N) for j in range(i + 1, N)] L = [t for t in L if t != 0] X = PS.subscheme(L) if (minimal or formal) and n != 1: @@ -4918,8 +4906,8 @@ def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='vari # we now deform by a parameter t T = R['t'] t = T.gens()[0] - Pt = ProjectiveSpace(N-1, R=T, names=[str(i) for i in CR.gens()]) - deformed_polys = [poly + t*Pt.gens()[-1]**d for poly in new_f.defining_polynomials()[:-1]] + Pt = ProjectiveSpace(N - 1, R=T, names=[str(i) for i in CR.gens()]) + deformed_polys = [poly + t * Pt.gens()[-1] ** d for poly in new_f.defining_polynomials()[:-1]] deformed_polys += [new_f.defining_polynomials()[-1]] f_deformed = DynamicalSystem(deformed_polys) @@ -4927,8 +4915,8 @@ def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='vari # will separate into different points. we can now calculate the minimal preperiodic # points with the parameter, and then specialize to get the formal periodic points ideal = f_deformed.periodic_points(n, return_scheme=True).defining_ideal() - L = [poly.specialization({t:0}) for poly in ideal.gens()] - subs_list = mat.inverse()*vector(CR.gens()) + L = [poly.specialization({t: 0}) for poly in ideal.gens()] + subs_list = mat.inverse() * vector(CR.gens()) subs = {} for i in range(len(subs_list)): subs[PS.gens()[i]] = subs_list[i] @@ -4936,15 +4924,14 @@ def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='vari X = PS.subscheme([poly.subs(subs) for poly in L]) else: K = [poly.subs(subs) for poly in L] - K = [poly*poly.denominator() for poly in K] + K = [poly * poly.denominator() for poly in K] X = PS.subscheme(K) elif minimal: Sn = [] for k in ZZ(n).divisors(): - if ZZ(n//k).is_prime(): + if ZZ(n // k).is_prime(): Sn.append(k) - if isinstance(R, (PolynomialRing_generic, - MPolynomialRing_base)): + if isinstance(R, (PolynomialRing_generic, MPolynomialRing_base)): phi = FlatteningMorphism(CR) flatCR = phi.codomain() Ik = flatCR.ideal(1) @@ -4976,7 +4963,7 @@ def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='vari good_points.sort() return good_points raise NotImplementedError("ring must be a number field or finite field") - else: #a higher dimensional scheme + else: # a higher dimensional scheme raise TypeError("use return_scheme=True") else: raise ValueError("algorithm must be either 'variety' or 'cyclegraph'") @@ -5223,7 +5210,7 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur PS = self.domain() n = Integer(n) - if (n < 1): + if n < 1: raise ValueError("period must be a positive integer") if not isinstance(PS, ProjectiveSpace_ring): raise NotImplementedError("not implemented for subschemes") @@ -5234,8 +5221,7 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur # if we are already using an algebraic closure, we move the # map into a finite extension and set use_algebraic_closure to True # in order to get a scheme defined over a finite extension - if isinstance(K, (sage.rings.abc.AlgebraicField, - AlgebraicClosureFiniteField_generic)): + if isinstance(K, (sage.rings.abc.AlgebraicField, AlgebraicClosureFiniteField_generic)): f = self.reduce_base_field() K = f.base_ring() use_algebraic_closure = True @@ -5302,7 +5288,7 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur new_point.append(ff_num) degree = ff_num.parent().degree() final_degree = final_degree.lcm(degree) - K_prime = GF(K.characteristic()**final_degree) + K_prime = GF(K.characteristic() ** final_degree) X_k = X.change_ring(K_prime) for i in range(X_k.multiplicity(new_point)): points.append(PS(point)) @@ -5315,16 +5301,15 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur d = self.degree() N = self.domain().ambient_space().dimension_relative() if not formal: - expected_number = sum(d**(n*i) for i in range(N+1)) + expected_number = sum(d ** (n * i) for i in range(N + 1)) else: expected_number = 0 for D in n.divisors(): - u = moebius(n/D) - inner_sum = sum(d**(D*j) for j in range(N+1)) - expected_number += u*inner_sum + u = moebius(n / D) + inner_sum = sum(d ** (D * j) for j in range(N + 1)) + expected_number += u * inner_sum if len(points) != expected_number: - raise ValueError('failed to compute the full multiplier spectra. Try use_algebraic_closure=True' - + ' or extend the base ring of this dynamical system') + raise ValueError('failed to compute the full multiplier spectra. Try use_algebraic_closure=True' + ' or extend the base ring of this dynamical system') else: K = FractionField(self.codomain().base_ring()) if use_algebraic_closure: @@ -5344,22 +5329,22 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur PS = f.domain() if not formal: G = f.nth_iterate_map(n) - F = G[0]*PS.gens()[1] - G[1]*PS.gens()[0] + F = G[0] * PS.gens()[1] - G[1] * PS.gens()[0] else: # periodic points of formal period n are the roots of the nth dynatomic polynomial F = f.dynatomic_polynomial(n) - other_roots = F.parent()(F([(f.domain().gens()[0]),1])).univariate_polynomial().roots(ring=f.base_ring()) + other_roots = F.parent()(F([(f.domain().gens()[0]), 1])).univariate_polynomial().roots(ring=f.base_ring()) points = [] - minfty = min(ex[1] for ex in F.exponents()) # include the point at infinity with the right multiplicity + minfty = min(ex[1] for ex in F.exponents()) # include the point at infinity with the right multiplicity for i in range(minfty): - points.append(PS([1,0])) + points.append(PS([1, 0])) for R in other_roots: for i in range(R[1]): - points.append(PS([R[0],1])) # include copies of higher multiplicity roots + points.append(PS([R[0], 1])) # include copies of higher multiplicity roots if type == 'cycle': # should include one representative point per cycle, included with the right multiplicity @@ -5370,7 +5355,7 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur newpoints.append(P) points.pop(0) Q = P - for i in range(1,n): + for i in range(1, n): try: points.remove(f(Q)) except ValueError: @@ -5379,14 +5364,13 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur points = newpoints if PS.dimension_relative() > 1: - multipliers = [f.multiplier(pt,n) for pt in points] + multipliers = [f.multiplier(pt, n) for pt in points] else: - multipliers = [f.multiplier(pt,n)[0,0] for pt in points] + multipliers = [f.multiplier(pt, n)[0, 0] for pt in points] return multipliers - def sigma_invariants(self, n, formal=False, embedding=None, type='point', - return_polynomial=False, chow=False, deform=False, check=True): + def sigma_invariants(self, n, formal=False, embedding=None, type='point', return_polynomial=False, chow=False, deform=False, check=True): r""" Compute the values of the elementary symmetric polynomials evaluated on the ``n`` multiplier spectra of this dynamical system. @@ -5758,11 +5742,11 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', T = base_ring['k'] k = T.gens()[0] Pt = ProjectiveSpace(N, R=T, names=[str(i) for i in CR.gens()]) - deformed_polys = [poly + k*Pt.gens()[-1]**d for poly in new_f.defining_polynomials()[:-1]] + deformed_polys = [poly + k * Pt.gens()[-1] ** d for poly in new_f.defining_polynomials()[:-1]] deformed_polys += [new_f.defining_polynomials()[-1]] f_deformed = DynamicalSystem(deformed_polys) sigma_poly = f_deformed.sigma_invariants(n, chow=chow, deform=False, return_polynomial=True, check=False) - sigma_polynomial = sigma_poly.specialization({k:0}) + sigma_polynomial = sigma_poly.specialization({k: 0}) # we fix the ordering of the parent polynomial ring new_parent = sigma_polynomial.parent().change_ring(order='lex') sigma_polynomial = new_parent(sigma_polynomial) @@ -5776,8 +5760,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', else: F = base_ring if isinstance(base_ring, FractionField_generic): - if isinstance(base_ring.ring(), (MPolynomialRing_base, - PolynomialRing_generic)): + if isinstance(base_ring.ring(), (MPolynomialRing_base, PolynomialRing_generic)): f.normalize_coordinates() f_ring = f.change_ring(base_ring.ring()) X = f_ring.periodic_points(n, minimal=False, formal=formal, return_scheme=True) @@ -5789,28 +5772,28 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', ringR = PolynomialRing(base_ring, 'w, t', 2, order='lex') if chow: # create full polynomial ring - R = PolynomialRing(F, 'v', 2*N+3, order='lex') + R = PolynomialRing(F, 'v', 2 * N + 3, order='lex') var = list(R.gens()) # create polynomial ring for result R2 = PolynomialRing(F, var[:N] + var[-2:]) - psi = R2.hom(N*[0]+list(newR.gens()), newR) + psi = R2.hom(N * [0] + list(newR.gens()), newR) # create substitution to set extra variables to 0 R_zero = {R.gen(N): 1} - for j in range(N+1, 2*N+1): + for j in range(N + 1, 2 * N + 1): R_zero[R.gen(j)] = 0 t = var.pop() w = var.pop() var = var[:N] else: - R = PolynomialRing(F, 'v', N+2, order='lex') - psi = R.hom(N*[0] + list(newR.gens()), newR) + R = PolynomialRing(F, 'v', N + 2, order='lex') + psi = R.hom(N * [0] + list(newR.gens()), newR) var = list(R.gens()) t = var.pop() w = var.pop() sigma_polynomial = 1 # go through each affine patch to avoid repeating periodic points # setting the visited coordinates to 0 as we go - for j in range(N,-1,-1): + for j in range(N, -1, -1): Xa = X.affine_patch(j) fa = Fn.dehomogenize(j) Pa = fa.domain() @@ -5818,21 +5801,21 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', # create the images for the Hom to the ring we will do the elimination over # with done affine patch coordinates as 0 if chow: - im = [R.gen(i) for i in range(j)] + (N-j)*[0] + [R.gen(i) for i in range(N, R.ngens())] + im = [R.gen(i) for i in range(j)] + (N - j) * [0] + [R.gen(i) for i in range(N, R.ngens())] else: - im = list(R.gens())[:j] + (N-j)*[0] + [R.gen(i) for i in range(N, R.ngens())] - phi = Ra.hom(R.gens()[0:len(Ra.gens())]) + im = list(R.gens())[:j] + (N - j) * [0] + [R.gen(i) for i in range(N, R.ngens())] + phi = Ra.hom(R.gens()[0 : len(Ra.gens())]) # create polynomial that evaluates to the characteristic polynomial - M = t*matrix.identity(R, N) - g = (M-jacobian([phi(F.numerator())/phi(F.denominator()) for F in fa], var)).det() + M = t * matrix.identity(R, N) + g = (M - jacobian([phi(F.numerator()) / phi(F.denominator()) for F in fa], var)).det() # create the terms of the sigma invariants prod(w-lambda) - g_prime = w*R(g.denominator())(im)-R(g.numerator())(im) + g_prime = w * R(g.denominator())(im) - R(g.numerator())(im) # move the defining polynomials to the polynomial ring L = [phi(h)(im) for h in Xa.defining_polynomials()] # add the appropriate final polynomial to compute the sigma invariant polynomial # via a Poisson product in elimination if chow: - L += [g_prime + sum(R.gen(j-1)*R.gen(N+j)*(R(g.denominator())(im)) for j in range(1,N+1))] + L += [g_prime + sum(R.gen(j - 1) * R.gen(N + j) * (R(g.denominator())(im)) for j in range(1, N + 1))] else: L += [g_prime] I = R.ideal(L) @@ -5856,14 +5839,13 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', if formal: expected_degree = 0 for D in n.divisors(): - u = moebius(n/D) - inner_sum = sum(d**(D*j) for j in range(N+1)) - expected_degree += u*inner_sum + u = moebius(n / D) + inner_sum = sum(d ** (D * j) for j in range(N + 1)) + expected_degree += u * inner_sum else: - expected_degree = sum(d**(n*i) for i in range(N+1)) + expected_degree = sum(d ** (n * i) for i in range(N + 1)) if degree_w != expected_degree: - raise ValueError('sigma polynomial dropped degree, as multiplicities were not accounted for correctly; ' - 'try setting chow=True and/or deform=True') + raise ValueError('sigma polynomial dropped degree, as multiplicities were not accounted for correctly; ' 'try setting chow=True and/or deform=True') if return_polynomial: return sigma_polynomial # if we are returning a numerical list, read off the coefficients @@ -5873,99 +5855,97 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', degree_w = sigma_polynomial.degrees()[0] w, t = sigma_polynomial.variables() for i in range(degree_w + 1): - for j in range(2*i, -1, -1): - sigmas.append((-1)**(i+j)*sigma_dictionary.pop(w**(degree_w - i)*t**(j), 0)) + for j in range(2 * i, -1, -1): + sigmas.append((-1) ** (i + j) * sigma_dictionary.pop(w ** (degree_w - i) * t ** (j), 0)) return sigmas base_ring = dom.base_ring() if isinstance(base_ring, FractionField_generic): base_ring = base_ring.ring() - if isinstance(base_ring, (PolynomialRing_generic, - MPolynomialRing_base)): + if isinstance(base_ring, (PolynomialRing_generic, MPolynomialRing_base)): base_ring = base_ring.base_ring() elif base_ring in FunctionFields(): base_ring = base_ring.constant_base_field() - if not (base_ring in NumberFields() or base_ring == ZZ or isinstance(base_ring, sage.rings.abc.Order) - or (base_ring in FiniteFields())): + if not (base_ring in NumberFields() or base_ring == ZZ or isinstance(base_ring, sage.rings.abc.Order) or (base_ring in FiniteFields())): raise NotImplementedError("incompatible base field, see documentation") - #now we find the two polynomials for the resultant + # now we find the two polynomials for the resultant Fn = self.nth_iterate_map(n) fn = Fn.dehomogenize(1) R = fn.domain().coordinate_ring() S = PolynomialRing(FractionField(self.base_ring()), 'z', 2) phi = R.hom([S.gen(0)], S) - psi = dom.coordinate_ring().hom([S.gen(0), 1], S) #dehomogenize + psi = dom.coordinate_ring().hom([S.gen(0), 1], S) # dehomogenize dfn = fn[0].derivative(R.gen()) - #polynomial to be evaluated at the periodic points - mult_poly = phi(dfn.denominator())*S.gen(1) - phi(dfn.numerator()) #w-f'(z) + # polynomial to be evaluated at the periodic points + mult_poly = phi(dfn.denominator()) * S.gen(1) - phi(dfn.numerator()) # w-f'(z) - #polynomial defining the periodic points - x,y = dom.gens() + # polynomial defining the periodic points + x, y = dom.gens() if formal: - fix_poly = self.dynatomic_polynomial(n) #f(z)-z + fix_poly = self.dynatomic_polynomial(n) # f(z)-z else: - fix_poly = Fn[0]*y - Fn[1]*x #f(z) - z + fix_poly = Fn[0] * y - Fn[1] * x # f(z) - z - #check infinity - inf = dom(1,0) + # check infinity + inf = dom(1, 0) inf_per = ZZ(1) Q = self(inf) while Q != inf and inf_per <= n: inf_per += 1 Q = self(Q) - #get multiplicity + # get multiplicity if inf_per <= n: e_inf = 0 - while (y**(e_inf + 1)).divides(fix_poly): + while (y ** (e_inf + 1)).divides(fix_poly): e_inf += 1 if type == 'cycle': - #now we need to deal with having the correct number of factors - #1 multiplier for each cycle. But we need to be careful about - #the length of the cycle and the multiplicities + # now we need to deal with having the correct number of factors + # 1 multiplier for each cycle. But we need to be careful about + # the length of the cycle and the multiplicities good_res = 1 if formal: - #then we are working with the n-th dynatomic and just need - #to take one multiplier per cycle + # then we are working with the n-th dynatomic and just need + # to take one multiplier per cycle - #evaluate the resultant + # evaluate the resultant fix_poly = psi(fix_poly) res = fix_poly.resultant(mult_poly, S.gen(0)) - #take infinity into consideration + # take infinity into consideration if inf_per.divides(n): - res *= (S.gen(1) - self.multiplier(inf, n)[0,0])**e_inf + res *= (S.gen(1) - self.multiplier(inf, n)[0, 0]) ** e_inf res = res.univariate_polynomial() - #adjust multiplicities + # adjust multiplicities L = res.factor() - for p,exp in L: - good_res *= p**(exp/n) + for p, exp in L: + good_res *= p ** (exp / n) else: - #For each d-th dynatomic for d dividing n, take - #one multiplier per cycle; e.g., this treats a double 2 - #cycle as a single 4 cycle for n=4 + # For each d-th dynatomic for d dividing n, take + # one multiplier per cycle; e.g., this treats a double 2 + # cycle as a single 4 cycle for n=4 for d in n.divisors(): fix_poly_d = self.dynatomic_polynomial(d) resd = mult_poly.resultant(psi(fix_poly_d), S.gen(0)) - #check infinity + # check infinity if inf_per == d: e_inf_d = 0 - while (y**(e_inf_d + 1)).divides(fix_poly_d): + while (y ** (e_inf_d + 1)).divides(fix_poly_d): e_inf_d += 1 - resd *= (S.gen(1) - self.multiplier(inf, n)[0,0])**e_inf + resd *= (S.gen(1) - self.multiplier(inf, n)[0, 0]) ** e_inf resd = resd.univariate_polynomial() Ld = resd.factor() - for pd,ed in Ld: - good_res *= pd**(ed/d) + for pd, ed in Ld: + good_res *= pd ** (ed / d) res = good_res - else: #type is 'point' - #evaluate the resultant + else: # type is 'point' + # evaluate the resultant fix_poly = psi(fix_poly) res = fix_poly.resultant(mult_poly, S.gen(0)) - #take infinity into consideration + # take infinity into consideration if inf_per.divides(n): - res *= (S.gen(1) - self.multiplier(inf, n)[0,0])**e_inf + res *= (S.gen(1) - self.multiplier(inf, n)[0, 0]) ** e_inf res = res.univariate_polynomial() # the sigmas are the coefficients @@ -5973,7 +5953,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', sig = res.coefficients(sparse=False) den = sig.pop(-1) sig.reverse() - sig = [sig[i] * (-1)**(i+1) / den for i in range(len(sig))] + sig = [sig[i] * (-1) ** (i + 1) / den for i in range(len(sig))] return sig def reduced_form(self, **kwds): @@ -6241,19 +6221,19 @@ def reduced_form(self, **kwds): raise NotImplementedError("smallest coeff only over ZZ or QQ") check_min = kwds.get('check_minimal', True) from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import smallest_dynamical - sm_f, m = smallest_dynamical(self, dynatomic=dynatomic, start_n=start_n, - prec=prec, emb=emb, algorithm=algorithm, check_minimal=check_min) + + sm_f, m = smallest_dynamical(self, dynatomic=dynatomic, start_n=start_n, prec=prec, emb=emb, algorithm=algorithm, check_minimal=check_min) else: - #reduce via covariant + # reduce via covariant PS = self.domain() CR = PS.coordinate_ring() - x,y = CR.gens() - n = start_n # sometimes you get a problem later with 0,infty as roots + x, y = CR.gens() + n = start_n # sometimes you get a problem later with 0,infty as roots pts_poly = self.dynatomic_polynomial(n) d = ZZ(pts_poly.degree()) try: - max_mult = max([ex for p,ex in pts_poly.factor()]) - except NotImplementedError: #not factorization in numerical rings + max_mult = max([ex for p, ex in pts_poly.factor()]) + except NotImplementedError: # not factorization in numerical rings CF = ComplexField(prec=prec) if pts_poly.base_ring() != CF: if emb is None: @@ -6261,19 +6241,19 @@ def reduced_form(self, **kwds): else: pts_poly_CF = pts_poly.change_ring(emb) pp_d = pts_poly.degree() - pts_poly_CF = pts_poly_CF.subs({pts_poly_CF.parent().gen(1):1}).univariate_polynomial() - max_mult = max([pp_d - pts_poly_CF.degree()] + [ex for p,ex in pts_poly_CF.roots()]) - while ((d < 3) or (max_mult >= d/2) and (n < 5)): - n = n+1 + pts_poly_CF = pts_poly_CF.subs({pts_poly_CF.parent().gen(1): 1}).univariate_polynomial() + max_mult = max([pp_d - pts_poly_CF.degree()] + [ex for p, ex in pts_poly_CF.roots()]) + while (d < 3) or (max_mult >= d / 2) and (n < 5): + n = n + 1 if dynatomic: pts_poly = self.dynatomic_polynomial(n) else: gn = self.nth_iterate_map(n) - pts_poly = y*gn[0] - x*gn[1] + pts_poly = y * gn[0] - x * gn[1] d = ZZ(pts_poly.degree()) try: - max_mult = max([ex for p,ex in pts_poly.factor()]) - except NotImplementedError: #not factorization in numerical rings + max_mult = max([ex for p, ex in pts_poly.factor()]) + except NotImplementedError: # not factorization in numerical rings CF = ComplexField(prec=prec) if pts_poly.base_ring() != CF: if emb is None: @@ -6281,10 +6261,10 @@ def reduced_form(self, **kwds): else: pts_poly_CF = pts_poly.change_ring(emb) pp_d = pts_poly.degree() - pts_poly_CF = pts_poly_CF.subs({pts_poly_CF.parent().gen(1):1}).univariate_polynomial() - max_mult = max([pp_d - pts_poly_CF.degree()] + [ex for p,ex in pts_poly_CF.roots()]) - assert (n <= 4), "n > 4, failed to find usable poly" - G,m = pts_poly.reduced_form(prec=prec, emb=emb, smallest_coeffs=False) + pts_poly_CF = pts_poly_CF.subs({pts_poly_CF.parent().gen(1): 1}).univariate_polynomial() + max_mult = max([pp_d - pts_poly_CF.degree()] + [ex for p, ex in pts_poly_CF.roots()]) + assert n <= 4, "n > 4, failed to find usable poly" + G, m = pts_poly.reduced_form(prec=prec, emb=emb, smallest_coeffs=False) sm_f = self.conjugate(m) if return_conjugation: @@ -6413,7 +6393,7 @@ def _is_preperiodic(self, P, err=0.1, return_period=False): # and the height, so the canonical height cannot be 0 B = f.height_difference_bound() orbit = [P] - n = 1 # to compute period + n = 1 # to compute period try: Q = self(P) except TypeError: @@ -6427,13 +6407,13 @@ def _is_preperiodic(self, P, err=0.1, return_period=False): raise ValueError('orbit of point leaves domain') H = Q.global_height() n += 1 - if H <= B: #it must have been in the cycle + if H <= B: # it must have been in the cycle if return_period: m = orbit.index(Q) return (m, n - m) return True if return_period: - return (0,0) + return (0, 0) return False def postcritical_set(self, check=True): @@ -6617,12 +6597,12 @@ def is_chebyshev(self): # Check if critical point is infinity if crit[1] == 0: - g = g.subs(x=1/x) + g = g.subs(x=1 / x) new_crit = F_crit.domain()([0, 1]) # Check if output is infinity if F_crit.nth_iterate(crit, 1)[1] == 0: - g = 1/g + g = 1 / g new_crit = new_crit.dehomogenize(1)[0] e = 1 @@ -6651,18 +6631,18 @@ def is_chebyshev(self): # check that we get a consistent r value. while F_crit.nth_iterate(point, 1) not in r.keys(): if point not in ram_points.keys(): - r[F_crit.nth_iterate(point,1)] = r[point] + r[F_crit.nth_iterate(point, 1)] = r[point] else: - r[F_crit.nth_iterate(point,1)] = r[point] * ram_points[point] + r[F_crit.nth_iterate(point, 1)] = r[point] * ram_points[point] - point = F_crit.nth_iterate(point,1) + point = F_crit.nth_iterate(point, 1) # Once we get here, the image of point has an assigned r value # We check that this value is consistent if point not in ram_points.keys(): - if r[F_crit.nth_iterate(point,1)] != r[point]: + if r[F_crit.nth_iterate(point, 1)] != r[point]: return False - elif r[F_crit.nth_iterate(point,1)] != r[point] * ram_points[point]: + elif r[F_crit.nth_iterate(point, 1)] != r[point] * ram_points[point]: return False # The non-one r values must be one of the following in order for F to be Chebyshev @@ -6776,12 +6756,12 @@ def is_Lattes(self): # Check if critical point is infinity if crit[1] == 0: - g = g.subs(x=1/x) + g = g.subs(x=1 / x) new_crit = F_crit.domain()([0, 1]) # Check if output is infinity if F_crit.nth_iterate(crit, 1)[1] == 0: - g = 1/g + g = 1 / g new_crit = new_crit.dehomogenize(1)[0] @@ -6810,7 +6790,7 @@ def is_Lattes(self): else: r[F_crit.nth_iterate(point, 1)] = r[point] * ram_points[point] - point = F_crit.nth_iterate(point,1) + point = F_crit.nth_iterate(point, 1) # Once we get here the image of point has an assigned r value # We check that this value is consistent. @@ -6967,7 +6947,7 @@ def Lattes_to_curve(self, return_conjugation=False, check_lattes=False): if self.base_ring() is not QQbar: if self.base_ring() not in NumberFields(): raise NotImplementedError("Base ring must be a number field") - #The Complex case is hard to implement and needs to be done later + # The Complex case is hard to implement and needs to be done later if sqrt(self.degree()) != int(sqrt(self.degree())): raise NotImplementedError("Map is not Lattes or is Complex Lattes") if check_lattes: @@ -6975,22 +6955,22 @@ def Lattes_to_curve(self, return_conjugation=False, check_lattes=False): if not V: raise ValueError("Map is not Lattes") n = int(sqrt(self.degree())) - #Creating a Symbolic Lattes map f_sym from a short Elliptic curve + # Creating a Symbolic Lattes map f_sym from a short Elliptic curve R = PolynomialRing(self.base_ring(), 6, "avar, bvar, uvar, vvar, wvar, tvar") a, b, u, v, w, t = R.gens() P = ProjectiveSpace(R, 1, self.domain().gens()) E_sym = EllipticCurve([a, b]) f_sym = P.Lattes_map(E_sym, n) - # Conjugating f_sym map to have the right form so we can solve for the conjugating matrix later + # Conjugating f_sym map to have the right form so we can solve for the conjugating matrix later m = matrix(R, 2, [u, v, t, w]) f_sym = f_sym.conjugate(m) - f_sym.scale_by(u*w - v*t) + f_sym.scale_by(u * w - v * t) F_sym = f_sym.dehomogenize(1) - #extracting the base variables to do term by term matching - self.scale_by(1/self[0].lc()) + # extracting the base variables to do term by term matching + self.scale_by(1 / self[0].lc()) F = self.dehomogenize(1) - #Creating a set of equations, eq, from term by term matching - eq = [u*w - v*t-1] + # Creating a set of equations, eq, from term by term matching + eq = [u * w - v * t - 1] for j in range(2): if j == 0: g = F[0].numerator() @@ -6999,7 +6979,7 @@ def Lattes_to_curve(self, return_conjugation=False, check_lattes=False): g = F[0].denominator() g_sym = F_sym[0].denominator() eq += (g - g_sym).coefficients() - #Solving the equations + # Solving the equations phi = QQbar.coerce_map_from(R.base_ring()) if phi is None: phi = R.base_ring().embeddings(QQbar)[0] @@ -7015,7 +6995,7 @@ def Lattes_to_curve(self, return_conjugation=False, check_lattes=False): t = pts[0]['tvar'] w = pts[0]['wvar'] K, [a, b, u, v, t, w], phi = number_field_elements_from_algebraics([a, b, u, v, t, w]) - #creating our end products + # creating our end products E = EllipticCurve([a, b]) if return_conjugation: M = matrix(K, 2, 2, [u, v, t, w]) @@ -7023,8 +7003,7 @@ def Lattes_to_curve(self, return_conjugation=False, check_lattes=False): return E -class DynamicalSystem_projective_field(DynamicalSystem_projective, - SchemeMorphism_polynomial_projective_space_field): +class DynamicalSystem_projective_field(DynamicalSystem_projective, SchemeMorphism_polynomial_projective_space_field): def lift_to_rational_periodic(self, points_modp, B=None): r""" @@ -7090,6 +7069,7 @@ def lift_to_rational_periodic(self, points_modp, B=None): if B is None: from sage.symbolic.constants import e + B = e ** self.height_difference_bound() p = points_modp[0][0].codomain().base_ring().characteristic() @@ -7098,38 +7078,38 @@ def lift_to_rational_periodic(self, points_modp, B=None): PS = self.domain() N = PS.dimension_relative() R = RealField() - #compute the maximum p-adic precision needed to conclusively determine - #if the rational point exists - L = R((R(2 ** (N/2 + 1) * sqrt(N+1) * B**2).log()) / R(p).log() + 1).trunc() + # compute the maximum p-adic precision needed to conclusively determine + # if the rational point exists + L = R((R(2 ** (N / 2 + 1) * sqrt(N + 1) * B**2).log()) / R(p).log() + 1).trunc() points = [] for i in range(len(points_modp)): - #[point mod p, period, current p-adic precision] + # [point mod p, period, current p-adic precision] points.append([points_modp[i][0].change_ring(QQ, check=False), points_modp[i][1], 1]) good_points = [] - #shifts is used in non-Hensel lifting + # shifts is used in non-Hensel lifting shifts = None - #While there are still points to consider try to lift to next precision + # While there are still points to consider try to lift to next precision while points: q = points.pop() qindex = N - #Find the last nonzero coordinate to use for normalizations + # Find the last nonzero coordinate to use for normalizations while q[0][qindex] % p == 0: qindex -= 1 T = q[0] n = q[1] k = q[2] - T.scale_by(1 / T[qindex]) #normalize + T.scale_by(1 / T[qindex]) # normalize bad = 0 - #stop where we reach the needed precision or the point is bad + # stop where we reach the needed precision or the point is bad while k < L and bad == 0: - l = self._multipliermod(T, n, p, 2*k) - l -= l.parent().one() #f^n(x) - x + l = self._multipliermod(T, n, p, 2 * k) + l -= l.parent().one() # f^n(x) - x lp = l.change_ring(Zmod(p**k)) ldet = lp.determinant() # if the matrix is invertible then we can Hensel lift if ldet % p != 0: - RQ = ZZ.quo(p**(2*k)) + RQ = ZZ.quo(p ** (2 * k)) T.clear_denominators() newT = T.change_ring(RQ, check=False) fp = self.change_ring(RQ, check=False) @@ -7148,32 +7128,32 @@ def lift_to_rational_periodic(self, points_modp, B=None): S.scale_by(-1 / p**k) vecs = [Zmod(p**k)(S._coords[iS]) for iS in range(N + 1)] vecs.pop(qindex) - newvecs = list((lp.inverse()) * vector(vecs)) #l.inverse should be mod p^k!! + newvecs = list((lp.inverse()) * vector(vecs)) # l.inverse should be mod p^k!! newS = [] [newS.append(QQ(newvecs[i])) for i in range(qindex)] newS.append(0) [newS.append(QQ(newvecs[i])) for i in range(qindex, N)] for i in range(N + 1): newS[i] = newS[i] % (p**k) - S = PS.point(newS, False) #don't check for [0,...,0] + S = PS.point(newS, False) # don't check for [0,...,0] newT = list(T) for i in range(N + 1): newT[i] += S[i] * (p**k) T = PS.point(newT, False) T.normalize_coordinates() - #Hensel gives us 2k for the newprecision - k = min(2*k, L) + # Hensel gives us 2k for the newprecision + k = min(2 * k, L) else: - #we are unable to Hensel Lift so must try all possible lifts - #to the next precision (k+1) + # we are unable to Hensel Lift so must try all possible lifts + # to the next precision (k+1) first = 0 newq = [] - RQ = Zmod(p**(k+1)) + RQ = Zmod(p ** (k + 1)) fp = self.change_ring(RQ, check=False) if shifts is None: shifts = xmrange([p for i in range(N)]) for shift in shifts: - newT = [RQ(t) for t in T] #T.change_ring(RQ, check = False) + newT = [RQ(t) for t in T] # T.change_ring(RQ, check = False) shiftindex = 0 for i in range(N + 1): if i != qindex: @@ -7188,37 +7168,37 @@ def lift_to_rational_periodic(self, points_modp, B=None): newq.append(k + 1) first = 1 else: - points.append([newT.change_ring(QQ, check=False), n, k+1]) + points.append([newT.change_ring(QQ, check=False), n, k + 1]) if not newq: bad = 1 break else: T = newq[0] k += 1 - #given a p-adic lift of appropriate precision - #perform LLL to find the "smallest" rational approximation - #If this height is small enough, then it is a valid rational point + # given a p-adic lift of appropriate precision + # perform LLL to find the "smallest" rational approximation + # If this height is small enough, then it is a valid rational point if bad == 0: M = matrix(N + 2, N + 1) T.clear_denominators() for i in range(N + 1): M[0, i] = T[i] - M[i+1, i] = p**L - M[N+1, N] = p**L + M[i + 1, i] = p**L + M[N + 1, N] = p**L M = M.LLL() Q = [] [Q.append(M[1, i]) for i in range(N + 1)] g = gcd(Q) - #remove gcds since this is a projective point + # remove gcds since this is a projective point newB = B * g for i in range(N + 1): if abs(Q[i]) > newB: - #height too big, so not a valid point + # height too big, so not a valid point bad = 1 break if bad == 0: P = PS.point(Q, False) - #check that it is actually periodic + # check that it is actually periodic newP = copy(P) k = 1 done = False @@ -7401,42 +7381,42 @@ def all_periodic_points(self, **kwds): if not K.is_absolute(): raise TypeError("base field must be an absolute field") d = K.absolute_degree() - #check that we are not over QQ + # check that we are not over QQ if d > 1: if PS.dimension_relative() != 1: raise NotImplementedError("rational periodic points for number fields only implemented in dimension 1") w = K.absolute_generator() - #we need to dehomogenize for the Weil restriction and will check that point at infty - #separately. We also check here that we are working with a polynomial. If the map - #is not a polynomial, the Weil restriction will not be a morphism and we cannot - #apply this algorithm. + # we need to dehomogenize for the Weil restriction and will check that point at infty + # separately. We also check here that we are working with a polynomial. If the map + # is not a polynomial, the Weil restriction will not be a morphism and we cannot + # apply this algorithm. g = DS.dehomogenize(1) - inf = PS([1,0]) + inf = PS([1, 0]) k = 1 if isinstance(g[0], FractionFieldElement): g = DS.dehomogenize(0) - inf = PS([0,1]) + inf = PS([0, 1]) k = 0 if isinstance(g[0], FractionFieldElement): raise NotImplementedError("rational periodic points for number fields only implemented for polynomials") - #determine rational periodic points - #infinity is a totally ramified fixed point for a polynomial + # determine rational periodic points + # infinity is a totally ramified fixed point for a polynomial periodic_points = set([inf]) - #compute the weil restriction + # compute the weil restriction G = g.weil_restriction() F = G.homogenize(d) - #find the QQ rational periodic points for the weil restriction + # find the QQ rational periodic points for the weil restriction Fper = F.all_periodic_points(**kwds) for P in Fper: - #take the 'good' points in the weil restriction and find the - #associated number field points. + # take the 'good' points in the weil restriction and find the + # associated number field points. if P[d] == 1: - pt = [sum([P[i]*w**i for i in range(d)])] - pt.insert(k,1) + pt = [sum([P[i] * w**i for i in range(d)])] + pt.insert(k, 1) Q = PS(pt) # for each periodic point get the entire cycle if Q not in periodic_points: - #check periodic not preperiodic and add all points in cycle + # check periodic not preperiodic and add all points in cycle orb = set([Q]) Q2 = DS(Q) while Q2 not in orb: @@ -7447,7 +7427,7 @@ def all_periodic_points(self, **kwds): return list(periodic_points) primebound = kwds.pop("prime_bound", [1, 20]) p = kwds.pop("lifting_prime", 23) - pd_bounds = kwds.pop("period_degree_bounds", [4,4]) + pd_bounds = kwds.pop("period_degree_bounds", [4, 4]) alg = kwds.pop("algorithm", None) periods = kwds.pop("periods", None) badprimes = kwds.pop("bad_primes", None) @@ -7477,8 +7457,7 @@ def all_periodic_points(self, **kwds): if alg != 'lifting': for i in periods[:]: - if (alg == 'dynatomic') or ((N == 1) - and i <= pd_bounds[0] and DS.degree() <= pd_bounds[1]): + if (alg == 'dynatomic') or ((N == 1) and i <= pd_bounds[0] and DS.degree() <= pd_bounds[1]): periodic.update(DS.periodic_points(i)) periods.remove(i) if not periods: @@ -7490,14 +7469,14 @@ def all_periodic_points(self, **kwds): B = e ** DS.height_difference_bound() f = DS.change_ring(GF(p)) - all_points = f.possible_periods(True) # return the list of points and their periods. + all_points = f.possible_periods(True) # return the list of points and their periods. pos_points = [] # check period, remove duplicates for i in range(len(all_points)): if all_points[i][1] in periods and all_points[i] not in pos_points: pos_points.append(all_points[i]) - periodic_points = DS.lift_to_rational_periodic(pos_points,B) - for p,n in periodic_points: + periodic_points = DS.lift_to_rational_periodic(pos_points, B) + for p, n in periodic_points: for k in range(n): p.normalize_coordinates() periodic.add(p) @@ -7694,7 +7673,7 @@ def all_preperiodic_points(self, **kwds): (1/6*w + 1/4 : 1), (1/12*w + 1 : 1)] """ - ring = kwds.pop("R",None) + ring = kwds.pop("R", None) if ring is not None: DS = self.change_ring(ring) else: @@ -7704,38 +7683,38 @@ def all_preperiodic_points(self, **kwds): if K not in NumberFields() or not K.is_absolute(): raise TypeError("base field must be an absolute field") d = K.absolute_degree() - #check that we are not over QQ + # check that we are not over QQ if d > 1: if PS.dimension_relative() != 1: raise NotImplementedError("rational preperiodic points for number fields only implemented in dimension 1") w = K.absolute_generator() - #we need to dehomogenize for the Weil restriction and will check that point at infty - #separately. We also check here that we are working with a polynomial. If the map - #is not a polynomial, the Weil restriction will not be a morphism and we cannot - #apply this algorithm. + # we need to dehomogenize for the Weil restriction and will check that point at infty + # separately. We also check here that we are working with a polynomial. If the map + # is not a polynomial, the Weil restriction will not be a morphism and we cannot + # apply this algorithm. g = DS.dehomogenize(1) - inf = PS([1,0]) + inf = PS([1, 0]) k = 1 if isinstance(g[0], FractionFieldElement): g = DS.dehomogenize(0) - inf = PS([0,1]) + inf = PS([0, 1]) k = 0 if isinstance(g[0], FractionFieldElement): raise NotImplementedError("rational preperiodic points for number fields only implemented for polynomials") - #determine rational preperiodic points - #infinity is a totally ramified fixed point for a polynomial + # determine rational preperiodic points + # infinity is a totally ramified fixed point for a polynomial preper = set([inf]) - #compute the weil restriction + # compute the weil restriction G = g.weil_restriction() F = G.homogenize(d) - #find the QQ rational preperiodic points for the weil restriction + # find the QQ rational preperiodic points for the weil restriction Fpre = F.all_preperiodic_points(**kwds) for P in Fpre: - #take the 'good' points in the weil restriction and find the - #associated number field points. + # take the 'good' points in the weil restriction and find the + # associated number field points. if P[d] == 1: - pt = [sum([P[i]*w**i for i in range(d)])] - pt.insert(k,1) + pt = [sum([P[i] * w**i for i in range(d)])] + pt.insert(k, 1) Q = PS(pt) # for each preperiodic point get the entire connected component if Q not in preper: @@ -7743,7 +7722,7 @@ def all_preperiodic_points(self, **kwds): preper.add(t) preper = list(preper) else: - #input error checking done in possible_periods and rational_periodic_points + # input error checking done in possible_periods and rational_periodic_points badprimes = kwds.pop("bad_primes", None) periods = kwds.pop("periods", None) primebound = kwds.pop("prime_bound", [1, 20]) @@ -7751,17 +7730,14 @@ def all_preperiodic_points(self, **kwds): if badprimes is None: badprimes = DS.primes_of_bad_reduction() if periods is None: - #determine the set of possible periods - periods = DS.possible_periods(prime_bound=primebound, - bad_primes=badprimes, ncpus=num_cpus) + # determine the set of possible periods + periods = DS.possible_periods(prime_bound=primebound, bad_primes=badprimes, ncpus=num_cpus) if periods == []: - return [] #no rational preperiodic points + return [] # no rational preperiodic points p = kwds.pop("lifting_prime", 23) - #find the rational preperiodic points - T = DS.all_periodic_points(prime_bound=primebound, lifting_prime=p, - periods=periods, bad_primes=badprimes, - ncpus=num_cpus, **kwds) - preper = DS.all_rational_preimages(T) #find the preperiodic points + # find the rational preperiodic points + T = DS.all_periodic_points(prime_bound=primebound, lifting_prime=p, periods=periods, bad_primes=badprimes, ncpus=num_cpus, **kwds) + preper = DS.all_rational_preimages(T) # find the preperiodic points preper = list(preper) return preper @@ -7839,7 +7815,7 @@ def rational_preperiodic_graph(self, **kwds): sage: f.rational_preperiodic_graph() # long time Looped digraph on 5 vertices """ - #input checking done in .rational_preperiodic_points() + # input checking done in .rational_preperiodic_points() preper = self.all_preperiodic_points(**kwds) g = self._preperiodic_points_to_cyclegraph(preper) return g @@ -7904,15 +7880,15 @@ def connected_rational_component(self, P, n=0): (1/2 : -1/2 : 1), (1/2 : 1/2 : 1)] """ - points = [[],[]] # list of points and a list of their corresponding levels + points = [[], []] # list of points and a list of their corresponding levels points[0].append(P) - points[1].append(0) # P is treated as level 0 + points[1].append(0) # P is treated as level 0 nextpoints = [] nextpoints.append(P) level = 1 - foundall = False # whether done or not + foundall = False # whether done or not while not foundall: newpoints = [] for Q in nextpoints: @@ -7920,15 +7896,15 @@ def connected_rational_component(self, P, n=0): newpoints.append(self(Q)) # preimages newpoints.extend(self.rational_preimages(Q)) - del nextpoints[:] # empty list + del nextpoints[:] # empty list # add any points that are not already in the connected component for Q in newpoints: - if (Q not in points[0]): + if Q not in points[0]: points[0].append(Q) points[1].append(level) nextpoints.append(Q) # done if max level was achieved or if there were no more points to add - if ((level + 1 > n and n != 0) or len(nextpoints) == 0): + if (level + 1 > n and n != 0) or len(nextpoints) == 0: foundall = True level = level + 1 @@ -8139,66 +8115,65 @@ def conjugating_set(self, other, R=None, num_cpus=2): try: f.normalize_coordinates() g.normalize_coordinates() - except (ValueError): + except ValueError: pass - if f.degree() != g.degree():# checks that maps are of equal degree + if f.degree() != g.degree(): # checks that maps are of equal degree return [] gens = f[0].parent().gens() M = len(gens) base = f.base_ring() - if f.degree() == 0: # all constant maps are conjugate - zer = [0 for i in range(M-1)] + if f.degree() == 0: # all constant maps are conjugate + zer = [0 for i in range(M - 1)] m = [] for i in range(M): m1 = copy(zer) - m1.insert(i, f[i]/g[i]) + m1.insert(i, f[i] / g[i]) m += m1 return [matrix(base, M, M, m)] - if f.degree() == 1: # for degree 1 maps, check if matrix representations are similar + if f.degree() == 1: # for degree 1 maps, check if matrix representations are similar # make matrix forms of f1 and f2 - m1 = matrix(base,M,M,[F.coefficient(var) for F in f for var in gens]) - m2 = matrix(base,M,M,[F.coefficient(var) for F in g for var in gens]) + m1 = matrix(base, M, M, [F.coefficient(var) for F in f for var in gens]) + m2 = matrix(base, M, M, [F.coefficient(var) for F in g for var in gens]) # Note: det_ratio will be nonzero for invertible f1, f2 if m1.det() != m2.det(): - det_ratio = m1.det()/m2.det() + det_ratio = m1.det() / m2.det() try: det_root = det_ratio.nth_root(M) - except ValueError: #no root in field + except ValueError: # no root in field return [] - #matrices must have same determinant to be similar, but were in PGL - #so we can scale so the determinants are equal - m1 = (1/det_root)*m1 - bol,m = m2.is_similar(m1, transformation=True) + # matrices must have same determinant to be similar, but were in PGL + # so we can scale so the determinants are equal + m1 = (1 / det_root) * m1 + bol, m = m2.is_similar(m1, transformation=True) if bol: if m.base_ring() == base: return [m] - #else is_similar went to algebraic closure + # else is_similar went to algebraic closure if base in NumberFields(): from sage.rings.qqbar import number_field_elements_from_algebraics - K,mK,phi = number_field_elements_from_algebraics([u for t in list(m) for u in t], - minimal=True) + + K, mK, phi = number_field_elements_from_algebraics([u for t in list(m) for u in t], minimal=True) if K == base: return [matrix(K, M, M, mK)] - #may be a subfield + # may be a subfield embeds = K.embeddings(base) if len(embeds) == 0: - #not a subfield + # not a subfield return [] for emb in embeds: - m_emb = matrix(base, M,M, [emb(u) for u in mK]) - #check that it is the right embedding + m_emb = matrix(base, M, M, [emb(u) for u in mK]) + # check that it is the right embedding if f.conjugate(m_emb) == g: return [m_emb] - else: #finite field case - #always comes from prime field so can coerce + else: # finite field case + # always comes from prime field so can coerce m = matrix(base, M, M, [base(u.as_finite_field_element()[1]) for t in list(m) for u in t]) return [m] - #not similar + # not similar return [] # sigma invariants are invariant under conjugacy but are only fast in dim 1 n = f.domain().dimension_relative() - if (n == 1) and (R in NumberFields() or R in FiniteFields())\ - and (f.sigma_invariants(1) != g.sigma_invariants(1)): + if (n == 1) and (R in NumberFields() or R in FiniteFields()) and (f.sigma_invariants(1) != g.sigma_invariants(1)): return [] tup = conjugating_set_initializer(f, g) if tup == []: @@ -8366,33 +8341,32 @@ def is_conjugate(self, other, R=None, num_cpus=2): try: f.normalize_coordinates() g.normalize_coordinates() - except (ValueError): + except ValueError: pass - if f.degree() != g.degree(): # checks that maps are of equal degree + if f.degree() != g.degree(): # checks that maps are of equal degree return False - if f.degree() == 0: # all constant maps are conjugate + if f.degree() == 0: # all constant maps are conjugate return True - if f.degree() == 1: # for degree 1 maps, check if matrix representations are similar + if f.degree() == 1: # for degree 1 maps, check if matrix representations are similar # make matrix forms of f1 and f2 gens = f[0].parent().gens() M = len(gens) - m1 = matrix(f.base_ring(),M,M,[F.coefficient(var) for F in f for var in gens]) - m2 = matrix(f.base_ring(),M,M,[F.coefficient(var) for F in g for var in gens]) + m1 = matrix(f.base_ring(), M, M, [F.coefficient(var) for F in f for var in gens]) + m2 = matrix(f.base_ring(), M, M, [F.coefficient(var) for F in g for var in gens]) # Note: det_ratio will be nonzero for invertible f1, f2 if m1.det() != m2.det(): - det_ratio = m1.det()/m2.det() + det_ratio = m1.det() / m2.det() try: det_root = det_ratio.nth_root(M) - except ValueError: #no root in field + except ValueError: # no root in field return False # matrices must have same determinant to be similar, but were in PGL # so we can scale to have the determinants equal - m1 = (1/det_root)*m1 + m1 = (1 / det_root) * m1 return m1.is_similar(m2) # sigma invariants are invariant under conjugacy but are only fast in dim 1 n = f.domain().dimension_relative() - if (n == 1) and (R in NumberFields() or R in FiniteFields())\ - and (f.sigma_invariants(1) != g.sigma_invariants(1)): + if (n == 1) and (R in NumberFields() or R in FiniteFields()) and (f.sigma_invariants(1) != g.sigma_invariants(1)): return False tup = conjugating_set_initializer(f, g) if tup == []: @@ -8477,50 +8451,51 @@ def is_polynomial(self): deg = K.degree() var = K.variable_name() g = self - #get polynomial defining fixed points + # get polynomial defining fixed points G = self.dehomogenize(1).dynatomic_polynomial(1) # see if infty = (1,0) is fixed if G.degree() <= g.degree(): - #check if infty is totally ramified + # check if infty is totally ramified if len((g[1]).factor()) == 1: return True - #otherwise we need to create the tower of extensions - #which contain the fixed points. We do - #this successively so we can exit early if - #we find one and not go all the way to the splitting field - i = 0 #field index + # otherwise we need to create the tower of extensions + # which contain the fixed points. We do + # this successively so we can exit early if + # we find one and not go all the way to the splitting field + i = 0 # field index if G.degree() != 0: G = G.polynomial(G.variable(0)) while G.degree() != 0: Y = G.factor() R = G.parent() u = G - for p,exp in Y: + for p, exp in Y: if p.degree() == 1: - if len((g[0]*p[1] + g[1]*p[0]).factor()) == 1: + if len((g[0] * p[1] + g[1] * p[0]).factor()) == 1: return True - G = R(G/(p**exp)) # we already checked this root + G = R(G / (p**exp)) # we already checked this root else: - u = p #need to extend to get these roots + u = p # need to extend to get these roots if G.degree() != 0: - #create the next extension + # create the next extension if K == QQ: from sage.rings.number_field.number_field import NumberField - L = NumberField(u, 't'+str(i)) + + L = NumberField(u, 't' + str(i)) i += 1 phi = K.embeddings(L)[0] K = L elif K in FiniteFields(): - deg = deg*G.degree() - K = GF(q**(deg), prefix=var) + deg = deg * G.degree() + K = GF(q ** (deg), prefix=var) else: - L = K.extension(u, 't'+str(i)) + L = K.extension(u, 't' + str(i)) i += 1 phi1 = K.embeddings(L)[0] K = L - L = K.absolute_field('t'+str(i)) + L = K.absolute_field('t' + str(i)) i += 1 - phi = K.embeddings(L)[0]*phi1 + phi = K.embeddings(L)[0] * phi1 K = L if K in FiniteFields(): G = G.change_ring(K) @@ -8624,111 +8599,111 @@ def normal_form(self, return_conjugation=False): raise NotImplementedError("must be over an absolute number field or finite field") if K in FiniteFields(): q = K.characteristic() - psi = K.hom([K.gen()]) #identity hom for return_embedding + psi = K.hom([K.gen()]) # identity hom for return_embedding g = self G = self.dehomogenize(1).dynatomic_polynomial(1) done = False bad = True - #check infty = (1,0) is fixed + # check infty = (1,0) is fixed if G.degree() <= g.degree(): - #check infty totally ramified + # check infty totally ramified if len((g[1]).factor()) == 1: - T = self.domain()(1,0) + T = self.domain()(1, 0) bad = False done = True - m = matrix(K, 2, 2, [1,0,0,1]) - #otherwise we need to create the tower of extensions - #which contain the fixed points. We do - #this successively so we can early exit if - #we find one and not go all the way to the splitting field + m = matrix(K, 2, 2, [1, 0, 0, 1]) + # otherwise we need to create the tower of extensions + # which contain the fixed points. We do + # this successively so we can early exit if + # we find one and not go all the way to the splitting field i = 0 if G.degree() != 0: if isinstance(G.parent(), MPolynomialRing_base): G = G.polynomial(G.variable(0)) else: - #no other fixed points + # no other fixed points raise NotImplementedError("map is not a polynomial") - #check other fixed points + # check other fixed points while not done: Y = G.factor() R = G.parent() done = True - for p,exp in Y: + for p, exp in Y: if p.degree() == 1: - if len((g[0]*p[1] + g[1]*p[0]).factor()) == 1: + if len((g[0] * p[1] + g[1] * p[0]).factor()) == 1: T = self.domain()(-p[0], p[1]) bad = False done = True - break # bc only 1 totally ramified fixed pt - G = R(G/p) + break # bc only 1 totally ramified fixed pt + G = R(G / p) else: done = False u = p if not done: - #extend + # extend if K == QQ: from sage.rings.number_field.number_field import NumberField - L = NumberField(u, 't'+str(i)) + + L = NumberField(u, 't' + str(i)) i += 1 phi = K.embeddings(L)[0] K = L elif K in FiniteFields(): K, phi = K.extension(G.degree(), map=True) else: - L = K.extension(u, 't'+str(i)) + L = K.extension(u, 't' + str(i)) i += 1 phi1 = K.embeddings(L)[0] K = L - L = K.absolute_field('t'+str(i)) + L = K.absolute_field('t' + str(i)) i += 1 - phi = K.embeddings(L)[0]*phi1 + phi = K.embeddings(L)[0] * phi1 K = L psi = phi * psi - #switch to the new field + # switch to the new field G = G.change_ring(phi) g = g.change_ring(phi) if bad: raise NotImplementedError("map is not a polynomial") - #conjugate to normal form + # conjugate to normal form Q = T.codomain() - #moved totally ramified fixed point to infty - target = [T, Q(T[0]+1, 1), Q(T[0]+2, 1)] + # moved totally ramified fixed point to infty + target = [T, Q(T[0] + 1, 1), Q(T[0] + 2, 1)] source = [Q(1, 0), Q(0, 1), Q(1, 1)] m = Q.point_transformation_matrix(source, target) N = g.base_ring() d = g.degree() gc = g.conjugate(m) - #make monic + # make monic R = PolynomialRing(N, 'z') - v = N(gc[1].coefficient([0,d])/gc[0].coefficient([d,0])) - #need a (d-1)-st root to make monic - u = R.gen(0)**(d-1) - v + v = N(gc[1].coefficient([0, d]) / gc[0].coefficient([d, 0])) + # need a (d-1)-st root to make monic + u = R.gen(0) ** (d - 1) - v if d != 2 and u.is_irreducible(): - #we need to extend again + # we need to extend again if N in FiniteFields(): - M, phi = N.extension(d-1, map=True) + M, phi = N.extension(d - 1, map=True) else: - L = N.extension(u,'t'+str(i)) + L = N.extension(u, 't' + str(i)) i += 1 phi1 = N.embeddings(L)[0] - M = L.absolute_field('t'+str(i)) - phi = L.embeddings(M)[0]*phi1 - psi = phi*psi + M = L.absolute_field('t' + str(i)) + phi = L.embeddings(M)[0] * phi1 + psi = phi * psi if M in FiniteFields(): gc = gc.change_ring(M) else: gc = gc.change_ring(phi) m = matrix(M, 2, 2, [phi(s) for t in list(m) for s in t]) - rv = phi(v).nth_root(d-1) - else: #root is already in the field + rv = phi(v).nth_root(d - 1) + else: # root is already in the field M = N - rv = v.nth_root(d-1) - mc = matrix(M, 2, 2, [rv,0,0,1]) + rv = v.nth_root(d - 1) + mc = matrix(M, 2, 2, [rv, 0, 0, 1]) gcc = gc.conjugate(mc) if not (M in FiniteFields() and q.divides(d)): - #remove 2nd order term - mc2 = matrix(M, 2, 2, [1, M((-gcc[0].coefficient([d-1, 1]) - / (d*gcc[1].coefficient([0, d]))).constant_coefficient()), 0, 1]) + # remove 2nd order term + mc2 = matrix(M, 2, 2, [1, M((-gcc[0].coefficient([d - 1, 1]) / (d * gcc[1].coefficient([0, d]))).constant_coefficient()), 0, 1]) else: mc2 = mc.parent().one() gccc = gcc.conjugate(mc2) @@ -8878,15 +8853,12 @@ def potential_good_reduction(self, prime, return_conjugation=False): hom = old_parent.hom([new_parent.gens()[0]]) L = field_of_definition_periodic if hom(K.defining_polynomial()) != L.defining_polynomial(): - raise ValueError('prime ideal of %s ' % K + - 'but field of definition of fixed points is %s. ' % L + - 'see documentation for examples') + raise ValueError('prime ideal of %s ' % K + 'but field of definition of fixed points is %s. ' % L + 'see documentation for examples') embedding = K.embeddings(field_of_definition_periodic)[0] prime = embedding(prime) else: if field_of_definition_periodic is not QQ: - raise ValueError('field of definition of fixed ' + - 'points is %s but prime is in QQ. ' % field_of_definition_periodic) + raise ValueError('field of definition of fixed ' + 'points is %s but prime is in QQ. ' % field_of_definition_periodic) system = self.change_ring(field_of_definition_periodic) fixed_points = system.periodic_points(1) @@ -8909,7 +8881,7 @@ def potential_good_reduction(self, prime, return_conjugation=False): system = system.change_ring(embedding_preimage) point = point.change_ring(embedding_preimage) preimages = [point] - for i in [1,2]: + for i in [1, 2]: preimages_of_point = system.rational_preimages(point, 1) for preimage in preimages_of_point: if preimage != point: @@ -8919,9 +8891,9 @@ def potential_good_reduction(self, prime, return_conjugation=False): else: preimages = [fixed_points[0], fixed_points[1], fixed_points[2]] field_of_definition = field_of_definition_periodic - P = ProjectiveSpace(field_of_definition,1) + P = ProjectiveSpace(field_of_definition, 1) preimages = [P(i) for i in preimages] - conjugation = P.point_transformation_matrix(preimages,[P(0),P(1),P([1,0])]) + conjugation = P.point_transformation_matrix(preimages, [P(0), P(1), P([1, 0])]) new_system = system.change_ring(field_of_definition) new_system = new_system.conjugate(conjugation) res = new_system.resultant() @@ -9068,12 +9040,13 @@ def is_newton(self, return_conjugation=False): # check if Newton map sigma_1 = self.sigma_invariants(1) d = ZZ(self.degree()) - Newton_sigma = [d/(d-1)] + [0] * d # almost Newton + Newton_sigma = [d / (d - 1)] + [0] * d # almost Newton if sigma_1 != Newton_sigma: if return_conjugation: return False, None return False from sage.rings.qqbar import QQbar + Fbar = self.change_ring(QQbar) Pbar = Fbar.domain() fixed = Fbar.periodic_points(1) @@ -9081,7 +9054,7 @@ def is_newton(self, return_conjugation=False): if Fbar.multiplier(Q, 1) != 0: inf = Q break - if inf != Pbar([1,0]): + if inf != Pbar([1, 0]): # need to move to inf to infinity fixed.remove(inf) source = [inf] + fixed[:2] @@ -9094,7 +9067,7 @@ def is_newton(self, return_conjugation=False): Newton = Newton._number_field_from_algebraics() else: Newton = self - M = matrix(QQ, 2, 2, [1,0,0,1]) + M = matrix(QQ, 2, 2, [1, 0, 0, 1]) N_aff = Newton.dehomogenize(1) z = N_aff.domain().gen(0) Npoly = (z - N_aff[0]).numerator() @@ -9105,8 +9078,7 @@ def is_newton(self, return_conjugation=False): return Npoly.derivative(z) == (z - N_aff[0]).denominator() -class DynamicalSystem_projective_finite_field(DynamicalSystem_projective_field, - SchemeMorphism_polynomial_projective_space_finite_field): +class DynamicalSystem_projective_finite_field(DynamicalSystem_projective_field, SchemeMorphism_polynomial_projective_space_finite_field): def is_postcritically_finite(self, **kwds): r""" @@ -9223,7 +9195,7 @@ def orbit_structure(self, P): Q.normalize_coordinates() index += 1 I = orbit.index(Q) - return (I, index-I-1) + return (I, index - I - 1) def cyclegraph(self): r""" @@ -9281,7 +9253,7 @@ def cyclegraph(self): Q = self(P) Q.normalize_coordinates() E.append([Q]) - except ValueError: #indeterminacy + except ValueError: # indeterminacy E.append([]) else: X = self.domain() @@ -9293,11 +9265,12 @@ def cyclegraph(self): Q = self(XP) Q.normalize_coordinates() E.append([Q]) - except ValueError: #indeterminacy + except ValueError: # indeterminacy E.append([]) except TypeError: # not a point on the scheme pass from sage.graphs.digraph import DiGraph + g = DiGraph(dict(zip(V, E)), loops=True) return g @@ -9524,5 +9497,5 @@ def all_periodic_points(self, **kwds): DS = self else: DS = self.change_ring(R) - return DS.all_periodic_points(**kwds) #ensures that the correct method is run, in case user switches to infinite fields + return DS.all_periodic_points(**kwds) # ensures that the correct method is run, in case user switches to infinite fields return _all_periodic_points(DS) diff --git a/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py b/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py index 1aa9a45633a..979d3a1572f 100644 --- a/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py +++ b/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py @@ -16,6 +16,7 @@ REFERENCES: [FH2015]_, [CS1996]_, [Weh1998]_, [Hutz2007] """ + # **************************************************************************** # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -111,10 +112,10 @@ def random_WehlerK3Surface(PP): CR = PP.coordinate_ring() BR = PP.base_ring() Q = 0 - for a in xmrange([3,3]): - for b in xmrange([3,3]): - Q += BR.random_element() * CR.gen(a[0]) * CR.gen(a[1]) * CR.gen(3+b[0]) * CR.gen(3+b[1]) - #We can always change coordinates to make L diagonal + for a in xmrange([3, 3]): + for b in xmrange([3, 3]): + Q += BR.random_element() * CR.gen(a[0]) * CR.gen(a[1]) * CR.gen(3 + b[0]) * CR.gen(3 + b[1]) + # We can always change coordinates to make L diagonal L = CR.gen(0) * CR.gen(3) + CR.gen(1) * CR.gen(4) + CR.gen(2) * CR.gen(5) return WehlerK3Surface([L, Q]) @@ -135,12 +136,13 @@ class WehlerK3Surface_ring(AlgebraicScheme_subscheme_product_projective): x*u - y*v, x*y*v^2 + z^2*u*w """ + def __init__(self, polys): if not isinstance(polys, (list, tuple)): raise TypeError("polys must be a list or tuple of polynomials") R = polys[0].parent() vars = R.variable_names() - A = ProductProjectiveSpaces([2, 2],R.base_ring(),vars) + A = ProductProjectiveSpaces([2, 2], R.base_ring(), vars) CR = A.coordinate_ring() # Check for following: # Is the user calling in 2 polynomials from a list or tuple? @@ -148,16 +150,16 @@ def __init__(self, polys): if len(polys) != 2: raise AttributeError("there must be 2 polynomials") - if (all(((e[0] + e[1] + e[2]) == 1 and (e[3] + e[4] + e[5]) == 1) for e in polys[0].exponents())): + if all(((e[0] + e[1] + e[2]) == 1 and (e[3] + e[4] + e[5]) == 1) for e in polys[0].exponents()): self.L = CR(polys[0]) - elif (all(((e[0] + e[1] + e[2]) == 1 and (e[3] + e[4] + e[5]) == 1) for e in polys[1].exponents())): + elif all(((e[0] + e[1] + e[2]) == 1 and (e[3] + e[4] + e[5]) == 1) for e in polys[1].exponents()): self.L = CR(polys[1]) else: raise AttributeError("there must be one bilinear polynomial") - if (all(((e[0] + e[1] + e[2]) == 2 and (e[3] + e[4] + e[5]) == 2) for e in polys[0].exponents())): + if all(((e[0] + e[1] + e[2]) == 2 and (e[3] + e[4] + e[5]) == 2) for e in polys[0].exponents()): self.Q = CR(polys[0]) - elif (all(((e[0] + e[1] + e[2]) == 2 and (e[3] + e[4] + e[5]) == 2) for e in polys[1].exponents())): + elif all(((e[0] + e[1] + e[2]) == 2 and (e[3] + e[4] + e[5]) == 2) for e in polys[1].exponents()): self.Q = CR(polys[1]) else: raise AttributeError("there must be one biquadratic polynomial") @@ -188,7 +190,7 @@ def change_ring(self, R): LR = self.L.change_ring(R) LQ = self.Q.change_ring(R) - return (WehlerK3Surface( [LR,LQ])) + return WehlerK3Surface([LR, LQ]) def _check_satisfies_equations(self, P): r""" @@ -282,7 +284,7 @@ def _Lcoeff(self, component, i): if i not in [0, 1, 2]: raise ValueError("index must be 0, 1, or 2") R = self.ambient_space().coordinate_ring() - return self.L.coefficient(R.gen(component*3 + i)) + return self.L.coefficient(R.gen(component * 3 + i)) def _Qcoeff(self, component, i, j): r""" @@ -372,13 +374,11 @@ def Gpoly(self, component, k): raise ValueError("index must be either 0, 1, or 2") Indices = [0, 1, 2] - Indices.remove( k) + Indices.remove(k) i = Indices[0] j = Indices[1] - return (self._Lcoeff(component, j)**2) * (self._Qcoeff(component, i, i)) - (self._Lcoeff(component, i)) * \ - (self._Lcoeff(component, j)) * (self._Qcoeff(component, i, j)) + (self._Lcoeff( component, i)**2) * \ - (self._Qcoeff( component, j, j)) + return (self._Lcoeff(component, j) ** 2) * (self._Qcoeff(component, i, i)) - (self._Lcoeff(component, i)) * (self._Lcoeff(component, j)) * (self._Qcoeff(component, i, j)) + (self._Lcoeff(component, i) ** 2) * (self._Qcoeff(component, j, j)) @cached_method def Hpoly(self, component, i, j): @@ -423,10 +423,7 @@ def Hpoly(self, component, i, j): k = Indices[0] - return 2*(self._Lcoeff(component, i)) * (self._Lcoeff(component, j)) * (self._Qcoeff(component, k, k)) -\ - (self._Lcoeff(component, i)) * (self._Lcoeff( component, k)) * (self._Qcoeff(component, j, k)) -\ - (self._Lcoeff(component, j)) * (self._Lcoeff(component, k)) * (self._Qcoeff( component, i, k)) +\ - (self._Lcoeff(component, k)**2) * (self._Qcoeff(component, i, j)) + return 2 * (self._Lcoeff(component, i)) * (self._Lcoeff(component, j)) * (self._Qcoeff(component, k, k)) - (self._Lcoeff(component, i)) * (self._Lcoeff(component, k)) * (self._Qcoeff(component, j, k)) - (self._Lcoeff(component, j)) * (self._Lcoeff(component, k)) * (self._Qcoeff(component, i, k)) + (self._Lcoeff(component, k) ** 2) * (self._Qcoeff(component, i, j)) def Lxa(self, a): r""" @@ -464,8 +461,8 @@ def Lxa(self, a): ASC = AS.coordinate_ring() PSY = AS[1] PSYC = PSY.coordinate_ring() - #Define projection homomorphism - p = ASC.hom([a[0],a[1],a[2]] + list(PSY.gens()), PSYC) + # Define projection homomorphism + p = ASC.hom([a[0], a[1], a[2]] + list(PSY.gens()), PSYC) return p(self.L) def Qxa(self, a): @@ -503,7 +500,7 @@ def Qxa(self, a): ASC = AS.coordinate_ring() PSY = AS[1] PSYC = PSY.coordinate_ring() - #Define projection homomorphism + # Define projection homomorphism p = ASC.hom([a[0], a[1], a[2]] + list(PSY.gens()), PSYC) return p(self.Q) @@ -543,7 +540,7 @@ def Sxa(self, a): if a not in self.ambient_space()[0]: raise TypeError("point must be in projective space of dimension 2") PSY = self.ambient_space()[1] - return PSY.subscheme([self.Lxa(a),self.Qxa(a)]) + return PSY.subscheme([self.Lxa(a), self.Qxa(a)]) def Lyb(self, b): r""" @@ -583,7 +580,7 @@ def Lyb(self, b): PSY = AS[0] PSYC = PSY.coordinate_ring() p = ASC.hom(list(PSY.gens()) + [b[0], b[1], b[2]], PSYC) - return (p(self.L)) + return p(self.L) def Qyb(self, b): r""" @@ -622,7 +619,7 @@ def Qyb(self, b): PSY = AS[0] PSYC = PSY.coordinate_ring() p = ASC.hom(list(PSY.gens()) + [b[0], b[1], b[2]], PSYC) - return (p(self.Q)) + return p(self.Q) def Syb(self, b): r""" @@ -694,18 +691,20 @@ def Ramification_poly(self, i): - 168*y0*y1^2*y2^3 - 122*y1^3*y2^3 + 14*y0^2*y2^4 + 8*y0*y1*y2^4 - 112*y1^2*y2^4 + y2^6 """ - return ((self._Lcoeff(i, 0))**2)*(self._Qcoeff(i, 1, 2))**2 + \ - ((self._Lcoeff(i, 1))**2)*(self._Qcoeff(i, 0, 2)**2) + \ - ((self._Lcoeff(i, 2))**2)*(self._Qcoeff(i, 0, 1)**2) - \ - 2*(self._Lcoeff(i, 0))*(self._Lcoeff(i, 1))*(self._Qcoeff(i, 0, 2))*(self._Qcoeff(i, 1, 2))\ - - 2*(self._Lcoeff(i, 0))*(self._Lcoeff(i, 2))*(self._Qcoeff(i, 0, 1))*(self._Qcoeff(i, 1, 2))\ - - 2*(self._Lcoeff(i, 1))*(self._Lcoeff(i, 2))*(self._Qcoeff(i, 0, 1))*(self._Qcoeff(i, 0, 2)) + \ - 4*(self._Lcoeff(i, 0))*(self._Lcoeff(i, 1))*(self._Qcoeff(i, 0, 1))*(self._Qcoeff(i, 2, 2)) + \ - 4*(self._Lcoeff(i, 0))*(self._Lcoeff(i, 2))*(self._Qcoeff(i, 0, 2))*(self._Qcoeff(i, 1, 1)) + \ - 4*(self._Lcoeff(i, 1))*(self._Lcoeff(i, 2))*(self._Qcoeff(i, 1, 2))*(self._Qcoeff(i, 0, 0)) - \ - 4*((self._Lcoeff(i, 0))**2)*(self._Qcoeff(i, 1, 1))*(self._Qcoeff(i, 2, 2)) - \ - 4*((self._Lcoeff(i, 1))**2)*(self._Qcoeff(i, 0, 0))*(self._Qcoeff(i, 2, 2)) - \ - 4*((self._Lcoeff(i, 2))**2)*(self._Qcoeff(i, 1, 1))*(self._Qcoeff(i, 0, 0)) + return ( + ((self._Lcoeff(i, 0)) ** 2) * (self._Qcoeff(i, 1, 2)) ** 2 + + ((self._Lcoeff(i, 1)) ** 2) * (self._Qcoeff(i, 0, 2) ** 2) + + ((self._Lcoeff(i, 2)) ** 2) * (self._Qcoeff(i, 0, 1) ** 2) + - 2 * (self._Lcoeff(i, 0)) * (self._Lcoeff(i, 1)) * (self._Qcoeff(i, 0, 2)) * (self._Qcoeff(i, 1, 2)) + - 2 * (self._Lcoeff(i, 0)) * (self._Lcoeff(i, 2)) * (self._Qcoeff(i, 0, 1)) * (self._Qcoeff(i, 1, 2)) + - 2 * (self._Lcoeff(i, 1)) * (self._Lcoeff(i, 2)) * (self._Qcoeff(i, 0, 1)) * (self._Qcoeff(i, 0, 2)) + + 4 * (self._Lcoeff(i, 0)) * (self._Lcoeff(i, 1)) * (self._Qcoeff(i, 0, 1)) * (self._Qcoeff(i, 2, 2)) + + 4 * (self._Lcoeff(i, 0)) * (self._Lcoeff(i, 2)) * (self._Qcoeff(i, 0, 2)) * (self._Qcoeff(i, 1, 1)) + + 4 * (self._Lcoeff(i, 1)) * (self._Lcoeff(i, 2)) * (self._Qcoeff(i, 1, 2)) * (self._Qcoeff(i, 0, 0)) + - 4 * ((self._Lcoeff(i, 0)) ** 2) * (self._Qcoeff(i, 1, 1)) * (self._Qcoeff(i, 2, 2)) + - 4 * ((self._Lcoeff(i, 1)) ** 2) * (self._Qcoeff(i, 0, 0)) * (self._Qcoeff(i, 2, 2)) + - 4 * ((self._Lcoeff(i, 2)) ** 2) * (self._Qcoeff(i, 1, 1)) * (self._Qcoeff(i, 0, 0)) + ) @cached_method def is_degenerate(self) -> bool: @@ -752,11 +751,10 @@ def is_degenerate(self) -> bool: R = PP.coordinate_ring() PS = PP[0] # check for x fibers vars = list(PS.gens()) - R0 = PolynomialRing(K, 3, vars) #for dimension calculation to work, - #must be done with Polynomial ring over a field - #Degenerate is equivalent to a common zero, see Prop 1.4 in [CS1996]_ - I = R.ideal(self.Gpoly(1, 0), self.Gpoly(1, 1), self.Gpoly(1, 2), self.Hpoly(1, 0, 1), - self.Hpoly(1, 0, 2), self.Hpoly(1, 1, 2)) + R0 = PolynomialRing(K, 3, vars) # for dimension calculation to work, + # must be done with Polynomial ring over a field + # Degenerate is equivalent to a common zero, see Prop 1.4 in [CS1996]_ + I = R.ideal(self.Gpoly(1, 0), self.Gpoly(1, 1), self.Gpoly(1, 2), self.Hpoly(1, 0, 1), self.Hpoly(1, 0, 2), self.Hpoly(1, 1, 2)) phi = R.hom(vars + [0, 0, 0], R0) I = phi(I) if I.dimension() != 0: @@ -764,11 +762,10 @@ def is_degenerate(self) -> bool: PS = PP[1] # check for y fibers vars = list(PS.gens()) - R0 = PolynomialRing(K,3,vars) #for dimension calculation to work, - #must be done with Polynomial ring over a field - #Degenerate is equivalent to a common zero, see Prop 1.4 in [CS1996]_ - I = R.ideal(self.Gpoly(0, 0), self.Gpoly(0, 1), self.Gpoly(0, 2), self.Hpoly(0, 0, 1), - self.Hpoly(0, 0, 2), self.Hpoly(0, 1, 2)) + R0 = PolynomialRing(K, 3, vars) # for dimension calculation to work, + # must be done with Polynomial ring over a field + # Degenerate is equivalent to a common zero, see Prop 1.4 in [CS1996]_ + I = R.ideal(self.Gpoly(0, 0), self.Gpoly(0, 1), self.Gpoly(0, 2), self.Hpoly(0, 0, 1), self.Hpoly(0, 0, 2), self.Hpoly(0, 1, 2)) phi = R.hom([0, 0, 0] + vars, R0) I = phi(I) return I.dimension() != 0 @@ -834,8 +831,7 @@ def degenerate_fibers(self): vars = list(PSX.gens()) K = FractionField(PSX.base_ring()) R0 = PolynomialRing(K, 3, vars) - I = R.ideal(self.Gpoly(1, 0), self.Gpoly(1, 1), self.Gpoly(1, 2), self.Hpoly(1, 0,1 ), - self.Hpoly(1, 0, 2), self.Hpoly(1, 1, 2)) + I = R.ideal(self.Gpoly(1, 0), self.Gpoly(1, 1), self.Gpoly(1, 2), self.Hpoly(1, 0, 1), self.Hpoly(1, 0, 2), self.Hpoly(1, 1, 2)) phi = R.hom(vars + [0, 0, 0], R0) I = phi(I) xFibers = [] @@ -845,28 +841,27 @@ def degenerate_fibers(self): del affvars[n] R1 = PolynomialRing(K, 2, affvars, order='lex') mapvars = list(R1.gens()) - mapvars.insert(n,1) + mapvars.insert(n, 1) phi1 = R0.hom(mapvars, R1) J = phi1(I) - if (J.dimension() == 0): + if J.dimension() == 0: Var = J.variety() if Var != [{}]: - for d in Var: #iterate through dictionaries - P = [] #new point - for z in mapvars: #assign coordinate values - if (z == 1): + for d in Var: # iterate through dictionaries + P = [] # new point + for z in mapvars: # assign coordinate values + if z == 1: P.append(1) else: P.append(d[z]) - MP = PSX(P) #make projective point + MP = PSX(P) # make projective point if MP not in xFibers: xFibers.append(MP) PSY = PP[1] vars = list(PSY.gens()) K = FractionField(PSY.base_ring()) R0 = PolynomialRing(K, 3, vars) - I = R.ideal(self.Gpoly(0, 0), self.Gpoly(0, 1), self.Gpoly(0, 2), self.Hpoly(0, 0, 1), - self.Hpoly(0, 0, 2), self.Hpoly(0, 1, 2)) + I = R.ideal(self.Gpoly(0, 0), self.Gpoly(0, 1), self.Gpoly(0, 2), self.Hpoly(0, 0, 1), self.Hpoly(0, 0, 2), self.Hpoly(0, 1, 2)) phi = PP.coordinate_ring().hom([0, 0, 0] + vars, R0) I = phi(I) yFibers = [] @@ -877,22 +872,22 @@ def degenerate_fibers(self): R1 = PolynomialRing(K, 2, affvars, order='lex') mapvars = list(R1.gens()) mapvars.insert(n, 1) - phi1 = R0.hom(mapvars,R1) + phi1 = R0.hom(mapvars, R1) J = phi1(I) - if (J.dimension() == 0): + if J.dimension() == 0: Var = J.variety() if Var != [{}]: - for d in Var: #iterate through dictionaries - P = [] #new point - for z in mapvars: #assign coordinate values - if (z == 1): + for d in Var: # iterate through dictionaries + P = [] # new point + for z in mapvars: # assign coordinate values + if z == 1: P.append(1) else: P.append(d[z]) - MP = PSY(P) #make projective point + MP = PSY(P) # make projective point if MP not in yFibers: yFibers.append(MP) - return [xFibers,yFibers] + return [xFibers, yFibers] @cached_method def degenerate_primes(self, check=True): @@ -944,23 +939,22 @@ def degenerate_primes(self, check=True): raise TypeError("surface is degenerate at all primes") RR = PP.coordinate_ring() - #x-fibers + # x-fibers PSX = PP[0] vars = list(PSX.gens()) K = PSX.base_ring() R = PolynomialRing(K, 3, vars) - I = RR.ideal(self.Gpoly(1, 0), self.Gpoly(1, 1), self.Gpoly(1, 2), self.Hpoly(1, 0, 1), - self.Hpoly(1, 0, 2), self.Hpoly(1, 1, 2)) + I = RR.ideal(self.Gpoly(1, 0), self.Gpoly(1, 1), self.Gpoly(1, 2), self.Hpoly(1, 0, 1), self.Hpoly(1, 0, 2), self.Hpoly(1, 1, 2)) phi = PP.coordinate_ring().hom(vars + [0, 0, 0], R) I = phi(I) bad_primes = [] - #move the ideal to the ring of integers + # move the ideal to the ring of integers if R.base_ring().is_field(): - S = PolynomialRing(R.base_ring().ring_of_integers(),R.gens(),R.ngens()) + S = PolynomialRing(R.base_ring().ring_of_integers(), R.gens(), R.ngens()) I = S.ideal(I.gens()) GB = I.groebner_basis() - #get the primes dividing the coefficients of the monomials x_i^k_i + # get the primes dividing the coefficients of the monomials x_i^k_i for i in range(len(GB)): LT = GB[i].lt().degrees() power = 0 @@ -968,23 +962,22 @@ def degenerate_primes(self, check=True): if LT[j] != 0: power += 1 if power == 1: - bad_primes = bad_primes+GB[i].lt().coefficients()[0].support() + bad_primes = bad_primes + GB[i].lt().coefficients()[0].support() - #y-fibers + # y-fibers PSY = PP[1] vars = list(PSY.gens()) K = PSY.base_ring() R = PolynomialRing(K, 3, vars) - I = RR.ideal(self.Gpoly(0, 0), self.Gpoly(0, 1), self.Gpoly(0, 2), self.Hpoly(0, 0, 1), - self.Hpoly(0, 0, 2), self.Hpoly(0, 1, 2)) + I = RR.ideal(self.Gpoly(0, 0), self.Gpoly(0, 1), self.Gpoly(0, 2), self.Hpoly(0, 0, 1), self.Hpoly(0, 0, 2), self.Hpoly(0, 1, 2)) phi = PP.coordinate_ring().hom([0, 0, 0] + vars, R) I = phi(I) - #move the ideal to the ring of integers + # move the ideal to the ring of integers if R.base_ring().is_field(): - S = PolynomialRing(R.base_ring().ring_of_integers(),R.gens(),R.ngens()) + S = PolynomialRing(R.base_ring().ring_of_integers(), R.gens(), R.ngens()) I = S.ideal(I.gens()) GB = I.groebner_basis() - #get the primes dividing the coefficients of the monomials x_i^k_i + # get the primes dividing the coefficients of the monomials x_i^k_i for i in range(len(GB)): LT = GB[i].lt().degrees() power = 0 @@ -992,7 +985,7 @@ def degenerate_primes(self, check=True): if LT[j] != 0: power += 1 if power == 1: - bad_primes = bad_primes+GB[i].lt().coefficients()[0].support() + bad_primes = bad_primes + GB[i].lt().coefficients()[0].support() bad_primes = sorted(set(bad_primes)) # check to return only the truly bad primes if check: @@ -1038,7 +1031,7 @@ def is_smooth(self) -> bool: vars = list(self.ambient_space().gens()) M = jacobian([self.L, self.Q], vars) R = self.ambient_space().coordinate_ring() - I = R.ideal(M.minors(2) + [self.L,self.Q]) + I = R.ideal(M.minors(2) + [self.L, self.Q]) T = PolynomialRing(self.ambient_space().base_ring().fraction_field(), 4, 'h') # check the 9 affine charts for a singular point for l in xmrange([3, 3]): @@ -1139,100 +1132,83 @@ def sigmaX(self, P, **kwds): raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented" % (P, self)) pt = list(P[0]) + [0, 0, 0] if P[1][0] != 0: - a, b, c = [P[1][0]*self.Gpoly(1, 0)(*pt), - -1*P[1][0]*self.Hpoly(1, 0, 1)(*pt) - P[1][1]*self.Gpoly(1, 0)(*pt), - -P[1][0]*self.Hpoly(1, 0, 2)(*pt) - P[1][2]*self.Gpoly(1, 0)(*pt)] + a, b, c = [P[1][0] * self.Gpoly(1, 0)(*pt), -1 * P[1][0] * self.Hpoly(1, 0, 1)(*pt) - P[1][1] * self.Gpoly(1, 0)(*pt), -P[1][0] * self.Hpoly(1, 0, 2)(*pt) - P[1][2] * self.Gpoly(1, 0)(*pt)] elif P[1][1] != 0: - a, b, c = [-1*P[1][1]*self.Hpoly(1, 0, 1)(*pt)-P[1][0]*self.Gpoly(1, 1)(*pt), - P[1][1]*self.Gpoly(1, 1)(*pt), - -P[1][1]*self.Hpoly(1, 1, 2)(*pt)-P[1][2]*self.Gpoly(1, 1)(*pt)] + a, b, c = [-1 * P[1][1] * self.Hpoly(1, 0, 1)(*pt) - P[1][0] * self.Gpoly(1, 1)(*pt), P[1][1] * self.Gpoly(1, 1)(*pt), -P[1][1] * self.Hpoly(1, 1, 2)(*pt) - P[1][2] * self.Gpoly(1, 1)(*pt)] else: - a, b, c = [-1*P[1][2]*self.Hpoly(1, 0, 2)(*pt) - P[1][0]*self.Gpoly(1, 2)(*pt), - -P[1][2]*self.Hpoly(1, 1, 2)(*pt) - P[1][1]*self.Gpoly(1, 2)(*pt), - P[1][2]*self.Gpoly(1, 2)(*pt)] + a, b, c = [-1 * P[1][2] * self.Hpoly(1, 0, 2)(*pt) - P[1][0] * self.Gpoly(1, 2)(*pt), -P[1][2] * self.Hpoly(1, 1, 2)(*pt) - P[1][1] * self.Gpoly(1, 2)(*pt), P[1][2] * self.Gpoly(1, 2)(*pt)] Point = [P[0][0], P[0][1], P[0][2], a, b, c] if any([a, b, c]): if normalize: - Point = self.point(Point,False) + Point = self.point(Point, False) Point.normalize_coordinates() return Point - return self.point(Point,False) - #Start of the degenerate case + return self.point(Point, False) + # Start of the degenerate case R = self.ambient_space().coordinate_ring() BR = self.ambient_space().base_ring() S = PolynomialRing(BR, 6, 's0, s1, w1, z0, z1, z2') - s0,s1,w1,z0,z1,z2 = S.gens() - #Define the blow-up map with (s0,s1) the new `\mathbb{P}^1` coordinates - #so that the points on the fiber come in pairs on the lines defined by `(s0,s1)` - #this allows us to extend the involution to degenerate fibers + s0, s1, w1, z0, z1, z2 = S.gens() + # Define the blow-up map with (s0,s1) the new `\mathbb{P}^1` coordinates + # so that the points on the fiber come in pairs on the lines defined by `(s0,s1)` + # this allows us to extend the involution to degenerate fibers if P[0][0] != 0: - t1 = BR(P[0][1]/P[0][0]) + t1 = BR(P[0][1] / P[0][0]) t = w1 - t1 - phi = R.hom([s0, s0*w1, s1*t + s0*P[0][2]/P[0][0], z0, z1, z2], S) + phi = R.hom([s0, s0 * w1, s1 * t + s0 * P[0][2] / P[0][0], z0, z1, z2], S) elif P[0][1] != 0: - t1 = BR(P[0][0]/P[0][1]) + t1 = BR(P[0][0] / P[0][1]) t = w1 - t1 - phi = R.hom([s0*w1, s0, s1*t + s0*P[0][2]/P[0][1], z0, z1, z2], S) + phi = R.hom([s0 * w1, s0, s1 * t + s0 * P[0][2] / P[0][1], z0, z1, z2], S) else: - t1 = BR(P[0][1]/P[0][2]) + t1 = BR(P[0][1] / P[0][2]) t = w1 - t1 - phi = R.hom([s1*(t) + s0*P[0][0]/P[0][2], s0*w1, s0, z0, z1, z2], S) + phi = R.hom([s1 * (t) + s0 * P[0][0] / P[0][2], s0 * w1, s0, z0, z1, z2], S) # Blow-up the fiber - T = [phi(self.L),phi(self.Q), - phi(self.Gpoly(1, 0)), - phi(self.Gpoly(1, 1)), - phi(self.Gpoly(1, 2)), - -phi(self.Hpoly(1, 0, 1)), - -phi(self.Hpoly(1, 0, 2)), - -phi(self.Hpoly(1, 1, 2))] + T = [phi(self.L), phi(self.Q), phi(self.Gpoly(1, 0)), phi(self.Gpoly(1, 1)), phi(self.Gpoly(1, 2)), -phi(self.Hpoly(1, 0, 1)), -phi(self.Hpoly(1, 0, 2)), -phi(self.Hpoly(1, 1, 2))] maxexp = [] - #Find highest exponent that we can divide out by to get a nonzero answer - for i in range(2,len(T)): + # Find highest exponent that we can divide out by to get a nonzero answer + for i in range(2, len(T)): e = 0 - while (T[i]/t**e).subs({w1:t1}) == 0: + while (T[i] / t**e).subs({w1: t1}) == 0: e += 1 maxexp.append(e) e = min(maxexp) - #Fix L and Q + # Fix L and Q for i in range(2): - while T[i].subs({w1:t1}) == 0: - T[i] = T[i]/t - T[i] = T[i].subs({w1:t1}) - - #Fix G and H polys - for i in range(2,len(T)): - T[i] = T[i]/t**e - T[i] = T[i].subs({w1:t1}) - - #Defines the ideal whose solution gives `(s0, s1)` and the two points - #on the fiber - RR = PolynomialRing(BR, 5,'s0, s1, z0, z1, z2',order='lex') + while T[i].subs({w1: t1}) == 0: + T[i] = T[i] / t + T[i] = T[i].subs({w1: t1}) + + # Fix G and H polys + for i in range(2, len(T)): + T[i] = T[i] / t**e + T[i] = T[i].subs({w1: t1}) + + # Defines the ideal whose solution gives `(s0, s1)` and the two points + # on the fiber + RR = PolynomialRing(BR, 5, 's0, s1, z0, z1, z2', order='lex') s0, s1, z0, z1, z2 = RR.gens() - I = RR.ideal([RR(T[0]), - RR(T[1]), - RR(T[2]) - P[1][0]*z0, RR(T[3]) - P[1][1]*z1, RR(T[4])-P[1][2]*z2, - RR(T[5]) - (P[1][0]*z1 + P[1][1]*z0), - RR(T[6]) - (P[1][0]*z2 + P[1][2]*z0), - RR(T[7]) - (P[1][1]*z2 + P[1][2]*z1)]) - - #Find the points - SS = PolynomialRing(BR, 4,'s, z0, z1, z2', order='lex') + I = RR.ideal([RR(T[0]), RR(T[1]), RR(T[2]) - P[1][0] * z0, RR(T[3]) - P[1][1] * z1, RR(T[4]) - P[1][2] * z2, RR(T[5]) - (P[1][0] * z1 + P[1][1] * z0), RR(T[6]) - (P[1][0] * z2 + P[1][2] * z0), RR(T[7]) - (P[1][1] * z2 + P[1][2] * z1)]) + + # Find the points + SS = PolynomialRing(BR, 4, 's, z0, z1, z2', order='lex') s, z0, z1, z2 = SS.gens() phi = RR.hom([s, 1, z0, z1, z2], SS) J = phi(I) if J.dimension() > 0: raise ValueError("cannot distinguish points in the degenerate fiber") V = J.variety() - #Our blow-up point has more than one line passing through it, thus we cannot find - #the corresponding point on the surface + # Our blow-up point has more than one line passing through it, thus we cannot find + # the corresponding point on the surface if len(V) > 2: raise ValueError("cannot distinguish points in the degenerate fiber") - #We always expect to have the trivial solution (0, 0, 0) + # We always expect to have the trivial solution (0, 0, 0) if len(V) == 2: for D in V: if D[s] != 0: @@ -1241,33 +1217,26 @@ def sigmaX(self, P, **kwds): newT = [phi(tee) for tee in T] for i in range(2): while newT[i] != 0 and s.divides(newT[i]): - newT[i] = SS(newT[i]/s) + newT[i] = SS(newT[i] / s) maxexp = [] for i in range(2, len(T)): e = 0 if newT[i] != 0: - while (newT[i]/s**e).subs({s:0}) == 0: + while (newT[i] / s**e).subs({s: 0}) == 0: e += 1 maxexp.append(e) e = min(maxexp) - #Cancel the powers of s - for i in range(2,len(T)): - newT[i] = newT[i]/s**e - #Create the new ideal - II = SS.ideal([SS(newT[0]), - SS(newT[1]), - SS(newT[2]) - P[1][0]*z0, - SS(newT[3]) - P[1][1]*z1, - SS(newT[4]) - P[1][2]*z2, - SS(newT[5]) - (P[1][0]*z1 + P[1][1]*z0), - SS(newT[6]) - (P[1][0]*z2 + P[1][2]*z0), - SS(newT[7]) - (P[1][1]*z2 + P[1][2]*z1)]) - - #Find the points + # Cancel the powers of s + for i in range(2, len(T)): + newT[i] = newT[i] / s**e + # Create the new ideal + II = SS.ideal([SS(newT[0]), SS(newT[1]), SS(newT[2]) - P[1][0] * z0, SS(newT[3]) - P[1][1] * z1, SS(newT[4]) - P[1][2] * z2, SS(newT[5]) - (P[1][0] * z1 + P[1][1] * z0), SS(newT[6]) - (P[1][0] * z2 + P[1][2] * z0), SS(newT[7]) - (P[1][1] * z2 + P[1][2] * z1)]) + + # Find the points SSS = PolynomialRing(BR, 3, 'z0, z1, z2', order='lex') - z0,z1,z2 = SSS.gens() + z0, z1, z2 = SSS.gens() phi = SS.hom([0, z0, z1, z2], SSS) J2 = phi(II) if J2.dimension() > 0: @@ -1281,7 +1250,7 @@ def sigmaX(self, P, **kwds): if len(V) == 0 or not any([a, b, c]): SS = PolynomialRing(BR, 3, 'z0, z1, z2', order='lex') - z0,z1,z2 = SS.gens() + z0, z1, z2 = SS.gens() phi = RR.hom([1, 0, z0, z1, z2], SS) J = phi(I) if J.dimension() > 0: @@ -1383,17 +1352,11 @@ def sigmaY(self, P, **kwds): raise TypeError("%s fails to convert into the map's domain %s, but a `pushforward` method is not properly implemented" % (P, self)) pt = [0, 0, 0] + list(P[1]) if P[0][0] != 0: - a, b, c = [P[0][0]*self.Gpoly(0, 0)(*pt), - -1*P[0][0]*self.Hpoly(0, 0, 1)(*pt) - P[0][1]*self.Gpoly(0, 0)(*pt), - -P[0][0]*self.Hpoly(0, 0, 2)(*pt) - P[0][2]*self.Gpoly(0, 0)(*pt)] + a, b, c = [P[0][0] * self.Gpoly(0, 0)(*pt), -1 * P[0][0] * self.Hpoly(0, 0, 1)(*pt) - P[0][1] * self.Gpoly(0, 0)(*pt), -P[0][0] * self.Hpoly(0, 0, 2)(*pt) - P[0][2] * self.Gpoly(0, 0)(*pt)] elif P[0][1] != 0: - a, b, c = [-1*P[0][1]*self.Hpoly(0, 0, 1)(*pt) - P[0][0]*self.Gpoly(0, 1)(*pt), - P[0][1]*self.Gpoly(0, 1)(*pt), - -P[0][1]*self.Hpoly(0, 1, 2)(*pt) - P[0][2]*self.Gpoly(0, 1)(*pt)] + a, b, c = [-1 * P[0][1] * self.Hpoly(0, 0, 1)(*pt) - P[0][0] * self.Gpoly(0, 1)(*pt), P[0][1] * self.Gpoly(0, 1)(*pt), -P[0][1] * self.Hpoly(0, 1, 2)(*pt) - P[0][2] * self.Gpoly(0, 1)(*pt)] else: - a, b, c = [-1*P[0][2]*self.Hpoly(0, 0, 2)(*pt) - P[0][0]*self.Gpoly(0, 2)(*pt), - - P[0][2]*self.Hpoly(0, 1, 2)(*pt) - P[0][1]*self.Gpoly(0, 2)(*pt), - P[0][2]*self.Gpoly(0, 2)(*pt)] + a, b, c = [-1 * P[0][2] * self.Hpoly(0, 0, 2)(*pt) - P[0][0] * self.Gpoly(0, 2)(*pt), -P[0][2] * self.Hpoly(0, 1, 2)(*pt) - P[0][1] * self.Gpoly(0, 2)(*pt), P[0][2] * self.Gpoly(0, 2)(*pt)] Point = [a, b, c, P[1][0], P[1][1], P[1][2]] if any([a, b, c]): if normalize: @@ -1402,69 +1365,55 @@ def sigmaY(self, P, **kwds): return Point return self.point(Point, False) - #Start of the degenerate case + # Start of the degenerate case R = self.ambient_space().coordinate_ring() BR = self.ambient_space().base_ring() S = PolynomialRing(BR, 6, 'z0, z1, z2, s0, s1, w1') z0, z1, z2, s0, s1, w1 = S.gens() - #Define the blow-up map with (s0,s1) the new `\mathbb{P}^1` coordinates - #so that the points on the fiber come in pairs on the lines defined by `(s0,s1)` - #this allows us to extend the involution to degenerate fibers + # Define the blow-up map with (s0,s1) the new `\mathbb{P}^1` coordinates + # so that the points on the fiber come in pairs on the lines defined by `(s0,s1)` + # this allows us to extend the involution to degenerate fibers if P[1][0] != 0: - t1 = BR(P[1][1]/P[1][0]) + t1 = BR(P[1][1] / P[1][0]) t = w1 - t1 - phi = R.hom([z0, z1, z2, s0, s0*w1, s1*t + s0*P[1][2]/P[1][0]], S) + phi = R.hom([z0, z1, z2, s0, s0 * w1, s1 * t + s0 * P[1][2] / P[1][0]], S) elif P[1][1] != 0: - t1 = BR(P[1][0]/P[1][1]) + t1 = BR(P[1][0] / P[1][1]) t = w1 - t1 - phi = R.hom([z0, z1, z2, s0*w1, s0, s1*t + s0*P[1][2]/P[1][1]], S) + phi = R.hom([z0, z1, z2, s0 * w1, s0, s1 * t + s0 * P[1][2] / P[1][1]], S) else: - t1 = BR(P[1][1]/P[1][2]) + t1 = BR(P[1][1] / P[1][2]) t = w1 - t1 - phi = R.hom([z0, z1, z2, s1*(t) + s0*P[1][0]/P[1][2], s0*w1, s0], S) - - #Blow-up the fiber - T = [phi(self.L), - phi(self.Q), - phi(self.Gpoly(0, 0)), - phi(self.Gpoly(0, 1)), - phi(self.Gpoly(0, 2)), - -phi(self.Hpoly(0, 0, 1)), - -phi(self.Hpoly(0, 0, 2)), - -phi(self.Hpoly(0, 1, 2))] + phi = R.hom([z0, z1, z2, s1 * (t) + s0 * P[1][0] / P[1][2], s0 * w1, s0], S) + + # Blow-up the fiber + T = [phi(self.L), phi(self.Q), phi(self.Gpoly(0, 0)), phi(self.Gpoly(0, 1)), phi(self.Gpoly(0, 2)), -phi(self.Hpoly(0, 0, 1)), -phi(self.Hpoly(0, 0, 2)), -phi(self.Hpoly(0, 1, 2))] maxexp = [] # Find highest exponent that we can divide out by to get a # nonzero answer for i in range(2, len(T)): e = 0 - while (T[i]/t**e).subs({w1:t1}) == 0: + while (T[i] / t**e).subs({w1: t1}) == 0: e += 1 maxexp.append(e) e = min(maxexp) for i in range(2): - while T[i].subs({w1:t1}) == 0: - T[i] = T[i]/t - T[i] = T[i].subs({w1:t1}) + while T[i].subs({w1: t1}) == 0: + T[i] = T[i] / t + T[i] = T[i].subs({w1: t1}) for i in range(2, len(T)): - T[i] = T[i]/t**e - T[i] = T[i].subs({w1:t1}) + T[i] = T[i] / t**e + T[i] = T[i].subs({w1: t1}) # Defines the ideal whose solution gives `(s0,s1)` and the two points # on the fiber RR = PolynomialRing(BR, 5, 's0, s1, z0, z1, z2', order='lex') s0, s1, z0, z1, z2 = RR.gens() - I = RR.ideal([RR(T[0]), - RR(T[1]), - RR(T[2]) - P[0][0]*z0, - RR(T[3]) - P[0][1]*z1, - RR(T[4]) - P[0][2]*z2, - RR(T[5]) - (P[0][0]*z1 + P[0][1]*z0), - RR(T[6]) - (P[0][0]*z2 + P[0][2]*z0), - RR(T[7]) - (P[0][1]*z2 + P[0][2]*z1)]) - #Find the points + I = RR.ideal([RR(T[0]), RR(T[1]), RR(T[2]) - P[0][0] * z0, RR(T[3]) - P[0][1] * z1, RR(T[4]) - P[0][2] * z2, RR(T[5]) - (P[0][0] * z1 + P[0][1] * z0), RR(T[6]) - (P[0][0] * z2 + P[0][2] * z0), RR(T[7]) - (P[0][1] * z2 + P[0][2] * z1)]) + # Find the points SS = PolynomialRing(BR, 4, 's, z0, z1, z2', order='lex') s, z0, z1, z2 = SS.gens() phi = RR.hom([s, 1, z0, z1, z2], SS) @@ -1473,8 +1422,8 @@ def sigmaY(self, P, **kwds): raise ValueError("cannot distinguish points in the degenerate fiber") V = J.variety() - #Our blow-up point has more than one line passing through it, thus we cannot find - #the corresponding point on the surface + # Our blow-up point has more than one line passing through it, thus we cannot find + # the corresponding point on the surface if len(V) > 2: raise ValueError("cannot distinguish points in the degenerate fiber") # We always expect to have the trivial solution (0, 0, 0) @@ -1486,27 +1435,20 @@ def sigmaY(self, P, **kwds): newT = [phi(tee) for tee in T] for i in range(2): while newT[i] != 0 and s.divides(newT[i]): - newT[i] = SS(newT[i]/s) + newT[i] = SS(newT[i] / s) maxexp = [] for i in range(2, len(T)): e = 0 if newT[i] != 0: - while (newT[i]/s**e).subs({s:0}) == 0: + while (newT[i] / s**e).subs({s: 0}) == 0: e += 1 maxexp.append(e) e = min(maxexp) - #Cancel out the powers of s - for i in range(2,len(T)): - newT[i] = newT[i]/s**e - #Create the new ideal - II = SS.ideal([SS(newT[0]), - SS(newT[1]), - SS(newT[2]) - P[0][0]*z0, - SS(newT[3]) - P[0][1]*z1, - SS(newT[4]) - P[0][2]*z2, - SS(newT[5]) - (P[0][0]*z1 + P[0][1]*z0), - SS(newT[6]) - (P[0][0]*z2 + P[0][2]*z0), - SS(newT[7]) - (P[0][1]*z2 + P[0][2]*z1)]) + # Cancel out the powers of s + for i in range(2, len(T)): + newT[i] = newT[i] / s**e + # Create the new ideal + II = SS.ideal([SS(newT[0]), SS(newT[1]), SS(newT[2]) - P[0][0] * z0, SS(newT[3]) - P[0][1] * z1, SS(newT[4]) - P[0][2] * z2, SS(newT[5]) - (P[0][0] * z1 + P[0][1] * z0), SS(newT[6]) - (P[0][0] * z2 + P[0][2] * z0), SS(newT[7]) - (P[0][1] * z2 + P[0][2] * z1)]) # Find the points SSS = PolynomialRing(BR, 3, 'z0, z1, z2', order='lex') z0, z1, z2 = SSS.gens() @@ -1668,50 +1610,46 @@ def lambda_plus(self, P, v, N, m, n, prec=100): K = Qp(v, prec) PK = P.change_ring(K) W = self.change_ring(K) - Rx = W.ambient_space().coordinate_ring().hom( - list(W.ambient_space()[0].coordinate_ring().gens()) + [0, 0, 0], - W.ambient_space()[0].coordinate_ring()) - Ry = W.ambient_space().coordinate_ring().hom( - [0, 0, 0] + list(W.ambient_space()[1].coordinate_ring().gens()), - W.ambient_space()[1].coordinate_ring()) + Rx = W.ambient_space().coordinate_ring().hom(list(W.ambient_space()[0].coordinate_ring().gens()) + [0, 0, 0], W.ambient_space()[0].coordinate_ring()) + Ry = W.ambient_space().coordinate_ring().hom([0, 0, 0] + list(W.ambient_space()[1].coordinate_ring().gens()), W.ambient_space()[1].coordinate_ring()) beta = R(2 + sqrt(3)) L = [x.abs() for x in list(PK[0])] i = L.index(max(L)) L = [y.abs() for y in list(PK[1])] j = L.index(max(L)) - #Compute the local height wrt the divisor E_{mn}^{+} - local_height = beta*R((PK[0][i]/PK[0][m]).abs()).log() - R((PK[1][j]/PK[1][n]).abs()).log() + # Compute the local height wrt the divisor E_{mn}^{+} + local_height = beta * R((PK[0][i] / PK[0][m]).abs()).log() - R((PK[1][j] / PK[1][n]).abs()).log() for e in range(N): - #Take next iterate + # Take next iterate Q = W.phi(PK, check=False) L = [x.abs() for x in list(Q[0])] k = L.index(max(L)) L = [y.abs() for y in list(Q[1])] l = L.index(max(L)) newP = copy(PK) - #normalize PK + # normalize PK newP.scale_by([~PK[0][i], ZZ.one()]) - #Find B and A, helper values for the local height + # Find B and A, helper values for the local height if PK[1][j].abs() <= PK[1][l].abs(): - B = Rx(W.Gpoly(1, l))(tuple(newP[0]))*PK[1][j]/PK[1][l] + B = Rx(W.Gpoly(1, l))(tuple(newP[0])) * PK[1][j] / PK[1][l] else: - B = -Rx(W.Gpoly(1, j))(tuple(newP[0]))*PK[1][l]/PK[1][j] + B = -Rx(W.Gpoly(1, j))(tuple(newP[0])) * PK[1][l] / PK[1][j] B = B - Rx(W.Hpoly(1, j, l))(tuple(newP[0])) - #Normalize Q + # Normalize Q newQ = copy(Q) newQ.scale_by([ZZ.one(), ~Q[1][l]]) if PK[0][i].abs() <= PK[0][k].abs(): - A = Ry(W.Gpoly(0, k))(tuple(newQ[1]))*PK[0][i]/PK[0][k] + A = Ry(W.Gpoly(0, k))(tuple(newQ[1])) * PK[0][i] / PK[0][k] else: - A = -Ry(W.Gpoly(0, i))(tuple(newQ[1]))*PK[0][k]/PK[0][i] + A = -Ry(W.Gpoly(0, i))(tuple(newQ[1])) * PK[0][k] / PK[0][i] A = A - Ry(W.Hpoly(0, i, k))(tuple(newQ[1])) - #Compute the new local height - local_height += beta**(-2*R(e)-1)*R(A.abs()).log() + beta**(-2*R(e))*R(B.abs()).log() + # Compute the new local height + local_height += beta ** (-2 * R(e) - 1) * R(A.abs()).log() + beta ** (-2 * R(e)) * R(B.abs()).log() i = k j = l @@ -1766,11 +1704,8 @@ def lambda_minus(self, P, v, N, m, n, prec=100): K = Qp(v, prec) PK = P.change_ring(K) W = self.change_ring(K) - Rx = W.ambient_space().coordinate_ring().hom(list(W.ambient_space()[0].coordinate_ring().gens()) - + [0, 0, 0], W.ambient_space()[0].coordinate_ring()) - Ry = W.ambient_space().coordinate_ring().hom([0, 0, 0] + - list(W.ambient_space()[1].coordinate_ring().gens()), - W.ambient_space()[1].coordinate_ring()) + Rx = W.ambient_space().coordinate_ring().hom(list(W.ambient_space()[0].coordinate_ring().gens()) + [0, 0, 0], W.ambient_space()[0].coordinate_ring()) + Ry = W.ambient_space().coordinate_ring().hom([0, 0, 0] + list(W.ambient_space()[1].coordinate_ring().gens()), W.ambient_space()[1].coordinate_ring()) beta = R(2 + sqrt(3)) L = [x.abs() for x in list(PK[0])] j = L.index(max(L)) @@ -1778,36 +1713,36 @@ def lambda_minus(self, P, v, N, m, n, prec=100): i = L.index(max(L)) ##Compute the local height wrt the divisor E_{mn}^{-} - local_height = beta*R((PK[1][i]/PK[1][n]).abs()).log() - R((PK[0][j]/PK[0][m]).abs()).log() + local_height = beta * R((PK[1][i] / PK[1][n]).abs()).log() - R((PK[0][j] / PK[0][m]).abs()).log() for e in range(N): - #Take the next iterate + # Take the next iterate Q = W.psi(PK, check=False) L = [x.abs() for x in list(Q[0])] l = L.index(max(L)) L = [y.abs() for y in list(Q[1])] k = L.index(max(L)) - #Normalize the point + # Normalize the point newP = copy(PK) newP.scale_by([ZZ.one(), ~PK[1][i]]) - #Find A and B, helper functions for computing local height + # Find A and B, helper functions for computing local height if PK[0][j].abs() <= PK[0][l].abs(): - B = Ry(W.Gpoly(0, l))(tuple(newP[1]))*PK[0][j]/PK[0][l] + B = Ry(W.Gpoly(0, l))(tuple(newP[1])) * PK[0][j] / PK[0][l] else: - B = -Ry(W.Gpoly(0, j))(tuple(newP[1]))*PK[0][l]/PK[0][j] + B = -Ry(W.Gpoly(0, j))(tuple(newP[1])) * PK[0][l] / PK[0][j] B = B - Ry(W.Hpoly(0, j, l))(tuple(newP[1])) - #Normalize Q + # Normalize Q newQ = copy(Q) newQ.scale_by([~Q[0][l], ZZ.one()]) if PK[1][i].abs() <= PK[1][k].abs(): - A = Rx(W.Gpoly(1, k))(tuple(newQ[0]))*PK[1][i]/PK[1][k] + A = Rx(W.Gpoly(1, k))(tuple(newQ[0])) * PK[1][i] / PK[1][k] else: - A = -Rx(W.Gpoly(1, i))(tuple(newQ[0]))*PK[1][k]/PK[1][i] - A = A-Rx(W.Hpoly(1, i, k))(tuple(newQ[0])) + A = -Rx(W.Gpoly(1, i))(tuple(newQ[0])) * PK[1][k] / PK[1][i] + A = A - Rx(W.Hpoly(1, i, k))(tuple(newQ[0])) - #Compute the local height - local_height += beta**(-2*R(e)-1)*R(A.abs()).log() + beta**(-2*R(e))*R(B.abs()).log() + # Compute the local height + local_height += beta ** (-2 * R(e) - 1) * R(A.abs()).log() + beta ** (-2 * R(e)) * R(B.abs()).log() i = k j = l newQ.scale_by([ZZ.one(), ~Q[1][k]]) @@ -1872,7 +1807,7 @@ def canonical_height_plus(self, P, N, badprimes=None, prec=100): m = m - 1 n = 2 while P[1][n] == 0: - n = n-1 + n = n - 1 h = self.lambda_plus(P, 0, N, m, n, prec) for p in badprimes: h += self.lambda_plus(P, p, N, m, n, prec) @@ -1936,7 +1871,7 @@ def canonical_height_minus(self, P, N, badprimes=None, prec=100): m = m - 1 n = 2 while P[1][n] == 0: - n = n-1 + n = n - 1 h = self.lambda_minus(P, 0, N, m, n, prec) for p in badprimes: h += self.lambda_minus(P, p, N, m, n, prec) @@ -1992,8 +1927,7 @@ def canonical_height(self, P, N, badprimes=None, prec=100): """ if badprimes is None: badprimes = self.degenerate_primes() - return (self.canonical_height_plus(P, N, badprimes, prec) + - self.canonical_height_minus(P, N, badprimes, prec)) + return self.canonical_height_plus(P, N, badprimes, prec) + self.canonical_height_minus(P, N, badprimes, prec) def fiber(self, p, component): r""" @@ -2064,40 +1998,40 @@ def fiber(self, p, component): P0 = [Zero, Zero, Zero] + P Points = [] - if (self.Gpoly(component,0)(P0) != 0): + if self.Gpoly(component, 0)(P0) != 0: # We are using the quadratic formula, we need this check # to ensure that the points will be rational - T0 = (self.Hpoly(component, 0, 1)(P0)**2 - 4*self.Gpoly(component, 0)(P0)*self.Gpoly(component, 1)(P0)) - T1 = (self.Hpoly(component, 0, 2)(P0)**2 - 4*self.Gpoly(component, 0)(P0)*self.Gpoly(component, 2)(P0)) - if (T0.is_square() and T1.is_square()): + T0 = self.Hpoly(component, 0, 1)(P0) ** 2 - 4 * self.Gpoly(component, 0)(P0) * self.Gpoly(component, 1)(P0) + T1 = self.Hpoly(component, 0, 2)(P0) ** 2 - 4 * self.Gpoly(component, 0)(P0) * self.Gpoly(component, 2)(P0) + if T0.is_square() and T1.is_square(): T0 = T0.sqrt() T1 = T1.sqrt() - B1 = (-self.Hpoly(component, 0, 1)(P0)+T0)/(2*self.Gpoly(component, 0)(P0)) - B2 = (-self.Hpoly(component, 0, 1)(P0)-T0)/(2*self.Gpoly(component, 0)(P0)) - C1 = (-self.Hpoly(component, 0, 2)(P0)+T1)/(2*self.Gpoly(component, 0)(P0)) - C2 = (-self.Hpoly(component, 0, 2)(P0)-T1)/(2*self.Gpoly(component, 0)(P0)) + B1 = (-self.Hpoly(component, 0, 1)(P0) + T0) / (2 * self.Gpoly(component, 0)(P0)) + B2 = (-self.Hpoly(component, 0, 1)(P0) - T0) / (2 * self.Gpoly(component, 0)(P0)) + C1 = (-self.Hpoly(component, 0, 2)(P0) + T1) / (2 * self.Gpoly(component, 0)(P0)) + C2 = (-self.Hpoly(component, 0, 2)(P0) - T1) / (2 * self.Gpoly(component, 0)(P0)) if component == 1: - Points.append(P+[One, B1, C1]) - Points.append(P+[One, B2, C1]) - Points.append(P+[One, B1, C2]) - Points.append(P+[One, B2, C2]) + Points.append(P + [One, B1, C1]) + Points.append(P + [One, B2, C1]) + Points.append(P + [One, B1, C2]) + Points.append(P + [One, B2, C2]) else: - Points.append([One, B1, C1]+P) - Points.append([One, B2, C1]+P) - Points.append([One, B1, C2]+P) - Points.append([One, B2, C2]+P) + Points.append([One, B1, C1] + P) + Points.append([One, B2, C1] + P) + Points.append([One, B1, C2] + P) + Points.append([One, B2, C2] + P) else: return [] - elif (self.Gpoly(component, 1)(P0) != 0): - T0 = (self.Hpoly(component, 0, 1)(P0)**2 - 4*self.Gpoly(component, 0)(P0)*self.Gpoly(component, 1)(P0)) - T1 = (self.Hpoly(component, 1, 2)(P0)**2 - 4*self.Gpoly(component, 1)(P0)*self.Gpoly(component, 2)(P0)) - if (T0.is_square() and T1.is_square()): + elif self.Gpoly(component, 1)(P0) != 0: + T0 = self.Hpoly(component, 0, 1)(P0) ** 2 - 4 * self.Gpoly(component, 0)(P0) * self.Gpoly(component, 1)(P0) + T1 = self.Hpoly(component, 1, 2)(P0) ** 2 - 4 * self.Gpoly(component, 1)(P0) * self.Gpoly(component, 2)(P0) + if T0.is_square() and T1.is_square(): T0 = T0.sqrt() T1 = T1.sqrt() - A1 = (-self.Hpoly(component, 0, 1)(P0)+T0)/(2*self.Gpoly(component, 1)(P0)) - A2 = (-self.Hpoly(component, 0, 1)(P0)-T0)/(2*self.Gpoly(component, 1)(P0)) - C1 = (-self.Hpoly(component, 1, 2)(P0)+T1)/(2*self.Gpoly(component, 1)(P0)) - C2 = (-self.Hpoly(component, 1, 2)(P0)-T1)/(2*self.Gpoly(component, 1)(P0)) + A1 = (-self.Hpoly(component, 0, 1)(P0) + T0) / (2 * self.Gpoly(component, 1)(P0)) + A2 = (-self.Hpoly(component, 0, 1)(P0) - T0) / (2 * self.Gpoly(component, 1)(P0)) + C1 = (-self.Hpoly(component, 1, 2)(P0) + T1) / (2 * self.Gpoly(component, 1)(P0)) + C2 = (-self.Hpoly(component, 1, 2)(P0) - T1) / (2 * self.Gpoly(component, 1)(P0)) if component == 1: Points.append(P + [A1, One, C1]) Points.append(P + [A1, One, C2]) @@ -2111,15 +2045,15 @@ def fiber(self, p, component): else: return [] elif self.Gpoly(component, 2)(P0) != 0: - T0 = (self.Hpoly(component, 0, 2)(P0)**2 - 4*self.Gpoly(component, 0)(P0)*self.Gpoly(component, 2)(P0)) - T1 = (self.Hpoly(component, 1, 2)(P0)**2 - 4*self.Gpoly(component, 1)(P0)*self.Gpoly(component, 2)(P0)) - if (T0.is_square() and T1.is_square()): + T0 = self.Hpoly(component, 0, 2)(P0) ** 2 - 4 * self.Gpoly(component, 0)(P0) * self.Gpoly(component, 2)(P0) + T1 = self.Hpoly(component, 1, 2)(P0) ** 2 - 4 * self.Gpoly(component, 1)(P0) * self.Gpoly(component, 2)(P0) + if T0.is_square() and T1.is_square(): T0 = T0.sqrt() T1 = T1.sqrt() - A1 = (-self.Hpoly(component, 0, 2)(P0)+T0)/(2*self.Gpoly(component, 2)(P0)) - A2 = (-self.Hpoly(component, 0, 2)(P0)-T0)/(2*self.Gpoly(component, 2)(P0)) - B1 = (-self.Hpoly(component, 1, 2)(P0)+T1)/(2*self.Gpoly(component, 2)(P0)) - B2 = (-self.Hpoly(component, 1, 2)(P0)-T1)/(2*self.Gpoly(component, 2)(P0)) + A1 = (-self.Hpoly(component, 0, 2)(P0) + T0) / (2 * self.Gpoly(component, 2)(P0)) + A2 = (-self.Hpoly(component, 0, 2)(P0) - T0) / (2 * self.Gpoly(component, 2)(P0)) + B1 = (-self.Hpoly(component, 1, 2)(P0) + T1) / (2 * self.Gpoly(component, 2)(P0)) + B2 = (-self.Hpoly(component, 1, 2)(P0) - T1) / (2 * self.Gpoly(component, 2)(P0)) if component == 1: Points.append(P + [A1, B1, One]) Points.append(P + [A1, B2, One]) @@ -2134,28 +2068,22 @@ def fiber(self, p, component): return [] elif self.Hpoly(component, 0, 1)(P0) != 0: if component == 1: - Points.append(P+[Zero, One, Zero]) - Points.append(P+[-self.Hpoly(component, 0, 1)(P0),Zero, - -self.Hpoly(component, 1, 2)(P0)]) - Points.append(P+[One,Zero,Zero]) - Points.append(P+[Zero,-self.Hpoly(component, 0, 1)(P0), - -self.Hpoly(component, 0, 2)(P0)]) + Points.append(P + [Zero, One, Zero]) + Points.append(P + [-self.Hpoly(component, 0, 1)(P0), Zero, -self.Hpoly(component, 1, 2)(P0)]) + Points.append(P + [One, Zero, Zero]) + Points.append(P + [Zero, -self.Hpoly(component, 0, 1)(P0), -self.Hpoly(component, 0, 2)(P0)]) else: - Points.append([Zero,One,Zero]+P) - Points.append([-self.Hpoly(component, 0, 1)(P0),Zero, - -self.Hpoly(component, 1, 2)(P0)] + P) - Points.append([One,Zero,Zero]+P) - Points.append([Zero,-self.Hpoly(component, 0, 1)(P0), - -self.Hpoly(component, 0, 2)(P0)] + P) + Points.append([Zero, One, Zero] + P) + Points.append([-self.Hpoly(component, 0, 1)(P0), Zero, -self.Hpoly(component, 1, 2)(P0)] + P) + Points.append([One, Zero, Zero] + P) + Points.append([Zero, -self.Hpoly(component, 0, 1)(P0), -self.Hpoly(component, 0, 2)(P0)] + P) elif self.Hpoly(component, 0, 2)(P0) != 0: if component == 1: - Points.append(P+[Zero, Zero, One]) - Points.append(P+[-self.Hpoly(component, 0, 2)(P0), - -self.Hpoly(component, 1, 2)(P0), Zero]) + Points.append(P + [Zero, Zero, One]) + Points.append(P + [-self.Hpoly(component, 0, 2)(P0), -self.Hpoly(component, 1, 2)(P0), Zero]) else: - Points.append([Zero, Zero, One]+P) - Points.append([-self.Hpoly(component, 0, 2)(P0), - -self.Hpoly(component, 1, 2)(P0), Zero] + P) + Points.append([Zero, Zero, One] + P) + Points.append([-self.Hpoly(component, 0, 2)(P0), -self.Hpoly(component, 1, 2)(P0), Zero] + P) elif self.Hpoly(component, 1, 2)(P0) != 0: if component == 1: Points.append(P + [Zero, Zero, One]) @@ -2229,13 +2157,13 @@ def nth_iterate_phi(self, P, n, **kwds): n = ZZ(n) except TypeError: raise TypeError("iterate number must be an integer") - #Since phi and psi are inverses and automorphisms + # Since phi and psi are inverses and automorphisms if n < 0: return self.nth_iterate_psi(P, abs(n), **kwds) if n == 0: return self Q = self.phi(P, **kwds) - for i in range(2, n+1): + for i in range(2, n + 1): Q = self.phi(Q, **kwds) return Q @@ -2282,13 +2210,13 @@ def nth_iterate_psi(self, P, n, **kwds): n = ZZ(n) except TypeError: raise TypeError("iterate number must be an integer") - #Since phi and psi and inverses + # Since phi and psi and inverses if n < 0: return self.nth_iterate_phi(P, abs(n), **kwds) if n == 0: return self Q = self.psi(P, **kwds) - for i in range(2, n+1): + for i in range(2, n + 1): Q = self.psi(Q, **kwds) return Q @@ -2497,12 +2425,12 @@ def is_symmetric_orbit(self, orbit) -> bool: return sym -class WehlerK3Surface_field( WehlerK3Surface_ring): +class WehlerK3Surface_field(WehlerK3Surface_ring): pass -class WehlerK3Surface_finite_field( WehlerK3Surface_field): - def cardinality( self): +class WehlerK3Surface_finite_field(WehlerK3Surface_field): + def cardinality(self): r""" Count the total number of points on the K3 surface. @@ -2525,11 +2453,13 @@ def cardinality( self): sage: X.cardinality() 55 """ + def getPx1(): return ([x, y, 1] for x in self.base_ring() for y in self.base_ring()) def getPx2(): return ([x, 1, 0] for x in self.base_ring()) + Count = 0 Xpoint = [1, 0, 0] Ypoint = [1, 0, 0] @@ -2546,7 +2476,7 @@ def getPx2(): B = i + Ypoint if self.L(B) == 0 and self.Q(B) == 0: Count += 1 - #Create all possible Px2 Values + # Create all possible Px2 Values for i in getPx2(): for j in getPx1(): A = i + j @@ -2554,21 +2484,21 @@ def getPx2(): Count += 1 for k in getPx2(): A = i + k - if (self.L(A) == 0 and self.Q(A) == 0): + if self.L(A) == 0 and self.Q(A) == 0: Count += 1 B = i + Ypoint - if (self.L(B) == 0 and self.Q(B) == 0): + if self.L(B) == 0 and self.Q(B) == 0: Count += 1 - #Create all Xpoint values + # Create all Xpoint values for j in getPx1(): - A = Xpoint+j - if (self.L(A) == 0 and self.Q(A) == 0): + A = Xpoint + j + if self.L(A) == 0 and self.Q(A) == 0: Count += 1 for k in getPx2(): B = Xpoint + k - if (self.L(B) == 0 and self.Q(B) == 0): + if self.L(B) == 0 and self.Q(B) == 0: Count += 1 C = Xpoint + Ypoint - if (self.L(C) == 0 and self.Q(C) == 0): + if self.L(C) == 0 and self.Q(C) == 0: Count += 1 return Count diff --git a/src/sage/dynamics/cellular_automata/all.py b/src/sage/dynamics/cellular_automata/all.py index ff4151c0588..b6d8c7bc8a6 100644 --- a/src/sage/dynamics/cellular_automata/all.py +++ b/src/sage/dynamics/cellular_automata/all.py @@ -1,6 +1,6 @@ import sage.dynamics.cellular_automata.catalog as cellular_automata from sage.misc.lazy_import import lazy_import -lazy_import("sage.dynamics.cellular_automata.solitons", - ["SolitonCellularAutomata", "PeriodicSolitonCellularAutomata"]) + +lazy_import("sage.dynamics.cellular_automata.solitons", ["SolitonCellularAutomata", "PeriodicSolitonCellularAutomata"]) del lazy_import diff --git a/src/sage/dynamics/cellular_automata/catalog.py b/src/sage/dynamics/cellular_automata/catalog.py index 44c28f07cb5..88d8d9cb501 100644 --- a/src/sage/dynamics/cellular_automata/catalog.py +++ b/src/sage/dynamics/cellular_automata/catalog.py @@ -21,13 +21,18 @@ """ from sage.misc.lazy_import import lazy_import -lazy_import('sage.dynamics.cellular_automata.elementary', - 'ElementaryCellularAutomata', 'Elementary',) -lazy_import('sage.dynamics.cellular_automata.glca', - 'GraftalLaceCellularAutomata', 'GraftalLace',) -lazy_import('sage.dynamics.cellular_automata.solitons', - 'SolitonCellularAutomata', 'Soliton') -lazy_import('sage.dynamics.cellular_automata.solitons', - 'PeriodicSolitonCellularAutomata', 'PeriodicSoliton') -del lazy_import # We remove the object from here so it doesn't appear under tab completion +lazy_import( + 'sage.dynamics.cellular_automata.elementary', + 'ElementaryCellularAutomata', + 'Elementary', +) +lazy_import( + 'sage.dynamics.cellular_automata.glca', + 'GraftalLaceCellularAutomata', + 'GraftalLace', +) +lazy_import('sage.dynamics.cellular_automata.solitons', 'SolitonCellularAutomata', 'Soliton') +lazy_import('sage.dynamics.cellular_automata.solitons', 'PeriodicSolitonCellularAutomata', 'PeriodicSoliton') + +del lazy_import # We remove the object from here so it doesn't appear under tab completion diff --git a/src/sage/dynamics/cellular_automata/elementary.py b/src/sage/dynamics/cellular_automata/elementary.py index 1c91687db8c..b9c8f1a1d0f 100644 --- a/src/sage/dynamics/cellular_automata/elementary.py +++ b/src/sage/dynamics/cellular_automata/elementary.py @@ -6,7 +6,7 @@ - Travis Scrimshaw (2018-07-07): Initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2018 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.structure.sage_object import SageObject from sage.typeset.ascii_art import AsciiArt @@ -22,6 +22,7 @@ from sage.rings.integer_ring import ZZ from sage.matrix.constructor import matrix from sage.misc.lazy_import import lazy_import + lazy_import("sage.plot.matrix_plot", "matrix_plot") from sage.misc.constant_function import ConstantFunction @@ -253,6 +254,7 @@ class ElementaryCellularAutomata(SageObject): :wikipedia:`Elementary_cellular_automaton` """ + def __init__(self, rule, width=None, initial_state=None, boundary=(0, 0)): """ Initialize ``self``. @@ -266,31 +268,29 @@ def __init__(self, rule, width=None, initial_state=None, boundary=(0, 0)): raise ValueError("invalid rule") self._rule = ZZ(rule).binary() # We reverse the rule to make it easier to work with - self._rule = [ZZ(x) for x in reversed('0'*(8-len(self._rule)) + self._rule)] + self._rule = [ZZ(x) for x in reversed('0' * (8 - len(self._rule)) + self._rule)] if isinstance(width, list): initial_state = width width = len(initial_state) if initial_state is None: self._width = width - initial_state = [ZZ.random_element(0,2) for d in range(width)] + initial_state = [ZZ.random_element(0, 2) for d in range(width)] else: - if not all(d in [0,1] for d in initial_state): + if not all(d in [0, 1] for d in initial_state): raise ValueError("invalid initial state") - initial_state = list(initial_state) # make sure it is a list and a copy + initial_state = list(initial_state) # make sure it is a list and a copy if width is None: self._width = len(initial_state) elif width >= len(initial_state): self._width = width - initial_state = ([0]*(width - len(initial_state)) - + initial_state) + initial_state = [0] * (width - len(initial_state)) + initial_state else: - raise ValueError("the width must be at least the length of" - " the initial state") + raise ValueError("the width must be at least the length of" " the initial state") self._states = [initial_state] if boundary is not None: self._bdry = tuple(boundary) - self._lbdry = ConstantFunction(boundary[0]) if boundary[0] in [0,1] else boundary[0] - self._rbdry = ConstantFunction(boundary[1]) if boundary[1] in [0,1] else boundary[1] + self._lbdry = ConstantFunction(boundary[0]) if boundary[0] in [0, 1] else boundary[0] + self._rbdry = ConstantFunction(boundary[1]) if boundary[1] in [0, 1] else boundary[1] else: self._bdry = boundary @@ -320,11 +320,7 @@ def __eq__(self, other): sage: ECA1 == ECA6 False """ - return (isinstance(other, ElementaryCellularAutomata) - and self._rule == other._rule - and self._width == other._width - and self._states[0] == other._states[0] - and self._bdry == other._bdry) + return isinstance(other, ElementaryCellularAutomata) and self._rule == other._rule and self._width == other._width and self._states[0] == other._states[0] and self._bdry == other._bdry def __ne__(self, other): """ @@ -397,6 +393,7 @@ def evolve(self, number=None): def to_int(triple): return ZZ(list(reversed(triple)), base=2) + if self._bdry is None: next_state[0] = self._rule[to_int([prev_state[-1]] + prev_state[:2])] next_state[-1] = self._rule[to_int(prev_state[-2:] + [prev_state[0]])] @@ -405,8 +402,8 @@ def to_int(triple): next_state[0] = self._rule[to_int([self._lbdry(n)] + prev_state[:2])] next_state[-1] = self._rule[to_int(prev_state[-2:] + [self._rbdry(n)])] - for i in range(1, self._width-1): - next_state[i] = self._rule[to_int(prev_state[i-1:i+2])] + for i in range(1, self._width - 1): + next_state[i] = self._rule[to_int(prev_state[i - 1 : i + 2])] self._states.append(next_state) # Output functions @@ -423,8 +420,7 @@ def _repr_(self): Elementary cellular automata with rule 123 and initial state [0, 0, 0, 0, 0, 0, 0, 0, 0, 1] """ - return "Elementary cellular automata with rule {} and initial state {}".format( - ZZ(self._rule, base=2), self._states[0]) + return "Elementary cellular automata with rule {} and initial state {}".format(ZZ(self._rule, base=2), self._states[0]) def print_state(self, number=None): r""" @@ -540,8 +536,7 @@ def _ascii_art_(self): X X X X X X X X XXX XXX XXX XXX XXX XXX XXX XX """ - return AsciiArt([''.join('X' if x else ' ' for x in state) - for state in self._states]) + return AsciiArt([''.join('X' if x else ' ' for x in state) for state in self._states]) def _unicode_art_(self): r""" @@ -583,8 +578,7 @@ def _unicode_art_(self): █ █ █ █ █ █ █ █ ███ ███ ███ ███ ███ ███ ███ ██ """ - return UnicodeArt([''.join('█' if x else ' ' for x in state) - for state in self._states]) + return UnicodeArt([''.join('█' if x else ' ' for x in state) for state in self._states]) def plot(self, number=None): r""" diff --git a/src/sage/dynamics/cellular_automata/glca.py b/src/sage/dynamics/cellular_automata/glca.py index 929f1131456..bf4d50c547c 100644 --- a/src/sage/dynamics/cellular_automata/glca.py +++ b/src/sage/dynamics/cellular_automata/glca.py @@ -6,7 +6,7 @@ - Travis Scrimshaw (2020-04-30): Initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2020 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -81,6 +81,7 @@ class GraftalLaceCellularAutomata(SageObject): - [Kas2018]_ """ + def __init__(self, rule): """ Initialize ``self``. @@ -131,8 +132,7 @@ def __eq__(self, other): sage: G1 is G3 False """ - return (isinstance(other, GraftalLaceCellularAutomata) - and self._rule == other._rule) + return isinstance(other, GraftalLaceCellularAutomata) and self._rule == other._rule def __ne__(self, other): """ @@ -204,8 +204,8 @@ def evolve(self, number=None): for i, val in enumerate(prev_state): next_state[i] += self._rule[val] & 0x1 - next_state[i+1] += self._rule[val] & 0x2 - next_state[i+2] += self._rule[val] & 0x4 + next_state[i + 1] += self._rule[val] & 0x2 + next_state[i + 2] += self._rule[val] & 0x4 self._states.append(next_state) # Output functions @@ -306,10 +306,10 @@ def _ascii_art_(self, number=None): number = len(self._states) space = len(self._states[:number]) * 2 - 1 - ret = AsciiArt([' '*space + 'o']) + ret = AsciiArt([' ' * space + 'o']) space += 1 - for i,state in enumerate(self._states[:number]): - temp = ' '*(space-2) + for i, state in enumerate(self._states[:number]): + temp = ' ' * (space - 2) last = ' ' for x in state: if x & 0x4: @@ -323,7 +323,7 @@ def _ascii_art_(self, number=None): last = '/' if x & 0x1 else ' ' ret *= AsciiArt([temp + last]) space -= 1 - ret *= AsciiArt([' '*space + ' '.join('o' for dummy in range(2*i+1))]) + ret *= AsciiArt([' ' * space + ' '.join('o' for dummy in range(2 * i + 1))]) space -= 1 return ret @@ -364,10 +364,10 @@ def _unicode_art_(self, number=None): number = len(self._states) space = len(self._states[:number]) * 2 - 1 - ret = UnicodeArt([' '*space + '◾']) + ret = UnicodeArt([' ' * space + '◾']) space += 1 - for i,state in enumerate(self._states[:number]): - temp = ' '*(space-2) + for i, state in enumerate(self._states[:number]): + temp = ' ' * (space - 2) last = ' ' for x in state: if x & 0x4: @@ -381,7 +381,7 @@ def _unicode_art_(self, number=None): last = '╱' if x & 0x1 else ' ' ret *= UnicodeArt([temp + last]) space -= 1 - ret *= UnicodeArt([' '*space + ' '.join('◾' for dummy in range(2*i+1))]) + ret *= UnicodeArt([' ' * space + ' '.join('◾' for dummy in range(2 * i + 1))]) space -= 1 return ret @@ -412,16 +412,16 @@ def plot(self, number=None): x = len(self._states[:number]) rad = 0.1 ret = circle((x, 1), rad, fill=True) - for i,state in enumerate(self._states[:number]): - for j,val in enumerate(state): + for i, state in enumerate(self._states[:number]): + for j, val in enumerate(state): if val & 0x4: - ret += line([(x+j,-i), (x+j-1,-i+1)]) + ret += line([(x + j, -i), (x + j - 1, -i + 1)]) if val & 0x2: - ret += line([(x+j,-i), (x+j,-i+1)]) + ret += line([(x + j, -i), (x + j, -i + 1)]) if val & 0x1: - ret += line([(x+j,-i), (x+j+1,-i+1)]) - for j in range(2*i+1): - ret += circle((x+j, -i), rad, fill=True) + ret += line([(x + j, -i), (x + j + 1, -i + 1)]) + for j in range(2 * i + 1): + ret += circle((x + j, -i), rad, fill=True) x -= 1 ret.set_aspect_ratio(1) ret.axes(False) @@ -461,16 +461,16 @@ def _latex_(self): x = len(self._states) rad = 2 ret += "\\fill ({},{}) circle ({}pt);\n".format(x, 1, rad) - for i,state in enumerate(self._states): - for j,val in enumerate(state): + for i, state in enumerate(self._states): + for j, val in enumerate(state): if val & 0x4: - ret += "\\draw[-] ({},{}) -- ({},{});\n".format(x+j,-i, x+j-1,-i+1) + ret += "\\draw[-] ({},{}) -- ({},{});\n".format(x + j, -i, x + j - 1, -i + 1) if val & 0x2: - ret += "\\draw[-] ({},{}) -- ({},{});\n".format(x+j,-i, x+j,-i+1) + ret += "\\draw[-] ({},{}) -- ({},{});\n".format(x + j, -i, x + j, -i + 1) if val & 0x1: - ret += "\\draw[-] ({},{}) -- ({},{});\n".format(x+j,-i, x+j+1,-i+1) - for j in range(2*i+1): - ret += "\\fill ({},{}) circle ({}pt);\n".format(x+j, -i, rad) + ret += "\\draw[-] ({},{}) -- ({},{});\n".format(x + j, -i, x + j + 1, -i + 1) + for j in range(2 * i + 1): + ret += "\\fill ({},{}) circle ({}pt);\n".format(x + j, -i, rad) x -= 1 ret += "\\end{tikzpicture}" return ret diff --git a/src/sage/dynamics/cellular_automata/solitons.py b/src/sage/dynamics/cellular_automata/solitons.py index 8f5c3110533..f57be99e420 100644 --- a/src/sage/dynamics/cellular_automata/solitons.py +++ b/src/sage/dynamics/cellular_automata/solitons.py @@ -291,6 +291,7 @@ class SolitonCellularAutomata(SageObject): t: 7 . (-2, 5)(-2, -5, 4, 6) ... (-6, 2) ... """ + def __init__(self, initial_state, cartan_type=2, vacuum=1): """ Initialize ``self``. @@ -301,7 +302,7 @@ def __init__(self, initial_state, cartan_type=2, vacuum=1): sage: TestSuite(B).run() """ if cartan_type in ZZ: - cartan_type = CartanType(['A',cartan_type-1,1]) + cartan_type = CartanType(['A', cartan_type - 1, 1]) else: cartan_type = CartanType(cartan_type) self._cartan_type = cartan_type @@ -317,14 +318,10 @@ def __init__(self, initial_state, cartan_type=2, vacuum=1): # We consider things 1-9 initial_state = [[ZZ(x) if x != '.' else ZZ.one()] for x in initial_state] try: - KRT = TensorProductOfKirillovReshetikhinTableaux(self._cartan_type, - [[vacuum, len(st)//vacuum] - for st in initial_state]) + KRT = TensorProductOfKirillovReshetikhinTableaux(self._cartan_type, [[vacuum, len(st) // vacuum] for st in initial_state]) self._states = [KRT(pathlist=initial_state)] except TypeError: - KRT = TensorProductOfKirillovReshetikhinTableaux(self._cartan_type, - [[vacuum, 1] - for st in initial_state]) + KRT = TensorProductOfKirillovReshetikhinTableaux(self._cartan_type, [[vacuum, 1] for st in initial_state]) self._states = [KRT(*initial_state)] self._evolutions = [] @@ -355,9 +352,7 @@ def __eq__(self, other): sage: B1 == B2 False """ - return (isinstance(other, SolitonCellularAutomata) - and self._states[0] == other._states[0] - and self._evolutions == other._evolutions) + return isinstance(other, SolitonCellularAutomata) and self._states[0] == other._states[0] and self._evolutions == other._evolutions def __ne__(self, other): """ @@ -498,8 +493,7 @@ def evolve(self, carrier_capacity=None, carrier_index=None, number=None): if not isinstance(carrier_index, (list, tuple)): carrier_index = [carrier_index] * len(carrier_capacity) if len(carrier_index) != len(carrier_capacity): - raise ValueError("carrier_index and carrier_capacity" - " must have the same length") + raise ValueError("carrier_index and carrier_capacity" " must have the same length") for i, r in zip(carrier_capacity, carrier_index): self.evolve(i, r) return @@ -532,8 +526,7 @@ def evolve(self, carrier_capacity=None, carrier_index=None, number=None): state = self._states[-1] dims = state.parent().dims while not passed: - KRT = TensorProductOfKirillovReshetikhinTableaux(self._cartan_type, - dims + (carrier_factor,)) + KRT = TensorProductOfKirillovReshetikhinTableaux(self._cartan_type, dims + (carrier_factor,)) elt = KRT(*(list(state) + [empty_carrier])) RC = RiggedConfigurations(self._cartan_type, (carrier_factor,) + dims) elt2 = RC(*elt.to_rigged_configuration()).to_tensor_product_of_kirillov_reshetikhin_tableaux() @@ -549,7 +542,7 @@ def evolve(self, carrier_capacity=None, carrier_index=None, number=None): else: # We need to add more vacuum states last_final_carrier = elt2[0] - dims = tuple([(self._vacuum, 1)]*carrier_capacity) + dims + dims = tuple([(self._vacuum, 1)] * carrier_capacity) + dims def state_evolution(self, num): """ @@ -599,9 +592,9 @@ def state_evolution(self, num): self.evolve() carrier = KirillovReshetikhinTableaux(self._cartan_type, *self._evolutions[num]) - num_factors = len(self._states[num+1]) + num_factors = len(self._states[num + 1]) vacuum = self._vacuum_elt - state = [vacuum]*(num_factors - len(self._states[num])) + list(self._states[num]) + state = [vacuum] * (num_factors - len(self._states[num])) + list(self._states[num]) final = [] u = [self._initial_carrier[num]] # Assume every element has the same parent @@ -677,7 +670,7 @@ def _column_repr(self, b, vacuum_letter=None): return ascii_art(s if s[0] != '-' else '_\n' + s[1:]) letter_str = [str(letter) for letter in b] max_width = max(len(s) for s in letter_str) - return ascii_art('\n'.join(' '*(max_width-len(s)) + s for s in letter_str)) + return ascii_art('\n'.join(' ' * (max_width - len(s)) + s for s in letter_str)) def _repr_state(self, state, vacuum_letter='.'): """ @@ -694,8 +687,7 @@ def _repr_state(self, state, vacuum_letter='.'): """ output = [self._column_repr(b, vacuum_letter) for b in state] max_width = max(cell.width() for cell in output) - return sum((ascii_art(' '*(max_width-b.width())) + b for b in output), - ascii_art('')) + return sum((ascii_art(' ' * (max_width - b.width())) + b for b in output), ascii_art('')) def _repr_(self): """ @@ -739,11 +731,7 @@ def _repr_(self): 3 . 1 2 """ ret = "Soliton cellular automata of type {} and vacuum = {}\n".format(self._cartan_type, self._vacuum) - ret += " initial state:\n{}\n evoltuions: {}\n current state:\n{}".format( - ascii_art(' ') + self._repr_state(self._states[0]), - self._evolutions, - ascii_art(' ') + self._repr_state(self._states[-1]) - ) + ret += " initial state:\n{}\n evoltuions: {}\n current state:\n{}".format(ascii_art(' ') + self._repr_state(self._states[0]), self._evolutions, ascii_art(' ') + self._repr_state(self._states[-1])) return ret def print_state(self, num=None, vacuum_letter='.', remove_trailing_vacuums=False): @@ -784,7 +772,7 @@ def print_state(self, num=None, vacuum_letter='.', remove_trailing_vacuums=False # entirely of vacuum elements. while pos >= 0 and state[pos] == self._vacuum_elt: pos -= 1 - state = state[:pos+1] + state = state[: pos + 1] print(self._repr_state(state, vacuum_letter)) def print_states(self, num=None, vacuum_letter='.'): @@ -946,16 +934,14 @@ def print_states(self, num=None, vacuum_letter='.'): self.evolve() vacuum = self._vacuum_elt - num_factors = len(self._states[num-1]) - for i,state in enumerate(self._states[:num]): - state = [vacuum]*(num_factors - len(state)) + list(state) + num_factors = len(self._states[num - 1]) + for i, state in enumerate(self._states[:num]): + state = [vacuum] * (num_factors - len(state)) + list(state) output = [self._column_repr(b, vacuum_letter) for b in state] max_width = max(b.width() for b in output) start = ascii_art("t: %s \n" % i) start._baseline = -1 - print(start - + sum((ascii_art(' '*(max_width-b.width())) + b for b in output), - ascii_art(''))) + print(start + sum((ascii_art(' ' * (max_width - b.width())) + b for b in output), ascii_art(''))) def latex_states(self, num=None, as_array=True, box_width='5pt'): r""" @@ -1011,6 +997,7 @@ def latex_states(self, num=None, as_array=True, box_width='5pt'): \end{array}} """ from sage.misc.latex import latex, LatexExpr + if not as_array: latex.add_package_to_preamble_if_available('xcolor') @@ -1035,17 +1022,17 @@ def compact_repr(b): if b == vacuum: return "{\\color{gray} %s}" % temp - return temp # "\\makebox[%s]{$%s$}"%(box_width, temp) + return temp # "\\makebox[%s]{$%s$}"%(box_width, temp) - num_factors = len(self._states[num-1]) + num_factors = len(self._states[num - 1]) if as_array: ret = "{\\arraycolsep=0.5pt \\begin{array}" - ret += "{c|c%s}\n" % ('c'*num_factors) + ret += "{c|c%s}\n" % ('c' * num_factors) else: ret = "{\\begin{array}" ret += "{c|c}\n" - for i,state in enumerate(self._states[:num]): - state = [vacuum]*(num_factors-len(state)) + list(state) + for i, state in enumerate(self._states[:num]): + state = [vacuum] * (num_factors - len(state)) + list(state) if as_array: ret += "t = %s & \\cdots & %s \\\\\n" % (i, r" & ".join(compact_repr(b) for b in state)) else: @@ -1080,9 +1067,9 @@ def print_state_evolution(self, num): 3 3 2 1 1 1 1 """ u = self.state_evolution(num) # Also evolves as necessary - final = self._states[num+1] + final = self._states[num + 1] vacuum = self._vacuum_elt - state = [vacuum]*(len(final) - len(self._states[num])) + list(self._states[num]) + state = [vacuum] * (len(final) - len(self._states[num])) + list(self._states[num]) carrier = KirillovReshetikhinTableaux(self._cartan_type, *self._evolutions[num]) def simple_repr(x): @@ -1090,26 +1077,25 @@ def simple_repr(x): def carrier_repr(x): if carrier._tableau_height == 1: - return sum((ascii_art(repr(b)) if repr(b)[0] != '-' - else ascii_art("_" + '\n' + repr(b)[1:]) - for b in x), - ascii_art('')) + return sum((ascii_art(repr(b)) if repr(b)[0] != '-' else ascii_art("_" + '\n' + repr(b)[1:]) for b in x), ascii_art('')) return ascii_art(''.join(repr(x).strip('[]').split(', '))) def cross_repr(i): ret = ascii_art( -""" + """ {!s:^7} | --+-- | {!s:^7} -""".format(simple_repr(state[i]), simple_repr(final[i]))) +""".format( + simple_repr(state[i]), simple_repr(final[i]) + ) + ) ret._baseline = 2 return ret - art = sum((cross_repr(i) - + carrier_repr(u[i+1]) - for i in range(len(state))), ascii_art('')) + + art = sum((cross_repr(i) + carrier_repr(u[i + 1]) for i in range(len(state))), ascii_art('')) print(ascii_art(carrier_repr(u[0])) + art) def latex_state_evolution(self, num, scale=1): @@ -1141,25 +1127,27 @@ def latex_state_evolution(self, num, scale=1): """ from sage.graphs.graph_latex import setup_latex_preamble from sage.misc.latex import LatexExpr + setup_latex_preamble() - u = self.state_evolution(num) # Also evolves as necessary - final = self._states[num+1] + u = self.state_evolution(num) # Also evolves as necessary + final = self._states[num + 1] vacuum = self._vacuum_elt - initial = [vacuum]*(len(final) - len(self._states[num])) + list(self._states[num]) - cs = len(u[0]) * 0.08 + 1 # carrier scaling + initial = [vacuum] * (len(final) - len(self._states[num])) + list(self._states[num]) + cs = len(u[0]) * 0.08 + 1 # carrier scaling def simple_repr(x): return ''.join(repr(x).strip('[]').split(', ')) + ret = '\\begin{{tikzpicture}}[scale={}]\n'.format(scale) - for i,val in enumerate(initial): - ret += '\\node (i{}) at ({},0.9) {{${}$}};\n'.format(i, 2*i*cs, simple_repr(val)) - for i,val in enumerate(final): - ret += '\\node (t{}) at ({},-1) {{${}$}};\n'.format(i, 2*i*cs, simple_repr(val)) - for i,val in enumerate(u): - ret += '\\node (u{}) at ({},0) {{${}$}};\n'.format(i, (2*i-1)*cs, simple_repr(val)) + for i, val in enumerate(initial): + ret += '\\node (i{}) at ({},0.9) {{${}$}};\n'.format(i, 2 * i * cs, simple_repr(val)) + for i, val in enumerate(final): + ret += '\\node (t{}) at ({},-1) {{${}$}};\n'.format(i, 2 * i * cs, simple_repr(val)) + for i, val in enumerate(u): + ret += '\\node (u{}) at ({},0) {{${}$}};\n'.format(i, (2 * i - 1) * cs, simple_repr(val)) for i in range(len(initial)): ret += '\\draw[->] (i{}) -- (t{});\n'.format(i, i) - ret += '\\draw[->] (u{}) -- (u{});\n'.format(i+1, i) + ret += '\\draw[->] (u{}) -- (u{});\n'.format(i + 1, i) ret += '\\end{tikzpicture}' return LatexExpr(ret) @@ -1294,6 +1282,7 @@ class PeriodicSolitonCellularAutomata(SolitonCellularAutomata): - [YT2002]_ - [YYT2003]_ """ + def evolve(self, carrier_capacity=None, carrier_index=None, number=None): r""" Evolve ``self``. @@ -1381,8 +1370,7 @@ def evolve(self, carrier_capacity=None, carrier_index=None, number=None): if not isinstance(carrier_index, (list, tuple)): carrier_index = [carrier_index] * len(carrier_capacity) if len(carrier_index) != len(carrier_capacity): - raise ValueError("carrier_index and carrier_capacity" - " must have the same length") + raise ValueError("carrier_index and carrier_capacity" " must have the same length") for i, r in zip(carrier_capacity, carrier_index): self.evolve(i, r) return @@ -1411,8 +1399,7 @@ def evolve(self, carrier_capacity=None, carrier_index=None, number=None): state = self._states[-1] dims = state.parent().dims for carrier in K: - KRT = TensorProductOfKirillovReshetikhinTableaux(self._cartan_type, - dims + (carrier_factor,)) + KRT = TensorProductOfKirillovReshetikhinTableaux(self._cartan_type, dims + (carrier_factor,)) elt = KRT(*(list(state) + [carrier])) RC = RiggedConfigurations(self._cartan_type, (carrier_factor,) + dims) elt2 = RC(*elt.to_rigged_configuration()).to_tensor_product_of_kirillov_reshetikhin_tableaux() @@ -1457,5 +1444,4 @@ def __eq__(self, other): sage: B == P False """ - return (isinstance(other, PeriodicSolitonCellularAutomata) - and SolitonCellularAutomata.__eq__(self, other)) + return isinstance(other, PeriodicSolitonCellularAutomata) and SolitonCellularAutomata.__eq__(self, other) diff --git a/src/sage/dynamics/complex_dynamics/all.py b/src/sage/dynamics/complex_dynamics/all.py index 0d8c4797497..62ad24bb749 100644 --- a/src/sage/dynamics/complex_dynamics/all.py +++ b/src/sage/dynamics/complex_dynamics/all.py @@ -1,4 +1,4 @@ from sage.misc.lazy_import import lazy_import -lazy_import("sage.dynamics.complex_dynamics.mandel_julia", - ["mandelbrot_plot", "external_ray", "kneading_sequence", "julia_plot"]) + +lazy_import("sage.dynamics.complex_dynamics.mandel_julia", ["mandelbrot_plot", "external_ray", "kneading_sequence", "julia_plot"]) del lazy_import diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia.py b/src/sage/dynamics/complex_dynamics/mandel_julia.py index efe11ab4482..a1d45268bd4 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia.py +++ b/src/sage/dynamics/complex_dynamics/mandel_julia.py @@ -20,7 +20,7 @@ - Ben Barros """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2017 BEN BARROS # # This program is free software: you can redistribute it and/or modify @@ -28,18 +28,12 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** -from sage.dynamics.complex_dynamics.mandel_julia_helper import (fast_mandelbrot_plot, - fast_external_ray, - convert_to_pixels, - get_line, - fast_julia_plot, - general_julia, - polynomial_mandelbrot, - julia_helper) +from sage.dynamics.complex_dynamics.mandel_julia_helper import fast_mandelbrot_plot, fast_external_ray, convert_to_pixels, get_line, fast_julia_plot, general_julia, polynomial_mandelbrot, julia_helper from sage.misc.lazy_import import lazy_import + lazy_import("sage.plot.colors", "Color") from sage.repl.image import Image from sage.functions.log import logb @@ -204,24 +198,17 @@ def mandelbrot_plot(f=None, **kwds): given_iterations = False from ipywidgets.widgets import FloatSlider, IntSlider, ColorPicker, interact + widgets = dict( - x_center=FloatSlider(min=-1.0, max=1.0, step=EPS, - value=x_center, description="Real center"), - y_center=FloatSlider(min=-1.0, max=1.0, step=EPS, - value=y_center, description="Imag center"), - image_width=FloatSlider(min=EPS, max=4.0, step=EPS, - value=image_width, description='Width'), - max_iteration=IntSlider(min=0, max=1000, - value=max_iteration, description='Iterations'), - pixel_count=IntSlider(min=10, max=1000, - value=pixel_count, description='Pixels'), - level_sep=IntSlider(min=1, max=20, - value=level_sep, description="Color sep"), - color_num=IntSlider(min=1, max=100, - value=number_of_colors, description="# Colors"), - base_color=ColorPicker(value=Color(base_color).html_color(), - description="Base color"), - ) + x_center=FloatSlider(min=-1.0, max=1.0, step=EPS, value=x_center, description="Real center"), + y_center=FloatSlider(min=-1.0, max=1.0, step=EPS, value=y_center, description="Imag center"), + image_width=FloatSlider(min=EPS, max=4.0, step=EPS, value=image_width, description='Width'), + max_iteration=IntSlider(min=0, max=1000, value=max_iteration, description='Iterations'), + pixel_count=IntSlider(min=10, max=1000, value=pixel_count, description='Pixels'), + level_sep=IntSlider(min=1, max=20, value=level_sep, description="Color sep"), + color_num=IntSlider(min=1, max=100, value=number_of_colors, description="# Colors"), + base_color=ColorPicker(value=Color(base_color).html_color(), description="Base color"), + ) if f is None: # Quadratic map f = z^2 + c @@ -229,9 +216,7 @@ def mandelbrot_plot(f=None, **kwds): if interacts: return interact(**widgets).widget(fast_mandelbrot_plot) - return fast_mandelbrot_plot(x_center, y_center, image_width, - max_iteration, pixel_count, level_sep, number_of_colors, - base_color) + return fast_mandelbrot_plot(x_center, y_center, image_width, max_iteration, pixel_count, level_sep, number_of_colors, base_color) if parameter is None: c = var('c') @@ -266,9 +251,7 @@ def mandelbrot_plot(f=None, **kwds): if interacts: return interact(**widgets).widget(fast_mandelbrot_plot) - return fast_mandelbrot_plot(x_center, y_center, image_width, - max_iteration, pixel_count, level_sep, number_of_colors, - base_color) + return fast_mandelbrot_plot(x_center, y_center, image_width, max_iteration, pixel_count, level_sep, number_of_colors, base_color) if interacts: raise NotImplementedError("interact only implemented for z^2 + c") else: @@ -278,9 +261,7 @@ def mandelbrot_plot(f=None, **kwds): max_iteration = 50 # Mandelbrot of General Polynomial Map - return polynomial_mandelbrot(f, parameter, x_center, y_center, - image_width, max_iteration, pixel_count, level_sep, - number_of_colors, base_color) + return polynomial_mandelbrot(f, parameter, x_center, y_center, image_width, max_iteration, pixel_count, level_sep, number_of_colors, base_color) def external_ray(theta, **kwds): @@ -395,14 +376,11 @@ def external_ray(theta, **kwds): # Check if theta is in the interval [0,1] for angle in theta: if angle < 0 or angle > 1: - raise ValueError("values for theta must be in " - "the closed interval [0,1].") + raise ValueError("values for theta must be in " "the closed interval [0,1].") # Loop through each value for theta in list and plot the external ray. for angle in theta: - E = fast_external_ray(angle, D=depth, S=sharpness, R=radial_parameter, - prec=precision, image_width=plot_width, - pixel_count=pixel_width) + E = fast_external_ray(angle, D=depth, S=sharpness, R=radial_parameter, prec=precision, image_width=plot_width, pixel_count=pixel_width) # Convert points to pixel coordinates. pixel_list = convert_to_pixels(E, x_0, y_0, plot_width, pixel_width) @@ -481,17 +459,17 @@ def kneading_sequence(theta): theta = theta - floor(theta) KS = [] not_done = True - left = theta/2 - right = (theta + 1)/2 + left = theta / 2 + right = (theta + 1) / 2 y = theta while not_done: - if ((y < left) or (y > right)): + if (y < left) or (y > right): KS.append('0') - elif ((y > left) and (y < right)): + elif (y > left) and (y < right): KS.append('1') else: not_done = False - y = 2*y - floor(2*y) + y = 2 * y - floor(2 * y) KS_str = ''.join(KS) + '*' return KS_str @@ -662,7 +640,7 @@ def julia_plot(f=None, **kwds): f_is_default_after_all = None - if period: # pick a random c with the specified period + if period: # pick a random c with the specified period R = PolynomialRing(CC, 'c') c = R.gen() x, y = ProjectiveSpace(R, 1, 'x,y').gens() @@ -675,7 +653,7 @@ def julia_plot(f=None, **kwds): EPS = 0.00001 - if f is not None and period is None: # f user-specified and no period given + if f is not None and period is None: # f user-specified and no period given # try to coerce f to live in a polynomial ring S = PolynomialRing(CC, names='z') @@ -684,26 +662,18 @@ def julia_plot(f=None, **kwds): f_poly = S(f) except TypeError: R = f.parent() - if not (R.is_integral_domain() and - (CC.is_subring(R) or CDF.is_subring(R))): + if not (R.is_integral_domain() and (CC.is_subring(R) or CDF.is_subring(R))): raise ValueError('given `f` must be a complex polynomial') - raise NotImplementedError( - 'Julia sets not implemented for rational functions') + raise NotImplementedError('Julia sets not implemented for rational functions') - if (f_poly - z*z) in CC: # f is specified and of the form z^2 + c. + if (f_poly - z * z) in CC: # f is specified and of the form z^2 + c. f_is_default_after_all = True - c = f_poly - z*z - else: # f is specified and not of the form z^2 + c + c = f_poly - z * z + else: # f is specified and not of the form z^2 + c if interacts: - raise NotImplementedError( - "The interactive plot is only implemented for " - "polynomials of the form f = z^2 + c." - ) + raise NotImplementedError("The interactive plot is only implemented for " "polynomials of the form f = z^2 + c.") else: - return general_julia(f_poly, x_center, y_center, - image_width, max_iteration, - pixel_count, level_sep, - number_of_colors, base_color) + return general_julia(f_poly, x_center, y_center, image_width, max_iteration, pixel_count, level_sep, number_of_colors, base_color) # otherwise we can use fast_julia_plot for z^2 + c if f_is_default_after_all or f is None or period is not None: @@ -716,42 +686,26 @@ def julia_plot(f=None, **kwds): c_real = c.real() c_imag = c.imag() - if interacts: # set widgets - from ipywidgets.widgets import FloatSlider, IntSlider, \ - ColorPicker, interact + if interacts: # set widgets + from ipywidgets.widgets import FloatSlider, IntSlider, ColorPicker, interact + widgets = dict( - c_real=FloatSlider(min=-2.0, max=2.0, step=EPS, - value=c_real, description="Real c"), - c_imag=FloatSlider(min=-2.0, max=2.0, step=EPS, - value=c_imag, description="Imag c"), - x_center=FloatSlider(min=-1.0, max=1.0, step=EPS, - value=x_center, description="Real center"), - y_center=FloatSlider(min=-1.0, max=1.0, step=EPS, - value=y_center, description="Imag center"), - image_width=FloatSlider(min=EPS, max=4.0, step=EPS, - value=image_width, description='Width'), - max_iteration=IntSlider(min=0, max=1000, - value=max_iteration, description='Iterations'), - pixel_count=IntSlider(min=10, max=1000, - value=pixel_count, description='Pixels'), - level_sep=IntSlider(min=1, max=20, - value=level_sep, description="Color sep"), - color_num=IntSlider(min=1, max=100, - value=number_of_colors, description="# Colors"), - base_color=ColorPicker(value=base_color.html_color(), - description="Base color"), + c_real=FloatSlider(min=-2.0, max=2.0, step=EPS, value=c_real, description="Real c"), + c_imag=FloatSlider(min=-2.0, max=2.0, step=EPS, value=c_imag, description="Imag c"), + x_center=FloatSlider(min=-1.0, max=1.0, step=EPS, value=x_center, description="Real center"), + y_center=FloatSlider(min=-1.0, max=1.0, step=EPS, value=y_center, description="Imag center"), + image_width=FloatSlider(min=EPS, max=4.0, step=EPS, value=image_width, description='Width'), + max_iteration=IntSlider(min=0, max=1000, value=max_iteration, description='Iterations'), + pixel_count=IntSlider(min=10, max=1000, value=pixel_count, description='Pixels'), + level_sep=IntSlider(min=1, max=20, value=level_sep, description="Color sep"), + color_num=IntSlider(min=1, max=100, value=number_of_colors, description="# Colors"), + base_color=ColorPicker(value=base_color.html_color(), description="Base color"), ) if mandelbrot: - widgets["point_color"] = ColorPicker(value=point_color.html_color(), - description="Point color") + widgets["point_color"] = ColorPicker(value=point_color.html_color(), description="Point color") return interact(**widgets).widget(julia_helper) return interact(**widgets).widget(fast_julia_plot) if mandelbrot: # non-interactive with mandelbrot - return julia_helper(c_real, c_imag, x_center, y_center, - image_width, max_iteration, pixel_count, - level_sep, number_of_colors, base_color, - point_color) + return julia_helper(c_real, c_imag, x_center, y_center, image_width, max_iteration, pixel_count, level_sep, number_of_colors, base_color, point_color) # non-interactive without mandelbrot - return fast_julia_plot(c_real, c_imag, x_center, y_center, - image_width, max_iteration, pixel_count, - level_sep, number_of_colors, base_color) + return fast_julia_plot(c_real, c_imag, x_center, y_center, image_width, max_iteration, pixel_count, level_sep, number_of_colors, base_color) diff --git a/src/sage/dynamics/finite_dynamical_system.py b/src/sage/dynamics/finite_dynamical_system.py index 1277d9540fd..02767bf70e6 100644 --- a/src/sage/dynamics/finite_dynamical_system.py +++ b/src/sage/dynamics/finite_dynamical_system.py @@ -71,6 +71,7 @@ - Interact with sage.dynamics. This requires someone who knows the latter part of the Sage library well. """ + # **************************************************************************** # Copyright (C) 2018 Darij Grinberg , # 2018 Tom Roby @@ -288,6 +289,7 @@ class DiscreteDynamicalSystem(SageObject, metaclass=ClasscallMetaclass): sage: D.inverse_evolution()((0, 1, 1, 0, 1, 0, 0, 1)) (1, 0, 1, 1, 0, 1, 0, 0) """ + @staticmethod def __classcall_private__(cls, X, phi, cache_orbits=False, create_tuple=False, inverse=None, is_finite=None): """ @@ -345,18 +347,15 @@ def __classcall_private__(cls, X, phi, cache_orbits=False, create_tuple=False, i """ if is_finite is None: - is_finite = (X in Sets().Finite() or isinstance(X, (list,tuple,set,frozenset))) + is_finite = X in Sets().Finite() or isinstance(X, (list, tuple, set, frozenset)) if inverse: - if inverse is True: # invertibility claimed, but inverse not provided + if inverse is True: # invertibility claimed, but inverse not provided # This is how the input for these subclasses work inverse = None - ret_cls = (InvertibleFiniteDynamicalSystem if is_finite - else InvertibleDiscreteDynamicalSystem) - return ret_cls(X, phi, cache_orbits=cache_orbits, - create_tuple=create_tuple, inverse=inverse) + ret_cls = InvertibleFiniteDynamicalSystem if is_finite else InvertibleDiscreteDynamicalSystem + return ret_cls(X, phi, cache_orbits=cache_orbits, create_tuple=create_tuple, inverse=inverse) if is_finite: - return FiniteDynamicalSystem(X, phi, cache_orbits=cache_orbits, - create_tuple=create_tuple) + return FiniteDynamicalSystem(X, phi, cache_orbits=cache_orbits, create_tuple=create_tuple) return typecall(cls, X, phi, cache_orbits=cache_orbits, create_tuple=create_tuple) def __init__(self, X, phi, cache_orbits=False, create_tuple=False): @@ -448,6 +447,7 @@ def evolution_power(self, n): ValueError: the n-th power of evolution is only defined for nonnegative integers n """ from sage.rings.semirings.non_negative_integer_semiring import NN + if n not in NN: raise ValueError("the n-th power of evolution is only defined for nonnegative integers n") ev = self.evolution() @@ -457,6 +457,7 @@ def evn(x): for _ in range(n): y = ev(y) return y + return evn def __iter__(self): @@ -507,8 +508,7 @@ def _repr_(self): """ if self._X is None: return "A discrete dynamical system with unspecified ground set" - return "A discrete dynamical system with ground set " \ - + repr(self._X) + return "A discrete dynamical system with ground set " + repr(self._X) def orbit(self, x, preperiod=False): r""" @@ -647,7 +647,8 @@ def is_homomesic(self, h, average=None, find_average=False, elements=None): True """ from sage.rings.rational_field import QQ - orbavgs = [] # This will be the list of all averages on cycles. + + orbavgs = [] # This will be the list of all averages on cycles. if elements is None: # The user has not provided elements, so we need to # check all cycles of the DDS. @@ -663,7 +664,7 @@ def is_homomesic(self, h, average=None, find_average=False, elements=None): # by the user. for element in elements: (orb, ix) = self.orbit(element, preperiod=True) - cyc = orb[ix:] # the cycle in the orbit of element + cyc = orb[ix:] # the cycle in the orbit of element l = len(cyc) avg = ~(QQ(l)) * sum(h(i) for i in cyc) if avg not in orbavgs: @@ -750,6 +751,7 @@ class InvertibleDiscreteDynamicalSystem(DiscreteDynamicalSystem): sage: D_right.ground_set() (0, 1, 2, 3, 4) """ + def __init__(self, X, phi, inverse=None, cache_orbits=False, create_tuple=False): r""" Initialize ``self``. @@ -807,6 +809,7 @@ def evolution_power(self, n): 6 """ from sage.rings.integer_ring import ZZ + if n not in ZZ: raise ValueError("the n-th power of evolution is only defined for integers n") if n >= 0: @@ -820,6 +823,7 @@ def evn(x): for _ in range(n): y = ev(y) return y + return evn def _repr_(self): @@ -838,8 +842,7 @@ def _repr_(self): """ if self._X is None: return "An invertible discrete dynamical system with unspecified ground set" - return "An invertible discrete dynamical system with ground set " \ - + repr(self._X) + return "An invertible discrete dynamical system with ground set " + repr(self._X) def inverse_evolution(self): r""" @@ -1005,6 +1008,7 @@ class FiniteDynamicalSystem(DiscreteDynamicalSystem): sage: D.evolution()((1, 1, 1, 0, 1, 0, 0, 1)) (1, 1, 0, 1, 0, 0, 1, 0) """ + def _repr_(self): r""" String representation of ``self``. @@ -1016,8 +1020,7 @@ def _repr_(self): A finite discrete dynamical system with ground set (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) """ - return "A finite discrete dynamical system with ground set " \ - + repr(self._X) + return "A finite discrete dynamical system with ground set " + repr(self._X) def is_invariant(self, f): r""" @@ -1169,6 +1172,7 @@ class InvertibleFiniteDynamicalSystem(InvertibleDiscreteDynamicalSystem, FiniteD sage: sorted(D.orbit_lengths()) [2, 4, 8, 8, 8, 8, 8, 8, 8, 8] """ + def _repr_(self): r""" String representation of ``self``. @@ -1180,8 +1184,7 @@ def _repr_(self): An invertible finite discrete dynamical system with ground set (0, 1, 2, 3, 4) """ - return "An invertible finite discrete dynamical system with ground set " \ - + repr(self._X) + return "An invertible finite discrete dynamical system with ground set " + repr(self._X) def orbits(self): r""" diff --git a/src/sage/dynamics/finite_dynamical_system_catalog.py b/src/sage/dynamics/finite_dynamical_system_catalog.py index f9f0cf7d806..714c27b4585 100644 --- a/src/sage/dynamics/finite_dynamical_system_catalog.py +++ b/src/sage/dynamics/finite_dynamical_system_catalog.py @@ -15,7 +15,8 @@ Functions ========= """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2018 Darij Grinberg , # 2018 Tom Roby # @@ -23,10 +24,8 @@ # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** -from sage.dynamics.finite_dynamical_system import DiscreteDynamicalSystem, \ - FiniteDynamicalSystem, InvertibleDiscreteDynamicalSystem, \ - InvertibleFiniteDynamicalSystem +# ***************************************************************************** +from sage.dynamics.finite_dynamical_system import DiscreteDynamicalSystem, FiniteDynamicalSystem, InvertibleDiscreteDynamicalSystem, InvertibleFiniteDynamicalSystem def permutation(pi, invertible=True): @@ -60,9 +59,10 @@ def permutation(pi, invertible=True): False """ from sage.combinat.permutation import Permutation + pi = Permutation(pi) n = len(pi) - X = range(1, n+1) + X = range(1, n + 1) return InvertibleFiniteDynamicalSystem(X, pi, inverse=pi.inverse(), create_tuple=True) @@ -90,6 +90,7 @@ def one_line(xs): def pi(i): return xs2[i - 1] + return FiniteDynamicalSystem(X, pi, create_tuple=True) @@ -137,11 +138,12 @@ def bitstring_rotation(n, ones=None): """ if ones is None: from sage.categories.cartesian_product import cartesian_product - X = cartesian_product([[0,1]] * n) + + X = cartesian_product([[0, 1]] * n) else: from itertools import combinations - X = [tuple((1 if i in cs else 0) for i in range(n)) - for cs in combinations(range(n), ones)] + + X = [tuple((1 if i in cs else 0) for i in range(n)) for cs in combinations(range(n), ones)] if n == 0: phi = lambda x: x psi = phi @@ -235,6 +237,7 @@ def striker_sweep(E, predicate, elements, lazy=False): """ from sage.combinat.subset import Subsets from sage.sets.set import Set + X = [F for F in Subsets(E) if predicate(F)] def phi(F): @@ -250,6 +253,7 @@ def psi(F): if predicate(G): F = G return F + return InvertibleFiniteDynamicalSystem(X, phi, inverse=psi) @@ -275,10 +279,10 @@ def syt_promotion(lam): """ from sage.combinat.partition import Partition from sage.combinat.tableau import StandardTableaux + lam = Partition(lam) X = StandardTableaux(lam) - return InvertibleFiniteDynamicalSystem(X, lambda T: T.promotion(), - inverse=lambda T: T.promotion_inverse()) + return InvertibleFiniteDynamicalSystem(X, lambda T: T.promotion(), inverse=lambda T: T.promotion_inverse()) def order_ideal_rowmotion(P): @@ -305,6 +309,7 @@ def order_ideal_rowmotion(P): True """ from sage.sets.set import Set + X = [Set(P.order_ideal(A)) for A in P.antichains()] # Using P.order_ideals_lattice() instead causes intransparency issues: # sage can't always do P.rowmotion(I) when I is in P.order_ideals_lattice(). @@ -316,6 +321,7 @@ def psi(I): # inverse of rowmotion for i in P.linear_extension(): result = P.order_ideal_toggle(result, i) return result + return InvertibleFiniteDynamicalSystem(X, phi, inverse=psi) @@ -336,15 +342,11 @@ def semidistributive_rowmotion(L): d = L._element_to_vertex_dict meet_irr = [u for u in H if sum(1 for _ in H.upper_covers_iterator(u)) == 1] join_irr = [u for u in H if sum(1 for _ in H.lower_covers_iterator(u)) == 1] - kappa_dual = {L._vertex_to_element(u): L._vertex_to_element(H.kappa_dual(u)) - for u in meet_irr} - row0 = {a: L.join(kappa_dual[e] for e in L.canonical_meetands(a)) - for a in L} - - kappa = {L._vertex_to_element(u): L._vertex_to_element(H.kappa(u)) - for u in join_irr} - row1 = {a: L.meet(kappa[e] for e in L.canonical_joinands(a)) - for a in L} + kappa_dual = {L._vertex_to_element(u): L._vertex_to_element(H.kappa_dual(u)) for u in meet_irr} + row0 = {a: L.join(kappa_dual[e] for e in L.canonical_meetands(a)) for a in L} + + kappa = {L._vertex_to_element(u): L._vertex_to_element(H.kappa(u)) for u in join_irr} + row1 = {a: L.meet(kappa[e] for e in L.canonical_joinands(a)) for a in L} return InvertibleFiniteDynamicalSystem(L, lambda a: row0[a], inverse=lambda a: row1[a]) @@ -399,6 +401,7 @@ def bulgarian_solitaire(n): False """ from sage.combinat.partition import Partitions, _Partitions + X = Partitions(n) def phi(lam): diff --git a/src/sage/env.py b/src/sage/env.py index f6c198a8617..ec4dbafd38d 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -243,9 +243,7 @@ def var(key: str, *fallbacks: Optional[str], force: bool = False) -> Optional[st # The semicolon-separated search path for GAP packages. It is passed # directly to GAP via the -l flag. -GAP_ROOT_PATHS = var("GAP_ROOT_PATHS", - ";".join([join(SAGE_LOCAL, "lib", "gap"), - join(SAGE_LOCAL, "share", "gap")])) +GAP_ROOT_PATHS = var("GAP_ROOT_PATHS", ";".join([join(SAGE_LOCAL, "lib", "gap"), join(SAGE_LOCAL, "share", "gap")])) # post process if DOT_SAGE is not None and ' ' in DOT_SAGE: @@ -301,16 +299,18 @@ def sage_include_directories(use_sources=False): True """ from sage.misc.superseded import deprecation + deprecation(40765, 'use sage.config.get_include_dirs() instead') if use_sources: dirs = [SAGE_SRC] else: import sage - dirs = [os.path.dirname(directory) - for directory in sage.__path__] + + dirs = [os.path.dirname(directory) for directory in sage.__path__] try: import numpy + dirs.append(numpy.get_include()) except ModuleNotFoundError: pass @@ -322,8 +322,7 @@ def sage_include_directories(use_sources=False): return dirs -default_required_modules = ('fflas-ffpack', 'givaro', 'gsl', 'linbox', 'Singular', - 'libpng', 'gdlib', 'm4ri', 'zlib', 'ecl') +default_required_modules = ('fflas-ffpack', 'givaro', 'gsl', 'linbox', 'Singular', 'libpng', 'gdlib', 'm4ri', 'zlib', 'ecl') default_optional_modules = ('lapack',) @@ -392,8 +391,7 @@ def cython_aliases(required_modules=None, optional_modules=None): aliases = {} - for lib, required in itertools.chain(((lib, True) for lib in required_modules), - ((lib, False) for lib in optional_modules)): + for lib, required in itertools.chain(((lib, True) for lib in required_modules), ((lib, False) for lib in optional_modules)): var = lib.upper().replace("-", "") + "_" if lib == 'zlib': aliases[var + "CFLAGS"] = "" @@ -402,6 +400,7 @@ def cython_aliases(required_modules=None, optional_modules=None): libs = pkgconfig.libs(lib) except pkgconfig.PackageNotFoundError: from collections import defaultdict + pc = defaultdict(list, {'libraries': ['z']}) libs = "-lz" elif lib == 'ecl': @@ -449,8 +448,7 @@ def uname_specific(name, value, alternative): else: return alternative - aliases["LINUX_NOEXECSTACK"] = uname_specific("Linux", ["-Wl,-z,noexecstack"], - []) + aliases["LINUX_NOEXECSTACK"] = uname_specific("Linux", ["-Wl,-z,noexecstack"], []) # LinBox needs special care because it actually requires C++11 with # GNU extensions: -std=c++11 does not work, you need -std=gnu++11 diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index 5a3e973f655..a9224df33b3 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -78,6 +78,7 @@ class TrivialClasscallMetaClass(type): """ A trivial version of :class:`sage.misc.classcall_metaclass.ClasscallMetaclass` without Cython dependencies. """ + def __call__(cls, *args, **kwds): r""" This method implements ``cls()``. @@ -138,6 +139,7 @@ class Feature(TrivialUniqueRepresentation): sage: GapPackage("grape") is GapPackage("grape") True """ + def __init__(self, name, spkg=None, url=None, description=None, type='optional'): r""" TESTS:: @@ -164,10 +166,8 @@ def __init__(self, name, spkg=None, url=None, description=None, type='optional') else: if spkg and (t := spkg_type(spkg)) not in (type, None): from warnings import warn - warn(f'Feature {name} is declared {type}, ' - f'but it is provided by {spkg}, ' - f'which is declared {t} in SAGE_ROOT/build/pkgs', - stacklevel=3) + + warn(f'Feature {name} is declared {type}, ' f'but it is provided by {spkg}, ' f'which is declared {t} in SAGE_ROOT/build/pkgs', stacklevel=3) def is_present(self): r""" @@ -325,6 +325,7 @@ def joined_features(self): [] """ from sage.features.join_feature import JoinFeature + res = [] if isinstance(self, JoinFeature): for f in self._features: @@ -432,6 +433,7 @@ class FeatureNotPresentError(RuntimeError): ... FeatureNotPresentError: missing is not available. """ + def __init__(self, feature, reason=None, resolution=None): self.feature = feature self.reason = reason @@ -501,6 +503,7 @@ class FeatureTestResult: sage: FeatureTestResult(package, False, resolution='rtm').resolution 'rtm' """ + def __init__(self, feature, is_present, reason=None, resolution=None): r""" TESTS:: @@ -563,6 +566,7 @@ def package_systems(): """ # The current implementation never returns more than one system. from subprocess import CalledProcessError, run + global _cache_package_systems if _cache_package_systems is None: from sage.features.pkg_systems import ( @@ -570,6 +574,7 @@ def package_systems(): PipPackageSystem, SagePackageSystem, ) + _cache_package_systems = [] # Try to use scripts from SAGE_ROOT (or an installation of sage_bootstrap) # to obtain system package advice. @@ -618,6 +623,7 @@ class FileFeature(Feature): sage: Executable(name='sh', executable='sh').is_present() FeatureTestResult('sh', True) """ + def _is_present(self): r""" Whether the file is present. @@ -677,6 +683,7 @@ class Executable(FileFeature): sage: Executable(name='does-not-exist', executable='does-not-exist-xxxxyxyyxyy').is_present() FeatureTestResult('does-not-exist', False) """ + def __init__(self, name, executable, **kwds): r""" TESTS:: @@ -750,9 +757,7 @@ def absolute_filename(self) -> str: path = shutil.which(self.executable) if path is not None: return path - raise FeatureNotPresentError(self, - reason="Executable {executable!r} not found on PATH.".format(executable=self.executable), - resolution=self.resolution()) + raise FeatureNotPresentError(self, reason="Executable {executable!r} not found on PATH.".format(executable=self.executable), resolution=self.resolution()) class StaticFile(FileFeature): @@ -773,6 +778,7 @@ class StaticFile(FileFeature): To install no_such_file...you can try to run...sage -i some_spkg... Further installation instructions might be available at http://rand.om. """ + def __init__(self, name, filename, *, search_path=None, type='optional', **kwds): r""" TESTS:: @@ -884,6 +890,7 @@ class CythonFeature(Feature): sage: broken.is_present() FeatureTestResult('broken', False) """ + def __init__(self, name, test_code, **kwds): r""" TESTS:: @@ -945,6 +952,7 @@ class PythonModule(Feature): sage: from sage.features import PythonModule sage: PythonModule("ssl").require() # not tested - output depends on the python build """ + def __init__(self, name, **kwds): r""" TESTS:: @@ -970,6 +978,7 @@ def _is_present(self): FeatureTestResult('_no_such_module_', False) """ import importlib + try: importlib.import_module(self.name) except ImportError as exception: diff --git a/src/sage/features/all.py b/src/sage/features/all.py index 9acf7fb4868..6115b7f388e 100644 --- a/src/sage/features/all.py +++ b/src/sage/features/all.py @@ -27,6 +27,7 @@ def all_features(): import pkgutil import importlib import sage.features + # Following https://packaging.python.org/guides/creating-and-discovering-plugins/#using-namespace-packages for finder, name, ispkg in pkgutil.iter_modules(sage.features.__path__, sage.features.__name__ + "."): module = importlib.import_module(name) diff --git a/src/sage/features/bitness.py b/src/sage/features/bitness.py index 6d9f0de7c0a..2b72ed2ef01 100644 --- a/src/sage/features/bitness.py +++ b/src/sage/features/bitness.py @@ -1,6 +1,7 @@ r""" Feature for testing if the machine is 32-bit. """ + from . import Feature, FeatureTestResult import sys @@ -17,6 +18,7 @@ class Is32Bit(Feature): sage: Is32Bit() is Is32Bit() True """ + def __init__(self): Feature.__init__(self, '32_bit') diff --git a/src/sage/features/bliss.py b/src/sage/features/bliss.py index f14893b5a89..913c02a9e86 100644 --- a/src/sage/features/bliss.py +++ b/src/sage/features/bliss.py @@ -52,9 +52,7 @@ def __init__(self): sage: BlissLibrary() Feature('libbliss') """ - CythonFeature.__init__(self, "libbliss", test_code=TEST_CODE, - spkg='bliss', - url='http://www.tcs.hut.fi/Software/bliss/') + CythonFeature.__init__(self, "libbliss", test_code=TEST_CODE, spkg='bliss', url='http://www.tcs.hut.fi/Software/bliss/') class Bliss(JoinFeature): @@ -67,6 +65,7 @@ class Bliss(JoinFeature): sage: from sage.features.bliss import Bliss sage: Bliss().require() # optional - bliss """ + def __init__(self): r""" TESTS:: @@ -75,9 +74,7 @@ def __init__(self): sage: Bliss() Feature('bliss') """ - JoinFeature.__init__(self, "bliss", - [PythonModule("sage.graphs.bliss", spkg='bliss', - url='http://www.tcs.hut.fi/Software/bliss/')]) + JoinFeature.__init__(self, "bliss", [PythonModule("sage.graphs.bliss", spkg='bliss', url='http://www.tcs.hut.fi/Software/bliss/')]) def all_features(): diff --git a/src/sage/features/brial.py b/src/sage/features/brial.py index 4bf72b8bf01..f05f5896296 100644 --- a/src/sage/features/brial.py +++ b/src/sage/features/brial.py @@ -24,6 +24,7 @@ class Brial(JoinFeature): FeatureTestResult('sage.rings.polynomial.pbori.pbori', False) """ + def __init__(self): r""" TESTS:: @@ -32,9 +33,7 @@ def __init__(self): sage: isinstance(Brial(), Brial) True """ - JoinFeature.__init__(self, 'brial', - [PythonModule('sage.rings.polynomial.pbori.pbori')], - spkg='sagemath_brial', type='standard') + JoinFeature.__init__(self, 'brial', [PythonModule('sage.rings.polynomial.pbori.pbori')], spkg='sagemath_brial', type='standard') def all_features(): diff --git a/src/sage/features/cddlib.py b/src/sage/features/cddlib.py index dbc93b6c798..d772919e33b 100644 --- a/src/sage/features/cddlib.py +++ b/src/sage/features/cddlib.py @@ -28,6 +28,7 @@ class CddExecutable(Executable): FeatureTestResult('cddexec_gmp', False) """ + def __init__(self, name='cddexec_gmp'): r""" TESTS:: @@ -36,8 +37,7 @@ def __init__(self, name='cddexec_gmp'): sage: isinstance(CddExecutable(), CddExecutable) True """ - Executable.__init__(self, name=name, executable=name, spkg='cddlib', - url='https://github.com/cddlib/cddlib', type='standard') + Executable.__init__(self, name=name, executable=name, spkg='cddlib', url='https://github.com/cddlib/cddlib', type='standard') def all_features(): diff --git a/src/sage/features/coxeter3.py b/src/sage/features/coxeter3.py index 3fdc3c88e03..91839e30838 100644 --- a/src/sage/features/coxeter3.py +++ b/src/sage/features/coxeter3.py @@ -27,6 +27,7 @@ class Coxeter3(JoinFeature): sage: from sage.features.coxeter3 import Coxeter3 sage: Coxeter3().require() # optional - coxeter3 """ + def __init__(self): r""" TESTS:: @@ -35,9 +36,7 @@ def __init__(self): sage: Coxeter3() Feature('coxeter3') """ - JoinFeature.__init__(self, "coxeter3", - [PythonModule("sage.libs.coxeter3.coxeter", - spkg='coxeter3')]) + JoinFeature.__init__(self, "coxeter3", [PythonModule("sage.libs.coxeter3.coxeter", spkg='coxeter3')]) def all_features(): diff --git a/src/sage/features/csdp.py b/src/sage/features/csdp.py index 0be4eb8d421..f29ea3f0911 100644 --- a/src/sage/features/csdp.py +++ b/src/sage/features/csdp.py @@ -32,6 +32,7 @@ class CSDP(Executable): sage: CSDP().is_present() # optional - csdp FeatureTestResult('csdp', True) """ + def __init__(self): r""" TESTS:: @@ -40,8 +41,7 @@ def __init__(self): sage: isinstance(CSDP(), CSDP) True """ - Executable.__init__(self, name='csdp', spkg='csdp', executable='theta', - url='https://github.com/dimpase/csdp') + Executable.__init__(self, name='csdp', spkg='csdp', executable='theta', url='https://github.com/dimpase/csdp') def is_functional(self): r""" @@ -64,16 +64,12 @@ def is_functional(self): try: lines = subprocess.check_output(command, stderr=devnull) except subprocess.CalledProcessError as e: - return FeatureTestResult(self, False, - reason="Call to `{command}` failed with exit code {e.returncode}." - .format(command=" ".join(command), e=e)) + return FeatureTestResult(self, False, reason="Call to `{command}` failed with exit code {e.returncode}.".format(command=" ".join(command), e=e)) result = bytes_to_str(lines).strip().split('\n')[-1] match = re.match("^The Lovasz Theta Number is (.*)$", result) if match is None: - return FeatureTestResult(self, False, - reason="Last line of the output of `{command}` did not have the expected format." - .format(command=" ".join(command))) + return FeatureTestResult(self, False, reason="Last line of the output of `{command}` did not have the expected format.".format(command=" ".join(command))) return FeatureTestResult(self, True) diff --git a/src/sage/features/cython.py b/src/sage/features/cython.py index 8f03155ac2f..09a8b83b5a2 100644 --- a/src/sage/features/cython.py +++ b/src/sage/features/cython.py @@ -19,6 +19,7 @@ class sage__misc__cython(CythonFeature): A :class:`~sage.features.Feature` which describes whether :mod:`sage.misc.cython` is available and functional. """ + def __init__(self): r""" TESTS:: diff --git a/src/sage/features/databases.py b/src/sage/features/databases.py index 4a83e74f380..d0f4f91cc61 100644 --- a/src/sage/features/databases.py +++ b/src/sage/features/databases.py @@ -39,9 +39,7 @@ class DatabaseCremona(StaticFile): FeatureTestResult('database_cremona_ellcurve', True) """ - def __init__( - self, name="cremona", spkg="database_cremona_ellcurve", type="optional" - ): + def __init__(self, name="cremona", spkg="database_cremona_ellcurve", type="optional"): r""" TESTS:: diff --git a/src/sage/features/dot2tex.py b/src/sage/features/dot2tex.py index a3ee24df97d..02da5c14af9 100644 --- a/src/sage/features/dot2tex.py +++ b/src/sage/features/dot2tex.py @@ -26,6 +26,7 @@ class dot2tex(PythonModule): sage: dot2tex().is_present() # optional - dot2tex FeatureTestResult('dot2tex', True) """ + def __init__(self): r""" TESTS:: diff --git a/src/sage/features/dvipng.py b/src/sage/features/dvipng.py index ed59029ba1b..f3bdcc94d1f 100644 --- a/src/sage/features/dvipng.py +++ b/src/sage/features/dvipng.py @@ -1,6 +1,7 @@ r""" Feature for testing the presence of ``dvipng`` """ + # **************************************************************************** # Copyright (C) 2021 Sebastien Labbe # @@ -24,6 +25,7 @@ class dvipng(Executable): sage: dvipng().is_present() # optional - dvipng FeatureTestResult('dvipng', True) """ + def __init__(self): r""" TESTS:: @@ -32,8 +34,7 @@ def __init__(self): sage: isinstance(dvipng(), dvipng) True """ - Executable.__init__(self, 'dvipng', executable='dvipng', - url='https://savannah.nongnu.org/projects/dvipng/') + Executable.__init__(self, 'dvipng', executable='dvipng', url='https://savannah.nongnu.org/projects/dvipng/') def all_features(): diff --git a/src/sage/features/ecm.py b/src/sage/features/ecm.py index a97c06d6aae..5467347d056 100644 --- a/src/sage/features/ecm.py +++ b/src/sage/features/ecm.py @@ -1,6 +1,7 @@ r""" Feature for testing the presence of ``ecm`` or ``gmp-ecm`` """ + # **************************************************************************** # Copyright (C) 2032 Dima Pasechnik # @@ -25,6 +26,7 @@ class Ecm(Executable): sage: Ecm().is_present() FeatureTestResult('ecm', True) """ + def __init__(self): r""" TESTS:: @@ -33,8 +35,7 @@ def __init__(self): sage: isinstance(Ecm(), Ecm) True """ - Executable.__init__(self, name='ecm', executable=SAGE_ECMBIN, - spkg='ecm', type='standard') + Executable.__init__(self, name='ecm', executable=SAGE_ECMBIN, spkg='ecm', type='standard') def all_features(): diff --git a/src/sage/features/ffmpeg.py b/src/sage/features/ffmpeg.py index 951b2433f5c..c260316f451 100644 --- a/src/sage/features/ffmpeg.py +++ b/src/sage/features/ffmpeg.py @@ -1,6 +1,7 @@ r""" Feature for testing the presence of ``ffmpeg`` """ + # **************************************************************************** # Copyright (C) 2018-2022 Sebastien Labbe # @@ -24,6 +25,7 @@ class FFmpeg(Executable): sage: FFmpeg().is_present() # optional - ffmpeg FeatureTestResult('ffmpeg', True) """ + def __init__(self): r""" TESTS:: @@ -32,9 +34,7 @@ def __init__(self): sage: isinstance(FFmpeg(), FFmpeg) True """ - Executable.__init__(self, 'ffmpeg', executable='ffmpeg', - spkg='ffmpeg', - url='https://www.ffmpeg.org/') + Executable.__init__(self, 'ffmpeg', executable='ffmpeg', spkg='ffmpeg', url='https://www.ffmpeg.org/') def is_functional(self): r""" @@ -62,12 +62,14 @@ def is_functional(self): # create a png file with the content from sage.misc.temporary_file import tmp_filename + base_filename_png = tmp_filename(ext='.png') with open(base_filename_png, 'wb') as f: f.write(content) # Set up filenames import os + base, filename_png = os.path.split(base_filename_png) filename, _png = os.path.splitext(filename_png) @@ -75,38 +77,28 @@ def is_functional(self): # The `-nostdin` is needed to avoid the command to hang, see # https://stackoverflow.com/questions/16523746/ffmpeg-hangs-when-run-in-background commands = [] - for ext in ['.avi', '.flv', '.gif', '.mkv', '.mov', - '.mp4', '.ogg', '.ogv', '.webm', '.wmv']: + for ext in ['.avi', '.flv', '.gif', '.mkv', '.mov', '.mp4', '.ogg', '.ogv', '.webm', '.wmv']: - cmd = ['ffmpeg', '-nostdin', '-y', '-f', 'image2', '-r', '5', - '-i', filename_png, '-pix_fmt', 'rgb24', '-loop', '0', - filename + ext] + cmd = ['ffmpeg', '-nostdin', '-y', '-f', 'image2', '-r', '5', '-i', filename_png, '-pix_fmt', 'rgb24', '-loop', '0', filename + ext] commands.append(cmd) - for ext in ['.avi', '.flv', '.gif', '.mkv', '.mov', '.mpg', - '.mp4', '.ogg', '.ogv', '.webm', '.wmv']: + for ext in ['.avi', '.flv', '.gif', '.mkv', '.mov', '.mpg', '.mp4', '.ogg', '.ogv', '.webm', '.wmv']: - cmd = ['ffmpeg', '-nostdin', '-y', '-f', 'image2', '-i', - filename_png, filename + ext] + cmd = ['ffmpeg', '-nostdin', '-y', '-f', 'image2', '-i', filename_png, filename + ext] commands.append(cmd) # Running the commands and reporting any issue encountered from subprocess import run + for cmd in commands: try: result = run(cmd, cwd=base, capture_output=True, text=True) except OSError as e: - return FeatureTestResult(self, False, reason='Running command "{}" ' - 'raised an OSError "{}" '.format(' '.join(cmd), e)) + return FeatureTestResult(self, False, reason='Running command "{}" ' 'raised an OSError "{}" '.format(' '.join(cmd), e)) # If an error occurred, return False if result.returncode: - return FeatureTestResult(self, False, reason='Running command "{}" ' - 'returned nonzero exit status "{}" with stderr ' - '"{}" and stdout "{}".'.format(result.args, - result.returncode, - result.stderr.strip(), - result.stdout.strip())) + return FeatureTestResult(self, False, reason='Running command "{}" ' 'returned nonzero exit status "{}" with stderr ' '"{}" and stdout "{}".'.format(result.args, result.returncode, result.stderr.strip(), result.stdout.strip())) # If necessary, run more tests here # ... diff --git a/src/sage/features/flatter.py b/src/sage/features/flatter.py index b160366c10a..194365b42c9 100644 --- a/src/sage/features/flatter.py +++ b/src/sage/features/flatter.py @@ -15,6 +15,7 @@ class flatter(Executable): sage: flatter().is_present() # optional - flatter FeatureTestResult('flatter', True) """ + def __init__(self): r""" TESTS:: diff --git a/src/sage/features/four_ti_2.py b/src/sage/features/four_ti_2.py index 5fb63363778..35b18b209c2 100644 --- a/src/sage/features/four_ti_2.py +++ b/src/sage/features/four_ti_2.py @@ -10,6 +10,7 @@ class FourTi2Executable(Executable): r""" A :class:`~sage.features.Feature` for the :ref:`4ti2 ` executables. """ + def __init__(self, name): r""" TESTS:: @@ -19,10 +20,8 @@ def __init__(self, name): True """ from sage.env import SAGE_ENV - Executable.__init__(self, - name="4ti2-" + name, - executable=SAGE_ENV.get("FOURTITWO_" + name.upper(), None) or name, - spkg='4ti2') + + Executable.__init__(self, name="4ti2-" + name, executable=SAGE_ENV.get("FOURTITWO_" + name.upper(), None) or name, spkg='4ti2') class FourTi2(JoinFeature): @@ -35,6 +34,7 @@ class FourTi2(JoinFeature): sage: FourTi2().is_present() # optional - 4ti2 FeatureTestResult('4ti2', True) """ + def __init__(self): r""" TESTS:: @@ -43,11 +43,15 @@ def __init__(self): sage: isinstance(FourTi2(), FourTi2) True """ - JoinFeature.__init__(self, '4ti2', - [FourTi2Executable(x) - # same list is tested in build/pkgs/4ti2/spkg-configure.m4 - for x in ('hilbert', 'markov', 'graver', 'zsolve', 'qsolve', - 'rays', 'ppi', 'circuits', 'groebner')]) + JoinFeature.__init__( + self, + '4ti2', + [ + FourTi2Executable(x) + # same list is tested in build/pkgs/4ti2/spkg-configure.m4 + for x in ('hilbert', 'markov', 'graver', 'zsolve', 'qsolve', 'rays', 'ppi', 'circuits', 'groebner') + ], + ) def all_features(): diff --git a/src/sage/features/fricas.py b/src/sage/features/fricas.py index 2fbbc31458a..ae0f3eedbcc 100644 --- a/src/sage/features/fricas.py +++ b/src/sage/features/fricas.py @@ -26,6 +26,7 @@ class FriCAS(Executable): sage: FriCAS().is_present() # optional - fricas FeatureTestResult('fricas', True) """ + MINIMUM_VERSION = "1.3.8" def __init__(self): @@ -36,9 +37,7 @@ def __init__(self): sage: isinstance(FriCAS(), FriCAS) True """ - Executable.__init__(self, name='fricas', spkg='fricas', - executable='fricas', - url='https://fricas.github.io') + Executable.__init__(self, name='fricas', spkg='fricas', executable='fricas', url='https://fricas.github.io') def get_version(self): r""" @@ -71,18 +70,14 @@ def is_functional(self): try: lines = subprocess.check_output(command, stderr=subprocess.STDOUT, shell=True) except subprocess.CalledProcessError as e: - return FeatureTestResult(self, False, - reason="Call `{command}` failed with exit code {e.returncode}".format(command=" ".join(command), e=e)) + return FeatureTestResult(self, False, reason="Call `{command}` failed with exit code {e.returncode}".format(command=" ".join(command), e=e)) expected = b"FriCAS" if lines.find(expected) == -1: - return FeatureTestResult(self, False, - reason="Call `{command}` did not produce output which contains `{expected}`".format(command=" ".join(command), - expected=expected)) + return FeatureTestResult(self, False, reason="Call `{command}` did not produce output which contains `{expected}`".format(command=" ".join(command), expected=expected)) version = self.get_version() if version is None: - return FeatureTestResult(self, False, - reason="Could not determine FriCAS version") + return FeatureTestResult(self, False, reason="Could not determine FriCAS version") try: if Version(version) < Version(self.MINIMUM_VERSION): diff --git a/src/sage/features/gap.py b/src/sage/features/gap.py index 94dd83d24dd..e89e4229265 100644 --- a/src/sage/features/gap.py +++ b/src/sage/features/gap.py @@ -1,6 +1,7 @@ r""" Features for testing the presence of the SageMath interfaces to ``gap`` and of GAP packages """ + # ***************************************************************************** # Copyright (C) 2016 Julian Rüth # 2018 Jeroen Demeyer @@ -33,6 +34,7 @@ class GapPackage(Feature): sage: GapPackage("grape", spkg='gap_packages') Feature('gap_package_grape') """ + def __init__(self, package, **kwds): r""" TESTS:: @@ -60,27 +62,16 @@ def _is_present(self): try: from sage.libs.gap.libgap import libgap except ImportError: - return FeatureTestResult(self, False, - reason="sage.libs.gap is not available") + return FeatureTestResult(self, False, reason="sage.libs.gap is not available") # This returns "true" even if the package is already loaded. command = 'LoadPackage("{package}")'.format(package=self.package) presence = libgap.eval(command) if presence: - return FeatureTestResult(self, True, - reason="`{command}` evaluated to `{presence}` in GAP.".format(command=command, presence=presence)) - return FeatureTestResult(self, False, - reason="`{command}` evaluated to `{presence}` in GAP.".format(command=command, presence=presence)) + return FeatureTestResult(self, True, reason="`{command}` evaluated to `{presence}` in GAP.".format(command=command, presence=presence)) + return FeatureTestResult(self, False, reason="`{command}` evaluated to `{presence}` in GAP.".format(command=command, presence=presence)) def all_features(): - return [GapPackage("atlasrep", spkg='gap_packages'), - GapPackage("design", spkg='gap_packages'), - GapPackage("grape", spkg='gap_packages'), - GapPackage("guava", spkg='gap_packages'), - GapPackage("hap", spkg='gap_packages'), - GapPackage("polenta", spkg='gap_packages'), - GapPackage("polycyclic", spkg='gap_packages'), - GapPackage("qpa", spkg='gap_packages'), - GapPackage("quagroup", spkg='gap_packages')] + return [GapPackage("atlasrep", spkg='gap_packages'), GapPackage("design", spkg='gap_packages'), GapPackage("grape", spkg='gap_packages'), GapPackage("guava", spkg='gap_packages'), GapPackage("hap", spkg='gap_packages'), GapPackage("polenta", spkg='gap_packages'), GapPackage("polycyclic", spkg='gap_packages'), GapPackage("qpa", spkg='gap_packages'), GapPackage("quagroup", spkg='gap_packages')] diff --git a/src/sage/features/gfan.py b/src/sage/features/gfan.py index ab3ea6d7d7a..ab535f331aa 100644 --- a/src/sage/features/gfan.py +++ b/src/sage/features/gfan.py @@ -18,6 +18,7 @@ class GfanExecutable(Executable): r""" A :class:`~sage.features.Feature` for the :ref:`gfan ` executables. """ + def __init__(self, cmd=None): r""" TESTS:: diff --git a/src/sage/features/giac.py b/src/sage/features/giac.py index 646ffa30359..59dd0de5a40 100644 --- a/src/sage/features/giac.py +++ b/src/sage/features/giac.py @@ -15,6 +15,7 @@ class Giac(Executable): sage: Giac().is_present() # needs giac FeatureTestResult('giac', True) """ + def __init__(self): r""" TESTS:: @@ -23,8 +24,7 @@ def __init__(self): sage: isinstance(Giac(), Giac) True """ - Executable.__init__(self, 'giac', executable='giac', - spkg='giac', type='optional') + Executable.__init__(self, 'giac', executable='giac', spkg='giac', type='optional') def all_features(): diff --git a/src/sage/features/graph_generators.py b/src/sage/features/graph_generators.py index ee22143790b..cd92b30b2c6 100644 --- a/src/sage/features/graph_generators.py +++ b/src/sage/features/graph_generators.py @@ -31,6 +31,7 @@ class Plantri(Executable): sage: Plantri().is_present() # optional - plantri FeatureTestResult('plantri', True) """ + def __init__(self): r""" TESTS:: @@ -39,9 +40,7 @@ def __init__(self): sage: isinstance(Plantri(), Plantri) True """ - Executable.__init__(self, name='plantri', spkg='plantri', - executable='plantri', - url='http://users.cecs.anu.edu.au/~bdm/plantri/') + Executable.__init__(self, name='plantri', spkg='plantri', executable='plantri', url='http://users.cecs.anu.edu.au/~bdm/plantri/') def is_functional(self): r""" @@ -57,13 +56,11 @@ def is_functional(self): try: lines = subprocess.check_output(command, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: - return FeatureTestResult(self, False, - reason="Call `{command}` failed with exit code {e.returncode}".format(command=" ".join(command), e=e)) + return FeatureTestResult(self, False, reason="Call `{command}` failed with exit code {e.returncode}".format(command=" ".join(command), e=e)) expected = b"1 triangulations written" if lines.find(expected) == -1: - return FeatureTestResult(self, False, - reason="Call `{command}` did not produce output which contains `{expected}`".format(command=" ".join(command), expected=expected)) + return FeatureTestResult(self, False, reason="Call `{command}` did not produce output which contains `{expected}`".format(command=" ".join(command), expected=expected)) return FeatureTestResult(self, True) @@ -78,6 +75,7 @@ class Buckygen(Executable): sage: Buckygen().is_present() # optional - buckygen FeatureTestResult('buckygen', True) """ + def __init__(self): r""" TESTS:: @@ -86,9 +84,7 @@ def __init__(self): sage: isinstance(Buckygen(), Buckygen) True """ - Executable.__init__(self, name='buckygen', spkg='buckygen', - executable='buckygen', - url='http://caagt.ugent.be/buckygen/') + Executable.__init__(self, name='buckygen', spkg='buckygen', executable='buckygen', url='http://caagt.ugent.be/buckygen/') def is_functional(self): r""" @@ -104,13 +100,11 @@ def is_functional(self): try: lines = subprocess.check_output(command, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: - return FeatureTestResult(self, False, - reason="Call `{command}` failed with exit code {e.returncode}".format(command=" ".join(command), e=e)) + return FeatureTestResult(self, False, reason="Call `{command}` failed with exit code {e.returncode}".format(command=" ".join(command), e=e)) expected = b"Number of fullerenes generated with 13 vertices: 0" if lines.find(expected) == -1: - return FeatureTestResult(self, False, - reason="Call `{command}` did not produce output which contains `{expected}`".format(command=" ".join(command), expected=expected)) + return FeatureTestResult(self, False, reason="Call `{command}` did not produce output which contains `{expected}`".format(command=" ".join(command), expected=expected)) return FeatureTestResult(self, True) @@ -126,6 +120,7 @@ class Benzene(Executable): sage: Benzene().is_present() # optional - benzene FeatureTestResult('benzene', True) """ + def __init__(self): r""" TESTS:: @@ -134,9 +129,7 @@ def __init__(self): sage: isinstance(Benzene(), Benzene) True """ - Executable.__init__(self, name='benzene', spkg='benzene', - executable='benzene', - url='http://www.grinvin.org/') + Executable.__init__(self, name='benzene', spkg='benzene', executable='benzene', url='http://www.grinvin.org/') def is_functional(self): r""" @@ -153,18 +146,14 @@ def is_functional(self): try: lines = subprocess.check_output(command, stderr=devnull) except subprocess.CalledProcessError as e: - return FeatureTestResult(self, False, - reason="Call `{command}` failed with exit code {e.returncode}".format(command=" ".join(command), e=e)) + return FeatureTestResult(self, False, reason="Call `{command}` failed with exit code {e.returncode}".format(command=" ".join(command), e=e)) expected = b">>planar_code<<" if not lines.startswith(expected): - return FeatureTestResult(self, False, - reason="Call `{command}` did not produce output that started with `{expected}`.".format(command=" ".join(command), expected=expected)) + return FeatureTestResult(self, False, reason="Call `{command}` did not produce output that started with `{expected}`.".format(command=" ".join(command), expected=expected)) return FeatureTestResult(self, True) def all_features(): - return [Plantri(), - Buckygen(), - Benzene()] + return [Plantri(), Buckygen(), Benzene()] diff --git a/src/sage/features/graphviz.py b/src/sage/features/graphviz.py index 56bcf0648ee..8fb7d6610f8 100644 --- a/src/sage/features/graphviz.py +++ b/src/sage/features/graphviz.py @@ -27,6 +27,7 @@ class dot(Executable): sage: dot().is_present() # optional - graphviz FeatureTestResult('dot', True) """ + def __init__(self): r""" TESTS:: @@ -35,9 +36,7 @@ def __init__(self): sage: isinstance(dot(), dot) True """ - Executable.__init__(self, 'dot', executable='dot', - spkg='graphviz', - url='https://www.graphviz.org/') + Executable.__init__(self, 'dot', executable='dot', spkg='graphviz', url='https://www.graphviz.org/') class neato(Executable): @@ -50,6 +49,7 @@ class neato(Executable): sage: neato().is_present() # optional - graphviz FeatureTestResult('neato', True) """ + def __init__(self): r""" TESTS:: @@ -58,9 +58,7 @@ def __init__(self): sage: isinstance(neato(), neato) True """ - Executable.__init__(self, 'neato', executable='neato', - spkg='graphviz', - url='https://www.graphviz.org/') + Executable.__init__(self, 'neato', executable='neato', spkg='graphviz', url='https://www.graphviz.org/') class twopi(Executable): @@ -73,6 +71,7 @@ class twopi(Executable): sage: twopi().is_present() # optional - graphviz FeatureTestResult('twopi', True) """ + def __init__(self): r""" TESTS:: @@ -81,9 +80,7 @@ def __init__(self): sage: isinstance(twopi(), twopi) True """ - Executable.__init__(self, 'twopi', executable='twopi', - spkg='graphviz', - url='https://www.graphviz.org/') + Executable.__init__(self, 'twopi', executable='twopi', spkg='graphviz', url='https://www.graphviz.org/') class Graphviz(JoinFeature): @@ -98,6 +95,7 @@ class Graphviz(JoinFeature): sage: Graphviz().is_present() # optional - graphviz FeatureTestResult('graphviz', True) """ + def __init__(self): r""" TESTS:: @@ -106,10 +104,7 @@ def __init__(self): sage: isinstance(Graphviz(), Graphviz) True """ - JoinFeature.__init__(self, 'graphviz', - [dot(), neato(), twopi()], - spkg='graphviz', - url='https://www.graphviz.org/') + JoinFeature.__init__(self, 'graphviz', [dot(), neato(), twopi()], spkg='graphviz', url='https://www.graphviz.org/') def all_features(): diff --git a/src/sage/features/igraph.py b/src/sage/features/igraph.py index 6e0850ce55b..c58eb32ca19 100644 --- a/src/sage/features/igraph.py +++ b/src/sage/features/igraph.py @@ -27,6 +27,7 @@ class python_igraph(JoinFeature): sage: python_igraph().is_present() # optional - python_igraph FeatureTestResult('python_igraph', True) """ + def __init__(self): r""" TESTS:: @@ -35,9 +36,7 @@ def __init__(self): sage: isinstance(python_igraph(), python_igraph) True """ - JoinFeature.__init__(self, 'python_igraph', - [PythonModule('igraph', spkg='python_igraph', - url='http://igraph.org')]) + JoinFeature.__init__(self, 'python_igraph', [PythonModule('igraph', spkg='python_igraph', url='http://igraph.org')]) def all_features(): diff --git a/src/sage/features/imagemagick.py b/src/sage/features/imagemagick.py index 2ac9948e6de..12de7508db5 100644 --- a/src/sage/features/imagemagick.py +++ b/src/sage/features/imagemagick.py @@ -31,6 +31,7 @@ class Magick(Executable): sage: Magick().is_present() # optional - imagemagick FeatureTestResult('magick', True) """ + def __init__(self): r""" TESTS:: @@ -71,35 +72,31 @@ def is_functional(self): # create a png file with the content from sage.misc.temporary_file import tmp_filename + base_filename_png = tmp_filename(ext='.png') with open(base_filename_png, 'wb') as f: f.write(content) # Set up filenames import os + base, filename_png = os.path.split(base_filename_png) filename, _png = os.path.splitext(filename_png) filename_gif = filename + '.gif' # running command magick/convert (taken from sage/plot/animate.py) from subprocess import run - cmd = [self.executable, '-dispose', 'Background', '-delay', '20', - '-loop', '0', filename_png, filename_gif] + + cmd = [self.executable, '-dispose', 'Background', '-delay', '20', '-loop', '0', filename_png, filename_gif] try: result = run(cmd, cwd=base, capture_output=True, text=True) except OSError as e: - return FeatureTestResult(self, False, reason='Running command "{}" ' - 'raised an OSError "{}" '.format(' '.join(cmd), e)) + return FeatureTestResult(self, False, reason='Running command "{}" ' 'raised an OSError "{}" '.format(' '.join(cmd), e)) # If an error occurred, return False if result.returncode: - return FeatureTestResult(self, False, reason='Running command "{}" ' - 'returned nonzero exit status "{}" with stderr ' - '"{}" and stdout "{}".'.format(result.args, - result.returncode, - result.stderr.strip(), - result.stdout.strip())) + return FeatureTestResult(self, False, reason='Running command "{}" ' 'returned nonzero exit status "{}" with stderr ' '"{}" and stdout "{}".'.format(result.args, result.returncode, result.stderr.strip(), result.stdout.strip())) # If necessary, run more tests here # ... @@ -121,6 +118,7 @@ class ImageMagick(JoinFeature): sage: ImageMagick().is_present() # optional - imagemagick FeatureTestResult('imagemagick', True) """ + def __init__(self): r""" TESTS:: @@ -129,10 +127,7 @@ def __init__(self): sage: isinstance(ImageMagick(), ImageMagick) True """ - JoinFeature.__init__(self, 'imagemagick', - [Magick()], - spkg='imagemagick', - url='https://www.imagemagick.org/') + JoinFeature.__init__(self, 'imagemagick', [Magick()], spkg='imagemagick', url='https://www.imagemagick.org/') def all_features(): diff --git a/src/sage/features/info.py b/src/sage/features/info.py index 65e6b1736d1..3193a69d3f9 100644 --- a/src/sage/features/info.py +++ b/src/sage/features/info.py @@ -15,6 +15,7 @@ class Info(Executable): sage: Info() Feature('info') """ + def __init__(self): r""" TESTS:: @@ -23,8 +24,7 @@ def __init__(self): sage: isinstance(Info(), Info) True """ - Executable.__init__(self, 'info', executable='info', - spkg='info', type='standard') + Executable.__init__(self, 'info', executable='info', spkg='info', type='standard') def all_features(): diff --git a/src/sage/features/interfaces.py b/src/sage/features/interfaces.py index 13952be1576..152c909dec8 100644 --- a/src/sage/features/interfaces.py +++ b/src/sage/features/interfaces.py @@ -36,6 +36,7 @@ class InterfaceFeature(Feature): sage: _.reason "Interface also_broken_interface cannot be imported: module 'sage.interfaces.interface' has no attribute 'also_broken_interface'" """ + @staticmethod def __classcall__(cls, name, module, description=None): """ @@ -80,14 +81,12 @@ def _is_present(self): try: interface = getattr(m, self.name) except Exception as exception: - return FeatureTestResult(self, False, - reason=f"Interface {self.name} cannot be imported: {exception}") + return FeatureTestResult(self, False, reason=f"Interface {self.name} cannot be imported: {exception}") try: interface('2+3') return FeatureTestResult(self, True) except Exception as exception: - return FeatureTestResult(self, False, - reason=f"Interface {interface} is not functional: {exception}") + return FeatureTestResult(self, False, reason=f"Interface {interface} is not functional: {exception}") class Mathics(InterfaceFeature): @@ -136,6 +135,7 @@ def __classcall__(cls): sage: F.module.unhide() """ from sage.features.join_feature import JoinFeature + interface = 'sage.interfaces.regina' mod = JoinFeature(interface, (PythonModule('regina'), PythonModule(interface))) return InterfaceFeature.__classcall__(cls, 'regina', mod) @@ -143,6 +143,7 @@ def __classcall__(cls): # The following are provided by external software only (no SPKG) + class Magma(InterfaceFeature): r""" A :class:`~sage.features.Feature` describing whether :class:`sage.interfaces.magma.Magma` @@ -280,12 +281,4 @@ def all_features(): Feature('regina'), Feature('scilab')] """ - return [Magma(), - Matlab(), - Mathematica(), - Mathics(), - Maple(), - Macaulay2(), - Octave(), - Regina(), - Scilab()] + return [Magma(), Matlab(), Mathematica(), Mathics(), Maple(), Macaulay2(), Octave(), Regina(), Scilab()] diff --git a/src/sage/features/internet.py b/src/sage/features/internet.py index 576b0136926..081be32b2ba 100644 --- a/src/sage/features/internet.py +++ b/src/sage/features/internet.py @@ -28,6 +28,7 @@ class Internet(Feature): sage: Internet() Feature('internet') """ + def __init__(self): r""" TESTS:: diff --git a/src/sage/features/jmol.py b/src/sage/features/jmol.py index 8dc1b86ef28..37b8de2b6a6 100644 --- a/src/sage/features/jmol.py +++ b/src/sage/features/jmol.py @@ -27,13 +27,7 @@ def __init__(self): jmol_search_path = JMOL_DIR or list(sage_data_paths('jmol')) - StaticFile.__init__( - self, name='jmol', - filename='JmolData.jar', - search_path=jmol_search_path, - spkg='jmol', - type='optional', - description="Java viewer for chemical structures in 3D") + StaticFile.__init__(self, name='jmol', filename='JmolData.jar', search_path=jmol_search_path, spkg='jmol', type='optional', description="Java viewer for chemical structures in 3D") def all_features(): diff --git a/src/sage/features/join_feature.py b/src/sage/features/join_feature.py index f76612ba45f..eefa6daa271 100644 --- a/src/sage/features/join_feature.py +++ b/src/sage/features/join_feature.py @@ -47,8 +47,7 @@ class JoinFeature(Feature): FeatureTestResult('xxyyyy', False) """ - def __init__(self, name, features, spkg=None, url=None, description=None, type=None, - **kwds): + def __init__(self, name, features, spkg=None, url=None, description=None, type=None, **kwds): """ TESTS: diff --git a/src/sage/features/kenzo.py b/src/sage/features/kenzo.py index 91f5e0b9b7d..102898c8fbb 100644 --- a/src/sage/features/kenzo.py +++ b/src/sage/features/kenzo.py @@ -28,6 +28,7 @@ class Kenzo(Feature): sage: Kenzo().is_present() # optional - kenzo FeatureTestResult('kenzo', True) """ + def __init__(self): r""" TESTS:: @@ -36,8 +37,7 @@ def __init__(self): sage: isinstance(Kenzo(), Kenzo) True """ - Feature.__init__(self, name='kenzo', spkg='kenzo', - url='https://github.com/miguelmarco/kenzo/') + Feature.__init__(self, name='kenzo', spkg='kenzo', url='https://github.com/miguelmarco/kenzo/') def _is_present(self): r""" @@ -56,13 +56,16 @@ def _is_present(self): # Redirection of ECL and Maxima stdout to /dev/null # This is also done in the Maxima library, but we # also do it here for redundancy. - ecl_eval(r"""(defparameter *dev-null* (make-two-way-stream - (make-concatenated-stream) (make-broadcast-stream)))""") + ecl_eval( + r"""(defparameter *dev-null* (make-two-way-stream + (make-concatenated-stream) (make-broadcast-stream)))""" + ) ecl_eval("(setf original-standard-output *standard-output*)") ecl_eval("(setf *standard-output* *dev-null*)") try: from sage.env import KENZO_FAS + if KENZO_FAS: ecl_eval("(require :kenzo \"{}\")".format(KENZO_FAS)) else: diff --git a/src/sage/features/khoca.py b/src/sage/features/khoca.py index c4bfffe545f..e6f75c30806 100644 --- a/src/sage/features/khoca.py +++ b/src/sage/features/khoca.py @@ -1,6 +1,7 @@ r""" Check for Khoca """ + from . import PythonModule @@ -16,6 +17,7 @@ class Khoca(PythonModule): sage: Khoca().is_present() # optional - khoca FeatureTestResult('khoca', True) """ + def __init__(self): r""" TESTS:: diff --git a/src/sage/features/latex.py b/src/sage/features/latex.py index 70d2c765d72..961893c72fb 100644 --- a/src/sage/features/latex.py +++ b/src/sage/features/latex.py @@ -31,6 +31,7 @@ class LaTeX(Executable): sage: latex().is_present() # optional - latex FeatureTestResult('latex', True) """ + def __init__(self, name): r""" TESTS:: @@ -77,14 +78,17 @@ def is_functional(self): # create a simple tex file with the content from sage.misc.temporary_file import tmp_filename + base_filename_tex = tmp_filename(ext='.tex') with open(base_filename_tex, 'w') as f: f.write(content) import os + base, filename_tex = os.path.split(base_filename_tex) # running latex from subprocess import run + cmd = [self.name, '-interaction=nonstopmode', filename_tex] cmd = ' '.join(cmd) result = run(cmd, shell=True, cwd=base, capture_output=True, text=True) @@ -92,13 +96,7 @@ def is_functional(self): # return if result.returncode == 0: return FeatureTestResult(self, True) - return FeatureTestResult(self, False, reason="Running latex on " - "a sample file (with command='{}') returned nonzero " - "exit status='{}' with stderr='{}' " - "and stdout='{}'".format(result.args, - result.returncode, - result.stderr.strip(), - result.stdout.strip())) + return FeatureTestResult(self, False, reason="Running latex on " "a sample file (with command='{}') returned nonzero " "exit status='{}' with stderr='{}' " "and stdout='{}'".format(result.args, result.returncode, result.stderr.strip(), result.stdout.strip())) class latex(LaTeX): @@ -111,6 +109,7 @@ class latex(LaTeX): sage: latex().is_present() # optional - latex FeatureTestResult('latex', True) """ + def __init__(self): r""" TESTS:: @@ -132,6 +131,7 @@ class pdflatex(LaTeX): sage: pdflatex().is_present() # optional - pdflatex FeatureTestResult('pdflatex', True) """ + def __init__(self): r""" TESTS:: @@ -153,6 +153,7 @@ class xelatex(LaTeX): sage: xelatex().is_present() # optional - xelatex FeatureTestResult('xelatex', True) """ + def __init__(self): r""" TESTS:: @@ -174,6 +175,7 @@ class lualatex(LaTeX): sage: lualatex().is_present() # optional - lualatex FeatureTestResult('lualatex', True) """ + def __init__(self): r""" TESTS:: @@ -195,6 +197,7 @@ class dvips(Executable): sage: dvips().is_present() # optional - dvips FeatureTestResult('dvips', True) """ + def __init__(self): r""" TESTS:: @@ -203,8 +206,7 @@ def __init__(self): sage: isinstance(dvips(), dvips) True """ - Executable.__init__(self, 'dvips', executable='dvips', - url='https://tug.org/texinfohtml/dvips.html') + Executable.__init__(self, 'dvips', executable='dvips', url='https://tug.org/texinfohtml/dvips.html') class TeXFile(StaticFile): @@ -217,6 +219,7 @@ class TeXFile(StaticFile): sage: TeXFile('x', 'x.tex').is_present() # optional - latex FeatureTestResult('x', True) """ + def __init__(self, name, filename, **kwds): r""" Initialize. @@ -241,9 +244,9 @@ def absolute_filename(self) -> str: '.../latex/base/article.cls' """ from subprocess import run, CalledProcessError + try: - proc = run(['kpsewhich', self.filename], - capture_output=True, text=True, check=True) + proc = run(['kpsewhich', self.filename], capture_output=True, text=True, check=True) return proc.stdout.strip() except CalledProcessError: reason = "{filename!r} not found by kpsewhich".format(filename=self.filename) @@ -275,6 +278,7 @@ class LaTeXPackage(TeXFile): sage: LaTeXPackage('graphics').is_present() # optional - latex FeatureTestResult('latex_package_graphics', True) """ + @staticmethod def __classcall__(cls, package_name, **kwds): """ @@ -284,16 +288,8 @@ def __classcall__(cls, package_name, **kwds): sage: LaTeXPackage('graphics') is LaTeXPackage('graphics') True """ - return TeXFile.__classcall__(cls, - f'latex_package_{package_name}'.replace('-', '_'), - f'{package_name}.sty', - **kwds) + return TeXFile.__classcall__(cls, f'latex_package_{package_name}'.replace('-', '_'), f'{package_name}.sty', **kwds) def all_features(): - return [latex(), - pdflatex(), - xelatex(), - lualatex(), - dvips(), - LaTeXPackage("tkz-graph")] + return [latex(), pdflatex(), xelatex(), lualatex(), dvips(), LaTeXPackage("tkz-graph")] diff --git a/src/sage/features/latte.py b/src/sage/features/latte.py index 8f7dc23fee8..7f9073d9c11 100644 --- a/src/sage/features/latte.py +++ b/src/sage/features/latte.py @@ -26,6 +26,7 @@ class Latte_count(Executable): r""" Feature for the executable ``count`` from :ref:`LattE integrale `. """ + def __init__(self): r""" TESTS:: @@ -34,15 +35,14 @@ def __init__(self): sage: isinstance(Latte_count(), Latte_count) True """ - Executable.__init__(self, 'count', executable='count', - spkg='latte_int', - url=LATTE_URL) + Executable.__init__(self, 'count', executable='count', spkg='latte_int', url=LATTE_URL) class Latte_integrate(Executable): r""" Feature for the executable ``integrate`` from :ref:`LattE integrale `. """ + def __init__(self): r""" TESTS:: @@ -51,9 +51,7 @@ def __init__(self): sage: isinstance(Latte_integrate(), Latte_integrate) True """ - Executable.__init__(self, 'integrate', executable='integrate', - spkg='latte_int', - url=LATTE_URL) + Executable.__init__(self, 'integrate', executable='integrate', spkg='latte_int', url=LATTE_URL) class Latte(JoinFeature): @@ -67,6 +65,7 @@ class Latte(JoinFeature): sage: Latte().is_present() # optional - latte_int FeatureTestResult('latte_int', True) """ + def __init__(self): r""" TESTS:: @@ -75,9 +74,7 @@ def __init__(self): sage: isinstance(Latte(), Latte) True """ - JoinFeature.__init__(self, 'latte_int', - (Latte_count(), Latte_integrate()), - description='LattE') + JoinFeature.__init__(self, 'latte_int', (Latte_count(), Latte_integrate()), description='LattE') def all_features(): diff --git a/src/sage/features/lrs.py b/src/sage/features/lrs.py index e22e3cbb8ac..03efd3f3db8 100644 --- a/src/sage/features/lrs.py +++ b/src/sage/features/lrs.py @@ -32,6 +32,7 @@ class Lrs(Executable): sage: Lrs().is_present() # optional - lrslib FeatureTestResult('lrs', True) """ + def __init__(self): r""" TESTS:: @@ -40,8 +41,7 @@ def __init__(self): sage: isinstance(Lrs(), Lrs) True """ - Executable.__init__(self, "lrs", executable='lrs', spkg='lrslib', - url='http://cgm.cs.mcgill.ca/~avis/C/lrs.html') + Executable.__init__(self, "lrs", executable='lrs', spkg='lrslib', url='http://cgm.cs.mcgill.ca/~avis/C/lrs.html') def is_functional(self): r""" @@ -62,20 +62,14 @@ def is_functional(self): try: result = subprocess.run(command, capture_output=True, text=True) except OSError as e: - return FeatureTestResult(self, False, reason='Running command "{}" ' - 'raised an OSError "{}" '.format(' '.join(command), e)) + return FeatureTestResult(self, False, reason='Running command "{}" ' 'raised an OSError "{}" '.format(' '.join(command), e)) if result.returncode: - return FeatureTestResult(self, False, - reason="Call to `{command}` failed with exit code {result.returncode}.".format(command=" ".join(command), result=result)) + return FeatureTestResult(self, False, reason="Call to `{command}` failed with exit code {result.returncode}.".format(command=" ".join(command), result=result)) expected_list = ["Volume= 1", "Volume=1"] if all(result.stdout.find(expected) == -1 for expected in expected_list): - return FeatureTestResult(self, False, - reason="Output of `{command}` did not contain the expected result {expected}; output: {result.stdout}".format( - command=" ".join(command), - expected=" or ".join(expected_list), - result=result)) + return FeatureTestResult(self, False, reason="Output of `{command}` did not contain the expected result {expected}; output: {result.stdout}".format(command=" ".join(command), expected=" or ".join(expected_list), result=result)) return FeatureTestResult(self, True) @@ -91,6 +85,7 @@ class LrsNash(Executable): sage: LrsNash().is_present() # optional - lrslib FeatureTestResult('lrsnash', True) """ + def __init__(self): r""" TESTS:: @@ -99,8 +94,7 @@ def __init__(self): sage: isinstance(LrsNash(), LrsNash) True """ - Executable.__init__(self, "lrsnash", executable='lrsnash', spkg='lrslib', - url='http://cgm.cs.mcgill.ca/~avis/C/lrs.html') + Executable.__init__(self, "lrsnash", executable='lrsnash', spkg='lrslib', url='http://cgm.cs.mcgill.ca/~avis/C/lrs.html') def is_functional(self): r""" @@ -123,15 +117,9 @@ def is_functional(self): try: result = subprocess.run(command, capture_output=True, text=True) except OSError as e: - return FeatureTestResult(self, False, reason='Running command "{}" ' - 'raised an OSError "{}" '.format(' '.join(command), e)) + return FeatureTestResult(self, False, reason='Running command "{}" ' 'raised an OSError "{}" '.format(' '.join(command), e)) if result.returncode: - return FeatureTestResult(self, False, reason='Running command "{}" ' - 'returned nonzero exit status "{}" with stderr ' - '"{}" and stdout "{}".'.format(' '.join(result.args), - result.returncode, - result.stderr.strip(), - result.stdout.strip())) + return FeatureTestResult(self, False, reason='Running command "{}" ' 'returned nonzero exit status "{}" with stderr ' '"{}" and stdout "{}".'.format(' '.join(result.args), result.returncode, result.stderr.strip(), result.stdout.strip())) return FeatureTestResult(self, True) @@ -147,6 +135,7 @@ class Lrslib(JoinFeature): sage: Lrslib().is_present() # optional - lrslib FeatureTestResult('lrslib', True) """ + def __init__(self): r""" TESTS:: @@ -155,8 +144,7 @@ def __init__(self): sage: isinstance(Lrslib(), Lrslib) True """ - JoinFeature.__init__(self, "lrslib", - (Lrs(), LrsNash())) + JoinFeature.__init__(self, "lrslib", (Lrs(), LrsNash())) def all_features(): diff --git a/src/sage/features/mcqd.py b/src/sage/features/mcqd.py index 7f0df8eedda..f92ce71af05 100644 --- a/src/sage/features/mcqd.py +++ b/src/sage/features/mcqd.py @@ -35,9 +35,7 @@ def __init__(self): sage: isinstance(Mcqd(), Mcqd) True """ - JoinFeature.__init__(self, 'mcqd', - [PythonModule('sage.graphs.mcqd', - spkg='mcqd')]) + JoinFeature.__init__(self, 'mcqd', [PythonModule('sage.graphs.mcqd', spkg='mcqd')]) def all_features(): diff --git a/src/sage/features/meataxe.py b/src/sage/features/meataxe.py index 3276b3cdba7..799256a4b0f 100644 --- a/src/sage/features/meataxe.py +++ b/src/sage/features/meataxe.py @@ -28,6 +28,7 @@ class Meataxe(JoinFeature): sage: Meataxe().is_present() # optional - meataxe FeatureTestResult('meataxe', True) """ + def __init__(self): r""" TESTS:: @@ -36,9 +37,7 @@ def __init__(self): sage: isinstance(Meataxe(), Meataxe) True """ - JoinFeature.__init__(self, 'meataxe', - [PythonModule('sage.matrix.matrix_gfpn_dense', - spkg='meataxe')]) + JoinFeature.__init__(self, 'meataxe', [PythonModule('sage.matrix.matrix_gfpn_dense', spkg='meataxe')]) def all_features(): diff --git a/src/sage/features/meson_editable.py b/src/sage/features/meson_editable.py index 9bc9eddf987..8a17e653659 100644 --- a/src/sage/features/meson_editable.py +++ b/src/sage/features/meson_editable.py @@ -1,6 +1,7 @@ r""" Feature for testing if Meson editable install is used. """ + from sage.config import is_editable_install from . import Feature, FeatureTestResult @@ -17,6 +18,7 @@ class MesonEditable(Feature): sage: MesonEditable() Feature('meson_editable') """ + def __init__(self): r""" TESTS:: diff --git a/src/sage/features/mip_backends.py b/src/sage/features/mip_backends.py index 98b4766c1f5..e47af2c32ca 100644 --- a/src/sage/features/mip_backends.py +++ b/src/sage/features/mip_backends.py @@ -20,6 +20,7 @@ class MIPBackend(Feature): r""" A :class:`~sage.features.Feature` describing whether a :class:`MixedIntegerLinearProgram` backend is available. """ + def _is_present(self): r""" Test for the presence of a :class:`MixedIntegerLinearProgram` backend. @@ -32,6 +33,7 @@ def _is_present(self): """ try: from sage.numerical.mip import MixedIntegerLinearProgram + MixedIntegerLinearProgram(solver=self.name) return FeatureTestResult(self, True) except Exception: @@ -42,6 +44,7 @@ class CPLEX(MIPBackend): r""" A :class:`~sage.features.Feature` describing whether the :class:`MixedIntegerLinearProgram` backend ``CPLEX`` is available. """ + def __init__(self): r""" TESTS:: @@ -50,14 +53,14 @@ def __init__(self): sage: CPLEX()._is_present() # optional - cplex FeatureTestResult('cplex', True) """ - MIPBackend.__init__(self, 'cplex', - spkg='sage_numerical_backends_cplex') + MIPBackend.__init__(self, 'cplex', spkg='sage_numerical_backends_cplex') class Gurobi(MIPBackend): r""" A :class:`~sage.features.Feature` describing whether the :class:`MixedIntegerLinearProgram` backend ``Gurobi`` is available. """ + def __init__(self): r""" TESTS:: @@ -66,14 +69,14 @@ def __init__(self): sage: Gurobi()._is_present() # optional - gurobi FeatureTestResult('gurobi', True) """ - MIPBackend.__init__(self, 'gurobi', - spkg='sage_numerical_backends_gurobi') + MIPBackend.__init__(self, 'gurobi', spkg='sage_numerical_backends_gurobi') class COIN(JoinFeature): r""" A :class:`~sage.features.Feature` describing whether the :class:`MixedIntegerLinearProgram` backend ``COIN`` is available. """ + def __init__(self): r""" TESTS:: @@ -82,15 +85,14 @@ def __init__(self): sage: COIN()._is_present() # optional - sage_numerical_backends_coin FeatureTestResult('sage_numerical_backends_coin', True) """ - JoinFeature.__init__(self, 'sage_numerical_backends_coin', - [MIPBackend('coin')], - spkg='sage_numerical_backends_coin') + JoinFeature.__init__(self, 'sage_numerical_backends_coin', [MIPBackend('coin')], spkg='sage_numerical_backends_coin') class CVXOPT(JoinFeature): r""" A :class:`~sage.features.Feature` describing whether the :class:`MixedIntegerLinearProgram` backend ``CVXOPT`` is available. """ + def __init__(self): r""" TESTS:: @@ -99,15 +101,8 @@ def __init__(self): sage: CVXOPT()._is_present() # optional - cvxopt FeatureTestResult('cvxopt', True) """ - JoinFeature.__init__(self, 'cvxopt', - [MIPBackend('CVXOPT'), - PythonModule('cvxopt')], - spkg='cvxopt', - type='standard') + JoinFeature.__init__(self, 'cvxopt', [MIPBackend('CVXOPT'), PythonModule('cvxopt')], spkg='cvxopt', type='standard') def all_features(): - return [CPLEX(), - Gurobi(), - COIN(), - CVXOPT()] + return [CPLEX(), Gurobi(), COIN(), CVXOPT()] diff --git a/src/sage/features/msolve.py b/src/sage/features/msolve.py index b6751beb005..f25c4e7b9ee 100644 --- a/src/sage/features/msolve.py +++ b/src/sage/features/msolve.py @@ -32,6 +32,7 @@ class msolve(Executable): sage: msolve().is_present() # optional - msolve FeatureTestResult('msolve', True) """ + def __init__(self): r""" TESTS:: @@ -40,8 +41,7 @@ def __init__(self): sage: isinstance(msolve(), msolve) True """ - Executable.__init__(self, "msolve", executable='msolve', - url='https://msolve.lip6.fr/') + Executable.__init__(self, "msolve", executable='msolve', url='https://msolve.lip6.fr/') def is_functional(self): r""" @@ -55,13 +55,11 @@ def is_functional(self): """ msolve_out = subprocess.run(["msolve", "-h"], capture_output=True) -# if msolve_out.returncode != 0: -# return FeatureTestResult(self, False, reason="msolve -h returned " -# f"nonzero exit status {msolve_out.returncode}") - if (msolve_out.stdout[:45] != - b'\nmsolve library for polynomial system solving'): - return FeatureTestResult(self, False, - reason="output of msolve -h not recognized") + # if msolve_out.returncode != 0: + # return FeatureTestResult(self, False, reason="msolve -h returned " + # f"nonzero exit status {msolve_out.returncode}") + if msolve_out.stdout[:45] != b'\nmsolve library for polynomial system solving': + return FeatureTestResult(self, False, reason="output of msolve -h not recognized") return FeatureTestResult(self, True) diff --git a/src/sage/features/normaliz.py b/src/sage/features/normaliz.py index f9b76f46509..9f148229b02 100644 --- a/src/sage/features/normaliz.py +++ b/src/sage/features/normaliz.py @@ -26,6 +26,7 @@ class PyNormaliz(JoinFeature): sage: PyNormaliz().is_present() # optional - pynormaliz FeatureTestResult('pynormaliz', True) """ + def __init__(self): r""" TESTS:: @@ -34,8 +35,7 @@ def __init__(self): sage: isinstance(PyNormaliz(), PyNormaliz) True """ - JoinFeature.__init__(self, 'pynormaliz', - [PythonModule('PyNormaliz', spkg='pynormaliz')]) + JoinFeature.__init__(self, 'pynormaliz', [PythonModule('PyNormaliz', spkg='pynormaliz')]) def all_features(): diff --git a/src/sage/features/palp.py b/src/sage/features/palp.py index 0545dc723d3..2594be0969c 100644 --- a/src/sage/features/palp.py +++ b/src/sage/features/palp.py @@ -1,6 +1,7 @@ r""" Feature for testing the presence of ``palp`` """ + # **************************************************************************** # Copyright (C) 2022 Matthias Koeppe # @@ -25,6 +26,7 @@ class PalpExecutable(Executable): - ``suff`` -- string or ``None`` """ + def __init__(self, palpprog, suff=None): r""" TESTS:: @@ -34,19 +36,16 @@ def __init__(self, palpprog, suff=None): True """ if suff: - Executable.__init__(self, f"palp_{palpprog}_{suff}d", - executable=f"{palpprog}-{suff}d.x", - spkg='palp', type='standard') + Executable.__init__(self, f"palp_{palpprog}_{suff}d", executable=f"{palpprog}-{suff}d.x", spkg='palp', type='standard') else: - Executable.__init__(self, f"palp_{palpprog}", - executable=f"{palpprog}.x", - spkg='palp', type='standard') + Executable.__init__(self, f"palp_{palpprog}", executable=f"{palpprog}.x", spkg='palp', type='standard') class Palp(JoinFeature): r""" A :class:`~sage.features.Feature` describing the presence of :ref:`PALP `. """ + def __init__(self): r""" TESTS:: @@ -55,11 +54,7 @@ def __init__(self): sage: isinstance(Palp(), Palp) True """ - JoinFeature.__init__(self, "palp", - [PalpExecutable(palpprog, suff) - for palpprog in ("poly", "class", "nef", "cws") - for suff in (None, 4, 5, 6, 11)], - description='PALP') + JoinFeature.__init__(self, "palp", [PalpExecutable(palpprog, suff) for palpprog in ("poly", "class", "nef", "cws") for suff in (None, 4, 5, 6, 11)], description='PALP') def all_features(): diff --git a/src/sage/features/pandoc.py b/src/sage/features/pandoc.py index 7600235a3c4..8961e261920 100644 --- a/src/sage/features/pandoc.py +++ b/src/sage/features/pandoc.py @@ -1,6 +1,7 @@ r""" Feature for testing the presence of ``pandoc`` """ + # **************************************************************************** # Copyright (C) 2018 Thierry Monteil # 2021 Matthias Koeppe @@ -25,6 +26,7 @@ class Pandoc(Executable): sage: Pandoc().is_present() # optional - pandoc FeatureTestResult('pandoc', True) """ + def __init__(self): r""" TESTS:: @@ -33,8 +35,7 @@ def __init__(self): sage: isinstance(Pandoc(), Pandoc) True """ - Executable.__init__(self, "pandoc", executable='pandoc', - url='https://pandoc.org/') + Executable.__init__(self, "pandoc", executable='pandoc', url='https://pandoc.org/') def all_features(): diff --git a/src/sage/features/pdf2svg.py b/src/sage/features/pdf2svg.py index a50d4ccc40e..9e09df6c498 100644 --- a/src/sage/features/pdf2svg.py +++ b/src/sage/features/pdf2svg.py @@ -1,6 +1,7 @@ r""" Feature for testing the presence of ``pdf2svg`` """ + # **************************************************************************** # Copyright (C) 2021 Sebastien Labbe # @@ -24,6 +25,7 @@ class pdf2svg(Executable): sage: pdf2svg().is_present() # optional - pdf2svg FeatureTestResult('pdf2svg', True) """ + def __init__(self): r""" TESTS:: @@ -32,9 +34,7 @@ def __init__(self): sage: isinstance(pdf2svg(), pdf2svg) True """ - Executable.__init__(self, "pdf2svg", executable='pdf2svg', - spkg='pdf2svg', - url='http://www.cityinthesky.co.uk/opensource/pdf2svg/') + Executable.__init__(self, "pdf2svg", executable='pdf2svg', spkg='pdf2svg', url='http://www.cityinthesky.co.uk/opensource/pdf2svg/') def all_features(): diff --git a/src/sage/features/phitigra.py b/src/sage/features/phitigra.py index 6c1896bd8df..8be6e9ac812 100644 --- a/src/sage/features/phitigra.py +++ b/src/sage/features/phitigra.py @@ -26,6 +26,7 @@ class Phitigra(PythonModule): sage: Phitigra().is_present() # optional - phitigra FeatureTestResult('phitigra', True) """ + def __init__(self): r""" TESTS:: diff --git a/src/sage/features/pkg_systems.py b/src/sage/features/pkg_systems.py index 9e35328dfc9..dd2ce551b94 100644 --- a/src/sage/features/pkg_systems.py +++ b/src/sage/features/pkg_systems.py @@ -24,6 +24,7 @@ class PackageSystem(Feature): sage: PackageSystem('conda') Feature('conda') """ + def _is_present(self): r""" Test whether ``self`` appears in the list of available package systems. @@ -36,6 +37,7 @@ def _is_present(self): True """ from . import package_systems + return self in package_systems() def spkg_installation_hint(self, spkgs, *, prompt=" !", feature=None): @@ -69,11 +71,11 @@ def _spkg_installation_hint(self, spkgs, prompt, feature): 'To install openblas using the fedora package manager, you can try to run:\n!sudo yum install openblas-devel' """ from subprocess import run, CalledProcessError + lines = [] system = self.name try: - proc = run(f'sage-get-system-packages {system} {spkgs}', - shell=True, capture_output=True, text=True, check=True) + proc = run(f'sage-get-system-packages {system} {spkgs}', shell=True, capture_output=True, text=True, check=True) system_packages = proc.stdout.strip() print_sys = f'sage-print-system-package-command {system} --verbose --sudo --prompt="{prompt}"' command = f'{print_sys} update && {print_sys} install {system_packages}' @@ -98,6 +100,7 @@ class SagePackageSystem(PackageSystem): sage: SagePackageSystem() Feature('sage_spkg') """ + @staticmethod def __classcall__(cls): r""" @@ -122,6 +125,7 @@ def _is_present(self): True """ from subprocess import run, DEVNULL, CalledProcessError + try: # "sage -p" is a fast way of checking whether sage-spkg is available. run('sage -p', shell=True, stdout=DEVNULL, stderr=DEVNULL, check=True) @@ -163,6 +167,7 @@ class PipPackageSystem(PackageSystem): sage: PipPackageSystem() Feature('pip') """ + @staticmethod def __classcall__(cls): r""" @@ -187,6 +192,7 @@ def _is_present(self): True """ from subprocess import run, DEVNULL, CalledProcessError + try: # The command below is missing the arguments to pip, but # when run from within the sage distribution, it will diff --git a/src/sage/features/polymake.py b/src/sage/features/polymake.py index bf1e95117fd..5a99468c539 100644 --- a/src/sage/features/polymake.py +++ b/src/sage/features/polymake.py @@ -26,6 +26,7 @@ class JuPyMake(JoinFeature): sage: JuPyMake().is_present() # optional - jupymake FeatureTestResult('jupymake', True) """ + def __init__(self): r""" TESTS:: @@ -34,8 +35,7 @@ def __init__(self): sage: isinstance(JuPyMake(), JuPyMake) True """ - JoinFeature.__init__(self, "jupymake", - [PythonModule("JuPyMake", spkg='jupymake')]) + JoinFeature.__init__(self, "jupymake", [PythonModule("JuPyMake", spkg='jupymake')]) def all_features(): diff --git a/src/sage/features/poppler.py b/src/sage/features/poppler.py index bfc0f29487c..0f95ff41a0e 100644 --- a/src/sage/features/poppler.py +++ b/src/sage/features/poppler.py @@ -19,6 +19,7 @@ Currently we only check for the presence of ``pdftocairo``. """ + # **************************************************************************** # Copyright (C) 2021 Sebastien Labbe # @@ -43,6 +44,7 @@ class pdftocairo(Executable): sage: pdftocairo().is_present() # optional: pdftocairo FeatureTestResult('pdftocairo', True) """ + def __init__(self): r""" TESTS:: @@ -51,8 +53,7 @@ def __init__(self): sage: isinstance(pdftocairo(), pdftocairo) True """ - Executable.__init__(self, "pdftocairo", executable='pdftocairo', - url='https://poppler.freedesktop.org/') + Executable.__init__(self, "pdftocairo", executable='pdftocairo', url='https://poppler.freedesktop.org/') def all_features(): diff --git a/src/sage/features/rubiks.py b/src/sage/features/rubiks.py index 6af32067f8b..0e115300326 100644 --- a/src/sage/features/rubiks.py +++ b/src/sage/features/rubiks.py @@ -1,6 +1,7 @@ r""" Features for testing the presence of ``rubiks`` """ + # **************************************************************************** # Copyright (C) 2020 John H. Palmieri # 2021-2022 Matthias Koeppe @@ -28,6 +29,7 @@ class cu2(Executable): sage: cu2().is_present() # optional - rubiks FeatureTestResult('cu2', True) """ + def __init__(self): r""" TESTS:: @@ -36,8 +38,7 @@ def __init__(self): sage: isinstance(cu2(), cu2) True """ - Executable.__init__(self, "cu2", executable=RUBIKS_BINS_PREFIX + "cu2", - spkg='rubiks') + Executable.__init__(self, "cu2", executable=RUBIKS_BINS_PREFIX + "cu2", spkg='rubiks') class size222(Executable): @@ -50,6 +51,7 @@ class size222(Executable): sage: size222().is_present() # optional - rubiks FeatureTestResult('size222', True) """ + def __init__(self): r""" TESTS:: @@ -58,8 +60,7 @@ def __init__(self): sage: isinstance(size222(), size222) True """ - Executable.__init__(self, "size222", executable=RUBIKS_BINS_PREFIX + "size222", - spkg='rubiks') + Executable.__init__(self, "size222", executable=RUBIKS_BINS_PREFIX + "size222", spkg='rubiks') class optimal(Executable): @@ -72,6 +73,7 @@ class optimal(Executable): sage: optimal().is_present() # optional - rubiks FeatureTestResult('optimal', True) """ + def __init__(self): r""" TESTS:: @@ -80,8 +82,7 @@ def __init__(self): sage: isinstance(optimal(), optimal) True """ - Executable.__init__(self, "optimal", executable=RUBIKS_BINS_PREFIX + "optimal", - spkg='rubiks') + Executable.__init__(self, "optimal", executable=RUBIKS_BINS_PREFIX + "optimal", spkg='rubiks') class mcube(Executable): @@ -94,6 +95,7 @@ class mcube(Executable): sage: mcube().is_present() # optional - rubiks FeatureTestResult('mcube', True) """ + def __init__(self): r""" TESTS:: @@ -102,8 +104,7 @@ def __init__(self): sage: isinstance(mcube(), mcube) True """ - Executable.__init__(self, "mcube", executable=RUBIKS_BINS_PREFIX + "mcube", - spkg='rubiks') + Executable.__init__(self, "mcube", executable=RUBIKS_BINS_PREFIX + "mcube", spkg='rubiks') class dikcube(Executable): @@ -116,6 +117,7 @@ class dikcube(Executable): sage: dikcube().is_present() # optional - rubiks FeatureTestResult('dikcube', True) """ + def __init__(self): r""" TESTS:: @@ -124,8 +126,7 @@ def __init__(self): sage: isinstance(dikcube(), dikcube) True """ - Executable.__init__(self, "dikcube", executable=RUBIKS_BINS_PREFIX + "dikcube", - spkg='rubiks') + Executable.__init__(self, "dikcube", executable=RUBIKS_BINS_PREFIX + "dikcube", spkg='rubiks') class cubex(Executable): @@ -138,6 +139,7 @@ class cubex(Executable): sage: cubex().is_present() # optional - rubiks FeatureTestResult('cubex', True) """ + def __init__(self): r""" TESTS:: @@ -146,8 +148,7 @@ def __init__(self): sage: isinstance(cubex(), cubex) True """ - Executable.__init__(self, "cubex", executable=RUBIKS_BINS_PREFIX + "cubex", - spkg='rubiks') + Executable.__init__(self, "cubex", executable=RUBIKS_BINS_PREFIX + "cubex", spkg='rubiks') class Rubiks(JoinFeature): @@ -162,6 +163,7 @@ class Rubiks(JoinFeature): sage: Rubiks().is_present() # optional - rubiks FeatureTestResult('rubiks', True) """ + def __init__(self): r""" TESTS:: @@ -170,9 +172,7 @@ def __init__(self): sage: isinstance(Rubiks(), Rubiks) True """ - JoinFeature.__init__(self, "rubiks", - [cu2(), size222(), optimal(), mcube(), dikcube(), cubex()], - spkg='rubiks') + JoinFeature.__init__(self, "rubiks", [cu2(), size222(), optimal(), mcube(), dikcube(), cubex()], spkg='rubiks') def all_features(): diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py index bd2f30b3597..e6929621f61 100644 --- a/src/sage/features/sagemath.py +++ b/src/sage/features/sagemath.py @@ -63,6 +63,7 @@ class sagemath_doc_html(StaticFile): sage: sagemath_doc_html().is_present() # needs sagemath_doc_html FeatureTestResult('sagemath_doc_html', True) """ + def __init__(self): r""" TESTS:: @@ -72,11 +73,8 @@ def __init__(self): True """ from sage.env import SAGE_DOC - StaticFile.__init__(self, 'sagemath_doc_html', - filename='html', - search_path=(SAGE_DOC,), - spkg='sagemath_doc_html', - type='optional') + + StaticFile.__init__(self, 'sagemath_doc_html', filename='html', search_path=(SAGE_DOC,), spkg='sagemath_doc_html', type='optional') class sage__combinat(JoinFeature): @@ -133,6 +131,7 @@ class sage__combinat(JoinFeature): sage: sage__combinat().is_present() # needs sage.combinat FeatureTestResult('sage.combinat', True) """ + def __init__(self): r""" TESTS:: @@ -145,11 +144,16 @@ def __init__(self): # Testing whether sage.combinat itself can be imported is meaningless. # Some modules providing basic combinatorics are already included in sagemath-categories. # Hence, we test a Python module within the package. - JoinFeature.__init__(self, 'sage.combinat', - [PythonModule('sage.combinat'), # namespace package - PythonModule('sage.combinat.tableau'), # representative - ], - spkg='sagemath_combinat', type='standard') + JoinFeature.__init__( + self, + 'sage.combinat', + [ + PythonModule('sage.combinat'), # namespace package + PythonModule('sage.combinat.tableau'), # representative + ], + spkg='sagemath_combinat', + type='standard', + ) class sage__geometry__polyhedron(JoinFeature): @@ -187,13 +191,18 @@ def __init__(self): sage: isinstance(sage__geometry__polyhedron(), sage__geometry__polyhedron) True """ - JoinFeature.__init__(self, 'sage.geometry.polyhedron', - [PythonModule('sage.geometry'), # namespace package - PythonModule('sage.geometry.polyhedron'), # representative - PythonModule('sage.schemes.toric'), # namespace package - PythonModule('sage.schemes.toric.variety'), # representative - ], - spkg='sagemath_polyhedra', type='standard') + JoinFeature.__init__( + self, + 'sage.geometry.polyhedron', + [ + PythonModule('sage.geometry'), # namespace package + PythonModule('sage.geometry.polyhedron'), # representative + PythonModule('sage.schemes.toric'), # namespace package + PythonModule('sage.schemes.toric.variety'), # representative + ], + spkg='sagemath_polyhedra', + type='standard', + ) class sage__graphs(JoinFeature): @@ -252,6 +261,7 @@ class sage__graphs(JoinFeature): sage: sage__graphs().is_present() # needs sage.graphs FeatureTestResult('sage.graphs', True) """ + def __init__(self): r""" TESTS:: @@ -260,22 +270,27 @@ def __init__(self): sage: isinstance(sage__graphs(), sage__graphs) True """ - JoinFeature.__init__(self, 'sage.graphs', - # These lists of modules are an (incomplete) duplication - # of information in the distribution's MANIFEST. - # But at least as long as the monolithic Sage library is - # around, we need this information here for use by - # sage-fixdoctests. - [PythonModule('sage.graphs'), # namespace package - PythonModule('sage.graphs.graph'), # representative - PythonModule('sage.combinat.designs'), # namespace package - PythonModule('sage.combinat.designs.block_design'), # representative - PythonModule('sage.combinat.posets'), # namespace package - PythonModule('sage.combinat.posets.posets'), # representative - PythonModule('sage.topology'), # namespace package - PythonModule('sage.topology.simplicial_complex'), # representative - ], - spkg='sagemath_graphs', type='standard') + JoinFeature.__init__( + self, + 'sage.graphs', + # These lists of modules are an (incomplete) duplication + # of information in the distribution's MANIFEST. + # But at least as long as the monolithic Sage library is + # around, we need this information here for use by + # sage-fixdoctests. + [ + PythonModule('sage.graphs'), # namespace package + PythonModule('sage.graphs.graph'), # representative + PythonModule('sage.combinat.designs'), # namespace package + PythonModule('sage.combinat.designs.block_design'), # representative + PythonModule('sage.combinat.posets'), # namespace package + PythonModule('sage.combinat.posets.posets'), # representative + PythonModule('sage.topology'), # namespace package + PythonModule('sage.topology.simplicial_complex'), # representative + ], + spkg='sagemath_graphs', + type='standard', + ) class sage__groups(JoinFeature): @@ -298,6 +313,7 @@ class sage__groups(JoinFeature): sage: sage__groups().is_present() # needs sage.groups FeatureTestResult('sage.groups', True) """ + def __init__(self): r""" TESTS:: @@ -306,9 +322,7 @@ def __init__(self): sage: isinstance(sage__groups(), sage__groups) True """ - JoinFeature.__init__(self, 'sage.groups', - [PythonModule('sage.groups.perm_gps.permgroup')], - spkg='sagemath_groups', type='standard') + JoinFeature.__init__(self, 'sage.groups', [PythonModule('sage.groups.perm_gps.permgroup')], spkg='sagemath_groups', type='standard') class sage__libs__braiding(PythonModule): @@ -330,8 +344,7 @@ def __init__(self): sage: isinstance(sage__libs__braiding(), sage__libs__braiding) True """ - PythonModule.__init__(self, 'sage.libs.braiding', - spkg='sagemath_libbraiding', type='standard') + PythonModule.__init__(self, 'sage.libs.braiding', spkg='sagemath_libbraiding', type='standard') class sage__libs__ecl(PythonModule): @@ -353,8 +366,7 @@ def __init__(self): sage: isinstance(sage__libs__ecl(), sage__libs__ecl) True """ - PythonModule.__init__(self, 'sage.libs.ecl', - spkg='sagemath_symbolics', type='standard') + PythonModule.__init__(self, 'sage.libs.ecl', spkg='sagemath_symbolics', type='standard') class sage__libs__flint(JoinFeature): @@ -371,6 +383,7 @@ class sage__libs__flint(JoinFeature): sage: sage__libs__flint().is_present() # needs sage.libs.flint FeatureTestResult('sage.libs.flint', True) """ + def __init__(self): r""" TESTS:: @@ -379,10 +392,7 @@ def __init__(self): sage: isinstance(sage__libs__flint(), sage__libs__flint) True """ - JoinFeature.__init__(self, 'sage.libs.flint', - [PythonModule('sage.libs.flint.arith_sage'), - PythonModule('sage.libs.flint.flint_sage')], - spkg='sagemath_flint', type='standard') + JoinFeature.__init__(self, 'sage.libs.flint', [PythonModule('sage.libs.flint.arith_sage'), PythonModule('sage.libs.flint.flint_sage')], spkg='sagemath_flint', type='standard') class sage__libs__gap(JoinFeature): @@ -403,6 +413,7 @@ class sage__libs__gap(JoinFeature): sage: sage__libs__gap().is_present() # needs sage.libs.gap FeatureTestResult('sage.libs.gap', True) """ + def __init__(self): r""" TESTS:: @@ -411,21 +422,7 @@ def __init__(self): sage: isinstance(sage__libs__gap(), sage__libs__gap) True """ - JoinFeature.__init__(self, 'sage.libs.gap', - [PythonModule('sage.libs.gap.libgap'), - PythonModule('sage.interfaces.gap'), - PythonModule('sage.groups.matrix_gps.finitely_generated_gap'), - PythonModule('sage.groups.matrix_gps.group_element_gap'), - PythonModule('sage.groups.matrix_gps.heisenberg'), - PythonModule('sage.groups.matrix_gps.isometries'), - PythonModule('sage.groups.matrix_gps.linear_gap'), - PythonModule('sage.groups.matrix_gps.matrix_group_gap'), - PythonModule('sage.groups.matrix_gps.named_group_gap'), - PythonModule('sage.groups.matrix_gps.orthogonal_gap'), - PythonModule('sage.groups.matrix_gps.symplectic_gap'), - PythonModule('sage.groups.matrix_gps.unitary_gap'), - PythonModule('sage.matrix.matrix_gap'), - PythonModule('sage.rings.universal_cyclotomic_field')]) + JoinFeature.__init__(self, 'sage.libs.gap', [PythonModule('sage.libs.gap.libgap'), PythonModule('sage.interfaces.gap'), PythonModule('sage.groups.matrix_gps.finitely_generated_gap'), PythonModule('sage.groups.matrix_gps.group_element_gap'), PythonModule('sage.groups.matrix_gps.heisenberg'), PythonModule('sage.groups.matrix_gps.isometries'), PythonModule('sage.groups.matrix_gps.linear_gap'), PythonModule('sage.groups.matrix_gps.matrix_group_gap'), PythonModule('sage.groups.matrix_gps.named_group_gap'), PythonModule('sage.groups.matrix_gps.orthogonal_gap'), PythonModule('sage.groups.matrix_gps.symplectic_gap'), PythonModule('sage.groups.matrix_gps.unitary_gap'), PythonModule('sage.matrix.matrix_gap'), PythonModule('sage.rings.universal_cyclotomic_field')]) class sage__libs__linbox(JoinFeature): @@ -442,6 +439,7 @@ class sage__libs__linbox(JoinFeature): sage: sage__libs__linbox().is_present() # needs sage.libs.linbox FeatureTestResult('sage.libs.linbox', True) """ + def __init__(self): r""" TESTS:: @@ -450,11 +448,7 @@ def __init__(self): sage: isinstance(sage__libs__linbox(), sage__libs__linbox) True """ - JoinFeature.__init__(self, 'sage.libs.linbox', - [PythonModule('sage.rings.finite_rings.element_givaro'), - PythonModule('sage.matrix.matrix_modn_dense_float'), - PythonModule('sage.matrix.matrix_modn_dense_double')], - spkg='sagemath_linbox', type='standard') + JoinFeature.__init__(self, 'sage.libs.linbox', [PythonModule('sage.rings.finite_rings.element_givaro'), PythonModule('sage.matrix.matrix_modn_dense_float'), PythonModule('sage.matrix.matrix_modn_dense_double')], spkg='sagemath_linbox', type='standard') class sage__libs__m4ri(JoinFeature): @@ -471,6 +465,7 @@ class sage__libs__m4ri(JoinFeature): sage: sage__libs__m4ri().is_present() # needs sage.libs.m4ri FeatureTestResult('sage.libs.m4ri', True) """ + def __init__(self): r""" TESTS:: @@ -479,10 +474,7 @@ def __init__(self): sage: isinstance(sage__libs__m4ri(), sage__libs__m4ri) True """ - JoinFeature.__init__(self, 'sage.libs.m4ri', - [PythonModule('sage.matrix.matrix_gf2e_dense'), - PythonModule('sage.matrix.matrix_mod2_dense')], - spkg='sagemath_m4ri', type='standard') + JoinFeature.__init__(self, 'sage.libs.m4ri', [PythonModule('sage.matrix.matrix_gf2e_dense'), PythonModule('sage.matrix.matrix_mod2_dense')], spkg='sagemath_m4ri', type='standard') class sage__libs__ntl(JoinFeature): @@ -499,6 +491,7 @@ class sage__libs__ntl(JoinFeature): sage: sage__libs__ntl().is_present() # needs sage.libs.ntl FeatureTestResult('sage.libs.ntl', True) """ + def __init__(self): r""" TESTS:: @@ -507,9 +500,7 @@ def __init__(self): sage: isinstance(sage__libs__ntl(), sage__libs__ntl) True """ - JoinFeature.__init__(self, 'sage.libs.ntl', - [PythonModule('sage.libs.ntl.convert')], - spkg='sagemath_ntl', type='standard') + JoinFeature.__init__(self, 'sage.libs.ntl', [PythonModule('sage.libs.ntl.convert')], spkg='sagemath_ntl', type='standard') class sage__libs__giac(JoinFeature): @@ -525,6 +516,7 @@ class sage__libs__giac(JoinFeature): sage: sage__libs__giac().is_present() # needs sage.libs.giac FeatureTestResult('sage.libs.giac', True) """ + def __init__(self): r""" TESTS:: @@ -533,9 +525,7 @@ def __init__(self): sage: isinstance(sage__libs__giac(), sage__libs__giac) True """ - JoinFeature.__init__(self, 'sage.libs.giac', - [PythonModule('sage.libs.giac.giac')], - spkg='sagemath_giac', type='optional') + JoinFeature.__init__(self, 'sage.libs.giac', [PythonModule('sage.libs.giac.giac')], spkg='sagemath_giac', type='optional') class sage__libs__homfly(JoinFeature): @@ -551,6 +541,7 @@ class sage__libs__homfly(JoinFeature): sage: sage__libs__homfly().is_present() # needs sage.libs.homfly FeatureTestResult('sage.libs.homfly', True) """ + def __init__(self): r""" TESTS:: @@ -559,9 +550,7 @@ def __init__(self): sage: isinstance(sage__libs__homfly(), sage__libs__homfly) True """ - JoinFeature.__init__(self, 'sage.libs.homfly', - [PythonModule('sage.libs.homfly')], - spkg='sagemath_homfly', type='standard') + JoinFeature.__init__(self, 'sage.libs.homfly', [PythonModule('sage.libs.homfly')], spkg='sagemath_homfly', type='standard') class sage__libs__pari(JoinFeature): @@ -589,6 +578,7 @@ class sage__libs__pari(JoinFeature): sage: sage__libs__pari().is_present() # needs sage.libs.pari FeatureTestResult('sage.libs.pari', True) """ + def __init__(self): r""" TESTS:: @@ -597,9 +587,7 @@ def __init__(self): sage: isinstance(sage__libs__pari(), sage__libs__pari) True """ - JoinFeature.__init__(self, 'sage.libs.pari', - [PythonModule('sage.libs.pari.convert_sage')], - spkg='sagemath_pari', type='standard') + JoinFeature.__init__(self, 'sage.libs.pari', [PythonModule('sage.libs.pari.convert_sage')], spkg='sagemath_pari', type='standard') class sage__libs__singular(JoinFeature): @@ -620,6 +608,7 @@ class sage__libs__singular(JoinFeature): sage: sage__libs__singular().is_present() # needs sage.libs.singular FeatureTestResult('sage.libs.singular', True) """ + def __init__(self): r""" TESTS:: @@ -628,9 +617,7 @@ def __init__(self): sage: isinstance(sage__libs__singular(), sage__libs__singular) True """ - JoinFeature.__init__(self, 'sage.libs.singular', - [PythonModule('sage.libs.singular.singular'), - PythonModule('sage.interfaces.singular')]) + JoinFeature.__init__(self, 'sage.libs.singular', [PythonModule('sage.libs.singular.singular'), PythonModule('sage.interfaces.singular')]) class sage__modular(JoinFeature): @@ -643,6 +630,7 @@ class sage__modular(JoinFeature): sage: sage__modular().is_present() # needs sage.modular FeatureTestResult('sage.modular', True) """ + def __init__(self): r""" TESTS:: @@ -651,9 +639,7 @@ def __init__(self): sage: isinstance(sage__modular(), sage__modular) True """ - JoinFeature.__init__(self, 'sage.modular', - [PythonModule('sage.modular.modform.eisenstein_submodule')], - spkg='sagemath_schemes', type='standard') + JoinFeature.__init__(self, 'sage.modular', [PythonModule('sage.modular.modform.eisenstein_submodule')], spkg='sagemath_schemes', type='standard') class sage__modules(JoinFeature): @@ -681,6 +667,7 @@ class sage__modules(JoinFeature): sage: sage__modules().is_present() # needs sage.modules FeatureTestResult('sage.modules', True) """ + def __init__(self): r""" TESTS:: @@ -689,26 +676,31 @@ def __init__(self): sage: isinstance(sage__modules(), sage__modules) True """ - JoinFeature.__init__(self, 'sage.modules', - [PythonModule('sage.modules'), # namespace package - PythonModule('sage.modules.free_module'), # representative - PythonModule('sage.matrix'), # namespace package - PythonModule('sage.matrix.matrix2'), # representative - PythonModule('sage.combinat.free_module'), - PythonModule('sage.quadratic_forms'), # namespace package - PythonModule('sage.quadratic_forms.quadratic_form'), # representative - PythonModule('sage.groups.additive_abelian'), # namespace package - PythonModule('sage.groups.additive_abelian.qmodnz'), # representative - PythonModule('sage.groups.affine_gps'), # namespace package - PythonModule('sage.groups.affine_gps.affine_group'), # representative - PythonModule('sage.groups.matrix_gps'), # namespace package - PythonModule('sage.groups.matrix_gps.named_group'), # representative - PythonModule('sage.homology'), # namespace package - PythonModule('sage.homology.chain_complex'), # representative - PythonModule('sage.matroids'), # namespace package - PythonModule('sage.matroids.matroid'), # representative - ], - spkg='sagemath_modules', type='standard') + JoinFeature.__init__( + self, + 'sage.modules', + [ + PythonModule('sage.modules'), # namespace package + PythonModule('sage.modules.free_module'), # representative + PythonModule('sage.matrix'), # namespace package + PythonModule('sage.matrix.matrix2'), # representative + PythonModule('sage.combinat.free_module'), + PythonModule('sage.quadratic_forms'), # namespace package + PythonModule('sage.quadratic_forms.quadratic_form'), # representative + PythonModule('sage.groups.additive_abelian'), # namespace package + PythonModule('sage.groups.additive_abelian.qmodnz'), # representative + PythonModule('sage.groups.affine_gps'), # namespace package + PythonModule('sage.groups.affine_gps.affine_group'), # representative + PythonModule('sage.groups.matrix_gps'), # namespace package + PythonModule('sage.groups.matrix_gps.named_group'), # representative + PythonModule('sage.homology'), # namespace package + PythonModule('sage.homology.chain_complex'), # representative + PythonModule('sage.matroids'), # namespace package + PythonModule('sage.matroids.matroid'), # representative + ], + spkg='sagemath_modules', + type='standard', + ) class sage__numerical__mip(PythonModule): @@ -721,6 +713,7 @@ class sage__numerical__mip(PythonModule): sage: sage__numerical__mip().is_present() # needs sage.numerical.mip FeatureTestResult('sage.numerical.mip', True) """ + def __init__(self): r""" TESTS:: @@ -729,8 +722,7 @@ def __init__(self): sage: isinstance(sage__numerical__mip(), sage__numerical__mip) True """ - PythonModule.__init__(self, 'sage.numerical.mip', - spkg='sagemath_polyhedra') + PythonModule.__init__(self, 'sage.numerical.mip', spkg='sagemath_polyhedra') class sage__plot(JoinFeature): @@ -743,6 +735,7 @@ class sage__plot(JoinFeature): sage: sage__plot().is_present() # needs sage.plot FeatureTestResult('sage.plot', True) """ + def __init__(self): r""" TESTS:: @@ -751,9 +744,7 @@ def __init__(self): sage: isinstance(sage__plot(), sage__plot) True """ - JoinFeature.__init__(self, 'sage.plot', - [PythonModule('sage.plot.plot')], - spkg='sagemath_plot', type='standard') + JoinFeature.__init__(self, 'sage.plot', [PythonModule('sage.plot.plot')], spkg='sagemath_plot', type='standard') class sage__rings__complex_double(PythonModule): @@ -766,6 +757,7 @@ class sage__rings__complex_double(PythonModule): sage: sage__rings__complex_double().is_present() # needs sage.rings.complex_double FeatureTestResult('sage.rings.complex_double', True) """ + def __init__(self): r""" TESTS:: @@ -774,8 +766,7 @@ def __init__(self): sage: isinstance(sage__rings__complex_double(), sage__rings__complex_double) True """ - PythonModule.__init__(self, 'sage.rings.complex_double', - spkg='sagemath_modules', type='standard') + PythonModule.__init__(self, 'sage.rings.complex_double', spkg='sagemath_modules', type='standard') class sage__rings__finite_rings(JoinFeature): @@ -789,6 +780,7 @@ class sage__rings__finite_rings(JoinFeature): sage: sage__rings__finite_rings().is_present() # needs sage.rings.finite_rings FeatureTestResult('sage.rings.finite_rings', True) """ + def __init__(self): r""" TESTS:: @@ -797,11 +789,7 @@ def __init__(self): sage: isinstance(sage__rings__finite_rings(), sage__rings__finite_rings) True """ - JoinFeature.__init__(self, 'sage.rings.finite_rings', - [PythonModule('sage.rings.finite_rings.element_pari_ffelt'), - PythonModule('sage.rings.algebraic_closure_finite_field'), - sage__libs__pari()], - type='standard') + JoinFeature.__init__(self, 'sage.rings.finite_rings', [PythonModule('sage.rings.finite_rings.element_pari_ffelt'), PythonModule('sage.rings.algebraic_closure_finite_field'), sage__libs__pari()], type='standard') class sage__rings__function_field(JoinFeature): @@ -834,6 +822,7 @@ class sage__rings__function_field(JoinFeature): sage: sage__rings__function_field().is_present() # needs sage.rings.function_field FeatureTestResult('sage.rings.function_field', True) """ + def __init__(self): r""" TESTS:: @@ -842,10 +831,7 @@ def __init__(self): sage: isinstance(sage__rings__function_field(), sage__rings__function_field) True """ - JoinFeature.__init__(self, 'sage.rings.function_field', - [PythonModule('sage.rings.function_field.function_field_polymod'), - sage__libs__singular()], - type='standard') + JoinFeature.__init__(self, 'sage.rings.function_field', [PythonModule('sage.rings.function_field.function_field_polymod'), sage__libs__singular()], type='standard') class sage__rings__number_field(JoinFeature): @@ -903,6 +889,7 @@ class sage__rings__number_field(JoinFeature): sage: sage__rings__number_field().is_present() # needs sage.rings.number_field FeatureTestResult('sage.rings.number_field', True) """ + def __init__(self): r""" TESTS:: @@ -911,11 +898,7 @@ def __init__(self): sage: isinstance(sage__rings__number_field(), sage__rings__number_field) True """ - JoinFeature.__init__(self, 'sage.rings.number_field', - [PythonModule('sage.rings.number_field.number_field_element'), - PythonModule('sage.rings.universal_cyclotomic_field'), - PythonModule('sage.rings.qqbar')], - type='standard') + JoinFeature.__init__(self, 'sage.rings.number_field', [PythonModule('sage.rings.number_field.number_field_element'), PythonModule('sage.rings.universal_cyclotomic_field'), PythonModule('sage.rings.qqbar')], type='standard') class sage__rings__padics(JoinFeature): @@ -928,6 +911,7 @@ class sage__rings__padics(JoinFeature): sage: sage__rings__padics().is_present() # needs sage.rings.padics FeatureTestResult('sage.rings.padics', True) """ + def __init__(self): r""" TESTS:: @@ -936,10 +920,7 @@ def __init__(self): sage: isinstance(sage__rings__padics(), sage__rings__padics) True """ - JoinFeature.__init__(self, 'sage.rings.padics', - [PythonModule('sage.rings.padics.factory')], - type='standard') - + JoinFeature.__init__(self, 'sage.rings.padics', [PythonModule('sage.rings.padics.factory')], type='standard') class sage__rings__real_double(PythonModule): @@ -962,6 +943,7 @@ class sage__rings__real_double(PythonModule): sage: sage__rings__real_double().is_present() # needs sage.rings.real_double FeatureTestResult('sage.rings.real_double', True) """ + def __init__(self): r""" TESTS:: @@ -983,6 +965,7 @@ class sage__rings__real_mpfr(JoinFeature): sage: sage__rings__real_mpfr().is_present() # needs sage.rings.real_mpfr FeatureTestResult('sage.rings.real_mpfr', True) """ + def __init__(self): r""" TESTS:: @@ -991,11 +974,16 @@ def __init__(self): sage: isinstance(sage__rings__real_mpfr(), sage__rings__real_mpfr) True """ - JoinFeature.__init__(self, 'sage.rings.real_mpfr', - [PythonModule('sage.rings.real_mpfr'), - PythonModule('sage.rings.complex_mpfr'), - ], - spkg='sagemath_modules', type='standard') + JoinFeature.__init__( + self, + 'sage.rings.real_mpfr', + [ + PythonModule('sage.rings.real_mpfr'), + PythonModule('sage.rings.complex_mpfr'), + ], + spkg='sagemath_modules', + type='standard', + ) class sage__sat(JoinFeature): @@ -1008,6 +996,7 @@ class sage__sat(JoinFeature): sage: sage__sat().is_present() # needs sage.sat FeatureTestResult('sage.sat', True) """ + def __init__(self): r""" TESTS:: @@ -1016,9 +1005,7 @@ def __init__(self): sage: isinstance(sage__sat(), sage__sat) True """ - JoinFeature.__init__(self, 'sage.sat', - [PythonModule('sage.sat.expression')], - spkg='sagemath_combinat', type='standard') + JoinFeature.__init__(self, 'sage.sat', [PythonModule('sage.sat.expression')], spkg='sagemath_combinat', type='standard') class sage__schemes(JoinFeature): @@ -1031,6 +1018,7 @@ class sage__schemes(JoinFeature): sage: sage__schemes().is_present() # needs sage.schemes FeatureTestResult('sage.schemes', True) """ + def __init__(self): r""" TESTS:: @@ -1039,9 +1027,7 @@ def __init__(self): sage: isinstance(sage__schemes(), sage__schemes) True """ - JoinFeature.__init__(self, 'sage.schemes', - [PythonModule('sage.schemes.elliptic_curves.ell_generic')], - spkg='sagemath_schemes', type='standard') + JoinFeature.__init__(self, 'sage.schemes', [PythonModule('sage.schemes.elliptic_curves.ell_generic')], spkg='sagemath_schemes', type='standard') class sage__symbolic(JoinFeature): @@ -1066,6 +1052,7 @@ class sage__symbolic(JoinFeature): sage: sage__symbolic().is_present() # needs sage.symbolic FeatureTestResult('sage.symbolic', True) """ + def __init__(self): r""" TESTS:: @@ -1074,31 +1061,37 @@ def __init__(self): sage: isinstance(sage__symbolic(), sage__symbolic) True """ - JoinFeature.__init__(self, 'sage.symbolic', - [PythonModule('sage.symbolic.expression'), - PythonModule('sage.manifolds'), - PythonModule('sage.calculus.calculus'), - PythonModule('sage.calculus.desolvers'), - PythonModule('sage.calculus.predefined'), - PythonModule('sage.calculus.tests'), - PythonModule('sage.calculus.var'), - PythonModule('sage.geometry.riemannian_manifolds'), - PythonModule('sage.geometry.hyperbolic_space'), - PythonModule('sage.dynamics.complex_dynamics'), - PythonModule('sage.libs.ecl'), - PythonModule('sage.interfaces.fricas'), - PythonModule('sage.interfaces.giac'), - PythonModule('sage.interfaces.magma'), - PythonModule('sage.interfaces.magma_free'), - PythonModule('sage.interfaces.maple'), - PythonModule('sage.interfaces.mathematica'), - PythonModule('sage.interfaces.mathics'), - PythonModule('sage.interfaces.maxima_abstract'), - PythonModule('sage.interfaces.maxima_lib'), - PythonModule('sage.interfaces.qepcad'), - PythonModule('sage.interfaces.sympy'), - PythonModule('sage.interfaces.sympy_wrapper'), - ], spkg='sagemath_symbolics', type='standard') + JoinFeature.__init__( + self, + 'sage.symbolic', + [ + PythonModule('sage.symbolic.expression'), + PythonModule('sage.manifolds'), + PythonModule('sage.calculus.calculus'), + PythonModule('sage.calculus.desolvers'), + PythonModule('sage.calculus.predefined'), + PythonModule('sage.calculus.tests'), + PythonModule('sage.calculus.var'), + PythonModule('sage.geometry.riemannian_manifolds'), + PythonModule('sage.geometry.hyperbolic_space'), + PythonModule('sage.dynamics.complex_dynamics'), + PythonModule('sage.libs.ecl'), + PythonModule('sage.interfaces.fricas'), + PythonModule('sage.interfaces.giac'), + PythonModule('sage.interfaces.magma'), + PythonModule('sage.interfaces.magma_free'), + PythonModule('sage.interfaces.maple'), + PythonModule('sage.interfaces.mathematica'), + PythonModule('sage.interfaces.mathics'), + PythonModule('sage.interfaces.maxima_abstract'), + PythonModule('sage.interfaces.maxima_lib'), + PythonModule('sage.interfaces.qepcad'), + PythonModule('sage.interfaces.sympy'), + PythonModule('sage.interfaces.sympy_wrapper'), + ], + spkg='sagemath_symbolics', + type='standard', + ) def all_features(): diff --git a/src/sage/features/sat.py b/src/sage/features/sat.py index 613b3122565..de903ad1639 100644 --- a/src/sage/features/sat.py +++ b/src/sage/features/sat.py @@ -16,6 +16,7 @@ class Glucose(Executable): sage: Glucose().is_present() # optional - glucose FeatureTestResult('glucose', True) """ + def __init__(self, executable="glucose"): r""" TESTS:: @@ -24,8 +25,7 @@ def __init__(self, executable="glucose"): sage: isinstance(Glucose(), Glucose) True """ - Executable.__init__(self, name=executable, executable=executable, - spkg="glucose", type="optional") + Executable.__init__(self, name=executable, executable=executable, spkg="glucose", type="optional") class Kissat(Executable): @@ -39,6 +39,7 @@ class Kissat(Executable): sage: Kissat().is_present() # optional - kissat FeatureTestResult('kissat', True) """ + def __init__(self): r""" TESTS:: @@ -47,8 +48,7 @@ def __init__(self): sage: isinstance(Kissat(), Kissat) True """ - Executable.__init__(self, name="kissat", executable="kissat", - spkg="kissat", type="optional") + Executable.__init__(self, name="kissat", executable="kissat", spkg="kissat", type="optional") class Pycosat(PythonModule): @@ -61,6 +61,7 @@ class Pycosat(PythonModule): sage: Pycosat().is_present() # optional - pycosat FeatureTestResult('pycosat', True) """ + def __init__(self): r""" TESTS:: @@ -69,8 +70,7 @@ def __init__(self): sage: isinstance(Pycosat(), Pycosat) True """ - PythonModule.__init__(self, "pycosat", - spkg="pycosat", type="optional") + PythonModule.__init__(self, "pycosat", spkg="pycosat", type="optional") class Pycryptosat(PythonModule): @@ -83,6 +83,7 @@ class Pycryptosat(PythonModule): sage: Pycryptosat().is_present() # optional - pycryptosat FeatureTestResult('pycryptosat', True) """ + def __init__(self): r""" TESTS:: @@ -91,12 +92,8 @@ def __init__(self): sage: isinstance(Pycryptosat(), Pycryptosat) True """ - PythonModule.__init__(self, "pycryptosat", - spkg="pycryptosat", type="optional") + PythonModule.__init__(self, "pycryptosat", spkg="pycryptosat", type="optional") def all_features(): - return [Glucose(), - Kissat(), - Pycosat(), - Pycryptosat()] + return [Glucose(), Kissat(), Pycosat(), Pycryptosat()] diff --git a/src/sage/features/singular.py b/src/sage/features/singular.py index fce89a8e91c..c4f6fcbcba8 100644 --- a/src/sage/features/singular.py +++ b/src/sage/features/singular.py @@ -31,6 +31,7 @@ class Singular(Executable): sage: Singular().is_present() # needs singular FeatureTestResult('singular', True) """ + def __init__(self): r""" TESTS:: @@ -39,8 +40,7 @@ def __init__(self): sage: isinstance(Singular(), Singular) True """ - Executable.__init__(self, "singular", SINGULAR_BIN, - spkg='singular', type='standard') + Executable.__init__(self, "singular", SINGULAR_BIN, spkg='singular', type='standard') def all_features(): diff --git a/src/sage/features/sirocco.py b/src/sage/features/sirocco.py index 727513f940f..6f24cfbb3c4 100644 --- a/src/sage/features/sirocco.py +++ b/src/sage/features/sirocco.py @@ -27,6 +27,7 @@ class Sirocco(JoinFeature): sage: from sage.features.sirocco import Sirocco sage: Sirocco().require() # optional - sirocco """ + def __init__(self): r""" TESTS:: @@ -35,9 +36,7 @@ def __init__(self): sage: Sirocco() Feature('sirocco') """ - JoinFeature.__init__(self, "sirocco", - [PythonModule("sage.libs.sirocco", - spkg='sirocco')]) + JoinFeature.__init__(self, "sirocco", [PythonModule("sage.libs.sirocco", spkg='sirocco')]) def all_features(): diff --git a/src/sage/features/sloane_database.py b/src/sage/features/sloane_database.py index 35acf520423..ef7d2d24324 100644 --- a/src/sage/features/sloane_database.py +++ b/src/sage/features/sloane_database.py @@ -26,6 +26,7 @@ class SloaneOEIS(Feature): sage: bool(SloaneOEIS().is_present()) # optional - sloane_database True """ + def __init__(self): r""" TESTS:: @@ -34,8 +35,7 @@ def __init__(self): sage: isinstance(SloaneOEIS(), SloaneOEIS) True """ - Feature.__init__(self, name='sloane_database', - description='Sloane Online Encyclopedia of Integer Sequences') + Feature.__init__(self, name='sloane_database', description='Sloane Online Encyclopedia of Integer Sequences') def _is_present(self): r""" diff --git a/src/sage/features/sphinx.py b/src/sage/features/sphinx.py index 976a3a2340c..defb0582764 100644 --- a/src/sage/features/sphinx.py +++ b/src/sage/features/sphinx.py @@ -27,6 +27,7 @@ class Sphinx(PythonModule): sage: Sphinx().is_present() # optional - sphinx FeatureTestResult('sphinx', True) """ + def __init__(self): r""" TESTS:: @@ -53,6 +54,7 @@ class JupyterSphinx(PythonModule): sage: JupyterSphinx().is_present() # optional - jupyter_sphinx FeatureTestResult('jupyter_sphinx', True) """ + def __init__(self): r""" TESTS:: @@ -61,10 +63,8 @@ def __init__(self): sage: isinstance(JupyterSphinx(), JupyterSphinx) True """ - PythonModule.__init__(self, 'jupyter_sphinx', - spkg='jupyter_sphinx', type='standard') + PythonModule.__init__(self, 'jupyter_sphinx', spkg='jupyter_sphinx', type='standard') def all_features(): - return [Sphinx(), - JupyterSphinx()] + return [Sphinx(), JupyterSphinx()] diff --git a/src/sage/features/standard.py b/src/sage/features/standard.py index 0dc27d8a4e7..2d64d0846c4 100644 --- a/src/sage/features/standard.py +++ b/src/sage/features/standard.py @@ -18,20 +18,22 @@ def all_features(): - return [PythonModule('cvxopt', spkg='cvxopt', type='standard'), - PythonModule('fpylll', spkg='fpylll', type='standard'), - JoinFeature('ipython', (PythonModule('IPython'),), spkg='ipython', type='standard'), - JoinFeature('lrcalc_python', (PythonModule('lrcalc'),), spkg='lrcalc_python', type='standard'), - PythonModule('mpmath', spkg='mpmath', type='standard'), - PythonModule('networkx', spkg='networkx', type='standard'), - PythonModule('numpy', spkg='numpy', type='standard'), - PythonModule('pexpect', spkg='pexpect', type='standard'), - JoinFeature('pillow', (PythonModule('PIL'),), spkg='pillow', type='standard'), - JoinFeature('pplpy', (PythonModule('ppl'),), spkg='pplpy', type='standard'), - PythonModule('primecountpy', spkg='primecountpy', type='standard'), - PythonModule('ptyprocess', spkg='ptyprocess', type='standard'), - PythonModule('pyparsing', spkg='pyparsing', type='standard'), - PythonModule('requests', spkg='requests', type='standard'), - PythonModule('rpy2', spkg='rpy2', type='standard'), - PythonModule('scipy', spkg='scipy', type='standard'), - PythonModule('sympy', spkg='sympy', type='standard')] + return [ + PythonModule('cvxopt', spkg='cvxopt', type='standard'), + PythonModule('fpylll', spkg='fpylll', type='standard'), + JoinFeature('ipython', (PythonModule('IPython'),), spkg='ipython', type='standard'), + JoinFeature('lrcalc_python', (PythonModule('lrcalc'),), spkg='lrcalc_python', type='standard'), + PythonModule('mpmath', spkg='mpmath', type='standard'), + PythonModule('networkx', spkg='networkx', type='standard'), + PythonModule('numpy', spkg='numpy', type='standard'), + PythonModule('pexpect', spkg='pexpect', type='standard'), + JoinFeature('pillow', (PythonModule('PIL'),), spkg='pillow', type='standard'), + JoinFeature('pplpy', (PythonModule('ppl'),), spkg='pplpy', type='standard'), + PythonModule('primecountpy', spkg='primecountpy', type='standard'), + PythonModule('ptyprocess', spkg='ptyprocess', type='standard'), + PythonModule('pyparsing', spkg='pyparsing', type='standard'), + PythonModule('requests', spkg='requests', type='standard'), + PythonModule('rpy2', spkg='rpy2', type='standard'), + PythonModule('scipy', spkg='scipy', type='standard'), + PythonModule('sympy', spkg='sympy', type='standard'), + ] diff --git a/src/sage/features/symengine_py.py b/src/sage/features/symengine_py.py index f9450ae484d..c6da68ee3ec 100644 --- a/src/sage/features/symengine_py.py +++ b/src/sage/features/symengine_py.py @@ -27,6 +27,7 @@ class symengine_py(JoinFeature): sage: symengine_py().is_present() # optional - symengine_py FeatureTestResult('symengine_py', True) """ + def __init__(self): r""" TESTS:: @@ -35,9 +36,7 @@ def __init__(self): sage: isinstance(symengine_py(), symengine_py) True """ - JoinFeature.__init__(self, 'symengine_py', - [PythonModule('symengine', spkg='symengine_py', - url='https://pypi.org/project/symengine')]) + JoinFeature.__init__(self, 'symengine_py', [PythonModule('symengine', spkg='symengine_py', url='https://pypi.org/project/symengine')]) def all_features(): diff --git a/src/sage/features/tdlib.py b/src/sage/features/tdlib.py index b47f9d8db9d..707d1f0ba1f 100644 --- a/src/sage/features/tdlib.py +++ b/src/sage/features/tdlib.py @@ -20,6 +20,7 @@ class Tdlib(JoinFeature): r""" A :class:`~sage.features.Feature` describing the presence of the SageMath interface to the :ref:`tdlib ` library. """ + def __init__(self): r""" TESTS:: @@ -28,9 +29,7 @@ def __init__(self): sage: isinstance(Tdlib(), Tdlib) True """ - JoinFeature.__init__(self, 'tdlib', - [PythonModule('sage.graphs.graph_decompositions.tdlib', - spkg='tdlib')]) + JoinFeature.__init__(self, 'tdlib', [PythonModule('sage.graphs.graph_decompositions.tdlib', spkg='tdlib')]) def all_features(): diff --git a/src/sage/features/threejs.py b/src/sage/features/threejs.py index 2a0021eca30..777804b0d4c 100644 --- a/src/sage/features/threejs.py +++ b/src/sage/features/threejs.py @@ -33,13 +33,7 @@ def __init__(self): except FileNotFoundError: filename = 'unknown' - StaticFile.__init__( - self, name='threejs', - filename=filename, - spkg='threejs', - type='standard', - search_path=threejs_search_path, - description="JavaScript library to display 3D graphics") + StaticFile.__init__(self, name='threejs', filename=filename, spkg='threejs', type='standard', search_path=threejs_search_path, description="JavaScript library to display 3D graphics") def required_version(self): """ diff --git a/src/sage/features/topcom.py b/src/sage/features/topcom.py index 5ee37e3053d..dee9dafcb65 100644 --- a/src/sage/features/topcom.py +++ b/src/sage/features/topcom.py @@ -25,6 +25,7 @@ class TOPCOMExecutable(Executable): sage: TOPCOMExecutable('points2allfinetriangs').is_present() # optional - topcom FeatureTestResult('topcom_points2allfinetriangs', True) """ + def __init__(self, name): r""" TESTS:: @@ -33,9 +34,7 @@ def __init__(self, name): sage: isinstance(TOPCOMExecutable('points2finetriangs'), TOPCOMExecutable) True """ - Executable.__init__(self, name=f"topcom_{name}", - executable=name, - spkg="topcom") + Executable.__init__(self, name=f"topcom_{name}", executable=name, spkg="topcom") class TOPCOM(JoinFeature): @@ -49,6 +48,7 @@ class TOPCOM(JoinFeature): sage: TOPCOM().is_present() # optional - topcom FeatureTestResult('topcom', True) """ + def __init__(self): r""" TESTS:: @@ -57,9 +57,7 @@ def __init__(self): sage: isinstance(TOPCOM(), TOPCOM) True """ - JoinFeature.__init__(self, "topcom", - [TOPCOMExecutable(name) - for name in ('points2allfinetriangs',)]) + JoinFeature.__init__(self, "topcom", [TOPCOMExecutable(name) for name in ('points2allfinetriangs',)]) def all_features(): diff --git a/src/sage/functions/airy.py b/src/sage/functions/airy.py index eeaf1b4639a..a136b0b9e16 100644 --- a/src/sage/functions/airy.py +++ b/src/sage/functions/airy.py @@ -55,8 +55,7 @@ lazy_import('sage.symbolic.ring', 'SR') lazy_import('sage.libs.mpmath.utils', 'call', as_='_mpmath_utils_call') -lazy_import('mpmath', ['airyai', 'airybi'], - as_=['_mpmath_airyai', '_mpmath_airybi']) +lazy_import('mpmath', ['airyai', 'airybi'], as_=['_mpmath_airyai', '_mpmath_airybi']) class FunctionAiryAiGeneral(BuiltinFunction): @@ -94,8 +93,7 @@ def __init__(self): sage: derivative(airy_ai_general(n, x), x) airy_ai(n + 1, x) """ - BuiltinFunction.__init__(self, "airy_ai", nargs=2, - latex_name=r"\operatorname{Ai}") + BuiltinFunction.__init__(self, "airy_ai", nargs=2, latex_name=r"\operatorname{Ai}") def _derivative_(self, alpha, x, diff_param=None): """ @@ -112,8 +110,7 @@ def _derivative_(self, alpha, x, diff_param=None): in the first parameter """ if diff_param == 0: - raise NotImplementedError("cannot differentiate airy_ai in the" - " first parameter") + raise NotImplementedError("cannot differentiate airy_ai in the" " first parameter") return airy_ai_general(alpha + 1, x) def _eval_(self, alpha, x): @@ -127,8 +124,7 @@ def _eval_(self, alpha, x): sage: airy_ai_general(n, 1.0) # needs sage.symbolic airy_ai(n, 1.00000000000000) """ - if not isinstance(x, Expression) and \ - not isinstance(alpha, Expression): + if not isinstance(x, Expression) and not isinstance(alpha, Expression): if self._is_numerical(x): return self._evalf_(alpha, x) if alpha == 0: @@ -136,7 +132,7 @@ def _eval_(self, alpha, x): if alpha == 1: return airy_ai_prime(x) if alpha == 2: - return x*airy_ai_simple(x) + return x * airy_ai_simple(x) else: return None @@ -148,8 +144,7 @@ def _evalf_(self, alpha, x, parent=None, algorithm=None): sage: airy_ai_general(-2, 1.0) # needs mpmath 0.136645379421096 """ - return _mpmath_utils_call(_mpmath_airyai, x, derivative=alpha, - parent=parent) + return _mpmath_utils_call(_mpmath_airyai, x, derivative=alpha, parent=parent) class FunctionAiryAiSimple(BuiltinFunction): @@ -165,13 +160,7 @@ def __init__(self): sage: airy_ai_simple(x)._sympy_() # needs sage.symbolic airyai(x) """ - BuiltinFunction.__init__(self, 'airy_ai', - latex_name=r"\operatorname{Ai}", - conversions=dict(mathematica='AiryAi', - maxima='airy_ai', - sympy='airyai', - fricas='airyAi', - giac='Airy_Ai')) + BuiltinFunction.__init__(self, 'airy_ai', latex_name=r"\operatorname{Ai}", conversions=dict(mathematica='AiryAi', maxima='airy_ai', sympy='airyai', fricas='airyAi', giac='Airy_Ai')) def _derivative_(self, x, diff_param=None): """ @@ -198,6 +187,7 @@ def _eval_(self, x): 0.331493305432141 - 0.317449858968444*I """ from .gamma import gamma + if x == 0: r = ZZ(2) / 3 return 1 / (3 ** (r) * gamma(r)) @@ -242,6 +232,7 @@ def _evalf_(self, x, **kwargs): from sage.rings.cc import CC from sage.functions.other import real, imag from scipy.special import airy + if x in RR: y = airy(real(x))[0] if parent is None: @@ -273,12 +264,7 @@ def __init__(self): sage: airy_ai_prime(x)._sympy_() # needs sympy airyaiprime(x) """ - BuiltinFunction.__init__(self, 'airy_ai_prime', - latex_name=r"\operatorname{Ai}'", - conversions=dict(mathematica='AiryAiPrime', - maxima='airy_dai', - sympy='airyaiprime', - fricas='airyAiPrime')) + BuiltinFunction.__init__(self, 'airy_ai_prime', latex_name=r"\operatorname{Ai}'", conversions=dict(mathematica='AiryAiPrime', maxima='airy_dai', sympy='airyaiprime', fricas='airyAiPrime')) def _derivative_(self, x, diff_param=None): """ @@ -299,6 +285,7 @@ def _eval_(self, x): -0.258819403792807 """ from .gamma import gamma + if x == 0: r = ZZ(1) / 3 return -1 / (3 ** (r) * gamma(r)) @@ -341,6 +328,7 @@ def _evalf_(self, x, **kwargs): from sage.rings.cc import CC from sage.functions.other import real, imag from scipy.special import airy + if x in RR: y = airy(real(x))[1] if parent is None: @@ -351,8 +339,7 @@ def _evalf_(self, x, **kwargs): return CC(y) return parent(y) if algorithm == 'mpmath': - return _mpmath_utils_call(_mpmath_airyai, x, derivative=1, - parent=parent) + return _mpmath_utils_call(_mpmath_airyai, x, derivative=1, parent=parent) raise ValueError("unknown algorithm '%s'" % algorithm) @@ -490,6 +477,7 @@ def airy_ai(alpha, x=None, hold_derivative=True, **kwds): return derivative(airy_ai_simple(v, **kwds), v, alpha).subs({v: x}) return airy_ai_general(alpha, x, **kwds) + ######################################################################## ######################################################################## @@ -529,8 +517,7 @@ def __init__(self): sage: derivative(airy_bi_general(n, x), x) airy_bi(n + 1, x) """ - BuiltinFunction.__init__(self, "airy_bi", nargs=2, - latex_name=r"\operatorname{Bi}") + BuiltinFunction.__init__(self, "airy_bi", nargs=2, latex_name=r"\operatorname{Bi}") def _derivative_(self, alpha, x, diff_param=None): """ @@ -547,8 +534,7 @@ def _derivative_(self, alpha, x, diff_param=None): in the first parameter """ if diff_param == 0: - raise NotImplementedError("cannot differentiate airy_bi in the" - " first parameter") + raise NotImplementedError("cannot differentiate airy_bi in the" " first parameter") return airy_bi_general(alpha + 1, x) def _eval_(self, alpha, x): @@ -562,14 +548,13 @@ def _eval_(self, alpha, x): sage: airy_bi_general(n, 1.0) # needs sage.symbolic airy_bi(n, 1.00000000000000) """ - if not isinstance(x, Expression) and \ - not isinstance(alpha, Expression): + if not isinstance(x, Expression) and not isinstance(alpha, Expression): if alpha == 0: return airy_bi_simple(x) if alpha == 1: return airy_bi_prime(x) if alpha == 2: - return x*airy_bi_simple(x) + return x * airy_bi_simple(x) def _evalf_(self, alpha, x, **kwargs): """ @@ -582,8 +567,8 @@ def _evalf_(self, alpha, x, **kwargs): parent = kwargs.get('parent') import mpmath from sage.libs.mpmath import utils as mpmath_utils - return _mpmath_utils_call(_mpmath_airybi, x, derivative=alpha, - parent=parent) + + return _mpmath_utils_call(_mpmath_airybi, x, derivative=alpha, parent=parent) class FunctionAiryBiSimple(BuiltinFunction): @@ -599,13 +584,7 @@ def __init__(self): sage: f._sympy_() # needs sympy sage.symbolic airybi(x) """ - BuiltinFunction.__init__(self, 'airy_bi', - latex_name=r"\operatorname{Bi}", - conversions=dict(mathematica='AiryBi', - maxima='airy_bi', - sympy='airybi', - fricas='airyBi', - giac='Airy_Bi')) + BuiltinFunction.__init__(self, 'airy_bi', latex_name=r"\operatorname{Bi}", conversions=dict(mathematica='AiryBi', maxima='airy_bi', sympy='airybi', fricas='airyBi', giac='Airy_Bi')) def _derivative_(self, x, diff_param=None): """ @@ -634,6 +613,7 @@ def _eval_(self, x): 0.648858208330395 + 0.344958634768048*I """ from .gamma import gamma + if x == 0: one_sixth = ZZ(1) / 6 return 1 / (3 ** (one_sixth) * gamma(4 * one_sixth)) @@ -678,6 +658,7 @@ def _evalf_(self, x, **kwargs): from sage.rings.cc import CC from sage.functions.other import real, imag from scipy.special import airy + if x in RR: y = airy(real(x))[2] if parent is None: @@ -690,6 +671,7 @@ def _evalf_(self, x, **kwargs): if algorithm == 'mpmath': import mpmath from sage.libs.mpmath import utils as mpmath_utils + return _mpmath_utils_call(_mpmath_airybi, x, parent=parent) raise ValueError("unknown algorithm '%s'" % algorithm) @@ -711,12 +693,7 @@ def __init__(self): sage: airy_bi_prime(x)._sympy_() # needs sympy airybiprime(x) """ - BuiltinFunction.__init__(self, 'airy_bi_prime', - latex_name=r"\operatorname{Bi}'", - conversions=dict(mathematica='AiryBiPrime', - maxima='airy_dbi', - sympy='airybiprime', - fricas='airyBiPrime')) + BuiltinFunction.__init__(self, 'airy_bi_prime', latex_name=r"\operatorname{Bi}'", conversions=dict(mathematica='AiryBiPrime', maxima='airy_dbi', sympy='airybiprime', fricas='airyBiPrime')) def _derivative_(self, x, diff_param=None): """ @@ -737,6 +714,7 @@ def _eval_(self, x): 0.448288357353826 """ from .gamma import gamma + if x == 0: one_sixth = ZZ(1) / 6 return 3 ** (one_sixth) / gamma(2 * one_sixth) @@ -779,6 +757,7 @@ def _evalf_(self, x, **kwargs): from sage.rings.cc import CC from sage.functions.other import real, imag from scipy.special import airy + if x in RR: y = airy(real(x))[3] if parent is None: @@ -789,8 +768,7 @@ def _evalf_(self, x, **kwargs): return CC(y) return parent(y) if algorithm == 'mpmath': - return _mpmath_utils_call(_mpmath_airybi, x, derivative=1, - parent=parent) + return _mpmath_utils_call(_mpmath_airybi, x, derivative=1, parent=parent) raise ValueError("unknown algorithm '%s'" % algorithm) diff --git a/src/sage/functions/all.py b/src/sage/functions/all.py index 4e4c092bc0f..a9f48b6cf45 100644 --- a/src/sage/functions/all.py +++ b/src/sage/functions/all.py @@ -1,94 +1,46 @@ - from sage.misc.lazy_import import lazy_import lazy_import('sage.functions.piecewise', 'piecewise') -lazy_import('sage.functions.error', ['erf', 'erfc', 'erfi', 'erfinv', - 'fresnel_sin', 'fresnel_cos']) - -from sage.functions.trig import (sin, cos, sec, csc, cot, tan, - asin, acos, atan, - acot, acsc, asec, - arcsin, arccos, arctan, - arccot, arccsc, arcsec, - arctan2, atan2) - -from sage.functions.hyperbolic import (tanh, sinh, cosh, coth, sech, csch, - asinh, acosh, atanh, acoth, asech, acsch, - arcsinh, arccosh, arctanh, arccoth, arcsech, arccsch) - -reciprocal_trig_functions = {'sec': cos, 'csc': sin, - 'cot': tan, 'sech': cosh, 'csch': sinh, 'coth': tanh} - - -from sage.functions.other import (ceil, floor, abs_symbolic, sqrt, real_nth_root, - arg, real_part, real, frac, - factorial, binomial, - imag_part, imag, imaginary, conjugate, cases, - complex_root_of) - -from sage.functions.log import (exp, exp_polar, log, ln, - polylog, dilog, lambert_w, harmonic_number) - -from sage.functions.transcendental import (zeta, zetaderiv, zeta_symmetric, hurwitz_zeta, - dickman_rho, stieltjes) - -from sage.functions.bessel import (bessel_I, bessel_J, bessel_K, bessel_Y, - Bessel, struve_H, struve_L, hankel1, hankel2, - spherical_bessel_J, spherical_bessel_Y, - spherical_hankel1, spherical_hankel2) - -from sage.functions.special import (spherical_harmonic, elliptic_e, - elliptic_f, elliptic_ec, elliptic_eu, - elliptic_kc, elliptic_pi, elliptic_j) - -from sage.functions.jacobi import (jacobi, inverse_jacobi, jacobi_nd, jacobi_ns, jacobi_nc, - jacobi_dn, jacobi_ds, jacobi_dc, jacobi_sn, jacobi_sd, - jacobi_sc, jacobi_cn, jacobi_cd, jacobi_cs, jacobi_am, - inverse_jacobi_nd, inverse_jacobi_ns, inverse_jacobi_nc, - inverse_jacobi_dn, inverse_jacobi_ds, inverse_jacobi_dc, - inverse_jacobi_sn, inverse_jacobi_sd, inverse_jacobi_sc, - inverse_jacobi_cn, inverse_jacobi_cd, inverse_jacobi_cs) - -from sage.functions.orthogonal_polys import (chebyshev_T, - chebyshev_U, - gen_laguerre, - gen_legendre_P, - gen_legendre_Q, - hermite, - jacobi_P, - laguerre, - legendre_P, - legendre_Q, - ultraspherical, - gegenbauer, - krawtchouk, - meixner, - hahn) +lazy_import('sage.functions.error', ['erf', 'erfc', 'erfi', 'erfinv', 'fresnel_sin', 'fresnel_cos']) + +from sage.functions.trig import sin, cos, sec, csc, cot, tan, asin, acos, atan, acot, acsc, asec, arcsin, arccos, arctan, arccot, arccsc, arcsec, arctan2, atan2 + +from sage.functions.hyperbolic import tanh, sinh, cosh, coth, sech, csch, asinh, acosh, atanh, acoth, asech, acsch, arcsinh, arccosh, arctanh, arccoth, arcsech, arccsch + +reciprocal_trig_functions = {'sec': cos, 'csc': sin, 'cot': tan, 'sech': cosh, 'csch': sinh, 'coth': tanh} + + +from sage.functions.other import ceil, floor, abs_symbolic, sqrt, real_nth_root, arg, real_part, real, frac, factorial, binomial, imag_part, imag, imaginary, conjugate, cases, complex_root_of + +from sage.functions.log import exp, exp_polar, log, ln, polylog, dilog, lambert_w, harmonic_number + +from sage.functions.transcendental import zeta, zetaderiv, zeta_symmetric, hurwitz_zeta, dickman_rho, stieltjes + +from sage.functions.bessel import bessel_I, bessel_J, bessel_K, bessel_Y, Bessel, struve_H, struve_L, hankel1, hankel2, spherical_bessel_J, spherical_bessel_Y, spherical_hankel1, spherical_hankel2 + +from sage.functions.special import spherical_harmonic, elliptic_e, elliptic_f, elliptic_ec, elliptic_eu, elliptic_kc, elliptic_pi, elliptic_j + +from sage.functions.jacobi import jacobi, inverse_jacobi, jacobi_nd, jacobi_ns, jacobi_nc, jacobi_dn, jacobi_ds, jacobi_dc, jacobi_sn, jacobi_sd, jacobi_sc, jacobi_cn, jacobi_cd, jacobi_cs, jacobi_am, inverse_jacobi_nd, inverse_jacobi_ns, inverse_jacobi_nc, inverse_jacobi_dn, inverse_jacobi_ds, inverse_jacobi_dc, inverse_jacobi_sn, inverse_jacobi_sd, inverse_jacobi_sc, inverse_jacobi_cn, inverse_jacobi_cd, inverse_jacobi_cs + +from sage.functions.orthogonal_polys import chebyshev_T, chebyshev_U, gen_laguerre, gen_legendre_P, gen_legendre_Q, hermite, jacobi_P, laguerre, legendre_P, legendre_Q, ultraspherical, gegenbauer, krawtchouk, meixner, hahn from sage.functions.spike_function import spike_function from sage.functions.prime_pi import legendre_phi, partial_sieve_function, prime_pi -from sage.functions.wigner import (wigner_3j, clebsch_gordan, racah, wigner_6j, - wigner_9j, gaunt) +from sage.functions.wigner import wigner_3j, clebsch_gordan, racah, wigner_6j, wigner_9j, gaunt -from sage.functions.generalized import (dirac_delta, heaviside, unit_step, sgn, sign, - kronecker_delta) +from sage.functions.generalized import dirac_delta, heaviside, unit_step, sgn, sign, kronecker_delta from sage.functions.min_max import max_symbolic, min_symbolic from sage.functions.airy import airy_ai, airy_ai_prime, airy_bi, airy_bi_prime -from sage.functions.exp_integral import (exp_integral_e, exp_integral_e1, log_integral, li, Li, - log_integral_offset, - sin_integral, cos_integral, Si, Ci, - sinh_integral, cosh_integral, Shi, Chi, - exponential_integral_1, Ei, exp_integral_ei) +from sage.functions.exp_integral import exp_integral_e, exp_integral_e1, log_integral, li, Li, log_integral_offset, sin_integral, cos_integral, Si, Ci, sinh_integral, cosh_integral, Shi, Chi, exponential_integral_1, Ei, exp_integral_ei from sage.functions.hypergeometric import hypergeometric, hypergeometric_M, hypergeometric_U -from sage.functions.gamma import (gamma, psi, beta, log_gamma, - gamma_inc, gamma_inc_lower) +from sage.functions.gamma import gamma, psi, beta, log_gamma, gamma_inc, gamma_inc_lower Γ = gamma ψ = psi diff --git a/src/sage/functions/bessel.py b/src/sage/functions/bessel.py index b1ad8028bde..977e4fe5bb2 100644 --- a/src/sage/functions/bessel.py +++ b/src/sage/functions/bessel.py @@ -197,6 +197,7 @@ - [WP-Struve]_ """ + # **************************************************************************** # Copyright (C) 2013 Benjamin Jones # @@ -231,13 +232,7 @@ lazy_import('sage.symbolic.ring', 'SR') lazy_import('sage.libs.mpmath.utils', 'call', as_='_mpmath_utils_call') -lazy_import('mpmath', - ['besseli', 'besselj', 'besselk', - 'bessely', 'hankel1', 'hankel2', - 'struveh', 'struvel'], - as_=['_mpmath_besseli', '_mpmath_besselj', '_mpmath_besselk', - '_mpmath_bessely', '_mpmath_hankel1', '_mpmath_hankel2', - '_mpmath_struveh', '_mpmath_struvel']) +lazy_import('mpmath', ['besseli', 'besselj', 'besselk', 'bessely', 'hankel1', 'hankel2', 'struveh', 'struvel'], as_=['_mpmath_besseli', '_mpmath_besselj', '_mpmath_besselk', '_mpmath_bessely', '_mpmath_hankel1', '_mpmath_hankel2', '_mpmath_struveh', '_mpmath_struvel']) class Function_Bessel_J(BuiltinFunction): @@ -334,6 +329,7 @@ class Function_Bessel_J(BuiltinFunction): - [AS-Bessel]_ """ + def __init__(self): """ See the docstring for :meth:`Function_Bessel_J`. @@ -345,13 +341,7 @@ def __init__(self): sage: bessel_J(x, x)._sympy_() # needs sympy sage.symbolic besselj(x, x) """ - BuiltinFunction.__init__(self, 'bessel_J', nargs=2, - conversions=dict(maple='BesselJ', - mathematica='BesselJ', - maxima='bessel_j', - sympy='besselj', - fricas='besselJ', - giac='BesselJ')) + BuiltinFunction.__init__(self, 'bessel_J', nargs=2, conversions=dict(maple='BesselJ', mathematica='BesselJ', maxima='bessel_j', sympy='besselj', fricas='besselJ', giac='BesselJ')) def _eval_(self, n, x): """ @@ -556,6 +546,7 @@ class Function_Bessel_Y(BuiltinFunction): - [WP-Bessel]_ """ + def __init__(self): """ See the docstring for :meth:`Function_Bessel_Y`. @@ -567,13 +558,7 @@ def __init__(self): sage: bessel_Y(x, x)._sympy_() # needs sympy sage.symbolic bessely(x, x) """ - BuiltinFunction.__init__(self, 'bessel_Y', nargs=2, - conversions=dict(maple='BesselY', - mathematica='BesselY', - maxima='bessel_y', - sympy='bessely', - fricas='besselY', - giac='BesselY')) + BuiltinFunction.__init__(self, 'bessel_Y', nargs=2, conversions=dict(maple='BesselY', mathematica='BesselY', maxima='bessel_y', sympy='bessely', fricas='besselY', giac='BesselY')) def _eval_(self, n, x): """ @@ -768,6 +753,7 @@ class Function_Bessel_I(BuiltinFunction): - [WP-Bessel]_ """ + def __init__(self): """ See the docstring for :meth:`Function_Bessel_I`. @@ -779,12 +765,7 @@ def __init__(self): sage: bessel_I(x, x)._sympy_() # needs sympy sage.symbolic besseli(x, x) """ - BuiltinFunction.__init__(self, 'bessel_I', nargs=2, - conversions=dict(maple='BesselI', - mathematica='BesselI', - maxima='bessel_i', - sympy='besseli', - fricas='besselI')) + BuiltinFunction.__init__(self, 'bessel_I', nargs=2, conversions=dict(maple='BesselI', mathematica='BesselI', maxima='bessel_i', sympy='besseli', fricas='besselI')) def _eval_(self, n, x): """ @@ -970,6 +951,7 @@ class Function_Bessel_K(BuiltinFunction): - [WP-Bessel]_ """ + def __init__(self): """ See the docstring for :meth:`Function_Bessel_K`. @@ -981,12 +963,7 @@ def __init__(self): sage: bessel_K(x, x)._sympy_() # needs sympy sage.symbolic besselk(x, x) """ - BuiltinFunction.__init__(self, 'bessel_K', nargs=2, - conversions=dict(maple='BesselK', - mathematica='BesselK', - maxima='bessel_k', - sympy='besselk', - fricas='besselK')) + BuiltinFunction.__init__(self, 'bessel_K', nargs=2, conversions=dict(maple='BesselK', mathematica='BesselK', maxima='bessel_k', sympy='besselk', fricas='besselK')) def _eval_(self, n, x): """ @@ -1202,7 +1179,7 @@ def Bessel(*args, **kwds): # Determine the order and type of function from the arguments and keywords. # These are recorded in local variables: _type, _order, _system, _nargs. _type = None - if len(args) == 0: # no order specified + if len(args) == 0: # no order specified _order = None _nargs = 2 elif len(args) == 1: # order is specified @@ -1260,6 +1237,7 @@ class Function_Struve_H(BuiltinFunction): - [WP-Struve]_ """ + def __init__(self): r""" EXAMPLES:: @@ -1273,12 +1251,7 @@ def __init__(self): sage: loads(dumps(struve_H(n,x))) struve_H(n, x) """ - BuiltinFunction.__init__(self, 'struve_H', nargs=2, - conversions=dict(maple='StruveH', - mathematica='StruveH', - maxima='struve_h', - fricas='struveH', - sympy='struveh')) + BuiltinFunction.__init__(self, 'struve_H', nargs=2, conversions=dict(maple='StruveH', mathematica='StruveH', maxima='struve_h', fricas='struveH', sympy='struveh')) def _eval_(self, a, z): """ @@ -1300,9 +1273,7 @@ def _eval_(self, a, z): sage: struve_H(-3/2, x) -bessel_J(3/2, x) """ - if z.is_zero() \ - and (SR(a).is_numeric() or SR(a).is_constant()) \ - and a.real() >= -1: + if z.is_zero() and (SR(a).is_numeric() or SR(a).is_constant()) and a.real() >= -1: return ZZ.zero() if a == QQ((-1, 2)): return sqrt(2 / (pi * z)) * sin(z) @@ -1310,7 +1281,7 @@ def _eval_(self, a, z): return sqrt(2 / (pi * z)) * (1 - cos(z)) if a < 0 and not SR(a).is_integer() and SR(2 * a).is_integer(): n = (a * (-2) - 1) / 2 - return Integer(-1)**n * bessel_J(n + QQ((1, 2)), z) + return Integer(-1) ** n * bessel_J(n + QQ((1, 2)), z) def _evalf_(self, a, z, parent=None, algorithm=None): """ @@ -1335,6 +1306,7 @@ def _derivative_(self, a, z, diff_param=None): raise ValueError("cannot differentiate struve_H in the first parameter") from .other import sqrt + return (z**a / (sqrt(pi) * 2**a * gamma(a + Integer(3) / Integer(2))) - struve_H(a + 1, z) + struve_H(a - 1, z)) / 2 def _print_latex_(self, a, z): @@ -1375,6 +1347,7 @@ class Function_Struve_L(BuiltinFunction): - [WP-Struve]_ """ + def __init__(self): r""" EXAMPLES:: @@ -1388,12 +1361,7 @@ def __init__(self): sage: loads(dumps(struve_L(n, x))) struve_L(n, x) """ - BuiltinFunction.__init__(self, 'struve_L', nargs=2, - conversions=dict(maple='StruveL', - mathematica='StruveL', - maxima='struve_l', - fricas='struveL', - sympy='struvel')) + BuiltinFunction.__init__(self, 'struve_L', nargs=2, conversions=dict(maple='StruveL', mathematica='StruveL', maxima='struve_l', fricas='struveL', sympy='struvel')) def _eval_(self, a, z): """ @@ -1415,9 +1383,7 @@ def _eval_(self, a, z): sage: struve_L(-3/2, x) -bessel_I(3/2, x) """ - if z.is_zero() \ - and (SR(a).is_numeric() or SR(a).is_constant()) \ - and a.real() >= -1: + if z.is_zero() and (SR(a).is_numeric() or SR(a).is_constant()) and a.real() >= -1: return ZZ.zero() if a == -Integer(1) / 2: return sqrt(2 / (pi * z)) * sinh(z) @@ -1425,7 +1391,7 @@ def _eval_(self, a, z): return sqrt(2 / (pi * z)) * (cosh(z) - 1) if a < 0 and not SR(a).is_integer() and SR(2 * a).is_integer(): n = (a * (-2) - 1) / 2 - return Integer(-1)**n * bessel_I(n + QQ((1, 2)), z) + return Integer(-1) ** n * bessel_I(n + QQ((1, 2)), z) def _evalf_(self, a, z, parent=None, algorithm=None): """ @@ -1449,6 +1415,7 @@ def _derivative_(self, a, z, diff_param=None): raise ValueError("cannot differentiate struve_L in the first parameter") from .other import sqrt + return (z**a / (sqrt(pi) * 2**a * gamma(a + Integer(3) / Integer(2))) - struve_L(a + 1, z) + struve_L(a - 1, z)) / 2 def _print_latex_(self, a, z): @@ -1491,6 +1458,7 @@ class Function_Hankel1(BuiltinFunction): - [AS-Bessel]_ see 9.1.6 """ + def __init__(self): r""" TESTS:: @@ -1498,12 +1466,7 @@ def __init__(self): sage: hankel1(3, x)._sympy_() # needs sympy sage.symbolic hankel1(3, x) """ - BuiltinFunction.__init__(self, 'hankel1', nargs=2, - conversions=dict(maple='HankelH1', - mathematica='HankelH1', - maxima='hankel1', - sympy='hankel1', - fricas='hankelH1')) + BuiltinFunction.__init__(self, 'hankel1', nargs=2, conversions=dict(maple='HankelH1', mathematica='HankelH1', maxima='hankel1', sympy='hankel1', fricas='hankelH1')) def _evalf_(self, nu, z, parent, algorithm=None): r""" @@ -1577,6 +1540,7 @@ class Function_Hankel2(BuiltinFunction): - [AS-Bessel]_ see 9.1.6 """ + def __init__(self): r""" TESTS:: @@ -1584,12 +1548,7 @@ def __init__(self): sage: hankel2(3, x)._sympy_() # needs sympy sage.symbolic hankel2(3, x) """ - BuiltinFunction.__init__(self, 'hankel2', nargs=2, - conversions=dict(maple='HankelH2', - mathematica='HankelH2', - maxima='hankel2', - sympy='hankel2', - fricas='hankelH2')) + BuiltinFunction.__init__(self, 'hankel2', nargs=2, conversions=dict(maple='HankelH2', mathematica='HankelH2', maxima='hankel2', sympy='hankel2', fricas='hankelH2')) def _evalf_(self, nu, z, parent, algorithm=None): r""" @@ -1675,6 +1634,7 @@ class SphericalBesselJ(BuiltinFunction): - [WP-Bessel]_ """ + def __init__(self): r""" TESTS:: @@ -1682,11 +1642,8 @@ def __init__(self): sage: spherical_bessel_J(3, x)._sympy_() # needs sympy sage.symbolic jn(3, x) """ - conversions = dict(mathematica='SphericalBesselJ', - maxima='spherical_bessel_j', - sympy='jn') - BuiltinFunction.__init__(self, 'spherical_bessel_J', nargs=2, - conversions=conversions) + conversions = dict(mathematica='SphericalBesselJ', maxima='spherical_bessel_j', sympy='jn') + BuiltinFunction.__init__(self, 'spherical_bessel_J', nargs=2, conversions=conversions) def _evalf_(self, n, z, parent, algorithm=None): r""" @@ -1697,8 +1654,7 @@ def _evalf_(self, n, z, parent, algorithm=None): sage: spherical_bessel_J(I, I).n() # needs sage.symbolic 0.215520585196889 - 0.282308805801851*I """ - return _mpmath_utils_call(spherical_bessel_f, 'besselj', n, z, - parent=parent) + return _mpmath_utils_call(spherical_bessel_f, 'besselj', n, z, parent=parent) def _latex_(self): r""" @@ -1729,8 +1685,7 @@ def _derivative_(self, n, z, diff_param): if SR(n).is_numeric() and not SR(n).is_integer(): raise NotImplementedError('derivative of spherical function with noninteger index') if diff_param == 1: - return (spherical_bessel_J(n - 1, z) - - ((n + 1) / z) * spherical_bessel_J(n, z)) + return spherical_bessel_J(n - 1, z) - ((n + 1) / z) * spherical_bessel_J(n, z) raise NotImplementedError('derivative with respect to order') @@ -1773,6 +1728,7 @@ class SphericalBesselY(BuiltinFunction): - [WP-Bessel]_ """ + def __init__(self): r""" TESTS:: @@ -1780,11 +1736,8 @@ def __init__(self): sage: spherical_bessel_Y(3, x)._sympy_() # needs sympy sage.symbolic yn(3, x) """ - conversions = dict(mathematica='SphericalBesselY', - maxima='spherical_bessel_y', - sympy='yn') - BuiltinFunction.__init__(self, 'spherical_bessel_Y', nargs=2, - conversions=conversions) + conversions = dict(mathematica='SphericalBesselY', maxima='spherical_bessel_y', sympy='yn') + BuiltinFunction.__init__(self, 'spherical_bessel_Y', nargs=2, conversions=conversions) def _evalf_(self, n, z, parent, algorithm=None): r""" @@ -1795,8 +1748,7 @@ def _evalf_(self, n, z, parent, algorithm=None): sage: spherical_bessel_Y(I, I).n() # needs sage.symbolic -0.174225389805399 + 1.36247234140312*I """ - return _mpmath_utils_call(spherical_bessel_f, 'bessely', n, z, - parent=parent) + return _mpmath_utils_call(spherical_bessel_f, 'bessely', n, z, parent=parent) def _latex_(self): r""" @@ -1828,9 +1780,7 @@ def _derivative_(self, n, z, diff_param): if SR(n).is_numeric() and not SR(n).is_integer(): raise NotImplementedError('derivative of spherical function with noninteger index') if diff_param == 1: - return (-spherical_bessel_Y(n, z) / (2 * z) + - (spherical_bessel_Y(n - 1, z) - - spherical_bessel_Y(n + 1, z)) / 2) + return -spherical_bessel_Y(n, z) / (2 * z) + (spherical_bessel_Y(n - 1, z) - spherical_bessel_Y(n + 1, z)) / 2 raise NotImplementedError('derivative with respect to order') @@ -1871,6 +1821,7 @@ class SphericalHankel1(BuiltinFunction): - [WP-Bessel]_ """ + def __init__(self): r""" TESTS:: @@ -1878,10 +1829,8 @@ def __init__(self): sage: spherical_hankel1 spherical_hankel1 """ - conversions = dict(mathematica='SphericalHankelH1', - maxima='spherical_hankel1') - BuiltinFunction.__init__(self, 'spherical_hankel1', nargs=2, - conversions=conversions) + conversions = dict(mathematica='SphericalHankelH1', maxima='spherical_hankel1') + BuiltinFunction.__init__(self, 'spherical_hankel1', nargs=2, conversions=conversions) def _evalf_(self, n, z, parent, algorithm=None): r""" @@ -1892,8 +1841,7 @@ def _evalf_(self, n, z, parent, algorithm=None): sage: spherical_hankel1(I, I).n() # needs sage.symbolic -1.14695175620623 - 0.456534195607250*I """ - return _mpmath_utils_call(spherical_bessel_f, 'hankel1', n, z, - parent=parent) + return _mpmath_utils_call(spherical_bessel_f, 'hankel1', n, z, parent=parent) def _latex_(self): r""" @@ -1925,9 +1873,7 @@ def _derivative_(self, n, z, diff_param): if SR(n).is_numeric() and not SR(n).is_integer(): raise NotImplementedError('derivative of spherical function with noninteger index') if diff_param == 1: - return (-spherical_hankel1(n, z) / (2 * z) + - (spherical_hankel1(n - 1, z) - - spherical_hankel1(n + 1, z)) / 2) + return -spherical_hankel1(n, z) / (2 * z) + (spherical_hankel1(n - 1, z) - spherical_hankel1(n + 1, z)) / 2 raise NotImplementedError('derivative with respect to order') @@ -1972,6 +1918,7 @@ class SphericalHankel2(BuiltinFunction): - [WP-Bessel]_ """ + def __init__(self): r""" TESTS:: @@ -1979,9 +1926,7 @@ def __init__(self): sage: spherical_hankel2 spherical_hankel2 """ - BuiltinFunction.__init__(self, 'spherical_hankel2', nargs=2, - conversions=dict(mathematica='SphericalHankelH2', - maxima='spherical_hankel2')) + BuiltinFunction.__init__(self, 'spherical_hankel2', nargs=2, conversions=dict(mathematica='SphericalHankelH2', maxima='spherical_hankel2')) def _evalf_(self, n, z, parent, algorithm=None): r""" @@ -1992,8 +1937,7 @@ def _evalf_(self, n, z, parent, algorithm=None): sage: spherical_hankel2(I, I).n() # needs sage.symbolic 1.57799292660001 - 0.108083415996452*I """ - return _mpmath_utils_call(spherical_bessel_f, 'hankel2', n, z, - parent=parent) + return _mpmath_utils_call(spherical_bessel_f, 'hankel2', n, z, parent=parent) def _latex_(self): r""" @@ -2034,9 +1978,7 @@ def _derivative_(self, n, z, diff_param): if SR(n).is_numeric() and not SR(n).is_integer(): raise NotImplementedError('derivative of spherical function with noninteger index') if diff_param == 1: - return (-spherical_hankel2(n, z) / (2 * z) + - (spherical_hankel2(n - 1, z) - - spherical_hankel2(n + 1, z)) / 2) + return -spherical_hankel2(n, z) / (2 * z) + (spherical_hankel2(n - 1, z) - spherical_hankel2(n + 1, z)) / 2 raise NotImplementedError('derivative with respect to order') @@ -2069,6 +2011,7 @@ def spherical_bessel_f(F, n, z): mpc(real='-0.21864196590306359', imag='0.0') """ from mpmath import mp as ctx + prec = ctx.prec try: n = ctx.convert(n) diff --git a/src/sage/functions/error.py b/src/sage/functions/error.py index ab994cad276..e97c4a8b30f 100644 --- a/src/sage/functions/error.py +++ b/src/sage/functions/error.py @@ -196,11 +196,7 @@ def __init__(self): sage: erf(2)._sympy_() # needs sympy sage.symbolic erf(2) """ - BuiltinFunction.__init__(self, "erf", latex_name=r"\operatorname{erf}", - conversions=dict(maxima='erf', - sympy='erf', - fricas='erf', - giac='erf')) + BuiltinFunction.__init__(self, "erf", latex_name=r"\operatorname{erf}", conversions=dict(maxima='erf', sympy='erf', fricas='erf', giac='erf')) def _eval_(self, x): """ @@ -305,7 +301,7 @@ def _derivative_(self, x, diff_param=None): sage: erf(c*x).diff(x)._maxima_init_() # needs sage.symbolic '((%pi)^(-1/2))*(_SAGE_VAR_c)*(exp(((_SAGE_VAR_c)^(2))*((_SAGE_VAR_x)^(2))*(-1)))*(2)' """ - return 2*exp(-x**2)/sqrt(pi) + return 2 * exp(-(x**2)) / sqrt(pi) erf = Function_erf() @@ -321,6 +317,7 @@ class Function_erfi(BuiltinFunction): \operatorname{erfi}(x) = -i \operatorname{erf}(ix). """ + def __init__(self): r""" Initialize ``self``. @@ -332,11 +329,7 @@ def __init__(self): sage: erfi(2)._sympy_() # needs sympy sage.symbolic erfi(2) """ - BuiltinFunction.__init__(self, "erfi", - latex_name=r"\operatorname{erfi}", - conversions=dict(maxima='erfi', - sympy='erfi', - fricas='erfi')) + BuiltinFunction.__init__(self, "erfi", latex_name=r"\operatorname{erfi}", conversions=dict(maxima='erfi', sympy='erfi', fricas='erfi')) def _eval_(self, x): """ @@ -383,7 +376,7 @@ def _derivative_(self, x, diff_param=None): sage: erfi(x).diff(x) # needs sage.symbolic 2*e^(x^2)/sqrt(pi) """ - return 2*exp(x**2)/sqrt(pi) + return 2 * exp(x**2) / sqrt(pi) erfi = Function_erfi() @@ -420,6 +413,7 @@ class Function_erfc(BuiltinFunction): sage: erfc(x)._fricas_() # optional - fricas, needs sage.symbolic - erf(x) + 1 """ + def __init__(self): r""" EXAMPLES:: @@ -429,12 +423,7 @@ def __init__(self): sage: erfc(2)._sympy_() # needs sympy sage.symbolic erfc(2) """ - BuiltinFunction.__init__(self, "erfc", - latex_name=r"\operatorname{erfc}", - conversions=dict(maxima='erfc', - sympy='erfc', - fricas='(x+->1-erf(x))', - giac='erfc')) + BuiltinFunction.__init__(self, "erfc", latex_name=r"\operatorname{erfc}", conversions=dict(maxima='erfc', sympy='erfc', fricas='(x+->1-erf(x))', giac='erfc')) def _eval_(self, x): """ @@ -485,7 +474,7 @@ def _derivative_(self, x, diff_param=None): sage: erfc(x).diff(x) # needs sage.symbolic -2*e^(-x^2)/sqrt(pi) """ - return -2*exp(-x**2)/sqrt(pi) + return -2 * exp(-(x**2)) / sqrt(pi) erfc = Function_erfc() @@ -501,6 +490,7 @@ class Function_erfinv(BuiltinFunction): \operatorname{erfinv}(x) = \operatorname{erf}^{-1}(x). """ + def __init__(self): r""" Initialize ``self``. @@ -526,10 +516,7 @@ def __init__(self): sage: y.n() 1.96303108415826 """ - BuiltinFunction.__init__(self, "erfinv", - latex_name=r"\operatorname{erfinv}", - conversions=dict(sympy='erfinv', - maxima='inverse_erf')) + BuiltinFunction.__init__(self, "erfinv", latex_name=r"\operatorname{erfinv}", conversions=dict(sympy='erfinv', maxima='inverse_erf')) def _eval_(self, x): """ @@ -545,7 +532,7 @@ def _eval_(self, x): if isinstance(x, Expression): if x.is_trivial_zero(): return x - if (x-1).is_trivial_zero(): + if (x - 1).is_trivial_zero(): return unsigned_infinity elif not x: return x @@ -573,7 +560,7 @@ def _derivative_(self, x, diff_param=None): sage: erfinv(x).diff(x) # needs sage.symbolic 1/2*sqrt(pi)*e^(erfinv(x)^2) """ - return sqrt(pi)*exp(erfinv(x)**2)/2 + return sqrt(pi) * exp(erfinv(x) ** 2) / 2 erfinv = Function_erfinv() @@ -616,13 +603,7 @@ def __init__(self): sage: fresnel_sin(x)._sympy_() # needs sympy fresnels(x) """ - BuiltinFunction.__init__(self, "fresnel_sin", nargs=1, - latex_name=r"\operatorname{S}", - conversions=dict(maxima='fresnel_s', - sympy='fresnels', - mathematica='FresnelS', - maple='FresnelS', - fricas='fresnelS')) + BuiltinFunction.__init__(self, "fresnel_sin", nargs=1, latex_name=r"\operatorname{S}", conversions=dict(maxima='fresnel_s', sympy='fresnels', mathematica='FresnelS', maple='FresnelS', fricas='fresnelS')) def _eval_(self, x): r""" @@ -648,9 +629,9 @@ def _eval_(self, x): if x.is_positive_infinity(): return Rational((1, 2)) if x.imag_part().is_positive_infinity(): - return -I*Rational((1, 2)) + return -I * Rational((1, 2)) if x.imag_part().is_negative_infinity(): - return I*Rational((1, 2)) + return I * Rational((1, 2)) elif x < 0: return -fresnel_sin(-x) elif not x: @@ -677,7 +658,7 @@ def _derivative_(self, x, diff_param=None): sage: fresnel_sin(x).diff(x) # needs sage.symbolic sin(1/2*pi*x^2) """ - return sin(pi*x**2/2) + return sin(pi * x**2 / 2) fresnel_sin = Function_Fresnel_sin() @@ -714,13 +695,7 @@ def __init__(self): sage: fresnel_cos(x)._sympy_() # needs sympy fresnelc(x) """ - BuiltinFunction.__init__(self, "fresnel_cos", nargs=1, - latex_name=r"\operatorname{C}", - conversions=dict(maxima='fresnel_c', - sympy='fresnelc', - mathematica='FresnelC', - maple='FresnelC', - fricas='fresnelC')) + BuiltinFunction.__init__(self, "fresnel_cos", nargs=1, latex_name=r"\operatorname{C}", conversions=dict(maxima='fresnel_c', sympy='fresnelc', mathematica='FresnelC', maple='FresnelC', fricas='fresnelC')) def _eval_(self, x): r""" @@ -746,9 +721,9 @@ def _eval_(self, x): if x.is_positive_infinity(): return Rational((1, 2)) if x.imag_part().is_positive_infinity(): - return I*Rational((1, 2)) + return I * Rational((1, 2)) if x.imag_part().is_negative_infinity(): - return -I*Rational((1, 2)) + return -I * Rational((1, 2)) elif x < 0: return -fresnel_cos(-x) elif not x: @@ -775,7 +750,7 @@ def _derivative_(self, x, diff_param=None): sage: fresnel_cos(x).diff(x) # needs sage.symbolic cos(1/2*pi*x^2) """ - return cos(pi*x**2/2) + return cos(pi * x**2 / 2) fresnel_cos = Function_Fresnel_cos() diff --git a/src/sage/functions/exp_integral.py b/src/sage/functions/exp_integral.py index 9d3c6ed5748..293f51b23fc 100644 --- a/src/sage/functions/exp_integral.py +++ b/src/sage/functions/exp_integral.py @@ -63,10 +63,7 @@ lazy_import('sage.symbolic.ring', 'SR') lazy_import('sage.libs.mpmath.utils', 'call', as_='_mpmath_utils_call') -lazy_import('mpmath', - ['chi', 'ci', 'e1', 'ei', 'expint', 'ei', 'li', 'shi', 'si'], - as_=['_mpmath_chi', '_mpmath_ci', '_mpmath_e1', '_mpmath_ei', '_mpmath_expint', - '_mpmath_ei', '_mpmath_li', '_mpmath_shi', '_mpmath_si']) +lazy_import('mpmath', ['chi', 'ci', 'e1', 'ei', 'expint', 'ei', 'li', 'shi', 'si'], as_=['_mpmath_chi', '_mpmath_ci', '_mpmath_e1', '_mpmath_ei', '_mpmath_expint', '_mpmath_ei', '_mpmath_li', '_mpmath_shi', '_mpmath_si']) class Function_exp_integral_e(BuiltinFunction): @@ -149,6 +146,7 @@ class Function_exp_integral_e(BuiltinFunction): Numerical evaluation is handled using mpmath, but symbolics are handled by Sage and Maxima. """ + def __init__(self): """ See the docstring for :meth:`Function_exp_integral_e`. @@ -160,9 +158,7 @@ def __init__(self): sage: exp_integral_e(1, x)._sympy_() # needs sage.symbolic expint(1, x) """ - BuiltinFunction.__init__(self, "exp_integral_e", nargs=2, - conversions=dict(maxima='expintegral_e', - sympy='expint')) + BuiltinFunction.__init__(self, "exp_integral_e", nargs=2, conversions=dict(maxima='expintegral_e', sympy='expint')) def _eval_(self, n, z): """ @@ -188,24 +184,24 @@ def _eval_(self, n, z): if z.is_trivial_zero(): z_zero = True # for later if n > 1: - return 1/(n-1) + return 1 / (n - 1) else: if not z: z_zero = True if n > 1: - return 1/(n-1) + return 1 / (n - 1) # special case: n == 0 if isinstance(n, Expression): if n.is_trivial_zero(): if z_zero: return None - return exp(-z)/z + return exp(-z) / z else: if not n: if z_zero: return None - return exp(-z)/z + return exp(-z) / z return None # leaves the expression unevaluated @@ -251,7 +247,7 @@ def _derivative_(self, n, z, diff_param=None): -1/2*exp_integral_e(1, sqrt(x))/sqrt(x) """ if n in ZZ and n > 0: - return -1*exp_integral_e(n-1, z) + return -1 * exp_integral_e(n - 1, z) raise NotImplementedError("The derivative of this function is only implemented for n = 1, 2, 3, ...") @@ -305,6 +301,7 @@ class Function_exp_integral_e1(BuiltinFunction): Numerical evaluation is handled using mpmath, but symbolics are handled by Sage and Maxima. """ + def __init__(self): """ See the docstring for :class:`Function_exp_integral_e1`. @@ -316,9 +313,7 @@ def __init__(self): sage: exp_integral_e1(x)._sympy_() # needs sympy sage.symbolic expint(1, x) """ - BuiltinFunction.__init__(self, "exp_integral_e1", nargs=1, - conversions=dict(maxima='expintegral_e1', - sympy='E1')) + BuiltinFunction.__init__(self, "exp_integral_e1", nargs=1, conversions=dict(maxima='expintegral_e1', sympy='E1')) def _evalf_(self, z, parent=None, algorithm=None): """ @@ -359,7 +354,7 @@ def _derivative_(self, z, diff_param=None): sage: f.diff(x) -2*e^(-x^2)/x """ - return -exp(-z)/z + return -exp(-z) / z exp_integral_e1 = Function_exp_integral_e1() @@ -417,6 +412,7 @@ class Function_log_integral(BuiltinFunction): .. _`logarithmic-integral`: http://mpmath.org/doc/current/functions/expintegrals.html#logarithmic-integral """ + def __init__(self): r""" See the docstring for ``Function_log_integral``. @@ -437,11 +433,7 @@ def __init__(self): sage: latex(log_integral(x)) # needs sage.symbolic \operatorname{log\_integral}\left(x\right) """ - BuiltinFunction.__init__(self, "log_integral", nargs=1, - latex_name=r'\operatorname{log\_integral}', - conversions=dict(maxima='expintegral_li', - sympy='li', - fricas='li')) + BuiltinFunction.__init__(self, "log_integral", nargs=1, latex_name=r'\operatorname{log\_integral}', conversions=dict(maxima='expintegral_li', sympy='li', fricas='li')) def _eval_(self, z): """ @@ -488,7 +480,7 @@ def _derivative_(self, z, diff_param=None): sage: f.diff(x) 2*x/log(x^2) """ - return 1/log(z) + return 1 / log(z) li = log_integral = Function_log_integral() @@ -630,9 +622,7 @@ def __init__(self): sage: latex(log_integral_offset) \operatorname{log\_integral\_offset} """ - BuiltinFunction.__init__(self, "log_integral_offset", nargs=1, - latex_name=r'\operatorname{log\_integral\_offset}', - conversions=dict(sympy='Li')) + BuiltinFunction.__init__(self, "log_integral_offset", nargs=1, latex_name=r'\operatorname{log\_integral\_offset}', conversions=dict(sympy='Li')) def _eval_(self, z): """ @@ -648,7 +638,7 @@ def _eval_(self, z): """ if z == 2: return SR(0) - return li(z)-li(2) + return li(z) - li(2) # If we return:(li(z)-li(2)) we get correct symbolic integration. # But on definite integration it returns x.xxxx-li(2). @@ -680,7 +670,7 @@ def _derivative_(self, z, diff_param=None): sage: f.diff(x) 2*x/log(x^2) """ - return 1/log(z) + return 1 / log(z) Li = log_integral_offset = Function_log_integral_offset() @@ -785,6 +775,7 @@ class Function_sin_integral(BuiltinFunction): .. _`si`: http://mpmath.org/doc/current/functions/expintegrals.html#si """ + def __init__(self): """ See the docstring for ``Function_sin_integral``. @@ -801,11 +792,7 @@ def __init__(self): sage: sin_integral(x)._giac_() # needs giac Si(sageVARx) """ - BuiltinFunction.__init__(self, "sin_integral", nargs=1, - latex_name=r'\operatorname{Si}', - conversions=dict(maxima='expintegral_si', - sympy='Si', - fricas='Si', giac='Si')) + BuiltinFunction.__init__(self, "sin_integral", nargs=1, latex_name=r'\operatorname{Si}', conversions=dict(maxima='expintegral_si', sympy='Si', fricas='Si', giac='Si')) def _eval_(self, z): """ @@ -871,7 +858,7 @@ def _derivative_(self, z, diff_param=None): sage: f.diff(x) 2*sin(x^2)/x """ - return sin(z)/z + return sin(z) / z Si = sin_integral = Function_sin_integral() @@ -960,6 +947,7 @@ class Function_cos_integral(BuiltinFunction): .. _`ci`: http://mpmath.org/doc/current/functions/expintegrals.html#ci """ + def __init__(self): """ See the docstring for :class:`Function_cos_integral`. @@ -976,11 +964,7 @@ def __init__(self): sage: cos_integral(x)._giac_() # needs giac Ci(sageVARx) """ - BuiltinFunction.__init__(self, "cos_integral", nargs=1, - latex_name=r'\operatorname{Ci}', - conversions=dict(maxima='expintegral_ci', - sympy='Ci', - fricas='Ci', giac='Ci')) + BuiltinFunction.__init__(self, "cos_integral", nargs=1, latex_name=r'\operatorname{Ci}', conversions=dict(maxima='expintegral_ci', sympy='Ci', fricas='Ci', giac='Ci')) def _evalf_(self, z, parent=None, algorithm=None): """ @@ -1010,7 +994,7 @@ def _derivative_(self, z, diff_param=None): sage: f.diff(x) 2*cos(x^2)/x """ - return cos(z)/z + return cos(z) / z Ci = cos_integral = Function_cos_integral() @@ -1095,6 +1079,7 @@ class Function_sinh_integral(BuiltinFunction): .. _`shi`: http://mpmath.org/doc/current/functions/expintegrals.html#shi """ + def __init__(self): """ See the docstring for ``Function_sinh_integral``. @@ -1106,11 +1091,7 @@ def __init__(self): sage: sinh_integral(x)._sympy_() # needs sympy sage.symbolic Shi(x) """ - BuiltinFunction.__init__(self, "sinh_integral", nargs=1, - latex_name=r'\operatorname{Shi}', - conversions=dict(maxima='expintegral_shi', - sympy='Shi', - fricas='Shi')) + BuiltinFunction.__init__(self, "sinh_integral", nargs=1, latex_name=r'\operatorname{Shi}', conversions=dict(maxima='expintegral_shi', sympy='Shi', fricas='Shi')) def _eval_(self, z): """ @@ -1157,7 +1138,7 @@ def _derivative_(self, z, diff_param=None): sage: f.diff(x) 1/2*(x^2 - 1)/(x^2*log(x)) """ - return sinh(z)/z + return sinh(z) / z Shi = sinh_integral = Function_sinh_integral() @@ -1238,6 +1219,7 @@ class Function_cosh_integral(BuiltinFunction): .. _`chi`: http://mpmath.org/doc/current/functions/expintegrals.html#chi """ + def __init__(self): """ See the docstring for ``Function_cosh_integral``. @@ -1249,11 +1231,7 @@ def __init__(self): sage: cosh_integral(x)._sympy_() # needs sage.symbolic Chi(x) """ - BuiltinFunction.__init__(self, "cosh_integral", nargs=1, - latex_name=r'\operatorname{Chi}', - conversions=dict(maxima='expintegral_chi', - sympy='Chi', - fricas='Chi')) + BuiltinFunction.__init__(self, "cosh_integral", nargs=1, latex_name=r'\operatorname{Chi}', conversions=dict(maxima='expintegral_chi', sympy='Chi', fricas='Chi')) def _evalf_(self, z, parent=None, algorithm=None): """ @@ -1281,7 +1259,7 @@ def _derivative_(self, z, diff_param=None): sage: f.diff(x) 1/2*(x^2 + 1)/(x^2*log(x)) """ - return cosh(z)/z + return cosh(z) / z Chi = cosh_integral = Function_cosh_integral() @@ -1292,6 +1270,7 @@ def _derivative_(self, z, diff_param=None): # This occurred as part of Issue #11143. ################################################################### + # This class has a name which is not specific enough # see Function_exp_integral_e above, for example, which # is the "generalized" exponential integral function. We @@ -1355,6 +1334,7 @@ class Function_exp_integral(BuiltinFunction): sage: (Ei(-Z)).limit(Z=1000).n() -5.07089306023517e-438 """ + def __init__(self): """ TESTS:: @@ -1364,10 +1344,7 @@ def __init__(self): sage: Ei(x)._sympy_() # needs sympy sage.symbolic Ei(x) """ - BuiltinFunction.__init__(self, "Ei", - conversions=dict(maxima='expintegral_ei', - sympy='Ei', - fricas='Ei')) + BuiltinFunction.__init__(self, "Ei", conversions=dict(maxima='expintegral_ei', sympy='Ei', fricas='Ei')) def _evalf_(self, x, parent=None, algorithm=None): """ @@ -1400,7 +1377,7 @@ def _derivative_(self, x, diff_param=None): sage: Ei(f(x)).diff(x) e^f(x)*diff(f(x), x)/f(x) """ - return exp(x)/x + return exp(x) / x Ei = exp_integral_ei = Function_exp_integral() @@ -1496,8 +1473,7 @@ def exponential_integral_1(x, n=0): if isinstance(x, Expression): if x.is_trivial_zero(): return Infinity - raise NotImplementedError("Use the symbolic exponential integral " + - "function: exp_integral_e1.") + raise NotImplementedError("Use the symbolic exponential integral " + "function: exp_integral_e1.") # x == 0 => return Infinity if not x: diff --git a/src/sage/functions/gamma.py b/src/sage/functions/gamma.py index 5af3b727911..4fbaf650a66 100644 --- a/src/sage/functions/gamma.py +++ b/src/sage/functions/gamma.py @@ -1,6 +1,7 @@ """ Gamma and related functions """ + from sage.misc.lazy_import import lazy_import from sage.rings.infinity import Infinity from sage.rings.rational import Rational @@ -175,13 +176,7 @@ def __init__(self): :meth:`gamma` """ - GinacFunction.__init__(self, 'gamma', latex_name=r"\Gamma", - ginac_name='gamma', - conversions={'mathematica':'Gamma', - 'maple':'GAMMA', - 'sympy':'gamma', - 'fricas':'Gamma', - 'giac':'Gamma'}) + GinacFunction.__init__(self, 'gamma', latex_name=r"\Gamma", ginac_name='gamma', conversions={'mathematica': 'Gamma', 'maple': 'GAMMA', 'sympy': 'gamma', 'fricas': 'Gamma', 'giac': 'Gamma'}) gamma1 = Function_gamma() @@ -294,11 +289,7 @@ def __init__(self): sage: conjugate(log_gamma(-2)) +Infinity """ - GinacFunction.__init__(self, "log_gamma", latex_name=r'\log\Gamma', - conversions=dict(mathematica='LogGamma', - maxima='log_gamma', - sympy='loggamma', - fricas='logGamma')) + GinacFunction.__init__(self, "log_gamma", latex_name=r'\log\Gamma', conversions=dict(mathematica='LogGamma', maxima='log_gamma', sympy='loggamma', fricas='logGamma')) log_gamma = Function_log_gamma() @@ -366,10 +357,7 @@ def __init__(self): :meth:`gamma` """ - BuiltinFunction.__init__(self, "gamma", nargs=2, latex_name=r"\Gamma", - conversions={'maxima':'gamma_incomplete', 'mathematica':'Gamma', - 'maple':'GAMMA', 'sympy':'uppergamma', 'fricas':'Gamma', - 'giac':'ugamma'}) + BuiltinFunction.__init__(self, "gamma", nargs=2, latex_name=r"\Gamma", conversions={'maxima': 'gamma_incomplete', 'mathematica': 'Gamma', 'maple': 'GAMMA', 'sympy': 'uppergamma', 'fricas': 'Gamma', 'giac': 'ugamma'}) def _method_arguments(self, x, y): r""" @@ -537,9 +525,7 @@ def __init__(self): :class:`Function_gamma_inc` """ - BuiltinFunction.__init__(self, "gamma_inc_lower", nargs=2, latex_name=r"\gamma", - conversions={'maxima':'gamma_incomplete_lower', - 'maple':'GAMMA', 'sympy':'lowergamma', 'giac':'igamma'}) + BuiltinFunction.__init__(self, "gamma_inc_lower", nargs=2, latex_name=r"\gamma", conversions={'maxima': 'gamma_incomplete_lower', 'maple': 'GAMMA', 'sympy': 'lowergamma', 'giac': 'igamma'}) def _eval_(self, x, y): """ @@ -626,10 +612,9 @@ def _derivative_(self, x, y, diff_param=None): NotImplementedError: cannot differentiate gamma_inc_lower in the first parameter """ if diff_param == 0: - raise NotImplementedError("cannot differentiate gamma_inc_lower in the" - " first parameter") + raise NotImplementedError("cannot differentiate gamma_inc_lower in the" " first parameter") else: - return exp(-y) * y**(x - 1) + return exp(-y) * y ** (x - 1) def _mathematica_init_evaled_(self, *args): r""" @@ -803,12 +788,7 @@ def __init__(self): sage: psi(x)._fricas_() # optional - fricas digamma(x) """ - GinacFunction.__init__(self, "psi", nargs=1, latex_name=r'\psi', - conversions=dict(mathematica='PolyGamma', - maxima='psi[0]', - maple='Psi', - sympy='digamma', - fricas='digamma')) + GinacFunction.__init__(self, "psi", nargs=1, latex_name=r'\psi', conversions=dict(mathematica='PolyGamma', maxima='psi[0]', maple='Psi', sympy='digamma', fricas='digamma')) class Function_psi2(GinacFunction): @@ -866,12 +846,7 @@ def __init__(self): sage: psi(2, x)._maple_init_() # needs sage.symbolic 'Psi(2,x)' """ - GinacFunction.__init__(self, "psi", nargs=2, latex_name=r'\psi', - conversions=dict(mathematica='PolyGamma', - sympy='polygamma', - maple='Psi', - giac='Psi', - fricas='polygamma')) + GinacFunction.__init__(self, "psi", nargs=2, latex_name=r'\psi', conversions=dict(mathematica='PolyGamma', sympy='polygamma', maple='Psi', giac='Psi', fricas='polygamma')) def _maxima_init_evaled_(self, *args): """ @@ -1062,14 +1037,7 @@ def __init__(self): sage: beta(-1.3, -0.4) # needs sage.symbolic -4.92909641669610 """ - GinacFunction.__init__(self, 'beta', nargs=2, - latex_name=r"\operatorname{B}", - conversions=dict(maxima='beta', - mathematica='Beta', - maple='Beta', - sympy='beta', - fricas='Beta', - giac='Beta')) + GinacFunction.__init__(self, 'beta', nargs=2, latex_name=r"\operatorname{B}", conversions=dict(maxima='beta', mathematica='Beta', maple='Beta', sympy='beta', fricas='Beta', giac='Beta')) def _method_arguments(self, x, y): r""" diff --git a/src/sage/functions/generalized.py b/src/sage/functions/generalized.py index c6caaa725cb..dd30ae89faa 100644 --- a/src/sage/functions/generalized.py +++ b/src/sage/functions/generalized.py @@ -93,6 +93,7 @@ class FunctionDiracDelta(BuiltinFunction): - :wikipedia:`Dirac_delta_function` """ + def __init__(self): r""" The Dirac delta (generalized) function, ``dirac_delta(x)``. @@ -118,11 +119,7 @@ def __init__(self): sage: dirac_delta(x)._sympy_() # needs sympy sage.symbolic DiracDelta(x) """ - BuiltinFunction.__init__(self, "dirac_delta", latex_name=r"\delta", - conversions=dict(maxima='delta', - mathematica='DiracDelta', - sympy='DiracDelta', - giac='Dirac')) + BuiltinFunction.__init__(self, "dirac_delta", latex_name=r"\delta", conversions=dict(maxima='delta', mathematica='DiracDelta', sympy='DiracDelta', giac='Dirac')) def _eval_(self, x): """ @@ -149,7 +146,7 @@ def _eval_(self, x): """ try: return self._evalf_(x) - except (TypeError, ValueError): # x is symbolic + except (TypeError, ValueError): # x is symbolic pass return None @@ -162,7 +159,7 @@ def _evalf_(self, x, **kwds): 0.000000000000000 """ approx_x = ComplexIntervalField()(x) - if bool(approx_x.imag() == 0): # x is real + if bool(approx_x.imag() == 0): # x is real if bool(approx_x.real() == 0): # x is zero return None return 0 @@ -229,6 +226,7 @@ class FunctionHeaviside(GinacFunction): - :wikipedia:`Heaviside_function` """ + def __init__(self): r""" The Heaviside step function, ``heaviside(x)``. @@ -258,11 +256,7 @@ def __init__(self): sage: h(pi).numerical_approx() 1.00000000000000 """ - GinacFunction.__init__(self, "heaviside", latex_name='H', - conversions=dict(maxima='hstep', - mathematica='HeavisideTheta', - sympy='Heaviside', - giac='Heaviside')) + GinacFunction.__init__(self, "heaviside", latex_name='H', conversions=dict(maxima='hstep', mathematica='HeavisideTheta', sympy='Heaviside', giac='Heaviside')) def _derivative_(self, x, diff_param=None): """ @@ -320,6 +314,7 @@ class FunctionUnitStep(GinacFunction): sage: h(pi).numerical_approx() 1.00000000000000 """ + def __init__(self): r""" The unit step function, ``unit_step(x)``. @@ -349,8 +344,7 @@ def __init__(self): sage: t.subs(x=0) # needs sage.symbolic 2 """ - GinacFunction.__init__(self, "unit_step", latex_name=r"\mathrm{u}", - conversions=dict(mathematica='UnitStep')) + GinacFunction.__init__(self, "unit_step", latex_name=r"\mathrm{u}", conversions=dict(mathematica='UnitStep')) def _derivative_(self, x, diff_param=None): """ @@ -424,6 +418,7 @@ class FunctionSignum(BuiltinFunction): - :wikipedia:`Sign_function` """ + def __init__(self): r""" The sgn function, ``sgn(x)``. @@ -441,11 +436,7 @@ def __init__(self): sage: sgn(x)._sympy_() # needs sympy sage.symbolic sign(x) """ - BuiltinFunction.__init__(self, "sgn", latex_name=r"\mathrm{sgn}", - conversions=dict(maxima='signum', mathematica='Sign', - sympy='sign', giac='sign', - fricas='(x+->abs(x)/x)'), - alt_name='sign') + BuiltinFunction.__init__(self, "sgn", latex_name=r"\mathrm{sgn}", conversions=dict(maxima='signum', mathematica='Sign', sympy='sign', giac='sign', fricas='(x+->abs(x)/x)'), alt_name='sign') def _eval_(self, x): """ @@ -485,7 +476,7 @@ def _eval_(self, x): """ try: return self._evalf_(x) - except (TypeError, ValueError): # x is symbolic + except (TypeError, ValueError): # x is symbolic pass return None @@ -509,11 +500,11 @@ def _evalf_(self, x, **kwds): if hasattr(x, 'sgn'): # or a sgn method return x.sgn() approx_x = ComplexIntervalField()(x) - if bool(approx_x.imag() == 0): # x is real + if bool(approx_x.imag() == 0): # x is real if bool(approx_x.real() == 0): # x is zero return ZZ(0) # Now we have a nonzero real - if bool((approx_x**(0.5)).imag() == 0): # Check: x > 0 + if bool((approx_x ** (0.5)).imag() == 0): # Check: x > 0 return ZZ(1) return ZZ(-1) raise ValueError("Numeric evaluation of symbolic expression") @@ -565,6 +556,7 @@ class FunctionKroneckerDelta(BuiltinFunction): - :wikipedia:`Kronecker_delta` """ + def __init__(self): r""" The Kronecker delta function. @@ -579,10 +571,7 @@ def __init__(self): sage: kronecker_delta(x, y)._sympy_() # needs sympy sage.symbolic KroneckerDelta(x, y) """ - BuiltinFunction.__init__(self, "kronecker_delta", nargs=2, - conversions=dict(maxima='kron_delta', - mathematica='KroneckerDelta', - sympy='KroneckerDelta')) + BuiltinFunction.__init__(self, "kronecker_delta", nargs=2, conversions=dict(maxima='kron_delta', mathematica='KroneckerDelta', sympy='KroneckerDelta')) def _eval_(self, m, n): """ @@ -614,7 +603,7 @@ def _eval_(self, m, n): """ try: return self._evalf_(m, n) - except (TypeError, ValueError): # x is symbolic + except (TypeError, ValueError): # x is symbolic pass return None @@ -630,11 +619,11 @@ def _evalf_(self, m, n, **kwds): return kronecker_delta(n, m) x = m - n approx_x = ComplexIntervalField()(x) - if approx_x.imag() == 0: # x is real + if approx_x.imag() == 0: # x is real if approx_x.real() == 0: # x is zero return 1 return 0 - return 0 # x is complex + return 0 # x is complex def _derivative_(self, *args, **kwds): """ diff --git a/src/sage/functions/hyperbolic.py b/src/sage/functions/hyperbolic.py index 6098a6de0bb..8dec0fc0b8c 100644 --- a/src/sage/functions/hyperbolic.py +++ b/src/sage/functions/hyperbolic.py @@ -289,7 +289,11 @@ def __init__(self): sage: sech(x)._sympy_() # needs sympy sech(x) """ - GinacFunction.__init__(self, "sech", latex_name=r"\operatorname{sech}",) + GinacFunction.__init__( + self, + "sech", + latex_name=r"\operatorname{sech}", + ) def _eval_numpy_(self, x): """ @@ -420,10 +424,7 @@ def __init__(self): sage: asinh(x)._sympy_() # needs sympy sage.symbolic asinh(x) """ - GinacFunction.__init__(self, "arcsinh", - latex_name=r"\operatorname{arsinh}", - conversions=dict(maxima='asinh', sympy='asinh', fricas='asinh', - giac='asinh', mathematica='ArcSinh')) + GinacFunction.__init__(self, "arcsinh", latex_name=r"\operatorname{arsinh}", conversions=dict(maxima='asinh', sympy='asinh', fricas='asinh', giac='asinh', mathematica='ArcSinh')) arcsinh = asinh = Function_arcsinh() @@ -511,10 +512,7 @@ def __init__(self): sage: acosh(x)._sympy_() # needs sympy sage.symbolic acosh(x) """ - GinacFunction.__init__(self, "arccosh", - latex_name=r"\operatorname{arcosh}", - conversions=dict(maxima='acosh', sympy='acosh', fricas='acosh', - giac='acosh', mathematica='ArcCosh')) + GinacFunction.__init__(self, "arccosh", latex_name=r"\operatorname{arcosh}", conversions=dict(maxima='acosh', sympy='acosh', fricas='acosh', giac='acosh', mathematica='ArcCosh')) arccosh = acosh = Function_arccosh() @@ -572,10 +570,7 @@ def __init__(self): sage: atanh(x)._sympy_() # needs sympy sage.symbolic atanh(x) """ - GinacFunction.__init__(self, "arctanh", - latex_name=r"\operatorname{artanh}", - conversions=dict(maxima='atanh', sympy='atanh', fricas='atanh', - giac='atanh', mathematica='ArcTanh')) + GinacFunction.__init__(self, "arctanh", latex_name=r"\operatorname{artanh}", conversions=dict(maxima='atanh', sympy='atanh', fricas='atanh', giac='atanh', mathematica='ArcTanh')) arctanh = atanh = Function_arctanh() @@ -622,11 +617,7 @@ def __init__(self): sage: acoth(float(1.1)) # needs sage.symbolic 1.5222612188617113 """ - GinacFunction.__init__(self, "arccoth", - latex_name=r"\operatorname{arcoth}", - conversions=dict(maxima='acoth', sympy='acoth', - mathematica='ArcCoth', - giac='acoth', fricas='acoth')) + GinacFunction.__init__(self, "arccoth", latex_name=r"\operatorname{arcoth}", conversions=dict(maxima='acoth', sympy='acoth', mathematica='ArcCoth', giac='acoth', fricas='acoth')) def _eval_numpy_(self, x): """ @@ -669,11 +660,7 @@ def __init__(self): sage: asech(x)._sympy_() # needs sympy sage.symbolic asech(x) """ - GinacFunction.__init__(self, "arcsech", - latex_name=r"\operatorname{arsech}", - conversions=dict(maxima='asech', sympy='asech', - mathematica='ArcSech', - fricas='asech')) + GinacFunction.__init__(self, "arcsech", latex_name=r"\operatorname{arsech}", conversions=dict(maxima='asech', sympy='asech', mathematica='ArcSech', fricas='asech')) def _eval_numpy_(self, x): """ @@ -724,11 +711,7 @@ def __init__(self): sage: acsch(x)._sympy_() # needs sympy sage.symbolic acsch(x) """ - GinacFunction.__init__(self, "arccsch", - latex_name=r"\operatorname{arcsch}", - conversions=dict(maxima='acsch', - mathematica='ArcCsch', - sympy='acsch', fricas='acsch')) + GinacFunction.__init__(self, "arccsch", latex_name=r"\operatorname{arcsch}", conversions=dict(maxima='acsch', mathematica='ArcCsch', sympy='acsch', fricas='acsch')) def _eval_numpy_(self, x): """ diff --git a/src/sage/functions/hypergeometric.py b/src/sage/functions/hypergeometric.py index 271163cff8e..ff8931330cc 100644 --- a/src/sage/functions/hypergeometric.py +++ b/src/sage/functions/hypergeometric.py @@ -243,6 +243,7 @@ class Hypergeometric(BuiltinFunction): where `(x)_n` is the rising factorial. """ + def __init__(self): """ Initialize class. @@ -260,13 +261,7 @@ def __init__(self): sage: G.simplify() # optional - maple 0 """ - BuiltinFunction.__init__(self, 'hypergeometric', nargs=3, - conversions={'mathematica': - 'HypergeometricPFQ', - 'maxima': 'hypergeometric', - 'maple': 'hypergeom', - 'sympy': 'hyper', - 'fricas': 'hypergeometricF'}) + BuiltinFunction.__init__(self, 'hypergeometric', nargs=3, conversions={'mathematica': 'HypergeometricPFQ', 'maxima': 'hypergeometric', 'maple': 'hypergeom', 'sympy': 'hyper', 'fricas': 'hypergeometricF'}) def __call__(self, a, b, z, **kwargs): """ @@ -301,10 +296,7 @@ def __call__(self, a, b, z, **kwargs): sage: hypergeometric([2, 3, 4], [4, 1], 1) hypergeometric((2, 3, 4), (4, 1), 1) """ - return BuiltinFunction.__call__(self, - SR._force_pyobject(a), - SR._force_pyobject(b), - z, **kwargs) + return BuiltinFunction.__call__(self, SR._force_pyobject(a), SR._force_pyobject(b), z, **kwargs) def _print_latex_(self, a, b, z): r""" @@ -316,8 +308,7 @@ def _print_latex_(self, a, b, z): aa = ",".join(latex(c) for c in a) bb = ",".join(latex(c) for c in b) z = latex(z) - return (r"\,_{}F_{}\left(\begin{{matrix}} {} \\ {} \end{{matrix}} ; " - r"{} \right)").format(len(a), len(b), aa, bb, z) + return (r"\,_{}F_{}\left(\begin{{matrix}} {} \\ {} \end{{matrix}} ; " r"{} \right)").format(len(a), len(b), aa, bb, z) def _eval_(self, a, b, z, **kwargs): """ @@ -330,7 +321,7 @@ def _eval_(self, a, b, z, **kwargs): raise TypeError("The first two parameters must be of type list") if not isinstance(z, Expression) and z == 0: # Expression is excluded - return Integer(1) # to avoid call to Maxima + return Integer(1) # to avoid call to Maxima def _evalf_try_(self, a, b, z): """ @@ -398,13 +389,9 @@ def _tderivative_(self, a, b, z, *args, **kwargs): """ diff_param = kwargs['diff_param'] if diff_param in hypergeometric(a, b, 1).variables(): # ignore z - raise NotImplementedError("derivative of hypergeometric function " - "with respect to parameters. Try calling" - " .simplify_hypergeometric() first.") - t = (reduce(lambda x, y: x * y, a, 1) * - reduce(lambda x, y: x / y, b, Integer(1))) - return (t * derivative(z, diff_param) * - hypergeometric([c + 1 for c in a], [c + 1 for c in b], z)) + raise NotImplementedError("derivative of hypergeometric function " "with respect to parameters. Try calling" " .simplify_hypergeometric() first.") + t = reduce(lambda x, y: x * y, a, 1) * reduce(lambda x, y: x / y, b, Integer(1)) + return t * derivative(z, diff_param) * hypergeometric([c + 1 for c in a], [c + 1 for c in b], z) class EvaluationMethods: @@ -657,9 +644,9 @@ def terms(self, a, b, z, n=None): while k <= n: yield t for aa in a: - t *= (aa + k - 1) + t *= aa + k - 1 for bb in b: - t /= (bb + k - 1) + t /= bb + k - 1 t *= z if t == 0: break @@ -722,8 +709,8 @@ def _deflated(self, a, b, z): for j, bbb in enumerate(bb): m = aaa - bbb if m in ZZ and m > 0: - aaaa = aa[:i] + aa[i + 1:] - bbbb = bb[:j] + bb[j + 1:] + aaaa = aa[:i] + aa[i + 1 :] + bbbb = bb[:j] + bb[j + 1 :] terms = [] for k in range(m + 1): # TODO: could rewrite prefactors as recurrence @@ -732,10 +719,9 @@ def _deflated(self, a, b, z): term *= rising_factorial(c, k) for c in bbbb: term /= rising_factorial(c, k) - term *= z ** k + term *= z**k term /= rising_factorial(aaa - m, k) - F = hypergeometric([c + k for c in aaaa], - [c + k for c in bbbb], z) + F = hypergeometric([c + k for c in aaaa], [c + k for c in bbbb], z) unique = [] counts = [] for c, f in F._deflated(): @@ -745,8 +731,7 @@ def _deflated(self, a, b, z): unique.append(f) counts.append(c) Fterms = zip(counts, unique) - terms += [(term * termG, G) for (termG, G) in - Fterms] + terms += [(term * termG, G) for (termG, G) in Fterms] return terms return ((1, new),) @@ -836,12 +821,11 @@ def _0f1(b, z): if 2 * b == 3: return F32 if 2 * b > 3: - return ((b - 2) * (b - 1) / z * (_0f1(b - 2, z) - - _0f1(b - 1, z))) + return (b - 2) * (b - 1) / z * (_0f1(b - 2, z) - _0f1(b - 1, z)) if 2 * b < 1: - return (_0f1(b + 1, z) + z / (b * (b + 1)) * - _0f1(b + 2, z)) + return _0f1(b + 1, z) + z / (b * (b + 1)) * _0f1(b + 2, z) raise ValueError + # Can evaluate 0F1 in terms of elementary functions when # the parameter is a half-integer if 2 * b[0] in ZZ and b[0] not in ZZ: @@ -859,18 +843,10 @@ def _0f1(b, z): if n in ZZ and m in ZZ and m > 0 and n > 0: rf = rising_factorial if m <= n: - return (exp(z) * sum(rf(m - n, k) * (-z) ** k / - factorial(k) / rf(m, k) for k in - range(n - m + 1))) - T = sum(rf(n - m + 1, k) * z ** k / - (factorial(k) * rf(2 - m, k)) for k in - range(m - n)) - U = sum(rf(1 - n, k) * (-z) ** k / - (factorial(k) * rf(2 - m, k)) for k in - range(n)) - return (factorial(m - 2) * rf(1 - m, n) * - z ** (1 - m) / factorial(n - 1) * - (T - exp(z) * U)) + return exp(z) * sum(rf(m - n, k) * (-z) ** k / factorial(k) / rf(m, k) for k in range(n - m + 1)) + T = sum(rf(n - m + 1, k) * z**k / (factorial(k) * rf(2 - m, k)) for k in range(m - n)) + U = sum(rf(1 - n, k) * (-z) ** k / (factorial(k) * rf(2 - m, k)) for k in range(n)) + return factorial(m - 2) * rf(1 - m, n) * z ** (1 - m) / factorial(n - 1) * (T - exp(z) * U) if p == 2 and q == 1: R12 = QQ((1, 2)) @@ -893,8 +869,7 @@ def _2f1(a, b, c, z): F1 = _2f1(a, b - 1, c, z) F2 = _2f1(a, b - 2, c, z) q = (b - 1) * (z - 1) - return (((c - 2 * b + 2 + (b - a - 1) * z) * F1 + - (b - c - 1) * F2) / q) + return ((c - 2 * b + 2 + (b - a - 1) * z) * F1 + (b - c - 1) * F2) / q if c > 2: # how to handle this case? if a - c + 1 == 0 or b - c + 1 == 0: @@ -921,17 +896,18 @@ def _2f1(a, b, c, z): if (a, b, c) == (2, 2, 1): return (1 + z) / (1 - z) ** 3 raise NotImplementedError + aa, bb = a - cc, = b + (cc,) = b if z == 1: - return (gamma(cc) * gamma(cc - aa - bb) / gamma(cc - aa) / - gamma(cc - bb)) + return gamma(cc) * gamma(cc - aa - bb) / gamma(cc - aa) / gamma(cc - bb) if all((cf * 2) in ZZ and cf > 0 for cf in (aa, bb, cc)): try: return _2f1(aa, bb, cc, z) except NotImplementedError: pass return hyp + return sum([coeff * _closed_form(pfq) for coeff, pfq in new._deflated()]) @@ -971,6 +947,7 @@ class Hypergeometric_M(BuiltinFunction): sage: hypergeometric_M(1, 1/2, x).simplify_hypergeometric() (-I*sqrt(pi)*x*erf(I*sqrt(-x))*e^x + sqrt(-x))/sqrt(-x) """ + def __init__(self): r""" TESTS:: @@ -980,13 +957,7 @@ def __init__(self): sage: latex(hypergeometric_M(1,1,x)) # needs sage.symbolic M\left(1, 1, x\right) """ - BuiltinFunction.__init__(self, 'hypergeometric_M', nargs=3, - conversions={'mathematica': - 'Hypergeometric1F1', - 'maple': 'KummerM', - 'maxima': 'kummer_m', - 'fricas': 'kummerM'}, - latex_name='M') + BuiltinFunction.__init__(self, 'hypergeometric_M', nargs=3, conversions={'mathematica': 'Hypergeometric1F1', 'maple': 'KummerM', 'maxima': 'kummer_m', 'fricas': 'kummerM'}, latex_name='M') def _eval_(self, a, b, z, **kwargs): """ @@ -1022,8 +993,7 @@ def _derivative_(self, a, b, z, diff_param): """ if diff_param == 2: return (a / b) * hypergeometric_M(a + 1, b + 1, z) - raise NotImplementedError('derivative of hypergeometric function ' - 'with respect to parameters') + raise NotImplementedError('derivative of hypergeometric function ' 'with respect to parameters') class EvaluationMethods: def generalized(self, a, b, z): @@ -1086,6 +1056,7 @@ class Hypergeometric_U(BuiltinFunction): sage: hypergeometric_U(1, 3, x).simplify_hypergeometric() # needs sage.symbolic (x + 1)/x^2 """ + def __init__(self): r""" TESTS:: @@ -1095,13 +1066,7 @@ def __init__(self): sage: latex(hypergeometric_U(1, 1, x)) # needs sage.symbolic U\left(1, 1, x\right) """ - BuiltinFunction.__init__(self, 'hypergeometric_U', nargs=3, - conversions={'mathematica': - 'HypergeometricU', - 'maple': 'KummerU', - 'maxima': 'kummer_u', - 'fricas': 'kummerU'}, - latex_name='U') + BuiltinFunction.__init__(self, 'hypergeometric_U', nargs=3, conversions={'mathematica': 'HypergeometricU', 'maple': 'KummerU', 'maxima': 'kummer_u', 'fricas': 'kummerU'}, latex_name='U') def _eval_(self, a, b, z, **kwargs): return @@ -1128,8 +1093,7 @@ def _derivative_(self, a, b, z, diff_param): """ if diff_param == 2: return -a * hypergeometric_U(a + 1, b + 1, z) - raise NotImplementedError('derivative of hypergeometric function ' - 'with respect to parameters') + raise NotImplementedError('derivative of hypergeometric function ' 'with respect to parameters') class EvaluationMethods: def generalized(self, a, b, z): @@ -1148,7 +1112,7 @@ def generalized(self, a, b, z): sage: hypergeometric_U(3, I, 2).generalized() 1/8*hypergeometric((3, -I + 4), (), -1/2) """ - return z ** (-a) * hypergeometric([a, a - b + 1], [], -z ** (-1)) + return z ** (-a) * hypergeometric([a, a - b + 1], [], -(z ** (-1))) hypergeometric_U = Hypergeometric_U() diff --git a/src/sage/functions/jacobi.py b/src/sage/functions/jacobi.py index 821395352ee..d0e1e375040 100644 --- a/src/sage/functions/jacobi.py +++ b/src/sage/functions/jacobi.py @@ -136,6 +136,7 @@ - Eviatar Bach (2013): complete rewrite, new numerical evaluation, and addition of the Jacobi amplitude function """ + # **************************************************************************** # Copyright (C) 2006 David Joyner # Copyright (C) 2013 Eviatar Bach @@ -145,12 +146,9 @@ # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.functions.hyperbolic import (arctanh, arccosh, arcsinh, arcsech, - arccsch, arccoth, cosh, coth, sech, - csch, tanh, sinh) +from sage.functions.hyperbolic import arctanh, arccosh, arcsinh, arcsech, arccsch, arccoth, cosh, coth, sech, csch, tanh, sinh from sage.functions.special import elliptic_e, elliptic_kc -from sage.functions.trig import (arctan, arcsin, arccos, arccot, arcsec, - arccsc, csc, sec, sin, cos, tan, cot) +from sage.functions.trig import arctan, arcsin, arccos, arccot, arcsec, arccsc, csc, sec, sin, cos, tan, cot from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer from sage.rings.rational_field import QQ @@ -168,6 +166,7 @@ class Jacobi(BuiltinFunction): """ Base class for the Jacobi elliptic functions. """ + def __init__(self, kind): r""" Initialize ``self``. @@ -195,17 +194,10 @@ def __init__(self, kind): sage: fricas(jacobi('dn',x, 2)) jacobiDn(x,2) """ - if kind not in ['nd', 'ns', 'nc', 'dn', 'ds', 'dc', 'sn', 'sd', - 'sc', 'cn', 'cd', 'cs']: - raise ValueError("kind must be one of 'nd', 'ns', 'nc', 'dn', " - "'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") + if kind not in ['nd', 'ns', 'nc', 'dn', 'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs']: + raise ValueError("kind must be one of 'nd', 'ns', 'nc', 'dn', " "'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") self.kind = kind - BuiltinFunction.__init__(self, - name=f'jacobi_{kind}', nargs=2, evalf_params_first=False, - conversions=dict(maple=('Jacobi{}'.format(kind.upper())), - mathematica=('Jacobi{}'.format(kind.upper())), - fricas=('jacobi{}'.format(kind.capitalize())), - maxima=('jacobi_{}'.format(kind)))) + BuiltinFunction.__init__(self, name=f'jacobi_{kind}', nargs=2, evalf_params_first=False, conversions=dict(maple=('Jacobi{}'.format(kind.upper())), mathematica=('Jacobi{}'.format(kind.upper())), fricas=('jacobi{}'.format(kind.capitalize())), maxima=('jacobi_{}'.format(kind)))) def _eval_(self, x, m): r""" @@ -419,87 +411,29 @@ def _derivative_(self, x, m, diff_param): elif diff_param == 1: # From Maxima if self.kind == 'nd': - return (HALF*((x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / - (m - Integer(1)))*jacobi_sn(x, m)*jacobi_cn(x, m) - - jacobi_dn(x, m)*jacobi_sn(x, m)**Integer(2)/(m - Integer(1))) / - jacobi_dn(x, m)**Integer(2)) + return HALF * ((x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_sn(x, m) * jacobi_cn(x, m) - jacobi_dn(x, m) * jacobi_sn(x, m) ** Integer(2) / (m - Integer(1))) / jacobi_dn(x, m) ** Integer(2) if self.kind == 'ns': - return (HALF*(jacobi_sn(x, m)*jacobi_cn(x, m)**Integer(2)/(m - Integer(1)) - - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / - (m - Integer(1)))*jacobi_dn(x, m)*jacobi_cn(x, m)/m) / - jacobi_sn(x, m)**Integer(2)) + return HALF * (jacobi_sn(x, m) * jacobi_cn(x, m) ** Integer(2) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_cn(x, m) / m) / jacobi_sn(x, m) ** Integer(2) if self.kind == 'nc': - return (-HALF*(jacobi_sn(x, m)**Integer(2)*jacobi_cn(x, m)/(m - Integer(1)) - - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / - (m - Integer(1)))*jacobi_dn(x, m) * - jacobi_sn(x, m)/m)/jacobi_cn(x, m)**Integer(2)) + return -HALF * (jacobi_sn(x, m) ** Integer(2) * jacobi_cn(x, m) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_sn(x, m) / m) / jacobi_cn(x, m) ** Integer(2) if self.kind == 'dn': - return (-HALF*(x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / - (m - Integer(1)))*jacobi_sn(x, m)*jacobi_cn(x, m) + - HALF*jacobi_dn(x, m)*jacobi_sn(x, m)**Integer(2)/(m - Integer(1))) + return -HALF * (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_sn(x, m) * jacobi_cn(x, m) + HALF * jacobi_dn(x, m) * jacobi_sn(x, m) ** Integer(2) / (m - Integer(1)) if self.kind == 'ds': - return (HALF*(jacobi_sn(x, m)*jacobi_cn(x, m)**Integer(2)/(m - Integer(1)) - - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / - (m - Integer(1)))*jacobi_dn(x, m)*jacobi_cn(x, m)/m) * - jacobi_dn(x, m)/jacobi_sn(x, m)**Integer(2) - - HALF*((x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / - (m - Integer(1)))*jacobi_sn(x, m)*jacobi_cn(x, m) - - jacobi_dn(x, m)*jacobi_sn(x, m)**Integer(2)/(m - Integer(1))) / - jacobi_sn(x, m)) + return HALF * (jacobi_sn(x, m) * jacobi_cn(x, m) ** Integer(2) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_cn(x, m) / m) * jacobi_dn(x, m) / jacobi_sn(x, m) ** Integer(2) - HALF * ((x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_sn(x, m) * jacobi_cn(x, m) - jacobi_dn(x, m) * jacobi_sn(x, m) ** Integer(2) / (m - Integer(1))) / jacobi_sn(x, m) if self.kind == 'dc': - return (-HALF*(jacobi_sn(x, m)**Integer(2)*jacobi_cn(x, m)/(m - Integer(1)) - - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / - (m - Integer(1)))*jacobi_dn(x, m) * - jacobi_sn(x, m)/m)*jacobi_dn(x, m) / - jacobi_cn(x, m)**Integer(2) - - HALF*((x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / - (m - Integer(1)))*jacobi_sn(x, m)*jacobi_cn(x, m) - - jacobi_dn(x, m)*jacobi_sn(x, m)**Integer(2)/(m - Integer(1))) / - jacobi_cn(x, m)) + return -HALF * (jacobi_sn(x, m) ** Integer(2) * jacobi_cn(x, m) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_sn(x, m) / m) * jacobi_dn(x, m) / jacobi_cn(x, m) ** Integer(2) - HALF * ((x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_sn(x, m) * jacobi_cn(x, m) - jacobi_dn(x, m) * jacobi_sn(x, m) ** Integer(2) / (m - Integer(1))) / jacobi_cn(x, m) if self.kind == 'sn': - return (-HALF*jacobi_sn(x, m)*jacobi_cn(x, m)**Integer(2)/(m - Integer(1)) + - HALF*(x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / - (m - Integer(1)))*jacobi_dn(x, m)*jacobi_cn(x, m)/m) + return -HALF * jacobi_sn(x, m) * jacobi_cn(x, m) ** Integer(2) / (m - Integer(1)) + HALF * (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_cn(x, m) / m if self.kind == 'sd': - return (-HALF*(jacobi_sn(x, m)*jacobi_cn(x, m)**Integer(2)/(m - Integer(1)) - - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / - (m - Integer(1)))*jacobi_dn(x, m)*jacobi_cn(x, m)/m) / - jacobi_dn(x, m) + HALF * - ((x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / - (m - Integer(1)))*jacobi_sn(x, m)*jacobi_cn(x, m) - - jacobi_dn(x, m)*jacobi_sn(x, m)**Integer(2)/(m - Integer(1))) * - jacobi_sn(x, m)/jacobi_dn(x, m)**Integer(2)) + return -HALF * (jacobi_sn(x, m) * jacobi_cn(x, m) ** Integer(2) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_cn(x, m) / m) / jacobi_dn(x, m) + HALF * ((x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_sn(x, m) * jacobi_cn(x, m) - jacobi_dn(x, m) * jacobi_sn(x, m) ** Integer(2) / (m - Integer(1))) * jacobi_sn(x, m) / jacobi_dn(x, m) ** Integer(2) if self.kind == 'sc': - return (-HALF*(jacobi_sn(x, m)*jacobi_cn(x, m)**Integer(2)/(m - Integer(1)) - - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / - (m - Integer(1)))*jacobi_dn(x, m) * - jacobi_cn(x, m)/m)/jacobi_cn(x, m) - - HALF*(jacobi_sn(x, m)**Integer(2)*jacobi_cn(x, m)/(m - Integer(1)) - - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / - (m - Integer(1)))*jacobi_dn(x, m)*jacobi_sn(x, m)/m) * - jacobi_sn(x, m)/jacobi_cn(x, m)**Integer(2)) + return -HALF * (jacobi_sn(x, m) * jacobi_cn(x, m) ** Integer(2) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_cn(x, m) / m) / jacobi_cn(x, m) - HALF * (jacobi_sn(x, m) ** Integer(2) * jacobi_cn(x, m) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_sn(x, m) / m) * jacobi_sn(x, m) / jacobi_cn(x, m) ** Integer(2) if self.kind == 'cn': - return (HALF*jacobi_sn(x, m)**Integer(2)*jacobi_cn(x, m)/(m - Integer(1)) - - HALF*(x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / - (m - Integer(1)))*jacobi_dn(x, m)*jacobi_sn(x, m)/m) + return HALF * jacobi_sn(x, m) ** Integer(2) * jacobi_cn(x, m) / (m - Integer(1)) - HALF * (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_sn(x, m) / m if self.kind == 'cd': - return (HALF*(jacobi_sn(x, m)**Integer(2)*jacobi_cn(x, m)/(m - Integer(1)) - - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / - (m - Integer(1)))*jacobi_dn(x, m)*jacobi_sn(x, m)/m) / - jacobi_dn(x, m) + - HALF*((x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / - (m - Integer(1)))*jacobi_sn(x, m)*jacobi_cn(x, m) - - jacobi_dn(x, m)*jacobi_sn(x, m)**Integer(2)/(m - Integer(1))) * - jacobi_cn(x, m)/jacobi_dn(x, m)**Integer(2)) + return HALF * (jacobi_sn(x, m) ** Integer(2) * jacobi_cn(x, m) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_sn(x, m) / m) / jacobi_dn(x, m) + HALF * ((x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_sn(x, m) * jacobi_cn(x, m) - jacobi_dn(x, m) * jacobi_sn(x, m) ** Integer(2) / (m - Integer(1))) * jacobi_cn(x, m) / jacobi_dn(x, m) ** Integer(2) if self.kind == 'cs': - return (HALF*(jacobi_sn(x, m)*jacobi_cn(x, m)**Integer(2)/(m - Integer(1)) - - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / - (m - Integer(1)))*jacobi_dn(x, m)*jacobi_cn(x, m)/m) * - jacobi_cn(x, m)/jacobi_sn(x, m)**Integer(2) + - HALF*(jacobi_sn(x, m)**Integer(2)*jacobi_cn(x, m)/(m - Integer(1)) - - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / - (m - Integer(1)))*jacobi_dn(x, m)*jacobi_sn(x, m)/m) / - jacobi_sn(x, m)) + return HALF * (jacobi_sn(x, m) * jacobi_cn(x, m) ** Integer(2) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_cn(x, m) / m) * jacobi_cn(x, m) / jacobi_sn(x, m) ** Integer(2) + HALF * (jacobi_sn(x, m) ** Integer(2) * jacobi_cn(x, m) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_sn(x, m) / m) / jacobi_sn(x, m) def _latex_(self): r""" @@ -517,9 +451,7 @@ def _print_latex_(self, x, m): sage: latex(jacobi_sn(x, 3)) # needs sage.symbolic \operatorname{sn}\left(x\middle|3\right) """ - return r"\operatorname{{{}}}\left({}\middle|{}\right)".format(self.kind, - latex(x), - latex(m)) + return r"\operatorname{{{}}}\left({}\middle|{}\right)".format(self.kind, latex(x), latex(m)) jacobi_nd = Jacobi('nd') @@ -540,6 +472,7 @@ class InverseJacobi(BuiltinFunction): r""" Base class for the inverse Jacobi elliptic functions. """ + def __init__(self, kind): r""" Initialize ``self``. @@ -550,16 +483,10 @@ def __init__(self, kind): sage: InverseJacobi('sn') inverse_jacobi_sn """ - if kind not in ['nd', 'ns', 'nc', 'dn', 'ds', 'dc', 'sn', 'sd', - 'sc', 'cn', 'cd', 'cs']: - raise ValueError("kind must be one of 'nd', 'ns', 'nc', 'dn', " - "'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") + if kind not in ['nd', 'ns', 'nc', 'dn', 'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs']: + raise ValueError("kind must be one of 'nd', 'ns', 'nc', 'dn', " "'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") self.kind = kind - BuiltinFunction.__init__(self, - name=f'inverse_jacobi_{kind}', nargs=2, evalf_params_first=False, - conversions=dict(maple=('InverseJacobi{}'.format(kind.upper())), - mathematica=f'InverseJacobi{kind.upper()}', - maxima=(f'inverse_jacobi_{kind}'))) + BuiltinFunction.__init__(self, name=f'inverse_jacobi_{kind}', nargs=2, evalf_params_first=False, conversions=dict(maple=('InverseJacobi{}'.format(kind.upper())), mathematica=f'InverseJacobi{kind.upper()}', maxima=(f'inverse_jacobi_{kind}'))) def _eval_(self, x, m): r""" @@ -791,108 +718,54 @@ def _derivative_(self, x, m, diff_param): # From Wolfram Functions Site if diff_param == 0: if self.kind == 'cd': - return (jacobi_sn(inverse_jacobi_cd(x, m), m) / - (x ** Integer(2) - Integer(1))) + return jacobi_sn(inverse_jacobi_cd(x, m), m) / (x ** Integer(2) - Integer(1)) if self.kind == 'cn': - return (jacobi_ds(inverse_jacobi_cn(x, m), m) / - (m * x ** Integer(2) - m + Integer(1))) + return jacobi_ds(inverse_jacobi_cn(x, m), m) / (m * x ** Integer(2) - m + Integer(1)) if self.kind == 'cs': - return (jacobi_nd(inverse_jacobi_cs(x, m), m) / - (x ** Integer(2) + Integer(1))) + return jacobi_nd(inverse_jacobi_cs(x, m), m) / (x ** Integer(2) + Integer(1)) if self.kind == 'dc': - return (jacobi_sn(inverse_jacobi_dc(x, m), m) / - (x ** Integer(2) - Integer(1))) + return jacobi_sn(inverse_jacobi_dc(x, m), m) / (x ** Integer(2) - Integer(1)) if self.kind == 'dn': - return -(jacobi_cs(inverse_jacobi_dn(x, m), m) / - (x ** Integer(2) + m - Integer(1))) + return -(jacobi_cs(inverse_jacobi_dn(x, m), m) / (x ** Integer(2) + m - Integer(1))) if self.kind == 'ds': - return (jacobi_nc(inverse_jacobi_ds(x, m), m) / - (x ** Integer(2) + m)) + return jacobi_nc(inverse_jacobi_ds(x, m), m) / (x ** Integer(2) + m) if self.kind == 'nc': - return (jacobi_ds(inverse_jacobi_nc(x, m), m) / - (-m * x ** Integer(2) + x ** Integer(2) + m)) + return jacobi_ds(inverse_jacobi_nc(x, m), m) / (-m * x ** Integer(2) + x ** Integer(2) + m) if self.kind == 'nd': - return (jacobi_sc(inverse_jacobi_nd(x, m), m) / - (x ** Integer(2) - Integer(1))) + return jacobi_sc(inverse_jacobi_nd(x, m), m) / (x ** Integer(2) - Integer(1)) if self.kind == 'ns': - return Integer(1) / (jacobi_cs(inverse_jacobi_ns(x, m), m) * - jacobi_ds(inverse_jacobi_ns(x, m), m)) + return Integer(1) / (jacobi_cs(inverse_jacobi_ns(x, m), m) * jacobi_ds(inverse_jacobi_ns(x, m), m)) if self.kind == 'sc': - return (jacobi_nd(inverse_jacobi_sc(x, m), m) / - (x ** Integer(2) + Integer(1))) + return jacobi_nd(inverse_jacobi_sc(x, m), m) / (x ** Integer(2) + Integer(1)) if self.kind == 'sd': - return (jacobi_cn(inverse_jacobi_sd(x, m), m) / - ((m - Integer(1)) * x ** Integer(2) + Integer(1))) + return jacobi_cn(inverse_jacobi_sd(x, m), m) / ((m - Integer(1)) * x ** Integer(2) + Integer(1)) if self.kind == 'sn': - return (jacobi_cd(inverse_jacobi_sn(x, m), m) / - (Integer(1) - x ** Integer(2))) + return jacobi_cd(inverse_jacobi_sn(x, m), m) / (Integer(1) - x ** Integer(2)) elif diff_param == 1: if self.kind == 'cd': - return ((Integer(1) / (Integer(2) * (Integer(1) - m) * m)) * - ((m - Integer(1)) * inverse_jacobi_cd(x, m) + - elliptic_e(jacobi_am(inverse_jacobi_cd(x, m), m), - m))) + return (Integer(1) / (Integer(2) * (Integer(1) - m) * m)) * ((m - Integer(1)) * inverse_jacobi_cd(x, m) + elliptic_e(jacobi_am(inverse_jacobi_cd(x, m), m), m)) if self.kind == 'cn': - return ((-(Integer(1) / (Integer(2) * (-Integer(1) + m) * m))) * - (elliptic_e(jacobi_am(inverse_jacobi_cn(x, m), m), - m) + (-Integer(1) + m) * - inverse_jacobi_cn(x, m) - m * x * - jacobi_sd(inverse_jacobi_cn(x, m), m))) + return (-(Integer(1) / (Integer(2) * (-Integer(1) + m) * m))) * (elliptic_e(jacobi_am(inverse_jacobi_cn(x, m), m), m) + (-Integer(1) + m) * inverse_jacobi_cn(x, m) - m * x * jacobi_sd(inverse_jacobi_cn(x, m), m)) if self.kind == 'cs': - return ((-(Integer(1) / (Integer(2) * (-Integer(1) + m) * m * (Integer(1) + x ** Integer(2))))) * - ((Integer(1) + x ** Integer(2)) * - elliptic_e(jacobi_am(inverse_jacobi_cs(x, m), m), - m) + (-Integer(1) + m) * (Integer(1) + x ** Integer(2)) * - inverse_jacobi_cs(x, m) - m * x * - jacobi_nd(inverse_jacobi_cs(x, m), m))) + return (-(Integer(1) / (Integer(2) * (-Integer(1) + m) * m * (Integer(1) + x ** Integer(2))))) * ((Integer(1) + x ** Integer(2)) * elliptic_e(jacobi_am(inverse_jacobi_cs(x, m), m), m) + (-Integer(1) + m) * (Integer(1) + x ** Integer(2)) * inverse_jacobi_cs(x, m) - m * x * jacobi_nd(inverse_jacobi_cs(x, m), m)) if self.kind == 'dc': - return ((Integer(1) / (Integer(2) * (Integer(1) - m) * m)) * - (elliptic_e(jacobi_am(inverse_jacobi_dc(x, m), m), - m) - (Integer(1) - m) * - inverse_jacobi_dc(x, m))) + return (Integer(1) / (Integer(2) * (Integer(1) - m) * m)) * (elliptic_e(jacobi_am(inverse_jacobi_dc(x, m), m), m) - (Integer(1) - m) * inverse_jacobi_dc(x, m)) if self.kind == 'dn': - return ((Integer(1) / (Integer(2) * (Integer(1) - m) * m)) * ((m - Integer(1)) * - inverse_jacobi_dn(x, m) + - elliptic_e(jacobi_am(inverse_jacobi_dn(x, m), m), m) - - x * jacobi_sc(inverse_jacobi_dn(x, m), m))) + return (Integer(1) / (Integer(2) * (Integer(1) - m) * m)) * ((m - Integer(1)) * inverse_jacobi_dn(x, m) + elliptic_e(jacobi_am(inverse_jacobi_dn(x, m), m), m) - x * jacobi_sc(inverse_jacobi_dn(x, m), m)) if self.kind == 'ds': - return ((-(Integer(1) / (Integer(2) * (-Integer(1) + m) * m))) * - (elliptic_e(jacobi_am(inverse_jacobi_ds(x, m), m), m) + - (-Integer(1) + m) * inverse_jacobi_ds(x, m) - - (m * x * jacobi_nc(inverse_jacobi_ds(x, m), m)) / - (m + x ** Integer(2)))) + return (-(Integer(1) / (Integer(2) * (-Integer(1) + m) * m))) * (elliptic_e(jacobi_am(inverse_jacobi_ds(x, m), m), m) + (-Integer(1) + m) * inverse_jacobi_ds(x, m) - (m * x * jacobi_nc(inverse_jacobi_ds(x, m), m)) / (m + x ** Integer(2))) if self.kind == 'nc': - return ((Integer(1) / (Integer(2) * (-Integer(1) + m) * m * x)) * ((-x) * - (elliptic_e(jacobi_am(inverse_jacobi_nc(x, m), m), m) + - (-Integer(1) + m) * inverse_jacobi_nc(x, m)) + m * - jacobi_sd(inverse_jacobi_nc(x, m), m))) + return (Integer(1) / (Integer(2) * (-Integer(1) + m) * m * x)) * ((-x) * (elliptic_e(jacobi_am(inverse_jacobi_nc(x, m), m), m) + (-Integer(1) + m) * inverse_jacobi_nc(x, m)) + m * jacobi_sd(inverse_jacobi_nc(x, m), m)) if self.kind == 'nd': - return ((Integer(1) / (Integer(2) * (m - Integer(1)) * m)) * - ((Integer(1) - m) * inverse_jacobi_nd(x, m) - - elliptic_e(jacobi_am(inverse_jacobi_nd(x, m), m), m) + - (Integer(1) / x) * jacobi_sc(inverse_jacobi_nd(x, m), m))) + return (Integer(1) / (Integer(2) * (m - Integer(1)) * m)) * ((Integer(1) - m) * inverse_jacobi_nd(x, m) - elliptic_e(jacobi_am(inverse_jacobi_nd(x, m), m), m) + (Integer(1) / x) * jacobi_sc(inverse_jacobi_nd(x, m), m)) if self.kind == 'ns': - return ((Integer(1)/(Integer(2) * (m - Integer(1)) * m)) * - ((Integer(1) - m) * inverse_jacobi_ns(x, m) - - elliptic_e(jacobi_am(inverse_jacobi_ns(x, m), m), m) + - (m / x) * jacobi_cd(inverse_jacobi_ns(x, m), m))) + return (Integer(1) / (Integer(2) * (m - Integer(1)) * m)) * ((Integer(1) - m) * inverse_jacobi_ns(x, m) - elliptic_e(jacobi_am(inverse_jacobi_ns(x, m), m), m) + (m / x) * jacobi_cd(inverse_jacobi_ns(x, m), m)) if self.kind == 'sc': - return ((-(Integer(1) / (Integer(2) * (-Integer(1) + m) * m * (Integer(1) + x ** Integer(2))))) * - ((Integer(1) + x ** Integer(2)) * - elliptic_e(jacobi_am(inverse_jacobi_sc(x, m), m), m) + - (-Integer(1) + m) * (Integer(1) + x ** Integer(2)) * inverse_jacobi_sc(x, m) - - m * x * jacobi_nd(inverse_jacobi_sc(x, m), m))) + return (-(Integer(1) / (Integer(2) * (-Integer(1) + m) * m * (Integer(1) + x ** Integer(2))))) * ((Integer(1) + x ** Integer(2)) * elliptic_e(jacobi_am(inverse_jacobi_sc(x, m), m), m) + (-Integer(1) + m) * (Integer(1) + x ** Integer(2)) * inverse_jacobi_sc(x, m) - m * x * jacobi_nd(inverse_jacobi_sc(x, m), m)) if self.kind == 'sd': - return ((-(Integer(1) / (Integer(2) * (-Integer(1) + m) * m))) * - (elliptic_e(jacobi_am(inverse_jacobi_sd(x, m), m), m) + - (-Integer(1) + m) * inverse_jacobi_sd(x, m) - - (m * x * jacobi_nc(inverse_jacobi_sd(x, m), m)) / - (Integer(1) + m * x ** Integer(2)))) + return (-(Integer(1) / (Integer(2) * (-Integer(1) + m) * m))) * (elliptic_e(jacobi_am(inverse_jacobi_sd(x, m), m), m) + (-Integer(1) + m) * inverse_jacobi_sd(x, m) - (m * x * jacobi_nc(inverse_jacobi_sd(x, m), m)) / (Integer(1) + m * x ** Integer(2))) if self.kind == 'sn': - return ((Integer(1) / (Integer(2) * (Integer(1) - m) * m)) * - (elliptic_e(jacobi_am(inverse_jacobi_sn(x, m), m), m) + - (-Integer(1) + m) * inverse_jacobi_sn(x, m) - m * x * - jacobi_cd(inverse_jacobi_sn(x, m), m))) + return (Integer(1) / (Integer(2) * (Integer(1) - m) * m)) * (elliptic_e(jacobi_am(inverse_jacobi_sn(x, m), m), m) + (-Integer(1) + m) * inverse_jacobi_sn(x, m) - m * x * jacobi_cd(inverse_jacobi_sn(x, m), m)) def _latex_(self): r""" @@ -910,9 +783,7 @@ def _print_latex_(self, x, m): sage: latex(inverse_jacobi_dn(x, 3)) # needs sage.symbolic \operatorname{arcdn}\left(x\middle|3\right) """ - return r"\operatorname{{arc{}}}\left({}\middle|{}\right)".format(self.kind, - latex(x), - latex(m)) + return r"\operatorname{{arc{}}}\left({}\middle|{}\right)".format(self.kind, latex(x), latex(m)) inverse_jacobi_nd = InverseJacobi('nd') @@ -981,8 +852,7 @@ def jacobi(kind, z, m, **kwargs): return jacobi_cd(z, m, **kwargs) if kind == 'cs': return jacobi_cs(z, m, **kwargs) - raise ValueError("kind must be one of 'nd', 'ns', 'nc', 'dn', " - "'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") + raise ValueError("kind must be one of 'nd', 'ns', 'nc', 'dn', " "'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") def inverse_jacobi(kind, x, m, **kwargs): @@ -1061,8 +931,7 @@ def inverse_jacobi(kind, x, m, **kwargs): return inverse_jacobi_cd(x, m, **kwargs) if kind == 'cs': return inverse_jacobi_cs(x, m, **kwargs) - raise ValueError("kind must be one of 'nd', 'ns', 'nc', 'dn', " - "'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") + raise ValueError("kind must be one of 'nd', 'ns', 'nc', 'dn', " "'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") class JacobiAmplitude(BuiltinFunction): @@ -1071,6 +940,7 @@ class JacobiAmplitude(BuiltinFunction): `\operatorname{am}(x|m) = \int_0^x \operatorname{dn}(t|m) dt` for `-K(m) \leq x \leq K(m)`, `F(\operatorname{am}(x|m)|m) = x`. """ + def __init__(self): r""" TESTS:: @@ -1079,10 +949,7 @@ def __init__(self): sage: JacobiAmplitude() jacobi_am """ - BuiltinFunction.__init__(self, name='jacobi_am', nargs=2, - conversions=dict(maple='JacobiAM', - mathematica='JacobiAmplitude'), - evalf_params_first=False) + BuiltinFunction.__init__(self, name='jacobi_am', nargs=2, conversions=dict(maple='JacobiAM', mathematica='JacobiAmplitude'), evalf_params_first=False) def _eval_(self, x, m): r""" @@ -1123,9 +990,7 @@ def _derivative_(self, x, m, diff_param): if diff_param == 0: return jacobi_dn(x, m) if diff_param == 1: - return (((Integer(-1) + m) * x + elliptic_e(jacobi_am(x, m), m)) * - jacobi('dn', x, m) - m * jacobi('cn', x, m) * - jacobi('sn', x, m)) / (Integer(2) * (Integer(-1) + m) * m) + return (((Integer(-1) + m) * x + elliptic_e(jacobi_am(x, m), m)) * jacobi('dn', x, m) - m * jacobi('cn', x, m) * jacobi('sn', x, m)) / (Integer(2) * (Integer(-1) + m) * m) def _latex_(self): r""" @@ -1143,8 +1008,7 @@ def _print_latex_(self, x, m): sage: latex(jacobi_am(3,x)) # needs sage.symbolic \operatorname{am}\left(3\middle|x\right) """ - return r"\operatorname{{am}}\left({}\middle|{}\right)".format(latex(x), - latex(m)) + return r"\operatorname{{am}}\left({}\middle|{}\right)".format(latex(x), latex(m)) jacobi_am = JacobiAmplitude() @@ -1293,6 +1157,7 @@ def inverse_jacobi_f(kind, x, m): mpf('4.0') """ from mpmath import mp as ctx + prec = ctx.prec try: x = ctx.convert(x) @@ -1307,7 +1172,7 @@ def inverse_jacobi_f(kind, x, m): if x == 0: return ctx.zero sign = ctx.sign(x) # sn is odd in x, so operate with abs(x) and - x = abs(x) # include the sign at the end + x = abs(x) # include the sign at the end if x <= 1: ctx.prec += 10 phi = ctx.asin(x) @@ -1362,7 +1227,7 @@ def inverse_jacobi_f(kind, x, m): return ctx.zero if 0 <= x < 1: ctx.prec += 10 - x2 = x ** 2 + x2 = x**2 ctx.prec += 10 osx2 = 1 - x2 ctx.prec += 10 @@ -1370,7 +1235,7 @@ def inverse_jacobi_f(kind, x, m): if -1 <= x < 0: K = ctx.ellipk(m) ctx.prec += 10 - x2 = x ** 2 + x2 = x**2 ctx.prec += 10 osx2 = 1 - x2 ctx.prec += 10 @@ -1429,7 +1294,7 @@ def inverse_jacobi_f(kind, x, m): sqrtm1 = ctx.sqrt(m1) if sqrtm1 <= x < 1: ctx.prec += 10 - x2 = x ** 2 + x2 = x**2 ctx.prec += 10 osx2 = 1 - x2 ctx.prec += 10 @@ -1451,7 +1316,7 @@ def inverse_jacobi_f(kind, x, m): if 0 <= x < sqrtm1: K = ctx.ellipk(m) ctx.prec += 10 - x2 = x ** 2 + x2 = x**2 ctx.prec += 10 x2dm1 = x2 / m1 osx2 = 1 - x2 @@ -1470,7 +1335,7 @@ def inverse_jacobi_f(kind, x, m): K_prime = ctx.ellipk(m1) ctx.prec += 10 tK_prime = 2 * K_prime - x2 = x ** 2 + x2 = x**2 ctx.prec += 10 x2dm1 = x2 / m1 osx2 = 1 - x2 @@ -1488,7 +1353,7 @@ def inverse_jacobi_f(kind, x, m): K = ctx.ellipk(m) K_prime = ctx.ellipk(m1) ctx.prec += 10 - x2 = x ** 2 + x2 = x**2 tK = 2 * K # Note that the factor of 2 is missing in the reference # (formula (81)), probably mistakenly so @@ -1641,6 +1506,7 @@ def jacobi_am_f(x, m): mpf('0.36067407399586108') """ from mpmath import mp as ctx + prec = ctx.prec try: x = ctx.convert(x) diff --git a/src/sage/functions/log.py b/src/sage/functions/log.py index 49077962364..3b31627a029 100644 --- a/src/sage/functions/log.py +++ b/src/sage/functions/log.py @@ -165,6 +165,7 @@ class Function_exp(GinacFunction): sage: exp(-x).subs(x=-oo) # needs sage.symbolic +Infinity """ + def __init__(self): """ TESTS:: @@ -174,8 +175,7 @@ def __init__(self): sage: maxima(exp(x))._sage_() # needs sage.symbolic e^x """ - GinacFunction.__init__(self, "exp", latex_name=r"\exp", - conversions=dict(maxima='exp', fricas='exp')) + GinacFunction.__init__(self, "exp", latex_name=r"\exp", conversions=dict(maxima='exp', fricas='exp')) exp = Function_exp() @@ -246,6 +246,7 @@ class Function_log1(GinacFunction): sage: polylog(QQbar(sqrt(2)),3) # needs sage.rings.number_field sage.symbolic polylog(1.414213562373095?, 3) """ + def __init__(self): """ TESTS:: @@ -255,9 +256,7 @@ def __init__(self): sage: maxima(ln(x))._sage_() # needs sage.symbolic log(x) """ - GinacFunction.__init__(self, 'log', latex_name=r'\log', - conversions=dict(maxima='log', fricas='log', - mathematica='Log', giac='ln')) + GinacFunction.__init__(self, 'log', latex_name=r'\log', conversions=dict(maxima='log', fricas='log', mathematica='Log', giac='ln')) ln = function_log = Function_log1() @@ -294,6 +293,7 @@ class Function_log2(GinacFunction): sage: float(logb(int(21743271936), 2)) # needs sage.symbolic 34.33985000288... """ + def __init__(self): """ TESTS:: @@ -302,9 +302,7 @@ def __init__(self): sage: loads(dumps(logb)) log """ - GinacFunction.__init__(self, 'log', ginac_name='logb', nargs=2, - latex_name=r'\log', - conversions=dict(maxima='log')) + GinacFunction.__init__(self, 'log', ginac_name='logb', nargs=2, latex_name=r'\log', conversions=dict(maxima='log')) logb = Function_log2() @@ -412,11 +410,7 @@ def __init__(self): sage: bool(x*polylog(x,x)==0) # needs sage.symbolic False """ - GinacFunction.__init__(self, "polylog", nargs=2, - conversions=dict(mathematica='PolyLog', - magma='Polylog', - matlab='polylog', - sympy='polylog')) + GinacFunction.__init__(self, "polylog", nargs=2, conversions=dict(mathematica='PolyLog', magma='Polylog', matlab='polylog', sympy='polylog')) def _maxima_init_evaled_(self, *args): """ @@ -548,10 +542,7 @@ def __init__(self): sage: parent(_) Complex Field with 13 bits of precision """ - GinacFunction.__init__(self, 'dilog', - conversions=dict(maxima='li[2]', - magma='Dilog', - fricas='(x+->dilog(1-x))')) + GinacFunction.__init__(self, 'dilog', conversions=dict(maxima='li[2]', magma='Dilog', fricas='(x+->dilog(1-x))')) def _sympy_(self, z): r""" @@ -684,13 +675,7 @@ def __init__(self): sage: lambert_w(n, x)._fricas_() # optional - fricas, needs sage.symbolic generalizedLambertW(n,x) """ - BuiltinFunction.__init__(self, "lambert_w", nargs=2, - conversions={'mathematica': 'ProductLog', - 'maple': 'LambertW', - 'matlab': 'lambertw', - 'maxima': 'generalized_lambert_w', - 'fricas': "((n,z)+->(if n=0 then lambertW(z) else operator('generalizedLambertW)(n,z)))", - 'sympy': 'LambertW'}) + BuiltinFunction.__init__(self, "lambert_w", nargs=2, conversions={'mathematica': 'ProductLog', 'maple': 'LambertW', 'matlab': 'lambertw', 'maxima': 'generalized_lambert_w', 'fricas': "((n,z)+->(if n=0 then lambertW(z) else operator('generalizedLambertW)(n,z)))", 'sympy': 'LambertW'}) def __call__(self, *args, **kwds): r""" @@ -967,9 +952,7 @@ def __init__(self): :wikipedia:`Complex_number#Polar_form` """ - BuiltinFunction.__init__(self, "exp_polar", - latex_name=r"\operatorname{exp\_polar}", - conversions=dict(sympy='exp_polar')) + BuiltinFunction.__init__(self, "exp_polar", latex_name=r"\operatorname{exp\_polar}", conversions=dict(sympy='exp_polar')) def _evalf_(self, z, parent=None, algorithm=None): r""" @@ -994,8 +977,7 @@ def _evalf_(self, z, parent=None, algorithm=None): ... ValueError: invalid attempt to numerically evaluate exp_polar() """ - if (not isinstance(z, Expression) and - bool(-const_pi < imag(z) <= const_pi)): + if not isinstance(z, Expression) and bool(-const_pi < imag(z) <= const_pi): return exp(z) raise ValueError("invalid attempt to numerically evaluate exp_polar()") @@ -1111,8 +1093,7 @@ def __init__(self): sage: harmonic_number(x, x)._sympy_() # needs sympy sage.symbolic harmonic(x, x) """ - BuiltinFunction.__init__(self, "harmonic_number", nargs=2, - conversions={'sympy': 'harmonic'}) + BuiltinFunction.__init__(self, "harmonic_number", nargs=2, conversions={'sympy': 'harmonic'}) def __call__(self, z, m=1, **kwds): r""" @@ -1289,6 +1270,7 @@ class _Function_swap_harmonic(BuiltinFunction): sage: max_to_sr(c.ecl()) harmonic_number(x, 2) """ + def __init__(self): BuiltinFunction.__init__(self, "_swap_harmonic", nargs=2) @@ -1328,11 +1310,7 @@ def __init__(self): sage: harmonic_number(x)._sympy_() # needs sympy sage.symbolic harmonic(x) """ - BuiltinFunction.__init__(self, "harmonic_number", nargs=1, - conversions={'mathematica': 'HarmonicNumber', - 'maple': 'harmonic', - 'maxima': 'harmonic_number', - 'sympy': 'harmonic'}) + BuiltinFunction.__init__(self, "harmonic_number", nargs=1, conversions={'mathematica': 'HarmonicNumber', 'maple': 'harmonic', 'maxima': 'harmonic_number', 'sympy': 'harmonic'}) def _eval_(self, z, **kwds): """ diff --git a/src/sage/functions/min_max.py b/src/sage/functions/min_max.py index 859f4a575b9..991daf0284c 100644 --- a/src/sage/functions/min_max.py +++ b/src/sage/functions/min_max.py @@ -184,8 +184,7 @@ def __init__(self): sage: max_symbolic(x, 5)._sympy_() # needs sympy Max(5, x) """ - BuiltinFunction.__init__(self, 'max', nargs=0, latex_name=r"\max", - conversions=dict(sympy='Max')) + BuiltinFunction.__init__(self, 'max', nargs=0, latex_name=r"\max", conversions=dict(sympy='Max')) def _eval_(self, *args): """ @@ -277,8 +276,7 @@ def __init__(self): sage: min_symbolic(x, 5)._sympy_() # needs sympy Min(5, x) """ - BuiltinFunction.__init__(self, 'min', nargs=0, latex_name=r"\min", - conversions=dict(sympy='Min')) + BuiltinFunction.__init__(self, 'min', nargs=0, latex_name=r"\min", conversions=dict(sympy='Min')) def _eval_(self, *args): """ diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index 52cbd8217c0..0b2faf9fde0 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -376,6 +376,7 @@ in the Maxima package "orthopoly" and was written by Barton Willis of the University of Nebraska at Kearney. """ + # **************************************************************************** # Copyright (C) 2006 William Stein # 2006 David Joyner @@ -435,6 +436,7 @@ class OrthogonalFunction(BuiltinFunction): the others are other values or parameters where the polynomial is evaluated. """ + def __init__(self, name, nargs=2, latex_name=None, conversions=None): """ :class:`OrthogonalFunction` class needs the same input parameter as @@ -453,9 +455,7 @@ def __init__(self, name, nargs=2, latex_name=None, conversions=None): self._maxima_name = conversions['maxima'] except KeyError: pass - super().__init__(name=name, nargs=nargs, - latex_name=latex_name, - conversions=conversions) + super().__init__(name=name, nargs=nargs, latex_name=latex_name, conversions=conversions) def eval_formula(self, *args): """ @@ -542,6 +542,7 @@ class ChebyshevFunction(OrthogonalFunction): sage: chebyshev_T(3, x) # needs sage.symbolic 4*x^3 - 3*x """ + def __call__(self, n, *args, **kwds): """ This overrides the call method from :class:`SageObject` to @@ -638,10 +639,10 @@ def _eval_(self, n, x): # We assume n and x are real/complex and evaluate numerically try: import sage.libs.mpmath.all as mpmath + return self._evalf_(n, x) except mpmath.NoConvergence: - warnings.warn("mpmath failed, keeping expression unevaluated", - RuntimeWarning) + warnings.warn("mpmath failed, keeping expression unevaluated", RuntimeWarning) return None except Exception: # Numerical evaluation failed => keep symbolic @@ -665,6 +666,7 @@ class Func_chebyshev_T(ChebyshevFunction): sage: test = chebyshev_T(k, x); test # needs sage.symbolic chebyshev_T(k, x) """ + def __init__(self): """ Init method for the chebyshev polynomials of the first kind. @@ -685,11 +687,7 @@ def __init__(self): sage: maxima(chebyshev_T(n, chebyshev_T(n, x))) chebyshev_t(_SAGE_VAR_n,chebyshev_t(_SAGE_VAR_n,_SAGE_VAR_x)) """ - ChebyshevFunction.__init__(self, 'chebyshev_T', nargs=2, - conversions=dict(maxima='chebyshev_t', - mathematica='ChebyshevT', - sympy='chebyshevt', - giac='tchebyshev1')) + ChebyshevFunction.__init__(self, 'chebyshev_T', nargs=2, conversions=dict(maxima='chebyshev_t', mathematica='ChebyshevT', sympy='chebyshevt', giac='tchebyshev1')) def _latex_(self): r""" @@ -741,7 +739,7 @@ def _eval_special_values_(self, n, x): return x**n if x == 0: - return (1+(-1)**n)*(-1)**(n/2)/2 + return (1 + (-1) ** n) * (-1) ** (n / 2) / 2 raise ValueError("no special value found") @@ -843,9 +841,9 @@ def eval_formula(self, n, x): res = parent(x).zero() for j in range(n // 2 + 1): - f = factorial(n-1-j) / factorial(j) / factorial(n-2*j) - res += (-1)**j * (2*x)**(n-2*j) * f - res *= n/2 + f = factorial(n - 1 - j) / factorial(j) / factorial(n - 2 * j) + res += (-1) ** j * (2 * x) ** (n - 2 * j) * f + res *= n / 2 return res def eval_algebraic(self, n, x): @@ -910,10 +908,10 @@ def _eval_recursive_(self, n, x, both=False): return x, parent(x).one() assert n >= 2 - a, b = self._eval_recursive_((n+1)//2, x, both or n % 2) + a, b = self._eval_recursive_((n + 1) // 2, x, both or n % 2) if n % 2 == 0: - return 2*a*a - 1, both and 2*a*b - x - return 2*a*b - x, both and 2*b*b - 1 + return 2 * a * a - 1, both and 2 * a * b - x + return 2 * a * b - x, both and 2 * b * b - 1 def _eval_numpy_(self, n, x): """ @@ -937,6 +935,7 @@ def _eval_numpy_(self, n, x): array([ 0.1 , -0.98]) """ from scipy.special import eval_chebyt + return eval_chebyt(n, x) def _derivative_(self, n, x, diff_param): @@ -961,7 +960,7 @@ def _derivative_(self, n, x, diff_param): if diff_param == 0: raise NotImplementedError("derivative w.r.t. to the index is not supported yet") elif diff_param == 1: - return n*chebyshev_U(n-1, x) + return n * chebyshev_U(n - 1, x) raise ValueError("illegal differentiation parameter {}".format(diff_param)) @@ -984,6 +983,7 @@ class Func_chebyshev_U(ChebyshevFunction): sage: chebyshev_U(3, t) 8*t^3 - 4*t """ + def __init__(self): """ Init method for the chebyshev polynomials of the second kind. @@ -1004,11 +1004,7 @@ def __init__(self): sage: maxima(chebyshev_U(n,x, hold=True)) chebyshev_u(_SAGE_VAR_n,_SAGE_VAR_x) """ - ChebyshevFunction.__init__(self, 'chebyshev_U', nargs=2, - conversions=dict(maxima='chebyshev_u', - mathematica='ChebyshevU', - sympy='chebyshevu', - giac='tchebyshev2')) + ChebyshevFunction.__init__(self, 'chebyshev_U', nargs=2, conversions=dict(maxima='chebyshev_u', mathematica='ChebyshevU', sympy='chebyshevu', giac='tchebyshev2')) def _latex_(self): r""" @@ -1059,12 +1055,12 @@ def eval_formula(self, n, x): True """ if n < -1: - return -self.eval_formula(-n-2, x) + return -self.eval_formula(-n - 2, x) res = parent(x).zero() for j in range(n // 2 + 1): - f = binomial(n-j, j) - res += (-1)**j * (2*x)**(n-2*j) * f + f = binomial(n - j, j) + res += (-1) ** j * (2 * x) ** (n - 2 * j) * f return res def eval_algebraic(self, n, x): @@ -1114,7 +1110,7 @@ def eval_algebraic(self, n, x): if n == -1: return parent(x).zero() if n < 0: - return -self._eval_recursive_(-n-2, x)[0] + return -self._eval_recursive_(-n - 2, x)[0] return self._eval_recursive_(n, x)[0] def _eval_recursive_(self, n, x, both=False): @@ -1132,13 +1128,13 @@ def _eval_recursive_(self, n, x, both=False): ((2*x + 1)*(2*x - 1) + 2*x)*((2*x + 1)*(2*x - 1) - 2*x)) """ if n == 0: - return parent(x).one(), 2*x + return parent(x).one(), 2 * x assert n >= 1 - a, b = self._eval_recursive_((n-1)//2, x, True) + a, b = self._eval_recursive_((n - 1) // 2, x, True) if n % 2 == 0: - return (b+a)*(b-a), both and 2*b*(x*b-a) - return 2*a*(b-x*a), both and (b+a)*(b-a) + return (b + a) * (b - a), both and 2 * b * (x * b - a) + return 2 * a * (b - x * a), both and (b + a) * (b - a) def _evalf_(self, n, x, **kwds): """ @@ -1196,13 +1192,13 @@ def _eval_special_values_(self, n, x): ValueError: no special value found """ if x == 1: - return x*(n+1) + return x * (n + 1) if x == -1: - return x**n*(n+1) + return x**n * (n + 1) if x == 0: - return (1+(-1)**n)*(-1)**(n/2)/2 + return (1 + (-1) ** n) * (-1) ** (n / 2) / 2 raise ValueError("no special value found") @@ -1251,7 +1247,7 @@ def _derivative_(self, n, x, diff_param): if diff_param == 0: raise NotImplementedError("derivative w.r.t. to the index is not supported yet") elif diff_param == 1: - return ((n+1)*chebyshev_T(n+1, x) - x*chebyshev_U(n, x)) / (x*x-1) + return ((n + 1) * chebyshev_T(n + 1, x) - x * chebyshev_U(n, x)) / (x * x - 1) raise ValueError("illegal differentiation parameter {}".format(diff_param)) @@ -1343,6 +1339,7 @@ class Func_legendre_P(GinacFunction): 2^(-n + 2)*(-1)^(1/2*n)*gamma(n)/(n*gamma(1/2*n)^2) sage: forget() """ + def __init__(self): r""" Init method for the Legendre polynomials of the first kind. @@ -1352,11 +1349,7 @@ def __init__(self): sage: loads(dumps(legendre_P)) legendre_P """ - BuiltinFunction.__init__(self, 'legendre_P', nargs=2, latex_name=r"P", - conversions={'maxima': 'legendre_p', - 'mathematica': 'LegendreP', - 'maple': 'LegendreP', - 'giac': 'legendre'}) + BuiltinFunction.__init__(self, 'legendre_P', nargs=2, latex_name=r"P", conversions={'maxima': 'legendre_p', 'mathematica': 'LegendreP', 'maple': 'LegendreP', 'giac': 'legendre'}) legendre_P = Func_legendre_P() @@ -1372,10 +1365,7 @@ def __init__(self): sage: maxima(legendre_Q(20, x, hold=True))._sage_().coefficient(x, 10) # needs sage.symbolic -29113619535/131072*log(-(x + 1)/(x - 1)) """ - BuiltinFunction.__init__(self, "legendre_Q", nargs=2, latex_name=r"Q", - conversions={'maxima': 'legendre_q', - 'mathematica': 'LegendreQ', - 'maple': 'LegendreQ'}) + BuiltinFunction.__init__(self, "legendre_Q", nargs=2, latex_name=r"Q", conversions={'maxima': 'legendre_q', 'mathematica': 'LegendreQ', 'maple': 'LegendreQ'}) def _eval_(self, n, x, *args, **kwds): r""" @@ -1401,6 +1391,7 @@ def _eval_(self, n, x, *args, **kwds): if n in ZZ: if n < 0: from sage.rings.infinity import unsigned_infinity + return SR(unsigned_infinity) return self.eval_formula(n, x) @@ -1420,27 +1411,31 @@ def _eval_special_values_(self, n, x): sage: legendre_Q(-1/2, 2) elliptic_kc(3/2) """ - if n == QQ(-1)/2: + if n == QQ(-1) / 2: from sage.functions.special import elliptic_kc - return elliptic_kc((x+1)/2) + + return elliptic_kc((x + 1) / 2) if x == 1: from sage.rings.infinity import unsigned_infinity + return SR(unsigned_infinity) if x == -1: from sage.rings.infinity import unsigned_infinity + return SR(unsigned_infinity) if x == 0: from .gamma import gamma from .other import sqrt from .trig import sin + try: - gam = gamma((n+1)/2)/gamma(n/2 + 1) + gam = gamma((n + 1) / 2) / gamma(n / 2 + 1) if gam.is_infinity(): return gam - return -(sqrt(SR.pi()))/2 * sin(SR.pi()/2*n) * gam + return -(sqrt(SR.pi())) / 2 * sin(SR.pi() / 2 * n) * gam except TypeError: pass @@ -1475,10 +1470,11 @@ def eval_recursive(self, n, arg, **kwds): -29113619535/131072*log(x + 1) + 29113619535/131072*log(-x + 1) """ from sage.functions.log import ln + if n == 0: - return (ln(1+arg)-ln(1-arg))/2 + return (ln(1 + arg) - ln(1 - arg)) / 2 if n == 1: - return arg/2*(ln(1+arg)-ln(1-arg))-1 + return arg / 2 * (ln(1 + arg) - ln(1 - arg)) - 1 x, l = PolynomialRing(QQ, 'x,l').gens() help1 = l / 2 @@ -1489,10 +1485,8 @@ def eval_recursive(self, n, arg, **kwds): help1 = help2 help2 = help3 - sum1 = sum(help3.monomial_coefficient(mon)*arg**(mon.exponents()[0][0]) - for mon in help3.monomials() if not l.divides(mon)) - sum2 = sum(help3.monomial_coefficient(mon)*arg**(mon.exponents()[0][0])*(ln(1+arg)-ln(1-arg)) - for mon in help3.monomials() if l.divides(mon)) + sum1 = sum(help3.monomial_coefficient(mon) * arg ** (mon.exponents()[0][0]) for mon in help3.monomials() if not l.divides(mon)) + sum2 = sum(help3.monomial_coefficient(mon) * arg ** (mon.exponents()[0][0]) * (ln(1 + arg) - ln(1 - arg)) for mon in help3.monomials() if l.divides(mon)) return sum1 + sum2 def eval_formula(self, n, arg, **kwds): @@ -1519,13 +1513,14 @@ def eval_formula(self, n, arg, **kwds): 0.549306144334055 - 1.57079632679490*I """ from sage.functions.log import ln + if n == 0: - return (ln(1+arg)-ln(1-arg))/2 + return (ln(1 + arg) - ln(1 - arg)) / 2 if n == 1: - return arg/2*(ln(1+arg)-ln(1-arg))-1 + return arg / 2 * (ln(1 + arg) - ln(1 - arg)) - 1 arg = SR(arg) - return legendre_P(n, arg)*(ln(1+arg)-ln(1-arg))/2 - self._Wfunc(n, arg) + return legendre_P(n, arg) * (ln(1 + arg) - ln(1 - arg)) / 2 - self._Wfunc(n, arg) def _Wfunc(self, n, arg): """ @@ -1576,7 +1571,7 @@ def _derivative_(self, n, x, *args, **kwds): if diff_param == 0: raise NotImplementedError("Derivative w.r.t. to the index is not supported.") else: - return (n*x*legendre_Q(n, x) - n*legendre_Q(n-1, x))/(x**2 - 1) + return (n * x * legendre_Q(n, x) - n * legendre_Q(n - 1, x)) / (x**2 - 1) legendre_Q = Func_legendre_Q() @@ -1693,6 +1688,7 @@ class Func_assoc_legendre_P(BuiltinFunction): - [DLMF-Legendre]_ """ + def __init__(self): r""" EXAMPLES:: @@ -1716,12 +1712,7 @@ def __init__(self): - x - - x 2 2 """ - BuiltinFunction.__init__(self, "gen_legendre_P", nargs=3, - latex_name=r"\mathtt{P}", - conversions={'maxima': 'assoc_legendre_p', - 'mathematica': 'LegendreP', - 'fricas': 'legendreP', - 'maple': 'LegendreP'}) + BuiltinFunction.__init__(self, "gen_legendre_P", nargs=3, latex_name=r"\mathtt{P}", conversions={'maxima': 'assoc_legendre_p', 'mathematica': 'LegendreP', 'fricas': 'legendreP', 'maple': 'LegendreP'}) def _eval_(self, n, m, x, *args, **kwds): r""" @@ -1789,8 +1780,9 @@ def _eval_special_values_(self, n, m, x): if x == 0: from .gamma import gamma from .other import sqrt + # https://dlmf.nist.gov/14.5#E1 - return 2**m*sqrt(SR.pi())/gamma(n/2-m/2+1)/gamma(QQ(1/2)-n/2-m/2) + return 2**m * sqrt(SR.pi()) / gamma(n / 2 - m / 2 + 1) / gamma(QQ(1 / 2) - n / 2 - m / 2) if m.is_integer() and n.is_integer(): if abs(m) > abs(n): # https://dlmf.nist.gov/14.7#E10 and https://dlmf.nist.gov/14.9#E3 @@ -1798,7 +1790,7 @@ def _eval_special_values_(self, n, m, x): return ZZ.zero() if m == n: # http://dlmf.nist.gov/14.5.iv and https://dlmf.nist.gov/14.9#E3 - return (-1)**m*factorial(2*m)/(2**m*factorial(m)) * (1-x**2)**(m/2) + return (-1) ** m * factorial(2 * m) / (2**m * factorial(m)) * (1 - x**2) ** (m / 2) def _eval_int_ord_deg_(self, n, m, x): r""" @@ -1817,10 +1809,10 @@ def _eval_int_ord_deg_(self, n, m, x): # use connection formulas to fall back on nonnegative n and m: if n < 0: # https://dlmf.nist.gov/14.9#E5 - return self._eval_int_ord_deg_(-n-1, m, x) + return self._eval_int_ord_deg_(-n - 1, m, x) if m < 0: # https://dlmf.nist.gov/14.9#E3 - return (-1)**(-m)*factorial(n+m)/factorial(n-m) * self._eval_int_ord_deg_(n, -m, x) + return (-1) ** (-m) * factorial(n + m) / factorial(n - m) * self._eval_int_ord_deg_(n, -m, x) # apply Rodrigues formula: return self.eval_gen_poly(n, m, x) @@ -1873,12 +1865,12 @@ def eval_gen_poly(self, n, m, arg, **kwds): return R = PolynomialRing(QQ, 'x') x = R.gen() - p = (1-x**2)**ZZ(n) + p = (1 - x**2) ** ZZ(n) for _ in range(m + n): p = p.diff(x) - ex1 = (1-arg**2)**(QQ(m)/2)/2**n/factorial(ZZ(n)) + ex1 = (1 - arg**2) ** (QQ(m) / 2) / 2**n / factorial(ZZ(n)) ex2 = sum(b * arg**a for a, b in enumerate(p)) - return (-1)**(m+n)*ex1*ex2 + return (-1) ** (m + n) * ex1 * ex2 def _derivative_(self, n, m, x, *args, **kwds): """ @@ -1903,7 +1895,7 @@ def _derivative_(self, n, m, x, *args, **kwds): raise NotImplementedError("Derivative w.r.t. to the index is not supported.") else: # https://dlmf.nist.gov/14.10#E4 - return ((m-n-1)*gen_legendre_P(n+1, m, x) + (n+1)*x*gen_legendre_P(n, m, x))/(1 - x**2) + return ((m - n - 1) * gen_legendre_P(n + 1, m, x) + (n + 1) * x * gen_legendre_P(n, m, x)) / (1 - x**2) gen_legendre_P = Func_assoc_legendre_P() @@ -1919,10 +1911,7 @@ def __init__(self): sage: maxima(gen_legendre_Q(2, 1, 3, hold=True))._sage_().simplify_full() # needs sage.symbolic 1/4*sqrt(2)*(36*pi - 36*I*log(2) + 25*I) """ - BuiltinFunction.__init__(self, "gen_legendre_Q", nargs=3, latex_name=r"Q", - conversions={'maxima': 'assoc_legendre_q', - 'mathematica': 'LegendreQ', - 'maple': 'LegendreQ'}) + BuiltinFunction.__init__(self, "gen_legendre_Q", nargs=3, latex_name=r"Q", conversions={'maxima': 'assoc_legendre_q', 'mathematica': 'LegendreQ', 'maple': 'LegendreQ'}) def _eval_(self, n, m, x, *args, **kwds): r""" @@ -1936,9 +1925,7 @@ def _eval_(self, n, m, x, *args, **kwds): ret = self._eval_special_values_(n, m, x) if ret is not None: return ret - if (n in ZZ and m in ZZ - and n >= 0 and m >= 0 - and (x in ZZ or not SR(x).is_numeric())): + if n in ZZ and m in ZZ and n >= 0 and m >= 0 and (x in ZZ or not SR(x).is_numeric()): return self.eval_recursive(n, m, x) def _eval_special_values_(self, n, m, x): @@ -1957,10 +1944,11 @@ def _eval_special_values_(self, n, m, x): from .gamma import gamma from .other import sqrt from .trig import sin + if m in QQ and n in QQ: - return -(sqrt(SR.pi()))*sin(SR.pi()/2*(m+n))*gamma(QQ(m+n+1)/2)/gamma(QQ(n-m)/2 + 1)*2**(m-1) + return -(sqrt(SR.pi())) * sin(SR.pi() / 2 * (m + n)) * gamma(QQ(m + n + 1) / 2) / gamma(QQ(n - m) / 2 + 1) * 2 ** (m - 1) if isinstance(n, Expression) or isinstance(m, Expression): - return -(sqrt(SR.pi()))*sin(SR.pi()/2*(m+n))*gamma((m+n+1)/2)/gamma((n-m)/2 + 1)*2**(m-1) + return -(sqrt(SR.pi())) * sin(SR.pi() / 2 * (m + n)) * gamma((m + n + 1) / 2) / gamma((n - m) / 2 + 1) * 2 ** (m - 1) def _evalf_(self, n, m, x, parent=None, **kwds): """ @@ -1998,15 +1986,16 @@ def eval_recursive(self, n, m, x, **kwds): 9/2*I*pi - 9/2*log(3) + 14/3 """ from sage.misc.functional import sqrt + if m == n + 1 or n == 0: if m.mod(2).is_zero(): - denom = (1 - x**2)**(m/2) + denom = (1 - x**2) ** (m / 2) else: - denom = sqrt(1 - x**2)*(1 - x**2)**((m-1)/2) + denom = sqrt(1 - x**2) * (1 - x**2) ** ((m - 1) / 2) if m == n + 1: - return (-1)**m*(m-1).factorial()*2**n/denom - return (-1)**m*(m-1).factorial()*((x+1)**m - (x-1)**m)/(2*denom) - return ((n-m+1)*x*gen_legendre_Q(n, m-1, x)-(n+m-1)*gen_legendre_Q(n-1, m-1, x))/sqrt(1-x**2) + return (-1) ** m * (m - 1).factorial() * 2**n / denom + return (-1) ** m * (m - 1).factorial() * ((x + 1) ** m - (x - 1) ** m) / (2 * denom) + return ((n - m + 1) * x * gen_legendre_Q(n, m - 1, x) - (n + m - 1) * gen_legendre_Q(n - 1, m - 1, x)) / sqrt(1 - x**2) def _derivative_(self, n, m, x, *args, **kwds): """ @@ -2032,7 +2021,7 @@ def _derivative_(self, n, m, x, *args, **kwds): if diff_param == 0: raise NotImplementedError("Derivative w.r.t. to the index is not supported.") else: - return ((n-m+1)*gen_legendre_Q(n+1, m, x) - (n+1)*x*gen_legendre_Q(n, m, x))/(x**2 - 1) + return ((n - m + 1) * gen_legendre_Q(n + 1, m, x) - (n + 1) * x * gen_legendre_Q(n, m, x)) / (x**2 - 1) gen_legendre_Q = Func_assoc_legendre_Q() @@ -2090,6 +2079,7 @@ class Func_hermite(GinacFunction): ... RuntimeError: derivative w.r.t. to the index is not supported yet """ + def __init__(self): r""" Init method for the Hermite polynomials. @@ -2112,13 +2102,7 @@ def __init__(self): 5 3 32 x - 160 x + 120 x """ - GinacFunction.__init__(self, "hermite", nargs=2, latex_name=r"H", - conversions={'maxima': 'hermite', - 'mathematica': 'HermiteH', - 'maple': 'HermiteH', - 'fricas': 'hermiteH', - 'sympy': 'hermite'}, - preserved_arg=2) + GinacFunction.__init__(self, "hermite", nargs=2, latex_name=r"H", conversions={'maxima': 'hermite', 'mathematica': 'HermiteH', 'maple': 'HermiteH', 'fricas': 'hermiteH', 'sympy': 'hermite'}, preserved_arg=2) hermite = Func_hermite() @@ -2145,6 +2129,7 @@ class Func_jacobi_P(OrthogonalFunction): sage: jacobi_P(2, 1, 2, 1.2) # needs sage.libs.flint 5.01000000000000 """ + def __init__(self): r""" Init method for the Jacobi polynomials. @@ -2171,12 +2156,7 @@ def __init__(self): ------- 2 """ - OrthogonalFunction.__init__(self, "jacobi_P", nargs=4, latex_name=r"P", - conversions={'maxima': 'jacobi_p', - 'mathematica': 'JacobiP', - 'maple': 'JacobiP', - 'fricas': 'jacobiP', - 'sympy': 'jacobi'}) + OrthogonalFunction.__init__(self, "jacobi_P", nargs=4, latex_name=r"P", conversions={'maxima': 'jacobi_p', 'mathematica': 'JacobiP', 'maple': 'JacobiP', 'fricas': 'jacobiP', 'sympy': 'jacobi'}) def _eval_(self, n, a, b, x): """ @@ -2223,8 +2203,9 @@ def _eval_(self, n, a, b, x): if n not in ZZ: return from .gamma import gamma - s = sum(binomial(n, m) * gamma(a+b+n+m+1) / gamma(a+m+1) * ((x-1)/2)**m for m in range(n+1)) - r = gamma(a+n+1) / factorial(n) / gamma(n+a+b+1) * s + + s = sum(binomial(n, m) * gamma(a + b + n + m + 1) / gamma(a + m + 1) * ((x - 1) / 2) ** m for m in range(n + 1)) + r = gamma(a + n + 1) / factorial(n) / gamma(n + a + b + 1) * s return r.to_gamma().gamma_normalize().normalize() def _evalf_(self, n, a, b, x, **kwds): @@ -2239,11 +2220,12 @@ def _evalf_(self, n, a, b, x, **kwds): 41.103034125334442891187112674 + 31.486722862692829003857755524*I """ from sage.rings.complex_arb import ComplexBallField as CBF + the_parent = kwds.get('parent', None) if the_parent is None: the_parent = parent(x) prec = the_parent.precision() - BF = CBF(prec+5) + BF = CBF(prec + 5) ret = BF(x).jacobi_P(BF(n), BF(a), BF(b)) return SR(ret)._eval_self(the_parent) @@ -2364,6 +2346,7 @@ class Func_ultraspherical(GinacFunction): ... RuntimeError: gegenb_eval: The index n must be a nonnegative integer """ + def __init__(self): r""" Init method for the ultraspherical polynomials. @@ -2375,11 +2358,7 @@ def __init__(self): sage: ultraspherical(x, x, x)._sympy_() # needs sympy sage.symbolic gegenbauer(x, x, x) """ - GinacFunction.__init__(self, "gegenbauer", nargs=3, latex_name=r"C", - conversions={'maxima': 'ultraspherical', - 'mathematica': 'GegenbauerC', - 'maple': 'GegenbauerC', - 'sympy': 'gegenbauer'}) + GinacFunction.__init__(self, "gegenbauer", nargs=3, latex_name=r"C", conversions={'maxima': 'ultraspherical', 'mathematica': 'GegenbauerC', 'maple': 'GegenbauerC', 'sympy': 'gegenbauer'}) ultraspherical = Func_ultraspherical() @@ -2392,6 +2371,7 @@ class Func_laguerre(OrthogonalFunction): - [AS1964]_ 22.5.16, page 778 and page 789. """ + def __init__(self): r""" Init method for the Laguerre polynomials. @@ -2412,12 +2392,19 @@ def __init__(self): sage: loads(dumps(laguerre)) laguerre """ - OrthogonalFunction.__init__(self, "laguerre", nargs=2, latex_name=r"L", - conversions={'maxima': 'laguerre', - 'mathematica': 'LaguerreL', - # 'fricas': 'laguerreL', 3 arguments ? - 'maple': 'LaguerreL', - 'sympy': 'laguerre'}) + OrthogonalFunction.__init__( + self, + "laguerre", + nargs=2, + latex_name=r"L", + conversions={ + 'maxima': 'laguerre', + 'mathematica': 'LaguerreL', + # 'fricas': 'laguerreL', 3 arguments ? + 'maple': 'LaguerreL', + 'sympy': 'laguerre', + }, + ) def _eval_(self, n, x, *args, **kwds): r""" @@ -2441,6 +2428,7 @@ def _eval_(self, n, x, *args, **kwds): """ from sage.functions.log import exp from sage.rings.integer import Integer + ret = self._eval_special_values_(n, x) if ret is not None: return ret @@ -2448,7 +2436,7 @@ def _eval_(self, n, x, *args, **kwds): if n >= 0 and not hasattr(x, 'prec'): return self._pol_laguerre(n, x) if n < 0: - return exp(x)*laguerre(-n-1, -x) + return exp(x) * laguerre(-n - 1, -x) def _eval_special_values_(self, n, x): """ @@ -2487,8 +2475,7 @@ def _pol_laguerre(self, n, x): x = x.pyobject() except TypeError: pass - return SR(sum(binomial(n, k) * (-1)**k / factorial(k) * x**k - for k in range(n + 1))) + return SR(sum(binomial(n, k) * (-1) ** k / factorial(k) * x**k for k in range(n + 1))) def _evalf_(self, n, x, **kwds): """ @@ -2509,7 +2496,8 @@ def _evalf_(self, n, x, **kwds): if n < 0: # work around mpmath issue 307 from sage.functions.log import exp - return exp(x) * _mpmath_utils_call(_mpmath_laguerre, -n-1, 0, -x, parent=the_parent) + + return exp(x) * _mpmath_utils_call(_mpmath_laguerre, -n - 1, 0, -x, parent=the_parent) return _mpmath_utils_call(_mpmath_laguerre, n, 0, x, parent=the_parent) def _derivative_(self, n, x, *args, **kwds): @@ -2533,7 +2521,7 @@ def _derivative_(self, n, x, *args, **kwds): if diff_param == 0: raise NotImplementedError("Derivative w.r.t. to the index is not supported.") if diff_param == 1: - return -gen_laguerre(n-1, 1, x) + return -gen_laguerre(n - 1, 1, x) raise ValueError(f"illegal differentiation parameter {diff_param}") @@ -2546,6 +2534,7 @@ class Func_gen_laguerre(OrthogonalFunction): - [AS1964]_ 22.5.16, page 778 and page 789. """ + def __init__(self): r""" Init method for the Laguerre polynomials. @@ -2567,11 +2556,7 @@ def __init__(self): sage: loads(dumps(gen_laguerre)) gen_laguerre """ - OrthogonalFunction.__init__(self, "gen_laguerre", nargs=3, latex_name=r"L", - conversions={'maxima': 'gen_laguerre', - 'mathematica': 'LaguerreL', - 'maple': 'LaguerreL', - 'sympy': 'assoc_laguerre'}) + OrthogonalFunction.__init__(self, "gen_laguerre", nargs=3, latex_name=r"L", conversions={'maxima': 'gen_laguerre', 'mathematica': 'LaguerreL', 'maple': 'LaguerreL', 'sympy': 'assoc_laguerre'}) def _eval_(self, n, a, x, *args, **kwds): r""" @@ -2592,6 +2577,7 @@ def _eval_(self, n, a, x, *args, **kwds): -1/6*x^3 + 3/2*x^2 - 3*x + 1 """ from sage.rings.integer import Integer + ret = self._eval_special_values_(n, a, x) if ret is not None: return ret @@ -2620,7 +2606,8 @@ def _eval_special_values_(self, n, a, x): return laguerre(n, x) if x == 0: from sage.arith.misc import binomial - return binomial(n+a, n) + + return binomial(n + a, n) def _pol_gen_laguerre(self, n, a, x): """ @@ -2636,8 +2623,7 @@ def _pol_gen_laguerre(self, n, a, x): sage: gen_laguerre(10, 1, 1 + I) # needs sage.symbolic 25189/2100*I + 11792/2835 """ - return sum(binomial(n + a, n - k) * (-1)**k / factorial(k) * x**k - for k in range(n + 1)) + return sum(binomial(n + a, n - k) * (-1) ** k / factorial(k) * x**k for k in range(n + 1)) def _evalf_(self, n, a, x, **kwds): """ @@ -2730,6 +2716,7 @@ class Func_krawtchouk(OrthogonalFunction): ....: == krawtchouk(j, x, n, 1-q) for j in range(n+1)) True """ + def __init__(self): """ Initialize ``self``. @@ -2755,8 +2742,7 @@ def eval_formula(self, k, x, n, p): + 1/6*x^3 + 1/6*(3*n^2*p^2 - 9*n*p^2 + 3*n*p + 6*p^2 - 6*p + 2)*x """ q = 1 - p - return sum((-1)**(k-i) * binomial(n-x, k-i) * binomial(x, i) * p**(k-i) * q**i - for i in range(k+1)) + return sum((-1) ** (k - i) * binomial(n - x, k - i) * binomial(x, i) * p ** (k - i) * q**i for i in range(k + 1)) def _eval_(self, j, x, n, p, *args, **kwds): r""" @@ -2786,7 +2772,8 @@ def _eval_(self, j, x, n, p, *args, **kwds): return None if j not in ZZ or j < 0: from sage.functions.hypergeometric import hypergeometric - return (-1)**j * binomial(n, j) * p**j * hypergeometric([-j, -x], [-n], 1/p) + + return (-1) ** j * binomial(n, j) * p**j * hypergeometric([-j, -x], [-n], 1 / p) try: return self.eval_formula(j, x, n, p) except (TypeError, ValueError): @@ -2825,8 +2812,8 @@ def eval_recursive(self, j, x, n, p, *args, **kwds): if j == 1: return x - n * p q = 1 - p - tm2 = p * q * (n - (j-1) + 1) * krawtchouk.eval_recursive(j-2, x, n, p) - tm1 = (x - p*(n-(j-1)) - (j-1)*q) * krawtchouk.eval_recursive(j-1, x, n, p) + tm2 = p * q * (n - (j - 1) + 1) * krawtchouk.eval_recursive(j - 2, x, n, p) + tm1 = (x - p * (n - (j - 1)) - (j - 1) * q) * krawtchouk.eval_recursive(j - 1, x, n, p) return (tm1 - tm2) / j @@ -2843,6 +2830,7 @@ class Func_meixner(OrthogonalFunction): - ``x`` -- the independent variable `x` - ``b``, ``c`` -- the parameters `b`, `c` """ + def __init__(self): """ Initialize ``self``. @@ -2872,9 +2860,8 @@ def eval_formula(self, n, x, b, c): def P(val, k): return prod(val + j for j in range(k)) - return sum((-1)**k * binomial(n, k) * binomial(x, k) * factorial(k) - * P(x + b, n - k) * c**-k - for k in range(n+1)) + + return sum((-1) ** k * binomial(n, k) * binomial(x, k) * factorial(k) * P(x + b, n - k) * c**-k for k in range(n + 1)) def _eval_(self, n, x, b, c, *args, **kwds): r""" @@ -2911,7 +2898,8 @@ def _eval_(self, n, x, b, c, *args, **kwds): if n not in ZZ or n < 0: from sage.functions.gamma import gamma from sage.functions.hypergeometric import hypergeometric - return gamma(b + n) / gamma(b) * hypergeometric([-n, -x], [b], 1 - 1/c) + + return gamma(b + n) / gamma(b) * hypergeometric([-n, -x], [b], 1 - 1 / c) try: return self.eval_formula(n, x, b, c) except (TypeError, ValueError): @@ -2950,9 +2938,9 @@ def eval_recursive(self, n, x, b, c, *args, **kwds): if n == 0: return parent(x).one() if n == 1: - return (1 - 1/c) * x + b - tm2 = (b+n-1) * (b+n-2) * (n - 1) * meixner.eval_recursive(n-2, x, b, c) - tm1 = (b+n-1) * ((c-1) * x + n-1 + (n-1+b) * c) * meixner.eval_recursive(n-1, x, b, c) + return (1 - 1 / c) * x + b + tm2 = (b + n - 1) * (b + n - 2) * (n - 1) * meixner.eval_recursive(n - 2, x, b, c) + tm1 = (b + n - 1) * ((c - 1) * x + n - 1 + (n - 1 + b) * c) * meixner.eval_recursive(n - 1, x, b, c) return (tm1 - tm2) / (c * (n - 1 + b)) @@ -2993,6 +2981,7 @@ class Func_hahn(OrthogonalFunction): sage: all(M[i,j] == 0 for i in range(3) for j in range(3) if i != j) True """ + def __init__(self): """ Initialize ``self``. @@ -3023,8 +3012,7 @@ def eval_formula(self, k, x, a, b, n): 1 """ P = rising_factorial - return sum(P(-k, i) * P(k+a+b+1, i) * P(-x, i) / (P(a+1, i) * P(-n, i) * factorial(i)) - for i in range(k+1)) + return sum(P(-k, i) * P(k + a + b + 1, i) * P(-x, i) / (P(a + 1, i) * P(-n, i) * factorial(i)) for i in range(k + 1)) def _eval_(self, k, x, a, b, n, *args, **kwds): r""" @@ -3053,7 +3041,8 @@ def _eval_(self, k, x, a, b, n, *args, **kwds): return None if k not in ZZ or k < 0: from sage.functions.hypergeometric import hypergeometric - return hypergeometric([-k, k+a+b+1, -x], [a+1, -n], 1) + + return hypergeometric([-k, k + a + b + 1, -x], [a + 1, -n], 1) try: return self.eval_formula(k, x, a, b, n) except (TypeError, ValueError): @@ -3087,11 +3076,11 @@ def eval_recursive(self, k, x, a, b, n, *args, **kwds): if k == 0: return parent(x).one() if k == 1: - return -(a+b+2) / ((a+1)*n) * x + 1 - A = (k+a+b) * (k+a) * (n-k+1) / ((2*k+a+b-1) * (2*k+a+b)) - C = (k-1) * (k+b-1) * (k+a+b+n) / ((2*k+a+b-2) * (2*k+a+b-1)) - Hm1 = (-x + A + C) * hahn.eval_recursive(k-1, x, a, b, n) - Hm2 = C * hahn.eval_recursive(k-2, x, a, b, n) + return -(a + b + 2) / ((a + 1) * n) * x + 1 + A = (k + a + b) * (k + a) * (n - k + 1) / ((2 * k + a + b - 1) * (2 * k + a + b)) + C = (k - 1) * (k + b - 1) * (k + a + b + n) / ((2 * k + a + b - 2) * (2 * k + a + b - 1)) + Hm1 = (-x + A + C) * hahn.eval_recursive(k - 1, x, a, b, n) + Hm2 = C * hahn.eval_recursive(k - 2, x, a, b, n) return (Hm1 - Hm2) / A diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 610cf1b782b..bda70444c54 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -35,9 +35,7 @@ lazy_import('sage.symbolic.ring', 'SR') -lazy_import('sage.functions.gamma', - ('gamma', 'log_gamma', 'gamma_inc', - 'gamma_inc_lower', 'psi', 'beta'), deprecation=24411) +lazy_import('sage.functions.gamma', ('gamma', 'log_gamma', 'gamma_inc', 'gamma_inc_lower', 'psi', 'beta'), deprecation=24411) class Function_abs(GinacFunction): @@ -122,11 +120,7 @@ def __init__(self): sage: fricas(abs(x)).sage().derivative() # optional - fricas # needs sage.symbolic 1/2*(x + conjugate(x))/abs(x) """ - GinacFunction.__init__(self, "abs", latex_name=r"\mathrm{abs}", - conversions=dict(sympy='Abs', - mathematica='Abs', - giac='abs', - fricas='abs')) + GinacFunction.__init__(self, "abs", latex_name=r"\mathrm{abs}", conversions=dict(sympy='Abs', mathematica='Abs', giac='abs', fricas='abs')) abs = abs_symbolic = Function_abs() @@ -207,6 +201,7 @@ def _eval_floor_ceil(self, x, method, bits=0, **kwds): return Integer(m(x)) if type(x).__module__ == 'numpy': import numpy + m = getattr(numpy, method) return m(x) @@ -399,10 +394,7 @@ def __init__(self): sage: loads(dumps(ceil)) ceil """ - BuiltinFunction.__init__(self, "ceil", - conversions=dict(maxima='ceiling', - sympy='ceiling', - giac='ceil')) + BuiltinFunction.__init__(self, "ceil", conversions=dict(maxima='ceiling', sympy='ceiling', giac='ceil')) def _print_latex_(self, x): r""" @@ -413,7 +405,7 @@ def _print_latex_(self, x): """ return r"\left \lceil %s \right \rceil" % latex(x) - #FIXME: this should be moved to _eval_ + # FIXME: this should be moved to _eval_ def __call__(self, x, **kwds): """ Allow an object of this class to behave like a function. If @@ -569,8 +561,7 @@ def __init__(self): sage: loads(dumps(floor)) floor """ - BuiltinFunction.__init__(self, "floor", - conversions=dict(sympy='floor', giac='floor')) + BuiltinFunction.__init__(self, "floor", conversions=dict(sympy='floor', giac='floor')) def _print_latex_(self, x): r""" @@ -581,7 +572,7 @@ def _print_latex_(self, x): """ return r"\left \lfloor %s \right \rfloor" % latex(x) - #FIXME: this should be moved to _eval_ + # FIXME: this should be moved to _eval_ def __call__(self, x, **kwds): """ Allow an object of this class to behave like a function. If @@ -667,9 +658,7 @@ def __init__(self): sage: x.Order().operator() # needs sage.symbolic Order """ - GinacFunction.__init__(self, "Order", - conversions=dict(), - latex_name=r"\mathcal{O}") + GinacFunction.__init__(self, "Order", conversions=dict(), latex_name=r"\mathcal{O}") def _sympy_(self, arg): """ @@ -690,14 +679,14 @@ def _sympy_(self, arg): sage: cos(x).series(x==pi, 3)._sympy_() # needs sympy sage.symbolic -1 + (pi - x)**2/2 + O((x - pi)**3, (x, pi)) """ - roots = arg.solve(arg.default_variable(), algorithm='sympy', - multiplicities=False, explicit_solutions=True) + roots = arg.solve(arg.default_variable(), algorithm='sympy', multiplicities=False, explicit_solutions=True) if len(roots) == 1: arg = (arg, (roots[0].lhs(), roots[0].rhs())) elif len(roots) > 1: raise ValueError("order term %s has multiple roots" % arg) # else there are no roots, e.g. O(1), so we leave arg unchanged import sympy + return sympy.O(*sympy.sympify(arg, evaluate=False)) @@ -737,9 +726,7 @@ def __init__(self): sage: loads(dumps(floor)) floor """ - BuiltinFunction.__init__(self, "frac", - conversions=dict(sympy='frac'), - latex_name=r"\operatorname{frac}") + BuiltinFunction.__init__(self, "frac", conversions=dict(sympy='frac'), latex_name=r"\operatorname{frac}") def _evalf_(self, x, **kwds): """ @@ -782,9 +769,7 @@ def _eval_(self, x): register_symbol(sqrt, dict(mathematica='Sqrt'), 2) symbol_table['functions']['sqrt'] = sqrt -Function_sqrt = type('deprecated_sqrt', (), - {'__call__': staticmethod(sqrt), - '__setstate__': lambda x, y: None}) +Function_sqrt = type('deprecated_sqrt', (), {'__call__': staticmethod(sqrt), '__setstate__': lambda x, y: None}) class Function_real_nth_root(BuiltinFunction): @@ -830,6 +815,7 @@ class Function_real_nth_root(BuiltinFunction): sage: _.diff() (abs(x)^3)^(1/5)*sgn(x^3) """ + def __init__(self): r""" Initialize. @@ -846,10 +832,7 @@ def __init__(self): sage: f._sympy_() # needs sympy sage.symbolic Piecewise((Abs(x)**(1/3)*sign(x), Eq(im(x), 0)), (x**(1/3), True)) """ - BuiltinFunction.__init__(self, "real_nth_root", nargs=2, - conversions=dict(sympy='real_root', - mathematica='Surd', - maple='surd')) + BuiltinFunction.__init__(self, "real_nth_root", nargs=2, conversions=dict(sympy='real_root', mathematica='Surd', maple='surd')) def _print_latex_(self, base, exp): r""" @@ -860,7 +843,7 @@ def _print_latex_(self, base, exp): sage: latex(real_nth_root(x^2 + x, 3)) # needs sage.symbolic {\left(x^{2} + x\right)}^{\frac{1}{3}} """ - return latex(base**(1/exp)) + return latex(base ** (1 / exp)) def _evalf_(self, base, exp, parent=None): """ @@ -896,7 +879,7 @@ def _evalf_(self, base, exp, parent=None): raise ValueError('no real nth root of negative real number with even n') base = -base - r = base**(1/exp) + r = base ** (1 / exp) if negative: return -r @@ -955,7 +938,7 @@ def _derivative_(self, base, exp, diff_param=None): sage: f.diff() -1/4*real_nth_root(-1/x^3, 4) """ - return 1/exp * self(base, exp)**(1-exp) + return 1 / exp * self(base, exp) ** (1 - exp) real_nth_root = Function_real_nth_root() @@ -1016,11 +999,7 @@ def __init__(self): sage: arg(2.0+3*i) # needs sage.symbolic 0.982793723247329 """ - BuiltinFunction.__init__(self, "arg", - conversions=dict(maxima='carg', - mathematica='Arg', - sympy='arg', - giac='arg')) + BuiltinFunction.__init__(self, "arg", conversions=dict(maxima='carg', mathematica='Arg', sympy='arg', giac='arg')) def _eval_(self, x): """ @@ -1046,13 +1025,13 @@ def _eval_(self, x): sage: arg(sqrt(2)+i) arg(sqrt(2) + I) """ - if isinstance(x,Expression): + if isinstance(x, Expression): if x.is_trivial_zero(): return x elif not x: return x else: - return arctan2(imag_part(x),real_part(x)) + return arctan2(imag_part(x), real_part(x)) def _evalf_(self, x, parent=None, algorithm=None): """ @@ -1189,12 +1168,7 @@ def __init__(self): sage: real(sqrt(sin(x))).subs(x==0) # needs sage.symbolic 0 """ - GinacFunction.__init__(self, "real_part", - conversions=dict(maxima='realpart', - sympy='re', - mathematica='Re', - giac='re', fricas='real'), - alt_name='real') + GinacFunction.__init__(self, "real_part", conversions=dict(maxima='realpart', sympy='re', mathematica='Re', giac='re', fricas='real'), alt_name='real') def __call__(self, x, **kwargs): r""" @@ -1251,13 +1225,7 @@ def __init__(self): sage: latex(f(x).imag()) # needs sage.symbolic \Im \left( f\left(x\right) \right) """ - GinacFunction.__init__(self, "imag_part", - conversions=dict(maxima='imagpart', - sympy='im', - mathematica='Im', - fricas='imag', - giac='im'), - alt_name='imag') + GinacFunction.__init__(self, "imag_part", conversions=dict(maxima='imagpart', sympy='im', mathematica='Im', fricas='imag', giac='im'), alt_name='imag') def __call__(self, x, **kwargs): r""" @@ -1356,11 +1324,7 @@ def __init__(self): sage: loads(dumps(conjugate)) conjugate """ - GinacFunction.__init__(self, "conjugate", - conversions=dict(sympy='conjugate', - giac='conj', - mathematica='Conjugate', - fricas='conjugate')) + GinacFunction.__init__(self, "conjugate", conversions=dict(sympy='conjugate', giac='conj', mathematica='Conjugate', fricas='conjugate')) conjugate = Function_conjugate() @@ -1497,12 +1461,7 @@ def __init__(self): sage: loads(dumps(factorial)) factorial """ - GinacFunction.__init__(self, "factorial", latex_name='{\\rm factorial}', - conversions=dict(maxima='factorial', - mathematica='Factorial', - sympy='factorial', - fricas='factorial', - giac='factorial')) + GinacFunction.__init__(self, "factorial", latex_name='{\\rm factorial}', conversions=dict(maxima='factorial', mathematica='Factorial', sympy='factorial', fricas='factorial', giac='factorial')) def _eval_(self, x): """ @@ -1550,11 +1509,13 @@ def _eval_(self, x): return elif isinstance(x, Rational): from sage.functions.gamma import gamma + return gamma(x + 1) elif isinstance(x, Element) and hasattr(x.parent(), 'precision'): return (x + 1).gamma() elif self._is_numerical(x): from sage.functions.gamma import gamma + return gamma(x + 1) @@ -1664,12 +1625,7 @@ def __init__(self): sage: loads(dumps(binomial(n, k))) # needs sage.symbolic binomial(n, k) """ - GinacFunction.__init__(self, "binomial", nargs=2, preserved_arg=1, - conversions=dict(maxima='binomial', - mathematica='Binomial', - sympy='binomial', - fricas='binomial', - giac='comb')) + GinacFunction.__init__(self, "binomial", nargs=2, preserved_arg=1, conversions=dict(maxima='binomial', mathematica='Binomial', sympy='binomial', fricas='binomial', giac='comb')) def _binomial_sym(self, n, k): """ @@ -1710,6 +1666,7 @@ def _binomial_sym(self, n, k): return n from sage.misc.misc_c import prod + return prod(n - i for i in range(k)) / factorial(k) def _method_arguments(self, n, k): @@ -1795,6 +1752,7 @@ class Function_sum(BuiltinFunction): sage: r.unhold() # needs sage.symbolic 55 """ + def __init__(self): """ EXAMPLES:: @@ -1803,8 +1761,7 @@ def __init__(self): sage: maxima(ssum(x, x, 1, 10)) # needs sage.symbolic 55 """ - BuiltinFunction.__init__(self, "sum", nargs=4, - conversions=dict(maxima='sum')) + BuiltinFunction.__init__(self, "sum", nargs=4, conversions=dict(maxima='sum')) def _print_latex_(self, x, var, a, b): r""" @@ -1814,8 +1771,7 @@ def _print_latex_(self, x, var, a, b): sage: latex(ssum(x^2, x, 1, 10)) # needs sage.symbolic {\sum_{x=1}^{10} x^{2}} """ - return r"{{\sum_{{{}={}}}^{{{}}} {}}}".format(latex(var), latex(a), - latex(b), latex(x)) + return r"{{\sum_{{{}={}}}^{{{}}} {}}}".format(latex(var), latex(a), latex(b), latex(x)) def _sympy_(self, term, k, a, n): """ @@ -1834,6 +1790,7 @@ def _sympy_(self, term, k, a, n): n**2/2 + n/2 """ import sympy + return sympy.Sum(term, (k, a, n)) @@ -1852,6 +1809,7 @@ class Function_prod(BuiltinFunction): sage: r.unhold() # needs sage.symbolic 3628800 """ + def __init__(self): """ EXAMPLES:: @@ -1871,9 +1829,7 @@ def __init__(self): sage: giac(sprod(m, m, 1, n)).sage() # needs giac factorial(n) """ - BuiltinFunction.__init__(self, "product", nargs=4, - conversions=dict(maxima='product', - sympy='Product', giac='product')) + BuiltinFunction.__init__(self, "product", nargs=4, conversions=dict(maxima='product', sympy='Product', giac='product')) def _print_latex_(self, x, var, a, b): r""" @@ -1883,8 +1839,7 @@ def _print_latex_(self, x, var, a, b): sage: latex(sprod(x^2, x, 1, 10)) # needs sage.symbolic {\prod_{x=1}^{10} x^{2}} """ - return r"{{\prod_{{{}={}}}^{{{}}} {}}}".format(latex(var), latex(a), - latex(b), latex(x)) + return r"{{\prod_{{{}={}}}^{{{}}} {}}}".format(latex(var), latex(a), latex(b), latex(x)) def _sympy_(self, term, k, a, n): """ @@ -1899,6 +1854,7 @@ def _sympy_(self, term, k, a, n): Product(k**2 + k + 1, (k, 1, n)) """ import sympy + return sympy.Product(term, (k, a, n)) @@ -1930,6 +1886,7 @@ class Function_limit(BuiltinFunction): sage: slimit(1/x, x, 0, minus) limit(1/x, x, 0, minus) """ + def __init__(self): """ EXAMPLES:: @@ -1938,8 +1895,7 @@ def __init__(self): sage: maxima(slimit(1/x, x, +oo)) # needs sage.symbolic 0 """ - BuiltinFunction.__init__(self, "limit", nargs=0, - conversions=dict(maxima='limit')) + BuiltinFunction.__init__(self, "limit", nargs=0, conversions=dict(maxima='limit')) def _latex_(self): r""" @@ -2004,8 +1960,7 @@ def _print_latex_(self, ex, var, to, direction=''): dir_str = '^+' else: dir_str = '' - return r"\lim_{{{} \to {}{}}}\, {}".format(latex(var), - latex(to), dir_str, latex(ex)) + return r"\lim_{{{} \to {}{}}}\, {}".format(latex(var), latex(to), dir_str, latex(ex)) symbolic_limit = Function_limit() @@ -2049,6 +2004,7 @@ class Function_cases(GinacFunction): sage: ex.subs(x==0, y==1) pi """ + def __init__(self): """ EXAMPLES:: @@ -2077,8 +2033,7 @@ def __call__(self, l, **kwargs): ... RuntimeError: cases argument not a sequence """ - return GinacFunction.__call__(self, - SR._force_pyobject(l), **kwargs) + return GinacFunction.__call__(self, SR._force_pyobject(l), **kwargs) def _print_latex_(self, l, **kwargs): r""" @@ -2101,8 +2056,8 @@ def _print_latex_(self, l, **kwargs): str = r"\begin{cases}" for pair in l: left = None - if (isinstance(pair, tuple)): - right,left = pair + if isinstance(pair, tuple): + right, left = pair else: right = pair str += r"{%s} & {%s}\\" % (latex(left), latex(right)) @@ -2118,6 +2073,7 @@ def _sympy_(self, l): sage: assert ex == ex._sympy_()._sage_() # needs sympy sage.symbolic """ from sympy import Piecewise as pw + args = [] for tup in l.operands(): cond, expr = tup.operands() @@ -2154,6 +2110,7 @@ class Function_crootof(BuiltinFunction): sage: (c^6 + c + 1).n(100) < 1e-25 True """ + def __init__(self): """ EXAMPLES:: @@ -2161,9 +2118,7 @@ def __init__(self): sage: loads(dumps(complex_root_of)) complex_root_of """ - BuiltinFunction.__init__(self, "complex_root_of", nargs=2, - conversions=dict(sympy='CRootOf'), - evalf_params_first=False) + BuiltinFunction.__init__(self, "complex_root_of", nargs=2, conversions=dict(sympy='CRootOf'), evalf_params_first=False) def _eval_(self, poly, index): """ @@ -2213,6 +2168,7 @@ def _evalf_(self, poly, index, parent=None, algorithm=None): """ from mpmath.libmp import prec_to_dps from sympy.polys import CRootOf, Poly + try: prec = parent.precision() except AttributeError: @@ -2246,6 +2202,7 @@ class Function_elementof(BuiltinFunction): sage: element_of(x, SR(Set([4,6,8]))) element_of(x, {8, 4, 6}) """ + def __init__(self): """ EXAMPLES:: @@ -2254,8 +2211,7 @@ def __init__(self): sage: loads(dumps(element_of)) element_of """ - BuiltinFunction.__init__(self, "element_of", nargs=2, - conversions=dict(sympy='Contains')) + BuiltinFunction.__init__(self, "element_of", nargs=2, conversions=dict(sympy='Contains')) def _eval_(self, x, s): """ @@ -2270,6 +2226,7 @@ def _eval_(self, x, s): ValueError: not a set: 0 """ from sage.categories.sets_cat import Sets + if s not in Sets(): raise ValueError("not a set: {}".format(s)) diff --git a/src/sage/functions/piecewise.py b/src/sage/functions/piecewise.py index 22cd58ae9d9..c9a9f576860 100644 --- a/src/sage/functions/piecewise.py +++ b/src/sage/functions/piecewise.py @@ -95,9 +95,7 @@ def __init__(self): sage: f(-1/2) 1/2*y^2 """ - BuiltinFunction.__init__(self, "piecewise", - latex_name='piecewise', - conversions=dict(), nargs=2) + BuiltinFunction.__init__(self, "piecewise", latex_name='piecewise', conversions=dict(), nargs=2) def __call__(self, function_pieces, **kwds): r""" @@ -136,6 +134,7 @@ def __call__(self, function_pieces, **kwds): (-1, 0, 1) """ from types import FunctionType + var = kwds.pop('var', None) parameters = [] domain_list = [] @@ -178,8 +177,7 @@ def _print_(self, parameters, variable): """ s = 'piecewise(' # NOTE : could use ⟼ instead of |--> - args = (f'{variable}|-->{func} on {domain}' - for domain, func in parameters) + args = (f'{variable}|-->{func} on {domain}' for domain, func in parameters) s += ', '.join(args) + f'; {variable})' return s @@ -220,8 +218,7 @@ def _subs_(self, subs_map, options, parameters, x): point = subs_map.apply_to(x, 0) if point.is_symbol(): # avoid to compare with x (see #37925) - new_params = [(domain, subs_map.apply_to(func, 0)) - for domain, func in parameters] + new_params = [(domain, subs_map.apply_to(func, 0)) for domain, func in parameters] return piecewise(new_params, var=point) if (point.is_numeric() or point.is_constant()) and point.is_real(): @@ -258,10 +255,12 @@ def in_operands(ex): sage: piecewise.in_operands(1+sin(0*f)) False """ + def is_piecewise(ex): if ex.operator() is piecewise: return True return any(is_piecewise(op) for op in ex.operands()) + return is_piecewise(ex) @staticmethod @@ -312,9 +311,7 @@ def _tderivative_(self, parameters, variable, *args, **kwds): sage: f.diff() piecewise(x|-->0 on (-oo, -1), x|-->-2*x*e^(1/(x^2 - 1))/(x^2 - 1)^2 on (-1, 1), x|-->0 on (1, +oo); x) """ - return piecewise([(domain, func.derivative(*args)) - for domain, func in parameters], - var=variable) + return piecewise([(domain, func.derivative(*args)) for domain, func in parameters], var=variable) class EvaluationMethods: @@ -334,9 +331,7 @@ def __pow__(self, parameters, variable, n): sage: (f^2).integral(definite=True) 4/3 """ - return piecewise(zip(self.domains(), - [ex**n for ex in self.expressions()]), - var=variable) + return piecewise(zip(self.domains(), [ex**n for ex in self.expressions()]), var=variable) def expression_at(self, parameters, variable, point): """ @@ -597,8 +592,7 @@ def unextend_zero(self, parameters, variable): sage: bool(h == f) True """ - result = [(domain, func) for domain, func in parameters - if func != 0] + result = [(domain, func) for domain, func in parameters if func != 0] if len(result) == len(self): return self return piecewise(result, var=variable) @@ -619,8 +613,7 @@ def pieces(self, parameters, variable): (piecewise(x|-->-x on (-1, 0); x), piecewise(x|-->x on [0, 1]; x)) """ - return tuple(piecewise([(domain, func)], var=variable) - for domain, func in parameters) + return tuple(piecewise([(domain, func)], var=variable) for domain, func in parameters) def end_points(self, parameters, variable) -> list: """ @@ -663,9 +656,7 @@ def piecewise_add(self, parameters, variable, other): x|-->x + 1 on (1/2, 1], x|-->x on (1, 2) ∪ (2, 3); x) """ - points = ([minus_infinity] + - sorted(set(self.end_points() + other.end_points())) + - [infinity]) + points = [minus_infinity] + sorted(set(self.end_points() + other.end_points())) + [infinity] domain = [] funcs = [] contains_lower = False @@ -673,10 +664,8 @@ def piecewise_add(self, parameters, variable, other): for i in range(len(points) - 1): a, b = points[i], points[i + 1] try: - contains_lower = (self.domain().contains(a) or - other.domain().contains(a)) and not contains_upper - contains_upper = (self.domain().contains(b) or - other.domain().contains(b)) + contains_lower = (self.domain().contains(a) or other.domain().contains(a)) and not contains_upper + contains_upper = self.domain().contains(b) or other.domain().contains(b) if contains_lower: if contains_upper: rs = RealSet.closed(a, b) @@ -873,6 +862,7 @@ def integral(self, parameters, variable, x=None, a=None, b=None, definite=False, # after the first piece. from sage.symbolic.assumptions import assume, forget + for domain, fun in parameters: for interval in domain: start = interval.lower() @@ -923,6 +913,7 @@ def critical_points(self, parameters, variable): True """ from sage.calculus.calculus import maxima + x = self.default_variable() crit_pts = [] for domain, f in parameters: @@ -1012,6 +1003,7 @@ def convolution(self, parameters, variable, other): x|-->1/2*x^2 - 3*x + 9/2 on (2, 3]; x) """ from sage.symbolic.integration.integral import definite_integral + f = self g = other if not f.end_points() or not g.end_points(): @@ -1057,9 +1049,7 @@ def convolution(self, parameters, variable, other): i1 = f0.subs({variable: uu}) i2 = g0.subs({variable: variable - uu}) expr = i1 * i2 - h = piecewise([[(start, stop), - definite_integral(expr, uu, mini, maxi)] - for start, stop, mini, maxi in todo]) + h = piecewise([[(start, stop), definite_integral(expr, uu, mini, maxi)] for start, stop, mini, maxi in todo]) flat_zero = piecewise([[(minus_infinity, infinity), 0]]) return (flat_zero.piecewise_add(h)).unextend_zero() # why ? @@ -1106,19 +1096,20 @@ def trapezoid(self, parameters, variable, N): y|-->7/2*y - 5/2 on (1, 3/2), y|-->-7/2*y + 8 on (3/2, 2); y) """ + def func(x0, x1): f0, f1 = self(x0), self(x1) - return [[(x0, x1), f0 + (f1-f0) * (x1-x0)**(-1) - * (self.default_variable()-x0)]] + return [[(x0, x1), f0 + (f1 - f0) * (x1 - x0) ** (-1) * (self.default_variable() - x0)]] + rsum = [] for domain, f in parameters: for interval in domain: a = interval.lower() b = interval.upper() - h = (b-a)/N + h = (b - a) / N for i in range(N): - x0 = a+i*h - x1 = a+(i+1)*h + x0 = a + i * h + x1 = a + (i + 1) * h rsum += func(x0, x1) return piecewise(rsum) @@ -1177,8 +1168,7 @@ def laplace(self, parameters, variable, x='x', s='t'): forget(s > 0) return result - def fourier_series_cosine_coefficient(self, parameters, - variable, n, L=None): + def fourier_series_cosine_coefficient(self, parameters, variable, n, L=None): r""" Return the `n`-th cosine coefficient of the Fourier series of the periodic function `f` extending the piecewise-defined @@ -1254,25 +1244,23 @@ def fourier_series_cosine_coefficient(self, parameters, """ from sage.functions.trig import cos from sage.symbolic.constants import pi + L0 = (self.domain().sup() - self.domain().inf()) / 2 if not L: L = L0 else: m = L0 / L if not (m.is_integer() and m > 0): - raise ValueError("the width of the domain of " + - "{} is not a multiple ".format(self) + - "of the given period") + raise ValueError("the width of the domain of " + "{} is not a multiple ".format(self) + "of the given period") result = 0 for domain, f in parameters: for interval in domain: a = interval.lower() b = interval.upper() - result += (f*cos(pi*variable*n/L)).integrate(variable, a, b) + result += (f * cos(pi * variable * n / L)).integrate(variable, a, b) return SR(result / L0).simplify_trig() - def fourier_series_sine_coefficient(self, parameters, variable, - n, L=None): + def fourier_series_sine_coefficient(self, parameters, variable, n, L=None): r""" Return the `n`-th sine coefficient of the Fourier series of the periodic function `f` extending the piecewise-defined @@ -1342,25 +1330,23 @@ def fourier_series_sine_coefficient(self, parameters, variable, """ from sage.functions.trig import sin from sage.symbolic.constants import pi + L0 = (self.domain().sup() - self.domain().inf()) / 2 if not L: L = L0 else: m = L0 / L if not (m.is_integer() and m > 0): - raise ValueError("the width of the domain of " + - "{} is not a multiple ".format(self) + - "of the given period") + raise ValueError("the width of the domain of " + "{} is not a multiple ".format(self) + "of the given period") result = 0 for domain, f in parameters: for interval in domain: a = interval.lower() b = interval.upper() - result += (f*sin(pi*variable*n/L)).integrate(variable, a, b) - return SR(result/L0).simplify_trig() + result += (f * sin(pi * variable * n / L)).integrate(variable, a, b) + return SR(result / L0).simplify_trig() - def fourier_series_partial_sum(self, parameters, variable, N, - L=None): + def fourier_series_partial_sum(self, parameters, variable, N, L=None): r""" Return the partial sum up to a given order of the Fourier series of the periodic function `f` extending the piecewise-defined @@ -1436,9 +1422,7 @@ def fourier_series_partial_sum(self, parameters, variable, N, L = (self.domain().sup() - self.domain().inf()) / 2 x = self.default_variable() a0 = self.fourier_series_cosine_coefficient(0, L) - result = a0/2 + sum([(self.fourier_series_cosine_coefficient(n, L)*cos(n*pi*x/L) + - self.fourier_series_sine_coefficient(n, L)*sin(n*pi*x/L)) - for n in srange(1, N+1)]) + result = a0 / 2 + sum([(self.fourier_series_cosine_coefficient(n, L) * cos(n * pi * x / L) + self.fourier_series_sine_coefficient(n, L) * sin(n * pi * x / L)) for n in srange(1, N + 1)]) return SR(result).expand() def _sympy_(self, parameters, variable): @@ -1460,9 +1444,8 @@ def _sympy_(self, parameters, variable): Piecewise((-1/x**2, (x > -100) & (x < -2)), (-sin(x), x > 1)) """ from sympy import Piecewise as pw - args = [(func._sympy_(), - domain._sympy_condition_(variable)) - for domain, func in parameters] + + args = [(func._sympy_(), domain._sympy_condition_(variable)) for domain, func in parameters] return pw(*args) def _giac_init_(self, parameters, variable): @@ -1495,9 +1478,8 @@ def _giac_init_(self, parameters, variable): piecewise(((sageVARx>=0) and (1>=sageVARx)),sageVARx,((sageVARx>1) and (2>sageVARx)),sageVARx*3) """ from sage.misc.flatten import flatten - args = [(domain._giac_condition_(variable), - func._giac_init_()) - for domain, func in parameters] + + args = [(domain._giac_condition_(variable), func._giac_init_()) for domain, func in parameters] args = ",".join(flatten(args)) return f"piecewise({args})" diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index d2e8dd4f41d..5a1191d2951 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -158,10 +158,7 @@ lazy_import('sage.symbolic.constants', ['I', 'pi']) lazy_import('sage.libs.mpmath.utils', 'call', as_='_mpmath_utils_call') -lazy_import('mpmath', - ['spherharm', 'ellipe', 'ellipf', 'ellipk', 'ellippi'], - as_=['_mpmath_spherharm', '_mpmath_ellipe', '_mpmath_ellipf', - '_mpmath_ellipk', '_mpmath_ellippi']) +lazy_import('mpmath', ['spherharm', 'ellipe', 'ellipf', 'ellipk', 'ellippi'], as_=['_mpmath_spherharm', '_mpmath_ellipe', '_mpmath_ellipf', '_mpmath_ellipk', '_mpmath_ellippi']) class SphericalHarmonic(BuiltinFunction): @@ -242,6 +239,7 @@ class SphericalHarmonic(BuiltinFunction): - :wikipedia:`Spherical_harmonics` """ + def __init__(self): r""" TESTS:: @@ -250,12 +248,7 @@ def __init__(self): sage: spherical_harmonic(n, m, theta, phi)._sympy_() # needs sympy sage.symbolic Ynm(n, m, theta, phi) """ - BuiltinFunction.__init__(self, 'spherical_harmonic', nargs=4, - conversions=dict( - maple='SphericalY', - mathematica='SphericalHarmonicY', - maxima='spherical_harmonic', - sympy='Ynm')) + BuiltinFunction.__init__(self, 'spherical_harmonic', nargs=4, conversions=dict(maple='SphericalY', mathematica='SphericalHarmonicY', maxima='spherical_harmonic', sympy='Ynm')) def _eval_(self, n, m, theta, phi, **kwargs): r""" @@ -307,14 +300,13 @@ def _eval_(self, n, m, theta, phi, **kwargs): if abs(m) > n: return ZZ(0) if m == 0 and theta.is_zero(): - return sqrt((2*n+1)/4/pi) + return sqrt((2 * n + 1) / 4 / pi) from sage.arith.misc import factorial from sage.functions.trig import cos from sage.functions.orthogonal_polys import gen_legendre_P - res = (sqrt(factorial(n-m) * (2*n+1) / (4*pi * factorial(n+m))) - * gen_legendre_P(n, m, cos(theta)) - * exp(I*m*phi)).simplify_trig() - res = res.substitute({sqrt(sin(theta)**2): sin(theta)}) + + res = (sqrt(factorial(n - m) * (2 * n + 1) / (4 * pi * factorial(n + m))) * gen_legendre_P(n, m, cos(theta)) * exp(I * m * phi)).simplify_trig() + res = res.substitute({sqrt(sin(theta) ** 2): sin(theta)}) return res def _evalf_(self, n, m, theta, phi, parent, **kwds): @@ -364,14 +356,11 @@ def _derivative_(self, n, m, theta, phi, diff_param): True """ if diff_param == 2: - return (m * cot(theta) * spherical_harmonic(n, m, theta, phi) + - sqrt((n - m) * (n + m + 1)) * exp(-I * phi) * - spherical_harmonic(n, m + 1, theta, phi)) + return m * cot(theta) * spherical_harmonic(n, m, theta, phi) + sqrt((n - m) * (n + m + 1)) * exp(-I * phi) * spherical_harmonic(n, m + 1, theta, phi) if diff_param == 3: return I * m * spherical_harmonic(n, m, theta, phi) - raise ValueError('only derivative with respect to theta or phi' - ' supported') + raise ValueError('only derivative with respect to theta or phi' ' supported') def _latex_(self): r""" @@ -390,8 +379,7 @@ def _print_latex_(self, n, m, theta, phi): sage: latex(spherical_harmonic(3, 2, x, y, hold=True)) # needs sage.symbolic Y_{3}^{2}\left(x, y\right) """ - return r"Y_{{{}}}^{{{}}}\left({}, {}\right)".format( - latex(n), latex(m), latex(theta), latex(phi)) + return r"Y_{{{}}}^{{{}}}\left({}, {}\right)".format(latex(n), latex(m), latex(theta), latex(phi)) spherical_harmonic = SphericalHarmonic() @@ -399,6 +387,7 @@ def _print_latex_(self, n, m, theta, phi): # elliptic functions and integrals + def elliptic_j(z, prec=53): r""" Return the elliptic modular `j`-function evaluated at `z`. @@ -453,17 +442,20 @@ def elliptic_j(z, prec=53): CC = z.parent() if not isinstance(CC, sage.rings.abc.ComplexField): from sage.rings.complex_mpfr import ComplexField + CC = ComplexField(prec) try: z = CC(z) except ValueError: raise ValueError("elliptic_j only defined for complex arguments.") from sage.libs.pari import pari + return CC(pari(z).ellj()) # elliptic integrals + class EllipticE(BuiltinFunction): r""" Return the incomplete elliptic integral of the @@ -501,6 +493,7 @@ class EllipticE(BuiltinFunction): - :wikipedia:`Jacobi_elliptic_functions` """ + def __init__(self): r""" TESTS:: @@ -538,13 +531,14 @@ def __init__(self): 0.000000000000000, 0.000000000000000] """ - BuiltinFunction.__init__(self, 'elliptic_e', nargs=2, - # Maple conversion left out since it uses - # k instead of m as the second argument - conversions=dict(mathematica='EllipticE', - maxima='elliptic_e', - sympy='elliptic_e', - fricas='((x,y)+->ellipticE(sin(x), y))')) + BuiltinFunction.__init__( + self, + 'elliptic_e', + nargs=2, + # Maple conversion left out since it uses + # k instead of m as the second argument + conversions=dict(mathematica='EllipticE', maxima='elliptic_e', sympy='elliptic_e', fricas='((x,y)+->ellipticE(sin(x), y))'), + ) def _eval_(self, z, m): """ @@ -645,6 +639,7 @@ class EllipticEC(BuiltinFunction): - :wikipedia:`Elliptic_integral#Complete_elliptic_integral_of_the_second_kind` """ + def __init__(self): """ EXAMPLES:: @@ -664,11 +659,7 @@ def __init__(self): sage: fricas.ellipticE(0.5).sage() # abs tol 1e-8 # optional - fricas, needs sage.symbolic 1.3506438810476755025201749 """ - BuiltinFunction.__init__(self, 'elliptic_ec', nargs=1, latex_name='E', - conversions=dict(mathematica='EllipticE', - maxima='elliptic_ec', - sympy='elliptic_e', - fricas='ellipticE')) + BuiltinFunction.__init__(self, 'elliptic_ec', nargs=1, latex_name='E', conversions=dict(mathematica='EllipticE', maxima='elliptic_ec', sympy='elliptic_e', fricas='ellipticE')) def _eval_(self, x): """ @@ -742,6 +733,7 @@ class EllipticEU(BuiltinFunction): - :wikipedia:`Jacobi_elliptic_functions` """ + def __init__(self): r""" EXAMPLES:: @@ -749,8 +741,7 @@ def __init__(self): sage: loads(dumps(elliptic_eu)) elliptic_eu """ - BuiltinFunction.__init__(self, 'elliptic_eu', nargs=2, - conversions=dict(maxima='elliptic_eu')) + BuiltinFunction.__init__(self, 'elliptic_eu', nargs=2, conversions=dict(maxima='elliptic_eu')) def _eval_(self, u, m): """ @@ -788,17 +779,11 @@ def _derivative_(self, u, m, diff_param): - elliptic_eu(x, m)*jacobi_dn(x, m))*sqrt(-m*jacobi_sn(x, m)^2 + 1)/((m - 1)*m) """ from sage.functions.jacobi import jacobi, jacobi_am + if diff_param == 0: - return (sqrt(-m * jacobi('sn', u, m) ** Integer(2) + - Integer(1)) * jacobi('dn', u, m)) + return sqrt(-m * jacobi('sn', u, m) ** Integer(2) + Integer(1)) * jacobi('dn', u, m) if diff_param == 1: - return (Integer(1) / Integer(2) * - (elliptic_eu(u, m) - elliptic_f(jacobi_am(u, m), m)) / m - - Integer(1) / Integer(2) * sqrt(-m * jacobi('sn', u, m) ** - Integer(2) + Integer(1)) * (m * jacobi('sn', u, m) * - jacobi('cn', u, m) - (m - Integer(1)) * u - - elliptic_eu(u, m) * jacobi('dn', u, m)) / - ((m - Integer(1)) * m)) + return Integer(1) / Integer(2) * (elliptic_eu(u, m) - elliptic_f(jacobi_am(u, m), m)) / m - Integer(1) / Integer(2) * sqrt(-m * jacobi('sn', u, m) ** Integer(2) + Integer(1)) * (m * jacobi('sn', u, m) * jacobi('cn', u, m) - (m - Integer(1)) * u - elliptic_eu(u, m) * jacobi('dn', u, m)) / ((m - Integer(1)) * m) def _print_latex_(self, u, m): """ @@ -824,6 +809,7 @@ def elliptic_eu_f(u, m): mpf('0.49605455128659691') """ from mpmath import mp as ctx + prec = ctx.prec try: u = ctx.convert(u) @@ -866,6 +852,7 @@ class EllipticF(BuiltinFunction): - :wikipedia:`Elliptic_integral#Incomplete_elliptic_integral_of_the_first_kind` """ + def __init__(self): r""" EXAMPLES:: @@ -903,11 +890,7 @@ def __init__(self): 0.000000000000000, 0.000000000000000] """ - BuiltinFunction.__init__(self, 'elliptic_f', nargs=2, - conversions=dict(mathematica='EllipticF', - maxima='elliptic_f', - fricas='((x,y)+->ellipticF(sin(x), y))', - sympy='elliptic_f')) + BuiltinFunction.__init__(self, 'elliptic_f', nargs=2, conversions=dict(mathematica='EllipticF', maxima='elliptic_f', fricas='((x,y)+->ellipticF(sin(x), y))', sympy='elliptic_f')) def _eval_(self, z, m): """ @@ -959,11 +942,7 @@ def _derivative_(self, z, m, diff_param): if diff_param == 0: return Integer(1) / sqrt(Integer(1) - m * sin(z) ** Integer(2)) if diff_param == 1: - return (elliptic_e(z, m) / (Integer(2) * (Integer(1) - m) * m) - - elliptic_f(z, m) / (Integer(2) * m) - - (sin(Integer(2) * z) / - (Integer(4) * (Integer(1) - m) * - sqrt(Integer(1) - m * sin(z) ** Integer(2))))) + return elliptic_e(z, m) / (Integer(2) * (Integer(1) - m) * m) - elliptic_f(z, m) / (Integer(2) * m) - (sin(Integer(2) * z) / (Integer(4) * (Integer(1) - m) * sqrt(Integer(1) - m * sin(z) ** Integer(2)))) def _print_latex_(self, z, m): r""" @@ -1003,6 +982,7 @@ class EllipticKC(BuiltinFunction): - :wikipedia:`Elliptic_integral#Incomplete_elliptic_integral_of_the_first_kind` """ + def __init__(self): """ EXAMPLES:: @@ -1022,11 +1002,7 @@ def __init__(self): sage: fricas.ellipticK(0.3).sage() # abs tol 1e-3 # optional - fricas, needs sage.symbolic 1.7138894481787910555457043 """ - BuiltinFunction.__init__(self, 'elliptic_kc', nargs=1, latex_name='K', - conversions=dict(mathematica='EllipticK', - maxima='elliptic_kc', - sympy='elliptic_k', - fricas='ellipticK')) + BuiltinFunction.__init__(self, 'elliptic_kc', nargs=1, latex_name='K', conversions=dict(mathematica='EllipticK', maxima='elliptic_kc', sympy='elliptic_k', fricas='ellipticK')) def _eval_(self, z): """ @@ -1074,8 +1050,7 @@ def _derivative_(self, z, diff_param): -1/2*((x - 1)*elliptic_kc(x) + elliptic_ec(x))/((x - 1)*x) """ - return ((elliptic_ec(z) - (Integer(1) - z) * elliptic_kc(z)) / - (Integer(2) * (Integer(1) - z) * z)) + return (elliptic_ec(z) - (Integer(1) - z) * elliptic_kc(z)) / (Integer(2) * (Integer(1) - z) * z) elliptic_kc = EllipticKC() @@ -1114,6 +1089,7 @@ class EllipticPi(BuiltinFunction): - :wikipedia:`Elliptic_integral#Incomplete_elliptic_integral_of_the_third_kind` """ + def __init__(self): """ EXAMPLES:: @@ -1123,11 +1099,17 @@ def __init__(self): sage: elliptic_pi(x, pi/4, 1)._sympy_() # needs sympy sage.symbolic elliptic_pi(x, pi/4, 1) """ - BuiltinFunction.__init__(self, 'elliptic_pi', nargs=3, - conversions=dict(mathematica='EllipticPi', - maxima='EllipticPi', - # fricas='ellipticPi', doubt - sympy='elliptic_pi')) + BuiltinFunction.__init__( + self, + 'elliptic_pi', + nargs=3, + conversions=dict( + mathematica='EllipticPi', + maxima='EllipticPi', + # fricas='ellipticPi', doubt + sympy='elliptic_pi', + ), + ) def _eval_(self, n, z, m): """ @@ -1177,22 +1159,11 @@ def _derivative_(self, n, z, m, diff_param): - 2*elliptic_pi(n, z, m))/(m - n) """ if diff_param == 0: - return ((Integer(1) / (Integer(2) * (m - n) * (n - Integer(1)))) * - (elliptic_e(z, m) + ((m - n) / n) * elliptic_f(z, m) + - ((n ** Integer(2) - m) / n) * elliptic_pi(n, z, m) - - (n * sqrt(Integer(1) - m * sin(z) ** Integer(2)) * - sin(Integer(2) * z)) / - (Integer(2) * (Integer(1) - n * sin(z) ** Integer(2))))) + return (Integer(1) / (Integer(2) * (m - n) * (n - Integer(1)))) * (elliptic_e(z, m) + ((m - n) / n) * elliptic_f(z, m) + ((n ** Integer(2) - m) / n) * elliptic_pi(n, z, m) - (n * sqrt(Integer(1) - m * sin(z) ** Integer(2)) * sin(Integer(2) * z)) / (Integer(2) * (Integer(1) - n * sin(z) ** Integer(2)))) if diff_param == 1: - return (Integer(1) / - (sqrt(Integer(1) - m * sin(z) ** Integer(Integer(2))) * - (Integer(1) - n * sin(z) ** Integer(2)))) + return Integer(1) / (sqrt(Integer(1) - m * sin(z) ** Integer(Integer(2))) * (Integer(1) - n * sin(z) ** Integer(2))) if diff_param == 2: - return ((Integer(1) / (Integer(2) * (n - m))) * - (elliptic_e(z, m) / (m - Integer(1)) + - elliptic_pi(n, z, m) - (m * sin(Integer(2) * z)) / - (Integer(2) * (m - Integer(1)) * - sqrt(Integer(1) - m * sin(z) ** Integer(2))))) + return (Integer(1) / (Integer(2) * (n - m))) * (elliptic_e(z, m) / (m - Integer(1)) + elliptic_pi(n, z, m) - (m * sin(Integer(2) * z)) / (Integer(2) * (m - Integer(1)) * sqrt(Integer(1) - m * sin(z) ** Integer(2)))) def _print_latex_(self, n, z, m): r""" diff --git a/src/sage/functions/spike_function.py b/src/sage/functions/spike_function.py index 4f9f04f1f6a..95b2fad1661 100644 --- a/src/sage/functions/spike_function.py +++ b/src/sage/functions/spike_function.py @@ -7,6 +7,7 @@ - Karl-Dieter Crisman (2009-09): adding documentation and doctests """ + # **************************************************************************** # Copyright (C) 2007 William Stein # Copyright (C) 2009 Karl-Dieter Crisman @@ -59,6 +60,7 @@ class SpikeFunction: sage: S.support # needs sage.symbolic [0.0, 1.0, 3.141592653589793] """ + def __init__(self, v, eps=0.0000001): """ Initialize base class SpikeFunction. @@ -77,10 +79,10 @@ def __init__(self, v, eps=0.0000001): v = sorted([(float(x[0]), float(x[1])) for x in v]) notify = False - for i in reversed(range(len(v)-1)): - if v[i+1][0] - v[i][0] <= eps: + for i in reversed(range(len(v) - 1)): + if v[i + 1][0] - v[i][0] <= eps: notify = True - del v[i+1] + del v[i + 1] if notify: print("Some overlapping spikes have been deleted.") @@ -163,7 +165,7 @@ def plot_fft_abs(self, samples=2**12, xmin=None, xmax=None, **kwds): """ w = self.vector(samples=samples, xmin=xmin, xmax=xmax) z = w.fft() - k = vector(RDF, [abs(z[i]) for i in range(len(z)//2)]) + k = vector(RDF, [abs(z[i]) for i in range(len(z) // 2)]) return k.plot(xmin=0, xmax=1, **kwds) def plot_fft_arg(self, samples=2**12, xmin=None, xmax=None, **kwds): @@ -183,7 +185,7 @@ def plot_fft_arg(self, samples=2**12, xmin=None, xmax=None, **kwds): """ w = self.vector(samples=samples, xmin=xmin, xmax=xmax) z = w.fft() - k = vector(RDF, [(z[i]).arg() for i in range(len(z)//2)]) + k = vector(RDF, [(z[i]).arg() for i in range(len(z) // 2)]) return k.plot(xmin=0, xmax=1, **kwds) def vector(self, samples=2**16, xmin=None, xmax=None): @@ -222,11 +224,11 @@ def _ranges(self, xmin, xmax): sage: S._ranges(None, None) (-1.0, 1.0) """ - width = (self.support[-1] + self.support[0])/float(2) + width = (self.support[-1] + self.support[0]) / float(2) if xmin is None: - xmin = self.support[0] - width/float(5) + xmin = self.support[0] - width / float(5) if xmax is None: - xmax = self.support[-1] + width/float(5) + xmax = self.support[-1] + width / float(5) if xmax <= xmin: xmax = xmin + 1 return xmin, xmax @@ -252,7 +254,7 @@ def plot(self, xmin=None, xmax=None, **kwds): if i != -1: x0 = self.support[i] + eps v.extend([(x0, y), (x0, 0)]) - if i+1 < len(self.support): + if i + 1 < len(self.support): x = self.support[i + 1] - eps v.append((x, 0)) else: @@ -269,7 +271,7 @@ def plot(self, xmin=None, xmax=None, **kwds): v.append((new_x, 0)) x = new_x L = line(v, **kwds) - L.xmin(xmin-1) + L.xmin(xmin - 1) L.xmax(xmax) return L diff --git a/src/sage/functions/transcendental.py b/src/sage/functions/transcendental.py index 5525e840c4c..9d42370e63a 100644 --- a/src/sage/functions/transcendental.py +++ b/src/sage/functions/transcendental.py @@ -1,6 +1,7 @@ """ Number-theoretic functions """ + # **************************************************************************** # Copyright (C) 2005 William Stein # @@ -151,11 +152,7 @@ def __init__(self): sage: zeta(3)._maple_().sage() # optional - maple # needs sage.symbolic zeta(3) """ - GinacFunction.__init__(self, 'zeta', - conversions={'giac': 'Zeta', - 'maple': 'Zeta', - 'sympy': 'zeta', - 'mathematica': 'Zeta'}) + GinacFunction.__init__(self, 'zeta', conversions={'giac': 'Zeta', 'maple': 'Zeta', 'sympy': 'zeta', 'mathematica': 'Zeta'}) zeta = Function_zeta() @@ -210,10 +207,7 @@ def __init__(self): sage: stieltjes(x).subs(x==0) # needs sage.symbolic euler_gamma """ - GinacFunction.__init__(self, "stieltjes", nargs=1, - conversions=dict(mathematica='StieltjesGamma', - sympy='stieltjes'), - latex_name=r'\gamma') + GinacFunction.__init__(self, "stieltjes", nargs=1, conversions=dict(mathematica='StieltjesGamma', sympy='stieltjes'), latex_name=r'\gamma') stieltjes = Function_stieltjes() @@ -229,10 +223,7 @@ def __init__(self): sage: hurwitz_zeta(x, 2)._sympy_() # needs sympy sage.symbolic zeta(x, 2) """ - BuiltinFunction.__init__(self, 'hurwitz_zeta', nargs=2, - conversions=dict(mathematica='HurwitzZeta', - sympy='zeta'), - latex_name=r'\zeta') + BuiltinFunction.__init__(self, 'hurwitz_zeta', nargs=2, conversions=dict(mathematica='HurwitzZeta', sympy='zeta'), latex_name=r'\zeta') def _eval_(self, s, x): r""" @@ -282,8 +273,7 @@ def _derivative_(self, s, x, diff_param): """ if diff_param == 1: return -s * hurwitz_zeta(s + 1, x) - raise NotImplementedError('derivative with respect to first ' - 'argument') + raise NotImplementedError('derivative with respect to first ' 'argument') hurwitz_zeta_func = Function_HurwitzZeta() @@ -374,8 +364,7 @@ def __init__(self): sage: zetaderiv(b, 1) # needs sage.libs.flint sage.symbolic zetaderiv([1.500000000 +/- 1.01e-10], 1) """ - GinacFunction.__init__(self, "zetaderiv", nargs=2, - conversions=dict(maple='Zeta')) + GinacFunction.__init__(self, "zetaderiv", nargs=2, conversions=dict(maple='Zeta')) def _evalf_(self, n, x, parent=None, algorithm=None): r""" @@ -453,7 +442,7 @@ def zeta_symmetric(s): if s == 1: # deal with poles, hopefully return R(0.5) - return (s/2 + 1).gamma() * (s-1) * (R.pi()**(-s/2)) * s.zeta() + return (s / 2 + 1).gamma() * (s - 1) * (R.pi() ** (-s / 2)) * s.zeta() class DickmanRho(BuiltinFunction): @@ -510,6 +499,7 @@ class DickmanRho(BuiltinFunction): Solutions to some Classical Differential-Difference Equations." Mathematics of Computation, Vol. 53, No. 187 (1989). """ + def __init__(self): """ Construct an object to represent Dickman's rho function. @@ -553,12 +543,12 @@ def _eval_(self, x): if self._cur_prec < x.parent().prec() or n not in self._f: self._cur_prec = rel_prec = x.parent().prec() # Go a bit beyond so we're not constantly re-computing. - max = x.parent()(1.1)*x + 10 - abs_prec = (-self.approximate(max).log2() + rel_prec + 2*max.log2()).ceil() + max = x.parent()(1.1) * x + 10 + abs_prec = (-self.approximate(max).log2() + rel_prec + 2 * max.log2()).ceil() self._f = {} with increase_recursion_limit(int(max)): self._compute_power_series(max.floor(), abs_prec, cache_ring=x.parent()) - return self._f[n](2*(x-n-x.parent()(0.5))) + return self._f[n](2 * (x - n - x.parent()(0.5))) def power_series(self, n, abs_prec): """ @@ -619,30 +609,30 @@ def _compute_power_series(self, n, abs_prec, cache_ring=None): if n == 0: return PolynomialRealDense(RealField(abs_prec)['x'], [1]) if n == 1: - nterms = (RDF(abs_prec) * RDF(2).log()/RDF(3).log()).ceil() + nterms = (RDF(abs_prec) * RDF(2).log() / RDF(3).log()).ceil() R = RealField(abs_prec) neg_three = ZZ(-3) - coeffs = [1 - R(1.5).log()] + [neg_three**-k/k for k in range(1, nterms)] + coeffs = [1 - R(1.5).log()] + [neg_three**-k / k for k in range(1, nterms)] f = PolynomialRealDense(R['x'], coeffs) if cache_ring is not None: - self._f[n] = f.truncate_abs(f[0] >> (cache_ring.prec()+1)).change_ring(cache_ring) + self._f[n] = f.truncate_abs(f[0] >> (cache_ring.prec() + 1)).change_ring(cache_ring) return f else: - f = self._compute_power_series(n-1, abs_prec, cache_ring) + f = self._compute_power_series(n - 1, abs_prec, cache_ring) # integrand = f / (2n+1 + x) # We calculate this way because the most significant term is the constant term, # and so we want to push the error accumulation and remainder out to the least # significant terms. - integrand = f.reverse().quo_rem(PolynomialRealDense(f.parent(), [1, 2*n+1]))[0].reverse() - integrand = integrand.truncate_abs(RR(2)**-abs_prec) + integrand = f.reverse().quo_rem(PolynomialRealDense(f.parent(), [1, 2 * n + 1]))[0].reverse() + integrand = integrand.truncate_abs(RR(2) ** -abs_prec) iintegrand = integrand.integral() ff = PolynomialRealDense(f.parent(), [f(1) + iintegrand(-1)]) - iintegrand i = 0 - while abs(f[i]) < abs(f[i+1]): + while abs(f[i]) < abs(f[i + 1]): i += 1 rel_prec = int(abs_prec + abs(RR(f[i])).log2()) if cache_ring is not None: - self._f[n] = ff.truncate_abs(ff[0] >> (cache_ring.prec()+1)).change_ring(cache_ring) + self._f[n] = ff.truncate_abs(ff[0] >> (cache_ring.prec() + 1)).change_ring(cache_ring) return ff.change_ring(RealField(rel_prec)) def approximate(self, x, parent=None): @@ -674,12 +664,12 @@ def approximate(self, x, parent=None): log, exp, sqrt, pi = math.log, math.exp, math.sqrt, math.pi x = float(x) xi = log(x) - y = (exp(xi)-1.0)/xi - x + y = (exp(xi) - 1.0) / xi - x while abs(y) > 1e-12: - dydxi = (exp(xi)*(xi-1.0) + 1.0)/(xi*xi) - xi -= y/dydxi - y = (exp(xi)-1.0)/xi - x - return (-x*xi + RR(xi).eint()).exp() / (sqrt(2*pi*x)*xi) + dydxi = (exp(xi) * (xi - 1.0) + 1.0) / (xi * xi) + xi -= y / dydxi + y = (exp(xi) - 1.0) / xi - x + return (-x * xi + RR(xi).eint()).exp() / (sqrt(2 * pi * x) * xi) dickman_rho = DickmanRho() diff --git a/src/sage/functions/trig.py b/src/sage/functions/trig.py index 337957e4c7a..0764c245351 100644 --- a/src/sage/functions/trig.py +++ b/src/sage/functions/trig.py @@ -18,6 +18,7 @@ sage: cot(x*(x+1)-x^2-x) Infinity """ + import math from sage.symbolic.function import GinacFunction @@ -144,9 +145,7 @@ def __init__(self): sage: sin(pi - 1/42*pi) # needs sage.symbolic sin(1/42*pi) """ - GinacFunction.__init__(self, 'sin', latex_name=r"\sin", - conversions=dict(maxima='sin', mathematica='Sin', - giac='sin', fricas='sin', sympy='sin')) + GinacFunction.__init__(self, 'sin', latex_name=r"\sin", conversions=dict(maxima='sin', mathematica='Sin', giac='sin', fricas='sin', sympy='sin')) sin = Function_sin() @@ -212,9 +211,7 @@ def __init__(self): sage: cos(pi - 1/42*pi) # needs sage.symbolic -cos(1/42*pi) """ - GinacFunction.__init__(self, 'cos', latex_name=r"\cos", - conversions=dict(maxima='cos', mathematica='Cos', - giac='cos', fricas='cos', sympy='cos')) + GinacFunction.__init__(self, 'cos', latex_name=r"\cos", conversions=dict(maxima='cos', mathematica='Cos', giac='cos', fricas='cos', sympy='cos')) cos = Function_cos() @@ -278,9 +275,7 @@ def __init__(self): sage: tan(2+I).imag().n() # needs sage.symbolic 1.16673625724092 """ - GinacFunction.__init__(self, 'tan', latex_name=r"\tan", - conversions=dict(maxima='tan', mathematica='Tan', - giac='tan', fricas='tan', sympy='tan')) + GinacFunction.__init__(self, 'tan', latex_name=r"\tan", conversions=dict(maxima='tan', mathematica='Tan', giac='tan', fricas='tan', sympy='tan')) tan = Function_tan() @@ -368,9 +363,7 @@ def __init__(self): sage: cot(1.+I) # needs sage.symbolic 0.217621561854403 - 0.868014142895925*I """ - GinacFunction.__init__(self, 'cot', latex_name=r"\cot", - conversions=dict(maxima='cot', mathematica='Cot', - giac='cot', fricas='cot', sympy='cot')) + GinacFunction.__init__(self, 'cot', latex_name=r"\cot", conversions=dict(maxima='cot', mathematica='Cot', giac='cot', fricas='cot', sympy='cot')) def _eval_numpy_(self, x): """ @@ -442,9 +435,7 @@ def __init__(self): sage: sec(complex(1,1)) # rel tol 1e-15 # needs sage.rings.complex_double (0.49833703055518686+0.5910838417210451j) """ - GinacFunction.__init__(self, 'sec', latex_name=r"\sec", - conversions=dict(maxima='sec', mathematica='Sec', - giac='sec', fricas='sec', sympy='sec')) + GinacFunction.__init__(self, 'sec', latex_name=r"\sec", conversions=dict(maxima='sec', mathematica='Sec', giac='sec', fricas='sec', sympy='sec')) def _eval_numpy_(self, x): """ @@ -516,9 +507,7 @@ def __init__(self): sage: csc(complex(1,1)) # rel tol 1e-15 # needs sage.rings.complex_double (0.6215180171704284-0.30393100162842646j) """ - GinacFunction.__init__(self, 'csc', latex_name=r"\csc", - conversions=dict(maxima='csc', mathematica='Csc', - giac='csc', fricas='csc', sympy='csc')) + GinacFunction.__init__(self, 'csc', latex_name=r"\csc", conversions=dict(maxima='csc', mathematica='Csc', giac='csc', fricas='csc', sympy='csc')) def _eval_numpy_(self, x): """ @@ -539,6 +528,7 @@ def _eval_numpy_(self, x): # Inverse Trigonometric Functions # ################################### + class Function_arcsin(GinacFunction): def __init__(self): """ @@ -594,10 +584,7 @@ def __init__(self): sage: asin(SR(2.1)) # needs sage.symbolic 1.57079632679490 - 1.37285914424258*I """ - GinacFunction.__init__(self, 'arcsin', latex_name=r"\arcsin", - conversions=dict(maxima='asin', sympy='asin', - mathematica='ArcSin', - fricas='asin', giac='asin')) + GinacFunction.__init__(self, 'arcsin', latex_name=r"\arcsin", conversions=dict(maxima='asin', sympy='asin', mathematica='ArcSin', fricas='asin', giac='asin')) arcsin = asin = Function_arcsin() @@ -663,10 +650,7 @@ def __init__(self): sage: arcsin(sqrt(2)/2) 1/4*pi """ - GinacFunction.__init__(self, 'arccos', latex_name=r"\arccos", - conversions=dict(maxima='acos', sympy='acos', - mathematica='ArcCos', - fricas='acos', giac='acos')) + GinacFunction.__init__(self, 'arccos', latex_name=r"\arccos", conversions=dict(maxima='acos', sympy='acos', mathematica='ArcCos', fricas='acos', giac='acos')) arccos = acos = Function_arccos() @@ -737,10 +721,7 @@ def __init__(self): sage: arctan(-x).subs(x=-oo) # needs sage.symbolic 1/2*pi """ - GinacFunction.__init__(self, 'arctan', latex_name=r"\arctan", - conversions=dict(maxima='atan', sympy='atan', - mathematica='ArcTan', - fricas='atan', giac='atan')) + GinacFunction.__init__(self, 'arctan', latex_name=r"\arctan", conversions=dict(maxima='atan', sympy='atan', mathematica='ArcTan', fricas='atan', giac='atan')) arctan = atan = Function_arctan() @@ -791,10 +772,7 @@ def __init__(self): sage: arccot(1.+I) # needs sage.symbolic 0.553574358897045 - 0.402359478108525*I """ - GinacFunction.__init__(self, 'arccot', latex_name=r"\operatorname{arccot}", - conversions=dict(maxima='acot', sympy='acot', - mathematica='ArcCot', - fricas='acot', giac='acot')) + GinacFunction.__init__(self, 'arccot', latex_name=r"\operatorname{arccot}", conversions=dict(maxima='acot', sympy='acot', mathematica='ArcCot', fricas='acot', giac='acot')) def _eval_numpy_(self, x): """ @@ -852,10 +830,7 @@ def __init__(self): sage: arccsc(complex(1,1)) # rel tol 1e-15 # needs sage.rings.complex_double (0.45227844715119064-0.5306375309525178j) """ - GinacFunction.__init__(self, 'arccsc', latex_name=r"\operatorname{arccsc}", - conversions=dict(maxima='acsc', sympy='acsc', - mathematica='ArcCsc', - fricas='acsc', giac='acsc')) + GinacFunction.__init__(self, 'arccsc', latex_name=r"\operatorname{arccsc}", conversions=dict(maxima='acsc', sympy='acsc', mathematica='ArcCsc', fricas='acsc', giac='acsc')) def _eval_numpy_(self, x): """ @@ -915,10 +890,7 @@ def __init__(self): sage: arcsec(complex(1,1)) # rel tol 1e-15 # needs sage.rings.complex_double (1.118517879643706+0.5306375309525178j) """ - GinacFunction.__init__(self, 'arcsec', latex_name=r"\operatorname{arcsec}", - conversions=dict(maxima='asec', sympy='asec', - mathematica='ArcSec', - fricas='asec', giac='asec')) + GinacFunction.__init__(self, 'arcsec', latex_name=r"\operatorname{arcsec}", conversions=dict(maxima='asec', sympy='asec', mathematica='ArcSec', fricas='asec', giac='asec')) def _eval_numpy_(self, x): """ @@ -1053,8 +1025,7 @@ def __init__(self): sage: arctan2(0, I*I) # needs sage.symbolic pi """ - GinacFunction.__init__(self, 'arctan2', nargs=2, latex_name=r"\arctan", - conversions=dict(maxima='atan2', sympy='atan2', giac='atan2')) + GinacFunction.__init__(self, 'arctan2', nargs=2, latex_name=r"\arctan", conversions=dict(maxima='atan2', sympy='atan2', giac='atan2')) arctan2 = atan2 = Function_arctan2() diff --git a/src/sage/functions/wigner.py b/src/sage/functions/wigner.py index e177fc1287b..4a8f5a54825 100644 --- a/src/sage/functions/wigner.py +++ b/src/sage/functions/wigner.py @@ -59,7 +59,7 @@ def _calc_factlist(nn): if nn >= len(_Factlist): for ii in range(len(_Factlist), nn + 1): _Factlist.append(_Factlist[ii - 1] * ii) - return _Factlist[:Integer(nn) + 1] + return _Factlist[: Integer(nn) + 1] def wigner_3j(j_1, j_2, j_3, m_1, m_2, m_3, prec=None): @@ -146,11 +146,9 @@ def wigner_3j(j_1, j_2, j_3, m_1, m_2, m_3, prec=None): - Jens Rasch (2009-03-24): initial version """ - if int(j_1 * 2) != j_1 * 2 or int(j_2 * 2) != j_2 * 2 or \ - int(j_3 * 2) != j_3 * 2: + if int(j_1 * 2) != j_1 * 2 or int(j_2 * 2) != j_2 * 2 or int(j_3 * 2) != j_3 * 2: raise ValueError("j values must be integer or half integer") - if int(m_1 * 2) != m_1 * 2 or int(m_2 * 2) != m_2 * 2 or \ - int(m_3 * 2) != m_3 * 2: + if int(m_1 * 2) != m_1 * 2 or int(m_2 * 2) != m_2 * 2 or int(m_3 * 2) != m_3 * 2: raise ValueError("m values must be integer or half integer") if m_1 + m_2 + m_3 != 0: return 0 @@ -168,22 +166,10 @@ def wigner_3j(j_1, j_2, j_3, m_1, m_2, m_3, prec=None): if (abs(m_1) > j_1) or (abs(m_2) > j_2) or (abs(m_3) > j_3): return 0 - maxfact = max(j_1 + j_2 + j_3 + 1, - j_1 + abs(m_1), - j_2 + abs(m_2), - j_3 + abs(m_3)) + maxfact = max(j_1 + j_2 + j_3 + 1, j_1 + abs(m_1), j_2 + abs(m_2), j_3 + abs(m_3)) _calc_factlist(maxfact) - argsqrt = Integer(_Factlist[int(j_1 + j_2 - j_3)] * - _Factlist[int(j_1 - j_2 + j_3)] * - _Factlist[int(-j_1 + j_2 + j_3)] * - _Factlist[int(j_1 - m_1)] * - _Factlist[int(j_1 + m_1)] * - _Factlist[int(j_2 - m_2)] * - _Factlist[int(j_2 + m_2)] * - _Factlist[int(j_3 - m_3)] * - _Factlist[int(j_3 + m_3)]) / \ - _Factlist[int(j_1 + j_2 + j_3 + 1)] + argsqrt = Integer(_Factlist[int(j_1 + j_2 - j_3)] * _Factlist[int(j_1 - j_2 + j_3)] * _Factlist[int(-j_1 + j_2 + j_3)] * _Factlist[int(j_1 - m_1)] * _Factlist[int(j_1 + m_1)] * _Factlist[int(j_2 - m_2)] * _Factlist[int(j_2 + m_2)] * _Factlist[int(j_3 - m_3)] * _Factlist[int(j_3 + m_3)]) / _Factlist[int(j_1 + j_2 + j_3 + 1)] ressqrt = argsqrt.sqrt(prec) if isinstance(ressqrt, ComplexNumber): @@ -193,12 +179,7 @@ def wigner_3j(j_1, j_2, j_3, m_1, m_2, m_3, prec=None): imax = int(min(j_2 + m_2, j_1 - m_1, j_1 + j_2 - j_3)) sumres = 0 for ii in range(imin, imax + 1): - den = _Factlist[ii] * \ - _Factlist[int(ii + j_3 - j_1 - m_2)] * \ - _Factlist[int(j_2 + m_2 - ii)] * \ - _Factlist[int(j_1 - ii - m_1)] * \ - _Factlist[int(ii + j_3 - j_2 + m_1)] * \ - _Factlist[int(j_1 + j_2 - j_3 - ii)] + den = _Factlist[ii] * _Factlist[int(ii + j_3 - j_1 - m_2)] * _Factlist[int(j_2 + m_2 - ii)] * _Factlist[int(j_1 - ii - m_1)] * _Factlist[int(ii + j_3 - j_2 + m_1)] * _Factlist[int(j_1 + j_2 - j_3 - ii)] sumres = sumres + Integer((-1) ** ii) / den return ressqrt * sumres * prefid @@ -250,8 +231,7 @@ def clebsch_gordan(j_1, j_2, j_3, m_1, m_2, m_3, prec=None): - Jens Rasch (2009-03-24): initial version """ - return (-1) ** int(j_1 - j_2 + m_3) * (2 * j_3 + 1).sqrt(prec) * \ - wigner_3j(j_1, j_2, j_3, m_1, m_2, -m_3, prec) + return (-1) ** int(j_1 - j_2 + m_3) * (2 * j_3 + 1).sqrt(prec) * wigner_3j(j_1, j_2, j_3, m_1, m_2, -m_3, prec) def _big_delta_coeff(aa, bb, cc, prec=None): @@ -294,10 +274,7 @@ def _big_delta_coeff(aa, bb, cc, prec=None): maxfact = max(aa + bb - cc, aa + cc - bb, bb + cc - aa, aa + bb + cc + 1) _calc_factlist(maxfact) - argsqrt = Integer(_Factlist[int(aa + bb - cc)] * - _Factlist[int(aa + cc - bb)] * - _Factlist[int(bb + cc - aa)]) /\ - Integer(_Factlist[int(aa + bb + cc + 1)]) + argsqrt = Integer(_Factlist[int(aa + bb - cc)] * _Factlist[int(aa + cc - bb)] * _Factlist[int(bb + cc - aa)]) / Integer(_Factlist[int(aa + bb + cc + 1)]) ressqrt = argsqrt.sqrt(prec) if isinstance(ressqrt, ComplexNumber): @@ -352,28 +329,18 @@ def racah(aa, bb, cc, dd, ee, ff, prec=None): - Jens Rasch (2009-03-24): initial version """ - prefac = _big_delta_coeff(aa, bb, ee, prec) * \ - _big_delta_coeff(cc, dd, ee, prec) * \ - _big_delta_coeff(aa, cc, ff, prec) * \ - _big_delta_coeff(bb, dd, ff, prec) + prefac = _big_delta_coeff(aa, bb, ee, prec) * _big_delta_coeff(cc, dd, ee, prec) * _big_delta_coeff(aa, cc, ff, prec) * _big_delta_coeff(bb, dd, ff, prec) if prefac == 0: return 0 imin = int(max(aa + bb + ee, cc + dd + ee, aa + cc + ff, bb + dd + ff)) imax = int(min(aa + bb + cc + dd, aa + dd + ee + ff, bb + cc + ee + ff)) - maxfact = max(imax + 1, aa + bb + cc + dd, aa + dd + ee + ff, - bb + cc + ee + ff) + maxfact = max(imax + 1, aa + bb + cc + dd, aa + dd + ee + ff, bb + cc + ee + ff) _calc_factlist(maxfact) sumres = 0 for kk in range(imin, imax + 1): - den = _Factlist[int(kk - aa - bb - ee)] * \ - _Factlist[int(kk - cc - dd - ee)] * \ - _Factlist[int(kk - aa - cc - ff)] * \ - _Factlist[int(kk - bb - dd - ff)] * \ - _Factlist[int(aa + bb + cc + dd - kk)] * \ - _Factlist[int(aa + dd + ee + ff - kk)] * \ - _Factlist[int(bb + cc + ee + ff - kk)] + den = _Factlist[int(kk - aa - bb - ee)] * _Factlist[int(kk - cc - dd - ee)] * _Factlist[int(kk - aa - cc - ff)] * _Factlist[int(kk - bb - dd - ff)] * _Factlist[int(aa + bb + cc + dd - kk)] * _Factlist[int(aa + dd + ee + ff - kk)] * _Factlist[int(bb + cc + ee + ff - kk)] sumres = sumres + Integer((-1) ** kk * _Factlist[kk + 1]) / den res = prefac * sumres * (-1) ** int(aa + bb + cc + dd) @@ -471,8 +438,7 @@ def wigner_6j(j_1, j_2, j_3, j_4, j_5, j_6, prec=None): for finite precision arithmetic and only useful for a computer algebra system [RH2003]_. """ - res = (-1) ** int(j_1 + j_2 + j_4 + j_5) * \ - racah(j_1, j_2, j_5, j_4, j_3, j_6, prec) + res = (-1) ** int(j_1 + j_2 + j_4 + j_5) * racah(j_1, j_2, j_5, j_4, j_3, j_6, prec) return res @@ -549,10 +515,7 @@ def wigner_9j(j_1, j_2, j_3, j_4, j_5, j_6, j_7, j_8, j_9, prec=None): sumres = 0 for kk in range(imin, imax + 1): - sumres = sumres + (2 * kk + 1) * \ - racah(j_1, j_2, j_9, j_6, j_3, kk, prec) * \ - racah(j_4, j_6, j_8, j_2, j_5, kk, prec) * \ - racah(j_1, j_4, j_9, j_8, j_7, kk, prec) + sumres = sumres + (2 * kk + 1) * racah(j_1, j_2, j_9, j_6, j_3, kk, prec) * racah(j_4, j_6, j_8, j_2, j_5, kk, prec) * racah(j_1, j_4, j_9, j_8, j_7, kk, prec) return sumres @@ -701,22 +664,14 @@ def gaunt(l_1, l_2, l_3, m_1, m_2, m_3, prec=None): maxfact = max(l_1 + l_2 + l_3 + 1, imax + 1) _calc_factlist(maxfact) - argsqrt = (2 * l_1 + 1) * (2 * l_2 + 1) * (2 * l_3 + 1) * \ - _Factlist[l_1 - m_1] * _Factlist[l_1 + m_1] * _Factlist[l_2 - m_2] * \ - _Factlist[l_2 + m_2] * _Factlist[l_3 - m_3] * _Factlist[l_3 + m_3] / \ - (4*pi) + argsqrt = (2 * l_1 + 1) * (2 * l_2 + 1) * (2 * l_3 + 1) * _Factlist[l_1 - m_1] * _Factlist[l_1 + m_1] * _Factlist[l_2 - m_2] * _Factlist[l_2 + m_2] * _Factlist[l_3 - m_3] * _Factlist[l_3 + m_3] / (4 * pi) ressqrt = argsqrt.sqrt() - prefac = Integer(_Factlist[bigL] * _Factlist[l_2 - l_1 + l_3] * - _Factlist[l_1 - l_2 + l_3] * _Factlist[l_1 + l_2 - l_3]) / \ - _Factlist[2 * bigL + 1] / \ - (_Factlist[bigL - l_1] * _Factlist[bigL - l_2] * _Factlist[bigL - l_3]) + prefac = Integer(_Factlist[bigL] * _Factlist[l_2 - l_1 + l_3] * _Factlist[l_1 - l_2 + l_3] * _Factlist[l_1 + l_2 - l_3]) / _Factlist[2 * bigL + 1] / (_Factlist[bigL - l_1] * _Factlist[bigL - l_2] * _Factlist[bigL - l_3]) sumres = 0 for ii in range(imin, imax + 1): - den = _Factlist[ii] * _Factlist[ii + l_3 - l_1 - m_2] * \ - _Factlist[l_2 + m_2 - ii] * _Factlist[l_1 - ii - m_1] * \ - _Factlist[ii + l_3 - l_2 + m_1] * _Factlist[l_1 + l_2 - l_3 - ii] + den = _Factlist[ii] * _Factlist[ii + l_3 - l_1 - m_2] * _Factlist[l_2 + m_2 - ii] * _Factlist[l_1 - ii - m_1] * _Factlist[ii + l_3 - l_2 + m_1] * _Factlist[l_1 + l_2 - l_3 - ii] sumres = sumres + Integer((-1) ** ii) / den res = ressqrt * prefac * sumres * (-1) ** (bigL + l_3 + m_1 - m_2) diff --git a/src/sage/game_theory/catalog_normal_form_games.py b/src/sage/game_theory/catalog_normal_form_games.py index 705957f079e..3560ea96125 100644 --- a/src/sage/game_theory/catalog_normal_form_games.py +++ b/src/sage/game_theory/catalog_normal_form_games.py @@ -42,6 +42,7 @@ - James Campbell and Vince Knight (06-2014) """ + from sage.game_theory.normal_form_game import NormalFormGame @@ -132,6 +133,7 @@ def PrisonersDilemma(R=-2, P=-4, S=-5, T=0): if not (T > R > P > S): raise TypeError("the input values for a Prisoners Dilemma must be of the form T > R > P > S") from sage.matrix.constructor import matrix + A = matrix([[R, S], [T, P]]) g = NormalFormGame([A, A.transpose()]) g.rename('Prisoners dilemma - ' + repr(g)) @@ -218,6 +220,7 @@ def CoordinationGame(A=10, a=5, B=0, b=0, C=0, c=0, D=5, d=10): if not (A > B and D > C and a > c and d > b): raise TypeError("the input values for a Coordination game must be of the form A > B, D > C, a > c and d > b") from sage.matrix.constructor import matrix + A = matrix([[A, C], [B, D]]) B = matrix([[a, c], [b, d]]) g = NormalFormGame([A, B]) @@ -403,6 +406,7 @@ def AntiCoordinationGame(A=3, a=3, B=5, b=1, C=1, c=5, D=0, d=0): if not (A < B and D < C and a < c and d < b): raise TypeError("the input values for an Anti coordination game must be of the form A < B, D < C, a < c and d < b") from sage.matrix.constructor import matrix + A = matrix([[A, C], [B, D]]) B = matrix([[a, c], [b, d]]) g = NormalFormGame([A, B]) @@ -494,8 +498,7 @@ def HawkDove(v=2, c=3): """ if not (c > v): raise TypeError("the input values for a Hawk Dove game must be of the form c > v") - g = AntiCoordinationGame(A=v/2-c, a=v/2-c, B=0, b=v, - C=v, c=0, D=v/2, d=v/2) + g = AntiCoordinationGame(A=v / 2 - c, a=v / 2 - c, B=0, b=v, C=v, c=0, D=v / 2, d=v / 2) g.rename('Hawk-Dove - ' + repr(g)) return g @@ -550,6 +553,7 @@ def Pigs(): [[(1, 0), (0, 1)]] """ from sage.matrix.constructor import matrix + A = matrix([[3, 1], [6, 0]]) B = matrix([[1, 4], [-1, 0]]) g = NormalFormGame([A, B]) @@ -592,6 +596,7 @@ def MatchingPennies(): [[(1/2, 1/2), (1/2, 1/2)]] """ from sage.matrix.constructor import matrix + A = matrix([[1, -1], [-1, 1]]) g = NormalFormGame([A]) g.rename('Matching pennies - ' + repr(g)) @@ -637,6 +642,7 @@ def RPS(): [[(1/3, 1/3, 1/3), (1/3, 1/3, 1/3)]] """ from sage.matrix.constructor import matrix + A = matrix([[0, -1, 1], [1, 0, -1], [-1, 1, 0]]) g = NormalFormGame([A]) g.rename('Rock-Paper-Scissors - ' + repr(g)) @@ -701,11 +707,8 @@ def RPSLS(): [[(1/5, 1/5, 1/5, 1/5, 1/5), (1/5, 1/5, 1/5, 1/5, 1/5)]] """ from sage.matrix.constructor import matrix - A = matrix([[0, -1, 1, 1, -1], - [1, 0, -1, -1, 1], - [-1, 1, 0, 1, -1], - [-1, 1, -1, 0, 1], - [1, -1, 1, -1, 0]]) + + A = matrix([[0, -1, 1, 1, -1], [1, 0, -1, -1, 1], [-1, 1, 0, 1, -1], [-1, 1, -1, 0, 1], [1, -1, 1, -1, 0]]) g = NormalFormGame([A]) g.rename('Rock-Paper-Scissors-Lizard-Spock - ' + repr(g)) return g @@ -915,8 +918,8 @@ def TravellersDilemma(max_value=10): """ from sage.matrix.constructor import matrix from sage.functions.generalized import sign - A = matrix([[min(i, j) + 2 * sign(j - i) for j in range(max_value, 1, -1)] - for i in range(max_value, 1, -1)]) + + A = matrix([[min(i, j) + 2 * sign(j - i) for j in range(max_value, 1, -1)] for i in range(max_value, 1, -1)]) g = NormalFormGame([A, A.transpose()]) g.rename('Travellers dilemma - ' + repr(g)) return g diff --git a/src/sage/game_theory/cooperative_game.py b/src/sage/game_theory/cooperative_game.py index a0b881936d6..bb857dd523f 100644 --- a/src/sage/game_theory/cooperative_game.py +++ b/src/sage/game_theory/cooperative_game.py @@ -252,6 +252,7 @@ class CooperativeGame(SageObject): sage: letter_game.is_symmetric({'A': 0, 'C': 35, 'B': 3}) True """ + def __init__(self, characteristic_function): r""" Initialize a co-operative game and checks the inputs. @@ -389,8 +390,7 @@ def shapley_value(self): k = Integer(len(coalition)) weight = 1 / (n.binomial(k) * k) t = tuple(p for p in coalition if p != player) - weighted_contribution += weight * (self.ch_f[tuple(coalition)] - - self.ch_f[t]) + weighted_contribution += weight * (self.ch_f[tuple(coalition)] - self.ch_f[t]) payoff_vector[player] = weighted_contribution return payoff_vector @@ -454,8 +454,7 @@ def is_monotone(self): sage: long_game.is_monotone() True """ - return not any(set(p1) <= set(p2) and self.ch_f[p1] > self.ch_f[p2] - for p1, p2 in permutations(self.ch_f.keys(), 2)) + return not any(set(p1) <= set(p2) and self.ch_f[p1] > self.ch_f[p2] for p1, p2 in permutations(self.ch_f.keys(), 2)) def is_superadditive(self): r""" diff --git a/src/sage/game_theory/matching_game.py b/src/sage/game_theory/matching_game.py index cfd7a770b2c..454b829e06b 100644 --- a/src/sage/game_theory/matching_game.py +++ b/src/sage/game_theory/matching_game.py @@ -321,6 +321,7 @@ class MatchingGame(SageObject): sage: g.solve() {1: -1, 2: -2, 3: -3} """ + def __init__(self, generator, revr=None): r""" Initialize a matching game and check the inputs. @@ -484,13 +485,7 @@ def __eq__(self, other): sage: g1 == g2 True """ - return (isinstance(other, MatchingGame) - and set(self._suitors) == set(other._suitors) - and set(self._reviewers) == set(other._reviewers) - and all(r1.pref == r2.pref for r1, r2 in - zip(set(self._reviewers), set(other._reviewers))) - and all(s1.pref == s2.pref for s1, s2 in - zip(set(self._suitors), set(other._suitors)))) + return isinstance(other, MatchingGame) and set(self._suitors) == set(other._suitors) and set(self._reviewers) == set(other._reviewers) and all(r1.pref == r2.pref for r1, r2 in zip(set(self._reviewers), set(other._reviewers))) and all(s1.pref == s2.pref for s1, s2 in zip(set(self._suitors), set(other._suitors))) __hash__ = None # not hashable because this is mutable. @@ -822,7 +817,7 @@ def suitors(self): sage: g.suitors() (1, 2) """ - return tuple(sorted(self._suitors, key=lambda s:str(s._name))) + return tuple(sorted(self._suitors, key=lambda s: str(s._name))) def reviewers(self): """ @@ -834,7 +829,7 @@ def reviewers(self): sage: g.reviewers() (-1, -2) """ - return tuple(sorted(self._reviewers, key=lambda r:str(r._name))) + return tuple(sorted(self._reviewers, key=lambda r: str(r._name))) def solve(self, invert=False): r""" @@ -947,6 +942,7 @@ class Player: These instances are used when initiating players and to keep track of whether or not partners have a preference. """ + def __init__(self, name): r""" TESTS:: diff --git a/src/sage/game_theory/normal_form_game.py b/src/sage/game_theory/normal_form_game.py index 9010967802e..c1d10f38184 100644 --- a/src/sage/game_theory/normal_form_game.py +++ b/src/sage/game_theory/normal_form_game.py @@ -906,6 +906,7 @@ def _repr_(self) -> str: (0, 1): [2, 3], (1, 0): [3, 1], (1, 1): [4, 4]} """ from pprint import pformat + base_str = "Normal Form Game with the following utilities: {}" return base_str.format(pformat(self.utilities)) @@ -964,8 +965,7 @@ def _two_matrix_game(self, matrices): self.add_player(matrices[0].dimensions()[0]) self.add_player(matrices[1].dimensions()[1]) for strategy_profile in self.utilities: - self.utilities[strategy_profile] = [matrices[0][strategy_profile], - matrices[1][strategy_profile]] + self.utilities[strategy_profile] = [matrices[0][strategy_profile], matrices[1][strategy_profile]] def _gambit_game(self, game): r""" @@ -1144,6 +1144,7 @@ def _gambit_(self, as_integer=False, maximization=True): """ from decimal import Decimal + strategy_sizes = [p.num_strategies for p in self.players] g = Game.new_table(strategy_sizes) @@ -1190,6 +1191,7 @@ def is_constant_sum(self): False """ import sys + if len(self.players) > 2: return False m1, m2 = self.payoff_matrices() @@ -1385,8 +1387,7 @@ def _is_complete(self): sage: example._is_complete() False """ - results = (all(not isinstance(i, bool) for i in profile) - for profile in self.utilities.values()) + results = (all(not isinstance(i, bool) for i in profile) for profile in self.utilities.values()) return all(results) def obtain_nash(self, algorithm=False, maximization=True, solver=None): @@ -1673,16 +1674,13 @@ def obtain_nash(self, algorithm=False, maximization=True, solver=None): (in which case the default one is used), or a callable. """ if len(self.players) > 2: - raise NotImplementedError("Nash equilibrium for games with more " - "than 2 players have not been " - "implemented yet. Please see the gambit " - "website (http://gambit.sourceforge.net/) that has a variety of " - "available algorithms") + raise NotImplementedError("Nash equilibrium for games with more " "than 2 players have not been " "implemented yet. Please see the gambit " "website (http://gambit.sourceforge.net/) that has a variety of " "available algorithms") if not self._is_complete(): raise ValueError("utilities have not been populated") from sage.features.lrs import LrsNash + if not algorithm: if self.is_constant_sum(): algorithm = "lp" @@ -1752,10 +1750,11 @@ def _solve_lrs(self, maximization=True): [(1, 0, 0), (0, 0, 1)]] """ from subprocess import PIPE, Popen + m1, m2 = self.payoff_matrices() if maximization is False: - m1 = - m1 - m2 = - m2 + m1 = -m1 + m2 = -m2 game_str = self._lrs_nash_format(m1, m2) game_name = tmp_filename() @@ -1763,9 +1762,9 @@ def _solve_lrs(self, maximization=True): game_file.write(game_str) from sage.features.lrs import LrsNash + LrsNash().require() - process = Popen([LrsNash().absolute_filename(), game_name], - stdout=PIPE, stderr=PIPE) + process = Popen([LrsNash().absolute_filename(), game_name], stdout=PIPE, stderr=PIPE) lrs_output = [bytes_to_str(row) for row in process.stdout] process.terminate() @@ -2017,18 +2016,18 @@ def _solve_enumeration(self, maximization=True): M1 = -M1 M2 = -M2 - potential_supports = [[tuple(support) for support in - powerset(range(player.num_strategies))] - for player in self.players] + potential_supports = [[tuple(support) for support in powerset(range(player.num_strategies))] for player in self.players] potential_support_pairs = (pair for pair in product(*potential_supports) if len(pair[0]) == len(pair[1])) equilibria = [] for pair in potential_support_pairs: # Check if any supports are dominated for row player - if (self._row_cond_dominance(pair[0], pair[1], M1) + if ( + self._row_cond_dominance(pair[0], pair[1], M1) # Check if any supports are dominated for col player - and self._row_cond_dominance(pair[1], pair[0], M2.transpose())): + and self._row_cond_dominance(pair[1], pair[0], M2.transpose()) + ): a = self._solve_indifference(pair[0], pair[1], M2) b = self._solve_indifference(pair[1], pair[0], M1.transpose()) if a and b and self._is_NE(a, b, pair[0], pair[1], M1, M2): @@ -2140,16 +2139,13 @@ def _solve_indifference(self, support1, support2, M): # Checking particular case of supports of pure strategies if len(support2) == 1: for strategy2 in range(M.ncols()): - if M[strategy1][support2[0]] < \ - M[strategy1][strategy2]: + if M[strategy1][support2[0]] < M[strategy1][strategy2]: return False else: for strategy_pair2 in range(len(support2)): # Coefficients of linear system that ensure indifference # between two consecutive strategies of the support - linearsystem[strategy_pair2, strategy1] = \ - M[strategy1][support2[strategy_pair2]] -\ - M[strategy1][support2[strategy_pair2 - 1]] + linearsystem[strategy_pair2, strategy1] = M[strategy1][support2[strategy_pair2]] - M[strategy1][support2[strategy_pair2 - 1]] # Coefficients of linear system that ensure the vector is # a probability vector. ie. sum to 1 linearsystem[-1, strategy1] = 1 @@ -2215,27 +2211,18 @@ def _is_NE(self, a, b, p1_support, p2_support, M1, M2): False """ # Check that supports are obeyed - if not (all(a[i] > 0 for i in p1_support) and - all(b[j] > 0 for j in p2_support) and - all(a[i] == 0 for i in range(len(a)) - if i not in p1_support) and - all(b[j] == 0 for j in range(len(b)) - if j not in p2_support)): + if not (all(a[i] > 0 for i in p1_support) and all(b[j] > 0 for j in p2_support) and all(a[i] == 0 for i in range(len(a)) if i not in p1_support) and all(b[j] == 0 for j in range(len(b)) if j not in p2_support)): return False # Check that have pair of best responses - p1_payoffs = [sum(v * row[i] for i, v in enumerate(b)) - for row in M1.rows()] - p2_payoffs = [sum(v * col[j] for j, v in enumerate(a)) - for col in M2.columns()] + p1_payoffs = [sum(v * row[i] for i, v in enumerate(b)) for row in M1.rows()] + p2_payoffs = [sum(v * col[j] for j, v in enumerate(a)) for col in M2.columns()] # if p1_payoffs.index(max(p1_payoffs)) not in p1_support: - if not any(i in p1_support for i, x in enumerate(p1_payoffs) - if x == max(p1_payoffs)): + if not any(i in p1_support for i, x in enumerate(p1_payoffs) if x == max(p1_payoffs)): return False - return any(i in p2_support for i, x in enumerate(p2_payoffs) - if x == max(p2_payoffs)) + return any(i in p2_support for i, x in enumerate(p2_payoffs) if x == max(p2_payoffs)) def _lrs_nash_format(self, m1, m2): r""" @@ -2265,6 +2252,7 @@ def _lrs_nash_format(self, m1, m2): The former legacy format has been removed in :issue:`39464`. """ from sage.geometry.polyhedron.misc import _to_space_separated_string + m = self.players[0].num_strategies n = self.players[1].num_strategies s = f'{m} {n}\n\n' @@ -2430,26 +2418,19 @@ def is_degenerate(self, certificate=False) -> bool: games with more than two players. """ if len(self.players) > 2: - raise NotImplementedError("Tests for Degeneracy is not yet " - "implemented for games with more than " - "two players.") + raise NotImplementedError("Tests for Degeneracy is not yet " "implemented for games with more than " "two players.") d = self._is_degenerate_pure(certificate) if d: return d M1, M2 = self.payoff_matrices() - potential_supports = [[tuple(support) for support in - powerset(range(player.num_strategies))] - for player in self.players] + potential_supports = [[tuple(support) for support in powerset(range(player.num_strategies))] for player in self.players] # filter out all supports that are pure or empty - potential_supports = [[i for i in k if len(i) > 1] - for k in potential_supports] + potential_supports = [[i for i in k if len(i) > 1] for k in potential_supports] - potential_support_pairs = [pair for pair in - product(*potential_supports) if - len(pair[0]) != len(pair[1])] + potential_support_pairs = [pair for pair in product(*potential_supports) if len(pair[0]) != len(pair[1])] # Sort so that solve small linear systems first potential_support_pairs.sort(key=lambda x: sum([len(k) for k in x])) diff --git a/src/sage/game_theory/parser.py b/src/sage/game_theory/parser.py index d667adb427f..aabbbe24cba 100644 --- a/src/sage/game_theory/parser.py +++ b/src/sage/game_theory/parser.py @@ -1,6 +1,7 @@ """ Parser For gambit And lrs Nash Equilibria """ + # **************************************************************************** # Copyright (C) 2014 James Campbell james.campbell@tanti.org.uk # 2015 Vincent Knight @@ -142,6 +143,7 @@ def format_lrs(self): equilibria = [] from sage.misc.sage_eval import sage_eval from itertools import groupby, dropwhile + lines = iter(self.raw_string) # Skip comment lines starting with a single star lines = dropwhile(lambda line: line.startswith('*'), lines) @@ -265,10 +267,10 @@ def format_gambit(self, gambit_game): nice_stuff = [] for gambitstrategy in self.raw_string: gambitstrategy = list(gambitstrategy) - profile = [tuple(gambitstrategy[:len(gambit_game.players[0].strategies)])] + profile = [tuple(gambitstrategy[: len(gambit_game.players[0].strategies)])] for player in list(gambit_game.players)[1:]: previousplayerstrategylength = len(profile[-1]) - profile.append(tuple(gambitstrategy[previousplayerstrategylength: previousplayerstrategylength + len(player.strategies)])) + profile.append(tuple(gambitstrategy[previousplayerstrategylength : previousplayerstrategylength + len(player.strategies)])) nice_stuff.append(profile) return nice_stuff diff --git a/src/sage/games/all.py b/src/sage/games/all.py index d2b0648440e..976d6cce6aa 100644 --- a/src/sage/games/all.py +++ b/src/sage/games/all.py @@ -1,4 +1,3 @@ - from sage.misc.lazy_import import lazy_import lazy_import('sage.games.sudoku', ['Sudoku', 'sudoku']) diff --git a/src/sage/games/hexad.py b/src/sage/games/hexad.py index 6a8b5e178e5..d5266ae022e 100644 --- a/src/sage/games/hexad.py +++ b/src/sage/games/hexad.py @@ -63,6 +63,7 @@ Some details are also online at: https://www.permutationpuzzles.org/hexad/ """ + # **************************************************************************** # Copyright (C) 2005 David Joyner # @@ -139,6 +140,7 @@ class Minimog: [ 5 9 8 10] [ 4 1 6 7] """ + def __init__(self, type='shuffle'): self.type = type MS34 = MatrixSpace(SR, 3, 4) @@ -260,6 +262,7 @@ def _latex_(self): \end{array}\right)$ """ from sage.misc.latex import latex + return f"Minimog of type {self.type} associated to\n ${latex(self.minimog)}$" def print_kitten(self): @@ -376,11 +379,10 @@ def find_hexad1(self, pts): """ H = set(pts) L = set(pts) - linez = [(1, 2), (1, 3), (2, 3), (4, 5), (4, 6), (5, 6), - (7, 8), (7, 9), (8, 9), (10, 11), (10, 12), (11, 12)] + linez = [(1, 2), (1, 3), (2, 3), (4, 5), (4, 6), (5, 6), (7, 8), (7, 9), (8, 9), (10, 11), (10, 12), (11, 12)] for x in linez: x1 = int(x[0] - 1) - x2 = int(x[1] - 1) # (recall | is union) + x2 = int(x[1] - 1) # (recall | is union) if L <= (picture_set(self.picture02, self.line[x1]) | picture_set(self.picture02, self.line[x2])): WHAT = ["lines " + str(x), "picture " + str(1)] H = picture_set(self.picture02, self.line[x1]) | picture_set(self.picture02, self.line[x2]) @@ -425,15 +427,15 @@ def find_hexad2(self, pts, x0): L = set(pts) H = {x0} for i in range(18): - if (x0 == MINIMOG[2][1] and L <= picture_set(self.picture02, self.cross[i])): + if x0 == MINIMOG[2][1] and L <= picture_set(self.picture02, self.cross[i]): WHAT = ["cross " + str(i), "picture " + str(1)] H = H | picture_set(self.picture02, self.cross[i]) return list(H), WHAT - if (x0 == MINIMOG[0][2] and L <= picture_set(self.picture21, self.cross[i])): + if x0 == MINIMOG[0][2] and L <= picture_set(self.picture21, self.cross[i]): WHAT = ["cross " + str(i), "picture " + str(MINIMOG[0][2])] H = H | picture_set(self.picture21, self.cross[i]) return list(H), WHAT - if (x0 == MINIMOG[0][0] and L <= picture_set(self.picture00, self.cross[i])): + if x0 == MINIMOG[0][0] and L <= picture_set(self.picture00, self.cross[i]): WHAT = ["cross " + str(i), "picture " + str(6)] H = H | picture_set(self.picture00, self.cross[i]) return list(H), WHAT @@ -466,15 +468,15 @@ def find_hexad3(self, pts, x0, x1): L = set(pts) H = {x0, x1} for i in range(18): - if (MINIMOG[0][2] not in H and L <= picture_set(self.picture21, self.square[i])): + if MINIMOG[0][2] not in H and L <= picture_set(self.picture21, self.square[i]): WHAT = ["square " + str(i), "picture " + str(MINIMOG[0][2])] H = H | picture_set(self.picture21, self.square[i]) return list(H), WHAT - if (MINIMOG[2][1] not in H and L <= picture_set(self.picture02, self.square[i])): + if MINIMOG[2][1] not in H and L <= picture_set(self.picture02, self.square[i]): WHAT = ["square " + str(i), "picture " + str(MINIMOG[2][1])] H = H | picture_set(self.picture02, self.square[i]) return list(H), WHAT - if (MINIMOG[0][0] not in H and L <= picture_set(self.picture00, self.square[i])): + if MINIMOG[0][0] not in H and L <= picture_set(self.picture00, self.square[i]): WHAT = ["square " + str(i), "picture " + str(MINIMOG[0][0])] H = H | picture_set(self.picture00, self.square[i]) return list(H), WHAT @@ -542,36 +544,33 @@ def find_hexad(self, pts): H, WHAT = self.find_hexad0(LL - pts_at_infty) return H, WHAT if len(L2) == 2: # type 0 or 3 - if (MINIMOG[0][2] in LL and MINIMOG[2][1] in LL): - H, WHAT = self.find_hexad3(LL - {MINIMOG[0][2], MINIMOG[2][1]}, - MINIMOG[0][2], MINIMOG[2][1]) - if H: # must be type 3 + if MINIMOG[0][2] in LL and MINIMOG[2][1] in LL: + H, WHAT = self.find_hexad3(LL - {MINIMOG[0][2], MINIMOG[2][1]}, MINIMOG[0][2], MINIMOG[2][1]) + if H: # must be type 3 return list(H), WHAT # could be type 0 H, WHAT = self.find_hexad0(LL - L2) - if H: # must be type 0 + if H: # must be type 0 return list(H), WHAT - if (MINIMOG[2][1] in LL and MINIMOG[0][0] in LL): - H, WHAT = self.find_hexad3(LL - {MINIMOG[2][1], MINIMOG[0][0]}, - MINIMOG[2][1], MINIMOG[0][0]) - if H: # must be type 3 + if MINIMOG[2][1] in LL and MINIMOG[0][0] in LL: + H, WHAT = self.find_hexad3(LL - {MINIMOG[2][1], MINIMOG[0][0]}, MINIMOG[2][1], MINIMOG[0][0]) + if H: # must be type 3 return list(H), WHAT # could be type 0 H, WHAT = self.find_hexad0(LL - L2) - if H: # must be type 0 + if H: # must be type 0 return list(H), WHAT - if (MINIMOG[0][2] in LL and MINIMOG[0][0] in LL): - H, WHAT = self.find_hexad3(LL - {MINIMOG[0][2], MINIMOG[0][0]}, - MINIMOG[0][2], MINIMOG[0][0]) - if H: # must be type 3 + if MINIMOG[0][2] in LL and MINIMOG[0][0] in LL: + H, WHAT = self.find_hexad3(LL - {MINIMOG[0][2], MINIMOG[0][0]}, MINIMOG[0][2], MINIMOG[0][0]) + if H: # must be type 3 return list(H), WHAT # could be type 0 H, WHAT = self.find_hexad0(LL - L2) - if H: # must be type 0 + if H: # must be type 0 return list(H), WHAT if len(L2) == 1: H, WHAT = self.find_hexad2(LL - L2, list(L2)[0]) - if not H: # not a cross in picture at infinity + if not H: # not a cross in picture at infinity if list(L2)[0] == MINIMOG[2][1]: L1 = LL - L2 H, WHAT = self.find_hexad3(L1, MINIMOG[0][0], MINIMOG[2][1]) @@ -582,20 +581,20 @@ def find_hexad(self, pts): if H: return list(H), WHAT if list(L2)[0] == MINIMOG[0][0]: - L1 = (LL - L2) + L1 = LL - L2 H, WHAT = self.find_hexad3(L1, MINIMOG[0][0], MINIMOG[2][1]) if H: return list(H), WHAT - L1 = (LL - L2) + L1 = LL - L2 H, WHAT = self.find_hexad3(L1, MINIMOG[0][0], MINIMOG[0][2]) if H: return list(H), WHAT if list(L2)[0] == MINIMOG[0][2]: - L1 = (LL - L2) + L1 = LL - L2 H, WHAT = self.find_hexad3(L1, MINIMOG[0][0], MINIMOG[0][2]) if H: return list(H), WHAT - L1 = (LL - L2) + L1 = LL - L2 H, WHAT = self.find_hexad3(L1, MINIMOG[2][1], MINIMOG[0][2]) if H: return list(H), WHAT @@ -605,7 +604,7 @@ def find_hexad(self, pts): for i in LL: for j in pts_at_infty: H, WHAT = self.find_hexad2(LL - {i}, j) - if (H and i in H): + if H and i in H: return list(H), WHAT # L is in a cross H, WHAT = self.find_hexad1(LL) # L is a union of lines return H, WHAT diff --git a/src/sage/games/quantumino.py b/src/sage/games/quantumino.py index 587e279e042..295ce145f30 100644 --- a/src/sage/games/quantumino.py +++ b/src/sage/games/quantumino.py @@ -166,6 +166,7 @@ - [2] `Quantumino - How to Play `_ on Youtube - [3] Knuth, Donald (2000). *Dancing links*. :arxiv:`cs/0011047`. """ + # **************************************************************************** # Copyright (C) 2011 Sebastien Labbe # @@ -177,6 +178,7 @@ from sage.structure.sage_object import SageObject from sage.misc.lazy_import import lazy_import + lazy_import("sage.plot.all", "Graphics") lazy_import("sage.plot.plot3d.platonic", "cube") lazy_import("sage.plot.plot3d.shapes2", "text3d") @@ -187,23 +189,23 @@ # Example: The family games america: Quantumino ################################################ pentaminos = [] -pentaminos.append(Polyomino([(0,0,0), (1,0,0), (1,1,0), (1,2,0), (1,1,1)], color='deeppink')) -pentaminos.append(Polyomino([(0,0,0), (1,0,0), (1,0,1), (2,0,0), (2,1,0)], color='deeppink')) -pentaminos.append(Polyomino([(0,0,0), (1,0,0), (1,1,0), (1,2,0), (0,0,1)], color='green')) -pentaminos.append(Polyomino([(0,0,0), (0,1,0), (0,2,0), (1,0,0), (1,0,1)], color='green')) -pentaminos.append(Polyomino([(0,1,0), (1,0,1), (1,1,0), (1,1,1), (1,2,0)], color='red')) -pentaminos.append(Polyomino([(0,0,0), (1,0,0), (1,1,0), (1,0,1), (2,0,1)], color='red')) -pentaminos.append(Polyomino([(0,0,0), (1,0,0), (1,1,0), (1,2,0), (1,2,1)], color='orange')) -pentaminos.append(Polyomino([(0,0,0), (1,0,0), (0,1,0), (0,2,0), (0,2,1)], color='orange')) -pentaminos.append(Polyomino([(0,0,0), (1,0,0), (0,1,0), (1,1,0), (0,0,1)], color='yellow')) -pentaminos.append(Polyomino([(0,0,0), (1,0,0), (1,1,0), (1,1,1), (0,0,1)], color='yellow')) -pentaminos.append(Polyomino([(0,0,0), (0,1,0), (1,1,0), (0,2,0), (1,1,1)], color='midnightblue')) -pentaminos.append(Polyomino([(0,0,0), (1,0,0), (1,1,0), (1,0,1), (1,2,0)], color='darkblue')) -pentaminos.append(Polyomino([(0,0,0), (1,0,0), (1,1,0), (1,1,1), (2,1,1)], color='blue')) -pentaminos.append(Polyomino([(0,0,0), (0,1,0), (1,1,0), (1,1,1), (1,2,1)], color='blue')) -pentaminos.append(Polyomino([(0,0,0), (1,0,0), (1,1,0), (2,1,0), (2,1,1)], color='purple')) -pentaminos.append(Polyomino([(0,0,0), (0,1,0), (1,1,0), (1,2,0), (1,2,1)], color='purple')) -pentaminos.append(Polyomino([(0,1,0), (1,0,0), (1,1,0), (1,1,1), (1,2,0)], color='gray')) +pentaminos.append(Polyomino([(0, 0, 0), (1, 0, 0), (1, 1, 0), (1, 2, 0), (1, 1, 1)], color='deeppink')) +pentaminos.append(Polyomino([(0, 0, 0), (1, 0, 0), (1, 0, 1), (2, 0, 0), (2, 1, 0)], color='deeppink')) +pentaminos.append(Polyomino([(0, 0, 0), (1, 0, 0), (1, 1, 0), (1, 2, 0), (0, 0, 1)], color='green')) +pentaminos.append(Polyomino([(0, 0, 0), (0, 1, 0), (0, 2, 0), (1, 0, 0), (1, 0, 1)], color='green')) +pentaminos.append(Polyomino([(0, 1, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1), (1, 2, 0)], color='red')) +pentaminos.append(Polyomino([(0, 0, 0), (1, 0, 0), (1, 1, 0), (1, 0, 1), (2, 0, 1)], color='red')) +pentaminos.append(Polyomino([(0, 0, 0), (1, 0, 0), (1, 1, 0), (1, 2, 0), (1, 2, 1)], color='orange')) +pentaminos.append(Polyomino([(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 2, 0), (0, 2, 1)], color='orange')) +pentaminos.append(Polyomino([(0, 0, 0), (1, 0, 0), (0, 1, 0), (1, 1, 0), (0, 0, 1)], color='yellow')) +pentaminos.append(Polyomino([(0, 0, 0), (1, 0, 0), (1, 1, 0), (1, 1, 1), (0, 0, 1)], color='yellow')) +pentaminos.append(Polyomino([(0, 0, 0), (0, 1, 0), (1, 1, 0), (0, 2, 0), (1, 1, 1)], color='midnightblue')) +pentaminos.append(Polyomino([(0, 0, 0), (1, 0, 0), (1, 1, 0), (1, 0, 1), (1, 2, 0)], color='darkblue')) +pentaminos.append(Polyomino([(0, 0, 0), (1, 0, 0), (1, 1, 0), (1, 1, 1), (2, 1, 1)], color='blue')) +pentaminos.append(Polyomino([(0, 0, 0), (0, 1, 0), (1, 1, 0), (1, 1, 1), (1, 2, 1)], color='blue')) +pentaminos.append(Polyomino([(0, 0, 0), (1, 0, 0), (1, 1, 0), (2, 1, 0), (2, 1, 1)], color='purple')) +pentaminos.append(Polyomino([(0, 0, 0), (0, 1, 0), (1, 1, 0), (1, 2, 0), (1, 2, 1)], color='purple')) +pentaminos.append(Polyomino([(0, 1, 0), (1, 0, 0), (1, 1, 0), (1, 1, 1), (1, 2, 0)], color='gray')) def show_pentaminos(box=(5, 8, 2)): @@ -234,7 +236,7 @@ def show_pentaminos(box=(5, 8, 2)): q = p + (x, y, 0) G += q.show3d() G += text3d(str(i), (x, y, 2)) - G += cube(color='gray',opacity=0.5).scale(box).translate((17, 6, 0)) + G += cube(color='gray', opacity=0.5).scale(box).translate((17, 6, 0)) # hack to set the aspect ratio to 1 a, b = G.bounding_box() @@ -243,6 +245,7 @@ def show_pentaminos(box=(5, 8, 2)): return G + ############################## # Class QuantuminoState ############################## @@ -281,6 +284,7 @@ class QuantuminoState(SageObject): Quantumino state where the following pentamino is put aside : Polyomino: [(0, 0, 0), (0, 1, 0), (0, 2, 0), (1, 0, 0), (1, 0, 1)], Color: green """ + def __init__(self, pentos, aside, box=(5, 8, 2)): r""" EXAMPLES:: @@ -370,22 +374,23 @@ def show3d(self, size=0.85): G = Graphics() for p in self: G += p.show3d(size=size) - aside_pento = self._aside.canonical() + (2,-4,0) + aside_pento = self._aside.canonical() + (2, -4, 0) G += aside_pento.show3d(size=size) # the box to fill - half_box = tuple(a/2 for a in self._box) - b = cube(color='gray',opacity=0.2).scale(self._box).translate(half_box) - b = b.translate((0, -.5, -.5)) + half_box = tuple(a / 2 for a in self._box) + b = cube(color='gray', opacity=0.2).scale(self._box).translate(half_box) + b = b.translate((0, -0.5, -0.5)) G += b # hack to set the aspect ratio to 1 - a,b = G.bounding_box() - a,b = map(vector, (a,b)) - G.frame_aspect_ratio(tuple(b-a)) + a, b = G.bounding_box() + a, b = map(vector, (a, b)) + G.frame_aspect_ratio(tuple(b - a)) return G + ############################## # Class QuantuminoSolver ############################## @@ -412,6 +417,7 @@ class QuantuminoSolver(SageObject): Quantumino solver for the box (5, 4, 4) Aside pentamino number: 12 """ + def __init__(self, aside, box=(5, 8, 2)): r""" Constructor. @@ -439,7 +445,7 @@ def __repr__(self): Quantumino solver for the box (5, 8, 2) Aside pentamino number: 0 """ - s = "Quantumino solver for the box %s\n" % (self._box, ) + s = "Quantumino solver for the box %s\n" % (self._box,) s += "Aside pentamino number: %s" % self._aside return s @@ -467,7 +473,7 @@ def tiling_solver(self): Reflection allowed: False Reusing pieces allowed: False """ - pieces = pentaminos[:self._aside] + pentaminos[self._aside+1:] + pieces = pentaminos[: self._aside] + pentaminos[self._aside + 1 :] return TilingSolver(pieces, box=self._box) def solve(self, partial=None): diff --git a/src/sage/games/sudoku.py b/src/sage/games/sudoku.py index a500fef808e..85717e87914 100644 --- a/src/sage/games/sudoku.py +++ b/src/sage/games/sudoku.py @@ -12,6 +12,7 @@ - Tom Boothby (2008/05/02): Exact Cover, Dancing Links algorithm - Robert Beezer (2009/05/29): Backtracking algorithm, Sudoku class """ + ###################################################################### # Copyright (C) 2009, Robert A. Beezer # @@ -81,7 +82,7 @@ def sudoku(m): if not isinstance(m, Matrix): raise ValueError('sudoku function expects puzzle to be a matrix, perhaps use the Sudoku class') solution = next(Sudoku(m).solve(algorithm='dlx')) - return (solution.to_matrix() if solution else None) + return solution.to_matrix() if solution else None class Sudoku(SageObject): @@ -132,6 +133,7 @@ class Sudoku(SageObject): |4 9 1|8 5 6|7 2 3| +-----+-----+-----+ """ + def __init__(self, puzzle, verify_input=True): r""" Initialize a Sudoku puzzle, determine its size, sanity-check the inputs. @@ -190,7 +192,7 @@ def __init__(self, puzzle, verify_input=True): elif char == '.': puzzle_numeric.append(0) else: - puzzle_numeric.append(ord(char.upper()) - ord('A')+10) + puzzle_numeric.append(ord(char.upper()) - ord('A') + 10) self.puzzle = tuple(puzzle_numeric) else: raise ValueError('Sudoku puzzle must be specified as a matrix, list or string') @@ -199,7 +201,7 @@ def __init__(self, puzzle, verify_input=True): if self.n**4 != len(self.puzzle): raise ValueError('Sudoku puzzle dimension of %s must be a perfect square' % puzzle_size) for x in self.puzzle: - if (x < 0) or (x > self.n*self.n): + if (x < 0) or (x > self.n * self.n): raise ValueError('Sudoku puzzle has an invalid entry') def __eq__(self, other): @@ -312,6 +314,7 @@ def _matrix_(self, R=None): ValueError: Sudoku puzzles only convert to matrices over Integer Ring, not Rational Field """ from sage.rings.integer_ring import ZZ, IntegerRing_class + if R and not isinstance(R, IntegerRing_class): raise ValueError('Sudoku puzzles only convert to matrices over %s, not %s' % (ZZ, R)) return self.to_matrix() @@ -360,7 +363,7 @@ def to_string(self): elif 1 <= x <= 9: encoded.append(str(x)) elif x <= 36: - encoded.append(chr(x-10+ord('a'))) + encoded.append(chr(x - 10 + ord('a'))) else: raise ValueError('Sudoku string representation is only valid for puzzles of size 36 or smaller') return ''.join(encoded) @@ -408,7 +411,8 @@ def to_matrix(self): """ from sage.rings.integer_ring import ZZ from sage.matrix.constructor import matrix - return matrix(ZZ, self.n*self.n, self.puzzle) + + return matrix(ZZ, self.n * self.n, self.puzzle) def to_ascii(self): r""" @@ -430,12 +434,13 @@ def to_ascii(self): '+---+---+\n| 4| |\n|3 2| |\n+---+---+\n| |1 4|\n| |3 |\n+---+---+' """ from re import compile + n = self.n - nsquare = n*n + nsquare = n * n m = self.to_matrix() - m.subdivide(list(range(0,nsquare+1,n)), list(range(0,nsquare+1,n))) + m.subdivide(list(range(0, nsquare + 1, n)), list(range(0, nsquare + 1, n))) naked_zero = compile(r'([\|, ]+)0') - blanked = naked_zero.sub(lambda x: x.group(1)+' ', m.str()) + blanked = naked_zero.sub(lambda x: x.group(1) + ' ', m.str()) brackets = compile(r'[\[,\]]') return brackets.sub('', blanked) @@ -461,7 +466,7 @@ def to_latex(self): '\\begin{array}{|*{2}{*{2}{r}|}}\\hline\n &4& & \\\\\n3&2& & \\\\\\hline\n & &1&4\\\\\n & &3& \\\\\\hline\n\\end{array}' """ n = self.n - nsquare = n*n + nsquare = n * n array = [] array.append('\\begin{array}{|*{%s}{*{%s}{r}|}}\\hline\n' % (n, n)) gen = iter(self.puzzle) @@ -470,7 +475,7 @@ def to_latex(self): entry = next(gen) array.append(str(entry) if entry else ' ') array.append('' if col == nsquare - 1 else '&') - array.append('\\\\\n' if (row+1) % n else '\\\\\\hline\n') + array.append('\\\\\n' if (row + 1) % n else '\\\\\\hline\n') array.append('\\end{array}') return ''.join(array) @@ -719,6 +724,7 @@ def backtrack(self): +-----+-----+-----+ """ from .sudoku_backtrack import backtrack_all + solutions = backtrack_all(self.n, self.puzzle) yield from solutions @@ -821,21 +827,21 @@ def dlx(self, count_only=False): from sage.combinat.matrices.dlxcpp import DLXCPP n = self.n - nsquare = n*n - nfour = nsquare*nsquare + nsquare = n * n + nfour = nsquare * nsquare # Boxes of the grid are numbered in row-major order # ``rcbox`` simply maps a row-column index pair to the box number it lives in - rcbox = [ [i//n + n*(j//n) for i in range(nsquare)] for j in range(nsquare)] + rcbox = [[i // n + n * (j // n) for i in range(nsquare)] for j in range(nsquare)] # Every entry in a Sudoku puzzle satisfies four constraints # Every location has a single entry, and each row, column and box has each symbol once # These arrays can be thought of as assigning ID numbers to these constraints, # and correspond to column numbers of the `0-1` matrix describing the exact cover - rows = [[i+j for i in range(nsquare)] for j in range(0, nfour, nsquare)] - cols = [[i+j for i in range(nsquare)] for j in range(nfour, 2*nfour, nsquare)] - boxes = [[i+j for i in range(nsquare)] for j in range(2*nfour, 3*nfour, nsquare)] - rowcol = [[i+j for i in range(nsquare)] for j in range(3*nfour, 4*nfour, nsquare)] + rows = [[i + j for i in range(nsquare)] for j in range(0, nfour, nsquare)] + cols = [[i + j for i in range(nsquare)] for j in range(nfour, 2 * nfour, nsquare)] + boxes = [[i + j for i in range(nsquare)] for j in range(2 * nfour, 3 * nfour, nsquare)] + rowcol = [[i + j for i in range(nsquare)] for j in range(3 * nfour, 4 * nfour, nsquare)] def make_row(row, col, entry): r""" @@ -867,7 +873,7 @@ def make_row(row, col, entry): for col in range(nsquare): puzz = next(gen) # All (zero-based) entries are possible, or only one is possible - entries = ([puzz-1] if puzz else range(nsquare)) + entries = [puzz - 1] if puzz else range(nsquare) for entry in entries: ones.append(make_row(row, col, entry)) rowinfo.append((row, col, entry)) diff --git a/src/sage/geometry/all.py b/src/sage/geometry/all.py index 0115d5b3ba8..95977aad32f 100644 --- a/src/sage/geometry/all.py +++ b/src/sage/geometry/all.py @@ -7,9 +7,7 @@ lazy_import('sage.geometry', 'cone_catalog', 'cones') lazy_import('sage.geometry.fan', ['Fan', 'FaceFan', 'NormalFan', 'Fan2d']) lazy_import('sage.geometry.fan_morphism', 'FanMorphism') -lazy_import('sage.geometry.lattice_polytope', - ['LatticePolytope', 'NefPartition', - 'ReflexivePolytope', 'ReflexivePolytopes']) +lazy_import('sage.geometry.lattice_polytope', ['LatticePolytope', 'NefPartition', 'ReflexivePolytope', 'ReflexivePolytopes']) lazy_import('sage.geometry', 'lattice_polytope') lazy_import('sage.geometry.toric_lattice', 'ToricLattice') lazy_import('sage.geometry', 'toric_plotter') diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index 4664653a18c..2dfd65e3199 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -205,14 +205,16 @@ from warnings import warn from sage.misc.lazy_import import lazy_import + lazy_import('sage.combinat.posets.posets', 'FinitePoset') from sage.arith.misc import GCD as gcd from sage.arith.functions import lcm from sage.geometry.point_collection import PointCollection from sage.geometry.polyhedron.constructor import Polyhedron + lazy_import('sage.geometry.hasse_diagram', 'lattice_from_incidences') -from sage.geometry.toric_lattice import (ToricLattice, ToricLattice_generic, - ToricLattice_quotient) +from sage.geometry.toric_lattice import ToricLattice, ToricLattice_generic, ToricLattice_quotient + lazy_import('sage.geometry.toric_plotter', ['ToricPlotter', 'label_list']) from sage.geometry.relative_interior import RelativeInterior from sage.matrix.constructor import matrix @@ -228,16 +230,15 @@ from sage.structure.sage_object import SageObject from sage.structure.element import parent from sage.structure.richcmp import richcmp_method, richcmp + lazy_import('sage.geometry.integral_points', 'parallelotope_points') from sage.geometry.convex_set import ConvexSet_closed import sage.geometry.abc from sage.features import PythonModule -lazy_import('ppl', ['C_Polyhedron', 'Generator_System', 'Constraint_System', - 'Linear_Expression', 'Poly_Con_Relation'], - feature=PythonModule("ppl", spkg='pplpy', type='standard')) -lazy_import('ppl', ['ray', 'point'], as_=['PPL_ray', 'PPL_point'], - feature=PythonModule("ppl", spkg='pplpy', type='standard')) + +lazy_import('ppl', ['C_Polyhedron', 'Generator_System', 'Constraint_System', 'Linear_Expression', 'Poly_Con_Relation'], feature=PythonModule("ppl", spkg='pplpy', type='standard')) +lazy_import('ppl', ['ray', 'point'], as_=['PPL_ray', 'PPL_point'], feature=PythonModule("ppl", spkg='pplpy', type='standard')) def Cone(rays, lattice=None, check=True, normalize=True): @@ -416,8 +417,7 @@ def Cone(rays, lattice=None, check=True, normalize=True): raise ValueError("%s is not a cone!" % polyhedron) apex = polyhedron.vertices()[0] if apex.count(0) != len(apex): - raise ValueError("the apex of %s is not at the origin!" - % polyhedron) + raise ValueError("the apex of %s is not at the origin!" % polyhedron) rays = normalize_rays(polyhedron.rays(), lattice) for line in normalize_rays(polyhedron.lines(), lattice): rays.append(line) @@ -431,22 +431,20 @@ def Cone(rays, lattice=None, check=True, normalize=True): if rays: lattice = rays[0].parent() else: - raise ValueError( - "lattice must be given explicitly if there are no rays!") + raise ValueError("lattice must be given explicitly if there are no rays!") if not check or not rays: return ConvexRationalPolyhedralCone(rays, lattice) # Any set of rays forms a cone, but we want to keep only generators if isinstance(lattice, ToricLattice_quotient): - gs = Generator_System( - PPL_point(Linear_Expression(lattice(0).vector(), 0))) + gs = Generator_System(PPL_point(Linear_Expression(lattice(0).vector(), 0))) for r in rays: if not r.is_zero(): gs.insert(PPL_ray(Linear_Expression(r.vector(), 0))) else: - gs = Generator_System( PPL_point(Linear_Expression(lattice(0),0)) ) + gs = Generator_System(PPL_point(Linear_Expression(lattice(0), 0))) for r in rays: if not r.is_zero(): - gs.insert( PPL_ray(Linear_Expression(r,0)) ) + gs.insert(PPL_ray(Linear_Expression(r, 0))) cone = C_Polyhedron(gs) return _Cone_from_PPL(cone, lattice, rays) @@ -489,8 +487,7 @@ def _Cone_from_PPL(cone, lattice, original_rays=None): rays.append(g) if g.is_line(): lines.append(g) - if (original_rays is not None and not lines and - len(rays) == len(original_rays)): + if original_rays is not None and not lines and len(rays) == len(original_rays): return ConvexRationalPolyhedralCone(original_rays, lattice, PPL=cone) rays = [ray.coefficients() for ray in rays] for line in lines: @@ -582,8 +579,7 @@ def try_base_extend(ring): if p is not None: return p if isinstance(parent(data), ToricLattice_generic): - raise TypeError("the point %s and %s have incompatible " - "lattices" % (data, body)) + raise TypeError("the point %s and %s have incompatible " "lattices" % (data, body)) # If we don't have a lattice element, try successively # less-desirable ambient spaces until (as a last resort) we @@ -608,8 +604,7 @@ def try_base_extend(ring): return p # Raise TypeError with our own message - raise TypeError("%s does not represent a valid point in the ambient " - "space of %s" % (data, body)) + raise TypeError("%s does not represent a valid point in the ambient " "space of %s" % (data, body)) def integral_length(v): @@ -686,14 +681,11 @@ def normalize_rays(rays, lattice): try: rays = list(rays) except TypeError: - raise TypeError( - "rays must be given as a list or a compatible structure!" - "\nGot: %s" % rays) + raise TypeError("rays must be given as a list or a compatible structure!" "\nGot: %s" % rays) if rays: if lattice is None: ray_parent = parent(rays[0]) - lattice = (ray_parent if isinstance(ray_parent, ToricLattice_generic) - else ToricLattice(len(rays[0]))) + lattice = ray_parent if isinstance(ray_parent, ToricLattice_generic) else ToricLattice(len(rays[0])) if lattice.base_ring() is not ZZ: raise TypeError("lattice must be a free module over ZZ") # Are we dealing with a quotient lattice? @@ -825,8 +817,7 @@ def __richcmp__(self, right, op): # We probably do need to have explicit comparison of lattices here # since if one of the collections does not live in a toric lattice, # comparison of rays may miss the difference. - return richcmp((self.lattice(), self.rays()), - (right.lattice(), right.rays()), op) + return richcmp((self.lattice(), self.rays()), (right.lattice(), right.rays()), op) def __hash__(self): r""" @@ -1007,7 +998,7 @@ def dual_lattice(self): try: return self.lattice().dual() except AttributeError: - return ZZ**self.lattice_dim() + return ZZ ** self.lattice_dim() def lattice_dim(self): r""" @@ -1215,7 +1206,7 @@ def codim(self): """ # same as ConvexSet_base.codim; the main point is the much more detailed # docstring. - return (self.lattice_dim() - self.dim()) + return self.lattice_dim() - self.dim() codimension = codim @@ -1344,34 +1335,34 @@ def classify_cone_2d(ray0, ray1, check=True): assert gcd(ray1) == 1 assert not ray0.is_zero() and not ray1.is_zero() - m = matrix([ray0, ray1]) # dim(ray) x 2 matrix + m = matrix([ray0, ray1]) # dim(ray) x 2 matrix basis = m.saturation().solve_left(m) # 2-d basis for the span of the cone basis = basis.change_ring(ZZ).transpose() if basis.nrows() < 2: d = 0 - k = basis[0,1] + k = basis[0, 1] else: - basis.echelonize() # columns are the "cone normal form" - d = basis[1,1] - k = basis[0,1] + basis.echelonize() # columns are the "cone normal form" + d = basis[1, 1] + k = basis[0, 1] if check: if d == 0: # degenerate cone - assert basis[0,0] == 1 + assert basis[0, 0] == 1 assert k == -1 or k == +1 - else: # non-degenerate cone - assert basis[0,0] == 1 and basis[1,0] == 0 + else: # non-degenerate cone + assert basis[0, 0] == 1 and basis[1, 0] == 0 assert d > 0 assert 0 <= k < d - assert gcd(d,k) == 1 + assert gcd(d, k) == 1 # compute unique k, see Proposition 10.1.3 of [CLS2011] if d > 0: for ktilde in range(k): - if (k*ktilde) % d == 1: + if (k * ktilde) % d == 1: k = ktilde break - return (d,k) + return (d, k) # Derived classes MUST allow construction of their objects using ``ambient`` @@ -1429,8 +1420,7 @@ class ConvexRationalPolyhedralCone(IntegralRayCollection, Container, ConvexSet_c this cone itself. """ - def __init__(self, rays=None, lattice=None, - ambient=None, ambient_ray_indices=None, PPL=None): + def __init__(self, rays=None, lattice=None, ambient=None, ambient_ray_indices=None, PPL=None): r""" See :class:`ConvexRationalPolyhedralCone` for documentation. @@ -1473,8 +1463,7 @@ def __init__(self, rays=None, lattice=None, else: self._ambient = ambient self._ambient_ray_indices = tuple(ambient_ray_indices) - superinit(ambient.rays(self._ambient_ray_indices), - ambient.lattice()) + superinit(ambient.rays(self._ambient_ray_indices), ambient.lattice()) if PPL is not None: self._PPL_C_Polyhedron = PPL @@ -1521,10 +1510,9 @@ def _PPL_cone(self): defined as the convex hull of 1 point """ if "_PPL_C_Polyhedron" not in self.__dict__: - gs = Generator_System( - PPL_point(Linear_Expression(self._lattice(0), 0))) + gs = Generator_System(PPL_point(Linear_Expression(self._lattice(0), 0))) for r in self.rays(): - gs.insert( PPL_ray(Linear_Expression(r,0)) ) + gs.insert(PPL_ray(Linear_Expression(r, 0))) self._PPL_C_Polyhedron = C_Polyhedron(gs) return self._PPL_C_Polyhedron @@ -1652,9 +1640,7 @@ def _contains(self, point, region='whole cone') -> bool: point = _ambient_space_point(self, point) except TypeError as ex: if str(ex).endswith("have incompatible lattices!"): - warn("you have checked if a cone contains a point " - "from an incompatible lattice, this is False!", - stacklevel=3) + warn("you have checked if a cone contains a point " "from an incompatible lattice, this is False!", stacklevel=3) return False if region not in ("whole cone", "relative interior", "interior"): @@ -1908,8 +1894,7 @@ def __richcmp__(self, right, op): """ if isinstance(right, sage.geometry.abc.ConvexRationalPolyhedralCone): # We don't care about particular type of right in this case - return richcmp((self.lattice(), self.rays()), - (right.lattice(), right.rays()), op) + return richcmp((self.lattice(), self.rays()), (right.lattice(), right.rays()), op) return NotImplemented def _latex_(self): @@ -1928,8 +1913,7 @@ def _latex_(self): """ if self.ambient() is self: return r"\sigma^{%d}" % self.dim() - return r"\sigma^{%d} \subset %s" % (self.dim(), - latex(self.ambient())) + return r"\sigma^{%d} \subset %s" % (self.dim(), latex(self.ambient())) def _repr_(self): r""" @@ -2003,18 +1987,16 @@ def _sort_faces(self, faces): ....: print("Wrong order!") """ faces = tuple(faces) - if len(faces) > 1: # Otherwise there is nothing to sort + if len(faces) > 1: # Otherwise there is nothing to sort if faces[0].n_rays() == 1: - faces = tuple(sorted(faces, - key=lambda f: f._ambient_ray_indices)) - elif faces[0].dim() == self.dim() - 1 and \ - self.facet_normals.is_in_cache(): + faces = tuple(sorted(faces, key=lambda f: f._ambient_ray_indices)) + elif faces[0].dim() == self.dim() - 1 and self.facet_normals.is_in_cache(): # If we already have facet normals, sort according to them faces = set(faces) sorted_faces = [None] * len(faces) for i, n in enumerate(self.facet_normals()): for f in faces: - if n*f.rays() == 0: + if n * f.rays() == 0: sorted_faces[i] = f faces.remove(f) break @@ -2353,8 +2335,7 @@ def embed(self, cone): if self.is_strictly_convex(): rays = self.rays() try: - ray_indices = tuple(sorted(rays.index(ray) - for ray in cone.rays())) + ray_indices = tuple(sorted(rays.index(ray) for ray in cone.rays())) for face in self.faces(cone.dim()): if face.ambient_ray_indices() == ray_indices: return face @@ -2519,10 +2500,8 @@ def face_lattice(self): def ConeFace(atoms, facets): if facets: - rays = sorted([atom_to_ray[a] for a in atoms] - + subspace_rays) - face = ConvexRationalPolyhedralCone( - ambient=self, ambient_ray_indices=rays) + rays = sorted([atom_to_ray[a] for a in atoms] + subspace_rays) + face = ConvexRationalPolyhedralCone(ambient=self, ambient_ray_indices=rays) # It may be nice if this functionality is exposed, # however it makes sense only for cones which are # thought of as faces of a single cone, not of a fan. @@ -2534,34 +2513,29 @@ def ConeFace(atoms, facets): # with rows corresponding to rays in subspace removed. mod_incidence_matrix = self.incidence_matrix()[atom_to_ray] - atom_to_facets = [row.nonzero_positions() - for row in mod_incidence_matrix.rows()] - facet_to_atoms = [column.nonzero_positions() - for column in mod_incidence_matrix.columns()] + atom_to_facets = [row.nonzero_positions() for row in mod_incidence_matrix.rows()] + facet_to_atoms = [column.nonzero_positions() for column in mod_incidence_matrix.columns()] - self._face_lattice = lattice_from_incidences( - atom_to_facets, facet_to_atoms, ConeFace, - key=id(self)) + self._face_lattice = lattice_from_incidences(atom_to_facets, facet_to_atoms, ConeFace, key=id(self)) else: # Get face lattice as a sublattice of the ambient one allowed_indices = frozenset(self._ambient_ray_indices) from sage.graphs.digraph import DiGraph + L = DiGraph() - origin = \ - self._ambient._face_lattice_function().bottom() - L.add_vertex(0) # In case it is the only one + origin = self._ambient._face_lattice_function().bottom() + L.add_vertex(0) # In case it is the only one dfaces = [origin] faces = [origin] - face_to_index = {origin:0} + face_to_index = {origin: 0} next_index = 1 - next_d = 1 # Dimension of faces to be considered next. + next_d = 1 # Dimension of faces to be considered next. while next_d < self.dim(): ndfaces = [] for face in dfaces: face_index = face_to_index[face] for new_face in face.facet_of(): - if not allowed_indices.issuperset( - new_face._ambient_ray_indices): + if not allowed_indices.issuperset(new_face._ambient_ray_indices): continue if new_face in ndfaces: new_face_index = face_to_index[new_face] @@ -2701,12 +2675,10 @@ def faces(self, dim=None, codim=None): in 2-d lattice N """ if dim is not None and codim is not None: - raise ValueError( - "dimension and codimension cannot be specified together!") + raise ValueError("dimension and codimension cannot be specified together!") dim = self.dim() - codim if codim is not None else dim if "_faces" not in self.__dict__: - self._faces = tuple(map(self._sort_faces, - self.face_lattice().level_sets())) + self._faces = tuple(map(self._sort_faces, self.face_lattice().level_sets())) if dim is None: return self._faces lsd = self.linear_subspace().dimension() @@ -2808,16 +2780,16 @@ def facet_normals(self): n.set_immutable() if len(normals) > 1: # Sort normals if they are rays - if self.dim() == 2 and normals[0]*self.ray(0) != 0: + if self.dim() == 2 and normals[0] * self.ray(0) != 0: normals = (normals[1], normals[0]) else: - try: # or if we have combinatorial faces already + try: # or if we have combinatorial faces already facets = self._faces[-2] normals = set(normals) sorted_normals = [None] * len(normals) for i, f in enumerate(facets): for n in normals: - if n*f.rays() == 0: + if n * f.rays() == 0: sorted_normals[i] = n normals.remove(n) break @@ -2859,8 +2831,7 @@ def facet_of(self): """ L = self._ambient._face_lattice_function() H = L.hasse_diagram() - return self._sort_faces( - f for f in H.neighbors_out(L(self)) if isinstance(f, sage.geometry.abc.ConvexRationalPolyhedralCone)) + return self._sort_faces(f for f in H.neighbors_out(L(self)) if isinstance(f, sage.geometry.abc.ConvexRationalPolyhedralCone)) def facets(self): r""" @@ -2916,12 +2887,11 @@ def incidence_matrix(self): Integer Ring """ normals = self.facet_normals() - incidence_matrix = matrix(ZZ, self.n_rays(), - len(normals), 0) + incidence_matrix = matrix(ZZ, self.n_rays(), len(normals), 0) for Hindex, normal in enumerate(self.facet_normals()): for Vindex, ray in enumerate(self.rays()): - if normal*ray == 0: + if normal * ray == 0: incidence_matrix[Vindex, Hindex] = 1 incidence_matrix.set_immutable() @@ -2997,12 +2967,10 @@ def intersection(self, other): # Cones of the same ambient cone or fan intersect nicely/quickly. # Can we maybe even return an element of the cone lattice?.. # But currently it can be done only for strictly convex cones. - ambient_ray_indices = tuple(r for r in self._ambient_ray_indices - if r in other._ambient_ray_indices) + ambient_ray_indices = tuple(r for r in self._ambient_ray_indices if r in other._ambient_ray_indices) # type(self) allows this code to work nicely for derived classes, # although it forces all of them to accept such input - return type(self)(ambient=self._ambient, - ambient_ray_indices=ambient_ray_indices) + return type(self)(ambient=self._ambient, ambient_ray_indices=ambient_ray_indices) # Generic (slow) intersection, returning a generic cone. p = C_Polyhedron(self._PPL_cone()) p.add_constraints(other._PPL_cone().constraints()) @@ -3114,7 +3082,7 @@ def is_face_of(self, cone): if self.is_equivalent(cone): return True # Obviously False case - if self.dim() >= cone.dim(): # if == and face, we return True above + if self.dim() >= cone.dim(): # if == and face, we return True above return False # It remains to test whether self is a proper face of cone: @@ -3126,8 +3094,7 @@ def is_face_of(self, cone): if c.is_equality() and not rel.implies(saturates): return False if c.is_inequality() and rel.implies(saturates): - c_eq = (Linear_Expression(c.coefficients(), - c.inhomogeneous_term()) == 0) + c_eq = Linear_Expression(c.coefficients(), c.inhomogeneous_term()) == 0 supporting_hyperplanes.insert(c_eq) if supporting_hyperplanes.empty(): return False @@ -3199,11 +3166,11 @@ def is_isomorphic(self, other): """ if self.is_strictly_convex() and other.is_strictly_convex(): from sage.geometry.fan import Fan + return Fan([self]).is_isomorphic(Fan([other])) if self.is_strictly_convex() ^ other.is_strictly_convex(): return False - raise NotImplementedError("isomorphism check for not strictly convex " - "cones is not implemented") + raise NotImplementedError("isomorphism check for not strictly convex " "cones is not implemented") def is_simplicial(self) -> bool: r""" @@ -3315,8 +3282,7 @@ def is_strictly_convex(self) -> bool: sage: cone2.is_strictly_convex() False """ - return all(not gs.is_line() - for gs in self._PPL_cone().minimized_generators()) + return all(not gs.is_line() for gs in self._PPL_cone().minimized_generators()) def is_pointed(self) -> bool: r""" @@ -3494,8 +3460,7 @@ def plot(self, **options): deg = self.lattice().degree() tp = ToricPlotter(options, deg, self.rays()) # Modify ray labels to match the ambient cone or fan. - tp.ray_label = label_list(tp.ray_label, self.n_rays(), deg <= 2, - self.ambient_ray_indices()) + tp.ray_label = label_list(tp.ray_label, self.n_rays(), deg <= 2, self.ambient_ray_indices()) result = tp.plot_lattice() + tp.plot_generators() # To deal with non-strictly convex cones we separate rays and labels. result += tp.plot_ray_labels() @@ -3513,8 +3478,7 @@ def plot(self, **options): ambient_walls = self.ambient().faces(2) except AttributeError: ambient_walls = self.ambient().cones(2) - tp.wall_label = label_list(tp.wall_label, len(walls), deg <= 2, - [ambient_walls.index(wall) for wall in walls]) + tp.wall_label = label_list(tp.wall_label, len(walls), deg <= 2, [ambient_walls.index(wall) for wall in walls]) tp.set_rays(self.ambient().rays()) result += tp.plot_walls(walls) return result @@ -3647,11 +3611,10 @@ def strict_quotient(self): # for names. If many subcones land in the same lattice - # that's just how it goes. if isinstance(L, ToricLattice_generic): - S = ToricLattice(Q.dimension(), L._name, L._dual_name, - L._latex_name, L._latex_dual_name) + S = ToricLattice(Q.dimension(), L._name, L._dual_name, L._latex_name, L._latex_dual_name) else: - S = ZZ**Q.dimension() - rays = ( Q(ray) for ray in self if not Q(ray).is_zero() ) + S = ZZ ** Q.dimension() + rays = (Q(ray) for ray in self if not Q(ray).is_zero()) quotient = Cone(rays, S, check=False) quotient._is_strictly_convex = True return quotient @@ -3764,14 +3727,13 @@ def solid_restriction(self): # similar to those in the strict_quotient() method. L = self.lattice() subL = self.sublattice() - S = ToricLattice(subL.dimension(), L._name, - L._dual_name, L._latex_name, L._latex_dual_name) + S = ToricLattice(subL.dimension(), L._name, L._dual_name, L._latex_name, L._latex_dual_name) # We don't need to check if these rays are zero: they will all # have at least one nonzero coordinate; otherwise they would # lie outside of the span of our cone. And they don't, because # they generate the cone. - rays = ( S(subL.coordinates(ray)) for ray in self ) + rays = (S(subL.coordinates(ray)) for ray in self) return Cone(rays, lattice=S, check=False) def _split_ambient_lattice(self): @@ -3811,7 +3773,7 @@ def _split_ambient_lattice(self): n = N.dimension() basis = self.rays().basis() r = len(basis) - Nsigma = matrix(ZZ, r, n, ( N.coordinates(v) for v in basis )) + Nsigma = matrix(ZZ, r, n, (N.coordinates(v) for v in basis)) D, U, V = Nsigma.smith_form() # D = U*N*V <=> N = Uinv*D*Vinv basis = (V.inverse() * N.basis_matrix()).rows() # spanned lattice N_sigma @@ -4050,8 +4012,7 @@ def orthogonal_sublattice(self, *args, **kwds): Nsigma = column_matrix(ZZ, (N.coordinates(v) for v in basis)) D, U, V = Nsigma.smith_form() # D = U * Nsigma * V M = self.dual_lattice() - self._orthogonal_sublattice = M.submodule_with_basis( - U.rows()[len(basis):]) + self._orthogonal_sublattice = M.submodule_with_basis(U.rows()[len(basis) :]) if args or kwds: return self._orthogonal_sublattice(*args, **kwds) return self._orthogonal_sublattice @@ -4148,7 +4109,7 @@ def relative_quotient(self, subcone): Nsubcone = subcone.sublattice() extra_ray = None - if Ncone.dimension()-Nsubcone.dimension() == 1: + if Ncone.dimension() - Nsubcone.dimension() == 1: extra_ray = set(self.rays().set() - subcone.rays().set()).pop() Q = Ncone.quotient(Nsubcone, positive_point=extra_ray) @@ -4243,7 +4204,7 @@ def relative_orthogonal_quotient(self, supercone): Msupercone = supercone.orthogonal_sublattice() extra_ray = None - if Mcone.dimension()-Msupercone.dimension() == 1: + if Mcone.dimension() - Msupercone.dimension() == 1: extra_ray = set(supercone.rays().set() - self.rays().set()).pop() Q = Mcone.quotient(Msupercone, positive_dual_point=extra_ray) @@ -4367,21 +4328,19 @@ def semigroup_generators(self): # recursively N = self.lattice() if not self.is_simplicial(): - from sage.geometry.triangulation.point_configuration \ - import PointConfiguration - origin = self.n_rays() # last one in pc + from sage.geometry.triangulation.point_configuration import PointConfiguration + + origin = self.n_rays() # last one in pc pc = PointConfiguration(tuple(self.rays()) + (N(0),), star=origin) triangulation = pc.triangulate() - subcones = ( Cone(( self.ray(i) for i in simplex if i != origin ), - lattice=N, check=False) - for simplex in triangulation ) + subcones = (Cone((self.ray(i) for i in simplex if i != origin), lattice=N, check=False) for simplex in triangulation) gens = set() for cone in subcones: gens.update(cone.semigroup_generators()) return tuple(gens) gens = list(parallelotope_points(self.rays(), N)) + list(self.rays()) - gens = ( v for v in gens if gcd(v) == 1 ) + gens = (v for v in gens if gcd(v) == 1) return PointCollection(gens, N) @cached_method @@ -4517,20 +4476,17 @@ def Hilbert_basis(self): if not self.is_strictly_convex(): # Our linear_subspace(), but as a cone, so that # containment testing using "in" works properly. - L = Cone((c*r for c in (1, -1) for r in self.lines()), - self.lattice(), - check=False) + L = Cone((c * r for c in (1, -1) for r in self.lines()), self.lattice(), check=False) irreducible = list(self.rays()) # these are irreducible for sure irr_modified = False # have we appended to "irreducible"? - gens = [x for x in self.semigroup_generators() - if x not in irreducible] + gens = [x for x in self.semigroup_generators() if x not in irreducible] from itertools import chain + while gens: x = gens.pop() - if all((y in L) or (x-y not in self) - for y in chain(irreducible, gens)): + if all((y in L) or (x - y not in self) for y in chain(irreducible, gens)): irreducible.append(x) irr_modified = True @@ -4541,8 +4497,7 @@ def Hilbert_basis(self): # added to the irreducible list beyond self.rays(). return self.rays() - def Hilbert_coefficients(self, point, solver=None, verbose=0, - *, integrality_tolerance=1e-3): + def Hilbert_coefficients(self, point, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return the expansion coefficients of ``point`` with respect to :meth:`Hilbert_basis`. @@ -4621,11 +4576,12 @@ def Hilbert_coefficients(self, point, solver=None, verbose=0, basis = self.Hilbert_basis() from sage.numerical.mip import MixedIntegerLinearProgram + p = MixedIntegerLinearProgram(maximization=False, solver=solver) p.set_objective(None) x = p.new_variable(integer=True, nonnegative=True) for i in range(self.lattice_dim()): - p.add_constraint(p.sum(b[i]*x[j] for j,b in enumerate(basis)) == point[i]) + p.add_constraint(p.sum(b[i] * x[j] for j, b in enumerate(basis)) == point[i]) p.solve(log=verbose) return vector(ZZ, p.get_values(x, convert=ZZ, tolerance=integrality_tolerance)) @@ -4673,7 +4629,7 @@ def is_solid(self): sage: K.is_solid() == K.dual().is_strictly_convex() True """ - return (self.dim() == self.lattice_dim()) + return self.dim() == self.lattice_dim() is_full_dimensional = is_solid @@ -4720,7 +4676,7 @@ def is_proper(self): sage: halfspace.is_proper() False """ - return (self.is_strictly_convex() and self.is_solid()) + return self.is_strictly_convex() and self.is_solid() def is_full_space(self): r""" @@ -4940,9 +4896,7 @@ def discrete_complementarity_set(self): """ # Return an immutable tuple instead of a mutable list because # the result will be cached. - return tuple( (x,s) for x in self - for s in self.dual() - if s*x == 0 ) + return tuple((x, s) for x in self for s in self.dual() if s * x == 0) def lyapunov_like_basis(self): r""" @@ -5080,19 +5034,18 @@ def lyapunov_like_basis(self): # These tensor products contain a basis for the orthogonal # complement of the Lyapunov-like transformations on this cone. - tensor_products = ( s.tensor_product(x) - for (x,s) in self.discrete_complementarity_set() ) + tensor_products = (s.tensor_product(x) for (x, s) in self.discrete_complementarity_set()) # Convert those tensor products to long vectors. W = VectorSpace(F, n**2) - perp_vectors = ( W(tp.list()) for tp in tensor_products ) + perp_vectors = (W(tp.list()) for tp in tensor_products) # Now find the Lyapunov-like transformations (as long vectors). LL_vectors = W.span(perp_vectors).complement() # And finally convert the long vectors back to matrices. M = MatrixSpace(F, n, n) - return [ M(v.list()) for v in LL_vectors.basis() ] + return [M(v.list()) for v in LL_vectors.basis()] def lyapunov_rank(self): r""" @@ -5307,7 +5260,7 @@ def lyapunov_rank(self): l = self.lineality() # cf. Theorem 2 - return len(K_SP.lyapunov_like_basis()) + l*m + (n - m)*n + return len(K_SP.lyapunov_like_basis()) + l * m + (n - m) * n def random_element(self, ring=ZZ): r""" @@ -5445,7 +5398,7 @@ def random_element(self, ring=ZZ): L = L.vector_space() # Scale each generator by a random nonnegative factor. - terms = ( ring.random_element().abs()*L(g) for g in self ) + terms = (ring.random_element().abs() * L(g) for g in self) # Make sure we return a lattice element or vector. Without the # explicit conversion, we return ``0`` when we have no rays. @@ -5836,12 +5789,11 @@ def positive_operators_gens(self, K2=None): n = self.lattice_dim() m = K2.lattice_dim() - tensor_products = ( s.tensor_product(x) for x in self - for s in K2.dual() ) + tensor_products = (s.tensor_product(x) for x in self for s in K2.dual()) # Convert those tensor products to long vectors. - W = VectorSpace(F, n*m) - vectors = ( W(tp.list()) for tp in tensor_products ) + W = VectorSpace(F, n * m) + vectors = (W(tp.list()) for tp in tensor_products) check = True if self.is_proper() and K2.is_proper(): @@ -5861,7 +5813,7 @@ def positive_operators_gens(self, K2=None): # And finally convert its rays back to matrix representations. M = MatrixSpace(F, m, n) - return [ M(v.list()) for v in pi_cone ] + return [M(v.list()) for v in pi_cone] def cross_positive_operators_gens(self): r""" @@ -6103,12 +6055,11 @@ def cross_positive_operators_gens(self): # These tensor products contain generators for the dual cone of # the cross-positive operators. - tensor_products = ( s.tensor_product(x) - for (x,s) in self.discrete_complementarity_set() ) + tensor_products = (s.tensor_product(x) for (x, s) in self.discrete_complementarity_set()) # Turn our matrices into long vectors... W = VectorSpace(F, n**2) - vectors = ( W(m.list()) for m in tensor_products ) + vectors = (W(m.list()) for m in tensor_products) check = True if self.is_proper(): @@ -6121,16 +6072,14 @@ def cross_positive_operators_gens(self): # Create the dual cone of the cross-positive operators, # expressed as long vectors. - cp_dual = Cone(vectors, - lattice=ToricLattice(W.dimension()), - check=check) + cp_dual = Cone(vectors, lattice=ToricLattice(W.dimension()), check=check) # Now compute the desired cone from its dual... cp_cone = cp_dual.dual() # And finally convert its rays back to matrix representations. M = MatrixSpace(F, n) - return [ M(v.list()) for v in cp_cone ] + return [M(v.list()) for v in cp_cone] def Z_operators_gens(self): r""" @@ -6176,7 +6125,7 @@ def Z_operators_gens(self): sage: all(L.is_Z_operator_on(K) for L in Z_gens) True """ - return [ -cp for cp in self.cross_positive_operators_gens() ] + return [-cp for cp in self.cross_positive_operators_gens()] def max_angle(self, other=None, exact=True, epsilon=0): r""" @@ -6364,18 +6313,17 @@ def max_angle(self, other=None, exact=True, epsilon=0): if other is None: other = self else: - if (other.lattice_dim() != self.lattice_dim()): - raise ValueError("lattice dimensions of self and other " - "must agree") + if other.lattice_dim() != self.lattice_dim(): + raise ValueError("lattice dimensions of self and other " "must agree") if other.is_trivial(): raise ValueError("other cone cannot be trivial") from sage.geometry.cone_critical_angles import max_angle + return max_angle(self, other, exact, epsilon) -def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None, - min_rays=0, max_rays=None, strictly_convex=None, solid=None): +def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None, min_rays=0, max_rays=None, strictly_convex=None, solid=None): r""" Generate a random convex rational polyhedral cone. @@ -6740,7 +6688,7 @@ def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None, if max_ambient_dim is not None: if max_ambient_dim < 0: raise ValueError('max_ambient_dim must be nonnegative.') - if (max_ambient_dim < min_ambient_dim): + if max_ambient_dim < min_ambient_dim: msg = 'max_ambient_dim cannot be less than min_ambient_dim.' raise ValueError(msg) if lattice is not None: @@ -6771,7 +6719,7 @@ def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None, if max_rays is not None: if max_rays < 0: raise ValueError('max_rays must be nonnegative.') - if (max_rays < min_rays): + if max_rays < min_rays: raise ValueError('max_rays cannot be less than min_rays.') # Also perform the "futile search" checks when a lattice is given, @@ -6824,8 +6772,7 @@ def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None, if max_ambient_dim is not None and max_ambient_dim == 0: msg = 'all cones are solid when max_ambient_dim is zero.' raise ValueError(msg) - if (max_ambient_dim is not None and - min_rays > 2 * (max_ambient_dim - 1)): + if max_ambient_dim is not None and min_rays > 2 * (max_ambient_dim - 1): msg = 'every cone is solid when ' msg += 'min_rays > 2*(max_ambient_dim - 1).' raise ValueError(msg) @@ -6855,10 +6802,10 @@ def random_cone(lattice=None, min_ambient_dim=0, max_ambient_dim=None, if max_rays is None and max_ambient_dim is not None: # This is an upper limit on the number of rays in a # non-solid cone. - max_rays = 2*(max_ambient_dim - 1) + max_rays = 2 * (max_ambient_dim - 1) if max_rays is None and lattice is not None: # Same thing, except when we're given a lattice. - max_rays = 2*(lattice.dimension() - 1) + max_rays = 2 * (lattice.dimension() - 1) def random_min_max(l, u): r""" @@ -6887,17 +6834,12 @@ def is_valid(K): # We only care about min/max_ambient_dim when no lattice is given. if K.lattice_dim() < min_ambient_dim: return False - if (max_ambient_dim is not None and - K.lattice_dim() > max_ambient_dim): + if max_ambient_dim is not None and K.lattice_dim() > max_ambient_dim: return False else: if K.lattice() is not lattice: return False - return all([K.n_rays() >= min_rays, - max_rays is None or K.n_rays() <= max_rays, - solid is None or K.is_solid() == solid, - strictly_convex is None or - K.is_strictly_convex() == strictly_convex]) + return all([K.n_rays() >= min_rays, max_rays is None or K.n_rays() <= max_rays, solid is None or K.is_solid() == solid, strictly_convex is None or K.is_strictly_convex() == strictly_convex]) # Now we actually compute the thing. To avoid recursion (and the # associated "maximum recursion depth exceeded" error), we loop @@ -6940,7 +6882,7 @@ def is_valid(K): # ask for more than 2*d rays, then you'll probably get the # minimum amount, because we'll start with 2*d and add them # one-at-a-time (see below). - rays = [L.random_element() for i in range(min(r,2*d))] + rays = [L.random_element() for i in range(min(r, 2 * d))] # The lattice parameter is required when no rays are given, so # we pass it in case r == 0 or d == 0 (or d == 1 but we're @@ -6961,7 +6903,7 @@ def is_valid(K): while r > K.n_rays() and not K.is_full_space(): rays.append(L.random_element()) K = Cone(rays, lattice=L) - rays = list(K.rays()) # Avoid re-normalizing next time around + rays = list(K.rays()) # Avoid re-normalizing next time around if strictly_convex is not None: if strictly_convex: @@ -6974,7 +6916,8 @@ def is_valid(K): # coordinates become positive/negative is chosen # randomly. from sage.misc.prandom import choice - pm = choice([-1,1]) + + pm = choice([-1, 1]) # rays has immutable elements rays = [copy(ray) for ray in rays] diff --git a/src/sage/geometry/cone_catalog.py b/src/sage/geometry/cone_catalog.py index df71f26829b..6de5626aa00 100644 --- a/src/sage/geometry/cone_catalog.py +++ b/src/sage/geometry/cone_catalog.py @@ -146,8 +146,7 @@ def _preprocess_args(ambient_dim, lattice): from sage.geometry.toric_lattice import ToricLattice if ambient_dim is None and lattice is None: - raise ValueError("either the ambient dimension or the lattice " - "must be specified") + raise ValueError("either the ambient dimension or the lattice " "must be specified") if ambient_dim is None: ambient_dim = lattice.rank() @@ -156,8 +155,7 @@ def _preprocess_args(ambient_dim, lattice): lattice = ToricLattice(ambient_dim) if lattice.rank() != ambient_dim: - raise ValueError("lattice rank=%d and ambient_dim=%d " - "are incompatible" % (lattice.rank(), ambient_dim)) + raise ValueError("lattice rank=%d and ambient_dim=%d " "are incompatible" % (lattice.rank(), ambient_dim)) return (ambient_dim, lattice) @@ -230,11 +228,7 @@ def barker_foran(lattice=None): one = ZZ.one() zero = ZZ.zero() - ext = [( one, one, one), - ( zero, one, one), - (-one, zero, one), - ( zero, -one, one), - ( one, -one, one)] # noqa: E221 + ext = [(one, one, one), (zero, one, one), (-one, zero, one), (zero, -one, one), (one, -one, one)] # noqa: E221 return Cone(ext, lattice, check=False) @@ -371,7 +365,7 @@ def downward_monotone(ambient_dim=None, lattice=None): if G.nrows() > 0: # Special case for when the ambient space is trivial. - G = G.insert_row(ambient_dim, -1*G.row(-1)) + G = G.insert_row(ambient_dim, -1 * G.row(-1)) return Cone(G.rows(), lattice) @@ -693,8 +687,7 @@ def rearrangement(p, ambient_dim=None, lattice=None): ambient_dim, lattice = _preprocess_args(ambient_dim, lattice) if p < 1 or p > ambient_dim or p not in ZZ: - raise ValueError("order p=%s should be an integer between 1 " - "and ambient_dim=%d, inclusive" % (p, ambient_dim)) + raise ValueError("order p=%s should be an integer between 1 " "and ambient_dim=%d, inclusive" % (p, ambient_dim)) I = matrix.identity(ZZ, ambient_dim) M = matrix.ones(ZZ, ambient_dim) - p * I @@ -840,7 +833,7 @@ def _f(i, j): return 0 # The "max" below catches the trivial case where ambient_dim == 0. - S = matrix(ZZ, max(0, ambient_dim-1), ambient_dim, _f) + S = matrix(ZZ, max(0, ambient_dim - 1), ambient_dim, _f) return Cone(S.rows(), lattice) diff --git a/src/sage/geometry/cone_critical_angles.py b/src/sage/geometry/cone_critical_angles.py index 367d97762bb..cd54a726acf 100644 --- a/src/sage/geometry/cone_critical_angles.py +++ b/src/sage/geometry/cone_critical_angles.py @@ -164,15 +164,12 @@ def _random_admissible_cone(ambient_dim): # The random_cone() method already crashes if we ask the # impossible of it, but having this here emits a more sensible # error message. - raise ValueError("there are no nontrivial cones in dimension %d" - % ambient_dim) + raise ValueError("there are no nontrivial cones in dimension %d" % ambient_dim) - args = { 'min_ambient_dim': ambient_dim, - 'max_ambient_dim': ambient_dim, - 'min_rays': 1, - 'max_rays': ambient_dim+2 } + args = {'min_ambient_dim': ambient_dim, 'max_ambient_dim': ambient_dim, 'min_rays': 1, 'max_rays': ambient_dim + 2} from sage.geometry.cone import random_cone + return random_cone(**args) return K @@ -312,22 +309,16 @@ def _solve_gevp_naive(GG, HH, M, I, J): ....: for (v,_,_,m) in _solve_gevp_naive(GG,HH,M,I,J) ) True """ - A = matrix.block([ - [ZZ.zero(), M[I,J]], - [M.transpose()[J,I], ZZ.zero()] - ]) - B = matrix.block([ - [GG[I,I], ZZ.zero()], - [ZZ.zero(), HH[J,J]] - ]) + A = matrix.block([[ZZ.zero(), M[I, J]], [M.transpose()[J, I], ZZ.zero()]]) + B = matrix.block([[GG[I, I], ZZ.zero()], [ZZ.zero(), HH[J, J]]]) M = B.inverse() * A # We'll format the result to match the solve_gevp_nonzero() return value. - for (evalue, evectors, multiplicity) in M.eigenvectors_right(): + for evalue, evectors, multiplicity in M.eigenvectors_right(): for z in evectors: - xi = z[0:len(I)] + xi = z[0 : len(I)] xi.set_immutable() - eta = z[len(I):] + eta = z[len(I) :] eta.set_immutable() yield (evalue, xi, eta, multiplicity) @@ -387,7 +378,7 @@ def solve_gevp_zero(M, I, J): # A Cartesian product would be more appropriate here, but Sage # isn't smart enough to figure out a basis for the product. So, # we use the direct sum and then chop it up. - M_IJ = M[I,J] + M_IJ = M[I, J] xi_space = M_IJ.left_kernel() eta_space = M_IJ.right_kernel() @@ -395,9 +386,9 @@ def solve_gevp_zero(M, I, J): multiplicity = fake_cartprod.dimension() for z in fake_cartprod.basis(): - z1 = z[0:len(I)] + z1 = z[0 : len(I)] z1.set_immutable() - z2 = z[len(I):] + z2 = z[len(I) :] z2.set_immutable() # The base ring of M will either be RDF or AA, which is enough @@ -580,28 +571,23 @@ def solve_gevp_nonzero(GG, HH, M, I, J): # convince yourself that switching GG <-> HH, I <-> J, and # transposing M does in fact switch from the "xi problem" to # the "eta problem." - yield from ((l, xi, eta, m) - for (l, eta, xi, m) - in solve_gevp_nonzero(HH, GG, M.transpose(), J, I)) + yield from ((l, xi, eta, m) for (l, eta, xi, m) in solve_gevp_nonzero(HH, GG, M.transpose(), J, I)) else: - M_IJ = M[I,J] - G_I_pinv_H_J = GG[I,I].inverse_positive_definite() * M_IJ - H_J_pinv_G_I = HH[J,J].inverse_positive_definite() * M_IJ.transpose() - L = (G_I_pinv_H_J * H_J_pinv_G_I) + M_IJ = M[I, J] + G_I_pinv_H_J = GG[I, I].inverse_positive_definite() * M_IJ + H_J_pinv_G_I = HH[J, J].inverse_positive_definite() * M_IJ.transpose() + L = G_I_pinv_H_J * H_J_pinv_G_I - for (sigma, xis, m) in L.eigenvectors_right(): + for sigma, xis, m in L.eigenvectors_right(): if sigma > 0: # Avoid recomputing these for each xi in xis sigma_sqrt = sigma.sqrt() inv_sqrt = ~sigma_sqrt - pm_sqrt_inv_pairs = [ - (-sigma_sqrt, -inv_sqrt), - (sigma_sqrt, inv_sqrt) - ] + pm_sqrt_inv_pairs = [(-sigma_sqrt, -inv_sqrt), (sigma_sqrt, inv_sqrt)] for xi in xis: for l, li in pm_sqrt_inv_pairs: - eta = li * H_J_pinv_G_I*xi + eta = li * H_J_pinv_G_I * xi eta.set_immutable() yield (l, xi, eta, m) @@ -697,7 +683,7 @@ def compute_gevp_M(gs, hs): for h in hs: val = g.inner_product(h) M_i.append(val) - if (val < min_ip): + if val < min_ip: min_ip = val min_u = g min_v = h @@ -706,8 +692,7 @@ def compute_gevp_M(gs, hs): return (matrix(M), min_ip, min_u, min_v) -def check_gevp_feasibility(cos_theta, xi, eta, G_I, G_I_c_T, - H_J, H_J_c_T, epsilon): +def check_gevp_feasibility(cos_theta, xi, eta, G_I, G_I_c_T, H_J, H_J_c_T, epsilon): r""" Determine if a solution to the generalized eigenvalue problem in Theorem 3 [Or2020]_ is feasible. @@ -832,7 +817,7 @@ def check_gevp_feasibility(cos_theta, xi, eta, G_I, G_I_c_T, sage: check_gevp_feasibility(0,xi,eta,G_I,G_I_c_T,H_J,H_J_c_T,0) (True, (1/2, 1/2, 1/2, 1/2), (1/2, 1/2, 1/2, 1/2)) """ - infeasible_result = (False, 0*xi, 0*eta) + infeasible_result = (False, 0 * xi, 0 * eta) if min(xi) <= -epsilon or min(eta) <= -epsilon: # xi or eta isn't in the interior of the nonnegative orthant, # so skip this (non-)solution. @@ -841,23 +826,23 @@ def check_gevp_feasibility(cos_theta, xi, eta, G_I, G_I_c_T, # Rescale xi to satisfy (44), and rescale eta by the same amount, # because (xi,eta) needs to remain in the same one-dimensional # eigenspace. - scale = ~((G_I*xi).norm()) + scale = ~((G_I * xi).norm()) xi_hat = xi * scale eta_hat = eta * scale # Now check that (45) is satisfied. - if ((H_J*eta_hat).norm() - 1).abs() > epsilon: + if ((H_J * eta_hat).norm() - 1).abs() > epsilon: return infeasible_result # And check that (42,43) are satisfied. v = H_J * eta_hat - rhs = v - cos_theta*G_I*xi_hat + rhs = v - cos_theta * G_I * xi_hat if any(x < -epsilon for x in G_I_c_T * rhs): return infeasible_result u = G_I * xi_hat - rhs = u - cos_theta*H_J*eta_hat + rhs = u - cos_theta * H_J * eta_hat if any(x < -epsilon for x in H_J_c_T * rhs): return infeasible_result @@ -903,15 +888,15 @@ def max_angle(P, Q, exact, epsilon): # so; then if P is contained in dual(Q), we just return the pair # with the smallest inner product. gs = [g.change_ring(ring).normalized() for g in P] - Q_is_P = (P == Q) # This is used again later + Q_is_P = P == Q # This is used again later if Q_is_P: hs = gs else: hs = [h.change_ring(ring).normalized() for h in Q] - (M, min_ip, min_u, min_v) = compute_gevp_M(gs,hs) + (M, min_ip, min_u, min_v) = compute_gevp_M(gs, hs) - if min_ip >= 0: # The maximal angle is acute! + if min_ip >= 0: # The maximal angle is acute! return (arccos(min_ip), min_u, min_v) # Also check to see if the maximal angle is pi. In particular this @@ -962,7 +947,7 @@ def max_angle(P, Q, exact, epsilon): H_J = H.matrix_from_columns(J) H_J_c_T = H.matrix_from_columns(J_complement).transpose() - for (cos_theta,xi,eta,mult) in solve_gevp_nonzero(GG, HH, M, I, J): + for cos_theta, xi, eta, mult in solve_gevp_nonzero(GG, HH, M, I, J): if cos_theta >= min_ip: # This potential critical angle is smaller than or @@ -975,14 +960,7 @@ def max_angle(P, Q, exact, epsilon): # "P_and_negative_Q" trick. continue - (is_feasible, u, v) = check_gevp_feasibility(cos_theta, - xi, - eta, - G_I, - G_I_c_T, - H_J, - H_J_c_T, - epsilon) + (is_feasible, u, v) = check_gevp_feasibility(cos_theta, xi, eta, G_I, G_I_c_T, H_J, H_J_c_T, epsilon) if is_feasible: min_ip = cos_theta @@ -994,7 +972,7 @@ def max_angle(P, Q, exact, epsilon): big_eigenspaces.append((cos_theta, xi, eta, mult)) continue - for (cos_theta, xi, eta, mult) in big_eigenspaces: + for cos_theta, xi, eta, mult in big_eigenspaces: if cos_theta < min_ip: # The existence of a big eigenspace is only a problem if # cos_theta could actually be minimal. @@ -1015,8 +993,6 @@ def max_angle(P, Q, exact, epsilon): # that the case where either P or Q is the ambient space # was handled much earlier, since in that case the maximal # angle is obviously pi.) - raise ValueError('eigenspace of dimension %d > 1 ' - 'corresponding to eigenvalue %s' - % (mult, cos_theta)) + raise ValueError('eigenspace of dimension %d > 1 ' 'corresponding to eigenvalue %s' % (mult, cos_theta)) return (arccos(min_ip), min_u, min_v) diff --git a/src/sage/geometry/convex_set.py b/src/sage/geometry/convex_set.py index 913d75217b3..c4270c4590d 100644 --- a/src/sage/geometry/convex_set.py +++ b/src/sage/geometry/convex_set.py @@ -291,6 +291,7 @@ def affine_hull(self, *args, **kwds): A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex and 2 lines """ from .polyhedron.constructor import Polyhedron + i_affine_basis = iter(self.an_affine_basis()) try: v = next(i_affine_basis) @@ -300,10 +301,7 @@ def affine_hull(self, *args, **kwds): return Polyhedron(vertices=[v], lines=[vector(p) - v for p in i_affine_basis]) @cached_method - def _affine_hull_projection(self, *, - as_convex_set=True, as_affine_map=True, as_section_map=True, - orthogonal=False, orthonormal=False, - extend=False, minimal=False): + def _affine_hull_projection(self, *, as_convex_set=True, as_affine_map=True, as_section_map=True, orthogonal=False, orthonormal=False, extend=False, minimal=False): r""" Return ``self`` projected into its affine hull. @@ -356,10 +354,7 @@ def _affine_hull_projection(self, *, section_translation=(2, 0, 0)) """ affine_hull = self.affine_hull() - data = affine_hull._affine_hull_projection( - as_convex_set=False, as_affine_map=True, as_section_map=True, - orthogonal=orthogonal, orthonormal=orthonormal, - extend=extend, minimal=minimal) + data = affine_hull._affine_hull_projection(as_convex_set=False, as_affine_map=True, as_section_map=True, orthogonal=orthogonal, orthonormal=orthonormal, extend=extend, minimal=minimal) if as_convex_set: data = copy(data) matrix = data.projection_linear_map.matrix().transpose() @@ -367,10 +362,7 @@ def _affine_hull_projection(self, *, data.image = projected.translation(data.projection_translation) return data - def affine_hull_projection(self, as_convex_set=None, as_affine_map=False, - orthogonal=False, orthonormal=False, - extend=False, minimal=False, - return_all_data=False, **kwds): + def affine_hull_projection(self, as_convex_set=None, as_affine_map=False, orthogonal=False, orthonormal=False, extend=False, minimal=False, return_all_data=False, **kwds): r""" Return ``self`` projected into its affine hull. @@ -407,16 +399,12 @@ def affine_hull_projection(self, as_convex_set=None, as_affine_map=False, if as_convex_set is None: as_convex_set = not as_affine_map if not as_affine_map and not as_convex_set: - raise ValueError('combining "as_affine_map=False" and ' - '"as_convex_set=False" not allowed') + raise ValueError('combining "as_affine_map=False" and ' '"as_convex_set=False" not allowed') if return_all_data: as_convex_set = True as_affine_map = True - result = self._affine_hull_projection( - as_convex_set=as_convex_set, as_affine_map=as_affine_map, as_section_map=return_all_data, - orthogonal=orthogonal, orthonormal=orthonormal, - extend=extend, minimal=minimal, **kwds) + result = self._affine_hull_projection(as_convex_set=as_convex_set, as_affine_map=as_affine_map, as_section_map=return_all_data, orthogonal=orthogonal, orthonormal=orthonormal, extend=extend, minimal=minimal, **kwds) # assemble result if return_all_data or (as_convex_set and as_affine_map): @@ -687,10 +675,10 @@ def _test_convex_set(self, tester=None, **options): if self.is_compact(): tester.assertTrue(self.is_closed()) from sage.misc.sage_unittest import TestSuite + if relint_self is not None and relint_self is not self: tester.info("\n Running the test suite of self.relative_interior()") - TestSuite(relint_self).run(verbose=tester._verbose, - prefix=tester._prefix + " ") + TestSuite(relint_self).run(verbose=tester._verbose, prefix=tester._prefix + " ") tester.info(tester._prefix + " ", newline=False) # Optional methods @@ -859,6 +847,7 @@ def _test_contains(self, tester=None, **options): tester.assertEqual(contains_space_point, self.contains(ext_space_point)) try: from sage.symbolic.ring import SR + symbolic_space = self.ambient_vector_space(SR) symbolic_space_point = symbolic_space(space_point) # Only test that it can accept SR vectors without error. diff --git a/src/sage/geometry/fan.py b/src/sage/geometry/fan.py index 721cef3bd70..dae111a4074 100644 --- a/src/sage/geometry/fan.py +++ b/src/sage/geometry/fan.py @@ -242,16 +242,15 @@ from sage.structure.richcmp import richcmp_method, richcmp from sage.misc.lazy_import import lazy_import + lazy_import('sage.combinat.combination', 'Combinations') lazy_import('sage.combinat.posets.posets', 'FinitePoset') -from sage.geometry.cone import (_ambient_space_point, - Cone, - ConvexRationalPolyhedralCone, - IntegralRayCollection, - normalize_rays) +from sage.geometry.cone import _ambient_space_point, Cone, ConvexRationalPolyhedralCone, IntegralRayCollection, normalize_rays + lazy_import('sage.geometry.hasse_diagram', 'lattice_from_incidences') from sage.geometry.point_collection import PointCollection from sage.geometry.toric_lattice import ToricLattice, ToricLattice_generic + lazy_import('sage.geometry.toric_plotter', 'ToricPlotter') from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method @@ -263,9 +262,7 @@ from sage.rings.rational_field import QQ -def Fan(cones, rays=None, lattice=None, check=True, normalize=True, - is_complete=None, virtual_rays=None, discard_faces=False, - allow_arrangement=False): +def Fan(cones, rays=None, lattice=None, check=True, normalize=True, is_complete=None, virtual_rays=None, discard_faces=False, allow_arrangement=False): r""" Construct a rational polyhedral fan. @@ -511,6 +508,7 @@ def Fan(cones, rays=None, lattice=None, check=True, normalize=True, sage: fan2.is_equivalent(fan1) True """ + def result(): # "global" does not work here... R, V = rays, virtual_rays @@ -522,8 +520,7 @@ def result(): V = PointCollection(V, lattice) d = lattice.dimension() if len(V) != d - R.dim() or (R + V).dim() != d: - raise ValueError("virtual rays must be linearly " - "independent and with other rays span the ambient space.") + raise ValueError("virtual rays must be linearly " "independent and with other rays span the ambient space.") return RationalPolyhedralFan(cones, R, lattice, is_complete, V) if not check and not normalize and not discard_faces and not allow_arrangement: @@ -532,17 +529,14 @@ def result(): try: cones = list(cones) except TypeError: - raise TypeError( - "cones must be given as an iterable!" - "\nGot: %s" % cones) + raise TypeError("cones must be given as an iterable!" "\nGot: %s" % cones) if not cones: if lattice is None: if rays is not None and rays: lattice = normalize_rays(rays, lattice)[0].parent() else: - raise ValueError("you must specify the lattice when you " - "construct a fan without rays and cones!") - cones = ((), ) + raise ValueError("you must specify the lattice when you " "construct a fan without rays and cones!") + cones = ((),) rays = () return result() if isinstance(cones[0], sage.geometry.abc.ConvexRationalPolyhedralCone): @@ -555,21 +549,18 @@ def result(): if check: for cone in cones: if cone.lattice() != lattice: - raise ValueError("cones belong to different lattices " - "(%s and %s), cannot determine the lattice of the " - "fan!" % (lattice, cone.lattice())) + raise ValueError("cones belong to different lattices " "(%s and %s), cannot determine the lattice of the " "fan!" % (lattice, cone.lattice())) for i, cone in enumerate(cones): if cone.lattice() != lattice: cones[i] = Cone(cone.rays(), lattice, check=False) if check: for cone in cones: if not cone.is_strictly_convex(): - raise ValueError( - "cones of a fan must be strictly convex!") + raise ValueError("cones of a fan must be strictly convex!") # Optimization for fans generated by a single cone if len(cones) == 1 and rays is None: cone = cones[0] - cones = (tuple(range(cone.n_rays())), ) + cones = (tuple(range(cone.n_rays())),) rays = cone.rays() is_complete = lattice.dimension() == 0 return result() @@ -580,8 +571,7 @@ def result(): # Maybe we should compute all faces of all cones and save them for # later if we are doing this check? generating_cones = [] - for cone in sorted(cones, key=lambda cone: cone.dim(), - reverse=True): + for cone in sorted(cones, key=lambda cone: cone.dim(), reverse=True): is_generating = True for g_cone in generating_cones: i_cone = cone.intersection(g_cone) @@ -590,40 +580,32 @@ def result(): is_generating = False # cone is a face of g_cone break else: - raise ValueError( - "these cones cannot belong to the same fan!" - "\nCone 1 rays: %s\nCone 2 rays: %s" - % (g_cone.rays(), cone.rays())) + raise ValueError("these cones cannot belong to the same fan!" "\nCone 1 rays: %s\nCone 2 rays: %s" % (g_cone.rays(), cone.rays())) if is_generating: generating_cones.append(cone) if len(cones) > len(generating_cones): if discard_faces: cones = generating_cones else: - raise ValueError("you have provided %d cones, but only %d " - "of them are maximal! Use discard_faces=True if you " - "indeed need to construct a fan from these cones." % - (len(cones), len(generating_cones))) + raise ValueError("you have provided %d cones, but only %d " "of them are maximal! Use discard_faces=True if you " "indeed need to construct a fan from these cones." % (len(cones), len(generating_cones))) elif discard_faces: cones = _discard_faces(cones) ray_set = set() for cone in cones: ray_set.update(cone.rays()) - if rays: # Preserve the initial order of rays, if they were given + if rays: # Preserve the initial order of rays, if they were given rays = normalize_rays(rays, lattice) new_rays = [] for ray in rays: if ray in ray_set and ray not in new_rays: new_rays.append(ray) if len(new_rays) != len(ray_set): - raise ValueError( - "if rays are given, they must include all rays of the fan!") + raise ValueError("if rays are given, they must include all rays of the fan!") rays = new_rays else: rays = tuple(sorted(ray_set)) ray_to_index = {ray: i for i, ray in enumerate(rays)} - cones = (tuple(sorted(ray_to_index[ray] for ray in cone.rays())) - for cone in cones) + cones = (tuple(sorted(ray_to_index[ray] for ray in cone.rays())) for cone in cones) return result() # Construct the fan from rays and "tuple cones" rays = normalize_rays(rays, lattice) @@ -635,10 +617,7 @@ def result(): if not check and not discard_faces and not allow_arrangement: return result() # If we do need to make all the check, build explicit cone objects first - return Fan((Cone([rays[n] for n in cone], lattice) for cone in cones), - rays, lattice, is_complete=is_complete, - virtual_rays=virtual_rays, discard_faces=discard_faces, - allow_arrangement=allow_arrangement) + return Fan((Cone([rays[n] for n in cone], lattice) for cone in cones), rays, lattice, is_complete=is_complete, virtual_rays=virtual_rays, discard_faces=discard_faces, allow_arrangement=allow_arrangement) def FaceFan(polytope, lattice=None): @@ -721,9 +700,7 @@ def FaceFan(polytope, lattice=None): ValueError: face fans are defined only for polytopes containing the origin as an interior point! """ - interior_point_error = ValueError( - "face fans are defined only for polytopes containing " - "the origin as an interior point!") + interior_point_error = ValueError("face fans are defined only for polytopes containing " "the origin as an interior point!") if isinstance(polytope, sage.geometry.abc.LatticePolytope): if any(d <= 0 for d in polytope.distances([0] * polytope.dim())): raise interior_point_error @@ -732,19 +709,16 @@ def FaceFan(polytope, lattice=None): is_complete = polytope.dim() == polytope.lattice_dim() else: origin = polytope.ambient_space().zero() - if not (polytope.is_compact() and - polytope.relative_interior_contains(origin)): + if not (polytope.is_compact() and polytope.relative_interior_contains(origin)): raise interior_point_error - cones = [[v.index() for v in facet.incident()] - for facet in polytope.inequalities()] + cones = [[v.index() for v in facet.incident()] for facet in polytope.inequalities()] rays = [vector(_) for _ in polytope.vertices()] is_complete = polytope.dim() == polytope.ambient_dim() if lattice is None: # Since default lattice polytopes are in the M lattice, # treat polyhedra as being there as well. lattice = ToricLattice(len(origin)).dual() - return Fan(cones, rays, lattice=lattice, check=False, - is_complete=is_complete) + return Fan(cones, rays, lattice=lattice, check=False, is_complete=is_complete) def NormalFan(polytope, lattice=None): @@ -810,8 +784,7 @@ def NormalFan(polytope, lattice=None): sage: fan1.is_equivalent(fan2) True """ - dimension_error = ValueError( - 'the normal fan is only defined for full-dimensional polytopes') + dimension_error = ValueError('the normal fan is only defined for full-dimensional polytopes') if isinstance(polytope, sage.geometry.abc.LatticePolytope): if polytope.dim() != polytope.lattice_dim(): raise dimension_error @@ -822,8 +795,7 @@ def NormalFan(polytope, lattice=None): raise dimension_error if not polytope.is_compact(): raise NotImplementedError('the normal fan is only supported for polytopes (compact polyhedra).') - cones = [[ieq.index() for ieq in vertex.incident()] - for vertex in polytope.vertices()] + cones = [[ieq.index() for ieq in vertex.incident()] for vertex in polytope.vertices()] rays = [ieq.A() for ieq in polytope.inequalities()] return Fan(cones, rays, lattice=lattice, check=False, is_complete=True) @@ -924,15 +896,13 @@ def Fan2d(rays, lattice=None): """ if not rays: if lattice is None or lattice.dimension() != 2: - raise ValueError('you must specify a 2-dimensional lattice when ' - 'you construct a fan without rays.') - return RationalPolyhedralFan(cones=((), ), rays=(), lattice=lattice) + raise ValueError('you must specify a 2-dimensional lattice when ' 'you construct a fan without rays.') + return RationalPolyhedralFan(cones=((),), rays=(), lattice=lattice) # remove multiple rays without changing order rays = normalize_rays(rays, lattice) rays = sorted((r, i) for i, r in enumerate(rays)) - distinct_rays = [rays[i] for i in range(len(rays)) - if rays[i][0] != rays[i-1][0]] + distinct_rays = [rays[i] for i in range(len(rays)) if rays[i][0] != rays[i - 1][0]] if distinct_rays: rays = sorted((i, r) for r, i in distinct_rays) rays = [r[1] for r in rays] @@ -943,24 +913,24 @@ def Fan2d(rays, lattice=None): raise ValueError('the lattice must be 2-dimensional.') n = len(rays) if n == 1 or n == 2 and rays[0] == -rays[1]: - cones = [(i, ) for i in range(n)] + cones = [(i,) for i in range(n)] return RationalPolyhedralFan(cones, rays, lattice, False) import math + # each sorted_rays entry = (angle, ray, original_ray_index) - sorted_rays = sorted((math.atan2(r[0], r[1]), r, i) - for i, r in enumerate(rays)) + sorted_rays = sorted((math.atan2(r[0], r[1]), r, i) for i, r in enumerate(rays)) cones = [] is_complete = True for i in range(n): - r0 = sorted_rays[i-1][1] + r0 = sorted_rays[i - 1][1] r1 = sorted_rays[i][1] if r1.is_zero(): raise ValueError('only nonzero vectors define rays') assert r0 != r1 cross_prod = r0[0] * r1[1] - r0[1] * r1[0] if cross_prod < 0: - r0_index = (i-1) % len(sorted_rays) + r0_index = (i - 1) % len(sorted_rays) r1_index = i cones.append((sorted_rays[r0_index][2], sorted_rays[r1_index][2])) else: @@ -1018,8 +988,7 @@ def __init__(self, ambient, ambient_ray_indices): 1-d cone of Rational polyhedral fan in 2-d lattice N sage: TestSuite(cone).run() # needs palp """ - super().__init__(ambient=ambient, - ambient_ray_indices=ambient_ray_indices) + super().__init__(ambient=ambient, ambient_ray_indices=ambient_ray_indices) self._is_strictly_convex = True # Because if not, this cone should not have been constructed @@ -1107,8 +1076,7 @@ def star_generators(self): (2-d cone of Rational polyhedral fan in 2-d lattice N,) """ if "_star_generators" not in self.__dict__: - self._star_generators = tuple(self.ambient().generating_cone(i) - for i in self.star_generator_indices()) + self._star_generators = tuple(self.ambient().generating_cone(i) for i in self.star_generator_indices()) return self._star_generators @@ -1154,8 +1122,7 @@ class RationalPolyhedralFan(IntegralRayCollection, Callable, Container): rational polyhedral fan """ - def __init__(self, cones, rays, lattice, - is_complete=None, virtual_rays=None): + def __init__(self, cones, rays, lattice, is_complete=None, virtual_rays=None): r""" See :class:`RationalPolyhedralFan` for documentation. @@ -1289,10 +1256,7 @@ def __richcmp__(self, right, op): False """ if isinstance(right, RationalPolyhedralFan): - return richcmp([self.rays(), self.virtual_rays(), - self.generating_cones()], - [right.rays(), right.virtual_rays(), - right.generating_cones()], op) + return richcmp([self.rays(), self.virtual_rays(), self.generating_cones()], [right.rays(), right.virtual_rays(), right.generating_cones()], op) return NotImplemented def __contains__(self, cone) -> bool: @@ -1399,9 +1363,10 @@ def _compute_cone_lattice(self): Here we got 1 origin, 3 rays (one is a generating cone), 1 2-dimensional cone (a generating one), and 1 fan. """ + # Define a face constructor def FanFace(rays, cones): - if not cones: # The top face, fan itself + if not cones: # The top face, fan itself return self if len(cones) == 1: # MAY be a generating cone or NOT!!! g_cone = self.generating_cone(cones[0]) @@ -1410,19 +1375,23 @@ def FanFace(rays, cones): face = Cone_of_fan(ambient=self, ambient_ray_indices=rays) face._star_generator_indices = cones return face + # Check directly if we know completeness already, since *determining* # completeness relies on this function if "_is_complete" in self.__dict__ and self._is_complete: # We can use a fast way for complete fans self._cone_lattice = lattice_from_incidences( - # When there are no rays, fan is the only atom - self._ray_to_cones() if self.rays() else [()], - (cone.ambient_ray_indices() for cone in self), - FanFace, key=id(self)) + # When there are no rays, fan is the only atom + self._ray_to_cones() if self.rays() else [()], + (cone.ambient_ray_indices() for cone in self), + FanFace, + key=id(self), + ) else: # For general fans we will "merge" face lattices of generating # cones. from sage.graphs.digraph import DiGraph + L = DiGraph() face_to_rays = {} # face |---> (indices of fan rays) rays_to_index = {} # (indices of fan rays) |---> face index @@ -1437,27 +1406,23 @@ def FanFace(rays, cones): # Set up translation of faces of cone to rays and indices # We make a standalone cone to compute its standalone face # lattice, since cones of fans get their lattices from fans - L_cone = Cone(cone.rays(), lattice=self.lattice(), - check=False, normalize=False).face_lattice() + L_cone = Cone(cone.rays(), lattice=self.lattice(), check=False, normalize=False).face_lattice() for f in L_cone: - f_rays = tuple(cone.ambient_ray_indices()[ray] - for ray in f.ambient_ray_indices()) + f_rays = tuple(cone.ambient_ray_indices()[ray] for ray in f.ambient_ray_indices()) face_to_rays[f] = f_rays try: f_index = rays_to_index[f_rays] index_to_cones[f_index].append(i) - except KeyError: # Did not see f before + except KeyError: # Did not see f before f_index = next_index next_index += 1 rays_to_index[f_rays] = f_index index_to_cones.append([i]) # Add all relations between faces of cone to L for f, g in L_cone.cover_relations_iterator(): - L.add_edge(rays_to_index[face_to_rays[f]], - rays_to_index[face_to_rays[g]]) + L.add_edge(rays_to_index[face_to_rays[f]], rays_to_index[face_to_rays[g]]) # Add the inclusion of cone into the fan itself - L.add_edge( - rays_to_index[face_to_rays[L_cone.top()]], 0) + L.add_edge(rays_to_index[face_to_rays[L_cone.top()]], 0) # Enumeration of graph vertices must be a linear extension of the # poset @@ -1476,8 +1441,7 @@ def FanFace(rays, cones): elements = [None] * next_index for rays, index in rays_to_index.items(): - elements[labels[index]] = FanFace( - rays, tuple(index_to_cones[index])) + elements[labels[index]] = FanFace(rays, tuple(index_to_cones[index])) # We need "special treatment" for the whole fan. If we added its # ray incidence information to the total list, it would be # confused with the generating cone in the case of a single cone. @@ -1525,15 +1489,13 @@ def _contains(self, cone) -> bool: True """ try: - self.embed(cone) # Fails if cone is not in self. + self.embed(cone) # Fails if cone is not in self. return True - except TypeError: # cone is not a cone + except TypeError: # cone is not a cone return False except ValueError: # cone is a cone, but wrong if not cone.lattice().is_submodule(self.lattice()): - warn("you have checked if a fan contains a cone " - "from another lattice, this is always False!", - stacklevel=3) + warn("you have checked if a fan contains a cone " "from another lattice, this is always False!", stacklevel=3) return False def support_contains(self, *args): @@ -1595,9 +1557,7 @@ def support_contains(self, *args): point = _ambient_space_point(self, point) except TypeError as ex: if str(ex).endswith("have incompatible lattices!"): - warn("you have checked if a fan contains a point " - "from an incompatible lattice, this is False!", - stacklevel=3) + warn("you have checked if a fan contains a point " "from an incompatible lattice, this is False!", stacklevel=3) return False if self.is_complete(): return True @@ -1637,12 +1597,10 @@ def cartesian_product(self, other, lattice=None): rc = super().cartesian_product(other, lattice) self_cones = [cone.ambient_ray_indices() for cone in self] n = self.n_rays() - other_cones = [tuple(n + i for i in cone.ambient_ray_indices()) - for cone in other] + other_cones = [tuple(n + i for i in cone.ambient_ray_indices()) for cone in other] new_cones = [c1 + c2 for c1 in self_cones for c2 in other_cones] - try: # Is completeness of the result obvious? - return RationalPolyhedralFan(new_cones, rc.rays(), rc.lattice(), - self._is_complete and other._is_complete) + try: # Is completeness of the result obvious? + return RationalPolyhedralFan(new_cones, rc.rays(), rc.lattice(), self._is_complete and other._is_complete) except AttributeError: # The result is either incomplete or unknown. return RationalPolyhedralFan(new_cones, rc.rays(), rc.lattice()) @@ -1721,6 +1679,7 @@ def common_refinement(self, other): """ from sage.categories.homset import End from sage.geometry.fan_morphism import FanMorphism + N = self.lattice() if other.lattice() is not N: raise ValueError('the fans are not in the same lattice') @@ -1779,8 +1738,7 @@ def _ray_to_cones(self, i=None): for k, cone in enumerate(self): for j in cone.ambient_ray_indices(): ray_to_cones[j].append(k) - self._ray_to_cones_tuple = tuple(frozenset(rtc) - for rtc in ray_to_cones) + self._ray_to_cones_tuple = tuple(frozenset(rtc) for rtc in ray_to_cones) if i is None: return self._ray_to_cones_tuple return self._ray_to_cones_tuple[i] @@ -1860,24 +1818,19 @@ def _subdivide_stellar(self, new_rays, verbose): new = [] for cone in cones: if ray in cone: - new.extend(Cone(tuple(facet.rays())+(ray,), check=False) - for facet in cone.facets() if ray not in facet) + new.extend(Cone(tuple(facet.rays()) + (ray,), check=False) for facet in cone.facets() if ray not in facet) else: new.append(cone) if verbose: t = walltime(start) added = len(new) - len(cones) T_new = "%d" % (t / added * 1000) if added else "-" - print("R:%d/%d C:%d T:%d(ms) T/new:%s(ms) T/all:%d(ms)" - % (n + 1, len(new_rays), len(new), t * 1000, - T_new, t / len(new) * 1000)) + print("R:%d/%d C:%d T:%d(ms) T/new:%s(ms) T/all:%d(ms)" % (n + 1, len(new_rays), len(new), t * 1000, T_new, t / len(new) * 1000)) cones = new new_fan_rays = list(self.rays()) - new_fan_rays.extend(ray for ray in new_rays - if ray not in self.rays().set()) + new_fan_rays.extend(ray for ray in new_rays if ray not in self.rays().set()) ray_to_index = {ray: i for i, ray in enumerate(new_fan_rays)} - cones = tuple(tuple(sorted(ray_to_index[ray] for ray in cone)) - for cone in cones) + cones = tuple(tuple(sorted(ray_to_index[ray] for ray in cone)) for cone in cones) fan = Fan(cones, new_fan_rays, check=False, normalize=False) return fan @@ -1958,12 +1911,10 @@ def cone_containing(self, *points): for ray in rays: generating_cones.intersection_update(self._ray_to_cones(ray)) if not generating_cones: - raise ValueError("there is no cone in %s containing all of " - "the given rays! Ray indices: %s" % (self, rays)) + raise ValueError("there is no cone in %s containing all of " "the given rays! Ray indices: %s" % (self, rays)) containing_cone = self.generating_cone(generating_cones.pop()) for cone in generating_cones: - containing_cone = containing_cone.intersection( - self.generating_cone(cone)) + containing_cone = containing_cone.intersection(self.generating_cone(cone)) if not self.is_complete(): # This cone may be too big in the case of incomplete fans rays = frozenset(rays) @@ -1994,8 +1945,7 @@ def cone_containing(self, *points): containing_cone = cone break if containing_cone is None: - raise ValueError("there is no cone in %s containing all of " - "the given points! Points: %s" % (self, points)) + raise ValueError("there is no cone in %s containing all of " "the given points! Points: %s" % (self, points)) # Now we take the intersection of facets that contain all points facets = containing_cone.facets() for facet in facets: @@ -2202,8 +2152,7 @@ def cones(self, dim=None, codim=None): if len(levels) >= 3: # There are cones of dimension higher than 1 top_cones = list(levels[-1]) if len(top_cones) == self.n_generating_cones(): - top_cones.sort(key=lambda cone: - cone.star_generator_indices()[0]) + top_cones.sort(key=lambda cone: cone.star_generator_indices()[0]) levels[-1] = top_cones if len(levels) >= 2: # We have rays rays = list(levels[1]) @@ -2215,8 +2164,7 @@ def cones(self, dim=None, codim=None): return self._cones dim = self.dim() - codim elif codim is not None: - raise ValueError( - "dimension and codimension cannot be specified together!") + raise ValueError("dimension and codimension cannot be specified together!") return self._cones[dim] if 0 <= dim < len(self._cones) else () def contains(self, cone) -> bool: @@ -2456,9 +2404,10 @@ def is_polytopal(self) -> bool: raise ValueError('to be polytopal, the fan should be complete') from sage.geometry.triangulation.point_configuration import PointConfiguration from sage.geometry.polyhedron.constructor import Polyhedron + pc = PointConfiguration(self.rays()) v_pc = [tuple(p) for p in pc] - pc_to_indices = {tuple(p):i for i, p in enumerate(pc)} + pc_to_indices = {tuple(p): i for i, p in enumerate(pc)} indices_to_vr = (tuple(r) for r in self.rays()) cone_indices = (cone.ambient_ray_indices() for cone in self.generating_cones()) translator = [pc_to_indices[t] for t in indices_to_vr] @@ -2543,6 +2492,7 @@ def vertex_graph(self): 4 """ from sage.geometry.cone import classify_cone_2d + graph = {} cones_1d = list(self(1)) while cones_1d: @@ -2555,6 +2505,7 @@ def vertex_graph(self): c0_edges[c1] = label graph[c0] = c0_edges from sage.graphs.graph import Graph + return Graph(graph) def is_complete(self) -> bool: @@ -2646,15 +2597,10 @@ def is_equivalent(self, other) -> bool: sage: fan1.is_equivalent(fan3) False """ - if (self.lattice() != other.lattice() - or self.dim() != other.dim() - or self.n_generating_cones() != other.n_generating_cones() - or self.rays().set() != other.rays().set() - or self.virtual_rays().set() != other.virtual_rays().set()): + if self.lattice() != other.lattice() or self.dim() != other.dim() or self.n_generating_cones() != other.n_generating_cones() or self.rays().set() != other.rays().set() or self.virtual_rays().set() != other.virtual_rays().set(): return False # Now we need to really compare cones, which can take a while - return sorted(sorted(cone.rays()) for cone in self) \ - == sorted(sorted(cone.rays()) for cone in other) + return sorted(sorted(cone.rays()) for cone in self) == sorted(sorted(cone.rays()) for cone in other) def is_isomorphic(self, other) -> bool: r""" @@ -2724,8 +2670,8 @@ def is_isomorphic(self, other) -> bool: sage: fan1.is_isomorphic(fan1) True """ - from sage.geometry.fan_isomorphism import \ - fan_isomorphic_necessary_conditions, fan_isomorphism_generator + from sage.geometry.fan_isomorphism import fan_isomorphic_necessary_conditions, fan_isomorphism_generator + if not fan_isomorphic_necessary_conditions(self, other): return False if self.lattice_dim() == 2: @@ -2757,6 +2703,7 @@ def _2d_echelon_forms(self): [ 0 1 0 -1]}) """ from sage.geometry.fan_isomorphism import fan_2d_echelon_forms + return fan_2d_echelon_forms(self) @cached_method @@ -2774,6 +2721,7 @@ def _2d_echelon_form(self): [ 0 1 0 -1] """ from sage.geometry.fan_isomorphism import fan_2d_echelon_form + return fan_2d_echelon_form(self) def isomorphism(self, other): @@ -2818,6 +2766,7 @@ def isomorphism(self, other): FanNotIsomorphicError """ from sage.geometry.fan_isomorphism import find_isomorphism + return find_isomorphism(self, other, check=False) def is_simplicial(self) -> bool: @@ -2906,8 +2855,7 @@ def is_smooth(self, codim=None) -> bool: codim = 0 if codim > self.lattice_dim() - 2: return True - return all(cone.is_smooth() for cone in self(codim=codim)) and \ - self.is_smooth(codim + 1) + return all(cone.is_smooth() for cone in self(codim=codim)) and self.is_smooth(codim + 1) def make_simplicial(self, **kwds): r""" @@ -2995,8 +2943,7 @@ def plot(self, **options): result += tp.plot_walls(self(2)) return result - def subdivide(self, new_rays=None, make_simplicial=False, - algorithm='default', verbose=False): + def subdivide(self, new_rays=None, make_simplicial=False, algorithm='default', verbose=False): r""" Construct a new fan subdividing ``self``. @@ -3056,8 +3003,7 @@ def subdivide(self, new_rays=None, make_simplicial=False, rays = list(self.rays()) else: rays = [] - rays.extend(ray for ray in normalize_rays(new_rays, self.lattice()) - if ray not in self.rays().set()) + rays.extend(ray for ray in normalize_rays(new_rays, self.lattice()) if ray not in self.rays().set()) if not rays: return self # Nothing has to be done if self.lattice().zero() in rays: @@ -3066,8 +3012,7 @@ def subdivide(self, new_rays=None, make_simplicial=False, algorithm = "stellar" method_name = "_subdivide_" + algorithm if not hasattr(self, method_name): - raise ValueError('"%s" is an unknown subdivision algorithm!' - % algorithm) + raise ValueError('"%s" is an unknown subdivision algorithm!' % algorithm) return getattr(self, method_name)(rays, verbose) def virtual_rays(self, *args): @@ -3214,8 +3159,7 @@ def is_in_SR(I): # called "primitive collections" such that # 1) I is not contained in a face # 2) if you remove any one entry j, then I-{j} is contained in a facet - facets = [frozenset(c.ambient_ray_indices()) - for c in self.generating_cones()] + facets = [frozenset(c.ambient_ray_indices()) for c in self.generating_cones()] all_points = frozenset(range(self.n_rays())) d_max = max(map(len, facets)) + 1 SR = [] @@ -3257,8 +3201,7 @@ def Stanley_Reisner_ideal(self, ring): Multivariate Polynomial Ring in A, B, C, D, E over Rational Field """ generators_indices = self.primitive_collections() - return ring.ideal([prod([ring.gen(i) for i in sr]) - for sr in generators_indices]) + return ring.ideal([prod([ring.gen(i) for i in sr]) for sr in generators_indices]) def linear_equivalence_ideal(self, ring): """ @@ -3284,8 +3227,7 @@ def linear_equivalence_ideal(self, ring): """ gens = [] for d in range(self.dim()): - gens.append(sum([self.ray(i)[d] * ring.gen(i) - for i in range(self.n_rays())])) + gens.append(sum([self.ray(i)[d] * ring.gen(i) for i in range(self.n_rays())])) return ring.ideal(gens) def oriented_boundary(self, cone): @@ -3377,6 +3319,7 @@ def sign(x): if x > 0: return 1 return -1 + N_QQ = self.lattice().base_extend(QQ) dim = self.lattice_dim() outward_vectors = {} @@ -3402,9 +3345,8 @@ def sign(x): c_matrix = matrix(outward_vectors[c] + list(c.rays().basis())) c_matrix_inv = c_matrix.inverse() for facet in c.facets(): - outward_ray_indices = set(c.ambient_ray_indices()) \ - .difference(set(facet.ambient_ray_indices())) - outward_vector = - sum(self.ray(i) for i in outward_ray_indices) + outward_ray_indices = set(c.ambient_ray_indices()).difference(set(facet.ambient_ray_indices())) + outward_vector = -sum(self.ray(i) for i in outward_ray_indices) outward_vectors[facet] = [outward_vector] + outward_vectors[c] facet_matrix = matrix(outward_vectors[facet] + list(facet.rays().basis())) orientation = sign((c_matrix_inv * facet_matrix).det()) @@ -3434,6 +3376,7 @@ def toric_variety(self, *args, **kwds): 2-d toric variety covered by 2 affine patches """ from sage.schemes.toric.variety import ToricVariety + return ToricVariety(self, *args, **kwds) def complex(self, base_ring=ZZ, extended=False): @@ -3562,8 +3505,7 @@ def complex(self, base_ring=ZZ, extended=False): dim = self.dim() delta = {} for degree in range(1, dim + 1): - m = matrix(base_ring, len(self(degree - 1)), len(self(degree)), - base_ring.zero()) + m = matrix(base_ring, len(self(degree - 1)), len(self(degree)), base_ring.zero()) for i, cone in enumerate(self(degree)): boundary = self.oriented_boundary(cone) for orientation, d_cone in boundary: @@ -3571,6 +3513,7 @@ def complex(self, base_ring=ZZ, extended=False): delta[dim - degree] = m from sage.homology.chain_complex import ChainComplex + if not extended: return ChainComplex(delta, base_ring=base_ring) diff --git a/src/sage/geometry/fan_isomorphism.py b/src/sage/geometry/fan_isomorphism.py index 6833f8ec4c9..c8a6e8d2b6c 100644 --- a/src/sage/geometry/fan_isomorphism.py +++ b/src/sage/geometry/fan_isomorphism.py @@ -1,6 +1,7 @@ """ Find isomorphisms between fans """ + # **************************************************************************** # Copyright (C) 2012 Volker Braun # @@ -18,6 +19,7 @@ class FanNotIsomorphicError(Exception): """ Exception to return if there is no fan isomorphism """ + pass @@ -142,40 +144,35 @@ def fan_isomorphism_generator(fan1, fan2): # Pick a basis of rays in fan1 max_cone = fan1(fan1.dim())[0] fan1_pivot_rays = max_cone.rays() - fan1_basis = fan1_pivot_rays + fan1.virtual_rays() # A QQ-basis for N_1 - fan1_pivot_cones = [ fan1.embed(Cone([r])) for r in fan1_pivot_rays ] + fan1_basis = fan1_pivot_rays + fan1.virtual_rays() # A QQ-basis for N_1 + fan1_pivot_cones = [fan1.embed(Cone([r])) for r in fan1_pivot_rays] # The fan2 cones as set(set(ray indices)) - fan2_cones = frozenset( - frozenset(cone.ambient_ray_indices()) - for cone in fan2.generating_cones() ) + fan2_cones = frozenset(frozenset(cone.ambient_ray_indices()) for cone in fan2.generating_cones()) # iterate over all graph isomorphisms graph1 -> graph2 for perm in graph2.automorphism_group(edge_labels=True): # find a candidate m that maps fan1_basis to the image rays under the graph isomorphism - fan2_pivot_cones = [ perm(graph_iso[c]) for c in fan1_pivot_cones ] - fan2_pivot_rays = fan2.rays([ c.ambient_ray_indices()[0] for c in fan2_pivot_cones ]) + fan2_pivot_cones = [perm(graph_iso[c]) for c in fan1_pivot_cones] + fan2_pivot_rays = fan2.rays([c.ambient_ray_indices()[0] for c in fan2_pivot_cones]) fan2_basis = fan2_pivot_rays + fan2.virtual_rays() try: m = matrix(ZZ, fan1_basis).solve_right(matrix(ZZ, fan2_basis)) m = m.change_ring(ZZ) except (ValueError, TypeError): - continue # no solution + continue # no solution # check that the candidate m lifts the vertex graph homomorphism - graph_image_ray_indices = [ perm(graph_iso[c]).ambient_ray_indices()[0] for c in fan1(1) ] + graph_image_ray_indices = [perm(graph_iso[c]).ambient_ray_indices()[0] for c in fan1(1)] try: - matrix_image_ray_indices = [ fan2.rays().index(r*m) for r in fan1.rays() ] + matrix_image_ray_indices = [fan2.rays().index(r * m) for r in fan1.rays()] except ValueError: continue if graph_image_ray_indices != matrix_image_ray_indices: continue # check that the candidate m maps generating cone to generating cone - image_cones = frozenset( # The image(fan1) cones as set(set(integers) - frozenset(graph_image_ray_indices[i] - for i in cone.ambient_ray_indices()) - for cone in fan1.generating_cones() ) + image_cones = frozenset(frozenset(graph_image_ray_indices[i] for i in cone.ambient_ray_indices()) for cone in fan1.generating_cones()) # The image(fan1) cones as set(set(integers) if image_cones == fan2_cones: m.set_immutable() yield m @@ -236,6 +233,7 @@ def find_isomorphism(fan1, fan2, check=False): raise FanNotIsomorphicError from sage.geometry.fan_morphism import FanMorphism + return FanMorphism(m, domain_fan=fan1, codomain=fan2, check=check) @@ -281,9 +279,11 @@ def fan_2d_cyclically_ordered_rays(fan): """ assert fan.lattice_dim() == 2 import math - rays = [ (math.atan2(r[0],r[1]), r) for r in fan.rays() ] - rays = [ r[1] for r in sorted(rays) ] + + rays = [(math.atan2(r[0], r[1]), r) for r in fan.rays()] + rays = [r[1] for r in sorted(rays)] from sage.geometry.point_collection import PointCollection + return PointCollection(rays, fan.lattice()) diff --git a/src/sage/geometry/fan_morphism.py b/src/sage/geometry/fan_morphism.py index cb83d968b7f..8b75d4f3745 100644 --- a/src/sage/geometry/fan_morphism.py +++ b/src/sage/geometry/fan_morphism.py @@ -242,11 +242,7 @@ class FanMorphism(FreeModuleMorphism): True """ - def __init__(self, morphism, domain_fan, - codomain=None, - subdivide=False, - check=True, - verbose=False): + def __init__(self, morphism, domain_fan, codomain=None, subdivide=False, check=True, verbose=False): r""" Create a fan morphism. @@ -277,12 +273,10 @@ def __init__(self, morphism, domain_fan, elif isinstance(morphism, Matrix): A = morphism if codomain is None: - raise ValueError("codomain (fan) must be given explicitly if " - "morphism is given by a matrix!") + raise ValueError("codomain (fan) must be given explicitly if " "morphism is given by a matrix!") parent = Hom(domain_fan.lattice(), codomain) else: - raise TypeError("morphism must be either a FreeModuleMorphism " - "or a matrix!\nGot: %s" % morphism) + raise TypeError("morphism must be either a FreeModuleMorphism " "or a matrix!\nGot: %s" % morphism) super().__init__(parent, A) self._domain_fan = domain_fan self._image_cone = dict() @@ -328,11 +322,9 @@ def __mul__(self, right): Codomain fan: Rational polyhedral fan in 3-d lattice N """ if not isinstance(right, FanMorphism): - raise TypeError( - "fan morphisms should be composed with fan morphisms") + raise TypeError("fan morphisms should be composed with fan morphisms") # We don't need it, we just check compatibility of fans: - FanMorphism(identity_matrix(self.domain().dimension()), - right.codomain_fan(), self.domain_fan()) + FanMorphism(identity_matrix(self.domain().dimension()), right.codomain_fan(), self.domain_fan()) m = right.matrix() * self.matrix() return FanMorphism(m, right.domain_fan(), self.codomain_fan()) @@ -367,12 +359,10 @@ def _RISGIS(self): """ if "_RISGIS_" not in self.__dict__: try: - cones = [self._codomain_fan.cone_containing(self(ray)) - for ray in self._domain_fan.rays()] + cones = [self._codomain_fan.cone_containing(self(ray)) for ray in self._domain_fan.rays()] except ValueError: self._support_error() - self._RISGIS_ = tuple(frozenset(cone.star_generator_indices()) - for cone in cones) + self._RISGIS_ = tuple(frozenset(cone.star_generator_indices()) for cone in cones) return self._RISGIS_ def _chambers(self): @@ -419,8 +409,7 @@ def _chambers(self): chambers = [] cone_to_chamber = [] for cone in self._codomain_fan: - chamber = Cone([self.lift(ray) for ray in cone.intersection(image)] - + kernel_rays, lattice=self.domain()) + chamber = Cone([self.lift(ray) for ray in cone.intersection(image)] + kernel_rays, lattice=self.domain()) cone_to_chamber.append(len(chambers)) for i, old_chamber in enumerate(chambers): if old_chamber.is_equivalent(chamber): @@ -465,11 +454,7 @@ def _construct_codomain_fan(self, check): # We literally try to construct the image fan and hope that it works. # If it does not, the fan constructor will raise an exception. domain_fan = self._domain_fan - self._codomain_fan = Fan(cones=(domain_cone.ambient_ray_indices() - for domain_cone in domain_fan), - rays=(self(ray) for ray in domain_fan.rays()), - lattice=self.codomain(), - discard_faces=True, check=check) + self._codomain_fan = Fan(cones=(domain_cone.ambient_ray_indices() for domain_cone in domain_fan), rays=(self(ray) for ray in domain_fan.rays()), lattice=self.codomain(), discard_faces=True, check=check) def _latex_(self): r""" @@ -496,8 +481,8 @@ def _latex_(self): \end{array}\right) : \Sigma^{2} \to \Sigma^{2} """ from sage.misc.latex import latex - return (r"%s : %s \to %s" % (latex(self.matrix()), - latex(self.domain_fan()), latex(self.codomain_fan()))) + + return r"%s : %s \to %s" % (latex(self.matrix()), latex(self.domain_fan()), latex(self.codomain_fan())) @cached_method def _ray_index_map(self): @@ -536,8 +521,7 @@ def _ray_index_map(self): for i, rho in enumerate(Sigma(1)): sigma_p = self.image_cone(rho) if sigma_p.n_rays() > 1: - raise ValueError("ray #%d is mapped into a %d-d cone!" % - (i, sigma_p.dim())) + raise ValueError("ray #%d is mapped into a %d-d cone!" % (i, sigma_p.dim())) elif sigma_p.n_rays() == 1: ray_index_map[i] = sigma_p.ambient_ray_indices()[0] return tuple(ray_index_map) @@ -561,11 +545,7 @@ def _repr_(self): Domain fan: Rational polyhedral fan in 2-d lattice N Codomain fan: Rational polyhedral fan in 2-d lattice N """ - return ("Fan morphism defined by the matrix\n" - "%s\n" - "Domain fan: %s\n" - "Codomain fan: %s" - % (self.matrix(), self.domain_fan(), self.codomain_fan())) + return "Fan morphism defined by the matrix\n" "%s\n" "Domain fan: %s\n" "Codomain fan: %s" % (self.matrix(), self.domain_fan(), self.codomain_fan()) def _subdivide_domain_fan(self, check, verbose): r""" @@ -667,6 +647,7 @@ def _subdivide_domain_fan(self, check, verbose): lattice_dim = self.domain().dimension() if verbose: from sage.misc.timing import walltime + start = walltime() print("Placing ray images", end=" ") # Figure out where 1-dimensional cones (i.e. rays) are mapped. @@ -674,11 +655,10 @@ def _subdivide_domain_fan(self, check, verbose): if verbose: print("(%.3f ms)" % walltime(start)) # Subdivide cones that require it. - chambers = None # preimages of codomain cones, computed if necessary + chambers = None # preimages of codomain cones, computed if necessary new_cones = [] for cone_index, domain_cone in enumerate(domain_fan): - if reduce(operator.and_, - (RISGIS[i] for i in domain_cone.ambient_ray_indices())): + if reduce(operator.and_, (RISGIS[i] for i in domain_cone.ambient_ray_indices())): # There is a codomain cone containing all rays of this domain # cone, no need to subdivide it. new_cones.append(domain_cone) @@ -691,9 +671,7 @@ def _subdivide_domain_fan(self, check, verbose): chambers, cone_to_chamber = self._chambers() if verbose: print("(%.3f ms)" % walltime(start)) - print("Number of domain cones: %d.\n" - "Number of chambers: %d." % - (domain_fan.n_generating_cones(), len(chambers))) + print("Number of domain cones: %d.\n" "Number of chambers: %d." % (domain_fan.n_generating_cones(), len(chambers))) # Subdivide domain_cone. if verbose: start = walltime() @@ -710,8 +688,7 @@ def _subdivide_domain_fan(self, check, verbose): if new_part.dim() < dim: continue # Small cones may have repetitive intersections with chambers. - if (dim == lattice_dim or - not any(part.is_equivalent(new_part) for part in parts)): + if dim == lattice_dim or not any(part.is_equivalent(new_part) for part in parts): parts.append(new_part) if verbose: print(chamber_index, end=" ") @@ -729,8 +706,7 @@ def _subdivide_domain_fan(self, check, verbose): cone_subdivision = Fan(parts, check=False) for cone in cone_subdivision(dim - 1): if len(cone.star_generators()) == 1: - if domain_cone.relative_interior_contains( - sum(cone.rays())): + if domain_cone.relative_interior_contains(sum(cone.rays())): self._support_error() new_cones.extend(parts) if verbose: @@ -744,8 +720,7 @@ def _subdivide_domain_fan(self, check, verbose): new_rays.append(ray) # Replace domain_fan, this is OK since this method must be called # only during initialization of the FanMorphism. - self._domain_fan = Fan(new_cones, new_rays, domain_fan.lattice(), - check=False) + self._domain_fan = Fan(new_cones, new_rays, domain_fan.lattice(), check=False) # Also remove RISGIS for the old fan del self._RISGIS_ @@ -778,13 +753,7 @@ def _support_error(self): into the support of Rational polyhedral fan in 2-d lattice N! """ - raise ValueError("morphism defined by\n" - "%s\n" - "does not map\n" - "%s\n" - "into the support of\n" - "%s!" - % (self.matrix(), self.domain_fan(), self.codomain_fan())) + raise ValueError("morphism defined by\n" "%s\n" "does not map\n" "%s\n" "into the support of\n" "%s!" % (self.matrix(), self.domain_fan(), self.codomain_fan())) def _validate(self): r""" @@ -861,20 +830,14 @@ def _validate(self): """ domain_fan = self._domain_fan if domain_fan.lattice() is not self.domain(): - raise ValueError("%s does not sit in %s!" - % (domain_fan, self.domain())) + raise ValueError("%s does not sit in %s!" % (domain_fan, self.domain())) codomain_fan = self._codomain_fan if codomain_fan.lattice() is not self.codomain(): - raise ValueError("%s does not sit in %s!" - % (codomain_fan, self.codomain())) + raise ValueError("%s does not sit in %s!" % (codomain_fan, self.codomain())) RISGIS = self._RISGIS() for n, domain_cone in enumerate(domain_fan): - if not domain_cone.is_trivial() and \ - not reduce(operator.and_, - (RISGIS[i] for i in domain_cone.ambient_ray_indices())): - raise ValueError("the image of generating cone #%d of the " - "domain fan is not contained in a single " - "cone of the codomain fan!" % n) + if not domain_cone.is_trivial() and not reduce(operator.and_, (RISGIS[i] for i in domain_cone.ambient_ray_indices())): + raise ValueError("the image of generating cone #%d of the " "domain fan is not contained in a single " "cone of the codomain fan!" % n) def codomain_fan(self, dim=None, codim=None): r""" @@ -986,16 +949,13 @@ def image_cone(self, cone): elif codomain_fan.is_complete(): # Optimization for a common case RISGIS = self._RISGIS() - CSGIS = set(reduce(operator.and_, - (RISGIS[i] for i in cone.ambient_ray_indices()))) + CSGIS = set(reduce(operator.and_, (RISGIS[i] for i in cone.ambient_ray_indices()))) image_cone = codomain_fan.generating_cone(CSGIS.pop()) for i in CSGIS: - image_cone = image_cone.intersection( - codomain_fan.generating_cone(i)) + image_cone = image_cone.intersection(codomain_fan.generating_cone(i)) self._image_cone[cone] = image_cone else: - self._image_cone[cone] = codomain_fan.cone_containing( - self(ray) for ray in cone) + self._image_cone[cone] = codomain_fan.cone_containing(self(ray) for ray in cone) return self._image_cone[cone] def index(self, cone=None): @@ -1099,9 +1059,8 @@ def index(self, cone=None): if not PPCs: return None Q = cone.sublattice_quotient() - S = Q.submodule([self(g) - for g in PPCs[0].sublattice_complement().gens()]) - i = prod((Q/S).invariants()) + S = Q.submodule([self(g) for g in PPCs[0].sublattice_complement().gens()]) + i = prod((Q / S).invariants()) return i if i > 0 else Infinity def is_birational(self): @@ -1190,32 +1149,30 @@ def is_bundle(self): a bundle, as its index is 2. The last map is not even a fibration. """ if self.index() != 1: - return False # Not surjective between lattices. + return False # Not surjective between lattices. Sigma = self.domain_fan() Sigma_p = self.codomain_fan() Sigma_0 = self.kernel_fan() - if (Sigma.n_generating_cones() != - Sigma_0.n_generating_cones() * Sigma_p.n_generating_cones()): - return False # Definitely no splitting. + if Sigma.n_generating_cones() != Sigma_0.n_generating_cones() * Sigma_p.n_generating_cones(): + return False # Definitely no splitting. try: ray_index_map = self._ray_index_map() except ValueError: return False # Rays are not mapped onto rays or the origin. # Figure out how Sigma_0 sits inside Sigma in terms of ray indices. - I_0s = [Sigma.embed(sigma_0).ambient_ray_indices() - for sigma_0 in Sigma_0] + I_0s = [Sigma.embed(sigma_0).ambient_ray_indices() for sigma_0 in Sigma_0] # We examine only generating cones, this is sufficient. for sigma_p in Sigma_p: primitive_cones = self.primitive_preimage_cones(sigma_p) - if len(primitive_cones) != 1: # Should be only sigma_hat. + if len(primitive_cones) != 1: # Should be only sigma_hat. return False sigma_hat = primitive_cones[0] if sigma_p.dim() != sigma_hat.dim(): - return False # sigma -> sigma_p is not a bijection + return False # sigma -> sigma_p is not a bijection I_p = sigma_p.ambient_ray_indices() I_hat = sigma_hat.ambient_ray_indices() if I_p != tuple(sorted(ray_index_map[i] for i in I_hat)): - return False # sigma -> sigma_p is not a bijection + return False # sigma -> sigma_p is not a bijection # Check that sigma_hat + sigma_0 is always in Sigma. for I_0 in I_0s: I = tuple(sorted(I_hat + I_0)) @@ -1295,7 +1252,7 @@ def is_fibration(self): try: ray_index_map = self._ray_index_map() except ValueError: - return False # Rays are not mapped onto rays or the origin. + return False # Rays are not mapped onto rays or the origin. Sigma_p = self.codomain_fan() # Rays are already checked, the origin is trivial, start with 2-cones. for d in range(2, Sigma_p.dim() + 1): @@ -1303,10 +1260,10 @@ def is_fibration(self): I_p = sigma_p.ambient_ray_indices() for sigma in self.primitive_preimage_cones(sigma_p): if sigma.dim() != d: - return False # sigma -> sigma_p is not a bijection + return False # sigma -> sigma_p is not a bijection I = sigma.ambient_ray_indices() if I_p != tuple(sorted(ray_index_map[i] for i in I)): - return False # sigma -> sigma_p is not a bijection + return False # sigma -> sigma_p is not a bijection return True @cached_method @@ -1377,8 +1334,7 @@ def is_injective(self): return prod(self.factor()[1:]).is_injective() # Now we know that underlying lattice morphism is bijective. Sigma = self.domain_fan() - return all(self.image_cone(sigma).dim() == d - for d in range(1, Sigma.dim() + 1) for sigma in Sigma(d)) + return all(self.image_cone(sigma).dim() == d for d in range(1, Sigma.dim() + 1) for sigma in Sigma(d)) @cached_method def is_surjective(self): @@ -1435,7 +1391,7 @@ def is_surjective(self): False """ if isinstance(self.index(), InfinityElement): - return False # Not surjective between vector spaces. + return False # Not surjective between vector spaces. for dcones in self.codomain_fan().cones(): for sigma_p in dcones: if not self.preimage_cones(sigma_p): @@ -1502,8 +1458,7 @@ def kernel_fan(self): (1-d cone of Rational polyhedral fan in Sublattice ,)) """ fan = self.preimage_fan(Cone([], lattice=self.codomain())) - return Fan((cone.ambient_ray_indices() for cone in fan), fan.rays(), - lattice=self.kernel(), check=False) + return Fan((cone.ambient_ray_indices() for cone in fan), fan.rays(), lattice=self.kernel(), check=False) def preimage_cones(self, cone): r""" @@ -1560,13 +1515,11 @@ def preimage_cones(self, cone): CSGI = cone.star_generator_indices() RISGIS = self._RISGIS() domain_fan = self._domain_fan - possible_rays = frozenset(i for i in range(domain_fan.n_rays()) - if RISGIS[i].issuperset(CSGI)) + possible_rays = frozenset(i for i in range(domain_fan.n_rays()) if RISGIS[i].issuperset(CSGI)) preimage_cones = [] for dcones in domain_fan.cones(): for dcone in dcones: - if (possible_rays.issuperset(dcone.ambient_ray_indices()) - and self.image_cone(dcone) == cone): + if possible_rays.issuperset(dcone.ambient_ray_indices()) and self.image_cone(dcone) == cone: preimage_cones.append(dcone) self._preimage_cones[cone] = tuple(preimage_cones) return self._preimage_cones[cone] @@ -1614,15 +1567,13 @@ def preimage_fan(self, cone): cones = [] for dcones in reversed(domain_fan.cones()): for dcone in dcones: - if (not any(dcone.is_face_of(other) for other in cones) and - self.image_cone(dcone).is_face_of(cone)): + if not any(dcone.is_face_of(other) for other in cones) and self.image_cone(dcone).is_face_of(cone): cones.append(dcone) # Now form the fan from these cones, keeping the ray order. ray_indices = set(cones[0].ambient_ray_indices()) for c in cones[1:]: ray_indices.update(c.ambient_ray_indices()) - self._preimage_fans[cone] = Fan(cones, - domain_fan.rays(sorted(ray_indices)), check=False) + self._preimage_fans[cone] = Fan(cones, domain_fan.rays(sorted(ray_indices)), check=False) return self._preimage_fans[cone] def primitive_preimage_cones(self, cone): @@ -1693,7 +1644,7 @@ def primitive_preimage_cones(self, cone): sage: phi.index() # needs palp 1 """ - sigma_p = self._codomain_fan.embed(cone) # Necessary if used as a key + sigma_p = self._codomain_fan.embed(cone) # Necessary if used as a key if sigma_p not in self._primitive_preimage_cones: primitive_cones = [] for sigma in self.preimage_cones(sigma_p): # Sorted by dimension @@ -1845,10 +1796,8 @@ def factor(self): phi_s = FanMorphism(m, self.domain_fan(), L, check=False) Sigma_prime = self.codomain_fan() L_cone = Cone(sum(([g, -g] for g in L.gens()), []), lattice=L) - Sigma_i = Fan(cones=(L_cone.intersection(cone) for cone in Sigma_prime), - lattice=L, discard_faces=True, check=False) - phi_b = FanMorphism(identity_matrix(d), phi_s.codomain_fan(), Sigma_i, - check=False) + Sigma_i = Fan(cones=(L_cone.intersection(cone) for cone in Sigma_prime), lattice=L, discard_faces=True, check=False) + phi_b = FanMorphism(identity_matrix(d), phi_s.codomain_fan(), Sigma_i, check=False) phi_i = FanMorphism(L.basis_matrix(), Sigma_i, Sigma_prime, check=False) return (phi_i, phi_b, phi_s) diff --git a/src/sage/geometry/hasse_diagram.py b/src/sage/geometry/hasse_diagram.py index 6ee7f10fb60..53d897557e1 100644 --- a/src/sage/geometry/hasse_diagram.py +++ b/src/sage/geometry/hasse_diagram.py @@ -19,11 +19,7 @@ from sage.combinat.posets.lattices import FiniteLatticePoset -def lattice_from_incidences(atom_to_coatoms, coatom_to_atoms, - face_constructor=None, - required_atoms=None, - key=None, - **kwds): +def lattice_from_incidences(atom_to_coatoms, coatom_to_atoms, face_constructor=None, required_atoms=None, key=None, **kwds): r""" Compute an atomic and coatomic lattice from the incidence between atoms and coatoms. @@ -119,6 +115,7 @@ def lattice_from_incidences(atom_to_coatoms, coatom_to_atoms, def default_face_constructor(atoms, coatoms, **kwds): return (atoms, coatoms) + if face_constructor is None: face_constructor = default_face_constructor atom_to_coatoms = [frozenset(atc) for atc in atom_to_coatoms] @@ -126,15 +123,15 @@ def default_face_constructor(atoms, coatoms, **kwds): coatom_to_atoms = [frozenset(cta) for cta in coatom_to_atoms] C = frozenset(range(len(coatom_to_atoms))) # All coatoms # Comments with numbers correspond to steps in Section 2.5 of the article - L = DiGraph(1) # 3: initialize L + L = DiGraph(1) # 3: initialize L faces = {} atoms = frozenset() coatoms = C faces[atoms, coatoms] = 0 next_index = 1 - Q = [(atoms, coatoms)] # 4: initialize Q with the empty face - while Q: # 5 - q_atoms, q_coatoms = Q.pop() # 6: remove some q from Q + Q = [(atoms, coatoms)] # 4: initialize Q with the empty face + while Q: # 5 + q_atoms, q_coatoms = Q.pop() # 6: remove some q from Q q = faces[q_atoms, q_coatoms] # 7: compute H = {closure(q+atom) : atom not in atoms of q} H = {} @@ -153,19 +150,19 @@ def default_face_constructor(atoms, coatoms, **kwds): if atoms.isdisjoint(candidates) and atoms.isdisjoint(minimals): minimals.add(candidate) # Now G == {H[atom] : atom in minimals} - for atom in minimals: # 9: for g in G: + for atom in minimals: # 9: for g in G: g_atoms, g_coatoms = H[atom] if required_atoms is not None: if g_atoms.isdisjoint(required_atoms): continue if (g_atoms, g_coatoms) in faces: g = faces[g_atoms, g_coatoms] - else: # 11: if g was newly created + else: # 11: if g was newly created g = next_index faces[g_atoms, g_coatoms] = g next_index += 1 Q.append((g_atoms, g_coatoms)) # 12 - L.add_edge(q, g) # 14 + L.add_edge(q, g) # 14 # End of algorithm, now construct a FiniteLatticePoset. @@ -177,15 +174,12 @@ def default_face_constructor(atoms, coatoms, **kwds): # Enumeration of graph vertices must be a linear extension of the poset new_order = L.topological_sort() # Make sure that coatoms are in the end in proper order - tail = [faces[atomes, frozenset([coatom])] - for coatom, atomes in enumerate(coatom_to_atoms)] + tail = [faces[atomes, frozenset([coatom])] for coatom, atomes in enumerate(coatom_to_atoms)] tail.append(faces[A, frozenset()]) new_order = [n for n in new_order if n not in tail] + tail # Make sure that atoms are in the beginning in proper order - head = [0] # We know that the empty face has index 0 - head.extend(faces[frozenset([atom]), coatoms] - for atom, coatoms in enumerate(atom_to_coatoms) - if required_atoms is None or atom in required_atoms) + head = [0] # We know that the empty face has index 0 + head.extend(faces[frozenset([atom]), coatoms] for atom, coatoms in enumerate(atom_to_coatoms) if required_atoms is None or atom in required_atoms) new_order = head + [n for n in new_order if n not in head] # "Invert" this list to a dictionary labels = {old: new for new, old in enumerate(new_order)} @@ -194,8 +188,7 @@ def default_face_constructor(atoms, coatoms, **kwds): elements = [None] * next_index for face, index in faces.items(): atoms, coatoms = face - elements[labels[index]] = face_constructor( - tuple(sorted(atoms)), tuple(sorted(coatoms)), **kwds) + elements[labels[index]] = face_constructor(tuple(sorted(atoms)), tuple(sorted(coatoms)), **kwds) D = dict(enumerate(elements)) L.relabel(D) return FiniteLatticePoset(L, elements, key=key) diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py b/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py index 35d28970860..d5bf28570d8 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py @@ -9,14 +9,14 @@ - Travis Scrimshaw (2014): initial version """ -#*********************************************************************** +# *********************************************************************** # Copyright (C) 2014 Travis Scrimshaw # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#*********************************************************************** +# *********************************************************************** from sage.categories.morphism import Morphism from sage.symbolic.constants import I @@ -28,6 +28,7 @@ from sage.misc.functional import sqrt from sage.geometry.hyperbolic_space.hyperbolic_constants import EPSILON from sage.misc.lazy_import import lazy_import + lazy_import('sage.misc.call', 'attrcall') @@ -35,6 +36,7 @@ class HyperbolicModelCoercion(Morphism): """ Abstract base class for morphisms between the hyperbolic models. """ + def _repr_type(self): """ Return the type of morphism. @@ -107,8 +109,7 @@ def convert_geodesic(self, x): sage: phi.convert_geodesic(PD.get_geodesic(0.5+0.5*I, -I)) Geodesic in UHP from 2.00000000000000 + 1.00000000000000*I to 0 """ - return self.codomain().get_geodesic(self(x.start()), self(x.end()), - **x.graphics_options()) + return self.codomain().get_geodesic(self(x.start()), self(x.end()), **x.graphics_options()) def convert_isometry(self, x): """ @@ -146,6 +147,7 @@ def __invert__(self): """ return self.domain().coerce_map_from(self.codomain()) + ############ # From UHP # ############ @@ -155,6 +157,7 @@ class CoercionUHPtoPD(HyperbolicModelCoercion): """ Coercion from the UHP to PD model. """ + def image_coordinates(self, x): """ Return the image of the coordinates of the hyperbolic point ``x`` @@ -170,7 +173,7 @@ def image_coordinates(self, x): """ if x == infinity: return I - return (x - I) / (Integer(1) - I*x) + return (x - I) / (Integer(1) - I * x) def image_isometry_matrix(self, x): """ @@ -188,14 +191,15 @@ def image_isometry_matrix(self, x): """ if x.det() < 0: # x = I * x - return matrix([[1,-I],[-I,1]]) * x * matrix([[1,I],[I,1]]).conjugate()/Integer(2) - return matrix([[1,-I],[-I,1]]) * x * matrix([[1,I],[I,1]])/Integer(2) + return matrix([[1, -I], [-I, 1]]) * x * matrix([[1, I], [I, 1]]).conjugate() / Integer(2) + return matrix([[1, -I], [-I, 1]]) * x * matrix([[1, I], [I, 1]]) / Integer(2) class CoercionUHPtoKM(HyperbolicModelCoercion): """ Coercion from the UHP to KM model. """ + def image_coordinates(self, x): """ Return the image of the coordinates of the hyperbolic point ``x`` @@ -211,8 +215,7 @@ def image_coordinates(self, x): """ if x == infinity: return (0, 1) - return ((2*real(x))/(real(x)**2 + imag(x)**2 + 1), - (real(x)**2 + imag(x)**2 - 1)/(real(x)**2 + imag(x)**2 + 1)) + return ((2 * real(x)) / (real(x) ** 2 + imag(x) ** 2 + 1), (real(x) ** 2 + imag(x) ** 2 - 1) / (real(x) ** 2 + imag(x) ** 2 + 1)) def image_isometry_matrix(self, x): """ @@ -236,6 +239,7 @@ class CoercionUHPtoHM(HyperbolicModelCoercion): """ Coercion from the UHP to HM model. """ + def image_coordinates(self, x): """ Return the image of the coordinates of the hyperbolic point ``x`` @@ -249,9 +253,7 @@ def image_coordinates(self, x): sage: phi.image_coordinates(3 + I) (3, 9/2, 11/2) """ - return vector((real(x)/imag(x), - (real(x)**2 + imag(x)**2 - 1)/(2*imag(x)), - (real(x)**2 + imag(x)**2 + 1)/(2*imag(x)))) + return vector((real(x) / imag(x), (real(x) ** 2 + imag(x) ** 2 - 1) / (2 * imag(x)), (real(x) ** 2 + imag(x) ** 2 + 1) / (2 * imag(x)))) def image_isometry_matrix(self, x): """ @@ -270,6 +272,7 @@ def image_isometry_matrix(self, x): """ return SL2R_to_SO21(x) + ########### # From PD # ########### @@ -279,6 +282,7 @@ class CoercionPDtoUHP(HyperbolicModelCoercion): """ Coercion from the PD to UHP model. """ + def image_coordinates(self, x): """ Return the image of the coordinates of the hyperbolic point ``x`` @@ -311,7 +315,7 @@ def image_coordinates(self, x): """ if abs(x - I) < EPSILON: return infinity - return (x + I)/(Integer(1) + I*x) + return (x + I) / (Integer(1) + I * x) def image_isometry_matrix(self, x): """ @@ -331,15 +335,17 @@ def image_isometry_matrix(self, x): [ 0 -1] """ from sage.geometry.hyperbolic_space.hyperbolic_isometry import HyperbolicIsometryPD + if not HyperbolicIsometryPD._orientation_preserving(x): - return matrix([[1,I],[I,1]]) * x * matrix([[1,-I],[-I,1]]).conjugate() / Integer(2) - return matrix([[1,I],[I,1]]) * x * matrix([[1,-I],[-I,1]]) / Integer(2) + return matrix([[1, I], [I, 1]]) * x * matrix([[1, -I], [-I, 1]]).conjugate() / Integer(2) + return matrix([[1, I], [I, 1]]) * x * matrix([[1, -I], [-I, 1]]) / Integer(2) class CoercionPDtoKM(HyperbolicModelCoercion): """ Coercion from the PD to KM model. """ + def image_coordinates(self, x): """ Return the image of the coordinates of the hyperbolic point ``x`` @@ -353,8 +359,7 @@ def image_coordinates(self, x): sage: phi.image_coordinates(0.5+0.5*I) (0.666666666666667, 0.666666666666667) """ - return (2*real(x)/(Integer(1) + real(x)**2 + imag(x)**2), - 2*imag(x)/(Integer(1) + real(x)**2 + imag(x)**2)) + return (2 * real(x) / (Integer(1) + real(x) ** 2 + imag(x) ** 2), 2 * imag(x) / (Integer(1) + real(x) ** 2 + imag(x) ** 2)) def image_isometry_matrix(self, x): """ @@ -371,14 +376,14 @@ def image_isometry_matrix(self, x): [ 0 1 0] [ 0 0 -1] """ - return SL2R_to_SO21(matrix(2, [1, I, I, 1]) * x * - matrix(2, [1, -I, -I, 1]) / Integer(2)) + return SL2R_to_SO21(matrix(2, [1, I, I, 1]) * x * matrix(2, [1, -I, -I, 1]) / Integer(2)) class CoercionPDtoHM(HyperbolicModelCoercion): """ Coercion from the PD to HM model. """ + def image_coordinates(self, x): """ Return the image of the coordinates of the hyperbolic point ``x`` @@ -392,10 +397,7 @@ def image_coordinates(self, x): sage: phi.image_coordinates(0.5+0.5*I) (2.00000000000000, 2.00000000000000, 3.00000000000000) """ - return vector((2*real(x)/(1 - real(x)**2 - imag(x)**2), - 2*imag(x)/(1 - real(x)**2 - imag(x)**2), - (real(x)**2 + imag(x)**2 + 1) / - (1 - real(x)**2 - imag(x)**2))) + return vector((2 * real(x) / (1 - real(x) ** 2 - imag(x) ** 2), 2 * imag(x) / (1 - real(x) ** 2 - imag(x) ** 2), (real(x) ** 2 + imag(x) ** 2 + 1) / (1 - real(x) ** 2 - imag(x) ** 2))) def image_isometry_matrix(self, x): """ @@ -412,8 +414,8 @@ def image_isometry_matrix(self, x): [ 0 1 0] [ 0 0 -1] """ - return SL2R_to_SO21(matrix(2, [1, I, I, 1]) * x * - matrix(2, [1, -I, -I, 1]) / Integer(2)) + return SL2R_to_SO21(matrix(2, [1, I, I, 1]) * x * matrix(2, [1, -I, -I, 1]) / Integer(2)) + ########### # From KM # @@ -424,6 +426,7 @@ class CoercionKMtoUHP(HyperbolicModelCoercion): """ Coercion from the KM to UHP model. """ + def image_coordinates(self, x): """ Return the image of the coordinates of the hyperbolic point ``x`` @@ -441,9 +444,7 @@ def image_coordinates(self, x): """ if tuple(x) == (0, 1): return infinity - return (-x[0]/(x[1] - 1) - + I*(-(sqrt(-x[0]**2 - x[1]**2 + 1) - x[0]**2 - x[1]**2 + 1) - / ((x[1] - 1)*sqrt(-x[0]**2 - x[1]**2 + 1) + x[1] - 1))) + return -x[0] / (x[1] - 1) + I * (-(sqrt(-x[0] ** 2 - x[1] ** 2 + 1) - x[0] ** 2 - x[1] ** 2 + 1) / ((x[1] - 1) * sqrt(-x[0] ** 2 - x[1] ** 2 + 1) + x[1] - 1)) def image_isometry_matrix(self, x): """ @@ -467,6 +468,7 @@ class CoercionKMtoPD(HyperbolicModelCoercion): """ Coercion from the KM to PD model. """ + def image_coordinates(self, x): """ Return the image of the coordinates of the hyperbolic point ``x`` @@ -480,8 +482,7 @@ def image_coordinates(self, x): sage: phi.image_coordinates((0, 0)) 0 """ - return (x[0]/(1 + (1 - x[0]**2 - x[1]**2).sqrt()) - + I*x[1]/(1 + (1 - x[0]**2 - x[1]**2).sqrt())) + return x[0] / (1 + (1 - x[0] ** 2 - x[1] ** 2).sqrt()) + I * x[1] / (1 + (1 - x[0] ** 2 - x[1] ** 2).sqrt()) def image_isometry_matrix(self, x): """ @@ -498,14 +499,14 @@ def image_isometry_matrix(self, x): [2*sqrt(1/3) sqrt(1/3)] [ sqrt(1/3) 2*sqrt(1/3)] """ - return (matrix(2,[1,-I,-I,1]) * SO21_to_SL2R(x) * - matrix(2,[1,I,I,1])/Integer(2)) + return matrix(2, [1, -I, -I, 1]) * SO21_to_SL2R(x) * matrix(2, [1, I, I, 1]) / Integer(2) class CoercionKMtoHM(HyperbolicModelCoercion): """ Coercion from the KM to HM model. """ + def image_coordinates(self, x): """ Return the image of the coordinates of the hyperbolic point ``x`` @@ -519,8 +520,7 @@ def image_coordinates(self, x): sage: phi.image_coordinates((0, 0)) (0, 0, 1) """ - return (vector((2*x[0], 2*x[1], 1 + x[0]**2 + x[1]**2)) - / (1 - x[0]**2 - x[1]**2)) + return vector((2 * x[0], 2 * x[1], 1 + x[0] ** 2 + x[1] ** 2)) / (1 - x[0] ** 2 - x[1] ** 2) def image_isometry_matrix(self, x): """ @@ -540,6 +540,7 @@ def image_isometry_matrix(self, x): """ return x + ########### # From HM # ########### @@ -549,6 +550,7 @@ class CoercionHMtoUHP(HyperbolicModelCoercion): """ Coercion from the HM to UHP model. """ + def image_coordinates(self, x): """ Return the image of the coordinates of the hyperbolic point ``x`` @@ -562,8 +564,7 @@ def image_coordinates(self, x): sage: phi.image_coordinates( vector((0,0,1)) ) I """ - return -((x[0]*x[2] + x[0]) + I*(x[2] + 1)) / ((x[1] - 1)*x[2] - - x[0]**2 - x[1]**2 + x[1] - 1) + return -((x[0] * x[2] + x[0]) + I * (x[2] + 1)) / ((x[1] - 1) * x[2] - x[0] ** 2 - x[1] ** 2 + x[1] - 1) def image_isometry_matrix(self, x): """ @@ -586,6 +587,7 @@ class CoercionHMtoPD(HyperbolicModelCoercion): """ Coercion from the HM to PD model. """ + def image_coordinates(self, x): """ Return the image of the coordinates of the hyperbolic point ``x`` @@ -599,7 +601,7 @@ def image_coordinates(self, x): sage: phi.image_coordinates( vector((0,0,1)) ) 0 """ - return x[0]/(1 + x[2]) + I*(x[1]/(1 + x[2])) + return x[0] / (1 + x[2]) + I * (x[1] / (1 + x[2])) def image_isometry_matrix(self, x): """ @@ -615,14 +617,14 @@ def image_isometry_matrix(self, x): [1 0] [0 1] """ - return (matrix(2,[1,-I,-I,1]) * SO21_to_SL2R(x) * - matrix(2,[1,I,I,1])/Integer(2)) + return matrix(2, [1, -I, -I, 1]) * SO21_to_SL2R(x) * matrix(2, [1, I, I, 1]) / Integer(2) class CoercionHMtoKM(HyperbolicModelCoercion): """ Coercion from the HM to KM model. """ + def image_coordinates(self, x): """ Return the image of the coordinates of the hyperbolic point ``x`` @@ -636,7 +638,7 @@ def image_coordinates(self, x): sage: phi.image_coordinates( vector((0,0,1)) ) (0, 0) """ - return (x[0]/(1 + x[2]), x[1]/(1 + x[2])) + return (x[0] / (1 + x[2]), x[1] / (1 + x[2])) def image_isometry_matrix(self, x): """ @@ -655,6 +657,7 @@ def image_isometry_matrix(self, x): """ return x + ##################################################################### ## Helper functions @@ -676,24 +679,13 @@ def SL2R_to_SO21(A): sage: norm(A.transpose()*J*A - J) < 10**-4 # needs scipy True """ - a, b, c, d = (A/A.det().sqrt()).list() + a, b, c, d = (A / A.det().sqrt()).list() # Kill ~0 imaginary parts - components = [ - a*d + b*c, a*c - b*d, a*c + b*d, a*b - c*d, - Integer(1)/Integer(2)*a**2 - Integer(1)/Integer(2)*b**2 - - Integer(1)/Integer(2)*c**2 + Integer(1)/Integer(2)*d**2, - Integer(1)/Integer(2)*a**2 + Integer(1)/Integer(2)*b**2 - - Integer(1)/Integer(2)*c**2 - Integer(1)/Integer(2)*d**2, - a*b + c*d, Integer(1)/Integer(2)*a**2 - - Integer(1)/Integer(2)*b**2 + Integer(1)/Integer(2)*c**2 - - Integer(1)/Integer(2)*d**2, Integer(1)/Integer(2)*a**2 + - Integer(1)/Integer(2)*b**2 + Integer(1)/Integer(2)*c**2 + - Integer(1)/Integer(2)*d**2 - ] + components = [a * d + b * c, a * c - b * d, a * c + b * d, a * b - c * d, Integer(1) / Integer(2) * a**2 - Integer(1) / Integer(2) * b**2 - Integer(1) / Integer(2) * c**2 + Integer(1) / Integer(2) * d**2, Integer(1) / Integer(2) * a**2 + Integer(1) / Integer(2) * b**2 - Integer(1) / Integer(2) * c**2 - Integer(1) / Integer(2) * d**2, a * b + c * d, Integer(1) / Integer(2) * a**2 - Integer(1) / Integer(2) * b**2 + Integer(1) / Integer(2) * c**2 - Integer(1) / Integer(2) * d**2, Integer(1) / Integer(2) * a**2 + Integer(1) / Integer(2) * b**2 + Integer(1) / Integer(2) * c**2 + Integer(1) / Integer(2) * d**2] B = matrix(3, [real(comp) for comp in components]) - #B = B.apply_map(attrcall('real')) + # B = B.apply_map(attrcall('real')) if A.det() > 0: return B # Orientation-reversing isometries swap the nappes of @@ -730,24 +722,22 @@ def SO21_to_SL2R(M): # algebra). These corresponds to AXA^-1 etc and give formulas # # for the entries of A. # #################################################################### - (m_1,m_2,m_3,m_4,m_5,m_6,m_7,m_8,m_9) = M.list() - d = sqrt(Integer(1)/Integer(2)*m_5 - Integer(1)/Integer(2)*m_6 - - Integer(1)/Integer(2)*m_8 + Integer(1)/Integer(2)*m_9) + (m_1, m_2, m_3, m_4, m_5, m_6, m_7, m_8, m_9) = M.list() + d = sqrt(Integer(1) / Integer(2) * m_5 - Integer(1) / Integer(2) * m_6 - Integer(1) / Integer(2) * m_8 + Integer(1) / Integer(2) * m_9) if M.det() > 0: # EPSILON? det_sign = 1 elif M.det() < 0: # EPSILON? det_sign = -1 if d > 0: # EPSILON? - c = (-Integer(1)/Integer(2)*m_4 + Integer(1)/Integer(2)*m_7)/d - b = (-Integer(1)/Integer(2)*m_2 + Integer(1)/Integer(2)*m_3)/d - ad = det_sign*1 + b*c # ad - bc = pm 1 - a = ad/d + c = (-Integer(1) / Integer(2) * m_4 + Integer(1) / Integer(2) * m_7) / d + b = (-Integer(1) / Integer(2) * m_2 + Integer(1) / Integer(2) * m_3) / d + ad = det_sign * 1 + b * c # ad - bc = pm 1 + a = ad / d else: # d is 0, so we make c > 0 - c = sqrt(-Integer(1)/Integer(2)*m_5 - Integer(1)/Integer(2)*m_6 + - Integer(1)/Integer(2)*m_8 + Integer(1)/Integer(2)*m_9) - d = (-Integer(1)/Integer(2)*m_4 + Integer(1)/Integer(2)*m_7)/c - # d = 0, so ad - bc = -bc = pm 1. - b = - (det_sign*1)/c - a = (Integer(1)/Integer(2)*m_4 + Integer(1)/Integer(2)*m_7)/b + c = sqrt(-Integer(1) / Integer(2) * m_5 - Integer(1) / Integer(2) * m_6 + Integer(1) / Integer(2) * m_8 + Integer(1) / Integer(2) * m_9) + d = (-Integer(1) / Integer(2) * m_4 + Integer(1) / Integer(2) * m_7) / c + # d = 0, so ad - bc = -bc = pm 1. + b = -(det_sign * 1) / c + a = (Integer(1) / Integer(2) * m_4 + Integer(1) / Integer(2) * m_7) / b A = matrix(2, [a, b, c, d]) return A diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_constants.py b/src/sage/geometry/hyperbolic_space/hyperbolic_constants.py index 1ea800e58b0..afd99a58555 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_constants.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_constants.py @@ -1,4 +1,4 @@ from sage.matrix.constructor import matrix -EPSILON = 10 ** -9 +EPSILON = 10**-9 LORENTZ_GRAM = matrix(3, [1, 0, 0, 0, 1, 0, 0, 0, -1]) diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py index afe7832cafc..c994d44af17 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_geodesic.py @@ -70,7 +70,6 @@ Or implement geodesics as a parent in the subobjects category? """ - # ********************************************************************** # Copyright (C) 2013 Greg Laun # @@ -102,8 +101,7 @@ lazy_import("sage.plot.line", "line") lazy_import("sage.plot.arc", "arc") lazy_import("sage.plot.bezier_path", "bezier_path") -lazy_import('sage.geometry.hyperbolic_space.hyperbolic_isometry', - 'moebius_transform') +lazy_import('sage.geometry.hyperbolic_space.hyperbolic_isometry', 'moebius_transform') class HyperbolicGeodesic(SageObject): @@ -188,7 +186,7 @@ def _complete(self): """ if self._model.is_bounded(): - return (self._start.is_boundary() and self._end.is_boundary()) + return self._start.is_boundary() and self._end.is_boundary() return False # All non-bounded geodesics start life incomplete. def _repr_(self): @@ -215,9 +213,7 @@ def _repr_(self): """ msg = "Geodesic in {0} from {1} to {2}" - return msg.format(self._model.short_name(), - self._start.coordinates(), - self._end.coordinates()) + return msg.format(self._model.short_name(), self._start.coordinates(), self._end.coordinates()) def __eq__(self, other): r""" @@ -234,9 +230,7 @@ def __eq__(self, other): """ if not isinstance(other, HyperbolicGeodesic): return False - return (self._model is other._model and - self._start == other._start and - self._end == other._end) + return self._model is other._model and self._start == other._start and self._end == other._end def __ne__(self, other): """ @@ -485,8 +479,7 @@ def is_asymptotically_parallel(self, other): p1, p2 = self.complete().endpoints() q1, q2 = other.complete().endpoints() - return ((self != other) and ((p1 in [q1, q2]) or (p2 in [q1, q2])) and - self.model() is other.model()) + return (self != other) and ((p1 in [q1, q2]) or (p2 in [q1, q2])) and self.model() is other.model() def is_ultra_parallel(self, other): r""" @@ -631,13 +624,11 @@ def ideal_endpoints(self): """ if not self._model.is_bounded(): - errtxt = "boundary points are not implemented in the " + \ - "{0} model".format(self._model.short_name()) + errtxt = "boundary points are not implemented in the " + "{0} model".format(self._model.short_name()) raise NotImplementedError(errtxt) if self.is_complete(): return self.endpoints() - return [self._model(k) - for k in self._cached_geodesic.ideal_endpoints()] + return [self._model(k) for k in self._cached_geodesic.ideal_endpoints()] def complete(self): r""" @@ -734,6 +725,7 @@ def complete(self): return self._model.get_geodesic(*self.ideal_endpoints()) from copy import copy + g = copy(self) g._complete = True return g @@ -834,8 +826,7 @@ def common_perpendicula(self, other): """ if not self.is_parallel(other): - raise ValueError('geodesics intersect; ' + - 'no common perpendicular exists') + raise ValueError('geodesics intersect; ' + 'no common perpendicular exists') cp = self._cached_geodesic.common_perpendicular(other) return cp.to_model(self._model) @@ -1017,8 +1008,8 @@ def length(self): arccosh(9/4) """ - return self._model._dist_points(self._start.coordinates(), - self._end.coordinates()) + return self._model._dist_points(self._start.coordinates(), self._end.coordinates()) + # *********************************************************************** # UHP geodesics @@ -1075,11 +1066,11 @@ def reflection_involution(self): """ x, y = (real(k.coordinates()) for k in self.ideal_endpoints()) if x == infinity: - M = matrix([[1, -2*y], [0, -1]]) + M = matrix([[1, -2 * y], [0, -1]]) elif y == infinity: - M = matrix([[1, -2*x], [0, -1]]) + M = matrix([[1, -2 * x], [0, -1]]) else: - M = matrix([[(x+y)/(y-x), -2*x*y/(y-x)], [2/(y-x), -(x+y)/(y-x)]]) + M = matrix([[(x + y) / (y - x), -2 * x * y / (y - x)], [2 / (y - x), -(x + y) / (y - x)]]) return self._model.get_isometry(M) def plot(self, boundary=True, **options): @@ -1152,8 +1143,7 @@ def plot(self, boundary=True, **options): opts.update(options) end_1, end_2 = (CC(k.coordinates()) for k in self.endpoints()) bd_1, bd_2 = (CC(k.coordinates()) for k in self.ideal_endpoints()) - if (abs(real(end_1) - real(end_2)) < EPSILON) \ - or CC(infinity) in [end_1, end_2]: # on same vertical line + if (abs(real(end_1) - real(end_2)) < EPSILON) or CC(infinity) in [end_1, end_2]: # on same vertical line # If one of the endpoints is infinity, we replace it with a # large finite point if end_1 == CC(infinity): @@ -1178,18 +1168,16 @@ def plot(self, boundary=True, **options): theta2 = CC(end_2 - center).arg() if abs(theta1 - theta2) < EPSILON: theta2 += pi - pic = arc((real(center), imag(center)), radius, - sector=(theta1, theta2), **opts) + pic = arc((real(center), imag(center)), radius, sector=(theta1, theta2), **opts) if boundary: # We want to draw a segment of the real line. The # computations below compute the projection of the # geodesic to the real line, and then draw a little # to the left and right of the projection. shadow_1, shadow_2 = (real(k) for k in [end_1, end_2]) - midpoint = (shadow_1 + shadow_2)/2 + midpoint = (shadow_1 + shadow_2) / 2 length = abs(shadow_1 - shadow_2) - bd_dict = {'bd_min': midpoint - length, 'bd_max': midpoint + - length} + bd_dict = {'bd_min': midpoint - length, 'bd_max': midpoint + length} bd_pic = self._model.get_background_graphic(**bd_dict) pic += bd_pic return pic @@ -1238,8 +1226,8 @@ def ideal_endpoints(self): if abs(x1 - x2) < EPSILON: return [M.get_point(x1), M.get_point(infinity)] # Otherwise, we have a semicircular arc in the UHP - c = ((x1+x2)*(x2-x1) + (y1+y2)*(y2-y1)) / (2*(x2-x1)) - r = sqrt((c - x1)**2 + y1**2) + c = ((x1 + x2) * (x2 - x1) + (y1 + y2) * (y2 - y1)) / (2 * (x2 - x1)) + r = sqrt((c - x1) ** 2 + y1**2) return [M.get_point(c - r), M.get_point(c + r)] def common_perpendicular(self, other): @@ -1289,8 +1277,7 @@ def common_perpendicular(self, other): B = other.reflection_involution() C = A * B if C.classification() != 'hyperbolic': - raise ValueError("geodesics intersect; " + - "no common perpendicular exists") + raise ValueError("geodesics intersect; " + "no common perpendicular exists") return C.fixed_point_set() def intersection(self, other): @@ -1566,13 +1553,11 @@ def perpendicular_bisector(self): # UHP end = self._end.coordinates() # The complete geodesic p1 -> p2 always returns p1 < p2, # so we might need to swap start and end - if ((real(start - end) > EPSILON) or - (abs(real(start - end)) < EPSILON and - imag(start - end) > 0)): + if (real(start - end) > EPSILON) or (abs(real(start - end)) < EPSILON and imag(start - end) > 0): start, end = end, start S = self.complete()._to_std_geod(start) d = self._model._dist_points(start, end) / 2 - T1 = matrix([[exp(d/2), 0], [0, exp(-d/2)]]) + T1 = matrix([[exp(d / 2), 0], [0, exp(-d / 2)]]) s2 = sqrt(2) / 2 T2 = matrix([[s2, -s2], [s2, s2]]) isom_mtrx = S.inverse() * (T1 * T2) * S @@ -1639,6 +1624,7 @@ def midpoint(self): # UHP True """ from sage.matrix.matrix_symbolic_dense import Matrix_symbolic_dense + if self.length() == infinity: raise ValueError("the length must be finite") @@ -1647,9 +1633,7 @@ def midpoint(self): # UHP d = self._model._dist_points(start, end) / 2 # The complete geodesic p1 -> p2 always returns p1 < p2, # so we might need to swap start and end - if ((real(start - end) > EPSILON) or - (abs(real(start - end)) < EPSILON and - imag(start - end) > 0)): + if (real(start - end) > EPSILON) or (abs(real(start - end)) < EPSILON and imag(start - end) > 0): start, end = end, start S = self.complete()._to_std_geod(start) @@ -1894,8 +1878,8 @@ def angle(self, other): # UHP # Check if the geodesics are approximately equal. This must be # done to prevent addition of ``infinity`` and ``-infinity``. - v = (abs(p1 - q1) < EPSILON and abs(p2 - q2) < EPSILON) - w = (abs(p1 - q2) < EPSILON and abs(p2 - q1) < EPSILON) + v = abs(p1 - q1) < EPSILON and abs(p2 - q2) < EPSILON + w = abs(p1 - q2) < EPSILON and abs(p2 - q1) < EPSILON if v or w: return 0 @@ -1991,17 +1975,17 @@ def _get_B(a): if isinstance(a, (int, float, complex)): # Python number a = CDF(a) - if isinstance(a, Expression): # symbolic + if isinstance(a, Expression): # symbolic P = SR zero = SR.zero() one = SR.one() I = SR("I") - elif isinstance(a, Element): # Sage number + elif isinstance(a, Element): # Sage number P = a.parent() zero = P.zero() one = P.one() I = P.gen() - if I.is_one() or (I*I).is_one() or not (-I*I).is_one(): + if I.is_one() or (I * I).is_one() or not (-I * I).is_one(): raise ValueError("invalid number") else: raise ValueError("not a complex number") @@ -2099,8 +2083,8 @@ def _crossratio_matrix(p0, p1, p2): # UHP return matrix([[1, -p0], [1, -p2]]) if p2 == infinity: return matrix([[1, -p0], [0, p1 - p0]]) - return matrix([[p1 - p2, (p1 - p2)*(-p0)], - [p1 - p0, (p1 - p0)*(-p2)]]) + return matrix([[p1 - p2, (p1 - p2) * (-p0)], [p1 - p0, (p1 - p0) * (-p2)]]) + # *********************************************************************** # Other geodesics @@ -2198,7 +2182,7 @@ def plot(self, boundary=True, **options): else: # If we are here, we know it's not a line # So we compute the center and radius of the circle - invdet = RR.one() / (real(bd_1)*imag(bd_2) - real(bd_2)*imag(bd_1)) + invdet = RR.one() / (real(bd_1) * imag(bd_2) - real(bd_2) * imag(bd_1)) centerx = (imag(bd_2) - imag(bd_1)) * invdet centery = (real(bd_1) - real(bd_2)) * invdet center = centerx + I * centery @@ -2210,8 +2194,7 @@ def plot(self, boundary=True, **options): # Make sure the sector is inside the disk if theta2 - theta1 > pi: theta1 += 2 * pi - pic = arc((centerx, centery), radius, - sector=(theta1, theta2), **opts) + pic = arc((centerx, centery), radius, sector=(theta1, theta2), **opts) if boundary: pic += self._model.get_background_graphic() return pic @@ -2272,9 +2255,9 @@ def map_pt(pt): if pt in CC: return CC(pt) return CC(*pt) + end_1, end_2 = (map_pt(k.coordinates()) for k in self.endpoints()) - pic = bezier_path([[(real(end_1), imag(end_1)), - (real(end_2), imag(end_2))]], **opts) + pic = bezier_path([[(real(end_1), imag(end_1)), (real(end_2), imag(end_2))]], **opts) if boundary: pic += self._model.get_background_graphic() return pic @@ -2310,6 +2293,7 @@ class HyperbolicGeodesicHM(HyperbolicGeodesic): g = HM.get_geodesic(p1, p2) sphinx_plot(g.plot(color='blue')) """ + def _plot_vertices(self, points=75): r""" Return ``self`` plotting vertices in `\RR^3`. @@ -2339,15 +2323,15 @@ def _plot_vertices(self, points=75): # v1 = u1, and I don't want to declare another variable, # hence the odd naming convention above. # We need the Lorentz dot product of v1 and u2. - v1_ldot_u2 = u2[0]*v1[0] + u2[1]*v1[1] - u2[2]*v1[2] + v1_ldot_u2 = u2[0] * v1[0] + u2[1] * v1[1] - u2[2] * v1[2] v2 = u2 + v1_ldot_u2 * v1 - v2_norm = sqrt(v2[0]**2 + v2[1]**2 - v2[2]**2) + v2_norm = sqrt(v2[0] ** 2 + v2[1] ** 2 - v2[2] ** 2) v2 = v2 / v2_norm - v2_ldot_u2 = u2[0]*v2[0] + u2[1]*v2[1] - u2[2]*v2[2] + v2_ldot_u2 = u2[0] * v2[0] + u2[1] * v2[1] - u2[2] * v2[2] # Now v1 and v2 are Lorentz orthogonal, and |v1| = -1, |v2|=1 # That is, v1 is unit timelike and v2 is unit spacelike. # This means that cosh(x)*v1 + sinh(x)*v2 is unit timelike. - hyperbola = tuple(cosh(x)*v1 + sinh(x)*v2) + hyperbola = tuple(cosh(x) * v1 + sinh(x) * v2) endtime = arcsinh(v2_ldot_u2) # mimic the function _parametric_plot3d_curve using a bezier3d # instead of a line3d @@ -2355,8 +2339,7 @@ def _plot_vertices(self, points=75): # polygons within the plot library g, ranges = setup_for_eval_on_grid(hyperbola, [(x, 0, endtime)], points) f_x, f_y, f_z = g - return [(f_x(u), f_y(u), f_z(u)) - for u in xsrange(*ranges[0], include_endpoint=True)] + return [(f_x(u), f_y(u), f_z(u)) for u in xsrange(*ranges[0], include_endpoint=True)] def plot(self, show_hyperboloid=True, **graphics_options): r""" @@ -2384,17 +2367,18 @@ def plot(self, show_hyperboloid=True, **graphics_options): # v1 = u1, and I don't want to declare another variable, # hence the odd naming convention above. # We need the Lorentz dot product of v1 and u2. - v1_ldot_u2 = u2[0]*v1[0] + u2[1]*v1[1] - u2[2]*v1[2] + v1_ldot_u2 = u2[0] * v1[0] + u2[1] * v1[1] - u2[2] * v1[2] v2 = u2 + v1_ldot_u2 * v1 - v2_norm = sqrt(v2[0]**2 + v2[1]**2 - v2[2]**2) + v2_norm = sqrt(v2[0] ** 2 + v2[1] ** 2 - v2[2] ** 2) v2 = v2 / v2_norm - v2_ldot_u2 = u2[0]*v2[0] + u2[1]*v2[1] - u2[2]*v2[2] + v2_ldot_u2 = u2[0] * v2[0] + u2[1] * v2[1] - u2[2] * v2[2] # Now v1 and v2 are Lorentz orthogonal, and |v1| = -1, |v2|=1 # That is, v1 is unit timelike and v2 is unit spacelike. # This means that cosh(x)*v1 + sinh(x)*v2 is unit timelike. - hyperbola = cosh(x)*v1 + sinh(x)*v2 + hyperbola = cosh(x) * v1 + sinh(x) * v2 endtime = arcsinh(v2_ldot_u2) from sage.plot.plot3d.all import parametric_plot3d + pic = parametric_plot3d(hyperbola, (x, 0, endtime), **graphics_options) if show_hyperboloid: pic += self._model.get_background_graphic() diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_interface.py b/src/sage/geometry/hyperbolic_space/hyperbolic_interface.py index 11f4c08add9..0837205a9b5 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_interface.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_interface.py @@ -39,6 +39,7 @@ sage: HyperbolicPlane().PD().get_point(1/2 + I/2) Point in PD 1/2*I + 1/2 """ + # ********************************************************************** # # Copyright (C) 2013 Greg Laun @@ -55,9 +56,7 @@ from sage.structure.parent import Parent from sage.categories.sets_cat import Sets from sage.categories.realizations import Realizations, Category_realization_of_parent -from sage.geometry.hyperbolic_space.hyperbolic_model import ( - HyperbolicModelUHP, HyperbolicModelPD, - HyperbolicModelHM, HyperbolicModelKM) +from sage.geometry.hyperbolic_space.hyperbolic_model import HyperbolicModelUHP, HyperbolicModelPD, HyperbolicModelHM, HyperbolicModelKM def HyperbolicSpace(n): @@ -86,6 +85,7 @@ class HyperbolicPlane(Parent, UniqueRepresentation): - ``KM`` -- Klein disk - ``HM`` -- hyperboloid model """ + def __init__(self): """ Initialize ``self``. @@ -96,7 +96,7 @@ def __init__(self): sage: TestSuite(H).run() """ Parent.__init__(self, category=Sets().Metric().WithRealizations()) - self.a_realization() # We create a realization so at least one is known + self.a_realization() # We create a realization so at least one is known def _repr_(self): """ @@ -138,6 +138,7 @@ class HyperbolicModels(Category_realization_of_parent): r""" The category of hyperbolic models of hyperbolic space. """ + def __init__(self, base): r""" Initialize the hyperbolic models of hyperbolic space. @@ -202,4 +203,5 @@ def _an_element_(self): Point in HM (0, 0, 1) """ from sage.rings.integer_ring import ZZ + return self(self.realization_of().PD().get_point(ZZ.zero())) diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py b/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py index 9d7208cd750..5548a91905f 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py @@ -94,8 +94,8 @@ def __init__(self, model, A, check=True): """ if check: model.isometry_test(A) - self._matrix = copy(A) # Make a copy of the potentially mutable matrix - self._matrix.set_immutable() # Make it immutable + self._matrix = copy(A) # Make a copy of the potentially mutable matrix + self._matrix.set_immutable() # Make it immutable Morphism.__init__(self, Hom(model, model)) @lazy_attribute @@ -192,8 +192,7 @@ def __eq__(self, other): m = self.matrix().ncols() A = A / sqrt(A.det(), m) # Normalized to have determinant 1 B = B / sqrt(B.det(), m) - test_matrix = ((A - B).norm() < EPSILON - or (A + B).norm() < EPSILON) + test_matrix = (A - B).norm() < EPSILON or (A + B).norm() < EPSILON return self.domain() is other.domain() and test_matrix def __hash__(self): @@ -215,8 +214,7 @@ def __hash__(self): """ if self.domain().is_isometry_group_projective(): # Special care must be taken for projective groups - m = matrix(self._matrix.nrows(), - [abs(x) for x in self._matrix.list()]) + m = matrix(self._matrix.nrows(), [abs(x) for x in self._matrix.list()]) m.set_immutable() else: m = self._matrix @@ -264,15 +262,15 @@ def __mul__(self, other): """ if isinstance(other, HyperbolicIsometry): other = other.to_model(self.codomain()) - return self.__class__(self.codomain(), self._matrix*other._matrix) + return self.__class__(self.codomain(), self._matrix * other._matrix) from sage.geometry.hyperbolic_space.hyperbolic_point import HyperbolicPoint + if isinstance(other, HyperbolicPoint): return self(other) if isinstance(other, HyperbolicGeodesic): return self.codomain().get_geodesic(self(other.start()), self(other.end())) - raise NotImplementedError("multiplication is not defined between a " - "hyperbolic isometry and {0}".format(other)) + raise NotImplementedError("multiplication is not defined between a " "hyperbolic isometry and {0}".format(other)) def _call_(self, p): r""" @@ -528,8 +526,7 @@ def axis(self): ... ValueError: the isometry is not hyperbolic: axis is undefined """ - if self.classification() not in ['hyperbolic', - 'orientation-reversing hyperbolic']: + if self.classification() not in ['hyperbolic', 'orientation-reversing hyperbolic']: raise ValueError("the isometry is not hyperbolic: axis is undefined") return self.fixed_point_set() @@ -582,8 +579,7 @@ def fixed_geodesic(self): """ fps = self._cached_isometry.fixed_point_set() if not isinstance(fps, HyperbolicGeodesic): - raise ValueError("isometries of type {0}".format(self.classification()) - + " do not fix geodesics") + raise ValueError("isometries of type {0}".format(self.classification()) + " do not fix geodesics") return fps.to_model(self.domain()) def repelling_fixed_point(self): @@ -636,6 +632,7 @@ class HyperbolicIsometryUHP(HyperbolicIsometry): [1 0] [0 1] """ + def _call_(self, p): # UHP r""" Return image of ``p`` under the action of ``self``. @@ -709,7 +706,7 @@ def classification(self): # UHP tau = abs(A.trace()) a = A.list() if A.det() > 0: - tf = bool((a[0] - 1)**2 + a[1]**2 + a[2]**2 + (a[3] - 1)**2 < EPSILON) + tf = bool((a[0] - 1) ** 2 + a[1] ** 2 + a[2] ** 2 + (a[3] - 1) ** 2 < EPSILON) if tf: return 'identity' if tau - 2 < -EPSILON: @@ -718,8 +715,7 @@ def classification(self): # UHP return 'parabolic' if tau - 2 > EPSILON: return 'hyperbolic' - raise ValueError("something went wrong with classification:" + - " trace is {}".format(A.trace())) + raise ValueError("something went wrong with classification:" + " trace is {}".format(A.trace())) # Otherwise The isometry reverses orientation if tau < EPSILON: return 'reflection' @@ -744,8 +740,8 @@ def translation_length(self): # UHP sage: bool((UHP.dist(p, Hp) - H.translation_length()) < 10**-9) True """ - d = sqrt(self._matrix.det()**2) - tau = sqrt((self._matrix / sqrt(d)).trace()**2) + d = sqrt(self._matrix.det() ** 2) + tau = sqrt((self._matrix / sqrt(d)).trace() ** 2) if self.classification() in ['hyperbolic', 'orientation-reversing hyperbolic']: return 2 * arccosh(tau / 2) raise TypeError("translation length is only defined for hyperbolic transformations") @@ -786,26 +782,25 @@ def fixed_point_set(self): # UHP tau = M.trace() ** 2 M_cls = self.classification() if M_cls == 'identity': - raise ValueError("the identity transformation fixes the entire " - "hyperbolic plane") + raise ValueError("the identity transformation fixes the entire " "hyperbolic plane") pt = self.domain().get_point if M_cls == 'parabolic': if abs(M[1, 0]) < EPSILON: return [pt(infinity)] # boundary point - return [pt((M[0,0] - M[1,1]) / (2*M[1,0]))] + return [pt((M[0, 0] - M[1, 1]) / (2 * M[1, 0]))] if M_cls == 'elliptic': d = sqrt(tau - 4) - return [pt((M[0,0] - M[1,1] + sign(M[1,0])*d) / (2*M[1,0]))] + return [pt((M[0, 0] - M[1, 1] + sign(M[1, 0]) * d) / (2 * M[1, 0]))] if M_cls == 'hyperbolic': - if M[1,0] != 0: # if the isometry does not fix infinity + if M[1, 0] != 0: # if the isometry does not fix infinity d = sqrt(tau - 4) - p_1 = (M[0,0] - M[1,1]+d) / (2*M[1,0]) - p_2 = (M[0,0] - M[1,1]-d) / (2*M[1,0]) + p_1 = (M[0, 0] - M[1, 1] + d) / (2 * M[1, 0]) + p_2 = (M[0, 0] - M[1, 1] - d) / (2 * M[1, 0]) return self.domain().get_geodesic(pt(p_1), pt(p_2)) - #else, it fixes infinity. - p_1 = M[0,1] / (M[1,1] - M[0,0]) + # else, it fixes infinity. + p_1 = M[0, 1] / (M[1, 1] - M[0, 0]) p_2 = infinity return self.domain().get_geodesic(pt(p_1), pt(p_2)) @@ -848,10 +843,8 @@ def repelling_fixed_point(self): # UHP sage: UHP.get_isometry(A).repelling_fixed_point() Boundary point in UHP 0 """ - if self.classification() not in ['hyperbolic', - 'orientation-reversing hyperbolic']: - raise ValueError("repelling fixed point is defined only" + - "for hyperbolic isometries") + if self.classification() not in ['hyperbolic', 'orientation-reversing hyperbolic']: + raise ValueError("repelling fixed point is defined only" + "for hyperbolic isometries") v = self._matrix.eigenmatrix_right()[1].column(1) if v[1] == 0: return self.domain().get_point(infinity) @@ -872,10 +865,8 @@ def attracting_fixed_point(self): # UHP sage: UHP.get_isometry(A).attracting_fixed_point() Boundary point in UHP +Infinity """ - if self.classification() not in \ - ['hyperbolic', 'orientation-reversing hyperbolic']: - raise ValueError("Attracting fixed point is defined only" + - "for hyperbolic isometries.") + if self.classification() not in ['hyperbolic', 'orientation-reversing hyperbolic']: + raise ValueError("Attracting fixed point is defined only" + "for hyperbolic isometries.") v = self._matrix.eigenmatrix_right()[1].column(0) if v[1] == 0: return self.domain().get_point(infinity) @@ -897,6 +888,7 @@ class HyperbolicIsometryPD(HyperbolicIsometry): [1 0] [0 1] """ + def _call_(self, p): # PD r""" Return image of ``p`` under the action of ``self``. @@ -980,8 +972,7 @@ def _orientation_preserving(A): # PD sage: orient(matrix([[0, I], [I, 0]])) False """ - return bool(A[1][0] == A[0][1].conjugate() and A[1][1] == A[0][0].conjugate() - and abs(A[0][0]) - abs(A[0][1]) != 0) + return bool(A[1][0] == A[0][1].conjugate() and A[1][1] == A[0][0].conjugate() and abs(A[0][0]) - abs(A[0][1]) != 0) class HyperbolicIsometryKM(HyperbolicIsometry): @@ -1000,6 +991,7 @@ class HyperbolicIsometryKM(HyperbolicIsometry): [0 1 0] [0 0 1] """ + def _call_(self, p): # KM r""" Return image of ``p`` under the action of ``self``. @@ -1017,6 +1009,7 @@ def _call_(self, p): # KM return self.codomain().get_point(infinity) return self.codomain().get_point(v[0:2] / v[2]) + ##################################################################### # Helper functions @@ -1076,5 +1069,4 @@ def moebius_transform(A, z): if c * z + d == 0: return infinity return (a * z + b) / (c * z + d) - raise TypeError("A must be an invertible 2x2 matrix over the" - " complex numbers or a symbolic ring") + raise TypeError("A must be an invertible 2x2 matrix over the" " complex numbers or a symbolic ring") diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_model.py b/src/sage/geometry/hyperbolic_space/hyperbolic_model.py index 4bf8eeeb1a2..b8237acefe2 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_model.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_model.py @@ -92,19 +92,10 @@ from sage.categories.homset import Hom from sage.geometry.hyperbolic_space.hyperbolic_constants import EPSILON, LORENTZ_GRAM -from sage.geometry.hyperbolic_space.hyperbolic_point import ( - HyperbolicPoint, HyperbolicPointUHP) -from sage.geometry.hyperbolic_space.hyperbolic_isometry import ( - HyperbolicIsometry, HyperbolicIsometryUHP, - HyperbolicIsometryPD, HyperbolicIsometryKM, moebius_transform) -from sage.geometry.hyperbolic_space.hyperbolic_geodesic import ( - HyperbolicGeodesic, HyperbolicGeodesicUHP, HyperbolicGeodesicPD, - HyperbolicGeodesicKM, HyperbolicGeodesicHM) -from sage.geometry.hyperbolic_space.hyperbolic_coercion import ( - CoercionUHPtoPD, CoercionUHPtoKM, CoercionUHPtoHM, - CoercionPDtoUHP, CoercionPDtoKM, CoercionPDtoHM, - CoercionKMtoUHP, CoercionKMtoPD, CoercionKMtoHM, - CoercionHMtoUHP, CoercionHMtoPD, CoercionHMtoKM) +from sage.geometry.hyperbolic_space.hyperbolic_point import HyperbolicPoint, HyperbolicPointUHP +from sage.geometry.hyperbolic_space.hyperbolic_isometry import HyperbolicIsometry, HyperbolicIsometryUHP, HyperbolicIsometryPD, HyperbolicIsometryKM, moebius_transform +from sage.geometry.hyperbolic_space.hyperbolic_geodesic import HyperbolicGeodesic, HyperbolicGeodesicUHP, HyperbolicGeodesicPD, HyperbolicGeodesicKM, HyperbolicGeodesicHM +from sage.geometry.hyperbolic_space.hyperbolic_coercion import CoercionUHPtoPD, CoercionUHPtoKM, CoercionUHPtoHM, CoercionPDtoUHP, CoercionPDtoKM, CoercionPDtoHM, CoercionKMtoUHP, CoercionKMtoPD, CoercionKMtoHM, CoercionHMtoUHP, CoercionHMtoPD, CoercionHMtoKM lazy_import('sage.modules.free_module_element', 'vector') @@ -116,12 +107,12 @@ class HyperbolicModel(Parent, UniqueRepresentation, BindableClass): r""" Abstract base class for hyperbolic models. """ + Element = HyperbolicPoint _Geodesic = HyperbolicGeodesic _Isometry = HyperbolicIsometry - def __init__(self, space, name, short_name, bounded, conformal, - dimension, isometry_group, isometry_group_is_projective): + def __init__(self, space, name, short_name, bounded, conformal, dimension, isometry_group, isometry_group_is_projective): """ Initialize ``self``. @@ -144,6 +135,7 @@ def __init__(self, space, name, short_name, bounded, conformal, self._isometry_group = isometry_group self._isometry_group_is_projective = isometry_group_is_projective from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicModels + Parent.__init__(self, category=HyperbolicModels(space)) def _repr_(self): # Abstract @@ -648,6 +640,7 @@ def dist(self, a, b): sage: UHP.dist(I, 2*I) arccosh(5/4) """ + def coords(x): return self(x).coordinates() @@ -664,8 +657,7 @@ def coords(x): # ...and return their distance return self._dist_points(coords(p), coords(q)) - raise NotImplementedError("can only compute distance between" - " ultra-parallel and intersecting geodesics") + raise NotImplementedError("can only compute distance between" " ultra-parallel and intersecting geodesics") # If only one is a geodesic, make sure it's b to make things easier a, b = b, a @@ -721,6 +713,7 @@ def _dist_geod_point(self, start, end, p): def phi(c): return R.coerce_map_from(self).image_coordinates(c) + return R._dist_geod_point(phi(start), phi(end), phi(p)) #################### @@ -763,10 +756,12 @@ def isometry_from_fixed_points(self, repel, attract): ##################################################################### # Upper half plane model + class HyperbolicModelUHP(HyperbolicModel): r""" Upper Half Plane model. """ + Element = HyperbolicPointUHP _Geodesic = HyperbolicGeodesicUHP _Isometry = HyperbolicIsometryUHP @@ -780,10 +775,7 @@ def __init__(self, space): sage: UHP = HyperbolicPlane().UHP() sage: TestSuite(UHP).run() """ - HyperbolicModel.__init__(self, space, - name="Upper Half Plane Model", short_name='UHP', - bounded=True, conformal=True, dimension=2, - isometry_group="PSL(2, \\RR)", isometry_group_is_projective=True) + HyperbolicModel.__init__(self, space, name="Upper Half Plane Model", short_name='UHP', bounded=True, conformal=True, dimension=2, isometry_group="PSL(2, \\RR)", isometry_group_is_projective=True) def _coerce_map_from_(self, X): """ @@ -909,9 +901,7 @@ def isometry_in_model(self, A): """ if isinstance(A, HyperbolicIsometry): return True - return bool(A.ncols() == 2 and A.nrows() == 2 and - sum([k in RR for k in A.list()]) == 4 and - abs(A.det()) > -EPSILON) + return bool(A.ncols() == 2 and A.nrows() == 2 and sum([k in RR for k in A.list()]) == 4 and abs(A.det()) > -EPSILON) def get_background_graphic(self, **bdry_options): r""" @@ -923,6 +913,7 @@ def get_background_graphic(self, **bdry_options): sage: hp = HyperbolicPlane().UHP().get_background_graphic() # needs sage.plot """ from sage.plot.line import line + bd_min = bdry_options.get('bd_min', -5) bd_max = bdry_options.get('bd_max', 5) return line(((bd_min, 0), (bd_max, 0)), color='black') @@ -945,11 +936,11 @@ def _dist_points(self, p1, p2): sage: HyperbolicPlane().UHP()._dist_points(4.0*I, I) 1.38629436111989 """ - num = (real(p2) - real(p1))**2 + (imag(p2) - imag(p1))**2 + num = (real(p2) - real(p1)) ** 2 + (imag(p2) - imag(p1)) ** 2 denom = 2 * imag(p1) * imag(p2) if denom == 0: return infinity - return arccosh(1 + num/denom) + return arccosh(1 + num / denom) def _dist_geod_point(self, start, end, p): r""" @@ -986,13 +977,13 @@ def _dist_geod_point(self, start, end, p): if start + end != infinity: # Not a straight line: # Map the endpoints to 0 and infinity and the midpoint to 1. - T = HyperbolicGeodesicUHP._crossratio_matrix(start, (start + end)/2, end) + T = HyperbolicGeodesicUHP._crossratio_matrix(start, (start + end) / 2, end) else: # Is a straight line: # Map the endpoints to 0 and infinity and another endpoint to 1. T = HyperbolicGeodesicUHP._crossratio_matrix(start, start + 1, end) x = moebius_transform(T, p) - return self._dist_points(x, abs(x)*I) + return self._dist_points(x, abs(x) * I) ################# # Point Methods # @@ -1014,8 +1005,7 @@ def random_point(self, **kwargs): real_max = 10 imag_min = 0 imag_max = 10 - p = RR.random_element(min=real_min, max=real_max) \ - + I * RR.random_element(min=imag_min, max=imag_max) + p = RR.random_element(min=real_min, max=real_max) + I * RR.random_element(min=imag_min, max=imag_max) return self.get_point(p) #################### @@ -1063,14 +1053,11 @@ def isometry_from_fixed_points(self, repel, attract): repel = real(repel) attract = real(attract) if repel == infinity: - A = self._moebius_sending([infinity, attract, attract + 1], - [infinity, attract, attract + 2]) + A = self._moebius_sending([infinity, attract, attract + 1], [infinity, attract, attract + 2]) elif attract == infinity: - A = self._moebius_sending([repel, infinity, repel + 1], - [repel, infinity, repel + 2]) + A = self._moebius_sending([repel, infinity, repel + 1], [repel, infinity, repel + 2]) else: - A = self._moebius_sending([repel, attract, infinity], - [repel, attract, max(repel, attract) + 1]) + A = self._moebius_sending([repel, attract, infinity], [repel, attract, max(repel, attract) + 1]) return self.get_isometry(A) def random_isometry(self, preserve_orientation=True, **kwargs): @@ -1131,6 +1118,7 @@ def _moebius_sending(z, w): # UHP B = HyperbolicGeodesicUHP._crossratio_matrix(w[0], w[1], w[2]) return B.inverse() * A + ##################################################################### # Poincaré disk model @@ -1139,6 +1127,7 @@ class HyperbolicModelPD(HyperbolicModel): r""" Poincaré Disk Model. """ + _Geodesic = HyperbolicGeodesicPD _Isometry = HyperbolicIsometryPD @@ -1153,11 +1142,7 @@ def __init__(self, space): """ # name should really be 'Poincaré Disk Model', but utf8 is not # accepted by repr - HyperbolicModel.__init__(self, space, - name='Poincare Disk Model', short_name='PD', - bounded=True, conformal=True, dimension=2, - isometry_group="PU(1, 1)", - isometry_group_is_projective=True) + HyperbolicModel.__init__(self, space, name='Poincare Disk Model', short_name='PD', bounded=True, conformal=True, dimension=2, isometry_group="PU(1, 1)", isometry_group_is_projective=True) def _coerce_map_from_(self, X): """ @@ -1243,8 +1228,7 @@ def isometry_in_model(self, A): # alpha = A[0][0] # beta = A[0][1] # Orientation preserving and reversing - return (HyperbolicIsometryPD._orientation_preserving(A) or - HyperbolicIsometryPD._orientation_preserving(I * A)) + return HyperbolicIsometryPD._orientation_preserving(A) or HyperbolicIsometryPD._orientation_preserving(I * A) def get_background_graphic(self, **bdry_options): r""" @@ -1257,16 +1241,19 @@ def get_background_graphic(self, **bdry_options): sage: circ = HyperbolicPlane().PD().get_background_graphic() # needs sage.plot """ from sage.plot.circle import circle + return circle((0, 0), 1, axes=False, color='black') ##################################################################### # Klein disk model + class HyperbolicModelKM(HyperbolicModel): r""" Klein Model. """ + _Geodesic = HyperbolicGeodesicKM _Isometry = HyperbolicIsometryKM @@ -1279,10 +1266,7 @@ def __init__(self, space): sage: KM = HyperbolicPlane().KM() sage: TestSuite(KM).run() """ - HyperbolicModel.__init__(self, space, - name="Klein Disk Model", short_name='KM', - bounded=True, conformal=False, dimension=2, - isometry_group="PSO(2, 1)", isometry_group_is_projective=True) + HyperbolicModel.__init__(self, space, name="Klein Disk Model", short_name='KM', bounded=True, conformal=False, dimension=2, isometry_group="PSO(2, 1)", isometry_group_is_projective=True) def _coerce_map_from_(self, X): """ @@ -1367,8 +1351,7 @@ def isometry_in_model(self, A): """ if isinstance(A, HyperbolicIsometry): return True - return bool((A * LORENTZ_GRAM * A.transpose() - LORENTZ_GRAM).norm()**2 < - EPSILON) + return bool((A * LORENTZ_GRAM * A.transpose() - LORENTZ_GRAM).norm() ** 2 < EPSILON) def get_background_graphic(self, **bdry_options): r""" @@ -1381,8 +1364,10 @@ def get_background_graphic(self, **bdry_options): sage: circ = HyperbolicPlane().KM().get_background_graphic() # needs sage.plot """ from sage.plot.circle import circle + return circle((0, 0), 1, axes=False, color='black') + ##################################################################### # Hyperboloid model @@ -1391,6 +1376,7 @@ class HyperbolicModelHM(HyperbolicModel): r""" Hyperboloid Model. """ + _Geodesic = HyperbolicGeodesicHM def __init__(self, space): @@ -1402,10 +1388,7 @@ def __init__(self, space): sage: HM = HyperbolicPlane().HM() sage: TestSuite(HM).run() """ - HyperbolicModel.__init__(self, space, - name="Hyperboloid Model", short_name='HM', - bounded=False, conformal=True, dimension=2, - isometry_group="SO(2, 1)", isometry_group_is_projective=False) + HyperbolicModel.__init__(self, space, name="Hyperboloid Model", short_name='HM', bounded=False, conformal=True, dimension=2, isometry_group="SO(2, 1)", isometry_group_is_projective=False) def _coerce_map_from_(self, X): """ @@ -1447,7 +1430,7 @@ def point_in_model(self, p): """ if isinstance(p, HyperbolicPoint): return p.is_boundary() - return len(p) == 3 and bool(abs(p[0]**2 + p[1]**2 - p[2]**2 + 1) < EPSILON) + return len(p) == 3 and bool(abs(p[0] ** 2 + p[1] ** 2 - p[2] ** 2 + 1) < EPSILON) def boundary_point_in_model(self, p): r""" @@ -1477,7 +1460,7 @@ def isometry_in_model(self, A): """ if isinstance(A, HyperbolicIsometry): return True - return bool((A * LORENTZ_GRAM * A.transpose() - LORENTZ_GRAM).norm()**2 < EPSILON) + return bool((A * LORENTZ_GRAM * A.transpose() - LORENTZ_GRAM).norm() ** 2 < EPSILON) def get_background_graphic(self, **bdry_options): r""" @@ -1491,11 +1474,10 @@ def get_background_graphic(self, **bdry_options): """ from sage.plot.plot3d.all import plot3d from sage.symbolic.ring import SR - hyperboloid_opacity = bdry_options.get('hyperboloid_opacity', .1) + + hyperboloid_opacity = bdry_options.get('hyperboloid_opacity', 0.1) z_height = bdry_options.get('z_height', 7.0) - x_max = sqrt((z_height ** 2 - 1) / 2.0) + x_max = sqrt((z_height**2 - 1) / 2.0) x = SR.var('x') y = SR.var('y') - return plot3d((1 + x ** 2 + y ** 2).sqrt(), - (x, -x_max, x_max), (y, -x_max, x_max), - opacity=hyperboloid_opacity, **bdry_options) + return plot3d((1 + x**2 + y**2).sqrt(), (x, -x_max, x_max), (y, -x_max, x_max), opacity=hyperboloid_opacity, **bdry_options) diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_point.py b/src/sage/geometry/hyperbolic_space/hyperbolic_point.py index f8900a2f54b..32a0ec3f267 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_point.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_point.py @@ -50,14 +50,14 @@ Point in HM (0, 0, 1) """ -#*********************************************************************** +# *********************************************************************** # Copyright (C) 2013 Greg Laun # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#*********************************************************************** +# *********************************************************************** from collections.abc import Iterable from sage.structure.element import Element @@ -185,6 +185,7 @@ class HyperbolicPoint(Element): ... NotImplementedError: boundary points are not implemented in the HM model """ + def __init__(self, model, coordinates, is_boundary, check=True, **graphics_options): r""" See ``HyperbolicPoint`` for full documentation. @@ -202,13 +203,9 @@ def __init__(self, model, coordinates, is_boundary, check=True, **graphics_optio if not model.is_bounded(): raise NotImplementedError("boundary points are not implemented in the {0} model".format(model.short_name())) if check and not model.boundary_point_in_model(coordinates): - raise ValueError( - "{0} is not a valid".format(coordinates) + - " boundary point in the {0} model".format(model.short_name())) + raise ValueError("{0} is not a valid".format(coordinates) + " boundary point in the {0} model".format(model.short_name())) elif check and not model.point_in_model(coordinates): - raise ValueError( - "{0} is not a valid".format(coordinates) + - " point in the {0} model".format(model.short_name())) + raise ValueError("{0} is not a valid".format(coordinates) + " point in the {0} model".format(model.short_name())) if isinstance(coordinates, Iterable): coordinates = vector(coordinates) @@ -299,8 +296,7 @@ def _richcmp_(self, other, op): sage: p1 == p2 True """ - if not (isinstance(other, HyperbolicPoint) - or self.parent() is other.parent()): + if not (isinstance(other, HyperbolicPoint) or self.parent() is other.parent()): return op == op_NE # bool is required to convert symbolic (in)equalities return bool(richcmp(self._coordinates, other._coordinates, op)) @@ -330,8 +326,7 @@ def __rmul__(self, other): # and returns an error instead of calling this method A = self.parent().get_isometry(other) return A(self) - raise TypeError("unsupported operand type(s) for *:" - "{0} and {1}".format(self, other)) + raise TypeError("unsupported operand type(s) for *:" "{0} and {1}".format(self, other)) ####################### # Setters and Getters # @@ -530,8 +525,7 @@ def show(self, boundary=True, **options): p = numerical_approx(p) pic = point((p, 0), **opts) if boundary: - bd_pic = self._model.get_background_graphic(bd_min=p - 1, - bd_max=p + 1) + bd_pic = self._model.get_background_graphic(bd_min=p - 1, bd_max=p + 1) pic = bd_pic + pic else: # It is an interior point if p in RR: @@ -561,6 +555,7 @@ class HyperbolicPointUHP(HyperbolicPoint): sage: HyperbolicPlane().UHP().get_point(1) Boundary point in UHP 1 """ + def symmetry_involution(self): r""" Return the involutory isometry fixing the given point. @@ -575,7 +570,7 @@ def symmetry_involution(self): p = self._coordinates x, y = real(p), imag(p) if y > 0: - M = matrix([[x/y, -(x**2/y) - y], [1/y, -(x/y)]]) + M = matrix([[x / y, -(x**2 / y) - y], [1 / y, -(x / y)]]) return self.parent().get_isometry(M) raise ValueError("cannot determine the isometry of a boundary point") @@ -601,19 +596,19 @@ def show(self, boundary=True, **options): opts.update(self.graphics_options()) opts.update(options) from sage.misc.functional import numerical_approx + p = numerical_approx(p + 0 * I) from sage.plot.point import point + if self._bdry: pic = point((p, 0), **opts) if boundary: - bd_pic = self.parent().get_background_graphic(bd_min=p - 1, - bd_max=p + 1) + bd_pic = self.parent().get_background_graphic(bd_min=p - 1, bd_max=p + 1) pic = bd_pic + pic else: pic = point(p, **opts) if boundary: cent = real(p) - bd_pic = self.parent().get_background_graphic(bd_min=cent - 1, - bd_max=cent + 1) + bd_pic = self.parent().get_background_graphic(bd_min=cent - 1, bd_max=cent + 1) pic = bd_pic + pic return pic diff --git a/src/sage/geometry/hyperplane_arrangement/affine_subspace.py b/src/sage/geometry/hyperplane_arrangement/affine_subspace.py index 034bba9cf36..19ac358f619 100644 --- a/src/sage/geometry/hyperplane_arrangement/affine_subspace.py +++ b/src/sage/geometry/hyperplane_arrangement/affine_subspace.py @@ -57,7 +57,7 @@ [] """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2013 David Perkinson # Volker Braun # @@ -65,7 +65,7 @@ # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.structure.sage_object import SageObject from sage.matrix.constructor import vector @@ -93,6 +93,7 @@ class AffineSubspace(SageObject): p = (1, 0, 0, 0) W = Vector space of dimension 4 over Rational Field """ + def __init__(self, p, V): r""" Construct an :class:`AffineSubspace`. @@ -107,6 +108,7 @@ def __init__(self, p, V): """ R = V.base_ring() from sage.categories.fields import Fields + if R not in Fields(): R = R.fraction_field() V = V.change_ring(R) @@ -145,7 +147,7 @@ def _repr_(self): p = (1, 0, 0, 0) W = Vector space of dimension 4 over Rational Field """ - return "Affine space p + W where:\n p = "+str(self._point)+"\n W = "+str(self._linear_part) + return "Affine space p + W where:\n p = " + str(self._point) + "\n W = " + str(self._linear_part) def __eq__(self, other): r""" @@ -223,7 +225,7 @@ def __le__(self, other): """ V = self._linear_part W = other._linear_part - return V.is_subspace(W) and self._point-other._point in W + return V.is_subspace(W) and self._point - other._point in W def __lt__(self, other): r""" @@ -371,8 +373,7 @@ def intersection(self, other): p = (3, 4, 0) W = Vector space of dimension 3 over Finite Field of size 5 """ - if self.linear_part().ambient_vector_space() != \ - other.linear_part().ambient_vector_space(): + if self.linear_part().ambient_vector_space() != other.linear_part().ambient_vector_space(): raise ValueError('incompatible ambient vector spaces') m = self.linear_part().matrix() n = other.linear_part().matrix() @@ -384,6 +385,6 @@ def intersection(self, other): t = M.solve_left(v) except ValueError: return None # empty intersection - new_p = p + t[:m.nrows()]*m + new_p = p + t[: m.nrows()] * m new_V = self.linear_part().intersection(other._linear_part) return AffineSubspace(new_p, new_V) diff --git a/src/sage/geometry/hyperplane_arrangement/arrangement.py b/src/sage/geometry/hyperplane_arrangement/arrangement.py index d0938f17be9..4218135e703 100644 --- a/src/sage/geometry/hyperplane_arrangement/arrangement.py +++ b/src/sage/geometry/hyperplane_arrangement/arrangement.py @@ -368,6 +368,7 @@ class HyperplaneArrangementElement(Element): :class:`HyperplaneArrangementElement` instances directly, always use the parent. """ + def __init__(self, parent, hyperplanes, check=True, backend=None): """ Construct a hyperplane arrangement. @@ -519,8 +520,7 @@ def _repr_(self): if len(self) < 5: hyperplanes = ' | '.join(h._repr_linear(include_zero=False) for h in self._hyperplanes) return 'Arrangement <{0}>'.format(hyperplanes) - return 'Arrangement of {0} hyperplanes of dimension {1} and rank {2}'.format( - len(self), self.dimension(), self.rank()) + return 'Arrangement of {0} hyperplanes of dimension {1} and rank {2}'.format(len(self), self.dimension(), self.rank()) def dimension(self): """ @@ -674,6 +674,7 @@ def plot(self, **kwds): Graphics object consisting of 3 graphics primitives """ from sage.geometry.hyperplane_arrangement.plot import plot + return plot(self, **kwds) def cone(self, variable='t'): @@ -826,16 +827,21 @@ def intersection_poset(self, element_label='int'): W = Vector space of dimension 2 over Rational Field] """ if element_label == "int": + def update(mapping, val, I0): mapping[val] = len(mapping) + elif element_label == "subset": from sage.sets.set import Set def update(mapping, val, I0): mapping[val] = Set(val) + elif element_label == "subspace": + def update(mapping, val, I0): mapping[val] = I0 + else: raise ValueError("invalid element label type") @@ -876,6 +882,7 @@ def update(mapping, val, I0): update(mapping, label, T) from sage.combinat.posets.posets import Poset + return Poset({mapping[i]: [mapping[j] for j in val] for i, val in hasse.items()}) def _slow_characteristic_polynomial(self): @@ -892,10 +899,11 @@ def _slow_characteristic_polynomial(self): x^2 - 2*x + 1 """ from sage.rings.polynomial.polynomial_ring import polygen + x = polygen(QQ, 'x') P = self.intersection_poset() n = self.dimension() - return sum([P.moebius_function(0, p) * x**(n - P.rank(p)) for p in P]) + return sum([P.moebius_function(0, p) * x ** (n - P.rank(p)) for p in P]) @cached_method def characteristic_polynomial(self): @@ -930,11 +938,12 @@ def characteristic_polynomial(self): 1 """ from sage.rings.polynomial.polynomial_ring import polygen + x = polygen(QQ, 'x') if self.rank() == 1: - return x**(self.dimension() - 1) * (x - len(self)) + return x ** (self.dimension() - 1) * (x - len(self)) if self.rank() == 0: - return x ** 0 + return x**0 H = self[0] R = self.restriction(H) @@ -959,7 +968,7 @@ def poincare_polynomial(self): charpoly = self.characteristic_polynomial() R = charpoly.parent() x = R.gen(0) - poincare = (-x)**self.dimension() * charpoly(-QQ(1)/x) + poincare = (-x) ** self.dimension() * charpoly(-QQ(1) / x) return R(poincare) @cached_method @@ -1003,12 +1012,12 @@ def cocharacteristic_polynomial(self): raise ValueError("only defined for central hyperplane arrangements") from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(ZZ, 'z') z = R.gen() L = self.intersection_poset(element_label='subspace').dual() B = L.minimal_elements()[0] - return R.sum(abs(L.moebius_function(B, X)) * z**X.dimension() - for X in L) + return R.sum(abs(L.moebius_function(B, X)) * z ** X.dimension() for X in L) @cached_method def primitive_eulerian_polynomial(self): @@ -1122,13 +1131,13 @@ def primitive_eulerian_polynomial(self): raise ValueError("only defined for central hyperplane arrangements") from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(ZZ, 'z') z = R.gen() L = self.intersection_poset(element_label='subspace').dual() B = L.minimal_elements()[0] n = self.dimension() - return R.sum(abs(L.moebius_function(B, X)) * (z - 1)**(n-X.dimension()) - for X in L) + return R.sum(abs(L.moebius_function(B, X)) * (z - 1) ** (n - X.dimension()) for X in L) def deletion(self, hyperplanes): r""" @@ -1262,6 +1271,7 @@ def restriction(self, hyperplane, repetitions=False): names = list(parent._names) names.pop(pivot) from sage.geometry.hyperplane_arrangement.ordered_arrangement import OrderedHyperplaneArrangements + if isinstance(parent, OrderedHyperplaneArrangements): H = OrderedHyperplaneArrangements(parent.base_ring(), names=tuple(names)) if not repetitions: @@ -1366,7 +1376,7 @@ def n_regions(self): if self.base_ring().characteristic() != 0: raise TypeError('base field must have characteristic zero') charpoly = self.characteristic_polynomial() - return (-1)**self.dimension() * charpoly(-1) + return (-1) ** self.dimension() * charpoly(-1) @cached_method def n_bounded_regions(self): @@ -1397,7 +1407,7 @@ def n_bounded_regions(self): if self.base_ring().characteristic() != 0: raise TypeError('base field must have characteristic zero') charpoly = self.characteristic_polynomial() - return (-1)**self.rank() * charpoly(1) + return (-1) ** self.rank() * charpoly(1) def has_good_reduction(self, p) -> bool: r""" @@ -1433,6 +1443,7 @@ def has_good_reduction(self, p) -> bool: if not p.is_prime(): raise TypeError('must reduce modulo a prime number') from sage.rings.finite_rings.finite_field_constructor import GF + a = self.change_ring(GF(p)) p = self.intersection_poset() q = a.intersection_poset() @@ -1532,6 +1543,7 @@ def is_central(self, certificate=False): if self.n_hyperplanes() == 0: if certificate: from sage.geometry.polyhedron.parent import Polyhedra + pp = Polyhedra(R, self.dimension(), backend=self._backend) return (True, pp.universe()) return True @@ -1545,6 +1557,7 @@ def is_central(self, certificate=False): # The solution set is empty, therefore the center is empty if certificate: from sage.geometry.polyhedron.parent import Polyhedra + pp = Polyhedra(R, self.dimension(), backend=self._backend) return (False, pp.empty()) return False @@ -1552,9 +1565,8 @@ def is_central(self, certificate=False): if certificate: Ker = m.right_kernel() from sage.geometry.polyhedron.constructor import Polyhedron - return (True, Polyhedron(base_ring=R, vertices=[x], - lines=Ker.basis(), - backend=self._backend)) + + return (True, Polyhedron(base_ring=R, vertices=[x], lines=Ker.basis(), backend=self._backend)) return True def center(self): @@ -1675,6 +1687,7 @@ def essentialization(self): sage: b.essentialization() is b True """ + def echelon_col_iter(row_iter): """helper to iterat over the echelon pivot column indices""" for row in row_iter: @@ -1704,7 +1717,7 @@ def echelon_col_iter(row_iter): v[pivot] = 1 complement_basis.append(vector(R, v)) # reduce the hyperplane equations - echelon_pivots = [] # the column indices where N has 1s from the echelonization + echelon_pivots = [] # the column indices where N has 1s from the echelonization for pivot, row in echelon_col_iter(complement_basis): assert row[pivot] == 1 echelon_pivots.append(pivot) @@ -1760,6 +1773,7 @@ def sign_vector(self, p): if self.base_ring().characteristic() != 0: raise ValueError('characteristic must be zero') from sage.functions.generalized import sign + values = [hyperplane(p) for hyperplane in self] signs = vector(ZZ, [sign(_) for _ in values]) signs.set_immutable() @@ -1784,7 +1798,7 @@ def face_vector(self): m = self.whitney_data()[0] v = list(sum(m.transpose().apply_map(abs))) v.reverse() - v = vector(ZZ, [0]*(self.dimension() - self.rank()) + v) + v = vector(ZZ, [0] * (self.dimension() - self.rank()) + v) v.set_immutable() return v @@ -1834,8 +1848,7 @@ def _parallel_hyperplanes(self) -> tuple: b = hyperplane.b() * (A / hyperplane.A()) parallel_planes.append([b, (hyperplane, A, b)]) parallels[through_origin] = parallel_planes - parallels = sorted(tuple(hyperplane[1] for hyperplane in sorted(value)) - for value in parallels.values()) + parallels = sorted(tuple(hyperplane[1] for hyperplane in sorted(value)) for value in parallels.values()) return tuple(parallels) def vertices(self, exclude_sandwiched=False): @@ -1883,16 +1896,18 @@ def vertices(self, exclude_sandwiched=False): """ import itertools from sage.matroids.constructor import Matroid + R = self.parent().base_ring() parallels = self._parallel_hyperplanes() A_list = [parallel[0][1] for parallel in parallels] - b_list_list = [[-hyperplane[2] for hyperplane in parallel] - for parallel in parallels] + b_list_list = [[-hyperplane[2] for hyperplane in parallel] for parallel in parallels] if exclude_sandwiched: + def skip(b_list): if len(b_list) == 1: return b_list return [b_list[0], b_list[-1]] + b_list_list = [skip(_) for _ in b_list_list] M = Matroid(groundset=range(len(parallels)), matrix=matrix(A_list).transpose()) d = self.dimension() @@ -1942,9 +1957,8 @@ def _make_region(self, hyperplanes): """ ieqs = [h.dense_coefficient_list() for h in hyperplanes] from sage.geometry.polyhedron.constructor import Polyhedron - return Polyhedron(ieqs=ieqs, ambient_dim=self.dimension(), - base_ring=self.parent().base_ring(), - backend=self._backend) + + return Polyhedron(ieqs=ieqs, ambient_dim=self.dimension(), base_ring=self.parent().base_ring(), backend=self._backend) @cached_method def regions(self): @@ -2043,12 +2057,11 @@ def regions(self): if self.base_ring().characteristic() != 0: raise ValueError('base field must have characteristic zero') from sage.geometry.polyhedron.constructor import Polyhedron + R = self.base_ring() dim = self.dimension() be = self._backend - universe = Polyhedron(eqns=[[0] + [0] * dim], - base_ring=R, - backend=be) + universe = Polyhedron(eqns=[[0] + [0] * dim], base_ring=R, backend=be) regions = [universe] if self.is_linear() and self.n_hyperplanes(): # We only take the positive half w.r. to the first hyperplane. @@ -2070,7 +2083,7 @@ def regions(self): # Determine if all vertices lie on one side of the hyperplane. # If so, we determine on which side. - valuations = tuple(ieq[0] + ieq[1:]*v[:] for v in region.vertices()) + valuations = tuple(ieq[0] + ieq[1:] * v[:] for v in region.vertices()) direction = 0 if any(x > 0 for x in valuations): direction = 1 @@ -2086,17 +2099,16 @@ def regions(self): if direction == 0: # In this case all vertices lie on the hyperplane and we must # check if rays are contained in one closed halfspace given by the hyperplane. - valuations = tuple(ieq[1:]*ray[:] for ray in region.rays()) + valuations = tuple(ieq[1:] * ray[:] for ray in region.rays()) if region_lines: - valuations += tuple(ieq[1:]*line[:] for line in region_lines) - valuations += tuple(-ieq[1:]*line[:] for line in region_lines) + valuations += tuple(ieq[1:] * line[:] for line in region_lines) + valuations += tuple(-ieq[1:] * line[:] for line in region_lines) if any(x > 0 for x in valuations) and any(x < 0 for x in valuations): splits = True else: # In this case, at least one of the vertices is not on the hyperplane. # So we check if any ray or line pokes the hyperplane. - if (any(ieq[1:]*r[:]*direction < 0 for r in region.rays()) or - any(ieq[1:]*ll[:] != 0 for ll in region_lines)): + if any(ieq[1:] * r[:] * direction < 0 for r in region.rays()) or any(ieq[1:] * ll[:] != 0 for ll in region_lines): splits = True if splits: @@ -2368,6 +2380,7 @@ def closed_faces(self, labelled=True): if R.characteristic() != 0: raise ValueError('base field must have characteristic zero') from sage.geometry.polyhedron.constructor import Polyhedron + dim = self.dimension() hypes = self.hyperplanes() be = self._backend @@ -2413,7 +2426,7 @@ def closed_faces(self, labelled=True): for l, testhype in enumerate(hypes[:k]): if signs[l] != 0: h = testhype.dense_coefficient_list() - testval = R.sum(h[i+1] * gi for i, gi in enumerate(zero_part_point)) + h[0] + testval = R.sum(h[i + 1] * gi for i, gi in enumerate(zero_part_point)) + h[0] if testval == 0: break else: @@ -2514,6 +2527,7 @@ def face_product(self, F, G, normalize=True): n = len(f) R = self.base_ring() from sage.geometry.polyhedron.constructor import Polyhedron + eqns = [[0] + [0] * n] ieqs = [] signs = [] @@ -2522,13 +2536,13 @@ def face_product(self, F, G, normalize=True): # on. H = hyperplane.dense_coefficient_list() ieq = vector(R, H) - x = R.sum(H[i+1] * fi for i, fi in enumerate(f)) + H[0] + x = R.sum(H[i + 1] * fi for i, fi in enumerate(f)) + H[0] if x < 0: side = -1 elif x > 0: side = 1 else: - x = R.sum(H[i+1] * gi for i, gi in enumerate(g)) + H[0] + x = R.sum(H[i + 1] * gi for i, gi in enumerate(g)) + H[0] if x < 0: side = -1 elif x > 0: @@ -2638,10 +2652,12 @@ def face_semigroup_algebra(self, field=None, names='e'): """ if field is None: from sage.rings.rational_field import QQ + field = QQ zero = field.zero() one = field.one() from sage.matrix.matrix_space import MatrixSpace + Fs = [F0 for F0, F1 in self.closed_faces()] # ``Fs`` is the list of the sign vectors of all closed faces of # ``self``. @@ -2658,13 +2674,13 @@ def face_semigroup_algebra(self, field=None, names='e'): matrix_j = [] for i, si in enumerate(Fs): row_i = [zero] * N - sk = [sil if sil != 0 else sj[l] - for l, sil in enumerate(si)] + sk = [sil if sil != 0 else sj[l] for l, sil in enumerate(si)] k = Fdict[tuple(sk)] row_i[k] = one matrix_j += row_i table.append(MS(matrix_j, coerce=False)) from sage.algebras.finite_dimensional_algebras.finite_dimensional_algebra import FiniteDimensionalAlgebra as FDA + return FDA(field, table, names=names, assume_associative=True) def region_containing_point(self, p): @@ -2737,15 +2753,13 @@ def _bounded_region_indices(self): (2, 7, 8, 9, 10, 11, 16) """ from sage.geometry.polyhedron.constructor import Polyhedron - normal = Polyhedron(vertices=[[0]*self.dimension()], - lines=[hyperplane.normal() for hyperplane in self], - backend=self._backend) + + normal = Polyhedron(vertices=[[0] * self.dimension()], lines=[hyperplane.normal() for hyperplane in self], backend=self._backend) if normal.dim() == 0: transverse = lambda poly: poly else: transverse = lambda poly: poly.intersection(normal) - return tuple(i for i, region in enumerate(self.regions()) - if transverse(region).is_compact()) + return tuple(i for i, region in enumerate(self.regions()) if transverse(region).is_compact()) def bounded_regions(self): r""" @@ -2871,8 +2885,9 @@ def whitney_data(self): r = p.rank_function() top = r(p.maximal_elements()[0]) from sage.matrix.constructor import zero_matrix - m1 = zero_matrix(ZZ, top+1, top+1) - m2 = zero_matrix(ZZ, top+1, top+1) + + m1 = zero_matrix(ZZ, top + 1, top + 1) + m2 = zero_matrix(ZZ, top + 1, top + 1) for i, j in p.relations_iterator(): m1[r(i), r(j)] += p.moebius_function(i, j) m2[r(i), r(j)] += 1 @@ -3020,6 +3035,7 @@ def is_separating_hyperplane(self, region1, region2, hyperplane) -> bool: except AttributeError: p2 = list(region2) from sage.functions.generalized import sign + s = sign(hyperplane(p1)) * sign(hyperplane(p2)) if s < 0: return True @@ -3048,8 +3064,7 @@ def distance_between_regions(self, region1, region2): sage: c.distance_between_regions(s, s) 0 """ - count = sum(1 for hyperplane in self - if self.is_separating_hyperplane(region1, region2, hyperplane)) + count = sum(1 for hyperplane in self if self.is_separating_hyperplane(region1, region2, hyperplane)) return ZZ(count) def distance_enumerator(self, base_region): @@ -3075,10 +3090,11 @@ def distance_enumerator(self, base_region): x^3 + 3*x^2 + 3*x + 1 """ d = [self.distance_between_regions(r, base_region) for r in self.regions()] - d = [d.count(i) for i in range(max(d)+1)] + d = [d.count(i) for i in range(max(d) + 1)] from sage.rings.polynomial.polynomial_ring import polygen + x = polygen(QQ, 'x') - return sum([d[i]*x**i for i in range(len(d))]) + return sum([d[i] * x**i for i in range(len(d))]) @cached_method def varchenko_matrix(self, names='h'): @@ -3124,6 +3140,7 @@ def varchenko_matrix(self, names='h'): """ from sage.matrix.constructor import identity_matrix from sage.misc.misc_c import prod + k = len(self) R = PolynomialRing(QQ, names, k) h = R.gens() @@ -3132,8 +3149,7 @@ def varchenko_matrix(self, names='h'): v = identity_matrix(R, n, n) for i in range(n): for j in range(i + 1, n): - t = prod(h[p] for p in range(k) if - self.is_separating_hyperplane(region[i], region[j], self[p])) + t = prod(h[p] for p in range(k) if self.is_separating_hyperplane(region[i], region[j], self[p])) v[i, j] = v[j, i] = t v.set_immutable() return v @@ -3169,6 +3185,7 @@ def matroid(self): raise ValueError("the hyperplane arrangement must be central") norms = [p.normal() for p in self] from sage.matroids.constructor import Matroid + return Matroid(matrix=matrix(norms).transpose()) def orlik_solomon_algebra(self, base_ring=None, ordering=None, **kwds): @@ -3371,6 +3388,7 @@ def derivation_module_free_chain(self): if not self.is_central(): raise NotImplementedError("only implemented for central arrangements") from sage.geometry.hyperplane_arrangement.check_freeness import construct_free_chain + return construct_free_chain(self) @cached_method(key=lambda self, a: None) @@ -3545,6 +3563,7 @@ def derivation_module_basis(self, algorithm='singular'): S = self.parent().ambient_space().symmetric_space() return matrix.identity(S, self.dimension()).rows() from sage.misc.misc_c import prod + return prod(reversed(C)).rows() return None raise ValueError("invalid algorithm") @@ -3573,6 +3592,7 @@ class HyperplaneArrangements(Parent, UniqueRepresentation): sage: H(x, y, x-1, y-1) Arrangement """ + Element = HyperplaneArrangementElement def __init__(self, base_ring, names=tuple()): @@ -3599,6 +3619,7 @@ def __init__(self, base_ring, names=tuple()): """ from sage.categories.sets_cat import Sets from sage.rings.ring import _Fields + if base_ring not in _Fields: raise ValueError('base ring must be a field') super().__init__(category=Sets()) @@ -3745,7 +3766,7 @@ def _element_constructor_(self, *args, **kwds): # zero = neutral element under addition = the empty hyperplane arrangement args = [] # process keyword arguments - not_char2 = (self.base_ring().characteristic() != 2) + not_char2 = self.base_ring().characteristic() != 2 signed = kwds.pop('signed', not_char2) warn_duplicates = kwds.pop('warn_duplicates', False) check = kwds.pop('check', True) @@ -3769,6 +3790,7 @@ def _element_constructor_(self, *args, **kwds): hyperplanes = set(hyperplanes) if warn_duplicates and n != len(hyperplanes): from warnings import warn + warn('Input contained {0} hyperplanes, but only {1} are distinct.'.format(n, len(hyperplanes))) # argument checking (optional but recommended) if check: diff --git a/src/sage/geometry/hyperplane_arrangement/check_freeness.py b/src/sage/geometry/hyperplane_arrangement/check_freeness.py index 42943d72669..cdbbe35e102 100644 --- a/src/sage/geometry/hyperplane_arrangement/check_freeness.py +++ b/src/sage/geometry/hyperplane_arrangement/check_freeness.py @@ -13,7 +13,7 @@ over a polynomial ring. """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2015 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -21,7 +21,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.matrix.constructor import matrix import sage.libs.singular.function_factory as fun_fact @@ -59,7 +59,7 @@ def less_generators(X): K.append(j) J = [l for l in J if r[l] == zero] break - if not K: # K is empty + if not K: # K is empty return X Kd = set(range(X.nrows())).difference(K) X = X.matrix_from_rows(sorted(Kd)) @@ -90,7 +90,7 @@ def construct_free_chain(A): ] """ AL = list(A) - if not AL: # Empty arrangement + if not AL: # Empty arrangement return [] S = A.parent().ambient_space().symmetric_space() @@ -106,7 +106,7 @@ def construct_free_chain(A): # Helper function def next_step(indices, prev, T): - for pos,i in enumerate(indices): + for pos, i in enumerate(indices): U = prev * T mu = U * phi[i] mu = mu.stack(matrix.diagonal([B[i]]).dense_matrix()) diff --git a/src/sage/geometry/hyperplane_arrangement/hyperplane.py b/src/sage/geometry/hyperplane_arrangement/hyperplane.py index c57a30c9307..58b077ac3b9 100644 --- a/src/sage/geometry/hyperplane_arrangement/hyperplane.py +++ b/src/sage/geometry/hyperplane_arrangement/hyperplane.py @@ -149,6 +149,7 @@ class Hyperplane(LinearExpression): sage: x + 0 == x + ambient(0) # because coercion requires them True """ + def __init__(self, parent, coefficients, constant): """ Initialize ``self``. @@ -240,6 +241,7 @@ def _normal_pivot(self): values = [abs(x) for x in self.A()] except ArithmeticError: from sage.rings.real_double import RDF + values = [abs(RDF(x)) for x in self.A()] max_pos = 0 max_value = values[max_pos] @@ -293,6 +295,7 @@ def polyhedron(self, **kwds): A vertex at (0, 0, 4/3)) """ from sage.geometry.polyhedron.constructor import Polyhedron + R = kwds.pop('base_ring', None) if R is None: R = self.parent().base_ring() @@ -320,6 +323,7 @@ def linear_part(self): """ AA = self.parent().ambient_module() from sage.matrix.constructor import matrix + return matrix(AA.base_ring(), [self.A()]).right_kernel() def linear_part_projection(self, point): @@ -401,6 +405,7 @@ def point(self): norm2 = sum(x**2 for x in self.A()) if norm2 == 0: from sage.matrix.constructor import matrix, vector + solution = matrix(R, self.A()).solve_right(vector(R, [-self.b()])) else: solution = [-x * self.b() / norm2 for x in self.A()] @@ -442,6 +447,7 @@ def intersection(self, other): A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 3 vertices """ from sage.geometry.polyhedron.constructor import Polyhedron + if not isinstance(other, sage.geometry.abc.Polyhedron): try: other = other.polyhedron() @@ -490,7 +496,7 @@ def orthogonal_projection(self, point): raise ValueError('norm of hyperplane normal is zero') point = P.ambient_vector_space()(point) n = self.normal() - return point - n * (self.b() + point*n) / norm2 + return point - n * (self.b() + point * n) / norm2 def primitive(self, signed=True): """ @@ -551,6 +557,7 @@ def primitive(self, signed=True): 60 """ from sage.rings.rational_field import QQ + base_ring = self.parent().base_ring() coeffs = self.coefficients() # first check if the linear expression even defines a hyperplane @@ -561,9 +568,10 @@ def primitive(self, signed=True): if base_ring is QQ: from sage.arith.functions import lcm from sage.arith.misc import gcd + d = lcm(x.denominator() for x in coeffs) n = gcd(x.numerator() for x in coeffs) - adjustment = d/n + adjustment = d / n # over other base rings, rescale the coefficients so that # the first nonzero of the normal vector is one or negative one else: @@ -606,6 +614,7 @@ def _affine_subspace(self): [ 1 2/3] """ from sage.geometry.hyperplane_arrangement.affine_subspace import AffineSubspace + return AffineSubspace(self.point(), self.linear_part()) def plot(self, **kwds): @@ -621,6 +630,7 @@ def plot(self, **kwds): Graphics object consisting of 2 graphics primitives """ from sage.geometry.hyperplane_arrangement.plot import plot_hyperplane + return plot_hyperplane(self, **kwds) def __or__(self, other): @@ -641,6 +651,7 @@ def __or__(self, other): True """ from sage.geometry.hyperplane_arrangement.arrangement import HyperplaneArrangements + parent = self.parent() arrangement = HyperplaneArrangements(parent.base_ring(), names=parent._names) return arrangement(self, other) @@ -669,7 +680,7 @@ def to_symmetric_space(self): S = self.parent().symmetric_space() G = S.gens() # We skip the first coefficient since it corresponds to the constant term - return S.sum(G[i]*c for i, c in enumerate(coeff[1:])) + return S.sum(G[i] * c for i, c in enumerate(coeff[1:])) class AmbientVectorSpace(LinearExpressionModule): @@ -700,11 +711,7 @@ def _repr_(self): sage: AmbientVectorSpace(QQ, ('x', 'y')) 2-dimensional linear space over Rational Field with coordinates x, y """ - return '{0}-dimensional linear space over {3} with coordinate{1} {2}'.format( - self.dimension(), - 's' if self.ngens() > 1 else '', - ', '.join(self._names), - self.base_ring()) + return '{0}-dimensional linear space over {3} with coordinate{1} {2}'.format(self.dimension(), 's' if self.ngens() > 1 else '', ', '.join(self._names), self.base_ring()) def dimension(self): """ @@ -766,4 +773,5 @@ def symmetric_space(self): Multivariate Polynomial Ring in x, y, z over Rational Field """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + return PolynomialRing(self.base_ring(), self.variable_names()) diff --git a/src/sage/geometry/hyperplane_arrangement/library.py b/src/sage/geometry/hyperplane_arrangement/library.py index e1354cb5a2e..6ac61393dd2 100644 --- a/src/sage/geometry/hyperplane_arrangement/library.py +++ b/src/sage/geometry/hyperplane_arrangement/library.py @@ -5,6 +5,7 @@ :mod:`sage.geometry.hyperplane_arrangement.arrangement` for details about how to construct your own hyperplane arrangements. """ + # **************************************************************************** # Copyright (C) 2013 David Perkinson # @@ -51,7 +52,7 @@ def make_parent(base_ring, dimension, names=None): Rational Field with coordinates t0, t1, t2 """ if names is None: - names = tuple('t'+str(i) for i in range(dimension)) + names = tuple('t' + str(i) for i in range(dimension)) else: names = tuple(map(str, names)) if len(names) != dimension: @@ -204,12 +205,12 @@ def Catalan(self, n, K=QQ, names=None): x = H.gens() hyperplanes = [] for i in range(n): - for j in range(i+1, n): + for j in range(i + 1, n): for k in [-1, 0, 1]: hyperplanes.append(x[i] - x[j] - k) Cn = H(*hyperplanes) x = polygen(QQ, 'x') - charpoly = x*prod([x-n-i for i in range(1, n)]) + charpoly = x * prod([x - n - i for i in range(1, n)]) Cn.characteristic_polynomial.set_cache(charpoly) return Cn @@ -501,14 +502,12 @@ def Ish(self, n, K=QQ, names=None): x = H.gens() hyperplanes = [] for i in range(n): - for j in range(i+1, n): + for j in range(i + 1, n): hyperplanes.append(x[i] - x[j]) - hyperplanes.append(x[0] - x[j] - (i+1)) + hyperplanes.append(x[0] - x[j] - (i + 1)) A = H(*hyperplanes) x = polygen(QQ, 'x') - charpoly = x * sum([(-1)**k * stirling_number2(n, n-k) * - prod([(x - 1 - j) for j in range(k, n-1)]) - for k in range(n)]) + charpoly = x * sum([(-1) ** k * stirling_number2(n, n - k) * prod([(x - 1 - j) for j in range(k, n - 1)]) for k in range(n)]) A.characteristic_polynomial.set_cache(charpoly) return A @@ -578,14 +577,14 @@ def IshB(self, n, K=QQ, names=None): x = H.gens() hyperplanes = [] for i in range(n): - for j in range(i+1, n): + for j in range(i + 1, n): hyperplanes.append(x[i] - x[j]) hyperplanes.append(x[i] + x[j]) - for a in range(i+1-n, n-i+1): + for a in range(i + 1 - n, n - i + 1): hyperplanes.append(x[i] - a) A = H(*hyperplanes) x = polygen(QQ, 'x') - charpoly = (x - 2*n) ** n + charpoly = (x - 2 * n) ** n A.characteristic_polynomial.set_cache(charpoly) return A @@ -627,11 +626,11 @@ def linial(self, n, K=QQ, names=None): x = H.gens() hyperplanes = [] for i in range(n): - for j in range(i+1, n): + for j in range(i + 1, n): hyperplanes.append(x[i] - x[j] - 1) A = H(*hyperplanes) x = polygen(QQ, 'x') - charpoly = x * sum(binomial(n, k)*(x - k)**(n - 1) for k in range(n + 1)) / 2**n + charpoly = x * sum(binomial(n, k) * (x - k) ** (n - 1) for k in range(n + 1)) / 2**n A.characteristic_polynomial.set_cache(charpoly) return A @@ -673,13 +672,12 @@ def semiorder(self, n, K=QQ, names=None): x = H.gens() hyperplanes = [] for i in range(n): - for j in range(i+1, n): + for j in range(i + 1, n): for k in [-1, 1]: hyperplanes.append(x[i] - x[j] - k) A = H(*hyperplanes) x = polygen(QQ, 'x') - charpoly = x * sum([stirling_number2(n, k) * prod([x - k - i for i in range(1, k)]) - for k in range(1, n+1)]) + charpoly = x * sum([stirling_number2(n, k) * prod([x - k - i for i in range(1, k)]) for k in range(1, n + 1)]) A.characteristic_polynomial.set_cache(charpoly) return A @@ -800,10 +798,10 @@ def Shi(self, data, K=QQ, names=None, m=1): for a in PR: for const in range(-m + 1, m + 1): - hyperplanes.append(sum(a[j]*x[j] for j in range(d))-const) + hyperplanes.append(sum(a[j] * x[j] for j in range(d)) - const) A = H(*hyperplanes) x = polygen(QQ, 'x') - charpoly = x**(d-n) * (x-m*h)**n + charpoly = x ** (d - n) * (x - m * h) ** n A.characteristic_polynomial.set_cache(charpoly) return A diff --git a/src/sage/geometry/hyperplane_arrangement/ordered_arrangement.py b/src/sage/geometry/hyperplane_arrangement/ordered_arrangement.py index 8b1008f03fa..42cf79d40b8 100644 --- a/src/sage/geometry/hyperplane_arrangement/ordered_arrangement.py +++ b/src/sage/geometry/hyperplane_arrangement/ordered_arrangement.py @@ -105,6 +105,7 @@ class OrderedHyperplaneArrangementElement(HyperplaneArrangementElement): :class:`OrderedHyperplaneArrangementElement` instances directly, always use the parent. """ + def __init__(self, parent, hyperplanes, check=True, backend=None): """ Construct an ordered hyperplane arrangement. @@ -451,8 +452,7 @@ def projective_fundamental_group(self): if n == 3: S = self.parent().ambient_space().symmetric_space() coord = vector(S.gens()) - Proj = ProjectivePlaneCurveArrangements(K, - names=self.parent().variable_names()) + Proj = ProjectivePlaneCurveArrangements(K, names=self.parent().variable_names()) L = Proj([vector(line.coefficients()[1:]) * coord for line in self]) G = L.fundamental_group() self._projective_fundamental_group = G @@ -529,6 +529,7 @@ class OrderedHyperplaneArrangements(HyperplaneArrangements): sage: H(x, y, x-1, y-1) Arrangement """ + Element = OrderedHyperplaneArrangementElement def _element_constructor_(self, *args, **kwds): @@ -591,7 +592,7 @@ def _element_constructor_(self, *args, **kwds): # zero = neutral element under addition = the empty hyperplane arrangement args = [] # process keyword arguments - not_char2 = (self.base_ring().characteristic() != 2) + not_char2 = self.base_ring().characteristic() != 2 signed = kwds.pop('signed', not_char2) check = kwds.pop('check', True) backend = kwds.pop('backend', None) diff --git a/src/sage/geometry/hyperplane_arrangement/plot.py b/src/sage/geometry/hyperplane_arrangement/plot.py index 1c19426545c..c8df892d5eb 100644 --- a/src/sage/geometry/hyperplane_arrangement/plot.py +++ b/src/sage/geometry/hyperplane_arrangement/plot.py @@ -104,10 +104,12 @@ sage: a.plot(hyperplane_labels=True, label_colors=['red','green','black']) # needs sage.plot Graphics3d Object """ + from copy import copy from colorsys import hsv_to_rgb from sage.misc.lazy_import import lazy_import + lazy_import("sage.plot.plot3d.parametric_plot3d", "parametric_plot3d") lazy_import("sage.plot.plot3d.shapes2", "text3d") lazy_import("sage.plot.graphics", "Graphics") @@ -155,24 +157,24 @@ def plot(hyperplane_arrangement, **kwds): if not hyperplane_arrangement.is_essential(): print('Displaying the essentialization.') hyperplane_arrangement = hyperplane_arrangement.essentialization() - elif dim not in [1,2,3]: # revise to handle 4d - return # silently + elif dim not in [1, 2, 3]: # revise to handle 4d + return # silently # handle extra keywords if 'hyperplane_colors' in kwds: hyp_colors = kwds.pop('hyperplane_colors') - if not isinstance(hyp_colors, list): # we assume its a single color then + if not isinstance(hyp_colors, list): # we assume its a single color then hyp_colors = [hyp_colors] * N else: - HSV_tuples = [(i*1.0/N, 0.8, 0.9) for i in range(N)] + HSV_tuples = [(i * 1.0 / N, 0.8, 0.9) for i in range(N)] hyp_colors = [hsv_to_rgb(*x) for x in HSV_tuples] if 'hyperplane_labels' in kwds: hyp_labels = kwds.pop('hyperplane_labels') has_hyp_label = True - if not isinstance(hyp_labels, list): # we assume its a boolean then + if not isinstance(hyp_labels, list): # we assume its a boolean then hyp_labels = [hyp_labels] * N relabeled = [] for i in range(N): - if hyp_labels[i] in [True,'long']: + if hyp_labels[i] in [True, 'long']: relabeled.append(True) else: relabeled.append(str(i)) @@ -182,14 +184,14 @@ def plot(hyperplane_arrangement, **kwds): if 'label_colors' in kwds: label_colors = kwds.pop('label_colors') has_label_color = True - if not isinstance(label_colors, list): # we assume its a single color then + if not isinstance(label_colors, list): # we assume its a single color then label_colors = [label_colors] * N else: has_label_color = False if 'label_fontsize' in kwds: label_fontsize = kwds.pop('label_fontsize') has_label_fontsize = True - if not isinstance(label_fontsize, list): # we assume its a single size then + if not isinstance(label_fontsize, list): # we assume its a single size then label_fontsize = [label_fontsize] * N else: has_label_fontsize = False @@ -197,12 +199,12 @@ def plot(hyperplane_arrangement, **kwds): has_offsets = True offsets = kwds.pop('label_offsets') else: - has_offsets = False # give default values below + has_offsets = False # give default values below hyperplane_legend = kwds.pop('hyperplane_legend', 'long' if dim < 3 else False) if 'hyperplane_opacities' in kwds: hyperplane_opacities = kwds.pop('hyperplane_opacities') has_opacity = True - if not isinstance(hyperplane_opacities, list): # we assume a single number then + if not isinstance(hyperplane_opacities, list): # we assume a single number then hyperplane_opacities = [hyperplane_opacities] * N else: has_opacity = False @@ -212,30 +214,30 @@ def plot(hyperplane_arrangement, **kwds): if 'ranges' in kwds: ranges_set = True ranges = kwds.pop('ranges') - if type(ranges) not in [list,tuple]: # ranges is a single number + if type(ranges) not in [list, tuple]: # ranges is a single number ranges = [ranges] * N # So ranges is some type of list. - elif dim == 2: # arrangement of lines in the plane - if type(ranges[0]) not in [list,tuple]: # a single interval + elif dim == 2: # arrangement of lines in the plane + if type(ranges[0]) not in [list, tuple]: # a single interval ranges = [ranges] * N - elif dim == 3: # arrangement of planes in 3-space - if type(ranges[0][0]) not in [list,tuple]: + elif dim == 3: # arrangement of planes in 3-space + if type(ranges[0][0]) not in [list, tuple]: ranges = [ranges] * N - elif dim not in [2,3]: # ranges is not an option unless dim is 2 or 3 + elif dim not in [2, 3]: # ranges is not an option unless dim is 2 or 3 ranges_set = False - else: # a list of intervals, one for each hyperplane is given - pass # ranges does not need to be modified + else: # a list of intervals, one for each hyperplane is given + pass # ranges does not need to be modified else: - ranges_set = False # give default values below + ranges_set = False # give default values below # the extra keywords have now been handled # now handle the legend - if dim in [1,2]: # points on a line or lines in the plane - if hyperplane_legend in [True,'long']: + if dim in [1, 2]: # points on a line or lines in the plane + if hyperplane_legend in [True, 'long']: hyps = hyperplane_arrangement.hyperplanes() legend_labels = [hyps[i]._latex_() for i in range(N)] - elif hyperplane_legend == 'short' : + elif hyperplane_legend == 'short': legend_labels = [str(i) for i in range(N)] - else: # dim==3, arrangement of planes in 3-space + else: # dim==3, arrangement of planes in 3-space if hyperplane_legend in [True, 'long']: legend3d = legend_3d(hyperplane_arrangement, hyp_colors, 'long') elif hyperplane_legend == 'short': @@ -262,21 +264,21 @@ def plot(hyperplane_arrangement, **kwds): newk['opacity'] = hyperplane_opacities[i] if dim == 1: newk['point_size'] = point_sizes[i] - if dim in [1,2] and hyperplane_legend: # more options than T/F + if dim in [1, 2] and hyperplane_legend: # more options than T/F newk['legend_label'] = legend_labels[i] if ranges_set: newk['ranges'] = ranges[i] p += plot_hyperplane(hyperplane_arrangement[i], rgbcolor=hyp_colors[i], **newk) if dim == 1: - if hyperplane_legend: # there are more options than T/F + if hyperplane_legend: # there are more options than T/F p.legend(True) return p if dim == 2: - if hyperplane_legend: # there are more options than T/F + if hyperplane_legend: # there are more options than T/F p.legend(True) return p # dim==3 - if hyperplane_legend: # there are more options than T/F + if hyperplane_legend: # there are more options than T/F return p, legend3d return p @@ -357,7 +359,7 @@ def plot_hyperplane(hyperplane, **kwds): """ if hyperplane.base_ring().characteristic(): raise NotImplementedError('base field must have characteristic zero') - elif hyperplane.dimension() not in [0, 1, 2]: # dimension of hyperplane, not ambient space + elif hyperplane.dimension() not in [0, 1, 2]: # dimension of hyperplane, not ambient space raise ValueError('can only plot hyperplanes in dimensions 1, 2, 3') # handle extra keywords if 'hyperplane_label' in kwds: @@ -366,17 +368,17 @@ def plot_hyperplane(hyperplane, **kwds): has_hyp_label = False else: has_hyp_label = True - else: # default + else: # default hyp_label = True has_hyp_label = True if has_hyp_label: - if hyp_label: # then label hyperplane with its equation - if hyperplane.dimension() == 2: # jmol does not like latex + if hyp_label: # then label hyperplane with its equation + if hyperplane.dimension() == 2: # jmol does not like latex label = hyperplane._repr_linear(include_zero=False) else: label = hyperplane._latex_() else: - label = hyp_label # a string + label = hyp_label # a string if 'label_color' in kwds: label_color = kwds.pop('label_color') else: @@ -389,7 +391,7 @@ def plot_hyperplane(hyperplane, **kwds): has_offset = True label_offset = kwds.pop('label_offset') else: - has_offset = False # give default values below + has_offset = False # give default values below if 'point_size' in kwds: pt_size = kwds.pop('point_size') else: @@ -402,28 +404,28 @@ def plot_hyperplane(hyperplane, **kwds): # the extra keywords have now been handled # now create the plot if hyperplane.dimension() == 0: # a point on a line - x, = hyperplane.A() + (x,) = hyperplane.A() d = hyperplane.b() - p = point((d/x,0), size=pt_size, **kwds) + p = point((d / x, 0), size=pt_size, **kwds) if has_hyp_label: if not has_offset: label_offset = 0.1 - p += text(label, (d/x,label_offset), - color=label_color,fontsize=label_fontsize) - p += text('',(d/x,label_offset+0.4)) # add space at top + p += text(label, (d / x, label_offset), color=label_color, fontsize=label_fontsize) + p += text('', (d / x, label_offset + 0.4)) # add space at top if 'ymax' not in kwds: kwds['ymax'] = 0.5 - elif hyperplane.dimension() == 1: # a line in the plane + elif hyperplane.dimension() == 1: # a line in the plane pnt = hyperplane.point() w = hyperplane.linear_part().matrix() from sage.symbolic.ring import SR + t = SR.var('t') if ranges_set: if isinstance(ranges, (list, tuple)): t0, t1 = ranges else: # ranges should be a single positive number t0, t1 = -ranges, ranges - else: # default + else: # default t0, t1 = -3, 3 p = parametric_plot(pnt + t * w[0], (t, t0, t1), **kwds) if has_hyp_label: @@ -431,13 +433,13 @@ def plot_hyperplane(hyperplane, **kwds): b0, b1 = label_offset else: b0, b1 = 0, 0.2 - label = text(label,(pnt[0] + b0, pnt[1] + b1), - color=label_color,fontsize=label_fontsize) + label = text(label, (pnt[0] + b0, pnt[1] + b1), color=label_color, fontsize=label_fontsize) p += label - elif hyperplane.dimension() == 2: # a plane in 3-space + elif hyperplane.dimension() == 2: # a plane in 3-space pnt = hyperplane.point() w = hyperplane.linear_part().matrix() from sage.symbolic.ring import SR + s, t = SR.var('s t') if ranges_set: if isinstance(ranges, (list, tuple)): @@ -449,14 +451,13 @@ def plot_hyperplane(hyperplane, **kwds): else: # default s0, s1 = -3, 3 t0, t1 = -3, 3 - p = parametric_plot3d(pnt+s*w[0]+t*w[1], (s,s0,s1), (t,t0,t1), **kwds) + p = parametric_plot3d(pnt + s * w[0] + t * w[1], (s, s0, s1), (t, t0, t1), **kwds) if has_hyp_label: if has_offset: b0, b1, b2 = label_offset else: b0, b1, b2 = 0, 0, 0 - label = text3d(label,(pnt[0]+b0, pnt[1]+b1, pnt[2]+b2), - color=label_color, fontsize=label_fontsize) + label = text3d(label, (pnt[0] + b0, pnt[1] + b1, pnt[2] + b2), color=label_color, fontsize=label_fontsize) p += label return p @@ -505,13 +506,10 @@ def legend_3d(hyperplane_arrangement, hyperplane_colors, length): if length == 'short': labels = [' ' + str(i) for i in range(N)] else: - labels = [' ' + hyps[i]._repr_linear(include_zero=False) for i in - range(N)] + labels = [' ' + hyps[i]._repr_linear(include_zero=False) for i in range(N)] p = Graphics() for i in range(N): - p += line([(0,0),(0,0)], color=hyperplane_colors[i], thickness=8, - legend_label=labels[i], axes=False) - p.set_legend_options(title='Hyperplanes', loc='center', labelspacing=0.4, - fancybox=True, font_size='x-large', ncol=2) + p += line([(0, 0), (0, 0)], color=hyperplane_colors[i], thickness=8, legend_label=labels[i], axes=False) + p.set_legend_options(title='Hyperplanes', loc='center', labelspacing=0.4, fancybox=True, font_size='x-large', ncol=2) p.legend(True) return p diff --git a/src/sage/geometry/integral_points.py b/src/sage/geometry/integral_points.py index b0554b7397f..3db5f6cb1a4 100644 --- a/src/sage/geometry/integral_points.py +++ b/src/sage/geometry/integral_points.py @@ -15,6 +15,4 @@ ) # __all__ is needed to generate Sphinx documentation -__all__ = ['InequalityCollection', 'Inequality_generic', 'Inequality_int', - 'loop_over_parallelotope_points', 'parallelotope_points', 'print_cache', - 'ray_matrix_normal_form', 'rectangular_box_points', 'simplex_points'] +__all__ = ['InequalityCollection', 'Inequality_generic', 'Inequality_int', 'loop_over_parallelotope_points', 'parallelotope_points', 'print_cache', 'ray_matrix_normal_form', 'rectangular_box_points', 'simplex_points'] diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index 7059889d314..c4be42f3ed3 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -135,8 +135,7 @@ from sage.features.palp import PalpExecutable from sage.features.databases import DatabaseReflexivePolytopes from sage.geometry.cone import _ambient_space_point, integral_length -from sage.geometry.point_collection import (PointCollection, - read_palp_point_collection) +from sage.geometry.point_collection import PointCollection, read_palp_point_collection from sage.geometry.toric_lattice import ToricLattice, ToricLattice_generic from sage.geometry.convex_set import ConvexSet_compact from sage.matrix.constructor import matrix @@ -164,10 +163,8 @@ lazy_import("sage.plot.plot3d.all", ["line3d", "point3d"]) lazy_import("sage.plot.plot3d.index_face_set", "IndexFaceSet") lazy_import("sage.plot.plot3d.shapes2", "text3d") -lazy_import('ppl', ['C_Polyhedron', 'Generator_System', 'Linear_Expression'], - feature=PythonModule("ppl", spkg='pplpy', type='standard')) -lazy_import('ppl', 'point', as_='PPL_point', - feature=PythonModule("ppl", spkg='pplpy', type='standard')) +lazy_import('ppl', ['C_Polyhedron', 'Generator_System', 'Linear_Expression'], feature=PythonModule("ppl", spkg='pplpy', type='standard')) +lazy_import('ppl', 'point', as_='PPL_point', feature=PythonModule("ppl", spkg='pplpy', type='standard')) def LatticePolytope(data, compute_vertices=True, n=0, lattice=None): @@ -287,8 +284,7 @@ def LatticePolytope(data, compute_vertices=True, n=0, lattice=None): if isinstance(data, LatticePolytopeClass): data = data._vertices compute_vertices = False - if (isinstance(data, PointCollection) and - (lattice is None or lattice is data.module())): + if isinstance(data, PointCollection) and (lattice is None or lattice is data.module()): return parent.element_class(parent, data, compute_vertices) if isinstance(data, str): with open(data) as f: @@ -303,8 +299,7 @@ def LatticePolytope(data, compute_vertices=True, n=0, lattice=None): raise TypeError("cannot construct a polytope from\n%s" % data) if lattice is None: if not data: - raise ValueError("lattice must be given explicitly for " - "empty polytopes!") + raise ValueError("lattice must be given explicitly for " "empty polytopes!") try: if isinstance(data[0].parent(), ToricLattice_generic): lattice = data[0].parent() @@ -325,7 +320,7 @@ def LatticePolytope(data, compute_vertices=True, n=0, lattice=None): return parent.element_class(parent, data, compute_vertices) -copyreg_constructor(LatticePolytope) # "safe for unpickling" +copyreg_constructor(LatticePolytope) # "safe for unpickling" def ReflexivePolytope(dim, n): @@ -423,9 +418,7 @@ def ReflexivePolytopes(dim): raise NotImplementedError("only 2- and 3-dimensional reflexive polytopes are available!") if _rp[dim] is None: db = DatabaseReflexivePolytopes() - rp = read_all_polytopes( - os.path.join(os.path.dirname(db.absolute_filename()), - f'reflexive_polytopes_{dim}d')) + rp = read_all_polytopes(os.path.join(os.path.dirname(db.absolute_filename()), f'reflexive_polytopes_{dim}d')) for n, p in enumerate(rp): # Data files have normal form of reflexive polytopes p.normal_form.set_cache(p._vertices) @@ -437,8 +430,7 @@ def ReflexivePolytopes(dim): @richcmp_method -class LatticePolytopeClass(Element, ConvexSet_compact, - sage.geometry.abc.LatticePolytope): +class LatticePolytopeClass(Element, ConvexSet_compact, sage.geometry.abc.LatticePolytope): r""" Create a lattice polytope. @@ -476,9 +468,8 @@ class LatticePolytopeClass(Element, ConvexSet_compact, Every polytope has an ambient structure. If it was not specified, it is this polytope itself. """ - def __init__(self, parent, points=None, compute_vertices=None, - ambient=None, ambient_vertex_indices=None, - ambient_facet_indices=None) -> None: + + def __init__(self, parent, points=None, compute_vertices=None, ambient=None, ambient_vertex_indices=None, ambient_facet_indices=None) -> None: r""" Construct a lattice polytope. @@ -496,8 +487,7 @@ def __init__(self, parent, points=None, compute_vertices=None, if ambient is None: self._ambient = self if compute_vertices: - P = C_Polyhedron(Generator_System( - [PPL_point(Linear_Expression(p, 0)) for p in points])) + P = C_Polyhedron(Generator_System([PPL_point(Linear_Expression(p, 0)) for p in points])) self._PPL.set_cache(P) vertices = P.minimized_generators() if len(vertices) != len(points): @@ -535,8 +525,7 @@ def _sage_input_(self, sib, coerced): """ if self._ambient is not self: raise NotImplementedError - return sib.name('LatticePolytope')(sib(self._vertices), - compute_vertices=False) + return sib.name('LatticePolytope')(sib(self._vertices), compute_vertices=False) def __contains__(self, point) -> bool: r""" @@ -697,8 +686,7 @@ def _compute_embedding(self) -> None: p0 = self._shift_vector = points[0] points = [point - p0 for point in points] H = self._sublattice = self.lattice().submodule(points).saturation() - self._sublattice_polytope = LatticePolytope([H.coordinates(point) - for point in points]) + self._sublattice_polytope = LatticePolytope([H.coordinates(point) for point in points]) M = self._embedding_matrix = H.basis_matrix().transpose() # In order to use facet normals obtained from subpolytopes, we # need the following (see Issue #9188). @@ -752,26 +740,23 @@ def _compute_facets(self): normals.append(n) constants.append(Integer(c.inhomogeneous_term())) # Sort normals if facets are vertices - if (self.dim() == 1 - and normals[0] * self.vertex(0) + constants[0] != 0): + if self.dim() == 1 and normals[0] * self.vertex(0) + constants[0] != 0: normals = (normals[1], normals[0]) constants = (constants[1], constants[0]) self._facet_normals = PointCollection(normals, N) # vector(ZZ, constants) is slow - self._facet_constants = (ZZ**len(constants))(constants) + self._facet_constants = (ZZ ** len(constants))(constants) self._facet_constants.set_immutable() - self.is_reflexive.set_cache(self.dim() == self.lattice_dim() and - all(c == 1 for c in constants)) + self.is_reflexive.set_cache(self.dim() == self.lattice_dim() and all(c == 1 for c in constants)) if self.is_reflexive(): - polar = LatticePolytope( - self._facet_normals, compute_vertices=False) + polar = LatticePolytope(self._facet_normals, compute_vertices=False) polar.dim.set_cache(self.dim()) polar.is_reflexive.set_cache(True) polar._polar = self self._polar = polar polar._facet_normals = self._vertices ones = [1] * self.n_vertices() - ones = (ZZ**len(ones))(ones) + ones = (ZZ ** len(ones))(ones) ones.set_immutable() polar._facet_constants = ones @@ -823,9 +808,7 @@ def _contains(self, point, region='whole polytope') -> bool: point = _ambient_space_point(self, point) except TypeError as ex: if str(ex).endswith("have incompatible lattices"): - warn("you have checked if a cone contains a point " - "from an incompatible lattice, this is False", - stacklevel=3) + warn("you have checked if a cone contains a point " "from an incompatible lattice, this is False", stacklevel=3) return False if region not in ("whole polytope", "relative interior", "interior"): @@ -874,8 +857,7 @@ def _embed(self, data): self._compute_embedding() M = self.lattice() if isinstance(data, PointCollection): - r = [M(self._embedding_matrix * point + self._shift_vector) - for point in data] + r = [M(self._embedding_matrix * point + self._shift_vector) for point in data] for point in r: point.set_immutable() return PointCollection(r, M) @@ -884,8 +866,7 @@ def _embed(self, data): for i, col in enumerate(r.columns(copy=False)): r.set_column(i, col + self._shift_vector) return r - return M(self._embedding_matrix * vector(QQ, data) + - self._shift_vector) + return M(self._embedding_matrix * vector(QQ, data) + self._shift_vector) def _latex_(self) -> str: r""" @@ -953,20 +934,15 @@ def _palp(self, command, reduce_dimension=False) -> str: 'M:5 4 F:4\n' """ if self.dim() <= 0: - raise ValueError(("Cannot run \"%s\" for the zero-dimensional " - + "polytope!\nPolytope: %s") % (command, self)) + raise ValueError(("Cannot run \"%s\" for the zero-dimensional " + "polytope!\nPolytope: %s") % (command, self)) if self.dim() < self.lattice_dim() and not reduce_dimension: - raise ValueError(("Cannot run PALP for a %d-dimensional polytope " + - "in a %d-dimensional space!") % (self.dim(), self.lattice_dim())) + raise ValueError(("Cannot run PALP for a %d-dimensional polytope " + "in a %d-dimensional space!") % (self.dim(), self.lattice_dim())) fn = _palp(command, [self], reduce_dimension) with open(fn) as f: result = f.read() os.remove(fn) - if (not result or - "!" in result or "failed." in result or - "increase" in result or "Unable" in result): - lines = ["Error executing '%s' for the given polytope!" % command, - "Output:", result] + if not result or "!" in result or "failed." in result or "increase" in result or "Unable" in result: + lines = ["Error executing '%s' for the given polytope!" % command, "Output:", result] raise ValueError("\n".join(lines)) return result @@ -1040,8 +1016,7 @@ def _pullback(self, data): point.set_immutable() return PointCollection(r, self._sublattice) if isinstance(data, Matrix): - r = matrix([self._pullback(col) - for col in data.columns(copy=False)]).transpose() + r = matrix([self._pullback(col) for col in data.columns(copy=False)]).transpose() return r data = vector(QQ, data) return self._sublattice.coordinates(data - self._shift_vector) @@ -1124,8 +1099,7 @@ def _read_equations(self, data): N = self.dual_lattice() if self.is_reflexive(): data.seek(pos) - polar = LatticePolytope( - read_palp_point_collection(data, N), compute_vertices=False) + polar = LatticePolytope(read_palp_point_collection(data, N), compute_vertices=False) polar.dim.set_cache(self.dim()) polar.is_reflexive.set_cache(True) polar._constructed_as_polar = True @@ -1134,11 +1108,11 @@ def _read_equations(self, data): self._facet_normals = polar._vertices polar._facet_normals = self._vertices ones = [1] * polar.n_vertices() - ones = (ZZ**len(ones))(ones) + ones = (ZZ ** len(ones))(ones) ones.set_immutable() self._facet_constants = ones ones = [1] * self.n_vertices() - ones = (ZZ**len(ones))(ones) + ones = (ZZ ** len(ones))(ones) ones.set_immutable() polar._facet_constants = ones else: @@ -1225,8 +1199,7 @@ def _read_nef_partitions(self, data) -> None: if start != -1: start += 2 end = line.find("[", start) - partition._hodge_numbers = tuple(int(h) - for h in line[start:end].split()) + partition._hodge_numbers = tuple(int(h) for h in line[start:end].split()) partitions.append(partition) line = data.readline() start = line.find("np=") @@ -1291,16 +1264,14 @@ def _sort_faces(self, faces) -> tuple: faces = tuple(faces) if len(faces) > 1: # Otherwise there is nothing to sort if faces[0].n_vertices() == 1: - faces = tuple(sorted(faces, - key=lambda f: f._ambient_vertex_indices)) - elif faces[0].dim() == self.dim() - 1 and \ - hasattr(self, "_facet_normals"): + faces = tuple(sorted(faces, key=lambda f: f._ambient_vertex_indices)) + elif faces[0].dim() == self.dim() - 1 and hasattr(self, "_facet_normals"): # If we already have facet normals, sort according to them faces = set(faces) sorted_faces = [None] * len(faces) for i, n in enumerate(self.facet_normals()): for f in faces: - if set(n * f.vertices()) == set([- self.facet_constant(i)]): + if set(n * f.vertices()) == set([-self.facet_constant(i)]): sorted_faces[i] = f faces.remove(f) break @@ -1631,9 +1602,7 @@ def boundary_point_indices(self): sage: face.boundary_point_indices() # needs sage.graphs (0, 1) """ - return tuple(i - for i, c in enumerate(self.distances().columns(copy=False)) - if len(c.nonzero_positions()) < self.n_facets()) + return tuple(i for i, c in enumerate(self.distances().columns(copy=False)) if len(c.nonzero_positions()) < self.n_facets()) def boundary_points(self): r""" @@ -1779,17 +1748,14 @@ def distances(self, point=None): (3, 1, -1, 1) """ if point is not None: - return (vector(QQ, point) * self.facet_normals() + - self.facet_constants()) + return vector(QQ, point) * self.facet_normals() + self.facet_constants() try: return self._distances except AttributeError: P = self.points() n = self.n_points() - self._distances = matrix(ZZ, [F * P + vector(ZZ, [c] * n) - for F, c in zip(self.facet_normals(), - self.facet_constants())]) + self._distances = matrix(ZZ, [F * P + vector(ZZ, [c] * n) for F, c in zip(self.facet_normals(), self.facet_constants())]) self._distances.set_immutable() return self._distances @@ -1843,7 +1809,7 @@ def dual_lattice(self): try: return self.lattice().dual() except AttributeError: - return ZZ**self.lattice_dim() + return ZZ ** self.lattice_dim() def edges(self): r""" @@ -1974,23 +1940,19 @@ def face_lattice(self): parent = self.parent() if self._ambient is self: # We need to compute face lattice on our own. - vertex_to_facets = [row.nonzero_positions() - for row in self.incidence_matrix().rows()] - facet_to_vertices = [column.nonzero_positions() - for column in self.incidence_matrix().columns()] + vertex_to_facets = [row.nonzero_positions() for row in self.incidence_matrix().rows()] + facet_to_vertices = [column.nonzero_positions() for column in self.incidence_matrix().columns()] def LPFace(vertices, facets): if not facets: return self - return parent.element_class(parent, ambient=self, - ambient_vertex_indices=vertices, - ambient_facet_indices=facets) + return parent.element_class(parent, ambient=self, ambient_vertex_indices=vertices, ambient_facet_indices=facets) - return lattice_from_incidences( - vertex_to_facets, facet_to_vertices, LPFace, key=id(self)) + return lattice_from_incidences(vertex_to_facets, facet_to_vertices, LPFace, key=id(self)) # Get face lattice as a sublattice of the ambient one allowed_indices = frozenset(self._ambient_vertex_indices) from sage.graphs.digraph import DiGraph + L = DiGraph() empty = self._ambient.face_lattice().bottom() L.add_vertex(0) # In case it is the only one @@ -2004,8 +1966,7 @@ def LPFace(vertices, facets): for face in dfaces: face_index = face_to_index[face] for new_face in face.facet_of(): - if not allowed_indices.issuperset( - new_face._ambient_vertex_indices): + if not allowed_indices.issuperset(new_face._ambient_vertex_indices): continue if new_face in ndfaces: new_face_index = face_to_index[new_face] @@ -2106,12 +2067,10 @@ def faces(self, dim=None, codim=None): in 2-d lattice M """ if dim is not None and codim is not None: - raise ValueError( - "dimension and codimension cannot be specified together!") + raise ValueError("dimension and codimension cannot be specified together!") dim = self.dim() - codim if codim is not None else dim if "_faces" not in self.__dict__: - self._faces = tuple(map(self._sort_faces, - self.face_lattice().level_sets())) + self._faces = tuple(map(self._sort_faces, self.face_lattice().level_sets())) if dim is None: return self._faces return self._faces[dim + 1] if -1 <= dim <= self.dim() else () @@ -2390,8 +2349,7 @@ def incidence_matrix(self): sage: o.incidence_matrix().base_ring() Integer Ring """ - incidence_matrix = matrix(ZZ, self.n_vertices(), - self.n_facets(), 0) + incidence_matrix = matrix(ZZ, self.n_vertices(), self.n_facets(), 0) for Hindex, normal in enumerate(self.facet_normals()): facet_constant = self.facet_constant(Hindex) @@ -2505,9 +2463,7 @@ def interior_point_indices(self) -> tuple[int, ...]: sage: face.interior_point_indices() # needs sage.graphs (2,) """ - return tuple(i - for i, c in enumerate(self.distances().columns(copy=False)) - if len(c.nonzero_positions()) == self.n_facets()) + return tuple(i for i, c in enumerate(self.distances().columns(copy=False)) if len(c.nonzero_positions()) == self.n_facets()) def interior_points(self) -> PointCollection: r""" @@ -2558,8 +2514,7 @@ def is_reflexive(self) -> bool: sage: p.is_reflexive() False """ - return self.dim() == self.lattice_dim() and \ - all(c == 1 for c in self.facet_constants()) + return self.dim() == self.lattice_dim() and all(c == 1 for c in self.facet_constants()) def is_cayley(self) -> bool: """ @@ -2596,8 +2551,7 @@ def is_cayley(self) -> bool: if not self.is_full_dimensional(): raise TypeError("the polytope is not full dimensional") verts = self.vertices() - return any(len(set(n.dot_product(v) for v in verts)) == 2 - for n in self.facet_normals()) + return any(len(set(n.dot_product(v) for v in verts)) == 2 for n in self.facet_normals()) def lattice(self): r""" @@ -2672,8 +2626,7 @@ def linearly_independent_vertices(self): """ return self.vertices().matrix().pivot_rows() - def nef_partitions(self, keep_symmetric=False, keep_products=True, - keep_projections=True, hodge_numbers=False): + def nef_partitions(self, keep_symmetric=False, keep_products=True, keep_projections=True, hodge_numbers=False): r""" Return 2-part nef-partitions of ``self``. @@ -2784,8 +2737,7 @@ def nef_partitions(self, keep_symmetric=False, keep_products=True, Polytope: 3-d lattice polytope in 3-d lattice M """ if not self.is_reflexive(): - raise ValueError("the given polytope is not reflexive:\n" - f"Polytope: {self}") + raise ValueError("the given polytope is not reflexive:\n" f"Polytope: {self}") keys = "-N -V" if keep_symmetric: keys += " -s" @@ -2799,16 +2751,9 @@ def nef_partitions(self, keep_symmetric=False, keep_products=True, oldkeys = self._npkeys if oldkeys == keys: return self._nef_partitions - if not (hodge_numbers and oldkeys.find("-p") != -1 - or keep_symmetric and oldkeys.find("-s") == -1 - or not keep_symmetric and oldkeys.find("-s") != -1 - or keep_projections and oldkeys.find("-P") == -1 - or keep_products and oldkeys.find("-D") == -1): + if not (hodge_numbers and oldkeys.find("-p") != -1 or keep_symmetric and oldkeys.find("-s") == -1 or not keep_symmetric and oldkeys.find("-s") != -1 or keep_projections and oldkeys.find("-P") == -1 or keep_products and oldkeys.find("-D") == -1): # Select only necessary partitions - return Sequence([p for p in self._nef_partitions - if (keep_projections or not p._is_projection) - and (keep_products or not p._is_product)], - cr=True, check=False) + return Sequence([p for p in self._nef_partitions if (keep_projections or not p._is_projection) and (keep_products or not p._is_product)], cr=True, check=False) self._read_nef_partitions(self.nef_x(keys)) self._npkeys = keys return self._nef_partitions @@ -3140,8 +3085,7 @@ def normal_form(self, algorithm='palp_native', permutation=False): raise ValueError("normal form is not defined for %s" % self) M = self.lattice() if algorithm == "palp": - result = read_palp_point_collection( - StringIO(self.poly_x("N")), M, permutation=permutation) + result = read_palp_point_collection(StringIO(self.poly_x("N")), M, permutation=permutation) elif algorithm == "palp_native": result = self._palp_native_normal_form(permutation=permutation) elif algorithm == "palp_modified": @@ -3202,8 +3146,7 @@ def _palp_modified_normal_form(self, permutation=False): PM_max = PM.permutation_normal_form() perm = PM.is_permutation_of(PM_max, check=True)[1] permutations = PM.automorphisms_of_rows_and_columns() - permutations = {k: [(perm[0])*p[0], (perm[1])*p[1]] - for k, p in enumerate(permutations)} + permutations = {k: [(perm[0]) * p[0], (perm[1]) * p[1]] for k, p in enumerate(permutations)} out = _palp_canonical_order(self.vertices(), PM_max, permutations) if permutation: return out @@ -3327,6 +3270,7 @@ def _palp_PM_max(self, check=False): [0 0 3 5 3] """ from .palp_normal_form import _palp_PM_max + return _palp_PM_max(self.vertex_facet_pairing_matrix(), check) def n_points(self): @@ -3435,16 +3379,7 @@ def origin(self): except ValueError: pass - def plot3d(self, - show_facets=True, facet_opacity=0.5, facet_color=(0, 1, 0), - facet_colors=None, - show_edges=True, edge_thickness=3, edge_color=(0.5, 0.5, 0.5), - show_vertices=True, vertex_size=10, vertex_color=(1, 0, 0), - show_points=True, point_size=10, point_color=(0, 0, 1), - show_vindices=None, vindex_color=(0, 0, 0), - vlabels=None, - show_pindices=None, pindex_color=(0, 0, 0), - index_shift=1.1): + def plot3d(self, show_facets=True, facet_opacity=0.5, facet_color=(0, 1, 0), facet_colors=None, show_edges=True, edge_thickness=3, edge_color=(0.5, 0.5, 0.5), show_vertices=True, vertex_size=10, vertex_color=(1, 0, 0), show_points=True, point_size=10, point_color=(0, 0, 1), show_vindices=None, vindex_color=(0, 0, 0), vlabels=None, show_pindices=None, pindex_color=(0, 0, 0), index_shift=1.1): r""" Return a 3d-plot of this polytope. @@ -3543,48 +3478,32 @@ def plot3d(self, if dim > 3: raise ValueError("%d-dimensional polytopes cannot be plotted in 3D!" % self.dim()) elif amb_dim > 3: - return self._sublattice_polytope.plot3d( - show_facets, facet_opacity, facet_color, - facet_colors, - show_edges, edge_thickness, edge_color, - show_vertices, vertex_size, vertex_color, - show_points, point_size, point_color, - show_vindices, vindex_color, - vlabels, - show_pindices, pindex_color, - index_shift) + return self._sublattice_polytope.plot3d(show_facets, facet_opacity, facet_color, facet_colors, show_edges, edge_thickness, edge_color, show_vertices, vertex_size, vertex_color, show_points, point_size, point_color, show_vindices, vindex_color, vlabels, show_pindices, pindex_color, index_shift) elif dim == 3: vertices = self.vertices() if show_points or show_pindices: - points = self.points()[self.n_vertices():] + points = self.points()[self.n_vertices() :] else: - vertices = [vector(ZZ, list(self.vertex(i))+[0]*(3-amb_dim)) - for i in range(self.n_vertices())] + vertices = [vector(ZZ, list(self.vertex(i)) + [0] * (3 - amb_dim)) for i in range(self.n_vertices())] if show_points or show_pindices: - points = [vector(ZZ, list(self.point(i))+[0]*(3-amb_dim)) - for i in range(self.n_vertices(), self.n_points())] + points = [vector(ZZ, list(self.point(i)) + [0] * (3 - amb_dim)) for i in range(self.n_vertices(), self.n_points())] pplot = 0 if show_facets: if dim == 2: - pplot += IndexFaceSet([self.traverse_boundary()], - vertices, opacity=facet_opacity, - rgbcolor=facet_color) + pplot += IndexFaceSet([self.traverse_boundary()], vertices, opacity=facet_opacity, rgbcolor=facet_color) elif dim == 3: if facet_colors is None: facet_colors = [facet_color] * self.n_facets() vertex_to_index = {v: i for i, v in enumerate(self.vertices())} for f, c in zip(self.facets(), facet_colors): - pplot += IndexFaceSet([[vertex_to_index[v] for v in f.vertices(f.traverse_boundary())]], - vertices, opacity=facet_opacity, rgbcolor=c) + pplot += IndexFaceSet([[vertex_to_index[v] for v in f.vertices(f.traverse_boundary())]], vertices, opacity=facet_opacity, rgbcolor=c) if show_edges: if dim == 1: pplot += line3d(vertices, thickness=edge_thickness, rgbcolor=edge_color) else: for e in self.edges(): start, end = e.ambient_vertex_indices() - pplot += line3d([vertices[start], vertices[end]], - thickness=edge_thickness, - rgbcolor=edge_color) + pplot += line3d([vertices[start], vertices[end]], thickness=edge_thickness, rgbcolor=edge_color) if show_vertices: pplot += point3d(vertices, size=vertex_size, rgbcolor=vertex_color) if show_vindices is None: @@ -3593,17 +3512,17 @@ def plot3d(self, show_pindices = show_points if show_vindices or show_pindices: # Compute the barycenter and shift text of labels away from it - bc = 1/Integer(len(vertices)) * vector(QQ, sum(vertices)) + bc = 1 / Integer(len(vertices)) * vector(QQ, sum(vertices)) if show_vindices: if vlabels is None: vlabels = list(range(len(vertices))) for i, v in enumerate(vertices): - pplot += text3d(vlabels[i], bc+index_shift*(v-bc), rgbcolor=vindex_color) + pplot += text3d(vlabels[i], bc + index_shift * (v - bc), rgbcolor=vindex_color) if show_points and points: pplot += point3d(points, size=point_size, rgbcolor=point_color) if show_pindices: for i, p in enumerate(points): - pplot += text3d(i+self.n_vertices(), bc+index_shift*(p-bc), rgbcolor=pindex_color) + pplot += text3d(i + self.n_vertices(), bc + index_shift * (p - bc), rgbcolor=pindex_color) return pplot def polyhedron(self, **kwds): @@ -3617,6 +3536,7 @@ def polyhedron(self, **kwds): A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices """ from sage.geometry.polyhedron.constructor import Polyhedron + return Polyhedron(vertices=[list(v) for v in self._vertices], **kwds) def show3d(self): @@ -3807,8 +3727,7 @@ def points(self, *args, **kwds): if m.ncols() > nv: points = list(points) for j in range(nv, m.ncols()): - current = M.element_class( - M, [m[i, j] for i in range(M.rank())]) + current = M.element_class(M, [m[i, j] for i in range(M.rank())]) current.set_immutable() points.append(current) if len(points) > nv: @@ -3879,8 +3798,7 @@ def polar(self): """ if self.is_reflexive(): return self._polar - raise ValueError("the given polytope is not reflexive:\n" - f"Polytope: {self}") + raise ValueError("the given polytope is not reflexive:\n" f"Polytope: {self}") def _mul_(self, other): """ @@ -3981,6 +3899,7 @@ def skeleton(self): [(0, 1, None), (0, 3, None), (1, 2, None), (2, 3, None)] """ from sage.graphs.graph import Graph + skeleton = Graph() skeleton.add_vertices(self.skeleton_points(1)) for edge in self.edges(): @@ -4066,7 +3985,7 @@ def skeleton_show(self, normal=None): normal = [ZZ.random_element(20) for _ in range(3)] normal = matrix(QQ, 3, 1, list(normal)) projectionm = normal.kernel().basis_matrix() - positions = dict(enumerate([list(c) for c in (projectionm*self.points()).columns(copy=False)])) + positions = dict(enumerate([list(c) for c in (projectionm * self.points()).columns(copy=False)])) self.skeleton().show(pos=positions) def traverse_boundary(self): @@ -4140,9 +4059,7 @@ def vertex_facet_pairing_matrix(self): """ V = self.vertices() nv = self.n_vertices() - PM = matrix(ZZ, [n * V + vector(ZZ, [c] * nv) - for n, c in zip(self.facet_normals(), - self.facet_constants())]) + PM = matrix(ZZ, [n * V + vector(ZZ, [c] * nv) for n, c in zip(self.facet_normals(), self.facet_constants())]) PM.set_immutable() return PM @@ -4335,8 +4252,7 @@ def __init__(self, data, Delta_polar, check=True): sage: TestSuite(np).run() # needs palp """ if check and not Delta_polar.is_reflexive(): - raise ValueError("nef-partitions can be constructed for reflexive " - "polytopes only!") + raise ValueError("nef-partitions can be constructed for reflexive " "polytopes only!") self._vertex_to_part = tuple(int(el) for el in data) self._nparts = max(self._vertex_to_part) + 1 self._Delta_polar = Delta_polar @@ -4379,9 +4295,7 @@ def __eq__(self, other): sage: np == 0 False """ - return (isinstance(other, NefPartition) - and self._Delta_polar == other._Delta_polar - and self._vertex_to_part == other._vertex_to_part) + return isinstance(other, NefPartition) and self._Delta_polar == other._Delta_polar and self._vertex_to_part == other._vertex_to_part def __hash__(self): r""" @@ -4662,10 +4576,7 @@ def dual(self): """ # Delta and nabla are interchanged compared to [BN2008]_. # The order of vertices of this nabla_polar will be adjusted. - nabla_polar = LatticePolytope( - reduce(minkowski_sum, - (nabla.vertices() for nabla in self.nablas())), - lattice=self._Delta_polar.lattice()).polar() + nabla_polar = LatticePolytope(reduce(minkowski_sum, (nabla.vertices() for nabla in self.nablas())), lattice=self._Delta_polar.lattice()).polar() vertex_to_part = [] nabla_polar_vertices = [] for i in range(self._nparts): @@ -4675,8 +4586,7 @@ def dual(self): vertex_to_part.append(i) nabla_polar_vertices.append(nabla_polar.vertex(j)) # Make dual look "ordered", like {0,1,2} ⊔ {3,4,5,6} ⊔ {7,8}. - nabla_polar = LatticePolytope(nabla_polar_vertices, - compute_vertices=False) + nabla_polar = LatticePolytope(nabla_polar_vertices, compute_vertices=False) # If self is a valid nef-partition, the dual is as well. dual = NefPartition(vertex_to_part, nabla_polar, check=False) dual.dual.set_cache(self) @@ -4820,10 +4730,7 @@ def nablas(self): """ Delta_polar = self._Delta_polar origin = [[0] * Delta_polar.dim()] - return tuple(LatticePolytope( - [Delta_polar.vertex(j) for j in part] + origin, - lattice=Delta_polar.lattice()) - for part in self.parts()) + return tuple(LatticePolytope([Delta_polar.vertex(j) for j in part] + origin, lattice=Delta_polar.lattice()) for part in self.parts()) def n_parts(self): r""" @@ -5081,25 +4988,21 @@ def _palp(command, polytopes, reduce_dimension=False): input_file = open(input_file_name, "w") for p in polytopes: if p.dim() == 0: - raise ValueError(("Cannot run \"%s\" for the zero-dimensional " - + "polytope!\nPolytope: %s") % (command, p)) + raise ValueError(("Cannot run \"%s\" for the zero-dimensional " + "polytope!\nPolytope: %s") % (command, p)) if p.dim() < p.lattice_dim(): if not reduce_dimension: - raise ValueError(("Cannot run PALP for a %d-dimensional polytope " + - "in a %d-dimensional space!") % (p.dim(), p.lattice_dim())) + raise ValueError(("Cannot run PALP for a %d-dimensional polytope " + "in a %d-dimensional space!") % (p.dim(), p.lattice_dim())) write_palp_matrix(p._pullback(p._vertices), input_file) else: p._vertices.write_for_palp(input_file) input_file.close() output_file_name = tmp_filename() c = "%s <%s >%s" % (command, input_file_name, output_file_name) - p = Popen(c, shell=True, bufsize=2048, - stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) + p = Popen(c, shell=True, bufsize=2048, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) stderr = p.stderr err = stderr.read() if err: - raise RuntimeError(("Error executing \"%s\" for a polytope sequence!" - + "\nOutput:\n%s") % (command, err)) + raise RuntimeError(("Error executing \"%s\" for a polytope sequence!" + "\nOutput:\n%s") % (command, err)) os.remove(input_file_name) try: p.terminate() @@ -5181,6 +5084,7 @@ def _palp_convert_permutation(permutation): sage: _palp_convert_permutation('0123456789bac') # needs sage.groups (11,12) """ + def from_palp_index(i): if i.isdigit(): i = int(i) @@ -5192,13 +5096,14 @@ def from_palp_index(i): elif o in range(65, 91): i = o - 28 else: - raise ValueError('cannot convert PALP index ' - + i + ' to number') + raise ValueError('cannot convert PALP index ' + i + ' to number') return i + n = len(permutation) domain = [from_palp_index(i) for i in permutation] from sage.groups.perm_gps.permgroup_element import make_permgroup_element from sage.groups.perm_gps.permgroup_named import SymmetricGroup + S = SymmetricGroup(n) return make_permgroup_element(S, domain) @@ -5303,14 +5208,13 @@ def _read_poly_x_incidences(data, dim): lines = [data.readline().split() for i in range(dim)] if len(lines) != dim: raise ValueError("Not enough data!") - n = len(lines[0][1]) # Number of vertices or facets + n = len(lines[0][1]) # Number of vertices or facets result = [] for line in lines: line.pop(0) subr = [] for e in line: - f = Sequence([j for j in range(n) if e[n-1-j] == '1'], - int, check=False) + f = Sequence([j for j in range(n) if e[n - 1 - j] == '1'], int, check=False) f.set_immutable() subr.append(f) result.append(subr) @@ -5394,8 +5298,7 @@ def all_nef_partitions(polytopes, keep_symmetric=False): with open(result_name) as result: for p in polytopes: if not p.is_reflexive(): - raise ValueError("nef-partitions can be computed for reflexive " - "polytopes only") + raise ValueError("nef-partitions can be computed for reflexive " "polytopes only") p._read_nef_partitions(result) p._nef_partitions_s = keep_symmetric os.remove(result_name) @@ -5444,8 +5347,7 @@ def all_points(polytopes): else: points = list(p.vertices()) for j in range(nv, m.ncols()): - current = M.element_class( - M, [m[i, j] for i in range(M.rank())]) + current = M.element_class(M, [m[i, j] for i in range(M.rank())]) current.set_immutable() points.append(current) p._points = PointCollection(points, M) @@ -5519,7 +5421,7 @@ def convex_hull(points): vpoints.append(v) p0 = vpoints[0] vpoints = [p - p0 for p in vpoints] - N = ZZ**p0.degree() + N = ZZ ** p0.degree() H = N.submodule(vpoints) if H.rank() == 0: return [p0] @@ -5922,8 +5824,7 @@ def write_palp_matrix(m, ofile=None, comment='', format=None): if isinstance(m, PointCollection): m = m.column_matrix() if format is None: - n = max(len(str(m[i, j])) - for i in range(m.nrows()) for j in range(m.ncols())) + n = max(len(str(m[i, j])) for i in range(m.nrows()) for j in range(m.ncols())) format = "%" + str(n) + "d" s = "%d %d %s\n" % (m.nrows(), m.ncols(), comment) if ofile is None: @@ -5950,6 +5851,7 @@ class LatticePolytopes(UniqueRepresentation, Parent): sage: S.cardinality() +Infinity """ + def __init__(self) -> None: """ The set of all lattice polytopes, as an infinite monoid. diff --git a/src/sage/geometry/linear_expression.py b/src/sage/geometry/linear_expression.py index 28388cd4232..2dfe39baf89 100644 --- a/src/sage/geometry/linear_expression.py +++ b/src/sage/geometry/linear_expression.py @@ -74,6 +74,7 @@ class LinearExpression(ModuleElement): sage: a - LZ([2, -1, 3], 1) 10*x + 5/3*y - 4*z - 3 """ + def __init__(self, parent, coefficients, constant, check=True): """ Initialize ``self``. @@ -407,8 +408,7 @@ def _richcmp_(self, other, op): sage: x == 'test' False """ - return richcmp((self._coeffs, self._const), - (other._coeffs, other._const), op) + return richcmp((self._coeffs, self._const), (other._coeffs, other._const), op) def evaluate(self, point): """ @@ -437,6 +437,7 @@ def evaluate(self, point): point = self.parent().ambient_module()(point) except TypeError: from sage.matrix.constructor import vector + point = vector(point) return self._coeffs * point + self._const @@ -459,6 +460,7 @@ class LinearExpressionModule(Parent, UniqueRepresentation): sage: L.an_element() x + 0*y + 0*z + 0 """ + Element = LinearExpression def __init__(self, base_ring, names=tuple()): @@ -480,6 +482,7 @@ def __init__(self, base_ring, names=tuple()): sage: TestSuite(L).run() """ from sage.categories.modules import Modules + super().__init__(base_ring, category=Modules(base_ring).WithBasis().FiniteDimensional()) self._names = names @@ -499,10 +502,10 @@ def basis(self): 0*x + 0*y + 0*z + 1] """ from sage.sets.family import Family + gens = self.gens() d = dict(enumerate(gens)) - d['b'] = self.element_class(self, self.ambient_module().zero(), - self.base_ring().one()) + d['b'] = self.element_class(self, self.ambient_module().zero(), self.base_ring().one()) return Family(list(range(len(gens))) + ['b'], lambda i: d[i]) @cached_method @@ -536,6 +539,7 @@ def gens(self) -> tuple: (x + 0*y + 0*z + 0, 0*x + y + 0*z + 0, 0*x + 0*y + z + 0) """ from sage.matrix.constructor import identity_matrix + identity = identity_matrix(self.base_ring(), self.ngens()) return tuple(self(e, 0) for e in identity.rows()) @@ -670,6 +674,7 @@ def ambient_module(self): Vector space of dimension 2 over Rational Field """ from sage.modules.free_module import FreeModule + return FreeModule(self.base_ring(), self.ngens()) @cached_method @@ -699,6 +704,7 @@ def ambient_vector_space(self): Vector space of dimension 2 over Rational Field """ from sage.modules.free_module import VectorSpace + field = self.base_ring().fraction_field() return VectorSpace(field, self.ngens()) @@ -726,8 +732,7 @@ def _coerce_map_from_(self, P): if self.base().has_coerce_map_from(P): return True try: - return self.ngens() == P.ngens() and \ - self.base().has_coerce_map_from(P.base()) + return self.ngens() == P.ngens() and self.base().has_coerce_map_from(P.base()) except AttributeError: pass return super()._coerce_map_from_(P) @@ -744,8 +749,7 @@ def _repr_(self): sage: L. = LinearExpressionModule(QQ); L Module of linear expressions in variable x over Rational Field """ - return 'Module of linear expressions in variable{2} {0} over {1}'.format( - ', '.join(self._names), self.base_ring(), 's' if self.ngens() > 1 else '') + return 'Module of linear expressions in variable{2} {0} over {1}'.format(', '.join(self._names), self.base_ring(), 's' if self.ngens() > 1 else '') def change_ring(self, base_ring): """ diff --git a/src/sage/geometry/newton_polygon.py b/src/sage/geometry/newton_polygon.py index 4bd4c1d0ec1..0f6d06598d9 100644 --- a/src/sage/geometry/newton_polygon.py +++ b/src/sage/geometry/newton_polygon.py @@ -30,6 +30,7 @@ class NewtonPolygon_element(Element): """ Class for infinite Newton polygons with last slope. """ + def __init__(self, polyhedron, parent): """ Initialize a Newton polygon. @@ -147,7 +148,7 @@ def last_slope(self): rays = self._polyhedron.rays() for r in rays: if r[0] > 0: - return r[1]/r[0] + return r[1] / r[0] return Infinity def slopes(self, repetition=True) -> list: @@ -181,9 +182,9 @@ def slopes(self, repetition=True) -> list: slopes = [] vertices = self.vertices(copy=False) for i in range(1, len(vertices)): - dx = vertices[i][0] - vertices[i-1][0] - dy = vertices[i][1] - vertices[i-1][1] - slope = dy/dx + dx = vertices[i][0] - vertices[i - 1][0] + dy = vertices[i][1] - vertices[i - 1][1] + slope = dy / dx if repetition: slopes.extend(dx * [slope]) else: @@ -375,7 +376,7 @@ def __call__(self, x): b = c xg, yg = vertices[a] xd, yd = vertices[b] - return ((x-xg)*yd + (xd-x)*yg) / (xd-xg) + return ((x - xg) * yd + (xd - x) * yg) / (xd - xg) def _richcmp_(self, other, op) -> bool: r""" @@ -464,24 +465,16 @@ def plot(self, **kwargs): vertices = self.vertices() if len(vertices) == 0: from sage.plot.graphics import Graphics + return Graphics() from sage.plot.line import line + xstart, ystart = vertices[0] xend, yend = vertices[-1] if self.last_slope() is Infinity: - return line([(xstart, ystart+1), (xstart, ystart+0.5)], - linestyle='--', **kwargs) \ - + line([(xstart, ystart+0.5)] + vertices - + [(xend, yend+0.5)], **kwargs) \ - + line([(xend, yend+0.5), (xend, yend+1)], - linestyle='--', **kwargs) - return line([(xstart, ystart+1), (xstart, ystart+0.5)], - linestyle='--', **kwargs) \ - + line([(xstart, ystart+0.5)] + vertices - + [(xend+0.5, yend + 0.5*self.last_slope())], **kwargs) \ - + line([(xend+0.5, yend + 0.5*self.last_slope()), (xend+1, yend+self.last_slope())], - linestyle='--', **kwargs) + return line([(xstart, ystart + 1), (xstart, ystart + 0.5)], linestyle='--', **kwargs) + line([(xstart, ystart + 0.5)] + vertices + [(xend, yend + 0.5)], **kwargs) + line([(xend, yend + 0.5), (xend, yend + 1)], linestyle='--', **kwargs) + return line([(xstart, ystart + 1), (xstart, ystart + 0.5)], linestyle='--', **kwargs) + line([(xstart, ystart + 0.5)] + vertices + [(xend + 0.5, yend + 0.5 * self.last_slope())], **kwargs) + line([(xend + 0.5, yend + 0.5 * self.last_slope()), (xend + 1, yend + self.last_slope())], linestyle='--', **kwargs) def reverse(self, degree=None): r""" @@ -519,8 +512,7 @@ def reverse(self, degree=None): vertices = [(degree - x, y) for x, y in self.vertices()] vertices.reverse() parent = self.parent() - polyhedron = Polyhedron(base_ring=parent.base_ring(), - vertices=vertices, rays=[(0, 1)]) + polyhedron = Polyhedron(base_ring=parent.base_ring(), vertices=vertices, rays=[(0, 1)]) return parent(polyhedron) @@ -650,6 +642,7 @@ def __init__(self) -> None: """ from sage.categories.semirings import Semirings from sage.rings.rational_field import QQ + Parent.__init__(self, category=Semirings(), base=QQ) def _repr_(self) -> str: @@ -680,8 +673,7 @@ def _an_element_(self): """ return self(Polyhedron(base_ring=self.base_ring(), ambient_dim=2)) - def _element_constructor_(self, arg, sort_slopes=True, - last_slope=Infinity): + def _element_constructor_(self, arg, sort_slopes=True, last_slope=Infinity): r""" INPUT: @@ -724,15 +716,13 @@ def _element_constructor_(self, arg, sort_slopes=True, polyhedron = Polyhedron(base_ring=self.base_ring(), ambient_dim=2) return self.element_class(polyhedron, parent=self) if arg == 1: - polyhedron = Polyhedron(base_ring=self.base_ring(), - vertices=[(0, 0)], rays=[(0, 1)]) + polyhedron = Polyhedron(base_ring=self.base_ring(), vertices=[(0, 0)], rays=[(0, 1)]) return self.element_class(polyhedron, parent=self) if not isinstance(arg, list): try: arg = list(arg) except TypeError: - raise TypeError("argument must be a list of coordinates " - "or a list of (rational) slopes") + raise TypeError("argument must be a list of coordinates " "or a list of (rational) slopes") if arg and arg[0] in self.base_ring(): if sort_slopes: arg.sort() @@ -740,8 +730,7 @@ def _element_constructor_(self, arg, sort_slopes=True, vertices = [(x, y)] for slope in arg: if slope not in self.base_ring(): - raise TypeError("argument must be a list of coordinates " - "or a list of (rational) slopes") + raise TypeError("argument must be a list of coordinates " "or a list of (rational) slopes") x += 1 y += slope vertices.append((x, y)) @@ -754,8 +743,7 @@ def _element_constructor_(self, arg, sort_slopes=True, rays = [(0, 1)] if last_slope is not Infinity: rays.append((1, last_slope)) - polyhedron = Polyhedron(base_ring=self.base_ring(), - vertices=vertices, rays=rays) + polyhedron = Polyhedron(base_ring=self.base_ring(), vertices=vertices, rays=rays) return self.element_class(polyhedron, parent=self) diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index b43ac2f4639..1143b0593d2 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -267,10 +267,9 @@ class PolyhedralComplex(GenericCellComplex): sage: Q.backend() 'cdd' """ + @rename_keyword(deprecation=41756, is_immutable='immutable') - def __init__(self, maximal_cells=None, backend=None, maximality_check=True, - face_to_face_check=False, immutable=False, - ambient_dim=None) -> None: + def __init__(self, maximal_cells=None, backend=None, maximality_check=True, face_to_face_check=False, immutable=False, ambient_dim=None) -> None: r""" Define a PolyhedralComplex. @@ -288,15 +287,13 @@ def __init__(self, maximal_cells=None, backend=None, maximality_check=True, cells_dict = {} elif isinstance(maximal_cells, (list, tuple)): if backend: - maximal_cells = [p.base_extend(p.base_ring(), backend) - for p in maximal_cells] + maximal_cells = [p.base_extend(p.base_ring(), backend) for p in maximal_cells] cells_dict = cells_list_to_cells_dict(maximal_cells) elif isinstance(maximal_cells, dict): cells_dict = {} for k, l in maximal_cells.items(): if backend: - cells_dict[k] = {p.base_extend(p.base_ring(), backend) - for p in l} + cells_dict[k] = {p.base_extend(p.base_ring(), backend) for p in l} else: cells_dict[k] = set(l) else: @@ -311,32 +308,27 @@ def __init__(self, maximal_cells=None, backend=None, maximality_check=True, ambient_dim = next(iter(cells_dict[self._dim])).ambient_dim() self._ambient_dim = ambient_dim self._maximal_cells = cells_dict - if not all((isinstance(cell, sage.geometry.abc.Polyhedron) and - cell.ambient_dim() == self._ambient_dim) - for cell in self.maximal_cell_iterator()): - raise ValueError("the given cells are not polyhedra " + - "in the same ambient space") + if not all((isinstance(cell, sage.geometry.abc.Polyhedron) and cell.ambient_dim() == self._ambient_dim) for cell in self.maximal_cell_iterator()): + raise ValueError("the given cells are not polyhedra " + "in the same ambient space") # initialize the attributes self._is_convex = None self._polyhedron = None - self._maximal_cells_sorted = None # needed for hash + self._maximal_cells_sorted = None # needed for hash self._cells = None self._face_poset = None if maximality_check: - self.cells() # compute self._cells and self._face_poset - self._maximal_cells = cells_list_to_cells_dict( - self._face_poset.maximal_elements()) + self.cells() # compute self._cells and self._face_poset + self._maximal_cells = cells_list_to_cells_dict(self._face_poset.maximal_elements()) if face_to_face_check: poset = self.face_poset() - maximal_cells = poset.maximal_elements() # a list + maximal_cells = poset.maximal_elements() # a list for i in range(len(maximal_cells)): p = maximal_cells[i] for j in range(i, len(maximal_cells)): q = maximal_cells[j] r = p.intersection(q) - if not (r.is_empty() or (r in poset) and - poset.is_gequal(p, r) and poset.is_gequal(q, r)): + if not (r.is_empty() or (r in poset) and poset.is_gequal(p, r) and poset.is_gequal(q, r)): raise ValueError("the given cells are not face-to-face") self._is_immutable = False if immutable: @@ -382,9 +374,9 @@ def cells(self, subcomplex=None) -> dict: if p not in covers: covers[p] = [] covers[p].append(cell) - if (k-1) not in cells: - cells[k-1] = set() - cells[k-1].add(p) + if (k - 1) not in cells: + cells[k - 1] = set() + cells[k - 1].add(p) self._face_poset = Poset(covers) self._cells = cells return self._cells @@ -445,8 +437,7 @@ def _n_cells_sorted(self, n, subcomplex=None) -> list: [] """ n_cells = self.n_cells(n, subcomplex) - return sorted(n_cells, - key=lambda p: (p.vertices(), p.rays(), p.lines())) + return sorted(n_cells, key=lambda p: (p.vertices(), p.rays(), p.lines())) def cells_sorted(self, subcomplex=None) -> list: """ @@ -610,8 +601,7 @@ def _n_maximal_cells_sorted(self, n) -> list: [[0, 0], [0, 2], [1, 2]] """ n_maximal_cells = self.n_maximal_cells(n) - return sorted(n_maximal_cells, - key=lambda p: (p.vertices(), p.rays(), p.lines())) + return sorted(n_maximal_cells, key=lambda p: (p.vertices(), p.rays(), p.lines())) def maximal_cells_sorted(self) -> list: """ @@ -788,8 +778,7 @@ def plot(self, **kwds): polyhedra = self.maximal_cell_iterator() if color == 'rainbow': polyhedra = list(polyhedra) - cell_colors_dict = dict(zip(polyhedra, - rainbow(len(polyhedra)))) + cell_colors_dict = dict(zip(polyhedra, rainbow(len(polyhedra)))) g = Graphics() for cell in polyhedra: options = copy(kwds) @@ -868,8 +857,7 @@ def __hash__(self) -> int: ValueError: this polyhedral complex must be immutable; call set_immutable() """ if not self._is_immutable: - raise ValueError("this polyhedral complex must be immutable; " + - "call set_immutable()") + raise ValueError("this polyhedral complex must be immutable; " + "call set_immutable()") return hash(tuple(self.maximal_cells_sorted())) def __eq__(self, right) -> bool: @@ -887,8 +875,7 @@ def __eq__(self, right) -> bool: sage: pc1 == pc2 True """ - return isinstance(right, PolyhedralComplex) and ( - self.maximal_cells_sorted() == right.maximal_cells_sorted()) + return isinstance(right, PolyhedralComplex) and (self.maximal_cells_sorted() == right.maximal_cells_sorted()) def __ne__(self, right) -> bool: """ @@ -916,8 +903,7 @@ def __copy__(self): sage: pc1 == pc2 True """ - return PolyhedralComplex(self._maximal_cells, maximality_check=False, - backend=self._backend) + return PolyhedralComplex(self._maximal_cells, maximality_check=False, backend=self._backend) def _an_element_(self): """ @@ -942,6 +928,7 @@ def _an_element_(self): return next(self.maximal_cell_iterator(increasing=False)) except StopIteration: from sage.categories.sets_cat import EmptySetError + raise EmptySetError("the complex is empty") def __contains__(self, x) -> bool: @@ -1029,7 +1016,7 @@ def face_poset(self): Finite poset containing 9 elements """ if self._face_poset is None: - self.cells() # poset is obtained and cached in cells() + self.cells() # poset is obtained and cached in cells() return self._face_poset def is_subcomplex(self, other) -> bool: @@ -1055,7 +1042,7 @@ def is_subcomplex(self, other) -> bool: False """ other_cells = other.cells() - for (d, stratum) in self.maximal_cells().items(): + for d, stratum in self.maximal_cells().items(): if not stratum.issubset(other_cells.get(d, set())): return False return True @@ -1174,7 +1161,7 @@ def is_connected(self) -> bool: True """ if self.is_compact(): - return self.graph().is_connected() # faster than using poset? + return self.graph().is_connected() # faster than using poset? return self.face_poset().is_connected() def connected_component(self, cell=None): @@ -1238,34 +1225,25 @@ def connected_component(self, cell=None): ValueError: the empty polyhedral complex has no connected components """ if self.dimension() == -1: - raise ValueError( - "the empty polyhedral complex has no connected components") + raise ValueError("the empty polyhedral complex has no connected components") if cell is None: cell = self._an_element_() - if self.is_compact(): # use graph (faster than poset?) + if self.is_compact(): # use graph (faster than poset?) if not cell.is_compact(): - raise ValueError( - "the polyhedral complex does not contain the given cell") + raise ValueError("the polyhedral complex does not contain the given cell") v = cell.vertices_matrix().columns()[0] g = self.graph() if v not in g: - raise ValueError( - "the polyhedral complex does not contain the given cell") + raise ValueError("the polyhedral complex does not contain the given cell") vertices = g.connected_component_containing_vertex(v, sort=False) - facets = [f for f in self.maximal_cell_iterator() - if any(vf in f.vertices_matrix().columns() - for vf in vertices)] - else: # use face_poset + facets = [f for f in self.maximal_cell_iterator() if any(vf in f.vertices_matrix().columns() for vf in vertices)] + else: # use face_poset g = self.face_poset().hasse_diagram() if cell not in g: - raise ValueError( - "the polyhedral complex does not contain the given cell") + raise ValueError("the polyhedral complex does not contain the given cell") faces = g.connected_component_containing_vertex(cell, sort=False) - facets = [f for f in self.maximal_cell_iterator() - if f in faces] - return PolyhedralComplex(facets, maximality_check=False, - immutable=self._is_immutable, - backend=self._backend) + facets = [f for f in self.maximal_cell_iterator() if f in faces] + return PolyhedralComplex(facets, maximality_check=False, immutable=self._is_immutable, backend=self._backend) def connected_components(self) -> list: """ @@ -1303,25 +1281,16 @@ def connected_components(self) -> list: ValueError: the empty polyhedral complex has no connected components """ if self.dimension() == -1: - raise ValueError( - "the empty polyhedral complex has no connected components") - if self.is_compact(): # use graph (faster than poset)? + raise ValueError("the empty polyhedral complex has no connected components") + if self.is_compact(): # use graph (faster than poset)? g = self.graph() lists_of_vertices = g.connected_components(sort=False) - lists_of_facets = [[f for f in self.maximal_cell_iterator() - if any(vf in f.vertices_matrix().columns() - for vf in vertices)] - for vertices in lists_of_vertices] - else: # use face_poset + lists_of_facets = [[f for f in self.maximal_cell_iterator() if any(vf in f.vertices_matrix().columns() for vf in vertices)] for vertices in lists_of_vertices] + else: # use face_poset g = self.face_poset().hasse_diagram() lists_of_faces = g.connected_components(sort=False) - lists_of_facets = [ - [f for f in self.maximal_cell_iterator() if f in faces] - for faces in lists_of_faces] - return [PolyhedralComplex(facets, maximality_check=False, - immutable=self._is_immutable, - backend=self._backend) - for facets in lists_of_facets] + lists_of_facets = [[f for f in self.maximal_cell_iterator() if f in faces] for faces in lists_of_faces] + return [PolyhedralComplex(facets, maximality_check=False, immutable=self._is_immutable, backend=self._backend) for facets in lists_of_facets] def n_skeleton(self, n): r""" @@ -1354,9 +1323,7 @@ def n_skeleton(self, n): return copy(self) facets = [f for f in self.maximal_cell_iterator() if f.dimension() < n] facets.extend(self.n_cells(n)) - return PolyhedralComplex(facets, maximality_check=False, - immutable=self._is_immutable, - backend=self._backend) + return PolyhedralComplex(facets, maximality_check=False, immutable=self._is_immutable, backend=self._backend) def stratify(self, n): r""" @@ -1391,9 +1358,7 @@ def stratify(self, n): Polyhedral complex with 1 maximal cell """ n_faces = self.n_maximal_cells(n) - return PolyhedralComplex(n_faces, maximality_check=False, - immutable=self._is_immutable, - backend=self._backend) + return PolyhedralComplex(n_faces, maximality_check=False, immutable=self._is_immutable, backend=self._backend) def boundary_subcomplex(self): """ @@ -1450,9 +1415,7 @@ def boundary_subcomplex(self): False """ if self.is_full_dimensional(): - return PolyhedralComplex(self.relative_boundary_cells(), - immutable=self._is_immutable, - backend=self._backend) + return PolyhedralComplex(self.relative_boundary_cells(), immutable=self._is_immutable, backend=self._backend) ans = copy(self) if self._is_immutable: ans.set_immutable() @@ -1597,6 +1560,7 @@ def is_convex(self) -> bool: if not self.is_full_dimensional(): # if max cells must lie in different subspaces, can't be convex. from sage.modules.free_module import span + f = self.n_maximal_cells(d)[0] affine_space = span(f.equations_list(), f.base_ring()) for f in self.n_maximal_cells(d)[1::]: @@ -1655,8 +1619,7 @@ def is_convex(self) -> bool: return False # lines are in the affine space of each boundary cell already self._is_convex = True - self._polyhedron = Polyhedron(vertices=vertices, rays=rays, lines=lines, - backend=self._backend) + self._polyhedron = Polyhedron(vertices=vertices, rays=rays, lines=lines, backend=self._backend) return True def union_as_polyhedron(self): @@ -1702,12 +1665,8 @@ def product(self, right): A vertex at (1, 0), A vertex at (1, 1)) """ - maximal_cells = [f.product(g) for f in self.maximal_cell_iterator() - for g in right.maximal_cell_iterator()] - return PolyhedralComplex(maximal_cells, maximality_check=False, - immutable=(self._is_immutable and - right._is_immutable), - backend=self._backend) + maximal_cells = [f.product(g) for f in self.maximal_cell_iterator() for g in right.maximal_cell_iterator()] + return PolyhedralComplex(maximal_cells, maximality_check=False, immutable=(self._is_immutable and right._is_immutable), backend=self._backend) def disjoint_union(self, right): """ @@ -1736,12 +1695,7 @@ def disjoint_union(self, right): for cell_right in maximal_cells_right: if not cell.intersection(cell_right).is_empty(): raise ValueError("the two complexes are not disjoint") - return PolyhedralComplex(maximal_cells_self + maximal_cells_right, - maximality_check=False, - face_to_face_check=False, - immutable=(self._is_immutable and - right._is_immutable), - backend=self._backend) + return PolyhedralComplex(maximal_cells_self + maximal_cells_right, maximality_check=False, face_to_face_check=False, immutable=(self._is_immutable and right._is_immutable), backend=self._backend) def union(self, right): """ @@ -1767,13 +1721,8 @@ def union(self, right): ... ValueError: the given cells are not face-to-face """ - maximal_cells = list(self.maximal_cell_iterator()) + list( - right.maximal_cell_iterator()) - return PolyhedralComplex(maximal_cells, maximality_check=True, - face_to_face_check=True, - immutable=(self._is_immutable and - right._is_immutable), - backend=self._backend) + maximal_cells = list(self.maximal_cell_iterator()) + list(right.maximal_cell_iterator()) + return PolyhedralComplex(maximal_cells, maximality_check=True, face_to_face_check=True, immutable=(self._is_immutable and right._is_immutable), backend=self._backend) def join(self, right): """ @@ -1795,12 +1744,8 @@ def join(self, right): A vertex at (0, 1, 1), A vertex at (1, 0, 0)) """ - maximal_cells = [f.join(g) for f in self.maximal_cell_iterator() - for g in right.maximal_cell_iterator()] - return PolyhedralComplex(maximal_cells, maximality_check=False, - immutable=(self._is_immutable and - right._is_immutable), - backend=self._backend) + maximal_cells = [f.join(g) for f in self.maximal_cell_iterator() for g in right.maximal_cell_iterator()] + return PolyhedralComplex(maximal_cells, maximality_check=False, immutable=(self._is_immutable and right._is_immutable), backend=self._backend) ############################################################ # abstract methods not implemented in generic cell complex @@ -1822,15 +1767,12 @@ def wedge(self, right): ... NotImplementedError: wedge is not implemented for polyhedral complex """ - raise NotImplementedError("wedge is not implemented for " - + "polyhedral complex") + raise NotImplementedError("wedge is not implemented for " + "polyhedral complex") ############################################################ # chain complexes, homology ############################################################ - def chain_complex(self, subcomplex=None, augmented=False, - verbose=False, check=True, dimensions=None, - base_ring=ZZ, cochain=False): + def chain_complex(self, subcomplex=None, augmented=False, verbose=False, check=True, dimensions=None, base_ring=ZZ, cochain=False): """ The chain complex associated to this polyhedral complex. @@ -1846,8 +1788,7 @@ def chain_complex(self, subcomplex=None, augmented=False, ... NotImplementedError: chain_complex is not implemented for polyhedral complex """ - raise NotImplementedError("chain_complex is not implemented for " - + "polyhedral complex") + raise NotImplementedError("chain_complex is not implemented for " + "polyhedral complex") def alexander_whitney(self, cell, dim_left): """ @@ -1866,8 +1807,7 @@ def alexander_whitney(self, cell, dim_left): ... NotImplementedError: alexander_whitney is not implemented for polyhedral complex """ - raise NotImplementedError("alexander_whitney is not implemented for " - + "polyhedral complex") + raise NotImplementedError("alexander_whitney is not implemented for " + "polyhedral complex") ############################################################ # end of chain complexes, homology @@ -2043,8 +1983,7 @@ def add_cell(self, cell): if self._is_immutable: raise ValueError("this polyhedral complex is not mutable") if not isinstance(cell, sage.geometry.abc.Polyhedron) or cell.ambient_dim() != self._ambient_dim: - raise ValueError("the given cell is not a polyhedron " + - "in the same ambient space") + raise ValueError("the given cell is not a polyhedron " + "in the same ambient space") # if cell is already in self, do nothing. if self.is_cell(cell): return @@ -2052,8 +1991,7 @@ def add_cell(self, cell): cell = cell.base_extend(cell.base_ring(), self._backend) # update cells and face poset cells = self.cells() - covers = {p: self.face_poset().upper_covers(p) - for p in self.cell_iterator()} + covers = {p: self.face_poset().upper_covers(p) for p in self.cell_iterator()} d = cell.dimension() d_cells = [cell] if d not in cells: @@ -2081,19 +2019,17 @@ def add_cell(self, cell): # check face-to-face between cell and previous maximal cells for p in self.maximal_cell_iterator(): r = p.intersection(cell) - if not (r.is_empty() or (r in poset) and - poset.is_gequal(p, r) and poset.is_gequal(cell, r)): + if not (r.is_empty() or (r in poset) and poset.is_gequal(p, r) and poset.is_gequal(cell, r)): raise ValueError("the cell is not face-to-face with complex") # update dim and maximal cells d = cell.dimension() self._dim = max(d, self._dim) - maximal_cells = poset.maximal_elements() # a list + maximal_cells = poset.maximal_elements() # a list self._maximal_cells = cells_list_to_cells_dict(maximal_cells) # update convexity if self was known to be convex, reset otherwise. if self._is_convex: try: - new_complex = PolyhedralComplex([self._polyhedron, cell], - face_to_face_check=True) + new_complex = PolyhedralComplex([self._polyhedron, cell], face_to_face_check=True) except ValueError: self._is_convex = False self._polyhedron = None @@ -2104,7 +2040,7 @@ def add_cell(self, cell): self._is_convex = None self._polyhedron = None # reset cached attribute - self._maximal_cells_sorted = None # needed for hash + self._maximal_cells_sorted = None # needed for hash def remove_cell(self, cell, check=False): r""" @@ -2205,13 +2141,11 @@ def remove_cell(self, cell, check=False): if self._is_immutable: raise ValueError("this polyhedral complex is not mutable") if not isinstance(cell, sage.geometry.abc.Polyhedron) or cell.ambient_dim() != self._ambient_dim: - raise ValueError("the given cell is not a polyhedron " + - "in the same ambient space") + raise ValueError("the given cell is not a polyhedron " + "in the same ambient space") # if cell is not in self, delete nothing. - if not self.is_cell(cell): # self.cells() is called + if not self.is_cell(cell): # self.cells() is called if check: - raise ValueError("trying to remove a cell which is not " + - "in the polyhedral complex") + raise ValueError("trying to remove a cell which is not " + "in the polyhedral complex") return # update cells and face poset poset = self._face_poset @@ -2221,18 +2155,17 @@ def remove_cell(self, cell, check=False): self._cells[d].remove(c) if not self._cells[d]: del self._cells[d] - covers = {p: [q for q in poset.upper_covers(p) if q not in deleting] - for p in self.cell_iterator()} + covers = {p: [q for q in poset.upper_covers(p) if q not in deleting] for p in self.cell_iterator()} self._face_poset = Poset(covers) # update dim and maximal cells - maximal_cells = self._face_poset.maximal_elements() # a list + maximal_cells = self._face_poset.maximal_elements() # a list self._maximal_cells = cells_list_to_cells_dict(maximal_cells) if not maximal_cells: self._dim = -1 else: self._dim = max(self._maximal_cells.keys()) # reset cached attributes - self._maximal_cells_sorted = None # needed for hash + self._maximal_cells_sorted = None # needed for hash self._is_convex = None self._polyhedron = None @@ -2274,9 +2207,7 @@ def is_polyhedral_fan(self) -> bool: sage: PolyhedralComplex([halfplane]).is_polyhedral_fan() True """ - return all((p.n_vertices() == 1) and ( - vector(p.vertices_list()[0]) == p.ambient_space().zero()) - for p in self.maximal_cell_iterator()) + return all((p.n_vertices() == 1) and (vector(p.vertices_list()[0]) == p.ambient_space().zero()) for p in self.maximal_cell_iterator()) def is_simplicial_fan(self) -> bool: """ @@ -2299,12 +2230,9 @@ def is_simplicial_fan(self) -> bool: sage: PolyhedralComplex([halfplane]).is_simplicial_fan() False """ - return self.is_polyhedral_fan() and all( - (p.n_lines() == 0 and p.n_rays() == p.dimension()) - for p in self.maximal_cell_iterator()) + return self.is_polyhedral_fan() and all((p.n_lines() == 0 and p.n_rays() == p.dimension()) for p in self.maximal_cell_iterator()) - def subdivide(self, make_simplicial=False, - new_vertices=None, new_rays=None): + def subdivide(self, make_simplicial=False, new_vertices=None, new_rays=None): """ Construct a new polyhedral complex by iterative stellar subdivision of ``self`` for each new vertex/ray given. @@ -2380,7 +2308,7 @@ def subdivide(self, make_simplicial=False, for v in new_vertices: vertices.add(tuple(v)) if not vertices: - return self # Nothing has to be done + return self # Nothing has to be done # bounded version of `fan._subdivide_stellar`; not require rational. cells = list(self.maximal_cell_iterator()) for v in vertices: @@ -2396,8 +2324,7 @@ def subdivide(self, make_simplicial=False, else: new.append(cell) cells = new - return PolyhedralComplex(cells, maximality_check=False, - backend=self._backend) + return PolyhedralComplex(cells, maximality_check=False, backend=self._backend) if self.is_polyhedral_fan(): if new_vertices and any(vi != 0 for v in new_vertices for vi in v): raise ValueError("new vertices cannot be used for subdivision") @@ -2434,10 +2361,8 @@ def subdivide(self, make_simplicial=False, # we rely on the canonical V-repr of Sage polyhedra. num_lines = len(plines) for neg_rays in powerset(range(num_lines)): - lines = [vector(plines[i]) if i not in neg_rays - else -vector(plines[i]) for i in range(num_lines)] - cones.append(Polyhedron(rays=(prays + lines), - backend=self._backend)) + lines = [vector(plines[i]) if i not in neg_rays else -vector(plines[i]) for i in range(num_lines)] + cones.append(Polyhedron(rays=(prays + lines), backend=self._backend)) rays = [] if new_rays: for r in new_rays: @@ -2451,7 +2376,7 @@ def subdivide(self, make_simplicial=False, if make_simplicial and not self.is_simplicial_fan(): rays = self_rays + rays if not rays: - return self # Nothing has to be done + return self # Nothing has to be done # mimic :class:`RationalPolyhedralFan`._subdivide_stellar(rays) # start with self maximal cells (subdivided into pointed cones) for ray in rays: @@ -2467,14 +2392,13 @@ def subdivide(self, make_simplicial=False, else: new.append(cone) cones = new - return PolyhedralComplex(cones, maximality_check=False, - backend=self._backend) + return PolyhedralComplex(cones, maximality_check=False, backend=self._backend) # TODO: ``self`` is unbounded, make it projectively simplicial. # (1) homogenize self of dim d to fan in space of dim d+1; # (2) call fan.subdivide(make_simplicial=True); # (3) take section back to the space of dim d. - raise NotImplementedError('subdivision of a non-compact polyhedral ' + - 'complex that is not a fan is not supported') + raise NotImplementedError('subdivision of a non-compact polyhedral ' + 'complex that is not a fan is not supported') + ############################################################ # Helper functions @@ -2509,9 +2433,7 @@ def cells_list_to_cells_dict(cells_list) -> dict: return cells_dict -def exploded_plot(polyhedra, *, - center=None, explosion_factor=1, sticky_vertices=False, - sticky_center=True, point=None, **kwds): +def exploded_plot(polyhedra, *, center=None, explosion_factor=1, sticky_vertices=False, sticky_center=True, point=None, **kwds): r""" Return a plot of several ``polyhedra`` in one figure with extra space between them. @@ -2569,13 +2491,11 @@ def exploded_plot(polyhedra, *, dim = polyhedra[0].ambient_dimension() if center is None: from sage.rings.rational_field import QQ + center = vector(QQ, dim) else: center = vector(center) - translations = [explosion_factor * ((p.center() - + sum(r.vector() for r in p.rays())) - - center) - for p in polyhedra] + translations = [explosion_factor * ((p.center() + sum(r.vector() for r in p.rays())) - center) for p in polyhedra] vertex_translations_dict = {} for P, t in zip(polyhedra, translations): for v in P.vertices(): @@ -2586,8 +2506,7 @@ def exploded_plot(polyhedra, *, color = kwds.get('color') if color == 'rainbow': - cell_colors_dict = dict(zip(polyhedra, - rainbow(len(polyhedra)))) + cell_colors_dict = dict(zip(polyhedra, rainbow(len(polyhedra)))) for p, t in zip(polyhedra, translations): options = copy(kwds) if color == 'rainbow': @@ -2613,8 +2532,7 @@ def exploded_plot(polyhedra, *, point = dict(size=10) if point is not False: if color == 'rainbow': - vertex_colors_dict = dict(zip(vertex_translations_dict.keys(), - rainbow(len(vertex_translations_dict.keys())))) + vertex_colors_dict = dict(zip(vertex_translations_dict.keys(), rainbow(len(vertex_translations_dict.keys())))) for vertex, vertex_translations in vertex_translations_dict.items(): options = copy(point) if color == 'rainbow': diff --git a/src/sage/geometry/polyhedron/all.py b/src/sage/geometry/polyhedron/all.py index cda722f4d6b..bf2913468dc 100644 --- a/src/sage/geometry/polyhedron/all.py +++ b/src/sage/geometry/polyhedron/all.py @@ -1,7 +1,6 @@ - from sage.misc.lazy_import import lazy_import + lazy_import('sage.geometry.polyhedron.constructor', 'Polyhedron') lazy_import('sage.geometry.polyhedron.library', 'polytopes') -lazy_import('sage.geometry.polyhedron.combinatorial_polyhedron.base', - 'CombinatorialPolyhedron') +lazy_import('sage.geometry.polyhedron.combinatorial_polyhedron.base', 'CombinatorialPolyhedron') del lazy_import diff --git a/src/sage/geometry/polyhedron/backend_cdd.py b/src/sage/geometry/polyhedron/backend_cdd.py index 07abff41d80..0d2574f1e93 100644 --- a/src/sage/geometry/polyhedron/backend_cdd.py +++ b/src/sage/geometry/polyhedron/backend_cdd.py @@ -1,6 +1,7 @@ r""" The cdd backend for polyhedral computations """ + # **************************************************************************** # Copyright (C) 2011-2014 Volker Braun # 2018 Timo Kaufmann @@ -27,6 +28,7 @@ class Polyhedron_cdd(Polyhedron_base): r""" Base class for the cdd backend. """ + def _init_from_Vrepresentation(self, vertices, rays, lines, verbose=False): """ Construct polyhedron from V-representation data. @@ -56,6 +58,7 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, verbose=False): convex hull of 1 vertex, 1 ray, 1 line """ from .cdd_file_format import cdd_Vrepresentation + s = cdd_Vrepresentation(self._cdd_type, vertices, rays, lines) s = self._run_cdd(s, '--redcheck', verbose=verbose) s = self._run_cdd(s, '--repall', verbose=verbose) @@ -64,7 +67,7 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, verbose=False): # cdd's parser cannot handle the full output of --repall, so we # need to extract the first block before we feed it back into cdd s = s.splitlines() - s = s[:s.index('end')+1] + s = s[: s.index('end') + 1] s = '\n'.join(s) t = self._run_cdd(s, '--rep', verbose=verbose) @@ -80,7 +83,9 @@ def parse(intro, data): # expert in that field by any means.) See also # https://github.com/cddlib/cddlib/pull/7. from warnings import warn + warn("This polyhedron data is numerically complicated; cdd could not convert between the inexact V and H representation without loss of data. The resulting object might show inconsistencies.") + Polyhedron_cdd._parse_block(t.splitlines(), 'V-representation', parse) def _init_from_Hrepresentation(self, ieqs, eqns, verbose=False): @@ -116,6 +121,7 @@ def _init_from_Hrepresentation(self, ieqs, eqns, verbose=False): A 5-dimensional polyhedron in QQ^5 defined as the convex hull of 1 vertex and 5 lines """ from .cdd_file_format import cdd_Hrepresentation + # We have to add a trivial inequality, in case the polyhedron is the universe. ieqs = tuple(ieqs) + ((1,) + tuple(0 for _ in range(self.ambient_dim())),) s = cdd_Hrepresentation(self._cdd_type, ieqs, eqns) @@ -130,7 +136,7 @@ def _init_from_Hrepresentation(self, ieqs, eqns, verbose=False): # cdd's parser cannot handle the full output of --repall, so we # need to extract the first block before we feed it back into cdd s = s.splitlines() - s = s[:s.index('end')+1] + s = s[: s.index('end') + 1] s = '\n'.join(s) t = self._run_cdd(s, '--rep', verbose=verbose) @@ -146,7 +152,9 @@ def parse(intro, data): # somewhat random numerical choices. (But I am not an # expert in that field by any means.) from warnings import warn + warn("This polyhedron data is numerically complicated; cdd could not convert between the inexact V and H representation without loss of data. The resulting object might show inconsistencies.") + Polyhedron_cdd._parse_block(t.splitlines(), 'H-representation', parse) def _run_cdd(self, cdd_input_string, cmdline_arg, verbose=False): @@ -154,9 +162,7 @@ def _run_cdd(self, cdd_input_string, cmdline_arg, verbose=False): print('---- CDD input -----') print(cdd_input_string) - cdd_proc = Popen([CddExecutable(self._cdd_executable).absolute_filename(), cmdline_arg], - stdin=PIPE, stdout=PIPE, stderr=PIPE, - encoding='latin-1') + cdd_proc = Popen([CddExecutable(self._cdd_executable).absolute_filename(), cmdline_arg], stdin=PIPE, stdout=PIPE, stderr=PIPE, encoding='latin-1') ans, err = cdd_proc.communicate(input=cdd_input_string) if verbose: @@ -195,14 +201,14 @@ def _parse_block(cls, cddout, header, parser): DATA: [['data', '0', '1', '2'], ['data', '3', '4', '5']] """ try: - block = cddout[cddout.index(header)+1:] + block = cddout[cddout.index(header) + 1 :] except ValueError: # section is missing in the cdd output return - intro = block[:block.index('begin')] + intro = block[: block.index('begin')] intro = [i.strip().split() for i in intro] - data = block[block.index('begin')+1:block.index('end')] + data = block[block.index('begin') + 1 : block.index('end')] data = [d.strip().split() for d in data] parser(intro, data) @@ -258,7 +264,7 @@ def _init_from_cdd_output(self, cddout): def parse_indices(count, cdd_indices, cdd_indices_to_sage_indices=None): cdd_indices = [int(x) for x in cdd_indices] if cdd_indices_to_sage_indices is None: - cdd_indices_to_sage_indices = {i: i-1 for i in cdd_indices} + cdd_indices_to_sage_indices = {i: i - 1 for i in cdd_indices} if count < 0: assert cdd_indices_to_sage_indices is not None, "Did not expect negative counts here" count = -count @@ -286,19 +292,18 @@ def parse_H_representation(intro, data): assert len(data) == count, "Unexpected number of lines" R = self.base_ring() from itertools import chain + # We add equations to the end of the Hrepresentation. - for i in chain( - (j for j in range(len(data)) if j not in equations), - equations): + for i in chain((j for j in range(len(data)) if j not in equations), equations): line = data[i] coefficients = [R(x) for x in line] if coefficients[0] != 0 and all(e == 0 for e in coefficients[1:]): # cddlib sometimes includes an implicit plane at infinity: 1 0 0 ... 0 # We do not care about this entry. - self._cdd_H_to_sage_H[i+1] = None + self._cdd_H_to_sage_H[i + 1] = None continue - self._cdd_H_to_sage_H[i+1] = len(self._Hrepresentation) + self._cdd_H_to_sage_H[i + 1] = len(self._Hrepresentation) if i in equations: self.parent()._make_Equation(self, coefficients) else: @@ -321,7 +326,7 @@ def parse_V_representation(intro, data): for i, line in enumerate(data): kind = line.pop(0) coefficients = map(self.base_ring(), line) - self._cdd_V_to_sage_V[i+1] = len(self._Vrepresentation) + self._cdd_V_to_sage_V[i + 1] = len(self._Vrepresentation) if i in lines: self.parent()._make_Line(self, coefficients) elif kind == '0': @@ -374,9 +379,9 @@ def parse_vertex_adjacency(intro, data): # we disagree, they are adjacent to everything. if v.is_line(): for j in range(len(self._Vrepresentation)): - self._V_adjacency_matrix[i ,j] = 1 + self._V_adjacency_matrix[i, j] = 1 self._V_adjacency_matrix[j, i] = 1 - self._V_adjacency_matrix[i,i] = 0 + self._V_adjacency_matrix[i, i] = 0 self._V_adjacency_matrix.set_immutable() self.vertex_adjacency_matrix.set_cache(self._V_adjacency_matrix) diff --git a/src/sage/geometry/polyhedron/backend_cdd_rdf.py b/src/sage/geometry/polyhedron/backend_cdd_rdf.py index 0f8e8b35da9..6dbdb60441c 100644 --- a/src/sage/geometry/polyhedron/backend_cdd_rdf.py +++ b/src/sage/geometry/polyhedron/backend_cdd_rdf.py @@ -79,6 +79,7 @@ class Polyhedron_RDF_cdd(Polyhedron_cdd, Polyhedron_RDF): sage: Polyhedron(vertices=[], backend='cdd', base_ring=RDF) The empty polyhedron in RDF^0 """ + _cdd_type = 'real' _cdd_executable = 'cddexec' @@ -158,6 +159,7 @@ def _init_from_Vrepresentation_and_Hrepresentation(self, Vrep, Hrep, verbose=Fal sage: P1*P2 The empty polyhedron in RDF^2 """ + def parse_Vrep(intro, data): count = int(data[0][0]) if count != len(vertices) + len(rays) + len(lines): @@ -170,6 +172,7 @@ def parse_Vrep(intro, data): # expert in that field by any means.) See also # https://github.com/cddlib/cddlib/pull/7. from warnings import warn + warn("This polyhedron data is numerically complicated; cdd could not convert between the inexact V and H representation without loss of data. The resulting object might show inconsistencies.") def parse_Hrep(intro, data): @@ -184,17 +187,20 @@ def parse_Hrep(intro, data): # somewhat random numerical choices. (But I am not an # expert in that field by any means.) from warnings import warn + warn("This polyhedron data is numerically complicated; cdd could not convert between the inexact V and H representation without loss of data. The resulting object might show inconsistencies.") def try_init(rep): if rep == "Vrep": from .cdd_file_format import cdd_Vrepresentation + s = cdd_Vrepresentation(self._cdd_type, vertices, rays, lines) else: # We have to add a trivial inequality, in case the polyhedron is the universe. new_ieqs = ieqs + ((1,) + tuple(0 for _ in range(self.ambient_dim())),) from .cdd_file_format import cdd_Hrepresentation + s = cdd_Hrepresentation(self._cdd_type, new_ieqs, eqns) s = self._run_cdd(s, '--redcheck', verbose=verbose) diff --git a/src/sage/geometry/polyhedron/backend_field.py b/src/sage/geometry/polyhedron/backend_field.py index de2531bb157..0c4e087e94e 100644 --- a/src/sage/geometry/polyhedron/backend_field.py +++ b/src/sage/geometry/polyhedron/backend_field.py @@ -20,7 +20,8 @@ An inequality (1, -0.5773502691896258?) x + 0 >= 0, An inequality (0, 1.154700538379252?) x + 0 >= 0) """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2014 Volker Braun # # This program is free software: you can redistribute it and/or modify @@ -28,7 +29,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from .base import Polyhedron_base @@ -71,6 +72,7 @@ class Polyhedron_field(Polyhedron_base): sage: Polyhedron(lines=[[1]], backend='field') A 1-dimensional polyhedron in QQ^1 defined as the convex hull of 1 vertex and 1 line """ + def _is_zero(self, x): """ Test whether ``x`` is zero. @@ -157,9 +159,7 @@ def _init_from_Vrepresentation_and_Hrepresentation(self, Vrep, Hrep): self._init_Vrepresentation(*Vrep) self._init_Hrepresentation(*Hrep) - def _init_from_Vrepresentation(self, vertices, rays, lines, - minimize=True, verbose=False, - internal_base_ring=None): + def _init_from_Vrepresentation(self, vertices, rays, lines, minimize=True, verbose=False, internal_base_ring=None): """ Construct polyhedron from V-representation data. @@ -190,15 +190,13 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, if internal_base_ring is None: internal_base_ring = self.base_ring() from sage.geometry.polyhedron.double_description_inhomogeneous import Hrep2Vrep, Vrep2Hrep + H = Vrep2Hrep(internal_base_ring, self.ambient_dim(), vertices, rays, lines) - V = Hrep2Vrep(internal_base_ring, self.ambient_dim(), - H.inequalities, H.equations) + V = Hrep2Vrep(internal_base_ring, self.ambient_dim(), H.inequalities, H.equations) self._init_Vrepresentation_backend(V) self._init_Hrepresentation_backend(H) - def _init_from_Hrepresentation(self, ieqs, eqns, - minimize=True, verbose=False, - internal_base_ring=None): + def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False, internal_base_ring=None): """ Construct polyhedron from H-representation data. @@ -226,9 +224,9 @@ def _init_from_Hrepresentation(self, ieqs, eqns, if internal_base_ring is None: internal_base_ring = self.base_ring() from sage.geometry.polyhedron.double_description_inhomogeneous import Hrep2Vrep, Vrep2Hrep + V = Hrep2Vrep(internal_base_ring, self.ambient_dim(), ieqs, eqns) - H = Vrep2Hrep(internal_base_ring, self.ambient_dim(), - V.vertices, V.rays, V.lines) + H = Vrep2Hrep(internal_base_ring, self.ambient_dim(), V.vertices, V.rays, V.lines) self._init_Vrepresentation_backend(V) self._init_Hrepresentation_backend(H) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index 5b60218d339..f1a09c0483e 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -35,8 +35,8 @@ from sage.misc.misc_c import prod from sage.misc.lazy_import import lazy_import import sage.features.normaliz -lazy_import('PyNormaliz', ['NmzResult', 'NmzCompute', 'NmzCone', 'NmzConeCopy'], - feature=sage.features.normaliz.PyNormaliz()) + +lazy_import('PyNormaliz', ['NmzResult', 'NmzCompute', 'NmzCone', 'NmzConeCopy'], feature=sage.features.normaliz.PyNormaliz()) from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -201,6 +201,7 @@ class Polyhedron_normaliz(Polyhedron_base_number_field): sage: P.vertices() # needs sage.rings.number_field sage.symbolic (A vertex at (2^(1/3)), A vertex at (sqrt(2))) """ + def __init__(self, parent, Vrep, Hrep, normaliz_cone=None, normaliz_data=None, internal_base_ring=None, **kwds): """ Initialize the polyhedron. @@ -266,6 +267,7 @@ def _nmz_result(self, normaliz_cone, property): sage: p._nmz_result(p._normaliz_cone, 'MaximalSubspace') [] """ + def rational_handler(list): return QQ(tuple(list)) @@ -273,9 +275,8 @@ def nfelem_handler(coords): # coords might be too short which is not accepted by Sage number field v = list(coords) + [0] * (self._internal_base_ring.degree() - len(coords)) return self._internal_base_ring(v) - return NmzResult(normaliz_cone, property, - RationalHandler=rational_handler, - NumberfieldElementHandler=nfelem_handler) + + return NmzResult(normaliz_cone, property, RationalHandler=rational_handler, NumberfieldElementHandler=nfelem_handler) def _init_from_normaliz_cone(self, normaliz_cone, internal_base_ring): """ @@ -336,11 +337,14 @@ def _convert_to_pynormaliz(x): (Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.41...)^4 defined as the convex hull of 4 vertices """ + def _QQ_pair(x): x = QQ(x) return [int(x.numerator()), int(x.denominator())] + from sage.rings.rational import Rational from types import GeneratorType + if isinstance(x, (list, tuple, GeneratorType)): return [Polyhedron_normaliz._convert_to_pynormaliz(y) for y in x] try: @@ -535,9 +539,7 @@ def vert_ray_line_NF(vertices, rays, lines): if lines is None: lines = [] - (nmz_vertices, nmz_rays, nmz_lines), internal_base_ring \ - = self._compute_data_lists_and_internal_base_ring( - (vertices, rays, lines), vert_ray_line_QQ, vert_ray_line_NF) + (nmz_vertices, nmz_rays, nmz_lines), internal_base_ring = self._compute_data_lists_and_internal_base_ring((vertices, rays, lines), vert_ray_line_QQ, vert_ray_line_NF) if not nmz_vertices and not nmz_rays and not nmz_lines: # Special case to avoid: @@ -545,9 +547,7 @@ def vert_ray_line_NF(vertices, rays, lines): # All input matrices empty! self._init_empty_polyhedron() else: - data = {"vertices": nmz_vertices, - "cone": nmz_rays, - "subspace": nmz_lines} + data = {"vertices": nmz_vertices, "cone": nmz_rays, "subspace": nmz_lines} number_field_data = self._number_field_triple(internal_base_ring) if number_field_data: data["number_field"] = number_field_data @@ -628,16 +628,13 @@ def nmz_ieqs_eqns_QQ(ieqs, eqns): if eqns is None: eqns = [] - (nmz_ieqs, nmz_eqns), internal_base_ring \ - = self._compute_data_lists_and_internal_base_ring( - (ieqs, eqns), nmz_ieqs_eqns_QQ, nmz_ieqs_eqns_NF) + (nmz_ieqs, nmz_eqns), internal_base_ring = self._compute_data_lists_and_internal_base_ring((ieqs, eqns), nmz_ieqs_eqns_QQ, nmz_ieqs_eqns_NF) if not nmz_ieqs: # If normaliz gets an empty list of inequalities, it adds # nonnegativities. So let's add a tautological inequality to work # around this. nmz_ieqs.append([0] * self.ambient_dim() + [0]) - data = {"inhom_equations": nmz_eqns, - "inhom_inequalities": nmz_ieqs} + data = {"inhom_equations": nmz_eqns, "inhom_inequalities": nmz_ieqs} number_field_data = self._number_field_triple(internal_base_ring) if number_field_data: data["number_field"] = number_field_data @@ -807,6 +804,7 @@ def rays_subspace_lattice_ieqs_QQ(vertices, rays, lines, ieqs): nmz_ieqs.append(A + [b]) from sage.matrix.constructor import Matrix + lattice = Matrix(ZZ, nmz_vertices + nmz_rays + nmz_lines).saturation() nmz_lattice = [list(y) for y in lattice] @@ -833,6 +831,7 @@ def rays_subspace_lattice_ieqs_NF(vertices, rays, lines, ieqs): nmz_ieqs.append(list(A) + [b]) from sage.matrix.constructor import Matrix + lattice = Matrix(nmz_vertices + nmz_rays + nmz_lines).row_space().basis() nmz_lattice = [list(y) for y in lattice] @@ -847,15 +846,9 @@ def rays_subspace_lattice_ieqs_NF(vertices, rays, lines, ieqs): return nmz_vertices + nmz_rays, nmz_lines, nmz_lattice, nmz_ieqs - (nmz_extreme_rays, nmz_subspace, nmz_lattice, nmz_ieqs), internal_base_ring \ - = self._compute_data_lists_and_internal_base_ring( - (vertices, rays, lines, ieqs), rays_subspace_lattice_ieqs_QQ, - rays_subspace_lattice_ieqs_NF) + (nmz_extreme_rays, nmz_subspace, nmz_lattice, nmz_ieqs), internal_base_ring = self._compute_data_lists_and_internal_base_ring((vertices, rays, lines, ieqs), rays_subspace_lattice_ieqs_QQ, rays_subspace_lattice_ieqs_NF) - data = {"extreme_rays": nmz_extreme_rays, - "maximal_subspace": nmz_subspace, - "generated_lattice": nmz_lattice, - "support_hyperplanes": nmz_ieqs} + data = {"extreme_rays": nmz_extreme_rays, "maximal_subspace": nmz_subspace, "generated_lattice": nmz_lattice, "support_hyperplanes": nmz_ieqs} ambient_dim = len(data["extreme_rays"][0]) if not homogeneous: @@ -899,6 +892,7 @@ def _test_far_facet_condition(self, tester=None, **options): nmz_ieqs = self._nmz_result(self._normaliz_cone, "SupportHyperplanes") from sage.matrix.constructor import Matrix + far_facet_condition = Matrix(nmz_vertices + nmz_rays).rank() == Matrix(nmz_rays).rank() + 1 tester.assertEqual(far_facet_condition, self.n_inequalities() != len(nmz_ieqs)) @@ -1019,6 +1013,7 @@ def _number_field_triple(internal_base_ring) -> list: return None from sage.rings.real_arb import RealBallField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + emb = RealBallField(53)(R.gen(0)) gen = 'a' R_a = PolynomialRing(QQ, gen) @@ -1085,11 +1080,7 @@ def _get_nmzcone_data(self) -> dict: ineqs = self._nmz_result(self._normaliz_cone, "SupportHyperplanes") eqs = self._nmz_result(self._normaliz_cone, "Equations") - return {'vertices': vertices, - 'cone': rays, - 'subspace': lines, - 'inhom_equations': eqs, - 'inhom_inequalities': ineqs} + return {'vertices': vertices, 'cone': rays, 'subspace': lines, 'inhom_equations': eqs, 'inhom_inequalities': ineqs} def _normaliz_format(self, data, file_output=None): r""" @@ -1118,6 +1109,7 @@ def _normaliz_format(self, data, file_output=None): # ----8<-------------------8<-------------------8<---- # Calling ... """ + def format_number(x): try: return '{}'.format(QQ(x)) @@ -1141,6 +1133,7 @@ def format_number_field_data(nf_triple): s = format_field('amb_space', self.ambient_dim()) if 'number_field' in data: from copy import copy + data = copy(data) s += 'number_field {}\n'.format(format_number_field_data(data['number_field'])) del data['number_field'] @@ -1290,9 +1283,7 @@ def __setstate__(self, state): inequalities = self.inequalities() equations = self.equations() - self._normaliz_cone = \ - self._cone_from_Vrepresentation_and_Hrepresentation( - vertices, rays, lines, inequalities, equations) + self._normaliz_cone = self._cone_from_Vrepresentation_and_Hrepresentation(vertices, rays, lines, inequalities, equations) def integral_hull(self): r""" @@ -1335,8 +1326,7 @@ def integral_hull(self): if self.is_empty(): return self cone = self._nmz_result(self._normaliz_cone, "IntegerHull") - return self.parent().element_class._from_normaliz_cone(parent=self.parent(), - normaliz_cone=cone) + return self.parent().element_class._from_normaliz_cone(parent=self.parent(), normaliz_cone=cone) def _h_star_vector_normaliz(self) -> list: r""" @@ -1476,9 +1466,11 @@ def _volume_normaliz(self, measure='euclidean'): return self.base_ring().zero() if not self.is_compact(): from sage.rings.infinity import infinity + return infinity from sage.arith.misc import factorial + return self._volume_normaliz('induced_lattice') / factorial(self.dim()) raise TypeError("the measure should be `ambient`, `euclidean`, or `induced_lattice`") @@ -1555,9 +1547,7 @@ def _triangulate_normaliz(self): cone = self._normaliz_cone else: # Make a inhomogeneous copy of the cone. - cone = self._cone_from_Vrepresentation_and_Hrepresentation( - self.vertices(), self.rays(), self.lines(), - self.inequalities(), self.equations(), homogeneous=True) + cone = self._cone_from_Vrepresentation_and_Hrepresentation(self.vertices(), self.rays(), self.lines(), self.inequalities(), self.equations(), homogeneous=True) # Compute the triangulation. assert cone @@ -1704,14 +1694,15 @@ def ehrhart_series(self, variable='t'): # 3) a shifting of the generating function. from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + poly_ring = PolynomialRing(ZZ, variable).fraction_field() t = poly_ring.gens()[0] es = sum([e[0][i] * t**i for i in range(len(e[0]))]) for expo in range(len(e[1])): - es = es / (1 - t**e[1][expo]) + es = es / (1 - t ** e[1][expo]) # The shift: - return es * t**e[2] + return es * t ** e[2] def _ehrhart_quasipolynomial_normaliz(self, variable='t'): r""" @@ -1769,6 +1760,7 @@ def _ehrhart_quasipolynomial_normaliz(self, variable='t'): e = self._nmz_result(cone, "EhrhartQuasiPolynomial") from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + poly_ring = PolynomialRing(QQ, variable) t = poly_ring.gens()[0] if len(e) == 2: @@ -1866,14 +1858,15 @@ def hilbert_series(self, grading, variable='t'): h = self._nmz_result(new_cone, "HilbertSeries") from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + poly_ring = PolynomialRing(ZZ, variable).fraction_field() t = poly_ring.gens()[0] hs = sum([h[0][i] * t**i for i in range(len(h[0]))]) for expo in range(len(h[1])): - hs = hs / (1 - t**h[1][expo]) + hs = hs / (1 - t ** h[1][expo]) # The shift: - return hs * t**h[2] + return hs * t ** h[2] def integral_points(self, threshold=10000) -> tuple: r""" @@ -2087,10 +2080,10 @@ def integral_points(self, threshold=10000) -> tuple: box_min, box_max = self.bounding_box(integral_hull=True) if box_min is None: return () - box_points = prod(max_coord - min_coord + 1 - for min_coord, max_coord in zip(box_min, box_max)) + box_points = prod(max_coord - min_coord + 1 for min_coord, max_coord in zip(box_min, box_max)) if box_points < threshold: from sage.geometry.integral_points import rectangular_box_points + return rectangular_box_points(list(box_min), list(box_max), self) # Compute with normaliz points = [] @@ -2268,6 +2261,7 @@ class functions. from sage.matrix.matrix_space import MatrixSpace from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.matrix.special import identity_matrix + # Setting the group G_perm = self.restricted_automorphism_group(output='permutation') @@ -2320,7 +2314,7 @@ class functions. mat = group_dict[perm] mat = mat.change_ring(ring) new_matrix = identity - mat * ts_matrix - det = (1 - t)**-codim * (new_matrix.determinant()) + det = (1 - t) ** -codim * (new_matrix.determinant()) det_vector.append(det) FF = ring.fraction_field() @@ -2407,6 +2401,7 @@ def _Hstar_as_rat_fct(self, initial_Hstar): """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.qqbar import QQbar + chi_vars = ','.join(f'chi_{i}' for i in range(len(initial_Hstar))) Chi_ring = PolynomialRing(QQbar, chi_vars) virtual_ring = PolynomialRing(Chi_ring, initial_Hstar.base_ring().gens()) @@ -2495,4 +2490,5 @@ class Polyhedron_ZZ_normaliz(Polyhedron_QQ_normaliz, Polyhedron_ZZ): ....: backend='normaliz', base_ring=ZZ) sage: TestSuite(p).run() """ + pass diff --git a/src/sage/geometry/polyhedron/backend_number_field.py b/src/sage/geometry/polyhedron/backend_number_field.py index 4e510472e9b..f2cd7a1a9f8 100644 --- a/src/sage/geometry/polyhedron/backend_number_field.py +++ b/src/sage/geometry/polyhedron/backend_number_field.py @@ -88,8 +88,7 @@ class Polyhedron_number_field(Polyhedron_field, Polyhedron_base_number_field): A 1-dimensional polyhedron in QQ^1 defined as the convex hull of 1 vertex and 1 line """ - def _init_from_Vrepresentation(self, vertices, rays, lines, - minimize=True, verbose=False): + def _init_from_Vrepresentation(self, vertices, rays, lines, minimize=True, verbose=False): """ Construct polyhedron from V-representation data. @@ -127,13 +126,9 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, sage: p.vertices()[0][0] 0 """ - (vertices, rays, lines), internal_base_ring \ - = self._compute_data_lists_and_internal_base_ring((vertices, rays, lines), - lambda *x: x, lambda *x: x) + (vertices, rays, lines), internal_base_ring = self._compute_data_lists_and_internal_base_ring((vertices, rays, lines), lambda *x: x, lambda *x: x) self._internal_base_ring = internal_base_ring - super()._init_from_Vrepresentation(vertices, rays, lines, - minimize=minimize, verbose=verbose, - internal_base_ring=internal_base_ring) + super()._init_from_Vrepresentation(vertices, rays, lines, minimize=minimize, verbose=verbose, internal_base_ring=internal_base_ring) def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): """ @@ -158,10 +153,6 @@ def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): sage: from sage.geometry.polyhedron.backend_number_field import Polyhedron_number_field sage: Polyhedron_number_field._init_from_Hrepresentation(p, [(1, 2, 3)], []) """ - (ieqs, eqns), internal_base_ring \ - = self._compute_data_lists_and_internal_base_ring((ieqs, eqns), - lambda *x: x, lambda *x: x) + (ieqs, eqns), internal_base_ring = self._compute_data_lists_and_internal_base_ring((ieqs, eqns), lambda *x: x, lambda *x: x) self._internal_base_ring = internal_base_ring - super()._init_from_Hrepresentation(ieqs, eqns, - minimize=minimize, verbose=verbose, - internal_base_ring=internal_base_ring) + super()._init_from_Hrepresentation(ieqs, eqns, minimize=minimize, verbose=verbose, internal_base_ring=internal_base_ring) diff --git a/src/sage/geometry/polyhedron/backend_polymake.py b/src/sage/geometry/polyhedron/backend_polymake.py index da741ba2822..05b02e8c712 100644 --- a/src/sage/geometry/polyhedron/backend_polymake.py +++ b/src/sage/geometry/polyhedron/backend_polymake.py @@ -11,7 +11,7 @@ - Matthias Köppe (2017-03): initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2017 Matthias Köppe # # This program is free software: you can redistribute it and/or modify @@ -19,7 +19,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** import itertools @@ -280,6 +280,7 @@ def _init_from_Vrepresentation(self, vertices, rays, lines, minimize=True, verbo sage: Polyhedron_polymake._init_from_Vrepresentation(p, [], [], []) # optional - jupymake """ from sage.interfaces.polymake import polymake + data = self._polymake_Vrepresentation_data(vertices, rays, lines) polymake_field = polymake(self.base_ring().fraction_field()) p = polymake.new_object("Polytope<{}>".format(polymake_field), **data) @@ -311,14 +312,8 @@ def _polymake_Vrepresentation_data(self, vertices, rays, lines, minimal=False): It is not checked. """ if not minimal: - return dict(CONE_AMBIENT_DIM=1+self.parent().ambient_dim(), - POINTS=( [ [1] + list(v) for v in vertices ] - + [ [0] + list(r) for r in rays ]), - INPUT_LINEALITY=[ [0] + list(l) for l in lines ]) - return dict(CONE_AMBIENT_DIM=1+self.parent().ambient_dim(), - VERTICES=( [ [1] + list(v) for v in vertices ] - + [ [0] + list(r) for r in rays ]), - LINEALITY_SPACE=[ [0] + list(l) for l in lines ]) + return dict(CONE_AMBIENT_DIM=1 + self.parent().ambient_dim(), POINTS=([[1] + list(v) for v in vertices] + [[0] + list(r) for r in rays]), INPUT_LINEALITY=[[0] + list(l) for l in lines]) + return dict(CONE_AMBIENT_DIM=1 + self.parent().ambient_dim(), VERTICES=([[1] + list(v) for v in vertices] + [[0] + list(r) for r in rays]), LINEALITY_SPACE=[[0] + list(l) for l in lines]) def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): r""" @@ -346,6 +341,7 @@ def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): sage: Polyhedron_polymake._init_from_Hrepresentation(p, [], []) # optional - jupymake """ from sage.interfaces.polymake import polymake + data = self._polymake_Hrepresentation_data(ieqs, eqns) polymake_field = polymake(self.base_ring().fraction_field()) p = polymake.new_object("Polytope<{}>".format(polymake_field), **data) @@ -380,20 +376,18 @@ def _polymake_Hrepresentation_data(self, ieqs, eqns, minimal=False): # using QuadraticExtension, when some all-zero inequalities are input. # https://forum.polymake.org/viewtopic.php?f=8&t=547 # Filter them out. - ieqs = [ list(v) for v in ieqs if not all(self._is_zero(x) for x in v) ] + ieqs = [list(v) for v in ieqs if not all(self._is_zero(x) for x in v)] # We do a similar filtering for equations. # Since Polymake 3.2, we can not give all zero vectors in equations - eqns = [ list(v) for v in eqns if not all(self._is_zero(x) for x in v) ] + eqns = [list(v) for v in eqns if not all(self._is_zero(x) for x in v)] if not ieqs: # Put in one trivial (all-zero) inequality. This is so that # the ambient dimension is set correctly. # Since Polymake 3.2, the constant should not be zero. - ieqs.append([1] + [0]*self.ambient_dim()) + ieqs.append([1] + [0] * self.ambient_dim()) if not minimal: - return dict(EQUATIONS=eqns, - INEQUALITIES=ieqs) - return dict(AFFINE_HULL=eqns, - FACETS=ieqs) + return dict(EQUATIONS=eqns, INEQUALITIES=ieqs) + return dict(AFFINE_HULL=eqns, FACETS=ieqs) def _init_from_Vrepresentation_and_Hrepresentation(self, Vrep, Hrep): """ @@ -453,17 +447,19 @@ def _polymake_polytope_from_Vrepresentation_and_Hrepresentation(self, Vrep, Hrep return from sage.interfaces.polymake import polymake + data = self._polymake_Vrepresentation_data(*Vrep, minimal=True) if any(Vrep[1:]): from sage.matrix.constructor import Matrix + polymake_rays = [r for r in data['VERTICES'] if r[0] == 0] if Matrix(data['VERTICES']).rank() == Matrix(polymake_rays).rank() + 1: # The recession cone is full-dimensional. # In this case the homogenized inequalities # do not ensure nonnegativy in the last coordinate. # In the homogeneous cone the far face is a facet. - Hrep[0] += [[1] + [0]*self.ambient_dim()] + Hrep[0] += [[1] + [0] * self.ambient_dim()] data.update(self._polymake_Hrepresentation_data(*Hrep, minimal=True)) polymake_field = polymake(self.base_ring().fraction_field()) @@ -551,15 +547,13 @@ def _from_polymake_polytope(cls, parent, polymake_polytope): if parent is None: from .parent import Polyhedra from sage.rings.rational_field import QQ + if polymake_polytope.typeof()[0] == 'Polymake::polytope::Polytope__Rational': base_ring = QQ else: from sage.structure.element import coercion_model - data = [g.sage() - for g in itertools.chain(polymake_polytope.VERTICES, - polymake_polytope.LINEALITY_SPACE, - polymake_polytope.FACETS, - polymake_polytope.AFFINE_HULL)] + + data = [g.sage() for g in itertools.chain(polymake_polytope.VERTICES, polymake_polytope.LINEALITY_SPACE, polymake_polytope.FACETS, polymake_polytope.AFFINE_HULL)] if data: base_ring = coercion_model.common_parent(*data).base_ring() else: @@ -703,6 +697,7 @@ def _test_polymake_pickling(self, tester=None, other=None, **options): if other is None: from sage.misc.persist import loads, dumps + other = loads(dumps(self)) tester.assertEqual(self, other) @@ -720,6 +715,7 @@ def _test_polymake_pickling(self, tester=None, other=None, **options): tester.assertEqual(P.FACETS, P1.FACETS) tester.assertEqual(P.AFFINE_HULL, P1.AFFINE_HULL) + ######################################################################### @@ -739,6 +735,7 @@ class Polyhedron_QQ_polymake(Polyhedron_polymake, Polyhedron_QQ): ....: backend='polymake', base_ring=QQ) sage: TestSuite(p).run() # optional - jupymake """ + pass @@ -759,4 +756,5 @@ class Polyhedron_ZZ_polymake(Polyhedron_polymake, Polyhedron_ZZ): ....: backend='polymake', base_ring=ZZ) sage: TestSuite(p).run() # optional - jupymake """ + pass diff --git a/src/sage/geometry/polyhedron/backend_ppl.py b/src/sage/geometry/polyhedron/backend_ppl.py index 2364b59ca08..43b800e2441 100644 --- a/src/sage/geometry/polyhedron/backend_ppl.py +++ b/src/sage/geometry/polyhedron/backend_ppl.py @@ -14,9 +14,8 @@ from sage.misc.lazy_import import lazy_import from sage.features import PythonModule -lazy_import('ppl', ['C_Polyhedron', 'Generator_System', 'Constraint_System', - 'Linear_Expression', 'line', 'ray', 'point'], - feature=PythonModule("ppl", spkg='pplpy', type='standard')) + +lazy_import('ppl', ['C_Polyhedron', 'Generator_System', 'Constraint_System', 'Linear_Expression', 'line', 'ray', 'point'], feature=PythonModule("ppl", spkg='pplpy', type='standard')) ######################################################################### @@ -305,7 +304,7 @@ def _init_Vrepresentation_from_ppl(self, minimize): if d.is_one(): parent._make_Vertex(self, coefficients) else: - parent._make_Vertex(self, [x/d for x in coefficients]) + parent._make_Vertex(self, [x / d for x in coefficients]) elif g.is_ray(): parent._make_Ray(self, coefficients) elif g.is_line(): @@ -439,7 +438,7 @@ def _convert_generator_to_ppl(v, typ): d = LCM_list([denominator(v_i) for v_i in v]) if d.is_one(): return ob(Linear_Expression(v, 0)) - dv = [ d*v_i for v_i in v ] + dv = [d * v_i for v_i in v] if typ == VERTEX: return ob(Linear_Expression(dv, 0), d) return ob(Linear_Expression(dv, 0)) @@ -500,7 +499,7 @@ def _convert_constraint_to_ppl(c, typ): x0+6*x1+2==0 """ d = LCM_list([denominator(c_i) for c_i in c]) - dc = [ ZZ(d*c_i) for c_i in c ] + dc = [ZZ(d * c_i) for c_i in c] b = dc[0] A = dc[1:] if typ == INEQUALITY: @@ -553,6 +552,7 @@ class Polyhedron_QQ_ppl(Polyhedron_ppl, Polyhedron_QQ): ....: backend='ppl', base_ring=QQ) sage: TestSuite(p).run() """ + pass @@ -573,4 +573,5 @@ class Polyhedron_ZZ_ppl(Polyhedron_ppl, Polyhedron_ZZ): ....: backend='ppl', base_ring=ZZ) sage: TestSuite(p).run() """ + pass diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 99fb922e99d..0e99783b829 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -262,6 +262,7 @@ def to_linear_program(self, solver=None, return_variable=False, base_ring=None): base_ring = self.base_ring() base_ring = base_ring.fraction_field() from sage.numerical.mip import MixedIntegerLinearProgram + p = MixedIntegerLinearProgram(solver=solver, base_ring=base_ring) x = p.new_variable(real=True, nonnegative=False) @@ -324,10 +325,9 @@ def boundary_complex(self): if self.is_simplicial(): from sage.topology.simplicial_complex import SimplicialComplex + inc_mat_cols = self.incidence_matrix().columns() - ineq_indices = [inc_mat_cols[i].nonzero_positions() - for i in range(self.n_Hrepresentation()) - if self.Hrepresentation()[i].is_inequality()] + ineq_indices = [inc_mat_cols[i].nonzero_positions() for i in range(self.n_Hrepresentation()) if self.Hrepresentation()[i].is_inequality()] return SimplicialComplex(ineq_indices, maximality_check=False) raise NotImplementedError("this function is only implemented for simplicial polytopes") @@ -545,28 +545,24 @@ def is_inscribed(self, certificate=False): raw_data = [] for vertex in affine_basis: vertex_vector = vertex.vector() - raw_data += [[sum(i**2 for i in vertex_vector)] + - list(vertex_vector) + [1]] + raw_data += [[sum(i**2 for i in vertex_vector)] + list(vertex_vector) + [1]] matrix_data = matrix(raw_data) # The determinant "a" should not be zero because # the vertices in ``affine_basis`` are an affine basis. - a = matrix_data.matrix_from_columns(range(1, dimension+2)).determinant() + a = matrix_data.matrix_from_columns(range(1, dimension + 2)).determinant() - minors = [(-1)**(i)*matrix_data.matrix_from_columns([j for j in range(dimension+2) if j != i]).determinant() - for i in range(1, dimension+1)] - c = (-1)**(dimension+1)*matrix_data.matrix_from_columns(range(dimension+1)).determinant() + minors = [(-1) ** (i) * matrix_data.matrix_from_columns([j for j in range(dimension + 2) if j != i]).determinant() for i in range(1, dimension + 1)] + c = (-1) ** (dimension + 1) * matrix_data.matrix_from_columns(range(dimension + 1)).determinant() - circumcenter = vector([minors[i]/(2*a) for i in range(dimension)]) - squared_circumradius = (sum(m**2 for m in minors) - 4 * a * c) / (4*a**2) + circumcenter = vector([minors[i] / (2 * a) for i in range(dimension)]) + squared_circumradius = (sum(m**2 for m in minors) - 4 * a * c) / (4 * a**2) # Checking if the circumcenter has the correct sign - if not all(sum(i**2 for i in v.vector() - circumcenter) == squared_circumradius - for v in vertices if v in affine_basis): - circumcenter = - circumcenter + if not all(sum(i**2 for i in v.vector() - circumcenter) == squared_circumradius for v in vertices if v in affine_basis): + circumcenter = -circumcenter - is_inscribed = all(sum(i**2 for i in v.vector() - circumcenter) == squared_circumradius - for v in vertices if v not in affine_basis) + is_inscribed = all(sum(i**2 for i in v.vector() - circumcenter) == squared_circumradius for v in vertices if v not in affine_basis) if certificate: if is_inscribed: @@ -596,6 +592,7 @@ def hyperplane_arrangement(self): """ names = tuple('t' + str(i) for i in range(self.ambient_dim())) from sage.geometry.hyperplane_arrangement.arrangement import HyperplaneArrangements + field = self.base_ring().fraction_field() H = HyperplaneArrangements(field, names) return H(self) @@ -849,8 +846,7 @@ def barycentric_subdivision(self, subdivision_frac=None): if not self.is_compact(): raise ValueError("the polytope has to be compact") if not (0 < subdivision_frac < ZZ.one() / 2): - raise ValueError("the subdivision fraction should be " - "between 0 and 1/2") + raise ValueError("the subdivision fraction should be " "between 0 and 1/2") barycenter = self.center() parent = self.parent().base_extend(subdivision_frac) @@ -870,15 +866,13 @@ def barycentric_subdivision(self, subdivision_frac=None): normal_vectors = [] for facet in Hrep: - if all(facet.contains(v) and not facet.interior_contains(v) - for v in face_vertices): + if all(facet.contains(v) and not facet.interior_contains(v) for v in face_vertices): # The facet contains the face normal_vectors.append(facet.A()) normal_vector = sum(normal_vectors) - B = - normal_vector * (face_vertices[0].vector()) - linear_evaluation = {-normal_vector * v.vector() - for v in polar.vertices()} + B = -normal_vector * (face_vertices[0].vector()) + linear_evaluation = {-normal_vector * v.vector() for v in polar.vertices()} if B == max(linear_evaluation): C = max(linear_evaluation.difference(set([B]))) @@ -980,8 +974,7 @@ def permutations_to_matrices(self, conj_class_reps, acting_group=None, additiona group_dict = {} def permutation_to_matrix(permutation, V, Vplus, W): - A = sum(V[permutation(i)].column() * Vplus[i].row() - for i in range(len(V))) + A = sum(V[permutation(i)].column() * Vplus[i].row() for i in range(len(V))) return A + W for perm in G.gens(): @@ -1039,6 +1032,7 @@ def bounding_box(self, integral=False, integral_hull=False): """ from sage.arith.misc import integer_ceil as ceil from sage.arith.misc import integer_floor as floor + box_min = [] box_max = [] if not self.is_compact(): @@ -1143,6 +1137,7 @@ def _polymake_init_(self): 1 -0.472135955 0 -1.236067978 """ from sage.interfaces.polymake import polymake + polymake_field = polymake(self.base_ring().fraction_field()) polymake_class = "Polytope<{}>".format(polymake_field) if self.is_empty(): @@ -1150,14 +1145,8 @@ def _polymake_init_(self): # FACETS and AFFINE_HULL. # Use corresponding input properties instead. # https://forum.polymake.org/viewtopic.php?f=8&t=545 - return polymake.new_object(polymake_class, - INEQUALITIES=self.inequalities_list(), - EQUATIONS=self.equations_list()) + return polymake.new_object(polymake_class, INEQUALITIES=self.inequalities_list(), EQUATIONS=self.equations_list()) verts_and_rays = [[1] + v for v in self.vertices_list()] verts_and_rays += [[0] + r for r in self.rays_list()] - return polymake.new_object(polymake_class, - FACETS=self.inequalities_list(), - AFFINE_HULL=self.equations_list(), - VERTICES=verts_and_rays, - LINEALITY_SPACE=[[0] + l for l in self.lines_list()]) + return polymake.new_object(polymake_class, FACETS=self.inequalities_list(), AFFINE_HULL=self.equations_list(), VERTICES=verts_and_rays, LINEALITY_SPACE=[[0] + l for l in self.lines_list()]) diff --git a/src/sage/geometry/polyhedron/base0.py b/src/sage/geometry/polyhedron/base0.py index 19ac9bea6af..f2b5be7309e 100644 --- a/src/sage/geometry/polyhedron/base0.py +++ b/src/sage/geometry/polyhedron/base0.py @@ -71,6 +71,7 @@ class Polyhedron_base0(Element, sage.geometry.abc.Polyhedron): sage: Polyhedron_base0.base_extend(P, QQ) A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex, 1 ray, 1 line """ + def __init__(self, parent, Vrep, Hrep, Vrep_minimal=None, Hrep_minimal=None, pref_rep=None, mutable=False, **kwds): """ Initialize the polyhedron. @@ -128,8 +129,7 @@ def __init__(self, parent, Vrep, Hrep, Vrep_minimal=None, Hrep_minimal=None, pre Element.__init__(self, parent=parent) if Vrep is not None and Hrep is not None: if not (Vrep_minimal is True and Hrep_minimal is True): - raise ValueError("if both Vrep and Hrep are provided, they must be minimal" - " and Vrep_minimal and Hrep_minimal must both be True") + raise ValueError("if both Vrep and Hrep are provided, they must be minimal" " and Vrep_minimal and Hrep_minimal must both be True") if hasattr(self, "_init_from_Vrepresentation_and_Hrepresentation"): self._init_from_Vrepresentation_and_Hrepresentation(Vrep, Hrep) return @@ -705,19 +705,16 @@ def Hrepresentation_str(self, separator='\n', latex=False, style='>=', align=Non if align: lengths = [(len(s[0]), len(s[1]), len(s[2])) for s in pretty_hs] from operator import itemgetter + length_left = max(lengths, key=itemgetter(0))[0] length_middle = max(lengths, key=itemgetter(1))[1] length_right = max(lengths, key=itemgetter(2))[2] if shift: length_right += 1 if latex: - h_line = "{:>" + "{}".format(length_left) + "} & {:" + \ - "{}".format(length_middle) + "} & {:" + \ - "{}".format(length_right) + "}\\\\" + h_line = "{:>" + "{}".format(length_left) + "} & {:" + "{}".format(length_middle) + "} & {:" + "{}".format(length_right) + "}\\\\" else: - h_line = "{:>" + "{}".format(length_left) \ - + "} {:" + "{}".format(length_middle) \ - + "} {:" + "{}".format(length_right) + "}" + h_line = "{:>" + "{}".format(length_left) + "} {:" + "{}".format(length_middle) + "} {:" + "{}".format(length_right) + "}" elif latex: h_line = "{} & {} & {}\\\\" else: @@ -727,8 +724,8 @@ def pad_non_minus(s): if align and shift and not s.startswith('-'): return ' ' + s return s - h_list = [h_line.format(pretty_h[0], pretty_h[1], pad_non_minus(pretty_h[2])) - for pretty_h in pretty_hs] + + h_list = [h_line.format(pretty_h[0], pretty_h[1], pad_non_minus(pretty_h[2])) for pretty_h in pretty_hs] pretty_print = separator.join(h_list) if not latex: @@ -1334,20 +1331,20 @@ def cdd_Hrepresentation(self): TypeError: the base ring must be ZZ, QQ, or RDF """ from .cdd_file_format import cdd_Hrepresentation + try: cdd_type = self._cdd_type except AttributeError: from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ + if self.base_ring() is ZZ or self.base_ring() is QQ: cdd_type = 'rational' elif isinstance(self.base_ring(), sage.rings.abc.RealDoubleField): cdd_type = 'real' else: raise TypeError('the base ring must be ZZ, QQ, or RDF') - return cdd_Hrepresentation(cdd_type, - list(self.inequality_generator()), - list(self.equation_generator())) + return cdd_Hrepresentation(cdd_type, list(self.inequality_generator()), list(self.equation_generator())) def write_cdd_Hrepresentation(self, filename): r""" @@ -1397,21 +1394,20 @@ def cdd_Vrepresentation(self): end """ from .cdd_file_format import cdd_Vrepresentation + try: cdd_type = self._cdd_type except AttributeError: from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ + if self.base_ring() is ZZ or self.base_ring() is QQ: cdd_type = 'rational' elif isinstance(self.base_ring(), sage.rings.abc.RealDoubleField): cdd_type = 'real' else: raise TypeError('the base ring must be ZZ, QQ, or RDF') - return cdd_Vrepresentation(cdd_type, - list(self.vertex_generator()), - list(self.ray_generator()), - list(self.line_generator())) + return cdd_Vrepresentation(cdd_type, list(self.vertex_generator()), list(self.ray_generator()), list(self.line_generator())) def write_cdd_Vrepresentation(self, filename): r""" diff --git a/src/sage/geometry/polyhedron/base1.py b/src/sage/geometry/polyhedron/base1.py index 73b7b287d0b..f4cc3cc61c8 100644 --- a/src/sage/geometry/polyhedron/base1.py +++ b/src/sage/geometry/polyhedron/base1.py @@ -106,16 +106,7 @@ def __hash__(self): True """ # TODO: find something better *but* fast - return hash((self.dim(), - self.ambient_dim(), - self.n_Hrepresentation(), - self.n_Vrepresentation(), - self.n_equations(), - self.n_facets(), - self.n_inequalities(), - self.n_lines(), - self.n_rays(), - self.n_vertices())) + return hash((self.dim(), self.ambient_dim(), self.n_Hrepresentation(), self.n_Vrepresentation(), self.n_equations(), self.n_facets(), self.n_inequalities(), self.n_lines(), self.n_rays(), self.n_vertices())) def _repr_(self): """ @@ -252,9 +243,7 @@ def _is_subpolyhedron(self, other): sage: Q._is_subpolyhedron(P) True """ - return all(other_H.contains(self_V) - for other_H in other.Hrepresentation() - for self_V in self.Vrepresentation()) + return all(other_H.contains(self_V) for other_H in other.Hrepresentation() for self_V in self.Vrepresentation()) def is_empty(self): """ @@ -331,7 +320,7 @@ def dim(self): -1 """ if self.n_Vrepresentation() == 0: - return -1 # the empty set + return -1 # the empty set return self.ambient_dim() - self.n_equations() dimension = dim @@ -469,7 +458,7 @@ def an_affine_basis(self): basis_indices.extend(face[:]) continue - prev_face = chain_indices[dim-1] + prev_face = chain_indices[dim - 1] for i in range(len(prev_face)): if prev_face[i] != face[i]: # We found a Vrep that ``face`` has, but its facet does not. @@ -486,8 +475,7 @@ def an_affine_basis(self): for vrep in Vreps: if vrep.is_vertex(): vertex = vrep - return [vrep if vrep.is_vertex() else vertex.vector() + vrep.vector() - for vrep in Vreps] + return [vrep if vrep.is_vertex() else vertex.vector() + vrep.vector() for vrep in Vreps] @abstract_method def a_maximal_chain(self): @@ -532,7 +520,7 @@ def representative_point(self): sage: Polyhedron(vertices=[(3,2)]).representative_point() (3, 2) """ - accumulator = vector(self.base_ring(), [0]*self.ambient_dim()) + accumulator = vector(self.base_ring(), [0] * self.ambient_dim()) for v in self.vertex_generator(): accumulator += v.vector() accumulator /= self.n_vertices() diff --git a/src/sage/geometry/polyhedron/base2.py b/src/sage/geometry/polyhedron/base2.py index ce6670d6b15..5ed3544a087 100644 --- a/src/sage/geometry/polyhedron/base2.py +++ b/src/sage/geometry/polyhedron/base2.py @@ -182,11 +182,10 @@ def lattice_polytope(self, envelope=False): vertices = self.vertices_matrix(ZZ).columns() except TypeError: if not envelope: - raise ValueError('Some vertices are not integral. ' - 'You probably want to add the argument ' - '"envelope=True" to compute an enveloping lattice polytope.') + raise ValueError('Some vertices are not integral. ' 'You probably want to add the argument ' '"envelope=True" to compute an enveloping lattice polytope.') from sage.arith.misc import integer_ceil as ceil from sage.arith.misc import integer_floor as floor + vertices = [] for v in self.vertex_generator(): vbox = [set([floor(x), ceil(x)]) for x in v] @@ -194,6 +193,7 @@ def lattice_polytope(self, envelope=False): # construct the (enveloping) lattice polytope from sage.geometry.lattice_polytope import LatticePolytope + return LatticePolytope(vertices) def _integral_points_PALP(self): @@ -497,6 +497,7 @@ def integral_points(self, threshold=100000): sage: S = set(P.integral_points()) """ from sage.misc.misc_c import prod + if not self.is_compact(): raise ValueError('can only enumerate points in a compact polyhedron') # Trivial cases: polyhedron with 0 or 1 vertices @@ -513,15 +514,15 @@ def integral_points(self, threshold=100000): box_min, box_max = self.bounding_box(integral_hull=True) if box_min is None: return () - box_points = prod(max_coord-min_coord+1 for min_coord, max_coord in zip(box_min, box_max)) - if not self.is_lattice_polytope() or \ - (self.is_simplex() and box_points < 1000) or \ - box_points < threshold: + box_points = prod(max_coord - min_coord + 1 for min_coord, max_coord in zip(box_min, box_max)) + if not self.is_lattice_polytope() or (self.is_simplex() and box_points < 1000) or box_points < threshold: from sage.geometry.integral_points import rectangular_box_points + return rectangular_box_points(list(box_min), list(box_max), self) # for more complicate polytopes, triangulate & use smith normal form from sage.geometry.integral_points import simplex_points + if self.is_simplex(): return simplex_points(self.Vrepresentation()) triangulation = self.triangulate() @@ -595,6 +596,7 @@ def get_integral_point(self, index, **kwds): """ from sage.arith.misc import integer_ceil as ceil from sage.arith.misc import integer_floor as floor + if not self.is_compact(): raise ValueError('can only enumerate points in a compact polyhedron') @@ -608,10 +610,10 @@ def get_integral_point(self, index, **kwds): S = self.parent() for i in range(D): # Now compute x_i, the ith component of coordinate. lower, upper = ceil(lower_bounds[i]), floor(upper_bounds[i]) + 1 # So lower <= x_i < upper. - while lower < upper-1: + while lower < upper - 1: guess = (lower + upper) // 2 # > lower. # Build new polyhedron by intersecting P with the halfspace {x_i < guess}. - P_lt_guess = P.intersection(S(None, ([[guess-1] + [0] * i + [-1] + [0] * (D - i - 1)], []))) + P_lt_guess = P.intersection(S(None, ([[guess - 1] + [0] * i + [-1] + [0] * (D - i - 1)], []))) # Avoid computing P_geq_guess = P.intersection({x_i >= guess}) right now, it might not be needed. P_lt_guess_count = P_lt_guess.integral_points_count(**kwds) if P_lt_guess_count > index: # Move upper down to guess. @@ -684,9 +686,10 @@ def random_integral_point(self, **kwds): count = self.integral_points_count() if count == 0: from sage.categories.sets_cat import EmptySetError + raise EmptySetError('polyhedron does not contain any integral points') - return self.get_integral_point(current_randstate().python_random().randint(0, count-1), **kwds) + return self.get_integral_point(current_randstate().python_random().randint(0, count - 1), **kwds) def generating_function_of_integral_points(self, **kwds): r""" @@ -814,4 +817,5 @@ def generating_function_of_integral_points(self, **kwds): :func:`~sage.geometry.polyhedron.generating_function.generating_function_of_integral_points`. """ from .generating_function import generating_function_of_integral_points + return generating_function_of_integral_points(self, **kwds) diff --git a/src/sage/geometry/polyhedron/base3.py b/src/sage/geometry/polyhedron/base3.py index 3931caf65ac..601733aff1b 100644 --- a/src/sage/geometry/polyhedron/base3.py +++ b/src/sage/geometry/polyhedron/base3.py @@ -158,8 +158,7 @@ def slack_matrix(self): Number Field in a with defining polynomial x^2 - 2 with a = 1.41... """ if not self.n_Vrepresentation() or not self.n_Hrepresentation(): - slack_matrix = matrix(self.base_ring(), self.n_Vrepresentation(), - self.n_Hrepresentation(), 0) + slack_matrix = matrix(self.base_ring(), self.n_Vrepresentation(), self.n_Hrepresentation(), 0) else: Vrep_matrix = matrix(self.base_ring(), self.Vrepresentation()) Hrep_matrix = matrix(self.base_ring(), self.Hrepresentation()) @@ -300,20 +299,17 @@ def incidence_matrix(self): incidence_matrix.set_immutable() return incidence_matrix - incidence_matrix = matrix(ZZ, self.n_Vrepresentation(), - self.n_Hrepresentation(), 0) + incidence_matrix = matrix(ZZ, self.n_Vrepresentation(), self.n_Hrepresentation(), 0) - Vvectors_vertices = tuple((v.vector(), v.index()) - for v in self.Vrep_generator() - if v.is_vertex()) - Vvectors_rays_lines = tuple((v.vector(), v.index()) - for v in self.Vrep_generator() - if not v.is_vertex()) + Vvectors_vertices = tuple((v.vector(), v.index()) for v in self.Vrep_generator() if v.is_vertex()) + Vvectors_rays_lines = tuple((v.vector(), v.index()) for v in self.Vrep_generator() if not v.is_vertex()) # Determine ``is_zero`` to save lots of time. if self.base_ring().is_exact(): + def is_zero(x): return not x + else: is_zero = self._is_zero @@ -322,13 +318,13 @@ def is_zero(x): Hvec = H.A() Hindex = H.index() for Vvec, Vindex in Vvectors_vertices: - if is_zero(Hvec*Vvec + Hconst): + if is_zero(Hvec * Vvec + Hconst): incidence_matrix[Vindex, Hindex] = 1 # A ray or line is considered incident with a hyperplane, # if it is orthogonal to the normal vector of the hyperplane. for Vvec, Vindex in Vvectors_rays_lines: - if is_zero(Hvec*Vvec): + if is_zero(Hvec * Vvec): incidence_matrix[Vindex, Hindex] = 1 incidence_matrix.set_immutable() @@ -353,6 +349,7 @@ def combinatorial_polyhedron(self): A 2-dimensional combinatorial polyhedron with 2 facets """ from sage.geometry.polyhedron.combinatorial_polyhedron.base import CombinatorialPolyhedron + return CombinatorialPolyhedron(self) def _test_combinatorial_polyhedron(self, tester=None, **options): @@ -367,8 +364,7 @@ def _test_combinatorial_polyhedron(self, tester=None, **options): tester = self._tester(tester=tester, **options) tester.info("\n Running the test suite of self.combinatorial_polyhedron()") - TestSuite(self.combinatorial_polyhedron()).run(verbose=tester._verbose, - prefix=tester._prefix+" ") + TestSuite(self.combinatorial_polyhedron()).run(verbose=tester._verbose, prefix=tester._prefix + " ") tester.info(tester._prefix + " ", newline=False) def face_generator(self, face_dimension=None, algorithm=None): @@ -605,6 +601,7 @@ def face_generator(self, face_dimension=None, algorithm=None): raise ValueError("algorithm must be 'primal', 'dual' or None") from sage.geometry.polyhedron.combinatorial_polyhedron.face_iterator import FaceIterator_geom + return FaceIterator_geom(self, output_dimension=face_dimension, dual=dual) def faces(self, face_dimension): @@ -754,7 +751,7 @@ def facets(self): """ if self.dimension() == 0: return () - return self.faces(self.dimension()-1) + return self.faces(self.dimension() - 1) @cached_method(do_pickle=True, key=lambda self, x, y, z: None) def f_vector(self, num_threads=None, parallelization_depth=None, algorithm=None): @@ -851,7 +848,7 @@ def bounded_edges(self): for i in range(len(obj)): if not obj[i].is_vertex(): continue - for j in range(i+1, len(obj)): + for j in range(i + 1, len(obj)): if not obj[j].is_vertex(): continue if self.vertex_adjacency_matrix()[i, j] == 0: @@ -1087,16 +1084,14 @@ def a_maximal_chain(self): comb_chain = self.combinatorial_polyhedron().a_maximal_chain() from sage.geometry.polyhedron.face import combinatorial_face_to_polyhedral_face + empty_face = self.faces(-1)[0] universe = self.faces(self.dim())[0] if self.dim() == -1: return [empty_face] - return [empty_face] + \ - [combinatorial_face_to_polyhedral_face(self, face) - for face in comb_chain] + \ - [universe] + return [empty_face] + [combinatorial_face_to_polyhedral_face(self, face) for face in comb_chain] + [universe] def is_simplex(self) -> bool: r""" @@ -1114,7 +1109,7 @@ def is_simplex(self) -> bool: sage: polytopes.hypercube(3).is_simplex() False """ - return self.is_compact() and (self.dim()+1 == self.n_vertices()) + return self.is_compact() and (self.dim() + 1 == self.n_vertices()) def simplicity(self): r""" @@ -1633,7 +1628,7 @@ def join_of_Vrep(self, *Vrepresentatives): from sage.geometry.polyhedron.representation import Vrepresentation from sage.geometry.polyhedron.face import PolyhedronFace - new_indices = [0]*len(Vrepresentatives) + new_indices = [0] * len(Vrepresentatives) for i, v in enumerate(Vrepresentatives): if isinstance(v, PolyhedronFace) and v.dim() == 0: if v.polyhedron() is not self: @@ -1834,6 +1829,7 @@ def _test_combinatorial_face_as_combinatorial_polyhedron(self, tester=None, **op D2._test_bitsets(tester, **options) try: import sage.graphs.graph + assert sage.graphs.graph # to muffle pyflakes except ImportError: pass diff --git a/src/sage/geometry/polyhedron/base4.py b/src/sage/geometry/polyhedron/base4.py index 7ee69b7e6b8..280e661e483 100644 --- a/src/sage/geometry/polyhedron/base4.py +++ b/src/sage/geometry/polyhedron/base4.py @@ -247,12 +247,12 @@ def vertex_digraph(self, f, increasing=True): :meth:`vertex_graph` """ from sage.modules.vector_space_morphism import VectorSpaceMorphism + if isinstance(f, VectorSpaceMorphism): if f.codomain().dimension() == 1: orientation_check = lambda v: f(v) >= 0 else: - raise TypeError('the linear map f must have ' - 'one-dimensional codomain') + raise TypeError('the linear map f must have ' 'one-dimensional codomain') else: try: if f.is_vector(): @@ -264,6 +264,7 @@ def vertex_digraph(self, f, increasing=True): if not increasing: f = -f from sage.graphs.digraph import DiGraph + dg = DiGraph() for j in range(self.n_vertices()): vj = self.Vrepresentation(j) @@ -386,6 +387,7 @@ def face_lattice(self): [[()], [(0, 1)]] """ from sage.combinat.posets.lattices import FiniteLatticePoset + return FiniteLatticePoset(self.hasse_diagram()) @cached_method @@ -449,12 +451,12 @@ def hasse_diagram(self): """ from sage.geometry.polyhedron.face import combinatorial_face_to_polyhedral_face + C = self.combinatorial_polyhedron() D = C.hasse_diagram() def index_to_polyhedron_face(n): - return combinatorial_face_to_polyhedral_face( - self, C.face_by_face_lattice_index(n)) + return combinatorial_face_to_polyhedral_face(self, C.face_by_face_lattice_index(n)) return D.relabel(index_to_polyhedron_face, inplace=False, immutable=True) @@ -972,8 +974,10 @@ def restricted_automorphism_group(self, output='abstract'): output = "permutation" if self.base_ring().is_exact(): + def rational_approximation(c): return c + else: c_list = [] @@ -989,8 +993,10 @@ def rational_approximation(c): return len(c_list) - 1 if self.is_compact(): + def edge_label(i, j, c_ij): return c_ij + else: # In the non-compact case, we also label the edges by the # type of the V-representation object. This ensures that @@ -1009,11 +1015,12 @@ def edge_label(i, j, c_ij): # Construct the graph. from sage.graphs.graph import Graph + G = Graph() for i in range(len(V)): - for j in range(i+1, len(V)): + for j in range(i + 1, len(V)): c_ij = rational_approximation(V[i] * Qplus * V[j]) - G.add_edge(index0+i, index0+j, edge_label(i, j, c_ij)) + G.add_edge(index0 + i, index0 + j, edge_label(i, j, c_ij)) permgroup = G.automorphism_group(edge_labels=True) if output == "permutation": @@ -1023,6 +1030,7 @@ def edge_label(i, j, c_ij): # Compute V+ = Vt Q+ as list of row vectors from sage.matrix.constructor import matrix + Vplus = list(matrix(V) * Qplus) # matrix(V) is Vt # Compute W = 1 - V V+ @@ -1045,6 +1053,7 @@ def edge_label(i, j, c_ij): if output == "matrixlist": return tuple(matrices) from sage.groups.matrix_gps.finitely_generated import MatrixGroup + return MatrixGroup(matrices) def is_combinatorially_isomorphic(self, other, algorithm='bipartite_graph'): @@ -1203,12 +1212,13 @@ def _test_is_combinatorially_isomorphic(self, tester=None, **options): return from sage.rings.integer_ring import ZZ - tester.assertTrue(self.is_combinatorially_isomorphic(ZZ(4)*self)) + + tester.assertTrue(self.is_combinatorially_isomorphic(ZZ(4) * self)) if self.n_vertices(): tester.assertTrue(self.is_combinatorially_isomorphic(self + self.center())) if self.n_vertices() < 20 and self.n_facets() < 20 and self.is_immutable(): - tester.assertTrue(self.is_combinatorially_isomorphic(ZZ(4)*self, algorithm='face_lattice')) + tester.assertTrue(self.is_combinatorially_isomorphic(ZZ(4) * self, algorithm='face_lattice')) if self.n_vertices(): tester.assertTrue(self.is_combinatorially_isomorphic(self + self.center(), algorithm='face_lattice')) diff --git a/src/sage/geometry/polyhedron/base5.py b/src/sage/geometry/polyhedron/base5.py index c804a1798f3..326b4515488 100644 --- a/src/sage/geometry/polyhedron/base5.py +++ b/src/sage/geometry/polyhedron/base5.py @@ -249,30 +249,28 @@ def polar(self, in_affine_span=False): if self.n_vertices() == 1: new_verts = self.vertices() elif not self.n_equations(): - new_verts = ((-h/h[0])[1:] for h in t_ieqs) + new_verts = ((-h / h[0])[1:] for h in t_ieqs) else: # Transform the equations such that the normals are pairwise orthogonal. t_eqns = list(t_eqns) for i, h in enumerate(t_eqns): for h1 in t_eqns[:i]: - a = h[1:]*h1[1:] + a = h[1:] * h1[1:] if a: - b = h1[1:]*h1[1:] - t_eqns[i] = b*h - a*h1 + b = h1[1:] * h1[1:] + t_eqns[i] = b * h - a * h1 def move_vertex_to_subspace(vertex): for h in t_eqns: - offset = vertex*h[1:]+h[0] - vertex = vertex-h[1:]*offset/(h[1:]*h[1:]) + offset = vertex * h[1:] + h[0] + vertex = vertex - h[1:] * offset / (h[1:] * h[1:]) return vertex - new_verts = (move_vertex_to_subspace((-h/h[0])[1:]) for h in t_ieqs) + new_verts = (move_vertex_to_subspace((-h / h[0])[1:]) for h in t_ieqs) pref_rep = 'Hrep' if self.n_vertices() <= self.n_inequalities() else 'Vrep' - return parent.element_class(parent, [new_verts, [], []], - [new_ieqs, t_eqns], - Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) + return parent.element_class(parent, [new_verts, [], []], [new_ieqs, t_eqns], Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) def pyramid(self): """ @@ -302,22 +300,19 @@ def pyramid(self): c = self.center() from itertools import chain - new_verts = chain(([0] + x for x in self.Vrep_generator()), - [[1] + list(c)]) - new_ieqs = chain(([i.b()] + [-c*i.A() - i.b()] + list(i.A()) for i in self.inequalities()), - [[0, 1] + [0]*self.ambient_dim()]) + + new_verts = chain(([0] + x for x in self.Vrep_generator()), [[1] + list(c)]) + new_ieqs = chain(([i.b()] + [-c * i.A() - i.b()] + list(i.A()) for i in self.inequalities()), [[0, 1] + [0] * self.ambient_dim()]) new_eqns = ([e.b()] + [0] + list(e.A()) for e in self.equations()) pref_rep = 'Hrep' if self.n_vertices() > self.n_inequalities() else 'Vrep' - parent = self.parent().base_extend(self.center().parent(), ambient_dim=self.ambient_dim()+1) + parent = self.parent().base_extend(self.center().parent(), ambient_dim=self.ambient_dim() + 1) if self.n_vertices() == 1: # Fix the polyhedron with one vertex. return parent.element_class(parent, [new_verts, [], []], None) - return parent.element_class(parent, [new_verts, [], []], - [new_ieqs, new_eqns], - Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) + return parent.element_class(parent, [new_verts, [], []], [new_ieqs, new_eqns], Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) def _test_pyramid(self, tester=None, **options): """ @@ -417,24 +412,21 @@ def bipyramid(self): """ c = self.center() from itertools import chain - new_verts = chain(([0] + list(x) for x in self.vertex_generator()), - [[1] + list(c), [-1] + list(c)]) + + new_verts = chain(([0] + list(x) for x in self.vertex_generator()), [[1] + list(c), [-1] + list(c)]) new_rays = ([0] + r for r in self.rays()) new_lines = ([0] + l for l in self.lines()) - new_ieqs = chain(([i.b()] + [ c*i.A() + i.b()] + list(i.A()) for i in self.inequalities()), - ([i.b()] + [-c*i.A() - i.b()] + list(i.A()) for i in self.inequalities())) + new_ieqs = chain(([i.b()] + [c * i.A() + i.b()] + list(i.A()) for i in self.inequalities()), ([i.b()] + [-c * i.A() - i.b()] + list(i.A()) for i in self.inequalities())) new_eqns = ([e.b()] + [0] + list(e.A()) for e in self.equations()) - pref_rep = 'Hrep' if 2 + (self.n_vertices() + self.n_rays()) >= 2*self.n_inequalities() else 'Vrep' - parent = self.parent().base_extend(self.center().parent(), ambient_dim=self.ambient_dim()+1) + pref_rep = 'Hrep' if 2 + (self.n_vertices() + self.n_rays()) >= 2 * self.n_inequalities() else 'Vrep' + parent = self.parent().base_extend(self.center().parent(), ambient_dim=self.ambient_dim() + 1) if c not in self.relative_interior(): # Fix polyhedra with non-proper center. return parent.element_class(parent, [new_verts, new_rays, new_lines], None) - return parent.element_class(parent, [new_verts, new_rays, new_lines], - [new_ieqs, new_eqns], - Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) + return parent.element_class(parent, [new_verts, new_rays, new_lines], [new_ieqs, new_eqns], Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) def _test_bipyramid(self, tester=None, **options): """ @@ -447,9 +439,7 @@ def _test_bipyramid(self, tester=None, **options): if tester is None: tester = self._tester(**options) - if (self.n_vertices() + self.n_rays() >= 40 - or self.n_facets() >= 40 - or self.n_vertices() <= 1): + if self.n_vertices() + self.n_rays() >= 40 or self.n_facets() >= 40 or self.n_vertices() <= 1: return bipyramid = self.bipyramid() @@ -469,7 +459,7 @@ def _test_bipyramid(self, tester=None, **options): tester.assertEqual(self.n_rays(), bipyramid.n_rays()) tester.assertEqual(self.n_lines(), bipyramid.n_lines()) tester.assertEqual(self.n_equations(), bipyramid.n_equations()) - tester.assertEqual(2*self.n_inequalities(), bipyramid.n_inequalities()) + tester.assertEqual(2 * self.n_inequalities(), bipyramid.n_inequalities()) if not self.is_compact(): # ``is_bipyramid`` is only implemented for compact polyhedra. @@ -507,24 +497,21 @@ def prism(self): 'cdd' """ from itertools import chain - new_verts = chain(([0] + v for v in self.vertices()), - ([1] + v for v in self.vertices())) + + new_verts = chain(([0] + v for v in self.vertices()), ([1] + v for v in self.vertices())) new_rays = ([0] + r for r in self.rays()) new_lines = ([0] + l for l in self.lines()) new_eqns = ([e.b()] + [0] + list(e[1:]) for e in self.equations()) - new_ieqs = chain(([i.b()] + [0] + list(i[1:]) for i in self.inequalities()), - [[0, 1] + [0]*self.ambient_dim(), [1, -1] + [0]*self.ambient_dim()]) + new_ieqs = chain(([i.b()] + [0] + list(i[1:]) for i in self.inequalities()), [[0, 1] + [0] * self.ambient_dim(), [1, -1] + [0] * self.ambient_dim()]) - pref_rep = 'Hrep' if 2*(self.n_vertices() + self.n_rays()) >= self.n_inequalities() + 2 else 'Vrep' - parent = self.parent().change_ring(self.base_ring(), ambient_dim=self.ambient_dim()+1) + pref_rep = 'Hrep' if 2 * (self.n_vertices() + self.n_rays()) >= self.n_inequalities() + 2 else 'Vrep' + parent = self.parent().change_ring(self.base_ring(), ambient_dim=self.ambient_dim() + 1) if not self.vertices(): # Fix the empty polyhedron. return parent.element_class(parent, [[], [], []], None) - return parent.element_class(parent, [new_verts, new_rays, new_lines], - [new_ieqs, new_eqns], - Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) + return parent.element_class(parent, [new_verts, new_rays, new_lines], [new_ieqs, new_eqns], Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) def _test_prism(self, tester=None, **options): """ @@ -547,7 +534,7 @@ def _test_prism(self, tester=None, **options): # Check that the prism preserves the backend. tester.assertEqual(prism.backend(), self.backend()) - tester.assertEqual(2*self.n_vertices(), prism.n_vertices()) + tester.assertEqual(2 * self.n_vertices(), prism.n_vertices()) tester.assertEqual(self.n_rays(), prism.n_rays()) tester.assertEqual(self.n_lines(), prism.n_lines()) tester.assertEqual(self.n_equations(), prism.n_equations()) @@ -568,9 +555,7 @@ def _test_prism(self, tester=None, **options): R = self.base_ring() cert_set = set(frozenset(tuple(v) for v in f) for f in cert) - expected_cert = set(frozenset((i,) + tuple(v) - for v in self.vertices()) - for i in (R(0), R(1))) + expected_cert = set(frozenset((i,) + tuple(v) for v in self.vertices()) for i in (R(0), R(1))) tester.assertEqual(cert_set, expected_cert) def truncation(self, cut_frac=None): @@ -655,7 +640,7 @@ def lawrence_polytope(self): V = self.vertices_matrix().transpose() n = self.n_vertices() I_n = matrix.identity(n) - lambda_V = block_matrix([[V, I_n], [V, 2*I_n]]) + lambda_V = block_matrix([[V, I_n], [V, 2 * I_n]]) parent = self.parent().change_ring(self.base_ring(), ambient_dim=self.ambient_dim() + n) return parent.element_class(parent, [lambda_V, [], []], None) @@ -711,6 +696,7 @@ def deformation_cone(self): 2.2 of [ACEP2020]. """ from .constructor import Polyhedron + m = matrix([ineq.A() for ineq in self.Hrepresentation()]) m = m.transpose() m_ker = m.right_kernel_matrix(basis='computed') @@ -719,8 +705,7 @@ def deformation_cone(self): n = len(gale) c = None for cone_indices in collection: - dual_cone = Polyhedron(rays=[gale[i] for i in range(n) if i not in - cone_indices]) + dual_cone = Polyhedron(rays=[gale[i] for i in range(n) if i not in cone_indices]) c = c.intersection(dual_cone) if c is not None else dual_cone preimages = [m_ker.solve_right(r.vector()) for r in c.rays()] return Polyhedron(lines=m.rows(), rays=preimages) @@ -885,21 +870,21 @@ def minkowski_difference(self, other): A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices """ if other.is_empty(): - return self.parent().universe() # empty intersection = everything + return self.parent().universe() # empty intersection = everything if not other.is_compact(): raise NotImplementedError('only subtracting compact polyhedra is implemented') new_eqns = [] for eq in self.equations(): - values = [ eq.A() * v.vector() for v in other.vertices() ] + values = [eq.A() * v.vector() for v in other.vertices()] eq = list(eq) - eq[0] += min(values) # shift constant term + eq[0] += min(values) # shift constant term new_eqns.append(eq) P = self.parent() new_ieqs = [] for ieq in self.inequalities(): - values = [ ieq.A() * v.vector() for v in other.vertices() ] + values = [ieq.A() * v.vector() for v in other.vertices()] ieq = list(ieq) - ieq[0] += min(values) # shift constant term + ieq[0] += min(values) # shift constant term new_ieqs.append(ieq) # Some vertices might need fractions. @@ -991,22 +976,18 @@ def product(self, other): try: new_ring = self.parent()._coerce_base_ring(other) except TypeError: - raise TypeError("no common canonical parent for objects with parents: " + str(self.parent()) - + " and " + str(other.parent())) + raise TypeError("no common canonical parent for objects with parents: " + str(self.parent()) + " and " + str(other.parent())) from itertools import chain - new_vertices = (tuple(x) + tuple(y) - for x in self.vertex_generator() for y in other.vertex_generator()) + new_vertices = (tuple(x) + tuple(y) for x in self.vertex_generator() for y in other.vertex_generator()) - self_zero = tuple(0 for _ in range( self.ambient_dim())) + self_zero = tuple(0 for _ in range(self.ambient_dim())) other_zero = tuple(0 for _ in range(other.ambient_dim())) - rays = chain((tuple(r) + other_zero for r in self.ray_generator()), - (self_zero + tuple(r) for r in other.ray_generator())) + rays = chain((tuple(r) + other_zero for r in self.ray_generator()), (self_zero + tuple(r) for r in other.ray_generator())) - lines = chain((tuple(l) + other_zero for l in self.line_generator()), - (self_zero + tuple(l) for l in other.line_generator())) + lines = chain((tuple(l) + other_zero for l in self.line_generator()), (self_zero + tuple(l) for l in other.line_generator())) if self.n_vertices() == 0 or other.n_vertices() == 0: # In this case we obtain the empty polyhedron. @@ -1015,23 +996,14 @@ def product(self, other): rays = () lines = () - ieqs = chain((tuple(i) + other_zero - for i in self.inequality_generator()), - ((i.b(),) + self_zero + tuple(i.A()) - for i in other.inequality_generator())) + ieqs = chain((tuple(i) + other_zero for i in self.inequality_generator()), ((i.b(),) + self_zero + tuple(i.A()) for i in other.inequality_generator())) - eqns = chain((tuple(e) + other_zero - for e in self.equation_generator()), - ((e.b(),) + self_zero + tuple(e.A()) - for e in other.equation_generator())) + eqns = chain((tuple(e) + other_zero for e in self.equation_generator()), ((e.b(),) + self_zero + tuple(e.A()) for e in other.equation_generator())) - pref_rep = 'Vrep' if self.n_vertices() + self.n_rays() + other.n_vertices() + other.n_rays() \ - <= self.n_inequalities() + other.n_inequalities() else 'Hrep' + pref_rep = 'Vrep' if self.n_vertices() + self.n_rays() + other.n_vertices() + other.n_rays() <= self.n_inequalities() + other.n_inequalities() else 'Hrep' parent = self.parent().change_ring(new_ring, ambient_dim=self.ambient_dim() + other.ambient_dim()) - return parent.element_class(parent, [new_vertices, rays, lines], - [ieqs, eqns], - Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) + return parent.element_class(parent, [new_vertices, rays, lines], [ieqs, eqns], Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) _mul_ = product @@ -1054,9 +1026,9 @@ def _test_product(self, tester=None, **options): if self.n_vertices() + self.n_rays() < 40 and self.n_facets() < 40: # Check that the product preserves the backend, where possible. P = polytopes.simplex(backend='cdd') - tester.assertEqual((self*P).backend(), self.backend()) + tester.assertEqual((self * P).backend(), self.backend()) Q = polytopes.simplex(backend='ppl') - tester.assertEqual((self*Q).backend(), self.backend()) + tester.assertEqual((self * Q).backend(), self.backend()) # And that it changes the backend correctly where necessary. try: @@ -1065,10 +1037,10 @@ def _test_product(self, tester=None, **options): pass else: if self.base_ring() is not AA and AA.has_coerce_map_from(self.base_ring()): - R = self*polytopes.regular_polygon(5, exact=True) + R = self * polytopes.regular_polygon(5, exact=True) assert R if RDF.has_coerce_map_from(self.base_ring()): - R = self*polytopes.regular_polygon(5, exact=False) + R = self * polytopes.regular_polygon(5, exact=False) assert R if self.base_ring() in (ZZ, QQ): @@ -1081,7 +1053,8 @@ def _test_product(self, tester=None, **options): else: (self_field * P)._test_basic_properties(tester) from .constructor import Polyhedron - Q = Polyhedron(rays=[[1,0,0,0],[0,1,1,0]], lines=[[0,1,0,1]], backend='field') + + Q = Polyhedron(rays=[[1, 0, 0, 0], [0, 1, 1, 0]], lines=[[0, 1, 0, 1]], backend='field') (self_field * Q)._test_basic_properties(tester) def join(self, other): @@ -1149,8 +1122,7 @@ def join(self, other): try: new_ring = self.parent()._coerce_base_ring(other) except TypeError: - raise TypeError("no common canonical parent for objects with parents: " + str(self.parent()) - + " and " + str(other.parent())) + raise TypeError("no common canonical parent for objects with parents: " + str(self.parent()) + " and " + str(other.parent())) from itertools import chain @@ -1158,16 +1130,16 @@ def join(self, other): dim_other = other.ambient_dim() parent = self.parent().change_ring(new_ring, ambient_dim=self.ambient_dim() + other.ambient_dim() + 1) - new_vertices1 = (list(x) + [0]*dim_other + [0] for x in self.vertex_generator()) - new_vertices2 = ([0]*dim_self + list(x) + [1] for x in other.vertex_generator()) + new_vertices1 = (list(x) + [0] * dim_other + [0] for x in self.vertex_generator()) + new_vertices2 = ([0] * dim_self + list(x) + [1] for x in other.vertex_generator()) new_vertices = chain(new_vertices1, new_vertices2) - new_rays1 = (list(r) + [0]*dim_other + [0] for r in self.ray_generator()) - new_rays2 = ([0]*dim_self + list(r) + [1] for r in other.ray_generator()) + new_rays1 = (list(r) + [0] * dim_other + [0] for r in self.ray_generator()) + new_rays2 = ([0] * dim_self + list(r) + [1] for r in other.ray_generator()) new_rays = chain(new_rays1, new_rays2) - new_lines1 = (list(l) + [0]*dim_other + [0] for l in self.line_generator()) - new_lines2 = ([0]*dim_self + list(l) + [1] for l in other.line_generator()) + new_lines1 = (list(l) + [0] * dim_other + [0] for l in self.line_generator()) + new_lines2 = ([0] * dim_self + list(l) + [1] for l in other.line_generator()) new_lines = chain(new_lines1, new_lines2) if not self.is_compact() or not other.is_compact() or self.n_vertices() <= 1 or other.n_vertices() <= 1: @@ -1176,21 +1148,21 @@ def join(self, other): # Facet defining inequalities that contain the corresponding vertices from ``new_vertices1`` # and all vertices from ``new_vertices2``. - new_inequalities1 = ([i[0]] + list(i[1:]) + [0]*dim_other + [-i[0]] for i in self.inequality_generator()) + new_inequalities1 = ([i[0]] + list(i[1:]) + [0] * dim_other + [-i[0]] for i in self.inequality_generator()) # Facet defining inequalities that contain the corresponding vertices from ``new_vertices2`` # and all vertices from ``new_vertices1``. - new_inequalities2 = ([0] + [0]*dim_self + list(i[1:]) + [i[0]] for i in other.inequality_generator()) + new_inequalities2 = ([0] + [0] * dim_self + list(i[1:]) + [i[0]] for i in other.inequality_generator()) new_inequalities = chain(new_inequalities1, new_inequalities2) # Equations that all vertices corresponding to ``new_vertices1`` satisfy. # For any vertex from ``new_vertices2`` the condition is trivial. - new_equations1 = ([e[0]] + list(e[1:]) + [0]*dim_other + [-e[0]] for e in self.equation_generator()) + new_equations1 = ([e[0]] + list(e[1:]) + [0] * dim_other + [-e[0]] for e in self.equation_generator()) # Equations that all vertices corresponding to ``new_vertices2`` satisfy. # For any vertex from ``new_vertices1`` the condition is trivial. - new_equations2 = ([0] + [0]*dim_self + list(e[1:]) + [e[0]] for e in other.equation_generator()) + new_equations2 = ([0] + [0] * dim_self + list(e[1:]) + [e[0]] for e in other.equation_generator()) new_equations = chain(new_equations1, new_equations2) @@ -1200,11 +1172,7 @@ def join(self, other): pref_rep = 'Vrep' if new_n_vertices + new_n_rays <= new_n_inequalities else 'Hrep' - return parent.element_class(parent, - [new_vertices, new_rays, new_lines], - [new_inequalities, new_equations], - Vrep_minimal=True, Hrep_minimal=True, - pref_rep=pref_rep) + return parent.element_class(parent, [new_vertices, new_rays, new_lines], [new_inequalities, new_equations], Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) def subdirect_sum(self, other): """ @@ -1248,24 +1216,18 @@ def subdirect_sum(self, other): try: new_ring = self.parent()._coerce_base_ring(other) except TypeError: - raise TypeError("no common canonical parent for objects with parents: " + str(self.parent()) - + " and " + str(other.parent())) + raise TypeError("no common canonical parent for objects with parents: " + str(self.parent()) + " and " + str(other.parent())) dim_self = self.ambient_dim() dim_other = other.ambient_dim() - new_vertices = [list(x)+[0]*dim_other for x in self.vertex_generator()] + \ - [[0]*dim_self+list(x) for x in other.vertex_generator()] + new_vertices = [list(x) + [0] * dim_other for x in self.vertex_generator()] + [[0] * dim_self + list(x) for x in other.vertex_generator()] new_rays = [] - new_rays.extend( [ r+[0]*dim_other - for r in self.ray_generator() ] ) - new_rays.extend( [ [0]*dim_self+r - for r in other.ray_generator() ] ) + new_rays.extend([r + [0] * dim_other for r in self.ray_generator()]) + new_rays.extend([[0] * dim_self + r for r in other.ray_generator()]) new_lines = [] - new_lines.extend( [ l+[0]*dim_other - for l in self.line_generator() ] ) - new_lines.extend( [ [0]*dim_self+l - for l in other.line_generator() ] ) + new_lines.extend([l + [0] * dim_other for l in self.line_generator()]) + new_lines.extend([[0] * dim_self + l for l in other.line_generator()]) parent = self.parent().change_ring(new_ring, ambient_dim=self.ambient_dim() + other.ambient_dim()) return parent.element_class(parent, [new_vertices, new_rays, new_lines], None) @@ -1322,24 +1284,18 @@ def direct_sum(self, other): # Some vertices might need fractions. new_ring = self.parent()._coerce_base_ring(other).fraction_field() except TypeError: - raise TypeError("no common canonical parent for objects with parents: " + str(self.parent()) - + " and " + str(other.parent())) + raise TypeError("no common canonical parent for objects with parents: " + str(self.parent()) + " and " + str(other.parent())) dim_self = self.ambient_dim() dim_other = other.ambient_dim() - new_vertices = [list(x) + [0]*dim_other for x in self.vertex_generator()] + \ - [list(self.center()) + list(x.vector() - other.center()) for x in other.vertex_generator()] + new_vertices = [list(x) + [0] * dim_other for x in self.vertex_generator()] + [list(self.center()) + list(x.vector() - other.center()) for x in other.vertex_generator()] new_rays = [] - new_rays.extend( [ r + [0]*dim_other - for r in self.ray_generator() ] ) - new_rays.extend( [ [0]*dim_self + r - for r in other.ray_generator() ] ) + new_rays.extend([r + [0] * dim_other for r in self.ray_generator()]) + new_rays.extend([[0] * dim_self + r for r in other.ray_generator()]) new_lines = [] - new_lines.extend( [ l + [0]*dim_other - for l in self.line_generator() ] ) - new_lines.extend( [ [0]*dim_self + l - for l in other.line_generator() ] ) + new_lines.extend([l + [0] * dim_other for l in self.line_generator()]) + new_lines.extend([[0] * dim_self + l for l in other.line_generator()]) parent = self.parent().change_ring(new_ring, ambient_dim=self.ambient_dim() + other.ambient_dim()) return parent.element_class(parent, [new_vertices, new_rays, new_lines], None) @@ -1547,8 +1503,7 @@ def translation(self, displacement): pref_rep = 'Vrep' if self.n_vertices() + self.n_rays() <= self.n_inequalities() else 'Hrep' - return parent.element_class(parent, Vrep, Hrep, - Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) + return parent.element_class(parent, Vrep, Hrep, Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) def _translation_double_description(self, displacement): r""" @@ -1575,7 +1530,7 @@ def _translation_double_description(self, displacement): Polyhedra in ZZ^2) """ displacement = vector(displacement) - new_vertices = (x.vector()+displacement for x in self.vertex_generator()) + new_vertices = (x.vector() + displacement for x in self.vertex_generator()) new_rays = self.rays() new_lines = self.lines() parent = self.parent().base_extend(displacement) @@ -1585,7 +1540,7 @@ def _translation_double_description(self, displacement): # Likewise for equations. def get_new(x): y = x.vector().change_ring(parent.base_ring()) - y[0] -= x.A()*displacement + y[0] -= x.A() * displacement return y new_ieqs = (get_new(x) for x in self.inequality_generator()) @@ -1649,20 +1604,17 @@ def dilation(self, scalar): one = parent.base_ring().one() sign = one if scalar > 0 else -one - make_new_Hrep = lambda h: tuple(scalar*sign*x if i == 0 else sign*x - for i, x in enumerate(h._vector)) + make_new_Hrep = lambda h: tuple(scalar * sign * x if i == 0 else sign * x for i, x in enumerate(h._vector)) - new_vertices = (tuple(scalar*x for x in v._vector) for v in self.vertex_generator()) - new_rays = (tuple(sign*x for x in r._vector) for r in self.ray_generator()) + new_vertices = (tuple(scalar * x for x in v._vector) for v in self.vertex_generator()) + new_rays = (tuple(sign * x for x in r._vector) for r in self.ray_generator()) new_lines = self.line_generator() new_inequalities = map(make_new_Hrep, self.inequality_generator()) new_equations = map(make_new_Hrep, self.equation_generator()) pref_rep = 'Vrep' if self.n_vertices() + self.n_rays() <= self.n_inequalities() else 'Hrep' - return parent.element_class(parent, [new_vertices, new_rays, new_lines], - [new_inequalities, new_equations], - Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) + return parent.element_class(parent, [new_vertices, new_rays, new_lines], [new_inequalities, new_equations], Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) def __truediv__(self, scalar): """ @@ -1678,7 +1630,7 @@ def __truediv__(self, scalar): sage: (p/int(5)).Vrepresentation() (A vertex at (0.4, 0.8, 1.6), A vertex at (0.6, 1.8, 5.4)) """ - return self.dilation(1/scalar) + return self.dilation(1 / scalar) def _test_dilation(self, tester=None, **options): """ @@ -1695,7 +1647,7 @@ def _test_dilation(self, tester=None, **options): tester = self._tester(**options) # Testing that the backend is preserved. - tester.assertEqual(self.dilation(2*self.base_ring().gen()).backend(), self.backend()) + tester.assertEqual(self.dilation(2 * self.base_ring().gen()).backend(), self.backend()) tester.assertEqual(self.dilation(ZZ(3)).backend(), self.backend()) if self.n_vertices() + self.n_rays() > 40: @@ -1707,11 +1659,11 @@ def _test_dilation(self, tester=None, **options): if self.base_ring() in (QQ, ZZ): p = self.base_extend(self.base_ring(), backend='field') (ZZ(2) * p)._test_basic_properties(tester) - (ZZ(2)/2 * p)._test_basic_properties(tester) + (ZZ(2) / 2 * p)._test_basic_properties(tester) (ZZ(-3) * p)._test_basic_properties(tester) - (ZZ(-1)/2 * p)._test_basic_properties(tester) + (ZZ(-1) / 2 * p)._test_basic_properties(tester) else: - tester.assertIsInstance(ZZ(1)/3*self, Polyhedron_base) + tester.assertIsInstance(ZZ(1) / 3 * self, Polyhedron_base) try: from sage.rings.qqbar import AA @@ -1724,18 +1676,19 @@ def _test_dilation(self, tester=None, **options): # Some sanity check on the volume (only run for relatively small instances). if self.dim() > -1 and self.is_compact() and self.base_ring().is_exact(): - tester.assertEqual(self.dilation(3).volume(measure='induced'), self.volume(measure='induced')*3**self.dim()) + tester.assertEqual(self.dilation(3).volume(measure='induced'), self.volume(measure='induced') * 3 ** self.dim()) # Testing coercion with algebraic numbers. from sage.rings.number_field.number_field import QuadraticField + K1 = QuadraticField(2, embedding=AA(2).sqrt()) sqrt2 = K1.gen() K2 = QuadraticField(3, embedding=AA(3).sqrt()) sqrt3 = K2.gen() if self.base_ring() in (QQ, ZZ, AA, RDF): - tester.assertIsInstance(sqrt2*self, Polyhedron_base) - tester.assertIsInstance(sqrt3*self, Polyhedron_base) + tester.assertIsInstance(sqrt2 * self, Polyhedron_base) + tester.assertIsInstance(sqrt3 * self, Polyhedron_base) elif hasattr(self.base_ring(), "composite_fields"): for scalar, K in ((sqrt2, K1), (sqrt3, K2)): new_ring = None @@ -1746,10 +1699,9 @@ def _test_dilation(self, tester=None, **options): pass if new_ring: p = self.change_ring(new_ring) - tester.assertIsInstance(scalar*p, Polyhedron_base) + tester.assertIsInstance(scalar * p, Polyhedron_base) - def linear_transformation(self, linear_transf, - new_base_ring=None): + def linear_transformation(self, linear_transf, new_base_ring=None): """ Return the linear transformation of ``self``. @@ -1889,15 +1841,15 @@ def linear_transformation(self, linear_transf, # Still we create generators, as possibly the Vrepresentation # will be discarded later on. if self.n_vertices(): - new_vertices = iter((linear_transf*self.vertices_matrix(R)).transpose()) + new_vertices = iter((linear_transf * self.vertices_matrix(R)).transpose()) else: new_vertices = () if self.n_rays(): - new_rays = iter(matrix(R, self.rays())*linear_transf.transpose()) + new_rays = iter(matrix(R, self.rays()) * linear_transf.transpose()) else: new_rays = () if self.n_lines(): - new_lines = iter(matrix(R, self.lines())*linear_transf.transpose()) + new_lines = iter(matrix(R, self.lines()) * linear_transf.transpose()) else: new_lines = () @@ -1906,7 +1858,7 @@ def linear_transformation(self, linear_transf, # To convert first to a list and then to a matrix seems to be necessary to obtain a meaningful error, # in case the number of columns doesn't match the dimension. - new_homogeneous_basis = matrix([[1] + list(linear_transf*vector(R, v)) for v in self.an_affine_basis()]).transpose() + new_homogeneous_basis = matrix([[1] + list(linear_transf * vector(R, v)) for v in self.an_affine_basis()]).transpose() if self.dim() + 1 == new_homogeneous_basis.rank(): # The transformation is injective on the polytope. @@ -1923,7 +1875,7 @@ def linear_transformation(self, linear_transf, # Note that such N must exist, as our map is injective on the polytope. # It is uniquely defined by considering a basis of the homogeneous vertices. N = new_homogeneous_basis.solve_left(homogeneous_basis) - new_inequalities = iter(matrix(R, self.inequalities())*N) + new_inequalities = iter(matrix(R, self.inequalities()) * N) # The equations are the left kernel matrix of the homogeneous vertices # or equivalently a basis thereof. @@ -1946,9 +1898,7 @@ def linear_transformation(self, linear_transf, # Set up with both Vrepresentation and Hrepresentation. pref_rep = 'Vrep' if self.n_vertices() <= self.n_inequalities() else 'Hrep' - return new_parent.element_class(new_parent, [new_vertices, new_rays, new_lines], - [new_inequalities, new_equations], - Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) + return new_parent.element_class(new_parent, [new_vertices, new_rays, new_lines], [new_inequalities, new_equations], Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) return new_parent.element_class(new_parent, [tuple(new_vertices), tuple(new_rays), tuple(new_lines)], None) @@ -1969,6 +1919,7 @@ def _test_linear_transformation(self, tester=None, **options): # Check that :issue:`30146` is fixed. from sage.matrix.special import identity_matrix + tester.assertEqual(self, self.linear_transformation(identity_matrix(self.ambient_dim()))) ########################################################### @@ -2117,18 +2068,16 @@ def face_truncation(self, face, linear_coefficients=None, cut_frac=None): normal_vectors = [] for facet in self.Hrepresentation(): - if all(facet.contains(x) and not facet.interior_contains(x) - for x in face_vertices): + if all(facet.contains(x) and not facet.interior_contains(x) for x in face_vertices): # The facet contains the face normal_vectors.append(facet.A()) if linear_coefficients is not None: - normal_vector = sum(linear_coefficients[i]*normal_vectors[i] - for i in range(len(normal_vectors))) + normal_vector = sum(linear_coefficients[i] * normal_vectors[i] for i in range(len(normal_vectors))) else: normal_vector = sum(normal_vectors) - B = - normal_vector * (face_vertices[0].vector()) + B = -normal_vector * (face_vertices[0].vector()) linear_evaluation = set(-normal_vector * (v.vector()) for v in self.vertices()) @@ -2144,7 +2093,7 @@ def face_truncation(self, face, linear_coefficients=None, cut_frac=None): new_eqns = self.equations_list() # Some vertices might need fractions. - parent = self.parent().base_extend(cut_frac/1) + parent = self.parent().base_extend(cut_frac / 1) return parent.element_class(parent, None, [new_ieqs, new_eqns]) def stack(self, face, position=None): @@ -2269,6 +2218,7 @@ def stack(self, face, position=None): A 4-dimensional polyhedron in QQ^4 defined as the convex hull of 9 vertices """ from sage.geometry.polyhedron.face import PolyhedronFace + if not isinstance(face, PolyhedronFace): raise TypeError("{} should be a PolyhedronFace of {}".format(face, self)) elif face.dim() == 0: @@ -2278,10 +2228,10 @@ def stack(self, face, position=None): if position is None: position = 1 - barycenter = ZZ.one()*sum([v.vector() for v in face.vertices()]) / len(face.vertices()) + barycenter = ZZ.one() * sum([v.vector() for v in face.vertices()]) / len(face.vertices()) locus_polyhedron = face.stacking_locus() repr_point = locus_polyhedron.representative_point() - new_vertex = (1-position)*barycenter + position*repr_point + new_vertex = (1 - position) * barycenter + position * repr_point if not locus_polyhedron.relative_interior_contains(new_vertex): raise ValueError("the chosen position is too large") @@ -2391,7 +2341,7 @@ def wedge(self, face, width=1): Real Double Field 'cdd' """ - width = width*ZZ.one() + width = width * ZZ.one() if not self.is_compact(): raise ValueError("polyhedron 'self' must be a polytope") @@ -2400,10 +2350,11 @@ def wedge(self, face, width=1): raise ValueError("the width should be nonzero") from sage.geometry.polyhedron.face import PolyhedronFace + if not isinstance(face, PolyhedronFace): raise TypeError("{} should be a PolyhedronFace of {}".format(face, self)) - F_Hrep = vector([0]*(self.ambient_dim()+1)) + F_Hrep = vector([0] * (self.ambient_dim() + 1)) for facet in face.ambient_Hrepresentation(): if facet.is_inequality(): F_Hrep = F_Hrep + facet.vector() @@ -2456,22 +2407,21 @@ def face_split(self, face): """ from sage.geometry.polyhedron.representation import Vertex from sage.geometry.polyhedron.face import PolyhedronFace + if isinstance(face, Vertex): - new_vertices = [list(x) + [0] for x in self.vertex_generator()] + \ - [list(face) + [x] for x in [-1, 1]] # Splitting the vertex + new_vertices = [list(x) + [0] for x in self.vertex_generator()] + [list(face) + [x] for x in [-1, 1]] # Splitting the vertex elif isinstance(face, PolyhedronFace): - new_vertices = [list(x) + [0] for x in self.vertex_generator()] + \ - [list(face.as_polyhedron().center()) + [x] for x in [-1, 1]] # Splitting the face + new_vertices = [list(x) + [0] for x in self.vertex_generator()] + [list(face.as_polyhedron().center()) + [x] for x in [-1, 1]] # Splitting the face else: raise TypeError("the face {} should be a Vertex or PolyhedronFace".format(face)) new_rays = [] - new_rays.extend( [ r + [0] for r in self.ray_generator() ] ) + new_rays.extend([r + [0] for r in self.ray_generator()]) new_lines = [] - new_lines.extend( [ l + [0] for l in self.line_generator() ] ) + new_lines.extend([l + [0] for l in self.line_generator()]) - parent = self.parent().change_ring(self.base_ring().fraction_field(), ambient_dim=self.ambient_dim()+1) + parent = self.parent().change_ring(self.base_ring().fraction_field(), ambient_dim=self.ambient_dim() + 1) return parent.element_class(parent, [new_vertices, new_rays, new_lines], None) ########################################################### @@ -2512,7 +2462,7 @@ def lawrence_extension(self, v): if self.contains(v) and (v not in V): raise ValueError("{} must not be a vertex or outside self".format(v)) - lambda_V = [u + [0] for u in V if u != v] + [v+[1]] + [v+[2]] + lambda_V = [u + [0] for u in V if u != v] + [v + [1]] + [v + [2]] parent = self.parent().base_extend(vector(v), ambient_dim=self.ambient_dim() + 1) return parent.element_class(parent, [lambda_V, [], []], None) @@ -2555,7 +2505,8 @@ def _test_lawrence(self, tester=None, **options): if self.n_vertices(): from sage.misc.prandom import randint - v = self.vertices()[randint(0, self.n_vertices()-1)].vector() + + v = self.vertices()[randint(0, self.n_vertices() - 1)].vector() # A lawrence extension with a vertex. P = self.lawrence_extension(v) @@ -2565,7 +2516,7 @@ def _test_lawrence(self, tester=None, **options): if self.n_vertices() > 1: # A lawrence extension with a point outside of the polyhedron. - Q = self.lawrence_extension(2*v - self.center()) + Q = self.lawrence_extension(2 * v - self.center()) tester.assertEqual(self.dim() + 1, Q.dim()) tester.assertEqual(self.n_vertices() + 2, Q.n_vertices()) tester.assertEqual(self.backend(), Q.backend()) # Any backend should handle the fraction field. @@ -2576,6 +2527,7 @@ def _test_lawrence(self, tester=None, **options): warnings.simplefilter("error") try: from sage.rings.real_double_field import RDF + two = RDF(2.0) # Implicitly checks :issue:`30328`. R = self.lawrence_extension(two * v - self.center()) @@ -2599,7 +2551,7 @@ def _test_lawrence(self, tester=None, **options): P = self.lawrence_polytope() tester.assertEqual(self.dim() + self.n_vertices(), P.dim()) - tester.assertEqual(self.n_vertices()*2, P.n_vertices()) + tester.assertEqual(self.n_vertices() * 2, P.n_vertices()) tester.assertEqual(self.backend(), P.backend()) tester.assertTrue(P.is_lawrence_polytope()) @@ -2608,7 +2560,7 @@ def _test_lawrence(self, tester=None, **options): Q = self i = 0 for v in V: - v = v + i*[0] + v = v + i * [0] Q = Q.lawrence_extension(v) i = i + 1 tester.assertEqual(P, Q) @@ -2662,6 +2614,7 @@ def one_point_suspension(self, vertex): """ from sage.geometry.polyhedron.representation import Vertex from sage.geometry.polyhedron.face import PolyhedronFace + if isinstance(vertex, Vertex): return self.face_split(vertex) if isinstance(vertex, PolyhedronFace) and vertex.dim() == 0: diff --git a/src/sage/geometry/polyhedron/base6.py b/src/sage/geometry/polyhedron/base6.py index 91f68c860d1..fec033f36cc 100644 --- a/src/sage/geometry/polyhedron/base6.py +++ b/src/sage/geometry/polyhedron/base6.py @@ -141,12 +141,8 @@ class Polyhedron_base6(Polyhedron_base5): sage: Polyhedron_base6.affine_hull_projection(R) A 5-dimensional polyhedron in ZZ^5 defined as the convex hull of 6 vertices """ - def plot(self, - point=None, line=None, polygon=None, # None means unspecified by the user - wireframe='blue', fill='green', - position=None, - orthonormal=True, # whether to use orthonormal projections - **kwds): + + def plot(self, point=None, line=None, polygon=None, wireframe='blue', fill='green', position=None, orthonormal=True, **kwds): # None means unspecified by the user # whether to use orthonormal projections r""" Return a graphical representation. @@ -407,6 +403,7 @@ def plot(self, sage: quarter.plot(fill='rainbow') # check it is not all black nor with too many colors # needs sage.plot Graphics3d Object """ + def merge_options(*opts): merged = dict() for i in range(len(opts)): @@ -422,10 +419,9 @@ def merge_options(*opts): return merged d = min(self.dim(), 2) - opts = [wireframe] * d + [fill] + [False] * (2-d) + opts = [wireframe] * d + [fill] + [False] * (2 - d) # The point/line/polygon options take precedence over wireframe/fill - opts = [merge_options(opt1, opt2, kwds) - for opt1, opt2 in zip(opts, [point, line, polygon])] + opts = [merge_options(opt1, opt2, kwds) for opt1, opt2 in zip(opts, [point, line, polygon])] def project(polyhedron, ortho): if polyhedron.ambient_dim() <= 3: @@ -443,8 +439,7 @@ def project(polyhedron, ortho): try: plot_method = projection.plot except AttributeError: - raise NotImplementedError('plotting of {0}-dimensional polyhedra not implemented' - .format(self.ambient_dim())) + raise NotImplementedError('plotting of {0}-dimensional polyhedra not implemented'.format(self.ambient_dim())) return plot_method(*opts) def show(self, **kwds): @@ -475,10 +470,7 @@ def show(self, **kwds): """ self.plot(**kwds).show() - def tikz(self, view=[0, 0, 1], angle=0, scale=1, - edge_color='blue!95!black', facet_color='blue!95!black', - opacity=0.8, vertex_color='green', axis=False, - output_type=None): + def tikz(self, view=[0, 0, 1], angle=0, scale=1, edge_color='blue!95!black', facet_color='blue!95!black', opacity=0.8, vertex_color='green', axis=False, output_type=None): r""" Return a tikz picture of ``self`` as a string or as a :class:`~sage.misc.latex_standalone.TikzPicture` @@ -599,10 +591,7 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, \end{document} sage: path_to_file = t.pdf() # not tested """ - return self.projection().tikz(view, angle, scale, - edge_color, facet_color, - opacity, vertex_color, axis, - output_type=output_type) + return self.projection().tikz(view, angle, scale, edge_color, facet_color, opacity, vertex_color, axis, output_type=output_type) def _rich_repr_(self, display_manager, **kwds): r""" @@ -628,8 +617,8 @@ def _rich_repr_(self, display_manager, **kwds): sage: dm.preferences.supplemental_plot = 'never' """ prefs = display_manager.preferences - is_small = (self.ambient_dim() <= 2) - can_plot = (prefs.supplemental_plot != 'never') + is_small = self.ambient_dim() <= 2 + can_plot = prefs.supplemental_plot != 'never' plot_graph = can_plot and (prefs.supplemental_plot == 'always' or is_small) # Under certain circumstances we display the plot as graphics if plot_graph: @@ -645,7 +634,7 @@ def _rich_repr_(self, display_manager, **kwds): text = repr(self) # latex() produces huge tikz environment, override tp = display_manager.types - if (prefs.text == 'latex' and tp.OutputLatex in display_manager.supported_output()): + if prefs.text == 'latex' and tp.OutputLatex in display_manager.supported_output(): return tp.OutputLatex(r'\text{{{0}}}'.format(text)) return tp.OutputPlainText(text) @@ -695,8 +684,7 @@ def gale_transform(self): if not self.is_compact(): raise ValueError('not a polytope') - A = matrix(self.n_vertices(), - [[1]+x for x in self.vertex_generator()]) + A = matrix(self.n_vertices(), [[1] + x for x in self.vertex_generator()]) A = A.transpose() A_ker = A.right_kernel_matrix(basis='computed') return tuple(A_ker.columns()) @@ -721,7 +709,7 @@ def _test_gale_transform(self, tester=None, **options): # Check :issue:`29073`. if not self.base_ring().is_exact() and self.ambient_dim() > 0: g = self.gale_transform() - tester.assertTrue(sum(g).norm() < 1e-10 or sum(g).norm()/matrix(g).norm() < 1e-13) + tester.assertTrue(sum(g).norm() < 1e-10 or sum(g).norm() / matrix(g).norm() < 1e-13) return # Prevent very long doctests. @@ -731,11 +719,13 @@ def _test_gale_transform(self, tester=None, **options): if not self.is_empty(): # ``gale_transform_to_polytope`` needs at least one vertex to work. from sage.geometry.polyhedron.library import gale_transform_to_polytope + g = self.gale_transform() P = gale_transform_to_polytope(g, base_ring=self.base_ring(), backend=self.backend()) try: import sage.graphs.graph + assert sage.graphs.graph # to muffle pyflakes except ImportError: pass @@ -767,6 +757,7 @@ def projection(self, projection=None): The projection of a polyhedron into 3 dimensions """ from .plot import Projection + if projection is not None: self.projection = Projection(self, projection) else: @@ -899,10 +890,7 @@ def affine_hull(self, *args, **kwds): return self_as_face.affine_tangent_cone() @cached_method - def _affine_hull_projection(self, *, - as_convex_set=True, as_affine_map=True, as_section_map=True, - orthogonal=False, orthonormal=False, - extend=False, minimal=False): + def _affine_hull_projection(self, *, as_convex_set=True, as_affine_map=True, as_section_map=True, orthogonal=False, orthonormal=False, extend=False, minimal=False): r""" Return ``self`` projected into its affine hull. @@ -977,10 +965,7 @@ def _affine_hull_projection(self, *, if as_convex_set: result.image = self if as_affine_map: - identity = linear_transformation(matrix(self.base_ring(), - self.dim(), - self.dim(), - self.base_ring().one())) + identity = linear_transformation(matrix(self.base_ring(), self.dim(), self.dim(), self.base_ring().one())) result.projection_linear_map = result.section_linear_map = identity result.projection_translation = result.section_translation = self.ambient_space().zero() elif orthogonal or orthonormal: @@ -1003,10 +988,12 @@ def _affine_hull_projection(self, *, if not extend: raise ValueError('the base ring needs to be extended; try with "extend=True"') from sage.rings.qqbar import AA + M = matrix(AA, M) A = M.gram_schmidt(orthonormal=orthonormal)[0] if minimal: from sage.rings.qqbar import number_field_elements_from_algebraics + new_ring = number_field_elements_from_algebraics(A.list(), embedded=True, minimal=True)[0] A = A.change_ring(new_ring) L = linear_transformation(A, side='right') @@ -1040,18 +1027,17 @@ def _affine_hull_projection(self, *, M = matrix(gens) pivots = M.pivots() - A = matrix(self.base_ring(), len(pivots), self.ambient_dim(), - [[1 if j == i else 0 for j in range(self.ambient_dim())] for i in pivots]) + A = matrix(self.base_ring(), len(pivots), self.ambient_dim(), [[1 if j == i else 0 for j in range(self.ambient_dim())] for i in pivots]) if as_affine_map: image_translation = vector(self.base_ring(), self.dim()) L = linear_transformation(A, side='right') result.projection_linear_map = L result.projection_translation = image_translation if as_convex_set: - result.image = A*self + result.image = A * self if as_section_map: if self.dim(): - B = M.transpose()/(A*M.transpose()) + B = M.transpose() / (A * M.transpose()) else: B = matrix(self.ambient_dim(), 0) L_section = linear_transformation(B, side='right') @@ -1060,12 +1046,7 @@ def _affine_hull_projection(self, *, return result - def affine_hull_projection(self, - as_polyhedron=None, as_affine_map=False, - orthogonal=False, orthonormal=False, - extend=False, minimal=False, - return_all_data=False, - *, as_convex_set=None): + def affine_hull_projection(self, as_polyhedron=None, as_affine_map=False, orthogonal=False, orthonormal=False, extend=False, minimal=False, return_all_data=False, *, as_convex_set=None): r""" Return the polyhedron projected into its affine hull. @@ -1486,11 +1467,7 @@ def affine_hull_projection(self, """ if as_polyhedron is not None: as_convex_set = as_polyhedron - return super().affine_hull_projection( - as_convex_set=as_convex_set, as_affine_map=as_affine_map, - orthogonal=orthogonal, orthonormal=orthonormal, - extend=extend, minimal=minimal, - return_all_data=return_all_data) + return super().affine_hull_projection(as_convex_set=as_convex_set, as_affine_map=as_affine_map, orthogonal=orthogonal, orthonormal=orthonormal, extend=extend, minimal=minimal, return_all_data=return_all_data) def _test_affine_hull_projection(self, tester=None, verbose=False, **options): r""" @@ -1520,18 +1497,11 @@ def _test_affine_hull_projection(self, tester=None, verbose=False, **options): data_sets = [] data_sets.append(self.affine_hull_projection(return_all_data=True)) if self.is_compact(): - data_sets.append(self.affine_hull_projection(return_all_data=True, - orthogonal=True, - extend=True)) + data_sets.append(self.affine_hull_projection(return_all_data=True, orthogonal=True, extend=True)) if AA is not None: try: - data_sets.append(self.affine_hull_projection(return_all_data=True, - orthonormal=True, - extend=True)) - data_sets.append(self.affine_hull_projection(return_all_data=True, - orthonormal=True, - extend=True, - minimal=True)) + data_sets.append(self.affine_hull_projection(return_all_data=True, orthonormal=True, extend=True)) + data_sets.append(self.affine_hull_projection(return_all_data=True, orthonormal=True, extend=True, minimal=True)) except ModuleNotFoundError: pass @@ -1539,18 +1509,14 @@ def _test_affine_hull_projection(self, tester=None, verbose=False, **options): if verbose: print("Running test number {}".format(i)) M = data.projection_linear_map.matrix().transpose() - tester.assertEqual(self.linear_transformation(M, new_base_ring=M.base_ring()) - + data.projection_translation, - data.image) + tester.assertEqual(self.linear_transformation(M, new_base_ring=M.base_ring()) + data.projection_translation, data.image) M = data.section_linear_map.matrix().transpose() if M.base_ring() is AA: self_extend = self.change_ring(AA) else: self_extend = self - tester.assertEqual(data.image.linear_transformation(M) - + data.section_translation, - self_extend) + tester.assertEqual(data.image.linear_transformation(M) + data.section_translation, self_extend) if i == 0: tester.assertEqual(data.image.base_ring(), self.base_ring()) else: @@ -1565,8 +1531,7 @@ def _test_affine_hull_projection(self, tester=None, verbose=False, **options): if self.base_ring() is not AA: tester.assertIsNot(data.image.base_ring(), AA) - def affine_hull_manifold(self, name=None, latex_name=None, start_index=0, ambient_space=None, - ambient_chart=None, names=None, **kwds): + def affine_hull_manifold(self, name=None, latex_name=None, start_index=0, ambient_space=None, ambient_chart=None, names=None, **kwds): r""" Return the affine hull of ``self`` as a manifold. @@ -1649,6 +1614,7 @@ def affine_hull_manifold(self, name=None, latex_name=None, start_index=0, ambien ambient_space = ambient_chart.manifold() else: from sage.manifolds.differentiable.examples.euclidean import EuclideanSpace + ambient_space = EuclideanSpace(self.ambient_dim(), start_index=start_index) if ambient_space.dimension() != self.ambient_dim(): raise ValueError('ambient_space and ambient_chart must match the ambient dimension') @@ -1661,10 +1627,10 @@ def affine_hull_manifold(self, name=None, latex_name=None, start_index=0, ambien CE = ambient_chart from sage.manifolds.manifold import Manifold + if name is None: name, latex_name = self._affine_hull_name_latex_name() - H = Manifold(self.dim(), name, ambient=ambient_space, structure='Riemannian', - latex_name=latex_name, start_index=start_index) + H = Manifold(self.dim(), name, ambient=ambient_space, structure='Riemannian', latex_name=latex_name, start_index=start_index) if names is None: names = tuple(f'x{i}' for i in range(self.dim())) CH = H.chart(names=names) @@ -1676,23 +1642,18 @@ def affine_hull_manifold(self, name=None, latex_name=None, start_index=0, ambien section_translation_vector = data.section_translation from sage.symbolic.ring import SR + # We use the slacks of the (linear independent) equations as the foliation parameters foliation_parameters = vector(SR.var(f't{i}') for i in range(self.ambient_dim() - self.dim())) normal_matrix = matrix(equation.A() for equation in self.equation_generator()).transpose() slack_matrix = normal_matrix.pseudoinverse() - phi = H.diff_map(ambient_space, {(CH, CE): - (section_matrix * vector(CH._xx) + section_translation_vector - + normal_matrix * foliation_parameters).list()}) - phi_inv = ambient_space.diff_map(H, {(CE, CH): - (projection_matrix * vector(CE._xx) + projection_translation_vector).list()}) + phi = H.diff_map(ambient_space, {(CH, CE): (section_matrix * vector(CH._xx) + section_translation_vector + normal_matrix * foliation_parameters).list()}) + phi_inv = ambient_space.diff_map(H, {(CE, CH): (projection_matrix * vector(CE._xx) + projection_translation_vector).list()}) - foliation_scalar_fields = {parameter: - ambient_space.scalar_field({CE: slack_matrix.row(i) * (vector(CE._xx) - section_translation_vector)}) - for i, parameter in enumerate(foliation_parameters)} + foliation_scalar_fields = {parameter: ambient_space.scalar_field({CE: slack_matrix.row(i) * (vector(CE._xx) - section_translation_vector)}) for i, parameter in enumerate(foliation_parameters)} - H.set_embedding(phi, inverse=phi_inv, - var=list(foliation_parameters), t_inverse=foliation_scalar_fields) + H.set_embedding(phi, inverse=phi_inv, var=list(foliation_parameters), t_inverse=foliation_scalar_fields) return H def _affine_hull_name_latex_name(self, name=None, latex_name=None): diff --git a/src/sage/geometry/polyhedron/base7.py b/src/sage/geometry/polyhedron/base7.py index e0173a04f60..ddaf5b0af4e 100644 --- a/src/sage/geometry/polyhedron/base7.py +++ b/src/sage/geometry/polyhedron/base7.py @@ -56,6 +56,7 @@ class Polyhedron_base7(Polyhedron_base6): sage: Polyhedron_base7.volume(P, measure='induced') 79/3 """ + @cached_method(do_pickle=True) def centroid(self, engine='auto', **kwds): r""" @@ -132,13 +133,14 @@ def centroid(self, engine='auto', **kwds): pc = triangulation.point_configuration() else: from sage.geometry.triangulation.point_configuration import PointConfiguration + A, b = self.affine_hull_projection(as_affine_map=True, orthogonal=True, orthonormal=True, extend=True) pc = PointConfiguration(A(v.vector()) for v in self.Vrep_generator()) - barycenters = [sum(self.Vrepresentation(i).vector() for i in simplex)/(self.dim() + 1) for simplex in triangulation] + barycenters = [sum(self.Vrepresentation(i).vector() for i in simplex) / (self.dim() + 1) for simplex in triangulation] volumes = [pc.volume(simplex) for simplex in triangulation] - centroid = sum(volumes[i]*barycenters[i] for i in range(len(volumes)))/sum(volumes) + centroid = sum(volumes[i] * barycenters[i] for i in range(len(volumes))) / sum(volumes) if self.ambient_dim() != self.dim(): # By the affine hull projection, the centroid has base ring ``AA``, # we try return the centroid in a reasonable ring. @@ -286,9 +288,9 @@ def triangulate(self, engine='auto', connected=True, fine=False, regular=None, s if not self.is_compact() and engine != 'normaliz': raise NotImplementedError("triangulation of pointed polyhedra requires 'normaliz'") from sage.geometry.triangulation.point_configuration import PointConfiguration + if self.is_compact(): - pc = PointConfiguration((v.vector() for v in self.vertex_generator()), - connected=connected, fine=fine, regular=regular, star=star) + pc = PointConfiguration((v.vector() for v in self.vertex_generator()), connected=connected, fine=fine, regular=regular, star=star) # If the engine is not normaliz, we pass directly to the # PointConfiguration module. if engine != 'normaliz': @@ -297,15 +299,14 @@ def triangulate(self, engine='auto', connected=True, fine=False, regular=None, s return pc(self._triangulate_normaliz()) # From above, we have a pointed cone and the engine is normaliz try: - pc = PointConfiguration((v.vector() for v in self.ray_generator()), - connected=connected, fine=fine, regular=regular, star=star) + pc = PointConfiguration((v.vector() for v in self.ray_generator()), connected=connected, fine=fine, regular=regular, star=star) return pc(self._triangulate_normaliz()) except AssertionError: # PointConfiguration is not adapted to inhomogeneous cones # This is a hack. TODO: Implement the necessary things in # PointConfiguration to accept such cases. c = self.representative_point() - normed_v = ((1/(r.vector()*c))*r.vector() for r in self.ray_generator()) + normed_v = ((1 / (r.vector() * c)) * r.vector() for r in self.ray_generator()) pc = PointConfiguration(normed_v, connected=connected, fine=fine, regular=regular, star=star) return pc(self._triangulate_normaliz()) @@ -329,6 +330,7 @@ def _volume_lrs(self, verbose=False): - David Avis's lrs program. """ from sage.features.lrs import Lrs + Lrs().require() from sage.misc.temporary_file import tmp_filename @@ -343,8 +345,7 @@ def _volume_lrs(self, verbose=False): if verbose: print(in_str) - lrs_procs = Popen([Lrs().absolute_filename(), in_filename], - stdin=PIPE, stdout=PIPE, stderr=PIPE) + lrs_procs = Popen([Lrs().absolute_filename(), in_filename], stdin=PIPE, stdout=PIPE, stderr=PIPE) ans, err = lrs_procs.communicate() ans = bytes_to_str(ans) err = bytes_to_str(err) @@ -668,8 +669,9 @@ def volume(self, measure='ambient', engine='auto', **kwds): sage: F2 = Polyhedron([[sqrt2,0],[0,sqrt3]]) sage: F2.volume(measure="induced") 2.236067977499790? - """ + """ from sage.features import FeatureNotPresentError + if measure == 'induced_rational' and engine not in ['auto', 'latte', 'normaliz']: raise RuntimeError("the induced rational measure can only be computed with the engine set to `auto`, `latte`, or `normaliz`") if measure == 'induced_lattice' and engine not in ['auto', 'latte', 'normaliz']: @@ -677,11 +679,13 @@ def volume(self, measure='ambient', engine='auto', **kwds): if engine == 'auto' and measure == 'induced_rational': # Enforce a default choice, change if a better engine is found. from sage.features.latte import Latte + try: Latte().require() engine = 'latte' except FeatureNotPresentError: from sage.features.normaliz import PyNormaliz + try: PyNormaliz().require() engine = 'normaliz' @@ -691,12 +695,14 @@ def volume(self, measure='ambient', engine='auto', **kwds): if engine == 'auto' and measure == 'induced_lattice': # Enforce a default choice, change if a better engine is found. from sage.features.normaliz import PyNormaliz + try: PyNormaliz().require() engine = 'normaliz' except FeatureNotPresentError: try: from sage.features.latte import Latte + Latte().require() engine = 'latte' except FeatureNotPresentError: @@ -713,6 +719,7 @@ def volume(self, measure='ambient', engine='auto', **kwds): # if the polyhedron is unbounded, return infinity if not self.is_compact(): from sage.rings.infinity import infinity + return infinity if engine == 'lrs': return self._volume_lrs(**kwds) @@ -731,6 +738,7 @@ def volume(self, measure='ambient', engine='auto', **kwds): # if the polyhedron is unbounded, return infinity if not self.is_compact(): from sage.rings.infinity import infinity + return infinity if engine == 'normaliz': return self._volume_normaliz(measure='euclidean') @@ -743,6 +751,7 @@ def volume(self, measure='ambient', engine='auto', **kwds): sqrt_Adet = Adet.sqrt() else: from sage.rings.qqbar import AA + sqrt_Adet = AA(Adet).sqrt() scaled_volume = AA(scaled_volume) return scaled_volume / sqrt_Adet @@ -750,6 +759,7 @@ def volume(self, measure='ambient', engine='auto', **kwds): # if the polyhedron is unbounded, return infinity if not self.is_compact(): from sage.rings.infinity import infinity + return infinity if engine == 'latte': return self._volume_latte(**kwds) @@ -759,6 +769,7 @@ def volume(self, measure='ambient', engine='auto', **kwds): # if the polyhedron is unbounded, return infinity if not self.is_compact(): from sage.rings.infinity import infinity + return infinity if engine == 'latte': return self._volume_latte(**kwds) * ZZ(self.dim()).factorial() @@ -902,8 +913,7 @@ def integrate(self, function, measure='ambient', **kwds): return self.base_ring().zero() if not self.is_compact(): - raise NotImplementedError( - 'integration over non-compact polyhedra not allowed') + raise NotImplementedError('integration over non-compact polyhedra not allowed') if measure == 'ambient': if not self.is_full_dimensional(): @@ -918,28 +928,27 @@ def integrate(self, function, measure='ambient', **kwds): return self.integrate(function, measure='ambient', **kwds) if isinstance(function, str): - raise NotImplementedError( - 'LattE description strings for polynomials not allowed ' - 'when using measure="induced"') + raise NotImplementedError('LattE description strings for polynomials not allowed ' 'when using measure="induced"') # use an orthogonal transformation affine_hull_data = self.affine_hull_projection(orthogonal=True, return_all_data=True) polyhedron = affine_hull_data.image from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(affine_hull_data.section_linear_map.base_ring(), 'x', self.dim()) coordinate_images = affine_hull_data.section_linear_map.matrix().transpose() * vector(R.gens()) + affine_hull_data.section_translation hom = function.parent().hom(coordinate_images) function_in_affine_hull = hom(function) - I = polyhedron.integrate(function_in_affine_hull, - measure='ambient', **kwds) + I = polyhedron.integrate(function_in_affine_hull, measure='ambient', **kwds) if measure == 'induced_nonnormalized': return I A = affine_hull_data.projection_linear_map.matrix() Adet = (A.transpose() * A).det() try: from sage.rings.qqbar import AA + Adet = AA.coerce(Adet) except TypeError: pass @@ -990,6 +999,5 @@ def _integrate_latte_(self, polynomial, **kwds): return polynomial(vertex) from sage.interfaces.latte import integrate - return integrate(self.cdd_Hrepresentation(), - polynomial, - cdd=True, **kwds) + + return integrate(self.cdd_Hrepresentation(), polynomial, cdd=True, **kwds) diff --git a/src/sage/geometry/polyhedron/base_QQ.py b/src/sage/geometry/polyhedron/base_QQ.py index df942a520ba..5e006d066f1 100644 --- a/src/sage/geometry/polyhedron/base_QQ.py +++ b/src/sage/geometry/polyhedron/base_QQ.py @@ -18,6 +18,7 @@ class Polyhedron_QQ(Polyhedron_base): A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex sage: TestSuite(p).run() """ + def _is_zero(self, x): """ Test whether ``x`` is zero. @@ -80,9 +81,7 @@ def _is_positive(self, x): _base_ring = QQ - def integral_points_count(self, verbose=False, use_Hrepresentation=False, - explicit_enumeration_threshold=1000, - preprocess=True, **kwds): + def integral_points_count(self, verbose=False, use_Hrepresentation=False, explicit_enumeration_threshold=1000, preprocess=True, **kwds): r""" Return the number of integral points in the polyhedron. @@ -177,7 +176,7 @@ def integral_points_count(self, verbose=False, use_Hrepresentation=False, box_min, box_max = self.bounding_box(integral_hull=True) if box_min is None: return 0 - box_points = prod(max_coord-min_coord+1 for min_coord, max_coord in zip(box_min, box_max)) + box_points = prod(max_coord - min_coord + 1 for min_coord, max_coord in zip(box_min, box_max)) if explicit_enumeration_threshold is None or box_points <= explicit_enumeration_threshold: return len(self.integral_points()) @@ -188,8 +187,7 @@ def integral_points_count(self, verbose=False, use_Hrepresentation=False, # If integral hull is known to lie in a coordinate hyperplane, # tighten bounds to reduce dimension. rat_box_min, rat_box_max = self.bounding_box(integral=False) - if any(a == b and (ra < a or b < rb) - for ra, a, b, rb in zip(rat_box_min, box_min, box_max, rat_box_max)): + if any(a == b and (ra < a or b < rb) for ra, a, b, rb in zip(rat_box_min, box_min, box_max, rat_box_max)): lp, x = self.to_linear_program(return_variable=True) for i, a in enumerate(box_min): lp.set_min(x[i], a) @@ -206,22 +204,13 @@ def integral_points_count(self, verbose=False, use_Hrepresentation=False, use_Hrepresentation = True from sage.interfaces.latte import count - return count( - p.cdd_Hrepresentation() if use_Hrepresentation else p.cdd_Vrepresentation(), - cdd=True, - verbose=verbose, - **kwds) + + return count(p.cdd_Hrepresentation() if use_Hrepresentation else p.cdd_Vrepresentation(), cdd=True, verbose=verbose, **kwds) n_points = integral_points_count @cached_method(do_pickle=True) - def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, - dual=None, irrational_primal=None, - irrational_all_primal=None, maxdet=None, - no_decomposition=None, compute_vertex_cones=None, - smith_form=None, dualization=None, - triangulation=None, - triangulation_max_height=None, **kwds): + def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, dual=None, irrational_primal=None, irrational_all_primal=None, maxdet=None, no_decomposition=None, compute_vertex_cones=None, smith_form=None, dualization=None, triangulation=None, triangulation_max_height=None, **kwds): r""" Return the Ehrhart polynomial of this polyhedron. @@ -360,6 +349,7 @@ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ + R = PolynomialRing(QQ, variable) # check if ``self`` is compact and has vertices in ZZ @@ -381,11 +371,7 @@ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, engine = 'latte' if engine == 'latte': - poly = self._ehrhart_polynomial_latte(verbose, dual, - irrational_primal, irrational_all_primal, maxdet, - no_decomposition, compute_vertex_cones, smith_form, - dualization, triangulation, triangulation_max_height, - **kwds) + poly = self._ehrhart_polynomial_latte(verbose, dual, irrational_primal, irrational_all_primal, maxdet, no_decomposition, compute_vertex_cones, smith_form, dualization, triangulation, triangulation_max_height, **kwds) return poly.change_variable_name(variable) # TO DO: replace this change of variable by creating the appropriate # polynomial ring in the latte interface. @@ -395,11 +381,7 @@ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, raise ValueError("engine must be 'latte' or 'normaliz'") @cached_method(do_pickle=True) - def ehrhart_quasipolynomial(self, variable='t', engine=None, verbose=False, - dual=None, irrational_primal=None, irrational_all_primal=None, - maxdet=None, no_decomposition=None, compute_vertex_cones=None, - smith_form=None, dualization=None, triangulation=None, - triangulation_max_height=None, **kwds): + def ehrhart_quasipolynomial(self, variable='t', engine=None, verbose=False, dual=None, irrational_primal=None, irrational_all_primal=None, maxdet=None, no_decomposition=None, compute_vertex_cones=None, smith_form=None, dualization=None, triangulation=None, triangulation_max_height=None, **kwds): r""" Compute the Ehrhart quasipolynomial of this polyhedron with rational vertices. @@ -567,6 +549,7 @@ def ehrhart_quasipolynomial(self, variable='t', engine=None, verbose=False, if self.is_empty(): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ + R = PolynomialRing(QQ, 't') return R.zero() @@ -581,11 +564,7 @@ def ehrhart_quasipolynomial(self, variable='t', engine=None, verbose=False, if engine == 'latte': if any(not v.is_integral() for v in self.vertex_generator()): raise TypeError("the polytope has nonintegral vertices, the engine and backend of self should be 'normaliz'") - poly = self._ehrhart_polynomial_latte(verbose, dual, - irrational_primal, irrational_all_primal, maxdet, - no_decomposition, compute_vertex_cones, smith_form, - dualization, triangulation, triangulation_max_height, - **kwds) + poly = self._ehrhart_polynomial_latte(verbose, dual, irrational_primal, irrational_all_primal, maxdet, no_decomposition, compute_vertex_cones, smith_form, dualization, triangulation, triangulation_max_height, **kwds) return poly.change_variable_name(variable) # TO DO: replace this change of variable by creating the appropriate # polynomial ring in the latte interface. @@ -645,11 +624,7 @@ def _ehrhart_quasipolynomial_normaliz(self, variable='t'): _ehrhart_polynomial_normaliz = _ehrhart_quasipolynomial_normaliz - def _ehrhart_polynomial_latte(self, verbose=False, dual=None, - irrational_primal=None, irrational_all_primal=None, maxdet=None, - no_decomposition=None, compute_vertex_cones=None, smith_form=None, - dualization=None, triangulation=None, triangulation_max_height=None, - **kwds): + def _ehrhart_polynomial_latte(self, verbose=False, dual=None, irrational_primal=None, irrational_all_primal=None, maxdet=None, no_decomposition=None, compute_vertex_cones=None, smith_form=None, dualization=None, triangulation=None, triangulation_max_height=None, **kwds): r""" Return the Ehrhart polynomial of this polyhedron using LattE integrale. @@ -790,19 +765,10 @@ def _ehrhart_polynomial_latte(self, verbose=False, dual=None, # note: the options below are explicitly written in the function # declaration in order to keep tab completion (see #18211). - kwds.update({ - 'dual' : dual, - 'irrational_primal' : irrational_primal, - 'irrational_all_primal' : irrational_all_primal, - 'maxdet' : maxdet, - 'no_decomposition' : no_decomposition, - 'compute_vertex_cones' : compute_vertex_cones, - 'smith_form' : smith_form, - 'dualization' : dualization, - 'triangulation' : triangulation, - 'triangulation_max_height': triangulation_max_height}) + kwds.update({'dual': dual, 'irrational_primal': irrational_primal, 'irrational_all_primal': irrational_all_primal, 'maxdet': maxdet, 'no_decomposition': no_decomposition, 'compute_vertex_cones': compute_vertex_cones, 'smith_form': smith_form, 'dualization': dualization, 'triangulation': triangulation, 'triangulation_max_height': triangulation_max_height}) from sage.interfaces.latte import count + ine = self.cdd_Hrepresentation() return count(ine, cdd=True, ehrhart_polynomial=True, verbose=verbose, **kwds) @@ -907,14 +873,14 @@ def fixed_subpolytope(self, vertex_permutation): size = len(orbit) if shift: # in this case, the indices in the orbit are 1 more than the index in the V - s = sum([(self.Vrepresentation()[i-1]).vector() for i in orbit]) + s = sum([(self.Vrepresentation()[i - 1]).vector() for i in orbit]) else: s = sum([(self.Vrepresentation()[i]).vector() for i in orbit]) - orbit_barycenter = (1/QQ(size)) * s + orbit_barycenter = (1 / QQ(size)) * s vertices += [orbit_barycenter] - P = self.parent().change_ring(self.base_ring().fraction_field(),backend='normaliz') - return P.element_class(P, [vertices,[],[]], None) + P = self.parent().change_ring(self.base_ring().fraction_field(), backend='normaliz') + return P.element_class(P, [vertices, [], []], None) def fixed_subpolytopes(self, conj_class_reps): r""" diff --git a/src/sage/geometry/polyhedron/base_RDF.py b/src/sage/geometry/polyhedron/base_RDF.py index 505355ac42c..14614bcc7bb 100644 --- a/src/sage/geometry/polyhedron/base_RDF.py +++ b/src/sage/geometry/polyhedron/base_RDF.py @@ -17,6 +17,7 @@ class Polyhedron_RDF(Polyhedron_base): A 0-dimensional polyhedron in RDF^2 defined as the convex hull of 1 vertex sage: TestSuite(p).run() """ + # 1e-6 is the cddf+ default fuzzy zero cutoff def _is_zero(self, x): diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index ebf8f421dcb..bb0d5a034ac 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -38,6 +38,7 @@ class Polyhedron_ZZ(Polyhedron_QQ): A 0-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex sage: TestSuite(p).run() """ + _base_ring = ZZ def __getattribute__(self, name): @@ -70,7 +71,7 @@ def __dir__(self): sage: 'ehrhart_quasipolynomial' in P.__dir__() False """ - orig_dir = (set(dir(self.__class__)) | set(self.__dict__.keys())) + orig_dir = set(dir(self.__class__)) | set(self.__dict__.keys()) return sorted(orig_dir - set(['ehrhart_quasipolynomial'])) def is_lattice_polytope(self): @@ -99,11 +100,7 @@ def is_lattice_polytope(self): """ return self.is_compact() - def _ehrhart_polynomial_latte(self, verbose=False, dual=None, - irrational_primal=None, irrational_all_primal=None, maxdet=None, - no_decomposition=None, compute_vertex_cones=None, smith_form=None, - dualization=None, triangulation=None, triangulation_max_height=None, - **kwds): + def _ehrhart_polynomial_latte(self, verbose=False, dual=None, irrational_primal=None, irrational_all_primal=None, maxdet=None, no_decomposition=None, compute_vertex_cones=None, smith_form=None, dualization=None, triangulation=None, triangulation_max_height=None, **kwds): r""" Return the Ehrhart polynomial of this polyhedron using LattE integrale. @@ -242,19 +239,10 @@ def _ehrhart_polynomial_latte(self, verbose=False, dual=None, """ # note: the options below are explicitly written in the function # declaration in order to keep tab completion (see #18211). - kwds.update({ - 'dual' : dual, - 'irrational_primal' : irrational_primal, - 'irrational_all_primal' : irrational_all_primal, - 'maxdet' : maxdet, - 'no_decomposition' : no_decomposition, - 'compute_vertex_cones' : compute_vertex_cones, - 'smith_form' : smith_form, - 'dualization' : dualization, - 'triangulation' : triangulation, - 'triangulation_max_height': triangulation_max_height}) + kwds.update({'dual': dual, 'irrational_primal': irrational_primal, 'irrational_all_primal': irrational_all_primal, 'maxdet': maxdet, 'no_decomposition': no_decomposition, 'compute_vertex_cones': compute_vertex_cones, 'smith_form': smith_form, 'dualization': dualization, 'triangulation': triangulation, 'triangulation_max_height': triangulation_max_height}) from sage.interfaces.latte import count + ine = self.cdd_Hrepresentation() return count(ine, cdd=True, ehrhart_polynomial=True, verbose=verbose, **kwds) @@ -295,13 +283,7 @@ def _ehrhart_polynomial_normaliz(self, variable='t'): raise TypeError("The polyhedron's backend should be 'normaliz'") @cached_method(do_pickle=True) - def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, - dual=None, irrational_primal=None, - irrational_all_primal=None, maxdet=None, - no_decomposition=None, compute_vertex_cones=None, - smith_form=None, dualization=None, - triangulation=None, triangulation_max_height=None, - **kwds): + def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, dual=None, irrational_primal=None, irrational_all_primal=None, maxdet=None, no_decomposition=None, compute_vertex_cones=None, smith_form=None, dualization=None, triangulation=None, triangulation_max_height=None, **kwds): r""" Return the Ehrhart polynomial of this polyhedron. @@ -462,6 +444,7 @@ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ + R = PolynomialRing(QQ, variable) if self.is_empty(): @@ -477,11 +460,7 @@ def ehrhart_polynomial(self, engine=None, variable='t', verbose=False, # setting the default to 'latte' engine = 'latte' if engine == 'latte': - poly = self._ehrhart_polynomial_latte(verbose, dual, - irrational_primal, irrational_all_primal, maxdet, - no_decomposition, compute_vertex_cones, smith_form, - dualization, triangulation, triangulation_max_height, - **kwds) + poly = self._ehrhart_polynomial_latte(verbose, dual, irrational_primal, irrational_all_primal, maxdet, no_decomposition, compute_vertex_cones, smith_form, dualization, triangulation, triangulation_max_height, **kwds) return poly.change_variable_name(variable) # TO DO: replace this change of variable by creating the appropriate # polynomial ring in the latte interface. @@ -525,8 +504,7 @@ def polar(self): if not self.has_IP_property(): raise ValueError('The polytope must have the IP property.') - vertices = tuple(ieq.A() / ieq.b() for - ieq in self.inequality_generator()) + vertices = tuple(ieq.A() / ieq.b() for ieq in self.inequality_generator()) ieqs = ((1,) + tuple(v[:]) for v in self.vertices()) @@ -538,8 +516,7 @@ def polar(self): else: parent = self.parent().change_ring(QQ) - return parent.element_class(parent, [vertices, [], []], [ieqs, []], - Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) + return parent.element_class(parent, [vertices, [], []], [ieqs, []], Vrep_minimal=True, Hrep_minimal=True, pref_rep=pref_rep) @cached_method def is_reflexive(self): @@ -581,7 +558,7 @@ def is_reflexive(self): b = H.b() if b < 1: return False - if not all(v_i/b in ZZ for v_i in H.A()): + if not all(v_i / b in ZZ for v_i in H.A()): return False return True @@ -645,6 +622,7 @@ def fibration_generator(self, dim): [A 2-dimensional polyhedron in ZZ^4 defined as the convex hull of 3 vertices] """ from sage.combinat.combination import Combinations + if not self.is_compact(): raise ValueError('Only polytopes (compact polyhedra) are allowed.') @@ -693,15 +671,12 @@ def find_translation(self, translated_polyhedron): ValueError: polyhedron is not a translation of self """ no_translation_exception = ValueError('polyhedron is not a translation of self') - if ( set(self.rays()) != set(translated_polyhedron.rays()) or - set(self.lines()) != set(translated_polyhedron.lines()) or - self.n_vertices() != translated_polyhedron.n_vertices() ): + if set(self.rays()) != set(translated_polyhedron.rays()) or set(self.lines()) != set(translated_polyhedron.lines()) or self.n_vertices() != translated_polyhedron.n_vertices(): raise no_translation_exception sorted_vertices = sorted(map(vector, self.vertices())) sorted_translated_vertices = sorted(map(vector, translated_polyhedron.vertices())) v = sorted_translated_vertices[0] - sorted_vertices[0] - if any(vertex+v != translated_vertex - for vertex, translated_vertex in zip(sorted_vertices, sorted_translated_vertices)): + if any(vertex + v != translated_vertex for vertex, translated_vertex in zip(sorted_vertices, sorted_translated_vertices)): raise no_translation_exception return v @@ -749,6 +724,7 @@ def _subpoly_parallel_facets(self): if self.dim() > 2 or not self.is_compact(): raise NotImplementedError('only implemented for bounded polygons') from sage.geometry.polyhedron.plot import cyclic_sort_vertices_2d + vertices = cyclic_sort_vertices_2d(self.vertices()) n = len(vertices) if n == 1: # single point @@ -756,20 +732,21 @@ def _subpoly_parallel_facets(self): return edge_vectors = [] for i in range(n): - v = vertices[(i+1) % n].vector() - vertices[i].vector() + v = vertices[(i + 1) % n].vector() - vertices[i].vector() d = gcd(list(v)) - v_prim = (v/d).change_ring(ZZ) - edge_vectors.append([ v_prim*i for i in range(d+1) ]) + v_prim = (v / d).change_ring(ZZ) + edge_vectors.append([v_prim * i for i in range(d + 1)]) origin = self.ambient_space().zero() parent = self.parent() from itertools import product + for edges in product(*edge_vectors): v = [] point = origin for e in edges: point += e v.append(point) - if point != origin: # does not close up, not a subpolygon + if point != origin: # does not close up, not a subpolygon continue yield parent([v, [], []], None) @@ -833,6 +810,7 @@ def is_known_summand(poly): return True except ValueError: pass + decompositions = [] for X in self._subpoly_parallel_facets(): if is_known_summand(X): diff --git a/src/sage/geometry/polyhedron/base_number_field.py b/src/sage/geometry/polyhedron/base_number_field.py index c1d0ab39190..2650669ce3c 100644 --- a/src/sage/geometry/polyhedron/base_number_field.py +++ b/src/sage/geometry/polyhedron/base_number_field.py @@ -41,13 +41,14 @@ def _number_field_elements_from_algebraics_list_of_lists_of_lists(listss, **kwds [[[-a^3 + 3*a], [1]], [[a^2 - 2]], [[1], []]] """ from sage.rings.qqbar import number_field_elements_from_algebraics + numbers = [] for lists in listss: for list in lists: numbers.extend(list) K, K_numbers, hom = number_field_elements_from_algebraics(numbers, **kwds) g = iter(K_numbers) - return K, [ [ [ next(g) for _ in list ] for list in lists ] for lists in listss ], hom + return K, [[[next(g) for _ in list] for list in lists] for lists in listss], hom class Polyhedron_base_number_field(Polyhedron_base): @@ -116,6 +117,5 @@ def _compute_data_lists_and_internal_base_ring(self, data_lists, convert_QQ, con internal_base_ring = K if K is QQ: # Compute it with Normaliz, not QNormaliz - internal_data_lists = convert_QQ(*[ [ [ QQ(x) for x in v ] for v in l] - for l in data_lists ]) + internal_data_lists = convert_QQ(*[[[QQ(x) for x in v] for v in l] for l in data_lists]) return internal_data_lists, internal_base_ring diff --git a/src/sage/geometry/polyhedron/cdd_file_format.py b/src/sage/geometry/polyhedron/cdd_file_format.py index edc04b4cb8f..52a8a966f22 100644 --- a/src/sage/geometry/polyhedron/cdd_file_format.py +++ b/src/sage/geometry/polyhedron/cdd_file_format.py @@ -59,11 +59,12 @@ def cdd_Vrepresentation(cdd_type, vertices, rays, lines, file_output=None): # cdd implicitly assumes that the origin is a vertex if none is given if vertices is None: - vertices = [[0]*ambient_dim] + vertices = [[0] * ambient_dim] num += 1 if cdd_type == 'real': from sage.rings.real_double import RDF + base_ring = RDF else: base_ring = None @@ -72,9 +73,9 @@ def cdd_Vrepresentation(cdd_type, vertices, rays, lines, file_output=None): if lines is not None: n = len(lines) s += "linearity " + repr(n) + ' ' - s += _to_space_separated_string(range(1,n+1)) + '\n' + s += _to_space_separated_string(range(1, n + 1)) + '\n' s += 'begin\n' - s += ' ' + repr(num) + ' ' + repr(ambient_dim+1) + ' ' + cdd_type + '\n' + s += ' ' + repr(num) + ' ' + repr(ambient_dim + 1) + ' ' + cdd_type + '\n' if lines is not None: for l in lines: s += ' 0 ' + _to_space_separated_string(l, base_ring) + '\n' @@ -93,6 +94,7 @@ def cdd_Vrepresentation(cdd_type, vertices, rays, lines, file_output=None): else: return s + ######################################################################### @@ -126,6 +128,7 @@ def cdd_Hrepresentation(cdd_type, ieqs, eqns, file_output=None): if cdd_type == 'real': from sage.rings.real_double import RDF + base_ring = RDF else: base_ring = None @@ -135,9 +138,9 @@ def cdd_Hrepresentation(cdd_type, ieqs, eqns, file_output=None): assert len(eqns) > 0 n = len(eqns) s += "linearity " + repr(n) + ' ' - s += _to_space_separated_string(range(1,n+1)) + '\n' + s += _to_space_separated_string(range(1, n + 1)) + '\n' s += 'begin\n' - s += ' ' + repr(num) + ' ' + repr(ambient_dim+1) + ' ' + cdd_type + '\n' + s += ' ' + repr(num) + ' ' + repr(ambient_dim + 1) + ' ' + cdd_type + '\n' if eqns is not None: for e in eqns: s += ' ' + _to_space_separated_string(e, base_ring) + '\n' diff --git a/src/sage/geometry/polyhedron/constructor.py b/src/sage/geometry/polyhedron/constructor.py index dbd5172f6bb..169be17c0f5 100644 --- a/src/sage/geometry/polyhedron/constructor.py +++ b/src/sage/geometry/polyhedron/constructor.py @@ -302,10 +302,7 @@ ######################################################################### -def Polyhedron(vertices=None, rays=None, lines=None, - ieqs=None, eqns=None, - ambient_dim=None, base_ring=None, minimize=True, verbose=False, - backend=None, mutable=False): +def Polyhedron(vertices=None, rays=None, lines=None, ieqs=None, eqns=None, ambient_dim=None, base_ring=None, minimize=True, verbose=False, backend=None, mutable=False): r""" Construct a polyhedron object. @@ -708,12 +705,14 @@ def Polyhedron(vertices=None, rays=None, lines=None, P = parent(values[0]) if any(parent(x) is not P for x in values): from sage.structure.sequence import Sequence + P = Sequence(values).universe() convert = True else: convert = False from sage.structure.coerce import py_scalar_parent + if isinstance(P, type): base_ring = py_scalar_parent(P) convert = convert or P is not base_ring @@ -722,8 +721,7 @@ def Polyhedron(vertices=None, rays=None, lines=None, if base_ring not in Fields(): got_compact_Vrep = got_Vrep and not rays and not lines - got_cone_Vrep = got_Vrep and all(x == 0 - for v in vertices for x in v) + got_cone_Vrep = got_Vrep and all(x == 0 for v in vertices for x in v) if not got_compact_Vrep and not got_cone_Vrep: base_ring = base_ring.fraction_field() convert = True @@ -757,6 +755,7 @@ def Polyhedron(vertices=None, rays=None, lines=None, # Specific backends can override the base_ring from sage.geometry.polyhedron.parent import Polyhedra + parent = Polyhedra(base_ring, ambient_dim, backend=backend) base_ring = parent.base_ring() diff --git a/src/sage/geometry/polyhedron/double_description.py b/src/sage/geometry/polyhedron/double_description.py index b42a41a8bdd..fd4488bba51 100644 --- a/src/sage/geometry/polyhedron/double_description.py +++ b/src/sage/geometry/polyhedron/double_description.py @@ -38,7 +38,7 @@ (0.5822623322995881?, -0.4177376677004119?, 0.4177376677004119?)] """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2014 Volker Braun # 2015 Vincent Delecroix <20100.delecroix@gmail.com> # @@ -47,10 +47,10 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** -#***************************************************************************** +# ***************************************************************************** # TODO # # The adjacency check should use caching and the "combinatorial @@ -98,6 +98,7 @@ def random_inequalities(d, n): sage: P.run().verify() """ from sage.matrix.constructor import random_matrix + while True: A = random_matrix(QQ, n, d) if A.rank() == min(n, d) and not any(a == 0 for a in A.rows()): @@ -205,13 +206,14 @@ def __repr__(self): """ from sage.typeset.ascii_art import ascii_art from sage.matrix.constructor import matrix + s = ascii_art('Double description pair (A, R) defined by') A = ascii_art(matrix(self.A)) - A._baseline = (len(self.A) // 2) + A._baseline = len(self.A) // 2 A = ascii_art('A = ') + A R = ascii_art(matrix(self.R).transpose()) if len(self.R) > 0: - R._baseline = (len(self.R[0]) // 2) + R._baseline = len(self.R[0]) // 2 else: R._baseline = 0 R = ascii_art('R = ') + R @@ -239,6 +241,7 @@ def inner_product_matrix(self): [0 0 1] """ from sage.matrix.constructor import matrix + return matrix(self.problem.base_ring(), [[a.inner_product(r) for r in self.R] for a in self.A]) def cone(self): @@ -265,7 +268,8 @@ def cone(self): An inequality (1, 0, 1) x + 0 >= 0) """ from sage.geometry.polyhedron.constructor import Polyhedron - assert self.problem.base_ring() == QQ # required for PPL backend + + assert self.problem.base_ring() == QQ # required for PPL backend if not self.A: return Polyhedron(vertices=[[0] * self.problem.dim()], backend='ppl') @@ -296,11 +300,11 @@ def verify(self): AssertionError """ from sage.geometry.polyhedron.constructor import Polyhedron + if self.problem.base_ring() is not QQ: return A_cone = self.cone() - R_cone = Polyhedron(vertices=[[self.zero] * self.problem.dim()], rays=self.R, - base_ring=self.problem.base_ring(), backend='ppl') + R_cone = Polyhedron(vertices=[[self.zero] * self.problem.dim()], rays=self.R, base_ring=self.problem.base_ring(), backend='ppl') assert A_cone == R_cone assert A_cone.n_inequalities() <= len(self.A) assert R_cone.n_rays() == len(self.R) @@ -365,7 +369,7 @@ def zero_set(self, ray): self.zero_set_cache[ray] = (0, set()) n, t = self.zero_set_cache[ray] if n != len(self.A): - t.update(self.A[i] for i in range(n,len(self.A)) if self.A[i].inner_product(ray) == self.zero) + t.update(self.A[i] for i in range(n, len(self.A)) if self.A[i].inner_product(ray) == self.zero) self.zero_set_cache[ray] = (len(self.A), t) return t @@ -382,6 +386,7 @@ def is_extremal(self, ray): True """ from sage.matrix.constructor import matrix + A_Zray = matrix(self.problem.base_ring(), list(self.zero_set(ray))) return A_Zray.rank() == self.problem.dim() - 1 @@ -532,7 +537,7 @@ def __init__(self, A): (1, 1) (-1, 1) """ - assert A.rank() == A.ncols() # implementation assumes maximal rank + assert A.rank() == A.ncols() # implementation assumes maximal rank if A.is_mutable(): A = A.__copy__() A.set_immutable() @@ -650,6 +655,7 @@ def initial_pair(self): A0 = [self.A()[pivot] for pivot in pivot_rows] Ac = [self.A()[i] for i in range(len(self.A())) if i not in pivot_rows] from sage.matrix.constructor import identity_matrix, matrix + I = identity_matrix(self.base_ring(), self.dim()) R = matrix(self.base_ring(), A0).solve_right(I) return self.pair_class(self, A0, R.columns()), list(Ac) @@ -718,6 +724,7 @@ class StandardAlgorithm(Problem): sage: DD.R # the extremal rays [(1/2, 1/2), (-1/2, 1/2)] """ + pair_class = StandardDoubleDescriptionPair def run(self): diff --git a/src/sage/geometry/polyhedron/double_description_inhomogeneous.py b/src/sage/geometry/polyhedron/double_description_inhomogeneous.py index 58813a37154..103a15bdade 100644 --- a/src/sage/geometry/polyhedron/double_description_inhomogeneous.py +++ b/src/sage/geometry/polyhedron/double_description_inhomogeneous.py @@ -334,6 +334,7 @@ def _repr_(self): def make_matrix(rows): return matrix(self.base_ring, len(rows), self.dim, rows).transpose() + V = make_matrix(self.vertices) R = make_matrix(self.rays) L = make_matrix(self.lines) @@ -358,16 +359,12 @@ def verify(self, inequalities, equations): """ from sage.rings.rational_field import QQ from sage.geometry.polyhedron.constructor import Polyhedron + if self.base_ring is not QQ: return - P = Polyhedron(vertices=self.vertices, rays=self.rays, lines=self.lines, - base_ring=QQ, ambient_dim=self.dim, backend='ppl') - Q = Polyhedron(ieqs=inequalities, eqns=equations, - base_ring=QQ, ambient_dim=self.dim, backend='ppl') - if (P != Q) or \ - (len(self.vertices) != P.n_vertices()) or \ - (len(self.rays) != P.n_rays()) or \ - (len(self.lines) != P.n_lines()): + P = Polyhedron(vertices=self.vertices, rays=self.rays, lines=self.lines, base_ring=QQ, ambient_dim=self.dim, backend='ppl') + Q = Polyhedron(ieqs=inequalities, eqns=equations, base_ring=QQ, ambient_dim=self.dim, backend='ppl') + if (P != Q) or (len(self.vertices) != P.n_vertices()) or (len(self.rays) != P.n_rays()) or (len(self.lines) != P.n_lines()): print('incorrect!', end="") print(Q.Vrepresentation()) print(P.Hrepresentation()) @@ -443,7 +440,7 @@ def __init__(self, base_ring, dim, vertices, rays, lines): # Manually setting a single equality in this case. one = self.base_ring.one() zero = self.base_ring.zero() - self.equations = [[one] + [zero]*self.dim] + self.equations = [[one] + [zero] * self.dim] self.inequalities = [] else: A = self._init_Vrep(vertices, rays, lines) @@ -473,11 +470,7 @@ def _init_Vrep(self, vertices, rays, lines): """ one = self.base_ring.one() zero = self.base_ring.zero() - homogeneous = \ - [[one] + list(v) for v in vertices] + \ - [[zero] + list(r) for r in rays] + \ - [[zero] + list(l) for l in lines] + \ - [[zero] + [-x for x in l] for l in lines] + homogeneous = [[one] + list(v) for v in vertices] + [[zero] + list(r) for r in rays] + [[zero] + list(l) for l in lines] + [[zero] + [-x for x in l] for l in lines] A = matrix(self.base_ring, homogeneous) return self._pivot_inequalities(A) @@ -503,6 +496,7 @@ def _extract_Hrep(self, DD): def is_trivial(ray): # trivial Hrep output 1 >= 0 return ray[0] > zero and all(r == zero for r in ray[1:]) + ieqs = (self._unpivot_ray(ra) for ra in DD.R) self.inequalities = [r for r in ieqs if not is_trivial(r)] self.equations = self._linear_subspace.matrix().rows() @@ -524,6 +518,7 @@ def _repr_(self): def make_matrix(cols): return matrix(self.base_ring, len(cols), self.dim + 1, cols) + I = make_matrix(self.inequalities) E = make_matrix(self.equations) return str(block_matrix([[I], [E]])) @@ -550,12 +545,11 @@ def verify(self, vertices, rays, lines): """ from sage.rings.rational_field import QQ from sage.geometry.polyhedron.constructor import Polyhedron + if self.base_ring is not QQ: return - P = Polyhedron(vertices=vertices, rays=rays, lines=lines, - base_ring=QQ, ambient_dim=self.dim) - Q = Polyhedron(ieqs=self.inequalities, eqns=self.equations, - base_ring=QQ, ambient_dim=self.dim) + P = Polyhedron(vertices=vertices, rays=rays, lines=lines, base_ring=QQ, ambient_dim=self.dim) + Q = Polyhedron(ieqs=self.inequalities, eqns=self.equations, base_ring=QQ, ambient_dim=self.dim) if not P == Q: print('incorrect!', P, Q) print(Q.Vrepresentation()) diff --git a/src/sage/geometry/polyhedron/face.py b/src/sage/geometry/polyhedron/face.py index 5141c54c40c..ad66e88df67 100644 --- a/src/sage/geometry/polyhedron/face.py +++ b/src/sage/geometry/polyhedron/face.py @@ -362,11 +362,9 @@ def __richcmp__(self, other, op): if not isinstance(other, PolyhedronFace): return NotImplemented if self._polyhedron is not other._polyhedron: - if (self._polyhedron.Vrepresentation() != other._polyhedron.Vrepresentation() - or self._polyhedron.Hrepresentation() != other._polyhedron.Hrepresentation()): + if self._polyhedron.Vrepresentation() != other._polyhedron.Vrepresentation() or self._polyhedron.Hrepresentation() != other._polyhedron.Hrepresentation(): return NotImplemented - return richcmp(self._ambient_Vrepresentation_indices, - other._ambient_Vrepresentation_indices, op) + return richcmp(self._ambient_Vrepresentation_indices, other._ambient_Vrepresentation_indices, op) def ambient_Hrepresentation(self, index=None): r""" @@ -582,10 +580,8 @@ def dim(self): if self.n_ambient_Vrepresentation() == 0: return -1 origin = self.vertices()[0].vector() - v_list = [vector(v) - origin for v in - self.ambient_Vrepresentation() if v.is_vertex()] - v_list += [vector(v) for v in self.ambient_Vrepresentation() - if v.is_ray() or v.is_line()] + v_list = [vector(v) - origin for v in self.ambient_Vrepresentation() if v.is_vertex()] + v_list += [vector(v) for v in self.ambient_Vrepresentation() if v.is_ray() or v.is_line()] return matrix(v_list).rank() def _repr_(self): @@ -711,8 +707,7 @@ def is_compact(self) -> bool: sage: line.is_compact() False """ - return not any(V.is_ray() or V.is_line() - for V in self.ambient_Vrepresentation()) + return not any(V.is_ray() or V.is_line() for V in self.ambient_Vrepresentation()) @cached_method def as_polyhedron(self, **kwds): @@ -738,9 +733,9 @@ def as_polyhedron(self, **kwds): parent = P.parent() Vrep = (self.vertices(), self.rays(), self.lines()) result = P.__class__(parent, Vrep, None) - if any(kwds.get(kwd) is not None - for kwd in ('base_ring', 'backend')): + if any(kwds.get(kwd) is not None for kwd in ('base_ring', 'backend')): from .constructor import Polyhedron + return Polyhedron(result, **kwds) return result @@ -930,10 +925,8 @@ def affine_tangent_cone(self): if self.dim() == -1: raise ValueError("affine tangent cone of the empty face not defined") parent = self.polyhedron().parent() - new_ieqs = [H for H in self.ambient_Hrepresentation() - if H.is_inequality()] - new_eqns = [H for H in self.ambient_Hrepresentation() - if H.is_equation()] + new_ieqs = [H for H in self.ambient_Hrepresentation() if H.is_inequality()] + new_eqns = [H for H in self.ambient_Hrepresentation() if H.is_equation()] return parent.element_class(parent, None, [new_ieqs, new_eqns]) @cached_method @@ -967,8 +960,7 @@ def stacking_locus(self): if self.dim() == self.polyhedron().dim() - 1: face_star = set([self.ambient_Hrepresentation()[-1]]) else: - face_star = set(facet for facet in self.ambient_Hrepresentation() if facet.is_inequality() - if all(not facet.interior_contains(x) for x in self.vertices())) + face_star = set(facet for facet in self.ambient_Hrepresentation() if facet.is_inequality() if all(not facet.interior_contains(x) for x in self.vertices())) neighboring_facets = set() for facet in face_star: @@ -1028,7 +1020,7 @@ def combinatorial_face_to_polyhedral_face(polyhedron, combinatorial_face): if polyhedron.backend() in ('ppl',): # Equations before inequalities in Hrep. H_indices = tuple(range(n_equations)) - H_indices += tuple(x+n_equations for x in combinatorial_face.ambient_H_indices(add_equations=False)) + H_indices += tuple(x + n_equations for x in combinatorial_face.ambient_H_indices(add_equations=False)) elif polyhedron.backend() in ('normaliz', 'cdd', 'field', 'number_field', 'polymake'): # Equations after the inequalities in Hrep. n_ieqs = polyhedron.n_inequalities() diff --git a/src/sage/geometry/polyhedron/generating_function.py b/src/sage/geometry/polyhedron/generating_function.py index c305a7868f5..e1b30947c1f 100644 --- a/src/sage/geometry/polyhedron/generating_function.py +++ b/src/sage/geometry/polyhedron/generating_function.py @@ -39,10 +39,7 @@ Hrepresentation_str_options = {'prefix': 'b', 'style': 'positive'} -def generating_function_of_integral_points(polyhedron, split=False, - result_as_tuple=None, - name=None, names=None, - **kwds): +def generating_function_of_integral_points(polyhedron, split=False, result_as_tuple=None, name=None, names=None, **kwds): r""" Return the multivariate generating function of the integral points of the ``polyhedron``. @@ -461,6 +458,7 @@ def generating_function_of_integral_points(polyhedron, split=False, TypeError: base ring Real Double Field of the polyhedron not ZZ or QQ """ import logging + logger = logging.getLogger(__name__) from sage.combinat.permutation import Permutations @@ -474,21 +472,19 @@ def generating_function_of_integral_points(polyhedron, split=False, if polyhedron.is_empty(): from sage.structure.factorization import Factorization + result = Factorization([], unit=0) if result_as_tuple: return (result,) return result if polyhedron.base_ring() not in (ZZ, QQ): - raise TypeError('base ring {} of the polyhedron not ' - 'ZZ or QQ'.format(polyhedron.base_ring())) + raise TypeError('base ring {} of the polyhedron not ' 'ZZ or QQ'.format(polyhedron.base_ring())) d = polyhedron.ambient_dim() - nonnegative_orthant = Polyhedron(ieqs=[dd*(0,) + (1,) + (d-dd)*(0,) - for dd in range(1, d+1)]) + nonnegative_orthant = Polyhedron(ieqs=[dd * (0,) + (1,) + (d - dd) * (0,) for dd in range(1, d + 1)]) if polyhedron & nonnegative_orthant != polyhedron: - raise NotImplementedError('cannot compute the generating function of ' - 'polyhedra with negative coordinates') + raise NotImplementedError('cannot compute the generating function of ' 'polyhedra with negative coordinates') logger.info('%s', polyhedron) @@ -507,13 +503,11 @@ def generating_function_of_integral_points(polyhedron, split=False, if result_as_tuple: return result if len(result) != 1: - raise ValueError("cannot unpack result " - "(set 'result_as_tuple=True')") + raise ValueError("cannot unpack result " "(set 'result_as_tuple=True')") return result[0] if d <= 1: - raise ValueError('cannot do splitting with only ' - 'dimension {}'.format(d)) + raise ValueError('cannot do splitting with only ' 'dimension {}'.format(d)) parts = None if split is True: @@ -521,18 +515,15 @@ def generating_function_of_integral_points(polyhedron, split=False, def polyhedron_from_permutation(pi): def ieq(a, b): - return ((0 if a < b else -1,) + - tuple(1 if i == b else (-1 if i == a else 0) - for i in range(1, d + 1))) + return (0 if a < b else -1,) + tuple(1 if i == b else (-1 if i == a else 0) for i in range(1, d + 1)) def ieq_repr_rhs(a, b): - return (' <= ' if a < b else ' < ') + 'b{}'.format(b-1) + return (' <= ' if a < b else ' < ') + 'b{}'.format(b - 1) def ieqs_repr_lhs(pi): - return 'b{}'.format(pi[0]-1) + return 'b{}'.format(pi[0] - 1) - ieqs, repr_rhss = zip(*[(ieq(a, b), ieq_repr_rhs(a, b)) - for a, b in zip(pi[:-1], pi[1:])]) + ieqs, repr_rhss = zip(*[(ieq(a, b), ieq_repr_rhs(a, b)) for a, b in zip(pi[:-1], pi[1:])]) return Polyhedron(ieqs=ieqs), ieqs_repr_lhs(pi) + ''.join(repr_rhss) split = (polyhedron_from_permutation(pi) for pi in Permutations(d)) @@ -540,26 +531,22 @@ def ieqs_repr_lhs(pi): else: if isinstance(split, (list, tuple)): parts = len(split) - split = ((ph, ph.Hrepresentation_str(**Hrepresentation_str_options)) - for ph in split) + split = ((ph, ph.Hrepresentation_str(**Hrepresentation_str_options)) for ph in split) result = [] for part, (split_polyhedron, pi_log) in enumerate(split): if parts is None: - parts_log = str(part+1) + parts_log = str(part + 1) else: - parts_log = '{}/{}'.format(part+1, parts) + parts_log = '{}/{}'.format(part + 1, parts) logger.info('(%s) split polyhedron by %s', parts_log, pi_log) - result.append(_generating_function_of_integral_points_( - polyhedron & split_polyhedron, name=name, **kwds)) + result.append(_generating_function_of_integral_points_(polyhedron & split_polyhedron, name=name, **kwds)) if not result_as_tuple: - raise ValueError("cannot unpack result" - "(unset 'result_as_tuple=False')") + raise ValueError("cannot unpack result" "(unset 'result_as_tuple=False')") return sum(result, ()) -def _generating_function_of_integral_points_( - polyhedron, indices=None, **kwds): +def _generating_function_of_integral_points_(polyhedron, indices=None, **kwds): r""" Helper function for :func:`generating_function_of_integral_points` which does the mid-level stuff. @@ -576,21 +563,20 @@ def _generating_function_of_integral_points_( y0*y1*y2 * (-y1^2*y2 + 1)^-1 * (-y0^2*y1^2*y2^2 + 1)^-1) """ import logging + logger = logging.getLogger(__name__) - logger.info('using polyhedron %s', - polyhedron.Hrepresentation_str(**Hrepresentation_str_options)) + logger.info('using polyhedron %s', polyhedron.Hrepresentation_str(**Hrepresentation_str_options)) if polyhedron.is_empty(): from sage.structure.factorization import Factorization + return (Factorization([], unit=0),) Hrepr = polyhedron.Hrepresentation() - inequalities = tuple(tuple(entry) - for entry in Hrepr if entry.is_inequality()) - equations = tuple(tuple(entry) - for entry in Hrepr if entry.is_equation()) + inequalities = tuple(tuple(entry) for entry in Hrepr if entry.is_inequality()) + equations = tuple(tuple(entry) for entry in Hrepr if entry.is_equation()) if len(inequalities) + len(equations) != len(Hrepr): raise ValueError('cannot handle {}.'.format(polyhedron)) @@ -602,24 +588,17 @@ def _generating_function_of_integral_points_( n = len(indices) + 1 if any(len(e) != n for e in inequalities): - raise ValueError('not all coefficient vectors of the inequalities ' - 'have the same length') + raise ValueError('not all coefficient vectors of the inequalities ' 'have the same length') if any(len(e) != n for e in equations): - raise ValueError('not all coefficient vectors of the equations ' - 'have the same length') + raise ValueError('not all coefficient vectors of the equations ' 'have the same length') mods = _TransformMod.generate_mods(equations) logger.debug('splitting by moduli %s', mods) - return tuple(__generating_function_of_integral_points__( - indices, inequalities, equations, mod, **kwds) for mod in mods) + return tuple(__generating_function_of_integral_points__(indices, inequalities, equations, mod, **kwds) for mod in mods) -def __generating_function_of_integral_points__( - indices, inequalities, equations, mod, - name, - Factorization_sort=False, Factorization_simplify=False, - sort_factors=False): +def __generating_function_of_integral_points__(indices, inequalities, equations, mod, name, Factorization_sort=False, Factorization_simplify=False, sort_factors=False): r""" Helper function for :func:`generating_function_of_integral_points` which does the actual computation of the generating function. @@ -642,18 +621,16 @@ def __generating_function_of_integral_points__( y0*y1*y2 * (-y1^2*y2 + 1)^-1 * (-y0^2*y1^2*y2^2 + 1)^-1 """ import logging + logger = logging.getLogger(__name__) from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.structure.factorization import Factorization - B = LaurentPolynomialRing(ZZ, - tuple(name + str(k) for k in indices), - len(indices)) + B = LaurentPolynomialRing(ZZ, tuple(name + str(k) for k in indices), len(indices)) - logger.info('preprocessing %s inequalities and %s equations...', - len(inequalities), len(equations)) + logger.info('preprocessing %s inequalities and %s equations...', len(inequalities), len(equations)) T_mod = _TransformMod(inequalities, equations, B, mod) inequalities = T_mod.inequalities @@ -669,22 +646,20 @@ def __generating_function_of_integral_points__( assert not equations logger.info('%s inequalities left; using Omega...', len(inequalities)) - numerator, terms = _generating_function_via_Omega_( - inequalities, B, skip_indices=T_equations.indices) + numerator, terms = _generating_function_via_Omega_(inequalities, B, skip_indices=T_equations.indices) numerator, terms = T_inequalities.apply_rules(numerator, terms) numerator, terms = T_equations.apply_rules(numerator, terms) numerator, terms = T_mod.apply_rules(numerator, terms) if sort_factors: + def key(t): D = t.monomial_coefficients().popitem()[0] return (-sum(abs(d) for d in D), D) + terms = sorted(terms, key=key, reverse=True) - return Factorization([(numerator, 1)] + - [(1 - t, -1) for t in terms], - sort=Factorization_sort, - simplify=Factorization_simplify) + return Factorization([(numerator, 1)] + [(1 - t, -1) for t in terms], sort=Factorization_sort, simplify=Factorization_simplify) def _generating_function_via_Omega_(inequalities, B, skip_indices=()): @@ -720,6 +695,7 @@ def _generating_function_via_Omega_(inequalities, B, skip_indices=()): (1, (y2, y0*y2, y1*y2)) """ import logging + logger = logging.getLogger(__name__) from .representation import repr_pretty @@ -735,13 +711,11 @@ def _generating_function_via_Omega_(inequalities, B, skip_indices=()): l = L.gen() logger.debug('mapping %s --> %s', l, repr_pretty(coeffs, 0)) it_coeffs = iter(coeffs) - numerator *= l**next(it_coeffs) + numerator *= l ** next(it_coeffs) assert numerator.parent() == L terms = tuple(l**c * t for c, t in zip(it_coeffs, terms)) - assert all(y == t for y, t in - (tuple(zip(B.gens(), terms))[i] for i in skip_indices)) - terms = tuple(t for i, t in enumerate(terms) - if i not in skip_indices) + assert all(y == t for y, t in (tuple(zip(B.gens(), terms))[i] for i in skip_indices)) + terms = tuple(t for i, t in enumerate(terms) if i not in skip_indices) logger.debug('terms denominator %s', terms) @@ -757,12 +731,9 @@ def decode_factor(factor): logger.debug('...(numerator has %s terms)', numerator.number_of_terms()) logger.debug('...numerator %s', numerator) - decoded_factors, other_factors = \ - partition((decode_factor(factor) for factor in terms), - lambda factor: factor[1] == 0) + decoded_factors, other_factors = partition((decode_factor(factor) for factor in terms), lambda factor: factor[1] == 0) other_factors = tuple(factor[0] for factor in other_factors) - numerator, factors_denominator = \ - _Omega_(numerator.monomial_coefficients(), tuple(decoded_factors)) + numerator, factors_denominator = _Omega_(numerator.monomial_coefficients(), tuple(decoded_factors)) terms = other_factors + factors_denominator return _simplify_(numerator, terms) @@ -872,8 +843,7 @@ def apply_rules(self, numerator, terms): sage: T.apply_rules(*gf(T.inequalities, B)) (1, (y0*y1, y1, y2)) """ - return (numerator.subs(self.rules) * self.factor, - tuple(t.subs(self.rules) for t in terms)) + return (numerator.subs(self.rules) * self.factor, tuple(t.subs(self.rules) for t in terms)) class _SplitOffSimpleInequalities(_TransformHrepresentation): @@ -1114,6 +1084,7 @@ def _transform_(self): B = self.B import logging + logger = logging.getLogger(__name__) from itertools import takewhile @@ -1128,20 +1099,18 @@ def _transform_(self): for coeffs in inequalities: dim = len(coeffs) if all(c >= 0 for c in coeffs): - logger.debug('skipping %s (all coefficients >= 0)', - repr_pretty(coeffs, 0)) + logger.debug('skipping %s (all coefficients >= 0)', repr_pretty(coeffs, 0)) continue constant = coeffs[0] - ones = tuple(i+1 for i, c in enumerate(coeffs[1:]) if c == 1) - mones = tuple(i+1 for i, c in enumerate(coeffs[1:]) if c == -1) - absgetwo = tuple(i+1 for i, c in enumerate(coeffs[1:]) if abs(c) >= 2) + ones = tuple(i + 1 for i, c in enumerate(coeffs[1:]) if c == 1) + mones = tuple(i + 1 for i, c in enumerate(coeffs[1:]) if c == -1) + absgetwo = tuple(i + 1 for i, c in enumerate(coeffs[1:]) if abs(c) >= 2) if len(ones) == 1 and not mones and not absgetwo: if constant < 0: # This case could be cleverly skipped... inequalities_filtered.append(coeffs) elif len(ones) == 1 and len(mones) == 1 and not absgetwo and constant <= 0: - logger.debug('handling %s', - repr_pretty(coeffs, 0)) + logger.debug('handling %s', repr_pretty(coeffs, 0)) chain_links[(mones[0], ones[0])] = constant else: inequalities_filtered.append(coeffs) @@ -1154,9 +1123,7 @@ def _transform_(self): for i in range(dim): D[(i, i)] = 1 for v in G.topological_sort(): - NP = iter(sorted(((n, potential[n] + chain_links[(n, v)]) - for n in G.neighbor_in_iterator(v)), - key=lambda k: (k[1], k[0]))) + NP = iter(sorted(((n, potential[n] + chain_links[(n, v)]) for n in G.neighbor_in_iterator(v)), key=lambda k: (k[1], k[0]))) n, p = next(NP, (None, 0)) potential[v] = p D[(0, v)] = -p @@ -1165,9 +1132,8 @@ def _transform_(self): D[(u, v)] = 1 for n, p in NP: - ell = len(tuple(takewhile(lambda u: u[0] == u[1], - zip(paths[n], paths[v])))) - coeffs = dim*[0] + ell = len(tuple(takewhile(lambda u: u[0] == u[1], zip(paths[n], paths[v])))) + coeffs = dim * [0] for u in paths[v][ell:]: coeffs[u] = 1 for u in paths[n][ell:]: @@ -1176,12 +1142,9 @@ def _transform_(self): inequalities_extra.append(tuple(coeffs)) T = matrix(ZZ, dim, dim, D) - self.inequalities = ([tuple(T * vector(ieq)) - for ieq in inequalities_filtered] - + inequalities_extra) + self.inequalities = [tuple(T * vector(ieq)) for ieq in inequalities_filtered] + inequalities_extra - rules_pre = ((y, B({tuple(row[1:]): 1})) - for y, row in zip((1,) + B.gens(), T.rows())) + rules_pre = ((y, B({tuple(row[1:]): 1})) for y, row in zip((1,) + B.gens(), T.rows())) self.factor = next(rules_pre)[1] self.rules = dict(rules_pre) @@ -1287,11 +1250,10 @@ def _transform_(self): gens = (1,) + B.gens() z = tuple(gens[i] for i in indices) gens_cols = tuple(zip(gens, TE.columns())) - rules_pre = ((y, y * prod(zz**(-c) for zz, c in zip(z, col))) - for y, col in (gens_cols[i] for i in indicesn)) + rules_pre = ((y, y * prod(zz ** (-c) for zz, c in zip(z, col))) for y, col in (gens_cols[i] for i in indicesn)) self.factor = next(rules_pre)[1] self.rules = dict(rules_pre) - self.indices = tuple(i-1 for i in indices) + self.indices = tuple(i - 1 for i in indices) self.equations = [] @staticmethod @@ -1335,8 +1297,7 @@ def prepare_equations_transformation(E): [ 0 -2/3 0 1], (2, 3), (0, 1) ) """ - indices_nonzero = tuple(i for i, col in enumerate(E.columns()) - if i > 0 and not col.is_zero()) + indices_nonzero = tuple(i for i, col in enumerate(E.columns()) if i > 0 and not col.is_zero()) indices = [] r = 0 for i in reversed(indices_nonzero): @@ -1454,12 +1415,11 @@ def _transform_(self): D = {(i, i): 1 for i in range(n)} for i, mr in mod.items(): - D[(i+1, i+1)] = mr[0] - D[(i+1, 0)] = mr[1] + D[(i + 1, i + 1)] = mr[0] + D[(i + 1, 0)] = mr[1] T = matrix(ZZ, n, n, D) - rules_pre = ((y, B({tuple(row[1:]): 1})) - for y, row in zip((1,) + B.gens(), T.columns())) + rules_pre = ((y, B({tuple(row[1:]): 1})) for y, row in zip((1,) + B.gens(), T.columns())) self.factor = next(rules_pre)[1] self.rules = dict(rules_pre) @@ -1505,16 +1465,10 @@ def generate_mods(equations): else: cols = TE.columns() assert all(cols[j][i] == 1 for i, j in enumerate(TEi)) - pre_mods = _compositions_mod((tuple(ZZ(cc*m) for cc in cols[i]) - for i in TEin), - m, r=(-cc*m for cc in cols[0]), - multidimensional=True) - mods = tuple({i-1: (aa.modulus(), ZZ(aa)) - for i, aa in zip(TEin, a) if aa.modulus() > 1} - for a in pre_mods) + pre_mods = _compositions_mod((tuple(ZZ(cc * m) for cc in cols[i]) for i in TEin), m, r=(-cc * m for cc in cols[0]), multidimensional=True) + mods = tuple({i - 1: (aa.modulus(), ZZ(aa)) for i, aa in zip(TEin, a) if aa.modulus() > 1} for a in pre_mods) else: - raise TypeError('equations over ZZ or QQ expected, but got ' - 'equations over {}.'.format(TE.base_ring())) + raise TypeError('equations over ZZ or QQ expected, but got ' 'equations over {}.'.format(TE.base_ring())) return mods @@ -1611,7 +1565,7 @@ def recursively_build_compositions(u, r): m = lcm(vv.order() for vv in v) Z = Zmod(m) for j in srange(m): - for a in recursively_build_compositions(u[1:], r - j*v): + for a in recursively_build_compositions(u[1:], r - j * v): yield (Z(j),) + a yield from recursively_build_compositions(u, r) diff --git a/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py b/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py index 6d26a0ff267..3786392081f 100644 --- a/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py +++ b/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py @@ -5,6 +5,7 @@ :class:`PPL lattice polytopes`. """ + ######################################################################## # Copyright (C) 2012 Volker Braun # @@ -24,6 +25,7 @@ class LatticePolytopeError(Exception): """ Base class for errors from lattice polytopes """ + pass @@ -32,6 +34,7 @@ class LatticePolytopesNotIsomorphicError(LatticePolytopeError): """ Raised when two lattice polytopes are not isomorphic. """ + pass @@ -40,6 +43,7 @@ class LatticePolytopeNoEmbeddingError(LatticePolytopeError): """ Raised when no embedding of the desired kind can be found. """ + pass @@ -101,13 +105,13 @@ def __call__(self, x): sage: M(LatticePolytope_PPL((0,0),(1,0),(0,1))) A 2-dimensional lattice polytope in ZZ^3 with 3 vertices """ - from sage.geometry.polyhedron.ppl_lattice_polytope import ( - LatticePolytope_PPL, LatticePolytope_PPL_class) + from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL, LatticePolytope_PPL_class + if isinstance(x, LatticePolytope_PPL_class): if x.is_empty(): from ppl import C_Polyhedron - return LatticePolytope_PPL(C_Polyhedron(self._b.degree(), - 'empty')) + + return LatticePolytope_PPL(C_Polyhedron(self._b.degree(), 'empty')) return LatticePolytope_PPL(*[self(v) for v in x.vertices()]) v = self._A * x + self._b v.set_immutable() @@ -124,8 +128,8 @@ def _repr_(self): sage: M._repr_() 'The map A*x+b with A=\n[ 1 2]\n[ 2 3]\n[-1 2]\nb = \n(1, 2, 3)' """ - s = 'The map A*x+b with A=\n'+str(self._A) - s += '\nb = \n'+str(self._b) + s = 'The map A*x+b with A=\n' + str(self._A) + s += '\nb = \n' + str(self._b) return s def domain_dim(self): diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index 6f55a84a10b..45106a30e73 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -69,6 +69,7 @@ :meth:`~sage.geometry.polyhedron.library.Polytopes.truncated_six_hundred_cell` :meth:`~sage.geometry.polyhedron.library.Polytopes.twenty_four_cell` """ + ######################################################################## # Copyright (C) 2008 Marshall Hampton # 2011 Volker Braun @@ -127,9 +128,10 @@ def zero_sum_projection(d, base_ring=None): """ from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector + if base_ring is None: from sage.rings.real_double import RDF as base_ring - basis = [vector(base_ring, [1]*i + [-i] + [0]*(d-i-1)) for i in range(1, d)] + basis = [vector(base_ring, [1] * i + [-i] + [0] * (d - i - 1)) for i in range(1, d)] return matrix(base_ring, [v / v.norm() for v in basis]) @@ -194,6 +196,7 @@ def project_points(*points, **kwds): if base_ring is None: from sage.rings.real_double import RDF as base_ring from sage.modules.free_module_element import vector + vecs = [vector(base_ring, p) for p in points] m = zero_sum_projection(len(vecs[0]), base_ring=base_ring) return [m * v for v in vecs] @@ -439,6 +442,7 @@ def gale_transform_to_primal(vectors, base_ring=None, backend=None): """ from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix + if base_ring: vectors = tuple(vector(base_ring, x) for x in vectors) else: @@ -464,6 +468,7 @@ def gale_transform_to_primal(vectors, base_ring=None, backend=None): solutions = Polyhedron(lines=tuple(ker.basis_matrix()), base_ring=base_ring, backend=backend) from sage.matrix.special import identity_matrix + pos_orthant = Polyhedron(rays=identity_matrix(len(vectors)), base_ring=base_ring, backend=backend) pos_solutions = solutions.intersection(pos_orthant) if base_ring is ZZ: @@ -474,15 +479,15 @@ def gale_transform_to_primal(vectors, base_ring=None, backend=None): x = pos_solutions.representative_point() if not all(y > 0 for y in x): raise ValueError("input vectors not totally cyclic") - vectors = tuple(vec*x[i] for i, vec in enumerate(vectors)) + vectors = tuple(vec * x[i] for i, vec in enumerate(vectors)) # The right kernel of ``vectors`` has a basis of the form ``[[1], [V]]``, # where ``V`` is the dehomogenized dual point configuration. # If we append a row of ones to ``vectors``, ``V`` is just the right kernel. if base_ring: - m = matrix(base_ring, vectors).transpose().stack(matrix(base_ring, [[1]*len(vectors)])) + m = matrix(base_ring, vectors).transpose().stack(matrix(base_ring, [[1] * len(vectors)])) else: - m = matrix(vectors).transpose().stack(matrix([[1]*len(vectors)])) + m = matrix(vectors).transpose().stack(matrix([[1] * len(vectors)])) if m.rank() != len(vectors[0]) + 1: # The given vectors do not span the ambient space, @@ -563,10 +568,11 @@ def regular_polygon(self, n, exact=True, base_ring=None, backend=None): from sage.rings.real_double import RDF as base_ring try: - omega = 2*base_ring.pi() / n - verts = [((i*omega).sin(), (i*omega).cos()) for i in range(n)] + omega = 2 * base_ring.pi() / n + verts = [((i * omega).sin(), (i * omega).cos()) for i in range(n)] except AttributeError: from sage.rings.qqbar import QQbar + z = QQbar.zeta(n) verts = [(base_ring((z**k).imag()), base_ring((z**k).real())) for k in range(n)] @@ -619,10 +625,10 @@ def Birkhoff_polytope(self, n, backend=None): sage: TestSuite(polytopes.Birkhoff_polytope(3)).run() """ from itertools import permutations + verts = [] for p in permutations(range(n)): - verts.append([ZZ.one() if p[i] == j else ZZ.zero() - for j in range(n) for i in range(n)]) + verts.append([ZZ.one() if p[i] == j else ZZ.zero() for j in range(n) for i in range(n)]) return Polyhedron(vertices=verts, base_ring=ZZ, backend=backend) def simplex(self, dim=3, project=False, base_ring=None, backend=None): @@ -693,7 +699,7 @@ def simplex(self, dim=3, project=False, base_ring=None, backend=None): sage: TestSuite(s6norm).run() # optional - pynormaliz sage: TestSuite(polytopes.simplex(5)).run() """ - verts = list((ZZ**(dim + 1)).basis()) + verts = list((ZZ ** (dim + 1)).basis()) if project: # Handling of default in base_ring is delegated to project_points verts = project_points(*verts, base_ring=base_ring) @@ -766,6 +772,7 @@ def icosahedron(self, exact=True, base_ring=None, backend=None): """ if base_ring is None and exact: from sage.rings.number_field.number_field import QuadraticField + K = QuadraticField(5, 'sqrt5') sqrt5 = K.gen() g = (1 + sqrt5) / 2 @@ -777,8 +784,7 @@ def icosahedron(self, exact=True, base_ring=None, backend=None): r12 = base_ring.one() / 2 z = base_ring.zero() - pts = [[z, s1 * r12, s2 * g / 2] - for s1, s2 in itertools.product([1, -1], repeat=2)] + pts = [[z, s1 * r12, s2 * g / 2] for s1, s2 in itertools.product([1, -1], repeat=2)] verts = [p(v) for p in AlternatingGroup(3) for v in pts] return Polyhedron(vertices=verts, base_ring=base_ring, backend=backend) @@ -886,6 +892,7 @@ def small_rhombicuboctahedron(self, exact=True, base_ring=None, backend=None): """ if base_ring is None and exact: from sage.rings.number_field.number_field import QuadraticField + K = QuadraticField(2, 'sqrt2') sqrt2 = K.gen() base_ring = K @@ -897,9 +904,9 @@ def small_rhombicuboctahedron(self, exact=True, base_ring=None, backend=None): one = base_ring.one() a = sqrt2 + one verts = [] - verts.extend([s1*one, s2*one, s3*a] for s1, s2, s3 in itertools.product([1, -1], repeat=3)) - verts.extend([s1*one, s3*a, s2*one] for s1, s2, s3 in itertools.product([1, -1], repeat=3)) - verts.extend([s1*a, s2*one, s3*one] for s1, s2, s3 in itertools.product([1, -1], repeat=3)) + verts.extend([s1 * one, s2 * one, s3 * a] for s1, s2, s3 in itertools.product([1, -1], repeat=3)) + verts.extend([s1 * one, s3 * a, s2 * one] for s1, s2, s3 in itertools.product([1, -1], repeat=3)) + verts.extend([s1 * a, s2 * one, s3 * one] for s1, s2, s3 in itertools.product([1, -1], repeat=3)) return Polyhedron(vertices=verts, backend=backend) def great_rhombicuboctahedron(self, exact=True, base_ring=None, backend=None): @@ -945,6 +952,7 @@ def great_rhombicuboctahedron(self, exact=True, base_ring=None, backend=None): """ if base_ring is None and exact: from sage.rings.number_field.number_field import QuadraticField + base_ring = QuadraticField(2, 'sqrt2') sqrt2 = base_ring.gen() else: @@ -955,9 +963,7 @@ def great_rhombicuboctahedron(self, exact=True, base_ring=None, backend=None): one = base_ring.one() v1 = sqrt2 + 1 v2 = 2 * sqrt2 + 1 - verts = [[s1 * z1, s2 * z2, s3 * z3] - for z1, z2, z3 in itertools.permutations([one, v1, v2]) - for s1, s2, s3 in itertools.product([1, -1], repeat=3)] + verts = [[s1 * z1, s2 * z2, s3 * z3] for z1, z2, z3 in itertools.permutations([one, v1, v2]) for s1, s2, s3 in itertools.product([1, -1], repeat=3)] return Polyhedron(vertices=verts, base_ring=base_ring, backend=backend) def rhombic_dodecahedron(self, backend=None): @@ -1049,9 +1055,7 @@ def cuboctahedron(self, backend=None): sage: co_norm = polytopes.cuboctahedron(backend='normaliz') # optional - pynormaliz sage: TestSuite(co_norm).run() # optional - pynormaliz """ - v = [[0, -1, -1], [0, 1, -1], [0, -1, 1], [0, 1, 1], - [-1, -1, 0], [1, -1, 0], [-1, 1, 0], [1, 1, 0], - [-1, 0, -1], [1, 0, -1], [-1, 0, 1], [1, 0, 1]] + v = [[0, -1, -1], [0, 1, -1], [0, -1, 1], [0, 1, 1], [-1, -1, 0], [1, -1, 0], [-1, 1, 0], [1, 1, 0], [-1, 0, -1], [1, 0, -1], [-1, 0, 1], [1, 0, 1]] return Polyhedron(vertices=v, base_ring=ZZ, backend=backend) def truncated_cube(self, exact=True, base_ring=None, backend=None): @@ -1103,6 +1107,7 @@ def truncated_cube(self, exact=True, base_ring=None, backend=None): """ if base_ring is None and exact: from sage.rings.number_field.number_field import QuadraticField + K = QuadraticField(2, 'sqrt2') sqrt2 = K.gen() g = sqrt2 - 1 @@ -1200,10 +1205,7 @@ def truncated_tetrahedron(self, backend=None): sage: tt_norm = polytopes.truncated_tetrahedron(backend='normaliz') # optional - pynormaliz sage: TestSuite(tt_norm).run() # optional - pynormaliz """ - v = [(3, 1, 1), (1, 3, 1), (1, 1, 3), - (-3, -1, 1), (-1, -3, 1), (-1, -1, 3), - (-3, 1, -1), (-1, 3, -1), (-1, 1, -3), - (3, -1, -1), (1, -3, -1), (1, -1, -3)] + v = [(3, 1, 1), (1, 3, 1), (1, 1, 3), (-3, -1, 1), (-1, -3, 1), (-1, -1, 3), (-3, 1, -1), (-1, 3, -1), (-1, 1, -3), (3, -1, -1), (1, -3, -1), (1, -1, -3)] return Polyhedron(vertices=v, base_ring=ZZ, backend=backend) def truncated_octahedron(self, backend=None): @@ -1247,8 +1249,7 @@ def truncated_octahedron(self, backend=None): sage: TestSuite(to_norm).run() # optional - pynormaliz, needs sage.combinat """ v = [(0, e, f) for e in [-1, 1] for f in [-2, 2]] - v = [(xyz[sigma(1) - 1], xyz[sigma(2) - 1], xyz[sigma(3) - 1]) - for sigma in Permutations(3) for xyz in v] + v = [(xyz[sigma(1) - 1], xyz[sigma(2) - 1], xyz[sigma(3) - 1]) for sigma in Permutations(3) for xyz in v] return Polyhedron(vertices=v, base_ring=ZZ, backend=backend) def octahedron(self, backend=None): @@ -1288,8 +1289,7 @@ def octahedron(self, backend=None): sage: o_norm = polytopes.octahedron(backend='normaliz') # optional - pynormaliz sage: TestSuite(o_norm).run() # optional - pynormaliz """ - v = [[0, 0, -1], [0, 0, 1], [1, 0, 0], - [-1, 0, 0], [0, 1, 0], [0, -1, 0]] + v = [[0, 0, -1], [0, 0, 1], [1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0]] return Polyhedron(vertices=v, base_ring=ZZ, backend=backend) def snub_cube(self, exact=False, base_ring=None, backend=None, verbose=False): @@ -1361,16 +1361,18 @@ def snub_cube(self, exact=False, base_ring=None, backend=None, verbose=False): sage: sc.f_vector() # optional - pynormaliz, needs sage.groups sage.rings.number_field (1, 24, 60, 38, 1) """ + def construct_z(field): # z here is the reciprocal of the tribonacci constant, that is, the # solution of the equation x^3 + x^2 + x - 1 = 0. tsqr33 = 3 * field(33).sqrt() - return ((17 + tsqr33)**QQ((1, 3)) - (-17 + tsqr33)**QQ((1, 3)) - 1) / 3 + return ((17 + tsqr33) ** QQ((1, 3)) - (-17 + tsqr33) ** QQ((1, 3)) - 1) / 3 if exact and base_ring is None: # construct the exact number field from sage.rings.qqbar import AA from sage.rings.number_field.number_field import NumberField + R = QQ['x'] f = R([-1, 1, 1, 1]) embedding = construct_z(AA) @@ -1382,7 +1384,7 @@ def construct_z(field): z = construct_z(base_ring) verts = [] - z2 = z ** 2 + z2 = z**2 A3 = AlternatingGroup(3) for e in [-1, 1]: for f in [-1, 1]: @@ -1500,10 +1502,9 @@ def icosidodecahedron(self, exact=True, backend=None): K = QuadraticField(5, 'sqrt5') one = K.one() - phi = (one+K.gen())/2 + phi = (one + K.gen()) / 2 - gens = [((-1)**a*one/2, (-1)**b*phi/2, (-1)**c*(one+phi)/2) - for a, b, c in product([0, 1], repeat=3)] + gens = [((-1) ** a * one / 2, (-1) ** b * phi / 2, (-1) ** c * (one + phi) / 2) for a, b, c in product([0, 1], repeat=3)] gens.extend([(0, 0, phi), (0, 0, -phi)]) verts = [] @@ -1513,6 +1514,7 @@ def icosidodecahedron(self, exact=True, backend=None): if exact: return Polyhedron(vertices=verts, base_ring=K, backend=backend) from sage.rings.real_mpfr import RR + verts = [(RR(x), RR(y), RR(z)) for x, y, z in verts] return Polyhedron(vertices=verts, backend=backend) @@ -1573,6 +1575,7 @@ def icosidodecahedron_V2(self, exact=True, base_ring=None, backend=None): """ if base_ring is None and exact: from sage.rings.number_field.number_field import QuadraticField + K = QuadraticField(5, 'sqrt5') sqrt5 = K.gen() g = (1 + sqrt5) / 2 @@ -1583,8 +1586,7 @@ def icosidodecahedron_V2(self, exact=True, base_ring=None, backend=None): g = (1 + base_ring(5).sqrt()) / 2 pts = [[g, 0, 0], [-g, 0, 0]] - pts += [[s1 * base_ring.one() / 2, s2 * g / 2, s3 * (1 + g)/2] - for s1, s2, s3 in itertools.product([1, -1], repeat=3)] + pts += [[s1 * base_ring.one() / 2, s2 * g / 2, s3 * (1 + g) / 2] for s1, s2, s3 in itertools.product([1, -1], repeat=3)] verts = pts verts += [[v[1], v[2], v[0]] for v in pts] verts += [[v[2], v[0], v[1]] for v in pts] @@ -1656,6 +1658,7 @@ def truncated_dodecahedron(self, exact=True, base_ring=None, backend=None): """ if base_ring is None and exact: from sage.rings.number_field.number_field import QuadraticField + K = QuadraticField(5, 'sqrt5') sqrt5 = K.gen() g = (1 + sqrt5) / 2 @@ -1666,12 +1669,9 @@ def truncated_dodecahedron(self, exact=True, base_ring=None, backend=None): g = (1 + base_ring(5).sqrt()) / 2 z = base_ring.zero() - pts = [[z, s1 * base_ring.one() / g, s2 * (2 + g)] - for s1, s2 in itertools.product([1, -1], repeat=2)] - pts += [[s1 * base_ring.one() / g, s2 * g, s3 * (2 * g)] - for s1, s2, s3 in itertools.product([1, -1], repeat=3)] - pts += [[s1 * g, s2 * base_ring(2), s3 * (g ** 2)] - for s1, s2, s3 in itertools.product([1, -1], repeat=3)] + pts = [[z, s1 * base_ring.one() / g, s2 * (2 + g)] for s1, s2 in itertools.product([1, -1], repeat=2)] + pts += [[s1 * base_ring.one() / g, s2 * g, s3 * (2 * g)] for s1, s2, s3 in itertools.product([1, -1], repeat=3)] + pts += [[s1 * g, s2 * base_ring(2), s3 * (g**2)] for s1, s2, s3 in itertools.product([1, -1], repeat=3)] verts = pts verts += [[v[1], v[2], v[0]] for v in pts] verts += [[v[2], v[0], v[1]] for v in pts] @@ -1753,11 +1753,7 @@ def Kirkman_icosahedron(self, backend=None): sage: ki_norm = polytopes.Kirkman_icosahedron(backend='normaliz') # optional - pynormaliz sage: TestSuite(ki_norm).run() # optional - pynormaliz """ - vertices = [[9, 6, 6], [-9, 6, 6], [9, -6, 6], [9, 6, -6], - [-9, -6, 6], [-9, 6, -6], [9, -6, -6], [-9, -6, -6], - [12, 4, 0], [-12, 4, 0], [12, -4, 0], [-12, -4, 0], - [0, 12, 8], [0, -12, 8], [0, 12, -8], [0, -12, -8], - [6, 0, 12], [-6, 0, 12], [6, 0, -12], [-6, 0, -12]] + vertices = [[9, 6, 6], [-9, 6, 6], [9, -6, 6], [9, 6, -6], [-9, -6, 6], [-9, 6, -6], [9, -6, -6], [-9, -6, -6], [12, 4, 0], [-12, 4, 0], [12, -4, 0], [-12, -4, 0], [0, 12, 8], [0, -12, 8], [0, 12, -8], [0, -12, -8], [6, 0, 12], [-6, 0, 12], [6, 0, -12], [-6, 0, -12]] return Polyhedron(vertices=vertices, base_ring=ZZ, backend=backend) def rhombicosidodecahedron(self, exact=True, base_ring=None, backend=None): @@ -1818,6 +1814,7 @@ def rhombicosidodecahedron(self, exact=True, base_ring=None, backend=None): """ if base_ring is None and exact: from sage.rings.number_field.number_field import QuadraticField + K = QuadraticField(5, 'sqrt5') sqrt5 = K.gen() g = (1 + sqrt5) / 2 @@ -1827,12 +1824,9 @@ def rhombicosidodecahedron(self, exact=True, base_ring=None, backend=None): from sage.rings.real_double import RDF as base_ring g = (1 + base_ring(5).sqrt()) / 2 - pts = [[s1 * base_ring.one(), s2 * base_ring.one(), s3 * (g**3)] - for s1, s2, s3 in itertools.product([1, -1], repeat=3)] - pts += [[s1 * (g**2), s2 * g, s3 * 2 * g] - for s1, s2, s3 in itertools.product([1, -1], repeat=3)] - pts += [[s1 * (2 + g), 0, s2 * (g**2)] - for s1, s2 in itertools.product([1, -1], repeat=2)] + pts = [[s1 * base_ring.one(), s2 * base_ring.one(), s3 * (g**3)] for s1, s2, s3 in itertools.product([1, -1], repeat=3)] + pts += [[s1 * (g**2), s2 * g, s3 * 2 * g] for s1, s2, s3 in itertools.product([1, -1], repeat=3)] + pts += [[s1 * (2 + g), 0, s2 * (g**2)] for s1, s2 in itertools.product([1, -1], repeat=2)] # the vertices are all even permutations of the lists in pts verts = pts verts += [[v[1], v[2], v[0]] for v in pts] @@ -1895,6 +1889,7 @@ def truncated_icosidodecahedron(self, exact=True, base_ring=None, backend=None): """ if base_ring is None and exact: from sage.rings.number_field.number_field import QuadraticField + K = QuadraticField(5, 'sqrt5') sqrt5 = K.gen() g = (1 + sqrt5) / 2 @@ -1904,16 +1899,11 @@ def truncated_icosidodecahedron(self, exact=True, base_ring=None, backend=None): from sage.rings.real_double import RDF as base_ring g = (1 + base_ring(5).sqrt()) / 2 - pts = [[s1 * 1 / g, s2 * 1 / g, s3 * (3 + g)] - for s1, s2, s3 in itertools.product([1, -1], repeat=3)] - pts += [[s1 * 2 / g, s2 * g, s3 * (1 + 2 * g)] - for s1, s2, s3 in itertools.product([1, -1], repeat=3)] - pts += [[s1 * 1 / g, s2 * (g**2), s3 * (-1 + 3 * g)] - for s1, s2, s3 in itertools.product([1, -1], repeat=3)] - pts += [[s1 * (-1 + 2 * g), s2 * 2 * base_ring.one(), s3 * (2 + g)] - for s1, s2, s3 in itertools.product([1, -1], repeat=3)] - pts += [[s1 * g, s2 * 3 * base_ring.one(), s3 * 2 * g] - for s1, s2, s3 in itertools.product([1, -1], repeat=3)] + pts = [[s1 * 1 / g, s2 * 1 / g, s3 * (3 + g)] for s1, s2, s3 in itertools.product([1, -1], repeat=3)] + pts += [[s1 * 2 / g, s2 * g, s3 * (1 + 2 * g)] for s1, s2, s3 in itertools.product([1, -1], repeat=3)] + pts += [[s1 * 1 / g, s2 * (g**2), s3 * (-1 + 3 * g)] for s1, s2, s3 in itertools.product([1, -1], repeat=3)] + pts += [[s1 * (-1 + 2 * g), s2 * 2 * base_ring.one(), s3 * (2 + g)] for s1, s2, s3 in itertools.product([1, -1], repeat=3)] + pts += [[s1 * g, s2 * 3 * base_ring.one(), s3 * 2 * g] for s1, s2, s3 in itertools.product([1, -1], repeat=3)] # the vertices are all ever permutations of the lists in pts verts = pts verts += [[v[1], v[2], v[0]] for v in pts] @@ -1970,23 +1960,17 @@ def snub_dodecahedron(self, base_ring=None, backend=None, verbose=False): if base_ring is None: from sage.rings.real_double import RDF as base_ring phi = (1 + base_ring(5).sqrt()) / 2 - xi = ((phi/2 + (phi - ZZ(5)/27).sqrt()/2)**(~ZZ(3)) + - (phi/2 - (phi - ZZ(5)/27).sqrt()/2)**(~ZZ(3))) + xi = (phi / 2 + (phi - ZZ(5) / 27).sqrt() / 2) ** (~ZZ(3)) + (phi / 2 - (phi - ZZ(5) / 27).sqrt() / 2) ** (~ZZ(3)) alpha = xi - 1 / xi beta = xi * phi + phi**2 + phi / xi signs = [[-1, -1, -1], [-1, 1, 1], [1, -1, 1], [1, 1, -1]] - pts = [[s1 * 2 * alpha, s2 * 2 * base_ring.one(), s3 * 2 * beta] - for s1, s2, s3 in signs] - pts += [[s1 * (alpha + beta/phi + phi), s2 * (-alpha * phi + beta + 1/phi), s3 * (alpha/phi + beta * phi - 1)] - for s1, s2, s3 in signs] - pts += [[s1 * (alpha + beta/phi - phi), s2 * (alpha * phi - beta + 1/phi), s3 * (alpha/phi + beta * phi + 1)] - for s1, s2, s3 in signs] - pts += [[s1 * (-alpha/phi + beta * phi + 1), s2 * (-alpha + beta/phi - phi), s3 * (alpha * phi + beta - 1/phi)] - for s1, s2, s3 in signs] - pts += [[s1 * (-alpha/phi + beta * phi - 1), s2 * (alpha - beta/phi - phi), s3 * (alpha * phi + beta + 1/phi)] - for s1, s2, s3 in signs] + pts = [[s1 * 2 * alpha, s2 * 2 * base_ring.one(), s3 * 2 * beta] for s1, s2, s3 in signs] + pts += [[s1 * (alpha + beta / phi + phi), s2 * (-alpha * phi + beta + 1 / phi), s3 * (alpha / phi + beta * phi - 1)] for s1, s2, s3 in signs] + pts += [[s1 * (alpha + beta / phi - phi), s2 * (alpha * phi - beta + 1 / phi), s3 * (alpha / phi + beta * phi + 1)] for s1, s2, s3 in signs] + pts += [[s1 * (-alpha / phi + beta * phi + 1), s2 * (-alpha + beta / phi - phi), s3 * (alpha * phi + beta - 1 / phi)] for s1, s2, s3 in signs] + pts += [[s1 * (-alpha / phi + beta * phi - 1), s2 * (alpha - beta / phi - phi), s3 * (alpha * phi + beta + 1 / phi)] for s1, s2, s3 in signs] # the vertices are all even permutations of the lists in pts verts = pts @@ -2268,21 +2252,23 @@ def six_hundred_cell(self, exact=False, backend=None): """ if exact: from sage.rings.number_field.number_field import QuadraticField + K = QuadraticField(5, 'sqrt5') sqrt5 = K.gen() g = (1 + sqrt5) / 2 base_ring = K else: from sage.rings.real_double import RDF as base_ring + g = (1 + base_ring(5).sqrt()) / 2 q12 = base_ring(1) / base_ring(2) z = base_ring.zero() - verts = [[s1*q12, s2*q12, s3*q12, s4*q12] for s1, s2, s3, s4 in itertools.product([1, -1], repeat=4)] - V = (base_ring)**4 + verts = [[s1 * q12, s2 * q12, s3 * q12, s4 * q12] for s1, s2, s3, s4 in itertools.product([1, -1], repeat=4)] + V = (base_ring) ** 4 verts.extend(V.basis()) verts.extend(-v for v in V.basis()) - pts = [[s1 * q12, s2*g/2, s3/(2*g), z] for s1, s2, s3 in itertools.product([1, -1], repeat=3)] + pts = [[s1 * q12, s2 * g / 2, s3 / (2 * g), z] for s1, s2, s3 in itertools.product([1, -1], repeat=3)] for p in AlternatingGroup(4): verts.extend(p(x) for x in pts) return Polyhedron(vertices=verts, base_ring=base_ring, backend=backend) @@ -2339,53 +2325,46 @@ def grand_antiprism(self, exact=True, backend=None, verbose=False): if exact: from sage.rings.number_field.number_field import QuadraticField + K = QuadraticField(5, 'sqrt5') sqrt5 = K.gen() g = (1 + sqrt5) / 2 base_ring = K else: from sage.rings.real_double import RDF as base_ring + g = (1 + base_ring(5).sqrt()) / 2 q12 = base_ring(1) / base_ring(2) z = base_ring.zero() - verts = [[s1*q12, s2*q12, s3*q12, s4*q12] - for s1, s2, s3, s4 in product([1, -1], repeat=4)] - V = (base_ring)**4 + verts = [[s1 * q12, s2 * q12, s3 * q12, s4 * q12] for s1, s2, s3, s4 in product([1, -1], repeat=4)] + V = (base_ring) ** 4 verts.extend(V.basis()[2:]) verts.extend(-v for v in V.basis()[2:]) - verts.extend([s1 * q12, s2/(2*g), s3*g/2, z] - for s1, s2, s3 in product([1, -1], repeat=3)) - verts.extend([s3*g/2, s1 * q12, s2/(2*g), z] - for s1, s2, s3 in product([1, -1], repeat=3)) - verts.extend([s2/(2*g), s3*g/2, s1 * q12, z] - for s1, s2, s3 in product([1, -1], repeat=3)) + verts.extend([s1 * q12, s2 / (2 * g), s3 * g / 2, z] for s1, s2, s3 in product([1, -1], repeat=3)) + verts.extend([s3 * g / 2, s1 * q12, s2 / (2 * g), z] for s1, s2, s3 in product([1, -1], repeat=3)) + verts.extend([s2 / (2 * g), s3 * g / 2, s1 * q12, z] for s1, s2, s3 in product([1, -1], repeat=3)) - verts.extend([s1 * q12, s2*g/2, z, s3/(2*g)] - for s1, s2, s3 in product([1, -1], repeat=3)) - verts.extend([s3/(2*g), s1 * q12, z, s2*g/2] - for s1, s2, s3 in product([1, -1], repeat=3)) - verts.extend([s2*g/2, s3/(2*g), z, s1 * q12] - for s1, s2, s3 in product([1, -1], repeat=3)) + verts.extend([s1 * q12, s2 * g / 2, z, s3 / (2 * g)] for s1, s2, s3 in product([1, -1], repeat=3)) + verts.extend([s3 / (2 * g), s1 * q12, z, s2 * g / 2] for s1, s2, s3 in product([1, -1], repeat=3)) + verts.extend([s2 * g / 2, s3 / (2 * g), z, s1 * q12] for s1, s2, s3 in product([1, -1], repeat=3)) - verts.extend([s1 * q12, z, s2/(2*g), s3*g/2] - for s1, s2, s3 in product([1, -1], repeat=3)) + verts.extend([s1 * q12, z, s2 / (2 * g), s3 * g / 2] for s1, s2, s3 in product([1, -1], repeat=3)) - verts.extend([z, s1 * q12, s2*g/2, s3/(2*g)] - for s1, s2, s3 in product([1, -1], repeat=3)) + verts.extend([z, s1 * q12, s2 * g / 2, s3 / (2 * g)] for s1, s2, s3 in product([1, -1], repeat=3)) - verts.extend([z, s1/(2*g), q12, g/2] for s1 in [1, -1]) - verts.extend([z, s1/(2*g), -q12, -g/2] for s1 in [1, -1]) + verts.extend([z, s1 / (2 * g), q12, g / 2] for s1 in [1, -1]) + verts.extend([z, s1 / (2 * g), -q12, -g / 2] for s1 in [1, -1]) - verts.extend([z, s1*g/2, 1/(2*g), q12] for s1 in [1, -1]) - verts.extend([z, s1*g/2, -1/(2*g), -q12] for s1 in [1, -1]) + verts.extend([z, s1 * g / 2, 1 / (2 * g), q12] for s1 in [1, -1]) + verts.extend([z, s1 * g / 2, -1 / (2 * g), -q12] for s1 in [1, -1]) - verts.extend([s1*g/2, z, q12, -1/(2*g)] for s1 in [1, -1]) - verts.extend([s1*g/2, z, -q12, 1/(2*g)] for s1 in [1, -1]) + verts.extend([s1 * g / 2, z, q12, -1 / (2 * g)] for s1 in [1, -1]) + verts.extend([s1 * g / 2, z, -q12, 1 / (2 * g)] for s1 in [1, -1]) - verts.extend([s1/(2*g), z, g/2, -q12] for s1 in [1, -1]) - verts.extend([s1/(2*g), z, -g/2, q12] for s1 in [1, -1]) + verts.extend([s1 / (2 * g), z, g / 2, -q12] for s1 in [1, -1]) + verts.extend([s1 / (2 * g), z, -g / 2, q12] for s1 in [1, -1]) return Polyhedron(vertices=verts, base_ring=base_ring, backend=backend, verbose=verbose) @@ -2414,9 +2393,10 @@ def Gosset_3_21(self, backend=None): sage: TestSuite(G321).run() # optional - pynormaliz, long time """ from itertools import combinations + verts = [] for i, j in combinations(range(8), 2): - x = [1]*8 + x = [1] * 8 x[i] = x[j] = -3 verts.append(x) verts.append([-xx for xx in x]) @@ -2453,7 +2433,7 @@ def cyclic_polytope(self, dim, n, base_ring=QQ, backend=None): sage: cp = polytopes.cyclic_polytope(4,10,backend='normaliz') # optional - pynormaliz sage: TestSuite(cp).run() # optional - pynormaliz """ - verts = [[t**i for i in range(1, dim+1)] for t in range(n)] + verts = [[t**i for i in range(1, dim + 1)] for t in range(n)] return Polyhedron(vertices=verts, base_ring=base_ring, backend=backend) def hypersimplex(self, dim, k, project=False, backend=None): @@ -2585,15 +2565,12 @@ def tri(m): # Each proper `S \subset [n]` corresponds exactly to # a facet that minimizes the coordinates in `S`. # The minimal sum for `m` coordinates is `(m*(m+1))/2`. - ieqs = ((-tri(sum(x)),) + x - for x in itertools.product([0, 1], repeat=n) - if 0 < sum(x) < n) + ieqs = ((-tri(sum(x)),) + x for x in itertools.product([0, 1], repeat=n) if 0 < sum(x) < n) # Adding the defining equality. eqns = ((-tri(n),) + tuple(1 for _ in range(n)),) - return parent([verts, [], []], [ieqs, eqns], - Vrep_minimal=True, Hrep_minimal=True, pref_rep='Hrep') + return parent([verts, [], []], [ieqs, eqns], Vrep_minimal=True, Hrep_minimal=True, pref_rep='Hrep') def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regular=False, backend=None): r""" @@ -2780,6 +2757,7 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula sage: TestSuite(perm_h3).run() # optional - pynormaliz # needs sage.combinat sage.rings.number_field """ from sage.combinat.root_system.coxeter_group import CoxeterGroup + try: W = CoxeterGroup(coxeter_type) except (TypeError, ValueError): @@ -2788,10 +2766,10 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula weights = W.fundamental_weights() if point is None: point = [ZZ.one()] * n - apex = sum(point[i-1] * weights[i] for i in weights.keys()) + apex = sum(point[i - 1] * weights[i] for i in weights.keys()) # Try to rationalize the starting point non_zero_index = list(apex).index([x for x in apex if x != 0][0]) - apex = (QQ(1)/apex[non_zero_index]) * apex + apex = (QQ(1) / apex[non_zero_index]) * apex apex.set_immutable() vertices = set() # This does not work well with UCF, so we set it to None: @@ -2807,19 +2785,20 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula from sage.rings.qqbar import AA from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector + # This transformation fixes the first root and adjust the other # roots to have the correct angles bf = W.bilinear_form() - transf_col = [[1] + [0]*(n-1)] + transf_col = [[1] + [0] * (n - 1)] for i in range(1, n): - new_col = [0]*i + [1] + [0]*(n-i-1) + new_col = [0] * i + [1] + [0] * (n - i - 1) transf_col += [new_col] m = matrix(AA, transf_col) col = bf.column(i) - rhs = vector(AA, list(col[:i+1])) + rhs = vector(AA, list(col[: i + 1])) adjusted_col = m.solve_right(rhs) # Then scales the images so that the polytope is inscribed - c = 1 - sum(adjusted_col[j]**2 for j in range(n) if j != i) + c = 1 - sum(adjusted_col[j] ** 2 for j in range(n) if j != i) c = c.sqrt() adjusted_col[i] = c transf_col[-1] = adjusted_col @@ -2830,6 +2809,7 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula br = AA if not exact: from sage.rings.real_double import RDF + vertices = [v.change_ring(RDF) for v in vertices] br = RDF return Polyhedron(vertices=vertices, backend=backend, base_ring=br) @@ -2871,8 +2851,7 @@ def harmonic_polytope(self, n): if n <= 0: raise ValueError("n must be positive") parent = Polyhedra(ZZ, 2 * n) - D_vertices = [2 * [1 if j == i else 0 for j in range(n)] - for i in range(n)] + D_vertices = [2 * [1 if j == i else 0 for j in range(n)] for i in range(n)] Dn = parent([D_vertices, [], []], None, convert=False) perms = [list(sigma) for sigma in Permutations(n)] P_vertices = [a + b for a in perms for b in perms] @@ -3158,6 +3137,7 @@ def one_hundred_twenty_cell(self, exact=True, backend=None, construction='coxete if not exact: raise ValueError("The 'cdd' backend produces numerical inconsistencies, use 'exact=True'.") from sage.rings.number_field.number_field import QuadraticField + base_ring = QuadraticField(5, 'sqrt5') sqrt5 = base_ring.gen() phi = (1 + sqrt5) / 2 @@ -3171,25 +3151,17 @@ def one_hundred_twenty_cell(self, exact=True, backend=None, construction='coxete # [±1/phi^2,±phi,±phi,±phi] # [±1/phi,±1/phi,±1/phi,±phi^2] from sage.categories.cartesian_product import cartesian_product - full_perm_vectors = [ - [[1, -1], [1, -1], [1, -1], [-sqrt5, sqrt5]], - [[phi_inv**2, -phi_inv**2], [phi, -phi], [phi, -phi], [-phi, phi]], - [[phi_inv, -phi_inv], [phi_inv, -phi_inv], [phi_inv, -phi_inv], [-(phi**2), phi**2]] - ] + + full_perm_vectors = [[[1, -1], [1, -1], [1, -1], [-sqrt5, sqrt5]], [[phi_inv**2, -(phi_inv**2)], [phi, -phi], [phi, -phi], [-phi, phi]], [[phi_inv, -phi_inv], [phi_inv, -phi_inv], [phi_inv, -phi_inv], [-(phi**2), phi**2]]] for vect in full_perm_vectors: cp = cartesian_product(vect) # The group action creates duplicates, so we reduce it: - verts += list({tuple(p) for c in cp - for p in Permutations(list(c))}) + verts += list({tuple(p) for c in cp for p in Permutations(list(c))}) # The 96 even permutations of [0,±1/phi^2,±1,±phi^2] # The 96 even permutations of [0,±1/phi,±phi,±sqrt(5)] # The 192 even permutations of [±1/phi,±1,±phi,±2] - even_perm_vectors = [ - [[0], [phi_inv**2, -phi_inv**2], [1, -1], [-(phi**2), phi**2]], - [[0], [phi_inv, -phi_inv], [phi, -phi], [-sqrt5, sqrt5]], - [[phi_inv, -phi_inv], [1, -1], [phi, -phi], [-2, 2]] - ] + even_perm_vectors = [[[0], [phi_inv**2, -(phi_inv**2)], [1, -1], [-(phi**2), phi**2]], [[0], [phi_inv, -phi_inv], [phi, -phi], [-sqrt5, sqrt5]], [[phi_inv, -phi_inv], [1, -1], [phi, -phi], [-2, 2]]] even_perm = AlternatingGroup(4) for vect in even_perm_vectors: cp = cartesian_product(vect) @@ -3366,6 +3338,7 @@ def hypercube(self, dim, intervals=None, backend=None): # resp. x_{dim-i} - a_i >= 0 for i >= dim def ieq_b(i): return intervals[i][1] if i < dim else -intervals[i - dim][0] + else: raise ValueError("the dimension of the hypercube must match the number of intervals") @@ -3378,9 +3351,7 @@ def ieq_A(i, pos): return 1 return 0 - ieqs = (tuple(ieq_b(i) if pos == 0 else ieq_A(i, pos - 1) - for pos in range(dim + 1)) - for i in range(2 * dim)) + ieqs = (tuple(ieq_b(i) if pos == 0 else ieq_A(i, pos - 1) for pos in range(dim + 1)) for i in range(2 * dim)) return parent([cp, [], []], [ieqs, []], convert=convert, Vrep_minimal=True, Hrep_minimal=True, pref_rep='Hrep') @@ -3520,6 +3491,7 @@ def parallelotope(self, generators, backend=None): sage: TestSuite(P).run() # needs sage.rings.number_field """ from sage.modules.free_module_element import vector + generators = [vector(v) for v in generators] if not generators: return Polyhedron(backend=backend) diff --git a/src/sage/geometry/polyhedron/misc.py b/src/sage/geometry/polyhedron/misc.py index e61090e83c8..1c7ea982ed0 100644 --- a/src/sage/geometry/polyhedron/misc.py +++ b/src/sage/geometry/polyhedron/misc.py @@ -1,6 +1,7 @@ r""" Miscellaneous helper functions """ + # ********************************************************************** # Copyright (C) 2008 Marshall Hampton # Copyright (C) 2011 Volker Braun diff --git a/src/sage/geometry/polyhedron/modules/formal_polyhedra_module.py b/src/sage/geometry/polyhedron/modules/formal_polyhedra_module.py index 91101f120fc..047876f22e0 100644 --- a/src/sage/geometry/polyhedron/modules/formal_polyhedra_module.py +++ b/src/sage/geometry/polyhedron/modules/formal_polyhedra_module.py @@ -1,6 +1,7 @@ r""" Formal modules generated by polyhedra """ + from sage.combinat.free_module import CombinatorialFreeModule from sage.categories.graded_modules_with_basis import GradedModulesWithBasis @@ -84,6 +85,7 @@ def __classcall__(cls, base_ring, dimension, basis, category=None): basis = tuple(basis) if isinstance(basis, tuple): # To make sure it only checks for finite input from sage.geometry.polyhedron.base import Polyhedron_base + for P in basis: if not isinstance(P, Polyhedron_base): raise TypeError(f"{P} is not a polyhedron") @@ -91,11 +93,7 @@ def __classcall__(cls, base_ring, dimension, basis, category=None): raise TypeError(f"{P} does not belong to the ambient space") if category is None: category = GradedModulesWithBasis(base_ring) - return super().__classcall__(cls, - base_ring=base_ring, - dimension=dimension, - basis=basis, - category=category) + return super().__classcall__(cls, base_ring=base_ring, dimension=dimension, basis=basis, category=category) def __init__(self, base_ring, dimension, basis, category): """ diff --git a/src/sage/geometry/polyhedron/palp_database.py b/src/sage/geometry/polyhedron/palp_database.py index 86910bc85c6..7da9e28dbba 100644 --- a/src/sage/geometry/polyhedron/palp_database.py +++ b/src/sage/geometry/polyhedron/palp_database.py @@ -109,14 +109,13 @@ def __init__(self, dim, data_basename=None, output='Polyhedron'): self._data_basename = data_basename else: db = DatabaseReflexivePolytopes() - self._data_basename = os.path.join( - os.path.dirname(db.absolute_filename()), - f'Full{dim}d', 'zzdb') + self._data_basename = os.path.join(os.path.dirname(db.absolute_filename()), f'Full{dim}d', 'zzdb') info = self._data_basename + '.info' if not os.path.exists(info): raise ValueError('Cannot find PALP database: {}'.format(info)) from sage.geometry.polyhedron.parent import Polyhedra + self._polyhedron_parent = Polyhedra(ZZ, dim) self._output = output.lower() @@ -134,8 +133,7 @@ def _palp_Popen(self): <...Popen...> """ - return Popen([PalpExecutable("class").absolute_filename(), "-b2a", "-di", self._data_basename], - stdout=PIPE, encoding='utf-8', errors='surrogateescape') + return Popen([PalpExecutable("class").absolute_filename(), "-b2a", "-di", self._data_basename], stdout=PIPE, encoding='utf-8', errors='surrogateescape') def _read_vertices(self, stdout, rows, cols): r""" @@ -213,7 +211,7 @@ def _iterate_list(self, start, stop, step): return # EOF l = l.split() dim = ZZ(l[0]) # dimension - n = ZZ(l[1]) # number of vertices + n = ZZ(l[1]) # number of vertices if i >= start and (i - start) % step == 0: if dim == self._dim: vertices = self._read_vertices(palp_out, dim, n) @@ -398,6 +396,7 @@ class Reflexive4dHodge(PALPreader): (A vertex at (-1, -1, -1, -1), A vertex at (0, 0, 0, 1), A vertex at (0, 0, 1, 0), A vertex at (0, 1, 0, 0), A vertex at (1, 0, 0, 0)) """ + def __init__(self, h11, h21, data_basename=None, **kwds): """ The Python constructor. @@ -416,9 +415,7 @@ def __init__(self, h11, h21, data_basename=None, **kwds): data_basename = os.path.join(db.absolute_filename(), 'all') info = data_basename + '.vinfo' if not os.path.exists(info): - raise ValueError( - 'Cannot find PALP database: {}. Did you install the ' - 'polytopes_db_4d optional spkg?'.format(info)) + raise ValueError('Cannot find PALP database: {}. Did you install the ' 'polytopes_db_4d optional spkg?'.format(info)) PALPreader.__init__(self, dim, data_basename=data_basename, **kwds) self._h11 = h11 @@ -438,7 +435,4 @@ def _palp_Popen(self): <...Popen...> """ - return Popen([PalpExecutable('class-4d').absolute_filename(), '-He', - 'H{}:{}L100000000'.format(self._h21, self._h11), - '-di', self._data_basename], stdout=PIPE, - encoding='utf-8', errors='surrogateescape') + return Popen([PalpExecutable('class-4d').absolute_filename(), '-He', 'H{}:{}L100000000'.format(self._h21, self._h11), '-di', self._data_basename], stdout=PIPE, encoding='utf-8', errors='surrogateescape') diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index 4a88f5df4c2..1d4998b887a 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -28,9 +28,7 @@ lazy_import('sage.symbolic.ring', 'SymbolicRing') - -def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, *, - ambient_space=None, base_ring=None): +def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, *, ambient_space=None, base_ring=None): r""" Construct a suitable parent class for polyhedra. @@ -181,6 +179,7 @@ def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, * base_field = base_ring.fraction_field() try: from sage.interfaces.polymake import polymake, PolymakeElement + polymake_base_field = polymake(base_field) assert isinstance(polymake_base_field, PolymakeElement) # to muffle pyflakes except TypeError: @@ -192,8 +191,7 @@ def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, * if not base_ring.is_exact(): raise ValueError("the 'field' backend for polyhedron cannot be used with non-exact fields") return Polyhedra_field(base_ring.fraction_field(), ambient_dim, backend) - raise ValueError('No such backend (=' + str(backend) + - ') implemented for given basering (=' + str(base_ring) + ').') + raise ValueError('No such backend (=' + str(backend) + ') implemented for given basering (=' + str(base_ring) + ').') class Polyhedra_base(UniqueRepresentation, Parent): @@ -226,6 +224,7 @@ class Polyhedra_base(UniqueRepresentation, Parent): sage: Polyhedra(ZZ, 3) Polyhedra in ZZ^3 """ + def __init__(self, base_ring, ambient_dim, backend): """ The Python constructor. @@ -248,6 +247,7 @@ def __init__(self, base_ring, ambient_dim, backend): self._ambient_dim = ambient_dim from sage.categories.polyhedra import PolyhedralSets from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets + category = PolyhedralSets(base_ring) if ambient_dim == 0: category = category & FiniteEnumeratedSets() @@ -393,18 +393,12 @@ def some_elements(self): A 0-dimensional polyhedron in ZZ^0 defined as the convex hull of 1 vertex] """ if self.ambient_dim() == 0: - return [ - self.element_class(self, None, None), - self.element_class(self, None, [[], []])] + return [self.element_class(self, None, None), self.element_class(self, None, [[], []])] points = [] R = self.base_ring() for i in range(self.ambient_dim() + 5): - points.append([R(i*j ^ 2) for j in range(self.ambient_dim())]) - return [ - self.element_class(self, [points[0:self.ambient_dim() + 1], [], []], None), - self.element_class(self, [points[0:1], points[1:self.ambient_dim() + 1], []], None), - self.element_class(self, [points[0:3], points[4:5], []], None), - self.element_class(self, None, None)] + points.append([R(i * j ^ 2) for j in range(self.ambient_dim())]) + return [self.element_class(self, [points[0 : self.ambient_dim() + 1], [], []], None), self.element_class(self, [points[0:1], points[1 : self.ambient_dim() + 1], []], None), self.element_class(self, [points[0:3], points[4:5], []], None), self.element_class(self, None, None)] @cached_method def zero(self): @@ -475,8 +469,10 @@ def Vrepresentation_space(self): """ if self.base_ring() in Fields(): from sage.modules.free_module import VectorSpace + return VectorSpace(self.base_ring(), self.ambient_dim()) from sage.modules.free_module import FreeModule + return FreeModule(self.base_ring(), self.ambient_dim()) ambient_space = Vrepresentation_space @@ -496,8 +492,10 @@ def Hrepresentation_space(self): """ if self.base_ring() in Fields(): from sage.modules.free_module import VectorSpace + return VectorSpace(self.base_ring(), self.ambient_dim() + 1) from sage.modules.free_module import FreeModule + return FreeModule(self.base_ring(), self.ambient_dim() + 1) def _repr_base_ring(self): @@ -668,6 +666,7 @@ def convert_base_ring_Hrep(lstlst): else: newlstlst.append(lst) return convert_base_ring(newlstlst) + if nargs == 2: Vrep, Hrep = args if convert and Hrep: @@ -722,8 +721,7 @@ def _element_constructor_polyhedron(self, polyhedron, **kwds): """ Vrep = None if hasattr(self.Element, '_init_from_Vrepresentation_and_Hrepresentation'): - Vrep = [polyhedron.vertex_generator(), polyhedron.ray_generator(), - polyhedron.line_generator()] + Vrep = [polyhedron.vertex_generator(), polyhedron.ray_generator(), polyhedron.line_generator()] Hrep = [polyhedron.inequality_generator(), polyhedron.equation_generator()] return self._element_constructor_(Vrep, Hrep, Vrep_minimal=True, Hrep_minimal=True, **kwds) @@ -792,9 +790,7 @@ def change_ring(self, base_ring, backend=None, ambient_dim=None): if ambient_dim is None: ambient_dim = self.ambient_dim() - if base_ring == self.base_ring() and \ - ambient_dim == self.ambient_dim() and \ - (backend is None or backend == self.backend()): + if base_ring == self.base_ring() and ambient_dim == self.ambient_dim() and (backend is None or backend == self.backend()): return self # if not specified try the same backend @@ -868,6 +864,7 @@ def _coerce_base_ring(self, other): defined as the convex hull of 4 vertices """ from sage.structure.element import Element + if isinstance(other, Element): other = other.parent() if other in Rings(): @@ -994,13 +991,9 @@ def _get_action_(self, other, op, self_is_left): extended_other = other.base_extend(base_ring) action = ActedUponAction(extended_other, extended_self, not self_is_left) if self_is_left: - action = PrecomposedAction(action, - extended_self._internal_coerce_map_from(self).__copy__(), - extended_other._internal_coerce_map_from(other).__copy__()) + action = PrecomposedAction(action, extended_self._internal_coerce_map_from(self).__copy__(), extended_other._internal_coerce_map_from(other).__copy__()) else: - action = PrecomposedAction(action, - extended_other._internal_coerce_map_from(other).__copy__(), - extended_self._internal_coerce_map_from(self).__copy__()) + action = PrecomposedAction(action, extended_other._internal_coerce_map_from(other).__copy__(), extended_self._internal_coerce_map_from(self).__copy__()) return action if op is operator.mul and other in Rings().Commutative(): @@ -1010,13 +1003,9 @@ def _get_action_(self, other, op, self_is_left): extended = self.base_extend(ring) action = ActedUponAction(ring, extended, not self_is_left) if self_is_left: - action = PrecomposedAction(action, - extended._internal_coerce_map_from(self).__copy__(), - ring._internal_coerce_map_from(other).__copy__()) + action = PrecomposedAction(action, extended._internal_coerce_map_from(self).__copy__(), ring._internal_coerce_map_from(other).__copy__()) else: - action = PrecomposedAction(action, - ring._internal_coerce_map_from(other).__copy__(), - extended._internal_coerce_map_from(self).__copy__()) + action = PrecomposedAction(action, ring._internal_coerce_map_from(other).__copy__(), extended._internal_coerce_map_from(self).__copy__()) return action def _make_Inequality(self, polyhedron, data): @@ -1146,6 +1135,7 @@ def _make_Line(self, polyhedron, data): from sage.geometry.polyhedron.backend_cdd import Polyhedron_QQ_cdd + lazy_import('sage.geometry.polyhedron.backend_cdd_rdf', 'Polyhedron_RDF_cdd') from sage.geometry.polyhedron.backend_ppl import Polyhedron_ZZ_ppl, Polyhedron_QQ_ppl from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz, Polyhedron_ZZ_normaliz, Polyhedron_QQ_normaliz @@ -1178,6 +1168,7 @@ def _element_constructor_polyhedron(self, polyhedron, **kwds): A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 4 vertices """ from copy import copy + if polyhedron.backend() == "ppl": return self._element_constructor_(None, None, ppl_polyhedron=copy(polyhedron._ppl_polyhedron), **kwds) return Polyhedra_base._element_constructor_polyhedron(self, polyhedron, **kwds) @@ -1211,6 +1202,7 @@ def _element_constructor_polyhedron(self, polyhedron, **kwds): A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices """ from copy import copy + if polyhedron.backend() == "ppl": return self._element_constructor_(None, None, ppl_polyhedron=copy(polyhedron._ppl_polyhedron), **kwds) return Polyhedra_base._element_constructor_polyhedron(self, polyhedron, **kwds) diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index 3d361ef046d..bb997fe4e9c 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -128,6 +128,7 @@ def cyclic_sort_vertices_2d(Vlist): result += chain return result + ######################################################################### @@ -158,6 +159,7 @@ class ProjectionFuncStereographic: sage: ppoints[5] (-0.0918273..., -0.036375...) """ + def __init__(self, projection_point): """ Create a stereographic projection function. @@ -192,8 +194,7 @@ def __init__(self, projection_point): if denom.is_zero(): self.house = identity_matrix(RDF, self.dim) else: - house = identity_matrix(RDF, self.dim) \ - - 2*polediff*polediff.transpose()/denom # Householder reflector + house = identity_matrix(RDF, self.dim) - 2 * polediff * polediff.transpose() / denom # Householder reflector # Make it preserve orientation (chirality): self.house = diagonal_matrix(RDF, [1] * (self.dim - 1) + [-1]) * house @@ -233,8 +234,7 @@ def __call__(self, x): img = self.house * x denom = self.psize - img[self.dim - 1] if denom.is_zero(): - raise ValueError('Point cannot coincide with ' - 'coordinate singularity at ' + repr(x)) + raise ValueError('Point cannot coincide with ' 'coordinate singularity at ' + repr(x)) return vector(RDF, [img[i] / denom for i in range(self.dim - 1)]) @@ -251,6 +251,7 @@ class ProjectionFuncSchlegel: sage: proj([0,0,0,0])[0] 1.0 """ + def __init__(self, facet, projection_point): """ Initialize the projection. @@ -311,12 +312,13 @@ def __call__(self, x): # The intersection of the segment with the facet # See Ziegler's "Lectures on Polytopes" p.133 vx = vector(x) - z = (self.full_b) + z = self.full_b a = -(self.full_A) y = self.projection_point - preimage = y + ((z-a*y)/(a*vx-a*y))*(vx - y) + preimage = y + ((z - a * y) / (a * vx - a * y)) * (vx - y) # The transformation matrix acts on the right: - return preimage*self.A + self.b + return preimage * self.A + self.b + ######################################################################### @@ -464,7 +466,7 @@ def stereographic(self, projection_point=None): The projection of a polyhedron into 3 dimensions """ if projection_point is None: - projection_point = [1] + [0]*(self.polyhedron_ambient_dim-1) + projection_point = [1] + [0] * (self.polyhedron_ambient_dim - 1) return self(ProjectionFuncStereographic(projection_point)) def schlegel(self, facet=None, position=None): @@ -528,6 +530,7 @@ def schlegel(self, facet=None, position=None): """ from sage.geometry.polyhedron.face import PolyhedronFace from sage.rings.integer_ring import ZZ + if facet is None: facet = self.parent_polyhedron.facets()[0] elif not isinstance(facet, PolyhedronFace): @@ -544,12 +547,11 @@ def schlegel(self, facet=None, position=None): # Figure out a somehow canonical point of view inside the locus # polyhedron from sage.geometry.polyhedron.constructor import Polyhedron - the_ray = Polyhedron(vertices=[barycenter], - rays=[repr_point - barycenter], - backend=locus_polyhedron.backend()) & locus_polyhedron + + the_ray = Polyhedron(vertices=[barycenter], rays=[repr_point - barycenter], backend=locus_polyhedron.backend()) & locus_polyhedron projection_point = the_ray.representative_point() else: - projection_point = (1-position)*barycenter + position*repr_point + projection_point = (1 - position) * barycenter + position * repr_point if not locus_polyhedron.relative_interior_contains(projection_point): raise ValueError("the chosen position is too large") @@ -570,7 +572,7 @@ def coord_index_of(self, v): return self.coords.index(v) except ValueError: self.coords.append(v) - return len(self.coords)-1 + return len(self.coords) - 1 def coord_indices_of(self, v_list): """ @@ -722,35 +724,28 @@ def _init_lines_arrows(self, polyhedron): adj_matrix = polyhedron.vertex_adjacency_matrix() for i in range(len(obj)): if not obj[i].is_vertex(): - if any(adj_matrix[i, j] != 0 - for j in range(len(obj))): + if any(adj_matrix[i, j] != 0 for j in range(len(obj))): continue # obj[i] is ray or line v = polyhedron.vertices()[0].vector() r = obj[i].vector() - self.arrows.append( [ self.coord_index_of(v), - self.coord_index_of(v + r) ] ) + self.arrows.append([self.coord_index_of(v), self.coord_index_of(v + r)]) if obj[i].is_line(): - self.arrows.append( [ self.coord_index_of(v), - self.coord_index_of(v - r) ] ) + self.arrows.append([self.coord_index_of(v), self.coord_index_of(v - r)]) for j in range(len(obj)): if adj_matrix[i, j] == 0: continue if i < j and obj[j].is_vertex(): l = [obj[i].vector(), obj[j].vector()] - self.lines.append( [ self.coord_index_of(l[0]), - self.coord_index_of(l[1]) ] ) + self.lines.append([self.coord_index_of(l[0]), self.coord_index_of(l[1])]) if obj[j].is_ray(): l = [obj[i].vector(), obj[i].vector() + obj[j].vector()] - self.arrows.append( [ self.coord_index_of(l[0]), - self.coord_index_of(l[1]) ] ) + self.arrows.append([self.coord_index_of(l[0]), self.coord_index_of(l[1])]) if obj[j].is_line(): l1 = [obj[i].vector(), obj[i].vector() + obj[j].vector()] l2 = [obj[i].vector(), obj[i].vector() - obj[j].vector()] - self.arrows.append( [ self.coord_index_of(l1[0]), - self.coord_index_of(l1[1]) ] ) - self.arrows.append( [ self.coord_index_of(l2[0]), - self.coord_index_of(l2[1]) ] ) + self.arrows.append([self.coord_index_of(l1[0]), self.coord_index_of(l1[1])]) + self.arrows.append([self.coord_index_of(l2[0]), self.coord_index_of(l2[1])]) def _init_area_2d(self, polyhedron): """ @@ -772,10 +767,10 @@ def _init_area_2d(self, polyhedron): def adjacent_vertices(i): n = len(vertices) - if vertices[(i-1) % n].is_vertex(): - yield vertices[(i-1) % n] - if vertices[(i+1) % n].is_vertex(): - yield vertices[(i+1) % n] + if vertices[(i - 1) % n].is_vertex(): + yield vertices[(i - 1) % n] + if vertices[(i + 1) % n].is_vertex(): + yield vertices[(i + 1) % n] for i in range(len(vertices)): v = vertices[i] @@ -795,8 +790,7 @@ def adjacent_vertices(i): a_line = next(polyhedron.line_generator()) for shift in [a_line(), -a_line()]: for i in range(len(coords)): - polygons.append([coords[i - 1], coords[i], - coords[i] + shift, coords[i - 1] + shift]) + polygons.append([coords[i - 1], coords[i], coords[i] + shift, coords[i - 1] + shift]) if polyhedron.n_lines() == 2: line1, line2 = polyhedron.lines() @@ -804,7 +798,7 @@ def adjacent_vertices(i): v = coords[0] l1 = line1() l2 = line2() - polygons = [[v-l1-l2, v+l1-l2, v+l1+l2, v-l1+l2]] + polygons = [[v - l1 - l2, v + l1 - l2, v + l1 + l2, v - l1 + l2]] polygons = [self.coord_indices_of(p) for p in polygons] self.polygons.extend(polygons) @@ -857,10 +851,10 @@ def defining_equation(): # corresponding to a polygon def adjacent_vertices(i): n = len(vertices) - if vertices[(i-1) % n].is_vertex(): - yield vertices[(i-1) % n] - if vertices[(i+1) % n].is_vertex(): - yield vertices[(i+1) % n] + if vertices[(i - 1) % n].is_vertex(): + yield vertices[(i - 1) % n] + if vertices[(i + 1) % n].is_vertex(): + yield vertices[(i + 1) % n] for i in range(len(vertices)): v = vertices[i] @@ -875,7 +869,7 @@ def adjacent_vertices(i): if polyhedron.n_lines() == 0: assert faces, "no vertices?" - self.polygons.extend( [self.coord_indices_of(f) for f in faces] ) + self.polygons.extend([self.coord_indices_of(f) for f in faces]) return # now some special cases if there are lines (dim < ambient_dim) @@ -887,15 +881,14 @@ def adjacent_vertices(i): shift = a_line() for coords in faces: assert len(coords) == 2, "There must be two points." - polygons.append([coords[0] - shift, coords[1] - shift, - coords[1] + shift, coords[0] + shift]) + polygons.append([coords[0] - shift, coords[1] - shift, coords[1] + shift, coords[0] + shift]) if polyhedron.n_lines() == 2: line1, line2 = polyhedron.line_generator() l1 = line1() l2 = line2() for v in polyhedron.vertex_generator(): - polygons.append([v()-l1-l2, v()+l1-l2, v()+l1+l2, v()-l1+l2]) + polygons.append([v() - l1 - l2, v() + l1 - l2, v() + l1 + l2, v() - l1 + l2]) self.polygons.extend([self.coord_indices_of(p) for p in polygons]) @@ -942,7 +935,7 @@ def render_line_1d(self, **kwds): if len(self.lines) == 1: line = self.coordinates_of(self.lines[0]) return line2d([line[0] + [0], line[1] + [0]], **kwds) - assert False # unreachable + assert False # unreachable def render_points_2d(self, **kwds): """ @@ -991,8 +984,7 @@ def render_fill_2d(self, **kwds): sage: filled_poly.axes_width() # needs sage.plot 0.8 """ - poly = [polygon2d(self.coordinates_of(p), **kwds) - for p in self.polygons] + poly = [polygon2d(self.coordinates_of(p), **kwds) for p in self.polygons] return sum(poly) def render_vertices_3d(self, **kwds): @@ -1213,8 +1205,8 @@ def render_3d(self, point_opts=None, line_opts=None, polygon_opts=None): point_opts.setdefault('size', 10) pplt = self.render_vertices_3d(**point_opts) if isinstance(line_opts, dict): - line_opts.setdefault('width', 1) # controls the width of arrow3d for a ray - line_opts.setdefault('thickness', 1) # controls the thickness of line3d + line_opts.setdefault('width', 1) # controls the width of arrow3d for a ray + line_opts.setdefault('thickness', 1) # controls the thickness of line3d lplt = self.render_wireframe_3d(**line_opts) if isinstance(polygon_opts, dict): if 'threejs_flat_shading' not in polygon_opts: @@ -1223,10 +1215,7 @@ def render_3d(self, point_opts=None, line_opts=None, polygon_opts=None): # zorder is not available return sum(_ for _ in [pplt, lplt, pgplt] if _ is not None) - def tikz(self, view=[0, 0, 1], angle=0, scale=1, - edge_color='blue!95!black', facet_color='blue!95!black', - opacity=0.8, vertex_color='green', axis=False, - output_type='TikzPicture'): + def tikz(self, view=[0, 0, 1], angle=0, scale=1, edge_color='blue!95!black', facet_color='blue!95!black', opacity=0.8, vertex_color='green', axis=False, output_type='TikzPicture'): r""" Return a tikz picture of ``self`` as a string or as a :class:`~sage.misc.latex_standalone.TikzPicture` @@ -1422,17 +1411,11 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, elif self.polyhedron_dim < 2 or self.polyhedron_dim > 3: raise NotImplementedError("The polytope has to be 2 or 3-dimensional.") elif self.polyhedron_ambient_dim == 2: # self is a polygon in 2-space - tikz_string = self._tikz_2d(scale, edge_color, - facet_color, opacity, - vertex_color, axis) + tikz_string = self._tikz_2d(scale, edge_color, facet_color, opacity, vertex_color, axis) elif self.polyhedron_dim == 2: # self is a polygon in 3-space - tikz_string = self._tikz_2d_in_3d(view, angle, scale, edge_color, - facet_color, opacity, - vertex_color, axis) + tikz_string = self._tikz_2d_in_3d(view, angle, scale, edge_color, facet_color, opacity, vertex_color, axis) else: # self is a 3-polytope in 3-space - tikz_string = self._tikz_3d_in_3d(view, angle, scale, edge_color, - facet_color, opacity, - vertex_color, axis) + tikz_string = self._tikz_3d_in_3d(view, angle, scale, edge_color, facet_color, opacity, vertex_color, axis) # return if output_type == 'LatexExpr': @@ -1440,12 +1423,10 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, if output_type == 'TikzPicture': from sage.misc.latex_standalone import TikzPicture - return TikzPicture(tikz_string, standalone_config=None, - usepackage=None, usetikzlibrary=None, - macros=None, use_sage_preamble=False) - raise ValueError("output_type (='{}') must be 'LatexExpr' or" - " 'TikzPicture'".format(output_type)) + return TikzPicture(tikz_string, standalone_config=None, usepackage=None, usetikzlibrary=None, macros=None, use_sage_preamble=False) + + raise ValueError("output_type (='{}') must be 'LatexExpr' or" " 'TikzPicture'".format(output_type)) def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): r""" @@ -1515,9 +1496,7 @@ def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): for index1, index2 in self.lines: # v1 = self.coords[index1] # v2 = self.coords[index2] - edges += "\\draw[%s] %s -- %s;\n" % ('edge', - dict_drawing[index1][2], - dict_drawing[index2][2]) + edges += "\\draw[%s] %s -- %s;\n" % ('edge', dict_drawing[index1][2], dict_drawing[index2][2]) # Start to write the output tikz_pic = '' @@ -1531,6 +1510,7 @@ def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): # Gives the reproduction information from sage.env import SAGE_VERSION + tikz_pic += "%% This TikZ-picture was produced with Sagemath version {}\n".format(SAGE_VERSION) tikz_pic += "%% with the command: ._tikz_2d and parameters:\n" tikz_pic += "%% scale = {}\n".format(scale) @@ -1574,8 +1554,7 @@ def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): return LatexExpr(tikz_pic) - def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, - opacity, vertex_color, axis): + def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, opacity, vertex_color, axis): r""" Return a string ``tikz_pic`` consisting of a tikz picture of ``self`` according to a projection ``view`` and an angle ``angle`` @@ -1637,7 +1616,7 @@ def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, from sage.rings.real_double import RDF view_vector = vector(RDF, view) - rot = rotate_arbitrary(view_vector, -(angle/360)*2*pi) + rot = rotate_arbitrary(view_vector, -(angle / 360) * 2 * pi) rotation_matrix = rot[:2].transpose() # Creates the nodes, coordinate and tag for every vertex of the polytope. @@ -1657,19 +1636,14 @@ def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, for index1, index2 in self.lines: # v1 = self.coords[index1] # v2 = self.coords[index2] - edges += "\\draw[%s] %s -- %s;\n" % ('edge', - dict_drawing[index1][2], - dict_drawing[index2][2]) + edges += "\\draw[%s] %s -- %s;\n" % ('edge', dict_drawing[index1][2], dict_drawing[index2][2]) # Start to write the output tikz_pic = '' tikz_pic += '\\begin{tikzpicture}%\n' - tikz_pic += '\t[x={(%fcm, %fcm)},\n' % (RDF(rotation_matrix[0][0]), - RDF(rotation_matrix[0][1])) - tikz_pic += '\ty={(%fcm, %fcm)},\n' % (RDF(rotation_matrix[1][0]), - RDF(rotation_matrix[1][1])) - tikz_pic += '\tz={(%fcm, %fcm)},\n' % (RDF(rotation_matrix[2][0]), - RDF(rotation_matrix[2][1])) + tikz_pic += '\t[x={(%fcm, %fcm)},\n' % (RDF(rotation_matrix[0][0]), RDF(rotation_matrix[0][1])) + tikz_pic += '\ty={(%fcm, %fcm)},\n' % (RDF(rotation_matrix[1][0]), RDF(rotation_matrix[1][1])) + tikz_pic += '\tz={(%fcm, %fcm)},\n' % (RDF(rotation_matrix[2][0]), RDF(rotation_matrix[2][1])) tikz_pic += '\tscale=%f,\n' % scale tikz_pic += '\tback/.style={loosely dotted, thin},\n' tikz_pic += '\tedge/.style={color=%s, thick},\n' % edge_color @@ -1679,6 +1653,7 @@ def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, # Gives the reproduction information from sage.env import SAGE_VERSION + tikz_pic += "%% This TikZ-picture was produced with Sagemath version {}\n".format(SAGE_VERSION) tikz_pic += "%% with the command: ._tikz_2d_in_3d and parameters:\n" tikz_pic += "%% view = {}\n".format(view) @@ -1725,8 +1700,7 @@ def _tikz_2d_in_3d(self, view, angle, scale, edge_color, facet_color, return LatexExpr(tikz_pic) - def _tikz_3d_in_3d(self, view, angle, scale, edge_color, - facet_color, opacity, vertex_color, axis): + def _tikz_3d_in_3d(self, view, angle, scale, edge_color, facet_color, opacity, vertex_color, axis): r""" Return a string ``tikz_pic`` consisting of a tikz picture of ``self`` according to a projection ``view`` and an angle ``angle`` @@ -1796,9 +1770,9 @@ def _tikz_3d_in_3d(self, view, angle, scale, edge_color, from sage.rings.real_double import RDF view_vector = vector(RDF, view) - rot = rotate_arbitrary(view_vector, -(angle/360)*2*pi) + rot = rotate_arbitrary(view_vector, -(angle / 360) * 2 * pi) rotation_matrix = rot[:2].transpose() - proj_vector = (rot**(-1))*vector(RDF, [0, 0, 1]) + proj_vector = (rot ** (-1)) * vector(RDF, [0, 0, 1]) # First compute the back and front vertices and facets front_facets, back_facets, front_vertices, back_vertices = self._front_back_facets(proj_vector) @@ -1832,23 +1806,16 @@ def _tikz_3d_in_3d(self, view, angle, scale, edge_color, # The back edge has to be between two vertices in the Back # AND such that the 2 facets touching them are in the Back if index1 in back_vertices and index2 in back_vertices and len(H_v12) == 2: - back_part += "\\draw[%s,back] %s -- %s;\n" % ('edge', - dict_drawing[index1][2], - dict_drawing[index2][2]) + back_part += "\\draw[%s,back] %s -- %s;\n" % ('edge', dict_drawing[index1][2], dict_drawing[index2][2]) else: - front_part += "\\draw[%s] %s -- %s;\n" % ('edge', - dict_drawing[index1][2], - dict_drawing[index2][2]) + front_part += "\\draw[%s] %s -- %s;\n" % ('edge', dict_drawing[index1][2], dict_drawing[index2][2]) # Start to write the output tikz_pic = '' tikz_pic += '\\begin{tikzpicture}%\n' - tikz_pic += '\t[x={(%fcm, %fcm)},\n' % (RDF(rotation_matrix[0][0]), - RDF(rotation_matrix[0][1])) - tikz_pic += '\ty={(%fcm, %fcm)},\n' % (RDF(rotation_matrix[1][0]), - RDF(rotation_matrix[1][1])) - tikz_pic += '\tz={(%fcm, %fcm)},\n' % (RDF(rotation_matrix[2][0]), - RDF(rotation_matrix[2][1])) + tikz_pic += '\t[x={(%fcm, %fcm)},\n' % (RDF(rotation_matrix[0][0]), RDF(rotation_matrix[0][1])) + tikz_pic += '\ty={(%fcm, %fcm)},\n' % (RDF(rotation_matrix[1][0]), RDF(rotation_matrix[1][1])) + tikz_pic += '\tz={(%fcm, %fcm)},\n' % (RDF(rotation_matrix[2][0]), RDF(rotation_matrix[2][1])) tikz_pic += '\tscale=%f,\n' % scale tikz_pic += '\tback/.style={loosely dotted, thin},\n' tikz_pic += '\tedge/.style={color=%s, thick},\n' % edge_color @@ -1858,6 +1825,7 @@ def _tikz_3d_in_3d(self, view, angle, scale, edge_color, # Gives the reproduction information from sage.env import SAGE_VERSION + tikz_pic += "%% This TikZ-picture was produced with Sagemath version {}\n".format(SAGE_VERSION) tikz_pic += "%% with the command: ._tikz_3d_in_3d and parameters:\n" tikz_pic += "%% view = {}\n".format(view) @@ -1942,7 +1910,7 @@ def _front_back_facets(self, projection_vector): facet_ineqs = self.face_inequalities front_facets = [] back_facets = [] - for index_facet,f in enumerate(facet_ineqs): + for index_facet, f in enumerate(facet_ineqs): A = f.A() if A * projection_vector < 0: front_facets.append(index_facet) diff --git a/src/sage/geometry/polyhedron/ppl_lattice_polygon.py b/src/sage/geometry/polyhedron/ppl_lattice_polygon.py index dc100230745..59d904c3b0b 100644 --- a/src/sage/geometry/polyhedron/ppl_lattice_polygon.py +++ b/src/sage/geometry/polyhedron/ppl_lattice_polygon.py @@ -21,12 +21,10 @@ from sage.rings.integer_ring import ZZ from sage.misc.cachefunc import cached_method, cached_function from sage.modules.free_module_element import vector, zero_vector -from sage.matrix.constructor import (matrix, zero_matrix, block_matrix) +from sage.matrix.constructor import matrix, zero_matrix, block_matrix from ppl import C_Polyhedron, Poly_Con_Relation -from sage.geometry.polyhedron.lattice_euclidean_group_element import ( - LatticeEuclideanGroupElement) -from sage.geometry.polyhedron.ppl_lattice_polytope import ( - LatticePolytope_PPL, LatticePolytope_PPL_class) +from sage.geometry.polyhedron.lattice_euclidean_group_element import LatticeEuclideanGroupElement +from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL, LatticePolytope_PPL_class ######################################################################## @@ -137,8 +135,8 @@ def _find_isomorphism_degenerate(self, polytope): ... LatticePolytopesNotIsomorphicError: different number of integral points """ - from sage.geometry.polyhedron.lattice_euclidean_group_element import \ - LatticePolytopesNotIsomorphicError + from sage.geometry.polyhedron.lattice_euclidean_group_element import LatticePolytopesNotIsomorphicError + polytope_vertices = polytope.vertices() self_vertices = self.ordered_vertices() # handle degenerate cases @@ -162,7 +160,7 @@ def _find_isomorphism_degenerate(self, polytope): A = zero_matrix(ZZ, Dp.nrows(), Ds.nrows()) A[0, 0] = 1 A = Up.inverse() * A * Us * (Vs[0, 0] * Vp[0, 0]) - b = polytope_origin - A*self_origin + b = polytope_origin - A * self_origin try: A = matrix(ZZ, A) b = vector(ZZ, b) @@ -173,9 +171,7 @@ def _find_isomorphism_degenerate(self, polytope): return hom raise LatticePolytopesNotIsomorphicError('different polygons') - def _find_cyclic_isomorphism_matching_edge(self, polytope, - polytope_origin, p_ray_left, - p_ray_right): + def _find_cyclic_isomorphism_matching_edge(self, polytope, polytope_origin, p_ray_left, p_ray_right): r""" Helper to find an isomorphism of polygons. @@ -213,22 +209,20 @@ def _find_cyclic_isomorphism_matching_edge(self, polytope, b = (0, 1, 0) """ - from sage.geometry.polyhedron.lattice_euclidean_group_element import \ - LatticePolytopesNotIsomorphicError - polytope_matrix = block_matrix(1, 2, [p_ray_left.column(), - p_ray_right.column()]) + from sage.geometry.polyhedron.lattice_euclidean_group_element import LatticePolytopesNotIsomorphicError + + polytope_matrix = block_matrix(1, 2, [p_ray_left.column(), p_ray_right.column()]) self_vertices = self.ordered_vertices() for i in range(len(self_vertices)): # three consecutive vertices - v_left = self_vertices[(i+0) % len(self_vertices)] - v_origin = self_vertices[(i+1) % len(self_vertices)] - v_right = self_vertices[(i+2) % len(self_vertices)] - r_left = v_left-v_origin - r_right = v_right-v_origin - self_matrix = block_matrix(1, 2, [r_left.column(), - r_right.column()]) + v_left = self_vertices[(i + 0) % len(self_vertices)] + v_origin = self_vertices[(i + 1) % len(self_vertices)] + v_right = self_vertices[(i + 2) % len(self_vertices)] + r_left = v_left - v_origin + r_right = v_right - v_origin + self_matrix = block_matrix(1, 2, [r_left.column(), r_right.column()]) A = self_matrix.solve_left(polytope_matrix) - b = polytope_origin - A*v_origin + b = polytope_origin - A * v_origin try: A = matrix(ZZ, A) b = vector(ZZ, b) @@ -287,8 +281,8 @@ def find_isomorphism(self, polytope): ... LatticePolytopesNotIsomorphicError: different number of integral points """ - from sage.geometry.polyhedron.lattice_euclidean_group_element import \ - LatticePolytopesNotIsomorphicError + from sage.geometry.polyhedron.lattice_euclidean_group_element import LatticePolytopesNotIsomorphicError + if polytope.affine_dimension() != self.affine_dimension(): raise LatticePolytopesNotIsomorphicError('different dimension') polytope_vertices = polytope.vertices() @@ -320,13 +314,11 @@ def find_isomorphism(self, polytope): p_ray_left = neighbors[0] - polytope_origin p_ray_right = neighbors[1] - polytope_origin try: - return self._find_cyclic_isomorphism_matching_edge(polytope, polytope_origin, - p_ray_left, p_ray_right) + return self._find_cyclic_isomorphism_matching_edge(polytope, polytope_origin, p_ray_left, p_ray_right) except LatticePolytopesNotIsomorphicError: pass try: - return self._find_cyclic_isomorphism_matching_edge(polytope, polytope_origin, - p_ray_right, p_ray_left) + return self._find_cyclic_isomorphism_matching_edge(polytope, polytope_origin, p_ray_right, p_ray_left) except LatticePolytopesNotIsomorphicError: pass raise LatticePolytopesNotIsomorphicError('different polygons') @@ -349,8 +341,8 @@ def is_isomorphic(self, polytope): sage: L1.is_isomorphic(L2) True """ - from sage.geometry.polyhedron.lattice_euclidean_group_element import \ - LatticePolytopesNotIsomorphicError + from sage.geometry.polyhedron.lattice_euclidean_group_element import LatticePolytopesNotIsomorphicError + try: self.find_isomorphism(polytope) return True @@ -412,15 +404,14 @@ def plot(self): """ from sage.plot.point import point2d from sage.plot.polygon import polygon2d + vertices = self.ordered_vertices() points = self.integral_points() if self.space_dimension() == 1: vertices = [vector(ZZ, (v[0], 0)) for v in vertices] points = [vector(ZZ, (p[0], 0)) for p in points] - point_plot = sum(point2d(p, pointsize=100, color='red') - for p in points) - polygon_plot = polygon2d(vertices, alpha=0.2, color='green', - zorder=-1, thickness=2) + point_plot = sum(point2d(p, pointsize=100, color='red') for p in points) + polygon_plot = polygon2d(vertices, alpha=0.2, color='green', zorder=-1, thickness=2) return polygon_plot + point_plot @@ -430,6 +421,7 @@ def plot(self): # ######################################################################## + @cached_function def polar_P2_polytope(): """ @@ -550,6 +542,7 @@ def sub_reflexive_polygons(): def add_result(subpolygon, ambient): if not any(subpolygon.is_isomorphic(p[0]) for p in result): result.append((subpolygon, ambient)) + for p in subpolygons_of_polar_P2(): add_result(p, polar_P2_polytope()) for p in subpolygons_of_polar_P2_112(): diff --git a/src/sage/geometry/polyhedron/ppl_lattice_polytope.py b/src/sage/geometry/polyhedron/ppl_lattice_polytope.py index 8f044dd957a..73ba00189c1 100644 --- a/src/sage/geometry/polyhedron/ppl_lattice_polytope.py +++ b/src/sage/geometry/polyhedron/ppl_lattice_polytope.py @@ -71,10 +71,7 @@ from sage.misc.cachefunc import cached_method from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix -from ppl import ( - C_Polyhedron, Linear_Expression, Variable, - point, line, Generator, Generator_System, - Poly_Con_Relation ) +from ppl import C_Polyhedron, Linear_Expression, Variable, point, line, Generator, Generator_System, Poly_Con_Relation ######################################################################## @@ -101,6 +98,7 @@ def _class_for_LatticePolytope(dim): """ if dim <= 2: from sage.geometry.polyhedron.ppl_lattice_polygon import LatticePolygon_PPL_class + return LatticePolygon_PPL_class return LatticePolytope_PPL_class @@ -157,9 +155,7 @@ def LatticePolytope_PPL(*args): if not all(p.is_point() and p.divisor() == 1 for p in polyhedron.generators()): raise TypeError('polyhedron has non-integral generators') return polytope_class(polyhedron) - if len(args) == 1 \ - and isinstance(args[0], (list, tuple)) \ - and isinstance(args[0][0], (list,tuple)): + if len(args) == 1 and isinstance(args[0], (list, tuple)) and isinstance(args[0][0], (list, tuple)): vertices = args[0] else: vertices = args @@ -323,6 +319,7 @@ def n_integral_points(self): return tuple() box_min, box_max = self.bounding_box() from sage.geometry.integral_points import rectangular_box_points + return rectangular_box_points(list(box_min), list(box_max), self, count_only=True) @cached_method @@ -394,6 +391,7 @@ def integral_points(self): return tuple() box_min, box_max = self.bounding_box() from sage.geometry.integral_points import rectangular_box_points + points = rectangular_box_points(list(box_min), list(box_max), self) if not self.n_integral_points.is_in_cache(): self.n_integral_points.set_cache(len(points)) @@ -430,8 +428,8 @@ def _integral_points_saturating(self): return tuple() box_min, box_max = self.bounding_box() from sage.geometry.integral_points import rectangular_box_points - points = rectangular_box_points(list(box_min), list(box_max), self, - return_saturated=True) + + points = rectangular_box_points(list(box_min), list(box_max), self, return_saturated=True) if not self.n_integral_points.is_in_cache(): self.n_integral_points.set_cache(len(points)) if not self.integral_points.is_in_cache(): @@ -517,8 +515,9 @@ def vertices_saturating(self, constraint): ((0, 0), (0, 1)) """ from ppl import C_Polyhedron, Poly_Con_Relation + result = [] - for i,v in enumerate(self.minimized_generators()): + for i, v in enumerate(self.minimized_generators()): v = C_Polyhedron(v) if v.relation_with(constraint).implies(Poly_Con_Relation.saturates()): result.append(self.vertices()[i]) @@ -576,7 +575,7 @@ def fibration_generator(self, dim): # in the $codim$-skeleton of the polytope, which is contained # in the points that saturate at least $dim$ equations. points = [p for p in self._integral_points_saturating() if len(p[1]) >= dim] - points = sorted(points, key=lambda x:len(x[1])) + points = sorted(points, key=lambda x: len(x[1])) # iterate over point combinations subject to all points being on one facet. def point_combinations_iterator(n, i0=0, saturated=None): @@ -591,10 +590,10 @@ def point_combinations_iterator(n, i0=0, saturated=None): if n == 1: yield [i] else: - for c in point_combinations_iterator(n-1, i+1, saturated_ieqs): + for c in point_combinations_iterator(n - 1, i + 1, saturated_ieqs): yield [i] + c - point_lines = [ line(Linear_Expression(p[0].list(),0)) for p in points ] + point_lines = [line(Linear_Expression(p[0].list(), 0)) for p in points] origin = point() fibers = set() gs = Generator_System() @@ -611,7 +610,7 @@ def point_combinations_iterator(n, i0=0, saturated=None): continue try: fiber = LatticePolytope_PPL(plane) - except TypeError: # not a lattice polytope + except TypeError: # not a lattice polytope continue fiber_vertices = tuple(sorted(fiber.vertices())) if fiber_vertices not in fibers: @@ -659,11 +658,9 @@ def pointsets_mod_automorphism(self, pointsets): for ps in pointsets: points.update(ps) points = tuple(sorted(points)) - Aut = self.lattice_automorphism_group(points, - point_labels=tuple(range(len(points)))) + Aut = self.lattice_automorphism_group(points, point_labels=tuple(range(len(points)))) point_to_index = {p: i for i, p in enumerate(points)} - indexsets = set(frozenset(point_to_index[p] for p in ps) - for ps in pointsets) + indexsets = set(frozenset(point_to_index[p] for p in ps) for ps in pointsets) orbits = [] while indexsets: idx = indexsets.pop() @@ -694,6 +691,7 @@ def ambient_space(self): Ambient free module of rank 3 over the principal ideal domain Integer Ring """ from sage.modules.free_module import FreeModule + return FreeModule(ZZ, self.space_dimension()) def contains(self, point_coordinates): @@ -764,7 +762,7 @@ def affine_space(self): vertices = self.vertices() if not self.contains_origin(): v0 = vertices[0] - vertices = [v-v0 for v in vertices] + vertices = [v - v0 for v in vertices] return self.ambient_space().span(vertices).saturation() def affine_lattice_polytope(self): @@ -790,10 +788,10 @@ def affine_lattice_polytope(self): """ V = self.affine_space() if self.contains_origin(): - vertices = [ V.coordinates(v) for v in self.vertices() ] + vertices = [V.coordinates(v) for v in self.vertices()] else: v0 = vertices[0] - vertices = [ V.coordinates(v-v0) for v in self.vertices() ] + vertices = [V.coordinates(v - v0) for v in self.vertices()] return LatticePolytope_PPL(*vertices) def base_projection(self, fiber): @@ -916,7 +914,7 @@ def has_IP_property(self) -> bool: sage: LatticePolytope_PPL((-1,-1), (1,1)).has_IP_property() False """ - origin = C_Polyhedron(point(0*Variable(self.space_dimension()))) + origin = C_Polyhedron(point(0 * Variable(self.space_dimension()))) is_included = Poly_Con_Relation.is_included() saturates = Poly_Con_Relation.saturates() for c in self.constraints(): @@ -983,11 +981,11 @@ def restricted_automorphism_group(self, vertex_labels=None): 1152 """ if not self.is_full_dimensional(): - return self.affine_lattice_polytope().\ - restricted_automorphism_group(vertex_labels=vertex_labels) + return self.affine_lattice_polytope().restricted_automorphism_group(vertex_labels=vertex_labels) if vertex_labels is None: vertex_labels = self.vertices() from sage.graphs.graph import Graph + # good coordinates for the vertices v_list = [] for v in self.minimized_generators(): @@ -996,10 +994,10 @@ def restricted_automorphism_group(self, vertex_labels=None): v_list.append(vector(v_coords)) # Finally, construct the graph - Qinv = sum( v.column() * v.row() for v in v_list ).inverse() + Qinv = sum(v.column() * v.row() for v in v_list).inverse() G = Graph() for i in range(len(v_list)): - for j in range(i+1,len(v_list)): + for j in range(i + 1, len(v_list)): v_i = v_list[i] v_j = v_list[j] G.add_edge(vertex_labels[i], vertex_labels[j], v_i * Qinv * v_j) @@ -1063,34 +1061,32 @@ def lattice_automorphism_group(self, points=None, point_labels=None): Permutation Group with generators [(), (1,2), (0,1), (0,1,2), (0,2,1), (0,2)] """ if not self.is_full_dimensional(): - return self.affine_lattice_polytope().lattice_automorphism_group( - point_labels=point_labels) + return self.affine_lattice_polytope().lattice_automorphism_group(point_labels=point_labels) if points is None: points = self.vertices() if point_labels is None: point_labels = tuple(points) - points = [ vector(ZZ, [1]+v.list()) for v in points ] + points = [vector(ZZ, [1] + v.list()) for v in points] for p in points: p.set_immutable() - vertices = [ vector(ZZ, [1]+v.list()) for v in self.vertices() ] + vertices = [vector(ZZ, [1] + v.list()) for v in self.vertices()] pivots = matrix(ZZ, vertices).pivot_rows() - basis = matrix(ZZ, [ vertices[i] for i in pivots ]) + basis = matrix(ZZ, [vertices[i] for i in pivots]) Mat_ZZ = basis.parent() basis_inverse = basis.inverse() from sage.groups.perm_gps.permgroup import PermutationGroup + lattice_gens = [] - G = self.restricted_automorphism_group( - vertex_labels=tuple(range(len(vertices)))) + G = self.restricted_automorphism_group(vertex_labels=tuple(range(len(vertices)))) for g in G: - image = matrix(ZZ, [ vertices[g(i)] for i in pivots ]) - m = basis_inverse*image + image = matrix(ZZ, [vertices[g(i)] for i in pivots]) + m = basis_inverse * image if m not in Mat_ZZ: continue - perm_list = [ point_labels[points.index(p*m)] - for p in points ] + perm_list = [point_labels[points.index(p * m)] for p in points] lattice_gens.append(perm_list) return PermutationGroup(lattice_gens, domain=point_labels) @@ -1154,8 +1150,8 @@ def _find_isomorphism_to_subreflexive_polytope(self): ((0, 1), (3, 0), (0, 3), (1, 0)) """ from .ppl_lattice_polygon import sub_reflexive_polygons - from sage.geometry.polyhedron.lattice_euclidean_group_element import \ - LatticePolytopesNotIsomorphicError, LatticePolytopeNoEmbeddingError + from sage.geometry.polyhedron.lattice_euclidean_group_element import LatticePolytopesNotIsomorphicError, LatticePolytopeNoEmbeddingError + for p, ambient in sub_reflexive_polygons(): try: return (ambient, p, p.find_isomorphism(self)) @@ -1244,6 +1240,6 @@ def embed_in_reflexive_polytope(self, output='hom'): if output == 'points': points = dict() for p in subreflexive.integral_points(): - points[ tuple(hom(p)) ] = p + points[tuple(hom(p))] = p return points - raise ValueError('output='+str(output)+' is not valid.') + raise ValueError('output=' + str(output) + ' is not valid.') diff --git a/src/sage/geometry/polyhedron/representation.py b/src/sage/geometry/polyhedron/representation.py index 8121ac9799d..1533fec8ce6 100644 --- a/src/sage/geometry/polyhedron/representation.py +++ b/src/sage/geometry/polyhedron/representation.py @@ -158,8 +158,7 @@ def __richcmp__(self, other, op): """ if not isinstance(other, PolyhedronRepresentation): return NotImplemented - return richcmp((self.type(), self._vector*self._comparison_scalar()), - (other.type(), other._vector*other._comparison_scalar()), op) + return richcmp((self.type(), self._vector * self._comparison_scalar()), (other.type(), other._vector * other._comparison_scalar()), op) def _comparison_scalar(self): r""" @@ -206,8 +205,8 @@ def _comparison_scalar(self): lcf = self._vector.leading_coefficient() if self.type() == self.EQUATION or self.type() == self.LINE: - return 1/lcf - return 1/lcf.abs() + return 1 / lcf + return 1 / lcf.abs() def vector(self, base_ring=None): """ @@ -555,7 +554,7 @@ def neighbors(self): adjacency_matrix = self.polyhedron().facet_adjacency_matrix() for x in self.polyhedron().Hrep_generator(): if not x.is_equation(): - if adjacency_matrix[self.index()-n_eqs, x.index()-n_eqs] == 1: + if adjacency_matrix[self.index() - n_eqs, x.index() - n_eqs] == 1: yield x def adjacent(self): @@ -829,6 +828,7 @@ def is_facet_defining_inequality(self, other): ....: assert ieq.is_facet_defining_inequality(p1) """ from sage.geometry.polyhedron.base import Polyhedron_base + if not isinstance(other, Polyhedron_base): raise ValueError("other must be a polyhedron") @@ -839,6 +839,7 @@ def is_facet_defining_inequality(self, other): # We evaluate ``self`` on the Vrepresentation of other. from sage.matrix.constructor import matrix + Vrep_matrix = matrix(other.base_ring(), other.Vrepresentation()) # Getting homogeneous coordinates of the Vrepresentation. @@ -925,13 +926,13 @@ def contains(self, Vobj): """ try: if Vobj.is_vector(): # assume we were passed a point - return self.polyhedron()._is_nonneg( self.eval(Vobj) ) + return self.polyhedron()._is_nonneg(self.eval(Vobj)) except AttributeError: pass if Vobj.is_line(): - return self.polyhedron()._is_zero( self.eval(Vobj) ) - return self.polyhedron()._is_nonneg( self.eval(Vobj) ) + return self.polyhedron()._is_zero(self.eval(Vobj)) + return self.polyhedron()._is_nonneg(self.eval(Vobj)) def interior_contains(self, Vobj): """ @@ -957,17 +958,17 @@ def interior_contains(self, Vobj): [True, True, False, True] """ try: - if Vobj.is_vector(): # assume we were passed a point - return self.polyhedron()._is_positive( self.eval(Vobj) ) + if Vobj.is_vector(): # assume we were passed a point + return self.polyhedron()._is_positive(self.eval(Vobj)) except AttributeError: pass if Vobj.is_line(): - return self.polyhedron()._is_zero( self.eval(Vobj) ) + return self.polyhedron()._is_zero(self.eval(Vobj)) if Vobj.is_vertex(): - return self.polyhedron()._is_positive( self.eval(Vobj) ) + return self.polyhedron()._is_positive(self.eval(Vobj)) # Vobj.is_ray() - return self.polyhedron()._is_nonneg( self.eval(Vobj) ) + return self.polyhedron()._is_nonneg(self.eval(Vobj)) def outer_normal(self): r""" @@ -1078,7 +1079,7 @@ def contains(self, Vobj): sage: a.contains(v) True """ - return self.polyhedron()._is_zero( self.eval(Vobj) ) + return self.polyhedron()._is_zero(self.eval(Vobj)) def interior_contains(self, Vobj): """ @@ -1636,8 +1637,7 @@ def evaluated_on(self, Hobj): return Hobj.A() * self.vector() -def repr_pretty(coefficients, type, prefix='x', indices=None, - latex=False, style='>=', split=False): +def repr_pretty(coefficients, type, prefix='x', indices=None, latex=False, style='>=', split=False): r""" Return a pretty representation of equation/inequality represented by the coefficients. @@ -1679,7 +1679,7 @@ def repr_pretty(coefficients, type, prefix='x', indices=None, coeffs = list(coefficients) if indices is None: - indices = range(len(coeffs)-1) + indices = range(len(coeffs) - 1) vars = [1] if latex: vars += [f'{prefix}_{{{i}}}' for i in indices] @@ -1693,8 +1693,7 @@ def repr_pretty(coefficients, type, prefix='x', indices=None, else: rel = r'\geq' if latex else '>=' else: - raise NotImplementedError( - 'no pretty printing available: wrong type {}'.format(type)) + raise NotImplementedError('no pretty printing available: wrong type {}'.format(type)) rvars = range(len(vars)) diff --git a/src/sage/geometry/pseudolines.py b/src/sage/geometry/pseudolines.py index 6b26c6eef43..2eec4c65b30 100644 --- a/src/sage/geometry/pseudolines.py +++ b/src/sage/geometry/pseudolines.py @@ -158,6 +158,7 @@ Methods ------- """ + ############################################################################## # Copyright (C) 2011 Nathann Cohen # Distributed under the terms of the GNU General Public License (GPL) @@ -234,36 +235,29 @@ def __init__(self, seq, encoding='auto'): """ # Sequence of transpositions - if (encoding == "transpositions" or - (encoding == "auto" and len(seq[0]) == 2 and len(seq) > 3)): + if encoding == "transpositions" or (encoding == "auto" and len(seq[0]) == 2 and len(seq) > 3): self._n = max(map(max, seq)) + 1 - if (self._n * (self._n-1))/2 != len(seq): - raise ValueError( - "A line is numbered "+str(self._n-1)+" but the number" + - " of transpositions is different from binomial(" + - str(self._n-1)+",2). Are the lines numbered from 0 to n-1?" + - " Are they really non-parallel? Please check the documentation.") + if (self._n * (self._n - 1)) / 2 != len(seq): + raise ValueError("A line is numbered " + str(self._n - 1) + " but the number" + " of transpositions is different from binomial(" + str(self._n - 1) + ",2). Are the lines numbered from 0 to n-1?" + " Are they really non-parallel? Please check the documentation.") self._permutations = [[] for i in range(self._n)] - for i,j in seq: + for i, j in seq: self._permutations[i].append(j) self._permutations[j].append(i) # Sequence of permutations - elif (encoding == "permutations" or - (encoding == "auto" and (len(seq[0]) == len(seq)-1) and max(seq[0]) > 1)): + elif encoding == "permutations" or (encoding == "auto" and (len(seq[0]) == len(seq) - 1) and max(seq[0]) > 1): self._n = len(seq) self._permutations = [list(_) for _ in seq] - if max(map(max, seq)) != self._n - 1 : + if max(map(max, seq)) != self._n - 1: raise ValueError("Are the lines really numbered from 0 to n-1?") # Felsner encoding - elif (encoding == "Felsner" or - (encoding == "auto" and len(seq[0]) == len(seq) - 1)): + elif encoding == "Felsner" or (encoding == "auto" and len(seq[0]) == len(seq) - 1): seq = deepcopy(seq) self._n = len(seq) @@ -271,24 +265,22 @@ def __init__(self, seq, encoding='auto'): self._permutations = [[] for i in range(self._n)] - crossings = (self._n * (self._n-1))/2 + crossings = (self._n * (self._n - 1)) / 2 i = 0 while crossings > 0: - if (seq[i] and - (seq[i][0] == 0 and - seq[i+1][0] == 1)): + if seq[i] and (seq[i][0] == 0 and seq[i + 1][0] == 1): crossings -= 1 - self._permutations[ordering[i]].append(ordering[i+1]) - self._permutations[ordering[i+1]].append(ordering[i]) + self._permutations[ordering[i]].append(ordering[i + 1]) + self._permutations[ordering[i + 1]].append(ordering[i]) - ordering[i], ordering[i+1] = ordering[i+1], ordering[i] - seq[i], seq[i+1] = seq[i+1], seq[i] + ordering[i], ordering[i + 1] = ordering[i + 1], ordering[i] + seq[i], seq[i + 1] = seq[i + 1], seq[i] seq[i].pop(0) - seq[i+1].pop(0) + seq[i + 1].pop(0) if i > 0 and seq[i - 1]: i -= 1 @@ -327,7 +319,7 @@ def transpositions(self): t = [] perm = deepcopy(self._permutations) - crossings = (self._n * (self._n-1))/2 + crossings = (self._n * (self._n - 1)) / 2 while crossings > 0: @@ -342,12 +334,7 @@ def transpositions(self): k += 1 if k > self._n: - raise ValueError( - "It looks like the data does not correspond to a" + - "pseudoline arrangement. We have found k>2 lines" + - "such that the ith line meets the (i+1)th before" + - " the (i-1)th (this creates a cyclic dependency)" + - " which is totally impossible.") + raise ValueError("It looks like the data does not correspond to a" + "pseudoline arrangement. We have found k>2 lines" + "such that the ith line meets the (i+1)th before" + " the (i-1)th (this creates a cyclic dependency)" + " which is totally impossible.") t.append((i, perm[i][0])) perm[perm[i][0]].pop(0) @@ -395,7 +382,7 @@ def felsner_matrix(self): m = [[] for i in range(self._n)] - for i,j in self.transpositions(): + for i, j in self.transpositions(): if i < j: i, j = j, i @@ -435,35 +422,31 @@ def show(self, **args): from sage.plot.line import line from sage.plot.text import text - lines = [[(0,self._n-1-i)] for i in range(self._n)] + lines = [[(0, self._n - 1 - i)] for i in range(self._n)] - for i,j in self.transpositions(): + for i, j in self.transpositions(): iy = lines[i][-1][1] jy = lines[j][-1][1] lines[i].append((x, iy)) lines[j].append((x, jy)) - if abs(iy-jy) != 1: - raise ValueError( - "There has been a problem while plotting the figure. It " + - "seems that the lines are not correctly ordered. Please " + - "check the pseudolines modules documentation, there is a " - + "warning about that. ") + if abs(iy - jy) != 1: + raise ValueError("There has been a problem while plotting the figure. It " + "seems that the lines are not correctly ordered. Please " + "check the pseudolines modules documentation, there is a " + "warning about that. ") - lines[i].append((x+2,jy)) - lines[j].append((x+2,iy)) + lines[i].append((x + 2, jy)) + lines[j].append((x + 2, iy)) x += 2 - L = line([(1,1)]) + L = line([(1, 1)]) for i, l in enumerate(lines): - l.append((x+2, l[-1][1])) + l.append((x + 2, l[-1][1])) L += line(l) - L += text(str(i), (0, l[0][1]+.3), horizontal_alignment='right') - L += text(str(i), (x+2, l[-1][1]+.3), horizontal_alignment='left') + L += text(str(i), (0, l[0][1] + 0.3), horizontal_alignment='right') + L += text(str(i), (x + 2, l[-1][1] + 0.3), horizontal_alignment='left') return L.show(axes=False, **args) diff --git a/src/sage/geometry/ribbon_graph.py b/src/sage/geometry/ribbon_graph.py index 5c2950519ad..b6de65ccd17 100644 --- a/src/sage/geometry/ribbon_graph.py +++ b/src/sage/geometry/ribbon_graph.py @@ -30,7 +30,7 @@ from sage.misc.flatten import flatten from copy import deepcopy -#Auxiliary functions that will be used in the classes. +# Auxiliary functions that will be used in the classes. def _find(l, k): @@ -276,6 +276,7 @@ class RibbonGraph(SageObject, UniqueRepresentation): sage: B23.rho() (1,8)(2,10)(3,12)(4,7)(5,9)(6,11) """ + @staticmethod def __classcall_private__(cls, sigma, rho, bipartite=False): """ @@ -454,43 +455,38 @@ def contract_edge(self, k): (1,2,3)(4,5,6)(7,8,9)(10,11,12)(13,14,15)(16,17,18) (1,16)(2,13)(3,10)(4,17)(5,14)(6,11)(7,18)(8,15)(9,12) """ - #the following two lines convert the list of tuples to list of lists + # the following two lines convert the list of tuples to list of lists aux_sigma = [list(x) for x in self._sigma.cycle_tuples(singletons=True)] aux_rho = [list(x) for x in self._rho.cycle_tuples()] - #The following ''if'' rules out the cases when we would be - #contracting a loop (which is not admissible since we would - #lose the topological type of the graph). - if (_find(aux_sigma, aux_rho[k][0])[0] == - _find(aux_sigma, aux_rho[k][1])[0]): + # The following ''if'' rules out the cases when we would be + # contracting a loop (which is not admissible since we would + # lose the topological type of the graph). + if _find(aux_sigma, aux_rho[k][0])[0] == _find(aux_sigma, aux_rho[k][1])[0]: raise ValueError("the edge is a loop and cannot be contracted") - #We store in auxiliary variables the positions of the vertices - #that are the ends of the edge to be contracted and we delete - #from them the darts corresponding to the edge that is going - #to be contracted. We also delete the contracted edge - #from aux_rho + # We store in auxiliary variables the positions of the vertices + # that are the ends of the edge to be contracted and we delete + # from them the darts corresponding to the edge that is going + # to be contracted. We also delete the contracted edge + # from aux_rho pos1 = _find(aux_sigma, aux_rho[k][0]) pos2 = _find(aux_sigma, aux_rho[k][1]) del aux_sigma[pos1[0]][pos1[1]] del aux_sigma[pos2[0]][pos2[1]] del aux_rho[k] - #Now we insert in one of the two vertices, the darts of the other - #vertex that appears after. We make sure that we don't - #change the topological type of the thickening of the graph by - #preserving the cyclic ordering. + # Now we insert in one of the two vertices, the darts of the other + # vertex that appears after. We make sure that we don't + # change the topological type of the thickening of the graph by + # preserving the cyclic ordering. n = len(aux_sigma[pos2[0]]) for i in range(n): - aux_sigma[pos1[0]].insert( - pos1[1] + i, - aux_sigma[pos2[0]][(pos2[1]+i) % n] - ) - #Finally we delete the vertex from which we copied all the darts. + aux_sigma[pos1[0]].insert(pos1[1] + i, aux_sigma[pos2[0]][(pos2[1] + i) % n]) + # Finally we delete the vertex from which we copied all the darts. del aux_sigma[pos2[0]] - #Now we convert this data that is on the form of lists of lists - #to actual permutations that form a ribbon graph. - return RibbonGraph(PermutationConstructor([tuple(x) for x in aux_sigma]), - PermutationConstructor([tuple(x) for x in aux_rho])) + # Now we convert this data that is on the form of lists of lists + # to actual permutations that form a ribbon graph. + return RibbonGraph(PermutationConstructor([tuple(x) for x in aux_sigma]), PermutationConstructor([tuple(x) for x in aux_rho])) def extrude_edge(self, vertex, dart1, dart2): r""" @@ -570,7 +566,7 @@ def extrude_edge(self, vertex, dart1, dart2): sage: F1.rho() (1,2)(3,4)(5,6)(7,8)(9,10) """ - #We first compute the vertices of valency 1 as in _repr_ + # We first compute the vertices of valency 1 as in _repr_ repr_sigma = [list(x) for x in self._sigma.cycle_tuples()] repr_rho = [list(x) for x in self._rho.cycle_tuples()] darts_rho = flatten(repr_rho) @@ -585,19 +581,18 @@ def extrude_edge(self, vertex, dart1, dart2): # We create the new vertex and append it to sigma. new_vertex = [repr_sigma[vertex][j] for j in range(dart1, dart2)] - new_vertex.insert(0, k+1) + new_vertex.insert(0, k + 1) repr_sigma.append(new_vertex) # We add the new dart at the vertex from which we are extruding # an edge. Also we delete the darts that have been extruded. - repr_sigma[vertex].insert(dart1,k+2) - del repr_sigma[vertex][dart1+1:dart2+1] + repr_sigma[vertex].insert(dart1, k + 2) + del repr_sigma[vertex][dart1 + 1 : dart2 + 1] - #We update rho - repr_rho.append([k+1, k+2]) + # We update rho + repr_rho.append([k + 1, k + 2]) - return RibbonGraph(PermutationConstructor([tuple(x) for x in repr_sigma]), - PermutationConstructor([tuple(x) for x in repr_rho])) + return RibbonGraph(PermutationConstructor([tuple(x) for x in repr_sigma]), PermutationConstructor([tuple(x) for x in repr_rho])) @cached_method def genus(self): @@ -622,23 +617,23 @@ def genus(self): sage: R3 = RibbonGraph(s3,r3); R3.genus() 3 """ - #We now use the same procedure as in _repr_ to get the vertices - #of valency 1 and distinguish them from the extra singletons of - #the permutation sigma. + # We now use the same procedure as in _repr_ to get the vertices + # of valency 1 and distinguish them from the extra singletons of + # the permutation sigma. repr_sigma = [list(x) for x in self._sigma.cycle_tuples()] repr_rho = [list(x) for x in self._rho.cycle_tuples()] darts_rho = flatten(repr_rho) darts_sigma = flatten(repr_sigma) val_one = [x for x in darts_rho if x not in darts_sigma] - #the total number of vertices of sigma is its number of cycles - #of length >1 plus the number of singletons that are actually - #vertices of valency 1 + # the total number of vertices of sigma is its number of cycles + # of length >1 plus the number of singletons that are actually + # vertices of valency 1 vertices = len(self._sigma.cycle_tuples()) + len(val_one) edges = len(self._rho.cycle_tuples()) - #formula for the genus using that the thickening is homotopically - #equivalent to the graph + # formula for the genus using that the thickening is homotopically + # equivalent to the graph g = (-vertices + edges - self.number_boundaries() + 2) // 2 return g @@ -713,20 +708,20 @@ def boundary(self): [2, 13, 14, 5, 6, 11, 12, 9, 7, 18, 19, 20, 20, 19, 16, 1], [3, 10, 11, 6, 4, 17, 18, 7, 8, 15, 13, 2]] """ - #initialize and empty list to hold the labels of the boundaries + # initialize and empty list to hold the labels of the boundaries bound = [] - #since lists of tuples are not modifiable, we change the data to a - #list of lists + # since lists of tuples are not modifiable, we change the data to a + # list of lists aux_perm = (self._rho * self._sigma).cycle_tuples(singletons=True) - #the cycles of the permutation rho*sigma are in 1:1 correspondence with - #the boundary components of the thickening (see function number_boundaries()) - #but they are not the labeled boundary components. - #With the next for, we convert the cycles of rho*sigma to actually - #the labelling of the edges. Each edge, therefore, should appear twice + # the cycles of the permutation rho*sigma are in 1:1 correspondence with + # the boundary components of the thickening (see function number_boundaries()) + # but they are not the labeled boundary components. + # With the next for, we convert the cycles of rho*sigma to actually + # the labelling of the edges. Each edge, therefore, should appear twice - for i,p in enumerate(aux_perm): + for i, p in enumerate(aux_perm): bound = bound + [[]] for j in range(len(p)): if self._rho(p[j]) != p[j]: @@ -735,8 +730,8 @@ def boundary(self): else: continue - #finally the function returns a List of lists. Each list contains - #a sequence of numbers and each number corresponds to a half-edge. + # finally the function returns a List of lists. Each list contains + # a sequence of numbers and each number corresponds to a half-edge. return _clean(bound) def reduced(self): @@ -785,29 +780,27 @@ def reduced(self): sage: G3.rho() (5,18)(6,14)(8,19)(9,15)(11,20)(12,16) """ - #the following two lines convert the list of tuples to list of lists - #we have to contract exactly n edges + # the following two lines convert the list of tuples to list of lists + # we have to contract exactly n edges aux_ribbon = deepcopy(self) aux_rho = [list(x) for x in aux_ribbon._rho.cycle_tuples()] - #Observe that in the end we will have `\mu` edges, so we - #know exactly how many steps we will iterate + # Observe that in the end we will have `\mu` edges, so we + # know exactly how many steps we will iterate while len(aux_rho) > self.mu(): aux_sigma = [list(x) for x in aux_ribbon._sigma.cycle_tuples(singletons=True)] aux_rho = [list(x) for x in aux_ribbon._rho.cycle_tuples()] for j in range(len(aux_rho)): - if (_find(aux_sigma, aux_rho[j][0])[0] != - _find(aux_sigma, aux_rho[j][1])[0]): + if _find(aux_sigma, aux_rho[j][0])[0] != _find(aux_sigma, aux_rho[j][1])[0]: aux_ribbon = aux_ribbon.contract_edge(j) - aux_rho = [list(x) for - x in aux_ribbon._rho.cycle_tuples()] + aux_rho = [list(x) for x in aux_ribbon._rho.cycle_tuples()] break - #finally we change the data to a list of tuples and return the - #information as a ribbon graph. + # finally we change the data to a list of tuples and return the + # information as a ribbon graph. return aux_ribbon - #the next function computes a basis of homology, it uses - #the previous function. + # the next function computes a basis of homology, it uses + # the previous function. def make_generic(self): r""" @@ -868,8 +861,8 @@ def make_generic(self): """ aux_ribbon = self.reduced() - for i in range(2*aux_ribbon.mu() - 2): - aux_ribbon = aux_ribbon.extrude_edge(i,0,2) + for i in range(2 * aux_ribbon.mu() - 2): + aux_ribbon = aux_ribbon.extrude_edge(i, 0, 2) return aux_ribbon @@ -961,8 +954,7 @@ def homology_basis(self): # in reduced() this set is contractible and can be define as the # complement of reduced_rho in rho - center = [list(x) for x in self._rho.cycle_tuples() - if (x not in self.reduced()._rho.cycle_tuples())] + center = [list(x) for x in self._rho.cycle_tuples() if (x not in self.reduced()._rho.cycle_tuples())] # We define an auxiliary list 'vertices' that will contain the # vertices (cycles of sigma) corresponding to each half edge. @@ -982,37 +974,32 @@ def homology_basis(self): if vertices[i].count(vertices[i][k]) == 1: m = k // 2 del basis[i][m] - del vertices[i][2*m:2*m+2] + del vertices[i][2 * m : 2 * m + 2] k = 0 else: k += 1 for i in range(len(basis)): for j in range(1, len(basis[i])): - n = [t for t, n in enumerate(vertices[i]) - if n == vertices[i][2*j-1]][1] + n = [t for t, n in enumerate(vertices[i]) if n == vertices[i][2 * j - 1]][1] ind = n // 2 if j != ind: basis[i][j], basis[i][ind] = basis[i][ind], basis[i][j] - vertices[i][2*j], vertices[i][2*ind] = \ - vertices[i][2*ind], vertices[i][2*j] + vertices[i][2 * j], vertices[i][2 * ind] = vertices[i][2 * ind], vertices[i][2 * j] - vertices[i][2*j+1], vertices[i][2*ind+1] = \ - vertices[i][2*ind+1], vertices[i][2*j+1] + vertices[i][2 * j + 1], vertices[i][2 * ind + 1] = vertices[i][2 * ind + 1], vertices[i][2 * j + 1] - if (vertices[i][2*j-1] != vertices[i][2*j]): - vertices[i][2*j], vertices[i][2*j+1] = \ - vertices[i][2*j+1], vertices[i][2*j] + if vertices[i][2 * j - 1] != vertices[i][2 * j]: + vertices[i][2 * j], vertices[i][2 * j + 1] = vertices[i][2 * j + 1], vertices[i][2 * j] - basis[i][j][0], basis[i][j][1] = \ - basis[i][j][1], basis[i][j][0] + basis[i][j][0], basis[i][j][1] = basis[i][j][1], basis[i][j][0] - #the variable basis is a LIST of Lists of lists. Each List - #corresponds to an element of the basis and each list in a List - #is just a 2-tuple which corresponds to an ''ordered'' edge of rho. + # the variable basis is a LIST of Lists of lists. Each List + # corresponds to an element of the basis and each list in a List + # is just a 2-tuple which corresponds to an ''ordered'' edge of rho. return basis @@ -1046,38 +1033,35 @@ def normalize(self): (1,2,3)(4,5,6) (1,4)(2,5)(3,6) """ - #First we compute the vertices of valency 1 and store them in val_one. + # First we compute the vertices of valency 1 and store them in val_one. aux_sigma = [list(x) for x in self._sigma.cycle_tuples()] aux_rho = [list(x) for x in self._rho.cycle_tuples()] darts_rho = flatten(aux_rho) darts_sigma = flatten(aux_sigma) val_one = [x for x in darts_rho if x not in darts_sigma] - #We add them to aux_sigma + # We add them to aux_sigma for i in range(len(val_one)): aux_sigma += [[val_one[i]]] - #Now we proceed to normalize the numbers enumerating the darts. - #We do this by checking if every number from 1 to len(darts_rho) - #is actually in darts_rho. + # Now we proceed to normalize the numbers enumerating the darts. + # We do this by checking if every number from 1 to len(darts_rho) + # is actually in darts_rho. for i in range(len(darts_rho)): - found = i+1 in darts_rho - #if a value is not in darts_rho, we take the next number that appears - #and change it to the new value. + found = i + 1 in darts_rho + # if a value is not in darts_rho, we take the next number that appears + # and change it to the new value. if not found: - aux_val = min(x for x in darts_rho if x > i+1) + aux_val = min(x for x in darts_rho if x > i + 1) pos_darts = darts_rho.index(aux_val) - pos_rho = _find(aux_rho,aux_val) - pos_sigma = _find(aux_sigma,aux_val) + pos_rho = _find(aux_rho, aux_val) + pos_sigma = _find(aux_sigma, aux_val) - #Now we set the found positions to the new normalized value - darts_rho[pos_darts] = i+1 - aux_sigma[pos_sigma[0]][pos_sigma[1]] = i+1 - aux_rho[pos_rho[0]][pos_rho[1]] = i+1 + # Now we set the found positions to the new normalized value + darts_rho[pos_darts] = i + 1 + aux_sigma[pos_sigma[0]][pos_sigma[1]] = i + 1 + aux_rho[pos_rho[0]][pos_rho[1]] = i + 1 - return RibbonGraph( - PermutationConstructor([tuple(x) for x in aux_sigma]), - PermutationConstructor([tuple(x) for x in aux_rho]) - ) + return RibbonGraph(PermutationConstructor([tuple(x) for x in aux_sigma]), PermutationConstructor([tuple(x) for x in aux_rho])) def make_ribbon(g, r): @@ -1130,28 +1114,27 @@ def make_ribbon(g, r): sage: R.rho() (1,16)(2,17)(3,18)(4,19)(5,20)(6,21)(7,22)(8,23)(9,24)(10,25)(11,26)(12,27)(13,28)(14,29)(15,30)(31,32)(33,34) """ - #Initialize the two vertices of sigma and the edge joining them - repr_sigma = [[1],[2*g+2]] - repr_rho = [[1,2*g+2]] - - #We first generate the surface of genus g and 1 boundary component. - #This is done by considering the usual planar representation of - #a surface as a polygon of 4*g+2 edges with identifications. (see - #any topology book on the classification of surfaces) - for i in range(2*g): - repr_sigma[0].append(i+2) - repr_sigma[1].append(i+(2*g+2)+1) - repr_rho += [[i+2,i+(2*g+2)+1]] - - #finally we add an edge for each additional boundary component. - max_dart = 4*g+2 - for j in range(r-1): - repr_sigma[0].insert(0, max_dart+2*(j+1)-1) - repr_sigma[1].insert(j+1, max_dart+2*(j+1)) - repr_rho += [[max_dart+2*(j+1)-1, max_dart+2*(j+1)]] - - return RibbonGraph(PermutationConstructor([tuple(x) for x in repr_sigma]), - PermutationConstructor([tuple(x) for x in repr_rho])) + # Initialize the two vertices of sigma and the edge joining them + repr_sigma = [[1], [2 * g + 2]] + repr_rho = [[1, 2 * g + 2]] + + # We first generate the surface of genus g and 1 boundary component. + # This is done by considering the usual planar representation of + # a surface as a polygon of 4*g+2 edges with identifications. (see + # any topology book on the classification of surfaces) + for i in range(2 * g): + repr_sigma[0].append(i + 2) + repr_sigma[1].append(i + (2 * g + 2) + 1) + repr_rho += [[i + 2, i + (2 * g + 2) + 1]] + + # finally we add an edge for each additional boundary component. + max_dart = 4 * g + 2 + for j in range(r - 1): + repr_sigma[0].insert(0, max_dart + 2 * (j + 1) - 1) + repr_sigma[1].insert(j + 1, max_dart + 2 * (j + 1)) + repr_rho += [[max_dart + 2 * (j + 1) - 1, max_dart + 2 * (j + 1)]] + + return RibbonGraph(PermutationConstructor([tuple(x) for x in repr_sigma]), PermutationConstructor([tuple(x) for x in repr_rho])) def bipartite_ribbon_graph(p, q): @@ -1206,22 +1189,19 @@ def bipartite_ribbon_graph(p, q): sigma = [] rho = [] for i in range(p): - aux_tuple = [i*q + j + 1 for j in range(q)] + aux_tuple = [i * q + j + 1 for j in range(q)] sigma += [aux_tuple] for i in range(q): - aux_tuple = [p*q + i*p + j + 1 for j in range(p)] + aux_tuple = [p * q + i * p + j + 1 for j in range(p)] sigma += [aux_tuple] - for i in range(p*q): - if (i+1) % q == 0: + for i in range(p * q): + if (i + 1) % q == 0: k = q - elif (i+1) % q != 0: - k = (i+1) % q + elif (i + 1) % q != 0: + k = (i + 1) % q t = 0 - if (i+1) % q != 0: + if (i + 1) % q != 0: t = 1 - aux_edge = [i+1, p*q + k*p - ((i+1 + t*q)/q).floor() + 1] + aux_edge = [i + 1, p * q + k * p - ((i + 1 + t * q) / q).floor() + 1] rho += [aux_edge] - return RibbonGraph( - PermutationConstructor([tuple(x) for x in sigma]), - PermutationConstructor([tuple(x) for x in rho]) - ) + return RibbonGraph(PermutationConstructor([tuple(x) for x in sigma]), PermutationConstructor([tuple(x) for x in rho])) diff --git a/src/sage/geometry/riemannian_manifolds/all.py b/src/sage/geometry/riemannian_manifolds/all.py index 705438b39c0..c7dcc8ce0af 100644 --- a/src/sage/geometry/riemannian_manifolds/all.py +++ b/src/sage/geometry/riemannian_manifolds/all.py @@ -1,6 +1,5 @@ from sage.misc.lazy_import import lazy_import -lazy_import('sage.geometry.riemannian_manifolds.parametrized_surface3d', - 'ParametrizedSurface3D') -lazy_import('sage.geometry.riemannian_manifolds.surface3d_generators', - 'surfaces') + +lazy_import('sage.geometry.riemannian_manifolds.parametrized_surface3d', 'ParametrizedSurface3D') +lazy_import('sage.geometry.riemannian_manifolds.surface3d_generators', 'surfaces') del lazy_import diff --git a/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py b/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py index 8e97a8fc263..ff2b0682d85 100644 --- a/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py +++ b/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py @@ -6,6 +6,7 @@ - Mikhail Malakhaltsev (2010-09-25): initial version - Joris Vankerschaver (2010-10-25): implementation, doctests """ + # **************************************************************************** # Copyright (C) 2010 Mikhail Malakhaltsev # Copyright (C) 2010 Joris Vankerschaver @@ -370,7 +371,7 @@ def __init__(self, equation, variables, name=None): self.variables_range = None self.variables_list = variables - self.variables = {1:self.variables_list[0], 2:self.variables_list[1]} + self.variables = {1: self.variables_list[0], 2: self.variables_list[1]} self.name = name def _latex_(self): @@ -387,6 +388,7 @@ def _latex_(self): \left(\cos\left(u\right) \cos\left(v\right), \cos\left(v\right) \sin\left(u\right), \sin\left(v\right)\right) """ from sage.misc.latex import latex + return latex(self.equation) def _repr_(self): @@ -406,8 +408,7 @@ def _repr_(self): name = 'Parametrized surface' if self.name is not None: name += " ('%s')" % self.name - s = '%(designation)s with equation %(eq)s' % \ - {'designation': name, 'eq': str(self.equation)} + s = '%(designation)s with equation %(eq)s' % {'designation': name, 'eq': str(self.equation)} return s def point(self, coords): @@ -477,8 +478,7 @@ def tangent_vector(self, coords, components): components = vector(components) d = dict(zip(self.variables_list, coords)) - jacobian = matrix([[f.diff(u).subs(d) for u in self.variables_list] - for f in self.equation]) + jacobian = matrix([[f.diff(u).subs(d) for u in self.variables_list] for f in self.equation]) return jacobian * components def plot(self, urange=None, vrange=None, **kwds): @@ -509,9 +509,9 @@ def plot(self, urange=None, vrange=None, **kwds): if self.variables_range is None: if urange is None: - urange = (0, 2*pi) + urange = (0, 2 * pi) if vrange is None: - vrange = (0, 2*pi) + vrange = (0, 2 * pi) else: if urange is None: urange = self.variables_range[0] @@ -542,14 +542,10 @@ def natural_frame(self): {1: (1, 0, 2*u), 2: (0, 1, 2*v)} """ - dr1 = \ - vector([_simplify_full_rad( diff(f,self.variables[1]) ) - for f in self.equation]) - dr2 = \ - vector([_simplify_full_rad( diff(f,self.variables[2]) ) - for f in self.equation]) + dr1 = vector([_simplify_full_rad(diff(f, self.variables[1])) for f in self.equation]) + dr2 = vector([_simplify_full_rad(diff(f, self.variables[2])) for f in self.equation]) - return {1:dr1, 2:dr2} + return {1: dr1, 2: dr2} @cached_method def normal_vector(self, normalized=False): @@ -600,7 +596,7 @@ def _compute_first_fundamental_form_coefficient(self, index): 4*u*v """ dr = self.natural_frame() - return _simplify_full_rad(dr[index[0]]*dr[index[1]]) + return _simplify_full_rad(dr[index[0]] * dr[index[1]]) def first_fundamental_form_coefficient(self, index): r""" @@ -653,8 +649,7 @@ def first_fundamental_form_coefficients(self): """ coefficients = {} for index in product((1, 2), repeat=2): - coefficients[index] = \ - self._compute_first_fundamental_form_coefficient(index) + coefficients[index] = self._compute_first_fundamental_form_coefficient(index) return coefficients def first_fundamental_form(self, vector1, vector2): @@ -687,8 +682,7 @@ def first_fundamental_form(self, vector1, vector2): 2*cos(v)^2 + 1 """ gamma = self.first_fundamental_form_coefficients() - return sum(gamma[(i,j)] * vector1[i - 1] * vector2[j - 1] - for i, j in product((1, 2), repeat=2)) + return sum(gamma[(i, j)] * vector1[i - 1] * vector2[j - 1] for i, j in product((1, 2), repeat=2)) def area_form_squared(self): """ @@ -709,7 +703,7 @@ def area_form_squared(self): cos(v)^2 """ gamma = self.first_fundamental_form_coefficients() - sq = gamma[(1,1)] * gamma[(2,2)] - gamma[(1,2)]**2 + sq = gamma[(1, 1)] * gamma[(2, 2)] - gamma[(1, 2)] ** 2 return _simplify_full_rad(sq) def area_form(self): @@ -751,14 +745,14 @@ def first_fundamental_form_inverse_coefficients(self): """ g = self.first_fundamental_form_coefficients() - D = g[(1,1)] * g[(2,2)] - g[(1,2)]**2 + D = g[(1, 1)] * g[(2, 2)] - g[(1, 2)] ** 2 - gi11 = _simplify_full_rad(g[(2,2)]/D) - gi12 = _simplify_full_rad(-g[(1,2)]/D) + gi11 = _simplify_full_rad(g[(2, 2)] / D) + gi12 = _simplify_full_rad(-g[(1, 2)] / D) gi21 = gi12 - gi22 = _simplify_full_rad(g[(1,1)]/D) + gi22 = _simplify_full_rad(g[(1, 1)] / D) - return {(1,1): gi11, (1,2): gi12, (2,1): gi21, (2,2): gi22} + return {(1, 1): gi11, (1, 2): gi12, (2, 1): gi21, (2, 2): gi22} def first_fundamental_form_inverse_coefficient(self, index): r""" @@ -827,11 +821,11 @@ def rotation(self, theta): gi = self.first_fundamental_form_inverse_coefficients() w12 = self.area_form() - R11 = (cos(theta) + sin(theta)*gi[1,2]*w12).simplify_full() - R12 = (- sin(theta)*gi[1,1]*w12).simplify_full() - R21 = (sin(theta)*gi[2,2]*w12).simplify_full() - R22 = (cos(theta) - sin(theta)*gi[2,1]*w12).simplify_full() - return matrix([[R11,R12],[R21,R22]]) + R11 = (cos(theta) + sin(theta) * gi[1, 2] * w12).simplify_full() + R12 = (-sin(theta) * gi[1, 1] * w12).simplify_full() + R21 = (sin(theta) * gi[2, 2] * w12).simplify_full() + R22 = (cos(theta) - sin(theta) * gi[2, 1] * w12).simplify_full() + return matrix([[R11, R12], [R21, R22]]) @cached_method def orthonormal_frame(self, coordinates='ext'): @@ -882,16 +876,14 @@ def orthonormal_frame(self, coordinates='ext'): from sage.symbolic.constants import pi if coordinates not in ['ext', 'int']: - raise ValueError("Coordinate system must be exterior ('ext') " - "or interior ('int').") + raise ValueError("Coordinate system must be exterior ('ext') " "or interior ('int').") c = self.first_fundamental_form_coefficient([1, 1]) if coordinates == 'ext': f1 = self.natural_frame()[1] E1 = _simplify_full_rad(f1 / sqrt(c)) - E2 = _simplify_full_rad( - self.normal_vector(normalized=True).cross_product(E1)) + E2 = _simplify_full_rad(self.normal_vector(normalized=True).cross_product(E1)) else: E1 = vector([_simplify_full_rad(1 / sqrt(c)), 0]) E2 = (self.rotation(pi / 2) * E1).simplify_full() @@ -960,11 +952,9 @@ def lie_bracket(self, v, w): w = vector(SR, w) variables = self.variables_list - Dv = matrix([[_simplify_full_rad(diff(component, u)) - for u in variables] for component in v]) - Dw = matrix([[_simplify_full_rad(diff(component, u)) - for u in variables] for component in w]) - return vector(Dv*w - Dw*v).simplify_full() + Dv = matrix([[_simplify_full_rad(diff(component, u)) for u in variables] for component in v]) + Dw = matrix([[_simplify_full_rad(diff(component, u)) for u in variables] for component in w]) + return vector(Dv * w - Dw * v).simplify_full() def frame_structure_functions(self, e1, e2): r""" @@ -1021,10 +1011,9 @@ def frame_structure_functions(self, e1, e2): lie_bracket = self.lie_bracket(e1, e2).simplify_full() transformation = matrix(SR, [e1, e2]).transpose() - w = (transformation.inverse()*lie_bracket).simplify_full() + w = (transformation.inverse() * lie_bracket).simplify_full() - return {(1,1,1): 0, (1,1,2): 0, (1,2,1): w[0], (1,2,2): w[1], - (2,1,1): -w[0], (2,1,2): -w[1], (2,2,1): 0, (2,2,2): 0} + return {(1, 1, 1): 0, (1, 1, 2): 0, (1, 2, 1): w[0], (1, 2, 2): w[1], (2, 1, 1): -w[0], (2, 1, 2): -w[1], (2, 2, 1): 0, (2, 2, 2): 0} @cached_method def _compute_second_order_frame_element(self, index): @@ -1045,8 +1034,7 @@ def _compute_second_order_frame_element(self, index): (0, 0, 2) """ variables = [self.variables[i] for i in index] - ddr_element = vector([_simplify_full_rad(diff(f, variables)) - for f in self.equation]) + ddr_element = vector([_simplify_full_rad(diff(f, variables)) for f in self.equation]) return ddr_element @@ -1077,8 +1065,7 @@ def second_order_natural_frame(self): vectors = {} for index in product((1, 2), repeat=2): sorted_index = tuple(sorted(index)) - vectors[index] = \ - self._compute_second_order_frame_element(sorted_index) + vectors[index] = self._compute_second_order_frame_element(sorted_index) return vectors def second_order_natural_frame_element(self, index): @@ -1125,7 +1112,7 @@ def _compute_second_fundamental_form_coefficient(self, index): """ N = self.normal_vector(normalized=True) v = self.second_order_natural_frame_element(index) - return _simplify_full_rad(v*N) + return _simplify_full_rad(v * N) def second_fundamental_form_coefficient(self, index): r""" @@ -1177,8 +1164,7 @@ def second_fundamental_form_coefficients(self): coefficients = {} for index in product((1, 2), repeat=2): - coefficients[index] = \ - self._compute_second_fundamental_form_coefficient(index) + coefficients[index] = self._compute_second_fundamental_form_coefficient(index) return coefficients def second_fundamental_form(self, vector1, vector2): @@ -1214,8 +1200,7 @@ def second_fundamental_form(self, vector1, vector2): -2*cos(v)^2 - 1 """ hh = self.second_fundamental_form_coefficients() - return sum(hh[(i, j)] * vector1[i - 1] * vector2[j - 1] - for (i, j) in product((1, 2), repeat=2)) + return sum(hh[(i, j)] * vector1[i - 1] * vector2[j - 1] for (i, j) in product((1, 2), repeat=2)) def gauss_curvature(self): r""" @@ -1237,8 +1222,7 @@ def gauss_curvature(self): R^(-2) """ hh = self.second_fundamental_form_coefficients() - return _simplify_full_rad( - (hh[(1,1)] * hh[(2,2)] - hh[(1,2)]**2)/self.area_form_squared()) + return _simplify_full_rad((hh[(1, 1)] * hh[(2, 2)] - hh[(1, 2)] ** 2) / self.area_form_squared()) def mean_curvature(self): r""" @@ -1261,10 +1245,9 @@ def mean_curvature(self): """ gg = self.first_fundamental_form_coefficients() hh = self.second_fundamental_form_coefficients() - denom = 2*self.area_form_squared() - numer = (gg[(2,2)]*hh[(1,1)] - 2*gg[(1,2)]*hh[(1,2)] + - gg[(1,1)]*hh[(2,2)]).simplify_full() - return _simplify_full_rad(numer/denom) + denom = 2 * self.area_form_squared() + numer = (gg[(2, 2)] * hh[(1, 1)] - 2 * gg[(1, 2)] * hh[(1, 2)] + gg[(1, 1)] * hh[(2, 2)]).simplify_full() + return _simplify_full_rad(numer / denom) @cached_method def shape_operator_coefficients(self): @@ -1290,12 +1273,12 @@ def shape_operator_coefficients(self): gi = self.first_fundamental_form_inverse_coefficients() hh = self.second_fundamental_form_coefficients() - sh_op11 = _simplify_full_rad(gi[(1,1)]*hh[(1,1)] + gi[(1,2)]*hh[(1,2)]) - sh_op12 = _simplify_full_rad(gi[(1,1)]*hh[(2,1)] + gi[(1,2)]*hh[(2,2)]) - sh_op21 = _simplify_full_rad(gi[(2,1)]*hh[(1,1)] + gi[(2,2)]*hh[(1,2)]) - sh_op22 = _simplify_full_rad(gi[(2,1)]*hh[(2,1)] + gi[(2,2)]*hh[(2,2)]) + sh_op11 = _simplify_full_rad(gi[(1, 1)] * hh[(1, 1)] + gi[(1, 2)] * hh[(1, 2)]) + sh_op12 = _simplify_full_rad(gi[(1, 1)] * hh[(2, 1)] + gi[(1, 2)] * hh[(2, 2)]) + sh_op21 = _simplify_full_rad(gi[(2, 1)] * hh[(1, 1)] + gi[(2, 2)] * hh[(1, 2)]) + sh_op22 = _simplify_full_rad(gi[(2, 1)] * hh[(2, 1)] + gi[(2, 2)] * hh[(2, 2)]) - return {(1,1): sh_op11, (1,2): sh_op12, (2,1): sh_op21, (2,2): sh_op22} + return {(1, 1): sh_op11, (1, 2): sh_op12, (2, 1): sh_op21, (2, 2): sh_op22} def shape_operator(self): r""" @@ -1330,8 +1313,7 @@ def shape_operator(self): """ shop = self.shape_operator_coefficients() - shop_matrix = matrix([[shop[(1,1)],shop[(1,2)]], - [shop[(2,1)],shop[(2,2)]]]) + shop_matrix = matrix([[shop[(1, 1)], shop[(1, 2)]], [shop[(2, 1)], shop[(2, 2)]]]) return shop_matrix def principal_directions(self): @@ -1405,15 +1387,13 @@ def connection_coefficients(self): gi = self.first_fundamental_form_inverse_coefficients() dg = {} - for i,j,k in product((1, 2), repeat=3): - dg[(i,j,k)] = _simplify_full_rad(gg[(j,k)].differentiate(x[i])) + for i, j, k in product((1, 2), repeat=3): + dg[(i, j, k)] = _simplify_full_rad(gg[(j, k)].differentiate(x[i])) structfun = {} - for i,j,k in product((1, 2), repeat=3): - structfun[(i,j,k)] = sum(gi[(k,s)]*(dg[(i,j,s)] + dg[(j,i,s)] - - dg[(s,i,j)])/2 - for s in (1,2)) - structfun[(i,j,k)] = _simplify_full_rad(structfun[(i,j,k)]) + for i, j, k in product((1, 2), repeat=3): + structfun[(i, j, k)] = sum(gi[(k, s)] * (dg[(i, j, s)] + dg[(j, i, s)] - dg[(s, i, j)]) / 2 for s in (1, 2)) + structfun[(i, j, k)] = _simplify_full_rad(structfun[(i, j, k)]) return structfun @cached_method @@ -1440,15 +1420,13 @@ def _create_geodesic_ode_system(self): with SR.temp_var(domain='real') as v1: with SR.temp_var(domain='real') as v2: - dv1 = - C[(1,1,1)]*v1**2 - 2*C[(1,2,1)]*v1*v2 - C[(2,2,1)]*v2**2 - dv2 = - C[(1,1,2)]*v1**2 - 2*C[(1,2,2)]*v1*v2 - C[(2,2,2)]*v2**2 + dv1 = -C[(1, 1, 1)] * v1**2 - 2 * C[(1, 2, 1)] * v1 * v2 - C[(2, 2, 1)] * v2**2 + dv2 = -C[(1, 1, 2)] * v1**2 - 2 * C[(1, 2, 2)] * v1 * v2 - C[(2, 2, 2)] * v2**2 fun1 = fast_float(dv1, str(u1), str(u2), str(v1), str(v2)) fun2 = fast_float(dv2, str(u1), str(u2), str(v1), str(v2)) geodesic_ode = ode_solver() - geodesic_ode.function = ( - lambda t, u1_u2_v1_v2: - [u1_u2_v1_v2[2], u1_u2_v1_v2[3], fun1(*u1_u2_v1_v2), fun2(*u1_u2_v1_v2)]) + geodesic_ode.function = lambda t, u1_u2_v1_v2: [u1_u2_v1_v2[2], u1_u2_v1_v2[3], fun1(*u1_u2_v1_v2), fun2(*u1_u2_v1_v2)] return geodesic_ode def geodesics_numerical(self, p0, v0, tinterval): @@ -1512,9 +1490,7 @@ def geodesics_numerical(self, p0, v0, tinterval): solver.y_0 = [p0[0], p0[1], v0[0], v0[1]] solver.ode_solve(t_span=t_interval, num_points=n) - parsed_solution = \ - [[vec[0], vec[1][0:2], vec[1][2:], self.point(vec[1])] - for vec in solver.solution] + parsed_solution = [[vec[0], vec[1][0:2], vec[1][2:], self.point(vec[1])] for vec in solver.solution] return parsed_solution @@ -1554,10 +1530,8 @@ def _create_pt_ode_system(self, curve, t): with SR.temp_var(domain='real') as v1: with SR.temp_var(domain='real') as v2: - dv1 = - C[(1,1,1)]*v1*du1 - C[(1,2,1)]*(du1*v2 + du2*v1) - \ - C[(2,2,1)]*du2*v2 - dv2 = - C[(1,1,2)]*v1*du1 - C[(1,2,2)]*(du1*v2 + du2*v1) - \ - C[(2,2,2)]*du2*v2 + dv1 = -C[(1, 1, 1)] * v1 * du1 - C[(1, 2, 1)] * (du1 * v2 + du2 * v1) - C[(2, 2, 1)] * du2 * v2 + dv2 = -C[(1, 1, 2)] * v1 * du1 - C[(1, 2, 2)] * (du1 * v2 + du2 * v1) - C[(2, 2, 2)] * du2 * v2 fun1 = fast_float(dv1, str(t), str(v1), str(v2)) fun2 = fast_float(dv2, str(t), str(v1), str(v2)) diff --git a/src/sage/geometry/riemannian_manifolds/surface3d_generators.py b/src/sage/geometry/riemannian_manifolds/surface3d_generators.py index 76177dc279b..86c133189b9 100644 --- a/src/sage/geometry/riemannian_manifolds/surface3d_generators.py +++ b/src/sage/geometry/riemannian_manifolds/surface3d_generators.py @@ -5,12 +5,13 @@ - Joris Vankerschaver (2012-06-16) """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2010 Joris Vankerschaver # # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.symbolic.constants import pi @@ -18,8 +19,7 @@ from sage.functions.trig import sin, cos, tan from sage.functions.hyperbolic import cosh, tanh from sage.symbolic.ring import var -from sage.geometry.riemannian_manifolds.parametrized_surface3d import \ - ParametrizedSurface3D +from sage.geometry.riemannian_manifolds.parametrized_surface3d import ParametrizedSurface3D class SurfaceGenerators: @@ -27,6 +27,7 @@ class SurfaceGenerators: A class consisting of generators for several common parametrized surfaces in 3D. """ + @staticmethod def Catenoid(c=1, name='Catenoid'): r""" @@ -56,7 +57,7 @@ def Catenoid(c=1, name='Catenoid'): Graphics3d Object """ u, v = var('u, v') - catenoid_eq = [c*cosh(v/c)*cos(u), c*cosh(v/c)*sin(u), v] + catenoid_eq = [c * cosh(v / c) * cos(u), c * cosh(v / c) * sin(u), v] coords = ((u, 0, 2 * pi), (v, -1, 1)) return ParametrizedSurface3D(catenoid_eq, coords, name) @@ -89,8 +90,7 @@ def Crosscap(r=1, name='Crosscap'): Graphics3d Object """ u, v = var('u, v') - crosscap_eq = [r*(1+cos(v))*cos(u), r*(1+cos(v))*sin(u), - -tanh(u-pi)*r*sin(v)] + crosscap_eq = [r * (1 + cos(v)) * cos(u), r * (1 + cos(v)) * sin(u), -tanh(u - pi) * r * sin(v)] coords = ((u, 0, 2 * pi), (v, 0, 2 * pi)) return ParametrizedSurface3D(crosscap_eq, coords, name) @@ -123,8 +123,7 @@ def Dini(a=1, b=1, name="Dini's surface"): Graphics3d Object """ u, v = var('u, v') - dini_eq = [a*cos(u)*sin(v), a*sin(u)*sin(v), - a*(cos(v) + log(tan(v/2))) + b*u] + dini_eq = [a * cos(u) * sin(v), a * sin(u) * sin(v), a * (cos(v) + log(tan(v / 2))) + b * u] coords = ((u, 0, 2 * pi), (v, 0, 2 * pi)) return ParametrizedSurface3D(dini_eq, coords, name) @@ -163,9 +162,7 @@ def Ellipsoid(center=(0, 0, 0), axes=(1, 1, 1), name='Ellipsoid'): u, v = var('u, v') x, y, z = center a, b, c = axes - ellipsoid_parametric_eq = [x + a*cos(u)*cos(v), - y + b*sin(u)*cos(v), - z + c*sin(v)] + ellipsoid_parametric_eq = [x + a * cos(u) * cos(v), y + b * sin(u) * cos(v), z + c * sin(v)] coords = ((u, 0, 2 * pi), (v, -pi / 2, pi / 2)) return ParametrizedSurface3D(ellipsoid_parametric_eq, coords, name) @@ -196,7 +193,7 @@ def Enneper(name="Enneper's surface"): Graphics3d Object """ u, v = var('u, v') - enneper_eq = [u*(1-u**2/3+v**2)/3, -v*(1-v**2/3+u**2)/3, (u**2-v**2)/3] + enneper_eq = [u * (1 - u**2 / 3 + v**2) / 3, -v * (1 - v**2 / 3 + u**2) / 3, (u**2 - v**2) / 3] coords = ((u, -3, 3), (v, -3, 3)) return ParametrizedSurface3D(enneper_eq, coords, name) @@ -230,7 +227,7 @@ def Helicoid(h=1, name='Helicoid'): Graphics3d Object """ rho, theta = var('rho, theta') - helicoid_eq = [rho*cos(theta), rho*sin(theta), h*theta/(2*pi)] + helicoid_eq = [rho * cos(theta), rho * sin(theta), h * theta / (2 * pi)] coords = ((rho, -2, 2), (theta, 0, 2 * pi)) return ParametrizedSurface3D(helicoid_eq, coords, name) @@ -263,9 +260,9 @@ def Klein(r=1, name="Klein bottle"): Graphics3d Object """ u, v = var('u, v') - x = (r + cos(u/2)*sin(v) - sin(u/2)*sin(2*v))*cos(u) - y = (r + cos(u/2)*sin(v) - sin(u/2)*sin(2*v))*sin(u) - z = sin(u/2)*sin(v) + cos(u/2)*sin(2*v) + x = (r + cos(u / 2) * sin(v) - sin(u / 2) * sin(2 * v)) * cos(u) + y = (r + cos(u / 2) * sin(v) - sin(u / 2) * sin(2 * v)) * sin(u) + z = sin(u / 2) * sin(v) + cos(u / 2) * sin(2 * v) klein_eq = [x, y, z] coords = ((u, 0, 2 * pi), (v, 0, 2 * pi)) @@ -294,7 +291,7 @@ def MonkeySaddle(name="Monkey saddle"): Graphics3d Object """ u, v = var('u, v') - monkey_eq = [u, v, u**3 - 3*u*v**2] + monkey_eq = [u, v, u**3 - 3 * u * v**2] coords = ((u, -2, 2), (v, -2, 2)) return ParametrizedSurface3D(monkey_eq, coords, name) @@ -338,9 +335,9 @@ def Paraboloid(a=1, b=1, c=1, elliptic=True, name=None): x = u y = v if elliptic: - z = c*(v**2/b**2 + u**2/a**2) + z = c * (v**2 / b**2 + u**2 / a**2) else: - z = c*(v**2/b**2 - u**2/a**2) + z = c * (v**2 / b**2 - u**2 / a**2) paraboloid_eq = [x, y, z] coords = ((u, -3, 3), (v, -3, 3)) @@ -424,7 +421,7 @@ def Torus(r=2, R=3, name='Torus'): Graphics3d Object """ u, v = var('u, v') - torus_eq = [(R+r*cos(v))*cos(u), (R+r*cos(v))*sin(u), r*sin(v)] + torus_eq = [(R + r * cos(v)) * cos(u), (R + r * cos(v)) * sin(u), r * sin(v)] coords = ((u, 0, 2 * pi), (v, 0, 2 * pi)) return ParametrizedSurface3D(torus_eq, coords, name) @@ -451,7 +448,7 @@ def WhitneyUmbrella(name="Whitney's umbrella"): Graphics3d Object """ u, v = var('u, v') - whitney_eq = [u*v, u, v**2] + whitney_eq = [u * v, u, v**2] coords = ((u, -1, 1), (v, -1, 1)) return ParametrizedSurface3D(whitney_eq, coords, name) diff --git a/src/sage/geometry/toric_lattice.py b/src/sage/geometry/toric_lattice.py index a3dcdfad264..f9dcf397314 100644 --- a/src/sage/geometry/toric_lattice.py +++ b/src/sage/geometry/toric_lattice.py @@ -133,6 +133,7 @@ sage: N(1,2,3) + N(1,2,3) N(2, 4, 6) """ + # Parts of the "tutorial" above are also in toric_lattice_element.pyx. @@ -147,17 +148,14 @@ from sage.geometry.toric_lattice_element import ToricLatticeElement from sage.misc.lazy_import import lazy_import + lazy_import('sage.geometry.toric_plotter', 'ToricPlotter') from sage.misc.latex import latex from sage.structure.element import parent -from sage.structure.richcmp import (richcmp_method, richcmp, rich_to_bool, - richcmp_not_equal) +from sage.structure.richcmp import richcmp_method, richcmp, rich_to_bool, richcmp_not_equal from sage.modules.fg_pid.fgp_element import FGP_Element from sage.modules.fg_pid.fgp_module import FGP_Module_class -from sage.modules.free_module import (FreeModule_ambient_pid, - FreeModule_generic_pid, - FreeModule_submodule_pid, - FreeModule_submodule_with_basis_pid) +from sage.modules.free_module import FreeModule_ambient_pid, FreeModule_generic_pid, FreeModule_submodule_pid, FreeModule_submodule_with_basis_pid from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.structure.factory import UniqueFactory @@ -247,8 +245,7 @@ class ToricLatticeFactory(UniqueFactory): for dual lattices or for LaTeX typesetting. """ - def create_key(self, rank, name=None, dual_name=None, - latex_name=None, latex_dual_name=None): + def create_key(self, rank, name=None, dual_name=None, latex_name=None, latex_dual_name=None): """ Create a key that uniquely identifies this toric lattice. @@ -271,8 +268,7 @@ def create_key(self, rank, name=None, dual_name=None, # Should we use standard M and N lattices? if name is None: if dual_name is not None: - raise ValueError("you can name the dual lattice only if you " - "also name the original one!") + raise ValueError("you can name the dual lattice only if you " "also name the original one!") name = "N" dual_name = "M" if latex_name is None: @@ -281,8 +277,7 @@ def create_key(self, rank, name=None, dual_name=None, # The default for latex_dual_name depends on whether dual_name was # given or constructed, so we determine it before dual_name if latex_dual_name is None: - latex_dual_name = (dual_name if dual_name is not None - else latex_name + "^*") + latex_dual_name = dual_name if dual_name is not None else latex_name + "^*" if dual_name is None: dual_name = name + "*" return (rank, name, dual_name, latex_name, latex_dual_name) @@ -368,12 +363,11 @@ def __call__(self, *args, **kwds): N2(1, 0) """ supercall = super().__call__ - if args == (0, ): + if args == (0,): # Special treatment for N(0) to return (0,...,0) return supercall(*args, **kwds) - if (isinstance(args[0], ToricLattice_quotient_element) - and args[0].parent().is_torsion_free()): + if isinstance(args[0], ToricLattice_quotient_element) and args[0].parent().is_torsion_free(): # convert a torsion free quotient lattice return supercall(list(args[0]), **kwds) @@ -381,11 +375,8 @@ def __call__(self, *args, **kwds): coordinates = [ZZ(_) for _ in args] except TypeError: # Prohibit conversion of elements of other lattices - if (isinstance(args[0], ToricLatticeElement) - and args[0].parent().ambient_module() - is not self.ambient_module()): - raise TypeError("%s cannot be converted to %s!" - % (args[0], self)) + if isinstance(args[0], ToricLatticeElement) and args[0].parent().ambient_module() is not self.ambient_module(): + raise TypeError("%s cannot be converted to %s!" % (args[0], self)) # "Standard call" return supercall(*args, **kwds) # Coordinates were given without packing them into a list or a tuple @@ -406,8 +397,7 @@ def _coerce_map_from_(self, other): ... TypeError: N(1, 2, 3) cannot be converted to 3-d lattice M! """ - if (isinstance(other, ToricLattice_generic) and - other.ambient_module() is not self.ambient_module()): + if isinstance(other, ToricLattice_generic) and other.ambient_module() is not self.ambient_module(): return None return super()._convert_map_from_(other) @@ -559,16 +549,14 @@ def intersection(self, other): if not isinstance(other, ToricLattice_generic): raise TypeError("%s is not a toric lattice!" % other) if self.ambient_module() != other.ambient_module(): - raise ValueError("%s and %s have different ambient lattices!" % - (self, other)) + raise ValueError("%s and %s have different ambient lattices!" % (self, other)) # Construct a generic intersection, but make sure to return a lattice. I = super().intersection(other) if not isinstance(I, ToricLattice_generic): I = self.ambient_module().submodule(I.basis()) return I - def quotient(self, sub, check=True, - positive_point=None, positive_dual_point=None, **kwds): + def quotient(self, sub, check=True, positive_point=None, positive_dual_point=None, **kwds): """ Return the quotient of ``self`` by the given sublattice ``sub``. @@ -664,8 +652,7 @@ def quotient(self, sub, check=True, 0-d lattice, quotient of 3-d lattice N by Sublattice """ - return ToricLattice_quotient(self, sub, check, - positive_point, positive_dual_point, **kwds) + return ToricLattice_quotient(self, sub, check, positive_point, positive_dual_point, **kwds) def saturation(self): r""" @@ -728,8 +715,7 @@ def span(self, gens, base_ring=ZZ, *args, **kwds): return ToricLattice_sublattice(A, gens) for g in gens: if isinstance(g, ToricLatticeElement) and g not in A: - raise ValueError("%s cannot generate a sublattice of %s" - % (g, A)) + raise ValueError("%s cannot generate a sublattice of %s" % (g, A)) return super().span(gens, base_ring, *args, **kwds) def span_of_basis(self, basis, base_ring=ZZ, *args, **kwds): @@ -780,8 +766,7 @@ def span_of_basis(self, basis, base_ring=ZZ, *args, **kwds): return ToricLattice_sublattice_with_basis(A, basis) for g in basis: if isinstance(g, ToricLatticeElement) and g not in A: - raise ValueError("%s cannot generate a sublattice of %s" - % (g, A)) + raise ValueError("%s cannot generate a sublattice of %s" % (g, A)) return super().span_of_basis(basis, base_ring, *args, **kwds) @@ -883,10 +868,7 @@ def __richcmp__(self, right, op): if lx != rx: return richcmp_not_equal(lx, rx, op) # If lattices are the same as ZZ-modules, compare associated names - return richcmp([self._name, self._dual_name, - self._latex_name, self._latex_dual_name], - [right._name, right._dual_name, - right._latex_name, right._latex_dual_name], op) + return richcmp([self._name, self._dual_name, self._latex_name, self._latex_dual_name], [right._name, right._dual_name, right._latex_name, right._latex_dual_name], op) def _latex_(self): r""" @@ -964,8 +946,7 @@ def dual(self): 32 """ if "_dual" not in self.__dict__: - self._dual = ToricLattice(self.rank(), self._dual_name, - self._name, self._latex_dual_name, self._latex_name) + self._dual = ToricLattice(self.rank(), self._dual_name, self._name, self._latex_dual_name, self._latex_name) return self._dual def plot(self, **options): @@ -994,8 +975,7 @@ def plot(self, **options): return tp.plot_lattice() -class ToricLattice_sublattice_with_basis(ToricLattice_generic, - FreeModule_submodule_with_basis_pid): +class ToricLattice_sublattice_with_basis(ToricLattice_generic, FreeModule_submodule_with_basis_pid): r""" Construct the sublattice of ``ambient`` toric lattice with given ``basis``. @@ -1091,10 +1071,8 @@ def dual(self): """ if "_dual" not in self.__dict__: if self is not self.saturation(): - raise ValueError("only dual lattices of saturated sublattices " - "can be constructed! Got %s." % self) - self._dual = (self.ambient_module().dual() / - self.basis_matrix().transpose().integer_kernel()) + raise ValueError("only dual lattices of saturated sublattices " "can be constructed! Got %s." % self) + self._dual = self.ambient_module().dual() / self.basis_matrix().transpose().integer_kernel() self._dual._dual = self return self._dual @@ -1135,8 +1113,7 @@ def plot(self, **options): return tp.plot_lattice() -class ToricLattice_sublattice(ToricLattice_sublattice_with_basis, - FreeModule_submodule_pid): +class ToricLattice_sublattice(ToricLattice_sublattice_with_basis, FreeModule_submodule_pid): r""" Construct the sublattice of ``ambient`` toric lattice generated by ``gens``. @@ -1174,6 +1151,7 @@ class ToricLattice_sublattice(ToricLattice_sublattice_with_basis, sage: sublattice.echelonized_basis() [N(1, 0, 1), N(0, 1, -1)] """ + pass @@ -1372,8 +1350,7 @@ def __init__(self, V, W, check=True, positive_point=None, positive_dual_point=No return self._flip_sign_of_generator = False - assert self.is_torsion_free() and self.ngens() == 1, \ - 'You may only specify a positive direction in the codimension one case.' + assert self.is_torsion_free() and self.ngens() == 1, 'You may only specify a positive direction in the codimension one case.' quotient_generator = self.gen(0) lattice = self.V().ambient_module() if (positive_point is not None) and (positive_dual_point is None): @@ -1381,15 +1358,15 @@ def __init__(self, V, W, check=True, positive_point=None, positive_dual_point=No point_quotient = self(positive_point) scalar_product = quotient_generator.vector()[0] * point_quotient.vector()[0] if scalar_product == 0: - raise ValueError(str(positive_point)+' is zero in the quotient.') + raise ValueError(str(positive_point) + ' is zero in the quotient.') elif (positive_point is None) and (positive_dual_point is not None): assert positive_dual_point in lattice.dual(), 'positive_dual_point must be a dual lattice point.' scalar_product = quotient_generator.lift() * positive_dual_point if scalar_product == 0: - raise ValueError(str(positive_dual_point)+' is zero on the lift of the quotient generator.') + raise ValueError(str(positive_dual_point) + ' is zero on the lift of the quotient generator.') else: raise ValueError('You may not specify both positive_point and positive_dual_point.') - self._flip_sign_of_generator = (scalar_product < 0) + self._flip_sign_of_generator = scalar_product < 0 def gens(self) -> tuple: """ @@ -1507,8 +1484,7 @@ def _repr_(self): by Sublattice """ if self.is_torsion_free(): - return "%d-d lattice, quotient of %s by %s" % (self.rank(), - self.V(), self.W()) + return "%d-d lattice, quotient of %s by %s" % (self.rank(), self.V(), self.W()) return "Quotient with torsion of %s by %s" % (self.V(), self.W()) def _module_constructor(self, V, W, check=True): @@ -1533,7 +1509,7 @@ def _module_constructor(self, V, W, check=True): sage: Q._module_constructor(N,Ns) Quotient with torsion of 3-d lattice N by Sublattice """ - return ToricLattice_quotient(V,W,check) + return ToricLattice_quotient(V, W, check) def base_extend(self, R): r""" @@ -1565,8 +1541,7 @@ def base_extend(self, R): return self if R is QQ: return self.V().base_extend(R) / self.W().base_extend(R) - raise NotImplementedError("quotients of toric lattices can only be " - "extended to ZZ or QQ, not %s!" % R) + raise NotImplementedError("quotients of toric lattices can only be " "extended to ZZ or QQ, not %s!" % R) def is_torsion_free(self): r""" @@ -1603,8 +1578,7 @@ def dual(self): Sublattice """ if "_dual" not in self.__dict__: - self._dual = self.V().dual().submodule( - self.W().basis_matrix().transpose().integer_kernel().gens()) + self._dual = self.V().dual().submodule(self.W().basis_matrix().transpose().integer_kernel().gens()) self._dual._dual = self return self._dual diff --git a/src/sage/geometry/toric_plotter.py b/src/sage/geometry/toric_plotter.py index 2fe29a8be0a..5aa03e20e63 100644 --- a/src/sage/geometry/toric_plotter.py +++ b/src/sage/geometry/toric_plotter.py @@ -34,7 +34,6 @@ Graphics object consisting of 31 graphics primitives """ - # **************************************************************************** # Copyright (C) 2010 Volker Braun # Copyright (C) 2010 Andrey Novoseltsev @@ -53,9 +52,8 @@ from sage.geometry.polyhedron.constructor import Polyhedron from sage.misc.lazy_import import lazy_import from sage.modules.free_module_element import vector -lazy_import("sage.plot.all", ["Color", "Graphics", - "arrow", "disk", "line", "point", - "polygon", "rainbow", "text"]) + +lazy_import("sage.plot.all", ["Color", "Graphics", "arrow", "disk", "line", "point", "polygon", "rainbow", "text"]) lazy_import("sage.plot.plot3d.all", "text3d") from sage.rings.real_double import RDF from sage.structure.sage_object import SageObject @@ -66,8 +64,8 @@ # automatically based on the plotted object and parameters actually provided by # the user. _default_options = dict() -_default_options["mode"] = "round" # Can be also "box" and "generators" -_default_options["show_lattice"] = None # Default is "True for small plots" +_default_options["mode"] = "round" # Can be also "box" and "generators" +_default_options["show_lattice"] = None # Default is "True for small plots" _default_options["show_rays"] = True _default_options["show_generators"] = True _default_options["show_walls"] = True @@ -211,10 +209,9 @@ def __init__(self, all_options, dimension, generators=None): if option not in sd: sd[option] = value if dimension not in [1, 2, 3]: - raise ValueError("toric objects can be plotted only for " - "dimensions 1, 2, and 3, not %s!" % dimension) + raise ValueError("toric objects can be plotted only for " "dimensions 1, 2, and 3, not %s!" % dimension) self.dimension = dimension - self.origin = vector(RDF, max(dimension, 2)) # 1-d is plotted in 2-d + self.origin = vector(RDF, max(dimension, 2)) # 1-d is plotted in 2-d if self.mode not in ["box", "generators", "round"]: raise ValueError("unrecognized plotting mode: %s!" % self.mode) # If radius was explicitly set by the user, it sets other bounds too. @@ -223,7 +220,7 @@ def __init__(self, all_options, dimension, generators=None): if sd["radius"] is not None: for key in ["xmin", "ymin", "zmin"]: if sd[key] is None: - sd[key] = - sd["radius"] + sd[key] = -sd["radius"] for key in ["xmax", "ymax", "zmax"]: if sd[key] is None: sd[key] = sd["radius"] @@ -300,8 +297,8 @@ def adjust_options(self): round = self.mode == "round" for key in ["xmin", "ymin", "zmin"]: if round or sd[key] is None: - sd[key] = - r - sd[key] = min(sd[key], - 0.5) + sd[key] = -r + sd[key] = min(sd[key], -0.5) sd[key] = RDF(sd[key]) for key in ["xmax", "ymax", "zmax"]: if round or sd[key] is None: @@ -393,22 +390,15 @@ def plot_generators(self): zorder = self.generator_zorder for generator, ray, color in zip(generators, self.rays, colors): if ray.dot_product(ray) < generator.dot_product(generator): - result += line([origin, ray], - color=color, thickness=thickness, - zorder=zorder, **extra_options) + result += line([origin, ray], color=color, thickness=thickness, zorder=zorder, **extra_options) else: # This should not be the case, but as of 4.6 plotting # functions are inconsistent and arrows behave very # different compared to lines. if d <= 2: - result += arrow(origin, generator, - color=color, width=thickness, - arrowsize=thickness + 1, - zorder=zorder, **extra_options) + result += arrow(origin, generator, color=color, width=thickness, arrowsize=thickness + 1, zorder=zorder, **extra_options) else: - result += line([origin, generator], arrow_head=True, - color=color, thickness=thickness, - zorder=zorder, **extra_options) + result += line([origin, generator], arrow_head=True, color=color, thickness=thickness, zorder=zorder, **extra_options) return result def plot_labels(self, labels, positions): @@ -441,9 +431,7 @@ def plot_labels(self, labels, positions): if label is None: continue if twod: - result += text(label, position, - color=color, fontsize=font_size, - zorder=zorder, **extra_options) + result += text(label, position, color=color, fontsize=font_size, zorder=zorder, **extra_options) else: result += text3d(label, position, color=color, **extra_options) return result @@ -467,19 +455,13 @@ def plot_lattice(self): return self.plot_points([self.origin]) d = self.dimension if d == 1: - points = ((x, 0) - for x in range(ceil(self.xmin), floor(self.xmax) + 1)) + points = ((x, 0) for x in range(ceil(self.xmin), floor(self.xmax) + 1)) elif d == 2: - points = ((x, y) - for x in range(ceil(self.xmin), floor(self.xmax) + 1) - for y in range(ceil(self.ymin), floor(self.ymax) + 1)) + points = ((x, y) for x in range(ceil(self.xmin), floor(self.xmax) + 1) for y in range(ceil(self.ymin), floor(self.ymax) + 1)) elif d == 3: - points = ((x, y, z) - for x in range(ceil(self.xmin), floor(self.xmax) + 1) - for y in range(ceil(self.ymin), floor(self.ymax) + 1) - for z in range(ceil(self.zmin), floor(self.zmax) + 1)) + points = ((x, y, z) for x in range(ceil(self.xmin), floor(self.xmax) + 1) for y in range(ceil(self.ymin), floor(self.ymax) + 1) for z in range(ceil(self.zmin), floor(self.zmax) + 1)) if self.mode == "round": - r = 1.01 * self.radius # To make sure integer values work OK. + r = 1.01 * self.radius # To make sure integer values work OK. points = (pt for pt in points if vector(pt).dot_product(vector(pt)) <= r) f = self.lattice_filter if f is not None: @@ -504,8 +486,7 @@ def plot_points(self, points): sage: tp.plot_points([(1,0), (0,1)]) # needs sage.plot Graphics object consisting of 1 graphics primitive """ - return point(points, color=self.point_color, size=self.point_size, - zorder=self.point_zorder, **self.extra_options) + return point(points, color=self.point_color, size=self.point_size, zorder=self.point_zorder, **self.extra_options) def plot_ray_labels(self): r""" @@ -526,8 +507,7 @@ def plot_ray_labels(self): sage: tp.plot_ray_labels() # needs sage.plot Graphics object consisting of 1 graphics primitive """ - return self.plot_labels(self.ray_label, - [1.1 * ray for ray in self.rays]) + return self.plot_labels(self.ray_label, [1.1 * ray for ray in self.rays]) def plot_rays(self): r""" @@ -555,9 +535,7 @@ def plot_rays(self): thickness = self.ray_thickness zorder = self.ray_zorder for end, color in zip(rays, colors): - result += line([origin, end], - color=color, thickness=thickness, - zorder=zorder, **extra_options) + result += line([origin, end], color=color, thickness=thickness, zorder=zorder, **extra_options) result += self.plot_ray_labels() return result @@ -603,29 +581,24 @@ def plot_walls(self, walls): zorder = self.wall_zorder if mode == "box": if self.dimension <= 2: - ieqs = [(self.xmax, -1, 0), (- self.xmin, 1, 0), - (self.ymax, 0, -1), (- self.ymin, 0, 1)] + ieqs = [(self.xmax, -1, 0), (-self.xmin, 1, 0), (self.ymax, 0, -1), (-self.ymin, 0, 1)] else: - ieqs = [(self.xmax, -1, 0, 0), (- self.xmin, 1, 0, 0), - (self.ymax, 0, -1, 0), (- self.ymin, 0, 1, 0), - (self.zmax, 0, 0, -1), (- self.zmin, 0, 0, 1)] + ieqs = [(self.xmax, -1, 0, 0), (-self.xmin, 1, 0, 0), (self.ymax, 0, -1, 0), (-self.ymin, 0, 1, 0), (self.zmax, 0, 0, -1), (-self.zmin, 0, 0, 1)] box = Polyhedron(ieqs=ieqs, base_ring=RDF) for wall, color in zip(walls, colors): - result += box.intersection(wall.polyhedron()).render_solid( - alpha=alpha, color=color, zorder=zorder, **extra_options) + result += box.intersection(wall.polyhedron()).render_solid(alpha=alpha, color=color, zorder=zorder, **extra_options) elif mode == "generators": origin = self.origin for wall, color in zip(walls, colors): vertices = [rays[i] for i in wall.ambient_ray_indices()] vertices.append(origin) - result += Polyhedron(vertices=vertices, base_ring=RDF).render_solid( - alpha=alpha, color=color, zorder=zorder, **extra_options) + result += Polyhedron(vertices=vertices, base_ring=RDF).render_solid(alpha=alpha, color=color, zorder=zorder, **extra_options) label_sectors = [] round = mode == "round" for wall, color in zip(walls, colors): S = wall.linear_subspace() lsd = S.dimension() - if lsd == 0: # Strictly convex wall + if lsd == 0: # Strictly convex wall r1, r2 = (rays[i] for i in wall.ambient_ray_indices()) elif lsd == 1: # wall is a half-plane for i, ray in zip(wall.ambient_ray_indices(), wall.rays()): @@ -635,9 +608,8 @@ def plot_walls(self, walls): r2 = rays[i] if round: # Plot one "extra" sector - result += sector(- r1, r2, - alpha=alpha, color=color, zorder=zorder, **extra_options) - else: # wall is a plane + result += sector(-r1, r2, alpha=alpha, color=color, zorder=zorder, **extra_options) + else: # wall is a plane r1, r2 = S.basis() r1 = vector(RDF, r1) r1 = r1 / r1.norm() * self.radius @@ -645,18 +617,13 @@ def plot_walls(self, walls): r2 = r2 / r2.norm() * self.radius if round: # Plot three "extra" sectors - result += sector(r1, - r2, - alpha=alpha, color=color, zorder=zorder, **extra_options) - result += sector(- r1, r2, - alpha=alpha, color=color, zorder=zorder, **extra_options) - result += sector(- r1, - r2, - alpha=alpha, color=color, zorder=zorder, **extra_options) + result += sector(r1, -r2, alpha=alpha, color=color, zorder=zorder, **extra_options) + result += sector(-r1, r2, alpha=alpha, color=color, zorder=zorder, **extra_options) + result += sector(-r1, -r2, alpha=alpha, color=color, zorder=zorder, **extra_options) label_sectors.append([r1, r2]) if round: - result += sector(r1, r2, - alpha=alpha, color=color, zorder=zorder, **extra_options) - result += self.plot_labels(self.wall_label, - [sum(label_sector) / 3 for label_sector in label_sectors]) + result += sector(r1, r2, alpha=alpha, color=color, zorder=zorder, **extra_options) + result += self.plot_labels(self.wall_label, [sum(label_sector) / 3 for label_sector in label_sectors]) return result def set_rays(self, generators): @@ -693,9 +660,8 @@ def set_rays(self, generators): self.generators = generators if self.mode == "box": rays = [] - bounds = [self.__dict__[bound] - for bound in ["xmin", "xmax", "ymin", "ymax", "zmin", "zmax"]] - bounds = bounds[:2 * d] + bounds = [self.__dict__[bound] for bound in ["xmin", "xmax", "ymin", "ymax", "zmin", "zmax"]] + bounds = bounds[: 2 * d] for gen in generators: factors = [] for i, gen_i in enumerate(gen): @@ -729,8 +695,7 @@ def _unrecognized_option(option): KeyError: "unrecognized toric plot option: 'nontoric'! Type 'toric_plotter.options?' to see available options." """ - raise KeyError("unrecognized toric plot option: '%s'! " % option - + "Type 'toric_plotter.options?' to see available options.") + raise KeyError("unrecognized toric plot option: '%s'! " % option + "Type 'toric_plotter.options?' to see available options.") def color_list(color, n): @@ -777,8 +742,7 @@ def color_list(color, n): except (ValueError, TypeError): if isinstance(color, (list, tuple)): if len(color) != n: - raise ValueError("expected %d colors, got %d!" - % (n, len(color))) + raise ValueError("expected %d colors, got %d!" % (n, len(color))) return color if color == "rainbow": return [Color(c) for c in rainbow(n, "rgbtuple")] @@ -1009,8 +973,7 @@ def options(option=None, **kwds): except KeyError: _unrecognized_option(option) else: - raise ValueError("you cannot specify 'option' and other arguments at " - "the same time!") + raise ValueError("you cannot specify 'option' and other arguments at " "the same time!") def reset_options(): @@ -1088,7 +1051,7 @@ def sector(ray1, ray2, **extra_options): phi1, phi2 = phi2, phi1 if phi2 - phi1 > pi: phi1, phi2 = phi2, phi1 + 2 * pi - return disk((0,0), r, (phi1, phi2), **extra_options) + return disk((0, 0), r, (phi1, phi2), **extra_options) # Plot a polygon, 30 vertices per radian. vertices_per_radian = 30 n = ceil(arccos(ray1 * ray2 / r**2) * vertices_per_radian) diff --git a/src/sage/geometry/triangulation/element.py b/src/sage/geometry/triangulation/element.py index 3ff2089abe9..680b7ead489 100644 --- a/src/sage/geometry/triangulation/element.py +++ b/src/sage/geometry/triangulation/element.py @@ -29,7 +29,7 @@ See :mod:`sage.geometry.triangulation.point_configuration` for more details. """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2010 Volker Braun # # This program is free software: you can redistribute it and/or modify @@ -37,7 +37,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.structure.richcmp import richcmp from sage.structure.element import Element @@ -71,11 +71,10 @@ def triangulation_render_2d(triangulation, **kwds): from sage.plot.point import point2d from sage.plot.line import line2d from sage.plot.polygon import polygon2d + points = [point.reduced_affine() for point in triangulation.point_configuration()] - coord = [ [p[0], p[1]] for p in points ] - plot_points = sum([ point2d(p, - zorder=2, pointsize=10, **kwds) - for p in coord ]) + coord = [[p[0], p[1]] for p in points] + plot_points = sum([point2d(p, zorder=2, pointsize=10, **kwds) for p in coord]) tmp_lines = [] for t in triangulation: @@ -93,21 +92,12 @@ def triangulation_render_2d(triangulation, **kwds): interior_lines.append(l) exterior_lines = [l for l in all_lines if l not in interior_lines] - plot_interior_lines = sum([ line2d([ coord[l[0]], coord[l[1]] ], - zorder=1, rgbcolor=(0,1,0), **kwds) - for l in interior_lines ]) - plot_exterior_lines = sum([ line2d([ coord[l[0]], coord[l[1]] ], - zorder=1, rgbcolor=(0,0,1), **kwds) - for l in exterior_lines ]) + plot_interior_lines = sum([line2d([coord[l[0]], coord[l[1]]], zorder=1, rgbcolor=(0, 1, 0), **kwds) for l in interior_lines]) + plot_exterior_lines = sum([line2d([coord[l[0]], coord[l[1]]], zorder=1, rgbcolor=(0, 0, 1), **kwds) for l in exterior_lines]) - plot_triangs = sum([ polygon2d([coord[t[0]], coord[t[1]], coord[t[2]]], - zorder=0, rgbcolor=(0.8, 1, 0.8), **kwds) - for t in triangulation if len(t) >= 3 ]) + plot_triangs = sum([polygon2d([coord[t[0]], coord[t[1]], coord[t[2]]], zorder=0, rgbcolor=(0.8, 1, 0.8), **kwds) for t in triangulation if len(t) >= 3]) - return \ - plot_points + \ - plot_interior_lines + plot_exterior_lines + \ - plot_triangs + return plot_points + plot_interior_lines + plot_exterior_lines + plot_triangs def triangulation_render_3d(triangulation, **kwds): @@ -131,11 +121,10 @@ def triangulation_render_3d(triangulation, **kwds): Graphics3d Object """ from sage.plot.plot3d.all import point3d, line3d, polygon3d - points = [ point.reduced_affine() for point in triangulation.point_configuration() ] - coord = [ [p[0], p[1], p[2] ] for p in points ] - plot_points = sum([ point3d(p, size=15, - **kwds) - for p in coord ]) + + points = [point.reduced_affine() for point in triangulation.point_configuration()] + coord = [[p[0], p[1], p[2]] for p in points] + plot_points = sum([point3d(p, size=15, **kwds) for p in coord]) tmp_lines = [] for t in triangulation: @@ -158,17 +147,14 @@ def triangulation_render_3d(triangulation, **kwds): exterior_lines = [l for l in all_lines if l not in interior_lines] from sage.plot.plot3d.texture import Texture + line_int = Texture(color='darkblue', ambient=1, diffuse=0) line_ext = Texture(color='green', ambient=1, diffuse=0) triang_int = Texture(opacity=0.3, specular=0, shininess=0, diffuse=0, ambient=1, color='yellow') triang_ext = Texture(opacity=0.6, specular=0, shininess=0, diffuse=0, ambient=1, color='green') - plot_interior_lines = sum([ line3d([ coord[l[0]], coord[l[1]] ], - thickness=2, texture=line_int, **kwds) - for l in interior_lines ]) - plot_exterior_lines = sum([ line3d([ coord[l[0]], coord[l[1]] ], - thickness=3, texture=line_ext, **kwds) - for l in exterior_lines ]) + plot_interior_lines = sum([line3d([coord[l[0]], coord[l[1]]], thickness=2, texture=line_int, **kwds) for l in interior_lines]) + plot_exterior_lines = sum([line3d([coord[l[0]], coord[l[1]]], thickness=3, texture=line_ext, **kwds) for l in exterior_lines]) tmp_triangs = [] for t in triangulation: @@ -187,18 +173,10 @@ def triangulation_render_3d(triangulation, **kwds): interior_triangs.append(l) exterior_triangs = [l for l in all_triangs if l not in interior_triangs] - plot_interior_triangs = \ - sum([polygon3d([coord[t[0]], coord[t[1]], coord[t[2]]], - texture=triang_int, **kwds) - for t in interior_triangs]) - plot_exterior_triangs = \ - sum([polygon3d([coord[t[0]], coord[t[1]], coord[t[2]]], - texture=triang_ext, **kwds) - for t in exterior_triangs]) + plot_interior_triangs = sum([polygon3d([coord[t[0]], coord[t[1]], coord[t[2]]], texture=triang_int, **kwds) for t in interior_triangs]) + plot_exterior_triangs = sum([polygon3d([coord[t[0]], coord[t[1]], coord[t[2]]], texture=triang_ext, **kwds) for t in exterior_triangs]) - return plot_points + \ - plot_interior_lines + plot_exterior_lines + \ - plot_interior_triangs + plot_exterior_triangs + return plot_points + plot_interior_lines + plot_exterior_lines + plot_interior_triangs + plot_exterior_triangs ######################################################################## @@ -216,6 +194,7 @@ class Triangulation(Element): :meth:`~sage.geometry.triangulation.point_configuration.PointConfiguration.triangulations` to triangulate point configurations. """ + def __init__(self, triangulation, parent, check=True): """ The constructor of a ``Triangulation`` object. @@ -258,12 +237,10 @@ def __init__(self, triangulation, parent, check=True): self._point_configuration = parent try: - triangulation = tuple(sorted( tuple(sorted(t)) for t in triangulation)) + triangulation = tuple(sorted(tuple(sorted(t)) for t in triangulation)) except TypeError: - triangulation = tuple( self.point_configuration().int_to_simplex(i) - for i in triangulation ) - assert not check or all( len(t) == self.point_configuration().dim()+1 - for t in triangulation) + triangulation = tuple(self.point_configuration().int_to_simplex(i) for i in triangulation) + assert not check or all(len(t) == self.point_configuration().dim() + 1 for t in triangulation) self._triangulation = triangulation def point_configuration(self): @@ -385,11 +362,11 @@ def _repr_(self): sage: next(t)._repr_() '(<1,4,5>, <2,4,5>)' """ - #s = 'A triangulation' - #s += ' in QQ^'+str(self.point_configuration().ambient_dim()) - #s += ' consisting of '+str(len(self))+' simplices.' + # s = 'A triangulation' + # s += ' in QQ^'+str(self.point_configuration().ambient_dim()) + # s += ' consisting of '+str(len(self))+' simplices.' s = '(' - s += ', '.join([ '<'+','.join(map(str,t))+'>' for t in self._triangulation]) + s += ', '.join(['<' + ','.join(map(str, t)) + '>' for t in self._triangulation]) s += ')' return s @@ -414,7 +391,7 @@ def plot(self, **kwds): if dim == 3: return triangulation_render_3d(self, **kwds) - raise NotImplementedError('Plotting '+str(dim)+'-dimensional triangulations not implemented!') + raise NotImplementedError('Plotting ' + str(dim) + '-dimensional triangulations not implemented!') def gkz_phi(self): r""" @@ -488,7 +465,7 @@ def enumerate_simplices(self): <4,6,9,10,11,12>, <4,6,10,11,12,13>) """ pc = self._point_configuration - return tuple( pc.simplex_to_int(t) for t in self ) + return tuple(pc.simplex_to_int(t) for t in self) def fan(self, origin=None): r""" @@ -540,6 +517,7 @@ def fan(self, origin=None): in 3-d lattice N """ from sage.geometry.fan import Fan + if origin is None: origin = self.point_configuration().star_center() R = self.base_ring() @@ -566,6 +544,7 @@ def simplicial_complex(self): {0: 0, 1: 0, 2: 0, 3: 0} """ from sage.topology.simplicial_complex import SimplicialComplex + return SimplicialComplex(self) @cached_method @@ -607,7 +586,7 @@ def _boundary_simplex_dictionary(self): result = dict() for simplex in self: for i in range(len(simplex)): - facet = simplex[:i] + simplex[i+1:] + facet = simplex[:i] + simplex[i + 1 :] result[facet] = result.get(facet, tuple()) + (simplex,) return result @@ -643,9 +622,7 @@ def boundary(self): sage: triangulation.interior_facets() frozenset({(0, 1, 7), (0, 2, 7), (0, 3, 7), (0, 4, 7), (0, 5, 7), (1, 5, 7)}) """ - return frozenset(facet for facet, bounded_simplices - in self._boundary_simplex_dictionary().items() - if len(bounded_simplices) == 1) + return frozenset(facet for facet, bounded_simplices in self._boundary_simplex_dictionary().items() if len(bounded_simplices) == 1) @cached_method def boundary_simplicial_complex(self): @@ -674,6 +651,7 @@ def boundary_simplicial_complex(self): True """ from sage.topology.simplicial_complex import SimplicialComplex + return SimplicialComplex(self.boundary(), maximality_check=False) @cached_method @@ -708,9 +686,7 @@ def interior_facets(self): sage: triangulation.interior_facets() frozenset({(0, 1, 7), (0, 2, 7), (0, 3, 7), (0, 4, 7), (0, 5, 7), (1, 5, 7)}) """ - return frozenset(facet for facet, bounded_simplices - in self._boundary_simplex_dictionary().items() - if len(bounded_simplices) == 2) + return frozenset(facet for facet, bounded_simplices in self._boundary_simplex_dictionary().items() if len(bounded_simplices) == 2) def polyhedral_complex(self, **kwds): """ @@ -739,14 +715,10 @@ def polyhedral_complex(self, **kwds): """ from sage.geometry.polyhedral_complex import PolyhedralComplex from sage.geometry.polyhedron.constructor import Polyhedron + ambient_dim = self.point_configuration().ambient_dim() points = self.point_configuration().points() - return PolyhedralComplex([Polyhedron(vertices=[points[i] for i in simplex]) - for simplex in self], - ambient_dim=ambient_dim, - maximality_check=False, - face_to_face_check=False, - **kwds) + return PolyhedralComplex([Polyhedron(vertices=[points[i] for i in simplex]) for simplex in self], ambient_dim=ambient_dim, maximality_check=False, face_to_face_check=False, **kwds) def boundary_polyhedral_complex(self, **kwds): r""" @@ -787,14 +759,10 @@ def boundary_polyhedral_complex(self, **kwds): """ from sage.geometry.polyhedral_complex import PolyhedralComplex from sage.geometry.polyhedron.constructor import Polyhedron + ambient_dim = self.point_configuration().ambient_dim() points = self.point_configuration().points() - return PolyhedralComplex([Polyhedron(vertices=[points[i] for i in simplex]) - for simplex in self.boundary()], - ambient_dim=ambient_dim, - maximality_check=False, - face_to_face_check=False, - **kwds) + return PolyhedralComplex([Polyhedron(vertices=[points[i] for i in simplex]) for simplex in self.boundary()], ambient_dim=ambient_dim, maximality_check=False, face_to_face_check=False, **kwds) @cached_method def normal_cone(self): @@ -853,6 +821,7 @@ def normal_cone(self): from ppl import Constraint_System, Linear_Expression, C_Polyhedron from sage.matrix.constructor import matrix from sage.arith.functions import lcm + pc = self.point_configuration() cs = Constraint_System() for facet in self.interior_facets(): @@ -861,24 +830,26 @@ def normal_cone(self): q = set(s1).difference(facet).pop() origin = pc.point(p).reduced_affine_vector() base_indices = [i for i in s0 if i != p] - base = matrix([ pc.point(i).reduced_affine_vector()-origin for i in base_indices ]) - sol = base.solve_left( pc.point(q).reduced_affine_vector()-origin ) - relation = [0]*pc.n_points() - relation[p] = sum(sol)-1 + base = matrix([pc.point(i).reduced_affine_vector() - origin for i in base_indices]) + sol = base.solve_left(pc.point(q).reduced_affine_vector() - origin) + relation = [0] * pc.n_points() + relation[p] = sum(sol) - 1 relation[q] = 1 for i, base_i in enumerate(base_indices): relation[base_i] = -sol[i] rel_denom = lcm([QQ(r).denominator() for r in relation]) - relation = [ ZZ(r*rel_denom) for r in relation ] - ex = Linear_Expression(relation,0) + relation = [ZZ(r * rel_denom) for r in relation] + ex = Linear_Expression(relation, 0) cs.insert(ex >= 0) from sage.modules.free_module import FreeModule + ambient = FreeModule(ZZ, self.point_configuration().n_points()) if cs.empty(): cone = C_Polyhedron(ambient.dimension(), 'universe') else: cone = C_Polyhedron(cs) from sage.geometry.cone import _Cone_from_PPL + return _Cone_from_PPL(cone, lattice=ambient) def adjacency_graph(self): @@ -911,5 +882,5 @@ def adjacency_graph(self): """ vertices = [Set(_) for _ in list(self)] from sage.graphs.graph import Graph - return Graph([vertices, - lambda x,y: len(x-y) == 1]) + + return Graph([vertices, lambda x, y: len(x - y) == 1]) diff --git a/src/sage/geometry/triangulation/point_configuration.py b/src/sage/geometry/triangulation/point_configuration.py index 5b00e3aff6b..1d1a059faeb 100644 --- a/src/sage/geometry/triangulation/point_configuration.py +++ b/src/sage/geometry/triangulation/point_configuration.py @@ -192,8 +192,7 @@ from sage.rings.rational_field import QQ from sage.structure.unique_representation import UniqueRepresentation -from sage.geometry.triangulation.base import \ - PointConfiguration_base, Point, ConnectedTriangulationsIterator +from sage.geometry.triangulation.base import PointConfiguration_base, Point, ConnectedTriangulationsIterator from sage.geometry.triangulation.element import Triangulation @@ -280,11 +279,9 @@ def _have_TOPCOM(cls): return PointConfiguration._have_TOPCOM_cached try: - out = next(PointConfiguration._TOPCOM_exec('points2placingtriang', - '[[0,1],[1,1]]', verbose=False)) + out = next(PointConfiguration._TOPCOM_exec('points2placingtriang', '[[0,1],[1,1]]', verbose=False)) PointConfiguration._have_TOPCOM_cached = True - assert out == '{{0,1}}',\ - 'TOPCOM ran but did not produce the correct output!' + assert out == '{{0,1}}', 'TOPCOM ran but did not produce the correct output!' except (FeatureNotPresentError, pexpect.ExceptionPexpect): PointConfiguration._have_TOPCOM_cached = False @@ -305,22 +302,21 @@ def __classcall__(cls, points, projective=False, connected=True, fine=False, reg """ if isinstance(points, PointConfiguration_base): pc = points - points = tuple( p.projective() for p in points ) + points = tuple(p.projective() for p in points) projective = True defined_affine = pc.is_affine() elif projective: - points = tuple( tuple(p) for p in points ) + points = tuple(tuple(p) for p in points) defined_affine = False else: - points = tuple( tuple(p)+(1,) for p in points ) + points = tuple(tuple(p) + (1,) for p in points) defined_affine = True if star is not None and star not in ZZ: star_point = tuple(star) if len(star_point) < len(points[0]): - star_point = tuple(star)+(1,) + star_point = tuple(star) + (1,) star = points.index(star_point) - return super().__classcall__(cls, points, connected, fine, - regular, star, defined_affine) + return super().__classcall__(cls, points, connected, fine, regular, star, defined_affine) def __init__(self, points, connected, fine, regular, star, defined_affine): """ @@ -384,9 +380,9 @@ def set_engine(cls, engine='auto'): """ engine = engine.lower() if engine not in ['auto', 'topcom', 'internal']: - raise ValueError('Unknown value for "engine": '+str(engine)) + raise ValueError('Unknown value for "engine": ' + str(engine)) - PointConfiguration._use_TOPCOM = (engine == 'topcom') + PointConfiguration._use_TOPCOM = engine == 'topcom' def star_center(self): r""" @@ -441,12 +437,10 @@ def __reduce__(self): True """ if self.is_affine(): - points = tuple( p.affine() for p in self ) - return (PointConfiguration, (points, False, - self._connected, self._fine, self._regular, self._star)) - points = tuple( p.projective() for p in self ) - return (PointConfiguration, (points, True, - self._connected, self._fine, self._regular, self._star)) + points = tuple(p.affine() for p in self) + return (PointConfiguration, (points, False, self._connected, self._fine, self._regular, self._star)) + points = tuple(p.projective() for p in self) + return (PointConfiguration, (points, True, self._connected, self._fine, self._regular, self._star)) def an_element(self): """ @@ -524,11 +518,11 @@ def _repr_(self): s += ' affine' else: s += ' projective' - s += " %s-space over %s" % (self.ambient_dim(),self.base_ring()) + s += " %s-space over %s" % (self.ambient_dim(), self.base_ring()) if len(self) == 1: - s += ' consisting of '+str(len(self))+' point. ' + s += ' consisting of ' + str(len(self)) + ' point. ' else: - s += ' consisting of '+str(len(self))+' points. ' + s += ' consisting of ' + str(len(self)) + ' points. ' s += 'The triangulations of this point configuration are assumed to be' @@ -544,7 +538,7 @@ def _repr_(self): if self._regular: s += ' regular' - elif self._regular is False: # may be False or None, with different meanings + elif self._regular is False: # may be False or None, with different meanings s += ' irregular' else: s += ' not necessarily regular' @@ -552,7 +546,7 @@ def _repr_(self): if self._star is None: s += '.' else: - s += ', and star with center '+str(self.star_center())+'.' + s += ', and star with center ' + str(self.star_center()) + '.' if self.n_points() == 0: s = 'The pointless empty configuration' return s @@ -569,9 +563,7 @@ def _TOPCOM_points(self): '[[0,0,0,1],[-2,0,0,1],[0,-2,0,1],[-2,-2,0,1],[0,0,-2,1]]' """ s = '[' - s += ','.join([ - '[' + ','.join(map(str,p.reduced_projective())) + ']' - for p in self ]) + s += ','.join(['[' + ','.join(map(str, p.reduced_projective())) + ']' for p in self]) s += ']' return s @@ -670,16 +662,14 @@ def _TOPCOM_communicate(self, executable, verbose=True): ####################### [(<0,1,2,4>, <1,2,3,4>)] """ - for line in self._TOPCOM_exec(executable, - self._TOPCOM_points(), verbose): - triangulation = line[ line.find('{{')+2 : line.rfind('}}') ] + for line in self._TOPCOM_exec(executable, self._TOPCOM_points(), verbose): + triangulation = line[line.find('{{') + 2 : line.rfind('}}')] triangulation = triangulation.split('},{') - triangulation = [ [ QQ(t) for t in triangle.split(',') ] - for triangle in triangulation ] + triangulation = [[QQ(t) for t in triangle.split(',')] for triangle in triangulation] if self._star is not None: o = self._star - if not all( t.count(o) > 0 for t in triangulation): + if not all(t.count(o) > 0 for t in triangulation): continue yield self(triangulation) @@ -744,9 +734,7 @@ def _TOPCOM_triangulate(self, verbose=True): [(0, 1, 2), (0, 1, 4), (0, 2, 4), (1, 2, 3)] sage: p.set_engine('internal') """ - assert self._regular is not False, \ - 'When asked for a single triangulation TOPCOM ' + \ - 'always returns a regular triangulation.' + assert self._regular is not False, 'When asked for a single triangulation TOPCOM ' + 'always returns a regular triangulation.' command = "points2" if self._fine: @@ -793,11 +781,7 @@ def restrict_to_regular_triangulations(self, regular=True): True sage: PointConfiguration.set_engine('internal') """ - return PointConfiguration(self, - connected=self._connected, - fine=self._fine, - regular=regular, - star=self._star) + return PointConfiguration(self, connected=self._connected, fine=self._fine, regular=regular, star=self._star) def restrict_to_connected_triangulations(self, connected=True): """ @@ -837,11 +821,7 @@ def restrict_to_connected_triangulations(self, connected=True): True sage: PointConfiguration.set_engine('internal') """ - return PointConfiguration(self, - connected=connected, - fine=self._fine, - regular=self._regular, - star=self._star) + return PointConfiguration(self, connected=connected, fine=self._fine, regular=self._regular, star=self._star) def restrict_to_fine_triangulations(self, fine=True): """ @@ -874,11 +854,7 @@ def restrict_to_fine_triangulations(self, fine=True): sage: p == p_fine.restrict_to_fine_triangulations(fine=False) True """ - return PointConfiguration(self, - connected=self._connected, - fine=fine, - regular=self._regular, - star=self._star) + return PointConfiguration(self, connected=self._connected, fine=fine, regular=self._regular, star=self._star) def restrict_to_star_triangulations(self, star): """ @@ -914,11 +890,7 @@ def restrict_to_star_triangulations(self, star): sage: p == p_star.restrict_to_star_triangulations(star=None) True """ - return PointConfiguration(self, - connected=self._connected, - fine=self._fine, - regular=self._regular, - star=star) + return PointConfiguration(self, connected=self._connected, fine=self._fine, regular=self._regular, star=star) def triangulations(self, verbose=False): r""" @@ -987,7 +959,7 @@ def triangulations(self, verbose=False): else: if not self._connected: raise ValueError('Need TOPCOM to find disconnected triangulations.') - if (self._regular is not None): + if self._regular is not None: raise ValueError('Need TOPCOM to test for regularity.') ci = ConnectedTriangulationsIterator(self, star=self._star, fine=self._fine) for encoded_triangulation in ci: @@ -1088,6 +1060,7 @@ def convex_hull(self): pass from sage.geometry.polyhedron.constructor import Polyhedron + pts = [p.reduced_affine() for p in self.points()] self._polyhedron = Polyhedron(vertices=pts) return self._polyhedron @@ -1142,8 +1115,8 @@ def restricted_automorphism_group(self): sage: DihedralGroup(1).is_isomorphic(_) # needs sage.graphs sage.groups True """ - v_list = [ vector(p.projective()) for p in self ] - Qinv = sum( v.column() * v.row() for v in v_list ).inverse() + v_list = [vector(p.projective()) for p in self] + Qinv = sum(v.column() * v.row() for v in v_list).inverse() # construct the graph from sage.graphs.graph import Graph @@ -1153,10 +1126,10 @@ def restricted_automorphism_group(self): # the backends are fixed. G = Graph(sparse=True) for i in range(len(v_list)): - for j in range(i+1,len(v_list)): + for j in range(i + 1, len(v_list)): v_i = v_list[i] v_j = v_list[j] - G.add_edge(i+1,j+1, v_i * Qinv * v_j) + G.add_edge(i + 1, j + 1, v_i * Qinv * v_j) return G.automorphism_group(edge_labels=True) @@ -1190,8 +1163,8 @@ def face_codimension(self, point): inequalities = [] for ieq in self.convex_hull().inequality_generator(): - if (ieq.A()*p + ieq.b() == 0): - inequalities += [ ieq.vector() ] + if ieq.A() * p + ieq.b() == 0: + inequalities += [ieq.vector()] return matrix(inequalities).rank() def face_interior(self, dim=None, codim=None): @@ -1210,9 +1183,9 @@ def face_interior(self, dim=None, codim=None): """ assert not (dim is not None and codim is not None), "You cannot specify both dim and codim." - if (dim is not None): - return self.face_interior()[self.convex_hull().dim()-dim] - if (codim is not None): + if dim is not None: + return self.face_interior()[self.convex_hull().dim() - dim] + if codim is not None: return self.face_interior()[codim] try: @@ -1220,10 +1193,9 @@ def face_interior(self, dim=None, codim=None): except AttributeError: pass - d = [ self.face_codimension(i) for i in range(self.n_points()) ] + d = [self.face_codimension(i) for i in range(self.n_points())] - return tuple( tuple(i for i in range(self.n_points()) if d[i] == codim ) - for codim in range(self.dim()+1) ) + return tuple(tuple(i for i in range(self.n_points()) if d[i] == codim) for codim in range(self.dim() + 1)) def exclude_points(self, point_idx_list): """ @@ -1251,14 +1223,8 @@ def exclude_points(self, point_idx_list): sage: p.exclude_points(p.face_interior(codim=1)).points() (P(-1, 0), P(0, 0), P(1, -1), P(1, 1)) """ - points = [self.point(i) for i in range(self.n_points()) - if i not in point_idx_list] - return PointConfiguration(points, - projective=False, - connected=self._connected, - fine=self._fine, - regular=self._regular, - star=self._star) + points = [self.point(i) for i in range(self.n_points()) if i not in point_idx_list] + return PointConfiguration(points, projective=False, connected=self._connected, fine=self._fine, regular=self._regular, star=self._star) def volume(self, simplex=None): """ @@ -1299,13 +1265,13 @@ def volume(self, simplex=None): things so that the volume of the standard `n`-simplex is 1. See [GKZ1994]_ page 182. """ - if (simplex is None): - return sum([ self.volume(s) for s in self.triangulate() ]) + if simplex is None: + return sum([self.volume(s) for s in self.triangulate()]) - #Form a matrix whose columns are the points of simplex - #with the first point of simplex shifted to the origin. - v = [ self.point(i).reduced_affine_vector() for i in simplex ] - m = matrix([ v_i - v[0] for v_i in v[1:] ]) + # Form a matrix whose columns are the points of simplex + # with the first point of simplex shifted to the origin. + v = [self.point(i).reduced_affine_vector() for i in simplex] + m = matrix([v_i - v[0] for v_i in v[1:]]) return abs(m.det()) def secondary_polytope(self): @@ -1352,9 +1318,10 @@ def secondary_polytope(self): An inequality (0, 0, 0, 3, 2) x - 14 >= 0) """ from sage.geometry.polyhedron.constructor import Polyhedron - #TODO: once restriction to regular triangulations is fixed, - #change the next line to only take the regular triangulations, - #since they are the vertices of the secondary polytope anyway. + + # TODO: once restriction to regular triangulations is fixed, + # change the next line to only take the regular triangulations, + # since they are the vertices of the secondary polytope anyway. l = self.triangulations_list() return Polyhedron(vertices=[x.gkz_phi() for x in l]) @@ -1390,10 +1357,10 @@ def circuits_support(self): supports_knext = set() possible_dependency = set() for indep in independent_k: - indep_plus_one = [ tuple(sorted(indep+(i,))) for i in (I-set(indep)) ] + indep_plus_one = [tuple(sorted(indep + (i,))) for i in (I - set(indep))] possible_dependency.update(indep_plus_one) for supp in supports_k: - supp_plus_one = [ tuple(sorted(supp+(i,))) for i in (I-set(supp)) ] + supp_plus_one = [tuple(sorted(supp + (i,))) for i in (I - set(supp))] possible_dependency.difference_update(supp_plus_one) supports_knext.update(supp_plus_one) @@ -1401,7 +1368,7 @@ def circuits_support(self): supports_k = list(supports_knext) independent_k = [] for idx in possible_dependency: - rk = matrix([ U[i] for i in idx ]).rank() + rk = matrix([U[i] for i in idx]).rank() if rk == k: independent_k.append(idx) else: @@ -1468,13 +1435,13 @@ def circuits(self): Circuits = () for support in self.circuits_support(): - m = matrix([ U[i] for i in support ]).transpose() + m = matrix([U[i] for i in support]).transpose() ker = m.right_kernel().basis()[0] assert len(ker) == len(support) - Cplus = [ support[i] for i in range(len(support)) if ker[i] > 0 ] - Cminus = [ support[i] for i in range(len(support)) if ker[i] < 0 ] - Czero = set( range(n) ).difference(support) - Circuits += ( (tuple(Cplus), tuple(Czero), tuple(Cminus)), ) + Cplus = [support[i] for i in range(len(support)) if ker[i] > 0] + Cminus = [support[i] for i in range(len(support)) if ker[i] < 0] + Czero = set(range(n)).difference(support) + Circuits += ((tuple(Cplus), tuple(Czero), tuple(Cminus)),) self._circuits = Circuits return Circuits @@ -1506,9 +1473,9 @@ def positive_circuits(self, *negative): Cpos = circuit[0] Cneg = circuit[2] if Cpos == negative: - pos += ( Cneg, ) + pos += (Cneg,) elif Cneg == negative: - pos += ( Cpos, ) + pos += (Cpos,) return pos def bistellar_flips(self): @@ -1551,12 +1518,9 @@ def bistellar_flips(self): for C in self.circuits(): Cpos = list(C[0]) Cneg = list(C[2]) - Tpos = [Cpos + Cneg[0:i] + Cneg[i+1:len(Cneg)] - for i in range(len(Cneg))] - Tneg = [Cneg + Cpos[0:i] + Cpos[i+1:len(Cpos)] - for i in range(len(Cpos))] - flips.append((self.element_class(Tpos, parent=self, check=False), - self.element_class(Tneg, parent=self, check=False))) + Tpos = [Cpos + Cneg[0:i] + Cneg[i + 1 : len(Cneg)] for i in range(len(Cneg))] + Tneg = [Cneg + Cpos[0:i] + Cpos[i + 1 : len(Cpos)] for i in range(len(Cpos))] + flips.append((self.element_class(Tpos, parent=self, check=False), self.element_class(Tneg, parent=self, check=False))) return tuple(flips) def lexicographic_triangulation(self): @@ -1604,19 +1568,19 @@ def lexicographic_triangulation(self): else: lex_supp.add(Cminus) - lex_supp = sorted(lex_supp, key=lambda x:-len(x)) + lex_supp = sorted(lex_supp, key=lambda x: -len(x)) basepts = copy(lex_supp) - for i in range(len(lex_supp)-1): - for j in range(i+1,len(lex_supp)): + for i in range(len(lex_supp) - 1): + for j in range(i + 1, len(lex_supp)): if set(lex_supp[j]).issubset(set(lex_supp[i])): try: basepts.remove(lex_supp[i]) except ValueError: pass - basepts = [ (len(b),)+b for b in basepts ] # decorate - basepts = sorted(basepts) # sort - basepts = [ b[1:] for b in basepts ] # undecorate + basepts = [(len(b),) + b for b in basepts] # decorate + basepts = sorted(basepts) # sort + basepts = [b[1:] for b in basepts] # undecorate def make_cotriang(basepts): if len(basepts) == 0: @@ -1624,7 +1588,7 @@ def make_cotriang(basepts): triangulation = set() for tail in make_cotriang(basepts[1:]): for head in basepts[0]: - triangulation.update([ frozenset([head]).union(tail) ]) + triangulation.update([frozenset([head]).union(tail)]) nonminimal = set() for rel in itertools.combinations(triangulation, 2): @@ -1634,15 +1598,15 @@ def make_cotriang(basepts): nonminimal.update([rel[0]]) triangulation.difference_update(nonminimal) - triangulation = [ [len(t)]+sorted(t) for t in triangulation ] # decorate - triangulation = sorted(triangulation) # sort - triangulation = [ frozenset(t[1:]) for t in triangulation ] # undecorate + triangulation = [[len(t)] + sorted(t) for t in triangulation] # decorate + triangulation = sorted(triangulation) # sort + triangulation = [frozenset(t[1:]) for t in triangulation] # undecorate return triangulation triangulation = make_cotriang(basepts) I = frozenset(range(self.n_points())) - triangulation = [ tuple(I.difference(t)) for t in triangulation ] + triangulation = [tuple(I.difference(t)) for t in triangulation] return self(triangulation) @@ -1678,7 +1642,7 @@ def distance_affine(self, x, y): self._assert_is_affine() d = 0 for xi, yi in zip(x.projective(), y.projective()): - d += (xi-yi)**2 + d += (xi - yi) ** 2 return d @cached_method @@ -1713,10 +1677,10 @@ def distance_FS(self, x, y): """ x2 = y2 = xy = 0 for xi, yi in zip(x.projective(), y.projective()): - x2 += xi*xi - y2 += yi*yi - xy += xi*yi - return 1-xy*xy/(x2*y2) + x2 += xi * xi + y2 += yi * yi + xy += xi * yi + return 1 - xy * xy / (x2 * y2) @cached_method def distance(self, x, y): @@ -1747,8 +1711,8 @@ def distance(self, x, y): [0, 1/2, 5/6, 5/6, 1/2] """ if self.is_affine(): - return self.distance_affine(x,y) - return self.distance_FS(x,y) + return self.distance_affine(x, y) + return self.distance_FS(x, y) def farthest_point(self, points, among=None): """ @@ -1783,9 +1747,9 @@ def farthest_point(self, points, among=None): continue if p_max is None: p_max = p - d_max = min(self.distance(p,q) for q in points) + d_max = min(self.distance(p, q) for q in points) continue - d = min(self.distance(p,q) for q in points) + d = min(self.distance(p, q) for q in points) if d > d_max: p_max = p return p_max @@ -1952,8 +1916,7 @@ def facets_of_simplex(simplex): simplex = list(simplex) origin = simplex[0] rest = simplex[1:] - span = matrix([origin.reduced_affine_vector()-p.reduced_affine_vector() - for p in rest]) + span = matrix([origin.reduced_affine_vector() - p.reduced_affine_vector() for p in rest]) # span.inverse() linearly transforms the simplex into the unit simplex normals = span.inverse().columns() facets = [] @@ -1979,8 +1942,7 @@ def facets_of_simplex(simplex): point_order = list(self.points()) elif isinstance(point_order[0], Point): point_order = list(point_order) - assert all(p.point_configuration() is self for p in point_order),\ - "Some point in 'point_order' does not belong to the PointConfiguration." + assert all(p.point_configuration() is self for p in point_order), "Some point in 'point_order' does not belong to the PointConfiguration." else: point_order = [self.point(i) for i in point_order] @@ -2111,7 +2073,7 @@ def Gale_transform(self, points=None, homogenize=True): points = self.points() else: try: - points = [ self.point(ZZ(i)) for i in points ] + points = [self.point(ZZ(i)) for i in points] except TypeError: pass if homogenize: @@ -2218,6 +2180,7 @@ def deformation_cone(self, collection): 2.2 of [ACEP2020]. """ from sage.geometry.polyhedron.constructor import Polyhedron + gale = self.Gale_transform(homogenize=False) dual_rays = gale.columns() n = self.n_points() @@ -2226,7 +2189,7 @@ def deformation_cone(self, collection): dual_cone = Polyhedron(rays=[dual_rays[i] for i in range(n) if i not in cone_indices]) K = K.intersection(dual_cone) if K is not None else dual_cone preimages = [gale.solve_right(r.vector()) for r in K.rays()] - return Polyhedron(lines=matrix(self.points()).transpose().rows(),rays=preimages) + return Polyhedron(lines=matrix(self.points()).transpose().rows(), rays=preimages) def plot(self, **kwds): r""" diff --git a/src/sage/geometry/voronoi_diagram.py b/src/sage/geometry/voronoi_diagram.py index 73b65248afe..b46a6caef1d 100644 --- a/src/sage/geometry/voronoi_diagram.py +++ b/src/sage/geometry/voronoi_diagram.py @@ -85,6 +85,7 @@ class VoronoiDiagram(SageObject): - Moritz Firsching (2012-09-21) """ + def __init__(self, points): r""" See ``VoronoiDiagram`` for full documentation. @@ -103,19 +104,15 @@ def __init__(self, points): self._base_ring = self._points.base_ring() elif isinstance(self._points.base_ring(), sage.rings.abc.RealField): from sage.rings.real_double import RDF + self._base_ring = RDF - self._points = PointConfiguration([[RDF(cor) for cor in poi] - for poi in self._points]) + self._points = PointConfiguration([[RDF(cor) for cor in poi] for poi in self._points]) else: - raise NotImplementedError('Base ring of the Voronoi diagram must ' - 'be one of QQ, RDF, AA.') + raise NotImplementedError('Base ring of the Voronoi diagram must ' 'be one of QQ, RDF, AA.') if self._n > 0: self._d = self._points.ambient_dim() - e = [([sum(vector(i)[k] ** 2 - for k in range(self._d))] + - [(-2) * vector(i)[l] for l in range(self._d)] + [1]) - for i in self._points] + e = [([sum(vector(i)[k] ** 2 for k in range(self._d))] + [(-2) * vector(i)[l] for l in range(self._d)] + [1]) for i in self._points] # we attach hyperplane to the paraboloid e = [[self._base_ring(i) for i in k] for k in e] @@ -145,15 +142,10 @@ def __init__(self, points): equ = p.Hrepresentation(hlistnormalized.index(enormalized[i])) else: equ = p.Hrepresentation(i) - pvert = [[u[k] for k in range(self._d)] for u in equ.incident() - if u.is_vertex()] - prays = [[u[k] for k in range(self._d)] for u in equ.incident() - if u.is_ray()] - pline = [[u[k] for k in range(self._d)] for u in equ.incident() - if u.is_line()] - (self._P)[self._points[i]] = Polyhedron(vertices=pvert, - lines=pline, rays=prays, - base_ring=self._base_ring) + pvert = [[u[k] for k in range(self._d)] for u in equ.incident() if u.is_vertex()] + prays = [[u[k] for k in range(self._d)] for u in equ.incident() if u.is_ray()] + pline = [[u[k] for k in range(self._d)] for u in equ.incident() if u.is_line()] + (self._P)[self._points[i]] = Polyhedron(vertices=pvert, lines=pline, rays=prays, base_ring=self._base_ring) def points(self): r""" @@ -289,6 +281,7 @@ def plot(self, cell_colors=None, **kwds): if cell_colors is None: from random import shuffle + cell_colors = rainbow(self._n) shuffle(cell_colors) else: @@ -300,9 +293,7 @@ def plot(self, cell_colors=None, **kwds): S += point(p, color=col, pointsize=10, zorder=3) S += point(p, color='black', pointsize=20, zorder=2) return plot(S, **kwds) - raise NotImplementedError('Plotting of ' + str(self.ambient_dim()) + - '-dimensional Voronoi diagrams not' + - ' implemented') + raise NotImplementedError('Plotting of ' + str(self.ambient_dim()) + '-dimensional Voronoi diagrams not' + ' implemented') def _are_points_in_regions(self): """ diff --git a/src/sage/graphs/all.py b/src/sage/graphs/all.py index a42a1d7210f..1684a5d44eb 100644 --- a/src/sage/graphs/all.py +++ b/src/sage/graphs/all.py @@ -1,11 +1,9 @@ - from sage.misc.lazy_import import lazy_import lazy_import("sage.graphs.graph_generators", "graphs") lazy_import("sage.graphs.digraph_generators", "digraphs") lazy_import("sage.graphs.hypergraph_generators", "hypergraphs") -lazy_import("sage.graphs.graph_database", [ - "GraphDatabase", "GenericGraphQuery", "GraphQuery"]) +lazy_import("sage.graphs.graph_database", ["GraphDatabase", "GenericGraphQuery", "GraphQuery"]) from sage.graphs.graph import Graph from sage.graphs.digraph import DiGraph from sage.graphs.bipartite_graph import BipartiteGraph @@ -14,11 +12,13 @@ import sage.graphs.lovasz_theta import sage.graphs.partial_cube from sage.graphs import graph_list as graphs_list + lazy_import("sage.graphs", "graph_coloring") lazy_import("sage.graphs.graph_database", "graph_db_info") lazy_import("sage.graphs.graph_editor", "graph_editor") from sage.graphs.isgci import graph_classes + """ TESTS: diff --git a/src/sage/graphs/bipartite_graph.py b/src/sage/graphs/bipartite_graph.py index 1ae1e0287db..c64e3c31506 100644 --- a/src/sage/graphs/bipartite_graph.py +++ b/src/sage/graphs/bipartite_graph.py @@ -449,17 +449,20 @@ def __init__(self, data=None, partition=None, check=True, hash_labels=None, *arg # vertices and edges; methods are restored at the end of big "if" # statement below from types import MethodType + self.add_vertex = MethodType(Graph.add_vertex, self) self.add_vertices = MethodType(Graph.add_vertices, self) self.add_edge = MethodType(Graph.add_edge, self) self.add_edges = MethodType(Graph.add_edges, self) from sage.structure.element import Matrix + if isinstance(data, BipartiteGraph): Graph.__init__(self, data, *args, **kwds) self.left = set(data.left) self.right = set(data.right) elif isinstance(data, str): import os + alist_file = os.path.exists(data) if alist_file: self.load_afile(data, immutable=immutable_request) @@ -474,17 +477,15 @@ def __init__(self, data=None, partition=None, check=True, hash_labels=None, *arg if partition is not None: left, right = set(partition[0]), set(partition[1]) - # Some error checking. + # Some error checking. if left & right: raise ValueError("the parts are not disjoint") if len(left) + len(right) != self.n_vertices(): raise ValueError("not all vertices appear in partition") if check: - if (any(left.intersection(self.neighbor_iterator(a)) for a in left) or - any(right.intersection(self.neighbor_iterator(a)) for a in right)): - raise TypeError("input graph is not bipartite with " - "respect to the given partition") + if any(left.intersection(self.neighbor_iterator(a)) for a in left) or any(right.intersection(self.neighbor_iterator(a)) for a in right): + raise TypeError("input graph is not bipartite with " "respect to the given partition") else: for a in left: a_nbrs = left.intersection(self.neighbor_iterator(a)) @@ -501,8 +502,7 @@ def __init__(self, data=None, partition=None, check=True, hash_labels=None, *arg elif isinstance(data, Matrix): # sanity check for mutually exclusive keywords if kwds.get("multiedges", False) and kwds.get("weighted", False): - raise TypeError("weighted multi-edge bipartite graphs from " - "reduced adjacency matrix not supported") + raise TypeError("weighted multi-edge bipartite graphs from " "reduced adjacency matrix not supported") ncols = data.ncols() nrows = data.nrows() self.left = set(range(ncols)) @@ -554,14 +554,11 @@ def edges(): elif data.node_type[v] == "Top": self.right.add(v) else: - raise TypeError("NetworkX node_type defies bipartite " - "assumption (is not 'Top' or 'Bottom')") + raise TypeError("NetworkX node_type defies bipartite " "assumption (is not 'Top' or 'Bottom')") elif partition: if check: - if (any(left.intersection(self.neighbor_iterator(a)) for a in left) or - any(right.intersection(self.neighbor_iterator(a)) for a in right)): - raise TypeError("input graph is not bipartite with " - "respect to the given partition") + if any(left.intersection(self.neighbor_iterator(a)) for a in left) or any(right.intersection(self.neighbor_iterator(a)) for a in right): + raise TypeError("input graph is not bipartite with " "respect to the given partition") else: for a in left: a_nbrs = left.intersection(data.neighbor_iterator(a)) @@ -628,11 +625,11 @@ def __hash__(self): edge_items = self.edge_iterator(labels=use_labels) if self.allows_multiple_edges(): from collections import Counter + edge_items = Counter(edge_items).items() return hash((frozenset(self.left), frozenset(self.right), frozenset(edge_items))) - raise TypeError("This graph is mutable, and thus not hashable. " - "Create an immutable copy by `g.copy(immutable=True)`") + raise TypeError("This graph is mutable, and thus not hashable. " "Create an immutable copy by `g.copy(immutable=True)`") def _upgrade_from_graph(self): """ @@ -758,8 +755,7 @@ def add_vertex(self, name=None, left=False, right=False): # do nothing if we already have this vertex (idempotent) if name is not None and name in self: - if ((left and name in self.left) or - (right and name in self.right)): + if (left and name in self.left) or (right and name in self.right): return raise RuntimeError("cannot add duplicate vertex to other partition") @@ -857,9 +853,7 @@ def add_vertices(self, vertices, left=False, right=False): # check that we're not trying to add vertices to the wrong sets # or that a vertex is to be placed in both - if ((new_left & self.right) or - (new_right & self.left) or - (new_right & new_left)): + if (new_left & self.right) or (new_right & self.left) or (new_right & new_left): raise RuntimeError("cannot add duplicate vertex to other partition") # add vertices @@ -1195,8 +1189,7 @@ def add_edges(self, edges, loops=True): vertex_in_left = self._check_bipartition_for_add_edges(edges_to_add) if vertex_in_left is False: - raise ValueError("the specified set of edges cannot be added while " - "still preserving the bipartition property") + raise ValueError("the specified set of edges cannot be added while " "still preserving the bipartition property") # If we get here, then we've found a valid bipartition. # We update the bipartition @@ -1252,8 +1245,7 @@ def _check_bipartition_for_add_edges(self, edges): vertex_in_left[v] = False # Map each vertex to the connected component it belongs to - vertex_to_component = {v: comp for comp in self.connected_components(sort=False) - for v in comp} + vertex_to_component = {v: comp for comp in self.connected_components(sort=False) for v in comp} for e in edges: u, v = e[:2] @@ -1585,13 +1577,14 @@ def matching_polynomial(self, algorithm='Godsil', name=None): return Graph.matching_polynomial(self, complement=False, name=name) if algorithm == "rook": from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + A = self.reduced_adjacency_matrix() a = A.rook_vector() m = A.nrows() n = A.ncols() b = [0] * (m + n + 1) for i in range(min(m, n) + 1): - b[m + n - 2 * i] = a[i] * (-1)**i + b[m + n - 2 * i] = a[i] * (-1) ** i if name is None: name = 'x' K = PolynomialRing(A.base_ring(), name) @@ -1833,20 +1826,14 @@ def edges(): yield (cidx, num_cols + ridx - 1) saved_methods = {} - graph_methods = (("add_vertex", Graph.add_vertex), - ("add_vertices", Graph.add_vertices), - ("add_edge", Graph.add_edge), - ("add_edges", Graph.add_edges)) + graph_methods = (("add_vertex", Graph.add_vertex), ("add_vertices", Graph.add_vertices), ("add_edge", Graph.add_edge), ("add_edges", Graph.add_edges)) for name, method in graph_methods: if name in self.__dict__: saved_methods[name] = self.__dict__[name] setattr(self, name, MethodType(method, self)) try: - Graph.__init__(self, [range(num_cols + num_rows), edges()], - format='vertices_and_edges', - loops=False, multiedges=False, - immutable=immutable) + Graph.__init__(self, [range(num_cols + num_rows), edges()], format='vertices_and_edges', loops=False, multiedges=False, immutable=immutable) finally: for name, _ in graph_methods: if name in saved_methods: @@ -2065,11 +2052,9 @@ def reduced_adjacency_matrix(self, sparse=True, *, base_ring=None, **kwds): TypeError: float() argument must be a string or a ...number, not 'sage.rings.finite_rings.element_givaro.FiniteField_givaroElement' """ if self.multiple_edges() and self.weighted(): - raise NotImplementedError( - "don't know how to represent weights for a multigraph") + raise NotImplementedError("don't know how to represent weights for a multigraph") if self.is_directed(): - raise NotImplementedError( - "reduced adjacency matrix does not exist for directed graphs") + raise NotImplementedError("reduced adjacency matrix does not exist for directed graphs") # Create mappings of left and right vertices to integers. # These mappings are used to translate an edge to its reduced adjacency @@ -2097,13 +2082,12 @@ def reduced_adjacency_matrix(self, sparse=True, *, base_ring=None, **kwds): # now construct and return the matrix from the dictionary we created from sage.matrix.constructor import matrix + if base_ring is None: return matrix(len(self.right), len(self.left), D, sparse=sparse, **kwds) return matrix(base_ring, len(self.right), len(self.left), D, sparse=sparse, **kwds) - def matching(self, value_only=False, algorithm=None, - use_edge_labels=False, solver=None, verbose=0, - *, integrality_tolerance=1e-3): + def matching(self, value_only=False, algorithm=None, use_edge_labels=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a maximum matching of the graph represented by the list of its edges. @@ -2247,11 +2231,11 @@ class :class:`MixedIntegerLinearProgram if algorithm == "Hopcroft-Karp" or algorithm == "Eppstein": if use_edge_labels: - raise ValueError('use_edge_labels cannot be used with ' - '"Hopcroft-Karp" or "Eppstein"') + raise ValueError('use_edge_labels cannot be used with ' '"Hopcroft-Karp" or "Eppstein"') d = [] if self.size(): import networkx + # NetworkX matching algorithms for bipartite graphs may fail # when the graph is not connected if not self.is_connected(): @@ -2265,25 +2249,17 @@ class :class:`MixedIntegerLinearProgram m = networkx.bipartite.hopcroft_karp_matching(h) else: m = networkx.bipartite.eppstein_matching(h) - d.extend((u, v, g.edge_label(u, v)) for u, v in m.items() - if v2int[u] < v2int[v]) + d.extend((u, v, g.edge_label(u, v)) for u, v in m.items() if v2int[u] < v2int[v]) if value_only: return Integer(len(d)) return d if algorithm == "Edmonds" or algorithm == "LP": - return Graph.matching(self, value_only=value_only, - algorithm=algorithm, - use_edge_labels=use_edge_labels, - solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) - raise ValueError('algorithm must be "Hopcroft-Karp", ' - '"Eppstein", "Edmonds" or "LP"') - - def vertex_cover(self, algorithm='Konig', value_only=False, - reduction_rules=True, solver=None, verbose=0, - *, integrality_tolerance=1e-3): + return Graph.matching(self, value_only=value_only, algorithm=algorithm, use_edge_labels=use_edge_labels, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) + raise ValueError('algorithm must be "Hopcroft-Karp", ' '"Eppstein", "Edmonds" or "LP"') + + def vertex_cover(self, algorithm='Konig', value_only=False, reduction_rules=True, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a minimum vertex cover of ``self`` represented by a set of vertices. @@ -2392,12 +2368,7 @@ def vertex_cover(self, algorithm='Konig', value_only=False, True """ if algorithm != "Konig": - return Graph.vertex_cover(self, algorithm=algorithm, - value_only=value_only, - reduction_rules=reduction_rules, - solver=solver, - verbose=verbose, - integrality_tolerance=integrality_tolerance) + return Graph.vertex_cover(self, algorithm=algorithm, value_only=value_only, reduction_rules=reduction_rules, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) if not self.is_connected(): VC = [] @@ -2489,8 +2460,7 @@ def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None, imm sage: H.order(), H.size() (5, 2) """ - B = self.__class__(weighted=self._weighted, loops=self.allows_loops(), - multiedges=self.allows_multiple_edges()) + B = self.__class__(weighted=self._weighted, loops=self.allows_loops(), multiedges=self.allows_multiple_edges()) B.name("Subgraph of ({})".format(self.name())) for u in vertices: if u in self.left: @@ -2504,10 +2474,7 @@ def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None, imm edges_to_keep_unlabeled = set(e for e in edges if len(e) == 2) edges_to_keep = [] for u, v, l in self.edge_boundary(B.left, B.right, sort=False): - if ((u, v, l) in edges_to_keep_labeled - or (v, u, l) in edges_to_keep_labeled - or (u, v) in edges_to_keep_unlabeled - or (v, u) in edges_to_keep_unlabeled): + if (u, v, l) in edges_to_keep_labeled or (v, u, l) in edges_to_keep_labeled or (u, v) in edges_to_keep_unlabeled or (v, u) in edges_to_keep_unlabeled: edges_to_keep.append((u, v, l)) if edge_property is not None: @@ -2520,8 +2487,7 @@ def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None, imm return B - def _subgraph_by_deleting(self, vertices=None, edges=None, inplace=False, - edge_property=None, immutable=None): + def _subgraph_by_deleting(self, vertices=None, edges=None, inplace=False, edge_property=None, immutable=None): r""" Return the subgraph containing the given vertices and edges. @@ -2587,10 +2553,7 @@ def _subgraph_by_deleting(self, vertices=None, edges=None, inplace=False, edges_to_keep_labeled = set(e for e in edges if len(e) == 3) edges_to_keep_unlabeled = set(e for e in edges if len(e) == 2) for u, v, l in B.edge_iterator(): - if ((u, v, l) not in edges_to_keep_labeled - and (v, u, l) not in edges_to_keep_labeled - and (u, v) not in edges_to_keep_unlabeled - and (v, u) not in edges_to_keep_unlabeled): + if (u, v, l) not in edges_to_keep_labeled and (v, u, l) not in edges_to_keep_labeled and (u, v) not in edges_to_keep_unlabeled and (v, u) not in edges_to_keep_unlabeled: edges_to_delete.append((u, v, l)) if edge_property is not None: # We might get duplicate edges, but this does handle the case of @@ -2600,9 +2563,7 @@ def _subgraph_by_deleting(self, vertices=None, edges=None, inplace=False, B.delete_edges(edges_to_delete) return B - def canonical_label(self, partition=None, certificate=False, - edge_labels=False, algorithm=None, return_graph=True, - immutable=None): + def canonical_label(self, partition=None, certificate=False, edge_labels=False, algorithm=None, return_graph=True, immutable=None): r""" Return the canonical graph. @@ -2723,12 +2684,7 @@ class by some canonization function `c`. If `G` and `H` are graphs, :meth:`~sage.graphs.generic_graph.GenericGraph.canonical_label()` """ if certificate: - C, cert = GenericGraph.canonical_label(self, partition=partition, - certificate=certificate, - edge_labels=edge_labels, - algorithm=algorithm, - return_graph=return_graph, - immutable=immutable) + C, cert = GenericGraph.canonical_label(self, partition=partition, certificate=certificate, edge_labels=edge_labels, algorithm=algorithm, return_graph=return_graph, immutable=immutable) else: from itertools import chain diff --git a/src/sage/graphs/cographs.py b/src/sage/graphs/cographs.py index 30569f63130..c2d69e97f4e 100644 --- a/src/sage/graphs/cographs.py +++ b/src/sage/graphs/cographs.py @@ -19,6 +19,7 @@ Methods ------- """ + # **************************************************************************** # Copyright (C) 2017-2024 Marianna Spyrakou # 2024 David Coudert @@ -40,6 +41,7 @@ class CoTree: This data structure is used for the generation of cographs in :meth:`cographs`. """ + def __init__(self, name='root'): r""" Initialize a cotree. @@ -211,8 +213,7 @@ def find_pivot(T): # Check if T is a pivot i = T.name - if (i != 1 and ((i//2 != T.children[0].name) or - (i//2 + i % 2 != T.children[1].name))): + if i != 1 and ((i // 2 != T.children[0].name) or (i // 2 + i % 2 != T.children[1].name)): T.info = 'p' # pivot mark return T return None @@ -343,9 +344,12 @@ def cographs(n, as_graph=True, immutable=False): if n < 1: raise ValueError('parameter n must be at least >= 1') if as_graph: + def func(T): return tree_to_graph(T, immutable=immutable) + else: + def func(T): return T @@ -432,6 +436,7 @@ def tree_to_graph(tree, immutable=False): [(1, 2)] """ from sage.graphs.graph import Graph + g = Graph() _tree_to_graph_rec(tree, g) return g.copy(immutable=True) if immutable else g diff --git a/src/sage/graphs/cycle_enumeration.py b/src/sage/graphs/cycle_enumeration.py index 6968432338f..90528eb69ca 100644 --- a/src/sage/graphs/cycle_enumeration.py +++ b/src/sage/graphs/cycle_enumeration.py @@ -14,6 +14,7 @@ Functions --------- """ + # **************************************************************************** # Copyright (C) 2025 Yuta Inoue # David Coudert @@ -27,11 +28,7 @@ from copy import copy -def _all_cycles_iterator_vertex(self, vertex, starting_vertices=None, simple=False, - rooted=False, max_length=None, trivial=False, - remove_acyclic_edges=True, - weight_function=None, by_weight=False, - check_weight=True, report_weight=False): +def _all_cycles_iterator_vertex(self, vertex, starting_vertices=None, simple=False, rooted=False, max_length=None, trivial=False, remove_acyclic_edges=True, weight_function=None, by_weight=False, check_weight=True, report_weight=False): r""" Return an iterator over the cycles of ``self`` starting with the given vertex in increasing length order. Each edge must have a positive weight. @@ -198,18 +195,18 @@ def _all_cycles_iterator_vertex(self, vertex, starting_vertices=None, simple=Fal int_to_vertex = list(h) vertex_to_int = {v: i for i, v in enumerate(int_to_vertex)} - by_weight, weight_function = self._get_weight_function(by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight) + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, weight_function=weight_function, check_weight=check_weight) if by_weight: for e in h.edge_iterator(): if weight_function(e) < 0: raise ValueError("negative weight is not allowed") from heapq import heappop, heappush + heap_queue = [(0, [vertex])] if max_length is None: from sage.rings.infinity import Infinity + max_length = Infinity while heap_queue: length, path = heappop(heap_queue) @@ -234,21 +231,17 @@ def _all_cycles_iterator_vertex(self, vertex, starting_vertices=None, simple=Fal yield path # If simple is set to True, only simple cycles are # allowed, Then it discards the current path - if (not simple or path.count(path[-1]) == 1): + if not simple or path.count(path[-1]) == 1: for e in h.edge_iterator(vertices=[path[-1]]): neighbor = e[1] if e[0] == path[-1] else e[0] # Makes sure that the current cycle is not too long. # If cycles are not rooted, makes sure to keep only the # minimum cycle according to the lexicographic order - if length + weight_function(e) <= max_length and \ - (rooted or neighbor not in starting_vertices or path[0] <= neighbor): + if length + weight_function(e) <= max_length and (rooted or neighbor not in starting_vertices or path[0] <= neighbor): heappush(heap_queue, (length + weight_function(e), path + [neighbor])) -def _all_simple_cycles_iterator_edge(self, edge, max_length=None, - remove_unnecessary_edges=True, - weight_function=None, by_weight=False, - check_weight=True, report_weight=False): +def _all_simple_cycles_iterator_edge(self, edge, max_length=None, remove_unnecessary_edges=True, weight_function=None, by_weight=False, check_weight=True, report_weight=False): r""" Return an iterator over the **simple** cycles of ``self`` starting with the given edge in increasing length order. Each edge must have a positive weight. @@ -366,26 +359,20 @@ def _all_simple_cycles_iterator_edge(self, edge, max_length=None, # delete edge h.delete_edge(edge) - by_weight, weight_function = self._get_weight_function(by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight) + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, weight_function=weight_function, check_weight=check_weight) if by_weight: for e in self.edge_iterator(): if weight_function(e) < 0: raise ValueError("negative weight is not allowed") - it = h.shortest_simple_paths(source=edge[1], target=edge[0], - weight_function=weight_function, - by_weight=by_weight, - check_weight=check_weight, - report_edges=False, - report_weight=True) + it = h.shortest_simple_paths(source=edge[1], target=edge[0], weight_function=weight_function, by_weight=by_weight, check_weight=check_weight, report_edges=False, report_weight=True) edge_weight = weight_function(edge) if max_length is None: from sage.rings.infinity import Infinity + max_length = Infinity for length, path in it: if length + edge_weight > max_length: @@ -397,11 +384,7 @@ def _all_simple_cycles_iterator_edge(self, edge, max_length=None, yield [edge[0]] + path -def all_cycles_iterator(self, starting_vertices=None, simple=False, - rooted=False, max_length=None, trivial=False, - weight_function=None, by_weight=False, - check_weight=True, report_weight=False, - algorithm='A'): +def all_cycles_iterator(self, starting_vertices=None, simple=False, rooted=False, max_length=None, trivial=False, weight_function=None, by_weight=False, check_weight=True, report_weight=False, algorithm='A'): r""" Return an iterator over all the cycles of ``self`` starting with one of the given vertices. Each edge must have a positive weight. @@ -621,9 +604,7 @@ def all_cycles_iterator(self, starting_vertices=None, simple=False, if starting_vertices is None: starting_vertices = self - by_weight, weight_function = self._get_weight_function(by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight) + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, weight_function=weight_function, check_weight=check_weight) if by_weight: for e in self.edge_iterator(): @@ -650,32 +631,21 @@ def all_cycles_iterator(self, starting_vertices=None, simple=False, # We create one cycles iterator per vertex. This is necessary if we # want to iterate over cycles with increasing length. def cycle_iter(v): - return h._all_cycles_iterator_vertex(v, - starting_vertices=starting_vertices, - simple=simple, - rooted=rooted, - max_length=max_length, - trivial=trivial, - remove_acyclic_edges=False, - weight_function=weight_function, - by_weight=by_weight, - check_weight=check_weight, - report_weight=True) + return h._all_cycles_iterator_vertex(v, starting_vertices=starting_vertices, simple=simple, rooted=rooted, max_length=max_length, trivial=trivial, remove_acyclic_edges=False, weight_function=weight_function, by_weight=by_weight, check_weight=check_weight, report_weight=True) iterators = {v: cycle_iter(v) for v in starting_vertices} elif algorithm == 'B': + def simple_cycle_iter(hh, e): - return hh._all_simple_cycles_iterator_edge(e, - max_length=max_length, - remove_unnecessary_edges=False, - weight_function=weight_function, - by_weight=by_weight, - check_weight=check_weight, - report_weight=True) + return hh._all_simple_cycles_iterator_edge(e, max_length=max_length, remove_unnecessary_edges=False, weight_function=weight_function, by_weight=by_weight, check_weight=check_weight, report_weight=True) + if self.is_directed(): + def decompose(hh): return [hh.subgraph(c, immutable=False) for c in hh.strongly_connected_components()] + else: + def decompose(hh): return [hh.subgraph(c, immutable=False) for c in hh.biconnected_components()] @@ -690,8 +660,10 @@ def decompose(hh): hh.delete_edge(e) components.extend(decompose(hh)) else: - raise ValueError(f"The algorithm {algorithm} is not valid. \ - Use the algorithm 'A' or 'B'.") + raise ValueError( + f"The algorithm {algorithm} is not valid. \ + Use the algorithm 'A' or 'B'." + ) cycles = [] for key, it in iterators.items(): @@ -703,6 +675,7 @@ def decompose(hh): # Since we always extract a shortest path, using a heap # can speed up the algorithm from heapq import heapify, heappop, heappush + heapify(cycles) while cycles: # We choose the shortest available cycle @@ -720,11 +693,7 @@ def decompose(hh): pass -def all_simple_cycles(self, starting_vertices=None, rooted=False, - max_length=None, trivial=False, - weight_function=None, by_weight=False, - check_weight=True, report_weight=False, - algorithm='B'): +def all_simple_cycles(self, starting_vertices=None, rooted=False, max_length=None, trivial=False, weight_function=None, by_weight=False, check_weight=True, report_weight=False, algorithm='B'): r""" Return a list of all simple cycles of ``self``. The cycles are enumerated in increasing length order. Each edge must have a @@ -915,11 +884,4 @@ def all_simple_cycles(self, starting_vertices=None, rooted=False, sage: g.all_simple_cycles(algorithm='A') [[0, 1, 2, 0]] """ - return list(self.all_cycles_iterator(starting_vertices=starting_vertices, - simple=True, rooted=rooted, - max_length=max_length, trivial=trivial, - weight_function=weight_function, - by_weight=by_weight, - check_weight=check_weight, - report_weight=report_weight, - algorithm=algorithm)) + return list(self.all_cycles_iterator(starting_vertices=starting_vertices, simple=True, rooted=rooted, max_length=max_length, trivial=trivial, weight_function=weight_function, by_weight=by_weight, check_weight=check_weight, report_weight=report_weight, algorithm=algorithm)) diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index bef74819816..597dce686f7 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -519,13 +519,10 @@ class DiGraph(GenericGraph): sage: DiGraph(DiGraph().networkx_graph(), weighted=None, format='NX') # needs networkx Digraph on 0 vertices """ + _directed = True - def __init__(self, data=None, pos=None, loops=None, format=None, - weighted=None, data_structure='sparse', - vertex_labels=True, name=None, - multiedges=None, convert_empty_dict_labels_to_None=None, - sparse=True, immutable=False, hash_labels=None): + def __init__(self, data=None, pos=None, loops=None, format=None, weighted=None, data_structure='sparse', vertex_labels=True, name=None, multiedges=None, convert_empty_dict_labels_to_None=None, sparse=True, immutable=False, hash_labels=None): """ TESTS:: @@ -653,8 +650,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if sparse is False: if data_structure != "sparse": - raise ValueError("the 'sparse' argument is an alias for " - "'data_structure', please do not define both") + raise ValueError("the 'sparse' argument is an alias for " "'data_structure', please do not define both") data_structure = "dense" if multiedges or weighted: @@ -669,13 +665,13 @@ def __init__(self, data=None, pos=None, loops=None, format=None, # as a static sparse graph. from sage.graphs.base.sparse_graph import SparseGraphBackend from sage.graphs.base.dense_graph import DenseGraphBackend + if data_structure in ["sparse", "static_sparse"]: CGB = SparseGraphBackend elif data_structure == "dense": CGB = DenseGraphBackend else: - raise ValueError("data_structure must be equal to 'sparse', " - "'static_sparse' or 'dense'") + raise ValueError("data_structure must be equal to 'sparse', " "'static_sparse' or 'dense'") self._backend = CGB(0, directed=True) if format is None and isinstance(data, str): @@ -691,20 +687,14 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if format is None and isinstance(data, DiGraph): format = 'DiGraph' from sage.graphs.graph import Graph + if format is None and isinstance(data, Graph): data = data.to_directed() format = 'DiGraph' - if format is None and isinstance(data, list) and \ - len(data) >= 2 and callable(data[1]): + if format is None and isinstance(data, list) and len(data) >= 2 and callable(data[1]): format = 'rule' - if (format is None and - isinstance(data, list) and - len(data) == 2 and - isinstance(data[0], list) and # a list of two lists, the second of - ((isinstance(data[1], list) and # which contains iterables (the edges) - (not data[1] or callable(getattr(data[1][0], "__iter__", None)))) or - (isinstance(data[1], EdgesView)))): + if format is None and isinstance(data, list) and len(data) == 2 and isinstance(data[0], list) and ((isinstance(data[1], list) and (not data[1] or callable(getattr(data[1][0], "__iter__", None)))) or (isinstance(data[1], EdgesView))): # a list of two lists, the second of # which contains iterables (the edges) format = "vertices_and_edges" if format is None and isinstance(data, dict): @@ -720,14 +710,11 @@ def __init__(self, data=None, pos=None, loops=None, format=None, # the input is a networkx (Multi)(Di)Graph format = 'NX' - if (format is None and hasattr(data, 'vcount') and - hasattr(data, 'get_edgelist')): + if format is None and hasattr(data, 'vcount') and hasattr(data, 'get_edgelist'): try: import igraph except ImportError: - raise ImportError("the data seems to be a igraph object, but " - "igraph is not installed in Sage. To install " - "it, run 'sage -i python_igraph'") + raise ImportError("the data seems to be a igraph object, but " "igraph is not installed in Sage. To install " "it, run 'sage -i python_igraph'") if format is None and isinstance(data, igraph.Graph): format = 'igraph' if format is None and isinstance(data, (int, Integer)): @@ -762,14 +749,17 @@ def __init__(self, data=None, pos=None, loops=None, format=None, self.allow_loops(bool(loops), check=False) self.allow_multiple_edges(bool(multiedges), check=False) from .graph_input import from_dig6 + from_dig6(self, data) elif format == 'adjacency_matrix': from .graph_input import from_adjacency_matrix + from_adjacency_matrix(self, data, loops=loops, multiedges=multiedges, weighted=weighted) elif format == 'incidence_matrix': from .graph_input import from_oriented_incidence_matrix + from_oriented_incidence_matrix(self, data, loops=loops, multiedges=multiedges, weighted=weighted) elif format == 'DiGraph': @@ -782,8 +772,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, elif not multiedges: e = data.edges(labels=False, sort=False) if len(e) != len(set(e)): - raise ValueError("no multiple edges but input digraph" - " has multiple edges") + raise ValueError("no multiple edges but input digraph" " has multiple edges") self.allow_multiple_edges(multiedges, check=False) self.allow_loops(loops, check=False) if weighted is None: @@ -812,26 +801,24 @@ def __init__(self, data=None, pos=None, loops=None, format=None, elif format == 'dict_of_dicts': from .graph_input import from_dict_of_dicts - from_dict_of_dicts(self, data, loops=loops, multiedges=multiedges, weighted=weighted, - convert_empty_dict_labels_to_None=False if convert_empty_dict_labels_to_None is None else convert_empty_dict_labels_to_None) + + from_dict_of_dicts(self, data, loops=loops, multiedges=multiedges, weighted=weighted, convert_empty_dict_labels_to_None=False if convert_empty_dict_labels_to_None is None else convert_empty_dict_labels_to_None) elif format == 'dict_of_lists': from .graph_input import from_dict_of_lists + from_dict_of_lists(self, data, loops=loops, multiedges=multiedges, weighted=weighted) elif format == 'NX': from sage.graphs.graph_input import from_networkx_graph - from_networkx_graph(self, data, - weighted=weighted, multiedges=multiedges, loops=loops, - convert_empty_dict_labels_to_None=convert_empty_dict_labels_to_None) + + from_networkx_graph(self, data, weighted=weighted, multiedges=multiedges, loops=loops, convert_empty_dict_labels_to_None=convert_empty_dict_labels_to_None) if weighted is None: weighted = self.allows_multiple_edges() elif format == 'igraph': if not data.is_directed(): - raise ValueError("a *directed* igraph graph was expected. To " - "build an undirected graph, call the Graph " - "constructor") + raise ValueError("a *directed* igraph graph was expected. To " "build an undirected graph, call the Graph " "constructor") self.add_vertices(range(data.vcount())) self.add_edges((e.source, e.target, e.attributes()) for e in data.es()) @@ -844,15 +831,13 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if weighted is None: weighted = False self.allow_loops(bool(loops), check=False) - self.allow_multiple_edges(bool(multiedges), - check=False) + self.allow_multiple_edges(bool(multiedges), check=False) if data < 0: raise ValueError("the number of vertices cannot be strictly negative") elif data: self.add_vertices(range(data)) elif format == 'list_of_edges': - self.allow_multiple_edges(bool(multiedges), - check=False) + self.allow_multiple_edges(bool(multiedges), check=False) self.allow_loops(bool(loops), check=False) self.add_edges(data) else: @@ -872,10 +857,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if data_structure == "static_sparse": from sage.graphs.base.static_sparse_backend import StaticSparseBackend - ib = StaticSparseBackend(self, - loops=self.allows_loops(), - multiedges=self.allows_multiple_edges(), - sort=(format != "vertices_and_edges")) + + ib = StaticSparseBackend(self, loops=self.allows_loops(), multiedges=self.allows_multiple_edges(), sort=(format != "vertices_and_edges")) self._backend = ib self._immutable = True @@ -1075,13 +1058,13 @@ def to_undirected(self, data_structure=None, sparse=None): """ if sparse is not None: if data_structure is not None: - raise ValueError("the 'sparse' argument is an alias for " - "'data_structure'. Please do not define both") + raise ValueError("the 'sparse' argument is an alias for " "'data_structure'. Please do not define both") data_structure = "sparse" if sparse else "dense" if data_structure is None: from sage.graphs.base.dense_graph import DenseGraphBackend from sage.graphs.base.sparse_graph import SparseGraphBackend + if isinstance(self._backend, DenseGraphBackend): data_structure = "dense" elif isinstance(self._backend, SparseGraphBackend): @@ -1089,12 +1072,8 @@ def to_undirected(self, data_structure=None, sparse=None): else: data_structure = "static_sparse" from sage.graphs.graph import Graph - G = Graph(name=self.name(), - pos=self._pos, - multiedges=self.allows_multiple_edges(), - loops=self.allows_loops(), - data_structure=(data_structure if data_structure != "static_sparse" - else "sparse")) # we need a mutable copy first + + G = Graph(name=self.name(), pos=self._pos, multiedges=self.allows_multiple_edges(), loops=self.allows_loops(), data_structure=(data_structure if data_structure != "static_sparse" else "sparse")) # we need a mutable copy first G.add_vertices(self.vertex_iterator()) G.set_vertices(self.get_vertices()) @@ -1519,12 +1498,12 @@ def degree_polynomial(self): (x + y)^4 """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(ZZ, 'x,y') x, y = R.gens() return R.sum(x ** self.in_degree(v) * y ** self.out_degree(v) for v in self) - def feedback_edge_set(self, constraint_generation=True, value_only=False, - solver=None, verbose=0, *, integrality_tolerance=1e-3): + def feedback_edge_set(self, constraint_generation=True, value_only=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Compute the minimum feedback edge set of a digraph (also called feedback arc set). @@ -1689,9 +1668,7 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, loops = D.loops(labels=None) D.delete_edges(loops) D.allow_loops(False, check=False) - FAS = D.feedback_edge_set(constraint_generation=constraint_generation, - value_only=value_only, solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + FAS = D.feedback_edge_set(constraint_generation=constraint_generation, value_only=value_only, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) if value_only: return FAS + len(loops) return FAS + loops @@ -1706,13 +1683,9 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, if not h.size(): continue if value_only: - FAS += h.feedback_edge_set(constraint_generation=constraint_generation, - value_only=True, solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + FAS += h.feedback_edge_set(constraint_generation=constraint_generation, value_only=True, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) else: - FAS.extend(h.feedback_edge_set(constraint_generation=constraint_generation, - value_only=False, solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance)) + FAS.extend(h.feedback_edge_set(constraint_generation=constraint_generation, value_only=False, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance)) return FAS from sage.numerical.mip import MixedIntegerLinearProgram @@ -1722,8 +1695,7 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, ######################################## if constraint_generation: - p = MixedIntegerLinearProgram(constraint_generation=True, - maximization=False, solver=solver) + p = MixedIntegerLinearProgram(constraint_generation=True, maximization=False, solver=solver) # A variable for each edge b = p.new_variable(binary=True) @@ -1739,8 +1711,7 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, # Building the graph without the edges removed by the MILP p.solve(log=verbose) val = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - h = DiGraph([e for e in self.edge_iterator(labels=False) if not val[e]], - format='list_of_edges') + h = DiGraph([e for e in self.edge_iterator(labels=False) if not val[e]], format='list_of_edges') # Is the digraph acyclic ? isok, certificate = h.is_directed_acyclic(certificate=True) @@ -1845,15 +1816,13 @@ def reverse(self, immutable=None): False """ from sage.graphs.base.dense_graph import DenseGraphBackend + if isinstance(self._backend, DenseGraphBackend): data_structure = "dense" else: data_structure = "sparse" - H = DiGraph(data_structure=data_structure, - multiedges=self.allows_multiple_edges(), loops=self.allows_loops(), - pos=copy(self._pos), weighted=self.weighted(), - hash_labels=self._hash_labels) + H = DiGraph(data_structure=data_structure, multiedges=self.allows_multiple_edges(), loops=self.allows_loops(), pos=copy(self._pos), weighted=self.weighted(), hash_labels=self._hash_labels) H.add_vertices(self) H.add_edges((v, u, d) for u, v, d in self.edge_iterator()) name = self.name() @@ -2062,7 +2031,7 @@ def reverse_edge(self, u, v=None, label=None, inplace=True, multiedges=None): # from the labels on the list label = tempG.edge_label(u, v)[0] - if ((not tempG.allows_multiple_edges()) and (tempG.has_edge(v, u))): + if (not tempG.allows_multiple_edges()) and (tempG.has_edge(v, u)): # If user wants to force digraph to allow parallel edges if multiedges: tempG.allow_multiple_edges(True) @@ -2077,10 +2046,7 @@ def reverse_edge(self, u, v=None, label=None, inplace=True, multiedges=None): # User is supposed to specify multiedges True or False else: - raise ValueError("reversing the given edge is about to " - "create two parallel edges but input digraph " - "doesn't allow them - User needs to specify " - "multiedges is True or False.") + raise ValueError("reversing the given edge is about to " "create two parallel edges but input digraph " "doesn't allow them - User needs to specify " "multiedges is True or False.") else: tempG.delete_edge(u, v, label) tempG.add_edge(v, u, label) @@ -2195,9 +2161,7 @@ def reverse_edges(self, edges, inplace=True, multiedges=None): # Distances - def eccentricity(self, v=None, by_weight=False, algorithm=None, - weight_function=None, check_weight=True, dist_dict=None, - with_labels=False): + def eccentricity(self, v=None, by_weight=False, algorithm=None, weight_function=None, check_weight=True, dist_dict=None, with_labels=False): """ Return the eccentricity of vertex (or vertices) ``v``. @@ -2338,9 +2302,7 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, ... ValueError: algorithm 'Johnson_Boost' works only if all eccentricities are needed """ - by_weight, weight_function = self._get_weight_function(by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight) + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, weight_function=weight_function, check_weight=check_weight) if not by_weight: # We don't want the default weight function @@ -2369,20 +2331,18 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, # If we want to use BFS, we use the Cython routine if algorithm == 'BFS': from sage.graphs.distances_all_pairs import eccentricity + algo = 'standard' if with_labels: return dict(zip(v, eccentricity(self, algorithm=algo, vertex_list=v))) return eccentricity(self, algorithm=algo, vertex_list=v) if algorithm in ['Floyd-Warshall-Python', 'Floyd-Warshall-Cython', 'Johnson_Boost']: - dist_dict = self.shortest_path_all_pairs(by_weight=by_weight, algorithm=algorithm, - weight_function=weight_function, - check_weight=False)[0] + dist_dict = self.shortest_path_all_pairs(by_weight=by_weight, algorithm=algorithm, weight_function=weight_function, check_weight=False)[0] algorithm = 'From_Dictionary' elif algorithm in ['Floyd-Warshall-Python', 'Floyd-Warshall-Cython', 'Johnson_Boost']: - raise ValueError("algorithm '" + algorithm + "' works only if all" + - " eccentricities are needed") + raise ValueError("algorithm '" + algorithm + "' works only if all" + " eccentricities are needed") ecc = {} @@ -2394,10 +2354,7 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, else: # If algorithm is wrong, the error is raised by the # shortest_path_lengths function - length = self.shortest_path_lengths(u, by_weight=by_weight, - algorithm=algorithm, - weight_function=weight_function, - check_weight=False) + length = self.shortest_path_lengths(u, by_weight=by_weight, algorithm=algorithm, weight_function=weight_function, check_weight=False) if len(length) != self.n_vertices(): ecc[u] = Infinity @@ -2408,12 +2365,11 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, return ecc if len(ecc) == 1: # return single value - v, = ecc.values() + (v,) = ecc.values() return v return [ecc[u] for u in v] - def radius(self, by_weight=False, algorithm=None, weight_function=None, - check_weight=True): + def radius(self, by_weight=False, algorithm=None, weight_function=None, check_weight=True): r""" Return the radius of the DiGraph. @@ -2475,13 +2431,9 @@ def radius(self, by_weight=False, algorithm=None, weight_function=None, if not self.order(): raise ValueError("radius is not defined for the empty DiGraph") - return min(self.eccentricity(v=list(self), by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight, - algorithm=algorithm)) + return min(self.eccentricity(v=list(self), by_weight=by_weight, weight_function=weight_function, check_weight=check_weight, algorithm=algorithm)) - def diameter(self, by_weight=False, algorithm=None, weight_function=None, - check_weight=True): + def diameter(self, by_weight=False, algorithm=None, weight_function=None, check_weight=True): r""" Return the diameter of the DiGraph. @@ -2617,9 +2569,7 @@ def diameter(self, by_weight=False, algorithm=None, weight_function=None, if not self.order(): raise ValueError("diameter is not defined for the empty DiGraph") - by_weight, weight_function = self._get_weight_function(by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight) + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, weight_function=weight_function, check_weight=check_weight) if not by_weight: # We don't want the default weight function @@ -2633,23 +2583,20 @@ def diameter(self, by_weight=False, algorithm=None, weight_function=None, if algorithm in ['2Dsweep', 'DiFUB']: if not by_weight: from sage.graphs.distances_all_pairs import diameter + return diameter(self, algorithm=algorithm) from sage.graphs.base.boost_graph import diameter - return diameter(self, algorithm=algorithm, - weight_function=weight_function, - check_weight=False) + + return diameter(self, algorithm=algorithm, weight_function=weight_function, check_weight=False) if algorithm == 'BFS': from sage.graphs.distances_all_pairs import diameter + return diameter(self, algorithm='standard') - return max(self.eccentricity(v=list(self), by_weight=by_weight, - weight_function=weight_function, - check_weight=False, - algorithm=algorithm)) + return max(self.eccentricity(v=list(self), by_weight=by_weight, weight_function=weight_function, check_weight=False, algorithm=algorithm)) - def center(self, by_weight=False, algorithm=None, weight_function=None, - check_weight=True): + def center(self, by_weight=False, algorithm=None, weight_function=None, check_weight=True): r""" Return the set of vertices in the center of the DiGraph. @@ -2708,19 +2655,14 @@ def center(self, by_weight=False, algorithm=None, weight_function=None, sage: G.center() [0, 1, 2] """ - ecc = self.eccentricity(v=list(self), by_weight=by_weight, - weight_function=weight_function, - algorithm=algorithm, - check_weight=check_weight, - with_labels=True) + ecc = self.eccentricity(v=list(self), by_weight=by_weight, weight_function=weight_function, algorithm=algorithm, check_weight=check_weight, with_labels=True) try: r = min(ecc.values()) except Exception: return [] return [v for v in self if ecc[v] == r] - def periphery(self, by_weight=False, algorithm=None, weight_function=None, - check_weight=True): + def periphery(self, by_weight=False, algorithm=None, weight_function=None, check_weight=True): r""" Return the set of vertices in the periphery of the DiGraph. @@ -2770,11 +2712,7 @@ def periphery(self, by_weight=False, algorithm=None, weight_function=None, sage: G.periphery() [0] """ - ecc = self.eccentricity(v=list(self), by_weight=by_weight, - weight_function=weight_function, - algorithm=algorithm, - check_weight=check_weight, - with_labels=True) + ecc = self.eccentricity(v=list(self), by_weight=by_weight, weight_function=weight_function, algorithm=algorithm, check_weight=check_weight, with_labels=True) try: d = max(ecc.values()) except Exception: @@ -2794,6 +2732,7 @@ def path_semigroup(self): [e_1, e_2, e_3, a, c, b, a*b, c*b] """ from sage.quivers.path_semigroup import PathSemigroup + return PathSemigroup(self) def auslander_reiten_quiver(self): @@ -2811,6 +2750,7 @@ def auslander_reiten_quiver(self): Auslander-Reiten quiver of Multi-digraph on 2 vertices """ from sage.quivers.ar_quiver import AuslanderReitenQuiver + return AuslanderReitenQuiver(self) # Directed Acyclic Graphs (DAGs) @@ -2887,6 +2827,7 @@ def topological_sort(self, implementation='default'): elif implementation == "NetworkX": import networkx + S = networkx.topological_sort(self.networkx_graph()) if S is None: raise TypeError('digraph is not acyclic; there is no topological sort') @@ -2937,11 +2878,10 @@ def topological_sort_generator(self): ....: print("this should never happen") """ from sage.combinat.posets.posets import Poset + return Poset(self).linear_extensions() - def longest_dag_path(self, source=None, target=None, - by_weight=False, weight_function=None, - check_weight=True): + def longest_dag_path(self, source=None, target=None, by_weight=False, weight_function=None, check_weight=True): r""" Return the longest path in this DAG, by edge count or total weight. @@ -3560,6 +3500,7 @@ def flow_polytope(self, edges=None, ends=None, backend=None): () """ from sage.geometry.polyhedron.constructor import Polyhedron + if edges is None: edges = self.edges(sort=False) m = len(edges) @@ -3620,8 +3561,8 @@ def is_tournament(self): return False import itertools - return not any(self.has_edge(u, v) == self.has_edge(v, u) - for u, v in itertools.combinations(self, 2)) + + return not any(self.has_edge(u, v) == self.has_edge(v, u) for u, v in itertools.combinations(self, 2)) def _girth_bfs(self, odd=False, certificate=False): r""" @@ -3704,6 +3645,7 @@ def _girth_bfs(self, odd=False, certificate=False): depth += 1 if best == n + 1: from sage.rings.infinity import Infinity + return (Infinity, None) if certificate else Infinity if certificate: cycles = {} @@ -3830,6 +3772,7 @@ def out_branchings(self, source, spanning=True): sage: len(list(G.out_branchings(0))) 2 """ + def _rec_out_branchings(depth): r""" The recursive function used to enumerate out branchings. @@ -3846,8 +3789,7 @@ def _rec_out_branchings(depth): # We iterate over the lists of labels in list_merged_edges and # yield the corresponding out_branchings for indexes in product(*list_merged_edges): - yield DiGraph([list_edges[index] for index in indexes], - format='list_of_edges', pos=self.get_pos()) + yield DiGraph([list_edges[index] for index in indexes], format='list_of_edges', pos=self.get_pos()) # 1) Clean the graph # delete loops on source if any @@ -4046,6 +3988,7 @@ def in_branchings(self, source, spanning=True): sage: len(list(G.in_branchings(0))) 1 """ + def _rec_in_branchings(depth): r""" The recursive function used to enumerate in branchings. @@ -4062,8 +4005,7 @@ def _rec_in_branchings(depth): # We iterate over the lists of labels in list_merged_edges and # yield the corresponding in_branchings for indexes in product(*list_merged_edges): - yield DiGraph([list_edges[index] for index in indexes], - format='list_of_edges', pos=self.get_pos()) + yield DiGraph([list_edges[index] for index in indexes], format='list_of_edges', pos=self.get_pos()) # 1) Clean the graph # delete loops on source if any diff --git a/src/sage/graphs/digraph_generators.py b/src/sage/graphs/digraph_generators.py index d71da30640e..ebfbba187b3 100644 --- a/src/sage/graphs/digraph_generators.py +++ b/src/sage/graphs/digraph_generators.py @@ -54,6 +54,7 @@ Functions and methods --------------------- """ + # **************************************************************************** # Copyright (C) 2006 Robert L. Miller # and Emily A. Kirkman @@ -301,16 +302,17 @@ def ButterflyGraph(self, n, vertices='strings', immutable=False): if n >= 31: raise NotImplementedError("vertices='strings' is only valid for n <= 30") from sage.graphs.generic_graph_pyx import int_to_binary_string + V = [] E = [] - for v in range(2 ** n): + for v in range(2**n): bv = int_to_binary_string(v) # pad and reverse the string padded_bv = ('0' * (n - len(bv)) + bv)[::-1] V.append(padded_bv) for i in range(n): w = v - w ^= (1 << i) # push 1 to the left by i and xor with w + w ^= 1 << i # push 1 to the left by i and xor with w bw = int_to_binary_string(w) padded_bw = ('0' * (n - len(bw)) + bw)[::-1] E.append(((padded_bv, i), (padded_bv, i + 1))) @@ -319,6 +321,7 @@ def ButterflyGraph(self, n, vertices='strings', immutable=False): from sage.modules.free_module import VectorSpace from sage.rings.finite_rings.finite_field_constructor import FiniteField from copy import copy + V = [] E = [] for v in VectorSpace(FiniteField(2), n): @@ -340,9 +343,7 @@ def ButterflyGraph(self, n, vertices='strings', immutable=False): for i, v in enumerate(sorted(V, reverse=True)): for x in range(n + 1): pos[v, x] = (dec * x, i) - return DiGraph([pos.keys(), E], format='vertices_and_edges', pos=pos, - name="{}-dimensional Butterfly".format(n), - immutable=immutable) + return DiGraph([pos.keys(), E], format='vertices_and_edges', pos=pos, name="{}-dimensional Butterfly".format(n), immutable=immutable) def Path(self, n, immutable=False): r""" @@ -365,9 +366,7 @@ def Path(self, n, immutable=False): sage: g.automorphism_group().cardinality() # needs sage.groups 1 """ - g = DiGraph([range(n), zip(range(n - 1), range(1, n))], - format='vertices_and_edges', name='Path', - immutable=immutable) + g = DiGraph([range(n), zip(range(n - 1), range(1, n))], format='vertices_and_edges', name='Path', immutable=immutable) g.set_pos({i: (i, 0) for i in range(n)}) return g @@ -413,14 +412,14 @@ def StronglyRegular(self, n, immutable=False): """ from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix from sage.matrix.constructor import ones_matrix, identity_matrix + if skew_hadamard_matrix(n + 1, existence=True) is not True: raise ValueError(f'strongly regular digraph with {n} vertices not yet implemented') H = skew_hadamard_matrix(n + 1, skew_normalize=True) M = H[1:, 1:] M = (M + ones_matrix(n)) / 2 - identity_matrix(n) - return DiGraph(M, format='adjacency_matrix', immutable=immutable, - name='Strongly regular digraph') + return DiGraph(M, format='adjacency_matrix', immutable=immutable, name='Strongly regular digraph') def Paley(self, q, immutable=False): r""" @@ -474,14 +473,12 @@ def Paley(self, q, immutable=False): from sage.rings.finite_rings.integer_mod import mod from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.arith.misc import is_prime_power + if not is_prime_power(q): raise ValueError("parameter q must be a prime power") if not mod(q, 4) == 3: raise ValueError("parameter q must be congruent to 3 mod 4") - return DiGraph([FiniteField(q, 'a'), - lambda i, j: (i != j) and (j - i).is_square()], - format='rule', loops=False, immutable=immutable, - name="Paley digraph with parameter {}".format(q)) + return DiGraph([FiniteField(q, 'a'), lambda i, j: (i != j) and (j - i).is_square()], format='rule', loops=False, immutable=immutable, name="Paley digraph with parameter {}".format(q)) def TransitiveTournament(self, n, immutable=False): r""" @@ -526,9 +523,8 @@ def TransitiveTournament(self, n, immutable=False): raise ValueError('the number of vertices cannot be strictly negative') from itertools import combinations - g = DiGraph([range(n), combinations(range(n), 2)], - format='vertices_and_edges', immutable=immutable, - name="Transitive Tournament") + + g = DiGraph([range(n), combinations(range(n), 2)], format='vertices_and_edges', immutable=immutable, name="Transitive Tournament") g._circle_embedding(list(range(n))) return g @@ -575,19 +571,14 @@ def RandomTournament(self, n, immutable=False): from sage.misc.prandom import getrandbits bits = getrandbits(n * (n - 1) // 2) - edges = ((i, j) if (bits >> k) & 1 else (j, i) - for k, (i, j) in enumerate(combinations(range(n), 2))) - g = DiGraph([range(n), edges], format='vertices_and_edges', - immutable=immutable, name="Random Tournament") + edges = ((i, j) if (bits >> k) & 1 else (j, i) for k, (i, j) in enumerate(combinations(range(n), 2))) + g = DiGraph([range(n), edges], format='vertices_and_edges', immutable=immutable, name="Random Tournament") g._circle_embedding(list(range(n))) return g - def tournaments_nauty(self, n, - min_out_degree=None, max_out_degree=None, - strongly_connected=False, debug=False, options="", - immutable=False): + def tournaments_nauty(self, n, min_out_degree=None, max_out_degree=None, strongly_connected=False, debug=False, options="", immutable=False): r""" Iterator over all tournaments on `n` vertices using Nauty. @@ -643,12 +634,10 @@ def tournaments_nauty(self, n, import shlex from sage.features.nauty import NautyExecutable + gentourng_path = NautyExecutable("gentourng").absolute_filename() - with subprocess.Popen(shlex.quote(gentourng_path) + " {0}".format(nauty_input), - shell=True, - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, close_fds=True) as sp: + with subprocess.Popen(shlex.quote(gentourng_path) + " {0}".format(nauty_input), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) as sp: if debug: yield sp.stderr.readline() @@ -673,8 +662,7 @@ def edges(s): # Exhausted list of graphs from nauty geng return - yield DiGraph([range(n), edges(s)], format='vertices_and_edges', - immutable=immutable) + yield DiGraph([range(n), edges(s)], format='vertices_and_edges', immutable=immutable) def nauty_directg(self, graphs, options='', debug=False, immutable=False): r""" @@ -777,14 +765,10 @@ def nauty_directg(self, graphs, options='', debug=False, immutable=False): import shlex from sage.features.nauty import NautyExecutable + directg_path = NautyExecutable("directg").absolute_filename() - with subprocess.Popen(shlex.quote(directg_path) + ' {0}'.format(options), - shell=True, - stdout=subprocess.PIPE, - stdin=subprocess.PIPE, - stderr=subprocess.STDOUT, - encoding='latin-1') as sub: + with subprocess.Popen(shlex.quote(directg_path) + ' {0}'.format(options), shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, encoding='latin-1') as sub: out, err = sub.communicate(input=input) if debug: @@ -843,11 +827,9 @@ def nauty_posetg(self, options='', debug=False, immutable=False): """ import shlex from sage.features.nauty import NautyExecutable + geng_path = NautyExecutable("genposetg").absolute_filename() - with subprocess.Popen(shlex.quote(geng_path) + f" {options}", shell=True, - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, close_fds=True, - encoding='latin-1') as sp: + with subprocess.Popen(shlex.quote(geng_path) + f" {options}", shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, encoding='latin-1') as sp: msg = sp.stderr.readline() if debug: yield msg @@ -902,9 +884,7 @@ def Complete(self, n, loops=False, immutable=False): raise ValueError('the number of vertices cannot be strictly negative') edges = ((u, v) for u in range(n) for v in range(n) if u != v or loops) - G = DiGraph([range(n), edges], format='vertices_and_edges', - loops=loops, immutable=immutable, - name="Complete digraph" + (" with loops" if loops else '')) + G = DiGraph([range(n), edges], format='vertices_and_edges', loops=loops, immutable=immutable, name="Complete digraph" + (" with loops" if loops else '')) G._circle_embedding(list(range(n))) @@ -935,13 +915,12 @@ def Circuit(self, n, immutable=False): if n < 0: raise ValueError('the number of vertices cannot be strictly negative') if n == 1: - return DiGraph([(0, 0)], format='list_of_edges', loops=True, - immutable=immutable, name='Circuit') + return DiGraph([(0, 0)], format='list_of_edges', loops=True, immutable=immutable, name='Circuit') from itertools import chain + edges = zip(range(n), chain(range(1, n), [0])) - g = DiGraph([range(n), edges], format='vertices_and_edges', - immutable=immutable, name='Circuit') + g = DiGraph([range(n), edges], format='vertices_and_edges', immutable=immutable, name='Circuit') g._circle_embedding(list(range(n))) return g @@ -1002,9 +981,7 @@ def Circulant(self, n, integers, immutable=False): loops = True edges = ((v, (v + j) % n) for j in integers for v in range(n)) - G = DiGraph([range(n), edges], format='vertices_and_edges', - loops=loops, immutable=immutable, - name="Circulant graph (" + str(integers) + ")") + G = DiGraph([range(n), edges], format='vertices_and_edges', loops=loops, immutable=immutable, name="Circulant graph (" + str(integers) + ")") G._circle_embedding(list(range(n))) return G @@ -1112,21 +1089,16 @@ def edges(): for w in W: ww = w[1:] ws = w.string_rep() - yield from ((ws, (ww * a).string_rep(), a.string_rep()) - for a in A) + yield from ((ws, (ww * a).string_rep(), a.string_rep()) for a in A) - return DiGraph(edges(), format='list_of_edges', name=name, - loops=True, multiedges=multiedges, - immutable=immutable) + return DiGraph(edges(), format='list_of_edges', name=name, loops=True, multiedges=multiedges, immutable=immutable) if vertices == 'integers': d = k if isinstance(k, Integer) else len(list(k)) if not d: - return DiGraph(loops=True, multiedges=True, name=name, - immutable=immutable) + return DiGraph(loops=True, multiedges=True, name=name, immutable=immutable) - return digraphs.GeneralizedDeBruijn(d ** n, d, immutable=immutable, - name=name) + return digraphs.GeneralizedDeBruijn(d**n, d, immutable=immutable, name=name) raise ValueError('unknown type for vertices') @@ -1192,9 +1164,7 @@ def GeneralizedDeBruijn(self, n, d, immutable=False, name=None): name = f"Generalized de Bruijn digraph (n={n}, d={d})" edges = ((u, a % n) for u in range(n) for a in range(u * d, u * d + d)) - return DiGraph([range(n), edges], format='vertices_and_edges', - loops=True, multiedges=True, immutable=immutable, - name=name) + return DiGraph([range(n), edges], format='vertices_and_edges', loops=True, multiedges=True, immutable=immutable, name=name) def ImaseItoh(self, n, d, immutable=False, name=None): r""" @@ -1264,9 +1234,7 @@ def ImaseItoh(self, n, d, immutable=False, name=None): name = f"Imase and Itoh digraph (n={n}, d={d})" edges = ((u, a % n) for u in range(n) for a in range(-u * d - d, -u * d)) - return DiGraph([range(n), edges], format='vertices_and_edges', - loops=True, multiedges=True, immutable=immutable, - name=name) + return DiGraph([range(n), edges], format='vertices_and_edges', loops=True, multiedges=True, immutable=immutable, name=name) def Kautz(self, k, D, vertices='strings', immutable=False): r""" @@ -1384,8 +1352,7 @@ def Kautz(self, k, D, vertices='strings', immutable=False): if vertices == 'strings': from sage.combinat.words.words import Words - my_alphabet = Words([str(i) for i in range(k + 1)] if isinstance(k, - Integer) else k, 1) + my_alphabet = Words([str(i) for i in range(k + 1)] if isinstance(k, Integer) else k, 1) if my_alphabet.alphabet().cardinality() < 2: raise ValueError("degree must be greater than or equal to one") @@ -1401,18 +1368,15 @@ def Kautz(self, k, D, vertices='strings', immutable=False): def edges(): for u in V: us = u.string_rep() - yield from ((us, (u[1:] * a).string_rep(), a.string_rep()) - for a in my_alphabet if not u.has_suffix(a)) + yield from ((us, (u[1:] * a).string_rep(), a.string_rep()) for a in my_alphabet if not u.has_suffix(a)) - return DiGraph(edges(), format='list_of_edges', - name=name, immutable=immutable) + return DiGraph(edges(), format='list_of_edges', name=name, immutable=immutable) if vertices == 'integers': d = k if isinstance(k, Integer) else (len(list(k)) - 1) if d < 1: raise ValueError("degree must be greater than or equal to one") - return digraphs.ImaseItoh((d + 1) * (d ** (D - 1)), d, - name=name, immutable=immutable) + return digraphs.ImaseItoh((d + 1) * (d ** (D - 1)), d, name=name, immutable=immutable) raise ValueError('unknown type for vertices') @@ -1485,6 +1449,7 @@ def RandomDirectedAcyclicGraph(self, n, p, weight_max=None, immutable=False): # integers are on 31 bits. We thus set the pivot value to p*2^31 from sage.misc.prandom import randint from sage.misc.randstate import random + RAND_MAX_f = float(1 << 31) pp = int(round(float(p * RAND_MAX_f))) @@ -1494,15 +1459,14 @@ def RandomDirectedAcyclicGraph(self, n, p, weight_max=None, immutable=False): else: from sage.rings.integer_ring import ZZ + if weight_max in ZZ and weight_max < 1: raise ValueError("parameter weight_max must be a positive integer") name = f"RandomWeightedDAG({n}, {p}, {weight_max})" - edges = ((i, j, randint(1, weight_max)) - for i in range(n) for j in range(i) if random() < pp) + edges = ((i, j, randint(1, weight_max)) for i in range(n) for j in range(i) if random() < pp) - return DiGraph([range(n), edges], format='vertices_and_edges', - name=name, immutable=immutable) + return DiGraph([range(n), edges], format='vertices_and_edges', name=name, immutable=immutable) def RandomDirectedGN(self, n, kernel=None, seed=None, immutable=False): r""" @@ -1546,8 +1510,8 @@ def RandomDirectedGN(self, n, kernel=None, seed=None, immutable=False): if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) import networkx - return DiGraph(networkx.gn_graph(n, kernel, seed=seed), - immutable=immutable) + + return DiGraph(networkx.gn_graph(n, kernel, seed=seed), immutable=immutable) def RandomDirectedGNC(self, n, seed=None, immutable=False): r""" @@ -1583,6 +1547,7 @@ def RandomDirectedGNC(self, n, seed=None, immutable=False): if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) import networkx + return DiGraph(networkx.gnc_graph(n, seed=seed), immutable=immutable) def RandomDirectedGNP(self, n, p, loops=False, seed=None, immutable=False): @@ -1619,14 +1584,14 @@ def RandomDirectedGNP(self, n, p, loops=False, seed=None, immutable=False): True """ from sage.graphs.graph_generators_pyx import RandomGNP + if 0.0 > p or 1.0 < p: raise ValueError("the probability p must be in [0..1]") if seed is None: seed = current_randstate().long_seed() - return RandomGNP(n, p, directed=True, loops=loops, seed=seed, - immutable=immutable) + return RandomGNP(n, p, directed=True, loops=loops, seed=seed, immutable=immutable) def RandomDirectedGNM(self, n, m, loops=False, immutable=False): r""" @@ -1711,8 +1676,7 @@ def RandomDirectedGNM(self, n, m, loops=False, immutable=False): m = n * (n - 1) - m if not good_input: - raise ValueError("the number of edges must satisfy 0 <= m <= n(n-1) " - "when no loops are allowed, and 0 <= m <= n^2 otherwise") + raise ValueError("the number of edges must satisfy 0 <= m <= n(n-1) " "when no loops are allowed, and 0 <= m <= n^2 otherwise") # When the given number of edges defines a density larger than 1/2, it # should be faster to compute the complement of the graph (less edges to @@ -1728,6 +1692,7 @@ def RandomDirectedGNM(self, n, m, loops=False, immutable=False): # We fill the dictionary structure. from sage.misc.prandom import _pyrand + rand = _pyrand() while m > 0: @@ -1749,10 +1714,8 @@ def RandomDirectedGNM(self, n, m, loops=False, immutable=False): # edges stored in the adj dictionary if is_dense: - edges = ((u, v) for u in range(n) for v in range(n) - if (u != v or loops) and v not in adj[u]) - return DiGraph([range(n), edges], format='vertices_and_edges', - loops=loops, immutable=immutable) + edges = ((u, v) for u in range(n) for v in range(n) if (u != v or loops) and v not in adj[u]) + return DiGraph([range(n), edges], format='vertices_and_edges', loops=loops, immutable=immutable) return DiGraph(adj, format='dict_of_lists', loops=loops) @@ -1792,6 +1755,7 @@ def RandomDirectedGNR(self, n, p, seed=None, immutable=False): if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) import networkx + return DiGraph(networkx.gnr_graph(n, p, seed=seed), immutable=immutable) def RandomSemiComplete(self, n, immutable=False): @@ -1851,17 +1815,15 @@ def edges(): if coin >= 2: yield (v, u) - G = DiGraph([range(n), edges()], format='vertices_and_edges', - immutable=immutable, name="Random Semi-Complete digraph") + G = DiGraph([range(n), edges()], format='vertices_and_edges', immutable=immutable, name="Random Semi-Complete digraph") G._circle_embedding(list(range(n))) return G -# ############################################################################## -# DiGraph Iterators -# ############################################################################## + # ############################################################################## + # DiGraph Iterators + # ############################################################################## - def __call__(self, vertices=None, property=lambda x: True, augment='edges', - size=None, sparse=True, copy=True, immutable=False): + def __call__(self, vertices=None, property=lambda x: True, augment='edges', size=None, sparse=True, copy=True, immutable=False): """ Access the generator of isomorphism class representatives [McK1998]_. Iterates over distinct, exhaustive representatives. @@ -1939,16 +1901,21 @@ def __call__(self, vertices=None, property=lambda x: True, augment='edges', sage: digraphs? # not tested """ if size is not None: + def extra_property(x): return x.size() == size + else: + def extra_property(x): return True + if augment == 'vertices': if vertices is None: raise NotImplementedError from sage.graphs.graph_generators import canaug_traverse_vert + g = DiGraph(sparse=sparse) for gg in canaug_traverse_vert(g, [], vertices, property, dig=True, sparse=sparse): if extra_property(gg): @@ -1959,11 +1926,11 @@ def extra_property(x): if vertices is None: vertices = 0 while True: - yield from self(vertices, sparse=sparse, copy=copy, - immutable=immutable) + yield from self(vertices, sparse=sparse, copy=copy, immutable=immutable) vertices += 1 from sage.graphs.graph_generators import canaug_traverse_edge + g = DiGraph(vertices, sparse=sparse) gens = [] for i in range(vertices - 1): diff --git a/src/sage/graphs/domination.py b/src/sage/graphs/domination.py index a5e485c369d..4616d84c886 100644 --- a/src/sage/graphs/domination.py +++ b/src/sage/graphs/domination.py @@ -206,20 +206,17 @@ def private_neighbors(G, vertex, dom): closed_neighborhood_vs = set() for u in dom: if u != vertex: - closed_neighborhood_vs.update( - G.neighbor_iterator(u, closed=True)) + closed_neighborhood_vs.update(G.neighbor_iterator(u, closed=True)) - return (neighbor - for neighbor in G.neighbor_iterator(vertex, closed=True) - if neighbor not in closed_neighborhood_vs) + return (neighbor for neighbor in G.neighbor_iterator(vertex, closed=True) if neighbor not in closed_neighborhood_vs) # ============================================================================== # Computation of minimum dominating sets # ============================================================================== -def dominating_sets(g, k=1, independent=False, total=False, connected=False, - solver=None, verbose=0, *, integrality_tolerance=1e-3): + +def dominating_sets(g, k=1, independent=False, total=False, connected=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return an iterator over the minimum distance-`k` dominating sets of the graph. @@ -395,8 +392,8 @@ def dominating_sets(g, k=1, independent=False, total=False, connected=False, from sage.numerical.mip import MixedIntegerLinearProgram from sage.numerical.mip import MIPSolverException - p = MixedIntegerLinearProgram(maximization=False, solver=solver, - constraint_generation=True) + + p = MixedIntegerLinearProgram(maximization=False, solver=solver, constraint_generation=True) b = p.new_variable(binary=True) if k == 1: @@ -435,8 +432,7 @@ def neighbors_iter(x): r_edge = p.new_variable(nonnegative=True, name='re') # 1. We want a tree - p.add_constraint(p.sum(edge[fe] for fe in E) - == p.sum(b[u] for u in g) - 1) + p.add_constraint(p.sum(edge[fe] for fe in E) == p.sum(b[u] for u in g) - 1) # 2. An edge can be in the tree if its end vertices are selected for fe in E: @@ -474,8 +470,7 @@ def neighbors_iter(x): p.add_constraint(p.sum(b[u] for u in dom) <= best - 1) -def dominating_set(g, k=1, independent=False, total=False, connected=False, value_only=False, - solver=None, verbose=0, *, integrality_tolerance=1e-3): +def dominating_set(g, k=1, independent=False, total=False, connected=False, value_only=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a minimum distance-`k` dominating set of the graph. @@ -577,11 +572,10 @@ def dominating_set(g, k=1, independent=False, total=False, connected=False, valu sage: [G.dominating_set(k=k, value_only=True) for k in range(G.radius() + 1)] # needs sage.numerical.mip [5, 2, 1] """ - dom = next(dominating_sets(g, k=k, independent=independent, total=total, - connected=connected, solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance)) + dom = next(dominating_sets(g, k=k, independent=independent, total=total, connected=connected, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance)) return Integer(len(dom)) if value_only else dom + # ============================================================================== # Enumeration of minimal dominating set as described in [BDHPR2019]_ # ============================================================================== @@ -628,10 +622,8 @@ def _parent(G, dom, V_prev): priv = set(G.neighbor_iterator(v, closed=True)) # We remove the vertices already dominated # by other vertices of (D_end union D_start) - priv.difference_update(*(G.neighbor_iterator(u, closed=True) - for u in D_start if u != v)) - priv.difference_update(*(G.neighbor_iterator(u, closed=True) - for u in D_end if u != v)) + priv.difference_update(*(G.neighbor_iterator(u, closed=True) for u in D_start if u != v)) + priv.difference_update(*(G.neighbor_iterator(u, closed=True) for u in D_end if u != v)) # Now priv is the private neighborhood of v in G wrt D_start + D_end if priv.intersection(V_prev) != set(): # if v has a private in V_prev, we keep it @@ -769,8 +761,7 @@ def _aux_with_rep(H, to_dom, u_next): for w in H.neighbor_iterator(u_next): remains_to_dom = set(to_dom) - remains_to_dom.difference_update( - H.neighbor_iterator(w, closed=True)) + remains_to_dom.difference_update(H.neighbor_iterator(w, closed=True)) # Here again we recurse on a smaller instance at it # excludes u_next (and w) for Q in H.minimal_dominating_sets(remains_to_dom): @@ -782,6 +773,7 @@ def _aux_with_rep(H, to_dom, u_next): if not H.is_redundant(ext): yield (ext, cand_ext_index) cand_ext_index += 1 + # # End of aux_with_rep routine @@ -980,6 +972,7 @@ def minimal_dominating_sets(G, to_dominate=None, work_on_copy=True, k=1): sage: {3, 'A'} in L True """ + def tree_search(H, plng, dom, i): r""" Enumerate minimal dominating sets recursively. @@ -1023,23 +1016,21 @@ def tree_search(H, plng, dom, i): return # Otherwise, V_next - is what we have to dominate - to_dom = V_next - set().union( - *(G.neighbor_iterator(vert, closed=True) - for vert in dom)) + to_dom = V_next - set().union(*(G.neighbor_iterator(vert, closed=True) for vert in dom)) for can_ext in _cand_ext_enum(H, to_dom, u_next): # We complete dom with can_ext -> canD canD = set().union(can_ext, dom) - if (not H.is_redundant(canD, V_next) - and set(dom) == set(_parent(H, canD, plng[i][1]))): + if not H.is_redundant(canD, V_next) and set(dom) == set(_parent(H, canD, plng[i][1])): # By construction, can_ext is a dominating set of # `V_next - N[dom]`, so canD dominates V_next. # If canD is a legitimate child of dom and is not redundant, we # recurse on it: for Di in tree_search(H, plng, canD, i + 1): yield Di + ## # end of tree-search routine @@ -1070,8 +1061,7 @@ def tree_search(H, plng, dom, i): # at distance at most k in G H = G.__class__(G.order()) for u, ui in vertex_to_int.items(): - H.add_edges((ui, vertex_to_int[v]) - for v in G.breadth_first_search(u, distance=k) if u != v) + H.add_edges((ui, vertex_to_int[v]) for v in G.breadth_first_search(u, distance=k) if u != v) G = H elif work_on_copy: G = G.relabel(perm=vertex_to_int, inplace=False) @@ -1089,6 +1079,7 @@ def tree_search(H, plng, dom, i): # Greedy heuristic for dominating set # ============================================================================== + def greedy_dominating_set(G, k=1, vertices=None, ordering=None, return_sets=False, closest=False): r""" Return a greedy distance-`k` dominating set of the graph. @@ -1247,6 +1238,7 @@ def greedy_dominating_set(G, k=1, vertices=None, ordering=None, return_sets=Fals if closest: # Attach each dominated vertex to its closest dominator from sage.rings.infinity import Infinity + dominator = {u: (u, +Infinity) for u in vertices} for u in vertices: if u in seen: @@ -1354,6 +1346,4 @@ def maximum_leaf_number(G, solver=None, verbose=0, integrality_tolerance=1e-3): raise ValueError('the graph must be connected') if G.order() <= 3: return G.order() - 1 - return G.order() - dominating_set(G, connected=True, value_only=True, - solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + return G.order() - dominating_set(G, connected=True, value_only=True, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) diff --git a/src/sage/graphs/dot2tex_utils.py b/src/sage/graphs/dot2tex_utils.py index b827f07d6c1..6d3f0ce1e27 100644 --- a/src/sage/graphs/dot2tex_utils.py +++ b/src/sage/graphs/dot2tex_utils.py @@ -1,6 +1,7 @@ r""" This file contains some utility functions for the interface with dot2tex """ + # **************************************************************************** # Copyright (C) 2010 Nicolas M. Thiery # @@ -29,6 +30,7 @@ def have_dot2tex() -> bool: """ try: import dot2tex + # Test for this required feature from dot2tex 2.8.7 return dot2tex.dot2tex("graph {}", format='positions') == {} except (Exception, SystemExit): @@ -97,4 +99,4 @@ def quoted_str(x): [0 1]\n\ [0 0] """ - return re.sub("\n", r"\\n\\"+"\n", re.sub("\"|\r|}|{", "", str(x))) + return re.sub("\n", r"\\n\\" + "\n", re.sub("\"|\r|}|{", "", str(x))) diff --git a/src/sage/graphs/generators/basic.py b/src/sage/graphs/generators/basic.py index 9deacb82618..de1dac16305 100644 --- a/src/sage/graphs/generators/basic.py +++ b/src/sage/graphs/generators/basic.py @@ -3,6 +3,7 @@ The methods defined here appear in :mod:`sage.graphs.graph_generators`. """ + # **************************************************************************** # Copyright (C) 2006 Robert L. Miller # and Emily A. Kirkman @@ -97,8 +98,7 @@ def BullGraph(immutable=False): """ edge_list = [(0, 1), (0, 2), (1, 2), (1, 3), (2, 4)] pos_dict = {0: (0, 0), 1: (-1, 1), 2: (1, 1), 3: (-2, 2), 4: (2, 2)} - return Graph([range(5), edge_list], format='vertices_and_edges', - immutable=immutable, pos=pos_dict, name="Bull graph") + return Graph([range(5), edge_list], format='vertices_and_edges', immutable=immutable, pos=pos_dict, name="Bull graph") def ButterflyGraph(immutable=False): @@ -156,19 +156,9 @@ def ButterflyGraph(immutable=False): sage: graphs.ButterflyGraph(immutable=True).is_immutable() True """ - edge_dict = { - 0: [3, 4], - 1: [2, 4], - 2: [4], - 3: [4]} - pos_dict = { - 0: [-1, 1], - 1: [1, 1], - 2: [1, -1], - 3: [-1, -1], - 4: [0, 0]} - return Graph(edge_dict, format='dict_of_lists', - immutable=immutable, pos=pos_dict, name="Butterfly graph") + edge_dict = {0: [3, 4], 1: [2, 4], 2: [4], 3: [4]} + pos_dict = {0: [-1, 1], 1: [1, 1], 2: [1, -1], 3: [-1, -1], 4: [0, 0]} + return Graph(edge_dict, format='dict_of_lists', immutable=immutable, pos=pos_dict, name="Butterfly graph") def CircularLadderGraph(n, immutable=False): @@ -226,17 +216,16 @@ def CircularLadderGraph(n, immutable=False): True """ from itertools import chain + edges_1 = zip(range(n), chain(range(1, n), (0,))) edges_2 = zip(range(n, 2 * n), chain(range(n + 1, 2 * n), (n,))) edges_3 = ((i, i + n) for i in range(n)) - G = Graph([range(2 * n), chain(edges_1, edges_2, edges_3)], - format='vertices_and_edges', immutable=immutable, - name="Circular Ladder graph") - G._circle_embedding(list(range(n)), radius=1, angle=pi/2) + G = Graph([range(2 * n), chain(edges_1, edges_2, edges_3)], format='vertices_and_edges', immutable=immutable, name="Circular Ladder graph") + G._circle_embedding(list(range(n)), radius=1, angle=pi / 2) if n == 2: - G._circle_embedding(list(range(4)), radius=1, angle=pi/2 + pi/8) + G._circle_embedding(list(range(4)), radius=1, angle=pi / 2 + pi / 8) else: - G._circle_embedding(list(range(n, 2*n)), radius=2, angle=pi/2) + G._circle_embedding(list(range(n, 2 * n)), radius=2, angle=pi / 2) return G @@ -275,8 +264,7 @@ def ClawGraph(immutable=False): """ edge_list = [(0, 1), (0, 2), (0, 3)] pos_dict = {0: (0, 1), 1: (-1, 0), 2: (0, 0), 3: (1, 0)} - return Graph([range(4), edge_list], format='vertices_and_edges', - immutable=immutable, pos=pos_dict, name="Claw graph") + return Graph([range(4), edge_list], format='vertices_and_edges', immutable=immutable, pos=pos_dict, name="Claw graph") def CycleGraph(n, immutable=False): @@ -369,13 +357,13 @@ def CycleGraph(n, immutable=False): raise ValueError("parameter n must be a positive integer") from itertools import chain + edges = zip(range(n), chain(range(1, n), (0,))) if n > 1 else [] - G = Graph([range(n), edges], format='vertices_and_edges', - immutable=immutable, name="Cycle graph") + G = Graph([range(n), edges], format='vertices_and_edges', immutable=immutable, name="Cycle graph") if n == 1: G.set_pos({0: (0, 0)}) else: - G._circle_embedding(list(range(n)), angle=pi/2) + G._circle_embedding(list(range(n)), angle=pi / 2) return G @@ -474,13 +462,12 @@ def CompleteGraph(n, immutable=False): True """ from itertools import combinations - G = Graph([range(n), combinations(range(n), 2)], - format='vertices_and_edges', immutable=immutable, - name="Complete graph") + + G = Graph([range(n), combinations(range(n), 2)], format='vertices_and_edges', immutable=immutable, name="Complete graph") if n == 1: G.set_pos({0: (0, 0)}) else: - G._circle_embedding(list(range(n)), angle=pi/2) + G._circle_embedding(list(range(n)), angle=pi / 2) return G @@ -548,8 +535,7 @@ def CorrelationGraph(seqs, alpha, include_anticorrelation, immutable=False): adjacency_matrix = Matrix(boolean_adjacency_matrix.astype(int)) # call graph constructor - return Graph(adjacency_matrix, format='adjacency_matrix', - immutable=immutable, name="Correlation Graph") + return Graph(adjacency_matrix, format='adjacency_matrix', immutable=immutable, name="Correlation Graph") def CompleteBipartiteGraph(p, q, set_position=True, immutable=False, name=None): @@ -685,8 +671,7 @@ def CompleteBipartiteGraph(p, q, set_position=True, immutable=False, name=None): name = f"Complete bipartite graph of order {p}+{q}" if name is None else name edges = ((i, j) for i in range(p) for j in range(p, p + q)) - G = Graph([range(p + q), edges], format='vertices_and_edges', - immutable=immutable, name=name) + G = Graph([range(p + q), edges], format='vertices_and_edges', immutable=immutable, name=name) # We now assign positions to vertices: # - vertices 0,..,p-1 are placed on the line (0, 1) to (max(p, q), 1) @@ -770,8 +755,7 @@ def CompleteMultipartiteGraph(L, immutable=False): # This position code gives bad results on bipartite or isolated graphs points = [(cos(2 * pi * i / r), sin(2 * pi * i / r)) for i in range(r)] - slopes = [(points[(i + 1) % r][0] - points[i % r][0], - points[(i + 1) % r][1] - points[i % r][1]) for i in range(r)] + slopes = [(points[(i + 1) % r][0] - points[i % r][0], points[(i + 1) % r][1] - points[i % r][1]) for i in range(r)] counter = 0 parts = [] @@ -786,9 +770,9 @@ def CompleteMultipartiteGraph(L, immutable=False): counter += 1 from itertools import combinations + edges = ((a, b) for A, B in combinations(parts, 2) for a in A for b in B) - return Graph([range(counter), edges], format='vertices_and_edges', - immutable=immutable, pos=positions, name=name) + return Graph([range(counter), edges], format='vertices_and_edges', immutable=immutable, pos=positions, name=name) def DiamondGraph(immutable=False): @@ -823,8 +807,7 @@ def DiamondGraph(immutable=False): """ pos_dict = {0: (0, 1), 1: (-1, 0), 2: (1, 0), 3: (0, -1)} edges = [(0, 1), (0, 2), (1, 2), (1, 3), (2, 3)] - return Graph([range(4), edges], format='vertices_and_edges', - immutable=immutable, pos=pos_dict, name="Diamond Graph") + return Graph([range(4), edges], format='vertices_and_edges', immutable=immutable, pos=pos_dict, name="Diamond Graph") def GemGraph(immutable=False): @@ -858,8 +841,7 @@ def GemGraph(immutable=False): """ pos_dict = {0: (0.5, 0), 1: (0, 0.75), 2: (0.25, 1), 3: (0.75, 1), 4: (1, 0.75)} edges = [(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (2, 3), (3, 4)] - return Graph([range(5), edges], format='vertices_and_edges', - immutable=immutable, pos=pos_dict, name="Gem Graph") + return Graph([range(5), edges], format='vertices_and_edges', immutable=immutable, pos=pos_dict, name="Gem Graph") def ForkGraph(immutable=False): @@ -893,8 +875,7 @@ def ForkGraph(immutable=False): """ pos_dict = {0: (0, 0), 1: (1, 0), 2: (0, 1), 3: (1, 1), 4: (0, 2)} edges = [(0, 2), (2, 3), (3, 1), (2, 4)] - return Graph([range(5), edges], format='vertices_and_edges', - immutable=immutable, pos=pos_dict, name="Fork Graph") + return Graph([range(5), edges], format='vertices_and_edges', immutable=immutable, pos=pos_dict, name="Fork Graph") def DartGraph(immutable=False): @@ -926,8 +907,7 @@ def DartGraph(immutable=False): """ pos_dict = {0: (0, 1), 1: (-1, 0), 2: (1, 0), 3: (0, -1), 4: (0, 0)} edges = [(0, 1), (0, 2), (1, 4), (2, 4), (0, 4), (3, 4)] - return Graph([range(5), edges], format='vertices_and_edges', - immutable=immutable, pos=pos_dict, name="Dart Graph") + return Graph([range(5), edges], format='vertices_and_edges', immutable=immutable, pos=pos_dict, name="Dart Graph") def EmptyGraph(immutable=False): @@ -1026,8 +1006,8 @@ def ToroidalGrid2dGraph(p, q, immutable=False): g.add_edges([((0, i), (p - 1, i)) for i in range(q)]) pos = g._pos - p += 0. - q += 0. + p += 0.0 + q += 0.0 uf = (p / 2) * (p / 2) vf = (q / 2) * (q / 2) for u, v in g: @@ -1176,14 +1156,12 @@ def Grid2dGraph(p, q, set_positions=True, immutable=False, name=None): vertices = ((i, j) for i in range(p) for j in range(q)) from itertools import chain - edges = chain((((i, j), (i + 1, j)) for i in range(p - 1) for j in range(q)), - (((i, j), (i, j + 1)) for i in range(p) for j in range(q - 1))) + + edges = chain((((i, j), (i + 1, j)) for i in range(p - 1) for j in range(q)), (((i, j), (i, j + 1)) for i in range(p) for j in range(q - 1))) pos_dict = None if set_positions: pos_dict = {(i, j): (j, -i) for i in range(p) for j in range(q)} - return Graph([vertices, edges], format='vertices_and_edges', - immutable=immutable, pos=pos_dict, - name=f"2D Grid Graph for [{p}, {q}]" if name is None else name) + return Graph([vertices, edges], format='vertices_and_edges', immutable=immutable, pos=pos_dict, name=f"2D Grid Graph for [{p}, {q}]" if name is None else name) def GridGraph(dim_list, immutable=False): @@ -1303,6 +1281,7 @@ def GridGraph(dim_list, immutable=False): def edges(): from itertools import product + for u in product(*[range(d) for d in dim]): for i in range(n_dim): if u[i] + 1 < dim[i]: @@ -1310,8 +1289,7 @@ def edges(): v[i] = u[i] + 1 yield (u, tuple(v)) - return Graph([V, edges()], format='vertices_and_edges', - immutable=immutable, name=name) + return Graph([V, edges()], format='vertices_and_edges', immutable=immutable, name=name) def HouseGraph(immutable=False): @@ -1350,8 +1328,7 @@ def HouseGraph(immutable=False): """ pos_dict = {0: (-1, 0), 1: (1, 0), 2: (-1, 1), 3: (1, 1), 4: (0, 2)} edges = [(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)] - return Graph([range(5), edges], format='vertices_and_edges', - immutable=immutable, pos=pos_dict, name="House Graph") + return Graph([range(5), edges], format='vertices_and_edges', immutable=immutable, pos=pos_dict, name="House Graph") def HouseXGraph(immutable=False): @@ -1391,8 +1368,7 @@ def HouseXGraph(immutable=False): """ pos_dict = {0: (-1, 0), 1: (1, 0), 2: (-1, 1), 3: (1, 1), 4: (0, 2)} edges = [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3), (2, 4), (3, 4)] - return Graph([range(5), edges], format='vertices_and_edges', - immutable=immutable, pos=pos_dict, name="House Graph") + return Graph([range(5), edges], format='vertices_and_edges', immutable=immutable, pos=pos_dict, name="House Graph") def LadderGraph(n, immutable=False): @@ -1448,12 +1424,11 @@ def LadderGraph(n, immutable=False): x = i - n pos_dict[i] = (x, 0) from itertools import chain + edges_1 = zip(range(n), range(1, n)) edges_2 = zip(range(n, 2 * n), range(n + 1, 2 * n)) edges_3 = ((i, i + n) for i in range(n)) - return Graph([range(2 * n), chain(edges_1, edges_2, edges_3)], - format='vertices_and_edges', immutable=immutable, - pos=pos_dict, name="Ladder graph") + return Graph([range(2 * n), chain(edges_1, edges_2, edges_3)], format='vertices_and_edges', immutable=immutable, pos=pos_dict, name="Ladder graph") def MoebiusLadderGraph(n, immutable=False): @@ -1541,12 +1516,11 @@ def MoebiusLadderGraph(n, immutable=False): raise ValueError("parameter n must be a nonnegative integer") from itertools import chain + edges_1 = zip(range(2 * n), chain(range(1, 2 * n), (0,))) edges_2 = ((i, i + n) for i in range(n)) - G = Graph([range(2 * n), chain(edges_1, edges_2)], - format='vertices_and_edges', immutable=immutable, - name="Moebius ladder graph") - G._circle_embedding(list(range(2 * n)), angle=pi/2) + G = Graph([range(2 * n), chain(edges_1, edges_2)], format='vertices_and_edges', immutable=immutable, name="Moebius ladder graph") + G._circle_embedding(list(range(2 * n)), angle=pi / 2) return G @@ -1618,8 +1592,7 @@ def PathGraph(n, pos=None, immutable=False, name=None): foo: Graph on 4 vertices """ edges = ((i, i + 1) for i in range(n - 1)) - G = Graph([range(n), edges], format='vertices_and_edges', - immutable=immutable, name="Path graph" if name is None else name) + G = Graph([range(n), edges], format='vertices_and_edges', immutable=immutable, name="Path graph" if name is None else name) pos_dict = {} @@ -1638,7 +1611,7 @@ def PathGraph(n, pos=None, immutable=False, name=None): if n == 1: G.set_pos({0: (0, 0)}) else: - G._circle_embedding(list(range(n)), angle=pi/2) + G._circle_embedding(list(range(n)), angle=pi / 2) # Draw 'line' else: counter = 0 # node index @@ -1755,8 +1728,7 @@ def StarGraph(n, immutable=False): sage: graphs.StarGraph(4, immutable=True).is_immutable() True """ - G = Graph({0: list(range(1, n + 1))}, format='dict_of_lists', - immutable=immutable, name="Star graph") + G = Graph({0: list(range(1, n + 1))}, format='dict_of_lists', immutable=immutable, name="Star graph") G.set_pos({0: (0, 0)}) - G._circle_embedding(list(range(1, n + 1)), angle=pi/2) + G._circle_embedding(list(range(1, n + 1)), angle=pi / 2) return G diff --git a/src/sage/graphs/generators/chessboard.py b/src/sage/graphs/generators/chessboard.py index aac1c45cfbd..80cb6e7558c 100644 --- a/src/sage/graphs/generators/chessboard.py +++ b/src/sage/graphs/generators/chessboard.py @@ -26,10 +26,7 @@ from sage.graphs.graph import Graph -def ChessboardGraphGenerator(dim_list, rook=True, rook_radius=None, - bishop=True, bishop_radius=None, - knight=True, knight_x=1, knight_y=2, - relabel=False, immutable=False): +def ChessboardGraphGenerator(dim_list, rook=True, rook_radius=None, bishop=True, bishop_radius=None, knight=True, knight_x=1, knight_y=2, relabel=False, immutable=False): r""" Return a Graph built on a `d`-dimensional chessboard with prescribed dimensions and interconnections. @@ -248,8 +245,7 @@ def edges(): else: G.relabel(inplace=True) else: - G = Graph([V, edges()], format="vertices_and_edges", - immutable=immutable) + G = Graph([V, edges()], format="vertices_and_edges", immutable=immutable) return G, dimstr @@ -317,12 +313,7 @@ def QueenGraph(dim_list, radius=None, relabel=False, immutable=False): ....: if not G.is_isomorphic(H): ....: print("that's not good!") """ - G, dimstr = ChessboardGraphGenerator(dim_list, - rook=True, rook_radius=radius, - bishop=True, bishop_radius=radius, - knight=False, - relabel=relabel, - immutable=immutable) + G, dimstr = ChessboardGraphGenerator(dim_list, rook=True, rook_radius=radius, bishop=True, bishop_radius=radius, knight=False, relabel=relabel, immutable=immutable) if radius is None: G._name = f"{dimstr}-Queen Graph" else: @@ -385,12 +376,7 @@ def KingGraph(dim_list, radius=None, relabel=False, immutable=False): """ rook_radius = 1 if radius is None else radius bishop_radius = 1 if radius is None else radius - G, dimstr = ChessboardGraphGenerator(dim_list, - rook=True, rook_radius=rook_radius, - bishop=True, bishop_radius=bishop_radius, - knight=False, - relabel=relabel, - immutable=immutable) + G, dimstr = ChessboardGraphGenerator(dim_list, rook=True, rook_radius=rook_radius, bishop=True, bishop_radius=bishop_radius, knight=False, relabel=relabel, immutable=immutable) if radius is None: G._name = f"{dimstr}-King Graph" else: @@ -450,10 +436,7 @@ def KnightGraph(dim_list, one=1, two=2, relabel=False, immutable=False): sage: G.is_hamiltonian() # needs sage.numerical.mip True """ - G, dimstr = ChessboardGraphGenerator(dim_list, - rook=False, bishop=False, - knight=True, knight_x=one, knight_y=two, - relabel=relabel, immutable=immutable) + G, dimstr = ChessboardGraphGenerator(dim_list, rook=False, bishop=False, knight=True, knight_x=one, knight_y=two, relabel=relabel, immutable=immutable) if one + two == 3: G._name = f"{dimstr}-Knight Graph" else: @@ -509,10 +492,7 @@ def RookGraph(dim_list, radius=None, relabel=False, immutable=False): sage: G.is_isomorphic( H ) True """ - G, dimstr = ChessboardGraphGenerator(dim_list, - rook=True, rook_radius=radius, - bishop=False, knight=False, - relabel=relabel, immutable=immutable) + G, dimstr = ChessboardGraphGenerator(dim_list, rook=True, rook_radius=radius, bishop=False, knight=False, relabel=relabel, immutable=immutable) if radius is None: G._name = f"{dimstr}-Rook Graph" else: @@ -567,10 +547,7 @@ def BishopGraph(dim_list, radius=None, relabel=False, immutable=False): ....: if not B.is_isomorphic(H): ....: print("that's not good!") """ - G, dimstr = ChessboardGraphGenerator(dim_list, - rook=False, knight=False, - bishop=True, bishop_radius=radius, - relabel=relabel, immutable=immutable) + G, dimstr = ChessboardGraphGenerator(dim_list, rook=False, knight=False, bishop=True, bishop_radius=radius, relabel=relabel, immutable=immutable) if radius is None: G._name = f"{dimstr}-Bishop Graph" else: diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index 27b90aee54b..99771097e56 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -88,27 +88,22 @@ def SymplecticPolarGraph(d, q, algorithm=None, immutable=False): raise ValueError("d must be even and greater than 2") name = f"Symplectic Polar Graph Sp({d},{q})" - if algorithm == "gap": # faster for larger (q>3) fields + if algorithm == "gap": # faster for larger (q>3) fields from sage.libs.gap.libgap import libgap - return _polar_graph(d, q, libgap.SymplecticGroup(d, q), - immutable=immutable, name=name, relabel=True) - if algorithm is None: # faster for small (q<4) fields + return _polar_graph(d, q, libgap.SymplecticGroup(d, q), immutable=immutable, name=name, relabel=True) + + if algorithm is None: # faster for small (q<4) fields from sage.modules.free_module import VectorSpace from sage.schemes.projective.projective_space import ProjectiveSpace from sage.matrix.constructor import identity_matrix, block_matrix, zero_matrix F = FiniteField(q, "x") - M = block_matrix(F, 2, 2, - [zero_matrix(F, d/2), - identity_matrix(F, d/2), - -identity_matrix(F, d/2), - zero_matrix(F, d/2)]) + M = block_matrix(F, 2, 2, [zero_matrix(F, d / 2), identity_matrix(F, d / 2), -identity_matrix(F, d / 2), zero_matrix(F, d / 2)]) V = VectorSpace(F, d) PV = [tuple(_) for _ in ProjectiveSpace(d - 1, F)] - return Graph([range(len(PV)), lambda i, j: V(PV[i])*(M*V(PV[j])) == 0], - format="rule", loops=False, name=name, immutable=immutable) + return Graph([range(len(PV)), lambda i, j: V(PV[i]) * (M * V(PV[j])) == 0], format="rule", loops=False, name=name, immutable=immutable) raise ValueError(f"unknown algorithm: {algorithm}") @@ -197,16 +192,12 @@ def AffineOrthogonalPolarGraph(d, q, sign='+', immutable=False): V = list(VectorSpace(F, d)) Vi = {tuple(x): i for i, x in enumerate(V)} - edges = ((Vi[tuple(x)], Vi[tuple(y)]) - for x, y in combinations(V, 2) - if not (x - y)*M*(x - y)) + edges = ((Vi[tuple(x)], Vi[tuple(y)]) for x, y in combinations(V, 2) if not (x - y) * M * (x - y)) name = f"Affine Polar Graph VO^{'+' if s == 1 else '-'}({d},{q})" - return Graph([range(len(V)), edges], format="vertices_and_edges", - name=name, immutable=immutable) + return Graph([range(len(V)), edges], format="vertices_and_edges", name=name, immutable=immutable) -def _orthogonal_polar_graph(m, q, sign='+', point_type=[0], immutable=False, - name=None): +def _orthogonal_polar_graph(m, q, sign='+', point_type=[0], immutable=False, name=None): r""" A helper function to build ``OrthogonalPolarGraph`` and ``NO2,3,5`` graphs. @@ -297,17 +288,13 @@ def _orthogonal_polar_graph(m, q, sign='+', point_type=[0], immutable=False, if not m % 2: if sign != "+" and sign != "-": - raise ValueError("sign must be equal to either '-' or '+' when " - "m is even") + raise ValueError("sign must be equal to either '-' or '+' when " "m is even") else: if sign != "" and sign != "+": - raise ValueError("sign must be equal to either '' or '+' when " - "m is odd") + raise ValueError("sign must be equal to either '' or '+' when " "m is odd") sign = "" - e = {'+': 1, - '-': -1, - '': 0}[sign] + e = {'+': 1, '-': -1, '': 0}[sign] M = Matrix(libgap.InvariantQuadraticForm(libgap.GeneralOrthogonalGroup(e, m, q))['matrix']) Fq = libgap.GF(q).sage() @@ -317,19 +304,21 @@ def _orthogonal_polar_graph(m, q, sign='+', point_type=[0], immutable=False, v.set_immutable() def F(x): - return x*M*x + return x * M * x if not q % 2: + def P(x, y): return F(x - y) + else: + def P(x, y): - return x*M*y + y*M*x + return x * M * y + y * M * x V = [x for x in PG if F(x) in point_type] - return Graph([range(len(V)), lambda i, j: P(V[i], V[j]) == 0], - format="rule", loops=False, immutable=immutable, name=name) + return Graph([range(len(V)), lambda i, j: P(V[i], V[j]) == 0], format="rule", loops=False, immutable=immutable, name=name) def OrthogonalPolarGraph(m, q, sign='+', immutable=False): @@ -390,8 +379,7 @@ def OrthogonalPolarGraph(m, q, sign='+', immutable=False): return G -def NonisotropicOrthogonalPolarGraph(m, q, sign='+', perp=None, - immutable=False): +def NonisotropicOrthogonalPolarGraph(m, q, sign='+', perp=None, immutable=False): r""" Return the Graph `NO^{\epsilon,\perp}_{m}(q)`. @@ -511,15 +499,13 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign='+', perp=None, dec = '' if not m % 2: if q in [2, 3]: - G = _orthogonal_polar_graph(m, q, sign=sign, point_type=[1], - immutable=immutable) + G = _orthogonal_polar_graph(m, q, sign=sign, point_type=[1], immutable=immutable) else: raise ValueError("for m even q must be 2 or 3") elif perp is not None: if q == 5: pt = [-1, 1] if sign == '+' else [2, 3] if sign == '-' else [] - G = _orthogonal_polar_graph(m, q, point_type=pt, - immutable=immutable) + G = _orthogonal_polar_graph(m, q, point_type=pt, immutable=immutable) dec = ",perp" else: raise ValueError("for perp not None q must be 5") @@ -527,25 +513,23 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign='+', perp=None, if sign not in ['+', '-']: raise ValueError("sign must be '+' or '-'") from sage.libs.gap.libgap import libgap + g0 = libgap.GeneralOrthogonalGroup(m, q) g = libgap.Group(libgap.List(g0.GeneratorsOfGroup(), libgap.TransposedMat)) F = libgap.GF(q) # F_q W = libgap.FullRowSpace(F, m) # F_q^m e = 1 if sign == '+' else -1 - n = (m - 1)/2 + n = (m - 1) / 2 # we build (q^n(q^n+e)/2, (q^n-e)(q^(n-1)+e), 2(q^(2n-2)-1)+eq^(n-1)(q-1), # 2q^(n-1)(q^(n-1)+e))-srg # **use** v and k to select appropriate orbit and orbital - nvert = (q**n)*(q**n + e)/2 # v - deg = (q**n - e)*(q**(n - 1) + e) # k - S = [libgap.Elements(libgap.Basis(x))[0] - for x in libgap.Elements(libgap.Subspaces(W, 1))] - (V,) = (x for x in libgap.Orbits(g, S, libgap.OnLines) - if len(x) == nvert) + nvert = (q**n) * (q**n + e) / 2 # v + deg = (q**n - e) * (q ** (n - 1) + e) # k + S = [libgap.Elements(libgap.Basis(x))[0] for x in libgap.Elements(libgap.Subspaces(W, 1))] + (V,) = (x for x in libgap.Orbits(g, S, libgap.OnLines) if len(x) == nvert) gp = libgap.Action(g, V, libgap.OnLines) # make a permutation group h = libgap.Stabilizer(gp, 1) - (Vh,) = (x for x in libgap.Orbits(h, libgap.Orbit(gp, 1)) - if len(x) == deg) + (Vh,) = (x for x in libgap.Orbits(h, libgap.Orbit(gp, 1)) if len(x) == deg) Vh = Vh[0] L = libgap.Orbit(gp, [1, Vh], libgap.OnSets) G = Graph(L, format="list_of_edges", immutable=immutable) @@ -553,8 +537,7 @@ def NonisotropicOrthogonalPolarGraph(m, q, sign='+', perp=None, return G -def _polar_graph(m, q, g, intersection_size=None, immutable=False, name=None, - relabel=False): +def _polar_graph(m, q, g, intersection_size=None, immutable=False, name=None, relabel=False): r""" The helper function to build graphs `(D)U(m,q)` and `(D)Sp(m,q)`. @@ -611,31 +594,28 @@ def _polar_graph(m, q, g, intersection_size=None, immutable=False, name=None, True """ from sage.libs.gap.libgap import libgap - W = libgap.FullRowSpace(libgap.GF(q), m) # F_q^m - B = libgap.Elements(libgap.Basis(W)) # the standard basis of W + + W = libgap.FullRowSpace(libgap.GF(q), m) # F_q^m + B = libgap.Elements(libgap.Basis(W)) # the standard basis of W V = libgap.Orbit(g, B[0], libgap.OnLines) # orbit on isotropic points - gp = libgap.Action(g, V, libgap.OnLines) # make a permutation group - s = libgap.Subspace(W, [B[i] for i in range(m//2)]) # a totally isotropic subspace + gp = libgap.Action(g, V, libgap.OnLines) # make a permutation group + s = libgap.Subspace(W, [B[i] for i in range(m // 2)]) # a totally isotropic subspace # and the points there sp = [libgap.Elements(libgap.Basis(x))[0] for x in libgap.Elements(s.Subspaces(1))] h = libgap.Set([libgap.Position(V, x) for x in sp]) # indices of the points in s L = libgap.Orbit(gp, h, libgap.OnSets) # orbit on these subspaces if intersection_size is None: from itertools import chain + # every pair of points in the subspace is adjacent to each other in G if relabel: vertices = set(chain.from_iterable(L)) v_to_i = {u: i for i, u in enumerate(vertices)} L = [[v_to_i[u] for u in x] for x in L] - return Graph(chain.from_iterable(combinations(x, 2) for x in L), - format="list_of_edges", loops=False, immutable=immutable, - name=name) + return Graph(chain.from_iterable(combinations(x, 2) for x in L), format="list_of_edges", loops=False, immutable=immutable, name=name) if relabel: - return Graph([range(len(L)), - lambda i, j: libgap.Size(libgap.Intersection(L[i], L[j])) == intersection_size], - format="rule", loops=False, immutable=immutable, name=name) - return Graph([L, lambda i, j: libgap.Size(libgap.Intersection(i, j)) == intersection_size], - format="rule", loops=False, immutable=immutable, name=name) + return Graph([range(len(L)), lambda i, j: libgap.Size(libgap.Intersection(L[i], L[j])) == intersection_size], format="rule", loops=False, immutable=immutable, name=name) + return Graph([L, lambda i, j: libgap.Size(libgap.Intersection(i, j)) == intersection_size], format="rule", loops=False, immutable=immutable, name=name) def UnitaryPolarGraph(m, q, algorithm='gap', immutable=False): @@ -687,12 +667,13 @@ def UnitaryPolarGraph(m, q, algorithm='gap', immutable=False): if algorithm == "gap": from sage.libs.gap.libgap import libgap - return _polar_graph(m, q**2, libgap.GeneralUnitaryGroup(m, q), - name=name, immutable=immutable, relabel=True) + + return _polar_graph(m, q**2, libgap.GeneralUnitaryGroup(m, q), name=name, immutable=immutable, relabel=True) if algorithm is None: # slow on large examples from sage.schemes.projective.projective_space import ProjectiveSpace from sage.modules.free_module_element import free_module_element as vector + Fq = FiniteField(q**2, 'a') PG = map(vector, ProjectiveSpace(m - 1, Fq)) @@ -704,8 +685,7 @@ def P(x, y): V = [x for x in PG if P(x, x)] # bottleneck is here, of course - return Graph([range(len(V)), lambda x, y: P(V[x], V[y])], format="rule", - loops=False, name=name, immutable=immutable) + return Graph([range(len(V)), lambda x, y: P(V[x], V[y])], format="rule", loops=False, name=name, immutable=immutable) raise ValueError(f"unknown algorithm: {algorithm}") @@ -749,16 +729,17 @@ def NonisotropicUnitaryPolarGraph(m, q, immutable=False): if not k: raise ValueError('q must be a prime power') from sage.libs.gap.libgap import libgap + F = libgap.GF(q**2) # F_{q^2} W = libgap.FullRowSpace(F, m) # F_{q^2}^m B = libgap.Elements(libgap.Basis(W)) # the standard basis of W if m % 2: - point = B[(m - 1)/2] + point = B[(m - 1) / 2] else: if p == 2: - point = B[m/2] + F.PrimitiveRoot()*B[(m - 2)/2] + point = B[m / 2] + F.PrimitiveRoot() * B[(m - 2) / 2] else: - point = B[(m - 2)/2] + B[m/2] + point = B[(m - 2) / 2] + B[m / 2] g = libgap.GeneralUnitaryGroup(m, q) V = libgap.Orbit(g, point, libgap.OnLines) # orbit on nonisotropic points gp = libgap.Action(g, V, libgap.OnLines) # make a permutation group @@ -767,17 +748,15 @@ def NonisotropicUnitaryPolarGraph(m, q, immutable=False): # and the points there sp = [libgap.Elements(libgap.Basis(x))[0] for x in libgap.Elements(s.Subspaces(1))] - h = libgap.Set([libgap.Position(V, x) - for x in libgap.Intersection(V, sp)]) # indices + h = libgap.Set([libgap.Position(V, x) for x in libgap.Intersection(V, sp)]) # indices L = libgap.Orbit(gp, h, libgap.OnSets) # orbit on the tangent lines from itertools import chain + vertices = set(chain.from_iterable(L)) v_to_i = {u: i for i, u in enumerate(vertices)} L = [[v_to_i[u] for u in x] for x in L] - return Graph(chain.from_iterable(combinations(x, 2) for x in L), - format="list_of_edges", immutable=immutable, - name=f"NU{(m, q)}") + return Graph(chain.from_iterable(combinations(x, 2) for x in L), format="list_of_edges", immutable=immutable, name=f"NU{(m, q)}") def UnitaryDualPolarGraph(m, q, immutable=False): @@ -826,14 +805,13 @@ def UnitaryDualPolarGraph(m, q, immutable=False): GAPError: Error, must be a prime or a finite field """ from sage.libs.gap.libgap import libgap + name = "Unitary Dual Polar Graph DU" + str((m, q)) if m == 4: name += '; GQ' + str((q, q**2)) if m == 5: name += '; GQ' + str((q**3, q**2)) - return _polar_graph(m, q**2, libgap.GeneralUnitaryGroup(m, q), - intersection_size=int((q**(2*(m//2 - 1)) - 1)/(q**2 - 1)), - name=name, immutable=immutable, relabel=True) + return _polar_graph(m, q**2, libgap.GeneralUnitaryGroup(m, q), intersection_size=int((q ** (2 * (m // 2 - 1)) - 1) / (q**2 - 1)), name=name, immutable=immutable, relabel=True) def SymplecticDualPolarGraph(m, q, immutable=False): @@ -869,12 +847,11 @@ def SymplecticDualPolarGraph(m, q, immutable=False): GAPError: Error, must be a prime or a finite field """ from sage.libs.gap.libgap import libgap + name = "Symplectic Dual Polar Graph DSp" + str((m, q)) if m == 4: name += '; GQ' + str((q, q)) - return _polar_graph(m, q, libgap.SymplecticGroup(m, q), - intersection_size=int((q**(m/2 - 1) - 1)/(q - 1)), - name=name, immutable=immutable, relabel=True) + return _polar_graph(m, q, libgap.SymplecticGroup(m, q), intersection_size=int((q ** (m / 2 - 1) - 1) / (q - 1)), name=name, immutable=immutable, relabel=True) def TaylorTwographDescendantSRG(q, clique_partition=False, immutable=False): @@ -939,6 +916,7 @@ def TaylorTwographDescendantSRG(q, clique_partition=False, immutable=False): raise ValueError('q must be an odd prime power') from sage.schemes.projective.projective_space import ProjectiveSpace from sage.rings.finite_rings.integer_mod import mod + Fq = FiniteField(q**2, 'a') PG = map(tuple, ProjectiveSpace(2, Fq)) @@ -950,14 +928,11 @@ def S(x, y): V.remove(v0) name = "Taylor two-graph descendant SRG" if mod(q, 4) == 1: - G = Graph([V, lambda y, z: not (S(v0, y)*S(y, z)*S(z, v0)).is_square()], - format="rule", loops=False, name=name, immutable=immutable) + G = Graph([V, lambda y, z: not (S(v0, y) * S(y, z) * S(z, v0)).is_square()], format="rule", loops=False, name=name, immutable=immutable) else: - G = Graph([V, lambda y, z: (S(v0, y)*S(y, z)*S(z, v0)).is_square()], - format="rule", loops=False, name=name, immutable=immutable) + G = Graph([V, lambda y, z: (S(v0, y) * S(y, z) * S(z, v0)).is_square()], format="rule", loops=False, name=name, immutable=immutable) if clique_partition: - lines = [[t for t in V if t[0] + z * t[1] == 0] - for z in Fq if z] + lines = [[t for t in V if t[0] + z * t[1] == 0] for z in Fq if z] return (G, lines, v0) return G @@ -993,7 +968,7 @@ def TaylorTwographSRG(q, immutable=False): """ G, l, v0 = TaylorTwographDescendantSRG(q, clique_partition=True) G.add_vertex(v0) - G.seidel_switching(sum(l[:(q**2 + 1)/2], [])) + G.seidel_switching(sum(l[: (q**2 + 1) / 2], [])) G.name("Taylor two-graph SRG") return G.copy(immutable=True) if immutable else G @@ -1036,6 +1011,7 @@ def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False, immutable=False): (175, 30, 5, 5) """ from sage.combinat.designs.incidence_structures import IncidenceStructure + p, k = is_prime_power(q, get_data=True) if not k or p == 2: raise ValueError('q must be an odd prime power') @@ -1046,7 +1022,7 @@ def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False, immutable=False): L.append(tuple((s, a, b) for s in F)) L.append(tuple((a, s, b) for s in F)) for c in F: - L.append(tuple((c*s**2 - b*s + a, -2*c*s + b, s) for s in F)) + L.append(tuple((c * s**2 - b * s + a, -2 * c * s + b, s) for s in F)) if dual: G = IncidenceStructure(L).intersection_graph(immutable=immutable) G._name = f"AS({q})*; GQ{(q + 1, q - 1)}" @@ -1056,8 +1032,7 @@ def AhrensSzekeresGeneralizedQuadrangleGraph(q, dual=False, immutable=False): return G -def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, - check_hyperoval=True, immutable=False): +def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, check_hyperoval=True, immutable=False): r""" Return the collinearity graph of the generalized quadrangle `T_2^*(q)`, or of its dual @@ -1147,9 +1122,7 @@ def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, Theta = PG(3, 1, F, point_coordinates=1) Pi = set(x for x in Theta.ground_set() if x[0] == F.zero()) if hyperoval is None: - HO = set(x for x in Pi - if (x[1] + x[2] * x[3] == 0) or - (x[1] == 1 and x[2] == x[3] == 0)) + HO = set(x for x in Pi if (x[1] + x[2] * x[3] == 0) or (x[1] == 1 and x[2] == x[3] == 0)) else: for v in hyperoval: v.set_immutable() @@ -1163,8 +1136,7 @@ def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, if len(HO.intersection(L)) not in [0, 2]: raise RuntimeError("incorrect hyperoval") - L = [[y for y in z if y not in HO] - for z in Theta.blocks() if len(HO.intersection(z)) == 1] + L = [[y for y in z if y not in HO] for z in Theta.blocks() if len(HO.intersection(z)) == 1] if dual: G = IncidenceStructure(L).intersection_graph(immutable=immutable) @@ -1175,8 +1147,7 @@ def T2starGeneralizedQuadrangleGraph(q, dual=False, hyperoval=None, field=None, return G -def HaemersGraph(q, hyperoval=None, hyperoval_matching=None, field=None, - check_hyperoval=True, immutable=False): +def HaemersGraph(q, hyperoval=None, hyperoval_matching=None, field=None, check_hyperoval=True, immutable=False): r""" Return the Haemers graph obtained from `T_2^*(q)^*`. @@ -1270,9 +1241,7 @@ def HaemersGraph(q, hyperoval=None, hyperoval_matching=None, field=None, F = field # for q=8, 95% of CPU time taken by this function is spent in the following call - G = T2starGeneralizedQuadrangleGraph(q, field=F, dual=True, - hyperoval=hyperoval, - check_hyperoval=check_hyperoval) + G = T2starGeneralizedQuadrangleGraph(q, field=F, dual=True, hyperoval=hyperoval, check_hyperoval=check_hyperoval) def normalize(v): # make sure the 1st non-0 coordinate is 1. d = next(x for x in v if x != F.zero()) @@ -1365,10 +1334,13 @@ def CossidentePenttilaGraph(q, immutable=False): raise ValueError('q(={}) must be an odd prime power'.format(q)) from sage.features.gap import GapPackage + GapPackage("grape", spkg='gap_packages').require() from sage.libs.gap.libgap import libgap - adj_list = libgap.function_factory("""function(q) + + adj_list = libgap.function_factory( + """function(q) local z, e, so, G, nu, G1, G0, B, T, s, O1, O2, x, sqo; LoadPackage("grape"); G0:=SO(3,q^2); @@ -1391,17 +1363,14 @@ def CossidentePenttilaGraph(q, immutable=False): G:=Graph(G1,Concatenation(O1,O2),OnSets, function(x,y) return x<>y and 0*z=T(x[1]+y[1]); end); return List([1..OrderGraph(G)],x->Adjacency(G,x)); - end;""") + end;""" + ) adj = adj_list(q) # for each vertex, we get the list of vertices it is adjacent to - return Graph(((i, int(j - 1)) - for i, ni in enumerate(adj) for j in ni), - format='list_of_edges', multiedges=False, immutable=immutable, - name=f"CossidentePenttila({q})") + return Graph(((i, int(j - 1)) for i, ni in enumerate(adj) for j in ni), format='list_of_edges', multiedges=False, immutable=immutable, name=f"CossidentePenttila({q})") -def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, - check_hyperoval=True, immutable=False): +def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, check_hyperoval=True, immutable=False): r""" Return the subgraph of nowhere 0 words from two-weight code of projective plane hyperoval. @@ -1499,9 +1468,7 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, Theta = PG(2, 1, F, point_coordinates=1) Pi = Theta.ground_set() if hyperoval is None: - hyperoval = [x for x in Pi - if (x[0] + x[1] * x[2] == 0) or - (x[0] == 1 and x[1] == x[2] == 0)] + hyperoval = [x for x in Pi if (x[0] + x[1] * x[2] == 0) or (x[0] == 1 and x[1] == x[2] == 0)] else: for v in hyperoval: v.set_immutable() @@ -1516,13 +1483,11 @@ def Nowhere0WordsTwoWeightCodeGraph(q, hyperoval=None, field=None, raise RuntimeError("incorrect hyperoval") M = matrix(hyperoval) F_0 = F.zero() - C = [p for p in [M*x for x in F**3] if F_0 not in p] + C = [p for p in [M * x for x in F**3] if F_0 not in p] for x in C: x.set_immutable() - return Graph([range(len(C)), lambda x, y: F_0 not in C[x] + C[y]], - format="rule", immutable=immutable, - name=f"Nowhere0WordsTwoWeightCodeGraph({q})") + return Graph([range(len(C)), lambda x, y: F_0 not in C[x] + C[y]], format="rule", immutable=immutable, name=f"Nowhere0WordsTwoWeightCodeGraph({q})") def OrthogonalDualPolarGraph(e, d, q, immutable=False): @@ -1588,7 +1553,7 @@ def hashable(v): if e not in {0, 1, -1}: raise ValueError("e must by 0, +1 or -1") - m = 2*d + 1 - e + m = 2 * d + 1 - e group = libgap.GeneralOrthogonalGroup(e, m, q) M = Matrix(libgap.InvariantQuadraticForm(group)["matrix"]) @@ -1612,20 +1577,19 @@ def hashable(v): found = False while not found: v = candidates.pop() - if v*M*v == 0: + if v * M * v == 0: # found another isotropic point # check if we can add it to K found = True for w in isotropicBasis: - if w*M*v + v*M*w != 0: + if w * M * v + v * M * w != 0: found = False break # here we found a valid point isotropicBasis.append(v) # remove new points of K - newVectors = map(hashable, - [k + s*v for k in K for s in nonZeroScalars]) + newVectors = map(hashable, [k + s * v for k in K for s in nonZeroScalars]) candidates.difference(newVectors) K = V.span(isotropicBasis) @@ -1641,22 +1605,16 @@ def hashable(v): # projective isotropic points # convert isoS into a list of ints representing the projective points - isoSPoints = [libgap.Elements(libgap.Basis(x))[0] - for x in libgap.Elements(isoS.Subspaces(1))] - isoSPointsInt = libgap.Set([libgap.Position(allIsoPoints, x) - for x in isoSPoints]) + isoSPoints = [libgap.Elements(libgap.Basis(x))[0] for x in libgap.Elements(isoS.Subspaces(1))] + isoSPointsInt = libgap.Set([libgap.Position(allIsoPoints, x) for x in isoSPoints]) # all isotropic subspaces of dimension d allIsoSubspaces = libgap.Orbit(permutation, isoSPointsInt, libgap.OnSets) # number of projective points in a (d-1)-subspace - intersection_size = (q**(d - 1) - 1) // (q - 1) + intersection_size = (q ** (d - 1) - 1) // (q - 1) n = len(allIsoSubspaces) - edges = [(i, j) for i, j in combinations(range(n), 2) - if libgap.Size(libgap.Intersection(allIsoSubspaces[i], - allIsoSubspaces[j])) - == intersection_size] + edges = [(i, j) for i, j in combinations(range(n), 2) if libgap.Size(libgap.Intersection(allIsoSubspaces[i], allIsoSubspaces[j])) == intersection_size] - return Graph(edges, format='list_of_edges', immutable=immutable, - name = f"Dual Polar Graph on Orthogonal group {(e, m, q)}") + return Graph(edges, format='list_of_edges', immutable=immutable, name=f"Dual Polar Graph on Orthogonal group {(e, m, q)}") diff --git a/src/sage/graphs/generators/degree_sequence.py b/src/sage/graphs/generators/degree_sequence.py index 1b61bb3f436..19862fa0ab4 100644 --- a/src/sage/graphs/generators/degree_sequence.py +++ b/src/sage/graphs/generators/degree_sequence.py @@ -64,8 +64,8 @@ def DegreeSequence(deg_sequence, immutable=False): sage: G.show() # long time # needs networkx sage.plot """ import networkx - return Graph(networkx.havel_hakimi_graph([int(i) for i in deg_sequence]), - immutable=immutable) + + return Graph(networkx.havel_hakimi_graph([int(i) for i in deg_sequence]), immutable=immutable) def DegreeSequenceBipartite(s1, s2, immutable=False): @@ -128,8 +128,7 @@ def DegreeSequenceBipartite(s1, s2, immutable=False): m = gale_ryser_theorem(s1, s2) if m is False: - raise ValueError("there exists no bipartite graph corresponding to " - "the given degree sequences") + raise ValueError("there exists no bipartite graph corresponding to " "the given degree sequences") return Graph(BipartiteGraph(m), immutable=immutable) @@ -179,9 +178,9 @@ def DegreeSequenceConfigurationModel(deg_sequence, seed=None, immutable=False): if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) import networkx + deg_sequence = [int(i) for i in deg_sequence] - return Graph(networkx.configuration_model(deg_sequence, seed=seed), - loops=True, multiedges=True, sparse=True, immutable=immutable) + return Graph(networkx.configuration_model(deg_sequence, seed=seed), loops=True, multiedges=True, sparse=True, immutable=immutable) def DegreeSequenceTree(deg_sequence, immutable=False): @@ -209,8 +208,8 @@ def DegreeSequenceTree(deg_sequence, immutable=False): sage: G.show() # long time # needs networkx sage.plot """ import networkx - return Graph(networkx.degree_sequence_tree([int(i) for i in deg_sequence]), - immutable=immutable) + + return Graph(networkx.degree_sequence_tree([int(i) for i in deg_sequence]), immutable=immutable) def DegreeSequenceExpected(deg_sequence, seed=None, immutable=False): @@ -247,6 +246,6 @@ def DegreeSequenceExpected(deg_sequence, seed=None, immutable=False): if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) import networkx + deg_sequence = [int(i) for i in deg_sequence] - return Graph(networkx.expected_degree_graph(deg_sequence, seed=seed), - loops=True, immutable=immutable) + return Graph(networkx.expected_degree_graph(deg_sequence, seed=seed), loops=True, immutable=immutable) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index 2374e3f7456..21d28ced776 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -72,13 +72,9 @@ def JohnsonGraph(n, k, immutable=False): from sage.combinat.subset import Set, Subsets S = Set(range(n)) - edges = ((sub + Set([i]), sub + Set([j])) - for sub in Subsets(S, k - 1) - for i, j in combinations(S - sub, 2)) + edges = ((sub + Set([i]), sub + Set([j])) for sub in Subsets(S, k - 1) for i, j in combinations(S - sub, 2)) - return Graph([Subsets(S, k), edges], format="vertices_and_edges", - name=f"Johnson graph with parameters {n},{k}", - immutable=immutable) + return Graph([Subsets(S, k), edges], format="vertices_and_edges", name=f"Johnson graph with parameters {n},{k}", immutable=immutable) def KneserGraph(n, k, immutable=False, name=None): @@ -136,11 +132,10 @@ def KneserGraph(n, k, immutable=False, name=None): from sage.combinat.subset import Subsets S = Subsets(n, k) - s0 = S.underlying_set() # {1,2,...,n} + s0 = S.underlying_set() # {1,2,...,n} edges = ((s, t) for s in S for t in Subsets(s0.difference(s), k)) - return Graph([S, edges], format="vertices_and_edges", - name=name, immutable=immutable) + return Graph([S, edges], format="vertices_and_edges", name=name, immutable=immutable) def FurerGadget(k, prefix=None, immutable=False): @@ -218,6 +213,7 @@ def FurerGadget(k, prefix=None, immutable=False): (('Prefix', (1, 2)), ('Prefix', (2, 'a')), None)] """ from itertools import repeat as rep, chain + if k <= 0: raise ValueError("The order of the Furer gadget must be greater than zero") @@ -235,8 +231,7 @@ def FurerGadget(k, prefix=None, immutable=False): E_a = chain.from_iterable([(s, (i, 'a')) for i in s] for s in powerset) E_b = chain.from_iterable([(s, (i, 'b')) for i in range(k) if i not in s] for s in powerset) - G = Graph([chain(V_a, V_b), chain(E_a, E_b)], format="vertices_and_edges", - immutable=immutable) + G = Graph([chain(V_a, V_b), chain(E_a, E_b)], format="vertices_and_edges", immutable=immutable) partition = [[V_a[i], V_b[i]] for i in range(k)] if prefix is not None: @@ -431,6 +426,7 @@ def EgawaGraph(p, s, immutable=False): """ from sage.graphs.generators.basic import CompleteGraph from itertools import product, chain, repeat + X = CompleteGraph(4) Y = Graph('O?Wse@UgqqT_LUebWkbT_') vertices = list(product(*chain(repeat(Y, p), repeat(X, s)))) @@ -439,22 +435,20 @@ def edges(): for v in vertices: for i in range(p): prefix = v[:i] - suffix = v[i+1:] + suffix = v[i + 1 :] for el in Y.neighbor_iterator(v[i]): u = prefix + (el,) + suffix yield (v, u) for i in range(p, s + p): prefix = v[:i] - suffix = v[i+1:] + suffix = v[i + 1 :] for el in X: if el == v[i]: continue u = prefix + (el,) + suffix yield (v, u) - return Graph([vertices, edges()], format="vertices_and_edges", - name=f"Egawa Graph with parameters {p},{s}", - multiedges=False, immutable=immutable) + return Graph([vertices, edges()], format="vertices_and_edges", name=f"Egawa Graph with parameters {p},{s}", multiedges=False, immutable=immutable) def HammingGraph(n, q, X=None, immutable=False): @@ -522,6 +516,7 @@ def HammingGraph(n, q, X=None, immutable=False): :wikipedia:`Hamming_graph` """ from itertools import product, repeat + if not X: X = list(range(q)) if q != len(X): @@ -533,16 +528,14 @@ def edges(): for v in vertices: for i in range(n): prefix = v[:i] - suffix = v[i+1:] + suffix = v[i + 1 :] for el in X: if el == v[i]: continue u = prefix + (el,) + suffix yield (v, u) - return Graph([vertices, edges()], format="vertices_and_edges", - name=f"Hamming Graph with parameters {n},{q}", - multiedges=False, immutable=immutable) + return Graph([vertices, edges()], format="vertices_and_edges", name=f"Hamming Graph with parameters {n},{q}", multiedges=False, immutable=immutable) def BarbellGraph(n1, n2, immutable=False): @@ -655,15 +648,15 @@ def BarbellGraph(n1, n2, immutable=False): raise ValueError("invalid graph description, n2 should be >= 0") from itertools import chain + K1 = ((i, j) for i, j in combinations(range(n1), 2)) P = zip(range(n1 - 1, n1 + n2), range(n1, n1 + n2 + 1)) - K2 = ((i, j) for i, j in combinations(range(n1 + n2, 2*n1 + n2), 2)) - G = Graph([range(2*n1 + n2), chain(K1, P, K2)], format="vertices_and_edges", - name="Barbell graph", immutable=immutable) + K2 = ((i, j) for i, j in combinations(range(n1 + n2, 2 * n1 + n2), 2)) + G = Graph([range(2 * n1 + n2), chain(K1, P, K2)], format="vertices_and_edges", name="Barbell graph", immutable=immutable) - G._circle_embedding(list(range(n1)), shift=1, angle=pi/4) + G._circle_embedding(list(range(n1)), shift=1, angle=pi / 4) G._line_embedding(list(range(n1, n1 + n2)), first=(2, 2), last=(n2 + 1, n2 + 1)) - G._circle_embedding(list(range(n1 + n2, n1 + n2 + n1)), center=(n2 + 3, n2 + 3), angle=5*pi/4) + G._circle_embedding(list(range(n1 + n2, n1 + n2 + n1)), center=(n2 + 3, n2 + 3), angle=5 * pi / 4) return G @@ -737,15 +730,15 @@ def LollipopGraph(n1, n2, immutable=False): raise ValueError("invalid graph description, n2 should be >= 0") from itertools import chain + K = ((i, j) for i, j in combinations(range(n1), 2)) s = 1 if n1 * n2 > 0 else 0 # need edge connecting the clique and the path P = zip(range(n1 - s, n1 + n2 - 1), range(n1 + 1 - s, n1 + n2)) - G = Graph([range(n1 + n2), chain(K, P)], format="vertices_and_edges", - name="Lollipop graph", immutable=immutable) + G = Graph([range(n1 + n2), chain(K, P)], format="vertices_and_edges", name="Lollipop graph", immutable=immutable) if n1 == 1: G.set_pos({0: (0, 0)}) else: - G._circle_embedding(list(range(n1)), shift=1, angle=pi/4) + G._circle_embedding(list(range(n1)), shift=1, angle=pi / 4) G._line_embedding(list(range(n1, n1 + n2)), first=(2, 2), last=(n2 + 1, n2 + 1)) return G @@ -814,13 +807,13 @@ def TadpoleGraph(n1, n2, immutable=False): raise ValueError("invalid graph description, n2 should be >= 0") from itertools import chain + C = ((i, i + 1) for i in range(n1 - 1)) e = ((0, n1 - 1),) s = 1 if n2 else 0 # need edge connecting the cycle and the path P = ((i, i + 1) for i in range(n1 - s, n1 + n2 - 1)) - G = Graph([range(n1 + n2), chain(C, e, P)], format="vertices_and_edges", - name="Tadpole graph", immutable=immutable) - G._circle_embedding(list(range(n1)), shift=1, angle=pi/4) + G = Graph([range(n1 + n2), chain(C, e, P)], format="vertices_and_edges", name="Tadpole graph", immutable=immutable) + G._circle_embedding(list(range(n1)), shift=1, angle=pi / 4) G._line_embedding(list(range(n1, n1 + n2)), first=(2, 2), last=(n2 + 1, n2 + 1)) return G @@ -862,12 +855,11 @@ def AztecDiamondGraph(n, immutable=False): True """ from sage.graphs.generators.basic import Grid2dGraph + if n: N = 2 * n G = Grid2dGraph(N, N, immutable=immutable) - H = G.subgraph([(i, j) for i in range(N) for j in range(N) - if i - n <= j <= n + i and - n - 1 - i <= j <= 3 * n - i - 1]) + H = G.subgraph([(i, j) for i in range(N) for j in range(N) if i - n <= j <= n + i and n - 1 - i <= j <= 3 * n - i - 1]) else: H = Graph(immutable=immutable) H._name = f"Aztec Diamond graph of order {n}" @@ -928,8 +920,7 @@ def DipoleGraph(n, immutable=False): if n < 0: raise ValueError("invalid graph description, n should be >= 0") - return Graph([[0, 1], [(0, 1)]*n], name="Dipole graph", - multiedges=True, immutable=immutable) + return Graph([[0, 1], [(0, 1)] * n], name="Dipole graph", multiedges=True, immutable=immutable) def BubbleSortGraph(n, immutable=False): @@ -1002,12 +993,13 @@ def BubbleSortGraph(n, immutable=False): """ # sanity checks if n < 1: - raise ValueError( - "Invalid number of symbols to permute, n should be >= 1") + raise ValueError("Invalid number of symbols to permute, n should be >= 1") if n == 1: from sage.graphs.generators.basic import CompleteGraph + return Graph(CompleteGraph(n), name="Bubble sort", immutable=immutable) from sage.combinat.permutation import Permutations + # create set from which to permute label_set = [str(i) for i in range(1, n + 1)] d = {} @@ -1026,8 +1018,7 @@ def BubbleSortGraph(n, immutable=False): v[i], v[i + 1] = v[i + 1], v[i] # add adjacency dict d[''.join(v)] = neighbors - return Graph(d, format="dict_of_lists", name="Bubble sort", - immutable=immutable) + return Graph(d, format="dict_of_lists", name="Bubble sort", immutable=immutable) def chang_graphs(immutable=False): @@ -1072,12 +1063,9 @@ def chang_graphs(immutable=False): ....: for x, G in zip(s, chang_graphs)] [True, True, True] """ - g1 = Graph("[}~~EebhkrRb_~SoLOIiAZ?LBBxDb?bQcggjHKEwoZFAaiZ?Yf[?dxb@@tdWGkwn", - loops=False, multiedges=False, immutable=immutable) - g2 = Graph("[~z^UipkkZPr_~Y_LOIiATOLBBxPR@`acoojBBSoWXTaabN?Yts?Yji_QyioClXZ", - loops=False, multiedges=False, immutable=immutable) - g3 = Graph(r"[~~vVMWdKFpV`^UGIaIERQ`\DBxpA@g`CbGRI`AxICNaFM[?fM\?Ytj@CxrGGlYt", - loops=False, multiedges=False, immutable=immutable) + g1 = Graph("[}~~EebhkrRb_~SoLOIiAZ?LBBxDb?bQcggjHKEwoZFAaiZ?Yf[?dxb@@tdWGkwn", loops=False, multiedges=False, immutable=immutable) + g2 = Graph("[~z^UipkkZPr_~Y_LOIiATOLBBxPR@`acoojBBSoWXTaabN?Yts?Yji_QyioClXZ", loops=False, multiedges=False, immutable=immutable) + g3 = Graph(r"[~~vVMWdKFpV`^UGIaIERQ`\DBxpA@g`CbGRI`AxICNaFM[?fM\?Ytj@CxrGGlYt", loops=False, multiedges=False, immutable=immutable) return [g1, g2, g3] @@ -1187,8 +1175,7 @@ def CirculantGraph(n, adjacency, immutable=False, name=None): name = f"Circulant graph ({adjacency})" edges = ((v, (v + j) % n) for v in range(n) for j in adjacency) - G = Graph([range(n), edges], format="vertices_and_edges", - name=name, immutable=immutable) + G = Graph([range(n), edges], format="vertices_and_edges", name=name, immutable=immutable) G._circle_embedding(list(range(n))) return G @@ -1279,9 +1266,9 @@ def CubeGraph(n, embedding=1, immutable=False): """ if embedding == 1 or embedding == 3: # construct recursively the adjacency dict and the embedding - theta = float(pi/n) + theta = float(pi / n) if embedding == 3 and n > 2: - theta = float(pi/(2*n-2)) + theta = float(pi / (2 * n - 2)) d = {'': []} dn = {} @@ -1309,8 +1296,7 @@ def CubeGraph(n, embedding=1, immutable=False): p, pn = pn, {} # construct the graph - G = Graph(d, format='dict_of_lists', pos=p, name=f"{n}-Cube", - immutable=immutable) + G = Graph(d, format='dict_of_lists', pos=p, name=f"{n}-Cube", immutable=immutable) else: # construct recursively the adjacency dict @@ -1335,12 +1321,12 @@ def CubeGraph(n, embedding=1, immutable=False): if embedding == 2: # Orthogonal projection - s = '0'*n + s = '0' * n L = [[] for _ in range(n + 1)] for u, d in G.breadth_first_search(s, report_distance=True): L[d].append(u) - p = G._circle_embedding(list(range(2*n)), radius=(n + 1)//2, angle=pi, return_dict=True) + p = G._circle_embedding(list(range(2 * n)), radius=(n + 1) // 2, angle=pi, return_dict=True) for i in range(n + 1): y = p[i][1] / 1.5 G._line_embedding(L[i], first=(i, y), last=(i, -y), return_dict=False) @@ -1387,8 +1373,8 @@ def GoethalsSeidelGraph(k, r, immutable=False): from sage.matrix.constructor import Matrix from sage.matrix.constructor import block_matrix - v = (k-1)*r + 1 - n = v*(r + 1) + v = (k - 1) * r + 1 + n = v * (r + 1) # N is the (v times b) incidence matrix of a bibd N = balanced_incomplete_block_design(v, k).incidence_matrix() @@ -1396,20 +1382,19 @@ def GoethalsSeidelGraph(k, r, immutable=False): # L is a (r+1 times r) matrix, where r is the row sum of N L = hadamard_matrix(r + 1).submatrix(0, 1) L = [Matrix(C).transpose() for C in L.columns()] - zero = Matrix(r + 1, 1, [0]*(r + 1)) + zero = Matrix(r + 1, 1, [0] * (r + 1)) # For every row of N, we replace the 0s with a column of zeros, and we # replace the ith 1 with the ith column of L. The result is P. P = [] for row in N: Ltmp = L[:] - P.append([Ltmp.pop(0) if i else zero - for i in row]) + P.append([Ltmp.pop(0) if i else zero for i in row]) P = block_matrix(P) # The final graph - PP = P*P.transpose() + PP = P * P.transpose() for i in range(n): PP[i, i] = 0 @@ -1455,9 +1440,8 @@ def DorogovtsevGoltsevMendesGraph(n, immutable=False): if n < 0: raise ValueError("n must be greater than or equal to 0") import networkx - return Graph(networkx.dorogovtsev_goltsev_mendes_graph(n), - name=f"Dorogovtsev-Goltsev-Mendes Graph, {n}-th generation", - immutable=immutable) + + return Graph(networkx.dorogovtsev_goltsev_mendes_graph(n), name=f"Dorogovtsev-Goltsev-Mendes Graph, {n}-th generation", immutable=immutable) def FoldedCubeGraph(n, immutable=False): @@ -1499,11 +1483,10 @@ def complement(x): return x from itertools import chain + H = CubeGraph(n - 1) extra = ((x, complement(x)) for x in H if x[0] == '0') - return Graph([H, chain(H.edges(labels=False), extra)], - format="vertices_and_edges", immutable=immutable, - name="Folded Cube Graph") + return Graph([H, chain(H.edges(labels=False), extra)], format="vertices_and_edges", immutable=immutable, name="Folded Cube Graph") def FriendshipGraph(n, immutable=False): @@ -1605,17 +1588,15 @@ def FriendshipGraph(n, immutable=False): # construct the friendship graph if n == 1: from sage.graphs.generators.basic import CycleGraph + G = CycleGraph(3, immutable=immutable) G._name = "Friendship graph" return G # build the edges and position dictionaries - N = 2 * n + 1 # order of F_n + N = 2 * n + 1 # order of F_n center = 2 * n - edges = (e - for i in range(0, N - 1, 2) - for e in combinations([center, i, i + 1], 2)) - G = Graph([range(N), edges], format="vertices_and_edges", - name="Friendship graph", immutable=immutable) + edges = (e for i in range(0, N - 1, 2) for e in combinations([center, i, i + 1], 2)) + G = Graph([range(N), edges], format="vertices_and_edges", name="Friendship graph", immutable=immutable) G.set_pos({center: (0, 0)}) G._circle_embedding(list(range(N - 1)), radius=1) return G @@ -1675,6 +1656,7 @@ def FuzzyBallGraph(partition, q, immutable=False): - 120877/3240*x^3 + 1351/100*x^2 - 931/450*x} """ from sage.graphs.generators.basic import CompleteGraph + if not partition or any(i <= 0 for i in partition): raise ValueError("partition must be a nonempty list of positive integers") if q < 0: @@ -1690,8 +1672,7 @@ def edges(): yield (u, v) curr_vertex += p - return Graph(edges(), format="list_of_edges", immutable=immutable, - name=f"Fuzzy-Ball({partition}, {q})") + return Graph(edges(), format="list_of_edges", immutable=immutable, name=f"Fuzzy-Ball({partition}, {q})") def GeneralizedPetersenGraph(n, k, immutable=False, name=None): @@ -1766,13 +1747,13 @@ def GeneralizedPetersenGraph(n, k, immutable=False, name=None): if name is None: name = f"Generalized Petersen graph (n={n},k={k})" from itertools import chain + E1 = ((i, (i + 1) % n) for i in range(n)) E2 = ((i, i + n) for i in range(n)) - E3 = (( i + n, n + (i + k) % n) for i in range(n)) - G = Graph([range(2*n), chain(E1, E2, E3)], format="vertices_and_edges", - name=name, immutable=immutable) - G._circle_embedding(list(range(n)), radius=1, angle=pi/2) - G._circle_embedding(list(range(n, 2*n)), radius=.5, angle=pi/2) + E3 = ((i + n, n + (i + k) % n) for i in range(n)) + G = Graph([range(2 * n), chain(E1, E2, E3)], format="vertices_and_edges", name=name, immutable=immutable) + G._circle_embedding(list(range(n)), radius=1, angle=pi / 2) + G._circle_embedding(list(range(n, 2 * n)), radius=0.5, angle=pi / 2) return G @@ -1855,14 +1836,13 @@ def IGraph(n, j, k, immutable=False): raise ValueError("k must be in 1 <= k <= floor((n - 1) / 2)") from itertools import chain + E1 = ((i, (i + j) % n) for i in range(n)) E2 = ((i, i + n) for i in range(n)) - E3 = (( i + n, n + (i + k) % n) for i in range(n)) - G = Graph([range(2*n), chain(E1, E2, E3)], format="vertices_and_edges", - name=f"I-graph (n={n}, j={j}, k={k})", - immutable=immutable) - G._circle_embedding(list(range(n)), radius=1, angle=pi/2) - G._circle_embedding(list(range(n, 2 * n)), radius=.5, angle=pi/2) + E3 = ((i + n, n + (i + k) % n) for i in range(n)) + G = Graph([range(2 * n), chain(E1, E2, E3)], format="vertices_and_edges", name=f"I-graph (n={n}, j={j}, k={k})", immutable=immutable) + G._circle_embedding(list(range(n)), radius=1, angle=pi / 2) + G._circle_embedding(list(range(n, 2 * n)), radius=0.5, angle=pi / 2) return G @@ -1926,19 +1906,18 @@ def DoubleGeneralizedPetersenGraph(n, k, immutable=False): raise ValueError("k must be in 1 <= k <= floor((n - 1) / 2)") from itertools import chain + E1 = ((i, (i + 1) % n) for i in range(n)) E2 = ((i + 3 * n, (i + 1) % n + 3 * n) for i in range(n)) E3 = ((i, i + n) for i in range(n)) E4 = ((i + 2 * n, i + 3 * n) for i in range(n)) E5 = ((i + n, (i + k) % n + 2 * n) for i in range(n)) E6 = ((i + 2 * n, (i + k) % n + n) for i in range(n)) - G = Graph([range(4*n), chain(E1, E2, E3, E4, E5, E6)], - format="vertices_and_edges", immutable=immutable, - name=f"Double generalized Petersen graph (n={n}, k={k})") - G._circle_embedding(list(range(n)), radius=3, angle=pi/2) - G._circle_embedding(list(range(n, 2 * n)), radius=2, angle=pi/2) - G._circle_embedding(list(range(2 * n, 3 * n)), radius=1.5, angle=pi/2) - G._circle_embedding(list(range(3 * n, 4 * n)), radius=0.5, angle=pi/2) + G = Graph([range(4 * n), chain(E1, E2, E3, E4, E5, E6)], format="vertices_and_edges", immutable=immutable, name=f"Double generalized Petersen graph (n={n}, k={k})") + G._circle_embedding(list(range(n)), radius=3, angle=pi / 2) + G._circle_embedding(list(range(n, 2 * n)), radius=2, angle=pi / 2) + G._circle_embedding(list(range(2 * n, 3 * n)), radius=1.5, angle=pi / 2) + G._circle_embedding(list(range(3 * n, 4 * n)), radius=0.5, angle=pi / 2) return G @@ -2024,15 +2003,14 @@ def RoseWindowGraph(n, a, r, immutable=False): raise ValueError("r must be different than n / 2") from itertools import chain + E1 = ((i, (i + 1) % n) for i in range(n)) E2 = ((i, i + n) for i in range(n)) E3 = (((i + a) % n, i + n) for i in range(n)) E4 = ((i + n, (i + r) % n + n) for i in range(n)) - G = Graph([range(2*n), chain(E1, E2, E3, E4)], - format="vertices_and_edges", immutable=immutable, - name=f"Rose window graph (n={n}, a={a}, r={r})") - G._circle_embedding(list(range(n)), radius=1, angle=pi/2) - G._circle_embedding(list(range(n, 2 * n)), radius=0.5, angle=pi/2) + G = Graph([range(2 * n), chain(E1, E2, E3, E4)], format="vertices_and_edges", immutable=immutable, name=f"Rose window graph (n={n}, a={a}, r={r})") + G._circle_embedding(list(range(n)), radius=1, angle=pi / 2) + G._circle_embedding(list(range(n, 2 * n)), radius=0.5, angle=pi / 2) return G @@ -2133,20 +2111,19 @@ def TabacjnGraph(n, a, b, r, immutable=False): raise ValueError("a must be different than b") if r < 1 or r >= n: raise ValueError("r must be an integer such that 1 <= r < n") - if r == n/2: + if r == n / 2: raise ValueError("r must be different than n / 2") from itertools import chain + E1 = ((i, (i + 1) % n) for i in range(n)) E2 = ((i, i + n) for i in range(n)) E3 = ((i + n, n + (i + r) % n) for i in range(n)) E4 = ((i, (i + a) % n + n) for i in range(n)) E5 = ((i, (i + b) % n + n) for i in range(n)) - G = Graph([range(2*n), chain(E1, E2, E3, E4, E5)], - format="vertices_and_edges", immutable=immutable, - name=f"Tabačjn graph (n={n}, a={a}, b={b}, r={r})") - G._circle_embedding(list(range(n)), radius=1, angle=pi/2) - G._circle_embedding(list(range(n, 2 * n)), radius=0.5, angle=pi/2) + G = Graph([range(2 * n), chain(E1, E2, E3, E4, E5)], format="vertices_and_edges", immutable=immutable, name=f"Tabačjn graph (n={n}, a={a}, b={b}, r={r})") + G._circle_embedding(list(range(n)), radius=1, angle=pi / 2) + G._circle_embedding(list(range(n, 2 * n)), radius=0.5, angle=pi / 2) return G @@ -2203,17 +2180,14 @@ def HararyGraph(k, n, immutable=False): name = f"Harary graph {k}, {n}" if not k % 2: - return CirculantGraph(n, list(range(1, k//2 + 1)), - immutable=immutable, name=name) + return CirculantGraph(n, list(range(1, k // 2 + 1)), immutable=immutable, name=name) if not n % 2: - shift_list = list(range(1, (k - 1)//2 + 1)) - shift_list.append(n//2) - return CirculantGraph(n, shift_list, - immutable=immutable, name=name) - G = CirculantGraph(n, list(range(1, (k - 1)//2 + 1)), - immutable=False, name=name) - for i in range((n - 1)//2 + 1): - G.add_edge(i, (i + (n - 1)//2) % n) + shift_list = list(range(1, (k - 1) // 2 + 1)) + shift_list.append(n // 2) + return CirculantGraph(n, shift_list, immutable=immutable, name=name) + G = CirculantGraph(n, list(range(1, (k - 1) // 2 + 1)), immutable=False, name=name) + for i in range((n - 1) // 2 + 1): + G.add_edge(i, (i + (n - 1) // 2) % n) return G.copy(immutable=True) if immutable else G @@ -2265,16 +2239,16 @@ def HyperStarGraph(n, k, immutable=False): - Michael Yurko (2009-09-01) """ if n < 0 or k < 0 or k > n: - raise ValueError("parameters n and k must be nonnegative integers " - "satisfying n >= k >= 0") + raise ValueError("parameters n and k must be nonnegative integers " "satisfying n >= k >= 0") if not n: adj = {} elif not k: - adj = {'0'*n: []} + adj = {'0' * n: []} elif k == n: - adj = {'1'*n: []} + adj = {'1' * n: []} else: from sage.data_structures.bitset import Bitset + adj = dict() # We consider the strings of n bits with k 1s and starting with a 0 for c in combinations(range(1, n), k): @@ -2290,8 +2264,7 @@ def HyperStarGraph(n, k, immutable=False): c[i] = one adj[u] = L - return Graph(adj, format='dict_of_lists', name=f"HS({n},{k})", - immutable=immutable) + return Graph(adj, format='dict_of_lists', name=f"HS({n},{k})", immutable=immutable) def LCFGraph(n, shift_list, repeats, immutable=False, name=None): @@ -2384,16 +2357,15 @@ def LCFGraph(n, shift_list, repeats, immutable=False, name=None): return Graph(name=name, immutable=immutable) from itertools import chain, repeat + # Edges of a cycle E1 = ((i, i + 1) for i in range(n - 1)) E2 = ((0, n - 1),) # Edges obtained from repeated iterations over the shift list - E3 = ((i % n, (i + shift) % n) - for i, shift in enumerate(chain(*repeat(shift_list, repeats)))) + E3 = ((i % n, (i + shift) % n) for i, shift in enumerate(chain(*repeat(shift_list, repeats)))) - G = Graph([range(n), chain(E1, E2, E3)], format="vertices_and_edges", - name=name, immutable=immutable) - G._circle_embedding(list(range(n)), radius=1, angle=pi/2) + G = Graph([range(n), chain(E1, E2, E3)], format="vertices_and_edges", name=name, immutable=immutable) + G._circle_embedding(list(range(n)), radius=1, angle=pi / 2) return G @@ -2460,8 +2432,7 @@ def MycielskiGraph(k=1, relabel=True, immutable=False): if k == 1: return Graph(1, name=name, immutable=immutable) if k == 2: - return Graph([(0, 1)], format="list_of_edges", name=name, - immutable=immutable) + return Graph([(0, 1)], format="list_of_edges", name=name, immutable=immutable) g = Graph([(0, 1)], format="list_of_edges") for _ in range(k - 2): @@ -2576,6 +2547,7 @@ def NKStarGraph(n, k, immutable=False): - Michael Yurko (2009-09-01) """ from sage.combinat.permutation import Arrangements + # set from which to permute set = [str(i) for i in range(1, n + 1)] # create dict @@ -2603,8 +2575,7 @@ def NKStarGraph(n, k, immutable=False): neighbors.append(vert) v[0] = tmp_bit d["".join(v)] = neighbors - return Graph(d, format="dict_of_lists", name=f"({n},{k})-star", - immutable=immutable) + return Graph(d, format="dict_of_lists", name=f"({n},{k})-star", immutable=immutable) def NStarGraph(n, immutable=False): @@ -2637,6 +2608,7 @@ def NStarGraph(n, immutable=False): - Michael Yurko (2009-09-01) """ from sage.combinat.permutation import Permutations + # set from which to permute set = [str(i) for i in range(1, n + 1)] # create dictionary of lists @@ -2655,8 +2627,7 @@ def NStarGraph(n, immutable=False): # swap back v[0], v[i] = v[i], v[0] d["".join(v)] = neighbors - return Graph(d, format="dict_of_lists", name=f"{n}-star", - immutable=immutable) + return Graph(d, format="dict_of_lists", name=f"{n}-star", immutable=immutable) def OddGraph(n, immutable=False): @@ -2699,8 +2670,7 @@ def OddGraph(n, immutable=False): """ if n <= 1: raise ValueError("parameter n should be an integer strictly greater than 1") - return KneserGraph(2*n - 1, n - 1, immutable=immutable, - name=f"Odd Graph with parameter {n}") + return KneserGraph(2 * n - 1, n - 1, immutable=immutable, name=f"Odd Graph with parameter {n}") def PaleyGraph(q, immutable=False): @@ -2745,13 +2715,12 @@ def PaleyGraph(q, immutable=False): from sage.rings.finite_rings.integer_mod import mod from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.arith.misc import is_prime_power + if not is_prime_power(q): raise ValueError("parameter q must be a prime power") if not mod(q, 4) == 1: raise ValueError("parameter q must be congruent to 1 mod 4") - return Graph([FiniteField(q, 'a'), lambda i, j: (i - j).is_square()], - format="rule", immutable=immutable, - loops=False, name=f"Paley graph with parameter {q}") + return Graph([FiniteField(q, 'a'), lambda i, j: (i - j).is_square()], format="rule", immutable=immutable, loops=False, name=f"Paley graph with parameter {q}") def PasechnikGraph(n, immutable=False): @@ -2794,10 +2763,10 @@ def PasechnikGraph(n, immutable=False): raise ValueError("parameter n must be >= 1") from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix from sage.matrix.constructor import identity_matrix + H = skew_hadamard_matrix(4 * n) M = H[1:].T[1:] - identity_matrix(4 * n - 1) - G = Graph(M.tensor_product(M.T), format='seidel_adjacency_matrix', - name=f"Pasechnik Graph_{n}") + G = Graph(M.tensor_product(M.T), format='seidel_adjacency_matrix', name=f"Pasechnik Graph_{n}") G.relabel() return G.copy(immutable=True) if immutable else G @@ -2846,6 +2815,7 @@ def SquaredSkewHadamardMatrixGraph(n, immutable=False): raise ValueError("parameter n must be >= 1") from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix from sage.matrix.constructor import identity_matrix, matrix + idm = identity_matrix(4 * n - 1) e = matrix([1] * (4 * n - 1)) H = skew_hadamard_matrix(4 * n) @@ -2903,7 +2873,7 @@ def SwitchedSquaredSkewHadamardMatrixGraph(n, immutable=False): ValueError: parameter n must be >= 1 """ G = SquaredSkewHadamardMatrixGraph(n).complement() - G.add_vertex((4 * n - 1)**2) + G.add_vertex((4 * n - 1) ** 2) G.seidel_switching(list(range((4 * n - 1) * (2 * n - 1)))) G.name("switch skewhad^2+*_" + str(n)) return G.copy(immutable=True) if immutable else G @@ -3070,6 +3040,7 @@ def HanoiTowerGraph(pegs, disks, labels=True, positions=True, immutable=False): """ # sanitize input from sage.rings.integer import Integer + pegs = Integer(pegs) if pegs < 2: raise ValueError("Pegs for Tower of Hanoi graph should be two or greater (not %d)" % pegs) @@ -3089,16 +3060,16 @@ def HanoiTowerGraph(pegs, disks, labels=True, positions=True, immutable=False): edges = [[i, j] for i in range(pegs) for j in range(i + 1, pegs)] nverts = 1 - for d in range(2, disks+1): - prevedges = edges # remember subgraph to build from - nverts = pegs*nverts # pegs^(d-1) + for d in range(2, disks + 1): + prevedges = edges # remember subgraph to build from + nverts = pegs * nverts # pegs^(d-1) edges = [] # Take an edge, change its two states in the same way by adding # a large disk to the bottom of the same peg in each state # This is accomplished by adding a multiple of pegs^(d-1) for p in range(pegs): - largedisk = p*nverts + largedisk = p * nverts for anedge in prevedges: edges.append([anedge[0] + largedisk, anedge[1] + largedisk]) @@ -3107,19 +3078,19 @@ def HanoiTowerGraph(pegs, disks, labels=True, positions=True, immutable=False): # otherwise being a common state with one less disk # We construct all such pairs of new states and add as edges from sage.combinat.subset import Subsets + for state in range(nverts): emptypegs = list(range(pegs)) reduced_state = state - for i in range(d-1): + for i in range(d - 1): apeg = reduced_state % pegs if apeg in emptypegs: emptypegs.remove(apeg) - reduced_state = reduced_state//pegs + reduced_state = reduced_state // pegs for freea, freeb in Subsets(emptypegs, 2): - edges.append([freea*nverts + state, freeb*nverts + state]) + edges.append([freea * nverts + state, freeb * nverts + state]) - H = Graph(edges, format="list_of_edges", loops=False, multiedges=False, - immutable=immutable and not labels) + H = Graph(edges, format="list_of_edges", loops=False, multiedges=False, immutable=immutable and not labels) # Making labels and/or computing positions can take a long time, # relative to just constructing the edges on integer vertices. @@ -3138,11 +3109,11 @@ def HanoiTowerGraph(pegs, disks, labels=True, positions=True, immutable=False): a = Integer(-1) one = Integer(1) if positions: - radius_multiplier = 1 + 1/sin(pi/pegs) + radius_multiplier = 1 + 1 / sin(pi / pegs) sine = [] cosine = [] for i in range(pegs): - angle = 2*i*pi/float(pegs) + angle = 2 * i * pi / float(pegs) sine.append(sin(angle)) cosine.append(cos(angle)) for i in range(pegs**disks): @@ -3161,8 +3132,8 @@ def HanoiTowerGraph(pegs, disks, labels=True, positions=True, immutable=False): p = state[index] radius *= radius_multiplier parity *= -1.0 - locx_temp = cosine[p]*locx - parity*sine[p]*locy + radius*cosine[p] - locy_temp = parity*sine[p]*locx + cosine[p]*locy - radius*parity*sine[p] + locx_temp = cosine[p] * locx - parity * sine[p] * locy + radius * cosine[p] + locy_temp = parity * sine[p] * locx + cosine[p] * locy - radius * parity * sine[p] locx = locx_temp locy = locy_temp pos[i] = (locx, locy) @@ -3203,16 +3174,10 @@ def line_graph_forbidden_subgraphs(immutable=False): Graph on 5 vertices] """ from sage.graphs.generators.basic import ClawGraph + L = [ClawGraph(immutable=immutable)] - dd = [{0: [1, 2, 3], 1: [2, 3], 4: [2], 5: [3]}, - {0: [1, 2, 3, 4], 1: [2, 3, 4], 3: [4], 2: [5]}, - {0: [1, 2, 3], 1: [2, 3], 4: [2, 3]}, - {0: [1, 2, 3], 1: [2, 3], 4: [2], 5: [3, 4]}, - {0: [1, 2, 3, 4], 1: [2, 3, 4], 3: [4], 5: [2, 0, 1]}, - {5: [0, 1, 2, 3, 4], 0: [1, 4], 2: [1, 3], 3: [4]}, - {1: [0, 2, 3, 4], 3: [0, 4], 2: [4, 5], 4: [5]}, - {0: [1, 2, 3], 1: [2, 3, 4], 2: [3, 4], 3: [4]}] + dd = [{0: [1, 2, 3], 1: [2, 3], 4: [2], 5: [3]}, {0: [1, 2, 3, 4], 1: [2, 3, 4], 3: [4], 2: [5]}, {0: [1, 2, 3], 1: [2, 3], 4: [2, 3]}, {0: [1, 2, 3], 1: [2, 3], 4: [2], 5: [3, 4]}, {0: [1, 2, 3, 4], 1: [2, 3, 4], 3: [4], 5: [2, 0, 1]}, {5: [0, 1, 2, 3, 4], 0: [1, 4], 2: [1, 3], 3: [4]}, {1: [0, 2, 3, 4], 3: [0, 4], 2: [4, 5], 4: [5]}, {0: [1, 2, 3], 1: [2, 3, 4], 2: [3, 4], 3: [4]}] for d in dd: L.append(Graph(d, format="dict_of_lists", immutable=immutable)) @@ -3276,23 +3241,22 @@ def petersen_family(generate=False, immutable=False): True """ from sage.graphs.generators.smallgraphs import PetersenGraph + if not generate: - from sage.graphs.generators.basic import CompleteGraph, \ - CompleteBipartiteGraph, CompleteMultipartiteGraph - l = [PetersenGraph(immutable=immutable), - CompleteGraph(6, immutable=immutable), - CompleteMultipartiteGraph([3, 3, 1], immutable=immutable)] + from sage.graphs.generators.basic import CompleteGraph, CompleteBipartiteGraph, CompleteMultipartiteGraph + + l = [PetersenGraph(immutable=immutable), CompleteGraph(6, immutable=immutable), CompleteMultipartiteGraph([3, 3, 1], immutable=immutable)] g = CompleteBipartiteGraph(4, 4) g.delete_edge(0, 4) g.name("") l.append(g.copy(immutable=True) if immutable else g) g = Graph('HKN?Yeb', format="graph6", immutable=immutable) g._circle_embedding([1, 2, 4, 3, 0, 5]) - g._circle_embedding([6, 7, 8], radius=.6, shift=1.25) + g._circle_embedding([6, 7, 8], radius=0.6, shift=1.25) l.append(g) g = Graph('Fs\\zw', format="graph6", immutable=immutable) g._circle_embedding([1, 2, 3]) - g._circle_embedding([4, 5, 6], radius=.7) + g._circle_embedding([4, 5, 6], radius=0.7) g._pos[0] = (0, 0) l.append(g) g = Graph('GYQ[p{', format="graph6", immutable=immutable) @@ -3365,46 +3329,9 @@ def p2_forbidden_minors(immutable=False): sage: len(graphs.families.p2_forbidden_minors()) 35 """ - p2_forbidden_minors_graph6 = [ - 'KFz_????wF?[', - 'J~{???F@oM?', - 'I~{?GKF@w', - 'JFz_?AB_sE?', - 'I~{?CME`_', - 'H~}CKMF', - 'G^~EMK', - 'H^|ACME', - 'Himp`cr', - 'Iimp_CpKO', - 'IFz@GCdHO', - 'IBz__aB_o', - 'FQ~~w', - 'GlvJ`k', - 'HilKH`J', - 'GjlKJs', - 'HhI]ECZ', - 'HiMIKSp', - 'HFwO]Kf', - 'I]q?a?n@o', - 'IHIWuFGo_', - 'IXJWMC`Eg', - 'GFzfF?', - 'I]o__OF@o', - 'G?^vf_', - 'H?]ufBo', - 'GlrHhs', - 'HhIWuRB', - 'IXCO]FGb?', - 'Fvz~o', - 'GlfH]{', - 'Hl`HGvV', - 'HhcIHmv', - 'IhEGICRiw', - 'JhEIDSD?ga_' - ] - - return [Graph(graph_str, format="graph6", immutable=immutable) - for graph_str in p2_forbidden_minors_graph6] + p2_forbidden_minors_graph6 = ['KFz_????wF?[', 'J~{???F@oM?', 'I~{?GKF@w', 'JFz_?AB_sE?', 'I~{?CME`_', 'H~}CKMF', 'G^~EMK', 'H^|ACME', 'Himp`cr', 'Iimp_CpKO', 'IFz@GCdHO', 'IBz__aB_o', 'FQ~~w', 'GlvJ`k', 'HilKH`J', 'GjlKJs', 'HhI]ECZ', 'HiMIKSp', 'HFwO]Kf', 'I]q?a?n@o', 'IHIWuFGo_', 'IXJWMC`Eg', 'GFzfF?', 'I]o__OF@o', 'G?^vf_', 'H?]ufBo', 'GlrHhs', 'HhIWuRB', 'IXCO]FGb?', 'Fvz~o', 'GlfH]{', 'Hl`HGvV', 'HhcIHmv', 'IhEGICRiw', 'JhEIDSD?ga_'] + + return [Graph(graph_str, format="graph6", immutable=immutable) for graph_str in p2_forbidden_minors_graph6] def SierpinskiGasketGraph(n, immutable=False): @@ -3488,8 +3415,7 @@ def next_step(triangle_list): dg.add_edges([(tuple(a), tuple(b)) for a, b, c in tri_list]) dg.add_edges([(tuple(b), tuple(c)) for a, b, c in tri_list]) dg.add_edges([(tuple(c), tuple(a)) for a, b, c in tri_list]) - dg.set_pos({(x, y): (x + y / 2, y * 3 / 4) - for x, y in dg}) + dg.set_pos({(x, y): (x + y / 2, y * 3 / 4) for x, y in dg}) dg.relabel() return dg.copy(immutable=True) if immutable else dg @@ -3625,7 +3551,7 @@ def rec(H, kk): # For each edge {u, v} of G, add edge {(u, v, ..., v), (v, u, ..., u)} l = len(next(H.vertex_iterator())) for u, v in G.edges(sort=True, labels=False): - I.add_edge((u,) + (v,)*l, (v,) + (u,)*l) + I.add_edge((u,) + (v,) * l, (v,) + (u,) * l) return rec(I, kk - 1) H = G.relabel(perm={u: (u,) for u in G}, inplace=False) @@ -3639,12 +3565,11 @@ def rec(H, kk): if stretch is None: # Find the geometric diameter from sage.modules.free_module_element import vector + L = [vector(p) for p in pos.values()] stretch = 2 * max((u - v).norm() for u, v in combinations(L, 2)) - H.set_pos({u: (sum(pos[x][0]*stretch**(k-i) for i, x in enumerate(u)), - sum(pos[y][1]*stretch**(k-i) for i, y in enumerate(u))) - for u in H}) + H.set_pos({u: (sum(pos[x][0] * stretch ** (k - i) for i, x in enumerate(u)), sum(pos[y][1] * stretch ** (k - i) for i, y in enumerate(u))) for u in H}) return H.copy(immutable=True) if immutable else H @@ -3724,16 +3649,17 @@ def WheelGraph(n, immutable=False): raise ValueError("parameter n must be a positive integer") if n < 4: from sage.graphs.generators.basic import CycleGraph + G = CycleGraph(n, immutable=immutable) G._name = "Wheel graph" else: from itertools import chain + E1 = ((i, i + 1) for i in range(1, n - 1)) E2 = ((1, n - 1),) E3 = ((0, i) for i in range(1, n)) - G = Graph([range(n), chain(E1, E2, E3)], format="vertices_and_edges", - immutable=immutable, name="Wheel graph") - G._circle_embedding(list(range(1, n)), angle=pi/2) + G = Graph([range(n), chain(E1, E2, E3)], format="vertices_and_edges", immutable=immutable, name="Wheel graph") + G._circle_embedding(list(range(1, n)), angle=pi / 2) G._pos[0] = (0, 0) return G @@ -3813,33 +3739,33 @@ def WindmillGraph(k, n, immutable=False): name = f"Windmill graph Wd({k}, {n})" if k == 2: from sage.graphs.generators.basic import StarGraph + G = StarGraph(n, immutable=immutable) G._name = name else: - sector = 2*pi/n - slide = 1/sin(sector/4) + sector = 2 * pi / n + slide = 1 / sin(sector / 4) pos_dict = {} for i in range(k): - x = float(cos(i*pi/(k-2))) - y = float(sin(i*pi/(k-2))) + slide + x = float(cos(i * pi / (k - 2))) + y = float(sin(i * pi / (k - 2))) + slide pos_dict[i] = (x, y) pos = {0: (0, 0)} for i in range(n): - V = range(i*(k - 1) + 1, (i + 1)*(k - 1) + 1) + V = range(i * (k - 1) + 1, (i + 1) * (k - 1) + 1) for j, v in enumerate(V): x, y = pos_dict[j] - xv = x*cos(i*sector) - y*sin(i*sector) - yv = x*sin(i*sector) + y*cos(i*sector) + xv = x * cos(i * sector) - y * sin(i * sector) + yv = x * sin(i * sector) + y * cos(i * sector) pos[v] = (xv, yv) from itertools import chain, combinations - K = chain(*(combinations(range(i*(k - 1) + 1, (i + 1)*(k - 1) + 1), 2) - for i in range(n))) - S = ((0, i) for i in range(1, n*(k - 1) + 1)) - G = Graph([range((k - 1) * n + 1), chain(K, S)], format="vertices_and_edges", - name=name, immutable=immutable, pos=pos) + + K = chain(*(combinations(range(i * (k - 1) + 1, (i + 1) * (k - 1) + 1), 2) for i in range(n))) + S = ((0, i) for i in range(1, n * (k - 1) + 1)) + G = Graph([range((k - 1) * n + 1), chain(K, S)], format="vertices_and_edges", name=name, immutable=immutable, pos=pos) return G @@ -3895,19 +3821,20 @@ def RingedTree(k, vertex_labels=True, immutable=False): # Creating the Balanced tree, which contains most edges already from sage.graphs.generators.trees import BalancedTree + g = BalancedTree(2, k - 1) g.name('Ringed Tree on ' + str(k) + ' levels') # We consider edges layer by layer for i in range(1, k): - vertices = list(range(2**(i) - 1, 2**(i + 1) - 1)) + vertices = list(range(2 ** (i) - 1, 2 ** (i + 1) - 1)) # Add the missing edges g.add_cycle(vertices) # And set the vertices' positions radius = i if i <= 1 else 1.5**i - shift = -2**(i - 2) + .5 if i > 1 else 0 + shift = -(2 ** (i - 2)) + 0.5 if i > 1 else 0 g._circle_embedding(vertices, radius=radius, shift=shift) # Specific position for the central vertex @@ -3919,7 +3846,7 @@ def RingedTree(k, vertex_labels=True, immutable=False): vertices = [''] for i in range(k - 1): - for j in range(2**(i) - 1, 2**(i + 1) - 1): + for j in range(2 ** (i) - 1, 2 ** (i + 1) - 1): v = vertices[j] vertices.append(v + '0') vertices.append(v + '1') @@ -3977,6 +3904,7 @@ def MathonPseudocyclicMergingGraph(M, t, immutable=False): AssertionError... """ from sage.matrix.constructor import identity_matrix + assert len(M) == 4 assert M[0] == identity_matrix(M[0].nrows()) A = sum(x.tensor_product(x) for x in M[1:]) @@ -4071,52 +3999,59 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None, immutable=False): """ from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF from sage.rings.integer_ring import ZZ - from sage.matrix.constructor import matrix, block_matrix, \ - ones_matrix, identity_matrix + from sage.matrix.constructor import matrix, block_matrix, ones_matrix, identity_matrix from sage.arith.misc import two_squares - p = 4*t + 1 + + p = 4 * t + 1 try: x = two_squares(p) except ValueError: - raise ValueError(str(p)+" must be a sum of two squares!") + raise ValueError(str(p) + " must be a sum of two squares!") if G is None: from sage.graphs.strongly_regular_db import strongly_regular_graph as SRG - G = SRG(p, 2*t, t - 1) + + G = SRG(p, 2 * t, t - 1) G.relabel(range(p)) if L is None: from sage.matrix.constructor import circulant + L = circulant(list(range(2 * t + 1)) + list(range(-2 * t, 0))) - q = 4*t - 1 + q = 4 * t - 1 K = GF(q, prefix='x') K_pairs = set(frozenset([x, -x]) for x in K) K_pairs.discard(frozenset([0])) - a = [None]*(q-1) # order the non-0 elements of K as required + a = [None] * (q - 1) # order the non-0 elements of K as required for i, (x, y) in enumerate(K_pairs): a[i] = x - a[-i-1] = y - a.append(K(0)) # and append the 0 of K at the end - P = [matrix(ZZ, q, q, lambda i, j: 1 if a[j] == a[i] + b else 0) - for b in a] + a[-i - 1] = y + a.append(K(0)) # and append the 0 of K at the end + P = [matrix(ZZ, q, q, lambda i, j: 1 if a[j] == a[i] + b else 0) for b in a] g = K.primitive_element() - F = sum(P[a.index(g**(2*i))] for i in range(1, 2*t)) + F = sum(P[a.index(g ** (2 * i))] for i in range(1, 2 * t)) E = matrix(ZZ, q, q, lambda i, j: 0 if (a[j] - a[0]).is_square() else 1) def B(m): I = identity_matrix(q) J = ones_matrix(q) if m == 0: + def f(i, j): if i == j: return 0 * I if (a[j] - a[i]).is_square(): return I + F return J - F - elif m < 2*t: + + elif m < 2 * t: + def f(i, j): - return F * P[a.index(g**(2*m) * (a[i] + a[j]))] - elif m == 2*t: + return F * P[a.index(g ** (2 * m) * (a[i] + a[j]))] + + elif m == 2 * t: + def f(i, j): return E * P[i] + return block_matrix(q, q, [f(i, j) for i in range(q) for j in range(q)]) def Acon(i, j): @@ -4132,7 +4067,7 @@ def Acon(i, j): return J - B(-L[i, j]).T A = Graph(block_matrix(p, p, [Acon(i, j) for i in range(p) for j in range(p)])) - A.name("Mathon's PC SRG on " + str(p*q**2) + " vertices") + A.name("Mathon's PC SRG on " + str(p * q**2) + " vertices") A.relabel() return A.copy(immutable=True) if immutable else A @@ -4196,15 +4131,14 @@ def TuranGraph(n, r, immutable=False): p = n // r s = n % r - vertex_sets = [p]*(r - s) + [p + 1]*s + vertex_sets = [p] * (r - s) + [p + 1] * s g = CompleteMultipartiteGraph(vertex_sets, immutable=immutable) g._name = f"Turan Graph with n: {n}, r: {r}" return g -def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False, - immutable=False): +def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False, immutable=False): r""" Return a strongly regular graph of S6 type from [Muz2007]_ on `n^d((n^d-1)/(n-1)+1)` vertices. @@ -4314,16 +4248,16 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False, from time import time assert d > 1, 'd must be at least 2' - assert is_even(n * (d-1)), 'n must be even or d must be odd' + assert is_even(n * (d - 1)), 'n must be even or d must be odd' assert is_prime_power(n), 'n must be a prime power' t = time() # build L, L_i and the design - m = int((n**d - 1)/(n - 1) + 1) # from m = p + 1, p = (n^d-1) / (n-1) + m = int((n**d - 1) / (n - 1) + 1) # from m = p + 1, p = (n^d-1) / (n-1) L = CompleteGraph(m) L.delete_edges([(2 * x, 2 * x + 1) for x in range(m // 2)]) L_i = [L.edges_incident(x, labels=False) for x in range(m)] - Design = ProjectiveGeometryDesign(d, d-1, GF(n, 'a'), point_coordinates=False) + Design = ProjectiveGeometryDesign(d, d - 1, GF(n, 'a'), point_coordinates=False) projBlocks = Design.blocks() atInf = projBlocks[-1] Blocks = [[x for x in block if x not in atInf] for block in projBlocks[:-1]] @@ -4353,14 +4287,14 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False, # build E^C_j E = {} v = ZZ(n**d) - k = ZZ(n**(d-1)) + k = ZZ(n ** (d - 1)) ones = ones_matrix(v) - ones_v = ones/v + ones_v = ones / v for C in ParClasses: EC = matrix(QQ, v) for line in C: for i, j in combinations(line, 2): - EC[i, j] = EC[j, i] = 1/k + EC[i, j] = EC[j, i] = 1 / k EC -= ones_v E[tuple(C[0])] = EC if verbose: @@ -4376,21 +4310,14 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False, rand = randrange(0, len(temp)) Phi[(x, line)] = temp.pop(rand) elif Phi == 'fixed': - Phi = {(x, line): val for x in range(m) - for val, line in enumerate(L_i[x])} + Phi = {(x, line): val for x in range(m) for val, line in enumerate(L_i[x])} else: - assert isinstance(Phi, dict), \ - "Phi must be a dictionary or 'random' or 'fixed'" - assert set(Phi.keys()) == {(x, line) for x in range(m) - for line in L_i[x]}, \ - 'each Phi_i must have domain L_i' + assert isinstance(Phi, dict), "Phi must be a dictionary or 'random' or 'fixed'" + assert set(Phi.keys()) == {(x, line) for x in range(m) for line in L_i[x]}, 'each Phi_i must have domain L_i' for x in range(m): - assert m - 2 == len({val for key, val in Phi.items() - if key[0] == x}), \ - 'each phi_i must be injective' + assert m - 2 == len({val for key, val in Phi.items() if key[0] == x}), 'each phi_i must be injective' for val in Phi.values(): - assert val in range(m - 1), \ - 'codomain should be {0,..., (n^d - 1)/(n - 1) - 1}' + assert val in range(m - 1), 'codomain should be {0,..., (n^d - 1)/(n - 1) - 1}' phi = {(x, line): ParClasses[Phi[(x, line)]] for x in range(m) for line in L_i[x]} if verbose: print('finished phi at %f (+%f)' % (time() - t, time() - t1)) @@ -4428,8 +4355,7 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False, for i, j in L.edges(sort=True, labels=False): for hyp in phi[(i, (i, j))]: for x in hyp: - newEdges = [((i, x), (j, y)) - for y in sigma[(i, j, tuple(hyp))]] + newEdges = [((i, x), (j, y)) for y in sigma[(i, j, tuple(hyp))]] edges.extend(newEdges) if verbose: print('finished edges at %f (+%f)' % (time() - t, time() - t1)) @@ -4440,12 +4366,12 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False, t1 = time() # build D_i, F_i and A_i - D_i = [0]*m + D_i = [0] * m for x in range(m): D_i[x] = sum([E[tuple(phi[x, line][0])] for line in L_i[x]]) F_i = [1 - D_i[x] - ones_v for x in range(m)] # as the sum of (1/v)*J_\Omega_i, D_i, F_i is identity - A_i = [(v-k)*ones_v - k*F_i[x] for x in range(m)] + A_i = [(v - k) * ones_v - k * F_i[x] for x in range(m)] # we know A_i = k''*(1/v)*J_\Omega_i + r''*D_i + s''*F_i, # and (k'', s'', r'') = (v - k, 0, -k) if verbose: @@ -4454,10 +4380,9 @@ def MuzychukS6Graph(n, d, Phi='fixed', Sigma='fixed', verbose=False, # add the edges of the graph of B to V for i in range(m): - V.add_edges([((i, x), (i, y)) for x in range(v) - for y in range(v) if not A_i[i][(x, y)]]) + V.add_edges([((i, x), (i, y)) for x in range(v) for y in range(v) if not A_i[i][(x, y)]]) - V.name('Muzychuk S6 graph with parameters ('+str(n)+','+str(d)+')') + V.name('Muzychuk S6 graph with parameters (' + str(n) + ',' + str(d) + ')') if verbose: print('finished at %f (+%f)' % ((time() - t), time() - t1)) return V.copy(immutable=True) if immutable else V @@ -4526,29 +4451,20 @@ def CubeConnectedCycle(d, immutable=False): if d == 1: # only d = 1 requires loops - return Graph([((0, 0), (0, 1)), ((0, 0), (0, 0)), ((0, 1), (0, 1))], - format="list_of_edges", loops=True, name=name, - immutable=immutable) + return Graph([((0, 0), (0, 1)), ((0, 0), (0, 0)), ((0, 1), (0, 1))], format="list_of_edges", loops=True, name=name, immutable=immutable) if d == 2: # only d = 2 require multiple edges - return Graph([((0, 0), (0, 1)), ((0, 0), (0, 1)), ((0, 0), (1, 0)), - ((0, 1), (2, 1)), ((1, 0), (1, 1)), ((1, 0), (1, 1)), - ((1, 1), (3, 1)), ((2, 0), (2, 1)), ((2, 0), (2, 1)), - ((2, 0), (3, 0)), ((3, 0), (3, 1)), ((3, 0), (3, 1))], - format="list_of_edges", multiedges=True, name=name, - immutable=immutable) + return Graph([((0, 0), (0, 1)), ((0, 0), (0, 1)), ((0, 0), (1, 0)), ((0, 1), (2, 1)), ((1, 0), (1, 1)), ((1, 0), (1, 1)), ((1, 1), (3, 1)), ((2, 0), (2, 1)), ((2, 0), (2, 1)), ((2, 0), (3, 0)), ((3, 0), (3, 1)), ((3, 0), (3, 1))], format="list_of_edges", multiedges=True, name=name, immutable=immutable) from itertools import chain def cycle(x, d): - return chain((((x, y), (x, y + 1)) for y in range(d - 1)), - (((x, 0), (x, d - 1)),)) + return chain((((x, y), (x, y + 1)) for y in range(d - 1)), (((x, 0), (x, d - 1)),)) cycles = chain(*(cycle(x, d) for x in range(1 << d))) cube = (((x, y), (x ^ (1 << y), y)) for x in range(1 << d) for y in range(d)) - return Graph(chain(cycles, cube), format="list_of_edges", name=name, - immutable=immutable) + return Graph(chain(cycles, cube), format="list_of_edges", name=name, immutable=immutable) def StaircaseGraph(n, immutable=False): @@ -4637,31 +4553,20 @@ def StaircaseGraph(n, immutable=False): if n < 3: raise ValueError("parameter n must be at least 3") - pos_dict = { - 0: (0, 1), - n - 2: (n, 1), - 2*n - 2: (0, -1), - 2*n - 1: (n, -1) - } + pos_dict = {0: (0, 1), n - 2: (n, 1), 2 * n - 2: (0, -1), 2 * n - 1: (n, -1)} for v in range(1, n - 2): pos_dict[v] = (v + 1, 1) - for v in range(n - 1, 2*n - 2): + for v in range(n - 1, 2 * n - 2): pos_dict[v] = (v - n + 2, 0) from itertools import chain - E1 = ((0, n - 1), - (0, 2*n - 2), - (n - 2, 2*n - 3), - (n - 2, 2*n - 1), - (n - 1, 2*n - 2), - (2*n - 3, 2*n - 1), - (2*n - 2, 2*n - 1)) + + E1 = ((0, n - 1), (0, 2 * n - 2), (n - 2, 2 * n - 3), (n - 2, 2 * n - 1), (n - 1, 2 * n - 2), (2 * n - 3, 2 * n - 1), (2 * n - 2, 2 * n - 1)) E2 = ((v, v + n - 1) for v in range(1, n - 2)) E3 = ((i, i + 1) for i in range(n - 2)) - E4 = ((i, i + 1) for i in range(n - 1, 2*n - 3)) + E4 = ((i, i + 1) for i in range(n - 1, 2 * n - 3)) - return Graph([range(2 * n), chain(E1, E2, E3, E4)], name="Staircase graph", - format="vertices_and_edges", pos=pos_dict, immutable=immutable) + return Graph([range(2 * n), chain(E1, E2, E3, E4)], name="Staircase graph", format="vertices_and_edges", pos=pos_dict, immutable=immutable) def BiwheelGraph(n, immutable=False): @@ -4750,18 +4655,19 @@ def BiwheelGraph(n, immutable=False): raise ValueError("parameter n must be at least 4") from itertools import chain - C1 = ((i, i + 1) for i in range(2*n - 3)) - C2 = ((0, 2*n - 3),) - S1 = ((i, 2*n - 1) for i in range(0, 2*n - 2, 2)) - S2 = ((i, 2*n - 2) for i in range(1, 2*n - 2, 2)) - G = Graph([range(2*n), chain(C1, C2, S1, S2)], format="vertices_and_edges", - name="Biwheel graph", immutable=immutable) + + C1 = ((i, i + 1) for i in range(2 * n - 3)) + C2 = ((0, 2 * n - 3),) + S1 = ((i, 2 * n - 1) for i in range(0, 2 * n - 2, 2)) + S2 = ((i, 2 * n - 2) for i in range(1, 2 * n - 2, 2)) + G = Graph([range(2 * n), chain(C1, C2, S1, S2)], format="vertices_and_edges", name="Biwheel graph", immutable=immutable) from sage.rings.rational_field import QQ - angle_param = (pi / (2*n - 2)) if n % 2 else 0 - pos_dict = G._circle_embedding(list(range(2*n - 2)), angle=angle_param, return_dict=True) - pos_dict[2*n - 2] = (-QQ((1, 3)), 0) - pos_dict[2*n - 1] = (QQ((1, 3)), 0) + + angle_param = (pi / (2 * n - 2)) if n % 2 else 0 + pos_dict = G._circle_embedding(list(range(2 * n - 2)), angle=angle_param, return_dict=True) + pos_dict[2 * n - 2] = (-QQ((1, 3)), 0) + pos_dict[2 * n - 1] = (QQ((1, 3)), 0) G.set_pos(pos_dict) return G @@ -4845,15 +4751,14 @@ def TruncatedBiwheelGraph(n, immutable=False): if n < 3: raise ValueError("parameter n must be at least 3") - pos_dict = {2*n - 2: (0, n), 2*n - 1: (0, -n)} - for v in range(2*n - 2): - pos_dict[v] = (2*(v-n) + 3, 0) + pos_dict = {2 * n - 2: (0, n), 2 * n - 1: (0, -n)} + for v in range(2 * n - 2): + pos_dict[v] = (2 * (v - n) + 3, 0) from itertools import chain - E1 = ((0, 2*n - 2), (2*n - 3, 2*n - 1)) - E2 = ((i, i + 1) for i in range(2*n - 3)) - S1 = ((v, 2*n - 1) for v in range(0, 2*n - 2, 2)) - S2 = ((v, 2*n - 2) for v in range(1, 2*n - 2, 2)) - return Graph([range(2 * n), chain(E1, E2, S1, S2)], - format="vertices_and_edges", pos=pos_dict, - name="Truncated biwheel graph", immutable=immutable) + + E1 = ((0, 2 * n - 2), (2 * n - 3, 2 * n - 1)) + E2 = ((i, i + 1) for i in range(2 * n - 3)) + S1 = ((v, 2 * n - 1) for v in range(0, 2 * n - 2, 2)) + S2 = ((v, 2 * n - 2) for v in range(1, 2 * n - 2, 2)) + return Graph([range(2 * n), chain(E1, E2, S1, S2)], format="vertices_and_edges", pos=pos_dict, name="Truncated biwheel graph", immutable=immutable) diff --git a/src/sage/graphs/generators/generators_test.py b/src/sage/graphs/generators/generators_test.py index 19160c32e54..886e58fca18 100644 --- a/src/sage/graphs/generators/generators_test.py +++ b/src/sage/graphs/generators/generators_test.py @@ -10,9 +10,7 @@ def test_shortened_000_111_extended_binary_Golay_code_graph(): """ from sage.coding import codes_catalog from sage.coding.linear_code import LinearCode - from sage.graphs.generators.distance_regular import ( - shortened_000_111_extended_binary_Golay_code_graph - ) + from sage.graphs.generators.distance_regular import shortened_000_111_extended_binary_Golay_code_graph from sage.matrix.constructor import matrix from sage.rings.finite_rings.finite_field_constructor import FiniteField diff --git a/src/sage/graphs/generators/intersection.py b/src/sage/graphs/generators/intersection.py index eee18c5aa62..e1d97a7df53 100644 --- a/src/sage/graphs/generators/intersection.py +++ b/src/sage/graphs/generators/intersection.py @@ -93,6 +93,7 @@ def IntervalGraph(intervals, points_ordered=False, immutable=False): n = len(intervals) if points_ordered: + def edges(): for i in range(n - 1): li, ri = intervals[i] @@ -103,6 +104,7 @@ def edges(): yield (i, j) else: + def edges(): for i in range(n - 1): min_I = min(intervals[i]) @@ -113,8 +115,7 @@ def edges(): continue yield (i, j) - g = Graph([range(n), edges()], format="vertices_and_edges", - immutable=immutable) + g = Graph([range(n), edges()], format="vertices_and_edges", immutable=immutable) rep = dict(zip(range(n), intervals)) g.set_vertices(rep) @@ -122,8 +123,7 @@ def edges(): return g -def PermutationGraph(second_permutation, first_permutation=None, - immutable=False): +def PermutationGraph(second_permutation, first_permutation=None, immutable=False): r""" Build a permutation graph from one permutation or from two lists. @@ -268,24 +268,20 @@ def PermutationGraph(second_permutation, first_permutation=None, first_permutation = sorted(second_permutation) else: if set(second_permutation) != set(first_permutation): - raise ValueError("The two permutations do not contain the same " - "set of elements ! It is going to be pretty " - "hard to define a permutation graph from that !") + raise ValueError("The two permutations do not contain the same " "set of elements ! It is going to be pretty " "hard to define a permutation graph from that !") vertex_to_index = {} for i, v in enumerate(first_permutation): vertex_to_index[v] = i + 1 from sage.combinat.permutation import Permutation + p2 = Permutation([vertex_to_index[x] for x in second_permutation]) p2 = p2.inverse() - edges = ((first_permutation[u - 1], first_permutation[v - 1]) - for u, v in p2.inversions()) + edges = ((first_permutation[u - 1], first_permutation[v - 1]) for u, v in p2.inversions()) - return Graph([second_permutation, edges], format="vertices_and_edges", - name=f"Permutation graph for {second_permutation}", - immutable=immutable) + return Graph([second_permutation, edges], format="vertices_and_edges", name=f"Permutation graph for {second_permutation}", immutable=immutable) def ToleranceGraph(tolrep, immutable=False, name=None): @@ -369,8 +365,7 @@ def ToleranceGraph(tolrep, immutable=False, name=None): for i in range(n): if tolrep[i][2] <= 0: - raise ValueError("Invalid tolerance representation at position " - "{}; third value must be > 0".format(i)) + raise ValueError("Invalid tolerance representation at position " "{}; third value must be > 0".format(i)) def edges(): for i in range(n): @@ -381,8 +376,7 @@ def edges(): yield (i, j) name = "Tolerance Graph" if name is None else name - g = Graph([range(n), edges()], format="vertices_and_edges", - name=name, immutable=immutable) + g = Graph([range(n), edges()], format="vertices_and_edges", name=name, immutable=immutable) rep = dict(zip(range(n), tolrep)) g.set_vertices(rep) @@ -511,6 +505,7 @@ def OrthogonalArrayBlockGraph(k, n, OA=None, immutable=False): if OA is None: from sage.combinat.designs.orthogonal_arrays import orthogonal_array + OA = orthogonal_array(k, n) else: assert len(OA) == n**2 @@ -524,10 +519,10 @@ def OrthogonalArrayBlockGraph(k, n, OA=None, immutable=False): d[i][x].append(R) from itertools import chain, combinations + edges = chain(*(combinations(ll, 2) for L in d for ll in L)) - return Graph(edges, format="list_of_edges", immutable=immutable, - name=f"OA({k},{n})") + return Graph(edges, format="list_of_edges", immutable=immutable, name=f"OA({k},{n})") def IntersectionGraph(S, immutable=False): @@ -576,8 +571,7 @@ def IntersectionGraph(S, immutable=False): ground_set_to_sets[x].append(s) from itertools import chain, combinations - edges = chain(*(combinations(set(clique), 2) - for clique in ground_set_to_sets.values())) - return Graph([S, edges], format="vertices_and_edges", - name="Intersection Graph", immutable=immutable) + edges = chain(*(combinations(set(clique), 2) for clique in ground_set_to_sets.values())) + + return Graph([S, edges], format="vertices_and_edges", name="Intersection Graph", immutable=immutable) diff --git a/src/sage/graphs/generators/platonic_solids.py b/src/sage/graphs/generators/platonic_solids.py index 6aa97a6cfe1..fe5abe4db4d 100644 --- a/src/sage/graphs/generators/platonic_solids.py +++ b/src/sage/graphs/generators/platonic_solids.py @@ -3,6 +3,7 @@ The methods defined here appear in :mod:`sage.graphs.graph_generators`. """ + # **************************************************************************** # # Copyright (C) 2006 Robert L. Miller @@ -67,12 +68,8 @@ def TetrahedralGraph(immutable=False): sage: G.show() # long time """ edges = ((0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)) - pos = {0: (0, 0), - 1: (0, 1), - 2: (cos(3.5*pi/3), sin(3.5*pi/3)), - 3: (cos(5.5*pi/3), sin(5.5*pi/3))} - return Graph([range(4), edges], format="vertices_and_edges", - name='Tetrahedron', pos=pos, immutable=immutable) + pos = {0: (0, 0), 1: (0, 1), 2: (cos(3.5 * pi / 3), sin(3.5 * pi / 3)), 3: (cos(5.5 * pi / 3), sin(5.5 * pi / 3))} + return Graph([range(4), edges], format="vertices_and_edges", name='Tetrahedron', pos=pos, immutable=immutable) def HexahedralGraph(immutable=False): @@ -117,18 +114,8 @@ def HexahedralGraph(immutable=False): sage: G.show() # long time """ adj = {0: [1, 3, 4], 1: [2, 5], 2: [3, 6], 3: [7], 4: [5, 7], 5: [6], 6: [7]} - pos = { - 0: (0, 0), - 1: (1, 0), - 3: (0, 1), - 2: (1, 1), - 4: (.5, .5), - 5: (1.5, .5), - 7: (.5, 1.5), - 6: (1.5, 1.5) - } - return Graph(adj, format="dict_of_lists", name='Hexahedron', pos=pos, - immutable=immutable) + pos = {0: (0, 0), 1: (1, 0), 3: (0, 1), 2: (1, 1), 4: (0.5, 0.5), 5: (1.5, 0.5), 7: (0.5, 1.5), 6: (1.5, 1.5)} + return Graph(adj, format="dict_of_lists", name='Hexahedron', pos=pos, immutable=immutable) def OctahedralGraph(immutable=False): @@ -175,10 +162,9 @@ def OctahedralGraph(immutable=False): sage: G.show() # long time """ adj = {0: [1, 2, 3, 4], 1: [2, 3, 5], 2: [4, 5], 3: [4, 5], 4: [5]} - G = Graph(adj, format='dict_of_lists', name='Octahedron', - immutable=immutable) - G._circle_embedding([0, 1, 2], radius=5, angle=pi/2) - G._circle_embedding([4, 3, 5], radius=1, angle=pi/6) + G = Graph(adj, format='dict_of_lists', name='Octahedron', immutable=immutable) + G._circle_embedding([0, 1, 2], radius=5, angle=pi / 2) + G._circle_embedding([4, 3, 5], radius=1, angle=pi / 6) return G @@ -224,13 +210,10 @@ def IcosahedralGraph(immutable=False): sage: G = graphics_array(j) sage: G.show() # long time """ - adj = {0: [1, 5, 7, 8, 11], 1: [2, 5, 6, 8], 2: [3, 6, 8, 9], - 3: [4, 6, 9, 10], 4: [5, 6, 10, 11], 5: [6, 11], - 7: [8, 9, 10, 11], 8: [9], 9: [10], 10: [11]} - G = Graph(adj, format='dict_of_lists', name='Icosahedron', - immutable=immutable) - G._circle_embedding([2, 8, 7, 11, 4, 6], radius=5, angle=pi/6) - G._circle_embedding([1, 9, 0, 10, 5, 3], radius=2, angle=pi/6) + adj = {0: [1, 5, 7, 8, 11], 1: [2, 5, 6, 8], 2: [3, 6, 8, 9], 3: [4, 6, 9, 10], 4: [5, 6, 10, 11], 5: [6, 11], 7: [8, 9, 10, 11], 8: [9], 9: [10], 10: [11]} + G = Graph(adj, format='dict_of_lists', name='Icosahedron', immutable=immutable) + G._circle_embedding([2, 8, 7, 11, 4, 6], radius=5, angle=pi / 6) + G._circle_embedding([1, 9, 0, 10, 5, 3], radius=2, angle=pi / 6) return G @@ -274,14 +257,10 @@ def DodecahedralGraph(immutable=False): sage: G = graphics_array(j) sage: G.show() # long time """ - adj = {0: [1, 10, 19], 1: [2, 8], 2: [3, 6], 3: [4, 19], 4: [5, 17], - 5: [6, 15], 6: [7], 7: [8, 14], 8: [9], 9: [10, 13], 10: [11], - 11: [12, 18], 12: [13, 16], 13: [14], 14: [15], 15: [16], 16: [17], - 17: [18], 18: [19]} - G = Graph(adj, format='dict_of_lists', name='Dodecahedron', - immutable=immutable) - G._circle_embedding([19, 0, 1, 2, 3], radius=7, angle=pi/10) - G._circle_embedding([18, 10, 8, 6, 4], radius=4.7, angle=pi/10) - G._circle_embedding([11, 9, 7, 5, 17], radius=3.8, angle=3*pi/10) - G._circle_embedding([12, 13, 14, 15, 16], radius=1.5, angle=3*pi/10) + adj = {0: [1, 10, 19], 1: [2, 8], 2: [3, 6], 3: [4, 19], 4: [5, 17], 5: [6, 15], 6: [7], 7: [8, 14], 8: [9], 9: [10, 13], 10: [11], 11: [12, 18], 12: [13, 16], 13: [14], 14: [15], 15: [16], 16: [17], 17: [18], 18: [19]} + G = Graph(adj, format='dict_of_lists', name='Dodecahedron', immutable=immutable) + G._circle_embedding([19, 0, 1, 2, 3], radius=7, angle=pi / 10) + G._circle_embedding([18, 10, 8, 6, 4], radius=4.7, angle=pi / 10) + G._circle_embedding([11, 9, 7, 5, 17], radius=3.8, angle=3 * pi / 10) + G._circle_embedding([12, 13, 14, 15, 16], radius=1.5, angle=3 * pi / 10) return G diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 92f2dfb6663..ab55641bd88 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -3,6 +3,7 @@ The methods defined here appear in :mod:`sage.graphs.graph_generators`. """ + ########################################################################### # # Copyright (C) 2006 Robert L. Miller @@ -14,6 +15,7 @@ ########################################################################### import sys + # import from Sage library from sage.graphs.graph import Graph from sage.misc.randstate import current_randstate @@ -110,12 +112,14 @@ def RandomGNP(n, p, seed=None, fast=True, algorithm='Sage', immutable=False): if p == 1: from sage.graphs.generators.basic import CompleteGraph + return CompleteGraph(n, immutable=immutable) if algorithm == 'networkx': if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) import networkx + if fast: G = networkx.fast_gnp_random_graph(n, p, seed=seed) else: @@ -124,6 +128,7 @@ def RandomGNP(n, p, seed=None, fast=True, algorithm='Sage', immutable=False): if algorithm in ['Sage', 'sage']: # We use the Sage generator from sage.graphs.graph_generators_pyx import RandomGNP as sageGNP + return sageGNP(n, p, seed=seed, immutable=immutable) raise ValueError("'algorithm' must be equal to 'networkx' or to 'Sage'") @@ -188,8 +193,8 @@ def RandomBarabasiAlbert(n, m, seed=None, immutable=False): if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) import networkx - return Graph(networkx.barabasi_albert_graph(int(n), int(m), seed=seed), - format="NX", immutable=immutable) + + return Graph(networkx.barabasi_albert_graph(int(n), int(m), seed=seed), format="NX", immutable=immutable) def RandomBipartite(n1, n2, p, set_position=False, seed=None, immutable=False): @@ -260,8 +265,7 @@ def RandomBipartite(n1, n2, p, set_position=False, seed=None, immutable=False): S1 = [(0, i) for i in range(n1)] S2 = [(1, i) for i in range(n2)] edges = ((v, w) for w in S2 for v in S1 if uniform() <= p) - g = Graph([chain(S1, S2), edges], format="vertices_and_edges", - name=name, immutable=immutable) + g = Graph([chain(S1, S2), edges], format="vertices_and_edges", name=name, immutable=immutable) # We now assign positions to vertices: # - vertices in S1 are placed on the line from (0, 1) to (max(n1, n2), 1) @@ -275,8 +279,7 @@ def RandomBipartite(n1, n2, p, set_position=False, seed=None, immutable=False): return g -def RandomRegularBipartite(n1, n2, d1, set_position=False, seed=None, - immutable=False): +def RandomRegularBipartite(n1, n2, d1, set_position=False, seed=None, immutable=False): r""" Return a random regular bipartite graph on `n1 + n2` vertices. @@ -351,7 +354,7 @@ def RandomRegularBipartite(n1, n2, d1, set_position=False, seed=None, set_random_seed(seed) complement = False - if d1 > n2/2 or d2 > n1/2: + if d1 > n2 / 2 or d2 > n1 / 2: # We build the complement graph instead complement = True d1 = n2 - d1 @@ -423,6 +426,7 @@ def RandomRegularBipartite(n1, n2, d1, set_position=False, seed=None, if complement: from sage.graphs.generators.basic import CompleteBipartiteGraph + E = E.symmetric_difference(CompleteBipartiteGraph(n1, n2).edges(sort=False, labels=False)) d1, d2 = n2 - d1, n1 - d2 @@ -441,8 +445,7 @@ def RandomRegularBipartite(n1, n2, d1, set_position=False, seed=None, return G -def RandomBlockGraph(m, k, kmax=None, incidence_structure=False, seed=None, - immutable=False): +def RandomBlockGraph(m, k, kmax=None, incidence_structure=False, seed=None, immutable=False): r""" Return a Random Block Graph. @@ -604,6 +607,7 @@ def RandomBlockGraph(m, k, kmax=None, incidence_structure=False, seed=None, else: name = f"Random Block Graph with {m} blocks of order {k} to {kmax}" from itertools import chain, combinations + edges = chain.from_iterable(combinations(block, 2) for block in IS) return Graph(edges, format="list_of_edges", name=name, immutable=immutable) @@ -663,7 +667,7 @@ def RandomBoundedToleranceGraph(n, seed=None, immutable=False): from sage.graphs.generators.intersection import ToleranceGraph - W = n ** 2 * 2 ** n + W = n**2 * 2**n tolrep = [] for _ in range(n): left = randint(0, W - 1) @@ -726,11 +730,10 @@ def RandomGNM(n, m, dense=False, seed=None, immutable=False): if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) import networkx + if dense: - return Graph(networkx.dense_gnm_random_graph(n, m, seed=seed), - format="NX", immutable=immutable) - return Graph(networkx.gnm_random_graph(n, m, seed=seed), - format="NX", immutable=immutable) + return Graph(networkx.dense_gnm_random_graph(n, m, seed=seed), format="NX", immutable=immutable) + return Graph(networkx.gnm_random_graph(n, m, seed=seed), format="NX", immutable=immutable) def RandomNewmanWattsStrogatz(n, k, p, seed=None, immutable=False): @@ -799,8 +802,8 @@ def RandomNewmanWattsStrogatz(n, k, p, seed=None, immutable=False): if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) import networkx - return Graph(networkx.newman_watts_strogatz_graph(n, k, p, seed=seed), - format="NX", immutable=immutable) + + return Graph(networkx.newman_watts_strogatz_graph(n, k, p, seed=seed), format="NX", immutable=immutable) def RandomHolmeKim(n, m, p, seed=None, immutable=False): @@ -847,8 +850,8 @@ def RandomHolmeKim(n, m, p, seed=None, immutable=False): if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) import networkx - return Graph(networkx.powerlaw_cluster_graph(n, m, p, seed=seed), - format="NX", immutable=immutable) + + return Graph(networkx.powerlaw_cluster_graph(n, m, p, seed=seed), format="NX", immutable=immutable) def RandomIntervalGraph(n, seed=None, immutable=False): @@ -992,7 +995,7 @@ def RandomProperIntervalGraph(n, seed=None, immutable=False): # # Since the i-th interval starts at the i-th symbol [ and ends at the # i-th symbol ], we directly build the intervals - intervals = [[0, 2*n] for _ in range(n)] + intervals = [[0, 2 * n] for _ in range(n)] L = 1 # next starting interval R = 0 # next ending interval hx = [0] @@ -1100,6 +1103,7 @@ def compute_C(n, h): # Random Chordal Graphs + def growing_subtrees(T, k): r""" Return a list of the vertex sets of `n` randomly chosen subtrees of `T`. @@ -1134,6 +1138,7 @@ def growing_subtrees(T, k): 10 """ from sage.misc.prandom import choice + n = T.order() S = [] for _ in range(n): @@ -1335,8 +1340,7 @@ def pruned_tree(T, f, s): return S -def RandomChordalGraph(n, algorithm='growing', k=None, l=None, f=None, s=None, - seed=None, immutable=False): +def RandomChordalGraph(n, algorithm='growing', k=None, l=None, f=None, s=None, seed=None, immutable=False): r""" Return a random chordal graph of order ``n``. @@ -1463,12 +1467,14 @@ def RandomChordalGraph(n, algorithm='growing', k=None, l=None, f=None, s=None, # 1. Generate a random tree of order n from sage.graphs.generators.trees import RandomTree + T = RandomTree(n) # 2. Generate n non-empty subtrees of T: {T1,...,Tn} if algorithm == "growing": if k is None: from sage.misc.functional import isqrt + k = isqrt(n) elif k < 1: raise ValueError("parameter k must be >= 1") @@ -1478,6 +1484,7 @@ def RandomChordalGraph(n, algorithm='growing', k=None, l=None, f=None, s=None, elif algorithm == "connecting": if l is None: from sage.rings.integer import Integer + l = Integer(n).log(2) elif l <= 0: raise ValueError("parameter l must be > 0") @@ -1487,11 +1494,12 @@ def RandomChordalGraph(n, algorithm='growing', k=None, l=None, f=None, s=None, elif algorithm == "pruned": if f is None: from sage.rings.rational import Rational + f = 1 / Rational(n - 1) elif f < 0 or f > 1: raise ValueError("parameter f must be 0 <= f <= 1") if s is None: - s = .5 + s = 0.5 elif s <= 0 or s >= 1: raise ValueError("parameter s must be 0 < s < 1") @@ -1506,9 +1514,9 @@ def RandomChordalGraph(n, algorithm='growing', k=None, l=None, f=None, s=None, for x in s: vertex_to_subtrees[x].append(i) from itertools import chain, combinations + edges = chain.from_iterable(combinations(X, 2) for X in vertex_to_subtrees) - return Graph([range(n), edges], format="vertices_and_edges", - name="Random Chordal Graph", immutable=immutable) + return Graph([range(n), edges], format="vertices_and_edges", name="Random Chordal Graph", immutable=immutable) def RandomKTree(n, k, seed=None, immutable=False): @@ -1584,23 +1592,23 @@ def RandomKTree(n, k, seed=None, immutable=False): set_random_seed(seed) from itertools import chain, combinations + first_clique = combinations(range(k + 1), 2) def extra_edges(): - cliques = [list(range(k+1))] + cliques = [list(range(k + 1))] # Randomly choose a row, and copy 1 of the cliques # One of those vertices is then replaced with a new vertex for newVertex in range(k + 1, n): - copiedClique = cliques[randint(0, len(cliques)-1)].copy() + copiedClique = cliques[randint(0, len(cliques) - 1)].copy() copiedClique[randint(0, k)] = newVertex cliques.append(copiedClique) for u in copiedClique: if u != newVertex: yield (u, newVertex) - return Graph(chain(first_clique, extra_edges()), format="list_of_edges", - name=f"Random {k}-tree", immutable=immutable) + return Graph(chain(first_clique, extra_edges()), format="list_of_edges", name=f"Random {k}-tree", immutable=immutable) def RandomPartialKTree(n, k, x, seed=None, immutable=False): @@ -1716,9 +1724,7 @@ def RandomPartialKTree(n, k, x, seed=None, immutable=False): return g # Build an immutable graph without the x first edges - return Graph([g, edges[x:]], format="vertices_and_edges", - name=f"Random partial {k}-tree", immutable=True) - + return Graph([g, edges[x:]], format="vertices_and_edges", name=f"Random partial {k}-tree", immutable=True) def RandomRegular(d, n, seed=None, immutable=False): @@ -1764,6 +1770,7 @@ def RandomRegular(d, n, seed=None, immutable=False): if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) import networkx + try: N = networkx.random_regular_graph(d, n, seed=seed) if N is False: @@ -1804,8 +1811,8 @@ def RandomShell(constructor, seed=None, immutable=False): if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) import networkx - return Graph(networkx.random_shell_graph(constructor, seed=seed), - format="NX", immutable=immutable) + + return Graph(networkx.random_shell_graph(constructor, seed=seed), format="NX", immutable=immutable) def RandomToleranceGraph(n, seed=None, immutable=False): @@ -1871,12 +1878,12 @@ def RandomToleranceGraph(n, seed=None, immutable=False): # The tolerance value must be > 0 tolrep.append((left, right, randint(1, W))) - return ToleranceGraph(tolrep, immutable=immutable, - name="Random tolerance graph") + return ToleranceGraph(tolrep, immutable=immutable, name="Random tolerance graph") # uniform random triangulation using Schaeffer-Poulalhon algorithm + def _auxiliary_random_forest_word(n, k): r""" Return a random word used to generate random triangulations. @@ -1941,7 +1948,8 @@ def _auxiliary_random_forest_word(n, k): ....: assert partial_sum >= -2*k + 4 """ from sage.misc.prandom import shuffle - w = [0] * (3*n + 2*k - 3) + [1] * n + + w = [0] * (3 * n + 2 * k - 3) + [1] * n shuffle(w) # Finding the admissible shift @@ -1956,7 +1964,7 @@ def _auxiliary_random_forest_word(n, k): if partial_sum < min_value: min_value = partial_sum min_pos = i - return w[min_pos+1:] + w[:min_pos] + return w[min_pos + 1 :] + w[:min_pos] def _contour_and_graph_from_words(pendant_word, forest_word): @@ -2068,7 +2076,7 @@ def _contour_and_graph_from_words(pendant_word, forest_word): leaf_stack = [index, index] # stack of active inner nodes inner_stack = [word[curr_word_pos][1], index] - word.insert(curr_word_pos+1, ('in', index)) + word.insert(curr_word_pos + 1, ('in', index)) curr_word_pos += 1 while len(inner_stack) > 1: curr_forest_word_pos += 1 @@ -2080,19 +2088,19 @@ def _contour_and_graph_from_words(pendant_word, forest_word): leaf_stack.extend([index, index]) inner_stack.append(index) edges.append(inner_stack[-2:]) - word.insert(curr_word_pos+1, ('in', index)) + word.insert(curr_word_pos + 1, ('in', index)) curr_word_pos += 1 else: # up and down to a new leaf if leaf_stack and inner_stack[-1] == leaf_stack[-1]: leaf_stack.pop() - word.insert(curr_word_pos+1, ('lf', inner_stack[-1])) - word.insert(curr_word_pos+2, ('in', inner_stack[-1])) + word.insert(curr_word_pos + 1, ('lf', inner_stack[-1])) + word.insert(curr_word_pos + 2, ('in', inner_stack[-1])) curr_word_pos += 2 # going down to a known inner vertex else: inner_stack.pop() - word.insert(curr_word_pos+1, ('in', inner_stack[-1])) + word.insert(curr_word_pos + 1, ('in', inner_stack[-1])) curr_word_pos += 1 # go to next insertion position else: @@ -2201,15 +2209,15 @@ def RandomTriangulation(n, set_position=False, k=3, seed=None, immutable=False): if k < 3: raise ValueError("The size 'k' of the outer face must be at least 3.") if n < k: - raise ValueError("The number 'n' of vertices must be at least the size " - "'k' of the outer face.") + raise ValueError("The number 'n' of vertices must be at least the size " "'k' of the outer face.") if seed is not None: set_random_seed(seed) from sage.misc.prandom import shuffle - pendant_word = [0] * (k-1) + [1] * (k-3) + + pendant_word = [0] * (k - 1) + [1] * (k - 3) shuffle(pendant_word) - forest_word = _auxiliary_random_forest_word(n-k, k) + forest_word = _auxiliary_random_forest_word(n - k, k) word, graph = _contour_and_graph_from_words(pendant_word, forest_word) edges = [] embedding = graph.get_embedding() @@ -2240,7 +2248,7 @@ def RandomTriangulation(n, set_position=False, k=3, seed=None, immutable=False): graph.add_edges(edges) graph.set_embedding(embedding) graph.relabel({0: -2, 1: -1}) - assert graph.n_edges() == 3*n - 3 - k + assert graph.n_edges() == 3 * n - 3 - k assert graph.n_vertices() == n if set_position: graph.layout(layout='planar', save_pos=True) @@ -2399,6 +2407,7 @@ def RandomBicubicPlanar(n, seed=None, immutable=False): """ from sage.combinat.binary_tree import BinaryTrees from sage.rings.finite_rings.integer_mod_ring import Zmod + if not n: raise ValueError("n must be at least 1") if seed is not None: @@ -2408,7 +2417,7 @@ def RandomBicubicPlanar(n, seed=None, immutable=False): t = BinaryTrees(n).random_element() # next pick a random blossoming of this tree, compute its contour - contour = blossoming_contour(t) + [('xb',)] # adding the final xb + contour = blossoming_contour(t) + [('xb',)] # adding the final xb # first step : rotate the contour word to one of 3 balanced N = len(contour) @@ -2426,7 +2435,7 @@ def RandomBicubicPlanar(n, seed=None, immutable=False): # random choice among 3 possibilities for a balanced word idx = not_touched[randint(0, 2)] - w = contour[idx + 1:] + contour[:idx + 1] + w = contour[idx + 1 :] + contour[: idx + 1] # second step : create the graph by closure from the balanced word G = Graph(multiedges=True) @@ -2462,7 +2471,7 @@ def RandomBicubicPlanar(n, seed=None, immutable=False): return G.copy(immutable=True) if immutable else G -def RandomUnitDiskGraph(n, radius=.1, side=1, seed=None, immutable=False): +def RandomUnitDiskGraph(n, radius=0.1, side=1, seed=None, immutable=False): r""" Return a random unit disk graph of order `n`. @@ -2513,10 +2522,8 @@ def RandomUnitDiskGraph(n, radius=.1, side=1, seed=None, immutable=False): if seed is not None: set_random_seed(seed) from scipy.spatial import KDTree - points = [(side*random(), side*random()) for i in range(n)] + + points = [(side * random(), side * random()) for i in range(n)] T = KDTree(points) - adj = {i: [u for u in T.query_ball_point([points[i]], radius).item() if u != i] - for i in range(n)} - return Graph(adj, format='dict_of_lists', - pos={i: points[i] for i in range(n)}, - name="Random unit disk graph", immutable=immutable) + adj = {i: [u for u in T.query_ball_point([points[i]], radius).item() if u != i] for i in range(n)} + return Graph(adj, format='dict_of_lists', pos={i: points[i] for i in range(n)}, name="Random unit disk graph", immutable=immutable) diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index d224068e2ca..728aefeccb2 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -3,6 +3,7 @@ The methods defined here appear in :mod:`sage.graphs.graph_generators`. """ + # **************************************************************************** # Copyright (C) 2006 Robert L. Miller # and Emily A. Kirkman @@ -26,6 +27,7 @@ # Named Graphs # **************************************************************************** + def HarborthGraph(immutable=False): r""" Return the Harborth Graph. @@ -57,10 +59,7 @@ def HarborthGraph(immutable=False): sage: g.is_isomorphic(h) True """ - g = Graph(':s_OGKI?@_?g[QABAo__YEFCp@?iIEbqHWuWLbbh?}[OfcXpGhNHdYPY_SgdYX]' - 'pZkfJPuo[lfZHys^mFcDs}`pG{UNNgoHC}DIgrI[qjMhTyDQrQlVydrBYmWkn', - loops=False, multiedges=False, immutable=immutable, - name="Harborth Graph") + g = Graph(':s_OGKI?@_?g[QABAo__YEFCp@?iIEbqHWuWLbbh?}[OfcXpGhNHdYPY_SgdYX]' 'pZkfJPuo[lfZHys^mFcDs}`pG{UNNgoHC}DIgrI[qjMhTyDQrQlVydrBYmWkn', loops=False, multiedges=False, immutable=immutable, name="Harborth Graph") g.set_pos( { @@ -177,9 +176,8 @@ def HarriesGraph(embedding=1, immutable=False): ValueError: the value of embedding must be 1 or 2 """ from sage.graphs.generators.families import LCFGraph - g = LCFGraph(70, [-29, -19, -13, 13, 21, -27, 27, 33, -13, 13, - 19, -21, -33, 29], 5, - immutable=immutable, name="Harries Graph") + + g = LCFGraph(70, [-29, -19, -13, 13, 21, -27, 27, 33, -13, 13, 19, -21, -33, 29], 5, immutable=immutable, name="Harries Graph") if embedding == 1: gpos = g.get_pos() @@ -187,22 +185,18 @@ def HarriesGraph(embedding=1, immutable=False): # The graph's four orbits o = [None] * 4 - o[0] = [0, 2, 6, 8, 14, 16, 20, 22, 28, 30, 34, 36, 42, 44, 48, 50, - 56, 58, 62, 64] - o[1] = [1, 3, 5, 7, 9, 13, 15, 17, 19, 21, 23, 27, 29, 31, 33, 35, - 37, 41, 43, 45, 47, 49, 51, 55, 57, 59, 61, 63, 65, 69] + o[0] = [0, 2, 6, 8, 14, 16, 20, 22, 28, 30, 34, 36, 42, 44, 48, 50, 56, 58, 62, 64] + o[1] = [1, 3, 5, 7, 9, 13, 15, 17, 19, 21, 23, 27, 29, 31, 33, 35, 37, 41, 43, 45, 47, 49, 51, 55, 57, 59, 61, 63, 65, 69] o[2] = [60, 10, 12, 4, 24, 26, 18, 38, 40, 32, 52, 54, 46, 66, 68] o[3] = [11, 25, 39, 53, 67] # Correspondence between the vertices of one of the two Petersen graphs # on o[0] and the vertices of a standard Petersen graph object - g_to_p = {0: 0, 2: 1, 42: 5, 44: 8, 14: 7, 16: 2, 56: 9, 58: 6, - 28: 4, 30: 3} + g_to_p = {0: 0, 2: 1, 42: 5, 44: 8, 14: 7, 16: 2, 56: 9, 58: 6, 28: 4, 30: 3} # Correspondence between the vertices of the other Petersen graph on # o[0] and the vertices of the first one - g_to_g = {64: 44, 34: 0, 36: 28, 6: 2, 8: 58, 48: 16, 50: 30, - 20: 14, 22: 56, 62: 42} + g_to_g = {64: 44, 34: 0, 36: 28, 6: 2, 8: 58, 48: 16, 50: 30, 20: 14, 22: 56, 62: 42} # Position for the vertices from the first copy for v, i in g_to_p.items(): @@ -212,22 +206,22 @@ def HarriesGraph(embedding=1, immutable=False): offset = 3.5 for v, i in g_to_g.items(): x, y = gpos[i] - gpos[v] = (x + offset*0.5, y) - gpos[i] = (x - offset*0.5, y) + gpos[v] = (x + offset * 0.5, y) + gpos[i] = (x - offset * 0.5, y) # Vertices from o[1]. These are actually the "edges" of the copies of # Petersen. for v in o[1]: p1, p2 = (gpos[x] for x in g.neighbors(v) if x in o[0]) - gpos[v] = ((p1[0] + p2[0])/2, (p1[1] + p2[1])/2) + gpos[v] = ((p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2) # 15 vertices from o[2] for i, v in enumerate(o[2]): - gpos[v] = (-1.75 + i*.25, 2) + gpos[v] = (-1.75 + i * 0.25, 2) # 5 vertices from o[3] for i, v in enumerate(o[3]): - gpos[v] = (-1 + i*.5, 2.5) + gpos[v] = (-1 + i * 0.5, 2.5) return g @@ -300,13 +294,10 @@ def HarriesWongGraph(embedding=1, immutable=False): ... ValueError: the value of embedding must be 1 or 2 """ - L = [9, 25, 31, -17, 17, 33, 9, -29, -15, -9, 9, 25, -25, 29, 17, -9, - 9, -27, 35, -9, 9, -17, 21, 27, -29, -9, -25, 13, 19, -9, -33, - -17, 19, -31, 27, 11, -25, 29, -33, 13, -13, 21, -29, -21, 25, - 9, -11, -19, 29, 9, -27, -19, -13, -35, -9, 9, 17, 25, -9, 9, 27, - -27, -21, 15, -9, 29, -29, 33, -9, -25] + L = [9, 25, 31, -17, 17, 33, 9, -29, -15, -9, 9, 25, -25, 29, 17, -9, 9, -27, 35, -9, 9, -17, 21, 27, -29, -9, -25, 13, 19, -9, -33, -17, 19, -31, 27, 11, -25, 29, -33, 13, -13, 21, -29, -21, 25, 9, -11, -19, 29, 9, -27, -19, -13, -35, -9, 9, 17, 25, -9, 9, 27, -27, -21, 15, -9, 29, -29, 33, -9, -25] from sage.graphs.generators.families import LCFGraph + g = LCFGraph(70, L, 1, immutable=immutable, name="Harries-Wong graph") if embedding == 1: @@ -315,16 +306,14 @@ def HarriesWongGraph(embedding=1, immutable=False): # Binary tree (left side) d[66] = (-9.5, 0) g._line_embedding([37, 65, 67], first=(-8, 2.25), last=(-8, -2.25)) - g._line_embedding([36, 38, 64, 24, 68, 30], first=(-7, 3), - last=(-7, -3)) - g._line_embedding([35, 39, 63, 25, 59, 29, 11, 5, 55, 23, 69, 31], - first=(-6, 3.5), last=(-6, -3.5)) + g._line_embedding([36, 38, 64, 24, 68, 30], first=(-7, 3), last=(-7, -3)) + g._line_embedding([35, 39, 63, 25, 59, 29, 11, 5, 55, 23, 69, 31], first=(-6, 3.5), last=(-6, -3.5)) # Cube, corners: [9, 15, 21, 27, 45, 51, 57, 61] - g._circle_embedding([61, 9], center=(0, -1.5), shift=.2, radius=4) - g._circle_embedding([27, 15], center=(0, -1.5), shift=.7, radius=4*.707) - g._circle_embedding([51, 21], center=(0, 2.5), shift=.2, radius=4) - g._circle_embedding([45, 57], center=(0, 2.5), shift=.7, radius=4*.707) + g._circle_embedding([61, 9], center=(0, -1.5), shift=0.2, radius=4) + g._circle_embedding([27, 15], center=(0, -1.5), shift=0.7, radius=4 * 0.707) + g._circle_embedding([51, 21], center=(0, 2.5), shift=0.2, radius=4) + g._circle_embedding([45, 57], center=(0, 2.5), shift=0.7, radius=4 * 0.707) # Cube, subdivision g._line_embedding([21, 22, 43, 44, 45], first=d[21], last=d[45]) @@ -439,25 +428,14 @@ def WellsGraph(immutable=False): g.name("Wells graph") # Giving our graph a "not-so-bad" layout - g.relabel({ - (1, 3): 8, (3, 0): 18, (3, '+'): 22, (2, 1): 13, - (1, '+'): 10, (0, 3): 2, (2, '+'): 16, ('inf', '-'): 31, - (4, 0): 24, (1, 2): 7, (4, '+'): 28, (0, '-'): 5, - (0, 4): 3, (4, 1): 25, (2, '-'): 17, (3, 2): 20, - (3, '-'): 23, (1, '-'): 11, (1, 4): 9, (2, 3): 14, - ('inf', '+'): 30, (4, 2): 26, (1, 0): 6, (0, 1): 0, - (3, 1): 19, (0, 2): 1, (2, 0): 12, (4, '-'): 29, - (0, '+'): 4, (4, 3): 27, (3, 4): 21, (2, 4): 15}) - - p = [(1, 29, 20, 13, 12, 28, 14, 7), - (2, 5, 30, 23, 18, 4, 31, 22), - (3, 17, 21, 9, 24, 16, 27, 25), - (6, 10, 8, 15, 0, 11, 19, 26)] + g.relabel({(1, 3): 8, (3, 0): 18, (3, '+'): 22, (2, 1): 13, (1, '+'): 10, (0, 3): 2, (2, '+'): 16, ('inf', '-'): 31, (4, 0): 24, (1, 2): 7, (4, '+'): 28, (0, '-'): 5, (0, 4): 3, (4, 1): 25, (2, '-'): 17, (3, 2): 20, (3, '-'): 23, (1, '-'): 11, (1, 4): 9, (2, 3): 14, ('inf', '+'): 30, (4, 2): 26, (1, 0): 6, (0, 1): 0, (3, 1): 19, (0, 2): 1, (2, 0): 12, (4, '-'): 29, (0, '+'): 4, (4, 3): 27, (3, 4): 21, (2, 4): 15}) + + p = [(1, 29, 20, 13, 12, 28, 14, 7), (2, 5, 30, 23, 18, 4, 31, 22), (3, 17, 21, 9, 24, 16, 27, 25), (6, 10, 8, 15, 0, 11, 19, 26)] g._circle_embedding(p[0], radius=1) - g._circle_embedding(p[1], radius=.9) - g._circle_embedding(p[2], radius=.8) - g._circle_embedding(p[3], radius=.7) + g._circle_embedding(p[1], radius=0.9) + g._circle_embedding(p[2], radius=0.8) + g._circle_embedding(p[3], radius=0.7) return g.copy(immutable=True) if immutable else g @@ -505,53 +483,30 @@ def Cell600(embedding=1, immutable=False): from sage.groups.perm_gps.permgroup_named import AlternatingGroup x = polygen(QQ, 'x') - K = NumberField(x ** 2 - x - 1, 'f') + K = NumberField(x**2 - x - 1, 'f') f = K.gen() K4 = VectorSpace(K, 4) # first 96 vertices - step = [[a * f / 2, b * K(1) / 2, c * (f - 1) / 2, 0] - for a in [-1, 1] for b in [-1, 1] for c in [-1, 1]] - vert96 = [K4([v[s(1) - 1], v[s(2) - 1], v[s(3) - 1], v[s(4) - 1]]) - for v in step for s in AlternatingGroup(4)] + step = [[a * f / 2, b * K(1) / 2, c * (f - 1) / 2, 0] for a in [-1, 1] for b in [-1, 1] for c in [-1, 1]] + vert96 = [K4([v[s(1) - 1], v[s(2) - 1], v[s(3) - 1], v[s(4) - 1]]) for v in step for s in AlternatingGroup(4)] # 16 more vertices - vert16 = [K4([K(a) / 2, K(b) / 2, K(c) / 2, K(d) / 2]) - for a in [-1, 1] for b in [-1, 1] - for c in [-1, 1] for d in [-1, 1]] + vert16 = [K4([K(a) / 2, K(b) / 2, K(c) / 2, K(d) / 2]) for a in [-1, 1] for b in [-1, 1] for c in [-1, 1] for d in [-1, 1]] # 8 last vertices - vert8 = [K4([1, 0, 0, 0]), K4([-1, 0, 0, 0]), - K4([0, 1, 0, 0]), K4([0, -1, 0, 0]), - K4([0, 0, 1, 0]), K4([0, 0, -1, 0]), - K4([0, 0, 0, 1]), K4([0, 0, 0, -1])] + vert8 = [K4([1, 0, 0, 0]), K4([-1, 0, 0, 0]), K4([0, 1, 0, 0]), K4([0, -1, 0, 0]), K4([0, 0, 1, 0]), K4([0, 0, -1, 0]), K4([0, 0, 0, 1]), K4([0, 0, 0, -1])] # all vertices together U = vert96 + vert16 + vert8 - g = Graph([list(range(120)), - lambda i, j: U[i].inner_product(U[j]) == f / 2], - format='rule', immutable=immutable) + g = Graph([list(range(120)), lambda i, j: U[i].inner_product(U[j]) == f / 2], format='rule', immutable=immutable) # Embedding if embedding == 1: - pos = [0, 1, 3, 13, 78, 90, 93, 110, 29, 104, 11, 48, 107, 83, 92, 55, - 32, 16, 117, 24, 26, 56, 52, 47, 75, 72, 66, 112, 27, 115, 21, - 33, 118, 79, 91, 37, 2, 5, 96, 31, 82, 88, 94, 74, 50, 28, 20, - 105, 45, 99, 70, 25, 101, 54, 46, 51, 17, 35, 98, 41, 84, 85, - 87, 73, 18, 6, 9, 97, 65, 103, 95, 36, 100, 23, 8, 43, 68, 76, - 116, 60, 62, 44, 40, 59, 15, 12, 30, 113, 63, 114, 81, 69, 119, - 19, 7, 49, 86, 89, 111, 67, 22, 4, 10, 14, 38, 64, 80, 102, 57, - 108, 34, 61, 106, 42, 58, 39, 77, 71, 109, 53] + pos = [0, 1, 3, 13, 78, 90, 93, 110, 29, 104, 11, 48, 107, 83, 92, 55, 32, 16, 117, 24, 26, 56, 52, 47, 75, 72, 66, 112, 27, 115, 21, 33, 118, 79, 91, 37, 2, 5, 96, 31, 82, 88, 94, 74, 50, 28, 20, 105, 45, 99, 70, 25, 101, 54, 46, 51, 17, 35, 98, 41, 84, 85, 87, 73, 18, 6, 9, 97, 65, 103, 95, 36, 100, 23, 8, 43, 68, 76, 116, 60, 62, 44, 40, 59, 15, 12, 30, 113, 63, 114, 81, 69, 119, 19, 7, 49, 86, 89, 111, 67, 22, 4, 10, 14, 38, 64, 80, 102, 57, 108, 34, 61, 106, 42, 58, 39, 77, 71, 109, 53] else: - pos = [0, 1, 2, 3, 4, 6, 7, 8, 10, 13, 14, 21, 37, 103, 36, 65, 113, - 25, 80, 26, 12, 78, 24, 83, 54, 66, 114, 46, 63, 101, 109, 93, - 79, 75, 51, 44, 31, 119, 43, 5, 57, 100, 11, 108, 34, 41, 69, - 96, 82, 116, 68, 64, 47, 102, 52, 35, 17, 76, 110, 38, 84, 85, - 86, 87, 88, 90, 91, 92, 94, 73, 74, 81, 49, 104, 48, 29, 112, - 61, 20, 62, 72, 18, 60, 23, 42, 30, 115, 58, 27, 106, 98, 9, 19, - 15, 39, 56, 67, 118, 55, 89, 45, 107, 95, 99, 70, 53, 33, 111, - 22, 117, 32, 28, 59, 105, 40, 71, 77, 16, 97, 50] + pos = [0, 1, 2, 3, 4, 6, 7, 8, 10, 13, 14, 21, 37, 103, 36, 65, 113, 25, 80, 26, 12, 78, 24, 83, 54, 66, 114, 46, 63, 101, 109, 93, 79, 75, 51, 44, 31, 119, 43, 5, 57, 100, 11, 108, 34, 41, 69, 96, 82, 116, 68, 64, 47, 102, 52, 35, 17, 76, 110, 38, 84, 85, 86, 87, 88, 90, 91, 92, 94, 73, 74, 81, 49, 104, 48, 29, 112, 61, 20, 62, 72, 18, 60, 23, 42, 30, 115, 58, 27, 106, 98, 9, 19, 15, 39, 56, 67, 118, 55, 89, 45, 107, 95, 99, 70, 53, 33, 111, 22, 117, 32, 28, 59, 105, 40, 71, 77, 16, 97, 50] g._circle_embedding(pos) @@ -599,87 +554,631 @@ def Cell120(immutable=False): from sage.combinat.permutation import Permutations x = polygen(QQ, 'x') - K = NumberField(x ** 2 - x - 1, 'f') + K = NumberField(x**2 - x - 1, 'f') f = K.gen() K4 = VectorSpace(K, 4) # first 216 vertices - step = [(0, 0, K(a) * 2, K(b) * 2) - for a in [-1, 1] for b in [-1, 1]] - step += [(a * K(1), b * K(1), c * K(1), d * (2 * f - 1)) - for a in [-1, 1] for b in [-1, 1] - for c in [-1, 1] for d in [-1, 1]] - step += [(a * (2 - f), b * f, c * f, d * f) - for a in [-1, 1] for b in [-1, 1] - for c in [-1, 1] for d in [-1, 1]] - step += [(a * (f - 1), b * (f - 1), c * (f - 1), d * (f + 1)) - for a in [-1, 1] for b in [-1, 1] - for c in [-1, 1] for d in [-1, 1]] - ens1 = frozenset([(v[s(1) - 1], v[s(2) - 1], v[s(3) - 1], v[s(4) - 1]) - for v in step for s in Permutations(4)]) + step = [(0, 0, K(a) * 2, K(b) * 2) for a in [-1, 1] for b in [-1, 1]] + step += [(a * K(1), b * K(1), c * K(1), d * (2 * f - 1)) for a in [-1, 1] for b in [-1, 1] for c in [-1, 1] for d in [-1, 1]] + step += [(a * (2 - f), b * f, c * f, d * f) for a in [-1, 1] for b in [-1, 1] for c in [-1, 1] for d in [-1, 1]] + step += [(a * (f - 1), b * (f - 1), c * (f - 1), d * (f + 1)) for a in [-1, 1] for b in [-1, 1] for c in [-1, 1] for d in [-1, 1]] + ens1 = frozenset([(v[s(1) - 1], v[s(2) - 1], v[s(3) - 1], v[s(4) - 1]) for v in step for s in Permutations(4)]) vert1 = [K4(w) for w in ens1] # 384 more vertices - step = [(0, a * (2 - f), b * K(1), c * (f + 1)) - for a in [-1, 1] for b in [-1, 1] for c in [-1, 1]] - step += [(0, a * (f - 1), b * f, c * (2 * f - 1)) - for a in [-1, 1] for b in [-1, 1] for c in [-1, 1]] - step += [(a * (f - 1), b * K(1), c * f, d * K(2)) - for a in [-1, 1] for b in [-1, 1] - for c in [-1, 1] for d in [-1, 1]] - vert2 = [K4([v[s(1) - 1], v[s(2) - 1], v[s(3) - 1], v[s(4) - 1]]) - for v in step for s in AlternatingGroup(4)] + step = [(0, a * (2 - f), b * K(1), c * (f + 1)) for a in [-1, 1] for b in [-1, 1] for c in [-1, 1]] + step += [(0, a * (f - 1), b * f, c * (2 * f - 1)) for a in [-1, 1] for b in [-1, 1] for c in [-1, 1]] + step += [(a * (f - 1), b * K(1), c * f, d * K(2)) for a in [-1, 1] for b in [-1, 1] for c in [-1, 1] for d in [-1, 1]] + vert2 = [K4([v[s(1) - 1], v[s(2) - 1], v[s(3) - 1], v[s(4) - 1]]) for v in step for s in AlternatingGroup(4)] # all vertices together U = vert1 + vert2 - g = Graph([list(range(600)), - lambda i, j: U[i].inner_product(U[j]) == 6*f-2], - format='rule', immutable=immutable) - - pos = [0, 1, 3, 5, 6, 7, 8, 9, 11, 12, 14, 15, 16, 17, 20, 21, 23, 24, 25, - 27, 33, 40, 47, 49, 76, 77, 216, 217, 218, 219, 220, 222, 224, 225, - 226, 230, 231, 232, 233, 235, 238, 241, 242, 245, 247, 249, 251, 253, - 260, 261, 211, 66, 26, 307, 598, 305, 187, 374, 311, 205, 296, 108, - 366, 172, 255, 89, 229, 81, 529, 548, 439, 382, 166, 496, 313, 484, - 402, 234, 530, 256, 358, 406, 553, 577, 583, 401, 334, 417, 257, 438, - 373, 544, 509, 365, 378, 487, 377, 390, 349, 325, 65, 78, 184, 13, - 185, 18, 210, 84, 145, 83, 180, 158, 118, 109, 103, 130, 105, 51, - 178, 155, 110, 85, 206, 95, 204, 190, 514, 513, 515, 466, 467, 441, - 442, 587, 585, 576, 565, 564, 566, 540, 506, 436, 435, 424, 507, 543, - 545, 547, 582, 440, 169, 63, 29, 575, 237, 549, 37, 375, 430, 159, - 457, 61, 331, 208, 498, 39, 578, 48, 244, 486, 411, 364, 73, 455, - 321, 240, 381, 542, 243, 500, 343, 333, 271, 518, 552, 357, 314, 299, - 499, 412, 376, 596, 561, 319, 400, 264, 388, 362, 355, 386, 87, 186, - 52, 99, 125, 113, 36, 121, 41, 127, 149, 100, 31, 137, 177, 43, 32, - 45, 62, 191, 188, 106, 195, 141, 142, 96, 489, 491, 490, 475, 474, - 447, 448, 589, 588, 517, 472, 473, 471, 450, 419, 519, 521, 468, 562, - 594, 595, 488, 554, 413, 167, 116, 4, 557, 504, 536, 170, 389, 410, - 128, 559, 203, 348, 147, 477, 22, 516, 162, 423, 266, 274, 320, 144, - 246, 395, 437, 363, 452, 425, 478, 315, 312, 428, 288, 270, 344, 323, - 493, 479, 275, 387, 286, 284, 347, 359, 462, 336, 368, 392, 324, 44, - 75, 69, 46, 57, 138, 35, 80, 88, 199, 70, 152, 161, 181, 34, 207, - 164, 71, 115, 55, 163, 72, 171, 93, 165, 124, 300, 301, 302, 303, - 304, 306, 308, 309, 310, 290, 291, 292, 293, 295, 298, 277, 278, 281, - 283, 285, 287, 265, 272, 273, 19, 10, 107, 223, 418, 221, 67, 338, - 227, 196, 236, 91, 354, 154, 267, 30, 289, 215, 469, 464, 571, 346, - 151, 508, 397, 520, 318, 294, 470, 268, 370, 322, 445, 421, 427, 317, - 394, 597, 269, 570, 337, 460, 497, 353, 342, 523, 341, 330, 361, 385, - 126, 92, 94, 176, 135, 117, 114, 197, 214, 179, 60, 42, 198, 202, - 102, 101, 174, 104, 146, 90, 38, 111, 122, 157, 153, 133, 502, 501, - 503, 550, 551, 573, 574, 431, 429, 420, 433, 432, 434, 456, 494, 568, - 567, 580, 495, 459, 461, 463, 426, 572, 182, 58, 82, 443, 297, 465, - 86, 339, 586, 209, 541, 140, 391, 143, 510, 28, 422, 213, 280, 522, - 591, 352, 120, 563, 405, 276, 345, 458, 279, 512, 379, 393, 259, 482, - 444, 369, 398, 239, 511, 592, 340, 416, 453, 403, 316, 252, 328, 350, - 367, 326, 2, 175, 97, 139, 74, 131, 173, 134, 193, 192, 132, 79, 50, - 200, 64, 150, 201, 194, 212, 183, 54, 56, 98, 123, 112, 156, 525, - 527, 526, 535, 534, 555, 556, 409, 408, 481, 532, 533, 531, 558, 599, - 483, 485, 528, 454, 414, 415, 524, 446, 593, 160, 59, 68, 449, 492, - 476, 148, 329, 590, 119, 451, 189, 360, 53, 537, 129, 480, 136, 579, - 254, 262, 404, 168, 282, 335, 569, 351, 560, 581, 538, 399, 396, 584, - 228, 258, 380, 407, 505, 539, 263, 327, 250, 248, 383, 371, 546, 372, - 356, 332, 384] + g = Graph([list(range(600)), lambda i, j: U[i].inner_product(U[j]) == 6 * f - 2], format='rule', immutable=immutable) + + pos = [ + 0, + 1, + 3, + 5, + 6, + 7, + 8, + 9, + 11, + 12, + 14, + 15, + 16, + 17, + 20, + 21, + 23, + 24, + 25, + 27, + 33, + 40, + 47, + 49, + 76, + 77, + 216, + 217, + 218, + 219, + 220, + 222, + 224, + 225, + 226, + 230, + 231, + 232, + 233, + 235, + 238, + 241, + 242, + 245, + 247, + 249, + 251, + 253, + 260, + 261, + 211, + 66, + 26, + 307, + 598, + 305, + 187, + 374, + 311, + 205, + 296, + 108, + 366, + 172, + 255, + 89, + 229, + 81, + 529, + 548, + 439, + 382, + 166, + 496, + 313, + 484, + 402, + 234, + 530, + 256, + 358, + 406, + 553, + 577, + 583, + 401, + 334, + 417, + 257, + 438, + 373, + 544, + 509, + 365, + 378, + 487, + 377, + 390, + 349, + 325, + 65, + 78, + 184, + 13, + 185, + 18, + 210, + 84, + 145, + 83, + 180, + 158, + 118, + 109, + 103, + 130, + 105, + 51, + 178, + 155, + 110, + 85, + 206, + 95, + 204, + 190, + 514, + 513, + 515, + 466, + 467, + 441, + 442, + 587, + 585, + 576, + 565, + 564, + 566, + 540, + 506, + 436, + 435, + 424, + 507, + 543, + 545, + 547, + 582, + 440, + 169, + 63, + 29, + 575, + 237, + 549, + 37, + 375, + 430, + 159, + 457, + 61, + 331, + 208, + 498, + 39, + 578, + 48, + 244, + 486, + 411, + 364, + 73, + 455, + 321, + 240, + 381, + 542, + 243, + 500, + 343, + 333, + 271, + 518, + 552, + 357, + 314, + 299, + 499, + 412, + 376, + 596, + 561, + 319, + 400, + 264, + 388, + 362, + 355, + 386, + 87, + 186, + 52, + 99, + 125, + 113, + 36, + 121, + 41, + 127, + 149, + 100, + 31, + 137, + 177, + 43, + 32, + 45, + 62, + 191, + 188, + 106, + 195, + 141, + 142, + 96, + 489, + 491, + 490, + 475, + 474, + 447, + 448, + 589, + 588, + 517, + 472, + 473, + 471, + 450, + 419, + 519, + 521, + 468, + 562, + 594, + 595, + 488, + 554, + 413, + 167, + 116, + 4, + 557, + 504, + 536, + 170, + 389, + 410, + 128, + 559, + 203, + 348, + 147, + 477, + 22, + 516, + 162, + 423, + 266, + 274, + 320, + 144, + 246, + 395, + 437, + 363, + 452, + 425, + 478, + 315, + 312, + 428, + 288, + 270, + 344, + 323, + 493, + 479, + 275, + 387, + 286, + 284, + 347, + 359, + 462, + 336, + 368, + 392, + 324, + 44, + 75, + 69, + 46, + 57, + 138, + 35, + 80, + 88, + 199, + 70, + 152, + 161, + 181, + 34, + 207, + 164, + 71, + 115, + 55, + 163, + 72, + 171, + 93, + 165, + 124, + 300, + 301, + 302, + 303, + 304, + 306, + 308, + 309, + 310, + 290, + 291, + 292, + 293, + 295, + 298, + 277, + 278, + 281, + 283, + 285, + 287, + 265, + 272, + 273, + 19, + 10, + 107, + 223, + 418, + 221, + 67, + 338, + 227, + 196, + 236, + 91, + 354, + 154, + 267, + 30, + 289, + 215, + 469, + 464, + 571, + 346, + 151, + 508, + 397, + 520, + 318, + 294, + 470, + 268, + 370, + 322, + 445, + 421, + 427, + 317, + 394, + 597, + 269, + 570, + 337, + 460, + 497, + 353, + 342, + 523, + 341, + 330, + 361, + 385, + 126, + 92, + 94, + 176, + 135, + 117, + 114, + 197, + 214, + 179, + 60, + 42, + 198, + 202, + 102, + 101, + 174, + 104, + 146, + 90, + 38, + 111, + 122, + 157, + 153, + 133, + 502, + 501, + 503, + 550, + 551, + 573, + 574, + 431, + 429, + 420, + 433, + 432, + 434, + 456, + 494, + 568, + 567, + 580, + 495, + 459, + 461, + 463, + 426, + 572, + 182, + 58, + 82, + 443, + 297, + 465, + 86, + 339, + 586, + 209, + 541, + 140, + 391, + 143, + 510, + 28, + 422, + 213, + 280, + 522, + 591, + 352, + 120, + 563, + 405, + 276, + 345, + 458, + 279, + 512, + 379, + 393, + 259, + 482, + 444, + 369, + 398, + 239, + 511, + 592, + 340, + 416, + 453, + 403, + 316, + 252, + 328, + 350, + 367, + 326, + 2, + 175, + 97, + 139, + 74, + 131, + 173, + 134, + 193, + 192, + 132, + 79, + 50, + 200, + 64, + 150, + 201, + 194, + 212, + 183, + 54, + 56, + 98, + 123, + 112, + 156, + 525, + 527, + 526, + 535, + 534, + 555, + 556, + 409, + 408, + 481, + 532, + 533, + 531, + 558, + 599, + 483, + 485, + 528, + 454, + 414, + 415, + 524, + 446, + 593, + 160, + 59, + 68, + 449, + 492, + 476, + 148, + 329, + 590, + 119, + 451, + 189, + 360, + 53, + 537, + 129, + 480, + 136, + 579, + 254, + 262, + 404, + 168, + 282, + 335, + 569, + 351, + 560, + 581, + 538, + 399, + 396, + 584, + 228, + 258, + 380, + 407, + 505, + 539, + 263, + 327, + 250, + 248, + 383, + 371, + 546, + 372, + 356, + 332, + 384, + ] g._circle_embedding(pos) return g @@ -710,8 +1209,8 @@ def SuzukiGraph(immutable=False): (1782, 416, 100, 96) """ from sage.groups.perm_gps.permgroup_named import SuzukiSporadicGroup - g = Graph(SuzukiSporadicGroup().orbit((1, 2), "OnSets"), - format='list_of_edges', name="Suzuki graph") + + g = Graph(SuzukiSporadicGroup().orbit((1, 2), "OnSets"), format='list_of_edges', name="Suzuki graph") if immutable: return g.relabel(inplace=False, immutable=True) g.relabel(inplace=True) @@ -789,60 +1288,61 @@ def HallJankoGraph(from_string=True, immutable=False): True """ if from_string: - string = (":~?@c__E@?g?A?w?A@GCA_?CA`OWF`W?EAW?@?_OD@_[GAgcIaGGB@OcIA" - "wCE@o_K_?GB@?WGAouC@OsN_?GB@O[GB`A@@_e?@OgLB_{Q_?GC@O[GAOs" - "OCWGBA?kKBPA@?_[KB_{OCPKT`o_RD`]A?o[HBOwODW?DA?cIB?wRDP[X`" - "ogKB_{QD@]B@o_KBPWXE`mC@o_JB?{PDPq@?oWGA_{OCPKTDp_YEwCA@_c" - "IBOwOC`OX_OGB@?WPDPcYFg?C@_gKBp?SE@cYF`{_`?SGAOoOC`_\\FwCE" - "A?gKBO{QD@k[FqI??_OFA_oQE@k\\Fq?`GgCB@pGRD@_XFP{a_?SE@ocIA" - "ooNCPOUEqU@?oODA?cJB_{UEqYC@_kLC@CREPk]GAGbHgCA@?SMBpCSD`[" - "YFq?`Ga]BA?gPC`KSD`_\\Fa?cHWGB@?[IAooPD`[WF@s^HASeIg?@@OcP" - "C`KYF@w^GQ[h`O[HAooMC@CQCpSVEPk\\GaSeIG?FA?kLB_{OC`OVE@cYG" - "QUA@?WLBp?PC`KVEqKgJg?DA?sMBpCSDP[WEQKfIay@?_KD@_[GC`SUE@k" - "[FaKdHa[k_?OLC@CRD@WVEpo^HAWfIAciIqoo_?CB@?kMCpOUE`o\\GAKg" - "IQgq_?GD@_[GB?{OCpWVE@cYFACaHAWhJR?q_?CC@_kKBpC\\GACdHa[kJ" - "a{o_?CA?oOFBpGRD@o\\GaKdIQonKrOt_?WHA`?PC`KTD`k]FqSeIaolJr" - "CqLWCA@OkKCPGRDpcYGAKdIAgjJAsmJr?t__OE@ogJB_{XEps`HA[gIQwn" - "KWKGAOoMBpGUE`k[Fa?aHqckJbSuLw?@?_SHA_kLC@OTFPw^GaOkLg?B@?" - "[HA_{PDP_XFaCbHa[gIqooKRWx_?CFBpOTE@cZFPw^GACcHQgoKrSvMwWG" - "BOwQCp_YFP{`HASfJAwnKRSx_OSSDP[WEq?aGqSfIQsoKR_zNWCE@o_HA_" - "sREPg^GAGcHQWfIAciKbOxNg?A@__IAooMC`KTD`g\\GAKcIasoKrOtLb[" - "wMbyCA?cKBp?TD`[WE`s^GQGbHqcjJrK{NRw~_oODA?sNC@CQCpOZF@s]G" - "QOfIaolJrGsLbk}_?OFA_sRD@SVE`k[HQcjJa{qLb[xMb|?_OOFA?cIAos" - "RDP_ZFa?aGqOfIAsuMbk{Ns@@OsQAA_sPDPWXE`o\\FqKdIQkkJrCuLr_x" - "Mro}NsDAPG?@@OWFApKUE@o`IQolKRKsLrc|NsQC@OWGAOgJCpOWE`o_GQ" - "KiIqwnKr_~OcLCPS]A?oWHA_oMBpKSDP[\\FagjKBWxMbk{OSQ@@O_IAoo" - "LBpCSD`g\\FaGbHQWgIQgmKRKwMRl?PgGC@OWHB@KSE@c[FqCaGqSeIAkk" - "KBCqLBSuMBpGQWCA@?cKBOwRDPWVE@k^GqOfJr?pKbKtLrs}OSHDQwKIBO" - "wPD@WWEQ?`HQWfIQglKBOtLbo}Ns@@OsTE_?kLCpWWHA[gIqomKBGwMRgz" - "NBw~OSPDPc\\H_?CFAOoLCPSVE`o\\GAOeJAwpKbKtMrx?Qcq??OKFA?gJ" - "B`?QDpcYEpo]FqKfIAgjJB?qKr_{NS@A__SE@o_HBO{PC`OTD`{_HaciIq" - "{vMbt?OcPFQCeB@?SKBOwRD@SXE`k[FPw`HQ_lKRKxNRxBPC\\HQclK_?K" - "EB?sOC`OTDa?`GqWgJRCrNBw~OSHFQStMRtDQ_?KC@OoQE`k_GaOdHa[gI" - "q{tMBg|Nb|?OcPMSDDQSwCB@_cJB_{OCpOVFP{dHa[jJQwqKrk}NsHBQCd" - "MRtMA?oSEA_wPDp_YEpo]GAOeIq{pLBk}NsLEQCtNTDU??OKEA_oLC@[[G" - "aKnKBOtLbk~OCPFQStNSDLSTgGKC@GSD`[WEpw_GQGcIAciJAwpKb_xMbk" - "~QShJRc|R`_wNCPcZF@s^GAGbHA_hJR?qKrOvMRg|NsDEPsxTTgCB@?gJB" - "?sMC@CUDp_]FqCaHQcjJQwtLrhCPS\\IRCtQTw?B@?SHA_wPC`_aGqOiJa" - "{oKRKvMRpFQChKRtXVUTi??ocNC@KUE@cYFaGdHa_mJrKsLb[yMro|OcXI" - "RdPTTddZaOgJB@?UEPk[FQCfIaolJrSvMBczNR|AOsXFQCtOTtaB@?WGAP" - "?TEPo\\GAGdHqgmKBCqLR[xMb|?PC`HQs|TTt`XUtu@?o[HB?sNCPGXF@{" - "_GQKcIqolJb_yNCLDPs`MRtDRTTdYUwSEA?kLB`CWF@s]FqGgIqooLRgzN" - "RxFQSlMSDDQTDXVUTi@?_KDAOoLBpKUEQOfIa{oLB_xMrt?Os\\HQcpMST" - "HSTtl[VT}A@ocJBOwSD`_XEpo_Ha_mJrKtLbgzNSTGQspLRtDUUDp\\WG[" - "HB`CQCp[WFQGgIQgkJQ{rLbc{Nc@APsdLRt@PSt\\WUtt_Wn") - g = Graph(string, loops=False, multiedges=False, immutable=immutable, - name="Hall-Janko graph") + string = ( + ":~?@c__E@?g?A?w?A@GCA_?CA`OWF`W?EAW?@?_OD@_[GAgcIaGGB@OcIA" + "wCE@o_K_?GB@?WGAouC@OsN_?GB@O[GB`A@@_e?@OgLB_{Q_?GC@O[GAOs" + "OCWGBA?kKBPA@?_[KB_{OCPKT`o_RD`]A?o[HBOwODW?DA?cIB?wRDP[X`" + "ogKB_{QD@]B@o_KBPWXE`mC@o_JB?{PDPq@?oWGA_{OCPKTDp_YEwCA@_c" + "IBOwOC`OX_OGB@?WPDPcYFg?C@_gKBp?SE@cYF`{_`?SGAOoOC`_\\FwCE" + "A?gKBO{QD@k[FqI??_OFA_oQE@k\\Fq?`GgCB@pGRD@_XFP{a_?SE@ocIA" + "ooNCPOUEqU@?oODA?cJB_{UEqYC@_kLC@CREPk]GAGbHgCA@?SMBpCSD`[" + "YFq?`Ga]BA?gPC`KSD`_\\Fa?cHWGB@?[IAooPD`[WF@s^HASeIg?@@OcP" + "C`KYF@w^GQ[h`O[HAooMC@CQCpSVEPk\\GaSeIG?FA?kLB_{OC`OVE@cYG" + "QUA@?WLBp?PC`KVEqKgJg?DA?sMBpCSDP[WEQKfIay@?_KD@_[GC`SUE@k" + "[FaKdHa[k_?OLC@CRD@WVEpo^HAWfIAciIqoo_?CB@?kMCpOUE`o\\GAKg" + "IQgq_?GD@_[GB?{OCpWVE@cYFACaHAWhJR?q_?CC@_kKBpC\\GACdHa[kJ" + "a{o_?CA?oOFBpGRD@o\\GaKdIQonKrOt_?WHA`?PC`KTD`k]FqSeIaolJr" + "CqLWCA@OkKCPGRDpcYGAKdIAgjJAsmJr?t__OE@ogJB_{XEps`HA[gIQwn" + "KWKGAOoMBpGUE`k[Fa?aHqckJbSuLw?@?_SHA_kLC@OTFPw^GaOkLg?B@?" + "[HA_{PDP_XFaCbHa[gIqooKRWx_?CFBpOTE@cZFPw^GACcHQgoKrSvMwWG" + "BOwQCp_YFP{`HASfJAwnKRSx_OSSDP[WEq?aGqSfIQsoKR_zNWCE@o_HA_" + "sREPg^GAGcHQWfIAciKbOxNg?A@__IAooMC`KTD`g\\GAKcIasoKrOtLb[" + "wMbyCA?cKBp?TD`[WE`s^GQGbHqcjJrK{NRw~_oODA?sNC@CQCpOZF@s]G" + "QOfIaolJrGsLbk}_?OFA_sRD@SVE`k[HQcjJa{qLb[xMb|?_OOFA?cIAos" + "RDP_ZFa?aGqOfIAsuMbk{Ns@@OsQAA_sPDPWXE`o\\FqKdIQkkJrCuLr_x" + "Mro}NsDAPG?@@OWFApKUE@o`IQolKRKsLrc|NsQC@OWGAOgJCpOWE`o_GQ" + "KiIqwnKr_~OcLCPS]A?oWHA_oMBpKSDP[\\FagjKBWxMbk{OSQ@@O_IAoo" + "LBpCSD`g\\FaGbHQWgIQgmKRKwMRl?PgGC@OWHB@KSE@c[FqCaGqSeIAkk" + "KBCqLBSuMBpGQWCA@?cKBOwRDPWVE@k^GqOfJr?pKbKtLrs}OSHDQwKIBO" + "wPD@WWEQ?`HQWfIQglKBOtLbo}Ns@@OsTE_?kLCpWWHA[gIqomKBGwMRgz" + "NBw~OSPDPc\\H_?CFAOoLCPSVE`o\\GAOeJAwpKbKtMrx?Qcq??OKFA?gJ" + "B`?QDpcYEpo]FqKfIAgjJB?qKr_{NS@A__SE@o_HBO{PC`OTD`{_HaciIq" + "{vMbt?OcPFQCeB@?SKBOwRD@SXE`k[FPw`HQ_lKRKxNRxBPC\\HQclK_?K" + "EB?sOC`OTDa?`GqWgJRCrNBw~OSHFQStMRtDQ_?KC@OoQE`k_GaOdHa[gI" + "q{tMBg|Nb|?OcPMSDDQSwCB@_cJB_{OCpOVFP{dHa[jJQwqKrk}NsHBQCd" + "MRtMA?oSEA_wPDp_YEpo]GAOeIq{pLBk}NsLEQCtNTDU??OKEA_oLC@[[G" + "aKnKBOtLbk~OCPFQStNSDLSTgGKC@GSD`[WEpw_GQGcIAciJAwpKb_xMbk" + "~QShJRc|R`_wNCPcZF@s^GAGbHA_hJR?qKrOvMRg|NsDEPsxTTgCB@?gJB" + "?sMC@CUDp_]FqCaHQcjJQwtLrhCPS\\IRCtQTw?B@?SHA_wPC`_aGqOiJa" + "{oKRKvMRpFQChKRtXVUTi??ocNC@KUE@cYFaGdHa_mJrKsLb[yMro|OcXI" + "RdPTTddZaOgJB@?UEPk[FQCfIaolJrSvMBczNR|AOsXFQCtOTtaB@?WGAP" + "?TEPo\\GAGdHqgmKBCqLR[xMb|?PC`HQs|TTt`XUtu@?o[HB?sNCPGXF@{" + "_GQKcIqolJb_yNCLDPs`MRtDRTTdYUwSEA?kLB`CWF@s]FqGgIqooLRgzN" + "RxFQSlMSDDQTDXVUTi@?_KDAOoLBpKUEQOfIa{oLB_xMrt?Os\\HQcpMST" + "HSTtl[VT}A@ocJBOwSD`_XEpo_Ha_mJrKtLbgzNSTGQspLRtDUUDp\\WG[" + "HB`CQCp[WFQGgIQgkJQ{rLbc{Nc@APsdLRt@PSt\\WUtt_Wn" + ) + g = Graph(string, loops=False, multiedges=False, immutable=immutable, name="Hall-Janko graph") else: # The following construction is due to version 3 of the ATLAS of # Finite Group Representations, specifically the page at # http://brauer.maths.qmul.ac.uk/Atlas/v5/permrep/J2G1-p100B0 . from sage.libs.gap.libgap import libgap + libgap.load_package("AtlasRep") # representation of HJ on 100 points G = libgap.AtlasGroup("HJ", libgap.NrMovedPoints, 100) - g = Graph(G.Orbit([1, 5], libgap.OnSets), format='list_of_edges', - name="Hall-Janko graph") + g = Graph(G.Orbit([1, 5], libgap.OnSets), format='list_of_edges', name="Hall-Janko graph") if immutable: g = g.relabel(inplace=False, immutable=True) else: @@ -904,13 +1404,10 @@ def Balaban10Cage(embedding=1, immutable=False): ... ValueError: the value of embedding must be 1 or 2 """ - L = [-9, -25, -19, 29, 13, 35, -13, -29, 19, 25, 9, -29, 29, 17, 33, - 21, 9, -13, -31, -9, 25, 17, 9, -31, 27, -9, 17, -19, -29, 27, - -17, -9, -29, 33, -25, 25, -21, 17, -17, 29, 35, -29, 17, -17, - 21, -25, 25, -33, 29, 9, 17, -27, 29, 19, -17, 9, -27, 31, -9, - -17, -25, 9, 31, 13, -9, -21, -33, -17, -29, 29] + L = [-9, -25, -19, 29, 13, 35, -13, -29, 19, 25, 9, -29, 29, 17, 33, 21, 9, -13, -31, -9, 25, 17, 9, -31, 27, -9, 17, -19, -29, 27, -17, -9, -29, 33, -25, 25, -21, 17, -17, 29, 35, -29, 17, -17, 21, -25, 25, -33, 29, 9, 17, -27, 29, 19, -17, 9, -27, 31, -9, -17, -25, 9, 31, 13, -9, -21, -33, -17, -29, 29] from sage.graphs.generators.families import LCFGraph + g = LCFGraph(70, L, 1, immutable=immutable, name="Balaban 10-cage") if embedding == 2: @@ -921,9 +1418,8 @@ def Balaban10Cage(embedding=1, immutable=False): L3 = [5, 24, 35, 46, 29, 40, 51, 34, 45, 56] g._circle_embedding(L3, center=(0, 0), radius=4.3) - L2 = [6, 4, 23, 25, 60, 36, 1, 47, 28, 30, 39, 41, 50, 52, 33, 9, 44, - 20, 55, 57] - g._circle_embedding(L2, center=(0, 0), radius=5, shift=-.5) + L2 = [6, 4, 23, 25, 60, 36, 1, 47, 28, 30, 39, 41, 50, 52, 33, 9, 44, 20, 55, 57] + g._circle_embedding(L2, center=(0, 0), radius=5, shift=-0.5) L1a = [69, 68, 67, 66, 65, 64, 63, 62, 61, 0] L1b = [19, 18, 17, 16, 15, 14, 13, 12, 11, 10] @@ -1009,103 +1505,143 @@ def Balaban11Cage(embedding=1, immutable=False): pos_dict = {} for j in range(8): for i in range(8): - pos_dict[str(j) + str(i)] = [ - 0.8 * float(cos(2*((8*j + i)*pi/64 + pi/128))), - 0.8 * float(sin(2*((8*j + i)*pi/64 + pi/128))) - ] + pos_dict[str(j) + str(i)] = [0.8 * float(cos(2 * ((8 * j + i) * pi / 64 + pi / 128))), 0.8 * float(sin(2 * ((8 * j + i) * pi / 64 + pi / 128)))] for i in range(4): - pos_dict['1' + str(j) + str(i)] = [ - 1.1 * float(cos(2*((4*j + i)*pi/32 + pi/64))), - 1.1 * float(sin(2*((4*j + i)*pi/32 + pi/64))) - ] + pos_dict['1' + str(j) + str(i)] = [1.1 * float(cos(2 * ((4 * j + i) * pi / 32 + pi / 64))), 1.1 * float(sin(2 * ((4 * j + i) * pi / 32 + pi / 64)))] for i in range(2): - pos_dict['1' + str(j) + str(i + 4)] = [ - 1.4 * float(cos(2*((2*j + i)*pi/16 + pi/32))), - 1.4 * float(sin(2*((2*j + i)*pi/16 + pi/32))) - ] + pos_dict['1' + str(j) + str(i + 4)] = [1.4 * float(cos(2 * ((2 * j + i) * pi / 16 + pi / 32))), 1.4 * float(sin(2 * ((2 * j + i) * pi / 16 + pi / 32)))] edge_dict = { - "00": ["11"], "01": ["10"], "02": ["53"], "03": ["52"], - "11": ["20"], "10": ["21"], "53": ["22"], "52": ["23"], - "20": ["31"], "21": ["30"], "22": ["33"], "23": ["32"], - "31": ["40"], "30": ["41"], "33": ["43"], "32": ["42"], - "40": ["50"], "41": ["51"], "43": ["12"], "42": ["13"], - "50": ["61"], "51": ["60"], "12": ["63"], "13": ["62"], - "61": ["70"], "60": ["71"], "63": ["72"], "62": ["73"], - "70": ["01"], "71": ["00"], "72": ["03"], "73": ["02"], - - "04": ["35"], "05": ["34"], "06": ["37"], "07": ["36"], - "35": ["64"], "34": ["65"], "37": ["66"], "36": ["67"], - "64": ["55"], "65": ["54"], "66": ["17"], "67": ["16"], - "55": ["45"], "54": ["44"], "17": ["46"], "16": ["47"], - "45": ["74"], "44": ["75"], "46": ["76"], "47": ["77"], - "74": ["25"], "75": ["24"], "76": ["27"], "77": ["26"], - "25": ["14"], "24": ["15"], "27": ["56"], "26": ["57"], - "14": ["05"], "15": ["04"], "56": ["07"], "57": ["06"], - - "100": ["03", "04"], "110": ["10", "12"], - "101": ["01", "06"], "111": ["11", "13"], - "102": ["00", "07"], "112": ["14", "16"], - "103": ["02", "05"], "113": ["15", "17"], - - "120": ["22", "24"], "130": ["33", "36"], - "121": ["20", "26"], "131": ["32", "37"], - "122": ["21", "27"], "132": ["31", "34"], - "123": ["23", "25"], "133": ["30", "35"], - - "140": ["43", "45"], "150": ["50", "52"], - "141": ["40", "46"], "151": ["51", "53"], - "142": ["41", "47"], "152": ["54", "56"], - "143": ["42", "44"], "153": ["55", "57"], - - "160": ["60", "66"], "170": ["73", "76"], - "161": ["63", "65"], "171": ["72", "77"], - "162": ["62", "64"], "172": ["71", "74"], - "163": ["61", "67"], "173": ["70", "75"], - - "104": ["100", "102", "105"], "114": ["110", "111", "115"], - "105": ["101", "103", "104"], "115": ["112", "113", "114"], - - "124": ["120", "121", "125"], "134": ["130", "131", "135"], - "125": ["122", "123", "124"], "135": ["132", "133", "134"], - - "144": ["140", "141", "145"], "154": ["150", "151", "155"], - "145": ["142", "143", "144"], "155": ["152", "153", "154"], - - "164": ["160", "161", "165"], "174": ["170", "171", "175"], - "165": ["162", "163", "164"], "175": ["172", "173", "174"] + "00": ["11"], + "01": ["10"], + "02": ["53"], + "03": ["52"], + "11": ["20"], + "10": ["21"], + "53": ["22"], + "52": ["23"], + "20": ["31"], + "21": ["30"], + "22": ["33"], + "23": ["32"], + "31": ["40"], + "30": ["41"], + "33": ["43"], + "32": ["42"], + "40": ["50"], + "41": ["51"], + "43": ["12"], + "42": ["13"], + "50": ["61"], + "51": ["60"], + "12": ["63"], + "13": ["62"], + "61": ["70"], + "60": ["71"], + "63": ["72"], + "62": ["73"], + "70": ["01"], + "71": ["00"], + "72": ["03"], + "73": ["02"], + "04": ["35"], + "05": ["34"], + "06": ["37"], + "07": ["36"], + "35": ["64"], + "34": ["65"], + "37": ["66"], + "36": ["67"], + "64": ["55"], + "65": ["54"], + "66": ["17"], + "67": ["16"], + "55": ["45"], + "54": ["44"], + "17": ["46"], + "16": ["47"], + "45": ["74"], + "44": ["75"], + "46": ["76"], + "47": ["77"], + "74": ["25"], + "75": ["24"], + "76": ["27"], + "77": ["26"], + "25": ["14"], + "24": ["15"], + "27": ["56"], + "26": ["57"], + "14": ["05"], + "15": ["04"], + "56": ["07"], + "57": ["06"], + "100": ["03", "04"], + "110": ["10", "12"], + "101": ["01", "06"], + "111": ["11", "13"], + "102": ["00", "07"], + "112": ["14", "16"], + "103": ["02", "05"], + "113": ["15", "17"], + "120": ["22", "24"], + "130": ["33", "36"], + "121": ["20", "26"], + "131": ["32", "37"], + "122": ["21", "27"], + "132": ["31", "34"], + "123": ["23", "25"], + "133": ["30", "35"], + "140": ["43", "45"], + "150": ["50", "52"], + "141": ["40", "46"], + "151": ["51", "53"], + "142": ["41", "47"], + "152": ["54", "56"], + "143": ["42", "44"], + "153": ["55", "57"], + "160": ["60", "66"], + "170": ["73", "76"], + "161": ["63", "65"], + "171": ["72", "77"], + "162": ["62", "64"], + "172": ["71", "74"], + "163": ["61", "67"], + "173": ["70", "75"], + "104": ["100", "102", "105"], + "114": ["110", "111", "115"], + "105": ["101", "103", "104"], + "115": ["112", "113", "114"], + "124": ["120", "121", "125"], + "134": ["130", "131", "135"], + "125": ["122", "123", "124"], + "135": ["132", "133", "134"], + "144": ["140", "141", "145"], + "154": ["150", "151", "155"], + "145": ["142", "143", "144"], + "155": ["152", "153", "154"], + "164": ["160", "161", "165"], + "174": ["170", "171", "175"], + "165": ["162", "163", "164"], + "175": ["172", "173", "174"], } - return Graph(edge_dict, pos=pos_dict, name="Balaban 11-cage", - immutable=immutable) + return Graph(edge_dict, pos=pos_dict, name="Balaban 11-cage", immutable=immutable) if embedding == 2 or embedding == 3: - L = [44, 26, -47, -15, 35, -39, 11, -27, 38, -37, 43, 14, 28, 51, - -29, -16, 41, -11, -26, 15, 22, -51, -35, 36, 52, -14, -33, - -26, -46, 52, 26, 16, 43, 33, -15, 17, -53, 23, -42, -35, -28, - 30, -22, 45, -44, 16, -38, -16, 50, -55, 20, 28, -17, -43, - 47, 34, -26, -41, 11, -36, -23, -16, 41, 17, -51, 26, -33, - 47, 17, -11, -20, -30, 21, 29, 36, -43, -52, 10, 39, -28, -17, - -52, 51, 26, 37, -17, 10, -10, -45, -34, 17, -26, 27, -21, - 46, 53, -10, 29, -50, 35, 15, -47, -29, -41, 26, 33, 55, -17, - 42, -26, -36, 16] + L = [44, 26, -47, -15, 35, -39, 11, -27, 38, -37, 43, 14, 28, 51, -29, -16, 41, -11, -26, 15, 22, -51, -35, 36, 52, -14, -33, -26, -46, 52, 26, 16, 43, 33, -15, 17, -53, 23, -42, -35, -28, 30, -22, 45, -44, 16, -38, -16, 50, -55, 20, 28, -17, -43, 47, 34, -26, -41, 11, -36, -23, -16, 41, 17, -51, 26, -33, 47, 17, -11, -20, -30, 21, 29, 36, -43, -52, 10, 39, -28, -17, -52, 51, 26, 37, -17, 10, -10, -45, -34, 17, -26, 27, -21, 46, 53, -10, 29, -50, 35, 15, -47, -29, -41, 26, 33, 55, -17, 42, -26, -36, 16] from sage.graphs.generators.families import LCFGraph + g = LCFGraph(112, L, 1, immutable=immutable, name="Balaban 11-cage") if embedding == 3: return g - v1 = [34, 2, 54, 43, 66, 20, 89, 100, 72, 76, 6, 58, 16, 78, 74, - 70, 36, 94, 27, 25, 10, 8, 45, 60, 14, 64, 80, 82, 109, 107, - 49, 98] - v2 = [88, 3, 19, 55, 67, 42, 101, 33, 77, 5, 17, 57, 69, 71, 73, - 75, 11, 61, 28, 9, 37, 26, 46, 95, 13, 63, 81, 83, 108, 106, - 48, 97] - l1 = [35, 93, 1, 24, 53, 7, 44, 59, 15, 65, 79, 21, 110, 90, 50, - 99] - l2 = [87, 4, 18, 56, 68, 41, 102, 32, 12, 62, 29, 84, 38, 105, 47, - 96] + v1 = [34, 2, 54, 43, 66, 20, 89, 100, 72, 76, 6, 58, 16, 78, 74, 70, 36, 94, 27, 25, 10, 8, 45, 60, 14, 64, 80, 82, 109, 107, 49, 98] + v2 = [88, 3, 19, 55, 67, 42, 101, 33, 77, 5, 17, 57, 69, 71, 73, 75, 11, 61, 28, 9, 37, 26, 46, 95, 13, 63, 81, 83, 108, 106, 48, 97] + l1 = [35, 93, 1, 24, 53, 7, 44, 59, 15, 65, 79, 21, 110, 90, 50, 99] + l2 = [87, 4, 18, 56, 68, 41, 102, 32, 12, 62, 29, 84, 38, 105, 47, 96] d = g.get_pos() for i, v in enumerate(v1): @@ -1121,10 +1657,10 @@ def Balaban11Cage(embedding=1, immutable=False): d[v] = (2, 16.5 - i) for i, v in enumerate([0, 111, 92, 91, 52, 51, 23, 22]): - d[v] = (-20, 14.5 - 4*i) + d[v] = (-20, 14.5 - 4 * i) for i, v in enumerate([104, 103, 86, 85, 40, 39, 31, 30]): - d[v] = (20, 14.5 - 4*i) + d[v] = (20, 14.5 - 4 * i) return g @@ -1190,12 +1726,9 @@ def BidiakisCube(immutable=False): sage: g.is_isomorphic(h) True """ - edge_dict = { - 0: [1, 6, 11], 1: [2, 5], 2: [3, 10], 3: [4, 9], 4: [5, 8], - 5: [6], 6: [7], 7: [8, 11], 8: [9], 9: [10], 10: [11]} - g = Graph(edge_dict, format='dict_of_lists', name="Bidiakis cube", - immutable=immutable) - g._circle_embedding(range(12), angle=pi/2) + edge_dict = {0: [1, 6, 11], 1: [2, 5], 2: [3, 10], 3: [4, 9], 4: [5, 8], 5: [6], 6: [7], 7: [8, 11], 8: [9], 9: [10], 10: [11]} + g = Graph(edge_dict, format='dict_of_lists', name="Bidiakis cube", immutable=immutable) + g._circle_embedding(range(12), angle=pi / 2) return g @@ -1241,43 +1774,27 @@ def BiggsSmithGraph(embedding=1, immutable=False): ... ValueError: the value of embedding must be 1 or 2 """ - L = [16, 24, -38, 17, 34, 48, -19, 41, -35, 47, -20, 34, -36, - 21, 14, 48, -16, -36, -43, 28, -17, 21, 29, -43, 46, -24, - 28, -38, -14, -50, -45, 21, 8, 27, -21, 20, -37, 39, -34, - -44, -8, 38, -21, 25, 15, -34, 18, -28, -41, 36, 8, -29, - -21, -48, -28, -20, -47, 14, -8, -15, -27, 38, 24, -48, -18, - 25, 38, 31, -25, 24, -46, -14, 28, 11, 21, 35, -39, 43, 36, - -38, 14, 50, 43, 36, -11, -36, -24, 45, 8, 19, -25, 38, 20, - -24, -14, -21, -8, 44, -31, -38, -28, 37] + L = [16, 24, -38, 17, 34, 48, -19, 41, -35, 47, -20, 34, -36, 21, 14, 48, -16, -36, -43, 28, -17, 21, 29, -43, 46, -24, 28, -38, -14, -50, -45, 21, 8, 27, -21, 20, -37, 39, -34, -44, -8, 38, -21, 25, 15, -34, 18, -28, -41, 36, 8, -29, -21, -48, -28, -20, -47, 14, -8, -15, -27, 38, 24, -48, -18, 25, 38, 31, -25, 24, -46, -14, 28, 11, 21, 35, -39, 43, 36, -38, 14, 50, 43, 36, -11, -36, -24, 45, 8, 19, -25, 38, 20, -24, -14, -21, -8, 44, -31, -38, -28, 37] from sage.graphs.generators.families import LCFGraph + g = LCFGraph(102, L, 1, immutable=immutable, name="Biggs-Smith graph") if embedding == 1: - orbs = [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0], - [17, 101, 25, 66, 20, 38, 53, 89, 48, 75, 56, 92, 45, 78, - 34, 28, 63], - [18, 36, 26, 65, 19, 37, 54, 90, 47, 76, 55, 91, 46, 77, - 35, 27, 64], - [21, 39, 52, 88, 49, 74, 57, 93, 44, 79, 33, 29, 62, 83, - 100, 24, 67], - [22, 97, 51, 96, 50, 95, 58, 94, 59, 80, 60, 81, 61, 82, - 99, 23, 98], - [30, 86, 84, 72, 70, 68, 42, 40, 31, 87, 85, 73, 71, 69, - 43, 41, 32]] + orbs = [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0], [17, 101, 25, 66, 20, 38, 53, 89, 48, 75, 56, 92, 45, 78, 34, 28, 63], [18, 36, 26, 65, 19, 37, 54, 90, 47, 76, 55, 91, 46, 77, 35, 27, 64], [21, 39, 52, 88, 49, 74, 57, 93, 44, 79, 33, 29, 62, 83, 100, 24, 67], [22, 97, 51, 96, 50, 95, 58, 94, 59, 80, 60, 81, 61, 82, 99, 23, 98], [30, 86, 84, 72, 70, 68, 42, 40, 31, 87, 85, 73, 71, 69, 43, 41, 32]] # central orbits - g._circle_embedding(orbs[1], center=(-.4, 0), radius=.2) - g._circle_embedding(orbs[3], center=(.4, 0), radius=.2, shift=4) + g._circle_embedding(orbs[1], center=(-0.4, 0), radius=0.2) + g._circle_embedding(orbs[3], center=(0.4, 0), radius=0.2, shift=4) # lower orbits - g._circle_embedding(orbs[0], center=(-.9, -.5), radius=.3, shift=2) - g._circle_embedding(orbs[2], center=(-.9, .5), radius=.3) + g._circle_embedding(orbs[0], center=(-0.9, -0.5), radius=0.3, shift=2) + g._circle_embedding(orbs[2], center=(-0.9, 0.5), radius=0.3) # upper orbits - g._circle_embedding(orbs[4], center=(.9, -.5), radius=.3, shift=4) - g._circle_embedding(orbs[5], center=(.9, .5), radius=.3, shift=-2) + g._circle_embedding(orbs[4], center=(0.9, -0.5), radius=0.3, shift=4) + g._circle_embedding(orbs[5], center=(0.9, 0.5), radius=0.3, shift=-2) elif embedding == 2: pass @@ -1329,12 +1846,11 @@ def BlanusaFirstSnarkGraph(immutable=False): True """ from itertools import chain - E1 = [(0, 5), (1, 17), (2, 14), (3, 8), (4, 17), (6, 11), (7, 17), - (9, 13), (10, 15), (12, 16)] + + E1 = [(0, 5), (1, 17), (2, 14), (3, 8), (4, 17), (6, 11), (7, 17), (9, 13), (10, 15), (12, 16)] E2 = ((i, i + 1) for i in range(16)) - E3 = ((0, 16), ) - g = Graph([range(18), chain(E1, E2, E3)], format='vertices_and_edges', - name="Blanusa First Snark Graph", immutable=immutable) + E3 = ((0, 16),) + g = Graph([range(18), chain(E1, E2, E3)], format='vertices_and_edges', name="Blanusa First Snark Graph", immutable=immutable) g._circle_embedding(list(range(17)), shift=0.25) g._pos[17] = (0, 0) @@ -1384,32 +1900,19 @@ def BlanusaSecondSnarkGraph(immutable=False): """ c0 = (-1, 0) c1 = (-1, 1) - g = Graph({c0: [(0, 0), (1, 4), c1], c1: [(0, 3), (1, 1)], - (0, 2): [(0, 5)], (0, 6): [(0, 4)], - (0, 7): [(0, 1)], (1, 7): [(1, 2)], - (1, 0): [(1, 6)], (1, 3): [(1, 5)]}, - name="Blanusa Second Snark Graph") + g = Graph({c0: [(0, 0), (1, 4), c1], c1: [(0, 3), (1, 1)], (0, 2): [(0, 5)], (0, 6): [(0, 4)], (0, 7): [(0, 1)], (1, 7): [(1, 2)], (1, 0): [(1, 6)], (1, 3): [(1, 5)]}, name="Blanusa Second Snark Graph") g.add_cycle([(0, i) for i in range(5)]) g.add_cycle([(1, i) for i in range(5)]) g.add_cycle([(0, 5), (0, 6), (0, 7), (1, 5), (1, 6), (1, 7)]) - g._circle_embedding([(0, (2 * i) % 5) for i in range(5)], - center=(-1.5, 0), - shift=.5) - g._circle_embedding([(1, (2 * i) % 5) for i in range(5)], - center=(1.5, 0)) - - g._circle_embedding([(0, i) for i in range(5, 8)] + [c0] * 4, - center=(-1.2, 0), - shift=2.5, - radius=2.2) - g._circle_embedding([(1, i) for i in range(5, 8)] + [c0] * 4, - center=(1.2, 0), - shift=-1, - radius=2.2) - - g._circle_embedding([c0, c1], shift=.5) + g._circle_embedding([(0, (2 * i) % 5) for i in range(5)], center=(-1.5, 0), shift=0.5) + g._circle_embedding([(1, (2 * i) % 5) for i in range(5)], center=(1.5, 0)) + + g._circle_embedding([(0, i) for i in range(5, 8)] + [c0] * 4, center=(-1.2, 0), shift=2.5, radius=2.2) + g._circle_embedding([(1, i) for i in range(5, 8)] + [c0] * 4, center=(1.2, 0), shift=-1, radius=2.2) + + g._circle_embedding([c0, c1], shift=0.5) if immutable: return g.relabel(inplace=False, immutable=True) g.relabel() @@ -1477,30 +1980,11 @@ def BrinkmannGraph(immutable=False): sage: g.is_isomorphic(h) True """ - edge_dict = { - 0: [2, 5, 7, 13], - 1: [3, 6, 7, 8], - 2: [4, 8, 9], - 3: [5, 9, 10], - 4: [6, 10, 11], - 5: [11, 12], - 6: [12, 13], - 7: [15, 20], - 8: [14, 16], - 9: [15, 17], - 10: [16, 18], - 11: [17, 19], - 12: [18, 20], - 13: [14, 19], - 14: [17, 18], - 15: [18, 19], - 16: [19, 20], - 17: [20]} - g = Graph(edge_dict, format='dict_of_lists', name="Brinkmann graph", - immutable=immutable) - g._circle_embedding(range(7), radius=4, angle=pi/2) - g._circle_embedding(range(7, 14), radius=2, angle=pi/2 + pi/7) - g._circle_embedding(range(14, 21), radius=1, angle=pi/2 + pi/7) + edge_dict = {0: [2, 5, 7, 13], 1: [3, 6, 7, 8], 2: [4, 8, 9], 3: [5, 9, 10], 4: [6, 10, 11], 5: [11, 12], 6: [12, 13], 7: [15, 20], 8: [14, 16], 9: [15, 17], 10: [16, 18], 11: [17, 19], 12: [18, 20], 13: [14, 19], 14: [17, 18], 15: [18, 19], 16: [19, 20], 17: [20]} + g = Graph(edge_dict, format='dict_of_lists', name="Brinkmann graph", immutable=immutable) + g._circle_embedding(range(7), radius=4, angle=pi / 2) + g._circle_embedding(range(7, 14), radius=2, angle=pi / 2 + pi / 7) + g._circle_embedding(range(14, 21), radius=1, angle=pi / 2 + pi / 7) return g @@ -1556,19 +2040,12 @@ def BrouwerHaemersGraph(immutable=False): V = VectorSpace(F, d) M = Matrix(F, identity_matrix(d)) M[1, 1] = -1 - G = Graph([[tuple(_) for _ in V], - lambda x, y: (V(x) - V(y))*(M*(V(x) - V(y))) == 0], - format='rule', loops=False, name="Brouwer-Haemers") + G = Graph([[tuple(_) for _ in V], lambda x, y: (V(x) - V(y)) * (M * (V(x) - V(y))) == 0], format='rule', loops=False, name="Brouwer-Haemers") if immutable: G = G.relabel(inplace=False, immutable=True) else: G.relabel() - ordering = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 48, 49, 50, 51, 52, 53, - 45, 46, 47, 30, 31, 32, 33, 34, 35, 27, 28, 29, 39, 40, 41, - 42, 43, 44, 36, 37, 38, 69, 70, 71, 63, 64, 65, 66, 67, 68, - 78, 79, 80, 72, 73, 74, 75, 76, 77, 60, 61, 62, 54, 55, 56, - 57, 58, 59] + ordering = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 48, 49, 50, 51, 52, 53, 45, 46, 47, 30, 31, 32, 33, 34, 35, 27, 28, 29, 39, 40, 41, 42, 43, 44, 36, 37, 38, 69, 70, 71, 63, 64, 65, 66, 67, 68, 78, 79, 80, 72, 73, 74, 75, 76, 77, 60, 61, 62, 54, 55, 56, 57, 58, 59] G._circle_embedding(ordering) return G @@ -1620,22 +2097,7 @@ def BuckyBall(immutable=False): sage: g.is_isomorphic(h) True """ - edges = [(0, 2), (0, 48), (0, 59), (1, 3), (1, 9), (1, 58), - (2, 3), (2, 36), (3, 17), (4, 6), (4, 8), (4, 12), - (5, 7), (5, 9), (5, 16), (6, 7), (6, 20), (7, 21), - (8, 9), (8, 56), (10, 11), (10, 12), (10, 20), (11, 27), - (11, 47), (12, 13), (13, 46), (13, 54), (14, 15), (14, 16), - (14, 21), (15, 25), (15, 41), (16, 17), (17, 40), (18, 19), - (18, 20), (18, 26), (19, 21), (19, 24), (22, 23), (22, 31), - (22, 34), (23, 25), (23, 38), (24, 25), (24, 30), (26, 27), - (26, 30), (27, 29), (28, 29), (28, 31), (28, 35), (29, 44), - (30, 31), (32, 34), (32, 39), (32, 50), (33, 35), (33, 45), - (33, 51), (34, 35), (36, 37), (36, 40), (37, 39), (37, 52), - (38, 39), (38, 41), (40, 41), (42, 43), (42, 46), (42, 55), - (43, 45), (43, 53), (44, 45), (44, 47), (46, 47), (48, 49), - (48, 52), (49, 53), (49, 57), (50, 51), (50, 52), (51, 53), - (54, 55), (54, 56), (55, 57), (56, 58), (57, 59), (58, 59) - ] + edges = [(0, 2), (0, 48), (0, 59), (1, 3), (1, 9), (1, 58), (2, 3), (2, 36), (3, 17), (4, 6), (4, 8), (4, 12), (5, 7), (5, 9), (5, 16), (6, 7), (6, 20), (7, 21), (8, 9), (8, 56), (10, 11), (10, 12), (10, 20), (11, 27), (11, 47), (12, 13), (13, 46), (13, 54), (14, 15), (14, 16), (14, 21), (15, 25), (15, 41), (16, 17), (17, 40), (18, 19), (18, 20), (18, 26), (19, 21), (19, 24), (22, 23), (22, 31), (22, 34), (23, 25), (23, 38), (24, 25), (24, 30), (26, 27), (26, 30), (27, 29), (28, 29), (28, 31), (28, 35), (29, 44), (30, 31), (32, 34), (32, 39), (32, 50), (33, 35), (33, 45), (33, 51), (34, 35), (36, 37), (36, 40), (37, 39), (37, 52), (38, 39), (38, 41), (40, 41), (42, 43), (42, 46), (42, 55), (43, 45), (43, 53), (44, 45), (44, 47), (46, 47), (48, 49), (48, 52), (49, 53), (49, 57), (50, 51), (50, 52), (51, 53), (54, 55), (54, 56), (55, 57), (56, 58), (57, 59), (58, 59)] pos = { 0: (1.00000000000000, 0.000000000000000), @@ -1697,11 +2159,10 @@ def BuckyBall(immutable=False): 56: (-0.331440949832714, -0.485757377537020), 57: (0.331440949832715, -0.485757377537021), 58: (-0.500000000000000, -0.866025403784438), - 59: (0.500000000000000, -0.866025403784439) + 59: (0.500000000000000, -0.866025403784439), } - return Graph([range(60), edges], format='vertices_and_edges', - pos=pos, immutable=immutable, name="Bucky Ball") + return Graph([range(60), edges], format='vertices_and_edges', pos=pos, immutable=immutable, name="Bucky Ball") def GossetGraph(immutable=False): @@ -1741,18 +2202,11 @@ def GossetGraph(immutable=False): sage: g.is_isomorphic(h) True """ - string = ('w~~~~rt{~Z\\ZxnvYZYmlfrb}|hDuhLlcmmMNf_^zzQGNYcP\\kcRZbaJjoNBx{' - '?N~o^}?A`}F_Kbbm_[QZ\\_]Cj\\oN_dm{BzB{?]WIMM@tPQRYBYRPIuAyJgQv?' - '|Bxb_M[kWIR@jTQcciDjShXCkFMgpwqBKxeKoS`TYqdTCcKtkdKwWQXrbEZ@OdU' - 'mITZ@_e[{KXn?YPABzvY?IcO`zvYg@caC\\zlf?BaGR]zb{?@wOjv`~w??N_n_~' - '~w???^_^~~{') + string = 'w~~~~rt{~Z\\ZxnvYZYmlfrb}|hDuhLlcmmMNf_^zzQGNYcP\\kcRZbaJjoNBx{' '?N~o^}?A`}F_Kbbm_[QZ\\_]Cj\\oN_dm{BzB{?]WIMM@tPQRYBYRPIuAyJgQv?' '|Bxb_M[kWIR@jTQcciDjShXCkFMgpwqBKxeKoS`TYqdTCcKtkdKwWQXrbEZ@OdU' 'mITZ@_e[{KXn?YPABzvY?IcO`zvYg@caC\\zlf?BaGR]zb{?@wOjv`~w??N_n_~' '~w???^_^~~{' G = Graph(string, name="Gosset Graph", immutable=immutable) - ordering = [0, 2, 4, 6, 43, 23, 50, 18, 28, 9, 8, 7, 44, 3, 26, 35, 16, 14, - 33, 15, 54, 30, 17, 21, 10, 13, 36, 31, 55, 53, 51, 49, 12, 32, - 5, 37, 27, 46, 47, 48, 11, 52, 29, 20, 39, 41, 22, 40, 1, 25, 38, - 34, 45, 42, 19, 24] + ordering = [0, 2, 4, 6, 43, 23, 50, 18, 28, 9, 8, 7, 44, 3, 26, 35, 16, 14, 33, 15, 54, 30, 17, 21, 10, 13, 36, 31, 55, 53, 51, 49, 12, 32, 5, 37, 27, 46, 47, 48, 11, 52, 29, 20, 39, 41, 22, 40, 1, 25, 38, 34, 45, 42, 19, 24] G._circle_embedding(ordering) @@ -1797,39 +2251,9 @@ def DoubleStarSnark(immutable=False): sage: g.is_isomorphic(h) True """ - d = {0: [1, 14, 15], - 1: [0, 2, 11], - 2: [1, 3, 7], - 3: [2, 4, 18], - 4: [3, 5, 14], - 5: [10, 4, 6], - 6: [5, 21, 7], - 7: [8, 2, 6], - 8: [9, 13, 7], - 9: [24, 8, 10], - 10: [9, 11, 5], - 11: [1, 10, 12], - 12: [11, 27, 13], - 13: [8, 12, 14], - 14: [0, 4, 13], - 15: [0, 16, 29], - 16: [15, 20, 23], - 17: [25, 18, 28], - 18: [3, 17, 19], - 19: [18, 26, 23], - 20: [16, 28, 21], - 21: [20, 6, 22], - 22: [26, 21, 29], - 23: [16, 24, 19], - 24: [25, 9, 23], - 25: [24, 17, 29], - 26: [27, 19, 22], - 27: [12, 26, 28], - 28: [17, 27, 20], - 29: [25, 22, 15]} - - g = Graph(d, format='dict_of_lists', name="Double star snark", - immutable=immutable) + d = {0: [1, 14, 15], 1: [0, 2, 11], 2: [1, 3, 7], 3: [2, 4, 18], 4: [3, 5, 14], 5: [10, 4, 6], 6: [5, 21, 7], 7: [8, 2, 6], 8: [9, 13, 7], 9: [24, 8, 10], 10: [9, 11, 5], 11: [1, 10, 12], 12: [11, 27, 13], 13: [8, 12, 14], 14: [0, 4, 13], 15: [0, 16, 29], 16: [15, 20, 23], 17: [25, 18, 28], 18: [3, 17, 19], 19: [18, 26, 23], 20: [16, 28, 21], 21: [20, 6, 22], 22: [26, 21, 29], 23: [16, 24, 19], 24: [25, 9, 23], 25: [24, 17, 29], 26: [27, 19, 22], 27: [12, 26, 28], 28: [17, 27, 20], 29: [25, 22, 15]} + + g = Graph(d, format='dict_of_lists', name="Double star snark", immutable=immutable) g._circle_embedding(list(range(15)), radius=2) g._circle_embedding(list(range(15, 30)), radius=1.4) @@ -1884,14 +2308,10 @@ def MeredithGraph(immutable=False): g.add_edge(('inner', i, j), ('inner', i, k + 4)) g.add_edge(('outer', i, j), ('outer', i, k + 4)) - g._circle_embedding(sum([[('outer', i, j) for j in range(4)] + 10 * [0] for i in range(5)], []), - radius=1, shift=2) - g._circle_embedding(sum([[('outer', i, j) for j in range(4, 7)] + 10 * [0] for i in range(5)], []), - radius=1.2, shift=2.2) - g._circle_embedding(sum([[('inner', i, j) for j in range(4)] + 7 * [0] for i in range(5)], []), - radius=.6, shift=1.24) - g._circle_embedding(sum([[('inner', i, j) for j in range(4, 7)] + 5 * [0] for i in range(5)], []), - radius=.4, shift=1.05) + g._circle_embedding(sum([[('outer', i, j) for j in range(4)] + 10 * [0] for i in range(5)], []), radius=1, shift=2) + g._circle_embedding(sum([[('outer', i, j) for j in range(4, 7)] + 10 * [0] for i in range(5)], []), radius=1.2, shift=2.2) + g._circle_embedding(sum([[('inner', i, j) for j in range(4)] + 7 * [0] for i in range(5)], []), radius=0.6, shift=1.24) + g._circle_embedding(sum([[('inner', i, j) for j in range(4, 7)] + 5 * [0] for i in range(5)], []), radius=0.4, shift=1.05) if immutable: return g.relabel(inplace=False, immutable=True) @@ -1927,26 +2347,14 @@ def KittellGraph(immutable=False): sage: g.chromatic_number() 4 """ - g = Graph({0: [1, 2, 4, 5, 6, 7], 1: [0, 2, 7, 10, 11, 13], - 2: [0, 1, 11, 4, 14], 3: [16, 12, 4, 5, 14], 4: [0, 2, 3, 5, 14], - 5: [0, 16, 3, 4, 6], 6: [0, 5, 7, 15, 16, 17, 18], - 7: [0, 1, 6, 8, 13, 18], 8: [9, 18, 19, 13, 7], - 9: [8, 10, 19, 20, 13], 10: [1, 9, 11, 13, 20, 21], - 11: [1, 2, 10, 12, 14, 15, 21], 12: [11, 16, 3, 14, 15], - 13: [8, 1, 10, 9, 7], 14: [11, 12, 2, 3, 4], - 15: [6, 11, 12, 16, 17, 21, 22], - 16: [3, 12, 5, 6, 15], 17: [18, 19, 22, 6, 15], - 18: [8, 17, 19, 6, 7], 19: [8, 9, 17, 18, 20, 22], - 20: [9, 10, 19, 21, 22], 21: [10, 11, 20, 22, 15], - 22: [17, 19, 20, 21, 15]}, format="dict_of_lists", - name="Kittell Graph", immutable=immutable) - - g._circle_embedding(list(range(3)), shift=.75) - g._circle_embedding(list(range(3, 13)), radius=.4) - g._circle_embedding(list(range(15, 22)), radius=.2, shift=-.15) + g = Graph({0: [1, 2, 4, 5, 6, 7], 1: [0, 2, 7, 10, 11, 13], 2: [0, 1, 11, 4, 14], 3: [16, 12, 4, 5, 14], 4: [0, 2, 3, 5, 14], 5: [0, 16, 3, 4, 6], 6: [0, 5, 7, 15, 16, 17, 18], 7: [0, 1, 6, 8, 13, 18], 8: [9, 18, 19, 13, 7], 9: [8, 10, 19, 20, 13], 10: [1, 9, 11, 13, 20, 21], 11: [1, 2, 10, 12, 14, 15, 21], 12: [11, 16, 3, 14, 15], 13: [8, 1, 10, 9, 7], 14: [11, 12, 2, 3, 4], 15: [6, 11, 12, 16, 17, 21, 22], 16: [3, 12, 5, 6, 15], 17: [18, 19, 22, 6, 15], 18: [8, 17, 19, 6, 7], 19: [8, 9, 17, 18, 20, 22], 20: [9, 10, 19, 21, 22], 21: [10, 11, 20, 22, 15], 22: [17, 19, 20, 21, 15]}, format="dict_of_lists", name="Kittell Graph", immutable=immutable) + + g._circle_embedding(list(range(3)), shift=0.75) + g._circle_embedding(list(range(3, 13)), radius=0.4) + g._circle_embedding(list(range(15, 22)), radius=0.2, shift=-0.15) pos = g._pos - pos[13] = (-.65, -.35) - pos[14] = (.65, -.35) + pos[13] = (-0.65, -0.35) + pos[14] = (0.65, -0.35) pos[22] = (0, 0) return g @@ -1979,6 +2387,7 @@ def CameronGraph(immutable=False): """ from sage.groups.perm_gps.permgroup_named import MathieuGroup from itertools import combinations + g = Graph(name="Cameron Graph") sets = MathieuGroup(22).orbit((1, 2, 3, 7, 10, 20), action='OnSets') for s in sets: @@ -1989,23 +2398,239 @@ def CameronGraph(immutable=False): g = g.relabel(inplace=False, immutable=True) else: g.relabel() - ordering = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 18, 19, 20, - 21, 24, 25, 26, 27, 29, 31, 34, 35, 38, 39, 96, 97, 101, 105, - 51, 117, 198, 32, 196, 201, 131, 167, 199, 197, 86, 102, 195, - 200, 186, 144, 202, 177, 44, 53, 58, 45, 48, 54, 43, 57, 50, - 46, 59, 133, 169, 104, 188, 118, 208, 157, 52, 207, 209, 132, - 204, 13, 187, 33, 203, 70, 145, 103, 168, 178, 87, 124, 123, - 125, 111, 120, 116, 119, 112, 95, 114, 115, 137, 218, 213, 108, - 76, 77, 74, 62, 64, 67, 63, 68, 69, 61, 41, 75, 73, 66, 71, 72, - 60, 22, 230, 151, 184, 138, 193, 109, 228, 174, 214, 219, 93, - 126, 143, 150, 146, 224, 181, 16, 223, 171, 90, 135, 106, 205, - 211, 121, 148, 160, 216, 222, 190, 36, 55, 185, 175, 94, 139, - 110, 215, 152, 220, 229, 194, 40, 128, 99, 141, 173, 154, 82, - 156, 164, 159, 28, 127, 158, 65, 162, 163, 153, 161, 155, 140, - 98, 47, 113, 84, 180, 30, 129, 179, 183, 165, 176, 142, 100, - 49, 134, 210, 170, 147, 91, 37, 206, 182, 191, 56, 136, 225, - 221, 149, 227, 217, 17, 107, 172, 212, 122, 226, 23, 85, 42, - 80, 92, 81, 89, 78, 83, 88, 79, 130, 192, 189, 166] + ordering = [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 14, + 15, + 18, + 19, + 20, + 21, + 24, + 25, + 26, + 27, + 29, + 31, + 34, + 35, + 38, + 39, + 96, + 97, + 101, + 105, + 51, + 117, + 198, + 32, + 196, + 201, + 131, + 167, + 199, + 197, + 86, + 102, + 195, + 200, + 186, + 144, + 202, + 177, + 44, + 53, + 58, + 45, + 48, + 54, + 43, + 57, + 50, + 46, + 59, + 133, + 169, + 104, + 188, + 118, + 208, + 157, + 52, + 207, + 209, + 132, + 204, + 13, + 187, + 33, + 203, + 70, + 145, + 103, + 168, + 178, + 87, + 124, + 123, + 125, + 111, + 120, + 116, + 119, + 112, + 95, + 114, + 115, + 137, + 218, + 213, + 108, + 76, + 77, + 74, + 62, + 64, + 67, + 63, + 68, + 69, + 61, + 41, + 75, + 73, + 66, + 71, + 72, + 60, + 22, + 230, + 151, + 184, + 138, + 193, + 109, + 228, + 174, + 214, + 219, + 93, + 126, + 143, + 150, + 146, + 224, + 181, + 16, + 223, + 171, + 90, + 135, + 106, + 205, + 211, + 121, + 148, + 160, + 216, + 222, + 190, + 36, + 55, + 185, + 175, + 94, + 139, + 110, + 215, + 152, + 220, + 229, + 194, + 40, + 128, + 99, + 141, + 173, + 154, + 82, + 156, + 164, + 159, + 28, + 127, + 158, + 65, + 162, + 163, + 153, + 161, + 155, + 140, + 98, + 47, + 113, + 84, + 180, + 30, + 129, + 179, + 183, + 165, + 176, + 142, + 100, + 49, + 134, + 210, + 170, + 147, + 91, + 37, + 206, + 182, + 191, + 56, + 136, + 225, + 221, + 149, + 227, + 217, + 17, + 107, + 172, + 212, + 122, + 226, + 23, + 85, + 42, + 80, + 92, + 81, + 89, + 78, + 83, + 88, + 79, + 130, + 192, + 189, + 166, + ] g._circle_embedding(ordering) return g @@ -2051,13 +2676,10 @@ def ChvatalGraph(immutable=False): sage: G.is_isomorphic(Graph(networkx.chvatal_graph())) # needs networkx True """ - edges = {0: [1, 4, 6, 9], 1: [2, 5, 7], 2: [3, 6, 8], 3: [4, 7, 9], - 4: [5, 8], 5: [10, 11], 6: [10, 11], 7: [8, 11], 8: [10], - 9: [10, 11]} - g = Graph(edges, format='dict_of_lists', name="Chvatal graph", - immutable=immutable) - g._circle_embedding(range(5), radius=4, angle=pi/2) - g._circle_embedding(range(5, 10), radius=2, angle=pi/2) + edges = {0: [1, 4, 6, 9], 1: [2, 5, 7], 2: [3, 6, 8], 3: [4, 7, 9], 4: [5, 8], 5: [10, 11], 6: [10, 11], 7: [8, 11], 8: [10], 9: [10, 11]} + g = Graph(edges, format='dict_of_lists', name="Chvatal graph", immutable=immutable) + g._circle_embedding(range(5), radius=4, angle=pi / 2) + g._circle_embedding(range(5, 10), radius=2, angle=pi / 2) g._circle_embedding(range(10, 12), radius=1) return g @@ -2086,6 +2708,7 @@ def ClebschGraph(immutable=False): 2 sage: g.show(figsize=[10, 10]) # long time # needs sage.plot """ + def edges(): x = 0 for i in range(8): @@ -2098,9 +2721,8 @@ def edges(): yield (x % 16, (x + 8) % 16) x += 1 - g = Graph([range(16), edges()], format="vertices_and_edges", - name="Clebsch graph", immutable=immutable) - g._circle_embedding(list(range(16)), shift=.5) + g = Graph([range(16), edges()], format="vertices_and_edges", name="Clebsch graph", immutable=immutable) + g._circle_embedding(list(range(16)), shift=0.5) return g @@ -2129,15 +2751,14 @@ def CoxeterGraph(immutable=False): sage: g.show(figsize=[10, 10]) # long time # needs sage.plot """ from itertools import chain - E1 = ((0, 24), (2, 25), (6, 27), (7, 24), (8, 25), (10, 26), (14, 27), - (15, 25), (16, 26), (18, 24), (22, 27), (23, 26)) + + E1 = ((0, 24), (2, 25), (6, 27), (7, 24), (8, 25), (10, 26), (14, 27), (15, 25), (16, 26), (18, 24), (22, 27), (23, 26)) E2 = ((i, i + 1) for i in range(23)) E3 = ((0, 23),) E4 = ((5, 11), (9, 20), (12, 1), (13, 19), (17, 4), (3, 21)) - g = Graph([range(28), chain(E1, E2, E3, E4)], format="vertices_and_edges", - name="Coxeter Graph", immutable=immutable) + g = Graph([range(28), chain(E1, E2, E3, E4)], format="vertices_and_edges", name="Coxeter Graph", immutable=immutable) g._circle_embedding(list(range(24))) - g._circle_embedding([24, 25, 26], radius=.5) + g._circle_embedding([24, 25, 26], radius=0.5) g._pos[27] = (0, 0) return g @@ -2247,9 +2868,8 @@ def CubeplexGraph(embedding='LM', immutable=False): E1 = ((i, i + 1) for i in range(11)) E2 = ((0, 11),) E3 = ((0, 3), (1, 6), (2, 8), (4, 9), (5, 11), (7, 10)) - G = Graph([range(12), chain(E1, E2, E3)], format="vertices_and_edges", - name='Cubeplex Graph', immutable=immutable) - G._circle_embedding(list(range(12)), angle=2*pi/3) + G = Graph([range(12), chain(E1, E2, E3)], format="vertices_and_edges", name='Cubeplex Graph', immutable=immutable) + G._circle_embedding(list(range(12)), angle=2 * pi / 3) elif embedding == 'NT': pos_dict = { @@ -2267,29 +2887,18 @@ def CubeplexGraph(embedding='LM', immutable=False): 11: (4, -1), } - edges = ((0, 2), (0, 4), (0, 6), (1, 3), (1, 5), (1, 6), - (2, 7), (2, 8), (3, 7), (3, 8), (4, 9), (4, 10), - (5, 9), (5, 10), (6, 11), (7, 11), (8, 9), (10, 11)) - G = Graph([range(12), edges], format="vertices_and_edges", pos=pos_dict, - name='Cubeplex Graph', immutable=immutable) + edges = ((0, 2), (0, 4), (0, 6), (1, 3), (1, 5), (1, 6), (2, 7), (2, 8), (3, 7), (3, 8), (4, 9), (4, 10), (5, 9), (5, 10), (6, 11), (7, 11), (8, 9), (10, 11)) + G = Graph([range(12), edges], format="vertices_and_edges", pos=pos_dict, name='Cubeplex Graph', immutable=immutable) elif embedding == 'LM': - pos_dict = { - 8: (0, 1), - 9: (1, 0), - 10: (-3*cos(pi/16), -3*sin(pi/16)), - 11: (3*cos(pi/16), -3*sin(pi/16)) - } + pos_dict = {8: (0, 1), 9: (1, 0), 10: (-3 * cos(pi / 16), -3 * sin(pi / 16)), 11: (3 * cos(pi / 16), -3 * sin(pi / 16))} for v in range(8): - t = pi * (v+2)/4 - pos_dict[v] = (-2*cos(t), 2*sin(t)) + t = pi * (v + 2) / 4 + pos_dict[v] = (-2 * cos(t), 2 * sin(t)) - edges = ((0, 1), (0, 7), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), - (0, 8), (1, 11), (2, 9), (3, 11), (4, 8), - (5, 10), (6, 9), (7, 10), (8, 9), (10, 11)) - G = Graph([range(12), edges], format="vertices_and_edges", pos=pos_dict, - name='Cubeplex Graph', immutable=immutable) + edges = ((0, 1), (0, 7), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (0, 8), (1, 11), (2, 9), (3, 11), (4, 8), (5, 10), (6, 9), (7, 10), (8, 9), (10, 11)) + G = Graph([range(12), edges], format="vertices_and_edges", pos=pos_dict, name='Cubeplex Graph', immutable=immutable) else: raise ValueError("parameter 'embedding' must be 'FL', 'NT' or 'LM'") @@ -2324,8 +2933,7 @@ def DejterGraph(immutable=False): from sage.rings.finite_rings.finite_field_constructor import FiniteField g = CubeGraph(7) - g.delete_vertices(["".join(map(str, x)) - for x in HammingCode(FiniteField(2), 3)]) + g.delete_vertices(["".join(map(str, x)) for x in HammingCode(FiniteField(2), 3)]) g.name("Dejter Graph") if immutable: return g.copy(immutable=True) @@ -2352,8 +2960,8 @@ def DesarguesGraph(immutable=False): sage: D.show() # long time # needs sage.plot """ from sage.graphs.generators.families import GeneralizedPetersenGraph - return GeneralizedPetersenGraph(10, 3, immutable=immutable, - name="Desargues Graph") + + return GeneralizedPetersenGraph(10, 3, immutable=immutable, name="Desargues Graph") def DurerGraph(immutable=False): @@ -2397,8 +3005,8 @@ def DurerGraph(immutable=False): True """ from sage.graphs.generators.families import GeneralizedPetersenGraph - return GeneralizedPetersenGraph(6, 2, immutable=immutable, - name="Durer graph") + + return GeneralizedPetersenGraph(6, 2, immutable=immutable, name="Durer graph") def DyckGraph(immutable=False): @@ -2467,37 +3075,47 @@ def DyckGraph(immutable=False): """ pos_dict = {} for i in range(8): - pos_dict[i] = [float(cos((2*i) * pi/8)), - float(sin((2*i) * pi/8))] - pos_dict[8 + i] = [0.75 * pos_dict[i][0], - 0.75 * pos_dict[i][1]] - pos_dict[16 + i] = [0.50 * pos_dict[i][0], - 0.50 * pos_dict[i][1]] - pos_dict[24 + i] = [0.25 * pos_dict[i][0], - 0.25 * pos_dict[i][1]] + pos_dict[i] = [float(cos((2 * i) * pi / 8)), float(sin((2 * i) * pi / 8))] + pos_dict[8 + i] = [0.75 * pos_dict[i][0], 0.75 * pos_dict[i][1]] + pos_dict[16 + i] = [0.50 * pos_dict[i][0], 0.50 * pos_dict[i][1]] + pos_dict[24 + i] = [0.25 * pos_dict[i][0], 0.25 * pos_dict[i][1]] edge_dict = { - 0O00: [0O07, 0O01, 0O10], 0O10: [0O00, 0O27, 0O21], - 0O01: [0O00, 0O02, 0O11], 0O11: [0O01, 0O20, 0O22], - 0O02: [0O01, 0O03, 0O12], 0O12: [0O02, 0O21, 0O23], - 0O03: [0O02, 0O04, 0O13], 0O13: [0O03, 0O22, 0O24], - 0O04: [0O03, 0O05, 0O14], 0O14: [0O04, 0O23, 0O25], - 0O05: [0O04, 0O06, 0O15], 0O15: [0O05, 0O24, 0O26], - 0O06: [0O05, 0O07, 0O16], 0O16: [0O06, 0O25, 0O27], - 0O07: [0O06, 0O00, 0O17], 0O17: [0O07, 0O26, 0O20], - - 0O20: [0O17, 0O11, 0O30], 0O30: [0O20, 0O35, 0O33], - 0O21: [0O10, 0O12, 0O31], 0O31: [0O21, 0O36, 0O34], - 0O22: [0O11, 0O13, 0O32], 0O32: [0O22, 0O37, 0O35], - 0O23: [0O12, 0O14, 0O33], 0O33: [0O23, 0O30, 0O36], - 0O24: [0O13, 0O15, 0O34], 0O34: [0O24, 0O31, 0O37], - 0O25: [0O14, 0O16, 0O35], 0O35: [0O25, 0O32, 0O30], - 0O26: [0O15, 0O17, 0O36], 0O36: [0O26, 0O33, 0O31], - 0O27: [0O16, 0O10, 0O37], 0O37: [0O27, 0O34, 0O32], + 0o00: [0o07, 0o01, 0o10], + 0o10: [0o00, 0o27, 0o21], + 0o01: [0o00, 0o02, 0o11], + 0o11: [0o01, 0o20, 0o22], + 0o02: [0o01, 0o03, 0o12], + 0o12: [0o02, 0o21, 0o23], + 0o03: [0o02, 0o04, 0o13], + 0o13: [0o03, 0o22, 0o24], + 0o04: [0o03, 0o05, 0o14], + 0o14: [0o04, 0o23, 0o25], + 0o05: [0o04, 0o06, 0o15], + 0o15: [0o05, 0o24, 0o26], + 0o06: [0o05, 0o07, 0o16], + 0o16: [0o06, 0o25, 0o27], + 0o07: [0o06, 0o00, 0o17], + 0o17: [0o07, 0o26, 0o20], + 0o20: [0o17, 0o11, 0o30], + 0o30: [0o20, 0o35, 0o33], + 0o21: [0o10, 0o12, 0o31], + 0o31: [0o21, 0o36, 0o34], + 0o22: [0o11, 0o13, 0o32], + 0o32: [0o22, 0o37, 0o35], + 0o23: [0o12, 0o14, 0o33], + 0o33: [0o23, 0o30, 0o36], + 0o24: [0o13, 0o15, 0o34], + 0o34: [0o24, 0o31, 0o37], + 0o25: [0o14, 0o16, 0o35], + 0o35: [0o25, 0o32, 0o30], + 0o26: [0o15, 0o17, 0o36], + 0o36: [0o26, 0o33, 0o31], + 0o27: [0o16, 0o10, 0o37], + 0o37: [0o27, 0o34, 0o32], } - return Graph(edge_dict, format="dict_of_lists", pos=pos_dict, - name="Dyck graph", immutable=immutable) + return Graph(edge_dict, format="dict_of_lists", pos=pos_dict, name="Dyck graph", immutable=immutable) def HortonGraph(immutable=False): @@ -2537,6 +3155,7 @@ def HortonGraph(immutable=False): # Each group of the 6 groups of vertices is based on the same 3-regular # graph. from sage.graphs.generators.families import LCFGraph + lcf = LCFGraph(16, [5, -5], 8) lcf.delete_edge(15, 0) lcf.delete_edge(7, 8) @@ -2559,14 +3178,12 @@ def HortonGraph(immutable=False): # Embedding for i in range(6): - g._circle_embedding([(i, j) for j in range(16)], - center=(cos(2 * i * pi / 6), sin(2 * i * pi / 6)), - radius=.3) + g._circle_embedding([(i, j) for j in range(16)], center=(cos(2 * i * pi / 6), sin(2 * i * pi / 6)), radius=0.3) for i in range(3): g.delete_vertex((2 * i + 1, 15)) - g._circle_embedding([c0, c1, c2], radius=.2, shift=-0.75) + g._circle_embedding([c0, c1, c2], radius=0.2, shift=-0.75) g.relabel() @@ -2612,19 +3229,9 @@ def EllinghamHorton54Graph(immutable=False): sage: g.show() # long time # needs sage.plot """ - edge_dict = { - 0: [1, 11, 15], 1: [2, 47], 2: [3, 13], 3: [4, 8], 4: [5, 15], - 5: [6, 10], 6: [7, 30], 7: [8, 12], 8: [9], 9: [10, 29], 10: [11], - 11: [12], 12: [13], 13: [14], 14: [48, 15], 16: [17, 21, 28], - 17: [24, 29], 18: [19, 23, 30], 19: [20, 31], 20: [32, 21], 21: [33], - 22: [23, 27, 28], 23: [29], 24: [25, 30], 25: [26, 31], 26: [32, 27], - 27: [33], 28: [31], 32: [52], 33: [53], 34: [35, 39, 46], 35: [42, 47], - 36: [48, 37, 41], 37: [49, 38], 38: [50, 39], 39: [51], - 40: [41, 45, 46], 41: [47], 42: [48, 43], 43: [49, 44], 44: [50, 45], - 45: [51], 46: [49], 50: [52], 51: [53], 52: [53]} - - g = Graph(data=edge_dict, format='dict_of_lists', - name="Ellingham-Horton 54-graph", immutable=immutable) + edge_dict = {0: [1, 11, 15], 1: [2, 47], 2: [3, 13], 3: [4, 8], 4: [5, 15], 5: [6, 10], 6: [7, 30], 7: [8, 12], 8: [9], 9: [10, 29], 10: [11], 11: [12], 12: [13], 13: [14], 14: [48, 15], 16: [17, 21, 28], 17: [24, 29], 18: [19, 23, 30], 19: [20, 31], 20: [32, 21], 21: [33], 22: [23, 27, 28], 23: [29], 24: [25, 30], 25: [26, 31], 26: [32, 27], 27: [33], 28: [31], 32: [52], 33: [53], 34: [35, 39, 46], 35: [42, 47], 36: [48, 37, 41], 37: [49, 38], 38: [50, 39], 39: [51], 40: [41, 45, 46], 41: [47], 42: [48, 43], 43: [49, 44], 44: [50, 45], 45: [51], 46: [49], 50: [52], 51: [53], 52: [53]} + + g = Graph(data=edge_dict, format='dict_of_lists', name="Ellingham-Horton 54-graph", immutable=immutable) # The set of vertices on top is 0..15 # Bottom left is 16..33 @@ -2632,25 +3239,25 @@ def EllinghamHorton54Graph(immutable=False): # The two other vertices are 52, 53 # Top - g._circle_embedding(list(range(16)), center=(0, .5), shift=.5, radius=.5) + g._circle_embedding(list(range(16)), center=(0, 0.5), shift=0.5, radius=0.5) # Bottom-left g._circle_embedding(list(range(16, 22)), center=(-1.5, -1)) - g._circle_embedding(list(range(22, 28)), center=(-1.5, -1), radius=.5) - g._circle_embedding(list(range(28, 34)), center=(-1.5, -1), radius=.7) + g._circle_embedding(list(range(22, 28)), center=(-1.5, -1), radius=0.5) + g._circle_embedding(list(range(28, 34)), center=(-1.5, -1), radius=0.7) # Bottom right g._circle_embedding(list(range(34, 40)), center=(1.5, -1)) - g._circle_embedding(list(range(40, 46)), center=(1.5, -1), radius=.5) - g._circle_embedding(list(range(46, 52)), center=(1.5, -1), radius=.7) + g._circle_embedding(list(range(40, 46)), center=(1.5, -1), radius=0.5) + g._circle_embedding(list(range(46, 52)), center=(1.5, -1), radius=0.7) d = g._pos - d[52] = (-.3, -2.5) - d[53] = (.3, -2.5) - d[31] = (-2.2, -.9) - d[28] = (-.8, -.9) - d[46] = (2.2, -.9) - d[49] = (.8, -.9) + d[52] = (-0.3, -2.5) + d[53] = (0.3, -2.5) + d[31] = (-2.2, -0.9) + d[28] = (-0.8, -0.9) + d[46] = (2.2, -0.9) + d[49] = (0.8, -0.9) return g @@ -2694,45 +3301,26 @@ def EllinghamHorton78Graph(immutable=False): sage: g.show(figsize=[10, 10]) # not tested (too long) """ - g = Graph({ - 0: [1, 5, 60], 1: [2, 12], 2: [3, 7], 3: [4, 14], 4: [5, 9], - 5: [6], 6: [7, 11], 7: [15], 8: [9, 13, 22], 9: [10], - 10: [11, 72], 11: [12], 12: [13], 13: [14], 14: [72], - 15: [16, 20], 16: [17, 27], 17: [18, 22], 18: [19, 29], - 19: [20, 24], 20: [21], 21: [22, 26], 23: [24, 28, 72], - 24: [25], 25: [26, 71], 26: [27], 27: [28], 28: [29], - 29: [69], 30: [31, 35, 52], 31: [32, 42], 32: [33, 37], - 33: [34, 43], 34: [35, 39], 35: [36], 36: [41, 63], - 37: [65, 66], 38: [39, 59, 74], 39: [40], 40: [41, 44], - 41: [42], 42: [74], 43: [44, 74], 44: [45], 45: [46, 50], - 46: [47, 57], 47: [48, 52], 48: [49, 75], 49: [50, 54], - 50: [51], 51: [52, 56], 53: [54, 58, 73], 54: [55], - 55: [56, 59], 56: [57], 57: [58], 58: [75], 59: [75], - 60: [61, 64], 61: [62, 71], 62: [63, 77], 63: [67], - 64: [65, 69], 65: [77], 66: [70, 73], 67: [68, 73], - 68: [69, 76], 70: [71, 76], 76: [77]}, format="dict_of_lists", - name="Ellingham-Horton 78-graph", immutable=immutable) + g = Graph({0: [1, 5, 60], 1: [2, 12], 2: [3, 7], 3: [4, 14], 4: [5, 9], 5: [6], 6: [7, 11], 7: [15], 8: [9, 13, 22], 9: [10], 10: [11, 72], 11: [12], 12: [13], 13: [14], 14: [72], 15: [16, 20], 16: [17, 27], 17: [18, 22], 18: [19, 29], 19: [20, 24], 20: [21], 21: [22, 26], 23: [24, 28, 72], 24: [25], 25: [26, 71], 26: [27], 27: [28], 28: [29], 29: [69], 30: [31, 35, 52], 31: [32, 42], 32: [33, 37], 33: [34, 43], 34: [35, 39], 35: [36], 36: [41, 63], 37: [65, 66], 38: [39, 59, 74], 39: [40], 40: [41, 44], 41: [42], 42: [74], 43: [44, 74], 44: [45], 45: [46, 50], 46: [47, 57], 47: [48, 52], 48: [49, 75], 49: [50, 54], 50: [51], 51: [52, 56], 53: [54, 58, 73], 54: [55], 55: [56, 59], 56: [57], 57: [58], 58: [75], 59: [75], 60: [61, 64], 61: [62, 71], 62: [63, 77], 63: [67], 64: [65, 69], 65: [77], 66: [70, 73], 67: [68, 73], 68: [69, 76], 70: [71, 76], 76: [77]}, format="dict_of_lists", name="Ellingham-Horton 78-graph", immutable=immutable) g._circle_embedding(list(range(15)), center=(-2.5, 1.5)) g._circle_embedding(list(range(15, 30)), center=(-2.5, -1.5)) - g._circle_embedding([30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 74, 43, 44], center=(2.5, 1.5)) - g._circle_embedding([45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 75, 59], center=(2.5, -1.5)) + g._circle_embedding([30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 74, 43, 44], center=(2.5, 1.5)) + g._circle_embedding([45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 75, 59], center=(2.5, -1.5)) d = g._pos - d[76] = (-.2, -.1) - d[77] = (.2, .1) - d[38] = (2.2, .1) - d[52] = (2.3, -.1) - d[15] = (-2.1, -.1) - d[72] = (-2.1, .1) + d[76] = (-0.2, -0.1) + d[77] = (0.2, 0.1) + d[38] = (2.2, 0.1) + d[52] = (2.3, -0.1) + d[15] = (-2.1, -0.1) + d[72] = (-2.1, 0.1) g._line_embedding([60, 61, 62, 63], first=(-1, 2), last=(1, 2)) - g._line_embedding([64, 65, 37], first=(-.5, 1.5), last=(1.2, 1.5)) - g._line_embedding([66, 73, 67, 68, 69], first=(1.2, -2), last=(-.8, -2)) - g._line_embedding([66, 70, 71], first=(.7, -1.5), last=(-1, -1.5)) + g._line_embedding([64, 65, 37], first=(-0.5, 1.5), last=(1.2, 1.5)) + g._line_embedding([66, 73, 67, 68, 69], first=(1.2, -2), last=(-0.8, -2)) + g._line_embedding([66, 70, 71], first=(0.7, -1.5), last=(-1, -1.5)) return g @@ -2791,23 +3379,8 @@ def ErreraGraph(immutable=False): sage: ag.is_isomorphic(DihedralGroup(10)) # needs sage.groups True """ - edge_dict = { - 0: [1, 7, 14, 15, 16], - 1: [2, 9, 14, 15], - 2: [3, 8, 9, 10, 14], - 3: [4, 9, 10, 11], - 4: [5, 10, 11, 12], - 5: [6, 11, 12, 13], - 6: [7, 8, 12, 13, 16], - 7: [13, 15, 16], - 8: [10, 12, 14, 16], - 9: [11, 13, 15], - 10: [12], - 11: [13], - 13: [15], - 14: [16]} - return Graph(edge_dict, format="dict_of_lists", - name="Errera graph", immutable=immutable) + edge_dict = {0: [1, 7, 14, 15, 16], 1: [2, 9, 14, 15], 2: [3, 8, 9, 10, 14], 3: [4, 9, 10, 11], 4: [5, 10, 11, 12], 5: [6, 11, 12, 13], 6: [7, 8, 12, 13, 16], 7: [13, 15, 16], 8: [10, 12, 14, 16], 9: [11, 13, 15], 10: [12], 11: [13], 13: [15], 14: [16]} + return Graph(edge_dict, format="dict_of_lists", name="Errera graph", immutable=immutable) def F26AGraph(immutable=False): @@ -2838,6 +3411,7 @@ def F26AGraph(immutable=False): (x - 3) * (x + 3) * (x^4 - 5*x^2 + 3)^6 """ from sage.graphs.generators.families import LCFGraph + return LCFGraph(26, [7, -7], 13, immutable=immutable, name="F26A Graph") @@ -2871,13 +3445,10 @@ def FlowerSnark(immutable=False): sage: F.show() # long time # needs sage.plot """ - d = {0: [1, 14, 15], 1: [2, 11], 2: [3, 7], 3: [2, 4, 16], 4: [5, 14], - 5: [6, 10], 6: [5, 7, 17], 8: [7, 9, 13], 9: [10, 18], 11: [10, 12], - 12: [13, 19], 13: [14], 15: [19], 16: [15, 17], 18: [17, 19]} - g = Graph(d, format='dict_of_lists', name="Flower Snark", - immutable=immutable) - g._circle_embedding(range(15), radius=2.5, angle=pi/2) - g._circle_embedding(range(15, 20), radius=1, angle=pi/2) + d = {0: [1, 14, 15], 1: [2, 11], 2: [3, 7], 3: [2, 4, 16], 4: [5, 14], 5: [6, 10], 6: [5, 7, 17], 8: [7, 9, 13], 9: [10, 18], 11: [10, 12], 12: [13, 19], 13: [14], 15: [19], 16: [15, 17], 18: [17, 19]} + g = Graph(d, format='dict_of_lists', name="Flower Snark", immutable=immutable) + g._circle_embedding(range(15), radius=2.5, angle=pi / 2) + g._circle_embedding(range(15, 20), radius=1, angle=pi / 2) return g @@ -2917,8 +3488,8 @@ def FolkmanGraph(immutable=False): True """ from sage.graphs.generators.families import LCFGraph - return LCFGraph(20, [5, -7, -7, 5], 5, immutable=immutable, - name="Folkman Graph") + + return LCFGraph(20, [5, -7, -7, 5], 5, immutable=immutable, name="Folkman Graph") def FosterGraph(immutable=False): @@ -2949,8 +3520,8 @@ def FosterGraph(immutable=False): True """ from sage.graphs.generators.families import LCFGraph - return LCFGraph(90, [17, -9, 37, -37, 9, -17], 15, - immutable=immutable, name="Foster Graph") + + return LCFGraph(90, [17, -9, 37, -37, 9, -17], 15, immutable=immutable, name="Foster Graph") def FranklinGraph(immutable=False): @@ -3001,19 +3572,8 @@ def FranklinGraph(immutable=False): sage: G.chromatic_number() 2 """ - edge_dict = { - 0: [1, 5, 6], - 1: [2, 7], - 2: [3, 8], - 3: [4, 9], - 4: [5, 10], - 5: [11], - 6: [7, 9], - 7: [10], - 8: [9, 11], - 10: [11]} - g = Graph(edge_dict, format='dict_of_lists', name="Franklin graph", - immutable=immutable) + edge_dict = {0: [1, 5, 6], 1: [2, 7], 2: [3, 8], 3: [4, 9], 4: [5, 10], 5: [11], 6: [7, 9], 7: [10], 8: [9, 11], 10: [11]} + g = Graph(edge_dict, format='dict_of_lists', name="Franklin graph", immutable=immutable) g._circle_embedding(range(6), radius=2) g._circle_embedding(range(6, 12), radius=1) return g @@ -3052,12 +3612,10 @@ def FruchtGraph(immutable=False): sage: G.is_isomorphic(Graph(networkx.frucht_graph())) # needs networkx True """ - edges = {0: [1, 6, 7], 1: [2, 7], 2: [3, 8], 3: [4, 9], 4: [5, 9], - 5: [6, 10], 6: [10], 7: [11], 8: [9, 11], 10: [11]} - g = Graph(edges, format='dict_of_lists', name="Frucht graph", - immutable=immutable) - g._circle_embedding(range(7), radius=2, angle=pi/2) - g._circle_embedding(range(7, 11), radius=1, angle=pi/2) + edges = {0: [1, 6, 7], 1: [2, 7], 2: [3, 8], 3: [4, 9], 4: [5, 9], 5: [6, 10], 6: [10], 7: [11], 8: [9, 11], 10: [11]} + g = Graph(edges, format='dict_of_lists', name="Frucht graph", immutable=immutable) + g._circle_embedding(range(7), radius=2, angle=pi / 2) + g._circle_embedding(range(7, 11), radius=1, angle=pi / 2) g._pos[11] = (0, 0) return g @@ -3107,33 +3665,11 @@ def GoldnerHararyGraph(immutable=False): sage: ag.is_isomorphic(DihedralGroup(6)) # needs sage.groups True """ - edge_dict = { - 0: [1, 3, 4], - 1: [2, 3, 4, 5, 6, 7, 10], - 2: [3, 7], - 3: [7, 8, 9, 10], - 4: [3, 5, 9, 10], - 5: [10], - 6: [7, 10], - 7: [8, 10], - 8: [10], - 9: [10]} + edge_dict = {0: [1, 3, 4], 1: [2, 3, 4, 5, 6, 7, 10], 2: [3, 7], 3: [7, 8, 9, 10], 4: [3, 5, 9, 10], 5: [10], 6: [7, 10], 7: [8, 10], 8: [10], 9: [10]} - pos = { - 0: (-2, 0), - 1: (0, 1.5), - 2: (2, 0), - 3: (0, -1.5), - 4: (-1.5, 0), - 5: (-0.5, 0.5), - 6: (0.5, 0.5), - 7: (1.5, 0), - 8: (0.5, -0.5), - 9: (-0.5, -0.5), - 10: (0, 0)} - - return Graph(edge_dict, format="dict_of_lists", pos=pos, - name="Goldner-Harary graph", immutable=immutable) + pos = {0: (-2, 0), 1: (0, 1.5), 2: (2, 0), 3: (0, -1.5), 4: (-1.5, 0), 5: (-0.5, 0.5), 6: (0.5, 0.5), 7: (1.5, 0), 8: (0.5, -0.5), 9: (-0.5, -0.5), 10: (0, 0)} + + return Graph(edge_dict, format="dict_of_lists", pos=pos, name="Goldner-Harary graph", immutable=immutable) def GolombGraph(immutable=False): @@ -3161,29 +3697,9 @@ def GolombGraph(immutable=False): sage: all(dist2(pos[u], pos[v]) == 1 for u, v in G.edge_iterator(labels=None)) # needs sage.symbolic True """ - edge_dict = { - 0: [1, 2, 3], - 1: [2, 5], - 2: [7], - 3: [4, 8, 9], - 4: [5, 9], - 5: [6, 9], - 6: [7, 9], - 7: [8, 9], - 8: [9]} - pos_dict = { - 0: [QQ('1/6'), QQ('1/6') * sqrt(11)], - 1: [QQ('1/12') * sqrt(33) - QQ('1/12'), - sqrt(QQ('1/72') * sqrt(33) + QQ('7/72'))], - 2: [- QQ('1/12') * sqrt(33) - QQ('1/12'), - sqrt(- QQ('1/72') * sqrt(33) + QQ('7/72'))], - 3: [1, 0], - 4: [QQ('1/2'), - QQ('1/2') * sqrt(3)], - 5: [- QQ('1/2'), - QQ('1/2') * sqrt(3)], - 6: [-1, 0], - 7: [- QQ('1/2'), QQ('1/2') * sqrt(3)], - 8: [QQ('1/2'), QQ('1/2') * sqrt(3)], - 9: [0, 0]} - return Graph(edge_dict, format="dict_of_lists", pos=pos_dict, - name="Golomb graph", immutable=immutable) + edge_dict = {0: [1, 2, 3], 1: [2, 5], 2: [7], 3: [4, 8, 9], 4: [5, 9], 5: [6, 9], 6: [7, 9], 7: [8, 9], 8: [9]} + pos_dict = {0: [QQ('1/6'), QQ('1/6') * sqrt(11)], 1: [QQ('1/12') * sqrt(33) - QQ('1/12'), -sqrt(QQ('1/72') * sqrt(33) + QQ('7/72'))], 2: [-QQ('1/12') * sqrt(33) - QQ('1/12'), -sqrt(-QQ('1/72') * sqrt(33) + QQ('7/72'))], 3: [1, 0], 4: [QQ('1/2'), -QQ('1/2') * sqrt(3)], 5: [-QQ('1/2'), -QQ('1/2') * sqrt(3)], 6: [-1, 0], 7: [-QQ('1/2'), QQ('1/2') * sqrt(3)], 8: [QQ('1/2'), QQ('1/2') * sqrt(3)], 9: [0, 0]} + return Graph(edge_dict, format="dict_of_lists", pos=pos_dict, name="Golomb graph", immutable=immutable) def GrayGraph(embedding=1, immutable=False): @@ -3222,13 +3738,13 @@ def GrayGraph(embedding=1, immutable=False): ValueError: the value of embedding must be 1, 2, or 3 """ from sage.graphs.generators.families import LCFGraph - g = LCFGraph(54, [-25, 7, -7, 13, -13, 25], 9, - immutable=immutable, name="Gray graph") + + g = LCFGraph(54, [-25, 7, -7, 13, -13, 25], 9, immutable=immutable, name="Gray graph") if embedding == 1: o = g.automorphism_group(orbits=True)[-1] g._circle_embedding(o[0], center=(0, 0), radius=1) - g._circle_embedding(o[1], center=(0, 0), radius=.6, shift=-.5) + g._circle_embedding(o[1], center=(0, 0), radius=0.6, shift=-0.5) elif embedding != 2: raise ValueError("the value of embedding must be 1, 2, or 3") @@ -3285,17 +3801,16 @@ def GrotzschGraph(immutable=False): True """ from itertools import chain + E1 = ((0, u) for u in range(1, 6)) E2 = ((10, 6), (10, 1), (6, 5)) E3 = ((u, u + 1) for u in range(6, 10)) E4 = ((u, u - 4) for u in range(6, 10)) E5 = ((u, u - 6) for u in range(7, 11)) - g = Graph([range(11), chain(E1, E2, E3, E4, E5)], - format='vertices_and_edges', name="Grotzsch graph", - immutable=immutable) - g._circle_embedding(range(1, 6), radius=1, angle=pi/2) - g._circle_embedding(range(6, 11), radius=2, angle=pi/2) + g = Graph([range(11), chain(E1, E2, E3, E4, E5)], format='vertices_and_edges', name="Grotzsch graph", immutable=immutable) + g._circle_embedding(range(1, 6), radius=1, angle=pi / 2) + g._circle_embedding(range(6, 11), radius=2, angle=pi / 2) g._pos[0] = (0, 0) return g @@ -3337,12 +3852,9 @@ def HeawoodGraph(immutable=False): sage: G.is_isomorphic(Graph(networkx.heawood_graph())) # needs networkx True """ - edges = {0: [1, 5, 13], 1: [2, 10], 2: [3, 7], 3: [4, 12], 4: [5, 9], - 5: [6], 6: [7, 11], 7: [8], 8: [9, 13], 9: [10], 10: [11], - 11: [12], 12: [13]} - g = Graph(edges, format='dict_of_lists', name="Heawood graph", - immutable=immutable) - g._circle_embedding(range(14), radius=1, angle=pi/2) + edges = {0: [1, 5, 13], 1: [2, 10], 2: [3, 7], 3: [4, 12], 4: [5, 9], 5: [6], 6: [7, 11], 7: [8], 8: [9, 13], 9: [10], 10: [11], 11: [12], 12: [13]} + g = Graph(edges, format='dict_of_lists', name="Heawood graph", immutable=immutable) + g._circle_embedding(range(14), radius=1, angle=pi / 2) return g @@ -3394,19 +3906,8 @@ def HerschelGraph(immutable=False): sage: ag.is_isomorphic(DihedralGroup(6)) # needs sage.groups True """ - edge_dict = { - 0: [1, 3, 4], - 1: [2, 5, 6], - 2: [3, 7], - 3: [8, 9], - 4: [5, 9], - 5: [10], - 6: [7, 10], - 7: [8], - 8: [10], - 9: [10]} - g = Graph(edge_dict, format='dict_of_lists', name="Herschel graph", - immutable=immutable) + edge_dict = {0: [1, 3, 4], 1: [2, 5, 6], 2: [3, 7], 3: [8, 9], 4: [5, 9], 5: [10], 6: [7, 10], 7: [8], 8: [10], 9: [10]} + g = Graph(edge_dict, format='dict_of_lists', name="Herschel graph", immutable=immutable) g._circle_embedding(range(4), radius=2) g._circle_embedding(range(4, 10), radius=1) g._pos[10] = (0, 0) @@ -3434,6 +3935,7 @@ def GritsenkoGraph(immutable=False): """ from sage.groups.perm_gps.permgroup import PermutationGroup from functools import reduce + p = '(0)(1,17,2,18)(3,6,4,5)(7,31,8,32)(9,25,10,26)(11,14,12,13)' p += '(15,24,16,23)(19,22,20,21)(27,29,28,30)(33,35,34,36)(37,61,38,62)' p += '(39,55,40,56)(41,43,42,44)(45,53,46,54)(47,63,48,64)(49,52,50,51)' @@ -3443,16 +3945,9 @@ def GritsenkoGraph(immutable=False): q += '(33,37,52,63,41,46,60,55,34,38,51,64,42,45,59,56)' q += '(35,39,58,53,44,47,49,62,36,40,57,54,43,48,50,61)' a = PermutationGroup([p, q]) - edges = [(0, 1), (1, 2), (1, 6), (1, 7), (1, 9), (1, 11), (1, 14), (1, 21), - (1, 24), (1, 36), (1, 38), (1, 40), (1, 42), (1, 44), (1, 47), - (1, 48), (1, 50), (1, 52), (1, 54), (1, 55), (1, 56), (1, 58), - (1, 62), (1, 63), (1, 64), (33, 35), (33, 38), (33, 46), (33, 47), - (33, 49), (33, 51), (33, 57), (33, 61)] + edges = [(0, 1), (1, 2), (1, 6), (1, 7), (1, 9), (1, 11), (1, 14), (1, 21), (1, 24), (1, 36), (1, 38), (1, 40), (1, 42), (1, 44), (1, 47), (1, 48), (1, 50), (1, 52), (1, 54), (1, 55), (1, 56), (1, 58), (1, 62), (1, 63), (1, 64), (33, 35), (33, 38), (33, 46), (33, 47), (33, 49), (33, 51), (33, 57), (33, 61)] # use the union of the orbits of a on the edges - return Graph(reduce(lambda x, y: x + y, - (a.orbit(o, action='OnSets') for o in edges)), - format='list_of_edges', immutable=immutable, - name="Gritsenko strongly regular graph") + return Graph(reduce(lambda x, y: x + y, (a.orbit(o, action='OnSets') for o in edges)), format='list_of_edges', immutable=immutable, name="Gritsenko strongly regular graph") def HigmanSimsGraph(relabel=True, immutable=False): @@ -3541,8 +4036,7 @@ def HigmanSimsGraph(relabel=True, immutable=False): # Four groups of either five pentagons, or five pentagrams 4 x 5 x 5 = 100 # vertices # First digit is "group", second is "penta{gon|gram}", third is "vertex" - vlist = ['%d%d%d' % (g, p, v) - for g in range(4) for p in range(5) for v in range(5)] + vlist = ['%d%d%d' % (g, p, v) for g in range(4) for p in range(5) for v in range(5)] HS.add_vertices(vlist) # Edges: Within groups 0 and 2, joined as pentagons @@ -3573,7 +4067,7 @@ def HigmanSimsGraph(relabel=True, immutable=False): for A in range(5): for a in range(5): for b in range(5): - B = (2*A*A + 3*a*A - a*a + b) % 5 + B = (2 * A * A + 3 * a * A - a * a + b) % 5 HS.add_edge(('2%d%d' % (A, B), '3%d%d' % (a, b))) # Edges: group 3 to group 0 @@ -3587,22 +4081,22 @@ def HigmanSimsGraph(relabel=True, immutable=False): for x in range(5): for A in range(5): for B in range(5): - y = (3*x*x + A*x + B + 1) % 5 + y = (3 * x * x + A * x + B + 1) % 5 HS.add_edge(('0%d%d' % (x, y), '2%d%d' % (A, B))) - y = (3*x*x + A*x + B - 1) % 5 + y = (3 * x * x + A * x + B - 1) % 5 HS.add_edge(('0%d%d' % (x, y), '2%d%d' % (A, B))) # Edges: group 1 to group 3 for m in range(5): for a in range(5): for b in range(5): - c = (m*(m - a) + b + 2) % 5 + c = (m * (m - a) + b + 2) % 5 HS.add_edge(('1%d%d' % (m, c), '3%d%d' % (a, b))) - c = (m*(m - a) + b - 2) % 5 + c = (m * (m - a) + b - 2) % 5 HS.add_edge(('1%d%d' % (m, c), '3%d%d' % (a, b))) # Layout vertices in a circle, in the order given in vlist - HS._circle_embedding(vlist, radius=10, angle=pi/2) + HS._circle_embedding(vlist, radius=10, angle=pi / 2) if immutable: return HS.relabel(inplace=False, immutable=True) if relabel else HS.copy(immutable=True) if relabel: @@ -3655,25 +4149,16 @@ def HoffmanSingletonGraph(immutable=False): sage: HS.layout()[1] # random (-0.904..., 0.425...) """ - H = Graph({ - 'q00': ['q01'], 'q01': ['q02'], 'q02': ['q03'], 'q03': ['q04'], 'q04': ['q00'], - 'q10': ['q11'], 'q11': ['q12'], 'q12': ['q13'], 'q13': ['q14'], 'q14': ['q10'], - 'q20': ['q21'], 'q21': ['q22'], 'q22': ['q23'], 'q23': ['q24'], 'q24': ['q20'], - 'q30': ['q31'], 'q31': ['q32'], 'q32': ['q33'], 'q33': ['q34'], 'q34': ['q30'], - 'q40': ['q41'], 'q41': ['q42'], 'q42': ['q43'], 'q43': ['q44'], 'q44': ['q40'], - 'p00': ['p02'], 'p02': ['p04'], 'p04': ['p01'], 'p01': ['p03'], 'p03': ['p00'], - 'p10': ['p12'], 'p12': ['p14'], 'p14': ['p11'], 'p11': ['p13'], 'p13': ['p10'], - 'p20': ['p22'], 'p22': ['p24'], 'p24': ['p21'], 'p21': ['p23'], 'p23': ['p20'], - 'p30': ['p32'], 'p32': ['p34'], 'p34': ['p31'], 'p31': ['p33'], 'p33': ['p30'], - 'p40': ['p42'], 'p42': ['p44'], 'p44': ['p41'], 'p41': ['p43'], 'p43': ['p40']}) + H = Graph({'q00': ['q01'], 'q01': ['q02'], 'q02': ['q03'], 'q03': ['q04'], 'q04': ['q00'], 'q10': ['q11'], 'q11': ['q12'], 'q12': ['q13'], 'q13': ['q14'], 'q14': ['q10'], 'q20': ['q21'], 'q21': ['q22'], 'q22': ['q23'], 'q23': ['q24'], 'q24': ['q20'], 'q30': ['q31'], 'q31': ['q32'], 'q32': ['q33'], 'q33': ['q34'], 'q34': ['q30'], 'q40': ['q41'], 'q41': ['q42'], 'q42': ['q43'], 'q43': ['q44'], 'q44': ['q40'], 'p00': ['p02'], 'p02': ['p04'], 'p04': ['p01'], 'p01': ['p03'], 'p03': ['p00'], 'p10': ['p12'], 'p12': ['p14'], 'p14': ['p11'], 'p11': ['p13'], 'p13': ['p10'], 'p20': ['p22'], 'p22': ['p24'], 'p24': ['p21'], 'p21': ['p23'], 'p23': ['p20'], 'p30': ['p32'], 'p32': ['p34'], 'p34': ['p31'], 'p31': ['p33'], 'p33': ['p30'], 'p40': ['p42'], 'p42': ['p44'], 'p44': ['p41'], 'p41': ['p43'], 'p43': ['p40']}) for j in range(5): for i in range(5): for k in range(5): - con = (i + j*k) % 5 + con = (i + j * k) % 5 H.add_edge(('q%d%d' % (k, con), 'p%d%d' % (j, i))) H.name('Hoffman-Singleton graph') from sage.combinat.permutation import Permutations from sage.misc.prandom import randint + P = Permutations([1, 2, 3, 4]) qpp = [0] + list(P[randint(0, 23)]) ppp = [0] + list(P[randint(0, 23)]) @@ -3703,7 +4188,7 @@ def pcycle(i, s): H, mymap = H.relabel(inplace=False, immutable=True, return_map=True) else: mymap = H.relabel(range(50), return_map=True) - H._circle_embedding([mymap[d] for d in D], angle=pi/2) + H._circle_embedding([mymap[d] for d in D], angle=pi / 2) return H @@ -3732,25 +4217,11 @@ def HoffmanGraph(immutable=False): sage: g.automorphism_group().cardinality() # needs sage.groups 48 """ - g = Graph({ - 0: [1, 7, 8, 13], - 1: [2, 9, 14], - 2: [3, 8, 10], - 3: [4, 9, 15], - 4: [5, 10, 11], - 5: [6, 12, 14], - 6: [7, 11, 13], - 7: [12, 15], - 8: [12, 14], - 9: [11, 13], - 10: [12, 15], - 11: [14], - 13: [15]}, - name="Hoffman Graph", immutable=immutable) + g = Graph({0: [1, 7, 8, 13], 1: [2, 9, 14], 2: [3, 8, 10], 3: [4, 9, 15], 4: [5, 10, 11], 5: [6, 12, 14], 6: [7, 11, 13], 7: [12, 15], 8: [12, 14], 9: [11, 13], 10: [12, 15], 11: [14], 13: [15]}, name="Hoffman Graph", immutable=immutable) g._circle_embedding(list(range(8))) - g._circle_embedding(list(range(8, 14)), radius=.7, shift=.5) - g._circle_embedding([14, 15], radius=.1) + g._circle_embedding(list(range(8, 14)), radius=0.7, shift=0.5) + g._circle_embedding([14, 15], radius=0.1) return g @@ -3786,6 +4257,7 @@ def HoltGraph(immutable=False): sage: g.automorphism_group().cardinality() # needs sage.groups 54 """ + def edges(): for x in range(9): for y in range(3): @@ -3794,12 +4266,9 @@ def edges(): yield ((x, y), ((7 * x + 7) % 9, (y + 1) % 3)) yield ((x, y), ((7 * x - 7) % 9, (y + 1) % 3)) - g = Graph(edges(), format="list_of_edges", loops=False, - name="Holt graph", immutable=immutable) + g = Graph(edges(), format="list_of_edges", loops=False, name="Holt graph", immutable=immutable) for j in range(0, 6, 2): - g._line_embedding([(x, j / 2) for x in range(9)], - first=(cos(2 * j * pi / 6), sin(2 * j * pi / 6)), - last=(cos(2 * (j + 1) * pi / 6), sin(2 * (j + 1) * pi / 6))) + g._line_embedding([(x, j / 2) for x in range(9)], first=(cos(2 * j * pi / 6), sin(2 * j * pi / 6)), last=(cos(2 * (j + 1) * pi / 6), sin(2 * (j + 1) * pi / 6))) return g @@ -3847,12 +4316,9 @@ def KrackhardtKiteGraph(immutable=False): sage: G.is_isomorphic(Graph(networkx.krackhardt_kite_graph())) # needs networkx True """ - edges = {0: [1, 2, 3, 5], 1: [3, 4, 6], 2: [3, 5], 3: [4, 5, 6], - 4: [6], 5: [6, 7], 6: [7], 7: [8], 8: [9]} - pos_dict = {0: (-1, 4), 1: (1, 4), 2: (-2, 3), 3: (0, 3), 4: (2, 3), - 5: (-1, 2), 6: (1, 2), 7: (0, 1), 8: (0, 0), 9: (0, -1)} - return Graph(edges, format="dict_of_lists", pos=pos_dict, - name="Krackhardt Kite Graph", immutable=immutable) + edges = {0: [1, 2, 3, 5], 1: [3, 4, 6], 2: [3, 5], 3: [4, 5, 6], 4: [6], 5: [6, 7], 6: [7], 7: [8], 8: [9]} + pos_dict = {0: (-1, 4), 1: (1, 4), 2: (-2, 3), 3: (0, 3), 4: (2, 3), 5: (-1, 2), 6: (1, 2), 7: (0, 1), 8: (0, 0), 9: (0, -1)} + return Graph(edges, format="dict_of_lists", pos=pos_dict, name="Krackhardt Kite Graph", immutable=immutable) def Klein3RegularGraph(immutable=False): @@ -3882,14 +4348,8 @@ def Klein3RegularGraph(immutable=False): sage: g.chromatic_number() 3 """ - g3 = Graph(':w`_GKWDBap`CMWFCpWsQUNdBwwuXPHrg`U`RIqypehVLqgHupYcFJyAv^Prk]' - 'EcarHwIVHAKh|\\tLVUxT]`ZDTJ{Af[o_AuKs{r_?ef', - loops=False, multiedges=False, immutable=immutable, - name="Klein 3-regular Graph") - g3._circle_embedding([0, 2, 3, 4, 6, 8, 14, 1, 37, 30, 34, 48, 55, 43, 40, - 45, 18, 20, 47, 42, 23, 17, 16, 10, 41, 11, 49, 25, - 51, 26, 54, 9, 22, 15, 21, 12, 24, 7, 52, 31, 32, 36, - 46, 35, 29, 50, 27, 19, 28, 5, 33, 13, 53, 39, 38, 44]) + g3 = Graph(':w`_GKWDBap`CMWFCpWsQUNdBwwuXPHrg`U`RIqypehVLqgHupYcFJyAv^Prk]' 'EcarHwIVHAKh|\\tLVUxT]`ZDTJ{Af[o_AuKs{r_?ef', loops=False, multiedges=False, immutable=immutable, name="Klein 3-regular Graph") + g3._circle_embedding([0, 2, 3, 4, 6, 8, 14, 1, 37, 30, 34, 48, 55, 43, 40, 45, 18, 20, 47, 42, 23, 17, 16, 10, 41, 11, 49, 25, 51, 26, 54, 9, 22, 15, 21, 12, 24, 7, 52, 31, 32, 36, 46, 35, 29, 50, 27, 19, 28, 5, 33, 13, 53, 39, 38, 44]) return g3 @@ -3920,11 +4380,8 @@ def Klein7RegularGraph(immutable=False): sage: g.chromatic_number() 4 """ - g7 = Graph(':W__@`AaBbC_CDbDcE`F_AG_@DEH_IgHIJbFGIKaFHILeFGHMdFKN_EKOPaCNP' - 'Q`HOQRcGLRS`BKMSTdJKLPTU', loops=False, multiedges=False, - name="Klein 7-regular Graph", immutable=immutable) - g7._circle_embedding([0, 2, 3, 1, 9, 16, 20, 21, 4, 19, 17, 7, 15, - 10, 8, 13, 11, 5, 23, 22, 14, 12, 18, 6]) + g7 = Graph(':W__@`AaBbC_CDbDcE`F_AG_@DEH_IgHIJbFGIKaFHILeFGHMdFKN_EKOPaCNP' 'Q`HOQRcGLRS`BKMSTdJKLPTU', loops=False, multiedges=False, name="Klein 7-regular Graph", immutable=immutable) + g7._circle_embedding([0, 2, 3, 1, 9, 16, 20, 21, 4, 19, 17, 7, 15, 10, 8, 13, 11, 5, 23, 22, 14, 12, 18, 6]) return g7 @@ -4000,12 +4457,10 @@ def LjubljanaGraph(embedding=1, immutable=False): ... ValueError: the value of embedding must be 1 or 2 """ - L = [47, -23, -31, 39, 25, -21, -31, -41, 25, 15, 29, -41, -19, 15, - -49, 33, 39, -35, -21, 17, -33, 49, 41, 31, -15, -29, 41, 31, - -15, -25, 21, 31, -51, -25, 23, 9, -17, 51, 35, -29, 21, -51, - -39, 33, -9, -51, 51, -47, -33, 19, 51, -21, 29, 21, -31, -39] + L = [47, -23, -31, 39, 25, -21, -31, -41, 25, 15, 29, -41, -19, 15, -49, 33, 39, -35, -21, 17, -33, 49, 41, 31, -15, -29, 41, 31, -15, -25, 21, 31, -51, -25, 23, 9, -17, 51, 35, -29, 21, -51, -39, 33, -9, -51, 51, -47, -33, 19, 51, -21, 29, 21, -31, -39] from sage.graphs.generators.families import LCFGraph + g = LCFGraph(112, L, 2, immutable=immutable, name="Ljubljana graph") if embedding == 1: @@ -4013,28 +4468,12 @@ def LjubljanaGraph(embedding=1, immutable=False): # Correspondence between the vertices of the Heawood Graph and 8-sets of # the Ljubljana Graph. - d = { - 0: [1, 21, 39, 57, 51, 77, 95, 107], - 1: [2, 22, 38, 58, 50, 78, 94, 106], - 2: [3, 23, 37, 59, 49, 79, 93, 105], - 3: [4, 24, 36, 60, 48, 80, 92, 104], - 4: [5, 25, 35, 61, 15, 81, 91, 71], - 9: [6, 26, 44, 62, 16, 82, 100, 72], - 10: [7, 27, 45, 63, 17, 83, 101, 73], - 11: [8, 28, 46, 64, 18, 84, 102, 74], - 12: [9, 29, 47, 65, 19, 85, 103, 75], - 13: [10, 30, 0, 66, 20, 86, 56, 76], - 8: [11, 31, 111, 67, 99, 87, 55, 43], - 7: [12, 32, 110, 68, 98, 88, 54, 42], - 6: [13, 33, 109, 69, 97, 89, 53, 41], - 5: [14, 34, 108, 70, 96, 90, 52, 40] - } + d = {0: [1, 21, 39, 57, 51, 77, 95, 107], 1: [2, 22, 38, 58, 50, 78, 94, 106], 2: [3, 23, 37, 59, 49, 79, 93, 105], 3: [4, 24, 36, 60, 48, 80, 92, 104], 4: [5, 25, 35, 61, 15, 81, 91, 71], 9: [6, 26, 44, 62, 16, 82, 100, 72], 10: [7, 27, 45, 63, 17, 83, 101, 73], 11: [8, 28, 46, 64, 18, 84, 102, 74], 12: [9, 29, 47, 65, 19, 85, 103, 75], 13: [10, 30, 0, 66, 20, 86, 56, 76], 8: [11, 31, 111, 67, 99, 87, 55, 43], 7: [12, 32, 110, 68, 98, 88, 54, 42], 6: [13, 33, 109, 69, 97, 89, 53, 41], 5: [14, 34, 108, 70, 96, 90, 52, 40]} # The vertices of each 8-set are plotted on a circle, and the # circles are slowly shifted to obtain a symmetric drawing. for i, (u, vertices) in enumerate(d.items()): - g._circle_embedding(vertices, center=dh[u], radius=.1, - shift=8.*i/14) + g._circle_embedding(vertices, center=dh[u], radius=0.1, shift=8.0 * i / 14) elif embedding != 2: raise ValueError("the value of embedding must be 1 or 2") @@ -4073,10 +4512,9 @@ def LivingstoneGraph(immutable=False): """ from sage.groups.perm_gps.permgroup_named import JankoGroup from sage.graphs.graph import Graph + G = JankoGroup(1) - return Graph(map(tuple, G.orbit((1, 24), action='OnSets')), - format="list_of_edges", immutable=immutable, - name="Livingstone Graph") + return Graph(map(tuple, G.orbit((1, 24), action='OnSets')), format="list_of_edges", immutable=immutable, name="Livingstone Graph") def M22Graph(immutable=False): @@ -4105,17 +4543,14 @@ def M22Graph(immutable=False): (77, 16, 0, 4) """ from sage.groups.perm_gps.permgroup_named import MathieuGroup + sets = [tuple(_) for _ in MathieuGroup(22).orbit((1, 2, 3, 7, 10, 20), action='OnSets')] g = Graph([sets, lambda x, y: not any(xx in y for xx in x)], name="M22 Graph") if immutable: g = g.relabel(inplace=False, immutable=True) else: g.relabel() - ordering = [0, 1, 3, 4, 5, 6, 7, 10, 12, 19, 20, 31, 2, 24, 35, 34, 22, 32, - 36, 23, 27, 25, 40, 26, 16, 71, 61, 63, 50, 68, 39, 52, 48, 44, - 69, 28, 9, 64, 60, 17, 38, 49, 45, 65, 14, 70, 72, 21, 43, 56, - 33, 73, 58, 55, 41, 29, 66, 54, 76, 46, 67, 11, 51, 47, 62, 53, - 15, 8, 18, 13, 59, 37, 30, 57, 75, 74, 42] + ordering = [0, 1, 3, 4, 5, 6, 7, 10, 12, 19, 20, 31, 2, 24, 35, 34, 22, 32, 36, 23, 27, 25, 40, 26, 16, 71, 61, 63, 50, 68, 39, 52, 48, 44, 69, 28, 9, 64, 60, 17, 38, 49, 45, 65, 14, 70, 72, 21, 43, 56, 33, 73, 58, 55, 41, 29, 66, 54, 76, 46, 67, 11, 51, 47, 62, 53, 15, 8, 18, 13, 59, 37, 30, 57, 75, 74, 42] g._circle_embedding(ordering) @@ -4166,10 +4601,9 @@ def MarkstroemGraph(immutable=False): g.add_cycle([21, 22, 23]) g.add_edges([(19, 22), (18, 21), (20, 23)]) - g._circle_embedding(sum([[9 + 3*i + j for j in range(3)] + [0]*2 for i in range(3)], []), - radius=.6, shift=.7) - g._circle_embedding([18, 19, 20], radius=.35, shift=.25) - g._circle_embedding([21, 22, 23], radius=.15, shift=.25) + g._circle_embedding(sum([[9 + 3 * i + j for j in range(3)] + [0] * 2 for i in range(3)], []), radius=0.6, shift=0.7) + g._circle_embedding([18, 19, 20], radius=0.35, shift=0.25) + g._circle_embedding([21, 22, 23], radius=0.15, shift=0.25) g._circle_embedding(list(range(9))) return g.copy(immutable=True) if immutable else g @@ -4211,6 +4645,7 @@ def McGeeGraph(embedding=2, immutable=False): ValueError: the value of embedding must be 1 or 2 """ from sage.graphs.generators.families import LCFGraph + g = LCFGraph(24, [12, 7, -7], 8, immutable=immutable, name='McGee graph') if embedding == 1: @@ -4218,13 +4653,11 @@ def McGeeGraph(embedding=2, immutable=False): if embedding == 2: - o = [[7, 2, 13, 8, 19, 14, 1, 20], - [5, 4, 11, 10, 17, 16, 23, 22], - [3, 12, 9, 18, 15, 0, 21, 6]] + o = [[7, 2, 13, 8, 19, 14, 1, 20], [5, 4, 11, 10, 17, 16, 23, 22], [3, 12, 9, 18, 15, 0, 21, 6]] g._circle_embedding(o[0], radius=1.5) - g._circle_embedding(o[1], radius=3, shift=-.5) - g._circle_embedding(o[2], radius=2.25, shift=.5) + g._circle_embedding(o[1], radius=3, shift=-0.5) + g._circle_embedding(o[2], radius=2.25, shift=0.5) return g @@ -4291,8 +4724,7 @@ def McLaughlinGraph(immutable=False): g.add_edge(b, c) # Here we relabel the elements of g in an architecture-independent way - perm = {v: i for i, v in enumerate(list(range(1, 23)) + - sorted(blocks, key=sorted))} + perm = {v: i for i, v in enumerate(list(range(1, 23)) + sorted(blocks, key=sorted))} if immutable: return g.relabel(perm=perm, inplace=False, immutable=True) g.relabel(perm=perm) @@ -4328,8 +4760,8 @@ def MoebiusKantorGraph(immutable=False): sage: (graphs.MoebiusKantorGraph()).show() # long time # needs sage.plot """ from sage.graphs.generators.families import GeneralizedPetersenGraph - return GeneralizedPetersenGraph(8, 3, immutable=immutable, - name="Moebius-Kantor Graph") + + return GeneralizedPetersenGraph(8, 3, immutable=immutable, name="Moebius-Kantor Graph") def MoserSpindle(immutable=False): @@ -4381,26 +4813,9 @@ def MoserSpindle(immutable=False): sage: ag.is_isomorphic(DihedralGroup(4)) True """ - edge_dict = { - 0: [1, 4, 6], - 1: [2, 5], - 2: [3, 5], - 3: [4, 5, 6], - 4: [6]} - pos_dict = { - 0: [QQ('1/2'), 0], - 1: [- QQ('1/2'), 0], - 2: [- QQ('1/12') * sqrt(33) - QQ('1/4'), - QQ('1/2') * sqrt(QQ('1/6') * sqrt(33) + QQ('17/6'))], - 3: [0, QQ('1/2') * sqrt(11)], - 4: [QQ('1/12') * sqrt(33) + QQ('1/4'), - QQ('1/2') * sqrt(QQ('1/6') * sqrt(33) + QQ('17/6'))], - 5: [QQ('1/12') * sqrt(33) - QQ('1/4'), - QQ('1/2') * sqrt(- QQ('1/6') * sqrt(33) + QQ('17/6'))], - 6: [- QQ('1/12') * sqrt(33) + QQ('1/4'), - QQ('1/2') * sqrt(- QQ('1/6') * sqrt(33) + QQ('17/6'))]} - return Graph(edge_dict, format="dict_of_lists", pos=pos_dict, - name="Moser spindle", immutable=immutable) + edge_dict = {0: [1, 4, 6], 1: [2, 5], 2: [3, 5], 3: [4, 5, 6], 4: [6]} + pos_dict = {0: [QQ('1/2'), 0], 1: [-QQ('1/2'), 0], 2: [-QQ('1/12') * sqrt(33) - QQ('1/4'), QQ('1/2') * sqrt(QQ('1/6') * sqrt(33) + QQ('17/6'))], 3: [0, QQ('1/2') * sqrt(11)], 4: [QQ('1/12') * sqrt(33) + QQ('1/4'), QQ('1/2') * sqrt(QQ('1/6') * sqrt(33) + QQ('17/6'))], 5: [QQ('1/12') * sqrt(33) - QQ('1/4'), QQ('1/2') * sqrt(-QQ('1/6') * sqrt(33) + QQ('17/6'))], 6: [-QQ('1/12') * sqrt(33) + QQ('1/4'), QQ('1/2') * sqrt(-QQ('1/6') * sqrt(33) + QQ('17/6'))]} + return Graph(edge_dict, format="dict_of_lists", pos=pos_dict, name="Moser spindle", immutable=immutable) def MurtyGraph(immutable=False): @@ -4468,21 +4883,10 @@ def MurtyGraph(immutable=False): - Janmenjaya Panda (2024-08-03) """ - pos_dict = { - 0: (-0.5, sqrt(3)/2), - 1: (0.5, sqrt(3)/2), - 2: (-1, 0), - 3: (0, 0), - 4: (1, 0), - 5: (-0.5, -1 - sqrt(3)/2), - 6: (0, -1), - 7: (0.5, -1 - sqrt(3)/2) - } + pos_dict = {0: (-0.5, sqrt(3) / 2), 1: (0.5, sqrt(3) / 2), 2: (-1, 0), 3: (0, 0), 4: (1, 0), 5: (-0.5, -1 - sqrt(3) / 2), 6: (0, -1), 7: (0.5, -1 - sqrt(3) / 2)} - edges = ((0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), - (2, 5), (3, 6), (4, 7), (5, 6), (5, 7), (6, 7)) - return Graph([range(8), edges], format="vertices_and_edges", pos=pos_dict, - name="Murty Graph", immutable=immutable) + edges = ((0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 5), (3, 6), (4, 7), (5, 6), (5, 7), (6, 7)) + return Graph([range(8), edges], format="vertices_and_edges", pos=pos_dict, name="Murty Graph", immutable=immutable) def NauruGraph(embedding=2, immutable=False): @@ -4524,12 +4928,12 @@ def NauruGraph(embedding=2, immutable=False): """ if embedding == 1: from sage.graphs.generators.families import LCFGraph - return LCFGraph(24, [5, -9, 7, -7, 9, -5], 4, - immutable=immutable, name="Nauru Graph") + + return LCFGraph(24, [5, -9, 7, -7, 9, -5], 4, immutable=immutable, name="Nauru Graph") if embedding == 2: from sage.graphs.generators.families import GeneralizedPetersenGraph - return GeneralizedPetersenGraph(12, 5, immutable=immutable, - name="Nauru Graph") + + return GeneralizedPetersenGraph(12, 5, immutable=immutable, name="Nauru Graph") raise ValueError("the value of embedding must be 1 or 2") @@ -4553,14 +4957,11 @@ def PappusGraph(immutable=False): sage: G.is_isomorphic(L) True """ - edges = {0: [1, 5, 6], 1: [2, 7], 2: [3, 8], 3: [4, 9], 4: [5, 10], 5: [11], - 6: [13, 17], 7: [12, 14], 8: [13, 15], 9: [14, 16], 10: [15, 17], - 11: [12, 16], 12: [15], 13: [16], 14: [17]} - g = Graph(edges, format='dict_of_lists', name="Pappus Graph", - immutable=immutable) - g._circle_embedding(range(6), radius=3, angle=pi/2) - g._circle_embedding(range(6, 12), radius=2, angle=pi/2) - g._circle_embedding(range(12, 18), radius=1, angle=pi/2) + edges = {0: [1, 5, 6], 1: [2, 7], 2: [3, 8], 3: [4, 9], 4: [5, 10], 5: [11], 6: [13, 17], 7: [12, 14], 8: [13, 15], 9: [14, 16], 10: [15, 17], 11: [12, 16], 12: [15], 13: [16], 14: [17]} + g = Graph(edges, format='dict_of_lists', name="Pappus Graph", immutable=immutable) + g._circle_embedding(range(6), radius=3, angle=pi / 2) + g._circle_embedding(range(6, 12), radius=2, angle=pi / 2) + g._circle_embedding(range(12, 18), radius=1, angle=pi / 2) return g @@ -4584,18 +4985,17 @@ def PoussinGraph(immutable=False): sage: g.is_planar() True """ - g = Graph({2: [7, 8, 3, 4], 1: [7, 6], 0: [6, 5, 4], 3: [5]}, - name="Poussin Graph") + g = Graph({2: [7, 8, 3, 4], 1: [7, 6], 0: [6, 5, 4], 3: [5]}, name="Poussin Graph") g.add_cycle(list(range(3))) g.add_cycle(list(range(3, 9))) g.add_cycle(list(range(9, 14))) g.add_path([8, 12, 7, 11, 6, 10, 5, 9, 3, 13, 8, 12]) g.add_edges([(14, i) for i in range(9, 14)]) - g._circle_embedding(list(range(3)), shift=.75) - g._circle_embedding(list(range(3, 9)), radius=.4, shift=0) - g._circle_embedding(list(range(9, 14)), radius=.2, shift=.4) - g._pos[14] = (0,0) + g._circle_embedding(list(range(3)), shift=0.75) + g._circle_embedding(list(range(3, 9)), radius=0.4, shift=0) + g._circle_embedding(list(range(9, 14)), radius=0.2, shift=0.4) + g._pos[14] = (0, 0) return g.copy(immutable=True) if immutable else g @@ -4629,8 +5029,8 @@ def PetersenGraph(immutable=False): sage: petersen_database.show() # long time # needs sage.plot """ from sage.graphs.generators.families import GeneralizedPetersenGraph - P = GeneralizedPetersenGraph(5, 2, immutable=immutable, - name="Petersen graph") + + P = GeneralizedPetersenGraph(5, 2, immutable=immutable, name="Petersen graph") P.is_projective_planar.set_cache(True) return P @@ -4665,10 +5065,7 @@ def PerkelGraph(immutable=False): g = g.relabel(inplace=False, immutable=True) else: g.relabel() - g._circle_embedding([0, 2, 3, 35, 8, 33, 45, 5, 53, 51, 18, 50, 29, 46, 30, - 48, 40, 17, 20, 27, 43, 16, 7, 14, 6, 4, 15, 41, 24, 37, - 28, 9, 55, 38, 19, 34, 39, 36, 54, 52, 44, 23, 12, 22, - 32, 10, 13, 26, 1, 21, 42, 56, 49, 31, 47, 11, 25]) + g._circle_embedding([0, 2, 3, 35, 8, 33, 45, 5, 53, 51, 18, 50, 29, 46, 30, 48, 40, 17, 20, 27, 43, 16, 7, 14, 6, 4, 15, 41, 24, 37, 28, 9, 55, 38, 19, 34, 39, 36, 54, 52, 44, 23, 12, 22, 32, 10, 13, 26, 1, 21, 42, 56, 49, 31, 47, 11, 25]) return g @@ -4705,6 +5102,7 @@ def RobertsonGraph(immutable=False): False """ from sage.graphs.generators.families import LCFGraph + lcf = [8, 4, 7, 4, 8, 5, 7, 4, 7, 8, 4, 5, 7, 8, 4, 8, 4, 8, 4] return LCFGraph(19, lcf, 1, immutable=immutable, name="Robertson Graph") @@ -4752,10 +5150,8 @@ def SchlaefliGraph(immutable=False): sage: graphs.ClebschGraph().complement().is_isomorphic(neighborhood) True """ - G = Graph('ZBXzr|}^z~TTitjLth|dmkrmsl|if}TmbJMhrJX]YfFyTbmsseztKTvyhDvw', - name="Schläfli graph", immutable=immutable) - order = [1, 8, 5, 10, 2, 6, 11, 15, 17, 13, 18, 12, 9, 24, 25, 3, 26, 7, - 16, 20, 23, 0, 21, 14, 22, 4, 19] + G = Graph('ZBXzr|}^z~TTitjLth|dmkrmsl|if}TmbJMhrJX]YfFyTbmsseztKTvyhDvw', name="Schläfli graph", immutable=immutable) + order = [1, 8, 5, 10, 2, 6, 11, 15, 17, 13, 18, 12, 9, 24, 25, 3, 26, 7, 16, 20, 23, 0, 21, 14, 22, 4, 19] G._circle_embedding(order) return G @@ -4832,32 +5228,11 @@ def ShrikhandeGraph(immutable=False): """ pos_dict = {} for i in range(8): - pos_dict[i] = [float(cos((2*i) * pi/8)), - float(sin((2*i) * pi/8))] - pos_dict[8 + i] = [0.5 * pos_dict[i][0], - 0.5 * pos_dict[i][1]] - edge_dict = { - 0O00: [0O06, 0O07, 0O01, 0O02, 0O11, 0O17], - 0O01: [0O07, 0O00, 0O02, 0O03, 0O12, 0O10], - 0O02: [0O00, 0O01, 0O03, 0O04, 0O13, 0O11], - 0O03: [0O01, 0O02, 0O04, 0O05, 0O14, 0O12], - 0O04: [0O02, 0O03, 0O05, 0O06, 0O15, 0O13], - 0O05: [0O03, 0O04, 0O06, 0O07, 0O16, 0O14], - 0O06: [0O04, 0O05, 0O07, 0O00, 0O17, 0O15], - 0O07: [0O05, 0O06, 0O00, 0O01, 0O10, 0O16], - - 0O10: [0O12, 0O13, 0O15, 0O16, 0O07, 0O01], - 0O11: [0O13, 0O14, 0O16, 0O17, 0O00, 0O02], - 0O12: [0O14, 0O15, 0O17, 0O10, 0O01, 0O03], - 0O13: [0O15, 0O16, 0O10, 0O11, 0O02, 0O04], - 0O14: [0O16, 0O17, 0O11, 0O12, 0O03, 0O05], - 0O15: [0O17, 0O10, 0O12, 0O13, 0O04, 0O06], - 0O16: [0O10, 0O11, 0O13, 0O14, 0O05, 0O07], - 0O17: [0O11, 0O12, 0O14, 0O15, 0O06, 0O00] - } + pos_dict[i] = [float(cos((2 * i) * pi / 8)), float(sin((2 * i) * pi / 8))] + pos_dict[8 + i] = [0.5 * pos_dict[i][0], 0.5 * pos_dict[i][1]] + edge_dict = {0o00: [0o06, 0o07, 0o01, 0o02, 0o11, 0o17], 0o01: [0o07, 0o00, 0o02, 0o03, 0o12, 0o10], 0o02: [0o00, 0o01, 0o03, 0o04, 0o13, 0o11], 0o03: [0o01, 0o02, 0o04, 0o05, 0o14, 0o12], 0o04: [0o02, 0o03, 0o05, 0o06, 0o15, 0o13], 0o05: [0o03, 0o04, 0o06, 0o07, 0o16, 0o14], 0o06: [0o04, 0o05, 0o07, 0o00, 0o17, 0o15], 0o07: [0o05, 0o06, 0o00, 0o01, 0o10, 0o16], 0o10: [0o12, 0o13, 0o15, 0o16, 0o07, 0o01], 0o11: [0o13, 0o14, 0o16, 0o17, 0o00, 0o02], 0o12: [0o14, 0o15, 0o17, 0o10, 0o01, 0o03], 0o13: [0o15, 0o16, 0o10, 0o11, 0o02, 0o04], 0o14: [0o16, 0o17, 0o11, 0o12, 0o03, 0o05], 0o15: [0o17, 0o10, 0o12, 0o13, 0o04, 0o06], 0o16: [0o10, 0o11, 0o13, 0o14, 0o05, 0o07], 0o17: [0o11, 0o12, 0o14, 0o15, 0o06, 0o00]} - return Graph(edge_dict, format="dict_of_lists", pos=pos_dict, - name="Shrikhande graph", immutable=immutable) + return Graph(edge_dict, format="dict_of_lists", pos=pos_dict, name="Shrikhande graph", immutable=immutable) def SylvesterGraph(immutable=False): @@ -4899,10 +5274,8 @@ def SylvesterGraph(immutable=False): g = g.relabel(inplace=False, immutable=True) else: g.relabel() - ordering = [0, 1, 2, 4, 5, 9, 16, 35, 15, 18, 20, 30, 22, 6, 33, 32, 14, - 10, 28, 29, 7, 24, 23, 26, 19, 12, 13, 21, 11, 31, 3, 27, 25, - 17, 8, 34] - g._circle_embedding(ordering, shift=.5) + ordering = [0, 1, 2, 4, 5, 9, 16, 35, 15, 18, 20, 30, 22, 6, 33, 32, 14, 10, 28, 29, 7, 24, 23, 26, 19, 12, 13, 21, 11, 31, 3, 27, 25, 17, 8, 34] + g._circle_embedding(ordering, shift=0.5) return g @@ -4947,10 +5320,7 @@ def SimsGewirtzGraph(immutable=False): g = g.relabel(inplace=False, immutable=True) else: g.relabel() - ordering = [0, 2, 3, 4, 6, 7, 8, 17, 1, 41, 49, 5, 22, 26, 11, 27, 15, 47, - 53, 52, 38, 43, 44, 18, 20, 32, 19, 42, 54, 36, 51, 30, 33, 35, - 37, 28, 34, 12, 29, 23, 55, 25, 40, 24, 9, 14, 48, 39, 45, 16, - 13, 21, 31, 50, 10, 46] + ordering = [0, 2, 3, 4, 6, 7, 8, 17, 1, 41, 49, 5, 22, 26, 11, 27, 15, 47, 53, 52, 38, 43, 44, 18, 20, 32, 19, 42, 54, 36, 51, 30, 33, 35, 37, 28, 34, 12, 29, 23, 55, 25, 40, 24, 9, 14, 48, 39, 45, 16, 13, 21, 31, 50, 10, 46] g._circle_embedding(ordering) return g @@ -4996,7 +5366,7 @@ def SousselierGraph(immutable=False): g.add_edge(6, 2) g.add_edges([(15, i) for i in range(15) if i % 3 == 1]) - g._circle_embedding(list(range(15)), shift=-.25) + g._circle_embedding(list(range(15)), shift=-0.25) g._pos[15] = (0, 0) return g.copy(immutable=True) if immutable else g @@ -5038,13 +5408,9 @@ def SzekeresSnarkGraph(immutable=False): g.add_edge((i, 0), ((i + 1) % 5, 8)) g.add_edge((i, 6), ((i + 2) % 5, 2)) - g._circle_embedding([(i, j) for j in range(9)], - radius=.3, - center=(cos(2 * (i + .25) * pi / 5), - sin(2 * (i + .25) * pi / 5)), - shift=5.45 + 1.8 * i) + g._circle_embedding([(i, j) for j in range(9)], radius=0.3, center=(cos(2 * (i + 0.25) * pi / 5), sin(2 * (i + 0.25) * pi / 5)), shift=5.45 + 1.8 * i) - g._circle_embedding(c, radius=1, shift=.25) + g._circle_embedding(c, radius=1, shift=0.25) if immutable: return g.relabel(inplace=False, immutable=True) g.relabel() @@ -5075,8 +5441,8 @@ def ThomsenGraph(immutable=False): sage: (graphs.ThomsenGraph()).show() # long time # needs sage.plot """ from sage.graphs.generators.basic import CompleteBipartiteGraph - return CompleteBipartiteGraph(3, 3, immutable=immutable, - name="Thomsen graph") + + return CompleteBipartiteGraph(3, 3, immutable=immutable, name="Thomsen graph") def TietzeGraph(immutable=False): @@ -5107,13 +5473,10 @@ def TietzeGraph(immutable=False): sage: g.automorphism_group().is_isomorphic(groups.permutation.Dihedral(6)) # needs sage.groups True """ - edges = ((0, 1), (0, 8), (0, 9), (1, 2), (1, 5), (2, 3), - (2, 7), (3, 4), (3, 10), (4, 5), (4, 8), (5, 6), - (6, 7), (6, 11), (7, 8), (9, 10), (9, 11), (10, 11)) - g = Graph([range(12), edges], format="vertices_and_edges", - name="Tietze Graph", immutable=immutable) + edges = ((0, 1), (0, 8), (0, 9), (1, 2), (1, 5), (2, 3), (2, 7), (3, 4), (3, 10), (4, 5), (4, 8), (5, 6), (6, 7), (6, 11), (7, 8), (9, 10), (9, 11), (10, 11)) + g = Graph([range(12), edges], format="vertices_and_edges", name="Tietze Graph", immutable=immutable) g._circle_embedding(list(range(9))) - g._circle_embedding([9, 10, 11], radius=.5) + g._circle_embedding([9, 10, 11], radius=0.5) return g @@ -5193,23 +5556,10 @@ def TricornGraph(immutable=False): - Janmenjaya Panda (2024-08-02) """ - pos_dict = { - 0: (0, 0), - 1: (0, 1), - 2: (1/2, 1 + sqrt(3)/2), - 3: (-1/2, 1 + sqrt(3)/2), - 4: (-sqrt(3)/2, -1/2), - 5: (-sqrt(3)/2 - 1, -1/2), - 6: (-sqrt(3)/2 - 1/2, -1/2 - sqrt(3)/2), - 7: (sqrt(3)/2, -1/2), - 8: (sqrt(3)/2 + 1/2, -1/2 - sqrt(3)/2), - 9: (sqrt(3)/2 + 1, -1/2) - } - edges = ((0, 1), (0, 4), (0, 7), (1, 2), (1, 3), (2, 3), (2, 9), (3, 5), - (4, 5), (4, 6), (5, 6), (6, 8), (7, 8), (7, 9), (8, 9)) + pos_dict = {0: (0, 0), 1: (0, 1), 2: (1 / 2, 1 + sqrt(3) / 2), 3: (-1 / 2, 1 + sqrt(3) / 2), 4: (-sqrt(3) / 2, -1 / 2), 5: (-sqrt(3) / 2 - 1, -1 / 2), 6: (-sqrt(3) / 2 - 1 / 2, -1 / 2 - sqrt(3) / 2), 7: (sqrt(3) / 2, -1 / 2), 8: (sqrt(3) / 2 + 1 / 2, -1 / 2 - sqrt(3) / 2), 9: (sqrt(3) / 2 + 1, -1 / 2)} + edges = ((0, 1), (0, 4), (0, 7), (1, 2), (1, 3), (2, 3), (2, 9), (3, 5), (4, 5), (4, 6), (5, 6), (6, 8), (7, 8), (7, 9), (8, 9)) - return Graph([range(10), edges], format="vertices_and_edges", pos=pos_dict, - name="Tricorn Graph", immutable=immutable) + return Graph([range(10), edges], format="vertices_and_edges", pos=pos_dict, name="Tricorn Graph", immutable=immutable) def TruncatedIcosidodecahedralGraph(immutable=False): @@ -5238,6 +5588,7 @@ def TruncatedIcosidodecahedralGraph(immutable=False): (120, 180) """ from sage.geometry.polyhedron.library import polytopes + # note that dropping exact=False here makes the construction take forever T = polytopes.icosidodecahedron(exact=False).truncation() G = T.graph(immutable=immutable) @@ -5266,11 +5617,10 @@ def TruncatedTetrahedralGraph(immutable=False): sage: g.is_isomorphic(polytopes.simplex(3).truncation().graph()) # needs sage.geometry.polyhedron True """ - g = Graph(':K`ESwC_EOyDl\\MCi', loops=False, multiedges=False, - name="Truncated Tetrahedron", immutable=immutable) + g = Graph(':K`ESwC_EOyDl\\MCi', loops=False, multiedges=False, name="Truncated Tetrahedron", immutable=immutable) g._circle_embedding(list(range(6)), radius=1) - g._circle_embedding(list(range(6, 9)), radius=.6, shift=.25) - g._circle_embedding(list(range(9, 12)), radius=.2, shift=.25) + g._circle_embedding(list(range(6, 9)), radius=0.6, shift=0.25) + g._circle_embedding(list(range(9, 12)), radius=0.2, shift=0.25) return g @@ -5298,10 +5648,10 @@ def Tutte12Cage(immutable=False): 6 sage: g.show() # needs sage.plot """ - L = [17, 27, -13, -59, -35, 35, -11, 13, -53, 53, -27, 21, 57, 11, - -21, -57, 59, -17] + L = [17, 27, -13, -59, -35, 35, -11, 13, -53, 53, -27, 21, 57, 11, -21, -57, 59, -17] from sage.graphs.generators.families import LCFGraph + return LCFGraph(126, L, 7, immutable=immutable, name="Tutte 12-Cage") @@ -5341,25 +5691,18 @@ def TutteCoxeterGraph(embedding=2, immutable=False): ValueError: the value of embedding must be 1 or 2 """ from sage.graphs.generators.families import LCFGraph - g = LCFGraph(30, [-13, -9, 7, -7, 9, 13], 5, - immutable=immutable, name="Tutte-Coxeter graph") + + g = LCFGraph(30, [-13, -9, 7, -7, 9, 13], 5, immutable=immutable, name="Tutte-Coxeter graph") if embedding == 1: - d = { - 0: [1, 3, 5, 7, 29], - 1: [2, 4, 6, 28, 0], - 2: [8, 18, 26, 22, 12], - 3: [9, 13, 23, 27, 17], - 4: [11, 15, 21, 25, 19], - 5: [10, 14, 24, 20, 16] - } - - g._circle_embedding(d[0], center=(-1, 1), radius=.25) - g._circle_embedding(d[1], center=(1, 1), radius=.25) - g._circle_embedding(d[2], center=(-.8, 0), radius=.25, shift=2.5) - g._circle_embedding(d[3], center=(1.2, 0), radius=.25) - g._circle_embedding(d[4], center=(-1, -1), radius=.25, shift=2) - g._circle_embedding(d[5], center=(1, -1), radius=.25) + d = {0: [1, 3, 5, 7, 29], 1: [2, 4, 6, 28, 0], 2: [8, 18, 26, 22, 12], 3: [9, 13, 23, 27, 17], 4: [11, 15, 21, 25, 19], 5: [10, 14, 24, 20, 16]} + + g._circle_embedding(d[0], center=(-1, 1), radius=0.25) + g._circle_embedding(d[1], center=(1, 1), radius=0.25) + g._circle_embedding(d[2], center=(-0.8, 0), radius=0.25, shift=2.5) + g._circle_embedding(d[3], center=(1.2, 0), radius=0.25) + g._circle_embedding(d[4], center=(-1, -1), radius=0.25, shift=2) + g._circle_embedding(d[5], center=(1, -1), radius=0.25) elif embedding != 2: raise ValueError("the value of embedding must be 1 or 2") @@ -5413,20 +5756,14 @@ def TutteGraph(immutable=False): g.add_edge((i, 4), (i, 14)) g.add_edge((i, 9), (i, 14)) - g._circle_embedding([(i, j) for i in range(3) for j in range(6)], shift=.5) - g._circle_embedding([(i, 14) for i in range(3)], radius=.3, shift=.25) + g._circle_embedding([(i, j) for i in range(3) for j in range(6)], shift=0.5) + g._circle_embedding([(i, 14) for i in range(3)], radius=0.3, shift=0.25) for i in range(3): - g._circle_embedding([(i, j) for j in range(3, 9)] + [0]*5, - shift=3.7*(i - 2) + .75, - radius=.4, - center=(.6*cos(2*(i + .25)*pi/3), .6*sin(2*(i + .25)*pi/3))) - g._circle_embedding([(i, j) for j in range(9, 14)], - shift=1.7*(i - 2) + 1, - radius=.2, - center=(.6*cos(2*(i + .25)*pi/3), .6*sin(2*(i + .25)*pi/3))) + g._circle_embedding([(i, j) for j in range(3, 9)] + [0] * 5, shift=3.7 * (i - 2) + 0.75, radius=0.4, center=(0.6 * cos(2 * (i + 0.25) * pi / 3), 0.6 * sin(2 * (i + 0.25) * pi / 3))) + g._circle_embedding([(i, j) for j in range(9, 14)], shift=1.7 * (i - 2) + 1, radius=0.2, center=(0.6 * cos(2 * (i + 0.25) * pi / 3), 0.6 * sin(2 * (i + 0.25) * pi / 3))) - g._pos[0] = (0,0) + g._pos[0] = (0, 0) return g.copy(immutable=True) if immutable else g @@ -5546,9 +5883,8 @@ def TwinplexGraph(embedding='LM', immutable=False): E1 = ((i, i + 1) for i in range(11)) E2 = ((0, 11),) E3 = ((0, 8), (1, 5), (2, 9), (3, 7), (4, 11), (6, 10)) - G = Graph([range(12), chain(E1, E2, E3)], format="vertices_and_edges", - name='Twinplex Graph', immutable=immutable) - G._circle_embedding(list(range(12)), angle=5*pi/12) + G = Graph([range(12), chain(E1, E2, E3)], format="vertices_and_edges", name='Twinplex Graph', immutable=immutable) + G._circle_embedding(list(range(12)), angle=5 * pi / 12) elif embedding == 'NT': pos_dict = { @@ -5565,54 +5901,26 @@ def TwinplexGraph(embedding='LM', immutable=False): 10: (3, 0), 11: (4, -1), } - edges = ((0, 2), (0, 4), (0, 6), (1, 3), (1, 5), (1, 6), - (2, 7), (2, 9), (3, 7), (3, 8), (4, 8), (4, 10), - (5, 9), (5, 10), (6, 11), (7, 11), (8, 9), (10, 11)) - G = Graph([range(12), edges], format="vertices_and_edges", pos=pos_dict, - name='Twinplex Graph', immutable=immutable) + edges = ((0, 2), (0, 4), (0, 6), (1, 3), (1, 5), (1, 6), (2, 7), (2, 9), (3, 7), (3, 8), (4, 8), (4, 10), (5, 9), (5, 10), (6, 11), (7, 11), (8, 9), (10, 11)) + G = Graph([range(12), edges], format="vertices_and_edges", pos=pos_dict, name='Twinplex Graph', immutable=immutable) elif embedding == 'RST': - pos_dict = { - 0: (-1, 3), - 1: (1, 3), - 2: (3, 1), - 3: (3, -1), - 4: (1, -3), - 5: (-1, -3), - 6: (-3, -1), - 7: (-3, 1), - 8: (-1, 1), - 9: (1, 1), - 10: (1, -1), - 11: (-1, -1) - } - edges = ((0, 1), (0, 4), (0, 7), (1, 2), (1, 8), (2, 3), - (2, 10), (3, 4), (3, 9), (4, 5), (5, 6), (5, 10), - (6, 7), (6, 8), (7, 11), (8, 9), (9, 11), (10, 11)) - G = Graph([range(12), edges], format="vertices_and_edges", pos=pos_dict, - name='Twinplex Graph', immutable=immutable) + pos_dict = {0: (-1, 3), 1: (1, 3), 2: (3, 1), 3: (3, -1), 4: (1, -3), 5: (-1, -3), 6: (-3, -1), 7: (-3, 1), 8: (-1, 1), 9: (1, 1), 10: (1, -1), 11: (-1, -1)} + edges = ((0, 1), (0, 4), (0, 7), (1, 2), (1, 8), (2, 3), (2, 10), (3, 4), (3, 9), (4, 5), (5, 6), (5, 10), (6, 7), (6, 8), (7, 11), (8, 9), (9, 11), (10, 11)) + G = Graph([range(12), edges], format="vertices_and_edges", pos=pos_dict, name='Twinplex Graph', immutable=immutable) elif embedding == 'LM': - pos_dict = { - 8: (0, 1), - 9: (1, 0), - 10: (-3*cos(pi/16), -3*sin(pi/16)), - 11: (3*cos(pi/16), -3*sin(pi/16)) - } + pos_dict = {8: (0, 1), 9: (1, 0), 10: (-3 * cos(pi / 16), -3 * sin(pi / 16)), 11: (3 * cos(pi / 16), -3 * sin(pi / 16))} for v in range(8): - t = pi * (v+2)/4 - pos_dict[v] = (-2*cos(t), 2*sin(t)) + t = pi * (v + 2) / 4 + pos_dict[v] = (-2 * cos(t), 2 * sin(t)) - edges = ((0, 1), (0, 7), (0, 8), (1, 2), (1, 11), (2, 3), - (2, 9), (3, 4), (3, 10), (4, 5), (4, 8), (5, 6), - (5, 11), (6, 7), (6, 9), (7, 10), (8, 9), (10, 11)) - G = Graph([range(12), edges], format="vertices_and_edges", pos=pos_dict, - name='Twinplex Graph', immutable=immutable) + edges = ((0, 1), (0, 7), (0, 8), (1, 2), (1, 11), (2, 3), (2, 9), (3, 4), (3, 10), (4, 5), (4, 8), (5, 6), (5, 11), (6, 7), (6, 9), (7, 10), (8, 9), (10, 11)) + G = Graph([range(12), edges], format="vertices_and_edges", pos=pos_dict, name='Twinplex Graph', immutable=immutable) else: - raise ValueError("parameter 'embedding' must be 'FL', 'NT'," - " 'LM' or 'RST'") + raise ValueError("parameter 'embedding' must be 'FL', 'NT'," " 'LM' or 'RST'") return G @@ -5642,6 +5950,7 @@ def WagnerGraph(immutable=False): sage: g.show() # needs sage.plot """ from sage.graphs.generators.families import LCFGraph + return LCFGraph(8, [4], 8, immutable=immutable, name="Wagner Graph") @@ -5673,10 +5982,7 @@ def WatkinsSnarkGraph(immutable=False): g.add_cycle([(i, j) for j in range(9)]) L = [(i, j) for j in range(4)] + [0, 0, (i, 4), 0, 0] L.extend((i, j) for j in range(5, 9)) - g._circle_embedding(L, - radius=.3, - center=(cos(2*(i + .25)*pi/5), sin(2*(i + .25)*pi/5)), - shift=2.7*i + 7.55) + g._circle_embedding(L, radius=0.3, center=(cos(2 * (i + 0.25) * pi / 5), sin(2 * (i + 0.25) * pi / 5)), shift=2.7 * i + 7.55) g.add_edge((i, 5), ((i + 1) % 5, 0)) g.add_edge((i, 8), ((i + 2) % 5, 3)) g.add_edge((i, 1), i) @@ -5684,7 +5990,7 @@ def WatkinsSnarkGraph(immutable=False): g.add_edge((i, 4), i) g.add_edge((i, 6), (i, 2)) - g._circle_embedding(list(range(5)), shift=.25, radius=1.1) + g._circle_embedding(list(range(5)), shift=0.25, radius=1.1) return g.copy(immutable=True) if immutable else g @@ -5725,13 +6031,10 @@ def WienerArayaGraph(immutable=False): g.add_cycle([(1, i) for i in range(12)]) g.add_cycle([(2, i) for i in range(20)]) g.add_cycle([(3, i) for i in range(6)]) - g._circle_embedding([(0, i) for i in range(4)], shift=.5) - g._circle_embedding(sum([[(1, 3 * i), (1, 3 * i + 1), 0, 0, 0, (1, 3 * i + 2), 0, 0, 0] - for i in range(4)], []), - shift=4, - radius=.65) - g._circle_embedding([(2, i) for i in range(20)], radius=.5) - g._circle_embedding([(3, i) for i in range(6)], radius=.3, shift=.5) + g._circle_embedding([(0, i) for i in range(4)], shift=0.5) + g._circle_embedding(sum([[(1, 3 * i), (1, 3 * i + 1), 0, 0, 0, (1, 3 * i + 2), 0, 0, 0] for i in range(4)], []), shift=4, radius=0.65) + g._circle_embedding([(2, i) for i in range(20)], radius=0.5) + g._circle_embedding([(3, i) for i in range(6)], radius=0.3, shift=0.5) for i in range(4): g.delete_edge((1, 3 * i), (1, 3 * i + 1)) @@ -5786,17 +6089,16 @@ def _EllipticLinesProjectivePlaneScheme(k): from sage.libs.gap.libgap import libgap from sage.matrix.constructor import matrix from itertools import product + q = 2**k g0 = libgap.GeneralOrthogonalGroup(3, q) # invariant form x0^2 + x1*x2 g = libgap.Group(libgap.List(g0.GeneratorsOfGroup(), libgap.TransposedMat)) W = libgap.FullRowSpace(libgap.GF(q), 3) l = sum(libgap.Elements(libgap.Basis(W))) gp = libgap.Action(g, libgap.Orbit(g, l, libgap.OnLines), libgap.OnLines) - orbitals = gp.Orbits(list(product(gp.Orbit(1), gp.Orbit(1))), - libgap.OnTuples) + orbitals = gp.Orbits(list(product(gp.Orbit(1), gp.Orbit(1))), libgap.OnTuples) mats = ([(int(x[0]) - 1, int(x[1]) - 1) for x in o] for o in orbitals) - return [matrix((q * (q - 1)) // 2, lambda i, j: 1 if (i, j) in x else 0) - for x in mats] + return [matrix((q * (q - 1)) // 2, lambda i, j: 1 if (i, j) in x else 0) for x in mats] def MathonStronglyRegularGraph(t, immutable=False): @@ -5829,6 +6131,7 @@ def MathonStronglyRegularGraph(t, immutable=False): (784, 297, 116, 110) """ from sage.graphs.generators.families import MathonPseudocyclicMergingGraph + ES = _EllipticLinesProjectivePlaneScheme(3) return MathonPseudocyclicMergingGraph(ES, t, immutable=immutable) @@ -5876,33 +6179,31 @@ def JankoKharaghaniGraph(v, immutable=False): D = ("--1-11", "-11-1-", "11-1--", "--11-1", "11---1", "1--11-") E = ("-1--11", "1-1--1", "-11-1-", "---111", "1-11--", "11-1--") F = ("-1-1-1", "11--1-", "--111-", "1-11--", "-11--1", "1---11") - B, C, D, E, F = (matrix([map({'1': 1, '-': -1}.get, r) for r in m]) - for m in [B, C, D, E, F]) + B, C, D, E, F = (matrix([map({'1': 1, '-': -1}.get, r) for r in m]) for m in [B, C, D, E, F]) H = [A, B, C, D, E, F] - H = [[-x for x in H[6-i:]] + H[:6-i] for i in range(6)] + H = [[-x for x in H[6 - i :]] + H[: 6 - i] for i in range(6)] H = matrix.block(H) # Definition of the BGW matrix W with the cyclotomic method # ([JK02] Lemma 1, and [GM87] Construction 1) m = 12 - t = (2 if v == 936 else 4) + t = 2 if v == 936 else 4 k = m q = m * t + 1 K = GF(q, 'alpha') a = K.primitive_element() - Ci = [[K(0)]] + [set(a**(k*j + i) for j in range(t)) for i in range(m)] + Ci = [[K(0)]] + [set(a ** (k * j + i) for j in range(t)) for i in range(m)] Kelem_to_Ci = {v: i for i, s in enumerate(Ci) for v in s} # maps v to [0,...,12] - W = ([[0] + [1]*(len(K))] + - [[1] + [Kelem_to_Ci[aj-ai] for aj in K] for ai in K]) + W = [[0] + [1] * (len(K))] + [[1] + [Kelem_to_Ci[aj - ai] for aj in K] for ai in K] # The nonzero elements of W are considered as elements of C_12, generated by # a matrix Omega of order 12 n = 18 U = matrix.circulant([int(i == 1) for i in range(2 * n)]) N = matrix.diagonal([1 if i else -1 for i in range(2 * n)]) - Omega = (U * N)**6 + Omega = (U * N) ** 6 assert Omega**12 == I(36) # The value w_{ij} is understood in the paper as matrix generated by Omega @@ -5912,24 +6213,21 @@ def JankoKharaghaniGraph(v, immutable=False): # w_ij represents in the paper the matrix w_{ij}*L. We perform this action while # computing what is noted '[ M w_{ij} ]' in the paper. - D = [[M*0 if w == 0 else M*(Omega**w)*L for w in R] - for R in W] + D = [[M * 0 if w == 0 else M * (Omega**w) * L for w in R] for R in W] D = matrix.block(D) # for v=1800 the construction is slightly different, and we must add to D a # matrix which we now compute. if v == 1800: + def my_abs(M): return matrix([[1 if x else 0 for x in R] for R in M.rows()]) M = (J(6) + I(6)).tensor_product(J(6)) # we define M = (J(6)+I(6)) x J(6) - D2 = [[M*0 if w == 0 else M*my_abs((Omega**w)*L) for w in R] # '[ (J(6)+I(6)) x J(6) |w_{ij}| ]' - for R in W] - D = (D + matrix.block(D2))/2 + D2 = [[M * 0 if w == 0 else M * my_abs((Omega**w) * L) for w in R] for R in W] # '[ (J(6)+I(6)) x J(6) |w_{ij}| ]' + D = (D + matrix.block(D2)) / 2 - return Graph([e for e, v in D.dict().items() if v == 1], - format="list_of_edges", multiedges=False, - name='Janko-Kharaghani', immutable=immutable) + return Graph([e for e, v in D.dict().items() if v == 1], format="list_of_edges", multiedges=False, name='Janko-Kharaghani', immutable=immutable) def JankoKharaghaniTonchevGraph(immutable=False): @@ -5955,59 +6253,21 @@ def JankoKharaghaniTonchevGraph(immutable=False): from sage.combinat.permutation import Permutation as P from sage.libs.gap.libgap import libgap - m1 = prod(P((9 * x + k, 9 * x + k + 3, 9 * x + k + 6)) - for k in range(1, 4) for x in range(36)) + m1 = prod(P((9 * x + k, 9 * x + k + 3, 9 * x + k + 6)) for k in range(1, 4) for x in range(36)) m2 = prod(P((3 * x + 1, 3 * x + 2, 3 * x + 3)) for x in range(108)) - t = prod(prod(map(P, [(9 * x + 2, 9 * x + 3), (9 * x + 4, 9 * x + 7), - (9 * x + 5, 9 * x + 9), (9 * x + 6, 9 * x + 8)])) - for x in range(36)) - n1 = prod(prod(map(P, [(1 + x, 19 + x, 37 + x), (55 + x, 73 + x, 91 + x), - (109 + x, 127 + x, 145 + x), (163 + x, 181 + x, 199 + x), - (217 + x, 235 + x, 253 + x), (271 + x, 289 + x, 307 + x)])) - for x in range(18)) - n2 = prod(prod(map(P, [(1 + x, 55 + x, 109 + x), (19 + x, 73 + x, 127 + x), - (37 + x, 91 + x, 145 + x), (163 + x, 217 + x, 271 + x), - (181 + x, 235 + x, 289 + x), (199 + x, 253 + x, 307 + x)])) - for x in range(18)) - s = prod(prod(map(P, [(19 + x, 37 + x), (55 + x, 109 + x), (73 + x, 145 + x), - (91 + x, 127 + x), (181 + x, 199 + x), (217 + x, 271 + x), - (235 + x, 307 + x), (253 + x, 289 + x)])) - for x in range(18)) - k = prod(prod(map(P, [(18 * x + 1, 18 * x + 10), (18 * x + 2, 18 * x + 11), - (18 * x + 3, 18 * x + 12), (18 * x + 4, 18 * x + 13), - (18 * x + 5, 18 * x + 14), (18 * x + 6, 18 * x + 15), - (18 * x + 7, 18 * x + 16), (18 * x + 8, 18 * x + 17), - (18 * x + 9, 18 * x + 18)])) - for x in range(18)) + t = prod(prod(map(P, [(9 * x + 2, 9 * x + 3), (9 * x + 4, 9 * x + 7), (9 * x + 5, 9 * x + 9), (9 * x + 6, 9 * x + 8)])) for x in range(36)) + n1 = prod(prod(map(P, [(1 + x, 19 + x, 37 + x), (55 + x, 73 + x, 91 + x), (109 + x, 127 + x, 145 + x), (163 + x, 181 + x, 199 + x), (217 + x, 235 + x, 253 + x), (271 + x, 289 + x, 307 + x)])) for x in range(18)) + n2 = prod(prod(map(P, [(1 + x, 55 + x, 109 + x), (19 + x, 73 + x, 127 + x), (37 + x, 91 + x, 145 + x), (163 + x, 217 + x, 271 + x), (181 + x, 235 + x, 289 + x), (199 + x, 253 + x, 307 + x)])) for x in range(18)) + s = prod(prod(map(P, [(19 + x, 37 + x), (55 + x, 109 + x), (73 + x, 145 + x), (91 + x, 127 + x), (181 + x, 199 + x), (217 + x, 271 + x), (235 + x, 307 + x), (253 + x, 289 + x)])) for x in range(18)) + k = prod(prod(map(P, [(18 * x + 1, 18 * x + 10), (18 * x + 2, 18 * x + 11), (18 * x + 3, 18 * x + 12), (18 * x + 4, 18 * x + 13), (18 * x + 5, 18 * x + 14), (18 * x + 6, 18 * x + 15), (18 * x + 7, 18 * x + 16), (18 * x + 8, 18 * x + 17), (18 * x + 9, 18 * x + 18)])) for x in range(18)) G = libgap.Group([libgap.PermList(p) for p in [m1, m2, t, n1, n2, s, k]]) st = libgap.Group([libgap.PermList(p) for p in [t, s]]) - B1 = (19, 22, 25, 29, 30, 31, 33, 34, 35, 37, 40, 43, 47, 48, 49, 51, 52, - 53, 55, 56, 57, 65, 66, 67, 68, 70, 72, 76, 77, 78, 79, 80, 81, 82, - 86, 90, 92, 93, 95, 96, 98, 99, 100, 105, 107, 109, 110, 111, 119, - 120, 121, 122, 124, 126, 128, 129, 131, 132, 134, 135, 136, 141, 143, - 148, 149, 150, 151, 152, 153, 154, 158, 162, 167, 168, 170, 171, 172, - 176, 177, 179, 180, 184, 186, 187, 188, 190, 191, 192, 193, 196, 202, - 204, 205, 206, 208, 209, 210, 211, 214, 218, 219, 221, 225, 226, 227, - 228, 229, 232, 236, 237, 238, 241, 244, 245, 246, 249, 251, 254, 255, - 256, 259, 262, 265, 266, 268, 270, 272, 273, 275, 279, 280, 281, 282, - 283, 286, 290, 291, 292, 295, 298, 301, 302, 304, 306, 308, 309, 310, - 313, 316, 317, 318, 321, 323) - B163 = (5, 6, 8, 9, 10, 14, 15, 17, 18, 22, 24, 25, 26, 28, 29, 30, 31, 34, - 40, 42, 43, 44, 46, 47, 48, 49, 52, 56, 57, 59, 63, 64, 65, 66, 67, - 70, 74, 75, 76, 79, 82, 83, 84, 87, 89, 92, 93, 94, 97, 100, 103, - 104, 106, 108, 110, 111, 113, 117, 118, 119, 120, 121, 124, 128, - 129, 130, 133, 136, 139, 140, 142, 144, 146, 147, 148, 151, 154, - 155, 156, 159, 161, 181, 185, 189, 191, 192, 194, 195, 197, 198, - 199, 203, 207, 209, 210, 212, 213, 215, 216, 217, 222, 224, 229, - 230, 231, 232, 233, 234, 236, 237, 238, 240, 241, 242, 244, 245, - 246, 254, 255, 256, 257, 259, 261, 262, 265, 268, 271, 276, 278, - 283, 284, 285, 286, 287, 288, 290, 291, 292, 293, 295, 297, 298, - 301, 304, 308, 309, 310, 312, 313, 314, 316, 317, 318) + B1 = (19, 22, 25, 29, 30, 31, 33, 34, 35, 37, 40, 43, 47, 48, 49, 51, 52, 53, 55, 56, 57, 65, 66, 67, 68, 70, 72, 76, 77, 78, 79, 80, 81, 82, 86, 90, 92, 93, 95, 96, 98, 99, 100, 105, 107, 109, 110, 111, 119, 120, 121, 122, 124, 126, 128, 129, 131, 132, 134, 135, 136, 141, 143, 148, 149, 150, 151, 152, 153, 154, 158, 162, 167, 168, 170, 171, 172, 176, 177, 179, 180, 184, 186, 187, 188, 190, 191, 192, 193, 196, 202, 204, 205, 206, 208, 209, 210, 211, 214, 218, 219, 221, 225, 226, 227, 228, 229, 232, 236, 237, 238, 241, 244, 245, 246, 249, 251, 254, 255, 256, 259, 262, 265, 266, 268, 270, 272, 273, 275, 279, 280, 281, 282, 283, 286, 290, 291, 292, 295, 298, 301, 302, 304, 306, 308, 309, 310, 313, 316, 317, 318, 321, 323) + B163 = (5, 6, 8, 9, 10, 14, 15, 17, 18, 22, 24, 25, 26, 28, 29, 30, 31, 34, 40, 42, 43, 44, 46, 47, 48, 49, 52, 56, 57, 59, 63, 64, 65, 66, 67, 70, 74, 75, 76, 79, 82, 83, 84, 87, 89, 92, 93, 94, 97, 100, 103, 104, 106, 108, 110, 111, 113, 117, 118, 119, 120, 121, 124, 128, 129, 130, 133, 136, 139, 140, 142, 144, 146, 147, 148, 151, 154, 155, 156, 159, 161, 181, 185, 189, 191, 192, 194, 195, 197, 198, 199, 203, 207, 209, 210, 212, 213, 215, 216, 217, 222, 224, 229, 230, 231, 232, 233, 234, 236, 237, 238, 240, 241, 242, 244, 245, 246, 254, 255, 256, 257, 259, 261, 262, 265, 268, 271, 276, 278, 283, 284, 285, 286, 287, 288, 290, 291, 292, 293, 295, 297, 298, 301, 304, 308, 309, 310, 312, 313, 314, 316, 317, 318) Gamma = Graph(multiedges=False, name='Janko-Kharaghani-Tonchev') for i, b in ((1, B1), (163, B163)): for x in st.OrbitsDomain(b): - Gamma.add_edges(map(tuple, G.Orbit(libgap.Set([i, x[0]]), - libgap.OnSets))) + Gamma.add_edges(map(tuple, G.Orbit(libgap.Set([i, x[0]]), libgap.OnSets))) if immutable: return Gamma.relabel(range(Gamma.order()), inplace=False, immutable=True) Gamma.relabel(range(Gamma.order())) @@ -6121,17 +6381,16 @@ def IoninKharaghani765Graph(immutable=False): 2016/02/24, see http://www.cs.uleth.ca/~hadi/research/IoninKharaghani.pdf """ from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF + K = GF(3) # the four φ functions - phi = [lambda xy: 1*xy[0] + 0*xy[1], - lambda xy: 0*xy[0] + 1*xy[1], - lambda xy: 1*xy[0] + 1*xy[1], - lambda xy: 1*xy[0] - 1*xy[1]] + phi = [lambda xy: 1 * xy[0] + 0 * xy[1], lambda xy: 0 * xy[0] + 1 * xy[1], lambda xy: 1 * xy[0] + 1 * xy[1], lambda xy: 1 * xy[0] - 1 * xy[1]] # Defining L_{i,j} L = {(i, j): set() for i in range(4) for j in K} from itertools import product + for p in product(K, K): for i in range(4): L[i, phi[i](p)].add(p) @@ -6150,18 +6409,16 @@ def M(S): def difference(xy, xxyy): return (K(xy[0] - xxyy[0]), K(xy[1] - xxyy[1])) - return matrix([[1 if difference(A[8-i], A[j]) in S else 0 - for i in range(9)] - for j in range(9)]) + + return matrix([[1 if difference(A[8 - i], A[j]) in S else 0 for i in range(9)] for j in range(9)]) def N(Xi): Xi = [M(x) for x in Xi] - return matrix.block([Xi[i:] + Xi[:i] - for i in range(len(Xi))]) + return matrix.block([Xi[i:] + Xi[:i] for i in range(len(Xi))]) # sigma = lambda Xi: Xi[1:] + [pi[Xi[0]]] def f_pow(f, i, X): - return f_pow(f, i-1, f(X)) if i else X + return f_pow(f, i - 1, f(X)) if i else X def sigma2(Xi): return Xi[1:] + [Xi[0]] @@ -6172,9 +6429,9 @@ def pi_vec(x): # The matrix W, with off-diagonal entries equal to integers 1,...,15 # (instead of x^1,...,x^15) from sage.matrix.constructor import matrix + GF16 = GF(16, 'x') - W = matrix([[x + y for x in GF16] + [1] for y in GF16] + - [[1]*16 + [0]]) + W = matrix([[x + y for x in GF16] + [1] for y in GF16] + [[1] * 16 + [0]]) x = GF16.primitive_element() log_x = {x**i: i for i in range(15)} W = W.apply_map(lambda x: log_x[x] + 1 if x else 0) @@ -6216,7 +6473,8 @@ def U42Graph216(immutable=False): GapPackage("grape", spkg='gap_packages').require() - adj_list = libgap.function_factory("""function() + adj_list = libgap.function_factory( + """function() local gg, hl, o216, a216, x, h, re, G; LoadPackage("grape"); gg:=SpecialUnitaryGroup(4,2); @@ -6232,12 +6490,11 @@ def U42Graph216(immutable=False): re:=Filtered(Orbits(h,[1..216]),x->Length(x)=20); G:=EdgeOrbitsGraph(a216, [[1,re[1][1]], [1,re[2][1]]]); return List([1..216],x->Adjacency(G,x)); - end;""") + end;""" + ) adj = adj_list() # for each vertex, we get the list of vertices it is adjacent to - return Graph(((i, int(j - 1)) for i, ni in enumerate(adj) for j in ni), - format='list_of_edges', multiedges=False, - name='U42Graph216', immutable=immutable) + return Graph(((i, int(j - 1)) for i, ni in enumerate(adj) for j in ni), format='list_of_edges', multiedges=False, name='U42Graph216', immutable=immutable) def U42Graph540(immutable=False): @@ -6267,7 +6524,8 @@ def U42Graph540(immutable=False): GapPackage("grape", spkg='gap_packages').require() - adj_list = libgap.function_factory("""function() + adj_list = libgap.function_factory( + """function() local f, o540, a540, x, oh, h, lo, G; LoadPackage("grape"); f:=Sp(4,3); @@ -6278,9 +6536,8 @@ def U42Graph540(immutable=False): lo:=List([8,9,10,11,12,16,19,22,23,24],x->[1,oh[x+1][1]]); G:=EdgeOrbitsGraph(a540,lo); return List([1..540],x->Adjacency(G,x)); - end;""") + end;""" + ) adj = adj_list() # for each vertex, we get the list of vertices it is adjacent to - return Graph(((i, int(j - 1)) for i, ni in enumerate(adj) for j in ni), - format='list_of_edges', multiedges=False, - name='U42Graph540', immutable=immutable) + return Graph(((i, int(j - 1)) for i, ni in enumerate(adj) for j in ni), format='list_of_edges', multiedges=False, name='U42Graph540', immutable=immutable) diff --git a/src/sage/graphs/generators/world_map.py b/src/sage/graphs/generators/world_map.py index 8ba8d650216..34d4c6356a9 100644 --- a/src/sage/graphs/generators/world_map.py +++ b/src/sage/graphs/generators/world_map.py @@ -59,42 +59,37 @@ def AfricaMap(continental=False, year=2018, immutable=False): raise ValueError("currently only year 2018 is implemented") common_border = { - 'Algeria': ['Libya', 'Mali', 'Mauritania', 'Morocco', 'Niger', 'Tunisia'], - 'Angola': ['Namibia', 'Zambia'], - 'Benin': ['Burkina Faso', 'Niger', 'Nigeria', 'Togo'], - 'Botswana': ['Namibia', 'South Africa', 'Zimbabwe'], - 'Burkina Faso': ['Ghana', 'Ivory Coast', 'Mali', 'Niger', 'Togo'], - 'Cameroon': ['Central Africa', 'Chad', 'Equatorial Guinea', 'Gabon', - 'Nigeria'], - 'Central Africa': ['Chad', 'South Sudan', 'Sudan'], - 'Chad': ['Libya', 'Niger', 'Nigeria', 'Sudan'], - 'Republic of the Congo': ['Gabon', 'Cameroon', 'Central Africa', 'Angola', - 'Democratic Republic of the Congo'], - 'Democratic Republic of the Congo': ['Zambia', 'South Sudan', 'Tanzania', - 'Burundi', 'Rwanda', 'Uganda', - 'Central Africa', 'Angola'], - 'Djibouti': ['Eritrea', 'Ethiopia', 'Somalia'], - 'Ethiopia': ['Eritrea', 'Kenya', 'Somalia', 'South Sudan', 'Sudan'], - 'Gabon': ['Equatorial Guinea'], - 'Ghana': ['Ivory Coast', 'Togo'], - 'Guinea': ['Guinea-Bissau', 'Ivory Coast', 'Liberia', 'Sierra Leone'], - 'Kenya': ['Somalia', 'South Sudan', 'Tanzania', 'Uganda'], - 'Liberia': ['Ivory Coast', 'Sierra Leone'], - 'Libya': ['Egypt', 'Niger', 'Sudan', 'Tunisia'], - 'Mali': ['Guinea', 'Ivory Coast', 'Mauritania', 'Niger', 'Senegal'], - 'Mozambique': ['Malawi', 'South Africa', 'Swaziland', 'Zimbabwe'], - 'Niger': ['Nigeria'], - 'Rwanda': ['Burundi', 'Tanzania', 'Uganda'], - 'Senegal': ['Guinea', 'Guinea-Bissau', 'Mauritania', 'Gambia'], - 'South Africa': ['Lesotho', 'Namibia', 'Swaziland', 'Zimbabwe'], - 'South Sudan': ['Uganda', 'Sudan', 'Democratic Republic of the Congo'], - 'Sudan': ['Egypt', 'Eritrea'], - 'Tanzania': ['Burundi', 'Malawi', 'Mozambique', 'Uganda', 'Zambia'], - 'Zambia': ['Malawi', 'Mozambique', 'Namibia', 'Zimbabwe'] - } - - no_land_border = ['Cape Verde', 'Seychelles', 'Mauritius', - 'São Tomé and Príncipe', 'Madagascar', 'Comoros'] + 'Algeria': ['Libya', 'Mali', 'Mauritania', 'Morocco', 'Niger', 'Tunisia'], + 'Angola': ['Namibia', 'Zambia'], + 'Benin': ['Burkina Faso', 'Niger', 'Nigeria', 'Togo'], + 'Botswana': ['Namibia', 'South Africa', 'Zimbabwe'], + 'Burkina Faso': ['Ghana', 'Ivory Coast', 'Mali', 'Niger', 'Togo'], + 'Cameroon': ['Central Africa', 'Chad', 'Equatorial Guinea', 'Gabon', 'Nigeria'], + 'Central Africa': ['Chad', 'South Sudan', 'Sudan'], + 'Chad': ['Libya', 'Niger', 'Nigeria', 'Sudan'], + 'Republic of the Congo': ['Gabon', 'Cameroon', 'Central Africa', 'Angola', 'Democratic Republic of the Congo'], + 'Democratic Republic of the Congo': ['Zambia', 'South Sudan', 'Tanzania', 'Burundi', 'Rwanda', 'Uganda', 'Central Africa', 'Angola'], + 'Djibouti': ['Eritrea', 'Ethiopia', 'Somalia'], + 'Ethiopia': ['Eritrea', 'Kenya', 'Somalia', 'South Sudan', 'Sudan'], + 'Gabon': ['Equatorial Guinea'], + 'Ghana': ['Ivory Coast', 'Togo'], + 'Guinea': ['Guinea-Bissau', 'Ivory Coast', 'Liberia', 'Sierra Leone'], + 'Kenya': ['Somalia', 'South Sudan', 'Tanzania', 'Uganda'], + 'Liberia': ['Ivory Coast', 'Sierra Leone'], + 'Libya': ['Egypt', 'Niger', 'Sudan', 'Tunisia'], + 'Mali': ['Guinea', 'Ivory Coast', 'Mauritania', 'Niger', 'Senegal'], + 'Mozambique': ['Malawi', 'South Africa', 'Swaziland', 'Zimbabwe'], + 'Niger': ['Nigeria'], + 'Rwanda': ['Burundi', 'Tanzania', 'Uganda'], + 'Senegal': ['Guinea', 'Guinea-Bissau', 'Mauritania', 'Gambia'], + 'South Africa': ['Lesotho', 'Namibia', 'Swaziland', 'Zimbabwe'], + 'South Sudan': ['Uganda', 'Sudan', 'Democratic Republic of the Congo'], + 'Sudan': ['Egypt', 'Eritrea'], + 'Tanzania': ['Burundi', 'Malawi', 'Mozambique', 'Uganda', 'Zambia'], + 'Zambia': ['Malawi', 'Mozambique', 'Namibia', 'Zimbabwe'], + } + + no_land_border = ['Cape Verde', 'Seychelles', 'Mauritius', 'São Tomé and Príncipe', 'Madagascar', 'Comoros'] if continental: name = "Continental Africa Map" @@ -102,8 +97,7 @@ def AfricaMap(continental=False, year=2018, immutable=False): common_border.update((c, []) for c in no_land_border) name = "Africa Map" - return Graph(common_border, format='dict_of_lists', - name=name, immutable=immutable) + return Graph(common_border, format='dict_of_lists', name=name, immutable=immutable) def EuropeMap(continental=False, year=2018, immutable=False): @@ -148,47 +142,38 @@ def EuropeMap(continental=False, year=2018, immutable=False): raise ValueError("currently only year 2018 is implemented") common_border = { - 'Austria': ['Czech Republic', 'Germany', 'Liechtenstein', 'Slovenia', - 'Switzerland'], - 'Belarus': ['Latvia', 'Lithuania', 'Poland', 'Russia', 'Ukraine'], - 'Belgium': ['France', 'Germany', 'Luxembourg', 'Netherlands'], - 'Croatia': ['Bosnia and Herzegovina', 'Hungary', 'Montenegro', 'Serbia', - 'Slovenia'], - 'France': ['Andorra', 'Germany', 'Italy', 'Luxembourg', 'Monaco', - 'Switzerland'], - 'Germany': ['Czech Republic', 'Denmark', 'Luxembourg', 'Netherlands', - 'Switzerland'], - 'Greece': ['Albania', 'Bulgaria', 'Macedonia'], - 'Hungary': ['Austria', 'Romania', 'Serbia', 'Slovakia', 'Slovenia', - 'Ukraine'], - 'Ireland': ['United Kingdom'], - 'Italy': ['Austria', 'San Marino', 'Slovenia', 'Switzerland', - 'Vatican City'], - 'Latvia': ['Estonia', 'Lithuania', 'Russia'], - 'Macedonia': ['Albania', 'Bulgaria', 'Serbia'], - 'Montenegro': ['Albania', 'Bosnia and Herzegovina', 'Serbia'], - 'Norway': ['Finland', 'Russia', 'Sweden'], - 'Poland': ['Czech Republic', 'Germany', 'Lithuania', 'Russia', 'Slovakia', - 'Ukraine'], - 'Romania': ['Bulgaria', 'Moldova', 'Serbia', 'Ukraine'], - 'Russia': ['Estonia', 'Finland', 'Lithuania', 'Ukraine'], - 'Serbia': ['Bosnia and Herzegovina', 'Bulgaria'], - 'Slovakia': ['Austria', 'Czech Republic', 'Ukraine'], - 'Spain': ['Andorra', 'France', 'Portugal'], - 'Sweden': ['Finland'], - 'Switzerland': ['Liechtenstein'], - 'Ukraine': ['Moldova'] + 'Austria': ['Czech Republic', 'Germany', 'Liechtenstein', 'Slovenia', 'Switzerland'], + 'Belarus': ['Latvia', 'Lithuania', 'Poland', 'Russia', 'Ukraine'], + 'Belgium': ['France', 'Germany', 'Luxembourg', 'Netherlands'], + 'Croatia': ['Bosnia and Herzegovina', 'Hungary', 'Montenegro', 'Serbia', 'Slovenia'], + 'France': ['Andorra', 'Germany', 'Italy', 'Luxembourg', 'Monaco', 'Switzerland'], + 'Germany': ['Czech Republic', 'Denmark', 'Luxembourg', 'Netherlands', 'Switzerland'], + 'Greece': ['Albania', 'Bulgaria', 'Macedonia'], + 'Hungary': ['Austria', 'Romania', 'Serbia', 'Slovakia', 'Slovenia', 'Ukraine'], + 'Ireland': ['United Kingdom'], + 'Italy': ['Austria', 'San Marino', 'Slovenia', 'Switzerland', 'Vatican City'], + 'Latvia': ['Estonia', 'Lithuania', 'Russia'], + 'Macedonia': ['Albania', 'Bulgaria', 'Serbia'], + 'Montenegro': ['Albania', 'Bosnia and Herzegovina', 'Serbia'], + 'Norway': ['Finland', 'Russia', 'Sweden'], + 'Poland': ['Czech Republic', 'Germany', 'Lithuania', 'Russia', 'Slovakia', 'Ukraine'], + 'Romania': ['Bulgaria', 'Moldova', 'Serbia', 'Ukraine'], + 'Russia': ['Estonia', 'Finland', 'Lithuania', 'Ukraine'], + 'Serbia': ['Bosnia and Herzegovina', 'Bulgaria'], + 'Slovakia': ['Austria', 'Czech Republic', 'Ukraine'], + 'Spain': ['Andorra', 'France', 'Portugal'], + 'Sweden': ['Finland'], + 'Switzerland': ['Liechtenstein'], + 'Ukraine': ['Moldova'], } no_land_border = ['Iceland', 'Malta'] if continental: - G = Graph(common_border, format='dict_of_lists', - name="Continental Europe Map", immutable=immutable) + G = Graph(common_border, format='dict_of_lists', name="Continental Europe Map", immutable=immutable) G = G.subgraph(G.connected_component_containing_vertex('Austria', sort=False)) else: common_border.update((c, []) for c in no_land_border) - G = Graph(common_border, format='dict_of_lists', - name="Europe Map", immutable=immutable) + G = Graph(common_border, format='dict_of_lists', name="Europe Map", immutable=immutable) return G @@ -227,73 +212,52 @@ def USAMap(continental=False, immutable=False): states = { "Alabama": ["Florida", "Georgia", "Mississippi", "Tennessee"], "Arizona": ["California", "Colorado", "Nevada", "New Mexico", "Utah"], - "Arkansas": ["Louisiana", "Mississippi", "Missouri", "Oklahoma", - "Tennessee", "Texas"], + "Arkansas": ["Louisiana", "Mississippi", "Missouri", "Oklahoma", "Tennessee", "Texas"], "California": ["Arizona", "Nevada", "Oregon"], - "Colorado": ["Arizona", "Kansas", "Nebraska", "New Mexico", "Oklahoma", - "Utah", "Wyoming"], + "Colorado": ["Arizona", "Kansas", "Nebraska", "New Mexico", "Oklahoma", "Utah", "Wyoming"], "Connecticut": ["Massachusetts", "New York", "Rhode Island"], "Delaware": ["Maryland", "New Jersey", "Pennsylvania"], "Florida": ["Alabama", "Georgia"], - "Georgia": ["Alabama", "Florida", "North Carolina", "South Carolina", - "Tennessee"], - "Idaho": ["Montana", "Nevada", "Oregon", "Utah", "Washington", - "Wyoming"], - "Illinois": ["Indiana", "Iowa", "Michigan", "Kentucky", "Missouri", - "Wisconsin"], + "Georgia": ["Alabama", "Florida", "North Carolina", "South Carolina", "Tennessee"], + "Idaho": ["Montana", "Nevada", "Oregon", "Utah", "Washington", "Wyoming"], + "Illinois": ["Indiana", "Iowa", "Michigan", "Kentucky", "Missouri", "Wisconsin"], "Indiana": ["Illinois", "Kentucky", "Michigan", "Ohio"], - "Iowa": ["Illinois", "Minnesota", "Missouri", "Nebraska", - "South Dakota", "Wisconsin"], + "Iowa": ["Illinois", "Minnesota", "Missouri", "Nebraska", "South Dakota", "Wisconsin"], "Kansas": ["Colorado", "Missouri", "Nebraska", "Oklahoma"], - "Kentucky": ["Illinois", "Indiana", "Missouri", "Ohio", "Tennessee", - "Virginia", "West Virginia"], + "Kentucky": ["Illinois", "Indiana", "Missouri", "Ohio", "Tennessee", "Virginia", "West Virginia"], "Louisiana": ["Arkansas", "Mississippi", "Texas"], "Maine": ["New Hampshire"], "Maryland": ["Delaware", "Pennsylvania", "Virginia", "West Virginia"], - "Massachusetts": ["Connecticut", "New Hampshire", "New York", - "Rhode Island", "Vermont"], + "Massachusetts": ["Connecticut", "New Hampshire", "New York", "Rhode Island", "Vermont"], "Michigan": ["Illinois", "Indiana", "Ohio", "Wisconsin"], "Minnesota": ["Iowa", "North Dakota", "South Dakota", "Wisconsin"], "Mississippi": ["Alabama", "Arkansas", "Louisiana", "Tennessee"], - "Missouri": ["Arkansas", "Illinois", "Iowa", "Kansas", "Kentucky", - "Nebraska", "Oklahoma", "Tennessee"], + "Missouri": ["Arkansas", "Illinois", "Iowa", "Kansas", "Kentucky", "Nebraska", "Oklahoma", "Tennessee"], "Montana": ["Idaho", "North Dakota", "South Dakota", "Wyoming"], - "Nebraska": ["Colorado", "Iowa", "Kansas", "Missouri", "South Dakota", - "Wyoming"], + "Nebraska": ["Colorado", "Iowa", "Kansas", "Missouri", "South Dakota", "Wyoming"], "Nevada": ["Arizona", "California", "Idaho", "Oregon", "Utah"], "New Hampshire": ["Maine", "Massachusetts", "Vermont"], "New Jersey": ["Delaware", "New York", "Pennsylvania"], "New Mexico": ["Arizona", "Colorado", "Oklahoma", "Texas", "Utah"], - "New York": ["Connecticut", "Massachusetts", "New Jersey", - "Pennsylvania", "Vermont"], - "North Carolina": ["Georgia", "South Carolina", "Tennessee", - "Virginia"], + "New York": ["Connecticut", "Massachusetts", "New Jersey", "Pennsylvania", "Vermont"], + "North Carolina": ["Georgia", "South Carolina", "Tennessee", "Virginia"], "North Dakota": ["Minnesota", "Montana", "South Dakota"], - "Ohio": ["Indiana", "Kentucky", "Michigan", "Pennsylvania", - "West Virginia"], - "Oklahoma": ["Arkansas", "Colorado", "Kansas", "Missouri", - "New Mexico", "Texas"], + "Ohio": ["Indiana", "Kentucky", "Michigan", "Pennsylvania", "West Virginia"], + "Oklahoma": ["Arkansas", "Colorado", "Kansas", "Missouri", "New Mexico", "Texas"], "Oregon": ["California", "Idaho", "Nevada", "Washington"], - "Pennsylvania": ["Delaware", "Maryland", "New Jersey", "New York", - "Ohio", "West Virginia"], + "Pennsylvania": ["Delaware", "Maryland", "New Jersey", "New York", "Ohio", "West Virginia"], "Rhode Island": ["Connecticut", "Massachusetts"], "South Carolina": ["Georgia", "North Carolina"], - "South Dakota": ["Iowa", "Minnesota", "Montana", "Nebraska", - "North Dakota", "Wyoming"], - "Tennessee": ["Alabama", "Arkansas", "Georgia", "Kentucky", - "Mississippi", "Missouri", "North Carolina", "Virginia"], + "South Dakota": ["Iowa", "Minnesota", "Montana", "Nebraska", "North Dakota", "Wyoming"], + "Tennessee": ["Alabama", "Arkansas", "Georgia", "Kentucky", "Mississippi", "Missouri", "North Carolina", "Virginia"], "Texas": ["Arkansas", "Louisiana", "New Mexico", "Oklahoma"], - "Utah": ["Arizona", "Colorado", "Idaho", "Nevada", "New Mexico", - "Wyoming"], + "Utah": ["Arizona", "Colorado", "Idaho", "Nevada", "New Mexico", "Wyoming"], "Vermont": ["Massachusetts", "New Hampshire", "New York"], - "Virginia": ["Kentucky", "Maryland", "North Carolina", "Tennessee", - "West Virginia"], + "Virginia": ["Kentucky", "Maryland", "North Carolina", "Tennessee", "West Virginia"], "Washington": ["Idaho", "Oregon"], - "West Virginia": ["Kentucky", "Maryland", "Ohio", "Pennsylvania", - "Virginia"], + "West Virginia": ["Kentucky", "Maryland", "Ohio", "Pennsylvania", "Virginia"], "Wisconsin": ["Illinois", "Iowa", "Michigan", "Minnesota"], - "Wyoming": ["Colorado", "Idaho", "Montana", "Nebraska", "South Dakota", - "Utah"] + "Wyoming": ["Colorado", "Idaho", "Montana", "Nebraska", "South Dakota", "Utah"], } if continental: name = "Continental USA Map" @@ -339,150 +303,330 @@ def WorldMap(immutable=False): True """ edges = [ - ('Afghanistan', 'China'), ('Afghanistan', 'Iran'), - ('Afghanistan', 'Uzbekistan'), ('Albania', 'Greece'), - ('Albania', 'Kosovo'), ('Albania', 'Macedonia'), - ('Albania', 'Montenegro'), ('Algeria', 'Morocco'), - ('Algeria', 'Tunisia'), ('Andorra', 'Spain'), - ('Angola', 'Democratic Republic of the Congo'), ('Angola', 'Namibia'), - ('Angola', 'Zambia'), ('Argentina', 'Bolivia'), ('Argentina', 'Brazil'), - ('Argentina', 'Chile'), ('Argentina', 'Paraguay'), - ('Argentina', 'Uruguay'), ('Armenia', 'Georgia'), ('Armenia', 'Iran'), - ('Austria', 'Germany'), ('Azerbaijan', 'Armenia'), - ('Azerbaijan', 'Georgia'), ('Azerbaijan', 'Iran'), - ('Azerbaijan', 'Russia'), ('Azerbaijan', 'Turkey'), - ('Bangladesh', 'Burma'), ('Belgium', 'Germany'), - ('Belgium', 'Netherlands'), ('Belize', 'Mexico'), - ('Benin', 'Burkina Faso'), ('Benin', 'Niger'), ('Benin', 'Nigeria'), - ('Benin', 'Togo'), ('Bolivia', 'Brazil'), ('Bolivia', 'Chile'), - ('Bolivia', 'Paraguay'), ('Bolivia', 'Peru'), + ('Afghanistan', 'China'), + ('Afghanistan', 'Iran'), + ('Afghanistan', 'Uzbekistan'), + ('Albania', 'Greece'), + ('Albania', 'Kosovo'), + ('Albania', 'Macedonia'), + ('Albania', 'Montenegro'), + ('Algeria', 'Morocco'), + ('Algeria', 'Tunisia'), + ('Andorra', 'Spain'), + ('Angola', 'Democratic Republic of the Congo'), + ('Angola', 'Namibia'), + ('Angola', 'Zambia'), + ('Argentina', 'Bolivia'), + ('Argentina', 'Brazil'), + ('Argentina', 'Chile'), + ('Argentina', 'Paraguay'), + ('Argentina', 'Uruguay'), + ('Armenia', 'Georgia'), + ('Armenia', 'Iran'), + ('Austria', 'Germany'), + ('Azerbaijan', 'Armenia'), + ('Azerbaijan', 'Georgia'), + ('Azerbaijan', 'Iran'), + ('Azerbaijan', 'Russia'), + ('Azerbaijan', 'Turkey'), + ('Bangladesh', 'Burma'), + ('Belgium', 'Germany'), + ('Belgium', 'Netherlands'), + ('Belize', 'Mexico'), + ('Benin', 'Burkina Faso'), + ('Benin', 'Niger'), + ('Benin', 'Nigeria'), + ('Benin', 'Togo'), + ('Bolivia', 'Brazil'), + ('Bolivia', 'Chile'), + ('Bolivia', 'Paraguay'), + ('Bolivia', 'Peru'), ('Bosnia and Herzegovina', 'Croatia'), ('Bosnia and Herzegovina', 'Montenegro'), - ('Bosnia and Herzegovina', 'Serbia'), ('Brazil', 'Colombia'), - ('Brazil', 'Guyana'), ('Brazil', 'Suriname'), ('Brazil', 'Venezuela'), - ('Bulgaria', 'Greece'), ('Bulgaria', 'Macedonia'), - ('Bulgaria', 'Romania'), ('Bulgaria', 'Serbia'), - ('Burkina Faso', 'Mali'), ('Burkina Faso', 'Niger'), + ('Bosnia and Herzegovina', 'Serbia'), + ('Brazil', 'Colombia'), + ('Brazil', 'Guyana'), + ('Brazil', 'Suriname'), + ('Brazil', 'Venezuela'), + ('Bulgaria', 'Greece'), + ('Bulgaria', 'Macedonia'), + ('Bulgaria', 'Romania'), + ('Bulgaria', 'Serbia'), + ('Burkina Faso', 'Mali'), + ('Burkina Faso', 'Niger'), ('Burkina Faso', 'Togo'), - ('Burundi', 'Democratic Republic of the Congo'), ('Cambodia', 'Laos'), - ('Cambodia', 'Thailand'), ('Cambodia', 'Vietnam'), - ('Cameroon', 'Central African Republic'), ('Cameroon', 'Chad'), - ('Cameroon', 'Equatorial Guinea'), ('Cameroon', 'Nigeria'), - ('Cameroon', 'Republic of the Congo'), ('Canada', 'United States'), + ('Burundi', 'Democratic Republic of the Congo'), + ('Cambodia', 'Laos'), + ('Cambodia', 'Thailand'), + ('Cambodia', 'Vietnam'), + ('Cameroon', 'Central African Republic'), + ('Cameroon', 'Chad'), + ('Cameroon', 'Equatorial Guinea'), + ('Cameroon', 'Nigeria'), + ('Cameroon', 'Republic of the Congo'), + ('Canada', 'United States'), ('Central African Republic', 'Chad'), ('Central African Republic', 'Democratic Republic of the Congo'), - ('Central African Republic', 'Sudan'), ('Chad', 'Niger'), - ('Chad', 'Nigeria'), ('Chad', 'Sudan'), ('China', 'Bhutan'), - ('China', 'Burma'), ('China', 'Hong Kong'), ('China', 'Kazakhstan'), - ('China', 'Kyrgyzstan'), ('China', 'Mongolia'), ('China', 'Nepal'), - ('China', 'North Korea'), ('China', 'Russia'), ('China', 'Vietnam'), - ('Colombia', 'Venezuela'), ('Costa Rica', 'Nicaragua'), - ("Cote d'Ivoire", 'Burkina Faso'), ("Cote d'Ivoire", 'Guinea'), - ("Cote d'Ivoire", 'Mali'), ('Cyprus', 'Akrotiri'), - ('Cyprus', 'Dhekelia'), ('Czech Republic', 'Austria'), - ('Czech Republic', 'Germany'), ('Czech Republic', 'Poland'), - ('Democratic Republic of the Congo', 'Zambia'), ('Denmark', 'Germany'), - ('Djibouti', 'Eritrea'), ('Dominican Republic', 'Haiti'), - ('Ecuador', 'Colombia'), ('El Salvador', 'Honduras'), - ('Ethiopia', 'Djibouti'), ('Ethiopia', 'Eritrea'), - ('Ethiopia', 'Kenya'), ('Ethiopia', 'Somalia'), ('Ethiopia', 'Sudan'), - ('Finland', 'Russia'), ('Finland', 'Sweden'), ('France', 'Andorra'), - ('France', 'Belgium'), ('France', 'Brazil'), ('France', 'Germany'), - ('France', 'Italy'), ('France', 'Luxembourg'), ('France', 'Spain'), - ('France', 'Suriname'), ('France', 'Switzerland'), - ('Gabon', 'Cameroon'), ('Gabon', 'Equatorial Guinea'), - ('Gabon', 'Republic of the Congo'), ('Gaza Strip', 'Egypt'), - ('Gaza Strip', 'Israel'), ('Ghana', 'Burkina Faso'), - ('Ghana', "Cote d'Ivoire"), ('Ghana', 'Togo'), ('Gibraltar', 'Spain'), - ('Guatemala', 'Belize'), ('Guatemala', 'El Salvador'), - ('Guatemala', 'Honduras'), ('Guatemala', 'Mexico'), - ('Guinea', 'Sierra Leone'), ('Guinea-Bissau', 'Guinea'), - ('Guinea-Bissau', 'Senegal'), ('Honduras', 'Nicaragua'), - ('Hungary', 'Austria'), ('Hungary', 'Croatia'), ('Hungary', 'Serbia'), - ('India', 'Bangladesh'), ('India', 'Bhutan'), ('India', 'Burma'), - ('India', 'China'), ('India', 'Nepal'), - ('Indonesia', 'Papua New Guinea'), ('Iran', 'Iraq'), - ('Ireland', 'United Kingdom'), ('Israel', 'Egypt'), - ('Italy', 'Austria'), ('Jordan', 'Iraq'), ('Jordan', 'Israel'), - ('Jordan', 'Syria'), ('Jordan', 'West Bank'), - ('Kazakhstan', 'Kyrgyzstan'), ('Kenya', 'Somalia'), ('Kenya', 'Sudan'), - ('Kenya', 'Uganda'), ('Kosovo', 'Macedonia'), ('Kosovo', 'Serbia'), - ('Kuwait', 'Iraq'), ('Laos', 'Burma'), ('Laos', 'China'), - ('Laos', 'Thailand'), ('Laos', 'Vietnam'), ('Latvia', 'Belarus'), - ('Latvia', 'Estonia'), ('Lebanon', 'Israel'), - ('Lesotho', 'South Africa'), ('Liberia', "Cote d'Ivoire"), - ('Liberia', 'Guinea'), ('Liberia', 'Sierra Leone'), - ('Libya', 'Algeria'), ('Libya', 'Chad'), ('Libya', 'Egypt'), - ('Libya', 'Niger'), ('Libya', 'Sudan'), ('Libya', 'Tunisia'), - ('Liechtenstein', 'Austria'), ('Liechtenstein', 'Switzerland'), - ('Lithuania', 'Belarus'), ('Lithuania', 'Latvia'), - ('Lithuania', 'Poland'), ('Lithuania', 'Russia'), - ('Luxembourg', 'Belgium'), ('Luxembourg', 'Germany'), - ('Macau', 'China'), ('Macedonia', 'Greece'), ('Macedonia', 'Serbia'), - ('Malaysia', 'Brunei'), ('Malaysia', 'Indonesia'), - ('Malaysia', 'Thailand'), ('Mali', 'Algeria'), ('Mali', 'Guinea'), - ('Mali', 'Niger'), ('Mali', 'Senegal'), ('Mauritania', 'Algeria'), - ('Mauritania', 'Mali'), ('Mauritania', 'Senegal'), - ('Mauritania', 'Western Sahara'), ('Monaco', 'France'), - ('Montenegro', 'Croatia'), ('Montenegro', 'Kosovo'), - ('Montenegro', 'Serbia'), ('Morocco', 'Spain'), - ('Mozambique', 'Malawi'), ('Mozambique', 'Zambia'), - ('Mozambique', 'Zimbabwe'), ('Namibia', 'Botswana'), - ('Namibia', 'Zambia'), ('Netherlands', 'Germany'), ('Niger', 'Algeria'), - ('Niger', 'Nigeria'), ('Norway', 'Finland'), ('Norway', 'Russia'), - ('Norway', 'Sweden'), ('Oman', 'United Arab Emirates'), - ('Oman', 'Yemen'), ('Pakistan', 'Afghanistan'), ('Pakistan', 'China'), - ('Pakistan', 'India'), ('Pakistan', 'Iran'), ('Panama', 'Colombia'), - ('Panama', 'Costa Rica'), ('Paraguay', 'Brazil'), ('Peru', 'Brazil'), - ('Peru', 'Chile'), ('Peru', 'Colombia'), ('Peru', 'Ecuador'), - ('Poland', 'Belarus'), ('Poland', 'Germany'), ('Portugal', 'Spain'), + ('Central African Republic', 'Sudan'), + ('Chad', 'Niger'), + ('Chad', 'Nigeria'), + ('Chad', 'Sudan'), + ('China', 'Bhutan'), + ('China', 'Burma'), + ('China', 'Hong Kong'), + ('China', 'Kazakhstan'), + ('China', 'Kyrgyzstan'), + ('China', 'Mongolia'), + ('China', 'Nepal'), + ('China', 'North Korea'), + ('China', 'Russia'), + ('China', 'Vietnam'), + ('Colombia', 'Venezuela'), + ('Costa Rica', 'Nicaragua'), + ("Cote d'Ivoire", 'Burkina Faso'), + ("Cote d'Ivoire", 'Guinea'), + ("Cote d'Ivoire", 'Mali'), + ('Cyprus', 'Akrotiri'), + ('Cyprus', 'Dhekelia'), + ('Czech Republic', 'Austria'), + ('Czech Republic', 'Germany'), + ('Czech Republic', 'Poland'), + ('Democratic Republic of the Congo', 'Zambia'), + ('Denmark', 'Germany'), + ('Djibouti', 'Eritrea'), + ('Dominican Republic', 'Haiti'), + ('Ecuador', 'Colombia'), + ('El Salvador', 'Honduras'), + ('Ethiopia', 'Djibouti'), + ('Ethiopia', 'Eritrea'), + ('Ethiopia', 'Kenya'), + ('Ethiopia', 'Somalia'), + ('Ethiopia', 'Sudan'), + ('Finland', 'Russia'), + ('Finland', 'Sweden'), + ('France', 'Andorra'), + ('France', 'Belgium'), + ('France', 'Brazil'), + ('France', 'Germany'), + ('France', 'Italy'), + ('France', 'Luxembourg'), + ('France', 'Spain'), + ('France', 'Suriname'), + ('France', 'Switzerland'), + ('Gabon', 'Cameroon'), + ('Gabon', 'Equatorial Guinea'), + ('Gabon', 'Republic of the Congo'), + ('Gaza Strip', 'Egypt'), + ('Gaza Strip', 'Israel'), + ('Ghana', 'Burkina Faso'), + ('Ghana', "Cote d'Ivoire"), + ('Ghana', 'Togo'), + ('Gibraltar', 'Spain'), + ('Guatemala', 'Belize'), + ('Guatemala', 'El Salvador'), + ('Guatemala', 'Honduras'), + ('Guatemala', 'Mexico'), + ('Guinea', 'Sierra Leone'), + ('Guinea-Bissau', 'Guinea'), + ('Guinea-Bissau', 'Senegal'), + ('Honduras', 'Nicaragua'), + ('Hungary', 'Austria'), + ('Hungary', 'Croatia'), + ('Hungary', 'Serbia'), + ('India', 'Bangladesh'), + ('India', 'Bhutan'), + ('India', 'Burma'), + ('India', 'China'), + ('India', 'Nepal'), + ('Indonesia', 'Papua New Guinea'), + ('Iran', 'Iraq'), + ('Ireland', 'United Kingdom'), + ('Israel', 'Egypt'), + ('Italy', 'Austria'), + ('Jordan', 'Iraq'), + ('Jordan', 'Israel'), + ('Jordan', 'Syria'), + ('Jordan', 'West Bank'), + ('Kazakhstan', 'Kyrgyzstan'), + ('Kenya', 'Somalia'), + ('Kenya', 'Sudan'), + ('Kenya', 'Uganda'), + ('Kosovo', 'Macedonia'), + ('Kosovo', 'Serbia'), + ('Kuwait', 'Iraq'), + ('Laos', 'Burma'), + ('Laos', 'China'), + ('Laos', 'Thailand'), + ('Laos', 'Vietnam'), + ('Latvia', 'Belarus'), + ('Latvia', 'Estonia'), + ('Lebanon', 'Israel'), + ('Lesotho', 'South Africa'), + ('Liberia', "Cote d'Ivoire"), + ('Liberia', 'Guinea'), + ('Liberia', 'Sierra Leone'), + ('Libya', 'Algeria'), + ('Libya', 'Chad'), + ('Libya', 'Egypt'), + ('Libya', 'Niger'), + ('Libya', 'Sudan'), + ('Libya', 'Tunisia'), + ('Liechtenstein', 'Austria'), + ('Liechtenstein', 'Switzerland'), + ('Lithuania', 'Belarus'), + ('Lithuania', 'Latvia'), + ('Lithuania', 'Poland'), + ('Lithuania', 'Russia'), + ('Luxembourg', 'Belgium'), + ('Luxembourg', 'Germany'), + ('Macau', 'China'), + ('Macedonia', 'Greece'), + ('Macedonia', 'Serbia'), + ('Malaysia', 'Brunei'), + ('Malaysia', 'Indonesia'), + ('Malaysia', 'Thailand'), + ('Mali', 'Algeria'), + ('Mali', 'Guinea'), + ('Mali', 'Niger'), + ('Mali', 'Senegal'), + ('Mauritania', 'Algeria'), + ('Mauritania', 'Mali'), + ('Mauritania', 'Senegal'), + ('Mauritania', 'Western Sahara'), + ('Monaco', 'France'), + ('Montenegro', 'Croatia'), + ('Montenegro', 'Kosovo'), + ('Montenegro', 'Serbia'), + ('Morocco', 'Spain'), + ('Mozambique', 'Malawi'), + ('Mozambique', 'Zambia'), + ('Mozambique', 'Zimbabwe'), + ('Namibia', 'Botswana'), + ('Namibia', 'Zambia'), + ('Netherlands', 'Germany'), + ('Niger', 'Algeria'), + ('Niger', 'Nigeria'), + ('Norway', 'Finland'), + ('Norway', 'Russia'), + ('Norway', 'Sweden'), + ('Oman', 'United Arab Emirates'), + ('Oman', 'Yemen'), + ('Pakistan', 'Afghanistan'), + ('Pakistan', 'China'), + ('Pakistan', 'India'), + ('Pakistan', 'Iran'), + ('Panama', 'Colombia'), + ('Panama', 'Costa Rica'), + ('Paraguay', 'Brazil'), + ('Peru', 'Brazil'), + ('Peru', 'Chile'), + ('Peru', 'Colombia'), + ('Peru', 'Ecuador'), + ('Poland', 'Belarus'), + ('Poland', 'Germany'), + ('Portugal', 'Spain'), ('Republic of the Congo', 'Angola'), ('Republic of the Congo', 'Central African Republic'), ('Republic of the Congo', 'Democratic Republic of the Congo'), - ('Romania', 'Hungary'), ('Romania', 'Moldova'), ('Romania', 'Serbia'), - ('Russia', 'Belarus'), ('Russia', 'Estonia'), ('Russia', 'Georgia'), - ('Russia', 'Kazakhstan'), ('Russia', 'Latvia'), ('Russia', 'Mongolia'), - ('Russia', 'North Korea'), ('Russia', 'Poland'), ('Rwanda', 'Burundi'), - ('Rwanda', 'Democratic Republic of the Congo'), ('Rwanda', 'Uganda'), - ('Saint Martin', 'Netherlands Antilles'), ('San Marino', 'Italy'), - ('Saudi Arabia', 'Iraq'), ('Saudi Arabia', 'Jordan'), - ('Saudi Arabia', 'Kuwait'), ('Saudi Arabia', 'Oman'), - ('Saudi Arabia', 'Qatar'), ('Saudi Arabia', 'United Arab Emirates'), - ('Saudi Arabia', 'Yemen'), ('Senegal', 'Guinea'), ('Serbia', 'Croatia'), - ('Slovakia', 'Austria'), ('Slovakia', 'Czech Republic'), - ('Slovakia', 'Hungary'), ('Slovakia', 'Poland'), - ('Slovakia', 'Ukraine'), ('Slovenia', 'Austria'), - ('Slovenia', 'Croatia'), ('Slovenia', 'Hungary'), ('Slovenia', 'Italy'), - ('Somalia', 'Djibouti'), ('South Africa', 'Botswana'), - ('South Africa', 'Mozambique'), ('South Africa', 'Namibia'), - ('South Africa', 'Zimbabwe'), ('South Korea', 'North Korea'), - ('Sudan', 'Democratic Republic of the Congo'), ('Sudan', 'Egypt'), - ('Sudan', 'Eritrea'), ('Suriname', 'Guyana'), - ('Swaziland', 'Mozambique'), ('Swaziland', 'South Africa'), - ('Switzerland', 'Austria'), ('Switzerland', 'Germany'), - ('Switzerland', 'Italy'), ('Syria', 'Iraq'), ('Syria', 'Israel'), - ('Syria', 'Lebanon'), ('Tajikistan', 'Afghanistan'), - ('Tajikistan', 'China'), ('Tajikistan', 'Kyrgyzstan'), - ('Tajikistan', 'Uzbekistan'), ('Tanzania', 'Burundi'), - ('Tanzania', 'Democratic Republic of the Congo'), ('Tanzania', 'Kenya'), - ('Tanzania', 'Malawi'), ('Tanzania', 'Mozambique'), - ('Tanzania', 'Rwanda'), ('Tanzania', 'Uganda'), ('Tanzania', 'Zambia'), - ('Thailand', 'Burma'), ('The Gambia', 'Senegal'), - ('Timor-Leste', 'Indonesia'), ('Turkey', 'Armenia'), - ('Turkey', 'Bulgaria'), ('Turkey', 'Georgia'), ('Turkey', 'Greece'), - ('Turkey', 'Iran'), ('Turkey', 'Iraq'), ('Turkey', 'Syria'), - ('Turkmenistan', 'Afghanistan'), ('Turkmenistan', 'Iran'), - ('Turkmenistan', 'Kazakhstan'), ('Turkmenistan', 'Uzbekistan'), - ('Uganda', 'Democratic Republic of the Congo'), ('Uganda', 'Sudan'), - ('Ukraine', 'Belarus'), ('Ukraine', 'Hungary'), ('Ukraine', 'Moldova'), - ('Ukraine', 'Poland'), ('Ukraine', 'Romania'), ('Ukraine', 'Russia'), - ('United States', 'Mexico'), ('Uruguay', 'Brazil'), - ('Uzbekistan', 'Kazakhstan'), ('Uzbekistan', 'Kyrgyzstan'), - ('Vatican City', 'Italy'), ('Venezuela', 'Guyana'), - ('West Bank', 'Israel'), ('Western Sahara', 'Algeria'), - ('Western Sahara', 'Morocco'), ('Zambia', 'Malawi'), - ('Zambia', 'Zimbabwe'), ('Zimbabwe', 'Botswana') - ] + ('Romania', 'Hungary'), + ('Romania', 'Moldova'), + ('Romania', 'Serbia'), + ('Russia', 'Belarus'), + ('Russia', 'Estonia'), + ('Russia', 'Georgia'), + ('Russia', 'Kazakhstan'), + ('Russia', 'Latvia'), + ('Russia', 'Mongolia'), + ('Russia', 'North Korea'), + ('Russia', 'Poland'), + ('Rwanda', 'Burundi'), + ('Rwanda', 'Democratic Republic of the Congo'), + ('Rwanda', 'Uganda'), + ('Saint Martin', 'Netherlands Antilles'), + ('San Marino', 'Italy'), + ('Saudi Arabia', 'Iraq'), + ('Saudi Arabia', 'Jordan'), + ('Saudi Arabia', 'Kuwait'), + ('Saudi Arabia', 'Oman'), + ('Saudi Arabia', 'Qatar'), + ('Saudi Arabia', 'United Arab Emirates'), + ('Saudi Arabia', 'Yemen'), + ('Senegal', 'Guinea'), + ('Serbia', 'Croatia'), + ('Slovakia', 'Austria'), + ('Slovakia', 'Czech Republic'), + ('Slovakia', 'Hungary'), + ('Slovakia', 'Poland'), + ('Slovakia', 'Ukraine'), + ('Slovenia', 'Austria'), + ('Slovenia', 'Croatia'), + ('Slovenia', 'Hungary'), + ('Slovenia', 'Italy'), + ('Somalia', 'Djibouti'), + ('South Africa', 'Botswana'), + ('South Africa', 'Mozambique'), + ('South Africa', 'Namibia'), + ('South Africa', 'Zimbabwe'), + ('South Korea', 'North Korea'), + ('Sudan', 'Democratic Republic of the Congo'), + ('Sudan', 'Egypt'), + ('Sudan', 'Eritrea'), + ('Suriname', 'Guyana'), + ('Swaziland', 'Mozambique'), + ('Swaziland', 'South Africa'), + ('Switzerland', 'Austria'), + ('Switzerland', 'Germany'), + ('Switzerland', 'Italy'), + ('Syria', 'Iraq'), + ('Syria', 'Israel'), + ('Syria', 'Lebanon'), + ('Tajikistan', 'Afghanistan'), + ('Tajikistan', 'China'), + ('Tajikistan', 'Kyrgyzstan'), + ('Tajikistan', 'Uzbekistan'), + ('Tanzania', 'Burundi'), + ('Tanzania', 'Democratic Republic of the Congo'), + ('Tanzania', 'Kenya'), + ('Tanzania', 'Malawi'), + ('Tanzania', 'Mozambique'), + ('Tanzania', 'Rwanda'), + ('Tanzania', 'Uganda'), + ('Tanzania', 'Zambia'), + ('Thailand', 'Burma'), + ('The Gambia', 'Senegal'), + ('Timor-Leste', 'Indonesia'), + ('Turkey', 'Armenia'), + ('Turkey', 'Bulgaria'), + ('Turkey', 'Georgia'), + ('Turkey', 'Greece'), + ('Turkey', 'Iran'), + ('Turkey', 'Iraq'), + ('Turkey', 'Syria'), + ('Turkmenistan', 'Afghanistan'), + ('Turkmenistan', 'Iran'), + ('Turkmenistan', 'Kazakhstan'), + ('Turkmenistan', 'Uzbekistan'), + ('Uganda', 'Democratic Republic of the Congo'), + ('Uganda', 'Sudan'), + ('Ukraine', 'Belarus'), + ('Ukraine', 'Hungary'), + ('Ukraine', 'Moldova'), + ('Ukraine', 'Poland'), + ('Ukraine', 'Romania'), + ('Ukraine', 'Russia'), + ('United States', 'Mexico'), + ('Uruguay', 'Brazil'), + ('Uzbekistan', 'Kazakhstan'), + ('Uzbekistan', 'Kyrgyzstan'), + ('Vatican City', 'Italy'), + ('Venezuela', 'Guyana'), + ('West Bank', 'Israel'), + ('Western Sahara', 'Algeria'), + ('Western Sahara', 'Morocco'), + ('Zambia', 'Malawi'), + ('Zambia', 'Zimbabwe'), + ('Zimbabwe', 'Botswana'), + ] gps_coordinates = { "Cote d'Ivoire": [[8, 'N'], [5, 'W']], 'Afghanistan': [[33, 'N'], [65, 'E']], @@ -734,9 +878,8 @@ def WorldMap(immutable=False): 'Western Sahara': [[24, 'N'], [13, 'W']], 'Yemen': [[15, 'N'], [48, 'E']], 'Zambia': [[15, 'S'], [30, 'E']], - 'Zimbabwe': [[20, 'S'], [30, 'E']] - } - g = Graph([gps_coordinates, edges], format="vertices_and_edges", - name="World Map", immutable=immutable) + 'Zimbabwe': [[20, 'S'], [30, 'E']], + } + g = Graph([gps_coordinates, edges], format="vertices_and_edges", name="World Map", immutable=immutable) g.gps_coordinates = gps_coordinates return g diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 545172d5503..22e0f7d96e7 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -478,8 +478,7 @@ class GenericGraph(GenericGraph_pyx): """ # Nice defaults for plotting arrays of graphs (see sage.misc.functional.show) - graphics_array_defaults = {'layout': 'circular', 'vertex_size': 50, - 'vertex_labels': False, 'graph_border': True} + graphics_array_defaults = {'layout': 'circular', 'vertex_size': 50, 'vertex_labels': False, 'graph_border': True} def __init__(self): r""" @@ -620,15 +619,11 @@ def __eq__(self, other): if not isinstance(other, GenericGraph): return False from sage.graphs.graph import Graph + g1_is_graph = isinstance(self, Graph) # otherwise, DiGraph g2_is_graph = isinstance(other, Graph) # otherwise, DiGraph # Fast checks - if (g1_is_graph != g2_is_graph or - self.allows_multiple_edges() != other.allows_multiple_edges() or - self.allows_loops() != other.allows_loops() or - self.order() != other.order() or - self.size() != other.size() or - self.weighted() != other.weighted()): + if g1_is_graph != g2_is_graph or self.allows_multiple_edges() != other.allows_multiple_edges() or self.allows_loops() != other.allows_loops() or self.order() != other.order() or self.size() != other.size() or self.weighted() != other.weighted(): return False return self._backend.is_subgraph(other._backend, self, ignore_labels=not self.weighted()) @@ -759,12 +754,10 @@ def __hash__(self): edge_items = self.edge_iterator(labels=use_labels) if self.allows_multiple_edges(): from collections import Counter + edge_items = Counter(edge_items).items() - return hash((frozenset(self.vertex_iterator()), - self._weighted, - frozenset(edge_items))) - raise TypeError("This graph is mutable, and thus not hashable. " - "Create an immutable copy by `g.copy(immutable=True)`") + return hash((frozenset(self.vertex_iterator()), self._weighted, frozenset(edge_items))) + raise TypeError("This graph is mutable, and thus not hashable. " "Create an immutable copy by `g.copy(immutable=True)`") def __mul__(self, n): r""" @@ -799,14 +792,8 @@ def __mul__(self, n): ns = self.order() ntot = n * ns vint = {u: i for i, u in enumerate(self)} - edges = ((i, j, l) for u, v, l in self.edge_iterator() - for i, j in zip(range(vint[u], ntot, ns), - range(vint[v], ntot, ns))) - return self.__class__([range(ntot), edges], format='vertices_and_edges', - loops=self.allows_loops(), - multiedges=self.allows_multiple_edges(), - immutable=self.is_immutable(), - name=f"Disjoint union of {n} copies of {str(self)}") + edges = ((i, j, l) for u, v, l in self.edge_iterator() for i, j in zip(range(vint[u], ntot, ns), range(vint[v], ntot, ns))) + return self.__class__([range(ntot), edges], format='vertices_and_edges', loops=self.allows_loops(), multiedges=self.allows_multiple_edges(), immutable=self.is_immutable(), name=f"Disjoint union of {n} copies of {str(self)}") raise TypeError('multiplication of a graph and something other than an integer is not defined') def __ne__(self, other): @@ -830,7 +817,7 @@ def __ne__(self, other): sage: g2 is g False """ - return (not (self == other)) + return not (self == other) def __rmul__(self, n): """ @@ -904,6 +891,7 @@ def _bit_vector(self): def bit(x, y): return x * n + y + else: total_length = (n * (n - 1)) // 2 @@ -969,15 +957,12 @@ def _latex_(self): \end{tikzpicture} """ from sage.graphs.graph_latex import setup_latex_preamble + setup_latex_preamble() return self.latex_options().latex() - def tikz(self, format=None, edge_labels=None, - color_by_label=False, prog='dot', rankdir='down', - standalone_config=None, usepackage=None, - usetikzlibrary=None, macros=None, - use_sage_preamble=None, **kwds): + def tikz(self, format=None, edge_labels=None, color_by_label=False, prog='dot', rankdir='down', standalone_config=None, usepackage=None, usetikzlibrary=None, macros=None, use_sage_preamble=None, **kwds): r""" Return a TikzPicture of the graph. @@ -1119,6 +1104,7 @@ def tikz(self, format=None, edge_labels=None, # use format dot2tex by default if format is None: from sage.features import PythonModule + if PythonModule("dot2tex").is_present(): format = 'dot2tex' else: @@ -1133,10 +1119,7 @@ def tikz(self, format=None, edge_labels=None, elif format == 'dot2tex': edge_labels = True - self.latex_options().set_options(format=format, - edge_labels=edge_labels, - color_by_label=color_by_label, - prog=prog, rankdir=rankdir, **kwds) + self.latex_options().set_options(format=format, edge_labels=edge_labels, color_by_label=color_by_label, prog=prog, rankdir=rankdir, **kwds) # by default use sage preamble only for format tkz_graph # because content generated by tkz_graph depends on it @@ -1150,12 +1133,8 @@ def tikz(self, format=None, edge_labels=None, standalone_config = ["border=4mm"] from sage.misc.latex_standalone import TikzPicture - return TikzPicture(self._latex_(), - standalone_config=standalone_config, - usepackage=usepackage, - usetikzlibrary=usetikzlibrary, - macros=macros, - use_sage_preamble=use_sage_preamble) + + return TikzPicture(self._latex_(), standalone_config=standalone_config, usepackage=usepackage, usetikzlibrary=usetikzlibrary, macros=macros, use_sage_preamble=use_sage_preamble) def _matrix_(self, R=None, vertices=None): """ @@ -1524,8 +1503,7 @@ def copy(self, weighted=None, data_structure=None, sparse=None, immutable=None, # data_structure is already defined so there is nothing left to do # here ! Did the user try to define too much ? if immutable is not None or sparse is not None: - raise ValueError("you cannot define 'immutable' or 'sparse' " - "when 'data_structure' has a value") + raise ValueError("you cannot define 'immutable' or 'sparse' " "when 'data_structure' has a value") # At this point : # - data_structure is None. elif immutable is True: @@ -1545,24 +1523,21 @@ def copy(self, weighted=None, data_structure=None, sparse=None, immutable=None, # Immutable copy of an immutable graph ? return self ! # (if okay for weightedness) - if (self.is_immutable() and - (weighted is None or self._weighted == weighted) and - (hash_labels is None or self._hash_labels == hash_labels)): + if self.is_immutable() and (weighted is None or self._weighted == weighted) and (hash_labels is None or self._hash_labels == hash_labels): from sage.graphs.base.static_sparse_backend import StaticSparseBackend - if (isinstance(self._backend, StaticSparseBackend) and - (data_structure == 'static_sparse' or data_structure is None)): + + if isinstance(self._backend, StaticSparseBackend) and (data_structure == 'static_sparse' or data_structure is None): return self if data_structure is None: from sage.graphs.base.dense_graph import DenseGraphBackend + if isinstance(self._backend, DenseGraphBackend): data_structure = "dense" else: data_structure = "sparse" - G = self.__class__(self, name=self.name(), pos=copy(self._pos), - weighted=weighted, hash_labels=hash_labels, - data_structure=data_structure) + G = self.__class__(self, name=self.name(), pos=copy(self._pos), weighted=weighted, hash_labels=hash_labels, data_structure=data_structure) # Copy attributes '_assoc' and '_embedding' if set G._copy_attribute_from(self, '_assoc') @@ -1661,17 +1636,10 @@ def export_to_file(self, filename, format=None, **kwds): """ import networkx - formats = {"adjlist": networkx.write_adjlist, - "dot": networkx.drawing.nx_pydot.write_dot, - "edgelist": networkx.write_edgelist, - "gexf": networkx.write_gexf, - "gml": networkx.write_gml, - "graphml": networkx.write_graphml, - "multiline_adjlist": networkx.write_multiline_adjlist, - "pajek": networkx.write_pajek} + formats = {"adjlist": networkx.write_adjlist, "dot": networkx.drawing.nx_pydot.write_dot, "edgelist": networkx.write_edgelist, "gexf": networkx.write_gexf, "gml": networkx.write_gml, "graphml": networkx.write_graphml, "multiline_adjlist": networkx.write_multiline_adjlist, "pajek": networkx.write_pajek} if format is None: - ext = filename[1 + filename.rfind("."):] + ext = filename[1 + filename.rfind(".") :] if ext not in formats: raise RuntimeError("the file format could not be guessed from '{}'".format(filename)) format = ext @@ -1758,10 +1726,7 @@ def _scream_if_not_simple(self, allow_loops=False, allow_multiple_edges=False): elif pb_with_multiple_edges: name = "multiedges" functions = "allow_multiple_edges()" - msg = ("This method is not known to work on graphs with " + name + ". " - "Perhaps this method can be updated to handle them, but in the " + - "meantime if you want to use it please disallow " + name + " using " + - functions + ".") + msg = "This method is not known to work on graphs with " + name + ". " "Perhaps this method can be updated to handle them, but in the " + "meantime if you want to use it please disallow " + name + " using " + functions + "." raise ValueError(msg) def _scream_if_immutable(self, message=None): @@ -1835,6 +1800,7 @@ def networkx_graph(self, weight_function=None): if weight_function is not None: self._check_weight_function(weight_function) import networkx + if self._directed and self.allows_multiple_edges(): class_type = networkx.MultiDiGraph elif self._directed: @@ -1843,10 +1809,10 @@ def networkx_graph(self, weight_function=None): class_type = networkx.MultiGraph else: class_type = networkx.Graph - N = class_type(selfloops=self.allows_loops(), multiedges=self.allows_multiple_edges(), - name=self.name()) + N = class_type(selfloops=self.allows_loops(), multiedges=self.allows_multiple_edges(), name=self.name()) N.add_nodes_from(self) from networkx import NetworkXError + for u, v, l in self.edge_iterator(): if weight_function is not None: N.add_edge(u, v, weight=weight_function((u, v, l))) @@ -2027,8 +1993,7 @@ def igraph_graph(self, vertex_list=None, vertex_attrs={}, edge_attrs={}): """ if vertex_list is None: vertex_list = self - elif (len(vertex_list) != self.order() or - set(vertex_list) != set(self)): + elif len(vertex_list) != self.order() or set(vertex_list) != set(self): raise ValueError("parameter vertex_list must be a permutation of the vertices") v_to_int = {v: i for i, v in enumerate(vertex_list)} @@ -2036,11 +2001,8 @@ def igraph_graph(self, vertex_list=None, vertex_attrs={}, edge_attrs={}): igraph_feature().require() import igraph - return igraph.Graph(n=self.n_vertices(), - edges=edges, - directed=self.is_directed(), - vertex_attrs=vertex_attrs, - edge_attrs=edge_attrs) + + return igraph.Graph(n=self.n_vertices(), edges=edges, directed=self.is_directed(), vertex_attrs=vertex_attrs, edge_attrs=edge_attrs) def to_dictionary(self, edge_labels=False, multiple_edges=False): r""" @@ -2259,10 +2221,8 @@ def _vertex_indices_and_keys(self, vertices=None, *, sort=None): try: vertices = self.vertices(sort=sort if sort is not None else True) except TypeError: - raise TypeError("Vertex labels are not comparable. You must " - "specify an ordering using parameter 'vertices'") - elif (len(vertices) != n or - set(vertices) != set(self.vertex_iterator())): + raise TypeError("Vertex labels are not comparable. You must " "specify an ordering using parameter 'vertices'") + elif len(vertices) != n or set(vertices) != set(self.vertex_iterator()): raise ValueError("parameter 'vertices' must be a permutation of the vertices") return {v: i for i, v in enumerate(vertices)}, keys @@ -2464,6 +2424,7 @@ def adjacency_matrix(self, sparse=None, vertices=None, *, base_ring=None, **kwds if not directed and i != j: D[j, i] = 1 from sage.matrix.constructor import matrix + if base_ring is None: base_ring = ZZ M = matrix(base_ring, n, n, D, sparse=sparse, **kwds) @@ -2471,8 +2432,7 @@ def adjacency_matrix(self, sparse=None, vertices=None, *, base_ring=None, **kwds am = adjacency_matrix # shorter call makes life easier - def incidence_matrix(self, oriented=None, sparse=True, vertices=None, edges=None, - *, base_ring=None, **kwds): + def incidence_matrix(self, oriented=None, sparse=True, vertices=None, edges=None, *, base_ring=None, **kwds): r""" Return the incidence matrix of the (di)graph. @@ -2709,14 +2669,17 @@ def incidence_matrix(self, oriented=None, sparse=True, vertices=None, edges=None i_edges = [(vertex_indices[e[0]], vertex_indices[e[1]]) for e in edges] s_edges = [(vertex_indices[u], vertex_indices[v]) for u, v in self.edge_iterator(labels=False)] else: + def reorder(u, v): return (u, v) if u <= v else (v, u) + i_edges = [reorder(vertex_indices[e[0]], vertex_indices[e[1]]) for e in edges] s_edges = [reorder(vertex_indices[u], vertex_indices[v]) for u, v in self.edge_iterator(labels=False)] if sorted(i_edges) != sorted(s_edges): raise ValueError("parameter edges must be a permutation of the edges") from sage.matrix.constructor import matrix + if base_ring is None: base_ring = ZZ immutable = kwds.pop('immutable', False) @@ -2841,14 +2804,12 @@ def distance_matrix(self, vertices=None, *, base_ring=None, **kwds): """ from sage.matrix.constructor import matrix - if ((self.is_directed() and not self.is_strongly_connected()) or - (not self.is_directed() and not self.is_connected())): + if (self.is_directed() and not self.is_strongly_connected()) or (not self.is_directed() and not self.is_connected()): raise ValueError("input (di)graph must be (strongly) connected") if vertices is None: vertices = self.vertices(sort=True) - elif (len(vertices) != self.order() or - set(vertices) != set(self.vertex_iterator())): + elif len(vertices) != self.order() or set(vertices) != set(self.vertex_iterator()): raise ValueError("parameter vertices must be a permutation of the vertices") # We extract from **kwds the arguments for distance_all_pairs @@ -2881,8 +2842,7 @@ def distance_matrix(self, vertices=None, *, base_ring=None, **kwds): ret.set_immutable() return ret - def weighted_adjacency_matrix(self, sparse=True, vertices=None, - default_weight=None, *, base_ring=None, **kwds): + def weighted_adjacency_matrix(self, sparse=True, vertices=None, default_weight=None, *, base_ring=None, **kwds): """ Return the weighted adjacency matrix of the graph. @@ -3009,12 +2969,14 @@ def weighted_adjacency_matrix(self, sparse=True, vertices=None, # Method for checking edge weights and setting default weight if default_weight is None: + def func(u, v, label): if label is None: - raise ValueError(f"cannot find the weight of ({u}, {v}, None). " - "Consider setting parameter 'default_weight'") + raise ValueError(f"cannot find the weight of ({u}, {v}, None). " "Consider setting parameter 'default_weight'") return label + else: + def func(u, v, label): if label is None: return default_weight @@ -3035,6 +2997,7 @@ def func(u, v, label): D[j, i] = label from sage.matrix.constructor import matrix + if base_ring is None: M = matrix(self.n_vertices(), D, sparse=sparse, **kwds) else: @@ -3246,8 +3209,8 @@ def kirchhoff_matrix(self, weighted=None, indegree=True, normalized=False, signl if normalized: from sage.misc.functional import sqrt - Dsqrt = diagonal_matrix([1 / sqrt(D[i, i]) if D[i, i] else 1 - for i in range(D.nrows())]) + + Dsqrt = diagonal_matrix([1 / sqrt(D[i, i]) if D[i, i] else 1 for i in range(D.nrows())]) if signless: ret = Dsqrt * (D + M) * Dsqrt else: @@ -3462,36 +3425,31 @@ def _check_embedding_validity(self, embedding=None, boolean=True): if boolean: return False if set(embedding).difference(self): - raise ValueError("vertices in {} from the embedding do not " - "belong to the graph".format(list(set(embedding).difference(self)))) + raise ValueError("vertices in {} from the embedding do not " "belong to the graph".format(list(set(embedding).difference(self)))) else: - raise ValueError("vertices in {} have no corresponding entry " - "in the embedding".format(list(set(self).difference(embedding)))) + raise ValueError("vertices in {} have no corresponding entry " "in the embedding".format(list(set(self).difference(embedding)))) if self._directed: + def connected(u, v): return self.has_edge(u, v) or self.has_edge(v, u) + else: connected = self.has_edge for v in embedding: if len(embedding[v]) != self.degree(v): if boolean: return False - raise ValueError("the list associated with vertex {} has " - "length {} but d({})={}".format(v, len(embedding[v]), - v, self.degree(v))) + raise ValueError("the list associated with vertex {} has " "length {} but d({})={}".format(v, len(embedding[v]), v, self.degree(v))) if len(embedding[v]) != len(set(embedding[v])): if boolean: return False - raise ValueError("the list associated with vertex {} contains >1 " - "occurrences of {}".format(v, [x for x in set(embedding[v]) - if embedding[v].count(x) > 1])) + raise ValueError("the list associated with vertex {} contains >1 " "occurrences of {}".format(v, [x for x in set(embedding[v]) if embedding[v].count(x) > 1])) for u in embedding[v]: if not connected(v, u): if boolean: return False - raise ValueError("{} and {} are not neighbors but {} is in " - "the list associated with {}".format(u, v, u, v)) + raise ValueError("{} and {} are not neighbors but {} is in " "the list associated with {}".format(u, v, u, v)) return True def has_loops(self) -> bool: @@ -4554,13 +4512,13 @@ def density(self): if not n: return Rational(0) if self._directed: - return Rational(self.size()) / Rational(n ** 2) - return Rational(self.size()) / Rational((n ** 2 + n) / 2) + return Rational(self.size()) / Rational(n**2) + return Rational(self.size()) / Rational((n**2 + n) / 2) if n < 2: return Rational(0) if self._directed: - return Rational(self.size()) / Rational(n ** 2 - n) - return Rational(self.size()) / Rational((n ** 2 - n) / 2) + return Rational(self.size()) / Rational(n**2 - n) + return Rational(self.size()) / Rational((n**2 - n) / 2) def is_bipartite(self, certificate=False): r""" @@ -4993,13 +4951,7 @@ def eulerian_circuit(self, return_vertices=False, labels=True, path=False): return edges, vertices return edges - def min_spanning_tree(self, - weight_function=None, - algorithm='Prim_Boost', - starting_vertex=None, - check=False, - by_weight=False, - check_weight=True): + def min_spanning_tree(self, weight_function=None, algorithm='Prim_Boost', starting_vertex=None, check=False, by_weight=False, check_weight=True): r""" Return the edges of a minimum spanning tree. @@ -5249,9 +5201,7 @@ def min_spanning_tree(self, if self.weighted(): by_weight = True - by_weight, weight_function = self._get_weight_function(by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight) + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, weight_function=weight_function, check_weight=check_weight) def wfunction_float(e): return float(weight_function(e)) @@ -5264,17 +5214,19 @@ def wfunction_float(e): if algorithm == "Kruskal": from .spanning_tree import kruskal + return kruskal(g, weight_function=wfunction_float, check_weight=False, check=check) if algorithm == "Filter_Kruskal": from .spanning_tree import filter_kruskal + return filter_kruskal(g, weight_function=wfunction_float, check_weight=False, check=check) if algorithm == "Boruvka": from .spanning_tree import boruvka + return boruvka(g, weight_function=wfunction_float, check_weight=False, check=check) from sage.graphs.base.boost_graph import min_spanning_tree - return min_spanning_tree(g, - weight_function=wfunction_float, - algorithm=algorithm.split("_")[0]) + + return min_spanning_tree(g, weight_function=wfunction_float, algorithm=algorithm.split("_")[0]) if algorithm == "Prim_fringe": if starting_vertex is None: @@ -5345,10 +5297,10 @@ def cmp_fun(x): if algorithm == "NetworkX": import networkx + G = networkx.Graph([(e[0], e[1], {'weight': wfunction_float(e)}) for e in self.edge_iterator()]) E = networkx.minimum_spanning_edges(G, data=False) - return [(u, v, self.edge_label(u, v)) if hash(u) < hash(v) else (v, u, self.edge_label(u, v)) - for u, v in E] + return [(u, v, self.edge_label(u, v)) if hash(u) < hash(v) else (v, u, self.edge_label(u, v)) for u, v in E] raise NotImplementedError("minimum spanning tree algorithm '%s' is not implemented" % algorithm) def number_of_spanning_trees(self, root_vertex=None): @@ -5600,11 +5552,10 @@ def cycle_basis(self, output='vertex'): if self.allows_multiple_edges(): if not self.is_connected(): - return sum([g.cycle_basis(output=output) - for g in self.connected_components_subgraphs()], - []) + return sum([g.cycle_basis(output=output) for g in self.connected_components_subgraphs()], []) from sage.graphs.graph import Graph + T = Graph(self.min_spanning_tree(), multiedges=True, format='list_of_edges') H = self.copy(immutable=False) H.delete_edges(T.edge_iterator()) @@ -5628,20 +5579,20 @@ def cycle_basis(self, output='vertex'): cycle = Q + P[-2::-1] if output == 'edge': - cycle = [e] + [(x, y, T.edge_label(x, y)[0]) - for x, y in zip(cycle[:-1], cycle[1:])] + cycle = [e] + [(x, y, T.edge_label(x, y)[0]) for x, y in zip(cycle[:-1], cycle[1:])] L.append(cycle) return L # second case: there are no multiple edges import networkx + cycle_basis_v = networkx.cycle_basis(self.networkx_graph()) if output == 'vertex': return cycle_basis_v def vertices_to_edges(x): - return [(u[0], u[1], self.edge_label(u[0], u[1])) - for u in zip(x, x[1:] + [x[0]])] + return [(u[0], u[1], self.edge_label(u[0], u[1])) for u in zip(x, x[1:] + [x[0]])] + return [vertices_to_edges(_) for _ in cycle_basis_v] def minimum_cycle_basis(self, algorithm=None, weight_function=None, by_weight=False, check_weight=True): @@ -5719,18 +5670,18 @@ def minimum_cycle_basis(self, algorithm=None, weight_function=None, by_weight=Fa raise NotImplementedError("not implemented for directed graphs") self._scream_if_not_simple() - by_weight, weight_function = self._get_weight_function(by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight) + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, weight_function=weight_function, check_weight=check_weight) if algorithm: algorithm = algorithm.lower() if algorithm == "networkx": import networkx + G = networkx.Graph([(e[0], e[1], {'weight': weight_function(e)}) for e in self.edge_iterator()]) return networkx.minimum_cycle_basis(G, weight='weight') if algorithm is None: from sage.graphs.base.boost_graph import min_cycle_basis + if self.is_connected(): CC = [self] else: @@ -5738,15 +5689,13 @@ def minimum_cycle_basis(self, algorithm=None, weight_function=None, by_weight=Fa basis = [] for comp in CC: # calling Cython implementation from backend - basis.append(min_cycle_basis(comp, weight_function=weight_function, - by_weight=by_weight)) + basis.append(min_cycle_basis(comp, weight_function=weight_function, by_weight=by_weight)) return sum(basis, []) raise NotImplementedError("only 'NetworkX' and Cython implementation is supported") # Planarity - def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, - set_pos=False, immutable=None): + def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, set_pos=False, immutable=None): r""" Check whether the graph is planar. @@ -5982,9 +5931,7 @@ def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, False """ # Quick check first - if (on_embedding is None and not kuratowski and not set_embedding and not set_pos - and not self.allows_loops() and not self.allows_multiple_edges() - and not self.is_directed()): + if on_embedding is None and not kuratowski and not set_embedding and not set_pos and not self.allows_loops() and not self.allows_multiple_edges() and not self.is_directed(): if self.order() > 4 and self.size() > 3 * self.order() - 6: return False @@ -5994,20 +5941,19 @@ def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, # of opposite arcs if self.has_multiple_edges() or self.has_loops(): raise NotImplementedError("cannot compute with embeddings of multiple-edged or looped graphs") - elif (self.is_directed() and - any(self.has_edge(v, u) for u, v in self.edge_iterator(labels=False))): + elif self.is_directed() and any(self.has_edge(v, u) for u, v in self.edge_iterator(labels=False)): raise NotImplementedError("cannot compute with embeddings of digraphs with pairs of opposite arcs") if on_embedding is not None: self._check_embedding_validity(on_embedding, boolean=False) - return (0 == self.genus(minimal=False, set_embedding=False, on_embedding=on_embedding)) + return 0 == self.genus(minimal=False, set_embedding=False, on_embedding=on_embedding) # We take the underlying undirected and simple graph G = self.to_simple(to_undirected=True) # And check if it is planar from sage.graphs.planarity import is_planar - planar = is_planar(G, kuratowski=kuratowski, set_pos=set_pos, - set_embedding=set_embedding, immutable=immutable) + + planar = is_planar(G, kuratowski=kuratowski, set_pos=set_pos, set_embedding=set_embedding, immutable=immutable) if kuratowski: bool_result = planar[0] else: @@ -6019,9 +5965,7 @@ def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, self._embedding = G._embedding return planar - def is_circular_planar(self, on_embedding=None, kuratowski=False, - set_embedding=True, boundary=None, - ordered=False, set_pos=False): + def is_circular_planar(self, on_embedding=None, kuratowski=False, set_embedding=True, boundary=None, ordered=False, set_pos=False): r""" Check whether the graph is circular planar (outerplanar). @@ -6153,9 +6097,7 @@ def is_circular_planar(self, on_embedding=None, kuratowski=False, raise ValueError("boundary must be set when ordered is True") # Quick check first - if (on_embedding is None and not kuratowski and set_embedding and - boundary is None and not ordered and not set_pos and - not self.allows_loops() and not self.allows_multiple_edges()): + if on_embedding is None and not kuratowski and set_embedding and boundary is None and not ordered and not set_pos and not self.allows_loops() and not self.allows_multiple_edges(): if self.order() > 3 and self.size() > 2 * self.order() - 3: return False @@ -6171,6 +6113,7 @@ def is_circular_planar(self, on_embedding=None, kuratowski=False, # A local copy of self from sage.graphs.graph import Graph from sage.graphs.planarity import is_planar + graph = Graph(self) if hasattr(graph, '_embedding'): del graph._embedding @@ -6219,9 +6162,7 @@ def is_circular_planar(self, on_embedding=None, kuratowski=False, return result - def layout_planar(self, set_embedding=False, on_embedding=None, - external_face=None, test=False, circular=False, - **options): + def layout_planar(self, set_embedding=False, on_embedding=None, external_face=None, test=False, circular=False, **options): """ Compute a planar layout of the graph using Schnyder's algorithm. @@ -6400,16 +6341,9 @@ def layout_planar(self, set_embedding=False, on_embedding=None, if not self.is_connected(): if external_face: - raise NotImplementedError('cannot fix the external face for a' - 'disconnected graph') + raise NotImplementedError('cannot fix the external face for a' 'disconnected graph') # Compute the layout component by component - pos = layout_split(G.__class__.layout_planar, - G, - set_embedding=set_embedding, - on_embedding=on_embedding, - external_face=None, - test=test, - **options) + pos = layout_split(G.__class__.layout_planar, G, set_embedding=set_embedding, on_embedding=on_embedding, external_face=None, test=test, **options) if set_embedding: self.set_embedding(G.get_embedding()) return pos @@ -6428,27 +6362,21 @@ def layout_planar(self, set_embedding=False, on_embedding=None, elif on_embedding is not None: G._check_embedding_validity(on_embedding, boolean=False) if not G.is_planar(on_embedding=on_embedding): - raise ValueError('provided embedding is not a planar ' - 'embedding for %s' % self) + raise ValueError('provided embedding is not a planar ' 'embedding for %s' % self) G.set_embedding(on_embedding) elif hasattr(G, '_embedding'): if G._check_embedding_validity(): if not G.is_planar(on_embedding=G._embedding): - raise ValueError('%s has nonplanar _embedding attribute. ' - 'Try putting set_embedding=True' % self) + raise ValueError('%s has nonplanar _embedding attribute. ' 'Try putting set_embedding=True' % self) embedding_copy = {v: neighbors[:] for v, neighbors in G._embedding.items()} else: - raise ValueError('provided embedding is not a valid ' - 'embedding for %s. Try putting ' - 'set_embedding=True' % self) + raise ValueError('provided embedding is not a valid ' 'embedding for %s. Try putting ' 'set_embedding=True' % self) elif not G.is_planar(set_embedding=True): raise ValueError('%s is not a planar graph' % self) if external_face: if not self.has_edge(external_face): - raise ValueError('{} is not an edge of {} but has been ' - 'provided as an edge of the external face' - ''.format(external_face, self)) + raise ValueError('{} is not an edge of {} but has been ' 'provided as an edge of the external face' ''.format(external_face, self)) _triangulate(G, G._embedding) @@ -6456,8 +6384,7 @@ def layout_planar(self, set_embedding=False, on_embedding=None, if test: if G._check_embedding_validity(): if not G.is_planar(on_embedding=G._embedding): - raise ValueError('%s has nonplanar _embedding attribute. ' - 'Try putting set_embedding=True' % self) + raise ValueError('%s has nonplanar _embedding attribute. ' 'Try putting set_embedding=True' % self) test_faces = G.faces(G._embedding) for face in test_faces: if len(face) != 3: @@ -6818,6 +6745,7 @@ def crossing_number(self): sage: g.crossing_number() 1 """ + def _crossing_number(G): """ Return the crossing number of a biconnected non-planar graph ``G``. @@ -6835,8 +6763,7 @@ def _crossing_number(G): G.delete_vertex(v) edgepairs = Subsets(G.edge_iterator(labels=False), 2) - edgepairs = [x for x in edgepairs if x[0][0] not in [x[1][0], x[1][1]] and - x[0][1] not in [x[1][0], x[1][1]]] + edgepairs = [x for x in edgepairs if x[0][0] not in [x[1][0], x[1][1]] and x[0][1] not in [x[1][0], x[1][1]]] k = 1 while True: @@ -7176,6 +7103,7 @@ def planar_dual(self, embedding=None): from itertools import combinations from sage.graphs.graph import Graph + verts = [tuple(f) for f in self.faces(embedding=embedding)] edges = [] for v1, v2 in combinations(verts, 2): @@ -7187,8 +7115,7 @@ def planar_dual(self, embedding=None): # Connectivity - def steiner_tree(self, vertices, weighted=False, solver=None, verbose=0, - *, integrality_tolerance=1e-3): + def steiner_tree(self, vertices, weighted=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a tree of minimum weight connecting the given set of vertices. @@ -7277,6 +7204,7 @@ def steiner_tree(self, vertices, weighted=False, solver=None, verbose=0, if self.is_directed(): from sage.graphs.graph import Graph + g = Graph(self) else: g = self @@ -7286,9 +7214,8 @@ def steiner_tree(self, vertices, weighted=False, solver=None, verbose=0, cc = g.connected_component_containing_vertex(vertices[0], sort=False) if any(v not in cc for v in vertices): from sage.categories.sets_cat import EmptySetError - raise EmptySetError("the given vertices do not all belong to the " - "same connected component. This problem has " - "no solution !") + + raise EmptySetError("the given vertices do not all belong to the " "same connected component. This problem has " "no solution !") # Can it be solved using the min spanning tree algorithm ? if not weighted: @@ -7300,6 +7227,7 @@ def steiner_tree(self, vertices, weighted=False, solver=None, verbose=0, # Then, LP formulation from sage.numerical.mip import MixedIntegerLinearProgram + p = MixedIntegerLinearProgram(maximization=False, solver=solver) # edges used in the Steiner Tree @@ -7319,8 +7247,7 @@ def steiner_tree(self, vertices, weighted=False, solver=None, verbose=0, p.add_constraint(p.sum(edges[frozenset(e)] for e in g.edges_incident(v, labels=False)), min=1) # The number of edges is equal to the number of vertices in our tree minus 1 - p.add_constraint(p.sum(vertex[v] for v in g) - - p.sum(edges[frozenset(e)] for e in g.edge_iterator(labels=False)), max=1, min=1) + p.add_constraint(p.sum(vertex[v] for v in g) - p.sum(edges[frozenset(e)] for e in g.edge_iterator(labels=False)), max=1, min=1) # There are no cycles in our graph @@ -7333,8 +7260,7 @@ def steiner_tree(self, vertices, weighted=False, solver=None, verbose=0, # Objective if weighted: - p.set_objective(p.sum((l if l is not None else 1) * edges[frozenset((u, v))] - for u, v, l in g.edge_iterator())) + p.set_objective(p.sum((l if l is not None else 1) * edges[frozenset((u, v))] for u, v, l in g.edge_iterator())) else: p.set_objective(p.sum(edges[frozenset(e)] for e in g.edge_iterator(labels=False))) @@ -7342,13 +7268,11 @@ def steiner_tree(self, vertices, weighted=False, solver=None, verbose=0, edges = p.get_values(edges, convert=bool, tolerance=integrality_tolerance) - st = g.subgraph(edges=[e for e in g.edge_iterator(labels=False) if edges[frozenset(e)]], - immutable=False) + st = g.subgraph(edges=[e for e in g.edge_iterator(labels=False) if edges[frozenset(e)]], immutable=False) st.delete_vertices(v for v in g if not st.degree(v)) return st - def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None, verbose=0, - *, integrality_tolerance=1e-3): + def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return the desired number of edge-disjoint spanning trees/arborescences. @@ -7525,10 +7449,10 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None raise ValueError('algorithm must be None or "MILP" for directed graphs') elif algorithm is None or algorithm == "Roskind-Tarjan": from sage.graphs.spanning_tree import edge_disjoint_spanning_trees + return edge_disjoint_spanning_trees(self, k) elif algorithm != "MILP": - raise ValueError('algorithm must be None, "Rosking-Tarjan" or "MILP" ' - 'for undirected graphs') + raise ValueError('algorithm must be None, "Rosking-Tarjan" or "MILP" ' 'for undirected graphs') G = self n = G.order() @@ -7542,8 +7466,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None if k == 1: E = G.min_spanning_tree(starting_vertex=root) if not E: - raise EmptySetError("this graph does not contain the required " - "number of trees/arborescences") + raise EmptySetError("this graph does not contain the required " "number of trees/arborescences") return [DiGraph(E) if G.is_directed() else Graph(E)] D = G if G.is_directed() else DiGraph(G) @@ -7581,17 +7504,14 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None # A vertex has at least one incident edge for u in D: - p.add_constraint(p.sum(edge[e, c] for e in D.incoming_edge_iterator(u, labels=False)) - + p.sum(edge[e, c] for e in D.outgoing_edge_iterator(u, labels=False)) - >= 1) + p.add_constraint(p.sum(edge[e, c] for e in D.incoming_edge_iterator(u, labels=False)) + p.sum(edge[e, c] for e in D.outgoing_edge_iterator(u, labels=False)) >= 1) # We use the Miller-Tucker-Zemlin subtour elimination constraints # combined with the Desrosiers-Langevin strengthening constraints for u, v in D.edge_iterator(labels=False): if D.has_edge(v, u): # DL - p.add_constraint(pos[u, c] + (n - 1)*edge[(u, v), c] + (n - 3)*edge[(v, u), c] - <= pos[v, c] + n - 2) + p.add_constraint(pos[u, c] + (n - 1) * edge[(u, v), c] + (n - 3) * edge[(v, u), c] <= pos[v, c] + n - 2) else: # MTZ: If edge uv is selected, v is after u in the partial ordering p.add_constraint(pos[u, c] + 1 - n * (1 - edge[(u, v), c]) <= pos[v, c]) @@ -7605,6 +7525,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None # We now solve this program and extract the solution from sage.numerical.backends.glpk_backend import GLPKBackend + if isinstance(p.get_backend(), GLPKBackend): # The MIP approach with GLPK is prone to compiler and # optimization-level weirdness on some hardware: @@ -7636,8 +7557,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None return classes - def edge_cut(self, s, t, value_only=True, use_edge_labels=False, vertices=False, - algorithm='FF', solver=None, verbose=0, *, integrality_tolerance=1e-3): + def edge_cut(self, s, t, value_only=True, use_edge_labels=False, vertices=False, algorithm='FF', solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a minimum edge cut between vertices `s` and `t`. @@ -7790,9 +7710,12 @@ def edge_cut(self, s, t, value_only=True, use_edge_labels=False, vertices=False, value_only = False if use_edge_labels: + def weight(x): return x if (x != {} and x is not None) else 1 + else: + def weight(x): return 1 @@ -7801,14 +7724,14 @@ def weight(x): return self.flow(s, t, value_only=value_only, use_edge_labels=use_edge_labels, algorithm=algorithm) from sage.graphs.digraph import DiGraph + g = DiGraph(self) flow_value, flow_graph = self.flow(s, t, value_only=value_only, use_edge_labels=use_edge_labels, algorithm=algorithm) for u, v, l in flow_graph.edge_iterator(): g.add_edge(v, u) - if (not use_edge_labels or - weight(g.edge_label(u, v)) == weight(l)): + if not use_edge_labels or weight(g.edge_label(u, v)) == weight(l): g.delete_edge(u, v) return_value = [flow_value] @@ -7823,10 +7746,10 @@ def weight(x): return return_value if algorithm != "LP": - raise ValueError("the algorithm argument has to be equal to \"FF\", " + - "\"LP\", \"igraph\", or None") + raise ValueError("the algorithm argument has to be equal to \"FF\", " + "\"LP\", \"igraph\", or None") from sage.numerical.mip import MixedIntegerLinearProgram + g = self p = MixedIntegerLinearProgram(maximization=False, solver=solver) b = p.new_variable(binary=True) @@ -7835,9 +7758,12 @@ def weight(x): # Helper function to ensure that we use arcs when g is directed and # frozensets otherwise if g.is_directed(): + def good_edge(e): return (e[0], e[1]) + else: + def good_edge(e): return frozenset((e[0], e[1])) @@ -7889,8 +7815,7 @@ def good_edge(e): answer.append([l0, l1]) return tuple(answer) - def vertex_cut(self, s, t, value_only=True, vertices=False, solver=None, verbose=0, - *, integrality_tolerance=1e-3): + def vertex_cut(self, s, t, value_only=True, vertices=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a minimum vertex cut between non-adjacent vertices `s` and `t` represented by a list of vertices. @@ -7957,9 +7882,11 @@ def vertex_cut(self, s, t, value_only=True, vertices=False, solver=None, verbose True """ from sage.numerical.mip import MixedIntegerLinearProgram + g = self if g.has_edge(s, t): from sage.categories.sets_cat import EmptySetError + raise EmptySetError("there can be no vertex cut between adjacent vertices") if vertices: value_only = False @@ -8013,8 +7940,7 @@ def vertex_cut(self, s, t, value_only=True, vertices=False, solver=None, verbose answer.append([l0, l1]) return tuple(answer) - def multiway_cut(self, vertices, value_only=False, use_edge_labels=False, - solver=None, verbose=0, *, integrality_tolerance=1e-3): + def multiway_cut(self, vertices, value_only=False, use_edge_labels=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a minimum edge multiway cut. @@ -8106,16 +8032,21 @@ def multiway_cut(self, vertices, value_only=False, use_edge_labels=False, # Helper function to correctly index variables cut if self.is_directed(): + def good_edge(e): return e + else: good_edge = frozenset # Weight function if use_edge_labels: + def weight(l): return l if l is not None else 1 + else: + def weight(l): return 1 @@ -8156,8 +8087,7 @@ def weight(l): return [e for e in self.edge_iterator() if cut[good_edge((e[0], e[1]))]] - def max_cut(self, value_only=True, use_edge_labels=False, vertices=False, - solver=None, verbose=0, *, integrality_tolerance=1e-3): + def max_cut(self, value_only=True, use_edge_labels=False, vertices=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a maximum edge cut of the graph. @@ -8234,13 +8164,17 @@ def max_cut(self, value_only=True, use_edge_labels=False, vertices=False, def weight(x): return x if x in RR else 1 + else: + def weight(x): return 1 if g.is_directed(): + def good_edge(e): return e + else: good_edge = frozenset @@ -8307,9 +8241,7 @@ def good_edge(e): return val - def longest_cycle(self, induced=False, use_edge_labels=False, - immutable=None, - solver=None, verbose=0, *, integrality_tolerance=0.001): + def longest_cycle(self, induced=False, use_edge_labels=False, immutable=None, solver=None, verbose=0, *, integrality_tolerance=0.001): r""" Return the longest (induced) cycle of ``self``. @@ -8491,12 +8423,15 @@ def longest_cycle(self, induced=False, use_edge_labels=False, # Helper functions to manipulate weights if use_edge_labels: + def weight(e): return 1 if (len(e) < 3 or e[2] is None) else e[2] def total_weight(gg): return sum(weight(e) for e in gg.edge_iterator()) + else: + def weight(e): return 1 @@ -8508,9 +8443,11 @@ def total_weight(gg): immutable = G.is_immutable() if directed: from sage.graphs.digraph import DiGraph as MyGraph + blocks = G.strongly_connected_components() else: from sage.graphs.graph import Graph as MyGraph + blocks = G.blocks_and_cut_vertices()[0] # Deal with graphs with multiple biconnected components @@ -8521,11 +8458,7 @@ def total_weight(gg): if induced and len(block) < 4: continue h = G.subgraph(vertices=block) - C = h.longest_cycle(induced=induced, - use_edge_labels=use_edge_labels, - immutable=immutable, - solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + C = h.longest_cycle(induced=induced, use_edge_labels=use_edge_labels, immutable=immutable, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) if total_weight(C) > best_w: best = C best_w = total_weight(C) @@ -8534,14 +8467,11 @@ def total_weight(gg): # We now know that the graph is biconnected or that the digraph is # strongly connected. - if ((induced and G.order() < 4) or - (not induced and ((directed and G.order() < 2) or - (not directed and G.order() < 3)))): + if (induced and G.order() < 4) or (not induced and ((directed and G.order() < 2) or (not directed and G.order() < 3))): if use_edge_labels: return 0, MyGraph(name=name, immutable=immutable) return MyGraph(name=name, immutable=immutable) - if (not induced and ((directed and G.order() == 2) or - (not directed and G.order() == 3))): + if not induced and ((directed and G.order() == 2) or (not directed and G.order() == 3)): answer = MyGraph(G, immutable=immutable, name=name) if use_edge_labels: return total_weight(answer), answer @@ -8549,17 +8479,18 @@ def total_weight(gg): # Helper functions to index edges if directed: + def F(e): return e[:2] + else: + def F(e): return frozenset(e[:2]) from sage.numerical.mip import MIPSolverException, MixedIntegerLinearProgram - p = MixedIntegerLinearProgram(maximization=True, - solver=solver, - constraint_generation=True) + p = MixedIntegerLinearProgram(maximization=True, solver=solver, constraint_generation=True) # We need one binary variable per vertex and per edge vertex = p.new_variable(binary=True, name='vertex') @@ -8569,23 +8500,19 @@ def F(e): p.set_objective(p.sum(weight(e) * edge[F(e)] for e in G.edge_iterator())) # We select as many vertices as edges - p.add_constraint(p.sum(edge[F(e)] for e in G.edge_iterator()) - == p.sum(vertex[u] for u in G)) + p.add_constraint(p.sum(edge[F(e)] for e in G.edge_iterator()) == p.sum(vertex[u] for u in G)) if directed: # If a vertex is selected, one of its incoming (resp. outgoing) edge # must be selected, and none of them otherwise for u in G: - p.add_constraint(p.sum(edge[F(e)] for e in G.outgoing_edge_iterator(u)) - <= vertex[u]) - p.add_constraint(p.sum(edge[F(e)] for e in G.incoming_edge_iterator(u)) - <= vertex[u]) + p.add_constraint(p.sum(edge[F(e)] for e in G.outgoing_edge_iterator(u)) <= vertex[u]) + p.add_constraint(p.sum(edge[F(e)] for e in G.incoming_edge_iterator(u)) <= vertex[u]) else: # If a vertex is selected, two of its incident edges must be # selected, and none of them otherwise for u in G: - p.add_constraint(p.sum(edge[F(e)] for e in G.edge_iterator(u)) - <= 2 * vertex[u]) + p.add_constraint(p.sum(edge[F(e)] for e in G.edge_iterator(u)) <= 2 * vertex[u]) if induced: # An edge is selected if its end vertices are. @@ -8649,7 +8576,7 @@ def F(e): p.add_constraint(vertex[u] <= p.sum(edge[F(e)] for e in G.edge_boundary(cbar, c))) else: for u in c: - p.add_constraint(2*vertex[u] <= p.sum(edge[F(e)] for e in G.edge_boundary(c))) + p.add_constraint(2 * vertex[u] <= p.sum(edge[F(e)] for e in G.edge_boundary(c))) if induced: # We eliminate this cycle @@ -8660,9 +8587,7 @@ def F(e): best.set_pos({u: pp for u, pp in G.get_pos().items() if u in best}) return (best_w, best) if use_edge_labels else best - def longest_path(self, s=None, t=None, use_edge_labels=False, - algorithm='MILP', immutable=None, - solver=None, verbose=0, *, integrality_tolerance=1e-3): + def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm='MILP', immutable=None, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a longest path of ``self``. @@ -8889,8 +8814,7 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, raise ValueError("algorithm must be either 'heuristic' or 'MILP'") if algorithm == 'heuristic': if s is not None or t is not None or use_edge_labels: - raise ValueError("parameters s, t, and use_edge_labels can not " - "be used in combination with algorithm 'heuristic'") + raise ValueError("parameters s, t, and use_edge_labels can not " "be used in combination with algorithm 'heuristic'") if immutable is None: immutable = self.is_immutable() @@ -8898,17 +8822,9 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, # Quick improvement if not self.is_connected(): if use_edge_labels: - return max((g.longest_path(s=s, t=t, immutable=immutable, - use_edge_labels=use_edge_labels, - algorithm=algorithm) - for g in self.connected_components_subgraphs()), - key=lambda x: x[0]) - - return max((g.longest_path(s=s, t=t, immutable=immutable, - use_edge_labels=use_edge_labels, - algorithm=algorithm) - for g in self.connected_components_subgraphs()), - key=lambda x: x.order()) + return max((g.longest_path(s=s, t=t, immutable=immutable, use_edge_labels=use_edge_labels, algorithm=algorithm) for g in self.connected_components_subgraphs()), key=lambda x: x[0]) + + return max((g.longest_path(s=s, t=t, immutable=immutable, use_edge_labels=use_edge_labels, algorithm=algorithm) for g in self.connected_components_subgraphs()), key=lambda x: x.order()) # Stupid cases # - Graph having <= 1 vertex. @@ -8921,17 +8837,7 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, # # - Both s and t are specified, but there is no path between # the two in a directed graph (the graph is connected). - if (self.order() <= 1 or - (s is not None and ( - (s not in self) or - (self._directed and not self.out_degree(s)) or - (not self._directed and not self.degree(s)))) or - (t is not None and ( - (t not in self) or - (self._directed and not self.in_degree(t)) or - (not self._directed and not self.degree(t)))) or - (self._directed and (s is not None) and (t is not None) and - not self.shortest_path(s, t))): + if self.order() <= 1 or (s is not None and ((s not in self) or (self._directed and not self.out_degree(s)) or (not self._directed and not self.degree(s)))) or (t is not None and ((t not in self) or (self._directed and not self.in_degree(t)) or (not self._directed and not self.degree(t)))) or (self._directed and (s is not None) and (t is not None) and not self.shortest_path(s, t)): if self._directed: from sage.graphs.digraph import DiGraph as MyGraph else: @@ -8942,9 +8848,9 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, # Calling the heuristic if asked if algorithm == "heuristic": from sage.graphs.generic_graph_pyx import find_hamiltonian as fh + x = fh(self, find_path=True)[1] - return self.subgraph(vertices=x, edges=list(zip(x[:-1], x[1:])), - immutable=immutable) + return self.subgraph(vertices=x, edges=list(zip(x[:-1], x[1:])), immutable=immutable) ################## # LP Formulation # @@ -8956,13 +8862,17 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, # Associating a weight to a label if use_edge_labels: + def weight(x): return x if (x is not None and x != {}) else 1 + else: + def weight(x): return 1 from sage.numerical.mip import MixedIntegerLinearProgram + p = MixedIntegerLinearProgram(solver=solver) # edge_used[(u,v)] == 1 if (u,v) is used @@ -8988,9 +8898,7 @@ def weight(x): p.add_constraint(vertex_used[u] >= edge_used[u, v]) # A path is a tree. If n vertices are used, at most n-1 edges are - p.add_constraint(p.sum(vertex_used[v] for v in self) - - p.sum(edge_used[e] for e in self.edge_iterator(labels=False)) - == 1) + p.add_constraint(p.sum(vertex_used[v] for v in self) - p.sum(edge_used[e] for e in self.edge_iterator(labels=False)) == 1) # A vertex has at most one incoming used edge and at most # one outgoing used edge @@ -9001,33 +8909,26 @@ def weight(x): # r_edge_used is "more" than edge_used, though it ignores # the direction for u, v in self.edge_iterator(labels=False): - p.add_constraint(r_edge_used[u, v] + r_edge_used[v, u] - >= edge_used[u, v]) + p.add_constraint(r_edge_used[u, v] + r_edge_used[v, u] >= edge_used[u, v]) # No cycles for v in self: - p.add_constraint(p.sum(r_edge_used[u, v] for u in self.neighbor_iterator(v)) - <= 1 - epsilon) + p.add_constraint(p.sum(r_edge_used[u, v] for u in self.neighbor_iterator(v)) <= 1 - epsilon) # Enforcing the source if asked.. If s is set, it has no # incoming edge and exactly one son if s is not None: - p.add_constraint(p.sum(edge_used[u, s] for u in self.neighbor_in_iterator(s)), - max=0, min=0) - p.add_constraint(p.sum(edge_used[s, u] for u in self.neighbor_out_iterator(s)), - min=1, max=1) + p.add_constraint(p.sum(edge_used[u, s] for u in self.neighbor_in_iterator(s)), max=0, min=0) + p.add_constraint(p.sum(edge_used[s, u] for u in self.neighbor_out_iterator(s)), min=1, max=1) # Enforcing the destination if asked.. If t is set, it has # no outgoing edge and exactly one parent if t is not None: - p.add_constraint(p.sum(edge_used[u, t] for u in self.neighbor_in_iterator(t)), - min=1, max=1) - p.add_constraint(p.sum(edge_used[t, u] for u in self.neighbor_out_iterator(t)), - max=0, min=0) + p.add_constraint(p.sum(edge_used[u, t] for u in self.neighbor_in_iterator(t)), min=1, max=1) + p.add_constraint(p.sum(edge_used[t, u] for u in self.neighbor_out_iterator(t)), max=0, min=0) # Defining the objective - p.set_objective(p.sum(weight(l) * edge_used[u, v] - for u, v, l in self.edge_iterator())) + p.set_objective(p.sum(weight(l) * edge_used[u, v] for u, v, l in self.edge_iterator())) else: # We use edge_used[frozenset((u, v))] to avoid having two different # variables for edge (u, v) @@ -9037,35 +8938,24 @@ def weight(x): for u in self.neighbor_iterator(v): p.add_constraint(vertex_used[v] - edge_used[frozenset((u, v))], min=0) # A path is a tree. If n vertices are used, at most n-1 edges are - p.add_constraint(p.sum(vertex_used[v] for v in self) - - p.sum(edge_used[frozenset((u, v))] - for u, v in self.edge_iterator(labels=False)), - min=1, max=1) + p.add_constraint(p.sum(vertex_used[v] for v in self) - p.sum(edge_used[frozenset((u, v))] for u, v in self.edge_iterator(labels=False)), min=1, max=1) # A vertex has at most two incident edges used for v in self: - p.add_constraint(p.sum(edge_used[frozenset((u, v))] for u in self.neighbor_iterator(v)), - max=2) + p.add_constraint(p.sum(edge_used[frozenset((u, v))] for u in self.neighbor_iterator(v)), max=2) # r_edge_used is "more" than edge_used for u, v in self.edge_iterator(labels=False): - p.add_constraint(r_edge_used[u, v] - + r_edge_used[v, u] - - edge_used[frozenset((u, v))], - min=0) + p.add_constraint(r_edge_used[u, v] + r_edge_used[v, u] - edge_used[frozenset((u, v))], min=0) # No cycles for v in self: - p.add_constraint(p.sum(r_edge_used[u, v] for u in self.neighbor_iterator(v)), - max=1 - epsilon) + p.add_constraint(p.sum(r_edge_used[u, v] for u in self.neighbor_iterator(v)), max=1 - epsilon) # Enforcing the destination if asked.. If s or t are set, # they have exactly one incident edge if s is not None: - p.add_constraint(p.sum(edge_used[frozenset((s, u))] for u in self.neighbor_iterator(s)), - max=1, min=1) + p.add_constraint(p.sum(edge_used[frozenset((s, u))] for u in self.neighbor_iterator(s)), max=1, min=1) if t is not None: - p.add_constraint(p.sum(edge_used[frozenset((t, u))] for u in self.neighbor_iterator(t)), - max=1, min=1) + p.add_constraint(p.sum(edge_used[frozenset((t, u))] for u in self.neighbor_iterator(t)), max=1, min=1) # Defining the objective - p.set_objective(p.sum(weight(l) * edge_used[frozenset((u, v))] - for u, v, l in self.edge_iterator())) + p.set_objective(p.sum(weight(l) * edge_used[frozenset((u, v))] for u, v, l in self.edge_iterator())) # Computing the result. No exception has to be raised, as this # problem always has a solution (there is at least one edge, @@ -9074,20 +8964,15 @@ def weight(x): edge_used = p.get_values(edge_used, convert=bool, tolerance=integrality_tolerance) vertex_used = p.get_values(vertex_used, convert=bool, tolerance=integrality_tolerance) if self._directed: - edges = ((u, v, l) for u, v, l in self.edge_iterator() - if edge_used[u, v]) + edges = ((u, v, l) for u, v, l in self.edge_iterator() if edge_used[u, v]) else: - edges = ((u, v, l) for u, v, l in self.edge_iterator() - if edge_used[frozenset((u, v))]) - g = self.subgraph(vertices=(v for v in self if vertex_used[v]), - edges=edges, immutable=immutable) + edges = ((u, v, l) for u, v, l in self.edge_iterator() if edge_used[frozenset((u, v))]) + g = self.subgraph(vertices=(v for v in self if vertex_used[v]), edges=edges, immutable=immutable) if use_edge_labels: return sum(map(weight, g.edge_labels())), g return g - def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, - maximize=False, algorithm='MILP', immutable=None, - solver=None, verbose=0, *, integrality_tolerance=1e-3): + def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, maximize=False, algorithm='MILP', immutable=None, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a Hamiltonian path of the current graph/digraph. @@ -9242,8 +9127,7 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, raise ValueError("algorithm must be either 'backtrack' or 'MILP'") if self.order() < 2: - raise ValueError('the Hamiltonian path problem is not well ' + - 'defined for empty and one-element (di)graphs') + raise ValueError('the Hamiltonian path problem is not well ' + 'defined for empty and one-element (di)graphs') if not self.is_connected(): return (0, None) if use_edge_labels else None @@ -9313,8 +9197,7 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, new_t = ones.pop() if not use_edge_labels and algorithm == "backtrack": - path = g.longest_path(s=new_s, t=new_t, algorithm='backtrack', - immutable=immutable) + path = g.longest_path(s=new_s, t=new_t, algorithm='backtrack', immutable=immutable) return path if path.order() == g.order() else None # @@ -9351,11 +9234,9 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, # We now search for a Hamiltonian Cycle in g # from sage.categories.sets_cat import EmptySetError + try: - tsp = g.traveling_salesman_problem(use_edge_labels=use_edge_labels, - maximize=maximize, - solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + tsp = g.traveling_salesman_problem(use_edge_labels=use_edge_labels, maximize=maximize, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) except EmptySetError: return (0, None) if use_edge_labels else None @@ -9366,12 +9247,10 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, def weight(label): return 1 if label is None else label + return (sum(map(weight, tsp.edge_labels())), tsp) if use_edge_labels else tsp - def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, - solver=None, constraint_generation=None, - verbose=0, verbose_constraints=False, - *, integrality_tolerance=1e-3): + def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, solver=None, constraint_generation=None, verbose=0, verbose_constraints=False, *, integrality_tolerance=1e-3): r""" Solve the traveling salesman problem (TSP). @@ -9599,9 +9478,12 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, # Associating a weight to a label if use_edge_labels: + def weight(label): return 1 if label is None else label + else: + def weight(label): return 1 @@ -9622,14 +9504,11 @@ def weight(label): if self.has_edge(uu, vv) and self.has_edge(vv, uu): if self.allows_multiple_edges(): if maximize: - edges = [(uu, vv, max(self.edge_label(uu, vv), key=weight)), - (vv, uu, max(self.edge_label(vv, uu), key=weight))] + edges = [(uu, vv, max(self.edge_label(uu, vv), key=weight)), (vv, uu, max(self.edge_label(vv, uu), key=weight))] else: - edges = [(uu, vv, min(self.edge_label(uu, vv), key=weight)), - (vv, uu, min(self.edge_label(vv, uu), key=weight))] + edges = [(uu, vv, min(self.edge_label(uu, vv), key=weight)), (vv, uu, min(self.edge_label(vv, uu), key=weight))] else: - edges = [(uu, vv, self.edge_label(uu, vv)), - (vv, uu, self.edge_label(vv, uu))] + edges = [(uu, vv, self.edge_label(uu, vv)), (vv, uu, self.edge_label(vv, uu))] answer = self.subgraph(edges=edges, immutable=self.is_immutable()) answer.set_pos(self.get_pos()) answer._name = "TSP from " + self.name() @@ -9674,7 +9553,7 @@ def weight(label): g = self if constraint_generation is None: - if g.density() > .7: + if g.density() > 0.7: constraint_generation = False else: constraint_generation = True @@ -9687,15 +9566,14 @@ def weight(label): if constraint_generation: - p = MixedIntegerLinearProgram(maximization=maximize, - solver=solver, - constraint_generation=True) + p = MixedIntegerLinearProgram(maximization=maximize, solver=solver, constraint_generation=True) # Directed Case # ################# if g.is_directed(): from sage.graphs.digraph import DiGraph + b = p.new_variable(binary=True) # Objective function @@ -9704,10 +9582,8 @@ def weight(label): # All the vertices have in-degree 1 and out-degree 1 for v in g: - p.add_constraint(p.sum(b[u, v] for u in g.neighbor_in_iterator(v)), - min=1, max=1) - p.add_constraint(p.sum(b[v, u] for u in g.neighbor_out_iterator(v)), - min=1, max=1) + p.add_constraint(p.sum(b[u, v] for u in g.neighbor_in_iterator(v)), min=1, max=1) + p.add_constraint(p.sum(b[v, u] for u in g.neighbor_out_iterator(v)), min=1, max=1) # Initial Solve try: @@ -9732,8 +9608,7 @@ def weight(label): for c in cc: if verbose_constraints: print("Adding a constraint on set", c) - p.add_constraint(p.sum(b[u, v] for u, v in g.edge_boundary(c, labels=False)), - min=1) + p.add_constraint(p.sum(b[u, v] for u, v in g.edge_boundary(c, labels=False)), min=1) try: p.solve(log=verbose) @@ -9745,6 +9620,7 @@ def weight(label): else: from sage.graphs.graph import Graph + b = p.new_variable(binary=True) # Objective function @@ -9753,8 +9629,7 @@ def weight(label): # All the vertices have degree 2 for v in g: - p.add_constraint(p.sum(b[frozenset((u, v))] for u in g.neighbor_iterator(v)), - min=2, max=2) + p.add_constraint(p.sum(b[frozenset((u, v))] for u in g.neighbor_iterator(v)), min=2, max=2) # Initial Solve try: @@ -9777,8 +9652,7 @@ def weight(label): for c in cc: if verbose_constraints: print("Adding a constraint on set", c) - p.add_constraint(p.sum(b[frozenset((u, v))] for u, v in g.edge_boundary(c, labels=False)), - min=2) + p.add_constraint(p.sum(b[frozenset((u, v))] for u, v in g.edge_boundary(c, labels=False)), min=2) try: p.solve(log=verbose) @@ -9788,7 +9662,7 @@ def weight(label): # We can now return the TSP ! answer = self.subgraph(edges=h.edges(sort=False), immutable=self.is_immutable()) answer.set_pos(self.get_pos()) - answer._name = "TSP from "+g.name() + answer._name = "TSP from " + g.name() return answer ################################################# @@ -9800,17 +9674,15 @@ def weight(label): f = p.new_variable(binary=True) r = p.new_variable(nonnegative=True) - eps = 1 / (2*Integer(g.order())) + eps = 1 / (2 * Integer(g.order())) x = next(g.vertex_iterator()) if g.is_directed(): # All the vertices have in-degree 1 and out-degree 1 for v in g: - p.add_constraint(p.sum(f[u, v] for u in g.neighbor_in_iterator(v)), - min=1, max=1) + p.add_constraint(p.sum(f[u, v] for u in g.neighbor_in_iterator(v)), min=1, max=1) - p.add_constraint(p.sum(f[v, u] for u in g.neighbor_out_iterator(v)), - min=1, max=1) + p.add_constraint(p.sum(f[v, u] for u in g.neighbor_out_iterator(v)), min=1, max=1) # r is greater than f vertex_to_int = {u: i for i, u in enumerate(g)} @@ -9830,13 +9702,13 @@ def weight(label): # defining the answer when g is directed from sage.graphs.digraph import DiGraph + tsp = DiGraph() else: # All the vertices have degree 2 for v in g: - p.add_constraint(p.sum(f[frozenset((u, v))] for u in g.neighbor_iterator(v)), - min=2, max=2) + p.add_constraint(p.sum(f[frozenset((u, v))] for u in g.neighbor_iterator(v)), min=2, max=2) # r is greater than f for u, v in g.edge_iterator(labels=None): @@ -9871,9 +9743,7 @@ def weight(label): except MIPSolverException: raise EmptySetError("the given graph is not Hamiltonian") - def hamiltonian_cycle(self, algorithm='tsp', solver=None, constraint_generation=None, - verbose=0, verbose_constraints=False, - *, integrality_tolerance=1e-3): + def hamiltonian_cycle(self, algorithm='tsp', solver=None, constraint_generation=None, verbose=0, verbose_constraints=False, *, integrality_tolerance=1e-3): r""" Return a Hamiltonian cycle/circuit of the current graph/digraph. @@ -9988,23 +9858,22 @@ def hamiltonian_cycle(self, algorithm='tsp', solver=None, constraint_generation= if algorithm == 'tsp': from sage.numerical.mip import MIPSolverException + try: - return self.traveling_salesman_problem(use_edge_labels=False, solver=solver, - constraint_generation=constraint_generation, - verbose=verbose, verbose_constraints=verbose_constraints, - integrality_tolerance=integrality_tolerance) + return self.traveling_salesman_problem(use_edge_labels=False, solver=solver, constraint_generation=constraint_generation, verbose=verbose, verbose_constraints=verbose_constraints, integrality_tolerance=integrality_tolerance) except MIPSolverException: from sage.categories.sets_cat import EmptySetError + raise EmptySetError("the given graph is not Hamiltonian") elif algorithm == 'backtrack': from sage.graphs.generic_graph_pyx import find_hamiltonian as fh + return fh(self) raise ValueError("algorithm (%s) should be 'tsp' or 'backtrack'." % (algorithm)) - def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, - constraint_generation=True, *, integrality_tolerance=1e-3): + def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, constraint_generation=True, *, integrality_tolerance=1e-3): r""" Return the minimum feedback vertex set of a (di)graph. @@ -10149,13 +10018,10 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, 1 """ if not constraint_generation and not self.is_directed(): - raise ValueError("the only implementation available for " - "undirected graphs is with constraint_generation " - "set to True") + raise ValueError("the only implementation available for " "undirected graphs is with constraint_generation " "set to True") # It would be a pity to start a LP if the graph is already acyclic - if ((not self.is_directed() and self.is_forest()) or - (self.is_directed() and self.is_directed_acyclic())): + if (not self.is_directed() and self.is_forest()) or (self.is_directed() and self.is_directed_acyclic()): if value_only: return 0 return [] @@ -10167,8 +10033,7 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, ######################################## if constraint_generation: - p = MixedIntegerLinearProgram(constraint_generation=True, - maximization=False, solver=solver) + p = MixedIntegerLinearProgram(constraint_generation=True, maximization=False, solver=solver) # A variable for each vertex b = p.new_variable(binary=True) @@ -10239,9 +10104,7 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, return Integer(sum(1 for v in self if b_sol[v])) return [v for v in self if b_sol[v]] - def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, - vertex_bound=False, algorithm=None, solver=None, verbose=0, - *, integrality_tolerance=1e-3): + def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, vertex_bound=False, algorithm=None, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a maximum flow in the graph from ``x`` to ``y``. @@ -10407,19 +10270,23 @@ def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, """ self._scream_if_not_simple(allow_loops=True) if vertex_bound and algorithm in ["FF", "igraph"]: - raise ValueError("this method does not support both " - "vertex_bound=True and algorithm='" + algorithm + "'") + raise ValueError("this method does not support both " "vertex_bound=True and algorithm='" + algorithm + "'") if use_edge_labels: from sage.rings.real_mpfr import RR + if integer: from math import floor def capacity(z): return floor(z) if z in RR else 1 + else: + def capacity(z): return z if z in RR else 1 + else: + def capacity(z): return 1 @@ -10431,16 +10298,14 @@ def capacity(z): else: algorithm = "FF" - if (algorithm == "FF"): + if algorithm == "FF": return self._ford_fulkerson(x, y, value_only=value_only, integer=integer, use_edge_labels=use_edge_labels) - if (algorithm == 'igraph'): + if algorithm == 'igraph': vertices = list(self) x_int = vertices.index(x) y_int = vertices.index(y) if use_edge_labels: - g_igraph = self.igraph_graph(vertex_list=vertices, - edge_attrs={'capacity': [float(capacity(e[2])) - for e in self.edge_iterator()]}) + g_igraph = self.igraph_graph(vertex_list=vertices, edge_attrs={'capacity': [float(capacity(e[2])) for e in self.edge_iterator()]}) maxflow = g_igraph.maxflow(x_int, y_int, 'capacity') else: g_igraph = self.igraph_graph(vertex_list=vertices) @@ -10449,6 +10314,7 @@ def capacity(z): if value_only: return maxflow.value from sage.graphs.digraph import DiGraph + flow_digraph = DiGraph() if self.is_directed(): for e in g_igraph.es(): @@ -10470,10 +10336,10 @@ def capacity(z): return [maxflow.value, flow_digraph] if algorithm != "LP": - raise ValueError("the algorithm argument has to be equal to either " - "\"FF\", \"LP\", \"igraph\", or None") + raise ValueError("the algorithm argument has to be equal to either " "\"FF\", \"LP\", \"igraph\", or None") from sage.numerical.mip import MixedIntegerLinearProgram + g = self p = MixedIntegerLinearProgram(maximization=True, solver=solver) flow = p.new_variable(integer=integer, nonnegative=True) @@ -10482,8 +10348,7 @@ def capacity(z): if g.is_directed(): # This function return the balance of flow at X def flow_sum(X): - return (p.sum(flow[X, v] for u, v in g.outgoing_edge_iterator([X], labels=None)) - - p.sum(flow[u, X] for u, v in g.incoming_edge_iterator([X], labels=None))) + return p.sum(flow[X, v] for u, v in g.outgoing_edge_iterator([X], labels=None)) - p.sum(flow[u, X] for u, v in g.incoming_edge_iterator([X], labels=None)) # The flow leaving x def flow_leaving(X): @@ -10545,6 +10410,7 @@ def capacity_sum(u, v): # Which could be a Graph if not self.is_directed(): from sage.graphs.graph import Graph + flow_graph = Graph(flow_graph) return [obj, flow_graph] @@ -10702,17 +10568,14 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler # If the (di)graph is not connected, we solve the problem on each # of its connected components if not self.is_connected(): - solution = DiGraph(loops=self.allows_loops(), - multiedges=self.allows_multiple_edges()) + solution = DiGraph(loops=self.allows_loops(), multiedges=self.allows_multiple_edges()) solution.add_vertices(self.vertex_iterator()) for g in self.connected_components_subgraphs(): - solution.add_edges(g.nowhere_zero_flow(k=k, solver=solver, - verbose=verbose).edge_iterator()) + solution.add_edges(g.nowhere_zero_flow(k=k, solver=solver, verbose=verbose).edge_iterator()) return solution # If the (di)graph has bridges, the problem is not feasible - if ((self.is_directed() and not self.is_strongly_connected() and next(self.to_undirected().bridges(), False)) - or (not self.is_directed() and next(self.bridges(), False))): + if (self.is_directed() and not self.is_strongly_connected() and next(self.to_undirected().bridges(), False)) or (not self.is_directed() and next(self.bridges(), False)): raise EmptySetError("(di)graphs with bridges have no feasible solution") # @@ -10722,9 +10585,7 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler G = copy(self) if self.is_directed() else next(self.orientations()) # We assign flow 1 to loops, if any - solution = DiGraph([list(G), [(u, v, 1) for u, v in G.loops(labels=False)]], - loops=G.has_loops(), - multiedges=G.has_multiple_edges()) + solution = DiGraph([list(G), [(u, v, 1) for u, v in G.loops(labels=False)]], loops=G.has_loops(), multiedges=G.has_multiple_edges()) G.allow_loops(False) # We ensure that multiple edges have distinct labels @@ -10743,14 +10604,14 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler # We use a MIP formulation to solve the problem # from sage.numerical.mip import MIPSolverException, MixedIntegerLinearProgram + p = MixedIntegerLinearProgram(solver=solver) f = p.new_variable(nonnegative=False, integer=True) b = p.new_variable(nonnegative=True, binary=True) # flow conservation constraints for u in G: - p.add_constraint(p.sum(f[e] for e in G.incoming_edge_iterator(u)) == - p.sum(f[e] for e in G.outgoing_edge_iterator(u))) + p.add_constraint(p.sum(f[e] for e in G.incoming_edge_iterator(u)) == p.sum(f[e] for e in G.outgoing_edge_iterator(u))) # The flow on edge e has value in {-k+1,..., -1, 1, ..., k-1} for e in G.edge_iterator(): @@ -10846,9 +10707,12 @@ def _ford_fulkerson(self, s, t, use_edge_labels=False, integer=False, value_only # Whether we should consider the edges labeled if use_edge_labels: + def l_capacity(x): return 1 if (x is None or x == {}) else (floor(x) if integer else x) + else: + def l_capacity(x): return 1 @@ -10894,8 +10758,7 @@ def path_to_edges(P): # Rewrites a path as a list of edges labeled with their # available capacity def path_to_labelled_edges(P): - return [(x_y[0], x_y[1], capacity[x_y[0], x_y[1]] - flow[x_y[0], x_y[1]] + flow[x_y[1], x_y[0]]) - for x_y in path_to_edges(P)] + return [(x_y[0], x_y[1], capacity[x_y[0], x_y[1]] - flow[x_y[0], x_y[1]] + flow[x_y[1], x_y[0]]) for x_y in path_to_edges(P)] # Total flow going from s to t flow_intensity = 0 @@ -10944,9 +10807,7 @@ def path_to_labelled_edges(P): return flow_intensity, g - def multicommodity_flow(self, terminals, integer=True, use_edge_labels=False, - vertex_bound=False, solver=None, verbose=0, - *, integrality_tolerance=1e-3): + def multicommodity_flow(self, terminals, integer=True, use_edge_labels=False, vertex_bound=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Solve a multicommodity flow problem. @@ -11029,6 +10890,7 @@ def multicommodity_flow(self, terminals, integer=True, use_edge_labels=False, """ self._scream_if_not_simple(allow_loops=True) from sage.numerical.mip import MixedIntegerLinearProgram + g = self p = MixedIntegerLinearProgram(maximization=True, solver=solver) @@ -11050,15 +10912,16 @@ def multicommodity_flow(self, terminals, integer=True, use_edge_labels=False, def capacity(x): return x if x in RR else 1 + else: + def capacity(x): return 1 if g.is_directed(): # This function return the balance of flow at X def flow_sum(i, X): - return (p.sum(flow[i, (X, v)] for u, v in g.outgoing_edge_iterator([X], labels=None)) - - p.sum(flow[i, (u, X)] for u, v in g.incoming_edge_iterator([X], labels=None))) + return p.sum(flow[i, (X, v)] for u, v in g.outgoing_edge_iterator([X], labels=None)) - p.sum(flow[i, (u, X)] for u, v in g.incoming_edge_iterator([X], labels=None)) # The flow leaving x def flow_leaving(i, X): @@ -11121,6 +10984,7 @@ def capacity_sum(i, u, v): p.solve(log=verbose) except MIPSolverException: from sage.categories.sets_cat import EmptySetError + raise EmptySetError("the multicommodity flow problem has no solution") # If integer is True, flow variables will be converted to integers. @@ -11128,12 +10992,12 @@ def capacity_sum(i, u, v): flow = p.get_values(flow, convert=True, tolerance=integrality_tolerance) # building clean flow digraphs - flow_graphs = [g._build_flow_graph({e: f for (ii, e), f in flow.items() if ii == i}, integer=integer) - for i in range(len(terminals))] + flow_graphs = [g._build_flow_graph({e: f for (ii, e), f in flow.items() if ii == i}, integer=integer) for i in range(len(terminals))] # which could be .. graphs ! if not self.is_directed(): from sage.graphs.graph import Graph + flow_graphs = [Graph(_) for _ in flow_graphs] return flow_graphs @@ -11186,6 +11050,7 @@ def _build_flow_graph(self, flow, integer): [('000', '001', 1)] """ from sage.graphs.digraph import DiGraph + g = DiGraph() # add significant edges @@ -11220,8 +11085,7 @@ def _build_flow_graph(self, flow, integer): return h - def disjoint_routed_paths(self, pairs, solver=None, verbose=0, - *, integrality_tolerance=1e-3): + def disjoint_routed_paths(self, pairs, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a set of disjoint routed paths. @@ -11267,15 +11131,13 @@ def disjoint_routed_paths(self, pairs, solver=None, verbose=0, EmptySetError: the disjoint routed paths do not exist """ from sage.categories.sets_cat import EmptySetError + try: - return self.multicommodity_flow(pairs, integer=True, vertex_bound=True, - solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + return self.multicommodity_flow(pairs, integer=True, vertex_bound=True, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) except EmptySetError: raise EmptySetError("the disjoint routed paths do not exist") - def edge_disjoint_paths(self, s, t, algorithm='FF', solver=None, verbose=False, - *, integrality_tolerance=1e-3): + def edge_disjoint_paths(self, s, t, algorithm='FF', solver=None, verbose=False, *, integrality_tolerance=1e-3): r""" Return a list of edge-disjoint paths between two vertices. @@ -11329,9 +11191,7 @@ def edge_disjoint_paths(self, s, t, algorithm='FF', solver=None, verbose=False, sage: g.edge_disjoint_paths(0, 1) [[0, 2, 1], [0, 3, 1], [0, 4, 1]] """ - [obj, flow_graph] = self.flow(s, t, value_only=False, integer=True, use_edge_labels=False, - algorithm=algorithm, solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + [obj, flow_graph] = self.flow(s, t, value_only=False, integer=True, use_edge_labels=False, algorithm=algorithm, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) paths = [] @@ -11345,8 +11205,7 @@ def edge_disjoint_paths(self, s, t, algorithm='FF', solver=None, verbose=False, return paths - def vertex_disjoint_paths(self, s, t, solver=None, verbose=0, - *, integrality_tolerance=1e-3): + def vertex_disjoint_paths(self, s, t, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a list of vertex-disjoint paths between two vertices. @@ -11394,9 +11253,7 @@ def vertex_disjoint_paths(self, s, t, solver=None, verbose=0, sage: g.vertex_disjoint_paths(1, 0) # needs sage.numerical.mip [] """ - obj, flow_graph = self.flow(s, t, value_only=False, integer=True, use_edge_labels=False, - vertex_bound=True, solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + obj, flow_graph = self.flow(s, t, value_only=False, integer=True, use_edge_labels=False, vertex_bound=True, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) paths = [] if not obj: @@ -11414,9 +11271,7 @@ def vertex_disjoint_paths(self, s, t, solver=None, verbose=0, return paths - def pagerank(self, alpha=0.85, personalization=None, by_weight=False, - weight_function=None, check_weight=True, - dangling=None, algorithm='scipy'): + def pagerank(self, alpha=0.85, personalization=None, by_weight=False, weight_function=None, check_weight=True, dangling=None, algorithm='scipy'): r""" Return the PageRank of the vertices of ``self``. @@ -11556,9 +11411,7 @@ def pagerank(self, alpha=0.85, personalization=None, by_weight=False, if not self.order(): return {} - by_weight, weight_function = self._get_weight_function(by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight) + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, weight_function=weight_function, check_weight=check_weight) if by_weight: weight = "weight" @@ -11569,10 +11422,9 @@ def pagerank(self, alpha=0.85, personalization=None, by_weight=False, algorithm = algorithm.lower() if algorithm == 'networkx' or algorithm == 'scipy': import networkx + gnx = self.networkx_graph(weight_function=weight_function) - return networkx.pagerank(gnx, alpha=alpha, - personalization=personalization, - weight=weight, dangling=dangling) + return networkx.pagerank(gnx, alpha=alpha, personalization=personalization, weight=weight, dangling=dangling) if algorithm == 'igraph': # An error will be raised if igraph is not installed if personalization: @@ -11580,8 +11432,7 @@ def pagerank(self, alpha=0.85, personalization=None, by_weight=False, if dangling: raise ValueError('dangling parameter is not used in igraph implementation') if by_weight: - I = self.igraph_graph(edge_attrs={'weight': [weight_function(e) - for e in self.edge_iterator()]}) + I = self.igraph_graph(edge_attrs={'weight': [weight_function(e) for e in self.edge_iterator()]}) else: I = self.igraph_graph() page_rank = I.pagerank(damping=alpha, weights=weight) @@ -11849,6 +11700,7 @@ def random_vertex(self, **kwds): if not self.order(): raise ValueError("cannot get a random vertex from the empty graph") from sage.misc.prandom import randint + it = self.vertex_iterator(**kwds) for i in range(randint(0, self.order() - 1)): next(it) @@ -11890,6 +11742,7 @@ def random_vertex_iterator(self, *args, **kwds): StopIteration """ from sage.misc.prandom import choice + if self.order(): V = list(self.vertex_iterator(*args, **kwds)) while True: @@ -11931,6 +11784,7 @@ def random_edge(self, **kwds): raise ValueError("cannot get a random edge from a graph without edges") from sage.misc.prandom import randint + it = self.edge_iterator(**kwds) for i in range(randint(0, self.size() - 1)): next(it) @@ -11980,6 +11834,7 @@ def random_edge_iterator(self, *args, **kwds): StopIteration """ from sage.misc.prandom import choice + if self.size(): E = list(self.edge_iterator(*args, **kwds)) while True: @@ -12298,8 +12153,7 @@ def neighbor_iterator(self, vertex, closed=False): if closed: if not self.has_vertex(vertex): - raise LookupError( - 'vertex ({0}) is not a vertex of the graph'.format(vertex)) + raise LookupError('vertex ({0}) is not a vertex of the graph'.format(vertex)) if not self.has_edge(vertex, vertex): yield vertex @@ -12534,8 +12388,7 @@ def merge_vertices(self, vertices): if self.is_directed(): out_edges = self.edge_boundary(vertices) - in_edges = self.edge_boundary([v for v in self - if v not in vertices]) + in_edges = self.edge_boundary([v for v in self if v not in vertices]) self.delete_vertices(vertices[1:]) self.add_edges((u, v0, l) for (u0, v0, l) in out_edges if u0 != u) self.add_edges((v0, u, l) for (v0, u0, l) in in_edges if u0 != u) @@ -13035,8 +12888,7 @@ def contract_edge(self, u, v=None, label=None): if u == v: return - if (self.allows_loops() and - (self.allows_multiple_edges() or not self.has_edge(u, u))): + if self.allows_loops() and (self.allows_multiple_edges() or not self.has_edge(u, u)): # add loops for x, y, l in self.edges_incident(v): if set([x, y]) == set([u, v]): @@ -13148,6 +13000,7 @@ def contract_edges(self, edges): # implementation of union_find using DisjointSet from sage.sets.disjoint_set import DisjointSet + DS = DisjointSet(self.vertex_iterator()) for u, v, label in edge_list: @@ -13167,7 +13020,7 @@ def contract_edges(self, edges): edges_incident.extend(self.edges_incident(v, sort=False)) self.delete_vertex(v) - for (u, v, label) in edges_incident: + for u, v, label in edges_incident: root_u = DS.find(u) root_v = DS.find(v) if root_v != root_u or self.allows_loops(): @@ -13295,8 +13148,7 @@ def set_edge_label(self, u, v, l): """ if self.allows_multiple_edges(): if len(self.edge_label(u, v)) > 1: - raise RuntimeError("cannot set edge label, since there are " - "multiple edges from %s to %s" % (u, v)) + raise RuntimeError("cannot set edge label, since there are " "multiple edges from %s to %s" % (u, v)) self._backend.set_edge_label(u, v, l, self._directed) def has_edge(self, u, v=None, label=None) -> bool: @@ -13332,8 +13184,7 @@ def has_edge(self, u, v=None, label=None) -> bool: label = None return self._backend.has_edge(u, v, label) - def edges(self, vertices=None, labels=True, sort=False, key=None, - ignore_direction=False, sort_vertices=True): + def edges(self, vertices=None, labels=True, sort=False, key=None, ignore_direction=False, sort_vertices=True): r""" Return a :class:`~EdgesView` of edges. @@ -13509,8 +13360,7 @@ def edges(self, vertices=None, labels=True, sort=False, key=None, if vertices is not None and vertices in self: vertices = [vertices] - return EdgesView(self, vertices=vertices, labels=labels, sort=sort, key=key, - ignore_direction=ignore_direction, sort_vertices=sort_vertices) + return EdgesView(self, vertices=vertices, labels=labels, sort=sort, key=key, ignore_direction=ignore_direction, sort_vertices=sort_vertices) def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False, key=None): r""" @@ -13596,19 +13446,14 @@ def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False, key= if self._directed: if vertices2 is not None: vertices2 = set(v for v in vertices2 if v in self) - output = [e for e in self.outgoing_edge_iterator(vertices1, labels=labels) - if e[1] in vertices2] + output = [e for e in self.outgoing_edge_iterator(vertices1, labels=labels) if e[1] in vertices2] else: - output = [e for e in self.outgoing_edge_iterator(vertices1, labels=labels) - if e[1] not in vertices1] + output = [e for e in self.outgoing_edge_iterator(vertices1, labels=labels) if e[1] not in vertices1] elif vertices2 is not None: vertices2 = set(v for v in vertices2 if v in self) - output = [e for e in self.edges(vertices=vertices1, labels=labels, sort=False) - if (e[0] in vertices1 and e[1] in vertices2) or - (e[1] in vertices1 and e[0] in vertices2)] + output = [e for e in self.edges(vertices=vertices1, labels=labels, sort=False) if (e[0] in vertices1 and e[1] in vertices2) or (e[1] in vertices1 and e[0] in vertices2)] else: - output = [e for e in self.edges(vertices=vertices1, labels=labels, sort=False) - if e[1] not in vertices1 or e[0] not in vertices1] + output = [e for e in self.edges(vertices=vertices1, labels=labels, sort=False) if e[1] not in vertices1 or e[0] not in vertices1] if sort: return sorted(output, key=key) return output @@ -13696,8 +13541,8 @@ def edge_iterator(self, vertices=None, labels=True, ignore_direction=False, sort if ignore_direction and self._directed: from itertools import chain - return chain(self._backend.iterator_out_edges(vertices, labels), - self._backend.iterator_in_edges(vertices, labels)) + + return chain(self._backend.iterator_out_edges(vertices, labels), self._backend.iterator_in_edges(vertices, labels)) if self._directed: return self._backend.iterator_out_edges(vertices, labels) if not sort_vertices: @@ -14217,9 +14062,7 @@ def is_regular(self, k=None) -> bool: # Substructures - def subgraph(self, vertices=None, edges=None, inplace=False, - vertex_property=None, edge_property=None, algorithm=None, - immutable=None): + def subgraph(self, vertices=None, edges=None, inplace=False, vertex_property=None, edge_property=None, algorithm=None, immutable=None): r""" Return the subgraph containing the given vertices and edges. @@ -14387,14 +14230,9 @@ def subgraph(self, vertices=None, edges=None, inplace=False, if algorithm is not None and algorithm not in ("delete", "add"): raise ValueError('algorithm should be None, "delete", or "add"') - if (inplace or algorithm == "delete"): - return self._subgraph_by_deleting(vertices=vertices, edges=edges, - inplace=inplace, - edge_property=edge_property, - immutable=immutable) - return self._subgraph_by_adding(vertices=vertices, edges=edges, - edge_property=edge_property, - immutable=immutable) + if inplace or algorithm == "delete": + return self._subgraph_by_deleting(vertices=vertices, edges=edges, inplace=inplace, edge_property=edge_property, immutable=immutable) + return self._subgraph_by_adding(vertices=vertices, edges=edges, edge_property=edge_property, immutable=immutable) def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None, immutable=None): r""" @@ -14503,8 +14341,7 @@ def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None, imm sage: h.get_vertices() {3: 'v3', 4: 'v4', 5: 'v5'} """ - G = self.__class__(weighted=self._weighted, loops=self.allows_loops(), - multiedges=self.allows_multiple_edges()) + G = self.__class__(weighted=self._weighted, loops=self.allows_loops(), multiedges=self.allows_multiple_edges()) G.name("Subgraph of (%s)" % self.name()) if edges is None and edge_property is None: self._backend.subgraph_given_vertices(G._backend, vertices) @@ -14523,21 +14360,15 @@ def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None, imm edges_to_keep = [] if self._directed: for u, v, l in self.edges(vertices=vertices, sort=False): - if (v in G and ((u, v, l) in edges_to_keep_labeled - or (u, v) in edges_to_keep_unlabeled)): + if v in G and ((u, v, l) in edges_to_keep_labeled or (u, v) in edges_to_keep_unlabeled): edges_to_keep.append((u, v, l)) else: for u, v, l in self.edges(vertices=vertices, sort=False): - if (u in G and v in G - and ((u, v, l) in edges_to_keep_labeled - or (v, u, l) in edges_to_keep_labeled - or (u, v) in edges_to_keep_unlabeled - or (v, u) in edges_to_keep_unlabeled)): + if u in G and v in G and ((u, v, l) in edges_to_keep_labeled or (v, u, l) in edges_to_keep_labeled or (u, v) in edges_to_keep_unlabeled or (v, u) in edges_to_keep_unlabeled): edges_to_keep.append((u, v, l)) else: s_vertices = set(G.vertices()) if vertices is None else set(vertices) - edges_to_keep = [e for e in self.edges(vertices=vertices, sort=False, sort_vertices=False) - if e[0] in s_vertices and e[1] in s_vertices] + edges_to_keep = [e for e in self.edges(vertices=vertices, sort=False, sort_vertices=False) if e[0] in s_vertices and e[1] in s_vertices] if edge_property is not None: edges_to_keep = [e for e in edges_to_keep if edge_property(e)] @@ -14567,8 +14398,7 @@ def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None, imm return G - def _subgraph_by_deleting(self, vertices=None, edges=None, inplace=False, - edge_property=None, immutable=None): + def _subgraph_by_deleting(self, vertices=None, edges=None, inplace=False, edge_property=None, immutable=None): r""" Return the subgraph containing the given vertices and edges. @@ -14709,15 +14539,11 @@ def _subgraph_by_deleting(self, vertices=None, edges=None, inplace=False, edges_to_delete = [] if G._directed: for e in G.edge_iterator(): - if (e not in edges_to_keep_labeled - and e[:2] not in edges_to_keep_unlabeled): + if e not in edges_to_keep_labeled and e[:2] not in edges_to_keep_unlabeled: edges_to_delete.append(e) else: for u, v, l in G.edge_iterator(): - if ((u, v, l) not in edges_to_keep_labeled - and (v, u, l) not in edges_to_keep_labeled - and (u, v) not in edges_to_keep_unlabeled - and (v, u) not in edges_to_keep_unlabeled): + if (u, v, l) not in edges_to_keep_labeled and (v, u, l) not in edges_to_keep_labeled and (u, v) not in edges_to_keep_unlabeled and (v, u) not in edges_to_keep_unlabeled: edges_to_delete.append((u, v, l)) if edge_property is not None: # We might get duplicate edges, but this does handle the case of @@ -15154,6 +14980,7 @@ def subgraph_search_iterator(self, G, induced=False, return_graphs=True): yield [v] else: from sage.graphs.generic_graph_pyx import SubgraphSearch + for g in SubgraphSearch(self, G, induced=induced): if not return_graphs: yield g @@ -15161,8 +14988,7 @@ def subgraph_search_iterator(self, G, induced=False, return_graphs=True): yield self.subgraph(g) else: G_to_g = dict(zip(G, g)) - yield self.subgraph(g, edges=[(G_to_g[u], G_to_g[v]) - for u, v in G.edge_iterator(labels=False)]) + yield self.subgraph(g, edges=[(G_to_g[u], G_to_g[v]) for u, v in G.edge_iterator(labels=False)]) def subgraph_decompositions(self, H, induced=False): r""" @@ -15509,9 +15335,7 @@ def is_chordal(self, certificate=False, algorithm='B'): # Iteratively removing vertices and checking everything is fine. for v in reversed(peo): - if (t_peo.out_degree(v) and - not frozenset(v1 for v1 in g.neighbor_iterator(v) if pos_in_peo[v1] > pos_in_peo[v]).issubset( - neighbors_subsets[next(t_peo.neighbor_out_iterator(v))])): + if t_peo.out_degree(v) and not frozenset(v1 for v1 in g.neighbor_iterator(v) if pos_in_peo[v1] > pos_in_peo[v]).issubset(neighbors_subsets[next(t_peo.neighbor_out_iterator(v))]): # Do we need to return a hole ? if certificate: @@ -15554,9 +15378,7 @@ def is_chordal(self, certificate=False, algorithm='B'): # answer is valid, especially when it is so cheap ;-) if hole.order() <= 3 or not hole.is_regular(k=2): - raise RuntimeError("the graph is not chordal, and something went wrong " - "in the computation of the certificate. Please report " - "this bug, providing the graph if possible") + raise RuntimeError("the graph is not chordal, and something went wrong " "in the computation of the certificate. Please report " "this bug, providing the graph if possible") return (False, hole) @@ -15647,10 +15469,7 @@ def is_circulant(self, certificate=False): # The automorphism group, the translation between the vertices of self # and 1..n, and the orbits. - ag, orbits = self.automorphism_group([list(self)], - order=False, - return_group=True, - orbits=True) + ag, orbits = self.automorphism_group([list(self)], order=False, return_group=True, orbits=True) # Not transitive ? Not a circulant graph ! if len(orbits) != 1: @@ -16009,9 +15828,9 @@ def is_clique(self, vertices=None, directed_clique=False, induced=True, loops=Fa N = G.order() if G.is_directed() and directed_clique: - M = N*(N-1) + (N if loops else 0) + M = N * (N - 1) + (N if loops else 0) else: - M = N*(N-1)/2 + (N if loops else 0) + M = N * (N - 1) / 2 + (N if loops else 0) # We check that the graph has a priori enough edges if G.size() < M or (induced and G.size() > M): @@ -16028,11 +15847,15 @@ def is_clique(self, vertices=None, directed_clique=False, induced=True, loops=Fa # We check that we have edges between all pairs of vertices v_to_int = {v: i for i, v in enumerate(self)} if G.is_directed() and not directed_clique: + def R(u, v): return (u, v) if u <= v else (v, u) + else: + def R(u, v): return (u, v) + if loops: edges = set(R(v_to_int[u], v_to_int[v]) for u, v in G.edge_iterator(labels=False)) else: @@ -16119,6 +15942,7 @@ def is_cycle(self, directed_cycle=True): # We make a copy of self ignoring the direction of edges from sage.graphs.graph import Graph + g = Graph(multiedges=True, loops=True) g.add_edges(self.edge_iterator(labels=False)) @@ -16240,6 +16064,7 @@ def is_subgraph(self, other, induced=True, up_to_isomorphism=False): """ from sage.graphs.digraph import DiGraph from sage.graphs.graph import Graph + if isinstance(self, Graph) and not isinstance(other, Graph): raise ValueError('the input parameter must be a Graph') @@ -16261,8 +16086,7 @@ def is_subgraph(self, other, induced=True, up_to_isomorphism=False): if induced: # Check whether ``self`` is contained in ``other`` # and whether the induced subgraph of ``other`` is contained in ``self``. - return (self._backend.is_subgraph(other._backend, self) - and other._backend.is_subgraph(self._backend, self)) + return self._backend.is_subgraph(other._backend, self) and other._backend.is_subgraph(self._backend, self) return self._backend.is_subgraph(other._backend, self) # Cluster @@ -16317,6 +16141,7 @@ def cluster_triangles(self, nbunch=None, implementation=None): """ if implementation is None: from sage.graphs.base.dense_graph import DenseGraphBackend + if isinstance(self._backend, DenseGraphBackend): implementation = 'dense_copy' else: @@ -16326,6 +16151,7 @@ def cluster_triangles(self, nbunch=None, implementation=None): if self.is_directed(): raise ValueError("the 'networkx' implementation does not support directed graphs") import networkx + return networkx.triangles(self.networkx_graph(), nbunch) if implementation == 'sparse_copy': @@ -16335,8 +16161,7 @@ def cluster_triangles(self, nbunch=None, implementation=None): from sage.graphs.base.static_dense_graph import triangles_count else: - raise ValueError("the implementation can only be 'networkx', " - "'sparse_copy', 'dense_copy' or None") + raise ValueError("the implementation can only be 'networkx', " "'sparse_copy', 'dense_copy' or None") if nbunch is None: return triangles_count(self) @@ -16391,6 +16216,7 @@ def clustering_average(self, implementation=None): """ if implementation is None: from sage.graphs.base.dense_graph import DenseGraphBackend + if self.is_directed(): implementation = 'networkx' elif isinstance(self._backend, DenseGraphBackend): @@ -16399,25 +16225,23 @@ def clustering_average(self, implementation=None): implementation = 'sparse_copy' if implementation not in ['networkx', 'boost', 'dense_copy', 'sparse_copy']: - raise ValueError("the implementation can only be 'networkx', " - "'boost', 'sparse_copy', 'dense_copy' or None") + raise ValueError("the implementation can only be 'networkx', " "'boost', 'sparse_copy', 'dense_copy' or None") if self.is_directed() and implementation != 'networkx': raise ValueError("this value of 'implementation' is invalid for directed graphs") if implementation == 'boost': from sage.graphs.base.boost_graph import clustering_coeff + return clustering_coeff(self)[0] if implementation == 'networkx': import networkx + return networkx.average_clustering(self.networkx_graph()) coeffs = self.clustering_coeff(implementation=implementation) return sum(coeffs.values()) / len(coeffs) - def clustering_coeff(self, - nodes=None, - weight=False, - implementation=None): + def clustering_coeff(self, nodes=None, weight=False, implementation=None): r""" Return the clustering coefficient for each vertex in ``nodes`` as a dictionary keyed by vertex. @@ -16517,6 +16341,7 @@ def clustering_coeff(self, if implementation is None: from sage.graphs.base.dense_graph import DenseGraphBackend + if self.is_directed() or weight: implementation = 'networkx' elif nodes is not None: @@ -16527,13 +16352,12 @@ def clustering_coeff(self, implementation = 'sparse_copy' if implementation not in ['networkx', 'boost', 'dense_copy', 'sparse_copy']: - raise ValueError("the implementation can only be 'networkx', " - "'boost', 'sparse_copy', 'dense_copy' or None") + raise ValueError("the implementation can only be 'networkx', " "'boost', 'sparse_copy', 'dense_copy' or None") if (self.is_directed() or weight) and implementation != 'networkx': raise ValueError("this value of 'implementation' is invalid for directed/weighted graphs") - if (implementation in ['sparse_copy', 'dense_copy'] and nodes is not None): + if implementation in ['sparse_copy', 'dense_copy'] and nodes is not None: raise ValueError("'sparse_copy','dense_copy' do not support 'nodes' different from 'None'") if not self.order(): @@ -16547,18 +16371,20 @@ def coeff_from_triangle_count(v, count): if implementation == 'boost': from sage.graphs.base.boost_graph import clustering_coeff + return clustering_coeff(self, nodes)[1] if implementation == 'networkx': import networkx + return networkx.clustering(self.networkx_graph(), nodes, weight=weight) if implementation == 'sparse_copy': from sage.graphs.base.static_sparse_graph import triangles_count - return {v: coeff_from_triangle_count(v, count) - for v, count in triangles_count(self).items()} + + return {v: coeff_from_triangle_count(v, count) for v, count in triangles_count(self).items()} if implementation == "dense_copy": from sage.graphs.base.static_dense_graph import triangles_count - return {v: coeff_from_triangle_count(v, count) - for v, count in triangles_count(self).items()} + + return {v: coeff_from_triangle_count(v, count) for v, count in triangles_count(self).items()} def cluster_transitivity(self): r""" @@ -16576,6 +16402,7 @@ def cluster_transitivity(self): 0.25 """ import networkx + return networkx.transitivity(self.networkx_graph()) # Distance @@ -16625,12 +16452,9 @@ def distance(self, u, v, by_weight=False, weight_function=None, check_weight=Tru sage: G.distance(0, 3, by_weight=True) 3 """ - return self.shortest_path_length(u, v, by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight) + return self.shortest_path_length(u, v, by_weight=by_weight, weight_function=weight_function, check_weight=check_weight) - def distance_all_pairs(self, by_weight=False, algorithm=None, - weight_function=None, check_weight=True): + def distance_all_pairs(self, by_weight=False, algorithm=None, weight_function=None, check_weight=True): r""" Return the distances between all pairs of vertices. @@ -16721,10 +16545,7 @@ def distance_all_pairs(self, by_weight=False, algorithm=None, * :meth:`~sage.graphs.generic_graph.GenericGraph.distance_matrix` * :meth:`~sage.graphs.generic_graph.GenericGraph.shortest_path_all_pairs` """ - return self.shortest_path_all_pairs(by_weight=by_weight, - algorithm=algorithm, - weight_function=weight_function, - check_weight=check_weight)[0] + return self.shortest_path_all_pairs(by_weight=by_weight, algorithm=algorithm, weight_function=weight_function, check_weight=check_weight)[0] def power(self, k): r""" @@ -17029,6 +16850,7 @@ def odd_girth(self, algorithm='bfs', certificate=False): if self.is_bipartite(): from sage.rings.infinity import Infinity + return (Infinity, None) if certificate else Infinity if algorithm == "bfs": @@ -17040,7 +16862,7 @@ def odd_girth(self, algorithm='bfs', certificate=False): ch = self.am().charpoly(algorithm=algorithm).coefficients(sparse=False) n = self.order() - for i in range(n-1, -1, -2): + for i in range(n - 1, -1, -2): if ch[i]: return n - i @@ -17112,6 +16934,7 @@ def _girth_bfs(self, odd=False, certificate=False): depth += 1 if best == n + 1: from sage.rings.infinity import Infinity + return (Infinity, None) if certificate else Infinity if certificate: cycles = {} @@ -17128,9 +16951,7 @@ def _girth_bfs(self, odd=False, certificate=False): # Centrality - def centrality_betweenness(self, k=None, normalized=True, weight=None, - endpoints=False, seed=None, exact=False, - algorithm=None): + def centrality_betweenness(self, k=None, normalized=True, weight=None, endpoints=False, seed=None, exact=False, algorithm=None): r""" Return the betweenness centrality. @@ -17210,30 +17031,22 @@ def centrality_betweenness(self, k=None, normalized=True, weight=None, """ if algorithm == "NetworkX" and exact: raise ValueError("'exact' is not available with the NetworkX implementation") - if (algorithm is None and - seed is None and - weight is None and - endpoints is False and - k is None): + if algorithm is None and seed is None and weight is None and endpoints is False and k is None: algorithm = "Sage" elif algorithm is None: algorithm = "NetworkX" if algorithm == "Sage": from .centrality import centrality_betweenness + return centrality_betweenness(self, normalize=normalized, exact=exact) if algorithm == "NetworkX": import networkx - return networkx.betweenness_centrality(self.networkx_graph(), - k=k, - normalized=normalized, - weight=weight, - endpoints=endpoints, - seed=seed) + + return networkx.betweenness_centrality(self.networkx_graph(), k=k, normalized=normalized, weight=weight, endpoints=endpoints, seed=seed) raise ValueError("'algorithm' can be \"NetworkX\", \"Sage\" or None") - def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, - weight_function=None, check_weight=True): + def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, weight_function=None, check_weight=True): r""" Return the closeness centrality of all vertices in ``vert``. @@ -17434,9 +17247,7 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, ....: for ci, cj in itertools.combinations(c, 2) ) True """ - by_weight, weight_function = self._get_weight_function(by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight) + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, weight_function=weight_function, check_weight=check_weight) onlyone = False if vert in self: @@ -17462,6 +17273,7 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, if algorithm == 'NetworkX': import networkx + if by_weight: if self.is_directed(): G = networkx.DiGraph([(e[1], e[0], {'weight': weight_function(e)}) for e in self.edge_iterator()]) @@ -17486,6 +17298,7 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, return closeness if algorithm == "Johnson_Boost": from sage.graphs.base.boost_graph import johnson_closeness_centrality + self.weighted(by_weight) closeness = johnson_closeness_centrality(self, weight_function) if onlyone: @@ -17494,19 +17307,12 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, closeness = dict() distances = None - if algorithm in ["Floyd-Warshall-Cython", - "Floyd-Warshall-Python"]: - distances = self.shortest_path_all_pairs(algorithm=algorithm, - by_weight=by_weight, - weight_function=weight_function, - check_weight=False)[0] + if algorithm in ["Floyd-Warshall-Cython", "Floyd-Warshall-Python"]: + distances = self.shortest_path_all_pairs(algorithm=algorithm, by_weight=by_weight, weight_function=weight_function, check_weight=False)[0] for v in v_iter: if distances is None: - distv = self.shortest_path_lengths(v, algorithm=algorithm, - by_weight=by_weight, - weight_function=weight_function, - check_weight=False) + distv = self.shortest_path_lengths(v, algorithm=algorithm, by_weight=by_weight, weight_function=weight_function, check_weight=False) else: distv = distances[v] try: @@ -17601,18 +17407,18 @@ def triangles_count(self, algorithm=None): """ if self.is_directed(): if algorithm is not None and algorithm != "iter": - raise ValueError("the value of algorithm(={}) must be 'iter' " - "or None for directed graphs".format(algorithm)) + raise ValueError("the value of algorithm(={}) must be 'iter' " "or None for directed graphs".format(algorithm)) self._scream_if_not_simple(allow_loops=True) from sage.graphs.digraph_generators import digraphs + return self.subgraph_search_count(digraphs.Circuit(3)) // 3 self._scream_if_not_simple() if algorithm is None: from sage.graphs.base.dense_graph import DenseGraphBackend - algorithm = ('dense_copy' if isinstance(self._backend, DenseGraphBackend) else - 'sparse_copy') + + algorithm = 'dense_copy' if isinstance(self._backend, DenseGraphBackend) else 'sparse_copy' if algorithm == 'iter': tr = 0 @@ -17623,16 +17429,17 @@ def triangles_count(self, algorithm=None): return Integer(tr // 6) if algorithm == "sparse_copy": from sage.graphs.base.static_sparse_graph import triangles_count + return sum(triangles_count(self).values()) // 3 if algorithm == "dense_copy": from sage.graphs.base.static_dense_graph import triangles_count + return sum(triangles_count(self).values()) // 3 if algorithm == 'matrix': - return (self.adjacency_matrix(vertices=list(self))**3).trace() // 6 + return (self.adjacency_matrix(vertices=list(self)) ** 3).trace() // 6 raise ValueError('unknown algorithm "{}"'.format(algorithm)) - def shortest_path(self, u, v, by_weight=False, algorithm=None, - weight_function=None, check_weight=True): + def shortest_path(self, u, v, by_weight=False, algorithm=None, weight_function=None, check_weight=True): r""" Return a list of vertices representing some shortest path from ``u`` to ``v``. @@ -17778,9 +17585,7 @@ def shortest_path(self, u, v, by_weight=False, algorithm=None, if u == v: return [u] - by_weight, weight_function = self._get_weight_function(by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight) + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, weight_function=weight_function, check_weight=check_weight) if algorithm is None: algorithm = 'Dijkstra_Bid' if by_weight else 'BFS_Bid' @@ -17791,8 +17596,7 @@ def shortest_path(self, u, v, by_weight=False, algorithm=None, weight_function = None if algorithm in ['BFS', 'Dijkstra_NetworkX', 'Bellman-Ford_Boost']: - all_paths = self.shortest_paths(u, algorithm=algorithm, by_weight=by_weight, - weight_function=weight_function, check_weight=False) + all_paths = self.shortest_paths(u, algorithm=algorithm, by_weight=by_weight, weight_function=weight_function, check_weight=False) if v in all_paths: return all_paths[v] return [] @@ -17800,6 +17604,7 @@ def shortest_path(self, u, v, by_weight=False, algorithm=None, return self._backend.bidirectional_dijkstra(u, v, weight_function) if algorithm == "Dijkstra_Bid_NetworkX": import networkx + if self.is_directed(): G = networkx.DiGraph([(e[0], e[1], {'weight': weight_function(e)}) for e in self.edge_iterator()]) else: @@ -17813,8 +17618,7 @@ def shortest_path(self, u, v, by_weight=False, algorithm=None, return self._backend.shortest_path(u, v) raise ValueError('unknown algorithm "{}"'.format(algorithm)) - def shortest_path_length(self, u, v, by_weight=False, algorithm=None, - weight_function=None, check_weight=True): + def shortest_path_length(self, u, v, by_weight=False, algorithm=None, weight_function=None, check_weight=True): r""" Return the minimal length of a path from ``u`` to ``v``. @@ -17962,9 +17766,7 @@ def shortest_path_length(self, u, v, by_weight=False, algorithm=None, if u == v: # to avoid a NetworkX bug return 0 - by_weight, weight_function = self._get_weight_function(by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight) + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, weight_function=weight_function, check_weight=check_weight) if algorithm is None: algorithm = 'Dijkstra_Bid' if by_weight else 'BFS_Bid' @@ -17979,12 +17781,14 @@ def shortest_path_length(self, u, v, by_weight=False, algorithm=None, if v in all_path_lengths: return all_path_lengths[v] from sage.rings.infinity import Infinity + return Infinity if algorithm == "Dijkstra_Bid": return self._backend.bidirectional_dijkstra(u, v, weight_function, distance_flag=True) if algorithm == "Dijkstra_Bid_NetworkX": import networkx + if self.is_directed(): G = networkx.DiGraph([(e[0], e[1], {'weight': weight_function(e)}) for e in self.edge_iterator()]) else: @@ -17994,6 +17798,7 @@ def shortest_path_length(self, u, v, by_weight=False, algorithm=None, return networkx.bidirectional_dijkstra(G, u, v)[0] except networkx.NetworkXNoPath: from sage.rings.infinity import Infinity + return Infinity elif algorithm == "BFS_Bid": return self._backend.shortest_path(u, v, distance_flag=True) @@ -18055,8 +17860,7 @@ def _check_weight_function(self, weight_function=None): if isinstance(temp, (str, bytes)): raise ValueError() except Exception: - raise ValueError("the weight function cannot find the " - "weight of " + str(e)) + raise ValueError("the weight function cannot find the " "weight of " + str(e)) def _get_weight_function(self, by_weight=False, weight_function=None, check_weight=True): r""" @@ -18124,17 +17928,20 @@ def _get_weight_function(self, by_weight=False, weight_function=None, check_weig by_weight = True if by_weight: if weight_function is None: + def weight_function(e): return 1 if e[2] is None else e[2] + if check_weight: self._check_weight_function(weight_function) else: + def weight_function(e): return 1 + return by_weight, weight_function - def shortest_paths(self, u, by_weight=False, algorithm=None, - weight_function=None, check_weight=True, cutoff=None): + def shortest_paths(self, u, by_weight=False, algorithm=None, weight_function=None, check_weight=True, cutoff=None): r""" Return a dictionary associating to each vertex ``v`` a shortest path from ``u`` to ``v``, if it exists. @@ -18284,21 +18091,19 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, ... ValueError: ('Contradictory paths found:', 'negative weights?') """ - by_weight, weight_function = self._get_weight_function(by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight) + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, weight_function=weight_function, check_weight=check_weight) if algorithm is None and not by_weight: algorithm = 'BFS' if algorithm == 'BFS': if by_weight: - raise ValueError("the 'BFS' algorithm does not work on " - "weighted graphs") + raise ValueError("the 'BFS' algorithm does not work on " "weighted graphs") return self._backend.shortest_path_all_vertices(u, cutoff) if algorithm == 'Dijkstra_NetworkX': import networkx + # If this is not present, an error might be raised by NetworkX if self.order() == 1 and self.has_vertex(u): return {u: [u]} @@ -18317,6 +18122,7 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, if algorithm in ['Dijkstra_Boost', 'Bellman-Ford_Boost', None]: from sage.graphs.base.boost_graph import shortest_paths + _, pred = shortest_paths(self, u, weight_function, algorithm) paths = {} for v in pred.keys(): @@ -18387,18 +18193,15 @@ def _path_length(self, path, by_weight=False, weight_function=None): """ if not path: from sage.rings.infinity import Infinity + return Infinity if by_weight or weight_function is not None: - _, weight_function = self._get_weight_function(by_weight=by_weight, - weight_function=weight_function, - check_weight=False) - return sum(weight_function((u, v, self.edge_label(u, v))) - for u, v in zip(path[:-1], path[1:])) + _, weight_function = self._get_weight_function(by_weight=by_weight, weight_function=weight_function, check_weight=False) + return sum(weight_function((u, v, self.edge_label(u, v))) for u, v in zip(path[:-1], path[1:])) return len(path) - 1 - def shortest_path_lengths(self, u, by_weight=False, algorithm=None, - weight_function=None, check_weight=True): + def shortest_path_lengths(self, u, by_weight=False, algorithm=None, weight_function=None, check_weight=True): r""" Return the length of a shortest path from ``u`` to any other vertex. @@ -18498,9 +18301,7 @@ def shortest_path_lengths(self, u, by_weight=False, algorithm=None, sage: d1 == d2 == d3 == d4 # needs networkx True """ - by_weight, weight_function = self._get_weight_function(by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight) + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, weight_function=weight_function, check_weight=check_weight) if algorithm is None and not by_weight: algorithm = 'BFS' @@ -18512,6 +18313,7 @@ def shortest_path_lengths(self, u, by_weight=False, algorithm=None, if algorithm == 'Dijkstra_NetworkX': import networkx + # If this is not present, an error might be raised by NetworkX if self.n_vertices() == 1 and next(self.vertex_iterator()) == u: return {u: [u]} @@ -18530,12 +18332,12 @@ def shortest_path_lengths(self, u, by_weight=False, algorithm=None, if algorithm in ['Dijkstra_Boost', 'Bellman-Ford_Boost', None]: from sage.graphs.base.boost_graph import shortest_paths + return shortest_paths(self, u, weight_function, algorithm)[0] raise ValueError('unknown algorithm "{}"'.format(algorithm)) - def shortest_path_all_pairs(self, by_weight=False, algorithm=None, - weight_function=None, check_weight=True): + def shortest_path_all_pairs(self, by_weight=False, algorithm=None, weight_function=None, check_weight=True): r""" Return a shortest path between each pair of vertices. @@ -18807,9 +18609,7 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, """ from sage.rings.infinity import Infinity - by_weight, weight_function = self._get_weight_function(by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight) + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, weight_function=weight_function, check_weight=check_weight) if algorithm is None: if by_weight: @@ -18821,21 +18621,23 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, algorithm = "BFS" if by_weight and algorithm in ['BFS', "Floyd-Warshall-Cython"]: - raise ValueError("algorithm '" + algorithm + "' does not work " - "with weights") + raise ValueError("algorithm '" + algorithm + "' does not work " "with weights") if algorithm == "BFS": from sage.graphs.distances_all_pairs import ( distances_and_predecessors_all_pairs, ) + return distances_and_predecessors_all_pairs(self) if algorithm == "Floyd-Warshall-Cython": from sage.graphs.distances_all_pairs import floyd_warshall + return floyd_warshall(self, distances=True) if algorithm == "Floyd-Warshall_Boost": from sage.graphs.base.boost_graph import floyd_warshall_shortest_paths + return floyd_warshall_shortest_paths(self, weight_function, distances=True, predecessors=True) if algorithm == "Floyd-Warshall_SciPy": @@ -18844,7 +18646,7 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, int_to_vertex = list(self) vertex_to_int = {u: i for i, u in enumerate(int_to_vertex)} if by_weight: - M = [[float('inf')]*n for _ in range(n)] + M = [[float('inf')] * n for _ in range(n)] for i in range(n): M[i][i] = 0 for e in self.edges(sort=False): @@ -18858,28 +18660,27 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, # We call the Floyd-Warshall method from SciPy import numpy # to ensure numpy 2.0 compatibility + if int(numpy.version.short_version[0]) > 1: numpy.set_printoptions(legacy="1.25") from numpy import array as np_array from scipy.sparse.csgraph import floyd_warshall - dd, pp = floyd_warshall(np_array(M), directed=self.is_directed(), - return_predecessors=True, unweighted=not by_weight) + + dd, pp = floyd_warshall(np_array(M), directed=self.is_directed(), return_predecessors=True, unweighted=not by_weight) # and format the result - dist = {int_to_vertex[i]: {int_to_vertex[j]: dd[i, j] - for j in range(n) if dd[i, j] != +Infinity} - for i in range(n)} - pred = {int_to_vertex[i]: {int_to_vertex[j]: (int_to_vertex[pp[i, j]] if i != j else None) - for j in range(n) if (i == j or pp[i, j] != -9999)} - for i in range(n)} + dist = {int_to_vertex[i]: {int_to_vertex[j]: dd[i, j] for j in range(n) if dd[i, j] != +Infinity} for i in range(n)} + pred = {int_to_vertex[i]: {int_to_vertex[j]: (int_to_vertex[pp[i, j]] if i != j else None) for j in range(n) if (i == j or pp[i, j] != -9999)} for i in range(n)} return dist, pred if algorithm == "Johnson_Boost": from sage.graphs.base.boost_graph import johnson_shortest_paths + return johnson_shortest_paths(self, weight_function, distances=True, predecessors=True) if algorithm == "Dijkstra_Boost": from sage.graphs.base.boost_graph import shortest_paths + dist = dict() pred = dict() for u in self: @@ -18890,14 +18691,9 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, dist = dict() pred = dict() for u in self: - paths = self.shortest_paths(u, by_weight=by_weight, - algorithm=algorithm, - weight_function=weight_function) - dist[u] = {v: self._path_length(p, by_weight=by_weight, - weight_function=weight_function) - for v, p in paths.items()} - pred[u] = {v: None if len(p) <= 1 else p[1] - for v, p in paths.items()} + paths = self.shortest_paths(u, by_weight=by_weight, algorithm=algorithm, weight_function=weight_function) + dist[u] = {v: self._path_length(p, by_weight=by_weight, weight_function=weight_function) for v, p in paths.items()} + pred[u] = {v: None if len(p) <= 1 else p[1] for v, p in paths.items()} return dist, pred if algorithm != "Floyd-Warshall-Python": @@ -18937,8 +18733,7 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, return dist, pred - def wiener_index(self, by_weight=False, algorithm=None, - weight_function=None, check_weight=True): + def wiener_index(self, by_weight=False, algorithm=None, weight_function=None, check_weight=True): r""" Return the Wiener index of ``self``. @@ -19088,9 +18883,7 @@ def wiener_index(self, by_weight=False, algorithm=None, elif self.order() == 1: return 0 - by_weight, weight_function = self._get_weight_function(by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight) + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, weight_function=weight_function, check_weight=check_weight) if algorithm in ['BFS', 'Floyd-Warshall-Cython']: if by_weight: @@ -19100,21 +18893,22 @@ def wiener_index(self, by_weight=False, algorithm=None, if algorithm == 'BFS' or (algorithm is None and not by_weight): from .distances_all_pairs import wiener_index + return wiener_index(self) if algorithm in ['Dijkstra_Boost', 'Bellman-Ford_Boost'] or (algorithm is None and by_weight): from .base.boost_graph import wiener_index - WI = wiener_index(self, algorithm=algorithm, - weight_function=weight_function, - check_weight=False) - elif (not self.is_connected() - or (self.is_directed() and not self.is_strongly_connected())): + WI = wiener_index(self, algorithm=algorithm, weight_function=weight_function, check_weight=False) + + elif not self.is_connected() or (self.is_directed() and not self.is_strongly_connected()): from sage.rings.infinity import Infinity + return Infinity elif algorithm == "Dijkstra_NetworkX": import networkx + if by_weight: if self.is_directed(): G = networkx.DiGraph([(e[0], e[1], {'weight': weight_function(e)}) for e in self.edges(sort=False)]) @@ -19126,14 +18920,11 @@ def wiener_index(self, by_weight=False, algorithm=None, else: G = networkx.Graph(list(self.edges(labels=False, sort=False))) G.add_nodes_from(self) - total = sum(sum(networkx.single_source_dijkstra_path_length(G, u).values()) - for u in G) + total = sum(sum(networkx.single_source_dijkstra_path_length(G, u).values()) for u in G) WI = total if self.is_directed() else (total / 2) else: - distances = self.shortest_path_all_pairs( - by_weight=by_weight, algorithm=algorithm, - weight_function=weight_function, check_weight=False)[0] + distances = self.shortest_path_all_pairs(by_weight=by_weight, algorithm=algorithm, weight_function=weight_function, check_weight=False)[0] total = sum(sum(u.values()) for u in distances.values()) WI = total if self.is_directed() else (total / 2) @@ -19142,8 +18933,7 @@ def wiener_index(self, by_weight=False, algorithm=None, return WI - def average_distance(self, by_weight=False, algorithm=None, - weight_function=None, check_weight=True): + def average_distance(self, by_weight=False, algorithm=None, weight_function=None, check_weight=True): r""" Return the average distance between vertices of the graph. @@ -19209,8 +18999,7 @@ def average_distance(self, by_weight=False, algorithm=None, """ if self.order() < 2: raise ValueError("average distance is not defined for empty or one-element graph") - WI = self.wiener_index(by_weight=by_weight, algorithm=algorithm, - weight_function=weight_function, check_weight=check_weight) + WI = self.wiener_index(by_weight=by_weight, algorithm=algorithm, weight_function=weight_function, check_weight=check_weight) f = 1 if self.is_directed() else 2 if WI in ZZ: return QQ((f * WI, self.order() * (self.order() - 1))) @@ -19218,10 +19007,7 @@ def average_distance(self, by_weight=False, algorithm=None, # Searches - def breadth_first_search(self, start, ignore_direction=False, - distance=None, neighbors=None, - report_distance=False, edges=False, - forbidden_vertices=None): + def breadth_first_search(self, start, ignore_direction=False, distance=None, neighbors=None, report_distance=False, edges=False, forbidden_vertices=None): """ Return an iterator over the vertices in a breadth-first ordering. @@ -19385,19 +19171,16 @@ def breadth_first_search(self, start, ignore_direction=False, ValueError: start vertex 1 is in the set of forbidden vertices """ from sage.rings.semirings.non_negative_integer_semiring import NN - if (distance is not None and distance not in NN): + + if distance is not None and distance not in NN: raise ValueError("distance must be a nonnegative integer, not {0}".format(distance)) - if (report_distance and edges): + if report_distance and edges: raise ValueError("parameters edges and report_distance cannot be ``True`` simultaneously") # Preferably use the Cython implementation - if (neighbors is None and not isinstance(start, list) and distance is None - and hasattr(self._backend, "breadth_first_search")): - yield from self._backend.breadth_first_search( - start, ignore_direction=ignore_direction, - report_distance=report_distance, edges=edges, - forbidden_vertices=forbidden_vertices) + if neighbors is None and not isinstance(start, list) and distance is None and hasattr(self._backend, "breadth_first_search"): + yield from self._backend.breadth_first_search(start, ignore_direction=ignore_direction, report_distance=report_distance, edges=edges, forbidden_vertices=forbidden_vertices) else: if neighbors is None: if not self._directed or ignore_direction: @@ -19439,12 +19222,11 @@ def breadth_first_search(self, start, ignore_direction=False, if edges: yield v, w elif report_distance: - yield w, d+1 + yield w, d + 1 else: yield w - def depth_first_search(self, start, ignore_direction=False, - neighbors=None, edges=False, forbidden_vertices=None): + def depth_first_search(self, start, ignore_direction=False, neighbors=None, edges=False, forbidden_vertices=None): """ Return an iterator over the vertices in a depth-first ordering. @@ -19572,10 +19354,8 @@ def depth_first_search(self, start, ignore_direction=False, ValueError: start vertex 1 is in the set of forbidden vertices """ # Preferably use the Cython implementation - if (neighbors is None and not isinstance(start, list) - and hasattr(self._backend, "depth_first_search") and not edges): - yield from self._backend.depth_first_search(start, ignore_direction=ignore_direction, - forbidden_vertices=forbidden_vertices) + if neighbors is None and not isinstance(start, list) and hasattr(self._backend, "depth_first_search") and not edges: + yield from self._backend.depth_first_search(start, ignore_direction=ignore_direction, forbidden_vertices=forbidden_vertices) else: if neighbors is None: if not self._directed or ignore_direction: @@ -19703,6 +19483,7 @@ def add_clique(self, vertices, loops=False): if vertices: self._scream_if_immutable() import itertools + if loops: if self.is_directed(): self.add_edges(itertools.product(vertices, repeat=2)) @@ -19980,6 +19761,7 @@ def to_simple(self, to_undirected=True, keep_label='any', immutable=None): """ if to_undirected: from sage.graphs.graph import Graph + g = Graph(self, immutable=False) else: g = self.copy(immutable=False) @@ -20073,9 +19855,9 @@ def disjoint_union(self, other, labels='pairs', immutable=None): r_other = {v: (1, v) for v in other} from itertools import chain + vertices = chain(r_self.values(), r_other.values()) - edges = chain(((r_self[u], r_self[v], w) for u, v, w in self.edge_iterator()), - ((r_other[u], r_other[v], w) for u, v, w in other.edge_iterator())) + edges = chain(((r_self[u], r_self[v], w) for u, v, w in self.edge_iterator()), ((r_other[u], r_other[v], w) for u, v, w in other.edge_iterator())) a = self.name() if not a: @@ -20096,9 +19878,7 @@ def disjoint_union(self, other, labels='pairs', immutable=None): else: from sage.graphs.graph import Graph as GT - return GT([vertices, edges], format='vertices_and_edges', - weighted=weighted, loops=loops, multiedges=multiedges, - name=name, immutable=immutable) + return GT([vertices, edges], format='vertices_and_edges', weighted=weighted, loops=loops, multiedges=multiedges, name=name, immutable=immutable) def union(self, other, immutable=None): """ @@ -20190,10 +19970,8 @@ def union(self, other, immutable=None): from sage.graphs.graph import Graph as GT from itertools import chain - return GT([chain(self, other), - chain(self.edge_iterator(), other.edge_iterator())], - format='vertices_and_edges', weighted=weighted, loops=loops, - multiedges=multiedges, immutable=immutable) + + return GT([chain(self, other), chain(self.edge_iterator(), other.edge_iterator())], format='vertices_and_edges', weighted=weighted, loops=loops, multiedges=multiedges, immutable=immutable) def cartesian_product(self, other, immutable=None): r""" @@ -20296,15 +20074,10 @@ def cartesian_product(self, other, immutable=None): loops = self.has_loops() or other.has_loops() vertices = ((u, v) for u in self for v in other) from itertools import chain - edges = chain((((u, v), (w, v)) - for u, w in self.edge_iterator(labels=False) - for v in other), - (((u, v), (u, x)) - for v, x in other.edge_iterator(labels=False) - for u in self)) - return GT([vertices, edges], format='vertices_and_edges', - loops=loops, immutable=immutable) + edges = chain((((u, v), (w, v)) for u, w in self.edge_iterator(labels=False) for v in other), (((u, v), (u, x)) for v, x in other.edge_iterator(labels=False) for u in self)) + + return GT([vertices, edges], format='vertices_and_edges', loops=loops, immutable=immutable) def tensor_product(self, other, immutable=None): r""" @@ -20400,19 +20173,14 @@ def tensor_product(self, other, immutable=None): self._scream_if_not_simple(allow_loops=True) if self._directed and other._directed: from sage.graphs.digraph import DiGraph as GT - edges = (((u, v), (w, x)) - for u, w in self.edge_iterator(labels=False) - for v, x in other.edge_iterator(labels=False)) + + edges = (((u, v), (w, x)) for u, w in self.edge_iterator(labels=False) for v, x in other.edge_iterator(labels=False)) elif (not self._directed) and (not other._directed): from itertools import chain from sage.graphs.graph import Graph as GT - edges = chain((((u, v), (w, x)) - for u, w in self.edge_iterator(labels=False) - for v, x in other.edge_iterator(labels=False)), - (((u, x), (w, v)) - for u, w in self.edge_iterator(labels=False) - for v, x in other.edge_iterator(labels=False))) + + edges = chain((((u, v), (w, x)) for u, w in self.edge_iterator(labels=False) for v, x in other.edge_iterator(labels=False)), (((u, x), (w, v)) for u, w in self.edge_iterator(labels=False) for v, x in other.edge_iterator(labels=False))) else: raise TypeError('the graphs should be both directed or both undirected') @@ -20420,8 +20188,7 @@ def tensor_product(self, other, immutable=None): immutable = self.is_immutable() and other.is_immutable() loops = self.has_loops() or other.has_loops() vertices = ((u, v) for u in self for v in other) - return GT([vertices, edges], format='vertices_and_edges', - loops=loops, immutable=immutable) + return GT([vertices, edges], format='vertices_and_edges', loops=loops, immutable=immutable) categorical_product = tensor_product kronecker_product = tensor_product @@ -20521,15 +20288,9 @@ def lexicographic_product(self, other, immutable=None): loops = self.has_loops() or other.has_loops() vertices = ((u, v) for u in self for v in other) from itertools import chain - edges = chain((((u, v), (w, x)) - for u, w in self.edge_iterator(labels=False) - for v in other - for x in other), - (((u, v), (u, x)) - for u in self - for v, x in other.edge_iterator(labels=False))) - return GT([vertices, edges], format='vertices_and_edges', - loops=loops, immutable=immutable) + + edges = chain((((u, v), (w, x)) for u, w in self.edge_iterator(labels=False) for v in other for x in other), (((u, v), (u, x)) for u in self for v, x in other.edge_iterator(labels=False))) + return GT([vertices, edges], format='vertices_and_edges', loops=loops, immutable=immutable) def strong_product(self, other, immutable=None): r""" @@ -20633,24 +20394,18 @@ def strong_product(self, other, immutable=None): loops = self.has_loops() or other.has_loops() vertices = ((u, v) for u in self for v in other) - edges_1 = (((u, v), (w, v)) - for u, w in self.edge_iterator(labels=False) for v in other) - edges_2 = (((u, v), (u, x)) - for v, x in other.edge_iterator(labels=False) for u in self) - edges_3 = (((u, v), (w, x)) - for u, w in self.edge_iterator(labels=False) - for v, x in other.edge_iterator(labels=False)) + edges_1 = (((u, v), (w, v)) for u, w in self.edge_iterator(labels=False) for v in other) + edges_2 = (((u, v), (u, x)) for v, x in other.edge_iterator(labels=False) for u in self) + edges_3 = (((u, v), (w, x)) for u, w in self.edge_iterator(labels=False) for v, x in other.edge_iterator(labels=False)) if self._directed: edges_4 = () else: - edges_4 = (((w, v), (u, x)) - for u, w in self.edge_iterator(labels=False) - for v, x in other.edge_iterator(labels=False)) + edges_4 = (((w, v), (u, x)) for u, w in self.edge_iterator(labels=False) for v, x in other.edge_iterator(labels=False)) from itertools import chain + edges = chain(edges_1, edges_2, edges_3, edges_4) - return GT([vertices, edges], format='vertices_and_edges', - loops=loops, immutable=immutable) + return GT([vertices, edges], format='vertices_and_edges', loops=loops, immutable=immutable) def disjunctive_product(self, other, immutable=None): r""" @@ -20746,18 +20501,12 @@ def disjunctive_product(self, other, immutable=None): immutable = self.is_immutable() and other.is_immutable() loops = self.has_loops() or other.has_loops() vertices = ((u, v) for u in self for v in other) - edges_1 = (((u, v), (w, x)) - for u, w in self.edge_iterator(labels=False) - for v in other - for x in other) - edges_2 = (((u, v), (w, x)) - for v, x in other.edge_iterator(labels=False) - for u in self - for w in self) + edges_1 = (((u, v), (w, x)) for u, w in self.edge_iterator(labels=False) for v in other for x in other) + edges_2 = (((u, v), (w, x)) for v, x in other.edge_iterator(labels=False) for u in self for w in self) from itertools import chain + edges = chain(edges_1, edges_2) - return GT([vertices, edges], format='vertices_and_edges', - loops=loops, immutable=immutable) + return GT([vertices, edges], format='vertices_and_edges', loops=loops, immutable=immutable) def transitive_closure(self, loops=None, immutable=None): r""" @@ -20849,8 +20598,7 @@ def transitive_closure(self, loops=None, immutable=None): from sage.graphs.digraph import DiGraph as GT else: from sage.graphs.graph import Graph as GT - return GT([self, edges], format='vertices_and_edges', loops=loops, - immutable=immutable, name=name) + return GT([self, edges], format='vertices_and_edges', loops=loops, immutable=immutable, name=name) def transitive_reduction(self, immutable=None): r""" @@ -20915,6 +20663,7 @@ def transitive_reduction(self, immutable=None): if self.is_directed(): if self.is_directed_acyclic(): from sage.graphs.generic_graph_pyx import transitive_reduction_acyclic + return transitive_reduction_acyclic(self, immutable=immutable) G = self.copy(immutable=False) @@ -20936,16 +20685,15 @@ def transitive_reduction(self, immutable=None): if self.is_connected(): CC = [self] else: - CC = (self.subgraph(c) - for c in self.connected_components(sort=False) if len(c) > 1) + CC = (self.subgraph(c) for c in self.connected_components(sort=False) if len(c) > 1) def edges(): for g in CC: yield from g.min_spanning_tree(weight_function=lambda e: 1) from sage.graphs.graph import Graph - return Graph([self, edges()], format='vertices_and_edges', - immutable=immutable) + + return Graph([self, edges()], format='vertices_and_edges', immutable=immutable) def is_transitively_reduced(self): r""" @@ -20987,6 +20735,7 @@ def is_transitively_reduced(self): return self == self.transitive_reduction() from sage.rings.infinity import Infinity + G = self.copy(immutable=False) for e in self.edge_iterator(): G.delete_edge(e) @@ -21097,12 +20846,15 @@ def _color_by_label(self, format='hex', as_function=False, default_color='black' labels.append(label) from sage.plot.colors import rainbow + colors = rainbow(len(labels), format=format) color_of_label = dict(zip(labels, colors)) color_of_label = color_of_label.__getitem__ elif isinstance(format, dict): + def color_of_label(label): return format.get(label, default_color) + else: # This assumes that ``format`` is already a function color_of_label = format @@ -21140,6 +20892,7 @@ def latex_options(self): """ if self._latex_opts is None: from sage.graphs.graph_latex import GraphLatex + self._latex_opts = GraphLatex(self) return self._latex_opts @@ -21377,6 +21130,7 @@ def layout_ranked(self, heights=None, dim=2, spring=False, **options): assert heights is not None from sage.misc.randstate import current_randstate + random = current_randstate().python_random().random if not self.order(): @@ -21401,11 +21155,7 @@ def layout_ranked(self, heights=None, dim=2, spring=False, **options): # - If k < 1, the layout gets squished horizontally. # - If k > 1, then two adjacent vertices in consecutive levels tend # to be further away than desired. - newpos = spring_layout_fast(self, - vpos=pos, - dim=dim, - height=True, - **options) + newpos = spring_layout_fast(self, vpos=pos, dim=dim, height=True, **options) # spring_layout_fast actually *does* touch the last coordinates # (conversion to floats + translation) # We restore back the original height. @@ -21445,6 +21195,7 @@ def layout_extend_randomly(self, pos, dim=2): """ assert dim == 2 # 3d not yet implemented from sage.misc.randstate import current_randstate + random = current_randstate().python_random().random xmin, xmax, ymin, ymax = self._layout_bounding_box(pos) @@ -21504,12 +21255,10 @@ def layout_circular(self, dim=2, center=(0, 0), radius=1, shift=0, angle=0, **op """ assert dim == 2, "3D circular layout not implemented" from math import pi - return self._circle_embedding(self.vertices(sort=True), center=(0, 0), - radius=1, shift=0, angle=pi/2, - return_dict=True) - def layout_forest(self, tree_orientation='down', forest_roots=None, - **options): + return self._circle_embedding(self.vertices(sort=True), center=(0, 0), radius=1, shift=0, angle=pi / 2, return_dict=True) + + def layout_forest(self, tree_orientation='down', forest_roots=None, **options): """ Return an ordered forest layout for this graph. @@ -21566,14 +21315,9 @@ def layout_forest(self, tree_orientation='down', forest_roots=None, if not self: return dict() # Compute the layout component by component - return layout_split(self.__class__.layout_tree, - self, - tree_orientation=tree_orientation, - forest_roots=forest_roots, - **options) - - def layout_tree(self, tree_orientation='down', tree_root=None, - dim=2, **options): + return layout_split(self.__class__.layout_tree, self, tree_orientation=tree_orientation, forest_roots=forest_roots, **options) + + def layout_tree(self, tree_orientation='down', tree_root=None, dim=2, **options): r""" Return an ordered tree layout for this graph. @@ -21676,9 +21420,9 @@ def layout_tree(self, tree_orientation='down', tree_root=None, return dict() from sage.graphs.graph import Graph + if not Graph(self).is_tree(): - raise RuntimeError("cannot use tree layout on this graph: " - "self.is_tree() returns False") + raise RuntimeError("cannot use tree layout on this graph: " "self.is_tree() returns False") emb = self.get_embedding() @@ -21773,7 +21517,7 @@ def slide(v, dx): else: ct = emb[t] idx = ct.index(pt) - ct = ct[idx + 1:] + ct[:idx] + ct = ct[idx + 1 :] + ct[:idx] children[t] = ct for c in ct: @@ -21875,6 +21619,7 @@ def layout_graphviz(self, dim=2, prog='dot', **options): key_to_vertex = {key(v): v for v in self} import dot2tex + positions = dot2tex.dot2tex(self.graphviz_string(**options), format='positions', prog=prog) return {key_to_vertex[key]: pos for key, pos in positions.items()} @@ -22088,6 +21833,7 @@ def _circle_embedding(self, vertices, center=(0, 0), radius=1, shift=0, angle=0, pos = self._pos = {} from math import cos, pi, sin + for i, v in enumerate(vertices): theta = angle + 2 * (i + shift) * pi / n # We round cos and sin to avoid results like 1.2246467991473532e-16 @@ -22161,7 +21907,7 @@ def _line_embedding(self, vertices, first=(0, 0), last=(0, 1), return_dict=False if pos is None: pos = self._pos = {} - n = len(vertices) - 1. + n = len(vertices) - 1.0 if n: fx, fy = first @@ -22214,6 +21960,7 @@ def graphplot(self, **options): Graphics object consisting of 22 graphics primitives """ from sage.graphs.graph_plot import GraphPlot + return GraphPlot(graph=self, options=options) def _rich_repr_(self, display_manager, **kwds): @@ -22240,8 +21987,8 @@ def _rich_repr_(self, display_manager, **kwds): sage: dm.preferences.supplemental_plot = 'never' """ prefs = display_manager.preferences - is_small = (0 < self.n_vertices() < 20) - can_plot = (prefs.supplemental_plot != 'never') + is_small = 0 < self.n_vertices() < 20 + can_plot = prefs.supplemental_plot != 'never' plot_graph = can_plot and (prefs.supplemental_plot == 'always' or is_small) # Under certain circumstances we display the plot as graphics if plot_graph: @@ -22257,7 +22004,7 @@ def _rich_repr_(self, display_manager, **kwds): text = repr(self) # latex() produces huge tikz environment, override tp = display_manager.types - if (prefs.text == 'latex' and tp.OutputLatex in display_manager.supported_output()): + if prefs.text == 'latex' and tp.OutputLatex in display_manager.supported_output(): return tp.OutputLatex(r'\text{{{0}}}'.format(text)) return tp.OutputPlainText(text) @@ -22617,6 +22364,7 @@ def show(self, method='matplotlib', **kwds): if method == "js": from sage.doctest import DOCTEST_MODE from sage.graphs.graph_plot_js import gen_html_code + filename = gen_html_code(self, **kwds) if DOCTEST_MODE: @@ -22624,10 +22372,12 @@ def show(self, method='matplotlib', **kwds): import os from sage.misc.viewer import browser + os.system('%s %s 2>/dev/null 1>/dev/null &' % (browser(), filename)) return from .graph_plot import graphplot_options + # This dictionary only contains the options that graphplot # understands. These options are removed from kwds at the same # time. @@ -22635,11 +22385,7 @@ def show(self, method='matplotlib', **kwds): return self.graphplot(**plot_kwds).show(**kwds) - def plot3d(self, bgcolor=(1, 1, 1), - vertex_colors=None, vertex_size=0.06, vertex_labels=False, - edge_colors=None, edge_size=0.02, edge_size2=0.0325, - pos3d=None, color_by_label=False, - engine='threejs', **kwds): + def plot3d(self, bgcolor=(1, 1, 1), vertex_colors=None, vertex_size=0.06, vertex_labels=False, edge_colors=None, edge_size=0.02, edge_size2=0.0325, pos3d=None, color_by_label=False, engine='threejs', **kwds): r""" Plot a graph in three dimensions. @@ -22798,6 +22544,7 @@ def plot3d(self, bgcolor=(1, 1, 1), - :meth:`graphviz_string` """ from . import graph_plot + layout_options = {key: kwds[key] for key in kwds.keys() if key in graph_plot.layout_options} kwds = {key: kwds[key] for key in kwds.keys() if key not in graph_plot.layout_options} if pos3d is None: @@ -22808,11 +22555,13 @@ def plot3d(self, bgcolor=(1, 1, 1), if engine in ['threejs', 'jmol']: from sage.plot.plot3d.all import arrow3d, line3d, sphere, text3d from sage.plot.plot3d.texture import Texture + kwds.setdefault('aspect_ratio', [1, 1, 1]) if vertex_colors is None: if 'partition' in kwds: from sage.plot.colors import rainbow + partition = kwds['partition'] l = len(partition) R = rainbow(l) @@ -22859,8 +22608,7 @@ def plot3d(self, bgcolor=(1, 1, 1), raise KeyError("you have not specified positions for all the vertices") elif engine == 'tachyon': - TT, pos3d = tachyon_vertex_plot(self, bgcolor=bgcolor, vertex_colors=vertex_colors, - vertex_size=vertex_size, pos3d=pos3d, **kwds) + TT, pos3d = tachyon_vertex_plot(self, bgcolor=bgcolor, vertex_colors=vertex_colors, vertex_size=vertex_size, pos3d=pos3d, **kwds) if color_by_label: if edge_colors is None: @@ -22874,32 +22622,20 @@ def plot3d(self, bgcolor=(1, 1, 1), for color in edge_colors: i += 1 - TT.texture('edge_color_%d' % i, ambient=0.1, diffuse=0.9, - specular=0.03, opacity=1.0, color=color) + TT.texture('edge_color_%d' % i, ambient=0.1, diffuse=0.9, specular=0.03, opacity=1.0, color=color) if self._directed: for u, v, l in edge_colors[color]: - TT.fcylinder((pos3d[u][0], pos3d[u][1], pos3d[u][2]), - (pos3d[v][0], pos3d[v][1], pos3d[v][2]), - edge_size, 'edge_color_%d' % i) - TT.fcylinder((0.25 * pos3d[u][0] + 0.75 * pos3d[v][0], - 0.25 * pos3d[u][1] + 0.75 * pos3d[v][1], - 0.25 * pos3d[u][2] + 0.75 * pos3d[v][2]), - (pos3d[v][0], pos3d[v][1], pos3d[v][2]), - edge_size2, 'edge_color_%d' % i) + TT.fcylinder((pos3d[u][0], pos3d[u][1], pos3d[u][2]), (pos3d[v][0], pos3d[v][1], pos3d[v][2]), edge_size, 'edge_color_%d' % i) + TT.fcylinder((0.25 * pos3d[u][0] + 0.75 * pos3d[v][0], 0.25 * pos3d[u][1] + 0.75 * pos3d[v][1], 0.25 * pos3d[u][2] + 0.75 * pos3d[v][2]), (pos3d[v][0], pos3d[v][1], pos3d[v][2]), edge_size2, 'edge_color_%d' % i) else: for u, v, l in edge_colors[color]: - TT.fcylinder((pos3d[u][0], pos3d[u][1], pos3d[u][2]), - (pos3d[v][0], pos3d[v][1], pos3d[v][2]), - edge_size, 'edge_color_%d' % i) + TT.fcylinder((pos3d[u][0], pos3d[u][1], pos3d[u][2]), (pos3d[v][0], pos3d[v][1], pos3d[v][2]), edge_size, 'edge_color_%d' % i) return TT raise TypeError("rendering engine (%s) not implemented" % engine) - def show3d(self, bgcolor=(1, 1, 1), vertex_colors=None, vertex_size=0.06, - edge_colors=None, edge_size=0.02, edge_size2=0.0325, - pos3d=None, color_by_label=False, - engine='threejs', **kwds): + def show3d(self, bgcolor=(1, 1, 1), vertex_colors=None, vertex_size=0.06, edge_colors=None, edge_size=0.02, edge_size2=0.0325, pos3d=None, color_by_label=False, engine='threejs', **kwds): """ Plot the graph and show the resulting plot. @@ -22995,10 +22731,7 @@ def show3d(self, bgcolor=(1, 1, 1), vertex_colors=None, vertex_size=0.06, ....: (0, 1, 0): [(0, 2, None)], ....: (0, 0, 1): [(1, 2, None)]}) """ - self.plot3d(bgcolor=bgcolor, vertex_colors=vertex_colors, - edge_colors=edge_colors, vertex_size=vertex_size, engine=engine, - edge_size=edge_size, edge_size2=edge_size2, pos3d=pos3d, - color_by_label=color_by_label, **kwds).show() + self.plot3d(bgcolor=bgcolor, vertex_colors=vertex_colors, edge_colors=edge_colors, vertex_size=vertex_size, engine=engine, edge_size=edge_size, edge_size2=edge_size2, pos3d=pos3d, color_by_label=color_by_label, **kwds).show() def _keys_for_vertices(self): """ @@ -23026,16 +22759,11 @@ def _keys_for_vertices(self): def get_label(vertex): return label[vertex] + return get_label # String representation to be used by other programs - @options(labels='string', - vertex_labels=True, edge_labels=False, - edge_color=None, edge_colors=None, - edge_options=(), - color_by_label=False, - rankdir='down', - subgraph_clusters=[]) + @options(labels='string', vertex_labels=True, edge_labels=False, edge_color=None, edge_colors=None, edge_options=(), color_by_label=False, rankdir='down', subgraph_clusters=[]) def graphviz_string(self, **options): r""" Return a representation in the ``dot`` language. @@ -23565,8 +23293,7 @@ def graphviz_string(self, **options): color_by_edge = {} for color in options['edge_colors'].keys(): for edge in options['edge_colors'][color]: - assert isinstance(edge, (list, tuple)) and len(edge) >= 2 and len(edge) <= 3, \ - "%s is not a valid format for edge" % (edge) + assert isinstance(edge, (list, tuple)) and len(edge) >= 2 and len(edge) <= 3, "%s is not a valid format for edge" % (edge) u = edge[0] v = edge[1] assert self.has_edge(*edge), "%s is not an edge" % (edge) @@ -23590,8 +23317,7 @@ def graphviz_string(self, **options): if options['rankdir'] not in directions: raise ValueError("rankdir should be one of %s" % directions.keys()) s += ' rankdir=%s\n' % (directions[options['rankdir']]) - if (options['vertex_labels'] and - options['labels'] == "latex"): # not a perfect option name + if options['vertex_labels'] and options['labels'] == "latex": # not a perfect option name # TODO: why do we set this only for latex labels? s += ' node [shape="plaintext"];\n' @@ -23622,22 +23348,12 @@ def graphviz_string(self, **options): # edges for loop for u, v, label in self.edge_iterator(): - edge_options = { - 'dir': default_edge_dir, - 'backward': False, - 'dot': None, - 'edge_string': default_edge_string, - 'color': default_color, - 'label': label, - 'label_style': options['labels'] if options['edge_labels'] else None - } + edge_options = {'dir': default_edge_dir, 'backward': False, 'dot': None, 'edge_string': default_edge_string, 'color': default_color, 'label': label, 'label_style': options['labels'] if options['edge_labels'] else None} for f in edge_option_functions: edge_options.update(f((u, v, label))) if edge_options['edge_string'] not in ['--', '->']: - raise ValueError("edge_string(='{}') in edge_options dict for " - "the edge ({}, {}) should be '--' or '->'" - .format(edge_options['edge_string'], u, v)) + raise ValueError("edge_string(='{}') in edge_options dict for " "the edge ({}, {}) should be '--' or '->'".format(edge_options['edge_string'], u, v)) dot_options = [] @@ -23672,14 +23388,11 @@ def graphviz_string(self, **options): elif edge_options['dir'] in ['forward', 'back', 'both', 'none']: dot_options.append('dir={}'.format(edge_options['dir'])) else: - raise ValueError("dir(='{}') in edge_options dict for the" - " edge ({}, {}) should be 'forward', 'back'," - " 'both', or 'none'" - .format(edge_options['dir'], u, v)) + raise ValueError("dir(='{}') in edge_options dict for the" " edge ({}, {}) should be 'forward', 'back'," " 'both', or 'none'".format(edge_options['dir'], u, v)) s += ' %s %s %s' % (key(u), edge_options['edge_string'], key(v)) if dot_options: - s += " [" + ", ".join(dot_options)+"]" + s += " [" + ", ".join(dot_options) + "]" s += ";\n" s += "}" @@ -24287,10 +24000,7 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input=True, c if not inplace: G = copy(self) - perm2 = G.relabel(perm, - return_map=return_map, - check_input=check_input, - complete_partial_function=complete_partial_function) + perm2 = G.relabel(perm, return_map=return_map, check_input=check_input, complete_partial_function=complete_partial_function) if immutable is None: immutable = self.is_immutable() @@ -24462,6 +24172,7 @@ def is_equitable(self, partition, quotient_matrix=False): False """ from sage.misc.flatten import flatten + if sorted(flatten(partition, max_level=1)) != self.vertices(sort=True): raise TypeError("Partition (%s) is not valid for this graph: vertices are incorrect." % partition) if any(not cell for cell in partition): @@ -24469,6 +24180,7 @@ def is_equitable(self, partition, quotient_matrix=False): if quotient_matrix: from sage.matrix.constructor import Matrix from sage.rings.integer_ring import IntegerRing + n = len(partition) M = Matrix(IntegerRing(), n) for i in range(n): @@ -24551,6 +24263,7 @@ def coarsest_equitable_refinement(self, partition, sparse=True): Melbourne, 1976. """ from sage.misc.flatten import flatten + if set(flatten(partition, max_level=1)) != set(self): raise TypeError("partition (%s) is not valid for this graph: vertices are incorrect" % partition) if any(len(cell) == 0 for cell in partition): @@ -24564,9 +24277,11 @@ def coarsest_equitable_refinement(self, partition, sparse=True): n = G.order() if sparse: from sage.graphs.base.sparse_graph import SparseGraph + CG = SparseGraph(n) else: from sage.graphs.base.dense_graph import DenseGraph + CG = DenseGraph(n) if G.is_directed(): for i, j in G.edge_iterator(labels=False): @@ -24579,12 +24294,11 @@ def coarsest_equitable_refinement(self, partition, sparse=True): from sage.groups.perm_gps.partn_ref.refinement_graphs import ( coarsest_equitable_refinement, ) + result = coarsest_equitable_refinement(CG, partition, G._directed) return [[perm_from[b] for b in cell] for cell in result] - def automorphism_group(self, partition=None, verbosity=0, - edge_labels=False, order=False, - return_group=True, orbits=False, algorithm=None): + def automorphism_group(self, partition=None, verbosity=0, edge_labels=False, order=False, return_group=True, orbits=False, algorithm=None): """ Return the automorphism group of the graph. @@ -24817,6 +24531,7 @@ def automorphism_group(self, partition=None, verbosity=0, [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]] """ from sage.features.bliss import Bliss + have_bliss = Bliss().is_present() # See trac #21704 @@ -24825,13 +24540,12 @@ def automorphism_group(self, partition=None, verbosity=0, raise NotImplementedError("algorithm 'bliss' cannot be used for graph with multiedges") have_bliss = False - if (algorithm == 'bliss' or # explicit choice from the user; or - (algorithm is None and # by default - have_bliss)): + if algorithm == 'bliss' or (algorithm is None and have_bliss): # explicit choice from the user; or # by default Bliss().require() from sage.graphs.bliss import automorphism_group + A = automorphism_group(self, partition, use_edge_labels=edge_labels) # If the user only wants the automorphism group, lets return it @@ -24860,15 +24574,14 @@ def automorphism_group(self, partition=None, verbosity=0, from sage.graphs.graph import Graph from sage.groups.perm_gps.partn_ref.refinement_graphs import search_tree from sage.groups.perm_gps.permgroup import PermutationGroup - dig = (self._directed or self.has_loops()) + + dig = self._directed or self.has_loops() if partition is None: partition = [list(self)] if edge_labels or self.has_multiple_edges(): - ret = graph_isom_equivalent_non_edge_labeled_graph(self, partition=partition, - return_relabeling=True, - ignore_edge_labels=(not edge_labels)) + ret = graph_isom_equivalent_non_edge_labeled_graph(self, partition=partition, return_relabeling=True, ignore_edge_labels=(not edge_labels)) G, partition, relabeling = ret G_vertices = list(chain(*partition)) G_to = {u: i for i, u in enumerate(G_vertices)} @@ -24940,7 +24653,8 @@ def automorphism_group(self, partition=None, verbosity=0, # We translate the integer permutations into a collection of # cycles. from sage.combinat.permutation import Permutation - gens = [Permutation(x+1 for x in aa).to_cycles() for aa in a] + + gens = [Permutation(x + 1 for x in aa).to_cycles() for aa in a] # We relabel the cycles using the vertices' names instead of integers n = self.order() @@ -24954,6 +24668,7 @@ def automorphism_group(self, partition=None, verbosity=0, if orbits: G_from = {G_to[v]: v for v in G_to} from sage.groups.perm_gps.partn_ref.refinement_graphs import get_orbits + output.append([[G_from[v] for v in W] for W in get_orbits(a, self.n_vertices())]) if len(output) == 1: @@ -24962,9 +24677,7 @@ def automorphism_group(self, partition=None, verbosity=0, return tuple(output) return None - def is_vertex_transitive(self, partition=None, verbosity=0, - edge_labels=False, order=False, - return_group=True, orbits=False): + def is_vertex_transitive(self, partition=None, verbosity=0, edge_labels=False, order=False, return_group=True, orbits=False): """ Return whether the automorphism group of ``self`` is transitive within the partition provided, by default the unit partition of the @@ -24996,17 +24709,11 @@ def is_vertex_transitive(self, partition=None, verbosity=0, if not all(self.degree(x) == d for x in p): return False - new_partition = self.automorphism_group(partition, - verbosity=verbosity, - edge_labels=edge_labels, - order=False, - return_group=False, orbits=True) + new_partition = self.automorphism_group(partition, verbosity=verbosity, edge_labels=edge_labels, order=False, return_group=False, orbits=True) - return (len(partition) == len(new_partition)) + return len(partition) == len(new_partition) - def is_hamiltonian(self, solver=None, constraint_generation=None, - verbose=0, verbose_constraints=False, - *, integrality_tolerance=1e-3): + def is_hamiltonian(self, solver=None, constraint_generation=None, verbose=0, verbose_constraints=False, *, integrality_tolerance=1e-3): r""" Test whether the current graph is Hamiltonian. @@ -25087,11 +24794,9 @@ def is_hamiltonian(self, solver=None, constraint_generation=None, True """ from sage.categories.sets_cat import EmptySetError + try: - self.traveling_salesman_problem(use_edge_labels=False, solver=solver, - constraint_generation=constraint_generation, - verbose=verbose, verbose_constraints=verbose_constraints, - integrality_tolerance=integrality_tolerance) + self.traveling_salesman_problem(use_edge_labels=False, solver=solver, constraint_generation=constraint_generation, verbose=verbose, verbose_constraints=verbose_constraints, integrality_tolerance=integrality_tolerance) return True except EmptySetError: return False @@ -25339,10 +25044,7 @@ def is_isomorphic(self, other, certificate=False, verbosity=0, edge_labels=False if not self.order() and not other.order(): return (True, None) if certificate else True - if (self.is_directed() != other.is_directed() or - self.order() != other.order() or - self.size() != other.size() or - self.degree_sequence() != other.degree_sequence()): + if self.is_directed() != other.is_directed() or self.order() != other.order() or self.size() != other.size() or self.degree_sequence() != other.degree_sequence(): if certificate: return False, None return False @@ -25354,23 +25056,22 @@ def is_isomorphic(self, other, certificate=False, verbosity=0, edge_labels=False if edge_labels or self.has_multiple_edges(): if edge_labels and sorted(self.edge_labels(), key=str) != sorted(other.edge_labels(), key=str): return (False, None) if certificate else False - ret = graph_isom_equivalent_non_edge_labeled_graph(self, return_relabeling=True, - ignore_edge_labels=(not edge_labels), - return_edge_labels=True) + ret = graph_isom_equivalent_non_edge_labeled_graph(self, return_relabeling=True, ignore_edge_labels=(not edge_labels), return_edge_labels=True) G, partition, relabeling, G_edge_labels = ret self_vertices = sum(partition, []) - ret = graph_isom_equivalent_non_edge_labeled_graph(other, return_relabeling=True, - ignore_edge_labels=(not edge_labels), - return_edge_labels=True) + ret = graph_isom_equivalent_non_edge_labeled_graph(other, return_relabeling=True, ignore_edge_labels=(not edge_labels), return_edge_labels=True) G2, partition2, relabeling2, G2_edge_labels = ret if [len(_) for _ in partition] != [len(_) for _ in partition2]: return (False, None) if certificate else False if edge_labels: + def multilabel(e): return e + else: + def multilabel(e): return [[None, el[1]] for el in e] @@ -25386,9 +25087,11 @@ def multilabel(e): G_to = {u: i for i, u in enumerate(self_vertices)} if self._directed: from sage.graphs.digraph import DiGraph + DoDG = DiGraph else: from sage.graphs.graph import Graph + DoDG = Graph H = DoDG(len(self_vertices), loops=G.allows_loops()) HB = H._backend @@ -25425,9 +25128,7 @@ def multilabel(e): isom_trans[v] = other_vertices[isom[G_to[v]]] return True, isom_trans - def canonical_label(self, partition=None, certificate=False, - edge_labels=False, algorithm=None, return_graph=True, - immutable=None): + def canonical_label(self, partition=None, certificate=False, edge_labels=False, algorithm=None, return_graph=True, immutable=None): r""" Return the canonical graph. @@ -25648,19 +25349,18 @@ class by some canonization function `c`. If `G` and `H` are graphs, if not has_multiedges: try: from sage.graphs.bliss import canonical_form + algorithm = 'bliss' except ImportError: pass if algorithm == 'bliss': if return_graph: - vert_dict = canonical_form(self, partition=partition, return_graph=False, - use_edge_labels=edge_labels, certificate=True)[1] + vert_dict = canonical_form(self, partition=partition, return_graph=False, use_edge_labels=edge_labels, certificate=True)[1] if not certificate: return self.relabel(vert_dict, inplace=False, immutable=immutable) return (self.relabel(vert_dict, inplace=False, immutable=immutable), vert_dict) - return canonical_form(self, partition=partition, return_graph=False, - use_edge_labels=edge_labels, certificate=certificate) + return canonical_form(self, partition=partition, return_graph=False, use_edge_labels=edge_labels, certificate=certificate) # algorithm == 'sage': from itertools import chain @@ -25669,12 +25369,11 @@ class by some canonization function `c`. If `G` and `H` are graphs, from sage.graphs.graph import Graph from sage.groups.perm_gps.partn_ref.refinement_graphs import search_tree - dig = (self.has_loops() or self._directed) + dig = self.has_loops() or self._directed if partition is None: partition = [list(self)] if edge_labels or self.has_multiple_edges(): - G, partition, relabeling = graph_isom_equivalent_non_edge_labeled_graph(self, partition=partition, - return_relabeling=True) + G, partition, relabeling = graph_isom_equivalent_non_edge_labeled_graph(self, partition=partition, return_relabeling=True) G_vertices = list(chain(*partition)) G_to = {u: i for i, u in enumerate(G_vertices)} DoDG = DiGraph if self._directed else Graph @@ -25708,8 +25407,7 @@ class by some canonization function `c`. If `G` and `H` are graphs, return H, c_new return H - def is_cayley(self, return_group=False, mapping=False, - generators=False, allow_disconnected=False): + def is_cayley(self, return_group=False, mapping=False, generators=False, allow_disconnected=False): r""" Check whether the graph is a Cayley graph. @@ -25841,24 +25539,18 @@ def is_cayley(self, return_group=False, mapping=False, c, CG = C[0].is_cayley(return_group=True) if c: from sage.groups.perm_gps.permgroup import PermutationGroup + I = [C[0].is_isomorphic(g, certificate=True)[1] for g in C] # gens generate the direct product of CG and a cyclic group - gens = [sum([[tuple([M[x] for x in p]) - for p in h.cycle_tuples()] for M in I], []) - for h in CG.gens()] + \ - [[tuple([M[v] for M in I]) - for v in C[0].vertices(sort=False)]] + gens = [sum([[tuple([M[x] for x in p]) for p in h.cycle_tuples()] for M in I], []) for h in CG.gens()] + [[tuple([M[v] for M in I]) for v in C[0].vertices(sort=False)]] G = PermutationGroup(gens, domain=self.vertices(sort=False)) else: c = C[0].is_cayley(return_group=False) - elif (not self.allows_loops() and not self.allows_multiple_edges() and - self.density() > Rational(1) / Rational(2)): + elif not self.allows_loops() and not self.allows_multiple_edges() and self.density() > Rational(1) / Rational(2): if certificate: - c, G = self.complement().is_cayley(return_group=True, - allow_disconnected=True) + c, G = self.complement().is_cayley(return_group=True, allow_disconnected=True) else: - c = self.complement().is_cayley(return_group=False, - allow_disconnected=True) + c = self.complement().is_cayley(return_group=False, allow_disconnected=True) else: A = self.automorphism_group() if certificate: @@ -25872,8 +25564,7 @@ def is_cayley(self, return_group=False, mapping=False, if generators: # self.(out_)neighbors ignores multiedges, # so we use edge_iterator instead - adj = [y if v == x else x - for x, y, z in self.edges(vertices=v, sort=False)] + adj = [y if v == x else x for x, y, z in self.edges(vertices=v, sort=False)] genset = [map[u] for u in adj] if certificate: out = [c] @@ -26014,6 +25705,7 @@ def is_self_complementary(self): maximum_leaf_number, ) from sage.graphs.line_graph import line_graph + rooted_product = LazyImport('sage.graphs.graph_decompositions.graph_products', 'rooted_product') from sage.graphs.morphisms import ( has_homomorphism_to, @@ -26028,6 +25720,7 @@ def is_self_complementary(self): shortest_simple_paths, ) from sage.graphs.traversals import lex_BFS, lex_DFS, lex_DOWN, lex_UP + is_geodetic = LazyImport('sage.graphs.convexity_properties', 'is_geodetic') from sage.graphs.cycle_enumeration import ( _all_cycles_iterator_vertex, @@ -26138,8 +25831,7 @@ def katz_matrix(self, alpha, nonedgesonly=False, vertices=None): raise ValueError('graph is empty') if vertices is None: vertices = self.vertices(sort=True) - elif (len(vertices) != n or - set(vertices) != set(self)): + elif len(vertices) != n or set(vertices) != set(self): raise ValueError("parameter vertices must be a permutation of the vertices") A = self.adjacency_matrix(vertices=vertices) @@ -26336,6 +26028,7 @@ def edge_polytope(self, backend=None): """ from sage.geometry.polyhedron.parent import Polyhedra from sage.matrix.special import identity_matrix + dim = self.n_vertices() e = identity_matrix(dim).rows() dic = {v: e[i] for i, v in enumerate(self)} @@ -26468,20 +26161,16 @@ def symmetric_edge_polytope(self, backend=None): from sage.geometry.polyhedron.parent import Polyhedra from sage.matrix.special import identity_matrix + dim = self.n_vertices() e = identity_matrix(dim).rows() dic = {v: e[i] for i, v in enumerate(self)} - vertices = chain(((dic[i] - dic[j]) for i, j in self.edge_iterator(sort_vertices=False, labels=False)), - ((dic[j] - dic[i]) for i, j in self.edge_iterator(sort_vertices=False, labels=False))) + vertices = chain(((dic[i] - dic[j]) for i, j in self.edge_iterator(sort_vertices=False, labels=False)), ((dic[j] - dic[i]) for i, j in self.edge_iterator(sort_vertices=False, labels=False))) parent = Polyhedra(ZZ, dim, backend=backend) return parent([vertices, [], []], None) -def tachyon_vertex_plot(g, bgcolor=(1, 1, 1), - vertex_colors=None, - vertex_size=0.06, - pos3d=None, - **kwds): +def tachyon_vertex_plot(g, bgcolor=(1, 1, 1), vertex_colors=None, vertex_size=0.06, pos3d=None, **kwds): """ Helper function for plotting graphs in 3d with :class:`~sage.plot.plot3d.tachyon.Tachyon`. @@ -26532,7 +26221,7 @@ def tachyon_vertex_plot(g, bgcolor=(1, 1, 1), pos3d[v][0] -= c[0] pos3d[v][1] -= c[1] pos3d[v][2] -= c[2] - r.append(abs(sqrt((pos3d[v][0])**2 + (pos3d[v][1])**2 + (pos3d[v][2])**2))) + r.append(abs(sqrt((pos3d[v][0]) ** 2 + (pos3d[v][1]) ** 2 + (pos3d[v][2]) ** 2))) r = max(r) if not r: r = 1 @@ -26548,18 +26237,14 @@ def tachyon_vertex_plot(g, bgcolor=(1, 1, 1), i = 0 for color in vertex_colors: i += 1 - TT.texture('node_color_%d' % i, ambient=0.1, diffuse=0.9, - specular=0.03, opacity=1.0, color=color) + TT.texture('node_color_%d' % i, ambient=0.1, diffuse=0.9, specular=0.03, opacity=1.0, color=color) for v in vertex_colors[color]: TT.sphere((pos3d[v][0], pos3d[v][1], pos3d[v][2]), vertex_size, 'node_color_%d' % i) return TT, pos3d -def graph_isom_equivalent_non_edge_labeled_graph(g, partition=None, standard_label=None, - return_relabeling=False, return_edge_labels=False, - inplace=False, ignore_edge_labels=False, - immutable=None): +def graph_isom_equivalent_non_edge_labeled_graph(g, partition=None, standard_label=None, return_relabeling=False, return_edge_labels=False, inplace=False, ignore_edge_labels=False, immutable=None): r""" Helper function for canonical labeling of edge labeled (di)graphs. diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index c943e2242df..28df97e65b7 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -400,7 +400,6 @@ ------- """ - # **************************************************************************** # Copyright (C) 2006-2007 Robert L. Miller # 2018 Julian Rüth @@ -427,8 +426,7 @@ from sage.features.mcqd import Mcqd from sage.misc.cachefunc import cached_method -lazy_import('sage.graphs.mcqd', ['mcqd'], - feature=Mcqd()) +lazy_import('sage.graphs.mcqd', ['mcqd'], feature=Mcqd()) class Graph(GenericGraph): @@ -916,13 +914,10 @@ class Graph(GenericGraph): sage: Graph(Graph().networkx_graph(), weighted=None, format='NX') # needs networkx Graph on 0 vertices """ + _directed = False - def __init__(self, data=None, pos=None, loops=None, format=None, - weighted=None, data_structure='sparse', - vertex_labels=True, name=None, - multiedges=None, convert_empty_dict_labels_to_None=None, - sparse=True, immutable=False, hash_labels=None): + def __init__(self, data=None, pos=None, loops=None, format=None, weighted=None, data_structure='sparse', vertex_labels=True, name=None, multiedges=None, convert_empty_dict_labels_to_None=None, sparse=True, immutable=False, hash_labels=None): """ TESTS:: @@ -1051,8 +1046,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if sparse is False: if data_structure != "sparse": - raise ValueError("The 'sparse' argument is an alias for " - "'data_structure'. Please do not define both.") + raise ValueError("The 'sparse' argument is an alias for " "'data_structure'. Please do not define both.") data_structure = "dense" if multiedges or weighted: @@ -1066,13 +1060,13 @@ def __init__(self, data=None, pos=None, loops=None, format=None, # as a static sparse graph. from sage.graphs.base.sparse_graph import SparseGraphBackend from sage.graphs.base.dense_graph import DenseGraphBackend + if data_structure in ["sparse", "static_sparse"]: CGB = SparseGraphBackend elif data_structure == "dense": CGB = DenseGraphBackend else: - raise ValueError("data_structure must be equal to 'sparse', " - "'static_sparse' or 'dense'") + raise ValueError("data_structure must be equal to 'sparse', " "'static_sparse' or 'dense'") self._backend = CGB(0, directed=False) if format is None and isinstance(data, str): @@ -1094,22 +1088,14 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if format is None and isinstance(data, Graph): format = 'Graph' from sage.graphs.digraph import DiGraph + if format is None and isinstance(data, DiGraph): data = data.to_undirected() format = 'Graph' - if (format is None and - isinstance(data, list) and - len(data) >= 2 and - callable(data[1])): + if format is None and isinstance(data, list) and len(data) >= 2 and callable(data[1]): format = 'rule' - if (format is None and - isinstance(data, list) and - len(data) == 2 and - isinstance(data[0], list) and # a list of two lists, the second of - ((isinstance(data[1], list) and # which contains iterables (the edges) - (not data[1] or callable(getattr(data[1][0], "__iter__", None)))) or - isinstance(data[1], EdgesView))): + if format is None and isinstance(data, list) and len(data) == 2 and isinstance(data[0], list) and ((isinstance(data[1], list) and (not data[1] or callable(getattr(data[1][0], "__iter__", None)))) or isinstance(data[1], EdgesView)): # a list of two lists, the second of # which contains iterables (the edges) format = "vertices_and_edges" if format is None and isinstance(data, dict): @@ -1125,15 +1111,11 @@ def __init__(self, data=None, pos=None, loops=None, format=None, # the input is a networkx (Multi)(Di)Graph format = 'NX' - if (format is None and - hasattr(data, 'vcount') and - hasattr(data, 'get_edgelist')): + if format is None and hasattr(data, 'vcount') and hasattr(data, 'get_edgelist'): try: import igraph except ImportError: - raise ImportError("The data seems to be a igraph object, but " - "igraph is not installed in Sage. To install " - "it, run 'sage -i python_igraph'") + raise ImportError("The data seems to be a igraph object, but " "igraph is not installed in Sage. To install " "it, run 'sage -i python_igraph'") if format is None and isinstance(data, igraph.Graph): format = 'igraph' if format is None and isinstance(data, (int, Integer)): @@ -1168,6 +1150,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, self.allow_loops(loops if loops else False, check=False) self.allow_multiple_edges(multiedges if multiedges else False, check=False) from .graph_input import from_graph6 + from_graph6(self, data) elif format == 'sparse6': @@ -1176,14 +1159,17 @@ def __init__(self, data=None, pos=None, loops=None, format=None, self.allow_loops(False if loops is False else True, check=False) self.allow_multiple_edges(False if multiedges is False else True, check=False) from .graph_input import from_sparse6 + from_sparse6(self, data) elif format == 'adjacency_matrix': from .graph_input import from_adjacency_matrix + from_adjacency_matrix(self, data, loops=loops, multiedges=multiedges, weighted=weighted) elif format == 'incidence_matrix': from .graph_input import from_incidence_matrix + from_incidence_matrix(self, data, loops=loops, multiedges=multiedges, weighted=weighted) elif format == 'seidel_adjacency_matrix': @@ -1191,6 +1177,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, self.allow_loops(False) self.allow_multiple_edges(False) from .graph_input import from_seidel_adjacency_matrix + from_seidel_adjacency_matrix(self, data) elif format == 'Graph': if loops is None: @@ -1209,17 +1196,14 @@ def __init__(self, data=None, pos=None, loops=None, format=None, elif format == 'NX': from sage.graphs.graph_input import from_networkx_graph - from_networkx_graph(self, data, - weighted=weighted, multiedges=multiedges, loops=loops, - convert_empty_dict_labels_to_None=convert_empty_dict_labels_to_None) + + from_networkx_graph(self, data, weighted=weighted, multiedges=multiedges, loops=loops, convert_empty_dict_labels_to_None=convert_empty_dict_labels_to_None) if weighted is None: weighted = self.allows_multiple_edges() elif format == 'igraph': if data.is_directed(): - raise ValueError("An *undirected* igraph graph was expected. " - "To build a directed graph, call the DiGraph " - "constructor.") + raise ValueError("An *undirected* igraph graph was expected. " "To build a directed graph, call the DiGraph " "constructor.") self.add_vertices(range(data.vcount())) self.add_edges((e.source, e.target, e.attributes()) for e in data.es()) @@ -1250,12 +1234,12 @@ def __init__(self, data=None, pos=None, loops=None, format=None, elif format == 'dict_of_dicts': from .graph_input import from_dict_of_dicts - from_dict_of_dicts(self, data, loops=loops, multiedges=multiedges, weighted=weighted, - convert_empty_dict_labels_to_None=(False if convert_empty_dict_labels_to_None is None - else convert_empty_dict_labels_to_None)) + + from_dict_of_dicts(self, data, loops=loops, multiedges=multiedges, weighted=weighted, convert_empty_dict_labels_to_None=(False if convert_empty_dict_labels_to_None is None else convert_empty_dict_labels_to_None)) elif format == 'dict_of_lists': from .graph_input import from_dict_of_lists + from_dict_of_lists(self, data, loops=loops, multiedges=multiedges, weighted=weighted) elif format == 'int': @@ -1267,8 +1251,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, self.add_vertices(range(data)) elif format == 'list_of_edges': - self.allow_multiple_edges(bool(multiedges), - check=False) + self.allow_multiple_edges(bool(multiedges), check=False) self.allow_loops(bool(loops), check=False) self.add_edges(data) else: @@ -1289,10 +1272,8 @@ def __init__(self, data=None, pos=None, loops=None, format=None, if data_structure == "static_sparse": from sage.graphs.base.static_sparse_backend import StaticSparseBackend - ib = StaticSparseBackend(self, - loops=self.allows_loops(), - multiedges=self.allows_multiple_edges(), - sort=(format != "vertices_and_edges")) + + ib = StaticSparseBackend(self, loops=self.allows_loops(), multiedges=self.allows_multiple_edges(), sort=(format != "vertices_and_edges")) self._backend = ib self._immutable = True @@ -1438,18 +1419,18 @@ def sparse6_string(self): while m < len(edges): if edges[m][1] > v + 1: sp = generic_graph_pyx.int_to_binary_string(edges[m][1]) - sp = '0'*(k-len(sp)) + sp + sp = '0' * (k - len(sp)) + sp s += '1' + sp v = edges[m][1] elif edges[m][1] == v + 1: sp = generic_graph_pyx.int_to_binary_string(edges[m][0]) - sp = '0'*(k-len(sp)) + sp + sp = '0' * (k - len(sp)) + sp s += '1' + sp v += 1 m += 1 else: sp = generic_graph_pyx.int_to_binary_string(edges[m][0]) - sp = '0'*(k-len(sp)) + sp + sp = '0' * (k - len(sp)) + sp s += '0' + sp m += 1 @@ -1460,7 +1441,7 @@ def sparse6_string(self): # split into groups of 6, and convert numbers to decimal, adding 63 six_bits = '' for i in range(0, len(s), 6): - six_bits += chr(int(s[i:i+6], 2) + 63) + six_bits += chr(int(s[i : i + 6], 2) + 63) return ':' + generic_graph_pyx.small_integer_to_graph6(n) + six_bits # Attributes @@ -1603,13 +1584,14 @@ def is_tree(self, certificate=False, output='vertex'): if output == 'edge': if self.allows_multiple_edges(): + def vertices_to_edges(x): - return [(u[0], u[1], self.edge_label(u[0], u[1])[0]) - for u in zip(x, x[1:] + [x[0]])] + return [(u[0], u[1], self.edge_label(u[0], u[1])[0]) for u in zip(x, x[1:] + [x[0]])] + else: + def vertices_to_edges(x): - return [(u[0], u[1], self.edge_label(u[0], u[1])) - for u in zip(x, x[1:] + [x[0]])] + return [(u[0], u[1], self.edge_label(u[0], u[1])) for u in zip(x, x[1:] + [x[0]])] # This code is a depth-first search that looks for a cycle in the # graph. We *know* it exists as there are too many edges around. @@ -1672,8 +1654,7 @@ def is_forest(self, certificate=False, output='vertex'): """ connected_components = self.connected_components(sort=False) number_of_connected_components = len(connected_components) - isit = (self.order() == - self.size() + number_of_connected_components) + isit = self.order() == self.size() + number_of_connected_components if not certificate: return isit @@ -1838,7 +1819,7 @@ def is_cograph(self): self._scream_if_not_simple() if self.order() < 4: return True - if self.density()*2 > 1: + if self.density() * 2 > 1: return self.complement().is_cograph() if not self.is_connected(): return all(part.is_cograph() for part in self.connected_components_subgraphs()) @@ -2198,8 +2179,7 @@ def is_overfull(self): # 2 * self._backend.n_edges(self._directed) > #2m > \Delta(G)*(n-1) # max(self.degree()) * (self._backend.n_vertices() - 1)) # unoptimized version - return (self.order() % 2 == 1) and ( - 2 * self.size() > max(self.degree()) * (self.order() - 1)) + return (self.order() % 2 == 1) and (2 * self.size() > max(self.degree()) * (self.order() - 1)) @doc_index("Graph properties") def is_even_hole_free(self, certificate=False): @@ -2458,12 +2438,14 @@ def is_triangle_free(self, algorithm='dense_graph', certificate=False): """ if algorithm == 'dense_graph': from sage.graphs.base.static_dense_graph import is_triangle_free + return is_triangle_free(self, certificate=certificate) if algorithm == 'bitset': if self.order() < 3: return (True, []) if certificate else True from sage.data_structures.bitset import Bitset + N = self.order() vertex_to_int = {} B = {} @@ -2489,7 +2471,7 @@ def is_triangle_free(self, algorithm='dense_graph', certificate=False): if algorithm == 'matrix': if self.order() < 3: return True - return (self.adjacency_matrix()**3).trace() == 0 + return (self.adjacency_matrix() ** 3).trace() == 0 raise ValueError("Algorithm '%s' not yet implemented. Please contribute." % (algorithm)) @@ -2556,8 +2538,8 @@ def is_split(self): else: break - left = sum(degree_sequence[:omega + 1]) - right = omega * (omega - 1) + sum(degree_sequence[omega + 1:]) + left = sum(degree_sequence[: omega + 1]) + right = omega * (omega - 1) + sum(degree_sequence[omega + 1 :]) return left == right @@ -2763,7 +2745,7 @@ def is_arc_transitive(self): e = next(self.edge_iterator(labels=False)) e = [A._domain_to_gap[e[0]], A._domain_to_gap[e[1]]] - return libgap(A).OrbitLength(e, libgap.OnTuples) == 2*self.size() + return libgap(A).OrbitLength(e, libgap.OnTuples) == 2 * self.size() @doc_index("Graph properties") def is_half_transitive(self): @@ -2798,9 +2780,7 @@ def is_half_transitive(self): if any(d % 2 for d in self.degree_iterator()): return False - return (self.is_edge_transitive() and - self.is_vertex_transitive() and - not self.is_arc_transitive()) + return self.is_edge_transitive() and self.is_vertex_transitive() and not self.is_arc_transitive() @doc_index("Graph properties") def is_semi_symmetric(self): @@ -2841,9 +2821,7 @@ def is_semi_symmetric(self): if not self.is_bipartite(): return False - return (self.is_regular() and - self.is_edge_transitive() and not - self.is_vertex_transitive()) + return self.is_regular() and self.is_edge_transitive() and not self.is_vertex_transitive() @doc_index("Graph properties") def is_path(self): @@ -3053,8 +3031,7 @@ def is_chordal_bipartite(self, certificate=False): return False, certif pewveo.extend(certif) return True, pewveo - return all(gg.is_chordal_bipartite() for gg in - self.connected_components_subgraphs()) + return all(gg.is_chordal_bipartite() for gg in self.connected_components_subgraphs()) left = [v for v, c in bipartite_certificate.items() if c == 0] right = [v for v, c in bipartite_certificate.items() if c == 1] @@ -3069,7 +3046,8 @@ def is_chordal_bipartite(self, certificate=False): # create a reduced_adjacency_matrix from sage.rings.finite_rings.finite_field_prime_modn import FiniteField_prime_modn - A = self.adjacency_matrix(vertices=left+right, base_ring=FiniteField_prime_modn(2)) + + A = self.adjacency_matrix(vertices=left + right, base_ring=FiniteField_prime_modn(2)) B = A[range(order_left), range(order_left, order_left + order_right)] # get doubly lexical ordering of reduced_adjacency_matrix @@ -3081,8 +3059,8 @@ def is_chordal_bipartite(self, certificate=False): if not certificate: return is_Gamma_free - row_ordering_dict = {k-1: v-1 for k, v in row_ordering.dict().items()} - col_ordering_dict = {k-1: v-1 for k, v in col_ordering.dict().items()} + row_ordering_dict = {k - 1: v - 1 for k, v in row_ordering.dict().items()} + col_ordering_dict = {k - 1: v - 1 for k, v in col_ordering.dict().items()} row_vertices = [left[row_ordering_dict[i]] for i in range(order_left)] col_vertices = [right[col_ordering_dict[i]] for i in range(order_right)] @@ -3140,8 +3118,7 @@ def is_chordal_bipartite(self, certificate=False): return False, cycle @doc_index("Connectivity, orientations, trees") - def degree_constrained_subgraph(self, bounds, solver=None, verbose=0, - *, integrality_tolerance=1e-3): + def degree_constrained_subgraph(self, bounds, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a degree-constrained subgraph. @@ -3208,8 +3185,10 @@ def degree_constrained_subgraph(self, bounds, solver=None, verbose=0, b = p.new_variable(binary=True) if isinstance(bounds, dict): + def f_bounds(x): return bounds[x] + else: f_bounds = bounds @@ -3218,18 +3197,17 @@ def f_bounds(x): def weight(x): return x if x in RR else 1 + else: + def weight(x): return 1 for v in self: minimum, maximum = f_bounds(v) - p.add_constraint(p.sum(b[frozenset((x, y))]*weight(l) - for x, y, l in self.edges_incident(v)), - min=minimum, max=maximum) + p.add_constraint(p.sum(b[frozenset((x, y))] * weight(l) for x, y, l in self.edges_incident(v)), min=minimum, max=maximum) - p.set_objective(p.sum(b[frozenset((x, y))]*weight(l) - for x, y, l in self.edge_iterator())) + p.set_objective(p.sum(b[frozenset((x, y))] * weight(l) for x, y, l in self.edge_iterator())) try: p.solve(log=verbose) @@ -3373,12 +3351,11 @@ def chromatic_index(self, solver=None, verbose=0, *, integrality_tolerance=1e-3) return 0 from sage.graphs.graph_coloring import edge_coloring - return edge_coloring(self, value_only=True, solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + + return edge_coloring(self, value_only=True, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) @doc_index("Coloring") - def chromatic_number(self, algorithm='DLX', solver=None, verbose=0, - *, integrality_tolerance=1e-3): + def chromatic_number(self, algorithm='DLX', solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return the minimal number of colors needed to color the vertices of the graph. @@ -3498,11 +3475,12 @@ def chromatic_number(self, algorithm='DLX', solver=None, verbose=0, self._scream_if_not_simple(allow_multiple_edges=True) if algorithm == "DLX": from sage.graphs.graph_coloring import chromatic_number + return chromatic_number(self) if algorithm == "MILP": from sage.graphs.graph_coloring import vertex_coloring - return vertex_coloring(self, value_only=True, solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + + return vertex_coloring(self, value_only=True, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) if algorithm == "CP": f = self.chromatic_polynomial() i = 0 @@ -3510,20 +3488,21 @@ def chromatic_number(self, algorithm='DLX', solver=None, verbose=0, i += 1 return i if algorithm == "parallel": + def use_all(algorithms): @parallel(len(algorithms), verbose=False) def func(alg): - return self.chromatic_number(algorithm=alg, solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + return self.chromatic_number(algorithm=alg, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) + for input, output in func(algorithms): return output + return use_all(['DLX', 'MILP', 'CP']) raise ValueError("the 'algorithm' keyword must be set to either 'DLX', 'MILP', 'CP' or 'parallel'") @doc_index("Coloring") - def coloring(self, algorithm='DLX', hex_colors=False, solver=None, verbose=0, - *, integrality_tolerance=1e-3): + def coloring(self, algorithm='DLX', hex_colors=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return the first (optimal) proper vertex-coloring found. @@ -3599,10 +3578,11 @@ def coloring(self, algorithm='DLX', hex_colors=False, solver=None, verbose=0, self._scream_if_not_simple(allow_multiple_edges=True) if algorithm == "MILP": from sage.graphs.graph_coloring import vertex_coloring - return vertex_coloring(self, hex_colors=hex_colors, solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + + return vertex_coloring(self, hex_colors=hex_colors, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) if algorithm == "DLX": from sage.graphs.graph_coloring import first_coloring + return first_coloring(self, hex_colors=hex_colors) raise ValueError("The 'algorithm' keyword must be set to either 'DLX' or 'MILP'.") @@ -3697,6 +3677,7 @@ def chromatic_symmetric_function(self, R=None, weights=None): """ from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.partition import _Partitions + if R is None: R = ZZ p = SymmetricFunctions(R).p() @@ -3719,9 +3700,7 @@ def summand(stack, dsf, sizes): # Compute powersum terms obtained by adding each subset of # edges in stack to current subgraph. if not stack: - return p.monomial(_Partitions(sorted( - [s for v, s in sizes.items() if dsf[v] is None], - reverse=True))) + return p.monomial(_Partitions(sorted([s for v, s in sizes.items() if dsf[v] is None], reverse=True))) ret = p.zero() e = stack.pop() u = find(dsf, e[0]) @@ -3813,6 +3792,7 @@ def chromatic_quasisymmetric_function(self, t=None, R=None): """ from sage.combinat.ncsf_qsym.qsym import QuasiSymmetricFunctions from sage.combinat.set_partition_ordered import OrderedSetPartitions + if t is None: t = ZZ['t'].gen() if R is None: @@ -3825,14 +3805,13 @@ def asc(sigma): stat = 0 for i, s in enumerate(sigma): for u in s: - stat += sum(1 for p in sigma[i+1:] for v in p - if v > u and self.has_edge(u, v)) + stat += sum(1 for p in sigma[i + 1 :] for v in p if v > u and self.has_edge(u, v)) return stat for sigma in OrderedSetPartitions(V): if any(not self.is_independent_set(s) for s in sigma): continue - ret += M.term(sigma.to_composition(), t**asc(sigma)) + ret += M.term(sigma.to_composition(), t ** asc(sigma)) return ret @doc_index("Coloring") @@ -3915,7 +3894,7 @@ def tutte_symmetric_function(self, R=None, t=None): V = self.vertices() M = Counter(self.edge_iterator(labels=False)) fact = [1] - fact.extend(fact[-1] * i for i in range(1, len(V)+1)) + fact.extend(fact[-1] * i for i in range(1, len(V) + 1)) def mono(pi): arcs = 0 @@ -3926,12 +3905,11 @@ def mono(pi): for pi in SetPartitions(V): pa = pi.to_partition() - ret += prod(fact[i] for i in pa.to_exp()) * m[pa] * (1+t)**mono(pi) + ret += prod(fact[i] for i in pa.to_exp()) * m[pa] * (1 + t) ** mono(pi) return ret @doc_index("Clique-related methods") - def fractional_clique_number(self, solver='PPL', verbose=0, - check_components=True, check_bipartite=True): + def fractional_clique_number(self, solver='PPL', verbose=0, check_components=True, check_bipartite=True): r""" Return the fractional clique number of the graph. @@ -3981,9 +3959,7 @@ def fractional_clique_number(self, solver='PPL', verbose=0, sage: g.fractional_clique_number() # needs sage.numerical.mip 7/3 """ - return self.fractional_chromatic_number(solver=solver, verbose=verbose, - check_components=check_components, - check_bipartite=check_bipartite) + return self.fractional_chromatic_number(solver=solver, verbose=verbose, check_components=check_components, check_bipartite=check_bipartite) @doc_index("Leftovers") def maximum_average_degree(self, value_only=True, solver=None, verbose=0): @@ -4086,8 +4062,7 @@ def maximum_average_degree(self, value_only=True, solver=None, verbose=0): p.add_constraint(p.sum(d[v] for v in g), max=1) - p.set_objective(p.sum(one[frozenset(uv)] - for uv in g.edge_iterator(labels=False))) + p.set_objective(p.sum(one[frozenset(uv)] for uv in g.edge_iterator(labels=False))) p.solve(log=verbose) @@ -4099,7 +4074,7 @@ def maximum_average_degree(self, value_only=True, solver=None, verbose=0): # setting the minimum to 1/(10 * size of the whole graph ) # should be safe :-) - m = 1/(10 * Integer(g.order())) + m = 1 / (10 * Integer(g.order())) d_val = p.get_values(d) g_mad = g.subgraph(v for v, l in d_val.items() if l > m) @@ -4108,8 +4083,7 @@ def maximum_average_degree(self, value_only=True, solver=None, verbose=0): return g_mad @doc_index("Algorithmically hard stuff") - def independent_set_of_representatives(self, family, solver=None, verbose=0, - *, integrality_tolerance=1e-3): + def independent_set_of_representatives(self, family, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return an independent set of representatives. @@ -4179,6 +4153,7 @@ def independent_set_of_representatives(self, family, solver=None, verbose=0, True """ from sage.numerical.mip import MixedIntegerLinearProgram + p = MixedIntegerLinearProgram(solver=solver) # Boolean variable indicating whether the vertex is the representative @@ -4369,6 +4344,7 @@ def minor(self, H, solver=None, verbose=0, induced=False, *, integrality_toleran self._scream_if_not_simple() H._scream_if_not_simple() from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException + p = MixedIntegerLinearProgram(solver=solver) # We use frozenset((u, v)) to avoid confusion between (u, v) and (v, u) @@ -4399,11 +4375,10 @@ def minor(self, H, solver=None, verbose=0, induced=False, *, integrality_toleran # of its representative set minus 1 for h in H: - p.add_constraint(p.sum(edges[h, frozenset(e)] for e in self.edge_iterator(labels=None)) - - p.sum(rs[h, v] for v in self), min=-1, max=-1) + p.add_constraint(p.sum(edges[h, frozenset(e)] for e in self.edge_iterator(labels=None)) - p.sum(rs[h, v] for v in self), min=-1, max=-1) # a tree has no cycle - epsilon = 1/(5*Integer(self.order())) + epsilon = 1 / (5 * Integer(self.order())) r_edges = p.new_variable(nonnegative=True) for h in H: @@ -4411,7 +4386,7 @@ def minor(self, H, solver=None, verbose=0, induced=False, *, integrality_toleran p.add_constraint(r_edges[h, (u, v)] + r_edges[h, (v, u)] - edges[h, frozenset((u, v))], min=0) for v in self: - p.add_constraint(p.sum(r_edges[h, (u, v)] for u in self.neighbor_iterator(v)), max=1-epsilon) + p.add_constraint(p.sum(r_edges[h, (u, v)] for u in self.neighbor_iterator(v)), max=1 - epsilon) # Once the representative sets are described, we must ensure # there are arcs corresponding to those of H between them @@ -4427,8 +4402,7 @@ def minor(self, H, solver=None, verbose=0, induced=False, *, integrality_toleran p.add_constraint(h_edges[(h2, h1), fv1v2] - rs[h1, v2], max=0) p.add_constraint(h_edges[(h2, h1), fv1v2] - rs[h2, v1], max=0) - p.add_constraint(p.sum(h_edges[(h1, h2), frozenset(e)] + h_edges[(h2, h1), frozenset(e)] - for e in self.edge_iterator(labels=None)), min=1) + p.add_constraint(p.sum(h_edges[(h1, h2), frozenset(e)] + h_edges[(h2, h1), frozenset(e)] for e in self.edge_iterator(labels=None)), min=1) # if induced is True # condition for induced subgraph ensures that if there @@ -4499,6 +4473,7 @@ def convexity_properties(self): makes perfect sense. """ from sage.graphs.convexity_properties import ConvexityProperties + return ConvexityProperties(self) # Centrality @@ -4539,20 +4514,18 @@ def centrality_degree(self, v=None): ValueError: the centrality degree is not defined on graphs with only one vertex """ from sage.rings.integer import Integer + n_minus_one = Integer(self.order() - 1) if n_minus_one == 0: - raise ValueError("the centrality degree is not defined " - "on graphs with only one vertex") + raise ValueError("the centrality degree is not defined " "on graphs with only one vertex") if v is None: - return {v: self.degree(v)/n_minus_one for v in self} - return self.degree(v)/n_minus_one + return {v: self.degree(v) / n_minus_one for v in self} + return self.degree(v) / n_minus_one # Distances @doc_index("Distances") - def eccentricity(self, v=None, by_weight=False, algorithm=None, - weight_function=None, check_weight=True, dist_dict=None, - with_labels=False): + def eccentricity(self, v=None, by_weight=False, algorithm=None, weight_function=None, check_weight=True, dist_dict=None, with_labels=False): """ Return the eccentricity of vertex (or vertices) ``v``. @@ -4711,9 +4684,7 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, ... ValueError: algorithm 'DHV' works only if all eccentricities are needed """ - by_weight, weight_function = self._get_weight_function(by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight) + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, weight_function=weight_function, check_weight=check_weight) if algorithm is None: if dist_dict is not None: @@ -4741,6 +4712,7 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, # If we want to use BFS, we use the Cython routine if algorithm == 'BFS': from sage.graphs.distances_all_pairs import eccentricity + algo = 'bounds' if with_labels: return dict(zip(v, eccentricity(self, algorithm=algo, vertex_list=v))) @@ -4749,29 +4721,23 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, if algorithm == 'DHV': if by_weight: from sage.graphs.base.boost_graph import eccentricity_DHV + if with_labels: - return dict(zip(v, eccentricity_DHV(self, vertex_list=v, - weight_function=weight_function, - check_weight=check_weight))) - return eccentricity_DHV(self, vertex_list=v, - weight_function=weight_function, - check_weight=check_weight) + return dict(zip(v, eccentricity_DHV(self, vertex_list=v, weight_function=weight_function, check_weight=check_weight))) + return eccentricity_DHV(self, vertex_list=v, weight_function=weight_function, check_weight=check_weight) from sage.graphs.distances_all_pairs import eccentricity + if with_labels: - return dict(zip(v, eccentricity(self, algorithm=algorithm, - vertex_list=v))) + return dict(zip(v, eccentricity(self, algorithm=algorithm, vertex_list=v))) return eccentricity(self, algorithm=algorithm, vertex_list=v) if algorithm in ['Floyd-Warshall-Python', 'Floyd-Warshall-Cython', 'Johnson_Boost']: - dist_dict = self.shortest_path_all_pairs(by_weight, algorithm, - weight_function, - check_weight)[0] + dist_dict = self.shortest_path_all_pairs(by_weight, algorithm, weight_function, check_weight)[0] algorithm = 'From_Dictionary' elif algorithm in ['Floyd-Warshall-Python', 'Floyd-Warshall-Cython', 'Johnson_Boost', 'DHV']: - raise ValueError("algorithm '" + algorithm + "' works only if all" + - " eccentricities are needed") + raise ValueError("algorithm '" + algorithm + "' works only if all" + " eccentricities are needed") ecc = {} @@ -4783,10 +4749,7 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, else: # If algorithm is wrong, the error is raised by the # shortest_path_lengths function - length = self.shortest_path_lengths(u, by_weight=by_weight, - algorithm=algorithm, - weight_function=weight_function, - check_weight=check_weight) + length = self.shortest_path_lengths(u, by_weight=by_weight, algorithm=algorithm, weight_function=weight_function, check_weight=check_weight) if len(length) != self.n_vertices(): ecc[u] = Infinity @@ -4797,13 +4760,12 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, return ecc if len(ecc) == 1: # return single value - v, = ecc.values() + (v,) = ecc.values() return v return [ecc[u] for u in v] @doc_index("Distances") - def radius(self, by_weight=False, algorithm='DHV', weight_function=None, - check_weight=True): + def radius(self, by_weight=False, algorithm='DHV', weight_function=None, check_weight=True): r""" Return the radius of the graph. @@ -4870,25 +4832,20 @@ def radius(self, by_weight=False, algorithm='DHV', weight_function=None, algorithm = 'DHV' if algorithm == 'DHV': - by_weight, weight_function = self._get_weight_function(by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight) + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, weight_function=weight_function, check_weight=check_weight) if by_weight: from sage.graphs.base.boost_graph import radius_DHV - return radius_DHV(self, weight_function=weight_function, - check_weight=False) + + return radius_DHV(self, weight_function=weight_function, check_weight=False) from sage.graphs.distances_all_pairs import radius_DHV + return radius_DHV(self) - return min(self.eccentricity(v=None, by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight, - algorithm=algorithm)) + return min(self.eccentricity(v=None, by_weight=by_weight, weight_function=weight_function, check_weight=check_weight, algorithm=algorithm)) @doc_index("Distances") - def diameter(self, by_weight=False, algorithm=None, weight_function=None, - check_weight=True): + def diameter(self, by_weight=False, algorithm=None, weight_function=None, check_weight=True): r""" Return the diameter of the graph. @@ -4998,9 +4955,7 @@ def diameter(self, by_weight=False, algorithm=None, weight_function=None, if not self.order(): raise ValueError("diameter is not defined for the empty graph") - by_weight, weight_function = self._get_weight_function(by_weight=by_weight, - weight_function=weight_function, - check_weight=check_weight) + by_weight, weight_function = self._get_weight_function(by_weight=by_weight, weight_function=weight_function, check_weight=check_weight) if not by_weight: # We don't want the default weight function weight_function = None @@ -5013,26 +4968,23 @@ def diameter(self, by_weight=False, algorithm=None, weight_function=None, if algorithm == 'DHV': if by_weight: from sage.graphs.base.boost_graph import diameter_DHV - return diameter_DHV(self, weight_function=weight_function, - check_weight=False) + + return diameter_DHV(self, weight_function=weight_function, check_weight=False) from sage.graphs.distances_all_pairs import diameter + return diameter(self, algorithm=algorithm) if algorithm in ['standard', '2sweep', 'multi-sweep', 'iFUB']: if by_weight: - raise ValueError("algorithm '" + algorithm + "' does not work" + - " on weighted graphs") + raise ValueError("algorithm '" + algorithm + "' does not work" + " on weighted graphs") from sage.graphs.distances_all_pairs import diameter + return diameter(self, algorithm=algorithm) - return max(self.eccentricity(v=list(self), by_weight=by_weight, - weight_function=weight_function, - check_weight=False, - algorithm=algorithm)) + return max(self.eccentricity(v=list(self), by_weight=by_weight, weight_function=weight_function, check_weight=False, algorithm=algorithm)) @doc_index("Distances") - def center(self, by_weight=False, algorithm=None, weight_function=None, - check_weight=True): + def center(self, by_weight=False, algorithm=None, weight_function=None, check_weight=True): r""" Return the set of vertices in the center of the graph. @@ -5091,11 +5043,7 @@ def center(self, by_weight=False, algorithm=None, weight_function=None, sage: G.center() [0] """ - ecc = self.eccentricity(v=list(self), by_weight=by_weight, - weight_function=weight_function, - algorithm=algorithm, - check_weight=check_weight, - with_labels=True) + ecc = self.eccentricity(v=list(self), by_weight=by_weight, weight_function=weight_function, algorithm=algorithm, check_weight=check_weight, with_labels=True) try: r = min(ecc.values()) except Exception: @@ -5103,8 +5051,7 @@ def center(self, by_weight=False, algorithm=None, weight_function=None, return [v for v in self if ecc[v] == r] @doc_index("Distances") - def periphery(self, by_weight=False, algorithm=None, weight_function=None, - check_weight=True): + def periphery(self, by_weight=False, algorithm=None, weight_function=None, check_weight=True): r""" Return the set of vertices in the periphery of the graph. @@ -5151,11 +5098,7 @@ def periphery(self, by_weight=False, algorithm=None, weight_function=None, sage: G.periphery() [0] """ - ecc = self.eccentricity(v=list(self), by_weight=by_weight, - weight_function=weight_function, - algorithm=algorithm, - check_weight=check_weight, - with_labels=True) + ecc = self.eccentricity(v=list(self), by_weight=by_weight, weight_function=weight_function, algorithm=algorithm, check_weight=check_weight, with_labels=True) try: d = max(ecc.values()) except Exception: @@ -5290,6 +5233,7 @@ def distance_graph(self, dist): Rob Beezer, 2009-11-25, :issue:`7533` """ from sage.rings.infinity import Infinity + # If input is not a list, make a list with this single object if not isinstance(dist, list): dist = [dist] @@ -5312,12 +5256,12 @@ def distance_graph(self, dist): name = "Distance graph for %s in " % dstring + self.name() looped = ZZ(0) in s_distances from sage.graphs.graph import Graph - D = Graph([self, []], format='vertices_and_edges', - multiedges=False, loops=looped, - pos=copy(self.get_pos()), name=name) + + D = Graph([self, []], format='vertices_and_edges', multiedges=False, loops=looped, pos=copy(self.get_pos()), name=name) # Create the appropriate edges import itertools + if self.is_connected(): CC = [self] else: @@ -5393,10 +5337,9 @@ def to_directed(self, data_structure=None, sparse=None): """ from sage.graphs.orientations import _initialize_digraph from itertools import chain - edges = chain(self.edge_iterator(), - ((v, u, l) for u, v, l in self.edge_iterator())) - return _initialize_digraph(self, edges, name=self.name(), - data_structure=data_structure, sparse=sparse) + + edges = chain(self.edge_iterator(), ((v, u, l) for u, v, l in self.edge_iterator())) + return _initialize_digraph(self, edges, name=self.name(), data_structure=data_structure, sparse=sparse) @doc_index("Basic methods") def to_undirected(self): @@ -5465,8 +5408,7 @@ def join(self, other, labels='pairs', immutable=None): """ G = self.disjoint_union(other, labels=labels, immutable=False) if labels == "integers": - G.add_edges((u, v) for u in range(self.order()) - for v in range(self.order(), self.order() + other.order())) + G.add_edges((u, v) for u in range(self.order()) for v in range(self.order(), self.order() + other.order())) else: G.add_edges(((0, u), (1, v)) for u in self for v in other) @@ -5519,10 +5461,8 @@ def seidel_adjacency_matrix(self, vertices=None, *, base_ring=None, **kwds): Real Double Field """ set_immutable = kwds.pop('immutable', False) - A = self.adjacency_matrix(sparse=False, vertices=vertices, - base_ring=base_ring, immutable=True, **kwds) - C = self.complement().adjacency_matrix(sparse=False, vertices=vertices, - base_ring=base_ring, **kwds) + A = self.adjacency_matrix(sparse=False, vertices=vertices, base_ring=base_ring, immutable=True, **kwds) + C = self.complement().adjacency_matrix(sparse=False, vertices=vertices, base_ring=base_ring, **kwds) n = self.order() for i in range(n): for j in range(n): @@ -5614,6 +5554,7 @@ def twograph(self): -- ditto, but much faster. """ from sage.combinat.designs.twographs import TwoGraph + G = self.relabel(range(self.order()), inplace=False) T = [] @@ -5659,10 +5600,11 @@ def write_to_eps(self, filename, **options): filename.pdf``. """ from sage.graphs.print_graphs import print_graph_eps + pos = self.layout(**options) xmin, xmax, ymin, ymax = self._layout_bounding_box(pos) for v in pos: - pos[v] = (1.8*(pos[v][0] - xmin)/(xmax - xmin) - 0.9, 1.8*(pos[v][1] - ymin)/(ymax - ymin) - 0.9) + pos[v] = (1.8 * (pos[v][0] - xmin) / (xmax - xmin) - 0.9, 1.8 * (pos[v][1] - ymin) / (ymax - ymin) - 0.9) if filename[-4:] != '.eps': filename += '.eps' f = open(filename, 'w') @@ -5670,8 +5612,7 @@ def write_to_eps(self, filename, **options): f.close() @doc_index("Algorithmically hard stuff") - def topological_minor(self, H, vertices=False, paths=False, solver=None, verbose=0, - *, integrality_tolerance=1e-3): + def topological_minor(self, H, vertices=False, paths=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a topological `H`-minor from ``self`` if one exists. @@ -5757,6 +5698,7 @@ def topological_minor(self, H, vertices=False, paths=False, solver=None, verbose G = self from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException + p = MixedIntegerLinearProgram(solver=solver) # This is an existence problem @@ -5846,8 +5788,7 @@ def flow_balance(C, v): # the vertex is a representent for g in G: - p.add_constraint(p.sum(is_internal[C, g] for C in H.edge_iterator(labels=False)) - + is_repr[g], max=1) + p.add_constraint(p.sum(is_internal[C, g] for C in H.edge_iterator(labels=False)) + is_repr[g], max=1) # (The following inequalities are not necessary, but they seem to be of # help (the solvers find the answer quicker when they are added) @@ -5856,9 +5797,7 @@ def flow_balance(C, v): # belong to at most one commodity and has a maximum intensity of 1. for g1, g2 in G.edge_iterator(labels=None): - p.add_constraint(p.sum(flow[C, (g1, g2)] for C in H.edge_iterator(labels=False)) + - p.sum(flow[C, (g2, g1)] for C in H.edge_iterator(labels=False)), - max=1) + p.add_constraint(p.sum(flow[C, (g1, g2)] for C in H.edge_iterator(labels=False)) + p.sum(flow[C, (g2, g1)] for C in H.edge_iterator(labels=False)), max=1) # Now we can solve the problem itself ! @@ -5955,15 +5894,16 @@ def cliques_maximal(self, algorithm='native'): """ if algorithm == "native": from sage.graphs.independent_sets import IndependentSets + return list(IndependentSets(self, maximal=True, complement=True)) if algorithm == "NetworkX": import networkx + return list(networkx.find_cliques(self.networkx_graph())) raise ValueError("Algorithm must be equal to 'native' or to 'NetworkX'.") @doc_index("Clique-related methods") - def clique_maximum(self, algorithm='Cliquer', solver=None, verbose=0, - *, integrality_tolerance=1e-3): + def clique_maximum(self, algorithm='Cliquer', solver=None, verbose=0, *, integrality_tolerance=1e-3): """ Return the vertex set of a maximal order complete subgraph. @@ -6038,17 +5978,16 @@ def clique_maximum(self, algorithm='Cliquer', solver=None, verbose=0, self._scream_if_not_simple(allow_multiple_edges=True) if algorithm == "Cliquer": from sage.graphs.cliquer import max_clique + return max_clique(self) if algorithm == "MILP": - return self.complement().independent_set(algorithm=algorithm, solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + return self.complement().independent_set(algorithm=algorithm, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) if algorithm == "mcqd": return mcqd(self) raise NotImplementedError("Only 'MILP', 'Cliquer' and 'mcqd' are supported.") @doc_index("Clique-related methods") - def clique_number(self, algorithm='Cliquer', cliques=None, solver=None, verbose=0, - *, integrality_tolerance=1e-3): + def clique_number(self, algorithm='Cliquer', cliques=None, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return the order of the largest clique of the graph. @@ -6140,13 +6079,14 @@ def clique_number(self, algorithm='Cliquer', cliques=None, solver=None, verbose= self._scream_if_not_simple(allow_loops=False) if algorithm == "Cliquer": from sage.graphs.cliquer import clique_number + return clique_number(self) if algorithm == "networkx": import networkx + return networkx.graph_clique_number(self.networkx_graph(), cliques) if algorithm == "MILP": - return len(self.complement().independent_set(algorithm=algorithm, solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance)) + return len(self.complement().independent_set(algorithm=algorithm, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance)) if algorithm == "mcqd": return len(mcqd(self)) raise NotImplementedError("Only 'networkx' 'MILP' 'Cliquer' and 'mcqd' are supported.") @@ -6200,6 +6140,7 @@ def cliques_number_of(self, vertices=None, cliques=None): return sum(1 for c in cliques if vertices in c) from collections import Counter + count = Counter() for c in cliques: @@ -6300,15 +6241,15 @@ def cliques_get_clique_bipartite(self, **kwds): """ G = Graph([self, []], format='vertices_and_edges') for i, clique in enumerate(IndependentSets(self, maximal=True, complement=True)): - idx = - i - 1 + idx = -i - 1 G.add_vertex(idx) G.add_edges((u, idx) for u in clique) from sage.graphs.bipartite_graph import BipartiteGraph + return BipartiteGraph(G, check=False) @doc_index("Algorithmically hard stuff") - def independent_set(self, algorithm='Cliquer', value_only=False, reduction_rules=True, - solver=None, verbose=0, *, integrality_tolerance=1e-3): + def independent_set(self, algorithm='Cliquer', value_only=False, reduction_rules=True, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a maximum independent set. @@ -6390,19 +6331,14 @@ def independent_set(self, algorithm='Cliquer', value_only=False, reduction_rules g = graphs.PetersenGraph() sphinx_plot(g.plot(partition=[g.independent_set()])) """ - my_cover = self.vertex_cover(algorithm=algorithm, value_only=value_only, - reduction_rules=reduction_rules, - solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + my_cover = self.vertex_cover(algorithm=algorithm, value_only=value_only, reduction_rules=reduction_rules, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) if value_only: return self.order() - my_cover my_cover = set(my_cover) return [u for u in self if u not in my_cover] @doc_index("Algorithmically hard stuff") - def vertex_cover(self, algorithm='Cliquer', value_only=False, - reduction_rules=True, solver=None, verbose=0, - *, integrality_tolerance=1e-3): + def vertex_cover(self, algorithm='Cliquer', value_only=False, reduction_rules=True, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a minimum vertex cover of ``self`` represented by a set of vertices. @@ -6558,8 +6494,7 @@ def vertex_cover(self, algorithm='Cliquer', value_only=False, # belongs to an optimal vertex cover # We first take a copy of the graph without multiple edges, if any. - g = Graph(data=self.edges(sort=False), format='list_of_edges', - multiedges=self.allows_multiple_edges()) + g = Graph(data=self.edges(sort=False), format='list_of_edges', multiedges=self.allows_multiple_edges()) g.allow_multiple_edges(False) degree_at_most_two = {u for u in g if g.degree(u) <= 2} @@ -6656,6 +6591,7 @@ def vertex_cover(self, algorithm='Cliquer', value_only=False, elif algorithm == "MILP": from sage.numerical.mip import MixedIntegerLinearProgram + p = MixedIntegerLinearProgram(maximization=False, solver=solver) b = p.new_variable(binary=True) @@ -6856,8 +6792,7 @@ def traverse(start, pointer): return chains @doc_index("Clique-related methods") - def cliques_vertex_clique_number(self, algorithm='cliquer', vertices=None, - cliques=None): + def cliques_vertex_clique_number(self, algorithm='cliquer', vertices=None, cliques=None): """ Return a dictionary of sizes of the largest maximal cliques containing each vertex, keyed by vertex. @@ -6907,6 +6842,7 @@ def cliques_vertex_clique_number(self, algorithm='cliquer', vertices=None, """ if algorithm == "cliquer": from sage.graphs.cliquer import clique_number + if vertices is None: vertices = self value = {} @@ -6916,6 +6852,7 @@ def cliques_vertex_clique_number(self, algorithm='cliquer', vertices=None, return value if algorithm == "networkx": import networkx + return dict(networkx.node_clique_number(self.networkx_graph(), vertices, cliques)) raise NotImplementedError("Only 'networkx' and 'cliquer' are supported.") @@ -6990,6 +6927,7 @@ def cliques_containing_vertex(self, vertices=None, cliques=None): return [c for c in cliques if vertices in c] from collections import defaultdict + d = defaultdict(list) for c in cliques: @@ -7027,6 +6965,7 @@ def clique_complex(self): if self.is_directed() or self.has_loops() or self.has_multiple_edges(): raise ValueError("Self must be an undirected simple graph to have a clique complex.") import sage.topology.simplicial_complex + C = sage.topology.simplicial_complex.SimplicialComplex(self.cliques_maximal(), maximality_check=True) C._graph = self return C @@ -7055,10 +6994,10 @@ def clique_polynomial(self, t=None): if t is None: R = PolynomialRing(ZZ, 't') t = R.gen() - number_of = [0]*(self.order() + 1) + number_of = [0] * (self.order() + 1) for x in IndependentSets(self, complement=True): number_of[len(x)] += 1 - return sum(coeff*t**i for i, coeff in enumerate(number_of) if coeff) + return sum(coeff * t**i for i, coeff in enumerate(number_of) if coeff) # Miscellaneous @@ -7181,7 +7120,7 @@ def cores(self, k=None, with_labels=False): return ([], list(self)) if not k else (list(self), []) if with_labels: return {u: 0 for u in self} - return [0]*self.order() + return [0] * self.order() # Compute the degrees of each vertex and set up initial guesses for core degrees = self.degree(labels=True) @@ -7202,6 +7141,7 @@ def cores(self, k=None, with_labels=False): if k is not None and d >= k: # all vertices have degree >= k. We can return the solution from itertools import chain + return verts, list(chain(*bucket)) while bucket[d]: @@ -7241,7 +7181,7 @@ def cores(self, k=None, with_labels=False): # If all the vertices have a degree larger than k, we can return # our answer if k is not None if k is not None and core[v] >= k: - return verts[:vert_pos[v]], verts[vert_pos[v]:] + return verts[: vert_pos[v]], verts[vert_pos[v] :] for u in nbrs[v]: if core[u] > core[v]: @@ -7576,8 +7516,7 @@ def modular_decomposition(self, algorithm=None, style="tuple"): PRIME[2[], SERIES[0[], 1[]], PARALLEL[3[], 4[]], PARALLEL[5[], 6[], 7[]]] """ - from sage.graphs.graph_decompositions.modular_decomposition import \ - modular_decomposition + from sage.graphs.graph_decompositions.modular_decomposition import modular_decomposition D = modular_decomposition(self, algorithm=algorithm) @@ -7594,14 +7533,14 @@ def relabel(x): if style == 'tree': from sage.combinat.rooted_tree import LabelledRootedTree + if D.is_empty(): return LabelledRootedTree([]) def to_tree(x): if x.is_leaf(): return LabelledRootedTree([], label=x.children[0]) - return LabelledRootedTree([to_tree(y) for y in x.children], - label=x.node_type) + return LabelledRootedTree([to_tree(y) for y in x.children], label=x.node_type) return to_tree(D) @@ -7647,10 +7586,7 @@ def is_polyhedral(self) -> bool: sage: G.is_polyhedral() False """ - return (not self.has_loops() - and not self.has_multiple_edges() - and self.vertex_connectivity(k=3) - and self.is_planar()) + return not self.has_loops() and not self.has_multiple_edges() and self.vertex_connectivity(k=3) and self.is_planar() @doc_index("Graph properties") def is_circumscribable(self, solver='ppl', verbose=0): @@ -7720,6 +7656,7 @@ def is_circumscribable(self, solver='ppl', verbose=0): from sage.numerical.mip import MixedIntegerLinearProgram from sage.numerical.mip import MIPSolverException + # For a description of the algorithm see paper by Rivin and: # https://www.ics.uci.edu/~eppstein/junkyard/uninscribable/ # In order to simulate strict inequalities in the following LP, we @@ -7735,9 +7672,9 @@ def is_circumscribable(self, solver='ppl', verbose=0): for e in self.edge_iterator(labels=0): fe = frozenset(e) - M.set_max(e_var[fe], ZZ(1)/ZZ(2)) + M.set_max(e_var[fe], ZZ(1) / ZZ(2)) M.add_constraint(e_var[fe] - c[0], min=0) - M.add_constraint(e_var[fe] + c[0], max=ZZ(1)/ZZ(2)) + M.add_constraint(e_var[fe] + c[0], max=ZZ(1) / ZZ(2)) # The faces are completely determined by the graph structure: # for polyhedral graph, there is only one way to choose the faces. @@ -7757,7 +7694,7 @@ def is_circumscribable(self, solver='ppl', verbose=0): if len(cycle) > 3: scycle = frozenset(cycle) if scycle not in vfaces: - edges = (frozenset((cycle[i], cycle[i+1])) for i in range(len(cycle)-1)) + edges = (frozenset((cycle[i], cycle[i + 1])) for i in range(len(cycle) - 1)) inequality_constraints.add(frozenset(edges)) for ieq in inequality_constraints: @@ -7877,8 +7814,7 @@ def is_prime(self, algorithm=None): sage: graphs.EmptyGraph().is_prime() True """ - from sage.graphs.graph_decompositions.modular_decomposition import \ - modular_decomposition + from sage.graphs.graph_decompositions.modular_decomposition import modular_decomposition if self.order() <= 1: return True @@ -7888,8 +7824,7 @@ def is_prime(self, algorithm=None): return MD.is_prime() and len(MD.children) == self.order() @doc_index("Connectivity, orientations, trees") - def gomory_hu_tree(self, algorithm=None, solver=None, verbose=0, - *, integrality_tolerance=1e-3): + def gomory_hu_tree(self, algorithm=None, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a Gomory-Hu tree of ``self``. @@ -8054,10 +7989,7 @@ def gomory_hu_tree(self, algorithm=None, solver=None, verbose=0, # Compute a uv min-edge-cut. # # The graph is split into U,V with u \in U and v\in V. - flow, edges, [U, V] = G.edge_cut(u, v, use_edge_labels=True, - vertices=True, algorithm=algorithm, - solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + flow, edges, [U, V] = G.edge_cut(u, v, use_edge_labels=True, vertices=True, algorithm=algorithm, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) # Add edge (u, v, flow) to the Gomory-Hu tree T.add_edge(u, v, flow) @@ -8171,8 +8103,8 @@ def two_factor_petersen(self, solver=None, verbose=0, *, integrality_tolerance=1 # This new bipartite graph is now edge_colored from sage.graphs.graph_coloring import edge_coloring - classes = edge_coloring(g, solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + + classes = edge_coloring(g, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) # The edges in the classes are of the form ((-1,u),(1,v)) # and have to be translated back to (u,v) @@ -8359,7 +8291,7 @@ def magnitude_function(self): for j in range(i): dij = dist[vertices[i]][vertices[j]] if dij in ZZ: - Z[i, j] = Z[j, i] = q ** dij + Z[i, j] = Z[j, i] = q**dij else: Z[i, j] = Z[j, i] = ring.zero() return sum(sum(u) for u in ~Z) @@ -8517,6 +8449,7 @@ def effective_resistance(self, i, j, *, base_ring=None): +Infinity """ from sage.matrix.constructor import matrix + if i not in self: raise ValueError("vertex ({0}) is not a vertex of the graph".format(repr(i))) elif j not in self: @@ -8535,6 +8468,7 @@ def effective_resistance(self, i, j, *, base_ring=None): component = self.subgraph(connected_i) return component.effective_resistance(i, j) from sage.rings.infinity import Infinity + return Infinity vert = list(self) @@ -8550,8 +8484,7 @@ def effective_resistance(self, i, j, *, base_ring=None): return diff[0, 0] @doc_index("Leftovers") - def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, - *, base_ring=None, **kwds): + def effective_resistance_matrix(self, vertices=None, nonedgesonly=True, *, base_ring=None, **kwds): r""" Return a matrix whose (`i` , `j`) entry gives the effective resistance between vertices `i` and `j`. @@ -8800,8 +8733,7 @@ def least_effective_resistance(self, nonedgesonly=True): return [e for e in edges if S[(verttoidx[e[0]], verttoidx[e[1]])] == rmin] @doc_index("Leftovers") - def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, - *, base_ring=None, **kwds): + def common_neighbors_matrix(self, vertices=None, nonedgesonly=True, *, base_ring=None, **kwds): r""" Return a matrix of numbers of common neighbors between each pairs. @@ -9062,6 +8994,7 @@ def arboricity(self, certificate=False): (0, []) """ from sage.matroids.constructor import Matroid + P = Matroid(self).partition() if certificate: return (len(P), [self.subgraph(edges=forest) for forest in P]) @@ -9220,8 +9153,7 @@ def folded_graph(self, check=False): numCliques = len(newVertices) edges = [] for i, j in itertools.combinations(range(numCliques), 2): - if any(self.has_edge(u, v) for u, v in - itertools.product(newVertices[i], newVertices[j])): + if any(self.has_edge(u, v) for u, v in itertools.product(newVertices[i], newVertices[j])): edges.append((i, j)) H = Graph([range(numCliques), edges], format='vertices_and_edges') @@ -9428,14 +9360,14 @@ def is_projective_planar(self, return_map=False): """ from sage.graphs.generators.families import p2_forbidden_minors + num_verts_G = self.n_vertices() num_edges_G = self.n_edges() for forbidden_minor in p2_forbidden_minors(): # Can't be a minor if it has more vertices or edges than G - if (forbidden_minor.n_vertices() > num_verts_G - or forbidden_minor.n_edges() > num_edges_G): + if forbidden_minor.n_vertices() > num_verts_G or forbidden_minor.n_edges() > num_edges_G: continue try: @@ -9454,6 +9386,7 @@ def is_projective_planar(self, return_map=False): # Aliases to functions defined in other modules from sage.graphs.weakly_chordal import is_long_hole_free, is_long_antihole_free, is_weakly_chordal from sage.graphs.asteroidal_triples import is_asteroidal_triple_free + chromatic_polynomial = LazyImport('sage.graphs.chrompoly', 'chromatic_polynomial', at_startup=True) rank_decomposition = LazyImport('sage.graphs.graph_decompositions.rankwidth', 'rank_decomposition', at_startup=True) from sage.graphs.graph_decompositions.tree_decomposition import treewidth @@ -9463,6 +9396,7 @@ def is_projective_planar(self, return_map=False): from sage.graphs.graph_decompositions.bandwidth import bandwidth from sage.graphs.graph_decompositions.cutwidth import cutwidth from sage.graphs.graph_decompositions.slice_decomposition import slice_decomposition + matching_polynomial = LazyImport('sage.graphs.matchpoly', 'matching_polynomial', at_startup=True) from sage.graphs.cliquer import all_max_clique as cliques_maximum from sage.graphs.cliquer import all_cliques @@ -9489,13 +9423,13 @@ def is_projective_planar(self, return_map=False): from sage.graphs.connectivity import minimal_separators from sage.graphs.comparability import is_comparability from sage.graphs.comparability import is_permutation + geodetic_closure = LazyImport('sage.graphs.convexity_properties', 'geodetic_closure', at_startup=True) from sage.graphs.domination import is_dominating from sage.graphs.domination import is_redundant from sage.graphs.domination import private_neighbors from sage.graphs.domination import minimal_dominating_sets - from sage.graphs.traversals import (lex_M, maximum_cardinality_search, - maximum_cardinality_search_M) + from sage.graphs.traversals import lex_M, maximum_cardinality_search, maximum_cardinality_search_M from sage.graphs.isoperimetric_inequalities import cheeger_constant, edge_isoperimetric_number, vertex_isoperimetric_number from sage.graphs.graph_coloring import fractional_chromatic_number from sage.graphs.graph_coloring import fractional_chromatic_index @@ -9509,65 +9443,65 @@ def is_projective_planar(self, return_map=False): _additional_categories = { - "is_long_hole_free" : "Graph properties", - "is_long_antihole_free" : "Graph properties", - "is_weakly_chordal" : "Graph properties", - "is_asteroidal_triple_free" : "Graph properties", - "chromatic_polynomial" : "Coloring", - "rank_decomposition" : "Algorithmically hard stuff", - "treewidth" : "Algorithmically hard stuff", - "pathwidth" : "Algorithmically hard stuff", - "treelength" : "Algorithmically hard stuff", - "matching_polynomial" : "Algorithmically hard stuff", - "all_max_clique" : "Clique-related methods", - "cliques_maximum" : "Clique-related methods", - "all_cliques" : "Clique-related methods", - "atoms_and_clique_separators" : "Clique-related methods", - "random_spanning_tree" : "Connectivity, orientations, trees", - "spanning_trees" : "Connectivity, orientations, trees", - "is_cartesian_product" : "Graph properties", - "is_distance_regular" : "Graph properties", - "is_strongly_regular" : "Graph properties", - "is_line_graph" : "Graph properties", - "is_partial_cube" : "Graph properties", - "is_comparability" : "Graph properties", - "is_permutation" : "Graph properties", - "tutte_polynomial" : "Algorithmically hard stuff", - "lovasz_theta" : "Leftovers", + "is_long_hole_free": "Graph properties", + "is_long_antihole_free": "Graph properties", + "is_weakly_chordal": "Graph properties", + "is_asteroidal_triple_free": "Graph properties", + "chromatic_polynomial": "Coloring", + "rank_decomposition": "Algorithmically hard stuff", + "treewidth": "Algorithmically hard stuff", + "pathwidth": "Algorithmically hard stuff", + "treelength": "Algorithmically hard stuff", + "matching_polynomial": "Algorithmically hard stuff", + "all_max_clique": "Clique-related methods", + "cliques_maximum": "Clique-related methods", + "all_cliques": "Clique-related methods", + "atoms_and_clique_separators": "Clique-related methods", + "random_spanning_tree": "Connectivity, orientations, trees", + "spanning_trees": "Connectivity, orientations, trees", + "is_cartesian_product": "Graph properties", + "is_distance_regular": "Graph properties", + "is_strongly_regular": "Graph properties", + "is_line_graph": "Graph properties", + "is_partial_cube": "Graph properties", + "is_comparability": "Graph properties", + "is_permutation": "Graph properties", + "tutte_polynomial": "Algorithmically hard stuff", + "lovasz_theta": "Leftovers", "orient": "Connectivity, orientations, trees", "orientations": "Connectivity, orientations, trees", - "strong_orientation" : "Connectivity, orientations, trees", - "strong_orientations_iterator" : "Connectivity, orientations, trees", - "random_orientation" : "Connectivity, orientations, trees", - "acyclic_orientations" : "Connectivity, orientations, trees", + "strong_orientation": "Connectivity, orientations, trees", + "strong_orientations_iterator": "Connectivity, orientations, trees", + "random_orientation": "Connectivity, orientations, trees", + "acyclic_orientations": "Connectivity, orientations, trees", "minimum_outdegree_orientation": "Connectivity, orientations, trees", "bounded_outdegree_orientation": "Connectivity, orientations, trees", "eulerian_orientation": "Connectivity, orientations, trees", - "bridges" : "Connectivity, orientations, trees", - "cleave" : "Connectivity, orientations, trees", - "spqr_tree" : "Connectivity, orientations, trees", - "is_triconnected" : "Connectivity, orientations, trees", - "minimal_separators" : "Connectivity, orientations, trees", - "is_dominating" : "Domination", - "is_redundant" : "Domination", - "private_neighbors" : "Domination", - "minimal_dominating_sets" : "Domination", - "lex_M" : "Traversals", - "maximum_cardinality_search" : "Traversals", - "maximum_cardinality_search_M" : "Traversals", - "cheeger_constant" : "Expansion properties", - "edge_isoperimetric_number" : "Expansion properties", - "vertex_isoperimetric_number" : "Expansion properties", - "fractional_chromatic_number" : "Coloring", - "fractional_chromatic_index" : "Coloring", - "geodetic_closure" : "Leftovers", - "hyperbolicity" : "Distances", - "has_perfect_matching" : "Matching", - "is_bicritical" : "Matching", - "is_factor_critical" : "Matching", - "is_matching_covered" : "Matching", - "matching" : "Matching", - "perfect_matchings" : "Matching" + "bridges": "Connectivity, orientations, trees", + "cleave": "Connectivity, orientations, trees", + "spqr_tree": "Connectivity, orientations, trees", + "is_triconnected": "Connectivity, orientations, trees", + "minimal_separators": "Connectivity, orientations, trees", + "is_dominating": "Domination", + "is_redundant": "Domination", + "private_neighbors": "Domination", + "minimal_dominating_sets": "Domination", + "lex_M": "Traversals", + "maximum_cardinality_search": "Traversals", + "maximum_cardinality_search_M": "Traversals", + "cheeger_constant": "Expansion properties", + "edge_isoperimetric_number": "Expansion properties", + "vertex_isoperimetric_number": "Expansion properties", + "fractional_chromatic_number": "Coloring", + "fractional_chromatic_index": "Coloring", + "geodetic_closure": "Leftovers", + "hyperbolicity": "Distances", + "has_perfect_matching": "Matching", + "is_bicritical": "Matching", + "is_factor_critical": "Matching", + "is_matching_covered": "Matching", + "matching": "Matching", + "perfect_matchings": "Matching", } __doc__ = __doc__.replace("{INDEX_OF_METHODS}", gen_thematic_rest_table_index(Graph, _additional_categories)) diff --git a/src/sage/graphs/graph_database.py b/src/sage/graphs/graph_database.py index 7c50a1e2f0f..66f2e86d7e1 100644 --- a/src/sage/graphs/graph_database.py +++ b/src/sage/graphs/graph_database.py @@ -98,6 +98,7 @@ def data_to_degseq(data, graph6=None): if not degseq: # compute number of 0s in list from graph6 string from sage.graphs.generic_graph_pyx import length_and_string_from_graph6 + return length_and_string_from_graph6(str(graph6))[0] * [0] return degseq @@ -163,12 +164,10 @@ def subgraphs_to_query(subgraphs, db): q = GraphQuery(graph_db=db, induced_subgraphs=subgraphs[1]) if subgraphs[0] == 'all_of': for i in range(2, len(subgraphs)): - q.intersect(GraphQuery(graph_db=db, induced_subgraphs=subgraphs[i]), - in_place=True) + q.intersect(GraphQuery(graph_db=db, induced_subgraphs=subgraphs[i]), in_place=True) elif subgraphs[0] == 'one_of': for i in range(2, len(subgraphs)): - q.union(GraphQuery(graph_db=db, induced_subgraphs=subgraphs[i]), - in_place=True) + q.union(GraphQuery(graph_db=db, induced_subgraphs=subgraphs[i]), in_place=True) else: raise KeyError('unable to initiate query: illegal input format for induced_subgraphs') return q @@ -176,44 +175,11 @@ def subgraphs_to_query(subgraphs, db): # tables columns input data type sqlite data type # ----------------------------------------------------------------------------- -aut_grp = ['aut_grp_size', # Integer INTEGER - 'num_orbits', # Integer INTEGER - 'num_fixed_points', # Integer INTEGER - 'vertex_transitive', # bool BOOLEAN - 'edge_transitive'] # bool BOOLEAN -degrees = ['degree_sequence', # list INTEGER (see degseq_to_data module function) - 'min_degree', # Integer INTEGER - 'max_degree', # Integer INTEGER - 'average_degree', # Real REAL - 'degrees_sd', # Real REAL - 'regular'] # bool BOOLEAN -misc = ['vertex_connectivity', # Integer INTEGER - 'edge_connectivity', # Integer INTEGER - 'num_components', # Integer INTEGER - 'girth', # Integer INTEGER - 'radius', # Integer INTEGER - 'diameter', # Integer INTEGER - 'clique_number', # Integer INTEGER - 'independence_number', # Integer INTEGER - 'num_cut_vertices', # Integer INTEGER - 'min_vertex_cover_size', # Integer INTEGER - 'num_spanning_trees', # Integer INTEGER - 'induced_subgraphs'] # String STRING -spectrum = ['spectrum', # String STRING - 'min_eigenvalue', # Real REAL - 'max_eigenvalue', # Real REAL - 'eigenvalues_sd', # Real REAL - 'energy'] # Real REAL -graph_data = ['complement_graph6', # String STRING - 'eulerian', # bool BOOLEAN - 'graph6', # String STRING - 'lovasz_number', # Real REAL - 'num_cycles', # Integer INTEGER - 'num_edges', # Integer INTEGER - 'num_hamiltonian_cycles', # Integer INTEGER - 'num_vertices', # Integer INTEGER - 'perfect', # bool BOOLEAN - 'planar'] # bool BOOLEAN +aut_grp = ['aut_grp_size', 'num_orbits', 'num_fixed_points', 'vertex_transitive', 'edge_transitive'] # Integer INTEGER # Integer INTEGER # Integer INTEGER # bool BOOLEAN # bool BOOLEAN +degrees = ['degree_sequence', 'min_degree', 'max_degree', 'average_degree', 'degrees_sd', 'regular'] # list INTEGER (see degseq_to_data module function) # Integer INTEGER # Integer INTEGER # Real REAL # Real REAL # bool BOOLEAN +misc = ['vertex_connectivity', 'edge_connectivity', 'num_components', 'girth', 'radius', 'diameter', 'clique_number', 'independence_number', 'num_cut_vertices', 'min_vertex_cover_size', 'num_spanning_trees', 'induced_subgraphs'] # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # String STRING +spectrum = ['spectrum', 'min_eigenvalue', 'max_eigenvalue', 'eigenvalues_sd', 'energy'] # String STRING # Real REAL # Real REAL # Real REAL # Real REAL +graph_data = ['complement_graph6', 'eulerian', 'graph6', 'lovasz_number', 'num_cycles', 'num_edges', 'num_hamiltonian_cycles', 'num_vertices', 'perfect', 'planar'] # String STRING # bool BOOLEAN # String STRING # Real REAL # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # bool BOOLEAN # bool BOOLEAN valid_kwds = aut_grp + degrees + misc + spectrum + graph_data @@ -245,11 +211,7 @@ def graph_db_info(tablename=None): 'perfect', 'planar'] """ - info = {'graph_data': graph_data, - 'aut_grp': aut_grp, - 'degrees': degrees, - 'misc': misc, - 'spectrum': spectrum} + info = {'graph_data': graph_data, 'aut_grp': aut_grp, 'degrees': degrees, 'misc': misc, 'spectrum': spectrum} if tablename is not None: info = info[tablename] return info @@ -318,8 +280,7 @@ def __init__(self, query_string, database=None, param_tuple=None): class GraphQuery(GenericGraphQuery): - def __init__(self, graph_db=None, query_dict=None, display_cols=None, - immutable=False, **kwds): + def __init__(self, graph_db=None, query_dict=None, display_cols=None, immutable=False, **kwds): r""" A query for an instance of :class:`~GraphDatabase`. @@ -479,11 +440,9 @@ class located in :mod:`sage.databases.sql_db` to make the query # add key parameter to query join_dict = {qdict['table_name']: ('graph_id', 'graph_id')} if key == 'induced_subgraphs' and isinstance(kwds[key], list): - self.intersect(subgraphs_to_query(kwds[key], graph_db), - 'graph_data', join_dict, in_place=True) + self.intersect(subgraphs_to_query(kwds[key], graph_db), 'graph_data', join_dict, in_place=True) else: - self.intersect(SQLQuery(graph_db, qdict), 'graph_data', - join_dict, in_place=True) + self.intersect(SQLQuery(graph_db, qdict), 'graph_data', join_dict, in_place=True) # include search params (keys) in join clause # again, we exclude graph_data because it is the base table @@ -541,9 +500,7 @@ class located in :mod:`sage.databases.sql_db` to make the query disp_str = ''.join(disp_list) # substitute disp_str and join_str back into self's query string - self.__query_string__ = re.sub('SELECT.*WHERE ', - disp_str + join_str + 'WHERE ', - self.__query_string__) + self.__query_string__ = re.sub('SELECT.*WHERE ', disp_str + join_str + 'WHERE ', self.__query_string__) self.__query_string__ += ' ORDER BY graph_data.graph6' def query_iterator(self, immutable=None): @@ -715,14 +672,9 @@ def show(self, max_field_size=20, with_picture=False): else: format_cols = {} if with_picture: - SQLQuery.show(self, max_field_size=max_field_size, - plot_cols={'graph6': graph6_to_plot}, - format_cols=format_cols, id_col='graph6', - relabel_cols=relabel) + SQLQuery.show(self, max_field_size=max_field_size, plot_cols={'graph6': graph6_to_plot}, format_cols=format_cols, id_col='graph6', relabel_cols=relabel) else: - SQLQuery.show(self, max_field_size=max_field_size, - format_cols=format_cols, relabel_cols=relabel, - id_col='graph6') + SQLQuery.show(self, max_field_size=max_field_size, format_cols=format_cols, relabel_cols=relabel, id_col='graph6') def get_graphs_list(self, immutable=None): """ @@ -993,6 +945,7 @@ class will also interface with the optional database package containing 'unique': False}}} """ from sage.features.databases import DatabaseGraphs + dblocation = DatabaseGraphs().absolute_filename() SQLDatabase.__init__(self, dblocation) @@ -1012,7 +965,9 @@ def _gen_interact_func(self, display, **kwds): t = """ print('

Query Results:

') GraphQuery(display_cols=%s,%s).show(with_picture=True) - """ % tuple([display, ','.join(params)]) + """ % tuple( + [display, ','.join(params)] + ) s += '\t' + '\n\t'.join(t.split('\n')) + '\n' exec(s) return locals()[function_name] diff --git a/src/sage/graphs/graph_editor.py b/src/sage/graphs/graph_editor.py index fc1fc72ccc8..02a20a7b532 100644 --- a/src/sage/graphs/graph_editor.py +++ b/src/sage/graphs/graph_editor.py @@ -24,6 +24,7 @@ from sage.misc.lazy_import import lazy_import from sage.features.phitigra import Phitigra + lazy_import('phitigra', 'GraphEditor', feature=Phitigra()) diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 9becac43944..9b0ad6471b0 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -29,10 +29,7 @@ def __append_to_doc(methods): global __doc__ - __doc__ += ("\n.. csv-table::\n" - " :class: contentstable\n" - " :widths: 33, 33, 33\n" - " :delim: |\n\n") + __doc__ += "\n.. csv-table::\n" " :class: contentstable\n" " :widths: 33, 33, 33\n" " :delim: |\n\n" h = (len(methods) + 2) // 3 # Reorders the list of methods for horizontal reading, the only one Sphinx understands @@ -58,35 +55,7 @@ def wrap_name(x): **Basic structures** """ -__append_to_doc( - ["BullGraph", - "ButterflyGraph", - "CircularLadderGraph", - "ClawGraph", - "CycleGraph", - "CompleteBipartiteGraph", - "CompleteGraph", - "CompleteMultipartiteGraph", - "CorrelationGraph", - "DiamondGraph", - "GemGraph", - "DartGraph", - "ForkGraph", - "DipoleGraph", - "EmptyGraph", - "Grid2dGraph", - "GridGraph", - "HouseGraph", - "HouseXGraph", - "LadderGraph", - "LollipopGraph", - "MoebiusLadderGraph", - "PathGraph", - "StarGraph", - "TadpoleGraph", - "ToroidalGrid2dGraph", - "Toroidal6RegularGrid2dGraph"] - ) +__append_to_doc(["BullGraph", "ButterflyGraph", "CircularLadderGraph", "ClawGraph", "CycleGraph", "CompleteBipartiteGraph", "CompleteGraph", "CompleteMultipartiteGraph", "CorrelationGraph", "DiamondGraph", "GemGraph", "DartGraph", "ForkGraph", "DipoleGraph", "EmptyGraph", "Grid2dGraph", "GridGraph", "HouseGraph", "HouseXGraph", "LadderGraph", "LollipopGraph", "MoebiusLadderGraph", "PathGraph", "StarGraph", "TadpoleGraph", "ToroidalGrid2dGraph", "Toroidal6RegularGrid2dGraph"]) __doc__ += """ **Small Graphs** @@ -96,126 +65,124 @@ def wrap_name(x): """ __append_to_doc( - ["Balaban10Cage", - "Balaban11Cage", - "BidiakisCube", - "BiggsSmithGraph", - "BlanusaFirstSnarkGraph", - "BlanusaSecondSnarkGraph", - "BrinkmannGraph", - "BrouwerHaemersGraph", - "BuckyBall", - "CameronGraph", - "Cell600", - "Cell120", - "ChvatalGraph", - "ClebschGraph", - "cocliques_HoffmannSingleton", - "ConwaySmith_for_3S7", - "CoxeterGraph", - "CubeplexGraph", - "DesarguesGraph", - "DejterGraph", - "distance_3_doubly_truncated_Golay_code_graph", - "DoubleStarSnark", - "DoublyTruncatedWittGraph", - "DurerGraph", - "DyckGraph", - "EllinghamHorton54Graph", - "EllinghamHorton78Graph", - "ErreraGraph", - "F26AGraph", - "FlowerSnark", - "FolkmanGraph", - "FosterGraph", - "FosterGraph3S6", - "FranklinGraph", - "FruchtGraph", - "GoldnerHararyGraph", - "GolombGraph", - "GossetGraph", - "graph_3O73", - "GrayGraph", - "GritsenkoGraph", - "GrotzschGraph", - "HallJankoGraph", - "HarborthGraph", - "HarriesGraph", - "HarriesWongGraph", - "HeawoodGraph", - "HerschelGraph", - "HigmanSimsGraph", - "HoffmanGraph", - "HoffmanSingletonGraph", - "HoltGraph", - "HortonGraph", - "IoninKharaghani765Graph", - "IvanovIvanovFaradjevGraph", - "J2Graph", - "JankoKharaghaniGraph", - "JankoKharaghaniTonchevGraph", - "KittellGraph", - "KrackhardtKiteGraph", - "Klein3RegularGraph", - "Klein7RegularGraph", - "LargeWittGraph", - "LeonardGraph", - "LjubljanaGraph", - "vanLintSchrijverGraph", - "LivingstoneGraph", - "locally_GQ42_distance_transitive_graph", - "LocalMcLaughlinGraph", - "M22Graph", - "MarkstroemGraph", - "MathonStronglyRegularGraph", - "McGeeGraph", - "McLaughlinGraph", - "MeredithGraph", - "MoebiusKantorGraph", - "MoserSpindle", - "MurtyGraph", - "NauruGraph", - "PappusGraph", - "PoussinGraph", - "PerkelGraph", - "PetersenGraph", - "RobertsonGraph", - "SchlaefliGraph", - "shortened_00_11_binary_Golay_code_graph", - "shortened_000_111_extended_binary_Golay_code_graph", - "ShrikhandeGraph", - "SimsGewirtzGraph", - "SousselierGraph", - "SylvesterGraph", - "SzekeresSnarkGraph", - "ThomsenGraph", - "TietzeGraph", - "TricornGraph", - "TruncatedIcosidodecahedralGraph", - "TruncatedTetrahedralGraph", - "TruncatedWittGraph", - "Tutte12Cage", - "TutteCoxeterGraph", - "TutteGraph", - "TwinplexGraph", - "U42Graph216", - "U42Graph540", - "WagnerGraph", - "WatkinsSnarkGraph", - "WellsGraph", - "WienerArayaGraph", - "SuzukiGraph"]) + [ + "Balaban10Cage", + "Balaban11Cage", + "BidiakisCube", + "BiggsSmithGraph", + "BlanusaFirstSnarkGraph", + "BlanusaSecondSnarkGraph", + "BrinkmannGraph", + "BrouwerHaemersGraph", + "BuckyBall", + "CameronGraph", + "Cell600", + "Cell120", + "ChvatalGraph", + "ClebschGraph", + "cocliques_HoffmannSingleton", + "ConwaySmith_for_3S7", + "CoxeterGraph", + "CubeplexGraph", + "DesarguesGraph", + "DejterGraph", + "distance_3_doubly_truncated_Golay_code_graph", + "DoubleStarSnark", + "DoublyTruncatedWittGraph", + "DurerGraph", + "DyckGraph", + "EllinghamHorton54Graph", + "EllinghamHorton78Graph", + "ErreraGraph", + "F26AGraph", + "FlowerSnark", + "FolkmanGraph", + "FosterGraph", + "FosterGraph3S6", + "FranklinGraph", + "FruchtGraph", + "GoldnerHararyGraph", + "GolombGraph", + "GossetGraph", + "graph_3O73", + "GrayGraph", + "GritsenkoGraph", + "GrotzschGraph", + "HallJankoGraph", + "HarborthGraph", + "HarriesGraph", + "HarriesWongGraph", + "HeawoodGraph", + "HerschelGraph", + "HigmanSimsGraph", + "HoffmanGraph", + "HoffmanSingletonGraph", + "HoltGraph", + "HortonGraph", + "IoninKharaghani765Graph", + "IvanovIvanovFaradjevGraph", + "J2Graph", + "JankoKharaghaniGraph", + "JankoKharaghaniTonchevGraph", + "KittellGraph", + "KrackhardtKiteGraph", + "Klein3RegularGraph", + "Klein7RegularGraph", + "LargeWittGraph", + "LeonardGraph", + "LjubljanaGraph", + "vanLintSchrijverGraph", + "LivingstoneGraph", + "locally_GQ42_distance_transitive_graph", + "LocalMcLaughlinGraph", + "M22Graph", + "MarkstroemGraph", + "MathonStronglyRegularGraph", + "McGeeGraph", + "McLaughlinGraph", + "MeredithGraph", + "MoebiusKantorGraph", + "MoserSpindle", + "MurtyGraph", + "NauruGraph", + "PappusGraph", + "PoussinGraph", + "PerkelGraph", + "PetersenGraph", + "RobertsonGraph", + "SchlaefliGraph", + "shortened_00_11_binary_Golay_code_graph", + "shortened_000_111_extended_binary_Golay_code_graph", + "ShrikhandeGraph", + "SimsGewirtzGraph", + "SousselierGraph", + "SylvesterGraph", + "SzekeresSnarkGraph", + "ThomsenGraph", + "TietzeGraph", + "TricornGraph", + "TruncatedIcosidodecahedralGraph", + "TruncatedTetrahedralGraph", + "TruncatedWittGraph", + "Tutte12Cage", + "TutteCoxeterGraph", + "TutteGraph", + "TwinplexGraph", + "U42Graph216", + "U42Graph540", + "WagnerGraph", + "WatkinsSnarkGraph", + "WellsGraph", + "WienerArayaGraph", + "SuzukiGraph", + ] +) __doc__ += """ **Platonic solids** (ordered ascending by number of vertices) """ -__append_to_doc( - ["TetrahedralGraph", - "OctahedralGraph", - "HexahedralGraph", - "IcosahedralGraph", - "DodecahedralGraph"]) +__append_to_doc(["TetrahedralGraph", "OctahedralGraph", "HexahedralGraph", "IcosahedralGraph", "DodecahedralGraph"]) __doc__ += """ **Families of graphs** @@ -227,76 +194,79 @@ def wrap_name(x): """ __append_to_doc( - ["AlternatingFormsGraph", - "AztecDiamondGraph", - "BarbellGraph", - "BilinearFormsGraph", - "BiwheelGraph", - "BubbleSortGraph", - "CaiFurerImmermanGraph", - "chang_graphs", - "CirculantGraph", - "cographs", - "cospectral_graphs", - "CubeGraph", - "CubeConnectedCycle", - "distance_regular_graph", - "DorogovtsevGoltsevMendesGraph", - "DoubleGrassmannGraph", - "DoubleOddGraph", - "EgawaGraph", - "FoldedCubeGraph", - "FriendshipGraph", - "fullerenes", - "FurerGadget", - "fusenes", - "FuzzyBallGraph", - "GeneralisedDodecagonGraph", - "GeneralisedHexagonGraph", - "GeneralisedOctagonGraph", - "GeneralizedPetersenGraph", - "GeneralizedSierpinskiGraph", - "GoethalsSeidelGraph", - "GrassmannGraph", - "HalfCube", - "HammingGraph", - "HanoiTowerGraph", - "HararyGraph", - "HermitianFormsGraph", - "HyperStarGraph", - "JohnsonGraph", - "KneserGraph", - "LCFGraph", - "line_graph_forbidden_subgraphs", - "MathonPseudocyclicMergingGraph", - "MathonPseudocyclicStronglyRegularGraph", - "MuzychukS6Graph", - "MycielskiGraph", - "MycielskiStep", - "nauty_geng", - "nauty_genbg", - "NKStarGraph", - "NStarGraph", - "OddGraph", - "PaleyGraph", - "PasechnikGraph", - "petersen_family", - "p2_forbidden_minors", - "planar_graphs", - "plantri_gen", - "quadrangulations", - "RingedTree", - "SierpinskiGasketGraph", - "SquaredSkewHadamardMatrixGraph", - "SwitchedSquaredSkewHadamardMatrixGraph", - "StaircaseGraph", - "strongly_regular_graph", - "TruncatedBiwheelGraph", - "triangulations", - "TuranGraph", - "UstimenkoGraph", - "WheelGraph", - "WindmillGraph"]) + [ + "AlternatingFormsGraph", + "AztecDiamondGraph", + "BarbellGraph", + "BilinearFormsGraph", + "BiwheelGraph", + "BubbleSortGraph", + "CaiFurerImmermanGraph", + "chang_graphs", + "CirculantGraph", + "cographs", + "cospectral_graphs", + "CubeGraph", + "CubeConnectedCycle", + "distance_regular_graph", + "DorogovtsevGoltsevMendesGraph", + "DoubleGrassmannGraph", + "DoubleOddGraph", + "EgawaGraph", + "FoldedCubeGraph", + "FriendshipGraph", + "fullerenes", + "FurerGadget", + "fusenes", + "FuzzyBallGraph", + "GeneralisedDodecagonGraph", + "GeneralisedHexagonGraph", + "GeneralisedOctagonGraph", + "GeneralizedPetersenGraph", + "GeneralizedSierpinskiGraph", + "GoethalsSeidelGraph", + "GrassmannGraph", + "HalfCube", + "HammingGraph", + "HanoiTowerGraph", + "HararyGraph", + "HermitianFormsGraph", + "HyperStarGraph", + "JohnsonGraph", + "KneserGraph", + "LCFGraph", + "line_graph_forbidden_subgraphs", + "MathonPseudocyclicMergingGraph", + "MathonPseudocyclicStronglyRegularGraph", + "MuzychukS6Graph", + "MycielskiGraph", + "MycielskiStep", + "nauty_geng", + "nauty_genbg", + "NKStarGraph", + "NStarGraph", + "OddGraph", + "PaleyGraph", + "PasechnikGraph", + "petersen_family", + "p2_forbidden_minors", + "planar_graphs", + "plantri_gen", + "quadrangulations", + "RingedTree", + "SierpinskiGasketGraph", + "SquaredSkewHadamardMatrixGraph", + "SwitchedSquaredSkewHadamardMatrixGraph", + "StaircaseGraph", + "strongly_regular_graph", + "TruncatedBiwheelGraph", + "triangulations", + "TuranGraph", + "UstimenkoGraph", + "WheelGraph", + "WindmillGraph", + ] +) __doc__ += """ @@ -306,34 +276,13 @@ def wrap_name(x): quadrics and Hermitean varieties there. """ -__append_to_doc( - ["AffineOrthogonalPolarGraph", - "AhrensSzekeresGeneralizedQuadrangleGraph", - "NonisotropicOrthogonalPolarGraph", - "NonisotropicUnitaryPolarGraph", - "OrthogonalDualPolarGraph", - "OrthogonalPolarGraph", - "SymplecticDualPolarGraph", - "SymplecticPolarGraph", - "TaylorTwographDescendantSRG", - "TaylorTwographSRG", - "T2starGeneralizedQuadrangleGraph", - "Nowhere0WordsTwoWeightCodeGraph", - "HaemersGraph", - "CossidentePenttilaGraph", - "UnitaryDualPolarGraph", - "UnitaryPolarGraph"]) +__append_to_doc(["AffineOrthogonalPolarGraph", "AhrensSzekeresGeneralizedQuadrangleGraph", "NonisotropicOrthogonalPolarGraph", "NonisotropicUnitaryPolarGraph", "OrthogonalDualPolarGraph", "OrthogonalPolarGraph", "SymplecticDualPolarGraph", "SymplecticPolarGraph", "TaylorTwographDescendantSRG", "TaylorTwographSRG", "T2starGeneralizedQuadrangleGraph", "Nowhere0WordsTwoWeightCodeGraph", "HaemersGraph", "CossidentePenttilaGraph", "UnitaryDualPolarGraph", "UnitaryPolarGraph"]) __doc__ += """ **Chessboard Graphs** """ -__append_to_doc( - ["BishopGraph", - "KingGraph", - "KnightGraph", - "QueenGraph", - "RookGraph"]) +__append_to_doc(["BishopGraph", "KingGraph", "KnightGraph", "QueenGraph", "RookGraph"]) __doc__ += """ **Intersection graphs** @@ -343,74 +292,31 @@ def wrap_name(x): of objects yield the graph edges. """ -__append_to_doc( - ["IntersectionGraph", - "IntervalGraph", - "OrthogonalArrayBlockGraph", - "PermutationGraph", - "ToleranceGraph"]) +__append_to_doc(["IntersectionGraph", "IntervalGraph", "OrthogonalArrayBlockGraph", "PermutationGraph", "ToleranceGraph"]) __doc__ += """ **Random graphs** """ -__append_to_doc( - ["RandomBarabasiAlbert", - "RandomBicubicPlanar", - "RandomBipartite", - "RandomRegularBipartite", - "RandomBlockGraph", - "RandomBoundedToleranceGraph", - "RandomChordalGraph", - "RandomGNM", - "RandomGNP", - "RandomHolmeKim", - "RandomIntervalGraph", - "RandomKTree", - "RandomPartialKTree", - "RandomNewmanWattsStrogatz", - "RandomProperIntervalGraph", - "RandomRegular", - "RandomShell", - "RandomToleranceGraph", - "RandomTriangulation", - "RandomUnitDiskGraph"]) +__append_to_doc(["RandomBarabasiAlbert", "RandomBicubicPlanar", "RandomBipartite", "RandomRegularBipartite", "RandomBlockGraph", "RandomBoundedToleranceGraph", "RandomChordalGraph", "RandomGNM", "RandomGNP", "RandomHolmeKim", "RandomIntervalGraph", "RandomKTree", "RandomPartialKTree", "RandomNewmanWattsStrogatz", "RandomProperIntervalGraph", "RandomRegular", "RandomShell", "RandomToleranceGraph", "RandomTriangulation", "RandomUnitDiskGraph"]) __doc__ += """ **Trees** """ -__append_to_doc( - ["BalancedTree", - "FibonacciTree", - "Caterpillar", - "RandomLobster", - "RandomTree", - "RandomTreePowerlaw", - "trees", - "nauty_gentreeg"]) +__append_to_doc(["BalancedTree", "FibonacciTree", "Caterpillar", "RandomLobster", "RandomTree", "RandomTreePowerlaw", "trees", "nauty_gentreeg"]) __doc__ += """ **Graphs with a given degree sequence** """ -__append_to_doc( - ["DegreeSequence", - "DegreeSequenceBipartite", - "DegreeSequenceConfigurationModel", - "DegreeSequenceExpected", - "DegreeSequenceTree"]) +__append_to_doc(["DegreeSequence", "DegreeSequenceBipartite", "DegreeSequenceConfigurationModel", "DegreeSequenceExpected", "DegreeSequenceTree"]) __doc__ += """ **Miscellaneous** """ -__append_to_doc( - ["WorldMap", - "EuropeMap", - "AfricaMap", - "USAMap"] - ) +__append_to_doc(["WorldMap", "EuropeMap", "AfricaMap", "USAMap"]) __doc__ += """ @@ -768,13 +674,11 @@ class GraphGenerators: of Algorithms*, Volume 26, Issue 2, February 1998, pages 306-324. """ -########################################################################### -# Graph Iterators -########################################################################### + ########################################################################### + # Graph Iterators + ########################################################################### - def __call__(self, vertices=None, property=None, augment='edges', size=None, - degree_sequence=None, loops=False, sparse=True, copy=True, - immutable=False): + def __call__(self, vertices=None, property=None, augment='edges', size=None, degree_sequence=None, loops=False, sparse=True, copy=True, immutable=False): """ Access the generator of isomorphism class representatives. Iterates over distinct, exhaustive representatives. See the docstring @@ -820,31 +724,32 @@ def __call__(self, vertices=None, property=None, augment='edges', size=None, pages 306-324. """ # Use nauty for the basic case, as it is much faster. - if (vertices and property is None and size is None and - degree_sequence is None and not loops and augment == 'edges' and - sparse and (copy or immutable)): + if vertices and property is None and size is None and degree_sequence is None and not loops and augment == 'edges' and sparse and (copy or immutable): yield from graphs.nauty_geng(vertices, immutable=immutable) return if property is None: + def property(x): return True if degree_sequence is not None: if vertices is None: raise NotImplementedError - if (len(degree_sequence) != vertices or sum(degree_sequence) % 2 - or sum(degree_sequence) > vertices * (vertices - 1)): + if len(degree_sequence) != vertices or sum(degree_sequence) % 2 or sum(degree_sequence) > vertices * (vertices - 1): raise ValueError("Invalid degree sequence.") degree_sequence = sorted(degree_sequence) if augment == 'edges': + def property(x): D = sorted(x.degree()) return all(degree_sequence[i] >= d for i, d in enumerate(D)) def extra_property(x): return degree_sequence == sorted(x.degree()) + else: + def property(x): D = sorted(x.degree() + [0] * (vertices - x.n_vertices())) return all(degree_sequence[i] >= d for i, d in enumerate(D)) @@ -853,10 +758,14 @@ def extra_property(x): if x.n_vertices() != vertices: return False return degree_sequence == sorted(x.degree()) + elif size is not None: + def extra_property(x): return x.size() == size + else: + def extra_property(x): return True @@ -870,6 +779,7 @@ def extra_property(x): elif augment == 'edges': if vertices is None: from sage.rings.integer import Integer + vertices = Integer(0) while True: for g in self(vertices, loops=loops, sparse=sparse): @@ -1016,11 +926,9 @@ def nauty_geng(self, options='', debug=False, immutable=False): import shlex from sage.features.nauty import NautyExecutable + geng_path = NautyExecutable("geng").absolute_filename() - with subprocess.Popen(shlex.quote(geng_path) + " {0}".format(options), shell=True, - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, close_fds=True, - encoding='latin-1') as sp: + with subprocess.Popen(shlex.quote(geng_path) + " {0}".format(options), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, encoding='latin-1') as sp: msg = sp.stderr.readline() if debug: yield msg @@ -1203,11 +1111,9 @@ def nauty_genbg(self, options='', debug=False, immutable=False): import shlex from sage.features.nauty import NautyExecutable + genbg_path = NautyExecutable("genbgL").absolute_filename() - with subprocess.Popen(shlex.quote(genbg_path) + " {0}".format(options), shell=True, - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, close_fds=True, - encoding='latin-1') as sp: + with subprocess.Popen(shlex.quote(genbg_path) + " {0}".format(options), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, encoding='latin-1') as sp: msg = sp.stderr.readline() if debug: yield msg @@ -1219,6 +1125,7 @@ def nauty_genbg(self, options='', debug=False, immutable=False): for s in msg.split(' '): if s.startswith('n='): from sage.rings.integer import Integer + n1, n2 = (Integer(t) for t in s[2:].split('+') if t.isdigit()) partition = [set(range(n1)), set(range(n1, n1 + n2))] break @@ -1231,14 +1138,14 @@ def nauty_genbg(self, options='', debug=False, immutable=False): gen = sp.stdout from sage.graphs.bipartite_graph import BipartiteGraph + while True: try: s = next(gen) except StopIteration: # Exhausted list of bipartite graphs from nauty genbgL return - yield BipartiteGraph(s[:-1], format='graph6', partition=partition, - immutable=immutable) + yield BipartiteGraph(s[:-1], format='graph6', partition=partition, immutable=immutable) def nauty_genktreeg(self, options='', debug=False, immutable=False): r""" @@ -1339,11 +1246,9 @@ def nauty_genktreeg(self, options='', debug=False, immutable=False): import shlex from sage.features.nauty import NautyExecutable + geng_path = NautyExecutable("genktreeg").absolute_filename() - with subprocess.Popen(shlex.quote(geng_path) + " {0}".format(options), shell=True, - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, close_fds=True, - encoding='latin-1') as sp: + with subprocess.Popen(shlex.quote(geng_path) + " {0}".format(options), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, encoding='latin-1') as sp: msg = sp.stderr.readline() if debug: yield msg @@ -1358,8 +1263,7 @@ def nauty_genktreeg(self, options='', debug=False, immutable=False): return yield graph.Graph(s[:-1], format='graph6', immutable=immutable) - def cospectral_graphs(self, vertices, matrix_function=None, graphs=None, - immutable=False): + def cospectral_graphs(self, vertices, matrix_function=None, graphs=None, immutable=False): r""" Find all sets of graphs on ``vertices`` vertices (with possible restrictions) which are cospectral with respect to a @@ -1463,15 +1367,16 @@ def prop(x): return True from sage.graphs.graph_generators import graphs as graph_gen + if graphs is None: graph_list = graph_gen(vertices, property=prop, immutable=immutable) elif callable(graphs): - graph_list = (g for g in graph_gen(vertices, property=prop, - immutable=immutable) if graphs(g)) + graph_list = (g for g in graph_gen(vertices, property=prop, immutable=immutable) if graphs(g)) else: graph_list = iter(graphs) from collections import defaultdict + charpolys = defaultdict(list) for g in graph_list: cp = matrix_function(g).charpoly() @@ -1599,8 +1504,7 @@ def _read_planar_code(self, code_input, immutable=False): # construct graph based on g # first taking care that every edge is given twice - edges_g = {i + 1: [j for j in di if j < i + 1] - for i, di in enumerate(g)} + edges_g = {i + 1: [j for j in di if j < i + 1] for i, di in enumerate(g)} # then adding half of the loops (if any) has_loops = False @@ -1711,15 +1615,15 @@ def fullerenes(self, order, ipr=False, immutable=False): return from sage.features.graph_generators import Buckygen + Buckygen().require() import shlex + command = shlex.quote(Buckygen().absolute_filename()) command += ' -' + ('I' if ipr else '') + 'd {0}d'.format(order) - with subprocess.Popen(command, shell=True, - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, close_fds=True) as sp: + with subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) as sp: yield from graphs._read_planar_code(sp.stdout, immutable=immutable) @@ -1799,15 +1703,15 @@ def fusenes(self, hexagon_count, benzenoids=False, immutable=False): return from sage.features.graph_generators import Benzene + Benzene().require() import shlex + command = shlex.quote(Benzene().absolute_filename()) command += (' b' if benzenoids else '') + ' {0} p'.format(hexagon_count) - with subprocess.Popen(command, shell=True, - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, close_fds=True) as sp: + with subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) as sp: yield from graphs._read_planar_code(sp.stdout, immutable=immutable) @@ -1985,29 +1889,20 @@ def plantri_gen(self, options="", immutable=False): AttributeError: invalid options '6 -c=3' """ from sage.features.graph_generators import Plantri + Plantri().require() import shlex - command = '{} {}'.format(shlex.quote(Plantri().absolute_filename()), - options) - with subprocess.Popen(command, shell=True, - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, close_fds=True) as sp: + + command = '{} {}'.format(shlex.quote(Plantri().absolute_filename()), options) + with subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) as sp: try: yield from graphs._read_planar_code(sp.stdout, immutable=immutable) except (TypeError, AssertionError): raise AttributeError("invalid options '{}'".format(options)) - def planar_graphs(self, order, minimum_degree=None, - minimum_connectivity=None, - exact_connectivity=False, - minimum_edges=None, - maximum_edges=None, - maximum_face_size=None, - only_bipartite=False, - dual=False, - immutable=False): + def planar_graphs(self, order, minimum_degree=None, minimum_connectivity=None, exact_connectivity=False, minimum_edges=None, maximum_edges=None, maximum_face_size=None, only_bipartite=False, dual=False, immutable=False): r""" An iterator over connected planar graphs using the plantri generator. @@ -2188,8 +2083,7 @@ def planar_graphs(self, order, minimum_degree=None, minimum_degree, minimum_connectivity = 1, 1 elif minimum_degree is None: minimum_degree = minimum_connectivity - elif (minimum_degree < minimum_connectivity and - minimum_degree > 0): + elif minimum_degree < minimum_connectivity and minimum_degree > 0: raise ValueError("Minimum connectivity can be at most the minimum degree.") # exact connectivity is not implemented for minimum connectivity ≥ 3 @@ -2211,8 +2105,7 @@ def planar_graphs(self, order, minimum_degree=None, if maximum_edges is None: edges = '-e{}:'.format(minimum_edges) elif minimum_edges > maximum_edges: - raise ValueError("the maximum number of edges must be larger " - "or equal to the minimum number of edges") + raise ValueError("the maximum number of edges must be larger " "or equal to the minimum number of edges") elif minimum_edges == maximum_edges: edges = '-e{}'.format(minimum_edges) else: @@ -2240,19 +2133,11 @@ def planar_graphs(self, order, minimum_degree=None, return cmd = '-p{}m{}c{}{}{} {} {} {}' - command = cmd.format('b' if only_bipartite else '', - minimum_degree, - minimum_connectivity, - 'x' if exact_connectivity else '', - 'd' if dual else '', - edges, faces, - order) + command = cmd.format('b' if only_bipartite else '', minimum_degree, minimum_connectivity, 'x' if exact_connectivity else '', 'd' if dual else '', edges, faces, order) yield from graphs.plantri_gen(command, immutable=immutable) - def triangulations(self, order, minimum_degree=None, minimum_connectivity=None, - exact_connectivity=False, only_eulerian=False, dual=False, - immutable=False): + def triangulations(self, order, minimum_degree=None, minimum_connectivity=None, exact_connectivity=False, only_eulerian=False, dual=False, immutable=False): r""" An iterator over connected planar triangulations using the plantri generator. @@ -2430,18 +2315,11 @@ def triangulations(self, order, minimum_degree=None, minimum_connectivity=None, return cmd = '-{}m{}c{}{}{} {}' - command = cmd.format('b' if only_eulerian else '', - minimum_degree, - minimum_connectivity, - 'x' if exact_connectivity else '', - 'd' if dual else '', - order) + command = cmd.format('b' if only_eulerian else '', minimum_degree, minimum_connectivity, 'x' if exact_connectivity else '', 'd' if dual else '', order) yield from graphs.plantri_gen(command, immutable=immutable) - def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None, - no_nonfacial_quadrangles=False, dual=False, - immutable=False): + def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None, no_nonfacial_quadrangles=False, dual=False, immutable=False): r""" An iterator over planar quadrangulations using the plantri generator. @@ -2544,10 +2422,8 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None if minimum_degree not in {None, 2, 3}: raise ValueError("Minimum degree should be None, 2 or 3.") - if (no_nonfacial_quadrangles and - minimum_connectivity == 2): - raise NotImplementedError("Generation of no non-facial quadrangles " - "and minimum connectivity 2 is not implemented") + if no_nonfacial_quadrangles and minimum_connectivity == 2: + raise NotImplementedError("Generation of no non-facial quadrangles " "and minimum connectivity 2 is not implemented") # check combination of values of minimum degree and minimum connectivity if minimum_connectivity is None: @@ -2570,17 +2446,15 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None minimum_connectivity = 4 cmd = '-qm{}c{}{} {}' - command = cmd.format(minimum_degree, - minimum_connectivity, - 'd' if dual else '', - order) + command = cmd.format(minimum_degree, minimum_connectivity, 'd' if dual else '', order) yield from graphs.plantri_gen(command, immutable=immutable) -########################################################################### -# Basic Graphs -########################################################################### + ########################################################################### + # Basic Graphs + ########################################################################### from sage.graphs.generators import basic + BullGraph = staticmethod(basic.BullGraph) ButterflyGraph = staticmethod(basic.ButterflyGraph) CircularLadderGraph = staticmethod(basic.CircularLadderGraph) @@ -2606,10 +2480,11 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None Toroidal6RegularGrid2dGraph = staticmethod(basic.Toroidal6RegularGrid2dGraph) ToroidalGrid2dGraph = staticmethod(basic.ToroidalGrid2dGraph) -########################################################################### -# Small Graphs -########################################################################### + ########################################################################### + # Small Graphs + ########################################################################### from sage.graphs.generators import distance_regular, smallgraphs + Balaban10Cage = staticmethod(smallgraphs.Balaban10Cage) Balaban11Cage = staticmethod(smallgraphs.Balaban11Cage) BidiakisCube = staticmethod(smallgraphs.BidiakisCube) @@ -2720,22 +2595,24 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None WienerArayaGraph = staticmethod(smallgraphs.WienerArayaGraph) SuzukiGraph = staticmethod(smallgraphs.SuzukiGraph) -########################################################################### -# Platonic Solids -########################################################################### + ########################################################################### + # Platonic Solids + ########################################################################### from sage.graphs.generators import platonic_solids + DodecahedralGraph = staticmethod(platonic_solids.DodecahedralGraph) HexahedralGraph = staticmethod(platonic_solids.HexahedralGraph) IcosahedralGraph = staticmethod(platonic_solids.IcosahedralGraph) OctahedralGraph = staticmethod(platonic_solids.OctahedralGraph) TetrahedralGraph = staticmethod(platonic_solids.TetrahedralGraph) -########################################################################### -# Families -########################################################################### + ########################################################################### + # Families + ########################################################################### from sage.graphs import cographs as cographs_module from sage.graphs import strongly_regular_db from sage.graphs.generators import families + AlternatingFormsGraph = staticmethod(distance_regular.AlternatingFormsGraph) AztecDiamondGraph = staticmethod(families.AztecDiamondGraph) BarbellGraph = staticmethod(families.BarbellGraph) @@ -2805,10 +2682,11 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None WheelGraph = staticmethod(families.WheelGraph) WindmillGraph = staticmethod(families.WindmillGraph) -########################################################################### -# Graphs from classical geometries over `F_q` -########################################################################### + ########################################################################### + # Graphs from classical geometries over `F_q` + ########################################################################### from sage.graphs.generators import classical_geometries + AffineOrthogonalPolarGraph = staticmethod(classical_geometries.AffineOrthogonalPolarGraph) AhrensSzekeresGeneralizedQuadrangleGraph = staticmethod(classical_geometries.AhrensSzekeresGeneralizedQuadrangleGraph) NonisotropicOrthogonalPolarGraph = staticmethod(classical_geometries.NonisotropicOrthogonalPolarGraph) @@ -2826,10 +2704,11 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None UnitaryDualPolarGraph = staticmethod(classical_geometries.UnitaryDualPolarGraph) UnitaryPolarGraph = staticmethod(classical_geometries.UnitaryPolarGraph) -########################################################################### -# Chessboard Graphs -########################################################################### + ########################################################################### + # Chessboard Graphs + ########################################################################### from sage.graphs.generators import chessboard + ChessboardGraphGenerator = staticmethod(chessboard.ChessboardGraphGenerator) BishopGraph = staticmethod(chessboard.BishopGraph) KingGraph = staticmethod(chessboard.KingGraph) @@ -2837,20 +2716,22 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None QueenGraph = staticmethod(chessboard.QueenGraph) RookGraph = staticmethod(chessboard.RookGraph) -########################################################################### -# Intersection graphs -########################################################################### + ########################################################################### + # Intersection graphs + ########################################################################### from sage.graphs.generators import intersection + IntervalGraph = staticmethod(intersection.IntervalGraph) IntersectionGraph = staticmethod(intersection.IntersectionGraph) PermutationGraph = staticmethod(intersection.PermutationGraph) OrthogonalArrayBlockGraph = staticmethod(intersection.OrthogonalArrayBlockGraph) ToleranceGraph = staticmethod(intersection.ToleranceGraph) -########################################################################### -# Random Graphs -########################################################################### + ########################################################################### + # Random Graphs + ########################################################################### from sage.graphs.generators import random + RandomBarabasiAlbert = staticmethod(random.RandomBarabasiAlbert) RandomBipartite = staticmethod(random.RandomBipartite) RandomRegularBipartite = staticmethod(random.RandomRegularBipartite) @@ -2872,10 +2753,11 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None RandomTriangulation = staticmethod(random.RandomTriangulation) RandomUnitDiskGraph = staticmethod(random.RandomUnitDiskGraph) -########################################################################### -# Trees -########################################################################### + ########################################################################### + # Trees + ########################################################################### from sage.graphs.generators import trees as gen_trees + BalancedTree = staticmethod(gen_trees.BalancedTree) FibonacciTree = staticmethod(gen_trees.FibonacciTree) nauty_gentreeg = staticmethod(gen_trees.nauty_gentreeg) @@ -2885,19 +2767,21 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None RandomTree = staticmethod(gen_trees.RandomTree) trees = staticmethod(gen_trees.trees) -########################################################################### -# Maps -########################################################################### + ########################################################################### + # Maps + ########################################################################### from sage.graphs.generators import world_map + WorldMap = staticmethod(world_map.WorldMap) EuropeMap = staticmethod(world_map.EuropeMap) AfricaMap = staticmethod(world_map.AfricaMap) USAMap = staticmethod(world_map.USAMap) -########################################################################### -# Degree Sequence -########################################################################### + ########################################################################### + # Degree Sequence + ########################################################################### from sage.graphs.generators import degree_sequence + DegreeSequence = staticmethod(degree_sequence.DegreeSequence) DegreeSequenceBipartite = staticmethod(degree_sequence.DegreeSequenceBipartite) DegreeSequenceConfigurationModel = staticmethod(degree_sequence.DegreeSequenceConfigurationModel) @@ -2960,6 +2844,7 @@ def canaug_traverse_vert(g, aut_gens, max_verts, property, dig=False, loops=Fals Digraph on 2 vertices """ from sage.groups.perm_gps.partn_ref.refinement_graphs import search_tree + if not property(g): return yield g @@ -2976,7 +2861,7 @@ def canaug_traverse_vert(g, aut_gens, max_verts, property, dig=False, loops=Fals else: possibilities = n num_roots = 2**possibilities - children = [-1]*num_roots + children = [-1] * num_roots # union-find C(g) under Aut(g) for gen in aut_gens: @@ -2985,9 +2870,9 @@ def canaug_traverse_vert(g, aut_gens, max_verts, property, dig=False, loops=Fals for j in range(possibilities): if (1 << j) & i: if dig and j >= n: - k += (1 << (gen[j - n] + n)) + k += 1 << (gen[j - n] + n) else: - k += (1 << gen[j]) + k += 1 << gen[j] while children[k] != -1: k = children[k] while children[i] != -1: @@ -3077,6 +2962,7 @@ def check_aut(aut_gens, cut_vert, n): [[1, 0, 3, 2], [1, 2, 3, 0]] """ from copy import copy + perm = list(range(n + 1)) seen_perms = [perm] unchecked_perms = [perm] @@ -3234,7 +3120,7 @@ def canaug_traverse_edge(g, aut_gens, property, dig=False, loops=False, sparse=T if not property(z): continue z_aut_gens, _, canonical_relabeling = search_tree(z, [z.vertices(sort=True)], certificate=True, dig=(dig or loops)) - relabel_inverse = [0]*n + relabel_inverse = [0] * n for ii in range(n): relabel_inverse[canonical_relabeling[ii]] = ii z_can = z.relabel(canonical_relabeling, inplace=False) @@ -3246,6 +3132,7 @@ def canaug_traverse_edge(g, aut_gens, property, dig=False, loops=False, sparse=T cut_edge = tuple(sorted(cut_edge)) from copy import copy + m_z = copy(z) m_z.delete_edge(cut_edge) if m_z == g: @@ -3281,6 +3168,7 @@ def check_aut_edge(aut_gens, cut_edge, i, j, n, dig=False): [[1, 0, 3, 2], [1, 2, 3, 0]] """ from copy import copy + perm = list(range(n)) seen_perms = [perm] unchecked_perms = [perm] diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index 678fdbcf32e..8eaa7491bb9 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -17,6 +17,7 @@ Functions --------- """ + from sage.cpython.string import bytes_to_str from sage.misc.rest_index_of_methods import gen_rest_table_index import sys @@ -100,20 +101,21 @@ def from_sparse6(G, g6_string): edges = [] else: from sage.rings.integer_ring import ZZ + k = int((ZZ(n) - 1).nbits()) ords = [ord(i) for i in s] if any(o > 126 or o < 63 for o in ords): raise RuntimeError("the string seems corrupt: valid characters are \n" + ''.join(chr(i) for i in range(63, 127))) - bits = ''.join(int_to_binary_string(o-63).zfill(6) for o in ords) + bits = ''.join(int_to_binary_string(o - 63).zfill(6) for o in ords) if not k: b = [int(x) for x in bits] x = [0] * len(b) else: b = [] x = [] - for i in range(0, len(bits)-k, k+1): - b.append(int(bits[i:i+1], 2)) - x.append(int(bits[i+1:i+k+1], 2)) + for i in range(0, len(bits) - k, k + 1): + b.append(int(bits[i : i + 1], 2)) + x.append(int(bits[i + 1 : i + k + 1], 2)) v = 0 edges = [] for i in range(len(b)): @@ -153,6 +155,7 @@ def from_dig6(G, dig6_string): [(0, 1), (0, 2), (1, 2), (2, 3), (3, 3)] """ from .generic_graph_pyx import length_and_string_from_graph6, binary_string_from_dig6 + if isinstance(dig6_string, bytes): dig6_string = bytes_to_str(dig6_string) elif not isinstance(dig6_string, str): @@ -198,14 +201,14 @@ def from_seidel_adjacency_matrix(G, M): """ from sage.structure.element import Matrix from sage.rings.integer_ring import ZZ + assert isinstance(M, Matrix) if M.base_ring() != ZZ: try: M = M.change_ring(ZZ) except TypeError: - raise ValueError("the adjacency matrix of a Seidel graph must" + - " have only 0,1,-1 integer entries") + raise ValueError("the adjacency matrix of a Seidel graph must" + " have only 0,1,-1 integer entries") if M.is_sparse(): entries = set(M[i, j] for i, j in M.nonzero_positions()) @@ -213,11 +216,9 @@ def from_seidel_adjacency_matrix(G, M): entries = set(M.list()) if any(e < -1 or e > 1 for e in entries): - raise ValueError("the adjacency matrix of a Seidel graph must" + - " have only 0,1,-1 integer entries") + raise ValueError("the adjacency matrix of a Seidel graph must" + " have only 0,1,-1 integer entries") if any(i == j for i, j in M.nonzero_positions()): - raise ValueError("the adjacency matrix of a Seidel graph must" + - " have 0s on the main diagonal") + raise ValueError("the adjacency matrix of a Seidel graph must" + " have 0s on the main diagonal") if not M.is_symmetric(): raise ValueError("the adjacency matrix of a Seidel graph must be symmetric") @@ -248,6 +249,7 @@ def from_adjacency_matrix(G, M, loops=False, multiedges=False, weighted=False): """ from sage.structure.element import Matrix from sage.rings.integer_ring import ZZ + assert isinstance(M, Matrix) # note: the adjacency matrix might be weighted and hence not # necessarily consists of integers @@ -256,8 +258,7 @@ def from_adjacency_matrix(G, M, loops=False, multiedges=False, weighted=False): M = M.change_ring(ZZ) except TypeError: if weighted is False: - raise ValueError("the adjacency matrix of a non-weighted graph" + - " must have only nonnegative integer entries") + raise ValueError("the adjacency matrix of a non-weighted graph" + " must have only nonnegative integer entries") weighted = True if M.is_sparse(): @@ -267,8 +268,7 @@ def from_adjacency_matrix(G, M, loops=False, multiedges=False, weighted=False): if not weighted and any(e < 0 for e in entries): if weighted is False: - raise ValueError("the adjacency matrix of a non-weighted graph" + - " must have only nonnegative integer entries") + raise ValueError("the adjacency matrix of a non-weighted graph" + " must have only nonnegative integer entries") weighted = True if multiedges is None: multiedges = False @@ -276,12 +276,11 @@ def from_adjacency_matrix(G, M, loops=False, multiedges=False, weighted=False): weighted = False if multiedges is None: - multiedges = ((not weighted) and any(e != 0 and e != 1 for e in entries)) + multiedges = (not weighted) and any(e != 0 and e != 1 for e in entries) if not loops and any(M[i, i] for i in range(M.nrows())): if loops is False: - raise ValueError("the adjacency matrix of a non-weighted graph" + - " must have zeroes on the diagonal") + raise ValueError("the adjacency matrix of a non-weighted graph" + " must have zeroes on the diagonal") loops = True if loops is None: loops = False @@ -323,6 +322,7 @@ def from_incidence_matrix(G, M, loops=False, multiedges=False, weighted=False): True """ from sage.structure.element import Matrix + assert isinstance(M, Matrix) oriented = any(M[pos] < 0 for pos in M.nonzero_positions(copy=False)) @@ -332,18 +332,13 @@ def from_incidence_matrix(G, M, loops=False, multiedges=False, weighted=False): NZ = M.nonzero_positions_in_column(i) if len(NZ) == 1: if oriented: - raise ValueError("column {} of the (oriented) incidence " - "matrix contains only one nonzero value".format(i)) + raise ValueError("column {} of the (oriented) incidence " "matrix contains only one nonzero value".format(i)) elif M[NZ[0], i] != 2: - raise ValueError("each column of a non-oriented incidence " - "matrix must sum to 2, but column {} does not".format(i)) + raise ValueError("each column of a non-oriented incidence " "matrix must sum to 2, but column {} does not".format(i)) if loops is None: loops = True positions.append((NZ[0], NZ[0])) - elif (len(NZ) != 2 or - (oriented and not ((M[NZ[0], i] == +1 and M[NZ[1], i] == -1) or - (M[NZ[0], i] == -1 and M[NZ[1], i] == +1))) or - (not oriented and (M[NZ[0], i] != 1 or M[NZ[1], i] != 1))): + elif len(NZ) != 2 or (oriented and not ((M[NZ[0], i] == +1 and M[NZ[1], i] == -1) or (M[NZ[0], i] == -1 and M[NZ[1], i] == +1))) or (not oriented and (M[NZ[0], i] != 1 or M[NZ[1], i] != 1)): msg = "there must be one or two nonzero entries per column in an incidence matrix, " msg += "got entries {} in column {}".format([M[j, i] for j in NZ], i) raise ValueError(msg) @@ -418,6 +413,7 @@ def from_oriented_incidence_matrix(G, M, loops=False, multiedges=False, weighted [(1, 0)] """ from sage.structure.element import Matrix + assert isinstance(M, Matrix) positions = [] @@ -513,9 +509,12 @@ def from_dict_of_dicts(G, M, loops=False, multiedges=False, weighted=False, conv verts.update(d) G.add_vertices(verts.keys()) if convert_empty_dict_labels_to_None: + def relabel(x): return x if x != {} else None + else: + def relabel(x): return x @@ -601,8 +600,7 @@ def from_dict_of_lists(G, D, loops=False, multiedges=False, weighted=False): v_to_id = {v: i for i, v in enumerate(verts.keys())} for u in D: for v in D[u]: - if (v_to_id[u] <= v_to_id[v] or - v not in D or u not in D[v] or u == v): + if v_to_id[u] <= v_to_id[v] or v not in D or u not in D[v] or u == v: G._backend.add_edge(u, v, None, False) else: for u in D: @@ -610,8 +608,7 @@ def from_dict_of_lists(G, D, loops=False, multiedges=False, weighted=False): G._backend.add_edge(u, v, None, is_directed) -def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, - convert_empty_dict_labels_to_None=None): +def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, convert_empty_dict_labels_to_None=None): r""" Fill `G` with the data of a NetworkX (di)graph. @@ -778,9 +775,11 @@ def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, """ from sage.graphs.graph import Graph from sage.graphs.digraph import DiGraph + if not isinstance(G, (Graph, DiGraph)): raise ValueError("the first parameter must a Sage Graph or DiGraph") import networkx + if not isinstance(gnx, (networkx.Graph, networkx.DiGraph)): raise ValueError("the second parameter must be a NetworkX (Multi)(Di)Graph") @@ -801,8 +800,10 @@ def from_networkx_graph(G, gnx, weighted=None, loops=None, multiedges=None, G.add_vertices(gnx.nodes()) G.set_vertices(gnx.nodes(data=True)) if convert_empty_dict_labels_to_None is not False: + def r(label): return None if label == {} else label + G.add_edges((u, v, r(ll)) for u, v, ll in gnx.edges(data=True)) else: G.add_edges(gnx.edges(data=True)) diff --git a/src/sage/graphs/graph_latex.py b/src/sage/graphs/graph_latex.py index 07873a9b2d6..5dd5dc7fee2 100644 --- a/src/sage/graphs/graph_latex.py +++ b/src/sage/graphs/graph_latex.py @@ -420,15 +420,24 @@ def check_tkz_graph(): sage: check_tkz_graph() # random - depends on TeX installation sage: check_tkz_graph() # at least the second time, so no output """ - latex.check_file("tikz.sty", """This package is required to render graphs in LaTeX. + latex.check_file( + "tikz.sty", + """This package is required to render graphs in LaTeX. Visit '...'. -""") - latex.check_file("tkz-graph.sty", """This package is required to render graphs in LaTeX. +""", + ) + latex.check_file( + "tkz-graph.sty", + """This package is required to render graphs in LaTeX. Visit 'https://www.ctan.org/pkg/tkz-graph'. -""") - latex.check_file("tkz-berge.sty", """This package is required to render graphs in LaTeX. +""", + ) + latex.check_file( + "tkz-berge.sty", + """This package is required to render graphs in LaTeX. Visit 'https://www.ctan.org/pkg/tkz-berge'. -""") +""", + ) def have_tkz_graph() -> bool: @@ -510,49 +519,51 @@ class GraphLatex(SageObject): # This dictionary could also contain type information (list of admissible # values) and a description # See e.g. @option - __graphlatex_options = {'tkz_style': 'Custom', - 'format': 'tkz_graph', - 'layout': 'acyclic', - 'prog': 'dot', - 'units': 'cm', - 'scale': 1.0, - 'graphic_size': (5, 5), - 'margins': (0, 0, 0, 0), - 'vertex_color': 'black', - 'vertex_colors': {}, - 'vertex_fill_color': 'white', - 'vertex_fill_colors': {}, - 'vertex_shape': 'circle', - 'vertex_shapes': {}, - 'vertex_size': 1.0, - 'vertex_sizes': {}, - 'vertex_labels': True, - 'vertex_labels_math': True, - 'vertex_label_color': 'black', - 'vertex_label_colors': {}, - 'vertex_label_placement': 'center', - 'vertex_label_placements': {}, - 'edge_options': (), - 'edge_color': 'black', - 'edge_colors': {}, - 'edge_fills': False, - 'edge_fill_color': 'black', - 'edge_fill_colors': {}, - 'edge_thickness': 0.1, - 'edge_thicknesses': {}, - 'edge_labels': False, - 'edge_labels_math': True, - 'edge_label_color': 'black', - 'edge_label_colors': {}, - 'edge_label_sloped': True, - 'edge_label_slopes': {}, - 'edge_label_placement': 0.50, - 'edge_label_placements': {}, - 'loop_placement': (3.0, 'NO'), - 'loop_placements': {}, - 'color_by_label': False, - 'rankdir': 'down', - 'subgraph_clusters': []} + __graphlatex_options = { + 'tkz_style': 'Custom', + 'format': 'tkz_graph', + 'layout': 'acyclic', + 'prog': 'dot', + 'units': 'cm', + 'scale': 1.0, + 'graphic_size': (5, 5), + 'margins': (0, 0, 0, 0), + 'vertex_color': 'black', + 'vertex_colors': {}, + 'vertex_fill_color': 'white', + 'vertex_fill_colors': {}, + 'vertex_shape': 'circle', + 'vertex_shapes': {}, + 'vertex_size': 1.0, + 'vertex_sizes': {}, + 'vertex_labels': True, + 'vertex_labels_math': True, + 'vertex_label_color': 'black', + 'vertex_label_colors': {}, + 'vertex_label_placement': 'center', + 'vertex_label_placements': {}, + 'edge_options': (), + 'edge_color': 'black', + 'edge_colors': {}, + 'edge_fills': False, + 'edge_fill_color': 'black', + 'edge_fill_colors': {}, + 'edge_thickness': 0.1, + 'edge_thicknesses': {}, + 'edge_labels': False, + 'edge_labels_math': True, + 'edge_label_color': 'black', + 'edge_label_colors': {}, + 'edge_label_sloped': True, + 'edge_label_slopes': {}, + 'edge_label_placement': 0.50, + 'edge_label_placements': {}, + 'loop_placement': (3.0, 'NO'), + 'loop_placements': {}, + 'color_by_label': False, + 'rankdir': 'down', + 'subgraph_clusters': [], + } def __init__(self, graph, **options): r""" @@ -1088,7 +1099,7 @@ def set_option(self, option_name, option_value=None): if option_name not in GraphLatex.__graphlatex_options: raise ValueError("%s is not a LaTeX option for a graph." % option_name) - if option_value is None: # clear the option, if set + if option_value is None: # clear the option, if set if option_name in self._options: del self._options[option_name] else: @@ -1108,12 +1119,9 @@ def set_option(self, option_name, option_value=None): # # Options with structurally similar tests # - boolean_options = ('vertex_labels', 'vertex_labels_math', 'edge_fills', - 'edge_labels', 'edge_labels_math', 'edge_label_sloped') - color_options = ('vertex_color', 'vertex_fill_color', 'vertex_label_color', - 'edge_color', 'edge_fill_color', 'edge_label_color') - color_dicts = ('vertex_colors', 'vertex_fill_colors', 'vertex_label_colors', - 'edge_colors', 'edge_fill_colors', 'edge_label_colors') + boolean_options = ('vertex_labels', 'vertex_labels_math', 'edge_fills', 'edge_labels', 'edge_labels_math', 'edge_label_sloped') + color_options = ('vertex_color', 'vertex_fill_color', 'vertex_label_color', 'edge_color', 'edge_fill_color', 'edge_label_color') + color_dicts = ('vertex_colors', 'vertex_fill_colors', 'vertex_label_colors', 'edge_colors', 'edge_fill_colors', 'edge_label_colors') boolean_dicts = ('edge_label_slopes',) positive_scalars = ('scale', 'vertex_size', 'edge_thickness') positive_scalar_dicts = ('vertex_sizes', 'edge_thicknesses') @@ -1142,18 +1150,11 @@ def set_option(self, option_name, option_value=None): raise ValueError('%s option must be the shape of a vertex, not %s' % (name, value)) elif name in positive_scalars and not (type(value) in number_types and (value >= 0.0)): raise ValueError('%s option must be a positive number, not %s' % (name, value)) - elif (name == 'vertex_label_placement' and value != 'center' and - not (isinstance(value, tuple) and len(value) == 2 and - type(value[0]) in number_types and value[0] >= 0 and - type(value[1]) in number_types and value[1] >= 0)): + elif name == 'vertex_label_placement' and value != 'center' and not (isinstance(value, tuple) and len(value) == 2 and type(value[0]) in number_types and value[0] >= 0 and type(value[1]) in number_types and value[1] >= 0): raise ValueError('%s option must be None, or a pair of positive numbers, not %s' % (name, value)) - elif (name == 'edge_label_placement' and - not ((type(value) in number_types and 0 <= value <= 1) - or value in label_places)): + elif name == 'edge_label_placement' and not ((type(value) in number_types and 0 <= value <= 1) or value in label_places): raise ValueError('%s option must be a number between 0.0 and 1.0 or a place (like "above"), not %s' % (name, value)) - elif (name == 'loop_placement' and - not (isinstance(value, tuple) and len(value) == 2 and - value[0] >= 0 and value[1] in compass_points)): + elif name == 'loop_placement' and not (isinstance(value, tuple) and len(value) == 2 and value[0] >= 0 and value[1] in compass_points): raise ValueError('%s option must be a pair that is a positive number followed by a compass point abbreviation, not %s' % (name, value)) # # Checks/test on dictionaries of values (ie per-vertex or per-edge defaults) @@ -1193,10 +1194,7 @@ def set_option(self, option_name, option_value=None): raise TypeError('%s option must be a dictionary, not %s' % (name, value)) else: for key, p in value.items(): - if (p != 'center' and - not (isinstance(p, tuple) and len(p) == 2 and - type(p[0]) in number_types and p[0] >= 0 and - type(p[1]) in number_types and p[1] >= 0)): + if p != 'center' and not (isinstance(p, tuple) and len(p) == 2 and type(p[0]) in number_types and p[0] >= 0 and type(p[1]) in number_types and p[1] >= 0): raise ValueError('%s option for %s needs to be None or a pair of positive numbers, not %s' % (name, key, p)) elif name == 'edge_label_placements': if not isinstance(value, dict): @@ -1419,6 +1417,7 @@ def dot2tex_picture(self): can work without ``graphviz`` if layout information is provided. """ from sage.graphs.dot2tex_utils import assert_have_dot2tex + assert_have_dot2tex() options = self.__graphlatex_options.copy() @@ -1438,12 +1437,8 @@ def dot2tex_picture(self): dotdata = self._graph.graphviz_string(labels='latex', **options) import dot2tex - return dot2tex.dot2tex(dotdata, - format='tikz', - autosize=True, - crop=True, - figonly='True', - prog=self.get_option('prog')).strip() + + return dot2tex.dot2tex(dotdata, format='tikz', autosize=True, crop=True, figonly='True', prog=self.get_option('prog')).strip() # usepdflatex = True, debug = True) def tkz_picture(self): @@ -1632,7 +1627,7 @@ def tkz_picture(self): # We preserve the pre-built style OR get defaults for each option, but # we do not mix the two style = self.get_option('tkz_style') - customized = (style == 'Custom') + customized = style == 'Custom' # We don't do much for a pre-built style # Layout information from the graph # And vertex labels (if used) are the latex representation of Sage objects @@ -1699,8 +1694,7 @@ def tkz_picture(self): # space def translate(p): - return ((p[0] - xmin) * x_scale + llx, - (p[1] - ymin) * y_scale + lly) + return ((p[0] - xmin) * x_scale + llx, (p[1] - ymin) * y_scale + lly) ############# # Vertices @@ -1995,8 +1989,7 @@ def translate(p): # these keys as a \Vertex[style={...}] option leaves them # ineffective for shape/color overrides. t += [r'\begin{scope}[VertexStyle/.append style={'] - t += ['minimum size=', str(round(float(scale * v_size[u]), 4)), - units, ','] + t += ['minimum size=', str(round(float(scale * v_size[u]), 4)), units, ','] t += ['draw=', vertex_color_names[u], ','] t += ['fill=', vertex_fill_color_names[u], ','] if vertex_labels: @@ -2071,7 +2064,7 @@ def translate(p): s += ['color=', edge_color_names[edge], ','] if edge_fills: s += ['double=', edge_fill_color_names[edge]] - s += ['},'] # end style list + s += ['},'] # end style list if edge_labels: s += ['labelstyle={'] if el_slope[edge]: diff --git a/src/sage/graphs/graph_list.py b/src/sage/graphs/graph_list.py index 6bfaf4f2908..9dce6efe7c1 100644 --- a/src/sage/graphs/graph_list.py +++ b/src/sage/graphs/graph_list.py @@ -112,9 +112,7 @@ def _from_whatever(data, fmt=None, immutable=False): try: lines = iter(data) except TypeError: - raise TypeError( - "must be a string, an iterable of strings, or a readable " - "file-like object") + raise TypeError("must be a string, an iterable of strings, or a readable " "file-like object") if fmt == 'graph6': kwargs = {'format': fmt} @@ -132,8 +130,7 @@ def _from_whatever(data, fmt=None, immutable=False): continue if '\n' in line: - out.append(_from_whatever(line.splitlines(), fmt=fmt, - immutable=immutable)) + out.append(_from_whatever(line.splitlines(), fmt=fmt, immutable=immutable)) else: out.append(Graph(line, immutable=immutable, **kwargs)) @@ -315,6 +312,7 @@ def to_graphics_array(graph_list, **kwds): Graphics Array of size 3 x 4 """ from sage.graphs import graph + plist = [] for graph_i in graph_list: if isinstance(graph_i, graph.GenericGraph): @@ -329,12 +327,11 @@ def to_graphics_array(graph_list, **kwds): kwds['graph_border'] = True plist.append(graph_i.plot(**kwds)) else: - plist.append(graph_i.plot(pos=pos, vertex_size=50, - vertex_labels=False, - graph_border=True)) + plist.append(graph_i.plot(pos=pos, vertex_size=50, vertex_labels=False, graph_border=True)) else: raise TypeError('param list must be a list of Sage (di)graphs.') from sage.plot.plot import graphics_array + return graphics_array(plist, ncols=4) @@ -405,5 +402,5 @@ def show_graphs(graph_list, **kwds): """ graph_list = list(graph_list) for i in range(len(graph_list) // 20 + 1): - graph_slice = graph_list[20 * i: 20 * (i + 1)] + graph_slice = graph_list[20 * i : 20 * (i + 1)] to_graphics_array(graph_slice, **kwds).show() diff --git a/src/sage/graphs/graph_plot.py b/src/sage/graphs/graph_plot.py index 93ad73cd557..2bac5fc0658 100644 --- a/src/sage/graphs/graph_plot.py +++ b/src/sage/graphs/graph_plot.py @@ -129,125 +129,56 @@ from math import sqrt, cos, sin, atan, pi from sage.structure.sage_object import SageObject from sage.misc.lazy_import import lazy_import -lazy_import("sage.plot.all", [ - "Graphics", "scatter_plot", "bezier_path", "line", "arrow", "text", "circle"]) + +lazy_import("sage.plot.all", ["Graphics", "scatter_plot", "bezier_path", "line", "arrow", "text", "circle"]) layout_options = { - 'layout': - 'A layout algorithm -- one of : "acyclic", "circular" (plots the ' - 'graph with vertices evenly distributed on a circle), "ranked", ' - '"graphviz", "planar", "spring" (traditional spring layout, using ' - 'the graph\'s current positions as initial positions), or "tree" ' - '(the tree will be plotted in levels, depending on minimum distance ' - 'for the root).', - 'iterations': - 'The number of times to execute the spring layout algorithm.', - 'heights': - 'A dictionary mapping heights to the list of vertices at this height.', - 'spring': - 'Use spring layout to finalize the current layout.', - 'tree_root': - 'A vertex designation for drawing trees. A vertex of the tree to ' - 'be used as the root for the ``layout=\'tree\'`` option. If no root ' - 'is specified, then one is chosen close to the center of the tree. ' - 'Ignored unless ``layout=\'tree\'``.', - 'forest_roots': - 'An iterable specifying which vertices to use as roots for the ' - '``layout=\'forest\'`` option. If no root is specified for a tree, ' - 'then one is chosen close to the center of the tree. ' - 'Ignored unless ``layout=\'forest\'``.', - 'tree_orientation': - 'The direction of tree branches -- \'up\', \'down\', ' - '\'left\' or \'right\'.', - 'external_face': - 'A list of the vertices of the external face of the graph, ' - 'used for Tutte embedding layout.', - 'external_face_pos': - 'A dictionary specifying the positions of the external face of the ' - 'graph, used for Tutte embedding layout. If none specified, the' - 'external face is a regular polygon.', - 'save_pos': - 'Whether or not to save the computed position for the graph.', - 'dim': - 'The dimension of the layout -- 2 or 3.', - 'prog': - 'Which graphviz layout program to use -- one of ' - '"circo", "dot", "fdp", "neato", or "twopi".', - 'by_component': - 'Whether to do the spring layout by connected component -- boolean.'} + 'layout': 'A layout algorithm -- one of : "acyclic", "circular" (plots the ' 'graph with vertices evenly distributed on a circle), "ranked", ' '"graphviz", "planar", "spring" (traditional spring layout, using ' 'the graph\'s current positions as initial positions), or "tree" ' '(the tree will be plotted in levels, depending on minimum distance ' 'for the root).', + 'iterations': 'The number of times to execute the spring layout algorithm.', + 'heights': 'A dictionary mapping heights to the list of vertices at this height.', + 'spring': 'Use spring layout to finalize the current layout.', + 'tree_root': 'A vertex designation for drawing trees. A vertex of the tree to ' 'be used as the root for the ``layout=\'tree\'`` option. If no root ' 'is specified, then one is chosen close to the center of the tree. ' 'Ignored unless ``layout=\'tree\'``.', + 'forest_roots': 'An iterable specifying which vertices to use as roots for the ' '``layout=\'forest\'`` option. If no root is specified for a tree, ' 'then one is chosen close to the center of the tree. ' 'Ignored unless ``layout=\'forest\'``.', + 'tree_orientation': 'The direction of tree branches -- \'up\', \'down\', ' '\'left\' or \'right\'.', + 'external_face': 'A list of the vertices of the external face of the graph, ' 'used for Tutte embedding layout.', + 'external_face_pos': 'A dictionary specifying the positions of the external face of the ' 'graph, used for Tutte embedding layout. If none specified, the' 'external face is a regular polygon.', + 'save_pos': 'Whether or not to save the computed position for the graph.', + 'dim': 'The dimension of the layout -- 2 or 3.', + 'prog': 'Which graphviz layout program to use -- one of ' '"circo", "dot", "fdp", "neato", or "twopi".', + 'by_component': 'Whether to do the spring layout by connected component -- boolean.', +} graphplot_options = layout_options.copy() -graphplot_options.update({ - 'pos': - 'The position dictionary of vertices.', - 'vertex_labels': - 'Vertex labels to draw. This can be ``True``/``False`` to indicate ' - 'whether to print the vertex string representation of not, ' - 'a dictionary keyed by vertices and associating to each vertex ' - 'a label string, or a function taking as input a vertex and returning ' - 'a label string.', - 'vertex_label_shift': - 'If layout is circular and we have vertex labels, will shift vertices ' - 'away from center of circle in coordinate fashion `(x, y)`.', - 'vertex_color': - 'Default color for vertices not listed ' - 'in vertex_colors dictionary.', - 'vertex_colors': - 'A dictionary specifying vertex colors: ' - 'each key is a color recognizable by matplotlib, ' - 'and each corresponding value is a list of vertices.', - 'vertex_size': - 'The size to draw the vertices.', - 'vertex_shape': - 'The shape to draw the vertices. ' - 'Currently unavailable for Multi-edged DiGraphs.', - 'edge_labels': - 'Whether or not to draw edge labels.', - 'edge_style': - 'The linestyle of the edges. It should be ' - 'one of "solid", "dashed", "dotted", "dashdot", ' - 'or "-", "--", ":", "-.", respectively. ', - 'edge_styles': - 'A dictionary specifying edge styles: ' - 'each key is an edge or a label (all same) and value is the linestyle ' - 'of the edge. It should be one of "solid", "dashed", "dotted", ' - '"dashdot", or "-", "--", ":", "-.", respectively.', - 'edge_thickness': - 'The thickness of the edges.', - 'edge_thicknesses': - 'A dictionary specifying edge thicknesses: ' - 'each key is an edge or a label (all same) and thickness of the ' - 'corresponding edge.', - 'edge_color': - 'The default color for edges not listed in edge_colors.', - 'edge_colors': - 'A dictionary specifying edge colors: ' - 'each key is a color recognized by matplotlib, ' - 'and each corresponding value is a list of edges.', - 'color_by_label': - 'Whether to color the edges according to their labels. This also ' - 'accepts a function or dictionary mapping labels to colors.', - 'partition': - 'A partition of the vertex set. If specified, plot will show each ' - 'cell in a different color; vertex_colors takes precedence.', - 'loop_size': - 'The radius of the smallest loop.', - 'arrowsize': - 'Size of arrows.', - 'dist': - 'The distance between multiedges.', - 'max_dist': - 'The max distance range to allow multiedges.', - 'talk': - 'Whether to display the vertices in talk mode (larger and white).', - 'label_fontsize': - 'font size of all labels', - 'graph_border': - 'Whether or not to draw a frame around the graph.', - 'edge_labels_background': - 'The color of the background of the edge labels.'}) +graphplot_options.update( + { + 'pos': 'The position dictionary of vertices.', + 'vertex_labels': 'Vertex labels to draw. This can be ``True``/``False`` to indicate ' 'whether to print the vertex string representation of not, ' 'a dictionary keyed by vertices and associating to each vertex ' 'a label string, or a function taking as input a vertex and returning ' 'a label string.', + 'vertex_label_shift': 'If layout is circular and we have vertex labels, will shift vertices ' 'away from center of circle in coordinate fashion `(x, y)`.', + 'vertex_color': 'Default color for vertices not listed ' 'in vertex_colors dictionary.', + 'vertex_colors': 'A dictionary specifying vertex colors: ' 'each key is a color recognizable by matplotlib, ' 'and each corresponding value is a list of vertices.', + 'vertex_size': 'The size to draw the vertices.', + 'vertex_shape': 'The shape to draw the vertices. ' 'Currently unavailable for Multi-edged DiGraphs.', + 'edge_labels': 'Whether or not to draw edge labels.', + 'edge_style': 'The linestyle of the edges. It should be ' 'one of "solid", "dashed", "dotted", "dashdot", ' 'or "-", "--", ":", "-.", respectively. ', + 'edge_styles': 'A dictionary specifying edge styles: ' 'each key is an edge or a label (all same) and value is the linestyle ' 'of the edge. It should be one of "solid", "dashed", "dotted", ' '"dashdot", or "-", "--", ":", "-.", respectively.', + 'edge_thickness': 'The thickness of the edges.', + 'edge_thicknesses': 'A dictionary specifying edge thicknesses: ' 'each key is an edge or a label (all same) and thickness of the ' 'corresponding edge.', + 'edge_color': 'The default color for edges not listed in edge_colors.', + 'edge_colors': 'A dictionary specifying edge colors: ' 'each key is a color recognized by matplotlib, ' 'and each corresponding value is a list of edges.', + 'color_by_label': 'Whether to color the edges according to their labels. This also ' 'accepts a function or dictionary mapping labels to colors.', + 'partition': 'A partition of the vertex set. If specified, plot will show each ' 'cell in a different color; vertex_colors takes precedence.', + 'loop_size': 'The radius of the smallest loop.', + 'arrowsize': 'Size of arrows.', + 'dist': 'The distance between multiedges.', + 'max_dist': 'The max distance range to allow multiedges.', + 'talk': 'Whether to display the vertices in talk mode (larger and white).', + 'label_fontsize': 'font size of all labels', + 'graph_border': 'Whether or not to draw a frame around the graph.', + 'edge_labels_background': 'The color of the background of the edge labels.', + } +) _PLOT_OPTIONS_TABLE = "" @@ -258,30 +189,7 @@ DEFAULT_SHOW_OPTIONS = {'figsize': (4, 4)} -DEFAULT_PLOT_OPTIONS = { - 'vertex_size' : 200, - 'vertex_labels' : True, - 'vertex_label_shift' : None, - 'layout' : None, - 'edge_style' : 'solid', - 'edge_styles' : None, - 'edge_thickness' : 1, - 'edge_thicknesses' : None, - 'edge_color' : 'black', - 'edge_colors' : None, - 'edge_labels' : False, - 'iterations' : 50, - 'tree_orientation' : 'down', - 'heights' : None, - 'graph_border' : False, - 'talk' : False, - 'color_by_label' : False, - 'partition' : None, - 'dist' : .075, - 'max_dist' : 1.5, - 'label_fontsize' : 10, - 'loop_size' : .075, - 'edge_labels_background' : 'white'} +DEFAULT_PLOT_OPTIONS = {'vertex_size': 200, 'vertex_labels': True, 'vertex_label_shift': None, 'layout': None, 'edge_style': 'solid', 'edge_styles': None, 'edge_thickness': 1, 'edge_thicknesses': None, 'edge_color': 'black', 'edge_colors': None, 'edge_labels': False, 'iterations': 50, 'tree_orientation': 'down', 'heights': None, 'graph_border': False, 'talk': False, 'color_by_label': False, 'partition': None, 'dist': 0.075, 'max_dist': 1.5, 'label_fontsize': 10, 'loop_size': 0.075, 'edge_labels_background': 'white'} class GraphPlot(SageObject): @@ -410,8 +318,7 @@ def set_pos(self): """ self._pos = self._graph.layout(**self._options) # Make sure the positions are floats (trac #10124) - self._pos = {k: (float(v[0]), float(v[1])) - for k, v in self._pos.items()} + self._pos = {k: (float(v[0]), float(v[1])) for k, v in self._pos.items()} def set_vertices(self, **vertex_options): """ @@ -522,16 +429,15 @@ def set_vertices(self, **vertex_options): else: voptions['markersize'] = self._options['vertex_size'] - if ('vertex_color' not in self._options - or self._options['vertex_color'] is None): + if 'vertex_color' not in self._options or self._options['vertex_color'] is None: vertex_color = '#fec7b8' else: vertex_color = self._options['vertex_color'] - if ('vertex_colors' not in self._options - or self._options['vertex_colors'] is None): + if 'vertex_colors' not in self._options or self._options['vertex_colors'] is None: if self._options['partition'] is not None: from sage.plot.colors import rainbow + partition = self._options['partition'] length = len(partition) R = rainbow(length) @@ -556,13 +462,9 @@ def set_vertices(self, **vertex_options): voptions['facecolor'] = vertex_colors pos = list(self._pos.values()) if self._arcdigraph: - self._plot_components['vertices'] = [ - circle(p, self._vertex_radius, fill=True, clip=False, - edgecolor='black', facecolor=vertex_colors) - for p in pos] + self._plot_components['vertices'] = [circle(p, self._vertex_radius, fill=True, clip=False, edgecolor='black', facecolor=vertex_colors) for p in pos] else: - self._plot_components['vertices'] = ( - scatter_plot(pos, clip=False, **voptions)) + self._plot_components['vertices'] = scatter_plot(pos, clip=False, **voptions) else: # Color list must be ordered: pos = [] @@ -578,43 +480,31 @@ def set_vertices(self, **vertex_options): colors.extend([vertex_color] * len(leftovers)) if self._arcdigraph: - self._plot_components['vertices'] = [ - circle(p, self._vertex_radius, fill=True, clip=False, - facecolor=colors[i], edgecolor='black') - for i, p in enumerate(pos)] + self._plot_components['vertices'] = [circle(p, self._vertex_radius, fill=True, clip=False, facecolor=colors[i], edgecolor='black') for i, p in enumerate(pos)] else: - self._plot_components['vertices'] = scatter_plot( - pos, facecolor=colors, clip=False, **voptions) + self._plot_components['vertices'] = scatter_plot(pos, facecolor=colors, clip=False, **voptions) vlabels = self._options['vertex_labels'] if vlabels: if vlabels is True: vfun = str elif isinstance(vlabels, dict): + def vfun(x): return vlabels.get(x, "") + else: vfun = vlabels # TODO: allow text options if self._options['layout'] == 'circular' and self._options['vertex_label_shift'] is not None: + def pos_shift(v, shift): - return (v[0] + (v[0] * shift[0])/100, v[1] + (v[1] * shift[1])/100) - self._plot_components['vertex_labels'] = [ - text( - vfun(v), - pos_shift(self._pos[v], self._options['vertex_label_shift']), - fontsize=self._options['label_fontsize'], - color='black', - zorder=8 - ) - for v in self._nodelist - ] + return (v[0] + (v[0] * shift[0]) / 100, v[1] + (v[1] * shift[1]) / 100) + + self._plot_components['vertex_labels'] = [text(vfun(v), pos_shift(self._pos[v], self._options['vertex_label_shift']), fontsize=self._options['label_fontsize'], color='black', zorder=8) for v in self._nodelist] else: - self._plot_components['vertex_labels'] = [ - text(vfun(v), self._pos[v], color='black', zorder=8, fontsize=self._options['label_fontsize']) - for v in self._nodelist - ] + self._plot_components['vertex_labels'] = [text(vfun(v), self._pos[v], color='black', zorder=8, fontsize=self._options['label_fontsize']) for v in self._nodelist] def set_edges(self, **edge_options): """ @@ -779,11 +669,9 @@ def set_edges(self, **edge_options): v_to_int = {v: i for i, v in enumerate(self._graph)} - if (self._options['color_by_label'] - or isinstance(self._options['edge_colors'], dict)): + if self._options['color_by_label'] or isinstance(self._options['edge_colors'], dict): if self._options['color_by_label']: - edge_colors = self._graph._color_by_label( - format=self._options['color_by_label']) + edge_colors = self._graph._color_by_label(format=self._options['color_by_label']) else: edge_colors = self._options['edge_colors'] edges_drawn = [] @@ -814,9 +702,7 @@ def set_edges(self, **edge_options): # Add unspecified edges (default color black set in DEFAULT_PLOT_OPTIONS) for a, b, c in self._graph.edge_iterator(): - if ((a, b, c) not in edges_drawn - and (self._graph.is_directed() - or (b, a, c) not in edges_drawn)): + if (a, b, c) not in edges_drawn and (self._graph.is_directed() or (b, a, c) not in edges_drawn): if v_to_int[a] < v_to_int[b]: key = (a, b) head = 1 @@ -847,6 +733,7 @@ def set_edges(self, **edge_options): min_loop_size = self._options['loop_size'] max_dist = self._options['max_dist'] from sage.misc.functional import sqrt + for a, b in tmp: if a == b: # Multiple loops need varying loop radius starting at @@ -864,13 +751,9 @@ def set_edges(self, **edge_options): estyle = self._options['edge_style'] ethickness = self._options['edge_thickness'] - if (style_key_edges is not None - and ((style_key_edges and (x, y) in self._options['edge_styles']) - or (not style_key_edges and lab in self._options['edge_styles']))): + if style_key_edges is not None and ((style_key_edges and (x, y) in self._options['edge_styles']) or (not style_key_edges and lab in self._options['edge_styles'])): estyle = style_key_edges and self._options['edge_styles'][(x, y)] or self._options['edge_styles'][lab] - if (thickness_key_edges is not None - and ((thickness_key_edges and (x, y) in self._options['edge_thicknesses']) - or (not thickness_key_edges and lab in self._options['edge_thicknesses']))): + if thickness_key_edges is not None and ((thickness_key_edges and (x, y) in self._options['edge_thicknesses']) or (not thickness_key_edges and lab in self._options['edge_thicknesses'])): ethickness = thickness_key_edges and self._options['edge_thicknesses'][(x, y)] or self._options['edge_thicknesses'][lab] c = circle((x, y), loop_size, rgbcolor=col, linestyle=estyle, thickness=ethickness) @@ -888,7 +771,7 @@ def set_edges(self, **edge_options): # Compute perpendicular bisector p1 = self._pos[a] p2 = self._pos[b] - m = ((p1[0] + p2[0]) / 2., (p1[1] + p2[1]) / 2.) # midpoint + m = ((p1[0] + p2[0]) / 2.0, (p1[1] + p2[1]) / 2.0) # midpoint if not p1[1] == p2[1]: s = (p1[0] - p2[0]) / (p2[1] - p1[1]) # perp slope @@ -898,25 +781,29 @@ def y(x): # f, g are functions to determine x-values of point # on line y at distance d from point m (on each side) def f(d): - return sqrt(d**2 / (1. + s**2)) + m[0] + return sqrt(d**2 / (1.0 + s**2)) + m[0] def g(d): - return -sqrt(d**2 / (1. + s**2)) + m[0] + return -sqrt(d**2 / (1.0 + s**2)) + m[0] odd_x = f even_x = g if p1[0] == p2[0]: + def odd_y(d): return m[1] even_y = odd_y else: + def odd_y(x): return y(f(x)) def even_y(x): return y(g(x)) + else: + def odd_x(d): return m[0] @@ -955,44 +842,16 @@ def even_xy(d): even_start = ph(p1, even_xy(k), vr)[0] even_end = ph(even_xy(k), p2, vr)[1] - self._plot_components['edges'].append( - arrow(path=[[odd_start, odd_xy(k), odd_end]], - head=local_labels[2 * i][2], zorder=1, - rgbcolor=local_labels[2 * i][1], - linestyle=estyle, - width=ethickness, - **eoptions - )) - self._plot_components['edges'].append( - arrow(path=[[even_start, even_xy(k), even_end]], - head=local_labels[2 * i + 1][2], zorder=1, - rgbcolor=local_labels[2 * i + 1][1], - linestyle=estyle, - width=ethickness, - **eoptions - )) + self._plot_components['edges'].append(arrow(path=[[odd_start, odd_xy(k), odd_end]], head=local_labels[2 * i][2], zorder=1, rgbcolor=local_labels[2 * i][1], linestyle=estyle, width=ethickness, **eoptions)) + self._plot_components['edges'].append(arrow(path=[[even_start, even_xy(k), even_end]], head=local_labels[2 * i + 1][2], zorder=1, rgbcolor=local_labels[2 * i + 1][1], linestyle=estyle, width=ethickness, **eoptions)) else: - self._plot_components['edges'].append( - bezier_path([[p1, odd_xy(k), p2]], zorder=1, - rgbcolor=local_labels[2 * i][1], - linestyle=estyle, - thickness=ethickness - )) - self._plot_components['edges'].append( - bezier_path([[p1, even_xy(k), p2]], zorder=1, - rgbcolor=local_labels[2 * i + 1][1], - linestyle=estyle, - thickness=ethickness - )) + self._plot_components['edges'].append(bezier_path([[p1, odd_xy(k), p2]], zorder=1, rgbcolor=local_labels[2 * i][1], linestyle=estyle, thickness=ethickness)) + self._plot_components['edges'].append(bezier_path([[p1, even_xy(k), p2]], zorder=1, rgbcolor=local_labels[2 * i + 1][1], linestyle=estyle, thickness=ethickness)) if labels: j = k / 2.0 bg = self._options['edge_labels_background'] - self._plot_components['edge_labels'].append( - text(local_labels[2 * i][0], odd_xy(j), - background_color=bg, fontsize=self._options['label_fontsize'])) - self._plot_components['edge_labels'].append( - text(local_labels[2 * i + 1][0], even_xy(j), - background_color=bg, fontsize=self._options['label_fontsize'])) + self._plot_components['edge_labels'].append(text(local_labels[2 * i][0], odd_xy(j), background_color=bg, fontsize=self._options['label_fontsize'])) + self._plot_components['edge_labels'].append(text(local_labels[2 * i + 1][0], even_xy(j), background_color=bg, fontsize=self._options['label_fontsize'])) if len_local_labels % 2: # draw line for last odd edges_to_draw[a, b] = [local_labels[-1]] @@ -1006,60 +865,25 @@ def even_xy(d): estyle = self._options['edge_style'] ethickness = self._options['edge_thickness'] - if (style_key_edges is not None - and ((style_key_edges and e in self._options['edge_styles']) - or (not style_key_edges and elabel in self._options['edge_styles']))): + if style_key_edges is not None and ((style_key_edges and e in self._options['edge_styles']) or (not style_key_edges and elabel in self._options['edge_styles'])): estyle = style_key_edges and self._options['edge_styles'][e] or self._options['edge_styles'][elabel] - if (thickness_key_edges is not None - and ((thickness_key_edges and e in self._options['edge_thicknesses']) - or (not thickness_key_edges and elabel in self._options['edge_thicknesses']))): + if thickness_key_edges is not None and ((thickness_key_edges and e in self._options['edge_thicknesses']) or (not thickness_key_edges and elabel in self._options['edge_thicknesses'])): ethickness = thickness_key_edges and self._options['edge_thicknesses'][e] or self._options['edge_thicknesses'][elabel] if self._arcdigraph: ph = self._polar_hack_for_multidigraph C, D = ph(self._pos[a], self._pos[b], self._vertex_radius) - self._plot_components['edges'].append( - arrow(C, D, - rgbcolor=ecolor, - head=ehead, - linestyle=estyle, - width=ethickness, - **eoptions - )) + self._plot_components['edges'].append(arrow(C, D, rgbcolor=ecolor, head=ehead, linestyle=estyle, width=ethickness, **eoptions)) if labels: bg = self._options['edge_labels_background'] - self._plot_components['edge_labels'].append( - text(str(elabel), - [(C[0] + D[0]) / 2., (C[1] + D[1]) / 2.], - background_color=bg, - fontsize=self._options['label_fontsize'] - )) + self._plot_components['edge_labels'].append(text(str(elabel), [(C[0] + D[0]) / 2.0, (C[1] + D[1]) / 2.0], background_color=bg, fontsize=self._options['label_fontsize'])) elif is_directed: - self._plot_components['edges'].append( - arrow(self._pos[a], self._pos[b], - rgbcolor=ecolor, - arrowshorten=self._arrowshorten, - head=ehead, - linestyle=estyle, - width=ethickness, - **eoptions - )) + self._plot_components['edges'].append(arrow(self._pos[a], self._pos[b], rgbcolor=ecolor, arrowshorten=self._arrowshorten, head=ehead, linestyle=estyle, width=ethickness, **eoptions)) else: - self._plot_components['edges'].append( - line([self._pos[a], self._pos[b]], - rgbcolor=ecolor, - linestyle=estyle, - thickness=ethickness - )) + self._plot_components['edges'].append(line([self._pos[a], self._pos[b]], rgbcolor=ecolor, linestyle=estyle, thickness=ethickness)) if labels and not self._arcdigraph: bg = self._options['edge_labels_background'] - self._plot_components['edge_labels'].append( - text(str(edges_to_draw[a, b][0][0]), - [(self._pos[a][0] + self._pos[b][0]) / 2., - (self._pos[a][1] + self._pos[b][1]) / 2.], - background_color=bg, - fontsize=self._options['label_fontsize'] - )) + self._plot_components['edge_labels'].append(text(str(edges_to_draw[a, b][0][0]), [(self._pos[a][0] + self._pos[b][0]) / 2.0, (self._pos[a][1] + self._pos[b][1]) / 2.0], background_color=bg, fontsize=self._options['label_fontsize'])) def _polar_hack_for_multidigraph(self, A, B, VR): """ @@ -1091,7 +915,7 @@ def _polar_hack_for_multidigraph(self, A, B, VR): ([0.08..., 1.04...], [1.91..., 1.95...]) """ D = [float(B[i] - A[i]) for i in range(2)] - R = sqrt(D[0]**2 + D[1]**2) + R = sqrt(D[0] ** 2 + D[1] ** 2) theta = 3 * pi / 2 if D[0] > 0: theta = atan(D[1] / D[0]) @@ -1103,8 +927,7 @@ def _polar_hack_for_multidigraph(self, A, B, VR): theta = pi / 2 cos_theta = cos(theta) sin_theta = sin(theta) - return ([VR * cos_theta + A[0], VR * sin_theta + A[1]], - [(R - VR) * cos_theta + A[0], (R - VR) * sin_theta + A[1]]) + return ([VR * cos_theta + A[0], VR * sin_theta + A[1]], [(R - VR) * cos_theta + A[0], (R - VR) * sin_theta + A[1]]) def show(self, **kwds): """ @@ -1652,11 +1475,8 @@ def plot(self, **kwds): ymax = G.ymax() dx = (xmax - xmin) / 10.0 dy = (ymax - ymin) / 10.0 - border = (line([(xmin - dx, ymin - dy), (xmin - dx, ymax + dy), - (xmax + dx, ymax + dy), (xmax + dx, ymin - dy), - (xmin - dx, ymin - dy)], thickness=1.3)) - border.axes_range(xmin=(xmin - dx), xmax=(xmax + dx), - ymin=(ymin - dy), ymax=(ymax + dy)) + border = line([(xmin - dx, ymin - dy), (xmin - dx, ymax + dy), (xmax + dx, ymax + dy), (xmax + dx, ymin - dy), (xmin - dx, ymin - dy)], thickness=1.3) + border.axes_range(xmin=(xmin - dx), xmax=(xmax + dx), ymin=(ymin - dy), ymax=(ymax + dy)) G += border G.set_aspect_ratio(1) G.axes(False) @@ -1687,8 +1507,7 @@ def layout_tree(self, root, orientation): T = self._graph if not self._graph.is_tree(): - raise RuntimeError("cannot use tree layout on this graph: " - "self.is_tree() returns False") + raise RuntimeError("cannot use tree layout on this graph: " "self.is_tree() returns False") children = {root: T.neighbors(root)} diff --git a/src/sage/graphs/graph_plot_js.py b/src/sage/graphs/graph_plot_js.py index b45e5cfea0d..e4d26410f2b 100644 --- a/src/sage/graphs/graph_plot_js.py +++ b/src/sage/graphs/graph_plot_js.py @@ -76,6 +76,7 @@ from pathlib import Path from sage.misc.temporary_file import tmp_filename from sage.misc.lazy_import import lazy_import + lazy_import("sage.plot.colors", "rainbow") # **************************************************************************** @@ -89,19 +90,7 @@ # **************************************************************************** -def gen_html_code(G, - vertex_labels=True, - edge_labels=False, - vertex_partition=[], - vertex_colors=None, - edge_partition=[], - force_spring_layout=False, - charge=-120, - link_distance=30, - link_strength=2, - gravity=.04, - vertex_size=7, - edge_thickness=4): +def gen_html_code(G, vertex_labels=True, edge_labels=False, vertex_partition=[], vertex_colors=None, edge_partition=[], force_spring_layout=False, charge=-120, link_distance=30, link_strength=2, gravity=0.04, vertex_size=7, edge_thickness=4): r""" Create a .html file showing the graph using `d3.js `_. @@ -234,7 +223,7 @@ def gen_html_code(G, edge_color = {} for i, l in enumerate(edge_partition): for e in l: - u, v, label = e if len(e) == 3 else e+(None,) + u, v, label = e if len(e) == 3 else e + (None,) edge_color[u, v, label] = color_list[i] if not directed: edge_color[v, u, label] = color_list[i] @@ -277,12 +266,7 @@ def gen_html_code(G, # Adding the edge to the list # The source (resp. target) is the index of u (resp. v) in list nodes - edges.append({"source": v_to_id[u], - "target": v_to_id[v], - "strength": 0, - "color": color, - "curve": curve, - "name": str(l) if edge_labels else ""}) + edges.append({"source": v_to_id[u], "target": v_to_id[v], "strength": 0, "color": color, "curve": curve, "name": str(l) if edge_labels else ""}) loops = [e for e in edges if e["source"] == e["target"]] edges = [e for e in edges if e["source"] != e["target"]] @@ -301,21 +285,11 @@ def gen_html_code(G, # Encodes the data as a JSON string from json import JSONEncoder - string = JSONEncoder().encode({"nodes": nodes, - "links": edges, - "loops": loops, - "pos": pos, - "directed": G.is_directed(), - "charge": int(charge), - "link_distance": int(link_distance), - "link_strength": int(link_strength), - "gravity": float(gravity), - "vertex_labels": bool(vertex_labels), - "edge_labels": bool(edge_labels), - "vertex_size": int(vertex_size), - "edge_thickness": int(edge_thickness)}) + + string = JSONEncoder().encode({"nodes": nodes, "links": edges, "loops": loops, "pos": pos, "directed": G.is_directed(), "charge": int(charge), "link_distance": int(link_distance), "link_strength": int(link_strength), "gravity": float(gravity), "vertex_labels": bool(vertex_labels), "edge_labels": bool(edge_labels), "vertex_size": int(vertex_size), "edge_thickness": int(edge_thickness)}) from sage.env import SAGE_EXTCODE, sage_data_paths + with open(Path(SAGE_EXTCODE) / "graphs" / "graph_plot_js.html") as f: js_code = f.read().replace("// GRAPH_DATA_HEREEEEEEEEEEE", string) diff --git a/src/sage/graphs/hypergraph_generators.py b/src/sage/graphs/hypergraph_generators.py index 394ea697d56..002f14aaba0 100644 --- a/src/sage/graphs/hypergraph_generators.py +++ b/src/sage/graphs/hypergraph_generators.py @@ -37,14 +37,7 @@ class HypergraphGenerators: A class consisting of constructors for common hypergraphs. """ - def nauty(self, number_of_sets, number_of_vertices, - multiple_sets=False, - vertex_min_degree=None, vertex_max_degree=None, - set_max_size=None, set_min_size=None, - regular=False, uniform=False, - max_intersection=None, - connected=False, - debug=False, options=''): + def nauty(self, number_of_sets, number_of_vertices, multiple_sets=False, vertex_min_degree=None, vertex_max_degree=None, set_max_size=None, set_min_size=None, regular=False, uniform=False, max_intersection=None, connected=False, debug=False, options=''): r""" Enumerate hypergraphs up to isomorphism using Nauty. @@ -149,6 +142,7 @@ def nauty(self, number_of_sets, number_of_vertices, import subprocess import shlex from sage.features.nauty import NautyExecutable + genbgL_path = NautyExecutable("genbgL").absolute_filename() nauty_input = options @@ -182,9 +176,7 @@ def nauty(self, number_of_sets, number_of_vertices, nauty_input += " " + str(number_of_vertices) + " " + str(number_of_sets) + " " - with subprocess.Popen(shlex.quote(genbgL_path) + " {0}".format(nauty_input), shell=True, - stdin=subprocess.PIPE, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, close_fds=True) as sp: + with subprocess.Popen(shlex.quote(genbgL_path) + " {0}".format(nauty_input), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) as sp: if debug: yield sp.stderr.readline() @@ -192,6 +184,7 @@ def nauty(self, number_of_sets, number_of_vertices, gen = sp.stdout total = number_of_sets + number_of_vertices from sage.graphs.graph import Graph + while True: try: s = next(gen) @@ -220,6 +213,7 @@ def CompleteUniform(self, n, k): """ from sage.combinat.designs.incidence_structures import IncidenceStructure from itertools import combinations + return IncidenceStructure(points=n, blocks=list(combinations(range(n), k))) def UniformRandomUniform(self, n, k, m): @@ -289,6 +283,7 @@ def UniformRandomUniform(self, n, k, m): raise ValueError("number of edges m must be between 0 and binomial({}, {})".format(n, k)) from sage.combinat.designs.incidence_structures import IncidenceStructure + return IncidenceStructure(points=vertices, blocks=edges) def BinomialRandomUniform(self, n, k, p): @@ -338,6 +333,7 @@ def BinomialRandomUniform(self, n, k, p): ValueError: the uniformity should be an integer """ from sage.rings.integer import Integer + if n < 0: raise ValueError("number of vertices should be nonnegative") try: @@ -355,6 +351,7 @@ def BinomialRandomUniform(self, n, k, p): import numpy.random as nrn from sage.arith.misc import binomial + m = nrn.binomial(binomial(nverts, uniformity), p) return hypergraphs.UniformRandomUniform(n, k, m) diff --git a/src/sage/graphs/isgci.py b/src/sage/graphs/isgci.py index 6a9109c6e2c..53bd13eeedf 100644 --- a/src/sage/graphs/isgci.py +++ b/src/sage/graphs/isgci.py @@ -420,6 +420,7 @@ class GraphClass(SageObject, CachedRepresentation): sage: Chordal >= Trees True """ + def __init__(self, name, gc_id, recognition_function=None): r""" Class constructor. @@ -599,8 +600,7 @@ def __contains__(self, g) -> bool: excluded = self.forbidden_subgraphs() if excluded is None: - raise NotImplementedError("No recognition algorithm is available " - "for this class.") + raise NotImplementedError("No recognition algorithm is available " "for this class.") return not any(g.subgraph_search(gg, induced=True) for gg in excluded) @@ -681,9 +681,7 @@ def get_class(self, id): name = "class " + str(id) return GraphClass(name, id) - raise ValueError("The given class id does not exist in the ISGCI " - "database. Is the db too old ? You can update it " - "with graph_classes.update_db().") + raise ValueError("The given class id does not exist in the ISGCI " "database. Is the db too old ? You can update it " "with graph_classes.update_db().") @cached_method def classes(self): @@ -769,6 +767,7 @@ def inclusion_digraph(self): inclusions = self.inclusions() from sage.graphs.digraph import DiGraph + inclusion_digraph = DiGraph() inclusion_digraph.add_vertices(classes.keys()) @@ -788,9 +787,9 @@ def _download_db(self): sage: graph_classes._download_db() # optional - internet """ import tempfile + data_dir = os.path.dirname(DatabaseGraphs().absolute_filename()) - u = urlopen('https://www.graphclasses.org/data.zip', - context=default_context()) + u = urlopen('https://www.graphclasses.org/data.zip', context=default_context()) with tempfile.NamedTemporaryFile(suffix='.zip') as f: f.write(u.read()) z = zipfile.ZipFile(f.name) @@ -908,12 +907,7 @@ def show_all(self): # We want to print the different fields, and this dictionary stores the # maximal number of characters of each field. - MAX = { - "id": 0, - "type": 0, - "smallgraph": 0, - "name": 0 - } + MAX = {"id": 0, "type": 0, "smallgraph": 0, "name": 0} # We sort the classes alphabetically, though we would like to display # the meaningful classes at the top of the list @@ -940,7 +934,7 @@ def sort_key(x): st += (" | {:" + str(MAX["type"]) + "}").format("type") st += (" | {:" + str(MAX["smallgraph"]) + "}").format("smallgraph") print(st) - print("-" * (sum(MAX.values())+9)) + print("-" * (sum(MAX.values()) + 9)) # Entries for entry in classes_list: diff --git a/src/sage/graphs/lovasz_theta.py b/src/sage/graphs/lovasz_theta.py index 5335a597ebf..ff42004e47e 100644 --- a/src/sage/graphs/lovasz_theta.py +++ b/src/sage/graphs/lovasz_theta.py @@ -65,6 +65,7 @@ def lovasz_theta(graph): import subprocess from sage.features.csdp import CSDP + CSDP().require() g = graph.relabel(inplace=False, perm=range(1, n + 1)).networkx_graph() diff --git a/src/sage/graphs/matching.py b/src/sage/graphs/matching.py index efb32d8611f..9320c95b444 100644 --- a/src/sage/graphs/matching.py +++ b/src/sage/graphs/matching.py @@ -53,8 +53,7 @@ from sage.graphs.views import EdgesView -def has_perfect_matching(G, algorithm='Edmonds', solver=None, verbose=0, - *, integrality_tolerance=1e-3): +def has_perfect_matching(G, algorithm='Edmonds', solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return whether the graph has a perfect matching. @@ -133,18 +132,12 @@ def has_perfect_matching(G, algorithm='Edmonds', solver=None, verbose=0, return False if algorithm == "Edmonds": - return len(G) == 2*G.matching(value_only=True, - use_edge_labels=False, - algorithm='Edmonds') + return len(G) == 2 * G.matching(value_only=True, use_edge_labels=False, algorithm='Edmonds') if algorithm == "LP_matching": - return len(G) == 2*G.matching(value_only=True, - use_edge_labels=False, - algorithm='LP', - solver=solver, - verbose=verbose, - integrality_tolerance=integrality_tolerance) + return len(G) == 2 * G.matching(value_only=True, use_edge_labels=False, algorithm='LP', solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) if algorithm == "LP": from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException + p = MixedIntegerLinearProgram(solver=solver) b = p.new_variable(binary=True) for v in G: @@ -160,8 +153,7 @@ def has_perfect_matching(G, algorithm='Edmonds', solver=None, verbose=0, raise ValueError('algorithm must be set to "Edmonds", "LP_matching" or "LP"') -def is_bicritical(G, matching=None, algorithm='Edmonds', coNP_certificate=False, - solver=None, verbose=0, *, integrality_tolerance=0.001): +def is_bicritical(G, matching=None, algorithm='Edmonds', coNP_certificate=False, solver=None, verbose=0, *, integrality_tolerance=0.001): r""" Check if the graph is bicritical. @@ -447,6 +439,7 @@ def is_bicritical(G, matching=None, algorithm='Edmonds', coNP_certificate=False, return (False, set(list(B)[:2])) from sage.graphs.graph import Graph + if matching: # The input matching must be a valid perfect matching of the graph M = Graph(matching) @@ -456,12 +449,11 @@ def is_bicritical(G, matching=None, algorithm='Edmonds', coNP_certificate=False, if any(not G.has_edge(edge) for edge in M.edge_iterator()): raise ValueError("the input is not a matching of the graph") - if (G.order() != M.order()) or (G.order() != 2*M.size()): + if (G.order() != M.order()) or (G.order() != 2 * M.size()): raise ValueError("the input is not a perfect matching of the graph") else: # A maximum matching of the graph is computed - M = Graph(G.matching(algorithm=algorithm, solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance)) + M = Graph(G.matching(algorithm=algorithm, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance)) # It must be a perfect matching if G.order() != M.order(): @@ -486,8 +478,7 @@ def is_bicritical(G, matching=None, algorithm='Edmonds', coNP_certificate=False, return (True, None) if coNP_certificate else True -def is_factor_critical(G, matching=None, algorithm='Edmonds', solver=None, verbose=0, - *, integrality_tolerance=0.001): +def is_factor_critical(G, matching=None, algorithm='Edmonds', solver=None, verbose=0, *, integrality_tolerance=0.001): r""" Check whether the graph is factor-critical. @@ -608,11 +599,11 @@ def is_factor_critical(G, matching=None, algorithm='Edmonds', solver=None, verbo # The graph must have an odd number of vertices, be 2-edge connected, so # without bridges, and not bipartite - if (not G.order() % 2 or not G.is_connected() or - list(G.bridges()) or G.is_bipartite()): + if not G.order() % 2 or not G.is_connected() or list(G.bridges()) or G.is_bipartite(): return False from sage.graphs.graph import Graph + if matching: # We check that the input matching is a valid near perfect matching # of the graph. @@ -621,12 +612,11 @@ def is_factor_critical(G, matching=None, algorithm='Edmonds', solver=None, verbo raise ValueError("the input is not a matching") if not M.is_subgraph(G, induced=False): raise ValueError("the input is not a matching of the graph") - if (G.order() != M.order() + 1) or (G.order() != 2*M.size() + 1): + if (G.order() != M.order() + 1) or (G.order() != 2 * M.size() + 1): raise ValueError("the input is not a near perfect matching of the graph") else: # We compute a maximum matching of the graph - M = Graph(G.matching(algorithm=algorithm, solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance)) + M = Graph(G.matching(algorithm=algorithm, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance)) # It must be a near-perfect matching if G.order() != M.order() + 1: @@ -640,6 +630,7 @@ def is_factor_critical(G, matching=None, algorithm='Edmonds', solver=None, verbo # We virtually build an M-alternating tree T from queue import Queue + Q = Queue() Q.put(u) even = set([u]) @@ -690,8 +681,7 @@ def is_factor_critical(G, matching=None, algorithm='Edmonds', solver=None, verbo return len(even) == G.order() -def is_matching_covered(G, matching=None, algorithm='Edmonds', coNP_certificate=False, - solver=None, verbose=0, *, integrality_tolerance=0.001): +def is_matching_covered(G, matching=None, algorithm='Edmonds', coNP_certificate=False, solver=None, verbose=0, *, integrality_tolerance=0.001): r""" Check if the graph is matching covered. @@ -979,6 +969,7 @@ def is_matching_covered(G, matching=None, algorithm='Edmonds', coNP_certificate= return (True, None) if coNP_certificate else True from sage.graphs.graph import Graph + if matching: # The input matching must be a valid perfect matching of the graph M = Graph(matching) @@ -989,12 +980,11 @@ def is_matching_covered(G, matching=None, algorithm='Edmonds', coNP_certificate= if any(not G.has_edge(edge) for edge in M.edge_iterator()): raise ValueError("the input is not a matching of the graph") - if (G.order() != M.order()) or (G.order() != 2*M.size()): + if (G.order() != M.order()) or (G.order() != 2 * M.size()): raise ValueError("the input is not a perfect matching of the graph") else: # A maximum matching of the graph is computed - M = Graph(G.matching(algorithm=algorithm, solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance)) + M = Graph(G.matching(algorithm=algorithm, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance)) # It must be a perfect matching if G.order() != M.order(): @@ -1016,6 +1006,7 @@ def is_matching_covered(G, matching=None, algorithm='Edmonds', coNP_certificate= color[u] = 0 if u in A else 1 from sage.graphs.digraph import DiGraph + H = DiGraph() for u, v in G.edge_iterator(labels=False): @@ -1073,9 +1064,7 @@ def dfs(v, visited, neighbor_iterator): return (True, None) if coNP_certificate else True -def matching(G, value_only=False, algorithm='Edmonds', - use_edge_labels=False, solver=None, verbose=0, - *, integrality_tolerance=1e-3): +def matching(G, value_only=False, algorithm='Edmonds', use_edge_labels=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return a maximum weighted matching of the graph represented by the list of its edges. @@ -1225,6 +1214,7 @@ def weight(x): if algorithm == "Edmonds": import networkx + g = networkx.Graph() if use_edge_labels: for (u, v), w in W.items(): @@ -1239,12 +1229,13 @@ def weight(x): return Integer(len(d)) from sage.graphs.graph import Graph - return EdgesView(Graph([(u, v, L[frozenset((u, v))]) for u, v in d], - format='list_of_edges')) + + return EdgesView(Graph([(u, v, L[frozenset((u, v))]) for u, v in d], format='list_of_edges')) if algorithm == "LP": g = G from sage.numerical.mip import MixedIntegerLinearProgram + # returns the weight of an edge considering it may not be # weighted ... p = MixedIntegerLinearProgram(maximization=True, solver=solver) @@ -1256,8 +1247,7 @@ def weight(x): # for any vertex v, there is at most one edge incident to v in # the maximum matching for v in g: - p.add_constraint(p.sum(b[frozenset(e)] for e in G.edge_iterator(vertices=[v], labels=False) - if e[0] != e[1]), max=1) + p.add_constraint(p.sum(b[frozenset(e)] for e in G.edge_iterator(vertices=[v], labels=False) if e[0] != e[1]), max=1) p.solve(log=verbose) b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) @@ -1267,9 +1257,8 @@ def weight(x): return Integer(sum(1 for fe in L if b[fe])) from sage.graphs.graph import Graph - return EdgesView(Graph([(u, v, L[frozenset((u, v))]) - for u, v in L if b[frozenset((u, v))]], - format='list_of_edges')) + + return EdgesView(Graph([(u, v, L[frozenset((u, v))]) for u, v in L if b[frozenset((u, v))]], format='list_of_edges')) raise ValueError('algorithm must be set to either "Edmonds" or "LP"') @@ -1550,6 +1539,7 @@ def M_alternating_even_mark(G, vertex, matching): # The input matching must be a valid matching of the graph from sage.graphs.graph import Graph + M = Graph(matching) if any(d != 1 for d in M.degree()): raise ValueError("the input is not a matching") diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 249fdc8b962..2e3c89f27b5 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -590,9 +590,7 @@ class MatchingCoveredGraph(Graph): TypeError: input data is of unknown type """ - def __init__(self, data=None, matching=None, algorithm='Edmonds', - solver=None, verbose=0, integrality_tolerance=0.001, - *args, **kwds): + def __init__(self, data=None, matching=None, algorithm='Edmonds', solver=None, verbose=0, integrality_tolerance=0.001, *args, **kwds): r""" Create a matching covered graph, that is a connected nontrivial graph wherein each edge participates in some perfect matching. @@ -605,8 +603,7 @@ def __init__(self, data=None, matching=None, algorithm='Edmonds', kwds = {'loops': False} else: if 'loops' in kwds and kwds['loops']: - raise ValueError('loops are not allowed in ' - 'matching covered graphs') + raise ValueError('loops are not allowed in ' 'matching covered graphs') kwds['loops'] = False if data is None: @@ -618,11 +615,7 @@ def __init__(self, data=None, matching=None, algorithm='Edmonds', elif isinstance(data, Graph): try: - self._upgrade_from_graph(data=data, matching=matching, - algorithm=algorithm, - solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance, - *args, **kwds) + self._upgrade_from_graph(data=data, matching=matching, algorithm=algorithm, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance, *args, **kwds) success = True except Exception as exception: @@ -848,12 +841,9 @@ def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None, imm return G - G = Graph(self, weighted=self._weighted, loops=self.allows_loops(), - multiedges=self.allows_multiple_edges()) + G = Graph(self, weighted=self._weighted, loops=self.allows_loops(), multiedges=self.allows_multiple_edges()) - H = G._subgraph_by_adding(vertices=vertices, edges=edges, - edge_property=edge_property, - immutable=False) + H = G._subgraph_by_adding(vertices=vertices, edges=edges, edge_property=edge_property, immutable=False) try: H = MatchingCoveredGraph(H) @@ -866,20 +856,14 @@ def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None, imm except Exception as exception: raise exception - def _upgrade_from_graph(self, data=None, matching=None, algorithm='Edmonds', - solver=None, verbose=0, integrality_tolerance=0.001, - *args, **kwds): + def _upgrade_from_graph(self, data=None, matching=None, algorithm='Edmonds', solver=None, verbose=0, integrality_tolerance=0.001, *args, **kwds): r""" Upgrade the given graph to a matching covered graph if eligible. See documentation ``MatchingCoveredGraph?`` for detailed information. """ try: - check = Graph.is_matching_covered(G=data, matching=matching, - algorithm=algorithm, - coNP_certificate=False, - solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + check = Graph.is_matching_covered(G=data, matching=matching, algorithm=algorithm, coNP_certificate=False, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) if check: Graph.__init__(self, data, *args, **kwds) @@ -1129,8 +1113,7 @@ def add_edge(self, u, v=None, label=None): if u in self and v in self: if u == v: - raise ValueError('loops are not allowed in ' - 'matching covered graphs') + raise ValueError('loops are not allowed in ' 'matching covered graphs') # If (u, v, label) is a multiple edge/ an existing edge if self.has_edge(u, v): @@ -1140,6 +1123,7 @@ def add_edge(self, u, v=None, label=None): # Check if there exists an M-alternating odd uv path starting and # ending with edges in self._matching from sage.graphs.matching import M_alternating_even_mark + w = next((b if a == u else a) for a, b, *_ in self.get_matching() if u in (a, b)) if v in M_alternating_even_mark(self, w, self.get_matching()): @@ -1147,8 +1131,7 @@ def add_edge(self, u, v=None, label=None): self._backend.add_edge(u, v, label, self._directed) return - raise ValueError('the graph obtained after the addition of edge ' - '(%s) is not matching covered' % str((u, v, label))) + raise ValueError('the graph obtained after the addition of edge ' '(%s) is not matching covered' % str((u, v, label))) @doc_index('Overwritten methods') def add_edges(self, edges, loops=False): @@ -1374,27 +1357,24 @@ def add_edges(self, edges, loops=False): TypeError: input edge None is of unknown type """ if loops: - raise ValueError('loops are not allowed in ' - 'matching covered graphs') + raise ValueError('loops are not allowed in ' 'matching covered graphs') if not edges: # do nothing return from collections.abc import Iterable + if not isinstance(edges, Iterable): - raise ValueError('expected an iterable of edges, ' - 'but got a non-iterable object') + raise ValueError('expected an iterable of edges, ' 'but got a non-iterable object') links = [] # to extract the nonloop input edges for edge in edges: if hasattr(edge, '__len__'): if len(edge) <= 1: - raise ValueError('need more than 1 value to unpack ' - f'for edge: {edge}') + raise ValueError('need more than 1 value to unpack ' f'for edge: {edge}') elif len(edge) > 3: - raise ValueError('too many values to unpack (expected 2) ' - f'for edge: {edge}') + raise ValueError('too many values to unpack (expected 2) ' f'for edge: {edge}') else: raise TypeError(f'input edge {edge} is of unknown type') @@ -1410,19 +1390,16 @@ def add_edges(self, edges, loops=False): links.append((u, v, l)) # If each of the input edges is existent - if (self.allows_multiple_edges() - and all(self.has_edge(*edge) for edge in links)): + if self.allows_multiple_edges() and all(self.has_edge(*edge) for edge in links): self._backend.add_edges(links, self._directed) return # Check if all the incident vertices of the input edges are existent - new_vertices = {x for u, v, _ in links for x in (u, v) - if x not in self} + new_vertices = {x for u, v, _ in links for x in (u, v) if x not in self} # Throw error if the no. of new vertices is odd if len(new_vertices) % 2: - raise ValueError('odd order is not allowed for ' - 'matching covered graphs') + raise ValueError('odd order is not allowed for ' 'matching covered graphs') try: G = Graph(self, multiedges=self.allows_multiple_edges()) @@ -1430,8 +1407,7 @@ def add_edges(self, edges, loops=False): # Check if G has a vertex with at most 1 neighbor if any(len(G.neighbors(v)) <= 1 for v in G): - raise ValueError('the resulting graph after the addition of' - 'the edges is not matching covered') + raise ValueError('the resulting graph after the addition of' 'the edges is not matching covered') # If all the vertices are existent, the existing perfect matching # can be used. @@ -1451,14 +1427,13 @@ def add_edges(self, edges, loops=False): M.add_edges(self.get_matching()) # Check if M is a perfect matching of the resulting graph - if (G.order() != 2 * M.size()): + if G.order() != 2 * M.size(): M = None self.__init__(data=G, matching=M) except Exception: - raise ValueError('the resulting graph after the addition of' - 'the edges is not matching covered') + raise ValueError('the resulting graph after the addition of' 'the edges is not matching covered') @doc_index('Overwritten methods') def add_vertex(self, name=None): @@ -1514,8 +1489,7 @@ def add_vertex(self, name=None): ValueError: isolated vertices are not allowed in matching covered graphs """ if name not in self: - raise ValueError('isolated vertices are not allowed in ' - 'matching covered graphs') + raise ValueError('isolated vertices are not allowed in ' 'matching covered graphs') @doc_index('Overwritten methods') def add_vertices(self, vertices): @@ -1584,8 +1558,7 @@ def add_vertices(self, vertices): ValueError: isolated vertices are not allowed in matching covered graphs """ if any(vertex not in self for vertex in vertices): - raise ValueError('isolated vertices are not allowed in ' - 'matching covered graphs') + raise ValueError('isolated vertices are not allowed in ' 'matching covered graphs') @doc_index('Overwritten methods') def allow_loops(self, new, check=True): @@ -1639,8 +1612,7 @@ def allow_loops(self, new, check=True): - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` """ if new: - raise ValueError('loops are not allowed in ' - 'matching covered graphs') + raise ValueError('loops are not allowed in ' 'matching covered graphs') @doc_index('Overwritten methods') def allows_loops(self): @@ -1823,8 +1795,7 @@ def delete_vertex(self, vertex, in_order=False): if in_order: vertex = self.vertices(sort=True)[vertex] - raise ValueError('odd order is not allowed for ' - 'matching covered graphs') + raise ValueError('odd order is not allowed for ' 'matching covered graphs') @doc_index('Overwritten methods') def delete_vertices(self, vertices): @@ -1939,24 +1910,21 @@ def delete_vertices(self, vertices): sage: G # Matching covered graph on 6 vertices Matching covered staircase graph: graph on 6 vertices """ - if not vertices: # do nothing + if not vertices: # do nothing return # Remove potentially duplicated vertices vertices = set(vertices) if len(vertices) % 2: # try to remove an odd number of vertices - raise ValueError('an odd no. of distinct vertices can not be ' - 'removed from a matching covered graph') + raise ValueError('an odd no. of distinct vertices can not be ' 'removed from a matching covered graph') for vertex in vertices: if vertex not in self: raise ValueError('vertex (%s) not in the graph' % str(vertex)) if self.order() == len(vertices): - raise ValueError('the resulting graph after the removal of the ' - 'vertices is trivial, therefore is not ' - 'matching covered') + raise ValueError('the resulting graph after the removal of the ' 'vertices is trivial, therefore is not ' 'matching covered') try: G = Graph(self, multiedges=self.allows_multiple_edges()) @@ -1969,14 +1937,13 @@ def delete_vertices(self, vertices): # must be a valid perfect matching of the resulting graph obtained # after the removal of the vertices - if (G.order() != 2 * M.size()): + if G.order() != 2 * M.size(): M = None self.__init__(data=G, matching=M) except Exception: - raise ValueError('the resulting graph after the removal of ' - 'the vertices is not matching covered') + raise ValueError('the resulting graph after the removal of ' 'the vertices is not matching covered') @doc_index('Miscellaneous methods') def get_matching(self): @@ -2195,8 +2162,8 @@ def maximal_barrier(self, vertex): # even: The set of all such vertex w from sage.graphs.matching import M_alternating_even_mark - even = M_alternating_even_mark(G=self, matching=matching, - vertex=u) + + even = M_alternating_even_mark(G=self, matching=matching, vertex=u) B = set([vertex]) B.update(v for v in self if v not in even) @@ -2275,8 +2242,7 @@ def has_loops(self) -> bool: return False @doc_index('Overwritten methods') - def has_perfect_matching(G, algorithm='Edmonds', solver=None, verbose=0, - *, integrality_tolerance=1e-3): + def has_perfect_matching(G, algorithm='Edmonds', solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Check whether the graph has a perfect matching. @@ -2356,8 +2322,7 @@ def has_perfect_matching(G, algorithm='Edmonds', solver=None, verbose=0, if algorithm in ['Edmonds', 'LP_matching', 'LP']: return True - raise ValueError('algorithm must be set to \'Edmonds\', ' - '\'LP_matching\' or \'LP\'') + raise ValueError('algorithm must be set to \'Edmonds\', ' '\'LP_matching\' or \'LP\'') @doc_index('Overwritten methods') def is_biconnected(self): @@ -2761,6 +2726,7 @@ def is_brace(self, coNP_certificate=False): # Construct the digraph D(e)(A ∪ B, F) defined as follows: from sage.graphs.digraph import DiGraph + D = DiGraph() # For each edge (a, b) in E(H(e)) ∩ M with a in A, b —> a in D(e). @@ -2819,9 +2785,7 @@ def dfs(x, visited, neighbor_iterator): X.add(u if (not color_class and u in A) or (color_class and u in B) or (color_class is None) else v) # Compute the nontrivial tight cut C := ∂(Y) - C = [(x, y, w) if x in X else (y, x, w) - for x, y, w in self.edge_iterator(sort_vertices=True) - if (x in X) ^ (y in X)] + C = [(x, y, w) if x in X else (y, x, w) for x, y, w in self.edge_iterator(sort_vertices=True) if (x in X) ^ (y in X)] # Obtain the barrier Z Z = None @@ -3149,16 +3113,10 @@ def is_brick(self, coNP_certificate=False): # Let K be a nontrivial odd component of H := G - B. Note that # there exists at least one such K since G is nonbipartite - nontrivial_odd_components = [ - set(component) for component in H.connected_components(sort=True) - if len(component) % 2 and len(component) > 1 - ] + nontrivial_odd_components = [set(component) for component in H.connected_components(sort=True) if len(component) % 2 and len(component) > 1] # Find a laminar set of nontrivial barrier cuts - C = [[(u, v, w) if u in nontrivial_odd_component else (v, u, w) - for u, v, w in self.edge_iterator() - if (u in nontrivial_odd_component) ^ (v in nontrivial_odd_component)] - for nontrivial_odd_component in nontrivial_odd_components] + C = [[(u, v, w) if u in nontrivial_odd_component else (v, u, w) for u, v, w in self.edge_iterator() if (u in nontrivial_odd_component) ^ (v in nontrivial_odd_component)] for nontrivial_odd_component in nontrivial_odd_components] return (False, C, nontrivial_odd_components, 'nontrivial barrier cut', B) @@ -3184,6 +3142,7 @@ def is_brick(self, coNP_certificate=False): # If no 2-vertex cut found, look for R nodes if not two_vertex_cut: from collections import Counter + R_frequency = Counter() for t, g in spqr_tree: @@ -3215,10 +3174,7 @@ def is_brick(self, coNP_certificate=False): nontrivial_odd_component.update(component) nontrivial_odd_components.append(nontrivial_odd_component) - C = [[(u, v, w) if u in nontrivial_odd_component else (v, u, w) - for u, v, w in self.edge_iterator() - if (u in nontrivial_odd_component) ^ (v in nontrivial_odd_component)] - for nontrivial_odd_component in nontrivial_odd_components] + C = [[(u, v, w) if u in nontrivial_odd_component else (v, u, w) for u, v, w in self.edge_iterator() if (u in nontrivial_odd_component) ^ (v in nontrivial_odd_component)] for nontrivial_odd_component in nontrivial_odd_components] # Edge (u, v, w) in C are formatted so that u is in a nontrivial odd component return (False, C, nontrivial_odd_components, nontrivial_tight_cut_variation, set(two_vertex_cut)) if coNP_certificate else False @@ -3535,8 +3491,7 @@ def remove_loops(self, vertices=None): from collections.abc import Iterable if vertices is not None and not isinstance(vertices, Iterable): - raise TypeError(f'\'{vertices.__class__.__name__}\' ' - 'object is not iterable') + raise TypeError(f'\'{vertices.__class__.__name__}\' ' 'object is not iterable') @doc_index('Overwritten methods') def subdivide_edge(self, *args): @@ -3720,8 +3675,7 @@ def subdivide_edge(self, *args): u, v, l = edge else: - raise ValueError('for two input arguments, the first one must be ' - f'of the form (u, v) or (u, v, l), but found: {edge}') + raise ValueError('for two input arguments, the first one must be ' f'of the form (u, v) or (u, v, l), but found: {edge}') elif len(args) == 3: u, v, k = args @@ -3743,8 +3697,7 @@ def subdivide_edge(self, *args): raise ValueError(f'the given edge {(u, v, l)} does not exist') if k < 0 or k % 2: - raise ValueError('the number of subdivisions must be a ' - f'nonnegative even integer, but found {k}') + raise ValueError('the number of subdivisions must be a ' f'nonnegative even integer, but found {k}') if not k: return @@ -3760,17 +3713,15 @@ def subdivide_edge(self, *args): self._backend.add_edge(new_vertices[-1], v, l, self._directed) from itertools import pairwise - self._backend.add_edges([(x, y, l) for x, y in pairwise(new_vertices)], - self._directed, remove_loops=True) + + self._backend.add_edges([(x, y, l) for x, y in pairwise(new_vertices)], self._directed, remove_loops=True) if M.degree(u): - M.add_edges([(x, y, l) - for x, y in zip(new_vertices[::2], new_vertices[1::2])]) + M.add_edges([(x, y, l) for x, y in zip(new_vertices[::2], new_vertices[1::2])]) else: M.add_edge(u, new_vertices[0], l) M.add_edge(new_vertices[-1], v, l) - M.add_edges([(x, y, l) - for x, y in zip(new_vertices[1::2], new_vertices[2::2])]) + M.add_edges([(x, y, l) for x, y in zip(new_vertices[1::2], new_vertices[2::2])]) self.update_matching(M) @@ -3963,12 +3914,12 @@ def subdivide_edges(self, edges, k): - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.subdivide_edge` """ from collections.abc import Iterable + if not isinstance(edges, Iterable): raise ValueError('expected an iterable of edges, but got a non-iterable object') if k < 0 or k % 2: - raise ValueError('the number of subdivisions must be a ' - f'nonnegative even integer, but found {k}') + raise ValueError('the number of subdivisions must be a ' f'nonnegative even integer, but found {k}') if not k: return @@ -3976,12 +3927,10 @@ def subdivide_edges(self, edges, k): for i, edge in enumerate(edges): if hasattr(edge, '__len__'): if len(edge) <= 1: - raise ValueError('need more than 1 value to unpack ' - f'for edge: {edge}') + raise ValueError('need more than 1 value to unpack ' f'for edge: {edge}') elif len(edge) > 3: - raise ValueError('too many values to unpack (expected 2) ' - f'for edge: {edge}') + raise ValueError('too many values to unpack (expected 2) ' f'for edge: {edge}') else: raise TypeError(f'input edge {edge} is of unknown type') @@ -4003,6 +3952,7 @@ def subdivide_edges(self, edges, k): edges[i] = (u, v, l) from collections import Counter + edge_frequency = Counter(edges) for edge, n in edge_frequency.items(): @@ -4012,12 +3962,12 @@ def subdivide_edges(self, edges, k): c = labels.count(l) if self.allows_multiple_edges() and isinstance(labels, list) else 1 if c < n: - raise ValueError(f'input contains {n} copies of the edge ' - f'{edge}, but the graph contains {c}') + raise ValueError(f'input contains {n} copies of the edge ' f'{edge}, but the graph contains {c}') M = Graph(self.get_matching()) from itertools import pairwise + for i, edge in enumerate(edges): u, v, l = edge self._backend.del_edge(u, v, l, self._directed) @@ -4026,20 +3976,17 @@ def subdivide_edges(self, edges, k): self._backend.add_edge(u, new_vertices[0], l, self._directed) self._backend.add_edge(new_vertices[-1], v, l, self._directed) - self._backend.add_edges([(x, y, l) for x, y in pairwise(new_vertices)], - self._directed, remove_loops=True) + self._backend.add_edges([(x, y, l) for x, y in pairwise(new_vertices)], self._directed, remove_loops=True) if M.has_edge(u, v, l): M.delete_edge(u, v, l) if M.degree(u): - M.add_edges([(x, y, l) - for x, y in zip(new_vertices[::2], new_vertices[1::2])]) + M.add_edges([(x, y, l) for x, y in zip(new_vertices[::2], new_vertices[1::2])]) else: M.add_edge(u, new_vertices[0], l) M.add_edge(new_vertices[-1], v, l) - M.add_edges([(x, y, l) - for x, y in zip(new_vertices[1::2], new_vertices[2::2])]) + M.add_edges([(x, y, l) for x, y in zip(new_vertices[1::2], new_vertices[2::2])]) self.update_matching(M) @@ -4121,7 +4068,7 @@ def update_matching(self, matching): if any(not self.has_edge(edge) for edge in M.edge_iterator()): raise ValueError("the input is not a matching of the graph") - if (self.order() != M.order()): + if self.order() != M.order(): raise ValueError("the input is not a perfect matching of the graph") self._matching = M.edges() diff --git a/src/sage/graphs/morphisms.py b/src/sage/graphs/morphisms.py index 6921f74d014..6e40895a314 100644 --- a/src/sage/graphs/morphisms.py +++ b/src/sage/graphs/morphisms.py @@ -23,6 +23,7 @@ Methods ------- """ + # **************************************************************************** # Copyright (C) 2025 David Coudert # @@ -34,8 +35,7 @@ # **************************************************************************** -def reduced_homeomorphic_graph(G, allow_multiple_edges=False, allow_loops=False, - return_steps=False, immutable=None): +def reduced_homeomorphic_graph(G, allow_multiple_edges=False, allow_loops=False, return_steps=False, immutable=None): r""" Return the smallest graph homeomorphic to `G`. @@ -180,8 +180,7 @@ def reduced_homeomorphic_graph(G, allow_multiple_edges=False, allow_loops=False, candidates = (u for u, d in G.in_degree_iterator(vertices=out_degree_one, labels=True) if d == 1) def get_neighbors(g, u): - return (next(g.neighbor_in_iterator(u)), - next(g.neighbor_out_iterator(u))) + return (next(g.neighbor_in_iterator(u)), next(g.neighbor_out_iterator(u))) else: from sage.graphs.graph import Graph as MyGraph @@ -203,9 +202,7 @@ def get_neighbors(g, u): return g.neighbors(u) # Copy of the (di)graph with required settings for loops and multiple edges - H = MyGraph([G, G.edge_iterator(labels=False)], format='vertices_and_edges', - multiedges=G.allows_multiple_edges() or allow_multiple_edges, - loops=G.allows_loops() or allow_loops, immutable=False) + H = MyGraph([G, G.edge_iterator(labels=False)], format='vertices_and_edges', multiedges=G.allows_multiple_edges() or allow_multiple_edges, loops=G.allows_loops() or allow_loops, immutable=False) steps = [] for u in candidates: @@ -304,8 +301,7 @@ def is_homeomorphic(G, H): return X.is_isomorphic(Y) -def has_homomorphism_to(G, H, core=False, solver=None, verbose=0, - *, integrality_tolerance=1e-3): +def has_homomorphism_to(G, H, core=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Check whether there is a homomorphism between two graphs. @@ -417,6 +413,7 @@ def has_homomorphism_to(G, H, core=False, solver=None, verbose=0, undirected = not G.is_directed() from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException + p = MixedIntegerLinearProgram(solver=solver, maximization=False) b = p.new_variable(binary=True) diff --git a/src/sage/graphs/orientations.py b/src/sage/graphs/orientations.py index a6cca61a080..7f5d3bc88a4 100644 --- a/src/sage/graphs/orientations.py +++ b/src/sage/graphs/orientations.py @@ -31,6 +31,7 @@ Methods ------- """ + # **************************************************************************** # Copyright (C) 2017 Kolja Knauer # 2017 Petru Valicov @@ -47,8 +48,7 @@ from sage.graphs.digraph import DiGraph -def _initialize_digraph(G, edges, name=None, weighted=None, sparse=None, - data_structure=None, immutable=None, hash_labels=None): +def _initialize_digraph(G, edges, name=None, weighted=None, sparse=None, data_structure=None, immutable=None, hash_labels=None): r""" Helper method to return a directed graph built from ``G``. @@ -140,8 +140,7 @@ def _initialize_digraph(G, edges, name=None, weighted=None, sparse=None, # data_structure is already defined so there is nothing left to do # here. Did the user try to define too much ? if immutable is not None or sparse is not None: - raise ValueError("you cannot define 'immutable' or 'sparse' " - "when 'data_structure' has a value") + raise ValueError("you cannot define 'immutable' or 'sparse' " "when 'data_structure' has a value") # At this point, data_structure is None. elif immutable is True: data_structure = 'static_sparse' @@ -162,6 +161,7 @@ def _initialize_digraph(G, edges, name=None, weighted=None, sparse=None, if data_structure is None: from sage.graphs.base.dense_graph import DenseGraphBackend from sage.graphs.base.sparse_graph import SparseGraphBackend + if isinstance(G._backend, DenseGraphBackend): data_structure = "dense" elif isinstance(G._backend, SparseGraphBackend): @@ -176,15 +176,7 @@ def _initialize_digraph(G, edges, name=None, weighted=None, sparse=None, if hash_labels is None: hash_labels = G._hash_labels - D = DiGraph(data=[G, edges], - format='vertices_and_edges', - data_structure=data_structure, - multiedges=G.allows_multiple_edges(), - loops=G.allows_loops(), - weighted=weighted, - pos=copy(G.get_pos()), - name=name, - hash_labels=hash_labels) + D = DiGraph(data=[G, edges], format='vertices_and_edges', data_structure=data_structure, multiedges=G.allows_multiple_edges(), loops=G.allows_loops(), weighted=weighted, pos=copy(G.get_pos()), name=name, hash_labels=hash_labels) # Copy attributes '_assoc' and '_embedding' if set D._copy_attribute_from(G, '_assoc') @@ -193,8 +185,7 @@ def _initialize_digraph(G, edges, name=None, weighted=None, sparse=None, return D -def orient(G, f, weighted=None, data_structure=None, sparse=None, - immutable=None, hash_labels=None): +def orient(G, f, weighted=None, data_structure=None, sparse=None, immutable=None, hash_labels=None): r""" Return an oriented version of `G` according the input function `f`. @@ -312,9 +303,7 @@ def orient(G, f, weighted=None, data_structure=None, sparse=None, """ edges = (f(e) for e in G.edge_iterator()) name = f"Orientation of {G.name()}" - return _initialize_digraph(G, edges, name=name, weighted=weighted, - data_structure=data_structure, sparse=sparse, - immutable=immutable, hash_labels=hash_labels) + return _initialize_digraph(G, edges, name=name, weighted=weighted, data_structure=data_structure, sparse=sparse, immutable=immutable, hash_labels=hash_labels) def orientations(G, data_structure=None, sparse=None): @@ -434,16 +423,14 @@ def orientations(G, data_structure=None, sparse=None): name = 'An orientation of ' + name if not G.size(): - yield _initialize_digraph(G, [], name=name, - data_structure=data_structure, sparse=sparse) + yield _initialize_digraph(G, [], name=name, data_structure=data_structure, sparse=sparse) return - E = [[(u, v, label), (v, u, label)] if u != v else [(u, v, label)] - for u, v, label in G.edge_iterator()] + E = [[(u, v, label), (v, u, label)] if u != v else [(u, v, label)] for u, v, label in G.edge_iterator()] from itertools import product + for edges in product(*E): - yield _initialize_digraph(G, edges, name=name, - data_structure=data_structure, sparse=sparse) + yield _initialize_digraph(G, edges, name=name, data_structure=data_structure, sparse=sparse) def acyclic_orientations(G): @@ -595,9 +582,9 @@ def order_edges(G, vertex_labels): return edge_labels def is_upset_of_poset(Poset, subset, keys): - for (u, v) in subset: - for (w, x) in keys: - if (Poset[(u, v), (w, x)] == 1 and (w, x) not in subset): + for u, v in subset: + for w, x in keys: + if Poset[(u, v), (w, x)] == 1 and (w, x) not in subset: return False return True @@ -619,10 +606,10 @@ def generate_orientations(globO, starting_of_Ek, m, k, keys): # Process vertices starting from starting_of_Ek new_G.add_vertices([u for u, _ in keys[starting_of_Ek:]] + [v for _, v in keys[starting_of_Ek:]]) - if (globO[(k-1, k)] == 1): + if globO[(k - 1, k)] == 1: new_G.add_edge(k, k - 1) else: - new_G.add_edge(k-1, k) + new_G.add_edge(k - 1, k) for i in range(starting_of_Ek, m - 1): for j in range(starting_of_Ek, m - 1): @@ -634,8 +621,8 @@ def generate_orientations(globO, starting_of_Ek, m, k, keys): # For each subset of the base set of E_k, check if it is an upset or not upsets = [] - for subset in Subsets(keys[starting_of_Ek:m-1]): - if (is_upset_of_poset(Poset, subset, keys[starting_of_Ek:m-1])): + for subset in Subsets(keys[starting_of_Ek : m - 1]): + if is_upset_of_poset(Poset, subset, keys[starting_of_Ek : m - 1]): upsets.append(list(subset)) for upset in upsets: @@ -657,7 +644,7 @@ def helper(G, globO, m, k): return starting_of_Ek = 0 - for (u, v) in keys: + for u, v in keys: if u >= k - 1 or v >= k - 1: break else: @@ -671,15 +658,15 @@ def helper(G, globO, m, k): # For each orientation of G_k-2, yield acyclic orientations for alpha in orientations_G_small: - for (u, v) in alpha: + for u, v in alpha: globO[(u, v)] = alpha[(u, v)] # Orienting H_k as 1 - globO[(k-1, k)] = 1 + globO[(k - 1, k)] = 1 yield from generate_orientations(globO, starting_of_Ek, m, k, keys) # Orienting H_k as 0 - globO[(k-1, k)] = 0 + globO[(k - 1, k)] = 0 yield from generate_orientations(globO, starting_of_Ek, m, k, keys) # Reorder vertices based on the logic in reorder_vertices function @@ -774,6 +761,7 @@ def strong_orientation(G): Multi-digraph on 3 vertices """ from sage.graphs.base.dense_graph import DenseGraphBackend + if isinstance(G._backend, DenseGraphBackend): data_structure = "dense" else: @@ -809,8 +797,7 @@ def strong_orientation(G): # If we discovered a new vertex if seen.get(e[1], False) is False: d.add_edge(e) - next_.extend(ee for ee in G.edges_incident(e[1]) - if ((e[0], e[1]) != (ee[0], ee[1])) and ((e[0], e[1]) != (ee[1], ee[0]))) + next_.extend(ee for ee in G.edges_incident(e[1]) if ((e[0], e[1]) != (ee[0], ee[1])) and ((e[0], e[1]) != (ee[1], ee[0]))) i += 1 seen[e[1]] = i @@ -950,7 +937,7 @@ def strong_orientations_iterator(G): previousWord = 0 # the orientation of one edge is fixed so we consider one edge less - nr = 2**(len(A) - 1) + nr = 2 ** (len(A) - 1) for i in range(nr): word = (i >> 1) ^ i bitChanged = word ^ previousWord @@ -1084,10 +1071,12 @@ def random_orientation(G): - :meth:`~sage.graphs.digraph_generators.DiGraphGenerators.nauty_directg` """ from sage.graphs.graph import Graph + if not isinstance(G, Graph): raise ValueError("the input parameter must be a Graph") from sage.misc.prandom import getrandbits + rbits = getrandbits(G.size()) edges = [] for u, v, l in G.edge_iterator(): @@ -1097,8 +1086,7 @@ def random_orientation(G): return _initialize_digraph(G, edges, name=f"Random orientation of {G.name()}") -def minimum_outdegree_orientation(G, use_edge_labels=False, solver=None, verbose=0, - *, integrality_tolerance=1e-3): +def minimum_outdegree_orientation(G, use_edge_labels=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Return an orientation of `G` with the smallest possible maximum outdegree. @@ -1169,8 +1157,7 @@ def minimum_outdegree_orientation(G, use_edge_labels=False, solver=None, verbose """ G._scream_if_not_simple() if G.is_directed(): - raise ValueError("Cannot compute an orientation of a DiGraph. " - "Please convert it to a Graph if you really mean it.") + raise ValueError("Cannot compute an orientation of a DiGraph. " "Please convert it to a Graph if you really mean it.") if use_edge_labels: from sage.rings.real_mpfr import RR @@ -1178,7 +1165,9 @@ def minimum_outdegree_orientation(G, use_edge_labels=False, solver=None, verbose def weight(e): label = G.edge_label(e[0], e[1]) return label if label in RR else 1 + else: + def weight(e): return 1 @@ -1201,9 +1190,7 @@ def outgoing(u, e, variable): return 1 - variable for u in G: - p.add_constraint(p.sum(weight(e) * outgoing(u, e, orientation[frozenset(e)]) - for e in G.edge_iterator(vertices=[u], labels=False)) - - degree['max'], max=0) + p.add_constraint(p.sum(weight(e) * outgoing(u, e, orientation[frozenset(e)]) for e in G.edge_iterator(vertices=[u], labels=False)) - degree['max'], max=0) p.set_objective(degree['max']) @@ -1215,8 +1202,7 @@ def outgoing(u, e, variable): return G.orient(lambda e: e if orientation[frozenset(e[:2])] else (e[1], e[0], e[2])) -def bounded_outdegree_orientation(G, bound, solver=None, verbose=False, - *, integrality_tolerance=1e-3): +def bounded_outdegree_orientation(G, bound, solver=None, verbose=False, *, integrality_tolerance=1e-3): r""" Return an orientation of `G` such that every vertex `v` has out-degree less than `b(v)`. @@ -1352,15 +1338,14 @@ def bounded_outdegree_orientation(G, bound, solver=None, verbose=False, try: b = dict(zip(vertices, map(bound, vertices))) except TypeError: - b = dict(zip(vertices, [bound]*n)) + b = dict(zip(vertices, [bound] * n)) d = DiGraph() # Adding the edges (s,v) and ((u,v),t) d.add_edges(('s', vertices_id[v], b[v]) for v in vertices) - d.add_edges(((vertices_id[u], vertices_id[v]), 't', 1) - for u, v in G.edges(sort=False, labels=None)) + d.add_edges(((vertices_id[u], vertices_id[v]), 't', 1) for u, v in G.edges(sort=False, labels=None)) # each v is linked to its incident edges @@ -1370,18 +1355,14 @@ def bounded_outdegree_orientation(G, bound, solver=None, verbose=False, d.add_edge(v, (u, v), 1) # Solving the maximum flow - value, flow = d.flow('s', 't', value_only=False, integer=True, - use_edge_labels=True, solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + value, flow = d.flow('s', 't', value_only=False, integer=True, use_edge_labels=True, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) if value != G.size(): raise ValueError("No orientation exists for the given bound") # The flow graph may not contain all the vertices, if they are # not part of the flow... - edges = ((vertices[u], vertices[vv if vv != u else uu]) - for u in range(n) if u in flow - for uu, vv in flow.neighbors_out(u)) + edges = ((vertices[u], vertices[vv if vv != u else uu]) for u in range(n) if u in flow for uu, vv in flow.neighbors_out(u)) return _initialize_digraph(G, edges) diff --git a/src/sage/graphs/partial_cube.py b/src/sage/graphs/partial_cube.py index b097cf73235..6638f2438e6 100644 --- a/src/sage/graphs/partial_cube.py +++ b/src/sage/graphs/partial_cube.py @@ -298,6 +298,7 @@ def is_partial_cube(G, certificate=False): from sage.graphs.digraph import DiGraph from sage.graphs.graph import Graph from sage.sets.disjoint_set import DisjointSet + contracted = DiGraph({v: {w: (v, w) for w in G[v]} for v in G}) unionfind = DisjointSet(contracted.edges(sort=True, labels=False)) available = n - 1 @@ -328,14 +329,12 @@ def is_partial_cube(G, certificate=False): for v, w in contracted.edge_iterator(labels=False): diff = bitvec[v] ^ bitvec[w] if not diff or not bitvec[w] & ~bitvec[v]: - continue # zero edge or wrong direction + continue # zero edge or wrong direction if diff not in neighbors: return fail neighbor = neighbors[diff] - unionfind.union(contracted.edge_label(v, w), - contracted.edge_label(root, neighbor)) - unionfind.union(contracted.edge_label(w, v), - contracted.edge_label(neighbor, root)) + unionfind.union(contracted.edge_label(v, w), contracted.edge_label(root, neighbor)) + unionfind.union(contracted.edge_label(w, v), contracted.edge_label(neighbor, root)) labeled.add_edge(v, w) # Map vertices to components of labeled-edge graph @@ -402,8 +401,7 @@ def scan(v): """ Find the next token that is effective for v. """ - a = next(i for i in range(state_to_active_token[v] + 1, len(activeTokens)) - if activeTokens[i] is not None and activeTokens[i] in action[v]) + a = next(i for i in range(state_to_active_token[v] + 1, len(activeTokens)) if activeTokens[i] is not None and activeTokens[i] in action[v]) state_to_active_token[v] = a token_to_states[a].append(v) diff --git a/src/sage/graphs/pq_trees.py b/src/sage/graphs/pq_trees.py index 92d0f7966ba..270ff3fada1 100644 --- a/src/sage/graphs/pq_trees.py +++ b/src/sage/graphs/pq_trees.py @@ -131,6 +131,7 @@ # defined in class PQ # ########################################################################## + def _set_contiguous(tree, x): """ Helper function for updating ``tree``. @@ -467,9 +468,7 @@ def simplify(self, v, left=False, right=False): if isinstance(self, Q): L = [] for c in self._children: - if (isinstance(c, PQ) and # Is c partial? - v in c and # (does c contain sets with - any(v not in cc for cc in c)): # and without v ?) + if isinstance(c, PQ) and v in c and any(v not in cc for cc in c): # Is c partial? # (does c contain sets with # and without v ?) L.extend(c.simplify(v, right=right, left=left)) else: L.append(c) @@ -480,8 +479,7 @@ def simplify(self, v, left=False, right=False): for c in self._children: if v in c: - if (isinstance(c, PQ) and # Is c partial? (does c contain - any(v not in cc for cc in c)): # sets with and without v ?) + if isinstance(c, PQ) and any(v not in cc for cc in c): # Is c partial? (does c contain # sets with and without v ?) partial = c.simplify(v, right=right, left=left) else: full.append(c) @@ -524,6 +522,7 @@ class P(PQ): For more information, see the documentation of :mod:`sage.graphs.pq_trees`. """ + def set_contiguous(self, v): r""" Update ``self`` so that the sets containing ``v`` are @@ -603,12 +602,7 @@ def set_contiguous(self, v): set_PARTIAL_ALIGNED = [] set_PARTIAL_UNALIGNED = [] - sorting = { - (FULL, ALIGNED): set_FULL, - (EMPTY, ALIGNED): set_EMPTY, - (PARTIAL, ALIGNED): set_PARTIAL_ALIGNED, - (PARTIAL, UNALIGNED): set_PARTIAL_UNALIGNED - } + sorting = {(FULL, ALIGNED): set_FULL, (EMPTY, ALIGNED): set_EMPTY, (PARTIAL, ALIGNED): set_PARTIAL_ALIGNED, (PARTIAL, UNALIGNED): set_PARTIAL_UNALIGNED} for i in self: sorting[f_seq[i]].append(i) @@ -621,8 +615,7 @@ def set_contiguous(self, v): # Excludes the situation where there is no solution. # read next comment for more explanations - if (n_PARTIAL_ALIGNED > 2 or - (n_PARTIAL_UNALIGNED >= 1 and n_EMPTY != self.number_of_children() - 1)): + if n_PARTIAL_ALIGNED > 2 or (n_PARTIAL_UNALIGNED >= 1 and n_EMPTY != self.number_of_children() - 1): raise ValueError(impossible_msg) # From now on, there are at most two pq-trees which are partially filled @@ -652,8 +645,7 @@ def set_contiguous(self, v): # If there is just one partial element and all the others are # empty, we just reorder the set to put it at the right end - elif (n_PARTIAL_ALIGNED == 1 and - n_EMPTY == self.number_of_children()-1): + elif n_PARTIAL_ALIGNED == 1 and n_EMPTY == self.number_of_children() - 1: self._children = set_EMPTY + set_PARTIAL_ALIGNED return (PARTIAL, ALIGNED) @@ -763,10 +755,11 @@ def cardinality(self): 1440 """ from math import factorial + n = factorial(self.number_of_children()) for c in self._children: if isinstance(c, PQ): - n = n*c.cardinality() + n = n * c.cardinality() return n def orderings(self): @@ -790,9 +783,9 @@ def orderings(self): ... """ from itertools import permutations, product + for p in permutations(self._children): - yield from product(*[x.orderings() if isinstance(x, PQ) else [x] - for x in p]) + yield from product(*[x.orderings() if isinstance(x, PQ) else [x] for x in p]) class Q(PQ): @@ -886,12 +879,7 @@ def set_contiguous(self, v): set_PARTIAL_ALIGNED = [] set_PARTIAL_UNALIGNED = [] - sorting = { - (FULL, ALIGNED): set_FULL, - (EMPTY, ALIGNED): set_EMPTY, - (PARTIAL, ALIGNED): set_PARTIAL_ALIGNED, - (PARTIAL, UNALIGNED): set_PARTIAL_UNALIGNED - } + sorting = {(FULL, ALIGNED): set_FULL, (EMPTY, ALIGNED): set_EMPTY, (PARTIAL, ALIGNED): set_PARTIAL_ALIGNED, (PARTIAL, UNALIGNED): set_PARTIAL_UNALIGNED} for i in self: sorting[f_seq[i]].append(i) @@ -921,9 +909,7 @@ def set_contiguous(self, v): # others are full # ################################################################### - if (f_seq[self._children[-1]] == (EMPTY, ALIGNED) or - (f_seq[self._children[-1]] == (PARTIAL, ALIGNED) and - n_FULL == self.number_of_children() - 1)): + if f_seq[self._children[-1]] == (EMPTY, ALIGNED) or (f_seq[self._children[-1]] == (PARTIAL, ALIGNED) and n_FULL == self.number_of_children() - 1): # We reverse the order of the elements in the SET only. # Which means that they are still aligned to the right ! self._children.reverse() @@ -938,9 +924,7 @@ def set_contiguous(self, v): # Excludes the situation where there is no solution. # read next comment for more explanations - if (n_PARTIAL_ALIGNED > 2 or - (n_PARTIAL_UNALIGNED >= 1 and - n_EMPTY != self.number_of_children() - 1)): + if n_PARTIAL_ALIGNED > 2 or (n_PARTIAL_UNALIGNED >= 1 and n_EMPTY != self.number_of_children() - 1): raise ValueError(impossible_msg) # From now on, there are at most two pq-trees which are partially filled @@ -962,8 +946,7 @@ def set_contiguous(self, v): # and all the others are empty, we just reorder # the set to put it at the right end - elif (n_PARTIAL_ALIGNED == 1 and - n_EMPTY == self.number_of_children() - 1): + elif n_PARTIAL_ALIGNED == 1 and n_EMPTY == self.number_of_children() - 1: if set_PARTIAL_ALIGNED[0] == self._children[-1]: return (PARTIAL, ALIGNED) @@ -1091,9 +1074,9 @@ def cardinality(self): n = 1 for c in self._children: if isinstance(c, PQ): - n = n*c.cardinality() + n = n * c.cardinality() - return n if (self.number_of_children() == 1) else 2*n + return n if (self.number_of_children() == 1) else 2 * n def orderings(self): r""" @@ -1117,7 +1100,7 @@ def orderings(self): yield from (c.orderings() if isinstance(c, PQ) else [c]) else: from itertools import product - for o in product(*[x.orderings() if isinstance(x, PQ) else [x] - for x in self._children]): + + for o in product(*[x.orderings() if isinstance(x, PQ) else [x] for x in self._children]): yield o yield o[::-1] diff --git a/src/sage/graphs/print_graphs.py b/src/sage/graphs/print_graphs.py index 80acb3970cf..ede761af702 100644 --- a/src/sage/graphs/print_graphs.py +++ b/src/sage/graphs/print_graphs.py @@ -135,11 +135,11 @@ def print_graph_ps(vert_ls, edge_iter, pos_dict): for v in vert_ls: x, y = pos_dict[v] - pos_dict[v] = int(floor(50*x))+50, int(floor(50*y))+50 + pos_dict[v] = int(floor(50 * x)) + 50, int(floor(50 * y)) + 50 x, y = pos_dict[v] s += "%s %s point\n" % (x, y) - for (u, v, l) in edge_iter: + for u, v, l in edge_iter: ux, uy = pos_dict[u] vx, vy = pos_dict[v] s += "%s %s %s %s edge\n" % (ux, uy, vx, vy) @@ -185,11 +185,11 @@ def print_graph_eps(vert_ls, edge_iter, pos_dict): for v in vert_ls: x, y = pos_dict[v] - pos_dict[v] = int(floor(50*x)) + 50, int(floor(50*y)) + 50 + pos_dict[v] = int(floor(50 * x)) + 50, int(floor(50 * y)) + 50 x, y = pos_dict[v] s += "%s %s point\n" % (x, y) - for (u, v, l) in edge_iter: + for u, v, l in edge_iter: ux, uy = pos_dict[u] vx, vy = pos_dict[v] s += "%s %s %s %s edge\n" % (ux, uy, vx, vy) diff --git a/src/sage/graphs/schnyder.py b/src/sage/graphs/schnyder.py index fc4e76e917f..8c7aefca306 100644 --- a/src/sage/graphs/schnyder.py +++ b/src/sage/graphs/schnyder.py @@ -9,6 +9,7 @@ - Jonathan Bober, Emily Kirkman (2008-02-09) -- initial version """ + # **************************************************************************** # Copyright (C) 2008 Jonathan Bober and Emily Kirkman # @@ -94,7 +95,7 @@ def _triangulate(g, comb_emb): faces = g.faces(comb_emb) # We start by finding all of the faces of this embedding. - edges_added = [] # The list of edges that we add to the graph. + edges_added = [] # The list of edges that we add to the graph. # This will be returned at the end. for face in faces: @@ -119,7 +120,7 @@ def _triangulate(g, comb_emb): new_edge = (face[i + 1][1], face[i][0]) # new_edge is from third vertex in face to first if g.has_edge(new_edge) or new_edge[0] == new_edge[1]: # check for repeats new_face.append(face[i]) # if repeated, keep first edge in face instead - if i == N - 2: # if we are two from the end, found a triangle already + if i == N - 2: # if we are two from the end, found a triangle already break i += 1 continue @@ -185,9 +186,7 @@ def _normal_label(g, comb_emb, external_face): # For now we will not take the order of the outer face into account. # We will correct this in the end of this function. - external_vertices = sorted([external_face[0][0], - external_face[1][0], - external_face[2][0]]) + external_vertices = sorted([external_face[0][0], external_face[1][0], external_face[2][0]]) v1, v2, v3 = external_vertices v1_neighbors = Set(g.neighbors(v1)) @@ -211,8 +210,7 @@ def _normal_label(g, comb_emb, external_face): # going to contract v v_neighbors = Set(g.neighbors(v)) - contracted.append((v, v_neighbors, - v_neighbors - v1_neighbors - Set([v1]))) + contracted.append((v, v_neighbors, v_neighbors - v1_neighbors - Set([v1]))) g.delete_vertex(v) v1_neighbors -= Set([v]) for w in v_neighbors - v1_neighbors - Set([v1]): @@ -223,8 +221,7 @@ def _normal_label(g, comb_emb, external_face): v1_neighbors += v_neighbors - Set([v1]) contractible = [] for w in g.neighbors(v1): - if (len(v1_neighbors.intersection(Set(g.neighbors(w)))) == 2 - and w not in [v1, v2, v3]): + if len(v1_neighbors.intersection(Set(g.neighbors(w)))) == 2 and w not in [v1, v2, v3]: contractible.append(w) # expansion phase: @@ -247,9 +244,7 @@ def _normal_label(g, comb_emb, external_face): # we are adding v into the face new_neighbors w1, w2, w3 = sorted(new_neighbors) - labels[v] = {(w1, w2): labels[w3].pop((w1, w2)), - (w2, w3): labels[w1].pop((w2, w3)), - (w1, w3): labels[w2].pop((w1, w3))} + labels[v] = {(w1, w2): labels[w3].pop((w1, w2)), (w2, w3): labels[w1].pop((w2, w3)), (w1, w3): labels[w2].pop((w1, w3))} labels[w1][tuple(sorted((w2, v)))] = labels[v][(w2, w3)] labels[w1][tuple(sorted((w3, v)))] = labels[v][(w2, w3)] @@ -402,9 +397,7 @@ def _realizer(g, x, example=False): tree_nodes = {} for v in g: - tree_nodes[v] = [TreeNode(label=v, children=[]), - TreeNode(label=v, children=[]), - TreeNode(label=v, children=[])] + tree_nodes[v] = [TreeNode(label=v, children=[]), TreeNode(label=v, children=[]), TreeNode(label=v, children=[])] for v in g: ones = [] @@ -579,6 +572,7 @@ class TreeNode: sage: tn3.depth 2 """ + def __init__(self, parent=None, children=None, label=None): """ INPUT: @@ -815,17 +809,15 @@ def minimal_schnyder_wood(graph, root_edge=None, minimal=True, check=True): path = list(emb[c]) idxa = path.index(a) path = path[idxa:] + path[:idxa] - neighbors_in_path = {i: len([u for u in graph.neighbors(i) if u in path]) - for i in graph} - removable_nodes = [u for u in path if neighbors_in_path[u] == 2 and - u != a and u != b] + neighbors_in_path = {i: len([u for u in graph.neighbors(i) if u in path]) for i in graph} + removable_nodes = [u for u in path if neighbors_in_path[u] == 2 and u != a and u != b] # iterated path shortening while len(path) > 2: if minimal: - v = removable_nodes[-1] # node to be removed from path + v = removable_nodes[-1] # node to be removed from path else: - v = removable_nodes[0] # node to be removed from path + v = removable_nodes[0] # node to be removed from path idx_v = path.index(v) left = path[idx_v - 1] new_g.add_edge((v, left, 'green')) @@ -837,7 +829,7 @@ def minimal_schnyder_wood(graph, root_edge=None, minimal=True, check=True): idx_right = neighbors_v.index(right) inside = neighbors_v[1:idx_right] new_g.add_edges([(w, v, 'red') for w in inside]) - path = path[:idx_v] + inside + path[idx_v + 1:] + path = path[:idx_v] + inside + path[idx_v + 1 :] # updating the table of neighbors_in_path for w in inside: for x in graph.neighbors(w): @@ -845,8 +837,7 @@ def minimal_schnyder_wood(graph, root_edge=None, minimal=True, check=True): for x in graph.neighbors(v): neighbors_in_path[x] -= 1 # updating removable nodes - removable_nodes = [u for u in path if neighbors_in_path[u] == 2 and - u != a and u != b] + removable_nodes = [u for u in path if neighbors_in_path[u] == 2 and u != a and u != b] def relabel(w): return -3 if w == c else w @@ -857,7 +848,7 @@ def relabel(w): if idx == 0: emb[u] = emb[u][1:-1] else: - emb[u] = emb[u][idx+1:] + emb[u][:idx-1] + emb[u] = emb[u][idx + 1 :] + emb[u][: idx - 1] new_g.set_embedding(emb) return new_g diff --git a/src/sage/graphs/tests/is_projective_planar_test.py b/src/sage/graphs/tests/is_projective_planar_test.py index 5f28e3465a8..e8b39f48e0f 100644 --- a/src/sage/graphs/tests/is_projective_planar_test.py +++ b/src/sage/graphs/tests/is_projective_planar_test.py @@ -7,6 +7,7 @@ def test_petersen_graph_is_projective_planar(): using the cache. """ from sage.graphs.generators.smallgraphs import PetersenGraph + P = PetersenGraph() P.is_projective_planar.clear_cache() assert not P.is_projective_planar.is_in_cache() diff --git a/src/sage/graphs/tutte_polynomial.py b/src/sage/graphs/tutte_polynomial.py index 5ef746309a5..0e2e214e7bd 100644 --- a/src/sage/graphs/tutte_polynomial.py +++ b/src/sage/graphs/tutte_polynomial.py @@ -189,6 +189,7 @@ def underlying_graph(G): [(0, 1, None)] """ from sage.graphs.graph import Graph + g = Graph() g.allow_loops(True) for edge in set(G.edges(sort=False, labels=False)): @@ -213,6 +214,7 @@ def edge_multiplicities(G): d[edge] = d.setdefault(edge, 0) + 1 return d + ######## # Ears # ######## @@ -233,6 +235,7 @@ class Ear: INPUT: """ + def __init__(self, graph, end_points, interior, is_cycle): """ EXAMPLES:: @@ -313,9 +316,7 @@ def find_ear(g): sage: E.vertices [0, 1, 2, 3] """ - degree_two_vertices = [v for v, degree - in g.degree_iterator(labels=True) - if degree == 2] + degree_two_vertices = [v for v, degree in g.degree_iterator(labels=True) if degree == 2] subgraph = g.subgraph(degree_two_vertices) for component in subgraph.connected_components(sort=False): edges = g.edges_incident(vertices=component, labels=True) @@ -367,6 +368,7 @@ def removed_from(self, G): for edge in deleted_edges: G.add_edge(edge) + ################## # Edge Selection # ################## @@ -496,6 +498,7 @@ def _cached(func): sage: tutte_polynomial(G)(1,1) #indirect doctest 2000 """ + @sage_wraps(func) def wrapper(G, *args, **kwds): cache = kwds.setdefault('cache', {}) @@ -505,6 +508,7 @@ def wrapper(G, *args, **kwds): result = func(G, *args, **kwds) cache[key] = result return result + wrapper.original_func = func return wrapper @@ -513,6 +517,7 @@ def wrapper(G, *args, **kwds): # Tutte Polynomial # #################### + @_cached def tutte_polynomial(G, edge_selector=None, cache=None): r""" @@ -630,18 +635,18 @@ def recursive_tp(graph=None): # Remove loops with removed_loops(G) as loops: if loops: - return y**len(loops) * recursive_tp() + return y ** len(loops) * recursive_tp() uG = underlying_graph(G) em = edge_multiplicities(G) d = list(em.values()) def yy(start, end): - return sum(y**i for i in range(start, end+1)) + return sum(y**i for i in range(start, end + 1)) # Lemma 1 if G.is_forest(): - return prod(x + yy(1, d_i-1) for d_i in d) + return prod(x + yy(1, d_i - 1) for d_i in d) # Theorem 1: from Haggard, Pearce, Royle 2008 blocks, cut_vertices = G.blocks_and_cut_vertices() @@ -655,7 +660,7 @@ def yy(start, end): with removed_edge(G, edge): if G.number_of_connected_components() > components: with contracted_edge(G, unlabeled_edge): - return x*recursive_tp() + return x * recursive_tp() ################################## # We are in the biconnected case # @@ -671,32 +676,26 @@ def yy(start, end): n = len(d) result = 0 for i in range(n - 2): - term = (prod((x + yy(1, d_j-1)) for d_j in d[i+1:]) * - prod((yy(0, d_k-1)) for d_k in d[:i])) + term = prod((x + yy(1, d_j - 1)) for d_j in d[i + 1 :]) * prod((yy(0, d_k - 1)) for d_k in d[:i]) result += term # The last part of the recursion - result += (x + yy(1, d[-1] + d[-2] - 1))*prod(yy(0, d_i-1) - for d_i in d[:-2]) + result += (x + yy(1, d[-1] + d[-2] - 1)) * prod(yy(0, d_i - 1) for d_i in d[:-2]) return result # Theorem 3 from Haggard, Pearce, and Royle, adapted to multi-ears ear = Ear.find_ear(uG) if ear is not None: - if (ear.is_cycle and ear.vertices == G.vertices(sort=True)): + if ear.is_cycle and ear.vertices == G.vertices(sort=True): # The graph is an ear (cycle) We should never be in this # case since we check for multi-cycles above return y + sum(x**i for i in range(1, ear.s)) with ear.removed_from(G): # result = sum(x^i for i in range(ear.s)) #single ear case - result = sum((prod(x + yy(1, em[e]-1) for e in ear.unlabeled_edges[i+1:]) - * prod(yy(0, em[e]-1) for e in ear.unlabeled_edges[:i])) - for i in range(len(ear.unlabeled_edges))) + result = sum((prod(x + yy(1, em[e] - 1) for e in ear.unlabeled_edges[i + 1 :]) * prod(yy(0, em[e] - 1) for e in ear.unlabeled_edges[:i])) for i in range(len(ear.unlabeled_edges))) result *= recursive_tp() - with contracted_edge(G, [ear.end_points[0], - ear.end_points[-1]]): - result += prod(yy(0, em[e]-1) - for e in ear.unlabeled_edges)*recursive_tp() + with contracted_edge(G, [ear.end_points[0], ear.end_points[-1]]): + result += prod(yy(0, em[e] - 1) for e in ear.unlabeled_edges) * recursive_tp() return result @@ -706,5 +705,5 @@ def yy(start, end): with removed_multiedge(G, unlabeled_edge): result = recursive_tp() with contracted_edge(G, unlabeled_edge): - result += sum(y**i for i in range(em[unlabeled_edge]))*recursive_tp() + result += sum(y**i for i in range(em[unlabeled_edge])) * recursive_tp() return result diff --git a/src/sage/groups/abelian_gps/abelian_aut.py b/src/sage/groups/abelian_gps/abelian_aut.py index c58eebc4b4f..32ac2bd056a 100644 --- a/src/sage/groups/abelian_gps/abelian_aut.py +++ b/src/sage/groups/abelian_gps/abelian_aut.py @@ -103,6 +103,7 @@ class AbelianGroupAutomorphism(ElementLibGAP): sage: G = AbelianGroupGap([2,3,4,5]) sage: f = G.aut().an_element() """ + def __init__(self, parent, x, check=True): """ The Python constructor. @@ -206,10 +207,7 @@ def matrix(self): return m -class AbelianGroupAutomorphismGroup_gap(CachedRepresentation, - GroupMixinLibGAP, - Group, - ParentLibGAP): +class AbelianGroupAutomorphismGroup_gap(CachedRepresentation, GroupMixinLibGAP, Group, ParentLibGAP): r""" Base class for groups of automorphisms of abelian groups. @@ -233,6 +231,7 @@ class AbelianGroupAutomorphismGroup_gap(CachedRepresentation, sage: AbelianGroupAutomorphismGroup_gap(domain, aut, Groups().Finite()) """ + Element = AbelianGroupAutomorphism def __init__(self, domain, gap_group, category, ambient=None): @@ -289,6 +288,7 @@ def _element_constructor_(self, x, check=True): images = [dom(row).gap() for row in x.rows()] x = dom.gap().GroupHomomorphismByImages(dom.gap(), images) from sage.modules.fg_pid.fgp_morphism import FGP_Morphism + if isinstance(x, FGP_Morphism): if x.base_ring() != ZZ: raise ValueError("base ring must be ZZ") @@ -431,6 +431,7 @@ class AbelianGroupAutomorphismGroup(AbelianGroupAutomorphismGroup_gap): sage: aut is aut1 True """ + Element = AbelianGroupAutomorphism def __init__(self, AbelianGroupGap): @@ -451,11 +452,7 @@ def __init__(self, AbelianGroupGap): raise ValueError("only finite abelian groups are supported") category = Groups().Finite().Enumerated() G = libgap.AutomorphismGroup(self._domain.gap()) - AbelianGroupAutomorphismGroup_gap.__init__(self, - self._domain, - gap_group=G, - category=category, - ambient=None) + AbelianGroupAutomorphismGroup_gap.__init__(self, self._domain, gap_group=G, category=category, ambient=None) def _repr_(self): r""" @@ -497,6 +494,7 @@ class AbelianGroupAutomorphismGroup_subgroup(AbelianGroupAutomorphismGroup_gap): Subgroup of automorphisms of Abelian group with gap, generator orders (2, 3, 4, 5) generated by 6 automorphisms """ + Element = AbelianGroupAutomorphism def __init__(self, ambient, generators): @@ -516,11 +514,7 @@ def __init__(self, ambient, generators): generators = tuple([g.gap() for g in generators]) H = ambient.gap().Subgroup(generators) category = Groups().Finite().Enumerated() - AbelianGroupAutomorphismGroup_gap.__init__(self, - self._domain, - gap_group=H, - category=category, - ambient=ambient) + AbelianGroupAutomorphismGroup_gap.__init__(self, self._domain, gap_group=H, category=category, ambient=ambient) self._covering_matrix_ring = ambient._covering_matrix_ring def _repr_(self): @@ -535,5 +529,4 @@ def _repr_(self): sage: f = aut.an_element() sage: sub = aut.subgroup([f]) """ - return "Subgroup of automorphisms of %s \n generated by %s automorphisms" % ( - self.domain(), len(self.gens())) + return "Subgroup of automorphisms of %s \n generated by %s automorphisms" % (self.domain(), len(self.gens())) diff --git a/src/sage/groups/abelian_gps/abelian_group.py b/src/sage/groups/abelian_gps/abelian_group.py index f455b178644..69c67bd4a98 100644 --- a/src/sage/groups/abelian_gps/abelian_group.py +++ b/src/sage/groups/abelian_gps/abelian_group.py @@ -223,6 +223,7 @@ # .. TODO:: + # this uses perm groups - the AbelianGroupElement instance method # uses a different implementation. def word_problem(words, g, verbose=False): @@ -303,13 +304,13 @@ def word_problem(words, g, verbose=False): 'PreImagesRepresentative') and may be faster. """ from sage.libs.gap.libgap import libgap + A = libgap.AbelianGroup(g.parent().gens_orders()) gens = libgap.GeneratorsOfGroup(A) gap_g = libgap.Product([gi**Li for gi, Li in zip(gens, g.list())]) - gensH = [libgap.Product([gi**Li for gi, Li in zip(gens, w.list())]) - for w in words] + gensH = [libgap.Product([gi**Li for gi, Li in zip(gens, w.list())]) for w in words] H = libgap.Group(gensH) x = libgap.Factorization(H, gap_g) @@ -318,8 +319,7 @@ def word_problem(words, g, verbose=False): indices = resu[0::2] powers = resu[1::2] if verbose: - v = '*'.join('(%s)^%s' % (words[indi - 1], powi) - for indi, powi in zip(indices, powers)) + v = '*'.join('(%s)^%s' % (words[indi - 1], powi) for indi, powi in zip(indices, powers)) print('%s = %s' % (g, v)) return [[words[indi - 1], powi] for indi, powi in zip(indices, powers)] @@ -386,7 +386,7 @@ def _normalize(n, gens_orders=None, names='f'): if any(i < 0 for i in gens_orders): raise ValueError(f'orders of generators cannot be negative but they are {gens_orders}') if len(gens_orders) > n: - raise ValueError('gens_orders (='+str(gens_orders)+') must have length n (='+str(n)+')') + raise ValueError('gens_orders (=' + str(gens_orders) + ') must have length n (=' + str(n) + ')') if isinstance(names, list): names = tuple(names) return (gens_orders, names) @@ -508,6 +508,7 @@ class AbelianGroup_class(UniqueRepresentation, AbelianGroupBase): sage: AbelianGroup(0).gens_orders() () """ + Element = AbelianGroupElement def __init__(self, generator_orders, names, category=None): @@ -696,10 +697,12 @@ def dual_group(self, names='X', base_ring=None): ValueError: group must be finite """ from sage.groups.abelian_gps.dual_abelian_group import DualAbelianGroup_class + if not self.is_finite(): raise ValueError('group must be finite') if base_ring is None: from sage.rings.number_field.number_field import CyclotomicField + base_ring = CyclotomicField(lcm(self.gens_orders())) return DualAbelianGroup_class(self, names=names, base_ring=base_ring) @@ -750,6 +753,7 @@ def elementary_divisors(self): (60,) """ from sage.matrix.constructor import diagonal_matrix + ed = diagonal_matrix(ZZ, self.gens_orders()).elementary_divisors() return tuple(d for d in ed if d != 1) @@ -823,8 +827,7 @@ def _latex_(self): sage: F._latex_() '$\\mathrm{AbelianGroup}( 10, (2, 2, 2, 2, 2, 2, 2, 2, 2, 2) )$' """ - return r"$\mathrm{AbelianGroup}( %s, %s )$" % (self.ngens(), - self.gens_orders()) + return r"$\mathrm{AbelianGroup}( %s, %s )$" % (self.ngens(), self.gens_orders()) @cached_method def _libgap_(self): @@ -855,6 +858,7 @@ def _libgap_(self): # Make sure to LoadPackage("Polycyclic") in gap from sage.features.gap import GapPackage + GapPackage("polycyclic", spkg='gap_packages').require() return libgap.AbelianPcpGroup(self.gens_orders()) @@ -881,6 +885,7 @@ def _gap_init_(self) -> str: return 'AbelianGroup(%s)' % list(self.gens_orders()) from sage.features.gap import GapPackage + # Make sure to LoadPackage("Polycyclic") in gap GapPackage("polycyclic", spkg='gap_packages').require() return 'AbelianPcpGroup(%s)' % list(self.gens_orders()) @@ -905,8 +910,8 @@ def gen(self, i=0): """ n = self.ngens() if i < 0 or i >= n: - raise IndexError("Argument i (= %s) must be between 0 and %s." % (i, n-1)) - x = [0]*n + raise IndexError("Argument i (= %s) must be between 0 and %s." % (i, n - 1)) + x = [0] * n if self._gens_orders[i] != 1: x[i] = 1 return self.element_class(self, x) @@ -1123,6 +1128,7 @@ def permutation_group(self): if not self.is_finite(): raise TypeError('Abelian group must be finite') from sage.groups.perm_gps.permgroup import PermutationGroup + s = 'Image(IsomorphismPermGroup(%s))' % self._gap_init_() return PermutationGroup(gap_group=s) @@ -1151,12 +1157,13 @@ def random_element(self): True """ from sage.misc.prandom import randint + result = self.one() for g in self.gens(): order = g.order() if order is infinity: order = 42 # infinite order; randomly chosen maximum - result *= g ** randint(0, order-1) + result *= g ** randint(0, order - 1) return result def _repr_(self) -> str: @@ -1302,8 +1309,8 @@ def __iter__(self): # A similar approach works for infinite groups. # (This would also work for finite groups, but is more complicated.) from sage.misc.mrange import cantor_product - yield from map(self, cantor_product(*[range(n) if n - else ZZ for n in invs])) + + yield from map(self, cantor_product(*[range(n) if n else ZZ for n in invs])) def number_of_subgroups(self, order=None): r""" @@ -1379,8 +1386,7 @@ def number_of_subgroups(self, order=None): from sage.combinat.integer_lists import IntegerListsLex # The group order is prod(p^e for (p,e) in primary_factors) - primary_factors = list(chain.from_iterable( - factor(ed) for ed in self.elementary_divisors())) + primary_factors = list(chain.from_iterable(factor(ed) for ed in self.elementary_divisors())) sylow_types = defaultdict(list) for p, e in primary_factors: sylow_types[p].append(e) @@ -1397,7 +1403,7 @@ def number_of_subgroups(self, order=None): return Integer(0) order_exps = dict(factor(order)) - for p in (set(sylow_types) - set(order_exps)): + for p in set(sylow_types) - set(order_exps): del sylow_types[p] for p in sylow_types: subgroups_orders_kwds[p] = {'n': order_exps[p]} @@ -1407,13 +1413,7 @@ def number_of_subgroups(self, order=None): p_exps.sort(reverse=True) # The sum is over all partitions mu contained in p_exps whose size # is determined by subgroups_orders_kwds. - result *= sum(q_subgroups_of_abelian_group(p_exps, mu, q=p) - for mu in IntegerListsLex(max_slope=0, - min_part=1, - max_length=len(p_exps), - ceiling=p_exps, - element_constructor=list, - **subgroups_orders_kwds[p])) + result *= sum(q_subgroups_of_abelian_group(p_exps, mu, q=p) for mu in IntegerListsLex(max_slope=0, min_part=1, max_length=len(p_exps), ceiling=p_exps, element_constructor=list, **subgroups_orders_kwds[p])) return result def subgroups(self, check=False): @@ -1479,7 +1479,7 @@ def subgroups(self, check=False): return [self] if self.ngens() == 1: n = self.gen(0).order() - return [self.subgroup([self.gen(0)**i]) for i in divisors(n)] + return [self.subgroup([self.gen(0) ** i]) for i in divisors(n)] v = self.gens_orders() A = AbelianGroup(v[:-1]) @@ -1494,8 +1494,7 @@ def subgroups(self, check=False): verbose("invariants are: %s" % [t.order() for t in G.gens()]) for H in divisors(x): # H = the subgroup of *index* H. - its = [range(0, H, H // gcd(H, G.gen(i).order())) - for i in range(ngens)] + its = [range(0, H, H // gcd(H, G.gen(i).order())) for i in range(ngens)] for f in product(*its): verbose("using hom from G to C_%s sending gens to %s" % (H, f)) new_sub = [] @@ -1510,6 +1509,7 @@ def subgroups(self, check=False): if check: verbose("Running Gap cross-check") from sage.libs.gap.libgap import libgap + t = libgap(v).AbelianGroup().SubgroupsSolvableGroup().Size().sage() if t != len(subgps): raise ArithmeticError("For %s Gap finds %s subgroups, I found %s" % (v, t, len(subgps))) @@ -1539,6 +1539,7 @@ def subgroup_reduced(self, elts, verbose=False): generated by {f0^2*f1^2, f0^3} """ from sage.matrix.constructor import matrix + d = self.ngens() X = ZZ**d try: @@ -1552,8 +1553,7 @@ def subgroup_reduced(self, elts, verbose=False): mat = matrix([elt_lattice.coordinate_vector(x) for x in isect.gens()]).change_ring(ZZ) D, U, V = mat.smith_form() new_basis = [(elt_lattice.linear_combination_of_basis((~V).row(i)).list(), D[i, i]) for i in range(U.ncols())] - return self.subgroup([self([x[0][i] % self.gens_orders()[i] - for i in range(d)]) for x in new_basis if x[1] != 1]) + return self.subgroup([self([x[0][i] % self.gens_orders()[i] for i in range(d)]) for x in new_basis if x[1] != 1]) def torsion_subgroup(self, n=None): """ @@ -1600,7 +1600,7 @@ def torsion_subgroup(self, n=None): if o == infinity: continue d = n.gcd(o) - torsion_generators.append(g**(o//d)) + torsion_generators.append(g ** (o // d)) return self.subgroup(torsion_generators) @@ -1614,6 +1614,7 @@ class AbelianGroup_subgroup(AbelianGroup_class): There should be a way to coerce an element of a subgroup into the ambient group. """ + def __init__(self, ambient, gens, names='f', category=None): """ EXAMPLES:: @@ -1694,6 +1695,7 @@ def __init__(self, ambient, gens, names='f', category=None): generated by {f0*f1^-2*f2^3*f3^-4*f4} """ from sage.libs.gap.libgap import libgap + if not isinstance(ambient, AbelianGroup_class): raise TypeError("ambient (=%s) must be an abelian group" % ambient) if not isinstance(gens, tuple): @@ -1706,8 +1708,7 @@ def __init__(self, ambient, gens, names='f', category=None): H = libgap(ambient).Subgroup(H_gens) invs = H.TorsionSubgroup().AbelianInvariants().sage() - rank = len([1 for g in H.GeneratorsOfGroup() - if g.Order().sage() is infinity]) + rank = len([1 for g in H.GeneratorsOfGroup() if g.Order().sage() is infinity]) invs += [0] * rank self._abinvs = invs @@ -1764,12 +1765,8 @@ def __contains__(self, x) -> bool: if x in self.ambient_group(): amb_inv = self.ambient_group().gens_orders() inv_basis = diagonal_matrix(ZZ, amb_inv) - gens_basis = matrix( - ZZ, len(self._gens), len(amb_inv), - [g.list() for g in self._gens] - ) - return (vector(ZZ, x.list()) - in inv_basis.stack(gens_basis).row_module()) + gens_basis = matrix(ZZ, len(self._gens), len(amb_inv), [g.list() for g in self._gens]) + return vector(ZZ, x.list()) in inv_basis.stack(gens_basis).row_module() return False def ambient_group(self): diff --git a/src/sage/groups/abelian_gps/abelian_group_element.py b/src/sage/groups/abelian_gps/abelian_group_element.py index d7f1f945ae0..7c660ffa660 100644 --- a/src/sage/groups/abelian_gps/abelian_group_element.py +++ b/src/sage/groups/abelian_gps/abelian_group_element.py @@ -71,6 +71,7 @@ class AbelianGroupElement(AbelianGroupElementBase): sage: a*b in F True """ + def as_permutation(self): r""" Return the element of the permutation group ``G`` (isomorphic to the @@ -91,6 +92,7 @@ def as_permutation(self): True """ from sage.libs.gap.libgap import libgap + G = self.parent() A = libgap.AbelianGroup(G.gens_orders()) phi = libgap.IsomorphismPermGroup(A) @@ -134,4 +136,5 @@ def word_problem(self, words): True """ from sage.groups.abelian_gps.abelian_group import word_problem + return word_problem(words, self) diff --git a/src/sage/groups/abelian_gps/abelian_group_gap.py b/src/sage/groups/abelian_gps/abelian_group_gap.py index eb41bbd8320..243cb90a66f 100644 --- a/src/sage/groups/abelian_gps/abelian_group_gap.py +++ b/src/sage/groups/abelian_gps/abelian_group_gap.py @@ -51,6 +51,7 @@ class AbelianGroupElement_gap(ElementLibGAP): sage: G.gens() (f1, f2) """ + def __init__(self, parent, x, check=True): """ The Python constructor. @@ -196,6 +197,7 @@ class AbelianGroupElement_polycyclic(AbelianGroupElement_gap): sage: G = AbelianGroupGap([4,7,0]) # optional - gap_package_polycyclic sage: TestSuite(G.an_element()).run() # optional - gap_package_polycyclic """ + def exponents(self): r""" Return the tuple of exponents of ``self``. @@ -242,6 +244,7 @@ class AbelianGroup_gap(UniqueRepresentation, GroupMixinLibGAP, ParentLibGAP, Abe sage: G Abelian group with gap, generator orders (3, 2, 5) """ + def __init__(self, G, category, ambient=None): r""" Create an instance of this class. @@ -344,6 +347,7 @@ def _element_constructor_(self, x, check=True): from sage.groups.abelian_gps.abelian_group_element import AbelianGroupElement from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroupElement from sage.modules.fg_pid.fgp_element import FGP_Element + if isinstance(x, AbelianGroupElement): exp = x.exponents() elif isinstance(x, AdditiveAbelianGroupElement): @@ -352,6 +356,7 @@ def _element_constructor_(self, x, check=True): exp = x.vector() else: from sage.modules.free_module_element import vector + exp = vector(ZZ, x) # turn the exponents into a gap element gens_gap = self.gens() @@ -399,6 +404,7 @@ def automorphism_group(self): Full group of automorphisms of Abelian group with gap, generator orders (2, 3) """ from sage.groups.abelian_gps.abelian_aut import AbelianGroupAutomorphismGroup + return AbelianGroupAutomorphismGroup(self) aut = automorphism_group @@ -455,6 +461,7 @@ def elementary_divisors(self): """ ediv = self.gap().AbelianInvariants().sage() from sage.matrix.constructor import diagonal_matrix + ed = diagonal_matrix(ZZ, ediv).elementary_divisors() return tuple(d for d in ed if d != 1) @@ -506,6 +513,7 @@ def gens_orders(self): False """ from sage.rings.infinity import Infinity + orders = [] for g in self.gens(): order = g.order() @@ -649,6 +657,7 @@ class AbelianGroupGap(AbelianGroup_gap): Needs the GAP package ``Polycyclic`` in case the group is infinite. """ + @staticmethod def __classcall_private__(cls, generator_orders): r""" @@ -701,6 +710,7 @@ def _latex_(self): \text{\texttt{Abelian group with gap, generator orders }} \left(2, 6\right) """ from sage.misc.latex import latex + base = r"\text{\texttt{Abelian group with gap, generator orders }}" return base + latex(self.gens_orders()) @@ -756,6 +766,7 @@ class AbelianGroupSubgroup_gap(AbelianGroup_gap): sage: gen = G.gens()[:2] sage: S = G.subgroup(gen) """ + def __init__(self, ambient, gens): r""" Initialize this subgroup. @@ -783,6 +794,7 @@ def __init__(self, ambient, gens): gens_gap = tuple([g.gap() for g in gens]) G = ambient.gap().Subgroup(gens_gap) from sage.rings.infinity import Infinity + category = Groups().Commutative() if G.Size().sage() < Infinity: category = category.Finite() @@ -805,7 +817,7 @@ def _repr_(self): Subgroup of Abelian group with gap, generator orders (2, 3, 4, 5) generated by (f1, f2) """ - return "Subgroup of %s generated by %s" % (self.ambient(),self.gens()) + return "Subgroup of %s generated by %s" % (self.ambient(), self.gens()) def __reduce__(self): r""" @@ -905,6 +917,7 @@ class AbelianGroupQuotient_gap(AbelianGroup_gap): sage: Q2 Quotient abelian group with generator orders (1, 3) """ + def __init__(self, G, N): r""" Constructor. @@ -937,8 +950,7 @@ def _repr_(self): sage: G.quotient(S) Quotient abelian group with generator orders (1, 1, 4, 5) """ - return "Quotient abelian group with generator orders " + str( - self.gens_orders()) + return "Quotient abelian group with generator orders " + str(self.gens_orders()) def __reduce__(self): r""" @@ -957,7 +969,7 @@ def __reduce__(self): """ G = self._cover N = self._relations - return G.quotient, (N, ) + return G.quotient, (N,) def _coerce_map_from_(self, S): r""" diff --git a/src/sage/groups/abelian_gps/abelian_group_morphism.py b/src/sage/groups/abelian_gps/abelian_group_morphism.py index 5261b913fb0..32820ceb6f3 100644 --- a/src/sage/groups/abelian_gps/abelian_group_morphism.py +++ b/src/sage/groups/abelian_gps/abelian_group_morphism.py @@ -11,6 +11,7 @@ - David Joyner (2006-03-03): initial version """ + # **************************************************************************** # Copyright (C) 2006 David Joyner and William Stein # @@ -28,6 +29,7 @@ class AbelianGroupMap(Morphism): """ A set-theoretic map between AbelianGroups. """ + def __init__(self, parent) -> None: """ The Python constructor. @@ -70,26 +72,27 @@ class AbelianGroupMorphism(Morphism): - David Joyner (2006-02) """ -# There is a homomorphism from H to G but not from G to H: -# -# sage: phi = AbelianGroupMorphism_im_gens(G,H,[a*b,a*c],[x,y]) -#------------------------------------------------------------ -#Traceback (most recent call last): -# File "", line 1, in ? -# File ".abeliangp_hom.sage.py", line 737, in __init__ -# raise TypeError("the orders of the corresponding elements in %s, %s must be equal" % (genss,imgss)) -#TypeError: the orders of the corresponding elements in [a*b, a*c], [x, y] must be equal -# -# sage: phi = AbelianGroupMorphism_im_gens(G,H,[a*b,(a*c)^2],[x*y,y]) -#------------------------------------------------------------ -#Traceback (most recent call last): -# File "", line 1, in ? -# File ".abeliangp_hom.sage.py", line 730, in __init__ -# raise TypeError("the list %s must generate G" % genss) -#TypeError: the list [a*b, c^2] must generate G + # There is a homomorphism from H to G but not from G to H: + # + # sage: phi = AbelianGroupMorphism_im_gens(G,H,[a*b,a*c],[x,y]) + # ------------------------------------------------------------ + # Traceback (most recent call last): + # File "", line 1, in ? + # File ".abeliangp_hom.sage.py", line 737, in __init__ + # raise TypeError("the orders of the corresponding elements in %s, %s must be equal" % (genss,imgss)) + # TypeError: the orders of the corresponding elements in [a*b, a*c], [x, y] must be equal + # + # sage: phi = AbelianGroupMorphism_im_gens(G,H,[a*b,(a*c)^2],[x*y,y]) + # ------------------------------------------------------------ + # Traceback (most recent call last): + # File "", line 1, in ? + # File ".abeliangp_hom.sage.py", line 730, in __init__ + # raise TypeError("the list %s must generate G" % genss) + # TypeError: the list [a*b, c^2] must generate G def __init__(self, G, H, genss, imgss): from sage.categories.homset import Hom + Morphism.__init__(self, Hom(G, H)) if len(genss) != len(imgss): raise TypeError("the lengths of %s, %s must be equal" % (genss, imgss)) @@ -210,5 +213,4 @@ def _call_(self, g): """ # g.word_problem is faster in general than word_problem(g) gens = self.codomaingens - return prod(gens[(self.domaingens).index(wi[0])]**wi[1] - for wi in g.word_problem(self.domaingens)) + return prod(gens[(self.domaingens).index(wi[0])] ** wi[1] for wi in g.word_problem(self.domaingens)) diff --git a/src/sage/groups/abelian_gps/all.py b/src/sage/groups/abelian_gps/all.py index f0c228a6a90..44ccc870376 100644 --- a/src/sage/groups/abelian_gps/all.py +++ b/src/sage/groups/abelian_gps/all.py @@ -18,9 +18,9 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** -#from dual_abelian_group import DualAbelianGroup +# from dual_abelian_group import DualAbelianGroup from sage.groups.abelian_gps.abelian_group import AbelianGroup, word_problem from sage.groups.abelian_gps.values import AbelianGroupWithValues diff --git a/src/sage/groups/abelian_gps/dual_abelian_group.py b/src/sage/groups/abelian_gps/dual_abelian_group.py index 278d7430e66..e2a3f8e7c6a 100644 --- a/src/sage/groups/abelian_gps/dual_abelian_group.py +++ b/src/sage/groups/abelian_gps/dual_abelian_group.py @@ -69,8 +69,7 @@ from sage.categories.groups import Groups from sage.structure.category_object import normalize_names from sage.structure.unique_representation import UniqueRepresentation -from sage.groups.abelian_gps.dual_abelian_group_element import ( - DualAbelianGroupElement) +from sage.groups.abelian_gps.dual_abelian_group_element import DualAbelianGroupElement from sage.misc.mrange import mrange from sage.misc.cachefunc import cached_method from sage.groups.group import AbelianGroup as AbelianGroupBase @@ -92,6 +91,7 @@ class DualAbelianGroup_class(UniqueRepresentation, AbelianGroupBase): Dual of Abelian Group isomorphic to Z/15Z x Z/7Z x Z/8Z x Z/9Z over Complex Field with 53 bits of precision """ + Element = DualAbelianGroupElement def __init__(self, G, names, base_ring) -> None: @@ -217,10 +217,11 @@ def random_element(self): ....: found[len([b for b in [x,y,z] if abs(X(b)-1)>10^(-8)])] = True """ from sage.misc.prandom import randint + result = self.one() for g in self.gens(): order = g.order() - result *= g**(randint(0, order)) + result *= g ** (randint(0, order)) return result def gen(self, i=0): diff --git a/src/sage/groups/abelian_gps/dual_abelian_group_element.py b/src/sage/groups/abelian_gps/dual_abelian_group_element.py index 589794d7d28..79babb156bf 100644 --- a/src/sage/groups/abelian_gps/dual_abelian_group_element.py +++ b/src/sage/groups/abelian_gps/dual_abelian_group_element.py @@ -101,8 +101,7 @@ def __call__(self, g): N = LCM(order) order_not = [N / o for o in order] zeta = F.zeta(N) - return F.prod(zeta**(expsX[i] * expsg[i] * order_not[i]) - for i in range(len(expsX))) + return F.prod(zeta ** (expsX[i] * expsg[i] * order_not[i]) for i in range(len(expsX))) def word_problem(self, words): """ @@ -132,11 +131,11 @@ def word_problem(self, words): [[b^2*c^2*d^3*e^5, 245]] """ from sage.libs.gap.libgap import libgap + A = libgap.AbelianGroup(self.parent().gens_orders()) gens = A.GeneratorsOfGroup() gap_g = libgap.Product([gi**Li for gi, Li in zip(gens, self.list())]) - gensH = [libgap.Product([gi**Li for gi, Li in zip(gens, w.list())]) - for w in words] + gensH = [libgap.Product([gi**Li for gi, Li in zip(gens, w.list())]) for w in words] H = libgap.Group(gensH) hom = H.EpimorphismFromFreeGroup() diff --git a/src/sage/groups/abelian_gps/element_base.py b/src/sage/groups/abelian_gps/element_base.py index 92a20a5320b..46075d16afa 100644 --- a/src/sage/groups/abelian_gps/element_base.py +++ b/src/sage/groups/abelian_gps/element_base.py @@ -8,7 +8,6 @@ As always, elements are immutable once constructed. """ - ########################################################################### # Copyright (C) 2006 William Stein # Copyright (C) 2006 David Joyner @@ -80,10 +79,8 @@ def __init__(self, parent, exponents): self._exponents = tuple(ZZ.zero() for i in range(n)) else: if len(exponents) != n: - raise IndexError('argument length (= %s) must be %s' - % (len(exponents), n)) - self._exponents = tuple(ZZ(e % o if o else e) for e, o in - zip(exponents, parent.gens_orders())) + raise IndexError('argument length (= %s) must be %s' % (len(exponents), n)) + self._exponents = tuple(ZZ(e % o if o else e) for e, o in zip(exponents, parent.gens_orders())) def __hash__(self): r""" @@ -130,8 +127,9 @@ def _libgap_(self): """ from sage.misc.misc_c import prod from sage.libs.gap.libgap import libgap + G = libgap(self.parent()) - return prod(g**i for g,i in zip(G.GeneratorsOfGroup(), self._exponents)) + return prod(g**i for g, i in zip(G.GeneratorsOfGroup(), self._exponents)) def list(self): """ @@ -237,7 +235,7 @@ def order(self): M = self.parent() order = M.gens_orders() L = self.exponents() - N = LCM([order[i]/GCD(order[i],L[i]) for i in range(len(order)) if L[i] != 0]) + N = LCM([order[i] / GCD(order[i], L[i]) for i in range(len(order)) if L[i] != 0]) if N == 0: return infinity return ZZ(N) @@ -258,8 +256,7 @@ def _div_(left, right): """ G = left.parent() assert G is right.parent() - exponents = [x - y for x, y in - zip(left._exponents, right._exponents)] + exponents = [x - y for x, y in zip(left._exponents, right._exponents)] return G.element_class(G, exponents) def _mul_(left, right): @@ -276,8 +273,7 @@ def _mul_(left, right): """ G = left.parent() assert G is right.parent() - exponents = [x + y for x, y in - zip(left._exponents, right._exponents)] + exponents = [x + y for x, y in zip(left._exponents, right._exponents)] return G.element_class(G, exponents) def __pow__(self, n): @@ -292,7 +288,7 @@ def __pow__(self, n): """ m = Integer(n) if n != m: - raise TypeError('argument n (= '+str(n)+') must be an integer.') + raise TypeError('argument n (= ' + str(n) + ') must be an integer.') G = self.parent() exponents = [m * e for e in self._exponents] return G.element_class(G, exponents) diff --git a/src/sage/groups/abelian_gps/values.py b/src/sage/groups/abelian_gps/values.py index 4328cac687e..0b3d3337799 100644 --- a/src/sage/groups/abelian_gps/values.py +++ b/src/sage/groups/abelian_gps/values.py @@ -141,10 +141,10 @@ def AbelianGroupWithValues(values, n, gens_orders=None, names='f', check=False, gens_orders, names = _normalize(n, gens_orders, names) if values_group is None: from sage.structure.sequence import Sequence + values_group = Sequence(values).universe() values = tuple(values_group(val) for val in values) - return AbelianGroupWithValues_class(gens_orders, names, - values, values_group) + return AbelianGroupWithValues_class(gens_orders, names, values, values_group) class AbelianGroupWithValuesEmbedding(Morphism): @@ -189,6 +189,7 @@ def __init__(self, domain, codomain): """ assert domain.values_group() is codomain from sage.categories.homset import Hom + Morphism.__init__(self, Hom(domain, codomain)) def _call_(self, x): @@ -321,7 +322,7 @@ def __pow__(self, n): """ m = Integer(n) if n != m: - raise TypeError('argument n (= '+str(n)+') must be an integer.') + raise TypeError('argument n (= ' + str(n) + ') must be an integer.') pow_self = AbelianGroupElement.__pow__(self, m) pow_self._value = pow(self.value(), m) return pow_self @@ -372,6 +373,7 @@ class AbelianGroupWithValues_class(AbelianGroup_class): sage: G. = AbelianGroupWithValues([2,-1], [0,4]) sage: TestSuite(G).run() """ + Element = AbelianGroupWithValuesElement def __init__(self, generator_orders, names, values, values_group): diff --git a/src/sage/groups/additive_abelian/additive_abelian_group.py b/src/sage/groups/additive_abelian/additive_abelian_group.py index 352343bf3cd..572746d0e48 100644 --- a/src/sage/groups/additive_abelian/additive_abelian_group.py +++ b/src/sage/groups/additive_abelian/additive_abelian_group.py @@ -200,6 +200,7 @@ def _repr_(self) -> str: # since we want to inherit things like __hash__ from there rather than the # hyper-generic implementation for abstract abelian groups. + class AdditiveAbelianGroup_class(FGP_Module_class): r""" An additive abelian group, implemented using the `\ZZ`-module machinery. @@ -283,6 +284,7 @@ def short_name(self): 'Z + Z/2 + Z/3' """ from sage.rings.infinity import Infinity as oo + invs = [j.additive_order() for j in self.gens()] if not invs: return "Trivial group" @@ -405,6 +407,7 @@ class AdditiveAbelianGroup_fixed_gens(AdditiveAbelianGroup_class): A variant which fixes a set of generators, which need not be in Smith form (or indeed independent). """ + def __init__(self, cover, rels, gens): r""" Standard initialisation function. @@ -468,5 +471,6 @@ def permutation_group(self): if not self.is_finite(): raise TypeError('Additive Abelian group must be finite') from sage.groups.perm_gps.permgroup import PermutationGroup + s = 'Image(IsomorphismPermGroup(AbelianGroup(%s)))' % (list(self.invariants()),) return PermutationGroup(gap_group=s) diff --git a/src/sage/groups/additive_abelian/additive_abelian_wrapper.py b/src/sage/groups/additive_abelian/additive_abelian_wrapper.py index c367f6b040a..e89e036cd74 100644 --- a/src/sage/groups/additive_abelian/additive_abelian_wrapper.py +++ b/src/sage/groups/additive_abelian/additive_abelian_wrapper.py @@ -80,6 +80,7 @@ class UnwrappingMorphism(Morphism): r""" The embedding into the ambient group. Used by the coercion framework. """ + def __init__(self, domain): r""" EXAMPLES:: @@ -365,12 +366,13 @@ def leq(G, H): return False dsG = G.invariants()[::-1] # descending dsH = H.invariants()[::-1] # descending - if not all(iG.divides(iH) for iG,iH in zip(dsG, dsH)): + if not all(iG.divides(iH) for iG, iH in zip(dsG, dsH)): return False # test if generating set of G is contained in H return all(g.element() in H for g in G.gens()) from sage.structure.richcmp import op_LT, op_LE, op_EQ, op_NE, op_GE, op_GT + if op == op_LE: return leq(self, other) if op == op_GE: @@ -411,6 +413,7 @@ def discrete_exp(self, v): True """ from sage.misc.verbose import verbose + v = self.V()(v) verbose("Calling discrete exp on %s" % v) # DUMB IMPLEMENTATION! @@ -689,6 +692,7 @@ def canonical_form(self, factors): """ if factors == 'invariant': from sage.matrix.special import diagonal_matrix + D = diagonal_matrix(ZZ, self._gen_orders) S, U, V = D.smith_form() newgens, newords = [], [] @@ -987,18 +991,19 @@ def basis_from_generators(gens, ords=None): ords = [g.order() for g in gens] from sage.rings.infinity import Infinity + if not all(o < Infinity for o in ords): raise ValueError('all provided generators must have finite order') from sage.arith.functions import lcm + lam = lcm(ords) ps = sorted(lam.prime_factors(), key=lam.valuation) gammas = [] ms = [] for p in ps: - pgens = [(o.prime_to_m_part(p) * g, o.p_primary_part(p)) - for g, o in zip(gens, ords) if not o % p] + pgens = [(o.prime_to_m_part(p) * g, o.p_primary_part(p)) for g, o in zip(gens, ords) if not o % p] assert pgens pgens.sort(key=lambda tup: tup[1]) @@ -1020,13 +1025,13 @@ def basis_from_generators(gens, ords=None): beta_q = beta for v in range(1, val_beta): beta_q *= p -# assert beta_q == beta * p**v + # assert beta_q == beta * p**v try: e = _discrete_log_pgroup(p, vals, alphas, -beta_q) except ValueError: continue _expand_basis_pgroup(p, alphas, vals, beta, val_beta, list(e) + [p**v]) -# assert all(a.order() == p**v for a,v in zip(alphas, vals)) + # assert all(a.order() == p**v for a,v in zip(alphas, vals)) break else: alphas.append(beta) @@ -1035,13 +1040,13 @@ def basis_from_generators(gens, ords=None): for i, (v, a) in enumerate(sorted(zip(vals, alphas), reverse=True)): if i < len(gammas): gammas[i] += a - ms[i] *= p ** v + ms[i] *= p**v else: gammas.append(a) - ms.append(p ** v) + ms.append(p**v) -# assert len({sum(i*g for i,g in zip(vec,gammas)) -# for vec in __import__('itertools').product(*map(range,ms))}) \ -# == __import__('sage').misc.misc_c.prod(ms) + # assert len({sum(i*g for i,g in zip(vec,gammas)) + # for vec in __import__('itertools').product(*map(range,ms))}) \ + # == __import__('sage').misc.misc_c.prod(ms) return gammas, ms diff --git a/src/sage/groups/additive_abelian/all.py b/src/sage/groups/additive_abelian/all.py index e65582f51b2..80268852455 100644 --- a/src/sage/groups/additive_abelian/all.py +++ b/src/sage/groups/additive_abelian/all.py @@ -1,3 +1,2 @@ - from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup from sage.groups.additive_abelian.additive_abelian_wrapper import * diff --git a/src/sage/groups/additive_abelian/qmodnz.py b/src/sage/groups/additive_abelian/qmodnz.py index 48c642af76d..ee7918af2ea 100644 --- a/src/sage/groups/additive_abelian/qmodnz.py +++ b/src/sage/groups/additive_abelian/qmodnz.py @@ -67,6 +67,7 @@ class QmodnZ(Parent, UniqueRepresentation): sage: QmodnZ(2/3) Q/(2/3)Z """ + Element = QmodnZ_Element def __init__(self, n=1) -> None: diff --git a/src/sage/groups/additive_abelian/qmodnz_element.py b/src/sage/groups/additive_abelian/qmodnz_element.py index 12bfc07626b..4729b2757b7 100644 --- a/src/sage/groups/additive_abelian/qmodnz_element.py +++ b/src/sage/groups/additive_abelian/qmodnz_element.py @@ -46,6 +46,7 @@ class QmodnZ_Element(AdditiveGroupElement): sage: G(400/19) 39/19 """ + def __init__(self, parent, x, construct=False): r""" Create an element of `\Q/n\Z`. diff --git a/src/sage/groups/affine_gps/affine_group.py b/src/sage/groups/affine_gps/affine_group.py index bc3582107fa..7e01ce79837 100644 --- a/src/sage/groups/affine_gps/affine_group.py +++ b/src/sage/groups/affine_gps/affine_group.py @@ -31,6 +31,7 @@ ################################################################# + class AffineGroup(UniqueRepresentation, Group): r""" An affine group. @@ -145,6 +146,7 @@ class AffineGroup(UniqueRepresentation, Group): - :wikipedia:`Affine_group` """ + @staticmethod def __classcall__(cls, *args, **kwds): """ @@ -174,8 +176,10 @@ def __classcall__(cls, *args, **kwds): if len(args) == 2: degree, ring = args from sage.rings.integer import Integer + if isinstance(ring, Integer): from sage.rings.finite_rings.finite_field_constructor import FiniteField + var = kwds.get('var', 'a') ring = FiniteField(ring, var) return super().__classcall__(cls, degree, ring) @@ -273,8 +277,7 @@ def _latex_(self): sage: latex(G) \mathrm{Aff}_{6}(\Bold{F}_{5}) """ - return "\\mathrm{Aff}_{%s}(%s)" % (self.degree(), - self.base_ring()._latex_()) + return "\\mathrm{Aff}_{%s}(%s)" % (self.degree(), self.base_ring()._latex_()) def _repr_(self): """ @@ -285,8 +288,7 @@ def _repr_(self): sage: AffineGroup(6, GF(5)) Affine Group of degree 6 over Finite Field of size 5 """ - return "Affine Group of degree %s over %s" % (self.degree(), - self.base_ring()) + return "Affine Group of degree %s over %s" % (self.degree(), self.base_ring()) def cardinality(self): """ @@ -302,7 +304,7 @@ def cardinality(self): +Infinity """ card_GL = self._GL.cardinality() - return card_GL * self.base_ring().cardinality()**self.degree() + return card_GL * self.base_ring().cardinality() ** self.degree() def degree(self): """ @@ -530,8 +532,7 @@ def some_elements(self): """ mats = self._GL.some_elements() vecs = self.vector_space().some_elements() - return [self.element_class(self, A, b, check=False, convert=False) - for A in mats for b in vecs] + return [self.element_class(self, A, b, check=False, convert=False) for A in mats for b in vecs] def __iter__(self): """ diff --git a/src/sage/groups/affine_gps/euclidean_group.py b/src/sage/groups/affine_gps/euclidean_group.py index 97677c777d1..cc0731e960a 100644 --- a/src/sage/groups/affine_gps/euclidean_group.py +++ b/src/sage/groups/affine_gps/euclidean_group.py @@ -154,6 +154,7 @@ class EuclideanGroup(AffineGroup): - :wikipedia:`Euclidean_group` """ + def _element_constructor_check(self, A, b): """ Verify that ``A``, ``b`` define an affine group element. @@ -239,7 +240,7 @@ def random_element(self): try: g1 = self.reflection(v) break - except ValueError: # v has norm zero + except ValueError: # v has norm zero pass g2 = self.translation(self.vector_space().random_element()) return g1 * g2 diff --git a/src/sage/groups/affine_gps/group_element.py b/src/sage/groups/affine_gps/group_element.py index 190a0180d1b..7e900d610fe 100644 --- a/src/sage/groups/affine_gps/group_element.py +++ b/src/sage/groups/affine_gps/group_element.py @@ -106,6 +106,7 @@ class AffineGroupElement(MultiplicativeGroupElement): x |-> [ 0 -1 0] x + [1] [-1 0 0] [1] """ + def __init__(self, parent, A, b=0, convert=True, check=True): r""" Create element of an affine group. @@ -125,7 +126,7 @@ def __init__(self, parent, A, b=0, convert=True, check=True): g = A d = parent.degree() A = g.submatrix(0, 0, d, d) - b = [g[i,d] for i in range(d)] + b = [g[i, d] for i in range(d)] convert = True if convert: A = parent.matrix_space()(A) @@ -229,9 +230,10 @@ def matrix(self): parent = self.parent() d = parent.degree() from sage.matrix.constructor import matrix, zero_matrix, block_matrix + zero = zero_matrix(parent.base_ring(), 1, d) one = matrix(parent.base_ring(), [[1]]) - m = block_matrix(2,2, [A, b.column(), zero, one]) + m = block_matrix(2, 2, [A, b.column(), zero, one]) m.set_immutable() return m @@ -255,10 +257,10 @@ def _repr_(self): indices = range(deg) s = [] for Ai, bi, i in zip(A.splitlines(), b.splitlines(), indices): - if i == deg//2: - s.append('x |-> '+Ai+' x + '+bi) + if i == deg // 2: + s.append('x |-> ' + Ai + ' x + ' + bi) else: - s.append(' '+Ai+' '+bi) + s.append(' ' + Ai + ' ' + bi) return '\n'.join(s) def _latex_(self): @@ -282,7 +284,7 @@ def _latex_(self): 1\n\\end{array}\\right)\\vec{x} + \\left(\\begin{array}{r}\n3 \\\\\n4\n\\end{array}\\right)' """ - return r'\vec{x}\mapsto '+self.A()._latex_()+r'\vec{x} + '+self.b().column()._latex_() + return r'\vec{x}\mapsto ' + self.A()._latex_() + r'\vec{x} + ' + self.b().column()._latex_() def _ascii_art_(self): r""" @@ -304,9 +306,10 @@ def _ascii_art_(self): [ 0 10 2] [5/2] """ from sage.typeset.ascii_art import ascii_art + deg = self.parent().degree() - A = ascii_art(self._A, baseline=deg//2) - b = ascii_art(self._b.column(), baseline=deg//2) + A = ascii_art(self._A, baseline=deg // 2) + b = ascii_art(self._b.column(), baseline=deg // 2) return ascii_art("x |-> ") + A + ascii_art(" x + ") + b def _unicode_art_(self): @@ -329,9 +332,10 @@ def _unicode_art_(self): ⎝ 0 10 2⎠ ⎝5/2⎠ """ from sage.typeset.unicode_art import unicode_art + deg = self.parent().degree() - A = unicode_art(self._A, baseline=deg//2) - b = unicode_art(self._b.column(), baseline=deg//2) + A = unicode_art(self._A, baseline=deg // 2) + b = unicode_art(self._b.column(), baseline=deg // 2) return unicode_art("x ↦ ") + A + unicode_art(" x + ") + b def _mul_(self, other): @@ -420,27 +424,31 @@ def __call__(self, v): # start with the most probable case, i.e., v is in the vector space if v in parent.vector_space(): - return self._A*v + self._b + return self._A * v + self._b from sage.rings.polynomial.polynomial_element import Polynomial + if isinstance(v, Polynomial) and parent.degree() == 1: ring = v.parent() - return ring([self._A[0,0], self._b[0]]) + return ring([self._A[0, 0], self._b[0]]) from sage.rings.polynomial.multi_polynomial import MPolynomial + if isinstance(v, MPolynomial) and parent.degree() == v.parent().ngens(): ring = v.parent() from sage.modules.free_module_element import vector + image_coords = self._A * vector(ring, ring.gens()) + self._b return v(*image_coords) import sage.geometry.abc + if isinstance(v, sage.geometry.abc.Polyhedron): - return self._A*v + self._b + return self._A * v + self._b # otherwise, coerce v into the vector space v = parent.vector_space()(v) - return self._A*v + self._b + return self._A * v + self._b def _act_on_(self, x, self_on_left): """ diff --git a/src/sage/groups/all.py b/src/sage/groups/all.py index 601ba6c7ec0..80e4216d536 100644 --- a/src/sage/groups/all.py +++ b/src/sage/groups/all.py @@ -7,8 +7,7 @@ from sage.groups.perm_gps.all import * -from sage.groups.generic import (discrete_log, discrete_log_rho, discrete_log_lambda, - linear_relation, multiple, multiples, order_from_multiple) +from sage.groups.generic import discrete_log, discrete_log_rho, discrete_log_lambda, linear_relation, multiple, multiples, order_from_multiple lazy_import('sage.groups.class_function', 'ClassFunction') @@ -33,9 +32,7 @@ lazy_import('sage.groups.semimonomial_transformations.semimonomial_transformation_group', 'SemimonomialTransformationGroup') lazy_import('sage.groups.group_exp', 'GroupExp') -lazy_import('sage.groups.group_exp', ['GroupExp_Class', 'GroupExpElement'], - deprecation=38238) +lazy_import('sage.groups.group_exp', ['GroupExp_Class', 'GroupExpElement'], deprecation=38238) lazy_import('sage.groups.group_semidirect_product', 'GroupSemidirectProduct') -lazy_import('sage.groups.group_semidirect_product', 'GroupSemidirectProductElement', - deprecation=38238) +lazy_import('sage.groups.group_semidirect_product', 'GroupSemidirectProductElement', deprecation=38238) diff --git a/src/sage/groups/artin.py b/src/sage/groups/artin.py index 9fb25e5418e..5e0e757e808 100644 --- a/src/sage/groups/artin.py +++ b/src/sage/groups/artin.py @@ -56,6 +56,7 @@ class ArtinGroupElement(FinitelyPresentedGroupElement): sage: A((1, 2, -3, -2)) s1*s2*s3^-1*s2^-1 """ + def _latex_(self): r""" Return a LaTeX representation of ``self``. @@ -79,8 +80,7 @@ def _latex_(self): word = self.Tietze() if not word: return '1' - return ''.join(r"\sigma_{%s}^{-1}" % (-i) if i < 0 else r"\sigma_{%s}" % i - for i in word) + return ''.join(r"\sigma_{%s}^{-1}" % (-i) if i < 0 else r"\sigma_{%s}" % i for i in word) def exponent_sum(self): """ @@ -304,12 +304,13 @@ def burau_matrix(self, var='t'): """ gens, invs = self.parent()._burau_generators MS = gens[0].parent() - ret = MS.prod(gens[i-1] if i > 0 else invs[-i-1] for i in self.Tietze()) + ret = MS.prod(gens[i - 1] if i > 0 else invs[-i - 1] for i in self.Tietze()) if var == 't': return ret from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + poly_ring = LaurentPolynomialRing(ret.base_ring().base_ring(), var) return ret.change_ring(poly_ring) @@ -318,6 +319,7 @@ class FiniteTypeArtinGroupElement(ArtinGroupElement): """ An element of a finite-type Artin group. """ + def _richcmp_(self, other, op): """ Compare ``self`` and ``other``. @@ -408,8 +410,7 @@ def left_normal_form(self): """ lnfp = self._left_normal_form_coxeter() P = self.parent() - return tuple([P.delta() ** lnfp[0]] + - [P._standard_lift(w) for w in lnfp[1:]]) + return tuple([P.delta() ** lnfp[0]] + [P._standard_lift(w) for w in lnfp[1:]]) def _left_normal_form_coxeter(self): r""" @@ -469,12 +470,12 @@ def _left_normal_form_coxeter(self): while S: a = list(S)[0] form[i] = form[i] * sr[a] - form[i + 1] = sr[a] * form[i+1] + form[i + 1] = sr[a] * form[i + 1] e = form[i].descents(side='right') s = form[i + 1].descents(side='left') S = set(s).difference(set(e)) - if form[i+1].length() == 0: - form.pop(i+1) + if form[i + 1].length() == 0: + form.pop(i + 1) i = 0 else: i += 1 @@ -563,6 +564,7 @@ class ArtinGroup(UniqueRepresentation, FinitelyPresentedGroup): :class:`~sage.groups.raag.RightAngledArtinGroup` """ + @staticmethod def __classcall_private__(cls, coxeter_data, names=None): """ @@ -604,15 +606,16 @@ def __classcall_private__(cls, coxeter_data, names=None): names = [names + str(i) for i in coxeter_data.index_set()] names = tuple(names) if len(names) != coxeter_data.rank(): - raise ValueError("the number of generators must match" - " the rank of the Coxeter type") + raise ValueError("the number of generators must match" " the rank of the Coxeter type") if all(m == Infinity for m in coxeter_data.coxeter_graph().edge_labels()): from sage.groups.raag import RightAngledArtinGroup + return RightAngledArtinGroup(coxeter_data.coxeter_graph(), names) if not coxeter_data.is_finite(): return super().__classcall__(cls, coxeter_data, names) if coxeter_data.coxeter_type().cartan_type().type() == 'A': from sage.groups.braid import BraidGroup + return BraidGroup(coxeter_data.rank() + 1, names) return FiniteTypeArtinGroup(coxeter_data, names) @@ -635,7 +638,7 @@ def __init__(self, coxeter_matrix, names) -> None: I = coxeter_matrix.index_set() gens = free_group.gens() for ii, i in enumerate(I): - for jj, j in enumerate(I[ii + 1:], start=ii + 1): + for jj, j in enumerate(I[ii + 1 :], start=ii + 1): m = coxeter_matrix[i, j] if m == Infinity: # no relation continue @@ -682,6 +685,7 @@ def cardinality(self): +Infinity """ from sage.rings.infinity import Infinity + return Infinity order = cardinality @@ -923,9 +927,11 @@ def _burau_generators(self): # Determine the base field if data.is_simply_laced(): from sage.rings.integer_ring import ZZ + base_ring = ZZ elif data.is_finite(): from sage.rings.number_field.number_field import QuadraticField + letter = data.cartan_type().type() if letter in ['B', 'C', 'F']: base_ring = QuadraticField(2) @@ -935,9 +941,11 @@ def _burau_generators(self): base_ring = QuadraticField(5) else: from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField + base_ring = UniversalCyclotomicField() else: from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField + base_ring = UniversalCyclotomicField() # Construct the matrices @@ -945,6 +953,7 @@ def _burau_generators(self): from sage.matrix.matrix_space import MatrixSpace from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing import sage.rings.abc + poly_ring = LaurentPolynomialRing(base_ring, 't') q = -poly_ring.gen() MS = MatrixSpace(poly_ring, n, sparse=True) @@ -960,8 +969,10 @@ def val(x): return 1 + q**2 E2x = E(2 * x) return q * (E2x + ~E2x) + elif isinstance(base_ring, sage.rings.abc.NumberField_quadratic): from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField + E = UniversalCyclotomicField().gen def val(x): @@ -970,7 +981,9 @@ def val(x): if x == 1: return 1 + q**2 return q * base_ring((E(2 * x) + ~E(2 * x)).to_cyclotomic_field()) + else: + def val(x): if x == -1: return 2 * q @@ -982,14 +995,12 @@ def val(x): return q from sage.functions.trig import cos from sage.symbolic.constants import pi + return q * base_ring(2 * cos(pi / x)) + index_set = data.index_set() - gens = [one - MS([SparseEntry(i, j, val(coxeter_matrix[index_set[i], index_set[j]])) - for j in range(n)]) - for i in range(n)] - invs = [one - q**-2 * MS([SparseEntry(i, j, val(coxeter_matrix[index_set[i], index_set[j]])) - for j in range(n)]) - for i in range(n)] + gens = [one - MS([SparseEntry(i, j, val(coxeter_matrix[index_set[i], index_set[j]])) for j in range(n)]) for i in range(n)] + invs = [one - q**-2 * MS([SparseEntry(i, j, val(coxeter_matrix[index_set[i], index_set[j]])) for j in range(n)]) for i in range(n)] return [gens, invs] Element = ArtinGroupElement @@ -1034,6 +1045,7 @@ class FiniteTypeArtinGroup(ArtinGroup): sage: GF = F.cayley_graph(elements=ball(F, 4), generators=F.gens()); GF # needs sage.combinat Digraph on 40 vertices """ + def delta(self): r""" Return the `\Delta` element of ``self``. diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index 45f93955ca7..fae16c583b7 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -82,8 +82,7 @@ GroupMorphismWithGensImages, ) from sage.groups.free_group import FreeGroup, is_FreeGroup -from sage.groups.perm_gps.permgroup_named import (SymmetricGroup, - SymmetricGroupElement) +from sage.groups.perm_gps.permgroup_named import SymmetricGroup, SymmetricGroupElement from sage.libs.gap.libgap import libgap from sage.matrix.constructor import identity_matrix, matrix from sage.misc.cachefunc import cached_method @@ -97,13 +96,7 @@ from sage.structure.element import Expression from sage.structure.richcmp import rich_to_bool, richcmp -lazy_import('sage.libs.braiding', - ['leftnormalform', 'rightnormalform', 'centralizer', - 'supersummitset', 'greatestcommondivisor', - 'leastcommonmultiple', 'conjugatingbraid', 'ultrasummitset', - 'thurston_type', 'rigidity', 'sliding_circuits', 'send_to_sss', - 'send_to_uss', 'send_to_sc', 'trajectory', 'cyclic_slidings'], - feature=sage__libs__braiding()) +lazy_import('sage.libs.braiding', ['leftnormalform', 'rightnormalform', 'centralizer', 'supersummitset', 'greatestcommondivisor', 'leastcommonmultiple', 'conjugatingbraid', 'ultrasummitset', 'thurston_type', 'rigidity', 'sliding_circuits', 'send_to_sss', 'send_to_uss', 'send_to_sc', 'trajectory', 'cyclic_slidings'], feature=sage__libs__braiding()) lazy_import('sage.knots.knot', 'Knot') @@ -123,6 +116,7 @@ class Braid(FiniteTypeArtinGroupElement): sage: B((1, 2, -3, -2)) s0*s1*s2^-1*s1^-1 """ + def _richcmp_(self, other, op): """ Compare ``self`` and ``other``. @@ -193,7 +187,7 @@ def components_in_closure(self): 1 """ cycles = self.permutation().to_cycles(singletons=False) - return self.strands() - sum(len(c)-1 for c in cycles) + return self.strands() - sum(len(c) - 1 for c in cycles) def burau_matrix(self, var='t', reduced=False): r""" @@ -315,15 +309,15 @@ def burau_matrix(self, var='t', reduced=False): for i in self.Tietze(): A = identity_matrix(R, n) if i > 0: - A[i-1, i-1] = 1-t + A[i - 1, i - 1] = 1 - t A[i, i] = 0 - A[i, i-1] = 1 - A[i-1, i] = t + A[i, i - 1] = 1 + A[i - 1, i] = t if i < 0: - A[-1-i, -1-i] = 0 - A[-i, -i] = 1-t**(-1) - A[-1-i, -i] = 1 - A[-i, -1-i] = t**(-1) + A[-1 - i, -1 - i] = 0 + A[-i, -i] = 1 - t ** (-1) + A[-1 - i, -i] = 1 + A[-i, -1 - i] = t ** (-1) M = M * A else: @@ -333,21 +327,21 @@ def burau_matrix(self, var='t', reduced=False): A = identity_matrix(R, n - 1) if j > 1: i = j - 1 - A[i-1, i-1] = 1 - t + A[i - 1, i - 1] = 1 - t A[i, i] = 0 - A[i, i-1] = 1 - A[i-1, i] = t + A[i, i - 1] = 1 + A[i - 1, i] = t if j < -1: i = j + 1 - A[-1-i, -1-i] = 0 + A[-1 - i, -1 - i] = 0 A[-i, -i] = 1 - t**-1 - A[-1-i, -i] = 1 - A[-i, -1-i] = t**-1 + A[-1 - i, -i] = 1 + A[-i, -1 - i] = t**-1 if j == 1: for k in range(n - 1): A[k, 0] = -t if j == -1: - A[0, 0] = -t**-1 + A[0, 0] = -(t**-1) for k in range(1, n - 1): A[k, 0] = -1 M = M * A @@ -355,19 +349,19 @@ def burau_matrix(self, var='t', reduced=False): elif reduced in ["simple", "unitary"]: M = identity_matrix(R, n - 1) for j in self.Tietze(): - A = identity_matrix(R, n-1) + A = identity_matrix(R, n - 1) if j > 0: - A[j-1, j-1] = -t + A[j - 1, j - 1] = -t if j > 1: - A[j-1, j-2] = t - if j < n-1: - A[j-1, j] = 1 + A[j - 1, j - 2] = t + if j < n - 1: + A[j - 1, j] = 1 if j < 0: - A[-j-1, -j-1] = -t**(-1) + A[-j - 1, -j - 1] = -(t ** (-1)) if -j > 1: - A[-j-1, -j-2] = 1 + A[-j - 1, -j - 2] = 1 if -j < n - 1: - A[-j-1, -j] = t**(-1) + A[-j - 1, -j] = t ** (-1) M = M * A else: @@ -380,20 +374,18 @@ def burau_matrix(self, var='t', reduced=False): # :class:`UnitaryMatrixGroup_generic` t_sq = R.hom([t**2], codomain=R) - Madj = matrix(R, n - 1, n - 1, - lambda i, j: t**(j - i) * t_sq(M[i, j])) + Madj = matrix(R, n - 1, n - 1, lambda i, j: t ** (j - i) * t_sq(M[i, j])) - t_inv = R.hom([t**(-1)], codomain=R) - M = matrix(R, n - 1, n - 1, - lambda i, j: t_inv(Madj[j, i])) + t_inv = R.hom([t ** (-1)], codomain=R) + M = matrix(R, n - 1, n - 1, lambda i, j: t_inv(Madj[j, i])) # We see if the hermitian form has been cached # in the parent H = self.parent()._hermitian_form if H is None: # Defining the hermitian form - H = (t + t**(-1)) * identity_matrix(R, n - 1) - for i in range(n-2): + H = (t + t ** (-1)) * identity_matrix(R, n - 1) + for i in range(n - 2): H[i, i + 1] = -1 H[i + 1, i] = -1 self.parent()._hermitian_form = H @@ -464,7 +456,7 @@ def alexander_polynomial(self, var='t', normalized=True): qn = sum(t**i for i in range(n)) p //= qn if normalized: - p *= t**(-p.degree()) + p *= t ** (-p.degree()) if p.constant_coefficient() < 0: p = -p return p @@ -503,8 +495,7 @@ def permutation(self, W=None): """ return self.coxeter_group_element(W) - def plot(self, color='rainbow', orientation='bottom-top', gap=0.05, - aspect_ratio=1, axes=False, **kwds): + def plot(self, color='rainbow', orientation='bottom-top', gap=0.05, aspect_ratio=1, axes=False, **kwds): """ Plot the braid. @@ -567,6 +558,7 @@ def plot(self, color='rainbow', orientation='bottom-top', gap=0.05, from sage.plot.bezier_path import bezier_path from sage.plot.colors import rainbow from sage.plot.plot import Graphics, line + if orientation == 'top-bottom': orx = 0 ory = -1 @@ -592,44 +584,26 @@ def plot(self, color='rainbow', orientation='bottom-top', gap=0.05, elif color == "rainbow": col = rainbow(n) else: - col = [color]*n + col = [color] * n braid = self.Tietze() a = Graphics() op = gap for i, m in enumerate(braid): for j in range(n): - if m == j+1: - a += bezier_path([[(j*nx+i*orx, i*ory+j*ny), (j*nx+orx*(i+0.25), j*ny+ory*(i+0.25)), - (nx*(j+0.5)+orx*(i+0.5), ny*(j+0.5)+ory*(i+0.5))], - [(nx*(j+1)+orx*(i+0.75), ny*(j+1)+ory*(i+0.75)), - (nx*(j+1)+orx*(i+1), ny*(j+1)+ory*(i+1))]], color=col[j], **kwds) + if m == j + 1: + a += bezier_path([[(j * nx + i * orx, i * ory + j * ny), (j * nx + orx * (i + 0.25), j * ny + ory * (i + 0.25)), (nx * (j + 0.5) + orx * (i + 0.5), ny * (j + 0.5) + ory * (i + 0.5))], [(nx * (j + 1) + orx * (i + 0.75), ny * (j + 1) + ory * (i + 0.75)), (nx * (j + 1) + orx * (i + 1), ny * (j + 1) + ory * (i + 1))]], color=col[j], **kwds) elif m == j: - a += bezier_path([[(nx*j+orx*i, ny*j+ory*i), (nx*j+orx*(i+0.25), ny*j+ory*(i+0.25)), - (nx*(j-0.5+4*op)+orx*(i+0.5-2*op), ny*(j-0.5+4*op)+ory*(i+0.5-2*op)), - (nx*(j-0.5+2*op)+orx*(i+0.5-op), ny*(j-0.5+2*op)+ory*(i+0.5-op))]], - color=col[j], **kwds) - a += bezier_path([[(nx*(j-0.5-2*op)+orx*(i+0.5+op), ny*(j-0.5-2*op)+ory*(i+0.5+op)), - (nx*(j-0.5-4*op)+orx*(i+0.5+2*op), ny*(j-0.5-4*op)+ory*(i+0.5+2*op)), - (nx*(j-1)+orx*(i+0.75), ny*(j-1)+ory*(i+0.75)), - (nx*(j-1)+orx*(i+1), ny*(j-1)+ory*(i+1))]], color=col[j], **kwds) - col[j], col[j-1] = col[j-1], col[j] - elif -m == j+1: - a += bezier_path([[(nx*j+orx*i, ny*j+ory*i), (nx*j+orx*(i+0.25), ny*j+ory*(i+0.25)), - (nx*(j+0.5-4*op)+orx*(i+0.5-2*op), ny*(j+0.5-4*op)+ory*(i+0.5-2*op)), - (nx*(j+0.5-2*op)+orx*(i+0.5-op), ny*(j+0.5-2*op)+ory*(i+0.5-op))]], - color=col[j], **kwds) - a += bezier_path([[(nx*(j+0.5+2*op)+orx*(i+0.5+op), ny*(j+0.5+2*op)+ory*(i+0.5+op)), - (nx*(j+0.5+4*op)+orx*(i+0.5+2*op), ny*(j+0.5+4*op)+ory*(i+0.5+2*op)), - (nx*(j+1)+orx*(i+0.75), ny*(j+1)+ory*(i+0.75)), - (nx*(j+1)+orx*(i+1), ny*(j+1)+ory*(i+1))]], color=col[j], **kwds) + a += bezier_path([[(nx * j + orx * i, ny * j + ory * i), (nx * j + orx * (i + 0.25), ny * j + ory * (i + 0.25)), (nx * (j - 0.5 + 4 * op) + orx * (i + 0.5 - 2 * op), ny * (j - 0.5 + 4 * op) + ory * (i + 0.5 - 2 * op)), (nx * (j - 0.5 + 2 * op) + orx * (i + 0.5 - op), ny * (j - 0.5 + 2 * op) + ory * (i + 0.5 - op))]], color=col[j], **kwds) + a += bezier_path([[(nx * (j - 0.5 - 2 * op) + orx * (i + 0.5 + op), ny * (j - 0.5 - 2 * op) + ory * (i + 0.5 + op)), (nx * (j - 0.5 - 4 * op) + orx * (i + 0.5 + 2 * op), ny * (j - 0.5 - 4 * op) + ory * (i + 0.5 + 2 * op)), (nx * (j - 1) + orx * (i + 0.75), ny * (j - 1) + ory * (i + 0.75)), (nx * (j - 1) + orx * (i + 1), ny * (j - 1) + ory * (i + 1))]], color=col[j], **kwds) + col[j], col[j - 1] = col[j - 1], col[j] + elif -m == j + 1: + a += bezier_path([[(nx * j + orx * i, ny * j + ory * i), (nx * j + orx * (i + 0.25), ny * j + ory * (i + 0.25)), (nx * (j + 0.5 - 4 * op) + orx * (i + 0.5 - 2 * op), ny * (j + 0.5 - 4 * op) + ory * (i + 0.5 - 2 * op)), (nx * (j + 0.5 - 2 * op) + orx * (i + 0.5 - op), ny * (j + 0.5 - 2 * op) + ory * (i + 0.5 - op))]], color=col[j], **kwds) + a += bezier_path([[(nx * (j + 0.5 + 2 * op) + orx * (i + 0.5 + op), ny * (j + 0.5 + 2 * op) + ory * (i + 0.5 + op)), (nx * (j + 0.5 + 4 * op) + orx * (i + 0.5 + 2 * op), ny * (j + 0.5 + 4 * op) + ory * (i + 0.5 + 2 * op)), (nx * (j + 1) + orx * (i + 0.75), ny * (j + 1) + ory * (i + 0.75)), (nx * (j + 1) + orx * (i + 1), ny * (j + 1) + ory * (i + 1))]], color=col[j], **kwds) elif -m == j: - a += bezier_path([[(nx*j+orx*i, ny*j+ory*i), (nx*j+orx*(i+0.25), ny*j+ory*(i+0.25)), - (nx*(j-0.5)+orx*(i+0.5), ny*(j-0.5)+ory*(i+0.5))], - [(nx*(j-1)+orx*(i+0.75), ny*(j-1)+ory*(i+0.75)), - (nx*(j-1)+orx*(i+1), ny*(j-1)+ory*(i+1))]], color=col[j], **kwds) - col[j], col[j-1] = col[j-1], col[j] + a += bezier_path([[(nx * j + orx * i, ny * j + ory * i), (nx * j + orx * (i + 0.25), ny * j + ory * (i + 0.25)), (nx * (j - 0.5) + orx * (i + 0.5), ny * (j - 0.5) + ory * (i + 0.5))], [(nx * (j - 1) + orx * (i + 0.75), ny * (j - 1) + ory * (i + 0.75)), (nx * (j - 1) + orx * (i + 1), ny * (j - 1) + ory * (i + 1))]], color=col[j], **kwds) + col[j], col[j - 1] = col[j - 1], col[j] else: - a += line([(nx*j+orx*i, ny*j+ory*i), (nx*j+orx*(i+1), ny*j+ory*(i+1))], color=col[j], **kwds) + a += line([(nx * j + orx * i, ny * j + ory * i), (nx * j + orx * (i + 1), ny * j + ory * (i + 1))], color=col[j], **kwds) a.set_aspect_ratio(aspect_ratio) a.axes(axes) return a @@ -664,6 +638,7 @@ def plot3d(self, color='rainbow'): """ from sage.plot.colors import rainbow from sage.plot.plot3d.shapes2 import bezier3d + b = [] n = self.strands() if isinstance(color, (list, tuple)): @@ -673,27 +648,23 @@ def plot3d(self, color='rainbow'): elif color == "rainbow": col = rainbow(n) else: - col = [color]*n + col = [color] * n braid = self.Tietze() for i, m in enumerate(braid): for j in range(n): - if m == j+1: - b.append(bezier3d([[(0, j, i), (0, j, i+0.25), (0.25, j, i+0.25), (0.25, j+0.5, i+0.5)], - [(0.25, j+1, i+0.75), (0, j+1, i+0.75), (0, j+1, i+1)]], color=col[j])) - elif -m == j+1: - b.append(bezier3d([[(0, j, i), (0, j, i+0.25), (-0.25, j, i+0.25), (-0.25, j+0.5, i+0.5)], - [(-0.25, j+1, i+0.75), (0, j+1, i+0.75), (0, j+1, i+1)]], color=col[j])) + if m == j + 1: + b.append(bezier3d([[(0, j, i), (0, j, i + 0.25), (0.25, j, i + 0.25), (0.25, j + 0.5, i + 0.5)], [(0.25, j + 1, i + 0.75), (0, j + 1, i + 0.75), (0, j + 1, i + 1)]], color=col[j])) + elif -m == j + 1: + b.append(bezier3d([[(0, j, i), (0, j, i + 0.25), (-0.25, j, i + 0.25), (-0.25, j + 0.5, i + 0.5)], [(-0.25, j + 1, i + 0.75), (0, j + 1, i + 0.75), (0, j + 1, i + 1)]], color=col[j])) elif m == j: - b.append(bezier3d([[(0, j, i), (0, j, i+0.25), (-0.25, j, i+0.25), (-0.25, j-0.5, i+0.5)], - [(-0.25, j-1, i+0.75), (0, j-1, i+0.75), (0, j-1, i+1)]], color=col[j])) - col[j], col[j-1] = col[j-1], col[j] + b.append(bezier3d([[(0, j, i), (0, j, i + 0.25), (-0.25, j, i + 0.25), (-0.25, j - 0.5, i + 0.5)], [(-0.25, j - 1, i + 0.75), (0, j - 1, i + 0.75), (0, j - 1, i + 1)]], color=col[j])) + col[j], col[j - 1] = col[j - 1], col[j] elif -m == j: - b.append(bezier3d([[(0, j, i), (0, j, i+0.25), (0.25, j, i+0.25), (0.25, j-0.5, i+0.5)], - [(0.25, j-1, i+0.75), (0, j-1, i+0.75), (0, j-1, i+1)]], color=col[j])) - col[j], col[j-1] = col[j-1], col[j] + b.append(bezier3d([[(0, j, i), (0, j, i + 0.25), (0.25, j, i + 0.25), (0.25, j - 0.5, i + 0.5)], [(0.25, j - 1, i + 0.75), (0, j - 1, i + 0.75), (0, j - 1, i + 1)]], color=col[j])) + col[j], col[j - 1] = col[j - 1], col[j] else: - b.append(bezier3d([[(0, j, i), (0, j, i+1)]], color=col[j])) + b.append(bezier3d([[(0, j, i), (0, j, i + 1)]], color=col[j])) return sum(b) def LKB_matrix(self, variables='x,y'): @@ -821,13 +792,12 @@ def TL_matrix(self, drain_size, variab=None, sparse=True): else: R = variab.parent() rep = self.parent().TL_representation(drain_size, variab) - M = identity_matrix(R, self.parent().dimension_of_TL_space(drain_size), - sparse=sparse) + M = identity_matrix(R, self.parent().dimension_of_TL_space(drain_size), sparse=sparse) for i in self.Tietze(): if i > 0: - M = M*rep[i-1][0] + M = M * rep[i - 1][0] if i < 0: - M = M*rep[-i-1][1] + M = M * rep[-i - 1][1] return M def links_gould_matrix(self, symbolics=False): @@ -866,9 +836,9 @@ def links_gould_matrix(self, symbolics=False): M = rep[0][0].parent().one() for i in self.Tietze(): if i > 0: - M = M * rep[i-1][0] + M = M * rep[i - 1][0] if i < 0: - M = M * rep[-i-1][1] + M = M * rep[-i - 1][1] return M @cached_method @@ -917,8 +887,7 @@ def links_gould_polynomial(self, varnames=None, use_symbolics=False): R = LaurentPolynomialRing(ZZ, varnames) # partial quantum trace according to I. Marin section 2.5 - part_trace = matrix(B, 4, 4, lambda i, j: sum(M[e * i + k, e * j + k] - for k in range(e))) + part_trace = matrix(B, 4, 4, lambda i, j: sum(M[e * i + k, e * j + k] for k in range(e))) ptemp = part_trace[0, 0] # part_trace == psymb*M.parent().one() if use_symbolics: v1, v2 = R.variable_names() @@ -930,7 +899,7 @@ def links_gould_polynomial(self, varnames=None, use_symbolics=False): # Since the result of the calculation is known to be a Laurent polynomial # in t0 and t1 all exponents of ltemp must be divisible by 2 L = ltemp.parent() - lred = L({(k[0]/2, k[1]/2): v for k, v in ltemp.monomial_coefficients().items()}) + lred = L({(k[0] / 2, k[1] / 2): v for k, v in ltemp.monomial_coefficients().items()}) t0, t1 = R.gens() return lred(t0, t1) @@ -960,23 +929,24 @@ def tropical_coordinates(self) -> list: """ coord = [0, 1] * self.strands() for s in self.Tietze(): - k = 2*(abs(s)-1) - x1, y1, x2, y2 = coord[k:k+4] + k = 2 * (abs(s) - 1) + x1, y1, x2, y2 = coord[k : k + 4] if s > 0: sign = 1 z = x1 - min(y1, 0) - x2 + max(y2, 0) - coord[k+1] = y2 - max(z, 0) - coord[k+3] = y1 + max(z, 0) + coord[k + 1] = y2 - max(z, 0) + coord[k + 3] = y1 + max(z, 0) else: sign = -1 z = x1 + min(y1, 0) - x2 - max(y2, 0) - coord[k+1] = y2 + min(z, 0) - coord[k+3] = y1 - min(z, 0) + coord[k + 1] = y2 + min(z, 0) + coord[k + 3] = y1 - min(z, 0) - coord[k] = x1 + sign*(max(y1, 0) + max(max(y2, 0) - sign*z, 0)) - coord[k+2] = x2 + sign*(min(y2, 0) + min(min(y1, 0) + sign*z, 0)) + coord[k] = x1 + sign * (max(y1, 0) + max(max(y2, 0) - sign * z, 0)) + coord[k + 2] = x2 + sign * (min(y2, 0) + min(min(y1, 0) + sign * z, 0)) from sage.rings.semirings.tropical_semiring import TropicalSemiring + T = TropicalSemiring(ZZ) return [T(c) for c in coord] @@ -1025,17 +995,16 @@ def markov_trace(self, variab=None, normalized=True): R = LaurentPolynomialRing(ZZ, 'A') A = R.gens()[0] one = ZZ.one() - quantum_integer = lambda d: R({i: one for i in range(-2*d, 2*d+1, 4)}) + quantum_integer = lambda d: R({i: one for i in range(-2 * d, 2 * d + 1, 4)}) else: A = variab - quantum_integer = lambda d: (A**(2*(d+1))-A**(-2*(d+1))) // (A**2-A**(-2)) + quantum_integer = lambda d: (A ** (2 * (d + 1)) - A ** (-2 * (d + 1))) // (A**2 - A ** (-2)) n = self.strands() - trace_sum = sum(quantum_integer(d) * self.TL_matrix(d, variab=variab).trace() - for d in range(n+1) if (n+d) % 2 == 0) + trace_sum = sum(quantum_integer(d) * self.TL_matrix(d, variab=variab).trace() for d in range(n + 1) if (n + d) % 2 == 0) if normalized: - delta = A**2 + A**(-2) + delta = A**2 + A ** (-2) trace_sum = trace_sum / delta**n return trace_sum @@ -1071,10 +1040,10 @@ def _jones_polynomial(self): """ trace = self.markov_trace(normalized=False) A = trace.parent().gens()[0] - D = A**2 + A**(-2) + D = A**2 + A ** (-2) exp_sum = self.exponent_sum() num_comp = self.components_in_closure() - return (-1)**(num_comp-1) * A**(2*exp_sum) * trace // D + return (-1) ** (num_comp - 1) * A ** (2 * exp_sum) * trace // D def jones_polynomial(self, variab=None, skein_normalization=False): r""" @@ -1169,9 +1138,10 @@ def jones_polynomial(self, variab=None, skein_normalization=False): variab = 't' if not isinstance(variab, Expression): from sage.symbolic.ring import SR + variab = SR(variab) # We force the result to be in the symbolic ring because of the expand - return self._jones_polynomial(variab**(ZZ(1)/ZZ(4))).expand() + return self._jones_polynomial(variab ** (ZZ(1) / ZZ(4))).expand() @cached_method def _enhanced_states(self): @@ -1230,6 +1200,7 @@ def _enhanced_states(self): """ from sage.functions.generalized import sgn from sage.graphs.graph import Graph + crossinglist = self.Tietze() ncross = len(crossinglist) writhe = 0 @@ -1257,11 +1228,7 @@ def _enhanced_states(self): crossings[prevbelow]["next_below"] = i else: crossings[prevbelow]["next_above"] = i - crossings[i] = {"cr": cr, - "prev_above": prevabove, - "prev_below": prevbelow, - "next_above": None, - "next_below": None} + crossings[i] = {"cr": cr, "prev_above": prevabove, "prev_below": prevbelow, "next_above": None, "next_below": None} last_crossing_in_row[abs(cr) - 1] = i last_crossing_in_row[abs(cr)] = i # tie up the ends of the list @@ -1282,10 +1249,10 @@ def _enhanced_states(self): # generate all the resolutions for i in range(2**ncross): v = Integer(i).bits() - v = v + [0]*(ncross - len(v)) + v = v + [0] * (ncross - len(v)) G = Graph() for j, cr in enumerate(crossings): - if (v[j]*2-1)*sgn(cr["cr"]) == -1: # oriented resolution + if (v[j] * 2 - 1) * sgn(cr["cr"]) == -1: # oriented resolution G.add_edge((j, cr["next_above"], abs(cr["cr"]) - 1), (j, 1)) G.add_edge((cr["prev_above"], j, abs(cr["cr"]) - 1), (j, 1)) G.add_edge((j, cr["next_below"], abs(cr["cr"])), (j, 3)) @@ -1310,18 +1277,17 @@ def _enhanced_states(self): trivial *= -1 else: circle.add(vertex) - trivial = (1-trivial) // 2 # convert to 0 - trivial, 1 - non-trivial + trivial = (1 - trivial) // 2 # convert to 0 - trivial, 1 - non-trivial sm.append((frozenset(circle), trivial)) smoothings.append((tuple(v), sm)) states = {} for sm in smoothings: iindex = (writhe - ncross) // 2 + sum(sm[0]) - for m in range(2**len(sm[1])): - m = [2*x-1 for x in Integer(m).bits()] - m = m + [-1]*(len(sm[1]) - len(m)) - qagrad = (writhe + iindex + sum(m), - sum([x for i, x in enumerate(m) if sm[1][i][1] == 1])) + for m in range(2 ** len(sm[1])): + m = [2 * x - 1 for x in Integer(m).bits()] + m = m + [-1] * (len(sm[1]) - len(m)) + qagrad = (writhe + iindex + sum(m), sum([x for i, x in enumerate(m) if sm[1][i][1] == 1])) circpos = set() circneg = set() for i, x in enumerate(m): @@ -1364,6 +1330,7 @@ def _annular_khovanov_complex_cached(self, qagrad, ring=None): {1: Z, 2: Z, 3: 0} """ from sage.homology.chain_complex import ChainComplex + if ring is None: ring = ZZ states = self._enhanced_states() @@ -1374,15 +1341,15 @@ def _annular_khovanov_complex_cached(self, qagrad, ring=None): return ChainComplex() C_differentials = {} for i in bases: - if i+1 in bases: - m = matrix(ring, len(bases[i+1]), len(bases[i]), sparse=True) + if i + 1 in bases: + m = matrix(ring, len(bases[i + 1]), len(bases[i]), sparse=True) for ii in range(m.nrows()): - source = bases[i+1][ii] + source = bases[i + 1][ii] for jj in range(m.ncols()): target = bases[i][jj] difs = [index for index, value in enumerate(source[0]) if value != target[0][index]] if len(difs) == 1 and not (target[2].intersection(source[1]) or target[1].intersection(source[2])): - m[ii, jj] = (-1)**sum(target[0][:difs[0]]) + m[ii, jj] = (-1) ** sum(target[0][: difs[0]]) else: m = matrix(ring, 0, len(bases[i]), sparse=True) C_differentials[i] = m @@ -1443,8 +1410,7 @@ def annular_khovanov_complex(self, qagrad=None, ring=None): if ring is None: ring = ZZ if qagrad is None: - return {qa: self._annular_khovanov_complex_cached(qa, ring) - for qa in self._enhanced_states()} + return {qa: self._annular_khovanov_complex_cached(qa, ring) for qa in self._enhanced_states()} return self._annular_khovanov_complex_cached(qagrad, ring) def annular_khovanov_homology(self, qagrad=None, ring=ZZ): @@ -1549,7 +1515,7 @@ def left_normal_form(self, algorithm='libbraiding'): if algorithm == 'libbraiding': lnf = leftnormalform(self) B = self.parent() - return tuple([B.delta()**lnf[0][0]] + [B(b) for b in lnf[1:]]) + return tuple([B.delta() ** lnf[0][0]] + [B(b) for b in lnf[1:]]) if algorithm == 'artin': return FiniteTypeArtinGroupElement.left_normal_form.f(self) raise ValueError("invalid algorithm") @@ -1608,12 +1574,12 @@ def _left_normal_form_coxeter(self): while S: a = list(S)[0] form[i] = form[i] * sr[a] - form[i + 1] = sr[a] * form[i+1] + form[i + 1] = sr[a] * form[i + 1] e = form[i].idescents(from_zero=False) s = form[i + 1].descents(from_zero=False) S = set(s).difference(set(e)) - if form[i+1].length() == 0: - form.pop(i+1) + if form[i + 1].length() == 0: + form.pop(i + 1) i = 0 else: i += 1 @@ -1642,7 +1608,7 @@ def right_normal_form(self): """ rnf = rightnormalform(self) B = self.parent() - return tuple([B(b) for b in rnf[:-1]] + [B.delta()**rnf[-1][0]]) + return tuple([B(b) for b in rnf[:-1]] + [B.delta() ** rnf[-1][0]]) def centralizer(self) -> list: """ @@ -2142,7 +2108,7 @@ def deformed_burau_matrix(self, variab='q'): gens_str += [f'{s}m_{i}' for i in minus for s in 'bca'] alg_ZZ = FreeAlgebra(ZZ, m3, gens_str) gen_indices = {k: i for i, k in enumerate(plus + minus)} - gens = [alg_ZZ.gens()[k:k + 3] for k in range(0, m3, 3)] + gens = [alg_ZZ.gens()[k : k + 3] for k in range(0, m3, 3)] M = identity_matrix(alg_ZZ, n) for k, i in enumerate(tz): @@ -2150,15 +2116,15 @@ def deformed_burau_matrix(self, variab='q'): b, c, a = gens[gen_indices[k]] # faster using row operations instead ? if i > 0: - A[i-1, i-1] = a + A[i - 1, i - 1] = a A[i, i] = 0 - A[i, i-1] = c - A[i-1, i] = b + A[i, i - 1] = c + A[i - 1, i] = b if i < 0: - A[-1-i, -1-i] = 0 + A[-1 - i, -1 - i] = 0 A[-i, -i] = a - A[-1-i, -i] = c - A[-i, -1-i] = b + A[-1 - i, -i] = c + A[-i, -1 - i] = b M = M * A alg_R = FreeAlgebra(R, m3, gens_str) @@ -2255,24 +2221,19 @@ def colored_jones_polynomial(self, N, variab=None, try_inverse=True): db = self.deformed_burau_matrix('q')[1:, 1:] q = db.parent().base_ring().base_ring().gen() n = db.ncols() - qword = sum((-1)**(s.cardinality() - 1) - * (q * db[list(s), list(s)]).quantum_determinant(q) - for s in Subsets(range(n)) if s) + qword = sum((-1) ** (s.cardinality() - 1) * (q * db[list(s), list(s)]).quantum_determinant(q) for s in Subsets(range(n)) if s) inverse_shorter = try_inverse if try_inverse: db_inv = self.inverse().deformed_burau_matrix('q')[1:, 1:] q_inv = db_inv.parent().base_ring().base_ring().gen() - qword_inv = sum((-1)**(s.cardinality() - 1) - * (q_inv*db_inv[list(s), list(s)]).quantum_determinant(q_inv) - for s in Subsets(range(n)) if s) + qword_inv = sum((-1) ** (s.cardinality() - 1) * (q_inv * db_inv[list(s), list(s)]).quantum_determinant(q_inv) for s in Subsets(range(n)) if s) # Check if the inverse has a shorter expression at this point inverse_shorter = len(list(qword_inv)) < len(list(qword)) use_inverse = try_inverse and inverse_shorter shorter_qword = qword_inv if use_inverse else qword knot = Knot(self.inverse()) if use_inverse else Knot(self) - cj = (q**((N - 1) * (knot.writhe() - self.strands() + 1) / 2) - * self._colored_jones_sum(N, shorter_qword)) - self._cj_with_q[N] = cj.subs({q: 1/q}) if use_inverse else cj + cj = q ** ((N - 1) * (knot.writhe() - self.strands() + 1) / 2) * self._colored_jones_sum(N, shorter_qword) + self._cj_with_q[N] = cj.subs({q: 1 / q}) if use_inverse else cj return self.colored_jones_polynomial(N, variab, try_inverse) def super_summit_set_element(self): @@ -2386,6 +2347,7 @@ class RightQuantumWord: q*cp_1*ap_1 + q^2*bp_1*cm_0*am_0*bm_2 reduced from ap_1*cp_1 + q^3*bm_2*bp_1*am_0*cm_0 """ + def __init__(self, words): r""" Initialize ``self``. @@ -2410,11 +2372,9 @@ def __init__(self, words): self.R = self._algebra.base_ring() self._unreduced_words = words self._gens = self._algebra._indices.gens() - self._minus_begin = min((i for i, gen in enumerate(self._gens) if 'm' in str(gen)), - default=len(self._gens)) // 3 + self._minus_begin = min((i for i, gen in enumerate(self._gens) if 'm' in str(gen)), default=len(self._gens)) // 3 split = ((g, str(g), i) for i, g in enumerate(self._gens)) - self._recognize = {g: (s[0], s[1] == 'm', 3 * (i // 3)) - for g, s, i in split} + self._recognize = {g: (s[0], s[1] == 'm', 3 * (i // 3)) for g, s, i in split} @lazy_attribute def tuples(self): @@ -2449,6 +2409,7 @@ def tuples(self): (1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0) q^2 """ from collections import defaultdict + ret = defaultdict(self.R) convert = self._recognize q = self.q @@ -2462,13 +2423,13 @@ def tuples(self): if letter == 'a': # is_a ret_tuple[index + 2] += exp elif letter == 'b': # is_b - j, k = ret_tuple[index + 1:index + 3] + j, k = ret_tuple[index + 1 : index + 3] ret_tuple[index] += exp - q_power *= q**(2*(k*exp + j*exp)) if is_minus else iq**(2*j*exp) + q_power *= q ** (2 * (k * exp + j * exp)) if is_minus else iq ** (2 * j * exp) else: # is_c k = ret_tuple[index + 2] ret_tuple[index + 1] += exp - q_power *= iq**(k*exp) if is_minus else q**(k*exp) + q_power *= iq ** (k * exp) if is_minus else q ** (k * exp) ret[tuple(ret_tuple)] += q_power return ret @@ -2519,11 +2480,9 @@ def reduced_word(self): M = self._algebra._indices def tuple_to_word(q_tuple): - return M.prod(self._gens[i]**exp - for i, exp in enumerate(q_tuple)) + return M.prod(self._gens[i] ** exp for i, exp in enumerate(q_tuple)) - ret = {tuple_to_word(q_tuple): q_factor - for q_tuple, q_factor in self.tuples.items() if q_factor} + ret = {tuple_to_word(q_tuple): q_factor for q_tuple, q_factor in self.tuples.items() if q_factor} return self._algebra._from_dict(ret, remove_zeros=False) def eps(self, N): @@ -2562,27 +2521,19 @@ def eps(self, N): Parallelize this function, calculating all summands in the sum in parallel. """ + def eps_monom(q_tuple): r""" Evaluate the map `\mathcal{E}_N` for a single monomial. """ q = self.q - ret_q = q**sum((N - 1 - q_tuple[3*i + 2])*q_tuple[3*i + 1] - for i in range(self._minus_begin)) - ret_q *= q**sum((N - 1)*(-q_tuple[rj]) - for rj in range(self._minus_begin * 3 + 1, - len(q_tuple), 3)) - ret_q *= prod(prod(1 - q**(N - 1 - q_tuple[3*i + 1] - h) - for h in range(q_tuple[3*i + 2])) - for i in range(self._minus_begin)) - ret_q *= prod(prod(1 - q**(q_tuple[3*j + 1] + k + 1 - N) - for k in range(q_tuple[3*j + 2])) - for j in range(self._minus_begin, - len(q_tuple)//3)) + ret_q = q ** sum((N - 1 - q_tuple[3 * i + 2]) * q_tuple[3 * i + 1] for i in range(self._minus_begin)) + ret_q *= q ** sum((N - 1) * (-q_tuple[rj]) for rj in range(self._minus_begin * 3 + 1, len(q_tuple), 3)) + ret_q *= prod(prod(1 - q ** (N - 1 - q_tuple[3 * i + 1] - h) for h in range(q_tuple[3 * i + 2])) for i in range(self._minus_begin)) + ret_q *= prod(prod(1 - q ** (q_tuple[3 * j + 1] + k + 1 - N) for k in range(q_tuple[3 * j + 2])) for j in range(self._minus_begin, len(q_tuple) // 3)) return ret_q - return sum(q_factor * eps_monom(q_tuple) - for q_tuple, q_factor in self.tuples.items()) + return sum(q_factor * eps_monom(q_tuple) for q_tuple, q_factor in self.tuples.items()) def __repr__(self) -> str: r""" @@ -2598,9 +2549,7 @@ def __repr__(self) -> str: The right quantum word represented by cp_1*bp_3*am_2 reduced from cp_1*am_2*bp_3 """ - return ('The right quantum word represented by ' - + f'{str(self.reduced_word())} reduced from ' - + f'{str(self._unreduced_words)}') + return 'The right quantum word represented by ' + f'{str(self.reduced_word())} reduced from ' + f'{str(self._unreduced_words)}' class BraidGroup_class(FiniteTypeArtinGroup): @@ -2618,6 +2567,7 @@ class BraidGroup_class(FiniteTypeArtinGroup): sage: B2 is BraidGroup(3) True """ + Element = Braid def __init__(self, names) -> None: @@ -2681,11 +2631,9 @@ def __init__(self, names) -> None: rels = [] for i in range(1, n): rels.append(free_group([i, i + 1, i, -i - 1, -i, -i - 1])) - rels.extend(free_group([i, j, -i, -j]) - for j in range(i + 2, n + 1)) + rels.extend(free_group([i, j, -i, -j]) for j in range(i + 2, n + 1)) cat = Groups().Infinite() - FinitelyPresentedGroup.__init__(self, free_group, tuple(rels), - category=cat) + FinitelyPresentedGroup.__init__(self, free_group, tuple(rels), category=cat) self._nstrands = n + 1 self._coxeter_group = Permutations(self._nstrands) @@ -2706,7 +2654,7 @@ def __reduce__(self) -> tuple: sage: B.__reduce__() (, (('sigma0', 'sigma1'),)) """ - return (BraidGroup_class, (self.variable_names(), )) + return (BraidGroup_class, (self.variable_names(),)) def _repr_(self) -> str: """ @@ -2733,6 +2681,7 @@ def cardinality(self): +Infinity """ from sage.rings.infinity import Infinity + return Infinity order = cardinality @@ -2813,7 +2762,7 @@ def some_elements(self) -> list: """ elements_list = [self.gen(0)] elements_list.append(self(range(1, self.strands()))) - elements_list.append(elements_list[-1]**self.strands()) + elements_list.append(elements_list[-1] ** self.strands()) return elements_list def _standard_lift_Tietze(self, p) -> tuple: @@ -2876,19 +2825,23 @@ def _links_gould_representation(self, symbolics=False): True """ from sage.matrix.constructor import matrix + n = self.strands() d = 4 # dimension of the natural module from sage.matrix.special import diagonal_matrix + if symbolics: from sage.misc.functional import sqrt from sage.symbolic.ring import SR as BR + t0, t1 = BR.var('t0, t1') s0 = sqrt(t0) s1 = sqrt(t1) - Y = sqrt(-(t0 - 1)*(t1 - 1)) + Y = sqrt(-(t0 - 1) * (t1 - 1)) sparse = False else: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + LR = LaurentPolynomialRing(ZZ, 's0r, s1r') s0r, s1r = LR.gens() PR = PolynomialRing(LR, 'Yr') @@ -2903,17 +2856,11 @@ def _links_gould_representation(self, symbolics=False): sparse = True # degree one quantum trace operator as defined in I. Marin - mu = diagonal_matrix([t0**(-1), - t1, - t0**(-1), t1]) + mu = diagonal_matrix([t0 ** (-1), -t1, -(t0 ** (-1)), t1]) if n == 2: # R-Matrix taken from I. Marin - R = matrix(BR, {(0, 0): t0, (1, 4): s0, (2, 8): s0, (3, 12): 1, - (4, 1): s0, (4, 4): t0 - 1, (5, 5): -1, (6, 6): t0*t1 - 1, - (6, 9): -s0*s1, (6, 12): -Y*s0*s1, (7, 13): s1, (8, 2): s0, - (8, 8): t0 - 1, (9, 6): -s0*s1, (9, 12): Y, (10, 10): -1, - (11, 14): s1, (12, 3): 1, (12, 6): -Y*s0*s1, (12, 9): Y, - (12, 12): -(t0 - 1)*(t1 - 1), (13, 7): s1, (13, 13): t1 - 1, - (14, 11): s1, (14, 14): t1 - 1, (15, 15): t1}, sparse=sparse) - RI = (~t0 + ~t1)*(1 + R) - ~t0*~t1*(R + R**2) - 1 + R = matrix(BR, {(0, 0): t0, (1, 4): s0, (2, 8): s0, (3, 12): 1, (4, 1): s0, (4, 4): t0 - 1, (5, 5): -1, (6, 6): t0 * t1 - 1, (6, 9): -s0 * s1, (6, 12): -Y * s0 * s1, (7, 13): s1, (8, 2): s0, (8, 8): t0 - 1, (9, 6): -s0 * s1, (9, 12): Y, (10, 10): -1, (11, 14): s1, (12, 3): 1, (12, 6): -Y * s0 * s1, (12, 9): Y, (12, 12): -(t0 - 1) * (t1 - 1), (13, 7): s1, (13, 13): t1 - 1, (14, 11): s1, (14, 14): t1 - 1, (15, 15): t1}, sparse=sparse) + RI = (~t0 + ~t1) * (1 + R) - ~t0 * ~t1 * (R + R**2) - 1 # quantum trace operator on two fold tensor space E = mu.parent().one() @@ -2921,8 +2868,9 @@ def _links_gould_representation(self, symbolics=False): return ([R, RI], mu2) from sage.matrix.matrix_space import MatrixSpace + Ed = MatrixSpace(BR, d, d, sparse=sparse).one() - BGsub = BraidGroup(n-1) + BGsub = BraidGroup(n - 1) if n > 3: BG2 = BraidGroup(2) else: @@ -2935,7 +2883,7 @@ def _links_gould_representation(self, symbolics=False): # extend former generators lg = [(g.tensor_product(Ed), gi.tensor_product(Ed)) for g, gi in lg_sub] - En = MatrixSpace(BR, d**(n-2), d**(n-2), sparse=sparse).one() + En = MatrixSpace(BR, d ** (n - 2), d ** (n - 2), sparse=sparse).one() # define new generator gn = En.tensor_product(R) @@ -2985,7 +2933,7 @@ def _LKB_matrix_(self, braid, variab): if len(braid) > 1: A = self._LKB_matrix_(braid[:1], variab) for i in braid[1:]: - A = A*self._LKB_matrix_((i,), variab) + A = A * self._LKB_matrix_((i,), variab) return A n2 = [set(X) for X in combinations(range(n), 2)] R = LaurentPolynomialRing(ZZ, variab) @@ -2999,43 +2947,43 @@ def _LKB_matrix_(self, braid, variab): for m in range(len(n2)): j = min(n2[m]) k = max(n2[m]) - if i == j-1: + if i == j - 1: A[n2.index(Set([i, k])), m] = q - A[n2.index(Set([i, j])), m] = q*q-q - A[n2.index(Set([j, k])), m] = 1-q - elif i == j and not j == k-1: + A[n2.index(Set([i, j])), m] = q * q - q + A[n2.index(Set([j, k])), m] = 1 - q + elif i == j and not j == k - 1: A[n2.index(Set([j, k])), m] = 0 - A[n2.index(Set([j+1, k])), m] = 1 - elif k-1 == i and not k-1 == j: + A[n2.index(Set([j + 1, k])), m] = 1 + elif k - 1 == i and not k - 1 == j: A[n2.index(Set([j, i])), m] = q - A[n2.index(Set([j, k])), m] = 1-q - A[n2.index(Set([i, k])), m] = (1-q)*q*t + A[n2.index(Set([j, k])), m] = 1 - q + A[n2.index(Set([i, k])), m] = (1 - q) * q * t elif i == k: A[n2.index(Set([j, k])), m] = 0 - A[n2.index(Set([j, k+1])), m] = 1 - elif i == j and j == k-1: - A[n2.index(Set([j, k])), m] = -t*q*q + A[n2.index(Set([j, k + 1])), m] = 1 + elif i == j and j == k - 1: + A[n2.index(Set([j, k])), m] = -t * q * q else: A[n2.index(Set([j, k])), m] = 1 return A - i = -braid[0]-1 + i = -braid[0] - 1 for m in range(len(n2)): j = min(n2[m]) k = max(n2[m]) - if i == j-1: - A[n2.index(Set([j-1, k])), m] = 1 - elif i == j and not j == k-1: - A[n2.index(Set([j+1, k])), m] = q**(-1) - A[n2.index(Set([j, k])), m] = 1-q**(-1) - A[n2.index(Set([j, j+1])), m] = t**(-1)*q**(-1)-t**(-1)*q**(-2) - elif k-1 == i and not k-1 == j: - A[n2.index(Set([j, k-1])), m] = 1 + if i == j - 1: + A[n2.index(Set([j - 1, k])), m] = 1 + elif i == j and not j == k - 1: + A[n2.index(Set([j + 1, k])), m] = q ** (-1) + A[n2.index(Set([j, k])), m] = 1 - q ** (-1) + A[n2.index(Set([j, j + 1])), m] = t ** (-1) * q ** (-1) - t ** (-1) * q ** (-2) + elif k - 1 == i and not k - 1 == j: + A[n2.index(Set([j, k - 1])), m] = 1 elif i == k: - A[n2.index(Set([j, k+1])), m] = q**(-1) - A[n2.index(Set([j, k])), m] = 1-q**(-1) - A[n2.index(Set([k, k+1])), m] = -q**(-1)+q**(-2) - elif i == j and j == k-1: - A[n2.index(Set([j, k])), m] = -t**(-1)*q**(-2) + A[n2.index(Set([j, k + 1])), m] = q ** (-1) + A[n2.index(Set([j, k])), m] = 1 - q ** (-1) + A[n2.index(Set([k, k + 1])), m] = -(q ** (-1)) + q ** (-2) + elif i == j and j == k - 1: + A[n2.index(Set([j, k])), m] = -(t ** (-1)) * q ** (-2) else: A[n2.index(Set([j, k])), m] = 1 return A @@ -3080,7 +3028,7 @@ def dimension_of_TL_space(self, drain_size): raise ValueError("parity of strands and drains must agree") m = (n - drain_size) // 2 - return Integer(n-1).binomial(m) - Integer(n-1).binomial(m - 2) + return Integer(n - 1).binomial(m) - Integer(n - 1).binomial(m - 2) def TL_basis_with_drain(self, drain_size): """ @@ -3131,6 +3079,7 @@ def TL_basis_with_drain(self, drain_size): sage: B.dimension_of_TL_space(d) == len(B.TL_basis_with_drain(d)) True """ + def fill_out_forest(forest, treesize): # The basis elements are built recursively using this function, # which takes a collection of partial basis elements, given in @@ -3172,7 +3121,7 @@ def fill_out_forest(forest, treesize): # have a drain size of d, so we use fill_out_forest to build all basis # elements out of this basis = [[drain_size]] - forest = fill_out_forest(basis, n-1) + forest = fill_out_forest(basis, n - 1) for tree in forest: tree.extend([1, 0]) return forest @@ -3232,33 +3181,33 @@ def _TL_action(self, drain_size): for v, tree in enumerate(basis): # For each basis element if tree[i - 1] < tree[i] and tree[i + 1] < tree[i]: # Here, for instance, we've created an unknot. - auxmat[i-1, v] = v - if tree[i-1] > tree[i] and tree[i+1] > tree[i]: + auxmat[i - 1, v] = v + if tree[i - 1] > tree[i] and tree[i + 1] > tree[i]: newtree = list(tree) newtree[i] += 2 - auxmat[i-1, v] = basis.index(newtree) - if tree[i-1] > tree[i] and tree[i+1] < tree[i]: + auxmat[i - 1, v] = basis.index(newtree) + if tree[i - 1] > tree[i] and tree[i + 1] < tree[i]: newtree = list(tree) - newtree[i-1] -= 2 + newtree[i - 1] -= 2 j = 2 - while newtree[i-j] != newtree[i] and i-j >= 0: - newtree[i-j] -= 2 + while newtree[i - j] != newtree[i] and i - j >= 0: + newtree[i - j] -= 2 j += 1 if newtree in basis: - auxmat[i-1, v] = basis.index(newtree) + auxmat[i - 1, v] = basis.index(newtree) else: - auxmat[i-1, v] = -1 - if tree[i-1] < tree[i] and tree[i+1] > tree[i]: + auxmat[i - 1, v] = -1 + if tree[i - 1] < tree[i] and tree[i + 1] > tree[i]: newtree = list(tree) - newtree[i+1] -= 2 + newtree[i + 1] -= 2 j = 2 - while newtree[i+j] != newtree[i] and i+j <= n: - newtree[i+j] -= 2 + while newtree[i + j] != newtree[i] and i + j <= n: + newtree[i + j] -= 2 j += 1 if newtree in basis: - auxmat[i-1, v] = basis.index(newtree) + auxmat[i - 1, v] = basis.index(newtree) else: - auxmat[i-1, v] = -1 + auxmat[i - 1, v] = -1 return auxmat def TL_representation(self, drain_size, variab=None): @@ -3353,11 +3302,11 @@ def TL_representation(self, drain_size, variab=None): # Store the respective powers Ap2 = A**2 - Apm2 = A**(-2) - Ap4 = -A**4 - Apm4 = -A**(-4) + Apm2 = A ** (-2) + Ap4 = -(A**4) + Apm4 = -(A ** (-4)) - for i in range(n-1): # For each \sigma_{i+1} + for i in range(n - 1): # For each \sigma_{i+1} rep_mat_new = identity_matrix(R, dimension, sparse=True) rep_mat_new_inv = identity_matrix(R, dimension, sparse=True) for v in range(dimension): @@ -3427,6 +3376,7 @@ def _get_action_(self, S, op, self_on_left): Unknown result parent. """ import operator + if is_FreeGroup(S) and op == operator.mul and not self_on_left: return self.mapping_class_action(S) return None @@ -3449,8 +3399,8 @@ def _element_from_libbraiding(self, nf): 1 """ if len(nf) == 1: - return self.delta()**nf[0][0] - return self.delta()**nf[0][0] * prod(self(i) for i in nf[1:]) + return self.delta() ** nf[0][0] + return self.delta() ** nf[0][0] * prod(self(i) for i in nf[1:]) def mirror_involution(self): r""" @@ -3510,8 +3460,7 @@ def presentation_two_generators(self, isomorphisms=False): n = self.strands() F = FreeGroup(2, "x") rel = [n * (2,) + (n - 1) * (-1,)] - rel += [(1,) + (j - 1) * (2,) + (1,) + j * (-2,) + (-1,) + (j + 1) * (2,) + (-1,) + j * (-2,) - for j in range(2, n - 1)] + rel += [(1,) + (j - 1) * (2,) + (1,) + j * (-2,) + (-1,) + (j + 1) * (2,) + (-1,) + j * (-2,) for j in range(2, n - 1)] G = F / rel if not isomorphisms: return G @@ -3551,22 +3500,20 @@ def epimorphisms(self, H) -> list: """ G, hom1, hom2 = self.presentation_two_generators(isomorphisms=True) from sage.misc.misc_c import prod + HomSpace = self.Hom(H) G0g = libgap(self) Gg = libgap(G) Hg = libgap(H) gquotients = Gg.GQuotients(Hg) - hom1g = libgap.GroupHomomorphismByImagesNC(G0g, Gg, - [libgap(hom1(u)) - for u in self.gens()]) + hom1g = libgap.GroupHomomorphismByImagesNC(G0g, Gg, [libgap(hom1(u)) for u in self.gens()]) g0quotients = [hom1g * h for h in gquotients] res = [] # the following closure is needed to attach a specific value of quo to # each function in the different morphisms def fmap(tup): - return (lambda a: H(prod(tup[abs(i) - 1]**sign(i) - for i in a.Tietze()))) + return lambda a: H(prod(tup[abs(i) - 1] ** sign(i) for i in a.Tietze())) for quo in g0quotients: tup = tuple(H(quo.ImageElm(i.gap()).sage()) for i in self.gens()) @@ -3639,7 +3586,7 @@ def BraidGroup(n=None, names='s'): # Support Freegroup('a,b') syntax if n is not None: try: - n = Integer(n)-1 + n = Integer(n) - 1 except TypeError: names = n n = None @@ -3651,6 +3598,7 @@ def BraidGroup(n=None, names='s'): names = list(names) n = len(names) from sage.structure.category_object import normalize_names + names = normalize_names(n, names) return BraidGroup_class(names) @@ -3704,6 +3652,7 @@ class group of the punctured disk. sage: A(x1^-1, s1) x1*x2^-1*x1^-1 """ + def __init__(self, G, M) -> None: """ TESTS:: @@ -3715,6 +3664,7 @@ def __init__(self, G, M) -> None: on generators {a, b, c} """ import operator + Action.__init__(self, G, M, False, operator.mul) def _act_(self, b, x): @@ -3744,21 +3694,21 @@ def _act_(self, b, x): s = [] for i in t: if j == i and i > 0: - s += [i, i+1, -i] + s += [i, i + 1, -i] elif j == -i and i < 0: - s += [-i, i-1, i] + s += [-i, i - 1, i] elif j == -i and i > 0: - s += [i+1] + s += [i + 1] elif j == i and i < 0: - s += [i-1] - elif i > 0 and j == i-1: - s += [i-1] - elif i < 0 and j == -i-1: - s += [i+1] - elif i > 0 and -j == i-1: - s += [-i, i-1, i] - elif i < 0 and j == i+1: - s += [i, i+1, -i] + s += [i - 1] + elif i > 0 and j == i - 1: + s += [i - 1] + elif i < 0 and j == -i - 1: + s += [i + 1] + elif i > 0 and -j == i - 1: + s += [-i, i - 1, i] + elif i < 0 and j == i + 1: + s += [i, i + 1, -i] else: s += [i] t = s diff --git a/src/sage/groups/cactus_group.py b/src/sage/groups/cactus_group.py index 2348e9f8bac..bdc9c7bdc8c 100644 --- a/src/sage/groups/cactus_group.py +++ b/src/sage/groups/cactus_group.py @@ -69,6 +69,7 @@ class CactusGroup(UniqueRepresentation, Group): ....: for p in range(1, 6) for q in range(p+1, 6)) True """ + def __init__(self, n): r""" Initialize ``self``. @@ -95,10 +96,7 @@ def __init__(self, n): """ self._n = n ell = len(str(n)) - names = ['s{}{}'.format('0' * (ell - len(str(i))) + str(i), - '0' * (ell - len(str(j))) + str(j)) - for i in range(1, self._n + 1) - for j in range(i + 1, self._n + 1)] + names = ['s{}{}'.format('0' * (ell - len(str(i))) + str(i), '0' * (ell - len(str(j))) + str(j)) for i in range(1, self._n + 1) for j in range(i + 1, self._n + 1)] cat = Groups().FinitelyGeneratedAsMagma() if n > 2: cat = cat.Infinite() @@ -130,14 +128,11 @@ def _WG(self): frozenset({1, 3, 4}), frozenset({2, 3, 4}), frozenset({1, 2, 3, 4})] """ n = self._n - I = list(range(1, n+1)) - PS = sum(([frozenset(A) for A in combinations(I, k)] for k in range(2,n+1)), []) - G = Graph([list(range(len(PS))), - [[i,j,-1] for j in range(1, len(PS)) for i in range(j) - if PS[i] & PS[j] not in [frozenset(), PS[i], PS[j]]] - ], format='vertices_and_edges') + I = list(range(1, n + 1)) + PS = sum(([frozenset(A) for A in combinations(I, k)] for k in range(2, n + 1)), []) + G = Graph([list(range(len(PS))), [[i, j, -1] for j in range(1, len(PS)) for i in range(j) if PS[i] & PS[j] not in [frozenset(), PS[i], PS[j]]]], format='vertices_and_edges') self._subsets = PS - self._subsets_inv = {X: i for i,X in enumerate(PS)} + self._subsets_inv = {X: i for i, X in enumerate(PS)} return G def right_angled_coxeter_group(self): @@ -165,6 +160,7 @@ def right_angled_coxeter_group(self): from sage.rings.rational_field import QQ from sage.combinat.root_system.coxeter_group import CoxeterGroup from sage.combinat.root_system.coxeter_matrix import CoxeterMatrix + return CoxeterGroup(CoxeterMatrix(self._WG), base_ring=QQ) def _repr_(self): @@ -213,8 +209,7 @@ def group_generators(self): sage: J3.group_generators() Finite family {(1, 2): s[1,2], (1, 3): s[1,3], (2, 3): s[2,3]} """ - l = [(i, j) for i in range(1, self._n + 1) - for j in range(i + 1, self._n + 1)] + l = [(i, j) for i in range(1, self._n + 1) for j in range(i + 1, self._n + 1)] return Family(l, lambda x: self.element_class(self, [x])) @cached_method @@ -258,7 +253,7 @@ def gen(self, i, j=None): return self.gens()[i] if not (1 <= i < j <= self._n): raise ValueError(f"s[{i},{j}] is not a valid generator") - return self.element_class(self, [(i,j)]) + return self.element_class(self, [(i, j)]) @cached_method def one(self): @@ -373,6 +368,7 @@ def random_element(self, max_length=10): s[1,2]*s[2,3]*s[1,2]*s[1,3] """ from sage.misc.prandom import randint + l = randint(0, max_length) gens = list(self.group_generators()) ret = self.one() @@ -436,6 +432,7 @@ def bilinear_form(self, t=None): if t is None: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.integer_ring import ZZ + t = PolynomialRing(ZZ, 't').gen() R = t.parent() ret = [] @@ -444,9 +441,7 @@ def bilinear_form(self, t=None): for y in K: if x is y: ret.append(R.one()) - elif (x[1] < y[0] or x[0] > y[1] or # Disjoint - (x[0] <= y[0] and y[1] <= x[1]) or # y <= x - (y[0] <= x[0] and x[1] <= y[1])): # x <= y + elif x[1] < y[0] or x[0] > y[1] or (x[0] <= y[0] and y[1] <= x[1]) or (y[0] <= x[0] and x[1] <= y[1]): # Disjoint # y <= x # x <= y ret.append(R.zero()) else: ret.append(-t) @@ -520,6 +515,7 @@ def geometric_representation_generators(self, t=None): F = B.base_ring().fraction_field() K = self.group_generators().keys() from sage.modules.free_module import FreeModule + V = FreeModule(F, len(K)) basis = V.basis() ret = {} @@ -548,6 +544,7 @@ class Element(MultiplicativeGroupElement): """ An element of a cactus group. """ + def __init__(self, parent, data): """ Initialize ``self``. @@ -575,7 +572,7 @@ def _repr_(self): """ if not self._data: return '1' - return '*'.join(f"s[{i},{j}]" for i,j in self._data) + return '*'.join(f"s[{i},{j}]" for i, j in self._data) def _latex_(self): """ @@ -591,7 +588,7 @@ def _latex_(self): """ if not self._data: return '1' - return " ".join(f"s_{{{i},{j}}}" for i,j in self._data) + return " ".join(f"s_{{{i},{j}}}" for i, j in self._data) def _unicode_art_(self): """ @@ -612,11 +609,12 @@ def _unicode_art_(self): s₃,₁₁ """ from sage.typeset.unicode_art import unicode_subscript, unicode_art + if not self._data: return unicode_art('1') if self.parent()._n < 10: - return unicode_art(' '.join('s{}{}'.format(unicode_subscript(p), unicode_subscript(q)) for p,q in self._data)) - return unicode_art(' '.join('s{},{}'.format(unicode_subscript(p), unicode_subscript(q)) for p,q in self._data)) + return unicode_art(' '.join('s{}{}'.format(unicode_subscript(p), unicode_subscript(q)) for p, q in self._data)) + return unicode_art(' '.join('s{},{}'.format(unicode_subscript(p), unicode_subscript(q)) for p, q in self._data)) def __hash__(self): r""" @@ -728,7 +726,7 @@ def to_permutation(self): ret = P.one() for x in self._data: lst = list(range(1, n + 1)) - lst[x[0] - 1:x[1]] = list(reversed(lst[x[0] - 1:x[1]])) + lst[x[0] - 1 : x[1]] = list(reversed(lst[x[0] - 1 : x[1]])) ret *= P(lst) return ret @@ -765,7 +763,7 @@ def _matrix_(self): True """ G = self.parent().geometric_representation_generators() - ret = G[(1,2)].parent().one() + ret = G[(1, 2)].parent().one() for x in self._data: ret *= G[x] ret.set_immutable() @@ -810,11 +808,11 @@ def _normalize(self): G = P._WG # The defining graph # Convert to an element in the right-angled Coxeter group - perm = list(range(1,n+1)) + perm = list(range(1, n + 1)) word = [] - for p,q in self._data: - word.append(P._subsets_inv[frozenset(perm[p-1:q])]) - perm[p-1:q] = reversed(perm[p-1:q]) + for p, q in self._data: + word.append(P._subsets_inv[frozenset(perm[p - 1 : q])]) + perm[p - 1 : q] = reversed(perm[p - 1 : q]) # Normalize the word # This code works for any right-angled Coxeter group @@ -828,7 +826,7 @@ def _normalize(self): if G.has_edge(cur, i): continue did_swap = False - for j in range(pos+1, len(word)): + for j in range(pos + 1, len(word)): if word[j] == i: word.pop(j) if cur == i: # canceling s_i s_i = 1 @@ -846,15 +844,15 @@ def _normalize(self): # Convert back ret = [] - perm = list(range(1,n+1)) + perm = list(range(1, n + 1)) for i in word: X = P._subsets[i] - pos = [j for j,val in enumerate(perm) if val in X] - for j in range(len(pos)//2): - perm[pos[j]], perm[pos[-j-1]] = perm[pos[-j-1]], perm[pos[j]] + pos = [j for j, val in enumerate(perm) if val in X] + for j in range(len(pos) // 2): + perm[pos[j]], perm[pos[-j - 1]] = perm[pos[-j - 1]], perm[pos[j]] pos.sort() - assert all(pos[k] + 1 == pos[k+1] for k in range(len(pos)-1)) - ret.append((pos[0]+1, pos[-1]+1)) + assert all(pos[k] + 1 == pos[k + 1] for k in range(len(pos) - 1)) + ret.append((pos[0] + 1, pos[-1] + 1)) self._data = tuple(ret) @@ -872,6 +870,7 @@ class PureCactusGroup(KernelSubgroup): 1 \longrightarrow PJ_n \longrightarrow J_n \longrightarrow S_n \longrightarrow 1. """ + def __init__(self, n): r""" Initialize ``self``. @@ -885,6 +884,7 @@ def __init__(self, n): """ J = CactusGroup(n) from sage.groups.perm_gps.permgroup_named import SymmetricGroup + S = SymmetricGroup(n) KernelSubgroup.__init__(self, S.coerce_map_from(J)) @@ -972,6 +972,7 @@ def gens(self) -> tuple: True """ from sage.arith.misc import factorial + J = self.ambient() G = J.gens() one = J.one() @@ -993,7 +994,7 @@ def gens(self) -> tuple: gens = [] for s in reprs.values(): for g in G: - val = s * g * ~(reprs[(s*g).to_permutation()]) + val = s * g * ~(reprs[(s * g).to_permutation()]) if val == one or val in gens: continue gens.append(val) diff --git a/src/sage/groups/class_function.py b/src/sage/groups/class_function.py index 2152ce55561..6f022a4c8fb 100644 --- a/src/sage/groups/class_function.py +++ b/src/sage/groups/class_function.py @@ -200,8 +200,7 @@ def __richcmp__(self, other, op) -> bool: True """ if isinstance(other, ClassFunction): - return richcmp((self._group, self.values()), - (other._group, other.values()), op) + return richcmp((self._group, self.values()), (other._group, other.values()), op) return NotImplemented def __reduce__(self) -> tuple: @@ -428,7 +427,7 @@ def __pow__(self, other): """ if not isinstance(other, (int, Integer)): raise NotImplementedError - return ClassFunction(self._group, self._gap_classfunction ** other) + return ClassFunction(self._group, self._gap_classfunction**other) def symmetric_power(self, n): r""" @@ -569,8 +568,7 @@ def decompose(self) -> tuple: ((3, Character of Symmetric group of order 5! as a permutation group), (2, Character of Symmetric group of order 5! as a permutation group)) """ - L = [(self.scalar_product(irr), irr) - for irr in self.irreducible_constituents()] + L = [(self.scalar_product(irr), irr) for irr in self.irreducible_constituents()] return tuple(L) def norm(self): @@ -677,6 +675,7 @@ def restrict(self, H): gapH = H.gap() except AttributeError: from sage.libs.gap.libgap import libgap + gapH = libgap(H) rest = self._gap_classfunction.RestrictedClassFunction(gapH) return ClassFunction(H, rest) @@ -711,6 +710,7 @@ def induct(self, G): gapG = G.gap() except AttributeError: from sage.libs.gap.libgap import libgap + gapG = libgap(G) ind = self._gap_classfunction.InducedClassFunction(gapG) return ClassFunction(G, ind) diff --git a/src/sage/groups/conjugacy_classes.py b/src/sage/groups/conjugacy_classes.py index d3cdc849180..58327a05e5a 100644 --- a/src/sage/groups/conjugacy_classes.py +++ b/src/sage/groups/conjugacy_classes.py @@ -75,6 +75,7 @@ class ConjugacyClass(Parent): Conjugacy class of (1,2,3,4) in Symmetric group of order 4! as a permutation group """ + def __init__(self, group, element): r""" Generic conjugacy classes for elements in a group. @@ -115,8 +116,7 @@ def _repr_(self) -> str: Conjugacy class of (1,2,3,4) in Symmetric group of order 4! as a permutation group """ - return "Conjugacy class of %s in %s" % (self._representative, - self._parent) + return "Conjugacy class of %s in %s" % (self._representative, self._parent) def __eq__(self, other) -> bool: r""" @@ -223,11 +223,10 @@ def __iter__(self): True """ from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet + g = self._representative gens = self._parent.monoid_generators() - R = RecursivelyEnumeratedSet([g], - lambda y: [c * y * c**-1 for c in gens], - structure=None) + R = RecursivelyEnumeratedSet([g], lambda y: [c * y * c**-1 for c in gens], structure=None) return R.breadth_first_search_iterator() @cached_method @@ -278,11 +277,10 @@ def set(self): """ if self._parent.is_finite(): from sage.sets.set import Set + return Set(iter(self)) # return Set(self) creates an infinite loop in __contains__ - raise NotImplementedError("listing the elements of conjugacy classes " - "is not implemented for infinite groups; " - "use the iter function instead") + raise NotImplementedError("listing the elements of conjugacy classes " "is not implemented for infinite groups; " "use the iter function instead") def list(self) -> list: r""" @@ -304,9 +302,7 @@ def list(self) -> list: # return list(self) creates an infinite loop because list calls # __len__ which calls list... - raise NotImplementedError("listing the elements of conjugacy classes " - "is not implemented for infinite groups; " - "use the iter function instead") + raise NotImplementedError("listing the elements of conjugacy classes " "is not implemented for infinite groups; " "use the iter function instead") def is_real(self) -> bool: """ @@ -320,7 +316,7 @@ def is_real(self) -> bool: sage: c.is_real() True """ - return self._representative**(-1) in self + return self._representative ** (-1) in self def is_rational(self) -> bool: """ @@ -335,7 +331,7 @@ def is_rational(self) -> bool: False """ g = self._representative - return all(g**k in self.set() for k in range(2, g.order())) + return all(g ** k in self.set() for k in range(2, g.order())) def representative(self): """ @@ -374,6 +370,7 @@ class ConjugacyClassGAP(ConjugacyClass): Conjugacy class of (1,2,3,4) in Symmetric group of order 4! as a permutation group """ + def __init__(self, group, element) -> None: r""" Constructor for the class. @@ -521,6 +518,7 @@ def set(self): True """ from sage.sets.set import Set + try: cc = self._gap_conjugacy_class.AsList().sage() return Set([self._parent(x) for x in cc]) diff --git a/src/sage/groups/cubic_braid.py b/src/sage/groups/cubic_braid.py index ae61e9898ae..b1ecebba608 100644 --- a/src/sage/groups/cubic_braid.py +++ b/src/sage/groups/cubic_braid.py @@ -70,6 +70,7 @@ - Sebastian Oehms 2019-02-16, initial version. """ + # **************************************************************************** # Copyright (C) 2019 Sebastian Oehms # @@ -102,6 +103,7 @@ # ############################################################################## + def _reduce_tietze(tietze_list): r""" Reduce the length of a list representing a cubic braid as much as it is @@ -113,6 +115,7 @@ def _reduce_tietze(tietze_list): sage: _reduce_tietze((2, 2, -3, 5, 3, 1, 1, 5)) [-2, -5, -1] """ + def eliminate_item(tietze_list): """ This sub method searches for an item in the Tietze expression such @@ -131,7 +134,7 @@ def eliminate_item(tietze_list): if i == 1: second = tietze_list[i] break - if all(abs(abs(tietze_list[j])-abs(first)) > 1 for j in range(1, i)): + if all(abs(abs(tietze_list[j]) - abs(first)) > 1 for j in range(1, i)): # the entry on position i can be moved right to the first entry # by the second braid relation second = tietze_list[i] @@ -139,7 +142,7 @@ def eliminate_item(tietze_list): if second is None: return None middle = tietze_list[1:i] - end = tietze_list[i+1:l] + end = tietze_list[i + 1 : l] if first == second: return [-first] + middle + end return middle + end @@ -227,6 +230,7 @@ def AssionGroupU(n=None, names='u'): # ############################################################################## + class CubicBraidElement(FinitelyPresentedGroupElement): r""" Elements of cubic factor groups of the braid group. @@ -242,6 +246,7 @@ class CubicBraidElement(FinitelyPresentedGroupElement): sage: ele1 == ele2 True """ + def __init__(self, parent, x, check=True): """ Initialize ``self``. @@ -352,8 +357,7 @@ def braid(self): return braid_group(self) @cached_method - def burau_matrix(self, root_bur=None, domain=None, characteristic=None, - var='t', reduced=False): + def burau_matrix(self, root_bur=None, domain=None, characteristic=None, var='t', reduced=False): r""" Return the Burau matrix of the cubic braid coset. @@ -455,6 +459,7 @@ def burau_matrix(self, root_bur=None, domain=None, characteristic=None, braid = self.braid() from sage.misc.functional import cyclotomic_polynomial + min_pol_root_bur = cyclotomic_polynomial(6, var=var) unitary = False if isinstance(reduced, str): @@ -476,6 +481,7 @@ def burau_matrix(self, root_bur=None, domain=None, characteristic=None, root_bur = domain.gen(6) if root_bur is None: + def find_root(domain): min_pol = min_pol_root_bur.change_ring(domain) root_list = min_pol.roots() @@ -513,12 +519,14 @@ def find_root(domain): raise ValueError('characteristic must be a prime') if characteristic.is_zero(): from sage.rings.number_field.number_field import CyclotomicField + if unitary: domain = CyclotomicField(12) else: domain = CyclotomicField(3) else: from sage.rings.finite_rings.finite_field_constructor import GF + domain = GF(characteristic) root_bur = find_root(domain) domain = root_bur.parent() @@ -540,7 +548,7 @@ def find_root(domain): def conv2domain(laur_pol): l1, l2 = laur_pol.polynomial_construction() p1 = l1.change_ring(domain) - p2 = root_bur**(l2) + p2 = root_bur ** (l2) res = p1(root_bur) * p2 return res @@ -678,6 +686,7 @@ class type(Enum): ... TypeError: the cbg_type must be an instance of """ + Coxeter = 'C' AssionS = 'S' AssionU = 'U' @@ -703,7 +712,7 @@ def __classcall_private__(cls, n=None, names='c', cbg_type=None): # Support Freegroup('a,b') syntax if n is not None: try: - n = Integer(n)-1 + n = Integer(n) - 1 except TypeError: names = n @@ -717,6 +726,7 @@ def __classcall_private__(cls, n=None, names='c', cbg_type=None): n = len(names) from sage.structure.category_object import normalize_names + names = tuple(normalize_names(n, names)) return super().__classcall__(cls, names, cbg_type=cbg_type) @@ -758,24 +768,24 @@ def __init__(self, names, cbg_type=None): self._braid_group = BraidGroup(names) # internal naming of elements for convenience - b = [free_group([i]) for i in range(1, n+1)] - t = [free_group([i, i+1]) ** 3 for i in range(1, n)] - ti = [free_group([-i, -i-1]) ** 3 for i in range(1, n)] + b = [free_group([i]) for i in range(1, n + 1)] + t = [free_group([i, i + 1]) ** 3 for i in range(1, n)] + ti = [free_group([-i, -i - 1]) ** 3 for i in range(1, n)] # first the braid relations rels = list(self._braid_group.relations()) # than the cubic relations - rels.extend(b[i]**3 for i in range(n)) + rels.extend(b[i] ** 3 for i in range(n)) # than Assion's relation Satz 2.2 for cbg_type=CubicBraidGroup.type.AssionS # and Satz 2.4 for cbg_type=CubicBraidGroup.type.AssionU if n > 3: for i in range(n - 3): if cbg_type == CubicBraidGroup.type.AssionU: - rels.append((t[i]*t[i+2])**3) + rels.append((t[i] * t[i + 2]) ** 3) elif cbg_type == CubicBraidGroup.type.AssionS: - rels.append(b[i+2]*b[i]*t[i+1]*b[i]*ti[i+1]*t[i+2]*t[i+1]*b[i]*ti[i+1]*ti[i+2]) + rels.append(b[i + 2] * b[i] * t[i + 1] * b[i] * ti[i + 1] * t[i + 2] * t[i + 1] * b[i] * ti[i + 1] * ti[i + 2]) if cbg_type != CubicBraidGroup.type.Coxeter: cat = Groups().Finite() @@ -790,12 +800,12 @@ def __init__(self, names, cbg_type=None): # the following global pointers to classical group realizations will be set in the private method # _create_classical_realization # ------------------------------------------------------------------------------------------------ - self._classical_group = None # This is the classical Group returned by as_classical_group - self._classical_base_group = None # this only differs for special cases for Assion groups from the former - self._classical_invariant_form = None # invariant form of the classical base group - self._classical_embedding = None # if self._classical_group different from self._classical_base_group - self._centralizing_matrix = None # for Assion groups: element in classical base group commuting with self - self._centralizing_element = None # image under nat. map of the former one in the proj. classical group + self._classical_group = None # This is the classical Group returned by as_classical_group + self._classical_base_group = None # this only differs for special cases for Assion groups from the former + self._classical_invariant_form = None # invariant form of the classical base group + self._classical_embedding = None # if self._classical_group different from self._classical_base_group + self._centralizing_matrix = None # for Assion groups: element in classical base group commuting with self + self._centralizing_element = None # image under nat. map of the former one in the proj. classical group def _repr_(self) -> str: r""" @@ -810,8 +820,7 @@ def _repr_(self) -> str: """ if self._cbg_type == CubicBraidGroup.type.Coxeter: return "Cubic Braid group on %s strands" % (self.strands()) - return "Assion group on %s strands of type %s" % (self.strands(), - self._cbg_type.value) + return "Assion group on %s strands of type %s" % (self.strands(), self._cbg_type.value) def index_set(self): r""" @@ -857,8 +866,7 @@ def degrees(self): raise TypeError('not a finite reflection group') if self.strands() > 5: raise TypeError('not a finite reflection group') - d_table = {1: (), 2: (3,), 3: (4, 6), - 4: (6, 9, 12), 5: (12, 18, 24, 30)} + d_table = {1: (), 2: (3,), 3: (4, 6), 4: (6, 9, 12), 5: (12, 18, 24, 30)} return tuple(Integer(deg) for deg in d_table[self.strands()]) def codegrees(self): @@ -876,8 +884,7 @@ def codegrees(self): raise TypeError('not a finite reflection group') if self.strands() > 5: raise TypeError('not a finite reflection group') - d_table = {1: (), 2: (0,), 3: (0, 2), - 4: (0, 3, 6), 5: (0, 6, 12, 18)} + d_table = {1: (), 2: (0,), 3: (0, 2), 4: (0, 3, 6), 5: (0, 6, 12, 18)} return tuple(Integer(deg) for deg in d_table[self.strands()]) # ------------------------------------------------------------------------------- @@ -1007,6 +1014,7 @@ def _test_reflection_group(self, **options): """ if self._cbg_type == CubicBraidGroup.type.Coxeter and self.is_finite() and self.strands() > 2: from sage.combinat.root_system.reflection_group_real import is_chevie_available + if is_chevie_available(): tester = self._tester(**options) reflgrp = self.as_reflection_group() @@ -1149,10 +1157,12 @@ def create_sympl_realization(self, m): n = self.strands() from sage.groups.matrix_gps.symplectic import Sp + base_group = Sp(m, 3) proj_group = None if m == n: from sage.groups.perm_gps.permgroup_named import PSp + proj_group = PSp(m, 3) bform = base_group.invariant_form() @@ -1171,11 +1181,11 @@ def create_sympl_realization(self, m): # computing the List of transvection vectors according to # the Assion paper, page 292. # ----------------------------------------------------------- - transvections = [xbas[0]] # t_1 = x_1 - for i in range(mhalf-1): - transvections.append(ybas[i]) # t_{2i} = y_i - transvections.append(xbas[i] + xbas[i+1]) # t_{2i+1} = x_j + x_(j+1) - transvections.append(ybas[mhalf-1]) # t_n = y_m + transvections = [xbas[0]] # t_1 = x_1 + for i in range(mhalf - 1): + transvections.append(ybas[i]) # t_{2i} = y_i + transvections.append(xbas[i] + xbas[i + 1]) # t_{2i+1} = x_j + x_(j+1) + transvections.append(ybas[mhalf - 1]) # t_n = y_m # ----------------------------------------------------------- # Conversion-Map from transvection vector to transvection @@ -1184,13 +1194,13 @@ def create_sympl_realization(self, m): from sage.matrix.constructor import matrix def transvec2mat(v, bas=bas, bform=bform, fact=1): - t = [x + fact*(x * bform * v) * v for x in bas] + t = [x + fact * (x * bform * v) * v for x in bas] return matrix(bform.base_ring(), t) # ------------------------------------------------------------------------------ # setting the centralizing matrix for the case of projective group realization # ------------------------------------------------------------------------------ - centralizing_vector = xbas[mhalf-1] + centralizing_vector = xbas[mhalf - 1] centralizing_matrix = base_group(transvec2mat(centralizing_vector, fact=1)) transvec_matrices = [transvec2mat(v) for v in transvections] @@ -1221,10 +1231,12 @@ def create_unitary_realization(self, m): n = self.strands() from sage.groups.matrix_gps.unitary import GU + base_group = GU(m, 2) proj_group = None if m == n: from sage.groups.perm_gps.permgroup_named import PGU + proj_group = PGU(m, 2) bform = base_group.invariant_form() @@ -1240,25 +1252,25 @@ def create_unitary_realization(self, m): # ----------------------------------------------------------- xbas = [] for i in range(m): - if 2*i == m-1: + if 2 * i == m - 1: xbas.append(bas[i]) else: - xbas.append(a*bas[i] + a.frobenius()*bas[m-1 - i]) + xbas.append(a * bas[i] + a.frobenius() * bas[m - 1 - i]) # ----------------------------------------------------------- # computing the List of transvection vectors according to # Assion paper, page 293. # ----------------------------------------------------------- - transvections = [xbas[0]] # t_1 = x_1 + transvections = [xbas[0]] # t_1 = x_1 if m > 1: - transvections.append(xbas[0]+xbas[1]+xbas[2]) # t_2 = x_1 + x_2 + x_3 + transvections.append(xbas[0] + xbas[1] + xbas[2]) # t_2 = x_1 + x_2 + x_3 for j in range(mthird): - pos = 3*(j+1)-1 - transvections.append(xbas[pos-1]) # t_{3i} = x_{3i-1} + pos = 3 * (j + 1) - 1 + transvections.append(xbas[pos - 1]) # t_{3i} = x_{3i-1} if pos + 1 < m: - transvections.append(xbas[pos-1]+xbas[pos]+xbas[pos+1]) # t_{3i+1} = x_{3i-1} + x_{3i} + x_{3i+1} + transvections.append(xbas[pos - 1] + xbas[pos] + xbas[pos + 1]) # t_{3i+1} = x_{3i-1} + x_{3i} + x_{3i+1} if pos + 3 < m: - transvections.append(xbas[pos+1]+xbas[pos+2]+xbas[pos+3]) # t_{3i+2} = x_{3i+1} + x_{3i+2} + x_{3i+3} + transvections.append(xbas[pos + 1] + xbas[pos + 2] + xbas[pos + 3]) # t_{3i+2} = x_{3i+1} + x_{3i+2} + x_{3i+3} # ----------------------------------------------------------- # Conversion-Map from transvection vector to transvection @@ -1274,7 +1286,7 @@ def transvec2mat(v, bas=bas, bform=bform, fact=a): # ------------------------------------------------------------------------------ # setting the centralizing matrix for the case of projective group realization. # ------------------------------------------------------------------------------ - centralizing_vector = xbas[m-2]+xbas[m-1] + centralizing_vector = xbas[m - 2] + xbas[m - 1] centralizing_matrix = base_group(transvec2mat(centralizing_vector, fact=1)) transvec_matrices = [transvec2mat(v) for v in transvections] @@ -1294,14 +1306,14 @@ def transvec2mat(v, bas=bas, bform=bform, fact=a): # Setting the Classical group # ------------------------------------------------------------------------------- if self._cbg_type == CubicBraidGroup.type.AssionS: - dim_sympl_group = n-1 # S(n-1) = Sp(n-1, 3) + dim_sympl_group = n - 1 # S(n-1) = Sp(n-1, 3) if n % 2 == 0: - dim_sympl_group = n # S(n-1) = subgroup of PSp(n, 3) + dim_sympl_group = n # S(n-1) = subgroup of PSp(n, 3) create_sympl_realization(self, dim_sympl_group) elif self._cbg_type == CubicBraidGroup.type.AssionU: - dim_unitary_group = n-1 # U(n-1) = GU(n-1, 2) + dim_unitary_group = n - 1 # U(n-1) = GU(n-1, 2) if n % 3 == 0: - dim_unitary_group = n # U(n-1) = subgroup PGU(n, 3) + dim_unitary_group = n # U(n-1) = subgroup PGU(n, 3) create_unitary_realization(self, dim_unitary_group) else: # ----------------------------------------------------------------------------------------------- @@ -1520,9 +1532,7 @@ def as_matrix_group(self, root_bur=None, domain=None, characteristic=None, var=' unitary = True gen_list = [] for braid_gen in self.gens(): - bur_mat = braid_gen.burau_matrix(root_bur=root_bur, domain=domain, - characteristic=characteristic, - var=var, reduced=reduced) + bur_mat = braid_gen.burau_matrix(root_bur=root_bur, domain=domain, characteristic=characteristic, var=var, reduced=reduced) if unitary: bur_mat, bur_mat_ad, herm_form = bur_mat @@ -1539,6 +1549,7 @@ def as_matrix_group(self, root_bur=None, domain=None, characteristic=None, var=' if unitary: from sage.rings.finite_rings.finite_field_base import FiniteField from sage.groups.matrix_gps.unitary import GU + _, d = herm_form.dimensions() if isinstance(domain, FiniteField): base_group = GU(d, domain, var=domain.gen(), invariant_form=herm_form) @@ -1548,6 +1559,7 @@ def as_matrix_group(self, root_bur=None, domain=None, characteristic=None, var=' matrix_group = base_group.subgroup(gen_list) else: from sage.groups.matrix_gps.finitely_generated import MatrixGroup + cat = self.category() if self.is_finite() else None matrix_group = MatrixGroup(gen_list, category=cat) @@ -1598,6 +1610,7 @@ def as_permutation_group(self, use_classical=True): if use_classical: CG = self.as_classical_group() from sage.groups.perm_gps.permgroup import PermutationGroup_generic + if isinstance(CG, PermutationGroup_generic): return CG CGM = CG.as_matrix_group() @@ -1784,6 +1797,7 @@ def as_reflection_group(self): # 5 strands -> G32 # ------------------------------------------------------------------------------- from sage.combinat.root_system.reflection_group_real import is_chevie_available + if not is_chevie_available(): raise ImportError("the GAP3 package 'CHEVIE' is needed to obtain the corresponding reflection groups") @@ -1963,6 +1977,7 @@ def order(self): +Infinity """ from sage.rings.infinity import infinity + n = self.strands() if self._cbg_type == CubicBraidGroup.type.Coxeter and n > 5: @@ -2033,7 +2048,7 @@ def cubic_braid_subgroup(self, nstrands=None): raise ValueError("nstrands must be positive and less than %s" % (self.strands())) names = self.variable_names() - names_red = names[:nstrands - 1] + names_red = names[: nstrands - 1] subgrp = CubicBraidGroup(names=names_red, cbg_type=self._cbg_type) subgrp._ambient = self return subgrp diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index b0086b12dfb..9d6731bbc3c 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -170,6 +170,7 @@ class GroupMorphismWithGensImages(SetMorphism): x1 |--> () x2 |--> () """ + def _repr_defn(self): r""" Return the part of the representation that includes the images of the generators. @@ -409,13 +410,7 @@ def __hash__(self): # Finite groups - hash by permutation representation phi = G._perm_isomorphism() if phi is None: - raise NotImplementedError( - "hashing requires a confluent rewriting system\n" - "for infinite non-free finitely presented groups;\n" - "first compute one via " - "k = G.rewriting_system(); k.make_confluent();\n" - "G.set_confluent_rewriting_system(k)" - ) + raise NotImplementedError("hashing requires a confluent rewriting system\n" "for infinite non-free finitely presented groups;\n" "first compute one via " "k = G.rewriting_system(); k.make_confluent();\n" "G.set_confluent_rewriting_system(k)") perm_elem = libgap.Image(phi, self.gap()) return hash(perm_elem) @@ -530,6 +525,7 @@ class RewritingSystem: - Miguel Angel Marco Buzunariz (2013-12-16) """ + def __init__(self, G): """ Initialize ``self``. @@ -836,6 +832,7 @@ class FinitelyPresentedGroup(GroupMixinLibGAP, CachedRepresentation, Group, Pare sage: type(_) """ + Element = FinitelyPresentedGroupElement def __init__(self, free_group, relations, category=None, libgap_fpgroup=None): @@ -877,6 +874,7 @@ def __init__(self, free_group, relations, category=None, libgap_fpgroup=None): sage: TestSuite(J).run() """ from sage.groups.free_group import is_FreeGroup + assert is_FreeGroup(free_group) assert isinstance(relations, tuple) self._free_group = free_group @@ -918,7 +916,8 @@ def __richcmp__(self, other, op): """ if not isinstance(other, self.__class__): from sage.structure.richcmp import op_NE - return (op == op_NE) + + return op == op_NE self_data = (self._free_group, self._relations) other_data = (other._free_group, other._relations) return richcmp(self_data, other_data, op) @@ -957,15 +956,15 @@ def _latex_(self): """ r = '\\langle ' for i in range(self.ngens()): - r = r+self.gen(i)._latex_() - if i < self.ngens()-1: - r = r+', ' - r = r+' \\mid ' + r = r + self.gen(i)._latex_() + if i < self.ngens() - 1: + r = r + ', ' + r = r + ' \\mid ' for i in range(len(self._relations)): - r = r+(self._relations)[i]._latex_() - if i < len(self.relations())-1: - r = r+' , ' - r = r+'\\rangle' + r = r + (self._relations)[i]._latex_() + if i < len(self.relations()) - 1: + r = r + ' , ' + r = r + '\\rangle' return r def _regina_(self, regina): @@ -1085,6 +1084,7 @@ def cardinality(self, limit=4096000): with libgap.global_context('CosetTableDefaultMaxLimit', limit): if not libgap.IsFinite(self.gap()): from sage.rings.infinity import Infinity + return Infinity try: size = self.gap().Size() @@ -1148,8 +1148,8 @@ def as_permutation_group(self, limit=4096000): raise ValueError('Coset enumeration exceeded limit, is the group finite?') from sage.combinat.permutation import Permutation from sage.groups.perm_gps.permgroup import PermutationGroup - return PermutationGroup([ - Permutation(coset_table[2*i]) for i in range(len(coset_table)//2)]) + + return PermutationGroup([Permutation(coset_table[2 * i]) for i in range(len(coset_table) // 2)]) def direct_product(self, H, reduced=False, new_names=True): r""" @@ -1258,8 +1258,7 @@ def direct_product(self, H, reduced=False, new_names=True): gen_names = [str(g) for g in self.gens()] + [str(g) for g in H.gens()] # Build the direct product in Sage for better variable names ret_F = FreeGroup(gen_names) - ret_rls = tuple([ret_F(rel_word.TietzeWordAbstractWord(GAP_gens).sage()) - for rel_word in fp_product.RelatorsOfFpGroup()]) + ret_rls = tuple([ret_F(rel_word.TietzeWordAbstractWord(GAP_gens).sage()) for rel_word in fp_product.RelatorsOfFpGroup()]) ret_fpg = FinitelyPresentedGroup(ret_F, ret_rls) if reduced: ret_fpg = ret_fpg.simplified() @@ -1408,14 +1407,12 @@ def semidirect_product(self, H, hom, check=True, reduced=False): auto_grp = libgap.AutomorphismGroup(H.gap()) self_gens = [h.gap() for h in hom[0]] # construct image automorphisms in GAP - GAP_aut_imgs = [libgap.GroupHomomorphismByImages(GAP_H, GAP_H, [g.gap() for g in gns], - [i.gap() for i in img]) for (gns, img) in hom[1]] + GAP_aut_imgs = [libgap.GroupHomomorphismByImages(GAP_H, GAP_H, [g.gap() for g in gns], [i.gap() for i in img]) for (gns, img) in hom[1]] # check for automorphism validity in images of operation defining homomorphism, # and construct the defining homomorphism. if check: - if not all(a in libgap.List(libgap.AutomorphismGroup(GAP_H)) - for a in GAP_aut_imgs): + if not all(a in libgap.List(libgap.AutomorphismGroup(GAP_H)) for a in GAP_aut_imgs): raise ValueError("images of input homomorphism must be automorphisms") GAP_def_hom = libgap.GroupHomomorphismByImages(GAP_self, auto_grp, self_gens, GAP_aut_imgs) else: @@ -1433,8 +1430,7 @@ def semidirect_product(self, H, hom, check=True, reduced=False): GAP_gens = prod.FreeGeneratorsOfFpGroup() name_itr = _lexi_gen() # Python generator for lexicographical variable names ret_F = FreeGroup([next(name_itr) for i in GAP_gens]) - ret_rls = tuple([ret_F(rel_word.TietzeWordAbstractWord(GAP_gens).sage()) - for rel_word in prod.RelatorsOfFpGroup()]) + ret_rls = tuple([ret_F(rel_word.TietzeWordAbstractWord(GAP_gens).sage()) for rel_word in prod.RelatorsOfFpGroup()]) ret_fpg = FinitelyPresentedGroup(ret_F, ret_rls) if reduced: ret_fpg = ret_fpg.simplified() @@ -1686,7 +1682,7 @@ def sorted_presentation(self): L1 = [] for rel in L0: C = [rel] - C.extend(rel[j + 1:] + rel[:j + 1] for j in range(len(rel) - 1)) + C.extend(rel[j + 1 :] + rel[: j + 1] for j in range(len(rel) - 1)) C1 = [tuple(-j for j in reversed(l)) for l in C] C += C1 C.sort() @@ -1795,8 +1791,7 @@ def alexander_matrix(self, im_gens=None): """ rel = self.relations() gen = self._free_group.gens() - return matrix(len(rel), len(gen), - lambda i, j: rel[i].fox_derivative(gen[j], im_gens)) + return matrix(len(rel), len(gen), lambda i, j: rel[i].fox_derivative(gen[j], im_gens)) @cached_method def abelian_alexander_matrix(self, ring=QQ, simplified=True): @@ -1865,7 +1860,7 @@ def abelian_alexander_matrix(self, ring=QQ, simplified=True): A.swap_rows(0, i) A.swap_columns(0, j) for k in range(1, n): - A.add_multiple_of_row(k, 0, -A[k, 0] * p ** -1) + A.add_multiple_of_row(k, 0, -A[k, 0] * p**-1) A = A.delete_rows([0]).delete_columns([0]) n, m = A.dimensions() else: diff --git a/src/sage/groups/finitely_presented_named.py b/src/sage/groups/finitely_presented_named.py index 76df3fad7dd..b33f29dde2b 100644 --- a/src/sage/groups/finitely_presented_named.py +++ b/src/sage/groups/finitely_presented_named.py @@ -55,6 +55,7 @@ sage: CyclicPresentation(4) Finitely presented group < a | a^4 > """ + # **************************************************************************** # Copyright (C) 2013 Davis Shurbert # @@ -100,7 +101,7 @@ def CyclicPresentation(n) -> FinitelyPresentedGroup: if n < 1: raise ValueError('finitely presented group order must be positive') F = FreeGroup('a') - rls = F([1])**n, + rls = (F([1]) ** n,) return FinitelyPresentedGroup(F, rls) @@ -187,22 +188,20 @@ def FinitelyGeneratedAbelianPresentation(int_list): True """ from sage.groups.free_group import _lexi_gen + check_ls = [Integer(x) for x in int_list if Integer(x) >= 0] if len(check_ls) != len(int_list): raise ValueError('input list must contain nonnegative entries') col_sp = diagonal_matrix(int_list).column_space() - invariants = FGP_Module(ZZ**(len(int_list)), col_sp).invariants() + invariants = FGP_Module(ZZ ** (len(int_list)), col_sp).invariants() name_gen = _lexi_gen() F = FreeGroup([next(name_gen) for i in invariants]) - ret_rls = [F([i + 1])**invariants[i] for i in range(len(invariants)) - if invariants[i] != 0] + ret_rls = [F([i + 1]) ** invariants[i] for i in range(len(invariants)) if invariants[i] != 0] # Build commutator relations - gen_pairs = [[F.gen(i), F.gen(j)] for i in range(F.ngens() - 1) - for j in range(i + 1, F.ngens())] - ret_rls = ret_rls + [x[0]**(-1) * x[1]**(-1) * x[0] * x[1] - for x in gen_pairs] + gen_pairs = [[F.gen(i), F.gen(j)] for i in range(F.ngens() - 1) for j in range(i + 1, F.ngens())] + ret_rls = ret_rls + [x[0] ** (-1) * x[1] ** (-1) * x[0] * x[1] for x in gen_pairs] return FinitelyPresentedGroup(F, tuple(ret_rls)) @@ -274,11 +273,12 @@ def FinitelyGeneratedHeisenbergPresentation(n=1, p=0) -> FinitelyPresentedGroup: F = FreeGroup(str_generators) x = F.gens()[0:n] # list of generators x1, x2, ..., xn - y = F.gens()[n:2 * n] # list of generators x1, x2, ..., xn + y = F.gens()[n : 2 * n] # list of generators x1, x2, ..., xn z = F.gen(n * 2) def commutator(a, b): return a * b * a**-1 * b**-1 + # First set of relations: [xi, yi] = z r1 = [commutator(x[i], y[i]) * z**-1 for i in range(n)] # Second set of relations: [z, xi] = 1 @@ -290,6 +290,7 @@ def commutator(a, b): rls = r1 + r2 + r3 + r4 from sage.sets.primes import Primes + if p not in Primes() and p != 0: raise ValueError("p must be 0 or a prime number") if p > 0: @@ -329,7 +330,7 @@ def DihedralPresentation(n) -> FinitelyPresentedGroup: if n < 1: raise ValueError('finitely presented group order must be positive') F = FreeGroup(['a', 'b']) - rls = F([1])**n, F([2])**2, (F([1]) * F([2]))**2 + rls = F([1]) ** n, F([2]) ** 2, (F([1]) * F([2])) ** 2 return FinitelyPresentedGroup(F, rls) @@ -380,7 +381,7 @@ def DiCyclicPresentation(n) -> FinitelyPresentedGroup: raise ValueError('input integer must be greater than 1') F = FreeGroup(['a', 'b']) - rls = F([1])**(2 * n), F([2, 2]) * F([-1])**n, F([-2, 1, 2, 1]) + rls = F([1]) ** (2 * n), F([2, 2]) * F([-1]) ** n, F([-2, 1, 2, 1]) return FinitelyPresentedGroup(F, rls) @@ -430,8 +431,7 @@ def SymmetricPresentation(n) -> FinitelyPresentedGroup: image_gens = GAP_fp_rep.FreeGeneratorsOfFpGroup() name_itr = _lexi_gen() # Python generator object for variable names F = FreeGroup([next(name_itr) for x in perm_rep.gens()]) - ret_rls = tuple([F(rel_word.TietzeWordAbstractWord(image_gens).sage()) - for rel_word in GAP_fp_rep.RelatorsOfFpGroup()]) + ret_rls = tuple([F(rel_word.TietzeWordAbstractWord(image_gens).sage()) for rel_word in GAP_fp_rep.RelatorsOfFpGroup()]) return FinitelyPresentedGroup(F, ret_rls) @@ -457,7 +457,7 @@ def QuaternionPresentation() -> FinitelyPresentedGroup: True """ F = FreeGroup(['a', 'b']) - rls = F([1])**4, F([2, 2, -1, -1]), F([1, 2, 1, -2]) + rls = F([1]) ** 4, F([2, 2, -1, -1]), F([1, 2, 1, -2]) return FinitelyPresentedGroup(F, rls) @@ -507,8 +507,7 @@ def AlternatingPresentation(n) -> FinitelyPresentedGroup: image_gens = GAP_fp_rep.FreeGeneratorsOfFpGroup() name_itr = _lexi_gen() # Python generator object for variable names F = FreeGroup([next(name_itr) for x in perm_rep.gens()]) - ret_rls = tuple([F(rel_word.TietzeWordAbstractWord(image_gens).sage()) - for rel_word in GAP_fp_rep.RelatorsOfFpGroup()]) + ret_rls = tuple([F(rel_word.TietzeWordAbstractWord(image_gens).sage()) for rel_word in GAP_fp_rep.RelatorsOfFpGroup()]) return FinitelyPresentedGroup(F, ret_rls) @@ -524,7 +523,7 @@ def KleinFourPresentation() -> FinitelyPresentedGroup: Finitely presented group < a, b | a^2, b^2, a^-1*b^-1*a*b > """ F = FreeGroup(['a', 'b']) - rls = F([1])**2, F([2])**2, F([-1]) * F([-2]) * F([1]) * F([2]) + rls = F([1]) ** 2, F([2]) ** 2, F([-1]) * F([-2]) * F([1]) * F([2]) return FinitelyPresentedGroup(F, rls) @@ -576,6 +575,7 @@ def CactusPresentation(n) -> FinitelyPresentedGroup: s12^2, s13^2, s23^2, s13*s12*s13^-1*s23^-1, s13*s23*s13^-1*s12^-1 > """ from sage.groups.cactus_group import CactusGroup + G = CactusGroup(n) F = FreeGroup(G.variable_names()) gens = F.gens() diff --git a/src/sage/groups/fqf_orthogonal.py b/src/sage/groups/fqf_orthogonal.py index 7ded93f4e7c..8159f45fb78 100644 --- a/src/sage/groups/fqf_orthogonal.py +++ b/src/sage/groups/fqf_orthogonal.py @@ -159,6 +159,7 @@ class FqfOrthogonalGroup(AbelianGroupAutomorphismGroup_subgroup): sage: Q.1 * g (0, 1) """ + Element = FqfIsometry def __init__(self, ambient, gens, fqf, check=False): @@ -253,11 +254,12 @@ def _element_constructor_(self, x, check=True): sage: assert Oq(Oq.0.matrix()) == Oq.0 """ from sage.libs.gap.element import GapElement + if not isinstance(x, GapElement): try: # if there is an action try that gen = self.invariant_form().smith_form_gens() - x = matrix(ZZ, [(g*x).vector() for g in gen]) + x = matrix(ZZ, [(g * x).vector() for g in gen]) except TypeError: pass f = AbelianGroupAutomorphismGroup_subgroup._element_constructor_(self, x, check=True) @@ -285,12 +287,12 @@ def _preserves_form(self, f): True """ g = self.invariant_form().smith_form_gens() - gf = tuple(h*f for h in g) + gf = tuple(h * f for h in g) n = len(g) for i in range(n): if gf[i].q() != g[i].q(): return False - for j in range(i+1, n): + for j in range(i + 1, n): if g[i].b(g[j]) != gf[i].b(gf[j]): return False return True @@ -316,6 +318,7 @@ def _get_action_(self, S, op, self_on_left): [ 0 4/3] """ import operator + if op == operator.mul and not self_on_left: T = self.invariant_form() if S == T: @@ -323,15 +326,12 @@ def _get_action_(self, S, op, self_on_left): try: if S.is_submodule(T): # check if the submodule is invariant - if all(T(s)*g in S for s in S.gens() for g in self.gens()): + if all(T(s) * g in S for s in S.gens() for g in self.gens()): return ActionOnFqf(self, S, on_subquotient=True) - elif S.V().is_submodule(T.V()) and T.W().is_submodule(S.W()): # is a subquotient - Q1 = S.V()/T.W() - Q2 = S.W()/T.W() - if ( - all(T(q) * g in Q1 for q in Q1.gens() for g in self.gens()) and - all(T(q) * g in Q2 for q in Q2.gens() for g in self.gens()) - ): + elif S.V().is_submodule(T.V()) and T.W().is_submodule(S.W()): # is a subquotient + Q1 = S.V() / T.W() + Q2 = S.W() / T.W() + if all(T(q) * g in Q1 for q in Q1.gens() for g in self.gens()) and all(T(q) * g in Q2 for q in Q2.gens() for g in self.gens()): return ActionOnFqf(self, S, on_subquotient=True) except AttributeError: pass @@ -405,6 +405,7 @@ class ActionOnFqf(Action): sage: x * g (2, 0) """ + def __init__(self, orthogonal_grp, fqf, on_subquotient=False, is_left=False): r""" Initialize the action. @@ -421,6 +422,7 @@ def __init__(self, orthogonal_grp, fqf, on_subquotient=False, is_left=False): ValueError: the action is from the right """ import operator + self._on_subquotient = on_subquotient if is_left: raise ValueError("the action is from the right") @@ -479,9 +481,9 @@ def _act_(self, g, a): elif self._on_subquotient: S = a.parent() T = g.parent().invariant_form() - return S(T(a)*g) + return S(T(a) * g) else: - v = (a.vector()*g.matrix()) + v = a.vector() * g.matrix() P = a.parent() return P.linear_combination_of_smith_form_gens(v) @@ -516,6 +518,7 @@ def _isom_fqf(A, B=None): ....: q = TorsionQuadraticForm(q) ....: assert q.orthogonal_group().order()==GO(3, p).order() """ + def orbits(G, L): r""" Return the orbits of `L` under `G`. @@ -530,7 +533,7 @@ def orbits(G, L): D = G.invariant_form() A = G.domain() L = libgap([[A(g).gap() for g in f] for f in L]) - orb = G.gap().Orbits(L,libgap.OnTuples) + orb = G.gap().Orbits(L, libgap.OnTuples) orb = [g[0] for g in orb] orb = [[D.linear_combination_of_smith_form_gens(A(g).exponents()) for g in f] for f in orb] return orb @@ -559,12 +562,12 @@ def orbits(G, L): return f g = ambient(matrix(f)) if g not in G: - G = B.orthogonal_group(tuple(ambient(s.matrix()) for s in G.gens())+(g,)) + G = B.orthogonal_group(tuple(ambient(s.matrix()) for s in G.gens()) + (g,)) waiting = orbits(G, waiting) continue # extend f to an i+1 - partial isometry in all possible ways a = A.smith_form_gens()[i] - card = ZZ.prod(A.smith_form_gen(k).order() for k in range(i+1)) + card = ZZ.prod(A.smith_form_gen(k).order() for k in range(i + 1)) for b in b_cand[i]: if all(b.b(f[k]) == a.b(A.smith_form_gens()[k]) for k in range(i)): fnew = f + [b] diff --git a/src/sage/groups/free_group.py b/src/sage/groups/free_group.py index b25711d8b39..65f1eae3e16 100644 --- a/src/sage/groups/free_group.py +++ b/src/sage/groups/free_group.py @@ -98,6 +98,7 @@ def is_FreeGroup(x): if isinstance(x, FreeGroup_class): return True from sage.groups.indexed_free_group import IndexedFreeGroup + return isinstance(x, IndexedFreeGroup) @@ -217,14 +218,14 @@ def __init__(self, parent, x): if 0 in l: raise ValueError('zero does not denote a generator') i = 0 - while i < len(l)-1: - if l[i] == -l[i+1]: + while i < len(l) - 1: + if l[i] == -l[i + 1]: l.pop(i) l.pop(i) if i > 0: - i = i-1 + i = i - 1 else: - i = i+1 + i = i + 1 AbstractWordTietzeWord = libgap.eval('AbstractWordTietzeWord') x = AbstractWordTietzeWord(l, parent.gap().GeneratorsOfGroup()) ElementLibGAP.__init__(self, parent, x) @@ -270,6 +271,7 @@ def _latex_(self): 'x_{0}\\cdot x_{1}^{2}\\cdot x_{2}^{-1}\\cdot x_{0}^{-1}\\cdot x_{3}^{11}\\cdot x_{0}^{-12}' """ import re + s = self._repr_() s = re.sub('([a-z]|[A-Z])([0-9]+)', r'\g<1>_{\g<2>}', s) s = re.sub(r'(\^)(-)([0-9]+)', r'\g<1>{\g<2>\g<3>}', s) @@ -304,6 +306,7 @@ def _regina_(self, regina): """ import string + word = '' for i in self.Tietze(): if i > 0: @@ -479,7 +482,7 @@ def fox_derivative(self, gen, im_gens=None, ring=None): else: R = ring symb = list(im_gens) - symb += reversed([a**(-1) for a in im_gens]) + symb += reversed([a ** (-1) for a in im_gens]) i = gen.Tietze()[0] # so gen is the i-th generator of the free group @@ -489,12 +492,12 @@ def fox_derivative(self, gen, im_gens=None, ring=None): b = l.pop(0) if b == i: a += coef * R.one() - coef *= symb[b-1] + coef *= symb[b - 1] elif b == -i: a -= coef * symb[b] coef *= symb[b] elif b > 0: - coef *= symb[b-1] + coef *= symb[b - 1] else: coef *= symb[b] return a @@ -528,8 +531,8 @@ def syllables(self): result = [] gen = self.parent().gen for i in range(k): - exponent = exponent_syllable(g, i+1).sage() - generator = gen(generator_syllable(g, i+1).sage() - 1) + exponent = exponent_syllable(g, i + 1).sage() + generator = gen(generator_syllable(g, i + 1).sage() - 1) result.append((generator, exponent)) return tuple(result) @@ -608,11 +611,9 @@ def __call__(self, *values): replace = dict(zip(G.gens(), values)) new_parent = coercion_model.common_parent(*[parent(v) for v in values]) try: - return new_parent.prod(replace[gen] ** power - for gen, power in self.syllables()) + return new_parent.prod(replace[gen] ** power for gen, power in self.syllables()) except AttributeError: - return prod(new_parent(replace[gen]) ** power - for gen, power in self.syllables()) + return prod(new_parent(replace[gen]) ** power for gen, power in self.syllables()) def FreeGroup(n=None, names='x', index_set=None, abelian=False, **kwds): @@ -689,13 +690,16 @@ def FreeGroup(n=None, names='x', index_set=None, abelian=False, **kwds): names = list(names) n = len(names) from sage.structure.category_object import normalize_names + names = normalize_names(n, names) if index_set is not None or abelian: if abelian: from sage.groups.indexed_free_group import IndexedFreeAbelianGroup + return IndexedFreeAbelianGroup(index_set, names=names, **kwds) from sage.groups.indexed_free_group import IndexedFreeGroup + return IndexedFreeGroup(index_set, names=names, **kwds) return FreeGroup_class(names, **kwds) @@ -714,6 +718,7 @@ class FreeGroup_class(CachedRepresentation, Group, ParentLibGAP): sage: G.category() Category of infinite groups """ + Element = FreeGroupElement def __init__(self, generator_names, gap_group=None): @@ -784,7 +789,8 @@ def __richcmp__(self, other, op): """ if not isinstance(other, self.__class__): from sage.structure.richcmp import op_NE - return (op == op_NE) + + return op == op_NE return richcmp(self._gen_names, other._gen_names, op) def _repr_(self): @@ -900,8 +906,7 @@ def _element_constructor_(self, *args, **kwds): if isinstance(P, FreeGroup_class): names = {P._gen_names[abs(i) - 1] for i in x.Tietze()} if names.issubset(self._gen_names): - return self([i.sign()*(self._gen_names.index(P._gen_names[abs(i)-1])+1) - for i in x.Tietze()]) + return self([i.sign() * (self._gen_names.index(P._gen_names[abs(i) - 1]) + 1) for i in x.Tietze()]) raise ValueError('generators of %s not in the group' % x) return self.element_class(self, x, **kwds) @@ -970,7 +975,7 @@ def quotient(self, relations, **kwds): Finitely presented group < a, b, c, d | a*b*a^-1 > """ from sage.groups.finitely_presented import FinitelyPresentedGroup - return FinitelyPresentedGroup(self, - tuple(map(self, relations)), **kwds) + + return FinitelyPresentedGroup(self, tuple(map(self, relations)), **kwds) __truediv__ = quotient diff --git a/src/sage/groups/galois_group.py b/src/sage/groups/galois_group.py index 84eb4a02ad2..3940888517b 100644 --- a/src/sage/groups/galois_group.py +++ b/src/sage/groups/galois_group.py @@ -19,8 +19,7 @@ from sage.misc.lazy_import import lazy_import from sage.rings.integer_ring import ZZ -lazy_import('sage.groups.galois_group_perm', - ['GaloisGroup_perm', 'GaloisSubgroup_perm']) +lazy_import('sage.groups.galois_group_perm', ['GaloisGroup_perm', 'GaloisSubgroup_perm']) lazy_import('sage.groups.perm_gps.permgroup', 'PermutationGroup') @@ -56,6 +55,7 @@ class _GMixin: It is just intended to provide common functionality between various different Galois group classes. """ + @lazy_attribute def _default_algorithm(self): """ @@ -166,6 +166,7 @@ class _GaloisMixin(_GMixin): This class provides methods for Galois groups, allowing concrete instances to inherit from both permutation group and abelian group classes. """ + @lazy_attribute def _field(self): """ @@ -252,7 +253,7 @@ def _field_degree(self): """ try: return self._field.degree() - except NotImplementedError: # relative number fields don't support degree + except NotImplementedError: # relative number fields don't support degree return self._field.absolute_degree() def transitive_label(self) -> str: @@ -291,6 +292,7 @@ class _SubGaloisMixin(_GMixin): This class provides methods for subgroups of Galois groups, allowing concrete instances to inherit from both permutation group and abelian group classes. """ + @lazy_attribute def _ambient_group(self): """ @@ -356,8 +358,8 @@ class GaloisGroup_ab(_GaloisMixin, AbelianGroup_class): r""" Abelian Galois groups """ - def __init__(self, field, generator_orders, - algorithm=None, gen_names='sigma') -> None: + + def __init__(self, field, generator_orders, algorithm=None, gen_names='sigma') -> None: r""" Initialize this Galois group. @@ -433,6 +435,7 @@ class GaloisGroup_cyc(GaloisGroup_ab): r""" Cyclic Galois groups """ + def transitive_number(self, algorithm=None, recompute=False): r""" Return the transitive number for the action on the roots of the defining polynomial. @@ -474,6 +477,7 @@ class GaloisSubgroup_ab(AbelianGroup_subgroup, _SubGaloisMixin): """ Subgroups of abelian Galois groups. """ + pass diff --git a/src/sage/groups/galois_group_perm.py b/src/sage/groups/galois_group_perm.py index 61a6e709c01..495d2c01cd2 100644 --- a/src/sage/groups/galois_group_perm.py +++ b/src/sage/groups/galois_group_perm.py @@ -1,6 +1,7 @@ r""" Galois groups of field extensions as permutation groups """ + from sage.groups.galois_group import _GaloisMixin, _SubGaloisMixin from sage.groups.perm_gps.permgroup import PermutationGroup_generic, PermutationGroup_subgroup from sage.misc.abstract_method import abstract_method @@ -25,6 +26,7 @@ class GaloisGroup_perm(_GaloisMixin, PermutationGroup_generic): defining polynomial of the original extension); the default value may vary based on the type of field """ + @abstract_method def transitive_number(self, algorithm=None, recompute=False): """ @@ -78,6 +80,7 @@ def __init__(self, field, algorithm=None, names=None, gc_numbering=False): # We do only the parts of the initialization of PermutationGroup_generic # that don't depend on _gens from sage.categories.permutation_groups import PermutationGroups + category = PermutationGroups().FinitelyGenerated().Finite() # Note that we DON'T call the __init__ method for PermutationGroup_generic # Instead, the relevant attributes are computed lazily @@ -182,6 +185,7 @@ class GaloisSubgroup_perm(PermutationGroup_subgroup, _SubGaloisMixin): we require that generators for a subgroup be specified during initialization, as specified in the ``__init__`` method of permutation subgroups. """ + pass diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 17a5af0955a..f7fab8ea2eb 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -190,8 +190,7 @@ def _parse_group_def(parent, operation, identity, inverse, op, *, check=True): if operation in multiplication_names: if identity is not None or inverse is not None or op is not None: - raise ValueError("in order to specify custom identity/inverse/op, " - "operation must be 'other'") + raise ValueError("in order to specify custom identity/inverse/op, " "operation must be 'other'") try: identity = parent.one() except Exception: @@ -201,8 +200,7 @@ def _parse_group_def(parent, operation, identity, inverse, op, *, check=True): op = mul elif operation in addition_names: if identity is not None or inverse is not None or op is not None: - raise ValueError("in order to specify custom identity/inverse/op, " - "operation must be 'other'") + raise ValueError("in order to specify custom identity/inverse/op, " "operation must be 'other'") try: identity = parent.zero() except Exception: @@ -212,8 +210,7 @@ def _parse_group_def(parent, operation, identity, inverse, op, *, check=True): op = add else: if check and (identity is None or inverse is None or op is None): - raise ValueError("identity, inverse and operation must all be specified " - "when operation is neither addition nor multiplication") + raise ValueError("identity, inverse and operation must all be specified " "when operation is neither addition nor multiplication") return 'other', identity, inverse, op @@ -385,6 +382,7 @@ def multiple(a, n, operation='*', identity=None, inverse=None, op=None): # Generic iterator for looping through multiples or powers # + class multiples: r""" Return an iterator which runs through ``P0+i*P`` for ``i`` in ``range(n)``. @@ -432,6 +430,7 @@ class multiples: 3 to the power 3 = 27 3 to the power 4 = 81 """ + def __init__(self, P, n, P0=None, indexed=False, operation='+', op=None): """ Create a multiples iterator. @@ -618,33 +617,33 @@ def bsgs(a, b, bounds, operation='*', identity=None, inverse=None, op=None): if a == identity and b != identity: raise ValueError("no solution in bsgs()") - ran = 1 + ub - lb # the length of the interval + ran = 1 + ub - lb # the length of the interval mult = lambda x, y: multiple(x, y, operation=operation, identity=identity, inverse=inverse, op=op) c = op(inverse(b), mult(a, lb)) - if ran < 30: # use simple search for small ranges + if ran < 30: # use simple search for small ranges d = c # for i,d in multiples(a,ran,c,indexed=True,operation=operation,identity=identity,inverse=inverse,op=op): for i0 in range(ran): i = lb + i0 - if identity == d: # identity == b^(-1)*a^i, so return i + if identity == d: # identity == b^(-1)*a^i, so return i return Z(i) d = op(a, d) raise ValueError("no solution in bsgs()") m = ran.isqrt() + 1 # we need sqrt(ran) rounded up - table = {} # will hold pairs (a^(lb+i),lb+i) for i in range(m) + table = {} # will hold pairs (a^(lb+i),lb+i) for i in range(m) d = c for i0 in xsrange(m): i = lb + i0 - if identity == d: # identity == b^(-1)*a^i, so return i + if identity == d: # identity == b^(-1)*a^i, so return i return Z(i) table[d] = i d = op(d, a) - c = op(c, inverse(d)) # this is now a**(-m) + c = op(c, inverse(d)) # this is now a**(-m) d = identity for i in xsrange(m): j = table.get(d) @@ -776,8 +775,7 @@ def discrete_log_rho(a, base, ord=None, operation='*', identity=None, inverse=No # random walk function setup m = [I.random_element() for i in range(partition_size)] n = [I.random_element() for i in range(partition_size)] - M = [mult(power(base, Integer(m[i])), power(a, Integer(n[i]))) - for i in range(partition_size)] + M = [mult(power(base, Integer(m[i])), power(a, Integer(n[i]))) for i in range(partition_size)] ax = I.random_element() x = power(base, Integer(ax)) @@ -1053,10 +1051,11 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i mult = op power = _power_func(operation, identity, inverse, op) - original_a = a # Store the original value of a so we can verify the answer + original_a = a # Store the original value of a so we can verify the answer if bounds: lb, ub = map(integer_ring.ZZ, bounds) from sage.rings.infinity import Infinity + if ord is None: ord = _ord_from_op(base, op) elif ord != Infinity: @@ -1096,7 +1095,7 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i j = -1 for j in range(ri): temp_bound = min(running_bound, pi - 1) - h = power(mult(a, power(base, -l[i])), ord // pi**(j + 1)) + h = power(mult(a, power(base, -l[i])), ord // pi ** (j + 1)) if algorithm == 'bsgs': c = bsgs(gamma, h, (0, temp_bound), inverse=inverse, identity=identity, op=op, operation=operation) elif algorithm == 'rho': @@ -1110,13 +1109,14 @@ def discrete_log(a, base, ord=None, bounds=None, operation='*', identity=None, i running_mod *= pi if running_mod > bound: break - mods.append(pi ** (j+1)) + mods.append(pi ** (j + 1)) if running_mod > bound: break # we have log%running_mod. if we know that log bool: return _rec(P, n) -def merge_points(P1, P2, operation='+', - identity=None, inverse=None, op=None, check=True): +def merge_points(P1, P2, operation='+', identity=None, inverse=None, op=None, check=True): r""" Return a group element whose order is the lcm of the given elements. @@ -1730,8 +1727,7 @@ def merge_points(P1, P2, operation='+', operation, identity, inverse, op = _parse_group_def(parent(g1), operation, identity, inverse, op) if check: - if (multiple(g1, n1, operation=operation, identity=identity, inverse=inverse, op=op) != identity or - multiple(g2, n2, operation=operation, identity=identity, inverse=inverse, op=op) != identity): + if multiple(g1, n1, operation=operation, identity=identity, inverse=inverse, op=op) != identity or multiple(g2, n2, operation=operation, identity=identity, inverse=inverse, op=op) != identity: raise ValueError("the orders provided do not divide the orders of the points provided") # trivial cases diff --git a/src/sage/groups/group_exp.py b/src/sage/groups/group_exp.py index e60f1de7cd2..f4f09265c2d 100644 --- a/src/sage/groups/group_exp.py +++ b/src/sage/groups/group_exp.py @@ -5,6 +5,7 @@ - Mark Shimozono (2013): initial version """ + # *************************************************************************** # Copyright (C) 2013 # @@ -89,6 +90,7 @@ class GroupExp(Functor): sage: y.parent() Multiplicative form of Ambient space of the Root system of type ['A', 2] """ + def __init__(self): r""" Initialize the :class:`GroupExp` functor. @@ -197,6 +199,7 @@ class GroupExpElement(ElementWrapper, MultiplicativeGroupElement): sage: EG(vector(QQ, (1, -3))) == z True """ + def __init__(self, parent, x): r""" EXAMPLES:: @@ -257,6 +260,7 @@ class GroupExp_Class(UniqueRepresentation, Parent): sage: GroupExp()(QQ) Multiplicative form of Rational Field """ + def __init__(self, G) -> None: r""" diff --git a/src/sage/groups/group_semidirect_product.py b/src/sage/groups/group_semidirect_product.py index 32f8f49fb5f..9642b092df1 100644 --- a/src/sage/groups/group_semidirect_product.py +++ b/src/sage/groups/group_semidirect_product.py @@ -5,6 +5,7 @@ - Mark Shimozono (2013) initial version """ + # **************************************************************************** # Copyright (C) 2013 Mark Shimozono # @@ -40,6 +41,7 @@ def _repr_(self): Weyl Group of type ['A', 3] (as a matrix group acting on the ambient space) """ + def wrapper(prefix, s): if prefix is None: return s @@ -245,8 +247,7 @@ class GroupSemidirectProduct(CartesianProduct): - Twofold Direct product as a special case of semidirect product """ - def __init__(self, G, H, twist=None, act_to_right=True, prefix0=None, - prefix1=None, print_tuple=False, category=Groups()): + def __init__(self, G, H, twist=None, act_to_right=True, prefix0=None, prefix1=None, print_tuple=False, category=Groups()): r""" EXAMPLES:: @@ -267,12 +268,9 @@ def __init__(self, G, H, twist=None, act_to_right=True, prefix0=None, def check_implemented_group(x): if x in Groups(): return - error = ("The semidirect product construction for groups " - "is implemented only for multiplicative groups") + error = "The semidirect product construction for groups " "is implemented only for multiplicative groups" if x in CommutativeAdditiveGroups(): - error += (f". Please change the commutative additive group {x}" - " into a multiplicative group " - "using the functor sage.groups.group_exp.GroupExp") + error += f". Please change the commutative additive group {x}" " into a multiplicative group " "using the functor sage.groups.group_exp.GroupExp" raise TypeError(error) check_implemented_group(G) @@ -323,9 +321,7 @@ def _repr_(self): act_string = "acting on" else: act_string = "acted upon by" - return "Semidirect product of %s %s %s" % (cartesian_factors[0], - act_string, - cartesian_factors[1]) + return "Semidirect product of %s %s %s" % (cartesian_factors[0], act_string, cartesian_factors[1]) def _element_constructor_(self, x): r""" @@ -339,6 +335,7 @@ def _element_constructor_(self, x): ....: WeylGroup(['A',3],prefix='t'), twist).an_element() sage: TestSuite(g).run() """ + def type_error(): raise TypeError(f"{x} cannot be converted into an element of {self}") @@ -377,8 +374,7 @@ def one(self): sage: one.cartesian_projection(1) (0, 0) """ - return self((self.cartesian_factors()[0].one(), - self.cartesian_factors()[1].one())) + return self((self.cartesian_factors()[0].one(), self.cartesian_factors()[1].one())) def group_generators(self): r""" @@ -393,6 +389,7 @@ def group_generators(self): sage: GroupSemidirectProduct(EZ, EZ, twist, print_tuple=True).group_generators() ((1, 0), (0, 1)) """ + def has_gens(G): if not hasattr(G, 'group_generators'): return False @@ -403,10 +400,8 @@ def has_gens(G): if g0 is not False: g1 = has_gens(factors[1]) if g1 is not False: - return tuple([self((x, factors[1].one())) for x in g0] + - [self((factors[0].one(), x)) for x in g1]) - raise NotImplementedError("one of the factors does not " - "implement 'group_generators'") + return tuple([self((x, factors[1].one())) for x in g0] + [self((factors[0].one(), x)) for x in g1]) + raise NotImplementedError("one of the factors does not " "implement 'group_generators'") def product(self, x, y): r""" @@ -472,14 +467,7 @@ def opposite_semidirect_product(self): sage: hop in Hop True """ - return GroupSemidirectProduct(self.cartesian_factors()[1], - self.cartesian_factors()[0], - twist=self._twist, - act_to_right=not self.act_to_right(), - prefix0=self._prefix1, - prefix1=self._prefix0, - print_tuple=self._print_tuple, - category=self._category) + return GroupSemidirectProduct(self.cartesian_factors()[1], self.cartesian_factors()[0], twist=self._twist, act_to_right=not self.act_to_right(), prefix0=self._prefix1, prefix1=self._prefix0, print_tuple=self._print_tuple, category=self._category) def construction(self): r""" diff --git a/src/sage/groups/indexed_free_group.py b/src/sage/groups/indexed_free_group.py index 2d044ce8cb4..cca19fa0fbe 100644 --- a/src/sage/groups/indexed_free_group.py +++ b/src/sage/groups/indexed_free_group.py @@ -23,9 +23,7 @@ from sage.categories.groups import Groups from sage.categories.poor_man_map import PoorManMap from sage.groups.group import Group, AbelianGroup -from sage.monoids.indexed_free_monoid import (IndexedMonoid, - IndexedFreeMonoidElement, - IndexedFreeAbelianMonoidElement) +from sage.monoids.indexed_free_monoid import IndexedMonoid, IndexedFreeMonoidElement, IndexedFreeAbelianMonoidElement from sage.misc.cachefunc import cached_method import sage.data_structures.blas_dict as blas from sage.rings.integer import Integer @@ -64,6 +62,7 @@ class IndexedGroup(IndexedMonoid): sage: G.is_finite() True """ + def order(self): r""" Return the number of elements of ``self``, which is `\infty` unless @@ -151,6 +150,7 @@ class IndexedFreeGroup(IndexedGroup, Group): sage: G Free group indexed by {'a', 'b', 'c', 'd', 'e'} """ + def __init__(self, indices, prefix, category=None, **kwds): """ Initialize ``self``. @@ -204,9 +204,9 @@ def gen(self, x): if x not in self._indices: raise IndexError("{} is not in the index set".format(x)) try: - return self.element_class(self, ((self._indices(x),1),)) - except TypeError: # Backup (if it is a string) - return self.element_class(self, ((x,1),)) + return self.element_class(self, ((self._indices(x), 1),)) + except TypeError: # Backup (if it is a string) + return self.element_class(self, ((x, 1),)) class Element(IndexedFreeMonoidElement): def __len__(self): @@ -231,7 +231,7 @@ def __len__(self): sage: len(elt) 7 """ - return sum(abs(exp) for gen,exp in self._monomial) + return sum(abs(exp) for gen, exp in self._monomial) length = __len__ @@ -277,8 +277,7 @@ def __invert__(self): sage: x * ~x 1 """ - return self.__class__(self.parent(), - tuple((x[0], -x[1]) for x in reversed(self._monomial))) + return self.__class__(self.parent(), tuple((x[0], -x[1]) for x in reversed(self._monomial))) def to_word_list(self) -> list[tuple]: """ @@ -294,8 +293,7 @@ def to_word_list(self) -> list[tuple]: sage: x.to_word_list() [(0, 1), (1, 1), (1, 1), (4, 1), (0, -1)] """ - return [(k, 1 if e > 0 else -1) for k, e in self._sorted_items() - for dummy in range(abs(e))] + return [(k, 1 if e > 0 else -1) for k, e in self._sorted_items() for dummy in range(abs(e))] class IndexedFreeAbelianGroup(IndexedGroup, AbelianGroup): @@ -311,6 +309,7 @@ class IndexedFreeAbelianGroup(IndexedGroup, AbelianGroup): sage: G Free abelian group indexed by {'a', 'b', 'c', 'd', 'e'} """ + def __init__(self, indices, prefix, category=None, **kwds): """ Initialize ``self``. @@ -402,9 +401,9 @@ def gen(self, x): if x not in self._indices: raise IndexError("{} is not in the index set".format(x)) try: - return self.element_class(self, {self._indices(x):1}) - except TypeError: # Backup (if it is a string) - return self.element_class(self, {x:1}) + return self.element_class(self, {self._indices(x): 1}) + except TypeError: # Backup (if it is a string) + return self.element_class(self, {x: 1}) class Element(IndexedFreeAbelianMonoidElement, IndexedFreeGroup.Element): def _mul_(self, other): @@ -422,8 +421,7 @@ def _mul_(self, other): sage: (a*b^-2*d^2) * (d^-2*b^2*a^-1) 1 """ - return self.__class__(self.parent(), - blas.add(self._monomial, other._monomial)) + return self.__class__(self.parent(), blas.add(self._monomial, other._monomial)) def __invert__(self): """ @@ -438,7 +436,7 @@ def __invert__(self): sage: x * ~x 1 """ - return self ** -1 + return self**-1 def __floordiv__(self, a): """ @@ -484,4 +482,4 @@ def __pow__(self, n): return self if n == 0: return self.parent().one() - return self.__class__(self.parent(), {k:v*n for k,v in self._monomial.items()}) + return self.__class__(self.parent(), {k: v * n for k, v in self._monomial.items()}) diff --git a/src/sage/groups/kernel_subgroup.py b/src/sage/groups/kernel_subgroup.py index 6a20b673c57..5fb9dcaeae1 100644 --- a/src/sage/groups/kernel_subgroup.py +++ b/src/sage/groups/kernel_subgroup.py @@ -29,6 +29,7 @@ class KernelSubgroup(UniqueRepresentation, Parent): Let `\phi : G \to H` be a group homomorphism. The kernel `K = \{\phi(g) = 1 | g \in G\}` is a normal subgroup of `G`. """ + def __init__(self, morphism): r""" Initialize ``self``. diff --git a/src/sage/groups/libgap_mixin.py b/src/sage/groups/libgap_mixin.py index dfdc34526f4..c4152755f5c 100644 --- a/src/sage/groups/libgap_mixin.py +++ b/src/sage/groups/libgap_mixin.py @@ -300,6 +300,7 @@ def conjugacy_classes(self): if not self.is_finite(): raise NotImplementedError("only implemented for finite groups") from sage.groups.conjugacy_classes import ConjugacyClassGAP + return tuple(ConjugacyClassGAP(self, self(g)) for g in self.conjugacy_classes_representatives()) def conjugacy_class(self, g): @@ -321,6 +322,7 @@ def conjugacy_class(self, g): [0 1] in Special Linear Group of degree 2 over Rational Field """ from sage.groups.conjugacy_classes import ConjugacyClassGAP + return ConjugacyClassGAP(self, self(g)) def class_function(self, values): @@ -340,6 +342,7 @@ class function on the conjugacy classes, in that order [0, 1, 2, 3, 4, 5, 6, 7] """ from sage.groups.class_function import ClassFunction + return ClassFunction(self, values) @cached_method @@ -504,8 +507,7 @@ def subgroups(self): if not self.is_finite(): raise NotImplementedError("group must be finite") ccs = self.gap().ConjugacyClassesSubgroups() - return [self.subgroup(h.GeneratorsOfGroup()) - for cc in ccs for h in cc.Elements()] + return [self.subgroup(h.GeneratorsOfGroup()) for cc in ccs for h in cc.Elements()] def conjugacy_classes_subgroups(self): r""" @@ -541,8 +543,7 @@ def conjugacy_classes_subgroups(self): """ if not self.is_finite(): raise NotImplementedError("group must be finite") - return [self.subgroup(sub.Representative().GeneratorsOfGroup()) - for sub in self.gap().ConjugacyClassesSubgroups()] + return [self.subgroup(sub.Representative().GeneratorsOfGroup()) for sub in self.gap().ConjugacyClassesSubgroups()] def group_id(self): r""" @@ -572,6 +573,7 @@ def group_id(self): GAPError: Error, the group identification for groups of size infinity is not available """ from sage.rings.integer import Integer + return [Integer(n) for n in self.gap().IdGroup()] id = group_id @@ -599,6 +601,7 @@ def exponent(self): if not self.is_finite(): raise NotImplementedError("group must be finite") from sage.rings.integer import Integer + return Integer(self._libgap_().Exponent()) def intersection(self, other): @@ -765,17 +768,20 @@ def character_table(self): G = self._libgap_() cl = self.conjugacy_classes() from sage.rings.integer import Integer + n = Integer(len(cl)) irrG = G.Irr() ct = [[irrG[i][j] for j in range(n)] for i in range(n)] from sage.rings.number_field.number_field import CyclotomicField + e = irrG.Flat().Conductor() K = CyclotomicField(e) ct = [[K(x) for x in v] for v in ct] # Finally return the result as a matrix. from sage.matrix.matrix_space import MatrixSpace + MS = MatrixSpace(K, n) return MS(ct) diff --git a/src/sage/groups/libgap_morphism.py b/src/sage/groups/libgap_morphism.py index 63db4c23383..10c6ae326c0 100644 --- a/src/sage/groups/libgap_morphism.py +++ b/src/sage/groups/libgap_morphism.py @@ -255,6 +255,7 @@ class GroupMorphism_libgap(Morphism): over Finite Field of size 2 to General Linear Group of degree 3 over Integer Ring in Category of groups """ + def __init__(self, homset, gap_hom, check=True): r""" Constructor method. @@ -416,6 +417,7 @@ def pushforward(self, J, *args, **kwds): if isinstance(J, dom.Element) and J in dom: return self._call_(dom(J)) from sage.groups.perm_gps.permgroup import PermutationGroup_generic + if not isinstance(J, (ParentLibGAP, PermutationGroup_generic)): raise TypeError("J (={}) must be a libgap or permutation group".format(J)) if dom.gap().IsSubgroup(J.gap()).sage(): @@ -548,6 +550,7 @@ def preimage(self, S): """ phi = self.gap() from sage.groups.perm_gps.permgroup import PermutationGroup_generic + if not isinstance(S, (ParentLibGAP, PermutationGroup_generic)): raise TypeError("%s must be a GAP or permutation group of %s" % (S, self)) if not self.codomain().gap().IsSubgroup(S.gap()).sage(): @@ -578,6 +581,7 @@ def section(self): """ from sage.categories.homset import Hom from sage.categories.sets_cat import Sets + H = Hom(self.codomain(), self.domain(), category=Sets()) return H(self.lift) @@ -606,6 +610,7 @@ class GroupHomset_libgap(HomsetWithBase): to Abelian group with gap, generator orders (2, 4) in Category of finite enumerated commutative groups """ + def __init__(self, G, H, category=None, check=True): r""" Return the homset of two libgap groups. @@ -619,6 +624,7 @@ def __init__(self, G, H, category=None, check=True): """ if check: from sage.groups.perm_gps.permgroup import PermutationGroup_generic + if not isinstance(G, (ParentLibGAP, PermutationGroup_generic)): raise TypeError("G (={}) must be a ParentLibGAP or a permutation group".format(G)) if not isinstance(H, (ParentLibGAP, PermutationGroup_generic)): @@ -675,6 +681,7 @@ def _element_constructor_(self, x, check=True, **options): if isinstance(x, (tuple, list)): # there should be a better way from sage.libs.gap.libgap import libgap + dom = self.domain() codom = self.codomain() gens = dom.gap().GeneratorsOfGroup() @@ -685,7 +692,7 @@ def _element_constructor_(self, x, check=True, **options): phi = libgap.GroupHomomorphismByImages(dom.gap(), codom.gap(), gens, imgs) # if it is not a group homomorphism, then # self._phi is the gap boolean fail - if phi.is_bool(): # check we did not fail + if phi.is_bool(): # check we did not fail raise ValueError("images do not define a group homomorphism") else: ByImagesNC = libgap.function_factory("GroupHomomorphismByImagesNC") @@ -746,11 +753,8 @@ def natural_map(self): dom_gap = self.domain().gap() codom_gap = self.codomain().gap() from sage.libs.gap.libgap import libgap - phi = libgap.GroupHomomorphismByImages(dom_gap, - codom_gap, - dom_gap.GeneratorsOfGroup(), - codom_gap.GeneratorsOfGroup() - ) - if not phi.is_bool(): # phi is indeed a group homomorphism + + phi = libgap.GroupHomomorphismByImages(dom_gap, codom_gap, dom_gap.GeneratorsOfGroup(), codom_gap.GeneratorsOfGroup()) + if not phi.is_bool(): # phi is indeed a group homomorphism return self.element_class(self, phi) return super().natural_map() diff --git a/src/sage/groups/lie_gps/nilpotent_lie_group.py b/src/sage/groups/lie_gps/nilpotent_lie_group.py index f2eda31d766..d93a5971d72 100644 --- a/src/sage/groups/lie_gps/nilpotent_lie_group.py +++ b/src/sage/groups/lie_gps/nilpotent_lie_group.py @@ -21,8 +21,7 @@ from sage.categories.lie_algebras import LieAlgebras from sage.groups.group import Group from sage.manifolds.differentiable.manifold import DifferentiableManifold -from sage.manifolds.structure import (DifferentialStructure, - RealDifferentialStructure) +from sage.manifolds.structure import DifferentialStructure, RealDifferentialStructure from sage.misc.cachefunc import cached_method from sage.misc.repr import repr_lincomb from sage.modules.free_module_element import vector @@ -70,8 +69,7 @@ def _symbolic_lie_algebra_copy(L): s_coeff = L.structure_coefficients() index_set = L.basis().keys() names = L.variable_names() - return LieAlgebraWithStructureCoefficients(SR, s_coeff, names=names, - index_set=index_set) + return LieAlgebraWithStructureCoefficients(SR, s_coeff, names=names, index_set=index_set) class NilpotentLieGroup(Group, DifferentiableManifold): @@ -222,8 +220,7 @@ def __init__(self, L, name, **kwds): required_cat = LieAlgebras(L.base_ring()).FiniteDimensional() required_cat = required_cat.WithBasis().Nilpotent() if L not in required_cat: - raise TypeError("L needs to be a finite dimensional nilpotent " - "Lie algebra with basis") + raise TypeError("L needs to be a finite dimensional nilpotent " "Lie algebra with basis") self._lie_algebra = L R = L.base_ring() @@ -234,8 +231,7 @@ def __init__(self, L, name, **kwds): else: structure = DifferentialStructure() - DifferentiableManifold.__init__(self, L.dimension(), name, R, - structure, category=category) + DifferentiableManifold.__init__(self, L.dimension(), name, R, structure, category=category) # initialize exponential coordinates of the first kind basis_strs = [str(X) for X in L.basis()] @@ -250,8 +246,7 @@ def __init__(self, L, name, **kwds): # compute a symbolic formula for the group law L_SR = _symbolic_lie_algebra_copy(L) n = L.dimension() - a, b = (tuple(SR.var('%s_%d' % (s, j)) for j in range(n)) - for s in ['a', 'b']) + a, b = (tuple(SR.var('%s_%d' % (s, j)) for j in range(n)) for s in ['a', 'b']) self._group_law_vars = (a, b) bch = L_SR.bch(L_SR.from_vector(a), L_SR.from_vector(b), L.step()) self._group_law = vector(SR, (zk.expand() for zk in bch.to_vector())) @@ -559,8 +554,7 @@ def left_invariant_frame(self, **kwds): coord_frame = self._Exp1.frame() symbol = kwds.pop('symbol', 'X') indices = kwds.pop('indices', self._var_indexing) - return coord_frame.new_frame(dLx_field, symbol=symbol, - indices=indices, **kwds) + return coord_frame.new_frame(dLx_field, symbol=symbol, indices=indices, **kwds) livf = left_invariant_frame @@ -681,8 +675,7 @@ def right_invariant_frame(self, **kwds): coord_frame = self._Exp1.frame() symbol = kwds.pop('symbol', 'XR') indices = kwds.pop('indices', self._var_indexing) - return coord_frame.new_frame(dRx_field, symbol=symbol, - indices=indices, **kwds) + return coord_frame.new_frame(dRx_field, symbol=symbol, indices=indices, **kwds) rivf = right_invariant_frame @@ -815,8 +808,7 @@ def adjoint(self, g): """ Adg_mat = self.conjugation(g).differential(self.one()).matrix() L = self.lie_algebra() - basis_images = {X: L.from_vector(Adg_mat * X.to_vector()) - for X in L.basis()} + basis_images = {X: L.from_vector(Adg_mat * X.to_vector()) for X in L.basis()} return L.morphism(basis_images, codomain=L) class Element(DifferentiableManifold.Element, MultiplicativeGroupElement): @@ -904,8 +896,7 @@ def _mul_(self, other): self_c = list(zip(a, self.coordinates(chart=G._Exp1))) other_c = list(zip(b, other.coordinates(chart=G._Exp1))) sd = dict(self_c + other_c) - return G.point([gk.expand() for gk in G._group_law.subs(sd)], - chart=G._Exp1) + return G.point([gk.expand() for gk in G._group_law.subs(sd)], chart=G._Exp1) def _repr_(self): r""" @@ -937,8 +928,7 @@ def _repr_(self): if chart == G._Exp1: s = repr_lincomb(nonzero_pairs) else: - s = ")exp(".join(repr_lincomb([(Xk, xk)]) - for Xk, xk in reversed(nonzero_pairs)) + s = ")exp(".join(repr_lincomb([(Xk, xk)]) for Xk, xk in reversed(nonzero_pairs)) if not s: s = "0" return "exp(%s)" % s diff --git a/src/sage/groups/matrix_gps/binary_dihedral.py b/src/sage/groups/matrix_gps/binary_dihedral.py index e52d164f7e4..ee24e700a5d 100644 --- a/src/sage/groups/matrix_gps/binary_dihedral.py +++ b/src/sage/groups/matrix_gps/binary_dihedral.py @@ -60,6 +60,7 @@ class BinaryDihedralGroup(UniqueRepresentation, FinitelyGeneratedMatrixGroup_gap - :wikipedia:`Dicyclic_group#Binary_dihedral_group` """ + def __init__(self, n): """ Initialize ``self``. @@ -72,19 +73,20 @@ def __init__(self, n): self._n = n if n % 2 == 0: - R = CyclotomicField(2*n) + R = CyclotomicField(2 * n) zeta = R.gen() - i = R.gen()**(n//2) + i = R.gen() ** (n // 2) else: - R = CyclotomicField(4*n) - zeta = R.gen()**2 - i = R.gen()**n + R = CyclotomicField(4 * n) + zeta = R.gen() ** 2 + i = R.gen() ** n MS = MatrixSpace(R, 2) zero = R.zero() gens = [MS([zeta, zero, zero, ~zeta]), MS([zero, i, i, zero])] from sage.libs.gap.libgap import libgap + gap_gens = [libgap(matrix_gen) for matrix_gen in gens] gap_group = libgap.Group(gap_gens) diff --git a/src/sage/groups/matrix_gps/coxeter_group.py b/src/sage/groups/matrix_gps/coxeter_group.py index c162482fa02..57c3a36728a 100644 --- a/src/sage/groups/matrix_gps/coxeter_group.py +++ b/src/sage/groups/matrix_gps/coxeter_group.py @@ -191,6 +191,7 @@ class CoxeterMatrixGroup(UniqueRepresentation, FinitelyGeneratedMatrixGroup_gene [3 1 5] [2 5 1] """ + @staticmethod def __classcall_private__(cls, data, base_ring=None, index_set=None): """ @@ -218,6 +219,7 @@ def __classcall_private__(cls, data, base_ring=None, index_set=None): base_ring = ZZ elif data.is_finite(): from sage.rings.number_field.number_field import QuadraticField + letter = data.coxeter_type().cartan_type().type() if letter in ['B', 'C', 'F']: base_ring = QuadraticField(2) @@ -227,9 +229,11 @@ def __classcall_private__(cls, data, base_ring=None, index_set=None): base_ring = QuadraticField(5) else: from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField + base_ring = UniversalCyclotomicField() else: from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField + base_ring = UniversalCyclotomicField() return super().__classcall__(cls, data, base_ring, data.index_set()) @@ -286,6 +290,7 @@ def val(x): if x == -1: return 2 return E(2 * x) + ~E(2 * x) + elif isinstance(base_ring, sage.rings.abc.NumberField_quadratic): from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField @@ -295,7 +300,9 @@ def val(x): if x == -1: return 2 return base_ring((E(2 * x) + ~E(2 * x)).to_cyclotomic_field()) + else: + def val(x): if x == -1: return 2 @@ -307,10 +314,10 @@ def val(x): return 1 from sage.functions.trig import cos from sage.symbolic.constants import pi + return base_ring(2 * cos(pi / x)) - gens = [one + MS([SparseEntry(i, j, val(coxeter_matrix[index_set[i], index_set[j]])) - for j in range(n)]) - for i in range(n)] + + gens = [one + MS([SparseEntry(i, j, val(coxeter_matrix[index_set[i], index_set[j]])) for j in range(n)]) for i in range(n)] # Make the generators dense matrices for consistency and speed gens = [g.dense_matrix() for g in gens] category = CoxeterGroups() @@ -321,15 +328,12 @@ def val(x): category = category.Finite() else: category = category.Infinite() - if all(self._matrix._matrix[i, j] == 2 - for i in range(n) for j in range(i)): + if all(self._matrix._matrix[i, j] == 2 for i in range(n) for j in range(i)): category = category.Commutative() if self._matrix.is_irreducible(): category = category.Irreducible() - self._index_set_inverse = {i: ii - for ii, i in enumerate(self._matrix.index_set())} - FinitelyGeneratedMatrixGroup_generic.__init__(self, ZZ(n), base_ring, - gens, category=category) + self._index_set_inverse = {i: ii for ii, i in enumerate(self._matrix.index_set())} + FinitelyGeneratedMatrixGroup_generic.__init__(self, ZZ(n), base_ring, gens, category=category) def _repr_(self): """ @@ -563,6 +567,7 @@ def _positive_roots_reflections(self): N = len(word) from sage.modules.free_module import FreeModule + simple_roots = FreeModule(self.base_ring(), self.ngens()).gens() refls = self.simple_reflections() @@ -728,6 +733,7 @@ class Element(MatrixGroupElement_generic): """ A Coxeter group element. """ + def first_descent(self, side='right', index_set=None, positive=False): """ Return the first left (resp. right) descent of ``self``, as diff --git a/src/sage/groups/matrix_gps/finitely_generated.py b/src/sage/groups/matrix_gps/finitely_generated.py index b8dd5b8c01d..3349da4983c 100644 --- a/src/sage/groups/matrix_gps/finitely_generated.py +++ b/src/sage/groups/matrix_gps/finitely_generated.py @@ -198,9 +198,10 @@ def QuaternionMatrixGroupGF3(): """ from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.matrix.matrix_space import MatrixSpace + MS = MatrixSpace(FiniteField(3), 2) - aye = MS([1,1,1,2]) - jay = MS([2,1,1,1]) + aye = MS([1, 1, 1, 2]) + jay = MS([2, 1, 1, 1]) return MatrixGroup([aye, jay]) @@ -272,7 +273,7 @@ def MatrixGroup(*gens, **kwds): ... AttributeError: 'LinearMatrixGroup_generic_with_category' object has no attribute 'gens'... """ - if isinstance(gens[-1], dict): # hack for unpickling + if isinstance(gens[-1], dict): # hack for unpickling kwds.update(gens[-1]) gens = gens[:-1] check = kwds.get('check', True) @@ -291,7 +292,7 @@ def MatrixGroup(*gens, **kwds): raise ValueError('each generator must be an invertible matrix') MS = gens.universe() base_ring = MS.base_ring() - degree = ZZ(MS.ncols()) # == MS.nrows() + degree = ZZ(MS.ncols()) # == MS.nrows() category = kwds.get('category', None) try: from sage.libs.gap.libgap import libgap @@ -302,13 +303,12 @@ def MatrixGroup(*gens, **kwds): try: gap_gens = [libgap(matrix_gen) for matrix_gen in gens] gap_group = libgap.Group(gap_gens) - return FinitelyGeneratedMatrixGroup_gap(degree, base_ring, gap_group, - category=category) + return FinitelyGeneratedMatrixGroup_gap(degree, base_ring, gap_group, category=category) except (TypeError, ValueError): pass - return FinitelyGeneratedMatrixGroup_generic(degree, base_ring, gens, - category=category) + return FinitelyGeneratedMatrixGroup_generic(degree, base_ring, gens, category=category) + ################################################################### # @@ -405,8 +405,7 @@ def gens(self) -> tuple: [0 1], [3 4] ) """ - return tuple(self.element_class(self, x, check=False, convert=False) - for x in self._gens_matrix) + return tuple(self.element_class(self, x, check=False, convert=False) for x in self._gens_matrix) def gen(self, i): """ @@ -481,5 +480,5 @@ def _test_matrix_generators(self, **options): sage: G._test_matrix_generators() """ tester = self._tester(**options) - for g,h in zip(self.gens(), MatrixGroup(self.gens()).gens()): + for g, h in zip(self.gens(), MatrixGroup(self.gens()).gens()): tester.assertEqual(g.matrix(), h.matrix()) diff --git a/src/sage/groups/matrix_gps/finitely_generated_gap.py b/src/sage/groups/matrix_gps/finitely_generated_gap.py index d5f78610089..0b8b2c379da 100644 --- a/src/sage/groups/matrix_gps/finitely_generated_gap.py +++ b/src/sage/groups/matrix_gps/finitely_generated_gap.py @@ -70,8 +70,7 @@ def __reduce__(self): [3 4], [-1 0] ) """ - return (MatrixGroup, - tuple(g.matrix() for g in self.gens()) + ({'check': False},)) + return (MatrixGroup, tuple(g.matrix() for g in self.gens()) + ({'check': False},)) def as_permutation_group(self, algorithm=None, seed=None): r""" @@ -185,16 +184,17 @@ def as_permutation_group(self, algorithm=None, seed=None): # memory locations and will change if you change the order of # doctests and/or architecture from sage.groups.perm_gps.permgroup import PermutationGroup + if not self.is_finite(): raise NotImplementedError("group must be finite") if seed is not None: from sage.libs.gap.libgap import libgap + libgap.set_seed(ZZ(seed)) iso = self._libgap_().IsomorphismPermGroup() if algorithm == "smaller": iso = iso.Image().SmallerDegreePermutationRepresentation() - return PermutationGroup(iso.Image().GeneratorsOfGroup().sage(), - canonicalize=False) + return PermutationGroup(iso.Image().GeneratorsOfGroup().sage(), canonicalize=False) def module_composition_factors(self, algorithm=None): r""" @@ -225,6 +225,7 @@ def module_composition_factors(self, algorithm=None): For more on MeatAxe notation, see :gap:`chap69`. """ from sage.libs.gap.libgap import libgap + F = self.base_ring() if not F.is_finite(): raise NotImplementedError("base ring must be finite") @@ -238,9 +239,7 @@ def module_composition_factors(self, algorithm=None): MCFs = compo(M) if algorithm == "verbose": print(str(MCFs) + "\n") - return sorted((MCF['field'].sage(), - MCF['dimension'].sage(), - MCF['IsIrreducible'].sage()) for MCF in MCFs) + return sorted((MCF['field'].sage(), MCF['dimension'].sage(), MCF['IsIrreducible'].sage()) for MCF in MCFs) def invariant_generators(self): r""" @@ -310,8 +309,8 @@ def invariant_generators(self): rings of finite groups", :arxiv:`math/0703035`. """ from sage.interfaces.singular import singular - from sage.rings.polynomial.polynomial_ring_constructor import \ - PolynomialRing + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + gens = self.gens() singular.LIB("finvar.lib") n = self.degree() # len((gens[0].matrix()).rows()) @@ -325,8 +324,7 @@ def invariant_generators(self): raise NotImplementedError("can only deal with finite fields and (simple algebraic extensions of) the rationals") FieldStr = '(%d,%s)' % (F.characteristic(), str(F.gen())) else: # we have a transcendental extension - FieldStr = '(%d,%s)' % (F.characteristic(), - ','.join(str(p) for p in F.gens())) + FieldStr = '(%d,%s)' % (F.characteristic(), ','.join(str(p) for p in F.gens())) # Setting Singular's variable names # We need to make sure that field generator and variables get different names. @@ -334,55 +332,51 @@ def invariant_generators(self): VarStr = 'y' else: VarStr = 'x' - VarNames = '(' + ','.join(VarStr+str(i) for i in range(1, n+1))+')' + VarNames = '(' + ','.join(VarStr + str(i) for i in range(1, n + 1)) + ')' # The function call and affectation below have side-effects. Do not remove! # (even if pyflakes say so) R = singular.ring(FieldStr, VarNames, 'dp') if hasattr(F, 'polynomial') and F.gen() != 1: # we have to define minpoly - singular.eval('minpoly = '+str(F.polynomial()).replace('x',str(F.gen()))) - A = [singular.matrix(n,n,str((x.matrix()).list())) for x in gens] + singular.eval('minpoly = ' + str(F.polynomial()).replace('x', str(F.gen()))) + A = [singular.matrix(n, n, str((x.matrix()).list())) for x in gens] Lgens = ','.join(x.name() for x in A) - PR = PolynomialRing(F, n, [VarStr+str(i) for i in range(1,n+1)]) + PR = PolynomialRing(F, n, [VarStr + str(i) for i in range(1, n + 1)]) if q == 0 or (q > 0 and self.cardinality() % q): from sage.matrix.constructor import Matrix + try: elements = [g.matrix() for g in self.list()] except (TypeError, ValueError): elements if elements is not None: - ReyName = 't'+singular._next_var_name() - singular.eval('matrix %s[%d][%d]' % (ReyName, - self.cardinality(), n)) - for i in range(1,self.cardinality()+1): - M = Matrix(F, elements[i-1]) + ReyName = 't' + singular._next_var_name() + singular.eval('matrix %s[%d][%d]' % (ReyName, self.cardinality(), n)) + for i in range(1, self.cardinality() + 1): + M = Matrix(F, elements[i - 1]) D = [{} for foobar in range(self.degree())] - for x,y in M.dict().items(): + for x, y in M.dict().items(): D[x[0]][x[1]] = y for row in range(self.degree()): for t in D[row].items(): - singular.eval('%s[%d,%d]=%s[%d,%d]+(%s)*var(%d)' - % (ReyName,i,row+1,ReyName,i,row+1, repr(t[1]),t[0]+1)) - IRName = 't'+singular._next_var_name() - singular.eval('matrix %s = invariant_algebra_reynolds(%s)' % (IRName,ReyName)) + singular.eval('%s[%d,%d]=%s[%d,%d]+(%s)*var(%d)' % (ReyName, i, row + 1, ReyName, i, row + 1, repr(t[1]), t[0] + 1)) + IRName = 't' + singular._next_var_name() + singular.eval('matrix %s = invariant_algebra_reynolds(%s)' % (IRName, ReyName)) else: - ReyName = 't'+singular._next_var_name() + ReyName = 't' + singular._next_var_name() singular.eval('list %s=group_reynolds((%s))' % (ReyName, Lgens)) - IRName = 't'+singular._next_var_name() + IRName = 't' + singular._next_var_name() singular.eval('matrix %s = invariant_algebra_reynolds(%s[1])' % (IRName, ReyName)) - OUT = [singular.eval(IRName+'[1,%d]' % (j)) - for j in range(1, 1+int(singular('ncols('+IRName+')')))] + OUT = [singular.eval(IRName + '[1,%d]' % (j)) for j in range(1, 1 + int(singular('ncols(' + IRName + ')')))] return [PR(gen) for gen in OUT] if self.cardinality() % q == 0: PName = 't' + singular._next_var_name() SName = 't' + singular._next_var_name() singular.eval('matrix %s,%s=invariant_ring(%s)' % (PName, SName, Lgens)) - OUT = [singular.eval(PName+'[1,%d]' % (j)) - for j in range(1,1+singular('ncols('+PName+')'))] - OUT += [singular.eval(SName+'[1,%d]' % (j)) - for j in range(2,1+singular('ncols('+SName+')'))] + OUT = [singular.eval(PName + '[1,%d]' % (j)) for j in range(1, 1 + singular('ncols(' + PName + ')'))] + OUT += [singular.eval(SName + '[1,%d]' % (j)) for j in range(2, 1 + singular('ncols(' + SName + ')'))] return [PR(gen) for gen in OUT] def molien_series(self, chi=None, return_series=True, prec=20, variable='t'): @@ -551,7 +545,7 @@ def molien_series(self, chi=None, return_series=True, prec=20, variable='t'): L = R mol = P(0) for g in self: - mol += L(chi(g)) / (M.identity_matrix()-t*g.matrix()).det().change_ring(L) + mol += L(chi(g)) / (M.identity_matrix() - t * g.matrix()).det().change_ring(L) elif R.characteristic().divides(N): raise NotImplementedError("characteristic cannot divide group order") else: # char p>0 @@ -561,6 +555,7 @@ def molien_series(self, chi=None, return_series=True, prec=20, variable='t'): # don't need to extend further in this case since the order of # the roots of unity in the character divide the order of the group from sage.rings.number_field.number_field import CyclotomicField + L = CyclotomicField(N, 'v') v = L.gen() # construct Molien series @@ -573,11 +568,11 @@ def molien_series(self, chi=None, return_series=True, prec=20, variable='t'): for e in g.matrix().eigenvalues(): # find power such that w**n = e n = 1 - while w**n != e and n < N+1: + while w**n != e and n < N + 1: n += 1 # raise v to that power - phi *= (1-t*v**n) - mol += P(1)/phi + phi *= 1 - t * v**n + mol += P(1) / phi # We know the coefficients will be integers mol = mol.numerator().change_ring(ZZ) / mol.denominator().change_ring(ZZ) # divide by group order @@ -585,6 +580,7 @@ def molien_series(self, chi=None, return_series=True, prec=20, variable='t'): if return_series: if prec == float('inf'): from sage.rings.lazy_series_ring import LazyPowerSeriesRing + PS = LazyPowerSeriesRing(ZZ, names=(variable,), sparse=P.is_sparse()) else: PS = PowerSeriesRing(ZZ, variable, default_prec=prec) @@ -779,7 +775,7 @@ def reynolds_operator(self, poly, chi=None): poly_gens = vector(poly.parent().gens()) F = L.zero() for g in self: - F += poly(*g.matrix()*vector(poly.parent().gens())) + F += poly(*g.matrix() * vector(poly.parent().gens())) F /= self.order() return F # non-trivial character case @@ -814,7 +810,7 @@ def reynolds_operator(self, poly, chi=None): poly_gens = vector(poly.parent().gens()) F = L.zero() for g in self: - F += L(chi(g)) * poly(*g.matrix().change_ring(L)*poly_gens) + F += L(chi(g)) * poly(*g.matrix().change_ring(L) * poly_gens) F /= self.order() try: # attempt to move F to base_ring of polynomial F = F.change_ring(R) @@ -912,13 +908,13 @@ def invariants_of_degree(self, deg, chi=None, R=None): elif R.ngens() != D: raise TypeError("number of variables in polynomial ring must match size of matrices") - ms = self.molien_series(prec=deg+1,chi=chi) + ms = self.molien_series(prec=deg + 1, chi=chi) if ms[deg].is_zero(): return [] inv = set() for e in IntegerVectors(deg, D): F = self.reynolds_operator(R.monomial(*e), chi=chi) - if not F.is_zero() and _new_invariant_is_linearly_independent((F := F/F.lc()), inv): + if not F.is_zero() and _new_invariant_is_linearly_independent((F := F / F.lc()), inv): inv.add(F) if len(inv) == ms[deg]: break @@ -939,4 +935,4 @@ def _new_invariant_is_linearly_independent(F, invariants): """ if len(invariants) == 0: return True - return PolynomialSequence(invariants).coefficients_monomials()[0].rank() != PolynomialSequence(list(invariants)+[F]).coefficients_monomials()[0].rank() + return PolynomialSequence(invariants).coefficients_monomials()[0].rank() != PolynomialSequence(list(invariants) + [F]).coefficients_monomials()[0].rank() diff --git a/src/sage/groups/matrix_gps/heisenberg.py b/src/sage/groups/matrix_gps/heisenberg.py index 64cefdcda9c..4d07931b495 100644 --- a/src/sage/groups/matrix_gps/heisenberg.py +++ b/src/sage/groups/matrix_gps/heisenberg.py @@ -80,6 +80,7 @@ class HeisenbergGroup(UniqueRepresentation, FinitelyGeneratedMatrixGroup_gap): - :wikipedia:`Heisenberg_group` """ + @staticmethod def __classcall_private__(cls, n=1, R=0): """ @@ -132,9 +133,10 @@ def __init__(self, n=1, R=0): sage: groups.matrix.Heisenberg(n=2, R=ZZ).category() Category of finitely generated infinite enumerated groups """ + def elementary_matrix(i, j, val, MS): elm = copy(MS.one()) - elm[i,j] = val + elm[i, j] = val elm.set_immutable() return elm @@ -153,14 +155,13 @@ def elementary_matrix(i, j, val, MS): dim = ZZ(n + 2) MS = MatrixSpace(self._ring, dim) - gens_x = [elementary_matrix(0, j, gen, MS) - for j in range(1, dim-1) for gen in ring_gens] - gens_y = [elementary_matrix(i, dim-1, gen, MS) - for i in range(1, dim-1) for gen in ring_gens] - gen_z = [elementary_matrix(0, dim-1, gen, MS) for gen in ring_gens] + gens_x = [elementary_matrix(0, j, gen, MS) for j in range(1, dim - 1) for gen in ring_gens] + gens_y = [elementary_matrix(i, dim - 1, gen, MS) for i in range(1, dim - 1) for gen in ring_gens] + gen_z = [elementary_matrix(0, dim - 1, gen, MS) for gen in ring_gens] gens = gens_x + gens_y + gen_z from sage.libs.gap.libgap import libgap + gap_gens = [libgap(single_gen) for single_gen in gens] gap_group = libgap.Group(gap_gens) @@ -170,8 +171,7 @@ def elementary_matrix(i, j, val, MS): else: cat = cat.Infinite() - FinitelyGeneratedMatrixGroup_gap.__init__(self, ZZ(dim), self._ring, - gap_group, category=cat) + FinitelyGeneratedMatrixGroup_gap.__init__(self, ZZ(dim), self._ring, gap_group, category=cat) def _repr_(self): """ @@ -220,8 +220,9 @@ def order(self): """ if self._ring is ZZ: from sage.rings.infinity import Infinity + return Infinity - return ZZ(self._ring.cardinality() ** (2*self._n + 1)) + return ZZ(self._ring.cardinality() ** (2 * self._n + 1)) cardinality = order diff --git a/src/sage/groups/matrix_gps/isometries.py b/src/sage/groups/matrix_gps/isometries.py index 9bb8fd1a469..acc50cbf3b5 100644 --- a/src/sage/groups/matrix_gps/isometries.py +++ b/src/sage/groups/matrix_gps/isometries.py @@ -88,11 +88,7 @@ class GroupOfIsometries(FinitelyGeneratedMatrixGroup_gap): +Infinity """ - def __init__(self, degree, base_ring, - gens, invariant_bilinear_form, - category=None, check=True, - invariant_submodule=None, - invariant_quotient_module=None): + def __init__(self, degree, base_ring, gens, invariant_bilinear_form, category=None, check=True, invariant_submodule=None, invariant_quotient_module=None): r""" Create this orthogonal group from the input. @@ -106,6 +102,7 @@ def __init__(self, degree, base_ring, sage: TestSuite(O).run() """ from copy import copy + G = copy(invariant_bilinear_form) G.set_immutable() self._invariant_bilinear_form = G @@ -118,18 +115,15 @@ def __init__(self, degree, base_ring, self._check_matrix(f) if (I is not None) and I * f != I: raise ValueError("the submodule is not preserved") - if Q is not None and (Q.W() != Q.W()*f or Q.V()*f != Q.V()): + if Q is not None and (Q.W() != Q.W() * f or Q.V() * f != Q.V()): raise ValueError("the quotient module is not preserved") - if len(gens) == 0: # handle the trivial group + if len(gens) == 0: # handle the trivial group gens = [G.parent().identity_matrix()] from sage.libs.gap.libgap import libgap + gap_gens = [libgap(matrix_gen) for matrix_gen in gens] gap_group = libgap.Group(gap_gens) - FinitelyGeneratedMatrixGroup_gap.__init__(self, - degree, - base_ring, - gap_group, - category=category) + FinitelyGeneratedMatrixGroup_gap.__init__(self, degree, base_ring, gap_group, category=category) def _repr_(self): r""" @@ -151,6 +145,7 @@ def _repr_(self): """ n = self.ngens() from sage.repl.display.util import format_list + if n > 5: return 'Group of isometries with %s generators ' % n if n == 1: @@ -171,12 +166,7 @@ def __reduce__(self): sage: loads(dumps(O)) == O True """ - args = (self.degree(), self.base_ring(), - tuple(g.matrix() for g in self.gens()), self._invariant_bilinear_form, - self.category(), - False, - self._invariant_submodule, - self._invariant_quotient_module) + args = (self.degree(), self.base_ring(), tuple(g.matrix() for g in self.gens()), self._invariant_bilinear_form, self.category(), False, self._invariant_submodule, self._invariant_quotient_module) return (GroupOfIsometries, args) def invariant_bilinear_form(self): @@ -221,12 +211,14 @@ def _get_action_(self, S, op, self_on_left): (0, 2) """ import operator + if op == operator.mul and not self_on_left: if S is self._invariant_submodule: return GroupActionOnSubmodule(self, S) if S is self._invariant_quotient_module: return GroupActionOnQuotientModule(self, S) from sage.modules.fg_pid.fgp_module import FGP_Module_class + T = self._invariant_quotient_module if isinstance(S, FGP_Module_class): if S.is_submodule(T): @@ -256,8 +248,7 @@ def _check_matrix(self, x, *args): """ F = self.invariant_bilinear_form() if x * F * x.transpose() != F: - raise TypeError('matrix must be orthogonal ' - 'with respect to the invariant form') + raise TypeError('matrix must be orthogonal ' 'with respect to the invariant form') class GroupActionOnSubmodule(Action): @@ -287,6 +278,7 @@ class GroupActionOnSubmodule(Action): Echelon basis matrix: [0 1] """ + def __init__(self, MatrixGroup, submodule, is_left=False): r""" Initialize the action. @@ -307,6 +299,7 @@ def __init__(self, MatrixGroup, submodule, is_left=False): [0 1] """ import operator + Action.__init__(self, MatrixGroup, submodule, is_left, operator.mul) def _act_(self, g, a): @@ -374,6 +367,7 @@ class GroupActionOnQuotientModule(Action): sage: (x*g).parent() Finitely generated module V/W over Integer Ring with invariants (6) """ + def __init__(self, MatrixGroup, quotient_module, is_left=False): r""" Initialize the action. @@ -391,6 +385,7 @@ def __init__(self, MatrixGroup, quotient_module, is_left=False): ((1), (5)) """ import operator + Action.__init__(self, MatrixGroup, quotient_module, is_left, operator.mul) def _act_(self, g, a): diff --git a/src/sage/groups/matrix_gps/linear.py b/src/sage/groups/matrix_gps/linear.py index 113a93cca44..eef593dfa1c 100644 --- a/src/sage/groups/matrix_gps/linear.py +++ b/src/sage/groups/matrix_gps/linear.py @@ -63,8 +63,7 @@ from sage.categories.fields import Fields from sage.categories.groups import Groups -from sage.groups.matrix_gps.named_group import ( - normalize_args_vectorspace, NamedMatrixGroup_generic) +from sage.groups.matrix_gps.named_group import normalize_args_vectorspace, NamedMatrixGroup_generic from sage.misc.latex import latex from sage.misc.misc_c import prod from sage.rings.infinity import Infinity @@ -76,6 +75,7 @@ # General Linear Group ############################################################################### + def GL(n, R, var='a'): r""" Return the general linear group. @@ -182,19 +182,18 @@ def GL(n, R, var='a'): else: try: cmd = 'GL({0}, {1})'.format(degree, ring._gap_init_()) - return LinearMatrixGroup_gap(degree, ring, False, name, ltx, cmd, - category=cat) + return LinearMatrixGroup_gap(degree, ring, False, name, ltx, cmd, category=cat) except ValueError: pass - return LinearMatrixGroup_generic(degree, ring, False, name, ltx, - category=cat) + return LinearMatrixGroup_generic(degree, ring, False, name, ltx, category=cat) ############################################################################### # Special Linear Group ############################################################################### + def SL(n, R, var='a'): r""" Return the special linear group. @@ -278,19 +277,18 @@ def SL(n, R, var='a'): else: try: cmd = 'SL({0}, {1})'.format(degree, ring._gap_init_()) - return LinearMatrixGroup_gap(degree, ring, True, name, ltx, cmd, - category=cat) + return LinearMatrixGroup_gap(degree, ring, True, name, ltx, cmd, category=cat) except ValueError: pass - return LinearMatrixGroup_generic(degree, ring, True, name, ltx, - category=cat) + return LinearMatrixGroup_generic(degree, ring, True, name, ltx, category=cat) ######################################################################## # Linear Matrix Group class ######################################################################## + class LinearMatrixGroup_generic(NamedMatrixGroup_generic): def _check_matrix(self, x, *args): @@ -379,10 +377,11 @@ def order(self): sage: GL(1, ZZ).order() 2 """ + def order_over_finite_field(q, n): ord = prod(q**n - q**i for i in range(n)) if self._special: - return ord // (q-1) + return ord // (q - 1) return ord n = self.degree() @@ -403,11 +402,11 @@ def order_over_finite_field(q, n): # By the Chinese remainder theorem we need to build the product # over the orders of GL(n, ZZ/p^e ZZ) (or SL) for all prime # powers in the factorization of q - for (p,e) in q.factor(): + for p, e in q.factor(): ord_base = order_over_finite_field(p, n) if not self._special: - ord *= p**((e-1)*n**2) * ord_base + ord *= p ** ((e - 1) * n**2) * ord_base # We apply |SL(n, R)| = |GL(n, R)| / euler_phi(q), but since we # already iterate over the prime factorization of q, we divide @@ -415,12 +414,11 @@ def order_over_finite_field(q, n): # handled in the call to order_over_finite_field, we only # need to remove p^(e-1) compared to the above formula else: - ord *= p**((e-1)*(n**2-1)) * ord_base + ord *= p ** ((e - 1) * (n**2 - 1)) * ord_base return ord - raise NotImplementedError("order computation of linear groups not " - "fully supported for arbitrary base rings") + raise NotImplementedError("order computation of linear groups not " "fully supported for arbitrary base rings") if n > 1 or (R.is_field() and not self._special): return Infinity @@ -431,7 +429,6 @@ def order_over_finite_field(q, n): if R == ZZ: return ZZ(2) - raise NotImplementedError("order computation of linear groups not " - "fully supported for arbitrary base rings") + raise NotImplementedError("order computation of linear groups not " "fully supported for arbitrary base rings") cardinality = order diff --git a/src/sage/groups/matrix_gps/linear_gap.py b/src/sage/groups/matrix_gps/linear_gap.py index f5c16f1c9fe..b148972ca65 100644 --- a/src/sage/groups/matrix_gps/linear_gap.py +++ b/src/sage/groups/matrix_gps/linear_gap.py @@ -20,4 +20,5 @@ class LinearMatrixGroup_gap(NamedMatrixGroup_gap, LinearMatrixGroup_generic, Fin sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) True """ + pass diff --git a/src/sage/groups/matrix_gps/matrix_group.py b/src/sage/groups/matrix_gps/matrix_group.py index 0ab06f7947d..ccf1bd868cf 100644 --- a/src/sage/groups/matrix_gps/matrix_group.py +++ b/src/sage/groups/matrix_gps/matrix_group.py @@ -62,8 +62,7 @@ from sage.rings.integer import Integer from sage.matrix.matrix_space import MatrixSpace from sage.misc.latex import latex -from sage.structure.richcmp import (richcmp_not_equal, rich_to_bool, - richcmp_method, richcmp) +from sage.structure.richcmp import richcmp_not_equal, rich_to_bool, richcmp_method, richcmp from sage.misc.cachefunc import cached_method from sage.groups.group import Group @@ -93,6 +92,7 @@ class MatrixGroup_base(Group): sage: G.category() Category of finite groups """ + _ambient = None # internal attribute to register the ambient group in case this instance is a subgroup def _check_matrix(self, x, *args) -> None: @@ -156,6 +156,7 @@ def as_matrix_group(self): ) """ from sage.groups.matrix_gps.finitely_generated import MatrixGroup + return MatrixGroup(self.gens()) def subgroup(self, generators, check=True): @@ -213,6 +214,7 @@ def subgroup(self, generators, check=True): raise ValueError("generator %s is not in the group" % (g)) from sage.groups.matrix_gps.finitely_generated import MatrixGroup + subgroup = MatrixGroup(generators, check=check, category=cat) subgroup._ambient = self return subgroup @@ -270,17 +272,15 @@ def _repr_(self): if ambient_group is None: if self.ngens() > 5: - return 'Matrix group over {0} with {1} generators'.format( - self.base_ring(), self.ngens()) + return 'Matrix group over {0} with {1} generators'.format(self.base_ring(), self.ngens()) from sage.repl.display.util import format_list - return 'Matrix group over {0} with {1} generators {2}'.format( - self.base_ring(), self.ngens(), format_list(self.gens())) + + return 'Matrix group over {0} with {1} generators {2}'.format(self.base_ring(), self.ngens(), format_list(self.gens())) if self.ngens() > 5: - return 'Subgroup with {0} generators of {1}'.format( - self.ngens(), ambient_group) + return 'Subgroup with {0} generators of {1}'.format(self.ngens(), ambient_group) from sage.repl.display.util import format_list - return 'Subgroup with {0} generators {1} of {2}'.format( - self.ngens(), format_list(self.gens()), ambient_group) + + return 'Subgroup with {0} generators {1} of {2}'.format(self.ngens(), format_list(self.gens()), ambient_group) def _repr_option(self, key): """ @@ -356,6 +356,7 @@ def sign_representation(self, base_ring=None): if base_ring.characteristic() == 2: # characteristic 2 return self.trivial_representation() from sage.modules.with_basis.representation import SignRepresentationMatrixGroup + return SignRepresentationMatrixGroup(self, base_ring) def natural_representation(self, base_ring=None): @@ -389,6 +390,7 @@ def natural_representation(self, base_ring=None): e[0] + e[1] + e[2] """ from sage.modules.with_basis.representation import NaturalMatrixRepresentation + return NaturalMatrixRepresentation(self, base_ring) @@ -536,6 +538,7 @@ def __richcmp__(self, other, op): return richcmp_not_equal(self, other, op) from sage.structure.element import InfinityElement as Infinity + if isinstance(n_self, Infinity) or isinstance(n_other, Infinity): return richcmp(id(self), id(other), op) @@ -586,6 +589,7 @@ def __hash__(self): return hash(id(self)) from sage.structure.element import InfinityElement as Infinity + if isinstance(ngens, Infinity): return hash(id(self)) diff --git a/src/sage/groups/matrix_gps/matrix_group_gap.py b/src/sage/groups/matrix_gps/matrix_group_gap.py index 552fcde3ff6..e81e31eb75a 100644 --- a/src/sage/groups/matrix_gps/matrix_group_gap.py +++ b/src/sage/groups/matrix_gps/matrix_group_gap.py @@ -217,6 +217,7 @@ def _check_matrix(self, x_sage, x_gap): TypeError: matrix is not in the finitely generated group """ from sage.libs.gap.libgap import libgap + libgap_contains = libgap.eval(r'\in') is_contained = libgap_contains(x_gap, self.gap()) if not is_contained.sage(): @@ -307,8 +308,7 @@ def _subgroup_constructor(self, libgap_subgroup): if self in Groups().Finite(): cat = cat.Finite() from sage.groups.matrix_gps.finitely_generated_gap import FinitelyGeneratedMatrixGroup_gap - return FinitelyGeneratedMatrixGroup_gap(self.degree(), self.base_ring(), - libgap_subgroup, ambient=self, - category=cat) + + return FinitelyGeneratedMatrixGroup_gap(self.degree(), self.base_ring(), libgap_subgroup, ambient=self, category=cat) from sage.groups.generic import structure_description diff --git a/src/sage/groups/matrix_gps/named_group.py b/src/sage/groups/matrix_gps/named_group.py index 4e953b3ef3d..6fccbcab0eb 100644 --- a/src/sage/groups/matrix_gps/named_group.py +++ b/src/sage/groups/matrix_gps/named_group.py @@ -99,6 +99,7 @@ def normalize_args_vectorspace(*args, **kwds): (2, Rational Field) """ from sage.rings.integer_ring import ZZ + if len(args) == 1: V = args[0] try: @@ -111,6 +112,7 @@ def normalize_args_vectorspace(*args, **kwds): try: ring = ZZ(ring) from sage.rings.finite_rings.finite_field_constructor import FiniteField + var = kwds.get('var', 'a') ring = FiniteField(ring, var) except (ValueError, TypeError): @@ -175,6 +177,7 @@ def normalize_args_invariant_form(R, d, invariant_form): return invariant_form from sage.matrix.constructor import matrix + m = matrix(R, d, d, invariant_form) if m.is_singular(): @@ -184,8 +187,7 @@ def normalize_args_invariant_form(R, d, invariant_form): class NamedMatrixGroup_generic(CachedRepresentation, MatrixGroup_generic): - def __init__(self, degree, base_ring, special, sage_name, latex_string, - category=None, invariant_form=None): + def __init__(self, degree, base_ring, special, sage_name, latex_string, category=None, invariant_form=None): """ Base class for "named" matrix groups. diff --git a/src/sage/groups/matrix_gps/named_group_gap.py b/src/sage/groups/matrix_gps/named_group_gap.py index 926ae0649a0..4a5ef1f2cfc 100644 --- a/src/sage/groups/matrix_gps/named_group_gap.py +++ b/src/sage/groups/matrix_gps/named_group_gap.py @@ -21,8 +21,7 @@ class NamedMatrixGroup_gap(NamedMatrixGroup_generic, MatrixGroup_gap): - def __init__(self, degree, base_ring, special, sage_name, latex_string, - gap_command_string, category=None): + def __init__(self, degree, base_ring, special, sage_name, latex_string, gap_command_string, category=None): """ Base class for "named" matrix groups using LibGAP. @@ -49,9 +48,9 @@ def __init__(self, degree, base_ring, special, sage_name, latex_string, True """ from sage.libs.gap.libgap import libgap + group = libgap.eval(gap_command_string) - MatrixGroup_gap.__init__(self, degree, base_ring, group, - category=category) + MatrixGroup_gap.__init__(self, degree, base_ring, group, category=category) self._special = special self._gap_string = gap_command_string self._name_string = sage_name diff --git a/src/sage/groups/matrix_gps/orthogonal.py b/src/sage/groups/matrix_gps/orthogonal.py index 0e8536fed5f..d298eb65d0e 100644 --- a/src/sage/groups/matrix_gps/orthogonal.py +++ b/src/sage/groups/matrix_gps/orthogonal.py @@ -95,9 +95,7 @@ from sage.rings.finite_rings.finite_field_base import FiniteField from sage.misc.latex import latex from sage.misc.cachefunc import cached_method -from sage.groups.matrix_gps.named_group import ( - normalize_args_vectorspace, normalize_args_invariant_form, - NamedMatrixGroup_generic) +from sage.groups.matrix_gps.named_group import normalize_args_vectorspace, normalize_args_invariant_form, NamedMatrixGroup_generic def normalize_args_e(degree, ring, e): @@ -144,6 +142,7 @@ def normalize_args_e(degree, ring, e): # Orthogonal Group: common Code for both GO and SO ############################################################################### + def _OG(n, R, special, e=0, var='a', invariant_form=None): r""" This function is commonly used by the functions GO and SO to avoid @@ -193,19 +192,14 @@ def _OG(n, R, special, e=0, var='a', invariant_form=None): except ValueError: inserted_text = "with respect to symmetric form" - name = '{0} Orthogonal Group of degree {1} over {2} {3}\n{4}'.format( - prefix, degree, ring, inserted_text, invariant_form) - ltx = r'\text{{{0}O}}_{{{1}}}({2})\text{{ {3} }}{4}'.format( - ltx_prefix, degree, latex(ring), inserted_text, - latex(invariant_form)) + name = '{0} Orthogonal Group of degree {1} over {2} {3}\n{4}'.format(prefix, degree, ring, inserted_text, invariant_form) + ltx = r'\text{{{0}O}}_{{{1}}}({2})\text{{ {3} }}{4}'.format(ltx_prefix, degree, latex(ring), inserted_text, latex(invariant_form)) else: name = '{0} Orthogonal Group of degree {1} over {2}'.format(prefix, degree, ring) ltx = r'\text{{{0}O}}_{{{1}}}({2})'.format(ltx_prefix, degree, latex(ring)) else: name = '{0} Orthogonal Group of degree {1} and form parameter {2} over {3}'.format(prefix, degree, e, ring) - ltx = r'\text{{{0}O}}_{{{1}}}({2}, {3})'.format(ltx_prefix, degree, - latex(ring), - '+' if e == 1 else '-') + ltx = r'\text{{{0}O}}_{{{1}}}({2}, {3})'.format(ltx_prefix, degree, latex(ring), '+' if e == 1 else '-') if isinstance(ring, FiniteField): try: @@ -223,6 +217,7 @@ def _OG(n, R, special, e=0, var='a', invariant_form=None): # General Orthogonal Group ######################################################################## + def GO(n, R, e=0, var='a', invariant_form=None): r""" Return the general orthogonal group. @@ -335,6 +330,7 @@ def GO(n, R, e=0, var='a', invariant_form=None): # Special Orthogonal Group ######################################################################## + def SO(n, R, e=None, var='a', invariant_form=None): r""" Return the special orthogonal group. @@ -443,6 +439,7 @@ def SO(n, R, e=None, var='a', invariant_form=None): # Orthogonal Group class ######################################################################## + class OrthogonalMatrixGroup_generic(NamedMatrixGroup_generic): r""" General Orthogonal Group over arbitrary rings. @@ -510,6 +507,7 @@ def invariant_bilinear_form(self): return self._invariant_form from sage.matrix.constructor import identity_matrix + m = identity_matrix(self.base_ring(), self.degree()) m.set_immutable() return m diff --git a/src/sage/groups/matrix_gps/orthogonal_gap.py b/src/sage/groups/matrix_gps/orthogonal_gap.py index 39947bda211..c2b32d1e961 100644 --- a/src/sage/groups/matrix_gps/orthogonal_gap.py +++ b/src/sage/groups/matrix_gps/orthogonal_gap.py @@ -36,6 +36,7 @@ class OrthogonalMatrixGroup_gap(OrthogonalMatrixGroup_generic, NamedMatrixGroup_ sage: isinstance(G, FinitelyGeneratedMatrixGroup_gap) True """ + @cached_method def invariant_bilinear_form(self): """ @@ -83,7 +84,7 @@ def invariant_bilinear_form(self): m.set_immutable() return m - invariant_form = invariant_bilinear_form # alias (analogues to symplectic and unitary cases) + invariant_form = invariant_bilinear_form # alias (analogues to symplectic and unitary cases) @cached_method def invariant_quadratic_form(self): diff --git a/src/sage/groups/matrix_gps/pickling_overrides.py b/src/sage/groups/matrix_gps/pickling_overrides.py index 9a62d03e6c4..ce2de3a09c2 100644 --- a/src/sage/groups/matrix_gps/pickling_overrides.py +++ b/src/sage/groups/matrix_gps/pickling_overrides.py @@ -34,13 +34,12 @@ def __setstate__(self, state): ring = state['_MatrixGroup_gap__R'] degree = state['_MatrixGroup_gap__n'] from sage.libs.gap.libgap import libgap + libgap_group = libgap.Group(libgap(matrix_gens)) self.__init__(degree, ring, libgap_group) -register_unpickle_override( - 'sage.groups.matrix_gps.matrix_group', 'MatrixGroup_gens_finite_field', - LegacyMatrixGroup) +register_unpickle_override('sage.groups.matrix_gps.matrix_group', 'MatrixGroup_gens_finite_field', LegacyMatrixGroup) class LegacyMatrixGroupElement(MatrixGroupElement_gap): @@ -76,9 +75,7 @@ def __setstate__(self, state): self.__init__(parent, m, check=False) -register_unpickle_override( - 'sage.groups.matrix_gps.matrix_group_element', 'MatrixGroupElement', - LegacyMatrixGroupElement) +register_unpickle_override('sage.groups.matrix_gps.matrix_group_element', 'MatrixGroupElement', LegacyMatrixGroupElement) class LegacyGeneralLinearGroup(LinearMatrixGroup_generic): @@ -105,6 +102,4 @@ def __setstate__(self, state): self.__init__(G.degree(), G.base_ring(), G._special, G._name_string, G._latex_string) -register_unpickle_override( - 'sage.groups.matrix_gps.general_linear', 'GeneralLinearGroup_finite_field', - LegacyGeneralLinearGroup) +register_unpickle_override('sage.groups.matrix_gps.general_linear', 'GeneralLinearGroup_finite_field', LegacyGeneralLinearGroup) diff --git a/src/sage/groups/matrix_gps/symplectic.py b/src/sage/groups/matrix_gps/symplectic.py index bbcf92b1bcf..8dfda105309 100644 --- a/src/sage/groups/matrix_gps/symplectic.py +++ b/src/sage/groups/matrix_gps/symplectic.py @@ -47,15 +47,14 @@ from sage.misc.latex import latex from sage.misc.cachefunc import cached_method from sage.rings.finite_rings.finite_field_base import FiniteField -from sage.groups.matrix_gps.named_group import ( - normalize_args_vectorspace, normalize_args_invariant_form, - NamedMatrixGroup_generic) +from sage.groups.matrix_gps.named_group import normalize_args_vectorspace, normalize_args_invariant_form, NamedMatrixGroup_generic ############################################################################### # Symplectic Group ############################################################################### + def Sp(n, R, var='a', invariant_form=None): r""" Return the symplectic group. @@ -156,10 +155,8 @@ def Sp(n, R, var='a', invariant_form=None): if not invariant_form.is_alternating(): raise ValueError("invariant_form must be alternating") - name = 'Symplectic Group of degree {0} over {1} with respect to alternating bilinear form\n{2}'.format( - degree, ring, invariant_form) - ltx = r'\text{{Sp}}_{{{0}}}({1})\text{{ with respect to alternating bilinear form}}{2}'.format( - degree, latex(ring), latex(invariant_form)) + name = 'Symplectic Group of degree {0} over {1} with respect to alternating bilinear form\n{2}'.format(degree, ring, invariant_form) + ltx = r'\text{{Sp}}_{{{0}}}({1})\text{{ with respect to alternating bilinear form}}{2}'.format(degree, latex(ring), latex(invariant_form)) else: name = 'Symplectic Group of degree {0} over {1}'.format(degree, ring) ltx = r'\text{{Sp}}_{{{0}}}({1})'.format(degree, latex(ring)) @@ -227,9 +224,10 @@ def invariant_form(self): R = self.base_ring() d = self.degree() from sage.matrix.constructor import zero_matrix + m = zero_matrix(R, d) for i in range(d): - m[i, d-i-1] = 1 if i < d/2 else -1 + m[i, d - i - 1] = 1 if i < d / 2 else -1 m.set_immutable() return m diff --git a/src/sage/groups/matrix_gps/unitary.py b/src/sage/groups/matrix_gps/unitary.py index e16ffb6a46b..467b8f8f4af 100644 --- a/src/sage/groups/matrix_gps/unitary.py +++ b/src/sage/groups/matrix_gps/unitary.py @@ -59,9 +59,7 @@ from sage.rings.finite_rings.finite_field_base import FiniteField from sage.misc.latex import latex from sage.misc.cachefunc import cached_method -from sage.groups.matrix_gps.named_group import ( - normalize_args_vectorspace, normalize_args_invariant_form, - NamedMatrixGroup_generic) +from sage.groups.matrix_gps.named_group import normalize_args_vectorspace, normalize_args_invariant_form, NamedMatrixGroup_generic def finite_field_sqrt(ring): @@ -88,6 +86,7 @@ def finite_field_sqrt(ring): # Unitary Group: common Code for both GU and SU ############################################################################### + def _UG(n, R, special, var='a', invariant_form=None): r""" This function is commonly used by the functions :func:`GU` and :func:`SU` @@ -125,10 +124,8 @@ def _UG(n, R, special, var='a', invariant_form=None): except ValueError: inserted_text = "with respect to hermitian form" - name = '{0} Unitary Group of degree {1} over {2} {3}\n{4}'.format(prefix, - degree, ring, inserted_text, invariant_form) - ltx = r'\text{{{0}U}}_{{{1}}}({2})\text{{ {3} }}{4}'.format(latex_prefix, - degree, latex(ring), inserted_text, latex(invariant_form)) + name = '{0} Unitary Group of degree {1} over {2} {3}\n{4}'.format(prefix, degree, ring, inserted_text, invariant_form) + ltx = r'\text{{{0}U}}_{{{1}}}({2})\text{{ {3} }}{4}'.format(latex_prefix, degree, latex(ring), inserted_text, latex(invariant_form)) else: name = '{0} Unitary Group of degree {1} over {2}'.format(prefix, degree, ring) ltx = r'\text{{{0}U}}_{{{1}}}({2})'.format(latex_prefix, degree, latex(ring)) @@ -142,14 +139,14 @@ def _UG(n, R, special, var='a', invariant_form=None): cmd = '{0}U({1}, {2})'.format(latex_prefix, degree, q) return UnitaryMatrixGroup_gap(degree, ring, special, name, ltx, cmd) - return UnitaryMatrixGroup_generic(degree, ring, special, name, ltx, - invariant_form=invariant_form) + return UnitaryMatrixGroup_generic(degree, ring, special, name, ltx, invariant_form=invariant_form) ############################################################################### # General Unitary Group ############################################################################### + def GU(n, R, var='a', invariant_form=None): r""" Return the general unitary group. @@ -264,6 +261,7 @@ def GU(n, R, var='a', invariant_form=None): # Special Unitary Group ############################################################################### + def SU(n, R, var='a', invariant_form=None): r""" The special unitary group `SU( d, R )` consists of all `d \times d` @@ -356,6 +354,7 @@ def SU(n, R, var='a', invariant_form=None): # Unitary Group class ######################################################################## + class UnitaryMatrixGroup_generic(NamedMatrixGroup_generic): r""" General Unitary Group over arbitrary rings. @@ -405,6 +404,7 @@ def invariant_form(self): return self._invariant_form from sage.matrix.constructor import identity_matrix + m = identity_matrix(self.base_ring(), self.degree()) m.set_immutable() return m diff --git a/src/sage/groups/matrix_gps/unitary_gap.py b/src/sage/groups/matrix_gps/unitary_gap.py index ab0512a4803..e2ca948c356 100644 --- a/src/sage/groups/matrix_gps/unitary_gap.py +++ b/src/sage/groups/matrix_gps/unitary_gap.py @@ -56,6 +56,7 @@ def invariant_form(self): # note that self.gap().InvariantSesquilinearForm()['matrix'].matrix().base_ring() != R for example for self = GU(3.2) # therefore we have to coerce into the right matrix space from sage.matrix.constructor import matrix + m = matrix(R, d, d, self.gap().InvariantSesquilinearForm()['matrix'].matrix()) m.set_immutable() return m diff --git a/src/sage/groups/misc_gps/argument_groups.py b/src/sage/groups/misc_gps/argument_groups.py index 470eadebac1..29911bcd35d 100644 --- a/src/sage/groups/misc_gps/argument_groups.py +++ b/src/sage/groups/misc_gps/argument_groups.py @@ -31,6 +31,7 @@ Classes and Methods =================== """ + # **************************************************************************** # Copyright (C) 2018 Daniel Krenn # @@ -94,12 +95,8 @@ def __init__(self, parent, element, normalize=True): except (TypeError, ValueError) as e: from sage.rings.asymptotic.misc import combine_exceptions from sage.structure.element import parent as parent_function - raise combine_exceptions( - ValueError( - '{} ({}) is not in {}'.format(element, - parent_function(element), - parent.base())), - e) + + raise combine_exceptions(ValueError('{} ({}) is not in {}'.format(element, parent_function(element), parent.base())), e) if normalize: element = self._normalize_(element) @@ -219,9 +216,7 @@ def _lt_(self, other): ... RuntimeError: cannot decide '<' for the roots of unity -1 and 1 """ - raise RuntimeError("cannot decide '<' " - "for the roots of unity " - "{} and {}".format(self, other)) + raise RuntimeError("cannot decide '<' " "for the roots of unity " "{} and {}".format(self, other)) def _act_on_(self, other, is_left): r""" @@ -270,13 +265,8 @@ def _act_on_(self, other, is_left): other = S.coerce(other) except (TypeError, ValueError) as e: from sage.rings.asymptotic.misc import combine_exceptions - raise combine_exceptions( - TypeError('{} ({}) cannot ({}-)act on ' - '{} ({})'.format( - self, self.parent(), - 'left' if is_left else 'right', - other, P)), - e) + + raise combine_exceptions(TypeError('{} ({}) cannot ({}-)act on ' '{} ({})'.format(self, self.parent(), 'left' if is_left else 'right', other, P)), e) return self._symbolic_(S) * other def __abs__(self): @@ -293,6 +283,7 @@ def __abs__(self): Integer Ring """ from sage.rings.integer_ring import ZZ + return ZZ.one() @@ -345,6 +336,7 @@ def _determine_category_(category): """ if category is None: from sage.categories.groups import Groups + category = Groups().Commutative() return category @@ -600,6 +592,7 @@ def is_minus_one(self): False """ from sage.rings.rational_field import QQ + return self.exponent == QQ((1, 2)) @@ -654,6 +647,7 @@ def _repr_short_(self): 'UU_RR' """ from sage.rings.asymptotic.misc import parent_to_repr_short + s = parent_to_repr_short(self.base()) if ' ' in s: s = '({})'.format(s) @@ -762,16 +756,13 @@ def _element_constructor_(self, data, exponent=None, **kwds): try: exponent = QQ(discrete_log(data, zeta)) / QQ(n) except ValueError as e: - raise combine_exceptions( - ValueError('{} is not in {}'.format(data, self)), e) + raise combine_exceptions(ValueError('{} is not in {}'.format(data, self)), e) if exponent is None: raise ValueError('{} is not in {}'.format(data, self)) elif not isinstance(data, int) or data != 0: - raise ValueError('input is ambiguous: ' - '{} as well as exponent={} ' - 'specified'.format(data, exponent)) + raise ValueError('input is ambiguous: ' '{} as well as exponent={} ' 'specified'.format(data, exponent)) return self.element_class(self, exponent, **kwds) @@ -944,6 +935,7 @@ def _repr_(self): zeta3^2 """ from sage.rings.rational_field import QQ + if self.exponent == 0: return '1' if self.exponent == QQ((1, 2)): @@ -1006,6 +998,7 @@ def __init__(self, category): Rational Field """ from sage.rings.rational_field import QQ + super().__init__(base=QQ, category=category) def _repr_(self): @@ -1174,7 +1167,7 @@ def __pow__(self, exponent): """ from sage.symbolic.ring import SymbolicRing - element = self._element_ ** exponent + element = self._element_**exponent parent = element.parent() if isinstance(parent, SymbolicRing): return self._symbolic_(parent) ** exponent @@ -1243,6 +1236,7 @@ def _repr_short_(self): 'Arg_CC' """ from sage.rings.asymptotic.misc import parent_to_repr_short, repr_op + return repr_op('Arg', '_', parent_to_repr_short(self.base())) def _element_constructor_(self, data, **kwds): @@ -1396,8 +1390,7 @@ def __init__(self, parent, element, normalize=True): """ super().__init__(parent, int(element), normalize=normalize) if self._element_ not in (-1, 1): - raise ValueError('{} is not allowed ' - '(only -1 or 1 is)'.format(element)) + raise ValueError('{} is not allowed ' '(only -1 or 1 is)'.format(element)) @staticmethod def _normalize_(element): @@ -1471,7 +1464,7 @@ def __pow__(self, exponent): Symbolic Ring """ - result = self._element_ ** exponent + result = self._element_**exponent P = self.parent() try: return P.element_class(P, result) @@ -1612,8 +1605,7 @@ def __classcall__(cls, category=None): Category of finite commutative groups """ category = cls._determine_category_(category).Finite() - return super(AbstractArgumentGroup, cls).__classcall__( - cls, category) + return super(AbstractArgumentGroup, cls).__classcall__(cls, category) def __init__(self, category): r""" @@ -1782,12 +1774,8 @@ class ArgumentGroupFactory(UniqueFactory): Unit Circle Group with Argument of Elements in Cyclotomic Field of order 3 and degree 2 """ - def create_key_and_extra_args(self, - data=None, - specification=None, - domain=None, - exponents=None, - **kwds): + + def create_key_and_extra_args(self, data=None, specification=None, domain=None, exponents=None, **kwds): r""" Normalize the input. @@ -1812,17 +1800,8 @@ def create_key_and_extra_args(self, from sage.rings.qqbar import AA from sage.rings.rational_field import QQ - if not exactly_one_is_true( - (data is not None, - specification is not None, - domain is not None, - exponents is not None)): - raise ValueError( - 'input ambiguous: ' + - ', '.join('{}={}'.format(s, v) for s, v in - [('data', data), ('specification', specification), - ('domain', domain), ('exponents', exponents)] - if v is not None)) + if not exactly_one_is_true((data is not None, specification is not None, domain is not None, exponents is not None)): + raise ValueError('input ambiguous: ' + ', '.join('{}={}'.format(s, v) for s, v in [('data', data), ('specification', specification), ('domain', domain), ('exponents', exponents)] if v is not None)) if data is not None: if isinstance(data, str): @@ -1837,22 +1816,19 @@ def create_key_and_extra_args(self, return (SignGroup, ()), kwds if specification.startswith('UU_'): from sage.rings.asymptotic.misc import repr_short_to_parent + exponents = repr_short_to_parent(specification[3:]) elif specification.startswith('Arg_') or specification.startswith('arg_'): from sage.rings.asymptotic.misc import repr_short_to_parent + domain = repr_short_to_parent(specification[4:]) else: raise ValueError('unknown specification {}'.format(specification)) if domain is not None: - if domain in (ZZ, QQ, AA) \ - or isinstance(domain, (sage.rings.abc.RealField, - sage.rings.abc.RealIntervalField, - sage.rings.abc.RealBallField)): + if domain in (ZZ, QQ, AA) or isinstance(domain, (sage.rings.abc.RealField, sage.rings.abc.RealIntervalField, sage.rings.abc.RealBallField)): return (SignGroup, ()), kwds - if isinstance(domain, (sage.rings.abc.ComplexField, - sage.rings.abc.ComplexIntervalField, - sage.rings.abc.ComplexBallField)): + if isinstance(domain, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexIntervalField, sage.rings.abc.ComplexBallField)): return (UnitCircleGroup, (domain._real_field(),)), kwds return (ArgumentByElementGroup, (domain,)), kwds diff --git a/src/sage/groups/misc_gps/imaginary_groups.py b/src/sage/groups/misc_gps/imaginary_groups.py index 0c942a6043d..ef098d7b536 100644 --- a/src/sage/groups/misc_gps/imaginary_groups.py +++ b/src/sage/groups/misc_gps/imaginary_groups.py @@ -19,6 +19,7 @@ Classes and Methods =================== """ + # **************************************************************************** # Copyright (C) 2018 Daniel Krenn # @@ -66,12 +67,8 @@ def __init__(self, parent, imag): except (TypeError, ValueError) as e: from sage.rings.asymptotic.misc import combine_exceptions from sage.structure.element import parent as parent_function - raise combine_exceptions( - ValueError( - '{} ({}) is not in {}'.format(imag, - parent_function(imag), - parent.base())), - e) + + raise combine_exceptions(ValueError('{} ({}) is not in {}'.format(imag, parent_function(imag), parent.base())), e) def imag(self): r""" @@ -154,9 +151,7 @@ def _lt_(self, other): ... RuntimeError: cannot decide '<' for imaginary elements 2*I and I """ - raise RuntimeError("cannot decide '<' " - "for imaginary elements " - "{} and {}".format(self, other)) + raise RuntimeError("cannot decide '<' " "for imaginary elements " "{} and {}".format(self, other)) def _repr_(self): r""" @@ -178,6 +173,7 @@ def _repr_(self): -42*I """ from sage.rings.asymptotic.misc import repr_op + if self._imag_ == 0: return '0' if self._imag_ == 1: @@ -297,6 +293,7 @@ def _determine_category_(category): """ if category is None: from sage.categories.additive_groups import AdditiveGroups + category = AdditiveGroups().AdditiveCommutative() return category @@ -362,6 +359,7 @@ def _repr_short_(self): 'ZZ*I' """ from sage.rings.asymptotic.misc import parent_to_repr_short, repr_op + return repr_op(parent_to_repr_short(self.base()), '*', 'I') def _element_constructor_(self, data, imag=None): @@ -461,9 +459,7 @@ def _element_constructor_(self, data, imag=None): if data.real() == 0: imag = data.imag() else: - raise ValueError( - '{} is not in {} because it is not ' - 'purely imaginary'.format(data, self)) + raise ValueError('{} is not in {} because it is not ' 'purely imaginary'.format(data, self)) except AttributeError: pass @@ -471,8 +467,6 @@ def _element_constructor_(self, data, imag=None): raise ValueError('{} is not in {}'.format(data, self)) elif not isinstance(data, int) or data != 0: - raise ValueError('input is ambiguous: ' - '{} as well as imag={} ' - 'specified'.format(data, imag)) + raise ValueError('input is ambiguous: ' '{} as well as imag={} ' 'specified'.format(data, imag)) return self.element_class(self, imag) diff --git a/src/sage/groups/pari_group.py b/src/sage/groups/pari_group.py index fb460e5b902..b72b657f2ef 100644 --- a/src/sage/groups/pari_group.py +++ b/src/sage/groups/pari_group.py @@ -54,8 +54,7 @@ def __eq__(self, other): sage: G1 == G2 False """ - return (isinstance(other, PariGroup) and - (self.__x, self.__degree) == (other.__x, other.__degree)) + return isinstance(other, PariGroup) and (self.__x, self.__degree) == (other.__x, other.__degree) def __ne__(self, other): """ diff --git a/src/sage/groups/perm_gps/all.py b/src/sage/groups/perm_gps/all.py index 2cda7602d8c..ae364c9b3af 100644 --- a/src/sage/groups/perm_gps/all.py +++ b/src/sage/groups/perm_gps/all.py @@ -1,20 +1,11 @@ -from sage.groups.perm_gps.permgroup_named import (SymmetricGroup, AlternatingGroup, - DihedralGroup, SplitMetacyclicGroup, - SemidihedralGroup, CyclicPermutationGroup, - DiCyclicGroup, TransitiveGroup, - PGL, PSL, PSp, PSU, PGU, - MathieuGroup, KleinFourGroup, QuaternionGroup, - PrimitiveGroup, PrimitiveGroups, - SuzukiGroup, TransitiveGroups, - GeneralDihedralGroup, SmallPermutationGroup) +from sage.groups.perm_gps.permgroup_named import SymmetricGroup, AlternatingGroup, DihedralGroup, SplitMetacyclicGroup, SemidihedralGroup, CyclicPermutationGroup, DiCyclicGroup, TransitiveGroup, PGL, PSL, PSp, PSU, PGU, MathieuGroup, KleinFourGroup, QuaternionGroup, PrimitiveGroup, PrimitiveGroups, SuzukiGroup, TransitiveGroups, GeneralDihedralGroup, SmallPermutationGroup from sage.groups.perm_gps.permgroup import PermutationGroup, PermutationGroup_generic, PermutationGroup_subgroup, direct_product_permgroups from sage.groups.perm_gps.constructor import PermutationGroupElement -from sage.groups.perm_gps.permgroup_morphism import (PermutationGroupMorphism as PermutationGroupMap, - PermutationGroupMorphism_im_gens, - PermutationGroupMorphism_id) +from sage.groups.perm_gps.permgroup_morphism import PermutationGroupMorphism as PermutationGroupMap, PermutationGroupMorphism_im_gens, PermutationGroupMorphism_id + PermutationGroupMorphism = PermutationGroupMorphism_im_gens from sage.groups.perm_gps.cubegroup import CubeGroup, RubiksCube diff --git a/src/sage/groups/perm_gps/constructor.py b/src/sage/groups/perm_gps/constructor.py index c80fca05f00..a2714b963ad 100644 --- a/src/sage/groups/perm_gps/constructor.py +++ b/src/sage/groups/perm_gps/constructor.py @@ -7,6 +7,7 @@ objects have a more group theoretic flavor than the more combinatorial :class:`~sage.combinat.permutation.Permutation`. """ + # **************************************************************************** # Copyright (C) 2006 William Stein # Copyright (C) 2006 David Joyner diff --git a/src/sage/groups/perm_gps/cubegroup.py b/src/sage/groups/perm_gps/cubegroup.py index 125f2857265..557814d1152 100644 --- a/src/sage/groups/perm_gps/cubegroup.py +++ b/src/sage/groups/perm_gps/cubegroup.py @@ -101,6 +101,7 @@ from sage.rings.real_double import RDF from sage.groups.perm_gps.permgroup_element import PermutationGroupElement from sage.misc.lazy_import import lazy_import + lazy_import("sage.plot.polygon", "polygon") lazy_import("sage.plot.text", "text") pi = RDF.pi() @@ -112,16 +113,16 @@ # ###################### predefined colors ################## named_colors = { - 'red': (1, 0, 0), # F face - 'green': (0, 1, 0), # R face - 'blue': (0, 0, 1), # D face - 'yellow': (1, 1, 0), # L face - 'white': (1, 1, 1), # none - 'orange': (1, 0.6, 0.3), # B face - 'purple': (1, 0, 1), # none - 'lpurple': (1, 0.63, 1), # U face - 'lightblue': (0, 1, 1), # none - 'lgrey': (0.75, 0.75, 0.75), # sagemath.org color + 'red': (1, 0, 0), # F face + 'green': (0, 1, 0), # R face + 'blue': (0, 0, 1), # D face + 'yellow': (1, 1, 0), # L face + 'white': (1, 1, 1), # none + 'orange': (1, 0.6, 0.3), # B face + 'purple': (1, 0, 1), # none + 'lpurple': (1, 0.63, 1), # U face + 'lightblue': (0, 1, 1), # none + 'lgrey': (0.75, 0.75, 0.75), # sagemath.org color } globals().update(named_colors) @@ -140,7 +141,7 @@ def xproj(x, y, z, r): sage: xproj(1,2,3,rot) 0.6123724356957945 """ - return (y*r[1] - x*r[3])*r[2] + return (y * r[1] - x * r[3]) * r[2] def yproj(x, y, z, r): @@ -154,7 +155,7 @@ def yproj(x, y, z, r): sage: yproj(1,2,3,rot) 1.378497416975604 """ - return z*r[2] - (x*r[1] + y*r[2])*r[0] + return z * r[2] - (x * r[1] + y * r[2]) * r[0] def rotation_list(tilt, turn): @@ -170,8 +171,8 @@ def rotation_list(tilt, turn): """ from sage.functions.trig import sin from sage.functions.trig import cos - return [sin(tilt*pi/180.0), sin(turn*pi/180.0), - cos(tilt*pi/180.0), cos(turn*pi/180.0)] + + return [sin(tilt * pi / 180.0), sin(turn * pi / 180.0), cos(tilt * pi / 180.0), cos(turn * pi / 180.0)] def polygon_plot3d(points, tilt=30, turn=30, **kwargs): @@ -196,10 +197,10 @@ def polygon_plot3d(points, tilt=30, turn=30, **kwargs): ....: rgbcolor=green) """ rot = rotation_list(tilt, turn) - points2 = [(xproj(x, y, z, rot), yproj(x, y, z, rot)) - for (x, y, z) in points] + points2 = [(xproj(x, y, z, rot), yproj(x, y, z, rot)) for (x, y, z) in points] return polygon(points2, **kwargs) + # ########################################################## # ############ lots of "internal" utility plot functions ######### @@ -221,65 +222,65 @@ def inv_list(lst): face_polys = { -# ## bottom layer L, F, R, B - 'ldb': [[-3,0],[-2,0], [-2,1], [-3,1]], # square labeled 14 - 'ld': [[-2,0],[-1,0], [-1,1], [-2,1]], # square labeled 15 - 'lfd': [[-1,0],[0,0], [0,1], [-1,1]], # square labeled 16 - 'fdl': [[0,0],[1,0], [1,1], [0,1]], # square labeled 22 - 'fd': [[1,0],[2,0], [2,1], [1,1]], # square labeled 23 - 'frd': [[2,0],[3,0], [3,1], [2,1]], # square labeled 24 - 'rdf': [[3,0],[4,0], [4,1], [3,1]], # square labeled 30 - 'rd': [[4,0],[5,0], [5,1], [4,1]], # square labeled 31 - 'rbd': [[5,0],[6,0], [6,1], [5,1]], # square labeled 32 - 'bdr': [[6,0],[7,0], [7,1], [6,1]], # square labeled 38 - 'bd': [[7,0],[8,0], [8,1], [7,1]], # square labeled 39 - 'bld': [[8,0],[9,0], [9,1], [8,1]], # square labeled 40 -# ## middle layer L,F,R, B - 'lb': [[-3,1],[-2,1], [-2,2], [-3,2]], # square labeled 12 - 'l_center': [[-2,1],[-1,1], [-1,2], [-2,2]], # center square - 'lf': [[-1,1],[0,1], [0,2], [-1,2]], # square labeled 13 - 'fl': [[0,1],[1,1], [1,2], [0,2]], # square labeled 20 - 'f_center': [[1,1],[2,1], [2,2], [1,2]], # center square - 'fr': [[2,1],[3,1], [3,2], [2,2]], # square labeled 21 - 'rf': [[3,1],[4,1], [4,2], [3,2]], # square labeled 28 - 'r_center': [[4,1],[5,1], [5,2], [4,2]], # center square - 'rb': [[5,1],[6,1], [6,2], [5,2]], # square labeled 29 - 'br': [[6,1],[7,1], [7,2], [6,2]], # square labeled 36 - 'b_center': [[7,1],[8,1], [8,2], [7,2]], # center square - 'bl': [[8,1],[9,1], [9,2], [8,2]], # square labeled 37 -# ## top layer L, F, R, B - 'lbu': [[-3,2],[-2,2], [-2,3], [-3,3]], # square labeled 9 - 'lu': [[-2,2],[-1,2], [-1,3], [-2,3]], # square labeled 10 - 'luf': [[-1,2],[0,2], [0,3], [-1,3]], # square labeled 11 - 'flu': [[0,2],[1,2], [1,3], [0,3]], # square labeled 17 - 'fu': [[1,2],[2,2], [2,3], [1,3]], # square labeled 18 - 'fur': [[2,2],[3,2], [3,3], [2,3]], # square labeled 19 - 'ruf': [[3,2],[4,2], [4,3], [3,3]], # square labeled 25 - 'ru': [[4,2],[5,2], [5,3], [4,3]], # square labeled 26 - 'rub': [[5,2],[6,2], [6,3], [5,3]], # square labeled 27 - 'bur': [[6,2],[7,2], [7,3], [6,3]], # square labeled 33 - 'bu': [[7,2],[8,2], [8,3], [7,3]], # square labeled 34 - 'bul': [[8,2],[9,2], [9,3], [8,3]], # square labeled 35 -# down face - 'dlf': [[0,-1],[1,-1], [1,0], [0,0]], # square labeled 41 - 'df': [[1,-1],[2,-1], [2,0], [1,0]], # square labeled 42 - 'dfr': [[2,-1],[3,-1], [3,0], [2,0]], # square labeled 43 - 'dl': [[0,-2],[1,-2], [1,-1], [0,-1]], # square labeled 44 - 'd_center': [[1,-2],[2,-2], [2,-1], [1,-1]], # center square - 'dr': [[2,-2],[3,-2], [3,-1], [2,-1]], # square labeled 45 - 'dlb': [[0,-3],[1,-3], [1,-2], [0,-2]], # square labeled 46 - 'db': [[1,-3],[2,-3], [2,-2], [1,-2]], # square labeled 47 - 'drb': [[2,-3],[3,-3], [3,-2], [2,-2]], # square labeled 48 -# up face - 'ufl': [[0,3],[1,3], [1,4], [0,4]], # square labeled 6 - 'uf': [[1,3],[2,3], [2,4], [1,4]], # square labeled 7 - 'urf': [[2,3],[3,3], [3,4], [2,4]], # square labeled 8 - 'ul': [[0,4],[1,4], [1,5], [0,5]], # square labeled 4 - 'u_center': [[1,4],[2,4], [2,5], [1,5]], # center square - 'ur': [[2,4],[3,4], [3,5], [2,5]], # square labeled 5 - 'ulb': [[0,6],[1,6], [1,5], [0,5]], # square labeled 1 - 'ub': [[1,6],[2,6], [2,5], [1,5]], # square labeled 2 - 'ubr': [[2,6],[3,6], [3,5], [2,5]], # square labeled 3 + # ## bottom layer L, F, R, B + 'ldb': [[-3, 0], [-2, 0], [-2, 1], [-3, 1]], # square labeled 14 + 'ld': [[-2, 0], [-1, 0], [-1, 1], [-2, 1]], # square labeled 15 + 'lfd': [[-1, 0], [0, 0], [0, 1], [-1, 1]], # square labeled 16 + 'fdl': [[0, 0], [1, 0], [1, 1], [0, 1]], # square labeled 22 + 'fd': [[1, 0], [2, 0], [2, 1], [1, 1]], # square labeled 23 + 'frd': [[2, 0], [3, 0], [3, 1], [2, 1]], # square labeled 24 + 'rdf': [[3, 0], [4, 0], [4, 1], [3, 1]], # square labeled 30 + 'rd': [[4, 0], [5, 0], [5, 1], [4, 1]], # square labeled 31 + 'rbd': [[5, 0], [6, 0], [6, 1], [5, 1]], # square labeled 32 + 'bdr': [[6, 0], [7, 0], [7, 1], [6, 1]], # square labeled 38 + 'bd': [[7, 0], [8, 0], [8, 1], [7, 1]], # square labeled 39 + 'bld': [[8, 0], [9, 0], [9, 1], [8, 1]], # square labeled 40 + # ## middle layer L,F,R, B + 'lb': [[-3, 1], [-2, 1], [-2, 2], [-3, 2]], # square labeled 12 + 'l_center': [[-2, 1], [-1, 1], [-1, 2], [-2, 2]], # center square + 'lf': [[-1, 1], [0, 1], [0, 2], [-1, 2]], # square labeled 13 + 'fl': [[0, 1], [1, 1], [1, 2], [0, 2]], # square labeled 20 + 'f_center': [[1, 1], [2, 1], [2, 2], [1, 2]], # center square + 'fr': [[2, 1], [3, 1], [3, 2], [2, 2]], # square labeled 21 + 'rf': [[3, 1], [4, 1], [4, 2], [3, 2]], # square labeled 28 + 'r_center': [[4, 1], [5, 1], [5, 2], [4, 2]], # center square + 'rb': [[5, 1], [6, 1], [6, 2], [5, 2]], # square labeled 29 + 'br': [[6, 1], [7, 1], [7, 2], [6, 2]], # square labeled 36 + 'b_center': [[7, 1], [8, 1], [8, 2], [7, 2]], # center square + 'bl': [[8, 1], [9, 1], [9, 2], [8, 2]], # square labeled 37 + # ## top layer L, F, R, B + 'lbu': [[-3, 2], [-2, 2], [-2, 3], [-3, 3]], # square labeled 9 + 'lu': [[-2, 2], [-1, 2], [-1, 3], [-2, 3]], # square labeled 10 + 'luf': [[-1, 2], [0, 2], [0, 3], [-1, 3]], # square labeled 11 + 'flu': [[0, 2], [1, 2], [1, 3], [0, 3]], # square labeled 17 + 'fu': [[1, 2], [2, 2], [2, 3], [1, 3]], # square labeled 18 + 'fur': [[2, 2], [3, 2], [3, 3], [2, 3]], # square labeled 19 + 'ruf': [[3, 2], [4, 2], [4, 3], [3, 3]], # square labeled 25 + 'ru': [[4, 2], [5, 2], [5, 3], [4, 3]], # square labeled 26 + 'rub': [[5, 2], [6, 2], [6, 3], [5, 3]], # square labeled 27 + 'bur': [[6, 2], [7, 2], [7, 3], [6, 3]], # square labeled 33 + 'bu': [[7, 2], [8, 2], [8, 3], [7, 3]], # square labeled 34 + 'bul': [[8, 2], [9, 2], [9, 3], [8, 3]], # square labeled 35 + # down face + 'dlf': [[0, -1], [1, -1], [1, 0], [0, 0]], # square labeled 41 + 'df': [[1, -1], [2, -1], [2, 0], [1, 0]], # square labeled 42 + 'dfr': [[2, -1], [3, -1], [3, 0], [2, 0]], # square labeled 43 + 'dl': [[0, -2], [1, -2], [1, -1], [0, -1]], # square labeled 44 + 'd_center': [[1, -2], [2, -2], [2, -1], [1, -1]], # center square + 'dr': [[2, -2], [3, -2], [3, -1], [2, -1]], # square labeled 45 + 'dlb': [[0, -3], [1, -3], [1, -2], [0, -2]], # square labeled 46 + 'db': [[1, -3], [2, -3], [2, -2], [1, -2]], # square labeled 47 + 'drb': [[2, -3], [3, -3], [3, -2], [2, -2]], # square labeled 48 + # up face + 'ufl': [[0, 3], [1, 3], [1, 4], [0, 4]], # square labeled 6 + 'uf': [[1, 3], [2, 3], [2, 4], [1, 4]], # square labeled 7 + 'urf': [[2, 3], [3, 3], [3, 4], [2, 4]], # square labeled 8 + 'ul': [[0, 4], [1, 4], [1, 5], [0, 5]], # square labeled 4 + 'u_center': [[1, 4], [2, 4], [2, 5], [1, 5]], # center square + 'ur': [[2, 4], [3, 4], [3, 5], [2, 5]], # square labeled 5 + 'ulb': [[0, 6], [1, 6], [1, 5], [0, 5]], # square labeled 1 + 'ub': [[1, 6], [2, 6], [2, 5], [1, 5]], # square labeled 2 + 'ubr': [[2, 6], [3, 6], [3, 5], [2, 5]], # square labeled 3 } @@ -295,6 +296,7 @@ def create_poly(face, color): """ return polygon(face_polys[face], rgbcolor=color) + #################################################### @@ -379,30 +381,30 @@ def color_of_square(facet, colors=['lpurple', 'yellow', 'red', 'green', 'orange' cubie_center_list = { # centers of the cubies on the F,U, R faces - 1: [1//2, 1//2, 5//2], # ulb - 2: [1//2, 3//2, 5//2], # ub - 3: [1//2, 5//2, 5//2], # ubr - 4: [3//2, 1//2, 5//2], # ul - 5: [3//2, 5//2, 5//2], # ur - 6: [5//2, 1//2, 5//2], # ufl - 7: [5//2, 3//2, 5//2], # uf - 8: [5//2, 5//2, 5//2], # urf - 17: [5//2, 1//2, 5//2], # flu - 18: [5//2, 3//2, 5//2], # fu - 19: [5//2, 5//2, 5//2], # fur - 20: [5//2, 1//2, 3//2], # fl - 21: [5//2, 5//2, 3//2], # fr - 22: [5//2, 1//2, 1//2], # fdl - 23: [5//2, 3//2, 1//2], # fd - 24: [5//2, 5//2, 1//2], # frd - 25: [5//2, 5//2, 5//2], # rfu - 26: [3//2, 5//2, 5//2], # ru - 27: [1//2, 5//2, 5//2], # rub - 28: [5//2, 5//2, 3//2], # rf - 29: [1//2, 5//2, 3//2], # rb - 30: [5//2, 5//2, 1//2], # rdf - 31: [3//2, 5//2, 1//2], # rd - 32: [1//2, 5//2, 1//2], # rbd + 1: [1 // 2, 1 // 2, 5 // 2], # ulb + 2: [1 // 2, 3 // 2, 5 // 2], # ub + 3: [1 // 2, 5 // 2, 5 // 2], # ubr + 4: [3 // 2, 1 // 2, 5 // 2], # ul + 5: [3 // 2, 5 // 2, 5 // 2], # ur + 6: [5 // 2, 1 // 2, 5 // 2], # ufl + 7: [5 // 2, 3 // 2, 5 // 2], # uf + 8: [5 // 2, 5 // 2, 5 // 2], # urf + 17: [5 // 2, 1 // 2, 5 // 2], # flu + 18: [5 // 2, 3 // 2, 5 // 2], # fu + 19: [5 // 2, 5 // 2, 5 // 2], # fur + 20: [5 // 2, 1 // 2, 3 // 2], # fl + 21: [5 // 2, 5 // 2, 3 // 2], # fr + 22: [5 // 2, 1 // 2, 1 // 2], # fdl + 23: [5 // 2, 3 // 2, 1 // 2], # fd + 24: [5 // 2, 5 // 2, 1 // 2], # frd + 25: [5 // 2, 5 // 2, 5 // 2], # rfu + 26: [3 // 2, 5 // 2, 5 // 2], # ru + 27: [1 // 2, 5 // 2, 5 // 2], # rub + 28: [5 // 2, 5 // 2, 3 // 2], # rf + 29: [1 // 2, 5 // 2, 3 // 2], # rb + 30: [5 // 2, 5 // 2, 1 // 2], # rdf + 31: [3 // 2, 5 // 2, 1 // 2], # rd + 32: [1 // 2, 5 // 2, 1 // 2], # rbd } @@ -435,53 +437,53 @@ def cubie_colors(label, state0): clr_any = named_colors['white'] state = inv_list(state0) if label == 1: - return [clr_any, named_colors[color_of_square(state[1-1])], clr_any] #ulb, + return [clr_any, named_colors[color_of_square(state[1 - 1])], clr_any] # ulb, if label == 2: - return [clr_any,named_colors[color_of_square(state[2-1])],clr_any] # ub, + return [clr_any, named_colors[color_of_square(state[2 - 1])], clr_any] # ub, if label == 3: - return [clr_any, named_colors[color_of_square(state[3-1])], named_colors[color_of_square(state[27-1])]] # ubr, + return [clr_any, named_colors[color_of_square(state[3 - 1])], named_colors[color_of_square(state[27 - 1])]] # ubr, if label == 4: - return [clr_any, named_colors[color_of_square(state[4-1])], clr_any] # ul, + return [clr_any, named_colors[color_of_square(state[4 - 1])], clr_any] # ul, if label == 5: - return [clr_any, named_colors[color_of_square(state[5-1])], named_colors[color_of_square(state[26-1])]] # ur, + return [clr_any, named_colors[color_of_square(state[5 - 1])], named_colors[color_of_square(state[26 - 1])]] # ur, if label == 6: - return [named_colors[color_of_square(state[17-1])], named_colors[color_of_square(state[6-1])], clr_any] # ufl, + return [named_colors[color_of_square(state[17 - 1])], named_colors[color_of_square(state[6 - 1])], clr_any] # ufl, if label == 7: - return [named_colors[color_of_square(state[18-1])], named_colors[color_of_square(state[7-1])], clr_any] # uf, + return [named_colors[color_of_square(state[18 - 1])], named_colors[color_of_square(state[7 - 1])], clr_any] # uf, if label == 8: - return [named_colors[color_of_square(state[19-1])], named_colors[color_of_square(state[8-1])], named_colors[color_of_square(state[25-1])]] # urf, + return [named_colors[color_of_square(state[19 - 1])], named_colors[color_of_square(state[8 - 1])], named_colors[color_of_square(state[25 - 1])]] # urf, if label == 17: - return [named_colors[color_of_square(state[17-1])], named_colors[color_of_square(state[6-1])], clr_any] # flu + return [named_colors[color_of_square(state[17 - 1])], named_colors[color_of_square(state[6 - 1])], clr_any] # flu if label == 18: - return [named_colors[color_of_square(state[18-1])], named_colors[color_of_square(state[7-1])], clr_any] # fu + return [named_colors[color_of_square(state[18 - 1])], named_colors[color_of_square(state[7 - 1])], clr_any] # fu if label == 19: - return [named_colors[color_of_square(state[19-1])], named_colors[color_of_square(state[8-1])], named_colors[color_of_square(state[25-1])]] # fur + return [named_colors[color_of_square(state[19 - 1])], named_colors[color_of_square(state[8 - 1])], named_colors[color_of_square(state[25 - 1])]] # fur if label == 20: - return [named_colors[color_of_square(state[20-1])], clr_any, clr_any] # fl + return [named_colors[color_of_square(state[20 - 1])], clr_any, clr_any] # fl if label == 21: - return [named_colors[color_of_square(state[21-1])], clr_any, named_colors[color_of_square(state[28-1])]] # fr + return [named_colors[color_of_square(state[21 - 1])], clr_any, named_colors[color_of_square(state[28 - 1])]] # fr if label == 22: - return [named_colors[color_of_square(state[22-1])], clr_any, clr_any] # fdl + return [named_colors[color_of_square(state[22 - 1])], clr_any, clr_any] # fdl if label == 23: - return [named_colors[color_of_square(state[23-1])], clr_any, clr_any] # fd + return [named_colors[color_of_square(state[23 - 1])], clr_any, clr_any] # fd if label == 24: - return [named_colors[color_of_square(state[24-1])], clr_any, named_colors[color_of_square(state[30-1])]] # frd + return [named_colors[color_of_square(state[24 - 1])], clr_any, named_colors[color_of_square(state[30 - 1])]] # frd if label == 25: - return [named_colors[color_of_square(state[19-1])],named_colors[color_of_square(state[8-1])],named_colors[color_of_square(state[25-1])]] #rfu, + return [named_colors[color_of_square(state[19 - 1])], named_colors[color_of_square(state[8 - 1])], named_colors[color_of_square(state[25 - 1])]] # rfu, if label == 26: - return [clr_any,named_colors[color_of_square(state[5-1])],named_colors[color_of_square(state[26-1])]] # ru, + return [clr_any, named_colors[color_of_square(state[5 - 1])], named_colors[color_of_square(state[26 - 1])]] # ru, if label == 27: - return [clr_any,named_colors[color_of_square(state[3-1])],named_colors[color_of_square(state[27-1])]] # rub, + return [clr_any, named_colors[color_of_square(state[3 - 1])], named_colors[color_of_square(state[27 - 1])]] # rub, if label == 28: - return [named_colors[color_of_square(state[21-1])],clr_any,named_colors[color_of_square(state[28-1])]] # rf, + return [named_colors[color_of_square(state[21 - 1])], clr_any, named_colors[color_of_square(state[28 - 1])]] # rf, if label == 29: - return [clr_any,clr_any,named_colors[color_of_square(state[29-1])]] # rb, + return [clr_any, clr_any, named_colors[color_of_square(state[29 - 1])]] # rb, if label == 30: - return [named_colors[color_of_square(state[24-1])],clr_any,named_colors[color_of_square(state[30-1])]] # rdf, + return [named_colors[color_of_square(state[24 - 1])], clr_any, named_colors[color_of_square(state[30 - 1])]] # rdf, if label == 31: - return [clr_any,clr_any,named_colors[color_of_square(state[31-1])]] # rd, + return [clr_any, clr_any, named_colors[color_of_square(state[31 - 1])]] # rd, if label == 32: - return [clr_any,clr_any,named_colors[color_of_square(state[32-1])]] #rbd, + return [clr_any, clr_any, named_colors[color_of_square(state[32 - 1])]] # rbd, def plot3d_cubie(cnt, clrs): @@ -501,12 +503,12 @@ def plot3d_cubie(cnt, clrs): x = cnt[0] - half y = cnt[1] - half z = cnt[2] - half - #ptsD = [[x+0,y+0,0+z],[x+1,y+0,0+z],[x+1,y+1,0+z],[x+0,y+1,0+z],[x+0,y+0,0+z]] - ptsF = [[x+1,y+0,0+z],[x+1,y+1,0+z],[x+1,y+1,1+z],[x+1,y+0,1+z],[x+1,y+0,0+z]] - #ptsB = [[x+0,y+0,0+z],[x+0,y+1,0+z],[x+0,y+1,1+z],[x+0,y+0,1+z],[x+0,y+0,0+z]] - ptsU = [[x+0,y+0,1+z],[x+1,y+0,1+z],[x+1,y+1,1+z],[x+0,y+1,1+z],[x+0,y+0,1+z]] - #ptsL = [[x+0,y+0,0+z],[x+1,y+0,0+z],[x+1,y+0,1+z],[x+0,y+0,1+z],[x+0,y+0,0+z]] - ptsR = [[x+0,y+1,0+z],[x+1,y+1,0+z],[x+1,y+1,1+z],[x+0,y+1,1+z],[x+0,y+1,0+z]] + # ptsD = [[x+0,y+0,0+z],[x+1,y+0,0+z],[x+1,y+1,0+z],[x+0,y+1,0+z],[x+0,y+0,0+z]] + ptsF = [[x + 1, y + 0, 0 + z], [x + 1, y + 1, 0 + z], [x + 1, y + 1, 1 + z], [x + 1, y + 0, 1 + z], [x + 1, y + 0, 0 + z]] + # ptsB = [[x+0,y+0,0+z],[x+0,y+1,0+z],[x+0,y+1,1+z],[x+0,y+0,1+z],[x+0,y+0,0+z]] + ptsU = [[x + 0, y + 0, 1 + z], [x + 1, y + 0, 1 + z], [x + 1, y + 1, 1 + z], [x + 0, y + 1, 1 + z], [x + 0, y + 0, 1 + z]] + # ptsL = [[x+0,y+0,0+z],[x+1,y+0,0+z],[x+1,y+0,1+z],[x+0,y+0,1+z],[x+0,y+0,0+z]] + ptsR = [[x + 0, y + 1, 0 + z], [x + 1, y + 1, 0 + z], [x + 1, y + 1, 1 + z], [x + 0, y + 1, 1 + z], [x + 0, y + 1, 0 + z]] P = polygon_plot3d(ptsR, rgbcolor=clrs[2]) P += polygon_plot3d(ptsU, rgbcolor=clrs[1]) P += polygon_plot3d(ptsF, rgbcolor=clrs[0]) @@ -559,6 +561,7 @@ class CubeGroup(PermutationGroup_generic): sage: groups.permutation.RubiksCube() The Rubik's cube group with generators R,L,F,B,U,D in SymmetricGroup(48). """ + def __init__(self): """ Initialize ``self``. @@ -594,7 +597,7 @@ def gen_names(self): sage: rubik.gen_names() ['B', 'D', 'F', 'L', 'R', 'U'] """ - return ['B','D','F','L','R','U'] + return ['B', 'D', 'F', 'L', 'R', 'U'] def __repr__(self): """ @@ -748,7 +751,7 @@ def parse(self, mv, check=True): for i in range(6): map[names[i]] = gens[i] g = self.identity() - mv = mv.strip().replace(" ","*").replace("**", "*").replace("'", "-1").replace('^','').replace('(','').replace(')','') + mv = mv.strip().replace(" ", "*").replace("**", "*").replace("'", "-1").replace('^', '').replace('(', '').replace(')', '') M = mv.split("*") for m in M: if not m: @@ -756,24 +759,24 @@ def parse(self, mv, check=True): elif len(m) == 1: g *= map[m[0]] else: - g *= map[m[0]]**int(m[1:]) + g *= map[m[0]] ** int(m[1:]) return g if isinstance(mv, dict): state = mv state_facets = [] keyss = sorted(state.keys()) for k in keyss: - r = state[k][0]+state[k][1]+state[k][2] + r = state[k][0] + state[k][1] + state[k][2] r.remove(0) state_facets = state_facets + r state0 = self.faces("") state0_facets = [] keyss = sorted(state0.keys()) for k in keyss: - r = state0[k][0]+state0[k][1]+state0[k][2] + r = state0[k][0] + state0[k][1] + state0[k][2] r.remove(0) state0_facets = state0_facets + r - p1 = [state0_facets.index(x) for x in range(1,49)] + p1 = [state0_facets.index(x) for x in range(1, 49)] p2 = [state_facets[j] for j in p1] return PermutationGroup_generic.__call__(self, p2, check) return PermutationGroup_generic.__call__(self, mv, check) @@ -830,12 +833,12 @@ def faces(self, mv): ('up', [[3, 5, 38], [2, 0, 36], [1, 4, 25]])] """ fcts = self.facets(self.parse(mv)) - faceR = [[fcts[24],fcts[25],fcts[26]],[fcts[27],0,fcts[28]],[fcts[29],fcts[30],fcts[31]]] - faceL = [[fcts[8],fcts[9],fcts[10]],[fcts[11],0,fcts[12]],[fcts[13],fcts[14],fcts[15]]] - faceU = [[fcts[0],fcts[1],fcts[2]],[fcts[3],0,fcts[4]],[fcts[5],fcts[6],fcts[7]]] - faceD = [[fcts[40],fcts[41],fcts[42]],[fcts[43],0,fcts[44]],[fcts[45],fcts[46],fcts[47]]] - faceF = [[fcts[16],fcts[17],fcts[18]],[fcts[19],0,fcts[20]],[fcts[21],fcts[22],fcts[23]]] - faceB = [[fcts[32],fcts[33],fcts[34]],[fcts[35],0,fcts[36]],[fcts[37],fcts[38],fcts[39]]] + faceR = [[fcts[24], fcts[25], fcts[26]], [fcts[27], 0, fcts[28]], [fcts[29], fcts[30], fcts[31]]] + faceL = [[fcts[8], fcts[9], fcts[10]], [fcts[11], 0, fcts[12]], [fcts[13], fcts[14], fcts[15]]] + faceU = [[fcts[0], fcts[1], fcts[2]], [fcts[3], 0, fcts[4]], [fcts[5], fcts[6], fcts[7]]] + faceD = [[fcts[40], fcts[41], fcts[42]], [fcts[43], 0, fcts[44]], [fcts[45], fcts[46], fcts[47]]] + faceF = [[fcts[16], fcts[17], fcts[18]], [fcts[19], 0, fcts[20]], [fcts[21], fcts[22], fcts[23]]] + faceB = [[fcts[32], fcts[33], fcts[34]], [fcts[35], 0, fcts[36]], [fcts[37], fcts[38], fcts[39]]] return {'right': faceR, 'left': faceL, 'up': faceU, 'down': faceD, 'front': faceF, 'back': faceB} def move(self, mv): @@ -943,7 +946,7 @@ def repr2d(self, mv): line11 = " │%3d bottom%3d │\n" % (lst[43], lst[44]) line12 = " │%3d %3d %3d │\n" % (lst[45], lst[46], lst[47]) line13 = " └──────────────┘\n" - return line1+line2+line3+line4+line5+line6+line7+line8+line9+line10+line11+line12+line13 + return line1 + line2 + line3 + line4 + line5 + line6 + line7 + line8 + line9 + line10 + line11 + line12 + line13 def plot_cube(self, mv, title=True, colors=[lpurple, yellow, red, green, orange, blue]): r""" @@ -964,12 +967,12 @@ def plot_cube(self, mv, title=True, colors=[lpurple, yellow, red, green, orange, """ g = self.parse(mv) state = self.facets(g) - cubies = [create_poly(index2singmaster(state[x]), color_of_square(x+1, colors)) for x in range(48)] + cubies = [create_poly(index2singmaster(state[x]), color_of_square(x + 1, colors)) for x in range(48)] centers = [create_poly('%s_center' % "ulfrbd"[i], colors[i]) for i in range(6)] clrs = sum(cubies) + sum(centers) clrs.axes(show=False) if title: - t = text('sagemath.org', (7.8, -3.5),rgbcolor=lgrey) + t = text('sagemath.org', (7.8, -3.5), rgbcolor=lgrey) P = clrs + t P.axes(show=False) return P @@ -997,17 +1000,17 @@ def plot3d_cube(self, mv, title=True): """ g = self.parse(mv) state = self.facets(g) - cubiesR = [plot3d_cubie(cubie_centers(c),cubie_colors(c,state)) for c in [32,31,30,29,28,27,26,25]] + cubiesR = [plot3d_cubie(cubie_centers(c), cubie_colors(c, state)) for c in [32, 31, 30, 29, 28, 27, 26, 25]] cubeR = sum(cubiesR) - cubiesU = [plot3d_cubie(cubie_centers(c),cubie_colors(c,state)) for c in range(1,9)] + cubiesU = [plot3d_cubie(cubie_centers(c), cubie_colors(c, state)) for c in range(1, 9)] cubeU = sum(cubiesU) - cubiesF = [plot3d_cubie(cubie_centers(c),cubie_colors(c,state)) for c in [22,23,24,20,21]] + cubiesF = [plot3d_cubie(cubie_centers(c), cubie_colors(c, state)) for c in [22, 23, 24, 20, 21]] cubeF = sum(cubiesF) - centerR = polygon_plot3d([[1,3,1],[2,3,1],[2,3,2],[1,3,2],[1,3,1]],rgbcolor=green) - centerF = polygon_plot3d([[3,1,1],[3,2,1],[3,2,2],[3,1,2],[3,1,1]],rgbcolor=red) - centerU = polygon_plot3d([[1,1,3],[1,2,3],[2,2,3],[2,1,3],[1,1,3]],rgbcolor=lpurple) - centers = centerF+centerR+centerU - P = cubeR+cubeF+cubeU+centers + centerR = polygon_plot3d([[1, 3, 1], [2, 3, 1], [2, 3, 2], [1, 3, 2], [1, 3, 1]], rgbcolor=green) + centerF = polygon_plot3d([[3, 1, 1], [3, 2, 1], [3, 2, 2], [3, 1, 2], [3, 1, 1]], rgbcolor=red) + centerU = polygon_plot3d([[1, 1, 3], [1, 2, 3], [2, 2, 3], [2, 1, 3], [1, 1, 3]], rgbcolor=lpurple) + centers = centerF + centerR + centerU + P = cubeR + cubeF + cubeU + centers P.axes(show=False) if title: t1 = text('Up, Front, and Right faces. ', (-0.2, -2.5)) @@ -1117,6 +1120,7 @@ def solve(self, state, algorithm='default'): # 3d object generation ########################################################## + def cubie_faces(): """ This provides a map from the 6 faces of the 27 cubies to the 48 @@ -1157,8 +1161,8 @@ def cubie_faces(): ((1, 1, 1), [0, 0, 0, 48, 38, 32])] """ faceR = [[25, 26, 27], [28, -3, 29], [30, 31, 32]] # green - faceL = [[9, 10, 11], [12, -5, 13], [14, 15, 16]] # orange - faceU = [[1, 2, 3], [4, -6, 5], [6, 7, 8]] # red + faceL = [[9, 10, 11], [12, -5, 13], [14, 15, 16]] # orange + faceU = [[1, 2, 3], [4, -6, 5], [6, 7, 8]] # red faceD = [[41, 42, 43], [44, -1, 45], [46, 47, 48]] # purple faceF = [[17, 18, 19], [20, -4, 21], [22, 23, 24]] # yellow faceB = [[33, 34, 35], [36, -2, 37], [38, 39, 40]] # blue @@ -1218,7 +1222,8 @@ class RubiksCube(SageObject): sage: C == RubiksCube("L*R") True """ - def __init__(self, state=None, history=[], colors=[lpurple,yellow,red,green,orange,blue]): + + def __init__(self, state=None, history=[], colors=[lpurple, yellow, red, green, orange, blue]): """ Initialize ``self``. @@ -1350,12 +1355,12 @@ def cubie(self, size, gap, x, y, z, colors, stickers=True): """ sides = cubie_face_list[x, y, z] t = 2 * size + gap - my_colors = [colors[sides[i]+6] for i in range(6)] + my_colors = [colors[sides[i] + 6] for i in range(6)] if stickers: - B = Box(size, size, size, color=(.1, .1, .1)) - S = B + B.stickers(my_colors, size*.1, size*.01) - return S.translate(-t*x, -t*z, -t*y) - return ColorCube(size, [colors[sides[i]+6] for i in range(6)]).translate(-t*x, -t*z, -t*y) + B = Box(size, size, size, color=(0.1, 0.1, 0.1)) + S = B + B.stickers(my_colors, size * 0.1, size * 0.01) + return S.translate(-t * x, -t * z, -t * y) + return ColorCube(size, [colors[sides[i] + 6] for i in range(6)]).translate(-t * x, -t * z, -t * y) def plot3d(self, stickers=True): r""" @@ -1368,17 +1373,17 @@ def plot3d(self, stickers=True): Graphics3d Object """ while len(self.colors) < 7: - self.colors.append((.1, .1, .1)) - side_colors = [Texture(color=c, ambient=.75) for c in self.colors] - start_colors = sum([[c]*8 for c in side_colors], []) + self.colors.append((0.1, 0.1, 0.1)) + side_colors = [Texture(color=c, ambient=0.75) for c in self.colors] + start_colors = sum([[c] * 8 for c in side_colors], []) facets = self._group.facets(self._state) facet_colors = [0] * 48 for i in range(48): - facet_colors[facets[i]-1] = start_colors[i] + facet_colors[facets[i] - 1] = start_colors[i] all_colors = side_colors + facet_colors - pm = [-1,0,1] - C = sum([self.cubie(.15, .025, x, y, z, all_colors, stickers) for x in pm for y in pm for z in pm], Box(.35, .35, .35, color=self.colors[-1])) - return C.rotateZ(1.5) #.scale([1,-1,1]).rotateZ(1.5) + pm = [-1, 0, 1] + C = sum([self.cubie(0.15, 0.025, x, y, z, all_colors, stickers) for x in pm for y in pm for z in pm], Box(0.35, 0.35, 0.35, color=self.colors[-1])) + return C.rotateZ(1.5) # .scale([1,-1,1]).rotateZ(1.5) def show3d(self): r""" @@ -1454,8 +1459,10 @@ def solve(self, algorithm='default', timeout=15): True """ from sage.features.rubiks import Rubiks + if Rubiks().is_present(): import sage.interfaces.rubik # here to avoid circular referencing + if algorithm == 'default': algorithm = "hybrid" else: diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index 3824e476f0f..e54305f2d0a 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -126,6 +126,7 @@ small values or the parameter) they are made using explicit generators. """ + # **************************************************************************** # Copyright (C) 2006 William Stein # David Joyner @@ -152,8 +153,7 @@ from sage.sets.finite_enumerated_set import FiniteEnumeratedSet from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.groups.conjugacy_classes import ConjugacyClassGAP -from sage.structure.richcmp import (richcmp_method, - richcmp, rich_to_bool, op_EQ, op_NE) +from sage.structure.richcmp import richcmp_method, richcmp, rich_to_bool, op_EQ, op_NE def load_hap(): @@ -165,6 +165,7 @@ def load_hap(): sage: sage.groups.perm_gps.permgroup.load_hap() # optional - gap_package_hap """ from sage.features.gap import GapPackage + GapPackage("hap", spkg='gap_packages').require() libgap.load_package("hap") @@ -192,14 +193,17 @@ def hap_decorator(f): ... ValueError: p must be 0 or prime """ + @wraps(f) def wrapped(self, n, p=0): load_hap() from sage.arith.misc import is_prime + if not (p == 0 or is_prime(p)): raise ValueError("p must be 0 or prime") return f(self, n, p=p) + return wrapped @@ -223,6 +227,7 @@ def direct_product_permgroups(P): n = len(P) if n == 0: from sage.groups.perm_gps.permgroup_named import SymmetricGroup + return SymmetricGroup(0) if n == 1: return P[0] @@ -248,14 +253,11 @@ def from_gap_list(G, src): """ # src is a list of strings, each of which is a permutation of # integers in cycle notation. It may contain \n and spaces. - src = [str(g)[1:].split(")(") - for g in str(src).replace(" ", "").replace("\n", "")[1:-2].split("),")] + src = [str(g)[1:].split(")(") for g in str(src).replace(" ", "").replace("\n", "")[1:-2].split("),")] # src is a list of list of strings. Each string is a list of # integers separated by ',' - src = [G([tuple(G._domain_from_gap[int(x)] for x in cycle.split(",")) - for cycle in g]) - for g in src] + src = [G([tuple(G._domain_from_gap[int(x)] for x in cycle.split(",")) for cycle in g]) for g in src] # src is now a list of group elements return src @@ -401,8 +403,7 @@ def PermutationGroup(gens=None, *args, **kwds): return PermutationGroup_action(gens, action, domain, gap_group=gap_group) if args: raise ValueError("please use keywords gap_group=, domain=, canonicalize=, category= in the input") - return PermutationGroup_generic(gens=gens, gap_group=gap_group, domain=domain, - canonicalize=canonicalize, category=category) + return PermutationGroup_generic(gens=gens, gap_group=gap_group, domain=domain, canonicalize=canonicalize, category=category) @richcmp_method @@ -425,8 +426,8 @@ class PermutationGroup_generic(FiniteGroup): sage: G = PermutationGroup([[(1,2,3),(4,5)],[(3,4)]]) sage: TestSuite(G).run() """ - def __init__(self, gens=None, gap_group=None, canonicalize=True, - domain=None, category=None): + + def __init__(self, gens=None, gap_group=None, canonicalize=True, domain=None, category=None): r""" Initialize ``self``. @@ -483,12 +484,12 @@ def __init__(self, gens=None, gap_group=None, canonicalize=True, sage: h Group endomorphism of Permutation Group with generators [(1,2,3,4,5), (4,5,6)] """ - if (gens is None and gap_group is None): + if gens is None and gap_group is None: raise ValueError("you must specify gens or gap_group") from sage.categories.permutation_groups import PermutationGroups - category = (PermutationGroups().FinitelyGenerated().Finite() - .or_subcategory(category)) + + category = PermutationGroups().FinitelyGenerated().Finite().or_subcategory(category) super().__init__(category=category) if isinstance(gap_group, str): @@ -530,8 +531,8 @@ def __init__(self, gens=None, gap_group=None, canonicalize=True, self._domain = domain self._deg = len(self._domain) - self._domain_to_gap = {key: i+1 for i, key in enumerate(self._domain)} - self._domain_from_gap = {i+1: key for i, key in enumerate(self._domain)} + self._domain_to_gap = {key: i + 1 for i, key in enumerate(self._domain)} + self._domain_from_gap = {i + 1: key for i, key in enumerate(self._domain)} if not gens: # length 0 gens = [()] @@ -597,8 +598,8 @@ def construction(self): if len(gens) == 1 and gens[0].is_one(): return None from sage.categories.pushout import PermutationGroupFunctor - return (PermutationGroupFunctor(gens, self.domain()), - PermutationGroup([])) + + return (PermutationGroupFunctor(gens, self.domain()), PermutationGroup([])) @cached_method def _has_natural_domain(self): @@ -617,7 +618,7 @@ def _has_natural_domain(self): False """ domain = self.domain() - natural_domain = FiniteEnumeratedSet(list(range(1, len(domain)+1))) + natural_domain = FiniteEnumeratedSet(list(range(1, len(domain) + 1))) return domain == natural_domain def _gap_init_(self) -> str: @@ -725,6 +726,7 @@ def _Hom_(self, G, category=None, check=True): [2 0] """ from sage.groups.libgap_morphism import GroupHomset_libgap + return GroupHomset_libgap(self, G, category=category, check=check) def _magma_init_(self, magma): @@ -915,15 +917,13 @@ def _element_constructor_(self, x, check=True): x_parent = x.parent() # We check if we can lift ``x`` to ``self`` directly # so we can pass check=False for speed. - if (isinstance(x_parent, PermutationGroup_subgroup) - and x_parent._ambient_group is self): + if isinstance(x_parent, PermutationGroup_subgroup) and x_parent._ambient_group is self: return self.element_class(x, self, check=False) from sage.groups.perm_gps.permgroup_named import SymmetricGroup - compatible_domains = all(point in self._domain_to_gap - for point in x_parent.domain()) - if compatible_domains and (isinstance(self, SymmetricGroup) - or x.gap() in self.gap()): + + compatible_domains = all(point in self._domain_to_gap for point in x_parent.domain()) + if compatible_domains and (isinstance(self, SymmetricGroup) or x.gap() in self.gap()): return self.element_class(x, self, check=False) return self.element_class(x, self, check=check) @@ -1042,11 +1042,14 @@ def _coerce_map_from_(self, G): if G.is_subgroup(self): return True from sage.groups.libgap_wrapper import ParentLibGAP + if isinstance(G, ParentLibGAP): from sage.categories.homset import Hom + try: nat = Hom(G, self).natural_map() from sage.groups.libgap_morphism import GroupMorphism_libgap + if isinstance(nat, GroupMorphism_libgap): return nat except TypeError: @@ -1230,6 +1233,7 @@ def iteration(self, algorithm='SGS'): True """ if algorithm == "SGS": + def elements(SGS): S = SGS.pop() if not SGS: @@ -1243,6 +1247,7 @@ def elements(SGS): return elements(SGS) if algorithm in ["BFS", "DFS"]: from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet + seeds = [self.one()] gens = self.gens() successors = lambda g: (g._mul_(h) for h in gens) @@ -1250,10 +1255,7 @@ def elements(SGS): enumeration = "breadth" else: enumeration = "depth" - return iter(RecursivelyEnumeratedSet( - seeds=seeds, - successors=successors, - enumeration=enumeration)) + return iter(RecursivelyEnumeratedSet(seeds=seeds, successors=successors, enumeration=enumeration)) raise ValueError("the input algorithm (='%s') must be 'SGS', 'BFS' or 'DFS'" % algorithm) def gens(self) -> tuple: @@ -1615,6 +1617,7 @@ def disjoint_direct_product_decomposition(self): """ from sage.combinat.set_partition import SetPartition from sage.sets.disjoint_set import DisjointSet + H = self._libgap_() # sort each orbit and order list by smallest element of each orbit O = libgap.List([libgap.ShallowCopy(orbit) for orbit in libgap.Orbits(H)]) @@ -1631,7 +1634,7 @@ def disjoint_direct_product_decomposition(self): P = DisjointSet(num_orbits) R = libgap.List([]) identity = libgap.Identity(H) - for i in range(num_orbits-1): + for i in range(num_orbits - 1): libgap.Append(R, O[i]) Xp = libgap.List([]) while True: @@ -1646,16 +1649,13 @@ def disjoint_direct_product_decomposition(self): xs = libgap.SiftedPermutation(C, x) if xs != identity: libgap.Add(Xp, xs) - if libgap.RestrictedPerm(xs, O[i+1]) != identity: + if libgap.RestrictedPerm(xs, O[i + 1]) != identity: cj = OrbitMapping[libgap.SmallestMovedPoint(libgap.RestrictedPerm(x, R))] - P.union(i+1, cj) + P.union(i + 1, cj) else: libgap.Add(Xp, x) X = Xp - return SetPartition([[self._domain_from_gap[Integer(x)] - for i in part - for x in O[i]] for part in P] + - [[x] for x in self.fixed_points()]) + return SetPartition([[self._domain_from_gap[Integer(x)] for i in part for x in O[i]] for part in P] + [[x] for x in self.fixed_points()]) def representative_action(self, x, y): r""" @@ -1723,8 +1723,7 @@ def orbits(self): - Nathan Dunfield """ orbits = self._libgap_().Orbits(libgap.eval(self._domain_gap())) - return tuple(tuple(self._domain_from_gap[x] for x in orbit) - for orbit in orbits.sage()) + return tuple(tuple(self._domain_from_gap[x] for x in orbit) for orbit in orbits.sage()) @cached_method def orbit(self, point, action='OnPoints'): @@ -1836,7 +1835,7 @@ def input_for_gap(x, depth, container): return self._domain_to_gap[x] except KeyError: raise ValueError('{0} is not part of the domain'.format(x)) - x = [input_for_gap(xx, depth+1, container) for xx in x] + x = [input_for_gap(xx, depth + 1, container) for xx in x] if container[depth] is Set: x.sort() return x @@ -1844,8 +1843,9 @@ def input_for_gap(x, depth, container): def gap_to_output(x, depth, container): if depth == len(container): return self._domain_from_gap[x] - x = [gap_to_output(xx, depth+1, container) for xx in x] + x = [gap_to_output(xx, depth + 1, container) for xx in x] return container[depth](x) + try: container = actions[action] except KeyError: @@ -1878,9 +1878,7 @@ def transversals(self, point): [(), ('a','c','d'), ('a','d','c')] """ G = self.gap() - return [self(G.RepresentativeAction(self._domain_to_gap[point], - self._domain_to_gap[i])) - for i in self.orbit(point)] + return [self(G.RepresentativeAction(self._domain_to_gap[point], self._domain_to_gap[i])) for i in self.orbit(point)] def stabilizer(self, point, action='OnPoints'): """ @@ -2124,10 +2122,10 @@ def strong_generating_system(self, base_of_group=None, implementation='sage'): """ if implementation == "gap": if base_of_group is not None: - raise ValueError("the optional argument 'base_of_group'" - " (='%s') must be None if 'implementation'='gap'" % base_of_group) + raise ValueError("the optional argument 'base_of_group'" " (='%s') must be None if 'implementation'='gap'" % base_of_group) - gap_cosets = libgap.function_factory("""function ( S0 ) + gap_cosets = libgap.function_factory( + """function ( S0 ) local CosetsStabChain; CosetsStabChain := function(S) # for the recursive call local cosets, # element list, result @@ -2163,7 +2161,8 @@ def strong_generating_system(self, base_of_group=None, implementation='sage'): return cosets; end; return CosetsStabChain(S0); - end;""") + end;""" + ) if self._gens: G = libgap.Group(self.gens()) # G = libgap(self) else: @@ -2171,8 +2170,7 @@ def strong_generating_system(self, base_of_group=None, implementation='sage'): S = G.StabChainImmutable() cosets = gap_cosets(S) one = self.one() - return [[one._generate_new_GAP(libgap.ListPerm(elt)) - for elt in coset] for coset in cosets] + return [[one._generate_new_GAP(libgap.ListPerm(elt)) for elt in coset] for coset in cosets] if implementation == "sage": sgs = [] @@ -2184,8 +2182,7 @@ def strong_generating_system(self, base_of_group=None, implementation='sage'): stab = stab.stabilizer(j) return sgs - raise ValueError("the optional argument 'implementation'" - " (='%s') must be 'sage' or 'gap'" % implementation) + raise ValueError("the optional argument 'implementation'" " (='%s') must be 'sage' or 'gap'" % implementation) def _repr_(self): r""" @@ -2229,8 +2226,7 @@ def _latex_(self): sage: latex(S) \langle (\text{\texttt{a}},\text{\texttt{b}},\text{\texttt{c}}), (\text{\texttt{a}},\text{\texttt{b}}) \rangle """ - return '\\langle {} \\rangle'.format( - ', '.join([x._latex_() for x in self.gens()])) + return '\\langle {} \\rangle'.format(', '.join([x._latex_() for x in self.gens()])) def _order(self): """ @@ -2629,8 +2625,7 @@ def conjugacy_classes(self): """ cls = self.gap().ConjugacyClasses() L = [cl.Representative() for cl in cls] - return [ConjugacyClassGAP(self, self.element_class(l, self, check=False)) - for l in L] + return [ConjugacyClassGAP(self, self.element_class(l, self, check=False)) for l in L] def conjugate(self, g): r""" @@ -2808,6 +2803,7 @@ def direct_product(self, other, maps=True): return D from sage.groups.perm_gps.permgroup_morphism import PermutationGroupMorphism_from_gap + iota1 = PermutationGroupMorphism_from_gap(self, D, G.Embedding(1)) iota2 = PermutationGroupMorphism_from_gap(other, D, G.Embedding(2)) pr1 = PermutationGroupMorphism_from_gap(D, self, G.Projection(1)) @@ -2962,6 +2958,7 @@ def semidirect_product(self, N, mapping, check=True): if check: from sage.categories.finite_permutation_groups import FinitePermutationGroups + if N not in FinitePermutationGroups(): raise TypeError("{0} is not a permutation group".format(N)) if not PermutationGroup(gens=mapping[0]) == self: @@ -2983,14 +2980,12 @@ def semidirect_product(self, N, mapping, check=True): libgap_gens = N_gap.GeneratorsOfGroup() for alpha in mapping[1]: images = [alpha(g) for g in N.gens()] - alpha_gap = N_gap.GroupHomomorphismByImages(N_gap, - libgap_gens, images) + alpha_gap = N_gap.GroupHomomorphismByImages(N_gap, libgap_gens, images) morphisms.Add(alpha_gap) # create the necessary homomorphism from self into the # automorphism group of N in GAP H = libgap.eval(f'Group({mapping[0]})') - phi = H.GroupHomomorphismByImages(N_gap.AutomorphismGroup(), - H.GeneratorsOfGroup(), morphisms) + phi = H.GroupHomomorphismByImages(N_gap.AutomorphismGroup(), H.GeneratorsOfGroup(), morphisms) sdp = H.SemidirectProduct(phi, N_gap) return PermutationGroup(gap_group=sdp) @@ -3071,8 +3066,7 @@ def subgroup(self, gens=None, gap_group=None, domain=None, category=None, canoni Subgroup generated by [(1,2,3)] of (Permutation Group with generators [(3,4,5), (1,2,3)]) """ - return self.Subgroup(self, gens=gens, gap_group=gap_group, domain=None, - category=category, canonicalize=canonicalize, check=check) + return self.Subgroup(self, gens=gens, gap_group=gap_group, domain=None, category=category, canonicalize=canonicalize, check=check) def _subgroup_constructor(self, libgap_group): """ @@ -3198,13 +3192,12 @@ def as_finitely_presented_group(self, reduced=False): fp = libgap.IsomorphismFpGroupByGenerators(self, self.gens()) image_fp = libgap.Image(fp) image_gens = image_fp.FreeGeneratorsOfFpGroup() - name_itr = _lexi_gen() # Python generator object for variable names + name_itr = _lexi_gen() # Python generator object for variable names F = FreeGroup([next(name_itr) for x in image_gens]) # Convert GAP relators to Sage relators using the Tietze word of each defining relation. - ret_rls = tuple([F(rel_word.TietzeWordAbstractWord(image_gens).sage()) - for rel_word in image_fp.RelatorsOfFpGroup()]) - ret_fp = FinitelyPresentedGroup(F,ret_rls) + ret_rls = tuple([F(rel_word.TietzeWordAbstractWord(image_gens).sage()) for rel_word in image_fp.RelatorsOfFpGroup()]) + ret_fp = FinitelyPresentedGroup(F, ret_rls) if reduced: ret_fp = ret_fp.simplified() return ret_fp @@ -3336,6 +3329,7 @@ def commutator(self, other=None): if other is None: return PermutationGroup(gap_group=libgap.DerivedSubgroup(self), domain=self.domain()) from sage.categories.finite_permutation_groups import FinitePermutationGroups + if other not in FinitePermutationGroups(): raise TypeError("{0} is not a permutation group".format(other)) gap_group = libgap.CommutatorSubgroup(self, other) @@ -3420,7 +3414,7 @@ def cohomology_part(self, n, p=0): return AbelianGroup(1, [1]) G = self._libgap_() S = G.SylowSubgroup(p) - R = S.ResolutionFiniteGroup(n+1) + R = S.ResolutionFiniteGroup(n + 1) HR = R.HomToIntegers() L = HR.Cohomology(n).sage() return AbelianGroup(len(L), L) @@ -3496,7 +3490,7 @@ def homology_part(self, n, p=0): if p == 0: return AbelianGroup(1, [1]) S = self._libgap_().SylowSubgroup(p) - R = S.ResolutionFiniteGroup(n+1) + R = S.ResolutionFiniteGroup(n + 1) TR = R.TensorWithIntegers() L = TR.Homology(n).sage() return AbelianGroup(len(L), L) @@ -3598,12 +3592,14 @@ def character_table(self): ct = [[irrG[i, j] for j in range(n)] for i in range(n)] from sage.rings.number_field.number_field import CyclotomicField + e = irrG.Flat().Conductor() K = CyclotomicField(e) ct = [[K(x) for x in v] for v in ct] # Finally return the result as a matrix. from sage.matrix.matrix_space import MatrixSpace + MS = MatrixSpace(K, n) return MS(ct) @@ -3628,7 +3624,7 @@ def trivial_character(self): sage: SymmetricGroup(3).trivial_character() # needs sage.rings.number_field Character of Symmetric group of order 3! as a permutation group """ - values = [1]*self._libgap_().NrConjugacyClasses().sage() + values = [1] * self._libgap_().NrConjugacyClasses().sage() return self.character(values) def character(self, values): @@ -3791,8 +3787,7 @@ def subgroups(self): - Rob Beezer (2011-01-24) """ ccs = self._libgap_().ConjugacyClassesSubgroups() - return [self.subgroup(gap_group=h) for cc in ccs - for h in cc.Elements()] + return [self.subgroup(gap_group=h) for cc in ccs for h in cc.Elements()] @cached_method def _regular_subgroup_gap(self): @@ -3813,8 +3808,7 @@ def _regular_subgroup_gap(self): ConjugacyClassSubgroups(SymmetricGroup( [ 1 .. 4 ] ),Group( [ (1,4)(2,3), (1,3)(2,4) ] )) """ - filt = libgap.eval('x -> IsRegular(Representative(x), [1..{}])'.format( - self.degree())) + filt = libgap.eval('x -> IsRegular(Representative(x), [1..{}])'.format(self.degree())) C = libgap.First(self._libgap_().ConjugacyClassesSubgroups(), filt) # prevent caching GAP fails if str(C) == 'fail': @@ -3861,7 +3855,7 @@ def has_regular_subgroup(self, return_group=False): G = self else: C = self._regular_subgroup_gap() - b = (C is not None) + b = C is not None if b and return_group: G = self.subgroup(gap_group=C.Representative()) @@ -3937,11 +3931,8 @@ def blocks_all(self, representatives=True): """ ag = self._libgap_() if representatives: - return [[self._domain_from_gap[x] for x in rep] - for rep in ag.AllBlocks().sage()] - return [[[self._domain_from_gap[x] for x in cl] - for cl in ag.Orbit(rep, libgap.OnSets).sage()] - for rep in ag.AllBlocks()] + return [[self._domain_from_gap[x] for x in rep] for rep in ag.AllBlocks().sage()] + return [[[self._domain_from_gap[x] for x in cl] for cl in ag.Orbit(rep, libgap.OnSets).sage()] for rep in ag.AllBlocks()] def cosets(self, S, side='right'): r""" @@ -4132,7 +4123,7 @@ def minimal_generating_set(self): sage: PermutationGroup(["(1,2,3)(4,5,6)","(1,2,3,4,5,6)"]).minimal_generating_set() [(2,5)(3,6), (1,5,3,4,2,6)] """ - return from_gap_list(self,str(self._libgap_().MinimalGeneratingSet())) + return from_gap_list(self, str(self._libgap_().MinimalGeneratingSet())) def normalizer(self, g): """ @@ -4220,8 +4211,7 @@ def minimal_normal_subgroups(self): [Subgroup generated by [(4,5)] of (Permutation Group with generators [(4,5), (1,2,3)]), Subgroup generated by [(1,2,3)] of (Permutation Group with generators [(4,5), (1,2,3)])] """ - return [self.subgroup(gap_group=gap_subgroup) - for gap_subgroup in self._libgap_().MinimalNormalSubgroups()] + return [self.subgroup(gap_group=gap_subgroup) for gap_subgroup in self._libgap_().MinimalNormalSubgroups()] def maximal_normal_subgroups(self): """ @@ -4237,8 +4227,7 @@ def maximal_normal_subgroups(self): [Subgroup generated by [(1,2,3)] of (Permutation Group with generators [(4,5), (1,2,3)]), Subgroup generated by [(4,5)] of (Permutation Group with generators [(4,5), (1,2,3)])] """ - return [self.subgroup(gap_group=gap_subgroup) - for gap_subgroup in self._libgap_().MaximalNormalSubgroups()] + return [self.subgroup(gap_group=gap_subgroup) for gap_subgroup in self._libgap_().MaximalNormalSubgroups()] # ##################### Boolean tests ##################### @@ -4353,6 +4342,7 @@ def isomorphism_to(self, right): dsts = [right(iso.Image(x), check=False) for x in self.gens()] from .permgroup_morphism import PermutationGroupMorphism_im_gens + return PermutationGroupMorphism_im_gens(self, right, dsts) def is_isomorphic(self, right) -> bool: @@ -4623,8 +4613,8 @@ def is_transitive(self, domain=None) -> bool: sage: gap(G).IsTransitive() true """ - #If the domain is not a subset of self.domain(), then the - #action isn't transitive. + # If the domain is not a subset of self.domain(), then the + # action isn't transitive. try: domain = libgap.eval(self._domain_gap(domain)) except ValueError: @@ -4676,8 +4666,8 @@ def is_primitive(self, domain=None) -> bool: sage: G.is_primitive([1,2,3]) False """ - #If the domain is not a subset of self.domain(), then the - #action isn't primitive. + # If the domain is not a subset of self.domain(), then the + # action isn't primitive. try: domain = libgap.eval(self._domain_gap(domain)) except ValueError: @@ -4919,15 +4909,13 @@ def molien_series(self): sage: PG.molien_series() == PG1.molien_series()*(1-x)^2 True """ - pi = self._libgap_().PermutationCharacter(list(self.domain()), - libgap.OnPoints) + pi = self._libgap_().PermutationCharacter(list(self.domain()), libgap.OnPoints) M = pi.MolienSeries() R = QQ['x'] nn = M.NumeratorOfRationalFunction() dd = M.DenominatorOfRationalFunction() - return (R(str(nn).replace("_1", "")) / - R(str(dd).replace("_1", ""))) + return R(str(nn).replace("_1", "")) / R(str(dd).replace("_1", "")) def normal_subgroups(self): r""" @@ -4983,6 +4971,7 @@ def poincare_series(self, p=2, n=10): """ load_hap() from sage.arith.misc import is_prime + if not (p == 0 or is_prime(p)): raise ValueError("p must be 0 or prime") @@ -4990,8 +4979,7 @@ def poincare_series(self, p=2, n=10): R = QQ['x'] nn = ff.NumeratorOfRationalFunction() dd = ff.DenominatorOfRationalFunction() - return (R(str(nn).replace('x_1', 'x')) / - R(str(dd).replace('x_1', 'x'))) + return R(str(nn).replace('x_1', 'x')) / R(str(dd).replace('x_1', 'x')) def sylow_subgroup(self, p): """ @@ -5061,8 +5049,10 @@ def sign_representation(self, base_ring=None): """ if base_ring is None: from sage.rings.integer_ring import ZZ + base_ring = ZZ from sage.modules.with_basis.representation import SignRepresentationPermgroup + return SignRepresentationPermgroup(self, base_ring) @@ -5087,8 +5077,8 @@ class PermutationGroup_subgroup(PermutationGroup_generic): sage: K.gens() ((1,2,3,4),) """ - def __init__(self, ambient, gens=None, gap_group=None, domain=None, - category=None, canonicalize=True, check=True): + + def __init__(self, ambient, gens=None, gap_group=None, domain=None, category=None, canonicalize=True, check=True): r""" Initialization method for the ``PermutationGroup_subgroup`` class. @@ -5147,14 +5137,12 @@ def __init__(self, ambient, gens=None, gap_group=None, domain=None, gap_group = ambient.gap().Subgroup([ambient(g, check=check).gap() for g in gens]) # the ambient element constructor checks if needed check = False - PermutationGroup_generic.__init__(self, gens=gens, - gap_group=gap_group, domain=domain, - category=category, - canonicalize=canonicalize) + PermutationGroup_generic.__init__(self, gens=gens, gap_group=gap_group, domain=domain, category=category, canonicalize=canonicalize) self._ambient_group = ambient if check: from sage.groups.perm_gps.permgroup_named import SymmetricGroup + if not isinstance(ambient, SymmetricGroup): ambient_gap_group = ambient._libgap_() for g in self.gens(): @@ -5275,10 +5263,8 @@ def _latex_(self): sage: S._latex_() '\\hbox{Subgroup } \\langle (1,2,3,4) \\rangle \\hbox{ of } \\langle (1,2,3,4), (1,4)(2,3) \\rangle' """ - gens = '\\langle ' + \ - ', '.join([x._latex_() for x in self.gens()]) + ' \\rangle' - return '\\hbox{Subgroup } %s \\hbox{ of } %s' % \ - (gens, self.ambient_group()._latex_()) + gens = '\\langle ' + ', '.join([x._latex_() for x in self.gens()]) + ' \\rangle' + return '\\hbox{Subgroup } %s \\hbox{ of } %s' % (gens, self.ambient_group()._latex_()) def ambient_group(self): """ @@ -5356,6 +5342,7 @@ class PermutationGroup_action(PermutationGroup_generic): ....: action=lambda g, x: x, domain=[1]) Permutation Group with generators [()] """ + def __init__(self, gens, action, domain, gap_group=None, category=None, canonicalize=None): """ Initialize ``self``. @@ -5387,14 +5374,14 @@ def __init__(self, gens, action, domain, gap_group=None, category=None, canonica """ from sage.combinat.cyclic_sieving_phenomenon import orbit_decomposition from sage.sets.disjoint_set import DisjointSet + if gap_group is not None: raise ValueError("gap_group is not supported with action") if gens is None: self._orbits = tuple(tuple(o) for o in orbit_decomposition(domain, action)) gens = [o for o in self._orbits if len(o) > 1] else: - g_orbits = [orbit_decomposition(domain, lambda x: action(g, x)) - for g in gens] + g_orbits = [orbit_decomposition(domain, lambda x: action(g, x)) for g in gens] gens = [] for g_orbit in g_orbits: g_gens = [tuple(o) for o in g_orbit if len(o) > 1] @@ -5408,10 +5395,7 @@ def __init__(self, gens, action, domain, gap_group=None, category=None, canonica D.union(o[0], o[i]) self._orbits = tuple(tuple(o) for o in D) - PermutationGroup_generic.__init__(self, gens=gens, - gap_group=gap_group, domain=domain, - category=category, - canonicalize=canonicalize) + PermutationGroup_generic.__init__(self, gens=gens, gap_group=gap_group, domain=domain, category=category, canonicalize=canonicalize) def orbits(self): """ @@ -5429,4 +5413,5 @@ def orbits(self): from sage.misc.rest_index_of_methods import gen_rest_table_index + __doc__ = __doc__.format(METHODS_OF_PermutationGroup_generic=gen_rest_table_index(PermutationGroup_generic)) diff --git a/src/sage/groups/perm_gps/permgroup_morphism.py b/src/sage/groups/perm_gps/permgroup_morphism.py index 2588354f0f5..a065aaaea08 100644 --- a/src/sage/groups/perm_gps/permgroup_morphism.py +++ b/src/sage/groups/perm_gps/permgroup_morphism.py @@ -46,6 +46,7 @@ class PermutationGroupMorphism(Morphism): r""" A set-theoretic map between PermutationGroups. """ + def _repr_type(self): r""" Return the type of this morphism. diff --git a/src/sage/groups/perm_gps/permgroup_named.py b/src/sage/groups/perm_gps/permgroup_named.py index 2418787e228..8e600ce66dd 100644 --- a/src/sage/groups/perm_gps/permgroup_named.py +++ b/src/sage/groups/perm_gps/permgroup_named.py @@ -78,6 +78,7 @@ permutation groups - the construction is too slow - unless (for small values or the parameter) they are made using explicit generators. """ + # **************************************************************************** # Copyright (C) 2006 William Stein # David Joyner @@ -118,6 +119,7 @@ class PermutationGroup_unique(CachedRepresentation, PermutationGroup_generic): sage: hash(G) == hash(G3) True """ + @weak_cached_function def __classcall__(cls, *args, **kwds): """ @@ -243,6 +245,7 @@ class SymmetricGroup(PermutationGroup_symalt): sage: h = SymmetricGroup(1).hom(SymmetricGroup(2)) """ + def __init__(self, domain=None): """ Initialize ``self``. @@ -260,8 +263,7 @@ def __init__(self, domain=None): # Note that we skip the call to the superclass initializer in order to # avoid infinite recursion since SymmetricGroup is called by # PermutationGroupElement - cat = Category.join([FinitePermutationGroups(), - FiniteWeylGroups().Irreducible()]) + cat = Category.join([FinitePermutationGroups(), FiniteWeylGroups().Irreducible()]) super(PermutationGroup_generic, self).__init__(category=cat) self._domain = domain @@ -276,8 +278,7 @@ def __init__(self, domain=None): gens = [tuple(self._domain)] if self._deg > 2: gens.append(tuple(self._domain[:2])) - self._gens = tuple([self.element_class(g, self, check=False) - for g in gens]) + self._gens = tuple([self.element_class(g, self, check=False) for g in gens]) def _gap_init_(self) -> str: """ @@ -352,6 +353,7 @@ def _coerce_map_from_(self, G): True """ from sage.groups.cactus_group import CactusGroup + if isinstance(G, CactusGroup) and G._n <= self._deg: return self._from_cactus_group_element return super()._coerce_map_from_(G) @@ -387,6 +389,7 @@ def cartan_type(self): ['A', 0] """ from sage.combinat.root_system.cartan_type import CartanType + return CartanType(['A', max(self.degree() - 1, 0)]) def coxeter_matrix(self): @@ -417,7 +420,7 @@ def simple_reflection(self, i): sage: A.simple_reflections() Finite family {2: (2,3), 3: (3,7)} """ - return self([(i, self._domain[self._domain.index(i)+1])], check=False) + return self([(i, self._domain[self._domain.index(i) + 1])], check=False) @cached_method def reflection_index_set(self): @@ -474,6 +477,7 @@ def reflections(self): [(1,2), (1,3), (2,3)] """ from itertools import combinations + dom = self._domain return [self([(i, j)], check=False) for i, j in combinations(dom, 2)] @@ -506,8 +510,7 @@ def young_subgroup(self, comp): gens = [] pos = 0 for c in comp: - gens.extend(self((domain[pos + i], domain[pos + i + 1])) - for i in range(c - 1)) + gens.extend(self((domain[pos + i], domain[pos + i + 1])) for i in range(c - 1)) pos += c return self.subgroup(gens) @@ -539,6 +542,7 @@ def major_index(self, parameter=None): t^6 + 3*t^5 + 5*t^4 + 6*t^3 + 5*t^2 + 3*t + 1 """ from sage.combinat.q_analogues import q_factorial + return q_factorial(self.degree(), parameter) def conjugacy_classes_representatives(self): @@ -577,9 +581,9 @@ def conjugacy_classes_representatives(self): """ from sage.combinat.partition import Partitions_n from sage.groups.perm_gps.symgp_conjugacy_class import default_representative + n = len(self.domain()) - return [default_representative(la, self) - for la in reversed(Partitions_n(n))] + return [default_representative(la, self) for la in reversed(Partitions_n(n))] def conjugacy_classes_iterator(self): """ @@ -593,6 +597,7 @@ def conjugacy_classes_iterator(self): """ from sage.combinat.partition import Partitions_n from sage.groups.perm_gps.symgp_conjugacy_class import SymmetricGroupConjugacyClass + P = Partitions_n(len(self.domain())) for la in reversed(P): yield SymmetricGroupConjugacyClass(self, la) @@ -642,6 +647,7 @@ def conjugacy_class(self, g): Symmetric group of order 5! as a permutation group """ from sage.groups.perm_gps.symgp_conjugacy_class import SymmetricGroupConjugacyClass + return SymmetricGroupConjugacyClass(self, g) def algebra(self, base_ring, category=None): @@ -695,6 +701,7 @@ def algebra(self, base_ring, category=None): (3,5) """ from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra + if all(i == j for i, j in enumerate(self.domain(), start=1)): return SymmetricGroupAlgebra(base_ring, self, category=category) return super().algebra(base_ring) @@ -815,7 +822,7 @@ def __init__(self, n): n = Integer(n) if n < 1: raise ValueError("n (=%s) must be >= 1" % n) - gens = tuple(range(1, n+1)) + gens = tuple(range(1, n + 1)) PermutationGroup_generic.__init__(self, [gens], n) def _repr_(self): @@ -863,7 +870,7 @@ def as_AbelianGroup(self): """ n = self.order() a = list(factor(n)) - invs = [x[0]**x[1] for x in a] + invs = [x[0] ** x[1] for x in a] G = AbelianGroup(len(a), invs) return G @@ -981,6 +988,7 @@ class DiCyclicGroup(PermutationGroup_unique): - Rob Beezer (2009-10-18) """ + def __init__(self, n): r""" The dicyclic group of order `4n`, as a permutation group. @@ -1003,26 +1011,25 @@ def __init__(self, n): # Certainly 2^2 is part of the first factor of the order # r is maximum power of 2 in the order # m is the rest, the odd part - order = 4*n + order = 4 * n factored = order.factor() - r = factored[0][0]**factored[0][1] - m = order//r - halfr, fourthr = r//2, r//4 + r = factored[0][0] ** factored[0][1] + m = order // r + halfr, fourthr = r // 2, r // 4 # Representation of a # Two cycles of length halfr - a = [tuple(range(1, halfr+1)), tuple(range(halfr+1, r+1))] + a = [tuple(range(1, halfr + 1)), tuple(range(halfr + 1, r + 1))] # With an odd part, a cycle of length m will give the right order for a if m > 1: a.append(tuple(range(r + 1, r + m + 1))) # Representation of x # Four-cycles that will conjugate the generator a properly - x = [(i+1, (-i) % halfr + halfr + 1, (fourthr+i) % halfr + 1, (-fourthr-i) % halfr + halfr + 1) - for i in range(fourthr)] + x = [(i + 1, (-i) % halfr + halfr + 1, (fourthr + i) % halfr + 1, (-fourthr - i) % halfr + halfr + 1) for i in range(fourthr)] # With an odd part, transpositions will conjugate the m-cycle to create inverse if m > 1: - x += [(r+i+1, r+m-i) for i in range((m-1)//2)] + x += [(r + i + 1, r + m - i) for i in range((m - 1) // 2)] PermutationGroup_generic.__init__(self, gens=[a, x]) @@ -1225,6 +1232,7 @@ class QuaternionGroup(DiCyclicGroup): - Rob Beezer (2009-10-09) """ + def __init__(self): r""" TESTS:: @@ -1385,6 +1393,7 @@ class GeneralDihedralGroup(PermutationGroup_generic): - Kevin Halasz (2012-7-12) """ + def __init__(self, factors): r""" Init method of class . See the docstring @@ -1415,7 +1424,7 @@ def __init__(self, factors): # To get uniform outputs for isomorphic inputs, we break # each inputted cyclic group into a direct product of cyclic # p-groups - simplified = sorted([term[0]**term[1] for a in factors for term in a.factor()]) + simplified = sorted([term[0] ** term[1] for a in factors for term in a.factor()]) gens = [] # genx is an element of order two that turns each of the @@ -1428,15 +1437,14 @@ def __init__(self, factors): gens.append([tuple(range(jumppoint, jumppoint + a))]) # make contribution to the generator that dihedralizes the # abelian group - genx.extend((jumppoint + i, jumppoint + a - i) - for i in range(1, (a//2) + 1) if i != a - i) + genx.extend((jumppoint + i, jumppoint + a - i) for i in range(1, (a // 2) + 1) if i != a - i) jumppoint += a # If all of the direct factors are C2, then the action turning # each element into its inverse is trivial, and the # semi-direct product becomes a direct product, so we simply # tack on another disjoint transposition if all(x == 2 for x in simplified): - genx.append((jumppoint, jumppoint+1)) + genx.append((jumppoint, jumppoint + 1)) gens.append(genx) PermutationGroup_generic.__init__(self, gens=gens) @@ -1667,10 +1675,10 @@ def __init__(self, p, m): # Judson's "Abstract Algebra" (abstract.pugetsound.edu). y = [1] point = 1 - for i in range(p**(m-1)-1): - next = (point + 1 + p**(m-2)) % (p**(m-1)) + for i in range(p ** (m - 1) - 1): + next = (point + 1 + p ** (m - 2)) % (p ** (m - 1)) if next == 0: - next = p**(m-1) + next = p ** (m - 1) y.append(next) point = next PermutationGroup_unique.__init__(self, gens=[x, y]) @@ -1776,10 +1784,10 @@ def __init__(self, m): # Judson's "Abstract Algebra" (abstract.pugetsound.edu). y = [1] k = 1 - for i in range(2**(m-1)-1): - next = (k - 1 + 2**(m-2)) % (2**(m-1)) + for i in range(2 ** (m - 1) - 1): + next = (k - 1 + 2 ** (m - 2)) % (2 ** (m - 1)) if next == 0: - next = 2**(m-1) + next = 2 ** (m - 1) y.append(next) k = next PermutationGroup_unique.__init__(self, gens=[x, y]) @@ -1915,7 +1923,7 @@ def __init__(self, d, n): if n > max_n or n <= 0: raise ValueError("index n must be in {1,..,%s}" % max_n) if d <= 1: - PermutationGroup_generic.__init__(self, gens=[()], domain=list(range(1, d+1))) + PermutationGroup_generic.__init__(self, gens=[()], domain=list(range(1, d + 1))) else: gap_group = libgap.TransitiveGroup(d, n) PermutationGroup_generic.__init__(self, gap_group=gap_group) @@ -2012,6 +2020,7 @@ class TransitiveGroupsAll(DisjointUnionEnumeratedSets): Transitive group number 2 of degree 3, Transitive group number 1 of degree 4, Transitive group number 2 of degree 4, Transitive group number 3 of degree 4) """ + def __init__(self): """ TESTS:: @@ -2021,9 +2030,7 @@ def __init__(self): Category of facade infinite enumerated sets sage: TestSuite(TransitiveGroups()).run() """ - DisjointUnionEnumeratedSets.__init__(self, - Family(NonNegativeIntegers(), - TransitiveGroups)) + DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), TransitiveGroups)) # We override the __call__ as the elements are not instances of Element __call__ = DisjointUnionEnumeratedSets._element_constructor_facade @@ -2084,6 +2091,7 @@ class TransitiveGroupsOfDegree(CachedRepresentation, Parent): sage: TestSuite(TransitiveGroups(3)).run() """ + def __init__(self, n): """ TESTS:: @@ -2230,6 +2238,7 @@ def cardinality(self): return Integer(libgap.NrTransitiveGroups(libgap(self._degree))) except RuntimeError: from sage.misc.verbose import verbose + verbose("Error: TransitiveGroups should come with GAP.", level=0) except TypeError: raise NotImplementedError("only the transitive groups of degree at most 31 are available in GAP's database") @@ -2305,7 +2314,7 @@ def __init__(self, d, n): raise ValueError("index n must be in {1,..,%s}" % max_n) if d <= 1: - PermutationGroup_generic.__init__(self, gens=[()], domain=list(range(1, d+1))) + PermutationGroup_generic.__init__(self, gens=[()], domain=list(range(1, d + 1))) self._pretty_name = "Trivial group" else: gap_group = libgap.PrimitiveGroup(d, n) @@ -2411,6 +2420,7 @@ class PrimitiveGroupsAll(DisjointUnionEnumeratedSets): sage: TestSuite(PrimitiveGroups()).run() # known bug, long time """ + def __init__(self): """ TESTS:: @@ -2419,9 +2429,7 @@ def __init__(self): sage: S.category() Category of facade infinite enumerated sets """ - DisjointUnionEnumeratedSets.__init__(self, - Family(NonNegativeIntegers(), - PrimitiveGroups)) + DisjointUnionEnumeratedSets.__init__(self, Family(NonNegativeIntegers(), PrimitiveGroups)) def _repr_(self): """ @@ -2485,6 +2493,7 @@ class PrimitiveGroupsOfDegree(CachedRepresentation, Parent): sage: TestSuite(PrimitiveGroups(3)).run() """ + def __init__(self, n): """ TESTS:: @@ -2767,6 +2776,7 @@ def __init__(self, n, q, name='a'): Finite Field in b of size 2^2 """ from sage.categories.finite_fields import FiniteFields + if q in FiniteFields(): if q.degree() > 1: name = q.gen() @@ -2835,8 +2845,7 @@ def ramification_module_decomposition_hurwitz_curve(self): F = self.base_ring() q = F.order() - libgap.Read(Path(SAGE_EXTCODE) / 'gap' / 'joyner' / - 'hurwitz_crv_rr_sp.gap') + libgap.Read(Path(SAGE_EXTCODE) / 'gap' / 'joyner' / 'hurwitz_crv_rr_sp.gap') mults = libgap.eval(f"ram_module_hurwitz({q})") return mults.sage() @@ -2875,12 +2884,12 @@ def ramification_module_decomposition_modular_curve(self): randomness to the ordering of the characters. """ from sage.env import SAGE_EXTCODE + if self.matrix_degree() != 2: raise ValueError("degree must be 2") F = self.base_ring() q = F.order() - libgap.Read(Path(SAGE_EXTCODE) / 'gap' / 'joyner' / - 'modular_crv_rr_sp.gap') + libgap.Read(Path(SAGE_EXTCODE) / 'gap' / 'joyner' / 'modular_crv_rr_sp.gap') mults = libgap.eval(f"ram_module_X({q})") return mults.sage() @@ -3234,6 +3243,7 @@ class ComplexReflectionGroup(PermutationGroup_unique): - :wikipedia:`Complex_reflection_group` """ + def __init__(self, m, p=None, n=None): """ Initialize ``self``. @@ -3261,8 +3271,7 @@ def __init__(self, m, p=None, n=None): 384 """ if p is None: - raise NotImplementedError("exceptional complex reflection groups" - " are not yet implemented") + raise NotImplementedError("exceptional complex reflection groups" " are not yet implemented") self._m = Integer(m) self._p = Integer(p) self._n = Integer(n) @@ -3273,18 +3282,19 @@ def __init__(self, m, p=None, n=None): from sage.categories.finite_complex_reflection_groups import FiniteComplexReflectionGroups from sage.categories.finite_permutation_groups import FinitePermutationGroups + cat = FinitePermutationGroups() & FiniteComplexReflectionGroups() - gens = [[(i+k, i+1+k) for k in range(0, self._m * self._n, self._n)] - for i in range(1, self._n)] + gens = [[(i + k, i + 1 + k) for k in range(0, self._m * self._n, self._n)] for i in range(1, self._n)] if self._p == 1: - gens.append([tuple(range(self._n, self._m*self._n + 1, self._n))]) + gens.append([tuple(range(self._n, self._m * self._n + 1, self._n))]) else: from sage.groups.perm_gps.constructor import PermutationGroupElement - sn = PermutationGroupElement([tuple(range(self._n, self._m*self._n + 1, self._n))]) + + sn = PermutationGroupElement([tuple(range(self._n, self._m * self._n + 1, self._n))]) if self._n > 1: snm = PermutationGroupElement(gens[-1]) - gens.append(sn**(self._m-1) * snm * sn) + gens.append(sn ** (self._m - 1) * snm * sn) if self._p != self._m: gens.append(sn**self._p) @@ -3379,18 +3389,18 @@ def simple_reflection(self, i): raise ValueError("not an index of a simple reflection") if i < self._n: - return self([(i+k, i+1+k) for k in range(0, self._m * self._n, self._n)]) + return self([(i + k, i + 1 + k) for k in range(0, self._m * self._n, self._n)]) if self._p == 1: - return self([tuple(range(self._n, self._m*self._n + 1, self._n))]) + return self([tuple(range(self._n, self._m * self._n + 1, self._n))]) from sage.groups.perm_gps.constructor import PermutationGroupElement - sn = PermutationGroupElement([tuple(range(self._n, self._m*self._n + 1, self._n))]) + + sn = PermutationGroupElement([tuple(range(self._n, self._m * self._n + 1, self._n))]) if i == self._n + 1 or self._n == 1: return self(sn**self._p) - snm = PermutationGroupElement([(self._n-1+k, self._n+k) - for k in range(0, self._m * self._n, self._n)]) - return self(sn**(self._m-1) * snm * sn) + snm = PermutationGroupElement([(self._n - 1 + k, self._n + k) for k in range(0, self._m * self._n, self._n)]) + return self(sn ** (self._m - 1) * snm * sn) def degrees(self): r""" @@ -3470,11 +3480,11 @@ def codegrees(self): """ # Special case for the usual symmetric group if self._m == 1: - return tuple(reversed(range(self._n-1))) + return tuple(reversed(range(self._n - 1))) if self._p < self._m: return tuple([self._m * i for i in reversed(range(self._n))]) - ret = [self._m * i for i in reversed(range(self._n-1))] - ret.append((self._n-1)*self._m - self._n) + ret = [self._m * i for i in reversed(range(self._n - 1))] + ret.append((self._n - 1) * self._m - self._n) return tuple(sorted(ret, reverse=True)) diff --git a/src/sage/groups/perm_gps/permutation_groups_catalog.py b/src/sage/groups/perm_gps/permutation_groups_catalog.py index 52f99920307..7db897dd113 100644 --- a/src/sage/groups/perm_gps/permutation_groups_catalog.py +++ b/src/sage/groups/perm_gps/permutation_groups_catalog.py @@ -26,6 +26,6 @@ from .permgroup_named import JankoGroup as Janko from .permgroup_named import SuzukiSporadicGroup as SuzukiSporadic from .permgroup_named import SuzukiGroup as Suzuki -from .permgroup_named import (PGL, PSL, PSp, PSU, PGU) +from .permgroup_named import PGL, PSL, PSp, PSU, PGU from .permgroup_named import TransitiveGroup as Transitive from .cubegroup import CubeGroup as RubiksCube diff --git a/src/sage/groups/perm_gps/symgp_conjugacy_class.py b/src/sage/groups/perm_gps/symgp_conjugacy_class.py index 62ac792c9c9..73f81accb78 100644 --- a/src/sage/groups/perm_gps/symgp_conjugacy_class.py +++ b/src/sage/groups/perm_gps/symgp_conjugacy_class.py @@ -20,6 +20,7 @@ class SymmetricGroupConjugacyClassMixin: Mixin class which contains methods for conjugacy classes of the symmetric group. """ + def __init__(self, domain, part): """ Initialize ``self``. @@ -105,6 +106,7 @@ class SymmetricGroupConjugacyClass(SymmetricGroupConjugacyClassMixin, ConjugacyC - ``group`` -- the symmetric group - ``part`` -- a partition or an element of ``group`` """ + def __init__(self, group, part): """ Initialize ``self``. @@ -167,8 +169,7 @@ def set(self): True """ if not self._set: - self._set = Set(self._parent.element_class(x, self._parent, check=False) - for x in conjugacy_class_iterator(self._part, self._domain)) + self._set = Set(self._parent.element_class(x, self._parent, check=False) for x in conjugacy_class_iterator(self._part, self._domain)) return self._set @@ -181,6 +182,7 @@ class PermutationsConjugacyClass(SymmetricGroupConjugacyClassMixin, ConjugacyCla - ``P`` -- the permutations of `n` - ``part`` -- a partition or an element of ``P`` """ + def __init__(self, P, part): """ Initialize ``self``. @@ -243,14 +245,14 @@ def set(self): True """ if not self._set: - self._set = Set(from_cycles(self._parent.n, x, self._parent) - for x in conjugacy_class_iterator(self._part, self._domain)) + self._set = Set(from_cycles(self._parent.n, x, self._parent) for x in conjugacy_class_iterator(self._part, self._domain)) return self._set ##################################################################### # Helper functions + def default_representative(part, G): r""" Construct the default representative for the conjugacy class of @@ -288,7 +290,7 @@ def default_representative(part, G): total = 0 cycles = [] for p in part: - cycles.append(tuple(D[total:total + p])) + cycles.append(tuple(D[total : total + p])) total += p return G.element_class(cycles, G, check=False) diff --git a/src/sage/groups/raag.py b/src/sage/groups/raag.py index c40ec8ddebc..f353254e2c2 100644 --- a/src/sage/groups/raag.py +++ b/src/sage/groups/raag.py @@ -136,6 +136,7 @@ class RightAngledArtinGroup(ArtinGroup): - :wikipedia:`Artin_group#Right-angled_Artin_groups` """ + @staticmethod def __classcall_private__(cls, G, names=None): """ @@ -173,8 +174,7 @@ def __classcall_private__(cls, G, names=None): names = [names + str(v) for v in G.vertices(sort=False)] names = tuple(names) if len(names) != G.n_vertices(): - raise ValueError("the number of generators must match the" - " number of vertices of the defining graph") + raise ValueError("the number of generators must match the" " number of vertices of the defining graph") return super().__classcall__(cls, G, names) def __init__(self, G, names): @@ -199,10 +199,8 @@ def __init__(self, G, names): cm[u][v] = 2 cm[v][u] = 2 self._coxeter_group = CoxeterGroup(CoxeterMatrix(cm, index_set=G.vertices(sort=True))) - rels = tuple(F([i + 1, j + 1, -i - 1, -j - 1]) - for i, j in CG.edge_iterator(labels=False)) # +/- 1 for indexing - FinitelyPresentedGroup.__init__(self, F, rels, - category=Groups().Infinite()) + rels = tuple(F([i + 1, j + 1, -i - 1, -j - 1]) for i, j in CG.edge_iterator(labels=False)) # +/- 1 for indexing + FinitelyPresentedGroup.__init__(self, F, rels, category=Groups().Infinite()) def _repr_(self) -> str: """ @@ -346,8 +344,7 @@ def _normal_form(self, word): # Check if this could fit in the commuting set if letter in comm_set: # Try to move it in - if any(G.has_edge(v[w[j][0]], v[letter]) - for j in range(pos + len(comm_set), i)): + if any(G.has_edge(v[w[j][0]], v[letter]) for j in range(pos + len(comm_set), i)): # We can't, so go onto the next letter i += 1 continue @@ -364,8 +361,7 @@ def _normal_form(self, word): pos = 0 # Start again since cancellation can be pronounced effects break - elif all(not G.has_edge(v[w[j][0]], v[letter]) - for j in range(pos, i)): + elif all(not G.has_edge(v[w[j][0]], v[letter]) for j in range(pos, i)): j = 0 for x in comm_set: if x > letter: @@ -392,6 +388,7 @@ def cohomology(self, F=None): """ if F is None: from sage.rings.rational_field import QQ + F = QQ return CohomologyRAAG(F, self) @@ -403,6 +400,7 @@ class Element(ArtinGroupElement): ``i`` is the index of a vertex in the defining graph (with some fixed order of the vertices) and ``p`` is the power. """ + def __init__(self, parent, lst): """ Initialize ``self``. @@ -529,6 +527,7 @@ def _latex_(self) -> str: return '1' from sage.misc.latex import latex + latexrepr = '' v = self.parent()._graph.vertices(sort=True) for i, p in self._data: @@ -645,6 +644,7 @@ class CohomologyRAAG(CombinatorialFreeModule): - [CQ2019]_ """ + def __init__(self, R, A): """ Initialize ``self``. @@ -668,6 +668,7 @@ def __init__(self, R, A): names = tuple(['e' + name[1:] for name in A.variable_names()]) from sage.graphs.independent_sets import IndependentSets from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + indices = [tuple(ind_set) for ind_set in IndependentSets(A._graph)] indices = FiniteEnumeratedSet(indices) cat = AlgebrasWithBasis(R.category()).Super().Graded().FiniteDimensional() @@ -745,6 +746,7 @@ def _unicode_art_term(self, m): if not m: return unicode_art('1') import unicodedata + wedge = unicodedata.lookup('LOGICAL AND') return unicode_art(*['e' + str(i) for i in m], sep=wedge) @@ -763,6 +765,7 @@ def _latex_term(self, m): if not m: return '1' from sage.misc.latex import latex + return " \\wedge ".join('e_{{{}}}'.format(latex(i)) for i in m) def gen(self, i): @@ -815,6 +818,7 @@ def algebra_generators(self): V = self._group._graph.vertices(True) d = {x: self.gen(i) for i, x in enumerate(V)} from sage.sets.family import Family + return Family(V, lambda x: d[x]) def gens(self) -> tuple: diff --git a/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py b/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py index f987d4c7e88..55e7279f85a 100644 --- a/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py +++ b/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py @@ -121,6 +121,7 @@ class SemimonomialTransformationGroup(FiniteGroup, UniqueRepresentation): ((1, 1, 1, 1); (), Ring endomorphism of Finite Field in a of size 3^2 Defn: a |--> a) """ + Element = SemimonomialTransformation def __init__(self, R, len): @@ -146,6 +147,7 @@ def __init__(self, R, len): self._len = len from sage.categories.finite_groups import FiniteGroups + super().__init__(category=FiniteGroups()) def _element_constructor_(self, arg1, v=None, perm=None, autom=None, check=True): @@ -178,6 +180,7 @@ def _element_constructor_(self, arg1, v=None, perm=None, autom=None, check=True) ((1, 1, 1, 1); (), Ring endomorphism of Finite Field in a of size 3^2 Defn: a |--> 2*a + 1) """ from sage.categories.homset import End + R = self.base_ring() if arg1 == 0: if v is None: @@ -191,20 +194,15 @@ def _element_constructor_(self, arg1, v=None, perm=None, autom=None, check=True) try: v = [R(x) for x in v] except TypeError: - raise TypeError('the vector attribute %s ' % v + - 'should be iterable') + raise TypeError('the vector attribute %s ' % v + 'should be iterable') if len(v) != self.degree(): - raise ValueError('the length of the vector is %s,' % len(v) + - ' should be %s' % self.degree()) + raise ValueError('the length of the vector is %s,' % len(v) + ' should be %s' % self.degree()) if not all(x.parent() is R and x.is_unit() for x in v): - raise ValueError('there is at least one element in the ' + - 'list %s not lying in %s ' % (v, R) + - 'or which is not invertible') + raise ValueError('there is at least one element in the ' + 'list %s not lying in %s ' % (v, R) + 'or which is not invertible') try: perm = Permutation(perm) except TypeError: - raise TypeError('the permutation attribute %s ' % perm + - 'could not be converted to a permutation') + raise TypeError('the permutation attribute %s ' % perm + 'could not be converted to a permutation') if len(perm) != self.degree(): txt = 'the permutation length is {}, should be {}' raise ValueError(txt.format(len(perm), self.degree())) @@ -213,8 +211,7 @@ def _element_constructor_(self, arg1, v=None, perm=None, autom=None, check=True) if autom.parent() != End(R): autom = End(R)(autom) except TypeError: - raise TypeError('%s of type %s' % (autom, type(autom)) + - ' is not coerceable to an automorphism') + raise TypeError('%s of type %s' % (autom, type(autom)) + ' is not coerceable to an automorphism') return self.Element(self, v, perm, autom) try: if arg1.parent() is self: @@ -223,12 +220,12 @@ def _element_constructor_(self, arg1, v=None, perm=None, autom=None, check=True) pass try: from sage.rings.integer import Integer + if Integer(arg1) == 1: return self() except TypeError: pass - raise TypeError('the first argument must be an integer' + - ' or an element of this group') + raise TypeError('the first argument must be an integer' + ' or an element of this group') def base_ring(self): r""" @@ -269,7 +266,7 @@ def _an_element_(self): p = Permutation([self.degree()] + list(range(1, self.degree()))) if not R.is_prime_field(): - f = R.hom([R.gen()**R.characteristic()]) + f = R.hom([R.gen() ** R.characteristic()]) else: f = R.Hom(R).identity() return self(0, v, p, f) @@ -309,12 +306,12 @@ def gens(self) -> tuple: Ring endomorphism of Finite Field in a of size 2^2 Defn: a |--> a + 1)) """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup + R = self.base_ring() l = [self(v=([R.primitive_element()] + [R.one()] * (self.degree() - 1)))] - l.extend(self(perm=Permutation(g)) - for g in SymmetricGroup(self.degree()).gens()) + l.extend(self(perm=Permutation(g)) for g in SymmetricGroup(self.degree()).gens()) if R.is_field() and not R.is_prime_field(): - l.append(self(autom=R.hom([R.primitive_element()**R.characteristic()]))) + l.append(self(autom=R.hom([R.primitive_element() ** R.characteristic()]))) return tuple(l) def order(self) -> Integer: @@ -329,6 +326,7 @@ def order(self) -> Integer: """ from sage.arith.misc import factorial from sage.categories.homset import End + n = self.degree() R = self.base_ring() if R.is_field(): @@ -387,8 +385,7 @@ def _repr_(self) -> str: sage: SemimonomialTransformationGroup(F, 3) # indirect doctest Semimonomial transformation group over Finite Field in a of size 2^2 of degree 3 """ - return ('Semimonomial transformation group over %s' % self.base_ring() + - ' of degree %s' % self.degree()) + return 'Semimonomial transformation group over %s' % self.base_ring() + ' of degree %s' % self.degree() def _latex_(self) -> str: r""" @@ -401,10 +398,9 @@ def _latex_(self) -> str: \left(\Bold{F}_{2^{2}}^3\wr\langle (1,2,3), (1,2) \rangle \right) \rtimes \operatorname{Aut}(\Bold{F}_{2^{2}}) """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup + ring_latex = self.base_ring()._latex_() - return ('\\left(' + ring_latex + '^' + str(self.degree()) + '\\wr' + - SymmetricGroup(self.degree())._latex_() + - ' \\right) \\rtimes \\operatorname{Aut}(' + ring_latex + ')') + return '\\left(' + ring_latex + '^' + str(self.degree()) + '\\wr' + SymmetricGroup(self.degree())._latex_() + ' \\right) \\rtimes \\operatorname{Aut}(' + ring_latex + ')' class SemimonomialActionVec(Action): @@ -417,6 +413,7 @@ class SemimonomialActionVec(Action): (The indexing of vectors is `0`-based here, so `\psi = (\psi_0, \psi_1, \ldots, \psi_{n-1})`.) """ + def __init__(self, G, V, check=True): r""" Initialization. @@ -431,6 +428,7 @@ def __init__(self, G, V, check=True): """ if check: from sage.modules.free_module import FreeModule_generic + if not isinstance(G, SemimonomialTransformationGroup): raise ValueError('%s is not a semimonomial group' % G) if not isinstance(V, FreeModule_generic): @@ -469,6 +467,7 @@ class SemimonomialActionMat(Action): See :class:`~sage.groups.semimonomial_transformations.semimonomial_transformation_group.SemimonomialActionVec` for the definition of the action on the row vectors of such a matrix. """ + def __init__(self, G, M, check=True): r""" Initialization. @@ -485,13 +484,13 @@ def __init__(self, G, M, check=True): """ if check: from sage.matrix.matrix_space import MatrixSpace + if not isinstance(G, SemimonomialTransformationGroup): raise ValueError('%s is not a semimonomial group' % G) if not isinstance(M, MatrixSpace): raise ValueError('%s is not a matrix space' % M) if M.ncols() != G.degree(): - raise ValueError('the number of columns of %s' % M + - ' and the degree of %s are different' % G) + raise ValueError('the number of columns of %s' % M + ' and the degree of %s are different' % G) if M.base_ring() != G.base_ring(): raise ValueError('%s and %s have different base rings' % (M, G)) Action.__init__(self, G, M) diff --git a/src/sage/homology/algebraic_topological_model.py b/src/sage/homology/algebraic_topological_model.py index 09edddcb2b9..3af22b42e4d 100644 --- a/src/sage/homology/algebraic_topological_model.py +++ b/src/sage/homology/algebraic_topological_model.py @@ -182,7 +182,7 @@ def algebraic_topological_model(K, base_ring=None): # its image in C, as an element in the free module of n-chains. iota_dict = {} - for n in range(K.dimension()+1): + for n in range(K.dimension() + 1): gens[n] = [] phi_dict[n] = {} pi_dict[n] = {} @@ -192,7 +192,7 @@ def algebraic_topological_model(K, base_ring=None): # old_cells: cells one dimension lower. old_cells = [] - for dim in range(K.dimension()+1): + for dim in range(K.dimension() + 1): n_cells = K._n_cells_sorted(dim) diff = C.differential(dim) # diff is sparse and low density. Dense matrices are faster @@ -220,9 +220,9 @@ def algebraic_topological_model(K, base_ring=None): c_bar = c_vec bdry_c = diff * c_vec # Apply phi to bdry_c and subtract from c_bar. - for (idx, coord) in bdry_c.items(): + for idx, coord in bdry_c.items(): try: - c_bar -= coord * phi_dict[dim-1][idx] + c_bar -= coord * phi_dict[dim - 1][idx] except KeyError: pass @@ -231,9 +231,9 @@ def algebraic_topological_model(K, base_ring=None): # Evaluate pi(bdry(c_bar)). pi_bdry_c_bar = zero - for (idx, coeff) in bdry_c_bar.items(): + for idx, coeff in bdry_c_bar.items(): try: - pi_bdry_c_bar += coeff * pi_dict[dim-1][idx] + pi_bdry_c_bar += coeff * pi_dict[dim - 1][idx] except KeyError: pass @@ -254,30 +254,30 @@ def algebraic_topological_model(K, base_ring=None): lambda_i = pi_bdry_c_bar[u_idx] # Now find the actual cell. u = old_cells[u_idx] - if u in gens[dim-1]: + if u in gens[dim - 1]: break # pi(c) = 0: no need to do anything about this. for c_j_idx in range(old_rank): # eta_ij = . try: - eta_ij = pi_dict[dim-1][c_j_idx][u_idx] + eta_ij = pi_dict[dim - 1][c_j_idx][u_idx] except (KeyError, IndexError): eta_ij = 0 if eta_ij: # Adjust phi(c_j). try: - phi_dict[dim-1][c_j_idx] += eta_ij * lambda_i**(-1) * c_bar + phi_dict[dim - 1][c_j_idx] += eta_ij * lambda_i ** (-1) * c_bar except KeyError: - phi_dict[dim-1][c_j_idx] = eta_ij * lambda_i**(-1) * c_bar + phi_dict[dim - 1][c_j_idx] = eta_ij * lambda_i ** (-1) * c_bar # Adjust pi(c_j). try: - pi_dict[dim-1][c_j_idx] += -eta_ij * lambda_i**(-1) * pi_bdry_c_bar + pi_dict[dim - 1][c_j_idx] += -eta_ij * lambda_i ** (-1) * pi_bdry_c_bar except KeyError: - pi_dict[dim-1][c_j_idx] = -eta_ij * lambda_i**(-1) * pi_bdry_c_bar + pi_dict[dim - 1][c_j_idx] = -eta_ij * lambda_i ** (-1) * pi_bdry_c_bar - gens[dim-1].remove(u) - del iota_dict[dim-1][u] + gens[dim - 1].remove(u) + del iota_dict[dim - 1][u] old_cells = n_cells # Now we have constructed the raw data for M, pi, iota, phi, so we @@ -293,7 +293,7 @@ def algebraic_topological_model(K, base_ring=None): pi_data = {} iota_data = {} phi_data = {} - for n in range(K.dimension()+1): + for n in range(K.dimension() + 1): n_cells = K._n_cells_sorted(n) # Remove zero entries from pi_dict and phi_dict. pi_dict[n] = {i: pi_dict[n][i] for i in pi_dict[n] if pi_dict[n][i]} @@ -307,11 +307,11 @@ def algebraic_topological_model(K, base_ring=None): # will define chain maps and chain homotopies. pi_cols = [] phi_cols = [] - for (idx, c) in enumerate(n_cells): + for idx, c in enumerate(n_cells): # First pi: if idx in pi_dict[n]: column = vector(base_ring, M_rows) - for (entry, coeff) in pi_dict[n][idx].items(): + for entry, coeff in pi_dict[n][idx].items(): # Translate from cells in n_cells to cells in gens[n]. column[gens[n].index(n_cells[entry])] = coeff else: @@ -322,7 +322,7 @@ def algebraic_topological_model(K, base_ring=None): try: column = phi_dict[n][idx] except KeyError: - column = vector(base_ring, len(K.n_cells(n+1))) + column = vector(base_ring, len(K.n_cells(n + 1))) phi_cols.append(column) # Now iota: iota_cols = [iota_dict[n][c] for c in gens[n]] @@ -433,6 +433,7 @@ def algebraic_topological_model_delta_complex(K, base_ring=None): sage: coC.differential(1) * H.dual().iota().in_degree(1).column(1) == 0 True """ + def conditionally_sparse(m): """ Return a sparse matrix if the characteristic is zero. @@ -456,7 +457,7 @@ def conditionally_sparse(m): phi_data = {} iota_data = {} - for n in range(-1, K.dimension()+1): + for n in range(-1, K.dimension() + 1): gens[n] = [] C = K.chain_complex(base_ring=base_ring) @@ -464,7 +465,7 @@ def conditionally_sparse(m): pi_cols = [] iota_cols = {} - for dim in range(K.dimension()+1): + for dim in range(K.dimension() + 1): # old_cells: cells one dimension lower. old_cells = n_cells # n_cells: the standard basis for the vector space C.free_module(dim). @@ -480,7 +481,7 @@ def conditionally_sparse(m): old_rank = len(old_cells) # Create some matrix spaces to try to speed up matrix creation. - MS_pi_t = MatrixSpace(base_ring, old_rank, len(gens[dim-1])) + MS_pi_t = MatrixSpace(base_ring, old_rank, len(gens[dim - 1])) pi_old = MS_pi_t.matrix(pi_cols).transpose() iota_cols_old = iota_cols @@ -522,7 +523,7 @@ def conditionally_sparse(m): # Take any u in gens so that lambda_i = != 0. # u_idx will be the index of the corresponding cell. (u_idx, lambda_i) = pi_bdry_c_bar.leading_item() - for (u_idx, lambda_i) in pi_bdry_c_bar.items(): + for u_idx, lambda_i in pi_bdry_c_bar.items(): if u_idx not in to_be_deleted: break # This element/column needs to be deleted from gens and @@ -536,16 +537,15 @@ def conditionally_sparse(m): eta_ij = c_j.dot_product(pi_old.row(u_idx)) if eta_ij: # Adjust phi(c_j). - phi_old_cols[c_j_idx] += eta_ij * lambda_i**(-1) * c_bar + phi_old_cols[c_j_idx] += eta_ij * lambda_i ** (-1) * c_bar # Adjust pi(c_j). - pi_cols_old[c_j_idx] -= eta_ij * lambda_i**(-1) * pi_bdry_c_bar + pi_cols_old[c_j_idx] -= eta_ij * lambda_i ** (-1) * pi_bdry_c_bar # The matrices involved have many zero entries. For # such matrices, using sparse matrices is faster over # the rationals, slower over finite fields. phi_old = matrix(base_ring, phi_old_cols, sparse=(base_ring == QQ)).transpose() - keep = vector(base_ring, pi_nrows, {i: 1 for i in range(pi_nrows) - if i not in to_be_deleted}) + keep = vector(base_ring, pi_nrows, {i: 1 for i in range(pi_nrows) if i not in to_be_deleted}) cols = [v.pairwise_product(keep) for v in pi_cols_old] pi_old = MS_pi_t.matrix(cols).transpose() @@ -553,15 +553,15 @@ def conditionally_sparse(m): cols = [iota_cols_old[i] for i in sorted(iota_cols_old.keys())] for r in sorted(to_be_deleted, reverse=True): del cols[r] - del gens[dim-1][r] - iota_data[dim-1] = matrix(base_ring, len(gens[dim-1]), old_rank, cols).transpose() + del gens[dim - 1][r] + iota_data[dim - 1] = matrix(base_ring, len(gens[dim - 1]), old_rank, cols).transpose() # keep: rows to keep in pi_cols_old. Start with all # columns, then delete those in to_be_deleted. keep = sorted(set(range(pi_nrows)).difference(to_be_deleted)) # Now cols is a temporary storage for columns of pi. cols = [v.list_from_positions(keep) for v in pi_cols_old] - pi_data[dim-1] = matrix(base_ring, old_rank, len(gens[dim-1]), cols).transpose() - phi_data[dim-1] = phi_old + pi_data[dim - 1] = matrix(base_ring, old_rank, len(gens[dim - 1]), cols).transpose() + phi_data[dim - 1] = phi_old V_gens = VectorSpace(base_ring, len(gens[dim])) if pi_cols: @@ -579,7 +579,7 @@ def conditionally_sparse(m): # just the ranks of consecutive graded pieces of M. M_data = {} M_rows = 0 - for n in range(K.dimension()+1): + for n in range(K.dimension() + 1): M_cols = len(gens[n]) M_data[n] = zero_matrix(base_ring, M_rows, M_cols) M_rows = M_cols diff --git a/src/sage/homology/all.py b/src/sage/homology/all.py index 21a95c6c4af..9c31993ca9f 100644 --- a/src/sage/homology/all.py +++ b/src/sage/homology/all.py @@ -3,4 +3,5 @@ from sage.homology.chain_complex_morphism import ChainComplexMorphism from sage.misc.lazy_import import lazy_import + lazy_import('sage.homology.koszul_complex', 'KoszulComplex') diff --git a/src/sage/homology/chain_complex.py b/src/sage/homology/chain_complex.py index 73700c1d0ec..d15d0c60855 100644 --- a/src/sage/homology/chain_complex.py +++ b/src/sage/homology/chain_complex.py @@ -89,9 +89,7 @@ def _latex_module(R, m): return str(latex(FreeModule(R, m))) -def ChainComplex(data=None, base_ring=None, grading_group=None, - degree_of_differential=1, degree=1, - check=True): +def ChainComplex(data=None, base_ring=None, grading_group=None, degree_of_differential=1, degree=1, check=True): r""" Define a chain complex. @@ -279,37 +277,35 @@ def ChainComplex(data=None, base_ring=None, grading_group=None, mat1 = data_dict[n] if (mat1.nrows(), mat1.ncols()) == (0, 0): del data_dict[n] - if (mat1.nrows() != 0) and (n+degree not in data_dict): - if n+2*degree in data_dict: - mat2 = matrix(base_ring, data_dict[n+2*degree].ncols(), mat1.nrows()) + if (mat1.nrows() != 0) and (n + degree not in data_dict): + if n + 2 * degree in data_dict: + mat2 = matrix(base_ring, data_dict[n + 2 * degree].ncols(), mat1.nrows()) else: mat2 = matrix(base_ring, 0, mat1.nrows()) mat2.set_immutable() - data_dict[n+degree] = mat2 - if (mat1.ncols() != 0) and (n-degree not in data_dict): - if n-2*degree in data_dict: - mat0 = matrix(base_ring, mat1.ncols(), data_dict[n-2*degree].nrows()) + data_dict[n + degree] = mat2 + if (mat1.ncols() != 0) and (n - degree not in data_dict): + if n - 2 * degree in data_dict: + mat0 = matrix(base_ring, mat1.ncols(), data_dict[n - 2 * degree].nrows()) else: mat0 = matrix(base_ring, mat1.ncols(), 0) mat0.set_immutable() - data_dict[n-degree] = mat0 + data_dict[n - degree] = mat0 # check that this is a complex: going twice is zero if check: for n in data_dict: mat0 = data_dict[n] try: - mat1 = data_dict[n+degree] + mat1 = data_dict[n + degree] except KeyError: continue try: prod = mat1 * mat0 except TypeError: - raise TypeError('the differentials d_{{{}}} and d_{{{}}} are not compatible: ' - 'their product is not defined'.format(n, n+degree)) + raise TypeError('the differentials d_{{{}}} and d_{{{}}} are not compatible: ' 'their product is not defined'.format(n, n + degree)) if not prod.is_zero(): - raise ValueError('the differentials d_{{{}}} and d_{{{}}} are not compatible: ' - 'their composition is not zero.'.format(n, n+degree)) + raise ValueError('the differentials d_{{{}}} and d_{{{}}} are not compatible: ' 'their composition is not zero.'.format(n, n + degree)) return ChainComplex_class(grading_group, degree, base_ring, data_dict) @@ -343,9 +339,7 @@ def __init__(self, parent, vectors, check=True) -> None: """ # only nonzero vectors shall be stored, ensuring this is the # job of the _element constructor_ - assert all(v.is_immutable() and not v.is_zero() - and v.base_ring() is parent.base_ring() - for v in vectors.values()) + assert all(v.is_immutable() and not v.is_zero() and v.base_ring() is parent.base_ring() for v in vectors.values()) self._vec = vectors super().__init__(parent) @@ -393,8 +387,7 @@ def _repr_(self) -> str: deg, vec = next(iter(self._vec.items())) return 'Chain({0}:{1})'.format(deg, vec) - return 'Chain with {0} nonzero terms over {1}'.format( - n, self.parent().base_ring()) + return 'Chain with {0} nonzero terms over {1}'.format(n, self.parent().base_ring()) def _ascii_art_(self): """ @@ -425,7 +418,7 @@ def _ascii_art_(self): def arrow_art(d): d_str = [' d_{0} '.format(d)] - arrow = ' <' + '-'*(len(d_str[0])-3) + ' ' + arrow = ' <' + '-' * (len(d_str[0]) - 3) + ' ' d_str.append(arrow) return AsciiArt(d_str, baseline=0) @@ -434,7 +427,7 @@ def vector_art(d): if v.degree() == 0: return AsciiArt(['0']) v = str(v.column()).splitlines() - return AsciiArt(v, baseline=len(v)//2) + return AsciiArt(v, baseline=len(v) // 2) result = [] chain_complex = self.parent() @@ -497,8 +490,7 @@ def vector_art(d): ordered = list(reversed(ordered)) if not ordered: return UnicodeArt(['0']) - result_ordered = vector_art(ordered[0] + - chain_complex.degree_of_differential()) + result_ordered = vector_art(ordered[0] + chain_complex.degree_of_differential()) for n in ordered: result_ordered += arrow_art(n) + vector_art(n) result = [result_ordered] + result @@ -665,8 +657,8 @@ class ChainComplex_class(Parent): sage: D Chain complex with at most 2 nonzero terms over Integer Ring """ - def __init__(self, grading_group, degree_of_differential, base_ring, - differentials) -> None: + + def __init__(self, grading_group, degree_of_differential, base_ring, differentials) -> None: """ Initialize ``self``. @@ -678,27 +670,23 @@ def __init__(self, grading_group, degree_of_differential, base_ring, sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])}) sage: TestSuite(C).run() """ - if any(d.base_ring() != base_ring or not d.is_immutable() or - (d.ncols(), d.nrows()) == (0, 0) - for d in differentials.values()): + if any(d.base_ring() != base_ring or not d.is_immutable() or (d.ncols(), d.nrows()) == (0, 0) for d in differentials.values()): raise ValueError('invalid differentials') if degree_of_differential.parent() is not grading_group: raise ValueError('the degree_of_differential.parent() must be grading_group') if grading_group is not ZZ and grading_group.is_multiplicative(): raise ValueError('grading_group must be either ZZ or multiplicative') # all differentials (excluding the 0x0 ones) must be specified to the constructor - if any(dim+degree_of_differential not in differentials and d.nrows() != 0 - for dim, d in differentials.items()): + if any(dim + degree_of_differential not in differentials and d.nrows() != 0 for dim, d in differentials.items()): raise ValueError('invalid differentials') - if any(dim - degree_of_differential not in differentials - and d.ncols() != 0 - for dim, d in differentials.items()): + if any(dim - degree_of_differential not in differentials and d.ncols() != 0 for dim, d in differentials.items()): raise ValueError('invalid differentials') self._grading_group = grading_group self._degree_of_differential = degree_of_differential self._diff = differentials from sage.categories.chain_complexes import ChainComplexes + category = ChainComplexes(base_ring) super().__init__(base=base_ring, category=category) @@ -839,8 +827,7 @@ def nonzero_degrees(self): sage: D.nonzero_degrees() (0, 1, 2, 3, 6, 7) """ - return tuple(sorted(n for n, d in self._diff.items() - if d.ncols())) + return tuple(sorted(n for n, d in self._diff.items() if d.ncols())) @cached_method def ordered_degrees(self, start=None, exclude_first=False): @@ -899,6 +886,7 @@ def ordered_degrees(self, start=None, exclude_first=False): return tuple(result) from collections import deque + result = deque() result.append(start) @@ -1002,7 +990,7 @@ def dual(self): data = {} deg = self.degree_of_differential() for d in self.differential(): - data[(d+deg)] = self.differential()[d].transpose() + data[(d + deg)] = self.differential()[d].transpose() return ChainComplex(data, degree=-deg) def free_module_rank(self, degree): @@ -1075,9 +1063,7 @@ def __hash__(self) -> int: sage: hash(C) == hash(D) True """ - return (hash(self.base_ring()) - ^ hash(tuple(self.differential().items())) - ^ hash(self.degree_of_differential())) + return hash(self.base_ring()) ^ hash(tuple(self.differential().items())) ^ hash(self.degree_of_differential()) def __eq__(self, other) -> bool: """ @@ -1103,8 +1089,7 @@ def __eq__(self, other) -> bool: if d not in other.differential(): equal = equal and mat.ncols() == 0 and mat.nrows() == 0 else: - equal = (equal and - other.differential()[d].change_ring(R) == mat.change_ring(R)) + equal = equal and other.differential()[d].change_ring(R) == mat.change_ring(R) for d, mat in other.differential().items(): if d not in self.differential(): equal = equal and mat.ncols() == 0 and mat.nrows() == 0 @@ -1130,8 +1115,7 @@ def __ne__(self, other) -> bool: """ return not self == other - def homology(self, deg=None, base_ring=None, generators=False, - verbose=False, algorithm='pari'): + def homology(self, deg=None, base_ring=None, generators=False, verbose=False, algorithm='pari'): r""" The homology of the chain complex. @@ -1304,34 +1288,31 @@ def change_ring(X): if generators: # Include the generators of the nullspace kernel_basis = d_out.right_kernel().basis() if kernel_basis: - return [(HomologyGroup(1, base_ring), self({deg: gen})) - for gen in d_out.right_kernel().basis()] + return [(HomologyGroup(1, base_ring), self({deg: gen})) for gen in d_out.right_kernel().basis()] return [] return HomologyGroup(d_out_nullity, base_ring) if generators: orders, gens = self._homology_generators_snf(d_in, d_out, d_out_rank) if orders: - answer = [(HomologyGroup(1, base_ring, [order]), self({deg: gen})) - for order, gen in zip(orders, gens)] + answer = [(HomologyGroup(1, base_ring, [order]), self({deg: gen})) for order, gen in zip(orders, gens)] else: answer = [] elif base_ring.is_field(): - d_in_rank = self.rank(deg-differential, ring=base_ring) + d_in_rank = self.rank(deg - differential, ring=base_ring) answer = HomologyGroup(d_out_nullity - d_in_rank, base_ring) elif base_ring == ZZ: if d_in.ncols() == 0: all_divs = [0] * d_out_nullity else: if algorithm in ['auto', 'no_chomp']: - if ((d_in.ncols() > 300 and d_in.nrows() > 300) - or (min(d_in.ncols(), d_in.nrows()) > 100 and - d_in.ncols() + d_in.nrows() > 600)): + if (d_in.ncols() > 300 and d_in.nrows() > 300) or (min(d_in.ncols(), d_in.nrows()) > 100 and d_in.ncols() + d_in.nrows() > 600): algorithm = 'dhsw' else: algorithm = 'pari' if algorithm == 'dhsw': from sage.homology.matrix_utils import dhsw_snf + all_divs = dhsw_snf(d_in, verbose=verbose) elif algorithm == 'pari': all_divs = d_in.elementary_divisors(algorithm) @@ -1371,12 +1352,11 @@ def _homology_generators_snf(self, d_in, d_out, d_out_rank): # Compute the induced map to the kernel S = K.augment(d_in).hermite_form() - d_in_induced = S.submatrix(row=0, nrows=d_in.nrows()-d_out_rank, - col=d_in.nrows()-d_out_rank, ncols=d_in.ncols()) + d_in_induced = S.submatrix(row=0, nrows=d_in.nrows() - d_out_rank, col=d_in.nrows() - d_out_rank, ncols=d_in.ncols()) # Find the SNF of the induced matrix and appropriate generators (N, P, Q) = d_in_induced.smith_form() - all_divs = [self.base_ring().zero()]*N.nrows() + all_divs = [self.base_ring().zero()] * N.nrows() non_triv = 0 for i in range(N.nrows()): if i >= N.ncols(): @@ -1436,8 +1416,7 @@ def betti(self, deg=None, base_ring=None): raise NotImplementedError('only implemented if the base ring is ZZ or a field') H = self.homology(deg, base_ring=base_ring) if isinstance(H, dict): - return {deg: homology_group.dimension() - for deg, homology_group in H.items()} + return {deg: homology_group.dimension() for deg, homology_group in H.items()} return H.dimension() def torsion_list(self, max_prime, min_prime=2): @@ -1506,8 +1485,8 @@ def torsion_list(self, max_prime, min_prime=2): current = temp_diff[i] if current > lower: diff_dict[i] = current - lower - if i-D in diff_dict: - diff_dict[i-D] -= current - lower + if i - D in diff_dict: + diff_dict[i - D] -= current - lower differences = [i for i, di in diff_dict.items() if di != 0] answer.append((p, differences)) return answer @@ -1530,6 +1509,7 @@ def _Hom_(self, other, category=None): Ring in Category of chain complexes over Integer Ring """ from sage.homology.chain_complex_homspace import ChainComplexHomspace + return ChainComplexHomspace(self, other) def _flip_(self): @@ -1619,9 +1599,8 @@ def shift(self, n=1): """ deg = self.degree_of_differential() shift = n * deg - sgn = (-1)**n - return ChainComplex({k-shift: sgn * self._diff[k] for k in self._diff}, - degree_of_differential=deg) + sgn = (-1) ** n + return ChainComplex({k - shift: sgn * self._diff[k] for k in self._diff}, degree_of_differential=deg) def _repr_(self) -> str: """ @@ -1637,7 +1616,7 @@ def _repr_(self) -> str: if len(diffs) == 0: s = 'Trivial chain complex' else: - s = 'Chain complex with at most {0} nonzero terms'.format(len(diffs)-1) + s = 'Chain complex with at most {0} nonzero terms'.format(len(diffs) - 1) s += f' over {self.base_ring()}' return s @@ -1670,8 +1649,8 @@ def arrow_art(n): d_n = self.differential(n) if d_n.nrows() == 0 or d_n.ncols() == 0: return AsciiArt(['<--']) - d_str = [' '+line+' ' for line in str(d_n).splitlines()] - arrow = '<' + '-'*(len(d_str[0])-1) + d_str = [' ' + line + ' ' for line in str(d_n).splitlines()] + arrow = '<' + '-' * (len(d_str[0]) - 1) d_str.append(arrow) return AsciiArt(d_str) @@ -1778,14 +1757,14 @@ def _latex_(self): sage: C._latex_() '\\Bold{Z}^{1} \\xrightarrow{d_{\\text{\\texttt{(0,{ }0)}}}} \\Bold{Z}^{1}' """ -# Warning: this is likely to screw up if, for example, the -# degree of the differential is 2 and there are nonzero terms -# in consecutive dimensions (e.g., in dimensions 0 and 1). In -# such cases, the representation might show a differential -# connecting these terms, although the differential goes from -# dimension 0 to dimension 2, and from dimension 1 to -# dimension 3, etc. I don't know how much effort should be -# put into trying to fix this. + # Warning: this is likely to screw up if, for example, the + # degree of the differential is 2 and there are nonzero terms + # in consecutive dimensions (e.g., in dimensions 0 and 1). In + # such cases, the representation might show a differential + # connecting these terms, although the differential goes from + # dimension 0 to dimension 2, and from dimension 1 to + # dimension 3, etc. I don't know how much effort should be + # put into trying to fix this. string = "" diffs = self._diff if len(diffs) == 0: @@ -1918,11 +1897,8 @@ def cartesian_product(self, *factors, **kwds): subdivide = kwds.get('subdivide', False) diffs = [D.differential() for D in factors] keys = reduce(lambda X, d: X.union(d.keys()), diffs, set()) - ret = {k: matrix.block_diagonal([d.get(k, zero) for d in diffs], - subdivide=subdivide) - for k in keys} - return ChainComplex(ret, degree_of_differential=deg_diff, - grading_group=self._grading_group) + ret = {k: matrix.block_diagonal([d.get(k, zero) for d in diffs], subdivide=subdivide) for k in keys} + return ChainComplex(ret, degree_of_differential=deg_diff, grading_group=self._grading_group) def tensor(self, *factors, **kwds): r""" @@ -2065,20 +2041,21 @@ def tensor(self, *factors, **kwds): ret = self if self._grading_group is ZZ: + def scalar(a): - return (-1)**(a * deg_diff) + return (-1) ** (a * deg_diff) + else: + def scalar(a): - return (-1)**(sum(a) * sum(deg_diff)) + return (-1) ** (sum(a) * sum(deg_diff)) for D in factors: # Setup d = ret.differential() dD = D.differential() - deg = sorted((k, ret.free_module_rank(k)) for k in d - if ret.free_module_rank(k) > 0) - degD = sorted((k, D.free_module_rank(k)) for k in dD - if D.free_module_rank(k) > 0) + deg = sorted((k, ret.free_module_rank(k)) for k in d if ret.free_module_rank(k) > 0) + degD = sorted((k, D.free_module_rank(k)) for k in dD if D.free_module_rank(k) > 0) diff = {} # Our choice for tensor products will be x # y = x1 * y + x2 * y + ... @@ -2088,26 +2065,26 @@ def scalar(a): for b, s in degD: rp = d[a].nrows() sp = dD[b].nrows() - if a+b not in diff: - diff[a+b] = {} - mor = diff[a+b] + if a + b not in diff: + diff[a + b] = {} + mor = diff[a + b] cur = {} - cur[(a+deg_diff, b)] = [] - cur[(a, b+deg_diff)] = [] + cur[(a + deg_diff, b)] = [] + cur[(a, b + deg_diff)] = [] for i in range(r): for j in range(s): # \partial x_i \otimes y_j - vec = [zero]*(rp*s) + vec = [zero] * (rp * s) for k, val in enumerate(d[a].column(i)): - vec[s*k+j] += val - cur[(a+deg_diff, b)].append(vec) + vec[s * k + j] += val + cur[(a + deg_diff, b)].append(vec) # (-1)^a x_i \otimes \partial y_j - vec = [zero]*(r*sp) + vec = [zero] * (r * sp) for k, val in enumerate(dD[b].column(j)): - vec[sp*i+k] += scalar(a) * val - cur[(a, b+deg_diff)].append(vec) + vec[sp * i + k] += scalar(a) * val + cur[(a, b + deg_diff)].append(vec) mor[a, b] = cur @@ -2147,8 +2124,7 @@ def scalar(a): for k in to_delete: del diff[k] - ret = ChainComplex(diff, degree_of_differential=deg_diff, - grading_group=self._grading_group) + ret = ChainComplex(diff, degree_of_differential=deg_diff, grading_group=self._grading_group) return ret diff --git a/src/sage/homology/chain_complex_homspace.py b/src/sage/homology/chain_complex_homspace.py index b5f2cb1ee97..a5f6bd1601a 100644 --- a/src/sage/homology/chain_complex_homspace.py +++ b/src/sage/homology/chain_complex_homspace.py @@ -119,6 +119,7 @@ class ChainComplexHomspace(sage.categories.homset.Homset): to Chain complex with at most 5 nonzero terms over Integer Ring in Category of chain complexes over Integer Ring """ + def __call__(self, f): """ `f` is a dictionary of matrices in the basis of the chain complex. diff --git a/src/sage/homology/chain_complex_morphism.py b/src/sage/homology/chain_complex_morphism.py index f12c6950e1e..ca4af1f2694 100644 --- a/src/sage/homology/chain_complex_morphism.py +++ b/src/sage/homology/chain_complex_morphism.py @@ -62,6 +62,7 @@ class ChainComplexMorphism(Morphism): """ An element of this class is a morphism of chain complexes. """ + def __init__(self, matrices, C, D, check=True) -> None: """ Create a morphism from a dictionary of matrices. @@ -116,8 +117,7 @@ def __init__(self, matrices, C, D, check=True) -> None: To: Chain complex with at most 1 nonzero terms over Integer Ring """ if not C.base_ring() == D.base_ring(): - raise NotImplementedError('morphisms between chain complexes of different' - ' base rings are not implemented') + raise NotImplementedError('morphisms between chain complexes of different' ' base rings are not implemented') d = C.degree_of_differential() if d != D.degree_of_differential(): raise ValueError('degree of differential does not match') @@ -134,17 +134,14 @@ def __init__(self, matrices, C, D, check=True) -> None: try: matrices[i] = initial_matrices.pop(i) except KeyError: - matrices[i] = zero_matrix(C.base_ring(), - D.differential(i).ncols(), - C.differential(i).ncols(), sparse=True) + matrices[i] = zero_matrix(C.base_ring(), D.differential(i).ncols(), C.differential(i).ncols(), sparse=True) if check: # All remaining matrices given must be 0x0. if not all(m.ncols() == m.nrows() == 0 for m in initial_matrices.values()): raise ValueError('the remaining matrices are not empty') # Check sizes of matrices. for i in matrices: - if (matrices[i].nrows() != D.free_module_rank(i) or - matrices[i].ncols() != C.free_module_rank(i)): + if matrices[i].nrows() != D.free_module_rank(i) or matrices[i].ncols() != C.free_module_rank(i): raise ValueError(f'matrix in degree {i} is not the right size') # Check commutativity. for i in degrees: @@ -153,11 +150,11 @@ def __init__(self, matrices, C, D, check=True) -> None: raise ValueError('{} and {} are not rank 0 in degree {}'.format(C, D, i)) continue if i + d not in degrees: - if not (C.free_module_rank(i+d) == D.free_module_rank(i+d) == 0): - raise ValueError('{} and {} are not rank 0 in degree {}'.format(C, D, i+d)) + if not (C.free_module_rank(i + d) == D.free_module_rank(i + d) == 0): + raise ValueError('{} and {} are not rank 0 in degree {}'.format(C, D, i + d)) continue Dm = D.differential(i) * matrices[i] - mC = matrices[i+d] * C.differential(i) + mC = matrices[i + d] * C.differential(i) if mC != Dm: raise ValueError('matrices must define a chain complex morphism') self._matrix_dictionary = {} @@ -231,8 +228,7 @@ def to_matrix(self, deg=None): """ if deg is not None: return self.in_degree(deg) - blocks = [self._matrix_dictionary[n] - for n in sorted(self._matrix_dictionary)] + blocks = [self._matrix_dictionary[n] for n in sorted(self._matrix_dictionary)] return block_diagonal_matrix(blocks) def dual(self): @@ -424,7 +420,7 @@ def __mul__(self, x): return ChainComplexMorphism(f, self.domain(), self.codomain()) f = {} for i in self._matrix_dictionary: - f[i] = self._matrix_dictionary[i]*x.in_degree(i) + f[i] = self._matrix_dictionary[i] * x.in_degree(i) return ChainComplexMorphism(f, x.domain(), self.codomain()) def __rmul__(self, x): @@ -503,10 +499,7 @@ def __eq__(self, x) -> bool: sage: x == y True """ - return isinstance(x, ChainComplexMorphism) \ - and self.codomain() == x.codomain() \ - and self.domain() == x.domain() \ - and self._matrix_dictionary == x._matrix_dictionary + return isinstance(x, ChainComplexMorphism) and self.codomain() == x.codomain() and self.domain() == x.domain() and self._matrix_dictionary == x._matrix_dictionary def is_identity(self) -> bool: """ diff --git a/src/sage/homology/chain_homotopy.py b/src/sage/homology/chain_homotopy.py index 2518716b190..6558b445059 100644 --- a/src/sage/homology/chain_homotopy.py +++ b/src/sage/homology/chain_homotopy.py @@ -109,6 +109,7 @@ class ChainHomotopy(Morphism): ... ValueError: the data do not define a valid chain homotopy """ + def __init__(self, matrices, f, g=None) -> None: r""" Create a chain homotopy between the given chain maps @@ -155,30 +156,29 @@ def __init__(self, matrices, f, g=None) -> None: raise ValueError('the chain complexes are not compatible') if g is not None: # Check that the chain maps are compatible. - if not (domain == g.domain() and codomain == - g.codomain()): + if not (domain == g.domain() and codomain == g.codomain()): raise ValueError('the chain maps are not compatible') # Check that the data define a chain homotopy. for i in domain.differential(): - if i in matrices and i+deg in matrices: - if not (codomain.differential(i-deg) * matrices[i] + matrices[i+deg] * domain.differential(i) == f.in_degree(i) - g.in_degree(i)): + if i in matrices and i + deg in matrices: + if not (codomain.differential(i - deg) * matrices[i] + matrices[i + deg] * domain.differential(i) == f.in_degree(i) - g.in_degree(i)): raise ValueError('the data do not define a valid chain homotopy') elif i in matrices: - if not (codomain.differential(i-deg) * matrices[i] == f.in_degree(i) - g.in_degree(i)): + if not (codomain.differential(i - deg) * matrices[i] == f.in_degree(i) - g.in_degree(i)): raise ValueError('the data do not define a valid chain homotopy') - elif i+deg in matrices: - if not (matrices[i+deg] * domain.differential(i) == f.in_degree(i) - g.in_degree(i)): + elif i + deg in matrices: + if not (matrices[i + deg] * domain.differential(i) == f.in_degree(i) - g.in_degree(i)): raise ValueError('the data do not define a valid chain homotopy') else: # Define g. g_data = {} for i in domain.differential(): - if i in matrices and i+deg in matrices: - g_data[i] = f.in_degree(i) - matrices[i+deg] * domain.differential(i) - codomain.differential(i-deg) * matrices[i] + if i in matrices and i + deg in matrices: + g_data[i] = f.in_degree(i) - matrices[i + deg] * domain.differential(i) - codomain.differential(i - deg) * matrices[i] elif i in matrices: - g_data[i] = f.in_degree(i) - codomain.differential(i-deg) * matrices[i] - elif i+deg in matrices: - g_data[i] = f.in_degree(i) - matrices[i+deg] * domain.differential(i) + g_data[i] = f.in_degree(i) - codomain.differential(i - deg) * matrices[i] + elif i + deg in matrices: + g_data[i] = f.in_degree(i) - matrices[i + deg] * domain.differential(i) g = ChainComplexMorphism(g_data, domain, codomain) self._matrix_dictionary = {} for i in matrices: @@ -237,8 +237,8 @@ def is_algebraic_gradient_vector_field(self) -> bool: deg = self.domain().degree_of_differential() matrices = self._matrix_dictionary for i in matrices: - if i-deg in matrices: - if matrices[i-deg] * matrices[i] != 0: + if i - deg in matrices: + if matrices[i - deg] * matrices[i] != 0: return False return True @@ -276,11 +276,11 @@ def is_homology_gradient_vector_field(self) -> bool: deg = self.domain().degree_of_differential() matrices = self._matrix_dictionary for i in matrices: - if i+deg in matrices: + if i + deg in matrices: diff_i = self.domain().differential(i) - if diff_i * matrices[i+deg] * diff_i != diff_i: + if diff_i * matrices[i + deg] * diff_i != diff_i: return False - if matrices[i] * self.domain().differential(i-deg) * matrices[i] != matrices[i]: + if matrices[i] * self.domain().differential(i - deg) * matrices[i] != matrices[i]: return False return True @@ -312,8 +312,9 @@ def in_degree(self, n): return self._matrix_dictionary[n] except KeyError: from sage.matrix.constructor import zero_matrix + deg = self.domain().degree_of_differential() - rows = self.codomain().free_module_rank(n-deg) + rows = self.codomain().free_module_rank(n - deg) cols = self.domain().free_module_rank(n) return zero_matrix(self.domain().base_ring(), rows, cols) @@ -342,7 +343,7 @@ def dual(self): """ matrix_dict = self._matrix_dictionary deg = self.domain().degree_of_differential() - matrices = {i-deg: matrix_dict[i].transpose() for i in matrix_dict} + matrices = {i - deg: matrix_dict[i].transpose() for i in matrix_dict} return ChainHomotopy(matrices, self._f.dual(), self._g.dual()) def __hash__(self) -> int: @@ -422,6 +423,7 @@ class ChainContraction(ChainHomotopy): ....: 1: zero_matrix(ZZ, 1), ....: 2: identity_matrix(ZZ, 1)}, pi, iota) """ + def __init__(self, matrices, pi, iota) -> None: r""" Create a chain contraction from the given data. @@ -462,8 +464,7 @@ def __init__(self, matrices, pi, iota) -> None: from sage.homology.chain_complex_morphism import ChainComplexMorphism from sage.matrix.constructor import identity_matrix - if not (pi.domain() == iota.codomain() - and pi.codomain() == iota.domain()): + if not (pi.domain() == iota.codomain() and pi.codomain() == iota.domain()): raise ValueError('the chain maps are not composable') C = pi.domain() D = pi.codomain() @@ -489,7 +490,7 @@ def __init__(self, matrices, pi, iota) -> None: # Check that `\pi H = 0`: deg = C.degree_of_differential() for i in matrices: - if pi.in_degree(i-deg) * matrices[i] != 0: + if pi.in_degree(i - deg) * matrices[i] != 0: raise ValueError('the data do not define a valid chain contraction: pi H != 0') # Check that `H \iota = 0`: for i in iota._matrix_dictionary: @@ -599,5 +600,5 @@ def dual(self): """ matrix_dict = self._matrix_dictionary deg = self.domain().degree_of_differential() - matrices = {i-deg: matrix_dict[i].transpose() for i in matrix_dict} + matrices = {i - deg: matrix_dict[i].transpose() for i in matrix_dict} return ChainContraction(matrices, self.iota().dual(), self.pi().dual()) diff --git a/src/sage/homology/chains.py b/src/sage/homology/chains.py index 7aeb9d189f2..b5c3cfc9142 100644 --- a/src/sage/homology/chains.py +++ b/src/sage/homology/chains.py @@ -124,8 +124,8 @@ class Chains(CellComplexReference, CombinatorialFreeModule): sage: c.eval(z) 6 """ - def __init__(self, cell_complex, degree, cells=None, - base_ring=None) -> None: + + def __init__(self, cell_complex, degree, cells=None, base_ring=None) -> None: """ EXAMPLES:: @@ -163,10 +163,7 @@ def __init__(self, cell_complex, degree, cells=None, if base_ring is None: base_ring = ZZ CellComplexReference.__init__(self, cell_complex, degree, cells=cells) - CombinatorialFreeModule.__init__( - self, base_ring, self._cells, - prefix='', bracket=False - ) + CombinatorialFreeModule.__init__(self, base_ring, self._cells, prefix='', bracket=False) def dual(self): """ @@ -186,10 +183,7 @@ def dual(self): sage: type(chains.dual()) """ - return Cochains( - self.cell_complex, self.degree, - cells=self._cells, base_ring=self.base_ring() - ) + return Cochains(self.cell_complex, self.degree, cells=self._cells, base_ring=self.base_ring()) def chain_complex(self): """ @@ -236,9 +230,7 @@ def to_complex(self): [0] [0] [0] [1] """ - return self.parent().chain_complex()({ - self.parent().degree(): self.to_vector() - }) + return self.parent().chain_complex()({self.parent().degree(): self.to_vector()}) def boundary(self): """ @@ -260,9 +252,7 @@ def boundary(self): chains = self.parent() degree = chains.degree() d = chains.chain_complex().differential(degree) - codomain = chains.cell_complex().n_chains( - degree - 1, base_ring=self.base_ring() - ) + codomain = chains.cell_complex().n_chains(degree - 1, base_ring=self.base_ring()) return codomain.from_vector(d * self.to_vector()) def is_cycle(self) -> bool: @@ -352,8 +342,8 @@ class Cochains(CellComplexReference, CombinatorialFreeModule): sage: c.eval(z) 6 """ - def __init__(self, cell_complex, degree, cells=None, - base_ring=None) -> None: + + def __init__(self, cell_complex, degree, cells=None, base_ring=None) -> None: """ EXAMPLES:: @@ -391,11 +381,7 @@ def __init__(self, cell_complex, degree, cells=None, if base_ring is None: base_ring = ZZ CellComplexReference.__init__(self, cell_complex, degree, cells=cells) - CombinatorialFreeModule.__init__( - self, base_ring, self._cells, - prefix='\\chi', - bracket=['_', ''] - ) + CombinatorialFreeModule.__init__(self, base_ring, self._cells, prefix='\\chi', bracket=['_', '']) def dual(self): """ @@ -415,10 +401,7 @@ def dual(self): sage: type(cochains.dual()) """ - return Chains( - self.cell_complex, self.degree, - cells=self._cells, base_ring=self.base_ring() - ) + return Chains(self.cell_complex, self.degree, cells=self._cells, base_ring=self.base_ring()) def cochain_complex(self): """ @@ -466,9 +449,7 @@ def to_complex(self): [0] [0] [1] [0] """ - return self.parent().cochain_complex()({ - self.parent().degree(): self.to_vector() - }) + return self.parent().cochain_complex()({self.parent().degree(): self.to_vector()}) def coboundary(self): r""" @@ -490,9 +471,7 @@ def coboundary(self): cochains = self.parent() degree = cochains.degree() d = cochains.cochain_complex().differential(degree) - codomain = cochains.cell_complex().n_chains( - degree + 1, base_ring=self.base_ring(), cochains=True - ) + codomain = cochains.cell_complex().n_chains(degree + 1, base_ring=self.base_ring(), cochains=True) return codomain.from_vector(d * self.to_vector()) def is_cocycle(self) -> bool: @@ -588,8 +567,7 @@ def eval(self, other): raise ValueError('argument is not a chain') if other.parent().indices() != self.parent().indices(): raise ValueError('the cells are not compatible') - result = sum(coeff * other.coefficient(cell) - for cell, coeff in self) + result = sum(coeff * other.coefficient(cell) for cell, coeff in self) R = self.base_ring() if R != other.base_ring(): R = coercion_model.common_parent(R, other.base_ring()) @@ -638,14 +616,12 @@ def cup_product(self, cochain): right_deg = cochain.parent().degree() left_chains = self.parent().dual() right_chains = cochain.parent().dual() - base_ring = coercion_model.common_parent( - left_chains.base_ring(), right_chains.base_ring()) + base_ring = coercion_model.common_parent(left_chains.base_ring(), right_chains.base_ring()) cx = self.parent().cell_complex() - codomain = cx.n_chains( - left_deg + right_deg, base_ring=base_ring, cochains=True) + codomain = cx.n_chains(left_deg + right_deg, base_ring=base_ring, cochains=True) accumulator = codomain.zero() for cell in codomain.indices(): - for (coeff, left_cell, right_cell) in cx.alexander_whitney(cell, left_deg): + for coeff, left_cell, right_cell in cx.alexander_whitney(cell, left_deg): if not coeff: continue left = left_chains(left_cell) diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index 703db29e689..637bd8bdb77 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -93,6 +93,7 @@ class FreeResolution(SageObject, metaclass=ClasscallMetaclass): that is exact (all homology groups are zero) such that the image of `d_1` is `M`. """ + @staticmethod def __classcall_private__(cls, module, *args, graded=False, degrees=None, shifts=None, **kwds): """ @@ -156,23 +157,20 @@ def __classcall_private__(cls, module, *args, graded=False, degrees=None, shifts if is_free_module: if graded: from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module - return GradedFiniteFreeResolution_free_module(module, - *args, - degrees=degrees, - shifts=shifts, - **kwds) + + return GradedFiniteFreeResolution_free_module(module, *args, degrees=degrees, shifts=shifts, **kwds) return FiniteFreeResolution_free_module(module, *args, **kwds) from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular + if not isinstance(S, MPolynomialRing_libsingular): - raise NotImplementedError("the matrix must be over a PID or a " - " polynomial ring that is using Singular") + raise NotImplementedError("the matrix must be over a PID or a " " polynomial ring that is using Singular") if graded: # We are computing a graded resolution from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular - return GradedFiniteFreeResolution_singular(module, *args, degrees=degrees, - shifts=shifts, **kwds) + + return GradedFiniteFreeResolution_singular(module, *args, degrees=degrees, shifts=shifts, **kwds) return FiniteFreeResolution_singular(module, **kwds) @@ -353,6 +351,7 @@ class FiniteFreeResolution(FreeResolution): [ y*z - x*w] [-y^2 + x*z] """ + @lazy_attribute def _length(self): """ @@ -588,6 +587,7 @@ def chain_complex(self): 0 <── C_0 <────────────────────────────── C_1 <────── C_2 <── 0 """ from sage.homology.chain_complex import ChainComplex + mats = {} for i in range(self._length, 0, -1): mats[i] = self.matrix(i) @@ -701,6 +701,7 @@ class FiniteFreeResolution_free_module(FiniteFreeResolution): sage: res = I.free_resolution(); res S^1 <-- S^1 <-- 0 """ + @lazy_attribute def _maps(self): r""" @@ -765,6 +766,7 @@ def _maps(self): """ if isinstance(self._module, Ideal_generic): from sage.matrix.constructor import matrix + return [matrix([[self._module.gen()]])] return [self._m()] @@ -851,6 +853,7 @@ class FiniteFreeResolution_singular(FiniteFreeResolution): [-y*z + x*w] [ z^2 - y*w] """ + def __init__(self, module, name='S', algorithm='heuristic', **kwds) -> None: r""" Initialize ``self``. @@ -915,7 +918,7 @@ def _maps(self): r = minres(nres(mod, 0)) elif self._algorithm == 'heuristic': std = singular_function('std') - res = singular_function('res') # heuristic method + res = singular_function('res') # heuristic method minres = singular_function('minres') r = minres(res(std(mod), 0)) diff --git a/src/sage/homology/graded_resolution.py b/src/sage/homology/graded_resolution.py index 4d2087129fe..ffcc613f434 100644 --- a/src/sage/homology/graded_resolution.py +++ b/src/sage/homology/graded_resolution.py @@ -83,9 +83,7 @@ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.ideal import Ideal_generic -from sage.homology.free_resolution import (FiniteFreeResolution, - FiniteFreeResolution_free_module, - FiniteFreeResolution_singular) +from sage.homology.free_resolution import FiniteFreeResolution, FiniteFreeResolution_free_module, FiniteFreeResolution_singular class GradedFiniteFreeResolution(FiniteFreeResolution): @@ -106,8 +104,8 @@ class GradedFiniteFreeResolution(FiniteFreeResolution): - ``name`` -- string; name of the base ring """ - def __init__(self, module, degrees=None, shifts=None, name='S', - **kwds) -> None: + + def __init__(self, module, degrees=None, shifts=None, name='S', **kwds) -> None: r""" Initialize ``self``. @@ -194,8 +192,7 @@ def _repr_module(self, i) -> str: if not shifts: return '0' - return '\u2295'.join(f'{self._name}' + '({})'.format(-sh) - for sh in shifts) + return '\u2295'.join(f'{self._name}' + '({})'.format(-sh) for sh in shifts) def shifts(self, i): r""" @@ -322,6 +319,7 @@ class GradedFiniteFreeResolution_free_module(GradedFiniteFreeResolution, FiniteF sage: res = FreeResolution(M, graded=True); res S(0)⊕S(0)⊕S(0) <-- S(-3)⊕S(-1) <-- 0 """ + def __init__(self, module, degrees=None, *args, **kwds) -> None: """ Initialize ``self``. @@ -338,8 +336,7 @@ def __init__(self, module, degrees=None, *args, **kwds) -> None: super().__init__(module, degrees=degrees, *args, **kwds) if len(self._degrees) > 1 and any(d != 1 for d in self._degrees): - raise NotImplementedError("only the natural grading supported " - "when more than one generator") + raise NotImplementedError("only the natural grading supported " "when more than one generator") @lazy_attribute def _maps(self): @@ -373,6 +370,7 @@ def _maps(self): sage: res._res_shifts [[9]] """ + def compute_degree(base, i): """ Compute the degree by ``base * deg + shift``, @@ -387,6 +385,7 @@ def compute_degree(base, i): if isinstance(self._module, Ideal_generic): from sage.matrix.constructor import matrix + val = self._module.gen(0) self._res_shifts = [[compute_degree(val.degree(), 0)]] return [matrix([[val]])] @@ -400,13 +399,11 @@ def find_deg(i): return ret raise NotImplementedError("a generator maps to 0") - self._res_shifts = [[compute_degree(find_deg(i), i) - for i in range(M.ncols())]] + self._res_shifts = [[compute_degree(find_deg(i), i) for i in range(M.ncols())]] return [M] -class GradedFiniteFreeResolution_singular(GradedFiniteFreeResolution, - FiniteFreeResolution_singular): +class GradedFiniteFreeResolution_singular(GradedFiniteFreeResolution, FiniteFreeResolution_singular): r""" Graded free resolutions of submodules and ideals of multivariate polynomial rings implemented using Singular. @@ -469,8 +466,8 @@ class GradedFiniteFreeResolution_singular(GradedFiniteFreeResolution, sage: r = I.graded_free_resolution(); r S(0) <-- S(-1)⊕S(-2)⊕S(-2) <-- S(-3)⊕S(-3)⊕S(-4) <-- S(-5) <-- 0 """ - def __init__(self, module, degrees=None, shifts=None, name='S', - algorithm='heuristic', **kwds) -> None: + + def __init__(self, module, degrees=None, shifts=None, name='S', algorithm='heuristic', **kwds) -> None: """ Initialize. @@ -531,7 +528,7 @@ def _maps(self): r = minres(nres(mod, 0)) elif self._algorithm == 'heuristic': std = singular_function('std') - res = singular_function('res') # heuristic method + res = singular_function('res') # heuristic method minres = singular_function('minres') r = minres(res(std(mod), 0)) diff --git a/src/sage/homology/hochschild_complex.py b/src/sage/homology/hochschild_complex.py index d6b3ce150b7..72089cebb1c 100644 --- a/src/sage/homology/hochschild_complex.py +++ b/src/sage/homology/hochschild_complex.py @@ -83,6 +83,7 @@ class HochschildComplex(UniqueRepresentation, Parent): - https://ncatlab.org/nlab/show/Hochschild+cohomology - [Red2001]_ """ + def __init__(self, A, M) -> None: """ Initialize ``self``. @@ -102,8 +103,7 @@ def __init__(self, A, M) -> None: """ self._A = A self._M = M - Parent.__init__(self, base=A.base_ring(), - category=ChainComplexes(A.base_ring())) + Parent.__init__(self, base=A.base_ring(), category=ChainComplexes(A.base_ring())) def _repr_(self) -> str: """ @@ -134,6 +134,7 @@ def _latex_(self) -> str: C_{\bullet}\left(..., ...\right) """ from sage.misc.latex import latex + return "C_{{\\bullet}}\\left({}, {}\\right)".format(latex(self._A), latex(self._M)) def algebra(self): @@ -267,7 +268,7 @@ def boundary(self, d): t = self.trivial_module() zero = t.zero() return self.module(0).module_morphism(lambda x: zero, codomain=t) - Fd = self.module(d-1) + Fd = self.module(d - 1) Fd1 = self.module(d) mone = -one @@ -275,13 +276,12 @@ def on_basis(k): p = self._M.monomial(k[0]) * self._A.monomial(k[1]) ret = Fd._from_dict({(m,) + k[2:]: c for m, c in p}, remove_zeros=False) for i in range(1, d): - p = self._A.monomial(k[i]) * self._A.monomial(k[i+1]) - ret += mone**i * Fd._from_dict({k[:i] + (m,) + k[i+2:]: c - for m, c in p}, remove_zeros=False) + p = self._A.monomial(k[i]) * self._A.monomial(k[i + 1]) + ret += mone**i * Fd._from_dict({k[:i] + (m,) + k[i + 2 :]: c for m, c in p}, remove_zeros=False) p = self._A.monomial(k[-1]) * self._M.monomial(k[0]) - ret += mone**d * Fd._from_dict({(m,) + k[1:-1]: c for m, c in p}, - remove_zeros=False) + ret += mone**d * Fd._from_dict({(m,) + k[1:-1]: c for m, c in p}, remove_zeros=False) return ret + return Fd1.module_morphism(on_basis, codomain=Fd) differential = boundary @@ -389,7 +389,7 @@ def homology(self, d): if self._A.category() is not self._A.category().FiniteDimensional(): raise NotImplementedError("the algebra must be finite dimensional") - maps = {d: self.boundary(d).matrix(), d+1: self.boundary(d+1).matrix()} + maps = {d: self.boundary(d).matrix(), d + 1: self.boundary(d + 1).matrix()} C = ChainComplex(maps, degree_of_differential=-1) try: return C.homology(d) @@ -397,10 +397,9 @@ def homology(self, d): pass # Fallback if we are not working over a field or \ZZ bdry = self.boundary(d) - bdry1 = self.boundary(d+1) + bdry1 = self.boundary(d + 1) ker = bdry.kernel() - im_retract = ker.submodule([ker.retract(b) for b in bdry1.image_basis()], - unitriangular=True) + im_retract = ker.submodule([ker.retract(b) for b in bdry1.image_basis()], unitriangular=True) return ker.quotient_module(im_retract) def cohomology(self, d): @@ -443,18 +442,17 @@ def cohomology(self, d): if self._A.category() is not self._A.category().FiniteDimensional(): raise NotImplementedError("the algebra must be finite dimensional") - maps = {d+1: self.coboundary(d+1).matrix(), d: self.coboundary(d).matrix()} + maps = {d + 1: self.coboundary(d + 1).matrix(), d: self.coboundary(d).matrix()} C = ChainComplex(maps, degree_of_differential=1) try: - return C.homology(d+1) + return C.homology(d + 1) except NotImplementedError: pass # Fallback if we are not working over a field or \ZZ cb = self.coboundary(d) - cb1 = self.coboundary(d+1) + cb1 = self.coboundary(d + 1) ker = cb1.kernel() - im_retract = ker.submodule([ker.retract(b) for b in cb.image_basis()], - unitriangular=True) + im_retract = ker.submodule([ker.retract(b) for b in cb.image_basis()], unitriangular=True) return ker.quotient_module(im_retract) def _element_constructor_(self, vectors): @@ -530,8 +528,7 @@ def _an_element_(self): 0, 0] """ - return self.element_class(self, {d: self.module(d).an_element() - for d in range(4)}) + return self.element_class(self, {d: self.module(d).an_element() for d in range(4)}) class Element(ModuleElement): """ @@ -570,6 +567,7 @@ class Element(ModuleElement): sage: H({0: x-y, 2: H.module(2).basis().an_element()}) Chain with 2 nonzero terms over Integer Ring """ + def __init__(self, parent, vectors) -> None: """ Initialize ``self``. @@ -623,7 +621,7 @@ def _repr_(self) -> str: return 'Trivial chain' if n == 1: - (deg, vec), = self._vec.items() + ((deg, vec),) = self._vec.items() return f'Chain({deg}: {vec})' return f'Chain with {n} nonzero terms over {self.parent().base_ring()}' @@ -649,22 +647,22 @@ def _ascii_art_(self): """ from sage.typeset.ascii_art import AsciiArt, ascii_art - if not self._vec: # 0 chain + if not self._vec: # 0 chain return AsciiArt(['0']) def arrow_art(d): d_str = [' d_{0} '.format(d)] - arrow = ' <' + '-'*(len(d_str[0])-3) + ' ' + arrow = ' <' + '-' * (len(d_str[0]) - 3) + ' ' d_str.append(arrow) return AsciiArt(d_str, baseline=0) result = AsciiArt(['0']) max_deg = max(self._vec) - for deg in range(min(self._vec), max_deg+1): + for deg in range(min(self._vec), max_deg + 1): A = ascii_art(self.vector(deg)) A._baseline = A.height() // 2 result += arrow_art(deg) + A - return result + arrow_art(max_deg+1) + AsciiArt(['0']) + return result + arrow_art(max_deg + 1) + AsciiArt(['0']) def _add_(self, other): """ diff --git a/src/sage/homology/homology_group.py b/src/sage/homology/homology_group.py index 38662bbe485..c46bec3421a 100644 --- a/src/sage/homology/homology_group.py +++ b/src/sage/homology/homology_group.py @@ -5,6 +5,7 @@ group that prints itself in a way that is suitable for homology groups. """ + ######################################################################## # Copyright (C) 2013 John H. Palmieri # Volker Braun @@ -45,6 +46,7 @@ class HomologyGroup_class(AdditiveAbelianGroup_fixed_gens): sage: HomologyGroup(100, ZZ) Z^100 """ + def __init__(self, n, invfac) -> None: """ See :func:`HomologyGroup` for full documentation. @@ -56,7 +58,7 @@ def __init__(self, n, invfac) -> None: C5 x C5 x C7 x C8 x C9 """ n = len(invfac) - A = ZZ ** n + A = ZZ**n B = A.span([A.gen(i) * invfac[i] for i in range(n)]) AdditiveAbelianGroup_fixed_gens.__init__(self, A, B, A.gens()) @@ -88,7 +90,7 @@ def _repr_(self) -> str: printed = [] for t in torsion: numfac = torsion.count(t) - too_many = (numfac > 4) + too_many = numfac > 4 if too_many: if t not in printed: g.append("C{}^{}".format(t, numfac)) @@ -124,7 +126,7 @@ def _latex_(self): printed = [] for t in torsion: numfac = torsion.count(t) - too_many = (numfac > 4) + too_many = numfac > 4 if too_many: if t not in printed: g.append("C_{{{}}}^{{{}}}".format(t, numfac)) diff --git a/src/sage/homology/homology_morphism.py b/src/sage/homology/homology_morphism.py index eb909b7d07b..f86f20b2027 100644 --- a/src/sage/homology/homology_morphism.py +++ b/src/sage/homology/homology_morphism.py @@ -130,6 +130,7 @@ class in the torus, we can define a map `S^1 \to T` inducing an sage: diag_c(c) h^{1,0} """ + def __init__(self, map, base_ring=None, cohomology=False) -> None: """ INPUT: @@ -165,8 +166,7 @@ def __init__(self, map, base_ring=None, cohomology=False) -> None: sage: g = Hom(S1, S1).identity() sage: h = g.induced_homology_morphism(QQ) """ - if (isinstance(map.domain(), SimplicialComplex) - and (map.domain().is_mutable() or map.codomain().is_mutable())): + if isinstance(map.domain(), SimplicialComplex) and (map.domain().is_mutable() or map.codomain().is_mutable()): raise ValueError('the domain and codomain complexes must be immutable') if base_ring is None: base_ring = QQ @@ -179,13 +179,11 @@ def __init__(self, map, base_ring=None, cohomology=False) -> None: if cohomology: domain = map.codomain().cohomology_ring(base_ring=base_ring) codomain = map.domain().cohomology_ring(base_ring=base_ring) - Morphism.__init__(self, Hom(domain, codomain, - category=GradedAlgebrasWithBasis(base_ring))) + Morphism.__init__(self, Hom(domain, codomain, category=GradedAlgebrasWithBasis(base_ring))) else: domain = map.domain().homology_with_basis(base_ring=base_ring, cohomology=cohomology) codomain = map.codomain().homology_with_basis(base_ring=base_ring, cohomology=cohomology) - Morphism.__init__(self, Hom(domain, codomain, - category=GradedModulesWithBasis(base_ring))) + Morphism.__init__(self, Hom(domain, codomain, category=GradedModulesWithBasis(base_ring))) def base_ring(self): """ @@ -236,17 +234,13 @@ def to_matrix(self, deg=None): codomain = self._map.codomain() phi_codomain, H_codomain = codomain.algebraic_topological_model(base_ring) phi_domain, H_domain = domain.algebraic_topological_model(base_ring) - mat = (phi_codomain.pi().to_matrix(deg) - * self._map.associated_chain_complex_morphism(self.base_ring()).to_matrix(deg) - * phi_domain.iota().to_matrix(deg)) + mat = phi_codomain.pi().to_matrix(deg) * self._map.associated_chain_complex_morphism(self.base_ring()).to_matrix(deg) * phi_domain.iota().to_matrix(deg) if self._cohomology: mat = mat.transpose() H_domain, H_codomain = H_codomain, H_domain if deg is None: - betti_domain = [H_domain.free_module_rank(n) - for n in range(domain.dimension() + 1)] - betti_codomain = [H_codomain.free_module_rank(n) - for n in range(codomain.dimension() + 1)] + betti_domain = [H_domain.free_module_rank(n) for n in range(domain.dimension() + 1)] + betti_codomain = [H_codomain.free_module_rank(n) for n in range(codomain.dimension() + 1)] # Compute cumulative sums of Betti numbers to get subdivisions: row_subdivs = list(itertools.accumulate(betti_codomain[:-1])) col_subdivs = list(itertools.accumulate(betti_domain[:-1])) @@ -318,10 +312,7 @@ def __eq__(self, other) -> bool: sage: f.induced_homology_morphism(QQ) == id.induced_homology_morphism(QQ) False """ - if (self._map.domain() != other._map.domain() - or self._map.codomain() != other._map.codomain() - or self.base_ring() != other.base_ring() - or self._cohomology != other._cohomology): + if self._map.domain() != other._map.domain() or self._map.codomain() != other._map.codomain() or self.base_ring() != other.base_ring() or self._cohomology != other._cohomology: return False dim = min(self._map.domain().dimension(), self._map.codomain().dimension()) return all(self.to_matrix(d) == other.to_matrix(d) for d in range(dim + 1)) diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index 6187cf3a393..c1165b36d16 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -182,8 +182,8 @@ class HomologyVectorSpaceWithBasis(CombinatorialFreeModule): sage: b.cup_product(b) h^{2,0} """ - def __init__(self, base_ring, cell_complex, cohomology=False, - category=None) -> None: + + def __init__(self, base_ring, cell_complex, cohomology=False, category=None) -> None: """ Initialize ``self``. @@ -213,10 +213,8 @@ def __init__(self, base_ring, cell_complex, cohomology=False, self._contraction = phi self._complex = cell_complex self._cohomology = cohomology - self._graded_indices = {deg: range(M.free_module_rank(deg)) - for deg in range(cell_complex.dimension()+1)} - indices = [(deg, i) for deg in self._graded_indices - for i in self._graded_indices[deg]] + self._graded_indices = {deg: range(M.free_module_rank(deg)) for deg in range(cell_complex.dimension() + 1)} + indices = [(deg, i) for deg in self._graded_indices for i in self._graded_indices[deg]] CombinatorialFreeModule.__init__(self, base_ring, indices, category=category) def basis(self, d=None): @@ -386,8 +384,7 @@ def _to_cycle_on_basis(self, i): \chi_(5, 6, 7, 8) """ vec = self.contraction().iota().in_degree(i[0]).column(i[1]) - chains = self.complex().n_chains(i[0], self.base_ring(), - cochains=self._cohomology) + chains = self.complex().n_chains(i[0], self.base_ring(), cochains=self._cohomology) return chains.from_vector(vec) def dual(self): @@ -409,13 +406,10 @@ def dual(self): """ if is_GF2(self.base_ring()): if self._cohomology: - return HomologyVectorSpaceWithBasis_mod2(self.base_ring(), - self.complex()) + return HomologyVectorSpaceWithBasis_mod2(self.base_ring(), self.complex()) return CohomologyRing_mod2(self.base_ring(), self.complex()) if self._cohomology: - return HomologyVectorSpaceWithBasis(self.base_ring(), - self.complex(), - not self._cohomology) + return HomologyVectorSpaceWithBasis(self.base_ring(), self.complex(), not self._cohomology) return CohomologyRing(self.base_ring(), self.complex()) def _test_duality(self, **options): @@ -575,6 +569,7 @@ class HomologyVectorSpaceWithBasis_mod2(HomologyVectorSpaceWithBasis): sage: x4 * Sq(3) 0 """ + def __init__(self, base_ring, cell_complex, category=None) -> None: """ Initialize ``self``. @@ -589,13 +584,8 @@ def __init__(self, base_ring, cell_complex, category=None) -> None: if not is_GF2(base_ring): raise ValueError category = Modules(base_ring).WithBasis().Graded().FiniteDimensional().or_subcategory(category) - category = Category.join((category, - LeftModules(SteenrodAlgebra(2)), - RightModules(SteenrodAlgebra(2)))) - HomologyVectorSpaceWithBasis.__init__(self, base_ring, - cell_complex, - cohomology=False, - category=category) + category = Category.join((category, LeftModules(SteenrodAlgebra(2)), RightModules(SteenrodAlgebra(2)))) + HomologyVectorSpaceWithBasis.__init__(self, base_ring, cell_complex, cohomology=False, category=category) class Element(HomologyVectorSpaceWithBasis.Element): @@ -692,8 +682,7 @@ def _acted_upon_(self, a, self_on_left): if not self_on_left: # i.e., module element on left a = a.antipode() P = self.parent() - return P._from_dict({x.support()[0]: self.eval(a * x) - for x in sorted(self.parent().dual().basis(m-n))}) + return P._from_dict({x.support()[0]: self.eval(a * x) for x in sorted(self.parent().dual().basis(m - n))}) class CohomologyRing(HomologyVectorSpaceWithBasis): @@ -730,6 +719,7 @@ class CohomologyRing(HomologyVectorSpaceWithBasis): sage: x * x -h^{4,0} """ + def __init__(self, base_ring, cell_complex, category=None) -> None: """ Initialize ``self``. @@ -869,7 +859,7 @@ def product_on_basis(self, li, ri): for gamma_index in H._graded_indices.get(deg_tot, []): gamma_coeff = base_ring.zero() for cell, coeff in H._to_cycle_on_basis((deg_tot, gamma_index)): - for (c, left_cell, right_cell) in scomplex.alexander_whitney(cell, deg_left): + for c, left_cell, right_cell in scomplex.alexander_whitney(cell, deg_left): if c: left = n_chains_left(left_cell) right = n_chains_right(right_cell) @@ -1003,6 +993,7 @@ class CohomologyRing_mod2(CohomologyRing): sage: x * Sq(3) h^{4,0} """ + def __init__(self, base_ring, cell_complex) -> None: """ Initialize ``self``. @@ -1016,9 +1007,7 @@ def __init__(self, base_ring, cell_complex) -> None: if not is_GF2(base_ring): raise ValueError("the base ring must be GF(2)") category = Algebras(base_ring).WithBasis().Graded().FiniteDimensional() - category = Category.join((category, - LeftModules(SteenrodAlgebra(2)), - RightModules(SteenrodAlgebra(2)))) + category = Category.join((category, LeftModules(SteenrodAlgebra(2)), RightModules(SteenrodAlgebra(2)))) CohomologyRing.__init__(self, base_ring, cell_complex, category=category) class Element(CohomologyRing.Element): @@ -1104,8 +1093,7 @@ def Sq(self, i): self = P.sum_of_terms(self.monomial_coefficients().items()) if not isinstance(scomplex, (SimplicialComplex, SimplicialSet_arbitrary)): print(scomplex, isinstance(scomplex, SimplicialComplex)) - raise NotImplementedError('Steenrod squares are not implemented for ' - 'this type of cell complex') + raise NotImplementedError('Steenrod squares are not implemented for ' 'this type of cell complex') scomplex = P.complex() base_ring = P.base_ring() if not is_GF2(base_ring): @@ -1141,12 +1129,11 @@ def Sq(self, i): n = j - i # Now assemble the indices over which the sums take place. # S(n) is defined to be floor((m+1)/2) + floor(n/2). - S_n = (m+1) // 2 + n // 2 + S_n = (m + 1) // 2 + n // 2 if n == 0: sums = [[S_n]] else: - sums = [[i_n] + l for i_n in range(S_n, m+1) - for l in sum_indices(n-1, i_n, S_n)] + sums = [[i_n] + l for i_n in range(S_n, m + 1) for l in sum_indices(n - 1, i_n, S_n)] # At this point, 'sums' is a list of lists of the form # [i_n, i_{n-1}, ..., i_0]. (It is reversed from the # obvious order because this is closer to the order in @@ -1192,10 +1179,7 @@ def Sq(self, i): for k in range(right_endpoint, -1, -1): right = scomplex.face(right, k) - if ((hasattr(left, 'is_nondegenerate') - and left.is_nondegenerate() - and right.is_nondegenerate()) - or not hasattr(left, 'is_nondegenerate')): + if (hasattr(left, 'is_nondegenerate') and left.is_nondegenerate() and right.is_nondegenerate()) or not hasattr(left, 'is_nondegenerate'): left = n_chains(left) right = n_chains(right) gamma_coeff += coeff * cycle.eval(left) * cycle.eval(right) @@ -1387,10 +1371,8 @@ def steenrod_module_map(self, deg_domain, deg_codomain, side='left'): # We built the matrix column by column, so now we take the # transpose. if side == 'left': - return matrix(base_ring, len(A_basis) * len(H_basis_dom), - len(H_basis_cod), entries).transpose() - return matrix(base_ring, len(A_basis) * len(H_basis_dom), - len(H_basis_cod), entries) + return matrix(base_ring, len(A_basis) * len(H_basis_dom), len(H_basis_cod), entries).transpose() + return matrix(base_ring, len(A_basis) * len(H_basis_dom), len(H_basis_cod), entries) def sum_indices(k, i_k_plus_one, S_k_plus_one): @@ -1427,11 +1409,10 @@ def sum_indices(k, i_k_plus_one, S_k_plus_one): sage: sum_indices(0, 4, 2) [[2]] """ - S_k = -S_k_plus_one + k//2 + (k+1)//2 + i_k_plus_one + S_k = -S_k_plus_one + k // 2 + (k + 1) // 2 + i_k_plus_one if k == 0: return [[S_k]] - return [[i_k] + l for i_k in range(S_k, i_k_plus_one) - for l in sum_indices(k-1, i_k, S_k)] + return [[i_k] + l for i_k in range(S_k, i_k_plus_one) for l in sum_indices(k - 1, i_k, S_k)] def is_GF2(R) -> bool: diff --git a/src/sage/homology/koszul_complex.py b/src/sage/homology/koszul_complex.py index 6ab88fbd36e..0164e6e96cb 100644 --- a/src/sage/homology/koszul_complex.py +++ b/src/sage/homology/koszul_complex.py @@ -1,6 +1,7 @@ """ Koszul Complexes """ + ######################################################################## # Copyright (C) 2014 Travis Scrimshaw # @@ -79,6 +80,7 @@ class KoszulComplex(ChainComplex_class, UniqueRepresentation): - :wikipedia:`Koszul_complex` """ + @staticmethod def __classcall_private__(cls, R=None, elements=None): """ @@ -134,19 +136,19 @@ def __init__(self, R, elements) -> None: diff = {} zero = R.zero() for i in I: - M = matrix(R, binomial(n, i), binomial(n, i+1), zero) + M = matrix(R, binomial(n, i), binomial(n, i + 1), zero) j = 0 - for comb in itertools.combinations(I, i+1): + for comb in itertools.combinations(I, i + 1): for k, val in enumerate(comb): - r = rank(comb[:k] + comb[k+1:], n, False) - M[r, j] = (-1)**k * elements[val] + r = rank(comb[:k] + comb[k + 1 :], n, False) + M[r, j] = (-1) ** k * elements[val] j += 1 M.set_immutable() - diff[i+1] = M + diff[i + 1] = M diff[0] = matrix(R, 0, 1, zero) diff[0].set_immutable() - diff[n+1] = matrix(R, 1, 0, zero) - diff[n+1].set_immutable() + diff[n + 1] = matrix(R, 1, 0, zero) + diff[n + 1].set_immutable() ChainComplex_class.__init__(self, ZZ, ZZ(-1), R, diff) def _repr_(self) -> str: diff --git a/src/sage/homology/matrix_utils.py b/src/sage/homology/matrix_utils.py index b44a25060d5..50cb9a7c069 100644 --- a/src/sage/homology/matrix_utils.py +++ b/src/sage/homology/matrix_utils.py @@ -5,6 +5,7 @@ with the differentials thought of as matrices. This module contains some utility functions for this purpose. """ + ######################################################################## # Copyright (C) 2013 John H. Palmieri # @@ -112,12 +113,12 @@ def dhsw_snf(mat, verbose=False): if not new_col.is_zero(): check_leading = True if not new_col.is_zero(): - new_mat.set_column(j-zero_cols, new_col.column(0)) + new_mat.set_column(j - zero_cols, new_col.column(0)) i = new_col.nonzero_positions_in_column(0)[0] if i in leading_positions: - leading_positions[i].append(j-zero_cols) + leading_positions[i].append(j - zero_cols) else: - leading_positions[i] = [j-zero_cols] + leading_positions[i] = [j - zero_cols] else: zero_cols += 1 # pass 2: @@ -151,9 +152,9 @@ def dhsw_snf(mat, verbose=False): unit, A, B = r.xgcd(-s) # unit ought to be 1 here jth_col = new_mat.column(j) nth_col = new_mat.column(n) - new_mat.set_column(j, r*jth_col + s*nth_col) - new_mat.set_column(n, B*jth_col + A*nth_col) - nth = B*jth + A*nth + new_mat.set_column(j, r * jth_col + s * nth_col) + new_mat.set_column(n, B * jth_col + A * nth_col) + nth = B * jth + A * nth jth = g # at this point, jth should divide nth quo = nth.divide_knowing_divisible_by(jth) @@ -191,14 +192,14 @@ def dhsw_snf(mat, verbose=False): if verbose: print("new matrix: %s by %s" % (new_mat.nrows(), new_mat.ncols())) if new_mat.is_sparse(): - ed = [1]*add_to_rank + new_mat.dense_matrix().elementary_divisors() + ed = [1] * add_to_rank + new_mat.dense_matrix().elementary_divisors() else: - ed = [1]*add_to_rank + new_mat.elementary_divisors() + ed = [1] * add_to_rank + new_mat.elementary_divisors() else: if verbose: print("new matrix: all pivots are 1 or -1") - ed = [1]*add_to_rank + ed = [1] * add_to_rank if len(ed) < rows: - return ed + [0]*(rows - len(ed)) + return ed + [0] * (rows - len(ed)) return ed[:rows] diff --git a/src/sage/interacts/all.py b/src/sage/interacts/all.py index c48e0cff2b5..d15f944c22f 100644 --- a/src/sage/interacts/all.py +++ b/src/sage/interacts/all.py @@ -21,5 +21,6 @@ from sage.interacts import statistics from sage.interacts import fractals from sage.interacts import algebra + lazy_import('sage.interacts.library', 'demo') del lazy_import diff --git a/src/sage/interacts/library.py b/src/sage/interacts/library.py index 38c9fc7b832..ad1851da9a4 100644 --- a/src/sage/interacts/library.py +++ b/src/sage/interacts/library.py @@ -89,9 +89,7 @@ ) -def library_interact( - decorator_target: Callable[..., Any] | None = None, **widgets: Callable[..., Any] -): +def library_interact(decorator_target: Callable[..., Any] | None = None, **widgets: Callable[..., Any]): r""" This is a decorator for using interacts in the Sage library. @@ -138,9 +136,7 @@ def library_interact( def decorator(f: Callable[..., Any]): @sage_wraps(f) def library_wrapper(): - widgets_constructed = { - key: constructor() for key, constructor in widgets.items() - } + widgets_constructed = {key: constructor() for key, constructor in widgets.items()} # This will display the interact, no need to return anything interact(f, **widgets_constructed) @@ -170,6 +166,7 @@ def html(obj):

Hello world

""" from sage.misc.html import html + pretty_print(html(obj)) @@ -232,9 +229,8 @@ def taylor_polynomial(title, f, order: int): ft = f.taylor(x, x0, order) pt = plot(ft, (-1, 5), color='green', thickness=2) html(r'$f(x)\;=\;%s$' % latex(f)) - html(r'$\hat{f}(x;%s)\;=\;%s+\mathcal{O}(x^{%s})$' % (x0, latex(ft), - order + 1)) - show(dot + p + pt, ymin=-.5, ymax=1) + html(r'$\hat{f}(x;%s)\;=\;%s+\mathcal{O}(x^{%s})$' % (x0, latex(ft), order + 1)) + show(dot + p + pt, ymin=-0.5, ymax=1) @library_interact( @@ -243,9 +239,7 @@ def taylor_polynomial(title, f, order: int): g=lambda: input_box(default='x^2', label="$g(x)=$"), interval=lambda: range_slider(-10, 10, default=(0, 3), label='Interval'), x_range=lambda: range_slider(-10, 10, default=(0, 3), label="plot range (x)"), - selection=lambda: selector( - ["f", "g", "f and g", "f - g"], default="f and g", label="Select" - ), + selection=lambda: selector(["f", "g", "f and g", "f - g"], default="f and g", label="Select"), ) def definite_integral(title, f, g, interval, x_range, selection): r""" @@ -291,12 +285,7 @@ def definite_integral(title, f, g, interval, x_range, selection): # Color and calculate the area between f and the horizontal axis. if selection == "f" or selection == "f and g": f_plot += plot(f(x), x, interval, color='blue', fill=True, fillcolor='blue', fillalpha=0.15) - text += r"$\int_{%.2f}^{%.2f}(\color{Blue}{f(x)})\,\mathrm{d}x=\int_{%.2f}^{%.2f}(%s)\,\mathrm{d}x=%.2f$" % ( - interval[0], interval[1], - interval[0], interval[1], - latex(f(x)), - f(x).nintegrate(x, interval[0], interval[1])[0] - ) + text += r"$\int_{%.2f}^{%.2f}(\color{Blue}{f(x)})\,\mathrm{d}x=\int_{%.2f}^{%.2f}(%s)\,\mathrm{d}x=%.2f$" % (interval[0], interval[1], interval[0], interval[1], latex(f(x)), f(x).nintegrate(x, interval[0], interval[1])[0]) if selection == "f and g": text += r"
" @@ -305,24 +294,14 @@ def definite_integral(title, f, g, interval, x_range, selection): if selection == "g" or selection == "f and g": g_plot = plot(g(x), x, x_range, color='green', thickness=1.5) g_plot += plot(g(x), x, interval, color='green', fill=True, fillcolor='yellow', fillalpha=0.5) - text += r"$\int_{%.2f}^{%.2f}(\color{Green}{g(x)})\,\mathrm{d}x=\int_{%.2f}^{%.2f}(%s)\,\mathrm{d}x=%.2f$" % ( - interval[0], interval[1], - interval[0], interval[1], - latex(g(x)), - g(x).nintegrate(x, interval[0], interval[1])[0] - ) + text += r"$\int_{%.2f}^{%.2f}(\color{Green}{g(x)})\,\mathrm{d}x=\int_{%.2f}^{%.2f}(%s)\,\mathrm{d}x=%.2f$" % (interval[0], interval[1], interval[0], interval[1], latex(g(x)), g(x).nintegrate(x, interval[0], interval[1])[0]) # Plot function f-g. Also color and calculate the area between f-g and the horizontal axis. if selection == "f - g": g_plot = plot(g(x), x, x_range, color='green', thickness=1.5) g_plot += plot(g(x), x, interval, color='green', fill=f(x), fillcolor='red', fillalpha=0.15) - h_plot = plot(f(x)-g(x), x, interval, color='red', thickness=1.5, fill=True, fillcolor='red', fillalpha=0.15) - text = r"$\int_{%.2f}^{%.2f}(\color{Red}{f(x)-g(x)})\,\mathrm{d}x=\int_{%.2f}^{%.2f}(%s)\,\mathrm{d}x=%.2f$" % ( - interval[0], interval[1], - interval[0], interval[1], - latex(f(x)-g(x)), - (f(x)-g(x)).nintegrate(x, interval[0], interval[1])[0] - ) + h_plot = plot(f(x) - g(x), x, interval, color='red', thickness=1.5, fill=True, fillcolor='red', fillalpha=0.15) + text = r"$\int_{%.2f}^{%.2f}(\color{Red}{f(x)-g(x)})\,\mathrm{d}x=\int_{%.2f}^{%.2f}(%s)\,\mathrm{d}x=%.2f$" % (interval[0], interval[1], interval[0], interval[1], latex(f(x) - g(x)), (f(x) - g(x)).nintegrate(x, interval[0], interval[1])[0]) show(f_plot + g_plot + h_plot, gridlines=True) html(text) @@ -364,7 +343,7 @@ def function_derivative(title, function, x_range, y_range): df = derivative(f, x) ddf = derivative(df, x) plots = plot(f(x), x_range, thickness=1.5) + plot(df(x), x_range, color='green') + plot(ddf(x), x_range, color='red') - if y_range == (0,0): + if y_range == (0, 0): show(plots, xmin=x_range[0], xmax=x_range[1]) else: show(plots, xmin=x_range[0], xmax=x_range[1], ymin=y_range[0], ymax=y_range[1]) @@ -409,33 +388,34 @@ def difference_quotient(title, f, interval, a, x0): x0: IntSlider(value=2, description='$x_0$ (start point)', max=10) """ html('

Difference Quotient

') - html('
\ + html( + '' - ) + ) x = SR.var('x') f = symbolic_expression(f).function(x) fmax = f.find_local_maximum(interval[0], interval[1])[0] fmin = f.find_local_minimum(interval[0], interval[1])[0] f_height = fmax - fmin - measure_y = fmin - 0.1*f_height + measure_y = fmin - 0.1 * f_height measure_0 = line2d([(x0, measure_y), (a, measure_y)], rgbcolor='black') - measure_1 = line2d([(x0, measure_y + 0.02*f_height), (x0, measure_y-0.02*f_height)], rgbcolor='black') - measure_2 = line2d([(a, measure_y + 0.02*f_height), (a, measure_y-0.02*f_height)], rgbcolor='black') - text_x0 = text("x0", (x0, measure_y - 0.05*f_height), rgbcolor='black') - text_a = text("a", (a, measure_y - 0.05*f_height), rgbcolor='black') + measure_1 = line2d([(x0, measure_y + 0.02 * f_height), (x0, measure_y - 0.02 * f_height)], rgbcolor='black') + measure_2 = line2d([(a, measure_y + 0.02 * f_height), (a, measure_y - 0.02 * f_height)], rgbcolor='black') + text_x0 = text("x0", (x0, measure_y - 0.05 * f_height), rgbcolor='black') + text_a = text("a", (a, measure_y - 0.05 * f_height), rgbcolor='black') measure = measure_0 + measure_1 + measure_2 + text_x0 + text_a - tanf = symbolic_expression((f(x0)-f(a))*(x-a)/(x0-a)+f(a)).function(x) + tanf = symbolic_expression((f(x0) - f(a)) * (x - a) / (x0 - a) + f(a)).function(x) fplot = plot(f(x), x, interval[0], interval[1]) tanplot = plot(tanf(x), x, interval[0], interval[1], rgbcolor='#FF0000') points = point([(x0, f(x0)), (a, f(a))], pointsize=20, rgbcolor='#005500') dashline = line2d([(x0, f(x0)), (x0, f(a)), (a, f(a))], rgbcolor='#005500', linestyle='--') html('

Difference Quotient

') - show(fplot + tanplot + points + dashline + measure, xmin=interval[0], xmax=interval[1], ymin=fmin-0.2*f_height, ymax=fmax) + show(fplot + tanplot + points + dashline + measure, xmin=interval[0], xmax=interval[1], ymin=fmin - 0.2 * f_height, ymax=fmax) html(r"
$\text{Line's equation:}$") html(r"$y = %s$
" % tanf(x)) html(r"$\text{Slope:}$") @@ -472,24 +452,24 @@ def quadratic_equation(A, B, C): C: IntSlider(value=-2, description='C', max=7, min=-7) """ x = SR.var('x') - f = symbolic_expression(A*x**2 + B*x + C).function(x) + f = symbolic_expression(A * x**2 + B * x + C).function(x) html('

The Solutions of the Quadratic Equation

') html("$%s = 0$" % f(x)) show(plot(f(x), x, (-10, 10), ymin=-10, ymax=10), aspect_ratio=1, figsize=4) - d = B**2 - 4*A*C + d = B**2 - 4 * A * C if d < 0: color = "Red" sol = r"\text{solution} \in \mathbb{C}" elif d == 0: color = "Blue" - sol = -B/(2*A) + sol = -B / (2 * A) else: color = "Green" - a = (-B+sqrt(B**2-4*A*C))/(2*A) - b = (-B-sqrt(B**2-4*A*C))/(2*A) + a = (-B + sqrt(B**2 - 4 * A * C)) / (2 * A) + b = (-B - sqrt(B**2 - 4 * A * C)) / (2 * A) sol = r"\begin{cases}%s\\%s\end{cases}" % (latex(a), latex(b)) if B < 0: @@ -499,10 +479,8 @@ def quadratic_equation(A, B, C): dis2 = r"\color{%s}{%s}" % (color, d) html("$Ax^2 + Bx + C = 0$") - calc = r"$x = \frac{-B\pm\sqrt{B^2-4AC}}{2A} = " + \ - r"\frac{-%s\pm\sqrt{%s}}{2*%s} = " + \ - r"\frac{-%s\pm\sqrt{%s}}{%s} = %s$" - html(calc % (B, dis1, A, B, dis2, (2*A), sol)) + calc = r"$x = \frac{-B\pm\sqrt{B^2-4AC}}{2A} = " + r"\frac{-%s\pm\sqrt{%s}}{2*%s} = " + r"\frac{-%s\pm\sqrt{%s}}{%s} = %s$" + html(calc % (B, dis1, A, B, dis2, (2 * A), sol)) @library_interact( @@ -540,12 +518,12 @@ def trigonometric_properties_triangle(a0, a1, a2): def distance(x1_y1, x2_y2): (x1, y1) = x1_y1 (x2, y2) = x2_y2 - return sqrt((x2-x1)**2 + (y2-y1)**2) + return sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) # Returns an angle (in radians) when sides a and b # are adjacent and the side c is opposite to the angle def angle(a, b, c): - a,b,c = map(float,[a,b,c]) + a, b, c = map(float, [a, b, c]) return acos(0.5 * (b**2 + c**2 - a**2) / (b * c)) # Returns the area of a triangle when an angle alpha @@ -553,7 +531,7 @@ def angle(a, b, c): def area(alpha, a, b): return 0.5 * a * b * sin(alpha) - xy = [0]*3 + xy = [0] * 3 html('

Trigonometric Properties of a Triangle

') # Coordinates of the angles a = [math.radians(float(x)) for x in [a0, a1, a2]] @@ -576,14 +554,13 @@ def area(alpha, a, b): triangle_points = point(xy, pointsize=30) # Labels of the angles drawn in a distance from points - a_label = text("A", (xy[0][0]*1.07, xy[0][1]*1.07)) - b_label = text("B", (xy[1][0]*1.07, xy[1][1]*1.07)) - c_label = text("C", (xy[2][0]*1.07, xy[2][1]*1.07)) + a_label = text("A", (xy[0][0] * 1.07, xy[0][1] * 1.07)) + b_label = text("B", (xy[1][0] * 1.07, xy[1][1] * 1.07)) + c_label = text("C", (xy[2][0] * 1.07, xy[2][1] * 1.07)) labels = a_label + b_label + c_label show(unit_circle + triangle + triangle_points + labels, figsize=[5, 5], xmin=-1, xmax=1, ymin=-1, ymax=1) - html(r"$\angle A = {%.3f}^{\circ},$ $\angle B = {%.3f}^{\circ},$ $\angle C = {%.3f}^{\circ}$" - % (math.degrees(ak[0]), math.degrees(ak[1]), math.degrees(ak[2]))) + html(r"$\angle A = {%.3f}^{\circ},$ $\angle B = {%.3f}^{\circ},$ $\angle C = {%.3f}^{\circ}$" % (math.degrees(ak[0]), math.degrees(ak[1]), math.degrees(ak[2]))) html(r"$AB = %.6f$, $BC = %.6f$, $CA = %.6f$" % (al[2], al[0], al[1])) html(r"Area of triangle $ABC = %.6f$" % A) @@ -616,8 +593,10 @@ def unit_circle(function, x): """ xy = (cos(x), sin(x)) t = SR.var('t') - html('
Lines of the same color have\ - the same length
') + html( + '
Lines of the same color have\ + the same length
' + ) # Unit Circle C = circle((0, 0), 1, figsize=[5, 5], aspect_ratio=1) @@ -634,15 +613,15 @@ def unit_circle(function, x): # Sine if function == 0: - Gf = plot(sin(t), t, 0, 2*pi, axes_labels=("x", "sin(x)")) + Gf = plot(sin(t), t, 0, 2 * pi, axes_labels=("x", "sin(x)")) Gf_point = point((x, sin(x)), pointsize=30, rgbcolor='red') - Gf_line = line([(x, 0),(x, sin(x))], rgbcolor='red') + Gf_line = line([(x, 0), (x, sin(x))], rgbcolor='red') Cf_point = point((0, xy[1]), pointsize=40, rgbcolor='red') Cf_line1 = line([(0, 0), (0, xy[1])], rgbcolor='red', thickness=3) Cf_line2 = line([(0, xy[1]), (xy[0], xy[1])], rgbcolor='purple', linestyle='--') # Cosine elif function == 1: - Gf = plot(cos(t), t, 0, 2*pi, axes_labels=("x", "cos(x)")) + Gf = plot(cos(t), t, 0, 2 * pi, axes_labels=("x", "cos(x)")) Gf_point = point((x, cos(x)), pointsize=30, rgbcolor='red') Gf_line = line([(x, 0), (x, cos(x))], rgbcolor='red') Cf_point = point((xy[0], 0), pointsize=40, rgbcolor='red') @@ -650,7 +629,7 @@ def unit_circle(function, x): Cf_line2 = line([(xy[0], 0), (xy[0], xy[1])], rgbcolor='purple', linestyle='--') # Tangent else: - Gf = plot(tan(t), t, 0, 2*pi, ymin=-8, ymax=8, axes_labels=("x", "tan(x)")) + Gf = plot(tan(t), t, 0, 2 * pi, ymin=-8, ymax=8, axes_labels=("x", "tan(x)")) Gf_point = point((x, tan(x)), pointsize=30, rgbcolor='red') Gf_line = line([(x, 0), (x, tan(x))], rgbcolor='red') Cf_point = point((1, tan(x)), pointsize=40, rgbcolor='red') @@ -724,35 +703,36 @@ def special_points( show_euler: Checkbox(value=False, description="Euler's Line") """ import math + # Return the intersection point of the bisector of the angle <(A[a],A[c],A[b]) and the unit circle. Angles given in radians. def half(A, a, b, c): if (A[a] < A[b] and (A[c] < A[a] or A[c] > A[b])) or (A[a] > A[b] and (A[c] > A[a] or A[c] < A[b])): p = A[a] + 0.5 * (A[b] - A[a]) else: - p = A[b] + 0.5 * (2*pi - (A[b]-A[a])) + p = A[b] + 0.5 * (2 * pi - (A[b] - A[a])) return (math.cos(p), math.sin(p)) # Returns the distance between points (x1,y1) and (x2,y2) def distance(x1_y1, x2_y2): (x1, y1) = x1_y1 (x2, y2) = x2_y2 - return math.sqrt((x2-x1)**2 + (y2-y1)**2) + return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) # Returns the line (graph) going through points (x1,y1) and (x2,y2) def line_to_points(x1_y1, x2_y2, **plot_kwargs): (x1, y1) = x1_y1 (x2, y2) = x2_y2 - return plot((y2-y1) / (x2-x1) * (x-x1) + y1, (x,-3,3), **plot_kwargs) + return plot((y2 - y1) / (x2 - x1) * (x - x1) + y1, (x, -3, 3), **plot_kwargs) # Coordinates of the angles a = [math.radians(float(x)) for x in [a0, a1, a2]] xy = [(math.cos(a[i]), math.sin(a[i])) for i in range(3)] # Labels of the angles drawn in a distance from points - a_label = text("A", (xy[0][0]*1.07, xy[0][1]*1.07)) - b_label = text("B", (xy[1][0]*1.07, xy[1][1]*1.07)) - c_label = text("C", (xy[2][0]*1.07, xy[2][1]*1.07)) + a_label = text("A", (xy[0][0] * 1.07, xy[0][1] * 1.07)) + b_label = text("B", (xy[1][0] * 1.07, xy[1][1] * 1.07)) + c_label = text("C", (xy[2][0] * 1.07, xy[2][1] * 1.07)) labels = a_label + b_label + c_label C = circle((0, 0), 1, aspect_ratio=1) @@ -765,18 +745,11 @@ def line_to_points(x1_y1, x2_y2, **plot_kwargs): ad = [distance(xy[1], xy[2]), distance(xy[2], xy[0]), distance(xy[0], xy[1])] # Midpoints of edges (bc, ca, ab) - a_middle = [ - (0.5 * (xy[1][0] + xy[2][0]), 0.5 * (xy[1][1] + xy[2][1])), - (0.5 * (xy[2][0] + xy[0][0]), 0.5 * (xy[2][1] + xy[0][1])), - (0.5 * (xy[0][0] + xy[1][0]), 0.5 * (xy[0][1] + xy[1][1])) - ] + a_middle = [(0.5 * (xy[1][0] + xy[2][0]), 0.5 * (xy[1][1] + xy[2][1])), (0.5 * (xy[2][0] + xy[0][0]), 0.5 * (xy[2][1] + xy[0][1])), (0.5 * (xy[0][0] + xy[1][0]), 0.5 * (xy[0][1] + xy[1][1]))] # Incircle perimeter = float(ad[0] + ad[1] + ad[2]) - incircle_center = ( - (ad[0]*xy[0][0] + ad[1]*xy[1][0] + ad[2]*xy[2][0]) / perimeter, - (ad[0]*xy[0][1] + ad[1]*xy[1][1] + ad[2]*xy[2][1]) / perimeter - ) + incircle_center = ((ad[0] * xy[0][0] + ad[1] * xy[1][0] + ad[2] * xy[2][0]) / perimeter, (ad[0] * xy[0][1] + ad[1] * xy[1][1] + ad[2] * xy[2][1]) / perimeter) if show_incircle: s = 0.5 * perimeter @@ -800,11 +773,7 @@ def line_to_points(x1_y1, x2_y2, **plot_kwargs): a_median = line([xy[0], a_middle[0]], rgbcolor='green', alpha=0.6) b_median = line([xy[1], a_middle[1]], rgbcolor='green', alpha=0.6) c_median = line([xy[2], a_middle[2]], rgbcolor='green', alpha=0.6) - median_point = point( - ( - (xy[0][0]+xy[1][0]+xy[2][0])/3.0, - (xy[0][1]+xy[1][1]+xy[2][1])/3.0 - ), rgbcolor='green', pointsize=28) + median_point = point(((xy[0][0] + xy[1][0] + xy[2][0]) / 3.0, (xy[0][1] + xy[1][1] + xy[2][1]) / 3.0), rgbcolor='green', pointsize=28) median_graph = a_median + b_median + c_median + median_point else: median_graph = Graphics() @@ -823,11 +792,11 @@ def line_to_points(x1_y1, x2_y2, **plot_kwargs): if show_alt: xA, xB, xC = xy[0][0], xy[1][0], xy[2][0] yA, yB, yC = xy[0][1], xy[1][1], xy[2][1] - a_alt = plot(((xC-xB)*x+(xB-xC)*xA)/(yB-yC)+yA, (x,-3,3), rgbcolor='brown', alpha=0.6) - b_alt = plot(((xA-xC)*x+(xC-xA)*xB)/(yC-yA)+yB, (x,-3,3), rgbcolor='brown', alpha=0.6) - c_alt = plot(((xB-xA)*x+(xA-xB)*xC)/(yA-yB)+yC, (x,-3,3), rgbcolor='brown', alpha=0.6) - alt_lx = (xA*xB*(yA-yB)+xB*xC*(yB-yC)+xC*xA*(yC-yA)-(yA-yB)*(yB-yC)*(yC-yA))/(xC*yB-xB*yC+xA*yC-xC*yA+xB*yA-xA*yB) - alt_ly = (yA*yB*(xA-xB)+yB*yC*(xB-xC)+yC*yA*(xC-xA)-(xA-xB)*(xB-xC)*(xC-xA))/(yC*xB-yB*xC+yA*xC-yC*xA+yB*xA-yA*xB) + a_alt = plot(((xC - xB) * x + (xB - xC) * xA) / (yB - yC) + yA, (x, -3, 3), rgbcolor='brown', alpha=0.6) + b_alt = plot(((xA - xC) * x + (xC - xA) * xB) / (yC - yA) + yB, (x, -3, 3), rgbcolor='brown', alpha=0.6) + c_alt = plot(((xB - xA) * x + (xA - xB) * xC) / (yA - yB) + yC, (x, -3, 3), rgbcolor='brown', alpha=0.6) + alt_lx = (xA * xB * (yA - yB) + xB * xC * (yB - yC) + xC * xA * (yC - yA) - (yA - yB) * (yB - yC) * (yC - yA)) / (xC * yB - xB * yC + xA * yC - xC * yA + xB * yA - xA * yB) + alt_ly = (yA * yB * (xA - xB) + yB * yC * (xB - xC) + yC * yA * (xC - xA) - (xA - xB) * (xB - xC) * (xC - xA)) / (yC * xB - yB * xC + yA * xC - yC * xA + yB * xA - yA * xB) alt_intersection = point((alt_lx, alt_ly), rgbcolor='brown', pointsize=28) alt_graph = a_alt + b_alt + c_alt + alt_intersection else: @@ -835,31 +804,16 @@ def line_to_points(x1_y1, x2_y2, **plot_kwargs): # Euler's Line if show_euler: - euler_graph = line_to_points( - (0, 0), - ( - (xy[0][0]+xy[1][0]+xy[2][0])/3.0, - (xy[0][1]+xy[1][1]+xy[2][1])/3.0 - ), - rgbcolor='purple', - thickness=2, - alpha=0.7 - ) + euler_graph = line_to_points((0, 0), ((xy[0][0] + xy[1][0] + xy[2][0]) / 3.0, (xy[0][1] + xy[1][1] + xy[2][1]) / 3.0), rgbcolor='purple', thickness=2, alpha=0.7) else: euler_graph = Graphics() - show( - C + triangle + triangle_points + labels + ab_graph + median_graph + - pb_graph + alt_graph + incircle_graph + euler_graph, - figsize=[5,5], xmin=-1, xmax=1, ymin=-1, ymax=1 - ) + show(C + triangle + triangle_points + labels + ab_graph + median_graph + pb_graph + alt_graph + incircle_graph + euler_graph, figsize=[5, 5], xmin=-1, xmax=1, ymin=-1, ymax=1) @library_interact( n=lambda: slider(2, 10000, 100, default=1000, label="Number of Tosses"), - interval=lambda: range_slider( - 0.0, 1.0, default=(0.45, 0.55), label="Plotting range (y)" - ), + interval=lambda: range_slider(0.0, 1.0, default=(0.45, 0.55), label="Plotting range (y)"), ) def coin(n, interval): r""" @@ -890,11 +844,12 @@ def coin(n, interval): interval: FloatRangeSlider(value=(0.45, 0.55), description='Plotting range (y)', max=1.0) """ from random import random + c = [] k = 0.0 for i in range(1, n + 1): k += random() - c.append((i, k/i)) + c.append((i, k / i)) show(point(c[1:], gridlines=[None, [0.5]], pointsize=1), ymin=interval[0], ymax=interval[1]) @@ -932,12 +887,13 @@ def bisection_method(title, f, interval, d, maxn): d: IntSlider(value=3, description='10^-d precision', max=16, min=1) maxn: IntSlider(value=10, description='max iterations', max=15) """ + def _bisection_method(f, a, b, maxn, eps): intervals = [(a, b)] round = 1 two = float(2) while True: - c = (b+a)/two + c = (b + a) / two if abs(f(c)) < h or round >= maxn: break fa = f(a) @@ -945,12 +901,12 @@ def _bisection_method(f, a, b, maxn, eps): fc = f(c) if abs(fc) < eps: return c, intervals - if fa*fc < 0: + if fa * fc < 0: b = c - elif fc*fb < 0: + elif fc * fb < 0: a = c else: - raise ValueError("f must have a sign change in the interval (%s,%s)" % (a,b)) + raise ValueError("f must have a sign change in the interval (%s,%s)" % (a, b)) intervals.append((a, b)) round += 1 return c, intervals @@ -958,7 +914,7 @@ def _bisection_method(f, a, b, maxn, eps): x = SR.var('x') f = symbolic_expression(f).function(x) a, b = interval - h = 10**(-d) + h = 10 ** (-d) try: c, intervals = _bisection_method(f, float(a), float(b), maxn, h) except ValueError: @@ -970,10 +926,10 @@ def _bisection_method(f, a, b, maxn, eps): html(r"${f(c) = }%s" % latex(f(c))) html(r"$%s \text{ iterations}" % len(intervals)) P = plot(f, a, b, color='red') - k = (P.ymax() - P.ymin()) / (1.5*len(intervals)) - L = sum(line([(c,k*i), (d,k*i)]) for i, (c,d) in enumerate(intervals) ) - L += sum(line([(c,k*i-k/4), (c,k*i+k/4)]) for i, (c,d) in enumerate(intervals) ) - L += sum(line([(d,k*i-k/4), (d,k*i+k/4)]) for i, (c,d) in enumerate(intervals) ) + k = (P.ymax() - P.ymin()) / (1.5 * len(intervals)) + L = sum(line([(c, k * i), (d, k * i)]) for i, (c, d) in enumerate(intervals)) + L += sum(line([(c, k * i - k / 4), (c, k * i + k / 4)]) for i, (c, d) in enumerate(intervals)) + L += sum(line([(d, k * i - k / 4), (d, k * i + k / 4)]) for i, (c, d) in enumerate(intervals)) show(P + L, xmin=a, xmax=b) @@ -1012,23 +968,24 @@ def secant_method(title, f, interval, d, maxn): d: IntSlider(value=3, description='10^-d precision', max=16, min=1) maxn: IntSlider(value=10, description='max iterations', max=15) """ + def _secant_method(f, a, b, maxn, h): - intervals = [(a,b)] + intervals = [(a, b)] round = 1 while True: - c = b-(b-a)*f(b)/(f(b)-f(a)) + c = b - (b - a) * f(b) / (f(b) - f(a)) if abs(f(c)) < h or round >= maxn: break a, b = b, c - intervals.append((a,b)) + intervals.append((a, b)) round += 1 return c, intervals x = SR.var('x') f = symbolic_expression(f).function(x) a, b = interval - h = 10**(-d) - if float(f(a)*f(b)) > 0: + h = 10 ** (-d) + if float(f(a) * f(b)) > 0: print("f must have opposite sign at the endpoints of the interval") show(plot(f, a, b, color='red'), xmin=a, xmax=b) else: @@ -1038,11 +995,11 @@ def _secant_method(f, a, b, maxn, h): html(r"${f(c) = }%s" % latex(f(c))) html(r"$%s \text{ iterations}" % len(intervals)) P = plot(f, a, b, color='red') - k = (P.ymax() - P.ymin()) / (1.5*len(intervals)) - L = sum(line([(c,k*i), (d,k*i)]) for i, (c,d) in enumerate(intervals) ) - L += sum(line([(c,k*i-k/4), (c,k*i+k/4)]) for i, (c,d) in enumerate(intervals) ) - L += sum(line([(d,k*i-k/4), (d,k*i+k/4)]) for i, (c,d) in enumerate(intervals) ) - S = sum(line([(c,f(c)), (d,f(d)), (d-(d-c)*f(d)/(f(d)-f(c)), 0)], color='green') for (c, d) in intervals) + k = (P.ymax() - P.ymin()) / (1.5 * len(intervals)) + L = sum(line([(c, k * i), (d, k * i)]) for i, (c, d) in enumerate(intervals)) + L += sum(line([(c, k * i - k / 4), (c, k * i + k / 4)]) for i, (c, d) in enumerate(intervals)) + L += sum(line([(d, k * i - k / 4), (d, k * i + k / 4)]) for i, (c, d) in enumerate(intervals)) + S = sum(line([(c, f(c)), (d, f(d)), (d - (d - c) * f(d) / (f(d) - f(c)), 0)], color='green') for (c, d) in intervals) show(P + L + S, xmin=a, xmax=b) @@ -1087,13 +1044,14 @@ def newton_method(title, f, c, d, maxn, interval, list_steps): interval: IntRangeSlider(value=(0, 6), description='Interval', max=10, min=-10) list_steps: Checkbox(value=False, description='List steps') """ + def _newton_method(f, c, maxn, h): midpoints = [c] round = 1 while True: - c = c-f(c)/f.derivative(x)(x=c) + c = c - f(c) / f.derivative(x)(x=c) midpoints.append(c) - if f(c-h)*f(c+h) < 0 or round == maxn: + if f(c - h) * f(c + h) < 0 or round == maxn: break round += 1 return c, midpoints @@ -1101,7 +1059,7 @@ def _newton_method(f, c, maxn, h): x = SR.var('x') f = symbolic_expression(f).function(x) a, b = interval - h = 10**(-d) + h = 10 ** (-d) c, midpoints = _newton_method(f, float(c), maxn, 0.5 * h) html(r"$\text{Precision } 2h = %s$" % latex(float(h))) html(r"${c = }%s$" % c) @@ -1110,13 +1068,13 @@ def _newton_method(f, c, maxn, h): if list_steps: s = [["$n$", "$x_n$", "$f(x_n)$", r"$f(x_n-h)\,f(x_n+h)$"]] for i, c in enumerate(midpoints): - s.append([i+1, c, f(c), (c-h)*f(c+h)]) + s.append([i + 1, c, f(c), (c - h) * f(c + h)]) pretty_print(table(s, header_row=True)) else: P = plot(f, x, interval, color='blue') L = sum(line([(c, 0), (c, f(c))], color='green') for c in midpoints[:-1]) for i in range(len(midpoints) - 1): - L += line([(midpoints[i], f(midpoints[i])), (midpoints[i+1], 0)], color='red') + L += line([(midpoints[i], f(midpoints[i])), (midpoints[i + 1], 0)], color='red') show(P + L, xmin=interval[0], xmax=interval[1], ymin=P.ymin(), ymax=P.ymax()) @@ -1131,13 +1089,9 @@ def _newton_method(f, c, maxn, h): ), interval_s=lambda: range_slider(-10, 10, default=(0, 8), label="slider: "), interval_g=lambda: input_grid(1, 2, default=[[0, 8]], label="keyboard: "), - output_form=lambda: selector( - ["traditional", "table", "none"], label="Computations form", buttons=True - ), + output_form=lambda: selector(["traditional", "table", "none"], label="Computations form", buttons=True), ) -def trapezoid_integration( - title, f, n, interval_input, interval_s, interval_g, output_form -): +def trapezoid_integration(title, f, n, interval_input, interval_s, interval_g, output_form): r""" Interact explaining the trapezoid method for definite integrals. @@ -1177,51 +1131,36 @@ def trapezoid_integration( interval = interval_s else: interval = interval_g[0] - h = float(interval[1]-interval[0])/n + h = float(interval[1] - interval[0]) / n x = SR.var('x') f = symbolic_expression(f).function(x) trapezoids = Graphics() for i in range(n): - xi = interval[0] + i*h + xi = interval[0] + i * h yi = f(xi) - trapezoids += line([[xi, 0], [xi, yi], [xi + h, f(xi + h)],[xi + h, 0],[xi, 0]], rgbcolor=(1, 0, 0)) + trapezoids += line([[xi, 0], [xi, yi], [xi + h, f(xi + h)], [xi + h, 0], [xi, 0]], rgbcolor=(1, 0, 0)) xs.append(xi) ys.append(yi) xs.append(xi + h) ys.append(f(xi + h)) html(r'Function $f(x)=%s$' % latex(f(x))) - show(plot(f, interval[0], interval[1]) + trapezoids, - xmin=interval[0], xmax=interval[1]) + show(plot(f, interval[0], interval[1]) + trapezoids, xmin=interval[0], xmax=interval[1]) numeric_value = integral_numerical(f, interval[0], interval[1])[0] - approx = h * (ys[0]/2 + sum([ys[i] for i in range(1,n)]) + ys[n]/2) + approx = h * (ys[0] / 2 + sum([ys[i] for i in range(1, n)]) + ys[n] / 2) - html(r'Integral value to seven decimal places is: $\displaystyle\int_{%.2f}^{%.2f} {f(x) \, \mathrm{d}x} = %.6f$' % ( - interval[0], interval[1], N(numeric_value, digits=7)) - ) + html(r'Integral value to seven decimal places is: $\displaystyle\int_{%.2f}^{%.2f} {f(x) \, \mathrm{d}x} = %.6f$' % (interval[0], interval[1], N(numeric_value, digits=7))) if output_form == 'traditional': - sum_formula_html = r"\frac {d}{2} \cdot \left[f(x_0) + %s + f(x_{%s})\right]" % ( - ' + '.join([ "2 f(x_{%s})" % i for i in range(1,n)]), - n - ) - sum_placement_html = r"\frac{%.2f}{2} \cdot \left[f(%.2f) + %s + f(%.2f)\right]" % ( - h, - N(xs[0], digits=5), - ' + '.join([ "2 f(%.2f)" % N(i, digits=5) for i in xs[1:-1]]), - N(xs[n], digits=5) - ) - sum_values_html = r"\frac{%.2f}{2} \cdot \left[%.2f + %s + %.2f\right]" % ( - h, - N(ys[0], digits=5), - ' + '.join([ r"2\cdot %.2f" % N(i, digits=5) for i in ys[1:-1]]), - N(ys[n], digits=5) - ) - - html(r''' + sum_formula_html = r"\frac {d}{2} \cdot \left[f(x_0) + %s + f(x_{%s})\right]" % (' + '.join(["2 f(x_{%s})" % i for i in range(1, n)]), n) + sum_placement_html = r"\frac{%.2f}{2} \cdot \left[f(%.2f) + %s + f(%.2f)\right]" % (h, N(xs[0], digits=5), ' + '.join(["2 f(%.2f)" % N(i, digits=5) for i in xs[1:-1]]), N(xs[n], digits=5)) + sum_values_html = r"\frac{%.2f}{2} \cdot \left[%.2f + %s + %.2f\right]" % (h, N(ys[0], digits=5), ' + '.join([r"2\cdot %.2f" % N(i, digits=5) for i in ys[1:-1]]), N(ys[n], digits=5)) + + html( + r'''
\begin{align*} \int_{%.2f}^{%.2f} {f(x) \, \mathrm{d}x} @@ -1231,19 +1170,17 @@ def trapezoid_integration( & = %s \end{align*}
- ''' % ( - interval[0], interval[1], - sum_formula_html, sum_placement_html, sum_values_html, - N(approx, digits=7) - )) + ''' + % (interval[0], interval[1], sum_formula_html, sum_placement_html, sum_values_html, N(approx, digits=7)) + ) elif output_form == 'table': s = [['$i$', '$x_i$', '$f(x_i)$', '$m$', r'$m\cdot f(x_i)$']] - for i in range(n+1): + for i in range(n + 1): if i == 0 or i == n: j = 1 else: j = 2 - s.append([i, xs[i], ys[i],j,N(j*ys[i])]) + s.append([i, xs[i], ys[i], j, N(j * ys[i])]) pretty_print(table(s, header_row=True)) @@ -1258,9 +1195,7 @@ def trapezoid_integration( ), interval_s=lambda: range_slider(-10, 10, default=(0, 10), label="slider: "), interval_g=lambda: input_grid(1, 2, default=[[0, 10]], label="keyboard: "), - output_form=lambda: selector( - ["traditional", "table", "none"], label="Computations form", buttons=True - ), + output_form=lambda: selector(["traditional", "table", "none"], label="Computations form", buttons=True), ) def simpson_integration( title, @@ -1313,65 +1248,49 @@ def simpson_integration( def parabola(a, b, c): from sage.symbolic.relation import solve + A, B, C = SR.var("A, B, C") - K = solve([A*a[0]**2+B*a[0]+C == a[1], A*b[0]**2+B*b[0]+C == b[1], A*c[0]**2+B*c[0]+C == c[1]], [A, B, C], solution_dict=True)[0] - f = K[A]*x**2+K[B]*x+K[C] + K = solve([A * a[0] ** 2 + B * a[0] + C == a[1], A * b[0] ** 2 + B * b[0] + C == b[1], A * c[0] ** 2 + B * c[0] + C == c[1]], [A, B, C], solution_dict=True)[0] + f = K[A] * x**2 + K[B] * x + K[C] return f + xs = [] ys = [] - dx = float(interval[1]-interval[0])/n + dx = float(interval[1] - interval[0]) / n - for i in range(n+1): - xs.append(interval[0] + i*dx) + for i in range(n + 1): + xs.append(interval[0] + i * dx) ys.append(f(x=xs[-1])) parabolas = Graphics() lines = Graphics() - for i in range(0, n-1, 2): - p = parabola((xs[i],ys[i]),(xs[i+1],ys[i+1]),(xs[i+2],ys[i+2])) - parabolas += plot(p(x=x), (x, xs[i], xs[i+2]), color='red') - lines += line([(xs[i],ys[i]), (xs[i],0), (xs[i+2],0)],color='red') - lines += line([(xs[i+1],ys[i+1]), (xs[i+1],0)], linestyle='-.', color='red') + for i in range(0, n - 1, 2): + p = parabola((xs[i], ys[i]), (xs[i + 1], ys[i + 1]), (xs[i + 2], ys[i + 2])) + parabolas += plot(p(x=x), (x, xs[i], xs[i + 2]), color='red') + lines += line([(xs[i], ys[i]), (xs[i], 0), (xs[i + 2], 0)], color='red') + lines += line([(xs[i + 1], ys[i + 1]), (xs[i + 1], 0)], linestyle='-.', color='red') - lines += line([(xs[-1],ys[-1]), (xs[-1],0)], color='red') + lines += line([(xs[-1], ys[-1]), (xs[-1], 0)], color='red') html(r'Function $f(x)=%s$' % latex(f(x))) - show(plot(f(x), x, interval[0], interval[1]) + parabolas + lines, - xmin=interval[0], xmax=interval[1]) + show(plot(f(x), x, interval[0], interval[1]) + parabolas + lines, xmin=interval[0], xmax=interval[1]) - numeric_value = integral_numerical(f,interval[0],interval[1])[0] - approx = dx/3 * (ys[0] + sum([4*ys[i] for i in range(1,n,2)]) + sum([2*ys[i] for i in range(2,n,2)]) + ys[n]) + numeric_value = integral_numerical(f, interval[0], interval[1])[0] + approx = dx / 3 * (ys[0] + sum([4 * ys[i] for i in range(1, n, 2)]) + sum([2 * ys[i] for i in range(2, n, 2)]) + ys[n]) - html(r'Integral value to seven decimal places is: $\displaystyle\int_{%.2f}^{%.2f} {f(x) \, \mathrm{d}x} = %.6f$' % - (interval[0],interval[1], - N(numeric_value,digits=7))) + html(r'Integral value to seven decimal places is: $\displaystyle\int_{%.2f}^{%.2f} {f(x) \, \mathrm{d}x} = %.6f$' % (interval[0], interval[1], N(numeric_value, digits=7))) if output_form == 'traditional': - sum_formula_html = r"\frac{d}{3} \cdot \left[ f(x_0) + %s + f(x_{%s})\right]" % ( - ' + '.join(r"%s \cdot f(x_{%s})" % (i % 2 * (-2) + 4, i + 1) - for i in range(n-1)), - n - ) - - sum_placement_html = r"\frac{%.2f}{3} \cdot \left[ f(%.2f) + %s + f(%.2f)\right]" % ( - dx, - N(xs[0],digits=5), - ' + '.join(r"%s \cdot f(%.2f)" % (i % 2 * (-2) + 4, N(xk, digits=5)) - for i, xk in enumerate(xs[1:-1])), - N(xs[n],digits=5) - ) - - sum_values_html = r"\frac{%.2f}{3} \cdot \left[ %s %s %s\right]" % ( - dx, - "%.2f + " % N(ys[0],digits=5), - ' + '.join(r"%s \cdot %.2f" % (i % 2 * (-2) + 4, N(yk, digits=5)) - for i, yk in enumerate(ys[1:-1])), - " + %.2f" % N(ys[n],digits=5) - ) - - html(r''' + sum_formula_html = r"\frac{d}{3} \cdot \left[ f(x_0) + %s + f(x_{%s})\right]" % (' + '.join(r"%s \cdot f(x_{%s})" % (i % 2 * (-2) + 4, i + 1) for i in range(n - 1)), n) + + sum_placement_html = r"\frac{%.2f}{3} \cdot \left[ f(%.2f) + %s + f(%.2f)\right]" % (dx, N(xs[0], digits=5), ' + '.join(r"%s \cdot f(%.2f)" % (i % 2 * (-2) + 4, N(xk, digits=5)) for i, xk in enumerate(xs[1:-1])), N(xs[n], digits=5)) + + sum_values_html = r"\frac{%.2f}{3} \cdot \left[ %s %s %s\right]" % (dx, "%.2f + " % N(ys[0], digits=5), ' + '.join(r"%s \cdot %.2f" % (i % 2 * (-2) + 4, N(yk, digits=5)) for i, yk in enumerate(ys[1:-1])), " + %.2f" % N(ys[n], digits=5)) + + html( + r'''
\begin{align*} \int_{%.2f}^{%.2f} {f(x) \, \mathrm{d}x} @@ -1381,11 +1300,9 @@ def parabola(a, b, c): & = %.6f \end{align*}
- ''' % ( - interval[0], interval[1], - sum_formula_html, sum_placement_html, sum_values_html, - N(approx,digits=7) - )) + ''' + % (interval[0], interval[1], sum_formula_html, sum_placement_html, sum_values_html, N(approx, digits=7)) + ) elif output_form == 'table': s = [['$i$', '$x_i$', '$f(x_i)$', '$m$', r'$m\cdot f(x_i)$']] for i in range(n + 1): @@ -1393,11 +1310,10 @@ def parabola(a, b, c): j = 1 else: j = (i + 1) % 2 * (-2) + 4 - s.append([i, xs[i], ys[i], j, N(j*ys[i])]) - s.append(['', '', '', r'$\sum$', '$%s$' % latex(3/dx*approx)]) + s.append([i, xs[i], ys[i], j, N(j * ys[i])]) + s.append(['', '', '', r'$\sum$', '$%s$' % latex(3 / dx * approx)]) pretty_print(table(s, header_row=True)) - html(r'$\int_{%.2f}^{%.2f} {f(x) \, \mathrm{d}x}\approx\frac {%.2f}{3}\cdot %s=%s$' % - (interval[0], interval[1],dx,latex(3/dx*approx),latex(approx))) + html(r'$\int_{%.2f}^{%.2f} {f(x) \, \mathrm{d}x}\approx\frac {%.2f}{3}\cdot %s=%s$' % (interval[0], interval[1], dx, latex(3 / dx * approx), latex(approx))) @library_interact( @@ -1465,6 +1381,7 @@ def riemann_sum( """ x = SR.var('x') from random import random + if interval_input == 'from slider': a = interval_s[0] b = interval_s[1] @@ -1472,36 +1389,27 @@ def riemann_sum( a = interval_g[0][0] b = interval_g[0][1] func = symbolic_expression(f).function(x) - division = [a]+[a+random()*(b-a) for i in range(n-1)]+[b] + division = [a] + [a + random() * (b - a) for i in range(n - 1)] + [b] division = sorted(division) - xs = [division[i]+random()*(division[i+1]-division[i]) for i in range(n)] + xs = [division[i] + random() * (division[i + 1] - division[i]) for i in range(n)] ys = [func(x_val) for x_val in xs] rects = Graphics() for i in range(n): - body = [[division[i], 0], [division[i], ys[i]], - [division[i+1], ys[i]], [division[i+1], 0]] + body = [[division[i], 0], [division[i], ys[i]], [division[i + 1], ys[i]], [division[i + 1], 0]] if ys[i].n() > 0: color_rect = 'green' else: color_rect = 'red' - rects = rects + polygon2d(body, rgbcolor=color_rect, alpha=0.1)\ - + point((xs[i], ys[i]), rgbcolor=(1, 0, 0))\ - + line(body, rgbcolor='black', zorder=-1) + rects = rects + polygon2d(body, rgbcolor=color_rect, alpha=0.1) + point((xs[i], ys[i]), rgbcolor=(1, 0, 0)) + line(body, rgbcolor='black', zorder=-1) html('Adjust your data and click Update button. Click repeatedly for another random values.') - show(plot(func(x),(x,a,b),zorder=5) + rects) - delka_intervalu = [division[i+1]-division[i] for i in range(n)] + show(plot(func(x), (x, a, b), zorder=5) + rects) + delka_intervalu = [division[i + 1] - division[i] for i in range(n)] if list_table: - pretty_print(table([ - ["$i$", "$[x_{i-1},x_i]$", r"$\eta_i$", r"$f(\eta_i)$", "$x_{i}-x_{i-1}$"] - ] + [ - [i+1,[division[i],division[i+1]],xs[i],ys[i],delka_intervalu[i]] for i in range(n) - ], header_row=True)) + pretty_print(table([["$i$", "$[x_{i-1},x_i]$", r"$\eta_i$", r"$f(\eta_i)$", "$x_{i}-x_{i-1}$"]] + [[i + 1, [division[i], division[i + 1]], xs[i], ys[i], delka_intervalu[i]] for i in range(n)], header_row=True)) - html(r'Riemann sum: $\displaystyle\sum_{i=1}^{%s} f(\eta_i)(x_i-x_{i-1})=%s$ ' % - (latex(n),latex(sum([ys[i]*delka_intervalu[i] for i in range(n)])))) - html(r'Exact value of the integral $\displaystyle\int_{%s}^{%s}%s\,\mathrm{d}x=%s$' % - (latex(a),latex(b),latex(func(x)),latex(integral_numerical(func(x),a,b)[0]))) + html(r'Riemann sum: $\displaystyle\sum_{i=1}^{%s} f(\eta_i)(x_i-x_{i-1})=%s$ ' % (latex(n), latex(sum([ys[i] * delka_intervalu[i] for i in range(n)])))) + html(r'Exact value of the integral $\displaystyle\int_{%s}^{%s}%s\,\mathrm{d}x=%s$' % (latex(a), latex(b), latex(func(x)), latex(integral_numerical(func(x), a, b)[0]))) x = SR.var("x") @@ -1602,22 +1510,22 @@ def function_tool(f, g, xrange, yrange, a, action, do_plot): h = f.denominator() lbl = r'\text{denom(f)}' elif action == '1/f': - h = 1/f + h = 1 / f lbl = r'\frac{1}{f}' elif action == 'finv': h = solve(f == SR.var('y'), x)[0].rhs() lbl = 'f^{-1}(y)' elif action == 'f+a': - h = f+a + h = f + a lbl = 'f + a' elif action == 'f-a': - h = f-a + h = f - a lbl = 'f - a' elif action == 'f*a': - h = f*a + h = f * a lbl = r'f \times a' elif action == 'f/a': - h = f/a + h = f / a lbl = r'\frac{f}{a}' elif action == 'f^a': h = f**a @@ -1626,22 +1534,22 @@ def function_tool(f, g, xrange, yrange, a, action, do_plot): h = f**a lbl = 'f^a' elif action == 'f(x+a)': - h = f.subs(x=x+a) + h = f.subs(x=x + a) lbl = 'f(x+a)' elif action == 'f(x*a)': - h = f.subs(x=x*a) + h = f.subs(x=x * a) lbl = 'f(xa)' elif action == 'f+g': - h = f+g + h = f + g lbl = 'f + g' elif action == 'f-g': - h = f-g + h = f - g lbl = 'f - g' elif action == 'f*g': - h = f*g + h = f * g lbl = r'f \times g' elif action == 'f/g': - h = f/g + h = f / g lbl = r'\frac{f}{g}' elif action == 'f(g)': h = f(g) @@ -1650,9 +1558,7 @@ def function_tool(f, g, xrange, yrange, a, action, do_plot): html('
$g = %s$
' % latex(g)) html('
$h = %s = %s$
' % (lbl, latex(h))) if do_plot: - P = plot(f, xrange, color='red', thickness=2) + \ - plot(g, xrange, color='green', thickness=2) + \ - plot(h, xrange, color='blue', thickness=2) + P = plot(f, xrange, color='red', thickness=2) + plot(g, xrange, color='green', thickness=2) + plot(h, xrange, color='blue', thickness=2) if yrange == 'auto': show(P, xmin=xrange[0], xmax=xrange[1]) else: @@ -1706,7 +1612,7 @@ def julia(expo, c_real, c_imag, iterations, zoom_x, zoom_y, plot_points, dpi): """ z = SR.var('z') I = CDF.gen() - f = symbolic_expression(z**expo + c_real + c_imag*I).function(z) + f = symbolic_expression(z**expo + c_real + c_imag * I).function(z) ff_j = fast_callable(f, vars=[z], domain=CDF) from sage.interacts.library_cython import julia @@ -1756,7 +1662,7 @@ def mandelbrot(expo, iterations, zoom_x, zoom_y, plot_points, dpi): """ x, z, c = SR.var('x, z, c') f = symbolic_expression(z**expo + c).function(z, c) - ff_m = fast_callable(f, vars=[z,c], domain=CDF) + ff_m = fast_callable(f, vars=[z, c], domain=CDF) from sage.interacts.library_cython import mandel @@ -1797,25 +1703,29 @@ def cellular_automaton(N, rule_number, size): size: IntSlider(value=6, description='size of graphic', max=11, min=1) """ from sage.rings.integer import Integer + if not 0 <= rule_number <= 255: raise ValueError('Invalid rule number') binary_digits = Integer(rule_number).digits(base=2) - rule = binary_digits + [0]*(8-len(binary_digits)) + rule = binary_digits + [0] * (8 - len(binary_digits)) - html('

Cellular Automaton

' + - '
"A cellular automaton is a collection of "colored" cells \ + html( + '

Cellular Automaton

' + + '
"A cellular automaton is a collection of "colored" cells \ on a grid of specified shape that evolves through a number of \ discrete time steps according to a set of rules based on the \ states of neighboring cells." — \ Mathworld,\ Cellular Automaton
\ -
Rule %s expands to %s
' % (rule_number, ''.join(map(str,rule))) - ) +
Rule %s expands to %s
' + % (rule_number, ''.join(map(str, rule))) + ) from sage.interacts.library_cython import cellular + M = cellular(rule, N) plot_M = matrix_plot(M, cmap='binary') - plot_M.show(figsize=[size,size]) + plot_M.show(figsize=[size, size]) @library_interact( @@ -1858,12 +1768,13 @@ def polar_prime_spiral(interval, show_factors, highlight_primes, show_curves, n, n: IntSlider(value=89, description='number $n$', max=200, min=1) dpi: IntSlider(value=100, description='dpi', max=300, min=10, step=10) """ - html('

Polar Prime Spiral

\ + html( + '

Polar Prime Spiral

\
\ For more information about the factors in the spiral, visit \ \ Number Spirals by John Williamson.
' - ) + ) start, end = interval from math import ceil @@ -1881,8 +1792,8 @@ def polar_prime_spiral(interval, show_factors, highlight_primes, show_curves, n, print("n < start value") return nn = SR.var('nn') - f1 = fast_float(sqrt(nn)*cos(2*pi*sqrt(nn)), 'nn') - f2 = fast_float(sqrt(nn)*sin(2*pi*sqrt(nn)), 'nn') + f1 = fast_float(sqrt(nn) * cos(2 * pi * sqrt(nn)), 'nn') + f2 = fast_float(sqrt(nn) * sin(2 * pi * sqrt(nn)), 'nn') f = lambda x: (f1(x), f2(x)) list = [] @@ -1890,34 +1801,34 @@ def polar_prime_spiral(interval, show_factors, highlight_primes, show_curves, n, if not show_factors: for i in srange(start, end, include_endpoint=True): if Integer(i).is_pseudoprime(): - list.append(f(i-start+1)) # primes list + list.append(f(i - start + 1)) # primes list else: - list2.append(f(i-start+1)) # composites list + list2.append(f(i - start + 1)) # composites list P = points(list) - R = points(list2, alpha=.1) # faded composites + R = points(list2, alpha=0.1) # faded composites else: for i in srange(start, end, include_endpoint=True): # Resize each of the dots depending of the number of factors of each number - list.append(disk((f(i-start+1)),0.05*pow(2,len(factor(i))-1), (0,2*pi))) + list.append(disk((f(i - start + 1)), 0.05 * pow(2, len(factor(i)) - 1), (0, 2 * pi))) if Integer(i).is_pseudoprime() and highlight_primes: - list2.append(f(i-start+1)) + list2.append(f(i - start + 1)) P = Graphics() for g in list: P += g p_size = 5 # the orange dot size of the prime markers if not highlight_primes: - list2 = [(f(n-start+1))] - R = points(list2, hue=.1, pointsize=p_size) + list2 = [(f(n - start + 1))] + R = points(list2, hue=0.1, pointsize=p_size) if n > 0: html('$n = %s$' % factor(n)) p = 1 # The X which marks the given n - W1 = disk((f(n-start+1)), p, (pi/6, 2*pi/6), alpha=.1) - W2 = disk((f(n-start+1)), p, (4*pi/6, 5*pi/6), alpha=.1) - W3 = disk((f(n-start+1)), p, (7*pi/6, 8*pi/6), alpha=.1) - W4 = disk((f(n-start+1)), p, (10*pi/6, 11*pi/6), alpha=.1) + W1 = disk((f(n - start + 1)), p, (pi / 6, 2 * pi / 6), alpha=0.1) + W2 = disk((f(n - start + 1)), p, (4 * pi / 6, 5 * pi / 6), alpha=0.1) + W3 = disk((f(n - start + 1)), p, (7 * pi / 6, 8 * pi / 6), alpha=0.1) + W4 = disk((f(n - start + 1)), p, (10 * pi / 6, 11 * pi / 6), alpha=0.1) Q = W1 + W2 + W3 + W4 n -= start - 1 # offset n for different start values to ensure accurate plotting @@ -1930,29 +1841,25 @@ def polar_prime_spiral(interval, show_factors, highlight_primes, show_curves, n, if n <= S * (S + 1): c = n - S**2 else: - c = n - (S + 1)**2 + c = n - (S + 1) ** 2 c2 = n - S * (S + 1) html('Pink Curve: $n^2 + %s$' % c) html('Green Curve: $n^2 + n + %s$' % c2) m = SR.var('m') - g = symbolic_expression(a*m**2+b*m+c).function(m) + g = symbolic_expression(a * m**2 + b * m + c).function(m) r = symbolic_expression(sqrt(g(m))).function(m) - theta = symbolic_expression(r(m) - m*sqrt(a)).function(m) - S1 = parametric_plot(((r(t))*cos(2*pi*(theta(t))),(r(t))*sin(2*pi*(theta(t)))), - (begin_curve, ceil(sqrt(end-start))), - color=hue(0.8), thickness=.3) # pink line + theta = symbolic_expression(r(m) - m * sqrt(a)).function(m) + S1 = parametric_plot(((r(t)) * cos(2 * pi * (theta(t))), (r(t)) * sin(2 * pi * (theta(t)))), (begin_curve, ceil(sqrt(end - start))), color=hue(0.8), thickness=0.3) # pink line b = 1 c = c2 - g = symbolic_expression(a*m**2+b*m+c).function(m) + g = symbolic_expression(a * m**2 + b * m + c).function(m) r = symbolic_expression(sqrt(g(m))).function(m) - theta = symbolic_expression(r(m) - m*sqrt(a)).function(m) - S2 = parametric_plot(((r(t))*cos(2*pi*(theta(t))),(r(t))*sin(2*pi*(theta(t)))), - (begin_curve, ceil(sqrt(end-start))), - color=hue(0.6), thickness=.3) # green line + theta = symbolic_expression(r(m) - m * sqrt(a)).function(m) + S2 = parametric_plot(((r(t)) * cos(2 * pi * (theta(t))), (r(t)) * sin(2 * pi * (theta(t)))), (begin_curve, ceil(sqrt(end - start))), color=hue(0.6), thickness=0.3) # green line - show(R+P+S1+S2+Q, aspect_ratio=1, axes=False, dpi=dpi) + show(R + P + S1 + S2 + Q, aspect_ratio=1, axes=False, dpi=dpi) else: - show(R+P+Q, aspect_ratio=1, axes=False, dpi=dpi) + show(R + P + Q, aspect_ratio=1, axes=False, dpi=dpi) else: - show(R+P, aspect_ratio=1, axes=False, dpi=dpi) + show(R + P, aspect_ratio=1, axes=False, dpi=dpi) diff --git a/src/sage/interfaces/abc.py b/src/sage/interfaces/abc.py index 9c451733631..91c3ce72f73 100644 --- a/src/sage/interfaces/abc.py +++ b/src/sage/interfaces/abc.py @@ -17,6 +17,7 @@ class AxiomElement: sage: len(sage.interfaces.abc.AxiomElement.__subclasses__()) <= 1 True """ + pass @@ -34,6 +35,7 @@ class ExpectElement: sage: len(sage.interfaces.abc.ExpectElement.__subclasses__()) <= 1 True """ + pass @@ -51,6 +53,7 @@ class FriCASElement: sage: len(sage.interfaces.abc.FriCASElement.__subclasses__()) <= 1 True """ + pass @@ -68,6 +71,7 @@ class GapElement: sage: len(sage.interfaces.abc.GapElement.__subclasses__()) <= 1 True """ + pass @@ -85,6 +89,7 @@ class GpElement: sage: len(sage.interfaces.abc.GpElement.__subclasses__()) <= 1 True """ + pass @@ -102,6 +107,7 @@ class Macaulay2Element: sage: len(sage.interfaces.abc.Macaulay2Element.__subclasses__()) <= 1 True """ + pass @@ -119,6 +125,7 @@ class MagmaElement: sage: len(sage.interfaces.abc.MagmaElement.__subclasses__()) <= 1 True """ + pass @@ -136,4 +143,5 @@ class SingularElement: sage: len(sage.interfaces.abc.SingularElement.__subclasses__()) <= 1 True """ + pass diff --git a/src/sage/interfaces/all.py b/src/sage/interfaces/all.py index 05f27868cf5..b820f7a1571 100644 --- a/src/sage/interfaces/all.py +++ b/src/sage/interfaces/all.py @@ -42,8 +42,5 @@ lazy_import('sage.interfaces.tachyon', 'tachyon_rt') # The following variable is used by sage-shell-mode in emacs: -interfaces = ['gap', 'gap3', 'giac', 'gp', 'mathematica', 'gnuplot', - 'kash', 'magma', 'macaulay2', 'maple', 'maxima', - 'mathematica', 'mwrank', 'octave', 'r', 'singular', - 'sage0', 'sage'] +interfaces = ['gap', 'gap3', 'giac', 'gp', 'mathematica', 'gnuplot', 'kash', 'magma', 'macaulay2', 'maple', 'maxima', 'mathematica', 'mwrank', 'octave', 'r', 'singular', 'sage0', 'sage'] del lazy_import diff --git a/src/sage/interfaces/axiom.py b/src/sage/interfaces/axiom.py index e3fc94be842..22c6ac563bb 100644 --- a/src/sage/interfaces/axiom.py +++ b/src/sage/interfaces/axiom.py @@ -228,18 +228,7 @@ def __init__( eval_using_file_cutoff = 200 self.__eval_using_file_cutoff = eval_using_file_cutoff self._COMMANDS_CACHE = '%s/%s_commandlist_cache.sobj' % (DOT_SAGE, name) - Expect.__init__(self, - name=name, - prompt=r'\([0-9]+\) -> ', - command=command, - script_subdirectory=script_subdirectory, - server=server, - server_tmpdir=server_tmpdir, - restart_on_ctrlc=False, - verbose_start=False, - init_code=init_code, - logfile=logfile, - eval_using_file_cutoff=eval_using_file_cutoff) + Expect.__init__(self, name=name, prompt=r'\([0-9]+\) -> ', command=command, script_subdirectory=script_subdirectory, server=server, server_tmpdir=server_tmpdir, restart_on_ctrlc=False, verbose_start=False, init_code=init_code, logfile=logfile, eval_using_file_cutoff=eval_using_file_cutoff) self._prompt_wait = self._prompt def _start(self): @@ -331,7 +320,7 @@ def _commands(self): i = s.find(start) end = "To get more information about" j = s.find(end) - return s[i + len(start):j].split() + return s[i + len(start) : j].split() def _tab_completion(self, verbose=True, use_disk_cache=True): """ @@ -359,6 +348,7 @@ def _tab_completion(self, verbose=True, use_disk_cache=True): return self.__tab_completion except AttributeError: import sage.misc.persist + if use_disk_cache: try: self.__tab_completion = sage.misc.persist.load(self._COMMANDS_CACHE) @@ -424,8 +414,7 @@ def get(self, var): s = s.strip() return s - def _eval_line(self, line, reformat=True, allow_use_file=False, - wait_for_prompt=True, restart_if_needed=False): + def _eval_line(self, line, reformat=True, allow_use_file=False, wait_for_prompt=True, restart_if_needed=False): """ EXAMPLES:: @@ -434,6 +423,7 @@ def _eval_line(self, line, reformat=True, allow_use_file=False, Type: PositiveInteger """ from sage.misc.verbose import verbose + if not wait_for_prompt: return Expect._eval_line(self, line) line = line.rstrip().rstrip(';') @@ -443,8 +433,7 @@ def _eval_line(self, line, reformat=True, allow_use_file=False, raise NotImplementedError("evaluation of long input lines (>3000 characters) in Axiom not yet implemented.") if self._expect is None: self._start() - if allow_use_file and self.__eval_using_file_cutoff and \ - len(line) > self.__eval_using_file_cutoff: + if allow_use_file and self.__eval_using_file_cutoff and len(line) > self.__eval_using_file_cutoff: return self._eval_line_using_file(line) try: E = self._expect @@ -462,8 +451,7 @@ def _eval_line(self, line, reformat=True, allow_use_file=False, except KeyboardInterrupt: self._keyboard_interrupt() - if '>> Error detected within library code:' in out or \ - 'Cannot find a definition or applicable library operation named' in out: + if '>> Error detected within library code:' in out or 'Cannot find a definition or applicable library operation named' in out: raise RuntimeError(out) if not reformat: @@ -472,7 +460,7 @@ def _eval_line(self, line, reformat=True, allow_use_file=False, return out # out = out.lstrip() i = out.find('\n') - out = out[i+1:] + out = out[i + 1 :] outs = out.split("\n") i = 0 for line in outs: @@ -637,7 +625,7 @@ def type(self): P = self._check_valid() s = P._eval_line(self.name()) i = s.rfind('Type:') - return P(s[i+5:].strip()) + return P(s[i + 5 :].strip()) def __len__(self): """ @@ -652,7 +640,7 @@ def __len__(self): P = self._check_valid() s = P.eval('# %s ' % self.name()) i = s.rfind('Type') - return int(s[:i - 1]) + return int(s[: i - 1]) def __getitem__(self, n): r""" @@ -724,13 +712,8 @@ def _latex_(self): raise RuntimeError("Error texing axiom object.") i = s.find('$$') j = s.rfind('$$') - s = s[i + 2:j] - s = multiple_replace({'\r': '', '\n': ' ', - ' \\sp ': '^', - '\\arcsin ': '\\sin^{-1} ', - '\\arccos ': '\\cos^{-1} ', - '\\arctan ': '\\tan^{-1} '}, - re.sub(r'\\leqno\(.*?\)', '', s)) # no eq number! + s = s[i + 2 : j] + s = multiple_replace({'\r': '', '\n': ' ', ' \\sp ': '^', '\\arcsin ': '\\sin^{-1} ', '\\arccos ': '\\cos^{-1} ', '\\arctan ': '\\tan^{-1} '}, re.sub(r'\\leqno\(.*?\)', '', s)) # no eq number! return s def as_type(self, type): @@ -767,11 +750,7 @@ def unparsed_input_form(self): s = P.eval('unparse(%s::InputForm)' % self._name) if 'translation error' in s or 'Cannot convert' in s: raise NotImplementedError - s = multiple_replace({'\r\n': '', # fix stupid Fortran-ish - 'DSIN(': 'sin(', - 'DCOS(': 'cos(', - 'DTAN(': 'tan(', - 'DSINH(': 'sinh('}, s) + s = multiple_replace({'\r\n': '', 'DSIN(': 'sin(', 'DCOS(': 'cos(', 'DTAN(': 'tan(', 'DSINH(': 'sinh('}, s) # fix stupid Fortran-ish r = re.search(r'"(.*)"', s) return r.groups(0)[0] if r else s @@ -843,18 +822,22 @@ def _sage_(self): if type == "Float": from sage.rings.integer_ring import ZZ from sage.rings.real_mpfr import RealField + prec = max(self.mantissa().length()._sage_(), 53) R = RealField(prec) x, e, b = self.unparsed_input_form().lstrip('float(').rstrip(')').split(',') - return R(ZZ(x) * ZZ(b)**ZZ(e)) + return R(ZZ(x) * ZZ(b) ** ZZ(e)) if type == "DoubleFloat": from sage.rings.real_double import RDF + return RDF(repr(self)) if type in ["PositiveInteger", "Integer"]: from sage.rings.integer_ring import ZZ + return ZZ(repr(self)) if type.startswith('Polynomial'): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + base_ring = P(type.removeprefix('Polynomial '))._sage_domain() vars = str(self.variables())[1:-1] R = PolynomialRing(base_ring, vars) @@ -865,12 +848,11 @@ def _sage_(self): # If all else fails, try using the unparsed input form try: import sage.misc.sage_eval + vars = sage.symbolic.ring.var(str(self.variables())[1:-1]) if isinstance(vars, tuple): - return sage.misc.sage_eval.sage_eval(self.unparsed_input_form(), - locals={str(x): x for x in vars}) - return sage.misc.sage_eval.sage_eval(self.unparsed_input_form(), - locals={str(vars): vars}) + return sage.misc.sage_eval.sage_eval(self.unparsed_input_form(), locals={str(x): x for x in vars}) + return sage.misc.sage_eval.sage_eval(self.unparsed_input_form(), locals={str(vars): vars}) except Exception: raise NotImplementedError @@ -894,9 +876,11 @@ def _sage_domain(self): name = str(self) if name == 'Integer': from sage.rings.integer_ring import ZZ + return ZZ if name == 'DoubleFloat': from sage.rings.real_double import RDF + return RDF if name.startswith('Fraction '): return P(name.lstrip('Fraction '))._sage_domain().fraction_field() @@ -988,7 +972,7 @@ def axiom_console(): ----------------------------------------------------------------------------- """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): - raise RuntimeError('Can use the console only in the terminal. ' - 'Try %%axiom magics instead.') + raise RuntimeError('Can use the console only in the terminal. ' 'Try %%axiom magics instead.') os.system('axiom -nox') diff --git a/src/sage/interfaces/ecm.py b/src/sage/interfaces/ecm.py index 80759169374..8952a708ef0 100644 --- a/src/sage/interfaces/ecm.py +++ b/src/sage/interfaces/ecm.py @@ -261,18 +261,7 @@ def interact(self): # Recommended settings from # http://www.mersennewiki.org/index.php/Elliptic_Curve_Method - _recommended_B1_list = {15: 2000, - 20: 11000, - 25: 50000, - 30: 250000, - 35: 1000000, - 40: 3000000, - 45: 11000000, - 50: 44000000, - 55: 110000000, - 60: 260000000, - 65: 850000000, - 70: 2900000000} + _recommended_B1_list = {15: 2000, 20: 11000, 25: 50000, 30: 250000, 35: 1000000, 40: 3000000, 45: 11000000, 50: 44000000, 55: 110000000, 60: 260000000, 65: 850000000, 70: 2900000000} def _B1_table_value(self, factor_digits, min_val=15, max_val=70): """ @@ -317,16 +306,13 @@ def recommended_B1(self, factor_digits): """ return self._recommended_B1_list[self._B1_table_value(factor_digits)] - _parse_status_re = re.compile( - r'Using B1=(\d+), B2=(\d+), polynomial ([^,]+), sigma=(\d+)') + _parse_status_re = re.compile(r'Using B1=(\d+), B2=(\d+), polynomial ([^,]+), sigma=(\d+)') _found_input_re = re.compile('Found input number N') - _found_factor_re = re.compile( - r'Found (?P.*) factor of [\s]*(?P\d+) digits: (?P\d+)') + _found_factor_re = re.compile(r'Found (?P.*) factor of [\s]*(?P\d+) digits: (?P\d+)') - _found_cofactor_re = re.compile( - r'(?P.*) cofactor (?P\d+) has [\s]*(?P\d+) digits') + _found_cofactor_re = re.compile(r'(?P.*) cofactor (?P\d+) has [\s]*(?P\d+) digits') def _parse_output(self, n, out): r""" @@ -391,8 +377,7 @@ def _parse_output(self, n, out): m = self._parse_status_re.match(line) if m is not None: group = m.groups() - self._last_params = {'B1': group[0], 'B2': group[1], - 'poly': group[2], 'sigma': group[3]} + self._last_params = {'B1': group[0], 'B2': group[1], 'poly': group[2], 'sigma': group[3]} continue m = self._found_input_re.match(line) if m is not None: @@ -620,8 +605,8 @@ def factor(self, n, factor_digits=None, B1=2000, proof=False, **kwds): True """ n = self._validate(n) - factors = [n] # factors that need to be factorized further - probable_prime_factors = [] # output prime factors + factors = [n] # factors that need to be factorized further + probable_prime_factors = [] # output prime factors while factors: n = factors.pop() @@ -756,7 +741,7 @@ def time(self, n, factor_digits, verbose=False): return out_lines = iter(out.splitlines()) - while next(out_lines)[:len(title_curves)] != title_curves: + while next(out_lines)[: len(title_curves)] != title_curves: pass header_curves = next(out_lines) curve_count_table = next(out_lines) @@ -767,8 +752,7 @@ def time(self, n, factor_digits, verbose=False): time_table = next(out_lines) assert header_curves == header_time - assert header_curves.split() == [ - '35', '40', '45', '50', '55', '60', '65', '70', '75', '80'] + assert header_curves.split() == ['35', '40', '45', '50', '55', '60', '65', '70', '75', '80'] h_min = 35 h_max = 80 offset = (self._B1_table_value(factor_digits, h_min, h_max) - h_min) // 5 diff --git a/src/sage/interfaces/expect.py b/src/sage/interfaces/expect.py index dff4bcfb0b3..c110d68fd29 100644 --- a/src/sage/interfaces/expect.py +++ b/src/sage/interfaces/expect.py @@ -109,6 +109,7 @@ class gc_disabled: sage: gc.isenabled() True """ + def __enter__(self): self._enabled = gc.isenabled() gc.disable() @@ -123,14 +124,8 @@ class Expect(Interface): """ Expect interface object. """ - def __init__(self, name, prompt, command=None, env={}, server=None, - server_tmpdir=None, - ulimit=None, maxread=None, - script_subdirectory=None, restart_on_ctrlc=False, - verbose_start=False, init_code=[], max_startup_time=None, - logfile=None, eval_using_file_cutoff=0, - do_cleaner=True, remote_cleaner=False, path=None, - terminal_echo=True): + + def __init__(self, name, prompt, command=None, env={}, server=None, server_tmpdir=None, ulimit=None, maxread=None, script_subdirectory=None, restart_on_ctrlc=False, verbose_start=False, init_code=[], max_startup_time=None, logfile=None, eval_using_file_cutoff=0, do_cleaner=True, remote_cleaner=False, path=None, terminal_echo=True): Interface.__init__(self, name) @@ -257,8 +252,7 @@ def command(self): executable = executable.name else: executable = executable.absolute_filename() - command = ' '.join([shlex.quote(executable)] - + [shlex.quote(arg) for arg in command[1:]]) + command = ' '.join([shlex.quote(executable)] + [shlex.quote(arg) for arg in command[1:]]) if server: if self.__remote_ulimit: command = f"ulimit {self.__remote_ulimit}; {command}" @@ -284,7 +278,7 @@ def _get(self, wait=0.1, alternate_prompt=None): return False, self._before() except pexpect.EOF: return True, self._before() - except Exception: # weird major problem! + except Exception: # weird major problem! return True, self._before() return True, self._before() @@ -326,7 +320,7 @@ def _so_far(self, wait=0.1, alternate_prompt=None): except (AttributeError, TypeError): self.__so_far = new return False, self.__so_far, new - except AttributeError as msg: # no __so_far + except AttributeError as msg: # no __so_far raise RuntimeError(msg) def is_remote(self): @@ -341,10 +335,8 @@ def user_dir(self): def _change_prompt(self, prompt): if isinstance(prompt, str): prompt = str_to_bytes(prompt) - elif (isinstance(prompt, type(re.compile(''))) and - isinstance(prompt.pattern, str)): - prompt = re.compile(str_to_bytes(prompt.pattern), - prompt.flags & ~re.U) + elif isinstance(prompt, type(re.compile(''))) and isinstance(prompt.pattern, str): + prompt = re.compile(str_to_bytes(prompt.pattern), prompt.flags & ~re.U) self._prompt = prompt def path(self): @@ -473,12 +465,11 @@ def _start(self, alt_message=None, block_during_init=True): # logfile in .sage/pexpect_logs/ if self.__logfilename is None and 'SAGE_PEXPECT_LOG' in os.environ: from sage.env import DOT_SAGE + logs = os.path.join(DOT_SAGE, 'pexpect_logs') os.makedirs(logs, exist_ok=True) - filename = '{name}-{pid}-{id}-{session}'.format( - name=self.name(), pid=os.getpid(), id=id(self), - session=self._session_number) + filename = '{name}-{pid}-{id}-{session}'.format(name=self.name(), pid=os.getpid(), id=id(self), session=self._session_number) self.__logfilename = os.path.join(logs, filename) if self.__logfilename is not None: self.__logfile = open(self.__logfilename, 'wb') @@ -514,25 +505,27 @@ def _start(self, alt_message=None, block_during_init=True): try: from sage.interfaces.sagespawn import SageSpawn - self._expect = SageSpawn(cmd, - logfile=self.__logfile, - timeout=None, # no timeout - env=pexpect_env, - name=self._repr_(), - echo=self._terminal_echo, - # Work around https://bugs.python.org/issue1652 - preexec_fn=lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL), - quit_string=self._quit_string()) + self._expect = SageSpawn( + cmd, + logfile=self.__logfile, + timeout=None, # no timeout + env=pexpect_env, + name=self._repr_(), + echo=self._terminal_echo, + # Work around https://bugs.python.org/issue1652 + preexec_fn=lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL), + quit_string=self._quit_string(), + ) # Attempt to shutdown the running process gracefully # when sage terminates. import atexit + atexit.register(self.quit) except (ExceptionPexpect, pexpect.EOF) as e: # Change pexpect errors to RuntimeError - raise RuntimeError("unable to start %s because the command %r failed: %s\n%s" % - (self.name(), cmd, e, self._install_hints())) + raise RuntimeError("unable to start %s because the command %r failed: %s\n%s" % (self.name(), cmd, e, self._install_hints())) except BaseException: self._expect = None self._session_number = BAD_SESSION @@ -767,6 +760,7 @@ def _local_tmpfile(self): import atexit from tempfile import NamedTemporaryFile + # FriCAS uses the ".input" suffix, and the other # interfaces are suffix-agnostic, so using ".input" here # lets us avoid a subclass override for FriCAS. @@ -1059,7 +1053,7 @@ def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if if self._terminal_echo: i = out.find("\n") j = out.rfind("\r") - return out[i + 1:j].replace('\r\n', '\n') + return out[i + 1 : j].replace('\r\n', '\n') return out.replace('\r\n', '\n') def _keyboard_interrupt(self): @@ -1356,8 +1350,7 @@ def _synchronize(self, cmd='1+%s;\n'): # END Synchronization code. ########################################################################### - def eval(self, code, strip=True, synchronize=False, locals=None, allow_use_file=True, - split_lines='nofile', **kwds): + def eval(self, code, strip=True, synchronize=False, locals=None, allow_use_file=True, split_lines='nofile', **kwds): """ INPUT: @@ -1406,12 +1399,10 @@ def eval(self, code, strip=True, synchronize=False, locals=None, allow_use_file= try: with gc_disabled(): - if (split_lines == "nofile" and allow_use_file and - self._eval_using_file_cutoff and len(code) > self._eval_using_file_cutoff): + if split_lines == "nofile" and allow_use_file and self._eval_using_file_cutoff and len(code) > self._eval_using_file_cutoff: return self._eval_line_using_file(code) if split_lines: - return '\n'.join(self._eval_line(L, allow_use_file=allow_use_file, **kwds) - for L in code.split('\n') if L) + return '\n'.join(self._eval_line(L, allow_use_file=allow_use_file, **kwds) for L in code.split('\n') if L) return self._eval_line(code, allow_use_file=allow_use_file, **kwds) # DO NOT CATCH KeyboardInterrupt, as it is being caught # by _eval_line @@ -1462,6 +1453,7 @@ class ExpectFunction(InterfaceFunction): """ Expect function. """ + pass @@ -1470,6 +1462,7 @@ class FunctionElement(InterfaceFunctionElement): """ Expect function element. """ + pass @@ -1478,16 +1471,16 @@ class ExpectElement(InterfaceElement, sage.interfaces.abc.ExpectElement): """ Expect element. """ + def __init__(self, parent, value, is_name=False, name=None): RingElement.__init__(self, parent) self._create = value if parent is None: - return # means "invalid element" + return # means "invalid element" # idea: Joe Wetherell -- try to find out if the output # is too long and if so get it using file, otherwise # don't. - if isinstance(value, str) and parent._eval_using_file_cutoff and \ - parent._eval_using_file_cutoff < len(value): + if isinstance(value, str) and parent._eval_using_file_cutoff and parent._eval_using_file_cutoff < len(value): self._get_using_file = True if is_name: @@ -1523,8 +1516,7 @@ def _check_valid(self): """ try: P = self.parent() - if P is None or P._session_number == BAD_SESSION or self._session_number == -1 or \ - P._session_number != self._session_number: + if P is None or P._session_number == BAD_SESSION or self._session_number == -1 or P._session_number != self._session_number: raise ValueError("The %s session in which this object was defined is no longer running." % P.name()) except AttributeError: raise ValueError("The session in which this object was defined is no longer running.") @@ -1544,6 +1536,7 @@ def __del__(self): except (RuntimeError, ExceptionPexpect): # needed to avoid infinite loops in some rare cases pass + # def _sage_repr(self): # TO DO: this could use file transfers when self.is_remote() @@ -1553,6 +1546,7 @@ class StdOutContext: A context in which all communication between Sage and a subprocess interfaced via pexpect is printed to stdout. """ + def __init__(self, interface, silent=False, stdout=None): """ Construct a new context in which all communication between Sage diff --git a/src/sage/interfaces/four_ti_2.py b/src/sage/interfaces/four_ti_2.py index 8d93ce9c5e3..449491f01a8 100644 --- a/src/sage/interfaces/four_ti_2.py +++ b/src/sage/interfaces/four_ti_2.py @@ -47,6 +47,7 @@ class FourTi2: Each 4ti2 command is exposed as a method of this class. """ + def __init__(self, directory=None): r""" Initialize this object. @@ -84,6 +85,7 @@ def directory(self): '/tmp/' """ from sage.misc.temporary_file import tmp_dir + if self._directory is None: # we have to put this here rather than in the __init__ # method since apparently importing sage.misc.misc does not @@ -130,6 +132,7 @@ def write_matrix(self, mat, filename): """ from sage.matrix.constructor import matrix from sage.structure.element import Matrix + if not isinstance(mat, Matrix): mat = matrix(ZZ, mat) if mat.base_ring() != ZZ: @@ -202,6 +205,7 @@ def read_matrix(self, filename): [3 4 6] """ from sage.matrix.constructor import matrix + try: f = open(os.path.join(self.directory(), filename)) lines = f.readlines() @@ -210,9 +214,7 @@ def read_matrix(self, filename): return matrix(ZZ, 0, 0) nrows, ncols = map(ZZ, lines.pop(0).strip().split()) - return matrix(ZZ, nrows, ncols, - [[ZZ(_) for _ in line.strip().split()] for line in lines - if line.strip() != ""]) + return matrix(ZZ, nrows, ncols, [[ZZ(_) for _ in line.strip().split()] for line in lines if line.strip() != ""]) def _process_input(self, kwds): r""" @@ -260,8 +262,7 @@ def _process_input(self, kwds): if ext == "project" or ext == "self": continue - if (isinstance(value, list) and - not (value and isinstance(value[0], list))): + if isinstance(value, list) and not (value and isinstance(value[0], list)): self.write_single_row(value, project + "." + ext) else: self.write_matrix(value, project + "." + ext) @@ -295,6 +296,7 @@ def call(self, command, project, verbose=True, *, options=()): """ import subprocess import shlex + feature = FourTi2Executable(command) executable = feature.absolute_filename() options = " ".join(options) @@ -332,8 +334,7 @@ def zsolve(self, mat=None, rel=None, rhs=None, sign=None, lat=None, project=None """ project = self._process_input(locals()) self.call('zsolve', project, options=['-q']) - return [self.read_matrix(project+'.'+ext) for ext in - ['zinhom', 'zhom', 'zfree']] + return [self.read_matrix(project + '.' + ext) for ext in ['zinhom', 'zhom', 'zfree']] def qsolve(self, mat=None, rel=None, sign=None, project=None): r""" @@ -350,8 +351,7 @@ def qsolve(self, mat=None, rel=None, sign=None, project=None): """ project = self._process_input(locals()) self.call('qsolve', project, options=['-q', '-parbitrary']) - return [self.read_matrix(project+'.'+ext) for ext in - ['qhom', 'qfree']] + return [self.read_matrix(project + '.' + ext) for ext in ['qhom', 'qfree']] def rays(self, mat=None, project=None): r""" @@ -370,7 +370,7 @@ def rays(self, mat=None, project=None): """ project = self._process_input(locals()) self.call('rays', project, options=['-q', '-parbitrary']) - return self.read_matrix(project+'.ray') + return self.read_matrix(project + '.ray') def hilbert(self, mat=None, lat=None, project=None): r""" @@ -394,7 +394,7 @@ def hilbert(self, mat=None, lat=None, project=None): """ project = self._process_input(locals()) self.call('hilbert', project, options=['-q']) - return self.read_matrix(project+'.hil') + return self.read_matrix(project + '.hil') def graver(self, mat=None, lat=None, project=None): r""" @@ -419,7 +419,7 @@ def graver(self, mat=None, lat=None, project=None): """ project = self._process_input(locals()) self.call('graver', project, options=['-q']) - return self.read_matrix(project+'.gra') + return self.read_matrix(project + '.gra') def ppi(self, n): r""" @@ -456,7 +456,7 @@ def circuits(self, mat=None, project=None): """ project = self._process_input(locals()) self.call('circuits', project, options=['-q', '-parbitrary']) - return self.read_matrix(project+'.cir') + return self.read_matrix(project + '.cir') def minimize(self, mat=None, lat=None): r""" @@ -472,8 +472,7 @@ def minimize(self, mat=None, lat=None): ... NotImplementedError: 4ti2 command 'minimize' not implemented in Sage. """ - raise NotImplementedError("4ti2 command 'minimize' not implemented " - "in Sage.") + raise NotImplementedError("4ti2 command 'minimize' not implemented " "in Sage.") def groebner(self, mat=None, lat=None, project=None): r""" @@ -496,7 +495,7 @@ def groebner(self, mat=None, lat=None, project=None): """ project = self._process_input(locals()) self.call('groebner', project, options=['-q', '-parbitrary']) - return self.read_matrix(project+'.gro') + return self.read_matrix(project + '.gro') def _magic3x3(self): r""" @@ -515,14 +514,8 @@ def _magic3x3(self): [ 1 1 0 0 -1 0 -1 0 0] """ from sage.matrix.constructor import matrix - return matrix(ZZ, 7, 9, - [[1, 1, 1, -1, -1, -1, 0, 0, 0], - [1, 1, 1, 0, 0, 0, -1, -1, -1], - [0, 1, 1, -1, 0, 0, -1, 0, 0], - [1, 0, 1, 0, -1, 0, 0, -1, 0], - [1, 1, 0, 0, 0, -1, 0, 0, -1], - [0, 1, 1, 0, -1, 0, 0, 0, -1], - [1, 1, 0, 0, -1, 0, -1, 0, 0]]) + + return matrix(ZZ, 7, 9, [[1, 1, 1, -1, -1, -1, 0, 0, 0], [1, 1, 1, 0, 0, 0, -1, -1, -1], [0, 1, 1, -1, 0, 0, -1, 0, 0], [1, 0, 1, 0, -1, 0, 0, -1, 0], [1, 1, 0, 0, 0, -1, 0, 0, -1], [0, 1, 1, 0, -1, 0, 0, 0, -1], [1, 1, 0, 0, -1, 0, -1, 0, 0]]) # The instance that should be used outside this file. diff --git a/src/sage/interfaces/fricas.py b/src/sage/interfaces/fricas.py index a3ca1972127..c3800899c46 100644 --- a/src/sage/interfaces/fricas.py +++ b/src/sage/interfaces/fricas.py @@ -206,12 +206,13 @@ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.misc.lazy_import import lazy_import + lazy_import('sage.symbolic.expression', ['register_symbol']) lazy_import('sage.symbolic.constants', ['I', 'e', 'pi']) FRICAS_SINGLE_LINE_START = 3 # where output starts when it fits next to the line number -FRICAS_MULTI_LINE_START = 2 # and when it doesn't -FRICAS_LINE_LENGTH = 80 # length of a line, should match the line length in sage +FRICAS_MULTI_LINE_START = 2 # and when it doesn't +FRICAS_LINE_LENGTH = 80 # length of a line, should match the line length in sage # the following messages have, unfortunately, no markup. FRICAS_WHAT_OPERATIONS_STRING = r"Operations whose names satisfy the above pattern\(s\):" FRICAS_ERROR_IN_LIBRARY_CODE = ">> Error detected within library code:" @@ -243,30 +244,10 @@ ")set message type off", ")set message void off", ")set output length " + str(FRICAS_LINE_LENGTH), - ")lisp (setf |$ioHook|" - " (lambda (x &optional args)" - " (when (member x '(|startAlgebraOutput| |endOfAlgebraOutput|" - " |startKeyedMsg| |endOfKeyedMsg|))" - " (prin1 x)" - " (princ #\\Newline))))") + ")lisp (setf |$ioHook|" " (lambda (x &optional args)" " (when (member x '(|startAlgebraOutput| |endOfAlgebraOutput|" " |startKeyedMsg| |endOfKeyedMsg|))" " (prin1 x)" " (princ #\\Newline))))", +) # code (one-line!) executed after having set up the prompt -FRICAS_HELPER_CODE = ( - 'sageprint(x:SExpression):String == ' + - '(atom? x => (' + - 'float? x => return float(x)::String;' + - 'integer? x => return integer(x)::String;' + - 'string? x => return concat(["_"", string(x)::String, "_""])$String;' + - 'symbol? x => return string(symbol(x));' + - 'list? x => return "()");' + - 'S: List String := [sageprint y for y in destruct x];' + - 'R: String := new(1 + reduce(_+, [1 + #(s)$String for s in S], 0),' + - 'space()$Character);' + - 'copyInto!(R, "(", 1);' + - 'i := 2;' + - 'for s in S repeat' - '(copyInto!(R, s, i); i := i + 1 + #(s)$String);' + - 'copyInto!(R, ")", i-1);' + - 'return R)') +FRICAS_HELPER_CODE = 'sageprint(x:SExpression):String == ' + '(atom? x => (' + 'float? x => return float(x)::String;' + 'integer? x => return integer(x)::String;' + 'string? x => return concat(["_"", string(x)::String, "_""])$String;' + 'symbol? x => return string(symbol(x));' + 'list? x => return "()");' + 'S: List String := [sageprint y for y in destruct x];' + 'R: String := new(1 + reduce(_+, [1 + #(s)$String for s in S], 0),' + 'space()$Character);' + 'copyInto!(R, "(", 1);' + 'i := 2;' + 'for s in S repeat' '(copyInto!(R, s, i); i := i + 1 + #(s)$String);' + 'copyInto!(R, ")", i-1);' + 'return R)' FRICAS_LINENUMBER_OFF_CODE = ")lisp (setf |$IOindex| NIL)" FRICAS_FIRST_PROMPT = r"\(1\) -> " @@ -277,9 +258,8 @@ class FriCAS(ExtraTabCompletion, Expect): """ Interface to a FriCAS interpreter. """ - def __init__(self, name='fricas', command=None, - script_subdirectory=None, logfile=None, - server=None, server_tmpdir=None): + + def __init__(self, name='fricas', command=None, script_subdirectory=None, logfile=None, server=None, server_tmpdir=None): """ Create an instance of the FriCAS interpreter. @@ -305,6 +285,7 @@ def __init__(self, name='fricas', command=None, """ if command is None: from sage.features.fricas import FriCAS + command = [FriCAS(), "-nosman"] eval_using_file_cutoff = 4096 - 5 # magic number from Expect._eval_line (there might be a bug) @@ -312,18 +293,7 @@ def __init__(self, name='fricas', command=None, self.__eval_using_file_cutoff = eval_using_file_cutoff self._COMMANDS_CACHE = '%s/%s_commandlist_cache.sobj' % (DOT_SAGE, name) # we run the init code in _start to avoid spurious output - Expect.__init__(self, - name=name, - prompt=FRICAS_FIRST_PROMPT, - command=command, - script_subdirectory=script_subdirectory, - server=server, - server_tmpdir=server_tmpdir, - restart_on_ctrlc=False, - verbose_start=False, - init_code=[], - logfile=logfile, - eval_using_file_cutoff=eval_using_file_cutoff) + Expect.__init__(self, name=name, prompt=FRICAS_FIRST_PROMPT, command=command, script_subdirectory=script_subdirectory, server=server, server_tmpdir=server_tmpdir, restart_on_ctrlc=False, verbose_start=False, init_code=[], logfile=logfile, eval_using_file_cutoff=eval_using_file_cutoff) def _start(self): """ @@ -422,8 +392,7 @@ def _commands(self): True """ output = self.eval(")what operations", reformat=False) - m = re.search(FRICAS_WHAT_OPERATIONS_STRING + r"\n(.*)\n\|startKeyedMsg\|", - output, flags=re.DOTALL) + m = re.search(FRICAS_WHAT_OPERATIONS_STRING + r"\n(.*)\n\|startKeyedMsg\|", output, flags=re.DOTALL) l = m.groups()[0].split() return l @@ -452,6 +421,7 @@ def _tab_completion(self, verbose=True, use_disk_cache=True): return self.__tab_completion except AttributeError: import sage.misc.persist + if use_disk_cache: try: self.__tab_completion = sage.misc.persist.load(self._COMMANDS_CACHE) @@ -512,20 +482,20 @@ def _remote_tmpfile(self): self.__remote_tmpfile = self._remote_tmpdir() + "/interface_%s:%s.input" % (LOCAL_IDENTIFIER, self.pid()) return self.__remote_tmpfile -# what I expect from FriCAS: - -# 1.) in set(self, var, value) -# -# no markers: -# there could be some "debugging" output, as in fricas("guessADE([1,1,1,1], debug==true)") -# -# startKeyedMsg: an error happened -# -# 2.) in get(self, var) -# -# |startAlgebraOutput\|...|endOfAlgebraOutput\| -# -# 3.) I also need a routine to send a system command and get its output. + # what I expect from FriCAS: + + # 1.) in set(self, var, value) + # + # no markers: + # there could be some "debugging" output, as in fricas("guessADE([1,1,1,1], debug==true)") + # + # startKeyedMsg: an error happened + # + # 2.) in get(self, var) + # + # |startAlgebraOutput\|...|endOfAlgebraOutput\| + # + # 3.) I also need a routine to send a system command and get its output. def _check_errors(self, line, output): """ @@ -570,11 +540,9 @@ def _check_errors(self, line, output): "$" to specify which version of the function you need. """ # otherwise there might be a message - m = re.search(r"\|startKeyedMsg\|\n(.*)\n\|endOfKeyedMsg\|", - output, flags=re.DOTALL) + m = re.search(r"\|startKeyedMsg\|\n(.*)\n\|endOfKeyedMsg\|", output, flags=re.DOTALL) if m: - replacements = [('|startKeyedMsg|\n', ''), - ('|endOfKeyedMsg|', '')] + replacements = [('|startKeyedMsg|\n', ''), ('|endOfKeyedMsg|', '')] for old, new in replacements: output = output.replace(old, new) raise RuntimeError("An error occurred when FriCAS evaluated '%s':\n%s" % (line, output)) @@ -600,6 +568,7 @@ def _register_symbols(): from sage.functions.special import elliptic_e, elliptic_f from sage.misc.functional import symbolic_sum, symbolic_prod from sage.rings.infinity import infinity + register_symbol(pi, {'fricas': 'pi'}, 0) # %pi::INFORM is %pi, but (pi) also exists register_symbol(lambda: infinity, {'fricas': 'infinity'}, 0) # %infinity::INFORM is (infinity) register_symbol(lambda: infinity, {'fricas': 'plusInfinity'}, 0) # %plusInfinity::INFORM is (plusInfinity) @@ -624,7 +593,7 @@ def _register_symbols(): register_symbol(lambda x, y: x - y, {'fricas': '-'}, 2) register_symbol(lambda x, y: x * y, {'fricas': '*'}, 2) register_symbol(lambda x, y: x / y, {'fricas': '/'}, 2) - register_symbol(lambda x, y: x ** y, {'fricas': '^'}, 2) + register_symbol(lambda x, y: x**y, {'fricas': '^'}, 2) register_symbol(lambda f, x: diff(f, x), {'fricas': 'D'}, 2) register_symbol(lambda x, y: x + y * I, {'fricas': 'complex'}, 2) register_symbol(lambda x: dilog(1 - x), {'fricas': 'dilog'}, 1) @@ -661,7 +630,7 @@ def _convert_prod(x, y): def explicitly_not_implemented(*args): raise NotImplementedError("the translation of the FriCAS Expression '%s' to sage is not yet implemented" % args) - register_symbol(lambda *args: explicitly_not_implemented("rootOfADE"), {'fricas': 'rootOfADE'}, 2) # to be removed once we fully on FriCAS 1.3.10+ + register_symbol(lambda *args: explicitly_not_implemented("rootOfADE"), {'fricas': 'rootOfADE'}, 2) # to be removed once we fully on FriCAS 1.3.10+ register_symbol(lambda *args: explicitly_not_implemented("FEseries"), {'fricas': 'FEseries'}, 2) register_symbol(lambda *args: explicitly_not_implemented("rootOfRec"), {'fricas': 'rootOfRec'}, 2) @@ -709,8 +678,7 @@ def get(self, var): """ output = self.eval(str(var), reformat=False) # if there is AlgebraOutput we ask no more - m = re.search(r"\|startAlgebraOutput\|\n(.*)\n\|endOfAlgebraOutput\|", - output, flags=re.DOTALL) + m = re.search(r"\|startAlgebraOutput\|\n(.*)\n\|endOfAlgebraOutput\|", output, flags=re.DOTALL) if m: lines = m.groups()[0].split("\n") if max(len(line) for line in lines) < FRICAS_LINE_LENGTH: @@ -853,8 +821,7 @@ def __reduce__(self): """ return reduce_load_fricas, tuple([]) - def eval(self, code, strip=True, synchronize=False, locals=None, allow_use_file=True, - split_lines='nofile', reformat=True, **kwds): + def eval(self, code, strip=True, synchronize=False, locals=None, allow_use_file=True, split_lines='nofile', reformat=True, **kwds): """ Evaluate ``code`` using FriCAS. @@ -876,19 +843,13 @@ def eval(self, code, strip=True, synchronize=False, locals=None, allow_use_file= sage: fricas("x") x """ - output = Expect.eval(self, code, strip=strip, - synchronize=synchronize, locals=locals, - allow_use_file=allow_use_file, split_lines=split_lines, - **kwds) + output = Expect.eval(self, code, strip=strip, synchronize=synchronize, locals=locals, allow_use_file=allow_use_file, split_lines=split_lines, **kwds) # we remove carriage returns (\r) to make parsing easier # they are sent depending on how fricas was invoked: # on linux, "fricas -nox -noclef" sends "\r\n" and "fricas -nosman" sends "\n" output = output.replace('\r', '') if reformat: - replacements = [('|startAlgebraOutput|\n', ''), - ('|endOfAlgebraOutput|', ''), - ('|startKeyedMsg|\n', ''), - ('|endOfKeyedMsg|', '')] + replacements = [('|startAlgebraOutput|\n', ''), ('|endOfAlgebraOutput|', ''), ('|startKeyedMsg|\n', ''), ('|endOfKeyedMsg|', '')] for old, new in replacements: output = output.replace(old, new) @@ -960,6 +921,7 @@ class FriCASElement(ExpectElement, sage.interfaces.abc.FriCASElement): .. automethod:: _sage_ """ + def __len__(self): """ Return the length of a list. @@ -1138,10 +1100,7 @@ def _latex_(self): sage: latex(fricas("integrate(sin(x+1/x),x)")) \int ^{\displaystyle x} {{\sin \left( {{\frac{{{{ \%...} ^{2}}+1}}{ \%...}}} \right)} \ {d \%...}} """ - replacements = [(r'\sp ', '^'), - (r'\sp{', '^{'), - (r'\sb ', '_'), - (r'\sb{', '_{')] + replacements = [(r'\sp ', '^'), (r'\sp{', '^{'), (r'\sb ', '_'), (r'\sb{', '_{')] P = self._check_valid() s = P.get_string("latex(%s)" % self._name) for old, new in replacements: @@ -1554,6 +1513,7 @@ def _sage_(self): -1/2*sqrt(1/3)*sqrt((3*(1/18*I*sqrt(229)*sqrt(3) + 1/2)^(2/3) + 4)/(1/18*I*sqrt(229)*sqrt(3) + 1/2)^(1/3)) + 1/2*sqrt(-(1/18*I*sqrt(229)*sqrt(3) + 1/2)^(1/3) + 6*sqrt(1/3)/sqrt((3*(1/18*I*sqrt(229)*sqrt(3) + 1/2)^(2/3) + 4)/(1/18*I*sqrt(229)*sqrt(3) + 1/2)^(1/3)) - 4/3/(1/18*I*sqrt(229)*sqrt(3) + 1/2)^(1/3)) """ from sage.interfaces.fricas_translator import SEXParser, SEXPorter, SEXEvaluator, LazyParent + P = self._check_valid() dom_str = P.get_string(f"sageprint(dom({self._name}))") dom = SEXParser(dom_str).parse() @@ -1640,6 +1600,7 @@ def fricas_console(): ----------------------------------------------------------------------------- """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%fricas magics instead.') os.system('fricas -nox') @@ -1659,4 +1620,5 @@ def __doctest_cleanup(): False """ import sage.interfaces.quit + sage.interfaces.quit.expect_quitall() diff --git a/src/sage/interfaces/fricas_translator.py b/src/sage/interfaces/fricas_translator.py index 318ba9f588a..3d7658ac87a 100644 --- a/src/sage/interfaces/fricas_translator.py +++ b/src/sage/interfaces/fricas_translator.py @@ -15,13 +15,12 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer + lazy_import('sage.calculus.var', ['var', 'function']) lazy_import('sage.symbolic.expression', ['symbol_table', 'register_symbol']) lazy_import('sage.symbolic.constants', ['I', 'e', 'pi']) -FRICAS_CONSTANTS = {'%i': I, - '%e': e, - '%pi': pi} +FRICAS_CONSTANTS = {'%i': I, '%e': e, '%pi': pi} # the dispatch dictionary for SEXPorter and Evaluator # if the first element of the pair is a function, it is used by @@ -49,12 +48,10 @@ "Factored": ("_unary", "_eval_factorization"), "Vector": ("_unary", "_eval_list"), "DirectProduct": ("_aggregate", "_eval_list"), - "UnivariatePolynomial": (lambda x: ("Polynomial", x[2]), - "_eval_polynomialring"), # coerce to Polynomial - "DistributedMultivariatePolynomial": (lambda x: ("Polynomial", x[2]), - "_eval_polynomialring"), - "MultivariatePolynomial": (lambda x: ("Polynomial", x[2]), - "_eval_polynomialring")} + "UnivariatePolynomial": (lambda x: ("Polynomial", x[2]), "_eval_polynomialring"), # coerce to Polynomial + "DistributedMultivariatePolynomial": (lambda x: ("Polynomial", x[2]), "_eval_polynomialring"), + "MultivariatePolynomial": (lambda x: ("Polynomial", x[2]), "_eval_polynomialring"), +} class SEXPorter: @@ -62,6 +59,7 @@ class SEXPorter: A class constructing the FriCAS package call to export objects in the given (parsed) domain. """ + def __init__(self, domain): """ INPUT: @@ -75,9 +73,7 @@ def __init__(self, domain): sage: SEXPorter(("Integer",))._domain ('Integer',) """ - if (isinstance(domain, tuple) - and (head := domain[0]) in FRICAS_DOMAIN_DISPATCH - and callable(fun := FRICAS_DOMAIN_DISPATCH[head][0])): + if isinstance(domain, tuple) and (head := domain[0]) in FRICAS_DOMAIN_DISPATCH and callable(fun := FRICAS_DOMAIN_DISPATCH[head][0]): self._domain = fun(domain) else: self._domain = domain @@ -115,9 +111,7 @@ def _unparse(self): dom = SEXPorter(self._domain[2])._unparse() return f"{tag}: {dom}" - return (self._domain[0] + "(" - + ",".join(SEXPorter(e)._unparse() for e in self._domain[1:]) - + ")") + return self._domain[0] + "(" + ",".join(SEXPorter(e)._unparse() for e in self._domain[1:]) + ")" def _inputform(self): """ @@ -260,8 +254,7 @@ def make_case(field, tag_index): domain = SEXPorter(field_domain) return f'obj case {domain._unparse()} => {make_call(field_domain, tag_index)}' - items = "; ".join(make_case(dom, tag) - for tag, dom in enumerate(self._domain[1:])) + items = "; ".join(make_case(dom, tag) for tag, dom in enumerate(self._domain[1:])) name = "sexport" + "".join(map(str, flatten(self._domain))) pattern = compile(r'[\W_]+') @@ -270,7 +263,6 @@ def make_case(field, tag_index): fricas.eval(f"{name}(obj:{self._unparse()}): SExpression == ({items});") return name - def export_call(self): """ Return the function call doing the export, as a string. @@ -512,8 +504,7 @@ def _eval_matrix(self): [1.3000000000000000000] """ base = self._dom.base() - m = [[SEXEvaluator(e, base).eval() for e in row] - for row in self._ast] + m = [[SEXEvaluator(e, base).eval() for e in row] for row in self._ast] P = self._dom.parent() return P(m) @@ -540,6 +531,7 @@ def _eval_polynomialring(self): P = self._dom.parent(names=names) from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(P, PolynomialRing_generic): def to_exponent(mon): @@ -547,17 +539,15 @@ def to_exponent(mon): return mon[0][1] return 0 - return P._from_dict({to_exponent(mon): SEXEvaluator(c, base).eval() - for mon, c in self._ast}) + return P._from_dict({to_exponent(mon): SEXEvaluator(c, base).eval() for mon, c in self._ast}) def to_tuple(mon): - t = [0]*len(P._names) + t = [0] * len(P._names) for v, e in mon: t[P._names.index(v)] = e return tuple(t) - return P._from_dict({to_tuple(mon): SEXEvaluator(c, base).eval() - for mon, c in self._ast}) + return P._from_dict({to_tuple(mon): SEXEvaluator(c, base).eval() for mon, c in self._ast}) def _eval_factorization(self): r""" @@ -578,13 +568,10 @@ def _eval_factorization(self): -1 * 2^4 * 3 """ from sage.structure.factorization import Factorization + base = self._dom.base() unit, factors = self._ast - return Factorization([(SEXEvaluator(f, base).eval(), e) - for f, e in factors], - unit=SEXEvaluator(unit, base).eval(), - sort=False, - simplify=False) + return Factorization([(SEXEvaluator(f, base).eval(), e) for f, e in factors], unit=SEXEvaluator(unit, base).eval(), sort=False, simplify=False) def _eval_sr_aux(self): r""" @@ -690,6 +677,7 @@ def convert_rootOf(x, y): # postprocessing of rootOf from sage.rings.qqbar import QQbar from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + while rootOf: for var, poly in rootOf.items(): pvars = poly.variables() @@ -717,9 +705,7 @@ def convert_rootOf(x, y): # we just need any root per FriCAS specification rootOf_ev[var] = poly.any_root() - return ex.subs({var: (val.radical_expression() - if val.parent() is QQbar else val) - for var, val in rootOf_ev.items()}) + return ex.subs({var: (val.radical_expression() if val.parent() is QQbar else val) for var, val in rootOf_ev.items()}) class LazyParent: @@ -772,18 +758,10 @@ def base(self): """ head = self.head() args = self.args() - if head in ["List", - "Fraction", - "Matrix", - "Polynomial", - "Factored", - "Vector"]: + if head in ["List", "Fraction", "Matrix", "Polynomial", "Factored", "Vector"]: return LazyParent(args[0]) - if head in ["UnivariatePolynomial", - "MultivariatePolynomial", - "DistributedMultivariatePolynomial", - "DirectProduct"]: + if head in ["UnivariatePolynomial", "MultivariatePolynomial", "DistributedMultivariatePolynomial", "DirectProduct"]: return LazyParent(args[1]) raise NotImplementedError(f"Cannot build base for {head}") @@ -810,59 +788,65 @@ def parent(self, **kwargs): if head in ["Vector", "DirectProduct"]: from sage.modules.free_module_element import vector + return vector if head in ["Matrix", "RectangularMatrix", "SquareMatrix"]: from sage.matrix.constructor import matrix + return matrix if head in ["FiniteField", "PrimeField"]: from sage.rings.finite_rings.finite_field_constructor import GF + return GF(*args) if head == "IntegerMod": from sage.rings.finite_rings.integer_mod_ring import IntegerModRing + return IntegerModRing(*args) if head in ["Integer", "PositiveInteger", "NonNegativeInteger"]: from sage.rings.integer_ring import ZZ + return ZZ if head == "AlgebraicNumber": from sage.rings.qqbar import QQbar + return QQbar if head == "Expression": from sage.symbolic.ring import SR + return SR if head == "Float": from sage.rings.real_mpfr import RealField + return RealField(kwargs["prec"]) if head == "Fraction": from sage.rings.fraction_field import FractionField + base = self.base().parent(**kwargs) return FractionField(base) - if head in ["UnivariatePolynomial", - "MultivariatePolynomial", - "DistributedMultivariatePolynomial"]: + if head in ["UnivariatePolynomial", "MultivariatePolynomial", "DistributedMultivariatePolynomial"]: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + base = self.base().parent(**kwargs) return PolynomialRing(base, args[0]) if head == "Polynomial": from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + base = self.base().parent(**kwargs) if not hasattr(self, "_polynomial_symbols"): self._polynomial_symbols = [] - self._polynomial_symbols = sorted(set(list(kwargs.get("names", [])) - + self._polynomial_symbols)) + self._polynomial_symbols = sorted(set(list(kwargs.get("names", [])) + self._polynomial_symbols)) # we always want a multivariate polynomial ring here - return PolynomialRing(base, - len(self._polynomial_symbols), - names=self._polynomial_symbols) + return PolynomialRing(base, len(self._polynomial_symbols), names=self._polynomial_symbols) raise NotImplementedError(f"Cannot build parent for {head}") @@ -972,12 +956,10 @@ def _parse_atom(self): a = self._start b = len(self._s) - while (a < b - and self._s[a] not in self._WHITESPACE - and self._s[a] != self._RIGHTBRACKET): + while a < b and self._s[a] not in self._WHITESPACE and self._s[a] != self._RIGHTBRACKET: a += 1 - token = self._s[self._start:a] + token = self._s[self._start : a] self._start = a - 1 try: return Integer(token) diff --git a/src/sage/interfaces/frobby.py b/src/sage/interfaces/frobby.py index 75200dc0694..e2fa05edbe0 100644 --- a/src/sage/interfaces/frobby.py +++ b/src/sage/interfaces/frobby.py @@ -170,7 +170,7 @@ def hilbert(self, monomial_ideal): resul = 0 for l in lines: lis = [int(_) for _ in l.split()] - resul += lis[0]+prod([ring.gen(i)**lis[i+1] for i in range(len(lis)-1)]) + resul += lis[0] + prod([ring.gen(i) ** lis[i + 1] for i in range(len(lis) - 1)]) return resul def associated_primes(self, monomial_ideal): @@ -204,7 +204,8 @@ def associated_primes(self, monomial_ideal): lists = [[int(_) for _ in a.split()] for a in lines] def to_monomial(exps): - return [v ** e for v, e in zip(monomial_ideal.ring().gens(), exps) if e != 0] + return [v**e for v, e in zip(monomial_ideal.ring().gens(), exps) if e != 0] + return [monomial_ideal.ring().ideal(to_monomial(a)) for a in lists] def dimension(self, monomial_ideal): @@ -323,19 +324,20 @@ def _parse_ideals(self, string, ring): if lines[0].split()[1] == 'ring': lines.pop(0) lines.pop(0) - matrices.append('1 '+str(ring.ngens())+'\n'+'0 '*ring.ngens()+'\n') + matrices.append('1 ' + str(ring.ngens()) + '\n' + '0 ' * ring.ngens() + '\n') else: nrows = int(lines[0].split()[0]) - nmatrix = lines.pop(0)+'\n' + nmatrix = lines.pop(0) + '\n' for i in range(nrows): - nmatrix += lines.pop(0)+'\n' + nmatrix += lines.pop(0) + '\n' matrices.append(nmatrix) def to_ideal(exps): if len(exps) == 0: return ring.zero_ideal() - gens = [prod([v ** e for v, e in zip(ring.gens(), expo) if e != 0]) for expo in exps] + gens = [prod([v**e for v, e in zip(ring.gens(), expo) if e != 0]) for expo in exps] return ring.ideal(gens or ring(1)) + return [to_ideal(self._parse_4ti2_matrix(a)) for a in matrices] or [ring.ideal()] def _parse_4ti2_matrix(self, string): @@ -376,8 +378,7 @@ def _parse_4ti2_matrix(self, string): except ValueError: raise RuntimeError("Format error: encountered non-number.") if len(ints) < 2: - raise RuntimeError("Format error: " + - "matrix dimensions not specified.") + raise RuntimeError("Format error: " + "matrix dimensions not specified.") term_count = ints[0] var_count = ints[1] diff --git a/src/sage/interfaces/gap.py b/src/sage/interfaces/gap.py index da29955cec1..ec87f084ced 100644 --- a/src/sage/interfaces/gap.py +++ b/src/sage/interfaces/gap.py @@ -251,6 +251,7 @@ def gap_command(use_workspace_cache=True, local=True): # ########### Classes with methods for both the GAP3 and GAP4 interface + class Gap_generic(ExtraTabCompletion, Expect): r""" Generic interface to the GAP3/GAP4 interpreters. @@ -262,6 +263,7 @@ class Gap_generic(ExtraTabCompletion, Expect): - Franco Saliola (Feb 2010): refactored to separate out the generic code """ + _identical_function = "IsIdenticalObj" def _synchronize(self, timeout=0.5, cmd='%s;'): @@ -290,6 +292,7 @@ def _synchronize(self, timeout=0.5, cmd='%s;'): return E = self._expect from sage.misc.prandom import randrange + rnd = randrange(2147483647) cmd = str(rnd) + ';' try: @@ -456,8 +459,7 @@ def load_package(self, pkg, verbose=False): print("Loading GAP package {}".format(pkg)) x = self.eval('LoadPackage("{}")'.format(pkg)) if x == 'fail': - raise RuntimeError("Error loading Gap package " + str(pkg) + ". " + - "You may want to install gap_packages SPKG.") + raise RuntimeError("Error loading Gap package " + str(pkg) + ". " + "You may want to install gap_packages SPKG.") def eval(self, x, newlines=False, strip=True, split_lines=True, **kwds): r""" @@ -546,18 +548,16 @@ def _execute_line(self, line, wait_for_prompt=True, expect_eof=False): if len(line) == 0: return (b'', b'') try: - terminal_echo = [] # to be discarded + terminal_echo = [] # to be discarded normal_outputs = [] # GAP stdout - error_outputs = [] # GAP stderr + error_outputs = [] # GAP stderr current_outputs = terminal_echo while True: x = E.expect_list(self._compiled_full_pattern) current_outputs.append(E.before) - if x == 0: # @p + if x == 0: # @p if E.after != b'@p1.': - warnings.warn( - "possibly wrong version of GAP package " - "interface. Crossing fingers and continuing.") + warnings.warn("possibly wrong version of GAP package " "interface. Crossing fingers and continuing.") elif x == 1: # @@ current_outputs.append(b'@') elif x == 2: # special char @@ -577,7 +577,7 @@ def _execute_line(self, line, wait_for_prompt=True, expect_eof=False): elif x == 8: # @i awaiting normal input break elif x == 9: # @m finished running a child - pass # there is no need to do anything + pass # there is no need to do anything elif x == 10: # @n normal output line current_outputs = normal_outputs elif x == 11: # @r echoing input @@ -695,8 +695,7 @@ def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if if allow_use_file and wait_for_prompt and len(line) > self._eval_using_file_cutoff: return self._eval_line_using_file(line) - (normal, error) = self._execute_line(line, wait_for_prompt=wait_for_prompt, - expect_eof=expect_eof) + (normal, error) = self._execute_line(line, wait_for_prompt=wait_for_prompt, expect_eof=expect_eof) # The internal method _execute_line returns bytes but the bytes it # returns should contain text (any terminal commands and other @@ -886,9 +885,7 @@ def function_call(self, function, args=None, kwds=None): # value, then that value will be in 'last', otherwise it will # be the marker. marker = '__SAGE_LAST__:="__SAGE_LAST__";;' - cmd = "%s(%s);;" % (function, ",".join([s.name() for s in args] + - [f'{key}={value.name()}' - for key, value in kwds.items()])) + cmd = "%s(%s);;" % (function, ",".join([s.name() for s in args] + [f'{key}={value.name()}' for key, value in kwds.items()])) if len(marker) + len(cmd) <= self._eval_using_file_cutoff: # We combine the two commands so we only run eval() once and the # only output would be from the second command @@ -900,6 +897,7 @@ def function_call(self, function, args=None, kwds=None): return self.new('last2;') if res.strip(): from sage.interfaces.interface import AsciiArtString + return AsciiArtString(res) def get_record_element(self, record, name): @@ -945,6 +943,7 @@ class GapElement_generic(ModuleElement, ExtraTabCompletion, ExpectElement): - Franco Saliola (Feb 2010): refactored to separate out the generic code """ + def _add_(self, other): """ EXAMPLES:: @@ -1050,9 +1049,9 @@ def _matrix_(self, R): m = int(v[2]) from sage.matrix.matrix_space import MatrixSpace + M = MatrixSpace(R, n, m) - entries = [[R(self[r, c]) for c in range(1, m + 1)] - for r in range(1, n + 1)] + entries = [[R(self[r, c]) for c in range(1, m + 1)] for r in range(1, n + 1)] return M(entries) @@ -1064,14 +1063,8 @@ class Gap(Gap_generic): - William Stein and David Joyner """ - def __init__(self, max_workspace_size=None, - maxread=None, script_subdirectory=None, - use_workspace_cache=True, - server=None, - server_tmpdir=None, - logfile=None, - seed=None, - env={}): + + def __init__(self, max_workspace_size=None, maxread=None, script_subdirectory=None, use_workspace_cache=True, server=None, server_tmpdir=None, logfile=None, seed=None, env={}): """ EXAMPLES:: @@ -1089,21 +1082,9 @@ def __init__(self, max_workspace_size=None, # -T: disable interactive break loop when encountering errors # -E: disable readline support cmd += " -b -p -T -E" - cmd += ' -m 64m ' # attempt at a workaround for http://tracker.gap-system.org/issues/224 + cmd += ' -m 64m ' # attempt at a workaround for http://tracker.gap-system.org/issues/224 cmd += ' ' + os.path.join(SAGE_EXTCODE, 'gap', 'sage.g') - Expect.__init__(self, - name='gap', - prompt='gap> ', - command=cmd, - maxread=maxread, - server=server, - server_tmpdir=server_tmpdir, - script_subdirectory=script_subdirectory, - restart_on_ctrlc=True, - verbose_start=False, - logfile=logfile, - eval_using_file_cutoff=100, - env=env) + Expect.__init__(self, name='gap', prompt='gap> ', command=cmd, maxread=maxread, server=server, server_tmpdir=server_tmpdir, script_subdirectory=script_subdirectory, restart_on_ctrlc=True, verbose_start=False, logfile=logfile, eval_using_file_cutoff=100, env=env) self.__seq = 0 self._seed = seed @@ -1180,6 +1161,7 @@ def _start(self): """ if self.__use_workspace_cache: from sage.libs.gap.saved_workspace import timestamp + try: # Check to see if we need to auto-regenerate the gap # workspace, i.e., if the gap script is more recent @@ -1212,9 +1194,7 @@ def _start(self): if self.__use_workspace_cache and self.__make_workspace: self.save_workspace() # Now, as self._expect exists, we can compile some useful pattern: - self._compiled_full_pattern = self._expect.compile_pattern_list([ - r'@p\d+\.', '@@', '@[A-Z]', r'@[123456!"#$%&][^+]*\+', - '@e', '@c', '@f', '@h', '@i', '@m', '@n', '@r', r'@s\d', r'@w.*\+', '@x', '@z']) + self._compiled_full_pattern = self._expect.compile_pattern_list([r'@p\d+\.', '@@', '@[A-Z]', r'@[123456!"#$%&][^+]*\+', '@e', '@c', '@f', '@h', '@i', '@m', '@n', '@r', r'@s\d', r'@w.*\+', '@x', '@z']) # read everything up to the first "ready" prompt self._expect.expect("@i") @@ -1286,6 +1266,7 @@ def save_workspace(self): # be included in the body of a loop or function, or called from a # break loop. from sage.misc.temporary_file import atomic_write + with atomic_write(WORKSPACE) as f: f.close() self.eval('SaveWorkspace("%s");' % (f.name), allow_use_file=False) @@ -1327,11 +1308,11 @@ def help(self, s, pager=True): sline = int(sline) - 1 if self.is_remote(): self._get_tmpfile() - with open(self._local_tmpfile(), - encoding=gap_encoding) as fobj: + with open(self._local_tmpfile(), encoding=gap_encoding) as fobj: help = fobj.read() if pager: from IPython.core.page import page + page(help, start=sline) else: # Find the n-th line and return from there @@ -1484,8 +1465,7 @@ def _tab_completion(self): sage: 'Order' in c True """ - names = eval(self.eval('NamesSystemGVars()')) + \ - eval(self.eval('NamesUserGVars()')) + names = eval(self.eval('NamesSystemGVars()')) + eval(self.eval('NamesUserGVars()')) return [n for n in names if n[0] in string.ascii_letters] @@ -1545,8 +1525,7 @@ def __getitem__(self, n): self._check_valid() if not isinstance(n, tuple): return self.parent().new('%s[%s]' % (self._name, n)) - return self.parent().new('%s%s' % (self._name, - ''.join('[%s]' % x for x in n))) + return self.parent().new('%s%s' % (self._name, ''.join('[%s]' % x for x in n))) def str(self, use_file=False): """ @@ -1569,6 +1548,7 @@ def _latex_(self): \left[\left[1, 2\right], \left[\frac{3}{4}, \frac{5}{6}\right]\right] """ from sage.misc.latex import latex + return latex(self._sage_()) @cached_method @@ -1589,8 +1569,7 @@ def _tab_completion(self): v = v.replace('Tester(', '').replace('Setter(', '').replace(')', '').replace('\n', '') v = v.split(',') v = (oper.split('"')[1] for oper in v) - v = [oper for oper in v - if all(ch in string.ascii_letters for ch in oper)] + v = [oper for oper in v if all(ch in string.ascii_letters for ch in oper)] return sorted(set(v)) @@ -1678,13 +1657,13 @@ def gfq_gap_to_sage(x, F): return F(0) i1 = s.index("(") i2 = s.index(")") - q = eval(s[i1 + 1:i2].replace('^', '**')) + q = eval(s[i1 + 1 : i2].replace('^', '**')) if not F.cardinality().is_power_of(q): raise ValueError('%r has no subfield of size %r' % (F, q)) if s.find(')^') == -1: e = 1 else: - e = int(s[i2 + 2:]) + e = int(s[i2 + 2 :]) if F.degree() == 1: g = F(gap.eval('Int(Z(%s))' % q)) elif F.is_conway(): @@ -1734,6 +1713,7 @@ def intmod_gap_to_sage(x): from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.rings.finite_rings.integer_mod import Mod from sage.rings.integer import Integer + s = str(x) m = re.search(r'Z\(([0-9]*)\)', s) if m: @@ -1795,6 +1775,7 @@ def gap_console(): True """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%gap magics instead.') cmd, _ = gap_command(use_workspace_cache=False) diff --git a/src/sage/interfaces/gap3.py b/src/sage/interfaces/gap3.py index aaf9df549f9..0167afa23b8 100644 --- a/src/sage/interfaces/gap3.py +++ b/src/sage/interfaces/gap3.py @@ -288,6 +288,7 @@ class Gap3(Gap_generic): - Franco Saliola (Feb 2010) """ + _identical_function = "IsIdentical" def __init__(self, command=gap3_cmd): @@ -319,22 +320,7 @@ def __init__(self, command=gap3_cmd): # -y -- sets the number of lines of the terminal; controls how many # lines of text are output by GAP3 before the pager is invoked. # This option is useful in dealing with the GAP3 help system. - Expect.__init__(self, - name='gap3', - prompt='gap> ', - command=self.__gap3_command_string + " -p -b -y 500", - server=None, - ulimit=None, - script_subdirectory=None, - restart_on_ctrlc=True, - verbose_start=False, - init_code=[], - max_startup_time=None, - logfile=None, - eval_using_file_cutoff=100, - do_cleaner=True, - remote_cleaner=False, - path=None) + Expect.__init__(self, name='gap3', prompt='gap> ', command=self.__gap3_command_string + " -p -b -y 500", server=None, ulimit=None, script_subdirectory=None, restart_on_ctrlc=True, verbose_start=False, init_code=[], max_startup_time=None, logfile=None, eval_using_file_cutoff=100, do_cleaner=True, remote_cleaner=False, path=None) def _start(self): r""" @@ -361,9 +347,7 @@ def _start(self): # The -p command-line option to GAP3 produces the following # funny-looking patterns in the interface. We compile the patterns # now, and use them later for interpreting interface messages. - self._compiled_full_pattern = self._expect.compile_pattern_list([ - r'@p\d+\.', '@@', '@[A-Z]', r'@[123456!"#$%&][^+]*\+', '@e', '@c', - '@f', '@h', '@i', '@m', '@n', '@r', r'@s\d', r'@w.*\+', '@x', '@z']) + self._compiled_full_pattern = self._expect.compile_pattern_list([r'@p\d+\.', '@@', '@[A-Z]', r'@[123456!"#$%&][^+]*\+', '@e', '@c', '@f', '@h', '@i', '@m', '@n', '@r', r'@s\d', r'@w.*\+', '@x', '@z']) self._compiled_small_pattern = self._expect.compile_pattern_list('@J') self._expect.expect("@i") @@ -426,8 +410,7 @@ def _execute_line(self, line, wait_for_prompt=True, expect_eof=False): # It seems that GAP3 does not classify syntax errors as regular error # messages, so the generic GAP interface processing code does not # detect it. So we test for a syntax error explicitly. - normal_output, error_output = \ - super()._execute_line(line, wait_for_prompt=True, expect_eof=False) + normal_output, error_output = super()._execute_line(line, wait_for_prompt=True, expect_eof=False) normal = bytes_to_str(normal_output) if normal.startswith("Syntax error:"): normal_output, error_output = "", normal_output @@ -474,6 +457,7 @@ def help(self, topic, pager=True): """ import pexpect + if self._expect is None: self._start() E = self._expect @@ -510,6 +494,7 @@ def help(self, topic, pager=True): helptext = "".join(bytes_to_str(line) for line in helptext).strip() if pager is True: from sage.misc.pager import pager as pag + pag()(helptext) else: print(helptext) @@ -594,7 +579,8 @@ def _install_hints(self): - If you do not have GAP3 installed, then you must either... """ - return r""" + return ( + r""" Your attempt to start GAP3 failed, either because you do not have have GAP3 installed, or because it is not configured correctly. @@ -618,7 +604,9 @@ def _install_hints(self): to point Sage to the correct command for your system. gap3 = Gap3(command='/usr/local/bin/gap3') - """ % self.__gap3_command_string + """ + % self.__gap3_command_string + ) @cached_method def _tab_completion(self): @@ -688,6 +676,7 @@ class GAP3Element(GapElement_generic): - Franco Saliola (Feb 2010) """ + def __init__(self, parent, value, is_name=False, name=None): r""" See ``GAP3Element`` for full documentation. @@ -742,8 +731,7 @@ def __getitem__(self, n): gap3_session = self._check_valid() if not isinstance(n, tuple): return gap3_session.new('%s[%s]' % (self.name(), n)) - return gap3_session.new('%s%s' % (self.name(), - ''.join('[%s]' % x for x in n))) + return gap3_session.new('%s%s' % (self.name(), ''.join('[%s]' % x for x in n))) def _latex_(self): r""" @@ -780,6 +768,7 @@ class GAP3Record(GAP3Element): - Franco Saliola (Feb 2010) """ + def recfields(self): r""" Return a list of the fields for the record. (Record fields are akin @@ -911,6 +900,7 @@ def gap3_console(): gap> """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%gap3 magics instead.') os.system(gap3_cmd) diff --git a/src/sage/interfaces/gap_workspace.py b/src/sage/interfaces/gap_workspace.py index c7df7ffaed1..a2cb09eea07 100644 --- a/src/sage/interfaces/gap_workspace.py +++ b/src/sage/interfaces/gap_workspace.py @@ -124,7 +124,7 @@ def prepare_workspace_dir(dir=None): W = os.path.join(dir, F) try: age = now - os.path.getatime(W) - if age >= 604800: # 1 week in seconds + if age >= 604800: # 1 week in seconds os.unlink(W) except OSError: # It's not a problem if W doesn't exist, everything diff --git a/src/sage/interfaces/genus2reduction.py b/src/sage/interfaces/genus2reduction.py index 487287386e6..c3bbe829a9a 100644 --- a/src/sage/interfaces/genus2reduction.py +++ b/src/sage/interfaces/genus2reduction.py @@ -144,8 +144,8 @@ class is R, then the following is the meaning of sur un corps de valuation discrète", Trans. AMS 348 (1996), 4577-4610, Section 7.2, Proposition 4). """ - def __init__(self, pari_result, P, Q, Pmin, Qmin, minimal_disc, - local_data, conductor): + + def __init__(self, pari_result, P, Q, Pmin, Qmin, minimal_disc, local_data, conductor): self.pari_result = pari_result self.P = P self.Q = Q @@ -212,7 +212,7 @@ def divisors_to_string(divs): n = 0 # How many times have we seen the current divisor? for i in range(len(divs)): n += 1 - if i+1 == len(divs) or divs[i+1] != divs[i]: + if i + 1 == len(divs) or divs[i + 1] != divs[i]: # Next divisor is different or we are done? Print current one if s: s += "x" @@ -336,6 +336,7 @@ class Genus2reduction(SageObject): Conrad-Edixhoven-Stein that the component group of `J(X_1(p))` is trivial for all primes `p`.) """ + def __init__(self): pass diff --git a/src/sage/interfaces/gfan.py b/src/sage/interfaces/gfan.py index 00b87f7e6b7..cb7388877d9 100644 --- a/src/sage/interfaces/gfan.py +++ b/src/sage/interfaces/gfan.py @@ -49,6 +49,7 @@ class Gfan: """ Interface to Anders Jensen's Groebner Fan program. """ + def __call__(self, input, cmd='', verbose=False): r""" Call Groebner Fan program with given input. @@ -91,8 +92,7 @@ def __call__(self, input, cmd='', verbose=False): print("gfan command:\n%s" % cmd) print("gfan input:\n%s" % input) - gfan_processes = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE, - encoding='latin-1') + gfan_processes = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE, encoding='latin-1') ans, err = gfan_processes.communicate(input=input) # sometimes, gfan outputs stuff to stderr even though diff --git a/src/sage/interfaces/giac.py b/src/sage/interfaces/giac.py index 96624112bde..1114352f007 100644 --- a/src/sage/interfaces/giac.py +++ b/src/sage/interfaces/giac.py @@ -324,6 +324,7 @@ class Giac(Expect): sage: g.n() 0.577215664901533 """ + def __init__(self, maxread=None, script_subdirectory=None, server=None, server_tmpdir=None, logfile=None): """ Create an instance of the Giac interpreter. @@ -334,19 +335,7 @@ def __init__(self, maxread=None, script_subdirectory=None, server=None, server_t sage: giac == loads(dumps(giac)) True """ - Expect.__init__(self, - name='giac', - prompt='[0-9]*>> ', - command="giac --sage", - env={"LANG": "C"}, - init_code=['maple_mode(0);I:=i;'], # coercion could be broken in maple_mode - script_subdirectory=script_subdirectory, - restart_on_ctrlc=False, - server=server, - server_tmpdir=server_tmpdir, - verbose_start=False, - logfile=logfile, - eval_using_file_cutoff=1000) + Expect.__init__(self, name='giac', prompt='[0-9]*>> ', command="giac --sage", env={"LANG": "C"}, init_code=['maple_mode(0);I:=i;'], script_subdirectory=script_subdirectory, restart_on_ctrlc=False, server=server, server_tmpdir=server_tmpdir, verbose_start=False, logfile=logfile, eval_using_file_cutoff=1000) # coercion could be broken in maple_mode def _function_class(self): """ @@ -369,7 +358,7 @@ def _keyboard_interrupt(self): print("Interrupting %s..." % self) self._expect.sendline(chr(3)) # send ctrl-c self._expect.expect(self._prompt) -# self._expect.expect(self._prompt) + # self._expect.expect(self._prompt) raise RuntimeError("Ctrl-c pressed while running %s" % self) def __reduce__(self): @@ -530,8 +519,7 @@ def _commands(self): True """ try: - v = sum([self.completions(chr(65 + n)) for n in range(26)], []) + \ - sum([self.completions(chr(97 + n)) for n in range(26)], []) + v = sum([self.completions(chr(65 + n)) for n in range(26)], []) + sum([self.completions(chr(97 + n)) for n in range(26)], []) except RuntimeError: print("\n" * 3) print("*" * 70) @@ -558,6 +546,7 @@ def _tab_completion(self, verbose=True, use_disk_cache=True): return self.__tab_completion except AttributeError: import sage.misc.persist + if use_disk_cache: try: self.__tab_completion = sage.misc.persist.load(COMMANDS_CACHE) @@ -616,12 +605,10 @@ def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if True """ with gc_disabled(): - z = Expect._eval_line(self, line, allow_use_file=allow_use_file, - wait_for_prompt=wait_for_prompt) + z = Expect._eval_line(self, line, allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt) if z.lower().find("error") != -1: raise RuntimeError("an error occurred running a Giac command:\nINPUT:\n%s\nOUTPUT:\n%s" % (line, z)) - lines = (line for line in z.splitlines() - if not line.startswith('Evaluation time:')) + lines = (line for line in z.splitlines() if not line.startswith('Evaluation time:')) return "\n".join(lines) def eval(self, code, strip=True, **kwds): @@ -923,20 +910,18 @@ def _richcmp_(self, other, op): False """ P = self.parent() - if P.eval("evalb(%s %s %s)" % (self.name(), P._equality_symbol(), - other.name())) == P._true_symbol(): + if P.eval("evalb(%s %s %s)" % (self.name(), P._equality_symbol(), other.name())) == P._true_symbol(): return rich_to_bool(op, 0) # (to be tested with giac). Maple does not allow comparing objects # of different types and it raises an error in this case. # We catch the error, and return True for < try: - if P.eval("evalb(%s %s %s)" % (self.name(), P._lessthan_symbol(), - other.name())) == P._true_symbol(): + if P.eval("evalb(%s %s %s)" % (self.name(), P._lessthan_symbol(), other.name())) == P._true_symbol(): return rich_to_bool(op, -1) except RuntimeError as e: msg = str(e) if 'is not valid' in msg and 'to < or <=' in msg: - if (hash(str(self)) < hash(str(other))): + if hash(str(self)) < hash(str(other)): return rich_to_bool(op, -1) return rich_to_bool(op, 1) raise RuntimeError(e) @@ -1045,6 +1030,7 @@ def _matrix_(self, R): m = int(v[1]) from sage.matrix.matrix_space import MatrixSpace + M = MatrixSpace(R, n, m) entries = [[R(self[r, c]) for c in range(m)] for r in range(n)] return M(entries) @@ -1135,9 +1121,7 @@ def _sage_(self, locals=None): lsymbols.update(locals) try: - return symbolic_expression_from_string(result, lsymbols, - accept_sequence=True, - parser=SR_parser_giac) + return symbolic_expression_from_string(result, lsymbols, accept_sequence=True, parser=SR_parser_giac) except Exception: raise NotImplementedError("unable to parse Giac output: %s" % result) else: @@ -1176,8 +1160,7 @@ def integral(self, var='x', min=None, max=None): return giac('int(%s,%s)' % (self.name(), var)) if max is None: raise ValueError("neither or both of min/max must be specified") - return giac('int(%s,%s,%s,%s)' % (self.name(), var, - giac(min), giac(max))) + return giac('int(%s,%s,%s,%s)' % (self.name(), var, giac(min), giac(max))) integrate = integral @@ -1205,8 +1188,7 @@ def sum(self, var, min=None, max=None): return giac('sum(%s,%s)' % (self.name(), var)) if max is None: raise ValueError("neither or both of min/max must be specified") - return giac('sum(%s,%s,%s,%s)' % (self.name(), var, - giac(min), giac(max))) + return giac('sum(%s,%s,%s,%s)' % (self.name(), var, giac(min), giac(max))) # An instance @@ -1242,6 +1224,7 @@ def giac_console(): Type ?commandname for help """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%giac magics instead.') os.system('giac') @@ -1260,4 +1243,5 @@ def __doctest_cleanup(): False """ import sage.interfaces.quit + sage.interfaces.quit.expect_quitall() diff --git a/src/sage/interfaces/gnuplot.py b/src/sage/interfaces/gnuplot.py index f9ddc8da914..ceb640cfe05 100644 --- a/src/sage/interfaces/gnuplot.py +++ b/src/sage/interfaces/gnuplot.py @@ -26,6 +26,7 @@ class Gnuplot(SageObject): """ Interface to the Gnuplot interpreter. """ + def _quit_string(self): return 'quit' @@ -35,6 +36,7 @@ def gnuplot(self): except AttributeError: try: import Gnuplot as GP + self._gnuplot = GP.Gnuplot() return self._gnuplot except ImportError: @@ -100,10 +102,7 @@ def plot(self, cmd, file=None, verbose=True, reset=True): time.sleep(0.1) self('set terminal x11') - def plot3d(self, f, xmin=-1, xmax=1, ymin=-1, ymax=1, zmin=-1, zmax=1, - title=None, - samples=25, isosamples=20, xlabel='x', ylabel='y', - interact=True): + def plot3d(self, f, xmin=-1, xmax=1, ymin=-1, ymax=1, zmin=-1, zmax=1, title=None, samples=25, isosamples=20, xlabel='x', ylabel='y', interact=True): if title is None: title = str(f) f = f.replace('^', '**') @@ -122,19 +121,24 @@ def plot3d(self, f, xmin=-1, xmax=1, ymin=-1, ymax=1, zmin=-1, zmax=1, #show pm3d #show palette splot %s - """ % (xlabel, ylabel, - xmin, xmax, ymin, ymax, # zmin, zmax, - samples, isosamples, - title, f) + """ % ( + xlabel, + ylabel, + xmin, + xmax, + ymin, + ymax, # zmin, zmax, + samples, + isosamples, + title, + f, + ) if interact: self.interact(cmd) else: self(cmd) - def plot3d_parametric(self, f='cos(u)*(3 + v*cos(u/2)), sin(u)*(3 + v*cos(u/2)), v*sin(u/2)', - range1='[u=-pi:pi]', - range2='[v=-0.2:0.2]', samples=50, title=None, - interact=True): + def plot3d_parametric(self, f='cos(u)*(3 + v*cos(u/2)), sin(u)*(3 + v*cos(u/2)), v*sin(u/2)', range1='[u=-pi:pi]', range2='[v=-0.2:0.2]', samples=50, title=None, interact=True): r""" Draw a parametric 3d surface and rotate it interactively. @@ -167,7 +171,13 @@ def plot3d_parametric(self, f='cos(u)*(3 + v*cos(u/2)), sin(u)*(3 + v*cos(u/2)), set title "%s" set pm3d; set palette; set parametric splot %s %s %s - """ % (samples, title, range1, range2, f) + """ % ( + samples, + title, + range1, + range2, + f, + ) cmd = cmd.replace('^', '**') if interact: self.interact(cmd) @@ -176,6 +186,7 @@ def plot3d_parametric(self, f='cos(u)*(3 + v*cos(u/2)), sin(u)*(3 + v*cos(u/2)), def interact(self, cmd): import tempfile + with tempfile.NamedTemporaryFile(mode='w+t') as f: f.write(cmd + '\n pause -1 "Press return to continue (no further rotation possible)"') os.system(f'gnuplot -persist {f.name}') @@ -190,6 +201,7 @@ def console(self): def gnuplot_console(): from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%gnuplot magics instead.') os.system('gnuplot') diff --git a/src/sage/interfaces/gp.py b/src/sage/interfaces/gp.py index e9d005c73dd..6fba791260f 100644 --- a/src/sage/interfaces/gp.py +++ b/src/sage/interfaces/gp.py @@ -187,13 +187,8 @@ class Gp(ExtraTabCompletion, Expect): sage: Gp() PARI/GP interpreter """ - def __init__(self, stacksize=10000000, # 10MB - maxread=None, script_subdirectory=None, - logfile=None, - server=None, - server_tmpdir=None, - init_list_length=1024, - seed=None): + + def __init__(self, stacksize=10000000, maxread=None, script_subdirectory=None, logfile=None, server=None, server_tmpdir=None, init_list_length=1024, seed=None): # 10MB """ Initialization of this PARI gp interpreter. @@ -218,19 +213,21 @@ def __init__(self, stacksize=10000000, # 10MB sage: gp == loads(dumps(gp)) True """ - Expect.__init__(self, - name='pari', - prompt='\\? ', - # --fast so the system gprc isn't read (we configure below) - command=f"gp --fast --emacs --quiet --stacksize {stacksize}", - maxread=maxread, - server=server, - server_tmpdir=server_tmpdir, - script_subdirectory=script_subdirectory, - restart_on_ctrlc=False, - verbose_start=False, - logfile=logfile, - eval_using_file_cutoff=1024) + Expect.__init__( + self, + name='pari', + prompt='\\? ', + # --fast so the system gprc isn't read (we configure below) + command=f"gp --fast --emacs --quiet --stacksize {stacksize}", + maxread=maxread, + server=server, + server_tmpdir=server_tmpdir, + script_subdirectory=script_subdirectory, + restart_on_ctrlc=False, + verbose_start=False, + logfile=logfile, + eval_using_file_cutoff=1024, + ) self.__seq = 0 self.__var_store_len = 0 self.__init_list_length = init_list_length @@ -455,16 +452,13 @@ def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if line = line.strip() if len(line) == 0: return '' - a = Expect._eval_line(self, line, - allow_use_file=allow_use_file, - wait_for_prompt=wait_for_prompt) + a = Expect._eval_line(self, line, allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt) if a.find("the PARI stack overflows") != -1: verbose("automatically doubling the PARI stack and re-executing current input line") b = self.eval("allocatemem()") if b.find("Warning: not enough memory") != -1: raise RuntimeError(a) - return self._eval_line(line, allow_use_file=allow_use_file, - wait_for_prompt=wait_for_prompt) + return self._eval_line(line, allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt) return a def cputime(self, t=None): @@ -855,6 +849,7 @@ class GpElement(ExpectElement, sage.interfaces.abc.GpElement): The two elliptic curves look the same, but internally the floating point numbers are slightly different. """ + def _reduce(self): """ Return the string representation of self, for pickling. @@ -1070,9 +1065,9 @@ def gp_console(): (readline v6.0 enabled, extended help enabled) """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): - raise RuntimeError('Can use the console only in the terminal. ' - 'Try %%gp magics instead.') + raise RuntimeError('Can use the console only in the terminal. ' 'Try %%gp magics instead.') os.system('gp') @@ -1085,7 +1080,7 @@ def gp_version(): """ v = gp.eval(r'\v') i = v.find("Version ") - w = v[i + len("Version "):] + w = v[i + len("Version ") :] i = w.find(' ') w = w[:i] t = tuple([int(n) for n in w.split('.')]) diff --git a/src/sage/interfaces/interface.py b/src/sage/interfaces/interface.py index 2246ed11315..254c3654aa3 100644 --- a/src/sage/interfaces/interface.py +++ b/src/sage/interfaces/interface.py @@ -67,6 +67,7 @@ class Interface(WithEqualityById, ParentWithBase): representations of objects in interfaces works correctly). Otherwise they are never equal. """ + def __init__(self, name): """ Initialize ``self``. @@ -128,12 +129,15 @@ def rand_seed(self): 365260051 """ import sage.doctest + if sage.doctest.DOCTEST_MODE: # set the random seed through the current randstate from sage.misc.randstate import current_randstate + seed = current_randstate().seed() else: from sage.misc.randstate import randstate + seed = randstate().seed() return seed & 0x1FFFFFFF @@ -183,6 +187,7 @@ def interact(self): in from sage to the interpreter. """ from sage.repl.interpreter import interface_shell_embed + shell = interface_shell_embed(self) try: ipython = get_ipython() @@ -345,12 +350,15 @@ def _coerce_impl(self, x, use_special=True): return self(self._true_symbol() if x else self._false_symbol()) if isinstance(x, int): from sage.rings.integer import Integer + return self(Integer(x)) if isinstance(x, float): from sage.rings.real_double import RDF + return self(RDF(x)) if isinstance(x, complex): from sage.rings.complex_double import CDF + return self(CDF(x)) if use_special: try: @@ -372,7 +380,7 @@ def _coerce_impl(self, x, use_special=True): z.append(w) X = ','.join(A) r = self.new('%s%s%s' % (self._left_list_delim(), X, self._right_list_delim())) - r.__sage_list = z # do this to avoid having the entries of the list be garbage collected + r.__sage_list = z # do this to avoid having the entries of the list be garbage collected return r raise TypeError("unable to coerce element into %s" % self.name()) @@ -439,12 +447,7 @@ def _relation_symbols(self): sage: symbols[operator.eq] '==' """ - return {operator.eq: self._equality_symbol(), - operator.ne: self._inequality_symbol(), - operator.lt: self._lessthan_symbol(), - operator.le: "<=", - operator.gt: self._greaterthan_symbol(), - operator.ge: ">="} + return {operator.eq: self._equality_symbol(), operator.ne: self._inequality_symbol(), operator.lt: self._lessthan_symbol(), operator.le: "<=", operator.gt: self._greaterthan_symbol(), operator.ge: ">="} def _exponent_symbol(self) -> str: """ @@ -610,9 +613,7 @@ def function_call(self, function, args=None, kwds=None): """ args, kwds = self._convert_args_kwds(args, kwds) self._check_valid_function_name(function) - s = self._function_call_string(function, - [s.name() for s in args], - ['%s=%s' % (key, value.name()) for key, value in kwds.items()]) + s = self._function_call_string(function, [s.name() for s in args], ['%s=%s' % (key, value.name()) for key, value in kwds.items()]) return self.new(s) def _function_call_string(self, function, args, kwds): @@ -661,6 +662,7 @@ class InterfaceFunction(SageObject): """ Interface function. """ + def __init__(self, parent, name): self._parent = parent self._name = name @@ -687,6 +689,7 @@ class InterfaceFunctionElement(SageObject): """ Interface function element. """ + def __init__(self, obj, name): self._obj = obj self._name = name @@ -716,11 +719,12 @@ class InterfaceElement(Element): """ Interface element. """ + def __init__(self, parent, value, is_name=False, name=None): Element.__init__(self, parent) self._create = value if parent is None: - return # means "invalid element" + return # means "invalid element" # idea: Joe Wetherell -- try to find out if the output # is too long and if so get it using file, otherwise # don't. @@ -946,8 +950,7 @@ def _richcmp_(self, other, op): """ P = self._check_valid() try: - if P.eval("%s %s %s" % (self.name(), P._equality_symbol(), - other.name())) == P._true_symbol(): + if P.eval("%s %s %s" % (self.name(), P._equality_symbol(), other.name())) == P._true_symbol(): return rich_to_bool(op, 0) except RuntimeError: pass @@ -1329,8 +1332,7 @@ def __bool__(self): True """ P = self._check_valid() - cmd = '%s %s %s' % (self._name, P._equality_symbol(), - P._false_symbol()) + cmd = '%s %s %s' % (self._name, P._equality_symbol(), P._false_symbol()) return P.eval(cmd) != P._true_symbol() def __float__(self): @@ -1360,6 +1362,7 @@ def _integer_(self, ZZ=None): 1 """ from sage.rings.integer import Integer + return Integer(repr(self)) def _rational_(self): @@ -1376,6 +1379,7 @@ def _rational_(self): 1/2 """ from sage.rings.rational import Rational + return Rational(repr(self)) def name(self, new_name=None): diff --git a/src/sage/interfaces/jmoldata.py b/src/sage/interfaces/jmoldata.py index babed6a5496..058218b7c10 100644 --- a/src/sage/interfaces/jmoldata.py +++ b/src/sage/interfaces/jmoldata.py @@ -38,6 +38,7 @@ class JmolData(SageObject): Create an animated image file (GIF) if spin is on and put data extracted from a file into a variable/string/structure to return """ + def __init__(self): """ EXAMPLES: @@ -103,13 +104,7 @@ def is_jmol_available(self): return self.is_jvm_available() - def export_image(self, - targetfile, - datafile, # name (path) of data file Jmol can read or script file telling it what to read or load - datafile_cmd='script', # "script" or "load" - image_type='PNG', # PNG, JPG, GIF - figsize=5, - **kwds): + def export_image(self, targetfile, datafile, datafile_cmd='script', image_type='PNG', figsize=5, **kwds): # name (path) of data file Jmol can read or script file telling it what to read or load # "script" or "load" # PNG, JPG, GIF r""" This executes JmolData.jar to make an image file. @@ -182,7 +177,7 @@ def export_image(self, target_native = targetfile launchscript = "" - if (datafile_cmd != 'script'): + if datafile_cmd != 'script': launchscript = "load " launchscript = launchscript + datafile @@ -195,10 +190,7 @@ def export_image(self, env = dict(os.environ) env['LC_ALL'] = 'C' env['LANG'] = 'C' - subprocess.call(["java", "-Xmx512m", "-Djava.awt.headless=true", - "-jar", jmolpath, "-iox", "-g", size_arg, - "-J", launchscript, "-j", imagescript], - stdout=jout, stderr=jout, env=env) + subprocess.call(["java", "-Xmx512m", "-Djava.awt.headless=true", "-jar", jmolpath, "-iox", "-g", size_arg, "-J", launchscript, "-j", imagescript], stdout=jout, stderr=jout, env=env) if not os.path.isfile(targetfile): raise RuntimeError(f"Jmol failed to create file {targetfile}: {Path(scratchout).read_text()}") os.unlink(scratchout) diff --git a/src/sage/interfaces/kash.py b/src/sage/interfaces/kash.py index 6abfdea68eb..55e613c3489 100644 --- a/src/sage/interfaces/kash.py +++ b/src/sage/interfaces/kash.py @@ -419,7 +419,6 @@ unlike for the other interfaces. """ - # **************************************************************************** # Copyright (C) 2005 William Stein # @@ -450,14 +449,8 @@ class Kash(Expect): - William Stein and David Joyner """ - def __init__(self, - max_workspace_size=None, - maxread=None, - script_subdirectory=None, - restart_on_ctrlc=True, - logfile=None, - server=None, - server_tmpdir=None): + + def __init__(self, max_workspace_size=None, maxread=None, script_subdirectory=None, restart_on_ctrlc=True, logfile=None, server=None, server_tmpdir=None): """ INPUT: @@ -470,19 +463,7 @@ def __init__(self, cmd = "kash3 -b -c -d " if max_workspace_size is not None: cmd += " -a %s" % int(max_workspace_size) - Expect.__init__(self, - name='kash', - prompt='kash% ', - command=cmd, - server=server, - server_tmpdir=server_tmpdir, - script_subdirectory=script_subdirectory, - restart_on_ctrlc=True, - verbose_start=False, - logfile=logfile, - eval_using_file_cutoff=100, - init_code=['X:=ZX.1;'] - ) + Expect.__init__(self, name='kash', prompt='kash% ', command=cmd, server=server, server_tmpdir=server_tmpdir, script_subdirectory=script_subdirectory, restart_on_ctrlc=True, verbose_start=False, logfile=logfile, eval_using_file_cutoff=100, init_code=['X:=ZX.1;']) # The above init_code programs around a bug reported by Jack Schmidt self.__seq = 0 @@ -512,14 +493,12 @@ def _eval_line_using_file(self, line): if self.is_remote(): self._send_tmpfile_to_server() tmp_to_use = self._remote_tmpfile() - return self._eval_line(self._read_in_file_command(tmp_to_use), - allow_use_file=False) + return self._eval_line(self._read_in_file_command(tmp_to_use), allow_use_file=False) # Change the default for KASH, since eval using a file doesn't # work except for setting variables. def _eval_line(self, line, allow_use_file=False, wait_for_prompt=True, restart_if_needed=False): - return Expect._eval_line(self, line, allow_use_file=allow_use_file, - wait_for_prompt=wait_for_prompt) + return Expect._eval_line(self, line, allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt) def __reduce__(self): return reduce_load_Kash, tuple([]) @@ -556,7 +535,7 @@ def eval(self, x, newlines=False, strip=True, **kwds): s = Expect.eval(self, x, **kwds) i = s.find('\r\n') if i != -1: - s = s[i + 2:] + s = s[i + 2 :] if newlines: return s return s.replace("\\\n", "") @@ -608,7 +587,7 @@ def _doc(self, V): i = C.find('m') j = C.find(':') try: - n = int(C[i + 1:j]) + n = int(C[i + 1 : j]) except ValueError: full = C else: @@ -664,10 +643,7 @@ def function_call(self, function, args=None, kwds=None): """ args, kwds = self._convert_args_kwds(args, kwds) self._check_valid_function_name(function) - s = self._function_call_string(function, - [s.name() for s in args], - ['%s:=%s' % (key, value.name()) - for key, value in kwds.items()]) + s = self._function_call_string(function, [s.name() for s in args], ['%s:=%s' % (key, value.name()) for key, value in kwds.items()]) return self.new(s) def _function_call_string(self, function, args, kwds): @@ -729,8 +705,7 @@ def __bool__(self): # our boolean conversion also has to test against 0. P = self.parent() - return (P.eval('%s = FALSE' % self.name()) == 'FALSE' and - P.eval('%s = 0' % self.name()) == 'FALSE') + return P.eval('%s = FALSE' % self.name()) == 'FALSE' and P.eval('%s = 0' % self.name()) == 'FALSE' def _sage_(self, locals={}, *args): """ @@ -795,9 +770,9 @@ def reduce_load_Kash(): def kash_console(): from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): - raise RuntimeError('Can use the console only in the terminal. ' - 'Try %%kash magics instead.') + raise RuntimeError('Can use the console only in the terminal. ' 'Try %%kash magics instead.') os.system("kash3 ") @@ -807,4 +782,5 @@ def kash_version(): def __doctest_cleanup(): import sage.interfaces.quit + sage.interfaces.quit.expect_quitall() diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index 8a90f0c424b..e40b703a662 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -13,6 +13,7 @@ as a C library in Sage. Kenzo objects in this interface are nothing but wrappers around ECL objects. """ + # **************************************************************************** # Copyright (C) 2019 Miguel Marco # and Ana Romero @@ -39,64 +40,7 @@ from sage.features.kenzo import Kenzo # defining the auxiliary functions as wrappers over the kenzo ones -kenzo_names = ['add', - 'array-dimensions', - 'basis_aux1', - 'basis_aux1', - 'bicomplex-spectral-sequence', - 'build-finite-ss2', - 'build-mrph-aux', - 'change-sorc-trgt-aux', - 'chcm-mat', - 'chcm-mat2', - 'classifying-space', - 'cmps', - 'convertmatrice', - 'crts-prdc', - 'degr-aux', - 'dffr-aux', - 'dffr_aux1', - 'dgop', - 'dgop-int-ext', - 'dstr-change-sorc-trgt-aux', - 'echcm', - 'eilenberg-moore-spectral-sequence', - 'evaluation-aux1', - 'gmsm', - 'homologie', - 'homotopy-list', - 'idnt-mrph', - 'join', - 'k-z', - 'k-z2', - 'k-zp', - 'kabstractsimplex_aux1', - 'kchaincomplex_aux1', - 'kmorphismchaincomplex_aux1', - 'loop-space', - 'make-array-from-lists', - 'make-array-to-lists', - 'moore', - 'ncol', - 'nlig', - 'nreverse', - 'nth', - 'opps', - 'orgn_aux1', - 'sbtr', - 'serre-spectral-sequence-product', - 'serre-whitehead-spectral-sequence', - 'sfinitesimplicialset_aux1', - 'smash-product', - 'sorc-aux', - 'spectral-sequence-differential-matrix', - 'spectral-sequence-group', - 'sphere', - 'suspension', - 'tnsr-prdc', - 'trgt-aux', - 'wedge', - 'zero-mrph'] +kenzo_names = ['add', 'array-dimensions', 'basis_aux1', 'basis_aux1', 'bicomplex-spectral-sequence', 'build-finite-ss2', 'build-mrph-aux', 'change-sorc-trgt-aux', 'chcm-mat', 'chcm-mat2', 'classifying-space', 'cmps', 'convertmatrice', 'crts-prdc', 'degr-aux', 'dffr-aux', 'dffr_aux1', 'dgop', 'dgop-int-ext', 'dstr-change-sorc-trgt-aux', 'echcm', 'eilenberg-moore-spectral-sequence', 'evaluation-aux1', 'gmsm', 'homologie', 'homotopy-list', 'idnt-mrph', 'join', 'k-z', 'k-z2', 'k-zp', 'kabstractsimplex_aux1', 'kchaincomplex_aux1', 'kmorphismchaincomplex_aux1', 'loop-space', 'make-array-from-lists', 'make-array-to-lists', 'moore', 'ncol', 'nlig', 'nreverse', 'nth', 'opps', 'orgn_aux1', 'sbtr', 'serre-spectral-sequence-product', 'serre-whitehead-spectral-sequence', 'sfinitesimplicialset_aux1', 'smash-product', 'sorc-aux', 'spectral-sequence-differential-matrix', 'spectral-sequence-group', 'sphere', 'suspension', 'tnsr-prdc', 'trgt-aux', 'wedge', 'zero-mrph'] # Now initialize Kenzo. For each string s in kenzo_names, the @@ -105,6 +49,7 @@ # are replaced with underscores to get valid Python identifiers. if Kenzo().is_present(): from sage.env import KENZO_FAS + if KENZO_FAS: ecl_eval("(require :kenzo \"{}\")".format(KENZO_FAS)) else: @@ -393,6 +338,7 @@ def table(self, p, i1, i2, j1, j2): 0 0 0 0 0 """ from sage.misc.table import table + groups = [] for j in range(j2 - j1 + 1): row = [] @@ -411,6 +357,7 @@ class KenzoChainComplex(KenzoObject): Wrapper to Kenzo chain complexes. Kenzo simplicial sets are a particular case of Kenzo chain complexes. """ + def homology(self, n): r""" Return the `n`-th homology group of the chain complex associated to this @@ -744,8 +691,10 @@ def homotopy_group(self, n): You might get wrong answers if it is not. """ if n not in ZZ or n < 2: - raise ValueError("""homotopy groups can only be computed - for dimensions greater than 1""") + raise ValueError( + """homotopy groups can only be computed + for dimensions greater than 1""" + ) lgens = __homotopy_list__(self._kenzo, n).python() if lgens is not None: trgens = [0 if i == 1 else i for i in sorted(lgens)] @@ -778,8 +727,10 @@ def em_spectral_sequence(self): You might get wrong answers if it is not. """ if self.homology(1).invariants(): - raise ValueError("""Eilenberg-Moore spectral sequence implemented - only for 1-reduced simplicial sets""") + raise ValueError( + """Eilenberg-Moore spectral sequence implemented + only for 1-reduced simplicial sets""" + ) return KenzoSpectralSequence(__eilenberg_moore_spectral_sequence__(self._kenzo)) def sw_spectral_sequence(self): @@ -803,8 +754,10 @@ def sw_spectral_sequence(self): Z 0 0 Z 0 """ if self.homology(1).invariants(): - raise ValueError("""Eilenberg-Moore spectral sequence implemented - only for 1-reduced simplicial sets""") + raise ValueError( + """Eilenberg-Moore spectral sequence implemented + only for 1-reduced simplicial sets""" + ) return KenzoSpectralSequence(__serre_whitehead_spectral_sequence__(self._kenzo)) def serre_spectral_sequence(self): @@ -835,8 +788,10 @@ def serre_spectral_sequence(self): You might get wrong answers if it is not. """ if self.homology(1).invariants(): - raise ValueError("""Eilenberg-Moore spectral sequence implemented - only for 1-reduced simplicial sets""") + raise ValueError( + """Eilenberg-Moore spectral sequence implemented + only for 1-reduced simplicial sets""" + ) return KenzoSpectralSequence(__serre_spectral_sequence_product__(self._kenzo)) def wedge(self, other): @@ -1111,7 +1066,7 @@ def SChainComplex(kchaincomplex, start=0, end=15): dffr_i = __chcm_mat2__(kchaincomplex._kenzo, i) nlig = __nlig__(dffr_i).python() ncol = __ncol__(dffr_i).python() - if ((nlig != 0) and (ncol != 0)): + if (nlig != 0) and (ncol != 0): matrices[i] = k2s_matrix(__convertmatrice__(dffr_i)) else: matrices[i] = matrix(nlig, ncol) @@ -1179,8 +1134,7 @@ def KAbstractSimplex(simplex): sage: SAbSm.dimension() == SAbSm2.dimension() True """ - return KenzoObject(__kabstractsimplex_aux1__(simplex.degeneracies(), - 's' + str(hash(simplex)))) + return KenzoObject(__kabstractsimplex_aux1__(simplex.degeneracies(), 's' + str(hash(simplex)))) def KFiniteSimplicialSet(sset): @@ -1219,17 +1173,17 @@ def KFiniteSimplicialSet(sset): Z """ from sage.topology.simplicial_set_constructions import ProductOfSimplicialSets + if isinstance(sset, ProductOfSimplicialSets): f0 = KFiniteSimplicialSet(sset.factor(0)) for f1 in sset.factors()[1:]: f0 = f0.cartesian_product(KFiniteSimplicialSet(f1)) return f0 allcells = sset.cells() - namecells = {c: 'cell_{}_{}'.format(d, allcells[d].index(c)) - for d in allcells for c in allcells[d]} + namecells = {c: 'cell_{}_{}'.format(d, allcells[d].index(c)) for d in allcells for c in allcells[d]} dim = sset.dimension() list_rslt = [namecells[i] for i in sset.n_cells(0)] - if (dim > 0): + if dim > 0: for k in range(1, dim + 1): k_cells = sset.n_cells(k) if k_cells: @@ -1290,9 +1244,7 @@ def SFiniteSimplicialSet(ksimpset, limit): """ list_orgn = __orgn_aux1__(ksimpset._kenzo).python() if __nth__(0, list_orgn).python()[0] == 'CRTS-PRDC': - return SFiniteSimplicialSet( - KenzoSimplicialSet(__nth__(1, list_orgn)), limit).cartesian_product( - SFiniteSimplicialSet(KenzoSimplicialSet(__nth__(2, list_orgn)), limit)) + return SFiniteSimplicialSet(KenzoSimplicialSet(__nth__(1, list_orgn)), limit).cartesian_product(SFiniteSimplicialSet(KenzoSimplicialSet(__nth__(2, list_orgn)), limit)) rslt = {} simplices = [] faces = [] @@ -1763,8 +1715,7 @@ def change_source_target_complex(self, source=None, target=None): """ source = source or self.source_complex() target = target or self.target_complex() - return KenzoChainComplexMorphism( - __change_sorc_trgt_aux__(self._kenzo, source._kenzo, target._kenzo)) + return KenzoChainComplexMorphism(__change_sorc_trgt_aux__(self._kenzo, source._kenzo, target._kenzo)) def destructive_change_source_target_complex(self, source=None, target=None): r""" @@ -1809,8 +1760,7 @@ def destructive_change_source_target_complex(self, source=None, target=None): """ source = source or self.source_complex() target = target or self.target_complex() - return KenzoChainComplexMorphism( - __dstr_change_sorc_trgt_aux__(self._kenzo, source._kenzo, target._kenzo)) + return KenzoChainComplexMorphism(__dstr_change_sorc_trgt_aux__(self._kenzo, source._kenzo, target._kenzo)) def build_morphism(source_complex, target_complex, degree, algorithm, strategy, orgn): @@ -1855,9 +1805,7 @@ def build_morphism(source_complex, target_complex, degree, algorithm, strategy, sage: type(A) """ - return KenzoChainComplexMorphism( - __build_mrph_aux__(source_complex._kenzo, target_complex._kenzo, - degree, algorithm, ":" + strategy, orgn)) + return KenzoChainComplexMorphism(__build_mrph_aux__(source_complex._kenzo, target_complex._kenzo, degree, algorithm, ":" + strategy, orgn)) def morphism_dictmat(morphism): @@ -1915,8 +1863,7 @@ def KChainComplexMorphism(morphism): source = KChainComplex(morphism.domain()) target = KChainComplex(morphism.codomain()) matrix_list = morphism_dictmat(morphism) - return KenzoChainComplexMorphism( - __kmorphismchaincomplex_aux1__(matrix_list, source._kenzo, target._kenzo)) + return KenzoChainComplexMorphism(__kmorphismchaincomplex_aux1__(matrix_list, source._kenzo, target._kenzo)) def s2k_listofmorphisms(l): diff --git a/src/sage/interfaces/khoca.py b/src/sage/interfaces/khoca.py index 2541f949ae1..4c32bd03dcc 100644 --- a/src/sage/interfaces/khoca.py +++ b/src/sage/interfaces/khoca.py @@ -54,6 +54,7 @@ class KnownKeywords(Enum): , ] """ + frobenius_algebra = 'frobenius_algebra' root = 'root' equivariant = 'equivariant' @@ -110,6 +111,7 @@ def khoca_interface(ring, **kwds): NotImplementedError: keyword equivariant is not implemented yet """ from sage.features.khoca import Khoca + Khoca().require() keys = check_kwds(**kwds) ch = ring.characteristic() @@ -117,6 +119,7 @@ def khoca_interface(ring, **kwds): if rg == 0 and ring.is_field(): rg = 1 from khoca import InteractiveCalculator + frobenius_algebra = (0, 0) if KnownKeywords.frobenius_algebra in keys: frobenius_algebra = kwds[KnownKeywords.frobenius_algebra.value] @@ -126,10 +129,7 @@ def khoca_interface(ring, **kwds): equivariant = None if KnownKeywords.equivariant in keys: raise NotImplementedError('keyword %s is not implemented yet' % KnownKeywords.equivariant.value) - return InteractiveCalculator(coefficient_ring=rg, - frobenius_algebra=frobenius_algebra, - root=root, - equivariant=equivariant) + return InteractiveCalculator(coefficient_ring=rg, frobenius_algebra=frobenius_algebra, root=root, equivariant=equivariant) @cached_function @@ -173,6 +173,7 @@ def khoca_raw_data(link, ring, red_typ=True, **kwds): ... ValueError: unknown code gauss, must be one of (pd, braid) """ + def prepare_data(data): r""" compress and adapt data to Sage diff --git a/src/sage/interfaces/latte.py b/src/sage/interfaces/latte.py index 48a33814b2d..6a159846a08 100644 --- a/src/sage/interfaces/latte.py +++ b/src/sage/interfaces/latte.py @@ -1,6 +1,7 @@ r""" Interface to LattE integrale programs """ + # **************************************************************************** # Copyright (C) 2017 Vincent Delecroix # @@ -146,6 +147,7 @@ def count(arg, ehrhart_polynomial=False, multivariate_generating_function=False, if multivariate_generating_function: from sage.misc.temporary_file import tmp_filename + filename = tmp_filename() with open(filename, 'w') as f: f.write(bytes_to_str(arg)) @@ -156,12 +158,10 @@ def count(arg, ehrhart_polynomial=False, multivariate_generating_function=False, # The cwd argument is needed because latte # always produces diagnostic output files. import tempfile + tempd = tempfile.TemporaryDirectory() - latte_proc = Popen(args, - stdin=PIPE, stdout=PIPE, - stderr=(None if verbose else PIPE), - cwd=tempd.name) + latte_proc = Popen(args, stdin=PIPE, stdout=PIPE, stderr=(None if verbose else PIPE), cwd=tempd.name) ans, err = latte_proc.communicate(arg) if err: @@ -187,6 +187,7 @@ def count(arg, ehrhart_polynomial=False, multivariate_generating_function=False, return ans from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ + R = PolynomialRing(QQ, 't') tempd.cleanup() return R(ans) @@ -372,6 +373,7 @@ def integrate(arg, polynomial=None, algorithm='triangulate', raw_output=False, v monomials_list = str(polynomial) from sage.misc.temporary_file import tmp_filename + filename_polynomial = tmp_filename() with open(filename_polynomial, 'w') as f: @@ -383,12 +385,10 @@ def integrate(arg, polynomial=None, algorithm='triangulate', raw_output=False, v # The cwd argument is needed because latte # always produces diagnostic output files. import tempfile + tempd = tempfile.TemporaryDirectory() - latte_proc = Popen(args, - stdin=PIPE, stdout=PIPE, - stderr=(None if verbose else PIPE), - cwd=tempd.name) + latte_proc = Popen(args, stdin=PIPE, stdout=PIPE, stderr=(None if verbose else PIPE), cwd=tempd.name) ans, err = latte_proc.communicate(arg) if err: @@ -460,8 +460,6 @@ def to_latte_polynomial(polynomial): exponents_list = [[exponent_vector_i] for exponent_vector_i in polynomial.exponents()] # assuming that the order in coefficients() and exponents() methods match - monomials_list = [list(monomial_i) - for monomial_i - in zip(coefficients_list, exponents_list)] + monomials_list = [list(monomial_i) for monomial_i in zip(coefficients_list, exponents_list)] return str(monomials_list) diff --git a/src/sage/interfaces/lie.py b/src/sage/interfaces/lie.py index 501f740a12a..068e5217932 100644 --- a/src/sage/interfaces/lie.py +++ b/src/sage/interfaces/lie.py @@ -317,10 +317,7 @@ class LiE(ExtraTabCompletion, Expect): using LiE (and get the result back as a string). """ - def __init__(self, - maxread=None, script_subdirectory=None, - logfile=None, - server=None): + def __init__(self, maxread=None, script_subdirectory=None, logfile=None, server=None): """ EXAMPLES:: @@ -328,36 +325,30 @@ def __init__(self, sage: lie == loads(dumps(lie)) True """ - Expect.__init__(self, - - # The capitalized version of this is used for printing. - name='LiE', - - # This is regexp of the input prompt. If you can change - # it to be very obfuscated that would be better. Even - # better is to use sequence numbers. - prompt='> ', - - # This is the command that starts up your program - command="bash lie", - - server=server, - script_subdirectory=script_subdirectory, - - # If this is true, then whenever the user presses Control-C to - # interrupt a calculation, the whole interface is restarted. - restart_on_ctrlc=False, - - # If true, print out a message when starting - # up the command when you first send a command - # to this interface. - verbose_start=False, - - logfile=logfile, - - # If an input is longer than this number of characters, then - # try to switch to outputting to a file. - eval_using_file_cutoff=1024) + Expect.__init__( + self, + # The capitalized version of this is used for printing. + name='LiE', + # This is regexp of the input prompt. If you can change + # it to be very obfuscated that would be better. Even + # better is to use sequence numbers. + prompt='> ', + # This is the command that starts up your program + command="bash lie", + server=server, + script_subdirectory=script_subdirectory, + # If this is true, then whenever the user presses Control-C to + # interrupt a calculation, the whole interface is restarted. + restart_on_ctrlc=False, + # If true, print out a message when starting + # up the command when you first send a command + # to this interface. + verbose_start=False, + logfile=logfile, + # If an input is longer than this number of characters, then + # try to switch to outputting to a file. + eval_using_file_cutoff=1024, + ) self._seq = 0 @@ -386,6 +377,7 @@ def _read_info_files(self, use_disk_cache=True): 'write'] """ import sage.misc.persist + if use_disk_cache: try: trait_dict = sage.misc.persist.load(COMMANDS_CACHE) @@ -435,7 +427,7 @@ def _read_info_files(self, use_disk_cache=True): if line[i + 1] == ")": t = 'vid' else: - t = line[i + 1:i + 4] + t = line[i + 1 : i + 4] # Save the help text for the command help[prev_command] = help.get(prev_command, "") + help_text @@ -768,7 +760,7 @@ def type(self): """ t = self.parent().eval('type(%s)' % self._name) i = t.find(':') - return t[i + 1:].strip() + return t[i + 1 :].strip() def _matrix_(self, R=None): """ @@ -812,6 +804,7 @@ def _sage_(self): raise ValueError("cannot convert Lie groups to native Sage objects") elif t == 'mat': import sage.matrix.constructor + data = sage_eval(str(self).replace('\n', '').strip()) return sage.matrix.constructor.matrix(data) elif t == 'pol': @@ -844,8 +837,8 @@ def _sage_(self): for term in terms: xpos = term.find('X') coef = eval(term[:xpos].strip()) - exps = eval(term[xpos + 1:].strip()) - monomial = prod([x[i]**exps[i] for i in range(nvars)]) + exps = eval(term[xpos + 1 :].strip()) + monomial = prod([x[i] ** exps[i] for i in range(nvars)]) pol += coef * monomial return pol @@ -915,6 +908,7 @@ def lie_console(): ... """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%lie magics instead.') os.system('bash `which lie`') diff --git a/src/sage/interfaces/lisp.py b/src/sage/interfaces/lisp.py index 2848a87f945..efdb0b59a9b 100644 --- a/src/sage/interfaces/lisp.py +++ b/src/sage/interfaces/lisp.py @@ -66,11 +66,7 @@ class Lisp(Expect): - def __init__(self, - maxread=None, script_subdirectory=None, - logfile=None, - server=None, - server_tmpdir=None): + def __init__(self, maxread=None, script_subdirectory=None, logfile=None, server=None, server_tmpdir=None): """ EXAMPLES:: @@ -78,38 +74,32 @@ def __init__(self, sage: lisp == loads(dumps(lisp)) True """ - Expect.__init__(self, - - # The capitalized version of this is used for printing. - name='Lisp', - - # This is regexp of the input prompt. If you - # can change it to be very obfuscated that - # would be better. Even better is to use - # sequence numbers. - prompt='> ', - - # This is the command that starts up your program - command='ecl', - - server=server, - server_tmpdir=server_tmpdir, - script_subdirectory=script_subdirectory, - - # If this is true, then whenever the user presses Control-C to - # interrupt a calculation, the whole interface is restarted. - restart_on_ctrlc=False, - - # If true, print out a message when starting - # up the command when you first send a command - # to this interface. - verbose_start=False, - - logfile=logfile, - - # If an input is longer than this number of characters, then - # try to switch to outputting to a file. - eval_using_file_cutoff=1024) + Expect.__init__( + self, + # The capitalized version of this is used for printing. + name='Lisp', + # This is regexp of the input prompt. If you + # can change it to be very obfuscated that + # would be better. Even better is to use + # sequence numbers. + prompt='> ', + # This is the command that starts up your program + command='ecl', + server=server, + server_tmpdir=server_tmpdir, + script_subdirectory=script_subdirectory, + # If this is true, then whenever the user presses Control-C to + # interrupt a calculation, the whole interface is restarted. + restart_on_ctrlc=False, + # If true, print out a message when starting + # up the command when you first send a command + # to this interface. + verbose_start=False, + logfile=logfile, + # If an input is longer than this number of characters, then + # try to switch to outputting to a file. + eval_using_file_cutoff=1024, + ) self.__seq = 0 self.__in_seq = 1 @@ -140,7 +130,7 @@ def eval(self, code, strip=True, **kwds): s = self.__in_seq + 1 M = self._eval_line(L, wait_for_prompt=self._prompt) if M.startswith(L + "\n"): - M = M[len(L):] # skip L in case it was echoed + M = M[len(L) :] # skip L in case it was echoed x.append(M.strip()) self.__in_seq = s except TypeError as s: @@ -306,10 +296,10 @@ def version(self): sage: lisp.version() 'Version information is given by lisp.console().' """ -# import subprocess -# p = subprocess.Popen('ecl --version', shell=True, stdin=subprocess.PIPE, -# stdout = subprocess.PIPE, stderr=subprocess.PIPE) -# return AsciiArtString(p.stdout.read()) + # import subprocess + # p = subprocess.Popen('ecl --version', shell=True, stdin=subprocess.PIPE, + # stdout = subprocess.PIPE, stderr=subprocess.PIPE) + # return AsciiArtString(p.stdout.read()) return "Version information is given by lisp.console()." def _object_class(self): @@ -361,8 +351,7 @@ def _equality_symbol(self): ... NotImplementedError: ... """ - raise NotImplementedError("We should never reach here in the Lisp interface. " + - "Please report this as a bug.") + raise NotImplementedError("We should never reach here in the Lisp interface. " + "Please report this as a bug.") def help(self, command): """ @@ -558,6 +547,7 @@ def lisp_console(): ... """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%lisp magics instead.') os.system('ecl') diff --git a/src/sage/interfaces/macaulay2.py b/src/sage/interfaces/macaulay2.py index d09a3ca389d..b973f815beb 100644 --- a/src/sage/interfaces/macaulay2.py +++ b/src/sage/interfaces/macaulay2.py @@ -182,9 +182,8 @@ class Macaulay2(ExtraTabCompletion, Expect): """ Interface to the Macaulay2 interpreter. """ - def __init__(self, maxread=None, script_subdirectory=None, - logfile=None, server=None, - server_tmpdir=None, command=None) -> None: + + def __init__(self, maxread=None, script_subdirectory=None, logfile=None, server=None, server_tmpdir=None, command=None) -> None: """ Initialize a Macaulay2 interface instance. @@ -212,8 +211,7 @@ def __init__(self, maxread=None, script_subdirectory=None, # Prompt changing commands 'sageLoadMode = false;' 'ZZ#{Standard,Core#"private dictionary"#"InputPrompt"} = ' - 'ZZ#{Standard,Core#"private dictionary"#"InputContinuationPrompt"} = ' + - 'lineno -> if(sageLoadMode) then "%s" else "%s";' % (PROMPT_LOAD, PROMPT) + + 'ZZ#{Standard,Core#"private dictionary"#"InputContinuationPrompt"} = ' + 'lineno -> if(sageLoadMode) then "%s" else "%s";' % (PROMPT_LOAD, PROMPT) + # Also prevent line wrapping in Macaulay2 "printWidth = 0;" + # And make all output labels to be of the same width @@ -222,16 +220,7 @@ def __init__(self, maxread=None, script_subdirectory=None, 'sageAssign = (k, v) -> (if not instance(v, Sequence) then use v; k <- v);' ) command = "%s --no-debug --no-readline --silent -e '%s'" % (command, init_str) - Expect.__init__(self, - name='macaulay2', - prompt=PROMPT, - command=command, - server=server, - server_tmpdir=server_tmpdir, - script_subdirectory=script_subdirectory, - verbose_start=False, - logfile=logfile, - eval_using_file_cutoff=500) + Expect.__init__(self, name='macaulay2', prompt=PROMPT, command=command, server=server, server_tmpdir=server_tmpdir, script_subdirectory=script_subdirectory, verbose_start=False, logfile=logfile, eval_using_file_cutoff=500) # Macaulay2 provides no "clear" function. However, Macaulay2 does provide # garbage collection; since expect automatically reuses variable names, @@ -300,8 +289,7 @@ def _post_process_from_file(self, s) -> str: ....: macaulay2.eval('ZZ^2\n%sZZ^3' % (' ' * macaulay2._eval_using_file_cutoff))) True """ - return '\n'.join(line for line in s.split('\n') - if not line.startswith(PROMPT_LOAD)) + return '\n'.join(line for line in s.split('\n') if not line.startswith(PROMPT_LOAD)) def eval(self, code, strip=True, **kwds): """ @@ -385,12 +373,10 @@ class options(GlobalOptions): ZZ-module, submodule of ZZ sage: macaulay2.options.after_print = False """ + NAME = 'Macaulay2' module = 'sage.interfaces.macaulay2' - after_print = dict(default=False, - description='append AfterPrint type information to ' - 'textual representations', - checker=lambda val: isinstance(val, bool)) + after_print = dict(default=False, description='append AfterPrint type information to ' 'textual representations', checker=lambda val: isinstance(val, bool)) def get(self, var): """ @@ -793,11 +779,13 @@ def _tab_completion(self) -> list[str]: # Get all the names from Macaulay2 except numbered outputs like # o1, o2, etc. and automatic Sage variable names sage0, sage1, etc. # It is faster to get it back as a string. - r = macaulay2.eval(r""" + r = macaulay2.eval( + r""" print toString select( apply(apropos "^[[:alnum:]]+$", toString), s -> not match("^(o|sage)[0-9]+$", s)) - """) + """ + ) # Now split this string into separate names # Macaulay2 sorts things like A, a, B, b, ... return sorted(r[1:-1].split(", ")) @@ -853,8 +841,7 @@ def _macaulay2_input_ring(self, base_ring, vars, order='GRevLex'): varstr = str(vars)[1:-1].rstrip(',') r = re.compile(r"(?<=,)|(?<=\.\.<)|(?<=\.\.)(?!<)") varstr = "symbol " + r.sub("symbol ", varstr) - return '%s[%s, MonomialSize=>16, MonomialOrder=>%s]' % (base_ring, varstr, - order) + return '%s[%s, MonomialSize=>16, MonomialOrder=>%s]' % (base_ring, varstr, order) @instancedoc @@ -867,6 +854,7 @@ class Macaulay2Element(ExtraTabCompletion, ExpectElement, sage.interfaces.abc.Ma .. automethod:: _sage_ """ + def _latex_(self) -> str: r""" EXAMPLES:: @@ -938,6 +926,7 @@ def _repr_(self) -> str: sage: macaulay2.options.after_print = False """ from sage.typeset.ascii_art import empty_ascii_art + P = self.parent() if P.options.after_print: # In M2, the wrapped output is indented by the width of the prompt, @@ -948,9 +937,7 @@ def _repr_(self) -> str: return P.eval('printWidth=%d;%s' % (width, self._name)) # Otherwise manually wrap the net representation which does not display # AfterPrint text - return P.eval('print(wrap(%d,"-",net %s))' - % (empty_ascii_art._terminal_width(), self._name), - strip=False) + return P.eval('print(wrap(%d,"-",net %s))' % (empty_ascii_art._terminal_width(), self._name), strip=False) def external_string(self) -> str: """ @@ -1019,11 +1006,12 @@ def name(self, new_name=None): m := lookup(GlobalReleaseHook, class {0}); if m =!= null then m(symbol {0}, {0}); {1} = {0}; - ))()""".format(self._name, new_name) + ))()""".format( + self._name, new_name + ) ans = P.eval(cmd) if ans.find("stdio:") != -1: - raise RuntimeError("Error evaluating Macaulay2 code.\n" - "IN:%s\nOUT:%s" % (cmd, ans)) + raise RuntimeError("Error evaluating Macaulay2 code.\n" "IN:%s\nOUT:%s" % (cmd, ans)) return P._object_class()(P, new_name, is_name=True) def __len__(self) -> int: @@ -1247,7 +1235,9 @@ def _tab_completion(self) -> list[str]: currentClass = parent currentClass; ); print toString total - ))()""" % self.name()) + ))()""" + % self.name() + ) r = sorted(r[1:-1].split(", ")) return r @@ -1284,8 +1274,7 @@ def after_print_text(self): 2 ZZ-module, submodule of ZZ """ - return self.parent().eval('(lookup({topLevelMode,AfterPrint},' + - 'class {0}))({0})'.format(self._name)) + return self.parent().eval('(lookup({topLevelMode,AfterPrint},' + 'class {0}))({0})'.format(self._name)) ############################ # Aliases for M2 operators # @@ -1501,9 +1490,11 @@ def _sage_(self): if repr_str == "ZZ": from sage.rings.integer_ring import ZZ + return ZZ if repr_str == "QQ": from sage.rings.rational_field import QQ + return QQ if cls_cls_str == "Type": @@ -1524,6 +1515,7 @@ def _sage_(self): if ambient.external_string() == 'ZZ': from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.integer_ring import ZZ + external_string = self.external_string() zz, n = external_string.split("/") @@ -1565,6 +1557,7 @@ def _sage_(self): if cls_str == "GaloisField": from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.integer_ring import ZZ + gf, n = repr_str.split(" ") n = ZZ(n) if n.is_prime(): @@ -1580,6 +1573,7 @@ def _sage_(self): return str(repr_str) if cls_str == "Module": from sage.modules.free_module import FreeModule + if self.isFreeModule()._sage_(): ring = self.ring()._sage_() rank = self.rank()._sage_() @@ -1587,9 +1581,11 @@ def _sage_(self): if cls_str in ("Graph", "Digraph"): if cls_str == "Graph": from sage.graphs.graph import Graph + graph_cls = Graph else: from sage.graphs.digraph import DiGraph + graph_cls = DiGraph adj_mat = self.adjacencyMatrix().sage() g = graph_cls(adj_mat, format='adjacency_matrix') @@ -1597,23 +1593,23 @@ def _sage_(self): return g if cls_str == "ChainComplex": from sage.homology.chain_complex import ChainComplex + ring = self.ring()._sage_() dd = self.dot('dd') degree = dd.degree()._sage_() a = self.min()._sage_() b = self.max()._sage_() - matrices = {i: dd.underscore(i)._matrix_(ring) - for i in range(a, b + 1)} + matrices = {i: dd.underscore(i)._matrix_(ring) for i in range(a, b + 1)} return ChainComplex(matrices, degree=degree) if cls_str == "ChainComplexMap": from sage.homology.chain_complex_morphism import ChainComplexMorphism + ring = self.ring()._sage_() source = self.source() a = source.min()._sage_() b = source.max()._sage_() degree = self.degree()._sage_() - matrices = {i: self.underscore(i)._matrix_(ring) - for i in range(a, b + 1)} + matrices = {i: self.underscore(i)._matrix_(ring) for i in range(a, b + 1)} C = source._sage_() # in Sage, chain complex morphisms are degree-preserving, # so we shift the degrees of the target @@ -1623,11 +1619,12 @@ def _sage_(self): # Handle the integers and rationals separately if cls_str == "ZZ": from sage.rings.integer_ring import ZZ + return ZZ(repr_str) if cls_str == "QQ": from sage.rings.rational_field import QQ - return QQ((self.numerator()._sage_(), - self.denominator()._sage_())) + + return QQ((self.numerator()._sage_(), self.denominator()._sage_())) m2_parent = self.cls() parent = m2_parent._sage_() @@ -1635,11 +1632,9 @@ def _sage_(self): if cls_cls_str == "PolynomialRing": # going through a dict if len(m2_parent.gens()) == 1: - d = {monome[0].sage(): coeff.sage() - for monome, coeff in self.listForm()} + d = {monome[0].sage(): coeff.sage() for monome, coeff in self.listForm()} else: - d = {tuple(monome.sage()): coeff.sage() - for monome, coeff in self.listForm()} + d = {tuple(monome.sage()): coeff.sage() for monome, coeff in self.listForm()} return parent(d) if cls_cls_str == "QuotientRing": return parent(self.external_string()) @@ -1648,6 +1643,7 @@ def _sage_(self): return parent._element_constructor_(entries) from sage.misc.sage_eval import sage_eval + try: return sage_eval(repr_str) except Exception: @@ -1682,6 +1678,7 @@ def _matrix_(self, R): (0, 2) """ from sage.matrix.constructor import matrix + m = matrix(R, self.entries()._sage_()) if not m.nrows(): return matrix(R, 0, self.numcols()._sage_()) @@ -1779,8 +1776,7 @@ def _instancedoc_(self): ... """ P = self._obj.parent() - r = P.eval('help prepend({0}, select(methods {0}, m->' - 'instance({1}, m#1)))'.format(self._name, self._obj._name)) + r = P.eval('help prepend({0}, select(methods {0}, m->' 'instance({1}, m#1)))'.format(self._name, self._obj._name)) end = r.rfind("\n\nDIV") if end != -1: r = r[:end] @@ -1794,9 +1790,7 @@ def _sage_src_(self): sage: m.resolution._sage_src_() -- code for method: freeResolution(Matrix)... """ - return self._obj.parent().eval( - 'code select(methods %s, m->instance(%s, m#1))' - % (self._name, self._obj._name)) + return self._obj.parent().eval('code select(methods %s, m->instance(%s, m#1))' % (self._name, self._obj._name)) # An instance @@ -1815,6 +1809,7 @@ def macaulay2_console(): ... """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%macaulay2 magics instead.') os.system('M2') diff --git a/src/sage/interfaces/magma.py b/src/sage/interfaces/magma.py index 5fd42057df0..239dba92656 100644 --- a/src/sage/interfaces/magma.py +++ b/src/sage/interfaces/magma.py @@ -258,6 +258,7 @@ def extcode_dir(iface=None) -> str: if not EXTCODE_DIR: if iface is None or iface._server is None: import shutil + tmp = sage.misc.temporary_file.tmp_dir() shutil.copytree('%s/magma/' % SAGE_EXTCODE, tmp + '/data') EXTCODE_DIR = "%s/data/" % tmp @@ -272,6 +273,7 @@ def extcode_dir(iface=None) -> str: except OSError: out_str = 'Tried to copy the file structure in "%s/magma/" to "%s:%s/data" and failed (possibly because scp is not installed in the system).\nFor the remote Magma to work you should populate the remote directory by some other method, or install scp in the system and retry.' % (SAGE_EXTCODE, iface._server, tmp) from warnings import warn + warn(out_str) return EXTCODE_DIR @@ -309,9 +311,8 @@ class Magma(ExtraTabCompletion, Expect): '1.1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' sage: magma.SetDefaultRealFieldPrecision(30, nvals=0) # optional - magma """ - def __init__(self, script_subdirectory=None, - logfile=None, server=None, server_tmpdir=None, - user_config=False, seed=None, command=None): + + def __init__(self, script_subdirectory=None, logfile=None, server=None, server_tmpdir=None, user_config=False, seed=None, command=None): """ INPUT: @@ -349,16 +350,7 @@ def __init__(self, script_subdirectory=None, if seed is None: seed = os.getenv('SAGE_MAGMA_SEED') - Expect.__init__(self, - name='magma', - prompt='>>SAGE>>', - command=command, - server=server, - server_tmpdir=server_tmpdir, - script_subdirectory=script_subdirectory, - restart_on_ctrlc=False, - logfile=logfile, - eval_using_file_cutoff=100) + Expect.__init__(self, name='magma', prompt='>>SAGE>>', command=command, server=server, server_tmpdir=server_tmpdir, script_subdirectory=script_subdirectory, restart_on_ctrlc=False, logfile=logfile, eval_using_file_cutoff=100) # We use "-n" above in the Magma startup command so # local user startup configuration is not read. @@ -466,7 +458,7 @@ def _post_process_from_file(self, s) -> str: i = s.find('\n') if i == -1: # special case -- command produced no output, so no \n return '' - return s[i + 1:] + return s[i + 1 :] def __getattr__(self, attrname): """ @@ -678,9 +670,7 @@ def objgens(self, value, gens): """ var = self._next_var_name() value = self(value) - out = self.eval("_zsage_<%s> := %s; %s := _zsage_" % (gens, - value.name(), - var)) + out = self.eval("_zsage_<%s> := %s; %s := _zsage_" % (gens, value.name(), var)) if out.lower().find("error") != -1: raise TypeError("Error executing Magma code:\n%s" % out) return self(var) @@ -824,8 +814,8 @@ def _coerce_from_special_method(self, x): z = SAGE_REF_RE.search(s) if not z: break - self.eval('delete %s;' % s[z.start():z.end()]) - s = s[z.end()+1:] + self.eval('delete %s;' % s[z.start() : z.end()]) + s = s[z.end() + 1 :] return a def _with_names(self, s, names): @@ -846,8 +836,7 @@ def _with_names(self, s, names): sage: magma._with_names('PolynomialRing(RationalField())', ['y']) # optional - magma 'SageCreateWithNames(PolynomialRing(RationalField()),["y"])' """ - return 'SageCreateWithNames(%s,[%s])' % (s, ','.join('"%s"' % x - for x in names)) + return 'SageCreateWithNames(%s,[%s])' % (s, ','.join('"%s"' % x for x in names)) def clear(self, var): """ @@ -1131,8 +1120,7 @@ def function_call(self, function, args=[], params={}, nvals=1): if len(params) == 0: par = '' else: - par = ' : ' + ','.join('%s:=%s' % (a, b.name()) - for a, b in params.items()) + par = ' : ' + ','.join('%s:=%s' % (a, b.name()) for a, b in params.items()) fun = "%s(%s%s)" % (function, ",".join(s.name() for s in args), par) @@ -1452,6 +1440,7 @@ def _tab_completion(self, verbose=True, use_disk_cache=True): return self.__tab_completion except AttributeError: import sage.misc.persist + if use_disk_cache: try: self.__tab_completion = sage.misc.persist.load(INTRINSIC_CACHE) @@ -1641,10 +1630,7 @@ def __call__(self, *args, **kwds): nvals = kwds['nvals'] del kwds['nvals'] M = self._obj.parent() - return M.function_call(self._name, - [self._obj.name()] + list(args), - params=kwds, - nvals=nvals) + return M.function_call(self._name, [self._obj.name()] + list(args), params=kwds, nvals=nvals) def _instancedoc_(self): """ @@ -1754,10 +1740,7 @@ def __call__(self, *args, **kwds): nvals = kwds['nvals'] del kwds['nvals'] M = self._parent - return M.function_call(self._name, - list(args), - params=kwds, - nvals=nvals) + return M.function_call(self._name, list(args), params=kwds, nvals=nvals) def _instancedoc_(self): """ @@ -1781,8 +1764,7 @@ def _instancedoc_(self): @instancedoc -class MagmaElement(ExtraTabCompletion, ExpectElement, - sage.interfaces.abc.MagmaElement): +class MagmaElement(ExtraTabCompletion, ExpectElement, sage.interfaces.abc.MagmaElement): def _ref(self): """ Return a variable name that is a new reference to this particular @@ -2043,8 +2025,7 @@ def AssignNames(self, names): a^2 + b """ P = self._check_valid() - cmd = 'AssignNames(~%s, [%s])' % (self.name(), - ','.join('"%s"' % x for x in names)) + cmd = 'AssignNames(~%s, [%s])' % (self.name(), ','.join('"%s"' % x for x in names)) P.eval(cmd) assign_names = AssignNames @@ -2400,7 +2381,7 @@ def _latex_(self) -> str: P = self._check_valid() s = str(P.eval('Latex(%s)' % self.name())) v = '\\mathrm{' - if s[:len(v)] == v: + if s[: len(v)] == v: raise AttributeError return s @@ -2421,7 +2402,7 @@ def set_magma_attribute(self, attrname, value): sage: V.M 10 """ - P = self.parent() # instance of Magma that contains this element. + P = self.parent() # instance of Magma that contains this element. if not (isinstance(value, MagmaElement) and value.parent() is P): value = P(value) P.eval('%s`%s := %s' % (self.name(), attrname, value.name())) @@ -2731,6 +2712,7 @@ def magma_console(): Total time: 2.820 seconds, Total memory usage: 3.95MB """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%magma magics instead.') os.system('magma') @@ -2740,12 +2722,11 @@ class MagmaGBLogPrettyPrinter: """ A device which filters Magma Groebner basis computation logs. """ + cmd_inpt = re.compile("^>>>$") app_inpt = re.compile("^Append\\(~_sage_, 0\\);$") - deg_curr = re.compile( - "^Basis length\\: (\\d+), queue length\\: (\\d+), step degree\\: (\\d+), num pairs\\: (\\d+)$" - ) + deg_curr = re.compile("^Basis length\\: (\\d+), queue length\\: (\\d+), step degree\\: (\\d+), num pairs\\: (\\d+)$") pol_curr = re.compile("^Number of pair polynomials\\: (\\d+), at (\\d+) column\\(s\\), .*") def __init__(self, verbosity=1, style='magma'): @@ -2821,12 +2802,12 @@ def __init__(self, verbosity=1, style='magma'): raise ValueError('style must be sage or magma') self.style = style - self.curr_deg = 0 # current degree + self.curr_deg = 0 # current degree self.curr_npairs = 0 # current number of pairs to be considered - self.max_deg = 0 # maximal degree in total + self.max_deg = 0 # maximal degree in total - self.storage = "" # stores incomplete strings - self.sync = None # should we expect a sync integer? + self.storage = "" # stores incomplete strings + self.sync = None # should we expect a sync integer? def write(self, s): """ @@ -2891,11 +2872,9 @@ def write(self, s): self.max_deg = max(self.max_deg, self.curr_deg) if style == "sage" and verbosity >= 1: - print("Leading term degree: %2d. Critical pairs: %d." % - (self.curr_deg, self.curr_npairs)) + print("Leading term degree: %2d. Critical pairs: %d." % (self.curr_deg, self.curr_npairs)) elif style == "sage" and verbosity >= 1: - print("Leading term degree: %2d. Critical pairs: %d (all pairs of current degree eliminated by criteria)." % - (self.curr_deg, self.curr_npairs)) + print("Leading term degree: %2d. Critical pairs: %d (all pairs of current degree eliminated by criteria)." % (self.curr_deg, self.curr_npairs)) if style == "magma" and verbosity >= 1: print(line) @@ -2909,6 +2888,7 @@ def flush(self): sage: logs.flush() """ import sys + sys.stdout.flush() @@ -2917,6 +2897,7 @@ class MagmaGBDefaultContext: Context to force preservation of verbosity options for Magma's Groebner basis computation. """ + def __init__(self, magma=None): """ INPUT: @@ -2932,6 +2913,7 @@ def __init__(self, magma=None): """ if magma is None: from sage.interfaces.magma import magma as magma_default + magma = magma_default self.magma = magma @@ -2983,4 +2965,5 @@ def wrapper(*args, **kwds): """ with MagmaGBDefaultContext(): return func(*args, **kwds) + return wrapper diff --git a/src/sage/interfaces/magma_free.py b/src/sage/interfaces/magma_free.py index 94a4065ed27..42194afb264 100644 --- a/src/sage/interfaces/magma_free.py +++ b/src/sage/interfaces/magma_free.py @@ -47,8 +47,7 @@ def magma_free_eval(code: str, strip=True, columns=0): refererUrl = "http://%s%s" % (server, refererPath) code = "SetColumns(%s);\n" % columns + code params = urlencode({'input': code}) - headers = {"Content-type": "application/x-www-form-urlencoded", - "Accept": "Accept: text/html, application/xml, application/xhtml+xml", "Referer": refererUrl} + headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "Accept: text/html, application/xml, application/xhtml+xml", "Referer": refererUrl} conn = httplib.HTTPConnection(server) conn.request("POST", processPath, params, headers) response = conn.getresponse() @@ -79,6 +78,7 @@ class MagmaFree: sage: magma_free("Factorization(9290348092384)") # optional - internet [ <2, 5>, <290323377887, 1> ] """ + def eval(self, x, **kwds): return magma_free_eval(x) diff --git a/src/sage/interfaces/maple.py b/src/sage/interfaces/maple.py index bf58e35eda6..93fbae00ee1 100644 --- a/src/sage/interfaces/maple.py +++ b/src/sage/interfaces/maple.py @@ -267,8 +267,8 @@ class Maple(ExtraTabCompletion, Expect): object, and ``maple.eval(...)`` to run a string using Maple (and get the result back as a string). """ - def __init__(self, maxread=None, script_subdirectory=None, server=None, - server_tmpdir=None, logfile=None, ulimit=None) -> None: + + def __init__(self, maxread=None, script_subdirectory=None, server=None, server_tmpdir=None, logfile=None, ulimit=None) -> None: """ Create an instance of the Maple interpreter. @@ -278,11 +278,8 @@ def __init__(self, maxread=None, script_subdirectory=None, server=None, sage: maple == loads(dumps(maple)) True """ - __maple_iface_opts = [ - 'screenwidth=infinity', - 'errorcursor=false'] - __maple_command = 'maple -t -c "interface({})"'.format( - ','.join(__maple_iface_opts)) + __maple_iface_opts = ['screenwidth=infinity', 'errorcursor=false'] + __maple_command = 'maple -t -c "interface({})"'.format(','.join(__maple_iface_opts)) # errorcursor=false avoids maple command line interface to dump # into the editor when an error occurs. Thus pexpect interface # is not messed up if a maple error occurs. @@ -290,18 +287,7 @@ def __init__(self, maxread=None, script_subdirectory=None, server=None, # your input lines. By doing this, file interface also works in the # event that sage_user_home + sage_tmp_file_stuff exceeds the # length of 79 characters. - Expect.__init__(self, - name='maple', - prompt='#-->', - command=__maple_command, - server=server, - server_tmpdir=server_tmpdir, - ulimit=ulimit, - script_subdirectory=script_subdirectory, - restart_on_ctrlc=False, - verbose_start=False, - logfile=logfile, - eval_using_file_cutoff=2048) # 2048 is + Expect.__init__(self, name='maple', prompt='#-->', command=__maple_command, server=server, server_tmpdir=server_tmpdir, ulimit=ulimit, script_subdirectory=script_subdirectory, restart_on_ctrlc=False, verbose_start=False, logfile=logfile, eval_using_file_cutoff=2048) # 2048 is # a small enough value to avoid conflicts with the 4096 limit # hardcoded in Expect. @@ -463,24 +449,24 @@ def console(self): """ maple_console() -# def killall(self): -# """ -# Kill all running instances of the maple interpreter -# on this system. - -# TODO: When Sage exits it doesn't correctly by default kill -# all running Maple interpreters, for some strange reason. -# Calling this function uses the kill and pidof operating system -# programs to find all instances of cmaple and kill them. -# """ -# import os -# self._expect = None -# while True: -# pid = os.popen("pidof cmaple").read()[:-1] -# if len(pid) > 0: -# os.system('kill -9 %s'%pid) -# else: -# break + # def killall(self): + # """ + # Kill all running instances of the maple interpreter + # on this system. + + # TODO: When Sage exits it doesn't correctly by default kill + # all running Maple interpreters, for some strange reason. + # Calling this function uses the kill and pidof operating system + # programs to find all instances of cmaple and kill them. + # """ + # import os + # self._expect = None + # while True: + # pid = os.popen("pidof cmaple").read()[:-1] + # if len(pid) > 0: + # os.system('kill -9 %s'%pid) + # else: + # break def completions(self, s) -> list: """ @@ -528,8 +514,7 @@ def _commands(self) -> list: True """ try: - v = sum([self.completions(chr(65 + n)) for n in range(26)], []) + \ - sum([self.completions(chr(97 + n)) for n in range(26)], []) + v = sum([self.completions(chr(65 + n)) for n in range(26)], []) + sum([self.completions(chr(97 + n)) for n in range(26)], []) except RuntimeError: red_in = '\033[31m' red_out = '\033[0m' @@ -560,6 +545,7 @@ def _tab_completion(self, verbose=True, use_disk_cache=True) -> list: return self.__tab_completion except AttributeError: import sage.misc.persist + if use_disk_cache: try: self.__tab_completion = sage.misc.persist.load(COMMANDS_CACHE) @@ -586,8 +572,7 @@ def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if """ line += ';' with gc_disabled(): - z = Expect._eval_line(self, line, allow_use_file=allow_use_file, - wait_for_prompt=wait_for_prompt).replace('\\\n', '').strip() + z = Expect._eval_line(self, line, allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt).replace('\\\n', '').strip() if z.lower().find("error") != -1: raise RuntimeError("An error occurred running a Maple command:\nINPUT:\n%s\nOUTPUT:\n%s" % (line, z)) return z @@ -1016,25 +1001,22 @@ def _richcmp_(self, other, op) -> bool: 'true' """ P = self.parent() - if P.eval("evalb(%s %s %s)" % (self.name(), P._equality_symbol(), - other.name())) == P._true_symbol(): + if P.eval("evalb(%s %s %s)" % (self.name(), P._equality_symbol(), other.name())) == P._true_symbol(): return rich_to_bool(op, 0) # Maple does not allow comparing objects of different types and # it raises an error in this case. # We catch the error, and return True for < try: - if P.eval("evalb(%s %s %s)" % (self.name(), P._lessthan_symbol(), - other.name())) == P._true_symbol(): + if P.eval("evalb(%s %s %s)" % (self.name(), P._lessthan_symbol(), other.name())) == P._true_symbol(): return rich_to_bool(op, -1) except RuntimeError as e: msg = str(e) if 'is not valid' in msg and 'to < or <=' in msg: - if (hash(str(self)) < hash(str(other))): + if hash(str(self)) < hash(str(other)): return rich_to_bool(op, -1) return rich_to_bool(op, 1) raise RuntimeError(e) - if P.eval("evalb(%s %s %s)" % (self.name(), P._greaterthan_symbol(), - other.name())) == P._true_symbol(): + if P.eval("evalb(%s %s %s)" % (self.name(), P._greaterthan_symbol(), other.name())) == P._true_symbol(): return rich_to_bool(op, 1) return NotImplemented @@ -1242,30 +1224,30 @@ def _sage_(self): from sage.modules.free_module_element import vector from sage.rings.integer_ring import ZZ from sage.symbolic.expression import symbol_table + symbol_maple = symbol_table["maple"] # The next few lines are a very crude excuse for a maple "parser" maple_type = repr(self.whattype()) result = repr(self) result = result.replace("Pi", "pi") - if maple_type == 'symbol': # pi - pass # left to symbolic ring - elif maple_type == 'string': # "banane" + if maple_type == 'symbol': # pi + pass # left to symbolic ring + elif maple_type == 'string': # "banane" return result - elif maple_type == 'exprseq': # 2, 2 + elif maple_type == 'exprseq': # 2, 2 n = self.parent()(f"[{self._name}]").nops()._sage_() return tuple(self[i] for i in range(1, n + 1)) - elif maple_type == 'set': # {1, 2} + elif maple_type == 'set': # {1, 2} n = self.nops()._sage_() return set(self.op(i)._sage_() for i in range(1, n + 1)) - elif maple_type == 'list': # [1, 2] + elif maple_type == 'list': # [1, 2] n = self.nops()._sage_() return [self.op(i)._sage_() for i in range(1, n + 1)] - elif maple_type == "Matrix": # Matrix(2, 2, [[1,2],[3,4]]) + elif maple_type == "Matrix": # Matrix(2, 2, [[1,2],[3,4]]) mn = self.op(1) m = mn[1]._sage_() n = mn[2]._sage_() - coeffs = [self[i + 1, j + 1]._sage_() - for i in range(m) for j in range(n)] + coeffs = [self[i + 1, j + 1]._sage_() for i in range(m) for j in range(n)] return matrix(m, n, coeffs) elif maple_type[:6] == "Vector": # Vector[row](3, [4,5,6]) n = self.op(1)._sage_() @@ -1279,18 +1261,21 @@ def _sage_(self): fun = str(self.op(0)) if fun in ['Sum', 'sum']: from sage.misc.functional import symbolic_sum + term = self.op(1)._sage_() variable = self.op(2).op(1)._sage_() bounds = [b._sage_() for b in self.op(2).op(2).op()] return symbolic_sum(term, variable, *bounds, hold=True) if fun in ['Int', 'int']: from sage.misc.functional import integral + term = self.op(1)._sage_() variable = self.op(2).op(1)._sage_() bounds = [b._sage_() for b in self.op(2).op(2).op()] return integral(term, variable, *bounds, hold=True) if fun in ['Product', 'product']: from sage.misc.functional import symbolic_prod + term = self.op(1)._sage_() variable = self.op(2).op(1)._sage_() bounds = [b._sage_() for b in self.op(2).op(2).op()] @@ -1306,6 +1291,7 @@ def _sage_(self): pass elif maple_type == "float": from sage.rings.real_mpfr import RealField + mantissa = len(repr(self.op(1))) prec = max(53, (mantissa * 13301) // 4004) R = RealField(prec) @@ -1314,13 +1300,15 @@ def _sage_(self): return sum(term._sage_() for term in self.op()) elif maple_type == '`*`': from sage.misc.misc_c import prod + return prod(term._sage_() for term in self.op()) elif maple_type == '`^`': - return self.op(1)._sage_()**self.op(2)._sage_() - elif maple_type == '`=`': # (1, 1) = 2 - return (self.op(1)._sage_() == self.op(2)._sage_()) + return self.op(1)._sage_() ** self.op(2)._sage_() + elif maple_type == '`=`': # (1, 1) = 2 + return self.op(1)._sage_() == self.op(2)._sage_() try: from sage.symbolic.ring import SR + return SR(result) except Exception: raise NotImplementedError("Unable to parse Maple output: %s" % result) @@ -1357,6 +1345,7 @@ def maple_console(): > """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%maple magics instead.') os.system('maple') @@ -1375,6 +1364,7 @@ def __doctest_cleanup(): False """ import sage.interfaces.quit + sage.interfaces.quit.expect_quitall() diff --git a/src/sage/interfaces/mathematica.py b/src/sage/interfaces/mathematica.py index d88e7982ed8..1e481643ddf 100644 --- a/src/sage/interfaces/mathematica.py +++ b/src/sage/interfaces/mathematica.py @@ -433,8 +433,7 @@ import re from sage.misc.cachefunc import cached_method -from sage.interfaces.expect import (Expect, ExpectElement, ExpectFunction, - FunctionElement) +from sage.interfaces.expect import Expect, ExpectElement, ExpectFunction, FunctionElement from sage.interfaces.interface import AsciiArtString from sage.interfaces.tab_completion import ExtraTabCompletion from sage.misc.instancedoc import instancedoc @@ -446,7 +445,7 @@ def clean_output(s): return '' i = s.find('Out[') j = i + s[i:].find('=') - s = s[:i] + ' ' * (j + 1 - i) + s[j + 1:] + s = s[:i] + ' ' * (j + 1 - i) + s[j + 1 :] s = s.replace('\\\n', '') return s.strip('\n') @@ -474,8 +473,8 @@ class Mathematica(ExtraTabCompletion, Expect): """ Interface to the Mathematica interpreter. """ - def __init__(self, maxread=None, script_subdirectory=None, logfile=None, server=None, - server_tmpdir=None, command=None, verbose_start=False): + + def __init__(self, maxread=None, script_subdirectory=None, logfile=None, server=None, server_tmpdir=None, command=None, verbose_start=False): r""" TESTS: @@ -507,17 +506,7 @@ def __init__(self, maxread=None, script_subdirectory=None, logfile=None, server= command = 'stty -echo; {}'.format(command) else: command = 'sh -c "stty -echo; {}"'.format(command) - Expect.__init__(self, - name='mathematica', - terminal_echo=False, - command=command, - prompt=r'In\[[0-9]+\]:= ', - server=server, - server_tmpdir=server_tmpdir, - script_subdirectory=script_subdirectory, - verbose_start=verbose_start, - logfile=logfile, - eval_using_file_cutoff=eval_using_file_cutoff) + Expect.__init__(self, name='mathematica', terminal_echo=False, command=command, prompt=r'In\[[0-9]+\]:= ', server=server, server_tmpdir=server_tmpdir, script_subdirectory=script_subdirectory, verbose_start=verbose_start, logfile=logfile, eval_using_file_cutoff=eval_using_file_cutoff) def _read_in_file_command(self, filename): return '<<"%s"' % filename @@ -619,8 +608,7 @@ def get(self, var, ascii_art=False): return self.eval('InputForm[%s, NumberMarks->False]' % var, strip=True) def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if_needed=False): - s = Expect._eval_line(self, line, - allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt) + s = Expect._eval_line(self, line, allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt) return str(s).strip('\n') def _function_call_string(self, function, args, kwds): @@ -731,12 +719,12 @@ def _reduce(self): return self.parent().eval('InputForm[%s]' % self.name()).strip() def __reduce__(self): - return reduce_load, (self._reduce(), ) + return reduce_load, (self._reduce(),) def _latex_(self): z = self.parent().eval('TeXForm[%s]' % self.name()) i = z.find('=') - return z[i + 1:].strip() + return z[i + 1 :].strip() def _repr_(self): P = self.parent() @@ -845,8 +833,11 @@ def _sage_(self, locals={}): # Get Mathematica's output and perform preliminary formatting res = self._sage_repr() if '"' in res: - raise NotImplementedError("String conversion from Mathematica \ - does not work. Mathematica's output was: %s" % res) + raise NotImplementedError( + "String conversion from Mathematica \ + does not work. Mathematica's output was: %s" + % res + ) # Find all the mathematica functions, constants and symbolic variables # present in `res`. Convert MMA functions and constants to their @@ -863,9 +854,7 @@ def _sage_(self, locals={}): lsymbols.update(locals) # Strategies for translating unknown functions/constants: - autotrans = [str.lower, # Try it in lower case - _un_camel, # Convert `CamelCase` to `camel_case` - lambda x: x] # Try the original name + autotrans = [str.lower, _un_camel, lambda x: x] # Try it in lower case # Convert `CamelCase` to `camel_case` # Try the original name # Find the MMA funcs/vars/constants - they start with a letter. # Exclude exponents (e.g. 'e8' from 4.e8) @@ -884,9 +873,12 @@ def _sage_(self, locals={}): lsymbols[m.group()] = f break else: - raise NotImplementedError("Don't know a Sage equivalent \ + raise NotImplementedError( + "Don't know a Sage equivalent \ for Mathematica function '%s'. Please specify one \ - manually using the 'locals' dictionary" % m.group()) + manually using the 'locals' dictionary" + % m.group() + ) # Check if Sage has an equivalent constant else: for t in autotrans: @@ -896,11 +888,13 @@ def _sage_(self, locals={}): # If Sage has never heard of the variable, then # symbolic_expression_from_string will automatically create it try: - return symbolic_expression_from_string(res, lsymbols, - accept_sequence=True) + return symbolic_expression_from_string(res, lsymbols, accept_sequence=True) except Exception: - raise NotImplementedError("Unable to parse Mathematica \ - output: %s" % res) + raise NotImplementedError( + "Unable to parse Mathematica \ + output: %s" + % res + ) def __str__(self): P = self._check_valid() @@ -957,8 +951,7 @@ def save_image(self, filename, ImageSize=600): if not self._is_graphics(): raise ValueError('mathematica expression is not graphics') filename = os.path.abspath(filename) - s = 'Export["%s", %s, ImageSize->%s]' % (filename, self.name(), - ImageSize) + s = 'Export["%s", %s, ImageSize->%s]' % (filename, self.name(), ImageSize) P.eval(s) def _rich_repr_(self, display_manager, **kwds): @@ -984,8 +977,7 @@ def _rich_repr_(self, display_manager, **kwds): if display_manager.preferences.graphics == 'disable': return if OutputImagePng in display_manager.supported_output(): - return display_manager.graphics_from_save( - self.save_image, kwds, '.png', OutputImagePng) + return display_manager.graphics_from_save(self.save_image, kwds, '.png', OutputImagePng) else: OutputLatex = display_manager.types.OutputLatex dmp = display_manager.preferences.text @@ -1027,6 +1019,7 @@ def show(self, ImageSize=600): sage: P.show(ImageSize=800) # optional - mathematica mathematicafrontend """ from sage.repl.rich_output import get_display_manager + dm = get_display_manager() dm.display_immediately(self, ImageSize=ImageSize) @@ -1107,6 +1100,7 @@ def reduce_load(X): def mathematica_console(readline=True): from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%mathematica magics instead.') if not readline: @@ -1118,6 +1112,7 @@ def mathematica_console(readline=True): # some tools for online interface + def request_wolfram_alpha(input, verbose=False): r""" Request Wolfram Alpha website. @@ -1165,8 +1160,7 @@ def request_wolfram_alpha(input, verbose=False): # we need cookies for this... cj = CookieJar() - opener = build_opener(HTTPCookieProcessor(cj), - HTTPSHandler(context=default_context())) + opener = build_opener(HTTPCookieProcessor(cj), HTTPSHandler(context=default_context())) # build initial query for code req = Request("https://www.wolframalpha.com/input/api/v1/code") resp = opener.open(req) @@ -1182,24 +1176,7 @@ def request_wolfram_alpha(input, verbose=False): # some parameters documented here: # https://products.wolframalpha.com/api/documentation/#parameter-reference # the following are the parameters used by the website - params = { - 'assumptionsversion': '2', - 'async': 'true', - 'banners': 'raw', - 'debuggingdata': 'false', - 'format': 'image,plaintext,imagemap,sound,minput,moutput', - 'formattimeout': '8', - 'input': input, - 'output': 'JSON', - 'parsetimeout': '5', - 'podinfosasync': 'true', - 'proxycode': proxy_code, - 'recalcscheme': 'parallel', - 'sbsdetails': 'true', - 'scantimeout': '0.5', - 'sponsorcategories': 'true', - 'statemethod': 'deploybutton', - 'storesubpodexprs': 'true'} + params = {'assumptionsversion': '2', 'async': 'true', 'banners': 'raw', 'debuggingdata': 'false', 'format': 'image,plaintext,imagemap,sound,minput,moutput', 'formattimeout': '8', 'input': input, 'output': 'JSON', 'parsetimeout': '5', 'podinfosasync': 'true', 'proxycode': proxy_code, 'recalcscheme': 'parallel', 'sbsdetails': 'true', 'scantimeout': '0.5', 'sponsorcategories': 'true', 'statemethod': 'deploybutton', 'storesubpodexprs': 'true'} # # we can also change some parameters # params = { # 'assumptionsversion': '2', @@ -1311,9 +1288,7 @@ def symbolic_expression_from_mathematica_string(mexpr): expr = expr.replace('{', '[').replace('}', ']') lsymbols = symbol_table['mathematica'].copy() lsymbols_names_only = [s[0] for s in lsymbols] - autotrans = [lambda x:x.lower(), # Try it in lower case - _un_camel, # Convert `CamelCase` to `camel_case` - lambda x: x] # Try the original name + autotrans = [lambda x: x.lower(), _un_camel, lambda x: x] # Try it in lower case # Convert `CamelCase` to `camel_case` # Try the original name # Find the MMA funcs/vars/constants - they start with a letter. # Exclude exponents (e.g. 'e8' from 4.e8) p = re.compile(r'(? """ from sage.symbolic.ring import SR + try: name = self.name if name.startswith('_Mathics_User_'): @@ -464,11 +465,8 @@ class Mathics(Interface): More examples can be found in the module header. """ - def __init__(self, - maxread=None, - logfile=None, - init_list_length=1024, - seed=None): + + def __init__(self, maxread=None, logfile=None, init_list_length=1024, seed=None): r""" Python constructor. @@ -513,11 +511,14 @@ def _start(self): if not self._session: from mathics.session import MathicsSession from mathics.core.load_builtin import import_and_load_builtins + import_and_load_builtins() self._session = MathicsSession() from sage.interfaces.sympy import sympy_init + sympy_init() from sympy import Symbol + Symbol._sage_ = _mathics_sympysage_symbol def _read_in_file_command(self, filename): @@ -563,6 +564,7 @@ def _eval(self, code): S = self._session expr = S.evaluate(code) from mathics.core.evaluation import Evaluation + ev = Evaluation(S.definitions) return ev.evaluate(expr) @@ -946,7 +948,7 @@ def __reduce__(self): sage: loads(dumps(mpol)) == mpol # optional - mathics True """ - return reduce_load, (self._reduce(), ) + return reduce_load, (self._reduce(),) def _latex_(self): r""" @@ -958,7 +960,7 @@ def _latex_(self): """ z = str(self.parent()('TeXForm[%s]' % self.name())) i = z.find('=') - return z[i + 1:] + return z[i + 1 :] def _repr_(self): r""" @@ -1050,6 +1052,7 @@ def _sage_(self, locals={}): # if locals are given we use `_sage_repr` # surely this only covers simple cases from sage.misc.sage_eval import sage_eval + return sage_eval(self._sage_repr(), locals=locals) self._check_valid() @@ -1057,6 +1060,7 @@ def _sage_(self, locals={}): m = self.to_mpmath() if self is not m and m is not None: from sage.libs.mpmath.utils import mpmath_to_sage + return mpmath_to_sage(m, self.get_precision()) s = self.to_sympy() if self is not s and s is not None: @@ -1067,8 +1071,10 @@ def _sage_(self, locals={}): pass p = self.to_python() if self is not p and p is not None: + def conv(i): return self.parent()(i).sage() + if isinstance(p, list): return [conv(i) for i in p] if isinstance(p, tuple): @@ -1151,8 +1157,7 @@ def _rich_repr_(self, display_manager, **kwds): if display_manager.preferences.graphics == 'disable': return if OutputImageSvg in display_manager.supported_output(): - return display_manager.graphics_from_save( - self.save_image, kwds, '.svg', OutputImageSvg) + return display_manager.graphics_from_save(self.save_image, kwds, '.svg', OutputImageSvg) else: OutputLatex = display_manager.types.OutputLatex dmp = display_manager.preferences.text @@ -1191,6 +1196,7 @@ def show(self, ImageSize=600): sage: P.show(ImageSize=800) # optional - mathics """ from sage.repl.rich_output import get_display_manager + dm = get_display_manager() dm.display_immediately(self, ImageSize=ImageSize) @@ -1303,7 +1309,9 @@ def mathics_console(): Goodbye! """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%mathics magics instead.') from mathics import main + main.main() diff --git a/src/sage/interfaces/matlab.py b/src/sage/interfaces/matlab.py index 3839e3aa178..0dc462adf98 100644 --- a/src/sage/interfaces/matlab.py +++ b/src/sage/interfaces/matlab.py @@ -173,19 +173,9 @@ class Matlab(Expect): 122 505 """ - def __init__(self, maxread=None, script_subdirectory=None, - logfile=None, server=None, server_tmpdir=None): - Expect.__init__(self, - name='matlab', - prompt='>> ', - command="matlab -nodisplay", - server=server, - server_tmpdir=server_tmpdir, - script_subdirectory=script_subdirectory, - restart_on_ctrlc=False, - verbose_start=False, - logfile=logfile, - eval_using_file_cutoff=100) + + def __init__(self, maxread=None, script_subdirectory=None, logfile=None, server=None, server_tmpdir=None): + Expect.__init__(self, name='matlab', prompt='>> ', command="matlab -nodisplay", server=server, server_tmpdir=server_tmpdir, script_subdirectory=script_subdirectory, restart_on_ctrlc=False, verbose_start=False, logfile=logfile, eval_using_file_cutoff=100) def __reduce__(self): return reduce_load_Matlab, tuple([]) @@ -228,21 +218,21 @@ def _start(self): def whos(self): return self.eval('whos') -# pdehaye/20070819: This is no obsolete, see Expect._get_tmpfile_from_server and Expect._send_tmpfile_to_server + # pdehaye/20070819: This is no obsolete, see Expect._get_tmpfile_from_server and Expect._send_tmpfile_to_server -# def get_via_file(self, var_name): -# t = self._temp_file(var_name) -# self.eval('save -text "%s" %s'%(t,var_name)) -# r = open(t).read() -# os.unlink(t) -# return r.strip('\n') + # def get_via_file(self, var_name): + # t = self._temp_file(var_name) + # self.eval('save -text "%s" %s'%(t,var_name)) + # r = open(t).read() + # os.unlink(t) + # return r.strip('\n') -# def set_via_file(self, var_name, x): -# t = self._temp_file(var_name) -# open(t,'w').write(x) -# print('load "%s" %s'%(t, var_name)) -# self.eval('load "%s" %s'%(t, var_name)) -# #os.unlink(t) + # def set_via_file(self, var_name, x): + # t = self._temp_file(var_name) + # open(t,'w').write(x) + # print('load "%s" %s'%(t, var_name)) + # self.eval('load "%s" %s'%(t, var_name)) + # #os.unlink(t) def set(self, var, value): """ @@ -277,7 +267,7 @@ def strip_answer(self, s): ' 2' """ i = s.find('=') - return s[i+1:].strip('\n') + return s[i + 1 :].strip('\n') def console(self): matlab_console() @@ -350,6 +340,7 @@ def _matrix_(self, R): 50 x 50 dense matrix over Real Field with 53 bits of precision """ from sage.matrix.constructor import matrix + matlab = self.parent() entries = matlab.strip_answer(matlab.eval("mat2str({0})".format(self.name()))) entries = entries.strip()[1:-1].replace(';', ' ') @@ -396,6 +387,7 @@ def matlab_console(): another. """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%matlab magics instead.') os.system('matlab -nodisplay') diff --git a/src/sage/interfaces/maxima.py b/src/sage/interfaces/maxima.py index 73dc7b08014..85095f218fa 100644 --- a/src/sage/interfaces/maxima.py +++ b/src/sage/interfaces/maxima.py @@ -540,8 +540,8 @@ class Maxima(MaximaAbstract, Expect): sage: m == maxima False """ - def __init__(self, script_subdirectory=None, logfile=None, server=None, - init_code=None): + + def __init__(self, script_subdirectory=None, logfile=None, server=None, init_code=None): """ Create an instance of the Maxima interpreter. @@ -592,28 +592,14 @@ def __init__(self, script_subdirectory=None, logfile=None, server=None, env['MAXIMA_PREFIX'] = MAXIMA_PREFIX MaximaAbstract.__init__(self, "maxima") - Expect.__init__(self, - name='maxima', - prompt=r'\(\%i[0-9]+\) ', - command='{0} -p {1}'.format(MAXIMA, shlex.quote(STARTUP)), - env=env, - script_subdirectory=script_subdirectory, - restart_on_ctrlc=False, - verbose_start=False, - init_code=init_code, - logfile=logfile, - eval_using_file_cutoff=eval_using_file_cutoff) + Expect.__init__(self, name='maxima', prompt=r'\(\%i[0-9]+\) ', command='{0} -p {1}'.format(MAXIMA, shlex.quote(STARTUP)), env=env, script_subdirectory=script_subdirectory, restart_on_ctrlc=False, verbose_start=False, init_code=init_code, logfile=logfile, eval_using_file_cutoff=eval_using_file_cutoff) # Must match what is in the file sage-maxima.lisp self._display_prompt = '' # See #15440 for the importance of the trailing space self._output_prompt_re = re.compile(r'\(\%o[0-9]+\) ') - self._ask = [b'zero or nonzero\\?', b'an integer\\?', - b'positive, negative or zero\\?', b'positive or negative\\?', - b'positive or zero\\?', b'equal to .*\\?'] + self._ask = [b'zero or nonzero\\?', b'an integer\\?', b'positive, negative or zero\\?', b'positive or negative\\?', b'positive or zero\\?', b'equal to .*\\?'] - self._prompt_wait = ([self._prompt] + - [re.compile(x) for x in self._ask] + - [b'Break [0-9]+']) + self._prompt_wait = [self._prompt] + [re.compile(x) for x in self._ask] + [b'Break [0-9]+'] # note that you might need to change _expect_expr if you # change this _prompt_wait @@ -761,18 +747,12 @@ def _expect_expr(self, expr=None, timeout=None): # Note that this depends on the order of self._prompt_wait if expr is self._prompt_wait and i > len(self._ask): self.quit() - raise ValueError( - "{}\nComputation failed due to a bug in Maxima " - "-- NOTE: Maxima had to be restarted.".format(v)) + raise ValueError("{}\nComputation failed due to a bug in Maxima " "-- NOTE: Maxima had to be restarted.".format(v)) j = v.find('Is ') v = v[j:] k = v.find(' ', 3) - msg = "Computation failed since Maxima requested additional " \ - "constraints (try the command " \ - "\"maxima.assume('{}>0')\" " \ - "before integral or limit evaluation, for example):\n" \ - "{}{}".format(v[3:k], v, self._after()) + msg = "Computation failed since Maxima requested additional " "constraints (try the command " "\"maxima.assume('{}>0')\" " "before integral or limit evaluation, for example):\n" "{}{}".format(v[3:k], v, self._after()) self._sendline(";") self._expect_expr() raise ValueError(msg) @@ -781,8 +761,8 @@ def _expect_expr(self, expr=None, timeout=None): while True: try: print("Control-C pressed. Interrupting Maxima. Please wait a few seconds...") - self._sendstr('quit;\n'+chr(3)) - self._sendstr('quit;\n'+chr(3)) + self._sendstr('quit;\n' + chr(3)) + self._sendstr('quit;\n' + chr(3)) self.interrupt() self.interrupt() except KeyboardInterrupt: @@ -793,8 +773,7 @@ def _expect_expr(self, expr=None, timeout=None): break raise KeyboardInterrupt(msg) - def _eval_line(self, line, allow_use_file=False, - wait_for_prompt=True, reformat=True, error_check=True, restart_if_needed=False): + def _eval_line(self, line, allow_use_file=False, wait_for_prompt=True, reformat=True, error_check=True, restart_if_needed=False): """ Return result of line evaluation. @@ -842,12 +821,11 @@ def _eval_line(self, line, allow_use_file=False, return out self._expect_expr() - assert len(self._before()) == 0, \ - 'Maxima expect interface is confused!' + assert len(self._before()) == 0, 'Maxima expect interface is confused!' r = self._output_prompt_re m = r.search(out) if m is not None: - out = out[m.end():] + out = out[m.end() :] return re.sub(r'\s+', ' ', out).rstrip() def _synchronize(self): @@ -877,7 +855,7 @@ def _synchronize(self): if self._expect is None: return r = randrange(2147483647) - s = marker + str(r+1) + s = marker + str(r + 1) # The 0; *is* necessary... it comes up in certain rare cases # that are revealed by extensive testing. @@ -930,7 +908,7 @@ def _batch(self, s, batchload=True): cmd = 'batch("%s");' % tmp_to_use r = randrange(2147483647) - s = str(r+1) + s = str(r + 1) cmd = "%s1+%s;\n" % (cmd, r) self._sendline(cmd) @@ -1021,8 +999,7 @@ def lisp(self, cmd): 19 ( """ - self._eval_line(':lisp %s\n""' % cmd, allow_use_file=False, - wait_for_prompt=False, reformat=False, error_check=False) + self._eval_line(':lisp %s\n""' % cmd, allow_use_file=False, wait_for_prompt=False, reformat=False, error_check=False) self._expect_expr('(%i)') return self._before() @@ -1139,6 +1116,7 @@ def _object_function_class(self): # living in the symbolic ring and return something # that is hopefully coercible into the symbolic ring again. + # def sr_integral(self, *args): # return args[0]._maxima_().integrate(*args[1:]) @@ -1265,14 +1243,11 @@ def __init__(self, parent, name, defn, args, latex): False """ MaximaElement.__init__(self, parent, name, is_name=True) - MaximaAbstractElementFunction.__init__(self, parent, - name, defn, args, latex) + MaximaAbstractElementFunction.__init__(self, parent, name, defn, args, latex) # An instance -maxima = Maxima(init_code=['display2d : false', - 'domain : complex', 'keepfloat : true'], - script_subdirectory=None) +maxima = Maxima(init_code=['display2d : false', 'domain : complex', 'keepfloat : true'], script_subdirectory=None) def reduce_load_Maxima(): # (init_code=None): @@ -1321,4 +1296,5 @@ def __doctest_cleanup(): False """ import sage.interfaces.quit + sage.interfaces.quit.expect_quitall() diff --git a/src/sage/interfaces/maxima_abstract.py b/src/sage/interfaces/maxima_abstract.py index 7de873341b2..31c763f9c49 100644 --- a/src/sage/interfaces/maxima_abstract.py +++ b/src/sage/interfaces/maxima_abstract.py @@ -156,16 +156,15 @@ def _command_runner(self, command, s, redirect=True): env = os.environ.copy() if redirect: - res = bytes_to_str(subprocess.check_output(cmd, shell=True, - env=env)) + res = bytes_to_str(subprocess.check_output(cmd, shell=True, env=env)) # We get a few lines of commented verbosity every time Maxima starts while res.startswith(';;;'): newline = res.find('\n') if newline == -1: break - res = res[newline + 1:] + res = res[newline + 1 :] # The input is echoed, so we need to get rid of it - res = res[res.find('\n')+1:] + res = res[res.find('\n') + 1 :] return AsciiArtString(res) subprocess.check_call(cmd, shell=True, env=env) @@ -309,14 +308,11 @@ def _commands(self): """ # Passing the empty string to apropos() gets ALL names. - all_names = self._eval_line('apropos("")', - error_check=False).split(",") + all_names = self._eval_line('apropos("")', error_check=False).split(",") # At the time of writing, searching a string for a specific # character was much much faster than searching a list/tuple. - a_to_Z = "".join(chr(i+j) - for i in range(ord('A'),ord('Z')+1) - for j in (0, 32)) # 'a' = 'A' + 32 + a_to_Z = "".join(chr(i + j) for i in range(ord('A'), ord('Z') + 1) for j in (0, 32)) # 'a' = 'A' + 32 # Whack-a-mole to kill junk entries: # @@ -336,11 +332,7 @@ def _commands(self): # with random leading spaces: ' tminverse', ' toeplitz', etc. # bad_chars = ("\\", "/", "?", "%") - return [c - for n in all_names - if (c := n.strip()) - and c[0] in a_to_Z - and not any(bad in c for bad in bad_chars)] + return [c for n in all_names if (c := n.strip()) and c[0] in a_to_Z and not any(bad in c for bad in bad_chars)] def _tab_completion(self, verbose=True, use_disk_cache=True): r""" @@ -367,6 +359,7 @@ def _tab_completion(self, verbose=True, use_disk_cache=True): return self.__tab_completion except AttributeError: import sage.misc.persist + if use_disk_cache: try: self.__tab_completion = sage.misc.persist.load(COMMANDS_CACHE) @@ -666,29 +659,29 @@ def function(self, args, defn, rep=None, latex=None): f = self._object_function_class()(self, name, rep, args, latex) return f -# def display2d(self, flag=True): -# """ -# Set the flag that determines whether Maxima objects are -# printed using their 2-d ASCII art representation. When the -# maxima interface starts the default is that objects are not -# represented in 2-d. + # def display2d(self, flag=True): + # """ + # Set the flag that determines whether Maxima objects are + # printed using their 2-d ASCII art representation. When the + # maxima interface starts the default is that objects are not + # represented in 2-d. -# INPUT: + # INPUT: -# flag -- boolean (default: ``True``) + # flag -- boolean (default: ``True``) -# EXAMPLES:: + # EXAMPLES:: -# sage: maxima('1/2') -# 1/2 -# sage: maxima.display2d(True) -# sage: maxima('1/2') -# 1 -# - -# 2 -# sage: maxima.display2d(False) -# """ -# self._display2d = bool(flag) + # sage: maxima('1/2') + # 1/2 + # sage: maxima.display2d(True) + # sage: maxima('1/2') + # 1 + # - + # 2 + # sage: maxima.display2d(False) + # """ + # self._display2d = bool(flag) def plot2d(self, *args): r""" @@ -753,8 +746,7 @@ def plot2d_parametric(self, r, var, trange, nticks=50, options=None): """ tmin = trange[0] tmax = trange[1] - cmd = "plot2d([parametric, %s, %s, [%s, %s, %s], [nticks, %s]]" % ( - r[0], r[1], var, tmin, tmax, nticks) + cmd = "plot2d([parametric, %s, %s, [%s, %s, %s], [nticks, %s]]" % (r[0], r[1], var, tmin, tmax, nticks) if options is None: cmd += ")" else: @@ -835,8 +827,7 @@ def plot3d_parametric(self, r, vars, urange, vrange, options=None): umax = urange[1] vmin = vrange[0] vmax = vrange[1] - cmd = 'plot3d([%s, %s, %s], [%s, %s, %s], [%s, %s, %s]' % ( - r[0], r[1], r[2], vars[0], umin, umax, vars[1], vmin, vmax) + cmd = 'plot3d([%s, %s, %s], [%s, %s, %s], [%s, %s, %s]' % (r[0], r[1], r[2], vars[0], umin, umax, vars[1], vmin, vmax) if options is None: cmd += ')' else: @@ -879,11 +870,10 @@ def de_solve(self, de, vars, ics=None): a = 'ode2(%s, %s)' % (m.name(), str_vars) if ics is not None: if len(ics) == 3: - cmd = "ic2("+a+",%s=%s,%s=%s,diff(%s,%s)=%s);" % (vars[0], ics[0], vars[1], ics[1], vars[1], vars[0], ics[2]) + cmd = "ic2(" + a + ",%s=%s,%s=%s,diff(%s,%s)=%s);" % (vars[0], ics[0], vars[1], ics[1], vars[1], vars[0], ics[2]) return self(cmd) if len(ics) == 2: - return self("ic1("+a+",%s=%s,%s=%s);" % (vars[0], ics[0], - vars[1], ics[1])) + return self("ic1(" + a + ",%s=%s,%s=%s);" % (vars[0], ics[0], vars[1], ics[1])) return self(a + ";") def de_solve_laplace(self, de, vars, ics=None): @@ -933,8 +923,7 @@ def de_solve_laplace(self, de, vars, ics=None): if ics is not None: d = len(ics) for i in range(d - 1): - ic = 'atvalue(diff(%s(%s), %s, %s), %s = %s, %s)' % ( - vars[1], vars[0], vars[0], i, vars[0], ics[0], ics[1+i]) + ic = 'atvalue(diff(%s(%s), %s, %s), %s = %s, %s)' % (vars[1], vars[0], vars[0], i, vars[0], ics[0], ics[1 + i]) self.eval(ic) return self('desolve(%s, %s(%s))' % (de, vars[1], vars[0])) @@ -996,6 +985,7 @@ def unit_quadratic_integer(self, n): """ from sage.rings.integer import Integer from sage.rings.number_field.number_field import QuadraticField + # Take square-free part so sqrt(n) doesn't get simplified # further by maxima # (The original version of this function would yield wrong answers if @@ -1095,14 +1085,14 @@ def plot_multilist(self, pts_list, options=None): n = len(pts_list) cmd = '[' for i in range(n): - if i < n-1: - cmd = cmd+'[discrete,'+str(pts_list[i][0])+','+str(pts_list[i][1])+'],' - if i == n-1: - cmd = cmd+'[discrete,'+str(pts_list[i][0])+','+str(pts_list[i][1])+']]' + if i < n - 1: + cmd = cmd + '[discrete,' + str(pts_list[i][0]) + ',' + str(pts_list[i][1]) + '],' + if i == n - 1: + cmd = cmd + '[discrete,' + str(pts_list[i][0]) + ',' + str(pts_list[i][1]) + ']]' if options is None: - self('plot2d('+cmd+')') + self('plot2d(' + cmd + ')') else: - self('plot2d('+cmd+','+options+')') + self('plot2d(' + cmd + ',' + options + ')') @instancedoc @@ -1120,6 +1110,7 @@ class MaximaAbstractElement(ExtraTabCompletion, InterfaceElement): sage: type(xp) """ + _cached_repr = True def __str__(self): @@ -1160,8 +1151,7 @@ def __bool__(self): True """ P = self._check_valid() - return (P.eval('is({0} = 0 or {0} = false);'.format(self.name())) - != P._true_symbol()) + return P.eval('is({0} = 0 or {0} = false);'.format(self.name())) != P._true_symbol() # but be careful, since for relations things like is(equal(a,b)) are # what Maxima needs @@ -1270,8 +1260,8 @@ def _sage_(self): (True, False) """ from sage.calculus import calculus - return calculus.symbolic_expression_from_maxima_string(self.name(), - maxima=self.parent()) + + return calculus.symbolic_expression_from_maxima_string(self.name(), maxima=self.parent()) def _symbolic_(self, R): """ @@ -1491,9 +1481,7 @@ def diff(self, var='x', n=1): derivative = diff - def nintegral(self, var='x', a=0, b=1, - desired_relative_error='1e-8', - maximum_num_subintervals=200): + def nintegral(self, var='x', a=0, b=1, desired_relative_error='1e-8', maximum_num_subintervals=200): r""" Return a numerical approximation to the integral of ``self`` from `a` to `b`. @@ -1551,8 +1539,8 @@ def nintegral(self, var='x', a=0, b=1, 0.52848223531423071361790491935415653021675547587292866196865279321015401702040079 """ from sage.rings.integer import Integer - v = self.quad_qags(var, a, b, epsrel=desired_relative_error, - limit=maximum_num_subintervals) + + v = self.quad_qags(var, a, b, epsrel=desired_relative_error, limit=maximum_num_subintervals) return v[0], v[1], Integer(v[2]), Integer(v[3]) def integral(self, var='x', min=None, max=None): @@ -1709,9 +1697,9 @@ def __getitem__(self, i): return list(self)[i] i = operator.index(i) if i < 0 or i >= len(self): - raise IndexError("i = (%s) must be between %s and %s" % (i, 0, len(self)-1)) + raise IndexError("i = (%s) must be between %s and %s" % (i, 0, len(self) - 1)) # If you change the i+1 to i below, better change __iter__ as well. - return InterfaceElement.__getitem__(self, i+1) + return InterfaceElement.__getitem__(self, i + 1) def __iter__(self): """ @@ -1803,9 +1791,7 @@ def _latex_(self): P = self.parent() s = P._eval_line(f"tex({self.name()}, false);", reformat=False) if "$$" not in s: - raise RuntimeError( - f"Error texing Maxima object {self.name()}. Expected '$$' in output, got: {s!r}" - ) + raise RuntimeError(f"Error texing Maxima object {self.name()}. Expected '$$' in output, got: {s!r}") i = s.find("$$") j = s.rfind("$$") s = s[i + 2 : j] @@ -1894,6 +1880,7 @@ def _matrix_(self, R): [ 4 2 4/3 1] """ from sage.matrix.matrix_space import MatrixSpace + self._check_valid() P = self.parent() nrows = int(P.eval('length(%s)' % self.name())) @@ -1901,8 +1888,7 @@ def _matrix_(self, R): return MatrixSpace(R, 0, 0)(0) ncols = int(P.eval('length(%s[1])' % self.name())) M = MatrixSpace(R, nrows, ncols) - s = self.str().replace('matrix', '').replace(',', "','").\ - replace("]','[", "','").replace('([', "['").replace('])', "']") + s = self.str().replace('matrix', '').replace(',', "','").replace("]','[", "','").replace('([', "['").replace('])', "']") s = eval(s) return M([R(x) for x in s]) @@ -2050,8 +2036,7 @@ def __reduce__(self): (, (Maxima, 'sin(x+y)', 'x,y', None)) """ - return reduce_load_MaximaAbstract_function, (self.parent(), - self.__defn, self.__args, self.__latex) + return reduce_load_MaximaAbstract_function, (self.parent(), self.__defn, self.__args, self.__latex) def __call__(self, *args): """ @@ -2176,8 +2161,7 @@ def integral(self, var): """ var = str(var) P = self._check_valid() - f = P('integrate(%s(%s), %s)' % (self.name(), - self.arguments(split=False), var)) + f = P('integrate(%s(%s), %s)' % (self.name(), self.arguments(split=False), var)) args = self.arguments() if var not in args: @@ -2274,6 +2258,7 @@ def maxima_console(): ... """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%maxima magics instead.') os.system('{}'.format(MAXIMA)) diff --git a/src/sage/interfaces/maxima_lib.py b/src/sage/interfaces/maxima_lib.py index 537f7a4bbfa..0716d482abc 100644 --- a/src/sage/interfaces/maxima_lib.py +++ b/src/sage/interfaces/maxima_lib.py @@ -160,6 +160,7 @@ # has multiple components this is quite plausible to happen. maxima_objdir = ecl_eval("*maxima-objdir*").python()[1:-1] import os + os.makedirs(maxima_objdir, exist_ok=True) # Call `(set-pathnames)` again to complete its job. ecl_eval("(set-pathnames)") @@ -177,7 +178,8 @@ # question and returning the answer. Our version throws an error in # which the text of the question is included. This is accomplished by # redirecting *standard-output* to a string. -ecl_eval(r""" +ecl_eval( + r""" (defun retrieve (msg flag &aux (print? nil)) (declare (special msg flag print?)) (or (eq flag 'noprint) (setq print? t)) @@ -200,11 +202,14 @@ (t (format-prompt t "~M" msg) (mterpri)))))))) -""") +""" +) # Redirection of ECL and Maxima stdout to /dev/null -ecl_eval(r"""(defparameter *dev-null* (make-two-way-stream - (make-concatenated-stream) (make-broadcast-stream)))""") +ecl_eval( + r"""(defparameter *dev-null* (make-two-way-stream + (make-concatenated-stream) (make-broadcast-stream)))""" +) ecl_eval("(setf original-standard-output *standard-output*)") ecl_eval("(setf *standard-output* *dev-null*)") # ecl_eval("(setf *error-output* *dev-null*)") @@ -220,9 +225,7 @@ # display2d -- no ascii art output # keepfloat -- don't automatically convert floats to rationals -init_code = ['besselexpand : true', 'display2d : false', 'domain : complex', 'keepfloat : true', - 'load(to_poly_solve)', 'load(simplify_sum)', - 'load(diag)', 'load(abs_integrate)'] +init_code = ['besselexpand : true', 'display2d : false', 'domain : complex', 'keepfloat : true', 'load(to_poly_solve)', 'load(simplify_sum)', 'load(diag)', 'load(abs_integrate)'] # Turn off the prompt labels, since computing them *very @@ -240,10 +243,12 @@ # This is the main function (ECL object) used for evaluation # This returns an EclObject -maxima_eval = ecl_eval(""" +maxima_eval = ecl_eval( + """ (defun maxima-eval( form ) (with-$error (meval form))) -""") +""" +) # Number of instances of this interface maxima_lib_instances = 0 @@ -251,8 +256,10 @@ # Here we define several useful ECL/Maxima objects # The Maxima string function can change the structure of its input # maxprint=EclObject("$STRING") -maxprint = EclObject(r"""(defun mstring-for-sage (form) - (coerce (mstring form) 'string))""").eval() +maxprint = EclObject( + r"""(defun mstring-for-sage (form) + (coerce (mstring form) 'string))""" +).eval() meval = EclObject("MEVAL") msetq = EclObject("MSETQ") mlist = EclObject("MLIST") @@ -295,8 +302,11 @@ def stdout_to_string(s): sage: stdout_to_string('disp(1+1)') '2\n\n' """ - return ecl_eval(r"""(with-output-to-string (*standard-output*) - (maxima-eval #$%s$))""" % s).python()[1:-1] + return ecl_eval( + r"""(with-output-to-string (*standard-output*) + (maxima-eval #$%s$))""" + % s + ).python()[1:-1] def max_to_string(s): @@ -319,10 +329,12 @@ def max_to_string(s): return maxprint(s).python()[1:-1] -my_mread = ecl_eval(""" +my_mread = ecl_eval( + """ (defun my-mread (cmd) (caddr (mread (make-string-input-stream cmd)))) -""") +""" +) def parse_max_string(s): @@ -364,6 +376,7 @@ class MaximaLib(MaximaAbstract): RuntimeError: Maxima interface in library mode can only be instantiated once """ + def __init__(self): """ Create an instance of the Maxima interpreter. @@ -473,12 +486,12 @@ def _eval_line(self, line, locals=None, reformat=True, **kwds): line = '' else: statement = line[:ind_semi] - line = line[ind_semi + 1:] + line = line[ind_semi + 1 :] if statement: result = ((result + '\n') if result else '') + max_to_string(maxima_eval("#$%s$" % statement)) else: statement = line[:ind_dollar] - line = line[ind_dollar + 1:] + line = line[ind_dollar + 1 :] if statement: maxima_eval("#$%s$" % statement) if not reformat: @@ -802,8 +815,7 @@ def sr_integral(self, *args): 2 """ try: - return max_to_sr(maxima_eval(([max_integrate], - [sr_to_max(SR(a)) for a in args]))) + return max_to_sr(maxima_eval(([max_integrate], [sr_to_max(SR(a)) for a in args]))) except RuntimeError as error: s = str(error) if "Divergent" in s or "divergent" in s: @@ -889,10 +901,7 @@ def sr_sum(self, *args): RuntimeError: ECL says: Zero to negative power computed. """ try: - return max_to_sr(maxima_eval([[max_ratsimp], - [[max_simplify_sum], - ([max_sum], - [sr_to_max(SR(a)) for a in args])]])) + return max_to_sr(maxima_eval([[max_ratsimp], [[max_simplify_sum], ([max_sum], [sr_to_max(SR(a)) for a in args])]])) except RuntimeError as error: s = str(error) if "divergent" in s: @@ -919,10 +928,7 @@ def sr_prod(self, *args): 2^n*factorial(n) """ try: - return max_to_sr(maxima_eval([[max_ratsimp], - [[max_simplify_prod], - ([max_prod], - [sr_to_max(SR(a)) for a in args])]])) + return max_to_sr(maxima_eval([[max_ratsimp], [[max_simplify_prod], ([max_prod], [sr_to_max(SR(a)) for a in args])]])) except RuntimeError as error: s = str(error) if "divergent" in s: @@ -1054,8 +1060,7 @@ def _missing_assumption(self, errstr): jj = 3 k = errstr.find(' ', jj + 1) - outstr = "Computation failed since Maxima requested additional constraints; using the 'assume' command before evaluation *may* help (example of legal syntax is 'assume("\ - + errstr[jj + 1:k] + ">0)', see `assume?` for more details)\n" + errstr + outstr = "Computation failed since Maxima requested additional constraints; using the 'assume' command before evaluation *may* help (example of legal syntax is 'assume(" + errstr[jj + 1 : k] + ">0)', see `assume?` for more details)\n" + errstr outstr = outstr.replace("_SAGE_VAR_", "") raise ValueError(outstr) @@ -1118,8 +1123,7 @@ def to_poly_solve(self, vars, options=""): [[x == pi*z...]] """ if options.find("use_grobner=true") != -1: - cmd = EclObject([[max_to_poly_solve], self.ecl(), sr_to_max(vars), - [[mequal], max_use_grobner, True]]) + cmd = EclObject([[max_to_poly_solve], self.ecl(), sr_to_max(vars), [[mequal], max_use_grobner, True]]) else: cmd = EclObject([[max_to_poly_solve], self.ecl(), sr_to_max(vars)]) return self.parent()(maxima_eval(cmd)) @@ -1235,6 +1239,7 @@ def reduce_load_MaximaLib(): # Here we correct the dictionaries for some simple operators + def sage_rat(x, y): r""" Return quotient x/y. @@ -1332,15 +1337,11 @@ def mqapply_to_sage(expr): dilog(3) """ if caaadr(expr) == max_li: - return sage.functions.log.polylog(max_to_sr(cadadr(expr)), - max_to_sr(caddr(expr))) + return sage.functions.log.polylog(max_to_sr(cadadr(expr)), max_to_sr(caddr(expr))) if caaadr(expr) == max_psi: - return sage.functions.gamma.psi(max_to_sr(cadadr(expr)), - max_to_sr(caddr(expr))) + return sage.functions.gamma.psi(max_to_sr(cadadr(expr)), max_to_sr(caddr(expr))) if caaadr(expr) == max_hyper: - return sage.functions.hypergeometric.hypergeometric(mlist_to_sage(car(cdr(cdr(expr)))), - mlist_to_sage(car(cdr(cdr(cdr(expr))))), - max_to_sr(car(cdr(cdr(cdr(cdr(expr))))))) + return sage.functions.hypergeometric.hypergeometric(mlist_to_sage(car(cdr(cdr(expr)))), mlist_to_sage(car(cdr(cdr(cdr(expr))))), max_to_sr(car(cdr(cdr(cdr(cdr(expr))))))) op = max_to_sr(cadr(expr)) max_args = cddr(expr) args = [max_to_sr(a) for a in max_args] @@ -1456,10 +1457,8 @@ def dummy_integrate(expr): """ args = [max_to_sr(a) for a in cdr(expr)] if len(args) == 4: - return sage.symbolic.integration.integral.definite_integral(*args, - hold=True) - return sage.symbolic.integration.integral.indefinite_integral(*args, - hold=True) + return sage.symbolic.integration.integral.definite_integral(*args, hold=True) + return sage.symbolic.integration.integral.indefinite_integral(*args, hold=True) def max_harmonic_to_sage(expr): @@ -1473,8 +1472,7 @@ def max_harmonic_to_sage(expr): sage: max_to_sr(c.ecl()) harmonic_number(x, 2) """ - return sage.functions.log.harmonic_number(max_to_sr(caddr(expr)), - max_to_sr(cadr(expr))) + return sage.functions.log.harmonic_number(max_to_sr(caddr(expr)), max_to_sr(cadr(expr))) def max_pochhammer_to_sage(expr): @@ -1489,31 +1487,16 @@ def max_pochhammer_to_sage(expr): gamma(n + x)/gamma(x) """ from sage.functions.gamma import gamma + x = max_to_sr(cadr(expr)) y = max_to_sr(caddr(expr)) return gamma(x + y) / gamma(x) # The dictionaries -special_max_to_sage = { - mrat: mrat_to_sage, - mqapply: mqapply_to_sage, - mdiff: mdiff_to_sage, - EclObject("%INTEGRATE"): dummy_integrate, - max_at: max_at_to_sage, - mlist: mlist_to_sage, - max_harmo: max_harmonic_to_sage, - max_pochhammer: max_pochhammer_to_sage -} +special_max_to_sage = {mrat: mrat_to_sage, mqapply: mqapply_to_sage, mdiff: mdiff_to_sage, EclObject("%INTEGRATE"): dummy_integrate, max_at: max_at_to_sage, mlist: mlist_to_sage, max_harmo: max_harmonic_to_sage, max_pochhammer: max_pochhammer_to_sage} -special_sage_to_max = { - sage.functions.log.polylog: lambda N, X: [[mqapply], [[max_li, max_array], N], X], - sage.functions.gamma.psi1: lambda X: [[mqapply], [[max_psi, max_array], 0], X], - sage.functions.gamma.psi2: lambda N, X: [[mqapply], [[max_psi, max_array], N], X], - sage.functions.log.lambert_w: lambda N, X: [[max_lambert_w], X] if N == EclObject(0) else [[mqapply], [[max_lambert_w, max_array], N], X], - sage.functions.log.harmonic_number: lambda N, X: [[max_harmo], X, N], - sage.functions.hypergeometric.hypergeometric: lambda A, B, X: [[mqapply], [[max_hyper, max_array], lisp_length(A.cdr()), lisp_length(B.cdr())], A, B, X] -} +special_sage_to_max = {sage.functions.log.polylog: lambda N, X: [[mqapply], [[max_li, max_array], N], X], sage.functions.gamma.psi1: lambda X: [[mqapply], [[max_psi, max_array], 0], X], sage.functions.gamma.psi2: lambda N, X: [[mqapply], [[max_psi, max_array], N], X], sage.functions.log.lambert_w: lambda N, X: [[max_lambert_w], X] if N == EclObject(0) else [[mqapply], [[max_lambert_w, max_array], N], X], sage.functions.log.harmonic_number: lambda N, X: [[max_harmo], X, N], sage.functions.hypergeometric.hypergeometric: lambda A, B, X: [[mqapply], [[max_hyper, max_array], lisp_length(A.cdr()), lisp_length(B.cdr())], A, B, X]} # Dictionaries for symbols @@ -1560,6 +1543,7 @@ def pyobject_to_max(obj): from sage.rings.number_field.number_field_element_quadratic import ( NumberFieldElement_quadratic, ) + if isinstance(obj, NumberFieldElement_quadratic) and obj.parent().defining_polynomial().list() == [1, 0, 1]: re, im = obj.list() return EclObject([[mplus], pyobject_to_max(re), [[mtimes], pyobject_to_max(im), max_i]]) @@ -1611,8 +1595,7 @@ def sr_to_max(expr): # (we need to have access to op, not only to expr.operands() if isinstance(op, FDerivativeOperator): args = expr.operands() - if (not all(isinstance(v, Expression) and v.is_symbol() for v in args) - or len(args) != len(set(args))): + if not all(isinstance(v, Expression) and v.is_symbol() for v in args) or len(args) != len(set(args)): # An evaluated derivative of the form f'(1) is not a # symbolic variable, yet we would like to treat it # like one. So, we replace the argument `1` with a @@ -1637,11 +1620,10 @@ def sr_to_max(expr): l = [[mdiff], f] l.extend(deriv_max) return EclObject(l) - if (op in special_sage_to_max): + if op in special_sage_to_max: return EclObject(special_sage_to_max[op](*[sr_to_max(o) for o in expr.operands()])) if op is tuple: - return EclObject(([mlist], - [sr_to_max(op) for op in expr.operands()])) + return EclObject(([mlist], [sr_to_max(op) for op in expr.operands()])) if op not in sage_op_dict: # Maxima does some simplifications automatically by default # so calling maxima(expr) can change the structure of expr @@ -1654,8 +1636,7 @@ def sr_to_max(expr): raise RuntimeError("Encountered operator mismatch in sr-to-maxima translation") sage_op_dict[op] = op_max max_op_dict[op_max] = op - return EclObject(([sage_op_dict[op]], - [sr_to_max(o) for o in expr.operands()])) + return EclObject(([sage_op_dict[op]], [sr_to_max(o) for o in expr.operands()])) if expr.is_symbol() or expr._is_registered_constant_(): if expr not in sage_sym_dict: sym_max = maxima(expr).ecl() @@ -1706,7 +1687,7 @@ def max_to_sr(expr): return special_max_to_sage[op_max](expr) if op_max not in max_op_dict: op_max_str = maxprint(op_max).python()[1:-1] - if op_max_str in max_to_pynac_table: # nargs ? + if op_max_str in max_to_pynac_table: # nargs ? op = max_to_pynac_table[op_max_str] else: # This could be unsafe if the conversion to SR @@ -1733,12 +1714,13 @@ def max_to_sr(expr): return sage.rings.real_double.RealDoubleElement(e) return e -#interface routines for evaluating maxima's `equal` and `notequal` + +# interface routines for evaluating maxima's `equal` and `notequal` max_equal = EclObject("$EQUAL") max_notequal = EclObject("$NOTEQUAL") max_is = EclObject("$IS") -test_max_equal = lambda A,B: maxima_eval([[max_is],[[max_equal],sr_to_max(A),sr_to_max(B)]]).python() -test_max_notequal = lambda A,B: maxima_eval([[max_is],[[max_notequal],sr_to_max(A),sr_to_max(B)]]).python() -test_max_relation = lambda R: maxima_eval([[max_is],sr_to_max(R)]).python() +test_max_equal = lambda A, B: maxima_eval([[max_is], [[max_equal], sr_to_max(A), sr_to_max(B)]]).python() +test_max_notequal = lambda A, B: maxima_eval([[max_is], [[max_notequal], sr_to_max(A), sr_to_max(B)]]).python() +test_max_relation = lambda R: maxima_eval([[max_is], sr_to_max(R)]).python() diff --git a/src/sage/interfaces/mupad.py b/src/sage/interfaces/mupad.py index 0f718c28ddc..c065e749215 100644 --- a/src/sage/interfaces/mupad.py +++ b/src/sage/interfaces/mupad.py @@ -114,6 +114,7 @@ class Mupad(ExtraTabCompletion, Expect): """ Interface to the MuPAD interpreter. """ + def __init__(self, maxread=None, script_subdirectory=None, server=None, server_tmpdir=None, logfile=None): """ Create an instance of the MuPAD interpreter. @@ -123,17 +124,19 @@ def __init__(self, maxread=None, script_subdirectory=None, server=None, server_t sage: mupad == loads(dumps(mupad)) # optional - mupad True """ - Expect.__init__(self, - name='MuPAD', - prompt=PROMPT, - # the -U SAGE=TRUE allows for MuPAD programs to test whether they are run from Sage - command="mupkern -P e -U SAGE=TRUE", - script_subdirectory=script_subdirectory, - server=server, - server_tmpdir=server_tmpdir, - restart_on_ctrlc=False, - verbose_start=False, - logfile=None) + Expect.__init__( + self, + name='MuPAD', + prompt=PROMPT, + # the -U SAGE=TRUE allows for MuPAD programs to test whether they are run from Sage + command="mupkern -P e -U SAGE=TRUE", + script_subdirectory=script_subdirectory, + server=server, + server_tmpdir=server_tmpdir, + restart_on_ctrlc=False, + verbose_start=False, + logfile=None, + ) def _function_class(self): """ @@ -244,8 +247,7 @@ def eval(self, code, strip=True, **kwds): s = Expect.eval(self, code, **kwds) return AsciiArtString(s) - def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, - need_output=True, restart_if_needed=False): + def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, need_output=True, restart_if_needed=False): """ EXAMPLES:: @@ -268,8 +270,8 @@ def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, START = '__start__(%s+1)' % seq END = '__end__(%s+1)' % seq line = '%s; %s; %s;' % (START, line, END) - START = '__start__(%s)' % (seq+1) - END = '__end__(%s)' % (seq+1) + START = '__start__(%s)' % (seq + 1) + END = '__end__(%s)' % (seq + 1) E = self._expect E.sendline(line) @@ -278,11 +280,11 @@ def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, i = z.find(START) if i == -1: raise RuntimeError("%s\nError evaluating code in MuPAD" % z) - z = z[i+len(START)+2:] + z = z[i + len(START) + 2 :] z = z.rstrip().rstrip(END).rstrip('"').rstrip().strip('\n').strip('\r').strip('\n').replace('\\\r\n', '') i = z.find('Error: ') if i != -1: - raise RuntimeError(z[i + 7:]) + raise RuntimeError(z[i + 7 :]) return z def cputime(self, t=None): @@ -293,8 +295,8 @@ def cputime(self, t=None): 0.11600000000000001 """ if t is None: - return float(str(self('time()')))/1000 - return float(str(self('time() - %s' % float(t))))/1000 + return float(str(self('time()'))) / 1000 + return float(str(self('time() - %s' % float(t)))) / 1000 def set(self, var, value): """ @@ -310,7 +312,7 @@ def set(self, var, value): out = self.eval(cmd) i = out.find('Error: ') if i != -1: - raise RuntimeError(out[i + 7:]) + raise RuntimeError(out[i + 7 :]) def get(self, var): """ @@ -324,7 +326,7 @@ def get(self, var): """ s = self.eval('%s' % var) i = s.find('=') - return s[i+1:] + return s[i + 1 :] def _object_class(self): """ @@ -375,8 +377,7 @@ def _commands(self): True """ try: - v = sum([self.completions(chr(65+n)) for n in range(26)], []) + \ - sum([self.completions(chr(97+n)) for n in range(26)], []) + v = sum([self.completions(chr(65 + n)) for n in range(26)], []) + sum([self.completions(chr(97 + n)) for n in range(26)], []) except RuntimeError: print("\n" * 3) print("*" * 70) @@ -400,6 +401,7 @@ def _tab_completion(self, verbose=True, use_disk_cache=True): return self.__tab_completion except AttributeError: import sage.misc.persist + if use_disk_cache: try: self.__tab_completion = sage.misc.persist.load(COMMANDS_CACHE) @@ -456,7 +458,7 @@ def __getattr__(self, attrname): """ if attrname[:1] == "_": raise AttributeError - return MupadFunction(self._parent, self._name+"::"+attrname) + return MupadFunction(self._parent, self._name + "::" + attrname) def _tab_completion(self): """ @@ -468,7 +470,7 @@ def _tab_completion(self): ... 'wiedemann'] """ - res = self._parent.completions(self._name+"::", strip=True) + res = self._parent.completions(self._name + "::", strip=True) return res if res != [] else self._parent._tab_completion() @@ -504,7 +506,7 @@ def __getattr__(self, attrname): raise AttributeError else: return self.__dict__[attrname] - name = self._name+"::"+attrname + name = self._name + "::" + attrname if P.eval('type(%s)' % name) == "DOM_DOMAIN": return MupadElement(P, name) return MupadFunctionElement(self._obj, name) @@ -518,7 +520,7 @@ def _tab_completion(self): True """ P = self._obj.parent() - res = P.completions(self._name+"::", strip=True) + res = P.completions(self._name + "::", strip=True) return res if res != [] else P._tab_completion() def __call__(self, *args): @@ -586,7 +588,7 @@ def _tab_completion(self): sage: 'HallLittlewood' in S._tab_completion() # optional - mupad-Combinat True """ - res = self.parent().completions(self.name()+"::", strip=True) + res = self.parent().completions(self.name() + "::", strip=True) return res if res != [] else self.parent()._tab_completion() def _latex_(self): @@ -664,6 +666,7 @@ def mupad_console(): *----* Licensed to: ... """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%mupad magics instead.') os.system('mupkern') @@ -682,4 +685,5 @@ def __doctest_cleanup(): False """ import sage.interfaces.quit + sage.interfaces.quit.expect_quitall() diff --git a/src/sage/interfaces/mwrank.py b/src/sage/interfaces/mwrank.py index 48848dd8109..8acb21905f5 100644 --- a/src/sage/interfaces/mwrank.py +++ b/src/sage/interfaces/mwrank.py @@ -126,6 +126,7 @@ def validate_mwrank_input(s): """ if isinstance(s, (list, tuple)): from sage.rings.integer_ring import ZZ + if len(s) != 5: raise ValueError("%s is not valid input to mwrank (should have 5 entries)" % s) try: @@ -148,6 +149,7 @@ class Mwrank_class(Expect): """ Interface to the Mwrank interpreter. """ + def __init__(self, options='', server=None, server_tmpdir=None): """ INPUT: @@ -186,14 +188,7 @@ def __init__(self, options='', server=None, server_tmpdir=None): sage: from sage.interfaces.mwrank import Mwrank_class sage: TestSuite(Mwrank_class).run() """ - Expect.__init__(self, - name='mwrank', - prompt='Enter curve: ', - command="mwrank %s" % options, - server=server, - server_tmpdir=server_tmpdir, - restart_on_ctrlc=True, - verbose_start=False) + Expect.__init__(self, name='mwrank', prompt='Enter curve: ', command="mwrank %s" % options, server=server, server_tmpdir=server_tmpdir, restart_on_ctrlc=True, verbose_start=False) def __getattr__(self, attrname): """ @@ -360,6 +355,7 @@ def mwrank_console(): Program mwrank: ... """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%mwrank magics instead.') os.system('mwrank') diff --git a/src/sage/interfaces/octave.py b/src/sage/interfaces/octave.py index 35a8c6829c9..0646e19070b 100644 --- a/src/sage/interfaces/octave.py +++ b/src/sage/interfaces/octave.py @@ -183,8 +183,7 @@ class Octave(Expect): True """ - def __init__(self, maxread=None, script_subdirectory=None, logfile=None, - server=None, server_tmpdir=None, seed=None, command=None): + def __init__(self, maxread=None, script_subdirectory=None, logfile=None, server=None, server_tmpdir=None, seed=None, command=None): """ EXAMPLES:: @@ -198,20 +197,22 @@ def __init__(self, maxread=None, script_subdirectory=None, logfile=None, server = os.getenv('SAGE_OCTAVE_SERVER') or None # Use a temporary workspace file. workspace_file = tmp_filename() - Expect.__init__(self, - name='octave', - # We want the prompt sequence to be unique to avoid confusion with syntax error messages containing >>> - prompt=r'octave\:\d+> ', - # We don't want any pagination of output - command=command + f" --no-line-editing --silent --eval 'PS2(PS1());more off; octave_core_file_name (\"{workspace_file}\")' --persist", - maxread=maxread, - server=server, - server_tmpdir=server_tmpdir, - script_subdirectory=script_subdirectory, - restart_on_ctrlc=False, - verbose_start=False, - logfile=logfile, - eval_using_file_cutoff=100) + Expect.__init__( + self, + name='octave', + # We want the prompt sequence to be unique to avoid confusion with syntax error messages containing >>> + prompt=r'octave\:\d+> ', + # We don't want any pagination of output + command=command + f" --no-line-editing --silent --eval 'PS2(PS1());more off; octave_core_file_name (\"{workspace_file}\")' --persist", + maxread=maxread, + server=server, + server_tmpdir=server_tmpdir, + script_subdirectory=script_subdirectory, + restart_on_ctrlc=False, + verbose_start=False, + logfile=logfile, + eval_using_file_cutoff=100, + ) self._seed = seed def set_seed(self, seed=None): @@ -285,8 +286,7 @@ def _install_hints(self): * Darwin ports and fink have Octave as well. """ - def _eval_line(self, line, reformat=True, allow_use_file=False, - wait_for_prompt=True, restart_if_needed=False): + def _eval_line(self, line, reformat=True, allow_use_file=False, wait_for_prompt=True, restart_if_needed=False): """ EXAMPLES:: @@ -294,6 +294,7 @@ def _eval_line(self, line, reformat=True, allow_use_file=False, ans = 4 """ from pexpect.exceptions import EOF + if not wait_for_prompt: return Expect._eval_line(self, line) if line == '': @@ -431,7 +432,7 @@ def get(self, var): """ s = self.eval('%s' % var) i = s.find('=') - return s[i+1:] + return s[i + 1 :] def clear(self, var): """ @@ -516,6 +517,7 @@ def solve_linear_system(self, A, b): raise ValueError("dimensions of A and b must be compatible") from sage.matrix.matrix_space import MatrixSpace from sage.rings.rational_field import QQ + MS = MatrixSpace(QQ, m, 1) b = MS(list(b)) # converted b to a "column vector" sA = self.sage2octave_matrix_string(A) @@ -637,12 +639,15 @@ def _get_sage_ring(self): """ if self.isinteger(): import sage.rings.integer_ring + return sage.rings.integer_ring.ZZ if self.isreal(): import sage.rings.real_double + return sage.rings.real_double.RDF if self.iscomplex(): import sage.rings.complex_double + return sage.rings.complex_double.CDF raise TypeError("no Sage ring associated to this element.") @@ -715,6 +720,7 @@ def _matrix_(self, R=None): w = [[to_complex(x, R) for x in row] for row in w] from sage.matrix.matrix_space import MatrixSpace + return MatrixSpace(R, nrows, ncols)(w) def _vector_(self, R=None): @@ -735,6 +741,7 @@ def _vector_(self, R=None): (1.0, 1.0*I) """ from sage.modules.free_module import FreeModule + if not self.isvector(): raise TypeError('not an octave vector') if R is None: @@ -853,6 +860,7 @@ def octave_console(): another. """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%octave magics instead.') os.system('octave-cli') diff --git a/src/sage/interfaces/phc.py b/src/sage/interfaces/phc.py index 9111b4f0ed6..c92028049ca 100644 --- a/src/sage/interfaces/phc.py +++ b/src/sage/interfaces/phc.py @@ -40,6 +40,7 @@ from sage.rings.cc import CC from sage.rings.integer import Integer from sage.misc.lazy_import import lazy_import + lazy_import("sage.plot.line", "line") lazy_import("sage.plot.point", "point") @@ -87,8 +88,7 @@ def get_solution_dicts(output_file_contents, input_ring, get_failures=True): for extras in range(rawsplit.count('')): rawsplit.remove('') temp_var = output_list[i + j].split(': ')[0].replace(' ', '') - temp_dict[input_ring(temp_var)] = CC(rawsplit[0], - rawsplit[1]) + temp_dict[input_ring(temp_var)] = CC(rawsplit[0], rawsplit[1]) solution_dicts.append(temp_dict) return solution_dicts @@ -144,8 +144,7 @@ def get_classified_solution_dicts(output_file_contents, input_ring, get_failures if phc_type == 'real': temp_dict[input_ring(temp_var)] = RR(rawsplit[0]) else: - temp_dict[input_ring(temp_var)] = CC(rawsplit[0], - rawsplit[1]) + temp_dict[input_ring(temp_var)] = CC(rawsplit[0], rawsplit[1]) solution_dicts[phc_type].append(temp_dict) return solution_dicts @@ -493,7 +492,7 @@ def _input_file(self, polys): raise TypeError('polys must be a list or tuple') s = '%s\n' % len(polys) for f in polys: - s += f._repr_() + ';\n' # note the semicolon *terminators* + s += f._repr_() + ';\n' # note the semicolon *terminators* return s def _parse_path_file(self, input_filename, verbose=False): @@ -574,8 +573,7 @@ def _parse_path_file(self, input_filename, verbose=False): # m.group(2) contains our var name # m.group(4) contains our real val # m.group(5) contains our imaginary val - temp_dict[m.group(2)] = CC(m.group(4), - m.group(5)) + temp_dict[m.group(2)] = CC(m.group(4), m.group(5)) steps_dicts.append(temp_dict) # check if its the end of a solution if end_test.find('Length of path') != -1: @@ -623,7 +621,7 @@ def _path_track_file(self, start_filename_or_string, polys, input_ring, c_skew=0 return self._output_from_command_list(['phc', '0', '0', 'A', start_filename, 'y', '1', '0', 'n', 'k', '2', 'a', '1', str(c_skew), '0', '0', '2'], polys, verbose=verbose) - def path_track(self, start_sys, end_sys, input_ring, c_skew=.001, saved_start=None): + def path_track(self, start_sys, end_sys, input_ring, c_skew=0.001, saved_start=None): """ This function computes homotopy paths between the solutions of ``start_sys`` and ``end_sys``. @@ -663,7 +661,7 @@ def path_track(self, start_sys, end_sys, input_ring, c_skew=.001, saved_start=No os.unlink(path_track_filename) return sol_paths - def plot_paths_2d(self, start_sys, end_sys, input_ring, c_skew=.001, endpoints=True, saved_start=None, rand_colors=False): + def plot_paths_2d(self, start_sys, end_sys, input_ring, c_skew=0.001, endpoints=True, saved_start=None, rand_colors=False): """ Return a graphics object of solution paths in the complex plane. @@ -917,6 +915,7 @@ def blackbox(self, polys, input_ring, verbose=False): # Was there an error? if e: from sage.features import Executable + phc_executable = Executable(name='phc', executable='phc') phc_executable.require() # todo -- why? etc. diff --git a/src/sage/interfaces/polymake.py b/src/sage/interfaces/polymake.py index b193bd3acdf..2bfda104a88 100644 --- a/src/sage/interfaces/polymake.py +++ b/src/sage/interfaces/polymake.py @@ -9,7 +9,6 @@ [GHJ2016]_, and [AGHJLPR2017]_. """ - # **************************************************************************** # Copyright (C) 2017 Simon King # @@ -40,17 +39,7 @@ _name_pattern = re.compile('SAGE[0-9]+') -_available_polymake_answers = { - 0: "returns prompt", - 1: "returns continuation prompt", - 2: "requests interactive input", - 3: "kills computation", - 4: "raises error", - 5: "issues warning", - 6: "shows additional information", - 7: "lost connection", - 8: "fails to respond timely" - } +_available_polymake_answers = {0: "returns prompt", 1: "returns continuation prompt", 2: "requests interactive input", 3: "kills computation", 4: "raises error", 5: "issues warning", 6: "shows additional information", 7: "lost connection", 8: "fails to respond timely"} class PolymakeError(RuntimeError): @@ -64,6 +53,7 @@ class PolymakeError(RuntimeError): ... PolymakeError: Unquoted string "foo" may clash with future reserved word... """ + pass @@ -91,6 +81,7 @@ def polymake_console(command=''): polytope > """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%polymake magics instead.') os.system(command or os.getenv('SAGE_POLYMAKE_COMMAND') or 'polymake') @@ -127,6 +118,7 @@ class PolymakeAbstract(ExtraTabCompletion, Interface): sage: p.F_VECTOR # optional - jupymake 20 94 148 74 """ + def __init__(self, seed=None): """ TESTS:: @@ -223,9 +215,7 @@ def function_call(self, function, args=None, kwds=None): """ args, kwds = self._convert_args_kwds(args, kwds) self._check_valid_function_name(function) - s = self._function_call_string(function, - [s.name() for s in args], - ['{}=>{}'.format(key, value.name()) for key, value in kwds.items()]) + s = self._function_call_string(function, [s.name() for s in args], ['{}=>{}'.format(key, value.name()) for key, value in kwds.items()]) return self(s) def _function_call_string(self, function, args, kwds): @@ -506,8 +496,8 @@ def _create(self, value, name=None): # the name returned by _create so that it can be used to # access the wrapped value. if self.eval('print scalar @{};'.format(name)).strip() == '1': - return '$'+name+'[0]' - return '@'+name + return '$' + name + '[0]' + return '@' + name def set(self, var, value): """ @@ -658,6 +648,7 @@ def help(self, topic, pager=True): raise PolymakeError("unknown help topic '{}'".format(topic)) if pager: from IPython.core.page import page + page(H, start=0) else: return H @@ -705,9 +696,7 @@ def _tab_completion(self): s = self.eval("apropos '';").split('\n') out = [] for name in s: - if (name.startswith("/common/functions/") - or name.startswith("/core/functions") - or name.startswith("/" + self._application + "/functions/")): + if name.startswith("/common/functions/") or name.startswith("/core/functions") or name.startswith("/" + self._application + "/functions/"): out.append(name.split("/")[-1]) self.__tab_completion[self._application] = sorted(out) return self.__tab_completion[self._application] @@ -845,6 +834,7 @@ def new_object(self, name, *args, **kwds): # Elements # -------- + class PolymakeElement(ExtraTabCompletion, InterfaceElement): """ Elements in the polymake interface. @@ -865,6 +855,7 @@ class PolymakeElement(ExtraTabCompletion, InterfaceElement): sage: p.VERTICES[2][2] # optional - jupymake 1450479926727001/2251799813685248 """ + def _repr_(self): """ String representation of polymake elements. @@ -1186,7 +1177,7 @@ def _tab_completion(self): 'zonotope_tiling_lattice', 'zonotope_vertices_fukuda'] """ - return sorted(self._member_list()+self.parent()._tab_completion()) + return sorted(self._member_list() + self.parent()._tab_completion()) def __getattr__(self, attrname): """ @@ -1441,7 +1432,7 @@ def typeof(self): P = self._check_valid() name = self._name T1, T2 = P.eval('print ref({});'.format(name)), P.eval('print reftype({});'.format(name)) - if T1 == 'false': # Polymake 3.4 returns this + if T1 == 'false': # Polymake 3.4 returns this T1 = '' return T1, T2 @@ -1509,13 +1500,15 @@ def _sage_(self): r = self._repr_() if 'Float' in T1: from sage.rings.real_double import RDF + base_ring = RDF str_to_base_ring = RDF elif 'QuadraticExtension' in T1 and 'r' in r: i = r.find('r') - i1 = min((r[i:]+' ').find(' '), (r[i:]+'\n').find('\n')) - d = int(r[i+1:i+i1]) + i1 = min((r[i:] + ' ').find(' '), (r[i:] + '\n').find('\n')) + d = int(r[i + 1 : i + i1]) from sage.rings.number_field.number_field import QuadraticField + base_ring = QuadraticField(d) def str_to_base_ring(s): @@ -1525,6 +1518,7 @@ def str_to_base_ring(s): elif 'Rational' in T1: from sage.rings.rational_field import QQ + base_ring = QQ str_to_base_ring = QQ else: @@ -1532,11 +1526,13 @@ def str_to_base_ring(s): if 'Vector' in T1: from sage.modules.free_module_element import vector + if r == '': return vector(base_ring) return vector(base_ring, [str_to_base_ring(s) for s in r.split(' ')]) if 'Matrix' in T1: from sage.matrix.constructor import matrix + if r == '': return matrix(base_ring) return matrix(base_ring, [[str_to_base_ring(s) for s in t.split(' ')] for t in r.split('\n')]) @@ -1554,20 +1550,25 @@ def str_to_base_ring(s): raise NotImplementedError("Cannot parse QuadraticExtension element: {}".format(self)) a, b, r = m.group(1), m.group(3), m.group(4) from sage.rings.rational_field import QQ + if r is None: # Prints like a rational, so we can't know the extension. Coerce to rational. return QQ(a) from sage.rings.number_field.number_field import QuadraticField + K = QuadraticField(r) return QQ(a) + QQ(b) * K.gen() if T1 == 'Vector' or T1 == 'SparseVector': from sage.modules.free_module_element import vector + return vector([x.sage() for x in self]) if T1 == 'Matrix' or T1 == 'SparseMatrix': from sage.matrix.constructor import matrix + return matrix([x.sage() for x in self]) if T1 == 'Polytope': from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake + return Polyhedron_polymake._from_polymake_polytope(None, self) return super()._sage_() @@ -1624,7 +1625,7 @@ def _sage_doc_(self): doc2 = '' if doc: if doc2: - doc = doc+os.linesep+doc2 + doc = doc + os.linesep + doc2 else: doc = doc2 try: @@ -1633,7 +1634,7 @@ def _sage_doc_(self): doc3 = '' if doc: if doc3: - doc = doc+os.linesep+doc3 + doc = doc + os.linesep + doc3 else: doc = doc3 if doc: @@ -1657,6 +1658,7 @@ class PolymakeFunctionElement(InterfaceFunctionElement): sage: c.contains(V) true """ + def __init__(self, obj, name, memberfunction=False): """ INPUT: @@ -1851,7 +1853,7 @@ def __init__(self, seed=None, verbose=False): self._verbose = verbose PolymakeAbstract.__init__(self, seed=seed) - _is_running = False # class variable + _is_running = False # class variable def is_running(self): """ @@ -1888,12 +1890,13 @@ def _start(self): True """ from JuPyMake import InitializePolymake + if not self.is_running(): - InitializePolymake() # Can only be called once + InitializePolymake() # Can only be called once PolymakeJuPyMake._is_running = True PolymakeAbstract._start(self) self.eval("sub Polymake::Core::Shell::Mock::fill_history {}") - self._tab_completion() # Run it here already because it causes a segfault when invoked in actual tab completion situation?! + self._tab_completion() # Run it here already because it causes a segfault when invoked in actual tab completion situation?! def eval(self, code, **kwds): r""" @@ -1994,6 +1997,7 @@ def eval(self, code, **kwds): if not self.is_running(): self._start() from JuPyMake import ExecuteCommand + if self._verbose: print("## eval: {}".format(code)) parsed, stdout, stderr, error = ExecuteCommand(code) diff --git a/src/sage/interfaces/povray.py b/src/sage/interfaces/povray.py index 6e7a6c8ef94..c80fddc79f3 100644 --- a/src/sage/interfaces/povray.py +++ b/src/sage/interfaces/povray.py @@ -26,6 +26,7 @@ class POVRay: POVRay: http://www.povray.org """ + def __repr__(self): return 'POV-Ray The Persistence of Vision Ray Tracer' diff --git a/src/sage/interfaces/psage.py b/src/sage/interfaces/psage.py index e3d16fcf661..a7fa0678d76 100644 --- a/src/sage/interfaces/psage.py +++ b/src/sage/interfaces/psage.py @@ -56,6 +56,7 @@ def __init__(self, **kwds): raise NotImplementedError("PSage doesn't work on remote server yet.") Sage.__init__(self, **kwds) import sage.misc.misc + T = sage.misc.temporary_file.tmp_dir('sage_smp') self.__tmp_dir = T self.__tmp = '%s/lock' % T diff --git a/src/sage/interfaces/qepcad.py b/src/sage/interfaces/qepcad.py index 22ef7179d66..0d84d5076a6 100644 --- a/src/sage/interfaces/qepcad.py +++ b/src/sage/interfaces/qepcad.py @@ -595,6 +595,7 @@ - Thierry Monteil (2015-07) repackaging + noncommutative doctests. """ + # **************************************************************************** # Copyright (C) 2008 Carl Witty # @@ -714,11 +715,9 @@ def _update_command_info(): special = None # These commands have been tweaked. - if cmd in ['d-all-cells-in-subtree', 'd-cell', 'd-pcad', - 'd-pscad', 'd-stack', 'manual-choose-cell']: + if cmd in ['d-all-cells-in-subtree', 'd-cell', 'd-pcad', 'd-pscad', 'd-stack', 'manual-choose-cell']: special = 'cell' - if cmd in ['ipfzt', 'rational-sample', 'triv-convert', 'use-db', - 'use-selected-cells-cond', 'verbose']: + if cmd in ['ipfzt', 'rational-sample', 'triv-convert', 'use-db', 'use-selected-cells-cond', 'verbose']: special = 'yn' # The tweaking for these commands has not been implemented yet. @@ -737,6 +736,7 @@ def _update_command_info(): _command_info_cache = cache + # QEPCAD does not have a typical "computer algebra system" interaction # model. Instead, you run QEPCAD once for each problem you wish to solve, # then interact with it while you solve that problem. @@ -752,10 +752,8 @@ class Qepcad_expect(ExtraTabCompletion, Expect): r""" The low-level wrapper for QEPCAD. """ - def __init__(self, memcells=None, - maxread=None, - logfile=None, - server=None): + + def __init__(self, memcells=None, maxread=None, logfile=None, server=None): r""" Initialize a low-level wrapper for QEPCAD. @@ -771,16 +769,18 @@ def __init__(self, memcells=None, sage: Qepcad_expect(memcells=100000, logfile=sys.stdout) Qepcad """ - Expect.__init__(self, - name='QEPCAD', - # yuck: when QEPCAD first starts, - # it doesn't give prompts - prompt="\nEnter an .*:\r", - command=_qepcad_cmd(memcells), - server=server, - restart_on_ctrlc=False, - verbose_start=False, - logfile=logfile) + Expect.__init__( + self, + name='QEPCAD', + # yuck: when QEPCAD first starts, + # it doesn't give prompts + prompt="\nEnter an .*:\r", + command=_qepcad_cmd(memcells), + server=server, + restart_on_ctrlc=False, + verbose_start=False, + logfile=logfile, + ) class Qepcad: @@ -788,9 +788,7 @@ class Qepcad: The wrapper for QEPCAD. """ - def __init__(self, formula, - vars=None, logfile=None, verbose=False, - memcells=None, server=None): + def __init__(self, formula, vars=None, logfile=None, verbose=False, memcells=None, server=None): r""" Construct a QEPCAD wrapper object. @@ -863,7 +861,7 @@ def __init__(self, formula, # and ensure they match up with the variables in the formula. if frozenset(varlist) != (fvars | frozenset(fqvars)): raise ValueError("specified vars don't match vars in formula") - if len(fqvars) and varlist[-len(fqvars):] != fqvars: + if len(fqvars) and varlist[-len(fqvars) :] != fqvars: raise ValueError("specified vars don't match quantified vars") free_vars = len(fvars) formula = repr(formula) @@ -927,9 +925,8 @@ def assume(self, assume): assume = qepcad_formula.formula(assume) if len(assume.qvars): raise ValueError("assumptions cannot be quantified") - if not assume.vars.issubset(frozenset(self._varlist[:self._free_vars])): - raise ValueError("assumption contains variables not " - "present in formula") + if not assume.vars.issubset(frozenset(self._varlist[: self._free_vars])): + raise ValueError("assumption contains variables not " "present in formula") assume = repr(assume) assume = assume.replace('_', '') result = self._eval_line("assume [%s]" % assume) @@ -1011,13 +1008,12 @@ def solution_extension(self, kind): {'y + x > 0', 'y^2 + x^2 - 3 = 0'} """ if kind == 'I': - raise ValueError("Interactive solution construction not " - "handled by Sage interface") + raise ValueError("Interactive solution construction not " "handled by Sage interface") result = self._eval_line('solution-extension %s' % kind) tagline = 'An equivalent quantifier-free formula:' loc = result.find(tagline) if loc >= 0: - result = result[loc + len(tagline):] + result = result[loc + len(tagline) :] result = result.strip() if len(result): return AsciiArtString(result) @@ -1295,7 +1291,7 @@ def _eval_line(self, cmd, restart_if_needed=False): amp = result.find('&', 0, nl) if amp > 0: - result = result[amp+1:] + result = result[amp + 1 :] result = result.strip() @@ -1373,6 +1369,7 @@ class QepcadFunction(ExpectFunction): r""" A wrapper for a QEPCAD command. """ + def _instancedoc_(self): r""" Return the documentation for a QEPCAD command, from @@ -1418,14 +1415,12 @@ def __call__(self, *args): args[0] = 'y' if args[0] else 'n' if special == 'interactive': - raise ValueError("Cannot call %s through Sage interface... " - "interactive commands not handled") + raise ValueError("Cannot call %s through Sage interface... " "interactive commands not handled") return self._parent._function_call(self._name, args) -def qepcad(formula, assume=None, interact=False, solution=None, - vars=None, **kwargs): +def qepcad(formula, assume=None, interact=False, solution=None, vars=None, **kwargs): r""" Quantifier elimination and formula simplification using QEPCAD B. @@ -1671,8 +1666,7 @@ def qepcad(formula, assume=None, interact=False, solution=None, qe.quit() for c in cells: if c._dimension > 0: - raise ValueError("input formula is true for " - "infinitely many points") + raise ValueError("input formula is true for " "infinitely many points") return [c.sample_point_dict() for c in cells] raise ValueError(f"Unknown solution type ({solution})") @@ -1688,6 +1682,7 @@ def qepcad_console(memcells=None): Enter an informal description between '[' and ']': """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%qepcad magics instead.') # This will only spawn local processes @@ -1750,6 +1745,7 @@ class qformula: A qformula holds a string describing a formula in QEPCAD's syntax, and a set of variables used. """ + def __init__(self, formula, vars, qvars=[]): r""" Construct a qformula from a string, a frozenset of variable names, @@ -1807,6 +1803,7 @@ def _normalize_op(self, op): '=' """ import operator + if op == operator.eq: return '=' if op == operator.ne: @@ -1885,8 +1882,7 @@ def _combine_formulas(self, formulas): for f in formulas: vars = vars | f.vars if len(f.qvars): - raise ValueError("QEPCAD formulas must be in prenex" - " (quantifiers outermost) form") + raise ValueError("QEPCAD formulas must be in prenex" " (quantifiers outermost) form") return formula_strs, vars def atomic(self, lhs, op='=', rhs=0): @@ -1927,6 +1923,7 @@ def atomic(self, lhs, op='=', rhs=0): return lhs from sage.structure.element import Expression + if isinstance(lhs, Expression) and lhs.is_relational(): lhs, op, rhs = lhs.lhs(), lhs.operator(), lhs.rhs() @@ -2117,6 +2114,7 @@ def exists(self, v, formula): (E b)[b^2 = a] """ return self.quantifier('E', v, formula) + E = exists def forall(self, v, formula): @@ -2144,6 +2142,7 @@ def forall(self, v, formula): (A b)[b^2 /= a] """ return self.quantifier('A', v, formula) + A = forall def infinitely_many(self, v, formula): @@ -2170,6 +2169,7 @@ def infinitely_many(self, v, formula): (F b)[b^2 /= a] """ return self.quantifier('F', v, formula, allow_multi=False) + F = infinitely_many def all_but_finitely_many(self, v, formula): @@ -2196,6 +2196,7 @@ def all_but_finitely_many(self, v, formula): (G b)[b^2 /= a] """ return self.quantifier('G', v, formula, allow_multi=False) + G = all_but_finitely_many def connected_subset(self, v, formula, allow_multi=False): @@ -2223,6 +2224,7 @@ def connected_subset(self, v, formula, allow_multi=False): (C b)[b^2 /= a] """ return self.quantifier('C', v, formula) + C = connected_subset def exactly_k(self, k, v, formula, allow_multi=False): @@ -2253,6 +2255,7 @@ def exactly_k(self, k, v, formula, allow_multi=False): (A b)[~a b = 1] """ from sage.rings.integer_ring import ZZ + k = ZZ(k) if k < 0: raise ValueError("negative k in exactly_k quantifier") @@ -2261,6 +2264,7 @@ def exactly_k(self, k, v, formula, allow_multi=False): return self.forall(v, self.not_(formula)) return self.quantifier('X%s' % k, v, formula) + X = exactly_k def quantifier(self, kind, v, formula, allow_multi=True): @@ -2288,25 +2292,21 @@ def quantifier(self, kind, v, formula, allow_multi=True): if allow_multi and isinstance(v, (list, tuple)): if not v: return formula - return self.quantifier(kind, v[0], - self.quantifier(kind, v[1:], formula)) + return self.quantifier(kind, v[0], self.quantifier(kind, v[1:], formula)) form_str = str(formula) if form_str[-1] != ']': form_str = '[' + form_str + ']' v = str(v) if v not in formula.vars: - raise ValueError("Attempting to quantify variable which " - "does not occur in formula") + raise ValueError("Attempting to quantify variable which " "does not occur in formula") form_str = f"({kind} {v}){form_str}" - return qformula(form_str, formula.vars - frozenset([v]), - [v] + formula.qvars) + return qformula(form_str, formula.vars - frozenset([v]), [v] + formula.qvars) qepcad_formula = qepcad_formula_factory() -_qepcad_algebraic_re = \ - re.compile(' ?the unique root of (.*) between (.*) and (.*)$') +_qepcad_algebraic_re = re.compile(' ?the unique root of (.*) between (.*) and (.*)$') def _eval_qepcad_algebraic(text): @@ -2355,6 +2355,7 @@ class QepcadCell: r""" A wrapper for a QEPCAD cell. """ + def __init__(self, parent, lines): r""" Construct a :class:`QepcadCell` wrapper for a QEPCAD cell, given @@ -2567,7 +2568,7 @@ def __repr__(self): ind = '(%s)' % ind[0] else: ind = str(ind) - return ('QEPCAD cell %s' % ind) + return 'QEPCAD cell %s' % ind def index(self): r""" diff --git a/src/sage/interfaces/quit.py b/src/sage/interfaces/quit.py index b8f483efef9..7f03e2194e1 100644 --- a/src/sage/interfaces/quit.py +++ b/src/sage/interfaces/quit.py @@ -36,6 +36,7 @@ def sage_spawned_process_file() -> str: True """ from sage.misc.temporary_file import tmp_dir + return os.path.join(tmp_dir(), "spawned_processes") diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py index e723214ae9d..26fde835e28 100644 --- a/src/sage/interfaces/r.py +++ b/src/sage/interfaces/r.py @@ -287,8 +287,7 @@ lazy_import("rpy2", "robjects", feature=rpy2_feature) lazy_import("rpy2.robjects", "packages", "rpy2_packages", feature=rpy2_feature) -lazy_import("rpy2.robjects.conversion", ["localconverter", "Converter"], - feature=rpy2_feature) +lazy_import("rpy2.robjects.conversion", ["localconverter", "Converter"], feature=rpy2_feature) # for help page fetching lazy_import("rpy2.robjects.help", "Package", feature=rpy2_feature) @@ -400,6 +399,7 @@ def float_to_int_if_possible(f): # Preserve the behaviour of the old r parser, e.g. return 1 instead of 1.0 float_or_int = int(f) if isinstance(f, int) or f.is_integer() else f return float_or_int + rpy2py.register(float, float_to_int_if_possible) def list_to_singleton_if_possible(l): @@ -424,12 +424,14 @@ def _vector(vec): } # if no names are present, convert to a normal list or a single value return data + rpy2py.register(SexpVector, _vector) def _matrix(mat): if 'dim' in mat.list_attrs(): try: from sage.matrix.constructor import matrix + dimensions = mat.do_slot("dim") if len(dimensions) != 2: raise NotImplementedError("Higher-dimension matrices are currently not supported") @@ -442,6 +444,7 @@ def _matrix(mat): pass else: return _vector(mat) + rpy2py.register(FloatSexpVector, _matrix) def _list_vector(vec): @@ -457,17 +460,14 @@ def _list_vector(vec): # We don't give the rclass here because the old expect interface # didn't do that either and we want to maintain compatibility. } + rpy2py.register(ListSexpVector, _list_vector) return cv class R(ExtraTabCompletion, Interface): - def __init__(self, - maxread=None, - logfile=None, - init_list_length=1024, - seed=None): + def __init__(self, maxread=None, logfile=None, init_list_length=1024, seed=None): """ An interface to the R interpreter. @@ -554,9 +554,12 @@ def _lazy_init(self): # exist in Python 3.13+ (object has no __del__). # https://github.com/rpy2/rpy2/pull/1234 import rpy2.robjects.help + if not hasattr(object, '__del__'): + def _Package__del__(self): self._dbcon.close() + rpy2.robjects.help.Package.__del__ = _Package__del__ self._r_to_sage_converter = _setup_r_to_sage_converter() self._start() @@ -973,6 +976,7 @@ def _equality_symbol(self): def _loaded_package_pages(self, topic): # for some reason `except` doesn't work with lazy import, so import this here from rpy2.robjects.help import HelpNotFoundError + self._lazy_init() res = list() @@ -1086,8 +1090,7 @@ def function_call(self, function, args=None, kwds=None): """ args, kwds = self._convert_args_kwds(args, kwds) self._check_valid_function_name(function) - return self.new("%s(%s)" % (function, ",".join([s.name() for s in args] + - [self._sage_to_r_name(key) + '=' + kwds[key].name() for key in kwds]))) + return self.new("%s(%s)" % (function, ",".join([s.name() for s in args] + [self._sage_to_r_name(key) + '=' + kwds[key].name() for key in kwds]))) def call(self, function_name, *args, **kwds): r""" @@ -1181,7 +1184,7 @@ def completions(self, s): sage: 'testInheritedMethods' in r.completions('tes') True """ - return [name for name in self._tab_completion() if name[:len(s)] == s] + return [name for name in self._tab_completion() if name[: len(s)] == s] def _commands(self): """ @@ -1250,6 +1253,7 @@ def _tab_completion(self, verbose=True, use_disk_cache=True): return self.__tab_completion except AttributeError: import sage.misc.persist + if use_disk_cache: try: self.__tab_completion = sage.misc.persist.load(COMMANDS_CACHE) @@ -1376,6 +1380,7 @@ def _r_to_sage_name(self, s): 'class_' """ from keyword import iskeyword + s = s.replace('.', '_') s = s.replace('<-', '__') if iskeyword(s): @@ -1840,6 +1845,7 @@ def _latex_(self): 2 """ from sage.misc.latex import LatexExpr + self._check_valid() P = self.parent() # latex is in Hmisc, this is currently not part of Sage's R!!! @@ -1950,8 +1956,7 @@ def __eq__(self, other): sage: r.mean == r.lr False """ - return (isinstance(other, RFunction) and - self._name == other._name) + return isinstance(other, RFunction) and self._name == other._name def __ne__(self, other): """ @@ -2040,6 +2045,7 @@ def r_console(): ... """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%r magics instead.') # This will only spawn local processes @@ -2067,6 +2073,7 @@ class HelpExpression(str): """ Used to improve printing of output of r.help. """ + def __repr__(self): r""" Return string representation of ``self``. diff --git a/src/sage/interfaces/read_data.py b/src/sage/interfaces/read_data.py index 325c8ce5cb1..5127c00f8ea 100644 --- a/src/sage/interfaces/read_data.py +++ b/src/sage/interfaces/read_data.py @@ -1,6 +1,7 @@ """ An interface to read data files """ + ############################################################################### # Sage: Open Source Mathematical Software # Copyright (C) 2010 Paul Zimmermann diff --git a/src/sage/interfaces/regina.py b/src/sage/interfaces/regina.py index 16fe715b88d..691eaec9d7c 100644 --- a/src/sage/interfaces/regina.py +++ b/src/sage/interfaces/regina.py @@ -167,6 +167,7 @@ class AlgorithmExt(Enum): This extends the ``Algorithm`` class of Regina. """ + ALG_SIMPLIFY = 4 ALG_WIRTINGER = 5 ALG_USE_EXTERIOR = 6 @@ -186,6 +187,7 @@ class Regina(ExtraTabCompletion, Interface): More examples can be found in the module header. """ + def __init__(self): r""" Python constructor. @@ -250,8 +252,10 @@ def _start(self): """ if not self._regina_globals: from sage.features.interfaces import Regina + Regina().module.require() import regina + self._namespace = regina.engine d = self._namespace.__dict__ # add extras to the fixed namespace @@ -423,6 +427,7 @@ def _convert_args_kwds(self, *args, **kwds): {'C': , 'D': (3, 7)}) """ + def convert_arg(arg): if isinstance(arg, InterfaceElement) and arg.parent() is self: return arg._inst @@ -472,6 +477,7 @@ def _function_call(self, name, *args, **kwds): def read_back(arg): if isinstance(arg, self._object_class()): self.set(arg._name, arg._inst) + for arg in args: read_back(arg) for val in kwds.values(): @@ -767,6 +773,7 @@ def _richcmp_(self, other, op): True """ from sage.structure.richcmp import rich_to_bool, op_EQ, op_NE + if self._inst == other._inst: return rich_to_bool(op, 0) if op == op_EQ: @@ -825,6 +832,7 @@ def _operation(self, operation, other=None): def is_native(inst): return type(inst) in (int, float, complex) + if operation in ('+', '*'): if is_native(sinst) and is_native(oinst): if operation == '*': @@ -850,9 +858,9 @@ def is_native(inst): return self * self if exp > 0: for i in range(exp): - return self**(exp - 1) * self + return self ** (exp - 1) * self else: - return (~self)**(-exp) + return (~self) ** (-exp) if operation == '1/': if is_native(sinst): return P(1 / sinst) @@ -907,6 +915,7 @@ def _sage_(self, locals={}): sage: fr.sage() == f True """ + def from_detail_str(lc): r""" Regina provides a detail method for many of its classes. @@ -916,6 +925,7 @@ def from_detail_str(lc): lc.update(locals) from sage.misc.sage_eval import sage_eval from sage.repl.preparse import implicit_mul + s = self.detail().split('\n')[0] s = s.replace(' ', '') v = list(lc) @@ -939,11 +949,13 @@ def from_detail_str(lc): elif isinstance(inst, nspc.Polynomial): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.integer_ring import ZZ + R = PolynomialRing(ZZ, 'x') lc = R.gens_dict() else: from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.integer_ring import ZZ + if isinstance(inst, nspc.Laurent): R = LaurentPolynomialRing(ZZ, 'x') else: @@ -956,12 +968,14 @@ def from_detail_str(lc): F = self._sage_parent else: from sage.groups.free_group import FreeGroup + F = FreeGroup(num_gens) gens = F.gens() lc = {'g%s' % i: gens[i] for i in range(num_gens)} return from_detail_str(lc) if isinstance(inst, nspc.Link): from sage.knots.link import Link + return Link(inst.pdData()) if hasattr(self, 'detail'): return from_detail_str(locals) @@ -969,6 +983,7 @@ def from_detail_str(lc): # if locals are given we use `_sage_repr` # surely this only covers simple cases from sage.misc.sage_eval import sage_eval + return sage_eval(self._sage_repr(), locals=locals) return inst @@ -986,6 +1001,7 @@ class ReginaFunctionElement(InterfaceFunctionElement): sage: type(A.addRank) """ + def __call__(self, *args, **kwds): r""" Call this function with the given args and kwds. @@ -1020,6 +1036,7 @@ class ReginaFunction(InterfaceFunction): sage: type(m) """ + def __call__(self, *args, **kwds): r""" Call this function with the given args and kwds. diff --git a/src/sage/interfaces/rubik.py b/src/sage/interfaces/rubik.py index 4d1f23e6d03..db4953d7458 100644 --- a/src/sage/interfaces/rubik.py +++ b/src/sage/interfaces/rubik.py @@ -44,18 +44,7 @@ # Can't seem to find consistency in letter ordering # between us and them... These are copied from the source. -optimal_solver_tokens = ["UF", "UR", "UB", "UL", - "DF", "DR", "DB", "DL", - "FR", "FL", "BR", "BL", - "FU", "RU", "BU", "LU", - "FD", "RD", "BD", "LD", - "RF", "LF", "RB", "LB", - "UFR", "URB", "UBL", "ULF", - "DRF", "DFL", "DLB", "DBR", - "FRU", "RBU", "BLU", "LFU", - "RFD", "FLD", "LBD", "BRD", - "RUF", "BUR", "LUB", "FUL", - "FDR", "LDF", "BDL", "RDB"] +optimal_solver_tokens = ["UF", "UR", "UB", "UL", "DF", "DR", "DB", "DL", "FR", "FL", "BR", "BL", "FU", "RU", "BU", "LU", "FD", "RD", "BD", "LD", "RF", "LF", "RB", "LB", "UFR", "URB", "UBL", "ULF", "DRF", "DFL", "DLB", "DBR", "FRU", "RBU", "BLU", "LFU", "RFD", "FLD", "LBD", "BRD", "RUF", "BUR", "LUB", "FUL", "FDR", "LDF", "BDL", "RDB"] # The input format. optimal_solver_format = "UF UR UB UL DF DR DB DL FR FL BR BL UFR URB UBL ULF DRF DFL DLB DBR" @@ -75,6 +64,7 @@ class SingNot: sage: SingNot("acb") == SingNot("bca") False """ + def __init__(self, s): self.rep = s self.canonical = (s[0] + "".join(sorted(s[1:]))).lower() @@ -97,6 +87,7 @@ class OptimalSolver: """ Interface to Michael Reid's optimal Rubik's Cube solver. """ + def __init__(self, verbose=False, wait=True): self.verbose = verbose self.start() @@ -168,20 +159,7 @@ def format_cube(self, facets): return " ".join(str(f) for f in L) -move_map = { - "LD": "L'", - "LU": "L", - "RD": "R", - "RU": "R'", - "FA": "F", - "FC": "F'", - "BA": "B'", - "BC": "B", - "UR": "U", - "UL": "U'", - "DR": "D'", - "DL": "D" -} +move_map = {"LD": "L'", "LU": "L", "RD": "R", "RU": "R'", "FA": "F", "FC": "F'", "BA": "B'", "BC": "B", "UR": "U", "UL": "U'", "DR": "D'", "DL": "D"} class CubexSolver: @@ -225,14 +203,14 @@ def solve(self, facets): raise ValueError(bytes_to_str(s)) def format_cube(self, facets): - colors = sum([[i]*8 for i in range(1, 7)], []) + colors = sum([[i] * 8 for i in range(1, 7)], []) facet_colors = [0] * 54 for i in range(48): - f = facets[i]-1 + f = facets[i] - 1 f += (f + 4) // 8 # to compensate for the centers facet_colors[f] = colors[i] for i in range(6): - facet_colors[i*9+4] = i+1 + facet_colors[i * 9 + 4] = i + 1 return "".join(str(c) for c in facet_colors) @@ -287,8 +265,7 @@ def solve(self, facets, timeout=10, extra_time=2): # format the string into our notation child.close(True) sol = bytes_to_str(sol) - return ' '.join(self.rot_map[m[0]] + str(4 - int(m[1])) - for m in reversed(sol.split(' '))).replace('1', '').replace('3', "'") + return ' '.join(self.rot_map[m[0]] + str(4 - int(m[1])) for m in reversed(sol.split(' '))).replace('1', '').replace('3', "'") if ix == 1: # invalid format child.close(True) @@ -310,20 +287,67 @@ def format_cube(self, facets): facet_colors[16 + i * 3] = i return "".join(str(c) for c in facet_colors) - facet_map = [ 1, 2, 3, - 4, 0, 5, - 6, 7, 8, - 9, 10, 11, 17, 18, 19, 25, 26, 27, 33, 34, 35, - 12, 0, 13, 20, 0, 21, 28, 0, 29, 36, 0, 37, - 14, 15, 16, 22, 23, 24, 30, 31, 32, 38, 39, 40, - 41, 42, 43, - 44, 0, 45, - 46, 47, 48, - ] + facet_map = [ + 1, + 2, + 3, + 4, + 0, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 17, + 18, + 19, + 25, + 26, + 27, + 33, + 34, + 35, + 12, + 0, + 13, + 20, + 0, + 21, + 28, + 0, + 29, + 36, + 0, + 37, + 14, + 15, + 16, + 22, + 23, + 24, + 30, + 31, + 32, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 0, + 45, + 46, + 47, + 48, + ] # to compensate for different face naming rot_map = dict(zip("BLURDF", "ULFRBD")) + # facet_map = [ # 1, 2, 3, # 4, 6, diff --git a/src/sage/interfaces/sage0.py b/src/sage/interfaces/sage0.py index ebde777cf6f..29cd4fff7ec 100644 --- a/src/sage/interfaces/sage0.py +++ b/src/sage/interfaces/sage0.py @@ -126,14 +126,8 @@ class Sage(ExtraTabCompletion, Expect): its arguments using the s interpreter, so the call to s3 is passed ``s('"x"')``, which is the string ``'x'`` in the s interpreter. """ - def __init__(self, - logfile=None, - preparse=True, - init_code=None, - server=None, - server_tmpdir=None, - remote_cleaner=True, - **kwds): + + def __init__(self, logfile=None, preparse=True, init_code=None, server=None, server_tmpdir=None, remote_cleaner=True, **kwds): """ EXAMPLES:: @@ -149,38 +143,33 @@ def __init__(self, try: init_code = list(init_code) except TypeError: - raise TypeError( - 'init_code should be a string or an iterable of lines ' - 'of code') + raise TypeError('init_code should be a string or an iterable of lines ' 'of code') command = 'python3 -u' prompt = re.compile(b'>>> |sage: |In : ') environment = 'sage.all' init_code.append(f'from {environment} import *') init_code.append('import pickle') - init_code.append(textwrap.dedent(""" + init_code.append( + textwrap.dedent( + """ def _sage0_load_local(filename): with open(filename, 'rb') as f: return pickle.load(f) - """)) - init_code.append(textwrap.dedent(""" + """ + ) + ) + init_code.append( + textwrap.dedent( + """ def _sage0_load_remote(filename): with open(filename, 'rb') as f: return loads(f.read()) - """)) - - Expect.__init__(self, - name='sage', - prompt=prompt, - command=command, - restart_on_ctrlc=False, - logfile=logfile, - init_code=init_code, - server=server, - server_tmpdir=server_tmpdir, - remote_cleaner=remote_cleaner, - **kwds - ) + """ + ) + ) + + Expect.__init__(self, name='sage', prompt=prompt, command=command, restart_on_ctrlc=False, logfile=logfile, init_code=init_code, server=server, server_tmpdir=server_tmpdir, remote_cleaner=remote_cleaner, **kwds) self._preparse = preparse def cputime(self, t=None): @@ -199,7 +188,7 @@ def cputime(self, t=None): s = self.eval('cputime(%s)' % t) i = s.rfind('m') if i != -1: - s = s[i + 1:-1] + s = s[i + 1 : -1] return float(s) def _tab_completion(self): @@ -243,7 +232,7 @@ def __call__(self, x): code = '_sage0_load_local({!r})'.format(self._local_tmpfile()) return SageElement(self, code) with open(self._local_tmpfile(), 'wb') as fobj: - fobj.write(dumps(x)) # my dumps is compressed by default + fobj.write(dumps(x)) # my dumps is compressed by default self._send_tmpfile_to_server() code = '_sage0_load_remote({!r})'.format(self._remote_tmpfile()) return SageElement(self, code) @@ -533,8 +522,7 @@ def _repr_(self): sage: sage0(4).gcd """ - return str(self._obj.parent().eval('%s.%s' % (self._obj._name, - self._name))) + return str(self._obj.parent().eval('%s.%s' % (self._obj._name, self._name))) sage0 = Sage() @@ -563,6 +551,7 @@ def reduce_load_element(s): Sage """ import base64 + s = base64.b32encode(s) sage0.eval('import base64') return sage0('loads(base64.b32decode({!r}))'.format(s)) @@ -582,6 +571,7 @@ def sage0_console(): ... """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%sage0 magics instead.') os.system('sage') diff --git a/src/sage/interfaces/scilab.py b/src/sage/interfaces/scilab.py index b99617c3810..96344003097 100644 --- a/src/sage/interfaces/scilab.py +++ b/src/sage/interfaces/scilab.py @@ -179,6 +179,7 @@ - Ronan Paixao (2008-11-26), based on the MATLAB tutorial by William Stein (2006-10-11) """ + # **************************************************************************** # Copyright (C) 2006 William Stein # Copyright (C) 2008 Ronan Paixao @@ -216,9 +217,8 @@ class Scilab(Expect): 122. 505. """ - def __init__(self, maxread=None, script_subdirectory=None, - logfile=None, server=None, server_tmpdir=None, - seed=None): + + def __init__(self, maxread=None, script_subdirectory=None, logfile=None, server=None, server_tmpdir=None, seed=None): """ Initialize the Scilab class. @@ -228,17 +228,7 @@ def __init__(self, maxread=None, script_subdirectory=None, sage: sci_obj = Scilab() sage: del sci_obj """ - Expect.__init__(self, - name='scilab', - prompt='-->', - command="scilab -nw", - server=server, - server_tmpdir=server_tmpdir, - script_subdirectory=script_subdirectory, - restart_on_ctrlc=False, - verbose_start=False, - logfile=logfile, - eval_using_file_cutoff=100) + Expect.__init__(self, name='scilab', prompt='-->', command="scilab -nw", server=server, server_tmpdir=server_tmpdir, script_subdirectory=script_subdirectory, restart_on_ctrlc=False, verbose_start=False, logfile=logfile, eval_using_file_cutoff=100) self._seed = seed def set_seed(self, seed=None): @@ -377,7 +367,7 @@ def get(self, var): """ s = self.eval(f'{var}') i = s.find('=') - return s[i+1:] + return s[i + 1 :] def console(self): """ @@ -499,6 +489,7 @@ def _matrix_(self, R): [3.00000000000000 4.50000000000000] """ from sage.matrix.matrix_space import MatrixSpace + s = str(self).strip() v = s.split('\n ') nrows = len(v) diff --git a/src/sage/interfaces/singular.py b/src/sage/interfaces/singular.py index db070da200a..609f1a822c9 100644 --- a/src/sage/interfaces/singular.py +++ b/src/sage/interfaces/singular.py @@ -364,6 +364,7 @@ class SingularError(RuntimeError): """ Raised if Singular printed an error message """ + pass @@ -387,9 +388,8 @@ class Singular(ExtraTabCompletion, Expect): - David Joyner and William Stein """ - def __init__(self, maxread=None, script_subdirectory=None, - logfile=None, server=None, server_tmpdir=None, - seed=None): + + def __init__(self, maxread=None, script_subdirectory=None, logfile=None, server=None, server_tmpdir=None, seed=None): """ EXAMPLES:: @@ -398,24 +398,25 @@ def __init__(self, maxread=None, script_subdirectory=None, True """ prompt = '> ' - Expect.__init__(self, - terminal_echo=False, - name='singular', - prompt=prompt, - # no tty, fine grained cputime() - # and do not display CTRL-C prompt - command="{} -t --ticks-per-sec 1000 --cntrlc=a".format( - shlex.quote(sage.features.singular.Singular().absolute_filename())), - server=server, - server_tmpdir=server_tmpdir, - script_subdirectory=script_subdirectory, - restart_on_ctrlc=True, - verbose_start=False, - logfile=logfile, - eval_using_file_cutoff=100 if platform.system() == "SunOS" else 1000) + Expect.__init__( + self, + terminal_echo=False, + name='singular', + prompt=prompt, + # no tty, fine grained cputime() + # and do not display CTRL-C prompt + command="{} -t --ticks-per-sec 1000 --cntrlc=a".format(shlex.quote(sage.features.singular.Singular().absolute_filename())), + server=server, + server_tmpdir=server_tmpdir, + script_subdirectory=script_subdirectory, + restart_on_ctrlc=True, + verbose_start=False, + logfile=logfile, + eval_using_file_cutoff=100 if platform.system() == "SunOS" else 1000, + ) self.__libs = [] self._prompt_wait = prompt - self.__to_clear = [] # list of variable names that need to be cleared. + self.__to_clear = [] # list of variable names that need to be cleared. self._seed = seed def set_seed(self, seed=None): @@ -458,7 +459,7 @@ def _start(self, alt_message=None): self.__libs = [] Expect._start(self, alt_message) # Load some standard libraries. - self.lib('general') # assumed loaded by misc/constants.py + self.lib('general') # assumed loaded by misc/constants.py # these options are required by the new coefficient rings # supported by Singular 3-1-0. @@ -704,8 +705,7 @@ def set(self, type, name, value): sage: singular.eval('defined(%s)'%n) '0' """ - cmd = ''.join('if(defined(%s)){kill %s;};' % (v, v) - for v in self.__to_clear) + cmd = ''.join('if(defined(%s)){kill %s;};' % (v, v) for v in self.__to_clear) cmd += '%s %s=%s;' % (type, name, value) self.__to_clear = [] self.eval(cmd) @@ -1120,8 +1120,7 @@ def ring(self, char=0, vars='(x)', order='lp'): 3*a """ if len(vars) > 2: - s = '; '.join('if(defined(%s)>0){kill %s;};' % (x, x) - for x in vars[1:-1].split(',')) + s = '; '.join('if(defined(%s)>0){kill %s;};' % (x, x) for x in vars[1:-1].split(',')) self.eval(s) R = self('%s,%s,%s' % (char, vars, order), 'ring') @@ -1394,10 +1393,10 @@ def _repr_(self): if s.startswith("polynomial ring,"): from sage.repl.rich_output import get_display_manager from sage.rings.polynomial.term_order import singular_name_mapping + # this is our cue that singular uses `rp` instead of `ip` if singular_name_mapping['invlex'] == 'rp' and 'doctest' in str(get_display_manager()): - s = re.sub('^(// .*block.* : ordering )rp$', '\\1ip', - s, flags=re.MULTILINE) + s = re.sub('^(// .*block.* : ordering )rp$', '\\1ip', s, flags=re.MULTILINE) return s def __copy__(self): @@ -1626,17 +1625,20 @@ def sage_global_ring(self): singular = self.parent() charstr = singular.eval('charstr(basering)').split(',', 1) from sage.rings.integer_ring import ZZ + is_extension = len(charstr) == 2 if charstr[0] in ['integer', 'ZZ']: br = ZZ is_extension = False elif charstr[0] in ['0', 'QQ']: from sage.rings.rational_field import QQ + br = QQ elif charstr[0].startswith('Float'): from sage.functions.other import ceil from sage.misc.functional import log from sage.rings.real_mpfr import RealField + prec = singular.eval('ringlist(basering)[1][2][1]') br = RealField(ceil((ZZ(prec) + 1) / log(2, 10))) is_extension = False @@ -1644,6 +1646,7 @@ def sage_global_ring(self): from sage.functions.other import ceil from sage.misc.functional import log from sage.rings.complex_mpfr import ComplexField + prec = singular.eval('ringlist(basering)[1][2][1]') br = ComplexField(ceil((ZZ(prec) + 1) / log(2, 10))) is_extension = False @@ -1651,6 +1654,7 @@ def sage_global_ring(self): # it ought to be a finite field q = ZZ(charstr[0].removeprefix('ZZ/')) from sage.rings.finite_rings.finite_field_constructor import GF + if q.is_prime(): br = GF(q) else: @@ -1664,6 +1668,7 @@ def sage_global_ring(self): minpoly = singular.eval('minpoly') if minpoly == '0': from sage.rings.fraction_field import FractionField as Frac + BR = Frac(br[charstr[1]]) else: is_short = singular.eval('short') @@ -1681,10 +1686,11 @@ def sage_global_ring(self): # using Singular's term order from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.term_order import termorder_from_singular + # Meanwhile Singulars quotient rings are also of 'ring' type, not 'qring' as it was in the past. # To find out if a singular ring is a quotient ring or not checking for ring type does not help # and instead of that we check if the quotient ring is zero or not: - if (singular.eval('ideal(basering)==0') == '1'): + if singular.eval('ideal(basering)==0') == '1': return PolynomialRing(BR, names=singular.eval('varstr(basering)'), order=termorder_from_singular(singular)) P = PolynomialRing(BR, names=singular.eval('varstr(basering)'), order=termorder_from_singular(singular)) return P.quotient(singular('ringlist(basering)[4]')._sage_(P), names=singular.eval('varstr(basering)')) @@ -1823,14 +1829,12 @@ def sage_poly(self, R=None, kcache=None): out = R(self) self.parent().eval('short=%s' % is_short) return out - singular_poly_list = self.parent().eval("string(coef(%s,%s))" % ( - self.name(), variable_str)).split(",") + singular_poly_list = self.parent().eval("string(coef(%s,%s))" % (self.name(), variable_str)).split(",") self.parent().eval('short=%s' % is_short) else: if isinstance(R, MPolynomialRing_libsingular): return R(self) - singular_poly_list = self.parent().eval("string(coef(%s,%s))" % ( - self.name(), variable_str)).split(",") + singular_poly_list = self.parent().eval("string(coef(%s,%s))" % (self.name(), variable_str)).split(",") # Directly treat constants if singular_poly_list[0] in ['1', '(1.000e+00)']: @@ -1927,6 +1931,7 @@ def sage_matrix(self, R, sparse=True): [0.0 0.0] """ from sage.matrix.constructor import matrix + nrows, ncols = int(self.nrows()), int(self.ncols()) if R is None: @@ -2037,13 +2042,16 @@ def _sage_(self, R=None): return [f._sage_(R) for f in self] if typ == 'intvec': from sage.modules.free_module_element import vector + return vector([sage.rings.integer.Integer(str(e)) for e in self]) if typ == 'bigintvec': from sage.modules.free_module_element import vector + return vector([sage.rings.rational.Rational(str(e)) for e in self]) if typ == 'intmat': from sage.matrix.constructor import matrix from sage.rings.integer_ring import ZZ + A = matrix(ZZ, int(self.nrows()), int(self.ncols())) for i in range(A.nrows()): for j in range(A.ncols()): @@ -2283,10 +2291,10 @@ def _instancedoc_(self): sage: groebner(singular(I)) x+y, y^2-y -""" % (self._name,) - return prefix + get_docstring(self._name, - prefix=True, - code=True) +""" % ( + self._name, + ) + return prefix + get_docstring(self._name, prefix=True, code=True) @instancedoc @@ -2375,15 +2383,12 @@ def get_docstring(name, prefix=False, code=False): from sage.features.info import Info if not Info().is_present(): - raise OSError("GNU Info is not installed. Singular's " - "documentation will not be available.") + raise OSError("GNU Info is not installed. Singular's " "documentation will not be available.") import subprocess + cmd_and_args = ["info", f"--node={name}", "singular"] try: - result = subprocess.run(cmd_and_args, - capture_output=True, - check=True, - text=True) + result = subprocess.run(cmd_and_args, capture_output=True, check=True, text=True) except subprocess.CalledProcessError as e: # Before Texinfo v7.0.0, the "info" program would exit # successfully even if the desired node was not found. @@ -2418,8 +2423,7 @@ def get_docstring(name, prefix=False, code=False): result = "::\n\n " + "\n ".join(result.split('\n')) if prefix: - result = (f'The Singular documentation for "{name}" is given below.' - + "\n\n" + result) + result = f'The Singular documentation for "{name}" is given below.' + "\n\n" + result return result @@ -2452,6 +2456,7 @@ def singular_console(): FB Mathematik der Universitaet, D-67653 Kaiserslautern \ """ from sage.repl.rich_output.display_manager import get_display_manager + if not get_display_manager().is_in_terminal(): raise RuntimeError('Can use the console only in the terminal. Try %%singular magics instead.') os.system(sage.features.singular.Singular().absolute_filename()) @@ -2474,25 +2479,26 @@ class SingularGBLogPrettyPrinter: A device which prints Singular Groebner basis computation logs more verbatim. """ + rng_chng = re.compile(r"\[\d+:\d+\]") # [m:n] internal ring change to # poly representation with # exponent bound m and n words in # exponent vector - new_elem = re.compile("s") # found a new element of the standard basis - red_zero = re.compile("-") # reduced a pair/S-polynomial to 0 - red_post = re.compile(r"\.") # postponed a reduction of a pair/S-polynomial - cri_hilb = re.compile("h") # used Hilbert series criterion - hig_corn = re.compile(r"H\(\d+\)") # found a 'highest corner' of degree d, no need to consider higher degrees - num_crit = re.compile(r"\(\d+\)") # n critical pairs are still to be reduced + new_elem = re.compile("s") # found a new element of the standard basis + red_zero = re.compile("-") # reduced a pair/S-polynomial to 0 + red_post = re.compile(r"\.") # postponed a reduction of a pair/S-polynomial + cri_hilb = re.compile("h") # used Hilbert series criterion + hig_corn = re.compile(r"H\(\d+\)") # found a 'highest corner' of degree d, no need to consider higher degrees + num_crit = re.compile(r"\(\d+\)") # n critical pairs are still to be reduced red_num = re.compile(r"\(S:\d+\)") # doing complete reduction of n elements - deg_lead = re.compile(r"\d+") # the degree of the leading terms is currently d + deg_lead = re.compile(r"\d+") # the degree of the leading terms is currently d # SlimGB red_para = re.compile(r"M\[(\d+),(\d+)\]") # parallel reduction of n elements with m nonzero output elements - red_betr = re.compile("b") # exchange of a reductor by a 'better' one - non_mini = re.compile("e") # a new reductor with non-minimal leading term + red_betr = re.compile("b") # exchange of a reductor by a 'better' one + non_mini = re.compile("e") # a new reductor with non-minimal leading term crt_lne1 = re.compile(r"product criterion:(\d+) chain criterion:(\d+)") crt_lne2 = re.compile(r"NF:(\d+) product criterion:(\d+), ext_product criterion:(\d+)") @@ -2523,15 +2529,15 @@ def __init__(self, verbosity=1): self.verbosity = verbosity self.curr_deg = 0 # current degree - self.max_deg = 0 # maximal degree in total + self.max_deg = 0 # maximal degree in total - self.nf = 0 # number of normal forms computed (SlimGB only) + self.nf = 0 # number of normal forms computed (SlimGB only) self.prod = 0 # number of S-polynomials discarded using product criterion self.ext_prod = 0 # number of S-polynomials discarded using extended product criterion self.chain = 0 # number of S-polynomials discarded using chain criterion self.storage = "" # stores incomplete strings - self.sync = None # should we expect a sync integer? + self.sync = None # should we expect a sync integer? def write(self, s): """ @@ -2588,8 +2594,8 @@ def write(self, s): line = None continue - token, = match.groups() - line = line[len(token):] + (token,) = match.groups() + line = line[len(token) :] if re.match(SingularGBLogPrettyPrinter.rng_chng, token): continue @@ -2652,6 +2658,7 @@ class SingularGBDefaultContext: - Martin Albrecht - Simon King """ + def __init__(self, singular=None): """ Within this context all Singular Groebner basis calculations @@ -2699,6 +2706,7 @@ def __init__(self, singular=None): """ if singular is None: from sage.interfaces.singular import singular as singular_default + singular = singular_default self.singular = singular @@ -2805,4 +2813,5 @@ def singular_gb_standard_options(func): def wrapper(*args, **kwds): with SingularGBDefaultContext(): return func(*args, **kwds) + return wrapper diff --git a/src/sage/interfaces/sympy.py b/src/sage/interfaces/sympy.py index 2723b7f2221..af6ea0319e0 100644 --- a/src/sage/interfaces/sympy.py +++ b/src/sage/interfaces/sympy.py @@ -57,6 +57,7 @@ # ################ numbers and constants ############## + def _sympysage_float(self): """ EXAMPLES:: @@ -66,6 +67,7 @@ def _sympysage_float(self): sage: assert SR(-1.34) == RN('-1.34')._sage_() """ from sage.rings.real_mpfr import create_RealNumber + return create_RealNumber(str(self)) @@ -78,6 +80,7 @@ def _sympysage_integer_ring(self): Integer Ring """ from sage.rings.integer_ring import ZZ + return ZZ @@ -92,6 +95,7 @@ def _sympysage_integer(self): """ from sage.rings.integer import Integer + return Integer(self.p) @@ -105,6 +109,7 @@ def _sympysage_rational(self): """ from sage.rings.integer import Integer from sage.rings.rational import Rational + return Rational((Integer(self.p), Integer(self.q))) @@ -117,6 +122,7 @@ def _sympysage_rational_field(self): Rational Field """ from sage.rings.rational_field import QQ + return QQ @@ -140,6 +146,7 @@ def _sympysage_real_interval(self): # potential issue with precision # Just to be (a little bit) safe, we set it to 1024 from sage.rings.real_mpfi import RealIntervalField + RIF = RealIntervalField(1024) # NOTE: we call fraction_field since sympy stores mpq even # for integral entries @@ -167,6 +174,7 @@ def _sympysage_complex_interval(self): # potential issue with precision # Just to be (a little bit) safe, we set it to 1024 from sage.rings.complex_interval_field import ComplexIntervalField + CIF = ComplexIntervalField(1024) # NOTE: we call fraction_field since sympy stores mpq even # for integral entries @@ -237,6 +245,7 @@ def _sympysage_pinfty(self): sage: assert SR(oo) == sinf._sage_() """ from sage.rings.infinity import PlusInfinity + return PlusInfinity() @@ -249,6 +258,7 @@ def _sympysage_ninfty(self): sage: assert SR(-oo) == (-sinf)._sage_() """ from sage.rings.infinity import MinusInfinity + return MinusInfinity() @@ -261,6 +271,7 @@ def _sympysage_uinfty(self): sage: assert unsigned_infinity == zoo._sage_() """ from sage.rings.infinity import unsigned_infinity + return unsigned_infinity @@ -273,6 +284,7 @@ def _sympysage_nan(self): sage: assert NaN == snan._sage_() """ from sage.symbolic.constants import NaN + return NaN @@ -285,6 +297,7 @@ def _sympysage_e(self): sage: assert e == E._sage_() """ from sage.symbolic.constants import e + return e @@ -297,6 +310,7 @@ def _sympysage_pi(self): sage: assert pi == spi._sage_() """ from sage.symbolic.constants import pi + return pi @@ -309,6 +323,7 @@ def _sympysage_golden_ratio(self): sage: assert golden_ratio == S.GoldenRatio._sage_() """ from sage.symbolic.constants import golden_ratio + return golden_ratio @@ -321,6 +336,7 @@ def _sympysage_eulerg(self): sage: assert euler_gamma == S.EulerGamma._sage_() """ from sage.symbolic.constants import euler_gamma + return euler_gamma @@ -333,6 +349,7 @@ def _sympysage_catalan(self): sage: assert catalan == S.Catalan._sage_() """ from sage.symbolic.constants import catalan + return catalan @@ -345,11 +362,13 @@ def _sympysage_i(self): sage: assert I == S.ImaginaryUnit._sage_() """ from sage.symbolic.constants import I + return I # ################# basic operators ############## + def _sympysage_add(self): """ EXAMPLES:: @@ -389,7 +408,7 @@ def _sympysage_pow(self): sage: assert (x^pi^5)._sympy_() == Symbol('x')**S.Pi**5 sage: assert x^pi^5 == (Symbol('x')**S.Pi**5)._sage_() """ - return self.args[0]._sage_()**self.args[1]._sage_() + return self.args[0]._sage_() ** self.args[1]._sage_() def _sympysage_symbol(self): @@ -401,6 +420,7 @@ def _sympysage_symbol(self): sage: assert x == Symbol('x')._sage_() """ from sage.symbolic.ring import SR + try: return SR.var(self.name) except ValueError: @@ -418,13 +438,13 @@ def _sympysage_Subs(self): sage: from sympy.core.singleton import S """ args = self.args - substi = {args[1][i]._sage_(): args[2][i]._sage_() - for i in range(len(args[1]))} + substi = {args[1][i]._sage_(): args[2][i]._sage_() for i in range(len(args[1]))} return args[0]._sage_().subs(substi) # ############# functions ############### + def _sympysage_function_by_name(fname): """ Given a sympy function with name ``fname`` find the corresponding @@ -439,16 +459,20 @@ def _sympysage_function_by_name(fname): sage: assert f == F._sage_() """ from sage.functions import all as sagefuncs + func = getattr(sagefuncs, fname, None) # In the case the function is not known in sage: if func is None: import sympy + if getattr(sympy, fname, None) is None: # symbolic function from sage.symbolic.expression import symbol_table + func = symbol_table['functions'].get(fname) if func is None: from sage.calculus.var import function + return function(fname) else: @@ -472,6 +496,7 @@ class UndefSageHelper: sage: assert f._sympy_() == F sage: assert f == F._sage_() """ + def __get__(self, ins, typ): if ins is None: return lambda: _sympysage_function_by_name(typ.__name__) @@ -523,6 +548,7 @@ def _sympysage_integral(self): sage: assert integral(x, x, 0, 1, hold=True) == Integral(sx, (sx,0,1))._sage_() """ from sage.misc.functional import integral + f, limits = self.function._sage_(), list(self.limits) for limit in limits: if len(limit) == 1: @@ -569,9 +595,9 @@ def _sympysage_derivative(self): """ from sage.calculus.functional import derivative from sympy.core.containers import Tuple + f = self.args[0]._sage_() - args = [a._sage_() for arg in self.args[1:] - for a in (arg if isinstance(arg, (tuple, Tuple)) else [arg])] + args = [a._sage_() for arg in self.args[1:] for a in (arg if isinstance(arg, (tuple, Tuple)) else [arg])] return derivative(f, *args) @@ -585,6 +611,7 @@ def _sympysage_order(self): sage: assert Order(1) == SOrder(1)._sage_() """ from sage.functions.other import Order + return Order(self.args[0])._sage_() @@ -597,6 +624,7 @@ def _sympysage_lambertw(self): sage: assert lambert_w(x) == LambertW(Symbol('x'))._sage_() """ from sage.functions.log import lambert_w + return lambert_w(self.args[0]._sage_()) @@ -611,6 +639,7 @@ def _sympysage_rf(self): sage: assert rising_factorial(x,y) == rfxy._sage_() """ from sage.arith.misc import rising_factorial + return rising_factorial(self.args[0]._sage_(), self.args[1]._sage_()) @@ -625,6 +654,7 @@ def _sympysage_ff(self): sage: assert falling_factorial(x,y) == ffxy._sage_() """ from sage.arith.misc import falling_factorial + return falling_factorial(self.args[0]._sage_(), self.args[1]._sage_()) @@ -637,6 +667,7 @@ def _sympysage_lgamma(self): sage: assert log_gamma(x) == loggamma(Symbol('x'))._sage_() """ from sage.functions.gamma import log_gamma + return log_gamma(self.args[0]._sage_()) @@ -655,6 +686,7 @@ def _sympysage_polygamma(self): integrate(psi(x), x) """ from sage.functions.gamma import psi + return psi(self.args[0]._sage_(), self.args[1]._sage_()) @@ -667,6 +699,7 @@ def _sympysage_dirac_delta(self): sage: assert dirac_delta(x) == DiracDelta(Symbol('x'))._sage_() """ from sage.functions.generalized import dirac_delta + return dirac_delta(self.args[0]._sage_()) @@ -679,6 +712,7 @@ def _sympysage_heaviside(self): sage: assert heaviside(x) == Heaviside(Symbol('x'))._sage_() """ from sage.functions.generalized import heaviside + return heaviside(self.args[0]._sage_()) @@ -693,6 +727,7 @@ def _sympysage_expint(self): sage: assert exp_integral_e(x,y) == sy._sage_() """ from sage.functions.exp_integral import exp_integral_e + return exp_integral_e(self.args[0]._sage_(), self.args[1]._sage_()) @@ -707,6 +742,7 @@ def _sympysage_hyp(self): sage: assert hypergeometric((a,b),(p,q),x) == sy._sage_() """ from sage.functions.hypergeometric import hypergeometric + ap = [arg._sage_() for arg in self.args[0]] bq = [arg._sage_() for arg in self.args[1]] return hypergeometric(ap, bq, self.argument._sage_()) @@ -721,6 +757,7 @@ def _sympysage_elliptic_k(self): sage: assert elliptic_kc(x) == elliptic_k(Symbol('x'))._sage_() """ from sage.functions.special import elliptic_kc + return elliptic_kc(self.args[0]._sage_()) @@ -735,6 +772,7 @@ def _sympysage_kronecker_delta(self): sage: assert kronecker_delta(x,y) == sy._sage_() """ from sage.functions.generalized import kronecker_delta + return kronecker_delta(self.args[0]._sage_(), self.args[1]._sage_()) @@ -749,6 +787,7 @@ def _sympysage_ceiling(self): integrate(ceil(x), x, 0, +Infinity) """ from sage.functions.other import ceil + return ceil(self.args[0]._sage_()) @@ -768,6 +807,7 @@ def _sympysage_piecewise(self): -y*z + cases(((log(x) != 0, x^y/log(x)), (1, y))) """ from sage.functions.other import cases + return cases([(p.cond._sage_(), p.expr._sage_()) for p in self.args]) @@ -783,6 +823,7 @@ def _sympysage_fresnels(self): sage: assert ex == sp._sage_() """ from sage.functions.error import fresnel_sin + return fresnel_sin(self.args[0]._sage_()) @@ -798,6 +839,7 @@ def _sympysage_fresnelc(self): sage: assert ex == sp._sage_() """ from sage.functions.error import fresnel_cos + return fresnel_cos(self.args[0]._sage_()) @@ -812,6 +854,7 @@ def _sympysage_besselj(self): sage: assert bessel_J(x,y) == sy._sage_() """ from sage.functions.bessel import bessel_J + return bessel_J(self.args[0]._sage_(), self.args[1]._sage_()) @@ -826,6 +869,7 @@ def _sympysage_bessely(self): sage: assert bessel_Y(x,y) == sy._sage_() """ from sage.functions.bessel import bessel_Y + return bessel_Y(self.args[0]._sage_(), self.args[1]._sage_()) @@ -840,6 +884,7 @@ def _sympysage_besseli(self): sage: assert bessel_I(x,y) == sy._sage_() """ from sage.functions.bessel import bessel_I + return bessel_I(self.args[0]._sage_(), self.args[1]._sage_()) @@ -854,6 +899,7 @@ def _sympysage_besselk(self): sage: assert bessel_K(x,y) == sy._sage_() """ from sage.functions.bessel import bessel_K + return bessel_K(self.args[0]._sage_(), self.args[1]._sage_()) @@ -868,10 +914,8 @@ def _sympysage_ynm(self): sage: assert spherical_harmonic(n,m,t,p) == sy._sage_() """ from sage.functions.special import spherical_harmonic - return spherical_harmonic(self.args[0]._sage_(), - self.args[1]._sage_(), - self.args[2]._sage_(), - self.args[3]._sage_()) + + return spherical_harmonic(self.args[0]._sage_(), self.args[1]._sage_(), self.args[2]._sage_(), self.args[3]._sage_()) def _sympysage_re(self): @@ -883,6 +927,7 @@ def _sympysage_re(self): sage: assert real_part(x) == re(Symbol('x'))._sage_() """ from sage.functions.other import real_part + return real_part(self.args[0]._sage_()) @@ -895,6 +940,7 @@ def _sympysage_im(self): sage: assert imag_part(x) == im(Symbol('x'))._sage_() """ from sage.functions.other import imag_part + return imag_part(self.args[0]._sage_()) @@ -907,6 +953,7 @@ def _sympysage_abs(self): sage: assert abs(x) == Abs(Symbol('x'))._sage_() """ from sage.functions.other import abs_symbolic + return abs_symbolic(self.args[0]._sage_()) @@ -926,6 +973,7 @@ def _sympysage_crootof(self): """ from sage.functions.other import complex_root_of from sage.symbolic.ring import SR + return complex_root_of(self.args[0]._sage_(), SR(self.args[1])) @@ -1001,22 +1049,21 @@ def _sympysage_matrix(self): from sage.matrix.constructor import matrix rows, cols = self.shape - d = {row_col: value._sage_() - for row_col, value in self.todok().items()} + d = {row_col: value._sage_() for row_col, value in self.todok().items()} if not d: from sage.rings.integer_ring import ZZ + base_ring = ZZ else: from sage.structure.element import get_coercion_model from sage.symbolic.ring import SR + coercion_model = get_coercion_model() try: base_ring = coercion_model.common_parent(*d.values()) except TypeError: # no common canonical parent base_ring = SR - result = matrix(base_ring, rows, cols, d, - sparse=isinstance(self, SparseMatrix), - immutable=True) + result = matrix(base_ring, rows, cols, d, sparse=isinstance(self, SparseMatrix), immutable=True) if isinstance(self, ImmutableMatrix): self._sage_object = result return result @@ -1043,6 +1090,7 @@ def _sympysage_relational(self): """ from operator import eq, ne, gt, lt, ge, le from sympy import Eq, Ne, Gt, Ge, Lt, Le + ops = {Eq: eq, Ne: ne, Gt: gt, Lt: lt, Ge: ge, Le: le} return ops.get(self.func)(self.lhs._sage_(), self.rhs._sage_()) @@ -1056,6 +1104,7 @@ def _sympysage_false(self): sage: assert SR(False) == BooleanFalse()._sage_() """ from sage.symbolic.ring import SR + return SR(False) @@ -1068,6 +1117,7 @@ def _sympysage_true(self): sage: assert SR(True) == BooleanTrue()._sage_() """ from sage.symbolic.ring import SR + return SR(True) @@ -1093,26 +1143,23 @@ def sympy_init(): sage: assert abs(x) == Abs(Symbol('x'))._sage_() """ from sympy import Add + if Add._sage_ == _sympysage_add: return from sympy import Mul, Pow, Symbol, Subs - from sympy.core.function import (Function, AppliedUndef, Derivative) - from sympy.core.numbers import (Float, Integer, Rational, Infinity, - NegativeInfinity, ComplexInfinity, - Exp1, Pi, GoldenRatio, - EulerGamma, Catalan, ImaginaryUnit) + from sympy.core.function import Function, AppliedUndef, Derivative + from sympy.core.numbers import Float, Integer, Rational, Infinity, NegativeInfinity, ComplexInfinity, Exp1, Pi, GoldenRatio, EulerGamma, Catalan, ImaginaryUnit from sympy.core.numbers import NaN as sympy_nan from sympy.core.relational import Relational - from sympy.functions.combinatorial.factorials import (RisingFactorial, - FallingFactorial) - from sympy.functions.elementary.complexes import (re, im, Abs) + from sympy.functions.combinatorial.factorials import RisingFactorial, FallingFactorial + from sympy.functions.elementary.complexes import re, im, Abs from sympy.functions.elementary.exponential import LambertW from sympy.functions.elementary.integers import ceiling from sympy.functions.elementary.piecewise import Piecewise from sympy.functions.special.error_functions import fresnels, fresnelc - from sympy.functions.special.bessel import (besselj, bessely, besseli, besselk) - from sympy.functions.special.delta_functions import (DiracDelta, Heaviside) + from sympy.functions.special.bessel import besselj, bessely, besseli, besselk + from sympy.functions.special.delta_functions import DiracDelta, Heaviside from sympy.functions.special.error_functions import expint from sympy.functions.special.elliptic_integrals import elliptic_k from sympy.functions.special.gamma_functions import loggamma, polygamma @@ -1162,6 +1209,7 @@ def sympy_init(): Function._sage_ = _sympysage_function AppliedUndef._sage_ = _sympysage_function import sympy.core.function + sympy.core.function._undef_sage_helper = UndefSageHelper() Integral._sage_ = _sympysage_integral Derivative._sage_ = _sympysage_derivative @@ -1204,7 +1252,8 @@ def check_expression(expr, var_symbols, only_from_sympy=False): sage: check_expression("1.123*x", "x") """ from sage.symbolic.ring import SR - from sympy import (__dict__ as sympydict, Basic, S, var as svar) + from sympy import __dict__ as sympydict, Basic, S, var as svar + # evaluate the expression in the context of Sage: if var_symbols: SR.var(var_symbols) @@ -1245,6 +1294,7 @@ def check_all(): sage: from sage.interfaces.sympy import check_all sage: check_all() """ + def test_basics(): check_expression("x", "x") check_expression("x**2", "x") @@ -1271,6 +1321,7 @@ def test_real(): def test_functions(): # Test at least one Function without own _sage_ method from sympy import factorial + assert "_sage_" not in factorial.__dict__ check_expression("factorial(x)", "x") check_expression("sin(x)", "x") @@ -1300,6 +1351,7 @@ def test_issue_4023(): from sage.symbolic.ring import SR from sage.misc.functional import log from sympy import integrate, simplify + a, x = SR.var("a x") i = integrate(log(x) / a, (x, a, a + 1)) i2 = simplify(i) @@ -1326,6 +1378,7 @@ def test_undefined_function(): from sage.symbolic.ring import SR from sage.calculus.var import function from sympy import Symbol, Function + f = function('f') sf = Function('f') x, y = SR.var('x y') @@ -1355,8 +1408,9 @@ def sympy_set_to_list(set, vars): Convert all set objects that can be returned by SymPy's solvers. """ from sage.rings.infinity import UnsignedInfinity - from sympy import (FiniteSet, And, Or, Union, Interval, oo, S) + from sympy import FiniteSet, And, Or, Union, Interval, oo, S from sympy.core.relational import Relational + if set == S.Reals: return [x._sage_() < oo for x in vars] if set == S.Complexes: @@ -1365,8 +1419,7 @@ def sympy_set_to_list(set, vars): return [] if isinstance(set, (And, Or, Relational)): if isinstance(set, And): - return [[item for rel in set._args[0] - for item in sympy_set_to_list(rel, vars)]] + return [[item for rel in set._args[0] for item in sympy_set_to_list(rel, vars)]] if isinstance(set, Or): return [sympy_set_to_list(iv, vars) for iv in set._args[0]] if isinstance(set, Relational): diff --git a/src/sage/interfaces/sympy_wrapper.py b/src/sage/interfaces/sympy_wrapper.py index 40c96d60d26..9188f308c36 100644 --- a/src/sage/interfaces/sympy_wrapper.py +++ b/src/sage/interfaces/sympy_wrapper.py @@ -121,6 +121,7 @@ def is_iterable(self): True """ from sage.categories.enumerated_sets import EnumeratedSets + return self._sage_() in EnumeratedSets() def __iter__(self): diff --git a/src/sage/interfaces/tab_completion.py b/src/sage/interfaces/tab_completion.py index 29865b54d9e..b824ab66a11 100644 --- a/src/sage/interfaces/tab_completion.py +++ b/src/sage/interfaces/tab_completion.py @@ -24,6 +24,7 @@ sage: sorted(dir(f)) [..., '_tab_completion', 'a', 'b', 'c', 'd'] """ + import builtins @@ -47,8 +48,7 @@ def __dir__(self): try: tab_fn = self._tab_completion except AttributeError: - raise NotImplementedError( - '{0} must implement _tab_completion() method'.format(self.__class__)) + raise NotImplementedError('{0} must implement _tab_completion() method'.format(self.__class__)) return dir(self.__class__) + list(self.__dict__) + tab_fn() @@ -85,7 +85,7 @@ def completions(s, globs): v += [x for x in builtins.__dict__ if x[:n] == s] else: i = s.rfind('.') - method = s[i + 1:] + method = s[i + 1 :] obj = s[:i] n = len(method) try: diff --git a/src/sage/interfaces/tachyon.py b/src/sage/interfaces/tachyon.py index f5fa115396c..1d419a4201f 100644 --- a/src/sage/interfaces/tachyon.py +++ b/src/sage/interfaces/tachyon.py @@ -741,6 +741,7 @@ class TachyonRT(SageObject): .. automethod:: __call__ """ + def _repr_(self): """ Return a brief description of this interface object (the Tachyon @@ -801,9 +802,7 @@ def __call__(self, model, outfile='sage.png', verbose=1, extra_opts=''): """ if self.version() >= '0.99.2': # this keyword was changed in 0.99.2 - model = model.replace( - " focallength ", - " focaldist ") + model = model.replace(" focallength ", " focaldist ") modelfile = tmp_filename(ext='.dat') with open(modelfile, 'w') as file: file.write(model) @@ -826,6 +825,7 @@ def __call__(self, model, outfile='sage.png', verbose=1, extra_opts=''): if verbose: print(' '.join(cmd)) import subprocess + out = bytes_to_str(subprocess.check_output(cmd)) if verbose >= 1: print(out) diff --git a/src/sage/interfaces/tides.py b/src/sage/interfaces/tides.py index 42877ede9ee..765956fa85c 100644 --- a/src/sage/interfaces/tides.py +++ b/src/sage/interfaces/tides.py @@ -40,6 +40,7 @@ from sage.rings.real_mpfr import RealField from sage.misc.lazy_import import lazy_import + lazy_import("sage.calculus.all", "symbolic_expression") from sage.misc.flatten import flatten from sage.ext.fast_callable import fast_callable @@ -146,6 +147,7 @@ def subexpressions_list(f, pars=None): ('exp', x^2 + sin(y))]) """ from sage.functions.trig import sin, cos, arcsin, arctan, arccos + variables = f[0].arguments() if not pars: parameters = [] @@ -153,7 +155,7 @@ def subexpressions_list(f, pars=None): parameters = pars varpar = list(parameters) + list(variables) F = symbolic_expression([i(*variables) for i in f]).function(*varpar) - lis = flatten([fast_callable(i,vars=varpar).op_list() for i in F], max_level=1) + lis = flatten([fast_callable(i, vars=varpar).op_list() for i in F], max_level=1) stack = [] const = [] stackcomp = [] @@ -164,14 +166,14 @@ def subexpressions_list(f, pars=None): elif i[0] == 'ipow': if i[1] in NN: basis = stack[-1] - for j in range(i[1]-1): + for j in range(i[1] - 1): a = stack.pop(-1) detail.append(('mul', a, basis)) - stack.append(a*basis) + stack.append(a * basis) stackcomp.append(stack[-1]) else: - detail.append(('pow',stack[-1],i[1])) - stack[-1] = stack[-1]**i[1] + detail.append(('pow', stack[-1], i[1])) + stack[-1] = stack[-1] ** i[1] stackcomp.append(stack[-1]) elif i[0] == 'load_const': @@ -181,21 +183,21 @@ def subexpressions_list(f, pars=None): a = stack.pop(-1) b = stack.pop(-1) detail.append(('mul', a, b)) - stack.append(a*b) + stack.append(a * b) stackcomp.append(stack[-1]) elif i == 'div': a = stack.pop(-1) b = stack.pop(-1) detail.append(('div', a, b)) - stack.append(b/a) + stack.append(b / a) stackcomp.append(stack[-1]) elif i == 'add': a = stack.pop(-1) b = stack.pop(-1) - detail.append(('add',a,b)) - stack.append(a+b) + detail.append(('add', a, b)) + stack.append(a + b) stackcomp.append(stack[-1]) elif i == 'pow': @@ -242,46 +244,46 @@ def subexpressions_list(f, pars=None): detail.append(('div', b, c)) stackcomp.append(b) stackcomp.append(c) - stackcomp.append(b/c) - stack.append(b/c) + stackcomp.append(b / c) + stack.append(b / c) elif i[0] == 'py_call' and str(i[1]) == 'arctan': a = stack.pop(-1) detail.append(('mul', a, a)) - detail.append(('add', 1, a*a)) + detail.append(('add', 1, a * a)) detail.append(('atan', a)) - stackcomp.append(a*a) - stackcomp.append(1+a*a) + stackcomp.append(a * a) + stackcomp.append(1 + a * a) stackcomp.append(arctan(a)) stack.append(arctan(a)) elif i[0] == 'py_call' and str(i[1]) == 'arcsin': a = stack.pop(-1) detail.append(('mul', a, a)) - detail.append(('mul', -1, a*a)) - detail.append(('add', 1, -a*a)) - detail.append(('pow', 1 - a*a, 0.5)) + detail.append(('mul', -1, a * a)) + detail.append(('add', 1, -a * a)) + detail.append(('pow', 1 - a * a, 0.5)) detail.append(('asin', a)) - stackcomp.append(a*a) - stackcomp.append(-a*a) - stackcomp.append(1-a*a) - stackcomp.append(sqrt(1-a*a)) + stackcomp.append(a * a) + stackcomp.append(-a * a) + stackcomp.append(1 - a * a) + stackcomp.append(sqrt(1 - a * a)) stackcomp.append(arcsin(a)) stack.append(arcsin(a)) elif i[0] == 'py_call' and str(i[1]) == 'arccos': a = stack.pop(-1) detail.append(('mul', a, a)) - detail.append(('mul', -1, a*a)) - detail.append(('add', 1, -a*a)) - detail.append(('pow', 1 - a*a, 0.5)) - detail.append(('mul', -1, sqrt(1-a*a))) + detail.append(('mul', -1, a * a)) + detail.append(('add', 1, -a * a)) + detail.append(('pow', 1 - a * a, 0.5)) + detail.append(('mul', -1, sqrt(1 - a * a))) detail.append(('acos', a)) - stackcomp.append(a*a) - stackcomp.append(-a*a) - stackcomp.append(1-a*a) - stackcomp.append(sqrt(1-a*a)) - stackcomp.append(-sqrt(1-a*a)) + stackcomp.append(a * a) + stackcomp.append(-a * a) + stackcomp.append(1 - a * a) + stackcomp.append(sqrt(1 - a * a)) + stackcomp.append(-sqrt(1 - a * a)) stackcomp.append(arccos(a)) stack.append(arccos(a)) @@ -297,7 +299,7 @@ def subexpressions_list(f, pars=None): stack.append(-a) stackcomp.append(-a) - return stackcomp,detail + return stackcomp, detail def remove_repeated(l1, l2): @@ -330,8 +332,8 @@ def remove_repeated(l1, l2): ('pow', -a^2 + 1, 0.5), ('asin', a)]) """ - for i in range(len(l1)-1): - j = i+1 + for i in range(len(l1) - 1): + j = i + 1 while j < len(l1): if str(l1[j]) == str(l1[i]): l1.pop(j) @@ -366,8 +368,7 @@ def remove_constants(l1, l2): i += 1 -def genfiles_mintides(integrator, driver, f, ics, initial, final, delta, - tolrel=1e-16, tolabs=1e-16, output=''): +def genfiles_mintides(integrator, driver, f, ics, initial, final, delta, tolrel=1e-16, tolabs=1e-16, output=''): r""" Generate the needed files for the min_tides library. @@ -476,7 +477,7 @@ def genfiles_mintides(integrator, driver, f, ics, initial, final, delta, if a in var: l3.append((oper, 'XX[{}]'.format(lv.index(str(a))))) elif a in l1: - l3.append((oper, 'XX[{}]'.format(l0.index(str(a))+len(var)))) + l3.append((oper, 'XX[{}]'.format(l0.index(str(a)) + len(var)))) else: a = i[1] @@ -487,14 +488,14 @@ def genfiles_mintides(integrator, driver, f, ics, initial, final, delta, if str(a) in lv: aa = 'XX[{}]'.format(lv.index(str(a))) elif str(a) in l0: - aa = 'XX[{}]'.format(l0.index(str(a))+len(var)) + aa = 'XX[{}]'.format(l0.index(str(a)) + len(var)) else: consta = True aa = RR(a).str() if str(b) in lv: bb = 'XX[{}]'.format(lv.index(str(b))) elif str(b) in l0: - bb = 'XX[{}]'.format(l0.index(str(b))+len(var)) + bb = 'XX[{}]'.format(l0.index(str(b)) + len(var)) else: constb = True bb = RR(b).str() @@ -516,30 +517,30 @@ def genfiles_mintides(integrator, driver, f, ics, initial, final, delta, elif el[0] == 'add_c': string += "(i==0)? {}+".format(el[2]) + el[1] + "[0] : " + el[1] + "[i];" elif el[0] == 'mul': - string += "mul_mc("+el[1]+","+el[2]+",i);" + string += "mul_mc(" + el[1] + "," + el[2] + ",i);" elif el[0] == 'mul_c': string += el[2] + "*" + el[1] + "[i];" elif el[0] == 'pow_c': - string += "pow_mc_c("+el[1]+","+el[2]+",XX[{}], i);".format(i+n) + string += "pow_mc_c(" + el[1] + "," + el[2] + ",XX[{}], i);".format(i + n) elif el[0] == 'div': - string += "div_mc("+el[2]+","+el[1]+",XX[{}], i);".format(i+n) + string += "div_mc(" + el[2] + "," + el[1] + ",XX[{}], i);".format(i + n) elif el[0] == 'div_c': - string += "inv_mc("+el[2]+","+el[1]+",XX[{}], i);".format(i+n) + string += "inv_mc(" + el[2] + "," + el[1] + ",XX[{}], i);".format(i + n) elif el[0] == 'log': - string += "log_mc(" + el[1] + ",XX[{}], i);".format(i+n) + string += "log_mc(" + el[1] + ",XX[{}], i);".format(i + n) elif el[0] == 'exp': - string += "exp_mc(" + el[1] + ",XX[{}], i);".format(i+n) + string += "exp_mc(" + el[1] + ",XX[{}], i);".format(i + n) elif el[0] == 'sin': - string += "sin_mc(" + el[1] + ",XX[{}], i);".format(i+n+1) + string += "sin_mc(" + el[1] + ",XX[{}], i);".format(i + n + 1) elif el[0] == 'cos': - string += "cos_mc(" + el[1] + ",XX[{}], i);".format(i+n-1) + string += "cos_mc(" + el[1] + ",XX[{}], i);".format(i + n - 1) res.append(string) l0 = lv + l0 indices = [l0.index(str(i(*var))) + n for i in f] for i in range(1, n): - res.append("XX[{}][i+1] = XX[{}][i] / (i+1.0);".format(i,indices[i-1]-n)) + res.append("XX[{}][i+1] = XX[{}][i] / (i+1.0);".format(i, indices[i - 1] - n)) code = res @@ -607,7 +608,9 @@ def genfiles_mintides(integrator, driver, f, ics, initial, final, delta, double tolrel, tolabs, tini, tend, dt; double v[VARS], p[PARS]; - """ % (n-1) + """ % ( + n - 1 + ) outfile.write(auxstring) for i in range(len(ics)): outfile.write('\tv[{}] = {} ; \n'.format(i, RR(ics[i]).str())) @@ -623,9 +626,7 @@ def genfiles_mintides(integrator, driver, f, ics, initial, final, delta, outfile.close() -def genfiles_mpfr(integrator, driver, f, ics, initial, final, delta, - parameters=None, parameter_values=None, dig=20, tolrel=1e-16, - tolabs=1e-16, output=''): +def genfiles_mpfr(integrator, driver, f, ics, initial, final, delta, parameters=None, parameter_values=None, dig=20, tolrel=1e-16, tolabs=1e-16, output=''): r""" Generate the needed files for the mpfr module of the tides library. @@ -789,7 +790,7 @@ def genfiles_mpfr(integrator, driver, f, ics, initial, final, delta, if consta: oper += '_c' if not oper == 'div': - bb, aa = aa,bb + bb, aa = aa, bb elif constb: oper += '_c' l3.append((oper, aa, bb)) @@ -832,13 +833,13 @@ def genfiles_mpfr(integrator, driver, f, ics, initial, final, delta, elif el[0] == 'cos': string += 'cos_t(itd, ' + el[1] + f', link[{i-1}], link[{i}], i);' elif el[0] == 'atan': - indarg = l0.index(str(1+l2[i][1]**2))-n + indarg = l0.index(str(1 + l2[i][1] ** 2)) - n string += 'atan_t(itd, ' + el[1] + f', link[{indarg}], link[{i}], i);' elif el[0] == 'asin': - indarg = l0.index(str(sqrt(1-l2[i][1]**2)))-n + indarg = l0.index(str(sqrt(1 - l2[i][1] ** 2))) - n string += 'asin_t(itd, ' + el[1] + f', link[{indarg}], link[{i}], i);' elif el[0] == 'acos': - indarg = l0.index(str(-sqrt(1-l2[i][1]**2)))-n + indarg = l0.index(str(-sqrt(1 - l2[i][1] ** 2))) - n string += 'acos_t(itd, ' + el[1] + f', link[{indarg}], link[{i}], i);' code.append(string) @@ -913,11 +914,11 @@ def genfiles_mpfr(integrator, driver, f, ics, initial, final, delta, outfile.write('\tfor(i=0; i 6: from sage.features.databases import DatabaseKnotInfo + DatabaseKnotInfo().require() current_max_crossing_number = self._max_crossing_number if not current_max_crossing_number: - current_max_crossing_number = - 1 + current_max_crossing_number = -1 self._index_dict = {} self._max_crossing_number = max_crossing_number @@ -190,6 +192,7 @@ def add_index(ki, sym): self._index_dict[self._from_knotinfo(ki, sym)] = (ki, sym) from sage.knots.knotinfo import KnotInfo + for K in KnotInfo: ncr = K.crossing_number() if ncr <= current_max_crossing_number: @@ -201,6 +204,7 @@ def add_index(ki, sym): add_index(K, sym) if current_max_crossing_number > 0: from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + self._indices = FiniteEnumeratedSet(self._index_dict) def _repr_(self): @@ -231,6 +235,7 @@ def _element_constructor_(self, x=None): if len(x) == 2: ki, sym = x from sage.knots.knotinfo import KnotInfoBase + if isinstance(ki, KnotInfoBase) and isinstance(sym, SymmetryMutant): mcr = ki.crossing_number() if mcr > self._max_crossing_number: @@ -241,6 +246,7 @@ def _element_constructor_(self, x=None): from sage.knots.knot import Knot from sage.knots.link import Link + if not isinstance(x, Knot): if isinstance(x, Link): x = Knot(x.pd_code()) @@ -470,6 +476,7 @@ def inject_variables(self, select=None, verbose=True): """ from sage.knots.knotinfo import KnotInfoBase, KnotInfoSeries from sage.rings.integer import Integer + gen_list = [] idx_dict = self._index_dict max_crn = self._max_crossing_number @@ -488,14 +495,14 @@ def inject_variables(self, select=None, verbose=True): crn = select if crn > max_crn: self._set_index_dictionary(max_crossing_number=crn) - gen_list += [k for k, v in idx_dict.items() - if v[0].crossing_number() == crn] + gen_list += [k for k, v in idx_dict.items() if v[0].crossing_number() == crn] else: raise TypeError('cannot select generators by %s' % select) else: gen_list = list(idx_dict.keys()) from sage.repl.user_globals import set_global, get_globals + for name in gen_list: if name not in get_globals().keys(): set_global(name, gens[name]) diff --git a/src/sage/knots/gauss_code.py b/src/sage/knots/gauss_code.py index 560b6831bfc..2576d9eb225 100644 --- a/src/sage/knots/gauss_code.py +++ b/src/sage/knots/gauss_code.py @@ -118,8 +118,8 @@ def recover_orientations(gauss): changed = list(gauss) for i in range(1, n + 1): id0 = changed.index(i) - start = changed[:id0 + 1] - after0 = changed[id0 + 1:] + start = changed[: id0 + 1] + after0 = changed[id0 + 1 :] id1 = after0.index(i) middle = list(reversed(after0[:id1])) end = after0[id1:] diff --git a/src/sage/knots/knot.py b/src/sage/knots/knot.py index 60d15fc9a74..d548cd1f955 100644 --- a/src/sage/knots/knot.py +++ b/src/sage/knots/knot.py @@ -20,8 +20,7 @@ from sage.knots.link import Link from sage.knots.knot_table import small_knots_table -from sage.knots.gauss_code import (recover_orientations, dowker_to_gauss, - rectangular_diagram) +from sage.knots.gauss_code import recover_orientations, dowker_to_gauss, rectangular_diagram from sage.structure.parent import Parent from sage.structure.element import Element @@ -83,6 +82,7 @@ class Knot(Link, Element, metaclass=InheritComparisonClasscallMetaclass): - :wikipedia:`Knot_(mathematics)` """ + @staticmethod def __classcall_private__(self, data, check=True): """ @@ -124,8 +124,7 @@ def __init__(self, data, check=True): Link.__init__(self, data) if check: if self.number_of_components() != 1: - raise ValueError("the input has more than 1 connected " - "component") + raise ValueError("the input has more than 1 connected " "component") def _repr_(self): """ @@ -239,6 +238,7 @@ def _unicode_art_(self): M[x][y] = V from sage.typeset.unicode_art import UnicodeArt + return UnicodeArt([''.join(ligne) for ligne in M]) def dt_code(self): @@ -382,8 +382,7 @@ def colored_jones_polynomial(self, N, variab=None, try_inverse=True): sage: K.colored_jones_polynomial(2, t+1) (t^3 + 3*t^2 + 4*t + 1)/(t^4 + 4*t^3 + 6*t^2 + 4*t + 1) """ - return self.braid().colored_jones_polynomial(N=N, variab=variab, - try_inverse=try_inverse) + return self.braid().colored_jones_polynomial(N=N, variab=variab, try_inverse=try_inverse) def connected_sum(self, other): r""" @@ -462,6 +461,7 @@ def connected_sum(self, other): - :wikipedia:`Connected_sum` """ from sage.functions.generalized import sign + ogc1 = self.oriented_gauss_code() ogc2 = other.oriented_gauss_code() if not ogc1[0]: @@ -485,6 +485,7 @@ class Knots(Singleton, Parent): """ The set for all knots, as a monoid for the connected sum. """ + def __init__(self): """ TESTS:: diff --git a/src/sage/knots/knot_table.py b/src/sage/knots/knot_table.py index 8defab899c4..8f4a62f8832 100644 --- a/src/sage/knots/knot_table.py +++ b/src/sage/knots/knot_table.py @@ -28,256 +28,255 @@ http://katlas.org/wiki/The_Thistlethwaite_Link_Table """ - small_knots_table = { (0, 1): (1, []), - (3, 1): (2, [-1,-1,-1]), - (4, 1): (3, [-1,2,-1,2]), - (5, 1): (2, [-1,-1,-1,-1,-1]), - (5, 2): (3, [-1,-1,-1,-2,1,-2]), - (6, 1): (4, [-1,-1,-2,1,3,-2,3]), - (6, 2): (3, [-1,-1,-1,2,-1,2]), - (6, 3): (3, [-1,-1,2,-1,2,2]), - (7, 1): (2, [-1,-1,-1,-1,-1,-1,-1]), - (7, 2): (4, [-1,-1,-1,-2,1,-2,-3,2,-3]), - (7, 3): (3, [1,1,1,1,1,2,-1,2]), - (7, 4): (4, [1,1,2,-1,2,2,3,-2,3]), - (7, 5): (3, [-1,-1,-1,-1,-2,1,-2,-2]), - (7, 6): (4, [-1,-1,2,-1,-3,2,-3]), - (7, 7): (4, [1,-2,1,-2,3,-2,3]), - (8, 1): (5, [-1,-1,-2,1,-2,-3,2,4,-3,4]), - (8, 2): (3, [-1,-1,-1,-1,-1,2,-1,2]), - (8, 3): (5, [-1,-1,-2,1,3,-2,3,4,-3,4]), - (8, 4): (4, [-1,-1,-1,2,-1,2,3,-2,3]), - (8, 5): (3, [1,1,1,-2,1,1,1,-2]), - (8, 6): (4, [-1,-1,-1,-1,-2,1,3,-2,3]), - (8, 7): (3, [1,1,1,1,-2,1,-2,-2]), - (8, 8): (4, [1,1,1,2,-1,-3,2,-3,-3]), - (8, 9): (3, [-1,-1,-1,2,-1,2,2,2]), - (8, 10): (3, [1,1,1,-2,1,1,-2,-2]), - (8, 11): (4, [-1,-1,-2,1,-2,-2,3,-2,3]), - (8, 12): (5, [-1,2,-1,-3,2,4,-3,4]), - (8, 13): (4, [-1,-1,2,-1,2,2,3,-2,3]), - (8, 14): (4, [-1,-1,-1,-2,1,-2,3,-2,3]), - (8, 15): (4, [-1,-1,2,-1,-3,-2,-2,-2,-3]), - (8, 16): (3, [-1,-1,2,-1,-1,2,-1,2]), - (8, 17): (3, [-1,-1,2,-1,2,-1,2,2]), - (8, 18): (3, [-1,2,-1,2,-1,2,-1,2]), - (8, 19): (3, [1,1,1,2,1,1,1,2]), - (8, 20): (3, [1,1,1,-2,-1,-1,-1,-2]), - (8, 21): (3, [-1,-1,-1,-2,1,1,-2,-2]), - (9, 1): (2, [-1,-1,-1,-1,-1,-1,-1,-1,-1]), - (9, 2): (5, [-1,-1,-1,-2,1,-2,-3,2,-3,-4,3,-4]), - (9, 3): (3, [1,1,1,1,1,1,1,2,-1,2]), - (9, 4): (4, [-1,-1,-1,-1,-1,-2,1,-2,-3,2,-3]), - (9, 5): (5, [1,1,2,-1,2,2,3,-2,3,4,-3,4]), - (9, 6): (3, [-1,-1,-1,-1,-1,-1,-2,1,-2,-2]), - (9, 7): (4, [-1,-1,-1,-1,-2,1,-2,-3,2,-3,-3]), - (9, 8): (5, [-1,-1,2,-1,2,3,-2,-4,3,-4]), - (9, 9): (3, [-1,-1,-1,-1,-1,-2,1,-2,-2,-2]), - (9, 10): (4, [1,1,2,-1,2,2,2,2,3,-2,3]), - (9, 11): (4, [1,1,1,1,-2,1,3,-2,3]), - (9, 12): (5, [-1,-1,2,-1,-3,2,-3,-4,3,-4]), - (9, 13): (4, [1,1,1,1,2,-1,2,2,3,-2,3]), - (9, 14): (5, [1,1,2,-1,-3,2,-3,4,-3,4]), - (9, 15): (5, [1,1,1,2,-1,-3,2,4,-3,4]), - (9, 16): (3, [1,1,1,1,2,2,-1,2,2,2]), - (9, 17): (4, [1,-2,1,-2,-2,-2,3,-2,3]), - (9, 18): (4, [-1,-1,-1,-2,1,-2,-2,-2,-3,2,-3]), - (9, 19): (5, [1,-2,1,-2,-2,-3,2,4,-3,4]), - (9, 20): (4, [-1,-1,-1,2,-1,-3,2,-3,-3]), - (9, 21): (5, [1,1,2,-1,2,-3,2,4,-3,4]), - (9, 22): (4, [-1,2,-1,2,-3,2,2,2,-3]), - (9, 23): (4, [-1,-1,-1,-2,1,-2,-2,-3,2,-3,-3]), - (9, 24): (4, [-1,-1,2,-1,-3,2,2,2,-3]), - (9, 25): (5, [-1,-1,2,-1,-3,-2,-2,4,-3,4]), - (9, 26): (4, [1,1,1,-2,1,-2,3,-2,3]), - (9, 27): (4, [-1,-1,2,-1,2,2,-3,2,-3]), - (9, 28): (4, [-1,-1,2,-1,-3,2,2,-3,-3]), - (9, 29): (4, [1,-2,-2,3,-2,1,-2,3,-2]), - (9, 30): (4, [-1,-1,2,2,-1,2,-3,2,-3]), - (9, 31): (4, [-1,-1,2,-1,2,-3,2,-3,-3]), - (9, 32): (4, [1,1,-2,1,-2,1,3,-2,3]), - (9, 33): (4, [-1,2,-1,2,2,-1,-3,2,-3]), - (9, 34): (4, [-1,2,-1,2,-3,2,-1,2,-3]), - (9, 35): (5, [-1,-1,-2,1,-2,-2,-3,2,2,-4,3,-2,-4,-3]), - (9, 36): (4, [1,1,1,-2,1,1,3,-2,3]), - (9, 37): (5, [-1,-1,2,-1,-3,2,1,4,-3,2,-3,4]), - (9, 38): (4, [-1,-1,-2,-2,3,-2,1,-2,-3,-3,-2]), - (9, 39): (5, [1,1,2,-1,-3,-2,1,4,3,-2,3,4]), - (9, 40): (4, [-1,2,-1,-3,2,-1,-3,2,-3]), - (9, 41): (5, [-1,-1,-2,1,3,2,2,-4,-3,2,-3,-4]), - (9, 42): (4, [1,1,1,-2,-1,-1,3,-2,3]), - (9, 43): (4, [1,1,1,2,1,1,-3,2,-3]), - (9, 44): (4, [-1,-1,-1,-2,1,1,3,-2,3]), - (9, 45): (4, [-1,-1,-2,1,-2,-1,-3,2,-3]), - (9, 46): (4, [-1,2,-1,2,-3,-2,1,-2,-3]), - (9, 47): (4, [-1,2,-1,2,3,2,-1,2,3]), - (9, 48): (4, [1,1,2,-1,2,1,-3,2,-1,2,-3]), - (9, 49): (4, [1,1,2,1,1,-3,2,-1,2,3,3]), - (10, 1): (6, [-1,-1,-2,1,-2,-3,2,-3,-4,3,5,-4,5]), - (10, 2): (3, [-1,-1,-1,-1,-1,-1,-1,2,-1,2]), - (10, 3): (6, [-1,-1,-2,1,-2,-3,2,4,-3,4,5,-4,5]), - (10, 4): (5, [-1,-1,-1,2,-1,2,3,-2,3,4,-3,4]), - (10, 5): (3, [1,1,1,1,1,1,-2,1,-2,-2]), - (10, 6): (4, [-1,-1,-1,-1,-1,-1,-2,1,3,-2,3]), - (10, 7): (5, [-1,-1,-2,1,-2,-3,2,-3,-3,4,-3,4]), - (10, 8): (4, [-1,-1,-1,-1,-1,2,-1,2,3,-2,3]), - (10, 9): (3, [1,1,1,1,1,-2,1,-2,-2,-2]), - (10, 10): (5, [-1,-1,2,-1,2,2,3,-2,3,4,-3,4]), - (10, 11): (5, [-1,-1,-1,-1,-2,1,3,-2,3,4,-3,4]), - (10, 12): (4, [1,1,1,1,1,2,-1,-3,2,-3,-3]), - (10, 13): (6, [-1,-1,-2,1,3,-2,-4,3,5,-4,5]), - (10, 14): (4, [-1,-1,-1,-1,-1,-2,1,-2,3,-2,3]), - (10, 15): (4, [1,1,1,1,-2,1,-2,-3,2,-3,-3]), - (10, 16): (5, [1,1,2,-1,2,2,-3,2,-3,-4,3,-4]), - (10, 17): (3, [-1,-1,-1,-1,2,-1,2,2,2,2]), - (10, 18): (5, [-1,-1,-1,-2,1,-2,3,-2,3,4,-3,4]), - (10, 19): (4, [-1,-1,-1,-1,2,-1,2,2,3,-2,3]), - (10, 20): (5, [-1,-1,-1,-1,-2,1,-2,-3,2,4,-3,4]), - (10, 21): (4, [-1,-1,-2,1,-2,-2,-2,-2,3,-2,3]), - (10, 22): (4, [1,1,1,1,2,-1,-3,2,-3,-3,-3]), - (10, 23): (4, [-1,-1,2,-1,2,2,2,2,3,-2,3]), - (10, 24): (5, [-1,-1,-2,1,-2,-2,-2,-3,2,4,-3,4]), - (10, 25): (4, [-1,-1,-1,-1,-2,1,-2,-2,3,-2,3]), - (10, 26): (4, [-1,-1,-1,2,-1,2,2,2,3,-2,3]), - (10, 27): (4, [-1,-1,-1,-1,-2,1,-2,3,-2,3,3]), - (10, 28): (5, [1,1,2,-1,2,2,3,-2,-4,3,-4,-4]), - (10, 29): (5, [-1,-1,-1,2,-1,-3,2,4,-3,4]), - (10, 30): (5, [-1,-1,-2,1,-2,-2,-3,2,-3,4,-3,4]), - (10, 31): (5, [-1,-1,-1,-2,1,3,-2,3,3,4,-3,4]), - (10, 32): (4, [1,1,1,-2,1,-2,-2,-3,2,-3,-3]), - (10, 33): (5, [-1,-1,-2,1,-2,3,-2,3,3,4,-3,4]), - (10, 34): (5, [1,1,1,2,-1,2,3,-2,-4,3,-4,-4]), - (10, 35): (6, [-1,2,-1,2,3,-2,-4,3,5,-4,5]), - (10, 36): (5, [-1,-1,-1,-2,1,-2,-3,2,-3,4,-3,4]), - (10, 37): (5, [-1,-1,-1,-2,1,3,-2,3,4,-3,4,4]), - (10, 38): (5, [-1,-1,-1,-2,1,-2,-2,-3,2,4,-3,4]), - (10, 39): (4, [-1,-1,-1,-2,1,-2,-2,-2,3,-2,3]), - (10, 40): (4, [1,1,1,2,-1,2,2,-3,2,-3,-3]), - (10, 41): (5, [1,-2,1,-2,-2,3,-2,-4,3,-4]), - (10, 42): (5, [-1,-1,2,-1,2,-3,2,4,-3,4]), - (10, 43): (5, [-1,-1,2,-1,-3,2,4,-3,4,4]), - (10, 44): (5, [-1,-1,2,-1,-3,2,-3,4,-3,4]), - (10, 45): (5, [-1,2,-1,2,-3,2,-3,4,-3,4]), - (10, 46): (3, [1,1,1,1,1,-2,1,1,1,-2]), - (10, 47): (3, [1,1,1,1,1,-2,1,1,-2,-2]), - (10, 48): (3, [-1,-1,-1,-1,2,2,-1,2,2,2]), - (10, 49): (4, [-1,-1,-1,-1,2,-1,-3,-2,-2,-2,-3]), - (10, 50): (4, [1,1,2,-1,2,2,-3,2,2,2,-3]), - (10, 51): (4, [1,1,2,-1,2,2,-3,2,2,-3,-3]), - (10, 52): (4, [1,1,1,-2,1,1,-2,-2,-3,2,-3]), - (10, 53): (5, [-1,-1,-2,1,-2,3,-2,-4,-3,-3,-3,-4]), - (10, 54): (4, [1,1,1,-2,1,1,-2,-3,2,-3,-3]), - (10, 55): (5, [-1,-1,-1,-2,1,3,-2,-4,-3,-3,-3,-4]), - (10, 56): (4, [1,1,1,2,-1,2,-3,2,2,2,-3]), - (10, 57): (4, [1,1,1,2,-1,2,-3,2,2,-3,-3]), - (10, 58): (6, [1,-2,1,3,-2,-4,-3,-3,5,-4,5]), - (10, 59): (5, [-1,2,-1,2,-3,2,2,4,-3,4]), - (10, 60): (5, [-1,2,-1,2,2,-3,2,-3,-2,-4,3,-4]), - (10, 61): (4, [1,1,1,-2,1,1,1,-2,-3,2,-3]), - (10, 62): (3, [1,1,1,1,-2,1,1,1,-2,-2]), - (10, 63): (5, [-1,-1,2,-1,-3,-2,-2,-2,-3,-4,3,-4]), - (10, 64): (3, [1,1,1,-2,1,1,1,-2,-2,-2]), - (10, 65): (4, [1,1,2,-1,2,-3,2,2,2,-3,-3]), - (10, 66): (4, [-1,-1,-1,2,-1,-3,-2,-2,-2,-3,-3]), - (10, 67): (5, [-1,-1,-1,-2,1,-2,-3,2,2,4,-3,-2,4,-3]), - (10, 68): (5, [1,1,-2,1,-2,-2,-3,2,2,-4,3,-2,-4,-3]), - (10, 69): (5, [1,1,2,-1,-3,2,1,4,-3,2,-3,4]), - (10, 70): (5, [-1,2,-1,-3,2,2,2,4,-3,4]), - (10, 71): (5, [-1,-1,2,-1,-3,2,2,4,-3,4]), - (10, 72): (4, [1,1,1,1,2,2,-1,2,-3,2,-3]), - (10, 73): (5, [-1,-1,-2,1,-2,-1,3,-2,3,-4,3,-4]), - (10, 74): (5, [-1,-1,-2,1,-2,-2,-3,2,2,4,-3,-2,4,-3]), - (10, 75): (5, [1,-2,1,-2,3,-2,-2,4,-3,2,4,3]), - (10, 76): (4, [1,1,1,1,2,-1,-3,2,2,2,-3]), - (10, 77): (4, [1,1,1,1,2,-1,-3,2,2,-3,-3]), - (10, 78): (5, [-1,-1,-2,1,-2,-1,3,-2,-4,3,-4,-4]), - (10, 79): (3, [-1,-1,-1,2,2,-1,-1,2,2,2]), - (10, 80): (4, [-1,-1,-1,2,-1,-1,-3,-2,-2,-2,-3]), - (10, 81): (5, [1,1,-2,1,3,2,2,-4,-3,-3,-3,-4]), - (10, 82): (3, [-1,-1,-1,-1,2,-1,2,-1,2,2]), - (10, 83): (4, [1,1,2,-1,2,-3,2,2,-3,2,-3]), - (10, 84): (4, [1,1,1,2,-1,-3,2,2,-3,2,-3]), - (10, 85): (3, [-1,-1,-1,-1,2,-1,-1,2,-1,2]), - (10, 86): (4, [-1,-1,2,-1,2,-1,2,2,3,-2,3]), - (10, 87): (4, [1,1,1,2,-1,-3,2,-3,2,-3,-3]), - (10, 88): (5, [-1,2,-1,-3,2,-3,2,4,-3,4]), - (10, 89): (5, [-1,2,-1,2,3,-2,-1,-4,-3,2,-3,-4]), - (10, 90): (4, [-1,-1,2,-1,2,3,-2,-1,3,2,2]), - (10, 91): (3, [-1,-1,-1,2,-1,2,2,-1,2,2]), - (10, 92): (4, [1,1,1,2,2,-3,2,-1,2,-3,2]), - (10, 93): (4, [-1,-1,2,-1,-1,2,-1,2,3,-2,3]), - (10, 94): (3, [1,1,1,-2,1,1,-2,-2,1,-2]), - (10, 95): (4, [-1,-1,2,2,-3,2,-1,2,3,3,2]), - (10, 96): (5, [-1,2,1,-3,2,1,-3,4,-3,2,-3,4]), - (10, 97): (5, [1,1,2,-1,2,1,-3,2,-1,2,3,-4,3,-4]), - (10, 98): (4, [-1,-1,-2,-2,3,-2,1,-2,-2,3,-2]), - (10, 99): (3, [-1,-1,2,-1,-1,2,2,-1,2,2]), - (10, 100): (3, [-1,-1,-1,2,-1,-1,2,-1,-1,2]), - (10, 101): (5, [1,1,1,2,-1,3,-2,1,3,2,2,4,-3,4]), - (10, 102): (4, [-1,-1,2,-1,-3,2,-1,2,2,3,3]), - (10, 103): (4, [-1,-1,-2,1,3,-2,-2,3,-2,-2,3]), - (10, 104): (3, [-1,-1,-1,2,2,-1,2,-1,2,2]), - (10, 105): (5, [1,1,-2,1,3,2,2,-4,-3,2,-3,-4]), - (10, 106): (3, [1,1,1,-2,1,-2,1,1,-2,-2]), - (10, 107): (5, [-1,-1,2,-1,3,2,2,-4,3,-2,3,-4]), - (10, 108): (4, [1,1,-2,1,1,3,-2,1,-2,-3,-3]), - (10, 109): (3, [-1,-1,2,-1,2,2,-1,-1,2,2]), - (10, 110): (5, [-1,2,-1,-3,-2,-2,-2,4,3,-2,3,4]), - (10, 111): (4, [1,1,2,2,-3,2,2,-1,2,-3,2]), - (10, 112): (3, [-1,-1,-1,2,-1,2,-1,2,-1,2]), - (10, 113): (4, [1,1,1,2,-3,2,-1,2,-3,2,-3]), - (10, 114): (4, [-1,-1,-2,1,3,-2,3,-2,3,-2,3]), - (10, 115): (5, [1,-2,1,3,2,2,-4,-3,2,-3,-3,-4]), - (10, 116): (3, [-1,-1,2,-1,-1,2,-1,2,-1,2]), - (10, 117): (4, [1,1,2,2,-3,2,-1,2,-3,2,-3]), - (10, 118): (3, [1,1,-2,1,-2,1,-2,-2,1,-2]), - (10, 119): (4, [-1,-1,2,-1,-3,2,-1,2,3,3,2]), - (10, 120): (5, [-1,-1,-2,1,3,2,-1,-4,-3,-2,-2,-3,-3,-4]), - (10, 121): (4, [-1,-1,-2,3,-2,1,-2,3,-2,3,-2]), - (10, 122): (4, [1,1,2,-3,2,-1,-3,2,-3,2,-3]), - (10, 123): (3, [-1,2,-1,2,-1,2,-1,2,-1,2]), - (10, 124): (3, [1,1,1,1,1,2,1,1,1,2]), - (10, 125): (3, [1,1,1,1,1,-2,-1,-1,-1,-2]), - (10, 126): (3, [-1,-1,-1,-1,-1,-2,1,1,1,-2]), - (10, 127): (3, [-1,-1,-1,-1,-1,-2,1,1,-2,-2]), - (10, 128): (4, [1,1,1,2,1,1,2,2,3,-2,3]), - (10, 129): (4, [1,1,1,-2,-1,-1,3,-2,-1,3,-2]), - (10, 130): (4, [1,1,1,-2,-1,-1,-2,-2,-3,2,-3]), - (10, 131): (4, [-1,-1,-1,-2,1,1,-2,-2,-3,2,-3]), - (10, 132): (4, [1,1,1,-2,-1,-1,-2,-3,2,-3,-3]), - (10, 133): (4, [-1,-1,-1,-2,1,1,-2,-3,2,-3,-3]), - (10, 134): (4, [1,1,1,2,1,1,2,3,-2,3,3]), - (10, 135): (4, [1,1,1,2,-1,2,-3,-2,-2,-2,-3]), - (10, 136): (5, [1,-2,1,-2,-3,2,2,4,-3,4]), - (10, 137): (5, [-1,2,-1,2,-3,-2,-2,4,-3,4]), - (10, 138): (5, [-1,2,-1,2,3,2,2,-4,3,-4]), - (10, 139): (3, [1,1,1,1,2,1,1,1,2,2]), - (10, 140): (4, [1,1,1,-2,-1,-1,-1,-2,-3,2,-3]), - (10, 141): (3, [1,1,1,1,-2,-1,-1,-1,-2,-2]), - (10, 142): (4, [1,1,1,2,1,1,1,2,3,-2,3]), - (10, 143): (3, [-1,-1,-1,-1,-2,1,1,1,-2,-2]), - (10, 144): (4, [-1,-1,-2,1,-2,-1,3,-2,-1,3,2]), - (10, 145): (4, [-1,-1,-2,1,-2,-1,-3,-2,1,-2,-3]), - (10, 146): (4, [-1,-1,2,-1,2,1,-3,2,-1,2,-3]), - (10, 147): (4, [1,1,1,-2,1,-2,-3,2,-1,2,-3]), - (10, 148): (3, [-1,-1,-1,-1,-2,1,1,-2,1,-2]), - (10, 149): (3, [-1,-1,-1,-1,-2,1,-2,1,-2,-2]), - (10, 150): (4, [1,1,1,-2,1,1,3,-2,-1,3,2]), - (10, 151): (4, [1,1,1,2,-1,-1,3,-2,1,3,-2]), - (10, 152): (3, [-1,-1,-1,-2,-2,-1,-1,-2,-2,-2]), - (10, 153): (4, [-1,-1,-1,-2,-1,-1,3,2,2,2,3]), - (10, 154): (4, [1,1,2,-1,2,1,3,2,2,2,3]), - (10, 155): (3, [1,1,1,2,-1,-1,2,-1,-1,2]), - (10, 156): (4, [-1,-1,-1,2,1,1,-3,-2,1,-2,-3]), - (10, 157): (3, [1,1,1,2,2,-1,2,-1,2,2]), - (10, 158): (4, [-1,-1,-1,-2,1,1,3,2,-1,2,3]), - (10, 159): (3, [-1,-1,-1,-2,1,-2,1,1,-2,-2]), - (10, 160): (4, [1,1,1,2,1,1,-3,2,-1,2,-3]), - (10, 161): (3, [-1,-1,-1,-2,1,-2,-1,-1,-2,-2]), - (10, 162): (4, [-1,-1,-2,1,1,-2,-2,-1,3,-2,3]), - (10, 163): (4, [1,1,-2,-1,-1,3,2,-1,2,2,3]), - (10, 164): (4, [1,1,-2,1,-2,-2,-3,2,-1,2,-3]), - (10, 165): (4, [1,1,2,-1,-3,2,-1,2,3,3,2]) + (3, 1): (2, [-1, -1, -1]), + (4, 1): (3, [-1, 2, -1, 2]), + (5, 1): (2, [-1, -1, -1, -1, -1]), + (5, 2): (3, [-1, -1, -1, -2, 1, -2]), + (6, 1): (4, [-1, -1, -2, 1, 3, -2, 3]), + (6, 2): (3, [-1, -1, -1, 2, -1, 2]), + (6, 3): (3, [-1, -1, 2, -1, 2, 2]), + (7, 1): (2, [-1, -1, -1, -1, -1, -1, -1]), + (7, 2): (4, [-1, -1, -1, -2, 1, -2, -3, 2, -3]), + (7, 3): (3, [1, 1, 1, 1, 1, 2, -1, 2]), + (7, 4): (4, [1, 1, 2, -1, 2, 2, 3, -2, 3]), + (7, 5): (3, [-1, -1, -1, -1, -2, 1, -2, -2]), + (7, 6): (4, [-1, -1, 2, -1, -3, 2, -3]), + (7, 7): (4, [1, -2, 1, -2, 3, -2, 3]), + (8, 1): (5, [-1, -1, -2, 1, -2, -3, 2, 4, -3, 4]), + (8, 2): (3, [-1, -1, -1, -1, -1, 2, -1, 2]), + (8, 3): (5, [-1, -1, -2, 1, 3, -2, 3, 4, -3, 4]), + (8, 4): (4, [-1, -1, -1, 2, -1, 2, 3, -2, 3]), + (8, 5): (3, [1, 1, 1, -2, 1, 1, 1, -2]), + (8, 6): (4, [-1, -1, -1, -1, -2, 1, 3, -2, 3]), + (8, 7): (3, [1, 1, 1, 1, -2, 1, -2, -2]), + (8, 8): (4, [1, 1, 1, 2, -1, -3, 2, -3, -3]), + (8, 9): (3, [-1, -1, -1, 2, -1, 2, 2, 2]), + (8, 10): (3, [1, 1, 1, -2, 1, 1, -2, -2]), + (8, 11): (4, [-1, -1, -2, 1, -2, -2, 3, -2, 3]), + (8, 12): (5, [-1, 2, -1, -3, 2, 4, -3, 4]), + (8, 13): (4, [-1, -1, 2, -1, 2, 2, 3, -2, 3]), + (8, 14): (4, [-1, -1, -1, -2, 1, -2, 3, -2, 3]), + (8, 15): (4, [-1, -1, 2, -1, -3, -2, -2, -2, -3]), + (8, 16): (3, [-1, -1, 2, -1, -1, 2, -1, 2]), + (8, 17): (3, [-1, -1, 2, -1, 2, -1, 2, 2]), + (8, 18): (3, [-1, 2, -1, 2, -1, 2, -1, 2]), + (8, 19): (3, [1, 1, 1, 2, 1, 1, 1, 2]), + (8, 20): (3, [1, 1, 1, -2, -1, -1, -1, -2]), + (8, 21): (3, [-1, -1, -1, -2, 1, 1, -2, -2]), + (9, 1): (2, [-1, -1, -1, -1, -1, -1, -1, -1, -1]), + (9, 2): (5, [-1, -1, -1, -2, 1, -2, -3, 2, -3, -4, 3, -4]), + (9, 3): (3, [1, 1, 1, 1, 1, 1, 1, 2, -1, 2]), + (9, 4): (4, [-1, -1, -1, -1, -1, -2, 1, -2, -3, 2, -3]), + (9, 5): (5, [1, 1, 2, -1, 2, 2, 3, -2, 3, 4, -3, 4]), + (9, 6): (3, [-1, -1, -1, -1, -1, -1, -2, 1, -2, -2]), + (9, 7): (4, [-1, -1, -1, -1, -2, 1, -2, -3, 2, -3, -3]), + (9, 8): (5, [-1, -1, 2, -1, 2, 3, -2, -4, 3, -4]), + (9, 9): (3, [-1, -1, -1, -1, -1, -2, 1, -2, -2, -2]), + (9, 10): (4, [1, 1, 2, -1, 2, 2, 2, 2, 3, -2, 3]), + (9, 11): (4, [1, 1, 1, 1, -2, 1, 3, -2, 3]), + (9, 12): (5, [-1, -1, 2, -1, -3, 2, -3, -4, 3, -4]), + (9, 13): (4, [1, 1, 1, 1, 2, -1, 2, 2, 3, -2, 3]), + (9, 14): (5, [1, 1, 2, -1, -3, 2, -3, 4, -3, 4]), + (9, 15): (5, [1, 1, 1, 2, -1, -3, 2, 4, -3, 4]), + (9, 16): (3, [1, 1, 1, 1, 2, 2, -1, 2, 2, 2]), + (9, 17): (4, [1, -2, 1, -2, -2, -2, 3, -2, 3]), + (9, 18): (4, [-1, -1, -1, -2, 1, -2, -2, -2, -3, 2, -3]), + (9, 19): (5, [1, -2, 1, -2, -2, -3, 2, 4, -3, 4]), + (9, 20): (4, [-1, -1, -1, 2, -1, -3, 2, -3, -3]), + (9, 21): (5, [1, 1, 2, -1, 2, -3, 2, 4, -3, 4]), + (9, 22): (4, [-1, 2, -1, 2, -3, 2, 2, 2, -3]), + (9, 23): (4, [-1, -1, -1, -2, 1, -2, -2, -3, 2, -3, -3]), + (9, 24): (4, [-1, -1, 2, -1, -3, 2, 2, 2, -3]), + (9, 25): (5, [-1, -1, 2, -1, -3, -2, -2, 4, -3, 4]), + (9, 26): (4, [1, 1, 1, -2, 1, -2, 3, -2, 3]), + (9, 27): (4, [-1, -1, 2, -1, 2, 2, -3, 2, -3]), + (9, 28): (4, [-1, -1, 2, -1, -3, 2, 2, -3, -3]), + (9, 29): (4, [1, -2, -2, 3, -2, 1, -2, 3, -2]), + (9, 30): (4, [-1, -1, 2, 2, -1, 2, -3, 2, -3]), + (9, 31): (4, [-1, -1, 2, -1, 2, -3, 2, -3, -3]), + (9, 32): (4, [1, 1, -2, 1, -2, 1, 3, -2, 3]), + (9, 33): (4, [-1, 2, -1, 2, 2, -1, -3, 2, -3]), + (9, 34): (4, [-1, 2, -1, 2, -3, 2, -1, 2, -3]), + (9, 35): (5, [-1, -1, -2, 1, -2, -2, -3, 2, 2, -4, 3, -2, -4, -3]), + (9, 36): (4, [1, 1, 1, -2, 1, 1, 3, -2, 3]), + (9, 37): (5, [-1, -1, 2, -1, -3, 2, 1, 4, -3, 2, -3, 4]), + (9, 38): (4, [-1, -1, -2, -2, 3, -2, 1, -2, -3, -3, -2]), + (9, 39): (5, [1, 1, 2, -1, -3, -2, 1, 4, 3, -2, 3, 4]), + (9, 40): (4, [-1, 2, -1, -3, 2, -1, -3, 2, -3]), + (9, 41): (5, [-1, -1, -2, 1, 3, 2, 2, -4, -3, 2, -3, -4]), + (9, 42): (4, [1, 1, 1, -2, -1, -1, 3, -2, 3]), + (9, 43): (4, [1, 1, 1, 2, 1, 1, -3, 2, -3]), + (9, 44): (4, [-1, -1, -1, -2, 1, 1, 3, -2, 3]), + (9, 45): (4, [-1, -1, -2, 1, -2, -1, -3, 2, -3]), + (9, 46): (4, [-1, 2, -1, 2, -3, -2, 1, -2, -3]), + (9, 47): (4, [-1, 2, -1, 2, 3, 2, -1, 2, 3]), + (9, 48): (4, [1, 1, 2, -1, 2, 1, -3, 2, -1, 2, -3]), + (9, 49): (4, [1, 1, 2, 1, 1, -3, 2, -1, 2, 3, 3]), + (10, 1): (6, [-1, -1, -2, 1, -2, -3, 2, -3, -4, 3, 5, -4, 5]), + (10, 2): (3, [-1, -1, -1, -1, -1, -1, -1, 2, -1, 2]), + (10, 3): (6, [-1, -1, -2, 1, -2, -3, 2, 4, -3, 4, 5, -4, 5]), + (10, 4): (5, [-1, -1, -1, 2, -1, 2, 3, -2, 3, 4, -3, 4]), + (10, 5): (3, [1, 1, 1, 1, 1, 1, -2, 1, -2, -2]), + (10, 6): (4, [-1, -1, -1, -1, -1, -1, -2, 1, 3, -2, 3]), + (10, 7): (5, [-1, -1, -2, 1, -2, -3, 2, -3, -3, 4, -3, 4]), + (10, 8): (4, [-1, -1, -1, -1, -1, 2, -1, 2, 3, -2, 3]), + (10, 9): (3, [1, 1, 1, 1, 1, -2, 1, -2, -2, -2]), + (10, 10): (5, [-1, -1, 2, -1, 2, 2, 3, -2, 3, 4, -3, 4]), + (10, 11): (5, [-1, -1, -1, -1, -2, 1, 3, -2, 3, 4, -3, 4]), + (10, 12): (4, [1, 1, 1, 1, 1, 2, -1, -3, 2, -3, -3]), + (10, 13): (6, [-1, -1, -2, 1, 3, -2, -4, 3, 5, -4, 5]), + (10, 14): (4, [-1, -1, -1, -1, -1, -2, 1, -2, 3, -2, 3]), + (10, 15): (4, [1, 1, 1, 1, -2, 1, -2, -3, 2, -3, -3]), + (10, 16): (5, [1, 1, 2, -1, 2, 2, -3, 2, -3, -4, 3, -4]), + (10, 17): (3, [-1, -1, -1, -1, 2, -1, 2, 2, 2, 2]), + (10, 18): (5, [-1, -1, -1, -2, 1, -2, 3, -2, 3, 4, -3, 4]), + (10, 19): (4, [-1, -1, -1, -1, 2, -1, 2, 2, 3, -2, 3]), + (10, 20): (5, [-1, -1, -1, -1, -2, 1, -2, -3, 2, 4, -3, 4]), + (10, 21): (4, [-1, -1, -2, 1, -2, -2, -2, -2, 3, -2, 3]), + (10, 22): (4, [1, 1, 1, 1, 2, -1, -3, 2, -3, -3, -3]), + (10, 23): (4, [-1, -1, 2, -1, 2, 2, 2, 2, 3, -2, 3]), + (10, 24): (5, [-1, -1, -2, 1, -2, -2, -2, -3, 2, 4, -3, 4]), + (10, 25): (4, [-1, -1, -1, -1, -2, 1, -2, -2, 3, -2, 3]), + (10, 26): (4, [-1, -1, -1, 2, -1, 2, 2, 2, 3, -2, 3]), + (10, 27): (4, [-1, -1, -1, -1, -2, 1, -2, 3, -2, 3, 3]), + (10, 28): (5, [1, 1, 2, -1, 2, 2, 3, -2, -4, 3, -4, -4]), + (10, 29): (5, [-1, -1, -1, 2, -1, -3, 2, 4, -3, 4]), + (10, 30): (5, [-1, -1, -2, 1, -2, -2, -3, 2, -3, 4, -3, 4]), + (10, 31): (5, [-1, -1, -1, -2, 1, 3, -2, 3, 3, 4, -3, 4]), + (10, 32): (4, [1, 1, 1, -2, 1, -2, -2, -3, 2, -3, -3]), + (10, 33): (5, [-1, -1, -2, 1, -2, 3, -2, 3, 3, 4, -3, 4]), + (10, 34): (5, [1, 1, 1, 2, -1, 2, 3, -2, -4, 3, -4, -4]), + (10, 35): (6, [-1, 2, -1, 2, 3, -2, -4, 3, 5, -4, 5]), + (10, 36): (5, [-1, -1, -1, -2, 1, -2, -3, 2, -3, 4, -3, 4]), + (10, 37): (5, [-1, -1, -1, -2, 1, 3, -2, 3, 4, -3, 4, 4]), + (10, 38): (5, [-1, -1, -1, -2, 1, -2, -2, -3, 2, 4, -3, 4]), + (10, 39): (4, [-1, -1, -1, -2, 1, -2, -2, -2, 3, -2, 3]), + (10, 40): (4, [1, 1, 1, 2, -1, 2, 2, -3, 2, -3, -3]), + (10, 41): (5, [1, -2, 1, -2, -2, 3, -2, -4, 3, -4]), + (10, 42): (5, [-1, -1, 2, -1, 2, -3, 2, 4, -3, 4]), + (10, 43): (5, [-1, -1, 2, -1, -3, 2, 4, -3, 4, 4]), + (10, 44): (5, [-1, -1, 2, -1, -3, 2, -3, 4, -3, 4]), + (10, 45): (5, [-1, 2, -1, 2, -3, 2, -3, 4, -3, 4]), + (10, 46): (3, [1, 1, 1, 1, 1, -2, 1, 1, 1, -2]), + (10, 47): (3, [1, 1, 1, 1, 1, -2, 1, 1, -2, -2]), + (10, 48): (3, [-1, -1, -1, -1, 2, 2, -1, 2, 2, 2]), + (10, 49): (4, [-1, -1, -1, -1, 2, -1, -3, -2, -2, -2, -3]), + (10, 50): (4, [1, 1, 2, -1, 2, 2, -3, 2, 2, 2, -3]), + (10, 51): (4, [1, 1, 2, -1, 2, 2, -3, 2, 2, -3, -3]), + (10, 52): (4, [1, 1, 1, -2, 1, 1, -2, -2, -3, 2, -3]), + (10, 53): (5, [-1, -1, -2, 1, -2, 3, -2, -4, -3, -3, -3, -4]), + (10, 54): (4, [1, 1, 1, -2, 1, 1, -2, -3, 2, -3, -3]), + (10, 55): (5, [-1, -1, -1, -2, 1, 3, -2, -4, -3, -3, -3, -4]), + (10, 56): (4, [1, 1, 1, 2, -1, 2, -3, 2, 2, 2, -3]), + (10, 57): (4, [1, 1, 1, 2, -1, 2, -3, 2, 2, -3, -3]), + (10, 58): (6, [1, -2, 1, 3, -2, -4, -3, -3, 5, -4, 5]), + (10, 59): (5, [-1, 2, -1, 2, -3, 2, 2, 4, -3, 4]), + (10, 60): (5, [-1, 2, -1, 2, 2, -3, 2, -3, -2, -4, 3, -4]), + (10, 61): (4, [1, 1, 1, -2, 1, 1, 1, -2, -3, 2, -3]), + (10, 62): (3, [1, 1, 1, 1, -2, 1, 1, 1, -2, -2]), + (10, 63): (5, [-1, -1, 2, -1, -3, -2, -2, -2, -3, -4, 3, -4]), + (10, 64): (3, [1, 1, 1, -2, 1, 1, 1, -2, -2, -2]), + (10, 65): (4, [1, 1, 2, -1, 2, -3, 2, 2, 2, -3, -3]), + (10, 66): (4, [-1, -1, -1, 2, -1, -3, -2, -2, -2, -3, -3]), + (10, 67): (5, [-1, -1, -1, -2, 1, -2, -3, 2, 2, 4, -3, -2, 4, -3]), + (10, 68): (5, [1, 1, -2, 1, -2, -2, -3, 2, 2, -4, 3, -2, -4, -3]), + (10, 69): (5, [1, 1, 2, -1, -3, 2, 1, 4, -3, 2, -3, 4]), + (10, 70): (5, [-1, 2, -1, -3, 2, 2, 2, 4, -3, 4]), + (10, 71): (5, [-1, -1, 2, -1, -3, 2, 2, 4, -3, 4]), + (10, 72): (4, [1, 1, 1, 1, 2, 2, -1, 2, -3, 2, -3]), + (10, 73): (5, [-1, -1, -2, 1, -2, -1, 3, -2, 3, -4, 3, -4]), + (10, 74): (5, [-1, -1, -2, 1, -2, -2, -3, 2, 2, 4, -3, -2, 4, -3]), + (10, 75): (5, [1, -2, 1, -2, 3, -2, -2, 4, -3, 2, 4, 3]), + (10, 76): (4, [1, 1, 1, 1, 2, -1, -3, 2, 2, 2, -3]), + (10, 77): (4, [1, 1, 1, 1, 2, -1, -3, 2, 2, -3, -3]), + (10, 78): (5, [-1, -1, -2, 1, -2, -1, 3, -2, -4, 3, -4, -4]), + (10, 79): (3, [-1, -1, -1, 2, 2, -1, -1, 2, 2, 2]), + (10, 80): (4, [-1, -1, -1, 2, -1, -1, -3, -2, -2, -2, -3]), + (10, 81): (5, [1, 1, -2, 1, 3, 2, 2, -4, -3, -3, -3, -4]), + (10, 82): (3, [-1, -1, -1, -1, 2, -1, 2, -1, 2, 2]), + (10, 83): (4, [1, 1, 2, -1, 2, -3, 2, 2, -3, 2, -3]), + (10, 84): (4, [1, 1, 1, 2, -1, -3, 2, 2, -3, 2, -3]), + (10, 85): (3, [-1, -1, -1, -1, 2, -1, -1, 2, -1, 2]), + (10, 86): (4, [-1, -1, 2, -1, 2, -1, 2, 2, 3, -2, 3]), + (10, 87): (4, [1, 1, 1, 2, -1, -3, 2, -3, 2, -3, -3]), + (10, 88): (5, [-1, 2, -1, -3, 2, -3, 2, 4, -3, 4]), + (10, 89): (5, [-1, 2, -1, 2, 3, -2, -1, -4, -3, 2, -3, -4]), + (10, 90): (4, [-1, -1, 2, -1, 2, 3, -2, -1, 3, 2, 2]), + (10, 91): (3, [-1, -1, -1, 2, -1, 2, 2, -1, 2, 2]), + (10, 92): (4, [1, 1, 1, 2, 2, -3, 2, -1, 2, -3, 2]), + (10, 93): (4, [-1, -1, 2, -1, -1, 2, -1, 2, 3, -2, 3]), + (10, 94): (3, [1, 1, 1, -2, 1, 1, -2, -2, 1, -2]), + (10, 95): (4, [-1, -1, 2, 2, -3, 2, -1, 2, 3, 3, 2]), + (10, 96): (5, [-1, 2, 1, -3, 2, 1, -3, 4, -3, 2, -3, 4]), + (10, 97): (5, [1, 1, 2, -1, 2, 1, -3, 2, -1, 2, 3, -4, 3, -4]), + (10, 98): (4, [-1, -1, -2, -2, 3, -2, 1, -2, -2, 3, -2]), + (10, 99): (3, [-1, -1, 2, -1, -1, 2, 2, -1, 2, 2]), + (10, 100): (3, [-1, -1, -1, 2, -1, -1, 2, -1, -1, 2]), + (10, 101): (5, [1, 1, 1, 2, -1, 3, -2, 1, 3, 2, 2, 4, -3, 4]), + (10, 102): (4, [-1, -1, 2, -1, -3, 2, -1, 2, 2, 3, 3]), + (10, 103): (4, [-1, -1, -2, 1, 3, -2, -2, 3, -2, -2, 3]), + (10, 104): (3, [-1, -1, -1, 2, 2, -1, 2, -1, 2, 2]), + (10, 105): (5, [1, 1, -2, 1, 3, 2, 2, -4, -3, 2, -3, -4]), + (10, 106): (3, [1, 1, 1, -2, 1, -2, 1, 1, -2, -2]), + (10, 107): (5, [-1, -1, 2, -1, 3, 2, 2, -4, 3, -2, 3, -4]), + (10, 108): (4, [1, 1, -2, 1, 1, 3, -2, 1, -2, -3, -3]), + (10, 109): (3, [-1, -1, 2, -1, 2, 2, -1, -1, 2, 2]), + (10, 110): (5, [-1, 2, -1, -3, -2, -2, -2, 4, 3, -2, 3, 4]), + (10, 111): (4, [1, 1, 2, 2, -3, 2, 2, -1, 2, -3, 2]), + (10, 112): (3, [-1, -1, -1, 2, -1, 2, -1, 2, -1, 2]), + (10, 113): (4, [1, 1, 1, 2, -3, 2, -1, 2, -3, 2, -3]), + (10, 114): (4, [-1, -1, -2, 1, 3, -2, 3, -2, 3, -2, 3]), + (10, 115): (5, [1, -2, 1, 3, 2, 2, -4, -3, 2, -3, -3, -4]), + (10, 116): (3, [-1, -1, 2, -1, -1, 2, -1, 2, -1, 2]), + (10, 117): (4, [1, 1, 2, 2, -3, 2, -1, 2, -3, 2, -3]), + (10, 118): (3, [1, 1, -2, 1, -2, 1, -2, -2, 1, -2]), + (10, 119): (4, [-1, -1, 2, -1, -3, 2, -1, 2, 3, 3, 2]), + (10, 120): (5, [-1, -1, -2, 1, 3, 2, -1, -4, -3, -2, -2, -3, -3, -4]), + (10, 121): (4, [-1, -1, -2, 3, -2, 1, -2, 3, -2, 3, -2]), + (10, 122): (4, [1, 1, 2, -3, 2, -1, -3, 2, -3, 2, -3]), + (10, 123): (3, [-1, 2, -1, 2, -1, 2, -1, 2, -1, 2]), + (10, 124): (3, [1, 1, 1, 1, 1, 2, 1, 1, 1, 2]), + (10, 125): (3, [1, 1, 1, 1, 1, -2, -1, -1, -1, -2]), + (10, 126): (3, [-1, -1, -1, -1, -1, -2, 1, 1, 1, -2]), + (10, 127): (3, [-1, -1, -1, -1, -1, -2, 1, 1, -2, -2]), + (10, 128): (4, [1, 1, 1, 2, 1, 1, 2, 2, 3, -2, 3]), + (10, 129): (4, [1, 1, 1, -2, -1, -1, 3, -2, -1, 3, -2]), + (10, 130): (4, [1, 1, 1, -2, -1, -1, -2, -2, -3, 2, -3]), + (10, 131): (4, [-1, -1, -1, -2, 1, 1, -2, -2, -3, 2, -3]), + (10, 132): (4, [1, 1, 1, -2, -1, -1, -2, -3, 2, -3, -3]), + (10, 133): (4, [-1, -1, -1, -2, 1, 1, -2, -3, 2, -3, -3]), + (10, 134): (4, [1, 1, 1, 2, 1, 1, 2, 3, -2, 3, 3]), + (10, 135): (4, [1, 1, 1, 2, -1, 2, -3, -2, -2, -2, -3]), + (10, 136): (5, [1, -2, 1, -2, -3, 2, 2, 4, -3, 4]), + (10, 137): (5, [-1, 2, -1, 2, -3, -2, -2, 4, -3, 4]), + (10, 138): (5, [-1, 2, -1, 2, 3, 2, 2, -4, 3, -4]), + (10, 139): (3, [1, 1, 1, 1, 2, 1, 1, 1, 2, 2]), + (10, 140): (4, [1, 1, 1, -2, -1, -1, -1, -2, -3, 2, -3]), + (10, 141): (3, [1, 1, 1, 1, -2, -1, -1, -1, -2, -2]), + (10, 142): (4, [1, 1, 1, 2, 1, 1, 1, 2, 3, -2, 3]), + (10, 143): (3, [-1, -1, -1, -1, -2, 1, 1, 1, -2, -2]), + (10, 144): (4, [-1, -1, -2, 1, -2, -1, 3, -2, -1, 3, 2]), + (10, 145): (4, [-1, -1, -2, 1, -2, -1, -3, -2, 1, -2, -3]), + (10, 146): (4, [-1, -1, 2, -1, 2, 1, -3, 2, -1, 2, -3]), + (10, 147): (4, [1, 1, 1, -2, 1, -2, -3, 2, -1, 2, -3]), + (10, 148): (3, [-1, -1, -1, -1, -2, 1, 1, -2, 1, -2]), + (10, 149): (3, [-1, -1, -1, -1, -2, 1, -2, 1, -2, -2]), + (10, 150): (4, [1, 1, 1, -2, 1, 1, 3, -2, -1, 3, 2]), + (10, 151): (4, [1, 1, 1, 2, -1, -1, 3, -2, 1, 3, -2]), + (10, 152): (3, [-1, -1, -1, -2, -2, -1, -1, -2, -2, -2]), + (10, 153): (4, [-1, -1, -1, -2, -1, -1, 3, 2, 2, 2, 3]), + (10, 154): (4, [1, 1, 2, -1, 2, 1, 3, 2, 2, 2, 3]), + (10, 155): (3, [1, 1, 1, 2, -1, -1, 2, -1, -1, 2]), + (10, 156): (4, [-1, -1, -1, 2, 1, 1, -3, -2, 1, -2, -3]), + (10, 157): (3, [1, 1, 1, 2, 2, -1, 2, -1, 2, 2]), + (10, 158): (4, [-1, -1, -1, -2, 1, 1, 3, 2, -1, 2, 3]), + (10, 159): (3, [-1, -1, -1, -2, 1, -2, 1, 1, -2, -2]), + (10, 160): (4, [1, 1, 1, 2, 1, 1, -3, 2, -1, 2, -3]), + (10, 161): (3, [-1, -1, -1, -2, 1, -2, -1, -1, -2, -2]), + (10, 162): (4, [-1, -1, -2, 1, 1, -2, -2, -1, 3, -2, 3]), + (10, 163): (4, [1, 1, -2, -1, -1, 3, 2, -1, 2, 2, 3]), + (10, 164): (4, [1, 1, -2, 1, -2, -2, -3, 2, -1, 2, -3]), + (10, 165): (4, [1, 1, 2, -1, -3, 2, -1, 2, 3, 3, 2]), } diff --git a/src/sage/knots/knotinfo.py b/src/sage/knots/knotinfo.py index 0e375905e3e..64f6f20fd0c 100644 --- a/src/sage/knots/knotinfo.py +++ b/src/sage/knots/knotinfo.py @@ -350,6 +350,7 @@ class of an oriented pair, `K = (S_3, S_1)`, with `S_i` the concordance inverse, `-K = (-S_3, -S_1)`, and the mirror image, `K^m = (-S_3, S_1)`. """ + itself = 's' reverse = 'r' concordance_inverse = 'c' @@ -783,7 +784,7 @@ def braid_notation(self, original=False): if not braid_notation: # don't forget the unknot - return (1, ) + return (1,) braid_notation = eval_knotinfo(braid_notation) if type(braid_notation) in (list, tuple): @@ -1211,7 +1212,7 @@ def is_almost_alternating(self) -> bool: sage: KnotInfo.K5_2.is_almost_alternating() # optional - database_knotinfo False """ - db._feature.require() # column not available in demo-version + db._feature.require() # column not available in demo-version return knotinfo_bool(self[self.items.almost_alternating]) @cached_method @@ -1224,7 +1225,7 @@ def is_quasi_alternating(self) -> bool: sage: KnotInfo.K5_2.is_quasi_alternating() # optional - database_knotinfo True """ - db._feature.require() # column not available in demo-version + db._feature.require() # column not available in demo-version return knotinfo_bool(self[self.items.quasi_alternating]) @cached_method @@ -1237,7 +1238,7 @@ def is_adequate(self) -> bool: sage: KnotInfo.K5_2.is_adequate() # optional - database_knotinfo True """ - db._feature.require() # column not available in demo-version + db._feature.require() # column not available in demo-version return knotinfo_bool(self[self.items.adequate]) @cached_method @@ -1262,7 +1263,7 @@ def is_quasipositive(self) -> bool: sage: KnotInfo.K5_2.is_quasipositive() # optional - database_knotinfo True """ - db._feature.require() # column not available in demo-version + db._feature.require() # column not available in demo-version return knotinfo_bool(self[self.items.quasipositive]) @cached_method @@ -1275,7 +1276,7 @@ def is_strongly_quasipositive(self) -> bool: sage: KnotInfo.K5_2.is_strongly_quasipositive() # optional - database_knotinfo True """ - db._feature.require() # column not available in demo-version + db._feature.require() # column not available in demo-version return knotinfo_bool(self[self.items.strongly_quasipositive]) @cached_method @@ -1288,7 +1289,7 @@ def is_positive_braid(self) -> bool: sage: KnotInfo.K5_2.is_positive_braid() # optional - database_knotinfo False """ - db._feature.require() # column not available in demo-version + db._feature.require() # column not available in demo-version return knotinfo_bool(self[self.items.positive_braid]) @cached_method @@ -1525,6 +1526,7 @@ def kauffman_polynomial(self, var1='a', var2='z', original=False): return kauffman_polynomial from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + R = LaurentPolynomialRing(ZZ, (var1, var2)) if not kauffman_polynomial and self.crossing_number() == 0: return R.one() @@ -1688,6 +1690,7 @@ def jones_polynomial(self, variab=None, skein_normalization=False, puiseux=False if not variab: variab = 'A' from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + R = LaurentPolynomialRing(ZZ, variab) else: if not variab: @@ -1697,9 +1700,11 @@ def jones_polynomial(self, variab=None, skein_normalization=False, puiseux=False variab = 'x' if puiseux: from sage.rings.puiseux_series_ring import PuiseuxSeriesRing # since PuiseuxPolynomial is not available, so far + R = PuiseuxSeriesRing(ZZ, variab) else: from sage.symbolic.ring import SR + R = SR if not jones_polynomial and self.crossing_number() == 0: @@ -1715,9 +1720,10 @@ def jones_polynomial(self, variab=None, skein_normalization=False, puiseux=False if self.is_knot(): lc = {'t': t} elif puiseux: - lc = {'x': t**(1/2)} + lc = {'x': t ** (1 / 2)} elif use_sqrt: from sage.misc.functional import sqrt + lc = {'x': sqrt(t)} else: lc = {'x': t} @@ -1797,15 +1803,17 @@ def alexander_polynomial(self, var='t', original=False, laurent_poly=False): if laurent_poly: from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + R = LaurentPolynomialRing(ZZ, var) else: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(ZZ, var) if not alexander_polynomial and self.crossing_number() == 0: return R.one() - t, = R.gens() + (t,) = R.gens() lc = {'t': t} ap = R(eval_knotinfo(alexander_polynomial, locals=lc)) if not laurent_poly or ap.is_constant(): @@ -1871,18 +1879,18 @@ def conway_polynomial(self, var='t', original=False): return conway_polynomial from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(ZZ, var) if not conway_polynomial and self.crossing_number() == 0: return R.one() - t, = R.gens() + (t,) = R.gens() lc = {'z': t} return R(eval_knotinfo(conway_polynomial, locals=lc)) @cached_method - def khovanov_polynomial(self, var1='q', var2='t', torsion='T', ring=None, original=False, - reduced=False, odd=False, base_ring=None): + def khovanov_polynomial(self, var1='q', var2='t', torsion='T', ring=None, original=False, reduced=False, odd=False, base_ring=None): r""" Return the Khovanov polynomial according to the value of columns ``khovanov_*`` for this knot or link as an instance of @@ -2012,11 +2020,13 @@ def khovanov_polynomial(self, var1='q', var2='t', torsion='T', ring=None, origin ring = ZZ else: from sage.rings.rational_field import QQ + ring = QQ if base_ring: ring = base_ring from sage.misc.superseded import deprecation + deprecation(40149, "base_ring is deprecated, use argument ring instead.") ch = ring.characteristic() @@ -2056,6 +2066,7 @@ def khovanov_polynomial(self, var1='q', var2='t', torsion='T', ring=None, origin return khovanov_polynomial from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + if integral: var_names = [var1, var2, torsion] else: @@ -2075,6 +2086,7 @@ def khovanov_polynomial(self, var1='q', var2='t', torsion='T', ring=None, origin raise NotImplementedError('Khovanov polynomial not available for this link') from sage.repl.preparse import implicit_mul + # since implicit_mul does not know about the choice of variable names # we have to insert * between them separately for i in ['q', 't', 'T', ')']: @@ -2230,6 +2242,7 @@ def link(self, use_item=db.columns().pd_notation, snappy=False): if self.is_knot() and not snappy: # Construction via Gauss and DT-Code only possible for knots from sage.knots.knot import Knots + if use_item == self.items.dt_notation: return Knots().from_dowker_code(self.dt_notation()) if use_item == self.items.gauss_notation: @@ -2317,6 +2330,7 @@ def is_recoverable(self, unique=True) -> bool: sage: KnotInfo.K12a_165.is_recoverable(unique=False) # optional - database_knotinfo, long time True """ + def recover(sym_mut, braid): r""" Check if ``self`` can be recovered form its associated @@ -2356,6 +2370,7 @@ def check_result(res): return any(check_result(r) for r in res) from sage.misc.misc import some_tuples + if SymmetryMutant.unknown.matches(self): sym_muts = [SymmetryMutant.unknown] else: @@ -2383,6 +2398,7 @@ def inject(self, verbose=True): if verbose: print("Defining %s" % (name)) from sage.repl.user_globals import set_global + set_global(name, self) @cached_method @@ -2441,6 +2457,7 @@ def diagram(self, single=False, new=0, autoraise=True): True """ import webbrowser + if self.is_knot(): filename = db.filename.knots else: @@ -2467,6 +2484,7 @@ def knot_atlas_webpage(self, new=0, autoraise=True): True """ import webbrowser + return webbrowser.open(self[self.items.knot_atlas_anon], new=new, autoraise=autoraise) def knotilus_webpage(self, new=0, autoraise=True): @@ -2486,6 +2504,7 @@ def knotilus_webpage(self, new=0, autoraise=True): True """ import webbrowser + return webbrowser.open(self[self.items.knotilus_page_anon], new=new, autoraise=autoraise) @@ -2712,6 +2731,7 @@ def __getitem__(self, item): [, , ] """ from sage.rings.integer import Integer + if type(item) not in (int, Integer): raise ValueError('item must be an integer') l = self.list() @@ -2755,6 +2775,7 @@ def __call__(self, item): return self[item] from sage.rings.integer import Integer + if type(item) not in (int, Integer): raise ValueError('item must be an integer') l = self.list() @@ -2762,7 +2783,7 @@ def __call__(self, item): if item < 1 or item > max_item: raise ValueError('item must be positive and smaller than %s' % (max_item)) - return l[item-1] + return l[item - 1] def _name(self): r""" @@ -2826,6 +2847,7 @@ def is_recoverable(self, unique=True, max_samples=8) -> bool: True """ from sage.misc.misc import some_tuples + l = self.list(oriented=True) bound = len(l) return all(L.is_recoverable(unique=unique) for L, in some_tuples(l, 1, bound, max_samples=max_samples)) @@ -2879,6 +2901,7 @@ def inject(self, verbose=True): if verbose: print("Defining %s" % (name)) from sage.repl.user_globals import set_global + set_global(name, self) diff --git a/src/sage/knots/link.py b/src/sage/knots/link.py index 98a211bdc15..fadc27d9731 100644 --- a/src/sage/knots/link.py +++ b/src/sage/knots/link.py @@ -385,6 +385,7 @@ def __init__(self, data): # construct from instances of external packages from_external = False from sage.interfaces.interface import InterfaceElement + if isinstance(data, InterfaceElement): L = data.sage() if isinstance(L, Link): @@ -557,6 +558,7 @@ def fundamental_group(self, presentation='wirtinger', algorithm=None): """ if algorithm: from sage.interfaces.regina import regina + if isinstance(algorithm, regina._object_class()): if not isinstance(algorithm._inst, regina.AlgorithmExt._name): raise TypeError('algorithm must be of type %s' % regina.AlgorithmExt._name) @@ -569,6 +571,7 @@ def fundamental_group(self, presentation='wirtinger', algorithm=None): return Lr.complement().group().sage() raise ValueError('algorithm %s is not supported' % algorithm) from sage.groups.free_group import FreeGroup + if presentation == 'braid': b = self.braid() F = FreeGroup(b.strands()) @@ -739,6 +742,7 @@ def braid(self, remove_loops=False): return self._braid from sage.groups.braid import BraidGroup + comp = self._isolated_components() if len(comp) > 1: L1 = Link(comp[0]) @@ -1170,7 +1174,7 @@ def _enhanced_states(self): ncross = len(crossings) smoothings = [] nmax = max(flatten(crossings)) + 1 - for i in range(2 ** ncross): + for i in range(2**ncross): v = Integer(i).bits() v = v + (ncross - len(v)) * [0] G = Graph() @@ -1188,8 +1192,7 @@ def _enhanced_states(self): G.add_edge((cr[0], cr[3], n), cr[3]) G.add_edge((cr[2], cr[1], n), cr[2]) G.add_edge((cr[2], cr[1], n), cr[1]) - sm = set(tuple(sorted(x for x in b if isinstance(x, tuple))) - for b in G.connected_components(sort=False)) + sm = set(tuple(sorted(x for x in b if isinstance(x, tuple))) for b in G.connected_components(sort=False)) iindex = (writhe - ncross + 2 * sum(v)) // 2 jmin = writhe + iindex - len(sm) jmax = writhe + iindex + len(sm) @@ -1247,10 +1250,12 @@ def _khovanov_homology_cached(self, height, implementation, ring=ZZ, **kwds): if implementation == 'Khoca': from sage.interfaces.khoca import khoca_raw_data + raw_data = khoca_raw_data(self, ring, **kwds) data = {(d, t): raw_data[(h, d, t)] for (h, d, t) in raw_data if h == height} from sage.homology.homology_group import HomologyGroup + if not data: return [(0, HomologyGroup(0, ring))] @@ -1260,7 +1265,7 @@ def _khovanov_homology_cached(self, height, implementation, ring=ZZ, **kwds): invfac[d] = [] for t in torsion: if (d, t) in data: - invfac[d] += [t]*data[(d, t)] + invfac[d] += [t] * data[(d, t)] res = [] for d in invfac: ifac = sorted(invfac[d]) @@ -1268,8 +1273,7 @@ def _khovanov_homology_cached(self, height, implementation, ring=ZZ, **kwds): return tuple(sorted(res)) ncross = len(crossings) - states = [(_0, set(_1), set(_2), _3, _4) - for (_0, _1, _2, _3, _4) in self._enhanced_states()] + states = [(_0, set(_1), set(_2), _3, _4) for (_0, _1, _2, _3, _4) in self._enhanced_states()] bases = {} # arrange them by (i,j) for st in states: i, j = st[3], st[4] @@ -1287,10 +1291,9 @@ def _khovanov_homology_cached(self, height, implementation, ring=ZZ, **kwds): for jj in range(m.ncols()): V2 = bases[(i + 1, j)][jj] V20 = V2[0] - difs = [index for index, value in enumerate(V1[0]) - if value != V20[index]] + difs = [index for index, value in enumerate(V1[0]) if value != V20[index]] if len(difs) == 1 and not (V2[2].intersection(V1[1]) or V2[1].intersection(V1[2])): - m[ii, jj] = (-1)**sum(V2[0][x] for x in range(difs[0] + 1, ncross)) + m[ii, jj] = (-1) ** sum(V2[0][x] for x in range(difs[0] + 1, ncross)) # Here we have the matrix constructed, now we have to put it in the dictionary of complexes else: m = matrix(ring, len(bij), 0) @@ -1409,6 +1412,7 @@ def khovanov_homology(self, ring=ZZ, height=None, degree=None, implementation='n if implementation == 'Khoca': khoca = True from sage.interfaces.khoca import check_kwds + check_kwds(**kwds) elif implementation != 'native': raise ValueError('%s is not a recognized implementation') @@ -1417,8 +1421,8 @@ def khovanov_homology(self, ring=ZZ, height=None, degree=None, implementation='n if not self.pd_code(): # special case for the unknot with no crossings from sage.homology.homology_group import HomologyGroup - homs = {-1: {0: HomologyGroup(1, ring, [0])}, - 1: {0: HomologyGroup(1, ring, [0])}} + + homs = {-1: {0: HomologyGroup(1, ring, [0])}, 1: {0: HomologyGroup(1, ring, [0])}} if height is not None: if height not in homs: return {} @@ -1433,6 +1437,7 @@ def khovanov_homology(self, ring=ZZ, height=None, degree=None, implementation='n heights = sorted(set(state[-1] for state in self._enhanced_states())) if khoca: from sage.interfaces.khoca import khoca_raw_data + raw_data = khoca_raw_data(self, ring, **kwds) heights = sorted(set(k[0] for k in raw_data)) if degree is not None: @@ -1602,11 +1607,9 @@ def pd_code(self): crossing_dic = {} for i, x in enumerate(oriented_gauss_code[1]): if x == -1: - crossing_dic[i + 1] = [d_dic[-(i + 1)][0], d_dic[i + 1][0], - d_dic[-(i + 1)][1], d_dic[i + 1][1]] + crossing_dic[i + 1] = [d_dic[-(i + 1)][0], d_dic[i + 1][0], d_dic[-(i + 1)][1], d_dic[i + 1][1]] elif x == 1: - crossing_dic[i + 1] = [d_dic[-(i + 1)][0], d_dic[i + 1][1], - d_dic[-(i + 1)][1], d_dic[i + 1][0]] + crossing_dic[i + 1] = [d_dic[-(i + 1)][0], d_dic[i + 1][1], d_dic[-(i + 1)][1], d_dic[i + 1][0]] elif len(oriented_gauss_code[0]) == 1: for i, j in enumerate(oriented_gauss_code[0][0]): d_dic[j] = [i + 1, i + 2] @@ -1614,11 +1617,9 @@ def pd_code(self): crossing_dic = {} for i, x in enumerate(oriented_gauss_code[1]): if x == -1: - crossing_dic[i + 1] = [d_dic[-(i + 1)][0], d_dic[i + 1][0], - d_dic[-(i + 1)][1], d_dic[i + 1][1]] + crossing_dic[i + 1] = [d_dic[-(i + 1)][0], d_dic[i + 1][0], d_dic[-(i + 1)][1], d_dic[i + 1][1]] elif x == 1: - crossing_dic[i + 1] = [d_dic[-(i + 1)][0], d_dic[i + 1][1], - d_dic[-(i + 1)][1], d_dic[i + 1][0]] + crossing_dic[i + 1] = [d_dic[-(i + 1)][0], d_dic[i + 1][1], d_dic[-(i + 1)][1], d_dic[i + 1][0]] else: crossing_dic = {} @@ -1633,11 +1634,9 @@ def pd_code(self): strings_max = strings[-1] for i in b: if i > 0: - pd.append( - [strings[i], strings_max + 2, strings_max + 1, strings[i - 1]]) + pd.append([strings[i], strings_max + 2, strings_max + 1, strings[i - 1]]) else: - pd.append( - [strings[abs(i) - 1], strings[abs(i)], strings_max + 2, strings_max + 1]) + pd.append([strings[abs(i) - 1], strings[abs(i)], strings_max + 2, strings_max + 1]) strings[abs(i) - 1] = strings_max + 1 strings[abs(i)] = strings_max + 2 strings_max = strings_max + 2 @@ -1711,8 +1710,7 @@ def dowker_notation(self): """ pd = self.pd_code() orient = self.orientation() - dn = [(i[0], i[1]) if orient[j] == -1 else (i[0], i[3]) - for j, i in enumerate(pd)] + dn = [(i[0], i[1]) if orient[j] == -1 else (i[0], i[3]) for j, i in enumerate(pd)] return dn def _braid_word_components(self): @@ -2060,6 +2058,7 @@ def omega_signature(self, omega): -2 """ from sage.rings.qqbar import QQbar + omega = QQbar(omega) V = self.seifert_matrix() m = (1 - omega) * V + (1 - omega.conjugate()) * V.transpose() @@ -2182,7 +2181,7 @@ def conway_polynomial(self): t = L.gen() alex = alex(t**2) exp = alex.exponents() - alex = t**((-max(exp) - min(exp)) // 2) * alex + alex = t ** ((-max(exp) - min(exp)) // 2) * alex conway = R.zero() t_poly = R.gen() @@ -2194,8 +2193,7 @@ def conway_polynomial(self): conway += coeff * t_poly**M return conway - def khovanov_polynomial(self, var1='q', var2='t', torsion='T', ring=ZZ, - base_ring=None, implementation='native', **kwds): + def khovanov_polynomial(self, var1='q', var2='t', torsion='T', ring=ZZ, base_ring=None, implementation='native', **kwds): r""" Return the Khovanov polynomial of ``self``. @@ -2275,6 +2273,7 @@ def khovanov_polynomial(self, var1='q', var2='t', torsion='T', ring=ZZ, if base_ring: ring = base_ring from sage.misc.superseded import deprecation + deprecation(40149, "base_ring is deprecated, use argument ring instead.") ch = ring.characteristic() @@ -2287,6 +2286,7 @@ def khovanov_polynomial(self, var1='q', var2='t', torsion='T', ring=ZZ, coeff = {} kh = self.khovanov_homology(ring=ring, implementation=implementation, **kwds) from sage.rings.infinity import infinity + for h in kh: for d in kh[h]: H = kh[h][d] @@ -2410,8 +2410,7 @@ def is_alternating(self) -> bool: if not x: return True s = [Integer(i).sign() for i in x[0]] - return (s == [(-1) ** (i + 1) for i in range(len(x[0]))] - or s == [(-1) ** i for i in range(len(x[0]))]) + return s == [(-1) ** (i + 1) for i in range(len(x[0]))] or s == [(-1) ** i for i in range(len(x[0]))] def orientation(self): r""" @@ -2493,8 +2492,7 @@ def seifert_circles(self): pd = self.pd_code() available_segments = set(flatten(pd)) # detect looped segments. They must be their own Seifert circles - result = [[a] for a in available_segments - if any(C.count(a) > 1 for C in pd)] + result = [[a] for a in available_segments if any(C.count(a) > 1 for C in pd)] # remove the looped segments from the available for a in result: @@ -3006,7 +3004,7 @@ def jones_polynomial(self, variab=None, skein_normalization=False, algorithm='jo poly = self._bracket() t = poly.parent().gens()[0] writhe = self.writhe() - jones = poly * (-t)**(-3 * writhe) + jones = poly * (-t) ** (-3 * writhe) # Switch to the variable A to have the result agree with the output # of the jonesrep algorithm A = LaurentPolynomialRing(ZZ, 'A').gen() @@ -3019,7 +3017,7 @@ def jones_polynomial(self, variab=None, skein_normalization=False, algorithm='jo if variab is None: variab = 't' # We force the result to be in the symbolic ring because of the expand - return jones(SR(variab)**(ZZ.one() / ZZ(4))).expand() + return jones(SR(variab) ** (ZZ.one() / ZZ(4))).expand() if algorithm == 'jonesrep': braid = self.braid() # Special case for the trivial knot with no crossings @@ -3055,36 +3053,36 @@ def _bracket(self): return t.parent().one() if len(pd_code) == 1: if pd_code[0][0] == pd_code[0][3]: - return -t**(-3) - return -t**3 + return -(t ** (-3)) + return -(t**3) cross = pd_code[0] rest = [list(vertex) for vertex in pd_code[1:]] a, b, c, d = cross if a == d and c == b and rest: - return (~t + t**(-5)) * Link(rest)._bracket() + return (~t + t ** (-5)) * Link(rest)._bracket() if a == b and c == d and len(rest) > 0: return (t + t**5) * Link(rest)._bracket() if a == d: for cross in rest: if b in cross: cross[cross.index(b)] = c - return -t**(-3) * Link(rest)._bracket() + return -(t ** (-3)) * Link(rest)._bracket() if a == b: for cross in rest: if c in cross: cross[cross.index(c)] = d - return -t**3 * Link(rest)._bracket() + return -(t**3) * Link(rest)._bracket() if c == d: for cross in rest: if b in cross: cross[cross.index(b)] = a - return -t**3 * Link(rest)._bracket() + return -(t**3) * Link(rest)._bracket() if c == b: for cross in rest: if d in cross: cross[cross.index(d)] = a - return -t**(-3) * Link(rest)._bracket() + return -(t ** (-3)) * Link(rest)._bracket() rest_2 = [list(vertex) for vertex in rest] for cross in rest: if b in cross: @@ -3121,8 +3119,7 @@ def _isolated_components(self): for j in range(i + 1, len(V)): if setV[i].intersection(setV[j]): G.add_edge(V[i], V[j]) - return [[list(i) for i in j] - for j in G.connected_components(sort=False)] + return [[list(i) for i in j] for j in G.connected_components(sort=False)] @cached_method(key=lambda s, v1, v2, n, a: (s, v1, v2, n)) def homfly_polynomial(self, var1=None, var2=None, normalization='lm', algorithm=None): @@ -3315,6 +3312,7 @@ def homfly_polynomial(self, var1=None, var2=None, normalization='lm', algorithm= if algorithm: from sage.interfaces.regina import regina + if isinstance(algorithm, regina._object_class()): if not isinstance(algorithm._inst, regina.Algorithm._name): raise TypeError('algorithm must be of type %s' % regina.Algorithm._name) @@ -3350,6 +3348,7 @@ def homfly_polynomial(self, var1=None, var2=None, normalization='lm', algorithm= for i, cr in enumerate(ogc[1]): s += ' {} {}'.format(i, cr) from sage.libs.homfly import homfly_polynomial_dict + dic = homfly_polynomial_dict(s) if normalization == 'lm': return L(dic) @@ -3421,6 +3420,7 @@ def _coloring_matrix(self, n=None): if not n: n = self.determinant() from sage.rings.finite_rings.integer_mod_ring import IntegerModRing + R = IntegerModRing(n) arcs = self.arcs(presentation='pd') di = len(arcs) @@ -3546,6 +3546,7 @@ def colorings(self, n=None): .. SEEALSO:: :meth:`is_colorable` and :meth:`coloring_maps` """ from sage.modules.free_module import FreeModule + M = self._coloring_matrix(n=n) KM = M.right_kernel_matrix() F = FreeModule(M.base_ring(), KM.dimensions()[0]) @@ -3556,8 +3557,7 @@ def colorings(self, n=None): colors = sorted(set(coloring)) if len(colors) >= 2: res.add(tuple(coloring)) - return [{tuple(arc): col for arc, col in zip(arcs, c)} - for c in sorted(res)] + return [{tuple(arc): col for arc, col in zip(arcs, c)} for c in sorted(res)] def coloring_maps(self, n=None, finitely_presented=False): r""" @@ -3634,9 +3634,11 @@ def coloring_maps(self, n=None, finitely_presented=False): if finitely_presented: from sage.groups.finitely_presented_named import DihedralPresentation + D = DihedralPresentation(n) else: from sage.groups.perm_gps.permgroup_named import DihedralGroup + D = DihedralGroup(n) a, b = D.gens() @@ -3649,8 +3651,7 @@ def coloring_maps(self, n=None, finitely_presented=False): maps.append(gr.hom(ims)) return maps - def plot(self, gap=0.1, component_gap=0.5, solver=None, - color='blue', **kwargs): + def plot(self, gap=0.1, component_gap=0.5, solver=None, color='blue', **kwargs): r""" Plot ``self``. @@ -3831,6 +3832,7 @@ def plot(self, gap=0.1, component_gap=0.5, solver=None, coloring = {int(i): color for i in set(flatten(pd_code))} else: from sage.plot.colors import rainbow + ncolors = max([int(i) for i in color.values()]) + 1 arcs = self.arcs() rainb = rainbow(ncolors) @@ -3918,8 +3920,7 @@ def flow_to_sink(e): values = MLP.get_values(v, convert=ZZ, tolerance=1e-3) s = [values[2 * i] - values[2 * i + 1] for i in range(len(edges))] # segments represents the different parts of the previous edges after bending - segments = {e: [(e, i) for i in range(abs(s[edges.index(e)]) + 1)] - for e in edges} + segments = {e: [(e, i) for i in range(abs(s[edges.index(e)]) + 1)] for e in edges} pieces = {tuple(i): [i] for j in segments.values() for i in j} nregions = [] for r in regions[:-1]: # interior regions @@ -3953,8 +3954,7 @@ def flow_to_sink(e): else: b += 1 c += badregion[b][1] - otherregion = [nr for nr in nregions - if any(badregion[b][0] == x[0] for x in nr)] + otherregion = [nr for nr in nregions if any(badregion[b][0] == x[0] for x in nr)] if len(otherregion) == 1: otherregion = None elif otherregion[0] == badregion: @@ -3967,8 +3967,7 @@ def flow_to_sink(e): segments.append(N1) segments.append(N2) if type(badregion[b][0]) in (int, Integer): - segmenttoadd = [x for x in pieces - if badregion[b][0] in pieces[x]] + segmenttoadd = [x for x in pieces if badregion[b][0] in pieces[x]] if len(segmenttoadd) > 0: pieces[segmenttoadd[0]].append(N2) else: @@ -3976,10 +3975,10 @@ def flow_to_sink(e): if a < b: r1 = badregion[:a] + [[badregion[a][0], 0], [N1, 1]] + badregion[b:] - r2 = badregion[a + 1:b] + [[N2, 1], [N1, 1]] + r2 = badregion[a + 1 : b] + [[N2, 1], [N1, 1]] else: r1 = badregion[b:a] + [[badregion[a][0], 0], [N1, 1]] - r2 = badregion[:b] + [[N2, 1], [N1, 1]] + badregion[a + 1:] + r2 = badregion[:b] + [[N2, 1], [N1, 1]] + badregion[a + 1 :] if otherregion: c = [x for x in otherregion if badregion[b][0] == x[0]] @@ -4046,7 +4045,7 @@ def flow_to_sink(e): if c.index(e) == 0 or (c.index(e) == 3 and orien == 1) or (c.index(e) == 1 and orien == -1): turn = -turn lengthse.reverse() - tailshort = (c.index(e) % 2 == 0) + tailshort = c.index(e) % 2 == 0 x0 = crossings[c][0] y0 = crossings[c][1] im = [] @@ -4076,7 +4075,7 @@ def flow_to_sink(e): if not c2: headshort = not tailshort else: - headshort = (c2[0].index(e) % 2 == 0) + headshort = c2[0].index(e) % 2 == 0 a = deepcopy(im[0][0]) b = deepcopy(im[-1][0]) @@ -4100,7 +4099,7 @@ def delta(u, v): l = bezier_path([[im[0][0][0], im[0][0][1], im[-1][0][0], im[-1][0][1]]], **kwargs) p = im[-1][0][1] else: - while c < len(im)-1: + while c < len(im) - 1: if im[c][1] > 1: (a, b) = im[c][0] if b[0] > a[0]: @@ -4113,23 +4112,21 @@ def delta(u, v): e = [b[0], b[1] + 1] l += line((p, e), **kwargs) p = e - if im[c+1][1] == 1 and c < len(im) - 2: - xr = round(im[c+2][0][1][0]) - yr = round(im[c+2][0][1][1]) - xp = xr - im[c+2][0][1][0] - yp = yr - im[c+2][0][1][1] - q = [p[0] + im[c+1][0][1][0] - im[c+1][0][0][0] - xp, - p[1] + im[c+1][0][1][1] - im[c+1][0][0][1] - yp] - l += bezier_path([[p, im[c+1][0][0], im[c+1][0][1], q]], **kwargs) + if im[c + 1][1] == 1 and c < len(im) - 2: + xr = round(im[c + 2][0][1][0]) + yr = round(im[c + 2][0][1][1]) + xp = xr - im[c + 2][0][1][0] + yp = yr - im[c + 2][0][1][1] + q = [p[0] + im[c + 1][0][1][0] - im[c + 1][0][0][0] - xp, p[1] + im[c + 1][0][1][1] - im[c + 1][0][0][1] - yp] + l += bezier_path([[p, im[c + 1][0][0], im[c + 1][0][1], q]], **kwargs) c += 2 p = q else: - if im[c+1][1] == 1: - q = im[c+1][0][1] + if im[c + 1][1] == 1: + q = im[c + 1][0][1] else: - q = [im[c+1][0][0][0] + sign(im[c+1][0][1][0] - im[c+1][0][0][0]), - im[c+1][0][0][1] + sign(im[c+1][0][1][1] - im[c+1][0][0][1])] - l += bezier_path([[p, im[c+1][0][0], q]], **kwargs) + q = [im[c + 1][0][0][0] + sign(im[c + 1][0][1][0] - im[c + 1][0][0][0]), im[c + 1][0][0][1] + sign(im[c + 1][0][1][1] - im[c + 1][0][0][1])] + l += bezier_path([[p, im[c + 1][0][0], q]], **kwargs) p = q c += 1 l += line([p, im[-1][0][1]], **kwargs) @@ -4189,17 +4186,17 @@ def _markov_move_cmp(self, braid): # if the braid of self has more strands we have to perform # Markov II moves B = sb.parent() - g = B.gen(ob_ind-1) + g = B.gen(ob_ind - 1) ob = B(ob) - if sb_ind > ob_ind+1: + if sb_ind > ob_ind + 1: # proceed by recursion - res = self._markov_move_cmp(ob*g) + res = self._markov_move_cmp(ob * g) if not res: - res = self._markov_move_cmp(ob*~g) + res = self._markov_move_cmp(ob * ~g) else: - res = sb.is_conjugated(ob*g) + res = sb.is_conjugated(ob * g) if not res: - res = sb.is_conjugated(ob*~g) + res = sb.is_conjugated(ob * ~g) return res L = Link(ob) return L._markov_move_cmp(sb) @@ -4233,6 +4230,7 @@ def _knotinfo_matching_list(self): ([], False) """ from sage.knots.knotinfo import KnotInfoSeries + pd_code = self.pd_code() cr = len(pd_code) co = self.number_of_components() @@ -4275,7 +4273,7 @@ def _knotinfo_matching_list(self): br_ind = br.strands() def cmp_braid(b): - if (b.strands() <= br_ind): + if b.strands() <= br_ind: return self._markov_move_cmp(b) return False @@ -4326,6 +4324,7 @@ def _knotinfo_matching_dict(self): : False}) """ from sage.knots.knotinfo import SymmetryMutant + mutant = {} mutant[SymmetryMutant.itself] = self mutant[SymmetryMutant.reverse] = self.reverse() @@ -4652,6 +4651,7 @@ def find_mutant(proved=True): if L.is_knot(): from sage.knots.free_knotinfo_monoid import FreeKnotInfoMonoid + FKIM = FreeKnotInfoMonoid() return FKIM((L, sym_mut)) @@ -4708,6 +4708,7 @@ def answer_list(l): # sum of K4_1 and K5_2 in the doctest of :meth:`_knotinfo_matching_list`) # Therefor we calculate it directly in the free KnotInfo monoid from sage.knots.free_knotinfo_monoid import FreeKnotInfoMonoid + FKIM = FreeKnotInfoMonoid() return FKIM.from_knot(self, unique=unique) @@ -4753,6 +4754,7 @@ def answer_list(l): if not l: from sage.features.databases import DatabaseKnotInfo + DatabaseKnotInfo().require() return l @@ -4839,6 +4841,7 @@ def is_isotopic(self, other) -> bool: sage: set_verbose(0) """ from sage.misc.verbose import verbose + if not isinstance(other, Link): verbose('other is not a link') return False @@ -4960,6 +4963,7 @@ def simplify(self, exhaustive=True, height=1, threads=1): Knot represented by 11 crossings """ from sage.interfaces.regina import regina + rL = regina(self) if self.is_knot() and exhaustive: res = rL.simplifyExhaustive(height=height, threads=threads) diff --git a/src/sage/lfunctions/dokchitser.py b/src/sage/lfunctions/dokchitser.py index f0f10234067..11a7b852318 100644 --- a/src/sage/lfunctions/dokchitser.py +++ b/src/sage/lfunctions/dokchitser.py @@ -183,8 +183,7 @@ class Dokchitser(SageObject): __globals_re = None __instance = 0 # Monotonically increasing unique instance ID __n_instances = 0 # Number of currently allocated instances - __template_filename = os.path.join(SAGE_EXTCODE, 'pari', 'dokchitser', - 'computel.gp.template') + __template_filename = os.path.join(SAGE_EXTCODE, 'pari', 'dokchitser', 'computel.gp.template') __init = False def __new__(cls, *args, **kwargs): @@ -194,9 +193,7 @@ def __new__(cls, *args, **kwargs): cls.__instance += 1 return inst - def __init__(self, conductor, gammaV, weight, eps, - poles=None, residues='automatic', prec=53, - init=None): + def __init__(self, conductor, gammaV, weight, eps, poles=None, residues='automatic', prec=53, init=None): """ Initialization of Dokchitser calculator EXAMPLES:: @@ -221,11 +218,10 @@ def __reduce__(self): D = copy.copy(self.__dict__) if '_Dokchitser__gp' in D: del D['_Dokchitser__gp'] - return reduce_load_dokchitser, (D, ) + return reduce_load_dokchitser, (D,) def _repr_(self) -> str: - return "Dokchitser L-series of conductor %s and weight %s" % ( - self.conductor, self.weight) + return "Dokchitser L-series of conductor %s and weight %s" % (self.conductor, self.weight) def __del__(self): self._teardown_gp(self.__instance) @@ -246,6 +242,7 @@ def gp(self): template = string.Template(tf.read()) from tempfile import NamedTemporaryFile + with NamedTemporaryFile(suffix='.gp', mode='w+t') as f: f.write(template.substitute(i=str(self.__instance))) f.flush() @@ -263,9 +260,9 @@ def gp(self): @classmethod def _instantiate_gp(cls): from sage.env import DOT_SAGE + logfile = os.path.join(DOT_SAGE, 'dokchitser.log') - cls.__gp = sage.interfaces.gp.Gp(script_subdirectory='dokchitser', - logfile=logfile) + cls.__gp = sage.interfaces.gp.Gp(script_subdirectory='dokchitser', logfile=logfile) # Read the script template and parse out all indexed global variables # (easy because they all end in "_$i" and there's nothing else in the # script that uses $) @@ -275,8 +272,7 @@ def _instantiate_gp(cls): for m in global_re.finditer(line): cls.__globals.add(m.group(1)) - cls.__globals_re = re.compile( - '([^a-zA-Z0-9_]|^)(%s)([^a-zA-Z0-9_]|$)' % '|'.join(cls.__globals)) + cls.__globals_re = re.compile('([^a-zA-Z0-9_]|^)(%s)([^a-zA-Z0-9_]|$)' % '|'.join(cls.__globals)) @classmethod def _teardown_gp(cls, instance=None): @@ -297,8 +293,7 @@ def _gp_call_inst(self, func, *args): ``self.gp().eval('L_N(1)')`` where ``N`` is ``self.__instance``. """ - cmd = '%s_%d(%s)' % (func, self.__instance, - ','.join(str(a) for a in args)) + cmd = '%s_%d(%s)' % (func, self.__instance, ','.join(str(a) for a in args)) return self._gp_eval(cmd) def _gp_set_inst(self, varname, value): @@ -368,11 +363,7 @@ def cost(self, T=1): num_coeffs = cost - def init_coeffs(self, v, cutoff=1, - w=None, - pari_precode='', - max_imaginary_part=0, - max_asymp_coeffs=40): + def init_coeffs(self, v, cutoff=1, w=None, pari_precode='', max_imaginary_part=0, max_asymp_coeffs=40): """ Set the coefficients `a_n` of the `L`-series. @@ -439,8 +430,7 @@ def init_coeffs(self, v, cutoff=1, self._instantiate_gp() def repl(m): - return '%s%s_%d%s' % (m.group(1), m.group(2), self.__instance, - m.group(3)) + return '%s%s_%d%s' % (m.group(1), m.group(2), self.__instance, m.group(3)) # If any of the pre-code contains references to some of the # templated global variables we must replace those as well @@ -466,10 +456,8 @@ def repl(m): else: w = ','.join(CC(a)._pari_init_() for a in w) self._gp_eval('Bvec = [%s]' % w) - self._gp_call_inst('initLdata', '"Avec[k]"', cutoff, - '"Bvec[k]"') - self.__init = (v, cutoff, w, pari_precode, max_imaginary_part, - max_asymp_coeffs) + self._gp_call_inst('initLdata', '"Avec[k]"', cutoff, '"Bvec[k]"') + self.__init = (v, cutoff, w, pari_precode, max_imaginary_part, max_asymp_coeffs) def _clear_value_cache(self): del self.__values @@ -522,7 +510,7 @@ def __call__(self, s, c=None): i = z.rfind('\n') msg = z[:i].replace('digits', 'decimal digits') verbose(msg, level=-1) - ans = CC(z[i + 1:]) + ans = CC(z[i + 1 :]) self.__values[s, c] = ans return ans ans = CC(z) diff --git a/src/sage/lfunctions/lcalc.py b/src/sage/lfunctions/lcalc.py index d59b2989a2f..84f616d6b82 100644 --- a/src/sage/lfunctions/lcalc.py +++ b/src/sage/lfunctions/lcalc.py @@ -63,6 +63,7 @@ class LCalc(SageObject): class. Type ``lcalc.help()`` for a list of commands and how to call them. """ + def _repr_(self): return "Rubinsteins L-function Calculator" @@ -157,8 +158,7 @@ def zeros_in_interval(self, x, y, stepsize, L=''): """ L = self._compute_L(L) RR = RealField(prec) - X = self('--zeros-interval -x %s -y %s --stepsize=%s %s' % ( - float(x), float(y), float(stepsize), L)) + X = self('--zeros-interval -x %s -y %s --stepsize=%s %s' % (float(x), float(y), float(stepsize), L)) return [tuple([RR(z) for z in t.split()]) for t in X.split('\n')] def value(self, s, L=''): @@ -261,8 +261,7 @@ def values_along_line(self, s0, s1, number_samples, L=''): CC = ComplexField(prec) s0 = CC(s0) s1 = CC(s1) - v = self('--value-line-segment -x %s -y %s -X %s -Y %s --number-samples %s %s' % ( - (s0.real(), s0.imag(), s1.real(), s1.imag(), int(number_samples), L))) + v = self('--value-line-segment -x %s -y %s -X %s -Y %s --number-samples %s %s' % ((s0.real(), s0.imag(), s1.real(), s1.imag(), int(number_samples), L))) w = [] for a in v.split('\n'): try: @@ -324,8 +323,7 @@ def twist_values(self, s, dmin, dmax, L=''): typ = '--twist-quadratic' dmin = int(dmin) dmax = int(dmax) - v = self('-v -x %s -y %s %s --start %s --finish %s %s' % ( - (s.real(), s.imag(), typ, dmin, dmax, L))) + v = self('-v -x %s -y %s %s --start %s --finish %s %s' % ((s.real(), s.imag(), typ, dmin, dmax, L))) w = [] if len(v) == 0: return w @@ -364,8 +362,7 @@ def twist_zeros(self, n, dmin, dmax, L=''): RR = RealField(prec) typ = '--twist-quadratic' n = int(n) - v = self('-z %s %s --start %s --finish %s %s' % ( - (n, typ, dmin, dmax, L))) + v = self('-z %s %s --start %s --finish %s %s' % ((n, typ, dmin, dmax, L))) w = {} if len(v) == 0: return w @@ -405,7 +402,7 @@ def analytic_rank(self, L=''): L = self._compute_L(L) s = self('--rank-compute %s' % L) i = s.find('equals') - return ZZ(s[i + 6:]) + return ZZ(s[i + 6 :]) # An instance diff --git a/src/sage/lfunctions/pari.py b/src/sage/lfunctions/pari.py index 08bb0cf6636..37c8692045f 100644 --- a/src/sage/lfunctions/pari.py +++ b/src/sage/lfunctions/pari.py @@ -11,6 +11,7 @@ - Frédéric Chapoton (2018) interface """ + # **************************************************************************** # Copyright (C) 2018 Frédéric Chapoton # @@ -88,8 +89,8 @@ class lfun_generic: sage: L.taylor_series(2, k=5) 1.64493406684823 - 0.937548254315844*z + 0.994640117149451*z^2 - 1.00002430047384*z^3 + 1.00006193307...*z^4 + O(z^5) """ - def __init__(self, conductor, gammaV, weight, eps, poles=[], - residues='automatic', *args, **kwds) -> None: + + def __init__(self, conductor, gammaV, weight, eps, poles=[], residues='automatic', *args, **kwds) -> None: """ Initialisation of a :pari:`lfun` from motivic data. @@ -112,8 +113,7 @@ def __init__(self, conductor, gammaV, weight, eps, poles=[], self.poles = poles self.residues = residues - if (isinstance(self.poles, (list, tuple)) and - isinstance(self.residues, (list, tuple))): + if isinstance(self.poles, (list, tuple)) and isinstance(self.residues, (list, tuple)): if len(self.poles) != len(self.residues): raise ValueError("poles and residues do not match") @@ -155,8 +155,7 @@ def init_empty(self) -> None: """ # empty placeholder # just storing the parameters, not the coefficients - self._L = pari.lfuncreate([[], [], self.gammaV, self.weight, - self.conductor, self.eps]) + self._L = pari.lfuncreate([[], [], self.gammaV, self.weight, self.conductor, self.eps]) def init_coeffs(self, v, w=1): """ @@ -218,12 +217,10 @@ def init_coeffs(self, v, w=1): raise TypeError("w (dual coefficients) must be a list or a function or the special value 0 or 1") if isinstance(self.poles, (tuple, list)) and not self.poles: - self._L = pari.lfuncreate([pv, pw, self.gammaV, self.weight, - self.conductor, self.eps]) + self._L = pari.lfuncreate([pv, pw, self.gammaV, self.weight, self.conductor, self.eps]) elif self.poles == 0: # trying automatic pole reconstruction - self._L = pari.lfuncreate([pv, pw, self.gammaV, self.weight, - self.conductor, self.eps, 0]) + self._L = pari.lfuncreate([pv, pw, self.gammaV, self.weight, self.conductor, self.eps, 0]) elif isinstance(self.residues, (list, tuple)): # pari expects pairs (pole, polar part as power series), # not residues @@ -234,16 +231,11 @@ def init_coeffs(self, v, w=1): # but we do not yet allow this x = pari("x") residues = (pari.Ser([r], "x", 1) / x for r in self.residues) - poles = tuple(pari.Col([b, Pb]) - for b, Pb in zip(self.poles, residues)) - self._L = pari.lfuncreate([pv, pw, self.gammaV, self.weight, - self.conductor, self.eps, - poles]) + poles = tuple(pari.Col([b, Pb]) for b, Pb in zip(self.poles, residues)) + self._L = pari.lfuncreate([pv, pw, self.gammaV, self.weight, self.conductor, self.eps, poles]) else: # assuming a single pole, given as a complex scalar - self._L = pari.lfuncreate([pv, pw, self.gammaV, self.weight, - self.conductor, self.eps, - self.poles[0]]) + self._L = pari.lfuncreate([pv, pw, self.gammaV, self.weight, self.conductor, self.eps, self.poles[0]]) def __pari__(self): """ @@ -419,6 +411,7 @@ def lfun_eta_quotient(scalings, exponents): ValueError: arguments should have the same length """ from sage.matrix.constructor import matrix + N = len(scalings) if N != len(exponents): raise ValueError('arguments should have the same length') @@ -554,6 +547,7 @@ def lfun_genus2(C): ValueError: curve must be hyperelliptic of genus 2 """ from sage.schemes.hyperelliptic_curves.hyperelliptic_g2 import HyperellipticCurve_g2 as hyp_g2 + if not isinstance(C, hyp_g2): raise ValueError('curve must be hyperelliptic of genus 2') P, Q = C.hyperelliptic_polynomials() @@ -633,6 +627,7 @@ class LFunction(SageObject): sage: L.taylor_series(1, 3) 0.0374412812685155 + 0.0709221123619322*z + 0.0380744761270520*z^2 + O(z^3) """ + def __init__(self, lfun, prec=None, max_im=1) -> None: """ Initialization of the `L`-function from a PARI `L`-function. @@ -688,8 +683,7 @@ def _repr_(self) -> str: sage: L = LFunction(lfun_number_field(QQ)); L L-series of conductor 1 and weight 1 """ - return "L-series of conductor %s and weight %s" % (self._conductor, - self._weight) + return "L-series of conductor %s and weight %s" % (self._conductor, self._weight) @property def conductor(self): @@ -977,8 +971,8 @@ def check_functional_equation(self): 16.0000000000000 """ if not self._max_im: - quality = pari.lfuncheckfeq(self._L, 335/339) + quality = pari.lfuncheckfeq(self._L, 335 / 339) else: # check by pari at 335/339 + I/7 quality = pari.lfuncheckfeq(self._L) - return self._RR(2)**quality + return self._RR(2) ** quality diff --git a/src/sage/lfunctions/sympow.py b/src/sage/lfunctions/sympow.py index 8368b150eab..91c6a525ec7 100644 --- a/src/sage/lfunctions/sympow.py +++ b/src/sage/lfunctions/sympow.py @@ -66,6 +66,7 @@ class Sympow(SageObject): this class. Type ``sympow.help()`` for a list of commands and how to call them. """ + def _repr_(self): """ Return a string describing this calculator module @@ -86,7 +87,7 @@ def _fix_err(self, err): w = err j = w.rfind('./sympow') if j != -1: - w = w[:j - 1] + "sympow('" + w[j + 9:] + ')' + w = w[: j - 1] + "sympow('" + w[j + 9 :] + ')' return w def _curve_str(self, E): @@ -144,7 +145,7 @@ def L(self, E, n, prec): if i == -1: print(self._fix_err(v)) raise RuntimeError("failed to compute symmetric power") - x = v[i + 2:] + x = v[i + 2 :] return x def Lderivs(self, E, n, prec, d): @@ -224,7 +225,7 @@ def modular_degree(self, E): if i == -1: print(self._fix_err(v)) raise RuntimeError("failed to compute modular degree") - return Integer(v[i + len(s):]) + return Integer(v[i + len(s) :]) def analytic_rank(self, E): r""" @@ -279,9 +280,9 @@ def analytic_rank(self, E): print(self._fix_err(v)) raise RuntimeError("failed to compute analytic rank") j = v.rfind(':') - r = Integer(v[i + len(s):j]) + r = Integer(v[i + len(s) : j]) i = v.rfind(' ') - L = v[i + 1:] + L = v[i + 1 :] return r, L def new_data(self, n): diff --git a/src/sage/libs/all.py b/src/sage/libs/all.py index f85115a4da2..b90307b594e 100644 --- a/src/sage/libs/all.py +++ b/src/sage/libs/all.py @@ -1,4 +1,3 @@ - import sage.libs.ntl.all as ntl from sage.libs.pari.all import pari, pari_gen, PariError @@ -6,6 +5,7 @@ import sage.libs.symmetrica.all as symmetrica from sage.misc.lazy_import import lazy_import + lazy_import('sage.libs.gap.libgap', 'libgap') lazy_import('sage.libs.eclib.constructor', 'CremonaModularSymbols') diff --git a/src/sage/libs/coxeter3/coxeter_group.py b/src/sage/libs/coxeter3/coxeter_group.py index 58be35ba912..2a7b1091a4f 100644 --- a/src/sage/libs/coxeter3/coxeter_group.py +++ b/src/sage/libs/coxeter3/coxeter_group.py @@ -11,9 +11,8 @@ from sage.features.coxeter3 import Coxeter3 from sage.misc.lazy_import import lazy_import -lazy_import("sage.libs.coxeter3.coxeter", - ["get_CoxGroup", "CoxGroupElement"], - feature=Coxeter3()) + +lazy_import("sage.libs.coxeter3.coxeter", ["get_CoxGroup", "CoxGroupElement"], feature=Coxeter3()) from sage.misc.cachefunc import cached_method @@ -43,6 +42,7 @@ def __classcall__(cls, cartan_type, *args, **options): implemented by Coxeter3 """ from sage.combinat.root_system.cartan_type import CartanType + ct = CartanType(cartan_type) return super().__classcall__(cls, ct, *args, **options) @@ -165,6 +165,7 @@ def simple_reflections(self): [1, 2, 1] """ from sage.sets.family import Family + return Family(self.index_set(), lambda i: self.element_class(self, [i])) gens = simple_reflections @@ -346,8 +347,7 @@ def kazhdan_lusztig_polynomial(self, u, v, constant_term_one=True): ZZq = PolynomialRing(ZZ, 'q', sparse=True) # This is the same as q**len_diff * p(q**(-2)) len_diff = v.length() - u.length() - d = {-2 * deg + len_diff: coeff for deg, coeff in enumerate(p) - if coeff != 0} + d = {-2 * deg + len_diff: coeff for deg, coeff in enumerate(p) if coeff != 0} return ZZq(d) def parabolic_kazhdan_lusztig_polynomial(self, u, v, J, constant_term_one=True): @@ -406,11 +406,9 @@ def parabolic_kazhdan_lusztig_polynomial(self, u, v, J, constant_term_one=True): WOI = self.weak_order_ideal(lambda x: J_set.issuperset(x.descents())) if constant_term_one: P = PolynomialRing(ZZ, 'q') - return P.sum((-1)**(z.length()) * self.kazhdan_lusztig_polynomial(u * z, v) - for z in WOI if (u * z).bruhat_le(v)) + return P.sum((-1) ** (z.length()) * self.kazhdan_lusztig_polynomial(u * z, v) for z in WOI if (u * z).bruhat_le(v)) P = PolynomialRing(ZZ, 'q', sparse=True) - return P.sum((-1)**(z.length()) * self.kazhdan_lusztig_polynomial(u * z, v, constant_term_one=False).shift(z.length()) - for z in WOI if (u * z).bruhat_le(v)) + return P.sum((-1) ** (z.length()) * self.kazhdan_lusztig_polynomial(u * z, v, constant_term_one=False).shift(z.length()) for z in WOI if (u * z).bruhat_le(v)) class Element(ElementWrapper): wrapped_class = CoxGroupElement @@ -679,9 +677,7 @@ def action_on_rational_function(self, f): n = W.rank() if Q.ngens() != n: - raise ValueError("the number of generators for the polynomial " - "ring must be the same as the rank of the " - "root system") + raise ValueError("the number of generators for the polynomial " "ring must be the same as the rank of the " "root system") basis_elements = [alpha[i] for i in W.index_set()] basis_to_order = {s: i for i, s in enumerate(W.index_set())} @@ -698,7 +694,7 @@ def action_on_rational_function(self, f): monomial = 1 for s, c in exponent.monomial_coefficients().items(): - monomial *= Q_gens[basis_to_order[s]]**int(c) + monomial *= Q_gens[basis_to_order[s]] ** int(c) result += monomial diff --git a/src/sage/libs/eclib/constructor.py b/src/sage/libs/eclib/constructor.py index 37df4eb935b..45caa235549 100644 --- a/src/sage/libs/eclib/constructor.py +++ b/src/sage/libs/eclib/constructor.py @@ -71,4 +71,5 @@ def CremonaModularSymbols(level, sign=0, cuspidal=False, verbose=0): Cremona Modular Symbols space of dimension 0 for Gamma_0(10) of weight 2 with sign -1 """ from .homspace import ModularSymbols + return ModularSymbols(level=level, sign=sign, cuspidal=cuspidal, verbose=verbose) diff --git a/src/sage/libs/eclib/interface.py b/src/sage/libs/eclib/interface.py index be3fa396ea5..79835d41be9 100644 --- a/src/sage/libs/eclib/interface.py +++ b/src/sage/libs/eclib/interface.py @@ -25,6 +25,7 @@ sage: [k for k in sys.modules if k.startswith("sage.libs.eclib")] ['...'] """ + import sys from sage.libs.eclib.mwrank import _Curvedata, _mw, _two_descent, parse_point_list @@ -116,8 +117,7 @@ def __init__(self, ainvs, verbose=False): except (TypeError, ValueError): raise TypeError("ainvs must be a list or tuple of integers.") self.__ainvs = a_int - self.__curve = _Curvedata(a_int[0], a_int[1], a_int[2], - a_int[3], a_int[4]) + self.__curve = _Curvedata(a_int[0], a_int[1], a_int[2], a_int[3], a_int[4]) if verbose: self.__verbose = True @@ -249,19 +249,11 @@ def __repr__(self): # we do not assume a1, a2, a3 are reduced to {0,1}, {-1,0,1}, {0,1} def coeff(a): - return ''.join([" +" if a > 0 else " -", - " " + str(abs(a)) if abs(a) > 1 else ""]) - - return ''.join(['y^2', - ' '.join([coeff(a1), 'xy']) if a1 else '', - ' '.join([coeff(a3), 'y']) if a3 else '', - ' = x^3', - ' '.join([coeff(a2), 'x^2']) if a2 else '', - ' '.join([coeff(a4), 'x']) if a4 else '', - ' '.join([" +" if a6 > 0 else " -", str(abs(a6))]) if a6 else '']) - - def two_descent(self, verbose=True, selmer_only=False, first_limit=20, - second_limit=8, n_aux=-1, second_descent=True): + return ''.join([" +" if a > 0 else " -", " " + str(abs(a)) if abs(a) > 1 else ""]) + + return ''.join(['y^2', ' '.join([coeff(a1), 'xy']) if a1 else '', ' '.join([coeff(a3), 'y']) if a3 else '', ' = x^3', ' '.join([coeff(a2), 'x^2']) if a2 else '', ' '.join([coeff(a4), 'x']) if a4 else '', ' '.join([" +" if a6 > 0 else " -", str(abs(a6))]) if a6 else '']) + + def two_descent(self, verbose=True, selmer_only=False, first_limit=20, second_limit=8, n_aux=-1, second_descent=True): r""" Compute 2-descent data for this curve. @@ -345,15 +337,9 @@ def two_descent(self, verbose=True, selmer_only=False, first_limit=20, first_limit = int(first_limit) second_limit = int(second_limit) n_aux = int(n_aux) - second_descent = int(second_descent) # convert from bool to (int) 0 or 1 + second_descent = int(second_descent) # convert from bool to (int) 0 or 1 self.__descent = _two_descent() - self.__descent.do_descent(self.__curve, - verbose, - selmer_only, - first_limit, - second_limit, - n_aux, - second_descent) + self.__descent.do_descent(self.__curve, verbose, selmer_only, first_limit, second_limit, n_aux, second_descent) if not self.__descent.ok(): raise RuntimeError("A 2-descent did not complete successfully.") self.__saturate = -2 # not yet saturated diff --git a/src/sage/libs/gap/all_documented_functions.py b/src/sage/libs/gap/all_documented_functions.py index 0820dc71064..10e4aedbd99 100644 --- a/src/sage/libs/gap/all_documented_functions.py +++ b/src/sage/libs/gap/all_documented_functions.py @@ -14,6 +14,7 @@ sage: List(_, Order) [ 2, 4, 2 ] """ + from sage.libs.gap.libgap import libgap from sage.libs.gap.assigned_names import FUNCTIONS as _FUNCTIONS diff --git a/src/sage/libs/gap/assigned_names.py b/src/sage/libs/gap/assigned_names.py index 216bee639ec..b10bfb9cb27 100644 --- a/src/sage/libs/gap/assigned_names.py +++ b/src/sage/libs/gap/assigned_names.py @@ -63,6 +63,7 @@ def load_or_compute(name, function): else: value = function() from sage.misc.temporary_file import atomic_write + with atomic_write(filename, binary=True) as f: pickle.dump(value, f) return value @@ -99,10 +100,7 @@ def list_globals(): sage: 'ZassenhausIntersection' in GLOBALS # indirect doctest True """ - gvars = set( - name.sage() for name in NamesGVars() - if IsBoundGlobal(name) - ) + gvars = set(name.sage() for name in NamesGVars() if IsBoundGlobal(name)) gvars.difference_update(KEYWORDS) return tuple(sorted(gvars)) diff --git a/src/sage/libs/gap/context_managers.py b/src/sage/libs/gap/context_managers.py index 611708ad96b..7321bf5f539 100644 --- a/src/sage/libs/gap/context_managers.py +++ b/src/sage/libs/gap/context_managers.py @@ -32,7 +32,6 @@ 123 """ - ############################################################################### # Copyright (C) 2012, Volker Braun # diff --git a/src/sage/libs/gap/gap_functions.py b/src/sage/libs/gap/gap_functions.py index 2dafa69647d..ac694ab10f9 100644 --- a/src/sage/libs/gap/gap_functions.py +++ b/src/sage/libs/gap/gap_functions.py @@ -14,1398 +14,1400 @@ # selected gap functions to use in tab completion -common_gap_functions = set([ - 'AbelianGroup', - 'AbelianInvariants', - 'AbelianInvariantsMultiplier', - 'AbelianInvariantsOfList', - 'AbelianNumberField', - 'AbsInt', - 'AbsoluteValue', - 'Action', - 'ActionHomomorphism', - 'Add', - 'AddCoeffs', - 'AddGenerator', - 'AddRelator', - 'AddRowVector', - 'AddRule', - 'AddSet', - 'AdjointMatrix', - 'Algebra', - 'AlternatingGroup', - 'AntiSymmetricParts', - 'Append', - 'AppendTo', - 'Apply', - 'AsGroup', - 'AtlasGroup', - 'AutomorphismGroup', - 'BaseOfGroup', - 'Basis', - 'BasisVectors', - 'Bell', - 'Binomial', - 'BlockMatrix', - 'Blocks', - 'CartanMatrix', - 'CartanSubalgebra', - 'Cartesian', - 'Center', - 'CentralCharacter', - 'Centralizer', - 'CentralizerInGLnZ', - 'CentralizerModulo', - 'Centre', - 'CentreOfCharacter', - 'Character', - 'CharacterDegrees', - 'CharacterNames', - 'CharacterTable', - 'Characteristic', - 'CharacteristicPolynomial', - 'CheckFixedPoints', - 'ChevalleyBasis', - 'ChiefNormalSeriesByPcgs', - 'ChiefSeries', - 'ChineseRem', - 'Chomp', - 'ClassElementLattice', - 'ClassFunction', - 'ClassFunctionSameType', - 'ClassOrbit', - 'ClassPermutation', - 'ClassRoots', - 'ClassesSolvableGroup', - 'CoKernel', - 'Coefficients', - 'CoefficientsRing', - 'CoeffsCyc', - 'CoeffsMod', - 'CollapsedMat', - 'Collected', - 'Combinations', - 'CombinatorialCollector', - 'CommutatorFactorGroup', - 'CommutatorLength', - 'CommutatorSubgroup', - 'Compacted', - 'CompanionMat', - 'ComplexConjugate', - 'ComplexificationQuat', - 'CompositionMapping', - 'CompositionMapping2', - 'CompositionMaps', - 'Concatenation', - 'Conductor', - 'ConjugacyClass', - 'ConjugacyClassSubgroups', - 'ConjugacyClasses', - 'ConjugateGroup', - 'ConjugateSubgroup', - 'ConjugateSubgroups', - 'ConstituentsCompositionMapping', - 'ContainedMaps', - 'ContinuedFractionApproximationOfRoot', - 'ContinuedFractionExpansionOfRoot', - 'ConvertToCharacterTable', - 'ConvertToMatrixRep', - 'ConvertToRangeRep', - 'ConvertToStringRep', - 'ConvertToTableOfMarks', - 'ConvertToVectorRep', - 'ConwayPolynomial', - 'CosetTable', - 'CosetTableInWholeGroup', - 'Cycle', - 'CycleLength', - 'CycleLengths', - 'CycleStructureClass', - 'CycleStructurePerm', - 'Cycles', - 'CyclicGroup', - 'CyclotomicField', - 'CyclotomicPolynomial', - 'DefiningPolynomial', - 'Degree', - 'DegreeFFE', - 'DenominatorCyc', - 'DenominatorOfRationalFunction', - 'DenominatorRat', - 'Derivations', - 'Derivative', - 'DerivedLength', - 'DerivedSeries', - 'DerivedSeriesOfGroup', - 'DerivedSubgroup', - 'Determinant', - 'DeterminantIntMat', - 'DeterminantMat', - 'DeterminantMatDivFree', - 'DeterminantOfCharacter', - 'DiagonalMat', - 'DihedralGroup', - 'Dimension', - 'DimensionOfMatrixGroup', - 'DimensionsMat', - 'DirectProduct', - 'Discriminant', - 'Display', - 'DivisorsInt', - 'DnLattice', - 'DominantCharacter', - 'DominantWeights', - 'DoubleCoset', - 'DoubleCosetRepsAndSizes', - 'DoubleCosets', - 'DoubleHashArraySize', - 'DuplicateFreeList', - 'E', - 'Eigenspaces', - 'Eigenvalues', - 'Eigenvectors', - 'ElementOfFpGroup', - 'ElementOfFpSemigroup', - 'ElementOrdersPowerMap', - 'Elements', - 'ElementsStabChain', - 'EpimorphismFromFreeGroup', - 'EpimorphismNilpotentQuotient', - 'EpimorphismPGroup', - 'EpimorphismQuotientSystem', - 'EpimorphismSchurCover', - 'EuclideanQuotient', - 'EuclideanRemainder', - 'EulerianFunction', - 'Exponent', - 'Extension', - 'ExteriorCentre', - 'ExteriorPower', - 'Extract', - 'FactorGroup', - 'Factorial', - 'Factorization', - 'Factors', - 'FactorsInt', - 'Fibonacci', - 'Field', - 'FieldExtension', - 'FieldOfMatrixGroup', - 'Filtered', - 'First', - 'FittingSubgroup', - 'Flat', - 'ForAll', - 'ForAny', - 'FreeGroup', - 'FreeProduct', - 'FreeSemigroup', - 'FrobeniusAutomorphism', - 'FullRowSpace', - 'GF', - 'GL', - 'GQuotients', - 'GaloisCyc', - 'GaloisField', - 'GaloisGroup', - 'GaloisMat', - 'GaloisStabilizer', - 'Gcd', - 'GcdInt', - 'GcdOp', - 'GeneralLinearGroup', - 'GeneralOrthogonalGroup', - 'GeneralUnitaryGroup', - 'GeneralisedEigenspaces', - 'GeneralisedEigenvalues', - 'GeneralizedEigenspaces', - 'GeneralizedEigenvalues', - 'GeneratorsOfField', - 'GeneratorsOfGroup', - 'GeneratorsOfIdeal', - 'GroebnerBasis', - 'Group', - 'GroupHomomorphismByFunction', - 'GroupHomomorphismByImages', - 'GroupRing', - 'HermiteNormalFormIntegerMat', - 'HermiteNormalFormIntegerMatTransform', - 'Hom', - 'IdGroup', - 'Ideal', - 'IdealByGenerators', - 'Idempotents', - 'Identifier', - 'Identity', - 'Image', - 'Images', - 'Index', - 'InfoLevel', - 'InfoText', - 'InnerAutomorphism', - 'InnerAutomorphismsAutomorphismGroup', - 'Int', - 'IntFFE', - 'IntFFESymm', - 'IntHexString', - 'IntScalarProducts', - 'IntVecFFE', - 'IntersectSet', - 'Intersection', - 'InvariantBilinearForm', - 'InvariantElementaryAbelianSeries', - 'InvariantLattice', - 'InvariantQuadraticForm', - 'InvariantSesquilinearForm', - 'Inverse', - 'InverseMap', - 'Irr', - 'IrrBaumClausen', - 'IrrConlon', - 'IrrDixonSchneider', - 'IrreducibleModules', - 'IrreducibleRepresentations', - 'IrreducibleRepresentationsDixon', - 'IsAbelian', - 'IsAbelianNumberField', - 'IsAbelianNumberFieldPolynomialRing', - 'IsAdditiveElement', - 'IsAdditiveElementWithInverse', - 'IsAdditiveElementWithZero', - 'IsAdditiveGroup', - 'IsAdditiveGroupGeneralMapping', - 'IsAdditiveGroupHomomorphism', - 'IsAdditivelyCommutative', - 'IsAdditivelyCommutativeElement', - 'IsAlgebra', - 'IsAlgebraGeneralMapping', - 'IsAlgebraHomomorphism', - 'IsAlgebraModule', - 'IsAlgebraWithOne', - 'IsAlgebraWithOneHomomorphism', - 'IsAlgebraicElement', - 'IsAlgebraicExtension', - 'IsAlternatingGroup', - 'IsAnticommutative', - 'IsAntisymmetricBinaryRelation', - 'IsAssocWord', - 'IsAssocWordWithInverse', - 'IsAssocWordWithOne', - 'IsAssociated', - 'IsAssociative', - 'IsAutomorphismGroup', - 'IsBasis', - 'IsBijective', - 'IsBinaryRelation', - 'IsBlockMatrixRep', - 'IsBool', - 'IsBoundGlobal', - 'IsBrauerTable', - 'IsBravaisGroup', - 'IsBuiltFromGroup', - 'IsBuiltFromSemigroup', - 'IsCanonicalBasis', - 'IsCanonicalBasisFullMatrixModule', - 'IsCanonicalBasisFullRowModule', - 'IsCanonicalNiceMonomorphism', - 'IsCentral', - 'IsCentralFactor', - 'IsChar', - 'IsCharacter', - 'IsCharacterTable', - 'IsCharacterTableInProgress', - 'IsCharacteristicSubgroup', - 'IsClosedStream', - 'IsCochain', - 'IsCochainCollection', - 'IsCommutative', - 'IsComponentObjectRep', - 'IsCompositionMappingRep', - 'IsConfluent', - 'IsConjugate', - 'IsCopyable', - 'IsCyc', - 'IsCyclic', - 'IsCyclotomic', - 'IsCyclotomicField', - 'IsCyclotomicMatrixGroup', - 'IsDenseList', - 'IsDiagonalMat', - 'IsDictionary', - 'IsDigitChar', - 'IsDivisionRing', - 'IsDomain', - 'IsDoneIterator', - 'IsDoubleCoset', - 'IsDuplicateFree', - 'IsDuplicateFreeList', - 'IsElementaryAbelian', - 'IsEmpty', - 'IsEmptyString', - 'IsEuclideanRing', - 'IsFFE', - 'IsField', - 'IsFinite', - 'IsFiniteDimensional', - 'IsFinitelyGeneratedGroup', - 'IsFixedStabilizer', - 'IsFpGroup', - 'IsFpMonoid', - 'IsFpSemigroup', - 'IsFreeGroup', - 'IsFreeLeftModule', - 'IsFullHomModule', - 'IsFullMatrixModule', - 'IsFullRowModule', - 'IsFunction', - 'IsGL', - 'IsGaussInt', - 'IsGaussRat', - 'IsGaussianIntegers', - 'IsGaussianRationals', - 'IsGaussianSpace', - 'IsGeneralLinearGroup', - 'IsGroup', - 'IsGroupHomomorphism', - 'IsGroupOfAutomorphisms', - 'IsGroupRing', - 'IsHasseDiagram', - 'IsHomogeneousList', - 'IsIdempotent', - 'IsInfinity', - 'IsInjective', - 'IsInnerAutomorphism', - 'IsInt', - 'IsIntegerMatrixGroup', - 'IsIntegers', - 'IsIntegralBasis', - 'IsIntegralCyclotomic', - 'IsIntegralRing', - 'IsIrreducible', - 'IsIrreducibleCharacter', - 'IsIrreducibleRingElement', - 'IsIterator', - 'IsJacobianRing', - 'IsLaurentPolynomial', - 'IsLaurentPolynomialDefaultRep', - 'IsLexicographicallyLess', - 'IsLieAbelian', - 'IsLieAlgebra', - 'IsLieMatrix', - 'IsLieObject', - 'IsLieObjectCollection', - 'IsLieSolvable', - 'IsLinearMapping', - 'IsLinearMappingsModule', - 'IsList', - 'IsMapping', - 'IsMatchingSublist', - 'IsMatrix', - 'IsMatrixGroup', - 'IsMatrixModule', - 'IsMatrixSpace', - 'IsMonomial', - 'IsMonomialGroup', - 'IsMonomialMatrix', - 'IsMonomialOrdering', - 'IsMultiplicativeZero', - 'IsMutable', - 'IsMutableBasis', - 'IsNilpotent', - 'IsNilpotentElement', - 'IsNilpotentGroup', - 'IsNormal', - 'IsNormalBasis', - 'IsNotIdenticalObj', - 'IsNumberField', - 'IsObject', - 'IsOddInt', - 'IsOne', - 'IsOrdering', - 'IsOrdinaryMatrix', - 'IsOrdinaryTable', - 'IsPGroup', - 'IsPSolvable', - 'IsPcGroup', - 'IsPcgs', - 'IsPerfect', - 'IsPerfectGroup', - 'IsPerm', - 'IsPermGroup', - 'IsPolycyclicGroup', - 'IsPolynomial', - 'IsPolynomialRing', - 'IsPosInt', - 'IsPosRat', - 'IsPositiveIntegers', - 'IsPrime', - 'IsPrimeField', - 'IsPrimeInt', - 'IsPrimePowerInt', - 'IsPrimitive', - 'IsPrimitiveCharacter', - 'IsPrimitivePolynomial', - 'IsProbablyPrimeInt', - 'IsPurePadicNumber', - 'IsQuaternion', - 'IsQuickPositionList', - 'IsQuotientSemigroup', - 'IsRandomSource', - 'IsRange', - 'IsRat', - 'IsRationalFunction', - 'IsRationalMatrixGroup', - 'IsRationals', - 'IsRecord', - 'IsReduced', - 'IsReductionOrdering', - 'IsReflexiveBinaryRelation', - 'IsRegular', - 'IsRegularSemigroup', - 'IsRegularSemigroupElement', - 'IsRing', - 'IsRingElement', - 'IsRingGeneralMapping', - 'IsRingWithOne', - 'IsRingWithOneGeneralMapping', - 'IsRingWithOneHomomorphism', - 'IsRowModule', - 'IsRowSpace', - 'IsRowVector', - 'IsSL', - 'IsSSortedList', - 'IsScalar', - 'IsSet', - 'IsSimple', - 'IsSimpleAlgebra', - 'IsSimpleGroup', - 'IsSimpleSemigroup', - 'IsSingleValued', - 'IsSolvable', - 'IsSolvableGroup', - 'IsSortedList', - 'IsSpecialLinearGroup', - 'IsSporadicSimple', - 'IsStandardIterator', - 'IsString', - 'IsStringRep', - 'IsSubgroup', - 'IsSubgroupFpGroup', - 'IsSubgroupOfWholeGroupByQuotientRep', - 'IsSubgroupSL', - 'IsSubset', - 'IsSubsetSet', - 'IsSubspace', - 'IsSupersolvable', - 'IsSupersolvableGroup', - 'IsSurjective', - 'IsSymmetricGroup', - 'IsTable', - 'IsTotal', - 'IsTotalOrdering', - 'IsTransformation', - 'IsTransitive', - 'IsTransitiveBinaryRelation', - 'IsTrivial', - 'IsUniqueFactorizationRing', - 'IsUnit', - 'IsUnivariatePolynomial', - 'IsUnivariatePolynomialRing', - 'IsUnivariateRationalFunction', - 'IsUpperAlphaChar', - 'IsUpperTriangularMat', - 'IsValidIdentifier', - 'IsVector', - 'IsVectorSpace', - 'IsVirtualCharacter', - 'IsWeylGroup', - 'IsWord', - 'IsZero', - 'IsZeroGroup', - 'IsZeroSimpleSemigroup', - 'IsZeroSquaredRing', - 'IsZmodnZObj', - 'IsZmodnZObjNonprime', - 'IsZmodpZObj', - 'IsZmodpZObjLarge', - 'IsZmodpZObjSmall', - 'IsomorphicSubgroups', - 'IsomorphismFpAlgebra', - 'IsomorphismFpGroup', - 'IsomorphismFpGroupByGenerators', - 'IsomorphismFpGroupByPcgs', - 'IsomorphismFpSemigroup', - 'IsomorphismGroups', - 'IsomorphismMatrixAlgebra', - 'IsomorphismPcGroup', - 'IsomorphismPermGroup', - 'IsomorphismPermGroupImfGroup', - 'IsomorphismReesMatrixSemigroup', - 'IsomorphismRefinedPcGroup', - 'IsomorphismSimplifiedFpGroup', - 'IsomorphismSpecialPcGroup', - 'IsomorphismTransformationSemigroup', - 'IsomorphismTypeInfoFiniteSimpleGroup', - 'Iterated', - 'Iterator', - 'IteratorByBasis', - 'IteratorByFunctions', - 'IteratorList', - 'IteratorSorted', - 'Jacobi', - 'JenningsLieAlgebra', - 'JenningsSeries', - 'JordanDecomposition', - 'Kernel', - 'KernelOfAdditiveGeneralMapping', - 'KernelOfCharacter', - 'KernelOfMultiplicativeGeneralMapping', - 'KernelOfTransformation', - 'KillingMatrix', - 'KnuthBendixRewritingSystem', - 'KroneckerProduct', - 'KuKGenerators', - 'LLL', - 'LLLReducedBasis', - 'LLLReducedGramMat', - 'Lambda', - 'LargestElementGroup', - 'LargestElementStabChain', - 'LargestMovedPoint', - 'LastSystemError', - 'LatticeByCyclicExtension', - 'LatticeSubgroups', - 'Lcm', - 'LcmInt', - 'LcmOp', - 'LeadingCoefficient', - 'LeadingCoefficientOfPolynomial', - 'LeadingExponentOfPcElement', - 'LeadingMonomial', - 'LeadingMonomialOfPolynomial', - 'LeadingTermOfPolynomial', - 'Legendre', - 'Length', - 'LenstraBase', - 'LessThanFunction', - 'LessThanOrEqualFunction', - 'LetterRepAssocWord', - 'LevelsOfGenerators', - 'LeviMalcevDecomposition', - 'LexicographicOrdering', - 'LieAlgebra', - 'LieAlgebraByStructureConstants', - 'LieBracket', - 'LieCenter', - 'LieCentralizer', - 'LieCentre', - 'LieCoboundaryOperator', - 'LieDerivedSeries', - 'LieDerivedSubalgebra', - 'LieLowerCentralSeries', - 'LieNilRadical', - 'LieNormalizer', - 'LieObject', - 'LieSolvableRadical', - 'LieUpperCentralSeries', - 'LiftedInducedPcgs', - 'LiftedPcElement', - 'LinearAction', - 'LinearActionLayer', - 'LinearCharacters', - 'LinearCombination', - 'LinearCombinationPcgs', - 'LinearIndependentColumns', - 'LinearOperation', - 'LinearOperationLayer', - 'LinesOfStraightLineProgram', - 'List', - 'ListN', - 'ListPerm', - 'ListStabChain', - 'ListWithIdenticalEntries', - 'ListX', - 'LoadDynamicModule', - 'LoadPackage', - 'Log', - 'LogFFE', - 'LogInt', - 'LogMod', - 'LogModShanks', - 'LogTo', - 'LongestWeylWordPerm', - 'LookupDictionary', - 'LowIndexSubgroupsFpGroup', - 'LowIndexSubgroupsFpGroupIterator', - 'LowerCentralSeries', - 'LowerCentralSeriesOfGroup', - 'LowercaseString', - 'Lucas', - 'MakeConfluent', - 'MakeImmutable', - 'MakeReadOnlyGlobal', - 'MakeReadWriteGlobal', - 'MappedWord', - 'MappingByFunction', - 'MappingPermListList', - 'MatAlgebra', - 'MatClassMultCoeffsCharTable', - 'MatLieAlgebra', - 'MatScalarProducts', - 'MathieuGroup', - 'MatrixAlgebra', - 'MatrixAutomorphisms', - 'MatrixByBlockMatrix', - 'MatrixLieAlgebra', - 'MatrixOfAction', - 'MaximalAbelianQuotient', - 'MaximalBlocks', - 'MaximalNormalSubgroups', - 'MaximalSubgroupClassReps', - 'MaximalSubgroups', - 'MaximalSubgroupsLattice', - 'Maximum', - 'MaximumList', - 'MeetEquivalenceRelations', - 'MeetMaps', - 'MinimalElementCosetStabChain', - 'MinimalGeneratingSet', - 'MinimalNonmonomialGroup', - 'MinimalNormalSubgroups', - 'MinimalPolynomial', - 'MinimalStabChain', - 'MinimalSupergroupsLattice', - 'MinimizedBombieriNorm', - 'Minimum', - 'MinimumList', - 'MinusCharacter', - 'ModuleByRestriction', - 'ModuleOfExtension', - 'ModuloPcgs', - 'MoebiusMu', - 'MolienSeries', - 'MolienSeriesInfo', - 'MolienSeriesWithGivenDenominator', - 'Monoid', - 'MonoidByGenerators', - 'MonoidByMultiplicationTable', - 'MonoidOfRewritingSystem', - 'MonomialComparisonFunction', - 'MonomialExtGrlexLess', - 'MonomialExtrepComparisonFun', - 'MonomialGrevlexOrdering', - 'MonomialGrlexOrdering', - 'MonomialLexOrdering', - 'MostFrequentGeneratorFpGroup', - 'MovedPoints', - 'MultRowVector', - 'MultiplicationTable', - 'MultiplicativeNeutralElement', - 'MultiplicativeZero', - 'MultiplicativeZeroOp', - 'NF', - 'NK', - 'NameFunction', - 'NaturalCharacter', - 'NaturalHomomorphismByGenerators', - 'NaturalHomomorphismByIdeal', - 'NaturalHomomorphismByNormalSubgroup', - 'NaturalHomomorphismBySubAlgebraModule', - 'NaturalHomomorphismBySubspace', - 'NearAdditiveGroup', - 'NearAdditiveGroupByGenerators', - 'NegativeRootVectors', - 'NegativeRoots', - 'NextIterator', - 'NextPrimeInt', - 'NiceBasis', - 'NiceFreeLeftModule', - 'NiceFreeLeftModuleInfo', - 'NiceMonomorphism', - 'NiceMonomorphismAutomGroup', - 'NiceObject', - 'NiceVector', - 'NilpotencyClassOfGroup', - 'NonabelianExteriorSquare', - 'Norm', - 'NormalBase', - 'NormalClosure', - 'NormalFormIntMat', - 'NormalIntersection', - 'NormalSeriesByPcgs', - 'NormalSubgroups', - 'NormalizeWhitespace', - 'NormalizedWhitespace', - 'Normalizer', - 'NormalizerInGLnZ', - 'NormalizerInGLnZBravaisGroup', - 'NormedRowVector', - 'NrArrangements', - 'NrBasisVectors', - 'NrCombinations', - 'NrConjugacyClasses', - 'NrConjugacyClassesGL', - 'NrConjugacyClassesGU', - 'NrConjugacyClassesPGL', - 'NrConjugacyClassesPGU', - 'NrConjugacyClassesPSL', - 'NrConjugacyClassesPSU', - 'NrConjugacyClassesSL', - 'NrConjugacyClassesSLIsogeneous', - 'NrConjugacyClassesSU', - 'NrConjugacyClassesSUIsogeneous', - 'NrDerangements', - 'NrInputsOfStraightLineProgram', - 'NrMovedPoints', - 'NrOrderedPartitions', - 'NrPartitionTuples', - 'NrPartitions', - 'NrPartitionsSet', - 'NrPermutationsList', - 'NrPolyhedralSubgroups', - 'NrPrimitiveGroups', - 'NrRestrictedPartitions', - 'NrTransitiveGroups', - 'NrTuples', - 'NrUnorderedTuples', - 'NullAlgebra', - 'NullMat', - 'NullspaceIntMat', - 'NullspaceMat', - 'NullspaceMatDestructive', - 'NullspaceModQ', - 'Number', - 'NumberArgumentsFunction', - 'NumberFFVector', - 'NumberPerfectGroups', - 'NumberPerfectLibraryGroups', - 'NumberSmallGroups', - 'NumberSyllables', - 'NumeratorOfModuloPcgs', - 'NumeratorOfRationalFunction', - 'NumeratorRat', - 'Objectify', - 'ObjectifyWithAttributes', - 'OctaveAlgebra', - 'OldGeneratorsOfPresentation', - 'Omega', - 'OnBreak', - 'OnBreakMessage', - 'OnIndeterminates', - 'OnLeftInverse', - 'OnLines', - 'OnPairs', - 'OnPoints', - 'OnRight', - 'OnSets', - 'OnSetsDisjointSets', - 'OnSetsSets', - 'OnSetsTuples', - 'OnSubspacesByCanonicalBasis', - 'OnTuples', - 'OnTuplesSets', - 'OnTuplesTuples', - 'One', - 'OneAttr', - 'OneCoboundaries', - 'OneCocycles', - 'OneFactorBound', - 'OneImmutable', - 'OneMutable', - 'OneOfPcgs', - 'OneOp', - 'OneSM', - 'OneSameMutability', - 'OperationAlgebraHomomorphism', - 'Orbit', - 'OrbitFusions', - 'OrbitLength', - 'OrbitLengths', - 'OrbitLengthsDomain', - 'OrbitPerms', - 'OrbitPowerMaps', - 'OrbitStabChain', - 'OrbitStabilizer', - 'OrbitStabilizerAlgorithm', - 'Orbits', - 'OrbitsDomain', - 'OrbitsPerms', - 'Order', - 'OrderMod', - 'OrderingOnGenerators', - 'Ordinal', - 'OrdinaryCharacterTable', - 'OrthogonalComponents', - 'OrthogonalEmbeddings', - 'OrthogonalEmbeddingsSpecialDimension', - 'PCentralLieAlgebra', - 'PCentralNormalSeriesByPcgsPGroup', - 'PCentralSeries', - 'PClassPGroup', - 'PCore', - 'PGL', - 'PGU', - 'POW', - 'PQuotient', - 'PROD', - 'PSL', - 'PSP', - 'PSU', - 'PSp', - 'PadicCoefficients', - 'PadicNumber', - 'PadicValuation', - 'Parametrized', - 'Parent', - 'ParentPcgs', - 'PartialFactorization', - 'PartialOrderByOrderingFunction', - 'PartialOrderOfHasseDiagram', - 'Partition', - 'PartitionTuples', - 'Partitions', - 'PartitionsGreatestEQ', - 'PartitionsGreatestLE', - 'PartitionsSet', - 'PcGroupCode', - 'PcGroupCodeRec', - 'PcGroupFpGroup', - 'PcGroupWithPcgs', - 'PcSeries', - 'Pcgs', - 'PcgsCentralSeries', - 'PcgsChiefSeries', - 'PcgsElementaryAbelianSeries', - 'PcgsPCentralSeriesPGroup', - 'Pcgs_OrbitStabilizer', - 'PerfectGroup', - 'PerfectIdentification', - 'PerfectResiduum', - 'Perform', - 'PermBounds', - 'PermCharInfo', - 'PermCharInfoRelative', - 'PermChars', - 'PermComb', - 'PermLeftQuoTransformation', - 'PermList', - 'PermListList', - 'Permanent', - 'Permutation', - 'PermutationCharacter', - 'PermutationCycle', - 'PermutationCycleOp', - 'PermutationGModule', - 'PermutationMat', - 'PermutationsList', - 'Permuted', - 'Phi', - 'PolynomialByExtRep', - 'PolynomialCoefficientsOfPolynomial', - 'PolynomialDivisionAlgorithm', - 'PolynomialModP', - 'PolynomialReducedRemainder', - 'PolynomialReduction', - 'PolynomialRing', - 'PopOptions', - 'Position', - 'PositionBound', - 'PositionCanonical', - 'PositionNonZero', - 'PositionNot', - 'PositionNthOccurrence', - 'PositionProperty', - 'PositionSet', - 'PositionSorted', - 'PositionStream', - 'PositionSublist', - 'PositionWord', - 'PositionsOp', - 'PositiveRoots', - 'PossibleClassFusions', - 'PossiblePowerMaps', - 'PowerMap', - 'PowerMapOp', - 'PowerModCoeffs', - 'PowerModInt', - 'PowerPartition', - 'PreImage', - 'PreImageElm', - 'PreImages', - 'PreImagesElm', - 'PreImagesRange', - 'PreImagesRepresentative', - 'PreImagesSet', - 'PrefrattiniSubgroup', - 'PreimagesOfTransformation', - 'PresentationFpGroup', - 'PresentationNormalClosure', - 'PresentationNormalClosureRrs', - 'PresentationSubgroup', - 'PresentationSubgroupMtc', - 'PresentationSubgroupRrs', - 'PresentationViaCosetTable', - 'PrevPrimeInt', - 'PrimaryGeneratorWords', - 'PrimeBlocks', - 'PrimeBlocksOp', - 'PrimeField', - 'PrimePGroup', - 'PrimePowersInt', - 'PrimeResidues', - 'PrimitiveElement', - 'PrimitiveGroup', - 'PrimitiveIdentification', - 'PrimitivePolynomial', - 'PrimitiveRoot', - 'PrimitiveRootMod', - 'Print', - 'PrintAmbiguity', - 'PrintArray', - 'PrintCharacterTable', - 'PrintFactorsInt', - 'PrintFormattingStatus', - 'PrintHashWithNames', - 'PrintObj', - 'PrintTo', - 'Process', - 'Product', - 'ProductCoeffs', - 'ProductSpace', - 'ProductX', - 'ProjectedInducedPcgs', - 'ProjectedPcElement', - 'Projection', - 'ProjectionMap', - 'ProjectiveActionHomomorphismMatrixGroup', - 'ProjectiveActionOnFullSpace', - 'ProjectiveGeneralLinearGroup', - 'ProjectiveGeneralUnitaryGroup', - 'ProjectiveOrder', - 'ProjectiveSpecialLinearGroup', - 'ProjectiveSpecialUnitaryGroup', - 'ProjectiveSymplecticGroup', - 'PseudoRandom', - 'PthPowerImage', - 'PthPowerImages', - 'PushOptions', - 'QUO', - 'Quadratic', - 'QuaternionAlgebra', - 'QuoInt', - 'QuotRemLaurpols', - 'Quotient', - 'QuotientMod', - 'QuotientPolynomialsExtRep', - 'QuotientRemainder', - 'READ', - 'RadicalGroup', - 'RadicalOfAlgebra', - 'Random', - 'RandomBinaryRelationOnPoints', - 'RandomHashKey', - 'RandomInvertibleMat', - 'RandomIsomorphismTest', - 'RandomList', - 'RandomMat', - 'RandomPrimitivePolynomial', - 'RandomSource', - 'RandomTransformation', - 'RandomUnimodularMat', - 'Range', - 'Rank', - 'RankAction', - 'RankFilter', - 'RankMat', - 'RankOfTransformation', - 'RankPGroup', - 'Rat', - 'RationalClass', - 'RationalClasses', - 'RationalizedMat', - 'Read', - 'ReadAll', - 'ReadAllLine', - 'ReadAsFunction', - 'ReadByte', - 'ReadLine', - 'ReadPackage', - 'ReadPkg', - 'ReadTest', - 'RealClasses', - 'RealPart', - 'RealizableBrauerCharacters', - 'RecFields', - 'RecNames', - 'RedispatchOnCondition', - 'ReduceCoeffs', - 'ReduceCoeffsMod', - 'ReduceRules', - 'ReduceStabChain', - 'Reduced', - 'ReducedAdditiveInverse', - 'ReducedCharacters', - 'ReducedClassFunctions', - 'ReducedComm', - 'ReducedConfluentRewritingSystem', - 'ReducedConjugate', - 'ReducedDifference', - 'ReducedForm', - 'ReducedGroebnerBasis', - 'ReducedInverse', - 'ReducedLeftQuotient', - 'ReducedOne', - 'ReducedPcElement', - 'ReducedPower', - 'ReducedProduct', - 'ReducedQuotient', - 'ReducedScalarProduct', - 'ReducedSum', - 'ReducedZero', - 'Ree', - 'ReeGroup', - 'ReesCongruenceOfSemigroupIdeal', - 'ReesMatrixSemigroup', - 'ReesMatrixSemigroupElement', - 'ReesZeroMatrixSemigroup', - 'ReesZeroMatrixSemigroupElement', - 'RefinedPcGroup', - 'RegularActionHomomorphism', - 'RegularModule', - 'RelationsOfFpSemigroup', - 'RelativeBasis', - 'RelativeOrders', - 'RelatorsOfFpGroup', - 'RemInt', - 'Remove', - 'RemoveCharacters', - 'RemoveFile', - 'RemoveOuterCoeffs', - 'RemoveRelator', - 'RemoveSet', - 'RemoveStabChain', - 'ReplacedString', - 'Representative', - 'RepresentativeAction', - 'RepresentativeLinearOperation', - 'RepresentativeSmallest', - 'RepresentativesContainedRightCosets', - 'RepresentativesFusions', - 'RepresentativesMinimalBlocks', - 'RepresentativesPerfectSubgroups', - 'RepresentativesPowerMaps', - 'RepresentativesSimpleSubgroups', - 'Reread', - 'RereadPackage', - 'Reset', - 'RestrictOutputsOfSLP', - 'Restricted', - 'RestrictedClassFunction', - 'RestrictedClassFunctions', - 'RestrictedMapping', - 'RestrictedPartitions', - 'RestrictedPerm', - 'RestrictedTransformation', - 'ResultOfStraightLineProgram', - 'Resultant', - 'Reversed', - 'RewriteWord', - 'RightCoset', - 'RightCosets', - 'RightDerivations', - 'Ring', - 'RingWithOne', - 'Root', - 'RootInt', - 'RootMod', - 'RootOfDefiningPolynomial', - 'RootSystem', - 'RootsMod', - 'RoundCyc', - 'Rules', - 'SL', - 'SO', - 'SP', - 'SQ', - 'SSortedList', - 'SU', - 'SameBlock', - 'SaveWorkspace', - 'ScalarProduct', - 'SchurCover', - 'SemiSimpleType', - 'SemidirectProduct', - 'Semigroup', - 'Set', - 'SetAssertionLevel', - 'SetCommutator', - 'SetConjugate', - 'SetCrystGroupDefaultAction', - 'SetEntrySCTable', - 'SetFilterObj', - 'SetHashEntry', - 'SetHashEntryAtLastIndex', - 'SetHelpViewer', - 'SetIndeterminateName', - 'SetInfoLevel', - 'SetName', - 'SetParent', - 'SetPower', - 'ShallowCopy', - 'ShiftedCoeffs', - 'ShiftedPadicNumber', - 'ShortLexOrdering', - 'ShortestVectors', - 'Sigma', - 'SignInt', - 'SignPartition', - 'SignPerm', - 'SimpleLieAlgebra', - 'SimpleSystem', - 'SimplifiedFpGroup', - 'SimplifyPresentation', - 'SimultaneousEigenvalues', - 'SingleCollector', - 'Size', - 'SizeConsiderFunction', - 'SizeNumbersPerfectGroups', - 'SizeOfFieldOfDefinition', - 'SizeScreen', - 'SizeStabChain', - 'SizesCentralizers', - 'SizesConjugacyClasses', - 'SizesPerfectGroups', - 'SmallGeneratingSet', - 'SmallGroup', - 'SmallerDegreePermutationRepresentation', - 'SmallestGeneratorPerm', - 'SmallestMovedPoint', - 'SmallestRootInt', - 'SmithNormalFormIntegerMat', - 'Socle', - 'SocleTypePrimitiveGroup', - 'SolutionIntMat', - 'SolutionMat', - 'SolutionMatDestructive', - 'SolutionNullspaceIntMat', - 'Sort', - 'SortParallel', - 'SortedCharacterTable', - 'SortedCharacters', - 'SortedList', - 'SortedSparseActionHomomorphism', - 'SortingPerm', - 'Sp', - 'SparseActionHomomorphism', - 'SparseCartanMatrix', - 'SparseHashTable', - 'SparseIntKey', - 'SpecialLinearGroup', - 'SpecialOrthogonalGroup', - 'SpecialPcgs', - 'SpecialUnitaryGroup', - 'SplitCharacters', - 'SplitExtension', - 'SplitString', - 'SplittingField', - 'Sqrt', - 'SquareRoots', - 'StabChain', - 'StabChainBaseStrongGenerators', - 'StabChainImmutable', - 'StabChainMutable', - 'StabChainOp', - 'StabChainOptions', - 'Stabilizer', - 'StabilizerOfExternalSet', - 'StabilizerPcgs', - 'StandardAssociate', - 'StandardizeTable', - 'StarCyc', - 'Stirling1', - 'Stirling2', - 'StratMeetPartition', - 'StretchImportantSLPElement', - 'String', - 'StringDate', - 'StringOfResultOfStraightLineProgram', - 'StringPP', - 'StringTime', - 'StructuralCopy', - 'StructureConstantsTable', - 'StructureDescription', - 'SubAlgebraModule', - 'Subalgebra', - 'SubdirectProduct', - 'SubdirectProducts', - 'Subfield', - 'Subfields', - 'Subgroup', - 'SubgroupByPcgs', - 'SubgroupByProperty', - 'SubgroupOfWholeGroupByCosetTable', - 'SubgroupOfWholeGroupByQuotientSubgroup', - 'SubgroupProperty', - 'SubgroupShell', - 'SubgroupsSolvableGroup', - 'Submodule', - 'Submonoid', - 'SubnearAdditiveGroup', - 'SubnormalSeries', - 'Subring', - 'SubringWithOne', - 'Subsemigroup', - 'Subspace', - 'Subspaces', - 'SubstitutedWord', - 'SubtractSet', - 'Subword', - 'Successors', - 'Sum', - 'SumFactorizationFunctionPcgs', - 'SumIntersectionMat', - 'SumX', - 'SupersolvableResiduum', - 'SurjectiveActionHomomorphismAttr', - 'SuzukiGroup', - 'SylowComplement', - 'SylowSubgroup', - 'SylowSystem', - 'SymmetricClosureBinaryRelation', - 'SymmetricGroup', - 'SymmetricParentGroup', - 'SymmetricParts', - 'SymmetricPower', - 'SymmetricPowerOfAlgebraModule', - 'Symmetrizations', - 'SymplecticComponents', - 'SymplecticGroup', - 'TableAutomorphisms', - 'TableOfMarks', - 'TableOfMarksByLattice', - 'TableOfMarksCyclic', - 'TableOfMarksDihedral', - 'TableOfMarksFrobenius', - 'Tau', - 'TensorProduct', - 'TensorProductGModule', - 'TensorProductOfAlgebraModules', - 'Tensored', - 'TietzeWordAbstractWord', - 'Trace', - 'TraceImmediateMethods', - 'TraceMat', - 'TraceMethods', - 'TracePolynomial', - 'TracedCosetFpGroup', - 'TransferDiagram', - 'Transformation', - 'TransformingPermutations', - 'TransformingPermutationsCharacterTables', - 'TransitiveClosureBinaryRelation', - 'TransitiveIdentification', - 'Transitivity', - 'TranslatorSubalgebra', - 'TransposedMat', - 'TransposedMatAttr', - 'TransposedMatDestructive', - 'TransposedMatImmutable', - 'TransposedMatMutable', - 'TransposedMatOp', - 'TransposedMatrixGroup', - 'TriangulizeIntegerMat', - 'TriangulizeMat', - 'TriangulizedIntegerMat', - 'TriangulizedIntegerMatTransform', - 'TriangulizedNullspaceMat', - 'TriangulizedNullspaceMatDestructive', - 'TrivialCharacter', - 'TrivialGroup', - 'TrivialIterator', - 'TrivialSubalgebra', - 'TrivialSubgroup', - 'TrivialSubmagmaWithOne', - 'TrivialSubmodule', - 'TrivialSubmonoid', - 'TrivialSubspace', - 'Tuple', - 'Tuples', - 'TypeObj', - 'UnbindElmWPObj', - 'UnbindGlobal', - 'UnderlyingCharacterTable', - 'UnderlyingCharacteristic', - 'UnderlyingElement', - 'UnderlyingElementOfReesMatrixSemigroupElement', - 'UnderlyingElementOfReesZeroMatrixSemigroupElement', - 'UnderlyingExternalSet', - 'UnderlyingGeneralMapping', - 'UnderlyingGroup', - 'UnderlyingLeftModule', - 'UnderlyingLieAlgebra', - 'UnderlyingRelation', - 'Union', - 'Union2', - 'Unique', - 'UniteSet', - 'Units', - 'UnivariatePolynomial', - 'UnivariatePolynomialByCoefficients', - 'UnivariatePolynomialRing', - 'UnivariateRationalFunctionByCoefficients', - 'UnivariatenessTestRationalFunction', - 'UniversalEnvelopingAlgebra', - 'Unknown', - 'UnorderedTuples', - 'UnprofileFunctions', - 'UnprofileMethods', - 'UntraceMethods', - 'UpdateMap', - 'UpperCentralSeries', - 'UpperCentralSeriesOfGroup', - 'UpperSubdiagonal', - 'UseBasis', - 'UseFactorRelation', - 'UseIsomorphismRelation', - 'UseSubsetRelation', - 'Valuation', - 'Value', - 'ValueCochain', - 'ValueGlobal', - 'ValueMolienSeries', - 'ValueOption', - 'ValuePol', - 'ValuesOfClassFunction', - 'VectorSpace', - 'VectorSpaceByPcgsOfElementaryAbelianGroup', - 'View', - 'VirtualCharacter', - 'WeakPointerObj', - 'WedgeGModule', - 'WeekDay', - 'WeightLexOrdering', - 'WeightOfGenerators', - 'WeightVecFFE', - 'WeylGroup', - 'WeylOrbitIterator', - 'Where', - 'WreathProduct', - 'WreathProductImprimitiveAction', - 'WreathProductOrdering', - 'WreathProductProductAction', - 'WriteAll', - 'WriteByte', - 'WriteLine', - 'ZClassRepsQClass', - 'Zero', - 'ZeroAttr', - 'ZeroCoefficient', - 'ZeroCoefficientRatFun', - 'ZeroMapping', - 'ZeroMutable', - 'ZeroOp', - 'ZeroSM', - 'ZeroSameMutability', - 'GASMAN_STATS', - 'GASMAN', - ]) +common_gap_functions = set( + [ + 'AbelianGroup', + 'AbelianInvariants', + 'AbelianInvariantsMultiplier', + 'AbelianInvariantsOfList', + 'AbelianNumberField', + 'AbsInt', + 'AbsoluteValue', + 'Action', + 'ActionHomomorphism', + 'Add', + 'AddCoeffs', + 'AddGenerator', + 'AddRelator', + 'AddRowVector', + 'AddRule', + 'AddSet', + 'AdjointMatrix', + 'Algebra', + 'AlternatingGroup', + 'AntiSymmetricParts', + 'Append', + 'AppendTo', + 'Apply', + 'AsGroup', + 'AtlasGroup', + 'AutomorphismGroup', + 'BaseOfGroup', + 'Basis', + 'BasisVectors', + 'Bell', + 'Binomial', + 'BlockMatrix', + 'Blocks', + 'CartanMatrix', + 'CartanSubalgebra', + 'Cartesian', + 'Center', + 'CentralCharacter', + 'Centralizer', + 'CentralizerInGLnZ', + 'CentralizerModulo', + 'Centre', + 'CentreOfCharacter', + 'Character', + 'CharacterDegrees', + 'CharacterNames', + 'CharacterTable', + 'Characteristic', + 'CharacteristicPolynomial', + 'CheckFixedPoints', + 'ChevalleyBasis', + 'ChiefNormalSeriesByPcgs', + 'ChiefSeries', + 'ChineseRem', + 'Chomp', + 'ClassElementLattice', + 'ClassFunction', + 'ClassFunctionSameType', + 'ClassOrbit', + 'ClassPermutation', + 'ClassRoots', + 'ClassesSolvableGroup', + 'CoKernel', + 'Coefficients', + 'CoefficientsRing', + 'CoeffsCyc', + 'CoeffsMod', + 'CollapsedMat', + 'Collected', + 'Combinations', + 'CombinatorialCollector', + 'CommutatorFactorGroup', + 'CommutatorLength', + 'CommutatorSubgroup', + 'Compacted', + 'CompanionMat', + 'ComplexConjugate', + 'ComplexificationQuat', + 'CompositionMapping', + 'CompositionMapping2', + 'CompositionMaps', + 'Concatenation', + 'Conductor', + 'ConjugacyClass', + 'ConjugacyClassSubgroups', + 'ConjugacyClasses', + 'ConjugateGroup', + 'ConjugateSubgroup', + 'ConjugateSubgroups', + 'ConstituentsCompositionMapping', + 'ContainedMaps', + 'ContinuedFractionApproximationOfRoot', + 'ContinuedFractionExpansionOfRoot', + 'ConvertToCharacterTable', + 'ConvertToMatrixRep', + 'ConvertToRangeRep', + 'ConvertToStringRep', + 'ConvertToTableOfMarks', + 'ConvertToVectorRep', + 'ConwayPolynomial', + 'CosetTable', + 'CosetTableInWholeGroup', + 'Cycle', + 'CycleLength', + 'CycleLengths', + 'CycleStructureClass', + 'CycleStructurePerm', + 'Cycles', + 'CyclicGroup', + 'CyclotomicField', + 'CyclotomicPolynomial', + 'DefiningPolynomial', + 'Degree', + 'DegreeFFE', + 'DenominatorCyc', + 'DenominatorOfRationalFunction', + 'DenominatorRat', + 'Derivations', + 'Derivative', + 'DerivedLength', + 'DerivedSeries', + 'DerivedSeriesOfGroup', + 'DerivedSubgroup', + 'Determinant', + 'DeterminantIntMat', + 'DeterminantMat', + 'DeterminantMatDivFree', + 'DeterminantOfCharacter', + 'DiagonalMat', + 'DihedralGroup', + 'Dimension', + 'DimensionOfMatrixGroup', + 'DimensionsMat', + 'DirectProduct', + 'Discriminant', + 'Display', + 'DivisorsInt', + 'DnLattice', + 'DominantCharacter', + 'DominantWeights', + 'DoubleCoset', + 'DoubleCosetRepsAndSizes', + 'DoubleCosets', + 'DoubleHashArraySize', + 'DuplicateFreeList', + 'E', + 'Eigenspaces', + 'Eigenvalues', + 'Eigenvectors', + 'ElementOfFpGroup', + 'ElementOfFpSemigroup', + 'ElementOrdersPowerMap', + 'Elements', + 'ElementsStabChain', + 'EpimorphismFromFreeGroup', + 'EpimorphismNilpotentQuotient', + 'EpimorphismPGroup', + 'EpimorphismQuotientSystem', + 'EpimorphismSchurCover', + 'EuclideanQuotient', + 'EuclideanRemainder', + 'EulerianFunction', + 'Exponent', + 'Extension', + 'ExteriorCentre', + 'ExteriorPower', + 'Extract', + 'FactorGroup', + 'Factorial', + 'Factorization', + 'Factors', + 'FactorsInt', + 'Fibonacci', + 'Field', + 'FieldExtension', + 'FieldOfMatrixGroup', + 'Filtered', + 'First', + 'FittingSubgroup', + 'Flat', + 'ForAll', + 'ForAny', + 'FreeGroup', + 'FreeProduct', + 'FreeSemigroup', + 'FrobeniusAutomorphism', + 'FullRowSpace', + 'GF', + 'GL', + 'GQuotients', + 'GaloisCyc', + 'GaloisField', + 'GaloisGroup', + 'GaloisMat', + 'GaloisStabilizer', + 'Gcd', + 'GcdInt', + 'GcdOp', + 'GeneralLinearGroup', + 'GeneralOrthogonalGroup', + 'GeneralUnitaryGroup', + 'GeneralisedEigenspaces', + 'GeneralisedEigenvalues', + 'GeneralizedEigenspaces', + 'GeneralizedEigenvalues', + 'GeneratorsOfField', + 'GeneratorsOfGroup', + 'GeneratorsOfIdeal', + 'GroebnerBasis', + 'Group', + 'GroupHomomorphismByFunction', + 'GroupHomomorphismByImages', + 'GroupRing', + 'HermiteNormalFormIntegerMat', + 'HermiteNormalFormIntegerMatTransform', + 'Hom', + 'IdGroup', + 'Ideal', + 'IdealByGenerators', + 'Idempotents', + 'Identifier', + 'Identity', + 'Image', + 'Images', + 'Index', + 'InfoLevel', + 'InfoText', + 'InnerAutomorphism', + 'InnerAutomorphismsAutomorphismGroup', + 'Int', + 'IntFFE', + 'IntFFESymm', + 'IntHexString', + 'IntScalarProducts', + 'IntVecFFE', + 'IntersectSet', + 'Intersection', + 'InvariantBilinearForm', + 'InvariantElementaryAbelianSeries', + 'InvariantLattice', + 'InvariantQuadraticForm', + 'InvariantSesquilinearForm', + 'Inverse', + 'InverseMap', + 'Irr', + 'IrrBaumClausen', + 'IrrConlon', + 'IrrDixonSchneider', + 'IrreducibleModules', + 'IrreducibleRepresentations', + 'IrreducibleRepresentationsDixon', + 'IsAbelian', + 'IsAbelianNumberField', + 'IsAbelianNumberFieldPolynomialRing', + 'IsAdditiveElement', + 'IsAdditiveElementWithInverse', + 'IsAdditiveElementWithZero', + 'IsAdditiveGroup', + 'IsAdditiveGroupGeneralMapping', + 'IsAdditiveGroupHomomorphism', + 'IsAdditivelyCommutative', + 'IsAdditivelyCommutativeElement', + 'IsAlgebra', + 'IsAlgebraGeneralMapping', + 'IsAlgebraHomomorphism', + 'IsAlgebraModule', + 'IsAlgebraWithOne', + 'IsAlgebraWithOneHomomorphism', + 'IsAlgebraicElement', + 'IsAlgebraicExtension', + 'IsAlternatingGroup', + 'IsAnticommutative', + 'IsAntisymmetricBinaryRelation', + 'IsAssocWord', + 'IsAssocWordWithInverse', + 'IsAssocWordWithOne', + 'IsAssociated', + 'IsAssociative', + 'IsAutomorphismGroup', + 'IsBasis', + 'IsBijective', + 'IsBinaryRelation', + 'IsBlockMatrixRep', + 'IsBool', + 'IsBoundGlobal', + 'IsBrauerTable', + 'IsBravaisGroup', + 'IsBuiltFromGroup', + 'IsBuiltFromSemigroup', + 'IsCanonicalBasis', + 'IsCanonicalBasisFullMatrixModule', + 'IsCanonicalBasisFullRowModule', + 'IsCanonicalNiceMonomorphism', + 'IsCentral', + 'IsCentralFactor', + 'IsChar', + 'IsCharacter', + 'IsCharacterTable', + 'IsCharacterTableInProgress', + 'IsCharacteristicSubgroup', + 'IsClosedStream', + 'IsCochain', + 'IsCochainCollection', + 'IsCommutative', + 'IsComponentObjectRep', + 'IsCompositionMappingRep', + 'IsConfluent', + 'IsConjugate', + 'IsCopyable', + 'IsCyc', + 'IsCyclic', + 'IsCyclotomic', + 'IsCyclotomicField', + 'IsCyclotomicMatrixGroup', + 'IsDenseList', + 'IsDiagonalMat', + 'IsDictionary', + 'IsDigitChar', + 'IsDivisionRing', + 'IsDomain', + 'IsDoneIterator', + 'IsDoubleCoset', + 'IsDuplicateFree', + 'IsDuplicateFreeList', + 'IsElementaryAbelian', + 'IsEmpty', + 'IsEmptyString', + 'IsEuclideanRing', + 'IsFFE', + 'IsField', + 'IsFinite', + 'IsFiniteDimensional', + 'IsFinitelyGeneratedGroup', + 'IsFixedStabilizer', + 'IsFpGroup', + 'IsFpMonoid', + 'IsFpSemigroup', + 'IsFreeGroup', + 'IsFreeLeftModule', + 'IsFullHomModule', + 'IsFullMatrixModule', + 'IsFullRowModule', + 'IsFunction', + 'IsGL', + 'IsGaussInt', + 'IsGaussRat', + 'IsGaussianIntegers', + 'IsGaussianRationals', + 'IsGaussianSpace', + 'IsGeneralLinearGroup', + 'IsGroup', + 'IsGroupHomomorphism', + 'IsGroupOfAutomorphisms', + 'IsGroupRing', + 'IsHasseDiagram', + 'IsHomogeneousList', + 'IsIdempotent', + 'IsInfinity', + 'IsInjective', + 'IsInnerAutomorphism', + 'IsInt', + 'IsIntegerMatrixGroup', + 'IsIntegers', + 'IsIntegralBasis', + 'IsIntegralCyclotomic', + 'IsIntegralRing', + 'IsIrreducible', + 'IsIrreducibleCharacter', + 'IsIrreducibleRingElement', + 'IsIterator', + 'IsJacobianRing', + 'IsLaurentPolynomial', + 'IsLaurentPolynomialDefaultRep', + 'IsLexicographicallyLess', + 'IsLieAbelian', + 'IsLieAlgebra', + 'IsLieMatrix', + 'IsLieObject', + 'IsLieObjectCollection', + 'IsLieSolvable', + 'IsLinearMapping', + 'IsLinearMappingsModule', + 'IsList', + 'IsMapping', + 'IsMatchingSublist', + 'IsMatrix', + 'IsMatrixGroup', + 'IsMatrixModule', + 'IsMatrixSpace', + 'IsMonomial', + 'IsMonomialGroup', + 'IsMonomialMatrix', + 'IsMonomialOrdering', + 'IsMultiplicativeZero', + 'IsMutable', + 'IsMutableBasis', + 'IsNilpotent', + 'IsNilpotentElement', + 'IsNilpotentGroup', + 'IsNormal', + 'IsNormalBasis', + 'IsNotIdenticalObj', + 'IsNumberField', + 'IsObject', + 'IsOddInt', + 'IsOne', + 'IsOrdering', + 'IsOrdinaryMatrix', + 'IsOrdinaryTable', + 'IsPGroup', + 'IsPSolvable', + 'IsPcGroup', + 'IsPcgs', + 'IsPerfect', + 'IsPerfectGroup', + 'IsPerm', + 'IsPermGroup', + 'IsPolycyclicGroup', + 'IsPolynomial', + 'IsPolynomialRing', + 'IsPosInt', + 'IsPosRat', + 'IsPositiveIntegers', + 'IsPrime', + 'IsPrimeField', + 'IsPrimeInt', + 'IsPrimePowerInt', + 'IsPrimitive', + 'IsPrimitiveCharacter', + 'IsPrimitivePolynomial', + 'IsProbablyPrimeInt', + 'IsPurePadicNumber', + 'IsQuaternion', + 'IsQuickPositionList', + 'IsQuotientSemigroup', + 'IsRandomSource', + 'IsRange', + 'IsRat', + 'IsRationalFunction', + 'IsRationalMatrixGroup', + 'IsRationals', + 'IsRecord', + 'IsReduced', + 'IsReductionOrdering', + 'IsReflexiveBinaryRelation', + 'IsRegular', + 'IsRegularSemigroup', + 'IsRegularSemigroupElement', + 'IsRing', + 'IsRingElement', + 'IsRingGeneralMapping', + 'IsRingWithOne', + 'IsRingWithOneGeneralMapping', + 'IsRingWithOneHomomorphism', + 'IsRowModule', + 'IsRowSpace', + 'IsRowVector', + 'IsSL', + 'IsSSortedList', + 'IsScalar', + 'IsSet', + 'IsSimple', + 'IsSimpleAlgebra', + 'IsSimpleGroup', + 'IsSimpleSemigroup', + 'IsSingleValued', + 'IsSolvable', + 'IsSolvableGroup', + 'IsSortedList', + 'IsSpecialLinearGroup', + 'IsSporadicSimple', + 'IsStandardIterator', + 'IsString', + 'IsStringRep', + 'IsSubgroup', + 'IsSubgroupFpGroup', + 'IsSubgroupOfWholeGroupByQuotientRep', + 'IsSubgroupSL', + 'IsSubset', + 'IsSubsetSet', + 'IsSubspace', + 'IsSupersolvable', + 'IsSupersolvableGroup', + 'IsSurjective', + 'IsSymmetricGroup', + 'IsTable', + 'IsTotal', + 'IsTotalOrdering', + 'IsTransformation', + 'IsTransitive', + 'IsTransitiveBinaryRelation', + 'IsTrivial', + 'IsUniqueFactorizationRing', + 'IsUnit', + 'IsUnivariatePolynomial', + 'IsUnivariatePolynomialRing', + 'IsUnivariateRationalFunction', + 'IsUpperAlphaChar', + 'IsUpperTriangularMat', + 'IsValidIdentifier', + 'IsVector', + 'IsVectorSpace', + 'IsVirtualCharacter', + 'IsWeylGroup', + 'IsWord', + 'IsZero', + 'IsZeroGroup', + 'IsZeroSimpleSemigroup', + 'IsZeroSquaredRing', + 'IsZmodnZObj', + 'IsZmodnZObjNonprime', + 'IsZmodpZObj', + 'IsZmodpZObjLarge', + 'IsZmodpZObjSmall', + 'IsomorphicSubgroups', + 'IsomorphismFpAlgebra', + 'IsomorphismFpGroup', + 'IsomorphismFpGroupByGenerators', + 'IsomorphismFpGroupByPcgs', + 'IsomorphismFpSemigroup', + 'IsomorphismGroups', + 'IsomorphismMatrixAlgebra', + 'IsomorphismPcGroup', + 'IsomorphismPermGroup', + 'IsomorphismPermGroupImfGroup', + 'IsomorphismReesMatrixSemigroup', + 'IsomorphismRefinedPcGroup', + 'IsomorphismSimplifiedFpGroup', + 'IsomorphismSpecialPcGroup', + 'IsomorphismTransformationSemigroup', + 'IsomorphismTypeInfoFiniteSimpleGroup', + 'Iterated', + 'Iterator', + 'IteratorByBasis', + 'IteratorByFunctions', + 'IteratorList', + 'IteratorSorted', + 'Jacobi', + 'JenningsLieAlgebra', + 'JenningsSeries', + 'JordanDecomposition', + 'Kernel', + 'KernelOfAdditiveGeneralMapping', + 'KernelOfCharacter', + 'KernelOfMultiplicativeGeneralMapping', + 'KernelOfTransformation', + 'KillingMatrix', + 'KnuthBendixRewritingSystem', + 'KroneckerProduct', + 'KuKGenerators', + 'LLL', + 'LLLReducedBasis', + 'LLLReducedGramMat', + 'Lambda', + 'LargestElementGroup', + 'LargestElementStabChain', + 'LargestMovedPoint', + 'LastSystemError', + 'LatticeByCyclicExtension', + 'LatticeSubgroups', + 'Lcm', + 'LcmInt', + 'LcmOp', + 'LeadingCoefficient', + 'LeadingCoefficientOfPolynomial', + 'LeadingExponentOfPcElement', + 'LeadingMonomial', + 'LeadingMonomialOfPolynomial', + 'LeadingTermOfPolynomial', + 'Legendre', + 'Length', + 'LenstraBase', + 'LessThanFunction', + 'LessThanOrEqualFunction', + 'LetterRepAssocWord', + 'LevelsOfGenerators', + 'LeviMalcevDecomposition', + 'LexicographicOrdering', + 'LieAlgebra', + 'LieAlgebraByStructureConstants', + 'LieBracket', + 'LieCenter', + 'LieCentralizer', + 'LieCentre', + 'LieCoboundaryOperator', + 'LieDerivedSeries', + 'LieDerivedSubalgebra', + 'LieLowerCentralSeries', + 'LieNilRadical', + 'LieNormalizer', + 'LieObject', + 'LieSolvableRadical', + 'LieUpperCentralSeries', + 'LiftedInducedPcgs', + 'LiftedPcElement', + 'LinearAction', + 'LinearActionLayer', + 'LinearCharacters', + 'LinearCombination', + 'LinearCombinationPcgs', + 'LinearIndependentColumns', + 'LinearOperation', + 'LinearOperationLayer', + 'LinesOfStraightLineProgram', + 'List', + 'ListN', + 'ListPerm', + 'ListStabChain', + 'ListWithIdenticalEntries', + 'ListX', + 'LoadDynamicModule', + 'LoadPackage', + 'Log', + 'LogFFE', + 'LogInt', + 'LogMod', + 'LogModShanks', + 'LogTo', + 'LongestWeylWordPerm', + 'LookupDictionary', + 'LowIndexSubgroupsFpGroup', + 'LowIndexSubgroupsFpGroupIterator', + 'LowerCentralSeries', + 'LowerCentralSeriesOfGroup', + 'LowercaseString', + 'Lucas', + 'MakeConfluent', + 'MakeImmutable', + 'MakeReadOnlyGlobal', + 'MakeReadWriteGlobal', + 'MappedWord', + 'MappingByFunction', + 'MappingPermListList', + 'MatAlgebra', + 'MatClassMultCoeffsCharTable', + 'MatLieAlgebra', + 'MatScalarProducts', + 'MathieuGroup', + 'MatrixAlgebra', + 'MatrixAutomorphisms', + 'MatrixByBlockMatrix', + 'MatrixLieAlgebra', + 'MatrixOfAction', + 'MaximalAbelianQuotient', + 'MaximalBlocks', + 'MaximalNormalSubgroups', + 'MaximalSubgroupClassReps', + 'MaximalSubgroups', + 'MaximalSubgroupsLattice', + 'Maximum', + 'MaximumList', + 'MeetEquivalenceRelations', + 'MeetMaps', + 'MinimalElementCosetStabChain', + 'MinimalGeneratingSet', + 'MinimalNonmonomialGroup', + 'MinimalNormalSubgroups', + 'MinimalPolynomial', + 'MinimalStabChain', + 'MinimalSupergroupsLattice', + 'MinimizedBombieriNorm', + 'Minimum', + 'MinimumList', + 'MinusCharacter', + 'ModuleByRestriction', + 'ModuleOfExtension', + 'ModuloPcgs', + 'MoebiusMu', + 'MolienSeries', + 'MolienSeriesInfo', + 'MolienSeriesWithGivenDenominator', + 'Monoid', + 'MonoidByGenerators', + 'MonoidByMultiplicationTable', + 'MonoidOfRewritingSystem', + 'MonomialComparisonFunction', + 'MonomialExtGrlexLess', + 'MonomialExtrepComparisonFun', + 'MonomialGrevlexOrdering', + 'MonomialGrlexOrdering', + 'MonomialLexOrdering', + 'MostFrequentGeneratorFpGroup', + 'MovedPoints', + 'MultRowVector', + 'MultiplicationTable', + 'MultiplicativeNeutralElement', + 'MultiplicativeZero', + 'MultiplicativeZeroOp', + 'NF', + 'NK', + 'NameFunction', + 'NaturalCharacter', + 'NaturalHomomorphismByGenerators', + 'NaturalHomomorphismByIdeal', + 'NaturalHomomorphismByNormalSubgroup', + 'NaturalHomomorphismBySubAlgebraModule', + 'NaturalHomomorphismBySubspace', + 'NearAdditiveGroup', + 'NearAdditiveGroupByGenerators', + 'NegativeRootVectors', + 'NegativeRoots', + 'NextIterator', + 'NextPrimeInt', + 'NiceBasis', + 'NiceFreeLeftModule', + 'NiceFreeLeftModuleInfo', + 'NiceMonomorphism', + 'NiceMonomorphismAutomGroup', + 'NiceObject', + 'NiceVector', + 'NilpotencyClassOfGroup', + 'NonabelianExteriorSquare', + 'Norm', + 'NormalBase', + 'NormalClosure', + 'NormalFormIntMat', + 'NormalIntersection', + 'NormalSeriesByPcgs', + 'NormalSubgroups', + 'NormalizeWhitespace', + 'NormalizedWhitespace', + 'Normalizer', + 'NormalizerInGLnZ', + 'NormalizerInGLnZBravaisGroup', + 'NormedRowVector', + 'NrArrangements', + 'NrBasisVectors', + 'NrCombinations', + 'NrConjugacyClasses', + 'NrConjugacyClassesGL', + 'NrConjugacyClassesGU', + 'NrConjugacyClassesPGL', + 'NrConjugacyClassesPGU', + 'NrConjugacyClassesPSL', + 'NrConjugacyClassesPSU', + 'NrConjugacyClassesSL', + 'NrConjugacyClassesSLIsogeneous', + 'NrConjugacyClassesSU', + 'NrConjugacyClassesSUIsogeneous', + 'NrDerangements', + 'NrInputsOfStraightLineProgram', + 'NrMovedPoints', + 'NrOrderedPartitions', + 'NrPartitionTuples', + 'NrPartitions', + 'NrPartitionsSet', + 'NrPermutationsList', + 'NrPolyhedralSubgroups', + 'NrPrimitiveGroups', + 'NrRestrictedPartitions', + 'NrTransitiveGroups', + 'NrTuples', + 'NrUnorderedTuples', + 'NullAlgebra', + 'NullMat', + 'NullspaceIntMat', + 'NullspaceMat', + 'NullspaceMatDestructive', + 'NullspaceModQ', + 'Number', + 'NumberArgumentsFunction', + 'NumberFFVector', + 'NumberPerfectGroups', + 'NumberPerfectLibraryGroups', + 'NumberSmallGroups', + 'NumberSyllables', + 'NumeratorOfModuloPcgs', + 'NumeratorOfRationalFunction', + 'NumeratorRat', + 'Objectify', + 'ObjectifyWithAttributes', + 'OctaveAlgebra', + 'OldGeneratorsOfPresentation', + 'Omega', + 'OnBreak', + 'OnBreakMessage', + 'OnIndeterminates', + 'OnLeftInverse', + 'OnLines', + 'OnPairs', + 'OnPoints', + 'OnRight', + 'OnSets', + 'OnSetsDisjointSets', + 'OnSetsSets', + 'OnSetsTuples', + 'OnSubspacesByCanonicalBasis', + 'OnTuples', + 'OnTuplesSets', + 'OnTuplesTuples', + 'One', + 'OneAttr', + 'OneCoboundaries', + 'OneCocycles', + 'OneFactorBound', + 'OneImmutable', + 'OneMutable', + 'OneOfPcgs', + 'OneOp', + 'OneSM', + 'OneSameMutability', + 'OperationAlgebraHomomorphism', + 'Orbit', + 'OrbitFusions', + 'OrbitLength', + 'OrbitLengths', + 'OrbitLengthsDomain', + 'OrbitPerms', + 'OrbitPowerMaps', + 'OrbitStabChain', + 'OrbitStabilizer', + 'OrbitStabilizerAlgorithm', + 'Orbits', + 'OrbitsDomain', + 'OrbitsPerms', + 'Order', + 'OrderMod', + 'OrderingOnGenerators', + 'Ordinal', + 'OrdinaryCharacterTable', + 'OrthogonalComponents', + 'OrthogonalEmbeddings', + 'OrthogonalEmbeddingsSpecialDimension', + 'PCentralLieAlgebra', + 'PCentralNormalSeriesByPcgsPGroup', + 'PCentralSeries', + 'PClassPGroup', + 'PCore', + 'PGL', + 'PGU', + 'POW', + 'PQuotient', + 'PROD', + 'PSL', + 'PSP', + 'PSU', + 'PSp', + 'PadicCoefficients', + 'PadicNumber', + 'PadicValuation', + 'Parametrized', + 'Parent', + 'ParentPcgs', + 'PartialFactorization', + 'PartialOrderByOrderingFunction', + 'PartialOrderOfHasseDiagram', + 'Partition', + 'PartitionTuples', + 'Partitions', + 'PartitionsGreatestEQ', + 'PartitionsGreatestLE', + 'PartitionsSet', + 'PcGroupCode', + 'PcGroupCodeRec', + 'PcGroupFpGroup', + 'PcGroupWithPcgs', + 'PcSeries', + 'Pcgs', + 'PcgsCentralSeries', + 'PcgsChiefSeries', + 'PcgsElementaryAbelianSeries', + 'PcgsPCentralSeriesPGroup', + 'Pcgs_OrbitStabilizer', + 'PerfectGroup', + 'PerfectIdentification', + 'PerfectResiduum', + 'Perform', + 'PermBounds', + 'PermCharInfo', + 'PermCharInfoRelative', + 'PermChars', + 'PermComb', + 'PermLeftQuoTransformation', + 'PermList', + 'PermListList', + 'Permanent', + 'Permutation', + 'PermutationCharacter', + 'PermutationCycle', + 'PermutationCycleOp', + 'PermutationGModule', + 'PermutationMat', + 'PermutationsList', + 'Permuted', + 'Phi', + 'PolynomialByExtRep', + 'PolynomialCoefficientsOfPolynomial', + 'PolynomialDivisionAlgorithm', + 'PolynomialModP', + 'PolynomialReducedRemainder', + 'PolynomialReduction', + 'PolynomialRing', + 'PopOptions', + 'Position', + 'PositionBound', + 'PositionCanonical', + 'PositionNonZero', + 'PositionNot', + 'PositionNthOccurrence', + 'PositionProperty', + 'PositionSet', + 'PositionSorted', + 'PositionStream', + 'PositionSublist', + 'PositionWord', + 'PositionsOp', + 'PositiveRoots', + 'PossibleClassFusions', + 'PossiblePowerMaps', + 'PowerMap', + 'PowerMapOp', + 'PowerModCoeffs', + 'PowerModInt', + 'PowerPartition', + 'PreImage', + 'PreImageElm', + 'PreImages', + 'PreImagesElm', + 'PreImagesRange', + 'PreImagesRepresentative', + 'PreImagesSet', + 'PrefrattiniSubgroup', + 'PreimagesOfTransformation', + 'PresentationFpGroup', + 'PresentationNormalClosure', + 'PresentationNormalClosureRrs', + 'PresentationSubgroup', + 'PresentationSubgroupMtc', + 'PresentationSubgroupRrs', + 'PresentationViaCosetTable', + 'PrevPrimeInt', + 'PrimaryGeneratorWords', + 'PrimeBlocks', + 'PrimeBlocksOp', + 'PrimeField', + 'PrimePGroup', + 'PrimePowersInt', + 'PrimeResidues', + 'PrimitiveElement', + 'PrimitiveGroup', + 'PrimitiveIdentification', + 'PrimitivePolynomial', + 'PrimitiveRoot', + 'PrimitiveRootMod', + 'Print', + 'PrintAmbiguity', + 'PrintArray', + 'PrintCharacterTable', + 'PrintFactorsInt', + 'PrintFormattingStatus', + 'PrintHashWithNames', + 'PrintObj', + 'PrintTo', + 'Process', + 'Product', + 'ProductCoeffs', + 'ProductSpace', + 'ProductX', + 'ProjectedInducedPcgs', + 'ProjectedPcElement', + 'Projection', + 'ProjectionMap', + 'ProjectiveActionHomomorphismMatrixGroup', + 'ProjectiveActionOnFullSpace', + 'ProjectiveGeneralLinearGroup', + 'ProjectiveGeneralUnitaryGroup', + 'ProjectiveOrder', + 'ProjectiveSpecialLinearGroup', + 'ProjectiveSpecialUnitaryGroup', + 'ProjectiveSymplecticGroup', + 'PseudoRandom', + 'PthPowerImage', + 'PthPowerImages', + 'PushOptions', + 'QUO', + 'Quadratic', + 'QuaternionAlgebra', + 'QuoInt', + 'QuotRemLaurpols', + 'Quotient', + 'QuotientMod', + 'QuotientPolynomialsExtRep', + 'QuotientRemainder', + 'READ', + 'RadicalGroup', + 'RadicalOfAlgebra', + 'Random', + 'RandomBinaryRelationOnPoints', + 'RandomHashKey', + 'RandomInvertibleMat', + 'RandomIsomorphismTest', + 'RandomList', + 'RandomMat', + 'RandomPrimitivePolynomial', + 'RandomSource', + 'RandomTransformation', + 'RandomUnimodularMat', + 'Range', + 'Rank', + 'RankAction', + 'RankFilter', + 'RankMat', + 'RankOfTransformation', + 'RankPGroup', + 'Rat', + 'RationalClass', + 'RationalClasses', + 'RationalizedMat', + 'Read', + 'ReadAll', + 'ReadAllLine', + 'ReadAsFunction', + 'ReadByte', + 'ReadLine', + 'ReadPackage', + 'ReadPkg', + 'ReadTest', + 'RealClasses', + 'RealPart', + 'RealizableBrauerCharacters', + 'RecFields', + 'RecNames', + 'RedispatchOnCondition', + 'ReduceCoeffs', + 'ReduceCoeffsMod', + 'ReduceRules', + 'ReduceStabChain', + 'Reduced', + 'ReducedAdditiveInverse', + 'ReducedCharacters', + 'ReducedClassFunctions', + 'ReducedComm', + 'ReducedConfluentRewritingSystem', + 'ReducedConjugate', + 'ReducedDifference', + 'ReducedForm', + 'ReducedGroebnerBasis', + 'ReducedInverse', + 'ReducedLeftQuotient', + 'ReducedOne', + 'ReducedPcElement', + 'ReducedPower', + 'ReducedProduct', + 'ReducedQuotient', + 'ReducedScalarProduct', + 'ReducedSum', + 'ReducedZero', + 'Ree', + 'ReeGroup', + 'ReesCongruenceOfSemigroupIdeal', + 'ReesMatrixSemigroup', + 'ReesMatrixSemigroupElement', + 'ReesZeroMatrixSemigroup', + 'ReesZeroMatrixSemigroupElement', + 'RefinedPcGroup', + 'RegularActionHomomorphism', + 'RegularModule', + 'RelationsOfFpSemigroup', + 'RelativeBasis', + 'RelativeOrders', + 'RelatorsOfFpGroup', + 'RemInt', + 'Remove', + 'RemoveCharacters', + 'RemoveFile', + 'RemoveOuterCoeffs', + 'RemoveRelator', + 'RemoveSet', + 'RemoveStabChain', + 'ReplacedString', + 'Representative', + 'RepresentativeAction', + 'RepresentativeLinearOperation', + 'RepresentativeSmallest', + 'RepresentativesContainedRightCosets', + 'RepresentativesFusions', + 'RepresentativesMinimalBlocks', + 'RepresentativesPerfectSubgroups', + 'RepresentativesPowerMaps', + 'RepresentativesSimpleSubgroups', + 'Reread', + 'RereadPackage', + 'Reset', + 'RestrictOutputsOfSLP', + 'Restricted', + 'RestrictedClassFunction', + 'RestrictedClassFunctions', + 'RestrictedMapping', + 'RestrictedPartitions', + 'RestrictedPerm', + 'RestrictedTransformation', + 'ResultOfStraightLineProgram', + 'Resultant', + 'Reversed', + 'RewriteWord', + 'RightCoset', + 'RightCosets', + 'RightDerivations', + 'Ring', + 'RingWithOne', + 'Root', + 'RootInt', + 'RootMod', + 'RootOfDefiningPolynomial', + 'RootSystem', + 'RootsMod', + 'RoundCyc', + 'Rules', + 'SL', + 'SO', + 'SP', + 'SQ', + 'SSortedList', + 'SU', + 'SameBlock', + 'SaveWorkspace', + 'ScalarProduct', + 'SchurCover', + 'SemiSimpleType', + 'SemidirectProduct', + 'Semigroup', + 'Set', + 'SetAssertionLevel', + 'SetCommutator', + 'SetConjugate', + 'SetCrystGroupDefaultAction', + 'SetEntrySCTable', + 'SetFilterObj', + 'SetHashEntry', + 'SetHashEntryAtLastIndex', + 'SetHelpViewer', + 'SetIndeterminateName', + 'SetInfoLevel', + 'SetName', + 'SetParent', + 'SetPower', + 'ShallowCopy', + 'ShiftedCoeffs', + 'ShiftedPadicNumber', + 'ShortLexOrdering', + 'ShortestVectors', + 'Sigma', + 'SignInt', + 'SignPartition', + 'SignPerm', + 'SimpleLieAlgebra', + 'SimpleSystem', + 'SimplifiedFpGroup', + 'SimplifyPresentation', + 'SimultaneousEigenvalues', + 'SingleCollector', + 'Size', + 'SizeConsiderFunction', + 'SizeNumbersPerfectGroups', + 'SizeOfFieldOfDefinition', + 'SizeScreen', + 'SizeStabChain', + 'SizesCentralizers', + 'SizesConjugacyClasses', + 'SizesPerfectGroups', + 'SmallGeneratingSet', + 'SmallGroup', + 'SmallerDegreePermutationRepresentation', + 'SmallestGeneratorPerm', + 'SmallestMovedPoint', + 'SmallestRootInt', + 'SmithNormalFormIntegerMat', + 'Socle', + 'SocleTypePrimitiveGroup', + 'SolutionIntMat', + 'SolutionMat', + 'SolutionMatDestructive', + 'SolutionNullspaceIntMat', + 'Sort', + 'SortParallel', + 'SortedCharacterTable', + 'SortedCharacters', + 'SortedList', + 'SortedSparseActionHomomorphism', + 'SortingPerm', + 'Sp', + 'SparseActionHomomorphism', + 'SparseCartanMatrix', + 'SparseHashTable', + 'SparseIntKey', + 'SpecialLinearGroup', + 'SpecialOrthogonalGroup', + 'SpecialPcgs', + 'SpecialUnitaryGroup', + 'SplitCharacters', + 'SplitExtension', + 'SplitString', + 'SplittingField', + 'Sqrt', + 'SquareRoots', + 'StabChain', + 'StabChainBaseStrongGenerators', + 'StabChainImmutable', + 'StabChainMutable', + 'StabChainOp', + 'StabChainOptions', + 'Stabilizer', + 'StabilizerOfExternalSet', + 'StabilizerPcgs', + 'StandardAssociate', + 'StandardizeTable', + 'StarCyc', + 'Stirling1', + 'Stirling2', + 'StratMeetPartition', + 'StretchImportantSLPElement', + 'String', + 'StringDate', + 'StringOfResultOfStraightLineProgram', + 'StringPP', + 'StringTime', + 'StructuralCopy', + 'StructureConstantsTable', + 'StructureDescription', + 'SubAlgebraModule', + 'Subalgebra', + 'SubdirectProduct', + 'SubdirectProducts', + 'Subfield', + 'Subfields', + 'Subgroup', + 'SubgroupByPcgs', + 'SubgroupByProperty', + 'SubgroupOfWholeGroupByCosetTable', + 'SubgroupOfWholeGroupByQuotientSubgroup', + 'SubgroupProperty', + 'SubgroupShell', + 'SubgroupsSolvableGroup', + 'Submodule', + 'Submonoid', + 'SubnearAdditiveGroup', + 'SubnormalSeries', + 'Subring', + 'SubringWithOne', + 'Subsemigroup', + 'Subspace', + 'Subspaces', + 'SubstitutedWord', + 'SubtractSet', + 'Subword', + 'Successors', + 'Sum', + 'SumFactorizationFunctionPcgs', + 'SumIntersectionMat', + 'SumX', + 'SupersolvableResiduum', + 'SurjectiveActionHomomorphismAttr', + 'SuzukiGroup', + 'SylowComplement', + 'SylowSubgroup', + 'SylowSystem', + 'SymmetricClosureBinaryRelation', + 'SymmetricGroup', + 'SymmetricParentGroup', + 'SymmetricParts', + 'SymmetricPower', + 'SymmetricPowerOfAlgebraModule', + 'Symmetrizations', + 'SymplecticComponents', + 'SymplecticGroup', + 'TableAutomorphisms', + 'TableOfMarks', + 'TableOfMarksByLattice', + 'TableOfMarksCyclic', + 'TableOfMarksDihedral', + 'TableOfMarksFrobenius', + 'Tau', + 'TensorProduct', + 'TensorProductGModule', + 'TensorProductOfAlgebraModules', + 'Tensored', + 'TietzeWordAbstractWord', + 'Trace', + 'TraceImmediateMethods', + 'TraceMat', + 'TraceMethods', + 'TracePolynomial', + 'TracedCosetFpGroup', + 'TransferDiagram', + 'Transformation', + 'TransformingPermutations', + 'TransformingPermutationsCharacterTables', + 'TransitiveClosureBinaryRelation', + 'TransitiveIdentification', + 'Transitivity', + 'TranslatorSubalgebra', + 'TransposedMat', + 'TransposedMatAttr', + 'TransposedMatDestructive', + 'TransposedMatImmutable', + 'TransposedMatMutable', + 'TransposedMatOp', + 'TransposedMatrixGroup', + 'TriangulizeIntegerMat', + 'TriangulizeMat', + 'TriangulizedIntegerMat', + 'TriangulizedIntegerMatTransform', + 'TriangulizedNullspaceMat', + 'TriangulizedNullspaceMatDestructive', + 'TrivialCharacter', + 'TrivialGroup', + 'TrivialIterator', + 'TrivialSubalgebra', + 'TrivialSubgroup', + 'TrivialSubmagmaWithOne', + 'TrivialSubmodule', + 'TrivialSubmonoid', + 'TrivialSubspace', + 'Tuple', + 'Tuples', + 'TypeObj', + 'UnbindElmWPObj', + 'UnbindGlobal', + 'UnderlyingCharacterTable', + 'UnderlyingCharacteristic', + 'UnderlyingElement', + 'UnderlyingElementOfReesMatrixSemigroupElement', + 'UnderlyingElementOfReesZeroMatrixSemigroupElement', + 'UnderlyingExternalSet', + 'UnderlyingGeneralMapping', + 'UnderlyingGroup', + 'UnderlyingLeftModule', + 'UnderlyingLieAlgebra', + 'UnderlyingRelation', + 'Union', + 'Union2', + 'Unique', + 'UniteSet', + 'Units', + 'UnivariatePolynomial', + 'UnivariatePolynomialByCoefficients', + 'UnivariatePolynomialRing', + 'UnivariateRationalFunctionByCoefficients', + 'UnivariatenessTestRationalFunction', + 'UniversalEnvelopingAlgebra', + 'Unknown', + 'UnorderedTuples', + 'UnprofileFunctions', + 'UnprofileMethods', + 'UntraceMethods', + 'UpdateMap', + 'UpperCentralSeries', + 'UpperCentralSeriesOfGroup', + 'UpperSubdiagonal', + 'UseBasis', + 'UseFactorRelation', + 'UseIsomorphismRelation', + 'UseSubsetRelation', + 'Valuation', + 'Value', + 'ValueCochain', + 'ValueGlobal', + 'ValueMolienSeries', + 'ValueOption', + 'ValuePol', + 'ValuesOfClassFunction', + 'VectorSpace', + 'VectorSpaceByPcgsOfElementaryAbelianGroup', + 'View', + 'VirtualCharacter', + 'WeakPointerObj', + 'WedgeGModule', + 'WeekDay', + 'WeightLexOrdering', + 'WeightOfGenerators', + 'WeightVecFFE', + 'WeylGroup', + 'WeylOrbitIterator', + 'Where', + 'WreathProduct', + 'WreathProductImprimitiveAction', + 'WreathProductOrdering', + 'WreathProductProductAction', + 'WriteAll', + 'WriteByte', + 'WriteLine', + 'ZClassRepsQClass', + 'Zero', + 'ZeroAttr', + 'ZeroCoefficient', + 'ZeroCoefficientRatFun', + 'ZeroMapping', + 'ZeroMutable', + 'ZeroOp', + 'ZeroSM', + 'ZeroSameMutability', + 'GASMAN_STATS', + 'GASMAN', + ] +) diff --git a/src/sage/libs/gap/gap_globals.py b/src/sage/libs/gap/gap_globals.py index 9bc897143c3..3de08c3a911 100644 --- a/src/sage/libs/gap/gap_globals.py +++ b/src/sage/libs/gap/gap_globals.py @@ -17,34 +17,4 @@ # selected gap globals to use in tab completion -common_gap_globals = { - 'Assert', - 'Cyclotomics', - 'GaussianIntegers', - 'GaussianRationals', - 'GlobalMersenneTwister', - 'GlobalRandomSource', - 'InfoAlgebra', - 'InfoAttributes', - 'InfoBckt', - 'InfoCharacterTable', - 'InfoCoh', - 'InfoComplement', - 'InfoCoset', - 'InfoFpGroup', - 'InfoGroebner', - 'InfoGroup', - 'InfoLattice', - 'InfoMatrix', - 'InfoMonomial', - 'InfoNumtheor', - 'InfoOptions', - 'InfoPackageLoading', - 'InfoPcSubgroup', - 'InfoWarning', - 'Integers', - 'NiceBasisFiltersInfo', - 'Primes', - 'Rationals', - 'TableOfMarksComponents' -} | common_gap_functions +common_gap_globals = {'Assert', 'Cyclotomics', 'GaussianIntegers', 'GaussianRationals', 'GlobalMersenneTwister', 'GlobalRandomSource', 'InfoAlgebra', 'InfoAttributes', 'InfoBckt', 'InfoCharacterTable', 'InfoCoh', 'InfoComplement', 'InfoCoset', 'InfoFpGroup', 'InfoGroebner', 'InfoGroup', 'InfoLattice', 'InfoMatrix', 'InfoMonomial', 'InfoNumtheor', 'InfoOptions', 'InfoPackageLoading', 'InfoPcSubgroup', 'InfoWarning', 'Integers', 'NiceBasisFiltersInfo', 'Primes', 'Rationals', 'TableOfMarksComponents'} | common_gap_functions diff --git a/src/sage/libs/gap/gap_test.py b/src/sage/libs/gap/gap_test.py index 561ec58e4b0..f1783b0ba26 100644 --- a/src/sage/libs/gap/gap_test.py +++ b/src/sage/libs/gap/gap_test.py @@ -53,7 +53,7 @@ def test_gc_loop_2(): two = libgap(2) for _ in range(100): - rel = libgap([a**2, b**2, a*b*a*b]) + rel = libgap([a**2, b**2, a * b * a * b]) H = G / rel H1 = H.GeneratorsOfGroup()[0] n = H1.Order() @@ -62,7 +62,7 @@ def test_gc_loop_2(): result = True for i in range(300000): n = libgap.Order(H1) - result &= (n == two) + result &= n == two assert result @@ -79,7 +79,7 @@ def test_gc_loop_3(): a, b = G.GeneratorsOfGroup() for _ in range(300000): lis = libgap([]) - lis.Add(a ** 2) - lis.Add(b ** 2) + lis.Add(a**2) + lis.Add(b**2) lis.Add(b * a) assert True diff --git a/src/sage/libs/gap/operations.py b/src/sage/libs/gap/operations.py index b2106583f0b..96ef9266ea5 100644 --- a/src/sage/libs/gap/operations.py +++ b/src/sage/libs/gap/operations.py @@ -91,10 +91,10 @@ def operations(self): sage: Unknown in x.operations() True """ + def mfi(o): filts = GET_OPER_FLAGS(o) - return any(all(IS_SUBSET_FLAGS(self.flags, fl) for fl in fls) - for fls in filts) + return any(all(IS_SUBSET_FLAGS(self.flags, fl) for fl in fls) for fls in filts) return (op for op in OPERATIONS if mfi(op)) diff --git a/src/sage/libs/lrcalc/lrcalc.py b/src/sage/libs/lrcalc/lrcalc.py index 2a5144c0934..9282bd7816b 100644 --- a/src/sage/libs/lrcalc/lrcalc.py +++ b/src/sage/libs/lrcalc/lrcalc.py @@ -177,6 +177,7 @@ - Anne Schilling, Nicolas M. Thiéry, and Anders Buch (2011): fusion product, iterating through LR tableaux, finalization, documentation """ + # **************************************************************************** # Copyright (C) 2010 Mike Hansen # @@ -202,8 +203,7 @@ def _lrcalc_dict_to_sage(result) -> dict: sage: mult([2,1],[3,2,1],3) # indirect doctest {[3, 3, 3]: 1, [4, 3, 2]: 2, [4, 4, 1]: 1, [5, 2, 2]: 1, [5, 3, 1]: 1} """ - return {_Partitions.element_class(_Partitions, [Integer(p) for p in la]): - Integer(k) for la, k in result.items()} + return {_Partitions.element_class(_Partitions, [Integer(p) for p in la]): Integer(k) for la, k in result.items()} def lrcoef_unsafe(outer, inner1, inner2): @@ -330,8 +330,7 @@ def mult(part1, part2, maxrows=None, level=None, quantum=None) -> dict: ValueError: missing parameters maxrows or level """ if maxrows is None and level is not None: - raise ValueError('maxrows needs to be specified if you specify' - ' the level') + raise ValueError('maxrows needs to be specified if you specify' ' the level') if quantum is not None and (level is None or maxrows is None): raise ValueError('missing parameters maxrows or level') @@ -348,7 +347,7 @@ def mult(part1, part2, maxrows=None, level=None, quantum=None) -> dict: output = {} for i, k in result.items(): la = _Partitions(i[0]) - output[la] = output.get(la, P.zero()) + k * quantum**(i[1]) + output[la] = output.get(la, P.zero()) + k * quantum ** (i[1]) return output @@ -405,10 +404,7 @@ def coprod(part, all=0) -> dict: [(([1, 1], [1]), 1), (([2], [1]), 1), (([2, 1], []), 1)] """ result = lrcalc.coprod(part, all) - return {tuple([_Partitions.element_class(_Partitions, - [Integer(p) for p in mu]) - for mu in la]): Integer(k) - for la, k in result.items()} + return {tuple([_Partitions.element_class(_Partitions, [Integer(p) for p in mu]) for mu in la]): Integer(k) for la, k in result.items()} def mult_schubert(w1, w2, rank=0) -> dict: diff --git a/src/sage/libs/mpmath/all.py b/src/sage/libs/mpmath/all.py index 14a4be971e6..fd150baa4c6 100644 --- a/src/sage/libs/mpmath/all.py +++ b/src/sage/libs/mpmath/all.py @@ -13,12 +13,7 @@ from sage.libs.mpmath.utils import call, mpmath_to_sage, sage_to_mpmath # Use mpmath internal functions for constants, to avoid unnecessary overhead -_constants_funcs = { - 'glaisher': glaisher_fixed, - 'khinchin': khinchin_fixed, - 'twinprime': twinprime_fixed, - 'mertens': mertens_fixed -} +_constants_funcs = {'glaisher': glaisher_fixed, 'khinchin': khinchin_fixed, 'twinprime': twinprime_fixed, 'mertens': mertens_fixed} def eval_constant(name, ring): diff --git a/src/sage/libs/ntl/all.py b/src/sage/libs/ntl/all.py index 752ddf03899..10397bcbbaf 100644 --- a/src/sage/libs/ntl/all.py +++ b/src/sage/libs/ntl/all.py @@ -5,6 +5,7 @@ Features of this library include *incredibly fast* arithmetic with polynomials and asymptotically fast factorization of polynomials. """ + # **************************************************************************** # Copyright (C) 2005 William Stein # @@ -20,21 +21,13 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.libs.ntl.ntl_ZZ import ( - ntl_setSeed, - ntl_ZZ as ZZ, - randomBnd as ZZ_random, - randomBits as ZZ_random_bits) +from sage.libs.ntl.ntl_ZZ import ntl_setSeed, ntl_ZZ as ZZ, randomBnd as ZZ_random, randomBits as ZZ_random_bits from sage.libs.ntl.ntl_ZZ_pContext import ntl_ZZ_pContext as ZZ_pContext -from sage.libs.ntl.ntl_ZZ_p import ( - ntl_ZZ_p as ZZ_p, - ntl_ZZ_p_random_element as ZZ_p_random) +from sage.libs.ntl.ntl_ZZ_p import ntl_ZZ_p as ZZ_p, ntl_ZZ_p_random_element as ZZ_p_random -from sage.libs.ntl.ntl_ZZX import ( - ntl_ZZX as ZZX, - zero_ZZX, one_ZZX) +from sage.libs.ntl.ntl_ZZX import ntl_ZZX as ZZX, zero_ZZX, one_ZZX from sage.libs.ntl.ntl_ZZ_pX import ntl_ZZ_pX as ZZ_pX @@ -54,15 +47,11 @@ from sage.libs.ntl.ntl_GF2 import ntl_GF2 as GF2 -from sage.libs.ntl.ntl_GF2X import ( - ntl_GF2X as GF2X, - GF2XHexOutput) +from sage.libs.ntl.ntl_GF2X import ntl_GF2X as GF2X, GF2XHexOutput from sage.libs.ntl.ntl_GF2EContext import ntl_GF2EContext as GF2EContext -from sage.libs.ntl.ntl_GF2E import ( - ntl_GF2E as GF2E, - ntl_GF2E_random as GF2E_random) +from sage.libs.ntl.ntl_GF2E import ntl_GF2E as GF2E, ntl_GF2E_random as GF2E_random from sage.libs.ntl.ntl_GF2EX import ntl_GF2EX as GF2EX diff --git a/src/sage/libs/singular/function_factory.py b/src/sage/libs/singular/function_factory.py index 86fdff8ea4f..f7973190207 100644 --- a/src/sage/libs/singular/function_factory.py +++ b/src/sage/libs/singular/function_factory.py @@ -5,6 +5,7 @@ - Martin Albrecht (2010-01): initial version """ + # **************************************************************************** # Copyright (C) 2010 Martin Albrecht # @@ -19,6 +20,7 @@ class SingularFunctionFactory: """ A convenient interface to libsingular functions. """ + def __getattr__(self, name): """ EXAMPLES:: diff --git a/src/sage/libs/singular/standard_options.py b/src/sage/libs/singular/standard_options.py index cdd81edf74c..709170e345f 100644 --- a/src/sage/libs/singular/standard_options.py +++ b/src/sage/libs/singular/standard_options.py @@ -30,6 +30,7 @@ def __init__(self): [84*c^4 - 40*c^3 + c^2 + c, 7*b + 210*c^3 - 79*c^2 + 3*c, 7*a - 420*c^3 + 158*c^2 + 8*c - 7] """ from sage.libs.singular.option import opt_ctx + self.libsingular_option_context = opt_ctx def __enter__(self): @@ -141,4 +142,5 @@ def wrapper(*args, **kwds): """ with LibSingularGBDefaultContext(): return func(*args, **kwds) + return wrapper diff --git a/src/sage/libs/symmetrica/all.py b/src/sage/libs/symmetrica/all.py index f69490654af..14da5d3fd90 100644 --- a/src/sage/libs/symmetrica/all.py +++ b/src/sage/libs/symmetrica/all.py @@ -15,6 +15,7 @@ from sage.libs.symmetrica.symmetrica import odg_symmetrica as odg from sage.libs.symmetrica.symmetrica import specht_dg_symmetrica as specht_dg from sage.libs.symmetrica.symmetrica import ndg_symmetrica as ndg + # from symmetrica import glmndg_symmetrica as glmndg @@ -22,6 +23,7 @@ from sage.libs.symmetrica.symmetrica import chartafel_symmetrica as chartafel from sage.libs.symmetrica.symmetrica import charvalue_symmetrica as charvalue from sage.libs.symmetrica.symmetrica import kranztafel_symmetrica as kranztafel + # from symmetrica import c_ijk_sn_symmetrica as c_ijk_sn # part diff --git a/src/sage/logic/booleval.py b/src/sage/logic/booleval.py index 48f6db9039e..fb3641e353c 100644 --- a/src/sage/logic/booleval.py +++ b/src/sage/logic/booleval.py @@ -23,6 +23,7 @@ sage: booleval.eval_formula(t, d) False """ + # **************************************************************************** # Copyright (C) 2006 Chris Gorecki # Copyright (C) 2013 Paul Scurek diff --git a/src/sage/logic/boolformula.py b/src/sage/logic/boolformula.py index 3d681b222de..ecb543e7648 100644 --- a/src/sage/logic/boolformula.py +++ b/src/sage/logic/boolformula.py @@ -122,6 +122,7 @@ - Paul Scurek (2013-08-08): added :meth:`~sage.logic.boolformula.BooleanFormula.implies()` """ + # ***************************************************************************** # Copyright (C) 2006 William Stein # Copyright (C) 2006 Chris Gorecki @@ -136,15 +137,11 @@ from . import booleval from . import logictable from . import logicparser + # import boolopt from sage.misc.flatten import flatten -latex_operators = [('&', '\\wedge '), - ('|', '\\vee '), - ('~', '\\neg '), - ('^', '\\oplus '), - ('<->', '\\leftrightarrow '), - ('->', '\\rightarrow ')] +latex_operators = [('&', '\\wedge '), ('|', '\\vee '), ('~', '\\neg '), ('^', '\\oplus '), ('<->', '\\leftrightarrow '), ('->', '\\rightarrow ')] class BooleanFormula: @@ -163,6 +160,7 @@ class BooleanFormula: - ``vo`` -- list; this contains the variables in the expression, in the order that they appear; each variable only occurs once in the list """ + __expression = "" __tree = [] __vars_order = [] @@ -1009,70 +1007,70 @@ def satformat(self): s = 'p cnf ' + str(len(self.__vars_order)) + ' ' + str(clauses) + '\n' + s return s[:-1] -# def simplify(self): -# r""" -# This function uses the propcalc package to simplify an expression to -# its minimal form. -# -# OUTPUT: a simplified expression -# -# EXAMPLES:: - -# sage: import sage.logic.propcalc as propcalc -# sage: f = propcalc.formula("a&((b|c)^a->c)<->b") -# sage: f.truthtable() -# a b c value -# False False False True -# False False True True -# False True False False -# False True True False -# True False False True -# True False True False -# True True False True -# True True True True -# sage: f.simplify() -# (~a&~b)|(a&~b&~c)|(a&b) -# sage: f.truthtable() -# a b c value -# False False False True -# False False True True -# False True False False -# False True True False -# True False False True -# True False True False -# True True False True -# True True True True -# -# .. NOTE:: -# -# If the instance of boolean formula has not been converted to -# cnf form by a call to convert_cnf() or convert_cnf_recur() -# satformat() will call convert_cnf(). Please see the notes for -# convert_cnf() and convert_cnf_recur() for performance issues. -# """ -# exp = '' -# self.__tree = logicparser.apply_func(self.__tree, self.reduce_op) -# plf = logicparser.apply_func(self.__tree, self.convert_opt) -# wff = boolopt.PLFtoWFF()(plf) # convert to positive-normal form -# wtd = boolopt.WFFtoDNF() -# dnf = wtd(wff) -# dnf = wtd.clean(dnf) -# if dnf == [] or dnf == [[]]: -# exp = self.__vars_order[0] + '&~' + self.__vars_order[0] + ' ' -# opt = boolopt.optimize(dnf) -# if exp == '' and (opt == [] or opt == [[]]): -# exp = self.__vars_order[0] + '|~' + self.__vars_order[0] + ' ' -# if exp == '': -# for con in opt: -# s = '(' -# for prop in con: -# if prop[0] == 'notprop': -# s += '~' -# s += prop[1] + '&' -# exp += s[:-1] + ')|' -# self.__expression = exp[:-1] -# self.__tree, self.__vars_order = logicparser.parse(self.__expression) -# return BooleanFormula(self.__expression, self.__tree, self.__vars_order) + # def simplify(self): + # r""" + # This function uses the propcalc package to simplify an expression to + # its minimal form. + # + # OUTPUT: a simplified expression + # + # EXAMPLES:: + + # sage: import sage.logic.propcalc as propcalc + # sage: f = propcalc.formula("a&((b|c)^a->c)<->b") + # sage: f.truthtable() + # a b c value + # False False False True + # False False True True + # False True False False + # False True True False + # True False False True + # True False True False + # True True False True + # True True True True + # sage: f.simplify() + # (~a&~b)|(a&~b&~c)|(a&b) + # sage: f.truthtable() + # a b c value + # False False False True + # False False True True + # False True False False + # False True True False + # True False False True + # True False True False + # True True False True + # True True True True + # + # .. NOTE:: + # + # If the instance of boolean formula has not been converted to + # cnf form by a call to convert_cnf() or convert_cnf_recur() + # satformat() will call convert_cnf(). Please see the notes for + # convert_cnf() and convert_cnf_recur() for performance issues. + # """ + # exp = '' + # self.__tree = logicparser.apply_func(self.__tree, self.reduce_op) + # plf = logicparser.apply_func(self.__tree, self.convert_opt) + # wff = boolopt.PLFtoWFF()(plf) # convert to positive-normal form + # wtd = boolopt.WFFtoDNF() + # dnf = wtd(wff) + # dnf = wtd.clean(dnf) + # if dnf == [] or dnf == [[]]: + # exp = self.__vars_order[0] + '&~' + self.__vars_order[0] + ' ' + # opt = boolopt.optimize(dnf) + # if exp == '' and (opt == [] or opt == [[]]): + # exp = self.__vars_order[0] + '|~' + self.__vars_order[0] + ' ' + # if exp == '': + # for con in opt: + # s = '(' + # for prop in con: + # if prop[0] == 'notprop': + # s += '~' + # s += prop[1] + '&' + # exp += s[:-1] + ')|' + # self.__expression = exp[:-1] + # self.__tree, self.__vars_order = logicparser.parse(self.__expression) + # return BooleanFormula(self.__expression, self.__tree, self.__vars_order) def convert_opt(self, tree): r""" @@ -1245,12 +1243,10 @@ def reduce_op(self, tree): """ if tree[0] == '<->': # parse tree for (~tree[1]|tree[2])&(~tree[2]|tree[1]) - new_tree = ['&', ['|', ['~', tree[1], None], tree[2]], - ['|', ['~', tree[2], None], tree[1]]] + new_tree = ['&', ['|', ['~', tree[1], None], tree[2]], ['|', ['~', tree[2], None], tree[1]]] elif tree[0] == '^': # parse tree for (tree[1]|tree[2])&~(tree[1]&tree[2]) - new_tree = ['&', ['|', tree[1], tree[2]], - ['~', ['&', tree[1], tree[2]], None]] + new_tree = ['&', ['|', tree[1], tree[2]], ['~', ['&', tree[1], tree[2]], None]] elif tree[0] == '->': # parse tree for ~tree[1]|tree[2] new_tree = ['|', ['~', tree[1], None], tree[2]] @@ -1325,12 +1321,10 @@ def dist_ors(self, tree): in :mod:`~sage.logic.logicparser`. """ if tree[0] == '|' and isinstance(tree[2], list) and tree[2][0] == '&': - new_tree = ['&', ['|', tree[1], tree[2][1]], - ['|', tree[1], tree[2][2]]] + new_tree = ['&', ['|', tree[1], tree[2][1]], ['|', tree[1], tree[2][2]]] return logicparser.apply_func(new_tree, self.dist_ors) if tree[0] == '|' and isinstance(tree[1], list) and tree[1][0] == '&': - new_tree = ['&', ['|', tree[1][1], tree[2]], - ['|', tree[1][2], tree[2]]] + new_tree = ['&', ['|', tree[1][1], tree[2]], ['|', tree[1][2], tree[2]]] return logicparser.apply_func(new_tree, self.dist_ors) return tree @@ -1394,7 +1388,7 @@ def convert_expression(self): if i < len(str_tree) - 2 and str_tree[i + 1] == '&' and open_flag: open_flag = False self.__expression += ')' - if str_tree[i:i + 4] == 'None': + if str_tree[i : i + 4] == 'None': i += 4 if i < len(str_tree) and str_tree[i] not in ' \',[]': self.__expression += str_tree[i] diff --git a/src/sage/logic/logic.py b/src/sage/logic/logic.py index 0d9b3578c8c..40162d19020 100644 --- a/src/sage/logic/logic.py +++ b/src/sage/logic/logic.py @@ -15,6 +15,7 @@ - Paul Scurek (2013-08-03): updated docstring formatting """ + # **************************************************************************** # Copyright (C) 2007 Chris Gorecki # Copyright (C) 2007 William Stein @@ -59,6 +60,7 @@ class SymbolicLogic: True | True | False | True | True | True | True | True | """ + def statement(self, s): r""" Return a token list to be used by other functions in the class. @@ -104,7 +106,7 @@ def statement(self, s): toks, vars, vars_order = ['OPAREN'], {}, [] tokenize(s, toks) statement = [toks, vars, vars_order] - try: # verify the syntax + try: # verify the syntax eval(toks) except (KeyError, RuntimeError): print('Malformed Statement') @@ -472,8 +474,8 @@ def eval_ltor_toks(lrtoks): sage: sage.logic.logic.eval_ltor_toks(ltor) 'True' """ - reduce_monos(lrtoks) # monotonic ! operators go first - reduce_bins(lrtoks) # then the binary operators + reduce_monos(lrtoks) # monotonic ! operators go first + reduce_bins(lrtoks) # then the binary operators if len(lrtoks) > 1: raise RuntimeError return lrtoks[0] @@ -814,10 +816,10 @@ def tokenize(s, toks): tok = tok_list[3] elif s[i] == '!': tok = tok_list[4] - elif s[i:i + 2] == '->': + elif s[i : i + 2] == '->': tok = tok_list[5] skip = 2 - elif s[i:i + 3] == '<->': + elif s[i : i + 3] == '<->': tok = tok_list[6] skip = 3 @@ -839,8 +841,7 @@ def tokenize(s, toks): if tok[0] not in string.ascii_letters: valid = 0 for c in tok: - if not (c in string.ascii_letters - or c in string.digits or c == '_'): + if not (c in string.ascii_letters or c in string.digits or c == '_'): valid = 0 if valid == 1: diff --git a/src/sage/logic/logicparser.py b/src/sage/logic/logicparser.py index 6b07ba1be05..fab2988ce79 100644 --- a/src/sage/logic/logicparser.py +++ b/src/sage/logic/logicparser.py @@ -75,6 +75,7 @@ sage: logicparser.tree_parse(r, polish = True) ['|', ['~', ['~', 'a']], 'b'] """ + # **************************************************************************** # Copyright (C) 2007 Chris Gorecki # Copyright (C) 2013 Paul Scurek @@ -208,6 +209,7 @@ def get_trees(*statements): """ trees = [] from . import boolformula + for statement in statements: if not isinstance(statement, boolformula.BooleanFormula): try: @@ -323,6 +325,7 @@ def recover_formula_internal(prefix_tree): - Paul Scurek (2013-08-06) """ from .propcalc import formula as propcalc_formula + if len(prefix_tree) == 3: bool_formula = '(' + prefix_tree[1] + prefix_tree[0] + prefix_tree[2] + ')' else: @@ -464,10 +467,10 @@ def tokenize(s): skip = valid = 1 if s[i] in '()~&|^': tok = s[i] - elif s[i:i + 2] == '->': + elif s[i : i + 2] == '->': tok = '->' skip = 2 - elif s[i:i + 3] == '<->': + elif s[i : i + 3] == '<->': tok = '<->' skip = 3 # check to see if '-', '<' or '>' are used incorrectly diff --git a/src/sage/logic/logictable.py b/src/sage/logic/logictable.py index d317c31d5c9..0d048d149e6 100644 --- a/src/sage/logic/logictable.py +++ b/src/sage/logic/logictable.py @@ -106,6 +106,7 @@ For statements that contain a variable list that when printed is longer than the latex page, the columns of the table will run off the screen. """ + # **************************************************************************** # Copyright (C) 2006 William Stein # Copyright (C) 2006 Chris Gorecki @@ -133,6 +134,7 @@ class Truthtable: - ``vo`` -- list of the variables in the expression in order, with each variable occurring only once """ + def __init__(self, t, vo): r""" Initialize the data fields. diff --git a/src/sage/logic/propcalc.py b/src/sage/logic/propcalc.py index 6058649cf02..912a5a5acad 100644 --- a/src/sage/logic/propcalc.py +++ b/src/sage/logic/propcalc.py @@ -129,6 +129,7 @@ ... NameError: invalid variable name 9b: identifiers must begin with a letter and contain only alphanumerics and underscores """ + # ***************************************************************************** # Copyright (C) 2006 William Stein # Copyright (C) 2006 Chris Gorecki diff --git a/src/sage/manifolds/catalog.py b/src/sage/manifolds/catalog.py index bbd05367960..a594f77beee 100644 --- a/src/sage/manifolds/catalog.py +++ b/src/sage/manifolds/catalog.py @@ -39,9 +39,7 @@ _lazy_import('sage.manifolds.differentiable.examples.real_line', 'RealLine') _lazy_import('sage.manifolds.differentiable.examples.euclidean', 'EuclideanSpace') _lazy_import('sage.manifolds.differentiable.examples.sphere', 'Sphere') -_lazy_import( - "sage.manifolds.differentiable.examples.symplectic_space", "StandardSymplecticSpace" -) +_lazy_import("sage.manifolds.differentiable.examples.symplectic_space", "StandardSymplecticSpace") def Minkowski(positive_spacelike=True, names=None): @@ -198,16 +196,16 @@ def Kerr(m=1, a=0, coordinates='BL', names=None): M._first_ngens = C._first_ngens g = M.metric('g') t, r, th, ph = C[:] - rho = sqrt(r**2 + a**2 * cos(th)**2) + rho = sqrt(r**2 + a**2 * cos(th) ** 2) g[0, 0], g[1, 1], g[2, 2], g[3, 3] = ( -(1 - 2 * m * r / rho**2), 1 + 2 * m * r / rho**2, rho**2, - (r**2 + a**2 + 2 * a**2 * m * r * sin(th)**2 / rho**2) * sin(th)**2, + (r**2 + a**2 + 2 * a**2 * m * r * sin(th) ** 2 / rho**2) * sin(th) ** 2, ) g[0, 1] = 2 * m * r / rho**2 - g[0, 3] = -2 * a * m * r / rho**2 * sin(th)**2 - g[1, 3] = -a * sin(th)**2 * (1 + 2 * m * r / rho**2) + g[0, 3] = -2 * a * m * r / rho**2 * sin(th) ** 2 + g[1, 3] = -a * sin(th) ** 2 * (1 + 2 * m * r / rho**2) return M if coordinates == "BL": @@ -229,19 +227,17 @@ def Kerr(m=1, a=0, coordinates='BL', names=None): M._first_ngens = C._first_ngens g = M.metric('g') t, r, th, ph = C[:] - rho = sqrt(r**2 + a**2 * cos(th)**2) + rho = sqrt(r**2 + a**2 * cos(th) ** 2) g[0, 0], g[1, 1], g[2, 2], g[3, 3] = ( -(1 - 2 * m * r / rho**2), rho**2 / (r**2 - 2 * m * r + a**2), rho**2, - (r**2 + a**2 + 2 * m * r * a**2 / rho**2 * sin(th)**2) * sin(th)**2, + (r**2 + a**2 + 2 * m * r * a**2 / rho**2 * sin(th) ** 2) * sin(th) ** 2, ) - g[0, 3] = -2 * m * r * a * sin(th)**2 / rho**2 + g[0, 3] = -2 * m * r * a * sin(th) ** 2 / rho**2 return M - raise NotImplementedError( - "coordinates system not implemented, see help for details" - ) + raise NotImplementedError("coordinates system not implemented, see help for details") def Torus(R=2, r=1, names=None): @@ -414,18 +410,12 @@ def RealProjectiveSpace(dim=2): xj = gi[j - 1] # use index j - 1 because i < j and xi is omitted in gi # the corresponding coordinates in R^{dim+1} - d_plus_one_coords = ( - [g / xj for g in gi[:i]] + [1 / xj] + [g / xj for g in gi[i:]] - ) + d_plus_one_coords = [g / xj for g in gi[:i]] + [1 / xj] + [g / xj for g in gi[i:]] cj_new_coords = d_plus_one_coords[:j] + d_plus_one_coords[j + 1 :] - Ci_to_Cj = Ci.transition_map( - Cj, cj_new_coords, restrictions1=xj != 0, restrictions2=xi != 0 - ) + Ci_to_Cj = Ci.transition_map(Cj, cj_new_coords, restrictions1=xj != 0, restrictions2=xi != 0) - d_plus_one_coords = ( - [g / xi for g in gj[:j]] + [1 / xi] + [g / xi for g in gj[j:]] - ) + d_plus_one_coords = [g / xi for g in gj[:j]] + [1 / xi] + [g / xi for g in gj[j:]] ci_new_coords = d_plus_one_coords[:i] + d_plus_one_coords[i + 1 :] Cj_to_Ci = Ci_to_Cj.set_inverse(*ci_new_coords, check=False) diff --git a/src/sage/manifolds/chart.py b/src/sage/manifolds/chart.py index fd0d0d0d83b..cbfc9898dae 100644 --- a/src/sage/manifolds/chart.py +++ b/src/sage/manifolds/chart.py @@ -323,9 +323,7 @@ def __classcall__( return domain._charts_by_coord[coord_string] except KeyError: # Make coord_restrictions hashable - coord_restrictions = cls._normalize_coord_restrictions( - coordinates, coord_restrictions - ) + coord_restrictions = cls._normalize_coord_restrictions(coordinates, coord_restrictions) self = super().__classcall__( cls, domain, @@ -373,27 +371,19 @@ def __init__( from sage.manifolds.manifold import TopologicalManifold if not isinstance(domain, TopologicalManifold): - raise TypeError( - "the first argument must be an open subset of " - + "a topological manifold" - ) + raise TypeError("the first argument must be an open subset of " + "a topological manifold") self._manifold = domain.manifold() self._domain = domain self._sindex = self._manifold.start_index() # Handling of calculus methods available on this chart: - self._calc_method = CalculusMethod( - current=calc_method, base_field_type=self.manifold().base_field_type() - ) + self._calc_method = CalculusMethod(current=calc_method, base_field_type=self.manifold().base_field_type()) self.simplify = self._calc_method.simplify # Treatment of the coordinates: self._periods = periods if len(coordinates) != self._manifold.dim(): - raise ValueError( - "the list of coordinates must contain " - + "{} elements".format(self._manifold.dim()) - ) + raise ValueError("the list of coordinates must contain " + "{} elements".format(self._manifold.dim())) self._xx = coordinates # # Additional restrictions on the coordinates. @@ -523,9 +513,7 @@ def normalize(r): if coord_restrictions is None: return frozenset() - if callable(coord_restrictions) and not isinstance( - coord_restrictions, Expression - ): + if callable(coord_restrictions) and not isinstance(coord_restrictions, Expression): # lambda-quoted coord_restrictions = coord_restrictions(*coordinates) @@ -781,9 +769,7 @@ def add_restrictions(self, restrictions): 32102, "Chart.add_restrictions is deprecated; provide the restrictions at the time of creating the chart", ) - self._restrictions.extend( - self._normalize_coord_restrictions(self._xx, restrictions) - ) + self._restrictions.extend(self._normalize_coord_restrictions(self._xx, restrictions)) def restrict(self, subset, restrictions=None): r""" @@ -837,17 +823,12 @@ def restrict(self, subset, restrictions=None): return self if subset not in self._dom_restrict: if not subset.is_subset(self.domain()): - raise ValueError( - "the specified subset is not a subset " - + "of the domain of definition of the chart" - ) + raise ValueError("the specified subset is not a subset " + "of the domain of definition of the chart") coordinates = "" for coord in self._xx: coordinates += repr(coord) + ' ' res_coord_restrictions = set(self._restrictions) - res_coord_restrictions.update( - self._normalize_coord_restrictions(self._xx, restrictions) - ) + res_coord_restrictions.update(self._normalize_coord_restrictions(self._xx, restrictions)) res = type(self)( subset, coordinates, @@ -960,13 +941,9 @@ def _check_restrictions(self, restrict, substitutions): False """ if isinstance(restrict, tuple): # case of 'or' conditions - return any( - self._check_restrictions(cond, substitutions) for cond in restrict - ) + return any(self._check_restrictions(cond, substitutions) for cond in restrict) if isinstance(restrict, (list, set, frozenset)): # case of 'and' conditions - return all( - self._check_restrictions(cond, substitutions) for cond in restrict - ) + return all(self._check_restrictions(cond, substitutions) for cond in restrict) # Case of a single condition: return bool(restrict.subs(substitutions)) @@ -1017,15 +994,11 @@ def _restrict_set(self, universe, coord_restrictions): if len(coord_restrictions) == 1: return A return A.union(self._restrict_set(universe, coord_restrictions[1:])) - if isinstance( - coord_restrictions, (list, set, frozenset) - ): # case of 'and' conditions + if isinstance(coord_restrictions, (list, set, frozenset)): # case of 'and' conditions A = self._restrict_set(universe, coord_restrictions[0]) if len(coord_restrictions) == 1: return A - return A.intersection( - self._restrict_set(universe, coord_restrictions[1:]) - ) + return A.intersection(self._restrict_set(universe, coord_restrictions[1:])) # Case of a single condition: from sage.sets.condition_set import ConditionSet @@ -1262,9 +1235,7 @@ def preimage(self, codomain_subset, name=None, latex_name=None): """ from sage.manifolds.subsets.pullback import ManifoldSubsetPullback - return ManifoldSubsetPullback( - self, codomain_subset, name=name, latex_name=latex_name - ) + return ManifoldSubsetPullback(self, codomain_subset, name=name, latex_name=latex_name) pullback = preimage @@ -2040,9 +2011,7 @@ def _parse_coordinates(cls, domain, coordinates): xx_list.append(coord_var) bounds_list.append(((xmin, xmin_included), (xmax, xmax_included))) period_list.append(period) - return tuple(xx_list), dict( - bounds=tuple(bounds_list), periods=tuple(period_list) - ) + return tuple(xx_list), dict(bounds=tuple(bounds_list), periods=tuple(period_list)) def coord_bounds(self, i=None): r""" @@ -2145,9 +2114,7 @@ def codomain(self): for ((xmin, min_included), (xmax, max_included)) in self._bounds ) if all(interval.is_universe() for interval in intervals): - ambient = VectorSpace( - self.manifold().base_field(), self.manifold().dimension() - ) + ambient = VectorSpace(self.manifold().base_field(), self.manifold().dimension()) else: ambient = cartesian_product(intervals) if self._restrictions: @@ -2234,9 +2201,7 @@ def _display_coord_range(self, xx, rtxt, rlatex): if resu_txt != "": resu_txt += "; " resu_latex += r";\quad " - resu_txt, resu_latex = _display_coord_range( - self, x, resu_txt, resu_latex - ) + resu_txt, resu_latex = _display_coord_range(self, x, resu_txt, resu_latex) else: resu_txt, resu_latex = _display_coord_range(self, xx, resu_txt, resu_latex) return FormattedExpansion(resu_txt, resu_latex) @@ -2328,9 +2293,7 @@ def _tighten_bounds(self): new_restrictions = [] for restrict in self._restrictions: restrict_used = False # determines whether restrict is used to set some coordinate bound - if not isinstance( - restrict, (tuple, list, set, frozenset) - ): + if not isinstance(restrict, (tuple, list, set, frozenset)): # case of combined # conditions excluded operands = restrict.operands() @@ -2453,17 +2416,12 @@ def restrict(self, subset, restrictions=None): return self if subset not in self._dom_restrict: if not subset.is_subset(self.domain()): - raise ValueError( - "the specified subset is not a subset " - + "of the domain of definition of the chart" - ) + raise ValueError("the specified subset is not a subset " + "of the domain of definition of the chart") coordinates = "" for coord in self._xx: coordinates += repr(coord) + ' ' res_coord_restrictions = set(self._restrictions) - res_coord_restrictions.update( - self._normalize_coord_restrictions(self._xx, restrictions) - ) + res_coord_restrictions.update(self._normalize_coord_restrictions(self._xx, restrictions)) res = type(self)( subset, coordinates, @@ -3163,10 +3121,7 @@ def _plot_xx_list(xx_list, rem_coords, ranges, steps, number_values): # to the ambient chart if mapping is None: if not self.domain().is_subset(chart.domain()): - raise ValueError( - "the domain of {} is not ".format(self) - + "included in that of {}".format(chart) - ) + raise ValueError("the domain of {} is not ".format(self) + "included in that of {}".format(chart)) coord_changes = chart.domain()._coord_changes for chart_pair in coord_changes: if chart_pair == (self, chart): @@ -3180,28 +3135,17 @@ def _plot_xx_list(xx_list, rem_coords, ranges, steps, number_values): transf = coord_changes[chart_pair]._transf else: if not isinstance(mapping, ContinuousMap): - raise TypeError( - "the argument 'mapping' must be a continuous manifold map" - ) + raise TypeError("the argument 'mapping' must be a continuous manifold map") if not self.domain().is_subset(mapping.domain()): - raise ValueError( - "the domain of {} is not ".format(self) - + "included in that of {}".format(mapping) - ) + raise ValueError("the domain of {} is not ".format(self) + "included in that of {}".format(mapping)) if not chart.domain().is_subset(mapping._codomain): - raise ValueError( - "the domain of {} is not ".format(chart) - + "included in the codomain of {}".format(mapping) - ) + raise ValueError("the domain of {} is not ".format(chart) + "included in the codomain of {}".format(mapping)) try: transf = mapping.coord_functions(chart1=self, chart2=chart) except ValueError: pass if transf is None: - raise ValueError( - "no relation has been found between " - + "{} and {}".format(self, chart) - ) + raise ValueError("no relation has been found between " + "{} and {}".format(self, chart)) # # 2/ Treatment of input parameters # ----------------------------- @@ -3260,15 +3204,11 @@ def _plot_xx_list(xx_list, rem_coords, ranges, steps, number_values): steps = {} for coord in coords: if coord not in steps: - steps[coord] = (ranges[coord][1] - ranges[coord][0]) / ( - number_values[coord] - 1 - ) + steps[coord] = (ranges[coord][1] - ranges[coord][0]) / (number_values[coord] - 1) else: from sage.functions.other import floor - number_values[coord] = 1 + floor( - (ranges[coord][1] - ranges[coord][0]) / steps[coord] - ) + number_values[coord] = 1 + floor((ranges[coord][1] - ranges[coord][0]) / steps[coord]) if not isinstance(color, dict): color0 = {} for coord in coords: @@ -3307,9 +3247,7 @@ def _plot_xx_list(xx_list, rem_coords, ranges, steps, number_values): rem_coords.remove(coord) xx_list = [xx0] if len(rem_coords) >= 1: - xx_list = _plot_xx_list( - xx_list, rem_coords, ranges, steps, number_values - ) + xx_list = _plot_xx_list(xx_list, rem_coords, ranges, steps, number_values) xmin, xmax = ranges[coord] nbp = plot_points[coord] dx = (xmax - xmin) / (nbp - 1) @@ -3345,16 +3283,9 @@ def _plot_xx_list(xx_list, rem_coords, ranges, steps, number_values): else: for i in range(nbp): xp[ind_coord] = xc - if self.valid_coordinates( - *xp, tolerance=1e-13, parameters=parameters - ): + if self.valid_coordinates(*xp, tolerance=1e-13, parameters=parameters): yp = transf(*xp, simplify=False) - curve.append( - [ - numerical_approx(yp[j].substitute(parameters)) - for j in ind_a - ] - ) + curve.append([numerical_approx(yp[j].substitute(parameters)) for j in ind_a]) first_invalid = True # next invalid point will be # the first one else: @@ -3373,9 +3304,7 @@ def _plot_xx_list(xx_list, rem_coords, ranges, steps, number_values): # be the first one xc += dx if curve: - resu += line( - curve, color=color_c, linestyle=style_c, thickness=thickness_c - ) + resu += line(curve, color=color_c, linestyle=style_c, thickness=thickness_c) if nca == 2: # 2D graphic resu.set_aspect_ratio(1) if label_axes: @@ -3383,9 +3312,7 @@ def _plot_xx_list(xx_list, rem_coords, ranges, steps, number_values): # to show()), instead of using the method # Graphics.axes_labels() since the latter is not robust w.r.t. # graph addition - resu._extra_kwds['axes_labels'] = [ - r'$' + latex(ac) + r'$' for ac in ambient_coords - ] + resu._extra_kwds['axes_labels'] = [r'$' + latex(ac) + r'$' for ac in ambient_coords] else: # 3D graphic resu.aspect_ratio(1) if label_axes: @@ -3459,9 +3386,7 @@ def __init__(self, chart1, chart2, *transformations): self._n1 = len(chart1._xx) self._n2 = len(chart2._xx) if len(transformations) != self._n2: - raise ValueError( - "{} coordinate transformations ".format(self._n2) + "must be provided" - ) + raise ValueError("{} coordinate transformations ".format(self._n2) + "must be provided") self._chart1 = chart1 self._chart2 = chart2 # The coordinate transformations are implemented via the class @@ -3538,11 +3463,7 @@ def __eq__(self, other): return True if not isinstance(other, CoordChange): return False - return ( - (self._chart1 == other._chart1) - and (self._chart2 == other._chart2) - and (self._transf == other._transf) - ) + return (self._chart1 == other._chart1) and (self._chart2 == other._chart2) and (self._transf == other._transf) def __ne__(self, other): r""" @@ -3640,11 +3561,7 @@ def inverse(self): n1 = self._n1 n2 = self._n2 if n1 != n2: - raise ValueError( - "the change of coordinates is not invertible " - + "(different number of coordinates in the two " - + "charts)" - ) + raise ValueError("the change of coordinates is not invertible " + "(different number of coordinates in the two " + "charts)") # New symbolic variables (different from x2 to allow for a # correct solution even when chart2 = chart1): base_field = self._chart1.domain().base_field_type() @@ -3663,10 +3580,7 @@ def inverse(self): try: solutions = solve(equations, *x1, solution_dict=True) except RuntimeError: - raise RuntimeError( - "the system could not be solved; use " - + "set_inverse() to set the inverse manually" - ) + raise RuntimeError("the system could not be solved; use " + "set_inverse() to set the inverse manually") substitutions = dict(zip(xp2, x2)) if len(solutions) == 1: x2_to_x1 = [solutions[0][x1[i]].subs(substitutions) for i in range(n1)] @@ -3682,11 +3596,7 @@ def inverse(self): list_x2_to_x1 = [] for sol in solutions: if x2[0] in sol: - raise ValueError( - "the system could not be solved; use " - + "set_inverse() to set the inverse " - + "manually" - ) + raise ValueError("the system could not be solved; use " + "set_inverse() to set the inverse " + "manually") try: x2_to_x1 = [sol[x1[i]].subs(substitutions) for i in range(n1)] except KeyError: # sol is not a valid solution @@ -3702,18 +3612,11 @@ def inverse(self): if self._chart1.valid_coordinates(*x2_to_x1): list_x2_to_x1.append(x2_to_x1) if len(list_x2_to_x1) == 0: - raise ValueError( - "no solution found; use set_inverse() to " - + "set the inverse manually" - ) + raise ValueError("no solution found; use set_inverse() to " + "set the inverse manually") if len(list_x2_to_x1) > 1: print("Multiple solutions found: ") print(list_x2_to_x1) - raise ValueError( - "non-unique solution to the inverse coordinate " - + "transformation; use set_inverse() to set the inverse " - + "manually" - ) + raise ValueError("non-unique solution to the inverse coordinate " + "transformation; use set_inverse() to set the inverse " + "manually") x2_to_x1 = list_x2_to_x1[0] self._inverse = type(self)(self._chart2, self._chart1, *x2_to_x1) self._inverse._inverse = self @@ -3858,9 +3761,7 @@ def set_inverse(self, *transformations, **kwds): any_failure = True infos.append(" {} {}".format(eq, resu)) if any_failure: - infos.append( - "NB: a failed report can reflect a mere lack of simplification." - ) + infos.append("NB: a failed report can reflect a mere lack of simplification.") if verbose or any_failure: for li in infos: print(li) @@ -3896,10 +3797,7 @@ def __mul__(self, other): if not isinstance(other, CoordChange): raise TypeError("{} is not a change of coordinate".format(other)) if other._chart2 != self._chart1: - raise ValueError( - "composition not possible: " - + "{} is different from {}".format(other._chart2, other._chart1) - ) + raise ValueError("composition not possible: " + "{} is different from {}".format(other._chart2, other._chart1)) transf = self._transf(*(other._transf.expr())) return type(self)(other._chart1, self._chart2, *transf) diff --git a/src/sage/manifolds/chart_func.py b/src/sage/manifolds/chart_func.py index e1ae45a1812..a6bee99c104 100644 --- a/src/sage/manifolds/chart_func.py +++ b/src/sage/manifolds/chart_func.py @@ -377,9 +377,7 @@ def __init__( if expression is not None: if calc_method is None: calc_method = self._calc_method._current - self._express[calc_method] = self._calc_method._tranf[calc_method]( - expression - ) + self._express[calc_method] = self._calc_method._tranf[calc_method](expression) # Derived quantities: self._der = None # list of partial derivatives (to be set by diff() # and unset by del_derived()) @@ -462,9 +460,7 @@ def scalar_field(self, name=None, latex_name=None): True """ alg = self._chart.domain().scalar_field_algebra() - return alg.element_class( - alg, coord_expression={self._chart: self}, name=name, latex_name=latex_name - ) + return alg.element_class(alg, coord_expression={self._chart: self}, name=name, latex_name=latex_name) def expr(self, method=None): r""" @@ -594,14 +590,9 @@ def set_expr(self, calc_method, expression): ValueError: Expressions are not equal """ if self.is_immutable(): - raise ValueError( - "the expressions of an immutable element cannot be changed" - ) + raise ValueError("the expressions of an immutable element cannot be changed") for vv in self._express.values(): - if not bool( - self._calc_method._tranf[calc_method](expression) - == self._calc_method._tranf[calc_method](vv) - ): + if not bool(self._calc_method._tranf[calc_method](expression) == self._calc_method._tranf[calc_method](vv)): raise ValueError("Expressions are not equal") self._express[calc_method] = expression @@ -1115,9 +1106,7 @@ def __eq__(self, other): method = list(self._express)[0] # pick a random method # other.expr(method) if method == 'sympy': - return bool( - sympy.simplify(other.expr(method) - self.expr(method)) == 0 - ) + return bool(sympy.simplify(other.expr(method) - self.expr(method)) == 0) return bool(other.expr(method) == self.expr(method)) return bool(self.expr(self._calc_method._current) == other) @@ -1686,9 +1675,7 @@ def log(self, base=None): if curr == 'SR': val = self.expr().log(base) elif curr == 'sympy': - val = ( - sympy.log(self.expr()) if base is None else sympy.log(self.expr(), base) - ) + val = sympy.log(self.expr()) if base is None else sympy.log(self.expr(), base) return type(self)( self.parent(), self._simplify(val), @@ -3283,9 +3270,7 @@ def jacobian(self): """ from sage.matrix.constructor import matrix - mat = matrix( - [[func.diff(coord) for coord in self._chart[:]] for func in self._functions] - ) + mat = matrix([[func.diff(coord) for coord in self._chart[:]] for func in self._functions]) mat.set_immutable() return mat @@ -3360,12 +3345,7 @@ def jacobian_det(self): raise ValueError("the Jacobian matrix is not a square matrix") mat = self.jacobian() # TODO: do the computation without the 'SR' enforcement - mat_expr = matrix( - [ - [mat[i, j].expr(method='SR') for i in range(self._nc)] - for j in range(self._nc) - ] - ) + mat_expr = matrix([[mat[i, j].expr(method='SR') for i in range(self._nc)] for j in range(self._nc)]) det = mat_expr.det() # the unsimplified determinant func = self._functions[0] return type(func)( diff --git a/src/sage/manifolds/continuous_map.py b/src/sage/manifolds/continuous_map.py index d407e448c91..5a2720bad80 100644 --- a/src/sage/manifolds/continuous_map.py +++ b/src/sage/manifolds/continuous_map.py @@ -396,9 +396,7 @@ def __init__( self._is_identity = True self._is_isomorphism = True if domain != codomain: - raise ValueError( - "the domain and codomain must coincide for the identity map" - ) + raise ValueError("the domain and codomain must coincide for the identity map") if name is None: name = 'Id_' + domain._name if latex_name is None: @@ -407,43 +405,27 @@ def __init__( self._latex_name = latex_name for chart in domain.atlas(): coord_funct = chart[:] - self._coord_expression[(chart, chart)] = chart.multifunction( - *coord_funct - ) + self._coord_expression[(chart, chart)] = chart.multifunction(*coord_funct) else: # Construction of a generic continuous map if is_isomorphism: self._is_isomorphism = True if domain.dim() != codomain.dim(): - raise ValueError( - "for an isomorphism, the source" - " manifold and target manifold must" - " have the same dimension" - ) + raise ValueError("for an isomorphism, the source" " manifold and target manifold must" " have the same dimension") if coord_functions is not None: n2 = self._codomain.dim() for chart_pair, expression in coord_functions.items(): if chart_pair[0] not in self._domain.atlas(): - raise ValueError( - "{} is not a chart ".format(chart_pair[0]) - + "defined on the {}".format(self._domain) - ) + raise ValueError("{} is not a chart ".format(chart_pair[0]) + "defined on the {}".format(self._domain)) if chart_pair[1] not in self._codomain.atlas(): - raise ValueError( - "{} is not a chart ".format(chart_pair[1]) - + "defined on the {}".format(self._codomain) - ) + raise ValueError("{} is not a chart ".format(chart_pair[1]) + "defined on the {}".format(self._codomain)) if n2 == 1: # a single expression entry is allowed if not isinstance(expression, (tuple, list)): expression = (expression,) if len(expression) != n2: - raise ValueError( - "{} coordinate ".format(n2) + "functions must be provided" - ) - self._coord_expression[chart_pair] = chart_pair[0].multifunction( - *expression - ) + raise ValueError("{} coordinate ".format(n2) + "functions must be provided") + self._coord_expression[chart_pair] = chart_pair[0].multifunction(*expression) self._name = name if latex_name is None: self._latex_name = self._name @@ -690,10 +672,7 @@ def _call_(self, point): if chart1 is not None: break else: - raise ValueError( - "no pair of charts has been found to " - + "compute the action of the {} on the {}".format(self, point) - ) + raise ValueError("no pair of charts has been found to " + "compute the action of the {} on the {}".format(self, point)) coord_map = self._coord_expression[(chart1, chart2)] y = coord_map(*(point._coordinates[chart1])) if point._name is None or self._name is None: @@ -703,9 +682,7 @@ def _call_(self, point): if point._latex_name is None or self._latex_name is None: res_latex_name = None else: - res_latex_name = ( - self._latex_name + r'\left(' + point._latex_name + r'\right)' - ) + res_latex_name = self._latex_name + r'\left(' + point._latex_name + r'\right)' # The image point is created as an element of the domain of chart2: dom2 = chart2.domain() return dom2.element_class( @@ -823,9 +800,7 @@ def _composition_(self, other, homset): for chart3 in self._codomain._top_charts: try: self23 = self.coord_functions(chart2, chart3) - resu_funct[(chart1, chart3)] = self23( - *other.expr(chart1, chart2), simplify=True - ) + resu_funct[(chart1, chart3)] = self23(*other.expr(chart1, chart2), simplify=True) except ValueError: pass return homset(resu_funct) @@ -943,9 +918,7 @@ def preimage(self, codomain_subset, name=None, latex_name=None): return self._domain from sage.manifolds.subsets.pullback import ManifoldSubsetPullback - return ManifoldSubsetPullback( - self, codomain_subset, name=name, latex_name=latex_name - ) + return ManifoldSubsetPullback(self, codomain_subset, name=name, latex_name=latex_name) pullback = preimage @@ -1236,28 +1209,12 @@ def _display_expression(self, chart1, chart2, result): symbol = '' else: symbol = self._name + ': ' - result._txt = ( - symbol - + self._domain._name - + ' ' - + unicode_to - + ' ' - + self._codomain._name - + '\n' - ) + result._txt = symbol + self._domain._name + ' ' + unicode_to + ' ' + self._codomain._name + '\n' if self._latex_name is None: symbol = '' else: symbol = self._latex_name + ':' - result._latex = ( - r'\begin{array}{llcl} ' - + symbol - + r'&' - + latex(self._domain) - + r'& \longrightarrow & ' - + latex(self._codomain) - + r'\\' - ) + result._latex = r'\begin{array}{llcl} ' + symbol + r'&' + latex(self._domain) + r'& \longrightarrow & ' + latex(self._codomain) + r'\\' if chart1 is None: if chart2 is None: for ch1 in self._domain._top_charts: @@ -1397,16 +1354,12 @@ def coord_functions(self, chart1=None, chart2=None): for ochart1, ochart2 in self._coord_expression: if chart1 in ochart1._subcharts and ochart2 in chart2._subcharts: coord_functions = self._coord_expression[(ochart1, ochart2)].expr() - self._coord_expression[(chart1, chart2)] = chart1.multifunction( - *coord_functions - ) + self._coord_expression[(chart1, chart2)] = chart1.multifunction(*coord_functions) return self._coord_expression[(chart1, chart2)] # Special case of the identity in a single chart: if self._is_identity and chart1 == chart2: coord_functions = chart1[:] - self._coord_expression[(chart1, chart1)] = chart1.multifunction( - *coord_functions - ) + self._coord_expression[(chart1, chart1)] = chart1.multifunction(*coord_functions) return self._coord_expression[(chart1, chart2)] # Some change of coordinates must be performed change_start = [] @@ -1419,10 +1372,7 @@ def coord_functions(self, chart1=None, chart2=None): # 1/ Trying to make a change of chart only on the codomain: # the codomain's default chart is privileged: sel_chart2 = None # selected chart2 - if ( - def_chart2 in change_arrival - and (def_chart2, chart2) in dom2._coord_changes - ): + if def_chart2 in change_arrival and (def_chart2, chart2) in dom2._coord_changes: sel_chart2 = def_chart2 else: for ochart2 in change_arrival: @@ -1432,18 +1382,13 @@ def coord_functions(self, chart1=None, chart2=None): if sel_chart2 is not None: oexpr = self._coord_expression[(chart1, sel_chart2)] chg2 = dom2._coord_changes[(sel_chart2, chart2)] - self._coord_expression[(chart1, chart2)] = chart1.multifunction( - *chg2(*oexpr.expr()) - ) + self._coord_expression[(chart1, chart2)] = chart1.multifunction(*chg2(*oexpr.expr())) return self._coord_expression[(chart1, chart2)] # 2/ Trying to make a change of chart only on the start domain: # the domain's default chart is privileged: sel_chart1 = None # selected chart1 - if ( - def_chart1 in change_start - and (chart1, def_chart1) in dom1._coord_changes - ): + if def_chart1 in change_start and (chart1, def_chart1) in dom1._coord_changes: sel_chart1 = def_chart1 else: for ochart1 in change_start: @@ -1453,19 +1398,13 @@ def coord_functions(self, chart1=None, chart2=None): if sel_chart1 is not None: oexpr = self._coord_expression[(sel_chart1, chart2)] chg1 = dom1._coord_changes[(chart1, sel_chart1)] - self._coord_expression[(chart1, chart2)] = chart1.multifunction( - *oexpr(*chg1._transf.expr()) - ) + self._coord_expression[(chart1, chart2)] = chart1.multifunction(*oexpr(*chg1._transf.expr())) return self._coord_expression[(chart1, chart2)] # 3/ If this point is reached, it is necessary to perform some # coordinate change both on the start domain and the arrival one # the default charts are privileged: - if ( - (def_chart1, def_chart2) in self._coord_expression - and (chart1, def_chart1) in dom1._coord_changes - and (def_chart2, chart2) in dom2._coord_changes - ): + if (def_chart1, def_chart2) in self._coord_expression and (chart1, def_chart1) in dom1._coord_changes and (def_chart2, chart2) in dom2._coord_changes: sel_chart1 = def_chart1 sel_chart2 = def_chart2 else: @@ -1481,19 +1420,12 @@ def coord_functions(self, chart1=None, chart2=None): oexpr = self._coord_expression[(sel_chart1, sel_chart2)] chg1 = dom1._coord_changes[(chart1, sel_chart1)] chg2 = dom2._coord_changes[(sel_chart2, chart2)] - self._coord_expression[(chart1, chart2)] = chart1.multifunction( - *chg2(*oexpr(*chg1._transf.expr())) - ) + self._coord_expression[(chart1, chart2)] = chart1.multifunction(*chg2(*oexpr(*chg1._transf.expr()))) return self._coord_expression[(chart1, chart2)] # 4/ If this point is reached, the demanded value cannot be # computed - raise ValueError( - "the expression of the map in the pair " - + "({}, {})".format(chart1, chart2) - + " cannot " - + "be computed by means of known changes of charts" - ) + raise ValueError("the expression of the map in the pair " + "({}, {})".format(chart1, chart2) + " cannot " + "be computed by means of known changes of charts") return self._coord_expression[(chart1, chart2)] @@ -1691,36 +1623,22 @@ def set_expr(self, chart1, chart2, coord_functions): True """ if self._is_identity: - raise NotImplementedError( - "set_expr() must not be used for the identity map" - ) + raise NotImplementedError("set_expr() must not be used for the identity map") if chart1 not in self._domain.atlas(): - raise ValueError( - "the {}".format(chart1) - + " has not been defined on the {}".format(self._domain) - ) + raise ValueError("the {}".format(chart1) + " has not been defined on the {}".format(self._domain)) if chart2 not in self._codomain.atlas(): - raise ValueError( - "the {}".format(chart2) - + " has not been defined on the {}".format(self._codomain) - ) + raise ValueError("the {}".format(chart2) + " has not been defined on the {}".format(self._codomain)) self._coord_expression.clear() self._del_derived() n2 = self._codomain.dim() if n2 > 1: if len(coord_functions) != n2: - raise ValueError( - "{} coordinate functions must ".format(n2) + "be provided." - ) - self._coord_expression[(chart1, chart2)] = chart1.multifunction( - *coord_functions - ) + raise ValueError("{} coordinate functions must ".format(n2) + "be provided.") + self._coord_expression[(chart1, chart2)] = chart1.multifunction(*coord_functions) else: if isinstance(coord_functions, (list, tuple)): coord_functions = coord_functions[0] - self._coord_expression[(chart1, chart2)] = chart1.multifunction( - coord_functions - ) + self._coord_expression[(chart1, chart2)] = chart1.multifunction(coord_functions) set_expression = set_expr @@ -1837,33 +1755,21 @@ def add_expr(self, chart1, chart2, coord_functions): True """ if self._is_identity: - raise NotImplementedError( - "add_expr() must not be used for the identity map" - ) + raise NotImplementedError("add_expr() must not be used for the identity map") if chart1 not in self._domain.atlas(): - raise ValueError( - "the {}".format(chart1) - + " has not been defined on the {}".format(self._domain) - ) + raise ValueError("the {}".format(chart1) + " has not been defined on the {}".format(self._domain)) if chart2 not in self._codomain.atlas(): - raise ValueError( - "the {}".format(chart2) - + " has not been defined on the {}".format(self._codomain) - ) + raise ValueError("the {}".format(chart2) + " has not been defined on the {}".format(self._codomain)) self._del_derived() n2 = self._codomain.dim() if n2 > 1: if len(coord_functions) != n2: raise ValueError("{} coordinate functions must be provided".format(n2)) - self._coord_expression[(chart1, chart2)] = chart1.multifunction( - *coord_functions - ) + self._coord_expression[(chart1, chart2)] = chart1.multifunction(*coord_functions) else: if isinstance(coord_functions, (list, tuple)): coord_functions = coord_functions[0] - self._coord_expression[(chart1, chart2)] = chart1.multifunction( - coord_functions - ) + self._coord_expression[(chart1, chart2)] = chart1.multifunction(coord_functions) add_expression = add_expr @@ -1951,16 +1857,9 @@ def restrict(self, subdomain, subcodomain=None): return self if (subdomain, subcodomain) not in self._restrictions: if not subdomain.is_subset(self._domain): - raise ValueError( - "the specified domain is not a subset" - " of the domain of definition of the" - " continuous map" - ) + raise ValueError("the specified domain is not a subset" " of the domain of definition of the" " continuous map") if not subcodomain.is_subset(self._codomain): - raise ValueError( - "the specified codomain is not a subset" - " of the codomain of the continuous map" - ) + raise ValueError("the specified codomain is not a subset" " of the codomain of the continuous map") # Special case of the identity map: if self._is_identity: self._restrictions[(subdomain, subcodomain)] = subdomain.identity_map() @@ -1968,10 +1867,7 @@ def restrict(self, subdomain, subcodomain=None): # First one tries to get the restriction from a tighter domain: for dom, rst in self._restrictions.items(): - if ( - subdomain.is_subset(dom[0]) - and (subdomain, subcodomain) in rst._restrictions - ): + if subdomain.is_subset(dom[0]) and (subdomain, subcodomain) in rst._restrictions: res = rst._restrictions[(subdomain, subcodomain)] self._restrictions[(subdomain, subcodomain)] = res self._restrictions.update(res._restrictions) @@ -2023,12 +1919,8 @@ def restrict(self, subdomain, subcodomain=None): for sch2 in ch2._subcharts: if (ch1, sch2) in resu._coord_expression: del resu._coord_expression[(ch1, sch2)] - coord_functions = self._coord_expression[ - charts - ].expr() - resu._coord_expression[(ch1, ch2)] = ( - ch1.multifunction(*coord_functions) - ) + coord_functions = self._coord_expression[charts].expr() + resu._coord_expression[(ch1, ch2)] = ch1.multifunction(*coord_functions) # propagate extensions for dom, ext in self._extensions_graph.items(): # includes self diff --git a/src/sage/manifolds/continuous_map_image.py b/src/sage/manifolds/continuous_map_image.py index 2000a00f692..19ec9903063 100644 --- a/src/sage/manifolds/continuous_map_image.py +++ b/src/sage/manifolds/continuous_map_image.py @@ -39,9 +39,7 @@ class ImageManifoldSubset(ManifoldSubset): ``map`` """ - def __init__( - self, map, inverse=None, name=None, latex_name=None, domain_subset=None - ): + def __init__(self, map, inverse=None, name=None, latex_name=None, domain_subset=None): r""" Construct a manifold subset that is the image of a continuous map. diff --git a/src/sage/manifolds/differentiable/affine_connection.py b/src/sage/manifolds/differentiable/affine_connection.py index df90fe270cc..0c9143f3144 100644 --- a/src/sage/manifolds/differentiable/affine_connection.py +++ b/src/sage/manifolds/differentiable/affine_connection.py @@ -17,6 +17,7 @@ - [KN1963]_ - [ONe1983]_ """ + # ***************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger @@ -364,6 +365,7 @@ class AffineConnection(SageObject): sage: nab_copy.is_immutable() False """ + def __init__(self, domain, name, latex_name=None): r""" Construct an affine connection. @@ -382,8 +384,7 @@ def __init__(self, domain, name, latex_name=None): sage: TestSuite(nab).run() """ if not isinstance(domain, DifferentiableManifold): - raise TypeError("the first argument must be a differentiable " + - "manifold") + raise TypeError("the first argument must be a differentiable " + "manifold") self._is_immutable = False self._domain = domain self._name = name @@ -392,7 +393,7 @@ def __init__(self, domain, name, latex_name=None): else: self._latex_name = latex_name self._coefficients = {} # dict. of connection coefficients, with the - # vector frames as keys + # vector frames as keys # Initialization of derived quantities: self._init_derived() @@ -445,17 +446,17 @@ def _init_derived(self): sage: nab = M.affine_connection('nabla', latex_name=r'\nabla') sage: nab._init_derived() """ - self._restrictions = {} # dict. of restrictions of ``self`` on some - # subdomains, with the subdomains as keys + self._restrictions = {} # dict. of restrictions of ``self`` on some + # subdomains, with the subdomains as keys self._torsion = None self._riemann = None self._ricci = None self._connection_forms = {} # dict. of dict. of connection 1-forms - # (key: vector frame) + # (key: vector frame) self._torsion_forms = {} # dict. of dict. of torsion 1-forms - # (key: vector frame) + # (key: vector frame) self._curvature_forms = {} # dict. of dict. of curvature 2-forms - # (key: vector frame) + # (key: vector frame) def _del_derived(self): r""" @@ -605,9 +606,8 @@ def _new_coef(self, frame): """ from sage.manifolds.differentiable.scalarfield import DiffScalarField from sage.tensor.modules.comp import Components - return Components(frame._domain.scalar_field_algebra(), frame, 3, - start_index=self._domain._sindex, - output_formatter=DiffScalarField.coord_function) + + return Components(frame._domain.scalar_field_algebra(), frame, 3, start_index=self._domain._sindex, output_formatter=DiffScalarField.coord_function) def coef(self, frame=None): r""" @@ -677,14 +677,14 @@ def coef(self, frame=None): else: # If not, the coefficients must be computed from scratch: manif = self._domain - ev = frame # the vector frame - ef = ev.coframe() # the dual frame + ev = frame # the vector frame + ef = ev.coframe() # the dual frame gam = self._new_coef(ev) for i in manif.irange(): nab_evi = self(ev[i]) for k in manif.irange(): for j in manif.irange(): - gam[[k,i,j]] = nab_evi(ef[k],ev[j]) + gam[[k, i, j]] = nab_evi(ef[k], ev[j]) self._coefficients[frame] = gam return self._coefficients[frame] @@ -768,16 +768,14 @@ class :class:`~sage.tensor.modules.comp.Components`; if such To keep them, use the method :meth:`add_coef` instead. """ if self.is_immutable(): - raise ValueError("the coefficients of an immutable element " - "cannot be changed") + raise ValueError("the coefficients of an immutable element " "cannot be changed") if frame is None: frame = self._domain._def_frame if frame not in self._coefficients: if frame not in self._domain._frames: - raise ValueError("the {} is not".format(frame) + - " a frame on the {}".format(self._domain)) + raise ValueError("the {} is not".format(frame) + " a frame on the {}".format(self._domain)) self._coefficients[frame] = self._new_coef(frame) - self._del_derived() # deletes the derived quantities + self._del_derived() # deletes the derived quantities self.del_other_coef(frame) return self._coefficients[frame] @@ -857,16 +855,14 @@ class :class:`~sage.tensor.modules.comp.Components`; if such To delete them, use the method :meth:`set_coef` instead. """ if self.is_immutable(): - raise ValueError("the coefficients of an immutable element " - "cannot be changed") + raise ValueError("the coefficients of an immutable element " "cannot be changed") if frame is None: frame = self._domain._def_frame if frame not in self._coefficients: if frame not in self._domain._frames: - raise ValueError("the {} is not".format(frame) + - " a frame on the {}".format(self._domain)) + raise ValueError("the {} is not".format(frame) + " a frame on the {}".format(self._domain)) self._coefficients[frame] = self._new_coef(frame) - self._del_derived() # deletes the derived quantities + self._del_derived() # deletes the derived quantities return self._coefficients[frame] def del_other_coef(self, frame=None): @@ -913,8 +909,7 @@ def del_other_coef(self, frame=None): if frame is None: frame = self._domain._def_frame if frame not in self._coefficients: - raise ValueError("the coefficients w.r.t. {}".format(frame) + - " have not been defined") + raise ValueError("the coefficients w.r.t. {}".format(frame) + " have not been defined") to_be_deleted = [] for other_frame in self._coefficients: if other_frame != frame: @@ -1181,10 +1176,7 @@ def __setitem__(self, args, value): frame = self._domain._def_frame self.set_coef(frame)[args] = value - def display(self, frame=None, chart=None, symbol=None, latex_symbol=None, - index_labels=None, index_latex_labels=None, - coordinate_labels=True, only_nonzero=True, - only_nonredundant=False): + def display(self, frame=None, chart=None, symbol=None, latex_symbol=None, index_labels=None, index_latex_labels=None, coordinate_labels=True, only_nonzero=True, only_nonredundant=False): r""" Display all the connection coefficients w.r.t. to a given frame, one per line. @@ -1308,6 +1300,7 @@ def display(self, frame=None, chart=None, symbol=None, latex_symbol=None, """ from sage.manifolds.differentiable.vectorframe import CoordFrame from sage.misc.latex import latex + if frame is None: frame = self._domain.default_frame() if chart is None: @@ -1316,16 +1309,11 @@ def display(self, frame=None, chart=None, symbol=None, latex_symbol=None, symbol = 'Gam' if latex_symbol is None: latex_symbol = r'\Gamma' - if index_labels is None and isinstance(frame, CoordFrame) and \ - coordinate_labels: + if index_labels is None and isinstance(frame, CoordFrame) and coordinate_labels: ch = frame.chart() index_labels = [str(z) for z in ch[:]] index_latex_labels = [latex(z) for z in ch[:]] - return self.coef(frame=frame).display(symbol, - latex_symbol=latex_symbol, index_positions='udd', - index_labels=index_labels, index_latex_labels=index_latex_labels, - format_spec=chart, only_nonzero=only_nonzero, - only_nonredundant=only_nonredundant) + return self.coef(frame=frame).display(symbol, latex_symbol=latex_symbol, index_positions='udd', index_labels=index_labels, index_latex_labels=index_latex_labels, format_spec=chart, only_nonzero=only_nonzero, only_nonredundant=only_nonredundant) def restrict(self, subdomain): r""" @@ -1377,10 +1365,8 @@ def restrict(self, subdomain): return self if subdomain not in self._restrictions: if not subdomain.is_subset(self._domain): - raise ValueError("The provided domains is not a subset of " + - "the connection's domain.") - resu = AffineConnection(subdomain, name=self._name, - latex_name=self._latex_name) + raise ValueError("The provided domains is not a subset of " + "the connection's domain.") + resu = AffineConnection(subdomain, name=self._name, latex_name=self._latex_name) for frame in self._coefficients: for sframe in subdomain._top_frames: if sframe in frame._subframes: @@ -1450,7 +1436,7 @@ def _common_frame(self, other): for frame in self._coefficients: for oframe in other._components: if oframe in frame._subframes: - self.coef(oframe) # update the coefficients of self in oframe + self.coef(oframe) # update the coefficients of self in oframe return oframe # # 4/ Search for a common frame via one component transformation @@ -1505,9 +1491,10 @@ def __call__(self, tensor): """ from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal from sage.tensor.modules.format_utilities import format_unop_latex + dom_resu = self._domain.intersection(tensor._domain) tensor_r = tensor.restrict(dom_resu) - if tensor_r._tensor_type == (0,0): # scalar field case + if tensor_r._tensor_type == (0, 0): # scalar field case return tensor_r.differential() if isinstance(tensor_r, TensorFieldParal): return self._derive_paral(tensor_r) @@ -1521,8 +1508,7 @@ def __call__(self, tensor): else: # dom is a not a subdomain and the computation is performed: resu_rst.append(self.__call__(rst)) - tensor_type_resu = (tensor_r._tensor_type[0], - tensor_r._tensor_type[1]+1) + tensor_type_resu = (tensor_r._tensor_type[0], tensor_r._tensor_type[1] + 1) if tensor_r._name is None: name_resu = None else: @@ -1530,13 +1516,9 @@ def __call__(self, tensor): if tensor_r._latex_name is None: latex_name_resu = None else: - latex_name_resu = format_unop_latex(self._latex_name + ' ', - tensor_r._latex_name) + latex_name_resu = format_unop_latex(self._latex_name + ' ', tensor_r._latex_name) vmodule = dom_resu.vector_field_module() - resu = vmodule.tensor(tensor_type_resu, name=name_resu, - latex_name=latex_name_resu, - sym=resu_rst[0]._sym, - antisym=resu_rst[0]._antisym) + resu = vmodule.tensor(tensor_type_resu, name=name_resu, latex_name=latex_name_resu, sym=resu_rst[0]._sym, antisym=resu_rst[0]._antisym) for rst in resu_rst: resu._restrictions[rst._domain] = rst return resu @@ -1566,6 +1548,7 @@ def _derive_paral(self, tensor): from sage.manifolds.differentiable.scalarfield import DiffScalarField from sage.tensor.modules.comp import Components, CompWithSym from sage.tensor.modules.format_utilities import format_unop_latex + manif = self._domain tdom = tensor._domain frame = self._common_frame(tensor) @@ -1575,16 +1558,9 @@ def _derive_paral(self, tensor): tc = tensor._components[frame] gam = self._coefficients[frame] if not tensor._sym and not tensor._antisym: - resc = Components(tdom.scalar_field_algebra(), frame, - tensor._tensor_rank+1, - start_index=self._domain._sindex, - output_formatter=DiffScalarField.coord_function) + resc = Components(tdom.scalar_field_algebra(), frame, tensor._tensor_rank + 1, start_index=self._domain._sindex, output_formatter=DiffScalarField.coord_function) else: - resc = CompWithSym(tdom.scalar_field_algebra(), frame, - tensor._tensor_rank+1, - start_index=self._domain._sindex, - output_formatter=DiffScalarField.coord_function, - sym=tensor._sym, antisym=tensor._antisym) + resc = CompWithSym(tdom.scalar_field_algebra(), frame, tensor._tensor_rank + 1, start_index=self._domain._sindex, output_formatter=DiffScalarField.coord_function, sym=tensor._sym, antisym=tensor._antisym) n_con = tensor._tensor_type[0] n_cov = tensor._tensor_type[1] @@ -1593,20 +1569,19 @@ def _derive_paral(self, tensor): # !!!!! Seems to work only when a frame is chosen !!!!!! nproc = Parallelism().get('tensor') - lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] + lol = lambda lst, sz: [lst[i : i + sz] for i in range(0, len(lst), sz)] ind_list = list(resc.non_redundant_index_generator()) - ind_step = max(1,int(len(ind_list)/nproc/2)) - local_list = lol(ind_list,ind_step) + ind_step = max(1, int(len(ind_list) / nproc / 2)) + local_list = lol(ind_list, ind_step) # definition of the list of input parameters listParalInput = [] for ind_part in local_list: - listParalInput.append((ind_part,tc,gam,frame,n_con, - tensor._tensor_rank,manif)) + listParalInput.append((ind_part, tc, gam, frame, n_con, tensor._tensor_rank, manif)) # definition of the parallel function - @parallel(p_iter='multiprocessing',ncpus=nproc) + @parallel(p_iter='multiprocessing', ncpus=nproc) def make_CovDerivative(ind_part, tc, gam, frame, n_con, rank, manif): partial = [] for ind in ind_part: @@ -1625,11 +1600,11 @@ def make_CovDerivative(ind_part, tc, gam, frame, n_con, rank, manif): indk = list(ind0) indk[k] = i rsum -= gam[[i, ind0[k], p]] * tc[[indk]] - partial.append([ind,rsum]) + partial.append([ind, rsum]) return partial # Computation and Assignation of values - for ii,val in make_CovDerivative(listParalInput): + for ii, val in make_CovDerivative(listParalInput): for jj in val: resc[[jj[0]]] = jj[1] @@ -1661,10 +1636,8 @@ def make_CovDerivative(ind_part, tc, gam, frame, n_con, rank, manif): if tensor._latex_name is None: latex_name_resu = None else: - latex_name_resu = format_unop_latex(self._latex_name + ' ', - tensor._latex_name) - return tdom.vector_field_module().tensor_from_comp((n_con, n_cov+1), - resc, name=name_resu, latex_name=latex_name_resu) + latex_name_resu = format_unop_latex(self._latex_name + ' ', tensor._latex_name) + return tdom.vector_field_module().tensor_from_comp((n_con, n_cov + 1), resc, name=name_resu, latex_name=latex_name_resu) def torsion(self): r""" @@ -1791,8 +1764,7 @@ def torsion(self): for k in manif.irange(): for i in manif.irange(): for j in manif.irange(start=i + 1): - res[[k,i,j]] = gam[[k,j,i]] - gam[[k,i,j]] - \ - sc[[k,i,j]] + res[[k, i, j]] = gam[[k, j, i]] - gam[[k, i, j]] - sc[[k, i, j]] self._torsion = resu return self._torsion @@ -1921,7 +1893,7 @@ def riemann(self): """ if self._riemann is None: manif = self._domain - resu = manif.tensor_field(1, 3, antisym=(2,3)) + resu = manif.tensor_field(1, 3, antisym=(2, 3)) for frame, gam in self._coefficients.items(): # The computation is performed only on the top frames: for oframe in self._coefficients: @@ -1936,34 +1908,28 @@ def riemann(self): if Parallelism().get('tensor') != 1: # parallel computation nproc = Parallelism().get('tensor') - lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, - len(lst), sz)] + lol = lambda lst, sz: [lst[i : i + sz] for i in range(0, len(lst), sz)] ind_list = [] for i in manif.irange(): for j in manif.irange(): for k in manif.irange(): - for l in manif.irange(start=k+1): - ind_list.append((i,j,k,l)) - ind_step = max(1, int(len(ind_list)/nproc/2)) + for l in manif.irange(start=k + 1): + ind_list.append((i, j, k, l)) + ind_step = max(1, int(len(ind_list) / nproc / 2)) local_list = lol(ind_list, ind_step) # definition of the list of input parameters listParalInput = [] for ind_part in local_list: - listParalInput.append((frame, gam, gam_gam, gam_sc, - ind_part)) + listParalInput.append((frame, gam, gam_gam, gam_sc, ind_part)) # definition of the parallel function @parallel(p_iter='multiprocessing', ncpus=nproc) def make_Riem(frame, gam, gam_gam, gam_sc, local_list_ijkl): partial = [] for i, j, k, l in local_list_ijkl: - partial.append([i, j, k, l, - frame[k](gam[[i, j, l]]) - - frame[l](gam[[i, j, k]]) + - gam_gam[[i, k, j, l]] - - gam_gam[[i, l, j, k]] - - gam_sc[[i, j, k, l]]]) + partial.append([i, j, k, l, frame[k](gam[[i, j, l]]) - frame[l](gam[[i, j, k]]) + gam_gam[[i, k, j, l]] - gam_gam[[i, l, j, k]] - gam_sc[[i, j, k, l]]]) return partial + # Computation and assignation of values for ii, val in make_Riem(listParalInput): for jj in val: @@ -1976,12 +1942,8 @@ def make_Riem(frame, gam, gam_gam, gam_sc, local_list_ijkl): for k in manif.irange(): # antisymmetry of the Riemann tensor taken # into account by l>k: - for l in manif.irange(start=k+1): - res[i,j,k,l] = frame[k](gam[[i,j,l]]) - \ - frame[l](gam[[i,j,k]]) + \ - gam_gam[[i,k,j,l]] - \ - gam_gam[[i,l,j,k]] - \ - gam_sc[[i,j,k,l]] + for l in manif.irange(start=k + 1): + res[i, j, k, l] = frame[k](gam[[i, j, l]]) - frame[l](gam[[i, j, k]]) + gam_gam[[i, k, j, l]] - gam_gam[[i, l, j, k]] - gam_sc[[i, j, k, l]] self._riemann = resu return self._riemann @@ -2029,7 +1991,7 @@ def ricci(self): True """ if self._ricci is None: - self._ricci = self.riemann().trace(0,2) + self._ricci = self.riemann().trace(0, 2) return self._ricci def connection_form(self, i, j, frame=None): @@ -2158,18 +2120,15 @@ def connection_form(self, i, j, frame=None): coef_frame = self.coef(frame) for i1 in self._domain.irange(): for j1 in self._domain.irange(): - name = self._name + " connection 1-form (" + str(i1) + \ - "," + str(j1) + ")" - latex_name = r"\omega^" + str(i1) + r"_{\ \, " + \ - str(j1) + "}" - omega = frame_dom.one_form(name=name, - latex_name=latex_name) + name = self._name + " connection 1-form (" + str(i1) + "," + str(j1) + ")" + latex_name = r"\omega^" + str(i1) + r"_{\ \, " + str(j1) + "}" + omega = frame_dom.one_form(name=name, latex_name=latex_name) comega = omega.set_comp(frame) for k in self._domain.irange(): - comega[k] = coef_frame[[i1,j1,k]] - forms[(i1,j1)] = omega + comega[k] = coef_frame[[i1, j1, k]] + forms[(i1, j1)] = omega self._connection_forms[frame] = forms - return self._connection_forms[frame][(i,j)] + return self._connection_forms[frame][(i, j)] def torsion_form(self, i, frame=None): r""" @@ -2260,15 +2219,13 @@ def torsion_form(self, i, frame=None): frame_dom = frame.domain() torsion_comp = self.torsion().comp(frame) for i1 in self._domain.irange(): - name = "torsion ({}) of connection ".format(i1) + \ - self._name + " w.r.t. {}".format(frame) + name = "torsion ({}) of connection ".format(i1) + self._name + " w.r.t. {}".format(frame) latex_name = r"\theta^" + str(i1) - theta = frame_dom.diff_form(2, name=name, - latex_name=latex_name) + theta = frame_dom.diff_form(2, name=name, latex_name=latex_name) ctheta = theta.set_comp(frame) for k in self._domain.irange(): - for l in self._domain.irange(start=k+1): - ctheta[k,l] = torsion_comp[[i1,k,l]] + for l in self._domain.irange(start=k + 1): + ctheta[k, l] = torsion_comp[[i1, k, l]] forms[i1] = theta self._torsion_forms[frame] = forms return self._torsion_forms[frame][i] @@ -2368,17 +2325,14 @@ def curvature_form(self, i, j, frame=None): riemann_comp = self.riemann().comp(frame) for i1 in self._domain.irange(): for j1 in self._domain.irange(): - name = "curvature ({},{}) of connection ".format(i1,j1) + \ - self._name + " w.r.t. {}".format(frame) - latex_name = r"\Omega^" + str(i1) + r"_{\ \, " + \ - str(j1) + "}" - omega = frame_dom.diff_form(2, name=name, - latex_name=latex_name) + name = "curvature ({},{}) of connection ".format(i1, j1) + self._name + " w.r.t. {}".format(frame) + latex_name = r"\Omega^" + str(i1) + r"_{\ \, " + str(j1) + "}" + omega = frame_dom.diff_form(2, name=name, latex_name=latex_name) comega = omega.set_comp(frame) for k in self._domain.irange(): - for l in self._domain.irange(start=k+1): - comega[k,l] = riemann_comp[[i1,j1,k,l]] - forms[(i1,j1)] = omega + for l in self._domain.irange(start=k + 1): + comega[k, l] = riemann_comp[[i1, j1, k, l]] + forms[(i1, j1)] = omega self._curvature_forms[frame] = forms return self._curvature_forms[frame][(i, j)] @@ -2469,6 +2423,5 @@ def __hash__(self): 2 """ if self.is_mutable(): - raise ValueError('element must be immutable in order to be ' - 'hashable') + raise ValueError('element must be immutable in order to be ' 'hashable') return hash((type(self).__name__, self._domain)) diff --git a/src/sage/manifolds/differentiable/automorphismfield.py b/src/sage/manifolds/differentiable/automorphismfield.py index 18d1ea94652..b9bfdbd95f4 100644 --- a/src/sage/manifolds/differentiable/automorphismfield.py +++ b/src/sage/manifolds/differentiable/automorphismfield.py @@ -138,6 +138,7 @@ class AutomorphismField(TensorField): sage: ia is ~a True """ + def __init__(self, vector_field_module, name=None, latex_name=None): r""" Construct a field of tangent-space automorphisms on a @@ -183,11 +184,9 @@ def __init__(self, vector_field_module, name=None, latex_name=None): Fix ``_test_pickling`` (in the superclass :class:`TensorField`). """ - TensorField.__init__(self, vector_field_module, (1,1), name=name, - latex_name=latex_name, - parent=vector_field_module.general_linear_group()) - self._is_identity = False # a priori - self._init_derived() # initialization of derived quantities + TensorField.__init__(self, vector_field_module, (1, 1), name=name, latex_name=latex_name, parent=vector_field_module.general_linear_group()) + self._is_identity = False # a priori + self._init_derived() # initialization of derived quantities def _repr_(self): r""" @@ -481,7 +480,7 @@ def __call__(self, *arg): if len(arg) == 1: # The identity map acting as such, on a vector field: vector = arg[0] - if vector._tensor_type != (1,0): + if vector._tensor_type != (1, 0): raise TypeError("the argument must be a vector field") dom = self._domain.intersection(vector._domain) return vector.restrict(dom) @@ -490,15 +489,14 @@ def __call__(self, *arg): # (1-form, vector field), returning a scalar field: oneform = arg[0] vector = arg[1] - dom = self._domain.intersection( - oneform._domain).intersection(vector._domain) + dom = self._domain.intersection(oneform._domain).intersection(vector._domain) return oneform.restrict(dom)(vector.restrict(dom)) raise TypeError("wrong number of arguments") # Generic case if len(arg) == 1: # The field of automorphisms acting on a vector field: vector = arg[0] - if vector._tensor_type != (1,0): + if vector._tensor_type != (1, 0): raise TypeError("the argument must be a vector field") dom = self._domain.intersection(vector._domain) vector_dom = vector.restrict(dom) @@ -508,8 +506,7 @@ def __call__(self, *arg): if self._name is not None and vector._name is not None: resu._name = self._name + "(" + vector._name + ")" if self._latex_name is not None and vector._latex_name is not None: - resu._latex_name = self._latex_name + r"\left(" + \ - vector._latex_name + r"\right)" + resu._latex_name = self._latex_name + r"\left(" + vector._latex_name + r"\right)" for sdom, automorph in self._restrictions.items(): resu._restrictions[sdom] = automorph(vector_dom.restrict(sdom)) return resu @@ -624,6 +621,7 @@ def __invert__(self): return self if self._inverse is None: from sage.tensor.modules.format_utilities import is_atomic + if self._name is None: inv_name = None else: @@ -637,10 +635,8 @@ def __invert__(self): if is_atomic(self._latex_name, ['\\circ', '\\otimes']): inv_latex_name = self._latex_name + r'^{-1}' else: - inv_latex_name = r'\left(' + self._latex_name + \ - r'\right)^{-1}' - self._inverse = self._vmodule.automorphism(name=inv_name, - latex_name=inv_latex_name) + inv_latex_name = r'\left(' + self._latex_name + r'\right)^{-1}' + self._inverse = self._vmodule.automorphism(name=inv_name, latex_name=inv_latex_name) for dom, rst in self._restrictions.items(): self._inverse._restrictions[dom] = rst.inverse() return self._inverse @@ -713,8 +709,7 @@ def _mul_(self, other): # General case: resu = type(self)(self._vmodule) for dom in self._common_subdomains(other): - resu._restrictions[dom] = (self._restrictions[dom] - * other._restrictions[dom]) + resu._restrictions[dom] = self._restrictions[dom] * other._restrictions[dom] return resu #### End of MultiplicativeGroupElement methods #### @@ -888,20 +883,18 @@ def restrict(self, subdomain, dest_map=None): return TensorField.restrict(self, subdomain, dest_map=dest_map) # Special case of the immutable identity map: if not subdomain.is_subset(self._domain): - raise ValueError("the provided domain is not a subset of " + - "the field's domain") + raise ValueError("the provided domain is not a subset of " + "the field's domain") if dest_map is None: dest_map = self._vmodule._dest_map.restrict(subdomain) elif not dest_map._codomain.is_subset(self._ambient_domain): - raise ValueError("the argument 'dest_map' is not compatible " + - "with the ambient domain of " + - "the {}".format(self)) + raise ValueError("the argument 'dest_map' is not compatible " + "with the ambient domain of " + "the {}".format(self)) smodule = subdomain.vector_field_module(dest_map=dest_map) self._restrictions[subdomain] = smodule.identity_map() return self._restrictions[subdomain] -#****************************************************************************** +# ****************************************************************************** + class AutomorphismFieldParal(FreeModuleAutomorphism, TensorFieldParal): r""" @@ -986,6 +979,7 @@ class AutomorphismFieldParal(FreeModuleAutomorphism, TensorFieldParal): sage: inv is ~rot True """ + def __init__(self, vector_field_module, name=None, latex_name=None): r""" Construct a field of tangent-space automorphisms. @@ -1020,13 +1014,12 @@ def __init__(self, vector_field_module, name=None, latex_name=None): [0 1] sage: TestSuite(b).run() """ - FreeModuleAutomorphism.__init__(self, vector_field_module, - name=name, latex_name=latex_name) + FreeModuleAutomorphism.__init__(self, vector_field_module, name=name, latex_name=latex_name) # TensorFieldParal attributes: self._vmodule = vector_field_module self._domain = vector_field_module._domain self._ambient_domain = vector_field_module._ambient_domain - self._is_identity = False # a priori + self._is_identity = False # a priori # Initialization of derived quantities: TensorFieldParal._init_derived(self) @@ -1076,7 +1069,7 @@ def _del_derived(self, del_restrictions=True): FreeModuleAutomorphism._del_derived(self) TensorFieldParal._del_derived(self, del_restrictions=del_restrictions) - # Method _new_instance() is defined in mother class FreeModuleAutomorphism + # Method _new_instance() is defined in mother class FreeModuleAutomorphism def __call__(self, *arg): r""" @@ -1116,18 +1109,14 @@ def __call__(self, *arg): # vector field) vector = arg[0] dom = self._domain.intersection(vector._domain) - return FreeModuleAutomorphism.__call__(self.restrict(dom), - vector.restrict(dom)) + return FreeModuleAutomorphism.__call__(self.restrict(dom), vector.restrict(dom)) if len(arg) == 2: # the automorphism acting as a type (1,1) tensor on a pair # (1-form, vector field), returning a scalar field: oneform = arg[0] vector = arg[1] - dom = self._domain.intersection(oneform._domain).intersection( - vector._domain) - return FreeModuleAutomorphism.__call__(self.restrict(dom), - oneform.restrict(dom), - vector.restrict(dom)) + dom = self._domain.intersection(oneform._domain).intersection(vector._domain) + return FreeModuleAutomorphism.__call__(self.restrict(dom), oneform.restrict(dom), vector.restrict(dom)) raise TypeError("wrong number of arguments") def __invert__(self): @@ -1168,10 +1157,12 @@ def __invert__(self): from sage.manifolds.differentiable.vectorframe import CoordFrame from sage.matrix.constructor import matrix from sage.tensor.modules.comp import Components + if self._is_identity: return self if self._inverse is None: from sage.tensor.modules.format_utilities import is_atomic + if self._name is None: inv_name = None else: @@ -1185,13 +1176,11 @@ def __invert__(self): if is_atomic(self._latex_name, ['\\circ', '\\otimes']): inv_latex_name = self._latex_name + r'^{-1}' else: - inv_latex_name = r'\left(' + self._latex_name + \ - r'\right)^{-1}' + inv_latex_name = r'\left(' + self._latex_name + r'\right)^{-1}' fmodule = self._fmodule si = fmodule._sindex nsi = fmodule._rank + si - self._inverse = fmodule.automorphism(name=inv_name, - latex_name=inv_latex_name) + self._inverse = fmodule.automorphism(name=inv_name, latex_name=inv_latex_name) for frame in self._components: if isinstance(frame, CoordFrame): chart = frame._chart @@ -1199,17 +1188,14 @@ def __invert__(self): chart = self._domain._def_chart # ! # to be improved try: # TODO: do the computation without the 'SR' enforcement - mat_self = matrix( - [[self.comp(frame)[i, j, chart].expr(method='SR') - for j in range(si, nsi)] for i in range(si, nsi)]) + mat_self = matrix([[self.comp(frame)[i, j, chart].expr(method='SR') for j in range(si, nsi)] for i in range(si, nsi)]) except (KeyError, ValueError): continue mat_inv = mat_self.inverse() - cinv = Components(fmodule._ring, frame, 2, start_index=si, - output_formatter=fmodule._output_formatter) + cinv = Components(fmodule._ring, frame, 2, start_index=si, output_formatter=fmodule._output_formatter) for i in range(si, nsi): for j in range(si, nsi): - val = chart.simplify(mat_inv[i-si,j-si], method='SR') + val = chart.simplify(mat_inv[i - si, j - si], method='SR') cinv[i, j] = {chart: val} self._inverse._components[frame] = cinv return self._inverse @@ -1275,18 +1261,14 @@ def restrict(self, subdomain, dest_map=None): return self if subdomain not in self._restrictions: if not self._is_identity: - return TensorFieldParal.restrict(self, subdomain, - dest_map=dest_map) + return TensorFieldParal.restrict(self, subdomain, dest_map=dest_map) # Special case of the identity map: if not subdomain.is_subset(self._domain): - raise ValueError("the provided domain is not a subset of " + - "the field's domain.") + raise ValueError("the provided domain is not a subset of " + "the field's domain.") if dest_map is None: dest_map = self._fmodule._dest_map.restrict(subdomain) elif not dest_map._codomain.is_subset(self._ambient_domain): - raise ValueError("the argument 'dest_map' is not compatible " + - "with the ambient domain of " + - "the {}".format(self)) + raise ValueError("the argument 'dest_map' is not compatible " + "with the ambient domain of " + "the {}".format(self)) smodule = subdomain.vector_field_module(dest_map=dest_map) self._restrictions[subdomain] = smodule.identity_map() return self._restrictions[subdomain] @@ -1361,8 +1343,7 @@ def at(self, point): True """ if point not in self._domain: - raise TypeError("the {} is not in the domain of the {}".format( - point, self)) + raise TypeError("the {} is not in the domain of the {}".format(point, self)) dest_map = self._fmodule._dest_map if dest_map.is_identity(): amb_point = point diff --git a/src/sage/manifolds/differentiable/automorphismfield_group.py b/src/sage/manifolds/differentiable/automorphismfield_group.py index 45a2fad087a..4ffa1fd839e 100644 --- a/src/sage/manifolds/differentiable/automorphismfield_group.py +++ b/src/sage/manifolds/differentiable/automorphismfield_group.py @@ -28,7 +28,7 @@ - Chap. 15 of [God1968]_ """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2016 Travis Scrimshaw # @@ -36,7 +36,7 @@ # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.groups import Groups from sage.manifolds.differentiable.automorphismfield import ( @@ -172,15 +172,13 @@ def __init__(self, vector_field_module): :class:`sage.manifolds.differentiable.tensorfield.TensorField`. """ if not isinstance(vector_field_module, VectorFieldModule): - raise TypeError("{} is not a module of vector fields".format( - vector_field_module)) + raise TypeError("{} is not a module of vector fields".format(vector_field_module)) Parent.__init__(self, category=Groups()) self._vmodule = vector_field_module #### Parent methods #### - def _element_constructor_(self, comp=[], frame=None, name=None, - latex_name=None): + def _element_constructor_(self, comp=[], frame=None, name=None, latex_name=None): r""" Construct a field of tangent-space automorphisms. @@ -212,11 +210,9 @@ def _element_constructor_(self, comp=[], frame=None, name=None, elif comp == 1: return self.one() if not isinstance(comp, (list, tuple)): - raise TypeError("cannot convert the {} ".format(comp) + - "to an element of {}".format(self)) + raise TypeError("cannot convert the {} ".format(comp) + "to an element of {}".format(self)) # standard construction - resu = self.element_class(self._vmodule, name=name, - latex_name=latex_name) + resu = self.element_class(self._vmodule, name=name, latex_name=latex_name) if comp: resu.set_comp(frame)[:] = comp return resu @@ -306,8 +302,7 @@ def one(self): for dom in resu._domain._subsets: if dom.is_manifestly_parallelizable(): fmodule = dom.vector_field_module() - resu._restrictions[dom] = fmodule.identity_map(name='Id', - latex_name=r'\mathrm{Id}') + resu._restrictions[dom] = fmodule.identity_map(name='Id', latex_name=r'\mathrm{Id}') resu._is_identity = True resu.set_immutable() return resu @@ -348,6 +343,7 @@ def _latex_(self): \mathrm{GL}\left( \mathfrak{X}\left(M\right) \right) """ from sage.misc.latex import latex + return r"\mathrm{GL}\left(" + latex(self._vmodule) + r"\right)" def base_module(self): @@ -382,7 +378,8 @@ def base_module(self): return self._vmodule -#****************************************************************************** +# ****************************************************************************** + class AutomorphismFieldParalGroup(FreeModuleLinearGroup): r""" @@ -598,6 +595,5 @@ def __init__(self, vector_field_module): sage: TestSuite(G).run() """ if not isinstance(vector_field_module, VectorFieldFreeModule): - raise TypeError("{} is not a free module of vector fields".format( - vector_field_module)) + raise TypeError("{} is not a free module of vector fields".format(vector_field_module)) FreeModuleLinearGroup.__init__(self, vector_field_module) diff --git a/src/sage/manifolds/differentiable/bundle_connection.py b/src/sage/manifolds/differentiable/bundle_connection.py index d578cf5deaf..4803dc1b253 100644 --- a/src/sage/manifolds/differentiable/bundle_connection.py +++ b/src/sage/manifolds/differentiable/bundle_connection.py @@ -29,6 +29,7 @@ - Michael Jung (2019) : initial version """ + # ****************************************************************************** # Copyright (C) 2019 Michael Jung # @@ -258,8 +259,7 @@ def __init__(self, vbundle, name, latex_name=None): sage: TestSuite(nab).run() """ if not isinstance(vbundle, DifferentiableVectorBundle): - raise TypeError("the first argument must be a differentiable " + - "vector bundle") + raise TypeError("the first argument must be a differentiable " + "vector bundle") Mutability.__init__(self) self._vbundle = vbundle self._domain = vbundle.base_space() @@ -391,8 +391,7 @@ def __eq__(self, other): if frame not in other._connection_forms: return False for ind in self._connection_forms[frame]: - if (other._connection_forms[frame][ind] != - self._connection_forms[frame][ind]): + if other._connection_forms[frame][ind] != self._connection_forms[frame][ind]: return False return True @@ -653,6 +652,7 @@ def __call__(self, v, s): """ from sage.manifolds.section import TrivialSection from sage.tensor.modules.format_utilities import format_unop_latex + if isinstance(s, TrivialSection): return self._derive_trivial(v, s) # Resulting section @@ -667,8 +667,7 @@ def __call__(self, v, s): else: nab_v_latex = self._latex_name + '_{' + v._latex_name + '} ' latex_name_resu = format_unop_latex(nab_v_latex, s._latex_name) - resu = vb.section(domain=dom, name=name_resu, - latex_name=latex_name_resu) + resu = vb.section(domain=dom, name=name_resu, latex_name=latex_name_resu) # gluing process for dom, rst in s._restrictions.items(): # the computation is performed only if dom is not a subdomain @@ -720,6 +719,7 @@ def _derive_trivial(self, v, s): raise ValueError("no local frame found for the computation") # Resulting section from sage.tensor.modules.format_utilities import format_unop_latex + if s._name is None or v._name is None: name_resu = None else: @@ -729,13 +729,11 @@ def _derive_trivial(self, v, s): else: nab_v_latex = self._latex_name + '_{' + v._latex_name + '} ' latex_name_resu = format_unop_latex(nab_v_latex, s._latex_name) - res = vb.section(domain=dom, name=name_resu, - latex_name=latex_name_resu) + res = vb.section(domain=dom, name=name_resu, latex_name=latex_name_resu) for j in vb.irange(): ds_comp = s[[frame, j]].differential() res_comp = ds_comp(v) - res_comp += sum(s[[frame, i]] * self[frame, i, j](v) - for i in vb.irange()) + res_comp += sum(s[[frame, i]] * self[frame, i, j](v) for i in vb.irange()) res[frame, j] = res_comp return res @@ -816,8 +814,7 @@ def add_connection_form(self, i, j, frame=None): # Are the components already known? if frame not in self._connection_forms: if frame not in self._vbundle._frames: - raise ValueError("the {} is not".format(frame) + - " a frame on the {}".format(self._domain)) + raise ValueError("the {} is not".format(frame) + " a frame on the {}".format(self._domain)) self._connection_forms[frame] = self._new_forms(frame) self._del_derived() # deletes the derived quantities return self._connection_forms[frame][(i, j)] @@ -947,8 +944,7 @@ def del_other_forms(self, frame=None): if frame is None: raise ValueError("a frame must be provided") if frame not in self._connection_forms: - raise ValueError("the coefficients w.r.t. {}".format(frame) + - " have not been defined") + raise ValueError("the coefficients w.r.t. {}".format(frame) + " have not been defined") to_be_deleted = [] for other_frame in self._connection_forms: if other_frame != frame: @@ -1004,14 +1000,11 @@ def curvature_form(self, i, j, frame=None): if frame not in self._curvature_forms: self._curvature_forms[frame] = {} if (i, j) not in self._curvature_forms[frame]: - name = "curvature ({},{}) of bundle connection ".format(i, j) + \ - self._name + " w.r.t. {}".format(frame) - latex_name = r"\Omega^" + str(i) + r"_{\ \, " + \ - str(j) + "}" + name = "curvature ({},{}) of bundle connection ".format(i, j) + self._name + " w.r.t. {}".format(frame) + latex_name = r"\Omega^" + str(i) + r"_{\ \, " + str(j) + "}" omega = self.connection_form curv_form = omega(i, j, frame).exterior_derivative() - curv_form += sum(omega(k, j, frame).wedge(omega(i, k, frame)) - for k in self._vbundle.irange()) + curv_form += sum(omega(k, j, frame).wedge(omega(i, k, frame)) for k in self._vbundle.irange()) curv_form.set_name(name=name, latex_name=latex_name) self._curvature_forms[frame][(i, j)] = curv_form return self._curvature_forms[frame][(i, j)] @@ -1116,10 +1109,8 @@ def __getitem__(self, args): indices = args if isinstance(indices, slice): if indices.start is None and indices.stop is None: - return [[self.connection_form(i, j, frame=frame) - for j in vb.irange()] for i in vb.irange()] - raise NotImplementedError("[start:stop] syntax not " - "implemented") + return [[self.connection_form(i, j, frame=frame) for j in vb.irange()] for i in vb.irange()] + raise NotImplementedError("[start:stop] syntax not " "implemented") if len(indices) != 2: raise ValueError("index must be a pair of integers") (i, j) = indices @@ -1210,31 +1201,25 @@ def __setitem__(self, args, value): for j in vb.irange(): self[frame, i, j] = 0 elif not isinstance(value, (list, tuple)): - raise TypeError("in case of [:] syntax, zero or a " - "list/tuple as value should be provided") + raise TypeError("in case of [:] syntax, zero or a " "list/tuple as value should be provided") elif any(not isinstance(row, (list, tuple)) for row in value): - raise TypeError("in case of [:] syntax, the list/tuple " - "of value must contain lists/tuples") + raise TypeError("in case of [:] syntax, the list/tuple " "of value must contain lists/tuples") else: # check lengths: rk = vb._rank if len(value) != rk: - raise ValueError("value must have " - "length {}".format(rk)) + raise ValueError("value must have " "length {}".format(rk)) if any(len(row) != rk for row in value): - raise ValueError("lists in value must have length " - "{}".format(rk)) + raise ValueError("lists in value must have length " "{}".format(rk)) # perform designation: sind = vb._base_space._sindex for i in vb.irange(): for j in vb.irange(): self[frame, i, j] = value[i - sind][j - sind] else: - raise NotImplementedError("[start:stop] syntax not " - "implemented") + raise NotImplementedError("[start:stop] syntax not " "implemented") - def display(self, frame=None, vector_frame=None, chart=None, - only_nonzero=True): + def display(self, frame=None, vector_frame=None, chart=None, only_nonzero=True): r""" Display all the connection 1-forms w.r.t. to a given local frame, one per line. diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index e7663861953..2ce1e014b03 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -328,6 +328,7 @@ class CharacteristicCohomologyClassRingElement(IndexedFreeModuleElement): sage: A == 1 - p1/24 + (7*p1^2-4*p2)/5760 + (44*p1*p2-31*p1^3-16*p3)/967680 True """ + def __init__(self, parent, x, name=None, latex_name=None): r""" Construct a characteristic cohomology class. @@ -345,7 +346,7 @@ def __init__(self, parent, x, name=None, latex_name=None): else: self._latex_name = latex_name self._mixed_forms = {} # dict. of characteristic forms of self - # (key: bundle connection) + # (key: bundle connection) super().__init__(parent, x) def _repr_(self): @@ -474,12 +475,10 @@ def get_form(self, nab): algorithm = parent._algorithm grading = parent.print_options()['sorting_key'] - res = [dom.diff_form_module(i).zero() - for i in range(dom._dim + 1)] + res = [dom.diff_form_module(i).zero() for i in range(dom._dim + 1)] for ind, c in self: deg = grading(ind) - gen_pow = [algorithm.get_gen_pow(nab, i, ind[i]) - for i in range(len(ind))] + gen_pow = [algorithm.get_gen_pow(nab, i, ind[i]) for i in range(len(ind))] res[deg] += c * reduce(lambda x, y: x.wedge(y), gen_pow) res = A(res) # convert result into mixed form @@ -508,8 +507,7 @@ def get_form(self, nab): comp_name = name + f'_{i}' + append_name comp_latex_name = latex_name + r'_{' + str(i) + '}' comp_latex_name += append_latex_name - res[step * i].set_name(name=comp_name, - latex_name=comp_latex_name) + res[step * i].set_name(name=comp_name, latex_name=comp_latex_name) # set global names res._name = name + append_name @@ -731,6 +729,7 @@ class CharacteristicCohomologyClassRing(FiniteGCAlgebra): over the 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean space E^3,) """ + Element = CharacteristicCohomologyClassRingElement def __init__(self, base, vbundle): @@ -766,18 +765,14 @@ def __init__(self, base, vbundle): self._algorithm = PontryaginEulerAlgorithm() # TODO: add relation e^2=p_k for dim=2*k else: - raise TypeError(f'Characteristic cohomology classes not supported ' - f'for vector bundles with ' - f'field type {vbundle._field_type}') + raise TypeError(f'Characteristic cohomology classes not supported ' f'for vector bundles with ' f'field type {vbundle._field_type}') if not names or not degrees: raise ValueError('cannot find any generators') names = tuple(names) # hashable degrees = tuple(degrees) # hashable - super().__init__(base=base, names=names, degrees=degrees, - max_degree=dim, mul_symbol='⌣', - mul_latex_symbol=r'\smile') + super().__init__(base=base, names=names, degrees=degrees, max_degree=dim, mul_symbol='⌣', mul_latex_symbol=r'\smile') def _element_constructor_(self, x, **kwargs): r""" @@ -807,16 +802,12 @@ def _element_constructor_(self, x, **kwargs): d = x._monomial_coefficients # x is an element of the basis enumerated set; # This is a very ugly way of testing this - elif ((hasattr(self._indices, 'element_class') and - isinstance(self._indices.element_class, type) and - isinstance(x, self._indices.element_class)) or - self.parent()(x) == self._indices): + elif (hasattr(self._indices, 'element_class') and isinstance(self._indices.element_class, type) and isinstance(x, self._indices.element_class)) or self.parent()(x) == self._indices: d = {x: R.one()} elif x in self._indices: d = {self._indices(x): R.one()} else: - raise TypeError(f"do not know how to make x (= {x}) " - f"an element of self (={self})") + raise TypeError(f"do not know how to make x (= {x}) " f"an element of self (={self})") name, latex_name = kwargs.get('name'), kwargs.get('latex_name') return self.element_class(self, d, name=name, latex_name=latex_name) @@ -920,8 +911,7 @@ def _build_element(self, *args, **kwargs): if latex_name is None: latex_name = r'\mathrm{ch}' class_type = 'additive' - coeff = [1 / factorial(k) for k in - range(dim // 2 + 1)] # exp(x) + coeff = [1 / factorial(k) for k in range(dim // 2 + 1)] # exp(x) val = P(coeff) elif val == 'Todd': if vbundle._field_type != 'complex': @@ -933,8 +923,7 @@ def _build_element(self, *args, **kwargs): class_type = 'multiplicative' val = 1 + x / 2 for k in range(1, dim // 2 + 1): - val += (-1) ** (k + 1) / factorial(2 * k) * bernoulli( - 2 * k) * x ** (2 * k) + val += (-1) ** (k + 1) / factorial(2 * k) * bernoulli(2 * k) * x ** (2 * k) elif val == 'Hirzebruch': if vbundle._field_type != 'real': raise ValueError(f'Hirzebruch class not defined on {vbundle}') @@ -943,8 +932,7 @@ def _build_element(self, *args, **kwargs): if latex_name is None: latex_name = 'L' class_type = 'multiplicative' - coeff = [2 ** (2 * k) * bernoulli(2 * k) / factorial(2 * k) - for k in range(dim // 4 + 1)] + coeff = [2 ** (2 * k) * bernoulli(2 * k) / factorial(2 * k) for k in range(dim // 4 + 1)] val = P(coeff) elif val == 'AHat': if vbundle._field_type != 'real': @@ -954,9 +942,7 @@ def _build_element(self, *args, **kwargs): if latex_name is None: latex_name = r'\hat{A}' class_type = 'multiplicative' - coeff = [- (2 ** (2 * k) - 2) / 2 ** (2 * k) * bernoulli( - 2 * k) / factorial(2 * k) - for k in range(dim // 4 + 1)] + coeff = [-(2 ** (2 * k) - 2) / 2 ** (2 * k) * bernoulli(2 * k) / factorial(2 * k) for k in range(dim // 4 + 1)] val = P(coeff) elif val == 'Euler': if vbundle._field_type != 'real' or not vbundle.has_orientation(): @@ -985,8 +971,7 @@ def _build_element(self, *args, **kwargs): # turn polynomial into a characteristic cohomology class via sequences if isinstance(val, Polynomial): if class_type is None: - raise TypeError(f'class_type must be stated if {val} ' - f'is a polynomial') + raise TypeError(f'class_type must be stated if {val} ' f'is a polynomial') n = self.ngens() s = 0 # shift; important in case of Euler class generator if self._algorithm is PontryaginEulerAlgorithm(): @@ -1048,6 +1033,7 @@ def _repr_(self): # ALGORITHMS # ***************************************************************************** + def multiplicative_sequence(q, n=None): r""" Turn the polynomial ``q`` into its multiplicative sequence. @@ -1097,9 +1083,7 @@ def multiplicative_sequence(q, n=None): m = Sym.m() # Get the multiplicative sequence in the monomial basis: - mon_pol = m._from_dict({p: prod(q[i] for i in p) - for k in range(n + 1) - for p in Partitions(k)}) + mon_pol = m._from_dict({p: prod(q[i] for i in p) for k in range(n + 1) for p in Partitions(k)}) return Sym.e()(mon_pol) @@ -1222,6 +1206,7 @@ class Algorithm_generic(SageObject): sage: algorithm.get_gen_pow Cached version of """ + @cached_method def get(self, nab): r""" @@ -1262,13 +1247,11 @@ def get(self, nab): dom = nab._domain res = [] # will be specified within first iteration for frame in dom._get_min_covering(nab._coefficients): - cmat = [[nab.curvature_form(i, j, frame) for j in vbundle.irange()] - for i in vbundle.irange()] + cmat = [[nab.curvature_form(i, j, frame) for j in vbundle.irange()] for i in vbundle.irange()] res_loc = self.get_local(cmat) if not res: # until now, degrees of generators were unknown - res = [dom.diff_form(loc_form.degree()) - for loc_form in res_loc] + res = [dom.diff_form(loc_form.degree()) for loc_form in res_loc] for form, loc_form in zip(res, res_loc): form.set_restriction(loc_form) # TODO: make `res` immutable? @@ -1385,6 +1368,7 @@ class ChernAlgorithm(Singleton, Algorithm_generic): sage: algorithm.get_gen_pow(nab, 0, 1) == algorithm.get(nab)[0] True """ + def get_local(self, cmat): r""" Return the local Chern forms w.r.t. a given curvature form matrix. @@ -1444,8 +1428,7 @@ def get_local(self, cmat): for i in range(rk): m[i][i] += c fac *= I / (2 * pi) - m = [[sum(cmat[i][l].wedge(m[l][j]) for l in range(rk)) - for j in range(rk)] for i in range(rk)] + m = [[sum(cmat[i][l].wedge(m[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] res.append(-fac * sum(m[i][i] for i in range(rk)) / ran) return res @@ -1471,6 +1454,7 @@ class PontryaginAlgorithm(Singleton, Algorithm_generic): sage: p1.display() # long time 0 """ + def get_local(self, cmat): r""" Return the local Pontryagin forms w.r.t. a given curvature form matrix. @@ -1513,17 +1497,14 @@ def get_local(self, cmat): return [] # nothing to compute fac = 1 / (2 * pi) ** 2 res = [] - m = cmat2 = [[sum(cmat[i][l].wedge(cmat[l][j]) - for l in range(rk)) - for j in range(rk)] for i in range(rk)] + m = cmat2 = [[sum(cmat[i][l].wedge(cmat[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] for k in range(1, ran): c = -sum(m[i][i] for i in range(rk)) / (2 * k) res.append(fac * c) for i in range(rk): m[i][i] += c fac *= 1 / (2 * pi) ** 2 - m = [[sum(cmat2[i][l].wedge(m[l][j]) for l in range(rk)) - for j in range(rk)] for i in range(rk)] + m = [[sum(cmat2[i][l].wedge(m[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] res.append(-fac * sum(m[i][i] for i in range(rk)) / (2 * ran)) return res @@ -1550,6 +1531,7 @@ class EulerAlgorithm(Singleton, Algorithm_generic): sage: algorithm.get(nab)[0].display() 0 """ + @cached_method def get(self, nab): r""" @@ -1608,24 +1590,19 @@ def get(self, nab): - [Baer2020]_ """ if not isinstance(nab, LeviCivitaConnection): - raise TypeError('Euler forms are currently only supported for ' - 'Levi-Civita connections') + raise TypeError('Euler forms are currently only supported for ' 'Levi-Civita connections') dom = nab._domain vbundle = dom.tangent_bundle() rk = vbundle._rank if not vbundle.has_orientation(): - raise ValueError('Euler forms can only be defined for orientable ' - 'vector bundles') + raise ValueError('Euler forms can only be defined for orientable ' 'vector bundles') if rk % 2 != 0: - raise ValueError('Euler forms are currently only supported for ' - 'vector bundles with even rank') + raise ValueError('Euler forms are currently only supported for ' 'vector bundles with even rank') res = dom.diff_form(rk) g = nab._metric for frame in dom._get_min_covering(vbundle.orientation()): # (G_s * Ω_s)_ij = g(R(.,.)s_i, s_j) - gcmat = [[sum(g[[frame, i, j]] * nab.curvature_form(j, k, frame) - for j in vbundle.irange()) - for k in vbundle.irange()] for i in vbundle.irange()] + gcmat = [[sum(g[[frame, i, j]] * nab.curvature_form(j, k, frame) for j in vbundle.irange()) for k in vbundle.irange()] for i in vbundle.irange()] [res_loc] = self.get_local(gcmat) # Pf(G_s * Ω_s) mod const. # e = 1 / sqrt(|det(G_s)|) * Pf(G_s * Ω_s) mod const. det = g.det(frame) @@ -1698,8 +1675,7 @@ def get_local(self, cmat): e = -sum(m[i][i] for i in range(rk)) / (2 * k) for i in range(rk): m[i][i] += e - m = [[sum(a[i][l].wedge(m[l][j]) for l in range(rk)) - for j in range(rk)] for i in range(rk)] + m = [[sum(a[i][l].wedge(m[l][j]) for l in range(rk)) for j in range(rk)] for i in range(rk)] e = -sum(m[i][i] for i in range(rk)) / (2 * ran) # Pfaffian mod sign e *= (-1 / (2 * pi)) ** ran # normalize return [e] diff --git a/src/sage/manifolds/differentiable/chart.py b/src/sage/manifolds/differentiable/chart.py index b9ee46f3c66..3e73e1a075c 100644 --- a/src/sage/manifolds/differentiable/chart.py +++ b/src/sage/manifolds/differentiable/chart.py @@ -21,6 +21,7 @@ - Chap. 1 of [Lee2013]_ """ + # **************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger @@ -273,6 +274,7 @@ class DiffChart(Chart): :class:`~sage.manifolds.differentiable.chart.RealDiffChart` for charts on differentiable manifolds over `\RR`. """ + def __init__(self, domain, coordinates, calc_method=None, periods=None, coord_restrictions=None): r""" Construct a chart. @@ -289,14 +291,12 @@ def __init__(self, domain, coordinates, calc_method=None, periods=None, coord_re [] sage: TestSuite(X).run() """ - super().__init__(domain, coordinates, calc_method=calc_method, - periods=periods, coord_restrictions=coord_restrictions) + super().__init__(domain, coordinates, calc_method=calc_method, periods=periods, coord_restrictions=coord_restrictions) # Construction of the coordinate frame associated to the chart: self._frame = CoordFrame(self) self._coframe = self._frame._coframe - def transition_map(self, other, transformations, intersection_name=None, - restrictions1=None, restrictions2=None): + def transition_map(self, other, transformations, intersection_name=None, restrictions1=None, restrictions2=None): r""" Construct the transition map between the current chart, `(U,\varphi)` say, and another one, `(V,\psi)` say. @@ -641,10 +641,10 @@ def symbolic_velocities(self, left='D', right=None): # string (of the type ['Dt']), which causes error in 'symbol'. # This might be corrected. if len(self[:]) == 1: - string_vel = left + format(self[:][0]) # will raise an error + string_vel = left + format(self[:][0]) # will raise an error # in case left is not a string if right is not None: - string_vel += right # will raise an error in case right + string_vel += right # will raise an error in case right # is not a string # If the argument of 'var' contains only one word, for @@ -656,19 +656,18 @@ def symbolic_velocities(self, left='D', right=None): # containing one symbolic expression. return [var(string_vel)] - list_strings_velocities = [left + format(coord_func) - for coord_func in self[:]] # will + list_strings_velocities = [left + format(coord_func) for coord_func in self[:]] # will # raise an error in case left is not a string if right is not None: - list_strings_velocities = [str_vel + right for str_vel - in list_strings_velocities] # will + list_strings_velocities = [str_vel + right for str_vel in list_strings_velocities] # will # raise an error in case right is not a string return list(var(list_strings_velocities)) -#***************************************************************************** +# ***************************************************************************** + class RealDiffChart(DiffChart, RealChart): r""" @@ -962,8 +961,8 @@ class RealDiffChart(DiffChart, RealChart): Chart grids can be drawn in 2D or 3D graphics thanks to the method :meth:`~sage.manifolds.chart.RealChart.plot`. """ - def __init__(self, domain, coordinates, calc_method=None, - bounds=None, periods=None, coord_restrictions=None): + + def __init__(self, domain, coordinates, calc_method=None, bounds=None, periods=None, coord_restrictions=None): r""" Construct a chart on a real differentiable manifold. @@ -980,8 +979,7 @@ def __init__(self, domain, coordinates, calc_method=None, [x is real, y is real] sage: TestSuite(X).run() """ - RealChart.__init__(self, domain, coordinates, calc_method=calc_method, - bounds=bounds, periods=periods, coord_restrictions=coord_restrictions) + RealChart.__init__(self, domain, coordinates, calc_method=calc_method, bounds=bounds, periods=periods, coord_restrictions=coord_restrictions) # Construction of the coordinate frame associated to the chart: self._frame = CoordFrame(self) self._coframe = self._frame._coframe @@ -1067,7 +1065,8 @@ def restrict(self, subset, restrictions=None): dom._top_frames.remove(resu._frame) return self._dom_restrict[subset] -#****************************************************************************** + +# ****************************************************************************** class DiffCoordChange(CoordChange): @@ -1117,6 +1116,7 @@ class DiffCoordChange(CoordChange): u = x + y v = x - y """ + def __init__(self, chart1, chart2, *transformations): r""" Construct a transition map. diff --git a/src/sage/manifolds/differentiable/curve.py b/src/sage/manifolds/differentiable/curve.py index 8a1cfc2e77e..ce8c5b90440 100644 --- a/src/sage/manifolds/differentiable/curve.py +++ b/src/sage/manifolds/differentiable/curve.py @@ -23,14 +23,14 @@ - Chap. 3 of [Lee2013]_ """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.manifolds.differentiable.diff_map import DiffMap from sage.manifolds.point import ManifoldPoint @@ -346,8 +346,8 @@ class DifferentiableCurve(DiffMap): sage: tau 1/9*sqrt(5) """ - def __init__(self, parent, coord_expression=None, name=None, - latex_name=None, is_isomorphism=False, is_identity=False): + + def __init__(self, parent, coord_expression=None, name=None, latex_name=None, is_isomorphism=False, is_identity=False): r""" Construct a curve. @@ -371,8 +371,7 @@ def __init__(self, parent, coord_expression=None, name=None, coord_functions = None else: if not isinstance(coord_expression, dict): - raise TypeError("{} is not a dictionary".format( - coord_expression)) + raise TypeError("{} is not a dictionary".format(coord_expression)) param_chart = parent.domain().canonical_chart() coord_functions = {} for chart, expr in coord_expression.items(): @@ -381,10 +380,7 @@ def __init__(self, parent, coord_expression=None, name=None, coord_functions[chart] = expr else: coord_functions[(param_chart, chart)] = expr - DiffMap.__init__(self, parent, coord_functions=coord_functions, - name=name, latex_name=latex_name, - is_isomorphism=is_isomorphism, - is_identity=is_identity) + DiffMap.__init__(self, parent, coord_functions=coord_functions, name=name, latex_name=latex_name, is_isomorphism=is_isomorphism, is_identity=is_identity) def _repr_(self): r""" @@ -434,8 +430,7 @@ def __reduce__(self): sage: loads(dumps(c)) Curve in the 2-dimensional differentiable manifold M """ - return (type(self), (self.parent(), None, self._name, self._latex_name, - self._is_isomorphism, self._is_identity)) + return (type(self), (self.parent(), None, self._name, self._latex_name, self._is_isomorphism, self._is_identity)) def coord_expr(self, chart=None): r""" @@ -534,8 +529,7 @@ def __call__(self, t, simplify=True): coord_functions = self._coord_expression[chart_pair]._functions n = codom._dim dict_subs = {canon_coord: t} - coords = [coord_functions[i].expr().substitute(dict_subs) - for i in range(n)] + coords = [coord_functions[i].expr().substitute(dict_subs) for i in range(n)] if simplify: coords = [chart_pair[0].simplify(coords[i]) for i in range(n)] if self._name is not None: @@ -546,9 +540,7 @@ def __call__(self, t, simplify=True): latex_name = r"{}\left({}\right)".format(self._latex_name, latex(t)) else: latex_name = None - return codom.element_class(codom, coords=coords, chart=chart_pair[1], - name=name, latex_name=latex_name, - check_coords=False) + return codom.element_class(codom, coords=coords, chart=chart_pair[1], name=name, latex_name=latex_name, check_coords=False) def tangent_vector_field(self, name=None, latex_name=None): r""" @@ -654,21 +646,17 @@ def tangent_vector_field(self, name=None, latex_name=None): for chart in codom_top_charts: try: jacob = self.differential_functions(canon_chart, chart) - restrict = self.restrict(canon_chart.domain(), - subcodomain=chart.domain()) + restrict = self.restrict(canon_chart.domain(), subcodomain=chart.domain()) fmodule = restrict._domain.vector_field_module(dest_map=restrict) frame = fmodule.basis(from_frame=chart.frame()) resu_rest = resu.restrict(canon_chart.domain(), dest_map=restrict) - resu_rest.add_comp(frame)[:, canon_chart] = [jacob[i][0] - for i in range(dim)] + resu_rest.add_comp(frame)[:, canon_chart] = [jacob[i][0] for i in range(dim)] except ValueError: pass return resu @options(thickness=1, plot_points=75, max_range=8, aspect_ratio='automatic') - def plot(self, chart=None, ambient_coords=None, mapping=None, prange=None, - include_end_point=(True, True), end_point_offset=(0.001, 0.001), - parameters=None, color='red', style='-', label_axes=True, **kwds): + def plot(self, chart=None, ambient_coords=None, mapping=None, prange=None, include_end_point=(True, True), end_point_offset=(0.001, 0.001), parameters=None, color='red', style='-', label_axes=True, **kwds): r""" Plot the current curve in a Cartesian graph based on the coordinates of some ambient chart. @@ -903,8 +891,7 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, prange=None, ambient_coords = chart[:] # all chart coordinates are used n_pc = len(ambient_coords) if n_pc != 2 and n_pc != 3: - raise ValueError("the number of coordinates involved in the " + - "plot must be either 2 or 3, not {}".format(n_pc)) + raise ValueError("the number of coordinates involved in the " + "plot must be either 2 or 3, not {}".format(n_pc)) # indices of plot coordinates ind_pc = [chart[:].index(pc) for pc in ambient_coords] # @@ -915,8 +902,7 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, prange=None, elif not isinstance(prange, (tuple, list)): raise TypeError("{} is neither a tuple nor a list".format(prange)) elif len(prange) != 2: - raise ValueError("the argument prange must be a tuple/list " + - "of 2 elements") + raise ValueError("the argument prange must be a tuple/list " + "of 2 elements") tmin = prange[0] tmax = prange[1] if tmin == -Infinity: @@ -932,8 +918,7 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, prange=None, # # The coordinate expression of the effective curve # - transf = eff_curve.coord_functions(chart1=self._domain.canonical_chart(), - chart2=chart) + transf = eff_curve.coord_functions(chart1=self._domain.canonical_chart(), chart2=chart) # # List of points for the plot curve # @@ -943,24 +928,17 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, prange=None, if parameters is None: for i in range(plot_points): x = transf(t, simplify=False) - plot_curve.append( [numerical_approx(x[j]) for j in ind_pc] ) + plot_curve.append([numerical_approx(x[j]) for j in ind_pc]) t += dt else: for i in range(plot_points): x = transf(t, simplify=False) - plot_curve.append( - [numerical_approx( x[j].substitute(parameters) ) - for j in ind_pc] ) + plot_curve.append([numerical_approx(x[j].substitute(parameters)) for j in ind_pc]) t += dt - return self._graphics(plot_curve, ambient_coords, - thickness=thickness, - aspect_ratio=aspect_ratio, color=color, - style=style, label_axes=label_axes) + return self._graphics(plot_curve, ambient_coords, thickness=thickness, aspect_ratio=aspect_ratio, color=color, style=style, label_axes=label_axes) - def _graphics(self, plot_curve, ambient_coords, thickness=1, - aspect_ratio='automatic', color='red', style='-', - label_axes=True): + def _graphics(self, plot_curve, ambient_coords, thickness=1, aspect_ratio='automatic', color='red', style='-', label_axes=True): r""" Plot a 2D or 3D curve in a Cartesian graph with axes labeled by the ambient coordinates; it is invoked by the methods @@ -1004,8 +982,7 @@ def _graphics(self, plot_curve, ambient_coords, thickness=1, # n_pc = len(ambient_coords) resu = Graphics() - resu += line(plot_curve, color=color, linestyle=style, - thickness=thickness) + resu += line(plot_curve, color=color, linestyle=style, thickness=thickness) if n_pc == 2: # 2D graphic resu.set_aspect_ratio(aspect_ratio) if label_axes: @@ -1013,9 +990,8 @@ def _graphics(self, plot_curve, ambient_coords, thickness=1, # to show()), instead of using the method # Graphics.axes_labels() since the latter is not robust w.r.t. # graph addition - resu._extra_kwds['axes_labels'] = [r'$'+latex(pc)+r'$' - for pc in ambient_coords] - else: # 3D graphic + resu._extra_kwds['axes_labels'] = [r'$' + latex(pc) + r'$' for pc in ambient_coords] + else: # 3D graphic if aspect_ratio == 'automatic': aspect_ratio = 1 resu.aspect_ratio(aspect_ratio) diff --git a/src/sage/manifolds/differentiable/de_rham_cohomology.py b/src/sage/manifolds/differentiable/de_rham_cohomology.py index 729ed375afa..f4bba6a5697 100644 --- a/src/sage/manifolds/differentiable/de_rham_cohomology.py +++ b/src/sage/manifolds/differentiable/de_rham_cohomology.py @@ -36,14 +36,14 @@ - Michael Jung (2021) : initial version """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2021 Michael Jung # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.algebras import Algebras from sage.manifolds.differentiable.characteristic_cohomology_class import ( @@ -99,6 +99,7 @@ class DeRhamCohomologyClass(AlgebraElement): ... NotImplementedError: comparison via exact forms is currently not supported """ + def __init__(self, parent, representative): r""" Construct an element of the de Rham cohomology ring. @@ -354,6 +355,7 @@ class DeRhamCohomologyRing(Parent, UniqueRepresentation): sage: H.one() [one] """ + def __init__(self, de_rham_complex): r""" Construct the de Rham cohomology ring. diff --git a/src/sage/manifolds/differentiable/degenerate.py b/src/sage/manifolds/differentiable/degenerate.py index 80da669f083..7a044ed69ed 100644 --- a/src/sage/manifolds/differentiable/degenerate.py +++ b/src/sage/manifolds/differentiable/degenerate.py @@ -1,6 +1,7 @@ r""" Degenerate manifolds """ + # ***************************************************************************** # Copyright (C) 2019 Hans Fotsing Tetsing # @@ -106,10 +107,8 @@ class DegenerateManifold(DifferentiableManifold): - [DB1996]_ - [DS2010]_ """ - def __init__(self, n, name, metric_name=None, signature=None, - base_manifold=None, diff_degree=infinity, latex_name=None, - metric_latex_name=None, start_index=0, category=None, - unique_tag=None): + + def __init__(self, n, name, metric_name=None, signature=None, base_manifold=None, diff_degree=infinity, latex_name=None, metric_latex_name=None, start_index=0, category=None, unique_tag=None): r""" Construct a degenerate manifold. @@ -126,16 +125,10 @@ def __init__(self, n, name, metric_name=None, signature=None, sage: TestSuite(M).run() """ if base_manifold and not isinstance(base_manifold, DegenerateManifold): - raise TypeError("the argument 'base_manifold' must be a " + - "Degenerate manifold") + raise TypeError("the argument 'base_manifold' must be a " + "Degenerate manifold") structure = DegenerateStructure() - DifferentiableManifold.__init__(self, n, name, 'real', structure, - base_manifold=base_manifold, - diff_degree=diff_degree, - latex_name=latex_name, - start_index=start_index, - category=category) - self._metric = None # to be initialized by metric() + DifferentiableManifold.__init__(self, n, name, 'real', structure, base_manifold=base_manifold, diff_degree=diff_degree, latex_name=latex_name, start_index=start_index, category=category) + self._metric = None # to be initialized by metric() self._metric_signature = signature if metric_name is None: metric_name = 'g' @@ -149,8 +142,7 @@ def __init__(self, n, name, metric_name=None, signature=None, raise TypeError("{} is not a string".format(metric_latex_name)) self._metric_latex_name = metric_latex_name - def metric(self, name=None, signature=None, latex_name=None, - dest_map=None) -> DegenerateMetric: + def metric(self, name=None, signature=None, latex_name=None, dest_map=None) -> DegenerateMetric: r""" Return the metric giving the null manifold structure to the manifold, or define a new metric tensor on the manifold. @@ -262,16 +254,11 @@ class :class:`~sage.manifolds.differentiable.diff_map.DiffMap` self._metric = self._manifold._metric.restrict(self) else: # creation from scratch: - self._metric = DifferentiableManifold.metric(self, - self._metric_name, - signature=self._metric_signature, - latex_name=self._metric_latex_name) + self._metric = DifferentiableManifold.metric(self, self._metric_name, signature=self._metric_signature, latex_name=self._metric_latex_name) return self._metric # Metric distinct from the default one: it is created by the method # metric of the superclass for generic differentiable manifolds: - return DifferentiableManifold.metric(self, name, signature=signature, - latex_name=latex_name, - dest_map=dest_map) + return DifferentiableManifold.metric(self, name, signature=signature, latex_name=latex_name, dest_map=dest_map) def open_subset(self, name, latex_name=None, coord_def={}): r""" @@ -338,14 +325,7 @@ def open_subset(self, name, latex_name=None, coord_def={}): sage: gV is g.restrict(V) True """ - resu = DegenerateManifold(self._dim, name, - metric_name=self._metric_name, - signature=self._metric_signature, - base_manifold=self._manifold, - diff_degree=self._diff_degree, - latex_name=latex_name, - metric_latex_name=self._metric_latex_name, - start_index=self._sindex) + resu = DegenerateManifold(self._dim, name, metric_name=self._metric_name, signature=self._metric_signature, base_manifold=self._manifold, diff_degree=self._diff_degree, latex_name=latex_name, metric_latex_name=self._metric_latex_name, start_index=self._sindex) resu._calculus_method = self._calculus_method resu._supersets.update(self._supersets) for sd in self._supersets: @@ -354,8 +334,7 @@ def open_subset(self, name, latex_name=None, coord_def={}): # Charts on the result from the coordinate definition: for chart, restrictions in coord_def.items(): if chart not in self._atlas: - raise ValueError("the {} does not belong to ".format(chart) + - "the atlas of {}".format(self)) + raise ValueError("the {} does not belong to ".format(chart) + "the atlas of {}".format(self)) chart.restrict(resu, restrictions) # Transition maps on the result inferred from those of self: for chart1 in coord_def: @@ -367,7 +346,7 @@ def open_subset(self, name, latex_name=None, coord_def={}): return resu -#******************************************************************************************* +# ******************************************************************************************* from sage.manifolds.differentiable.tensorfield import TensorField from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal @@ -428,6 +407,7 @@ class TangentTensor(TensorFieldParal): sage: T2(xi.along(Phi)).display() sqrt(u^2 + v^2) ∂/∂t """ + def __init__(self, tensor, embedding, screen=None): r""" @@ -466,18 +446,16 @@ def __init__(self, tensor, embedding, screen=None): except ValueError: pass if isinstance(tensor, TensorFieldParal): - TensorFieldParal.__init__(self, tensor._vmodule, tensor._tensor_type, name=tensor._name, - latex_name=tensor._latex_name, sym=tensor._sym, antisym=tensor._antisym) + TensorFieldParal.__init__(self, tensor._vmodule, tensor._tensor_type, name=tensor._name, latex_name=tensor._latex_name, sym=tensor._sym, antisym=tensor._antisym) else: - TensorField.__init__(self, tensor._vmodule, tensor._tensor_type, name=tensor._name, - latex_name=tensor._latex_name, sym=tensor._sym, antisym=tensor._antisym) + TensorField.__init__(self, tensor._vmodule, tensor._tensor_type, name=tensor._name, latex_name=tensor._latex_name, sym=tensor._sym, antisym=tensor._antisym) f = tensor._domain._ambient.default_frame().along(embedding) self[f, :] = tensor[f, :] frame = self._domain.adapted_frame(screen) self.display(frame) for i in self._domain._ambient.index_generator(tensor.tensor_rank()): for j in range(len(i)): - if i[j] == self._domain._ambient._dim-self._domain._sindex-1: + if i[j] == self._domain._ambient._dim - self._domain._sindex - 1: self[frame, i] = 0 def __call__(self, *args): @@ -514,8 +492,7 @@ def __call__(self, *args): except ValueError: pass if not self._domain.is_tangent(vector): - raise ValueError("The provided vector field is not " + - "tangent to {}".format(self._domain._name)) + raise ValueError("The provided vector field is not " + "tangent to {}".format(self._domain._name)) try: return TensorField.__call__(self._tensor.along(self._embedding), *args) except ValueError: diff --git a/src/sage/manifolds/differentiable/degenerate_submanifold.py b/src/sage/manifolds/differentiable/degenerate_submanifold.py index 82f220d3af5..d7b941d454f 100644 --- a/src/sage/manifolds/differentiable/degenerate_submanifold.py +++ b/src/sage/manifolds/differentiable/degenerate_submanifold.py @@ -146,6 +146,7 @@ - [DS2010]_ - [FNO2019]_ """ + # ***************************************************************************** # Copyright (C) 2019 Hans Fotsing Tetsing # @@ -225,10 +226,8 @@ class DegenerateSubmanifold(DegenerateManifold, DifferentiableSubmanifold): :mod:`~sage.manifolds.manifold` and :mod:`~sage.manifolds.differentiable.differentiable_submanifold` """ - def __init__(self, n, name, ambient=None, metric_name=None, signature=None, - base_manifold=None, diff_degree=infinity, latex_name=None, - metric_latex_name=None, start_index=0, category=None, - unique_tag=None): + + def __init__(self, n, name, ambient=None, metric_name=None, signature=None, base_manifold=None, diff_degree=infinity, latex_name=None, metric_latex_name=None, start_index=0, category=None, unique_tag=None): r""" Construct a degenerate submanifold. @@ -242,21 +241,8 @@ def __init__(self, n, name, ambient=None, metric_name=None, signature=None, 2-dimensional degenerate submanifold S embedded in 4-dimensional differentiable manifold M """ - DegenerateManifold.__init__(self, n, name=name, - metric_name=metric_name, - signature=signature, - base_manifold=base_manifold, - diff_degree=diff_degree, - latex_name=latex_name, - metric_latex_name=metric_latex_name, - start_index=start_index, - category=category) - DifferentiableSubmanifold.__init__(self, n, name, self._field, - self._structure, ambient=ambient, - base_manifold=base_manifold, - latex_name=latex_name, - start_index=start_index, - category=category) + DegenerateManifold.__init__(self, n, name=name, metric_name=metric_name, signature=signature, base_manifold=base_manifold, diff_degree=diff_degree, latex_name=latex_name, metric_latex_name=metric_latex_name, start_index=start_index, category=category) + DifferentiableSubmanifold.__init__(self, n, name, self._field, self._structure, ambient=ambient, base_manifold=base_manifold, latex_name=latex_name, start_index=start_index, category=category) self._normal = None self._first_fundamental_form = None self._induced_metric = None @@ -275,12 +261,10 @@ def __init__(self, n, name, ambient=None, metric_name=None, signature=None, ndim = self._ambient._dim try: if signature[0] == ndim or signature[1] == ndim: - raise ValueError("ambient must be a proper pseudo-Riemannian" - " or a degenerate manifold") + raise ValueError("ambient must be a proper pseudo-Riemannian" " or a degenerate manifold") except TypeError: if signature == ndim or signature == -ndim: - raise ValueError("ambient must be a proper pseudo-Riemannian" - " or a degenerate manifold") + raise ValueError("ambient must be a proper pseudo-Riemannian" " or a degenerate manifold") self._transverse = {} def _repr_(self): @@ -303,14 +287,8 @@ def _repr_(self): if self._ambient is None: return super(DegenerateManifold, self).__repr__() if self._ambient._dim - self._dim == 1: - return "degenerate hypersurface {} embedded " \ - "in {}-dimensional differentiable " \ - "manifold {}".format(self._name, self._ambient._dim, - self._ambient._name) - return "{}-dimensional degenerate submanifold {} embedded " \ - "in {}-dimensional differentiable " \ - "manifold {}".format(self._dim, self._name, self._ambient._dim, - self._ambient._name) + return "degenerate hypersurface {} embedded " "in {}-dimensional differentiable " "manifold {}".format(self._name, self._ambient._dim, self._ambient._name) + return "{}-dimensional degenerate submanifold {} embedded " "in {}-dimensional differentiable " "manifold {}".format(self._dim, self._name, self._ambient._dim, self._ambient._name) def ambient_metric(self): r""" @@ -336,10 +314,8 @@ def ambient_metric(self): Lorentzian metric g on the 3-dimensional Lorentzian manifold M """ if self._ambient_metric is None: - if not self._embedded or not isinstance(self._ambient, - (PseudoRiemannianManifold, DegenerateManifold)): - raise ValueError("degenerate submanifold must be embedded in a " - "pseudo-Riemannian or degenerate manifold") + if not self._embedded or not isinstance(self._ambient, (PseudoRiemannianManifold, DegenerateManifold)): + raise ValueError("degenerate submanifold must be embedded in a " "pseudo-Riemannian or degenerate manifold") self._ambient_metric = self._ambient.metric() return self._ambient_metric @@ -491,7 +467,7 @@ def set_transverse(self, rigging=None, normal=None): raise ValueError("{} is normal to {}".format(u.display(), self._name)) rig.append(u) l2 += 1 - if l1+l2 != self._codim: + if l1 + l2 != self._codim: raise ValueError("length of the transverse must be {}".format(self._codim)) self._transverse['normal'] = tuple(nor) self._transverse['rigging'] = tuple(rig) @@ -551,14 +527,13 @@ def screen(self, name, screen, rad, latex_name=None): if name in self._screens: if list(screen) == self._screens[name]._screen and list(rad) == self._screens[name]._rad: return self._screens[name] - raise ValueError("a different screen distribution with the " - "same name had already been set") - if len(screen)+len(rad) != self._dim: + raise ValueError("a different screen distribution with the " "same name had already been set") + if len(screen) + len(rad) != self._dim: raise ValueError("total length screen+rad must be {}".format(self._dim)) frame = self.default_frame() im = self.immersion() g = self.ambient_metric().along(im) - for (i, u) in enumerate(screen): + for i, u in enumerate(screen): if isinstance(u, Expression): u = self._ambient.scalar_field(u).gradient() screen[i] = u @@ -569,7 +544,7 @@ def screen(self, name, screen, rad, latex_name=None): sc = True if not sc: raise ValueError("{} cannot belong to a screen distribution".format(u.display())) - for (i, u) in enumerate(rad): + for i, u in enumerate(rad): if isinstance(u, Expression): u = self._ambient.scalar_field(u).gradient() rad[i] = u @@ -616,8 +591,7 @@ def induced_metric(self) -> DegenerateMetric: """ if self._induced_metric is None or self._induced_metric._components == {}: self._induced_metric = self.metric() - self._induced_metric.set( - self.immersion().pullback(self.ambient_metric())) + self._induced_metric.set(self.immersion().pullback(self.ambient_metric())) self._induced_metric.set_name("gamma", r"\gamma") return self._induced_metric @@ -657,7 +631,7 @@ def first_fundamental_form(self): if self._first_fundamental_form is None: g = self.ambient_metric() h = g.copy() - h.set_name(g._name+"|"+self._name, g._latex_name+r"|_"+self._latex_name) + h.set_name(g._name + "|" + self._name, g._latex_name + r"|_" + self._latex_name) h = TangentTensor(h, self.immersion()) self._first_fundamental_form = h return self._first_fundamental_form @@ -732,12 +706,12 @@ def _ambient_decomposition(self, screen=None): xi = rad[0] v = rig[0] g = self.ambient_metric() - N = (1/g(xi, v))*(v-(g(v,v)/(2*g(xi, v)))*xi) + N = (1 / g(xi, v)) * (v - (g(v, v) / (2 * g(xi, v))) * xi) if not self._adapted_frame: N.set_name(name='N') else: n = len(self._adapted_frame) - N.set_name(name='N'+str(n)) + N.set_name(name='N' + str(n)) rig = [N] return [screen, rad, normal, rig] @@ -793,19 +767,19 @@ def _adapted_frame_(self, screen=None): i = self._ambient._sindex for u in sc: for j in self._ambient.irange(): - A[j,i] = u[j] + A[j, i] = u[j] i += 1 for u in rad: for j in self._ambient.irange(): - A[j,i] = u[j] + A[j, i] = u[j] i += 1 for u in normal: for j in self._ambient.irange(): - A[j,i] = u[j] + A[j, i] = u[j] i += 1 for u in rigging: for j in self._ambient.irange(): - A[j,i] = u[j] + A[j, i] = u[j] i += 1 f = self._ambient.default_frame() GLHPhi = f.along(self.immersion())[0].parent().general_linear_group() @@ -813,22 +787,21 @@ def _adapted_frame_(self, screen=None): e = f.new_frame(A, 'vv') else: n = len(self._adapted_frame) - e = f.new_frame(A, 'vv'+str(n)) - self.set_change_of_frame(f.along(self.immersion()), e.along( - self.immersion()), GLHPhi(A.along(self.immersion()))) + e = f.new_frame(A, 'vv' + str(n)) + self.set_change_of_frame(f.along(self.immersion()), e.along(self.immersion()), GLHPhi(A.along(self.immersion()))) b = e.dual_basis() if self._codim == 1: if not self._adapted_frame: - e[self._dim-self._sindex].set_name('N') + e[self._dim - self._sindex].set_name('N') else: n = len(self._adapted_frame) - e[self._dim-self._sindex].set_name('N'+str(n)) - e[self._dim-self._sindex-1].set_name('xi', latex_name=r'\xi') + e[self._dim - self._sindex].set_name('N' + str(n)) + e[self._dim - self._sindex - 1].set_name('xi', latex_name=r'\xi') if not self._adapted_frame: - b[self._dim-self._sindex].set_name('N^b', latex_name=r'N^\flat') + b[self._dim - self._sindex].set_name('N^b', latex_name=r'N^\flat') else: - b[self._dim-self._sindex].set_name('N'+str(n)+'^b', latex_name=r'N'+str(n)+r'^\flat') - b[self._dim-self._sindex-1].set_name('xi^b', latex_name=r'\xi^\flat') + b[self._dim - self._sindex].set_name('N' + str(n) + '^b', latex_name=r'N' + str(n) + r'^\flat') + b[self._dim - self._sindex - 1].set_name('xi^b', latex_name=r'\xi^\flat') self._adapted_frame[screen._name] = e return e @@ -876,16 +849,16 @@ def adapted_frame(self, screen=None): b = e.dual_basis() if self._codim == 1: if not self._adapted_frame: - e[self._dim-self._sindex].set_name('N') + e[self._dim - self._sindex].set_name('N') else: n = len(self._adapted_frame) - e[self._dim-self._sindex].set_name('N'+str(n)) - e[self._dim-self._sindex-1].set_name('xi', latex_name=r'\xi') + e[self._dim - self._sindex].set_name('N' + str(n)) + e[self._dim - self._sindex - 1].set_name('xi', latex_name=r'\xi') if not self._adapted_frame: - b[self._dim-self._sindex].set_name('N^b', latex_name=r'N^\flat') + b[self._dim - self._sindex].set_name('N^b', latex_name=r'N^\flat') else: - b[self._dim-self._sindex].set_name('N'+str(n)+'^b', latex_name=r'N'+str(n)+r'^\flat') - b[self._dim-self._sindex-1].set_name('xi^b', latex_name=r'\xi^\flat') + b[self._dim - self._sindex].set_name('N' + str(n) + '^b', latex_name=r'N' + str(n) + r'^\flat') + b[self._dim - self._sindex - 1].set_name('xi^b', latex_name=r'\xi^\flat') return self._adapted_frame_(screen).along(self.immersion()) def second_fundamental_form(self, screen=None): @@ -938,15 +911,12 @@ def second_fundamental_form(self, screen=None): sage: B.display() # long time B = 0 """ - if self._ambient._dim-self._dim != 1: - raise ValueError("'second_fundamental_form' is defined" + - " only for hypersurfaces.") + if self._ambient._dim - self._dim != 1: + raise ValueError("'second_fundamental_form' is defined" + " only for hypersurfaces.") if screen is None: screen = self.default_screen() if screen._name not in self._second_fundamental_form: - resu = self._ambient.vector_field_module() \ - .tensor((0, 2), name='B', latex_name='B', sym=[(0, 1)], antisym=[]) \ - .along(self.immersion()) + resu = self._ambient.vector_field_module().tensor((0, 2), name='B', latex_name='B', sym=[(0, 1)], antisym=[]).along(self.immersion()) f = self.adapted_frame(screen) rad = self._ambient_decomposition(screen)[1] nab = self.ambient_metric().connection() @@ -998,8 +968,7 @@ def projection(self, tensor, screen=None): sage: U1 = S.projection(U) # long time """ if tensor.tensor_type()[0] != 1: - raise NotImplementedError("``projection`` is implemented only for " - "tensors with 1 as contravariant order") + raise NotImplementedError("``projection`` is implemented only for " "tensors with 1 as contravariant order") return TangentTensor(tensor, self.immersion(), screen) def screen_projection(self, tensor, screen=None): @@ -1040,8 +1009,7 @@ def screen_projection(self, tensor, screen=None): sage: U1 = S.screen_projection(U); # long time """ if tensor.tensor_type()[0] != 1: - raise NotImplementedError("``projection`` is implemented only for " + - "tensors with 1 as contravariant order") + raise NotImplementedError("``projection`` is implemented only for " + "tensors with 1 as contravariant order") frame = self.adapted_frame(screen) T = tensor.copy() try: @@ -1050,12 +1018,12 @@ def screen_projection(self, tensor, screen=None): pass T.display(frame) for i in self._ambient.index_generator(T.tensor_rank()): - if i[0] in range(self._dim-self._sindex-1,self._ambient._dim-self._sindex): + if i[0] in range(self._dim - self._sindex - 1, self._ambient._dim - self._sindex): T[frame, i] = 0 if tensor._latex_name is None: T.set_name(tensor._name) else: - T.set_name("P"+tensor._name, latex_name=r'P'+tensor._latex_name) + T.set_name("P" + tensor._name, latex_name=r'P' + tensor._latex_name) return TangentTensor(T, self.immersion(), screen) def weingarten_map(self, screen=None): @@ -1117,8 +1085,7 @@ def weingarten_map(self, screen=None): T = T.along(im) except ValueError: pass - T.set_name("nabla_g(xi)|X("+self._name+")", - latex_name=r'\nabla_g(\xi)|_{\mathfrak{X}('+self._latex_name+r')}') + T.set_name("nabla_g(xi)|X(" + self._name + ")", latex_name=r'\nabla_g(\xi)|_{\mathfrak{X}(' + self._latex_name + r')}') return TangentTensor(T, im, screen) def shape_operator(self, screen=None): @@ -1217,17 +1184,14 @@ def gauss_curvature(self, screen=None): S → ℝ (u, v, w) ↦ 0 """ - if self._ambient._dim-self._dim != 1: - raise ValueError("'gauss_curvature' is defined" - " only for hypersurfaces.") + if self._ambient._dim - self._dim != 1: + raise ValueError("'gauss_curvature' is defined" " only for hypersurfaces.") if screen is None: screen = self.default_screen() if screen._name not in self._gauss_curvature: f = self.adapted_frame() A = self.shape_operator() - self._gauss_curvature[screen._name] = self.scalar_field( - {chart: A[f,:,chart].determinant() - for chart in self.top_charts()}) + self._gauss_curvature[screen._name] = self.scalar_field({chart: A[f, :, chart].determinant() for chart in self.top_charts()}) return self._gauss_curvature[screen._name] def principal_directions(self, screen=None): @@ -1271,27 +1235,22 @@ def principal_directions(self, screen=None): e_2 = xi """ if self._codim != 1: - raise ValueError("'principal directions' is defined" + - " only for hypersurfaces.") + raise ValueError("'principal directions' is defined" + " only for hypersurfaces.") if screen is None: screen = self.default_screen() if screen._name in self._principal_directions: return self._principal_directions[screen._name] a = self.shape_operator(screen) frame = self.adapted_frame(screen) - pr_d = matrix( - [[a[frame, :][i, j].expr() for i in self.irange()] - for j in self.irange()]).eigenvectors_right() + pr_d = matrix([[a[frame, :][i, j].expr() for i in self.irange()] for j in self.irange()]).eigenvectors_right() res = [] counter = self.irange() for eigen_space in pr_d: for eigen_vector in eigen_space[1]: - v = self._ambient.vector_field(name="e_{}".format(next(counter)) - ).along(self.immersion()) + v = self._ambient.vector_field(name="e_{}".format(next(counter))).along(self.immersion()) v[frame, :] = list(eigen_vector) + [0] - res.append((TangentTensor(v, self.immersion()), self.scalar_field( - {chart: eigen_space[0] for chart in self.top_charts()}))) - #res[-1][0].set_name("e_{}".format(next(counter))) + res.append((TangentTensor(v, self.immersion()), self.scalar_field({chart: eigen_space[0] for chart in self.top_charts()}))) + # res[-1][0].set_name("e_{}".format(next(counter))) self._principal_directions[screen._name] = res return res @@ -1336,15 +1295,13 @@ def mean_curvature(self, screen=None): (u, v, w) ↦ 0 """ if self._codim != 1: - raise ValueError("'mean_curvature' is defined" + - " only for hypersurfaces.") + raise ValueError("'mean_curvature' is defined" + " only for hypersurfaces.") if screen is None: screen = self.default_screen() if screen._name in self._mean_curvature: return self._mean_curvature[screen._name] pc = [elt[-1] for elt in self.principal_directions(screen)] - self._mean_curvature[screen._name] = self.scalar_field({chart: sum( - pc).expr(chart)/self._dim for chart in self.top_charts()}) + self._mean_curvature[screen._name] = self.scalar_field({chart: sum(pc).expr(chart) / self._dim for chart in self.top_charts()}) return self._mean_curvature[screen._name] def is_tangent(self, v): @@ -1391,12 +1348,13 @@ def is_tangent(self, v): decomposition = self._ambient_decomposition() rad, normal = decomposition[1], decomposition[2] for u in rad: - if not g.along(im)(u.along(im),v).is_zero(): + if not g.along(im)(u.along(im), v).is_zero(): return False return all(g.along(im)(u.along(im), v).is_zero() for u in normal) -#************************************************************************************** +# ************************************************************************************** + class Screen(VectorFieldModule): r""" @@ -1530,12 +1488,11 @@ def _repr_(self): 3-dimensional differentiable manifold M mapped into the 3-dimensional Lorentzian manifold M' """ - description = "screen distribution "+self._name + description = "screen distribution " + self._name if self._dest_map is self._domain.identity_map(): description += " on the {}".format(self._domain) else: - description += (" along the {}".format(self._domain) - + " mapped into the {}".format(self._ambient_domain)) + description += " along the {}".format(self._domain) + " mapped into the {}".format(self._ambient_domain) return description def __getitem__(self, i): @@ -1575,7 +1532,7 @@ def __getitem__(self, i): Lorentzian manifold M """ sc = [elt.along(self._domain.immersion()) for elt in self._screen] - return sc[i-self._domain._sindex] + return sc[i - self._domain._sindex] def normal_tangent_vector(self): r""" @@ -1660,6 +1617,6 @@ def rigging(self): xi = self.normal_tangent_vector() v = rig[0] g = self._domain.ambient_metric().along(im) - N = (1/g(xi, v))*(v-(g(v,v)/(2*g(xi, v)))*xi) + N = (1 / g(xi, v)) * (v - (g(v, v) / (2 * g(xi, v))) * xi) N.set_name(name='N') return N diff --git a/src/sage/manifolds/differentiable/diff_form.py b/src/sage/manifolds/differentiable/diff_form.py index bd6c4727872..e0acd475a80 100644 --- a/src/sage/manifolds/differentiable/diff_form.py +++ b/src/sage/manifolds/differentiable/diff_form.py @@ -281,6 +281,7 @@ class DiffForm(TensorField): sage: s.display(eV) f*a = u**2*v/2 du - u**3/2 dv """ + def __init__(self, vector_field_module, degree, name=None, latex_name=None): r""" Construct a differential form. @@ -321,9 +322,7 @@ def __init__(self, vector_field_module, degree, name=None, latex_name=None): Fix ``_test_pickling`` (in the superclass :class:`TensorField`). """ - TensorField.__init__(self, vector_field_module, (0, degree), name=name, - latex_name=latex_name, antisym=range(degree), - parent=vector_field_module.dual_exterior_power(degree)) + TensorField.__init__(self, vector_field_module, (0, degree), name=name, latex_name=latex_name, antisym=range(degree), parent=vector_field_module.dual_exterior_power(degree)) self._init_derived() # initialization of derived quantities def _repr_(self): @@ -451,15 +450,13 @@ def exterior_derivative(self) -> DiffForm: vmodule = self._vmodule # shortcut rname = format_unop_txt("d", self._name) rlname = format_unop_latex(r"\mathrm{d}", self._latex_name) - resu = vmodule.alternating_form( - self._tensor_rank + 1, name=rname, latex_name=rlname - ) + resu = vmodule.alternating_form(self._tensor_rank + 1, name=rname, latex_name=rlname) for dom, rst in self._restrictions.items(): resu._restrictions[dom] = rst.exterior_derivative() return resu derivative = exterior_derivative # allows one to use functional notation, - # e.g. diff(a) for a.exterior_derivative() + # e.g. diff(a) for a.exterior_derivative() def wedge(self, other: DiffForm) -> DiffForm: r""" @@ -529,6 +526,7 @@ def wedge(self, other: DiffForm) -> DiffForm: return self * other from sage.tensor.modules.format_utilities import is_atomic from sage.typeset.unicode_characters import unicode_wedge + if self._domain.is_subset(other._domain): if not self._ambient_domain.is_subset(other._ambient_domain): raise ValueError("incompatible ambient domains for exterior product") @@ -539,18 +537,14 @@ def wedge(self, other: DiffForm) -> DiffForm: ambient_dom_resu = self._ambient_domain.intersection(other._ambient_domain) resu_degree = self._tensor_rank + other._tensor_rank dest_map = self._vmodule._dest_map - dest_map_resu = dest_map.restrict(dom_resu, - subcodomain=ambient_dom_resu) + dest_map_resu = dest_map.restrict(dom_resu, subcodomain=ambient_dom_resu) # Facilitate computations involving zero: if resu_degree > ambient_dom_resu._dim: - return dom_resu.diff_form_module(resu_degree, - dest_map=dest_map_resu).zero() + return dom_resu.diff_form_module(resu_degree, dest_map=dest_map_resu).zero() if self._is_zero or other._is_zero: - return dom_resu.diff_form_module(resu_degree, - dest_map=dest_map_resu).zero() + return dom_resu.diff_form_module(resu_degree, dest_map=dest_map_resu).zero() if self is other and (self._tensor_rank % 2) == 1: - return dom_resu.diff_form_module(resu_degree, - dest_map=dest_map_resu).zero() + return dom_resu.diff_form_module(resu_degree, dest_map=dest_map_resu).zero() # Generic case: self_r = self.restrict(dom_resu) other_r = other.restrict(dom_resu) @@ -577,12 +571,10 @@ def wedge(self, other: DiffForm) -> DiffForm: olname = '(' + olname + ')' resu_latex_name = slname + r'\wedge ' + olname vmodule = dom_resu.vector_field_module(dest_map=dest_map_resu) - resu = vmodule.alternating_form(resu_degree, name=resu_name, - latex_name=resu_latex_name) + resu = vmodule.alternating_form(resu_degree, name=resu_name, latex_name=resu_latex_name) for dom in self_r._restrictions: if dom in other_r._restrictions: - resu._restrictions[dom] = self_r._restrictions[dom].wedge( - other_r._restrictions[dom]) + resu._restrictions[dom] = self_r._restrictions[dom].wedge(other_r._restrictions[dom]) return resu def degree(self) -> int: @@ -607,9 +599,7 @@ def degree(self) -> int: def hodge_dual( self, - nondegenerate_tensor: Union[ - PseudoRiemannianMetric, SymplecticForm, None - ] = None, + nondegenerate_tensor: Union[PseudoRiemannianMetric, SymplecticForm, None] = None, minus_eigenvalues_convention: bool = False, ) -> DiffForm: r""" @@ -785,12 +775,14 @@ def hodge_dual( result = result / factorial(p) if minus_eigenvalues_convention: from sage.manifolds.differentiable.metric import PseudoRiemannianMetric + if isinstance(nondegenerate_tensor, PseudoRiemannianMetric): result = result * nondegenerate_tensor._indic_signat from sage.manifolds.differentiable.symplectic_form import SymplecticForm + if isinstance(nondegenerate_tensor, SymplecticForm): # correction because we lifted the indices of the volume (see above) - result = result * (-1)**p + result = result * (-1) ** p result.set_name( name=format_unop_txt("*", self._name), @@ -892,14 +884,13 @@ def interior_product(self, qvect): True """ from sage.tensor.modules.format_utilities import is_atomic + if self._domain.is_subset(qvect._domain): if not self._ambient_domain.is_subset(qvect._ambient_domain): - raise ValueError("incompatible ambient domains for interior " + - "product") + raise ValueError("incompatible ambient domains for interior " + "product") elif qvect._domain.is_subset(self._domain): if not qvect._ambient_domain.is_subset(self._ambient_domain): - raise ValueError("incompatible ambient domains for interior " + - "product") + raise ValueError("incompatible ambient domains for interior " + "product") dom_resu = self._domain.intersection(qvect._domain) ambient_dom_resu = self._ambient_domain.intersection(qvect._ambient_domain) self_r = self.restrict(dom_resu) @@ -927,26 +918,22 @@ def interior_product(self, qvect): resu_latex_name = r'\iota_{' + slname + '} ' + olname # Domain and computation of the result dest_map = self._vmodule._dest_map - dest_map_resu = dest_map.restrict(dom_resu, - subcodomain=ambient_dom_resu) + dest_map_resu = dest_map.restrict(dom_resu, subcodomain=ambient_dom_resu) vmodule = dom_resu.vector_field_module(dest_map=dest_map_resu) resu_degree = qvect._tensor_rank - self._tensor_rank - resu = vmodule.alternating_contravariant_tensor(resu_degree, - name=resu_name, latex_name=resu_latex_name) + resu = vmodule.alternating_contravariant_tensor(resu_degree, name=resu_name, latex_name=resu_latex_name) for dom in self_r._restrictions: if dom in qvect_r._restrictions: - resu._restrictions[dom] = \ - self_r._restrictions[dom].interior_product( - qvect_r._restrictions[dom]) + resu._restrictions[dom] = self_r._restrictions[dom].interior_product(qvect_r._restrictions[dom]) if resu_degree == 0: if not resu._express: # only the restrictions to subdomains have # been initialized for chart in dom_resu.top_charts(): - resu._express[chart] = \ - resu.restrict(chart.domain()).coord_function(chart) + resu._express[chart] = resu.restrict(chart.domain()).coord_function(chart) return resu + # ***************************************************************************** @@ -1242,8 +1229,8 @@ class DiffFormParal(FreeModuleAltForm, TensorFieldParal, DiffForm): sage: c.symmetries() # c has no symmetries: no symmetry; no antisymmetry """ - def __init__(self, vector_field_module: VectorFieldModule, degree: int, name: Optional[str] = None, - latex_name: Optional[str] = None): + + def __init__(self, vector_field_module: VectorFieldModule, degree: int, name: Optional[str] = None, latex_name: Optional[str] = None): r""" Construct a differential form. @@ -1276,8 +1263,7 @@ def __init__(self, vector_field_module: VectorFieldModule, degree: int, name: Op sage: a.display() a = x*y dx∧dy """ - FreeModuleAltForm.__init__(self, vector_field_module, degree, - name=name, latex_name=latex_name) + FreeModuleAltForm.__init__(self, vector_field_module, degree, name=name, latex_name=latex_name) # TensorFieldParal attributes: self._vmodule = vector_field_module self._domain = vector_field_module._domain @@ -1447,12 +1433,11 @@ def exterior_derivative(self) -> DiffFormParal: format_unop_latex, format_unop_txt, ) - fmodule = self._fmodule # shortcut + + fmodule = self._fmodule # shortcut rname = format_unop_txt('d', self._name) rlname = format_unop_latex(r'\mathrm{d}', self._latex_name) - resu = fmodule.alternating_form(self._tensor_rank + 1, - name=rname, - latex_name=rlname) + resu = fmodule.alternating_form(self._tensor_rank + 1, name=rname, latex_name=rlname) # 1/ List of all coordinate frames in which the components of self # are known coord_frames = [] @@ -1486,22 +1471,18 @@ def exterior_derivative(self) -> DiffFormParal: for frame in coord_frames: chart = frame._chart sc = self._components[frame] - dc = CompFullyAntiSym(fmodule._ring, frame, - self._tensor_rank + 1, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter) + dc = CompFullyAntiSym(fmodule._ring, frame, self._tensor_rank + 1, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) for ind, val in sc._comp.items(): for i in fmodule.irange(): ind_d = (i,) + ind if len(ind_d) == len(set(ind_d)): # all indices are different - dc[[ind_d]] += \ - val.coord_function(chart).diff(i).scalar_field() + dc[[ind_d]] += val.coord_function(chart).diff(i).scalar_field() resu._components[frame] = dc return resu derivative = exterior_derivative # allows one to use functional notation, - # e.g. diff(a) for a.exterior_derivative() + # e.g. diff(a) for a.exterior_derivative() def wedge(self, other): r""" @@ -1551,12 +1532,10 @@ def wedge(self, other): return self * other if self._domain.is_subset(other._domain): if not self._ambient_domain.is_subset(other._ambient_domain): - raise ValueError("incompatible ambient domains for exterior " + - "product") + raise ValueError("incompatible ambient domains for exterior " + "product") elif other._domain.is_subset(self._domain): if not other._ambient_domain.is_subset(self._ambient_domain): - raise ValueError("incompatible ambient domains for exterior " + - "product") + raise ValueError("incompatible ambient domains for exterior " + "product") dom_resu = self._domain.intersection(other._domain) self_r = self.restrict(dom_resu) other_r = other.restrict(dom_resu) @@ -1647,12 +1626,10 @@ def interior_product(self, qvect): """ if self._domain.is_subset(qvect._domain): if not self._ambient_domain.is_subset(qvect._ambient_domain): - raise ValueError("incompatible ambient domains for interior " + - "product") + raise ValueError("incompatible ambient domains for interior " + "product") elif qvect._domain.is_subset(self._domain): if not qvect._ambient_domain.is_subset(self._ambient_domain): - raise ValueError("incompatible ambient domains for interior " + - "product") + raise ValueError("incompatible ambient domains for interior " + "product") dom_resu = self._domain.intersection(qvect._domain) self_r = self.restrict(dom_resu) qvect_r = qvect.restrict(dom_resu) diff --git a/src/sage/manifolds/differentiable/diff_form_module.py b/src/sage/manifolds/differentiable/diff_form_module.py index c380989a513..1b7e60da590 100644 --- a/src/sage/manifolds/differentiable/diff_form_module.py +++ b/src/sage/manifolds/differentiable/diff_form_module.py @@ -26,6 +26,7 @@ - [KN1963]_ - [Lee2013]_ """ + # ***************************************************************************** # Copyright (C) 2015-2021 Eric Gourgoulhon # 2016 Travis Scrimshaw @@ -255,6 +256,7 @@ class DiffFormModule(UniqueRepresentation, Parent): sage: a_U.display(eU) a = 3*x dx∧dy """ + Element = DiffForm def __init__(self, vector_field_module, degree): @@ -313,8 +315,7 @@ def __init__(self, vector_field_module, degree): #### Parent methods - def _element_constructor_(self, comp=[], frame=None, name=None, - latex_name=None): + def _element_constructor_(self, comp=[], frame=None, name=None, latex_name=None): r""" Construct a differential form. @@ -340,30 +341,22 @@ def _element_constructor_(self, comp=[], frame=None, name=None, return self.zero() if isinstance(comp, (DiffForm, DiffFormParal)): # coercion by domain restriction - if (self._degree == comp._tensor_type[1] - and self._domain.is_subset(comp._domain) - and self._ambient_domain.is_subset(comp._ambient_domain)): + if self._degree == comp._tensor_type[1] and self._domain.is_subset(comp._domain) and self._ambient_domain.is_subset(comp._ambient_domain): return comp.restrict(self._domain) - raise TypeError("cannot convert the {} ".format(comp) + - "to an element of {}".format(self)) + raise TypeError("cannot convert the {} ".format(comp) + "to an element of {}".format(self)) if isinstance(comp, TensorField): # coercion of a tensor of type (0,1) to a linear form - tensor = comp # for readability - if (tensor.tensor_type() == (0,1) and self._degree == 1 - and tensor._vmodule is self._vmodule): - resu = self.element_class(self._vmodule, 1, name=tensor._name, - latex_name=tensor._latex_name) + tensor = comp # for readability + if tensor.tensor_type() == (0, 1) and self._degree == 1 and tensor._vmodule is self._vmodule: + resu = self.element_class(self._vmodule, 1, name=tensor._name, latex_name=tensor._latex_name) for dom, rst in tensor._restrictions.items(): resu._restrictions[dom] = dom.diff_form_module(1)(rst) return resu - raise TypeError("cannot convert the {} ".format(tensor) + - "to an element of {}".format(self)) + raise TypeError("cannot convert the {} ".format(tensor) + "to an element of {}".format(self)) if not isinstance(comp, (list, tuple)): - raise TypeError("cannot convert the {} ".format(comp) + - "to an element of {}".format(self)) + raise TypeError("cannot convert the {} ".format(comp) + "to an element of {}".format(self)) # standard construction - resu = self.element_class(self._vmodule, self._degree, name=name, - latex_name=latex_name) + resu = self.element_class(self._vmodule, self._degree, name=name, latex_name=latex_name) if comp: resu.set_comp(frame)[:] = comp return resu @@ -386,8 +379,7 @@ def _an_element_(self): for oc in self._domain.open_covers(trivial=False): # the first non-trivial open cover is selected for dom in oc: - vmodule_dom = dom.vector_field_module( - dest_map=self._dest_map.restrict(dom)) + vmodule_dom = dom.vector_field_module(dest_map=self._dest_map.restrict(dom)) dmodule_dom = vmodule_dom.dual_exterior_power(self._degree) resu.set_restriction(dmodule_dom._an_element_()) return resu @@ -415,15 +407,13 @@ def _coerce_map_from_(self, other): """ if isinstance(other, (DiffFormModule, DiffFormFreeModule)): # coercion by domain restriction - return (self._degree == other._degree - and self._domain.is_subset(other._domain) - and self._ambient_domain.is_subset(other._ambient_domain)) + return self._degree == other._degree and self._domain.is_subset(other._domain) and self._ambient_domain.is_subset(other._ambient_domain) from sage.manifolds.differentiable.tensorfield_module import TensorFieldModule + if isinstance(other, TensorFieldModule): # coercion of a type-(0,1) tensor to a linear form - return (self._vmodule is other._vmodule and self._degree == 1 - and other.tensor_type() == (0,1)) + return self._vmodule is other._vmodule and self._degree == 1 and other.tensor_type() == (0, 1) return False @@ -469,8 +459,7 @@ def _repr_(self): if self._dest_map is self._domain.identity_map(): description += "on the {}".format(self._domain) else: - description += "along the {} mapped into the {}".format( - self._domain, self._ambient_domain) + description += "along the {} mapped into the {}".format(self._domain, self._ambient_domain) return description def _latex_(self): @@ -565,6 +554,7 @@ def degree(self): """ return self._degree + # ***************************************************************************** @@ -760,16 +750,14 @@ def __init__(self, vector_field_module, degree): latex_name += "," + dm_latex_name name += ")" latex_name += r"\right)" - ExtPowerDualFreeModule.__init__(self, vector_field_module, degree, - name=name, latex_name=latex_name) + ExtPowerDualFreeModule.__init__(self, vector_field_module, degree, name=name, latex_name=latex_name) self._domain = domain self._dest_map = dest_map self._ambient_domain = vector_field_module._ambient_domain #### Parent methods - def _element_constructor_(self, comp=[], frame=None, name=None, - latex_name=None): + def _element_constructor_(self, comp=[], frame=None, name=None, latex_name=None): r""" Construct a differential form. @@ -799,30 +787,22 @@ def _element_constructor_(self, comp=[], frame=None, name=None, return self.zero() if isinstance(comp, (DiffForm, DiffFormParal)): # coercion by domain restriction - if (self._degree == comp._tensor_type[1] - and self._domain.is_subset(comp._domain) - and self._ambient_domain.is_subset(comp._ambient_domain)): + if self._degree == comp._tensor_type[1] and self._domain.is_subset(comp._domain) and self._ambient_domain.is_subset(comp._ambient_domain): return comp.restrict(self._domain) - raise TypeError("cannot convert the {} ".format(comp) + - "to a differential form in {}".format(self)) + raise TypeError("cannot convert the {} ".format(comp) + "to a differential form in {}".format(self)) if isinstance(comp, TensorFieldParal): # coercion of a tensor of type (0,1) to a linear form - tensor = comp # for readability - if (tensor.tensor_type() == (0,1) and self._degree == 1 - and tensor._fmodule is self._fmodule): - resu = self.element_class(self._fmodule, 1, name=tensor._name, - latex_name=tensor._latex_name) + tensor = comp # for readability + if tensor.tensor_type() == (0, 1) and self._degree == 1 and tensor._fmodule is self._fmodule: + resu = self.element_class(self._fmodule, 1, name=tensor._name, latex_name=tensor._latex_name) for frame, comp in tensor._components.items(): resu._components[frame] = comp.copy() return resu - raise TypeError("cannot convert the {} ".format(tensor) + - "to an element of {}".format(self)) + raise TypeError("cannot convert the {} ".format(tensor) + "to an element of {}".format(self)) if not isinstance(comp, (list, tuple)): - raise TypeError("cannot convert the {} ".format(comp) + - "to an element of {}".format(self)) + raise TypeError("cannot convert the {} ".format(comp) + "to an element of {}".format(self)) # standard construction - resu = self.element_class(self._fmodule, self._degree, name=name, - latex_name=latex_name) + resu = self.element_class(self._fmodule, self._degree, name=name, latex_name=latex_name) if comp: resu.set_comp(frame)[:] = comp return resu @@ -854,17 +834,15 @@ def _coerce_map_from_(self, other): """ if isinstance(other, (DiffFormModule, DiffFormFreeModule)): # coercion by domain restriction - return (self._degree == other._degree - and self._domain.is_subset(other._domain) - and self._ambient_domain.is_subset(other._ambient_domain)) + return self._degree == other._degree and self._domain.is_subset(other._domain) and self._ambient_domain.is_subset(other._ambient_domain) from sage.manifolds.differentiable.tensorfield_module import ( TensorFieldFreeModule, ) + if isinstance(other, TensorFieldFreeModule): # coercion of a type-(0,1) tensor to a linear form - return (self._fmodule is other._fmodule and self._degree == 1 - and other.tensor_type() == (0,1)) + return self._fmodule is other._fmodule and self._degree == 1 and other.tensor_type() == (0, 1) return False #### End of Parent methods @@ -889,8 +867,7 @@ def _repr_(self): if self._dest_map is self._domain.identity_map(): description += "on the {}".format(self._domain) else: - description += "along the {} mapped into the {}".format( - self._domain, self._ambient_domain) + description += "along the {} mapped into the {}".format(self._domain, self._ambient_domain) return description diff --git a/src/sage/manifolds/differentiable/diff_map.py b/src/sage/manifolds/differentiable/diff_map.py index 6ac44fa7fb6..7b1e92b2607 100644 --- a/src/sage/manifolds/differentiable/diff_map.py +++ b/src/sage/manifolds/differentiable/diff_map.py @@ -399,8 +399,8 @@ class is sage: ~id is id True """ - def __init__(self, parent, coord_functions=None, name=None, - latex_name=None, is_isomorphism=False, is_identity=False): + + def __init__(self, parent, coord_functions=None, name=None, latex_name=None, is_isomorphism=False, is_identity=False): r""" Construct a differentiable map. @@ -427,10 +427,7 @@ def __init__(self, parent, coord_functions=None, name=None, (x, y) ↦ (x, y) sage: TestSuite(f).run() """ - ContinuousMap.__init__(self, parent, coord_functions=coord_functions, - name=name, latex_name=latex_name, - is_isomorphism=is_isomorphism, - is_identity=is_identity) + ContinuousMap.__init__(self, parent, coord_functions=coord_functions, name=name, latex_name=latex_name, is_isomorphism=is_isomorphism, is_identity=is_identity) # # SageObject methods @@ -466,8 +463,7 @@ def _repr_(self): 'Identity map f of the 2-dimensional differentiable manifold M' """ if self._is_identity: - return "Identity map " + self._name + \ - " of the {}".format(self._domain) + return "Identity map " + self._name + " of the {}".format(self._domain) if self._is_isomorphism: description = "Diffeomorphism" else: @@ -480,8 +476,7 @@ def _repr_(self): else: description += " from the {} to itself".format(self._domain) else: - description += " from the {} to the {}".format(self._domain, - self._codomain) + description += " from the {} to the {}".format(self._domain, self._codomain) return description def _init_derived(self): @@ -521,7 +516,7 @@ def _del_derived(self): sage: f._inverse # has been set to None by _del_derived() """ ContinuousMap._del_derived(self) # derived quantities of the mother - # class + # class self._diff.clear() def differential(self, point: ManifoldPoint) -> FiniteRankFreeModuleMorphism: @@ -630,8 +625,7 @@ def differential(self, point: ManifoldPoint) -> FiniteRankFreeModuleMorphism: break if chartp is None: - raise ValueError("no common chart have been found for the " + - "coordinate expressions of {} and {}".format(self, point)) + raise ValueError("no common chart have been found for the " + "coordinate expressions of {} and {}".format(self, point)) diff_funct = self.differential_functions(*chartp) chart1 = chartp[0] @@ -639,20 +633,17 @@ def differential(self, point: ManifoldPoint) -> FiniteRankFreeModuleMorphism: coord_point = point.coord(chart1) n1 = self._domain.dim() n2 = self._codomain.dim() - matrix = [[diff_funct[i][j](*coord_point) for j in range(n1)] - for i in range(n2)] + matrix = [[diff_funct[i][j](*coord_point) for j in range(n1)] for i in range(n2)] bases = (chart1.frame().at(point), chart2.frame().at(image_point)) if self._name is not None and point._name is not None: name = 'd%s_%s' % (self._name, point._name) else: name = None if self._latex_name is not None and point._latex_name is not None: - latex_name = r'{\mathrm{d}%s}_{%s}' % (self._latex_name, - point._latex_name) + latex_name = r'{\mathrm{d}%s}_{%s}' % (self._latex_name, point._latex_name) else: latex_name = None - return tsp_source.hom(tsp_image, matrix, bases=bases, - name=name, latex_name=latex_name) + return tsp_source.hom(tsp_image, matrix, bases=bases, name=name, latex_name=latex_name) def differential_functions(self, chart1=None, chart2=None): r""" @@ -839,11 +830,11 @@ def jacobian_matrix(self, chart1=None, chart2=None): Full MatrixSpace of 3 by 2 dense matrices over Symbolic Ring """ from sage.matrix.constructor import matrix + diff_funct = self.differential_functions(chart1, chart2) n1 = self._domain.dim() n2 = self._codomain.dim() - return matrix([[diff_funct[i][j].expr() for j in range(n1)] - for i in range(n2)]) + return matrix([[diff_funct[i][j].expr() for j in range(n1)] for i in range(n2)]) def pullback(self, tensor_or_codomain_subset, name=None, latex_name=None): r""" @@ -947,8 +938,7 @@ def pullback(self, tensor_or_codomain_subset, name=None, latex_name=None): (2*cos(t) + 2) dt⊗dt """ if not hasattr(tensor_or_codomain_subset, '_domain'): - return super().pullback(tensor_or_codomain_subset, - name=name, latex_name=latex_name) + return super().pullback(tensor_or_codomain_subset, name=name, latex_name=latex_name) tensor = tensor_or_codomain_subset from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal @@ -984,18 +974,14 @@ def _pullback_chart(diff_map, tensor, chart1, chart2): resu_latex_name = None if diff_map._name is not None and tensor._name is not None: resu_name = diff_map._name + '^*(' + tensor._name + ')' - if (diff_map._latex_name is not None and - tensor._latex_name is not None): - resu_latex_name = '{' + diff_map._latex_name + '}^*' \ - + tensor._latex_name + if diff_map._latex_name is not None and tensor._latex_name is not None: + resu_latex_name = '{' + diff_map._latex_name + '}^*' + tensor._latex_name fmodule1 = dom1.vector_field_module() ring1 = fmodule1._ring si1 = fmodule1._sindex of1 = fmodule1._output_formatter si2 = dom2._sindex - resu = fmodule1.tensor((0, ncov), name=resu_name, - latex_name=resu_latex_name, sym=tensor._sym, - antisym=tensor._antisym) + resu = fmodule1.tensor((0, ncov), name=resu_name, latex_name=resu_latex_name, sym=tensor._sym, antisym=tensor._antisym) nproc = Parallelism().get('tensor') ind_old_list = list(dom2.manifold().index_generator(ncov)) @@ -1005,18 +991,13 @@ def _pullback_chart(diff_map, tensor, chart1, chart2): tcomp = tensor._components[frame2] if isinstance(tcomp, CompFullySym): - ptcomp = CompFullySym(ring1, frame1, ncov, start_index=si1, - output_formatter=of1) + ptcomp = CompFullySym(ring1, frame1, ncov, start_index=si1, output_formatter=of1) elif isinstance(tcomp, CompFullyAntiSym): - ptcomp = CompFullyAntiSym(ring1, frame1, ncov, start_index=si1, - output_formatter=of1) + ptcomp = CompFullyAntiSym(ring1, frame1, ncov, start_index=si1, output_formatter=of1) elif isinstance(tcomp, CompWithSym): - ptcomp = CompWithSym(ring1, frame1, ncov, start_index=si1, - output_formatter=of1, sym=tcomp.sym, - antisym=tcomp.antisym) + ptcomp = CompWithSym(ring1, frame1, ncov, start_index=si1, output_formatter=of1, sym=tcomp.sym, antisym=tcomp.antisym) else: - ptcomp = Components(ring1, frame1, ncov, start_index=si1, - output_formatter=of1) + ptcomp = Components(ring1, frame1, ncov, start_index=si1, output_formatter=of1) phi = diff_map._coord_expression[(chart1, chart2)] jacob = phi.jacobian() # X2 coordinates expressed in terms of X1 ones via the diff. map: @@ -1024,18 +1005,15 @@ def _pullback_chart(diff_map, tensor, chart1, chart2): if nproc != 1: # Parallel computation - lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] + lol = lambda lst, sz: [lst[i : i + sz] for i in range(0, len(lst), sz)] ind_list = list(ptcomp.non_redundant_index_generator()) ind_step = max(1, (len(ind_list) // nproc) // 2) local_list = lol(ind_list, ind_step) # list of input parameters - listParalInput = [(tcomp, chart1, chart2, coord2_1, jacob, - ind_old_list, si1, si2, ncov, ind_part) - for ind_part in local_list] + listParalInput = [(tcomp, chart1, chart2, coord2_1, jacob, ind_old_list, si1, si2, ncov, ind_part) for ind_part in local_list] @parallel(p_iter='multiprocessing', ncpus=nproc) - def paral_comp(tcomp, chart1, chart2, coord2_1, jacob, - ind_old_list, si1, si2, ncov, local_list_ind): + def paral_comp(tcomp, chart1, chart2, coord2_1, jacob, ind_old_list, si1, si2, ncov, local_list_ind): partial = [] for ind_new in local_list_ind: res = 0 @@ -1043,7 +1021,7 @@ def paral_comp(tcomp, chart1, chart2, coord2_1, jacob, ff = tcomp[[ind_old]].coord_function(chart2) t = chart1.function(ff(*coord2_1)) for i in range(ncov): - t *= jacob[ind_old[i]-si2, ind_new[i]-si1] + t *= jacob[ind_old[i] - si2, ind_new[i] - si1] res += t partial.append([ind_new, res]) return partial @@ -1060,12 +1038,13 @@ def paral_comp(tcomp, chart1, chart2, coord2_1, jacob, ff = tcomp[[ind_old]].coord_function(chart2) t = chart1.function(ff(*coord2_1)) for i in range(ncov): - t *= jacob[ind_old[i]-si2, ind_new[i]-si1] + t *= jacob[ind_old[i] - si2, ind_new[i] - si1] res += t ptcomp[ind_new] = res resu._components[frame1] = ptcomp return resu + # End of function _pullback_chart # Special case of the identity map: @@ -1079,15 +1058,13 @@ def paral_comp(tcomp, chart1, chart2, coord2_1, jacob, raise ValueError("the tensor field is not defined on the map codomain") (ncon, ncov) = tensor._tensor_type if ncon != 0: - raise TypeError("the pullback cannot be taken on a tensor " + - "with some contravariant part") + raise TypeError("the pullback cannot be taken on a tensor " + "with some contravariant part") resu_name = None resu_latex_name = None if self._name is not None and tensor._name is not None: resu_name = self._name + '^*(' + tensor._name + ')' if self._latex_name is not None and tensor._latex_name is not None: - resu_latex_name = '{' + self._latex_name + '}^*' \ - + tensor._latex_name + resu_latex_name = '{' + self._latex_name + '}^*' + tensor._latex_name if ncov == 0: # Case of a scalar field resu_fc = [] @@ -1097,19 +1074,17 @@ def paral_comp(tcomp, chart1, chart2, coord2_1, jacob, phi = self._coord_expression[(chart1, chart2)] coord1 = chart1._xx ff = tensor._express[chart2] - resu_fc.append( chart1.function(ff(*(phi(*coord1)))) ) + resu_fc.append(chart1.function(ff(*(phi(*coord1))))) dom_resu = resu_fc[0].parent()._chart.domain() for fc in resu_fc[1:]: dom_resu = dom_resu.union(fc.parent()._chart.domain()) - resu = dom_resu.scalar_field(name=resu_name, - latex_name=resu_latex_name) + resu = dom_resu.scalar_field(name=resu_name, latex_name=resu_latex_name) for fc in resu_fc: resu._express[fc.parent()._chart] = fc else: # Case of tensor field of rank >= 1 if tensor._vmodule._dest_map is not tdom.identity_map(): - raise TypeError("the pullback is defined only for tensor " + - "fields on {}".format(dom2)) + raise TypeError("the pullback is defined only for tensor " + "fields on {}".format(dom2)) resu_rst = [] for chart_pair in self._coord_expression: chart1 = chart_pair[0] @@ -1119,15 +1094,11 @@ def paral_comp(tcomp, chart1, chart2, coord2_1, jacob, self_r = self.restrict(chart1._domain, subcodomain=ch2dom) tensor_r = tensor.restrict(ch2dom) if chart2.frame() in tensor_r._components: - resu_rst.append(_pullback_chart(self_r, tensor_r, - chart1, chart2)) + resu_rst.append(_pullback_chart(self_r, tensor_r, chart1, chart2)) dom_resu = resu_rst[0]._domain for rst in resu_rst[1:]: dom_resu = dom_resu.union(rst._domain) - resu = dom_resu.tensor_field(0, ncov, name=resu_name, - latex_name=resu_latex_name, - sym=resu_rst[0]._sym, - antisym=resu_rst[0]._antisym) + resu = dom_resu.tensor_field(0, ncov, name=resu_name, latex_name=resu_latex_name, sym=resu_rst[0]._sym, antisym=resu_rst[0]._antisym) for rst in resu_rst: if rst._domain is not resu._domain: resu._restrictions[rst._domain] = rst @@ -1204,26 +1175,22 @@ def pushforward(self, tensor): Components, CompWithSym, ) + vmodule = tensor.base_module() dest_map = vmodule.destination_map() dom1 = tensor.domain() ambient_dom1 = dest_map.codomain() if not ambient_dom1.is_subset(self._domain): - raise ValueError("the {} does not take its ".format(tensor) + - "values on the domain of the {}".format(self)) + raise ValueError("the {} does not take its ".format(tensor) + "values on the domain of the {}".format(self)) (ncon, ncov) = tensor.tensor_type() if ncov != 0: - raise ValueError("the pushforward cannot be taken on a tensor " + - "with some covariant part") + raise ValueError("the pushforward cannot be taken on a tensor " + "with some covariant part") if ncon == 0: - raise ValueError("the pushforward cannot be taken on a scalar " + - "field") + raise ValueError("the pushforward cannot be taken on a scalar " + "field") if dest_map != dom1.identity_map(): - raise NotImplementedError("the case of a non-trivial destination" + - " map is not implemented yet") + raise NotImplementedError("the case of a non-trivial destination" + " map is not implemented yet") if not isinstance(tensor, TensorFieldParal): - raise NotImplementedError("the case of a non-parallelizable " + - "domain is not implemented yet") + raise NotImplementedError("the case of a non-parallelizable " + "domain is not implemented yet") # A pair of charts (chart1, chart2) where the computation # is feasible is searched, privileging the default chart of the # map's domain for chart1 @@ -1231,21 +1198,19 @@ def pushforward(self, tensor): chart2 = None def_chart1 = dom1.default_chart() def_chart2 = self._codomain.default_chart() - if (def_chart1._frame in tensor._components - and (def_chart1, def_chart2) in self._coord_expression): + if def_chart1._frame in tensor._components and (def_chart1, def_chart2) in self._coord_expression: chart1 = def_chart1 chart2 = def_chart2 else: - for (chart1n, chart2n) in self._coord_expression: - if (chart2n == def_chart2 - and chart1n._frame in tensor._components): + for chart1n, chart2n in self._coord_expression: + if chart2n == def_chart2 and chart1n._frame in tensor._components: chart1 = chart1n chart2 = def_chart2 break if chart2 is None: # It is not possible to have def_chart2 as chart for # expressing the result; any other chart is then looked for: - for (chart1n, chart2n) in self._coord_expression: + for chart1n, chart2n in self._coord_expression: if chart1n._frame in tensor._components: chart1 = chart1n chart2 = chart2n @@ -1262,9 +1227,7 @@ def pushforward(self, tensor): except ValueError: pass else: - raise ValueError("no pair of charts could be found to " + - "compute the pushforward of " + - "the {} by the {}".format(tensor, self)) + raise ValueError("no pair of charts could be found to " + "compute the pushforward of " + "the {} by the {}".format(tensor, self)) # Vector field module for the result: fmodule2 = dom1.vector_field_module(dest_map=self) @@ -1277,18 +1240,13 @@ def pushforward(self, tensor): tcomp = tensor._components[chart1.frame()] # Construction of the pushforward components (ptcomp): if isinstance(tcomp, CompFullySym): - ptcomp = CompFullySym(ring2, frame2, ncon, start_index=si2, - output_formatter=of2) + ptcomp = CompFullySym(ring2, frame2, ncon, start_index=si2, output_formatter=of2) elif isinstance(tcomp, CompFullyAntiSym): - ptcomp = CompFullyAntiSym(ring2, frame2, ncon, start_index=si2, - output_formatter=of2) + ptcomp = CompFullyAntiSym(ring2, frame2, ncon, start_index=si2, output_formatter=of2) elif isinstance(tcomp, CompWithSym): - ptcomp = CompWithSym(ring2, frame2, ncon, start_index=si2, - output_formatter=of2, sym=tcomp._sym, - antisym=tcomp._antisym) + ptcomp = CompWithSym(ring2, frame2, ncon, start_index=si2, output_formatter=of2, sym=tcomp._sym, antisym=tcomp._antisym) else: - ptcomp = Components(ring2, frame2, ncon, start_index=si2, - output_formatter=of2) + ptcomp = Components(ring2, frame2, ncon, start_index=si2, output_formatter=of2) # Computation of the pushforward components: jacob = self.differential_functions(chart1=chart1, chart2=chart2) si2 = chart2.domain().start_index() @@ -1297,7 +1255,7 @@ def pushforward(self, tensor): for ind_old in dom1.index_generator(ncon): t = tcomp[[ind_old]].coord_function(chart1) for i in range(ncon): - t *= jacob[ind_new[i]-si2, ind_old[i]-si1] + t *= jacob[ind_new[i] - si2, ind_old[i] - si1] res += t ptcomp[ind_new] = res # Name of the result: @@ -1306,9 +1264,7 @@ def pushforward(self, tensor): if self._name is not None and tensor._name is not None: resu_name = self._name + '_*(' + tensor._name + ')' if self._latex_name is not None and tensor._latex_name is not None: - resu_latex_name = '{' + self._latex_name + '}_*' \ - + tensor._latex_name + resu_latex_name = '{' + self._latex_name + '}_*' + tensor._latex_name # Creation of the result with the components obtained above: - resu = fmodule2.tensor_from_comp((ncon, 0), ptcomp, name=resu_name, - latex_name=resu_latex_name) + resu = fmodule2.tensor_from_comp((ncon, 0), ptcomp, name=resu_name, latex_name=resu_latex_name) return resu diff --git a/src/sage/manifolds/differentiable/differentiable_submanifold.py b/src/sage/manifolds/differentiable/differentiable_submanifold.py index 51dd2962557..550585bc60b 100644 --- a/src/sage/manifolds/differentiable/differentiable_submanifold.py +++ b/src/sage/manifolds/differentiable/differentiable_submanifold.py @@ -159,10 +159,8 @@ class DifferentiableSubmanifold(DifferentiableManifold, TopologicalSubmanifold): :mod:`~sage.manifolds.manifold` and :mod:`~sage.manifolds.topological_submanifold` """ - def __init__(self, n, name, field, structure, ambient=None, - base_manifold=None, diff_degree=infinity, - latex_name=None, start_index=0, category=None, - unique_tag=None): + + def __init__(self, n, name, field, structure, ambient=None, base_manifold=None, diff_degree=infinity, latex_name=None, start_index=0, category=None, unique_tag=None): r""" Construct a submanifold of a differentiable manifold. @@ -180,14 +178,8 @@ def __init__(self, n, name, field, structure, ambient=None, sage: S.start_index() 1 """ - DifferentiableManifold.__init__(self, n, name, field, structure, - base_manifold=base_manifold, - diff_degree=diff_degree, - latex_name=latex_name, - start_index=start_index, - category=category) - if not (ambient is None - or isinstance(ambient, DifferentiableManifold)): + DifferentiableManifold.__init__(self, n, name, field, structure, base_manifold=base_manifold, diff_degree=diff_degree, latex_name=latex_name, start_index=start_index, category=category) + if not (ambient is None or isinstance(ambient, DifferentiableManifold)): raise TypeError("ambient must be a differentiable manifold") self._init_immersion(ambient=ambient) @@ -216,10 +208,8 @@ def _repr_(self): if self._ambient is None: return super(DifferentiableManifold, self).__repr__() if self._embedded: - return "{}-dimensional {} submanifold {} embedded in the {}".format( - self._dim, self._structure.name, self._name, self._ambient) - return "{}-dimensional {} submanifold {} immersed in the {}".format( - self._dim, self._structure.name, self._name, self._ambient) + return "{}-dimensional {} submanifold {} embedded in the {}".format(self._dim, self._structure.name, self._name, self._ambient) + return "{}-dimensional {} submanifold {} immersed in the {}".format(self._dim, self._structure.name, self._name, self._ambient) def open_subset(self, name, latex_name=None, coord_def={}, supersets=None): r""" @@ -277,12 +267,7 @@ def open_subset(self, name, latex_name=None, coord_def={}, supersets=None): 2-dimensional differentiable submanifold N embedded in the 3-dimensional differentiable manifold M """ - resu = DifferentiableSubmanifold(self._dim, name, self._field, - self._structure, ambient=self._ambient, - base_manifold=self._manifold, - diff_degree=self._diff_degree, - latex_name=latex_name, - start_index=self._sindex) + resu = DifferentiableSubmanifold(self._dim, name, self._field, self._structure, ambient=self._ambient, base_manifold=self._manifold, diff_degree=self._diff_degree, latex_name=latex_name, start_index=self._sindex) if supersets is None: supersets = [self] for superset in supersets: diff --git a/src/sage/manifolds/differentiable/examples/euclidean.py b/src/sage/manifolds/differentiable/examples/euclidean.py index 433993d36ad..4bf2db00c6f 100644 --- a/src/sage/manifolds/differentiable/examples/euclidean.py +++ b/src/sage/manifolds/differentiable/examples/euclidean.py @@ -399,14 +399,14 @@ - \M. Berger: *Geometry I* [Ber1987]_ """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2018 Eric Gourgoulhon # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.manifolds import Manifolds from sage.categories.metric_spaces import MetricSpaces @@ -642,11 +642,9 @@ class EuclideanSpace(PseudoRiemannianManifold): sage: g.display() g = dx1⊗dx1 + dx2⊗dx2 + dx3⊗dx3 + dx4⊗dx4 """ + @staticmethod - def __classcall_private__(cls, n=None, name=None, latex_name=None, - coordinates='Cartesian', symbols=None, - metric_name='g', metric_latex_name=None, - start_index=1, names=None, unique_tag=None): + def __classcall_private__(cls, n=None, name=None, latex_name=None, coordinates='Cartesian', symbols=None, metric_name='g', metric_latex_name=None, start_index=1, names=None, unique_tag=None): r""" Determine the correct class to return based upon the input. @@ -698,37 +696,18 @@ def __classcall_private__(cls, n=None, name=None, latex_name=None, from time import time from sage.misc.prandom import getrandbits + if unique_tag is None: unique_tag = getrandbits(128) * time() if n == 2: - return EuclideanPlane(name=name, latex_name=latex_name, - coordinates=coordinates, symbols=symbols, - metric_name=metric_name, - metric_latex_name=metric_latex_name, - start_index=start_index, - unique_tag=unique_tag) + return EuclideanPlane(name=name, latex_name=latex_name, coordinates=coordinates, symbols=symbols, metric_name=metric_name, metric_latex_name=metric_latex_name, start_index=start_index, unique_tag=unique_tag) if n == 3: - return Euclidean3dimSpace(name=name, latex_name=latex_name, - coordinates=coordinates, symbols=symbols, - metric_name=metric_name, - metric_latex_name=metric_latex_name, - start_index=start_index, - unique_tag=unique_tag) - - return super().__classcall__(cls, - n, name=name, latex_name=latex_name, - coordinates=coordinates, symbols=symbols, - metric_name=metric_name, - metric_latex_name=metric_latex_name, - start_index=start_index, - unique_tag=unique_tag) - - def __init__(self, n, name=None, latex_name=None, - coordinates='Cartesian', symbols=None, metric_name='g', - metric_latex_name=None, start_index=1, base_manifold=None, - category=None, init_coord_methods=None, - unique_tag=None): + return Euclidean3dimSpace(name=name, latex_name=latex_name, coordinates=coordinates, symbols=symbols, metric_name=metric_name, metric_latex_name=metric_latex_name, start_index=start_index, unique_tag=unique_tag) + + return super().__classcall__(cls, n, name=name, latex_name=latex_name, coordinates=coordinates, symbols=symbols, metric_name=metric_name, metric_latex_name=metric_latex_name, start_index=start_index, unique_tag=unique_tag) + + def __init__(self, n, name=None, latex_name=None, coordinates='Cartesian', symbols=None, metric_name='g', metric_latex_name=None, start_index=1, base_manifold=None, category=None, init_coord_methods=None, unique_tag=None): r""" Construct a Euclidean space. @@ -771,12 +750,7 @@ def __init__(self, n, name=None, latex_name=None, category = Manifolds(RR).Smooth().Connected() & MetricSpaces().Complete() # NB: RR is a proxy for the field of real numbers, until # Issue #24456 is ready - PseudoRiemannianManifold.__init__(self, n, name, metric_name=metric_name, - signature=n, base_manifold=base_manifold, - latex_name=latex_name, - metric_latex_name=metric_latex_name, - start_index=start_index, - category=category) + PseudoRiemannianManifold.__init__(self, n, name, metric_name=metric_name, signature=n, base_manifold=base_manifold, latex_name=latex_name, metric_latex_name=metric_latex_name, start_index=start_index, category=category) if symbols is None: if n == 1: if coordinates == 'Cartesian': @@ -850,9 +824,7 @@ def _init_cartesian(self, symbols): frame = chart.frame() # Renaming (∂/∂x, ∂/∂y, ...) to (e_x, e_y, ...): coords = chart[:] - frame.set_name('e', - indices=tuple(str(x) for x in coords), - latex_indices=tuple(latex(x) for x in coords)) + frame.set_name('e', indices=tuple(str(x) for x in coords), latex_indices=tuple(latex(x) for x in coords)) g = self.metric() gc = g.add_comp(frame) for i in self.irange(): @@ -969,11 +941,10 @@ def dist(self, p, q): d2 = 0 for xp, xq in zip(coords_p, coords_q): dx = xp - xq - d2 += dx*dx + d2 += dx * dx return sqrt(d2) - def sphere(self, radius=1, center=None, name=None, latex_name=None, - coordinates='spherical', names=None): + def sphere(self, radius=1, center=None, name=None, latex_name=None, coordinates='spherical', names=None): r""" Return an `(n-1)`-sphere smoothly embedded in ``self``. @@ -1036,9 +1007,9 @@ def sphere(self, radius=1, center=None, name=None, latex_name=None, if n == 1: raise ValueError('Euclidean space must have dimension of at least 2') from sage.manifolds.differentiable.examples.sphere import Sphere - return Sphere(n-1, radius=radius, ambient_space=self, - center=center, name=name, latex_name=latex_name, - coordinates=coordinates, names=names) + + return Sphere(n - 1, radius=radius, ambient_space=self, center=center, name=name, latex_name=latex_name, coordinates=coordinates, names=names) + ############################################################################### @@ -1163,9 +1134,8 @@ class EuclideanPlane(EuclideanSpace): :ref:`EuclideanSpace_example1` """ - def __init__(self, name=None, latex_name=None, coordinates='Cartesian', - symbols=None, metric_name='g', metric_latex_name=None, - start_index=1, base_manifold=None, category=None, unique_tag=None): + + def __init__(self, name=None, latex_name=None, coordinates='Cartesian', symbols=None, metric_name='g', metric_latex_name=None, start_index=1, base_manifold=None, category=None, unique_tag=None): r""" Construct a Euclidean plane. @@ -1186,17 +1156,8 @@ def __init__(self, name=None, latex_name=None, coordinates='Cartesian', symbols = 'r ph:\\phi' self._polar_chart = None # to be constructed later if necessary self._polar_frame = None # orthonormal frame associated to polar coord - init_coord_methods = {'Cartesian': self._init_cartesian, - 'polar': self._init_polar} - EuclideanSpace.__init__(self, 2, name=name, - latex_name=latex_name, - coordinates=coordinates, - symbols=symbols, - metric_name=metric_name, - metric_latex_name=metric_latex_name, - start_index=start_index, - base_manifold=base_manifold, category=category, - init_coord_methods=init_coord_methods) + init_coord_methods = {'Cartesian': self._init_cartesian, 'polar': self._init_polar} + EuclideanSpace.__init__(self, 2, name=name, latex_name=latex_name, coordinates=coordinates, symbols=symbols, metric_name=metric_name, metric_latex_name=metric_latex_name, start_index=start_index, base_manifold=base_manifold, category=category, init_coord_methods=init_coord_methods) if coordinates == 'polar': # The default frame is the polar coordinate frame; we change it # to the orthonormal polar frame @@ -1235,8 +1196,7 @@ def _init_polar(self, symbols): """ coords = symbols.split() # list of strings, one per coordinate # Adding the coordinate ranges: - coordinates = (coords[0] + ':(0,+oo) ' + coords[1] - + ':(0,2*pi):periodic') + coordinates = coords[0] + ':(0,+oo) ' + coords[1] + ':(0,2*pi):periodic' chart = self.chart(coordinates=coordinates) self._polar_chart = chart frame = chart.frame() @@ -1253,9 +1213,7 @@ def _init_polar(self, symbols): to_orthonormal = self.automorphism_field() to_orthonormal[frame, i1, i1, chart] = 1 to_orthonormal[frame, i2, i2, chart] = 1 / r - oframe = frame.new_frame(to_orthonormal, 'e', - indices=(str(r), str(ph)), - latex_indices=(latex(r), latex(ph))) + oframe = frame.new_frame(to_orthonormal, 'e', indices=(str(r), str(ph)), latex_indices=(latex(r), latex(ph))) self._polar_frame = oframe g.comp(oframe) @@ -1292,9 +1250,8 @@ def _transition_polar_cartesian(self): chart_pol = self._polar_chart x, y = chart_cart[:] r, ph = chart_pol[:] - pol_to_cart = chart_pol.transition_map(chart_cart, - [r*cos(ph), r*sin(ph)]) - pol_to_cart.set_inverse(sqrt(x**2+y**2), atan2(y,x), check=False) + pol_to_cart = chart_pol.transition_map(chart_cart, [r * cos(ph), r * sin(ph)]) + pol_to_cart.set_inverse(sqrt(x**2 + y**2), atan2(y, x), check=False) # Automorphism Cartesian frame → orthonormal polar frame: oframe = self._polar_frame cframe = chart_cart.frame() @@ -1309,7 +1266,7 @@ def _transition_polar_cartesian(self): cmp_cf = cframe_to_oframe.add_comp(cframe) for i in self.irange(): for j in self.irange(): - cmp_cf[[i,j]] = cmp_of[[i,j]] + cmp_cf[[i, j]] = cmp_of[[i, j]] # Automorphism orthonormal polar frame → Cartesian frame: oframe_to_cframe = chg[(sframe, cframe)] * chg[(oframe, sframe)] # oframe_to_cframe has been computed only in sframe; @@ -1320,15 +1277,13 @@ def _transition_polar_cartesian(self): cmp_cf = oframe_to_cframe.add_comp(cframe) for i in self.irange(): for j in self.irange(): - cmp_cf[[i,j]] = cmp_of[[i,j]] + cmp_cf[[i, j]] = cmp_of[[i, j]] # Storage of the results: chg[(cframe, oframe)] = cframe_to_oframe chg[(oframe, cframe)] = oframe_to_cframe vmodule = self.vector_field_module() - vmodule.set_change_of_basis(cframe, oframe, cframe_to_oframe, - compute_inverse=False) - vmodule.set_change_of_basis(oframe, cframe, oframe_to_cframe, - compute_inverse=False) + vmodule.set_change_of_basis(cframe, oframe, cframe_to_oframe, compute_inverse=False) + vmodule.set_change_of_basis(oframe, cframe, oframe_to_cframe, compute_inverse=False) def cartesian_coordinates(self, symbols=None, names=None): r""" @@ -1554,6 +1509,7 @@ def polar_frame(self): ############################################################################### + class Euclidean3dimSpace(EuclideanSpace): r""" 3-dimensional Euclidean space. @@ -1684,9 +1640,8 @@ class Euclidean3dimSpace(EuclideanSpace): :ref:`EuclideanSpace_example2` """ - def __init__(self, name=None, latex_name=None, coordinates='Cartesian', - symbols=None, metric_name='g', metric_latex_name=None, - start_index=1, base_manifold=None, category=None, unique_tag=None): + + def __init__(self, name=None, latex_name=None, coordinates='Cartesian', symbols=None, metric_name='g', metric_latex_name=None, start_index=1, base_manifold=None, category=None, unique_tag=None): r""" Construct a Euclidean 3-space. @@ -1707,22 +1662,12 @@ def __init__(self, name=None, latex_name=None, coordinates='Cartesian', symbols = 'r th:\\theta ph:\\phi' elif coordinates == 'cylindrical': symbols = 'r ph:\\phi z' - self._spherical_chart = None # to be constructed later if necessary - self._spherical_frame = None # orthonormal frame + self._spherical_chart = None # to be constructed later if necessary + self._spherical_frame = None # orthonormal frame self._cylindrical_chart = None self._cylindrical_frame = None # orthonormal frame - init_coord_methods = {'Cartesian': self._init_cartesian, - 'spherical': self._init_spherical, - 'cylindrical': self._init_cylindrical} - EuclideanSpace.__init__(self, 3, name=name, - latex_name=latex_name, - coordinates=coordinates, - symbols=symbols, - metric_name=metric_name, - metric_latex_name=metric_latex_name, - start_index=start_index, - base_manifold=base_manifold, category=category, - init_coord_methods=init_coord_methods) + init_coord_methods = {'Cartesian': self._init_cartesian, 'spherical': self._init_spherical, 'cylindrical': self._init_cylindrical} + EuclideanSpace.__init__(self, 3, name=name, latex_name=latex_name, coordinates=coordinates, symbols=symbols, metric_name=metric_name, metric_latex_name=metric_latex_name, start_index=start_index, base_manifold=base_manifold, category=category, init_coord_methods=init_coord_methods) if coordinates == 'spherical': # The default frame is the spherical coordinate frame; we change it # to the orthonormal spherical frame @@ -1765,8 +1710,7 @@ def _init_spherical(self, symbols): """ coords = symbols.split() # list of strings, one per coordinate # Adding the coordinate ranges: - coordinates = (coords[0] + ':(0,+oo) ' + coords[1] + ':(0,pi) ' - + coords[2] + ':(0,2*pi):periodic') + coordinates = coords[0] + ':(0,+oo) ' + coords[1] + ':(0,pi) ' + coords[2] + ':(0,2*pi):periodic' chart = self.chart(coordinates=coordinates) self._spherical_chart = chart frame = chart.frame() @@ -1780,15 +1724,13 @@ def _init_spherical(self, symbols): r, th, ph = chart[:] gc[i1, i1, chart] = 1 gc[i2, i2, chart] = r**2 - gc[i3, i3, chart] = (r*sin(th))**2 + gc[i3, i3, chart] = (r * sin(th)) ** 2 # Orthonormal frame associated with spherical coordinates: to_orthonormal = self.automorphism_field() to_orthonormal[frame, i1, i1, chart] = 1 - to_orthonormal[frame, i2, i2, chart] = 1/r - to_orthonormal[frame, i3, i3, chart] = 1/(r*sin(th)) - oframe = frame.new_frame(to_orthonormal, 'e', - indices=(str(r), str(th), str(ph)), - latex_indices=(latex(r), latex(th), latex(ph))) + to_orthonormal[frame, i2, i2, chart] = 1 / r + to_orthonormal[frame, i3, i3, chart] = 1 / (r * sin(th)) + oframe = frame.new_frame(to_orthonormal, 'e', indices=(str(r), str(th), str(ph)), latex_indices=(latex(r), latex(th), latex(ph))) self._spherical_frame = oframe g.comp(oframe) @@ -1808,8 +1750,7 @@ def _init_cylindrical(self, symbols): """ coords = symbols.split() # list of strings, one per coordinate # Adding the coordinate ranges: - coordinates = (coords[0] + ':(0,+oo) ' + coords[1] - + ':(0,2*pi):periodic ' + coords[2]) + coordinates = coords[0] + ':(0,+oo) ' + coords[1] + ':(0,2*pi):periodic ' + coords[2] chart = self.chart(coordinates=coordinates) self._cylindrical_chart = chart frame = chart.frame() @@ -1829,9 +1770,7 @@ def _init_cylindrical(self, symbols): to_orthonormal[frame, i1, i1, chart] = 1 to_orthonormal[frame, i2, i2, chart] = 1 / rh to_orthonormal[frame, i3, i3, chart] = 1 - oframe = frame.new_frame(to_orthonormal, 'e', - indices=(str(rh), str(ph), str(z)), - latex_indices=(latex(rh), latex(ph), latex(z))) + oframe = frame.new_frame(to_orthonormal, 'e', indices=(str(rh), str(ph), str(z)), latex_indices=(latex(rh), latex(ph), latex(z))) self._cylindrical_frame = oframe g.comp(oframe) @@ -1874,11 +1813,8 @@ def _transition_spherical_cartesian(self): chart_spher = self._spherical_chart x, y, z = chart_cart[:] r, th, ph = chart_spher[:] - spher_to_cart = chart_spher.transition_map(chart_cart, - [r*sin(th)*cos(ph), r*sin(th)*sin(ph), r*cos(th)]) - spher_to_cart.set_inverse(sqrt(x**2+y**2+z**2), - atan2(sqrt(x**2+y**2),z), atan2(y, x), - check=False) + spher_to_cart = chart_spher.transition_map(chart_cart, [r * sin(th) * cos(ph), r * sin(th) * sin(ph), r * cos(th)]) + spher_to_cart.set_inverse(sqrt(x**2 + y**2 + z**2), atan2(sqrt(x**2 + y**2), z), atan2(y, x), check=False) # Automorphism Cartesian frame → orthonormal spherical frame: oframe = self._spherical_frame cframe = chart_cart.frame() @@ -1893,7 +1829,7 @@ def _transition_spherical_cartesian(self): cmp_cf = cframe_to_oframe.add_comp(cframe) for i in self.irange(): for j in self.irange(): - cmp_cf[[i,j]] = cmp_of[[i,j]] + cmp_cf[[i, j]] = cmp_of[[i, j]] # Automorphism orthonormal spherical frame → Cartesian frame: oframe_to_cframe = chg[(sframe, cframe)] * chg[(oframe, sframe)] # oframe_to_cframe has been computed only in sframe; @@ -1904,15 +1840,13 @@ def _transition_spherical_cartesian(self): cmp_cf = oframe_to_cframe.add_comp(cframe) for i in self.irange(): for j in self.irange(): - cmp_cf[[i,j]] = cmp_of[[i,j]] + cmp_cf[[i, j]] = cmp_of[[i, j]] # Storage of the results: chg[(cframe, oframe)] = cframe_to_oframe chg[(oframe, cframe)] = oframe_to_cframe vmodule = self.vector_field_module() - vmodule.set_change_of_basis(cframe, oframe, cframe_to_oframe, - compute_inverse=False) - vmodule.set_change_of_basis(oframe, cframe, oframe_to_cframe, - compute_inverse=False) + vmodule.set_change_of_basis(cframe, oframe, cframe_to_oframe, compute_inverse=False) + vmodule.set_change_of_basis(oframe, cframe, oframe_to_cframe, compute_inverse=False) def _transition_cylindrical_cartesian(self): r""" @@ -1953,9 +1887,8 @@ def _transition_cylindrical_cartesian(self): chart_cylind = self._cylindrical_chart x, y, z = chart_cart[:] rh, ph, z = chart_cylind[:] - cylind_to_cart = chart_cylind.transition_map(chart_cart, - [rh*cos(ph), rh*sin(ph), z]) - cylind_to_cart.set_inverse(sqrt(x**2+y**2), atan2(y, x), z, check=False) + cylind_to_cart = chart_cylind.transition_map(chart_cart, [rh * cos(ph), rh * sin(ph), z]) + cylind_to_cart.set_inverse(sqrt(x**2 + y**2), atan2(y, x), z, check=False) # Automorphism Cartesian frame → orthonormal cylindrical frame: oframe = self._cylindrical_frame cframe = chart_cart.frame() @@ -1970,7 +1903,7 @@ def _transition_cylindrical_cartesian(self): cmp_cf = cframe_to_oframe.add_comp(cframe) for i in self.irange(): for j in self.irange(): - cmp_cf[[i,j]] = cmp_of[[i,j]] + cmp_cf[[i, j]] = cmp_of[[i, j]] # Automorphism orthonormal cylindrical frame → Cartesian frame: oframe_to_cframe = chg[(sframe, cframe)] * chg[(oframe, sframe)] # oframe_to_cframe has been computed only in sframe; @@ -1981,15 +1914,13 @@ def _transition_cylindrical_cartesian(self): cmp_cf = oframe_to_cframe.add_comp(cframe) for i in self.irange(): for j in self.irange(): - cmp_cf[[i,j]] = cmp_of[[i,j]] + cmp_cf[[i, j]] = cmp_of[[i, j]] # Storage of the results: chg[(cframe, oframe)] = cframe_to_oframe chg[(oframe, cframe)] = oframe_to_cframe vmodule = self.vector_field_module() - vmodule.set_change_of_basis(cframe, oframe, cframe_to_oframe, - compute_inverse=False) - vmodule.set_change_of_basis(oframe, cframe, oframe_to_cframe, - compute_inverse=False) + vmodule.set_change_of_basis(cframe, oframe, cframe_to_oframe, compute_inverse=False) + vmodule.set_change_of_basis(oframe, cframe, oframe_to_cframe, compute_inverse=False) def _transition_spherical_cylindrical(self): r""" @@ -2030,15 +1961,13 @@ def _transition_spherical_cylindrical(self): spher = self._spherical_chart rh, ph, z = cylind[:] r, th, ph = spher[:] - spher_to_cylind = spher.transition_map(cylind, - [r*sin(th), ph, r*cos(th)]) - spher_to_cylind.set_inverse(sqrt(rh**2 + z**2), atan2(rh,z), ph, - check=False) + spher_to_cylind = spher.transition_map(cylind, [r * sin(th), ph, r * cos(th)]) + spher_to_cylind.set_inverse(sqrt(rh**2 + z**2), atan2(rh, z), ph, check=False) # Automorphism orthon. cylindrical frame -> orthon. spherical frame - cf = cylind.frame() # coordinate cylindrical frame + cf = cylind.frame() # coordinate cylindrical frame sf = spher.frame() # coordinate spherical frame - ocf = self._cylindrical_frame # orthonormal cylindrical frame - osf = self._spherical_frame # orthonormal spherical frame + ocf = self._cylindrical_frame # orthonormal cylindrical frame + osf = self._spherical_frame # orthonormal spherical frame chg = self._frame_changes oc_to_os = chg[(sf, osf)] * chg[(cf, sf)] * chg[(ocf, cf)] # oc_to_os has been computed only in sf frame; its components in osf @@ -2049,7 +1978,7 @@ def _transition_spherical_cylindrical(self): cmp_ocf = oc_to_os.add_comp(ocf) for i in self.irange(): for j in self.irange(): - cmp_ocf[[i,j]] = cmp_osf[[i,j]] + cmp_ocf[[i, j]] = cmp_osf[[i, j]] # Automorphism orthon. spherical frame -> orthon. cylindrical frame os_to_oc = chg[(cf, ocf)] * chg[(sf, cf)] * chg[(osf, sf)] # oc_to_os has been computed only in cf frame; its components in ocf @@ -2060,7 +1989,7 @@ def _transition_spherical_cylindrical(self): cmp_osf = os_to_oc.add_comp(osf) for i in self.irange(): for j in self.irange(): - cmp_osf[[i,j]] = cmp_ocf[[i,j]] + cmp_osf[[i, j]] = cmp_ocf[[i, j]] # Storage of the results: chg[(ocf, osf)] = oc_to_os chg[(osf, ocf)] = os_to_oc diff --git a/src/sage/manifolds/differentiable/examples/real_line.py b/src/sage/manifolds/differentiable/examples/real_line.py index ef71608529e..1704fc9a764 100644 --- a/src/sage/manifolds/differentiable/examples/real_line.py +++ b/src/sage/manifolds/differentiable/examples/real_line.py @@ -14,7 +14,8 @@ - [Lee2013]_ """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger # @@ -22,7 +23,7 @@ # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.manifolds import Manifolds from sage.manifolds.differentiable.manifold import DifferentiableManifold @@ -296,10 +297,9 @@ class OpenInterval(DifferentiableManifold): sage: XK.coord_range() t: (1/2, 1) """ + @staticmethod - def __classcall_private__(cls, lower, upper, ambient_interval=None, - name=None, latex_name=None, coordinate=None, - names=None, start_index=0): + def __classcall_private__(cls, lower, upper, ambient_interval=None, name=None, latex_name=None, coordinate=None, names=None, start_index=0): r""" Determine the correct interval to return based upon the input. @@ -318,14 +318,9 @@ def __classcall_private__(cls, lower, upper, ambient_interval=None, coordinate = None names = None start_index = 0 - return super().__classcall__(cls, lower, upper, - ambient_interval=ambient_interval, name=name, - latex_name=latex_name, coordinate=coordinate, - names=names, start_index=start_index) - - def __init__(self, lower, upper, ambient_interval=None, - name=None, latex_name=None, - coordinate=None, names=None, start_index=0): + return super().__classcall__(cls, lower, upper, ambient_interval=ambient_interval, name=name, latex_name=latex_name, coordinate=coordinate, names=names, start_index=start_index) + + def __init__(self, lower, upper, ambient_interval=None, name=None, latex_name=None, coordinate=None, names=None, start_index=0): r""" Construct an open interval. @@ -354,11 +349,7 @@ def __init__(self, lower, upper, ambient_interval=None, field = 'real' structure = RealDifferentialStructure() category = Manifolds(RR).Smooth().Connected() - DifferentiableManifold.__init__(self, 1, name, field, structure, - base_manifold=ambient_manifold, - latex_name=latex_name, - start_index=start_index, - category=category) + DifferentiableManifold.__init__(self, 1, name, field, structure, base_manifold=ambient_manifold, latex_name=latex_name, start_index=start_index, category=category) if ambient_interval is None: if coordinate is None: if names is None: @@ -367,11 +358,9 @@ def __init__(self, lower, upper, ambient_interval=None, coordinate = names[0] else: if lower < ambient_interval.lower_bound(): - raise ValueError("the lower bound is smaller than that of " - + "the containing interval") + raise ValueError("the lower bound is smaller than that of " + "the containing interval") if upper > ambient_interval.upper_bound(): - raise ValueError("the upper bound is larger than that of " - + "the containing interval") + raise ValueError("the upper bound is larger than that of " + "the containing interval") self.declare_subset(ambient_interval) ambient_interval._top_subsets.add(self) if lower != minus_infinity: @@ -385,11 +374,9 @@ def __init__(self, lower, upper, ambient_interval=None, else: restrictions = None if ambient_interval is None: - self._canon_chart = self.chart(coordinates=coordinate, - coord_restrictions=restrictions) + self._canon_chart = self.chart(coordinates=coordinate, coord_restrictions=restrictions) else: - self._canon_chart = ambient_interval.canonical_chart().restrict(self, - restrictions=restrictions) + self._canon_chart = ambient_interval.canonical_chart().restrict(self, restrictions=restrictions) self._lower = lower self._upper = upper @@ -435,8 +422,7 @@ def _first_ngens(self, n): """ return self._canon_chart[:] - def _element_constructor_(self, coords=None, chart=None, name=None, - latex_name=None, check_coords=True): + def _element_constructor_(self, coords=None, chart=None, name=None, latex_name=None, check_coords=True): r""" Construct an element of ``self``. @@ -487,9 +473,7 @@ def _element_constructor_(self, coords=None, chart=None, name=None, """ if coords in SR: coords = (coords,) - return super()._element_constructor_(coords=coords, - chart=chart, name=name, latex_name=latex_name, - check_coords=check_coords) + return super()._element_constructor_(coords=coords, chart=chart, name=name, latex_name=latex_name, check_coords=check_coords) def _Hom_(self, other, category=None): r""" @@ -520,6 +504,7 @@ def _Hom_(self, other, category=None): True """ from sage.manifolds.differentiable.manifold_homset import DifferentiableCurveSet + return DifferentiableCurveSet(self, other) def canonical_chart(self): @@ -683,15 +668,14 @@ def open_interval(self, lower, upper, name=None, latex_name=None): if name is None: if latex_name is None: return OpenInterval(lower, upper, ambient_interval=self) - return OpenInterval(lower, upper, ambient_interval=self, - latex_name=latex_name) + return OpenInterval(lower, upper, ambient_interval=self, latex_name=latex_name) if latex_name is None: return OpenInterval(lower, upper, ambient_interval=self, name=name) - return OpenInterval(lower, upper, ambient_interval=self, name=name, - latex_name=latex_name) + return OpenInterval(lower, upper, ambient_interval=self, name=name, latex_name=latex_name) + +# ****************************************************************************** -#****************************************************************************** class RealLine(OpenInterval): r""" @@ -842,9 +826,9 @@ class RealLine(OpenInterval): sage: list(R.subset_family()) [Real interval (0, 1), Real number line ℝ] """ + @staticmethod - def __classcall__(cls, name=unicode_mathbbR, latex_name=r'\Bold{R}', - coordinate=None, names=None, start_index=0): + def __classcall__(cls, name=unicode_mathbbR, latex_name=r'\Bold{R}', coordinate=None, names=None, start_index=0): r""" Determine the correct interval to return based upon the input. @@ -857,13 +841,9 @@ def __classcall__(cls, name=unicode_mathbbR, latex_name=r'\Bold{R}', sage: R is R1 True """ - return super().__classcall__(cls, name=name, - latex_name=latex_name, - coordinate=coordinate, - names=names, start_index=start_index) + return super().__classcall__(cls, name=name, latex_name=latex_name, coordinate=coordinate, names=names, start_index=start_index) - def __init__(self, name=unicode_mathbbR, latex_name=r'\Bold{R}', - coordinate=None, names=None, start_index=0): + def __init__(self, name=unicode_mathbbR, latex_name=r'\Bold{R}', coordinate=None, names=None, start_index=0): r""" Construct the real line manifold. @@ -876,9 +856,7 @@ def __init__(self, name=unicode_mathbbR, latex_name=r'\Bold{R}', of precision sage: TestSuite(R).run(skip='_test_elements') # pickling of elements fails """ - OpenInterval.__init__(self, minus_infinity, infinity, name=name, - latex_name=latex_name, coordinate=coordinate, - names=names, start_index=start_index) + OpenInterval.__init__(self, minus_infinity, infinity, name=name, latex_name=latex_name, coordinate=coordinate, names=names, start_index=start_index) def _repr_(self): r""" diff --git a/src/sage/manifolds/differentiable/examples/sphere.py b/src/sage/manifolds/differentiable/examples/sphere.py index 284674a7bb9..48eec8ecafb 100644 --- a/src/sage/manifolds/differentiable/examples/sphere.py +++ b/src/sage/manifolds/differentiable/examples/sphere.py @@ -287,11 +287,9 @@ class Sphere(PseudoRiemannianSubmanifold): higher dimensions. Henceforth, high computation times are expected with increasing dimension. """ + @staticmethod - def __classcall_private__(cls, n=None, radius=1, ambient_space=None, - center=None, name=None, latex_name=None, - coordinates='spherical', names=None, - unique_tag=None): + def __classcall_private__(cls, n=None, radius=1, ambient_space=None, center=None, name=None, latex_name=None, coordinates='spherical', names=None, unique_tag=None): r""" Determine the correct class to return based upon the input. @@ -319,19 +317,13 @@ def __classcall_private__(cls, n=None, radius=1, ambient_space=None, from time import time from sage.misc.prandom import getrandbits + if unique_tag is None: unique_tag = getrandbits(128) * time() - return super().__classcall__(cls, n, radius=radius, - ambient_space=ambient_space, - center=center, - name=name, latex_name=latex_name, - coordinates=coordinates, names=names, - unique_tag=unique_tag) + return super().__classcall__(cls, n, radius=radius, ambient_space=ambient_space, center=center, name=name, latex_name=latex_name, coordinates=coordinates, names=names, unique_tag=unique_tag) - def __init__(self, n, radius=1, ambient_space=None, center=None, name=None, - latex_name=None, coordinates='spherical', names=None, - category=None, init_coord_methods=None, unique_tag=None): + def __init__(self, n, radius=1, ambient_space=None, center=None, name=None, latex_name=None, coordinates='spherical', names=None, category=None, init_coord_methods=None, unique_tag=None): r""" Construct sphere smoothly embedded in Euclidean space. @@ -349,14 +341,14 @@ def __init__(self, n, radius=1, ambient_space=None, center=None, name=None, raise ValueError('radius must be greater than zero') # ambient space if ambient_space is None: - ambient_space = EuclideanSpace(n+1) + ambient_space = EuclideanSpace(n + 1) elif not isinstance(ambient_space, EuclideanSpace): raise TypeError("the argument 'ambient_space' must be a Euclidean space") - elif ambient_space._dim != n+1: - raise ValueError("Euclidean space must have dimension {}".format(n+1)) + elif ambient_space._dim != n + 1: + raise ValueError("Euclidean space must have dimension {}".format(n + 1)) if center is None: cart = ambient_space.cartesian_coordinates() - c_coords = [0]*(n+1) + c_coords = [0] * (n + 1) center = ambient_space.point(c_coords, chart=cart) elif center not in ambient_space: raise ValueError('{} must be an element of {}'.format(center, ambient_space)) @@ -373,21 +365,15 @@ def __init__(self, n, radius=1, ambient_space=None, center=None, name=None, if center._latex_name: latex_name += r'({})'.format(center._latex_name) if category is None: - category = Manifolds(RR).Smooth() & MetricSpaces().Complete() & \ - TopologicalSpaces().Compact().Connected() + category = Manifolds(RR).Smooth() & MetricSpaces().Complete() & TopologicalSpaces().Compact().Connected() # initialize - PseudoRiemannianSubmanifold.__init__(self, n, name, - ambient=ambient_space, - signature=n, latex_name=latex_name, - metric_name='g', start_index=1, - category=category) + PseudoRiemannianSubmanifold.__init__(self, n, name, ambient=ambient_space, signature=n, latex_name=latex_name, metric_name='g', start_index=1, category=category) # set attributes self._radius = radius self._center = center self._coordinates = {} # established coordinates; values are lists - self._init_coordinates = {'spherical': self._init_spherical, - 'stereographic': self._init_stereographic} - # predefined coordinates + self._init_coordinates = {'spherical': self._init_spherical, 'stereographic': self._init_stereographic} + # predefined coordinates if init_coord_methods: self._init_coordinates.update(init_coord_methods) if coordinates not in self._init_coordinates: @@ -429,8 +415,7 @@ def _repr_(self): sage: S2_3 # indirect doctest 2-sphere S^2_3 of radius 3 smoothly embedded in the Euclidean space E^3 """ - s = "{}-sphere {} of radius {} smoothly embedded in " \ - "the {}".format(self._dim, self._name, self._radius, self._ambient) + s = "{}-sphere {} of radius {} smoothly embedded in " "the {}".format(self._dim, self._name, self._radius, self._ambient) if self._center._name: s += ' centered at the Point {}'.format(self._center._name) return s @@ -515,8 +500,7 @@ def _init_chart_domains(self): # intersection: int = self._stereoN_dom.intersection(self._stereoS_dom) int._name = self._name + '-{NP,SP}' - int._latex_name = self._latex_name + \ - r'\setminus\{\mathrm{NP}, \mathrm{SP}\}' + int._latex_name = self._latex_name + r'\setminus\{\mathrm{NP}, \mathrm{SP}\}' # without half circle: self._spher_dom = int.open_subset('A') # declare union: @@ -591,8 +575,7 @@ def _init_spherical(self, names=None): n = self._dim if names: # add interval: - names = tuple([x + ':(0,pi)' for x in names[:-1]] + - [names[-1] + ':(-pi,pi):periodic']) + names = tuple([x + ':(0,pi)' for x in names[:-1]] + [names[-1] + ':(-pi,pi):periodic']) else: if n == 1: names = ('phi:(-pi,pi):periodic',) @@ -601,8 +584,7 @@ def _init_spherical(self, names=None): elif n == 3: names = ('chi:(0,pi)', 'theta:(0,pi)', 'phi:(-pi,pi):periodic') else: - names = tuple(["phi_{}:(0,pi)".format(i) for i in range(1,n)] + - ["phi_{}:(-pi,pi):periodic".format(n)]) + names = tuple(["phi_{}:(0,pi)".format(i) for i in range(1, n)] + ["phi_{}:(-pi,pi):periodic".format(n)]) spher = A.chart(names=names) coord = spher[:] @@ -616,10 +598,10 @@ def _init_spherical(self, names=None): R = self._radius - coordfunc = [R*cos(coord[n-1])*prod(sin(coord[i]) for i in range(n-1))] - coordfunc += [R*prod(sin(coord[i]) for i in range(n))] - for k in reversed(range(n-1)): - c = R*cos(coord[k])*prod(sin(coord[i]) for i in range(k)) + coordfunc = [R * cos(coord[n - 1]) * prod(sin(coord[i]) for i in range(n - 1))] + coordfunc += [R * prod(sin(coord[i]) for i in range(n))] + for k in reversed(range(n - 1)): + c = R * cos(coord[k]) * prod(sin(coord[i]) for i in range(k)) coordfunc.append(c) cart = self._ambient.cartesian_coordinates() # shift coordinates to barycenter: @@ -935,24 +917,22 @@ def _init_stereographic(self, names, default_pole='north'): V.set_default_frame(stereoS.frame()) # predefine variables... - r2_N = sum(y ** 2 for y in coordN) - r2_S = sum(yp ** 2 for yp in coordS) + r2_N = sum(y**2 for y in coordN) + r2_S = sum(yp**2 for yp in coordS) R = self._radius R2 = R**2 # define transition map... - coordN_to_S = tuple(R*y/r2_N for y in coordN) - coordS_to_N = tuple(R*yp/r2_S for yp in coordS) - stereoN_to_S = stereoN.transition_map(stereoS, coordN_to_S, - restrictions1=r2_N != 0, - restrictions2=r2_S != 0) + coordN_to_S = tuple(R * y / r2_N for y in coordN) + coordS_to_N = tuple(R * yp / r2_S for yp in coordS) + stereoN_to_S = stereoN.transition_map(stereoS, coordN_to_S, restrictions1=r2_N != 0, restrictions2=r2_S != 0) stereoN_to_S.set_inverse(*coordS_to_N, check=False) # manage embedding... - coordfuncN = [2*y*R2 / (R2+r2_N) for y in coordN] - coordfuncN += [(R*r2_N-R*R2)/(R2+r2_N)] - coordfuncS = [2*yp*R2 / (R2+r2_S) for yp in coordS] - coordfuncS += [(R*R2-R*r2_S)/(R2+r2_S)] + coordfuncN = [2 * y * R2 / (R2 + r2_N) for y in coordN] + coordfuncN += [(R * r2_N - R * R2) / (R2 + r2_N)] + coordfuncS = [2 * yp * R2 / (R2 + r2_S) for yp in coordS] + coordfuncS += [(R * R2 - R * r2_S) / (R2 + r2_S)] cart = self._ambient.cartesian_coordinates() # shift coordinates to barycenter: coordfuncN = self._shift_coords(coordfuncN, s='+') @@ -1012,10 +992,8 @@ def _transition_spher_stereo(self): rstS += (coordS[0] > 0,) stereoN_A = stereoN.restrict(A, rstN) stereoS_A = stereoS.restrict(A, rstS) - self._coord_changes[(stereoN.restrict(W), - stereoS.restrict(W))].restrict(A) - self._coord_changes[(stereoS.restrict(W), - stereoN.restrict(W))].restrict(A) + self._coord_changes[(stereoN.restrict(W), stereoS.restrict(W))].restrict(A) + self._coord_changes[(stereoS.restrict(W), stereoN.restrict(W))].restrict(A) spher = self._coordinates['spherical'][0] R = self._radius @@ -1026,18 +1004,19 @@ def _transition_spher_stereo(self): cart = self._ambient.cartesian_coordinates() # get ambient coordinates and shift to coordinate origin: x = self._shift_coords(imm.expr(spher, cart), s='-') - coordfunc = [(R*x[i])/(R-x[-1]) for i in range(n)] + coordfunc = [(R * x[i]) / (R - x[-1]) for i in range(n)] # define transition map: spher_to_stereoN = spher.transition_map(stereoN_A, coordfunc) # transition: stereoN to spher... from sage.functions.trig import acos, atan2 from sage.misc.functional import sqrt + # get ambient coordinates and shift to coordinate origin: x = self._shift_coords(imm.expr(stereoN, cart), s='-') - coordfunc = [atan2(x[1],x[0])] - for k in range(2, n+1): - c = acos(x[k]/sqrt(sum(x[i]**2 for i in range(k+1)))) + coordfunc = [atan2(x[1], x[0])] + for k in range(2, n + 1): + c = acos(x[k] / sqrt(sum(x[i] ** 2 for i in range(k + 1)))) coordfunc.append(c) coordfunc = reversed(coordfunc) spher_to_stereoN.set_inverse(*coordfunc, check=False) @@ -1098,6 +1077,7 @@ def dist(self, p, q): pi*r """ from sage.functions.trig import acos + # get Euclidean points: x = self._immersion(p) y = self._immersion(q) @@ -1108,7 +1088,7 @@ def dist(self, p, q): n = self._dim + 1 r = self._radius - inv_angle = sum(x_coord[i]*y_coord[i] for i in range(n)) / r**2 + inv_angle = sum(x_coord[i] * y_coord[i] for i in range(n)) / r**2 return (r * acos(inv_angle)).simplify() def radius(self): @@ -1154,6 +1134,7 @@ def minimal_triangulation(self): 2 """ from sage.topology.simplicial_complex_examples import Sphere as SymplicialSphere + return SymplicialSphere(self._dim) def center(self): diff --git a/src/sage/manifolds/differentiable/examples/symplectic_space.py b/src/sage/manifolds/differentiable/examples/symplectic_space.py index 9893fcda207..a8a6c497c91 100644 --- a/src/sage/manifolds/differentiable/examples/symplectic_space.py +++ b/src/sage/manifolds/differentiable/examples/symplectic_space.py @@ -117,9 +117,7 @@ def __init__( """ # Check that manifold is even dimensional if dimension % 2 == 1: - raise ValueError( - f"the dimension of the manifold must be even but it is {dimension}" - ) + raise ValueError(f"the dimension of the manifold must be even but it is {dimension}") dim_half = dimension // 2 if names is not None and symbols is None: @@ -129,9 +127,7 @@ def __init__( if dim_half == 1: symbols = r"q:q p:p" else: - symbols_list = [ - f"q{i}:q^{i} p{i}:p_{i}" for i in range(1, dim_half + 1) - ] + symbols_list = [f"q{i}:q^{i} p{i}:p_{i}" for i in range(1, dim_half + 1)] symbols = " ".join(symbols_list) if name is None: @@ -152,9 +148,7 @@ def __init__( init_coord_methods=None, ) - self._symplectic_form = SymplecticFormParal( - self, symplectic_name, symplectic_latex_name - ) + self._symplectic_form = SymplecticFormParal(self, symplectic_name, symplectic_latex_name) for i in range(dim_half): q_index = 2 * i + 1 self._symplectic_form.set_comp()[q_index, q_index + 1] = -1 diff --git a/src/sage/manifolds/differentiable/integrated_curve.py b/src/sage/manifolds/differentiable/integrated_curve.py index 5f0aa3ba421..02353b2f0c1 100644 --- a/src/sage/manifolds/differentiable/integrated_curve.py +++ b/src/sage/manifolds/differentiable/integrated_curve.py @@ -363,10 +363,7 @@ class IntegratedCurve(DifferentiableCurve): sphinx_plot(graph) """ - def __init__(self, parent, equations_rhs, velocities, - curve_parameter, initial_tangent_vector, chart=None, - name=None, latex_name=None, verbose=False, - across_charts=False): + def __init__(self, parent, equations_rhs, velocities, curve_parameter, initial_tangent_vector, chart=None, name=None, latex_name=None, verbose=False, across_charts=False): r""" Construct a curve defined by a system of second order differential equations in the coordinate functions. @@ -427,8 +424,7 @@ def __init__(self, parent, equations_rhs, velocities, # start with parent class method to initialize the four last # arguments: - DifferentiableCurve.__init__(self, parent, name=name, - latex_name=latex_name) + DifferentiableCurve.__init__(self, parent, name=name, latex_name=latex_name) # check argument 'parent': 't_min' and 't_max' below are only # allowed to be either expressions of finite real values: @@ -436,8 +432,7 @@ def __init__(self, parent, equations_rhs, velocities, t_min = domain.lower_bound() t_max = domain.upper_bound() if t_min == -Infinity or t_max == +Infinity: - raise ValueError("both boundaries of the interval " + - "need to be finite") + raise ValueError("both boundaries of the interval " + "need to be finite") codomain = self.codomain() @@ -446,26 +441,22 @@ def __init__(self, parent, equations_rhs, velocities, if not isinstance(equations_rhs, dict): if len(equations_rhs) != dim: - raise ValueError("number of equations should equal " + - "codomain dimension") + raise ValueError("number of equations should equal " + "codomain dimension") else: for eq in equations_rhs.values(): if len(eq) != dim: - raise ValueError("number of equations should equal " + - "codomain dimension") + raise ValueError("number of equations should equal " + "codomain dimension") # check the chart: if chart is not None: if chart not in codomain.atlas(): - raise ValueError("{} should be a chart ".format(chart) + - "on the {}".format(codomain)) + raise ValueError("{} should be a chart ".format(chart) + "on the {}".format(codomain)) else: chart = codomain.default_chart() # check argument 'velocities': if len(velocities) != dim: - raise ValueError("number of velocities should equal " + - "codomain dimension") + raise ValueError("number of velocities should equal " + "codomain dimension") # in particular, check that no velocity coincides with a # coordinate: for vel in velocities: @@ -477,8 +468,7 @@ def __init__(self, parent, equations_rhs, velocities, # check argument 'curve_parameter': if not isinstance(curve_parameter, Expression): - raise TypeError("{} should be ".format(curve_parameter) + - "a symbolic expression") + raise TypeError("{} should be ".format(curve_parameter) + "a symbolic expression") # in particular, check that it does not coincide with a # coordinate or a velocity: coords_vels = list(chart[:]) + list(velocities) @@ -493,8 +483,7 @@ def __init__(self, parent, equations_rhs, velocities, # check argument 'initial_tangent_vector': if not isinstance(initial_tangent_vector, TangentVector): - raise TypeError("{} ".format(initial_tangent_vector) + - "should be a tangent vector") + raise TypeError("{} ".format(initial_tangent_vector) + "should be a tangent vector") initial_pt = initial_tangent_vector.parent().base_point() # line above retrieves the initial point as the base point of # the tangent space to which the initial tangent vector belongs @@ -527,7 +516,7 @@ def __init__(self, parent, equations_rhs, velocities, # extract all the variables appearing in the initial tangent # vector components: initial_coord_basis = chart.frame().at(initial_pt) - initial_tgt_vec_comps = initial_tangent_vector[initial_coord_basis,:] + initial_tgt_vec_comps = initial_tangent_vector[initial_coord_basis, :] for comp in initial_tgt_vec_comps: if isinstance(comp, Expression): parameters = parameters.union(comp.variables()) @@ -573,15 +562,13 @@ def __init__(self, parent, equations_rhs, velocities, def fast_CoF(pos, vel, M=M): # using default arguments for binding (ugly python) # print(det(*pos)) - return list(np.dot([[M[j, i](*pos) for i in range(dim)] - for j in range(dim)], vel)) + return list(np.dot([[M[j, i](*pos) for i in range(dim)] for j in range(dim)], vel)) self._fast_changes_of_frame[CoF] = fast_CoF for CoC in self._codomain._coord_changes: transf = self._codomain._coord_changes[CoC]._transf - fast_transf = [fast_callable(f.expr(), vars=list(CoC[0][:]), domain=float) - for f in transf] + fast_transf = [fast_callable(f.expr(), vars=list(CoC[0][:]), domain=float) for f in transf] self._fast_changes_of_chart[CoC] = fast_transf self._velocities = list(velocities) # converts to list @@ -590,13 +577,13 @@ def fast_CoF(pos, vel, M=M): self._initial_tangent_vector = initial_tangent_vector self._chart = chart self._parameters = parameters - self._ode_solver = None # if needed, becomes an instance of + self._ode_solver = None # if needed, becomes an instance of # 'ode_solver', which performs most of the numerical integrations # offered by method 'solve' - self._solutions = {} # dictionary containing all numerically + self._solutions = {} # dictionary containing all numerically # computed lists of points of the curve, the keys being chosen # by the user when calling method 'solve' - self._interpolations = {} # dictionary containing lists of + self._interpolations = {} # dictionary containing lists of # interpolation objects, each interpolation object implementing # the interpolation of one of the numerical coordinate curves, # and the keys being chosen by the user when calling @@ -605,12 +592,9 @@ def fast_CoF(pos, vel, M=M): if verbose: print("The curve was correctly set.") if self._parameters: - print("Parameters appearing in the differential " + - "system defining the curve are " + - "{}.".format(sorted(self._parameters, key=str))) + print("Parameters appearing in the differential " + "system defining the curve are " + "{}.".format(sorted(self._parameters, key=str))) else: - print("No parameter appears in the differential " + - "system defining the curve.") + print("No parameter appears in the differential " + "system defining the curve.") def _repr_(self): r""" @@ -681,10 +665,7 @@ def __reduce__(self): Integrated curve c in the 3-dimensional differentiable manifold M """ - return (type(self), (self.parent(), self._equations_rhs, - self._velocities, self._curve_parameter, - self._initial_tangent_vector, self._chart, - self._name, self._latex_name, False, self._across_charts)) + return (type(self), (self.parent(), self._equations_rhs, self._velocities, self._curve_parameter, self._initial_tangent_vector, self._chart, self._name, self._latex_name, False, self._across_charts)) def system(self, verbose=False): r""" @@ -747,7 +728,7 @@ def system(self, verbose=False): if verbose: initial_tgt_space = v0.parent() - initial_pt = initial_tgt_space.base_point() # retrieves + initial_pt = initial_tgt_space.base_point() # retrieves # the initial point as the base point of the tangent space # to which initial tangent vector belongs initial_pt_coords = list(initial_pt.coordinates(chart)) @@ -756,7 +737,7 @@ def system(self, verbose=False): # known initial_coord_basis = chart.frame().at(initial_pt) - initial_tgt_vec_comps = v0[initial_coord_basis,:] # will + initial_tgt_vec_comps = v0[initial_coord_basis, :] # will # raise error if components in coordinate basis are not # known @@ -780,15 +761,11 @@ def system(self, verbose=False): description += "{}".format(initial_tgt_vec_comps) description += " with respect to {}\n\n".format(chart) - for coord_func,velocity in zip(chart[:],self._velocities): - description += "d({})/d{} = {}\n".format(coord_func, - self._curve_parameter, - velocity) + for coord_func, velocity in zip(chart[:], self._velocities): + description += "d({})/d{} = {}\n".format(coord_func, self._curve_parameter, velocity) - for velocity,eqn in zip(self._velocities,self._equations_rhs): - description += "d({})/d{} = {}\n".format(velocity, - self._curve_parameter, - eqn) + for velocity, eqn in zip(self._velocities, self._equations_rhs): + description += "d({})/d{} = {}\n".format(velocity, self._curve_parameter, eqn) print(description) @@ -874,29 +851,29 @@ def solve_analytical(self, verbose=False): assume(param != 0) y = [] - for i in range(2*dim): - name = "y{}".format(i+i0) + for i in range(2 * dim): + name = "y{}".format(i + i0) y += [function(name)(par)] for i in range(dim): vel = self._velocities[i] - des[i] = des[i].substitute({vel: y[dim+i]}) - des[i] = diff(y[i],par) == des[i] + des[i] = des[i].substitute({vel: y[dim + i]}) + des[i] = diff(y[i], par) == des[i] for j in range(dim): - coord = self._chart[:][j] # important to use '[:]' on + coord = self._chart[:][j] # important to use '[:]' on # 'chart' to avoid problems due to nonzero starting # index (i0) veloc = self._velocities[j] - des[dim+i] = des[dim+i].substitute({coord: y[j]}) - des[dim+i] = des[dim+i].substitute({veloc: y[dim+j]}) - des[dim+i] = (diff(y[dim+i], par) == des[dim+i]) + des[dim + i] = des[dim + i].substitute({coord: y[j]}) + des[dim + i] = des[dim + i].substitute({veloc: y[dim + j]}) + des[dim + i] = diff(y[dim + i], par) == des[dim + i] dvars = y ics = [0] y_ics_first_half = [] y_ics_second_half = [] for i in range(dim): - coord = self._chart[:][i] # important to use '[:]' + coord = self._chart[:][i] # important to use '[:]' # on 'chart' to avoid problems due to nonzero # starting index (i0) veloc = self._velocities[i] @@ -919,16 +896,14 @@ def solve_analytical(self, verbose=False): for relation in sol[:dim]: expr = relation.rhs().simplify_full() coords_sol_expr += [expr] - self.add_expr(self.domain().default_chart(), self._chart, - coords_sol_expr) + self.add_expr(self.domain().default_chart(), self._chart, coords_sol_expr) for param in self._parameters: forget(param != 0) return tuple(coords_sol_expr) - def solve(self, step=None, method='odeint', solution_key=None, - parameters_values=None, verbose=False, **control_param): + def solve(self, step=None, method='odeint', solution_key=None, parameters_values=None, verbose=False, **control_param): r""" Integrate the curve numerically over the domain of definition. @@ -1055,15 +1030,12 @@ def solve(self, step=None, method='odeint', solution_key=None, from sage.symbolic.ring import SR if verbose: - print("Performing numerical integration with method '" + - method + "'...") + print("Performing numerical integration with method '" + method + "'...") if solution_key is None: solution_key = method if verbose: - print("Resulting list of points will be associated " + - "with the key '{}' ".format(solution_key) + - "by default.") + print("Resulting list of points will be associated " + "with the key '{}' ".format(solution_key) + "by default.") t_min = self.domain().lower_bound() t_max = self.domain().upper_bound() @@ -1089,7 +1061,7 @@ def solve(self, step=None, method='odeint', solution_key=None, chart = self._chart initial_tgt_space = v0.parent() - initial_pt = initial_tgt_space.base_point() # retrieves + initial_pt = initial_tgt_space.base_point() # retrieves # the initial point as the base point of the tangent space # to which the initial tangent vector belongs initial_pt_coords = list(initial_pt.coordinates(chart)) @@ -1098,16 +1070,13 @@ def solve(self, step=None, method='odeint', solution_key=None, # raise error if coordinates in chart cannot be obtained initial_coord_basis = chart.frame().at(initial_pt) - initial_tgt_vec_comps = list(v0[initial_coord_basis,:]) # idem + initial_tgt_vec_comps = list(v0[initial_coord_basis, :]) # idem dim = self.codomain().dim() if self._parameters: if parameters_values is None or len(parameters_values) != len(self._parameters): - raise ValueError("numerical values should be " + - "provided for each of the " + - "parameters " - "{}".format(sorted(self._parameters, key=str))) + raise ValueError("numerical values should be " + "provided for each of the " + "parameters " "{}".format(sorted(self._parameters, key=str))) for key in parameters_values: # Get numerical values in case some parameters values # contain expressions such as pi; will raise error if @@ -1117,17 +1086,15 @@ def solve(self, step=None, method='odeint', solution_key=None, if isinstance(t_min, Expression): t_min = parameters_values[t_min] if t_min == -Infinity or t_min == +Infinity: - raise ValueError("both boundaries of the " + - "interval need to be finite") + raise ValueError("both boundaries of the " + "interval need to be finite") if isinstance(t_max, Expression): t_max = parameters_values[t_max] if t_max == -Infinity or t_max == +Infinity: - raise ValueError("both boundaries of the " + - "interval need to be finite") + raise ValueError("both boundaries of the " + "interval need to be finite") for i in range(dim): - if isinstance(eqns_num[i], Expression): # some right + if isinstance(eqns_num[i], Expression): # some right # hand sides might merely be real numbers and not # expressions, so that they do not contain any variable, # and hence no substitution is required @@ -1161,10 +1128,8 @@ def solve(self, step=None, method='odeint', solution_key=None, step = numerical_approx(step) - initial_pt_coords = [numerical_approx(coord) for coord - in initial_pt_coords] - initial_tgt_vec_comps = [numerical_approx(comp) for comp - in initial_tgt_vec_comps] + initial_pt_coords = [numerical_approx(coord) for coord in initial_pt_coords] + initial_tgt_vec_comps = [numerical_approx(comp) for comp in initial_tgt_vec_comps] # the last two instructions retrieve numerical values even # if no parameters had to be substituted, in case some # coordinates or components contain expressions such as pi, @@ -1173,22 +1138,16 @@ def solve(self, step=None, method='odeint', solution_key=None, # RealNumber if not chart.valid_coordinates(*initial_pt_coords): - raise ValueError("initial point should be in the " + - "domain of the chart") + raise ValueError("initial point should be in the " + "domain of the chart") - ode_solver_methods = ["rk2", "rk4", "rkf45", "rkck", "rk8pd", - "rk2imp", "rk4imp", "gear1", "gear2", "bsimp"] + ode_solver_methods = ["rk2", "rk4", "rkf45", "rkck", "rk8pd", "rk2imp", "rk4imp", "gear1", "gear2", "bsimp"] if method == 'rk4_maxima': des = self._velocities + eqns_num dvars = list(chart[:]) + self._velocities ics = [t_min] + initial_pt_coords + initial_tgt_vec_comps - sol = desolve_system_rk4(des, dvars, - ivar=self._curve_parameter, - ics=ics, - end_points=[t_min, t_max], - step=step) + sol = desolve_system_rk4(des, dvars, ivar=self._curve_parameter, ics=ics, end_points=[t_min, t_max], step=step) # The value of 'step' being set by the user when calling # method 'solve', the value of (t_max - tmin)/step is not @@ -1216,74 +1175,69 @@ def solve(self, step=None, method='odeint', solution_key=None, elif method in ["odeint", "ode_int"]: # "ode_int" is here only for backward compatibility - des = [fast_callable(eq, vars=tuple(list(self._chart[:]) - + self._velocities - + [self._curve_parameter]), - domain=float) - for eq in (self._velocities + eqns_num)] + des = [fast_callable(eq, vars=tuple(list(self._chart[:]) + self._velocities + [self._curve_parameter]), domain=float) for eq in (self._velocities + eqns_num)] ics = initial_pt_coords + initial_tgt_vec_comps times = srange(t_min, t_max, step, include_endpoint=True) dvars = list(chart[:]) + self._velocities # Setting 1.e-10 as default value for the error control # parameters rtol and atol: if 'rtol' not in control_param: - control_param['rtol'] = 1.e-10 + control_param['rtol'] = 1.0e-10 if 'atol' not in control_param: - control_param['atol'] = 1.e-10 - sol0 = desolve_odeint(des, ics, times, dvars, - ivar=self._curve_parameter, **control_param) + control_param['atol'] = 1.0e-10 + sol0 = desolve_odeint(des, ics, times, dvars, ivar=self._curve_parameter, **control_param) # rewrite the solution to prepare for the extraction (which # removes information about the velocities), and convert # elements of type 'numpy.float64' to standard type 'float' import numpy as np - sol = np.column_stack((times, sol0)) # tolist() done later + + sol = np.column_stack((times, sol0)) # tolist() done later elif method in ["dopri5", "dop853"]: import numpy as np - des = [fast_callable(eq, vars=tuple(list(self._chart[:]) - + self._velocities), domain=float) - for eq in (self._velocities + eqns_num)] + + des = [fast_callable(eq, vars=tuple(list(self._chart[:]) + self._velocities), domain=float) for eq in (self._velocities + eqns_num)] ics = initial_pt_coords + initial_tgt_vec_comps - times = np.linspace(t_min, t_max, int((t_max-t_min)/step) + 1, - endpoint=True) + times = np.linspace(t_min, t_max, int((t_max - t_min) / step) + 1, endpoint=True) # ode accepts a function returning a list, and not a list of functions - r = ode(lambda t, y: [de(*y) for de in des]).set_integrator(method, - **control_param) + r = ode(lambda t, y: [de(*y) for de in des]).set_integrator(method, **control_param) r.set_initial_value(ics, t_min) - r.set_solout(lambda t, y: 0 if chart.valid_coordinates_numerical(*y[0:dim]) - else -1) + r.set_solout(lambda t, y: 0 if chart.valid_coordinates_numerical(*y[0:dim]) else -1) nt = len(times) - sol0 = np.zeros((nt, 2*dim)) - sol0[0,:] = np.array(ics) + sol0 = np.zeros((nt, 2 * dim)) + sol0[0, :] = np.array(ics) for i in range(1, nt): - sol0[i,:] = r.integrate(times[i]) + sol0[i, :] = r.integrate(times[i]) if not r.successful(): break - sol = np.column_stack((times, sol0)) # tolist() done later + sol = np.column_stack((times, sol0)) # tolist() done later elif method in ode_solver_methods: T = self._ode_solver if T is None: + def system(t, y): syst = self._velocities + eqns_num par = self._curve_parameter for i in range(dim): vel = self._velocities[i] - syst[i] = syst[i].substitute({vel:y[dim+i]}) - syst[dim+i] = syst[dim+i].substitute({par:t}) + syst[i] = syst[i].substitute({vel: y[dim + i]}) + syst[dim + i] = syst[dim + i].substitute({par: t}) for j in range(dim): - coord = chart[:][j] # important to use '[:]' + coord = chart[:][j] # important to use '[:]' # on 'chart' to avoid problems due to non # zero starting index (i0) veloc = self._velocities[j] - syst[dim+i] = syst[dim+i].substitute({coord:y[j]}) - syst[dim+i] = syst[dim+i].substitute({veloc:y[dim+j]}) + syst[dim + i] = syst[dim + i].substitute({coord: y[j]}) + syst[dim + i] = syst[dim + i].substitute({veloc: y[dim + j]}) return syst + from sage.calculus.ode import ode_solver + T = ode_solver(function=system, **control_param) T.algorithm = method @@ -1296,11 +1250,12 @@ def system(t, y): # of the system to be provided if T.jacobian is None: + def jacobian(t, y): jac = [] par = self._curve_parameter for i in range(dim): - new_row = [0] * (2*dim) + new_row = [0] * (2 * dim) new_row[dim + i] = 1 jac += [new_row] @@ -1308,7 +1263,7 @@ def jacobian(t, y): semi_row_coords = [] semi_row_vels = [] for j in range(dim): - coord = chart[:][j] # important to use + coord = chart[:][j] # important to use # '[:]' on 'chart' to avoid problems due # to nonzero starting index (i0) vel = self._velocities[j] @@ -1317,15 +1272,15 @@ def jacobian(t, y): AUX = AUX.substitute({par: t}) AUX2 = AUX2.substitute({par: t}) for k in range(dim): - coordin = chart[:][k] # important to + coordin = chart[:][k] # important to # use '[:]' on 'chart' to avoid # problems due to nonzero starting # index (i0) veloc = self._velocities[k] AUX = AUX.substitute({coordin: y[k]}) - AUX = AUX.substitute({veloc: y[dim+k]}) + AUX = AUX.substitute({veloc: y[dim + k]}) AUX2 = AUX2.substitute({coordin: y[k]}) - AUX2 = AUX2.substitute({veloc: y[dim+k]}) + AUX2 = AUX2.substitute({veloc: y[dim + k]}) semi_row_coords += [AUX] semi_row_vels += [AUX2] jac += [semi_row_coords + semi_row_vels] @@ -1336,17 +1291,18 @@ def jacobian(t, y): AUX3 = eqns_num[j].derivative(par) AUX3 = AUX3.substitute({par: t}) for m in range(dim): - coordin = chart[:][m] # important to use + coordin = chart[:][m] # important to use # '[:]' on 'chart' to avoid problems due # to nonzero starting index (i0) veloc = self._velocities[m] AUX3 = AUX3.substitute({coordin: y[m]}) - AUX3 = AUX3.substitute({veloc: y[dim+m]}) + AUX3 = AUX3.substitute({veloc: y[dim + m]}) last_semi_row_vels += [AUX3] jac += [last_semi_row_coords + last_semi_row_vels] # 'AUX', 'AUX2' and 'AUX3' only used for the lines # of source code to be shorter return jac + T.jacobian = jacobian T.ode_solve(y_0=y_0, t_span=t_span) @@ -1362,8 +1318,7 @@ def jacobian(t, y): # all methods else: - raise ValueError("no available method of integration " + - "referred to as '{}'".format(method)) + raise ValueError("no available method of integration " + "referred to as '{}'".format(method)) # eventually, extract the time and corresponding coordinate # values from each point of the solution computed (thus removing @@ -1373,44 +1328,27 @@ def jacobian(t, y): # tangent vectors.) if isinstance(sol, list): - coords_sol = [point[0:dim + 1] for point in sol] + coords_sol = [point[0 : dim + 1] for point in sol] else: - coords_sol = sol[:, 0:dim + 1].tolist() # far faster in numpy + coords_sol = sol[:, 0 : dim + 1].tolist() # far faster in numpy if verbose: - print("Numerical integration completed.\n\n" + - "Checking all points are in the chart domain...") + print("Numerical integration completed.\n\n" + "Checking all points are in the chart domain...") N = len(coords_sol) n = 0 - while n < N and chart.valid_coordinates_numerical(*coords_sol[n][1:dim+1]): + while n < N and chart.valid_coordinates_numerical(*coords_sol[n][1 : dim + 1]): n += 1 if n < N: - raise ValueError("the {}th point ".format(n) + - "(initial point being the '0th' point) " + - "of the numerical solution (obtained " + - "for a curve parameter equal " + - "to {}) is out ".format(sol[n][0]) + - "of the chart domain; a curve with a " + - "smaller maximal value of the curve " + - "parameter, or a smaller initial tangent " + - "vector, might be considered. You can also try " + - "'solve_across_charts' in order not to be " + - "confined to a single chart") + raise ValueError("the {}th point ".format(n) + "(initial point being the '0th' point) " + "of the numerical solution (obtained " + "for a curve parameter equal " + "to {}) is out ".format(sol[n][0]) + "of the chart domain; a curve with a " + "smaller maximal value of the curve " + "parameter, or a smaller initial tangent " + "vector, might be considered. You can also try " + "'solve_across_charts' in order not to be " + "confined to a single chart") else: self._solutions[solution_key] = coords_sol if verbose: - print("All points are in the chart domain.\n\n" + - "The resulting list of points was associated " + - "with the key '{}' ".format(solution_key) + - "(if this key already referred to a former " + - "numerical solution, such a solution was erased).") + print("All points are in the chart domain.\n\n" + "The resulting list of points was associated " + "with the key '{}' ".format(solution_key) + "(if this key already referred to a former " + "numerical solution, such a solution was erased).") return self._solutions[solution_key] - def solve_across_charts(self, charts=None, step=None, solution_key=None, - parameters_values=None, verbose=False, - **control_param): + def solve_across_charts(self, charts=None, step=None, solution_key=None, parameters_values=None, verbose=False, **control_param): r""" Integrate the curve numerically over the domain of integration, with the ability to switch chart mid-integration. @@ -1600,16 +1538,13 @@ def solve_across_charts(self, charts=None, step=None, solution_key=None, else: for c in charts: if not isinstance(c, Chart) or c.domain() is not self._codomain: - raise ValueError("'charts' needs to be a list of " - "charts of the manifold") + raise ValueError("'charts' needs to be a list of " "charts of the manifold") print("Integration will take place on {} charts.".format(len(charts))) if solution_key is None: solution_key = "ode_multichart" if verbose: - print("Resulting list of points will be associated " + - "with the key '{}' ".format(solution_key) + - "by default.") + print("Resulting list of points will be associated " + "with the key '{}' ".format(solution_key) + "by default.") print(" ...") t_min = self.domain().lower_bound() @@ -1640,24 +1575,19 @@ def solve_across_charts(self, charts=None, step=None, solution_key=None, if self._parameters: if parameters_values is None or len(parameters_values) != len(self._parameters): - raise ValueError("numerical values should be " + - "provided for each of the " + - "parameters " - "{}".format(sorted(self._parameters, key=str))) + raise ValueError("numerical values should be " + "provided for each of the " + "parameters " "{}".format(sorted(self._parameters, key=str))) for key in parameters_values: parameters_values[key] = numerical_approx(parameters_values[key]) if isinstance(t_min, Expression): t_min = parameters_values[t_min] if t_min == -Infinity or t_min == +Infinity: - raise ValueError("both boundaries of the " + - "interval need to be finite") + raise ValueError("both boundaries of the " + "interval need to be finite") if isinstance(t_max, Expression): t_max = parameters_values[t_max] if t_max == -Infinity or t_max == +Infinity: - raise ValueError("both boundaries of the " + - "interval need to be finite") + raise ValueError("both boundaries of the " + "interval need to be finite") for i in range(dim): for chart in eqns_num: @@ -1676,10 +1606,8 @@ def solve_across_charts(self, charts=None, step=None, solution_key=None, step = numerical_approx(step) - initial_pt_coords = [numerical_approx(coord) for coord - in initial_pt_coords] - initial_tgt_vec_comps = [numerical_approx(comp) for comp - in initial_tgt_vec_comps] + initial_pt_coords = [numerical_approx(coord) for coord in initial_pt_coords] + initial_tgt_vec_comps = [numerical_approx(comp) for comp in initial_tgt_vec_comps] t_min = numerical_approx(t_min) t_max = numerical_approx(t_max) @@ -1690,18 +1618,13 @@ def solve_across_charts(self, charts=None, step=None, solution_key=None, else: # No initial chart found - raise ValueError("initial point should be in the " + - "domain of its chart") + raise ValueError("initial point should be in the " + "domain of its chart") # Transformation to fast_callable happens here - des = {chart: [fast_callable(SR(eq), vars=tuple( - list(chart[:]) + chart.symbolic_velocities()), domain=float) - for eq in (chart.symbolic_velocities() + eqns_num[chart])] - for chart in charts} + des = {chart: [fast_callable(SR(eq), vars=tuple(list(chart[:]) + chart.symbolic_velocities()), domain=float) for eq in (chart.symbolic_velocities() + eqns_num[chart])] for chart in charts} ics = initial_pt_coords + initial_tgt_vec_comps - times = np.linspace(t_min, t_max, int((t_max - t_min) / step) + 1, - endpoint=True) + times = np.linspace(t_min, t_max, int((t_max - t_min) / step) + 1, endpoint=True) nt = len(times) sol = [] @@ -1713,8 +1636,7 @@ def solve_across_charts(self, charts=None, step=None, solution_key=None, sol_chart[0, :] = np.array(ics) # starting with initial condition # Current equation to integrate, with initial and stop conditions - r = ode(lambda t, y: [de(*y) for de in des[chart]]).set_integrator('dopri5', - **control_param) + r = ode(lambda t, y: [de(*y) for de in des[chart]]).set_integrator('dopri5', **control_param) r.set_initial_value(ics, t_min) r.set_solout(lambda t, y: 0 if chart.valid_coordinates_numerical(*y[0:dim]) else -1) @@ -1729,13 +1651,13 @@ def solve_across_charts(self, charts=None, step=None, solution_key=None, raise RuntimeError("unsuccessful integration") # step leads outside of the chart domain - if abs(r.t-times[i]) > 1e-8: + if abs(r.t - times[i]) > 1e-8: if verbose: print("Exiting chart, trying to switch to another chart.") # Last known point - last_pts = sol_chart[i-2-start_index, :dim] - last_vel = sol_chart[i-2-start_index, dim:] + last_pts = sol_chart[i - 2 - start_index, :dim] + last_vel = sol_chart[i - 2 - start_index, dim:] random_order = list(set(charts).difference(tried_charts)) shuffle(random_order) @@ -1746,9 +1668,7 @@ def solve_across_charts(self, charts=None, step=None, solution_key=None, inter = chart.domain().intersection(new_chart.domain()) # The change of chart is performed here - new_pts = [f(*last_pts) for f in - self._fast_changes_of_chart[(chart.restrict(inter), - new_chart.restrict(inter))]] + new_pts = [f(*last_pts) for f in self._fast_changes_of_chart[(chart.restrict(inter), new_chart.restrict(inter))]] # If this line throws an error, check your changes # of chart @@ -1757,8 +1677,7 @@ def solve_across_charts(self, charts=None, step=None, solution_key=None, print("New chart found. Resuming integration.") if start_index != i - 1: # len(1) solution are ditched # col-stack the times - sol_stacked = np.column_stack((times[start_index:i-1], - sol_chart[:i-start_index-1, :])) + sol_stacked = np.column_stack((times[start_index : i - 1], sol_chart[: i - start_index - 1, :])) # add it to the global solution sol.append((chart, sol_stacked)) @@ -1767,8 +1686,7 @@ def solve_across_charts(self, charts=None, step=None, solution_key=None, # change of frame manually (with a precompiled # function) - new_vel = self._fast_changes_of_frame[(new_chart.frame().restrict(inter), - chart.frame().restrict(inter))](last_pts, last_vel) + new_vel = self._fast_changes_of_frame[(new_chart.frame().restrict(inter), chart.frame().restrict(inter))](last_pts, last_vel) ics = new_pts + new_vel chart = new_chart @@ -1777,11 +1695,9 @@ def solve_across_charts(self, charts=None, step=None, solution_key=None, sol_chart = np.zeros((nt, 2 * dim)) sol_chart[0, :] = np.array(ics) - r = ode(lambda t, y: [de(*y) for de in des[chart]])\ - .set_integrator('dopri5') + r = ode(lambda t, y: [de(*y) for de in des[chart]]).set_integrator('dopri5') r.set_initial_value(ics, times[i - 1]) - r.set_solout(lambda t, y: 0 if chart. - valid_coordinates_numerical(*y[0:dim]) else -1) + r.set_solout(lambda t, y: 0 if chart.valid_coordinates_numerical(*y[0:dim]) else -1) i -= 1 # go back in the past to redo failed step break # every chart was tried @@ -1789,31 +1705,29 @@ def solve_across_charts(self, charts=None, step=None, solution_key=None, if verbose: print("No chart found, stopping integration.") # col-stack the times - sol_chart = np.column_stack((times[start_index:i-1], - sol_chart[:i-start_index-1, :])) + sol_chart = np.column_stack((times[start_index : i - 1], sol_chart[: i - start_index - 1, :])) # add it to the global solution sol.append((chart, sol_chart)) break # the integration step was successful else: - sol_chart[i-start_index, :] = current_sol # register the result + sol_chart[i - start_index, :] = current_sol # register the result tried_charts.clear() # the set is reset. i += 1 - else: # integration finishes successfully + else: # integration finishes successfully if verbose: print("Integration successful.") # col-stack the times - sol_chart = np.column_stack((times[start_index:i-1], - sol_chart[:i-start_index-1, :])) + sol_chart = np.column_stack((times[start_index : i - 1], sol_chart[: i - start_index - 1, :])) # add it to the global solution sol.append((chart, sol_chart)) coords_sol = [] for chart, chart_sol in sol: - coords_sol.append((chart, chart_sol[:, 0:dim + 1])) # remove velocities + coords_sol.append((chart, chart_sol[:, 0 : dim + 1])) # remove velocities self._solutions[solution_key] = coords_sol @@ -1871,18 +1785,13 @@ def solution(self, solution_key=None, verbose=False): solution_key = next(iter(self._solutions)) # will raise an error if self._solutions is empty if verbose: - print("Returning the numerical solution associated " + - "with the key '{}' ".format(solution_key) + - "by default...") + print("Returning the numerical solution associated " + "with the key '{}' ".format(solution_key) + "by default...") elif solution_key not in self._solutions: - raise ValueError("no existing key " + - "'{}' ".format(solution_key) + - "referring to any numerical solution") + raise ValueError("no existing key " + "'{}' ".format(solution_key) + "referring to any numerical solution") return self._solutions[solution_key] - def interpolate(self, solution_key=None, method=None, - interpolation_key=None, verbose=False): + def interpolate(self, solution_key=None, method=None, interpolation_key=None, verbose=False): r""" Interpolate the chosen numerical solution using the given interpolation method. @@ -1961,31 +1870,23 @@ def interpolate(self, solution_key=None, method=None, if 'odeint' in self._solutions: solution_key = 'odeint' else: - solution_key = next(iter(self._solutions)) # will raise + solution_key = next(iter(self._solutions)) # will raise # error if self._solutions empty if verbose: - print("Interpolating the numerical solution " + - "associated with the key " + - "'{}' ".format(solution_key) + - "by default...") + print("Interpolating the numerical solution " + "associated with the key " + "'{}' ".format(solution_key) + "by default...") elif solution_key not in self._solutions: - raise ValueError("no existing key " + - "'{}' ".format(solution_key) + - "referring to any numerical solution") + raise ValueError("no existing key " + "'{}' ".format(solution_key) + "referring to any numerical solution") if method is None: method = 'cubic spline' if verbose: - print("Performing cubic spline interpolation by " - "default...") + print("Performing cubic spline interpolation by " "default...") if interpolation_key is None: interpolation_key = "{}-interp-".format(method) interpolation_key += "{}".format(solution_key) if verbose: - print("Resulting interpolation will be associated " + - "with the key '{}' ".format(interpolation_key) + - "by default.") + print("Resulting interpolation will be associated " + "with the key '{}' ".format(interpolation_key) + "by default.") if method == 'cubic spline': self._interpolations[interpolation_key] = [] @@ -1994,9 +1895,9 @@ def interpolate(self, solution_key=None, method=None, for i in range(dim): coordinate_curve = [] for point in self._solutions[solution_key]: - coordinate_curve += [[point[0], point[i+1]]] + coordinate_curve += [[point[0], point[i + 1]]] self._interpolations[interpolation_key] += [Spline(coordinate_curve)] - else: # case multi charts + else: # case multi charts j = 0 for chart, sol in self._solutions[solution_key]: interp_chart = [] @@ -2006,17 +1907,13 @@ def interpolate(self, solution_key=None, method=None, coordinate_curve += [[point[0], point[i + 1]]] interp_chart += [Spline(coordinate_curve)] self._interpolations[interpolation_key] += [(chart, interp_chart)] - self._interpolations[interpolation_key+"_chart_"+str(j)] = interp_chart + self._interpolations[interpolation_key + "_chart_" + str(j)] = interp_chart j += 1 else: - raise ValueError("no available method of interpolation " + - "referred to as '{}'".format(method)) + raise ValueError("no available method of interpolation " + "referred to as '{}'".format(method)) if verbose: - print("Interpolation completed and associated with the " + - "key '{}' ".format(interpolation_key) + - "(if this key already referred to a former " + - "interpolation, such an interpolation was erased).") + print("Interpolation completed and associated with the " + "key '{}' ".format(interpolation_key) + "(if this key already referred to a former " + "interpolation, such an interpolation was erased).") return self._interpolations[interpolation_key] @@ -2081,18 +1978,13 @@ def interpolation(self, interpolation_key=None, verbose=False): interpolation_key = next(iter(self._interpolations)) # will # raise error if self._interpolations empty if verbose: - print("Returning the interpolation associated with " + - "the key '{}' ".format(interpolation_key) + - "by default...") + print("Returning the interpolation associated with " + "the key '{}' ".format(interpolation_key) + "by default...") elif interpolation_key not in self._interpolations: - raise ValueError("no existing key " + - "'{}' ".format(interpolation_key) + - "referring to any interpolation") + raise ValueError("no existing key " + "'{}' ".format(interpolation_key) + "referring to any interpolation") return self._interpolations[interpolation_key] - def __call__(self, t, interpolation_key=None, - verbose=False): + def __call__(self, t, interpolation_key=None, verbose=False): r""" Return the image of the curve for the given value of the curve parameter, using the chosen interpolation. @@ -2150,13 +2042,9 @@ def __call__(self, t, interpolation_key=None, # will raise error if self._interpolations empty interpolation_key = next(iter(self._interpolations)) if verbose: - print("Evaluating point coordinates from the " + - "interpolation associated with the key " + - "'{}' by default...".format(interpolation_key)) + print("Evaluating point coordinates from the " + "interpolation associated with the key " + "'{}' by default...".format(interpolation_key)) elif interpolation_key not in self._interpolations: - raise ValueError("no existing key " + - "'{}' ".format(interpolation_key) + - "referring to any interpolation") + raise ValueError("no existing key " + "'{}' ".format(interpolation_key) + "referring to any interpolation") interpolation = self._interpolations[interpolation_key] @@ -2165,13 +2053,10 @@ def __call__(self, t, interpolation_key=None, # contain lists of instances of the Spline class raise TypeError("unexpected type of interpolation object") - interpolated_coordinates = [coord_curve_spline(t) - for coord_curve_spline in interpolation] - return self.codomain().point(coords=interpolated_coordinates, - chart=self._chart) + interpolated_coordinates = [coord_curve_spline(t) for coord_curve_spline in interpolation] + return self.codomain().point(coords=interpolated_coordinates, chart=self._chart) - def tangent_vector_eval_at(self, t, - interpolation_key=None, verbose=False): + def tangent_vector_eval_at(self, t, interpolation_key=None, verbose=False): r""" Return the vector tangent to ``self`` at the given curve parameter with components evaluated from the given @@ -2243,13 +2128,9 @@ def tangent_vector_eval_at(self, t, # will raise error if self._interpolations empty interpolation_key = next(iter(self._interpolations)) if verbose: - print("Evaluating tangent vector components from the " + - "interpolation associated with the key " + - "'{}' by default...".format(interpolation_key)) + print("Evaluating tangent vector components from the " + "interpolation associated with the key " + "'{}' by default...".format(interpolation_key)) elif interpolation_key not in self._interpolations: - raise ValueError("no existing key " + - "'{}' ".format(interpolation_key) + - "referring to any interpolation") + raise ValueError("no existing key " + "'{}' ".format(interpolation_key) + "referring to any interpolation") interpolation = self._interpolations[interpolation_key] @@ -2258,26 +2139,18 @@ def tangent_vector_eval_at(self, t, # contain lists of instances of the Spline class raise TypeError("unexpected type of interpolation object") - interpolated_coordinates = [coordinate_curve_spline(t) - for coordinate_curve_spline in interpolation] + interpolated_coordinates = [coordinate_curve_spline(t) for coordinate_curve_spline in interpolation] M = self.codomain() p = M.point(interpolated_coordinates, chart=self._chart, name=None) Tp = M.tangent_space(p) # by default, order=1 in method 'derivative' of a class Spline - evaluated_tgt_vec_comp = [coord_curve_spline.derivative(t) - for coord_curve_spline in interpolation] + evaluated_tgt_vec_comp = [coord_curve_spline.derivative(t) for coord_curve_spline in interpolation] basis = self._chart.frame().at(p) return Tp(evaluated_tgt_vec_comp, basis=basis) - @options(thickness=1, plot_points=75, aspect_ratio='automatic', - plot_points_tangent=10, width_tangent=1, scale=1) - def plot_integrated(self, chart=None, ambient_coords=None, - mapping=None, prange=None, interpolation_key=None, - include_end_point=(True, True), - end_point_offset=(0.001, 0.001), verbose=False, color='red', - style='-', label_axes=True, display_tangent=False, - color_tangent='blue', across_charts=False, **kwds): + @options(thickness=1, plot_points=75, aspect_ratio='automatic', plot_points_tangent=10, width_tangent=1, scale=1) + def plot_integrated(self, chart=None, ambient_coords=None, mapping=None, prange=None, interpolation_key=None, include_end_point=(True, True), end_point_offset=(0.001, 0.001), verbose=False, color='red', style='-', label_axes=True, display_tangent=False, color_tangent='blue', across_charts=False, **kwds): r""" Plot the 2D or 3D projection of ``self`` onto the space of the chosen two or three ambient coordinates, based on the @@ -2379,19 +2252,15 @@ def plot_integrated(self, chart=None, ambient_coords=None, interpolation_key = key break else: - raise ValueError("Did you forget to " - "integrate or interpolate the result?") + raise ValueError("Did you forget to " "integrate or interpolate the result?") else: interpolation_key = next(iter(self._interpolations)) # will raise error if self._interpolations empty if verbose: - print("Plotting from the interpolation associated " + - "with the key '{}' ".format(interpolation_key) + - "by default...") + print("Plotting from the interpolation associated " + "with the key '{}' ".format(interpolation_key) + "by default...") elif interpolation_key not in self._interpolations: - raise ValueError("no existing key '{}' ".format(interpolation_key) - + "referring to any interpolation") + raise ValueError("no existing key '{}' ".format(interpolation_key) + "referring to any interpolation") interpolation = self._interpolations[interpolation_key] @@ -2403,19 +2272,9 @@ def plot_integrated(self, chart=None, ambient_coords=None, color = color * len(interpolation) res = 0 for i in range(len(interpolation)): - nb_pts = int(float(plot_points)*len(interpolation[i][1][0])/len_tot) + nb_pts = int(float(plot_points) * len(interpolation[i][1][0]) / len_tot) self._chart = interpolation[i][0] - res += self.plot_integrated(chart=chart, ambient_coords=ambient_coords, - mapping=mapping, prange=prange, - interpolation_key=interpolation_key+"_chart_"+str(i), - include_end_point=include_end_point, - end_point_offset=end_point_offset, - verbose=verbose, color=color[i], - style=style, label_axes=False, - display_tangent=display_tangent, - color_tangent=color_tangent, - across_charts=False, - plot_points=nb_pts, **kwds) + res += self.plot_integrated(chart=chart, ambient_coords=ambient_coords, mapping=mapping, prange=prange, interpolation_key=interpolation_key + "_chart_" + str(i), include_end_point=include_end_point, end_point_offset=end_point_offset, verbose=verbose, color=color[i], style=style, label_axes=False, display_tangent=display_tangent, color_tangent=color_tangent, across_charts=False, plot_points=nb_pts, **kwds) return res @@ -2452,9 +2311,7 @@ def plot_integrated(self, chart=None, ambient_coords=None, ambient_coords = chart[:] # all chart coordinates are used n_pc = len(ambient_coords) if n_pc != 2 and n_pc != 3: - raise ValueError("the number of coordinates involved in " + - "the plot must be either 2 or 3, " + - "not {}".format(n_pc)) + raise ValueError("the number of coordinates involved in " + "the plot must be either 2 or 3, " + "not {}".format(n_pc)) # From now on, 'pc' will denote coordinates in terms of which # the curve is plotted (i.e. the "ambient coordinates"), while @@ -2481,17 +2338,13 @@ def plot_integrated(self, chart=None, ambient_coords=None, if prange is None: prange = (param_min, param_max) elif not isinstance(prange, (tuple, list)): - raise TypeError("{} is neither ".format(prange) + - "a tuple nor a list") + raise TypeError("{} is neither ".format(prange) + "a tuple nor a list") elif len(prange) != 2: - raise ValueError("the argument prange must be a " + - "tuple/list of 2 elements") + raise ValueError("the argument prange must be a " + "tuple/list of 2 elements") else: p = prange # 'p' declared only for the line below to be shorter if p[0] < param_min or p[0] > param_max or p[1] < param_min or p[1] > param_max: - raise ValueError("parameter range should be a " + - "subinterval of the curve domain " + - "({})".format(self.domain())) + raise ValueError("parameter range should be a " + "subinterval of the curve domain " + "({})".format(self.domain())) tmin = numerical_approx(prange[0]) tmax = numerical_approx(prange[1]) @@ -2526,15 +2379,11 @@ def plot_integrated(self, chart=None, ambient_coords=None, # self.domain.lower_bound(). Hence the line below # that adds 1% of the step to compute even more # safely the first point - t = param_min + 0.01*dt + t = param_min + 0.01 * dt if verbose: - print("A tiny initial offset equal to " + - "{} ".format(0.01*dt) + - "was introduced for the first point " + - "only, in order to safely compute " + - "it from the interpolation.") + print("A tiny initial offset equal to " + "{} ".format(0.01 * dt) + "was introduced for the first point " + "only, in order to safely compute " + "it from the interpolation.") - if k == plot_points-1 and t > param_max: + if k == plot_points - 1 and t > param_max: # This might happen for the last point # (i.e. k = plot_points-1) when prange[1], and hence # tmax, should equal param_max; but mere numerical @@ -2544,15 +2393,11 @@ def plot_integrated(self, chart=None, ambient_coords=None, # greater than self.domain.upper_bound(). # Hence the line below that subtract 1% of the # step to compute even more safely the last point - t = param_max - 0.01*dt + t = param_max - 0.01 * dt if verbose: - print("A tiny final offset equal to " + - "{} ".format(0.01*dt) + - "was introduced for the last point " + - "in order to safely compute " + - "it from the interpolation.") + print("A tiny final offset equal to " + "{} ".format(0.01 * dt) + "was introduced for the last point " + "in order to safely compute " + "it from the interpolation.") - plot_curve.append([interpolation[j-i0](t) for j in ind_pc]) + plot_curve.append([interpolation[j - i0](t) for j in ind_pc]) if k == 0 and t > tmin: # in case an initial offset was earlier added to @@ -2586,13 +2431,9 @@ def plot_integrated(self, chart=None, ambient_coords=None, # self.domain.lower_bound(). # Hence the line below that add 1% of the step # to compute even more safely the first point. - t = param_min + 0.01*dt + t = param_min + 0.01 * dt if verbose: - print("A tiny initial offset equal to " + - "{} ".format(0.01*dt) + - "was introduced for the first point " + - "only, in order to safely compute " + - "it from the interpolation.") + print("A tiny initial offset equal to " + "{} ".format(0.01 * dt) + "was introduced for the first point " + "only, in order to safely compute " + "it from the interpolation.") if k == plot_points_tangent - 1 and t > param_max: # This might happen for the last point @@ -2605,37 +2446,25 @@ def plot_integrated(self, chart=None, ambient_coords=None, # self.domain.upper_bound(). Hence the line below # that subtracts 1% of the step to compute even # more safely the last point. - t = param_max - 0.01*dt + t = param_max - 0.01 * dt if verbose: - print("A tiny final offset equal to " + - "{} ".format(0.01*dt) + - "was introduced for the last point " + - "in order to safely compute " + - "it from the interpolation.") + print("A tiny final offset equal to " + "{} ".format(0.01 * dt) + "was introduced for the last point " + "in order to safely compute " + "it from the interpolation.") # interpolated ambient coordinates: - xp = [interpolation[j-i0](t) for j in ind_pc] + xp = [interpolation[j - i0](t) for j in ind_pc] # tangent vector ambiant components evaluated # from the interpolation: - vec = [coordinate_curve_spline.derivative(t) - for coordinate_curve_spline in interpolation] + vec = [coordinate_curve_spline.derivative(t) for coordinate_curve_spline in interpolation] coord_tail = xp - coord_head = [xp[j] + scale*vec[j] - for j in range(len(xp))] + coord_head = [xp[j] + scale * vec[j] for j in range(len(xp))] if coord_head != coord_tail: if n_pc == 2: - plot_vectors += arrow2d(tailpoint=coord_tail, - headpoint=coord_head, - color=color_tangent, - width=width_tangent) + plot_vectors += arrow2d(tailpoint=coord_tail, headpoint=coord_head, color=color_tangent, width=width_tangent) else: - plot_vectors += arrow3d(coord_tail, - coord_head, - color=color_tangent, - width=width_tangent) + plot_vectors += arrow3d(coord_tail, coord_head, color=color_tangent, width=width_tangent) if k == 0 and t > tmin: # in case an initial offset was earlier added @@ -2644,18 +2473,9 @@ def plot_integrated(self, chart=None, ambient_coords=None, t = tmin t += dt - return plot_vectors + DifferentiableCurve._graphics(self, - plot_curve, ambient_coords, - thickness=thickness, - aspect_ratio=aspect_ratio, - color=color, - style=style, - label_axes=label_axes) - - return DifferentiableCurve._graphics(self, plot_curve, - ambient_coords, thickness=thickness, - aspect_ratio=aspect_ratio, color=color, - style=style, label_axes=label_axes) + return plot_vectors + DifferentiableCurve._graphics(self, plot_curve, ambient_coords, thickness=thickness, aspect_ratio=aspect_ratio, color=color, style=style, label_axes=label_axes) + + return DifferentiableCurve._graphics(self, plot_curve, ambient_coords, thickness=thickness, aspect_ratio=aspect_ratio, color=color, style=style, label_axes=label_axes) # # The coordinate expressions of the mapping and the # coordinates involved @@ -2672,17 +2492,15 @@ def plot_integrated(self, chart=None, ambient_coords=None, # 'AUX' used only for the lines of source code # to be shorter transf[pc] = AUX.expr()[jpc] - AUX2 = transf[pc].variables() # idem + AUX2 = transf[pc].variables() # idem required_coords = required_coords.union(AUX2) break else: - raise ValueError("no expression has been found for " + - "{} in terms of {}".format(self,chart)) + raise ValueError("no expression has been found for " + "{} in terms of {}".format(self, chart)) # fastf is the fast version of a substitution + numerical evaluation # using fast_callable. - fastf = [fast_callable(transf[chart[i]], vars=tuple(self._chart[:])) - for i in ind_pc] + fastf = [fast_callable(transf[chart[i]], vars=tuple(self._chart[:])) for i in ind_pc] if not isinstance(interpolation[0], Spline): # partial test, in case future interpolation objects do not @@ -2707,13 +2525,9 @@ def plot_integrated(self, chart=None, ambient_coords=None, # interpolation at a time smaller than # self.domain.lower_bound(). Hence the line below that adds # 1% of the step to compute even more safely the first point - t = param_min + 0.01*dt + t = param_min + 0.01 * dt if verbose: - print("A tiny initial offset equal to " + - "{} ".format(0.01*dt) + - "was introduced for the first point " + - "only, in order to safely compute " + - "it from the interpolation.") + print("A tiny initial offset equal to " + "{} ".format(0.01 * dt) + "was introduced for the first point " + "only, in order to safely compute " + "it from the interpolation.") if k == plot_points - 1 and t > param_max: # This might happen for the last point (i.e. k = plot_points-1) @@ -2725,13 +2539,9 @@ def plot_integrated(self, chart=None, ambient_coords=None, # self.domain.upper_bound(). Hence the line below that # subtracts 1% of the step to compute even more safely # the last point. - t = param_max - 0.01*dt + t = param_max - 0.01 * dt if verbose: - print("A tiny final offset equal to " + - "{} ".format(0.01*dt) + - "was introduced for the last point " + - "in order to safely compute " + - "it from the interpolation.") + print("A tiny final offset equal to " + "{} ".format(0.01 * dt) + "was introduced for the last point " + "in order to safely compute " + "it from the interpolation.") # list of coordinates, argument of fastf, the fast diff_map arg = [inter(t) for inter in interpolation] @@ -2778,13 +2588,9 @@ def plot_integrated(self, chart=None, ambient_coords=None, # self.domain.lower_bound(). Hence the line below # that adds 1% of the step to compute even more # safely the first point - t = param_min + 0.01*dt + t = param_min + 0.01 * dt if verbose: - print("A tiny initial offset equal to " + - "{} ".format(0.01*dt) + - "was introduced for the first point " + - "only, in order to safely compute " + - "it from the interpolation.") + print("A tiny initial offset equal to " + "{} ".format(0.01 * dt) + "was introduced for the first point " + "only, in order to safely compute " + "it from the interpolation.") if k == plot_points_tangent - 1 and t > param_max: # This might happen for the last point @@ -2797,17 +2603,13 @@ def plot_integrated(self, chart=None, ambient_coords=None, # self.domain.upper_bound(). Hence the line below # that subtracts 1% of the step to compute even # more safely the last point - t = param_max - 0.01*dt + t = param_max - 0.01 * dt if verbose: - print("A tiny final offset equal to " + - "{} ".format(0.01*dt) + - "was introduced for the last point " + - "in order to safely compute " + - "it from the interpolation.") + print("A tiny final offset equal to " + "{} ".format(0.01 * dt) + "was introduced for the last point " + "in order to safely compute " + "it from the interpolation.") for coord in required_coords: i = self._chart[:].index(coord) - AUX = interpolation[i] # 'AUX' only used + AUX = interpolation[i] # 'AUX' only used # for the lines below to be shorter required_coords_values[coord] = AUX(t) Dcoord_Dt[coord] = AUX.derivative(t) @@ -2832,20 +2634,13 @@ def plot_integrated(self, chart=None, ambient_coords=None, pushed_vec += [pushed_comp] coord_tail = xp - coord_head = [val + scale*pushed_vec[j] - for j, val in enumerate(xp)] + coord_head = [val + scale * pushed_vec[j] for j, val in enumerate(xp)] if coord_head != coord_tail: if n_pc == 2: - plot_vectors += arrow2d(tailpoint=coord_tail, - headpoint=coord_head, - color=color_tangent, - width=width_tangent) + plot_vectors += arrow2d(tailpoint=coord_tail, headpoint=coord_head, color=color_tangent, width=width_tangent) else: - plot_vectors += arrow3d(coord_tail, - coord_head, - color=color_tangent, - width=width_tangent) + plot_vectors += arrow3d(coord_tail, coord_head, color=color_tangent, width=width_tangent) if k == 0 and t > tmin: # in case an initial offset was earlier added to @@ -2854,17 +2649,8 @@ def plot_integrated(self, chart=None, ambient_coords=None, t = tmin t += dt - return plot_vectors + DifferentiableCurve._graphics(self, - plot_curve, ambient_coords, - thickness=thickness, - aspect_ratio=aspect_ratio, - color=color, - style=style, - label_axes=label_axes) - return DifferentiableCurve._graphics(self, plot_curve, - ambient_coords, thickness=thickness, - aspect_ratio=aspect_ratio, color=color, - style=style, label_axes=label_axes) + return plot_vectors + DifferentiableCurve._graphics(self, plot_curve, ambient_coords, thickness=thickness, aspect_ratio=aspect_ratio, color=color, style=style, label_axes=label_axes) + return DifferentiableCurve._graphics(self, plot_curve, ambient_coords, thickness=thickness, aspect_ratio=aspect_ratio, color=color, style=style, label_axes=label_axes) class IntegratedAutoparallelCurve(IntegratedCurve): @@ -3383,9 +3169,7 @@ class IntegratedAutoparallelCurve(IntegratedCurve): sphinx_plot(graph) """ - def __init__(self, parent, affine_connection, curve_parameter, - initial_tangent_vector, chart=None, name=None, - latex_name=None, verbose=False, across_charts=False): + def __init__(self, parent, affine_connection, curve_parameter, initial_tangent_vector, chart=None, name=None, latex_name=None, verbose=False, across_charts=False): r""" Construct an autoparallel curve with respect to the given affine connection with the given initial tangent vector. @@ -3428,7 +3212,7 @@ def __init__(self, parent, affine_connection, curve_parameter, for mu in range(dim): for nu in range(dim): vMUvNU = velocities[mu] * velocities[nu] - gammaRHO_mu_nu = gamma[[rho+i0, mu+i0, nu+i0]].expr(chart=chart) + gammaRHO_mu_nu = gamma[[rho + i0, mu + i0, nu + i0]].expr(chart=chart) # line above is the expression of the scalar # field 'gamma[[rho+i0, mu+i0, nu+i0]]' in terms # of 'chart' (here, in any point of the manifold, @@ -3441,7 +3225,7 @@ def __init__(self, parent, affine_connection, curve_parameter, # line above to be shorter equations_rhs += [rhs.simplify_full()] else: - equations_rhs = {} # Dict of all equation in all top_charts + equations_rhs = {} # Dict of all equation in all top_charts for chart in parent.codomain().top_charts(): velocities = chart.symbolic_velocities() equations_rhs_chart = [] # Equation in one chart @@ -3451,17 +3235,12 @@ def __init__(self, parent, affine_connection, curve_parameter, for mu in range(dim): for nu in range(dim): vMUvNU = velocities[mu] * velocities[nu] - gammaRHO_mu_nu = gamma[ - [rho + i0, mu + i0, nu + i0]].expr(chart=chart) + gammaRHO_mu_nu = gamma[[rho + i0, mu + i0, nu + i0]].expr(chart=chart) rhs -= gammaRHO_mu_nu * vMUvNU equations_rhs_chart += [rhs.simplify_full()] equations_rhs[chart] = equations_rhs_chart - IntegratedCurve.__init__(self, parent, equations_rhs, - velocities, curve_parameter, - initial_tangent_vector, chart=chart, - name=name, latex_name=latex_name, - verbose=verbose, across_charts=across_charts) + IntegratedCurve.__init__(self, parent, equations_rhs, velocities, curve_parameter, initial_tangent_vector, chart=chart, name=name, latex_name=latex_name, verbose=verbose, across_charts=across_charts) self._affine_connection = affine_connection @@ -3533,10 +3312,7 @@ def __reduce__(self): Integrated autoparallel curve c in the 3-dimensional differentiable manifold M """ - return (type(self), (self.parent(), self._affine_connection, - self._curve_parameter, self._initial_tangent_vector, - self._chart, self._name, self._latex_name, False, - self._across_charts)) + return (type(self), (self.parent(), self._affine_connection, self._curve_parameter, self._initial_tangent_vector, self._chart, self._name, self._latex_name, False, self._across_charts)) def system(self, verbose=False): r""" @@ -3602,7 +3378,7 @@ def system(self, verbose=False): if verbose: initial_tgt_space = v0.parent() - initial_pt = initial_tgt_space.base_point() # retrieves + initial_pt = initial_tgt_space.base_point() # retrieves # the initial point as the base point of the tangent space # to which initial tangent vector belongs initial_pt_coords = list(initial_pt.coordinates(chart)) @@ -3611,7 +3387,7 @@ def system(self, verbose=False): # known initial_coord_basis = chart.frame().at(initial_pt) - initial_tgt_vec_comps = v0[initial_coord_basis,:] # will + initial_tgt_vec_comps = v0[initial_coord_basis, :] # will # raise error if components in coordinate basis are not # known @@ -3637,15 +3413,11 @@ def system(self, verbose=False): description += "{}".format(initial_tgt_vec_comps) description += " with respect to {}\n\n".format(chart) - for coord_func,velocity in zip(chart[:],self._velocities): - description += "d({})/d{} = {}\n".format(coord_func, - self._curve_parameter, - velocity) + for coord_func, velocity in zip(chart[:], self._velocities): + description += "d({})/d{} = {}\n".format(coord_func, self._curve_parameter, velocity) - for velocity,eqn in zip(self._velocities,self._equations_rhs): - description += "d({})/d{} = {}\n".format(velocity, - self._curve_parameter, - eqn) + for velocity, eqn in zip(self._velocities, self._equations_rhs): + description += "d({})/d{} = {}\n".format(velocity, self._curve_parameter, eqn) print(description) @@ -3806,9 +3578,7 @@ class IntegratedGeodesic(IntegratedAutoparallelCurve): sphinx_plot(graph) """ - def __init__(self, parent, metric, curve_parameter, - initial_tangent_vector, chart=None, name=None, - latex_name=None, verbose=False, across_charts=False): + def __init__(self, parent, metric, curve_parameter, initial_tangent_vector, chart=None, name=None, latex_name=None, verbose=False, across_charts=False): r""" Construct a geodesic curve with respect to the given metric with the given initial tangent vector. @@ -3832,11 +3602,7 @@ def __init__(self, parent, metric, curve_parameter, affine_connection = metric.connection() - IntegratedAutoparallelCurve.__init__(self, parent, - affine_connection, curve_parameter, - initial_tangent_vector, chart=chart, - name=name, latex_name=latex_name, - verbose=verbose, across_charts=across_charts) + IntegratedAutoparallelCurve.__init__(self, parent, affine_connection, curve_parameter, initial_tangent_vector, chart=chart, name=name, latex_name=latex_name, verbose=verbose, across_charts=across_charts) self._metric = metric self._across_charts = across_charts @@ -3909,10 +3675,7 @@ def __reduce__(self): Integrated geodesic c in the 2-dimensional Riemannian manifold S^2 """ - return (type(self), (self.parent(), self._metric, - self._curve_parameter, self._initial_tangent_vector, - self._chart, self._name, self._latex_name, False, - self._across_charts)) + return (type(self), (self.parent(), self._metric, self._curve_parameter, self._initial_tangent_vector, self._chart, self._name, self._latex_name, False, self._across_charts)) def system(self, verbose=False): r""" @@ -3984,7 +3747,7 @@ def system(self, verbose=False): # not known initial_coord_basis = chart.frame().at(initial_pt) - initial_tgt_vec_comps = v0[initial_coord_basis,:] + initial_tgt_vec_comps = v0[initial_coord_basis, :] # will raise error if components in coordinate basis are # not known @@ -4010,15 +3773,11 @@ def system(self, verbose=False): description += "{}".format(initial_tgt_vec_comps) description += " with respect to {}\n\n".format(chart) - for coord_func,velocity in zip(chart[:],self._velocities): - description += "d({})/d{} = {}\n".format(coord_func, - self._curve_parameter, - velocity) + for coord_func, velocity in zip(chart[:], self._velocities): + description += "d({})/d{} = {}\n".format(coord_func, self._curve_parameter, velocity) - for velocity,eqn in zip(self._velocities,self._equations_rhs): - description += "d({})/d{} = {}\n".format(velocity, - self._curve_parameter, - eqn) + for velocity, eqn in zip(self._velocities, self._equations_rhs): + description += "d({})/d{} = {}\n".format(velocity, self._curve_parameter, eqn) print(description) diff --git a/src/sage/manifolds/differentiable/levi_civita_connection.py b/src/sage/manifolds/differentiable/levi_civita_connection.py index 13ef1b1bc91..edfc52ec30c 100644 --- a/src/sage/manifolds/differentiable/levi_civita_connection.py +++ b/src/sage/manifolds/differentiable/levi_civita_connection.py @@ -18,7 +18,8 @@ - [Lee1997]_ - [ONe1983]_ """ -#****************************************************************************** + +# ****************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger # Copyright (C) 2015 Marco Mancini @@ -27,7 +28,7 @@ # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.manifolds.differentiable.affine_connection import AffineConnection from sage.manifolds.differentiable.vectorframe import CoordFrame @@ -200,6 +201,7 @@ class LeviCivitaConnection(AffineConnection): Gam^ph_r,ph = 1/r Gam^ph_th,ph = cos(th)/sin(th) """ + def __init__(self, metric, name, latex_name=None, init_coef=True): r""" Construct a Levi-Civita connection. @@ -322,12 +324,8 @@ def restrict(self, subdomain): return self if subdomain not in self._restrictions: if not subdomain.is_subset(self._domain): - raise ValueError("the provided domain is not a subdomain of " + - "the current connection's domain") - resu = LeviCivitaConnection(self._metric.restrict(subdomain), - name=self._name, - latex_name=self._latex_name, - init_coef=False) + raise ValueError("the provided domain is not a subdomain of " + "the current connection's domain") + resu = LeviCivitaConnection(self._metric.restrict(subdomain), name=self._name, latex_name=self._latex_name, init_coef=False) for frame in self._coefficients: for sframe in subdomain._top_frames: if sframe in frame._subframes: @@ -367,16 +365,12 @@ def _new_coef(self, frame): from sage.manifolds.differentiable.scalarfield import DiffScalarField from sage.manifolds.differentiable.vectorframe import CoordFrame from sage.tensor.modules.comp import Components, CompWithSym + if isinstance(frame, CoordFrame): # the Christoffel symbols are symmetric: - return CompWithSym(frame._domain.scalar_field_algebra(), frame, 3, - start_index=self._domain._sindex, - output_formatter=DiffScalarField.coord_function, - sym=(1,2)) + return CompWithSym(frame._domain.scalar_field_algebra(), frame, 3, start_index=self._domain._sindex, output_formatter=DiffScalarField.coord_function, sym=(1, 2)) # a priori no symmetry in a generic frame: - return Components(frame._domain.scalar_field_algebra(), frame, 3, - start_index=self._domain._sindex, - output_formatter=DiffScalarField.coord_function) + return Components(frame._domain.scalar_field_algebra(), frame, 3, start_index=self._domain._sindex, output_formatter=DiffScalarField.coord_function) def coef(self, frame=None): r""" @@ -461,6 +455,7 @@ def coef(self, frame=None): (-cos(th)/(r*sin(th)), cos(th)/(r*sin(th))) """ from sage.manifolds.differentiable.vectorframe import CoordFrame + if frame is None: frame = self._domain._def_frame if frame not in self._coefficients: @@ -489,40 +484,36 @@ def coef(self, frame=None): if Parallelism().get('tensor') != 1: # parallel computation nproc = Parallelism().get('tensor') - lol = lambda lst, sz: [lst[i:i+sz] for i in - range(0, len(lst), sz)] + lol = lambda lst, sz: [lst[i : i + sz] for i in range(0, len(lst), sz)] ind_list = [] for ind in gam.non_redundant_index_generator(): i, j, k = ind - ind_list.append((i,j,k)) - ind_step = max(1,int(len(ind_list)/nproc/2)) - local_list = lol(ind_list,ind_step) + ind_list.append((i, j, k)) + ind_step = max(1, int(len(ind_list) / nproc / 2)) + local_list = lol(ind_list, ind_step) # definition of the list of input parameters listParalInput = [] for ind_part in local_list: - listParalInput.append((ind_part,chart,ginv,gg,manif)) + listParalInput.append((ind_part, chart, ginv, gg, manif)) # definition of the parallel function - @parallel(p_iter='multiprocessing',ncpus=nproc) + @parallel(p_iter='multiprocessing', ncpus=nproc) def make_Connect(local_list_ijk, chart, ginv, gg, manif): partial = [] - for i,j,k in local_list_ijk: + for i, j, k in local_list_ijk: rsum = 0 for s in manif.irange(): - if ginv[i,s, chart] != 0: - rsum += ginv[i,s, chart] * ( - gg[s,k, chart].diff(j) - + gg[j,s, chart].diff(k) - - gg[j,k, chart].diff(s) ) - partial.append([i,j,k,rsum / 2]) + if ginv[i, s, chart] != 0: + rsum += ginv[i, s, chart] * (gg[s, k, chart].diff(j) + gg[j, s, chart].diff(k) - gg[j, k, chart].diff(s)) + partial.append([i, j, k, rsum / 2]) return partial # Computation and Assignation of values for ii, val in make_Connect(listParalInput): for jj in val: - gam[jj[0],jj[1],jj[2],ii[0][1]] = jj[3] + gam[jj[0], jj[1], jj[2], ii[0][1]] = jj[3] else: # sequential @@ -531,11 +522,8 @@ def make_Connect(local_list_ijk, chart, ginv, gg, manif): # The computation is performed at the ChartFunction level: rsum = 0 for s in manif.irange(): - rsum += ginv[i,s, chart] * ( - gg[s,k, chart].diff(j) - + gg[j,s, chart].diff(k) - - gg[j,k, chart].diff(s) ) - gam[i,j,k, chart] = rsum / 2 + rsum += ginv[i, s, chart] * (gg[s, k, chart].diff(j) + gg[j, s, chart].diff(k) - gg[j, k, chart].diff(s)) + gam[i, j, k, chart] = rsum / 2 # Assignation of results self._coefficients[frame] = gam @@ -576,7 +564,7 @@ def torsion(self): 0 """ if self._torsion is None: - resu = self._domain.tensor_field(1, 2, antisym=(1,2)) + resu = self._domain.tensor_field(1, 2, antisym=(1, 2)) for frame in self._coefficients: # Initialization of the frame components to zero: resu.add_comp(frame) @@ -653,11 +641,9 @@ def riemann(self, name=None, latex_name=None): if name is None: name = "Riem(" + self._metric._name + ")" if latex_name is None: - latex_name = (r"\mathrm{Riem}\left(" + self._metric._latex_name - + r"\right)") + latex_name = r"\mathrm{Riem}\left(" + self._metric._latex_name + r"\right)" manif = self._domain - resu = manif.tensor_field(1, 3, antisym=(2,3), name=name, - latex_name=latex_name) + resu = manif.tensor_field(1, 3, antisym=(2, 3), name=name, latex_name=latex_name) for frame, gam in self._coefficients.items(): # The computation is performed only on the top frames: for oframe in self._coefficients: @@ -669,51 +655,47 @@ def riemann(self, name=None, latex_name=None): gam_gam = gam.contract(1, gam, 0) gam_sc = gam.contract(2, sc, 0) res = resu.add_comp(frame) - use_Bianchi = isinstance(frame,CoordFrame) + use_Bianchi = isinstance(frame, CoordFrame) if Parallelism().get('tensor') != 1: # parallel computation nproc = Parallelism().get('tensor') - lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, - len(lst), sz)] + lol = lambda lst, sz: [lst[i : i + sz] for i in range(0, len(lst), sz)] ind_list = [] for i in manif.irange(): for j in manif.irange(): for k in manif.irange(start=j): - for l in manif.irange(start=k+1): - ind_list.append((i,j,k,l)) - ind_step = max(1, int(len(ind_list)/nproc/2)) + for l in manif.irange(start=k + 1): + ind_list.append((i, j, k, l)) + ind_step = max(1, int(len(ind_list) / nproc / 2)) local_list = lol(ind_list, ind_step) # definition of the list of input parameters listParalInput = [] for ind_part in local_list: - listParalInput.append((frame, gam, gam_gam, gam_sc, - use_Bianchi, ind_part)) + listParalInput.append((frame, gam, gam_gam, gam_sc, use_Bianchi, ind_part)) # definition of the parallel function @parallel(p_iter='multiprocessing', ncpus=nproc) - def make_Riem(frame, gam, gam_gam, gam_sc, use_Bianchi, - local_list_ijkl): - def compute_component(i,j,k,l, frame, gam, gam_gam, gam_sc): - return frame[k](gam[[i,j,l]]) - frame[l](gam[[i,j,k]]) + \ - gam_gam[[i,k,j,l]] - gam_gam[[i,l,j,k]] - gam_sc[[i,j,k,l]] + def make_Riem(frame, gam, gam_gam, gam_sc, use_Bianchi, local_list_ijkl): + def compute_component(i, j, k, l, frame, gam, gam_gam, gam_sc): + return frame[k](gam[[i, j, l]]) - frame[l](gam[[i, j, k]]) + gam_gam[[i, k, j, l]] - gam_gam[[i, l, j, k]] - gam_sc[[i, j, k, l]] + partial = [] - for i,j,k,l in local_list_ijkl: - R_ijkl = compute_component(i,j,k,l, frame, gam, gam_gam, gam_sc) - partial.append([i,j,k,l, R_ijkl]) + for i, j, k, l in local_list_ijkl: + R_ijkl = compute_component(i, j, k, l, frame, gam, gam_gam, gam_sc) + partial.append([i, j, k, l, R_ijkl]) if j == k: - partial.append([i,l,k,l, compute_component(i,l,k,l, frame, - gam, gam_gam, gam_sc)]) + partial.append([i, l, k, l, compute_component(i, l, k, l, frame, gam, gam_gam, gam_sc)]) else: - R_ikjl = compute_component(i,k,j,l, frame, gam, gam_gam, gam_sc) - partial.append([i,k,j,l, R_ikjl]) + R_ikjl = compute_component(i, k, j, l, frame, gam, gam_gam, gam_sc) + partial.append([i, k, j, l, R_ikjl]) if use_Bianchi: - partial.append([i,l,j,k, R_ikjl - R_ijkl]) + partial.append([i, l, j, k, R_ikjl - R_ijkl]) else: - partial.append([i,l,j,k, compute_component(i,l,j,k, frame, - gam, gam_gam, gam_sc)]) + partial.append([i, l, j, k, compute_component(i, l, j, k, frame, gam, gam_gam, gam_sc)]) return partial + # Computation and assignation of values - for ii,val in make_Riem(listParalInput): + for ii, val in make_Riem(listParalInput): for jj in val: res[jj[0], jj[1], jj[2], jj[3]] = jj[4] @@ -724,20 +706,16 @@ def compute_component(i,j,k,l, frame, gam, gam_gam, gam_sc): for k in manif.irange(): # antisymmetry of the Riemann tensor taken # into account by l>k: - for l in manif.irange(start=k+1): + for l in manif.irange(start=k + 1): if not use_Bianchi or (j <= k or j <= l): - res[i,j,k,l] = frame[k](gam[[i,j,l]]) - \ - frame[l](gam[[i,j,k]]) + \ - gam_gam[[i,k,j,l]] - \ - gam_gam[[i,l,j,k]] - \ - gam_sc[[i,j,k,l]] + res[i, j, k, l] = frame[k](gam[[i, j, l]]) - frame[l](gam[[i, j, k]]) + gam_gam[[i, k, j, l]] - gam_gam[[i, l, j, k]] - gam_sc[[i, j, k, l]] if use_Bianchi: # first Bianchi identity for j in manif.irange(): - for k in manif.irange(end=j-1): - for l in manif.irange(start=k+1,end=j-1): + for k in manif.irange(end=j - 1): + for l in manif.irange(start=k + 1, end=j - 1): # j > k and j > l: - res[i,j,k,l] = res[i,l,k,j] - res[i,k,l,j] + res[i, j, k, l] = res[i, l, k, j] - res[i, k, l, j] self._riemann = resu return self._riemann @@ -819,12 +797,10 @@ def ricci(self, name=None, latex_name=None): if name is None: name = "Ric(" + self._metric._name + ")" if latex_name is None: - latex_name = r"\mathrm{Ric}\left(" + \ - self._metric._latex_name + r"\right)" + latex_name = r"\mathrm{Ric}\left(" + self._metric._latex_name + r"\right)" manif = self._domain riem = self.riemann() - resu = manif.tensor_field(0, 2, sym=(0,1), name=name, - latex_name=latex_name) + resu = manif.tensor_field(0, 2, sym=(0, 1), name=name, latex_name=latex_name) for frame in self._coefficients: cric = resu.add_comp(frame) criem = riem.comp(frame) @@ -833,7 +809,7 @@ def ricci(self, name=None, latex_name=None): for j in manif.irange(start=i): rsum = 0 for k in manif.irange(): - rsum += criem[[k,i,k,j]] - cric[i,j] = rsum + rsum += criem[[k, i, k, j]] + cric[i, j] = rsum self._ricci = resu return self._ricci diff --git a/src/sage/manifolds/differentiable/manifold.py b/src/sage/manifolds/differentiable/manifold.py index 1ad2543827a..4323af263a5 100644 --- a/src/sage/manifolds/differentiable/manifold.py +++ b/src/sage/manifolds/differentiable/manifold.py @@ -635,9 +635,8 @@ class DifferentiableManifold(TopologicalManifold): sage: TestSuite(M).run() """ - def __init__(self, n, name, field, structure, base_manifold=None, - diff_degree=infinity, latex_name=None, start_index=0, - category=None, unique_tag=None): + + def __init__(self, n, name, field, structure, base_manifold=None, diff_degree=infinity, latex_name=None, start_index=0, category=None, unique_tag=None): r""" Construct a differentiable manifold. @@ -677,21 +676,15 @@ def __init__(self, n, name, field, structure, base_manifold=None, else: category = Manifolds(field_c).Differentiable() elif not isinstance(base_manifold, DifferentiableManifold): - raise TypeError("the argument 'base_manifold' must be a " + - "differentiable manifold") - TopologicalManifold.__init__(self, n, name, field, structure, - base_manifold=base_manifold, - latex_name=latex_name, - start_index=start_index, - category=category) + raise TypeError("the argument 'base_manifold' must be a " + "differentiable manifold") + TopologicalManifold.__init__(self, n, name, field, structure, base_manifold=base_manifold, latex_name=latex_name, start_index=start_index, category=category) # The degree of differentiability: if diff_degree == infinity: self._diff_degree = infinity elif not isinstance(diff_degree, (int, Integer)): raise TypeError("the argument 'diff_degree' must be an integer") elif diff_degree < 1: - raise ValueError("the argument 'diff_degree' must be a positive " + - "integer") + raise ValueError("the argument 'diff_degree' must be a positive " + "integer") else: self._diff_degree = diff_degree # Vector frames: @@ -704,14 +697,14 @@ def __init__(self, n, name, field, structure, base_manifold=None, # List of vector frames that individually cover self, i.e. whose # domains are self (if non-empty, self is parallelizable): self._covering_frames = [] - self._parallelizable_parts = set() # parallelizable subsets contained in self - self._frame_changes = {} # dictionary of changes of frames + self._parallelizable_parts = set() # parallelizable subsets contained in self + self._frame_changes = {} # dictionary of changes of frames # Dictionary of vector field modules along self # (keys = diff. map from self to an open set (possibly the identity map)) - self._vector_field_modules = {} # dict of all established vector field - # modules - self._tensor_bundles = {} # dict of dict of all established tensor - # bundles + self._vector_field_modules = {} # dict of all established vector field + # modules + self._tensor_bundles = {} # dict of dict of all established tensor + # bundles def diff_degree(self): r""" @@ -828,11 +821,7 @@ def open_subset(self, name, latex_name=None, coord_def={}, supersets=None): sage: M((-1/2,1/3)) in U True """ - resu = DifferentiableManifold(self._dim, name, self._field, - self._structure, base_manifold=self._manifold, - diff_degree=self._diff_degree, - latex_name=latex_name, - start_index=self._sindex) + resu = DifferentiableManifold(self._dim, name, self._field, self._structure, base_manifold=self._manifold, diff_degree=self._diff_degree, latex_name=latex_name, start_index=self._sindex) if supersets is None: supersets = [self] for superset in supersets: @@ -866,8 +855,7 @@ def _init_open_subset(self, resu, coord_def): super()._init_open_subset(resu, coord_def=coord_def) #!# update vector frames and change of frames - def diff_map(self, codomain, coord_functions=None, chart1=None, - chart2=None, name=None, latex_name=None): + def diff_map(self, codomain, coord_functions=None, chart1=None, chart2=None, name=None, latex_name=None): r""" Define a differentiable map between the current differentiable manifold and a differentiable manifold over the same topological field. @@ -962,18 +950,15 @@ def diff_map(self, codomain, coord_functions=None, chart1=None, if chart1 is None: chart1 = self._def_chart elif chart1 not in self._atlas: - raise ValueError("{} is not a chart ".format(chart1) + - "defined on the {}".format(self)) + raise ValueError("{} is not a chart ".format(chart1) + "defined on the {}".format(self)) if chart2 is None: chart2 = codomain._def_chart elif chart2 not in codomain._atlas: - raise ValueError("{} is not a chart ".format(chart2) + - " defined on the {}".format(codomain)) + raise ValueError("{} is not a chart ".format(chart2) + " defined on the {}".format(codomain)) coord_functions = {(chart1, chart2): coord_functions} return homset(coord_functions, name=name, latex_name=latex_name) - def diffeomorphism(self, codomain=None, coord_functions=None, chart1=None, - chart2=None, name=None, latex_name=None): + def diffeomorphism(self, codomain=None, coord_functions=None, chart1=None, chart2=None, name=None, latex_name=None): r""" Define a diffeomorphism between the current manifold and another one. @@ -1060,16 +1045,13 @@ def diffeomorphism(self, codomain=None, coord_functions=None, chart1=None, if chart1 is None: chart1 = self._def_chart elif chart1 not in self._atlas: - raise ValueError("{} is not a chart ".format(chart1) + - "defined on the {}".format(self)) + raise ValueError("{} is not a chart ".format(chart1) + "defined on the {}".format(self)) if chart2 is None: chart2 = codomain._def_chart elif chart2 not in codomain._atlas: - raise ValueError("{} is not a chart ".format(chart2) + - " defined on the {}".format(codomain)) + raise ValueError("{} is not a chart ".format(chart2) + " defined on the {}".format(codomain)) coord_functions = {(chart1, chart2): coord_functions} - return homset(coord_functions, name=name, latex_name=latex_name, - is_isomorphism=True) + return homset(coord_functions, name=name, latex_name=latex_name, is_isomorphism=True) def vector_bundle(self, rank, name, field='real', latex_name=None): r""" @@ -1100,8 +1082,8 @@ class as the manifold. from sage.manifolds.differentiable.vector_bundle import ( DifferentiableVectorBundle, ) - return DifferentiableVectorBundle(rank, name, self, field=field, - latex_name=latex_name) + + return DifferentiableVectorBundle(rank, name, self, field=field, latex_name=latex_name) def tangent_bundle(self, dest_map=None): r""" @@ -1210,19 +1192,16 @@ def tensor_bundle(self, k, l, dest_map=None): dest_map = self.identity_map() if dest_map not in self._tensor_bundles: from sage.manifolds.differentiable.vector_bundle import TensorBundle - self._tensor_bundles[dest_map] = {(k, l): - TensorBundle(self, k, l, - dest_map=dest_map)} + + self._tensor_bundles[dest_map] = {(k, l): TensorBundle(self, k, l, dest_map=dest_map)} else: if (k, l) not in self._tensor_bundles[dest_map]: from sage.manifolds.differentiable.vector_bundle import TensorBundle - self._tensor_bundles[dest_map][(k, l)] = TensorBundle(self, k, - l, dest_map=dest_map) + + self._tensor_bundles[dest_map][(k, l)] = TensorBundle(self, k, l, dest_map=dest_map) return self._tensor_bundles[dest_map][(k, l)] - def vector_field_module( - self, dest_map: Optional[DiffMap] = None, force_free: bool = False - ) -> Union[VectorFieldModule, VectorFieldFreeModule]: + def vector_field_module(self, dest_map: Optional[DiffMap] = None, force_free: bool = False) -> Union[VectorFieldModule, VectorFieldFreeModule]: r""" Return the set of vector fields defined on ``self``, possibly with values in another differentiable manifold, as a module over the @@ -1371,16 +1350,15 @@ def vector_field_module( VectorFieldFreeModule, VectorFieldModule, ) + if dest_map is None: dest_map = self.identity_map() codomain = dest_map._codomain if dest_map not in self._vector_field_modules: if codomain.is_manifestly_parallelizable() or force_free: - self._vector_field_modules[dest_map] = \ - VectorFieldFreeModule(self, dest_map=dest_map) + self._vector_field_modules[dest_map] = VectorFieldFreeModule(self, dest_map=dest_map) else: - self._vector_field_modules[dest_map] = \ - VectorFieldModule(self, dest_map=dest_map) + self._vector_field_modules[dest_map] = VectorFieldModule(self, dest_map=dest_map) return self._vector_field_modules[dest_map] def tensor_field_module(self, tensor_type, dest_map=None): @@ -1884,8 +1862,7 @@ def tensor_field(self, *args, **kwargs): antisym = kwargs.pop('antisym', None) dest_map = kwargs.pop('dest_map', None) vmodule = self.vector_field_module(dest_map) - resu = vmodule.tensor((k, l), name=name, latex_name=latex_name, - sym=sym, antisym=antisym) + resu = vmodule.tensor((k, l), name=name, latex_name=latex_name, sym=sym, antisym=antisym) if len(args) > 2: # Some components are to be initialized resu._init_components(args[2], **kwargs) @@ -2046,8 +2023,7 @@ class :class:`~sage.manifolds.differentiable.diff_map.DiffMap` latex_name = kwargs.pop('latex_name', None) dest_map = kwargs.pop('dest_map', None) vmodule = self.vector_field_module(dest_map) - resu = vmodule.tensor((0, 2), name=name, latex_name=latex_name, - sym=(0,1)) + resu = vmodule.tensor((0, 2), name=name, latex_name=latex_name, sym=(0, 1)) if comp: # Some components are to be initialized resu._init_components(*comp, **kwargs) @@ -2151,8 +2127,7 @@ def multivector_field(self, *args, **kwargs): latex_name = kwargs.pop('latex_name', None) dest_map = kwargs.pop('dest_map', None) vmodule = self.vector_field_module(dest_map) - resu = vmodule.alternating_contravariant_tensor(degree, name=name, - latex_name=latex_name) + resu = vmodule.alternating_contravariant_tensor(degree, name=name, latex_name=latex_name) if len(args) > 1: # Some components are to be initialized resu._init_components(args[1], **kwargs) @@ -2254,8 +2229,7 @@ def diff_form(self, *args, **kwargs) -> DiffForm: latex_name = kwargs.pop('latex_name', None) dest_map = kwargs.pop('dest_map', None) vmodule = self.vector_field_module(dest_map) - resu = vmodule.alternating_form(degree, name=name, - latex_name=latex_name) + resu = vmodule.alternating_form(degree, name=name, latex_name=latex_name) if len(args) > 1: # Some components are to be initialized resu._init_components(args[1], **kwargs) @@ -2431,9 +2405,7 @@ def mixed_form(self, comp=None, name=None, latex_name=None, dest_map=None): resu[:] = comp return resu - def symplectic_form( - self, name: Optional[str] = None, latex_name: Optional[str] = None - ): + def symplectic_form(self, name: Optional[str] = None, latex_name: Optional[str] = None): r""" Construct a symplectic form on the current manifold. @@ -2454,9 +2426,7 @@ def symplectic_form( """ return self.vector_field_module().symplectic_form(name, latex_name) - def poisson_tensor( - self, name: Optional[str] = None, latex_name: Optional[str] = None - ): + def poisson_tensor(self, name: Optional[str] = None, latex_name: Optional[str] = None): r""" Construct a Poisson tensor on the current manifold. @@ -2699,6 +2669,7 @@ def set_orientation(self, orientation): Coordinate frame (V, (∂/∂u,∂/∂v))] """ from sage.manifolds.differentiable.vectorframe import VectorFrame + chart_type = self._structure.chart if isinstance(orientation, chart_type): orientation = [orientation.frame()] @@ -2710,16 +2681,14 @@ def set_orientation(self, orientation): else: orientation = list(orientation) else: - raise TypeError("orientation must be a chart/frame or a " - "list/tuple of charts/frames") + raise TypeError("orientation must be a chart/frame or a " "list/tuple of charts/frames") dom_union = None for frame in orientation: if not isinstance(frame, VectorFrame): raise ValueError("orientation must consist of vector frames") dom = frame._domain if not dom.is_subset(self): - raise ValueError("{} must be defined ".format(frame) + - "on a subset of {}".format(self)) + raise ValueError("{} must be defined ".format(frame) + "on a subset of {}".format(self)) if dom_union is not None: dom_union = dom.union(dom_union) else: @@ -2873,6 +2842,7 @@ def set_default_frame(self, frame): Vector frame (M, (e_0,e_1)) """ from sage.manifolds.differentiable.vectorframe import VectorFrame + if not isinstance(frame, VectorFrame): raise TypeError("{} is not a vector frame".format(frame)) if not frame._domain.is_subset(self): @@ -2942,12 +2912,10 @@ def change_of_frame(self, frame1, frame2): True """ if (frame1, frame2) not in self._frame_changes: - raise ValueError("the change of frame from {} to {}".format(frame1, frame2) + - " has not been defined on the {}".format(self)) + raise ValueError("the change of frame from {} to {}".format(frame1, frame2) + " has not been defined on the {}".format(self)) return self._frame_changes[(frame1, frame2)] - def set_change_of_frame(self, frame1, frame2, change_of_frame, - compute_inverse=True): + def set_change_of_frame(self, frame1, frame2, change_of_frame, compute_inverse=True): r""" Relate two vector frames by an automorphism. @@ -2991,15 +2959,13 @@ def set_change_of_frame(self, frame1, frame2, change_of_frame, from sage.manifolds.differentiable.automorphismfield import ( AutomorphismFieldParal, ) + fmodule = frame1._fmodule if frame2._fmodule != fmodule: - raise ValueError("the two frames are not defined on the same " + - "vector field module") + raise ValueError("the two frames are not defined on the same " + "vector field module") if not isinstance(change_of_frame, AutomorphismFieldParal): - raise TypeError("the argument change_of_frame must be some " + - "instance of AutomorphismFieldParal") - fmodule.set_change_of_basis(frame1, frame2, change_of_frame, - compute_inverse=compute_inverse) + raise TypeError("the argument change_of_frame must be some " + "instance of AutomorphismFieldParal") + fmodule.set_change_of_basis(frame1, frame2, change_of_frame, compute_inverse=compute_inverse) for sdom in self.open_supersets(): sdom._frame_changes[(frame1, frame2)] = change_of_frame if compute_inverse: @@ -3145,6 +3111,7 @@ def vector_frame(self, *args, **kwargs) -> VectorFrame: :class:`~sage.manifolds.differentiable.vectorframe.VectorFrame`. """ from sage.manifolds.differentiable.vectorframe import VectorFrame + # Input processing symbol = None vector_fields = None @@ -3154,8 +3121,7 @@ def vector_frame(self, *args, **kwargs) -> VectorFrame: if n_args == 2: vector_fields = args[1] elif n_args > 2: - raise TypeError("vector_frame() takes at most two positional " - "arguments") + raise TypeError("vector_frame() takes at most two positional " "arguments") latex_symbol = kwargs.pop('latex_symbol', None) dest_map = kwargs.pop('dest_map', None) from_frame = kwargs.pop('from_frame', None) @@ -3169,22 +3135,15 @@ def vector_frame(self, *args, **kwargs) -> VectorFrame: if dest_map and dest_map is not dest_map0: raise ValueError("incompatible values of destination maps") dest_map = dest_map0 - resu = VectorFrame(self.vector_field_module(dest_map=dest_map, - force_free=True), - symbol=symbol, latex_symbol=latex_symbol, - from_frame=from_frame, indices=indices, - latex_indices=latex_indices, symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) + resu = VectorFrame(self.vector_field_module(dest_map=dest_map, force_free=True), symbol=symbol, latex_symbol=latex_symbol, from_frame=from_frame, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) if vector_fields: linked = False try: resu._init_from_family(vector_fields) except ArithmeticError as err: - linked = str(err) in ["non-invertible matrix", - "input matrix must be nonsingular"] + linked = str(err) in ["non-invertible matrix", "input matrix must be nonsingular"] if linked: - raise ValueError("the provided vector fields are not " - "linearly independent") + raise ValueError("the provided vector fields are not " "linearly independent") # Adding the newly generated changes of frame to the # dictionary _frame_changes of self and its supersets: for frame_pair, chge in resu._fmodule._basis_changes.items(): @@ -3401,14 +3360,14 @@ def tangent_space(self, point, base_ring=None): """ from sage.manifolds.differentiable.tangent_space import TangentSpace from sage.manifolds.point import ManifoldPoint + if not isinstance(point, ManifoldPoint): raise TypeError("{} is not a manifold point".format(point)) if point not in self: raise ValueError("{} is not a point on the {}".format(point, self)) return TangentSpace(point, base_ring=base_ring) - def curve(self, coord_expression, param, chart=None, - name=None, latex_name=None): + def curve(self, coord_expression, param, chart=None, name=None, latex_name=None): r""" Define a differentiable curve in the manifold. @@ -3480,11 +3439,11 @@ def curve(self, coord_expression, param, chart=None, for more examples, including plots. """ from sage.manifolds.differentiable.examples.real_line import RealLine + if not isinstance(param, (tuple, list)): param = (param, minus_infinity, infinity) elif len(param) != 3: - raise ValueError("the argument 'param' must be of the form " + - "(t, t_min, t_max)") + raise ValueError("the argument 'param' must be of the form " + "(t, t_min, t_max)") t = param[0] t_min = param[1] t_max = param[2] @@ -3496,8 +3455,7 @@ def curve(self, coord_expression, param, chart=None, if chart is None: chart = self._def_chart elif chart not in self._atlas: - raise ValueError("the {} has not been ".format(chart) + - "defined on the {}".format(self)) + raise ValueError("the {} has not been ".format(chart) + "defined on the {}".format(self)) if isinstance(coord_expression, (tuple, list)): coord_expression = {chart: coord_expression} else: @@ -3505,9 +3463,7 @@ def curve(self, coord_expression, param, chart=None, coord_expression = {chart: (coord_expression,)} return curve_set(coord_expression, name=name, latex_name=latex_name) - def integrated_curve(self, equations_rhs, velocities, curve_param, - initial_tangent_vector, chart=None, name=None, - latex_name=None, verbose=False, across_charts=False): + def integrated_curve(self, equations_rhs, velocities, curve_param, initial_tangent_vector, chart=None, name=None, latex_name=None, verbose=False, across_charts=False): r""" Construct a curve defined by a system of second order differential equations in the coordinate functions. @@ -3601,24 +3557,17 @@ def integrated_curve(self, equations_rhs, velocities, curve_param, from sage.manifolds.differentiable.manifold_homset import IntegratedCurveSet if len(curve_param) != 3: - raise ValueError("the argument 'curve_param' must be of the form " + - "(t, t_min, t_max)") + raise ValueError("the argument 'curve_param' must be of the form " + "(t, t_min, t_max)") t = curve_param[0] t_min = curve_param[1] t_max = curve_param[2] real_field = RealLine(names=(repr(t),)) interval = real_field.open_interval(t_min, t_max) - integrated_curve_set = IntegratedCurveSet(interval, self) # not + integrated_curve_set = IntegratedCurveSet(interval, self) # not # possible to use Hom(interval, self) - return integrated_curve_set(equations_rhs, velocities, t, - initial_tangent_vector, chart=chart, - name=name, latex_name=latex_name, - verbose=verbose, across_charts=across_charts) - - def integrated_autoparallel_curve(self, affine_connection, - curve_param, initial_tangent_vector, chart=None, - name=None, latex_name=None, verbose=False, - across_charts=False): + return integrated_curve_set(equations_rhs, velocities, t, initial_tangent_vector, chart=chart, name=name, latex_name=latex_name, verbose=verbose, across_charts=across_charts) + + def integrated_autoparallel_curve(self, affine_connection, curve_param, initial_tangent_vector, chart=None, name=None, latex_name=None, verbose=False, across_charts=False): r""" Construct an autoparallel curve on the manifold with respect to a given affine connection. @@ -3735,27 +3684,17 @@ def integrated_autoparallel_curve(self, affine_connection, ) if len(curve_param) != 3: - raise ValueError("the argument 'curve_param' must be " + - "of the form (t, t_min, t_max)") + raise ValueError("the argument 'curve_param' must be " + "of the form (t, t_min, t_max)") t = curve_param[0] t_min = curve_param[1] t_max = curve_param[2] real_field = RealLine(names=(repr(t),)) interval = real_field.open_interval(t_min, t_max) - autoparallel_curve_set = IntegratedAutoparallelCurveSet(interval, - self) + autoparallel_curve_set = IntegratedAutoparallelCurveSet(interval, self) # not possible to use Hom(interval, self) - return autoparallel_curve_set(affine_connection, t, - initial_tangent_vector, - chart=chart, name=name, - latex_name=latex_name, - verbose=verbose, - across_charts=across_charts) - - def integrated_geodesic(self, metric, curve_param, - initial_tangent_vector, chart=None, - name=None, latex_name=None, verbose=False, - across_charts=False): + return autoparallel_curve_set(affine_connection, t, initial_tangent_vector, chart=chart, name=name, latex_name=latex_name, verbose=verbose, across_charts=across_charts) + + def integrated_geodesic(self, metric, curve_param, initial_tangent_vector, chart=None, name=None, latex_name=None, verbose=False, across_charts=False): r""" Construct a geodesic on the manifold with respect to a given metric. @@ -3853,19 +3792,14 @@ def integrated_geodesic(self, metric, curve_param, from sage.manifolds.differentiable.manifold_homset import IntegratedGeodesicSet if len(curve_param) != 3: - raise ValueError("the argument 'curve_param' must be of " + - "the form (t, t_min, t_max)") + raise ValueError("the argument 'curve_param' must be of " + "the form (t, t_min, t_max)") t = curve_param[0] t_min = curve_param[1] t_max = curve_param[2] real_field = RealLine(names=(repr(t),)) interval = real_field.open_interval(t_min, t_max) integrated_geodesic_set = IntegratedGeodesicSet(interval, self) - return integrated_geodesic_set(metric, t, initial_tangent_vector, - chart=chart, name=name, - latex_name=latex_name, - verbose=verbose, - across_charts=across_charts) + return integrated_geodesic_set(metric, t, initial_tangent_vector, chart=chart, name=name, latex_name=latex_name, verbose=verbose, across_charts=across_charts) def affine_connection(self, name, latex_name=None): r""" @@ -3901,11 +3835,10 @@ def affine_connection(self, name, latex_name=None): for more examples. """ from sage.manifolds.differentiable.affine_connection import AffineConnection + return AffineConnection(self, name, latex_name) - def metric(self, name: str, signature: Optional[int] = None, - latex_name: Optional[str] = None, - dest_map: Optional[DiffMap] = None) -> PseudoRiemannianMetric: + def metric(self, name: str, signature: Optional[int] = None, latex_name: Optional[str] = None, dest_map: Optional[DiffMap] = None) -> PseudoRiemannianMetric: r""" Define a pseudo-Riemannian metric on the manifold. @@ -4012,7 +3945,7 @@ class :class:`~sage.manifolds.differentiable.diff_map.DiffMap` """ vmodule = self.vector_field_module(dest_map) dim = vmodule.ambient_domain().dimension() - return vmodule.metric(name, signature=(0,dim-1,1), latex_name=latex_name) + return vmodule.metric(name, signature=(0, dim - 1, 1), latex_name=latex_name) def riemannian_metric(self, name, latex_name=None, dest_map=None): r""" @@ -4066,8 +3999,7 @@ class :class:`~sage.manifolds.differentiable.diff_map.DiffMap` dim = vmodule.ambient_domain().dimension() return vmodule.metric(name, signature=dim, latex_name=latex_name) - def lorentzian_metric(self, name, signature='positive', latex_name=None, - dest_map=None): + def lorentzian_metric(self, name, signature='positive', latex_name=None, dest_map=None): r""" Define a Lorentzian metric on the manifold. @@ -4232,7 +4164,7 @@ def tangent_vector(self, *args, **kwargs): if len(args) < 2: raise TypeError("a point and a set of components must be provided") point = args[0] - tspace = self.tangent_space(point) # checks on point are performed here + tspace = self.tangent_space(point) # checks on point are performed here comp0 = args[1] if hasattr(comp0, '__len__') and hasattr(comp0, '__getitem__'): # comp0 is a list/vector of components @@ -4242,8 +4174,7 @@ def tangent_vector(self, *args, **kwargs): dim = self._dim if len(args) != dim + 1: raise ValueError(f"{dim} components must be provided") - comp = args[1:dim + 1] - return tspace._element_constructor_(comp=comp, basis=basis, name=name, - latex_name=latex_name) + comp = args[1 : dim + 1] + return tspace._element_constructor_(comp=comp, basis=basis, name=name, latex_name=latex_name) vector = tangent_vector diff --git a/src/sage/manifolds/differentiable/manifold_homset.py b/src/sage/manifolds/differentiable/manifold_homset.py index 1ce82e51ae1..3ca1349792b 100644 --- a/src/sage/manifolds/differentiable/manifold_homset.py +++ b/src/sage/manifolds/differentiable/manifold_homset.py @@ -33,14 +33,15 @@ - [Lee2013]_ - [KN1963]_ """ -#****************************************************************************** + +# ****************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.manifolds.differentiable.curve import DifferentiableCurve from sage.manifolds.differentiable.diff_map import DiffMap @@ -183,14 +184,12 @@ def __init__(self, domain, codomain, name=None, latex_name=None): sage: TestSuite(E).run() """ from sage.manifolds.differentiable.manifold import DifferentiableManifold + if not isinstance(domain, DifferentiableManifold): - raise TypeError("domain = {} is not an ".format(domain) + - "instance of DifferentiableManifold") + raise TypeError("domain = {} is not an ".format(domain) + "instance of DifferentiableManifold") if not isinstance(codomain, DifferentiableManifold): - raise TypeError("codomain = {} is not an ".format(codomain) + - "instance of DifferentiableManifold") - TopologicalManifoldHomset.__init__(self, domain, codomain, name=name, - latex_name=latex_name) + raise TypeError("codomain = {} is not an ".format(codomain) + "instance of DifferentiableManifold") + TopologicalManifoldHomset.__init__(self, domain, codomain, name=name, latex_name=latex_name) #### Parent methods #### @@ -218,7 +217,8 @@ def _coerce_map_from_(self, other): #### End of parent methods #### -#****************************************************************************** +# ****************************************************************************** + class DifferentiableCurveSet(DifferentiableManifoldHomset): r""" @@ -368,6 +368,7 @@ class DifferentiableCurveSet(DifferentiableManifoldHomset): sage: TestSuite(EI).run() """ + Element = DifferentiableCurve def __init__(self, domain, codomain, name=None, latex_name=None): @@ -405,16 +406,14 @@ def __init__(self, domain, codomain, name=None, latex_name=None): sage: TestSuite(H).run() """ from sage.manifolds.differentiable.examples.real_line import OpenInterval + if not isinstance(domain, OpenInterval): raise TypeError("{} is not an open real interval".format(domain)) - DifferentiableManifoldHomset.__init__(self, domain, codomain, name=name, - latex_name=latex_name) + DifferentiableManifoldHomset.__init__(self, domain, codomain, name=name, latex_name=latex_name) #### Parent methods #### - def _element_constructor_(self, coord_expression, name=None, - latex_name=None, is_isomorphism=False, - is_identity=False): + def _element_constructor_(self, coord_expression, name=None, latex_name=None, is_isomorphism=False, is_identity=False): r""" Construct an element of ``self``, i.e. a differentiable curve `I \to M`, where `I` is a real interval and `M` some @@ -435,10 +434,7 @@ def _element_constructor_(self, coord_expression, name=None, Identity map Id_ℝ of the Real number line ℝ """ # Standard construction - return self.element_class(self, coord_expression=coord_expression, - name=name, latex_name=latex_name, - is_isomorphism=is_isomorphism, - is_identity=is_identity) + return self.element_class(self, coord_expression=coord_expression, name=name, latex_name=latex_name, is_isomorphism=is_isomorphism, is_identity=is_identity) def _an_element_(self): r""" @@ -476,6 +472,7 @@ def _an_element_(self): """ from sage.rings.infinity import Infinity from sage.rings.rational_field import QQ + dom = self.domain() codom = self.codomain() # A simple curve is constructed around a point of the codomain: @@ -489,26 +486,27 @@ def _an_element_(self): one_half = QQ(1) / QQ(2) if xmin == -Infinity: if xmax == Infinity: - x1 = - one_half + x1 = -one_half x2 = one_half else: - x1 = xmax - 3*one_half + x1 = xmax - 3 * one_half x2 = xmax - one_half else: if xmax == Infinity: x1 = xmin + one_half - x2 = xmin + 3*one_half + x2 = xmin + 3 * one_half else: dx = (xmax - xmin) / 4 x1 = xmin + dx x2 = xmax - dx # The coordinate function defining the curve: t = dom.canonical_coordinate() - target_coord[0] = x1 + (x2-x1) / (1+t*t) + target_coord[0] = x1 + (x2 - x1) / (1 + t * t) coord_expression = {chart2: target_coord} return self.element_class(self, coord_expression) -#****************************************************************************** + +# ****************************************************************************** class IntegratedCurveSet(DifferentiableCurveSet): @@ -719,27 +717,22 @@ def __init__(self, domain, codomain, name=None, latex_name=None): from sage.rings.infinity import Infinity - DifferentiableCurveSet.__init__(self, domain, codomain, - name=name, latex_name=latex_name) + DifferentiableCurveSet.__init__(self, domain, codomain, name=name, latex_name=latex_name) # checking argument 'domain': 't_min' and 't_max' are only # allowed to be either expressions of finite real values t_min = domain.lower_bound() t_max = domain.upper_bound() if t_min == -Infinity or t_max == +Infinity: - raise ValueError("both boundaries of the interval " + - "defining the domain of a Homset of " + - "integrated curves need to be finite") + raise ValueError("both boundaries of the interval " + "defining the domain of a Homset of " + "integrated curves need to be finite") if name is None: - self._name = "Hom_integrated({},{})".format(domain._name, - codomain._name) + self._name = "Hom_integrated({},{})".format(domain._name, codomain._name) else: self._name = name if latex_name is None: self._latex_name = r"\mathrm{{Hom}_{integrated}}" - self._latex_name += r"\left({},{}\right)".format( - domain._latex_name, codomain._latex_name) + self._latex_name += r"\left({},{}\right)".format(domain._latex_name, codomain._latex_name) else: self._latex_name = latex_name @@ -760,14 +753,11 @@ def _repr_(self): spaces which actually are integrated curves """ description = "Set of Morphisms " - description += "from {} to {} in {} ".format(self._domain, - self._codomain, self.category()) + description += "from {} to {} in {} ".format(self._domain, self._codomain, self.category()) description += "which actually are integrated curves" return description - def _element_constructor_(self, equations_rhs, velocities, - curve_parameter, initial_tangent_vector, chart=None, - name=None, latex_name=None, verbose=False, across_charts=False): + def _element_constructor_(self, equations_rhs, velocities, curve_parameter, initial_tangent_vector, chart=None, name=None, latex_name=None, verbose=False, across_charts=False): r""" Construct an element of ``self``, i.e. an integrated curve `I \to M`, where `I` is a real interval and `M` some @@ -794,9 +784,7 @@ def _element_constructor_(self, equations_rhs, velocities, manifold M """ # Standard construction - return self.element_class(self, equations_rhs, velocities, - curve_parameter, initial_tangent_vector, chart=chart, - name=name, latex_name=latex_name, verbose=verbose, across_charts=across_charts) + return self.element_class(self, equations_rhs, velocities, curve_parameter, initial_tangent_vector, chart=chart, name=name, latex_name=latex_name, verbose=verbose, across_charts=across_charts) def _an_element_(self): r""" @@ -868,7 +856,7 @@ def _an_element_(self): dom = self.domain() t = dom.canonical_coordinate() - t_min = dom.lower_bound() # this is either an expression or a + t_min = dom.lower_bound() # this is either an expression or a # finite value thanks to tests in '__init__' codom = self.codomain() @@ -910,11 +898,11 @@ def _an_element_(self): p = codom.point(p_coords) # The initial tangent vector: - v_comps = [(x0_B-x0_A)/2] + [0 for i in range(dim-1)] + v_comps = [(x0_B - x0_A) / 2] + [0 for i in range(dim - 1)] v = codom.tangent_space(p)(v_comps) # The equations defining the curve: - eqns_rhs = [-(x0_B-x0_A)/2*sin(param-t_min)]+[0 for i in range(dim-1)] + eqns_rhs = [-(x0_B - x0_A) / 2 * sin(param - t_min)] + [0 for i in range(dim - 1)] # combined with the initial components above, all velocities # vanish, except the first one, which is a cosine function. # This differential system results in a curve constant in all @@ -924,7 +912,7 @@ def _an_element_(self): # The symbolic expressions for the velocities: vels = chart2.symbolic_velocities() - return self.element_class(self,eqns_rhs,vels,param,v) + return self.element_class(self, eqns_rhs, vels, param, v) def one(self): r""" @@ -960,11 +948,10 @@ def one(self): if self.codomain() != self.domain(): raise TypeError("{} is not a monoid".format(self)) else: - raise ValueError("the identity is not implemented for " + - "integrated curves and associated " + - "subclasses") + raise ValueError("the identity is not implemented for " + "integrated curves and associated " + "subclasses") -#****************************************************************************** + +# ****************************************************************************** class IntegratedAutoparallelCurveSet(IntegratedCurveSet): @@ -1151,17 +1138,13 @@ def __init__(self, domain, codomain, name=None, latex_name=None): from sage.rings.infinity import Infinity - DifferentiableCurveSet.__init__(self, domain, codomain, - name=name, latex_name=latex_name) + DifferentiableCurveSet.__init__(self, domain, codomain, name=name, latex_name=latex_name) # checking argument 'domain' t_min = domain.lower_bound() t_max = domain.upper_bound() if t_min == -Infinity or t_max == +Infinity: - raise ValueError("both boundaries of the interval " + - "defining the domain of a Homset of " + - "integrated autoparallel curves need to " + - "be finite") + raise ValueError("both boundaries of the interval " + "defining the domain of a Homset of " + "integrated autoparallel curves need to " + "be finite") if name is None: self._name = "Hom_autoparallel" @@ -1170,8 +1153,7 @@ def __init__(self, domain, codomain, name=None, latex_name=None): self._name = name if latex_name is None: self._latex_name = r"\mathrm{{Hom}_{autoparallel}}" - self._latex_name += r"\left({},{}\right)".format( - domain._latex_name, codomain._latex_name) + self._latex_name += r"\left({},{}\right)".format(domain._latex_name, codomain._latex_name) else: self._latex_name = latex_name @@ -1194,15 +1176,12 @@ def _repr_(self): """ description = "Set of Morphisms " - description += "from {} to {} in {} ".format(self._domain, - self._codomain, self.category()) + description += "from {} to {} in {} ".format(self._domain, self._codomain, self.category()) description += "which actually are integrated autoparallel " description += "curves with respect to a certain affine connection" return description - def _element_constructor_(self, affine_connection, curve_parameter, - initial_tangent_vector, chart=None, name=None, - latex_name=None, verbose=False, across_charts=False): + def _element_constructor_(self, affine_connection, curve_parameter, initial_tangent_vector, chart=None, name=None, latex_name=None, verbose=False, across_charts=False): r""" Construct an element of ``self``, i.e. an integrated autoparallel curve `I \to M`, where `I` is a real interval and @@ -1231,9 +1210,7 @@ def _element_constructor_(self, affine_connection, curve_parameter, differentiable manifold M """ # Standard construction - return self.element_class(self, affine_connection, - curve_parameter, initial_tangent_vector, chart=chart, - name=name,latex_name=latex_name, verbose=verbose, across_charts=across_charts) + return self.element_class(self, affine_connection, curve_parameter, initial_tangent_vector, chart=chart, name=name, latex_name=latex_name, verbose=verbose, across_charts=across_charts) def _an_element_(self): r""" @@ -1315,9 +1292,9 @@ def _an_element_(self): dom = self.domain() t = dom.canonical_coordinate() - t_min = dom.lower_bound() # this is either an expression or a + t_min = dom.lower_bound() # this is either an expression or a # finite value thanks to tests in '__init__' - t_max = dom.upper_bound() # idem + t_max = dom.upper_bound() # idem codom = self.codomain() dim = codom.dim() @@ -1348,18 +1325,18 @@ def _an_element_(self): # where a certain integrated autoparallel curve may be defined: H = Hom(dom, codom) c = H.an_element() - x_A = c.expr()[0].substitute({t:1}) - x_B = c.expr()[0].substitute({t:0}) # necessarily, x_A < x_B + x_A = c.expr()[0].substitute({t: 1}) + x_B = c.expr()[0].substitute({t: 0}) # necessarily, x_A < x_B if dim == 1: nab = codom.affine_connection('nab') - nab.set_coef()[i0,i0,i0] = 1 + nab.set_coef()[i0, i0, i0] = 1 # The initial point: p = codom.point([x_A]) # The initial tangent vector: - x_dot_A = (exp(x_B - x_A) - 1)/(t_max - t_min) + x_dot_A = (exp(x_B - x_A) - 1) / (t_max - t_min) v = codom.tangent_space(p)([x_dot_A]) return self.element_class(self, nab, param, v) @@ -1372,7 +1349,7 @@ def _an_element_(self): # else: (i.e. dim >= 2) nab = codom.affine_connection('nab') - nab.set_coef()[i0,i0,i0+1] = 1 + nab.set_coef()[i0, i0, i0 + 1] = 1 y_bounds = chart2._bounds[1] # bounds of second coordinate # Determination of an interval (y_A, y_B) around target_point: @@ -1381,15 +1358,15 @@ def _an_element_(self): one_half = QQ(1) / QQ(2) if y_min == -Infinity: if y_max == Infinity: - y_A = - one_half + y_A = -one_half y_B = one_half else: - y_A = y_max - 3*one_half + y_A = y_max - 3 * one_half y_B = y_max - one_half else: if y_max == Infinity: y_A = y_min + one_half - y_B = y_min + 3*one_half + y_B = y_min + 3 * one_half else: dy = (y_max - y_min) / 4 y_A = y_min + dy @@ -1401,8 +1378,8 @@ def _an_element_(self): # The initial tangent vector: y_dot_A = (y_B - y_A) / (t_max - t_min) - x_dot_A = y_dot_A*(x_B - x_A) / (1-exp(-y_dot_A*(t_max-t_min))) - v_comps = [x_dot_A] + [y_dot_A] + [0 for i in range(dim-2)] + x_dot_A = y_dot_A * (x_B - x_A) / (1 - exp(-y_dot_A * (t_max - t_min))) + v_comps = [x_dot_A] + [y_dot_A] + [0 for i in range(dim - 2)] v = codom.tangent_space(p)(v_comps) return self.element_class(self, nab, param, v) @@ -1418,7 +1395,8 @@ def _an_element_(self): # y(t_min) = y_A and y(t_max) = y_B due to y_dot_A set to the # value above -#****************************************************************************** + +# ****************************************************************************** class IntegratedGeodesicSet(IntegratedAutoparallelCurveSet): @@ -1599,16 +1577,13 @@ def __init__(self, domain, codomain, name=None, latex_name=None): from sage.rings.infinity import Infinity - DifferentiableCurveSet.__init__(self, domain, codomain, - name=name, latex_name=latex_name) + DifferentiableCurveSet.__init__(self, domain, codomain, name=name, latex_name=latex_name) # checking argument 'domain' t_min = domain.lower_bound() t_max = domain.upper_bound() if t_min == -Infinity or t_max == +Infinity: - raise ValueError("both boundaries of the interval " + - "defining the domain of a Homset of " + - "integrated geodesics need to be finite") + raise ValueError("both boundaries of the interval " + "defining the domain of a Homset of " + "integrated geodesics need to be finite") if name is None: self._name = "Hom_geodesic" @@ -1617,8 +1592,7 @@ def __init__(self, domain, codomain, name=None, latex_name=None): self._name = name if latex_name is None: self._latex_name = r"\mathrm{{Hom}_{geodesic}}" - self._latex_name += r"\left({},{}\right)".format( - domain._latex_name, codomain._latex_name) + self._latex_name += r"\left({},{}\right)".format(domain._latex_name, codomain._latex_name) else: self._latex_name = latex_name @@ -1640,15 +1614,12 @@ def _repr_(self): certain metric """ description = "Set of Morphisms " - description += "from {} to {} in {} ".format(self._domain, - self._codomain, self.category()) + description += "from {} to {} in {} ".format(self._domain, self._codomain, self.category()) description += "which actually are integrated geodesics " description += "with respect to a certain metric" return description - def _element_constructor_(self, metric, curve_parameter, - initial_tangent_vector, chart=None, name=None, - latex_name=None, verbose=False, across_charts=False): + def _element_constructor_(self, metric, curve_parameter, initial_tangent_vector, chart=None, name=None, latex_name=None, verbose=False, across_charts=False): r""" Construct an element of ``self``, i.e. an integrated geodesic `I \to M`, where `I` is a real interval and @@ -1675,9 +1646,7 @@ def _element_constructor_(self, metric, curve_parameter, manifold M """ # Standard construction - return self.element_class(self, metric, curve_parameter, - initial_tangent_vector, chart=chart, name=name, - latex_name=latex_name, verbose=verbose, across_charts=across_charts) + return self.element_class(self, metric, curve_parameter, initial_tangent_vector, chart=chart, name=name, latex_name=latex_name, verbose=verbose, across_charts=across_charts) def _an_element_(self): r""" @@ -1761,9 +1730,9 @@ def _an_element_(self): dom = self.domain() t = dom.canonical_coordinate() - t_min = dom.lower_bound() # this is either an expression or a + t_min = dom.lower_bound() # this is either an expression or a # finite value thanks to tests in '__init__' - t_max = dom.upper_bound() # idem + t_max = dom.upper_bound() # idem codom = self.codomain() dim = codom.dim() @@ -1795,22 +1764,22 @@ def _an_element_(self): # where a certain integrated autoparallel curve may be defined: H = Hom(dom, codom) c = H.an_element() - x_A = c.expr()[0].substitute({t:1}) - x_B = c.expr()[0].substitute({t:0}) # necessarily, x_A < x_B + x_A = c.expr()[0].substitute({t: 1}) + x_B = c.expr()[0].substitute({t: 0}) # necessarily, x_A < x_B g = codom.metric('g') - g[i0,i0] = exp(2*x) + g[i0, i0] = exp(2 * x) if dim > 1: - for i in range(1,dim): - g[i0+i,i0+i] = 1 + for i in range(1, dim): + g[i0 + i, i0 + i] = 1 # The initial point: p_coords = [x_A] + list(c.expr()[1:dim]) p = codom.point(p_coords) # The initial tangent vector: - x_dot_A = (exp(x_B - x_A) - 1)/(t_max - t_min) - v_comps = [x_dot_A] + [0 for i in range(dim-1)] + x_dot_A = (exp(x_B - x_A) - 1) / (t_max - t_min) + v_comps = [x_dot_A] + [0 for i in range(dim - 1)] v = codom.tangent_space(p)(v_comps) return self.element_class(self, g, param, v) diff --git a/src/sage/manifolds/differentiable/metric.py b/src/sage/manifolds/differentiable/metric.py index 01b48ef9724..9df60cd26dc 100644 --- a/src/sage/manifolds/differentiable/metric.py +++ b/src/sage/manifolds/differentiable/metric.py @@ -28,6 +28,7 @@ - [DB1996]_ - [DS2010]_ """ + # ***************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger @@ -334,11 +335,10 @@ class PseudoRiemannianMetric(TensorField): sage: riem == - r*(g*delta).antisymmetrize(2,3) True """ - _derived_objects = ('_connection', '_ricci_scalar', '_weyl', - '_schouten', '_cotton', '_cotton_york') - def __init__(self, vector_field_module, name, signature=None, - latex_name=None): + _derived_objects = ('_connection', '_ricci_scalar', '_weyl', '_schouten', '_cotton', '_cotton_york') + + def __init__(self, vector_field_module, name, signature=None, latex_name=None): r""" Construct a metric. @@ -370,8 +370,7 @@ def __init__(self, vector_field_module, name, signature=None, - add a specific parent to the metrics, to fit with the category framework """ - TensorField.__init__(self, vector_field_module, (0,2), - name=name, latex_name=latex_name, sym=(0,1)) + TensorField.__init__(self, vector_field_module, (0, 2), name=name, latex_name=latex_name, sym=(0, 1)) # signature: ndim = self._ambient_domain.dimension() if signature is None: @@ -379,17 +378,17 @@ def __init__(self, vector_field_module, name, signature=None, else: if not isinstance(signature, (int, Integer)): raise TypeError("the metric signature must be an integer") - if (signature < - ndim) or (signature > ndim): + if (signature < -ndim) or (signature > ndim): raise ValueError("metric signature out of range") - if (signature+ndim) % 2 == 1: + if (signature + ndim) % 2 == 1: if ndim % 2 == 0: raise ValueError("the metric signature must be even") else: raise ValueError("the metric signature must be odd") self._signature = signature # the pair (n_+, n_-): - self._signature_pm = ((ndim+signature)//2, (ndim-signature)//2) - self._indic_signat = 1 - 2*(self._signature_pm[1] % 2) # (-1)^n_- + self._signature_pm = ((ndim + signature) // 2, (ndim - signature) // 2) + self._indic_signat = 1 - 2 * (self._signature_pm[1] % 2) # (-1)^n_- # Initialization of derived quantities: PseudoRiemannianMetric._init_derived(self) @@ -414,7 +413,7 @@ def _repr_(self): s = self._signature if s == n: description = "Riemannian metric " - elif s == n-2 or s == 2-n: + elif s == n - 2 or s == 2 - n: description = "Lorentzian metric " else: description = "Pseudo-Riemannian metric " @@ -440,9 +439,7 @@ def _new_instance(self): sage: g1.signature() == g.signature() True """ - return type(self)(self._vmodule, 'unnamed metric', - signature=self._signature, - latex_name=r'\text{unnamed metric}') + return type(self)(self._vmodule, 'unnamed metric', signature=self._signature, latex_name=r'\text{unnamed metric}') def _init_derived(self): r""" @@ -459,14 +456,12 @@ def _init_derived(self): # inverse metric: inv_name = 'inv_' + self._name inv_latex_name = self._latex_name + r'^{-1}' - self._inverse = self._vmodule.tensor((2,0), name=inv_name, - latex_name=inv_latex_name, - sym=(0,1)) + self._inverse = self._vmodule.tensor((2, 0), name=inv_name, latex_name=inv_latex_name, sym=(0, 1)) for attr in self._derived_objects: self.__setattr__(attr, None) - self._determinants = {} # determinants in various frames - self._sqrt_abs_dets = {} # sqrt(abs(det g)) in various frames - self._vol_forms = [] # volume form and associated tensors + self._determinants = {} # determinants in various frames + self._sqrt_abs_dets = {} # sqrt(abs(det g)) in various frames + self._vol_forms = [] # volume form and associated tensors def _del_derived(self): r""" @@ -634,13 +629,12 @@ def set(self, symbiform): """ if not isinstance(symbiform, TensorField): raise TypeError("the argument must be a tensor field") - if symbiform._tensor_type != (0,2): + if symbiform._tensor_type != (0, 2): raise TypeError("the argument must be of tensor type (0,2)") - if symbiform._sym != ((0,1),): + if symbiform._sym != ((0, 1),): raise TypeError("the argument must be symmetric") if not symbiform._domain.is_subset(self._domain): - raise TypeError("the symmetric bilinear form is not defined " + - "on the metric domain") + raise TypeError("the symmetric bilinear form is not defined " + "on the metric domain") self._del_derived() self._restrictions.clear() if isinstance(symbiform, TensorFieldParal): @@ -712,10 +706,8 @@ def inverse(self, expansion_symbol=None, order=1): """ # Is the inverse metric up to date? for dom, rst in self._restrictions.items(): - self._inverse._restrictions[dom] = rst.inverse( - expansion_symbol=expansion_symbol, - order=order) # forces the update - # of the restriction + self._inverse._restrictions[dom] = rst.inverse(expansion_symbol=expansion_symbol, order=order) # forces the update + # of the restriction return self._inverse def connection(self, name=None, latex_name=None, init_coef=True): @@ -787,6 +779,7 @@ def connection(self, name=None, latex_name=None, init_coef=True): from sage.manifolds.differentiable.levi_civita_connection import ( LeviCivitaConnection, ) + if self._connection is None: if latex_name is None: if name is None: @@ -795,9 +788,7 @@ def connection(self, name=None, latex_name=None, init_coef=True): latex_name = name if name is None: name = 'nabla_' + self._name - self._connection = LeviCivitaConnection(self, name, - latex_name=latex_name, - init_coef=init_coef) + self._connection = LeviCivitaConnection(self, name, latex_name=latex_name, init_coef=init_coef) return self._connection def christoffel_symbols(self, chart=None): @@ -864,10 +855,7 @@ def christoffel_symbols(self, chart=None): frame = chart._frame return self.connection().coef(frame) - def christoffel_symbols_display(self, chart=None, symbol=None, - latex_symbol=None, index_labels=None, index_latex_labels=None, - coordinate_labels=True, only_nonzero=True, - only_nonredundant=True): + def christoffel_symbols_display(self, chart=None, symbol=None, latex_symbol=None, index_labels=None, index_latex_labels=None, coordinate_labels=True, only_nonzero=True, only_nonredundant=True): r""" Display the Christoffel symbols w.r.t. to a given chart, one per line. @@ -969,11 +957,7 @@ def christoffel_symbols_display(self, chart=None, symbol=None, """ if chart is None: chart = self._domain.default_chart() - return self.connection().display(frame=chart.frame(), chart=chart, - symbol=symbol, latex_symbol=latex_symbol, - index_labels=index_labels, index_latex_labels=index_latex_labels, - coordinate_labels=coordinate_labels, only_nonzero=only_nonzero, - only_nonredundant=only_nonredundant) + return self.connection().display(frame=chart.frame(), chart=chart, symbol=symbol, latex_symbol=latex_symbol, index_labels=index_labels, index_latex_labels=index_latex_labels, coordinate_labels=coordinate_labels, only_nonzero=only_nonzero, only_nonredundant=only_nonredundant) def riemann(self, name=None, latex_name=None): r""" @@ -1153,8 +1137,7 @@ def ricci_scalar(self, name=None, latex_name=None): if name is None: name = "r(" + self._name + ")" if latex_name is None: - latex_name = r"\mathrm{r}\left(" + self._latex_name + \ - r"\right)" + latex_name = r"\mathrm{r}\left(" + self._latex_name + r"\right)" resu._name = name resu._latex_name = latex_name self._ricci_scalar = resu @@ -1204,16 +1187,15 @@ def weyl(self, name=None, latex_name=None): if self._weyl is None: n = self._ambient_domain.dimension() if n < 3: - raise ValueError("the Weyl tensor is not defined for a " + - "manifold of dimension n <= 2") + raise ValueError("the Weyl tensor is not defined for a " + "manifold of dimension n <= 2") delta = self._domain.tangent_identity_field(dest_map=self._vmodule._dest_map) riem = self.riemann() ric = self.ricci() rscal = self.ricci_scalar() # First index of the Ricci tensor raised with the metric ricup = ric.up(self, 0) - aux = self*ricup + ric*delta - rscal/(n-1) * self*delta - self._weyl = riem + 2/(n-2) * aux.antisymmetrize(2,3) + aux = self * ricup + ric * delta - rscal / (n - 1) * self * delta + self._weyl = riem + 2 / (n - 2) * aux.antisymmetrize(2, 3) if name is None: name = "C(" + self._name + ")" if latex_name is None: @@ -1270,10 +1252,9 @@ def schouten(self, name=None, latex_name=None): """ n = self._ambient_domain.dimension() if n < 3: - raise ValueError("the Schouten tensor is only defined for a " + - "manifold of dimension >= 3") + raise ValueError("the Schouten tensor is only defined for a " + "manifold of dimension >= 3") if self._schouten is None: - s = (1/(n-2))*self.ricci() - (self.ricci_scalar()/(2*(n-1)*(n-2)))*self + s = (1 / (n - 2)) * self.ricci() - (self.ricci_scalar() / (2 * (n - 1) * (n - 2))) * self name = name or 'Schouten(' + self._name + ')' latex_name = latex_name or r'\mathrm{Schouten}(' + self._latex_name + ')' s.set_name(name=name, latex_name=latex_name) @@ -1327,12 +1308,11 @@ def cotton(self, name=None, latex_name=None): """ n = self._ambient_domain.dimension() if n < 3: - raise ValueError("the Cotton tensor is only defined for a " + - "manifold of dimension >= 3") + raise ValueError("the Cotton tensor is only defined for a " + "manifold of dimension >= 3") if self._cotton is None: nabla = self.connection() s = self.schouten() - cot = 2*(n-2)*nabla(s).antisymmetrize(1,2) + cot = 2 * (n - 2) * nabla(s).antisymmetrize(1, 2) name = name or 'Cot(' + self._name + ')' latex_name = latex_name or r'\mathrm{Cot}(' + self._latex_name + ')' cot.set_name(name=name, latex_name=latex_name) @@ -1386,12 +1366,11 @@ def cotton_york(self, name=None, latex_name=None): """ n = self._ambient_domain.dimension() if n != 3: - raise ValueError("the Cotton-York tensor is only defined for a " + - "manifold of dimension 3") + raise ValueError("the Cotton-York tensor is only defined for a " + "manifold of dimension 3") if self._cotton_york is None: cot = self.cotton() eps = self.volume_form(2) - cy = eps.contract(0, 1, cot, 2, 1)/2 + cy = eps.contract(0, 1, cot, 2, 1) / 2 name = name or 'CY(' + self._name + ')' latex_name = latex_name or r'\mathrm{CY}(' + self._latex_name + ')' cy.set_name(name=name, latex_name=latex_name) @@ -1476,6 +1455,7 @@ def determinant(self, frame=None): -x**2*y**2 + x - y*(x + 1) + 1 """ from sage.matrix.constructor import matrix + dom = self._domain if frame is None: frame = dom._def_frame @@ -1491,8 +1471,7 @@ def determinant(self, frame=None): i1 = manif.start_index() for chart in gg[[i1, i1]]._express: # TODO: do the computation without the 'SR' enforcement - gm = matrix( [[ gg[i, j, chart].expr(method='SR') - for j in manif.irange()] for i in manif.irange()] ) + gm = matrix([[gg[i, j, chart].expr(method='SR') for j in manif.irange()] for i in manif.irange()]) detgm = chart.simplify(gm.det(), method='SR') resu.add_expr(detgm, chart=chart) self._determinants[frame] = resu @@ -1758,25 +1737,23 @@ def volume_form(self, contra=0): if not orient: raise ValueError('{} must admit an orientation'.format(dom)) if contra > ndim: - raise ValueError('The number of contravariant indices is greater ' - 'than the manifold dimension') + raise ValueError('The number of contravariant indices is greater ' 'than the manifold dimension') if self._vol_forms == []: # a new computation is necessary # The result is constructed on the vector field module, # so that dest_map is taken automatically into account: - eps = self._vmodule.alternating_form(ndim, name='eps_'+self._name, - latex_name=r'\epsilon_{'+self._latex_name+r'}') + eps = self._vmodule.alternating_form(ndim, name='eps_' + self._name, latex_name=r'\epsilon_{' + self._latex_name + r'}') si = manif.start_index() - ind = tuple(range(si, si+ndim)) + ind = tuple(range(si, si + ndim)) for frame in orient: if frame.destination_map() is frame.domain().identity_map(): eps.add_comp(frame)[[ind]] = self.sqrt_abs_det(frame) self._vol_forms.append(eps) # Levi-Civita tensor constructed if contra >= len(self._vol_forms): # Tensors related to the Levi-Civita one by index rising: - for k in range(len(self._vol_forms), contra+1): - epskm1 = self._vol_forms[k-1] - epsk = epskm1.up(self, k-1) + for k in range(len(self._vol_forms), contra + 1): + epskm1 = self._vol_forms[k - 1] + epsk = epskm1.up(self, k - 1) if k > 1: # restoring the antisymmetry after the up operation: epsk = epsk.antisymmetrize(*range(k)) @@ -1953,7 +1930,8 @@ def hodge_star(self, pform: DiffForm) -> DiffForm: return pform.hodge_dual(self) -#****************************************************************************** +# ****************************************************************************** + class PseudoRiemannianMetricParal(PseudoRiemannianMetric, TensorFieldParal): r""" @@ -2075,8 +2053,8 @@ class PseudoRiemannianMetricParal(PseudoRiemannianMetric, TensorFieldParal): + x*y/(x^2*y^2 + x^2 - 1) ∂/∂x⊗∂/∂y + x*y/(x^2*y^2 + x^2 - 1) ∂/∂y⊗∂/∂x - (x + 1)/(x^2*y^2 + x^2 - 1) ∂/∂y⊗∂/∂y """ - def __init__(self, vector_field_module, name, signature=None, - latex_name=None): + + def __init__(self, vector_field_module, name, signature=None, latex_name=None): r""" Construct a metric on a parallelizable manifold. @@ -2097,8 +2075,7 @@ def __init__(self, vector_field_module, name, signature=None, - add a specific parent to the metrics, to fit with the category framework """ - TensorFieldParal.__init__(self, vector_field_module, (0,2), - name=name, latex_name=latex_name, sym=(0,1)) + TensorFieldParal.__init__(self, vector_field_module, (0, 2), name=name, latex_name=latex_name, sym=(0, 1)) # signature: ndim = self._ambient_domain.dimension() if signature is None: @@ -2106,17 +2083,17 @@ def __init__(self, vector_field_module, name, signature=None, else: if not isinstance(signature, (int, Integer)): raise TypeError("the metric signature must be an integer") - if (signature < - ndim) or (signature > ndim): + if (signature < -ndim) or (signature > ndim): raise ValueError("metric signature out of range") - if (signature+ndim) % 2 == 1: + if (signature + ndim) % 2 == 1: if ndim % 2 == 0: raise ValueError("the metric signature must be even") else: raise ValueError("the metric signature must be odd") self._signature = signature # the pair (n_+, n_-): - self._signature_pm = ((ndim+signature)//2, (ndim-signature)//2) - self._indic_signat = 1 - 2*(self._signature_pm[1] % 2) # (-1)^n_- + self._signature_pm = ((ndim + signature) // 2, (ndim - signature) // 2) + self._indic_signat = 1 - 2 * (self._signature_pm[1] % 2) # (-1)^n_- # Initialization of derived quantities: PseudoRiemannianMetricParal._init_derived(self) @@ -2260,15 +2237,13 @@ def set(self, symbiform): g = (x^2 + 1) dx⊗dx + x*y dx⊗dy + x*y dy⊗dx + (y^2 + 1) dy⊗dy """ if not isinstance(symbiform, TensorFieldParal): - raise TypeError("the argument must be a tensor field with " + - "values on a parallelizable domain") - if symbiform._tensor_type != (0,2): + raise TypeError("the argument must be a tensor field with " + "values on a parallelizable domain") + if symbiform._tensor_type != (0, 2): raise TypeError("the argument must be of tensor type (0,2)") - if symbiform._sym != ((0,1),): + if symbiform._sym != ((0, 1),): raise TypeError("the argument must be symmetric") if symbiform._vmodule is not self._vmodule: - raise TypeError("the symmetric bilinear form and the metric are " + - "not defined on the same vector field module") + raise TypeError("the symmetric bilinear form and the metric are " + "not defined on the same vector field module") self._del_derived() self._components.clear() for frame in symbiform._components: @@ -2379,10 +2354,7 @@ def inverse(self, expansion_symbol=None, order=1): [ 0 0 -e 1] """ if expansion_symbol is not None: - if (self._inverse is not None and bool(self._inverse._components) - and self._inverse._components.values()[0][0,0]._expansion_symbol - == expansion_symbol - and self._inverse._components.values()[0][0,0]._order == order): + if self._inverse is not None and bool(self._inverse._components) and self._inverse._components.values()[0][0, 0]._expansion_symbol == expansion_symbol and self._inverse._components.values()[0][0, 0]._order == order: return self._inverse if order != 1: @@ -2391,8 +2363,8 @@ def inverse(self, expansion_symbol=None, order=1): g0 = decompo[0] g1 = decompo[1] - g0m = self._new_instance() # needed because only metrics have - g0m.set_comp()[:] = g0[:] # an "inverse" method. + g0m = self._new_instance() # needed because only metrics have + g0m.set_comp()[:] = g0[:] # an "inverse" method. contraction = g1.contract(0, g0m.inverse(), 0) contraction = contraction.contract(1, g0m.inverse(), 1) @@ -2402,6 +2374,7 @@ def inverse(self, expansion_symbol=None, order=1): from sage.matrix.constructor import matrix from sage.tensor.modules.comp import CompFullySym + # Is the inverse metric up to date ? for frame in self._components: if frame not in self._inverse._components: @@ -2410,29 +2383,26 @@ def inverse(self, expansion_symbol=None, order=1): si = fmodule._sindex nsi = fmodule._rank + si dom = self._domain - cinv = CompFullySym(fmodule._ring, frame, 2, start_index=si, - output_formatter=fmodule._output_formatter) + cinv = CompFullySym(fmodule._ring, frame, 2, start_index=si, output_formatter=fmodule._output_formatter) cinv_scal = {} # dict. of scalars representing the components - # of the inverse (keys: comp. indices) + # of the inverse (keys: comp. indices) for i in range(si, nsi): - for j in range(i, nsi): # symmetry taken into account - cinv_scal[(i,j)] = dom.scalar_field() + for j in range(i, nsi): # symmetry taken into account + cinv_scal[(i, j)] = dom.scalar_field() for chart in dom.top_charts(): # TODO: do the computation without the 'SR' enforcement try: - gmat = matrix( - [[self.comp(frame)[i, j, chart].expr(method='SR') - for j in range(si, nsi)] for i in range(si, nsi)]) + gmat = matrix([[self.comp(frame)[i, j, chart].expr(method='SR') for j in range(si, nsi)] for i in range(si, nsi)]) gmat_inv = gmat.inverse() except (KeyError, ValueError): continue for i in range(si, nsi): for j in range(i, nsi): - val = chart.simplify(gmat_inv[i-si,j-si], method='SR') - cinv_scal[(i,j)].add_expr(val, chart=chart) + val = chart.simplify(gmat_inv[i - si, j - si], method='SR') + cinv_scal[(i, j)].add_expr(val, chart=chart) for i in range(si, nsi): for j in range(i, nsi): - cinv[i,j] = cinv_scal[(i,j)] + cinv[i, j] = cinv_scal[(i, j)] self._inverse._components[frame] = cinv return self._inverse @@ -2489,25 +2459,24 @@ def ricci_scalar(self, name=None, latex_name=None): cig = ig._components[frame] rsum1 = 0 for i in manif.irange(): - rsum1 += cig[[i,i]] * cric[[i,i]] + rsum1 += cig[[i, i]] * cric[[i, i]] rsum2 = 0 for i in manif.irange(): - for j in manif.irange(start=i+1): - rsum2 += cig[[i,j]] * cric[[i,j]] - self._ricci_scalar = rsum1 + 2*rsum2 + for j in manif.irange(start=i + 1): + rsum2 += cig[[i, j]] * cric[[i, j]] + self._ricci_scalar = rsum1 + 2 * rsum2 if name is None: self._ricci_scalar._name = "r(" + self._name + ")" else: self._ricci_scalar._name = name if latex_name is None: - self._ricci_scalar._latex_name = r"\mathrm{r}\left(" + \ - self._latex_name + r"\right)" + self._ricci_scalar._latex_name = r"\mathrm{r}\left(" + self._latex_name + r"\right)" else: self._ricci_scalar._latex_name = latex_name return self._ricci_scalar -#**************************************************************************************************** +# **************************************************************************************************** class DegenerateMetric(TensorField): @@ -2587,8 +2556,7 @@ class DegenerateMetric(TensorField): (x, y, z) ↦ 0 """ - def __init__(self, vector_field_module, name, signature=None, - latex_name=None): + def __init__(self, vector_field_module, name, signature=None, latex_name=None): r""" Construct a metric. @@ -2610,25 +2578,24 @@ def __init__(self, vector_field_module, name, signature=None, g = (2*m/r - 1) dt⊗dt + 2*m/r dt⊗dr + 2*m/r dr⊗dt + (2*m/r + 1) dr⊗dr + r^2 dth⊗dth + r^2*sin(th)^2 dph⊗dph """ - TensorField.__init__(self, vector_field_module, (0,2), - name=name, latex_name=latex_name, sym=(0,1)) + TensorField.__init__(self, vector_field_module, (0, 2), name=name, latex_name=latex_name, sym=(0, 1)) # signature: ndim = self._ambient_domain.dimension() if signature is None: - signature = (ndim-1,0,1) + signature = (ndim - 1, 0, 1) else: try: for elt in signature: if (elt < 0) or (not isinstance(elt, (int, Integer))): raise ValueError("{} must be a positive integer".format(elt)) if elt > ndim: - raise ValueError("{} must be less than {}".format(elt,ndim)) - sign = signature[0]+signature[1]+signature[2] + raise ValueError("{} must be less than {}".format(elt, ndim)) + sign = signature[0] + signature[1] + signature[2] if sign != ndim: raise ValueError("{} is different from {}".format(sign, ndim)) except TypeError: raise TypeError("signature must be an iterable") - self._signature = (signature[0],signature[1],signature[2]) + self._signature = (signature[0], signature[1], signature[2]) # the tuple (n_+, n_-, n_0): self._signature_pm = self._signature @@ -2643,7 +2610,7 @@ def _repr_(self): sage: g._repr_() 'degenerate metric g on the 3-dimensional differentiable manifold M' """ - return self._final_repr("degenerate metric "+self._name + " ") + return self._final_repr("degenerate metric " + self._name + " ") def _new_instance(self): r""" @@ -2663,9 +2630,7 @@ def _new_instance(self): sage: g1.signature() == g.signature() True """ - return type(self)(self._vmodule, 'unnamed metric', - signature=self._signature, - latex_name=r'\text{unnamed metric}') + return type(self)(self._vmodule, 'unnamed metric', signature=self._signature, latex_name=r'\text{unnamed metric}') def signature(self): r""" @@ -2734,13 +2699,12 @@ def set(self, symbiform): """ if not isinstance(symbiform, TensorField): raise TypeError("the argument must be a tensor field") - if symbiform._tensor_type != (0,2): + if symbiform._tensor_type != (0, 2): raise TypeError("the argument must be of tensor type (0,2)") - if symbiform._sym != ((0,1),): + if symbiform._sym != ((0, 1),): raise TypeError("the argument must be symmetric") if not symbiform._domain.is_subset(self._domain): - raise TypeError("the symmetric bilinear form is not defined " + - "on the metric domain") + raise TypeError("the symmetric bilinear form is not defined " + "on the metric domain") self._restrictions.clear() if isinstance(symbiform, TensorFieldParal): rst = self.restrict(symbiform._domain) @@ -2814,7 +2778,8 @@ def determinant(self): det = determinant -#**************************************************************************************** + +# **************************************************************************************** class DegenerateMetricParal(DegenerateMetric, TensorFieldParal): @@ -2894,8 +2859,7 @@ class DegenerateMetricParal(DegenerateMetric, TensorFieldParal): (x, y, z) ↦ 0 """ - def __init__(self, vector_field_module, name, signature=None, - latex_name=None): + def __init__(self, vector_field_module, name, signature=None, latex_name=None): r""" Construct a metric. @@ -2918,23 +2882,22 @@ def __init__(self, vector_field_module, name, signature=None, - x*z/(x^2 + y^2 + z^2) dz⊗dx - y*z/(x^2 + y^2 + z^2) dz⊗dy + (x^2 + y^2)/(x^2 + y^2 + z^2) dz⊗dz """ - TensorFieldParal.__init__(self, vector_field_module, (0,2), - name=name, latex_name=latex_name, sym=(0,1)) + TensorFieldParal.__init__(self, vector_field_module, (0, 2), name=name, latex_name=latex_name, sym=(0, 1)) # signature: ndim = self._ambient_domain.dimension() if signature is None: - signature = (ndim-1,0,1) + signature = (ndim - 1, 0, 1) else: try: for elt in signature: if (elt < 0) or (not isinstance(elt, (int, Integer))): raise ValueError("{} must be a positive integer".format(elt)) - sign = signature[0]+signature[1]+signature[2] + sign = signature[0] + signature[1] + signature[2] if sign != ndim: raise ValueError("{} is different from {}".format(sign, ndim)) except TypeError: raise TypeError("signature must be an iterable") - self._signature = (signature[0],signature[1],signature[2]) + self._signature = (signature[0], signature[1], signature[2]) # the tuple (n_+, n_-, n_0): self._signature_pm = self._signature @@ -2964,15 +2927,13 @@ def set(self, symbiform): g = dx⊗dx + dy⊗dy """ if not isinstance(symbiform, TensorFieldParal): - raise TypeError("the argument must be a tensor field with " + - "values on a parallelizable domain") - if symbiform._tensor_type != (0,2): + raise TypeError("the argument must be a tensor field with " + "values on a parallelizable domain") + if symbiform._tensor_type != (0, 2): raise TypeError("the argument must be of tensor type (0,2)") - if symbiform._sym != ((0,1),): + if symbiform._sym != ((0, 1),): raise TypeError("the argument must be symmetric") if symbiform._vmodule is not self._vmodule: - raise TypeError("the symmetric bilinear form and the metric are " + - "not defined on the same vector field module") + raise TypeError("the symmetric bilinear form and the metric are " + "not defined on the same vector field module") self._components.clear() for frame in symbiform._components: self._components[frame] = symbiform._components[frame].copy() @@ -3028,4 +2989,5 @@ def restrict(self, subdomain, dest_map=None): self._restrictions[subdomain] = resu return self._restrictions[subdomain] -#**************************************************************************************** + +# **************************************************************************************** diff --git a/src/sage/manifolds/differentiable/mixed_form.py b/src/sage/manifolds/differentiable/mixed_form.py index 7fb2d53ded2..ac4a1450066 100644 --- a/src/sage/manifolds/differentiable/mixed_form.py +++ b/src/sage/manifolds/differentiable/mixed_form.py @@ -13,6 +13,7 @@ - Michael Jung (2019) : initial version """ + # ***************************************************************************** # Copyright (C) 2019 Michael Jung # @@ -212,6 +213,7 @@ class MixedForm(AlgebraElement, ModuleElementWithMutability): ... ValueError: the components of an immutable element cannot be changed """ + def __init__(self, parent, name=None, latex_name=None): r""" Construct a mixed form. @@ -284,8 +286,7 @@ def _init_comp(self): if self._latex_name is not None: comp_latex_name = '{' + self._latex_name + '}_{' + str(i) + '}' diff_form = self._domain.diff_form - self._comp.append(diff_form(i, name=comp_name, - latex_name=comp_latex_name)) + self._comp.append(diff_form(i, name=comp_name, latex_name=comp_latex_name)) def _repr_(self): r""" @@ -414,6 +415,7 @@ def display_expansion(self, frame=None, chart=None, from_chart=None): from sage.misc.latex import latex from sage.tensor.modules.format_utilities import FormattedExpansion, is_atomic from sage.typeset.unicode_characters import unicode_wedge + # In case, no frame is given: if frame is None: frame = self._domain._def_frame @@ -439,8 +441,7 @@ def display_expansion(self, frame=None, chart=None, from_chart=None): # Differential form terms: for j in self.irange(1): rst = self[j].restrict(frame._domain, dest_map=frame._dest_map) - basis, format_spec = rst._preparse_display(basis=frame, - format_spec=chart) + basis, format_spec = rst._preparse_display(basis=frame, format_spec=chart) cobasis = basis.dual_basis() comp = rst.comp(basis) for ind in comp.non_redundant_index_generator(): @@ -472,13 +473,11 @@ def display_expansion(self, frame=None, chart=None, from_chart=None): if is_atomic(coef_txt): terms_txt.append(coef_txt + " " + basis_term_txt) else: - terms_txt.append("(" + coef_txt + ") " + - basis_term_txt) + terms_txt.append("(" + coef_txt + ") " + basis_term_txt) if is_atomic(coef_latex): terms_latex.append(coef_latex + basis_term_latex) else: - terms_latex.append(r"\left(" + coef_latex + - r"\right)" + basis_term_latex) + terms_latex.append(r"\left(" + coef_latex + r"\right)" + basis_term_latex) if not terms_txt: resu_txt += "0" else: @@ -523,6 +522,7 @@ def display(self): """ from sage.misc.latex import latex from sage.tensor.modules.format_utilities import FormattedExpansion + # Mixed form name: if self._name is not None: resu_txt = self._name + " = " @@ -605,8 +605,7 @@ def set_name(self, name=None, latex_name=None, apply_to_comp=True): eta = g + F_1 + F_2 + F_3 + F_4 """ if self.is_immutable(): - raise ValueError("the name of an immutable element " - "cannot be changed") + raise ValueError("the name of an immutable element " "cannot be changed") if name is not None: self._name = name if latex_name is None: @@ -710,6 +709,7 @@ def _richcmp_(self, other, op): True """ from sage.structure.richcmp import op_EQ, op_NE + if op == op_NE: return not self == other if op == op_EQ: @@ -974,17 +974,16 @@ def wedge(self, other): return self # Generic case: resu = self._new_instance() - resu._comp = [sum(self[k].wedge(other[j - k]) for k in range(j + 1)) - for j in self.irange()] + resu._comp = [sum(self[k].wedge(other[j - k]) for k in range(j + 1)) for j in self.irange()] # Compose name: from sage.tensor.modules.format_utilities import ( format_mul_latex, format_mul_txt, ) from sage.typeset.unicode_characters import unicode_wedge + resu._name = format_mul_txt(self._name, unicode_wedge, other._name) - resu._latex_name = format_mul_latex(self._latex_name, r'\wedge ', - other._latex_name) + resu._latex_name = format_mul_latex(self._latex_name, r'\wedge ', other._latex_name) return resu _mul_ = wedge @@ -1037,9 +1036,9 @@ def _lmul_(self, other): format_mul_txt, ) from sage.typeset.unicode_characters import unicode_wedge + resu._name = format_mul_txt(repr(other), unicode_wedge, self._name) - resu._latex_name = format_mul_latex(latex(other), r'\wedge ', - self._latex_name) + resu._latex_name = format_mul_latex(latex(other), r'\wedge ', self._latex_name) return resu @cached_method @@ -1099,13 +1098,13 @@ def exterior_derivative(self): """ resu = self._new_instance() resu[0] = self._domain.zero_scalar_field() - resu[1:] = [self[j].exterior_derivative() - for j in range(self._max_deg)] + resu[1:] = [self[j].exterior_derivative() for j in range(self._max_deg)] # Compose name: from sage.tensor.modules.format_utilities import ( format_unop_latex, format_unop_txt, ) + resu._name = format_unop_txt('d', self._name) resu._latex_name = format_unop_latex(r'\mathrm{d}', self._latex_name) return resu @@ -1200,8 +1199,7 @@ def __setitem__(self, index, values): A = x + y dx + x*y dx∧dy """ if self.is_immutable(): - raise ValueError("the components of an immutable element " - "cannot be changed") + raise ValueError("the components of an immutable element " "cannot be changed") if isinstance(index, (int, Integer)): start, stop, step = index, index + 1, 1 elif isinstance(index, slice): @@ -1307,8 +1305,7 @@ def set_restriction(self, rst): if not isinstance(rst, MixedForm): raise TypeError("the argument must be a mixed form") if not rst._domain.is_subset(self._domain): - raise ValueError("the specified domain is not a subset of " - "the domain of definition of the mixed form") + raise ValueError("the specified domain is not a subset of " "the domain of definition of the mixed form") for j in self.irange(): self[j].set_restriction(rst[j]) self._is_zero = False # a priori @@ -1376,11 +1373,9 @@ def restrict(self, subdomain, dest_map=None): sage: FV.display_expansion(e_uv) F = u^2/(u^4 + 2*u^2*v^2 + v^4) - (u^2*v^2 - v^4)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) du - 2*u*v^3/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) dv - u^2*v^2/(u^12 + 6*u^10*v^2 + 15*u^8*v^4 + 20*u^6*v^6 + 15*u^4*v^8 + 6*u^2*v^10 + v^12) du∧dv """ - resu = type(self)(subdomain.mixed_form_algebra(dest_map=dest_map), - name=self._name, latex_name=self._latex_name) + resu = type(self)(subdomain.mixed_form_algebra(dest_map=dest_map), name=self._name, latex_name=self._latex_name) resu[0] = self[0].restrict(subdomain) - resu[1:] = [self[j].restrict(subdomain, dest_map) - for j in self.irange(1)] + resu[1:] = [self[j].restrict(subdomain, dest_map) for j in self.irange(1)] return resu def add_comp_by_continuation(self, frame, subdomain, chart=None): diff --git a/src/sage/manifolds/differentiable/mixed_form_algebra.py b/src/sage/manifolds/differentiable/mixed_form_algebra.py index 65e1e29582a..bdb2c1262b4 100644 --- a/src/sage/manifolds/differentiable/mixed_form_algebra.py +++ b/src/sage/manifolds/differentiable/mixed_form_algebra.py @@ -19,14 +19,14 @@ - Michael Jung (2019) : initial version """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2019-2021 Michael Jung # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.chain_complexes import ChainComplexes from sage.categories.graded_algebras import GradedAlgebras @@ -142,6 +142,7 @@ class MixedFormAlgebra(Parent, UniqueRepresentation): sage: OmegaU.has_coerce_map_from(Omega) True """ + Element = MixedForm def __init__(self, vector_field_module): @@ -225,8 +226,7 @@ def _element_constructor_(self, comp, name=None, latex_name=None): res = self.element_class(self, name=name, latex_name=latex_name) if isinstance(comp, (tuple, list)): if len(comp) != self._max_deg + 1: - raise IndexError("input list must have " - "length {}".format(self._max_deg + 1)) + raise IndexError("input list must have " "length {}".format(self._max_deg + 1)) if isinstance(comp, tuple): comp = list(comp) res[:] = comp[:] @@ -238,8 +238,7 @@ def _element_constructor_(self, comp, name=None, latex_name=None): deg = d break else: - raise TypeError("cannot convert {} into an element of " - "the {}".format(comp, self)) + raise TypeError("cannot convert {} into an element of " "the {}".format(comp, self)) # fill up with zeroes: res[:] = [0] * (self._max_deg + 1) # set comp where it belongs: @@ -270,8 +269,7 @@ def _an_element_(self): """ res = self.element_class(self) dom = self._domain - res._comp = [dom.diff_form_module(j, self._dest_map)._an_element_() - for j in self.irange()] + res._comp = [dom.diff_form_module(j, self._dest_map)._an_element_() for j in self.irange()] return res def _coerce_map_from_(self, S): @@ -301,8 +299,7 @@ def _coerce_map_from_(self, S): """ if isinstance(S, type(self)): # coercion by domain restriction - if (self._domain.is_subset(S._domain) and - self._ambient_domain.is_subset(S._ambient_domain)): + if self._domain.is_subset(S._domain) and self._ambient_domain.is_subset(S._ambient_domain): return True # Still, there could be a coerce map if self.irange() != S.irange(): @@ -317,8 +314,7 @@ def _coerce_map_from_(self, S): return True # Let us check for each degree consecutively: dom = self._domain - return any(dom.diff_form_module(deg, self._dest_map).has_coerce_map_from(S) - for deg in self.irange()) + return any(dom.diff_form_module(deg, self._dest_map).has_coerce_map_from(S) for deg in self.irange()) @cached_method def zero(self): @@ -334,8 +330,7 @@ def zero(self): manifold M """ res = self.element_class(self, name='zero', latex_name='0') - res._comp = [self._domain.diff_form_module(j, dest_map=self._dest_map).zero() - for j in self.irange()] + res._comp = [self._domain.diff_form_module(j, dest_map=self._dest_map).zero() for j in self.irange()] res._is_zero = True # This element is certainly zero res.set_immutable() return res @@ -354,9 +349,7 @@ def one(self): manifold M """ res = self.element_class(self, name='one', latex_name='1') - res._comp = [self._domain.one_scalar_field(), - *(self._domain.diff_form_module(j, dest_map=self._dest_map).zero() - for j in self.irange(1))] + res._comp = [self._domain.one_scalar_field(), *(self._domain.diff_form_module(j, dest_map=self._dest_map).zero() for j in self.irange(1))] res.set_immutable() return res @@ -497,6 +490,7 @@ def cohomology(self, *args, **kwargs): from sage.manifolds.differentiable.de_rham_cohomology import ( DeRhamCohomologyRing, ) + return DeRhamCohomologyRing(self) homology = cohomology diff --git a/src/sage/manifolds/differentiable/multivector_module.py b/src/sage/manifolds/differentiable/multivector_module.py index c810337cb8c..fac47e37f48 100644 --- a/src/sage/manifolds/differentiable/multivector_module.py +++ b/src/sage/manifolds/differentiable/multivector_module.py @@ -23,14 +23,15 @@ - \R. L. Bishop and S. L. Goldberg (1980) [BG1980]_ - \C.-M. Marle (1997) [Mar1997]_ """ -#****************************************************************************** + +# ****************************************************************************** # Copyright (C) 2017 Eric Gourgoulhon # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.modules import Modules from sage.manifolds.differentiable.multivectorfield import ( @@ -217,6 +218,7 @@ class :class:`MultivectorFreeModule` must be used instead. sage: a_U.display(eU) a = 3*x ∂/∂x∧∂/∂y """ + Element = MultivectorField def __init__(self, vector_field_module, degree): @@ -250,8 +252,7 @@ def __init__(self, vector_field_module, degree): domain = vector_field_module._domain dest_map = vector_field_module._dest_map name = "A^{}(".format(degree) + domain._name - latex_name = r"A^{{{}}}\left({}".format(degree, - domain._latex_name) + latex_name = r"A^{{{}}}\left({}".format(degree, domain._latex_name) if dest_map is not domain.identity_map(): dm_name = dest_map._name dm_latex_name = dest_map._latex_name @@ -268,8 +269,7 @@ def __init__(self, vector_field_module, degree): # the member self._ring is created for efficiency (to avoid # calls to self.base_ring()): self._ring = domain.scalar_field_algebra() - Parent.__init__(self, base=self._ring, - category=Modules(self._ring)) + Parent.__init__(self, base=self._ring, category=Modules(self._ring)) self._domain = domain self._dest_map = dest_map self._ambient_domain = vector_field_module._ambient_domain @@ -279,8 +279,7 @@ def __init__(self, vector_field_module, degree): #### Parent methods - def _element_constructor_(self, comp=[], frame=None, name=None, - latex_name=None): + def _element_constructor_(self, comp=[], frame=None, name=None, latex_name=None): r""" Construct a multivector field. @@ -307,19 +306,13 @@ def _element_constructor_(self, comp=[], frame=None, name=None, return self.zero() if isinstance(comp, (MultivectorField, MultivectorFieldParal)): # coercion by domain restriction - if (self._degree == comp._tensor_type[0] - and self._domain.is_subset(comp._domain) - and self._ambient_domain.is_subset( - comp._ambient_domain)): + if self._degree == comp._tensor_type[0] and self._domain.is_subset(comp._domain) and self._ambient_domain.is_subset(comp._ambient_domain): return comp.restrict(self._domain) - raise TypeError("cannot convert the {} ".format(comp) + - "to an element of {}".format(self)) + raise TypeError("cannot convert the {} ".format(comp) + "to an element of {}".format(self)) if not isinstance(comp, (list, tuple)): - raise TypeError("cannot convert the {} ".format(comp) + - "to an element of {}".format(self)) + raise TypeError("cannot convert the {} ".format(comp) + "to an element of {}".format(self)) # standard construction - resu = self.element_class(self._vmodule, self._degree, - name=name, latex_name=latex_name) + resu = self.element_class(self._vmodule, self._degree, name=name, latex_name=latex_name) if comp: resu.set_comp(frame)[:] = comp return resu @@ -343,8 +336,7 @@ def _an_element_(self): for oc in self._domain.open_covers(trivial=False): # the first non-trivial open cover is selected for dom in oc: - vmodule_dom = dom.vector_field_module( - dest_map=self._dest_map.restrict(dom)) + vmodule_dom = dom.vector_field_module(dest_map=self._dest_map.restrict(dom)) dmodule_dom = vmodule_dom.exterior_power(self._degree) resu.set_restriction(dmodule_dom._an_element_()) return resu @@ -369,10 +361,7 @@ def _coerce_map_from_(self, other): """ if isinstance(other, (MultivectorModule, MultivectorFreeModule)): # coercion by domain restriction - return (self._degree == other._degree - and self._domain.is_subset(other._domain) - and self._ambient_domain.is_subset( - other._ambient_domain)) + return self._degree == other._degree and self._domain.is_subset(other._domain) and self._ambient_domain.is_subset(other._ambient_domain) return False @cached_method @@ -418,8 +407,7 @@ def _repr_(self): if self._dest_map is self._domain.identity_map(): description += "on the {}".format(self._domain) else: - description += "along the {} mapped into the {}".format( - self._domain, self._ambient_domain) + description += "along the {} mapped into the {}".format(self._domain, self._ambient_domain) return description def _latex_(self): @@ -487,7 +475,8 @@ def degree(self): """ return self._degree -#*********************************************************************** + +# *********************************************************************** class MultivectorFreeModule(ExtPowerFreeModule): @@ -674,8 +663,7 @@ def __init__(self, vector_field_module, degree): domain = vector_field_module._domain dest_map = vector_field_module._dest_map name = "A^{}(".format(degree) + domain._name - latex_name = r"A^{{{}}}\left({}".format(degree, - domain._latex_name) + latex_name = r"A^{{{}}}\left({}".format(degree, domain._latex_name) if dest_map is not domain.identity_map(): dm_name = dest_map._name dm_latex_name = dest_map._latex_name @@ -687,16 +675,14 @@ def __init__(self, vector_field_module, degree): latex_name += "," + dm_latex_name name += ")" latex_name += r"\right)" - ExtPowerFreeModule.__init__(self, vector_field_module, degree, - name=name, latex_name=latex_name) + ExtPowerFreeModule.__init__(self, vector_field_module, degree, name=name, latex_name=latex_name) self._domain = domain self._dest_map = dest_map self._ambient_domain = vector_field_module._ambient_domain #### Parent methods - def _element_constructor_(self, comp=[], frame=None, name=None, - latex_name=None): + def _element_constructor_(self, comp=[], frame=None, name=None, latex_name=None): r""" Construct a multivector field. @@ -721,19 +707,13 @@ def _element_constructor_(self, comp=[], frame=None, name=None, return self.zero() if isinstance(comp, (MultivectorField, MultivectorFieldParal)): # coercion by domain restriction - if (self._degree == comp._tensor_type[0] - and self._domain.is_subset(comp._domain) - and self._ambient_domain.is_subset( - comp._ambient_domain)): + if self._degree == comp._tensor_type[0] and self._domain.is_subset(comp._domain) and self._ambient_domain.is_subset(comp._ambient_domain): return comp.restrict(self._domain) - raise TypeError("cannot convert the {} ".format(comp) + - "to a multivector field in {}".format(self)) + raise TypeError("cannot convert the {} ".format(comp) + "to a multivector field in {}".format(self)) if not isinstance(comp, (list, tuple)): - raise TypeError("cannot convert the {} ".format(comp) + - "to an element of {}".format(self)) + raise TypeError("cannot convert the {} ".format(comp) + "to an element of {}".format(self)) # standard construction - resu = self.element_class(self._fmodule, self._degree, name=name, - latex_name=latex_name) + resu = self.element_class(self._fmodule, self._degree, name=name, latex_name=latex_name) if comp: resu.set_comp(frame)[:] = comp return resu @@ -763,10 +743,7 @@ def _coerce_map_from_(self, other): """ if isinstance(other, (MultivectorModule, MultivectorFreeModule)): # coercion by domain restriction - return (self._degree == other._degree - and self._domain.is_subset(other._domain) - and self._ambient_domain.is_subset( - other._ambient_domain)) + return self._degree == other._degree and self._domain.is_subset(other._domain) and self._ambient_domain.is_subset(other._ambient_domain) return False #### End of Parent methods @@ -791,6 +768,5 @@ def _repr_(self): if self._dest_map is self._domain.identity_map(): description += "on the {}".format(self._domain) else: - description += "along the {} mapped into the {}".format( - self._domain, self._ambient_domain) + description += "along the {} mapped into the {}".format(self._domain, self._ambient_domain) return description diff --git a/src/sage/manifolds/differentiable/multivectorfield.py b/src/sage/manifolds/differentiable/multivectorfield.py index 7531e9b02f6..f143a4f6b9f 100644 --- a/src/sage/manifolds/differentiable/multivectorfield.py +++ b/src/sage/manifolds/differentiable/multivectorfield.py @@ -154,6 +154,7 @@ class MultivectorField(TensorField): f*(a∧b) = (1/2*u^5 - 1/2*u^3*v^2 - 1/2*u^2*v^3 + u^3 + 1/2*(u^4 + 2*u^2)*v) ∂/∂u∧∂/∂v """ + def __init__(self, vector_field_module, degree, name=None, latex_name=None): r""" Construct a multivector field. @@ -194,10 +195,8 @@ def __init__(self, vector_field_module, degree, name=None, latex_name=None): Fix ``_test_pickling`` (in the superclass :class:`TensorField`). """ - TensorField.__init__(self, vector_field_module, (degree, 0), name=name, - latex_name=latex_name, antisym=range(degree), - parent=vector_field_module.exterior_power(degree)) - self._init_derived() # initialization of derived quantities + TensorField.__init__(self, vector_field_module, (degree, 0), name=name, latex_name=latex_name, antisym=range(degree), parent=vector_field_module.exterior_power(degree)) + self._init_derived() # initialization of derived quantities def _repr_(self): r""" @@ -302,14 +301,13 @@ def wedge(self, other): """ from sage.tensor.modules.format_utilities import is_atomic from sage.typeset.unicode_characters import unicode_wedge + if self._domain.is_subset(other._domain): if not self._ambient_domain.is_subset(other._ambient_domain): - raise ValueError("incompatible ambient domains for exterior " + - "product") + raise ValueError("incompatible ambient domains for exterior " + "product") elif other._domain.is_subset(self._domain): if not other._ambient_domain.is_subset(self._ambient_domain): - raise ValueError("incompatible ambient domains for exterior " + - "product") + raise ValueError("incompatible ambient domains for exterior " + "product") dom_resu = self._domain.intersection(other._domain) ambient_dom_resu = self._ambient_domain.intersection(other._ambient_domain) self_r = self.restrict(dom_resu) @@ -337,16 +335,13 @@ def wedge(self, other): olname = '(' + olname + ')' resu_latex_name = slname + r'\wedge ' + olname dest_map = self._vmodule._dest_map - dest_map_resu = dest_map.restrict(dom_resu, - subcodomain=ambient_dom_resu) + dest_map_resu = dest_map.restrict(dom_resu, subcodomain=ambient_dom_resu) vmodule = dom_resu.vector_field_module(dest_map=dest_map_resu) resu_degree = self._tensor_rank + other._tensor_rank - resu = vmodule.alternating_contravariant_tensor(resu_degree, - name=resu_name, latex_name=resu_latex_name) + resu = vmodule.alternating_contravariant_tensor(resu_degree, name=resu_name, latex_name=resu_latex_name) for dom in self_r._restrictions: if dom in other_r._restrictions: - resu._restrictions[dom] = self_r._restrictions[dom].wedge( - other_r._restrictions[dom]) + resu._restrictions[dom] = self_r._restrictions[dom].wedge(other_r._restrictions[dom]) return resu def interior_product(self, form): @@ -453,14 +448,13 @@ def interior_product(self, form): True """ from sage.tensor.modules.format_utilities import is_atomic + if self._domain.is_subset(form._domain): if not self._ambient_domain.is_subset(form._ambient_domain): - raise ValueError("incompatible ambient domains for interior " + - "product") + raise ValueError("incompatible ambient domains for interior " + "product") elif form._domain.is_subset(self._domain): if not form._ambient_domain.is_subset(self._ambient_domain): - raise ValueError("incompatible ambient domains for interior " + - "product") + raise ValueError("incompatible ambient domains for interior " + "product") dom_resu = self._domain.intersection(form._domain) ambient_dom_resu = self._ambient_domain.intersection(form._ambient_domain) self_r = self.restrict(dom_resu) @@ -488,25 +482,19 @@ def interior_product(self, form): resu_latex_name = r'\iota_{' + slname + '} ' + olname # Domain and computation of the result dest_map = self._vmodule._dest_map - dest_map_resu = dest_map.restrict(dom_resu, - subcodomain=ambient_dom_resu) + dest_map_resu = dest_map.restrict(dom_resu, subcodomain=ambient_dom_resu) vmodule = dom_resu.vector_field_module(dest_map=dest_map_resu) resu_degree = form._tensor_rank - self._tensor_rank - resu = vmodule.alternating_form(resu_degree, - name=resu_name, - latex_name=resu_latex_name) + resu = vmodule.alternating_form(resu_degree, name=resu_name, latex_name=resu_latex_name) for dom in self_r._restrictions: if dom in form_r._restrictions: - resu._restrictions[dom] = \ - self_r._restrictions[dom].interior_product( - form_r._restrictions[dom]) + resu._restrictions[dom] = self_r._restrictions[dom].interior_product(form_r._restrictions[dom]) if resu_degree == 0: if not resu._express: # only the restrictions to subdomains have # been initialized for chart in dom_resu.top_charts(): - resu._express[chart] = \ - resu.restrict(chart.domain()).coord_function(chart) + resu._express[chart] = resu.restrict(chart.domain()).coord_function(chart) return resu def bracket(self, other): @@ -627,21 +615,19 @@ def bracket(self, other): of standards identities involving the Schouten-Nijenhuis bracket """ from sage.manifolds.differentiable.scalarfield import DiffScalarField + pp = self._tensor_rank - mp1 = (-1)**(pp+1) + mp1 = (-1) ** (pp + 1) if isinstance(other, DiffScalarField): resu = other.differential().interior_product(self) if mp1 == 1: return resu - return - resu + return -resu # Some checks: if not isinstance(other, (MultivectorField, MultivectorFieldParal)): raise TypeError("{} is not a multivector field".format(other)) - if (self._vmodule.destination_map() is not self._domain.identity_map() - or other._vmodule.destination_map() is not - other._domain.identity_map()): - raise ValueError("the Schouten-Nijenhuis bracket is defined " + - "only for fields with a trivial destination map") + if self._vmodule.destination_map() is not self._domain.identity_map() or other._vmodule.destination_map() is not other._domain.identity_map(): + raise ValueError("the Schouten-Nijenhuis bracket is defined " + "only for fields with a trivial destination map") # Search for a common domain dom_resu = self._domain.intersection(other._domain) self_r = self.restrict(dom_resu) @@ -656,20 +642,18 @@ def bracket(self, other): if self._name is not None and other._name is not None: resu_name = '[' + self._name + ',' + other._name + ']' if self._latex_name is not None and other._latex_name is not None: - resu_latex_name = r'\left[' + self._latex_name + ',' + \ - other._latex_name + r'\right]' + resu_latex_name = r'\left[' + self._latex_name + ',' + other._latex_name + r'\right]' vmodule = dom_resu.vector_field_module() deg_resu = pp + other._tensor_rank - 1 # degree of the result - resu = vmodule.alternating_contravariant_tensor(deg_resu, - name=resu_name, latex_name=resu_latex_name) + resu = vmodule.alternating_contravariant_tensor(deg_resu, name=resu_name, latex_name=resu_latex_name) for dom in self_r._restrictions: if dom in other_r._restrictions: - resu._restrictions[dom] = self_r._restrictions[dom].bracket( - other_r._restrictions[dom]) + resu._restrictions[dom] = self_r._restrictions[dom].bracket(other_r._restrictions[dom]) return resu -#****************************************************************************** +# ****************************************************************************** + class MultivectorFieldParal(AlternatingContrTensor, TensorFieldParal): r""" @@ -857,8 +841,8 @@ class MultivectorFieldParal(AlternatingContrTensor, TensorFieldParal): sage: ab.lie_der(a) 2-vector field on the 3-dimensional differentiable manifold R3 """ - def __init__(self, vector_field_module, degree, name=None, - latex_name=None): + + def __init__(self, vector_field_module, degree, name=None, latex_name=None): r""" Construct a multivector field. @@ -885,8 +869,7 @@ def __init__(self, vector_field_module, degree, name=None, sage: a1.parent() is a.parent() True """ - AlternatingContrTensor.__init__(self, vector_field_module, degree, - name=name, latex_name=latex_name) + AlternatingContrTensor.__init__(self, vector_field_module, degree, name=name, latex_name=latex_name) # TensorFieldParal attributes: self._vmodule = vector_field_module self._domain = vector_field_module._domain @@ -1050,12 +1033,10 @@ def wedge(self, other): return self * other if self._domain.is_subset(other._domain): if not self._ambient_domain.is_subset(other._ambient_domain): - raise ValueError("incompatible ambient domains for exterior " + - "product") + raise ValueError("incompatible ambient domains for exterior " + "product") elif other._domain.is_subset(self._domain): if not other._ambient_domain.is_subset(self._ambient_domain): - raise ValueError("incompatible ambient domains for exterior " + - "product") + raise ValueError("incompatible ambient domains for exterior " + "product") dom_resu = self._domain.intersection(other._domain) self_r = self.restrict(dom_resu) other_r = other.restrict(dom_resu) @@ -1165,12 +1146,10 @@ def interior_product(self, form): """ if self._domain.is_subset(form._domain): if not self._ambient_domain.is_subset(form._ambient_domain): - raise ValueError("incompatible ambient domains for interior " + - "product") + raise ValueError("incompatible ambient domains for interior " + "product") elif form._domain.is_subset(self._domain): if not form._ambient_domain.is_subset(self._ambient_domain): - raise ValueError("incompatible ambient domains for interior " + - "product") + raise ValueError("incompatible ambient domains for interior " + "product") dom_resu = self._domain.intersection(form._domain) self_r = self.restrict(dom_resu) form_r = form.restrict(dom_resu) @@ -1407,21 +1386,19 @@ def bracket(self, other): from sage.combinat.permutation import Permutation from sage.manifolds.differentiable.scalarfield import DiffScalarField from sage.tensor.modules.comp import CompFullyAntiSym, Components, CompWithSym + pp = self._tensor_rank - mp1 = (-1)**(pp+1) + mp1 = (-1) ** (pp + 1) if isinstance(other, DiffScalarField): resu = other.differential().interior_product(self) if mp1 == 1: return resu - return - resu + return -resu # Some checks: if not isinstance(other, (MultivectorField, MultivectorFieldParal)): raise TypeError("{} is not a multivector field".format(other)) - if (self._vmodule.destination_map() is not self._domain.identity_map() - or other._vmodule.destination_map() is not - other._domain.identity_map()): - raise ValueError("the Schouten-Nijenhuis bracket is defined " + - "only for fields with a trivial destination map") + if self._vmodule.destination_map() is not self._domain.identity_map() or other._vmodule.destination_map() is not other._domain.identity_map(): + raise ValueError("the Schouten-Nijenhuis bracket is defined " + "only for fields with a trivial destination map") # Search for a common domain dom_resu = self._domain.intersection(other._domain) self_r = self.restrict(dom_resu) @@ -1433,52 +1410,38 @@ def bracket(self, other): chart = coord_frame.chart() dom_resu = chart.domain() fmodule = dom_resu.vector_field_module() - ring = fmodule.base_ring() # same as dom_resu.scalar_field_algebra() + ring = fmodule.base_ring() # same as dom_resu.scalar_field_algebra() aa = self_r.comp(coord_frame) # components A^{i_1...i_p} - bb = other_r.comp(coord_frame) # components B^{j_1...j_q} + bb = other_r.comp(coord_frame) # components B^{j_1...j_q} qq = other._tensor_rank deg_resu = pp + qq - 1 # degree of the result if deg_resu == 1: - resuc = Components(ring, coord_frame, 1, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter) + resuc = Components(ring, coord_frame, 1, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) else: - resuc = CompFullyAntiSym(ring, coord_frame, deg_resu, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter) + resuc = CompFullyAntiSym(ring, coord_frame, deg_resu, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) # Partial derivatives of the components of self: if pp == 1: - daa = Components(ring, coord_frame, 2, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter) + daa = Components(ring, coord_frame, 2, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) else: - daa = CompWithSym(ring, coord_frame, pp+1, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter, - antisym=range(pp)) + daa = CompWithSym(ring, coord_frame, pp + 1, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter, antisym=range(pp)) for ind, val in aa._comp.items(): for k in fmodule.irange(): - daa[[ind+(k,)]] = val.coord_function(chart).diff(k) + daa[[ind + (k,)]] = val.coord_function(chart).diff(k) # Partial derivatives of the components of other: if qq == 1: - dbb = Components(ring, coord_frame, 2, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter) + dbb = Components(ring, coord_frame, 2, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) else: - dbb = CompWithSym(ring, coord_frame, qq+1, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter, - antisym=range(qq)) + dbb = CompWithSym(ring, coord_frame, qq + 1, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter, antisym=range(qq)) for ind, val in bb._comp.items(): for k in fmodule.irange(): - dbb[[ind+(k,)]] = val.coord_function(chart).diff(k) + dbb[[ind + (k,)]] = val.coord_function(chart).diff(k) # Computation for ind in resuc.non_redundant_index_generator(): sind = set(ind) # {i_1, i_2, ..., i_{p+q-1}} # Term a^{l j_2 ... j_p} \partial_l b^{k_1 ... k_q} # with (j_2,...,j_p,k_1,...,k_q) spanning all permutations of # (i_1, i_2, ..., i_{p+q-1}) - for sind_a in combinations(sind, pp-1): + for sind_a in combinations(sind, pp - 1): sind_b = sind.difference(sind_a) ind_a = tuple(sorted(sind_a)) ind_b = tuple(sorted(sind_b)) @@ -1487,14 +1450,14 @@ def bracket(self, other): sum += aa[[(l,) + ind_a]] * dbb[[ind_b + (l,)]] ind_ab = ind_a + ind_b sign = Permutation([ind_ab.index(i) + 1 for i in ind]).signature() - if mp1*sign == 1: + if mp1 * sign == 1: resuc[[ind]] += sum else: resuc[[ind]] -= sum # Term b^{l k_2 ... k_q} \partial_l a^{j_1 ... j_p} # with (j_1,...,j_p,k_2,...,k_q) spanning all permutations of # (i_1, i_2, ..., i_{p+q-1}) - for sind_b in combinations(sind, qq-1): + for sind_b in combinations(sind, qq - 1): sind_a = sind.difference(sind_b) ind_a = tuple(sorted(sind_a)) ind_b = tuple(sorted(sind_b)) @@ -1513,9 +1476,7 @@ def bracket(self, other): if self._name is not None and other._name is not None: resu_name = '[' + self._name + ',' + other._name + ']' if self._latex_name is not None and other._latex_name is not None: - resu_latex_name = r'\left[' + self._latex_name + ',' + \ - other._latex_name + r'\right]' + resu_latex_name = r'\left[' + self._latex_name + ',' + other._latex_name + r'\right]' # Creation of the multivector with the components obtained above: - resu = fmodule.tensor_from_comp((deg_resu, 0), resuc, name=resu_name, - latex_name=resu_latex_name) + resu = fmodule.tensor_from_comp((deg_resu, 0), resuc, name=resu_name, latex_name=resu_latex_name) return resu diff --git a/src/sage/manifolds/differentiable/poisson_tensor.py b/src/sage/manifolds/differentiable/poisson_tensor.py index 63fcab8d588..0027e4db1f0 100644 --- a/src/sage/manifolds/differentiable/poisson_tensor.py +++ b/src/sage/manifolds/differentiable/poisson_tensor.py @@ -112,9 +112,7 @@ def __init__( except AttributeError: vector_field_module = manifold - MultivectorField.__init__( - self, vector_field_module, 2, name=name, latex_name=latex_name - ) + MultivectorField.__init__(self, vector_field_module, 2, name=name, latex_name=latex_name) def hamiltonian_vector_field(self, function: DiffScalarField) -> VectorField: r""" @@ -175,17 +173,13 @@ def sharp(self, form: DiffForm) -> VectorField: a_sharp = e_p """ if form.degree() != 1: - raise ValueError( - f"the degree of the differential form must be one but it is {form.degree()}" - ) + raise ValueError(f"the degree of the differential form must be one but it is {form.degree()}") vector_field = form.up(self) vector_field.set_name(f"{form._name}_sharp", f"{form._latex_name}^\\sharp") return vector_field - def poisson_bracket( - self, f: DiffScalarField, g: DiffScalarField - ) -> DiffScalarField: + def poisson_bracket(self, f: DiffScalarField, g: DiffScalarField) -> DiffScalarField: r""" Return the Poisson bracket @@ -211,9 +205,7 @@ def poisson_bracket( poisson(f, g): E^2 → ℝ (q, p) ↦ d(f)/dp*d(g)/dq - d(f)/dq*d(g)/dp """ - bracket = self.contract(0, f.exterior_derivative()).contract( - 0, g.exterior_derivative() - ) + bracket = self.contract(0, f.exterior_derivative()).contract(0, g.exterior_derivative()) bracket.set_name( f"poisson({f._name}, {g._name})", "\\{" + f"{f._latex_name}, {g._latex_name}" + "\\}", diff --git a/src/sage/manifolds/differentiable/pseudo_riemannian.py b/src/sage/manifolds/differentiable/pseudo_riemannian.py index c44d063bdc3..8e852a9400f 100644 --- a/src/sage/manifolds/differentiable/pseudo_riemannian.py +++ b/src/sage/manifolds/differentiable/pseudo_riemannian.py @@ -258,14 +258,14 @@ - \J. M. Lee : *Riemannian Manifolds* [Lee1997]_ """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2018 Eric Gourgoulhon # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.manifolds.differentiable.manifold import DifferentiableManifold from sage.manifolds.structure import ( @@ -414,10 +414,8 @@ class PseudoRiemannianManifold(DifferentiableManifold): sage: M.metric().signature() -2 """ - def __init__(self, n, name, metric_name=None, signature=None, - base_manifold=None, diff_degree=infinity, latex_name=None, - metric_latex_name=None, start_index=0, category=None, - unique_tag=None): + + def __init__(self, n, name, metric_name=None, signature=None, base_manifold=None, diff_degree=infinity, latex_name=None, metric_latex_name=None, start_index=0, category=None, unique_tag=None): r""" Construct a pseudo-Riemannian manifold. @@ -435,21 +433,15 @@ def __init__(self, n, name, metric_name=None, signature=None, sage: TestSuite(M).run() """ if base_manifold and not isinstance(base_manifold, PseudoRiemannianManifold): - raise TypeError("the argument 'base_manifold' must be a " + - "pseudo-Riemannian manifold") + raise TypeError("the argument 'base_manifold' must be a " + "pseudo-Riemannian manifold") if signature is None or signature == n: structure = RiemannianStructure() - elif signature == n-2 or signature == 2-n: + elif signature == n - 2 or signature == 2 - n: structure = LorentzianStructure() else: structure = PseudoRiemannianStructure() - DifferentiableManifold.__init__(self, n, name, 'real', structure, - base_manifold=base_manifold, - diff_degree=diff_degree, - latex_name=latex_name, - start_index=start_index, - category=category) - self._metric = None # to be initialized by metric() + DifferentiableManifold.__init__(self, n, name, 'real', structure, base_manifold=base_manifold, diff_degree=diff_degree, latex_name=latex_name, start_index=start_index, category=category) + self._metric = None # to be initialized by metric() self._metric_signature = signature if metric_name is None: metric_name = 'g' @@ -463,8 +455,7 @@ def __init__(self, n, name, metric_name=None, signature=None, raise TypeError("{} is not a string".format(metric_latex_name)) self._metric_latex_name = metric_latex_name - def metric(self, name=None, signature=None, latex_name=None, - dest_map=None): + def metric(self, name=None, signature=None, latex_name=None, dest_map=None): r""" Return the metric giving the pseudo-Riemannian structure to the manifold, or define a new metric tensor on the manifold. @@ -576,16 +567,11 @@ class :class:`~sage.manifolds.differentiable.diff_map.DiffMap` self._metric = self._manifold._metric.restrict(self) else: # creation from scratch: - self._metric = DifferentiableManifold.metric(self, - self._metric_name, - signature=self._metric_signature, - latex_name=self._metric_latex_name) + self._metric = DifferentiableManifold.metric(self, self._metric_name, signature=self._metric_signature, latex_name=self._metric_latex_name) return self._metric # Metric distinct from the default one: it is created by the method # metric of the superclass for generic differentiable manifolds: - return DifferentiableManifold.metric(self, name, signature=signature, - latex_name=latex_name, - dest_map=dest_map) + return DifferentiableManifold.metric(self, name, signature=signature, latex_name=latex_name, dest_map=dest_map) def volume_form(self, contra=0): r""" @@ -739,14 +725,7 @@ def open_subset(self, name, latex_name=None, coord_def={}, supersets=None): sage: gV is g.restrict(V) True """ - resu = PseudoRiemannianManifold(self._dim, name, - metric_name=self._metric_name, - signature=self._metric_signature, - base_manifold=self._manifold, - diff_degree=self._diff_degree, - latex_name=latex_name, - metric_latex_name=self._metric_latex_name, - start_index=self._sindex) + resu = PseudoRiemannianManifold(self._dim, name, metric_name=self._metric_name, signature=self._metric_signature, base_manifold=self._manifold, diff_degree=self._diff_degree, latex_name=latex_name, metric_latex_name=self._metric_latex_name, start_index=self._sindex) if supersets is None: supersets = [self] for superset in supersets: diff --git a/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py b/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py index 57dc1c99862..63455dafc6f 100644 --- a/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +++ b/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py @@ -205,8 +205,7 @@ from sage.symbolic.ring import SR -class PseudoRiemannianSubmanifold(PseudoRiemannianManifold, - DifferentiableSubmanifold): +class PseudoRiemannianSubmanifold(PseudoRiemannianManifold, DifferentiableSubmanifold): r""" Pseudo-Riemannian submanifold. @@ -302,10 +301,8 @@ class PseudoRiemannianSubmanifold(PseudoRiemannianManifold, :mod:`~sage.manifolds.manifold` and :mod:`~sage.manifolds.differentiable.differentiable_submanifold` """ - def __init__(self, n, name, ambient=None, metric_name=None, - signature=None, base_manifold=None, diff_degree=infinity, - latex_name=None, metric_latex_name=None, start_index=0, - category=None, unique_tag=None): + + def __init__(self, n, name, ambient=None, metric_name=None, signature=None, base_manifold=None, diff_degree=infinity, latex_name=None, metric_latex_name=None, start_index=0, category=None, unique_tag=None): r""" Construct a pseudo-Riemannian submanifold. @@ -341,17 +338,8 @@ def __init__(self, n, name, ambient=None, metric_name=None, if metric_name is None: metric_name = 'gamma' metric_latex_name = r'\gamma' - PseudoRiemannianManifold.__init__(self, n, name=name, - metric_name=metric_name, - signature=signature, - base_manifold=base_manifold, - diff_degree=diff_degree, - latex_name=latex_name, - metric_latex_name=metric_latex_name, - start_index=start_index, - category=category) - if not (ambient is None - or isinstance(ambient, (PseudoRiemannianManifold, DegenerateManifold))): + PseudoRiemannianManifold.__init__(self, n, name=name, metric_name=metric_name, signature=signature, base_manifold=base_manifold, diff_degree=diff_degree, latex_name=latex_name, metric_latex_name=metric_latex_name, start_index=start_index, category=category) + if not (ambient is None or isinstance(ambient, (PseudoRiemannianManifold, DegenerateManifold))): raise TypeError("ambient must be a pseudo-Riemannian manifold") self._init_immersion(ambient=ambient) self._difft = None @@ -397,10 +385,8 @@ def _repr_(self): if self._ambient is None: return super(PseudoRiemannianManifold, self).__repr__() if self._embedded: - return "{}-dimensional {} submanifold {} embedded in the {}".format( - self._dim, self._structure.name, self._name, self._ambient) - return "{}-dimensional {} submanifold {} immersed in the {}".format( - self._dim, self._structure.name, self._name, self._ambient) + return "{}-dimensional {} submanifold {} embedded in the {}".format(self._dim, self._structure.name, self._name, self._ambient) + return "{}-dimensional {} submanifold {} immersed in the {}".format(self._dim, self._structure.name, self._name, self._ambient) def open_subset(self, name, latex_name=None, coord_def={}, supersets=None): r""" @@ -462,15 +448,7 @@ def open_subset(self, name, latex_name=None, coord_def={}, supersets=None): 2-dimensional Riemannian submanifold N embedded in the 3-dimensional Riemannian manifold M """ - resu = PseudoRiemannianSubmanifold(self._dim, name, - ambient=self._ambient, - metric_name=self._metric_name, - signature=self._metric_signature, - base_manifold=self._manifold, - diff_degree=self._diff_degree, - latex_name=latex_name, - metric_latex_name=self._metric_latex_name, - start_index=self._sindex) + resu = PseudoRiemannianSubmanifold(self._dim, name, ambient=self._ambient, metric_name=self._metric_name, signature=self._metric_signature, base_manifold=self._manifold, diff_degree=self._diff_degree, latex_name=latex_name, metric_latex_name=self._metric_latex_name, start_index=self._sindex) if supersets is None: supersets = [self] for superset in supersets: @@ -554,14 +532,12 @@ def first_fundamental_form(self): """ if self._first_fundamental_form is None: self._first_fundamental_form = super().metric() - self._first_fundamental_form.set( - self._immersion.pullback(self.ambient_metric())) + self._first_fundamental_form.set(self._immersion.pullback(self.ambient_metric())) return self._first_fundamental_form induced_metric = first_fundamental_form - def metric(self, name=None, signature=None, latex_name=None, - dest_map=None): + def metric(self, name=None, signature=None, latex_name=None, dest_map=None): r""" Return the induced metric (first fundamental form) or define a new metric tensor on the submanifold. @@ -631,8 +607,7 @@ class :class:`~sage.manifolds.differentiable.diff_map.DiffMap` """ if name is None or name == self._metric_name: return self.first_fundamental_form() - return super().metric(name=name, signature=signature, - latex_name=latex_name, dest_map=dest_map) + return super().metric(name=name, signature=signature, latex_name=latex_name, dest_map=dest_map) @cached_method def difft(self): @@ -671,11 +646,9 @@ def difft(self): z/sqrt(x^2 + y^2 + z^2) dz """ if self._dim_foliation == 0: - raise ValueError("A foliation is needed to " - "perform this calculation") + raise ValueError("A foliation is needed to " "perform this calculation") self._difft = self._t_inverse[self._var[0]].differential() - self._difft.set_name("d" + self._var[0]._repr_(), - r"\mathrm{d}" + self._var[0]._latex_()) + self._difft.set_name("d" + self._var[0]._repr_(), r"\mathrm{d}" + self._var[0]._latex_()) return self._difft @cached_method @@ -715,13 +688,10 @@ def gradt(self): + z/sqrt(x^2 + y^2 + z^2) e_z """ if self._dim_foliation == 0: - raise ValueError("A foliation is needed to perform " - "this calculation") + raise ValueError("A foliation is needed to perform " "this calculation") param = self._var[0] self._gradt = self._t_inverse[param].gradient() - self._gradt.set_name("grad({})".format(param), - r"\mathrm{grad}\left(" + param._latex_() - + r"\right)") + self._gradt.set_name("grad({})".format(param), r"\mathrm{grad}\left(" + param._latex_() + r"\right)") return self._gradt @cached_method @@ -854,15 +824,13 @@ def normal(self): sage: n.restrict(U).display(format_spec=spher) # long time n = -cos(phi)*sin(the) e_X - sin(phi)*sin(the) e_Y - cos(the) e_Z """ - if self._dim_foliation != 0: # case of a foliation + if self._dim_foliation != 0: # case of a foliation self._normal = self._sgn * self.lapse() * self.gradt() self._normal.set_name("n") return self._normal # case of no foliation: max_frame = self._ambient.default_frame().along(self._immersion) - self._normal = self.multivector_field(self._ambient._dim - self._dim, - name='n', - dest_map=self._immersion) + self._normal = self.multivector_field(self._ambient._dim - self._dim, name='n', dest_map=self._immersion) # an auxiliary function: def calc_normal(chart): @@ -870,30 +838,19 @@ def calc_normal(chart): Calculate the normal vector field according to the formula in the documentation in a given chart. """ - eps = self.ambient_metric().volume_form(self._dim).along( - self._immersion).restrict(chart.domain()) + eps = self.ambient_metric().volume_form(self._dim).along(self._immersion).restrict(chart.domain()) args = list(range(self._dim)) + [eps] + list(range(self._dim)) r = self.irange() - n_form = self._immersion.restrict(chart.domain()).pushforward( - chart.frame()[next(r)]).down( - self.ambient_metric().along(self._immersion).restrict( - chart.domain())) + n_form = self._immersion.restrict(chart.domain()).pushforward(chart.frame()[next(r)]).down(self.ambient_metric().along(self._immersion).restrict(chart.domain())) for i in r: - n_form = n_form.wedge( - self._immersion.restrict(chart.domain()).pushforward( - chart.frame()[i]).down( - self.ambient_metric().along( - self._immersion).restrict( - chart.domain()))) - n_comp = (n_form.contract(*args) / factorial(self._dim)).contract( - self.ambient_metric().inverse().along(self._immersion)) + n_form = n_form.wedge(self._immersion.restrict(chart.domain()).pushforward(chart.frame()[i]).down(self.ambient_metric().along(self._immersion).restrict(chart.domain()))) + n_comp = (n_form.contract(*args) / factorial(self._dim)).contract(self.ambient_metric().inverse().along(self._immersion)) if self._ambient._dim - self._dim == 1: n_comp = n_comp / n_comp.norm(self.ambient_metric()) norm_rst = self._normal.restrict(chart.domain()) norm_rst.add_comp(max_frame.restrict(chart.domain()))[:] = n_comp[:] - self._normal.add_comp_by_continuation(max_frame, chart.domain(), - chart) + self._normal.add_comp_by_continuation(max_frame, chart.domain(), chart) # start breadth-first graph exploration marked = set() @@ -917,8 +874,7 @@ def calc_normal(chart): # case continuation if vp in v._supercharts and vp not in marked: f.put(vp) - self._normal.add_comp_by_continuation( - max_frame.restrict(vp.domain()), v.domain(), vp) + self._normal.add_comp_by_continuation(max_frame.restrict(vp.domain()), v.domain(), vp) marked.add(vp) # case coordinates change @@ -981,14 +937,12 @@ def ambient_first_fundamental_form(self): [-2*x/(x^2 + 4) 4/(x^2 + 4)] """ if self._ambient._dim - self._dim != 1: - raise NotImplementedError("ambient_first_fundamental_form() is " - "implemented only for hypersurfaces") + raise NotImplementedError("ambient_first_fundamental_form() is " "implemented only for hypersurfaces") if self._ambient_first_fundamental_form is None: g = self.ambient_metric() if self._dim_foliation == 0: # case no foliation g = g.along(self._immersion) - self._ambient_first_fundamental_form = g - self._sgn * g.contract( - self.normal()) * g.contract(self.normal()) + self._ambient_first_fundamental_form = g - self._sgn * g.contract(self.normal()) * g.contract(self.normal()) self._ambient_first_fundamental_form.set_name("gamma", r"\gamma") return self._ambient_first_fundamental_form @@ -1031,10 +985,8 @@ def lapse(self): (th_E3, ph_E3, r_E3) ↦ 1 """ if self._dim_foliation == 0: - raise ValueError("A foliation is needed " - "to perform this calculation") - self._lapse = 1 / (self._sgn * self.ambient_metric()( - self.gradt(), self.gradt())).sqrt() + raise ValueError("A foliation is needed " "to perform this calculation") + self._lapse = 1 / (self._sgn * self.ambient_metric()(self.gradt(), self.gradt())).sqrt() self._lapse.set_name("N") return self._lapse @@ -1074,11 +1026,9 @@ def shift(self): beta = 0 """ if self._dim_foliation == 0: - raise ValueError("A foliation is needed " - "to perform this calculation") + raise ValueError("A foliation is needed " "to perform this calculation") sia = self._ambient._sindex - self._shift = self._adapted_charts[0].frame()[self._dim + sia]\ - - self.lapse() * self.normal() + self._shift = self._adapted_charts[0].frame()[self._dim + sia] - self.lapse() * self.normal() self._shift.set_name("beta", r"\beta") return self._shift @@ -1130,41 +1080,28 @@ def ambient_second_fundamental_form(self): [ 2*x/(x^2 + 4) -4/(x^2 + 4)] """ if self._ambient._dim - self._dim != 1: - raise ValueError("ambient_second_fundamental_form is defined only " - "for hypersurfaces") + raise ValueError("ambient_second_fundamental_form is defined only " "for hypersurfaces") if self._ambient_second_fundamental_form is None: if self._dim_foliation == 0: - self._ambient_second_fundamental_form = self.tensor_field(0, 2, - sym=[(0, 1)], dest_map=self._immersion) + self._ambient_second_fundamental_form = self.tensor_field(0, 2, sym=[(0, 1)], dest_map=self._immersion) k = self.second_fundamental_form() g = self.ambient_metric().along(self._immersion) max_frame = self._ambient.default_frame().along(self._immersion) for chart in self.top_charts(): - pf = [self._immersion.restrict(chart.domain()).pushforward( - chart.frame()[i]) for i in self.irange()] + pf = [self._immersion.restrict(chart.domain()).pushforward(chart.frame()[i]) for i in self.irange()] for i in range(self._dim): pf[i] = pf[i] / g(pf[i], pf[i]) - gam_rst = sum( - g.restrict(chart.domain()).contract(pf[i]) * - g.restrict(chart.domain()).contract(pf[j]) * - self.scalar_field({chart: k.comp(chart.frame())[:][i, j]}) - for i in range(self._dim) for j in range(self._dim)) + gam_rst = sum(g.restrict(chart.domain()).contract(pf[i]) * g.restrict(chart.domain()).contract(pf[j]) * self.scalar_field({chart: k.comp(chart.frame())[:][i, j]}) for i in range(self._dim) for j in range(self._dim)) gam_rst._sym = ((0, 1),) self._ambient_second_fundamental_form.set_restriction(gam_rst) charts = iter(self.top_charts()) - self._ambient_second_fundamental_form.add_comp_by_continuation( - max_frame, next(charts).domain()) + self._ambient_second_fundamental_form.add_comp_by_continuation(max_frame, next(charts).domain()) for chart in charts: - self._ambient_second_fundamental_form.add_expr_from_subdomain( - max_frame, chart.domain()) + self._ambient_second_fundamental_form.add_expr_from_subdomain(max_frame, chart.domain()) else: nab = self.ambient_metric().connection('nabla', r'\nabla') - self._ambient_second_fundamental_form = \ - -self.ambient_metric().contract(nab(self.normal())) \ - - nab(self.normal()).contract(self.normal())\ - .contract(self.ambient_metric())\ - * self.normal().contract(self.ambient_metric()) + self._ambient_second_fundamental_form = -self.ambient_metric().contract(nab(self.normal())) - nab(self.normal()).contract(self.normal()).contract(self.ambient_metric()) * self.normal().contract(self.ambient_metric()) self._ambient_second_fundamental_form.set_name("K") return self._ambient_second_fundamental_form @@ -1231,11 +1168,9 @@ def second_fundamental_form(self): K = 2*sqrt(u^4 + 2*u^2 + 2)*u/(u^6 + 3*u^4 + 4*u^2 + 2) du⊗du """ if self._ambient._dim - self._dim != 1: - raise ValueError("second_fundamental_form is defined only for" - + " hypersurfaces") + raise ValueError("second_fundamental_form is defined only for" + " hypersurfaces") if self._second_fundamental_form is None: - resu = self.vector_field_module().tensor((0, 2), name='K', - sym=[(0, 1)]) + resu = self.vector_field_module().tensor((0, 2), name='K', sym=[(0, 1)]) if self._dim_foliation != 0: inverse_subs = {v: k for k, v in self._subs[0].items()} asff = self.ambient_second_fundamental_form() @@ -1243,43 +1178,29 @@ def second_fundamental_form(self): dsi = self._ambient._sindex - self._sindex for i in self.irange(): for j in self.irange(start=i): - resu[i, j] = asff[adapted_chart.frame(), - i + dsi, j + dsi, - adapted_chart].expr().subs(inverse_subs) + resu[i, j] = asff[adapted_chart.frame(), i + dsi, j + dsi, adapted_chart].expr().subs(inverse_subs) else: nab = self.ambient_metric().connection('nabla', r'\nabla') n = self.normal() for chart in self.atlas(): gamma_n = matrix(SR, self._dim + 1, self._dim + 1) - subs = dict(zip(self._ambient.default_chart()[:], - self._immersion.expression(chart))) + subs = dict(zip(self._ambient.default_chart()[:], self._immersion.expression(chart))) for i in range(self._dim + 1): for j in range(self._dim + 1): - Gam_ij = [nab[self._ambient.frames()[0], - :][i][j][k].expr().subs(subs) - for k in range(self._dim + 1)] - gamma_n[i, j] = chart.simplify(sum( - Gam_ij[k] * - n.restrict(chart.domain()).comp( - n.restrict(chart.domain())._fmodule.bases()[0]) - [:][k].expr() for k in range(self._dim + 1))) + Gam_ij = [nab[self._ambient.frames()[0], :][i][j][k].expr().subs(subs) for k in range(self._dim + 1)] + gamma_n[i, j] = chart.simplify(sum(Gam_ij[k] * n.restrict(chart.domain()).comp(n.restrict(chart.domain())._fmodule.bases()[0])[:][k].expr() for k in range(self._dim + 1))) dXdu = self._immersion.differential_functions(chart) dNdu = matrix(SR, self._dim + 1, self._dim) for i in range(self._dim + 1): for j in range(self._dim): - dNdu[i, j] = n.restrict(chart.domain()).comp( - n.restrict(chart.domain())._fmodule.bases()[0])[:, - chart][i].diff(chart[:][j]).expr() - g = self.ambient_metric().along( - self._immersion.restrict(chart.domain())).restrict( - chart.domain())[:, chart] + dNdu[i, j] = n.restrict(chart.domain()).comp(n.restrict(chart.domain())._fmodule.bases()[0])[:, chart][i].diff(chart[:][j]).expr() + g = self.ambient_metric().along(self._immersion.restrict(chart.domain())).restrict(chart.domain())[:, chart] K = dXdu.transpose() * g * (dNdu + gamma_n * dXdu) si = self._sindex for i in self.irange(): for j in self.irange(i): # since K is symmetric - resu[chart.frame(), i, j, chart] = chart.simplify( - K[i - si, j - si].expr()) + resu[chart.frame(), i, j, chart] = chart.simplify(K[i - si, j - si].expr()) self._second_fundamental_form = resu return self._second_fundamental_form @@ -1332,8 +1253,7 @@ def projector(self): 0 """ if self._ambient._dim - self._dim != 1: - raise NotImplementedError("projector() is implemented only for " - "hypersurfaces") + raise NotImplementedError("projector() is implemented only for " "hypersurfaces") g = self.ambient_metric().inverse() if self._dim_foliation == 0: g = g.along(self._immersion) @@ -1388,11 +1308,9 @@ def project(self, tensor): Note that the output of ``project()`` is not cached. """ if self._ambient._dim - self._dim != 1: - raise NotImplementedError("project() is implemented only for " - "hypersurfaces") + raise NotImplementedError("project() is implemented only for " "hypersurfaces") resu = tensor.copy() - resu.set_name(tensor._name + "_" + self._name, - r"{" + tensor._latex_() + r"}_{" + self._latex_() + r"}") + resu.set_name(tensor._name + "_" + self._name, r"{" + tensor._latex_() + r"}_{" + self._latex_() + r"}") for i in range(tensor.tensor_type()[0]): resu = self.projector().contract(1, resu, i) for i in range(tensor.tensor_type()[1]): @@ -1469,8 +1387,7 @@ def mixed_projection(self, tensor, indices=0): (th_E3, ph_E3, r_E3) ↦ 1 """ if self._ambient._dim - self._dim != 1: - raise NotImplementedError("mixed_projection() is implemented only " - "for hypersurfaces") + raise NotImplementedError("mixed_projection() is implemented only " "for hypersurfaces") if isinstance(indices, (Integer, int)): indices = list(range(indices)) @@ -1482,8 +1399,8 @@ def mixed_projection(self, tensor, indices=0): g = g.along(self._immersion) multiprojector = 1 - k = tensor.tensor_rank() # order of the tensor - kp = 2 * k - len(indices) # order of the multiprojector + k = tensor.tensor_rank() # order of the tensor + kp = 2 * k - len(indices) # order of the multiprojector for i in range(tensor.tensor_type()[1]): if i in indices: multiprojector = multiprojector * self.normal() @@ -1494,8 +1411,7 @@ def mixed_projection(self, tensor, indices=0): multiprojector = multiprojector * self.normal().contract(g) else: multiprojector = multiprojector * self.projector() - args = list(range(kp - tensor.tensor_type()[0], kp)) + list(range( - tensor.tensor_type()[1])) + [tensor] + list(range(k)) + args = list(range(kp - tensor.tensor_type()[0], kp)) + list(range(tensor.tensor_type()[1])) + [tensor] + list(range(k)) return multiprojector.contract(*args) @cached_method @@ -1540,12 +1456,9 @@ def gauss_curvature(self): on V: y ↦ -1 """ if self._ambient._dim - self._dim != 1: - raise ValueError("gauss_curvature is defined only for " - "hypersurfaces") + raise ValueError("gauss_curvature is defined only for " "hypersurfaces") a = self.shape_operator() - self._gauss_curvature = self.scalar_field( - {chart: a[chart.frame(), :, chart].determinant() - for chart in self.top_charts()}) + self._gauss_curvature = self.scalar_field({chart: a[chart.frame(), :, chart].determinant() for chart in self.top_charts()}) return self._gauss_curvature @cached_method @@ -1597,12 +1510,9 @@ def principal_directions(self, chart): e_0 = ∂/∂x """ if self._ambient._dim - self._dim != 1: - raise ValueError("principal directions is defined only for " - "hypersurfaces") + raise ValueError("principal directions is defined only for " "hypersurfaces") a = self.shape_operator() - pr_d = matrix( - [[a[chart.frame(), :, chart][i, j].expr() for i in self.irange()] - for j in self.irange()]).eigenvectors_right() + pr_d = matrix([[a[chart.frame(), :, chart][i, j].expr() for i in self.irange()] for j in self.irange()]).eigenvectors_right() res = [] v = self.vector_field() counter = self.irange() @@ -1665,16 +1575,12 @@ def principal_curvatures(self, chart): on W: y ↦ -1 """ if self._ambient._dim - self._dim != 1: - raise ValueError("principal_curvatures is defined only for " - "hypersurfaces") + raise ValueError("principal_curvatures is defined only for " "hypersurfaces") a = self.shape_operator() - res = matrix( - [[a[chart.frame(), :, chart][i, j].expr() for i in self.irange()] - for j in self.irange()]).eigenvalues() + res = matrix([[a[chart.frame(), :, chart][i, j].expr() for i in self.irange()] for j in self.irange()]).eigenvalues() counter = self.irange() for i in range(self._dim): - res[i] = self.scalar_field({chart: res[i]}, - name="k_{}".format(next(counter))) + res[i] = self.scalar_field({chart: res[i]}, name="k_{}".format(next(counter))) self._principal_curvatures[chart] = res return res @@ -1720,12 +1626,8 @@ def mean_curvature(self): on V: y ↦ -1 """ if self._ambient._dim - self._dim != 1: - raise ValueError("mean_curvature is defined only for " - "hypersurfaces") - self._shape_operator = self.scalar_field({chart: self._sgn * sum( - self.principal_curvatures(chart)).expr(chart) / self._dim - for chart in - self.top_charts()}) + raise ValueError("mean_curvature is defined only for " "hypersurfaces") + self._shape_operator = self.scalar_field({chart: self._sgn * sum(self.principal_curvatures(chart)).expr(chart) / self._dim for chart in self.top_charts()}) return self._shape_operator @cached_method @@ -1771,10 +1673,8 @@ def shape_operator(self): -∂/∂x⊗dx """ if self._ambient._dim - self._dim != 1: - raise ValueError("shape_operator is defined only for " - "hypersurfaces") - self._shape_operator = self.second_fundamental_form().contract( - self.induced_metric().inverse()) + raise ValueError("shape_operator is defined only for " "hypersurfaces") + self._shape_operator = self.second_fundamental_form().contract(self.induced_metric().inverse()) return self._shape_operator def clear_cache(self): diff --git a/src/sage/manifolds/differentiable/scalarfield.py b/src/sage/manifolds/differentiable/scalarfield.py index 72d04db04f0..9741b6d9dbc 100644 --- a/src/sage/manifolds/differentiable/scalarfield.py +++ b/src/sage/manifolds/differentiable/scalarfield.py @@ -26,7 +26,7 @@ - [ONe1983]_ """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2015, 2018 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger # @@ -34,7 +34,7 @@ # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from __future__ import annotations @@ -620,8 +620,8 @@ class DiffScalarField(ScalarField): sage: TestSuite(f).run() sage: TestSuite(zer).run() """ - def __init__(self, parent, coord_expression=None, chart=None, name=None, - latex_name=None): + + def __init__(self, parent, coord_expression=None, chart=None, name=None, latex_name=None): r""" Construct a scalar field. @@ -639,9 +639,8 @@ def __init__(self, parent, coord_expression=None, chart=None, name=None, differentiable manifold M sage: TestSuite(f).run() """ - ScalarField.__init__(self, parent, coord_expression=coord_expression, - chart=chart, name=name, latex_name=latex_name) - self._tensor_type = (0,0) + ScalarField.__init__(self, parent, coord_expression=coord_expression, chart=chart, name=name, latex_name=latex_name) + self._tensor_type = (0, 0) self._tensor_rank = 0 ####### Required methods for an algebra element (beside arithmetic) ####### @@ -657,9 +656,9 @@ def _init_derived(self): sage: f = M.scalar_field({X: x+y}) sage: f._init_derived() """ - ScalarField._init_derived(self) # derived quantities of the parent class + ScalarField._init_derived(self) # derived quantities of the parent class self._differential = None # differential 1-form of the scalar field - self._lie_derivatives = {} # dict. of Lie derivatives of self, (keys: id(vector)) + self._lie_derivatives = {} # dict. of Lie derivatives of self, (keys: id(vector)) def _del_derived(self): r""" @@ -682,7 +681,7 @@ def _del_derived(self): sage: f._restrictions # restrictions are derived quantities {} """ - ScalarField._del_derived(self) # derived quantities of the mother class + ScalarField._del_derived(self) # derived quantities of the mother class self._differential = None # reset of the differential # First deletes any reference to self in the vectors' dictionaries: for val in self._lie_derivatives.values(): @@ -793,16 +792,16 @@ def differential(self) -> DiffForm: format_unop_latex, format_unop_txt, ) + if self._differential is None: # A new computation is necessary: rname = format_unop_txt('d', self._name) rlname = format_unop_latex(r'\mathrm{d}', self._latex_name) - self._differential = self._domain.one_form(name=rname, - latex_name=rlname) + self._differential = self._domain.one_form(name=rname, latex_name=rlname) if self._is_zero: for chart in self._domain._atlas: - self._differential.add_comp(chart._frame) # since a newly - # created set of components is zero + self._differential.add_comp(chart._frame) # since a newly + # created set of components is zero else: for chart, func in self._express.items(): diff_func = self._differential.add_comp(chart._frame) @@ -812,7 +811,7 @@ def differential(self) -> DiffForm: exterior_derivative = differential # a scalar field being a 0-form derivative = differential # allows one to use functional notation, - # e.g. diff(f) for f.differential() + # e.g. diff(f) for f.differential() def lie_derivative(self, vector): r""" @@ -881,9 +880,7 @@ def lie_derivative(self, vector): lie_der = lie_derivative - def hodge_dual( - self, nondegenerate_tensor: Union[PseudoRiemannianMetric, SymplecticForm] - ) -> DiffForm: + def hodge_dual(self, nondegenerate_tensor: Union[PseudoRiemannianMetric, SymplecticForm]) -> DiffForm: r""" Compute the Hodge dual of the scalar field with respect to some non-degenerate bilinear form (Riemannian metric or symplectic form). @@ -1004,7 +1001,7 @@ def bracket(self, other): """ if isinstance(other, DiffScalarField): return self._domain.intersection(other._domain).zero_scalar_field() - return - self.differential().interior_product(other) + return -self.differential().interior_product(other) def wedge(self, other): r""" @@ -1157,12 +1154,10 @@ def gradient(self, metric=None): if self._name is not None: if default_metric: resu._name = "grad({})".format(self._name) - resu._latex_name = r"\mathrm{grad}\left(" + \ - self._latex_name + r"\right)" + resu._latex_name = r"\mathrm{grad}\left(" + self._latex_name + r"\right)" else: resu._name = "grad_{}({})".format(metric._name, self._name) - resu._latex_name = r"\mathrm{grad}_{" + metric._latex_name + \ - r"}\left(" + self._latex_name + r"\right)" + resu._latex_name = r"\mathrm{grad}_{" + metric._latex_name + r"}\left(" + self._latex_name + r"\right)" # The name is propagated to possible restrictions of self: for restrict in resu._restrictions.values(): restrict.set_name(resu._name, latex_name=resu._latex_name) @@ -1250,12 +1245,10 @@ def laplacian(self, metric=None): if self._name is not None: if default_metric: resu._name = "Delta({})".format(self._name) - resu._latex_name = r"\Delta\left(" + self._latex_name + \ - r"\right)" + resu._latex_name = r"\Delta\left(" + self._latex_name + r"\right)" else: resu._name = "Delta_{}({})".format(metric._name, self._name) - resu._latex_name = r"\Delta_{" + metric._latex_name + \ - r"}\left(" + self._latex_name + r"\right)" + resu._latex_name = r"\Delta_{" + metric._latex_name + r"}\left(" + self._latex_name + r"\right)" # The name is propagated to possible restrictions of self: for restrict in resu._restrictions.values(): restrict.set_name(resu._name, latex_name=resu._latex_name) @@ -1323,19 +1316,16 @@ def dalembertian(self, metric=None): metric = self._domain.metric() nm2 = self._manifold.dim() - 2 if metric.signature() not in [nm2, -nm2]: - raise TypeError("the {} is not a Lorentzian ".format(metric) + - "metric; use laplacian() instead") + raise TypeError("the {} is not a Lorentzian ".format(metric) + "metric; use laplacian() instead") nabla = metric.connection() resu = nabla(self.differential().up(metric)).trace() if self._name is not None: if default_metric: resu._name = "Box({})".format(self._name) - resu._latex_name = r"\Box\left(" + self._latex_name + \ - r"\right)" + resu._latex_name = r"\Box\left(" + self._latex_name + r"\right)" else: resu._name = "Box_{}({})".format(metric._name, self._name) - resu._latex_name = r"\Box_{" + metric._latex_name + \ - r"}\left(" + self._latex_name + r"\right)" + resu._latex_name = r"\Box_{" + metric._latex_name + r"}\left(" + self._latex_name + r"\right)" # The name is propagated to possible restrictions of self: for restrict in resu._restrictions.values(): restrict.set_name(resu._name, latex_name=resu._latex_name) diff --git a/src/sage/manifolds/differentiable/scalarfield_algebra.py b/src/sage/manifolds/differentiable/scalarfield_algebra.py index a4afb0ae9ad..f3e2a1d9084 100644 --- a/src/sage/manifolds/differentiable/scalarfield_algebra.py +++ b/src/sage/manifolds/differentiable/scalarfield_algebra.py @@ -20,7 +20,7 @@ class `C^k` over a topological field `K` (in - [ONe1983]_ """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger # @@ -28,7 +28,7 @@ class `C^k` over a topological field `K` (in # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.manifolds.differentiable.scalarfield import DiffScalarField from sage.manifolds.scalarfield_algebra import ScalarFieldAlgebra @@ -421,9 +421,9 @@ def _coerce_map_from_(self, other): if isinstance(other, SymbolicRing): return True # coercion from the base ring (multiplication by the - # algebra unit, i.e. self.one()) - # cf. ScalarField._lmul_() for the implementation of - # the coercion map + # algebra unit, i.e. self.one()) + # cf. ScalarField._lmul_() for the implementation of + # the coercion map if isinstance(other, DiffScalarFieldAlgebra): return self._domain.is_subset(other._domain) if isinstance(other, ChartFunctionRing): @@ -445,8 +445,7 @@ def _repr_(self): sage: repr(CM) # indirect doctest 'Algebra of differentiable scalar fields on the 2-dimensional differentiable manifold M' """ - return "Algebra of differentiable scalar fields on " + \ - "the {}".format(self._domain) + return "Algebra of differentiable scalar fields on " + "the {}".format(self._domain) def _latex_(self): r""" @@ -466,5 +465,4 @@ def _latex_(self): latex_degree = r"\infty" # to skip the "+" in latex(infinity) else: latex_degree = "{}".format(degree) - return r"C^{" + latex_degree + r"}\left(" + self._domain._latex_() + \ - r"\right)" + return r"C^{" + latex_degree + r"}\left(" + self._domain._latex_() + r"\right)" diff --git a/src/sage/manifolds/differentiable/symplectic_form.py b/src/sage/manifolds/differentiable/symplectic_form.py index 44d37a5f10f..5d7f11ea653 100644 --- a/src/sage/manifolds/differentiable/symplectic_form.py +++ b/src/sage/manifolds/differentiable/symplectic_form.py @@ -15,6 +15,7 @@ - [AM1990]_ - [RS2012]_ """ + # ***************************************************************************** # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of @@ -145,16 +146,12 @@ def __init__( if latex_name is None: latex_name = name - DiffForm.__init__( - self, vector_field_module, 2, name=name, latex_name=latex_name - ) + DiffForm.__init__(self, vector_field_module, 2, name=name, latex_name=latex_name) # Check that manifold is even dimensional dim = self._ambient_domain.dimension() if dim % 2 == 1: - raise ValueError( - f"the dimension of the manifold must be even but it is {dim}" - ) + raise ValueError(f"the dimension of the manifold must be even but it is {dim}") self._dim_half = dim // 2 # Initialization of derived quantities @@ -227,9 +224,7 @@ def _del_derived(self): self._vol_form._del_derived() self._vol_form = None - def restrict( - self, subdomain: DifferentiableManifold, dest_map: Optional[DiffMap] = None - ) -> DiffForm: + def restrict(self, subdomain: DifferentiableManifold, dest_map: Optional[DiffMap] = None) -> DiffForm: r""" Return the restriction of the symplectic form to some subdomain. @@ -271,9 +266,7 @@ def restrict( return self._restrictions[subdomain] @staticmethod - def wrap( - form: DiffForm, name: Optional[str] = None, latex_name: Optional[str] = None - ) -> SymplecticForm: + def wrap(form: DiffForm, name: Optional[str] = None, latex_name: Optional[str] = None) -> SymplecticForm: r""" Define the symplectic form from a differential form. @@ -303,9 +296,7 @@ def wrap( symplectic_form = form.base_module().symplectic_form(name, latex_name) for dom, rst in form._restrictions.items(): - symplectic_form._restrictions[dom] = SymplecticForm.wrap( - rst, name, latex_name - ) + symplectic_form._restrictions[dom] = SymplecticForm.wrap(rst, name, latex_name) if isinstance(form, DiffFormParal): for frame in form._components: @@ -313,9 +304,7 @@ def wrap( return symplectic_form - def poisson( - self, expansion_symbol: Optional[Expression] = None, order: int = 1 - ) -> PoissonTensorField: + def poisson(self, expansion_symbol: Optional[Expression] = None, order: int = 1) -> PoissonTensorField: r""" Return the Poisson tensor associated with the symplectic form. @@ -355,17 +344,13 @@ def poisson( # Initialize the Poisson tensor poisson_name = f"poisson_{self._name}" poisson_latex_name = f"{self._latex_name}^{{-1}}" - self._poisson = self._vmodule.poisson_tensor( - poisson_name, poisson_latex_name - ) + self._poisson = self._vmodule.poisson_tensor(poisson_name, poisson_latex_name) # Update the Poisson tensor # TODO: Should this be done instead when a new restriction is added? for domain, restriction in self._restrictions.items(): # Forces the update of the restriction - self._poisson._restrictions[domain] = restriction.poisson( - expansion_symbol=expansion_symbol, order=order - ) + self._poisson._restrictions[domain] = restriction.poisson(expansion_symbol=expansion_symbol, order=order) return self._poisson def hamiltonian_vector_field(self, function: DiffScalarField) -> VectorField: @@ -425,9 +410,7 @@ def flat(self, vector_field: VectorField) -> DiffForm: X_flat = 2 dq - 2 dp """ form = vector_field.down(self) - form.set_name( - vector_field._name + "_flat", vector_field._latex_name + "^\\flat" - ) + form.set_name(vector_field._name + "_flat", vector_field._latex_name + "^\\flat") return form def sharp(self, form: DiffForm) -> VectorField: @@ -463,9 +446,7 @@ def sharp(self, form: DiffForm) -> VectorField: """ return self.poisson().sharp(form) - def poisson_bracket( - self, f: DiffScalarField, g: DiffScalarField - ) -> DiffScalarField: + def poisson_bracket(self, f: DiffScalarField, g: DiffScalarField) -> DiffScalarField: r""" Return the Poisson bracket @@ -629,9 +610,7 @@ def on_forms(self, first: DiffForm, second: DiffForm) -> DiffScalarField: raise ValueError("the two forms must have the same degree") all_positions = range(first.degree()) - return first.contract( - *all_positions, second.up(self), *all_positions - ) / factorial(first.degree()) + return first.contract(*all_positions, second.up(self), *all_positions) / factorial(first.degree()) class SymplecticFormParal(SymplecticForm, DiffFormParal): @@ -663,6 +642,7 @@ class SymplecticFormParal(SymplecticForm, DiffFormParal): sage: omega.display() omega = -dq∧dp """ + _poisson: TensorFieldParal def __init__( @@ -690,16 +670,12 @@ def __init__( if name is None: name = "omega" - DiffFormParal.__init__( - self, vector_field_module, 2, name=name, latex_name=latex_name - ) + DiffFormParal.__init__(self, vector_field_module, 2, name=name, latex_name=latex_name) # Check that manifold is even dimensional dim = self._ambient_domain.dimension() if dim % 2 == 1: - raise ValueError( - f"the dimension of the manifold must be even but it is {dim}" - ) + raise ValueError(f"the dimension of the manifold must be even but it is {dim}") self._dim_half = dim // 2 # Initialization of derived quantities @@ -747,9 +723,7 @@ def _del_derived(self, del_restrictions: bool = True): SymplecticForm._del_derived(self) - def restrict( - self, subdomain: DifferentiableManifold, dest_map: Optional[DiffMap] = None - ) -> SymplecticFormParal: + def restrict(self, subdomain: DifferentiableManifold, dest_map: Optional[DiffMap] = None) -> SymplecticFormParal: r""" Return the restriction of the symplectic form to some subdomain. @@ -788,9 +762,7 @@ def restrict( self._restrictions[subdomain] = SymplecticFormParal.wrap(resu) return self._restrictions[subdomain] - def poisson( - self, expansion_symbol: Optional[Expression] = None, order: int = 1 - ) -> TensorFieldParal: + def poisson(self, expansion_symbol: Optional[Expression] = None, order: int = 1) -> TensorFieldParal: r""" Return the Poisson tensor associated with the symplectic form. @@ -831,13 +803,7 @@ def poisson( super().poisson() if expansion_symbol is not None: - if ( - self._poisson is not None - and bool(self._poisson._components) - and list(self._poisson._components.values())[0][0, 0]._expansion_symbol - == expansion_symbol - and list(self._poisson._components.values())[0][0, 0]._order == order - ): + if self._poisson is not None and bool(self._poisson._components) and list(self._poisson._components.values())[0][0, 0]._expansion_symbol == expansion_symbol and list(self._poisson._components.values())[0][0, 0]._order == order: return self._poisson if order != 1: @@ -873,32 +839,20 @@ def poisson( start_index=si, output_formatter=fmodule._output_formatter, ) - comp_poisson_scal = ( - {} - ) # dict. of scalars representing the components of the poisson tensor (keys: comp. indices) + comp_poisson_scal = {} # dict. of scalars representing the components of the poisson tensor (keys: comp. indices) for i in fmodule.irange(): for j in range(i, nsi): # symmetry taken into account comp_poisson_scal[(i, j)] = dom.scalar_field() for chart in dom.top_charts(): # TODO: do the computation without the 'SR' enforcement try: - self_matrix = matrix( - [ - [ - self.comp(frame)[i, j, chart].expr(method='SR') - for j in fmodule.irange() - ] - for i in fmodule.irange() - ] - ) + self_matrix = matrix([[self.comp(frame)[i, j, chart].expr(method='SR') for j in fmodule.irange()] for i in fmodule.irange()]) self_matrix_inv = self_matrix.inverse() except (KeyError, ValueError): continue for i in fmodule.irange(): for j in range(i, nsi): - val = chart.simplify( - -self_matrix_inv[i - si, j - si], method="SR" - ) + val = chart.simplify(-self_matrix_inv[i - si, j - si], method="SR") comp_poisson_scal[(i, j)].add_expr(val, chart=chart) for i in range(si, nsi): for j in range(i, nsi): diff --git a/src/sage/manifolds/differentiable/symplectic_form_test.py b/src/sage/manifolds/differentiable/symplectic_form_test.py index 4ef7cf81020..efd787f8e3a 100644 --- a/src/sage/manifolds/differentiable/symplectic_form_test.py +++ b/src/sage/manifolds/differentiable/symplectic_form_test.py @@ -21,17 +21,11 @@ def omega(self): return SymplecticForm(M, "omega") def test_repr(self, omega: SymplecticForm): - assert ( - str(omega) - == "Symplectic form omega on the 6-dimensional differentiable manifold M" - ) + assert str(omega) == "Symplectic form omega on the 6-dimensional differentiable manifold M" def test_new_instance_repr(self, omega: SymplecticForm): omega1 = omega._new_instance() # type: ignore reportPrivateUsage - assert ( - str(omega1) - == "Symplectic form unnamed symplectic form on the 6-dimensional differentiable manifold M" - ) + assert str(omega1) == "Symplectic form unnamed symplectic form on the 6-dimensional differentiable manifold M" def test_new_instance_same_type(self, omega: SymplecticForm): omega1 = omega._new_instance() # type: ignore reportPrivateUsage @@ -70,42 +64,28 @@ def omega(self, M): return M.symplectic_form() return SymplecticForm.wrap(M.metric().volume_form(), "omega") - def test_flat_of_hamiltonian_vector_field( - self, M: DifferentiableManifold, omega: SymplecticForm - ): + def test_flat_of_hamiltonian_vector_field(self, M: DifferentiableManifold, omega: SymplecticForm): H = generic_scalar_field(M, "H") assert omega.flat(omega.hamiltonian_vector_field(H)) == -H.differential() - def test_hamiltonian_vector_field_contr_symplectic_form( - self, M: DifferentiableManifold, omega: SymplecticForm - ): + def test_hamiltonian_vector_field_contr_symplectic_form(self, M: DifferentiableManifold, omega: SymplecticForm): H = generic_scalar_field(M, "H") # X_H \lrcorner \omega + \dif H = 0 assert omega.contract(0, omega.hamiltonian_vector_field(H)) == -H.differential() - def test_poisson_bracket_as_contraction_symplectic_form( - self, M: DifferentiableManifold, omega: SymplecticForm - ): + def test_poisson_bracket_as_contraction_symplectic_form(self, M: DifferentiableManifold, omega: SymplecticForm): f = generic_scalar_field(M, "f") g = generic_scalar_field(M, "g") # {f, g} = \omega(X_f, X_g) - assert omega.poisson_bracket(f, g) == omega.contract( - 0, omega.hamiltonian_vector_field(f) - ).contract(0, omega.hamiltonian_vector_field(g)) + assert omega.poisson_bracket(f, g) == omega.contract(0, omega.hamiltonian_vector_field(f)).contract(0, omega.hamiltonian_vector_field(g)) - def test_poisson_bracket_as_contraction_poisson_tensor( - self, M: DifferentiableManifold, omega: SymplecticForm - ): + def test_poisson_bracket_as_contraction_poisson_tensor(self, M: DifferentiableManifold, omega: SymplecticForm): f = generic_scalar_field(M, "f") g = generic_scalar_field(M, "g") # {f, g} = \pi(\dif f, \dif g) - assert omega.poisson_bracket(f, g) == omega.poisson().contract( - 0, f.exterior_derivative() - ).contract(0, g.exterior_derivative()) + assert omega.poisson_bracket(f, g) == omega.poisson().contract(0, f.exterior_derivative()).contract(0, g.exterior_derivative()) - def test_poisson_bracket_as_contraction_hamiltonian_vector_field( - self, M: DifferentiableManifold, omega: SymplecticForm - ): + def test_poisson_bracket_as_contraction_hamiltonian_vector_field(self, M: DifferentiableManifold, omega: SymplecticForm): f = generic_scalar_field(M, "f") g = generic_scalar_field(M, "g") # {f, g} = X_f (g) @@ -113,48 +93,34 @@ def test_poisson_bracket_as_contraction_hamiltonian_vector_field( # {f, g} = -X_g(f) assert omega.poisson_bracket(f, g) == -omega.hamiltonian_vector_field(g)(f) - def test_poisson_bracket_as_commutator_hamiltonian_vector_fields( - self, M: DifferentiableManifold, omega: SymplecticForm - ): + def test_poisson_bracket_as_commutator_hamiltonian_vector_fields(self, M: DifferentiableManifold, omega: SymplecticForm): f = generic_scalar_field(M, "f") g = generic_scalar_field(M, "g") # [X_f, X_g] = X_{{f,g}} - assert omega.hamiltonian_vector_field(f).bracket( - omega.hamiltonian_vector_field(g) - ) == omega.hamiltonian_vector_field(omega.poisson_bracket(f, g)) + assert omega.hamiltonian_vector_field(f).bracket(omega.hamiltonian_vector_field(g)) == omega.hamiltonian_vector_field(omega.poisson_bracket(f, g)) - def test_hodge_star_of_one_is_volume( - self, M: DifferentiableManifold, omega: SymplecticForm - ): + def test_hodge_star_of_one_is_volume(self, M: DifferentiableManifold, omega: SymplecticForm): assert M.one_scalar_field().hodge_dual(omega) == omega.volume_form() - def test_hodge_star_of_volume_is_one( - self, M: DifferentiableManifold, omega: SymplecticForm - ): + def test_hodge_star_of_volume_is_one(self, M: DifferentiableManifold, omega: SymplecticForm): assert omega.volume_form().hodge_dual(omega) == M.one_scalar_field() - def test_trace_of_two_form_is_given_using_contraction_with_omega( - self, M: DifferentiableManifold, omega: SymplecticForm - ): + def test_trace_of_two_form_is_given_using_contraction_with_omega(self, M: DifferentiableManifold, omega: SymplecticForm): a = M.diff_form(2) - a[1,2] = 3 + a[1, 2] = 3 assert a.trace(using=omega) == a.up(omega, 1).trace() - def test_omega_on_forms_is_determinant_for_decomposables( - self, M: DifferentiableManifold, omega: SymplecticForm - ): - a = M.one_form(1,2) - b = M.one_form(3,4) - c = M.one_form(5,6) - d = M.one_form(7,8) - - assert omega.on_forms(a.wedge(b), c.wedge(d)) == omega.on_forms(a,c) * omega.on_forms(b, d) - omega.on_forms(a,d) * omega.on_forms(b,c) - - def test_omega_on_one_forms_is_omega_on_dual_vectors( - self, M: DifferentiableManifold, omega: SymplecticForm - ): - a = M.one_form(1,2) - b = M.one_form(3,4) + def test_omega_on_forms_is_determinant_for_decomposables(self, M: DifferentiableManifold, omega: SymplecticForm): + a = M.one_form(1, 2) + b = M.one_form(3, 4) + c = M.one_form(5, 6) + d = M.one_form(7, 8) + + assert omega.on_forms(a.wedge(b), c.wedge(d)) == omega.on_forms(a, c) * omega.on_forms(b, d) - omega.on_forms(a, d) * omega.on_forms(b, c) + + def test_omega_on_one_forms_is_omega_on_dual_vectors(self, M: DifferentiableManifold, omega: SymplecticForm): + a = M.one_form(1, 2) + b = M.one_form(3, 4) assert omega.on_forms(a, b) == omega(a.up(omega), b.up(omega)) @@ -179,9 +145,7 @@ def test_poisson(self, omega: SymplecticForm): # TODO: Shouldn't this be written with wedge product? assert str(omega.poisson().display()) == r"poisson_omega = -e_q∧e_p" - def test_hamiltonian_vector_field( - self, M: StandardSymplecticSpace, omega: SymplecticForm - ): + def test_hamiltonian_vector_field(self, M: StandardSymplecticSpace, omega: SymplecticForm): H = generic_scalar_field(M, "H") XH = omega.hamiltonian_vector_field(H) assert str(XH.display()) == r"XH = d(H)/dp e_q - d(H)/dq e_p" @@ -193,8 +157,8 @@ def test_flat(self, M: StandardSymplecticSpace, omega: SymplecticForm): def test_hodge_star(self, M: StandardSymplecticSpace, omega: SymplecticForm): # Standard basis - e = M.one_form(0,1, name='e') - f = M.one_form(1,0, name='f') + e = M.one_form(0, 1, name='e') + f = M.one_form(1, 0, name='f') assert e.wedge(f) == omega assert M.one_scalar_field().hodge_dual(omega) == omega @@ -204,15 +168,13 @@ def test_hodge_star(self, M: StandardSymplecticSpace, omega: SymplecticForm): def test_omega_on_one_forms(self, M: StandardSymplecticSpace, omega: SymplecticForm): # Standard basis - e = M.one_form(0,1, name='e') - f = M.one_form(1,0, name='f') + e = M.one_form(0, 1, name='e') + f = M.one_form(1, 0, name='f') assert e.wedge(f) == omega assert omega.on_forms(e, f) == 1 - def test_hodge_star_is_given_using_omega_on_forms( - self, M: StandardSymplecticSpace, omega: SymplecticForm - ): - a = M.one_form(1,2) - b = M.one_form(3,4) + def test_hodge_star_is_given_using_omega_on_forms(self, M: StandardSymplecticSpace, omega: SymplecticForm): + a = M.one_form(1, 2) + b = M.one_form(3, 4) assert a.wedge(b.hodge_dual(omega)) == omega.on_forms(a, b) * omega.volume_form() diff --git a/src/sage/manifolds/differentiable/tangent_space.py b/src/sage/manifolds/differentiable/tangent_space.py index 0320b70bb93..fd799bc7037 100644 --- a/src/sage/manifolds/differentiable/tangent_space.py +++ b/src/sage/manifolds/differentiable/tangent_space.py @@ -14,7 +14,7 @@ - Chap. 3 of [Lee2013]_ """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger # @@ -22,7 +22,7 @@ # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from __future__ import annotations from typing import TYPE_CHECKING @@ -230,6 +230,7 @@ class TangentSpace(FiniteRankFreeModule): :class:`~sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule` for more documentation. """ + Element = TangentVector def __init__(self, point: ManifoldPoint, base_ring=None): @@ -254,9 +255,7 @@ def __init__(self, point: ManifoldPoint, base_ring=None): self._manif = manif if base_ring is None: base_ring = SR - FiniteRankFreeModule.__init__(self, base_ring, manif._dim, name=name, - latex_name=latex_name, - start_index=manif._sindex) + FiniteRankFreeModule.__init__(self, base_ring, manif._dim, name=name, latex_name=latex_name, start_index=manif._sindex) # Initialization of bases of the tangent space from existing vector # frames around the point: @@ -269,12 +268,7 @@ def __init__(self, point: ManifoldPoint, base_ring=None): if frame.destination_map().is_identity(): if point in frame._domain: coframe = frame.coframe() - basis = self.basis(frame._symbol, - latex_symbol=frame._latex_symbol, - indices=frame._indices, - latex_indices=frame._latex_indices, - symbol_dual=coframe._symbol, - latex_symbol_dual=coframe._latex_symbol) + basis = self.basis(frame._symbol, latex_symbol=frame._latex_symbol, indices=frame._indices, latex_indices=frame._latex_indices, symbol_dual=coframe._symbol, latex_symbol_dual=coframe._latex_symbol) self._frame_bases[frame] = basis # The basis induced by the default frame of the manifold subset # in which the point has been created is declared the default @@ -362,7 +356,7 @@ def _an_element_(self): """ resu = self.element_class(self) if self._def_basis is not None: - resu.set_comp()[:] = range(1, self._rank+1) + resu.set_comp()[:] = range(1, self._rank + 1) return resu def dimension(self): diff --git a/src/sage/manifolds/differentiable/tangent_vector.py b/src/sage/manifolds/differentiable/tangent_vector.py index 81b89e29646..29e8c047074 100644 --- a/src/sage/manifolds/differentiable/tangent_vector.py +++ b/src/sage/manifolds/differentiable/tangent_vector.py @@ -121,6 +121,7 @@ class TangentVector(FiniteRankFreeModuleElement): :class:`~sage.tensor.modules.free_module_element.FiniteRankFreeModuleElement` for more documentation. """ + def __init__(self, parent, name=None, latex_name=None): r""" Construct a tangent vector. @@ -137,8 +138,7 @@ def __init__(self, parent, name=None, latex_name=None): sage: v[:] = 5, -3/2 sage: TestSuite(v).run() """ - FiniteRankFreeModuleElement.__init__(self, parent, name=name, - latex_name=latex_name) + FiniteRankFreeModuleElement.__init__(self, parent, name=name, latex_name=latex_name) # Extra data (with respect to FiniteRankFreeModuleElement): self._point = parent._point @@ -159,6 +159,7 @@ def _repr_(self): 'Tangent vector v at Point p on the 2-dimensional differentiable manifold M' """ from sage.manifolds.differentiable.examples.euclidean import EuclideanSpace + if isinstance(self._point.parent(), EuclideanSpace): desc = "Vector" else: @@ -169,9 +170,7 @@ def _repr_(self): return desc @options(scale=1) - def plot(self, chart=None, ambient_coords=None, mapping=None, - color='blue', print_label=True, label=None, label_color=None, - fontsize=10, label_offset=0.1, parameters=None, **extra_options): + def plot(self, chart=None, ambient_coords=None, mapping=None, color='blue', print_label=True, label=None, label_color=None, fontsize=10, label_offset=0.1, parameters=None, **extra_options): r""" Plot the vector in a Cartesian graph based on the coordinates of some ambient chart. @@ -484,8 +483,7 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, ambient_coords = chart[:] # all chart coordinates are used n_pc = len(ambient_coords) if n_pc != 2 and n_pc != 3: - raise ValueError("the number of coordinates involved in the " + - "plot must be either 2 or 3, not {}".format(n_pc)) + raise ValueError("the number of coordinates involved in the " + "plot must be either 2 or 3, not {}".format(n_pc)) # indices coordinates involved in the plot: ind_pc = [chart[:].index(pc) for pc in ambient_coords] # @@ -500,21 +498,15 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, resu = Graphics() if parameters is None: coord_tail = [numerical_approx(xp[i]) for i in ind_pc] - coord_head = [numerical_approx(xp[i] + scale*vcomp[i]) - for i in ind_pc] + coord_head = [numerical_approx(xp[i] + scale * vcomp[i]) for i in ind_pc] else: - coord_tail = [numerical_approx(xp[i].substitute(parameters)) - for i in ind_pc] - coord_head = [numerical_approx( - (xp[i] + scale*vcomp[i]).substitute(parameters)) - for i in ind_pc] + coord_tail = [numerical_approx(xp[i].substitute(parameters)) for i in ind_pc] + coord_head = [numerical_approx((xp[i] + scale * vcomp[i]).substitute(parameters)) for i in ind_pc] if coord_head != coord_tail: if n_pc == 2: - resu += arrow2d(tailpoint=coord_tail, headpoint=coord_head, - color=color, **extra_options) + resu += arrow2d(tailpoint=coord_tail, headpoint=coord_head, color=color, **extra_options) else: - resu += arrow3d(coord_tail, coord_head, color=color, - **extra_options) + resu += arrow3d(coord_tail, coord_head, color=color, **extra_options) # # The label # @@ -529,11 +521,9 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, if label_color is None: label_color = color if n_pc == 2: - resu += text(label, xlab, fontsize=fontsize, - color=label_color) + resu += text(label, xlab, fontsize=fontsize, color=label_color) else: - resu += text3d(label, xlab, fontsize=fontsize, - color=label_color) + resu += text3d(label, xlab, fontsize=fontsize, color=label_color) return resu def __call__(self, f): @@ -605,11 +595,9 @@ def __call__(self, f): if isinstance(f, FreeModuleAltForm): # Case of self acting on a linear form if f.tensor_type() != (0, 1): - raise TypeError("the argument of __call__ must be a linear form, " - "not {}".format(f)) + raise TypeError("the argument of __call__ must be a linear form, " "not {}".format(f)) return f(self) if not isinstance(f, DiffScalarField): - raise TypeError("the argument of __call__ must be either a linear " - "form or a scalar field, not {}".format(f)) + raise TypeError("the argument of __call__ must be either a linear " "form or a scalar field, not {}".format(f)) # Case of self acting on a scalar field return f.differential().at(self._point)(self) diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py index 92dff677ac9..cdb32e07c04 100644 --- a/src/sage/manifolds/differentiable/tensorfield.py +++ b/src/sage/manifolds/differentiable/tensorfield.py @@ -485,19 +485,18 @@ def __init__( self._ambient_domain = vector_field_module._ambient_domain self._extensions_graph = {self._domain: self} - # dict. of known extensions of self on bigger domains, - # including self, with domains as keys. Its elements can be - # seen as incoming edges on a graph. + # dict. of known extensions of self on bigger domains, + # including self, with domains as keys. Its elements can be + # seen as incoming edges on a graph. self._restrictions_graph = {self._domain: self} - # dict. of known restrictions of self on smaller domains, - # including self, with domains as keys. Its elements can be - # seen as outgoing edges on a graph. + # dict. of known restrictions of self on smaller domains, + # including self, with domains as keys. Its elements can be + # seen as outgoing edges on a graph. - self._restrictions = {} # dict. of restrictions of self on subdomains - # of self._domain, with the subdomains as keys + self._restrictions = {} # dict. of restrictions of self on subdomains + # of self._domain, with the subdomains as keys # Treatment of symmetry declarations: - self._sym, self._antisym = CompWithSym._canonicalize_sym_antisym( - self._tensor_rank, sym, antisym) + self._sym, self._antisym = CompWithSym._canonicalize_sym_antisym(self._tensor_rank, sym, antisym) # Initialization of derived quantities: self._init_derived() @@ -559,7 +558,7 @@ def _repr_(self) -> str: Tensor field t of type (1,3) on the 2-dimensional differentiable manifold M """ # Special cases - if self._tensor_type == (0,2) and self._sym == ((0,1),): + if self._tensor_type == (0, 2) and self._sym == ((0, 1),): description = "Field of symmetric bilinear forms " if self._name is not None: description += self._name + " " @@ -568,8 +567,7 @@ def _repr_(self) -> str: description = "Tensor field " if self._name is not None: description += self._name + " " - description += "of type ({},{}) ".format( - self._tensor_type[0], self._tensor_type[1]) + description += "of type ({},{}) ".format(self._tensor_type[0], self._tensor_type[1]) return self._final_repr(description) def _latex_(self): @@ -625,8 +623,7 @@ def set_name(self, name: Optional[str] = None, latex_name: Optional[str] = None) a """ if self.is_immutable(): - raise ValueError("the name of an immutable element " - "cannot be changed") + raise ValueError("the name of an immutable element " "cannot be changed") if name is not None: self._name = name if latex_name is None: @@ -653,8 +650,7 @@ def _new_instance(self): sage: t1.parent() is t.parent() True """ - return type(self)(self._vmodule, self._tensor_type, sym=self._sym, - antisym=self._antisym, parent=self.parent()) + return type(self)(self._vmodule, self._tensor_type, sym=self._sym, antisym=self._antisym, parent=self.parent()) def _final_repr(self, description: str) -> str: r""" @@ -671,8 +667,7 @@ def _final_repr(self, description: str) -> str: if self._domain == self._ambient_domain: description += "on the {}".format(self._domain) else: - description += "along the {} ".format(self._domain) + \ - "with values on the {}".format(self._ambient_domain) + description += "along the {} ".format(self._domain) + "with values on the {}".format(self._ambient_domain) return description def _init_derived(self): @@ -685,7 +680,7 @@ def _init_derived(self): sage: t = M.tensor_field(1, 3, name='t') sage: t._init_derived() """ - self._lie_derivatives = {} # dict. of Lie derivatives of self (keys: id(vector)) + self._lie_derivatives = {} # dict. of Lie derivatives of self (keys: id(vector)) def _del_derived(self): r""" @@ -977,39 +972,28 @@ def set_restriction(self, rst: TensorField): True """ if self.is_immutable(): - raise ValueError("the restrictions of an immutable element " - "cannot be changed") + raise ValueError("the restrictions of an immutable element " "cannot be changed") if not isinstance(rst, TensorField): raise TypeError("the argument must be a tensor field") if not rst._domain.is_subset(self._domain): - raise ValueError("the domain of the declared restriction is not " + - "a subset of the field's domain") + raise ValueError("the domain of the declared restriction is not " + "a subset of the field's domain") if not rst._ambient_domain.is_subset(self._ambient_domain): - raise ValueError("the ambient domain of the declared " + - "restriction is not a subset of the " + - "field's ambient domain") + raise ValueError("the ambient domain of the declared " + "restriction is not a subset of the " + "field's ambient domain") if rst._tensor_type != self._tensor_type: - raise ValueError("the declared restriction has not the same " + - "tensor type as the current tensor field") + raise ValueError("the declared restriction has not the same " + "tensor type as the current tensor field") if rst._tensor_type != self._tensor_type: - raise ValueError("the declared restriction has not the same " + - "tensor type as the current tensor field") + raise ValueError("the declared restriction has not the same " + "tensor type as the current tensor field") if rst._sym != self._sym: - raise ValueError("the declared restriction has not the same " + - "symmetries as the current tensor field") + raise ValueError("the declared restriction has not the same " + "symmetries as the current tensor field") if rst._antisym != self._antisym: - raise ValueError("the declared restriction has not the same " + - "antisymmetries as the current tensor field") + raise ValueError("the declared restriction has not the same " + "antisymmetries as the current tensor field") if self._domain is rst._domain: self.copy_from(rst) else: - self._restrictions[rst._domain] = rst.copy(name=self._name, - latex_name=self._latex_name) + self._restrictions[rst._domain] = rst.copy(name=self._name, latex_name=self._latex_name) self._is_zero = False # a priori - def restrict( - self: T, subdomain: DifferentiableManifold, dest_map: Optional[DiffMap] = None - ) -> T: + def restrict(self: T, subdomain: DifferentiableManifold, dest_map: Optional[DiffMap] = None) -> T: r""" Return the restriction of ``self`` to some subdomain. @@ -1089,19 +1073,15 @@ def restrict( sage: vU.restrict(U) is vU True """ - if (subdomain == self._domain - and (dest_map is None or dest_map == self._vmodule._dest_map)): + if subdomain == self._domain and (dest_map is None or dest_map == self._vmodule._dest_map): return self if subdomain not in self._restrictions: if not subdomain.is_subset(self._domain): - raise ValueError("the provided domain is not a subset of " + - "the field's domain") + raise ValueError("the provided domain is not a subset of " + "the field's domain") if dest_map is None: dest_map = self._vmodule._dest_map.restrict(subdomain) elif not dest_map._codomain.is_subset(self._ambient_domain): - raise ValueError("the argument 'dest_map' is not compatible " + - "with the ambient domain of " + - "the {}".format(self)) + raise ValueError("the argument 'dest_map' is not compatible " + "with the ambient domain of " + "the {}".format(self)) # First one tries to get the restriction from a tighter domain: for dom, rst in self._restrictions.items(): if subdomain.is_subset(dom) and subdomain in rst._restrictions: @@ -1135,10 +1115,7 @@ def restrict( # If this fails, the restriction is created from scratch: smodule = subdomain.vector_field_module(dest_map=dest_map) - res = smodule.tensor(self._tensor_type, name=self._name, - latex_name=self._latex_name, sym=self._sym, - antisym=self._antisym, - specific_type=type(self)) + res = smodule.tensor(self._tensor_type, name=self._name, latex_name=self._latex_name, sym=self._sym, antisym=self._antisym, specific_type=type(self)) res._extensions_graph.update(self._extensions_graph) for dom, ext in self._extensions_graph.items(): ext._restrictions[subdomain] = res @@ -1217,7 +1194,7 @@ def _set_comp_unsafe(self, basis=None): """ if basis is None: basis = self._domain._def_frame - self._del_derived() # deletes the derived quantities + self._del_derived() # deletes the derived quantities rst = self.restrict(basis._domain, dest_map=basis._dest_map) return rst._set_comp_unsafe(basis) @@ -1286,12 +1263,11 @@ def set_comp(self, basis=None): changed """ if self.is_immutable(): - raise ValueError("the components of an immutable element " - "cannot be changed") + raise ValueError("the components of an immutable element " "cannot be changed") self._is_zero = False # a priori if basis is None: basis = self._domain._def_frame - self._del_derived() # deletes the derived quantities + self._del_derived() # deletes the derived quantities rst = self.restrict(basis._domain, dest_map=basis._dest_map) return rst.set_comp(basis=basis) @@ -1349,7 +1325,7 @@ def _add_comp_unsafe(self, basis=None): """ if basis is None: basis = self._domain._def_frame - self._del_derived() # deletes the derived quantities + self._del_derived() # deletes the derived quantities rst = self.restrict(basis._domain, dest_map=basis._dest_map) return rst._add_comp_unsafe(basis) @@ -1414,12 +1390,11 @@ def add_comp(self, basis=None) -> Components: changed """ if self.is_immutable(): - raise ValueError("the components of an immutable element " - "cannot be changed") + raise ValueError("the components of an immutable element " "cannot be changed") self._is_zero = False # a priori if basis is None: basis = self._domain._def_frame - self._del_derived() # deletes the derived quantities + self._del_derived() # deletes the derived quantities rst = self.restrict(basis._domain, dest_map=basis._dest_map) return rst.add_comp(basis=basis) @@ -1488,18 +1463,16 @@ def add_comp_by_continuation(self, frame, subdomain, chart=None): and `a` is defined on the entire manifold `S^2`. """ if self.is_immutable(): - raise ValueError("the components of an immutable element " - "cannot be changed") + raise ValueError("the components of an immutable element " "cannot be changed") dom = frame._domain if not dom.is_subset(self._domain): - raise ValueError("the vector frame is not defined on a subset " + - "of the tensor field domain") + raise ValueError("the vector frame is not defined on a subset " + "of the tensor field domain") if chart is None: chart = dom._def_chart sframe = frame.restrict(subdomain) schart = chart.restrict(subdomain) scomp = self.comp(sframe) - resu = self._add_comp_unsafe(frame) # _del_derived is performed here + resu = self._add_comp_unsafe(frame) # _del_derived is performed here for ind in resu.non_redundant_index_generator(): resu[[ind]] = dom.scalar_field({chart: scomp[[ind]].expr(schart)}) @@ -1587,15 +1560,12 @@ def add_expr_from_subdomain(self, frame, subdomain): on V: (xp, yp) ↦ 1/(xp^2 + yp^2) """ if self.is_immutable(): - raise ValueError("the expressions of an immutable element " - "cannot be changed") + raise ValueError("the expressions of an immutable element " "cannot be changed") dom = frame._domain if not dom.is_subset(self._domain): - raise ValueError("the vector frame is not defined on a subset " + - "of the tensor field domain") + raise ValueError("the vector frame is not defined on a subset " + "of the tensor field domain") if frame not in self.restrict(frame.domain())._components: - raise ValueError("the tensor doesn't have an expression in " - "the frame"+frame._repr_()) + raise ValueError("the tensor doesn't have an expression in " "the frame" + frame._repr_()) comp = self._add_comp_unsafe(frame) # the components stay the same scomp = self.restrict(subdomain).comp(frame.restrict(subdomain)) for ind in comp.non_redundant_index_generator(): @@ -1825,8 +1795,7 @@ def display(self, frame=None, chart=None): disp = display - def display_comp(self, frame=None, chart=None, coordinate_labels=True, - only_nonzero=True, only_nonredundant=False): + def display_comp(self, frame=None, chart=None, coordinate_labels=True, only_nonzero=True, only_nonredundant=False): r""" Display the tensor components with respect to a given frame, one per line. @@ -1899,19 +1868,13 @@ def display_comp(self, frame=None, chart=None, coordinate_labels=True, else: for rst in self._restrictions.values(): try: - return rst.display_comp(chart=chart, - coordinate_labels=coordinate_labels, - only_nonzero=only_nonzero, - only_nonredundant=only_nonredundant) + return rst.display_comp(chart=chart, coordinate_labels=coordinate_labels, only_nonzero=only_nonzero, only_nonredundant=only_nonredundant) except ValueError: pass if frame is None: # should be "is still None" ;-) raise ValueError("a frame must be provided for the display") rst = self.restrict(frame.domain(), dest_map=frame._dest_map) - return rst.display_comp(frame=frame, chart=chart, - coordinate_labels=coordinate_labels, - only_nonzero=only_nonzero, - only_nonredundant=only_nonredundant) + return rst.display_comp(frame=frame, chart=chart, coordinate_labels=coordinate_labels, only_nonzero=only_nonzero, only_nonredundant=only_nonredundant) def __getitem__(self, args): r""" @@ -1956,7 +1919,7 @@ def __getitem__(self, args): M → ℝ on U: (x, y) ↦ (x + 1)*y + x """ - if isinstance(args, str): # tensor with specified indices + if isinstance(args, str): # tensor with specified indices return TensorWithIndices(self, args).update() if isinstance(args, list): # case of [[...]] syntax if not isinstance(args[0], (int, Integer, slice)): @@ -2071,16 +2034,13 @@ def copy_from(self, other): False """ if self.is_immutable(): - raise ValueError("the components of an immutable element " - "cannot be changed") + raise ValueError("the components of an immutable element " "cannot be changed") if other not in self.parent(): - raise TypeError("the original must be an element of " - f"{self.parent()}") + raise TypeError("the original must be an element of " f"{self.parent()}") self._del_derived() - self._del_restrictions() # delete restrictions + self._del_restrictions() # delete restrictions for dom, rst in other._restrictions.items(): - self._restrictions[dom] = rst.copy(name=self._name, - latex_name=self._latex_name) + self._restrictions[dom] = rst.copy(name=self._name, latex_name=self._latex_name) self._is_zero = other._is_zero def copy(self, name=None, latex_name=None): @@ -2141,8 +2101,7 @@ def copy(self, name=None, latex_name=None): resu._latex_name = latex_name # set restrictions for dom, rst in self._restrictions.items(): - resu._restrictions[dom] = rst.copy(name=name, - latex_name=latex_name) + resu._restrictions[dom] = rst.copy(name=name, latex_name=latex_name) resu._is_zero = self._is_zero return resu @@ -2231,7 +2190,7 @@ def __eq__(self, other): if other is self: return True - if other in ZZ: # to compare with 0 + if other in ZZ: # to compare with 0 if other == 0: return self.is_zero() return False @@ -2250,8 +2209,7 @@ def __eq__(self, other): resu = True for dom in oc: try: - resu = resu and \ - bool(self.restrict(dom) == other.restrict(dom)) + resu = resu and bool(self.restrict(dom) == other.restrict(dom)) except ValueError: break else: @@ -2271,7 +2229,7 @@ def __eq__(self, other): resu = resu and bool(rst == other._restrictions[dom]) else: return False # the restrictions are not on the same - # subdomains + # subdomains return resu def __ne__(self, other): @@ -2338,12 +2296,13 @@ def __pos__(self): """ resu = self._new_instance() for dom, rst in self._restrictions.items(): - resu._restrictions[dom] = + rst + resu._restrictions[dom] = +rst # Compose names: from sage.tensor.modules.format_utilities import ( format_unop_latex, format_unop_txt, ) + resu._name = format_unop_txt('+', self._name) resu._latex_name = format_unop_latex(r'+', self._latex_name) return resu @@ -2384,12 +2343,13 @@ def __neg__(self): """ resu = self._new_instance() for dom, rst in self._restrictions.items(): - resu._restrictions[dom] = - rst + resu._restrictions[dom] = -rst # Compose names: from sage.tensor.modules.format_utilities import ( format_unop_latex, format_unop_txt, ) + resu._name = format_unop_txt('-', self._name) resu._latex = format_unop_latex(r'-', self._latex_name) return resu @@ -2457,8 +2417,7 @@ def _add_(self, other): some_rst = next(iter(resu_rst.values())) resu_sym = some_rst._sym resu_antisym = some_rst._antisym - resu = self._vmodule.tensor(self._tensor_type, sym=resu_sym, - antisym=resu_antisym) + resu = self._vmodule.tensor(self._tensor_type, sym=resu_sym, antisym=resu_antisym) resu._restrictions = resu_rst if self._name is not None and other._name is not None: resu._name = self._name + '+' + other._name @@ -2525,8 +2484,7 @@ def _sub_(self, other): some_rst = next(iter(resu_rst.values())) resu_sym = some_rst._sym resu_antisym = some_rst._antisym - resu = self._vmodule.tensor(self._tensor_type, sym=resu_sym, - antisym=resu_antisym) + resu = self._vmodule.tensor(self._tensor_type, sym=resu_sym, antisym=resu_antisym) resu._restrictions = resu_rst if self._name is not None and other._name is not None: resu._name = self._name + '-' + other._name @@ -2604,9 +2562,9 @@ def _rmul_(self, scalar): format_mul_latex, format_mul_txt, ) + resu_name = format_mul_txt(scalar._name, '*', self._name) - resu_latex = format_mul_latex(scalar._latex_name, r' \cdot ', - self._latex_name) + resu_latex = format_mul_latex(scalar._latex_name, r' \cdot ', self._latex_name) resu.set_name(name=resu_name, latex_name=resu_latex) return resu @@ -2713,6 +2671,7 @@ def __mul__(self, other: TensorField) -> TensorField: True """ from sage.manifolds.differentiable.mixed_form import MixedForm + if isinstance(other, MixedForm): return other.parent()(self)._mul_(other) if not isinstance(other, TensorField): @@ -2740,9 +2699,7 @@ def __mul__(self, other: TensorField) -> TensorField: resu_rst.append(self_rr * other_rr) k1, l1 = self._tensor_type k2, l2 = other._tensor_type - resu = vmodule.tensor((k1+k2, l1+l2), - sym=resu_rst[0]._sym, - antisym=resu_rst[0]._antisym) + resu = vmodule.tensor((k1 + k2, l1 + l2), sym=resu_rst[0]._sym, antisym=resu_rst[0]._antisym) for rst in resu_rst: resu._restrictions[rst._domain] = rst @@ -2884,11 +2841,11 @@ def __call__(self, *args): True """ p = len(args) - if p == 1 and self._tensor_type == (1,1): + if p == 1 and self._tensor_type == (1, 1): # type-(1,1) tensor acting as a field of tangent-space # endomorphisms: vector = args[0] - if vector._tensor_type != (1,0): + if vector._tensor_type != (1, 0): raise TypeError("the argument must be a vector field") dom_resu = self._domain.intersection(vector._domain) if dom_resu.is_manifestly_parallelizable(): @@ -2899,24 +2856,19 @@ def __call__(self, *args): else: name_resu = None if self._latex_name is not None and vector._latex_name is not None: - latex_name_resu = r"{}\left({}\right)".format(self._latex_name, - vector._latex_name) + latex_name_resu = r"{}\left({}\right)".format(self._latex_name, vector._latex_name) else: latex_name_resu = None dest_map = vector._vmodule._dest_map dest_map_resu = dest_map.restrict(dom_resu) - resu = dom_resu.vector_field(name=name_resu, - latex_name=latex_name_resu, - dest_map=dest_map_resu) + resu = dom_resu.vector_field(name=name_resu, latex_name=latex_name_resu, dest_map=dest_map_resu) for dom in self._common_subdomains(vector): if dom.is_subset(dom_resu): - resu._restrictions[dom] = \ - self._restrictions[dom](vector._restrictions[dom]) + resu._restrictions[dom] = self._restrictions[dom](vector._restrictions[dom]) return resu # Generic case if p != self._tensor_rank: - raise TypeError("{} arguments must be ".format(self._tensor_rank) + - "provided") + raise TypeError("{} arguments must be ".format(self._tensor_rank) + "provided") # Domain of the result dom_resu = self._domain ambient_dom = self._ambient_domain @@ -2952,15 +2904,15 @@ def __call__(self, *args): res_name = None if self._name is not None: res_name = self._name + "(" - for i in range(p-1): + for i in range(p - 1): if args[i]._name is not None: res_name += args[i]._name + "," else: res_name = None break if res_name is not None: - if args[p-1]._name is not None: - res_name += args[p-1]._name + ")" + if args[p - 1]._name is not None: + res_name += args[p - 1]._name + ")" else: res_name = None resu._name = res_name @@ -2968,15 +2920,15 @@ def __call__(self, *args): res_latex = None if self._latex_name is not None: res_latex = self._latex_name + r"\left(" - for i in range(p-1): + for i in range(p - 1): if args[i]._latex_name is not None: res_latex += args[i]._latex_name + "," else: res_latex = None break if res_latex is not None: - if args[p-1]._latex_name is not None: - res_latex += args[p-1]._latex_name + r"\right)" + if args[p - 1]._latex_name is not None: + res_latex += args[p - 1]._latex_name + r"\right)" else: res_latex = None resu._latex_name = res_latex @@ -2986,9 +2938,7 @@ def trace( self, pos1=0, pos2=1, - using: Optional[ - Union[PseudoRiemannianMetric, SymplecticForm, PoissonTensorField] - ] = None, + using: Optional[Union[PseudoRiemannianMetric, SymplecticForm, PoissonTensorField]] = None, ): r""" Trace (contraction) on two slots of the tensor field. @@ -3112,24 +3062,20 @@ def trace( """ if using is not None: if self.tensor_type() != (0, 2): - raise ValueError( - "trace with respect to a non-degenerate form is only defined for type-(0,2) tensor fields" - ) + raise ValueError("trace with respect to a non-degenerate form is only defined for type-(0,2) tensor fields") return self.up(using, 1).trace() # The indices at pos1 and pos2 must be of different types: k_con = self._tensor_type[0] l_cov = self._tensor_type[1] if pos1 < k_con and pos2 < k_con: - raise IndexError("contraction on two contravariant indices is " + - "not allowed") + raise IndexError("contraction on two contravariant indices is " + "not allowed") if pos1 >= k_con and pos2 >= k_con: - raise IndexError("contraction on two covariant indices is " + - "not allowed") + raise IndexError("contraction on two covariant indices is " + "not allowed") resu_rst = [] for rst in self._restrictions.values(): resu_rst.append(rst.trace(pos1, pos2)) - if (k_con, l_cov) == (1,1): + if (k_con, l_cov) == (1, 1): # scalar field result resu = self._domain.scalar_field() all_zero = True @@ -3145,8 +3091,7 @@ def trace( resu = self._domain._zero_scalar_field else: # tensor field result - resu = self._vmodule.tensor((k_con-1, l_cov-1), - sym=resu_rst[0]._sym, antisym=resu_rst[0]._antisym) + resu = self._vmodule.tensor((k_con - 1, l_cov - 1), sym=resu_rst[0]._sym, antisym=resu_rst[0]._antisym) for rst in resu_rst: resu._restrictions[rst._domain] = rst return resu @@ -3327,17 +3272,16 @@ def contract(self, *args: Union[int, TensorField]) -> TensorField: it = i break else: - raise TypeError("a tensor field must be provided in the " + - "argument list") + raise TypeError("a tensor field must be provided in the " + "argument list") if it == 0: pos1 = (self._tensor_rank - 1,) else: pos1 = args[:it] - if it == nargs-1: + if it == nargs - 1: pos2 = (0,) else: - pos2 = args[it+1:] - ncontr = len(pos1) # number of contractions + pos2 = args[it + 1 :] + ncontr = len(pos1) # number of contractions if len(pos2) != ncontr: raise IndexError("different number of indices for the contraction") if self._domain.is_subset(other._domain): @@ -3367,7 +3311,7 @@ def contract(self, *args: Union[int, TensorField]) -> TensorField: other_rr = other_r._restrictions[dom] args = pos1 + (other_rr,) + pos2 resu_rst.append(self_rr.contract(*args)) - if tensor_type_resu == (0,0): + if tensor_type_resu == (0, 0): # scalar field result resu = dom_resu.scalar_field() all_zero = True @@ -3384,12 +3328,10 @@ def contract(self, *args: Union[int, TensorField]) -> TensorField: else: # tensor field result dest_map = self._vmodule._dest_map - dest_map_resu = dest_map.restrict(dom_resu, - subcodomain=ambient_dom_resu) + dest_map_resu = dest_map.restrict(dom_resu, subcodomain=ambient_dom_resu) vmodule = dom_resu.vector_field_module(dest_map=dest_map_resu) - resu = vmodule.tensor(tensor_type_resu, sym=resu_rst[0]._sym, - antisym=resu_rst[0]._antisym) + resu = vmodule.tensor(tensor_type_resu, sym=resu_rst[0]._sym, antisym=resu_rst[0]._antisym) for rst in resu_rst: resu._restrictions[rst._domain] = rst return resu @@ -3448,8 +3390,7 @@ def symmetrize(self, *pos): resu_rst = [] for rst in self._restrictions.values(): resu_rst.append(rst.symmetrize(*pos)) - resu = self._vmodule.tensor(self._tensor_type, sym=resu_rst[0]._sym, - antisym=resu_rst[0]._antisym) + resu = self._vmodule.tensor(self._tensor_type, sym=resu_rst[0]._sym, antisym=resu_rst[0]._antisym) for rst in resu_rst: resu._restrictions[rst._domain] = rst return resu @@ -3509,8 +3450,7 @@ def antisymmetrize(self, *pos): resu_rst = [] for rst in self._restrictions.values(): resu_rst.append(rst.antisymmetrize(*pos)) - resu = self._vmodule.tensor(self._tensor_type, sym=resu_rst[0]._sym, - antisym=resu_rst[0]._antisym) + resu = self._vmodule.tensor(self._tensor_type, sym=resu_rst[0]._sym, antisym=resu_rst[0]._antisym) for rst in resu_rst: resu._restrictions[rst._domain] = rst return resu @@ -3587,7 +3527,7 @@ def lie_derivative(self, vector): sage: a.lie_der(w)(f) == w(a(f)) - a(w(f)) # long time True """ - if vector._tensor_type != (1,0): + if vector._tensor_type != (1, 0): raise TypeError("the argument must be a vector field") # The Lie derivative is cached in _lie_derivates while neither @@ -3597,9 +3537,7 @@ def lie_derivative(self, vector): resu_rst = [] for dom, rst in self._restrictions.items(): resu_rst.append(rst.lie_derivative(vector.restrict(dom))) - resu = self._vmodule.tensor(self._tensor_type, - sym=resu_rst[0]._sym, - antisym=resu_rst[0]._antisym) + resu = self._vmodule.tensor(self._tensor_type, sym=resu_rst[0]._sym, antisym=resu_rst[0]._antisym) for rst in resu_rst: resu._restrictions[rst._domain] = rst self._lie_derivatives[id(vector)] = (vector, resu) @@ -3676,8 +3614,7 @@ def at(self, point: ManifoldPoint) -> FreeModuleTensor: (5, -1) """ if point not in self._domain: - raise ValueError("the {} is not a point in the ".format(point) + - "domain of {}".format(self)) + raise ValueError("the {} is not a point in the ".format(point) + "domain of {}".format(self)) for dom, rst in self._restrictions.items(): if point in dom: return rst.at(point) @@ -3817,7 +3754,7 @@ def up( sage: dd1tuu == t # should be true True """ - n_con = self._tensor_type[0] # number of contravariant indices = k + n_con = self._tensor_type[0] # number of contravariant indices = k if pos is None: result = self for p in range(n_con, self._tensor_rank): @@ -4108,26 +4045,24 @@ def divergence(self, metric=None): sage: s.display() div(v⊗w) = -y e_x + x e_y """ - n_con = self._tensor_type[0] # number of contravariant indices = k - n_cov = self._tensor_type[1] # number of covariant indices = l + n_con = self._tensor_type[0] # number of contravariant indices = k + n_cov = self._tensor_type[1] # number of covariant indices = l default_metric = metric is None if default_metric: metric = self._domain.metric() nabla = metric.connection() if n_cov == 0: - resu = nabla(self).trace(n_con-1, n_con) + resu = nabla(self).trace(n_con - 1, n_con) else: - tup = self.up(metric, self._tensor_rank-1) + tup = self.up(metric, self._tensor_rank - 1) resu = nabla(tup).trace(n_con, self._tensor_rank) if self._name is not None: if default_metric: resu._name = "div({})".format(self._name) - resu._latex_name = r"\mathrm{div}\left(" + self._latex_name + \ - r"\right)" + resu._latex_name = r"\mathrm{div}\left(" + self._latex_name + r"\right)" else: resu._name = "div_{}({})".format(metric._name, self._name) - resu._latex_name = r"\mathrm{div}_{" + metric._latex_name + \ - r"}\left(" + self._latex_name + r"\right)" + resu._latex_name = r"\mathrm{div}_{" + metric._latex_name + r"}\left(" + self._latex_name + r"\right)" # The name is propagated to possible restrictions of self: for restrict in resu._restrictions.values(): restrict.set_name(resu._name, latex_name=resu._latex_name) @@ -4206,23 +4141,21 @@ def laplacian(self, metric=None): Delta_h(v) = -(8*x^5 - 2*x^4 - x^2*y^2 + 15*x^3 - 4*x^2 + 6*x - 2)/(x^4 + 2*x^2 + 1) e_x - 3*x^3*y/(x^4 + 2*x^2 + 1) e_y """ - n_con = self._tensor_type[0] # number of contravariant indices = k - trank = self._tensor_rank # k + l + n_con = self._tensor_type[0] # number of contravariant indices = k + trank = self._tensor_rank # k + l default_metric = metric is None if default_metric: metric = self._domain.metric() nabla = metric.connection() tmp = nabla(nabla(self).up(metric, pos=trank)) - resu = tmp.trace(n_con, trank+1) + resu = tmp.trace(n_con, trank + 1) if self._name is not None: if default_metric: resu._name = "Delta({})".format(self._name) - resu._latex_name = r"\Delta\left(" + self._latex_name + \ - r"\right)" + resu._latex_name = r"\Delta\left(" + self._latex_name + r"\right)" else: resu._name = "Delta_{}({})".format(metric._name, self._name) - resu._latex_name = r"\Delta_{" + metric._latex_name + \ - r"}\left(" + self._latex_name + r"\right)" + resu._latex_name = r"\Delta_{" + metric._latex_name + r"}\left(" + self._latex_name + r"\right)" # The name is propagated to possible restrictions of self: for restrict in resu._restrictions.values(): restrict.set_name(resu._name, latex_name=resu._latex_name) @@ -4302,18 +4235,15 @@ def dalembertian(self, metric=None): metric = self._domain.metric() nm2 = self._domain.dim() - 2 if metric.signature() not in [nm2, -nm2]: - raise TypeError("the {} is not a Lorentzian ".format(metric) + - "metric; use laplacian() instead") + raise TypeError("the {} is not a Lorentzian ".format(metric) + "metric; use laplacian() instead") resu = self.laplacian(metric=metric) if self._name is not None: if default_metric: resu._name = "Box({})".format(self._name) - resu._latex_name = r"\Box\left(" + self._latex_name + \ - r"\right)" + resu._latex_name = r"\Box\left(" + self._latex_name + r"\right)" else: resu._name = "Box_{}({})".format(metric._name, self._name) - resu._latex_name = r"\Box_{" + metric._latex_name + \ - r"}\left(" + self._latex_name + r"\right)" + resu._latex_name = r"\Box_{" + metric._latex_name + r"}\left(" + self._latex_name + r"\right)" # The name is propagated to possible restrictions of self: for restrict in resu._restrictions.values(): restrict.set_name(resu._name, latex_name=resu._latex_name) @@ -4404,8 +4334,7 @@ def along(self, mapping): """ dom = self._domain if self._ambient_domain is not dom: - raise ValueError("{} is not a tensor field ".format(self) + - "with values in the {}".format(dom)) + raise ValueError("{} is not a tensor field ".format(self) + "with values in the {}".format(dom)) if mapping.codomain().is_subset(dom): rmapping = mapping else: @@ -4415,16 +4344,13 @@ def along(self, mapping): rmapping = rest break else: - raise ValueError("the codomain of {} is not ".format(mapping) + - "included in the domain of {}".format(self)) + raise ValueError("the codomain of {} is not ".format(mapping) + "included in the domain of {}".format(self)) resu_ambient_domain = rmapping.codomain() if resu_ambient_domain.is_manifestly_parallelizable(): return self.restrict(resu_ambient_domain).along(rmapping) dom_resu = rmapping.domain() vmodule = dom_resu.vector_field_module(dest_map=rmapping) - resu = vmodule.tensor(self._tensor_type, name=self._name, - latex_name=self._latex_name, sym=self._sym, - antisym=self._antisym) + resu = vmodule.tensor(self._tensor_type, name=self._name, latex_name=self._latex_name, sym=self._sym, antisym=self._antisym) for rdom in resu_ambient_domain._parallelizable_parts: if rdom in resu_ambient_domain._top_subsets: for chart1, chart2 in rmapping._coord_expression: @@ -4521,8 +4447,7 @@ def set_calc_order(self, symbol, order, truncate=False): rst.set_calc_order(symbol, order, truncate) self._del_derived() - def apply_map(self, fun, frame=None, chart=None, - keep_other_components=False): + def apply_map(self, fun, frame=None, chart=None, keep_other_components=False): r""" Apply a function to the coordinate expressions of all components of ``self`` in a given vector frame. @@ -4646,15 +4571,15 @@ def apply_map(self, fun, frame=None, chart=None, if keep_other_components: comps = self.comp(frame)._comp else: - comps = self.set_comp(frame)._comp # set_comp() deletes the - # components in other frames + comps = self.set_comp(frame)._comp # set_comp() deletes the + # components in other frames if chart: for scalar in comps.values(): scalar.add_expr(fun(scalar.expr(chart=chart)), chart=chart) else: for scalar in comps.values(): cfunc_dict = {} # new dict of chart functions in order not to - # modify scalar._express while looping on it + # modify scalar._express while looping on it for ch, fct in scalar._express.items(): cfunc_dict[ch] = ch.function(fun(fct.expr())) scalar._express = cfunc_dict diff --git a/src/sage/manifolds/differentiable/tensorfield_module.py b/src/sage/manifolds/differentiable/tensorfield_module.py index 57445a3f63c..bfcc26442c1 100644 --- a/src/sage/manifolds/differentiable/tensorfield_module.py +++ b/src/sage/manifolds/differentiable/tensorfield_module.py @@ -238,6 +238,7 @@ class TensorFieldModule(UniqueRepresentation, ReflexiveModule_tensor): [Module X(M) of vector fields on the 2-dimensional differentiable manifold M, Module Omega^1(M) of 1-forms on the 2-dimensional differentiable manifold M] """ + Element = TensorField def __init__(self, vector_field_module, tensor_type, category=None): @@ -299,8 +300,7 @@ def __init__(self, vector_field_module, tensor_type, category=None): #### Parent methods - def _element_constructor_(self, comp=[], frame=None, name=None, - latex_name=None, sym=None, antisym=None): + def _element_constructor_(self, comp=[], frame=None, name=None, latex_name=None, sym=None, antisym=None): r""" Construct a tensor field. @@ -328,70 +328,50 @@ def _element_constructor_(self, comp=[], frame=None, name=None, return self.zero() if isinstance(comp, DiffForm): # coercion of a p-form to a type-(0,p) tensor field: - form = comp # for readability + form = comp # for readability p = form.degree() - if (self._tensor_type != (0,p) or - self._vmodule != form.base_module()): - raise TypeError("cannot convert the {}".format(form) + - " to an element of {}".format(self)) + if self._tensor_type != (0, p) or self._vmodule != form.base_module(): + raise TypeError("cannot convert the {}".format(form) + " to an element of {}".format(self)) if p == 1: asym = None else: asym = range(p) - resu = self.element_class(self._vmodule, (0,p), - name=form._name, - latex_name=form._latex_name, - antisym=asym) + resu = self.element_class(self._vmodule, (0, p), name=form._name, latex_name=form._latex_name, antisym=asym) for dom, rst in form._restrictions.items(): - resu._restrictions[dom] = dom.tensor_field_module((0,p))(rst) + resu._restrictions[dom] = dom.tensor_field_module((0, p))(rst) return resu if isinstance(comp, MultivectorField): # coercion of a p-vector field to a type-(p,0) tensor: - pvect = comp # for readability + pvect = comp # for readability p = pvect.degree() - if (self._tensor_type != (p,0) or - self._vmodule != pvect.base_module()): - raise TypeError("cannot convert the {}".format(pvect) + - " to an element of {}".format(self)) + if self._tensor_type != (p, 0) or self._vmodule != pvect.base_module(): + raise TypeError("cannot convert the {}".format(pvect) + " to an element of {}".format(self)) if p == 1: asym = None else: asym = range(p) - resu = self.element_class(self._vmodule, (p,0), - name=pvect._name, - latex_name=pvect._latex_name, - antisym=asym) + resu = self.element_class(self._vmodule, (p, 0), name=pvect._name, latex_name=pvect._latex_name, antisym=asym) for dom, rst in pvect._restrictions.items(): - resu._restrictions[dom] = dom.tensor_field_module((p,0))(rst) + resu._restrictions[dom] = dom.tensor_field_module((p, 0))(rst) return resu if isinstance(comp, AutomorphismField): # coercion of an automorphism to a type-(1,1) tensor: - autom = comp # for readability - if (self._tensor_type != (1,1) or - self._vmodule != autom.base_module()): - raise TypeError("cannot convert the {}".format(autom) + - " to an element of {}".format(self)) - resu = self.element_class(self._vmodule, (1,1), - name=autom._name, - latex_name=autom._latex_name) + autom = comp # for readability + if self._tensor_type != (1, 1) or self._vmodule != autom.base_module(): + raise TypeError("cannot convert the {}".format(autom) + " to an element of {}".format(self)) + resu = self.element_class(self._vmodule, (1, 1), name=autom._name, latex_name=autom._latex_name) for dom, rest in autom._restrictions.items(): - resu._restrictions[dom] = dom.tensor_field_module((1,1))(rest) + resu._restrictions[dom] = dom.tensor_field_module((1, 1))(rest) return resu if isinstance(comp, TensorField): # coercion by domain restriction - if (self._tensor_type == comp._tensor_type - and self._domain.is_subset(comp._domain) - and self._ambient_domain.is_subset(comp._ambient_domain)): + if self._tensor_type == comp._tensor_type and self._domain.is_subset(comp._domain) and self._ambient_domain.is_subset(comp._ambient_domain): return comp.restrict(self._domain) - raise TypeError("cannot convert the {}".format(comp) + - " to an element of {}".format(self)) + raise TypeError("cannot convert the {}".format(comp) + " to an element of {}".format(self)) if not isinstance(comp, (list, tuple)): - raise TypeError("cannot convert the {} ".format(comp) + - "to an element of {}".format(self)) + raise TypeError("cannot convert the {} ".format(comp) + "to an element of {}".format(self)) # standard construction - resu = self.element_class(self._vmodule, self._tensor_type, - name=name, latex_name=latex_name, - sym=sym, antisym=antisym) + resu = self.element_class(self._vmodule, self._tensor_type, name=name, latex_name=latex_name, sym=sym, antisym=antisym) if comp: resu.set_comp(frame)[:] = comp return resu @@ -449,23 +429,19 @@ def _coerce_map_from_(self, other): ) from sage.manifolds.differentiable.diff_form_module import DiffFormModule from sage.manifolds.differentiable.multivector_module import MultivectorModule + if isinstance(other, (TensorFieldModule, TensorFieldFreeModule)): # coercion by domain restriction - return (self._tensor_type == other._tensor_type - and self._domain.is_subset(other._domain) - and self._ambient_domain.is_subset(other._ambient_domain)) + return self._tensor_type == other._tensor_type and self._domain.is_subset(other._domain) and self._ambient_domain.is_subset(other._ambient_domain) if isinstance(other, DiffFormModule): # coercion of p-forms to type-(0,p) tensor fields - return (self._vmodule is other.base_module() - and self._tensor_type == (0, other.degree())) + return self._vmodule is other.base_module() and self._tensor_type == (0, other.degree()) if isinstance(other, MultivectorModule): # coercion of p-vector fields to type-(p,0) tensor fields - return (self._vmodule is other.base_module() - and self._tensor_type == (other.degree(),0)) + return self._vmodule is other.base_module() and self._tensor_type == (other.degree(), 0) if isinstance(other, AutomorphismFieldGroup): # coercion of automorphism fields to type-(1,1) tensor fields - return (self._vmodule is other.base_module() - and self._tensor_type == (1,1)) + return self._vmodule is other.base_module() and self._tensor_type == (1, 1) return False #### End of parent methods @@ -489,14 +465,12 @@ def _repr_(self): description = "Module " if self._name is not None: description += self._name + " " - description += "of type-({},{})".format(self._tensor_type[0], - self._tensor_type[1]) + description += "of type-({},{})".format(self._tensor_type[0], self._tensor_type[1]) description += " tensors fields " if self._dest_map is self._domain.identity_map(): description += "on the {}".format(self._domain) else: - description += "along the {}".format(self._domain) + \ - " mapped into the {}".format(self._ambient_domain) + description += "along the {}".format(self._domain) + " mapped into the {}".format(self._ambient_domain) return description def _latex_(self): @@ -585,7 +559,8 @@ def zero(self): resu.set_immutable() return resu -#*********************************************************************** + +# *********************************************************************** class TensorFieldFreeModule(TensorFreeModule): @@ -730,6 +705,7 @@ class TensorFieldFreeModule(TensorFreeModule): [0 1 0] [0 0 1] """ + Element = TensorFieldParal def __init__(self, vector_field_module, tensor_type): @@ -755,8 +731,7 @@ def __init__(self, vector_field_module, tensor_type): kcon = tensor_type[0] lcov = tensor_type[1] name = "T^({},{})({}".format(kcon, lcov, domain._name) - latex_name = r"\mathcal{{T}}^{{({}, {})}}\left({}".format(kcon, - lcov, domain._latex_name) + latex_name = r"\mathcal{{T}}^{{({}, {})}}\left({}".format(kcon, lcov, domain._latex_name) if dest_map is not domain.identity_map(): dm_name = dest_map._name dm_latex_name = dest_map._latex_name @@ -768,16 +743,14 @@ def __init__(self, vector_field_module, tensor_type): latex_name += "," + dm_latex_name name += ")" latex_name += r"\right)" - TensorFreeModule.__init__(self, vector_field_module, tensor_type, - name=name, latex_name=latex_name) + TensorFreeModule.__init__(self, vector_field_module, tensor_type, name=name, latex_name=latex_name) self._domain = domain self._dest_map = dest_map self._ambient_domain = vector_field_module._ambient_domain #### Parent methods - def _element_constructor_(self, comp=[], frame=None, name=None, - latex_name=None, sym=None, antisym=None): + def _element_constructor_(self, comp=[], frame=None, name=None, latex_name=None, sym=None, antisym=None): r""" Construct a tensor field. @@ -805,71 +778,50 @@ def _element_constructor_(self, comp=[], frame=None, name=None, return self.zero() if isinstance(comp, DiffFormParal): # coercion of a p-form to a type-(0,p) tensor field: - form = comp # for readability + form = comp # for readability p = form.degree() - if (self._tensor_type != (0,p) or - self._fmodule != form.base_module()): - raise TypeError("cannot convert the {}".format(form) + - " to an element of {}".format(self)) + if self._tensor_type != (0, p) or self._fmodule != form.base_module(): + raise TypeError("cannot convert the {}".format(form) + " to an element of {}".format(self)) if p == 1: asym = None else: asym = range(p) - resu = self.element_class(self._fmodule, (0,p), - name=form._name, - latex_name=form._latex_name, - antisym=asym) + resu = self.element_class(self._fmodule, (0, p), name=form._name, latex_name=form._latex_name, antisym=asym) for frame, cp in form._components.items(): resu._components[frame] = cp.copy() return resu if isinstance(comp, MultivectorFieldParal): # coercion of a p-vector field to a type-(p,0) tensor field: - pvect = comp # for readability + pvect = comp # for readability p = pvect.degree() - if (self._tensor_type != (p,0) or - self._fmodule != pvect.base_module()): - raise TypeError("cannot convert the {}".format(pvect) + - " to an element of {}".format(self)) + if self._tensor_type != (p, 0) or self._fmodule != pvect.base_module(): + raise TypeError("cannot convert the {}".format(pvect) + " to an element of {}".format(self)) if p == 1: asym = None else: asym = range(p) - resu = self.element_class(self._fmodule, (p,0), - name=pvect._name, - latex_name=pvect._latex_name, - antisym=asym) + resu = self.element_class(self._fmodule, (p, 0), name=pvect._name, latex_name=pvect._latex_name, antisym=asym) for frame, cp in pvect._components.items(): resu._components[frame] = cp.copy() return resu if isinstance(comp, AutomorphismFieldParal): # coercion of an automorphism to a type-(1,1) tensor: - autom = comp # for readability - if (self._tensor_type != (1,1) or - self._fmodule != autom.base_module()): - raise TypeError("cannot convert the {}".format(autom) + - " to an element of {}".format(self)) - resu = self.element_class(self._fmodule, (1,1), - name=autom._name, - latex_name=autom._latex_name) + autom = comp # for readability + if self._tensor_type != (1, 1) or self._fmodule != autom.base_module(): + raise TypeError("cannot convert the {}".format(autom) + " to an element of {}".format(self)) + resu = self.element_class(self._fmodule, (1, 1), name=autom._name, latex_name=autom._latex_name) for basis, comp in autom._components.items(): resu._components[basis] = comp.copy() return resu if isinstance(comp, TensorField): # coercion by domain restriction - if (self._tensor_type == comp._tensor_type - and self._domain.is_subset(comp._domain) - and self._ambient_domain.is_subset( - comp._ambient_domain)): + if self._tensor_type == comp._tensor_type and self._domain.is_subset(comp._domain) and self._ambient_domain.is_subset(comp._ambient_domain): return comp.restrict(self._domain) - raise TypeError("cannot convert the {}".format(comp) + - " to an element of {}".format(self)) + raise TypeError("cannot convert the {}".format(comp) + " to an element of {}".format(self)) if not isinstance(comp, (list, tuple)): - raise TypeError("cannot convert the {} ".format(comp) + - "to an element of {}".format(self)) + raise TypeError("cannot convert the {} ".format(comp) + "to an element of {}".format(self)) # Standard construction - resu = self.element_class(self._fmodule, self._tensor_type, - name=name, latex_name=latex_name, - sym=sym, antisym=antisym) + resu = self.element_class(self._fmodule, self._tensor_type, name=name, latex_name=latex_name, sym=sym, antisym=antisym) if comp: resu.set_comp(frame)[:] = comp return resu @@ -907,23 +859,19 @@ def _coerce_map_from_(self, other): from sage.manifolds.differentiable.multivector_module import ( MultivectorFreeModule, ) + if isinstance(other, (TensorFieldModule, TensorFieldFreeModule)): # coercion by domain restriction - return (self._tensor_type == other._tensor_type - and self._domain.is_subset(other._domain) - and self._ambient_domain.is_subset(other._ambient_domain)) + return self._tensor_type == other._tensor_type and self._domain.is_subset(other._domain) and self._ambient_domain.is_subset(other._ambient_domain) if isinstance(other, DiffFormFreeModule): # coercion of p-forms to type-(0,p) tensor fields - return (self._fmodule is other.base_module() - and self._tensor_type == (0, other.degree())) + return self._fmodule is other.base_module() and self._tensor_type == (0, other.degree()) if isinstance(other, MultivectorFreeModule): # coercion of p-vector fields to type-(p,0) tensor fields - return (self._fmodule is other.base_module() - and self._tensor_type == (other.degree(),0)) + return self._fmodule is other.base_module() and self._tensor_type == (other.degree(), 0) if isinstance(other, AutomorphismFieldParalGroup): # coercion of automorphism fields to type-(1,1) tensor fields - return (self._fmodule is other.base_module() - and self._tensor_type == (1,1)) + return self._fmodule is other.base_module() and self._tensor_type == (1, 1) return False #### End of parent methods @@ -948,12 +896,10 @@ def _repr_(self): description = "Free module " if self._name is not None: description += self._name + " " - description += "of type-({},{})".format(self._tensor_type[0], - self._tensor_type[1]) + description += "of type-({},{})".format(self._tensor_type[0], self._tensor_type[1]) description += " tensors fields " if self._dest_map is self._domain.identity_map(): description += "on the {}".format(self._domain) else: - description += "along the {}".format(self._domain) + \ - " mapped into the {}".format(self._ambient_domain) + description += "along the {}".format(self._domain) + " mapped into the {}".format(self._ambient_domain) return description diff --git a/src/sage/manifolds/differentiable/tensorfield_paral.py b/src/sage/manifolds/differentiable/tensorfield_paral.py index 7e6b9adb0d4..128314afb60 100644 --- a/src/sage/manifolds/differentiable/tensorfield_paral.py +++ b/src/sage/manifolds/differentiable/tensorfield_paral.py @@ -613,8 +613,8 @@ class TensorFieldParal(FreeModuleTensor, TensorField): sage: h.display() h = (t + 1) ∂/∂x⊗∂/∂x + t^2 ∂/∂x⊗∂/∂y + sin(t) ∂/∂z⊗∂/∂x """ - def __init__(self, vector_field_module, tensor_type, name=None, - latex_name=None, sym=None, antisym=None): + + def __init__(self, vector_field_module, tensor_type, name=None, latex_name=None, sym=None, antisym=None): r""" Construct a tensor field. @@ -638,9 +638,7 @@ def __init__(self, vector_field_module, tensor_type, name=None, 2-dimensional differentiable manifold M sage: TestSuite(t).run() """ - FreeModuleTensor.__init__(self, vector_field_module, tensor_type, - name=name, latex_name=latex_name, - sym=sym, antisym=antisym) + FreeModuleTensor.__init__(self, vector_field_module, tensor_type, name=name, latex_name=latex_name, sym=sym, antisym=antisym) # TensorField attributes: self._vmodule = vector_field_module self._domain = vector_field_module._domain @@ -689,8 +687,7 @@ def _new_instance(self): sage: type(t._new_instance()) is type(t) True """ - return type(self)(self._fmodule, self._tensor_type, sym=self._sym, - antisym=self._antisym) + return type(self)(self._fmodule, self._tensor_type, sym=self._sym, antisym=self._antisym) def _init_derived(self): r""" @@ -705,8 +702,8 @@ def _init_derived(self): """ FreeModuleTensor._init_derived(self) TensorField._init_derived(self) - self._restrictions = {} # dict. of restrictions of self on subdomains - # of self._domain, with the subdomains as keys + self._restrictions = {} # dict. of restrictions of self on subdomains + # of self._domain, with the subdomains as keys self._extensions_graph = {self._domain: self} self._restrictions_graph = {self._domain: self} @@ -916,8 +913,7 @@ class :class:`~sage.tensor.modules.comp.Components`; if such in the Vector frame (M, (e_0,e_1)) """ if self.is_immutable(): - raise ValueError("the components of an immutable element " - "cannot be changed") + raise ValueError("the components of an immutable element " "cannot be changed") if basis is None: basis = self._fmodule._def_basis @@ -1092,8 +1088,7 @@ class :class:`~sage.tensor.modules.comp.Components`; if such t = x e_0⊗e^1 """ if self.is_immutable(): - raise ValueError("the components of an immutable element " - "cannot be changed") + raise ValueError("the components of an immutable element " "cannot be changed") if basis is None: basis = self._fmodule._def_basis @@ -1164,8 +1159,7 @@ class :class:`~sage.tensor.modules.comp.Components` if basis._domain == self._domain: # components on the tensor field domain: - return FreeModuleTensor.comp(self, basis=basis, - from_basis=from_basis) + return FreeModuleTensor.comp(self, basis=basis, from_basis=from_basis) # components on a subdomain: rst = self.restrict(basis._domain, dest_map=basis._dest_map) @@ -1231,6 +1225,7 @@ def _common_coord_frame(self, other): + (-1/2*x^2 + 1/2*y^2 + 1/2*x + 1/2*y + 1/2) ∂/∂y """ from sage.manifolds.differentiable.vectorframe import CoordFrame + # Compatibility checks: if not isinstance(other, TensorFieldParal): raise TypeError("the argument must be of type TensorFieldParal") @@ -1241,10 +1236,8 @@ def _common_coord_frame(self, other): # without performing any component transformation. # ------------------------------------------------------------- # 1a/ Direct search - if (def_frame in self._components - and def_frame in other._components - and isinstance(dom._def_frame, CoordFrame)): - return def_frame # the domain's default frame is privileged + if def_frame in self._components and def_frame in other._components and isinstance(dom._def_frame, CoordFrame): + return def_frame # the domain's default frame is privileged for frame1 in self._components: if frame1 in other._components and isinstance(frame1, CoordFrame): return frame1 @@ -1298,16 +1291,12 @@ def _common_coord_frame(self, other): # two component transformations to get a common frame for sframe in self._components: for oframe in other._components: - if ((sframe, def_frame) in dom._frame_changes - and (oframe, def_frame) in dom._frame_changes - and isinstance(def_frame, CoordFrame)): + if (sframe, def_frame) in dom._frame_changes and (oframe, def_frame) in dom._frame_changes and isinstance(def_frame, CoordFrame): self.comp(def_frame, from_basis=sframe) other.comp(def_frame, from_basis=oframe) return def_frame for frame in dom._frames: - if ((sframe, frame) in dom._frame_changes - and (oframe, frame) in dom._frame_changes - and isinstance(frame, CoordFrame)): + if (sframe, frame) in dom._frame_changes and (oframe, frame) in dom._frame_changes and isinstance(frame, CoordFrame): self.comp(frame, from_basis=sframe) other.comp(frame, from_basis=oframe) return frame @@ -1392,7 +1381,7 @@ def lie_derivative(self, vector): ....: + om(v).exterior_derivative()) True """ - if vector._tensor_type != (1,0): + if vector._tensor_type != (1, 0): raise TypeError("the argument must be a vector field") # The Lie derivative is stored in the dictionary @@ -1417,15 +1406,15 @@ def lie_derivative(self, vector): if nproc != 1: # Parallel computation - lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] + lol = lambda lst, sz: [lst[i : i + sz] for i in range(0, len(lst), sz)] ind_list = list(resc.non_redundant_index_generator()) ind_step = max(1, len(ind_list) // nproc) local_list = lol(ind_list, ind_step) # list of input parameters: listParalInput = [(self, vector, coord_frame, chart, ind_part) for ind_part in local_list] - @parallel(p_iter='multiprocessing',ncpus=nproc) - def paral_lie_deriv(a, b , coord_frame, chart_cp, local_list_ind): + @parallel(p_iter='multiprocessing', ncpus=nproc) + def paral_lie_deriv(a, b, coord_frame, chart_cp, local_list_ind): # # 2/ Component computation: tc = a._components[coord_frame] @@ -1438,33 +1427,30 @@ def paral_lie_deriv(a, b , coord_frame, chart_cp, local_list_ind): for ind in local_list_ind: rsum = 0 for i in vf_module.irange(): - rsum += vc[[i]].coord_function(chart_cp) * \ - tc[[ind]].coord_function(chart_cp).diff(i) + rsum += vc[[i]].coord_function(chart_cp) * tc[[ind]].coord_function(chart_cp).diff(i) # loop on contravariant indices: for k in range(n_con): for i in vf_module.irange(): indk = list(ind) indk[k] = i - rsum -= tc[[indk]].coord_function(chart_cp) * \ - vc[[ind[k]]].coord_function(chart_cp).diff(i) + rsum -= tc[[indk]].coord_function(chart_cp) * vc[[ind[k]]].coord_function(chart_cp).diff(i) # loop on covariant indices: for k in range(n_con, a._tensor_rank): for i in vf_module.irange(): indk = list(ind) indk[k] = i - rsum += tc[[indk]].coord_function(chart_cp) * \ - vc[[i]].coord_function(chart_cp).diff(ind[k]) + rsum += tc[[indk]].coord_function(chart_cp) * vc[[i]].coord_function(chart_cp).diff(ind[k]) local_res.append([ind, rsum.scalar_field()]) return local_res # call to parallel lie derivative - for ii,val in paral_lie_deriv(listParalInput): + for ii, val in paral_lie_deriv(listParalInput): for jj in val: resc[[jj[0]]] = jj[1] - else : + else: # Sequential computation # # 2/ Component computation: @@ -1476,22 +1462,19 @@ def paral_lie_deriv(a, b , coord_frame, chart_cp, local_list_ind): for ind in resc.non_redundant_index_generator(): rsum = 0 for i in vf_module.irange(): - rsum += vc[[i]].coord_function(chart) * \ - tc[[ind]].coord_function(chart).diff(i) + rsum += vc[[i]].coord_function(chart) * tc[[ind]].coord_function(chart).diff(i) # loop on contravariant indices: for k in range(n_con): for i in vf_module.irange(): indk = list(ind) indk[k] = i - rsum -= tc[[indk]].coord_function(chart) * \ - vc[[ind[k]]].coord_function(chart).diff(i) + rsum -= tc[[indk]].coord_function(chart) * vc[[ind[k]]].coord_function(chart).diff(i) # loop on covariant indices: for k in range(n_con, self._tensor_rank): for i in vf_module.irange(): indk = list(ind) indk[k] = i - rsum += tc[[indk]].coord_function(chart) * \ - vc[[i]].coord_function(chart).diff(ind[k]) + rsum += tc[[indk]].coord_function(chart) * vc[[i]].coord_function(chart).diff(ind[k]) resc[[ind]] = rsum.scalar_field() # @@ -1564,20 +1547,15 @@ def restrict(self, subdomain: DifferentiableManifold, dest_map: Optional[DiffMap sage: v.restrict(M) is v True """ - if (subdomain == self._domain - and (dest_map is None or dest_map == self._vmodule._dest_map)): + if subdomain == self._domain and (dest_map is None or dest_map == self._vmodule._dest_map): return self if subdomain not in self._restrictions: if not subdomain.is_subset(self._domain): - raise ValueError( - f"the provided domain {subdomain} is not a subset of the field's domain {self._domain}" - ) + raise ValueError(f"the provided domain {subdomain} is not a subset of the field's domain {self._domain}") if dest_map is None: dest_map = self._fmodule._dest_map.restrict(subdomain) elif not dest_map._codomain.is_subset(self._ambient_domain): - raise ValueError("the argument 'dest_map' is not compatible " + - "with the ambient domain of " + - "the {}".format(self)) + raise ValueError("the argument 'dest_map' is not compatible " + "with the ambient domain of " + "the {}".format(self)) # First one tries to derive the restriction from a tighter domain: for dom, rst in self._restrictions.items(): if subdomain.is_subset(dom) and subdomain in rst._restrictions: @@ -1611,16 +1589,11 @@ def restrict(self, subdomain: DifferentiableManifold, dest_map: Optional[DiffMap # If this fails, the restriction is created from scratch: smodule = subdomain.vector_field_module(dest_map=dest_map) - res = smodule.tensor(self._tensor_type, name=self._name, - latex_name=self._latex_name, sym=self._sym, - antisym=self._antisym, - specific_type=type(self)) + res = smodule.tensor(self._tensor_type, name=self._name, latex_name=self._latex_name, sym=self._sym, antisym=self._antisym, specific_type=type(self)) for frame in self._components: for sframe in subdomain._frames: - if (sframe.domain() is subdomain and - sframe.destination_map() is dest_map and - sframe in frame._subframes): + if sframe.domain() is subdomain and sframe.destination_map() is dest_map and sframe in frame._subframes: comp_store = self._components[frame]._comp scomp = res._new_comp(sframe) scomp_store = scomp._comp @@ -1704,11 +1677,12 @@ def __call__(self, *args): True """ from sage.categories.homset import End + p = len(args) - if p == 1 and self._tensor_type == (1,1): + if p == 1 and self._tensor_type == (1, 1): # type-(1,1) tensor acting as an endomorphism: vector = args[0] - if vector._tensor_type != (1,0): + if vector._tensor_type != (1, 0): raise TypeError("the argument must be a vector field") dom = self._domain.intersection(vector._domain) sd = self.restrict(dom) @@ -1717,8 +1691,7 @@ def __call__(self, *args): return endom(vd) # Generic case if p != self._tensor_rank: - raise TypeError("{} arguments must be ".format(self._tensor_rank) + - "provided") + raise TypeError("{} arguments must be ".format(self._tensor_rank) + "provided") # Domain of the result dom_resu = self._domain for arg in args: @@ -1857,8 +1830,7 @@ def __mul__(self, other): # the FreeModuleTensor one return TensorField.__mul__(self, other) - def display_comp(self, frame=None, chart=None, coordinate_labels=True, - only_nonzero=True, only_nonredundant=False): + def display_comp(self, frame=None, chart=None, coordinate_labels=True, only_nonzero=True, only_nonredundant=False): r""" Display the tensor components with respect to a given frame, one per line. @@ -1977,6 +1949,7 @@ def display_comp(self, frame=None, chart=None, coordinate_labels=True, """ from sage.manifolds.differentiable.vectorframe import CoordFrame from sage.misc.latex import latex + if frame is None: if chart is not None: frame = chart.frame() @@ -1990,11 +1963,7 @@ def display_comp(self, frame=None, chart=None, coordinate_labels=True, ch = frame.chart() index_labels = list(map(str, ch[:])) index_latex_labels = list(map(latex, ch[:])) - return FreeModuleTensor.display_comp(self, basis=frame, - format_spec=chart, index_labels=index_labels, - index_latex_labels=index_latex_labels, - only_nonzero=only_nonzero, - only_nonredundant=only_nonredundant) + return FreeModuleTensor.display_comp(self, basis=frame, format_spec=chart, index_labels=index_labels, index_latex_labels=index_latex_labels, only_nonzero=only_nonzero, only_nonredundant=only_nonredundant) def at(self, point): r""" @@ -2112,17 +2081,14 @@ def at(self, point): v = (1/6*pi + 1) ∂/∂x + 1/36*pi^2 ∂/∂y """ if point not in self._domain: - raise ValueError("the {} is not in the domain of ".format(point) + - "the {}".format(self)) + raise ValueError("the {} is not in the domain of ".format(point) + "the {}".format(self)) dest_map = self._fmodule._dest_map if dest_map.is_identity(): amb_point = point else: amb_point = dest_map(point) # "ambient" point ts = amb_point._manifold.tangent_space(amb_point) - resu = ts.tensor(self._tensor_type, name=self._name, - latex_name=self._latex_name, sym=self._sym, - antisym=self._antisym) + resu = ts.tensor(self._tensor_type, name=self._name, latex_name=self._latex_name, sym=self._sym, antisym=self._antisym) for frame, comp in self._components.items(): comp_resu = resu.add_comp(frame.at(point)) for ind, val in comp._comp.items(): @@ -2204,8 +2170,7 @@ def along(self, mapping): """ dom = self._domain if self._ambient_domain is not dom: - raise ValueError("{} is not a tensor field ".format(self) + - "with values in the {}".format(dom)) + raise ValueError("{} is not a tensor field ".format(self) + "with values in the {}".format(dom)) if mapping.codomain().is_subset(dom): rmapping = mapping else: @@ -2215,13 +2180,10 @@ def along(self, mapping): rmapping = rest break else: - raise ValueError("the codomain of {} is not ".format(mapping) + - "included in the domain of {}".format(self)) + raise ValueError("the codomain of {} is not ".format(mapping) + "included in the domain of {}".format(self)) dom_resu = rmapping.domain() vmodule = dom_resu.vector_field_module(dest_map=rmapping) - resu = vmodule.tensor(self._tensor_type, name=self._name, - latex_name=self._latex_name, sym=self._sym, - antisym=self._antisym) + resu = vmodule.tensor(self._tensor_type, name=self._name, latex_name=self._latex_name, sym=self._sym, antisym=self._antisym) for frame, comp in self._components.items(): comp_resu = resu.add_comp(frame.along(rmapping)) for ind, val in comp._comp.items(): @@ -2235,9 +2197,7 @@ def along(self, mapping): coord2_1 = phi(*(chart1._xx)) val_resu.add_expr(func2(*coord2_1), chart=chart1) if not val_resu._express: - raise ValueError("no pair of charts has been found to " + - "set the value of the component " + - "{} in the {}".format(ind, frame)) + raise ValueError("no pair of charts has been found to " + "set the value of the component " + "{} in the {}".format(ind, frame)) comp_resu._comp[ind] = val_resu return resu @@ -2305,25 +2265,21 @@ def series_expansion(self, symbol: Expression, order: int) -> list[TensorFieldPa True """ from sage.tensor.modules.comp import Components + orderp1 = order + 1 res = [0] * orderp1 for k in range(orderp1): - res[k] = self.domain().tensor_field(*self.tensor_type(), - dest_map=self._fmodule._dest_map, - sym=self._sym, - antisym=self._antisym) + res[k] = self.domain().tensor_field(*self.tensor_type(), dest_map=self._fmodule._dest_map, sym=self._sym, antisym=self._antisym) for frame in self._components: decompo = {} comp = self.comp(frame) res_comp = [0] * orderp1 for inds in comp.index_generator(): - decompo[inds] = comp[inds].expr().series(symbol, - orderp1).truncate().coefficients(symbol) + decompo[inds] = comp[inds].expr().series(symbol, orderp1).truncate().coefficients(symbol) for k in range(orderp1): res_comp[k] = Components(SR, frame, self.tensor_rank()) for inds in comp.index_generator(): - res_comp_k = [decompo[inds][l][0] for l in range(len(decompo[inds])) - if decompo[inds][l][1] == k] + res_comp_k = [decompo[inds][l][0] for l in range(len(decompo[inds])) if decompo[inds][l][1] == k] res_comp[k][inds] = res_comp_k[0] if len(res_comp_k) >= 1 else 0 res[k].add_comp(frame)[:] = res_comp[k][:] return res diff --git a/src/sage/manifolds/differentiable/vector_bundle.py b/src/sage/manifolds/differentiable/vector_bundle.py index 268fbad6981..fb2a93166f1 100644 --- a/src/sage/manifolds/differentiable/vector_bundle.py +++ b/src/sage/manifolds/differentiable/vector_bundle.py @@ -86,8 +86,8 @@ class DifferentiableVectorBundle(TopologicalVectorBundle): sage: M.diff_degree() == E.diff_degree() True """ - def __init__(self, rank, name, base_space, field='real', latex_name=None, - category=None, unique_tag=None) -> None: + + def __init__(self, rank, name, base_space, field='real', latex_name=None, category=None, unique_tag=None) -> None: r""" Construct a differentiable vector bundle. @@ -111,10 +111,7 @@ def __init__(self, rank, name, base_space, field='real', latex_name=None, category = VectorBundles(base_space, field_c).Smooth() else: category = VectorBundles(base_space, field_c).Differentiable() - TopologicalVectorBundle.__init__(self, rank, name, base_space, - field=field, - latex_name=latex_name, - category=category) + TopologicalVectorBundle.__init__(self, rank, name, base_space, field=field, latex_name=latex_name, category=category) self._diff_degree = diff_degree # Override diff degree def _repr_(self) -> str: @@ -158,6 +155,7 @@ def bundle_connection(self, name, latex_name=None): :class:`~sage.manifolds.differentiable.bundle_connection.BundleConnection`. """ from sage.manifolds.differentiable.bundle_connection import BundleConnection + return BundleConnection(self, name, latex_name) def characteristic_cohomology_class_ring(self, base=QQ): @@ -318,21 +316,17 @@ def total_space(self): """ if self._total_space is None: from sage.manifolds.manifold import Manifold + base_space = self._base_space dim = base_space._dim + self._rank sindex = base_space.start_index() - self._total_space = Manifold( - dim, self._name, - latex_name=self._latex_name, - field=self._field, structure='differentiable', - diff_degree=self._diff_degree, - start_index=sindex - ) + self._total_space = Manifold(dim, self._name, latex_name=self._latex_name, field=self._field, structure='differentiable', diff_degree=self._diff_degree, start_index=sindex) # TODO: if update_atlas: introduce charts via self._atlas return self._total_space + # ***************************************************************************** @@ -427,6 +421,7 @@ class TensorBundle(DifferentiableVectorBundle): sage: R_tensor_module is PhiTM.section_module() True """ + def __init__(self, base_space, k, l, dest_map=None) -> None: r""" Construct a tensor bundle. @@ -470,13 +465,10 @@ def __init__(self, base_space, k, l, dest_map=None) -> None: latex_name += r'T^*{}'.format(self._ambient_domain._latex_name) else: name += "T^({},{}){}".format(k, l, self._ambient_domain._name) - latex_name += r'T^{(' + str(k) + r',' + str(l) + r')}' + \ - self._ambient_domain._latex_name + latex_name += r'T^{(' + str(k) + r',' + str(l) + r')}' + self._ambient_domain._latex_name # Initialize differentiable vector bundle: rank = self._ambient_domain.dim() ** (k + l) - DifferentiableVectorBundle.__init__(self, rank, name, base_space, - field=base_space._field, - latex_name=latex_name) + DifferentiableVectorBundle.__init__(self, rank, name, base_space, field=base_space._field, latex_name=latex_name) def _init_derived(self): r""" @@ -631,12 +623,8 @@ def section_module(self, domain=None): """ if domain is None: base_space = self.base_space() - return base_space.tensor_field_module(self._tensor_type, - dest_map=self._dest_map) - return domain.tensor_field_module( - self._tensor_type, - dest_map=self._dest_map.restrict(domain) - ) + return base_space.tensor_field_module(self._tensor_type, dest_map=self._dest_map) + return domain.tensor_field_module(self._tensor_type, dest_map=self._dest_map.restrict(domain)) def section(self, *args, **kwargs): r""" @@ -726,8 +714,7 @@ def section(self, *args, **kwargs): kwargs['dest_map'] = self._dest_map.restrict(domain) return domain.tensor_field(*nargs, **kwargs) - def set_change_of_frame(self, frame1, frame2, change_of_frame, - compute_inverse=True): + def set_change_of_frame(self, frame1, frame2, change_of_frame, compute_inverse=True): r""" Relate two vector frames by an automorphism. @@ -782,11 +769,8 @@ def set_change_of_frame(self, frame1, frame2, change_of_frame, [0 3] """ if not frame1._domain.is_subset(self._ambient_domain): - raise ValueError("the frames must be defined on a subset of " - "the {}".format(self._ambient_domain)) - frame1._domain.set_change_of_frame(frame1=frame1, frame2=frame2, - change_of_frame=change_of_frame, - compute_inverse=compute_inverse) + raise ValueError("the frames must be defined on a subset of " "the {}".format(self._ambient_domain)) + frame1._domain.set_change_of_frame(frame1=frame1, frame2=frame2, change_of_frame=change_of_frame, compute_inverse=compute_inverse) def change_of_frame(self, frame1, frame2): r""" @@ -1108,8 +1092,7 @@ def trivialization(self, coordinates='', names=None, calc_method=None): sage: X[:] (x, y) """ - return self._ambient_domain.chart(coordinates=coordinates, names=names, - calc_method=calc_method) + return self._ambient_domain.chart(coordinates=coordinates, names=names, calc_method=calc_method) def transitions(self): r""" @@ -1414,8 +1397,7 @@ def local_frame(self, *args, **kwargs): if not args and not kwargs: # if no argument is provided, the default basis of the # base vector field module is returned: - return domain.vector_field_module(dest_map=dest_map, - force_free=True).basis() + return domain.vector_field_module(dest_map=dest_map, force_free=True).basis() kwargs['dest_map'] = dest_map return domain.vector_frame(*args, **kwargs) @@ -1548,12 +1530,11 @@ def set_default_frame(self, frame): Vector frame (M, (e_0,e_1)) """ from sage.manifolds.differentiable.vectorframe import VectorFrame + if not isinstance(frame, VectorFrame): raise TypeError("{} is not a vector frame".format(frame)) - if (not frame._domain.is_subset(self._base_space) or - frame._dest_map != self._dest_map): - raise ValueError("the frame must be defined on " + - "the {}".format(self)) + if not frame._domain.is_subset(self._base_space) or frame._dest_map != self._dest_map: + raise ValueError("the frame must be defined on " + "the {}".format(self)) if self._dest_map.is_identity(): self._base_space.set_default_frame(frame) else: diff --git a/src/sage/manifolds/differentiable/vectorfield.py b/src/sage/manifolds/differentiable/vectorfield.py index c038e8afab2..ad3d5611e05 100644 --- a/src/sage/manifolds/differentiable/vectorfield.py +++ b/src/sage/manifolds/differentiable/vectorfield.py @@ -198,6 +198,7 @@ class VectorField(MultivectorField): (x, y) ↦ 2*x^2 - 2*y^2 + 2*x + 2*y (t, u) ↦ 2*t*u + 2*t """ + def __init__(self, vector_field_module, name=None, latex_name=None): r""" Construct a vector field with values on a non-parallelizable manifold. @@ -231,8 +232,7 @@ def __init__(self, vector_field_module, name=None, latex_name=None): Fix ``_test_pickling`` (in the superclass :class:`TensorField`). """ - MultivectorField.__init__(self, vector_field_module, 1, name=name, - latex_name=latex_name) + MultivectorField.__init__(self, vector_field_module, 1, name=name, latex_name=latex_name) # Initialization of derived quantities: MultivectorField._init_derived(self) # Initialization of list of quantities depending on self: @@ -334,11 +334,11 @@ def __call__(self, scalar): sage: s == f.differential()(a) True """ - if scalar._tensor_type == (0,1): + if scalar._tensor_type == (0, 1): # This is actually the action of the vector field on a 1-form, # as a tensor field of type (1,0): return scalar(self) - if scalar._tensor_type != (0,0): + if scalar._tensor_type != (0, 0): raise TypeError("the argument must be a scalar field") resu = scalar.differential()(self) if not resu.is_immutable(): @@ -354,10 +354,7 @@ def __call__(self, scalar): return resu @options(max_range=8, scale=1, color='blue') - def plot(self, chart=None, ambient_coords=None, mapping=None, - chart_domain=None, fixed_coords=None, ranges=None, - number_values=None, steps=None, - parameters=None, label_axes=True, **extra_options): + def plot(self, chart=None, ambient_coords=None, mapping=None, chart_domain=None, fixed_coords=None, ranges=None, number_values=None, steps=None, parameters=None, label_axes=True, **extra_options): r""" Plot the vector field in a Cartesian graph based on the coordinates of some ambient chart. @@ -683,17 +680,14 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, if chart is None: chart = self._domain.default_chart() elif not isinstance(chart, RealChart): - raise TypeError("{} is not a chart on a real ".format(chart) + - "manifold") + raise TypeError("{} is not a chart on a real ".format(chart) + "manifold") if chart_domain is None: chart_domain = self._domain.default_chart() elif not isinstance(chart_domain, RealChart): - raise TypeError("{} is not a chart on a ".format(chart_domain) + - "real manifold") + raise TypeError("{} is not a chart on a ".format(chart_domain) + "real manifold") elif not chart_domain.domain().is_subset(self._domain): - raise ValueError("the domain of {} is not ".format(chart_domain) + - "included in the domain of {}".format(self)) - coords_full = tuple(chart_domain[:]) # all coordinates of chart_domain + raise ValueError("the domain of {} is not ".format(chart_domain) + "included in the domain of {}".format(self)) + coords_full = tuple(chart_domain[:]) # all coordinates of chart_domain if fixed_coords is None: coords = coords_full else: @@ -709,15 +703,13 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, ambient_coords = tuple(ambient_coords) nca = len(ambient_coords) if nca != 2 and nca != 3: - raise ValueError("the number of ambient coordinates must be " + - "either 2 or 3, not {}".format(nca)) + raise ValueError("the number of ambient coordinates must be " + "either 2 or 3, not {}".format(nca)) if ranges is None: ranges = {} ranges0 = {} for coord in coords: if coord in ranges: - ranges0[coord] = (numerical_approx(ranges[coord][0]), - numerical_approx(ranges[coord][1])) + ranges0[coord] = (numerical_approx(ranges[coord][0]), numerical_approx(ranges[coord][1])) else: bounds = chart_domain._bounds[coords_full.index(coord)] xmin0 = bounds[0][0] @@ -727,19 +719,19 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, elif bounds[0][1]: xmin = numerical_approx(xmin0) else: - xmin = numerical_approx(xmin0 + 1.e-3) + xmin = numerical_approx(xmin0 + 1.0e-3) if xmax0 == Infinity: xmax = numerical_approx(max_range) elif bounds[1][1]: xmax = numerical_approx(xmax0) else: - xmax = numerical_approx(xmax0 - 1.e-3) + xmax = numerical_approx(xmax0 - 1.0e-3) ranges0[coord] = (xmin, xmax) ranges = ranges0 if number_values is None: - if nca == 2: # 2D plot + if nca == 2: # 2D plot number_values = 9 - else: # 3D plot + else: # 3D plot number_values = 5 if not isinstance(number_values, dict): number_values0 = {} @@ -750,11 +742,9 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, steps = {} for coord in coords: if coord not in steps: - steps[coord] = (ranges[coord][1] - ranges[coord][0]) / \ - (number_values[coord]-1) + steps[coord] = (ranges[coord][1] - ranges[coord][0]) / (number_values[coord] - 1) else: - number_values[coord] = 1 + int( - (ranges[coord][1] - ranges[coord][0]) / steps[coord]) + number_values[coord] = 1 + int((ranges[coord][1] - ranges[coord][0]) / steps[coord]) # # 2/ Plots # ----- @@ -794,52 +784,39 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, for i in range(ncp): xx[ind_coord[i]] = xmin[i] + ind[i] * step_tab[i] - if chart_domain.valid_coordinates(*xx, tolerance=1e-13, - parameters=parameters): + if chart_domain.valid_coordinates(*xx, tolerance=1e-13, parameters=parameters): # needed a xx*1 to copy the list by value - list_xx.append(xx*1) + list_xx.append(xx * 1) # Next index: ret = 1 - for pos in range(ncp-1,-1,-1): + for pos in range(ncp - 1, -1, -1): imax = number_values[coords[pos]] - 1 if ind[pos] != imax: ind[pos] += ret ret = 0 elif ret == 1: if pos == 0: - ind[pos] = imax + 1 # end point reached + ind[pos] = imax + 1 # end point reached else: ind[pos] = 0 ret = 1 - lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] - ind_step = max(1, int(len(list_xx)/nproc/2)) - local_list = lol(list_xx,ind_step) + lol = lambda lst, sz: [lst[i : i + sz] for i in range(0, len(lst), sz)] + ind_step = max(1, int(len(list_xx) / nproc / 2)) + local_list = lol(list_xx, ind_step) # definition of the list of input parameters - listParalInput = [(vector, dom, ind_part, - chart_domain, chart, - ambient_coords, mapping, - scale, color, parameters, - extra_options) - for ind_part in local_list] + listParalInput = [(vector, dom, ind_part, chart_domain, chart, ambient_coords, mapping, scale, color, parameters, extra_options) for ind_part in local_list] # definition of the parallel function @parallel(p_iter='multiprocessing', ncpus=nproc) - def add_point_plot(vector, dom, xx_list, chart_domain, chart, - ambient_coords, mapping, scale, color, - parameters, extra_options): + def add_point_plot(vector, dom, xx_list, chart_domain, chart, ambient_coords, mapping, scale, color, parameters, extra_options): count = 0 for xx in xx_list: point = dom(xx, chart=chart_domain) - part = vector.at(point).plot(chart=chart, - ambient_coords=ambient_coords, - mapping=mapping,scale=scale, - color=color, print_label=False, - parameters=parameters, - **extra_options) + part = vector.at(point).plot(chart=chart, ambient_coords=ambient_coords, mapping=mapping, scale=scale, color=color, print_label=False, parameters=parameters, **extra_options) if count == 0: local_resu = part else: @@ -855,26 +832,20 @@ def add_point_plot(vector, dom, xx_list, chart_domain, chart, # sequential plot while ind != ind_max: for i in range(ncp): - xx[ind_coord[i]] = xmin[i] + ind[i]*step_tab[i] - if chart_domain.valid_coordinates(*xx, tolerance=1e-13, - parameters=parameters): + xx[ind_coord[i]] = xmin[i] + ind[i] * step_tab[i] + if chart_domain.valid_coordinates(*xx, tolerance=1e-13, parameters=parameters): point = dom(xx, chart=chart_domain) - resu += vector.at(point).plot(chart=chart, - ambient_coords=ambient_coords, - mapping=mapping, scale=scale, - color=color, print_label=False, - parameters=parameters, - **extra_options) + resu += vector.at(point).plot(chart=chart, ambient_coords=ambient_coords, mapping=mapping, scale=scale, color=color, print_label=False, parameters=parameters, **extra_options) # Next index: ret = 1 - for pos in range(ncp-1, -1, -1): + for pos in range(ncp - 1, -1, -1): imax = number_values[coords[pos]] - 1 if ind[pos] != imax: ind[pos] += ret ret = 0 elif ret == 1: if pos == 0: - ind[pos] = imax + 1 # end point reached + ind[pos] = imax + 1 # end point reached else: ind[pos] = 0 ret = 1 @@ -885,9 +856,8 @@ def add_point_plot(vector, dom, xx_list, chart_domain, chart, # to show()), instead of using the method # Graphics.axes_labels() since the latter is not robust w.r.t. # graph addition - resu._extra_kwds['axes_labels'] = [r'$'+latex(ac)+r'$' - for ac in ambient_coords] - else: # 3D graphic + resu._extra_kwds['axes_labels'] = [r'$' + latex(ac) + r'$' for ac in ambient_coords] + else: # 3D graphic labels = [str(ac) for ac in ambient_coords] resu = set_axes_labels(resu, *labels) return resu @@ -1015,8 +985,7 @@ def curl(self, metric=None): 0 """ if self._domain.dim() < 3: - raise ValueError("the curl is not defined in dimension lower " + - "than 3") + raise ValueError("the curl is not defined in dimension lower " + "than 3") default_metric = metric is None if default_metric: metric = self._domain.metric() @@ -1025,12 +994,10 @@ def curl(self, metric=None): if self._name is not None: if default_metric: resu._name = "curl({})".format(self._name) - resu._latex_name = r"\mathrm{curl}\left(" + self._latex_name + \ - r"\right)" + resu._latex_name = r"\mathrm{curl}\left(" + self._latex_name + r"\right)" else: resu._name = "curl_{}({})".format(metric._name, self._name) - resu._latex_name = r"\mathrm{curl}_{" + metric._latex_name + \ - r"}\left(" + self._latex_name + r"\right)" + resu._latex_name = r"\mathrm{curl}_{" + metric._latex_name + r"}\left(" + self._latex_name + r"\right)" # The name is propagated to possible restrictions of self: for restrict in resu._restrictions.values(): restrict.set_name(resu._name, latex_name=resu._latex_name) @@ -1141,11 +1108,9 @@ def dot_product(self, other, metric=None): # From the above operation the name of resu is "g(u,v')" where # g = metric._name, u = self._name, v = other._name # For a default metric, we change it to "u.v": - if (default_metric and self._name is not None and - other._name is not None): + if default_metric and self._name is not None and other._name is not None: resu._name = "{}.{}".format(self._name, other._name) - resu._latex_name = "{" + self._latex_name + r"}\cdot{" + \ - other._latex_name + "}" + resu._latex_name = "{" + self._latex_name + r"}\cdot{" + other._latex_name + "}" # The name is propagated to possible restrictions of self: for restrict in resu._restrictions.values(): restrict.set_name(resu._name, latex_name=resu._latex_name) @@ -1236,12 +1201,10 @@ def norm(self, metric=None): if self._name is not None: if default_metric: resu._name = "|{}|".format(self._name) - resu._latex_name = r"\left\|" + self._latex_name + \ - r"\right\|" + resu._latex_name = r"\left\|" + self._latex_name + r"\right\|" else: resu._name = "|{}|_{}".format(self._name, metric._name) - resu._latex_name = r"\left\|" + self._latex_name + \ - r"\right\| _{" + metric._latex_name + "}" + resu._latex_name = r"\left\|" + self._latex_name + r"\right\| _{" + metric._latex_name + "}" # The name is propagated to possible restrictions of self: for restrict in resu._restrictions.values(): restrict.set_name(resu._name, latex_name=resu._latex_name) @@ -1350,8 +1313,7 @@ def cross_product(self, other, metric=None): C' x e_x = e_y - cos(t) e_z """ if self._ambient_domain.dim() != 3: - raise ValueError("the cross product is not defined in dimension " + - "different from 3") + raise ValueError("the cross product is not defined in dimension " + "different from 3") default_metric = metric is None if default_metric: metric = self._ambient_domain.metric() @@ -1364,11 +1326,9 @@ def cross_product(self, other, metric=None): other = other.along(dest_map) resu = eps.contract(1, 2, self.wedge(other), 0, 1) / 2 # The result is named "u x v" only for a default metric: - if (default_metric and self._name is not None and - other._name is not None): + if default_metric and self._name is not None and other._name is not None: resu._name = "{} x {}".format(self._name, other._name) - resu._latex_name = "{" + self._latex_name + r"}\times{" + \ - other._latex_name + "}" + resu._latex_name = "{" + self._latex_name + r"}\times{" + other._latex_name + "}" # The name is propagated to possible restrictions of self: for restrict in resu._restrictions.values(): restrict.set_name(resu._name, latex_name=resu._latex_name) @@ -1376,11 +1336,11 @@ def cross_product(self, other, metric=None): cross = cross_product -#****************************************************************************** + +# ****************************************************************************** -class VectorFieldParal(FiniteRankFreeModuleElement, MultivectorFieldParal, - VectorField): +class VectorFieldParal(FiniteRankFreeModuleElement, MultivectorFieldParal, VectorField): r""" Vector field along a differentiable manifold, with values on a parallelizable manifold. @@ -1585,6 +1545,7 @@ class VectorFieldParal(FiniteRankFreeModuleElement, MultivectorFieldParal, sage: w.at(p) == v.at(Phi(p)) True """ + def __init__(self, vector_field_module, name=None, latex_name=None): r""" Construct a vector field with values on a parallelizable manifold. @@ -1614,8 +1575,7 @@ def __init__(self, vector_field_module, name=None, latex_name=None): True sage: TestSuite(u).run() """ - FiniteRankFreeModuleElement.__init__(self, vector_field_module, - name=name, latex_name=latex_name) + FiniteRankFreeModuleElement.__init__(self, vector_field_module, name=name, latex_name=latex_name) # MultivectorFieldParal attributes: self._domain = vector_field_module._domain self._ambient_domain = vector_field_module._ambient_domain @@ -1627,7 +1587,7 @@ def __init__(self, vector_field_module, name=None, latex_name=None): # Initialization of list of quantities depending on self: self._init_dependencies() - def _repr_(self) : + def _repr_(self): r""" String representation of ``self``. @@ -1677,8 +1637,7 @@ def _del_derived(self, del_restrictions=True): sage: v = M.vector_field(name='v') sage: v._del_derived() """ - MultivectorFieldParal._del_derived(self, - del_restrictions=del_restrictions) + MultivectorFieldParal._del_derived(self, del_restrictions=del_restrictions) VectorField._del_derived(self) self._del_dependencies() diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index a0d0812ab3a..2d9bfca08e2 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -193,6 +193,7 @@ class VectorFieldModule(UniqueRepresentation, ReflexiveModule_base): The conversion map is actually the restriction of vector fields defined on `M` to `U`. """ + Element = VectorField def __init__(self, domain: DifferentiableManifold, dest_map: Optional[DiffMap] = None): @@ -244,13 +245,12 @@ def __init__(self, domain: DifferentiableManifold, dest_map: Optional[DiffMap] = # The member self._ring is created for efficiency (to avoid # calls to self.base_ring()): self._ring = domain.scalar_field_algebra() - Parent.__init__(self, base=self._ring, - category=Modules(self._ring)) + Parent.__init__(self, base=self._ring, category=Modules(self._ring)) # Dictionary of the tensor modules built on self # (keys = (k,l) --the tensor type) # This dictionary is to be extended on need by the method tensor_module - self._tensor_modules = {(1,0): self} # self is considered as the set - # of tensors of type (1,0) + self._tensor_modules = {(1, 0): self} # self is considered as the set + # of tensors of type (1,0) # Dictionaries of exterior powers of self and of its dual # (keys = p --the power degree) # These dictionaries are to be extended on need by the methods @@ -261,8 +261,7 @@ def __init__(self, domain: DifferentiableManifold, dest_map: Optional[DiffMap] = #### Parent methods - def _element_constructor_(self, comp=[], frame=None, name=None, - latex_name=None): + def _element_constructor_(self, comp=[], frame=None, name=None, latex_name=None): r""" Construct an element of the module. @@ -287,14 +286,11 @@ def _element_constructor_(self, comp=[], frame=None, name=None, if comp == 0: return self.zero() if isinstance(comp, VectorField): - if (self._domain.is_subset(comp._domain) - and self._ambient_domain.is_subset(comp._ambient_domain)): + if self._domain.is_subset(comp._domain) and self._ambient_domain.is_subset(comp._ambient_domain): return comp.restrict(self._domain) - raise ValueError("cannot convert the {} ".format(comp) + - "to a vector field in {}".format(self)) + raise ValueError("cannot convert the {} ".format(comp) + "to a vector field in {}".format(self)) if not isinstance(comp, (list, tuple)): - raise TypeError("cannot convert the {} ".format(comp) + - "to an element of {}".format(self)) + raise TypeError("cannot convert the {} ".format(comp) + "to an element of {}".format(self)) # standard construction resu = self.element_class(self, name=name, latex_name=latex_name) if comp: @@ -319,8 +315,7 @@ def _an_element_(self): for oc in self._domain.open_covers(trivial=False): # the first non-trivial open cover is selected for dom in oc: - vmodule_dom = dom.vector_field_module( - dest_map=self._dest_map.restrict(dom)) + vmodule_dom = dom.vector_field_module(dest_map=self._dest_map.restrict(dom)) resu.set_restriction(vmodule_dom._an_element_()) return resu return resu @@ -341,8 +336,7 @@ def _coerce_map_from_(self, other): True """ if isinstance(other, (VectorFieldModule, VectorFieldFreeModule)): - return self._domain.is_subset(other._domain) and \ - self._ambient_domain.is_subset(other._ambient_domain) + return self._domain.is_subset(other._domain) and self._ambient_domain.is_subset(other._ambient_domain) return False #### End of parent methods @@ -370,8 +364,7 @@ def _repr_(self): if self._dest_map is self._domain.identity_map(): description += "on the {}".format(self._domain) else: - description += ("along the {}".format(self._domain) - + " mapped into the {}".format(self._ambient_domain)) + description += "along the {}".format(self._domain) + " mapped into the {}".format(self._ambient_domain) return description def _latex_(self): @@ -543,13 +536,14 @@ def tensor_module(self, k, l, *, sym=None, antisym=None): if sym or antisym: raise NotImplementedError try: - return self._tensor_modules[(k,l)] + return self._tensor_modules[(k, l)] except KeyError: from sage.manifolds.differentiable.tensorfield_module import ( TensorFieldModule, ) - T = TensorFieldModule(self, (k,l)) - self._tensor_modules[(k,l)] = T + + T = TensorFieldModule(self, (k, l)) + self._tensor_modules[(k, l)] = T return T def exterior_power(self, p): @@ -607,6 +601,7 @@ def exterior_power(self, p): from sage.manifolds.differentiable.multivector_module import ( MultivectorModule, ) + L = MultivectorModule(self, p) self._exterior_powers[p] = L return L @@ -665,6 +660,7 @@ def dual_exterior_power(self, p): from sage.manifolds.differentiable.diff_form_module import ( DiffFormModule, ) + L = DiffFormModule(self, p) self._dual_exterior_powers[p] = L return L @@ -716,11 +712,11 @@ def general_linear_group(self): from sage.manifolds.differentiable.automorphismfield_group import ( AutomorphismFieldGroup, ) + self._general_linear_group = AutomorphismFieldGroup(self) return self._general_linear_group - def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, - antisym=None, specific_type=None): + def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, antisym=None, specific_type=None): r""" Construct a tensor on ``self``. @@ -776,37 +772,30 @@ def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, PseudoRiemannianMetric, ) from sage.tensor.modules.comp import CompWithSym - sym, antisym = CompWithSym._canonicalize_sym_antisym( - tensor_type[0] + tensor_type[1], sym, antisym) - if tensor_type == (1,0): - return self.element_class(self, name=name, - latex_name=latex_name) - if tensor_type == (0,1): + + sym, antisym = CompWithSym._canonicalize_sym_antisym(tensor_type[0] + tensor_type[1], sym, antisym) + if tensor_type == (1, 0): + return self.element_class(self, name=name, latex_name=latex_name) + if tensor_type == (0, 1): return self.linear_form(name=name, latex_name=latex_name) - if tensor_type == (1,1) and specific_type is not None: + if tensor_type == (1, 1) and specific_type is not None: if issubclass(specific_type, AutomorphismField): - return self.automorphism(name=name, - latex_name=latex_name) + return self.automorphism(name=name, latex_name=latex_name) elif tensor_type[0] == 0 and tensor_type[1] > 1 and antisym: if len(antisym[0]) == tensor_type[1]: - return self.alternating_form(tensor_type[1], name=name, - latex_name=latex_name) + return self.alternating_form(tensor_type[1], name=name, latex_name=latex_name) elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym: if len(antisym[0]) == tensor_type[0]: - return self.alternating_contravariant_tensor( - tensor_type[0], name=name, latex_name=latex_name) - elif tensor_type == (0,2) and specific_type is not None: + return self.alternating_contravariant_tensor(tensor_type[0], name=name, latex_name=latex_name) + elif tensor_type == (0, 2) and specific_type is not None: if issubclass(specific_type, PseudoRiemannianMetric): return self.metric(name, latex_name=latex_name) # NB: the signature is not treated if issubclass(specific_type, DegenerateMetric): sign = self._domain._dim - return self.metric(name, latex_name=latex_name, - signature=(0, sign-1, 1)) + return self.metric(name, latex_name=latex_name, signature=(0, sign - 1, 1)) # Generic case - return self.tensor_module(*tensor_type).element_class( - self, tensor_type, name=name, latex_name=latex_name, - sym=sym, antisym=antisym) + return self.tensor_module(*tensor_type).element_class(self, tensor_type, name=name, latex_name=latex_name, sym=sym, antisym=antisym) def tensor(self, *args, **kwds): r""" @@ -885,8 +874,7 @@ def tensor(self, *args, **kwds): return self.tensor_product(*args, **kwds) return self._tensor(*args, **kwds) - def alternating_contravariant_tensor(self, degree, name=None, - latex_name=None): + def alternating_contravariant_tensor(self, degree, name=None, latex_name=None): r""" Construct an alternating contravariant tensor on the vector field module ``self``. @@ -933,16 +921,11 @@ def alternating_contravariant_tensor(self, degree, name=None, if degree == 0: return self._domain.scalar_field(name=name, latex_name=latex_name) if degree == 1: - return self.element_class(self, name=name, - latex_name=latex_name) - return self.exterior_power(degree).element_class(self, degree, - name=name, - latex_name=latex_name) + return self.element_class(self, name=name, latex_name=latex_name) + return self.exterior_power(degree).element_class(self, degree, name=name, latex_name=latex_name) @overload - def alternating_form( - self, degree: Literal[0], name=None, latex_name=None - ) -> ScalarField: + def alternating_form(self, degree: Literal[0], name=None, latex_name=None) -> ScalarField: pass def alternating_form(self, degree: int, name=None, latex_name=None) -> DiffForm: @@ -985,8 +968,7 @@ def alternating_form(self, degree: int, name=None, latex_name=None) -> DiffForm: """ if degree == 0: return self._domain.scalar_field(name=name, latex_name=latex_name) - return self.dual_exterior_power(degree).element_class(self, - degree, name=name, latex_name=latex_name) + return self.dual_exterior_power(degree).element_class(self, degree, name=name, latex_name=latex_name) def linear_form(self, name=None, latex_name=None): r""" @@ -1022,8 +1004,7 @@ def linear_form(self, name=None, latex_name=None): :class:`~sage.manifolds.differentiable.diff_form.DiffForm` for more examples and documentation. """ - return self.dual_exterior_power(1).element_class(self, 1, - name=name, latex_name=latex_name) + return self.dual_exterior_power(1).element_class(self, 1, name=name, latex_name=latex_name) def automorphism(self, name=None, latex_name=None): r""" @@ -1061,8 +1042,7 @@ def automorphism(self, name=None, latex_name=None): :class:`~sage.manifolds.differentiable.automorphismfield.AutomorphismField` for more examples and documentation. """ - return self.general_linear_group().element_class(self, - name=name, latex_name=latex_name) + return self.general_linear_group().element_class(self, name=name, latex_name=latex_name) @cached_method def identity_map(self): @@ -1170,33 +1150,30 @@ def metric(self, name: str, signature: Optional[int] = None, latex_name: Optiona if (elt < 0) or (not isinstance(elt, (int, Integer))): raise ValueError("{} must be a positive integer".format(elt)) if elt > ndim: - raise ValueError("{} must be less than {}".format(elt,ndim)) - sign = signature[0]+signature[1]+signature[2] + raise ValueError("{} must be less than {}".format(elt, ndim)) + sign = signature[0] + signature[1] + signature[2] if sign != ndim: - raise ValueError("{} is different from the dimension".format(sign) + - " of the manifold, who is {}".format(ndim)) + raise ValueError("{} is different from the dimension".format(sign) + " of the manifold, who is {}".format(ndim)) if signature[2] != 0: from sage.manifolds.differentiable.metric import DegenerateMetric - return DegenerateMetric(self, name, signature=signature, - latex_name=latex_name) + + return DegenerateMetric(self, name, signature=signature, latex_name=latex_name) except TypeError: pass if signature is None: - signature = (ndim,0) + signature = (ndim, 0) if isinstance(signature, (Integer, int)): - if (signature+ndim) % 2 == 1: + if (signature + ndim) % 2 == 1: if ndim % 2 == 0: raise ValueError("the metric signature must be even") else: raise ValueError("the metric signature must be odd") - signature = (int((ndim+signature)/2), int((ndim-signature)/2)) + signature = (int((ndim + signature) / 2), int((ndim - signature) / 2)) from sage.manifolds.differentiable.metric import PseudoRiemannianMetric - return PseudoRiemannianMetric(self, name, signature=signature[0]-signature[1], - latex_name=latex_name) - def symplectic_form( - self, name: Optional[str] = None, latex_name: Optional[str] = None - ): + return PseudoRiemannianMetric(self, name, signature=signature[0] - signature[1], latex_name=latex_name) + + def symplectic_form(self, name: Optional[str] = None, latex_name: Optional[str] = None): r""" Construct a symplectic form on the current vector field module. @@ -1220,9 +1197,7 @@ def symplectic_form( return SymplecticForm(self, name, latex_name) - def poisson_tensor( - self, name: Optional[str] = None, latex_name: Optional[str] = None - ): + def poisson_tensor(self, name: Optional[str] = None, latex_name: Optional[str] = None): r""" Construct a Poisson tensor on the current vector field module. @@ -1246,7 +1221,8 @@ def poisson_tensor( return PoissonTensorField(self, name, latex_name) -#****************************************************************************** +# ****************************************************************************** + class VectorFieldFreeModule(FiniteRankFreeModule): r""" @@ -1517,6 +1493,7 @@ def __init__(self, domain, dest_map=None): sage: TestSuite(XM).run() """ from sage.manifolds.differentiable.scalarfield import DiffScalarField + self._domain = domain if dest_map is None: dest_map = domain.identity_map() @@ -1537,11 +1514,7 @@ def __init__(self, domain, dest_map=None): latex_name += r"\right)" manif = self._ambient_domain.manifold() cat = Modules(domain.scalar_field_algebra()).FiniteDimensional() - FiniteRankFreeModule.__init__(self, domain.scalar_field_algebra(), - manif._dim, name=name, latex_name=latex_name, - start_index=manif._sindex, - output_formatter=DiffScalarField.coord_function, - category=cat) + FiniteRankFreeModule.__init__(self, domain.scalar_field_algebra(), manif._dim, name=name, latex_name=latex_name, start_index=manif._sindex, output_formatter=DiffScalarField.coord_function, category=cat) # # Special treatment when self._dest_map != identity: # bases of self are created from vector frames of the ambient domain @@ -1549,8 +1522,7 @@ def __init__(self, domain, dest_map=None): self._induced_bases = {} if self._dest_map != self._domain.identity_map(): for frame in self._ambient_domain._top_frames: - if (frame.destination_map() == - self._ambient_domain.identity_map()): + if frame.destination_map() == self._ambient_domain.identity_map(): basis = self.basis(from_frame=frame) self._induced_bases[frame] = basis @@ -1559,10 +1531,7 @@ def __init__(self, domain, dest_map=None): for dom in domain.open_supersets(): if dom is not domain: for supbase in dom._frames: - if (supbase.domain() is dom and - supbase.destination_map().restrict(domain) - is self._dest_map and - domain not in supbase._restrictions): + if supbase.domain() is dom and supbase.destination_map().restrict(domain) is self._dest_map and domain not in supbase._restrictions: supbase._restrictions[domain] = basis supbase._subframes.add(basis) basis._superframes.add(supbase) @@ -1570,17 +1539,14 @@ def __init__(self, domain, dest_map=None): # basis is added as a superframe of smaller domain for superframe in basis._superframes: for subframe in superframe._subframes: - if subframe.domain() is not domain and subframe.domain().is_subset( - self._domain) and self._dest_map.restrict( - subframe.domain()) is subframe.destination_map(): + if subframe.domain() is not domain and subframe.domain().is_subset(self._domain) and self._dest_map.restrict(subframe.domain()) is subframe.destination_map(): subframe._superframes.update(basis._superframes) basis._subframes.update(subframe._subframes) basis._restrictions.update(subframe._restrictions) #### Parent methods - def _element_constructor_(self, comp=[], basis=None, name=None, - latex_name=None): + def _element_constructor_(self, comp=[], basis=None, name=None, latex_name=None): r""" Construct an element of ``self``. @@ -1603,14 +1569,11 @@ def _element_constructor_(self, comp=[], basis=None, name=None, if comp == 0: return self.zero() if isinstance(comp, VectorField): - if (self._domain.is_subset(comp._domain) - and self._ambient_domain.is_subset(comp._ambient_domain)): + if self._domain.is_subset(comp._domain) and self._ambient_domain.is_subset(comp._ambient_domain): return comp.restrict(self._domain) - raise ValueError("cannot convert the {}".format(comp) + - "to a vector field in {}".format(self)) + raise ValueError("cannot convert the {}".format(comp) + "to a vector field in {}".format(self)) if not isinstance(comp, (list, tuple)): - raise TypeError("cannot convert the {} ".format(comp) + - "to an element of {}".format(self)) + raise TypeError("cannot convert the {} ".format(comp) + "to an element of {}".format(self)) # standard construction resu = self.element_class(self, name=name, latex_name=latex_name) if comp: @@ -1636,8 +1599,7 @@ def _coerce_map_from_(self, other): True """ if isinstance(other, (VectorFieldModule, VectorFieldFreeModule)): - return (self._domain.is_subset(other._domain) - and self._ambient_domain.is_subset(other._ambient_domain)) + return self._domain.is_subset(other._domain) and self._ambient_domain.is_subset(other._ambient_domain) return False #### End of parent methods @@ -1668,8 +1630,7 @@ def _repr_(self): if self._dest_map is self._domain.identity_map(): description += "on the {}".format(self._domain) else: - description += "along the {}".format(self._domain) + \ - " mapped into the {}".format(self._ambient_domain) + description += "along the {}".format(self._domain) + " mapped into the {}".format(self._ambient_domain) return description def domain(self) -> DifferentiableManifold: @@ -1832,7 +1793,7 @@ def tensor_module(self, k, l, *, sym=None, antisym=None): if sym or antisym: raise NotImplementedError try: - return self._tensor_modules[(k,l)] + return self._tensor_modules[(k, l)] except KeyError: if (k, l) == (1, 0): T = self @@ -1842,8 +1803,9 @@ def tensor_module(self, k, l, *, sym=None, antisym=None): from sage.manifolds.differentiable.tensorfield_module import ( TensorFieldFreeModule, ) - T = TensorFieldFreeModule(self, (k,l)) - self._tensor_modules[(k,l)] = T + + T = TensorFieldFreeModule(self, (k, l)) + self._tensor_modules[(k, l)] = T return T def exterior_power(self, p): @@ -1904,6 +1866,7 @@ def exterior_power(self, p): from sage.manifolds.differentiable.multivector_module import ( MultivectorFreeModule, ) + L = MultivectorFreeModule(self, p) self._exterior_powers[p] = L return L @@ -1961,11 +1924,13 @@ def dual_exterior_power(self, p): from sage.manifolds.differentiable.diff_form_module import ( VectorFieldDualFreeModule, ) + L = VectorFieldDualFreeModule(self) else: from sage.manifolds.differentiable.diff_form_module import ( DiffFormFreeModule, ) + L = DiffFormFreeModule(self, p) self._dual_exterior_powers[p] = L return L @@ -2003,11 +1968,10 @@ def general_linear_group(self): from sage.manifolds.differentiable.automorphismfield_group import ( AutomorphismFieldParalGroup, ) + return AutomorphismFieldParalGroup(self) - def basis(self, symbol=None, latex_symbol=None, from_frame=None, - indices=None, latex_indices=None, symbol_dual=None, - latex_symbol_dual=None): + def basis(self, symbol=None, latex_symbol=None, from_frame=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): r""" Define a basis of ``self``. @@ -2064,6 +2028,7 @@ def basis(self, symbol=None, latex_symbol=None, from_frame=None, for more examples and documentation. """ from sage.manifolds.differentiable.vectorframe import VectorFrame + if symbol is None: if from_frame is None: return self.default_basis() @@ -2076,14 +2041,9 @@ def basis(self, symbol=None, latex_symbol=None, from_frame=None, for other in self._known_bases: if symbol == other._symbol: return other - return VectorFrame(self, symbol, latex_symbol=latex_symbol, - from_frame=from_frame, indices=indices, - latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) - - def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, - antisym=None, specific_type=None): + return VectorFrame(self, symbol, latex_symbol=latex_symbol, from_frame=from_frame, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) + + def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, antisym=None, specific_type=None): r""" Construct a tensor on ``self``. @@ -2150,40 +2110,32 @@ def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, PseudoRiemannianMetric, ) from sage.tensor.modules.comp import CompWithSym - sym, antisym = CompWithSym._canonicalize_sym_antisym( - tensor_type[0] + tensor_type[1], sym, antisym) - if tensor_type == (1,0): - return self.element_class(self, name=name, - latex_name=latex_name) - if tensor_type == (0,1): + + sym, antisym = CompWithSym._canonicalize_sym_antisym(tensor_type[0] + tensor_type[1], sym, antisym) + if tensor_type == (1, 0): + return self.element_class(self, name=name, latex_name=latex_name) + if tensor_type == (0, 1): return self.linear_form(name=name, latex_name=latex_name) - if tensor_type == (1,1) and specific_type is not None: - if issubclass(specific_type, - (AutomorphismField, AutomorphismFieldParal)): + if tensor_type == (1, 1) and specific_type is not None: + if issubclass(specific_type, (AutomorphismField, AutomorphismFieldParal)): return self.automorphism(name=name, latex_name=latex_name) elif tensor_type[0] == 0 and tensor_type[1] > 1 and antisym: if len(antisym[0]) == tensor_type[1]: - return self.alternating_form(tensor_type[1], name=name, - latex_name=latex_name) + return self.alternating_form(tensor_type[1], name=name, latex_name=latex_name) elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym: if len(antisym[0]) == tensor_type[0]: - return self.alternating_contravariant_tensor( - tensor_type[0], name=name, latex_name=latex_name) - elif tensor_type == (0,2) and specific_type is not None: + return self.alternating_contravariant_tensor(tensor_type[0], name=name, latex_name=latex_name) + elif tensor_type == (0, 2) and specific_type is not None: if issubclass(specific_type, PseudoRiemannianMetric): return self.metric(name, latex_name=latex_name) # NB: the signature is not treated if issubclass(specific_type, DegenerateMetric): sign = self._domain._dim - return self.metric(name, latex_name=latex_name, - signature=(0, sign-1, 1)) + return self.metric(name, latex_name=latex_name, signature=(0, sign - 1, 1)) # Generic case - return self.tensor_module(*tensor_type).element_class( - self, tensor_type, name=name, latex_name=latex_name, - sym=sym, antisym=antisym) + return self.tensor_module(*tensor_type).element_class(self, tensor_type, name=name, latex_name=latex_name, sym=sym, antisym=antisym) - def tensor_from_comp(self, tensor_type, comp, name=None, - latex_name=None): + def tensor_from_comp(self, tensor_type, comp, name=None, latex_name=None): r""" Construct a tensor on ``self`` from a set of components. @@ -2239,32 +2191,23 @@ def tensor_from_comp(self, tensor_type, comp, name=None, # 0/ Compatibility checks: if comp._ring is not self._ring: - raise ValueError("the components are not defined on the " - "same ring as the module") + raise ValueError("the components are not defined on the " "same ring as the module") if comp._frame not in self._known_bases: - raise ValueError("the components are not defined on a " - "basis of the module") + raise ValueError("the components are not defined on a " "basis of the module") if comp._nid != tensor_type[0] + tensor_type[1]: - raise ValueError("number of component indices not " - "compatible with the tensor type") + raise ValueError("number of component indices not " "compatible with the tensor type") # # 1/ Construction of the tensor: if tensor_type == (1, 0): - resu = self.element_class(self, name=name, - latex_name=latex_name) - elif tensor_type == (0,1): + resu = self.element_class(self, name=name, latex_name=latex_name) + elif tensor_type == (0, 1): resu = self.linear_form(name=name, latex_name=latex_name) - elif (tensor_type[0] == 0 and tensor_type[1] > 1 - and isinstance(comp, CompFullyAntiSym)): - resu = self.alternating_form(tensor_type[1], name=name, - latex_name=latex_name) - elif (tensor_type[0] > 1 and tensor_type[1] == 0 - and isinstance(comp, CompFullyAntiSym)): - resu = self.alternating_contravariant_tensor(tensor_type[0], - name=name, latex_name=latex_name) + elif tensor_type[0] == 0 and tensor_type[1] > 1 and isinstance(comp, CompFullyAntiSym): + resu = self.alternating_form(tensor_type[1], name=name, latex_name=latex_name) + elif tensor_type[0] > 1 and tensor_type[1] == 0 and isinstance(comp, CompFullyAntiSym): + resu = self.alternating_contravariant_tensor(tensor_type[0], name=name, latex_name=latex_name) else: - resu = self.tensor_module(*tensor_type).element_class(self, - tensor_type, name=name, latex_name=latex_name) + resu = self.tensor_module(*tensor_type).element_class(self, tensor_type, name=name, latex_name=latex_name) # Tensor symmetries deduced from those of comp: if isinstance(comp, CompWithSym): resu._sym = comp._sym @@ -2312,8 +2255,7 @@ def sym_bilinear_form(self, name=None, latex_name=None): :class:`~sage.manifolds.differentiable.tensorfield_paral.TensorFieldParal` for more examples and documentation. """ - return self.tensor((0,2), name=name, latex_name=latex_name, - sym=(0,1)) + return self.tensor((0, 2), name=name, latex_name=latex_name, sym=(0, 1)) #### End of methods to be redefined by derived classes of FiniteRankFreeModule #### @@ -2363,33 +2305,29 @@ def metric(self, name, signature=None, latex_name=None): for elt in signature: if (elt < 0) or (not isinstance(elt, (int, Integer))): raise ValueError("{} must be a positive integer".format(elt)) - sign = signature[0]+signature[1]+signature[2] + sign = signature[0] + signature[1] + signature[2] if sign != ndim: - raise ValueError("{} is different from the dimension".format(sign) + - " of the manifold, who is {}".format(ndim)) + raise ValueError("{} is different from the dimension".format(sign) + " of the manifold, who is {}".format(ndim)) if signature[2] != 0: from sage.manifolds.differentiable.metric import DegenerateMetricParal - return DegenerateMetricParal(self, name, signature=signature, - latex_name=latex_name) + + return DegenerateMetricParal(self, name, signature=signature, latex_name=latex_name) except TypeError: pass if signature is None: - signature = (ndim,0) + signature = (ndim, 0) if isinstance(signature, (Integer, int)): - if (signature+ndim) % 2 == 1: + if (signature + ndim) % 2 == 1: if ndim % 2 == 0: raise ValueError("the metric signature must be even") else: raise ValueError("the metric signature must be odd") - signature = (int((ndim+signature)/2), int((ndim-signature)/2)) + signature = (int((ndim + signature) / 2), int((ndim - signature) / 2)) from sage.manifolds.differentiable.metric import PseudoRiemannianMetricParal - return PseudoRiemannianMetricParal(self, name, - signature=signature[0]-signature[1], - latex_name=latex_name) - def symplectic_form( - self, name: Optional[str] = None, latex_name: Optional[str] = None - ): + return PseudoRiemannianMetricParal(self, name, signature=signature[0] - signature[1], latex_name=latex_name) + + def symplectic_form(self, name: Optional[str] = None, latex_name: Optional[str] = None): r""" Construct a symplectic form on the current vector field module. @@ -2412,9 +2350,7 @@ def symplectic_form( return SymplecticFormParal(self, name, latex_name) - def poisson_tensor( - self, name: Optional[str] = None, latex_name: Optional[str] = None - ): + def poisson_tensor(self, name: Optional[str] = None, latex_name: Optional[str] = None): r""" Construct a Poisson tensor on the current vector field module. diff --git a/src/sage/manifolds/differentiable/vectorframe.py b/src/sage/manifolds/differentiable/vectorframe.py index a4df55bd276..90acdf8699e 100644 --- a/src/sage/manifolds/differentiable/vectorframe.py +++ b/src/sage/manifolds/differentiable/vectorframe.py @@ -296,8 +296,8 @@ class CoFrame(FreeModuleCoBasis): sage: e[3](v[1]).expr(), e[3](v[2]).expr(), e[3](v[3]).expr() (0, 0, 1) """ - def __init__(self, frame, symbol, latex_symbol=None, indices=None, - latex_indices=None): + + def __init__(self, frame, symbol, latex_symbol=None, indices=None, latex_indices=None): r""" Construct a coframe, dual to a given vector frame. @@ -312,9 +312,7 @@ def __init__(self, frame, symbol, latex_symbol=None, indices=None, """ self._domain = frame._domain self._manifold = self._domain.manifold() - FreeModuleCoBasis.__init__(self, frame, symbol, - latex_symbol=latex_symbol, indices=indices, - latex_indices=latex_indices) + FreeModuleCoBasis.__init__(self, frame, symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices) # The coframe is added to the domain's set of coframes, as well as to # all the superdomains' sets of coframes for sd in self._domain.open_supersets(): @@ -393,9 +391,7 @@ def at(self, point): """ return self._basis.at(point).dual_basis() - def set_name(self, symbol, latex_symbol=None, indices=None, - latex_indices=None, index_position='up', - include_domain=True): + def set_name(self, symbol, latex_symbol=None, indices=None, latex_indices=None, index_position='up', include_domain=True): r""" Set (or change) the text name and LaTeX name of ``self``. @@ -445,15 +441,12 @@ def set_name(self, symbol, latex_symbol=None, indices=None, sage: latex(e) \left(M, \left(e^{\xi},e^{\zeta}\right)\right) """ - super().set_name(symbol, latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - index_position=index_position) + super().set_name(symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, index_position=index_position) if include_domain: # Redefinition of the name and the LaTeX name to include the domain self._name = "({}, {})".format(self._domain._name, self._name) - self._latex_name = r"\left({}, {}\right)".format( - self._domain._latex_name, self._latex_name) + self._latex_name = r"\left({}, {}\right)".format(self._domain._latex_name, self._latex_name) + # ****************************************************************************** @@ -631,10 +624,7 @@ class VectorFrame(FreeModuleBasis): _cobasis_class = CoFrame @staticmethod - def __classcall_private__(cls, vector_field_module, symbol, - latex_symbol=None, from_frame=None, indices=None, - latex_indices=None, symbol_dual=None, - latex_symbol_dual=None): + def __classcall_private__(cls, vector_field_module, symbol, latex_symbol=None, from_frame=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): """ Transform input lists into tuples for the unique representation of VectorFrame. @@ -663,16 +653,9 @@ def __classcall_private__(cls, vector_field_module, symbol, symbol_dual = tuple(symbol_dual) if isinstance(latex_symbol_dual, list): latex_symbol_dual = tuple(latex_symbol_dual) - return super().__classcall__(cls, vector_field_module, - symbol, latex_symbol=latex_symbol, - from_frame=from_frame, indices=indices, - latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) - - def __init__(self, vector_field_module, symbol, latex_symbol=None, - from_frame=None, indices=None, latex_indices=None, - symbol_dual=None, latex_symbol_dual=None): + return super().__classcall__(cls, vector_field_module, symbol, latex_symbol=latex_symbol, from_frame=from_frame, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) + + def __init__(self, vector_field_module, symbol, latex_symbol=None, from_frame=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): r""" Construct a vector frame on a parallelizable manifold. @@ -686,11 +669,10 @@ def __init__(self, vector_field_module, symbol, latex_symbol=None, sage: TestSuite(e).run() """ from sage.manifolds.differentiable.manifold import DifferentiableManifold + # Some sanity check: if not isinstance(vector_field_module, FiniteRankFreeModule): - raise ValueError("the {} has already been constructed as a " - "non-free module and therefore cannot have " - "a basis".format(vector_field_module)) + raise ValueError("the {} has already been constructed as a " "non-free module and therefore cannot have " "a basis".format(vector_field_module)) self._domain = vector_field_module._domain self._ambient_domain = vector_field_module._ambient_domain self._dest_map = vector_field_module._dest_map @@ -698,9 +680,7 @@ def __init__(self, vector_field_module, symbol, latex_symbol=None, self._manifold = self._domain.manifold() if from_frame is not None: if not from_frame._domain.is_subset(self._dest_map._codomain): - raise ValueError("the domain of the frame 'from_frame' is " + - "not included in the codomain of the " + - "destination map") + raise ValueError("the domain of the frame 'from_frame' is " + "not included in the codomain of the " + "destination map") if symbol is None: if from_frame is None: raise TypeError("some frame symbol must be provided") @@ -710,11 +690,7 @@ def __init__(self, vector_field_module, symbol, latex_symbol=None, latex_indices = from_frame._latex_indices symbol_dual = from_frame._symbol_dual latex_symbol_dual = from_frame._latex_symbol_dual - FreeModuleBasis.__init__(self, vector_field_module, - symbol, latex_symbol=latex_symbol, - indices=indices, latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) + FreeModuleBasis.__init__(self, vector_field_module, symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) # The frame is added to the domain's set of frames, as well as to all # the superdomains' sets of frames; moreover the first defined frame # is considered as the default one @@ -738,7 +714,7 @@ def __init__(self, vector_field_module, symbol, latex_symbol=None, # Dual coframe self._coframe = self.dual_basis() # self._coframe = a shortcut for - # self._dual_basis + # self._dual_basis # Derived quantities: # Initialization of the set of frames that are restrictions of the @@ -748,9 +724,9 @@ def __init__(self, vector_field_module, symbol, latex_symbol=None, # restriction of: self._superframes = set([self]) - self._restrictions = {} # dict. of the restrictions of self to - # subdomains of self._domain, with the - # subdomains as keys + self._restrictions = {} # dict. of the restrictions of self to + # subdomains of self._domain, with the + # subdomains as keys # NB: set(self._restrictions.values()) is identical to # self._subframes @@ -785,9 +761,7 @@ def _repr_(self): description += " with values on the {}".format(self._dest_map.codomain()) return description - def _new_instance(self, symbol, latex_symbol=None, indices=None, - latex_indices=None, symbol_dual=None, - latex_symbol_dual=None): + def _new_instance(self, symbol, latex_symbol=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): r""" Construct a new vector frame on the same vector field module as ``self``. @@ -830,10 +804,7 @@ def _new_instance(self, symbol, latex_symbol=None, indices=None, sage: e._new_instance('f') Vector frame (M, (f_0,f_1)) """ - return VectorFrame(self._fmodule, symbol, latex_symbol=latex_symbol, - indices=indices, latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) + return VectorFrame(self._fmodule, symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) ###### End of methods to be redefined by derived classes ###### @@ -956,9 +927,7 @@ def coframe(self): """ return self._coframe - def new_frame(self, change_of_frame, symbol, latex_symbol=None, - indices=None, latex_indices=None, symbol_dual=None, - latex_symbol_dual=None): + def new_frame(self, change_of_frame, symbol, latex_symbol=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): r""" Define a new vector frame from ``self``. @@ -1044,17 +1013,10 @@ def new_frame(self, change_of_frame, symbol, latex_symbol=None, sage: e[1].comp(n)[:] [1/2, 1/2*sqrt(3)] """ - the_new_frame = self.new_basis(change_of_frame, symbol, - latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) + the_new_frame = self.new_basis(change_of_frame, symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) for sdom in self._domain.open_supersets(): - sdom._frame_changes[(self, the_new_frame)] = \ - self._fmodule._basis_changes[(self, the_new_frame)] - sdom._frame_changes[(the_new_frame, self)] = \ - self._fmodule._basis_changes[(the_new_frame, self)] + sdom._frame_changes[(self, the_new_frame)] = self._fmodule._basis_changes[(self, the_new_frame)] + sdom._frame_changes[(the_new_frame, self)] = self._fmodule._basis_changes[(the_new_frame, self)] return the_new_frame def restrict(self, subdomain): @@ -1102,8 +1064,7 @@ def restrict(self, subdomain): return self if subdomain not in self._restrictions: if not subdomain.is_subset(self._domain): - raise ValueError("the provided domain is not a subdomain of " + - "the current frame's domain") + raise ValueError("the provided domain is not a subdomain of " + "the current frame's domain") # First one tries to get the restriction from a tighter domain: for dom, rst in self._restrictions.items(): if subdomain.is_subset(dom) and subdomain in rst._restrictions: @@ -1126,25 +1087,19 @@ def restrict(self, subdomain): # If this point is reached, the restriction has to be created # from scratch sdest_map = self._dest_map.restrict(subdomain) - resmodule = subdomain.vector_field_module(sdest_map, - force_free=True) + resmodule = subdomain.vector_field_module(sdest_map, force_free=True) if subdomain in self._restrictions: # the restriction has been generated during the creation of # resmodule (which may happen if sdest_map is not trivial) return self._restrictions[subdomain] - res = VectorFrame(resmodule, - self._symbol, latex_symbol=self._latex_symbol, - indices=self._indices, - latex_indices=self._latex_indices, - symbol_dual=self._symbol_dual, - latex_symbol_dual=self._latex_symbol_dual) + res = VectorFrame(resmodule, self._symbol, latex_symbol=self._latex_symbol, indices=self._indices, latex_indices=self._latex_indices, symbol_dual=self._symbol_dual, latex_symbol_dual=self._latex_symbol_dual) res._from_frame = self._from_frame for dom in subdomain.open_supersets(): if dom is not subdomain: dom._top_frames.remove(res) # since it was added by - # VectorFrame constructor + # VectorFrame constructor new_vectors = list() for i in self._fmodule.irange(): vrest = self[i].restrict(subdomain) @@ -1159,7 +1114,7 @@ def restrict(self, subdomain): res._superframes.update(sframe._superframes) for sframe in res._superframes: sframe._subframes.add(res) - sframe._restrictions[subdomain] = res # includes sframe = self + sframe._restrictions[subdomain] = res # includes sframe = self for dom, rst in self._restrictions.items(): if dom.is_subset(subdomain): res._restrictions.update(rst._restrictions) @@ -1222,19 +1177,16 @@ def structure_coeff(self): from sage.tensor.modules.comp import CompWithSym fmodule = self._fmodule - structure_coeff = CompWithSym(self._fmodule._ring, self, 3, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter, - antisym=(1,2)) + structure_coeff = CompWithSym(self._fmodule._ring, self, 3, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter, antisym=(1, 2)) si = fmodule._sindex nsi = si + fmodule.rank() for k in range(si, nsi): - ce_k = self._coframe._vec[k-si] + ce_k = self._coframe._vec[k - si] for i in range(si, nsi): - e_i = self._vec[i-si] - for j in range(i+1, nsi): - e_j = self._vec[j-si] - structure_coeff[[k,i,j]] = ce_k(e_j.lie_der(e_i)) + e_i = self._vec[i - si] + for j in range(i + 1, nsi): + e_j = self._vec[j - si] + structure_coeff[[k, i, j]] = ce_k(e_j.lie_der(e_i)) return structure_coeff def along(self, mapping): @@ -1300,8 +1252,7 @@ def along(self, mapping): rmapping = rest break else: - raise ValueError("the codomain of {} is not ".format(mapping) + - " included in the domain of {}".format(self)) + raise ValueError("the codomain of {} is not ".format(mapping) + " included in the domain of {}".format(self)) vmodule = rmapping.domain().vector_field_module(dest_map=rmapping) return vmodule.basis(from_frame=self) @@ -1411,8 +1362,7 @@ def at(self, point): # Determination of the tangent space: if point not in self._domain: - raise ValueError("the {} is not a point in the ".format(point) + - "domain of {}".format(self)) + raise ValueError("the {} is not a point in the ".format(point) + "domain of {}".format(self)) if self._dest_map.is_identity(): ambient_point = point @@ -1432,11 +1382,7 @@ def at(self, point): # scratch. # The names of the basis vectors set to those of the frame vector # fields: - basis = ts.basis(self._symbol, latex_symbol=self._latex_symbol, - indices=self._indices, - latex_indices=self._latex_indices, - symbol_dual=self._symbol_dual, - latex_symbol_dual=self._latex_symbol_dual) + basis = ts.basis(self._symbol, latex_symbol=self._latex_symbol, indices=self._indices, latex_indices=self._latex_indices, symbol_dual=self._symbol_dual, latex_symbol_dual=self._latex_symbol_dual) ts_frame_bases[self] = basis # Update of the change of bases in the tangent space: for frame_pair, automorph in self._domain._frame_changes.items(): @@ -1486,9 +1432,7 @@ def at(self, point): ts._basis_changes[(basis1, basis2)] = auto return basis - def set_name(self, symbol, latex_symbol=None, indices=None, - latex_indices=None, index_position='down', - include_domain=True): + def set_name(self, symbol, latex_symbol=None, indices=None, latex_indices=None, index_position='down', include_domain=True): r""" Set (or change) the text name and LaTeX name of ``self``. @@ -1541,17 +1485,14 @@ def set_name(self, symbol, latex_symbol=None, indices=None, sage: latex(e) \left(M, \left(E_{\alpha},E_{\beta}\right)\right) """ - super().set_name(symbol, latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - index_position=index_position) + super().set_name(symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, index_position=index_position) if include_domain: # Redefinition of the name and the LaTeX name to include the domain self._name = "({}, {})".format(self._domain._name, self._name) - self._latex_name = r"\left({}, {}\right)".format( - self._domain._latex_name, self._latex_name) + self._latex_name = r"\left({}, {}\right)".format(self._domain._latex_name, self._latex_name) + -#****************************************************************************** +# ****************************************************************************** class CoordCoFrame(CoFrame): @@ -1627,8 +1568,8 @@ class CoordCoFrame(CoFrame): sage: dX[1].exterior_derivative() == 0 True """ - def __init__(self, coord_frame, symbol, latex_symbol=None, indices=None, - latex_indices=None): + + def __init__(self, coord_frame, symbol, latex_symbol=None, indices=None, latex_indices=None): r""" Construct a coordinate coframe. @@ -1643,8 +1584,7 @@ def __init__(self, coord_frame, symbol, latex_symbol=None, indices=None, """ if not isinstance(coord_frame, CoordFrame): raise TypeError("the first argument must be a coordinate frame") - CoFrame.__init__(self, coord_frame, symbol, latex_symbol=latex_symbol, - indices=indices, latex_indices=latex_indices) + CoFrame.__init__(self, coord_frame, symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices) self._chart = coord_frame._chart def _repr_(self): @@ -1665,7 +1605,8 @@ def _repr_(self): """ return "Coordinate coframe " + self._name -#****************************************************************************** + +# ****************************************************************************** class CoordFrame(VectorFrame): @@ -1717,30 +1658,21 @@ def __init__(self, chart): from sage.manifolds.differentiable.chart import DiffChart from sage.misc.latex import latex from sage.typeset.unicode_characters import unicode_partial + if not isinstance(chart, DiffChart): raise TypeError("the first argument must be a chart") dom = chart.domain() # Some sanity check: vmodule = dom._vector_field_modules.get(dom.identity_map()) if vmodule and not isinstance(vmodule, FiniteRankFreeModule): - raise ValueError("the {} has already been constructed as a " - "non-free module, which implies that the {} is " - "not parallelizable and hence cannot be the " - "domain of a coordinate chart".format(vmodule, - dom)) + raise ValueError("the {} has already been constructed as a " "non-free module, which implies that the {} is " "not parallelizable and hence cannot be the " "domain of a coordinate chart".format(vmodule, dom)) self._chart = chart - coords = chart[:] # list of all coordinates - symbol = tuple(f"{unicode_partial}/{unicode_partial}{x!s}" - for x in coords) - latex_symbol = tuple(r"\frac{\partial}{\partial" + latex(x) + "}" - for x in coords) + coords = chart[:] # list of all coordinates + symbol = tuple(f"{unicode_partial}/{unicode_partial}{x!s}" for x in coords) + latex_symbol = tuple(r"\frac{\partial}{\partial" + latex(x) + "}" for x in coords) symbol_dual = tuple("d" + str(x) for x in coords) latex_symbol_dual = tuple(r"\mathrm{d}" + latex(x) for x in coords) - VectorFrame.__init__(self, - dom.vector_field_module(force_free=True), - symbol=symbol, latex_symbol=latex_symbol, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) + VectorFrame.__init__(self, dom.vector_field_module(force_free=True), symbol=symbol, latex_symbol=latex_symbol, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) # In the above: # - force_free=True ensures that a free module is constructed in case # it is the first call to the vector field module on chart.domain() @@ -1824,8 +1756,6 @@ def structure_coeff(self): True """ from sage.tensor.modules.comp import CompWithSym + # A zero CompWithSym - return CompWithSym(self._fmodule._ring, self, 3, - start_index=self._fmodule._sindex, - output_formatter=self._fmodule._output_formatter, - antisym=(1,2)) + return CompWithSym(self._fmodule._ring, self, 3, start_index=self._fmodule._sindex, output_formatter=self._fmodule._output_formatter, antisym=(1, 2)) diff --git a/src/sage/manifolds/family.py b/src/sage/manifolds/family.py index e74a982e070..cd62bca1d67 100644 --- a/src/sage/manifolds/family.py +++ b/src/sage/manifolds/family.py @@ -15,6 +15,7 @@ - Matthias Koeppe (2021): initial version """ + # ***************************************************************************** # Copyright (C) 2021 Matthias Koeppe # @@ -98,9 +99,7 @@ def __init__(self, objects=(), keys=None): if keys is None: keys = sorted(dictionary.keys()) FiniteFamily.__init__(self, dictionary, keys) - names_and_latex_names = sorted( - (object._name, object._latex_name) for object in self - ) + names_and_latex_names = sorted((object._name, object._latex_name) for object in self) self._name = '{' + ', '.join(keys) + '}' latex_names = (latex_name for name, latex_name in names_and_latex_names) self._latex_name = r'\{' + ', '.join(latex_names) + r'\}' @@ -111,9 +110,7 @@ def __init__(self, objects=(), keys=None): self._manifold = None else: if not all(object._manifold == self._manifold for object in object_iter): - raise TypeError( - f'all {self._repr_object_type()} must have the same manifold' - ) + raise TypeError(f'all {self._repr_object_type()} must have the same manifold') def _repr_object_type(self): r""" @@ -167,9 +164,7 @@ def __repr__(self): 'Set {A, B} of objects of the 2-dimensional topological manifold M' """ if self: - return "Set {} of {} of the {}".format( - self._name, self._repr_object_type(), self._manifold - ) + return "Set {} of {} of the {}".format(self._name, self._repr_object_type(), self._manifold) return "{}" def _latex_(self): diff --git a/src/sage/manifolds/local_frame.py b/src/sage/manifolds/local_frame.py index 3d13c977f9a..e2d6fb7e100 100644 --- a/src/sage/manifolds/local_frame.py +++ b/src/sage/manifolds/local_frame.py @@ -252,8 +252,8 @@ class LocalCoFrame(FreeModuleCoBasis): sage: f[3](e[1]).expr(), f[3](e[2]).expr(), f[3](e[3]).expr() (0, 0, 1) """ - def __init__(self, frame, symbol, latex_symbol=None, indices=None, - latex_indices=None): + + def __init__(self, frame, symbol, latex_symbol=None, indices=None, latex_indices=None): r""" Construct a local coframe, dual to a given local frame. @@ -270,9 +270,7 @@ def __init__(self, frame, symbol, latex_symbol=None, indices=None, self._domain = frame.domain() self._base_space = frame.base_space() self._vbundle = frame.vector_bundle() - FreeModuleCoBasis.__init__(self, frame, symbol, - latex_symbol=latex_symbol, indices=indices, - latex_indices=latex_indices) + FreeModuleCoBasis.__init__(self, frame, symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices) # The coframe is added to the vector bundle's set of coframes self._vbundle._coframes.append(self) @@ -339,9 +337,7 @@ def at(self, point): """ return self._basis.at(point).dual_basis() - def set_name(self, symbol, latex_symbol=None, indices=None, - latex_indices=None, index_position='up', - include_domain=True): + def set_name(self, symbol, latex_symbol=None, indices=None, latex_indices=None, index_position='up', include_domain=True): r""" Set (or change) the text name and LaTeX name of ``self``. @@ -392,20 +388,14 @@ def set_name(self, symbol, latex_symbol=None, indices=None, sage: latex(e) \left(E|_{M}, \left(e^{\xi},e^{\zeta}\right)\right) """ - super().set_name(symbol, latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - index_position=index_position) + super().set_name(symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, index_position=index_position) if include_domain: # Redefinition of the name and the LaTeX name to include the domain - self._name = "({}|_{}, {})".format(self._vbundle._name, - self._domain._name, self._name) - self._latex_name = r"\left({}|_{{{}}}, {}\right)".format( - self._vbundle._latex_name, - self._domain._latex_name, - self._latex_name) + self._name = "({}|_{}, {})".format(self._vbundle._name, self._domain._name, self._name) + self._latex_name = r"\left({}|_{{{}}}, {}\right)".format(self._vbundle._latex_name, self._domain._latex_name, self._latex_name) + -#****************************************************************************** +# ****************************************************************************** class LocalFrame(FreeModuleBasis): @@ -557,10 +547,7 @@ class LocalFrame(FreeModuleBasis): _cobasis_class = LocalCoFrame @staticmethod - def __classcall_private__(cls, section_module, symbol, - latex_symbol=None, indices=None, - latex_indices=None, symbol_dual=None, - latex_symbol_dual=None): + def __classcall_private__(cls, section_module, symbol, latex_symbol=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): """ Transform input lists into tuples for the unique representation of LocalFrame. @@ -590,15 +577,9 @@ def __classcall_private__(cls, section_module, symbol, symbol_dual = tuple(symbol_dual) if isinstance(latex_symbol_dual, list): latex_symbol_dual = tuple(latex_symbol_dual) - return super().__classcall__(cls, section_module, - symbol, latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) - - def __init__(self, section_module, symbol, latex_symbol=None, indices=None, - latex_indices=None, symbol_dual=None, latex_symbol_dual=None): + return super().__classcall__(cls, section_module, symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) + + def __init__(self, section_module, symbol, latex_symbol=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): r""" Construct a local frame on a vector bundle. @@ -615,17 +596,11 @@ def __init__(self, section_module, symbol, latex_symbol=None, indices=None, ### # Some sanity check: if not isinstance(section_module, FiniteRankFreeModule): - raise ValueError("the {} has already been constructed as a " - "non-free module and therefore cannot have " - "a basis".format(section_module)) + raise ValueError("the {} has already been constructed as a " "non-free module and therefore cannot have " "a basis".format(section_module)) self._domain = section_module.domain() self._base_space = section_module.base_space() self._vbundle = section_module.vector_bundle() - FreeModuleBasis.__init__(self, section_module, - symbol, latex_symbol=latex_symbol, - indices=indices, latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) + FreeModuleBasis.__init__(self, section_module, symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) if self._vbundle._def_frame is None: self._vbundle._def_frame = self # The frame is added to the domain's modules of frames, as well as to @@ -647,12 +622,12 @@ def __init__(self, section_module, symbol, latex_symbol=None, indices=None, self._coframe = self.dual_basis() # Shortcut for self._dual_basis ### # Frame restrictions: - self._subframes = set([self]) # Set of frames which are just a - # restriction of self - self._superframes = set([self]) # Set of frames for which self is a - # restriction of - self._restrictions = {} # Key: subdomain of self._domain; value: - # restriction of self on this subdomain + self._subframes = set([self]) # Set of frames which are just a + # restriction of self + self._superframes = set([self]) # Set of frames for which self is a + # restriction of + self._restrictions = {} # Key: subdomain of self._domain; value: + # restriction of self on this subdomain ###### Methods that must be redefined by derived classes of ###### ###### FreeModuleBasis ###### @@ -675,9 +650,7 @@ def _repr_(self): desc = "Local frame " + self._name return desc - def _new_instance(self, symbol, latex_symbol=None, indices=None, - latex_indices=None, symbol_dual=None, - latex_symbol_dual=None): + def _new_instance(self, symbol, latex_symbol=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): r""" Construct a new local frame on the same section module as ``self``. @@ -717,10 +690,7 @@ def _new_instance(self, symbol, latex_symbol=None, indices=None, sage: e._new_instance('f') Local frame (E|_M, (f_0,f_1)) """ - return LocalFrame(self._fmodule, symbol, latex_symbol=latex_symbol, - indices=indices, latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) + return LocalFrame(self._fmodule, symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) ###### End of methods to be redefined by derived classes ###### @@ -788,9 +758,7 @@ def coframe(self): """ return self._coframe - def new_frame(self, change_of_frame, symbol, latex_symbol=None, - indices=None, latex_indices=None, symbol_dual=None, - latex_symbol_dual=None): + def new_frame(self, change_of_frame, symbol, latex_symbol=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): r""" Define a new local frame from ``self``. @@ -877,16 +845,9 @@ def new_frame(self, change_of_frame, symbol, latex_symbol=None, sage: e[2].comp(f)[:] [1/2, 1/2*sqrt(3)] """ - the_new_frame = self.new_basis(change_of_frame, symbol, - latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) - self._vbundle._frame_changes[(self, the_new_frame)] = \ - self._fmodule._basis_changes[(self, the_new_frame)] - self._vbundle._frame_changes[(the_new_frame, self)] = \ - self._fmodule._basis_changes[(the_new_frame, self)] + the_new_frame = self.new_basis(change_of_frame, symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) + self._vbundle._frame_changes[(self, the_new_frame)] = self._fmodule._basis_changes[(self, the_new_frame)] + self._vbundle._frame_changes[(the_new_frame, self)] = self._fmodule._basis_changes[(the_new_frame, self)] return the_new_frame def restrict(self, subdomain): @@ -940,8 +901,7 @@ def restrict(self, subdomain): return self if subdomain not in self._restrictions: if not subdomain.is_subset(self._domain): - raise ValueError("the provided domain is not a subdomain of " + - "the current frame's domain") + raise ValueError("the provided domain is not a subdomain of " + "the current frame's domain") # First one tries to get the restriction from a tighter domain: for dom, rst in self._restrictions.items(): if subdomain.is_subset(dom) and subdomain in rst._restrictions: @@ -963,14 +923,8 @@ def restrict(self, subdomain): return self._restrictions[subdomain] # If this point is reached, the restriction has to be created # from scratch - resmodule = self._vbundle.section_module(domain=subdomain, - force_free=True) - res = LocalFrame(resmodule, - self._symbol, latex_symbol=self._latex_symbol, - indices=self._indices, - latex_indices=self._latex_indices, - symbol_dual=self._symbol_dual, - latex_symbol_dual=self._latex_symbol_dual) + resmodule = self._vbundle.section_module(domain=subdomain, force_free=True) + res = LocalFrame(resmodule, self._symbol, latex_symbol=self._latex_symbol, indices=self._indices, latex_indices=self._latex_indices, symbol_dual=self._symbol_dual, latex_symbol_dual=self._latex_symbol_dual) new_vectors = list() for i in self._fmodule.irange(): @@ -986,7 +940,7 @@ def restrict(self, subdomain): res._superframes.update(sframe._superframes) for sframe in res._superframes: sframe._subframes.add(res) - sframe._restrictions[subdomain] = res # includes sframe = self + sframe._restrictions[subdomain] = res # includes sframe = self for dom, rst in self._restrictions.items(): if dom.is_subset(subdomain): res._restrictions.update(rst._restrictions) @@ -1094,8 +1048,7 @@ def at(self, point): """ # Determination of the vector bundle fiber: if point not in self._domain: - raise ValueError("the {} is not a point in the ".format(point) + - "domain of {}".format(self)) + raise ValueError("the {} is not a point in the ".format(point) + "domain of {}".format(self)) vbf = self._vbundle.fiber(point) # If the basis has already been constructed, it is simply returned: vbf_frame_bases = vbf._frame_bases @@ -1107,11 +1060,7 @@ def at(self, point): # If this point is reached, the basis has to be constructed from # scratch. # The names of the basis vectors set to those of the frame sections: - basis = vbf.basis(self._symbol, latex_symbol=self._latex_symbol, - indices=self._indices, - latex_indices=self._latex_indices, - symbol_dual=self._symbol_dual, - latex_symbol_dual=self._latex_symbol_dual) + basis = vbf.basis(self._symbol, latex_symbol=self._latex_symbol, indices=self._indices, latex_indices=self._latex_indices, symbol_dual=self._symbol_dual, latex_symbol_dual=self._latex_symbol_dual) vbf_frame_bases[self] = basis # Update of the change of bases in the fiber: for frame_pair, automorph in self._vbundle._frame_changes.items(): @@ -1161,9 +1110,7 @@ def at(self, point): vbf._basis_changes[(basis1, basis2)] = auto return basis - def set_name(self, symbol, latex_symbol=None, indices=None, - latex_indices=None, index_position='down', - include_domain=True): + def set_name(self, symbol, latex_symbol=None, indices=None, latex_indices=None, index_position='down', include_domain=True): r""" Set (or change) the text name and LaTeX name of ``self``. @@ -1217,20 +1164,14 @@ def set_name(self, symbol, latex_symbol=None, indices=None, sage: latex(e) \left(E|_{M}, \left(E_{\alpha},E_{\beta}\right)\right) """ - super().set_name(symbol, latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - index_position=index_position) + super().set_name(symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, index_position=index_position) if include_domain: # Redefinition of the name and the LaTeX name to include the domain - self._name = "({}|_{}, {})".format(self._vbundle._name, - self._domain._name, self._name) - self._latex_name = r"\left({}|_{{{}}}, {}\right)".format( - self._vbundle._latex_name, - self._domain._latex_name, - self._latex_name) + self._name = "({}|_{}, {})".format(self._vbundle._name, self._domain._name, self._name) + self._latex_name = r"\left({}|_{{{}}}, {}\right)".format(self._vbundle._latex_name, self._domain._latex_name, self._latex_name) + -#****************************************************************************** +# ****************************************************************************** class TrivializationCoFrame(LocalCoFrame): @@ -1321,8 +1262,8 @@ class `C^k` and rank `n` over the topological field `K` and over a sage: f[3](e[1]).expr(), f[3](e[2]).expr(), f[3](e[3]).expr() (0, 0, 1) """ - def __init__(self, triv_frame, symbol, latex_symbol=None, - indices=None, latex_indices=None): + + def __init__(self, triv_frame, symbol, latex_symbol=None, indices=None, latex_indices=None): r""" Construct a local coframe from a local trivialization. @@ -1337,11 +1278,8 @@ def __init__(self, triv_frame, symbol, latex_symbol=None, sage: TestSuite(f).run() """ if not isinstance(triv_frame, TrivializationFrame): - raise TypeError("the first argument must be a local trivialization " - "frame") - LocalCoFrame.__init__(self, triv_frame, symbol, - latex_symbol=latex_symbol, indices=indices, - latex_indices=latex_indices) + raise TypeError("the first argument must be a local trivialization " "frame") + LocalCoFrame.__init__(self, triv_frame, symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices) self._trivialization = triv_frame._trivialization def _repr_(self): @@ -1363,7 +1301,8 @@ def _repr_(self): """ return "Trivialization coframe " + self._name -#****************************************************************************** + +# ****************************************************************************** class TrivializationFrame(LocalFrame): @@ -1415,6 +1354,7 @@ def __init__(self, trivialization): """ from sage.manifolds.trivialization import Trivialization from sage.misc.latex import latex + if not isinstance(trivialization, Trivialization): raise TypeError("the first argument must be a trivialization") ### @@ -1426,30 +1366,18 @@ def __init__(self, trivialization): # Some sanity check: smodule = vbundle._section_modules.get(domain) if smodule and not isinstance(smodule, FiniteRankFreeModule): - raise ValueError("the {} has already been constructed as a " - "non-free module and therefore cannot have " - "a basis".format(smodule)) + raise ValueError("the {} has already been constructed as a " "non-free module and therefore cannot have " "a basis".format(smodule)) ### # Set trivialization: self._trivialization = triv ### # Define trivialization names rank = vbundle.rank() - symbol = tuple("(" + triv._name + "^*" + "e_" + str(i) + ")" - for i in range(1, rank + 1)) - symbol_dual = tuple("(" + triv._name + "^*" + "e^" + str(i) + ")" - for i in range(1, rank + 1)) - latex_symbol = tuple(r'\left(' + triv._latex_name + r'^* e_{' + - latex(i) + r'}\right)' - for i in range(1, rank + 1)) - latex_symbol_dual = tuple(r'\left(' + triv._latex_name + r'^* e^{' + - latex(i) + r'}\right)' - for i in range(1, rank + 1)) - LocalFrame.__init__(self, - vbundle.section_module(domain=domain, force_free=True), - symbol=symbol, latex_symbol=latex_symbol, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) + symbol = tuple("(" + triv._name + "^*" + "e_" + str(i) + ")" for i in range(1, rank + 1)) + symbol_dual = tuple("(" + triv._name + "^*" + "e^" + str(i) + ")" for i in range(1, rank + 1)) + latex_symbol = tuple(r'\left(' + triv._latex_name + r'^* e_{' + latex(i) + r'}\right)' for i in range(1, rank + 1)) + latex_symbol_dual = tuple(r'\left(' + triv._latex_name + r'^* e^{' + latex(i) + r'}\right)' for i in range(1, rank + 1)) + LocalFrame.__init__(self, vbundle.section_module(domain=domain, force_free=True), symbol=symbol, latex_symbol=latex_symbol, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) def _repr_(self): r""" diff --git a/src/sage/manifolds/manifold.py b/src/sage/manifolds/manifold.py index 29c1b1dfb6d..509e7fb7e27 100644 --- a/src/sage/manifolds/manifold.py +++ b/src/sage/manifolds/manifold.py @@ -360,6 +360,7 @@ ############################################################################# # Class + class TopologicalManifold(ManifoldSubset): r""" Topological manifold over a topological field `K`. @@ -519,11 +520,10 @@ class being :class:`~sage.manifolds.point.ManifoldPoint`. :mod:`sage.manifolds.manifold` """ + _dim: int - def __init__(self, n, name, field, structure, base_manifold=None, - latex_name=None, start_index=0, category=None, - unique_tag=None): + def __init__(self, n, name, field, structure, base_manifold=None, latex_name=None, start_index=0, category=None, unique_tag=None): r""" Construct a topological manifold. @@ -578,8 +578,7 @@ def __init__(self, n, name, field, structure, base_manifold=None, else: category = base_manifold.category().Subobjects() # Initialization as a manifold set: - ManifoldSubset.__init__(self, base_manifold, name, latex_name=latex_name, - category=category) + ManifoldSubset.__init__(self, base_manifold, name, latex_name=latex_name, category=category) self._is_open = True self._open_covers.append([self]) # list of open covers of self @@ -589,14 +588,14 @@ def __init__(self, n, name, field, structure, base_manifold=None, self._atlas = [] # list of charts defined on subsets of self self._top_charts = [] # list of charts defined on subsets of self - # that are not subcharts of charts on larger subsets + # that are not subcharts of charts on larger subsets self._def_chart = None # default chart - self._orientation = [] # set no orientation a priori - self._charts_by_coord = {} # dictionary of charts whose domain is self - # (key: string formed by the coordinate - # symbols separated by a white space) - self._coord_changes = {} # dictionary of transition maps (key: pair of - # of charts) + self._orientation = [] # set no orientation a priori + self._charts_by_coord = {} # dictionary of charts whose domain is self + # (key: string formed by the coordinate + # symbols separated by a white space) + self._coord_changes = {} # dictionary of transition maps (key: pair of + # of charts) # List of charts that individually cover self, i.e. whose # domains are self (if non-empty, self is a coordinate domain): self._covering_charts = [] @@ -640,23 +639,12 @@ def _repr_(self): """ if self is self._manifold: if self._field_type == 'real': - return "{}-dimensional {} manifold {}".format(self._dim, - self._structure.name, - self._name) + return "{}-dimensional {} manifold {}".format(self._dim, self._structure.name, self._name) if self._field_type == 'complex': if isinstance(self._structure, DifferentialStructure): - return "{}-dimensional complex manifold {}".format( - self._dim, - self._name) - return "Complex {}-dimensional {} manifold {}".format( - self._dim, - self._structure.name, - self._name) - return "{}-dimensional {} manifold {} over the {}".format( - self._dim, - self._structure.name, - self._name, - self._field) + return "{}-dimensional complex manifold {}".format(self._dim, self._name) + return "Complex {}-dimensional {} manifold {}".format(self._dim, self._structure.name, self._name) + return "{}-dimensional {} manifold {} over the {}".format(self._dim, self._structure.name, self._name, self._field) return "Open subset {} of the {}".format(self._name, self._manifold) def _an_element_(self): @@ -688,6 +676,7 @@ def _an_element_(self): (-pi - 1, 2) """ from sage.rings.infinity import Infinity + if self._def_chart is None: return self.element_class(self) # Attempt to construct a point in the domain of the default chart @@ -706,16 +695,16 @@ def _an_element_(self): if xmax == Infinity: x = xmin + 1 else: - x = (xmin + xmax)/2 + x = (xmin + xmax) / 2 coords.append(x) else: - coords = self._dim*[0] + coords = self._dim * [0] if not chart.valid_coordinates(*coords): # Attempt to construct a point in the domain of other charts if self._field_type == 'real': for ch in self._atlas: if ch is self._def_chart: - continue # since this case has already been attempted + continue # since this case has already been attempted coords = [] for coord_range in ch._bounds: xmin = coord_range[0][0] @@ -729,7 +718,7 @@ def _an_element_(self): if xmax == Infinity: x = xmin + 1 else: - x = (xmin + xmax)/2 + x = (xmin + xmax) / 2 coords.append(x) if ch.valid_coordinates(*coords): chart = ch @@ -744,7 +733,7 @@ def _an_element_(self): # Case of manifolds over a field different from R for ch in self._atlas: if ch is self._def_chart: - continue # since this case has already been attempted + continue # since this case has already been attempted if ch.valid_coordinates(*coords): chart = ch break @@ -752,8 +741,7 @@ def _an_element_(self): return self.element_class(self) # The point is constructed with check_coords=False since the check # has just been performed above: - return self.element_class(self, coords=coords, chart=chart, - check_coords=False) + return self.element_class(self, coords=coords, chart=chart, check_coords=False) def __contains__(self, point): r""" @@ -786,12 +774,11 @@ def __contains__(self, point): return True for chart in self._atlas: if chart in point._coordinates: - if chart.valid_coordinates( *(point._coordinates[chart]) ): + if chart.valid_coordinates(*(point._coordinates[chart])): return True for chart in point._coordinates: for schart in chart._subcharts: - if schart in self._atlas and schart.valid_coordinates( - *(point._coordinates[chart]) ): + if schart in self._atlas and schart.valid_coordinates(*(point._coordinates[chart])): return True return False @@ -879,11 +866,7 @@ def open_subset(self, name, latex_name=None, coord_def={}, supersets=None): sage: M.point((1,2)) in U False """ - resu = TopologicalManifold(self._dim, name, self._field, - self._structure, - base_manifold=self._manifold, - latex_name=latex_name, - start_index=self._sindex) + resu = TopologicalManifold(self._dim, name, self._field, self._structure, base_manifold=self._manifold, latex_name=latex_name, start_index=self._sindex) if supersets is None: supersets = [self] for superset in supersets: @@ -923,8 +906,7 @@ def _init_open_subset(self, resu, coord_def): # Charts on the result from the coordinate definition: for chart, restrictions in coord_def.items(): if chart not in self._atlas: - raise ValueError("the {} does not belong to ".format(chart) + - "the atlas of {}".format(self)) + raise ValueError("the {} does not belong to ".format(chart) + "the atlas of {}".format(self)) chart.restrict(resu, restrictions) # Transition maps on the result inferred from those of self: for chart1 in coord_def: @@ -984,9 +966,7 @@ def get_chart(self, coordinates, domain=None): try: return dom._charts_by_coord[coordinates] except KeyError: - raise KeyError("the coordinates '{}' ".format(coordinates) + - "do not correspond to any chart with " + - "the {} as domain".format(dom)) + raise KeyError("the coordinates '{}' ".format(coordinates) + "do not correspond to any chart with " + "the {} as domain".format(dom)) def dimension(self): r""" @@ -1174,17 +1154,17 @@ def index_generator(self, nb_indices): imax = self._dim - 1 + si ind = [si for k in range(nb_indices)] ind_end = [si for k in range(nb_indices)] - ind_end[0] = imax+1 + ind_end[0] = imax + 1 while ind != ind_end: yield tuple(ind) ret = 1 - for pos in range(nb_indices-1, -1, -1): + for pos in range(nb_indices - 1, -1, -1): if ind[pos] != imax: ind[pos] += ret ret = 0 elif ret == 1: if pos == 0: - ind[pos] = imax + 1 # end point reached + ind[pos] = imax + 1 # end point reached else: ind[pos] = si ret = 1 @@ -1231,7 +1211,7 @@ def atlas(self) -> list[Chart]: :meth:`top_charts` """ - return list(self._atlas) # Make a (shallow) copy + return list(self._atlas) # Make a (shallow) copy def top_charts(self): r""" @@ -1265,7 +1245,7 @@ def top_charts(self): :meth:`atlas` for the complete list of charts defined on the manifold. """ - return list(self._top_charts) # Make a (shallow) copy + return list(self._top_charts) # Make a (shallow) copy def default_chart(self): r""" @@ -1320,6 +1300,7 @@ def set_default_chart(self, chart): Chart (M, (u, v)) """ from sage.manifolds.chart import Chart + if not isinstance(chart, Chart): raise TypeError("{} is not a chart".format(chart)) if chart not in self._atlas: @@ -1358,9 +1339,7 @@ def coord_change(self, chart1, chart2): Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v)) """ if (chart1, chart2) not in self._coord_changes: - raise TypeError("the change of coordinates from " + - "{} to {}".format(chart1, chart2) + " has not " + - "been defined on the {}".format(self)) + raise TypeError("the change of coordinates from " + "{} to {}".format(chart1, chart2) + " has not " + "been defined on the {}".format(self)) return self._coord_changes[(chart1, chart2)] def coord_changes(self): @@ -1608,9 +1587,7 @@ def chart( """ if calc_method is None: calc_method = self._calculus_method - return self._structure.chart(self, coordinates=coordinates, - names=names, calc_method=calc_method, - coord_restrictions=coord_restrictions) + return self._structure.chart(self, coordinates=coordinates, names=names, calc_method=calc_method, coord_restrictions=coord_restrictions) def is_open(self): """ @@ -1668,16 +1645,14 @@ def set_orientation(self, orientation): elif isinstance(orientation, (tuple, list)): orientation = list(orientation) else: - raise TypeError("orientation must be a chart or a list/tuple of " - "charts") + raise TypeError("orientation must be a chart or a list/tuple of " "charts") dom_union = None for c in orientation: if not isinstance(c, chart_type): raise ValueError("orientation must consist of charts") dom = c._domain if not dom.is_subset(self): - raise ValueError("{} must be defined ".format(c) + - "on a subset of {}".format(self)) + raise ValueError("{} must be defined ".format(c) + "on a subset of {}".format(self)) if dom_union is not None: dom_union = dom.union(dom_union) else: @@ -1871,8 +1846,8 @@ def vector_bundle(self, rank, name, field='real', latex_name=None): 2-dimensional topological manifold M """ from sage.manifolds.vector_bundle import TopologicalVectorBundle - return TopologicalVectorBundle(rank, name, self, field=field, - latex_name=latex_name) + + return TopologicalVectorBundle(rank, name, self, field=field, latex_name=latex_name) def scalar_field_algebra(self): r""" @@ -1908,9 +1883,7 @@ def scalar_field_algebra(self): """ return self._scalar_field_algebra - def scalar_field( - self, coord_expression=None, chart=None, name=None, latex_name=None - ) -> ScalarField: + def scalar_field(self, coord_expression=None, chart=None, name=None, latex_name=None) -> ScalarField: r""" Define a scalar field on the manifold. @@ -2000,11 +1973,9 @@ def scalar_field( # check validity of entry for chart in coord_expression: if not chart.domain().is_subset(self): - raise ValueError("the {} is not defined ".format(chart) + - "on some subset of the " + str(self)) + raise ValueError("the {} is not defined ".format(chart) + "on some subset of the " + str(self)) alg = self.scalar_field_algebra() - return alg.element_class(alg, coord_expression=coord_expression, - name=name, latex_name=latex_name, chart=chart) + return alg.element_class(alg, coord_expression=coord_expression, name=name, latex_name=latex_name, chart=chart) def constant_scalar_field(self, value, name=None, latex_name=None): r""" @@ -2059,8 +2030,7 @@ def constant_scalar_field(self, value, name=None, latex_name=None): if value == 0: return self.zero_scalar_field() alg = self.scalar_field_algebra() - return alg.element_class(alg, coord_expression=value, name=name, - latex_name=latex_name, chart='all') + return alg.element_class(alg, coord_expression=value, name=name, latex_name=latex_name, chart='all') def zero_scalar_field(self): r""" @@ -2164,15 +2134,12 @@ class options(GlobalOptions): u*v sage: M.options._reset() """ + NAME = 'manifolds' module = 'sage.manifolds.manifold' option_class = 'TopologicalManifold' - textbook_output = dict(default=True, - description='textbook-like output instead of the Pynac output for derivatives', - checker=lambda x: isinstance(x, bool)) - omit_function_arguments = dict(default=False, - description='Determine whether the arguments of symbolic functions are printed', - checker=lambda x: isinstance(x, bool)) + textbook_output = dict(default=True, description='textbook-like output instead of the Pynac output for derivatives', checker=lambda x: isinstance(x, bool)) + omit_function_arguments = dict(default=False, description='Determine whether the arguments of symbolic functions are printed', checker=lambda x: isinstance(x, bool)) def _Hom_(self, other, category=None): r""" @@ -2212,8 +2179,7 @@ def _Hom_(self, other, category=None): """ return self._structure.homset(self, other) - def continuous_map(self, codomain, coord_functions=None, chart1=None, - chart2=None, name=None, latex_name=None): + def continuous_map(self, codomain, coord_functions=None, chart1=None, chart2=None, name=None, latex_name=None): r""" Define a continuous map from ``self`` to ``codomain``. @@ -2305,8 +2271,7 @@ def continuous_map(self, codomain, coord_functions=None, chart1=None, Allow the construction of continuous maps from ``self`` to the base field (considered as a trivial 1-dimensional manifold). """ - if (not isinstance(codomain, TopologicalManifold) - or codomain.base_field() != self.base_field()): + if not isinstance(codomain, TopologicalManifold) or codomain.base_field() != self.base_field(): raise ValueError("{} is not a manifold over {}".format(codomain, self.base_field())) homset = Hom(self, codomain) if coord_functions is None: @@ -2316,18 +2281,15 @@ def continuous_map(self, codomain, coord_functions=None, chart1=None, if chart1 is None: chart1 = self._def_chart elif chart1 not in self._atlas: - raise ValueError("{} is not a chart ".format(chart1) + - "defined on the {}".format(self)) + raise ValueError("{} is not a chart ".format(chart1) + "defined on the {}".format(self)) if chart2 is None: chart2 = codomain._def_chart elif chart2 not in codomain._atlas: - raise ValueError("{} is not a chart ".format(chart2) + - " defined on the {}".format(codomain)) + raise ValueError("{} is not a chart ".format(chart2) + " defined on the {}".format(codomain)) coord_functions = {(chart1, chart2): coord_functions} return homset(coord_functions, name=name, latex_name=latex_name) - def homeomorphism(self, codomain, coord_functions=None, chart1=None, - chart2=None, name=None, latex_name=None): + def homeomorphism(self, codomain, coord_functions=None, chart1=None, chart2=None, name=None, latex_name=None): r""" Define a homeomorphism between the current manifold and another one. @@ -2409,16 +2371,13 @@ def homeomorphism(self, codomain, coord_functions=None, chart1=None, if chart1 is None: chart1 = self._def_chart elif chart1 not in self._atlas: - raise ValueError("{} is not a chart ".format(chart1) + - "defined on the {}".format(self)) + raise ValueError("{} is not a chart ".format(chart1) + "defined on the {}".format(self)) if chart2 is None: chart2 = codomain._def_chart elif chart2 not in codomain._atlas: - raise ValueError("{} is not a chart ".format(chart2) + - " defined on the {}".format(codomain)) + raise ValueError("{} is not a chart ".format(chart2) + " defined on the {}".format(codomain)) coord_functions = {(chart1, chart2): coord_functions} - return homset(coord_functions, name=name, latex_name=latex_name, - is_isomorphism=True) + return homset(coord_functions, name=name, latex_name=latex_name, is_isomorphism=True) @overload def identity_map(self: TopologicalManifold) -> ContinuousMap: ... @@ -2670,8 +2629,7 @@ def set_simplify_function(self, simplifying_func, method=None): """ for chart in self._atlas: - chart.calculus_method().set_simplify_function(simplifying_func, - method=method) + chart.calculus_method().set_simplify_function(simplifying_func, method=method) ########################################################### @@ -2966,11 +2924,10 @@ def Manifold( global _manifold_id _manifold_id += 1 - unique_tag = lambda: getrandbits(128)*_manifold_id + unique_tag = lambda: getrandbits(128) * _manifold_id if structure is None: - if any(extra_kwds.get(x, None) is not None - for x in ('metric_name', 'metric_latex_name', 'signature')): + if any(extra_kwds.get(x, None) is not None for x in ('metric_name', 'metric_latex_name', 'signature')): structure = 'pseudo-Riemannian' if structure is None: @@ -2989,21 +2946,13 @@ def Manifold( structure = TopologicalStructure() if 'ambient' in extra_kwds: ambient = extra_kwds['ambient'] - return TopologicalSubmanifold(dim, name, field, structure, - ambient=ambient, - latex_name=latex_name, - start_index=start_index, - unique_tag=unique_tag()) - return TopologicalManifold(dim, name, field, structure, - latex_name=latex_name, - start_index=start_index, - unique_tag=unique_tag()) + return TopologicalSubmanifold(dim, name, field, structure, ambient=ambient, latex_name=latex_name, start_index=start_index, unique_tag=unique_tag()) + return TopologicalManifold(dim, name, field, structure, latex_name=latex_name, start_index=start_index, unique_tag=unique_tag()) if structure in ['differentiable', 'diff', 'smooth']: if 'diff_degree' in extra_kwds: diff_degree = extra_kwds['diff_degree'] if structure == 'smooth' and diff_degree != infinity: - raise ValueError("diff_degree = {} is ".format(diff_degree) + - "not compatible with a smooth structure") + raise ValueError("diff_degree = {} is ".format(diff_degree) + "not compatible with a smooth structure") else: diff_degree = infinity if field == 'real' or isinstance(field, sage.rings.abc.RealField): @@ -3012,18 +2961,9 @@ def Manifold( structure = DifferentialStructure() if 'ambient' in extra_kwds: ambient = extra_kwds['ambient'] - return DifferentiableSubmanifold(dim, name, field, structure, - ambient=ambient, - diff_degree=diff_degree, - latex_name=latex_name, - start_index=start_index, - unique_tag=unique_tag()) - return DifferentiableManifold(dim, name, field, structure, - diff_degree=diff_degree, - latex_name=latex_name, - start_index=start_index, - unique_tag=unique_tag()) - if structure in ['pseudo-Riemannian', 'Riemannian', 'Lorentzian','degenerate_metric']: + return DifferentiableSubmanifold(dim, name, field, structure, ambient=ambient, diff_degree=diff_degree, latex_name=latex_name, start_index=start_index, unique_tag=unique_tag()) + return DifferentiableManifold(dim, name, field, structure, diff_degree=diff_degree, latex_name=latex_name, start_index=start_index, unique_tag=unique_tag()) + if structure in ['pseudo-Riemannian', 'Riemannian', 'Lorentzian', 'degenerate_metric']: diff_degree = extra_kwds.get('diff_degree', infinity) metric_name = extra_kwds.get('metric_name', None) metric_latex_name = extra_kwds.get('metric_latex_name', None) @@ -3032,7 +2972,7 @@ def Manifold( elif structure == 'Riemannian': signature = dim elif structure == 'degenerate_metric': - signature = (0, dim-1, 1) + signature = (0, dim - 1, 1) elif structure == 'Lorentzian': if 'signature' in extra_kwds: signat = extra_kwds['signature'] @@ -3041,47 +2981,18 @@ def Manifold( elif signat == 'negative' or signat == 2 - dim: signature = 2 - dim else: - raise ValueError("signature {} not ".format(signat) + - "compatible with a Lorentzian " + - "manifold of dimension {}".format(dim)) + raise ValueError("signature {} not ".format(signat) + "compatible with a Lorentzian " + "manifold of dimension {}".format(dim)) else: signature = dim - 2 # default value for a Lorentzian manifold if 'ambient' in extra_kwds: ambient = extra_kwds['ambient'] if structure == 'degenerate_metric': - return DegenerateSubmanifold(dim, name, ambient=ambient, - metric_name=metric_name, - signature=signature, - diff_degree=diff_degree, - latex_name=latex_name, - metric_latex_name=metric_latex_name, - start_index=start_index, - unique_tag=unique_tag()) - return PseudoRiemannianSubmanifold(dim, name, ambient=ambient, - metric_name=metric_name, - signature=signature, - diff_degree=diff_degree, - latex_name=latex_name, - metric_latex_name=metric_latex_name, - start_index=start_index, - unique_tag=unique_tag()) + return DegenerateSubmanifold(dim, name, ambient=ambient, metric_name=metric_name, signature=signature, diff_degree=diff_degree, latex_name=latex_name, metric_latex_name=metric_latex_name, start_index=start_index, unique_tag=unique_tag()) + return PseudoRiemannianSubmanifold(dim, name, ambient=ambient, metric_name=metric_name, signature=signature, diff_degree=diff_degree, latex_name=latex_name, metric_latex_name=metric_latex_name, start_index=start_index, unique_tag=unique_tag()) if structure == 'degenerate_metric': - return DegenerateManifold(dim, name, metric_name=metric_name, - signature=signature, - diff_degree=diff_degree, - latex_name=latex_name, - metric_latex_name=metric_latex_name, - start_index=start_index, - unique_tag=unique_tag()) - return PseudoRiemannianManifold(dim, name, metric_name=metric_name, - signature=signature, - diff_degree=diff_degree, - latex_name=latex_name, - metric_latex_name=metric_latex_name, - start_index=start_index, - unique_tag=unique_tag()) - raise NotImplementedError(f"manifolds of type {structure} are " + - "not implemented") + return DegenerateManifold(dim, name, metric_name=metric_name, signature=signature, diff_degree=diff_degree, latex_name=latex_name, metric_latex_name=metric_latex_name, start_index=start_index, unique_tag=unique_tag()) + return PseudoRiemannianManifold(dim, name, metric_name=metric_name, signature=signature, diff_degree=diff_degree, latex_name=latex_name, metric_latex_name=metric_latex_name, start_index=start_index, unique_tag=unique_tag()) + raise NotImplementedError(f"manifolds of type {structure} are " + "not implemented") Manifold.options = TopologicalManifold.options diff --git a/src/sage/manifolds/manifold_homset.py b/src/sage/manifolds/manifold_homset.py index f62c89e38e6..8ee811d22d0 100644 --- a/src/sage/manifolds/manifold_homset.py +++ b/src/sage/manifolds/manifold_homset.py @@ -16,6 +16,7 @@ - [Lee2011]_ - [KN1963]_ """ + # ****************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2016 Travis Scrimshaw @@ -175,15 +176,9 @@ def __init__(self, domain, codomain, name=None, latex_name=None): from sage.manifolds.manifold import TopologicalManifold if not isinstance(domain, TopologicalManifold): - raise TypeError( - "domain = {} is not an ".format(domain) - + "instance of TopologicalManifold" - ) + raise TypeError("domain = {} is not an ".format(domain) + "instance of TopologicalManifold") if not isinstance(codomain, TopologicalManifold): - raise TypeError( - "codomain = {} is not an ".format(codomain) - + "instance of TopologicalManifold" - ) + raise TypeError("codomain = {} is not an ".format(codomain) + "instance of TopologicalManifold") common_cat = domain.category()._meet_(codomain.category()) Homset.__init__(self, domain, codomain, category=common_cat) if name is None: @@ -191,9 +186,7 @@ def __init__(self, domain, codomain, name=None, latex_name=None): else: self._name = name if latex_name is None: - self._latex_name = r"\mathrm{{Hom}}\left({},{}\right)".format( - domain._latex_name, codomain._latex_name - ) + self._latex_name = r"\mathrm{{Hom}}\left({},{}\right)".format(domain._latex_name, codomain._latex_name) else: self._latex_name = latex_name @@ -345,9 +338,7 @@ def _coerce_map_from_(self, other): True """ if isinstance(other, TopologicalManifoldHomset): - return other.domain().has_coerce_map_from( - self.domain() - ) and self.codomain().has_coerce_map_from(other.codomain()) + return other.domain().has_coerce_map_from(self.domain()) and self.codomain().has_coerce_map_from(other.codomain()) return False #!# check diff --git a/src/sage/manifolds/point.py b/src/sage/manifolds/point.py index 54090190a26..a296cdeb569 100644 --- a/src/sage/manifolds/point.py +++ b/src/sage/manifolds/point.py @@ -76,7 +76,7 @@ True """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger # @@ -85,7 +85,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.decorators import options from sage.rings.integer_ring import ZZ @@ -164,8 +164,8 @@ class ManifoldPoint(Element): Points can be drawn in 2D or 3D graphics thanks to the method :meth:`plot`. """ - def __init__(self, parent, coords=None, chart=None, name=None, - latex_name=None, check_coords=True): + + def __init__(self, parent, coords=None, chart=None, name=None, latex_name=None, check_coords=True): r""" Construct a manifold point. @@ -186,23 +186,21 @@ def __init__(self, parent, coords=None, chart=None, name=None, Element.__init__(self, parent) parent._has_defined_points = True self._manifold = parent.manifold() # a useful shortcut - self._coordinates = {} # dictionary of the point coordinates in various - # charts, with the charts as keys + self._coordinates = {} # dictionary of the point coordinates in various + # charts, with the charts as keys if coords is not None: if len(coords) != parent.manifold().dimension(): - raise ValueError("the number of coordinates must be equal " + - "to the manifold's dimension") + raise ValueError("the number of coordinates must be equal " + "to the manifold's dimension") from sage.manifolds.manifold import TopologicalManifold + if chart is None: chart = parent._def_chart elif isinstance(parent, TopologicalManifold): if chart not in parent._atlas: - raise ValueError("the {} has not been".format(chart) + - "defined on the {}".format(parent)) + raise ValueError("the {} has not been".format(chart) + "defined on the {}".format(parent)) if check_coords: if not chart.valid_coordinates(*coords): - raise ValueError("the coordinates {}".format(coords) + - " are not valid on the {}".format(chart)) + raise ValueError("the coordinates {}".format(coords) + " are not valid on the {}".format(chart)) for schart in chart._supercharts: self._coordinates[schart] = tuple(coords) for schart in chart._subcharts: @@ -373,8 +371,7 @@ def coordinates(self, chart=None, old_chart=None): dom = chart.domain() def_chart = dom._def_chart if self not in dom: - raise ValueError("the point does not belong to the domain " + - "of {}".format(chart)) + raise ValueError("the point does not belong to the domain " + "of {}".format(chart)) if chart not in self._coordinates: # Check whether chart corresponds to a superchart of a chart # in which the coordinates are known: @@ -390,8 +387,7 @@ def coordinates(self, chart=None, old_chart=None): else: # A chart must be found as a starting point of the computation # The domain's default chart is privileged: - if (def_chart in self._coordinates - and (def_chart, chart) in dom._coord_changes): + if def_chart in self._coordinates and (def_chart, chart) in dom._coord_changes: old_chart = def_chart s_old_chart = def_chart s_chart = chart @@ -421,9 +417,7 @@ def coordinates(self, chart=None, old_chart=None): if old_chart is not None: break if old_chart is None: - raise ValueError("the coordinates of {}".format(self) + - " in the {}".format(chart) + " cannot be computed " + - "by means of known changes of charts.") + raise ValueError("the coordinates of {}".format(self) + " in the {}".format(chart) + " cannot be computed " + "by means of known changes of charts.") else: chcoord = dom._coord_changes[(s_old_chart, s_chart)] self._coordinates[chart] = chcoord(*self._coordinates[old_chart]) @@ -549,14 +543,12 @@ def add_coordinates(self, coords, chart=None): {Chart (M, (u, v)): (-1, 5)} """ if len(coords) != self.parent().manifold()._dim: - raise ValueError("the number of coordinates must be equal to " + - "the manifold's dimension.") + raise ValueError("the number of coordinates must be equal to " + "the manifold's dimension.") if chart is None: chart = self.parent()._def_chart else: if chart not in self.parent()._atlas: - raise ValueError("the {}".format(chart) + " has not been " + - "defined on the {}".format(self.parent())) + raise ValueError("the {}".format(chart) + " has not been " + "defined on the {}".format(self.parent())) self._coordinates[chart] = coords add_coord = add_coordinates @@ -685,12 +677,11 @@ def __eq__(self, other): # raise ValueError("no common chart has been found to compare " + # "{} and {}".format(self, other)) periods = common_chart.periods() - for ind, (xs, xo) in enumerate(zip(self._coordinates[common_chart], - other._coordinates[common_chart])): + for ind, (xs, xo) in enumerate(zip(self._coordinates[common_chart], other._coordinates[common_chart])): diff = xs - xo period = periods[ind] if period is not None: - if diff/period not in ZZ: + if diff / period not in ZZ: return False else: if isinstance(diff, Expression) and not diff.is_trivial_zero(): @@ -743,8 +734,7 @@ def __hash__(self): return hash(self.parent().manifold()) @options(size=10, color='black', label_color=None, fontsize=10, label_offset=0.1) - def plot(self, chart=None, ambient_coords=None, mapping=None, - label=None, parameters=None, **kwds): + def plot(self, chart=None, ambient_coords=None, mapping=None, label=None, parameters=None, **kwds): r""" For real manifolds, plot ``self`` in a Cartesian graph based on the coordinates of some ambient chart. @@ -940,9 +930,9 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, from sage.plot.plot3d.shapes2 import point3d, text3d from sage.plot.point import point2d from sage.plot.text import text + if self._manifold.base_field_type() != 'real': - raise NotImplementedError('plot of points on manifolds over fields different' - ' from the real field is not implemented') + raise NotImplementedError('plot of points on manifolds over fields different' ' from the real field is not implemented') # The ambient chart: if chart is None: chart = self.parent().default_chart() @@ -983,11 +973,9 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, if nca == 2: if label is None: label = r'$' + self._latex_name + r'$' - resu += (point2d(xp, color=color, size=size) + - text(label, xlab, fontsize=fontsize, color=label_color)) + resu += point2d(xp, color=color, size=size) + text(label, xlab, fontsize=fontsize, color=label_color) else: if label is None: label = self._name - resu += (point3d(xp, color=color, size=size) + - text3d(label, xlab, fontsize=fontsize, color=label_color)) + resu += point3d(xp, color=color, size=size) + text3d(label, xlab, fontsize=fontsize, color=label_color) return resu diff --git a/src/sage/manifolds/scalarfield.py b/src/sage/manifolds/scalarfield.py index 18445f3f06f..e95dc179f41 100644 --- a/src/sage/manifolds/scalarfield.py +++ b/src/sage/manifolds/scalarfield.py @@ -1112,8 +1112,7 @@ class ScalarField(CommutativeAlgebraElement, ModuleElementWithMutability): _name: Optional[str] - def __init__(self, parent, coord_expression=None, chart=None, name=None, - latex_name=None): + def __init__(self, parent, coord_expression=None, chart=None, name=None, latex_name=None): r""" Construct a scalar field. @@ -1167,7 +1166,7 @@ def __init__(self, parent, coord_expression=None, chart=None, name=None, self._express[ch] = ch.function(coord_expression) else: self._express[chart] = chart.function(coord_expression) - self._init_derived() # initialization of derived quantities + self._init_derived() # initialization of derived quantities # ### Required methods for an algebra element (beside arithmetic) ### @@ -1341,8 +1340,7 @@ def is_unit(self): """ if self._is_zero: return False - return not any(func.is_trivial_zero() - for func in self._express.values()) + return not any(func.is_trivial_zero() for func in self._express.values()) def __eq__(self, other): r""" @@ -1542,8 +1540,7 @@ def set_name(self, name=None, latex_name=None): \Phi """ if self.is_immutable(): - raise ValueError("the name of an immutable element " - "cannot be changed") + raise ValueError("the name of an immutable element " "cannot be changed") if name is not None: self._name = name if latex_name is None: @@ -1670,11 +1667,9 @@ def copy_from(self, other): False """ if self.is_immutable(): - raise ValueError("the expressions of an immutable element " - "cannot be changed") + raise ValueError("the expressions of an immutable element " "cannot be changed") if other not in self.parent(): - raise TypeError("the original must be an element of " - f"{self.parent()}") + raise TypeError("the original must be an element of " f"{self.parent()}") self._del_derived() for chart, funct in other._express.items(): self._express[chart] = funct.copy() @@ -1749,8 +1744,7 @@ def coord_function(self, chart=None, from_chart=None): chart = self._domain._def_chart else: if chart not in self._domain._atlas: - raise ValueError("the {} is not a chart ".format(chart) + - "defined on the {}".format(self._domain)) + raise ValueError("the {} is not a chart ".format(chart) + "defined on the {}".format(self._domain)) if chart not in self._express: # Check whether chart corresponds to a subchart of a chart # where the expression of self is known: @@ -1773,18 +1767,15 @@ def coord_function(self, chart=None, from_chart=None): from_chart = skchart found = True if skchart not in self._express: - self._express[skchart] = skchart.function( - self._express[kchart].expr()) + self._express[skchart] = skchart.function(self._express[kchart].expr()) break if found: break if not found: - raise ValueError("no starting chart could be found to " + - "compute the expression in the {}".format(chart)) + raise ValueError("no starting chart could be found to " + "compute the expression in the {}".format(chart)) change = self._domain._coord_changes[(chart, from_chart)] # old coordinates expressed in terms of the new ones: - coords = [change._transf._functions[i].expr() - for i in range(self._manifold.dim())] + coords = [change._transf._functions[i].expr() for i in range(self._manifold.dim())] new_expr = self._express[from_chart](*coords) self._express[chart] = chart.function(new_expr) self._del_derived() @@ -1900,8 +1891,7 @@ def set_expr(self, coord_expression, chart=None): changed """ if self.is_immutable(): - raise ValueError("the expressions of an immutable element " - "cannot be changed") + raise ValueError("the expressions of an immutable element " "cannot be changed") if chart is None: chart = self._domain._def_chart self._express.clear() @@ -1963,8 +1953,7 @@ def add_expr(self, coord_expression, chart=None): changed """ if self.is_immutable(): - raise ValueError("the expressions of an immutable element " - "cannot be changed") + raise ValueError("the expressions of an immutable element " "cannot be changed") if chart is None: chart = self._domain._def_chart self._express[chart] = chart.function(coord_expression) @@ -2032,11 +2021,9 @@ def add_expr_by_continuation(self, chart, subdomain): on V: (u, v) ↦ arctan(1/(u^2 + v^2)) """ if self.is_immutable(): - raise ValueError("the expressions of an immutable element " - "cannot be changed") + raise ValueError("the expressions of an immutable element " "cannot be changed") if not chart.domain().is_subset(self._domain): - raise ValueError("the chart is not defined on a subset of " + - "the scalar field domain") + raise ValueError("the chart is not defined on a subset of " + "the scalar field domain") schart = chart.restrict(subdomain) self._express[chart] = chart.function(self.expr(schart)) self._is_zero = False # a priori @@ -2069,15 +2056,12 @@ def set_restriction(self, rst): True """ if self.is_immutable(): - raise ValueError("the expressions of an immutable element " - "cannot be changed") + raise ValueError("the expressions of an immutable element " "cannot be changed") if not isinstance(rst, ScalarField): raise TypeError("the argument must be a scalar field") if not rst._domain.is_subset(self._domain): - raise ValueError("the domain of the declared restriction is not " + - "a subset of the field's domain") - self._restrictions[rst._domain] = rst.copy(name=self._name, - latex_name=self._latex_name) + raise ValueError("the domain of the declared restriction is not " + "a subset of the field's domain") + self._restrictions[rst._domain] = rst.copy(name=self._name, latex_name=self._latex_name) for chart, expr in rst._express.items(): intersection = chart.domain().intersection(rst._domain) self._express[chart.restrict(intersection)] = expr @@ -2166,12 +2150,9 @@ def _display_expression(self, chart, result): result._latex += " & " else: result._txt += "on " + chart.domain()._name + ": " - result._latex += r"\text{on}\ " + latex(chart.domain()) \ - + r": & " - result._txt += repr(coords) + " " + unicode_mapsto + " " \ - + repr(expression) + "\n" - result._latex += latex(coords) + r"& \longmapsto & " \ - + latex(expression) + r"\\" + result._latex += r"\text{on}\ " + latex(chart.domain()) + r": & " + result._txt += repr(coords) + " " + unicode_mapsto + " " + repr(expression) + "\n" + result._latex += latex(coords) + r"& \longmapsto & " + latex(expression) + r"\\" # Name of the base field: field = self._domain.base_field() @@ -2191,15 +2172,12 @@ def _display_expression(self, chart, result): symbol = "" else: symbol = self._name + ": " - result._txt = symbol + self._domain._name + " " + unicode_to + " " \ - + field_name + "\n" + result._txt = symbol + self._domain._name + " " + unicode_to + " " + field_name + "\n" if self._latex_name is None: symbol = "" else: symbol = self._latex_name + ":" - result._latex = r"\begin{array}{llcl} " + symbol + r"&" + \ - latex(self._domain) + r"& \longrightarrow & " + \ - field_latex_name + r" \\" + result._latex = r"\begin{array}{llcl} " + symbol + r"&" + latex(self._domain) + r"& \longrightarrow & " + field_latex_name + r" \\" if chart is None: for ch in self._domain._top_charts: ### @@ -2284,8 +2262,7 @@ def restrict(self, subdomain): return self if subdomain not in self._restrictions: if not subdomain.is_subset(self._domain): - raise ValueError("the specified domain is not a subset of " + - "the domain of definition of the scalar field") + raise ValueError("the specified domain is not a subset of " + "the domain of definition of the scalar field") # Special case of the zero scalar field: if self._is_zero: return subdomain._zero_scalar_field @@ -2301,9 +2278,7 @@ def restrict(self, subdomain): for schart in subdomain.atlas(): if schart in chart._subcharts: sexpress[schart] = funct.expr() - resu = type(self)(subdomain.scalar_field_algebra(), - coord_expression=sexpress, name=self._name, - latex_name=self._latex_name) + resu = type(self)(subdomain.scalar_field_algebra(), coord_expression=sexpress, name=self._name, latex_name=self._latex_name) if self.is_immutable(): resu.set_immutable() # restriction must be immutable, too self._restrictions[subdomain] = resu @@ -2497,8 +2472,7 @@ def __call__(self, p, chart=None): # ! # it should be "if p not in self_domain:" instead, but this test is # skipped for efficiency if p not in self._manifold: - raise ValueError("the {} ".format(p) + "does not belong " + - "to the {}".format(self._manifold)) + raise ValueError("the {} ".format(p) + "does not belong " + "to the {}".format(self._manifold)) if self._is_zero: return 0 if chart is None: @@ -2531,8 +2505,7 @@ def __call__(self, p, chart=None): except (TypeError, ValueError): pass if chart is None: - raise ValueError("no common chart has been found to evaluate " + - "the action of {} on the {}".format(self, p)) + raise ValueError("no common chart has been found to evaluate " + "the action of {} on the {}".format(self, p)) return self._express[chart](*(p._coordinates[chart])) def preimage(self, codomain_subset, name=None, latex_name=None): @@ -2572,8 +2545,8 @@ def preimage(self, codomain_subset, name=None, latex_name=None): if self.is_trivial_zero() and 0 in codomain_subset: return self.domain() from sage.manifolds.subsets.pullback import ManifoldSubsetPullback - return ManifoldSubsetPullback(self, codomain_subset, - name=name, latex_name=latex_name) + + return ManifoldSubsetPullback(self, codomain_subset, name=name, latex_name=latex_name) pullback = preimage @@ -2595,7 +2568,7 @@ def __pos__(self): """ result = type(self)(self.parent()) for chart in self._express: - result._express[chart] = + self._express[chart] + result._express[chart] = +self._express[chart] if self._name is not None: result._name = '+' + self._name if self._latex_name is not None: @@ -2623,7 +2596,7 @@ def __neg__(self): """ result = type(self)(self.parent()) for chart in self._express: - result._express[chart] = - self._express[chart] + result._express[chart] = -self._express[chart] if self._name is not None: result._name = '-' + self._name if self._latex_name is not None: @@ -2773,6 +2746,7 @@ def _mul_(self, other): format_mul_latex, format_mul_txt, ) + com_charts = self.common_charts(other) if com_charts is None: raise ValueError("no common chart for the multiplication") @@ -2781,8 +2755,7 @@ def _mul_(self, other): # ChartFunction multiplication: result._express[chart] = self._express[chart] * other._express[chart] result._name = format_mul_txt(self._name, '*', other._name) - result._latex_name = format_mul_latex(self._latex_name, r' \cdot ', - other._latex_name) + result._latex_name = format_mul_latex(self._latex_name, r' \cdot ', other._latex_name) return result def _div_(self, other): @@ -2820,6 +2793,7 @@ def _div_(self, other): format_mul_latex, format_mul_txt, ) + # Trivial cases: if other.is_trivial_zero(): raise ZeroDivisionError("division of a scalar field by zero") @@ -2834,8 +2808,7 @@ def _div_(self, other): # ChartFunction division: result._express[chart] = self._express[chart] / other._express[chart] result._name = format_mul_txt(self._name, '/', other._name) - result._latex_name = format_mul_latex(self._latex_name, '/', - other._latex_name) + result._latex_name = format_mul_latex(self._latex_name, '/', other._latex_name) return result def _lmul_(self, number): @@ -2916,8 +2889,7 @@ def _lmul_(self, number): # or (ii) no symbolic variable in number belongs to a # different chart chart_coords = chart[:] - var_not_in_chart = [s for s in var - if s not in chart_coords] + var_not_in_chart = [s for s in var if s not in chart_coords] any_in_other_chart = False if var_not_in_chart: for other_chart in self._domain.atlas(): @@ -3086,6 +3058,7 @@ def __pow__(self, exponent): True """ from sage.misc.latex import latex + if self._name is None: name = None else: @@ -3093,8 +3066,7 @@ def __pow__(self, exponent): if self._latex_name is None: latex_name = None else: - latex_name = r"{" + self._latex_name + r"}^{" + \ - latex(exponent) + r"}" + latex_name = r"{" + self._latex_name + r"}^{" + latex(exponent) + r"}" resu = type(self)(self.parent(), name=name, latex_name=latex_name) for chart, func in self._express.items(): resu._express[chart] = func.__pow__(exponent) @@ -3127,8 +3099,7 @@ def sqrt(self): sage: sqrt(M.zero_scalar_field()) == M.zero_scalar_field() True """ - name, latex_name = self._function_name("sqrt", r"\sqrt", - parentheses=False) + name, latex_name = self._function_name("sqrt", r"\sqrt", parentheses=False) resu = type(self)(self.parent(), name=name, latex_name=latex_name) for chart, func in self._express.items(): resu._express[chart] = func.sqrt() @@ -3711,6 +3682,5 @@ def __hash__(self): 1 """ if self.is_mutable(): - raise ValueError('element must be immutable in order to be ' - 'hashable') + raise ValueError('element must be immutable in order to be ' 'hashable') return hash((type(self).__name__, self._domain)) diff --git a/src/sage/manifolds/scalarfield_algebra.py b/src/sage/manifolds/scalarfield_algebra.py index 6f0f8a114ba..4926e884293 100644 --- a/src/sage/manifolds/scalarfield_algebra.py +++ b/src/sage/manifolds/scalarfield_algebra.py @@ -19,7 +19,7 @@ - [KN1963]_ """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger # Copyright (C) 2016 Travis Scrimshaw @@ -28,7 +28,7 @@ # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.commutative_algebras import CommutativeAlgebras from sage.categories.topological_spaces import TopologicalSpaces @@ -381,14 +381,12 @@ def __init__(self, domain): base_field = domain.base_field() if domain.base_field_type() in ['real', 'complex']: base_field = SR - Parent.__init__(self, base=base_field, - category=CommutativeAlgebras(base_field) & TopologicalSpaces().Homsets()) + Parent.__init__(self, base=base_field, category=CommutativeAlgebras(base_field) & TopologicalSpaces().Homsets()) self._domain = domain self._populate_coercion_lists_() #### Methods required for any Parent - def _element_constructor_(self, coord_expression=None, chart=None, - name=None, latex_name=None): + def _element_constructor_(self, coord_expression=None, chart=None, name=None, latex_name=None): r""" Construct a scalar field. @@ -467,14 +465,9 @@ def _element_constructor_(self, coord_expression=None, chart=None, # Anything going wrong here should produce a readable error: try: # generic constructor: - resu = self.element_class(self, - coord_expression=coord_expression, - name=name, latex_name=latex_name, - chart=chart) + resu = self.element_class(self, coord_expression=coord_expression, name=name, latex_name=latex_name, chart=chart) except TypeError: - raise TypeError("cannot convert " + - "{} to a scalar ".format(coord_expression) + - "field on {}".format(self._domain)) + raise TypeError("cannot convert " + "{} to a scalar ".format(coord_expression) + "field on {}".format(self._domain)) return resu def _an_element_(self): @@ -519,11 +512,12 @@ def _coerce_map_from_(self, other): True """ from sage.manifolds.chart_func import ChartFunctionRing + if isinstance(other, SymbolicRing): return True # coercion from the base ring (multiplication by the - # algebra unit, i.e. self.one()) - # cf. ScalarField._lmul_() for the implementation of - # the coercion map + # algebra unit, i.e. self.one()) + # cf. ScalarField._lmul_() for the implementation of + # the coercion map if isinstance(other, ScalarFieldAlgebra): return self._domain.is_subset(other._domain) if isinstance(other, ChartFunctionRing): @@ -586,11 +580,8 @@ def zero(self): sage: CM.zero() is z True """ - coord_express = {chart: chart.zero_function() - for chart in self._domain.atlas()} - zero = self.element_class(self, - coord_expression=coord_express, - name='zero', latex_name='0') + coord_express = {chart: chart.zero_function() for chart in self._domain.atlas()} + zero = self.element_class(self, coord_expression=coord_express, name='zero', latex_name='0') zero._is_zero = True zero.set_immutable() return zero @@ -619,9 +610,7 @@ def one(self): sage: CM.one() is h True """ - coord_express = {chart: chart.one_function() - for chart in self._domain.atlas()} - one = self.element_class(self, coord_expression=coord_express, - name='1', latex_name='1') + coord_express = {chart: chart.one_function() for chart in self._domain.atlas()} + one = self.element_class(self, coord_expression=coord_express, name='1', latex_name='1') one.set_immutable() return one diff --git a/src/sage/manifolds/section.py b/src/sage/manifolds/section.py index 1df88686ff4..82c9b91242b 100644 --- a/src/sage/manifolds/section.py +++ b/src/sage/manifolds/section.py @@ -10,7 +10,7 @@ - Michael Jung (2019): initial version """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2019 Michael Jung # @@ -18,7 +18,7 @@ # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.structure.element import ModuleElementWithMutability @@ -211,6 +211,7 @@ class Section(ModuleElementWithMutability): ... ValueError: the name of an immutable element cannot be changed """ + def __init__(self, section_module, name=None, latex_name=None): r""" Construct a local section. @@ -354,8 +355,8 @@ def _init_derived(self): sage: s = E.section(name='s') sage: s._init_derived() """ - self._restrictions = {} # dict. of restrictions of self on subdomains - # of self._domain, with the subdomains as keys + self._restrictions = {} # dict. of restrictions of self on subdomains + # of self._domain, with the subdomains as keys self._extensions_graph = {self._domain: self} self._restrictions_graph = {self._domain: self} @@ -410,8 +411,7 @@ def set_name(self, name=None, latex_name=None): a """ if self.is_immutable(): - raise ValueError("the name of an immutable element " - "cannot be changed") + raise ValueError("the name of an immutable element " "cannot be changed") if name is not None: self._name = name if latex_name is None: @@ -608,10 +608,8 @@ def set_restriction(self, rst): True """ if self.is_immutable(): - raise ValueError("the restrictions of an immutable element " - "cannot be changed") - self._restrictions[rst._domain] = rst.copy(name=self._name, - latex_name=self._latex_name) + raise ValueError("the restrictions of an immutable element " "cannot be changed") + self._restrictions[rst._domain] = rst.copy(name=self._name, latex_name=self._latex_name) self._is_zero = False # a priori def restrict(self, subdomain): @@ -697,8 +695,7 @@ def restrict(self, subdomain): return self if subdomain not in self._restrictions: if not subdomain.is_subset(self._domain): - raise ValueError("the provided domain is not a subset of " + - "the field's domain") + raise ValueError("the provided domain is not a subset of " + "the field's domain") # First one tries to get the restriction from a tighter domain: for dom, rst in self._restrictions.items(): @@ -733,8 +730,7 @@ def restrict(self, subdomain): # If this fails, the restriction is created from scratch: smodule = self._vbundle.section_module(domain=subdomain) - res = smodule.element_class(smodule, name=self._name, - latex_name=self._latex_name) + res = smodule.element_class(smodule, name=self._name, latex_name=self._latex_name) res._extensions_graph.update(self._extensions_graph) for dom, ext in self._extensions_graph.items(): @@ -823,7 +819,7 @@ def _set_comp_unsafe(self, basis=None): """ if basis is None: basis = self._smodule.default_frame() - if basis is None: # should be "is still None" ;-) + if basis is None: # should be "is still None" ;-) raise ValueError("a frame must be provided for the display") rst = self.restrict(basis._domain) return rst._set_comp_unsafe(basis) @@ -893,11 +889,10 @@ def set_comp(self, basis=None): the Trivialization frame (E|_V, ((phi_V^*e_1),(phi_V^*e_2))) """ if self.is_immutable(): - raise ValueError("the components of an immutable element " - "cannot be changed") + raise ValueError("the components of an immutable element " "cannot be changed") if basis is None: basis = self._smodule.default_frame() - if basis is None: # should be "is still None" ;-) + if basis is None: # should be "is still None" ;-) raise ValueError("a frame must be provided for the display") rst = self.restrict(basis._domain) self._is_zero = False # a priori @@ -965,7 +960,7 @@ def _add_comp_unsafe(self, basis=None): """ if basis is None: basis = self._smodule.default_frame() - if basis is None: # should be "is still None" ;-) + if basis is None: # should be "is still None" ;-) raise ValueError("a frame must be provided for the display") rst = self.restrict(basis._domain) return rst._add_comp_unsafe(basis) @@ -1029,11 +1024,10 @@ def add_comp(self, basis=None): s = (u + v) (phi_V^*e_1) """ if self.is_immutable(): - raise ValueError("the components of an immutable element " - "cannot be changed") + raise ValueError("the components of an immutable element " "cannot be changed") if basis is None: basis = self._smodule.default_frame() - if basis is None: # should be "is still None" ;-) + if basis is None: # should be "is still None" ;-) raise ValueError("a frame must be provided for the display") rst = self.restrict(basis._domain) self._is_zero = False # a priori @@ -1110,18 +1104,16 @@ def add_comp_by_continuation(self, frame, subdomain, chart=None): and `a` is defined on the entire manifold `S^2`. """ if self.is_immutable(): - raise ValueError("the components of an immutable element " - "cannot be changed") + raise ValueError("the components of an immutable element " "cannot be changed") dom = frame._domain if not dom.is_subset(self._domain): - raise ValueError("the local frame is not defined on a subset " + - "of the section's domain") + raise ValueError("the local frame is not defined on a subset " + "of the section's domain") if chart is None: chart = dom._def_chart sframe = frame.restrict(subdomain) schart = chart.restrict(subdomain) scomp = self.comp(sframe) - resu = self.add_comp(frame) # _del_derived is performed here + resu = self.add_comp(frame) # _del_derived is performed here for ind in resu.non_redundant_index_generator(): resu[[ind]] = dom.scalar_field({chart: scomp[[ind]].expr(schart)}) @@ -1193,15 +1185,12 @@ def add_expr_from_subdomain(self, frame, subdomain): on V: (u, v) ↦ v/(u^2 + v^2) """ if self.is_immutable(): - raise ValueError("the expressions of an immutable element " - "cannot be changed") + raise ValueError("the expressions of an immutable element " "cannot be changed") dom = frame._domain if not dom.is_subset(self._domain): - raise ValueError("the local frame is not defined on a subset " + - "of the section's domain") + raise ValueError("the local frame is not defined on a subset " + "of the section's domain") if frame not in self.restrict(frame.domain())._components: - raise ValueError("the section doesn't have an expression in " - "the frame " + frame._repr_()) + raise ValueError("the section doesn't have an expression in " "the frame " + frame._repr_()) comp = self.comp(frame) scomp = self.restrict(subdomain).comp(frame.restrict(subdomain)) for ind in comp.non_redundant_index_generator(): @@ -1271,7 +1260,7 @@ def comp(self, basis=None, from_basis=None): """ if basis is None: basis = self._smodule.default_frame() - if basis is None: # should be "is still None" ;-) + if basis is None: # should be "is still None" ;-) raise ValueError("a frame must be provided for the display") rst = self.restrict(basis._domain) @@ -1429,8 +1418,7 @@ def display_comp(self, frame=None, chart=None, only_nonzero=True): if frame is None: # should be "is still None" ;-) raise ValueError("a frame must be provided for the display") rst = self.restrict(frame.domain()) - return rst.display_comp(frame=frame, chart=chart, - only_nonzero=only_nonzero) + return rst.display_comp(frame=frame, chart=chart, only_nonzero=only_nonzero) def at(self, point): r""" @@ -1495,8 +1483,7 @@ def at(self, point): (5, -1) """ if point not in self._domain: - raise ValueError("the {} is not a point in the ".format(point) + - "domain of {}".format(self)) + raise ValueError("the {} is not a point in the ".format(point) + "domain of {}".format(self)) for dom, rst in self._restrictions.items(): if point in dom: return rst.at(point) @@ -1542,7 +1529,7 @@ def __getitem__(self, args): Scalar field on the 3-dimensional topological manifold M, Scalar field on the 3-dimensional topological manifold M] """ - if isinstance(args, str): # section with specified indices + if isinstance(args, str): # section with specified indices return TensorWithIndices(self, args).update() if isinstance(args, list): # case of [[...]] syntax if not isinstance(args[0], (int, Integer, slice)): @@ -1663,16 +1650,13 @@ def copy_from(self, other): False """ if self.is_immutable(): - raise ValueError("the components of an immutable element " - "cannot be changed") + raise ValueError("the components of an immutable element " "cannot be changed") if other not in self.parent(): - raise TypeError("the original must be an element of " - f"{self.parent()}") + raise TypeError("the original must be an element of " f"{self.parent()}") self._del_derived() - self._del_restrictions() # delete restrictions + self._del_restrictions() # delete restrictions for dom, rst in other._restrictions.items(): - self._restrictions[dom] = rst.copy(name=self._name, - latex_name=self._latex_name) + self._restrictions[dom] = rst.copy(name=self._name, latex_name=self._latex_name) self._is_zero = other._is_zero def copy(self, name=None, latex_name=None): @@ -1739,8 +1723,7 @@ def copy(self, name=None, latex_name=None): resu._latex_name = latex_name # set restrictions for dom, rst in self._restrictions.items(): - resu._restrictions[dom] = rst.copy(name=name, - latex_name=latex_name) + resu._restrictions[dom] = rst.copy(name=name, latex_name=latex_name) resu._is_zero = self._is_zero return resu @@ -1837,7 +1820,7 @@ def __eq__(self, other): """ if other is self: return True - if other in ZZ: # to compare with 0 + if other in ZZ: # to compare with 0 if other == 0: return self.is_zero() return False @@ -1851,8 +1834,7 @@ def __eq__(self, other): resu = True for dom in oc: try: - resu = resu and \ - bool(self.restrict(dom) == other.restrict(dom)) + resu = resu and bool(self.restrict(dom) == other.restrict(dom)) except ValueError: break else: @@ -1872,7 +1854,7 @@ def __eq__(self, other): resu = resu and bool(rst == other._restrictions[dom]) else: return False # the restrictions are not on the same - # subdomains + # subdomains return resu def __ne__(self, other): @@ -1949,7 +1931,7 @@ def __pos__(self): """ resu = self._new_instance() for dom, rst in self._restrictions.items(): - resu._restrictions[dom] = + rst + resu._restrictions[dom] = +rst if self._name is not None: resu._name = '+' + self._name if self._latex_name is not None: @@ -1997,7 +1979,7 @@ def __neg__(self): """ resu = self._new_instance() for dom, rst in self._restrictions.items(): - resu._restrictions[dom] = - rst + resu._restrictions[dom] = -rst if self._name is not None: resu._name = '-' + self._name if self._latex_name is not None: @@ -2216,12 +2198,12 @@ def _rmul_(self, scalar): format_mul_latex, format_mul_txt, ) + resu = self._new_instance() for dom, rst in self._restrictions.items(): resu._restrictions[dom] = scalar.restrict(dom) * rst resu_name = format_mul_txt(scalar._name, '*', self._name) - resu_latex = format_mul_latex(scalar._latex_name, r' \cdot ', - self._latex_name) + resu_latex = format_mul_latex(scalar._latex_name, r' \cdot ', self._latex_name) resu.set_name(name=resu_name, latex_name=resu_latex) return resu @@ -2250,7 +2232,8 @@ def set_immutable(self): rst.set_immutable() super().set_immutable() -#****************************************************************************** + +# ****************************************************************************** class TrivialSection(FiniteRankFreeModuleElement, Section): @@ -2332,6 +2315,7 @@ class TrivialSection(FiniteRankFreeModuleElement, Section): sage: isinstance(s.parent(), FiniteRankFreeModule) True """ + def __init__(self, section_module, name=None, latex_name=None): r""" Construct a section on a trivial vector bundle. @@ -2357,8 +2341,7 @@ def __init__(self, section_module, name=None, latex_name=None): manifold M with values in the real vector bundle E of rank 2 sage: TestSuite(s).run() """ - FiniteRankFreeModuleElement.__init__(self, section_module, - name=name, latex_name=latex_name) + FiniteRankFreeModuleElement.__init__(self, section_module, name=name, latex_name=latex_name) self._domain = section_module.domain() self._vbundle = section_module.vector_bundle() self._base_space = section_module.base_space() @@ -2402,7 +2385,7 @@ def _del_derived(self, del_restrictions=True): FiniteRankFreeModuleElement._del_derived(self) Section._del_derived(self, del_restrictions=del_restrictions) - def _repr_(self) : + def _repr_(self): r""" String representation of ``self``. @@ -2516,8 +2499,7 @@ class :class:`~sage.tensor.modules.comp.Components`; if such if basis._domain == self._domain: # Setting components on the section domain: - return FiniteRankFreeModuleElement._set_comp_unsafe(self, - basis=basis) + return FiniteRankFreeModuleElement._set_comp_unsafe(self, basis=basis) # Setting components on a subdomain: # # Creating or saving the restriction to the subdomain: @@ -2599,8 +2581,7 @@ class :class:`~sage.tensor.modules.comp.Components`; if such in the Local frame (E|_M, (f_0,f_1)) """ if self.is_immutable(): - raise ValueError("the components of an immutable element " - "cannot be changed") + raise ValueError("the components of an immutable element " "cannot be changed") if basis is None: basis = self._smodule.default_frame() @@ -2694,8 +2675,7 @@ class :class:`~sage.tensor.modules.comp.Components`; if such # they are deleted by FreeModuleTensor.add_comp (which # invokes del_derived()), and restore them afterwards restrictions_save = self._restrictions.copy() - comp = FiniteRankFreeModuleElement._add_comp_unsafe(self, - basis=basis) + comp = FiniteRankFreeModuleElement._add_comp_unsafe(self, basis=basis) self._restrictions = restrictions_save return comp @@ -2771,8 +2751,7 @@ class :class:`~sage.tensor.modules.comp.Components`; if such s = x f_0 """ if self.is_immutable(): - raise ValueError("the components of an immutable element " - "cannot be changed") + raise ValueError("the components of an immutable element " "cannot be changed") if basis is None: basis = self._smodule.default_frame() @@ -2840,8 +2819,7 @@ class :class:`~sage.tensor.modules.comp.Components` if basis._domain == self._domain: # components on the local section domain: - return FiniteRankFreeModuleElement.comp(self, basis=basis, - from_basis=from_basis) + return FiniteRankFreeModuleElement.comp(self, basis=basis, from_basis=from_basis) # components on a subdomain: rst = self.restrict(basis._domain) @@ -2906,8 +2884,7 @@ def restrict(self, subdomain): return self if subdomain not in self._restrictions: if not subdomain.is_subset(self._domain): - raise ValueError("the provided domain is not a subset of " + - "the field's domain") + raise ValueError("the provided domain is not a subset of " + "the field's domain") # First one tries to derive the restriction from a tighter domain: for dom, rst in self._restrictions.items(): if subdomain.is_subset(dom) and subdomain in rst._restrictions: @@ -2941,13 +2918,11 @@ def restrict(self, subdomain): # If this fails, the restriction is created from scratch: smodule = self._vbundle.section_module(domain=subdomain) - res = smodule.element_class(smodule, name=self._name, - latex_name=self._latex_name) + res = smodule.element_class(smodule, name=self._name, latex_name=self._latex_name) for frame in self._components: for sframe in self._vbundle._frames: - if (sframe.domain() is subdomain and - sframe in frame._subframes): + if sframe.domain() is subdomain and sframe in frame._subframes: comp_store = self._components[frame]._comp scomp = res._new_comp(sframe) scomp_store = scomp._comp @@ -3049,9 +3024,7 @@ def display_comp(self, frame=None, chart=None, only_nonzero=False): frame = self._smodule.default_basis() if chart is None: chart = self._domain.default_chart() - return FiniteRankFreeModuleElement.display_comp(self, basis=frame, - format_spec=chart, - only_nonzero=only_nonzero) + return FiniteRankFreeModuleElement.display_comp(self, basis=frame, format_spec=chart, only_nonzero=only_nonzero) def at(self, point): r""" @@ -3097,11 +3070,9 @@ def at(self, point): s = 3 e_0 + 4 e_1 """ if point not in self._domain: - raise ValueError("the {} is not in the domain of ".format(point) + - "the {}".format(self)) + raise ValueError("the {} is not in the domain of ".format(point) + "the {}".format(self)) vbf = self._vbundle.fiber(point) - resu = vbf.tensor((1,0), name=self._name, - latex_name=self._latex_name) + resu = vbf.tensor((1, 0), name=self._name, latex_name=self._latex_name) for frame, comp in self._components.items(): comp_resu = resu.add_comp(frame.at(point)) for ind, val in comp._comp.items(): diff --git a/src/sage/manifolds/section_module.py b/src/sage/manifolds/section_module.py index 33e673eed3b..4519f990c92 100644 --- a/src/sage/manifolds/section_module.py +++ b/src/sage/manifolds/section_module.py @@ -16,7 +16,7 @@ - Michael Jung (2019): initial version """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2019 Michael Jung # @@ -24,7 +24,7 @@ # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.categories.modules import Modules from sage.manifolds.section import Section, TrivialSection @@ -141,6 +141,7 @@ class SectionModule(UniqueRepresentation, Parent): The conversion map is actually the restriction of sections defined on `M` to `U`. """ + Element = Section def __init__(self, vbundle, domain): @@ -175,27 +176,23 @@ def __init__(self, vbundle, domain): if not domain.is_subset(base_space): raise ValueError("domain must be a subset of base space") if vbundle._diff_degree == infinity: - repr_deg = "infinity" # to skip the "+" in repr(infinity) - latex_deg = r"\infty" # to skip the "+" in latex(infinity) + repr_deg = "infinity" # to skip the "+" in repr(infinity) + latex_deg = r"\infty" # to skip the "+" in latex(infinity) else: repr_deg = r"{}".format(vbundle._diff_degree) latex_deg = r"{}".format(vbundle._diff_degree) self._name = "C^{}({};{})".format(repr_deg, domain._name, vbundle._name) - self._latex_name = r"C^{" + latex_deg + r"}" + \ - r"({};{})".format(domain._latex_name, - vbundle._latex_name) + self._latex_name = r"C^{" + latex_deg + r"}" + r"({};{})".format(domain._latex_name, vbundle._latex_name) self._vbundle = vbundle self._domain = domain self._base_space = vbundle.base_space() self._ring = domain.scalar_field_algebra() self._def_frame = None - Parent.__init__(self, base=self._ring, - category=Modules(self._ring)) + Parent.__init__(self, base=self._ring, category=Modules(self._ring)) #### Begin of parent methods - def _element_constructor_(self, comp=[], frame=None, name=None, - latex_name=None): + def _element_constructor_(self, comp=[], frame=None, name=None, latex_name=None): r""" Construct an element of the module. @@ -226,11 +223,9 @@ def _element_constructor_(self, comp=[], frame=None, name=None, if isinstance(comp, Section): if self._domain.is_subset(comp._domain): return comp.restrict(self._domain) - raise ValueError("cannot convert the {} ".format(comp) + - "to a local section in {}".format(self)) + raise ValueError("cannot convert the {} ".format(comp) + "to a local section in {}".format(self)) if not isinstance(comp, (list, tuple)): - raise TypeError("cannot convert the {} ".format(comp) + - "to an element of {}".format(self)) + raise TypeError("cannot convert the {} ".format(comp) + "to an element of {}".format(self)) # standard construction resu = self.element_class(self, name=name, latex_name=latex_name) if comp: @@ -303,12 +298,8 @@ def _repr_(self): Module C^0(M;E) of sections on the 2-dimensional topological manifold M with values in the real vector bundle E of rank 2 """ - desc = "Module {} of sections on the {} with values in the {} vector " \ - "bundle {} of rank {}" - desc = desc.format(self._name, self._domain, - self._vbundle.base_field_type(), - self._vbundle._name, - self._vbundle.rank()) + desc = "Module {} of sections on the {} with values in the {} vector " "bundle {} of rank {}" + desc = desc.format(self._name, self._domain, self._vbundle.base_field_type(), self._vbundle._name, self._vbundle.rank()) return desc def _latex_(self): @@ -466,14 +457,15 @@ def set_default_frame(self, basis): Open subset U of the 3-dimensional topological manifold M """ from sage.manifolds.local_frame import LocalFrame + if not isinstance(basis, LocalFrame): raise ValueError("the argument is not a local frame") elif not basis._domain.is_subset(self._domain): - raise ValueError("local frame's domain must be a subset " - "of the {}".format(self._domain)) + raise ValueError("local frame's domain must be a subset " "of the {}".format(self._domain)) self._def_frame = basis -#****************************************************************************** + +# ****************************************************************************** class SectionFreeModule(FiniteRankFreeModule): @@ -565,6 +557,7 @@ class SectionFreeModule(FiniteRankFreeModule): sage: TestSuite(C0).run() """ + Element = TrivialSection def __init__(self, vbundle, domain): @@ -586,25 +579,19 @@ def __init__(self, vbundle, domain): sage: TestSuite(C0).run() """ from sage.manifolds.scalarfield import ScalarField + self._domain = domain name = "C^0({};{})".format(domain._name, vbundle._name) - latex_name = r'C^0({};{})'.format(domain._latex_name, - vbundle._latex_name) + latex_name = r'C^0({};{})'.format(domain._latex_name, vbundle._latex_name) base_space = vbundle.base_space() self._base_space = base_space self._vbundle = vbundle cat = Modules(domain.scalar_field_algebra()).FiniteDimensional() - FiniteRankFreeModule.__init__(self, domain.scalar_field_algebra(), - vbundle.rank(), name=name, - latex_name=latex_name, - start_index=base_space._sindex, - output_formatter=ScalarField.coord_function, - category=cat) + FiniteRankFreeModule.__init__(self, domain.scalar_field_algebra(), vbundle.rank(), name=name, latex_name=latex_name, start_index=base_space._sindex, output_formatter=ScalarField.coord_function, category=cat) #### Parent methods - def _element_constructor_(self, comp=[], basis=None, name=None, - latex_name=None): + def _element_constructor_(self, comp=[], basis=None, name=None, latex_name=None): r""" Construct an element of ``self``. @@ -634,11 +621,9 @@ def _element_constructor_(self, comp=[], basis=None, name=None, if isinstance(comp, Section): if self._domain.is_subset(comp._domain): return comp.restrict(self._domain) - raise ValueError("cannot convert the {}".format(comp) + - "to a local section in {}".format(self)) + raise ValueError("cannot convert the {}".format(comp) + "to a local section in {}".format(self)) if not isinstance(comp, (list, tuple)): - raise TypeError("cannot convert the {} ".format(comp) + - "to an element of {}".format(self)) + raise TypeError("cannot convert the {} ".format(comp) + "to an element of {}".format(self)) # standard construction resu = self.element_class(self, name=name, latex_name=latex_name) if comp: @@ -688,12 +673,8 @@ def _repr_(self): Free module C^0(M;E) of sections on the 2-dimensional topological manifold M with values in the real vector bundle E of rank 2 """ - desc = "Free module {} of sections on the {} with values in the {} " \ - "vector bundle {} of rank {}" - desc = desc.format(self._name, self._domain, - self._vbundle.base_field_type(), - self._vbundle._name, - self._vbundle.rank()) + desc = "Free module {} of sections on the {} with values in the {} " "vector bundle {} of rank {}" + desc = desc.format(self._name, self._domain, self._vbundle.base_field_type(), self._vbundle._name, self._vbundle.rank()) return desc def domain(self): @@ -752,9 +733,7 @@ def vector_bundle(self): """ return self._vbundle - def basis(self, symbol=None, latex_symbol=None, from_frame=None, - indices=None, latex_indices=None, symbol_dual=None, - latex_symbol_dual=None): + def basis(self, symbol=None, latex_symbol=None, from_frame=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): r""" Define a basis of ``self``. @@ -806,6 +785,7 @@ def basis(self, symbol=None, latex_symbol=None, from_frame=None, and documentation. """ from sage.manifolds.local_frame import LocalFrame + if symbol is None: symbol = from_frame._symbol latex_symbol = from_frame._latex_symbol @@ -816,11 +796,7 @@ def basis(self, symbol=None, latex_symbol=None, from_frame=None, for other in self._known_bases: if symbol == other._symbol: return other - return LocalFrame(self, symbol, latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) + return LocalFrame(self, symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) set_default_frame = FiniteRankFreeModule.set_default_basis default_frame = FiniteRankFreeModule.default_basis diff --git a/src/sage/manifolds/structure.py b/src/sage/manifolds/structure.py index 6d0797c062d..d0ff2b1b960 100644 --- a/src/sage/manifolds/structure.py +++ b/src/sage/manifolds/structure.py @@ -12,7 +12,7 @@ :class:`RiemannianStructure` and :class:`LorentzianStructure` """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2015, 2018 Eric Gourgoulhon # Copyright (C) 2015 Travis Scrimshaw # @@ -21,7 +21,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.manifolds.chart import Chart, RealChart from sage.manifolds.differentiable.chart import DiffChart, RealDiffChart @@ -39,6 +39,7 @@ class TopologicalStructure(Singleton): """ The structure of a topological manifold over a general topological field. """ + chart = Chart name = "topological" scalar_field_algebra = ScalarFieldAlgebra @@ -63,6 +64,7 @@ class RealTopologicalStructure(Singleton): r""" The structure of a topological manifold over `\RR`. """ + chart = RealChart name = "topological" scalar_field_algebra = ScalarFieldAlgebra @@ -88,6 +90,7 @@ class DifferentialStructure(Singleton): The structure of a differentiable manifold over a general topological field. """ + chart = DiffChart name = "differentiable" scalar_field_algebra = DiffScalarFieldAlgebra @@ -112,6 +115,7 @@ class RealDifferentialStructure(Singleton): r""" The structure of a differentiable manifold over `\RR`. """ + chart = RealDiffChart name = "differentiable" scalar_field_algebra = DiffScalarFieldAlgebra @@ -136,6 +140,7 @@ class PseudoRiemannianStructure(Singleton): """ The structure of a pseudo-Riemannian manifold. """ + chart = RealDiffChart name = "pseudo-Riemannian" scalar_field_algebra = DiffScalarFieldAlgebra @@ -160,6 +165,7 @@ class RiemannianStructure(Singleton): """ The structure of a Riemannian manifold. """ + chart = RealDiffChart name = "Riemannian" scalar_field_algebra = DiffScalarFieldAlgebra @@ -184,6 +190,7 @@ class LorentzianStructure(Singleton): """ The structure of a Lorentzian manifold. """ + chart = RealDiffChart name = "Lorentzian" scalar_field_algebra = DiffScalarFieldAlgebra @@ -208,6 +215,7 @@ class DegenerateStructure(Singleton): """ The structure of a degenerate manifold. """ + chart = RealDiffChart name = "degenerate_metric" scalar_field_algebra = DiffScalarFieldAlgebra diff --git a/src/sage/manifolds/subset.py b/src/sage/manifolds/subset.py index 5623eefd14e..584b538af59 100644 --- a/src/sage/manifolds/subset.py +++ b/src/sage/manifolds/subset.py @@ -54,6 +54,7 @@ Set {A, A_inter_B, A_union_B, B} of subsets of the 2-dimensional topological manifold M """ + # *************************************************************************** # Copyright (C) 2015-2020 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger @@ -191,9 +192,7 @@ def __init__(self, manifold, name: str, latex_name=None, category=None): if self is not manifold: for dom in manifold._subsets: if name == dom._name: - raise ValueError("the name '" + name + - "' is already used for another " + - "subset of the {}".format(manifold)) + raise ValueError("the name '" + name + "' is already used for another " + "subset of the {}".format(manifold)) manifold._subsets.add(self) # subsets containing self @@ -212,7 +211,7 @@ def __init__(self, manifold, name: str, latex_name=None, category=None): self._unions = {} self._open_covers = [] # list of open covers of self - self._is_open = False # a priori (may be redefined by subclasses) + self._is_open = False # a priori (may be redefined by subclasses) self._manifold = manifold # the ambient manifold self._has_defined_points = False @@ -263,8 +262,7 @@ def _latex_(self) -> str: # ### Methods required for any Parent in the category of sets: - def _element_constructor_(self, coords=None, chart=None, name=None, - latex_name=None, check_coords=True): + def _element_constructor_(self, coords=None, chart=None, name=None, latex_name=None, check_coords=True): r""" Construct a point in the subset from its coordinates in some chart. @@ -345,16 +343,12 @@ def _element_constructor_(self, coords=None, chart=None, name=None, if point.parent() is self: return point if point in self: - resu = self.element_class(self, name=point._name, - latex_name=point._latex_name) + resu = self.element_class(self, name=point._name, latex_name=point._latex_name) for chart, coords in point._coordinates.items(): resu._coordinates[chart] = coords return resu - raise ValueError("the {}".format(point) + - " is not in {}".format(self)) - return self.element_class(self, coords=coords, chart=chart, - name=name, latex_name=latex_name, - check_coords=check_coords) + raise ValueError("the {}".format(point) + " is not in {}".format(self)) + return self.element_class(self, coords=coords, chart=chart, name=name, latex_name=latex_name, check_coords=check_coords) def _an_element_(self): r""" @@ -693,8 +687,7 @@ def open_cover_family(self, trivial=True, supersets=False): sage: M.open_cover_family() Set {{A, B, V}, {M}, {U, V}} of objects of the 2-dimensional topological manifold M """ - return ManifoldObjectFiniteFamily(self.open_covers( - trivial=trivial, supersets=supersets)) + return ManifoldObjectFiniteFamily(self.open_covers(trivial=trivial, supersets=supersets)) def open_supersets(self): r""" @@ -887,22 +880,28 @@ def label(element): sphinx_plot(graphics_array([g1, g2, g3]), figsize=(8, 3)) """ from sage.graphs.digraph import DiGraph + D = DiGraph(multiedges=False, loops=loops) if loops: add_edges = D.add_edges else: + def add_edges(edges): for u, v in edges: if u != v: D.add_edge((u, v)) if quotient: + def vertex_family(subset): return ManifoldSubsetFiniteFamily(subset.equal_subsets()) + else: + def vertex_family(subset): return ManifoldSubsetFiniteFamily([subset]) + subset_to_vertex = {} def vertex(subset): @@ -928,13 +927,11 @@ def vertex(subset): if lower_bound is None: subsets = S._subsets else: - subsets = [subset for subset in S._subsets - if lower_bound.is_subset(subset)] + subsets = [subset for subset in S._subsets if lower_bound.is_subset(subset)] add_edges((vertex(subset), vertex(S)) for subset in subsets) - subsets_without_S = [subset for subset in subsets - if subset is not S] + subsets_without_S = [subset for subset in subsets if subset is not S] to_visit.extend(subsets_without_S) # Make sure to include isolated vertices in the graph @@ -946,8 +943,7 @@ def open_cover_vertex(open_cover): return tuple(sorted(ManifoldSubsetFiniteFamily([subset]) for subset in open_cover)) for S in visited: - add_edges((vertex(S), open_cover_vertex(open_cover)) - for open_cover in S.open_covers(trivial=False)) + add_edges((vertex(S), open_cover_vertex(open_cover)) for open_cover in S.open_covers(trivial=False)) if points is not False: subset_to_points = defaultdict(list) @@ -967,10 +963,7 @@ def point_vertex(point): def anonymous_point_vertex(S): return f"p{S._name}" - add_edges((anonymous_point_vertex(S), vertex(S)) - for S in visited - if S.has_defined_points(subsets=False) - and S not in subset_to_points) + add_edges((anonymous_point_vertex(S), vertex(S)) for S in visited if S.has_defined_points(subsets=False) and S not in subset_to_points) return D @@ -1051,8 +1044,8 @@ def label(element): sphinx_plot(graphics_array([g1, g2, g3]), figsize=(8, 3)) """ from sage.combinat.posets.posets import Poset - return Poset(self.subset_digraph(open_covers=open_covers, points=points, - quotient=True, lower_bound=lower_bound)) + + return Poset(self.subset_digraph(open_covers=open_covers, points=points, quotient=True, lower_bound=lower_bound)) def equal_subsets(self): r""" @@ -1171,8 +1164,7 @@ def superset_digraph(self, loops=False, quotient=False, open_covers=False, point """ if upper_bound is None: upper_bound = self._manifold - return upper_bound.subset_digraph(loops=loops, open_covers=open_covers, points=points, - quotient=quotient, lower_bound=self) + return upper_bound.subset_digraph(loops=loops, open_covers=open_covers, points=points, quotient=quotient, lower_bound=self) def superset_poset(self, open_covers=False, points=False, upper_bound=None): r""" @@ -1197,8 +1189,7 @@ def superset_poset(self, open_covers=False, points=False, upper_bound=None): """ if upper_bound is None: upper_bound = self._manifold - return upper_bound.subset_poset(open_covers=open_covers, points=points, - lower_bound=self) + return upper_bound.subset_poset(open_covers=open_covers, points=points, lower_bound=self) def get_subset(self, name): r""" @@ -1384,15 +1375,12 @@ def _declare_union_2_subsets(self, dom1, dom2): """ if dom1 == dom2: if dom1 != self: - raise ValueError("the union of two identical sets must be " + - "this set") + raise ValueError("the union of two identical sets must be " + "this set") return if not dom1.is_subset(self): - raise TypeError("the {} is not a subset of ".format(dom1) + - "the {}".format(self)) + raise TypeError("the {} is not a subset of ".format(dom1) + "the {}".format(self)) if not dom2.is_subset(self): - raise TypeError("the {} is not a subset of ".format(dom2) + - "the {}".format(self)) + raise TypeError("the {} is not a subset of ".format(dom2) + "the {}".format(self)) dom1._unions[dom2._name] = self dom2._unions[dom1._name] = self for oc1 in dom1._open_covers: @@ -1716,8 +1704,7 @@ def is_empty(self): if self.has_defined_points(subsets=False): # Fast path, do not check subsets return False - return any(not cover - for cover in self.open_covers(trivial=False, supersets=True)) + return any(not cover for cover in self.open_covers(trivial=False, supersets=True)) def declare_nonempty(self): r""" @@ -1820,8 +1807,7 @@ def point(self, coords=None, chart=None, name=None, latex_name=None): sage: q._coordinates {Chart (A, (u, v)): (-1, 0)} """ - return self.element_class(self, coords=coords, chart=chart, - name=name, latex_name=latex_name) + return self.element_class(self, coords=coords, chart=chart, name=name, latex_name=latex_name) def declare_closed(self): r""" @@ -1848,6 +1834,7 @@ def declare_closed(self): return self.complement(is_open=True) from sage.manifolds.subsets.closure import ManifoldSubsetClosure + for closure in self.manifold().subsets(): if isinstance(closure, ManifoldSubsetClosure): if closure._subset.is_subset(self): @@ -1974,9 +1961,7 @@ def open_subset(self, name, latex_name=None, coord_def={}, supersets=None): supersets = set(supersets) supersets.update([self]) # Delegate to the manifold's method. - return self._manifold.open_subset(name, latex_name=latex_name, - coord_def=coord_def, - supersets=supersets) + return self._manifold.open_subset(name, latex_name=latex_name, coord_def=coord_def, supersets=supersets) def _init_open_subset(self, resu, coord_def): r""" @@ -2241,9 +2226,10 @@ def reduce(): subsets.add(UV) return True return False + while reduce(): pass - assert subsets # there must be a survivor + assert subsets # there must be a survivor return ManifoldSubsetFiniteFamily(subsets) def _intersection_subset(self, *others, name=None, latex_name=None): @@ -2463,6 +2449,7 @@ def reduce(): subsets.add(UV) return True return False + while reduce(): pass return ManifoldSubsetFiniteFamily(subsets) @@ -2574,9 +2561,7 @@ def complement(self, superset=None, name=None, latex_name=None, is_open=False): superset = self.manifold() elif not self.is_subset(superset): raise TypeError("superset must be a superset of self") - return superset.difference(self, - name=name, latex_name=latex_name, - is_open=is_open) + return superset.difference(self, name=name, latex_name=latex_name, is_open=is_open) def difference(self, other, name=None, latex_name=None, is_open=False): r""" @@ -2656,8 +2641,7 @@ def difference(self, other, name=None, latex_name=None, is_open=False): if latex_name is None: if name is None: - latex_name = r'\setminus '.join(S._latex_name - for S in (self, other)) + latex_name = r'\setminus '.join(S._latex_name for S in (self, other)) else: latex_name = name if name is None: @@ -2713,6 +2697,7 @@ def closure(self, name=None, latex_name=None): if self.is_closed(): return self from sage.manifolds.subsets.closure import ManifoldSubsetClosure + return ManifoldSubsetClosure(self, name=name, latex_name=latex_name) # ### End of construction of new sets from self diff --git a/src/sage/manifolds/subsets/closure.py b/src/sage/manifolds/subsets/closure.py index d8b6dc83323..422eccf4661 100644 --- a/src/sage/manifolds/subsets/closure.py +++ b/src/sage/manifolds/subsets/closure.py @@ -89,9 +89,7 @@ def __init__(self, subset, name=None, latex_name=None): name = 'cl_' + subset._name ManifoldSubset.__init__(self, base_manifold, name, latex_name=latex_name) self.declare_superset(subset) - self.declare_subset(superset - for superset in subset.supersets() - if superset.is_closed()) + self.declare_subset(superset for superset in subset.supersets() if superset.is_closed()) def _repr_(self): r""" diff --git a/src/sage/manifolds/subsets/pullback.py b/src/sage/manifolds/subsets/pullback.py index 539d993df6a..b0db3d7129c 100644 --- a/src/sage/manifolds/subsets/pullback.py +++ b/src/sage/manifolds/subsets/pullback.py @@ -2,7 +2,6 @@ Manifold Subsets Defined as Pullbacks of Subsets under Continuous Maps """ - # **************************************************************************** # Copyright (C) 2021 Matthias Koeppe # @@ -134,9 +133,9 @@ class ManifoldSubsetPullback(ManifoldSubset): sage: N.point((2,0)) in D False """ + @staticmethod - def __classcall_private__(cls, map, codomain_subset, inverse=None, - name=None, latex_name=None): + def __classcall_private__(cls, map, codomain_subset, inverse=None, name=None, latex_name=None): """ Normalize arguments and delegate to other constructors. @@ -174,6 +173,7 @@ def __classcall_private__(cls, map, codomain_subset, inverse=None, if inverse is None: if isinstance(map, Chart): from sage.misc.latex import latex + inverse_latex_name = '(' + ','.join(str(latex(x)) + '^{-1}' for x in map) + ')' inverse_name = '_'.join(repr(x) for x in map) + '_inv' else: @@ -189,6 +189,7 @@ def __classcall_private__(cls, map, codomain_subset, inverse=None, codomain_subset_name = codomain_subset._name except AttributeError: from sage.misc.latex import latex + codomain_subset_latex_name = str(latex(codomain_subset)) s = repr(codomain_subset) if len(s) > 10: @@ -210,8 +211,7 @@ def __classcall_private__(cls, map, codomain_subset, inverse=None, except NotImplementedError: pass else: - return map.domain().open_subset(name=name, latex_name=latex_name, - coord_def=coord_def) + return map.domain().open_subset(name=name, latex_name=latex_name, coord_def=coord_def) self = super().__classcall__(cls, map, codomain_subset, inverse, name, latex_name) @@ -315,8 +315,7 @@ def _is_open(codomain_subset): cs = codomain_subset.minimized_constraints() if cs.has_equalities(): return False - return not any(constraint.is_nonstrict_inequality() - for constraint in cs) + return not any(constraint.is_nonstrict_inequality() for constraint in cs) return False @@ -360,11 +359,11 @@ def _interval_restriction(expr, interval): conjunction = [] if interval.lower() != minus_infinity: if interval.lower_closed(): - condition = (expr >= interval.lower()) - negation = (expr < interval.lower()) + condition = expr >= interval.lower() + negation = expr < interval.lower() else: - condition = (expr > interval.lower()) - negation = (expr <= interval.lower()) + condition = expr > interval.lower() + negation = expr <= interval.lower() if negation: # known to be false return () @@ -374,11 +373,11 @@ def _interval_restriction(expr, interval): if interval.upper() != infinity: if interval.upper_closed(): - condition = (expr <= interval.upper()) - negation = (expr > interval.upper()) + condition = expr <= interval.upper() + negation = expr > interval.upper() else: - condition = (expr < interval.upper()) - negation = (expr >= interval.upper()) + condition = expr < interval.upper() + negation = expr >= interval.upper() if negation: # known to be false return () @@ -469,11 +468,11 @@ def _polyhedron_restriction(expr, polyhedron, relint=False): if constraint.is_inequality(): if relint: - condition = (constraint.eval(expr) > 0) + condition = constraint.eval(expr) > 0 else: - condition = (constraint.eval(expr) >= 0) + condition = constraint.eval(expr) >= 0 else: - condition = (constraint.eval(expr) == 0) + condition = constraint.eval(expr) == 0 if not condition: # not known to be true conjunction.append(condition) @@ -529,21 +528,17 @@ def _coord_def(map, codomain_subset): """ if isinstance(map, ScalarField) and isinstance(codomain_subset, RealSet): - return {chart: ManifoldSubsetPullback._realset_restriction(func.expr(), - codomain_subset) - for chart, func in map._express.items()} + return {chart: ManifoldSubsetPullback._realset_restriction(func.expr(), codomain_subset) for chart, func in map._express.items()} if isinstance(map, Chart): chart = map if isinstance(codomain_subset, RealSet): - return {chart: ManifoldSubsetPullback._realset_restriction(chart[0], - codomain_subset)} + return {chart: ManifoldSubsetPullback._realset_restriction(chart[0], codomain_subset)} if isinstance(codomain_subset, RelativeInterior) and isinstance(codomain_subset.closure(), sage.geometry.abc.Polyhedron): - return {chart: ManifoldSubsetPullback._polyhedron_restriction( - chart, codomain_subset.closure(), relint=True)} + return {chart: ManifoldSubsetPullback._polyhedron_restriction(chart, codomain_subset.closure(), relint=True)} raise NotImplementedError @@ -566,9 +561,7 @@ def __init__(self, map, codomain_subset, inverse, name, latex_name): """ if inverse is None and isinstance(map, Chart): chart = map - scalar_codomain = (isinstance(codomain_subset, RealSet) - or any(field.has_coerce_map_from(codomain_subset) - for field in (CDF, RDF, CLF, RLF))) + scalar_codomain = isinstance(codomain_subset, RealSet) or any(field.has_coerce_map_from(codomain_subset) for field in (CDF, RDF, CLF, RLF)) if scalar_codomain: if chart.domain().dimension() != 1: raise ValueError('to pull back a set of scalars by a chart, the manifold must be 1-dimensional') @@ -576,9 +569,12 @@ def __init__(self, map, codomain_subset, inverse, name, latex_name): def _inverse(coord): return self.point((coord,), chart=chart) + else: + def _inverse(coords): return self.point(coords, chart=map) + inverse = _inverse self._map = map @@ -872,8 +868,6 @@ def closure(self, name=None, latex_name=None): codomain_subset_closure = self._codomain_subset.closure() except AttributeError: return super().closure() - closure = ManifoldSubsetPullback(self._map, codomain_subset_closure, - inverse=self._inverse, - name=name, latex_name=latex_name) + closure = ManifoldSubsetPullback(self._map, codomain_subset_closure, inverse=self._inverse, name=name, latex_name=latex_name) closure.declare_superset(self) return closure diff --git a/src/sage/manifolds/topological_submanifold.py b/src/sage/manifolds/topological_submanifold.py index 9ea40b0f621..96dca643c23 100644 --- a/src/sage/manifolds/topological_submanifold.py +++ b/src/sage/manifolds/topological_submanifold.py @@ -32,7 +32,6 @@ - \J. M. Lee: *Introduction to Smooth Manifolds* [Lee2013]_ """ - # ***************************************************************************** # Copyright (C) 2018 Florentin Jaffredo # Copyright (C) 2018-2019 Eric Gourgoulhon @@ -175,9 +174,8 @@ class TopologicalSubmanifold(TopologicalManifold): :mod:`~sage.manifolds.manifold` """ - def __init__(self, n, name, field, structure, ambient=None, - base_manifold=None, latex_name=None, start_index=0, - category=None, unique_tag=None): + + def __init__(self, n, name, field, structure, ambient=None, base_manifold=None, latex_name=None, start_index=0, category=None, unique_tag=None): r""" Construct a submanifold of a topological manifold. @@ -189,13 +187,8 @@ def __init__(self, n, name, field, structure, ambient=None, 2-dimensional topological submanifold N immersed in the 3-dimensional topological manifold M """ - TopologicalManifold.__init__(self, n, name, field, structure, - base_manifold=base_manifold, - latex_name=latex_name, - start_index=start_index, - category=category) - if not (ambient is None - or isinstance(ambient, TopologicalManifold)): + TopologicalManifold.__init__(self, n, name, field, structure, base_manifold=base_manifold, latex_name=latex_name, start_index=start_index, category=category) + if not (ambient is None or isinstance(ambient, TopologicalManifold)): raise TypeError("ambient must be a manifold") self._init_immersion(ambient=ambient) @@ -226,8 +219,7 @@ def _init_immersion(self, ambient=None): self._ambient = ambient self._codim = ambient._dim - self._dim if self._codim < 0: - raise ValueError("the submanifold must be of smaller " - + "dimension than its ambient manifold") + raise ValueError("the submanifold must be of smaller " + "dimension than its ambient manifold") self._immersed = False self._embedded = False self._adapted_charts = None @@ -258,10 +250,8 @@ def _repr_(self): if self._ambient is self: return super(TopologicalManifold, self).__repr__() if self._embedded: - return "{}-dimensional {} submanifold {} embedded in the {}".format( - self._dim, self._structure.name, self._name, self._ambient) - return "{}-dimensional {} submanifold {} immersed in the {}".format( - self._dim, self._structure.name, self._name, self._ambient) + return "{}-dimensional {} submanifold {} embedded in the {}".format(self._dim, self._structure.name, self._name, self._ambient) + return "{}-dimensional {} submanifold {} immersed in the {}".format(self._dim, self._structure.name, self._name, self._ambient) def open_subset(self, name, latex_name=None, coord_def={}, supersets=None): r""" @@ -319,11 +309,7 @@ def open_subset(self, name, latex_name=None, coord_def={}, supersets=None): 2-dimensional topological submanifold N embedded in the 3-dimensional topological manifold M """ - resu = TopologicalSubmanifold(self._dim, name, self._field, - self._structure, self._ambient, - base_manifold=self._manifold, - latex_name=latex_name, - start_index=self._sindex) + resu = TopologicalSubmanifold(self._dim, name, self._field, self._structure, self._ambient, base_manifold=self._manifold, latex_name=latex_name, start_index=self._sindex) if supersets is None: supersets = [self] for superset in supersets: @@ -370,13 +356,11 @@ def _init_open_subset(self, resu, coord_def): super()._init_open_subset(resu, coord_def=coord_def) ## Extras for Submanifold if self._immersed: - resu.set_immersion(self._immersion.restrict(resu), - var=self._var, t_inverse=self._t_inverse) + resu.set_immersion(self._immersion.restrict(resu), var=self._var, t_inverse=self._t_inverse) if self._embedded: resu.declare_embedding() - def set_immersion(self, phi, inverse=None, var=None, - t_inverse=None): + def set_immersion(self, phi, inverse=None, var=None, t_inverse=None): r""" Register the immersion of the immersed submanifold. @@ -433,8 +417,7 @@ def set_immersion(self, phi, inverse=None, var=None, if not isinstance(phi, ContinuousMap): raise TypeError("the argument phi must be a continuous map") if phi.domain() is not self or phi.codomain() is not self._ambient: - raise ValueError("{} is not a map from {} to {}".format(phi, self, - self._ambient)) + raise ValueError("{} is not a map from {} to {}".format(phi, self, self._ambient)) self._immersion = phi if inverse is not None: @@ -449,8 +432,7 @@ def set_immersion(self, phi, inverse=None, var=None, raise TypeError() except TypeError: if not isinstance(var, Expression): - raise TypeError("var must be a variable " - "or list of variables") + raise TypeError("var must be a variable " "or list of variables") if isinstance(var, Expression): self._var = [var] @@ -499,13 +481,10 @@ def declare_embedding(self): True """ if not self._immersed: - raise ValueError("please declare an embedding using set_immersion " - "before calling declare_embedding()") + raise ValueError("please declare an embedding using set_immersion " "before calling declare_embedding()") self._embedded = True - def set_embedding( - self, phi: ContinuousMap, inverse=None, var=None, t_inverse=None - ): + def set_embedding(self, phi: ContinuousMap, inverse=None, var=None, t_inverse=None): r""" Register the embedding of an embedded submanifold. @@ -639,8 +618,7 @@ def adapted_chart(self, postscript=None, latex_postscript=None): raise ValueError("an embedding is required") if self._dim_foliation + self._dim != self._ambient._dim: - raise ValueError("a foliation of dimension dim(M) - dim(N) is " - "needed to find an adapted chart") + raise ValueError("a foliation of dimension dim(M) - dim(N) is " "needed to find an adapted chart") res = [] self._subs = [] @@ -654,12 +632,8 @@ def adapted_chart(self, postscript=None, latex_postscript=None): # All possible expressions for the immersion chart_pairs = list(self._immersion._coord_expression.keys()) - for (chart1, chart2) in chart_pairs: - name = " ".join(chart1[i]._repr_() + postscript + ":{" - + chart1[i]._latex_() + "}" + latex_postscript - for i in self.irange()) + " " \ - + " ".join(v._repr_() + postscript + ":{" + v._latex_() - + "}" + latex_postscript for v in self._var) + for chart1, chart2 in chart_pairs: + name = " ".join(chart1[i]._repr_() + postscript + ":{" + chart1[i]._latex_() + "}" + latex_postscript for i in self.irange()) + " " + " ".join(v._repr_() + postscript + ":{" + v._latex_() + "}" + latex_postscript for v in self._var) chart = chart2.domain().chart(name) if chart not in res: @@ -677,28 +651,20 @@ def adapted_chart(self, postscript=None, latex_postscript=None): self._subs.append(subs) res.append(chart) - self._immersion.add_expr(chart1, chart, - list(chart1[:]) + self._var) - self._immersion_inv.add_expr(chart, chart1, - chart[:][0:self._dim]) + self._immersion.add_expr(chart1, chart, list(chart1[:]) + self._var) + self._immersion_inv.add_expr(chart, chart1, chart[:][0 : self._dim]) for i in range(len(self._var)): - self._t_inverse[self._var[i]].add_expr( - chart[:][self._dim:][i], chart=chart) - - for (chartNV, chartMV) in self._immersion._coord_expression: - for (chartNU, chartMU) in self._immersion._coord_expression: - if chartMU is not chartMV and\ - (chartMU, chartMV) not in self._ambient._coord_changes: - if (chartNU, chartNV) in self._coord_changes or \ - chartNU is chartNV: + self._t_inverse[self._var[i]].add_expr(chart[:][self._dim :][i], chart=chart) + + for chartNV, chartMV in self._immersion._coord_expression: + for chartNU, chartMU in self._immersion._coord_expression: + if chartMU is not chartMV and (chartMU, chartMV) not in self._ambient._coord_changes: + if (chartNU, chartNV) in self._coord_changes or chartNU is chartNV: _f = self._immersion.coord_functions(chartNV, chartMV) - _g = self._coord_changes[(chartNU, chartNV)]._transf \ - if chartNU is not chartNV else lambda *x: x - _h = self._immersion_inv.coord_functions(chartMU, - chartNU) + _g = self._coord_changes[(chartNU, chartNV)]._transf if chartNU is not chartNV else lambda *x: x + _h = self._immersion_inv.coord_functions(chartMU, chartNU) expr = list(_f(*_g(*_h(*chartMU[:])))) - substitutions = {v: self._t_inverse[v].expr(chartMU) - for v in self._var} + substitutions = {v: self._t_inverse[v].expr(chartMU) for v in self._var} for i in range(len(expr)): expr[i] = expr[i].subs(substitutions) diff --git a/src/sage/manifolds/trivialization.py b/src/sage/manifolds/trivialization.py index 5898d38a089..946d61f1c9d 100644 --- a/src/sage/manifolds/trivialization.py +++ b/src/sage/manifolds/trivialization.py @@ -180,9 +180,7 @@ def _latex_(self): '\\varphi : E |_{M} \\to M \\times \\Bold{R}^1' """ latex = self._latex_name + r' : ' - latex += r'{} |_{{{}}} \to {} \times {}^{}'.format(self._vbundle._latex_name, - self._domain._latex_(), self._domain._latex_(), - self._base_field._latex_(), self._bdl_rank) + latex += r'{} |_{{{}}} \to {} \times {}^{}'.format(self._vbundle._latex_name, self._domain._latex_(), self._domain._latex_(), self._base_field._latex_(), self._bdl_rank) return latex def base_space(self): @@ -227,8 +225,7 @@ def transition_map(self, other, transf, compute_inverse=True): Transition map from Trivialization (phi_U, E|_U) to Trivialization (phi_V, E|_V) """ - return TransitionMap(self, other, transf, - compute_inverse=compute_inverse) + return TransitionMap(self, other, transf, compute_inverse=compute_inverse) def vector_bundle(self): r""" @@ -301,6 +298,7 @@ def coframe(self): """ return self._frame._coframe + # ***************************************************************************** @@ -362,6 +360,7 @@ class TransitionMap(SageObject): Transition map from Trivialization (phi_U, E|_U) to Trivialization (phi_V, E|_V) """ + def __init__(self, triv1, triv2, transf, compute_inverse=True): r""" Construct a transition map between two trivializations. @@ -408,23 +407,19 @@ def __init__(self, triv1, triv2, transf, compute_inverse=True): self._inverse = None self._vbundle._transitions[(triv1, triv2)] = self self._name = triv2._name + "*" + triv1._name + "^(-1)" - self._latex_name = triv2._latex_name + r'\circ ' + triv1._latex_name + \ - r'^{-1}' + self._latex_name = triv2._latex_name + r'\circ ' + triv1._latex_name + r'^{-1}' ### # Define the automorphism auto_name = triv1._name + "^(-1)*" + triv2._name auto_lname = triv1._latex_name + r'^{-1} \circ ' + triv2._latex_name sec_module = self._vbundle.section_module(dom, force_free=True) auto_group = sec_module.general_linear_group() - auto = auto_group(transf, basis=self._frame1, name=auto_name, - latex_name=auto_lname) + auto = auto_group(transf, basis=self._frame1, name=auto_name, latex_name=auto_lname) self._automorphism = auto # Add this change of basis to the basis changes - self._vbundle.set_change_of_frame(self._frame2, self._frame1, auto, - compute_inverse=compute_inverse) + self._vbundle.set_change_of_frame(self._frame2, self._frame1, auto, compute_inverse=compute_inverse) if compute_inverse: - self._inverse = type(self)(self._triv2, self._triv1, ~auto, - compute_inverse=False) + self._inverse = type(self)(self._triv2, self._triv1, ~auto, compute_inverse=False) self._inverse._inverse = self def _repr_(self): @@ -481,8 +476,7 @@ def _latex_(self): \varphi_V\circ \varphi_U^{-1}:U\cap V\times \Bold{R}^2 \to U\cap V\times \Bold{R}^2 """ - vspace_lname = r'\times {}^{}'.format(self._triv1._base_field._latex_(), - self._bdl_rank) + vspace_lname = r'\times {}^{}'.format(self._triv1._base_field._latex_(), self._bdl_rank) latex = self._latex_name + r':' latex += self._domain._latex_name latex += vspace_lname + r' \to ' @@ -566,11 +560,8 @@ def inverse(self): True """ if self._inverse is None: - self._vbundle.set_change_of_frame(self._frame1, self._frame2, - ~self._automorphism) - self._inverse = type(self)(self._triv2, self._triv1, - ~self._automorphism, - compute_inverse=False) + self._vbundle.set_change_of_frame(self._frame1, self._frame2, ~self._automorphism) + self._inverse = type(self)(self._triv2, self._triv1, ~self._automorphism, compute_inverse=False) self._inverse._inverse = self return self._inverse @@ -706,9 +697,7 @@ def __eq__(self, other): return True if not isinstance(other, TransitionMap): return False - return ((self._triv1 == other._triv1) - and (self._triv2 == other._triv2) - and (self._automorphism == other._automorphism)) + return (self._triv1 == other._triv1) and (self._triv2 == other._triv2) and (self._automorphism == other._automorphism) def __ne__(self, other): r""" diff --git a/src/sage/manifolds/utilities.py b/src/sage/manifolds/utilities.py index 8adfe33b991..6b9006ee134 100644 --- a/src/sage/manifolds/utilities.py +++ b/src/sage/manifolds/utilities.py @@ -121,6 +121,7 @@ class SimplifySqrtReal(ExpressionTreeWalker): :func:`simplify_sqrt_real` for more examples with :class:`SimplifySqrtReal` at work. """ + def arithmetic(self, ex, operator): r""" This is the only method of the base class @@ -164,7 +165,7 @@ def arithmetic(self, ex, operator): if operator is _pow: operands = ex.operands() power = operands[1] - one_half = Rational((1,2)) + one_half = Rational((1, 2)) minus_one_half = -one_half if (power == one_half) or (power == minus_one_half): # This is a square root or the inverse of a square root @@ -189,10 +190,7 @@ def arithmetic(self, ex, operator): else: ex = sqrt(argum) simpl = SR(ex._maxima_().radcan()) - if (not simpl.match(sqrt_pattern) and - not simpl.match(inv_sqrt_pattern) and - not simpl.match(sqrt_ratio_pattern1) and - not simpl.match(sqrt_ratio_pattern2)): + if not simpl.match(sqrt_pattern) and not simpl.match(inv_sqrt_pattern) and not simpl.match(sqrt_ratio_pattern1) and not simpl.match(sqrt_ratio_pattern2): # radcan transformed substantially the expression, # possibly getting rid of some sqrt; in order to ensure a # positive result, the absolute value of radcan's output @@ -200,7 +198,7 @@ def arithmetic(self, ex, operator): # assumptions regarding signs of subexpression of simpl: simpl = abs(simpl).simplify() if power == minus_one_half: - simpl = SR(1)/simpl + simpl = SR(1) / simpl return simpl # If operator is not a square root, we default to ExpressionTreeWalker: return super().arithmetic(ex, operator) @@ -264,6 +262,7 @@ class SimplifyAbsTrig(ExpressionTreeWalker): :func:`simplify_abs_trig` for more examples with :class:`SimplifyAbsTrig` at work. """ + def composition(self, ex, operator): r""" This is the only method of the base class @@ -322,7 +321,7 @@ def composition(self, ex, operator): # Simplifications for values of x in the range [-pi, 2*pi]: if x >= 0 and x <= pi: ex = sin(x) - elif (x > pi and x <= 2*pi) or (x >= -pi and x < 0): + elif (x > pi and x <= 2 * pi) or (x >= -pi and x < 0): ex = -sin(x) return ex if argum.operator() is cos: @@ -332,9 +331,9 @@ def composition(self, ex, operator): if x.has(abs_symbolic(sin(w0))) or x.has(abs_symbolic(cos(w0))): x = self(x) # treatment of nested abs(sin_or_cos(...)) # Simplifications for values of x in the range [-pi, 2*pi]: - if (x >= -pi/2 and x <= pi/2) or (x >= 3*pi/2 and x <= 2*pi): + if (x >= -pi / 2 and x <= pi / 2) or (x >= 3 * pi / 2 and x <= 2 * pi): ex = cos(x) - elif (x > pi/2 and x <= 3*pi/2) or (x >= -pi and x < -pi/2): + elif (x > pi / 2 and x <= 3 * pi / 2) or (x >= -pi and x < -pi / 2): ex = -cos(x) return ex # If no pattern is found, we default to ExpressionTreeWalker: @@ -405,8 +404,8 @@ def simplify_sqrt_real(expr): sage: forget() # for doctests below """ w0 = SR.wild() - one_half = Rational((1,2)) - if expr.has(w0**one_half) or expr.has(w0**(-one_half)): + one_half = Rational((1, 2)) + if expr.has(w0**one_half) or expr.has(w0 ** (-one_half)): return SimplifySqrtReal(expr)() return expr @@ -806,7 +805,8 @@ def simplify_chain_real_sympy(expr): expr = expr.simplify() return expr -#****************************************************************************** + +# ****************************************************************************** class ExpressionNice(Expression): @@ -903,6 +903,7 @@ class ExpressionNice(Expression): sage: latex(ExpressionNice(fun)) f\left(x, y\right) \left(\frac{\partial\,f}{\partial y}\right)^{2} """ + def __init__(self, ex): r""" Initialize ``self``. @@ -919,6 +920,7 @@ def __init__(self, ex): d(f)/dx """ from sage.symbolic.ring import SR + self._parent = SR Expression.__init__(self, SR, x=ex) @@ -973,8 +975,7 @@ def _repr_(self): strv[i] = "(" + sv + ")" # dictionary to group multiple occurrences of differentiation: d/dxdx -> d/dx^2 etc. - occ = {i: strv[i] + "^" + str(D) if (D := diffargs.count(i)) > 1 - else strv[i] for i in diffargs} + occ = {i: strv[i] + "^" + str(D) if (D := diffargs.count(i)) > 1 else strv[i] for i in diffargs} res = f"d{numargs}({funcname})/d" + "d".join(occ.values()) @@ -993,6 +994,7 @@ def _repr_(self): import re from sage.manifolds.manifold import TopologicalManifold + if TopologicalManifold.options.omit_function_arguments: list_f = [] _list_functions(self, list_f) @@ -1075,12 +1077,9 @@ def _latex_(self): latv[i] = r"\left(" + latv[i] + r"\right)" # dictionary to group multiple occurrences of differentiation: d/dxdx -> d/dx^2 etc. - occ = {i: (latv[i] + "^" + latex(diffargs.count(i)) - if diffargs.count(i) > 1 else latv[i]) - for i in diffargs} + occ = {i: (latv[i] + "^" + latex(diffargs.count(i)) if diffargs.count(i) > 1 else latv[i]) for i in diffargs} - res = r"\frac{\partial" + numargs + r"\," + funcname + \ - r"}{\partial " + r"\partial ".join(i for i in occ.values()) + "}" + res = r"\frac{\partial" + numargs + r"\," + funcname + r"}{\partial " + r"\partial ".join(i for i in occ.values()) + "}" # representation of the operator s = self._parent._latex_element_(m[0]) @@ -1095,6 +1094,7 @@ def _latex_(self): d = d.replace(o, res) from sage.manifolds.manifold import TopologicalManifold + if TopologicalManifold.options.omit_function_arguments: list_f = [] _list_functions(self, list_f) @@ -1160,8 +1160,7 @@ def _list_derivatives(ex, list_d, exponent=0): if function == latex_function: latex_function = latex_variable_name(str(op.function())) - list_d.append((ex, function, latex_function, parameter_set, - operands, exponent)) + list_d.append((ex, function, latex_function, parameter_set, operands, exponent)) for operand in operands: _list_derivatives(operand, list_d, exponent) @@ -1218,7 +1217,7 @@ def _list_functions(ex, list_f): repr_args = repr(ex.arguments()) # remove comma in case of singleton if len(ex.arguments()) == 1: - repr_args = repr_args.replace(",","") + repr_args = repr_args.replace(",", "") latex_args = latex(ex.arguments()) @@ -1227,7 +1226,8 @@ def _list_functions(ex, list_f): for operand in operands: _list_functions(operand, list_f) -#****************************************************************************** + +# ****************************************************************************** def set_axes_labels(graph, xlabel, ylabel, zlabel, **kwds): @@ -1263,6 +1263,7 @@ def set_axes_labels(graph, xlabel, ylabel, zlabel, **kwds): Graphics3d Object, Graphics3d Object] """ from sage.plot.plot3d.shapes2 import text3d + xmin, ymin, zmin = graph.bounding_box()[0] xmax, ymax, zmax = graph.bounding_box()[1] dx = xmax - xmin diff --git a/src/sage/manifolds/vector_bundle.py b/src/sage/manifolds/vector_bundle.py index dc3055c6e0c..91f2d04c209 100644 --- a/src/sage/manifolds/vector_bundle.py +++ b/src/sage/manifolds/vector_bundle.py @@ -190,8 +190,8 @@ class TopologicalVectorBundle(CategoryObject, UniqueRepresentation): sage: s in E.section_module() True """ - def __init__(self, rank, name, base_space, field='real', - latex_name=None, category=None, unique_tag=None): + + def __init__(self, rank, name, base_space, field='real', latex_name=None, category=None, unique_tag=None): r""" Construct a topological vector bundle. @@ -223,15 +223,12 @@ def __init__(self, rank, name, base_space, field='real', self._field_type = 'neither_real_nor_complex' bs_field = base_space.base_field() if not bs_field.is_subring(self._field): - raise ValueError("for concrete implementation, manifold's base " - "field must be a subfield of the vector bundle's " - "base field") + raise ValueError("for concrete implementation, manifold's base " "field must be a subfield of the vector bundle's " "base field") ### # Get the category: if category is None: category = VectorBundles(base_space, self._field) - CategoryObject.__init__(self, base=self._field, - category=category) + CategoryObject.__init__(self, base=self._field, category=category) # Check rank: if not isinstance(rank, (int, Integer)): raise TypeError("the rank must be an integer") @@ -441,6 +438,7 @@ def trivialization(self, name, domain=None, latex_name=None): if domain is None: domain = self._base_space from sage.manifolds.trivialization import Trivialization + return Trivialization(self, name, domain=domain, latex_name=latex_name) def transitions(self): @@ -506,9 +504,7 @@ def transition(self, triv1, triv2): (phi_U, E|_U) """ if (triv1, triv2) not in self._transitions: - raise TypeError("the transition map from " + - "{} to {}".format(triv1, triv2) + " has not " + - "been defined on the {}".format(self)) + raise TypeError("the transition map from " + "{} to {}".format(triv1, triv2) + " has not " + "been defined on the {}".format(self)) return self._transitions[(triv1, triv2)] def atlas(self): @@ -642,6 +638,7 @@ def section_module(self, domain=None, force_free=False): if domain is None: domain = self._base_space from sage.manifolds.section_module import SectionFreeModule, SectionModule + if domain not in self._section_modules: if force_free or domain in self._trivial_parts: self._section_modules[domain] = SectionFreeModule(self, domain) @@ -771,11 +768,11 @@ def local_frame(self, *args, **kwargs): indices, see :class:`~sage.manifolds.local_frame.LocalFrame`. """ from sage.manifolds.local_frame import LocalFrame + # Input processing n_args = len(args) if n_args < 1 or n_args > 2: - raise TypeError("local_frame() takes one or two positional " - "arguments, not {}".format(n_args)) + raise TypeError("local_frame() takes one or two positional " "arguments, not {}".format(n_args)) symbol = args[0] sections = None if n_args == 2: @@ -788,20 +785,15 @@ def local_frame(self, *args, **kwargs): domain = kwargs.pop('domain', None) sec_module = self.section_module(domain=domain, force_free=True) - resu = LocalFrame(sec_module, symbol=symbol, latex_symbol=latex_symbol, - indices=indices, latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) + resu = LocalFrame(sec_module, symbol=symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) if sections: linked = False try: resu._init_from_family(sections) except ArithmeticError as err: - linked = str(err) in ["non-invertible matrix", - "input matrix must be nonsingular"] + linked = str(err) in ["non-invertible matrix", "input matrix must be nonsingular"] if linked: - raise ValueError("the provided sections are not linearly " - "independent") + raise ValueError("the provided sections are not linearly " "independent") return resu def section(self, *comp, **kwargs): @@ -876,22 +868,17 @@ def total_space(self): """ if self._total_space is None: from sage.manifolds.manifold import Manifold + base_space = self._base_space dim = base_space._dim + self._rank sindex = base_space.start_index() - self._total_space = Manifold( - dim, self._name, - latex_name=self._latex_name, - field=self._field, structure='topological', - start_index=sindex - ) + self._total_space = Manifold(dim, self._name, latex_name=self._latex_name, field=self._field, structure='topological', start_index=sindex) # TODO: if update_atlas: introduce charts via self._atlas return self._total_space - def set_change_of_frame(self, frame1, frame2, change_of_frame, - compute_inverse=True): + def set_change_of_frame(self, frame1, frame2, change_of_frame, compute_inverse=True): r""" Relate two vector frames by an automorphism. @@ -933,17 +920,16 @@ def set_change_of_frame(self, frame1, frame2, change_of_frame, [0 3] """ from sage.tensor.modules.free_module_automorphism import FreeModuleAutomorphism + sec_module = frame1._fmodule if frame2._fmodule != sec_module: - raise ValueError("the two frames are not defined on the same " + - "section module") + raise ValueError("the two frames are not defined on the same " + "section module") if isinstance(change_of_frame, FreeModuleAutomorphism): auto = change_of_frame else: # Otherwise try to coerce the input auto_group = sec_module.general_linear_group() auto = auto_group(change_of_frame, basis=frame1) - sec_module.set_change_of_basis(frame1, frame2, auto, - compute_inverse=compute_inverse) + sec_module.set_change_of_basis(frame1, frame2, auto, compute_inverse=compute_inverse) self._frame_changes[(frame1, frame2)] = auto if compute_inverse: self._frame_changes[(frame2, frame1)] = ~auto @@ -983,8 +969,7 @@ def change_of_frame(self, frame1, frame2): True """ if (frame1, frame2) not in self._frame_changes: - raise ValueError("the change of frame from {} to {}".format(frame1, frame2) + - " has not been defined on the {}".format(self)) + raise ValueError("the change of frame from {} to {}".format(frame1, frame2) + " has not been defined on the {}".format(self)) return self._frame_changes[(frame1, frame2)] def changes_of_frame(self): @@ -1102,11 +1087,11 @@ def set_default_frame(self, frame): Local frame (E|_M, (f_0,f_1)) """ from sage.manifolds.local_frame import LocalFrame + if not isinstance(frame, LocalFrame): raise TypeError("{} is not a local frame".format(frame)) if not frame._domain.is_subset(self._base_space): - raise ValueError("the frame must be defined on " + - "the {}".format(self)) + raise ValueError("the frame must be defined on " + "the {}".format(self)) frame._fmodule.set_default_basis(frame) self._def_frame = frame @@ -1158,18 +1143,17 @@ def set_orientation(self, orientation): Local frame (E|_V, (f_0,f_1))] """ from sage.manifolds.local_frame import LocalFrame + if isinstance(orientation, LocalFrame): orientation = [orientation] elif isinstance(orientation, (tuple, list)): orientation = list(orientation) else: - raise TypeError("orientation must be a frame or a list/tuple of " - "frames") + raise TypeError("orientation must be a frame or a list/tuple of " "frames") dom_union = None for frame in orientation: if frame not in self.frames(): - raise ValueError("{} must be a frame ".format(frame) + - "defined on {}".format(self)) + raise ValueError("{} must be a frame ".format(frame) + "defined on {}".format(self)) dom = frame.domain() if dom_union is not None: dom_union = dom.union(dom_union) @@ -1177,8 +1161,7 @@ def set_orientation(self, orientation): dom_union = dom base_space = self._base_space if dom_union != base_space: - raise ValueError("the frames's domains must " - "cover {}".format(base_space)) + raise ValueError("the frames's domains must " "cover {}".format(base_space)) self._orientation = orientation def orientation(self): diff --git a/src/sage/manifolds/vector_bundle_fiber.py b/src/sage/manifolds/vector_bundle_fiber.py index a7cebfba9f8..7cc88a0b92a 100644 --- a/src/sage/manifolds/vector_bundle_fiber.py +++ b/src/sage/manifolds/vector_bundle_fiber.py @@ -8,14 +8,14 @@ - Michael Jung (2019): initial version """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2019 Michael Jung # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.manifolds.vector_bundle_fiber_element import VectorBundleFiberElement from sage.symbolic.ring import SR @@ -158,6 +158,7 @@ class VectorBundleFiber(FiniteRankFreeModule): :class:`~sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule` for more documentation. """ + Element = VectorBundleFiberElement def __init__(self, vector_bundle, point): @@ -175,38 +176,29 @@ def __init__(self, vector_bundle, point): sage: TestSuite(Ep).run() """ if point._manifold is not vector_bundle._base_space: - raise ValueError("Point must be an element " - "of {}".format(vector_bundle._manifold)) + raise ValueError("Point must be an element " "of {}".format(vector_bundle._manifold)) name = "{}_{}".format(vector_bundle._name, point._name) - latex_name = r'{}_{{{}}}'.format(vector_bundle._latex_name, - point._latex_name) + latex_name = r'{}_{{{}}}'.format(vector_bundle._latex_name, point._latex_name) self._rank = vector_bundle._rank self._vbundle = vector_bundle self._point = point self._base_space = point._manifold - FiniteRankFreeModule.__init__(self, SR, self._rank, name=name, - latex_name=latex_name, - start_index=self._base_space._sindex) + FiniteRankFreeModule.__init__(self, SR, self._rank, name=name, latex_name=latex_name, start_index=self._base_space._sindex) ### # Construct basis - self._frame_bases = {} # dictionary of bases of the vector bundle fiber - # derived from local frames around the point - # (keys: local frames) + self._frame_bases = {} # dictionary of bases of the vector bundle fiber + # derived from local frames around the point + # (keys: local frames) self._def_basis = None for frame in vector_bundle._frames: # the frame is used to construct a basis of the vector bundle fiber # only if it is a frame for the given point: if point in frame.domain(): coframe = frame.coframe() - basis = self.basis(frame._symbol, - latex_symbol=frame._latex_symbol, - indices=frame._indices, - latex_indices=frame._latex_indices, - symbol_dual=coframe._symbol, - latex_symbol_dual=coframe._latex_symbol) + basis = self.basis(frame._symbol, latex_symbol=frame._latex_symbol, indices=frame._indices, latex_indices=frame._latex_indices, symbol_dual=coframe._symbol, latex_symbol_dual=coframe._latex_symbol) self._frame_bases[frame] = basis if self._def_basis is None: - self._def_basis = basis # Declare the first basis as default + self._def_basis = basis # Declare the first basis as default # Initialization of the changes of bases from the existing changes of # frames around the point: for frame_pair, automorph in self._vbundle._frame_changes.items(): @@ -266,8 +258,7 @@ def _repr_(self): sage: E.fiber(p)._repr_() 'Fiber of E at Point p on the 3-dimensional topological manifold M' """ - return "Fiber of {} at {}".format(self._vbundle._name, - self._point) + return "Fiber of {} at {}".format(self._vbundle._name, self._point) def dimension(self): r""" diff --git a/src/sage/manifolds/vector_bundle_fiber_element.py b/src/sage/manifolds/vector_bundle_fiber_element.py index 39f18691463..7526cd3e958 100644 --- a/src/sage/manifolds/vector_bundle_fiber_element.py +++ b/src/sage/manifolds/vector_bundle_fiber_element.py @@ -9,14 +9,14 @@ - Michael Jung (2019): initial version """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2019 Michael Jung # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#****************************************************************************** +# ****************************************************************************** from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement @@ -58,6 +58,7 @@ class VectorBundleFiberElement(FiniteRankFreeModuleElement): :class:`~sage.tensor.modules.free_module_element.FiniteRankFreeModuleElement` for more documentation. """ + def __init__(self, parent, name=None, latex_name=None): r""" Construct a vector in the given fiber of a given vector bundle. @@ -76,8 +77,7 @@ def __init__(self, parent, name=None, latex_name=None): sage: v[:] = 5, -3/2 sage: TestSuite(v).run() """ - FiniteRankFreeModuleElement.__init__(self, parent, name=name, - latex_name=latex_name) + FiniteRankFreeModuleElement.__init__(self, parent, name=name, latex_name=latex_name) # Extra data (with respect to FiniteRankFreeModuleElement): self._point = parent._point self._vbundle = parent._vbundle @@ -105,6 +105,5 @@ def _repr_(self): desc = "Vector " if self._name: desc += str(self._name) + " " - desc += "in the fiber of {} at {}".format(self._vbundle._name, - self._point) + desc += "in the fiber of {} at {}".format(self._vbundle._name, self._point) return desc diff --git a/src/sage/matrix/all.py b/src/sage/matrix/all.py index 0902e081afb..c4f0b76355b 100644 --- a/src/sage/matrix/all.py +++ b/src/sage/matrix/all.py @@ -1,8 +1,6 @@ from sage.misc.lazy_import import lazy_import from sage.matrix.matrix_space import MatrixSpace -from sage.matrix.constructor import (matrix, Matrix, column_matrix, random_matrix, - diagonal_matrix, identity_matrix, block_matrix, - block_diagonal_matrix, jordan_block, zero_matrix, - ones_matrix, elementary_matrix, companion_matrix) +from sage.matrix.constructor import matrix, Matrix, column_matrix, random_matrix, diagonal_matrix, identity_matrix, block_matrix, block_diagonal_matrix, jordan_block, zero_matrix, ones_matrix, elementary_matrix, companion_matrix + Mat = MatrixSpace del lazy_import diff --git a/src/sage/matrix/benchmark.py b/src/sage/matrix/benchmark.py index ed469cc729d..d5328e65b98 100644 --- a/src/sage/matrix/benchmark.py +++ b/src/sage/matrix/benchmark.py @@ -60,6 +60,7 @@ def report(F, title, systems=['sage', 'magma'], **kwds): ====================================================================== """ import os + if len(systems) > 2: raise NotImplementedError("at most two systems ('sage' or 'magma')") print('=' * 70) @@ -68,7 +69,7 @@ def report(F, title, systems=['sage', 'magma'], **kwds): os.system('uname -a') print('\n') for f in F: - print("-"*70) + print("-" * 70) print(f.__doc__.strip()) print(('%15s' * len(systems)) % tuple(systems)) w = [] @@ -84,10 +85,10 @@ def report(F, title, systems=['sage', 'magma'], **kwds): if w[1] == 0: w.append(0.0) else: - w.append(w[0]/w[1]) + w.append(w[0] / w[1]) w = tuple(w) - print(('%15.3f'*len(w)) % w) + print(('%15.3f' * len(w)) % w) print('=' * 70) @@ -95,6 +96,7 @@ def report(F, title, systems=['sage', 'magma'], **kwds): # Dense Benchmarks over ZZ ####################################################################### + def report_ZZ(**kwds): """ Reports all the benchmarks for integer matrices and few @@ -115,14 +117,12 @@ def report_ZZ(**kwds): ... ====================================================================== """ - F = [vecmat_ZZ, rank_ZZ, rank2_ZZ, charpoly_ZZ, smithform_ZZ, - det_ZZ, det_QQ, matrix_multiply_ZZ, matrix_add_ZZ, - matrix_add_ZZ_2, - nullspace_ZZ] + F = [vecmat_ZZ, rank_ZZ, rank2_ZZ, charpoly_ZZ, smithform_ZZ, det_ZZ, det_QQ, matrix_multiply_ZZ, matrix_add_ZZ, matrix_add_ZZ_2, nullspace_ZZ] title = 'Dense benchmarks over ZZ' report(F, title, **kwds) + # Integer Nullspace @@ -146,7 +146,7 @@ def nullspace_ZZ(n=200, min=0, max=2**32, system='sage'): sage: tm = b.nullspace_ZZ(200, system='magma') # optional - magma """ if system == 'sage': - A = random_matrix(ZZ, n+1, n, x=min, y=max+1).change_ring(QQ) + A = random_matrix(ZZ, n + 1, n, x=min, y=max + 1).change_ring(QQ) t = cputime() v = A.kernel() return cputime(t) @@ -157,7 +157,11 @@ def nullspace_ZZ(n=200, min=0, max=2**32, system='sage'): t := Cputime(); K := Kernel(A); s := Cputime(t); -""" % (n, min, max) +""" % ( + n, + min, + max, + ) if verbose: print(code) magma.eval(code) @@ -185,7 +189,7 @@ def charpoly_ZZ(n=100, min=0, max=9, system='sage'): sage: tm = b.charpoly_ZZ(100, system='magma') # optional - magma """ if system == 'sage': - A = random_matrix(ZZ, n, n, x=min, y=max+1) + A = random_matrix(ZZ, n, n, x=min, y=max + 1) t = cputime() v = A.charpoly() return cputime(t) @@ -196,7 +200,11 @@ def charpoly_ZZ(n=100, min=0, max=9, system='sage'): t := Cputime(); K := CharacteristicPolynomial(A); s := Cputime(t); -""" % (n, min, max) +""" % ( + n, + min, + max, + ) if verbose: print(code) magma.eval(code) @@ -224,7 +232,7 @@ def rank_ZZ(n=700, min=0, max=9, system='sage'): sage: tm = b.rank_ZZ(300, system='magma') # optional - magma """ if system == 'sage': - A = random_matrix(ZZ, n, n+10, x=min, y=max+1) + A = random_matrix(ZZ, n, n + 10, x=min, y=max + 1) t = cputime() v = A.rank() return cputime(t) @@ -235,7 +243,11 @@ def rank_ZZ(n=700, min=0, max=9, system='sage'): t := Cputime(); K := Rank(A); s := Cputime(t); -""" % (n, min, max) +""" % ( + n, + min, + max, + ) if verbose: print(code) magma.eval(code) @@ -263,7 +275,7 @@ def rank2_ZZ(n=400, min=0, max=2**64, system='sage'): sage: tm = b.rank2_ZZ(300, system='magma') # optional - magma """ if system == 'sage': - A = random_matrix(ZZ, n+10, n, x=min, y=max+1) + A = random_matrix(ZZ, n + 10, n, x=min, y=max + 1) t = cputime() v = A.rank() return cputime(t) @@ -274,13 +286,18 @@ def rank2_ZZ(n=400, min=0, max=2**64, system='sage'): t := Cputime(); K := Rank(A); s := Cputime(t); -""" % (n, min, max) +""" % ( + n, + min, + max, + ) if verbose: print(code) magma.eval(code) return float(magma.eval('s')) raise ValueError('unknown system "%s"' % system) + # Smith Form @@ -304,7 +321,7 @@ def smithform_ZZ(n=128, min=0, max=9, system='sage'): sage: tm = b.smithform_ZZ(100, system='magma') # optional - magma """ if system == 'sage': - A = random_matrix(ZZ, n, n, x=min, y=max+1) + A = random_matrix(ZZ, n, n, x=min, y=max + 1) t = cputime() v = A.elementary_divisors() return cputime(t) @@ -315,7 +332,11 @@ def smithform_ZZ(n=128, min=0, max=9, system='sage'): t := Cputime(); K := ElementaryDivisors(A); s := Cputime(t); -""" % (n, min, max) +""" % ( + n, + min, + max, + ) if verbose: print(code) magma.eval(code) @@ -344,12 +365,12 @@ def matrix_multiply_ZZ(n=300, min=-9, max=9, system='sage', times=1): sage: tm = b.matrix_multiply_ZZ(200, system='magma') # optional - magma """ if system == 'sage': - A = random_matrix(ZZ, n, n, x=min, y=max+1) + A = random_matrix(ZZ, n, n, x=min, y=max + 1) B = A + 1 t = cputime() for z in range(times): v = A * B - return cputime(t)/times + return cputime(t) / times if system == 'magma': code = """ n := %s; @@ -360,11 +381,16 @@ def matrix_multiply_ZZ(n=300, min=-9, max=9, system='sage', times=1): K := A * B; end for; s := Cputime(t); -""" % (n, min, max, times) +""" % ( + n, + min, + max, + times, + ) if verbose: print(code) magma.eval(code) - return float(magma.eval('s'))/times + return float(magma.eval('s')) / times raise ValueError('unknown system "%s"' % system) @@ -389,12 +415,12 @@ def matrix_add_ZZ(n=200, min=-9, max=9, system='sage', times=50): sage: tm = b.matrix_add_ZZ(200, system='magma') # optional - magma """ if system == 'sage': - A = random_matrix(ZZ, n, n, x=min, y=max+1) - B = random_matrix(ZZ, n, n, x=min, y=max+1) + A = random_matrix(ZZ, n, n, x=min, y=max + 1) + B = random_matrix(ZZ, n, n, x=min, y=max + 1) t = cputime() for z in range(times): v = A + B - return cputime(t)/times + return cputime(t) / times if system == 'magma': code = """ n := %s; @@ -407,11 +433,16 @@ def matrix_add_ZZ(n=200, min=-9, max=9, system='sage', times=50): K := A + B; end for; s := Cputime(t); -""" % (n, min, max, times) +""" % ( + n, + min, + max, + times, + ) if verbose: print(code) magma.eval(code) - return float(magma.eval('s'))/times + return float(magma.eval('s')) / times raise ValueError('unknown system "%s"' % system) @@ -435,7 +466,7 @@ def matrix_add_ZZ_2(n=200, bits=16, system='sage', times=50): sage: tm = b.matrix_add_ZZ_2(200, system='magma') # optional - magma """ b = 2**bits - return matrix_add_ZZ(n=n, min=-b, max=b,system=system, times=times) + return matrix_add_ZZ(n=n, min=-b, max=b, system=system, times=times) def det_ZZ(n=200, min=1, max=100, system='sage'): @@ -458,7 +489,7 @@ def det_ZZ(n=200, min=1, max=100, system='sage'): sage: tm = b.det_ZZ(200, system='magma') # optional - magma """ if system == 'sage': - A = random_matrix(ZZ, n, n, x=min, y=max+1) + A = random_matrix(ZZ, n, n, x=min, y=max + 1) t = cputime() d = A.determinant() return cputime(t) @@ -469,7 +500,11 @@ def det_ZZ(n=200, min=1, max=100, system='sage'): t := Cputime(); d := Determinant(A); s := Cputime(t); -""" % (n, min, max) +""" % ( + n, + min, + max, + ) if verbose: print(code) magma.eval(code) @@ -509,7 +544,12 @@ def det_QQ(n=300, num_bound=10, den_bound=10, system='sage'): t := Cputime(); d := Determinant(A); s := Cputime(t); -""" % (n,-num_bound, num_bound, den_bound) +""" % ( + n, + -num_bound, + num_bound, + den_bound, + ) if verbose: print(code) magma.eval(code) @@ -540,12 +580,12 @@ def vecmat_ZZ(n=300, min=-9, max=9, system='sage', times=200): sage: tm = b.vecmat_ZZ(300, system='magma') # optional - magma """ if system == 'sage': - A = random_matrix(ZZ, n, n, x=min, y=max+1) + A = random_matrix(ZZ, n, n, x=min, y=max + 1) v = A.row(0) t = cputime() for z in range(times): w = v * A - return cputime(t)/times + return cputime(t) / times if system == 'magma': code = """ n := %s; @@ -556,11 +596,16 @@ def vecmat_ZZ(n=300, min=-9, max=9, system='sage', times=200): K := v * A; end for; s := Cputime(t); -""" % (n, min, max, times) +""" % ( + n, + min, + max, + times, + ) if verbose: print(code) magma.eval(code) - return float(magma.eval('s'))/times + return float(magma.eval('s')) / times raise ValueError('unknown system "%s"' % system) @@ -568,6 +613,7 @@ def vecmat_ZZ(n=300, min=-9, max=9, system='sage', times=200): # Dense Benchmarks over GF(p), for small p. ####################################################################### + def report_GF(p=16411, **kwds): """ Run all the reports for finite field matrix operations, for @@ -595,11 +641,11 @@ def report_GF(p=16411, **kwds): ... ====================================================================== """ - F = [rank_GF, rank2_GF, nullspace_GF, charpoly_GF, - matrix_multiply_GF, det_GF] + F = [rank_GF, rank2_GF, nullspace_GF, charpoly_GF, matrix_multiply_GF, det_GF] title = 'Dense benchmarks over GF with prime %i' % p report(F, title, **kwds) + # Nullspace over GF @@ -621,7 +667,7 @@ def nullspace_GF(n=300, p=16411, system='sage'): sage: tm = b.nullspace_GF(300, system='magma') # optional - magma """ if system == 'sage': - A = random_matrix(GF(p), n, n+1) + A = random_matrix(GF(p), n, n + 1) t = cputime() v = A.kernel() return cputime(t) @@ -632,7 +678,10 @@ def nullspace_GF(n=300, p=16411, system='sage'): t := Cputime(); K := Kernel(A); s := Cputime(t); -""" % (n,p) +""" % ( + n, + p, + ) if verbose: print(code) magma.eval(code) @@ -642,6 +691,7 @@ def nullspace_GF(n=300, p=16411, system='sage'): # Characteristic Polynomial over GF + def charpoly_GF(n=100, p=16411, system='sage'): """ Given a n x n matrix over GF with random entries, compute the @@ -671,7 +721,10 @@ def charpoly_GF(n=100, p=16411, system='sage'): t := Cputime(); K := CharacteristicPolynomial(A); s := Cputime(t); -""" % (n,p) +""" % ( + n, + p, + ) if verbose: print(code) magma.eval(code) @@ -713,7 +766,12 @@ def matrix_add_GF(n=1000, p=16411, system='sage', times=100): K := A + B; end for; s := Cputime(t); -""" % (n,p,p,times) +""" % ( + n, + p, + p, + times, + ) if verbose: print(code) magma.eval(code) @@ -723,6 +781,7 @@ def matrix_add_GF(n=1000, p=16411, system='sage', times=100): # Matrix multiplication over GF(p) + def matrix_multiply_GF(n=100, p=16411, system='sage', times=3): """ Given an n x n matrix A over GF(p) with random entries, compute @@ -758,11 +817,15 @@ def matrix_multiply_GF(n=100, p=16411, system='sage', times=3): K := A * B; end for; s := Cputime(t); -""" % (n,p,times) +""" % ( + n, + p, + times, + ) if verbose: print(code) magma.eval(code) - return float(magma.eval('s'))/times + return float(magma.eval('s')) / times raise ValueError('unknown system "%s"' % system) @@ -784,7 +847,7 @@ def rank_GF(n=500, p=16411, system='sage'): sage: tm = b.rank_GF(1000, system='magma') # optional - magma """ if system == 'sage': - A = random_matrix(GF(p), n, n+10) + A = random_matrix(GF(p), n, n + 10) t = cputime() v = A.rank() return cputime(t) @@ -795,7 +858,10 @@ def rank_GF(n=500, p=16411, system='sage'): t := Cputime(); K := Rank(A); s := Cputime(t); -""" % (n,p) +""" % ( + n, + p, + ) if verbose: print(code) magma.eval(code) @@ -821,7 +887,7 @@ def rank2_GF(n=500, p=16411, system='sage'): sage: tm = b.rank2_GF(500, system='magma') # optional - magma """ if system == 'sage': - A = random_matrix(GF(p), n+10, n) + A = random_matrix(GF(p), n + 10, n) t = cputime() v = A.rank() return cputime(t) @@ -832,7 +898,10 @@ def rank2_GF(n=500, p=16411, system='sage'): t := Cputime(); K := Rank(A); s := Cputime(t); -""" % (n,p) +""" % ( + n, + p, + ) if verbose: print(code) magma.eval(code) @@ -840,7 +909,7 @@ def rank2_GF(n=500, p=16411, system='sage'): raise ValueError('unknown system "%s"' % system) -def det_GF(n=400, p=16411 , system='sage'): +def det_GF(n=400, p=16411, system='sage'): """ Dense determinant over GF(p). Given an n x n matrix A over GF with random entries compute @@ -870,7 +939,10 @@ def det_GF(n=400, p=16411 , system='sage'): t := Cputime(); d := Determinant(A); s := Cputime(t); -""" % (n,p) +""" % ( + n, + p, + ) if verbose: print(code) magma.eval(code) @@ -882,6 +954,7 @@ def det_GF(n=400, p=16411 , system='sage'): # Dense Benchmarks over QQ ####################################################################### + def hilbert_matrix(n): """ Return the Hilbert matrix of size n over rationals. @@ -894,12 +967,13 @@ def hilbert_matrix(n): [1/2 1/3 1/4] [1/3 1/4 1/5] """ - A = Matrix(QQ,n,n) + A = Matrix(QQ, n, n) for i in range(A.nrows()): for j in range(A.ncols()): - A[i,j] = QQ(1)/((i+1)+(j+1)-1) + A[i, j] = QQ(1) / ((i + 1) + (j + 1) - 1) return A + # Reduced row echelon form over QQ @@ -922,7 +996,7 @@ def echelon_QQ(n=100, min=0, max=9, system='sage'): sage: tm = b.echelon_QQ(100, system='magma') # optional - magma """ if system == 'sage': - A = random_matrix(ZZ, n, 2*n, x=min, y=max+1).change_ring(QQ) + A = random_matrix(ZZ, n, 2 * n, x=min, y=max + 1).change_ring(QQ) t = cputime() v = A.echelon_form() return cputime(t) @@ -933,13 +1007,18 @@ def echelon_QQ(n=100, min=0, max=9, system='sage'): t := Cputime(); K := EchelonForm(A); s := Cputime(t); -""" % (n, min, max) +""" % ( + n, + min, + max, + ) if verbose: print(code) magma.eval(code) return float(magma.eval('s')) raise ValueError('unknown system "%s"' % system) + # Invert a matrix over QQ. @@ -962,7 +1041,7 @@ def inverse_QQ(n=100, min=0, max=9, system='sage'): sage: tm = b.inverse_QQ(100, system='magma') # optional - magma """ if system == 'sage': - A = random_matrix(ZZ, n, n, x=min, y=max+1).change_ring(QQ) + A = random_matrix(ZZ, n, n, x=min, y=max + 1).change_ring(QQ) t = cputime() v = ~A return cputime(t) @@ -973,7 +1052,11 @@ def inverse_QQ(n=100, min=0, max=9, system='sage'): t := Cputime(); K := A^(-1); s := Cputime(t); -""" % (n, min, max) +""" % ( + n, + min, + max, + ) if verbose: print(code) magma.eval(code) @@ -1007,7 +1090,7 @@ def matrix_multiply_QQ(n=100, bnd=2, system='sage', times=1): t = cputime() for z in range(times): v = A * B - return cputime(t)/times + return cputime(t) / times if system == 'magma': A = magma(random_matrix(QQ, n, n, num_bound=bnd, den_bound=bnd)) code = """ @@ -1019,11 +1102,15 @@ def matrix_multiply_QQ(n=100, bnd=2, system='sage', times=1): K := A * B; end for; s := Cputime(t); -""" % (n, A.name(), times) +""" % ( + n, + A.name(), + times, + ) if verbose: print(code) magma.eval(code) - return float(magma.eval('s'))/times + return float(magma.eval('s')) / times raise ValueError('unknown system "%s"' % system) @@ -1050,18 +1137,22 @@ def det_hilbert_QQ(n=80, system='sage'): d = A.determinant() return cputime(t) if system == 'magma': - code = """ + code = ( + """ h := HilbertMatrix(%s); tinit := Cputime(); d := Determinant(h); s := Cputime(tinit); delete h; -""" % n +""" + % n + ) if verbose: print(code) magma.eval(code) return float(magma.eval('s')) + # inverse of Hilbert matrix @@ -1084,16 +1175,19 @@ def invert_hilbert_QQ(n=40, system='sage'): if system == 'sage': A = hilbert_matrix(n) t = cputime() - d = A**(-1) + d = A ** (-1) return cputime(t) if system == 'magma': - code = """ + code = ( + """ h := HilbertMatrix(%s); tinit := Cputime(); d := h^(-1); s := Cputime(tinit); delete h; -""" % n +""" + % n + ) if verbose: print(code) magma.eval(code) @@ -1121,10 +1215,10 @@ def MatrixVector_QQ(n=1000, h=100, system='sage', times=1): if system == 'sage': V = QQ**n v = V.random_element(h) - M = random_matrix(QQ,n) + M = random_matrix(QQ, n) t = cputime() for i in range(times): - w = M*v + w = M * v return cputime(t) if system == 'magma': code = """ @@ -1138,7 +1232,11 @@ def MatrixVector_QQ(n=1000, h=100, system='sage', times=1): W:=v*M; end for; s := Cputime(t); - """ % (n,h,times) + """ % ( + n, + h, + times, + ) if verbose: print(code) magma.eval(code) @@ -1154,6 +1252,7 @@ def MatrixVector_QQ(n=1000, h=100, system='sage', times=1): # Real Nullspace + def nullspace_RR(n=300, min=0, max=10, system='sage'): """ Nullspace over RR: @@ -1175,7 +1274,8 @@ def nullspace_RR(n=300, min=0, max=10, system='sage'): """ if system == 'sage': from sage.rings.real_mpfr import RR - A = random_matrix(ZZ, n+1, n, x=min, y=max+1).change_ring(RR) + + A = random_matrix(ZZ, n + 1, n, x=min, y=max + 1).change_ring(RR) t = cputime() v = A.kernel() return cputime(t) @@ -1186,7 +1286,11 @@ def nullspace_RR(n=300, min=0, max=10, system='sage'): t := Cputime(); K := Kernel(A); s := Cputime(t); -""" % (n, min, max) +""" % ( + n, + min, + max, + ) if verbose: print(code) magma.eval(code) @@ -1215,7 +1319,8 @@ def nullspace_RDF(n=300, min=0, max=10, system='sage'): """ if system == 'sage': from sage.rings.real_double import RDF - A = random_matrix(ZZ, n+1, n, x=min, y=max+1).change_ring(RDF) + + A = random_matrix(ZZ, n + 1, n, x=min, y=max + 1).change_ring(RDF) t = cputime() v = A.kernel() return cputime(t) @@ -1226,7 +1331,11 @@ def nullspace_RDF(n=300, min=0, max=10, system='sage'): t := Cputime(); K := Kernel(A); s := Cputime(t); -""" % (n, min, max) +""" % ( + n, + min, + max, + ) if verbose: print(code) magma.eval(code) diff --git a/src/sage/matrix/berlekamp_massey.py b/src/sage/matrix/berlekamp_massey.py index e9284f3c08e..b56e0744b20 100644 --- a/src/sage/matrix/berlekamp_massey.py +++ b/src/sage/matrix/berlekamp_massey.py @@ -5,6 +5,7 @@ - William Stein """ + # **************************************************************************** # Copyright (C) 2005 William Stein # @@ -86,7 +87,7 @@ def berlekamp_massey(a): K = sage.rings.rational_field.RationalField() R, x = K['x'].objgen() - f0, f1 = R(a), x**(2 * M) + f0, f1 = R(a), x ** (2 * M) s0, s1 = 1, 0 while f1.degree() >= M: f0, (q, f1) = f1, f0.quo_rem(f1) diff --git a/src/sage/matrix/compute_J_ideal.py b/src/sage/matrix/compute_J_ideal.py index bb00d8d3b0d..fdf5ad11aab 100644 --- a/src/sage/matrix/compute_J_ideal.py +++ b/src/sage/matrix/compute_J_ideal.py @@ -200,20 +200,20 @@ def lifting(p, t, A, G): if t == 0: return matrix(DX, d, 0) - if not (A*G % p**(t-1)).is_zero(): - raise ValueError("A*G not zero mod %s^%s" % (p, t-1)) + if not (A * G % p ** (t - 1)).is_zero(): + raise ValueError("A*G not zero mod %s^%s" % (p, t - 1)) - R = A*G/p**(t-1) + R = A * G / p ** (t - 1) R.change_ring(DX) AR = matrix.block([[A, R]]) - Fp = D.quotient(p*D) + Fp = D.quotient(p * D) FpX = PolynomialRing(Fp, name=X) ARb = AR.change_ring(FpX) (Db, Sb, Tb) = ARb.smith_form() - #assert Sb * ARb * Tb == Db - #assert all(i == j or Db[i, j].is_zero() + # assert Sb * ARb * Tb == Db + # assert all(i == j or Db[i, j].is_zero() # for i in range(Db.nrows()) # for j in range(Db.ncols())) @@ -223,9 +223,9 @@ def lifting(p, t, A, G): T = Tb.change_ring(DX) - F1 = matrix.block([[p**(t-1) * matrix.identity(d), G]])*T + F1 = matrix.block([[p ** (t - 1) * matrix.identity(d), G]]) * T F = F1.matrix_from_columns(range(r, F1.ncols())) - assert (A*F % (p**t)).is_zero(), "A*F=%s" % (A*F) + assert (A * F % (p**t)).is_zero(), "A*F=%s" % (A * F) return F @@ -265,8 +265,7 @@ def p_part(f, p): """ DX = f.parent() (X,) = DX.gens() - return DX(sum(c//p * X**i for i, c in enumerate(f.list()) - if c % p == 0)) + return DX(sum(c // p * X**i for i, c in enumerate(f.list()) if c % p == 0)) class ComputeMinimalPolynomials(SageObject): @@ -315,6 +314,7 @@ class ComputeMinimalPolynomials(SageObject): sage: C.integer_valued_polynomials_generators() (x^3 + x^2 - 12*x - 20, [1, 1/4*x^2 + 3/4*x + 1/2]) """ + def __init__(self, B): r""" Initialize the ComputeMinimalPolynomials class. @@ -341,11 +341,11 @@ def __init__(self, B): self._D = B.base_ring() X = polygen(self._D) adjugate = (X - B).adjugate() - d = B.nrows()**2 + d = B.nrows() ** 2 b = matrix(d, 1, adjugate.list()) self.chi_B = B.charpoly(X) self.mu_B = B.minimal_polynomial() - self._A = matrix.block([[b , -self.chi_B*matrix.identity(d)]]) + self._A = matrix.block([[b, -self.chi_B * matrix.identity(d)]]) self._DX = X.parent() self._cache = {} @@ -398,13 +398,11 @@ def find_monic_replacements(self, p, t, pt_generators, prev_nu): """ from sage.arith.misc import xgcd - if not all((g(self._B) % p**t).is_zero() - for g in pt_generators): - raise ValueError("%s not in N_{(%s^%s)}(B)" % - (pt_generators, p, t)) + if not all((g(self._B) % p**t).is_zero() for g in pt_generators): + raise ValueError("%s not in N_{(%s^%s)}(B)" % (pt_generators, p, t)) - if not (prev_nu(self._B) % p**(t-1)).is_zero(): - raise ValueError("%s not in N_{(%s^%s)}(B)" % (prev_nu, p, t-1)) + if not (prev_nu(self._B) % p ** (t - 1)).is_zero(): + raise ValueError("%s not in N_{(%s^%s)}(B)" % (prev_nu, p, t - 1)) (X,) = self._DX.gens() @@ -413,19 +411,18 @@ def find_monic_replacements(self, p, t, pt_generators, prev_nu): g = f p_prt = p_part(g, p) - while g != p*p_prt: + while g != p * p_prt: r = p_prt.quo_rem(prev_nu)[1] - g1 = g - p*p_prt + g1 = g - p * p_prt d, u, v = xgcd(g1.leading_coefficient(), p) - h = u*(p*r + g1) + v*p*prev_nu*X**(g1.degree()-prev_nu.degree()) + h = u * (p * r + g1) + v * p * prev_nu * X ** (g1.degree() - prev_nu.degree()) replacements.append(h % p**t) - #reduce coefficients mod p^t to keep coefficients small + # reduce coefficients mod p^t to keep coefficients small g = g.quo_rem(h)[1] p_prt = p_part(g, p) replacements = list(set(replacements)) - assert all(g.is_monic() for g in replacements),\ - "Something went wrong in find_monic_replacements" + assert all(g.is_monic() for g in replacements), "Something went wrong in find_monic_replacements" return replacements @@ -478,13 +475,11 @@ def current_nu(self, p, t, pt_generators, prev_nu): from sage.misc.verbose import verbose - if not all((g(self._B) % p**t).is_zero() - for g in pt_generators): - raise ValueError("%s not in N_{(%s^%s)}(B)" % - (pt_generators, p, t)) + if not all((g(self._B) % p**t).is_zero() for g in pt_generators): + raise ValueError("%s not in N_{(%s^%s)}(B)" % (pt_generators, p, t)) - if not (prev_nu(self._B) % p**(t-1)).is_zero(): - raise ValueError("%s not in N_{(%s^%s)}(B)" % (prev_nu, p, t-1)) + if not (prev_nu(self._B) % p ** (t - 1)).is_zero(): + raise ValueError("%s not in N_{(%s^%s)}(B)" % (prev_nu, p, t - 1)) generators = self.find_monic_replacements(p, t, pt_generators, prev_nu) @@ -502,7 +497,7 @@ def current_nu(self, p, t, pt_generators, prev_nu): # find nu while heap: deg_f, f = heapq.heappop(heap) - #take first element in generators not equal g + # take first element in generators not equal g r = (f.quo_rem(g)[1]) % p**t if r != 0: for h in self.find_monic_replacements(p, t, [r], prev_nu): @@ -558,15 +553,11 @@ def mccoy_column(self, p, t, nu): ValueError: x^2 + x not in (2^2)-ideal """ if not (nu(self._B) % p**t).is_zero(): - raise ValueError( - "%s not in (%s^%s)-ideal" % (nu, p, t)) + raise ValueError("%s not in (%s^%s)-ideal" % (nu, p, t)) - column = matrix(self._DX, self._A.ncols(), 1, - [nu] + [(nu*b).quo_rem(self.chi_B)[0] - for b in self._A[:, 0].list()]) + column = matrix(self._DX, self._A.ncols(), 1, [nu] + [(nu * b).quo_rem(self.chi_B)[0] for b in self._A[:, 0].list()]) - assert (self._A * column % p**t).is_zero(),\ - "McCoy column incorrect" + assert (self._A * column % p**t).is_zero(), "McCoy column incorrect" return column @@ -780,7 +771,7 @@ def p_minimal_polynomials(self, p, s_max=None): if nu.degree() == deg_prev_nu: G = G.delete_columns([G.ncols() - 1]) - del p_min_polys[t-1] + del p_min_polys[t - 1] column = self.mccoy_column(p, t, nu) verbose("corresponding columns for G") @@ -792,8 +783,7 @@ def p_minimal_polynomials(self, p, s_max=None): self._cache[p] = (t, G, p_min_polys) if s_max < t: - result = {r: polynomial - for r, polynomial in p_min_polys.items() if r < s_max} + result = {r: polynomial for r, polynomial in p_min_polys.items() if r < s_max} next_t_candidates = [r for r in p_min_polys if r >= s_max] if next_t_candidates: next_t = min(next_t_candidates) @@ -845,16 +835,14 @@ def null_ideal(self, b=0): if b == 0: mu_B_coefficients = [1] else: - for (p, t) in factor(b): + for p, t in factor(b): cofactor = b // p**t p_polynomials = self.p_minimal_polynomials(p, t) - generators += [cofactor*p**(t-s)*nu - for s, nu in p_polynomials.items()] + generators += [cofactor * p ** (t - s) * nu for s, nu in p_polynomials.items()] if not p_polynomials or max(p_polynomials) < t: mu_B_coefficients.append(cofactor) - assert all((g(self._B) % b).is_zero() for g in generators), \ - "Polynomials not in %s-ideal" % (b,) + assert all((g(self._B) % b).is_zero() for g in generators), "Polynomials not in %s-ideal" % (b,) if mu_B_coefficients: (mu_B_coefficient,) = self._D.ideal(mu_B_coefficients).gens() @@ -919,7 +907,4 @@ def integer_valued_polynomials_generators(self): sage: C.integer_valued_polynomials_generators() (x^3 + x^2 - 12*x - 20, [1, 1/4*x^2 + 3/4*x + 1/2]) """ - return (self.mu_B, [self._DX(1)] + - [nu / p**s - for p in self.prime_candidates() - for s, nu in self.p_minimal_polynomials(p).items()]) + return (self.mu_B, [self._DX(1)] + [nu / p**s for p in self.prime_candidates() for s, nu in self.p_minimal_polynomials(p).items()]) diff --git a/src/sage/matrix/matrix_integer_dense_hnf.py b/src/sage/matrix/matrix_integer_dense_hnf.py index 7b589693be8..c16b235a6ab 100644 --- a/src/sage/matrix/matrix_integer_dense_hnf.py +++ b/src/sage/matrix/matrix_integer_dense_hnf.py @@ -43,8 +43,7 @@ def max_det_prime(n): return Integer(8388593) -def det_from_modp_and_divisor(A, d, p, z_mod, moduli, - z_so_far=ZZ.one(), N_so_far=ZZ.one()): +def det_from_modp_and_divisor(A, d, p, z_mod, moduli, z_so_far=ZZ.one(), N_so_far=ZZ.one()): """ This is used for internal purposes for computing determinants quickly (with the hybrid `p`-adic / multimodular algorithm). @@ -83,7 +82,7 @@ def det_from_modp_and_divisor(A, d, p, z_mod, moduli, z_mod.append(z) moduli.append(p) z = CRT_list([z_so_far, z], [N_so_far, p]) - N = N_so_far*p + N = N_so_far * p if z > N // 2: z -= N @@ -161,13 +160,12 @@ def det_given_divisor(A, d, proof=True, stabilize=2): N_so_far = 1 if proof: N = 1 - B = (2 * 10**A.hadamard_bound()) // d + 1 + B = (2 * 10 ** A.hadamard_bound()) // d + 1 dd = d # bad verbose statement, since computing the log overflows! est = int(RR(B).log() / RR(p).log()) + 1 cnt = 1 - verbose("Multimodular det -- need to use about %s primes." % est, - level=1) + verbose("Multimodular det -- need to use about %s primes." % est, level=1) while N < B: if d % p != 0: tm = cputime() @@ -319,7 +317,7 @@ def add_column_fallback(B, a, proof): tt = verbose('add column fallback...') W = B.augment(matrix(ZZ, B.nrows(), a.list())) H, _ = hnf(W, proof) - C = H.matrix_from_columns([H.ncols()-1]) + C = H.matrix_from_columns([H.ncols() - 1]) verbose('finished add column fallback', tt) return C @@ -359,7 +357,7 @@ def solve_system_with_difficult_last_row(B, a): # by a random very nice row. C = copy(B) while True: - C[C.nrows()-1] = random_matrix(ZZ, 1, C.ncols()).row(0) + C[C.nrows() - 1] = random_matrix(ZZ, 1, C.ncols()).row(0) # 2. Then we find the unique solution to C * x = a try: x = C.solve_right(a) @@ -370,7 +368,7 @@ def solve_system_with_difficult_last_row(B, a): # 3. We next delete the last row of B and find a basis vector k # for the 1-dimensional kernel. - D = B.matrix_from_rows(range(C.nrows()-1)) + D = B.matrix_from_rows(range(C.nrows() - 1)) N = D._rational_kernel_iml() if N.ncols() != 1: verbose("Try difficult solve again with different random vector") @@ -396,7 +394,7 @@ def solve_system_with_difficult_last_row(B, a): w = B[-1] # last row of B a_prime = a[-1] - lhs = w*k + lhs = w * k rhs = a_prime - w * x if lhs[0] == 0: @@ -404,7 +402,7 @@ def solve_system_with_difficult_last_row(B, a): return solve_system_with_difficult_last_row(B, a) alpha = rhs[0] / lhs[0] - z = x + alpha*k + z = x + alpha * k return z @@ -564,10 +562,10 @@ def hnf_square(A, proof): raise ValueError("matrix must have full rank") t = verbose("starting slicings") - B = A.matrix_from_rows(range(m-2)).matrix_from_columns(range(n-1)) - c = A.matrix_from_rows([m-2]).matrix_from_columns(range(n-1)) - d = A.matrix_from_rows([m-1]).matrix_from_columns(range(n-1)) - b = A.matrix_from_columns([n-1]).matrix_from_rows(range(m-2)) + B = A.matrix_from_rows(range(m - 2)).matrix_from_columns(range(n - 1)) + c = A.matrix_from_rows([m - 2]).matrix_from_columns(range(n - 1)) + d = A.matrix_from_rows([m - 1]).matrix_from_columns(range(n - 1)) + b = A.matrix_from_columns([n - 1]).matrix_from_rows(range(m - 2)) verbose("done slicing", t) try: @@ -592,7 +590,7 @@ def hnf_square(A, proof): # A nasty example is A = n*random_matrix(ZZ,m), where # this algorithm gets killed. This is not random input though. f = W.gcd() - g = g / (f**W.nrows()) + g = g / (f ** W.nrows()) if 2 * g <= CUTOFF: verbose("Found common factor of %s -- dividing out; get new g = %s" % (f, g)) W0 = (W / f).change_ring(ZZ) @@ -611,16 +609,12 @@ def hnf_square(A, proof): else: H = W._hnf_mod(2 * g) - x = add_column(W, H, b.stack(matrix(1, 1, - [k*A[m-2, m-1] + l*A[m-1, m-1]])), - proof) + x = add_column(W, H, b.stack(matrix(1, 1, [k * A[m - 2, m - 1] + l * A[m - 1, m - 1]])), proof) Hprime = H.augment(x) pivots = pivots_of_hnf_matrix(Hprime) - Hprime, pivots = add_row(Hprime, A.matrix_from_rows([m - 2]), - pivots, include_zero_rows=False) - Hprime, pivots = add_row(Hprime, A.matrix_from_rows([m - 1]), - pivots, include_zero_rows=False) + Hprime, pivots = add_row(Hprime, A.matrix_from_rows([m - 2]), pivots, include_zero_rows=False) + Hprime, pivots = add_row(Hprime, A.matrix_from_rows([m - 1]), pivots, include_zero_rows=False) return Hprime.matrix_from_rows(range(m)) @@ -742,7 +736,7 @@ def ones(H, pivots) -> tuple[list, list, list, list]: onerow.append(i) onecol_set = set(onecol) non_onerow = [j for j in range(len(pivots)) if j not in onerow] - non_onecol = [j for j in range(H.ncols()) if j not in onecol_set][:len(non_onerow)] + non_onecol = [j for j in range(H.ncols()) if j not in onecol_set][: len(non_onerow)] return onecol, onerow, non_onecol, non_onerow @@ -798,7 +792,7 @@ def extract_ones_data(H, pivots): D = H.matrix_from_rows_and_columns(non_onerow, non_onecol).transpose() tt = verbose("extract ones -- INVERT %s x %s" % (len(non_onerow), len(non_onecol)), level=1) try: - E = D**(-1) + E = D ** (-1) except ZeroDivisionError: C = D = E = None verbose("done inverting", tt, level=1) @@ -972,8 +966,7 @@ def probable_hnf(A, include_zero_rows, proof) -> tuple: else: z = A.matrix_from_rows_and_columns([i], non_onecol) w = A.matrix_from_rows_and_columns([i], onecol) - tt = verbose("checking denom (%s x %s)" % (D.nrows(), - D.ncols())) + tt = verbose("checking denom (%s x %s)" % (D.nrows(), D.ncols())) Y = (z - w * C).transpose() k = E * Y verbose("done checking denom", tt) @@ -1080,15 +1073,13 @@ def hnf(A, include_zero_rows=True, proof=True): return A, pivots if not proof: - H, pivots = probable_hnf(A, include_zero_rows=include_zero_rows, - proof=False) + H, pivots = probable_hnf(A, include_zero_rows=include_zero_rows, proof=False) if not include_zero_rows and len(pivots) > H.nrows(): return H.matrix_from_rows(range(len(pivots))), pivots while True: try: - H, pivots = probable_hnf(A, include_zero_rows=include_zero_rows, - proof=True) + H, pivots = probable_hnf(A, include_zero_rows=include_zero_rows, proof=True) except ValueError: verbose("The attempt failed since the pivots must have been wrong. We try again.") continue @@ -1196,6 +1187,7 @@ def benchmark_magma_hnf(nrange, bits=4): ('magma', 100, 32, ...), """ from sage.interfaces.magma import magma + b = 2**bits for n in nrange: a = magma('MatrixAlgebra(IntegerRing(),%s)![Random(%s,%s) : i in [1..%s]]' % (n, -b, b, n**2)) @@ -1205,8 +1197,7 @@ def benchmark_magma_hnf(nrange, bits=4): print('%s,' % (('magma', n, bits, tm),)) -def sanity_checks(times=50, n=8, m=5, proof=True, stabilize=2, - check_using_magma=True): +def sanity_checks(times=50, n=8, m=5, proof=True, stabilize=2, check_using_magma=True): """ Run random sanity checks on the modular `p`-adic HNF with tall and wide matrices both dense and sparse. @@ -1258,27 +1249,24 @@ def __do_check(v): if check_using_magma: if magma(hnf(a)[0]) != magma(a).EchelonForm(): print("bug computing hnf of a matrix") - print('a = matrix(ZZ, %s, %s, %s)' % (a.nrows(), a.ncols(), - a.list())) + print('a = matrix(ZZ, %s, %s, %s)' % (a.nrows(), a.ncols(), a.list())) return else: if hnf(a)[0] != a.echelon_form(algorithm='pari'): print("bug computing hnf of a matrix") - print('a = matrix(ZZ, %s, %s, %s)' % (a.nrows(), a.ncols(), - a.list())) + print('a = matrix(ZZ, %s, %s, %s)' % (a.nrows(), a.ncols(), a.list())) return print(" (done)") + print("small %s x %s" % (n, m)) __do_check([random_matrix(ZZ, n, m, x=-1, y=1) for _ in range(times)]) print("big %s x %s" % (n, m)) - __do_check([random_matrix(ZZ, n, m, x=-2**32, y=2**32) - for _ in range(times)]) + __do_check([random_matrix(ZZ, n, m, x=-(2**32), y=2**32) for _ in range(times)]) print("small %s x %s" % (m, n)) __do_check([random_matrix(ZZ, m, n, x=-1, y=1) for _ in range(times)]) print("big %s x %s" % (m, n)) - __do_check([random_matrix(ZZ, m, n, x=-2**32, y=2**32) - for _ in range(times)]) + __do_check([random_matrix(ZZ, m, n, x=-(2**32), y=2**32) for _ in range(times)]) print("sparse %s x %s" % (n, m)) __do_check([random_matrix(ZZ, n, m, density=0.1) for _ in range(times)]) @@ -1286,7 +1274,7 @@ def __do_check(v): __do_check([random_matrix(ZZ, m, n, density=0.1) for _ in range(times)]) print("ill conditioned -- 1000*A -- %s x %s" % (n, m)) - __do_check([1000*random_matrix(ZZ, n, m, x=-1, y=1) for _ in range(times)]) + __do_check([1000 * random_matrix(ZZ, n, m, x=-1, y=1) for _ in range(times)]) print("ill conditioned -- 1000*A but one row -- %s x %s" % (n, m)) v = [] diff --git a/src/sage/matrix/matrix_integer_dense_saturation.py b/src/sage/matrix/matrix_integer_dense_saturation.py index a0e7a3edfe0..92f570105ad 100644 --- a/src/sage/matrix/matrix_integer_dense_saturation.py +++ b/src/sage/matrix/matrix_integer_dense_saturation.py @@ -1,6 +1,7 @@ """ Saturation over ZZ """ + from copy import copy from sage.arith.misc import binomial, GCD as gcd @@ -145,14 +146,14 @@ def solve_system_with_difficult_last_row(B, A): # This function is just a generalization of that one to A a matrix. C = copy(B) while True: - C[C.nrows()-1] = random_matrix(ZZ, 1, C.ncols()).row(0) + C[C.nrows() - 1] = random_matrix(ZZ, 1, C.ncols()).row(0) try: X = C.solve_right(A) except ValueError: verbose("Try difficult solve again with different random vector") else: break - D = B.matrix_from_rows(range(C.nrows()-1)) + D = B.matrix_from_rows(range(C.nrows() - 1)) N = D._rational_kernel_flint() if N.ncols() != 1: verbose("Difficult solve quickly failed. Using direct approach.") @@ -171,7 +172,7 @@ def solve_system_with_difficult_last_row(B, A): # so alpha*w*k = A' - w*X. w = B[-1] # last row of B A_prime = A[-1] # last row of A - lhs = w*k + lhs = w * k rhs = A_prime - w * X if lhs[0] == 0: @@ -180,7 +181,7 @@ def solve_system_with_difficult_last_row(B, A): for i in range(X.ncols()): alpha = rhs[i] / lhs[0] - X.set_column(i, (X.matrix_from_columns([i]) + alpha*k).list()) + X.set_column(i, (X.matrix_from_columns([i]) + alpha * k).list()) verbose("Done getting linear combinations.", tm) return X diff --git a/src/sage/matrix/matrix_misc.py b/src/sage/matrix/matrix_misc.py index a539f22ddff..870e347f556 100644 --- a/src/sage/matrix/matrix_misc.py +++ b/src/sage/matrix/matrix_misc.py @@ -18,6 +18,7 @@ # **************************************************************************** from sage.categories.fields import Fields + _Fields = Fields() @@ -283,7 +284,7 @@ def permanental_minor_polynomial(A, permanent_only=False, var='t', prec=None): p1 = {} else: p1 = {0: K.one()} - a = A[i] # the i-th row of A + a = A[i] # the i-th row of A for j in range(len(a)): if a[j]: p1[1 << j] = a[j] * t @@ -294,7 +295,7 @@ def permanental_minor_polynomial(A, permanent_only=False, var='t', prec=None): j = 0 while j < len(vars_to_do): jj = vars_to_do[j] - if all(A[k][jj] == 0 for k in range(i+1, nrows)): + if all(A[k][jj] == 0 for k in range(i + 1, nrows)): mask_free += 1 << jj vars_to_do.remove(jj) else: @@ -305,8 +306,7 @@ def permanental_minor_polynomial(A, permanent_only=False, var='t', prec=None): return K.zero() if len(p) != 1 or 0 not in p: - raise RuntimeError("Something is wrong! Certainly a problem in the" - " algorithm... please contact sage-devel@googlegroups.com") + raise RuntimeError("Something is wrong! Certainly a problem in the" " algorithm... please contact sage-devel@googlegroups.com") p = p[0] return p[min(nrows, ncols)] if permanent_only else p diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index eed90d1a77a..c362caab6f5 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -57,8 +57,8 @@ from sage.misc.lazy_import import lazy_import from sage.features.meataxe import Meataxe -lazy_import('sage.matrix.matrix_gfpn_dense', ['Matrix_gfpn_dense'], - feature=Meataxe()) + +lazy_import('sage.matrix.matrix_gfpn_dense', ['Matrix_gfpn_dense'], feature=Meataxe()) lazy_import('sage.groups.matrix_gps.matrix_group', ['MatrixGroup_base']) _Semirings = Semirings() @@ -228,6 +228,7 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): if (not R.is_prime_field()) and R.order() < 256: try: from . import matrix_gfpn_dense + return matrix_gfpn_dense.Matrix_gfpn_dense except ImportError: pass @@ -245,6 +246,7 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): if isinstance(R, sage.rings.abc.NumberField_cyclotomic): from . import matrix_cyclo_dense + return matrix_cyclo_dense.Matrix_cyclo_dense try: @@ -303,19 +305,23 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): else: if isinstance(R, TropicalSemiring): from sage.rings.semirings import tropical_matrix + return tropical_matrix.Matrix_tropical_dense # The fallback from sage.matrix.matrix_generic_dense import Matrix_generic_dense + return Matrix_generic_dense # Deal with request for a specific implementation if implementation == 'flint': if R is sage.rings.integer_ring.ZZ: from . import matrix_integer_dense + return matrix_integer_dense.Matrix_integer_dense if R is sage.rings.rational_field.QQ: from . import matrix_rational_dense + return matrix_rational_dense.Matrix_rational_dense raise ValueError("'flint' matrices are only available over the integers or the rationals") @@ -323,8 +329,10 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): if R.is_field() and R.characteristic() == 2 and R.order() <= 65536: if R.order() == 2: from . import matrix_mod2_dense + return matrix_mod2_dense.Matrix_mod2_dense from . import matrix_gf2e_dense + return matrix_gf2e_dense.Matrix_gf2e_dense raise ValueError("'m4ri' matrices are only available for fields of characteristic 2 and order <= 65536") @@ -336,39 +344,47 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): if implementation == 'numpy': if R is sage.rings.real_double.RDF: from . import matrix_real_double_dense + return matrix_real_double_dense.Matrix_real_double_dense if R is sage.rings.complex_double.CDF: from . import matrix_complex_double_dense + return matrix_complex_double_dense.Matrix_complex_double_dense if R is sage.rings.integer_ring.ZZ: from . import matrix_numpy_integer_dense + return matrix_numpy_integer_dense.Matrix_numpy_integer_dense raise ValueError("'numpy' matrices are only available over RDF, CDF, and ZZ") if implementation == 'rational': if isinstance(R, sage.rings.abc.NumberField_cyclotomic): from . import matrix_cyclo_dense + return matrix_cyclo_dense.Matrix_cyclo_dense raise ValueError("'rational' matrices are only available over a cyclotomic field") if implementation == 'linbox-float': from . import matrix_modn_dense_float + if R.order() < matrix_modn_dense_float.MAX_MODULUS: return matrix_modn_dense_float.Matrix_modn_dense_float raise ValueError("'linbox-float' matrices can only deal with order < %s" % matrix_modn_dense_float.MAX_MODULUS) if implementation == 'linbox-double': from . import matrix_modn_dense_double + if R.order() < matrix_modn_dense_double.MAX_MODULUS: return matrix_modn_dense_double.Matrix_modn_dense_double raise ValueError("'linbox-double' matrices can only deal with order < %s" % matrix_modn_dense_double.MAX_MODULUS) if implementation == 'generic': from sage.matrix.matrix_generic_dense import Matrix_generic_dense + return Matrix_generic_dense if implementation == 'gap': from sage.matrix.matrix_gap import Matrix_gap + return Matrix_gap raise ValueError("unknown matrix implementation %r over %r" % (implementation, R)) @@ -404,6 +420,7 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): if isinstance(R, (sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField)): from . import matrix_double_sparse + return matrix_double_sparse.Matrix_double_sparse try: from sage.symbolic.ring import SR @@ -420,6 +437,7 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): # the fallback from sage.matrix.matrix_generic_sparse import Matrix_generic_sparse + return Matrix_generic_sparse @@ -658,12 +676,7 @@ class MatrixSpace(UniqueRepresentation, Parent): """ @staticmethod - def __classcall__(cls, base_ring, - nrows_or_row_keys=None, ncols_or_column_keys=None, - sparse=False, implementation=None, *, - nrows=None, ncols=None, - row_keys=None, column_keys=None, - **kwds): + def __classcall__(cls, base_ring, nrows_or_row_keys=None, ncols_or_column_keys=None, sparse=False, implementation=None, *, nrows=None, ncols=None, row_keys=None, column_keys=None, **kwds): """ Normalize the arguments to call the ``__init__`` constructor or delegate to another class. @@ -723,8 +736,7 @@ def __classcall__(cls, base_ring, raise ValueError("duplicate values for ncols") ncols = n if column_keys is not None and ncols is not None and ncols != len(column_keys): - raise ValueError(f"inconsistent number of columns: should be cardinality of {column_keys} " - f"but got {ncols}") + raise ValueError(f"inconsistent number of columns: should be cardinality of {column_keys} " f"but got {ncols}") if nrows_or_row_keys is not None: try: @@ -738,8 +750,7 @@ def __classcall__(cls, base_ring, raise ValueError("duplicate values for nrows") nrows = n if row_keys is not None and nrows is not None and nrows != len(row_keys): - raise ValueError(f"inconsistent number of rows: should be cardinality of {row_keys} " - f"but got {nrows}") + raise ValueError(f"inconsistent number of rows: should be cardinality of {row_keys} " f"but got {nrows}") if ncols is None and column_keys is None: ncols = nrows @@ -751,10 +762,8 @@ def __classcall__(cls, base_ring, from sage.categories.homset import Hom from sage.modules.free_module import FreeModule - domain = FreeModule(base_ring, rank=ncols, basis_keys=column_keys, - sparse=sparse, **kwds) - codomain = FreeModule(base_ring, rank=nrows, basis_keys=row_keys, - sparse=sparse, **kwds) + domain = FreeModule(base_ring, rank=ncols, basis_keys=column_keys, sparse=sparse, **kwds) + codomain = FreeModule(base_ring, rank=nrows, basis_keys=row_keys, sparse=sparse, **kwds) return Hom(domain, codomain) if nrows < 0: @@ -765,8 +774,7 @@ def __classcall__(cls, base_ring, raise OverflowError("number of rows and columns may be at most %s" % sys.maxsize) matrix_cls = get_matrix_class(base_ring, nrows, ncols, sparse, implementation) - return super().__classcall__(cls, base_ring, nrows, - ncols, sparse, matrix_cls, **kwds) + return super().__classcall__(cls, base_ring, nrows, ncols, sparse, matrix_cls, **kwds) def __init__(self, base_ring, nrows, ncols, sparse, implementation) -> None: r""" @@ -881,6 +889,7 @@ def __init__(self, base_ring, nrows, ncols, sparse, implementation) -> None: from sage.categories.modules import Modules from sage.categories.algebras import Algebras + if base_ring in Rings(): if nrows == ncols: category = Algebras(base_ring.category()) @@ -926,6 +935,7 @@ def cardinality(self): """ if not self.__nrows or not self.__ncols: from sage.rings.integer_ring import ZZ + return ZZ.one() return self.base_ring().cardinality() ** (self.__nrows * self.__ncols) @@ -991,8 +1001,7 @@ def transposed(self): sage: M.transposed Full MatrixSpace of 3 by 2 dense matrices over Integer Ring """ - return MatrixSpace(self._base, self.__ncols, self.__nrows, - self.__is_sparse, self.Element) + return MatrixSpace(self._base, self.__ncols, self.__nrows, self.__is_sparse, self.Element) @lazy_attribute def _copy_zero(self): @@ -1217,6 +1226,7 @@ def construction(self): Full MatrixSpace of 2 by 2 sparse matrices over Rational Field """ from sage.categories.pushout import MatrixFunctor + return MatrixFunctor(self.__nrows, self.__ncols, is_sparse=self.is_sparse()), self.base_ring() def _get_action_(self, S, op, self_on_left): @@ -1267,6 +1277,7 @@ def _get_action_(self, S, op, self_on_left): SchemeHomset_generic = SchemeHomset_points = None if op is operator.mul: from . import action as matrix_action + if self_on_left: if isinstance(S, MatrixSpace): # matrix multiplications @@ -1489,8 +1500,7 @@ def _repr_(self): s = "sparse" else: s = "dense" - s = "Full MatrixSpace of %s by %s %s matrices over %s" % ( - self.__nrows, self.__ncols, s, self.base_ring()) + s = "Full MatrixSpace of %s by %s %s matrices over %s" % (self.__nrows, self.__ncols, s, self.base_ring()) if not self._has_default_implementation(): s += " (using {})".format(self.Element.__name__) @@ -1523,8 +1533,7 @@ def _latex_(self): sage: latex(MS3) \mathrm{Mat}_{6\times 6}(\Bold{Q}) """ - return "\\mathrm{Mat}_{%s\\times %s}(%s)" % (self.nrows(), self.ncols(), - latex.latex(self.base_ring())) + return "\\mathrm{Mat}_{%s\\times %s}(%s)" % (self.nrows(), self.ncols(), latex.latex(self.base_ring())) def __len__(self): """ @@ -1552,7 +1561,7 @@ def __len__(self): ... TypeError: len() of unsized object """ - return len(self.base_ring())**(self.nrows() * self.ncols()) + return len(self.base_ring()) ** (self.nrows() * self.ncols()) def __iter__(self): r""" @@ -1736,7 +1745,7 @@ def __iter__(self): base_ring = self.base_ring() base_iter = iter(base_ring) - number_of_entries = (self.__nrows * self.__ncols) + number_of_entries = self.__nrows * self.__ncols # If the number of entries is zero, then just # yield the empty matrix in that case and return @@ -1831,9 +1840,7 @@ def basis(self): [0 0], [0 0], [1 0], [0 1] ] """ - v = {(r, c): self.zero_matrix().__copy__() - for r in range(self.__nrows) - for c in range(self.__ncols)} + v = {(r, c): self.zero_matrix().__copy__() for r in range(self.__nrows) for c in range(self.__ncols)} one = self.base_ring().one() keys = [] for r in range(self.__nrows): @@ -1842,6 +1849,7 @@ def basis(self): v[r, c][r, c] = one v[r, c].set_immutable() from sage.sets.family import Family + return Family(keys, v.__getitem__) def dimension(self): @@ -1869,9 +1877,7 @@ def dims(self): """ return (self.__nrows, self.__ncols) - def submodule(self, gens, check=True, already_echelonized=False, - unitriangular=False, support_order=None, category=None, - *args, **opts): + def submodule(self, gens, check=True, already_echelonized=False, unitriangular=False, support_order=None, category=None, *args, **opts): r""" The submodule spanned by a finite set of matrices. @@ -1948,6 +1954,7 @@ def submodule(self, gens, check=True, already_echelonized=False, gens = self.echelon_form(gens, unitriangular, order=support_order) else: from copy import copy + # We will be making gens immutable, so copy the mutable matrices gens = [copy(g) if g.is_mutable() else g for g in gens] @@ -1956,10 +1963,8 @@ def submodule(self, gens, check=True, already_echelonized=False, g.set_immutable() from sage.modules.with_basis.subquotient import SubmoduleWithBasis - return SubmoduleWithBasis(gens, ambient=self, - support_order=support_order, - unitriangular=unitriangular, - category=category, *args, **opts) + + return SubmoduleWithBasis(gens, ambient=self, support_order=support_order, unitriangular=unitriangular, category=category, *args, **opts) from sage.misc.cachefunc import cached_method @@ -2372,8 +2377,7 @@ def row_space(self): try: return self.__row_space except AttributeError: - self.__row_space = sage.modules.free_module.FreeModule(self.base_ring(), - self.ncols(), sparse=self.is_sparse()) + self.__row_space = sage.modules.free_module.FreeModule(self.base_ring(), self.ncols(), sparse=self.is_sparse()) return self.__row_space def column_space(self): @@ -2390,8 +2394,7 @@ def column_space(self): try: return self.__column_space except AttributeError: - self.__column_space = sage.modules.free_module.FreeModule(self.base_ring(), self.nrows(), - sparse=self.is_sparse()) + self.__column_space = sage.modules.free_module.FreeModule(self.base_ring(), self.nrows(), sparse=self.is_sparse()) return self.__column_space def random_element(self, density=None, *args, **kwds): @@ -2446,11 +2449,9 @@ def random_element(self, density=None, *args, **kwds): """ Z = self.zero_matrix().__copy__() if density is None: - Z.randomize(density=float(1), nonzero=kwds.pop('nonzero', False), - *args, **kwds) + Z.randomize(density=float(1), nonzero=kwds.pop('nonzero', False), *args, **kwds) else: - Z.randomize(density=density, nonzero=kwds.pop('nonzero', True), - *args, **kwds) + Z.randomize(density=density, nonzero=kwds.pop('nonzero', True), *args, **kwds) return Z def _an_element_(self): @@ -2485,6 +2486,7 @@ def _an_element_(self): True """ from .args import MatrixArgs + dim = self.dimension() if dim > 100 and self.is_sparse(): # Sparse case: add 100 elements @@ -2492,6 +2494,7 @@ def _an_element_(self): nr = self.nrows() nc = self.ncols() from random import randrange + n = 0 while True: for el in self.base().some_elements(): @@ -2578,6 +2581,7 @@ def _polymake_init_(self): Matrix """ from sage.interfaces.polymake import polymake + K = polymake(self.base_ring()) return '"Matrix<{}>"'.format(K) @@ -2752,8 +2756,7 @@ def _test_trivial_matrices_inverse(ring, sparse=True, implementation=None, check # Check that the empty 0x3 and 3x0 matrices are not invertible and that # computing the determinant raise the proper exception. - for ms0 in [MatrixSpace(ring, 0, 3, sparse=sparse), - MatrixSpace(ring, 3, 0, sparse=sparse)]: + for ms0 in [MatrixSpace(ring, 0, 3, sparse=sparse), MatrixSpace(ring, 3, 0, sparse=sparse)]: mn0 = ms0(0) assert not mn0.is_invertible() try: @@ -2805,17 +2808,13 @@ def _test_trivial_matrices_inverse(ring, sparse=True, implementation=None, check def _MatrixSpace_ZZ_2x2(): from sage.rings.integer_ring import ZZ + return MatrixSpace(ZZ, 2) -register_unpickle_override('sage.matrix.matrix_modn_dense', - 'Matrix_modn_dense', Matrix_modn_dense_double) -register_unpickle_override('sage.matrix.matrix_integer_2x2', - 'Matrix_integer_2x2', Matrix_integer_dense) -register_unpickle_override('sage.matrix.matrix_integer_2x2', - 'MatrixSpace_ZZ_2x2_class', MatrixSpace) -register_unpickle_override('sage.matrix.matrix_integer_2x2', - 'MatrixSpace_ZZ_2x2', _MatrixSpace_ZZ_2x2) +register_unpickle_override('sage.matrix.matrix_modn_dense', 'Matrix_modn_dense', Matrix_modn_dense_double) +register_unpickle_override('sage.matrix.matrix_integer_2x2', 'Matrix_integer_2x2', Matrix_integer_dense) +register_unpickle_override('sage.matrix.matrix_integer_2x2', 'MatrixSpace_ZZ_2x2_class', MatrixSpace) +register_unpickle_override('sage.matrix.matrix_integer_2x2', 'MatrixSpace_ZZ_2x2', _MatrixSpace_ZZ_2x2) lazy_import('sage.matrix.matrix_gf2e_dense', 'unpickle_matrix_gf2e_dense_v0') -register_unpickle_override('sage.matrix.matrix_mod2e_dense', - 'unpickle_matrix_mod2e_dense_v0', unpickle_matrix_gf2e_dense_v0) +register_unpickle_override('sage.matrix.matrix_mod2e_dense', 'unpickle_matrix_mod2e_dense_v0', unpickle_matrix_gf2e_dense_v0) diff --git a/src/sage/matrix/operation_table.py b/src/sage/matrix/operation_table.py index 6dc925dceee..c4232825937 100644 --- a/src/sage/matrix/operation_table.py +++ b/src/sage/matrix/operation_table.py @@ -417,7 +417,7 @@ def __init__(self, S, operation, names='letters', elements=None, closed=True): # Determine the elements of S, specified or not # If elements are given, we check if they are all in S # Note: there exist listable infinite objects (like ZZ) - if (elements is None): + if elements is None: if hasattr(S, 'is_finite'): if not S.is_finite(): raise ValueError('%s is infinite' % S) @@ -441,7 +441,7 @@ def __init__(self, S, operation, names='letters', elements=None, closed=True): self._n = len(self._elts) self._name_dict = {} self._closed = closed - self._elts_ext = [] # elements that are not in _elts + self._elts_ext = [] # elements that are not in _elts self._n_ext = 0 # Determine the operation, if given by a string @@ -451,10 +451,8 @@ def __init__(self, S, operation, names='letters', elements=None, closed=True): # ascii-symbol must be exactly one character wide # Note double-backslash to escape properly for latex from operator import add, mul - supported = { - add: (add, '+', '+'), - mul: (mul, '*', '\\ast') - } + + supported = {add: (add, '+', '+'), mul: (mul, '*', '\\ast')} # default symbols for upper-left-hand-corner of table self._ascii_symbol = '.' self._latex_symbol = '\\cdot' @@ -483,8 +481,7 @@ def __init__(self, S, operation, names='letters', elements=None, closed=True): try: result = self._operation(g, h) except Exception: - raise TypeError('elements %s and %s of %s are incompatible with operation: %s' % ( - g, h, S, self._operation)) + raise TypeError('elements %s and %s of %s are incompatible with operation: %s' % (g, h, S, self._operation)) try: r = get_row(result) @@ -510,8 +507,7 @@ def __init__(self, S, operation, names='letters', elements=None, closed=True): except Exception: raise TypeError('unable to coerce %s into %s' % (result, S)) else: - raise ValueError('%s%s%s=%s, and so the set is not closed. You may try "closed=False".' % ( - g, self._ascii_symbol, h, result)) + raise ValueError('%s%s%s=%s, and so the set is not closed. You may try "closed=False".' % (g, self._ascii_symbol, h, result)) row.append(r) self._table.append(row) @@ -583,6 +579,7 @@ def _name_maker(self, names): ValueError: element names must be a list, or one of the keywords: 'letters', 'digits', 'elements' """ from math import log, log10 + name_list = [] name_list_ext = [] if names == 'digits': @@ -597,13 +594,14 @@ def _name_maker(self, names): elif names == 'letters': from string import ascii_lowercase as letters from sage.rings.integer import Integer + base = len(letters) if self._n + self._n_ext <= 1: width = 1 else: width = int(log(self._n + self._n_ext - 1, base)) + 1 for i in range(self._n): - places = Integer(i).digits( base=base, digits=letters, padto=width) + places = Integer(i).digits(base=base, digits=letters, padto=width) places.reverse() name_list.append(''.join(places)) for i in range(self._n_ext): @@ -624,18 +622,15 @@ def _name_maker(self, names): if names is not None and not self._closed: raise ValueError('custom names cannot be used together with closed=False') if len(names) != self._n: - raise ValueError('list of element names must be the same size as the set, %s != %s' % ( - len(names), self._n)) + raise ValueError('list of element names must be the same size as the set, %s != %s' % (len(names), self._n)) width = 0 for name in names: if not isinstance(name, str): - raise ValueError( - 'list of element names must only contain strings, not %s' % name) + raise ValueError('list of element names must only contain strings, not %s' % name) width = max(len(name), width) name_list.append(name) else: - raise ValueError( - "element names must be a list, or one of the keywords: 'letters', 'digits', 'elements'") + raise ValueError("element names must be a list, or one of the keywords: 'letters', 'digits', 'elements'") name_dict = {} for i in range(self._n): name_dict[name_list[i]] = self._elts[i] @@ -692,15 +687,13 @@ def __getitem__(self, pair): IndexError: invalid indices of operation table: ((1,512), (1,3,2,4)(5,7)) """ if not (isinstance(pair, tuple) and len(pair) == 2): - raise TypeError( - 'indexing into an operation table requires exactly two elements') + raise TypeError('indexing into an operation table requires exactly two elements') g, h = pair try: row = self._elts.index(g) col = self._elts.index(h) except ValueError: - raise IndexError( - 'invalid indices of operation table: (%s, %s)' % (g, h)) + raise IndexError('invalid indices of operation table: (%s, %s)' % (g, h)) r = self._table[row][col] return self._elts[r] if r < self._n else self._elts_ext[r - self._n] @@ -728,8 +721,7 @@ def __eq__(self, other): sage: P == P, P == Q, P == R, P == S (True, True, False, False) """ - return ((self._elts == other._elts) and (self._elts_ext == other._elts_ext) and - (self._operation == other._operation)) + return (self._elts == other._elts) and (self._elts_ext == other._elts_ext) and (self._operation == other._operation) def __ne__(self, other): """ @@ -813,8 +805,7 @@ def set_print_symbols(self, ascii, latex): ValueError: ASCII symbol should be a single character, not 5 """ if not isinstance(ascii, str) or not len(ascii) == 1: - raise ValueError( - 'ASCII symbol should be a single character, not %s' % ascii) + raise ValueError('ASCII symbol should be a single character, not %s' % ascii) if not isinstance(latex, str): raise ValueError('LaTeX symbol must be a string, not %s' % latex) self._ascii_symbol = ascii @@ -999,10 +990,10 @@ def matrix_of_variables(self): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.matrix.matrix_space import MatrixSpace from sage.rings.rational_field import QQ + R = PolynomialRing(QQ, 'x', self._n) MS = MatrixSpace(R, self._n, self._n) - entries = [R('x'+str(self._table[i][j])) - for i in range(self._n) for j in range(self._n)] + entries = [R('x' + str(self._table[i][j])) for i in range(self._n) for j in range(self._n)] return MS(entries) def color_table(self, element_names=True, cmap=None, **options): @@ -1038,8 +1029,7 @@ def color_table(self, element_names=True, cmap=None, **options): from matplotlib.cm import gist_rainbow as cmap # Base matrix plot object, without text - plot = matrix_plot(Matrix(self._table), cmap=cmap, - frame=False, **options) + plot = matrix_plot(Matrix(self._table), cmap=cmap, frame=False, **options) if element_names: @@ -1063,6 +1053,7 @@ def color_table(self, element_names=True, cmap=None, **options): # https://moyix.blogspot.com/2022/09/someones-been-messing-with-my-subnormals.html import warnings + warnings.filterwarnings("ignore", message="The value of the smallest subnormal for") return plot @@ -1092,6 +1083,7 @@ def gray_table(self, **options): sphinx_plot(OTa.gray_table(), figsize=(3.0, 3.0)) """ from matplotlib.cm import Greys + return self.color_table(cmap=Greys, **options) def _ascii_table(self): @@ -1177,18 +1169,18 @@ def _ascii_table(self): # Headers table = ['{0: >{1}s} '.format(self._ascii_symbol, width)] - table += [' '+widenames[i] for i in range(n)]+['\n'] - table += [' ']*width + ['+'] + ['-']*(n*(width+1))+['\n'] + table += [' ' + widenames[i] for i in range(n)] + ['\n'] + table += [' '] * width + ['+'] + ['-'] * (n * (width + 1)) + ['\n'] # Row labels, body of table for g in range(n): - table.append(widenames[g]+'|') + table.append(widenames[g] + '|') for h in range(n): r = self._table[g][h] if r < len(widenames): - table.append(' '+widenames[r]) + table.append(' ' + widenames[r]) elif r < len(widenames_ext): - table.append(' '+widenames_ext[r]) + table.append(' ' + widenames_ext[r]) else: raise ValueError('unknown error') table.append('\n') @@ -1212,9 +1204,9 @@ def _latex_(self): # Headers table = ['{\\setlength{\\arraycolsep}{2ex}\n'] - table.append('\\begin{array}{r|*{'+str(n)+'}{r}}\n') - table.append('\\multicolumn{1}{c|}{'+self._latex_symbol+'}') - table += ['&'+names[i] for i in range(n)] + table.append('\\begin{array}{r|*{' + str(n) + '}{r}}\n') + table.append('\\multicolumn{1}{c|}{' + self._latex_symbol + '}') + table += ['&' + names[i] for i in range(n)] table.append('\\\\\\hline\n') # Row label and body of table @@ -1223,7 +1215,7 @@ def _latex_(self): table.append('{}') table.append(names[g]) for h in range(n): - table.append('&'+names[self._table[g][h]]) + table.append('&' + names[self._table[g][h]]) table.append('\\\\\n') # Finish diff --git a/src/sage/matrix/special.py b/src/sage/matrix/special.py index 93f09f08a61..b103c2b8a55 100644 --- a/src/sage/matrix/special.py +++ b/src/sage/matrix/special.py @@ -115,8 +115,7 @@ def matrix_method(func=None, name=None): if func is not None: if name is None: name = func.__name__.replace('matrix', '').strip('_') - prefix = " This function is available as %s(...) and matrix.%s(...)." % ( - func.__name__, name) + prefix = " This function is available as %s(...) and matrix.%s(...)." % (func.__name__, name) func.__doc__ = "%s\n\n%s" % (prefix, func.__doc__) setattr(matrix, name, func) return func @@ -893,6 +892,7 @@ def diagonal_matrix(arg0=None, arg1=None, arg2=None, sparse=True): # Convert entries to a list v over a common ring from sage.modules.free_module_element import prepare + v, ring = prepare(entries, ring) # Create a "diagonal" dictionary for matrix constructor @@ -974,7 +974,7 @@ def lehmer(ring, n=0): if isinstance(ring, (Integer, int)): n = ring ring = QQ - return matrix_space.MatrixSpace(ring, n, n).matrix([[min(i, j)/max(i, j) for i in IntegerRange(1, n+1)] for j in IntegerRange(1, n+1)]) + return matrix_space.MatrixSpace(ring, n, n).matrix([[min(i, j) / max(i, j) for i in IntegerRange(1, n + 1)] for j in IntegerRange(1, n + 1)]) @matrix_method @@ -1120,9 +1120,9 @@ def ones_matrix(ring, nrows=None, ncols=None, sparse=False): if ncols is None: nents = nrows**2 else: - nents = nrows*ncols + nents = nrows * ncols one = ring(1) - return matrix_space.MatrixSpace(ring, nrows, ncols, sparse).matrix([one]*nents) + return matrix_space.MatrixSpace(ring, nrows, ncols, sparse).matrix([one] * nents) @matrix_method @@ -2078,8 +2078,7 @@ def block_matrix(*args, **kwds): if isinstance(sub_matrices, Matrix): M = sub_matrices # a single matrix (check nrows/ncols/ring) - if (nrows is not None and nrows != 1) or \ - (ncols is not None and ncols != 1): + if (nrows is not None and nrows != 1) or (ncols is not None and ncols != 1): raise ValueError("invalid nrows/ncols passed to block_matrix") if ring is not None: M = M.change_ring(ring) @@ -2096,8 +2095,7 @@ def block_matrix(*args, **kwds): try_grid = True if not sub_matrices: - if (nrows is not None and nrows != 0) or \ - (ncols is not None and ncols != 0): + if (nrows is not None and nrows != 0) or (ncols is not None and ncols != 0): raise ValueError("invalid nrows/ncols passed to block_matrix") elif isinstance(sub_matrices[0], (list, tuple)): # A list of lists: verify all elements are lists, and if @@ -2125,19 +2123,19 @@ def block_matrix(*args, **kwds): if nrows * ncols != n: raise ValueError("given number of rows (%s), columns (%s) incompatible with number of submatrices (%s)" % (nrows, ncols, n)) # Now create a list of lists from this - sub_matrices = [sub_matrices[i * ncols: (i + 1) * ncols] - for i in range(nrows)] + sub_matrices = [sub_matrices[i * ncols : (i + 1) * ncols] for i in range(nrows)] # At this point sub_matrices is a list of lists from sage.structure.coerce import py_scalar_to_element from sage.structure.element import Vector - sub_matrices = [[M.column() if isinstance(M, Vector) else M if isinstance(M, Matrix) else py_scalar_to_element(M) - for M in row] for row in sub_matrices] + + sub_matrices = [[M.column() if isinstance(M, Vector) else M if isinstance(M, Matrix) else py_scalar_to_element(M) for M in row] for row in sub_matrices] # determine the base ring and sparsity if ring is None: from sage.structure.element import get_coercion_model + parents = [M.base_ring() if isinstance(M, Matrix) else parent(M) for row in sub_matrices for M in row] for p in parents: if p not in Rings(): @@ -2212,8 +2210,7 @@ def block_matrix(*args, **kwds): big = matrix(ring, 0, 0) if subdivide: - big.subdivide(running_total(row_heights[:-1]), - running_total(col_widths[:-1])) + big.subdivide(running_total(row_heights[:-1]), running_total(col_widths[:-1])) return big @@ -2251,7 +2248,7 @@ def block_diagonal_matrix(*sub_matrices, **kwds): n = len(sub_matrices) entries = [ZZ.zero()] * n**2 for i in range(n): - entries[n*i+i] = sub_matrices[i] + entries[n * i + i] = sub_matrices[i] return block_matrix(n, n, entries, **kwds) @@ -2463,6 +2460,7 @@ def companion_matrix(poly, format='right'): - Rob Beezer (2011-05-19) """ import sage.matrix.constructor + if format not in ['right', 'left', 'top', 'bottom']: raise ValueError("format must be 'right', 'left', 'top' or 'bottom', not {0}".format(format)) try: @@ -2481,23 +2479,23 @@ def companion_matrix(poly, format='right'): # 1s below diagonal, or above diagonal if format in ['right', 'top']: for i in range(n - 1): - M[i+1, i] = 1 + M[i + 1, i] = 1 else: - for i in range(n-1): - M[i, i+1] = 1 + for i in range(n - 1): + M[i, i + 1] = 1 # right side, left side (reversed), bottom edge, top edge (reversed) if format == 'right': for i in range(n): - M[i, n-1] = -poly[i] + M[i, n - 1] = -poly[i] elif format == 'left': for i in range(n): - M[n-1-i, 0] = -poly[i] + M[n - 1 - i, 0] = -poly[i] elif format == 'bottom': for i in range(n): - M[n-1, i] = -poly[i] + M[n - 1, i] = -poly[i] elif format == 'top': for i in range(n): - M[0, n-1-i] = -poly[i] + M[0, n - 1 - i] = -poly[i] return M @@ -2637,7 +2635,7 @@ def random_rref_matrix(parent, num_pivots): # No harm if no pivots at all. subset = list(range(1, num_col)) shuffle(subset) - pivots = [0] + sorted(subset[:num_pivots - 1]) + pivots = [0] + sorted(subset[: num_pivots - 1]) # Use the list of pivot columns to set the pivot entries of the return_matrix to leading ones. for pivot_row, pivot in enumerate(pivots): @@ -2651,14 +2649,14 @@ def random_rref_matrix(parent, num_pivots): entry_generator1 = pd.RealDistribution("beta", [6, 4]) # Experimental distribution used to generate the values. for non_pivot_column_entry in range(pivot_index + 1): - sign1 = (2 * randint(0, 1) - 1) + sign1 = 2 * randint(0, 1) - 1 return_matrix[non_pivot_column_entry, non_pivot_column_index] = sign1 * int(entry_generator1.get_random_element() * ((1 - non_pivot_column_entry / return_matrix.ncols()) * 7)) # Use index to fill entries of the columns to the right of the last pivot column. for rest_non_pivot_column in range(pivots[num_pivots - 1] + 1, num_col): entry_generator2 = pd.RealDistribution("beta", [2.6, 4]) # experimental distribution to generate small values. for rest_entries in range(num_pivots): - sign2 = (2 * randint(0, 1) - 1) + sign2 = 2 * randint(0, 1) - 1 return_matrix[rest_entries, rest_non_pivot_column] = sign2 * int(entry_generator2.get_random_element() * 5) else: for pivot_index in range(num_pivots - 1): @@ -2805,7 +2803,7 @@ def random_echelonizable_matrix(parent, rank, upper_bound=None, max_tries=100): rows = parent.nrows() if rank < 0: raise ValueError("matrices must have rank zero or greater.") - if rank > min(rows,parent.ncols()): + if rank > min(rows, parent.ncols()): raise ValueError("matrices cannot have rank greater than min(ncols,nrows).") matrix = random_rref_matrix(parent, rank) @@ -2815,18 +2813,16 @@ def random_echelonizable_matrix(parent, rank, upper_bound=None, max_tries=100): # If upper_bound is not set, don't control entry size. if upper_bound is None: # If size control is not desired, the routine will run slightly faster, particularly with large matrices. - for pivots in range(rank-1, -1, -1): + for pivots in range(rank - 1, -1, -1): row_index = 0 while row_index < rows: if pivots == row_index: row_index += 1 if pivots != row_index and row_index != rows: - matrix.add_multiple_of_row(row_index, - matrix.pivot_rows()[pivots], - randint(-5, 5)) + matrix.add_multiple_of_row(row_index, matrix.pivot_rows()[pivots], randint(-5, 5)) row_index += 1 if rows > 1: - matrix.add_multiple_of_row(0, randint(1,rows-1), randint(-3,3)) + matrix.add_multiple_of_row(0, randint(1, rows - 1), randint(-3, 3)) else: if rank == 1: # would be better just to have a special generator... tries = 0 @@ -2834,7 +2830,7 @@ def random_echelonizable_matrix(parent, rank, upper_bound=None, max_tries=100): matrix = random_rref_matrix(parent, rank) tries += 1 if tries > max_tries: # to prevent endless attempts - raise ValueError("tried "+str(max_tries)+" times to get a rank 1 random matrix. Try bigger upper_bound?") + raise ValueError("tried " + str(max_tries) + " times to get a rank 1 random matrix. Try bigger upper_bound?") matrix_copy = matrix for pivots in range(len(matrix.pivots()) - 1, -1, -1): @@ -2848,7 +2844,7 @@ def random_echelonizable_matrix(parent, rank, upper_bound=None, max_tries=100): if pivots != row_index: # To ensure a leading one is not removed by the addition of the pivot row by its # additive inverse. - matrix_copy = matrix.with_added_multiple_of_row(row_index,matrix.pivot_rows()[pivots],randint(-5,5)) + matrix_copy = matrix.with_added_multiple_of_row(row_index, matrix.pivot_rows()[pivots], randint(-5, 5)) tries += 1 # Range for scalar multiples determined experimentally. if max(map(abs, matrix_copy.list())) < upper_bound: @@ -2857,29 +2853,29 @@ def random_echelonizable_matrix(parent, rank, upper_bound=None, max_tries=100): row_index += 1 tries = 0 if tries > max_tries: # to prevent endless unsuccessful row adding - raise ValueError("tried "+str(max_tries)+" times to get row number "+str(row_index)+". Try bigger upper_bound?") + raise ValueError("tried " + str(max_tries) + " times to get row number " + str(row_index) + ". Try bigger upper_bound?") # The leading one in row one has not been altered, so add a scalar multiple of a random row # to row one. row1 = 0 if rows > 1: while row1 < 1: - matrix_copy = matrix.with_added_multiple_of_row(0,randint(1,rows-1),randint(-3,3)) - if max(map(abs,matrix_copy.list())) < upper_bound: + matrix_copy = matrix.with_added_multiple_of_row(0, randint(1, rows - 1), randint(-3, 3)) + if max(map(abs, matrix_copy.list())) < upper_bound: matrix = matrix_copy row1 += 1 # If the matrix generated over a different ring, random elements from the designated ring are used as and # the routine is run similarly to the size unchecked version for rationals and integers. else: - for pivots in range(rank-1,-1,-1): + for pivots in range(rank - 1, -1, -1): row_index = 0 while row_index < rows: if pivots == row_index: row_index += 1 if pivots != row_index and row_index != rows: - matrix.add_multiple_of_row(row_index,matrix.pivot_rows()[pivots],ring.random_element()) + matrix.add_multiple_of_row(row_index, matrix.pivot_rows()[pivots], ring.random_element()) row_index += 1 if rows > 1: - matrix.add_multiple_of_row(0,randint(1,rows-1),ring.random_element()) + matrix.add_multiple_of_row(0, randint(1, rows - 1), ring.random_element()) return matrix @@ -3004,23 +3000,20 @@ def random_subspaces_matrix(parent, rank=None): # skewing to smaller numbers, always at least 1. if rank is None: left_nullity_generator = pd.RealDistribution("beta", [1.4, 5.5]) - nullity = int(left_nullity_generator.get_random_element()*(rows-1) + 1) + nullity = int(left_nullity_generator.get_random_element() * (rows - 1) + 1) rank = rows - nullity if rank < 0: raise ValueError("matrices must have rank zero or greater.") if rank > rows or rank > columns: raise ValueError("rank cannot exceed the number of rows or columns.") nullity = rows - rank - B = random_matrix(ring, rows, columns, algorithm='echelon_form', - num_pivots=rank) + B = random_matrix(ring, rows, columns, algorithm='echelon_form', num_pivots=rank) # Create a nonsingular matrix whose columns will be used to stack a matrix # over the L matrix, forming a nonsingular matrix. - K_nonzero_columns = random_matrix(ring, rank, rank, - algorithm='echelonizable', rank=rank) + K_nonzero_columns = random_matrix(ring, rank, rank, algorithm='echelonizable', rank=rank) K = matrix(QQ, rank, rows) - L = random_matrix(ring, nullity, rows, algorithm='echelon_form', - num_pivots=nullity) + L = random_matrix(ring, nullity, rows, algorithm='echelon_form', num_pivots=nullity) for column in range(len(L.nonpivots())): for entry in range(rank): K[entry, L.nonpivots()[column]] = K_nonzero_columns[entry, column] @@ -3134,7 +3127,7 @@ def random_unimodular_matrix(parent, upper_bound=None, max_tries=100): # random_echelonizable_matrix() always returns a determinant one matrix if given full rank. return random_matrix(ring, size, algorithm='echelonizable', rank=size) if upper_bound is not None and (ring == ZZ or ring == QQ): - return random_matrix(ring, size,algorithm='echelonizable',rank=size, upper_bound=upper_bound, max_tries=max_tries) + return random_matrix(ring, size, algorithm='echelonizable', rank=size, upper_bound=upper_bound, max_tries=max_tries) @matrix_method @@ -3276,31 +3269,30 @@ def random_unitary_matrix(parent): raise ValueError("base ring of parent must have characteristic zero") from sage.rings.real_lazy import CLF, RLF - if not (RLF.has_coerce_map_from(F) or - F.has_coerce_map_from(RLF) or - CLF.has_coerce_map_from(F) or - F.has_coerce_map_from(CLF)): + + if not (RLF.has_coerce_map_from(F) or F.has_coerce_map_from(RLF) or CLF.has_coerce_map_from(F) or F.has_coerce_map_from(CLF)): # The implementation of SR.random_element() currently just # returns a random integer coerced into SR, so there is no # benefit to allowing SR here when QQ is available. - raise ValueError("base ring of parent must be a subfield " - "of the complex numbers") + raise ValueError("base ring of parent must be a subfield " "of the complex numbers") - I = identity_matrix(F,n) - A = random_matrix(F,n) + I = identity_matrix(F, n) + A = random_matrix(F, n) S = A - A.conjugate_transpose() - U = (S-I).inverse()*(S+I) + U = (S - I).inverse() * (S + I) # Scale the rows of U by plus/minus one with equal probability. # This generates the equivalence class of U according to the # Liebeck/Osborne paper. from random import random + for i in range(n): if random() < 0.5: U.set_row_to_multiple_of_row(i, i, -1) return U + @matrix_method def random_bistochastic_matrix(parent): """ @@ -3396,14 +3388,15 @@ def random_bistochastic_matrix(parent): ValueError: base ring of parent must be a subfield of the real numbers """ from sage.rings.real_mpfr import RR + if not parent.base_ring().is_subring(RR): - raise ValueError("base ring of parent must be a subfield of the real " - "numbers") + raise ValueError("base ring of parent must be a subfield of the real " "numbers") B = random_unitary_matrix(parent) # Squaring every entry. return B.elementwise_product(B) + @matrix_method def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): """ @@ -3601,46 +3594,46 @@ def random_diagonalizable_matrix(parent, eigenvalues=None, dimensions=None): low_bound = 0 for row_index in range(len(dimensions)): up_bound = up_bound + dimensions[row_index] - for entry in range(low_bound,up_bound): + for entry in range(low_bound, up_bound): diagonal_matrix[entry, entry] = eigenvalues[row_index] - low_bound = low_bound+dimensions[row_index] + low_bound = low_bound + dimensions[row_index] # Create a matrix to hold each of the eigenvectors as its columns, begin with an identity matrix so that after row and column # operations the resulting matrix will be unimodular. eigenvector_matrix = matrix.identity(ring, size) upper_limit = 0 lower_limit = 0 # run the routine over the necessary number of columns corresponding eigenvalue dimension. - for dimension_index in range(len(dimensions)-1): - upper_limit = upper_limit+dimensions[dimension_index] - lowest_index_row_with_one = size-dimensions[dimension_index] + for dimension_index in range(len(dimensions) - 1): + upper_limit = upper_limit + dimensions[dimension_index] + lowest_index_row_with_one = size - dimensions[dimension_index] # assign a one to the row that is the eigenvalue dimension rows up from the bottom row then assign ones diagonally down to the right. - for eigen_ones in range(lower_limit,upper_limit): - eigenvector_matrix[lowest_index_row_with_one,eigen_ones] = 1 + for eigen_ones in range(lower_limit, upper_limit): + eigenvector_matrix[lowest_index_row_with_one, eigen_ones] = 1 lowest_index_row_with_one += 1 - lower_limit = lower_limit+dimensions[dimension_index] + lower_limit = lower_limit + dimensions[dimension_index] # Create a list to give the eigenvalue dimension corresponding to each column. dimension_check = [] for i in range(len(dimensions)): for k in range(dimensions[i]): dimension_check.append(dimensions[i]) # run routine over the rows that are in the range of the protected ones. Use addition of column multiples to fill entries. - for dimension_multiplicity in range(max(dimensions),min(dimensions),-1): - highest_one_row = size-dimension_multiplicity + for dimension_multiplicity in range(max(dimensions), min(dimensions), -1): + highest_one_row = size - dimension_multiplicity highest_one_column = 0 # find the column with the protected one in the lowest indexed row. - while eigenvector_matrix[highest_one_row,highest_one_column] == 0: + while eigenvector_matrix[highest_one_row, highest_one_column] == 0: highest_one_column += 1 # dimension_check determines if column has a low enough eigenvalue dimension to take a column multiple. for bottom_entry_filler in range(len(dimension_check)): - if dimension_check[bottom_entry_filler] < dimension_multiplicity and eigenvector_matrix[highest_one_row,bottom_entry_filler] == 0: + if dimension_check[bottom_entry_filler] < dimension_multiplicity and eigenvector_matrix[highest_one_row, bottom_entry_filler] == 0: # randint range determined experimentally to keep entries manageable. - eigenvector_matrix.add_multiple_of_column(bottom_entry_filler,highest_one_column,randint(-4,4)) + eigenvector_matrix.add_multiple_of_column(bottom_entry_filler, highest_one_column, randint(-4, 4)) # Fill remaining rows using scalar row addition. - for row in range(size-max(dimensions),size): - for upper_row in range(size-max(dimensions)): + for row in range(size - max(dimensions), size): + for upper_row in range(size - max(dimensions)): # range of multiplier determined experimentally so that entries stay manageable for small matrices - eigenvector_matrix.add_multiple_of_row(upper_row,row,randint(-4,4)) - return eigenvector_matrix*diagonal_matrix*(eigenvector_matrix.inverse()) + eigenvector_matrix.add_multiple_of_row(upper_row, row, randint(-4, 4)) + return eigenvector_matrix * diagonal_matrix * (eigenvector_matrix.inverse()) @matrix_method @@ -3817,6 +3810,7 @@ def ith_to_zero_rotation_matrix(v, i, ring=None): if b == 0: return identity_matrix(dim, sparse=True) from sage.misc.functional import sqrt + norm = sqrt(a * a + b * b) aa = a / norm bb = b / norm @@ -3854,8 +3848,10 @@ def hilbert(dim, ring=QQ): [1/4 1/5 1/6 1/7 1/8] [1/5 1/6 1/7 1/8 1/9] """ + def entries(i, j): return ZZ.one() / (i + j + 1) + return matrix(entries, nrows=dim, ncols=dim, base_ring=ring) @@ -3888,8 +3884,10 @@ def vandermonde(v, ring=None): [ 1 x1 x1^2] [ 1 x2 x2^2] """ + def entries(i, j): - return v[i]**j + return v[i] ** j + return matrix(entries, nrows=len(v), ncols=len(v), base_ring=ring) @@ -3934,9 +3932,11 @@ def toeplitz(c, r, ring=None): [ 0 1 -2 1] [ 0 0 1 -2] """ + def entries(i, j): return c[i - j] if i >= j else r[j - i - 1] - return matrix(entries, nrows=len(c), ncols=len(r)+1, base_ring=ring) + + return matrix(entries, nrows=len(c), ncols=len(r) + 1, base_ring=ring) @matrix_method @@ -4006,4 +4006,5 @@ def hankel(c, r=None, ring=None): def entries(i): return c[i] if i < m else r[i - m] + return matrix(lambda i, j: entries(i + j), nrows=m, ncols=n + 1, base_ring=ring) diff --git a/src/sage/matrix/symplectic_basis.py b/src/sage/matrix/symplectic_basis.py index de8cb9401df..e139276b1b9 100644 --- a/src/sage/matrix/symplectic_basis.py +++ b/src/sage/matrix/symplectic_basis.py @@ -99,42 +99,42 @@ def _inplace_move_to_positive_pivot(G, row, col, B, pivot): """ v = G[row, col] - if (row, col) == (pivot, pivot+1): + if (row, col) == (pivot, pivot + 1): pass - elif (row, col) == (pivot+1, pivot): - B.swap_rows(pivot, pivot+1) - G.swap_rows(pivot, pivot+1) - G.swap_columns(pivot, pivot+1) - elif row != pivot and row != pivot+1 and col != pivot and col != pivot+1: + elif (row, col) == (pivot + 1, pivot): + B.swap_rows(pivot, pivot + 1) + G.swap_rows(pivot, pivot + 1) + G.swap_columns(pivot, pivot + 1) + elif row != pivot and row != pivot + 1 and col != pivot and col != pivot + 1: B.swap_rows(pivot, row) - B.swap_rows(pivot+1, col) + B.swap_rows(pivot + 1, col) G.swap_rows(pivot, row) - G.swap_rows(pivot+1, col) + G.swap_rows(pivot + 1, col) G.swap_columns(pivot, row) - G.swap_columns(pivot+1, col) + G.swap_columns(pivot + 1, col) elif row == pivot: - B.swap_rows(pivot+1, col) - G.swap_rows(pivot+1, col) - G.swap_columns(pivot+1, col) - elif row == pivot+1: + B.swap_rows(pivot + 1, col) + G.swap_rows(pivot + 1, col) + G.swap_columns(pivot + 1, col) + elif row == pivot + 1: B.swap_rows(pivot, col) G.swap_rows(pivot, col) G.swap_columns(pivot, col) elif col == pivot: - B.swap_rows(pivot+1, row) - G.swap_rows(pivot+1, row) - G.swap_columns(pivot+1, row) - elif col == pivot+1: + B.swap_rows(pivot + 1, row) + G.swap_rows(pivot + 1, row) + G.swap_columns(pivot + 1, row) + elif col == pivot + 1: B.swap_rows(pivot, row) G.swap_rows(pivot, row) G.swap_columns(pivot, row) # all that swapping can switch the sign of a row - if G[pivot, pivot+1] != v: - B.swap_rows(pivot, pivot+1) - G.swap_rows(pivot, pivot+1) - G.swap_columns(pivot, pivot+1) + if G[pivot, pivot + 1] != v: + B.swap_rows(pivot, pivot + 1) + G.swap_rows(pivot, pivot + 1) + G.swap_columns(pivot, pivot + 1) def symplectic_basis_over_field(M): @@ -307,22 +307,22 @@ def symplectic_basis_over_field(M): _inplace_move_to_positive_pivot(E, pivot, found_i, B, pivot) # scale row and col - v = ZZ(1)/E[pivot, pivot+1] + v = ZZ(1) / E[pivot, pivot + 1] E.rescale_row(pivot, v) E.rescale_col(pivot, v) B.rescale_row(pivot, v) # use nonzero element to clean row pivot - for i in range(pivot+2, n): - v = - E[i, pivot] / E[pivot+1, pivot] + for i in range(pivot + 2, n): + v = -E[i, pivot] / E[pivot + 1, pivot] if v != 0: - E.add_multiple_of_row(i, pivot+1, v) - E.add_multiple_of_column(i, pivot+1, v) - B.add_multiple_of_row(i, pivot+1, v) + E.add_multiple_of_row(i, pivot + 1, v) + E.add_multiple_of_column(i, pivot + 1, v) + B.add_multiple_of_row(i, pivot + 1, v) # use nonzero element to clean row pivot+1 - for i in range(pivot+2, n): - v = - E[i, pivot+1] / E[pivot, pivot+1] + for i in range(pivot + 2, n): + v = -E[i, pivot + 1] / E[pivot, pivot + 1] if v != 0: E.add_multiple_of_row(i, pivot, v) E.add_multiple_of_column(i, pivot, v) @@ -330,7 +330,7 @@ def symplectic_basis_over_field(M): # record for basis reconstruction es.append(pivot) - fs.append(pivot+1) + fs.append(pivot + 1) pivot += 2 C = B.matrix_from_rows(es + fs + zeroes) @@ -508,19 +508,19 @@ def symplectic_basis_over_ZZ(M): # use nonzero element to clean row pivot all_zero = True - u = E[pivot+1, pivot] - for i in range(pivot+2, n): + u = E[pivot + 1, pivot] + for i in range(pivot + 2, n): v, r = (-E[i, pivot]).quo_rem(u) if v != 0: all_zero = False - E.add_multiple_of_row(i, pivot+1, v) - E.add_multiple_of_column(i, pivot+1, v) - B.add_multiple_of_row(i, pivot+1, v) + E.add_multiple_of_row(i, pivot + 1, v) + E.add_multiple_of_column(i, pivot + 1, v) + B.add_multiple_of_row(i, pivot + 1, v) # use nonzero element to clean row pivot+1 - u = E[pivot, pivot+1] - for i in range(pivot+2, n): - v, r = (-E[i, pivot+1]).quo_rem(u) + u = E[pivot, pivot + 1] + for i in range(pivot + 2, n): + v, r = (-E[i, pivot + 1]).quo_rem(u) if v != 0: all_zero = False E.add_multiple_of_row(i, pivot, v) @@ -529,7 +529,7 @@ def symplectic_basis_over_ZZ(M): if all_zero: # record for basis reconstruction - ps.append((E[pivot, pivot+1], pivot)) + ps.append((E[pivot, pivot + 1], pivot)) pivot += 2 ps.sort() diff --git a/src/sage/matroids/advanced.py b/src/sage/matroids/advanced.py index 65b30f1bc36..8c3beb3cc16 100644 --- a/src/sage/matroids/advanced.py +++ b/src/sage/matroids/advanced.py @@ -68,6 +68,7 @@ # lazy import of GraphicMatroid for modularization purposes from sage.misc.lazy_import import lazy_import + lazy_import('sage.matroids.graphic_matroid', 'GraphicMatroid') from sage.matroids.extension import LinearSubclasses, MatroidExtensions diff --git a/src/sage/matroids/all.py b/src/sage/matroids/all.py index e40ab089e1c..8ae3f679d57 100644 --- a/src/sage/matroids/all.py +++ b/src/sage/matroids/all.py @@ -1,11 +1,14 @@ """ Matroids """ + # install the docstring of this module to the containing package from sage.misc.namespace_package import install_doc + install_doc(__package__, __doc__) from sage.misc.lazy_import import lazy_import + lazy_import('sage.matroids.constructor', 'Matroid') lazy_import('sage.matroids', 'matroids_catalog', 'matroids') del lazy_import diff --git a/src/sage/matroids/catalog.py b/src/sage/matroids/catalog.py index e5b5c065fac..6f3ac8d6b58 100644 --- a/src/sage/matroids/catalog.py +++ b/src/sage/matroids/catalog.py @@ -7,37 +7,138 @@ """ from sage.matroids.database_matroids import ( - U24, U25, U35, K4, Whirl3, Q6, P6, U36, R6, - Fano, FanoDual, NonFano, NonFanoDual, O7, P7, - AG32, AG32prime, R8, F8, Q8, L8, S8, Vamos, T8, J, P8, P8pp, - Wheel4, Whirl4, - K33dual, K33, AG23, TernaryDowling3, R9, Pappus, NonPappus, - K5, K5dual, R10, NonDesargues, - R12, ExtendedTernaryGolayCode, T12, + U24, + U25, + U35, + K4, + Whirl3, + Q6, + P6, + U36, + R6, + Fano, + FanoDual, + NonFano, + NonFanoDual, + O7, + P7, + AG32, + AG32prime, + R8, + F8, + Q8, + L8, + S8, + Vamos, + T8, + J, + P8, + P8pp, + Wheel4, + Whirl4, + K33dual, + K33, + AG23, + TernaryDowling3, + R9, + Pappus, + NonPappus, + K5, + K5dual, + R10, + NonDesargues, + R12, + ExtendedTernaryGolayCode, + T12, PG23, ) from sage.matroids.database_matroids import ( - RelaxedNonFano, TippedFree3spike, - AG23minusDY, TQ8, P8p, KP8, Sp8, Sp8pp, LP8, WQ8, - BB9, TQ9, TQ9p, M8591, PP9, BB9gDY, A9, FN9, FX9, KR9, KQ9, - UG10, FF10, GP10, FZ10, UQ10, FP10, TQ10, FY10, PP10, FU10, D10, UK10, - PK10, GK10, FT10, TK10, KT10, TU10, UT10, FK10, KF10, + RelaxedNonFano, + TippedFree3spike, + AG23minusDY, + TQ8, + P8p, + KP8, + Sp8, + Sp8pp, + LP8, + WQ8, + BB9, + TQ9, + TQ9p, + M8591, + PP9, + BB9gDY, + A9, + FN9, + FX9, + KR9, + KQ9, + UG10, + FF10, + GP10, + FZ10, + UQ10, + FP10, + TQ10, + FY10, + PP10, + FU10, + D10, + UK10, + PK10, + GK10, + FT10, + TK10, + KT10, + TU10, + UT10, + FK10, + KF10, FA11, - FR12, GP12, FQ12, FF12, FZ12, UQ12, FP12, FS12, UK12, UA12, AK12, - FK12, KB12, AF12, NestOfTwistedCubes, + FR12, + GP12, + FQ12, + FF12, + FZ12, + UQ12, + FP12, + FS12, + UK12, + UA12, + AK12, + FK12, + KB12, + AF12, + NestOfTwistedCubes, XY13, - N3, N3pp, UP14, VP14, FV14, OW14, FM14, + N3, + N3pp, + UP14, + VP14, + FV14, + OW14, + FM14, FA15, N4, ) from sage.matroids.database_matroids import ( - NonVamos, NotP8, AG23minus, - P9, R9A, R9B, Block_9_4, TicTacToe, - N1, Block_10_5, Q10, + NonVamos, + NotP8, + AG23minus, + P9, + R9A, + R9B, + Block_9_4, + TicTacToe, + N1, + Block_10_5, + Q10, BetsyRoss, N2, - D16, Terrahawk, + D16, + Terrahawk, ExtendedBinaryGolayCode, ) diff --git a/src/sage/matroids/chow_ring.py b/src/sage/matroids/chow_ring.py index 9b05f93552e..b79a8f4144c 100644 --- a/src/sage/matroids/chow_ring.py +++ b/src/sage/matroids/chow_ring.py @@ -5,6 +5,7 @@ - Shriya M """ + # **************************************************************************** # Copyright (C) 2024 Shriya M <25shriya at gmail.com> # @@ -113,6 +114,7 @@ class ChowRing(QuotientRing_generic, Representation_abstract): Chow ring of P8'': Matroid of rank 4 on 8 elements with 8 nonspanning circuits in Feitchner-Yuzvinsky presentation over Rational Field """ + def __init__(self, R, M, augmented, presentation=None): r""" Initialize ``self``. @@ -144,10 +146,7 @@ def __init__(self, R, M, augmented, presentation=None): else: raise ValueError(f"invalid presentation '{presentation}'") C = CommutativeRings().Quotients() & KahlerAlgebras(R) - QuotientRing_generic.__init__(self, R=self._ideal.ring(), - I=self._ideal, - names=self._ideal.ring().variable_names(), - category=C) + QuotientRing_generic.__init__(self, R=self._ideal.ring(), I=self._ideal, names=self._ideal.ring().variable_names(), category=C) Representation_abstract.__init__(self, semigroup=M.automorphism_group(), side="left") def _repr_(self): @@ -183,6 +182,7 @@ def _latex_(self): 'A(\\begin{array}{l}\n\\text{\\texttt{U(2,{ }5):{ }Matroid{ }of{ }rank{ }2{ }on{ }5{ }elements{ }with{ }circuit{-}closures}}\\\\\n\\text{\\texttt{{\\char`\\{}2:{ }{\\char`\\{}{\\char`\\{}0,{ }1,{ }2,{ }3,{ }4{\\char`\\}}{\\char`\\}}{\\char`\\}}}}\n\\end{array})_{\\Bold{Q}}' """ from sage.misc.latex import latex + base = "A({})_{{{}}}" if self._augmented: base += "^*" @@ -243,6 +243,7 @@ def basis(self): True """ from sage.sets.family import Family + monomial_basis = self._ideal.normal_basis() return Family([self.element_class(self, mon, reduce=False) for mon in monomial_basis]) @@ -331,8 +332,7 @@ def lefschetz_element(self): -20*A01234^3], 3: [0]} """ - w = sum(len(F) * (len(self.matroid().groundset()) - len(F)) * gen - for F, gen in self.defining_ideal().flats_to_generator_dict().items()) + w = sum(len(F) * (len(self.matroid().groundset()) - len(F)) * gen for F, gen in self.defining_ideal().flats_to_generator_dict().items()) return self.element_class(self, w) @cached_method @@ -378,12 +378,12 @@ def graded_character(self, G=None): if G is None: G = self._matroid.automorphism_group() from sage.rings.rational_field import QQ + q = QQ['q'].gen() B = self.basis() from sage.modules.free_module_element import vector - return vector(q.parent(), [sum(q**b.degree() * (g * b).lift().monomial_coefficient(b.lift()) for b in B) - for g in G.conjugacy_classes_representatives()], - immutable=True) + + return vector(q.parent(), [sum(q ** b.degree() * (g * b).lift().monomial_coefficient(b.lift()) for b in B) for g in G.conjugacy_classes_representatives()], immutable=True) class Element(QuotientRing_generic.Element): def to_vector(self, order=None): @@ -546,10 +546,9 @@ def _acted_upon_(self, scalar, self_on_left=True): return super()._acted_upon_(scalar, self_on_left) if scalar in P._matroid.automorphism_group(): gens = P.ambient().gens() - return P.retract(self.lift().subs({g: gens[scalar(i+1)-1] for i, g in enumerate(gens)})) + return P.retract(self.lift().subs({g: gens[scalar(i + 1) - 1] for i, g in enumerate(gens)})) if not self_on_left and scalar in P._matroid.automorphism_group(): scalar = P._semigroup_algebra(scalar) gens = P.ambient().gens() - return P.sum(c * P.retract(self.lift().subs({g: gens[sigma(i+1)-1] for i, g in enumerate(gens)})) - for sigma, c in scalar.monomial_coefficients(copy=False).items()) + return P.sum(c * P.retract(self.lift().subs({g: gens[sigma(i + 1) - 1] for i, g in enumerate(gens)})) for sigma, c in scalar.monomial_coefficients(copy=False).items()) return super()._acted_upon_(scalar, self_on_left) diff --git a/src/sage/matroids/chow_ring_ideal.py b/src/sage/matroids/chow_ring_ideal.py index e5a6336268d..9e18ad4460b 100644 --- a/src/sage/matroids/chow_ring_ideal.py +++ b/src/sage/matroids/chow_ring_ideal.py @@ -5,6 +5,7 @@ - Shriya M """ + # **************************************************************************** # Copyright (C) 2024 Shriya M <25shriya at gmail.com> # @@ -174,6 +175,7 @@ class ChowRingIdeal_nonaug_fy(ChowRingIdeal): Chow ring ideal of Fano: Binary matroid of rank 3 on 7 elements, type (3, 0) - non augmented in Feitchner-Yuzvinksy presentation """ + def __init__(self, M, R) -> None: r""" Initialize ``self``. @@ -184,8 +186,7 @@ def __init__(self, M, R) -> None: sage: TestSuite(I).run(skip="_test_category") """ self._matroid = M - flats = [X for i in range(1, self._matroid.rank() + 1) - for X in self._matroid.flats(i)] + flats = [X for i in range(1, self._matroid.rank() + 1) for X in self._matroid.flats(i)] names = ['A{}'.format(''.join(str(x) for x in sorted(F, key=cmp_elements_key))) for F in flats] poly_ring = ChowRingIdeal._construct_ambient_poly_ring(R, names, flats) gens = poly_ring.gens() @@ -268,6 +269,7 @@ def _latex_(self) -> str: '(I_{\\text{\\texttt{Matroid{ }of{ }rank{ }2{ }on{ }4{ }elements{ }with{ }3{ }bases}}} + J_{\\text{\\texttt{Matroid{ }of{ }rank{ }2{ }on{ }4{ }elements{ }with{ }3{ }bases}}}' """ from sage.misc.latex import latex + return '(I_{{{M}}} + J_{{{M}}}'.format(M=latex(self._matroid)) def groebner_basis(self, algorithm='', *args, **kwargs): @@ -358,14 +360,14 @@ def normal_basis(self, algorithm='', *args, **kwargs): for subset in chains: max_powers = [] k = len(subset) - if (k == 0): + if k == 0: monomial_basis.append(R.one()) elif not ((k == 1) & (ranks[subset[0]] == 1)): for i in range(k): if i == 0: max_powers.append(ranks[subset[i]]) else: - max_powers.append(ranks[subset[i]] - ranks[subset[i-1]]) + max_powers.append(ranks[subset[i]] - ranks[subset[i - 1]]) for combination in product(*(range(1, p) for p in max_powers)): expression = R.one() for val, c in zip(subset, combination): @@ -376,6 +378,7 @@ def normal_basis(self, algorithm='', *args, **kwargs): # Redirecting the unpickling of old class: from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.matroids.chow_ring_ideal', 'ChowRingIdeal_nonaug', ChowRingIdeal_nonaug_fy) @@ -429,6 +432,7 @@ class ChowRingIdeal_nonaug_af(ChowRingIdeal): Chow ring ideal of NonFano: Ternary matroid of rank 3 on 7 elements, type 0- - non augmented in the atom-free presentation """ + def __init__(self, M, R): r""" Initialize ``self``. @@ -439,8 +443,7 @@ def __init__(self, M, R): sage: TestSuite(I).run(skip="_test_category") """ self._matroid = M - flats = [X for i in range(2, self._matroid.rank() + 1) - for X in self._matroid.flats(i)] + flats = [X for i in range(2, self._matroid.rank() + 1) for X in self._matroid.flats(i)] names = ['A{}'.format(''.join(str(x) for x in sorted(F, key=cmp_elements_key))) for F in flats] poly_ring = ChowRingIdeal._construct_ambient_poly_ring(R, names, flats) gens = poly_ring.gens() @@ -503,7 +506,7 @@ def _gens_constructor(self, poly_ring): term1 += flats_gen[F] ** 2 for G in lattice_flats.order_filter([F]): if G != F: - term2 += flats_gen[F]*flats_gen[G] + term2 += flats_gen[F] * flats_gen[G] K.append(term1 + (2 * term2)) return I + J + K @@ -532,6 +535,7 @@ def _latex_(self): '(I_{\\text{\\texttt{Matroid{ }of{ }rank{ }2{ }on{ }4{ }elements{ }with{ }3{ }bases}}} + J_{\\text{\\texttt{Matroid{ }of{ }rank{ }2{ }on{ }4{ }elements{ }with{ }3{ }bases}}} + K_{\\text{\\texttt{Matroid{ }of{ }rank{ }2{ }on{ }4{ }elements{ }with{ }3{ }bases}}}' """ from sage.misc.latex import latex + return '(I_{{{M}}} + J_{{{M}}} + K_{{{M}}}'.format(M=latex(self._matroid)) def groebner_basis(self, algorithm='', *args, **kwargs): @@ -610,9 +614,9 @@ def normal_basis(self, algorithm='', *args, **kwargs): if i == 0: max_powers.append(ranks[subset[i]]) else: - max_powers.append(ranks[subset[i]] - ranks[subset[i-1]]) + max_powers.append(ranks[subset[i]] - ranks[subset[i - 1]]) ranges = [range(1, p) for p in max_powers] - first_rank = ranks[subset[k-1]] + first_rank = ranks[subset[k - 1]] for combination in product(*(r for r in ranges)): # Generating combinations for all powers from 1 to max_powers if sum(combination) <= first_rank: @@ -666,6 +670,7 @@ class ChowRingIdeal_nonaug_sp(ChowRingIdeal): Chow ring ideal of NonFano: Ternary matroid of rank 3 on 7 elements, type 0- - non augmented in simplicial presentation """ + def __init__(self, M, R): r""" Initialize ``self``. @@ -676,8 +681,7 @@ def __init__(self, M, R): sage: TestSuite(I).run(skip="_test_category") """ self._matroid = M - flats = [X for i in range(1, self._matroid.rank() + 1) - for X in self._matroid.flats(i)] + flats = [X for i in range(1, self._matroid.rank() + 1) for X in self._matroid.flats(i)] names = ['A{}'.format(''.join(str(x) for x in sorted(F, key=cmp_elements_key))) for F in flats] poly_ring = ChowRingIdeal._construct_ambient_poly_ring(R, names, flats) gens = poly_ring.gens() @@ -751,6 +755,7 @@ def _latex_(self): '(I_{\\text{\\texttt{Matroid{ }of{ }rank{ }2{ }on{ }4{ }elements{ }with{ }3{ }bases}}} + J_{\\text{\\texttt{Matroid{ }of{ }rank{ }2{ }on{ }4{ }elements{ }with{ }3{ }bases}}}' """ from sage.misc.latex import latex + return '(I_{{{M}}} + J_{{{M}}}'.format(M=latex(self._matroid)) def groebner_basis(self, algorithm='', *args, **kwargs): @@ -835,7 +840,7 @@ def normal_basis(self, algorithm='', *args, **kwargs): max_powers = [] max_powers.append(ranks[subset[0]]) for i in range(1, k): - max_powers.append(ranks[subset[i]] - ranks[subset[i-1]]) + max_powers.append(ranks[subset[i]] - ranks[subset[i - 1]]) ranges = [range(1, p) for p in max_powers] ranges[0] = range(1, max_powers[0]) for combination in product(*(ran for ran in ranges)): @@ -925,6 +930,7 @@ class AugmentedChowRingIdeal_fy(ChowRingIdeal): Augmented Chow ring ideal of Wheel(3): Regular matroid of rank 3 on 6 elements with 16 bases of Feitchner-Yuzvinsky presentation """ + def __init__(self, M, R) -> None: r""" Initialize ``self``. @@ -935,8 +941,7 @@ def __init__(self, M, R) -> None: sage: TestSuite(I).run(skip="_test_category") """ self._matroid = M - self._flats = [X for i in range(self._matroid.rank() + 1) - for X in self._matroid.flats(i)] + self._flats = [X for i in range(self._matroid.rank() + 1) for X in self._matroid.flats(i)] E = list(self._matroid.groundset()) self._flats_generator = dict() names_groundset = ['A{}'.format(''.join(str(x))) for x in E] @@ -995,8 +1000,7 @@ def _gens_constructor(self, poly_ring) -> list: antichains = lattice_flats.antichains().elements_of_depth_iterator(2) # Quadratic generators - Q = [self._flats_generator[F] * self._flats_generator[G] - for F, G in antichains] + Q = [self._flats_generator[F] * self._flats_generator[G] for F, G in antichains] for x in E: term = poly_ring.zero() @@ -1034,6 +1038,7 @@ def _latex_(self) -> str: 'I_{FY}(\\text{\\texttt{Graphic{ }matroid{ }of{ }rank{ }2{ }on{ }3{ }elements}})' """ from sage.misc.latex import latex + return 'I_{{FY}}({})'.format(latex(self._matroid)) def groebner_basis(self, algorithm='', *args, **kwargs): @@ -1075,11 +1080,11 @@ def groebner_basis(self, algorithm='', *args, **kwargs): for H in lattice_flats.order_filter([F]): term1 += self._flats_generator[H] if term1 != poly_ring.zero(): - gb.append(term1**(self._matroid.rank(F) + 1)) # 5.6 (MM2022) + gb.append(term1 ** (self._matroid.rank(F) + 1)) # 5.6 (MM2022) order_ideal_modified = lattice_flats.order_ideal([F]) order_ideal_modified.remove(F) for G in order_ideal_modified: # nested flats - gb.append(self._flats_generator[G] * term1**(self._matroid.rank(F) - self._matroid.rank(G))) + gb.append(self._flats_generator[G] * term1 ** (self._matroid.rank(F) - self._matroid.rank(G))) return PolynomialSequence(poly_ring, [gb]) @@ -1116,8 +1121,7 @@ def normal_basis(self, algorithm='', *args, **kwargs): else: k = len(subset) max_powers = [ranks[subset[0]]] - max_powers.extend(ranks[subset[i]] - ranks[subset[i - 1]] - for i in range(1, k)) + max_powers.extend(ranks[subset[i]] - ranks[subset[i - 1]] for i in range(1, k)) ranges = [range(1, p) for p in max_powers] ranges[0] = range(1, max_powers[0] + 1) for combination in product(*(r for r in ranges)): @@ -1177,6 +1181,7 @@ class AugmentedChowRingIdeal_atom_free(ChowRingIdeal): Augmented Chow ring ideal of Wheel(3): Regular matroid of rank 3 on 6 elements with 16 bases in the atom-free presentation """ + def __init__(self, M, R) -> None: r""" Initialize ``self``. @@ -1187,8 +1192,7 @@ def __init__(self, M, R) -> None: sage: TestSuite(I).run(skip="_test_category") """ self._matroid = M - self._flats = [X for i in range(1, self._matroid.rank() + 1) - for X in self._matroid.flats(i)] + self._flats = [X for i in range(1, self._matroid.rank() + 1) for X in self._matroid.flats(i)] names = ['A{}'.format(''.join(str(x) for x in sorted(F, key=cmp_elements_key))) for F in self._flats] poly_ring = ChowRingIdeal._construct_ambient_poly_ring(R, names, self._flats) gens = poly_ring.gens() @@ -1257,6 +1261,7 @@ def _latex_(self) -> str: 'I_{af}(\\text{\\texttt{Graphic{ }matroid{ }of{ }rank{ }2{ }on{ }3{ }elements}})' """ from sage.misc.latex import latex + return 'I_{{af}}({})'.format(latex(self._matroid)) def groebner_basis(self, algorithm='', *args, **kwargs): @@ -1286,7 +1291,7 @@ def groebner_basis(self, algorithm='', *args, **kwargs): lattice_flats = Poset(H) antichains = lattice_flats.antichains().elements_of_depth_iterator(2) for F, G in antichains: - gb.append(self._flats_generator[F]*self._flats_generator[G]) + gb.append(self._flats_generator[F] * self._flats_generator[G]) for F in self._flats: term = poly_ring.zero() for H in lattice_flats.order_filter([F]): @@ -1337,10 +1342,10 @@ def normal_basis(self, algorithm='', *args, **kwargs): if i == 0: max_powers.append(ranks[subset[i]]) else: - max_powers.append(ranks[subset[i]] - ranks[subset[i-1]]) + max_powers.append(ranks[subset[i]] - ranks[subset[i - 1]]) ranges = [range(1, p) for p in max_powers] ranges[0] = range(1, max_powers[0] + 1) - first_rank = ranks[subset[k-1]] + 1 + first_rank = ranks[subset[k - 1]] + 1 for combination in product(*(r for r in ranges)): # Generating combinations for all powers from 1 to max_powers if sum(combination) <= first_rank: diff --git a/src/sage/matroids/constructor.py b/src/sage/matroids/constructor.py index ec1ff3cd5d0..b350213ce03 100644 --- a/src/sage/matroids/constructor.py +++ b/src/sage/matroids/constructor.py @@ -783,10 +783,7 @@ def Matroid(groundset=None, data=None, **kwds): # "key" is the kind of data we got key = None if data is None: - for k in ['bases', 'independent_sets', 'circuits', - 'nonspanning_circuits', 'flats', 'graph', 'matrix', - 'reduced_matrix', 'morphism', 'reduced_morphism', - 'rank_function', 'revlex', 'circuit_closures', 'matroid']: + for k in ['bases', 'independent_sets', 'circuits', 'nonspanning_circuits', 'flats', 'graph', 'matrix', 'reduced_matrix', 'morphism', 'reduced_morphism', 'rank_function', 'revlex', 'circuit_closures', 'matroid']: if k in kwds: data = kwds.pop(k) key = k @@ -804,12 +801,9 @@ def Matroid(groundset=None, data=None, **kwds): Graph = () if isinstance(data, Graph): key = 'graph' - elif isinstance(data, Matrix) or ( - isinstance(data, tuple) and isinstance(data[0], Matrix)): + elif isinstance(data, Matrix) or (isinstance(data, tuple) and isinstance(data[0], Matrix)): key = 'matrix' - elif isinstance(data, sage.modules.with_basis.morphism.ModuleMorphism) or ( - isinstance(data, tuple) and - isinstance(data[0], sage.modules.with_basis.morphism.ModuleMorphism)): + elif isinstance(data, sage.modules.with_basis.morphism.ModuleMorphism) or (isinstance(data, tuple) and isinstance(data[0], sage.modules.with_basis.morphism.ModuleMorphism)): key = 'morphism' elif isinstance(data, sage.matroids.matroid.Matroid): key = 'matroid' @@ -862,8 +856,7 @@ def Matroid(groundset=None, data=None, **kwds): try: rk = kwds.pop("rank") except TypeError: - raise TypeError("the rank needs to be specified alongside the " + - "nonspanning circuits") + raise TypeError("the rank needs to be specified alongside the " + "nonspanning circuits") # Determine groundset (note that this cannot detect coloops) if groundset is None: groundset = set() @@ -880,10 +873,7 @@ def Matroid(groundset=None, data=None, **kwds): if flag: B += [list(b)] # convert to circuits matroid defined by non-spanning circuits - M = CircuitsMatroid( - BasisMatroid(groundset=groundset, bases=B), - nsc_defined=True - ) + M = CircuitsMatroid(BasisMatroid(groundset=groundset, bases=B), nsc_defined=True) # Flats elif key == 'flats': @@ -939,7 +929,7 @@ def Matroid(groundset=None, data=None, **kwds): # Matrices: elif key in ['matrix', 'reduced_matrix', 'morphism', 'reduced_morphism']: A = data - is_reduced = (key == 'reduced_matrix' or key == 'reduced_morphism') + is_reduced = key == 'reduced_matrix' or key == 'reduced_morphism' if isinstance(data, tuple): A = data[0] if key == 'matrix' or key == 'reduced_matrix': @@ -1027,12 +1017,11 @@ def Matroid(groundset=None, data=None, **kwds): def revlex_sort_key(s): return tuple(reversed(s)) + subsets = sorted(combinations(range(N), rk), key=revlex_sort_key) if len(data) != len(subsets): - raise ValueError("expected string of length %s (%s choose %s), got %s" % - (len(subsets), N, rk, len(data))) - bases = [[groundset[c] for c in subsets[i]] - for i, x in enumerate(data) if x != '0'] + raise ValueError("expected string of length %s (%s choose %s), got %s" % (len(subsets), N, rk, len(data))) + bases = [[groundset[c] for c in subsets[i]] for i, x in enumerate(data) if x != '0'] M = BasisMatroid(groundset=groundset, bases=bases) # Circuit closures: diff --git a/src/sage/matroids/database_collections.py b/src/sage/matroids/database_collections.py index 774dee7723b..78a2319513a 100644 --- a/src/sage/matroids/database_collections.py +++ b/src/sage/matroids/database_collections.py @@ -162,6 +162,7 @@ def AllMatroids(n, r=None, type='all'): """ from sage.matroids.constructor import Matroid from sage.features.databases import DatabaseMatroids + DatabaseMatroids().require() import matroid_database @@ -169,11 +170,7 @@ def AllMatroids(n, r=None, type='all'): try: getattr(Matroid(bases=[[1, 2], [1, 3]]), 'is_' + type) except AttributeError: - raise AttributeError( - "The type '%s' is not available. " % type + - "There needs to be an 'is_%s()' attribute for the " % type + - "type to be supported." - ) + raise AttributeError("The type '%s' is not available. " % type + "There needs to be an 'is_%s()' attribute for the " % type + "type to be supported.") if r is None and type == 'unorientable': raise ValueError("The rank needs to be specified for type '%s'" % type) @@ -201,10 +198,7 @@ def AllMatroids(n, r=None, type='all'): try: matroids_bases(n, rp).__next__() except ValueError: - raise ValueError( - "(n=%s, r=%s, type='%s')" % (n, r, type) - + " is not available in the database" - ) + raise ValueError("(n=%s, r=%s, type='%s')" % (n, r, type) + " is not available in the database") cnt = 0 for B in matroids_bases(n, rp): @@ -246,29 +240,9 @@ def OxleyMatroids(): These matroids are the nonparametrized matroids that appear in the Appendix ``Some Interesting Matroids`` in [Oxl2011]_ (p. 639-64). """ - from sage.matroids.database_matroids import ( - U24, U25, U35, K4, Whirl3, Q6, P6, U36, R6, - Fano, FanoDual, NonFano, NonFanoDual, O7, P7, - AG32, AG32prime, R8, F8, Q8, L8, S8, Vamos, T8, J, P8, P8pp, - Wheel4, Whirl4, - K33dual, K33, AG23, TernaryDowling3, R9, Pappus, NonPappus, - K5, K5dual, R10, NonDesargues, - R12, ExtendedTernaryGolayCode, T12, - PG23 - ) - - lst = [U24, # 4 - U25, U35, # 5 - K4, Whirl3, Q6, P6, U36, R6, # 6 - Fano, FanoDual, NonFano, NonFanoDual, O7, P7, # 7 - AG32, AG32prime, - R8, F8, Q8, L8, S8, - Vamos, T8, J, P8, P8pp, - Wheel4, Whirl4, # 8 - K33dual, K33, AG23, TernaryDowling3, R9, Pappus, NonPappus, # 9 - K5, K5dual, R10, NonDesargues, # 10 - R12, ExtendedTernaryGolayCode, T12, # 12 - PG23] # 13 + from sage.matroids.database_matroids import U24, U25, U35, K4, Whirl3, Q6, P6, U36, R6, Fano, FanoDual, NonFano, NonFanoDual, O7, P7, AG32, AG32prime, R8, F8, Q8, L8, S8, Vamos, T8, J, P8, P8pp, Wheel4, Whirl4, K33dual, K33, AG23, TernaryDowling3, R9, Pappus, NonPappus, K5, K5dual, R10, NonDesargues, R12, ExtendedTernaryGolayCode, T12, PG23 + + lst = [U24, U25, U35, K4, Whirl3, Q6, P6, U36, R6, Fano, FanoDual, NonFano, NonFanoDual, O7, P7, AG32, AG32prime, R8, F8, Q8, L8, S8, Vamos, T8, J, P8, P8pp, Wheel4, Whirl4, K33dual, K33, AG23, TernaryDowling3, R9, Pappus, NonPappus, K5, K5dual, R10, NonDesargues, R12, ExtendedTernaryGolayCode, T12, PG23] # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 for M in lst: yield M() @@ -291,33 +265,9 @@ def BrettellMatroids(): :mod:`Matroid catalog `, under ``Brettell's matroid collection``. """ - from sage.matroids.database_matroids import ( - RelaxedNonFano, TippedFree3spike, - AG23minusDY, TQ8, P8p, KP8, Sp8, Sp8pp, LP8, WQ8, - BB9, TQ9, TQ9p, M8591, PP9, BB9gDY, A9, FN9, FX9, KR9, KQ9, - UG10, FF10, GP10, FZ10, UQ10, FP10, TQ10, FY10, PP10, FU10, D10, UK10, - PK10, GK10, FT10, TK10, KT10, TU10, UT10, FK10, KF10, - FA11, - FR12, GP12, FQ12, FF12, FZ12, UQ12, FP12, FS12, UK12, UA12, AK12, - FK12, KB12, AF12, NestOfTwistedCubes, - XY13, - N3, N3pp, UP14, VP14, FV14, OW14, FM14, - FA15, - N4 - ) - - lst = [RelaxedNonFano, TippedFree3spike, # 7 - AG23minusDY, TQ8, P8p, KP8, Sp8, Sp8pp, LP8, WQ8, # 8 - BB9, TQ9, TQ9p, M8591, PP9, BB9gDY, A9, FN9, FX9, KR9, KQ9, # 9 - UG10, FF10, GP10, FZ10, UQ10, FP10, TQ10, FY10, PP10, FU10, D10, - UK10, PK10, GK10, FT10, TK10, KT10, TU10, UT10, FK10, KF10, # 10 - FA11, # 11 - FR12, GP12, FQ12, FF12, FZ12, UQ12, FP12, FS12, UK12, UA12, AK12, - FK12, KB12, AF12, NestOfTwistedCubes, # 12 - XY13, # 13 - N3, N3pp, UP14, VP14, FV14, OW14, FM14, # 14 - FA15, # 15 - N4] # 16 + from sage.matroids.database_matroids import RelaxedNonFano, TippedFree3spike, AG23minusDY, TQ8, P8p, KP8, Sp8, Sp8pp, LP8, WQ8, BB9, TQ9, TQ9p, M8591, PP9, BB9gDY, A9, FN9, FX9, KR9, KQ9, UG10, FF10, GP10, FZ10, UQ10, FP10, TQ10, FY10, PP10, FU10, D10, UK10, PK10, GK10, FT10, TK10, KT10, TU10, UT10, FK10, KF10, FA11, FR12, GP12, FQ12, FF12, FZ12, UQ12, FP12, FS12, UK12, UA12, AK12, FK12, KB12, AF12, NestOfTwistedCubes, XY13, N3, N3pp, UP14, VP14, FV14, OW14, FM14, FA15, N4 + + lst = [RelaxedNonFano, TippedFree3spike, AG23minusDY, TQ8, P8p, KP8, Sp8, Sp8pp, LP8, WQ8, BB9, TQ9, TQ9p, M8591, PP9, BB9gDY, A9, FN9, FX9, KR9, KQ9, UG10, FF10, GP10, FZ10, UQ10, FP10, TQ10, FY10, PP10, FU10, D10, UK10, PK10, GK10, FT10, TK10, KT10, TU10, UT10, FK10, KF10, FA11, FR12, GP12, FQ12, FF12, FZ12, UQ12, FP12, FS12, UK12, UA12, AK12, FK12, KB12, AF12, NestOfTwistedCubes, XY13, N3, N3pp, UP14, VP14, FV14, OW14, FM14, FA15, N4] # 7 # 8 # 9 # 10 # 11 # 12 # 13 # 14 # 15 # 16 for M in lst: yield M() @@ -340,22 +290,8 @@ def VariousMatroids(): :mod:`Matroid catalog `, under ``Collection of various matroids``. """ - from sage.matroids.database_matroids import ( - NonVamos, NotP8, AG23minus, - P9, R9A, R9B, Block_9_4, TicTacToe, - N1, Block_10_5, Q10, - BetsyRoss, - N2, - D16, Terrahawk, - ExtendedBinaryGolayCode - ) - - lst = [NonVamos, NotP8, AG23minus, # 8 - P9, R9A, R9B, Block_9_4, TicTacToe, # 9 - N1, Block_10_5, Q10, # 10 - BetsyRoss, # 11 - N2, # 12 - D16, Terrahawk, # 16 - ExtendedBinaryGolayCode] # 24 + from sage.matroids.database_matroids import NonVamos, NotP8, AG23minus, P9, R9A, R9B, Block_9_4, TicTacToe, N1, Block_10_5, Q10, BetsyRoss, N2, D16, Terrahawk, ExtendedBinaryGolayCode + + lst = [NonVamos, NotP8, AG23minus, P9, R9A, R9B, Block_9_4, TicTacToe, N1, Block_10_5, Q10, BetsyRoss, N2, D16, Terrahawk, ExtendedBinaryGolayCode] # 8 # 9 # 10 # 11 # 12 # 16 # 24 for M in lst: yield M() diff --git a/src/sage/matroids/database_matroids.py b/src/sage/matroids/database_matroids.py index e10ef26b3bd..b7ecffad204 100644 --- a/src/sage/matroids/database_matroids.py +++ b/src/sage/matroids/database_matroids.py @@ -38,12 +38,7 @@ from sage.matrix.constructor import Matrix from sage.matroids.constructor import Matroid -from sage.matroids.linear_matroid import ( - RegularMatroid, - BinaryMatroid, - TernaryMatroid, - QuaternaryMatroid -) +from sage.matroids.linear_matroid import RegularMatroid, BinaryMatroid, TernaryMatroid, QuaternaryMatroid from sage.rings.integer_ring import ZZ from sage.rings.finite_rings.finite_field_constructor import GF from sage.schemes.projective.projective_space import ProjectiveSpace @@ -289,8 +284,7 @@ def Q6(groundset='abcdef'): A = Matrix(F, [[1, 0, 0, 1, 0, 1], [0, 1, 0, 1, 1, x], [0, 0, 1, 0, 1, 1]]) M = QuaternaryMatroid(A, groundset) M = _rename_and_relabel(M, "Q6") - pos = dict(zip(groundset, [(1, -1), (-1, 0), (1, 1), - (0, -0.5), (0, 0.5), (1.5, 0)])) + pos = dict(zip(groundset, [(1, -1), (-1, 0), (1, 1), (0, -0.5), (0, 0.5), (1.5, 0)])) M._fix_positions(pos_dict=pos) return M @@ -325,8 +319,7 @@ def P6(groundset=None): CC = {2: ['abc'], 3: ['abcdef']} M = Matroid(circuit_closures=CC) M = _rename_and_relabel(M, "P6", groundset) - pos = dict(zip(groundset or 'abcdef', - [(-1, 0), (0, 0), (1, 0), (-0.8, 0.7), (0, 1), (0.8, 0.7)])) + pos = dict(zip(groundset or 'abcdef', [(-1, 0), (0, 0), (1, 0), (-0.8, 0.7), (0, 1), (0.8, 0.7)])) M._fix_positions(pos_dict=pos) return M @@ -393,13 +386,10 @@ def R6(groundset='abcdef'): [Oxl2011]_, p. 642. """ - A = Matrix( - GF(3), [[1, 0, 0, 1, 1, 1], [0, 1, 0, 1, 2, 1], [0, 0, 1, 1, 0, 2]] - ) + A = Matrix(GF(3), [[1, 0, 0, 1, 1, 1], [0, 1, 0, 1, 2, 1], [0, 0, 1, 1, 0, 2]]) M = TernaryMatroid(A, groundset) M = _rename_and_relabel(M, "R6") - pos = dict(zip(groundset, [(-1, 0), (1, 0), (1, 1), - (-1, 1), (0, 0), (0, 1)])) + pos = dict(zip(groundset, [(-1, 0), (1, 0), (1, 1), (-1, 1), (0, 0), (0, 1)])) M._fix_positions(pos_dict=pos) return M @@ -445,10 +435,7 @@ def Fano(groundset='abcdefg'): [Oxl2011]_, p. 643. """ - A = Matrix( - GF(2), - [[1, 0, 0, 0, 1, 1, 1], [0, 1, 0, 1, 0, 1, 1], [0, 0, 1, 1, 1, 0, 1]] - ) + A = Matrix(GF(2), [[1, 0, 0, 0, 1, 1, 1], [0, 1, 0, 1, 0, 1, 1], [0, 0, 1, 1, 1, 0, 1]]) M = BinaryMatroid(A, groundset) M = _rename_and_relabel(M, "Fano") return M @@ -520,10 +507,7 @@ def NonFano(groundset='abcdefg'): [Oxl2011]_, p. 643-4. """ - A = Matrix( - GF(3), - [[1, 0, 0, 0, 1, 1, 1], [0, 1, 0, 1, 0, 1, 1], [0, 0, 1, 1, 1, 0, 1]] - ) + A = Matrix(GF(3), [[1, 0, 0, 0, 1, 1, 1], [0, 1, 0, 1, 0, 1, 1], [0, 0, 1, 1, 1, 0, 1]]) M = TernaryMatroid(A, groundset) M = _rename_and_relabel(M, "NonFano") return M @@ -592,10 +576,7 @@ def O7(groundset='abcdefg'): [Oxl2011]_, p. 644. """ - A = Matrix( - GF(3), - [[1, 0, 0, 1, 1, 1, 1], [0, 1, 0, 0, 1, 2, 2], [0, 0, 1, 1, 0, 1, 0]] - ) + A = Matrix(GF(3), [[1, 0, 0, 1, 1, 1, 1], [0, 1, 0, 0, 1, 2, 2], [0, 0, 1, 1, 0, 1, 0]]) M = TernaryMatroid(A, groundset) M = _rename_and_relabel(M, "O7") return M @@ -625,14 +606,10 @@ def P7(groundset='abcdefg'): [Oxl2011]_, p. 644-5. """ - A = Matrix( - GF(3), - [[1, 0, 0, 2, 1, 1, 0], [0, 1, 0, 1, 1, 0, 1], [0, 0, 1, 1, 0, 1, 1]] - ) + A = Matrix(GF(3), [[1, 0, 0, 2, 1, 1, 0], [0, 1, 0, 1, 1, 0, 1], [0, 0, 1, 1, 0, 1, 1]]) M = TernaryMatroid(A, groundset) M = _rename_and_relabel(M, "P7") - pos = dict(zip(groundset, [(0, 1), (-1, -1), (1, -1), (0, 0), (-0.5, 0), - (0.5, 0), (0, -1)])) + pos = dict(zip(groundset, [(0, 1), (-1, -1), (1, -1), (0, 0), (-0.5, 0), (0.5, 0), (0, -1)])) M._fix_positions(pos_dict=pos) return M @@ -737,8 +714,19 @@ def AG32prime(groundset=None): """ CC = { 3: [ - 'abfg', 'bcdg', 'defg', 'cdeh', 'aefh', 'abch', 'abed', - 'cfgh', 'bcef', 'adgh', 'acdf', 'begh', 'aceg', + 'abfg', + 'bcdg', + 'defg', + 'cdeh', + 'aefh', + 'abch', + 'abed', + 'cfgh', + 'bcef', + 'adgh', + 'acdf', + 'begh', + 'aceg', ], 4: ['abcdefgh'], } @@ -836,9 +824,18 @@ def F8(groundset=None): """ CC = { 3: [ - 'abfg', 'bcdg', 'defg', 'cdeh', - 'aefh', 'abch', 'abed', 'cfgh', - 'bcef', 'adgh', 'acdf', 'aceg', + 'abfg', + 'bcdg', + 'defg', + 'cdeh', + 'aefh', + 'abch', + 'abed', + 'cfgh', + 'bcef', + 'adgh', + 'acdf', + 'aceg', ], 4: ['abcdefgh'], } @@ -886,8 +883,17 @@ def Q8(groundset=None): """ CC = { 3: [ - 'abfg', 'bcdg', 'defg', 'cdeh', 'aefh', 'abch', - 'abed', 'cfgh', 'bcef', 'adgh', 'acdf', + 'abfg', + 'bcdg', + 'defg', + 'cdeh', + 'aefh', + 'abch', + 'abed', + 'cfgh', + 'bcef', + 'adgh', + 'acdf', ], 4: ['abcdefgh'], } @@ -936,8 +942,7 @@ def L8(groundset=None): [Oxl2011]_, p. 648. """ - CC = {3: ['abfg', 'bcdg', 'defg', 'cdeh', 'aefh', 'abch', 'aceg', 'bdfh'], - 4: ['abcdefgh']} + CC = {3: ['abfg', 'bcdg', 'defg', 'cdeh', 'aefh', 'abch', 'aceg', 'bdfh'], 4: ['abcdefgh']} M = Matroid(circuit_closures=CC) M = _rename_and_relabel(M, "L8", groundset) return M @@ -1393,8 +1398,7 @@ def R9(groundset=None): [Oxl2011]_, p. 654. """ - NSC = ['abc', 'abd', 'acd', 'aef', 'agh', 'bcd', 'bfh', 'bgi', - 'ceg', 'cfi', 'deh', 'dei', 'dfg', 'dhi', 'ehi'] + NSC = ['abc', 'abd', 'acd', 'aef', 'agh', 'bcd', 'bfh', 'bgi', 'ceg', 'cfi', 'deh', 'dei', 'dfg', 'dhi', 'ehi'] M = Matroid(rank=3, nonspanning_circuits=NSC) M = _rename_and_relabel(M, "R9", groundset) return M @@ -1703,14 +1707,7 @@ def ExtendedTernaryGolayCode(groundset='abcdefghijkl'): [Oxl2011]_, p. 658. """ - A = Matrix(GF(3), [ - [1, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 0], - [0, 1, 0, 0, 0, 0, 1, 1, 2, 1, 0, 2], - [0, 0, 1, 0, 0, 0, 1, 2, 1, 0, 1, 2], - [0, 0, 0, 1, 0, 0, 1, 2, 0, 1, 2, 1], - [0, 0, 0, 0, 1, 0, 1, 0, 2, 2, 1, 1], - [0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1] - ]) + A = Matrix(GF(3), [[1, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 0], [0, 1, 0, 0, 0, 0, 1, 1, 2, 1, 0, 2], [0, 0, 1, 0, 0, 0, 1, 2, 1, 0, 1, 2], [0, 0, 0, 1, 0, 0, 1, 2, 0, 1, 2, 1], [0, 0, 0, 0, 1, 0, 1, 0, 2, 2, 1, 1], [0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1]]) M = TernaryMatroid(A, groundset) M = _rename_and_relabel(M, "Extended Ternary Golay Code") return M @@ -2060,9 +2057,7 @@ def AG(n, q, x=None, groundset=None): x = 'x' F = GF(q, x) P = ProjectiveSpace(n, F) - A = Matrix( - F, [list(p) for p in list(P) if not list(p)[0] == 0] - ).transpose() + A = Matrix(F, [list(p) for p in list(P) if not list(p)[0] == 0]).transpose() M = Matroid(A) M = _rename_and_relabel(M, f'AG({n}, {q})', groundset) return M @@ -2142,6 +2137,7 @@ def Z(r, t=True, groundset=None): [Oxl2011]_, p. 661-2. """ from sage.matrix.special import identity_matrix, ones_matrix + Id = Matrix(GF(2), identity_matrix(r)) J = Matrix(GF(2), ones_matrix(r)) tip = Matrix(GF(2), ones_matrix(r, 1)) @@ -2255,23 +2251,17 @@ def Spike(r, t=True, C3=[], groundset=None): if C3 == [] and r > 3: # free spike (can be defined fast through circuit closures) lines = [['t', f'x{i}', f'y{i}'] for i in range(1, r + 1)] - planes = [['t', f'x{i}', f'y{i}', f'x{j}', f'y{j}'] - for i in range(1, r + 1) for j in range(i + 1, r + 1)] + planes = [['t', f'x{i}', f'y{i}', f'x{j}', f'y{j}'] for i in range(1, r + 1) for j in range(i + 1, r + 1)] CC = {2: lines, 3: planes, r: [E]} M = Matroid(circuit_closures=CC) else: for S in C3: for xy in S: if xy not in X + Y: - raise ValueError( - "The sets in C3 must contain elements xi and yi only." - ) + raise ValueError("The sets in C3 must contain elements xi and yi only.") for T in C3: if S != T and len(set(S).intersection(set(T))) > r - 2: - raise ValueError( - "Every pair of sets in C3 must not have more than " - + "r - 2 common elements." - ) + raise ValueError("Every pair of sets in C3 must not have more than " + "r - 2 common elements.") NSC = [] # nonspanning_circuits NSC += C3 @@ -2348,6 +2338,7 @@ def Theta(n, groundset=None): Y = [f'y{i}' for i in range(n)] import itertools + C = [] C += list(itertools.combinations(X, 3)) for i in range(n): @@ -2496,9 +2487,7 @@ def TippedFree3spike(groundset=None): GF4 = GF(4, 'w') w = GF4('w') A = Matrix(GF4, [[1, 1, 1, 1], [1, w + 1, 0, w], [1, 0, w + 1, w]]) - M = QuaternaryMatroid( - reduced_matrix=A, groundset=[0, 3, 5, 1, 4, 6, 2] - ) + M = QuaternaryMatroid(reduced_matrix=A, groundset=[0, 3, 5, 1, 4, 6, 2]) M = _rename_and_relabel(M, "Tipped rank-3 free spike", groundset) return M @@ -2542,12 +2531,8 @@ def TQ8(groundset=None): """ GF4 = GF(4, 'w') w = GF4('w') - A = Matrix( - GF4, [[0, w, 1, 1], [1, 0, w, w + 1], [1, w, 0, w], [1, w + 1, 1, 0]] - ) - M = QuaternaryMatroid( - reduced_matrix=A, groundset=[1, 7, 5, 3, 8, 6, 4, 2] - ) + A = Matrix(GF4, [[0, w, 1, 1], [1, 0, w, w + 1], [1, w, 0, w], [1, w + 1, 1, 0]]) + M = QuaternaryMatroid(reduced_matrix=A, groundset=[1, 7, 5, 3, 8, 6, 4, 2]) M = _rename_and_relabel(M, "TQ8", groundset) return M @@ -2569,12 +2554,8 @@ def P8p(groundset=None): """ GF4 = GF(4, 'w') w = GF4('w') - A = Matrix( - GF4, [[1, 1, 1, w], [1, w + 1, 1, 0], [1, 0, w, w], [0, 1, 1, 1]] - ) - M = QuaternaryMatroid( - reduced_matrix=A, groundset=['a', 'c', 'b', 'f', 'd', 'e', 'g', 'h'] - ) + A = Matrix(GF4, [[1, 1, 1, w], [1, w + 1, 1, 0], [1, 0, w, w], [0, 1, 1, 1]]) + M = QuaternaryMatroid(reduced_matrix=A, groundset=['a', 'c', 'b', 'f', 'd', 'e', 'g', 'h']) M = _rename_and_relabel(M, "P8-", groundset) return M @@ -2596,12 +2577,8 @@ def KP8(groundset=None): """ GF4 = GF(4, 'w') w = GF4('w') - A = Matrix( - GF4, [[0, 1, 1, 1], [1, 0, w, w], [1, 1, 1, 1 + w], [1, 1, 1 + w, 0]] - ) - M = QuaternaryMatroid( - reduced_matrix=A, groundset=[1, 4, 3, 5, 6, 7, 0, 2] - ) + A = Matrix(GF4, [[0, 1, 1, 1], [1, 0, w, w], [1, 1, 1, 1 + w], [1, 1, 1 + w, 0]]) + M = QuaternaryMatroid(reduced_matrix=A, groundset=[1, 4, 3, 5, 6, 7, 0, 2]) M = _rename_and_relabel(M, "KP8", groundset) return M @@ -2623,12 +2600,8 @@ def Sp8(groundset=None): """ GF4 = GF(4, 'w') w = GF4('w') - A = Matrix( - GF4, [[1, 1, w + 1, 0], [1, 1, 0, w + 1], [1, 0, w, w], [0, 1, 1, 1]] - ) - M = QuaternaryMatroid( - reduced_matrix=A, groundset=[1, 2, 3, 5, 4, 6, 7, 8] - ) + A = Matrix(GF4, [[1, 1, w + 1, 0], [1, 1, 0, w + 1], [1, 0, w, w], [0, 1, 1, 1]]) + M = QuaternaryMatroid(reduced_matrix=A, groundset=[1, 2, 3, 5, 4, 6, 7, 8]) M = _rename_and_relabel(M, "Sp8", groundset) return M @@ -2651,9 +2624,7 @@ def Sp8pp(groundset=None): GF4 = GF(4, 'w') w = GF4('w') A = Matrix(GF4, [[1, w, 1, 0], [1, 1, 1, 1], [w, 0, 1, w], [0, w, 1, 1]]) - M = QuaternaryMatroid( - reduced_matrix=A, groundset=[1, 5, 6, 7, 2, 3, 4, 8] - ) + M = QuaternaryMatroid(reduced_matrix=A, groundset=[1, 5, 6, 7, 2, 3, 4, 8]) M = _rename_and_relabel(M, "Sp8=", groundset) return M @@ -2675,12 +2646,8 @@ def LP8(groundset=None): """ GF4 = GF(4, 'w') w = GF4('w') - A = Matrix( - GF4, [[1, 1, 1, 1], [w + 1, w, 0, 1], [1, 0, w + 1, 1], [0, w, w, 1]] - ) - M = QuaternaryMatroid( - reduced_matrix=A, groundset=['a', 'b', 'd', 'e', 'c', 'f', 'g', 'h'] - ) + A = Matrix(GF4, [[1, 1, 1, 1], [w + 1, w, 0, 1], [1, 0, w + 1, 1], [0, w, w, 1]]) + M = QuaternaryMatroid(reduced_matrix=A, groundset=['a', 'b', 'd', 'e', 'c', 'f', 'g', 'h']) M = _rename_and_relabel(M, "LP8", groundset) return M @@ -2702,12 +2669,8 @@ def WQ8(groundset=None): """ GF4 = GF(4, 'w') w = GF4('w') - A = Matrix( - GF4, [[1, 0, 1, w + 1], [1, 1, 1, 1], [w, 1, 1, 0], [0, w, 1, 1]] - ) - M = QuaternaryMatroid( - reduced_matrix=A, groundset=[0, 1, 3, 4, 2, 5, 6, 7] - ) + A = Matrix(GF4, [[1, 0, 1, w + 1], [1, 1, 1, 1], [w, 1, 1, 0], [0, w, 1, 1]]) + M = QuaternaryMatroid(reduced_matrix=A, groundset=[0, 1, 3, 4, 2, 5, 6, 7]) M = _rename_and_relabel(M, "WQ8", groundset) return M @@ -2741,15 +2704,8 @@ def BB9(groundset=None): """ GF4 = GF(4, 'w') w = GF4('w') - A = Matrix( - GF4, [[1, 0, 1, 1, 1, 1], - [0, 1, w, 1, 0, w], - [w + 1, 1, w + 1, 1, w, 0]] - ) - M = QuaternaryMatroid( - reduced_matrix=A, - groundset=['i', 'b', 'd', 'j', 'h', 'f', 'c', 'a', 'k'] - ) + A = Matrix(GF4, [[1, 0, 1, 1, 1, 1], [0, 1, w, 1, 0, w], [w + 1, 1, w + 1, 1, w, 0]]) + M = QuaternaryMatroid(reduced_matrix=A, groundset=['i', 'b', 'd', 'j', 'h', 'f', 'c', 'a', 'k']) M = _rename_and_relabel(M, "BB9", groundset) return M @@ -2777,14 +2733,10 @@ def TQ9(groundset=None): GF4 = GF(4, 'w') w = GF4('w') A = Matrix( - GF4, [[1, 0, w, 1, 1], - [w + 1, 0, 0, w, 1], - [1, w, 0, 0, w + 1], - [1, 1, 1, 1, 0]], - ) - M = QuaternaryMatroid( - reduced_matrix=A, groundset=[1, 4, 6, 0, 2, 5, 3, 7, 8] + GF4, + [[1, 0, w, 1, 1], [w + 1, 0, 0, w, 1], [1, w, 0, 0, w + 1], [1, 1, 1, 1, 0]], ) + M = QuaternaryMatroid(reduced_matrix=A, groundset=[1, 4, 6, 0, 2, 5, 3, 7, 8]) M = _rename_and_relabel(M, "TQ9", groundset) return M @@ -2821,9 +2773,7 @@ def TQ9p(groundset=None): [0, 1, w + 1, w + 1, 0], ], ) - M = QuaternaryMatroid( - reduced_matrix=A, groundset=[1, 4, 7, 8, 0, 6, 5, 2, 3] - ) + M = QuaternaryMatroid(reduced_matrix=A, groundset=[1, 4, 7, 8, 0, 6, 5, 2, 3]) M = _rename_and_relabel(M, "TQ9'", groundset) return M @@ -2845,12 +2795,7 @@ def M8591(groundset=None): """ GF4 = GF(4, 'w') w = GF4('w') - A = Matrix( - GF4, [[1, 1, 0, w, 1], - [0, 1, 1, w, w + 1], - [1, 0, w, w, 1], - [0, 0, 1, 1, 0]] - ) + A = Matrix(GF4, [[1, 1, 0, w, 1], [0, 1, 1, w, w + 1], [1, 0, w, w, 1], [0, 0, 1, 1, 0]]) M = QuaternaryMatroid(reduced_matrix=A) M = _rename_and_relabel(M, "M8591", groundset) return M @@ -2882,16 +2827,8 @@ def PP9(groundset=None): """ GF4 = GF(4, 'w') w = GF4('w') - A = Matrix( - GF4, [[1, 1, 1, w, w], - [1, 1 + w, 1, 0, w], - [1, 0, w, w, w], - [0, 1, 1, 1, 1]] - ) - M = QuaternaryMatroid( - reduced_matrix=A, - groundset=['a', 'c', 'b', 'f', 'd', 'e', 'g', 'h', 'z'] - ) + A = Matrix(GF4, [[1, 1, 1, w, w], [1, 1 + w, 1, 0, w], [1, 0, w, w, w], [0, 1, 1, 1, 1]]) + M = QuaternaryMatroid(reduced_matrix=A, groundset=['a', 'c', 'b', 'f', 'd', 'e', 'g', 'h', 'z']) M = _rename_and_relabel(M, "PP9", groundset) return M @@ -2926,10 +2863,7 @@ def BB9gDY(groundset=None): ], ) # M9573 - M = QuaternaryMatroid( - reduced_matrix=A, - groundset=['c', 'd', 'i', 'f', 'h', 'a', 'j', 'k', 'b'] - ) + M = QuaternaryMatroid(reduced_matrix=A, groundset=['c', 'd', 'i', 'f', 'h', 'a', 'j', 'k', 'b']) M = _rename_and_relabel(M, "Segment cosegment exchange on BB9", groundset) return M @@ -2951,14 +2885,8 @@ def A9(groundset=None): """ GF4 = GF(4, 'w') w = GF4('w') - A = Matrix( - GF4, [[w + 1, 1, w, w, w, w], - [0, 1, 1, w + 1, 0, w], - [w, 0, 1, w + 1, w, 1]] - ) - M = QuaternaryMatroid( - reduced_matrix=A, groundset=[6, 5, 4, 1, 2, 3, 7, 8, 0] - ) + A = Matrix(GF4, [[w + 1, 1, w, w, w, w], [0, 1, 1, w + 1, 0, w], [w, 0, 1, w + 1, w, 1]]) + M = QuaternaryMatroid(reduced_matrix=A, groundset=[6, 5, 4, 1, 2, 3, 7, 8, 0]) M = _rename_and_relabel(M, "A9", groundset) return M @@ -2989,10 +2917,7 @@ def FN9(groundset=None): ], ) # M3209 - M = QuaternaryMatroid( - reduced_matrix=A, - groundset=['b0', 'a', 'y', 'z', 'x', "c0", 'b', 'c', 'a0'] - ) + M = QuaternaryMatroid(reduced_matrix=A, groundset=['b0', 'a', 'y', 'z', 'x', "c0", 'b', 'c', 'a0']) M = _rename_and_relabel(M, "FN9", groundset) return M @@ -3057,9 +2982,7 @@ def KR9(groundset=None): [w + 1, w + 1, w, w + 1, 0], ], ) - M = QuaternaryMatroid( - reduced_matrix=A, groundset=[2, 4, 0, 6, 1, 5, 3, 7, 8] - ) + M = QuaternaryMatroid(reduced_matrix=A, groundset=[2, 4, 0, 6, 1, 5, 3, 7, 8]) M = _rename_and_relabel(M, "KR9", groundset) return M @@ -3096,9 +3019,7 @@ def KQ9(groundset=None): [1, 1, w + 1, 0, w + 1], ], ) - M = QuaternaryMatroid( - reduced_matrix=A, groundset=[5, 0, 4, 3, 2, 6, 8, 7, 1] - ) + M = QuaternaryMatroid(reduced_matrix=A, groundset=[5, 0, 4, 3, 2, 6, 8, 7, 1]) M = _rename_and_relabel(M, "KQ9", groundset) return M @@ -3166,9 +3087,7 @@ def FF10(groundset=None): [1 + w, 1 + w, w, w, 1 + w], ], ) - M = QuaternaryMatroid( - reduced_matrix=A, groundset=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - ) + M = QuaternaryMatroid(reduced_matrix=A, groundset=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) M = _rename_and_relabel(M, "FF10", groundset) return M @@ -3327,9 +3246,7 @@ def TQ10(groundset=None): [w + 1, 0, w, w + 1, 0], ], ) - M = QuaternaryMatroid( - reduced_matrix=A, groundset=[1, 6, 8, 'c', 3, 7, 'd', 2, 5, 4] - ) + M = QuaternaryMatroid(reduced_matrix=A, groundset=[1, 6, 8, 'c', 3, 7, 'd', 2, 5, 4]) M = _rename_and_relabel(M, "TQ10", groundset) return M @@ -3398,10 +3315,7 @@ def PP10(groundset=None): [w, 1, w + 1, w, w + 1], ], ) - M = QuaternaryMatroid( - reduced_matrix=A, - groundset=['z', 'f', 'c', 'g', 'e', 'b', 'a', 'h', 'd', 'x'] - ) + M = QuaternaryMatroid(reduced_matrix=A, groundset=['z', 'f', 'c', 'g', 'e', 'b', 'a', 'h', 'd', 'x']) M = _rename_and_relabel(M, "PP10", groundset) return M @@ -3808,9 +3722,7 @@ def FA11(groundset=None): [w + 1, w + 1, w + 1, 0, w, 0], ], ) - M = QuaternaryMatroid( - reduced_matrix=A, groundset=[1, 3, 4, 2, 8, 7, 9, 0, 5, 10, 6] - ) + M = QuaternaryMatroid(reduced_matrix=A, groundset=[1, 3, 4, 2, 8, 7, 9, 0, 5, 10, 6]) M = _rename_and_relabel(M, "FA11", groundset) return M @@ -3916,9 +3828,7 @@ def FQ12(groundset=None): [0, 1, 1, w, w + 1, 1], ], ) - M = QuaternaryMatroid( - reduced_matrix=A, groundset=[7, 4, 5, 9, 2, 1, 0, 6, 'd', 'c', 8, 3] - ) + M = QuaternaryMatroid(reduced_matrix=A, groundset=[7, 4, 5, 9, 2, 1, 0, 6, 'd', 'c', 8, 3]) M = _rename_and_relabel(M, "FQ12", groundset) return M @@ -3955,9 +3865,7 @@ def FF12(groundset=None): [1, w + 1, 1, 0, w + 1, w], ], ) - M = QuaternaryMatroid( - reduced_matrix=A, groundset=[0, 4, 'c', 3, 5, 'd', 8, 9, 2, 7, 1, 6] - ) + M = QuaternaryMatroid(reduced_matrix=A, groundset=[0, 4, 'c', 3, 5, 'd', 8, 9, 2, 7, 1, 6]) M = _rename_and_relabel(M, "FF12", groundset) return M @@ -4295,12 +4203,12 @@ def NestOfTwistedCubes(groundset=None): sage: M.is_3connected() True """ + # utility function def complement(groundset, subset): return list(set(groundset).difference(subset)) - gs = ["e1", "e2", "e3", "e4", "e5", "e6", - "f1", "f2", "f3", "f4", "f5", "f6"] + gs = ["e1", "e2", "e3", "e4", "e5", "e6", "f1", "f2", "f3", "f4", "f5", "f6"] M = Matroid( groundset=gs, circuit_closures={ @@ -4729,10 +4637,7 @@ def NonVamos(groundset=None): [Oxl2011]_, p. 72, 84. """ - CC = { - 3: ['abcd', 'abef', 'cdef', 'abgh', 'cdgh', 'efgh'], - 4: ['abcdefgh'] - } + CC = {3: ['abcd', 'abef', 'cdef', 'abgh', 'cdgh', 'efgh'], 4: ['abcdefgh']} M = Matroid(circuit_closures=CC) M = _rename_and_relabel(M, "NonVamos", groundset) return M @@ -4756,12 +4661,7 @@ def NotP8(groundset='abcdefgh'): [Oxl1992]_, p.512 (the first edition). """ - A = Matrix(GF(3), [ - [1, 0, 0, 0, 0, 1, 1, -1], - [0, 1, 0, 0, 1, 0, 1, 1], - [0, 0, 1, 0, 1, 1, 0, 1], - [0, 0, 0, 1, -1, 1, 1, 1] - ]) + A = Matrix(GF(3), [[1, 0, 0, 0, 0, 1, 1, -1], [0, 1, 0, 0, 1, 0, 1, 1], [0, 0, 1, 0, 1, 1, 0, 1], [0, 0, 0, 1, -1, 1, 1, 1]]) M = TernaryMatroid(A, groundset) M = _rename_and_relabel(M, "NotP8") return M @@ -4789,8 +4689,7 @@ class of near-regular matroids. [Oxl2011]_, p. 653. """ - CC = {2: ['abc', 'ceh', 'fgh', 'adf', 'aeg', 'cdg', 'bdh', 'bef'], - 3: ['abcdefgh']} + CC = {2: ['abc', 'ceh', 'fgh', 'adf', 'aeg', 'cdg', 'bdh', 'bef'], 3: ['abcdefgh']} M = Matroid(circuit_closures=CC) M = _rename_and_relabel(M, "AG23minus", groundset) return M @@ -4812,12 +4711,7 @@ def P9(groundset='abcdefghi'): This is the matroid referred to as `P_9` by Oxley in his paper "The binary matroids with no 4-wheel minor", [Oxl1987]_. """ - A = Matrix(GF(2), [ - [1, 0, 0, 0, 1, 0, 0, 1, 1], - [0, 1, 0, 0, 1, 1, 0, 0, 1], - [0, 0, 1, 0, 0, 1, 1, 0, 1], - [0, 0, 0, 1, 0, 0, 1, 1, 0] - ]) + A = Matrix(GF(2), [[1, 0, 0, 0, 1, 0, 0, 1, 1], [0, 1, 0, 0, 1, 1, 0, 0, 1], [0, 0, 1, 0, 0, 1, 1, 0, 1], [0, 0, 0, 1, 0, 0, 1, 1, 0]]) M = BinaryMatroid(A, groundset) M = _rename_and_relabel(M, "P9") return M @@ -4839,8 +4733,7 @@ def R9A(groundset=None): sage: M.is_valid() True """ - NSC = ['abch', 'abde', 'abfi', 'acdi', 'aceg', 'adgh', 'aefh', 'bcdf', - 'bdhi', 'begi', 'cehi', 'defi', 'fghi'] + NSC = ['abch', 'abde', 'abfi', 'acdi', 'aceg', 'adgh', 'aefh', 'bcdf', 'bdhi', 'begi', 'cehi', 'defi', 'fghi'] M = Matroid(rank=4, nonspanning_circuits=NSC) M = _rename_and_relabel(M, "R9A", groundset) return M @@ -4862,8 +4755,7 @@ def R9B(groundset=None): sage: M.is_valid() and M.is_paving() True """ - NSC = ['abde', 'bcdf', 'aceg', 'abch', 'befh', 'cdgh', 'bcei', 'adfi', - 'abgi', 'degi', 'bdhi', 'aehi', 'fghi'] + NSC = ['abde', 'bcdf', 'aceg', 'abch', 'befh', 'cdgh', 'bcei', 'adfi', 'abgi', 'degi', 'bdhi', 'aehi', 'fghi'] M = Matroid(rank=4, nonspanning_circuits=NSC) M = _rename_and_relabel(M, "R9B", groundset) return M @@ -4885,9 +4777,7 @@ def Block_9_4(groundset=None): sage: BD.is_t_design(return_parameters=True) (True, (2, 9, 4, 3)) """ - NSC = ['abcd', 'acef', 'bdef', 'cdeg', 'abfg', 'adeh', 'bcfh', 'acgh', - 'begh', 'dfgh', 'abei', 'cdfi', 'bcgi', 'adgi', 'efgi', 'bdhi', - 'cehi', 'afhi'] + NSC = ['abcd', 'acef', 'bdef', 'cdeg', 'abfg', 'adeh', 'bcfh', 'acgh', 'begh', 'dfgh', 'abei', 'cdfi', 'bcgi', 'adgi', 'efgi', 'bdhi', 'cehi', 'afhi'] M = Matroid(rank=4, nonspanning_circuits=NSC) M = _rename_and_relabel(M, "Block(9, 4)", groundset) return M @@ -4911,8 +4801,7 @@ def TicTacToe(groundset=None): [Hoc]_ """ - NSC = ['abcdg', 'adefg', 'abceh', 'abcfi', 'cdefi', 'adghi', 'beghi', - 'cfghi'] + NSC = ['abcdg', 'adefg', 'abceh', 'abcfi', 'cdefi', 'adghi', 'beghi', 'cfghi'] M = Matroid(rank=5, nonspanning_circuits=NSC) M = _rename_and_relabel(M, "TicTacToe", groundset) return M @@ -4937,13 +4826,7 @@ def N1(groundset='abcdefghij'): [Oxl2011]_, p. 554. """ - A = Matrix(GF(3), [ - [1, 0, 0, 0, 0, 2, 0, 0, 1, 1], - [0, 1, 0, 0, 0, 1, 2, 0, 0, 1], - [0, 0, 1, 0, 0, 0, 1, 2, 0, 1], - [0, 0, 0, 1, 0, 0, 0, 1, 2, 2], - [0, 0, 0, 0, 1, 1, 1, 1, 2, 0] - ]) + A = Matrix(GF(3), [[1, 0, 0, 0, 0, 2, 0, 0, 1, 1], [0, 1, 0, 0, 0, 1, 2, 0, 0, 1], [0, 0, 1, 0, 0, 0, 1, 2, 0, 1], [0, 0, 0, 1, 0, 0, 0, 1, 2, 2], [0, 0, 0, 0, 1, 1, 1, 1, 2, 0]]) M = TernaryMatroid(A, groundset) M = _rename_and_relabel(M, "N1") return M @@ -4965,12 +4848,7 @@ def Block_10_5(groundset=None): sage: BD.is_t_design(return_parameters=True) (True, (3, 10, 5, 3)) """ - NSC = ['abcde', 'acdfg', 'bdefg', 'bcdfh', 'abefh', 'abcgh', 'adegh', - 'cefgh', 'bcefi', 'adefi', 'bcdgi', 'acegi', 'abfgi', 'abdhi', - 'cdehi', 'acfhi', 'beghi', 'dfghi', 'abdfj', 'acefj', 'abegj', - 'cdegj', 'bcfgj', 'acdhj', 'bcehj', 'defhj', 'bdghj', 'afghj', - 'abcij', 'bdeij', 'cdfij', 'adgij', 'efgij', 'aehij', 'bfhij', - 'cghij'] + NSC = ['abcde', 'acdfg', 'bdefg', 'bcdfh', 'abefh', 'abcgh', 'adegh', 'cefgh', 'bcefi', 'adefi', 'bcdgi', 'acegi', 'abfgi', 'abdhi', 'cdehi', 'acfhi', 'beghi', 'dfghi', 'abdfj', 'acefj', 'abegj', 'cdegj', 'bcfgj', 'acdhj', 'bcehj', 'defhj', 'bdghj', 'afghj', 'abcij', 'bdeij', 'cdfij', 'adgij', 'efgij', 'aehij', 'bfhij', 'cghij'] M = Matroid(rank=5, nonspanning_circuits=NSC) M = _rename_and_relabel(M, "Block(10, 5)", groundset) return M @@ -5006,13 +4884,7 @@ def Q10(groundset='abcdefghij'): """ F = GF(4, 'x') x = F.gens()[0] - A = Matrix(F, [ - [1, 0, 0, 0, 0, 1, x, 0, 0, x + 1], - [0, 1, 0, 0, 0, x + 1, 1, x, 0, 0], - [0, 0, 1, 0, 0, 0, x + 1, 1, x, 0], - [0, 0, 0, 1, 0, 0, 0, x + 1, 1, x], - [0, 0, 0, 0, 1, x, 0, 0, x + 1, 1] - ]) + A = Matrix(F, [[1, 0, 0, 0, 0, 1, x, 0, 0, x + 1], [0, 1, 0, 0, 0, x + 1, 1, x, 0, 0], [0, 0, 1, 0, 0, 0, x + 1, 1, x, 0], [0, 0, 0, 1, 0, 0, 0, x + 1, 1, x], [0, 0, 0, 0, 1, x, 0, 0, x + 1, 1]]) M = QuaternaryMatroid(A, groundset) M = _rename_and_relabel(M, "Q10") return M @@ -5036,23 +4908,10 @@ def BetsyRoss(groundset=None): sage: M.is_valid() True """ - NSC = ['acf', 'acg', 'adi', 'adj', 'afg', 'ahk', 'aij', 'bdg', 'bdh', - 'bef', 'bej', 'bfj', 'bgh', 'bik', 'ceh', 'cei', 'cfg', 'chi', - 'cjk', 'dfk', 'dgh', 'dij', 'efj', 'egk', 'ehi'] + NSC = ['acf', 'acg', 'adi', 'adj', 'afg', 'ahk', 'aij', 'bdg', 'bdh', 'bef', 'bej', 'bfj', 'bgh', 'bik', 'ceh', 'cei', 'cfg', 'chi', 'cjk', 'dfk', 'dgh', 'dij', 'efj', 'egk', 'ehi'] M = Matroid(rank=3, nonspanning_circuits=NSC) M = _rename_and_relabel(M, "BetsyRoss", groundset) - pos = dict(zip(groundset or 'abcdefghijk', - [(0, 1.61000000000000), - (1.53120099123520, 0.497517360943665), - (0.946334256190882, -1.30251736094367), - (-0.946334256190882, -1.30251736094367), - (-1.53120099123520, 0.497517360943665), - (0.365084007635076, 0.502495027562079), - (0.590718333102580, -0.191936021350899), - (0, -0.621118012422360), - (-0.590718333102580, -0.191936021350899), - (-0.365084007635076, 0.502495027562079), - (0, 0)])) + pos = dict(zip(groundset or 'abcdefghijk', [(0, 1.61000000000000), (1.53120099123520, 0.497517360943665), (0.946334256190882, -1.30251736094367), (-0.946334256190882, -1.30251736094367), (-1.53120099123520, 0.497517360943665), (0.365084007635076, 0.502495027562079), (0.590718333102580, -0.191936021350899), (0, -0.621118012422360), (-0.590718333102580, -0.191936021350899), (-0.365084007635076, 0.502495027562079), (0, 0)])) M._fix_positions(pos_dict=pos) return M @@ -5076,14 +4935,7 @@ def N2(groundset='abcdefghijkl'): [Oxl2011]_, p. 554. """ - A = Matrix(GF(3), [ - [1, 0, 0, 0, 0, 0, 2, 0, 0, 1, 1, 1], - [0, 1, 0, 0, 0, 0, 1, 2, 0, 0, 0, 1], - [0, 0, 1, 0, 0, 0, 0, 1, 2, 0, 0, 1], - [0, 0, 0, 1, 0, 0, 0, 0, 1, 2, 1, 0], - [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1], - [0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 0, 1] - ]) + A = Matrix(GF(3), [[1, 0, 0, 0, 0, 0, 2, 0, 0, 1, 1, 1], [0, 1, 0, 0, 0, 0, 1, 2, 0, 0, 0, 1], [0, 0, 1, 0, 0, 0, 0, 1, 2, 0, 0, 1], [0, 0, 0, 1, 0, 0, 0, 0, 1, 2, 1, 0], [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 0, 1]]) M = TernaryMatroid(A, groundset) M = _rename_and_relabel(M, "N2") return M @@ -5109,16 +4961,7 @@ def D16(groundset='abcdefghijklmnop'): # A.K.A. the Carolyn Chun Matroid [CMO2012]_ """ - A = Matrix(GF(2), [ - [1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0], - [0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1], - [0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1], - [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1], - [0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0] - ]) + A = Matrix(GF(2), [[1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0], [0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1], [0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1], [0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0]]) M = BinaryMatroid(A, groundset) M = _rename_and_relabel(M, "D16") return M @@ -5142,16 +4985,7 @@ def Terrahawk(groundset='abcdefghijklmnop'): # aka the Dillon Mayhew Matroid [CMO2011]_ """ - A = Matrix(GF(2), [ - [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - [1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0] - ]) + A = Matrix(GF(2), [[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0]]) M = BinaryMatroid(A, groundset) M = _rename_and_relabel(M, "Terrahawk") return M @@ -5175,32 +5009,7 @@ def ExtendedBinaryGolayCode(groundset='abcdefghijklmnopqrstuvwx'): :class:`GolayCode ` """ - A = Matrix(GF(2), [ - [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0], - [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1], - [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0], - [1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0], - [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0], - [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1], - [1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1], - [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, - 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1], - [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, - 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0], - [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, - 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1], - [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] - ]) + A = Matrix(GF(2), [[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0], [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1], [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0], [1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0], [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0], [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]) M = BinaryMatroid(A, groundset) M = _rename_and_relabel(M, "Extended Binary Golay Code") return M @@ -5236,10 +5045,7 @@ def CompleteGraphic(n, groundset=None): """ from sage.graphs.graph_generators import graphs - M = Matroid( - groundset=list(range((n * (n - 1)) // 2)), - graph=graphs.CompleteGraph(n) - ) + M = Matroid(groundset=list(range((n * (n - 1)) // 2)), graph=graphs.CompleteGraph(n)) M = _rename_and_relabel(M, f'M(K{n})', groundset) return M @@ -5264,10 +5070,7 @@ def _rename_and_relabel(M, name=None, groundset=None): """ if groundset is not None: if len(groundset) != len(M.groundset()): - raise ValueError( - "the groundset should be of size %s (%s given)" % - (len(M.groundset()), len(groundset)) - ) + raise ValueError("the groundset should be of size %s (%s given)" % (len(M.groundset()), len(groundset))) M = M.relabel(dict(zip(sorted(M.groundset()), groundset))) if name is not None: diff --git a/src/sage/matroids/dual_matroid.py b/src/sage/matroids/dual_matroid.py index 4dde691def5..86c756eecf1 100644 --- a/src/sage/matroids/dual_matroid.py +++ b/src/sage/matroids/dual_matroid.py @@ -343,8 +343,7 @@ def _minor(self, contractions=None, deletions=None): """ # Assumption: if self._matroid cannot make a dual, neither can # its minor. - return DualMatroid(self._matroid._minor(contractions=deletions, - deletions=contractions)) + return DualMatroid(self._matroid._minor(contractions=deletions, deletions=contractions)) def dual(self): r""" @@ -502,6 +501,7 @@ def __reduce__(self): 4: {{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}}}' """ import sage.matroids.unpickling + data = (self._matroid, self.get_custom_name()) version = 0 return sage.matroids.unpickling.unpickle_dual_matroid, (version, data) diff --git a/src/sage/matroids/gammoid.py b/src/sage/matroids/gammoid.py index 8d0b1745f3e..d65bd876ad9 100644 --- a/src/sage/matroids/gammoid.py +++ b/src/sage/matroids/gammoid.py @@ -256,7 +256,7 @@ def __eq__(self, other): if not isinstance(other, Gammoid): return False # The roots are implied by self._D - return (self._D == other._D and self._groundset == other._groundset) + return self._D == other._D and self._groundset == other._groundset def __ne__(self, other): """ @@ -283,7 +283,7 @@ def __ne__(self, other): sage: M.delete(8) == N.delete('a') True """ - return (not self == other) + return not self == other def __reduce__(self): """ @@ -313,6 +313,7 @@ def __reduce__(self): Gammoid of rank 3 on 7 elements """ import sage.matroids.unpickling + data = (self._D, self._roots, self._groundset, self.get_custom_name()) version = 0 return sage.matroids.unpickling.unpickle_gammoid, (version, data) @@ -358,8 +359,7 @@ def digraph_plot(self): # Vertices just in the ending set are blue "#0072B2" # Vertices in both are pink "#CC79A7" # Vertices in neither are grey "#999999" - d = {"#D55E00": list(self._buckets), "#CC79A7": list(self._inter), - "#0072B2": list(self._ending), "#999999": list(self._therest)} + d = {"#D55E00": list(self._buckets), "#CC79A7": list(self._inter), "#0072B2": list(self._ending), "#999999": list(self._therest)} return self._G.plot(vertex_colors=d) def _rank(self, X): @@ -529,8 +529,7 @@ def gammoid_extension(self, vertex, neighbors=[]): if neighbors: raise ValueError("neighbors of vertex in digraph cannot be changed") new_groundset = set(self._groundset).union([vertex]) - return Gammoid(D=self._G, roots=self._roots, - groundset=new_groundset) + return Gammoid(D=self._G, roots=self._roots, groundset=new_groundset) else: if not set(neighbors).issubset(self._G.vertices()): raise ValueError("neighbors must already be in graph") diff --git a/src/sage/matroids/matroids_plot_helpers.py b/src/sage/matroids/matroids_plot_helpers.py index 597365d6a04..288fee9351e 100644 --- a/src/sage/matroids/matroids_plot_helpers.py +++ b/src/sage/matroids/matroids_plot_helpers.py @@ -79,8 +79,7 @@ from sage.misc.lazy_import import lazy_import from sage.sets.set import Set -lazy_import("sage.plot.all", ["Graphics", "line", "text", - "polygon2d", "point", "points"]) +lazy_import("sage.plot.all", ["Graphics", "line", "text", "polygon2d", "point", "points"]) lazy_import("sage.plot.colors", "Color") @@ -158,24 +157,22 @@ def it(M, B1, nB1, lps) -> tuple[dict, list, list, list]: L3.append(i) L = [L1, L2, L3] # megalist lines = [] # the list of lines - for i in range(1, len(L)+1): - lines.append([B1[pairs[i-1][0]]]) - lines[i-1].extend(L[i-1]) - lines[i-1].extend([B1[pairs[i-1][1]]]) + for i in range(1, len(L) + 1): + lines.append([B1[pairs[i - 1][0]]]) + lines[i - 1].extend(L[i - 1]) + lines[i - 1].extend([B1[pairs[i - 1][1]]]) # place triangle and L1,L2,L3 for i in L: # loop over megalist - interval = 1/float(len(i)+1) + interval = 1 / float(len(i) + 1) pt1 = list(tripts[pairs[L.index(i)][0]]) pt2 = list(tripts[pairs[L.index(i)][1]]) - for j in range(1, len(i)+1): + for j in range(1, len(i) + 1): # loop over L1,L2,L3 - cc = interval*j - pts[i[j-1]] = (cc*pt1[0]+(1-cc)*pt2[0], cc*pt1[1]+(1-cc)*pt2[1]) + cc = interval * j + pts[i[j - 1]] = (cc * pt1[0] + (1 - cc) * pt2[0], cc * pt1[1] + (1 - cc) * pt2[1]) trilines = [set(x) for x in lines if len(x) >= 3] set_lps = set(lps) - curvedlines = [list(sx.difference(set_lps)) - for x in M.flats(2) if (sx := set(x)) not in trilines - and len(list(x)) >= 3] + curvedlines = [list(sx.difference(set_lps)) for x in M.flats(2) if (sx := set(x)) not in trilines and len(list(x)) >= 3] nontripts = [i for i in nB1 if i not in pts] trilines = [list(s) for s in trilines] return pts, trilines, nontripts, curvedlines @@ -211,12 +208,10 @@ def trigrid(tripts) -> list[list]: This method does NOT do any checks. """ pairs = [[0, 1], [1, 2], [0, 2]] - cpt = [float(tripts[0][0] + tripts[1][0] + tripts[2][0]) / 3, - float(tripts[0][1] + tripts[1][1] + tripts[2][1]) / 3] + cpt = [float(tripts[0][0] + tripts[1][0] + tripts[2][0]) / 3, float(tripts[0][1] + tripts[1][1] + tripts[2][1]) / 3] grid = [cpt] for p, q in pairs: - pt = [float(tripts[p][0] + tripts[q][0] + cpt[0]) / 3, - float(tripts[p][1] + tripts[q][1] + cpt[1]) / 3] + pt = [float(tripts[p][0] + tripts[q][0] + cpt[0]) / 3, float(tripts[p][1] + tripts[q][1] + cpt[1]) / 3] grid.append(pt) return grid @@ -269,14 +264,11 @@ def addnontripts(tripts_labels, nontripts_labels, ptsdict) -> dict: pairs = [[0, 1], [1, 2], [0, 2]] q = [tripts] num = len(nontripts_labels) - gridpts = [[float((tripts[0][0] + tripts[1][0] + tripts[2][0]) / 3), - float(tripts[0][1] + tripts[1][1] + tripts[2][1]) / 3]] + gridpts = [[float((tripts[0][0] + tripts[1][0] + tripts[2][0]) / 3), float(tripts[0][1] + tripts[1][1] + tripts[2][1]) / 3]] n = 0 while n < num + 1: g = trigrid(q[0]) - q.extend([[g[0], q[0][pairs[0][0]], q[0][pairs[0][1]]], - [g[0], q[0][pairs[1][0]], q[0][pairs[1][1]]], - [g[0], q[0][pairs[2][0]], q[0][pairs[2][1]]]]) + q.extend([[g[0], q[0][pairs[0][0]], q[0][pairs[0][1]]], [g[0], q[0][pairs[1][0]], q[0][pairs[1][1]]], [g[0], q[0][pairs[2][0]], q[0][pairs[2][1]]]]) q.remove(q[0]) gridpts.extend(g[1:]) if n == 0: @@ -346,8 +338,8 @@ def createline(ptsdict, ll, lineorders2=None) -> tuple[list, list, list, list]: linepts = [list(ptsdict[i]) for i in ll] xpts = [xx[0] for xx in linepts] ypts = [yy[1] for yy in linepts] - xdim = (float(max(xpts))-float(min(xpts))) - ydim = (float(max(ypts))-float(min(ypts))) + xdim = float(max(xpts)) - float(min(xpts)) + ydim = float(max(ypts)) - float(min(ypts)) if xdim > ydim: sortedind = sorted(range(len(xpts)), key=lambda k: float(xpts[k])) else: @@ -423,16 +415,14 @@ def slp(M1, pos_dict=None, B=None) -> tuple: P = set(M1.groundset()) - nP if P: if pos_dict is not None: - pcls = list({frozenset(set(M1.closure([p])) - L) - for p in list(P)}) + pcls = list({frozenset(set(M1.closure([p])) - L) for p in list(P)}) newP = [] for pcl in pcls: pcl_in_dict = [p for p in list(pcl) if p in pos_dict.keys()] newP.extend(list(pcl - set([pcl_in_dict[0]]))) return [M1.delete(L | set(newP)), L, set(newP)] if B is not None: - pcls = list({frozenset(set(M1.closure([p])) - L) - for p in list(P)}) + pcls = list({frozenset(set(M1.closure([p])) - L) for p in list(P)}) newP = [] for pcl in pcls: pcl_list = list(pcl) @@ -496,19 +486,14 @@ def addlp(M, M1, L, P, ptsdict, G=None, limits=None) -> tuple: recty = -1 else: rectx = limits[0] - recty = limits[2]-1 - rectw = 0.5 + 0.4*len(loops) + 0.5 # controlled based on len(loops) + recty = limits[2] - 1 + rectw = 0.5 + 0.4 * len(loops) + 0.5 # controlled based on len(loops) recth = 0.6 - G += polygon2d([[rectx, recty], [rectx, recty+recth], - [rectx+rectw, recty+recth], [rectx+rectw, recty]], - color='black', fill=False, thickness=4) - G += text(looptext, (rectx+0.5, recty+0.3), color='black', - fontsize=13) - G += point((rectx+0.2, recty+0.3), color=Color('#BDBDBD'), size=300, - zorder=2) - G += text('Loop(s)', (rectx+0.5+0.4*len(loops)+0.1, recty+0.3), - fontsize=13, color='black') - limits = tracklims(limits, [rectx, rectx+rectw], [recty, recty+recth]) + G += polygon2d([[rectx, recty], [rectx, recty + recth], [rectx + rectw, recty + recth], [rectx + rectw, recty]], color='black', fill=False, thickness=4) + G += text(looptext, (rectx + 0.5, recty + 0.3), color='black', fontsize=13) + G += point((rectx + 0.2, recty + 0.3), color=Color('#BDBDBD'), size=300, zorder=2) + G += text('Loop(s)', (rectx + 0.5 + 0.4 * len(loops) + 0.1, recty + 0.3), fontsize=13, color='black') + limits = tracklims(limits, [rectx, rectx + rectw], [recty, recty + recth]) # deal with parallel elements if P: # create list of lists where inner lists are parallel classes @@ -526,29 +511,19 @@ def addlp(M, M1, L, P, ptsdict, G=None, limits=None) -> tuple: basept = list(ptsdict[pcl[0]]) if len(pcl) <= 2: # add side by side - ptsdict[pcl[1]] = (basept[0], basept[1]-0.13) - G += points(zip([basept[0]], [basept[1]-0.13]), - color=Color('#BDBDBD'), size=300, zorder=2) - G += text(pcl[0], (float(basept[0]), - float(basept[1])), color='black', - fontsize=13) - G += text(pcl[1], (float(basept[0]), - float(basept[1])-0.13), color='black', - fontsize=13) - limits = tracklims(limits, [basept[0]], [basept[1]-0.13]) + ptsdict[pcl[1]] = (basept[0], basept[1] - 0.13) + G += points(zip([basept[0]], [basept[1] - 0.13]), color=Color('#BDBDBD'), size=300, zorder=2) + G += text(pcl[0], (float(basept[0]), float(basept[1])), color='black', fontsize=13) + G += text(pcl[1], (float(basept[0]), float(basept[1]) - 0.13), color='black', fontsize=13) + limits = tracklims(limits, [basept[0]], [basept[1] - 0.13]) else: # add in a bracket pce = sorted([str(kk) for kk in pcl]) l = newlabel(set(ext_gnd)) ext_gnd.append(l) - G += text(l+'={ '+", ".join(pce)+' }', (float(basept[0]), - float(basept[1]-0.2)-0.034), color='black', - fontsize=13) - G += text(l, (float(basept[0]), - float(basept[1])), color='black', - fontsize=13) - limits = tracklims(limits, [basept[0]], - [(basept[1]-0.2)-0.034]) + G += text(l + '={ ' + ", ".join(pce) + ' }', (float(basept[0]), float(basept[1] - 0.2) - 0.034), color='black', fontsize=13) + G += text(l, (float(basept[0]), float(basept[1])), color='black', fontsize=13) + limits = tracklims(limits, [basept[0]], [(basept[1] - 0.2) - 0.034]) return G, limits @@ -678,8 +653,7 @@ def posdict_is_sane(M1, pos_dict) -> bool: allP = [] for pcl in pcls: allP.extend(pcl) - return all(x in pos_dict - for x in list(set(M1.groundset()) - (L | set(allP)))) + return all(x in pos_dict for x in list(set(M1.groundset()) - (L | set(allP)))) def tracklims(lims, x_i=[], y_i=[]) -> list: @@ -705,10 +679,8 @@ def tracklims(lims, x_i=[], y_i=[]) -> list: This method does NOT do any checks. """ - if lims is not None and lims[0] is not None and lims[1] is not None and \ - lims[2] is not None and lims[3] is not None: - lims = [min(*x_i, lims[0]), max(*x_i, lims[1]), - min(*y_i, lims[2]), max(*y_i, lims[3])] + if lims is not None and lims[0] is not None and lims[1] is not None and lims[2] is not None and lims[3] is not None: + lims = [min(*x_i, lims[0]), max(*x_i, lims[1]), min(*y_i, lims[2]), max(*y_i, lims[3])] else: lims = [min(x_i), max(x_i), min(y_i), max(y_i)] return lims @@ -768,46 +740,34 @@ def geomrep(M1, B1=None, lineorders1=None, pd=None, sp=False): recty = -1 rectw = 0.5 + 0.4 * len(loops) + 0.5 # controlled based on len(loops) recth = 0.6 - G += polygon2d([[rectx, recty], [rectx, recty+recth], - [rectx+rectw, recty+recth], [rectx+rectw, recty]], - color='black', fill=False, thickness=4) - G += text(looptext, (rectx+0.5, recty+0.3), color='black', - fontsize=13) - G += point((rectx+0.2, recty+0.3), color=Color('#BDBDBD'), size=300, - zorder=2) - G += text('Loop(s)', (rectx+0.5+0.4*len(loops)+0.1, recty+0.3), - fontsize=13, color='black') - limits = tracklims(limits, [rectx, rectx+rectw], [recty, recty+recth]) + G += polygon2d([[rectx, recty], [rectx, recty + recth], [rectx + rectw, recty + recth], [rectx + rectw, recty]], color='black', fill=False, thickness=4) + G += text(looptext, (rectx + 0.5, recty + 0.3), color='black', fontsize=13) + G += point((rectx + 0.2, recty + 0.3), color=Color('#BDBDBD'), size=300, zorder=2) + G += text('Loop(s)', (rectx + 0.5 + 0.4 * len(loops) + 0.1, recty + 0.3), fontsize=13, color='black') + limits = tracklims(limits, [rectx, rectx + rectw], [recty, recty + recth]) G.axes(False) - G.axes_range(xmin=limits[0]-0.5, xmax=limits[1]+0.5, - ymin=limits[2]-0.5, ymax=limits[3]+0.5) + G.axes_range(xmin=limits[0] - 0.5, xmax=limits[1] + 0.5, ymin=limits[2] - 0.5, ymax=limits[3] + 0.5) return G if M.rank() == 1: - if M._cached_info is not None and \ - 'plot_positions' in M._cached_info.keys() and \ - M._cached_info['plot_positions'] is not None: + if M._cached_info is not None and 'plot_positions' in M._cached_info.keys() and M._cached_info['plot_positions'] is not None: pts = M._cached_info['plot_positions'] else: pts = {} gnd = sorted(M.groundset()) - pts[gnd[0]] = (1, float(2)/3) - G += point((1, float(2)/3), size=300, color=Color('#BDBDBD'), zorder=2) - pt = [1, float(2)/3] + pts[gnd[0]] = (1, float(2) / 3) + G += point((1, float(2) / 3), size=300, color=Color('#BDBDBD'), zorder=2) + pt = [1, float(2) / 3] if not P: - G += text(gnd[0], (float(pt[0]), float(pt[1])), color='black', - fontsize=13) + G += text(gnd[0], (float(pt[0]), float(pt[1])), color='black', fontsize=13) pts2 = pts # track limits [xmin,xmax,ymin,ymax] pl = [list(x) for x in pts2.values()] - lims = tracklims([None, None, None, None], [pnt[0] for pnt in pl], - [pnt[1] for pnt in pl]) + lims = tracklims([None, None, None, None], [pnt[0] for pnt in pl], [pnt[1] for pnt in pl]) elif M.rank() == 2: nB1 = set(M.groundset()) - set(B1) bline = [j for j in nB1 if M.is_dependent([j, B1[0], B1[1]])] - interval = len(bline)+1 - if M._cached_info is not None and \ - 'plot_positions' in M._cached_info.keys() and \ - M._cached_info['plot_positions'] is not None: + interval = len(bline) + 1 + if M._cached_info is not None and 'plot_positions' in M._cached_info.keys() and M._cached_info['plot_positions'] is not None: pts2 = M._cached_info['plot_positions'] else: pts2 = {} @@ -816,71 +776,55 @@ def geomrep(M1, B1=None, lineorders1=None, pd=None, sp=False): lpt = list(pts2[B1[0]]) rpt = list(pts2[B1[1]]) for k in range(len(bline)): - cc = (float(1)/interval)*(k+1) - pts2[bline[k]] = (cc*lpt[0]+(1-cc)*rpt[0], - cc*lpt[1]+(1-cc)*rpt[1]) + cc = (float(1) / interval) * (k + 1) + pts2[bline[k]] = (cc * lpt[0] + (1 - cc) * rpt[0], cc * lpt[1] + (1 - cc) * rpt[1]) if sp: M._cached_info['plot_positions'] = pts2 # track limits [xmin,xmax,ymin,ymax] pl = [list(x) for x in pts2.values()] - lims = tracklims([None, None, None, None], [pt[0] for pt in pl], - [pt[1] for pt in pl]) + lims = tracklims([None, None, None, None], [pt[0] for pt in pl], [pt[1] for pt in pl]) bline.extend(B1) ptsx, ptsy, x_i, y_i = createline(pts2, bline, lineorders1) lims = tracklims(lims, x_i, y_i) G += line(zip(x_i, y_i), color='black', thickness=3, zorder=1) - pels = [p for p in pts2 - if any(M1.rank([p, q]) == 1 for q in P)] + pels = [p for p in pts2 if any(M1.rank([p, q]) == 1 for q in P)] allpts = [list(pts2[i]) for i in M.groundset()] xpts = [float(k[0]) for k in allpts] ypts = [float(k[1]) for k in allpts] - G += points(zip(xpts, ypts), color=Color('#BDBDBD'), size=300, - zorder=2) + G += points(zip(xpts, ypts), color=Color('#BDBDBD'), size=300, zorder=2) for i in pts2: if i not in pels: pt = list(pts2[i]) - G += text(i, (float(pt[0]), float(pt[1])), color='black', - fontsize=13) + G += text(i, (float(pt[0]), float(pt[1])), color='black', fontsize=13) else: - if M._cached_info is None or \ - 'plot_positions' not in M._cached_info.keys() or \ - M._cached_info['plot_positions'] is None: - (pts, trilines, - nontripts, curvedlines) = it(M1, B1, - list(set(M.groundset())-set(B1)), - list(set(L) | set(P))) + if M._cached_info is None or 'plot_positions' not in M._cached_info.keys() or M._cached_info['plot_positions'] is None: + (pts, trilines, nontripts, curvedlines) = it(M1, B1, list(set(M.groundset()) - set(B1)), list(set(L) | set(P))) pts2 = addnontripts([B1[0], B1[1], B1[2]], nontripts, pts) trilines.extend(curvedlines) else: pts2 = M._cached_info['plot_positions'] - trilines = [list(set(x).difference(L | P)) - for x in M1.flats(2) if len(list(x)) >= 3] + trilines = [list(set(x).difference(L | P)) for x in M1.flats(2) if len(list(x)) >= 3] pl = [list(x) for x in pts2.values()] - lims = tracklims([None, None, None, None], [pt[0] for pt in pl], - [pt[1] for pt in pl]) + lims = tracklims([None, None, None, None], [pt[0] for pt in pl], [pt[1] for pt in pl]) for ll in trilines: if len(ll) >= 3: ptsx, ptsy, x_i, y_i = createline(pts2, ll, lineorders1) lims = tracklims(lims, x_i, y_i) G += line(zip(x_i, y_i), color='black', thickness=3, zorder=1) - pels = [p for p in pts2 - if any(M1.rank([p, q]) == 1 for q in P)] + pels = [p for p in pts2 if any(M1.rank([p, q]) == 1 for q in P)] allpts = [list(pts2[i]) for i in M.groundset()] xpts = [float(k[0]) for k in allpts] ypts = [float(k[1]) for k in allpts] - G += points(zip(xpts, ypts), color=Color('#BDBDBD'), size=300, - zorder=2) + G += points(zip(xpts, ypts), color=Color('#BDBDBD'), size=300, zorder=2) for i in pts2: if i not in pels: pt = list(pts2[i]) - G += text(i, (float(pt[0]), float(pt[1])), color='black', - fontsize=13) + G += text(i, (float(pt[0]), float(pt[1])), color='black', fontsize=13) if sp: M1._cached_info['plot_positions'] = pts2 M1._cached_info['plot_lineorders'] = lineorders1 # deal with loops and parallel elements G, lims = addlp(M1, M, L, P, pts2, G, lims) G.axes(False) - G.axes_range(xmin=lims[0]-0.5, xmax=lims[1]+0.5, ymin=lims[2]-0.5, - ymax=lims[3]+0.5) + G.axes_range(xmin=lims[0] - 0.5, xmax=lims[1] + 0.5, ymin=lims[2] - 0.5, ymax=lims[3] + 0.5) return G diff --git a/src/sage/matroids/minor_matroid.py b/src/sage/matroids/minor_matroid.py index 871a8892579..d84b7eee813 100644 --- a/src/sage/matroids/minor_matroid.py +++ b/src/sage/matroids/minor_matroid.py @@ -63,6 +63,7 @@ Methods ======= """ + # **************************************************************************** # Copyright (C) 2013 Rudi Pendavingh # Copyright (C) 2013 Michael Welsh @@ -474,6 +475,7 @@ def __reduce__(self): 4: {{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}}} """ import sage.matroids.unpickling + data = (self._matroid, self._contractions, self._deletions, self.get_custom_name()) version = 0 return sage.matroids.unpickling.unpickle_minor_matroid, (version, data) diff --git a/src/sage/matroids/rank_matroid.py b/src/sage/matroids/rank_matroid.py index b7ac75209e5..e8f33746ba3 100644 --- a/src/sage/matroids/rank_matroid.py +++ b/src/sage/matroids/rank_matroid.py @@ -47,6 +47,7 @@ class ``RankMatroid``. All that is required is a groundset and a function that Methods ======= """ + # **************************************************************************** # Copyright (C) 2013 Rudi Pendavingh # Copyright (C) 2013 Stefan van Zwam @@ -83,6 +84,7 @@ class RankMatroid(Matroid): sage: M.is_isomorphic(matroids.Uniform(3, 6)) True """ + def __init__(self, groundset, rank_function): """ Initialize the rank matroid. diff --git a/src/sage/matroids/utilities.py b/src/sage/matroids/utilities.py index 8ab0b71512b..46b3140459d 100644 --- a/src/sage/matroids/utilities.py +++ b/src/sage/matroids/utilities.py @@ -12,6 +12,7 @@ - Stefan van Zwam (2011-06-24): initial version """ + # **************************************************************************** # Copyright (C) 2013 Rudi Pendavingh # Copyright (C) 2013 Stefan van Zwam @@ -118,8 +119,7 @@ def setprint_s(X, toplevel=False): if isinstance(X, (frozenset, set)): return '{' + ', '.join(sorted(setprint_s(x) for x in X)) + '}' if isinstance(X, dict): - return '{' + ', '.join(sorted(setprint_s(key) + ': ' + setprint_s(val) - for key, val in X.items())) + '}' + return '{' + ', '.join(sorted(setprint_s(key) + ': ' + setprint_s(val) for key, val in X.items())) + '}' if isinstance(X, str): if toplevel: return X @@ -260,6 +260,7 @@ def make_regular_matroid_from_matroid(matroid): True """ import sage.matroids.linear_matroid + M = matroid if isinstance(M, sage.matroids.linear_matroid.RegularMatroid): return M @@ -370,13 +371,13 @@ def spanning_forest(M): # Given a matrix, produce a spanning tree G = Graph() m = M.ncols() - for (x, y) in M.dict(): + for x, y in M.dict(): G.add_edge(x + m, y) T = [] # find spanning tree in each component for component in G.connected_components_subgraphs(): spanning_tree = kruskal(component) - for (x, y, z) in spanning_tree: + for x, y, z in spanning_tree: if x < m: t = x x = y @@ -415,7 +416,7 @@ def spanning_stars(M): for x, y in M.dict(): G.add_edge(x + m, y) - delta = (M.nrows() + m)**0.5 + delta = (M.nrows() + m) ** 0.5 # remove low degree vertices H = [] # candidate vertices @@ -469,6 +470,7 @@ def spanning_stars(M): T.append((x - m, y)) return T + # Partial fields and lifting @@ -639,7 +641,7 @@ def lift_cross_ratios(A, lift_map=None): if cr == minus_one1: Z[entry] = Z[entry] * (minus_one2**degree) else: - Z[entry] = Z[entry] * (lift_map[cr]**degree) + Z[entry] = Z[entry] * (lift_map[cr] ** degree) return Z @@ -704,7 +706,7 @@ def lift_map(target): z = ZZ['z'].gen() S = NumberField(z * z - z + 1, 'z') z = S(z) - return {R.one(): S.one(), R(3): z, R(3)**(-1): z**5} + return {R.one(): S.one(), R(3): z, R(3) ** (-1): z**5} if target == "dyadic": R = GF(11) @@ -716,10 +718,7 @@ def lift_map(target): R = GF(19) t = QQ['t'].gen() G = NumberField(t * t - t - 1, 't') - return {R(1): G(1), R(5): G(t), - R(1) / R(5): G(1) / G(t), R(-5): G(-t), - R(-5)**(-1): G(-t)**(-1), R(5)**2: G(t)**2, - R(5)**(-2): G(t)**(-2)} + return {R(1): G(1), R(5): G(t), R(1) / R(5): G(1) / G(t), R(-5): G(-t), R(-5) ** (-1): G(-t) ** (-1), R(5) ** 2: G(t) ** 2, R(5) ** (-2): G(t) ** (-2)} raise NotImplementedError(target) diff --git a/src/sage/misc/abstract_method.py b/src/sage/misc/abstract_method.py index 74d73ffa43a..b0ff9dd8375 100644 --- a/src/sage/misc/abstract_method.py +++ b/src/sage/misc/abstract_method.py @@ -1,6 +1,7 @@ """ Abstract methods """ + # **************************************************************************** # Copyright (C) 2008 Nicolas M. Thiery # @@ -156,8 +157,7 @@ def __init__(self, f, optional=False): sage: x.__module__ '__main__' """ - assert (isinstance(f, types.FunctionType) or - getattr(type(f), '__name__', None) == 'cython_function_or_method') + assert isinstance(f, types.FunctionType) or getattr(type(f), '__name__', None) == 'cython_function_or_method' assert isinstance(optional, bool) self._f = f self._optional = optional @@ -195,6 +195,7 @@ def _sage_src_lines_(self): 19 """ from sage.misc.sageinspect import sage_getsourcelines + return sage_getsourcelines(self._f) def __get__(self, instance, cls): @@ -260,8 +261,7 @@ def abstract_methods_of_class(cls): {'optional': ['optional1', 'optional2'], 'required': ['required1', 'required2']} """ - result = {"required": [], - "optional": []} + result = {"required": [], "optional": []} for name in dir(cls): entry = getattr(cls, name) if not isinstance(entry, AbstractMethod): diff --git a/src/sage/misc/abstract_method.pyi b/src/sage/misc/abstract_method.pyi index ac68f7ee459..f6082876c77 100644 --- a/src/sage/misc/abstract_method.pyi +++ b/src/sage/misc/abstract_method.pyi @@ -1,24 +1,13 @@ from collections.abc import Callable from typing import Union -def abstract_method(f: Callable | None = None, optional: bool = False) -> Callable: - ... +def abstract_method(f: Callable | None = None, optional: bool = False) -> Callable: ... class AbstractMethod: - def __init__(self, f: Callable, optional: bool = False) -> None: - ... + def __init__(self, f: Callable, optional: bool = False) -> None: ... + def __repr__(self) -> str: ... + def _sage_src_lines_(self) -> Union[str, int]: ... + def __get__(self, instance: object, cls: type) -> Union[Callable, NotImplementedError]: ... + def is_optional(self) -> bool: ... - def __repr__(self) -> str: - ... - - def _sage_src_lines_(self) -> Union[str, int]: - ... - - def __get__(self, instance: object, cls: type) -> Union[Callable, NotImplementedError]: - ... - - def is_optional(self) -> bool: - ... - -def abstract_methods_of_class(cls: type) -> dict[str, list[str]]: - ... +def abstract_methods_of_class(cls: type) -> dict[str, list[str]]: ... diff --git a/src/sage/misc/all.py b/src/sage/misc/all.py index 4102073d48d..0898f6a0242 100644 --- a/src/sage/misc/all.py +++ b/src/sage/misc/all.py @@ -1,15 +1,15 @@ from sage.misc.lazy_attribute import lazy_attribute, lazy_class_attribute from sage.misc.lazy_import import lazy_import -import sage.structure.all # to break a cyclic import +import sage.structure.all # to break a cyclic import -from sage.misc.verbose import (set_verbose, set_verbose_files, - get_verbose_files, unset_verbose_files, get_verbose) -lazy_import('sage.misc.verbose', 'verbose', - deprecation=17815) +from sage.misc.verbose import set_verbose, set_verbose_files, get_verbose_files, unset_verbose_files, get_verbose + +lazy_import('sage.misc.verbose', 'verbose', deprecation=17815) from sage.misc.call import attrcall from sage.misc.misc_c import prod, running_total, balanced_sum + mul = prod add = sum @@ -39,10 +39,7 @@ from sage.misc.sage_input import sage_input -from sage.misc.misc import ( - exists, forall, is_iterator, random_sublist, pad_zeros, - newton_method_sizes, compose, nest -) +from sage.misc.misc import exists, forall, is_iterator, random_sublist, pad_zeros, newton_method_sizes, compose, nest from sage.misc.banner import version @@ -68,10 +65,7 @@ lazy_import('sage.misc.pager', 'pager') -lazy_import('sage.misc.sagedoc', ['browse_sage_doc', - 'search_src', 'search_def', 'search_doc', - 'tutorial', 'reference', 'manual', 'developer', - 'constructions', 'help']) +lazy_import('sage.misc.sagedoc', ['browse_sage_doc', 'search_src', 'search_def', 'search_doc', 'tutorial', 'reference', 'manual', 'developer', 'constructions', 'help']) lazy_import('pydoc', 'help', 'python_help') from sage.misc.classgraph import class_graph @@ -80,68 +74,14 @@ from sage.misc.mathml import mathml -from sage.misc.defaults import (set_default_variable_name, - series_precision, set_series_precision) +from sage.misc.defaults import set_default_variable_name, series_precision, set_series_precision lazy_import("sage.misc.cython", "cython_lambda") lazy_import("sage.misc.cython", "cython_compile", "cython") from sage.misc.func_persist import func_persist -from sage.misc.functional import (additive_order, - base_ring, - base_field, - basis, - category, - charpoly, - characteristic_polynomial, - coerce, - cyclotomic_polynomial, - decomposition, - denominator, - det, - dimension, - dim, - discriminant, - disc, - eta, - fcp, - gen, - gens, - hecke_operator, - image, - integral, integrate, - integral_closure, - interval, - xinterval, - is_even, - is_odd, - kernel, - krull_dimension, - lift, - log as log_b, - minimal_polynomial, - minpoly, - multiplicative_order, - ngens, - norm, - numerator, - numerical_approx, - n, N, - objgens, - objgen, - order, - rank, - regulator, - round, - quotient, - quo, - isqrt, - squarefree_part, - sqrt, - symbolic_sum as sum, - symbolic_prod as product, - transpose) +from sage.misc.functional import additive_order, base_ring, base_field, basis, category, charpoly, characteristic_polynomial, coerce, cyclotomic_polynomial, decomposition, denominator, det, dimension, dim, discriminant, disc, eta, fcp, gen, gens, hecke_operator, image, integral, integrate, integral_closure, interval, xinterval, is_even, is_odd, kernel, krull_dimension, lift, log as log_b, minimal_polynomial, minpoly, multiplicative_order, ngens, norm, numerator, numerical_approx, n, N, objgens, objgen, order, rank, regulator, round, quotient, quo, isqrt, squarefree_part, sqrt, symbolic_sum as sum, symbolic_prod as product, transpose from sage.misc.latex import LatexExpr, latex, view @@ -158,8 +98,6 @@ lazy_import('sage.misc.edit_module', 'set_edit_template', deprecation=34259) lazy_import('sage.misc.profiler', 'Profiler', deprecation=34259) lazy_import('sage.misc.trace', 'trace', deprecation=34259) -lazy_import('sage.misc.package', ('installed_packages', 'is_package_installed', - 'package_versions'), - deprecation=34259) +lazy_import('sage.misc.package', ('installed_packages', 'is_package_installed', 'package_versions'), deprecation=34259) lazy_import('sage.misc.benchmark', 'benchmark', deprecation=34259) lazy_import('sage.repl.interpreter', 'logstr', deprecation=34259) diff --git a/src/sage/misc/allocator.pyi b/src/sage/misc/allocator.pyi index 412ece2d794..3666ae710a7 100644 --- a/src/sage/misc/allocator.pyi +++ b/src/sage/misc/allocator.pyi @@ -1,7 +1,4 @@ from cpython.object import PyTypeObject, newfunc, destructor -def hook_tp_functions_type(tp: PyTypeObject, tp_new: newfunc, tp_dealloc: destructor, useGC: bool) -> None: - ... - -def hook_tp_functions(global_dummy: object, tp_new: newfunc, tp_dealloc: destructor, useGC: bool) -> None: - ... +def hook_tp_functions_type(tp: PyTypeObject, tp_new: newfunc, tp_dealloc: destructor, useGC: bool) -> None: ... +def hook_tp_functions(global_dummy: object, tp_new: newfunc, tp_dealloc: destructor, useGC: bool) -> None: ... diff --git a/src/sage/misc/banner.py b/src/sage/misc/banner.py index a4d7cd64803..30ffb501243 100644 --- a/src/sage/misc/banner.py +++ b/src/sage/misc/banner.py @@ -74,6 +74,7 @@ def banner_text(full=True): pre = version_dict()['prerelease'] try: import sage.all + have_sage_all = True except ImportError: have_sage_all = False @@ -184,8 +185,7 @@ def version_dict(): return dict -def require_version(major, minor=0, tiny=0, prerelease=False, - print_message=False): +def require_version(major, minor=0, tiny=0, prerelease=False, print_message=False): """ Return ``True`` if Sage version is at least ``major.minor.tiny``. @@ -226,13 +226,8 @@ def require_version(major, minor=0, tiny=0, prerelease=False, False """ vers = version_dict() - prerelease_checked = (prerelease if vers['prerelease'] else True) - if (vers['major'] > major - or (vers['major'] == major and vers['minor'] > minor) - or (vers['major'] == major and vers['minor'] == minor - and vers['tiny'] > tiny) - or (vers['major'] == major and vers['minor'] == minor - and vers['tiny'] == tiny and prerelease_checked)): + prerelease_checked = prerelease if vers['prerelease'] else True + if vers['major'] > major or (vers['major'] == major and vers['minor'] > minor) or (vers['major'] == major and vers['minor'] == minor and vers['tiny'] > tiny) or (vers['major'] == major and vers['minor'] == minor and vers['tiny'] == tiny and prerelease_checked): return True if print_message: txt = "This code requires at least version {} of SageMath to run correctly." diff --git a/src/sage/misc/benchmark.py b/src/sage/misc/benchmark.py index 4b9aa1e8b70..e5bf0b48d16 100644 --- a/src/sage/misc/benchmark.py +++ b/src/sage/misc/benchmark.py @@ -93,7 +93,7 @@ def bench0(): desc = """Benchmark 0: Factor the following polynomial over the rational numbers: (x^97+19*x+1)*(x^103-19*x^97+14)*(x^100-1)""" x = polygen(QQ, "x") - f = (x**97+19*x+1)*(x**103-19*x**97+14)*(x**100-1) + f = (x**97 + 19 * x + 1) * (x**103 - 19 * x**97 + 14) * (x**100 - 1) t = cputime() F = f.factor() return (desc, cputime(t)) @@ -128,7 +128,7 @@ def bench2(): """ desc = """Some basic arithmetic with very large Integer numbers: '3^1000001 * 19^100001""" t = cputime() - a = ZZ(3)**1000001 * ZZ(19)**100001 + a = ZZ(3) ** 1000001 * ZZ(19) ** 100001 return (desc, cputime(t)) @@ -144,7 +144,7 @@ def bench3(): """ desc = """Some basic arithmetic with very large Rational numbers: '(2/3)^100001 * (17/19)^100001""" t = cputime() - a = QQ((2, 3))**100001 * QQ((17, 19))**100001 + a = QQ((2, 3)) ** 100001 * QQ((17, 19)) ** 100001 return (desc, cputime(t)) @@ -161,7 +161,7 @@ def bench4(): desc = """Rational polynomial arithmetic using Sage. Compute (x^29+17*x-5)^200.""" x = PolynomialRing(QQ, 'x').gen() t = cputime() - f = x**29 + 17*x-5 + f = x**29 + 17 * x - 5 a = f**200 return (desc, cputime(t)) @@ -179,7 +179,7 @@ def bench5(): desc = """Rational polynomial arithmetic using Sage. Compute (x^19 - 18*x + 1)^50 one hundred times.""" x = PolynomialRing(QQ, 'x').gen() t = cputime() - f = x**19 - 18*x + 1 + f = x**19 - 18 * x + 1 w = [f**50 for _ in range(100)] return (desc, cputime(t)) diff --git a/src/sage/misc/binary_tree.pyi b/src/sage/misc/binary_tree.pyi index 7adb4caf709..faff1ee7871 100644 --- a/src/sage/misc/binary_tree.pyi +++ b/src/sage/misc/binary_tree.pyi @@ -6,32 +6,15 @@ class binary_tree_node: right: Optional['binary_tree_node'] value: object -def BinaryTreeNode(key: int, value: object) -> binary_tree_node: - ... - -def free_binary_tree_node(node: binary_tree_node) -> None: - ... - -def binary_tree_dealloc(node: Optional[binary_tree_node]) -> None: - ... - -def binary_tree_insert(node: binary_tree_node, key: int, value: object) -> None: - ... - -def binary_tree_get(node: Optional[binary_tree_node], key: int) -> Optional[object]: - ... - -def binary_tree_delete(node: binary_tree_node, key: int) -> Optional[object]: - ... - -def binary_tree_left_excise(node: binary_tree_node) -> Optional[binary_tree_node]: - ... - -def binary_tree_right_excise(node: binary_tree_node) -> Optional[binary_tree_node]: - ... - -def binary_tree_head_excise(node: binary_tree_node) -> Optional[binary_tree_node]: - ... +def BinaryTreeNode(key: int, value: object) -> binary_tree_node: ... +def free_binary_tree_node(node: binary_tree_node) -> None: ... +def binary_tree_dealloc(node: Optional[binary_tree_node]) -> None: ... +def binary_tree_insert(node: binary_tree_node, key: int, value: object) -> None: ... +def binary_tree_get(node: Optional[binary_tree_node], key: int) -> Optional[object]: ... +def binary_tree_delete(node: binary_tree_node, key: int) -> Optional[object]: ... +def binary_tree_left_excise(node: binary_tree_node) -> Optional[binary_tree_node]: ... +def binary_tree_right_excise(node: binary_tree_node) -> Optional[binary_tree_node]: ... +def binary_tree_head_excise(node: binary_tree_node) -> Optional[binary_tree_node]: ... LIST_PREORDER: int LIST_POSTORDER: int @@ -39,50 +22,22 @@ LIST_INORDER: int LIST_KEYS: int LIST_VALUES: int -def binary_tree_list(node: binary_tree_node, behavior: int) -> list[object]: - ... +def binary_tree_list(node: binary_tree_node, behavior: int) -> list[object]: ... class BinaryTree: head: Optional[binary_tree_node] - def __cinit__(self) -> None: - ... - - def __dealloc__(self) -> None: - ... - - def insert(self, key: object, value: Optional[object] = None) -> None: - ... - - def delete(self, key: int) -> Optional[object]: - ... - - def get(self, key: int) -> Optional[object]: - ... - - def contains(self, key: int) -> bool: - ... - - def get_max(self) -> Optional[object]: - ... - - def get_min(self) -> Optional[object]: - ... - - def pop_max(self) -> Optional[object]: - ... - - def pop_min(self) -> Optional[object]: - ... - - def is_empty(self) -> bool: - ... - - def keys(self, order: str = 'inorder') -> list[int]: - ... - - def values(self, order: str = 'inorder') -> list[object]: - ... - - def _headkey_(self) -> int: - ... + def __cinit__(self) -> None: ... + def __dealloc__(self) -> None: ... + def insert(self, key: object, value: Optional[object] = None) -> None: ... + def delete(self, key: int) -> Optional[object]: ... + def get(self, key: int) -> Optional[object]: ... + def contains(self, key: int) -> bool: ... + def get_max(self) -> Optional[object]: ... + def get_min(self) -> Optional[object]: ... + def pop_max(self) -> Optional[object]: ... + def pop_min(self) -> Optional[object]: ... + def is_empty(self) -> bool: ... + def keys(self, order: str = 'inorder') -> list[int]: ... + def values(self, order: str = 'inorder') -> list[object]: ... + def _headkey_(self) -> int: ... diff --git a/src/sage/misc/bindable_class.py b/src/sage/misc/bindable_class.py index 69e3a5d6473..91422215253 100644 --- a/src/sage/misc/bindable_class.py +++ b/src/sage/misc/bindable_class.py @@ -1,6 +1,7 @@ """ Bindable classes """ + # **************************************************************************** # Copyright (C) 2012 Nicolas M. Thiery # @@ -121,6 +122,7 @@ class BindableClass(metaclass=ClasscallMetaclass): sage: outer = Outer() sage: TestSuite(outer.Inner).run(skip=["_test_pickling"]) """ + @staticmethod def __classget__(cls, instance, owner): """ @@ -210,6 +212,7 @@ class BoundClass(functools.partial): sage: g() 8 """ + __doc__ = None # See warning above def __init__(self, *args): @@ -233,6 +236,7 @@ def __repr__(self): # Test classes ############################################################################## + class Inner2(BindableClass): """ Some documentation for Inner2 @@ -244,6 +248,7 @@ class Outer(metaclass=NestedClassMetaclass): """ A class with a bindable nested class, for testing purposes """ + class Inner(BindableClass): """ Some documentation for Outer.Inner diff --git a/src/sage/misc/c3.pyi b/src/sage/misc/c3.pyi index d3a795c78e7..8f0b18f5274 100644 --- a/src/sage/misc/c3.pyi +++ b/src/sage/misc/c3.pyi @@ -1,3 +1 @@ - -def C3_algorithm(start: object, bases: str, attribute: str, proper: bool) -> list[object]: - ... +def C3_algorithm(start: object, bases: str, attribute: str, proper: bool) -> list[object]: ... diff --git a/src/sage/misc/cachefunc.pyi b/src/sage/misc/cachefunc.pyi index 374852ca71e..781b7e3024f 100644 --- a/src/sage/misc/cachefunc.pyi +++ b/src/sage/misc/cachefunc.pyi @@ -1,124 +1,52 @@ from collections.abc import Callable from typing import Any -def dict_key(o: Any) -> Any: - ... - -def cache_key(o: Any) -> Any: - ... - -def cached_method(f=None, name: str | None = None, key=None, do_pickle: bool = False) -> CachedMethod: - ... - -def cached_function(f=None, name: str | None = None, key=None, do_pickle: bool = False) -> CachedFunction: - ... +def dict_key(o: Any) -> Any: ... +def cache_key(o: Any) -> Any: ... +def cached_method(f=None, name: str | None = None, key=None, do_pickle: bool = False) -> CachedMethod: ... +def cached_function(f=None, name: str | None = None, key=None, do_pickle: bool = False) -> CachedFunction: ... class CachedFunction: - def __init__(self, f: Callable, classmethod: bool = False, - name: str | None = None, key: Callable | None = None, - do_pickle: bool = False) -> None: - ... - - def __call__(self, *args: Any, **kwds: Any) -> Any: - ... - - def cached(self, *args: Any, **kwds: Any) -> Any: - ... - - def is_in_cache(self, *args: Any, **kwds: Any) -> bool: - ... - - def set_cache(self, value: Any, *args: Any, **kwds: Any) -> None: - ... - - def get_key(self, *args: Any, **kwds: Any) -> Any: - ... - - def __repr__(self) -> str: - ... - - def clear_cache(self) -> None: - ... - - def precompute(self, arglist: Any, num_processes: int = 1) -> None: - ... + def __init__(self, f: Callable, classmethod: bool = False, name: str | None = None, key: Callable | None = None, do_pickle: bool = False) -> None: ... + def __call__(self, *args: Any, **kwds: Any) -> Any: ... + def cached(self, *args: Any, **kwds: Any) -> Any: ... + def is_in_cache(self, *args: Any, **kwds: Any) -> bool: ... + def set_cache(self, value: Any, *args: Any, **kwds: Any) -> None: ... + def get_key(self, *args: Any, **kwds: Any) -> Any: ... + def __repr__(self) -> str: ... + def clear_cache(self) -> None: ... + def precompute(self, arglist: Any, num_processes: int = 1) -> None: ... class CachedMethod: - def __init__(self, f: Callable, name: str | None = None, - key: Callable | None = None, - do_pickle: bool = False) -> None: - ... - - def __call__(self, inst: Any, *args: Any, **kwds: Any) -> Any: - ... - - def _get_instance_cache(self, inst: Any) -> dict: - ... - - def __get__(self, inst: Any, cls: Any) -> Any: - ... + def __init__(self, f: Callable, name: str | None = None, key: Callable | None = None, do_pickle: bool = False) -> None: ... + def __call__(self, inst: Any, *args: Any, **kwds: Any) -> Any: ... + def _get_instance_cache(self, inst: Any) -> dict: ... + def __get__(self, inst: Any, cls: Any) -> Any: ... class CacheDict(dict): pass class CachedInParentMethod(CachedMethod): - def __init__(self, f: Callable, name: str | None = None, - key: Callable | None = None, - do_pickle: bool = False) -> None: - ... - - def _get_instance_cache(self, inst: Any) -> dict: - ... - - def __get__(self, inst: Any, cls: Any) -> Any: - ... + def __init__(self, f: Callable, name: str | None = None, key: Callable | None = None, do_pickle: bool = False) -> None: ... + def _get_instance_cache(self, inst: Any) -> dict: ... + def __get__(self, inst: Any, cls: Any) -> Any: ... class CachedMethodCaller(CachedFunction): - def __init__(self, cachedmethod: CachedMethod, inst: Any, - cache: dict | None = None, name: str | None = None, - key: Callable | None = None, - do_pickle: bool = False) -> None: - ... - - def _instance_call(self, *args: Any, **kwds: Any) -> Any: - ... - - def __call__(self, *args: Any, **kwds: Any) -> Any: - ... - - def cached(self, *args: Any, **kwds: Any) -> Any: - ... - - def __get__(self, inst: Any, cls: Any) -> Any: - ... - - def precompute(self, arglist: Any, num_processes: int = 1) -> None: - ... + def __init__(self, cachedmethod: CachedMethod, inst: Any, cache: dict | None = None, name: str | None = None, key: Callable | None = None, do_pickle: bool = False) -> None: ... + def _instance_call(self, *args: Any, **kwds: Any) -> Any: ... + def __call__(self, *args: Any, **kwds: Any) -> Any: ... + def cached(self, *args: Any, **kwds: Any) -> Any: ... + def __get__(self, inst: Any, cls: Any) -> Any: ... + def precompute(self, arglist: Any, num_processes: int = 1) -> None: ... class CachedMethodCallerNoArgs(CachedFunction): - def __init__(self, inst: Any, f: Callable, cache: Any = None, - name: str | None = None, - do_pickle: bool = False) -> None: - ... - - def _instance_call(self) -> Any: - ... - - def __call__(self) -> Any: - ... - - def set_cache(self, value: Any) -> None: - ... - - def clear_cache(self) -> None: - ... - - def is_in_cache(self) -> bool: - ... - - def __get__(self, inst: Any, cls: Any) -> Any: - ... + def __init__(self, inst: Any, f: Callable, cache: Any = None, name: str | None = None, do_pickle: bool = False) -> None: ... + def _instance_call(self) -> Any: ... + def __call__(self) -> Any: ... + def set_cache(self, value: Any) -> None: ... + def clear_cache(self) -> None: ... + def is_in_cache(self) -> bool: ... + def __get__(self, inst: Any, cls: Any) -> Any: ... class GloballyCachedMethodCaller(CachedMethodCaller): - def get_key_args_kwds(self, args: tuple, kwds: dict) -> Any: - ... + def get_key_args_kwds(self, args: tuple, kwds: dict) -> Any: ... diff --git a/src/sage/misc/call.py b/src/sage/misc/call.py index ff8baf2e353..832609d3df3 100644 --- a/src/sage/misc/call.py +++ b/src/sage/misc/call.py @@ -184,4 +184,5 @@ def call_method(obj, name, *args, **kwds): from sage.misc.persist import register_unpickle_override + register_unpickle_override("sage.misc.misc", "call_method", call_method) diff --git a/src/sage/misc/callable_dict.pyi b/src/sage/misc/callable_dict.pyi index b3c8f349513..15b8185ca92 100644 --- a/src/sage/misc/callable_dict.pyi +++ b/src/sage/misc/callable_dict.pyi @@ -1,6 +1,3 @@ class CallableDict(dict): - def __call__(self, key: object) -> object: - ... - - def __repr__(self) -> str: - ... + def __call__(self, key: object) -> object: ... + def __repr__(self) -> str: ... diff --git a/src/sage/misc/citation.pyi b/src/sage/misc/citation.pyi index 2aba40502ea..5cb98db8fef 100644 --- a/src/sage/misc/citation.pyi +++ b/src/sage/misc/citation.pyi @@ -1,6 +1,2 @@ - -def get_systems(cmd: str) -> list[str]: - ... - -def cython_profile_enabled() -> bool: - ... +def get_systems(cmd: str) -> list[str]: ... +def cython_profile_enabled() -> bool: ... diff --git a/src/sage/misc/classgraph.py b/src/sage/misc/classgraph.py index 30d7b8372bb..0f0283c2737 100644 --- a/src/sage/misc/classgraph.py +++ b/src/sage/misc/classgraph.py @@ -1,6 +1,7 @@ r""" Class inheritance graphs """ + # **************************************************************************** # Copyright (C) 2007 William Stein # 2011 Nicolas M. Thiery @@ -103,8 +104,7 @@ def class_graph(top, depth=5, name_filter=None, classes=None, as_graph=True): return classes if name_filter is None: name_filter = top.__name__ - children = [item for item in top.__dict__.values() - if inspect.ismodule(item) or inspect.isclass(item)] + children = [item for item in top.__dict__.values() if inspect.ismodule(item) or inspect.isclass(item)] depth -= 1 elif inspect.isclass(top): if name_filter is None: @@ -118,11 +118,11 @@ def class_graph(top, depth=5, name_filter=None, classes=None, as_graph=True): # Recurse for child in children: - class_graph(child, depth=depth, name_filter=name_filter, - classes=classes, as_graph=False) + class_graph(child, depth=depth, name_filter=name_filter, classes=classes, as_graph=False) # (first recursive call): construct the graph if as_graph: from sage.graphs.digraph import DiGraph + return DiGraph(classes) return classes diff --git a/src/sage/misc/compat.py b/src/sage/misc/compat.py index 91bc00834c0..4f6e0bd8082 100644 --- a/src/sage/misc/compat.py +++ b/src/sage/misc/compat.py @@ -48,6 +48,7 @@ def _find_library(name): os.environ['DYLD_LIBRARY_PATH'] = orig_dyld_library_path else: os.environ.pop('DYLD_LIBRARY_PATH', None) + else: # On other Unix-like platforms, at least where gcc is available, # ctypes.util.find_library works, because it takes into account where gcc @@ -82,7 +83,6 @@ def find_library(name): lib_dirs = (LDPATH_STR.split(':') if LDPATH_STR else []) + [os.path.join(SAGE_LOCAL, 'lib')] for libdir in lib_dirs: for libext in ['so', 'a']: - implib = os.path.join(libdir, - 'lib{0}.{1}'.format(name, libext)) + implib = os.path.join(libdir, 'lib{0}.{1}'.format(name, libext)) if os.path.exists(implib): return implib diff --git a/src/sage/misc/converting_dict.py b/src/sage/misc/converting_dict.py index 1481dc2b66a..b41ab22987f 100644 --- a/src/sage/misc/converting_dict.py +++ b/src/sage/misc/converting_dict.py @@ -35,6 +35,7 @@ sage: list(v)[0].parent() Multivariate Polynomial Ring in x, y over Algebraic Real Field """ + # **************************************************************************** # Copyright (C) 2015 Martin von Gagern # diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index 6d30189ae89..2b721b6fea5 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -58,6 +58,7 @@ def _standard_libs_libdirs_incdirs_aliases(): standard_incdirs = [dir.as_posix() for dir in get_include_dirs()] + aliases["NTL_INCDIR"] return standard_libs, standard_libdirs, standard_incdirs, aliases + ################################################################ # If the user attaches a .spyx file and changes it, we have # to reload an .so. @@ -82,9 +83,7 @@ def _webbrowser_open_file(path): webbrowser.open(Path(path).as_uri()) -def cython(filename, verbose=0, compile_message=False, - use_cache=False, create_local_c_file=False, annotate=True, view_annotate=False, - view_annotate_callback=None, sage_namespace=True, create_local_so_file=False): +def cython(filename, verbose=0, compile_message=False, use_cache=False, create_local_c_file=False, annotate=True, view_annotate=False, view_annotate_callback=None, sage_namespace=True, create_local_so_file=False): r""" Compile a Cython file. This converts a Cython file to a C (or C++ file), and then compiles that. The .c file and the .so file are @@ -300,12 +299,13 @@ def cython(filename, verbose=0, compile_message=False, # Find the name. if use_cache: from importlib.machinery import EXTENSION_SUFFIXES + for f in os.listdir(target_dir): for suffix in EXTENSION_SUFFIXES: if f.endswith(suffix): # use the first matching extension prev_file = os.path.join(target_dir, f) - prev_name = f[:-len(suffix)] + prev_name = f[: -len(suffix)] break else: # no match, try next file @@ -357,6 +357,7 @@ def cython(filename, verbose=0, compile_message=False, from Cython.Compiler.Errors import CompileError from setuptools.dist import Distribution from setuptools.extension import Extension + set_verbosity(verbose) Cython.Compiler.Options.annotate = annotate @@ -366,12 +367,7 @@ def cython(filename, verbose=0, compile_message=False, extra_compile_args = ['-w'] # no warnings extra_link_args = [] - ext = Extension(name, - sources=[pyxfile], - extra_compile_args=extra_compile_args, - extra_link_args=extra_link_args, - libraries=standard_libs, - library_dirs=standard_libdirs) + ext = Extension(name, sources=[pyxfile], extra_compile_args=extra_compile_args, extra_link_args=extra_link_args, libraries=standard_libs, library_dirs=standard_libdirs) directives = {'language_level': 3, 'cdivision': True} @@ -381,14 +377,9 @@ def cython(filename, verbose=0, compile_message=False, with restore_cwd(target_dir): try: from sage.misc.package_dir import cython_namespace_package_support + with cython_namespace_package_support(): - ext, = cythonize([ext], - aliases=aliases, - include_path=includes, - compiler_directives=directives, - quiet=(verbose <= 0), - errors_to_stderr=False, - use_listing_file=True) + (ext,) = cythonize([ext], aliases=aliases, include_path=includes, compiler_directives=directives, quiet=(verbose <= 0), errors_to_stderr=False, use_listing_file=True) finally: # Read the "listing file" which is the file containing # warning and error messages generated by Cython. @@ -402,20 +393,15 @@ def cython(filename, verbose=0, compile_message=False, if verbose >= 0: # triggered by Cython 3 with unpatched cysignals 1.11.2 - cython_messages = re.sub( - "^.*The keyword 'nogil' should appear at the end of the function signature line. " - "Placing it before 'except' or 'noexcept' will be disallowed in a future version of Cython.\n", - "", cython_messages, flags=re.MULTILINE) + cython_messages = re.sub("^.*The keyword 'nogil' should appear at the end of the function signature line. " "Placing it before 'except' or 'noexcept' will be disallowed in a future version of Cython.\n", "", cython_messages, flags=re.MULTILINE) sys.stderr.write(cython_messages) sys.stderr.flush() if create_local_c_file: - shutil.copy(os.path.join(target_dir, ext.sources[0]), - os.curdir) + shutil.copy(os.path.join(target_dir, ext.sources[0]), os.curdir) if annotate: - shutil.copy(os.path.join(target_dir, name + ".html"), - os.curdir) + shutil.copy(os.path.join(target_dir, name + ".html"), os.curdir) if view_annotate: if not annotate: @@ -468,6 +454,7 @@ def _removed(ep): if create_local_so_file: # Copy module to current directory from importlib.machinery import EXTENSION_SUFFIXES + for ext in EXTENSION_SUFFIXES: path = os.path.join(target_dir, name + ext) if os.path.exists(path): @@ -550,7 +537,10 @@ def __getattr__(self, name): def f(%s): return %s - """ % (v, expr) + """ % ( + v, + expr, + ) if verbose > 0: print(s) tmpfile = tmp_filename(ext='.pyx') @@ -588,6 +578,7 @@ def cython_import(filename, **kwds): return builtins.__import__(name) except ModuleNotFoundError: import importlib + importlib.invalidate_caches() return builtins.__import__(name) finally: diff --git a/src/sage/misc/decorators.py b/src/sage/misc/decorators.py index 87c4dc1193b..b627d776fb4 100644 --- a/src/sage/misc/decorators.py +++ b/src/sage/misc/decorators.py @@ -12,6 +12,7 @@ file into the reference manual. - Julian Rueth (2014-03-19): added ``decorator_keywords`` decorator """ + # ***************************************************************************** # Copyright (C) 2009 Tim Dumol # 2010,2011 Johan S. R. Nielsen @@ -175,6 +176,7 @@ def f(wrapper, assigned=assigned, updated=updated): # as the argspec of the function instead of using reflection. wrapper._sage_argspec_ = lambda: sage_getargspec(wrapped) return wrapper + return f @@ -242,12 +244,7 @@ def __call__(self, func): left_meth = self.operators[self.precedence]['left'] right_meth = self.operators[self.precedence]['right'] wrapper_name = func.__name__ - wrapper_members = { - 'function': staticmethod(func), - left_meth: _infix_wrapper._left, - right_meth: _infix_wrapper._right, - '_sage_src_': lambda: sage_getsource(func) - } + wrapper_members = {'function': staticmethod(func), left_meth: _infix_wrapper._left, right_meth: _infix_wrapper._right, '_sage_src_': lambda: sage_getsource(func)} for attr in WRAPPER_ASSIGNMENTS: try: wrapper_members[attr] = getattr(func, attr) @@ -283,8 +280,7 @@ def _left(self, right): new = copy(self) new.right = right return new - raise SyntaxError("Infix operator already has its " - "right argument") + raise SyntaxError("Infix operator already has its " "right argument") else: return self.function(self.left, right) @@ -295,8 +291,7 @@ def _right(self, left): new = copy(self) new.left = left return new - raise SyntaxError("Infix operator already has its " - "left argument") + raise SyntaxError("Infix operator already has its " "left argument") else: return self.function(left, self.right) @@ -338,12 +333,14 @@ def decorator_defaults(func): (3, 4) my_fun """ + @sage_wraps(func) def my_wrap(*args, **kwds): if len(kwds) == 0 and len(args) == 1: # call without parentheses return func(*args) return lambda f: func(f, *args, **kwds) + return my_wrap @@ -396,16 +393,17 @@ def __call__(self, func): FullArgSpec(args=['arrow_size'], varargs='args', varkw='kwds', defaults=(2,), kwonlyargs=[], kwonlydefaults=None, annotations={}) """ + @sage_wraps(func) def wrapper(*args, **kwds): suboptions = copy(self.options) - suboptions.update(kwds.pop(self.name+"options", {})) + suboptions.update(kwds.pop(self.name + "options", {})) # Collect all the relevant keywords in kwds # and put them in suboptions for key, value in list(kwds.items()): if key.startswith(self.name): - suboptions[key[len(self.name):]] = value + suboptions[key[len(self.name) :]] = value del kwds[key] kwds[self.name + "options"] = suboptions @@ -420,13 +418,13 @@ def argspec(): def listForNone(l): return l if l is not None else [] + newArgs = [self.name + opt for opt in self.options.keys()] args = (argspec.args if argspec.args is not None else []) + newArgs - defaults = (argspec.defaults if argspec.defaults is not None else ()) \ - + tuple(self.options.values()) + defaults = (argspec.defaults if argspec.defaults is not None else ()) + tuple(self.options.values()) # Note: argspec.defaults is not always a tuple for some reason - return FullArgSpec(args, argspec.varargs, argspec.varkw, defaults, - kwonlyargs=[], kwonlydefaults=None, annotations={}) + return FullArgSpec(args, argspec.varargs, argspec.varkw, defaults, kwonlyargs=[], kwonlydefaults=None, annotations={}) + wrapper._sage_argspec_ = argspec return wrapper @@ -486,6 +484,7 @@ def __call__(self, func): sage: f2(alpha=1) () [('__original_opts', {'alpha': 1}), ('alpha', 1), ('rgbcolor', (0, 0, 1))] """ + @sage_wraps(func) def wrapper(*args, **kwds): options = copy(wrapper.options) @@ -499,12 +498,10 @@ def wrapper(*args, **kwds): # special attribute _sage_argspec_ (see e.g. sage.misc.sageinspect) def argspec(): argspec = sage_getargspec(func) - args = ((argspec.args if argspec.args is not None else []) + - list(self.options)) + args = (argspec.args if argspec.args is not None else []) + list(self.options) defaults = (argspec.defaults or ()) + tuple(self.options.values()) # Note: argspec.defaults is not always a tuple for some reason - return FullArgSpec(args, argspec.varargs, argspec.varkw, defaults, - kwonlyargs=[], kwonlydefaults=None, annotations={}) + return FullArgSpec(args, argspec.varargs, argspec.varkw, defaults, kwonlyargs=[], kwonlydefaults=None, annotations={}) wrapper._sage_argspec_ = argspec @@ -553,20 +550,26 @@ def reset(): wrapper.options = copy(self.options) wrapper.reset = reset - wrapper.reset.__doc__ = """ + wrapper.reset.__doc__ = ( + """ Reset the options to the defaults. Defaults: %s - """ % self.options + """ + % self.options + ) wrapper.defaults = defaults - wrapper.defaults.__doc__ = """ + wrapper.defaults.__doc__ = ( + """ Return the default options. Defaults: %s - """ % self.options + """ + % self.options + ) return wrapper @@ -643,14 +646,15 @@ def __call__(self, func): See https://github.com/sagemath/sage/issues/13109 for details. () {'new_option': 1} """ + @sage_wraps(func) def wrapper(*args, **kwds): for old_name, new_name in self.renames.items(): if old_name in kwds and new_name not in kwds: if self.deprecation is not None: from sage.misc.superseded import deprecation - deprecation(self.deprecation, "use the option " - "%r instead of %r" % (new_name, old_name)) + + deprecation(self.deprecation, "use the option " "%r instead of %r" % (new_name, old_name)) kwds[new_name] = kwds[old_name] del kwds[old_name] return func(*args, **kwds) @@ -687,6 +691,7 @@ class specialize: sage: greet(name = 'Javert') Bon Voyage, Javert! """ + def __init__(self, *args, **kwargs): self.args = args self.kwargs = kwargs @@ -726,9 +731,11 @@ def decorator_keywords(func): sage: foo(1) 1 """ + @sage_wraps(func) def wrapped(f=None, **kwargs): if f is None: return sage_wraps(func)(lambda f: func(f, **kwargs)) return func(f, **kwargs) + return wrapped diff --git a/src/sage/misc/defaults.py b/src/sage/misc/defaults.py index ea2719a2bf6..4d7851b786a 100644 --- a/src/sage/misc/defaults.py +++ b/src/sage/misc/defaults.py @@ -3,6 +3,7 @@ AUTHORS: William Stein and David Kohel """ + # **************************************************************************** # Copyright (C) 2004 William Stein # diff --git a/src/sage/misc/dev_tools.py b/src/sage/misc/dev_tools.py index 7cd32fb321c..0269f7eae43 100644 --- a/src/sage/misc/dev_tools.py +++ b/src/sage/misc/dev_tools.py @@ -7,6 +7,7 @@ - Vincent Delecroix (2012 and 2013): improve import_statements """ + # **************************************************************************** # Copyright (C) 2011 Nicolas M. Thiery # @@ -73,8 +74,7 @@ def runsnake(command): deprecation(39274, "just use the runsnake program directly") tmpfile = tmp_filename() - cProfile.runctx(preparse(command.lstrip().rstrip()), get_main_globals(), - locals(), filename=tmpfile) + cProfile.runctx(preparse(command.lstrip().rstrip()), get_main_globals(), locals(), filename=tmpfile) os.system("/usr/bin/python -E `which runsnake` %s &" % tmpfile) @@ -180,6 +180,7 @@ def load_submodules(module=None, exclude_pattern=None): if module is None: import sage + module = sage exclude_pattern = r"^sage\.libs|^sage\.tests|tests$|^sage\.all_|all$|sage\.interacts$|^sage\.misc\.benchmark$" @@ -490,13 +491,13 @@ def expand_comma_separated_names(obj): else: yield obj - for obj in itertools.chain.from_iterable(expand_comma_separated_names(object) - for object in objects): - name = None # the name of the object + for obj in itertools.chain.from_iterable(expand_comma_separated_names(object) for object in objects): + name = None # the name of the object # 1. if obj is a string, we look for an object that has that name if isinstance(obj, str): from sage.all import sage_globals + G = sage_globals() name = obj if name in G: @@ -530,8 +531,7 @@ def expand_comma_separated_names(obj): modules = set() for o in obj: modules.update(find_object_modules(o)) - print("# **Warning**: distinct objects with name '{}' " - "in:".format(name)) + print("# **Warning**: distinct objects with name '{}' " "in:".format(name)) for mod in sorted(modules): print("# - {}".format(mod)) @@ -541,9 +541,7 @@ def expand_comma_separated_names(obj): obj = obj[0] except IndexError: if deprecation: - raise LookupError( - "object named {!r} is deprecated (see Issue #" - "{})".format(name, deprecation)) + raise LookupError("object named {!r} is deprecated (see Issue #" "{})".format(name, deprecation)) else: raise LookupError("no object named {!r}".format(name)) @@ -579,9 +577,8 @@ def is_ascii(s): Equivalent of `str.isascii` in Python >= 3.7 """ return all(ord(c) < 128 for c in s) - if any(is_ascii(s) - for obj_names in modules.values() - for s in obj_names): + + if any(is_ascii(s) for obj_names in modules.values() for s in obj_names): for module_name, obj_names in list(modules.items()): if any(not is_ascii(s) for s in obj_names): obj_names = [name for name in obj_names if is_ascii(name)] @@ -591,11 +588,10 @@ def is_ascii(s): modules[module_name] = obj_names if len(modules) == 1: # the module is well defined - (module_name, obj_names), = modules.items() + ((module_name, obj_names),) = modules.items() if name is None: if verbose and len(obj_names) > 1: - print("# ** Warning **: several names for that object: " - "{}".format(', '.join(sorted(obj_names)))) + print("# ** Warning **: several names for that object: " "{}".format(', '.join(sorted(obj_names)))) name = alias = obj_names[0] elif name in modules[module_name]: alias = name @@ -619,6 +615,7 @@ def is_ascii(s): # if the object is a class instance, it is likely that it is defined in # some XYZ.all module from .sageinspect import isclassinstance + if isclassinstance(obj): module_name = type(obj).__module__ i = module_name.rfind('.') @@ -633,16 +630,13 @@ def is_ascii(s): # here, either "obj" is a class instance but there is no natural # candidate for its module or "obj" is not a class instance. all_re = re.compile(r'.+\.all(?:_\w+)?$') - not_all_modules = [mod for mod in modules - if not all_re.match(mod)] + not_all_modules = [mod for mod in modules if not all_re.match(mod)] if not not_all_modules: - print("# ** Warning **: the object {} is only defined in " - ".all modules".format(obj)) + print("# ** Warning **: the object {} is only defined in " ".all modules".format(obj)) module_name = next(iter(modules)) else: if len(not_all_modules) > 1: - print("# ** Warning **: several modules for the object " - "{}: {}".format(obj, ', '.join(sorted(modules)))) + print("# ** Warning **: several modules for the object " "{}: {}".format(obj, ', '.join(sorted(modules)))) module_name = not_all_modules[0] # 3. Now that we found the module, we fix the problem of the alias @@ -659,8 +653,7 @@ def is_ascii(s): if lazy: res.append("from sage.misc.lazy_import import lazy_import") - res.extend(import_statement_string(module_name, answer[module_name], lazy) - for module_name in sorted(answer)) + res.extend(import_statement_string(module_name, answer[module_name], lazy) for module_name in sorted(answer)) if answer_as_str: return '\n'.join(res) diff --git a/src/sage/misc/edit_module.py b/src/sage/misc/edit_module.py index 90981803fd5..df55e896cf9 100644 --- a/src/sage/misc/edit_module.py +++ b/src/sage/misc/edit_module.py @@ -23,6 +23,7 @@ In fact, if the environment variable :envvar:`EDITOR` is set to a known editor, then the system will use that if no template has been set explicitly. """ + # **************************************************************************** # Copyright (C) 2007 Nils Bruin and # William Stein @@ -45,15 +46,7 @@ # we can set some defaults, however. Add your own if you like. -template_defaults = { - 'vi': Template('vi -c ${line} ${file}'), - 'vim': Template('vim -c ${line} ${file}'), - 'emacs': Template('emacs ${opts} +${line} ${file}'), - 'nedit-nc': Template('nedit-nc -line ${line} ${file}'), - 'nedit-client': Template('nedit-client -line ${line} ${file}'), - 'ncl': Template('ncl -line ${line} ${file}'), - 'gedit': Template('gedit +${line} ${file} &'), - 'kate': Template('kate -u --line +${line} ${file} &')} +template_defaults = {'vi': Template('vi -c ${line} ${file}'), 'vim': Template('vim -c ${line} ${file}'), 'emacs': Template('emacs ${opts} +${line} ${file}'), 'nedit-nc': Template('nedit-nc -line ${line} ${file}'), 'nedit-client': Template('nedit-client -line ${line} ${file}'), 'ncl': Template('ncl -line ${line} ${file}'), 'gedit': Template('gedit +${line} ${file} &'), 'kate': Template('kate -u --line +${line} ${file} &')} def file_and_line(obj): @@ -99,6 +92,7 @@ def file_and_line(obj): # for the 3 lines that were prefixed in the preparsing process # from sage.misc.sageinspect import sage_getfile, sage_getsourcelines + filename = sage_getfile(obj) lineno = sage_getsourcelines(obj)[1] - 1 if filename.endswith('.py'): @@ -140,6 +134,7 @@ def template_fields(template): dict[inst.args[0]] = None return list(dict) + # The routine set_edit_template should only do some consistency # checks on template_string It should not do any magic. This routine # should give the user full control over what is going on. @@ -175,6 +170,7 @@ def set_edit_template(template_string): raise ValueError("Only ${file} and ${line} are allowed as template variables, and ${file} must occur.") edit_template = template_string + # The routine set_editor is for convenience and hence is allowed to # apply magic. Given an editor name and possibly some options, it # should try to set an editor_template that is as appropriate as @@ -256,7 +252,7 @@ def edit(obj, editor=None, bg=None): ED = os.environ['EDITOR'] EDITOR = ED.split() base = EDITOR[0] - opts = ' '.join(EDITOR[1:]) # for future use + opts = ' '.join(EDITOR[1:]) # for future use set_editor(base, opts=opts) except (ValueError, KeyError, IndexError): raise ValueError("Use set_edit_template() to set a default") @@ -295,6 +291,7 @@ def edit_devel(self, filename, linenum): editor supports it, also at the line in which gcd is defined. """ import IPython.core.hooks + runpathpattern = '^' + sage.env.SAGE_LIB develbranch = sage.env.SAGE_SRC filename = re.sub(runpathpattern, develbranch, filename) diff --git a/src/sage/misc/element_with_label.py b/src/sage/misc/element_with_label.py index 8ae3d4ee523..30295c31fbf 100644 --- a/src/sage/misc/element_with_label.py +++ b/src/sage/misc/element_with_label.py @@ -42,6 +42,7 @@ class ElementWithLabel: sage: list(nP) [(0, 0), (0, 0)] """ + def __init__(self, element, label): """ Construct an object that wraps ``element`` but presents itself @@ -148,8 +149,7 @@ def __eq__(self, other): sage: b == 1 False """ - if not (isinstance(self, ElementWithLabel) and - isinstance(other, ElementWithLabel)): + if not (isinstance(self, ElementWithLabel) and isinstance(other, ElementWithLabel)): return False return self.element == other.element and self.label == other.label diff --git a/src/sage/misc/explain_pickle.py b/src/sage/misc/explain_pickle.py index 660bdaf23ba..5b1ca85f2fb 100644 --- a/src/sage/misc/explain_pickle.py +++ b/src/sage/misc/explain_pickle.py @@ -166,8 +166,7 @@ from sage.misc.sage_input import SageInputBuilder, SageInputExpression from sage.misc.sage_eval import sage_eval -from sage.misc.persist import (unpickle_override, unpickle_global, dumps, - register_unpickle_override, SageUnpickler) +from sage.misc.persist import unpickle_override, unpickle_global, dumps, register_unpickle_override, SageUnpickler # Python 3 does not have a "ClassType". Instead, we ensure that @@ -258,9 +257,7 @@ def explain_pickle(pickle=None, file=None, compress=True, **kwargs): return explain_pickle_string(p, **kwargs) -def explain_pickle_string(pickle, in_current_sage=False, - default_assumptions=False, eval=False, preparse=True, - pedantic=False): +def explain_pickle_string(pickle, in_current_sage=False, default_assumptions=False, eval=False, preparse=True, pedantic=False): r""" This is a helper function for :func:`explain_pickle`. It takes a decompressed pickle string as input; other than that, its options are all the same @@ -275,9 +272,7 @@ def explain_pickle_string(pickle, in_current_sage=False, """ sib = SageInputBuilder(preparse=preparse) - pe = PickleExplainer(sib, in_current_sage=in_current_sage, - default_assumptions=default_assumptions, - pedantic=pedantic) + pe = PickleExplainer(sib, in_current_sage=in_current_sage, default_assumptions=default_assumptions, pedantic=pedantic) v = pe.run_pickle(pickle) @@ -287,6 +282,7 @@ def explain_pickle_string(pickle, in_current_sage=False, if default_assumptions: raise ValueError("Not safe to evaluate code generated with default_assumptions") from sage.misc.sage_eval import sage_eval + result = sage_eval(ans, preparse=preparse) print(ans) return result @@ -385,6 +381,7 @@ class PickleDict: instead of always starting with an empty dictionary and assigning to it. """ + def __init__(self, items): r""" Initialize a PickleDict. @@ -404,6 +401,7 @@ class PickleInstance: other possible values of a :class:`PickleObject`, a :class:`PickleInstance` doesn't represent an exact value; instead, it gives the class (type) of the object. """ + def __init__(self, klass): r""" Initialize a PickleInstance. @@ -423,8 +421,8 @@ class PickleExplainer: symbolically and constructs :class:`SageInputExpression` objects instead of directly constructing values. """ - def __init__(self, sib, in_current_sage=False, default_assumptions=False, - pedantic=False): + + def __init__(self, sib, in_current_sage=False, default_assumptions=False, pedantic=False): r""" Initialize a PickleExplainer interpreter for the pickle virtual machine. @@ -835,10 +833,7 @@ def _APPENDS_helper(self, lst, slice): lst.value.extend(slice) lst.expression = self.sib(lst.value) elif isinstance(lst, PickleObject) or self.default_assumptions: - if isinstance(lst.value, list) or \ - (isinstance(lst.value, PickleInstance) and - issubclass(lst.value.klass, list)) or \ - self.default_assumptions: + if isinstance(lst.value, list) or (isinstance(lst.value, PickleInstance) and issubclass(lst.value.klass, list)) or self.default_assumptions: if len(slice) > 1: self.sib.command(lst, self.sib.name('list').extend(lst, slice)) else: @@ -1943,8 +1938,7 @@ def REDUCE(self): obj = self.pop() simple_call = False new_inst = False - if isinstance(args, PickleObject) and isinstance(args.value, tuple) \ - and len(args.value) > 0: + if isinstance(args, PickleObject) and isinstance(args.value, tuple) and len(args.value) > 0: simple_call = True if self.default_assumptions: simple_call = True @@ -2174,7 +2168,7 @@ def _SETITEMS_helper(self, slice): i = 0 while i < len(slice): k = slice[i] - v = slice[i+1] + v = slice[i + 1] # This marks d as immutable, if k or v happens to include d. self.sib(k) self.sib(v) @@ -2378,6 +2372,7 @@ def UNICODE(self, s): # Helper routines for explain_pickle + def unpickle_newobj(klass, args): r""" Create a new object; this corresponds to the C code @@ -2509,6 +2504,7 @@ def unpickle_extension(code): sage: remove_extension('sage.misc.explain_pickle', 'EmptyNewstyleClass', 42) """ from copyreg import _inverted_registry, _extension_cache + # copied from .get_extension() in pickle.py nil = [] obj = _extension_cache.get(code, nil) @@ -2654,6 +2650,7 @@ class EmptyOldstyleClass: A featureless old-style class (does not inherit from object); used for testing :func:`explain_pickle`. """ + def __repr__(self): r""" Print an EmptyOldstyleClass. @@ -2692,6 +2689,7 @@ class EmptyNewstyleClass: A featureless new-style class (inherits from object); used for testing :func:`explain_pickle`. """ + def __repr__(self): r""" Print an EmptyNewstyleClass. @@ -2715,6 +2713,7 @@ class TestReduceGetinitargs: An old-style class with a :func:`__getinitargs__` method. Used for testing :func:`explain_pickle`. """ + def __init__(self): r""" Initialize a TestReduceGetinitargs object. Note that the @@ -2767,6 +2766,7 @@ class TestReduceNoGetinitargs: An old-style class with no :meth:`__getinitargs__` method. Used for testing :func:`explain_pickle`. """ + def __init__(self): r""" Initialize a TestReduceNoGetinitargs object. Note that the @@ -2805,6 +2805,7 @@ class TestAppendList(list): A subclass of :class:`list`, with deliberately-broken append and extend methods. Used for testing :func:`explain_pickle`. """ + def append(self): r""" A deliberately broken append method. @@ -2853,6 +2854,7 @@ class TestAppendNonlist: A list-like class, carefully designed to test exact unpickling behavior. Used for testing :func:`explain_pickle`. """ + def __init__(self): r""" Construct a TestAppendNonlist. @@ -2937,6 +2939,7 @@ class TestBuild: A simple class with a :meth:`__getstate__` but no :meth:`__setstate__`. Used for testing :func:`explain_pickle`. """ + def __getstate__(self): r""" A __getstate__ method for testing pickling. @@ -2974,6 +2977,7 @@ class TestBuildSetstate(TestBuild): A simple class with a :meth:`__getstate__` and a :meth:`__setstate__`. Used for testing :func:`explain_pickle`. """ + def __setstate__(self, state): r""" Set the state of a TestBuildSetstate. Both prints a message, and @@ -3004,6 +3008,7 @@ class TestGlobalOldName: sage: loads(dumps(TestGlobalOldName())) TestGlobalNewName """ + pass @@ -3019,6 +3024,7 @@ class instead. Used for testing :func:`explain_pickle`. sage: loads(dumps(TestGlobalOldName())) TestGlobalNewName """ + def __repr__(self): r""" Print a TestGlobalNewName. @@ -3054,6 +3060,7 @@ class TestGlobalFunnyName: sage: globals()['funny$name'] is TestGlobalFunnyName True """ + def __repr__(self): r""" Print a TestGlobalFunnyName. diff --git a/src/sage/misc/flatten.py b/src/sage/misc/flatten.py index ccb81dcad09..1916eb7293e 100644 --- a/src/sage/misc/flatten.py +++ b/src/sage/misc/flatten.py @@ -70,9 +70,9 @@ def flatten(in_list, ltypes=(list, tuple), max_level=sys.maxsize): while isinstance(new_list[index], ltypes) and current_level < max_level: v = list(new_list[index]) len_v = len(v) - new_list[index: index + 1] = v + new_list[index : index + 1] = v old_level = level_list[index] - level_list[index: index + 1] = [0] * len_v + level_list[index : index + 1] = [0] * len_v if len_v: current_level += 1 level_list[index + len_v - 1] = old_level + 1 diff --git a/src/sage/misc/func_persist.py b/src/sage/misc/func_persist.py index 0b7f200ad58..137b72de654 100644 --- a/src/sage/misc/func_persist.py +++ b/src/sage/misc/func_persist.py @@ -32,6 +32,7 @@ def bern(n): ``func_persist`` of the current working directory, with one file for each evaluation of the function. """ + ######################################################################## # Copyright (C) 2006 William Stein # @@ -51,14 +52,12 @@ class func_persist: Put ``@func_persist`` right before your function definition to cache values it computes to disk. """ + def __init__(self, f, dir='func_persist'): self.__func = f self.__dir = dir os.makedirs(dir, exist_ok=True) - self.__doc__ = '%s%s%s' % ( - f.__name__, - inspect.signature(f), - f.__doc__) + self.__doc__ = '%s%s%s' % (f.__name__, inspect.signature(f), f.__doc__) def __call__(self, *args, **kwds): key = (tuple(args), tuple(kwds.items())) diff --git a/src/sage/misc/functional.py b/src/sage/misc/functional.py index cc854cb0d7b..00fb6d14a27 100644 --- a/src/sage/misc/functional.py +++ b/src/sage/misc/functional.py @@ -10,6 +10,7 @@ - David Joyner (2005-12-20): More Examples """ + # **************************************************************************** # Copyright (C) 2004 William Stein # @@ -125,6 +126,7 @@ def category(x): return x.category() except AttributeError: from sage.categories.objects import Objects + return Objects() @@ -586,6 +588,7 @@ def symbolic_sum(expression, *args, **kwds): if max(len(args), len(kwds)) <= 1: return sum(expression, *args, **kwds) from sage.symbolic.ring import SR + return SR(expression).sum(*args, **kwds) @@ -636,11 +639,13 @@ def symbolic_prod(expression, *args, **kwds): sum(log(f(i)), i, 1, n) """ from .misc_c import prod as c_prod + if hasattr(expression, 'prod'): return expression.prod(*args, **kwds) if len(args) <= 1: return c_prod(expression, *args) from sage.symbolic.ring import SR + return SR(expression).prod(*args, **kwds) @@ -786,6 +791,7 @@ def integral(x, *args, **kwds): if hasattr(x, 'integral'): return x.integral(*args, **kwds) from sage.symbolic.ring import SR + return SR(x).integral(*args, **kwds) @@ -1167,6 +1173,7 @@ def log(*args, **kwds): raise TypeError("log takes at least 1 arguments (0 given)") if len(args) == 1: from sage.functions.log import ln + return ln(args[0], **kwds) if len(args) > 2: raise TypeError("log takes at most 2 arguments (%s given)" % (len(args) + 1 - (base is not None))) @@ -1178,6 +1185,7 @@ def log(*args, **kwds): except (AttributeError, TypeError): pass from sage.functions.log import logb + return logb(args[0], args[1]) @@ -1581,11 +1589,13 @@ def numerical_approx(x, prec=None, digits=None, algorithm=None): """ if prec is None: from sage.arith.numerical_approx import digits_to_bits + prec = digits_to_bits(digits) try: n = x.numerical_approx except AttributeError: from sage.arith.numerical_approx import numerical_approx_generic + return numerical_approx_generic(x, prec) else: return n(prec, algorithm=algorithm) @@ -1783,6 +1793,7 @@ def isqrt(x): return x.isqrt() except AttributeError: from sage.functions.other import floor + n = Integer(floor(x)) return n.isqrt() @@ -1827,6 +1838,7 @@ def squarefree_part(x): pass from sage.arith.misc import factor from sage.structure.element import parent + F = factor(x) n = parent(x)(1) for p, e in F: @@ -1877,13 +1889,16 @@ def _do_sqrt(x, prec=None, extend=True, all=False): if prec: if x >= 0: from sage.rings.real_mpfr import RealField + return RealField(prec)(x).sqrt(all=all) from sage.rings.complex_mpfr import ComplexField + return ComplexField(prec)(x).sqrt(all=all) if x == -1: from sage.symbolic.constants import I as z else: from sage.symbolic.ring import SR + z = SR(x).sqrt() if all: @@ -1977,6 +1992,7 @@ def sqrt(x, *args, **kwds): return math.sqrt(x) if type(x).__module__ == 'numpy': from numpy import sqrt + return sqrt(x) try: return x.sqrt(*args, **kwds) diff --git a/src/sage/misc/gperftools.py b/src/sage/misc/gperftools.py index ce418f1200c..a35c673a0a4 100644 --- a/src/sage/misc/gperftools.py +++ b/src/sage/misc/gperftools.py @@ -66,6 +66,7 @@ def __init__(self, filename=None) -> None: """ if filename is None: from sage.misc.temporary_file import tmp_filename + self._filename = tmp_filename(ext='.perf') else: self._filename = filename @@ -115,6 +116,7 @@ def _libprofiler(self): if libprofiler is not None: return libprofiler import ctypes.util + name = ctypes.util.find_library('profiler') if name: libprofiler = ctypes.CDLL(name) @@ -136,6 +138,7 @@ def start(self): """ from signal import SIGPROF, SIG_DFL from cysignals.pysignals import setossignal + self._previous_sigprof_handler = setossignal(SIGPROF, SIG_DFL) profiler = self._libprofiler() self._t_start = time.time() @@ -161,8 +164,8 @@ def stop(self): self._t_stop = time.time() if (self._t_stop - self._t_start) < 0.1: from warnings import warn - warn('not enough samples, total runtime was ' - 'less than 100ms', RuntimeWarning) + + warn('not enough samples, total runtime was ' 'less than 100ms', RuntimeWarning) @cached_method def _pprof(self) -> str: @@ -186,6 +189,7 @@ def _pprof(self) -> str: """ potential_names = ['google-pprof', 'pprof'] from subprocess import check_output, CalledProcessError, STDOUT + for name in potential_names: try: bytes_version = check_output([name, '--version'], stderr=STDOUT) @@ -194,8 +198,8 @@ def _pprof(self) -> str: version = bytes_version.decode() if 'gperftools' not in version: from warnings import warn - warn('the "{0}" utility does not appear to be the gperftools profiler' - .format(name), RuntimeWarning) + + warn('the "{0}" utility does not appear to be the gperftools profiler'.format(name), RuntimeWarning) continue return name raise OSError('unable to run pprof, please install gperftools') @@ -235,6 +239,7 @@ def _call_pprof(self, *args, **kwds): ... """ from subprocess import check_call + check_call([self._pprof()] + list(args), **kwds) def top(self, cumulative=True): @@ -330,6 +335,7 @@ def crun(s, evaluator): """ prof = Profiler() from sage.repl.preparse import preparse + py_s = preparse(s) prof.start() try: @@ -351,8 +357,9 @@ def run_100ms() -> None: sage: from sage.misc.gperftools import run_100ms sage: run_100ms() """ - t0 = time.time() # start - t1 = t0 + 0.1 # end + t0 = time.time() # start + t1 = t0 + 0.1 # end from sage.symbolic.ring import SR + while time.time() < t1: sum(1 / (1 + SR(n) ** 2) for n in range(100)) diff --git a/src/sage/misc/html.py b/src/sage/misc/html.py index 8bccd25b900..533bc207351 100644 --- a/src/sage/misc/html.py +++ b/src/sage/misc/html.py @@ -102,15 +102,15 @@ def math_parse(s): if i == -1: # No dollar signs -- definitely done. return HtmlFragment(t + s) - if i > 0 and s[i-1] == '\\': + if i > 0 and s[i - 1] == '\\': # A dollar sign with a backslash right before it, so this is a # normal dollar sign. If processEscapes is enabled in MathJax, "\$" # will do the job. But as we do not assume that, we use the span # tag safely. - t += s[:i-1] + '$' - s = s[i+1:] + t += s[: i - 1] + '$' + s = s[i + 1 :] continue - elif i+1 < len(s) and s[i+1] == '$': + elif i + 1 < len(s) and s[i + 1] == '$': # Found a math environment. Double dollar sign so display mode. disp = True else: @@ -120,27 +120,27 @@ def math_parse(s): # Now find the matching $ sign and form the html string. if disp: - j = s[i+2:].find('$$') + j = s[i + 2 :].find('$$') if j == -1: j = len(s) s += '$$' else: j += i + 2 - txt = s[i+2:j] + txt = s[i + 2 : j] else: - j = s[i+2:].find('$') + j = s[i + 2 :].find('$') if j == -1: j = len(s) s += '$' else: j += i + 2 - txt = s[i+1:j] + txt = s[i + 1 : j] if disp: t += s[:i] + r'\[{0}\]'.format(' '.join(txt.splitlines())) else: t += s[:i] + r'\({0}\)'.format(' '.join(txt.splitlines())) - s = s[j+1:] + s = s[j + 1 :] if disp: s = s[1:] return HtmlFragment(t) @@ -156,6 +156,7 @@ class MathJaxExpr: sage: MathJaxExpr("a^{2}") + MathJaxExpr("x^{-1}") a^{2}x^{-1} """ + def __init__(self, y): """ Initialize a MathJax expression. @@ -307,7 +308,7 @@ def eval(self, x, globals=None, locals=None, mode='display', combine_all=False): parts = x.split(prefix) for i, part in enumerate(parts): if i == 0: - continue # Nothing to do with the head part + continue # Nothing to do with the head part n = 1 for closing, c in enumerate(part): if c == "{" and part[closing - 1] != "\\": @@ -318,7 +319,7 @@ def eval(self, x, globals=None, locals=None, mode='display', combine_all=False): break # part should end in "}}", so omit the last two characters # from y - y = part[:closing-1] + y = part[: closing - 1] for delimiter in r"""|"'`#%&,.:;?!@_~^+-/\=<>()[]{}0123456789E""": if delimiter not in y: break @@ -341,7 +342,7 @@ def eval(self, x, globals=None, locals=None, mode='display', combine_all=False): subparts.append(wrapper % (" " * nspaces)) nspaces = 1 subparts.append(wrapper % subpart) - subparts.append(part[closing + 1:]) + subparts.append(part[closing + 1 :]) parts[i] = "".join(subparts) from sage.misc.latex_macros import sage_latex_macros @@ -452,6 +453,7 @@ def __call__(self, obj, concatenate=True, strict=False): pass from sage.repl.rich_output.display_manager import get_display_manager + dm = get_display_manager() if dm.preferences.align_latex == 'center': mode = 'display' @@ -492,6 +494,7 @@ def eval(self, s, locals=None): """ if locals is None: from sage.repl.user_globals import get_globals + locals = get_globals() s = str(s) s = math_parse(s) @@ -505,8 +508,8 @@ def eval(self, s, locals=None): if j == -1: t += s break - t += s[:i] + r'\({}\)'.format(latex(sage_eval(s[6+i:j], locals=locals))) - s = s[j+7:] + t += s[:i] + r'\({}\)'.format(latex(sage_eval(s[6 + i : j], locals=locals))) + s = s[j + 7 :] return HtmlFragment(t) def iframe(self, url, height=400, width=800): @@ -550,8 +553,7 @@ def iframe(self, url, height=400, width=800): url = 'file://{0}'.format(url) elif '://' not in url: url = 'http://{0}'.format(url) - return HtmlFragment('' - .format(height, width, url)) + return HtmlFragment(''.format(height, width, url)) html = HTMLFragmentFactory() @@ -583,5 +585,6 @@ def pretty_print_default(enable=True): 'foo' """ from sage.repl.rich_output import get_display_manager + dm = get_display_manager() dm.preferences.text = 'latex' if enable else None diff --git a/src/sage/misc/inline_fortran.py b/src/sage/misc/inline_fortran.py index 85f3740d984..5dbfe00ea01 100644 --- a/src/sage/misc/inline_fortran.py +++ b/src/sage/misc/inline_fortran.py @@ -132,6 +132,7 @@ def eval(self, x, globals=None, locals=None): globals = self.globs if globals is None: from sage.repl.user_globals import get_globals + globals = get_globals() # Create everything in a temporary directory @@ -167,8 +168,7 @@ def eval(self, x, globals=None, locals=None): try: out = subprocess.check_output(cmd, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as exc: - raise RuntimeError( - "failed to compile Fortran code:\n{}".format(exc.output)) + raise RuntimeError("failed to compile Fortran code:\n{}".format(exc.output)) # Note that f2py() doesn't raise an exception if it fails. # In that case, the import below will fail. diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index cd5f7cfe4e6..6c7b80af8a1 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -15,6 +15,7 @@ - Joel B. Mohler: latex_variable_name() drastic rewrite and many doc-tests """ + # **************************************************************************** # Copyright (C) 2005 William Stein # @@ -46,22 +47,28 @@ \usepackage[T1]{fontenc} ''' -LATEX_HEADER = (r'''\documentclass{article} -''' + COMMON_HEADER + -r'''\oddsidemargin 0.0in +LATEX_HEADER = ( + r'''\documentclass{article} +''' + + COMMON_HEADER + + r'''\oddsidemargin 0.0in \evensidemargin 0.0in \textwidth 6.45in \topmargin 0.0in \headheight 0.0in \headsep 0.0in \textheight 9.0in -''') +''' +) -SLIDE_HEADER = (r'''\documentclass[a0,8pt]{beamer} -''' + COMMON_HEADER + -r'''\textwidth=1.1\textwidth +SLIDE_HEADER = ( + r'''\documentclass[a0,8pt]{beamer} +''' + + COMMON_HEADER + + r'''\textwidth=1.1\textwidth \textheight=2\textheight -''') +''' +) def list_function(x): @@ -269,10 +276,8 @@ def dict_function(x): \left\{\left(1, 2, x^{2}\right) : \left[\sin\left(z^{2}\right), \frac{1}{2} \, y\right]\right\} """ - return "".join([r"\left\{", - ", ".join(r"%s : %s" % (latex(key), latex(value)) - for key, value in x.items()), - r"\right\}"]) + return "".join([r"\left\{", ", ".join(r"%s : %s" % (latex(key), latex(value)) for key, value in x.items()), r"\right\}"]) + # One can add to the latex_table in order to install latexing # functionality for other types. (Suggested by Robert Kerns of Enthought.) @@ -304,21 +309,11 @@ def float_function(x): 2 \times 10^{-13} """ from sage.rings.real_double import RDF + return latex(RDF(x)) -latex_table = { - type(None): None_function, - bool: bool_function, - dict: dict_function, - float: float_function, - int: str, - list: list_function, - str: str_function, - tuple: tuple_function, - type(NotImplemented): builtin_constant_function, - type(Ellipsis): builtin_constant_function -} +latex_table = {type(None): None_function, bool: bool_function, dict: dict_function, float: float_function, int: str, list: list_function, str: str_function, tuple: tuple_function, type(NotImplemented): builtin_constant_function, type(Ellipsis): builtin_constant_function} class LatexExpr(str): @@ -368,6 +363,7 @@ class LatexExpr(str): sage: str(latex(x^20 + 1)) # needs sage.symbolic 'x^{20} + 1' """ + def __add__(self, other): r""" Add a LatexExpr and another LatexExpr (or a string). @@ -491,9 +487,11 @@ def default_engine(): ('lualatex', 'LuaLaTeX') """ from sage.misc.superseded import deprecation + deprecation(39351, "default_engine is being removed from the public API and replaced with the internal function _default_engine") from sage.features.latex import pdflatex, xelatex, lualatex + if lualatex().is_present(): return 'lualatex', 'LuaLaTeX' if xelatex().is_present(): @@ -536,6 +534,7 @@ def _default_engine(): sage: sage.misc.latex._default_engine = real_de """ from sage.features.latex import pdflatex, xelatex, lualatex + if lualatex().is_present(): return 'lualatex' if xelatex().is_present(): @@ -549,8 +548,8 @@ class _Latex_prefs_object(SageObject): """ An object that holds LaTeX global preferences. """ - def __init__(self, bb=False, delimiters=["(", ")"], - matrix_column_alignment='r'): + + def __init__(self, bb=False, delimiters=["(", ")"], matrix_column_alignment='r'): """ Define an object that holds LaTeX global preferences. @@ -634,9 +633,8 @@ def latex_extra_preamble(): """ from sage.misc.latex_macros import sage_latex_macros - return "\n".join([_Latex_prefs._option['preamble'], - "\n".join(sage_latex_macros()), - _Latex_prefs._option['macros']]) + + return "\n".join([_Latex_prefs._option['preamble'], "\n".join(sage_latex_macros()), _Latex_prefs._option['macros']]) def _run_latex_(filename, debug=False, density=150, engine=None, png=False, do_in_background=False): @@ -703,6 +701,7 @@ def _run_latex_(filename, debug=False, density=150, engine=None, png=False, do_i if not engine or engine == "latex": from sage.features.latex import latex + latex().require() command = "latex" # 'suffix' is used in the 'convert' command list @@ -710,18 +709,21 @@ def _run_latex_(filename, debug=False, density=150, engine=None, png=False, do_i return_suffix = "dvi" elif engine == "pdflatex": from sage.features.latex import pdflatex + pdflatex().require() command = "pdflatex" suffix = "pdf" return_suffix = "pdf" elif engine == "xelatex": from sage.features.latex import xelatex + xelatex().require() command = "xelatex" suffix = "pdf" return_suffix = "pdf" elif engine == "lualatex": from sage.features.latex import lualatex + lualatex().require() command = "lualatex" suffix = "pdf" @@ -732,9 +734,9 @@ def _run_latex_(filename, debug=False, density=150, engine=None, png=False, do_i # if png output + latex, check to see if dvipng or magick/convert is installed. from sage.features.imagemagick import ImageMagick from sage.features.dvipng import dvipng + if png: - if ((not engine or engine == "latex") - and not (dvipng().is_present() or ImageMagick().is_present())): + if (not engine or engine == "latex") and not (dvipng().is_present() or ImageMagick().is_present()): print() print("Error: neither dvipng nor magick/convert (from the ImageMagick suite)") print("appear to be installed. Displaying LaTeX, PDFLaTeX output") @@ -774,8 +776,7 @@ def _run_latex_(filename, debug=False, density=150, engine=None, png=False, do_i lt = [command, r'\nonstopmode', r'\input{' + filename + '.tex}'] # dvipng is run with the 'picky' option: this means that if # there are warnings, no png file is created. - dvipng = ['dvipng', '--picky', '-q', '-T', 'tight', - '-D', str(density), filename + '.dvi', '-o', filename + '.png'] + dvipng = ['dvipng', '--picky', '-q', '-T', 'tight', '-D', str(density), filename + '.dvi', '-o', filename + '.png'] dvips = ['dvips', filename + '.dvi'] @@ -785,9 +786,8 @@ def _run_latex_(filename, debug=False, density=150, engine=None, png=False, do_i # when using dvipng: density = int(1.4 * density / 1.3) from sage.features.imagemagick import Magick - magick = [Magick().executable, '-density', - '{0}x{0}'.format(density), '-trim', filename + '.' + suffix, - filename + '.png'] + + magick = [Magick().executable, '-density', '{0}x{0}'.format(density), '-trim', filename + '.' + suffix, filename + '.png'] # it is possible to get through the following commands # without running a program, so in that case we force error @@ -797,8 +797,8 @@ def _run_latex_(filename, debug=False, density=150, engine=None, png=False, do_i # finer-grained analysis of the return code. Think of the output as # a boolean: "the command exited normally" def subpcall(x): - return not call(x, stdout=redirect, - stderr=redirect, cwd=base) + return not call(x, stdout=redirect, stderr=redirect, cwd=base) + if engine in ['pdflatex', 'xelatex', 'lualatex']: if debug: print(lt) @@ -808,7 +808,7 @@ def subpcall(x): if png: e = e and subpcall(magick) else: # latex - if (png or check_validity): + if png or check_validity: if dvipng().is_present(): if debug: print(lt) @@ -889,6 +889,7 @@ class :class:`Latex` inherits from this. This class is used in sage: type(LatexCall()(ZZ)) """ + def __call__(self, x, combine_all=False): r""" Return a :class:`LatexExpr` built out of the argument ``x``. @@ -969,6 +970,7 @@ class Latex(LatexCall): sage: LatexExpr(r"y \neq") + latex(x^20 + 1) # needs sage.symbolic y \neq x^{20} + 1 """ + def __init__(self, debug=False, slide=False, density=150, engine=None): """ Initialize the latex builder. @@ -997,9 +999,8 @@ def _relation_symbols(self): ' \\geq ' """ import operator - return {operator.lt: ' < ', operator.le: ' \\leq ', - operator.eq: ' = ', operator.ne: ' \\neq ', - operator.ge: ' \\geq ', operator.gt: ' > '} + + return {operator.lt: ' < ', operator.le: ' \\leq ', operator.eq: ' = ', operator.ne: ' \\neq ', operator.ge: ' \\geq ', operator.gt: ' > '} def _latex_preparse(self, s, locals): r""" @@ -1013,13 +1014,14 @@ def _latex_preparse(self, s, locals): '2' """ from sage.misc.sage_eval import sage_eval + i0 = -1 while True: i = s.find('\\sage{') if i == -1 or i == i0: return s i0 = i - t = s[i + 6:] + t = s[i + 6 :] j = t.find('}') if j == -1: return s @@ -1030,10 +1032,9 @@ def _latex_preparse(self, s, locals): except Exception as msg: print(msg) k = '\\mbox{\\rm [%s undefined]}' % var - s = s[:i] + k + t[j + 1:] + s = s[:i] + k + t[j + 1 :] - def eval(self, x, globals, strip=False, filename=None, debug=None, - density=None, engine=None, locals={}): + def eval(self, x, globals, strip=False, filename=None, debug=None, density=None, engine=None, locals={}): r""" Compile the formatted tex given by ``x`` as a png and writes the output file to the directory given by ``filename``. @@ -1118,15 +1119,10 @@ def eval(self, x, globals, strip=False, filename=None, debug=None, if engine is None: engine = _default_engine() - e = _run_latex_(os.path.join(base, filename + ".tex"), - debug=debug, - density=density, - engine=engine, - png=True) + e = _run_latex_(os.path.join(base, filename + ".tex"), debug=debug, density=density, engine=engine, png=True) if e.find("Error") == -1: - shutil.copy(os.path.join(base, filename + ".png"), - os.path.join(orig_base, filename + ".png")) + shutil.copy(os.path.join(base, filename + ".png"), os.path.join(orig_base, filename + ".png")) result = '' return result @@ -1160,6 +1156,7 @@ def blackboard_bold(self, t=None): if t is None: return _Latex_prefs._option["blackboard_bold"] from .latex_macros import sage_configurable_latex_macros + old = _Latex_prefs._option["blackboard_bold"] _Latex_prefs._option["blackboard_bold"] = bool(t) if bool(old) != bool(t): @@ -1354,9 +1351,8 @@ def has_file(self, file_name) -> bool: """ assert isinstance(file_name, str) try: - retcode = call("kpsewhich %s" % file_name, shell=True, - stdout=PIPE, stderr=PIPE) - return (retcode == 0) + retcode = call("kpsewhich %s" % file_name, shell=True, stdout=PIPE, stderr=PIPE) + return retcode == 0 except OSError: return False @@ -1390,8 +1386,12 @@ def check_file(self, file_name, more_info=""): """ assert isinstance(file_name, str) if not self.has_file(file_name): - print(""" -Warning: `{}` is not part of this computer's TeX installation.""".format(file_name)) + print( + """ +Warning: `{}` is not part of this computer's TeX installation.""".format( + file_name + ) + ) if more_info: print(more_info) @@ -1602,10 +1602,7 @@ def engine(self, e=None): latex.__doc__ = Latex.__call__.__doc__ -def _latex_file_(objects, title='SAGE', debug=False, - sep='', tiny=False, math_left='\\[', - math_right='\\]', - extra_preamble=''): +def _latex_file_(objects, title='SAGE', debug=False, sep='', tiny=False, math_left='\\[', math_right='\\]', extra_preamble=''): r"""nodetex Produce a string to be used as a LaTeX file, containing a representation of each object in objects. @@ -1730,9 +1727,7 @@ def _latex_file_(objects, title='SAGE', debug=False, return s -def view(objects, title='Sage', debug=False, sep='', tiny=False, - engine=None, viewer=None, tightpage=True, margin=None, - mode='inline', combine_all=False, **kwds): +def view(objects, title='Sage', debug=False, sep='', tiny=False, engine=None, viewer=None, tightpage=True, margin=None, mode='inline', combine_all=False, **kwds): r"""nodetex Compute a latex representation of each object in objects, compile, and display typeset. If used from the command line, this requires @@ -1874,11 +1869,7 @@ def view(objects, title='Sage', debug=False, sep='', tiny=False, margin_str = "" else: margin_str = '\n\\setlength\\PreviewBorder{%fmm}' % margin - latex_options = {'extra_preamble': - '\\usepackage[tightpage,active]{preview}\n' + - '\\PreviewEnvironment{page}%s' % margin_str, - 'math_left': '\\begin{page}$', - 'math_right': '$\\end{page}'} + latex_options = {'extra_preamble': '\\usepackage[tightpage,active]{preview}\n' + '\\PreviewEnvironment{page}%s' % margin_str, 'math_left': '\\begin{page}$', 'math_right': '$\\end{page}'} title = None else: latex_options = {} @@ -1905,9 +1896,11 @@ def view(objects, title='Sage', debug=False, sep='', tiny=False, suffix = _run_latex_(tex_file, debug=debug, engine=engine, png=False) if suffix == "pdf": from sage.misc.viewer import pdf_viewer + viewer = pdf_viewer() elif suffix == "dvi": from sage.misc.viewer import dvi_viewer + viewer = dvi_viewer() else: print("Latex error") @@ -1930,6 +1923,7 @@ def run_viewer(): # immediately. The "daemon" flag is important because, without it, # sage won't quit until the viewer does. from threading import Thread + t = Thread(target=run_viewer) t.daemon = True t.start() @@ -1969,6 +1963,7 @@ def pdf(x, filename, tiny=False, tightpage=True, margin=None, engine=None, debug ....: pdf(ZZ[x], f.name) """ from sage.plot.graphics import Graphics + if isinstance(x, Graphics): x.save(filename) return @@ -1978,11 +1973,7 @@ def pdf(x, filename, tiny=False, tightpage=True, margin=None, engine=None, debug margin_str = "" else: margin_str = '\n\\setlength\\PreviewBorder{%fmm}' % margin - latex_options = {'extra_preamble': - '\\usepackage[tightpage,active]{preview}\n' + - '\\PreviewEnvironment{page}%s' % margin_str, - 'math_left': '\\begin{page}$', - 'math_right': '$\\end{page}'} + latex_options = {'extra_preamble': '\\usepackage[tightpage,active]{preview}\n' + '\\PreviewEnvironment{page}%s' % margin_str, 'math_left': '\\begin{page}$', 'math_right': '$\\end{page}'} else: latex_options = {} @@ -2011,8 +2002,7 @@ def pdf(x, filename, tiny=False, tightpage=True, margin=None, engine=None, debug print("Latex error or no pdf was generated.") -def png(x, filename, density=150, debug=False, - do_in_background=False, tiny=False, engine=None): +def png(x, filename, density=150, debug=False, do_in_background=False, tiny=False, engine=None): """ Create a png image representation of ``x`` and save to the given filename. @@ -2049,9 +2039,7 @@ def png(x, filename, density=150, debug=False, x.save(filename) return # if not graphics: create a string of latex code to write in a file - s = _latex_file_([x], math_left='$\\displaystyle', math_right='$', title='', - debug=debug, tiny=tiny, - extra_preamble='\\textheight=2\\textheight') + s = _latex_file_([x], math_left='$\\displaystyle', math_right='$', title='', debug=debug, tiny=tiny, extra_preamble='\\textheight=2\\textheight') if engine is None: engine = _Latex_prefs._option["engine"] if engine is None: @@ -2067,8 +2055,7 @@ def png(x, filename, density=150, debug=False, with open(tex_file, 'w') as file: file.write(s) # run latex on the file, producing png output to png_file - e = _run_latex_(tex_file, density=density, debug=debug, - png=True, engine=engine) + e = _run_latex_(tex_file, density=density, debug=debug, png=True, engine=engine) if e.find("Error") == -1: # if no errors, copy png_file to the appropriate place shutil.copy(png_file, abs_path_to_png) @@ -2159,6 +2146,7 @@ def repr_lincomb(symbols, coeffs): \text{\texttt{x}} + 2\text{\texttt{y}} """ from sage.rings.cc import CC + terms = [] for c, sym in zip(coeffs, symbols): if c == 0: @@ -2190,45 +2178,7 @@ def repr_lincomb(symbols, coeffs): return s.replace("+ -", "- ") -common_varnames = ['alpha', - 'beta', - 'gamma', - 'Gamma', - 'delta', - 'Delta', - 'epsilon', - 'zeta', - 'eta', - 'theta', - 'Theta', - 'iota', - 'kappa', - 'lambda', - 'Lambda', - 'mu', - 'nu', - 'xi', - 'Xi', - 'pi', - 'Pi', - 'rho', - 'sigma', - 'Sigma', - 'tau', - 'upsilon', - 'phi', - 'Phi', - 'varphi', - 'chi', - 'psi', - 'Psi', - 'omega', - 'Omega', - 'ast', - 'bullet', - 'circ', - 'times', - 'star'] +common_varnames = ['alpha', 'beta', 'gamma', 'Gamma', 'delta', 'Delta', 'epsilon', 'zeta', 'eta', 'theta', 'Theta', 'iota', 'kappa', 'lambda', 'Lambda', 'mu', 'nu', 'xi', 'Xi', 'pi', 'Pi', 'rho', 'sigma', 'Sigma', 'tau', 'upsilon', 'phi', 'Phi', 'varphi', 'chi', 'psi', 'Psi', 'omega', 'Omega', 'ast', 'bullet', 'circ', 'times', 'star'] def latex_varify(a, is_fname=False): @@ -2353,13 +2303,14 @@ def latex_variable_name(x, is_fname=False): prefix = x suffix = None else: - prefix = x[:m.start()] - suffix = x[m.start():] + prefix = x[: m.start()] + suffix = x[m.start() :] else: prefix = x[:underscore] - suffix = x[underscore + 1:] + suffix = x[underscore + 1 :] if prefix == '': from sage.calculus.calculus import symtable + for sym in symtable.values(): if sym[0] == '_' and sym[1:] == suffix: return latex_variable_name(suffix) @@ -2395,6 +2346,7 @@ class LatexExamples: [rrr] !{\ar @{-}@'{p-(0,1)@+}-(1,1)} }}} """ + class graph(SageObject): """ LaTeX example for testing display of graphs. See its string diff --git a/src/sage/misc/latex_macros.py b/src/sage/misc/latex_macros.py index 24b2818bc8c..b5645504d60 100644 --- a/src/sage/misc/latex_macros.py +++ b/src/sage/misc/latex_macros.py @@ -78,6 +78,7 @@ def produce_latex_macro(name, *sample_args): '\\newcommand{\\FiniteField}[1]{\\Bold{F}_{#1}}' """ from sage.misc.latex import LatexCall # type: ignore + # this import is used inside a string below names_split = name.rsplit('.', 1) if len(names_split) == 1: @@ -95,7 +96,7 @@ def produce_latex_macro(name, *sample_args): for i, x in enumerate(sample_args): s = str(x) assert s in defn - defn = defn.replace(s, "#" + str(i+1)) + defn = defn.replace(s, "#" + str(i + 1)) return newcommand + defn @@ -124,15 +125,15 @@ def convert_latex_macro_to_mathjax(macro): right_bracket = macro.find('[') if left_bracket >= 0: right_bracket = macro.find(']') - num_args = int(macro[left_bracket + 1: right_bracket]) + num_args = int(macro[left_bracket + 1 : right_bracket]) else: num_args = 0 start_name = macro.find('{') + 1 # add one to go past the backslash end_name = macro.find('}') - name = macro[start_name + 1: end_name] + name = macro[start_name + 1 : end_name] start_defn = macro.find('{', end_name) end_defn = macro.rfind('}') - defn = macro[start_defn + 1: end_defn] + defn = macro[start_defn + 1 : end_defn] if num_args == 0: return name, defn return name, [defn, num_args] @@ -148,29 +149,27 @@ def convert_latex_macro_to_mathjax(macro): # documentation), and look at the resulting tex file in # SAGE_DOC/latex/en/tutorial. The preamble should contain # \newcommand's for each of the entries here. -macros = [["ZZ"], - ["NN"], - ["RR"], - ["CC"], - ["QQ"], - ["QQbar"], - ["GF", 2], - ["Zp", 2], - ["Qp", 2], - ["Zmod", 2], - ["CDF"], - ["CIF"], - ["CLF"], - ["RDF"], - ["RIF"], - ["RLF"], - ] +macros = [ + ["ZZ"], + ["NN"], + ["RR"], + ["CC"], + ["QQ"], + ["QQbar"], + ["GF", 2], + ["Zp", 2], + ["Qp", 2], + ["Zmod", 2], + ["CDF"], + ["CIF"], + ["CLF"], + ["RDF"], + ["RIF"], + ["RLF"], +] # Use this list to define additional latex macros for sage documentation -latex_macros = [r"\newcommand{\SL}{\mathrm{SL}}", - r"\newcommand{\PSL}{\mathrm{PSL}}", - r"\newcommand{\lcm}{\mathop{\operatorname{lcm}}}", - r"\newcommand{\dist}{\mathrm{dist}}"] +latex_macros = [r"\newcommand{\SL}{\mathrm{SL}}", r"\newcommand{\PSL}{\mathrm{PSL}}", r"\newcommand{\lcm}{\mathop{\operatorname{lcm}}}", r"\newcommand{\dist}{\mathrm{dist}}"] # The following is to allow customization of typesetting of rings: # mathbf vs mathbb. See latex.py for more information. diff --git a/src/sage/misc/latex_standalone.py b/src/sage/misc/latex_standalone.py index 18398bece12..d70a5a9efaf 100644 --- a/src/sage/misc/latex_standalone.py +++ b/src/sage/misc/latex_standalone.py @@ -288,9 +288,8 @@ class Standalone(SageObject): Test \end{document} """ - def __init__(self, content, document_class_options=None, - standalone_config=None, usepackage=None, macros=None, - use_sage_preamble=False): + + def __init__(self, content, document_class_options=None, standalone_config=None, usepackage=None, macros=None, use_sage_preamble=False): r""" See :class:`Standalone` for full information. @@ -307,11 +306,13 @@ def __init__(self, content, document_class_options=None, self._macros = [] if macros is None else macros if use_sage_preamble: from sage.misc.latex import _Latex_prefs + for key in ['preamble', 'macros']: s = _Latex_prefs._option[key] if s: self._macros.append(s) from sage.misc.latex_macros import sage_latex_macros + self._macros.extend(sage_latex_macros()) def _latex_file_header_lines(self): @@ -336,10 +337,8 @@ def _latex_file_header_lines(self): lines.append(r"\documentclass[{}]{{standalone}}".format(options)) else: lines.append(r"\documentclass{standalone}") - lines.extend(r"\standaloneconfig{{{}}}".format(config) - for config in self._standalone_config) - lines.extend(r"\usepackage{{{}}}".format(package) - for package in self._usepackage) + lines.extend(r"\standaloneconfig{{{}}}".format(config) for config in self._standalone_config) + lines.extend(r"\usepackage{{{}}}".format(package) for package in self._usepackage) lines.extend(self._macros) return lines @@ -409,8 +408,7 @@ def _repr_(self): else: lines.extend(L[:5]) lines.append('---') - lines.append('{} lines not printed ({} characters in total).'.format(len(L) - 10, - len(self._content))) + lines.append('{} lines not printed ({} characters in total).'.format(len(L) - 10, len(self._content))) lines.append('Use print to see the full content.') lines.append('---') lines.extend(L[-5:]) @@ -452,13 +450,12 @@ def _rich_repr_(self, display_manager, **kwds): return # Do not use rich output if not in IPython notebook (Jupyter) from sage.repl.rich_output.backend_ipython import BackendIPythonNotebook + if not isinstance(display_manager._backend, BackendIPythonNotebook): return types = display_manager.types - prefer_raster = ( - ('png', types.OutputImagePng), - ) + prefer_raster = (('png', types.OutputImagePng),) prefer_vector = ( ('svg', types.OutputImageSvg), ('pdf', types.OutputImagePdf), @@ -477,6 +474,7 @@ def _rich_repr_(self, display_manager, **kwds): if output_container in display_manager.supported_output(): filename = getattr(self, format)(view=False, **kwds) from sage.repl.rich_output.buffer import OutputBuffer + buf = OutputBuffer.from_file(filename) return output_container(buf) @@ -697,6 +695,7 @@ def pdf(self, filename=None, view=True, program=None): # set up filenames from sage.misc.temporary_file import tmp_filename + temp_filename_tex = tmp_filename('tikz_', '.tex') with open(temp_filename_tex, 'w') as f: f.write(str(self)) @@ -709,15 +708,7 @@ def pdf(self, filename=None, view=True, program=None): # If a problem with the tex source occurs, provide the log if result.returncode != 0: - print("Command \n" - " '{}'\n" - "returned nonzero exit status {}.\n" - "Here is the content of the stderr:{}\n" - "Here is the content of the stdout:" - "{}\n".format(' '.join(result.args), - result.returncode, - result.stderr.strip(), - result.stdout.strip())) + print("Command \n" " '{}'\n" "returned nonzero exit status {}.\n" "Here is the content of the stderr:{}\n" "Here is the content of the stdout:" "{}\n".format(' '.join(result.args), result.returncode, result.stderr.strip(), result.stdout.strip())) result.check_returncode() temp_filename_pdf = os.path.join(base, temp_filename + '.pdf') @@ -725,12 +716,14 @@ def pdf(self, filename=None, view=True, program=None): if filename: filename = os.path.abspath(filename) import shutil + shutil.move(temp_filename_pdf, filename) return filename # open the tmp pdf if view: from sage.misc.viewer import pdf_viewer + cmd = pdf_viewer().split() cmd.append(temp_filename_pdf) # we use check_call as opposed to run, because @@ -738,6 +731,7 @@ def pdf(self, filename=None, view=True, program=None): # see https://stackoverflow.com/a/71342967 # run(cmd, cwd=base, capture_output=True, check=True) from subprocess import check_call, PIPE + check_call(cmd, cwd=base, stdout=PIPE, stderr=PIPE) return temp_filename_pdf @@ -821,6 +815,7 @@ def dvi(self, filename=None, view=True, program='latex'): # set up filenames from sage.misc.temporary_file import tmp_filename + temp_filename_tex = tmp_filename('tikz_', '.tex') with open(temp_filename_tex, 'w') as f: f.write(str(self)) @@ -833,15 +828,7 @@ def dvi(self, filename=None, view=True, program='latex'): # If a problem with the tex source occurs, provide the log if result.returncode != 0: - print("Command \n" - " '{}'\n" - "returned nonzero exit status {}.\n" - "Here is the content of the stderr:{}\n" - "Here is the content of the stdout:" - "{}\n".format(' '.join(result.args), - result.returncode, - result.stderr.strip(), - result.stdout.strip())) + print("Command \n" " '{}'\n" "returned nonzero exit status {}.\n" "Here is the content of the stderr:{}\n" "Here is the content of the stdout:" "{}\n".format(' '.join(result.args), result.returncode, result.stderr.strip(), result.stdout.strip())) result.check_returncode() temp_filename_dvi = os.path.join(base, temp_filename + '.dvi') @@ -849,12 +836,14 @@ def dvi(self, filename=None, view=True, program='latex'): if filename: filename = os.path.abspath(filename) import shutil + shutil.move(temp_filename_dvi, filename) return filename # open the tmp dvi if view: from sage.misc.viewer import dvi_viewer + cmd = dvi_viewer().split() cmd.append(temp_filename_dvi) # we use check_call as opposed to run, because @@ -862,6 +851,7 @@ def dvi(self, filename=None, view=True, program='latex'): # see https://stackoverflow.com/a/71342967 # run(cmd, cwd=base, capture_output=True, check=True) from subprocess import check_call, PIPE + check_call(cmd, cwd=base, stdout=PIPE, stderr=PIPE) return temp_filename_dvi @@ -906,6 +896,7 @@ def png(self, filename=None, density=150, view=True): '.png' """ from sage.features.imagemagick import ImageMagick + ImageMagick().require() temp_filename_pdf = self.pdf(filename=None, view=False) @@ -913,34 +904,26 @@ def png(self, filename=None, density=150, view=True): temp_filename_png = temp_filename + '.png' # convert to png - cmd = ['convert', '-density', - '{0}x{0}'.format(density), '-trim', temp_filename_pdf, - temp_filename_png] + cmd = ['convert', '-density', '{0}x{0}'.format(density), '-trim', temp_filename_pdf, temp_filename_png] result = run(cmd, capture_output=True, text=True) # If a problem occurs, provide the log if result.returncode != 0: - print("Command \n" - " '{}'\n" - "returned nonzero exit status {}.\n" - "Here is the content of the stderr:{}\n" - "Here is the content of the stdout:" - "{}\n".format(' '.join(result.args), - result.returncode, - result.stderr.strip(), - result.stdout.strip())) + print("Command \n" " '{}'\n" "returned nonzero exit status {}.\n" "Here is the content of the stderr:{}\n" "Here is the content of the stdout:" "{}\n".format(' '.join(result.args), result.returncode, result.stderr.strip(), result.stdout.strip())) result.check_returncode() # move the png into the good location if filename: filename = os.path.abspath(filename) import shutil + shutil.move(temp_filename_png, filename) return filename # open the tmp png if view: from sage.misc.viewer import png_viewer + cmd = png_viewer().split() cmd.append(temp_filename_png) # we use check_call as opposed to run, because @@ -948,6 +931,7 @@ def png(self, filename=None, density=150, view=True): # see https://stackoverflow.com/a/71342967 # run(cmd, capture_output=True, check=True) from subprocess import check_call, PIPE + check_call(cmd, stdout=PIPE, stderr=PIPE) return temp_filename_png @@ -1004,42 +988,37 @@ def svg(self, filename=None, view=True, program='pdftocairo'): # set the command if program == 'pdftocairo': from sage.features.poppler import pdftocairo + pdftocairo().require() cmd = ['pdftocairo', '-svg', temp_filename_pdf, temp_filename_svg] elif program == 'pdf2svg': from sage.features.pdf2svg import pdf2svg + pdf2svg().require() cmd = ['pdf2svg', temp_filename_pdf, temp_filename_svg] else: - raise ValueError("program(={}) should be 'pdftocairo' or" - " 'pdf2svg'".format(program)) + raise ValueError("program(={}) should be 'pdftocairo' or" " 'pdf2svg'".format(program)) # convert to svg result = run(cmd, capture_output=True, text=True) # If a problem occurs, provide the log if result.returncode != 0: - print("Command \n" - " '{}'\n" - "returned nonzero exit status {}.\n" - "Here is the content of the stderr:{}\n" - "Here is the content of the stdout:" - "{}\n".format(' '.join(result.args), - result.returncode, - result.stderr.strip(), - result.stdout.strip())) + print("Command \n" " '{}'\n" "returned nonzero exit status {}.\n" "Here is the content of the stderr:{}\n" "Here is the content of the stdout:" "{}\n".format(' '.join(result.args), result.returncode, result.stderr.strip(), result.stdout.strip())) result.check_returncode() # move the svg into the good location if filename: filename = os.path.abspath(filename) import shutil + shutil.move(temp_filename_svg, filename) return filename # open the tmp svg if view: from sage.misc.viewer import browser + cmd = browser().split() cmd.append(temp_filename_svg) # we use check_call as opposed to run, because @@ -1047,6 +1026,7 @@ def svg(self, filename=None, view=True, program='pdftocairo'): # see https://stackoverflow.com/a/71342967 # run(cmd, capture_output=True, check=True) from subprocess import check_call, PIPE + check_call(cmd, stdout=PIPE, stderr=PIPE) return temp_filename_svg @@ -1108,6 +1088,7 @@ def eps(self, filename=None, view=True, program='dvips'): if program == 'pdftocairo': from sage.features.poppler import pdftocairo + pdftocairo().require() # set the temporary filenames temp_filename_pdf = self.pdf(filename=None, view=False) @@ -1117,6 +1098,7 @@ def eps(self, filename=None, view=True, program='dvips'): cmd = ['pdftocairo', '-eps', temp_filename_pdf, temp_filename_eps] elif program == 'dvips': from sage.features.latex import dvips + dvips().require() # set the temporary filenames temp_filename_dvi = self.dvi(filename=None, view=False) @@ -1125,35 +1107,28 @@ def eps(self, filename=None, view=True, program='dvips'): # set the command cmd = ['dvips', '-E', '-o', temp_filename_eps, temp_filename_dvi] else: - raise ValueError("program(={}) should be 'pdftocairo' or" - " 'dvips'".format(program)) + raise ValueError("program(={}) should be 'pdftocairo' or" " 'dvips'".format(program)) # convert to eps result = run(cmd, capture_output=True, text=True) # If a problem occurs, provide the log if result.returncode != 0: - print("Command \n" - " '{}'\n" - "returned nonzero exit status {}.\n" - "Here is the content of the stderr:{}\n" - "Here is the content of the stdout:" - "{}\n".format(' '.join(result.args), - result.returncode, - result.stderr.strip(), - result.stdout.strip())) + print("Command \n" " '{}'\n" "returned nonzero exit status {}.\n" "Here is the content of the stderr:{}\n" "Here is the content of the stdout:" "{}\n".format(' '.join(result.args), result.returncode, result.stderr.strip(), result.stdout.strip())) result.check_returncode() # move the eps into the good location if filename: filename = os.path.abspath(filename) import shutil + shutil.move(temp_filename_eps, filename) return filename # open the tmp eps if view: from sage.misc.viewer import viewer + cmd = viewer().split() cmd.append(temp_filename_eps) # we use check_call as opposed to run, because @@ -1161,6 +1136,7 @@ def eps(self, filename=None, view=True, program='dvips'): # see https://stackoverflow.com/a/71342967 # run(cmd, capture_output=True, check=True) from subprocess import check_call, PIPE + check_call(cmd, stdout=PIPE, stderr=PIPE) return temp_filename_eps @@ -1204,6 +1180,7 @@ def tex(self, filename=None, content_only=False, include_header=None): """ if filename is None: from sage.misc.temporary_file import tmp_filename + filename = tmp_filename('tikz_', '.tex') else: filename = os.path.abspath(filename) @@ -1211,10 +1188,8 @@ def tex(self, filename=None, content_only=False, include_header=None): if include_header is not None: content_only = not include_header from sage.misc.superseded import deprecation - deprecation(20343, "When merging this code from slabbe into " - "SageMath the argument include_header=False was " - "replaced by content_only=True. Please update your code " - "before include_header option gets removed from SageMath.") + + deprecation(20343, "When merging this code from slabbe into " "SageMath the argument include_header=False was " "replaced by content_only=True. Please update your code " "before include_header option gets removed from SageMath.") if content_only: output = self.content() @@ -1279,8 +1254,7 @@ def save(self, filename, **kwds): elif ext == '.dvi': self.dvi(filename, **kwds) else: - raise ValueError("allowed file extensions for images are " - ".pdf, .png, .svg, .eps, .dvi!") + raise ValueError("allowed file extensions for images are " ".pdf, .png, .svg, .eps, .dvi!") class TikzPicture(Standalone): @@ -1359,8 +1333,8 @@ class TikzPicture(Standalone): ....: usetikzlibrary=tikzlib, macros=macros) sage: _ = t.pdf(view=False) # long time (2s), optional - latex """ - def __init__(self, content, standalone_config=None, usepackage=None, - usetikzlibrary=None, macros=None, use_sage_preamble=False): + + def __init__(self, content, standalone_config=None, usepackage=None, usetikzlibrary=None, macros=None, use_sage_preamble=False): r""" See :class:`TikzPicture` for full information. @@ -1370,9 +1344,7 @@ def __init__(self, content, standalone_config=None, usepackage=None, sage: s = "\\begin{tikzpicture}\n\\draw (0,0) -- (1,1);\n\\end{tikzpicture}" sage: t = TikzPicture(s) """ - Standalone.__init__(self, content, document_class_options=['tikz'], - standalone_config=standalone_config, usepackage=usepackage, - macros=macros, use_sage_preamble=use_sage_preamble) + Standalone.__init__(self, content, document_class_options=['tikz'], standalone_config=standalone_config, usepackage=usepackage, macros=macros, use_sage_preamble=use_sage_preamble) self._usetikzlibrary = [] if usetikzlibrary is None else usetikzlibrary @@ -1469,24 +1441,20 @@ def from_dot_string(cls, dotdata, prog='dot'): sage: _ = tikz.pdf() # not tested """ from sage.features import PythonModule + PythonModule("dot2tex").require() from sage.features.graphviz import Graphviz + Graphviz().require() import dot2tex - tikz = dot2tex.dot2tex(dotdata, - format='tikz', - autosize=True, - crop=True, - figonly='True', - prog=prog).strip() - return TikzPicture(tikz, standalone_config=["border=4mm"], - usetikzlibrary=['shapes']) + + tikz = dot2tex.dot2tex(dotdata, format='tikz', autosize=True, crop=True, figonly='True', prog=prog).strip() + return TikzPicture(tikz, standalone_config=["border=4mm"], usetikzlibrary=['shapes']) @classmethod @experimental(issue_number=20343) - def from_graph(cls, graph, merge_multiedges=True, - merge_label_function=tuple, **kwds): + def from_graph(cls, graph, merge_multiedges=True, merge_label_function=tuple, **kwds): r""" Convert a graph to a tikzpicture using graphviz and dot2tex. @@ -1607,28 +1575,33 @@ def from_graph(cls, graph, merge_multiedges=True, sage: _ = tikz.pdf() # not tested """ from sage.features.latex import pdflatex + pdflatex().require() from sage.features.graphviz import Graphviz + Graphviz().require() from sage.features import PythonModule + PythonModule("dot2tex").require() if merge_multiedges and graph.has_multiple_edges(): from collections import defaultdict + d = defaultdict(list) - for (u, v, label) in graph.edges(sort=False): + for u, v, label in graph.edges(sort=False): d[(u, v)].append(label) edges = [(u, v, merge_label_function(label_list)) for (u, v), label_list in d.items()] loops = graph.has_loops() if graph.is_directed(): from sage.graphs.digraph import DiGraph + graph = DiGraph(edges, format='list_of_edges', loops=loops) else: from sage.graphs.graph import Graph + graph = Graph(edges, format='list_of_edges', loops=loops) - options = {'format': 'dot2tex', 'edge_labels': True, - 'color_by_label': False, 'prog': 'dot', 'rankdir': 'down'} + options = {'format': 'dot2tex', 'edge_labels': True, 'color_by_label': False, 'prog': 'dot', 'rankdir': 'down'} options.update(kwds) graph.latex_options().set_options(**options) @@ -1637,8 +1610,7 @@ def from_graph(cls, graph, merge_multiedges=True, @classmethod @experimental(issue_number=20343) - def from_graph_with_pos(cls, graph, scale=1, merge_multiedges=True, - merge_label_function=tuple): + def from_graph_with_pos(cls, graph, scale=1, merge_multiedges=True, merge_label_function=tuple): r""" Convert a graph with positions defined for vertices to a tikzpicture. @@ -1711,16 +1683,19 @@ def from_graph_with_pos(cls, graph, scale=1, merge_multiedges=True, if merge_multiedges and graph.has_multiple_edges(): from collections import defaultdict + d = defaultdict(list) - for (u, v, label) in graph.edges(sort=True): + for u, v, label in graph.edges(sort=True): d[(u, v)].append(label) edges = [(u, v, merge_label_function(label_list)) for (u, v), label_list in d.items()] loops = graph.has_loops() if graph.is_directed(): from sage.graphs.digraph import DiGraph + graph = DiGraph(edges, format='list_of_edges', loops=loops) else: from sage.graphs.graph import Graph + graph = Graph(edges, format='list_of_edges', loops=loops) keys_for_vertices = graph._keys_for_vertices() @@ -1732,33 +1707,26 @@ def from_graph_with_pos(cls, graph, scale=1, merge_multiedges=True, # vertices lines.append(r'% vertices') for u in graph.vertices(sort=False): - line = r'\node ({}) at {} {{{}}};'.format(keys_for_vertices(u), - pos[u], u) + line = r'\node ({}) at {} {{{}}};'.format(keys_for_vertices(u), pos[u], u) lines.append(line) # edges lines.append(r'% edges') arrow = '->' if graph.is_directed() else '' - for (u, v, label) in graph.edges(sort=True): + for u, v, label in graph.edges(sort=True): if u == v: # loops are done below continue if label: - line = r'\draw[{}] ({}) -- node {{{}}} ({});'.format(arrow, - keys_for_vertices(u), - label, - keys_for_vertices(v)) + line = r'\draw[{}] ({}) -- node {{{}}} ({});'.format(arrow, keys_for_vertices(u), label, keys_for_vertices(v)) else: - line = r'\draw[{}] ({}) -- ({});'.format(arrow, - keys_for_vertices(u), - keys_for_vertices(v)) + line = r'\draw[{}] ({}) -- ({});'.format(arrow, keys_for_vertices(u), keys_for_vertices(v)) lines.append(line) # loops lines.append(r'% loops') - for (u, v, label) in graph.loop_edges(): - line = r'\draw ({}) edge [loop above] node {{{}}} ();'.format( - keys_for_vertices(u), label) + for u, v, label in graph.loop_edges(): + line = r'\draw ({}) edge [loop above] node {{{}}} ();'.format(keys_for_vertices(u), label) lines.append(line) lines.append(r'\end{tikzpicture}') diff --git a/src/sage/misc/lazy_attribute.pyi b/src/sage/misc/lazy_attribute.pyi index b857216eed1..703e489cbe8 100644 --- a/src/sage/misc/lazy_attribute.pyi +++ b/src/sage/misc/lazy_attribute.pyi @@ -5,8 +5,5 @@ from typing import Any # Adapted from https://github.com/python/typeshed/blob/b9640005eb586afdbe0a57bac2b88a7a12465069/stdlib/builtins.pyi#L1237-L1254 class lazy_attribute: - def __init__( - self, - f: Callable[[Any], Any] | None = ... - ) -> None: ... + def __init__(self, f: Callable[[Any], Any] | None = ...) -> None: ... def __get__(self, a: Any, cls: type) -> Any: ... diff --git a/src/sage/misc/lazy_format.py b/src/sage/misc/lazy_format.py index 09dfe8c5e3d..6b933b37ce5 100644 --- a/src/sage/misc/lazy_format.py +++ b/src/sage/misc/lazy_format.py @@ -2,7 +2,6 @@ Lazy format strings """ - from typing import Self @@ -98,7 +97,7 @@ def __mod__(self, args) -> Self: """ if hasattr(self, "_args"): # self is already bound... - self = LazyFormat(""+self) + self = LazyFormat("" + self) self._args = args return self @@ -124,7 +123,7 @@ def __repr__(self) -> str: try: args = self._args except AttributeError: - return "unbound LazyFormat(\""+self+"\")" + return "unbound LazyFormat(\"" + self + "\")" else: return str.__mod__(self, args) diff --git a/src/sage/misc/lazy_import_cache.py b/src/sage/misc/lazy_import_cache.py index d47b6d5edfd..2bc16ba5dab 100644 --- a/src/sage/misc/lazy_import_cache.py +++ b/src/sage/misc/lazy_import_cache.py @@ -1,6 +1,7 @@ """ Lazy import cache """ + import os import hashlib @@ -31,5 +32,4 @@ def get_cache_file(): sage: sage.misc.lazy_import_cache.DOT_SAGE = OLD """ mangled = hashlib.sha256(os.path.realpath(SAGE_LIB).encode('utf-8')).hexdigest() - return os.path.join(DOT_SAGE, 'cache', - "%s-lazy_import_cache.pickle" % mangled) + return os.path.join(DOT_SAGE, 'cache', "%s-lazy_import_cache.pickle" % mangled) diff --git a/src/sage/misc/map_threaded.py b/src/sage/misc/map_threaded.py index db525e0ef6f..82217bf36d9 100644 --- a/src/sage/misc/map_threaded.py +++ b/src/sage/misc/map_threaded.py @@ -33,5 +33,4 @@ def map_threaded(function, sequence): """ if hasattr(sequence, 'apply_map'): return sequence.apply_map(function) - return [map_threaded(function, x) if isinstance(x, (list, tuple)) - else function(x) for x in sequence] + return [map_threaded(function, x) if isinstance(x, (list, tuple)) else function(x) for x in sequence] diff --git a/src/sage/misc/mathml.py b/src/sage/misc/mathml.py index 7d38ad19128..4b515b20106 100644 --- a/src/sage/misc/mathml.py +++ b/src/sage/misc/mathml.py @@ -43,14 +43,7 @@ def str_function(x): # One can add to the latex_table in order to install latexing # functionality for other types. -mathml_table = { - list: list_function, - tuple: tuple_function, - bool: bool_function, - str: str_function, - float: str, - int: str -} +mathml_table = {list: list_function, tuple: tuple_function, bool: bool_function, str: str_function, float: str, int: str} class MathML(str): diff --git a/src/sage/misc/messaging.py b/src/sage/misc/messaging.py index 98183875387..0261c03f235 100644 --- a/src/sage/misc/messaging.py +++ b/src/sage/misc/messaging.py @@ -77,9 +77,6 @@ def pushover(message, **kwds): request.update(pushover_defaults) request.update(kwds) - conn = httplib.HTTPSConnection("api.pushover.net:443", - context=default_context()) - conn.request("POST", "/1/messages.json", - urlencode(request), - {"Content-type": "application/x-www-form-urlencoded"}) + conn = httplib.HTTPSConnection("api.pushover.net:443", context=default_context()) + conn.request("POST", "/1/messages.json", urlencode(request), {"Content-type": "application/x-www-form-urlencoded"}) return conn.getresponse().status == 200 diff --git a/src/sage/misc/method_decorator.py b/src/sage/misc/method_decorator.py index 5f2f630bc58..fb5ea235e0f 100644 --- a/src/sage/misc/method_decorator.py +++ b/src/sage/misc/method_decorator.py @@ -5,6 +5,7 @@ - Martin Albrecht (2009-05): inspired by a conversation with and code by Mike Hansen """ + from typing import Self from sage.structure.sage_object import SageObject @@ -48,6 +49,7 @@ def _sage_src_(self): True """ from sage.misc.sageinspect import sage_getsource + return sage_getsource(self.f) def __call__(self, *args, **kwds): diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index 372b7905676..a37a20b6a34 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -48,13 +48,9 @@ from sage.env import DOT_SAGE, HOSTNAME from sage.misc.lazy_import import lazy_import -lazy_import("sage.combinat.subset", ["powerset", "subsets", "uniq"], - deprecation=35564) +lazy_import("sage.combinat.subset", ["powerset", "subsets", "uniq"], deprecation=35564) -lazy_import( - "sage.misc.timing", ["cputime", "GlobalCputime", "walltime"], - deprecation=35816 -) +lazy_import("sage.misc.timing", ["cputime", "GlobalCputime", "walltime"], deprecation=35816) LOCAL_IDENTIFIER = '%s.%s' % (HOSTNAME, os.getpid()) @@ -363,6 +359,7 @@ def nest(f, n, x): # The A \ b operator has been removed after issue #36394 ################################################################# + ################################################################# # is_iterator function ################################################################# @@ -878,9 +875,7 @@ def inject_variable(name, value, warn=True): # also from functions in various modules. G = get_main_globals() if name in G and warn: - warnings.warn( - "redefining global value `%s`" % name, RuntimeWarning, stacklevel=2 - ) + warnings.warn("redefining global value `%s`" % name, RuntimeWarning, stacklevel=2) G[name] = value diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 80fb01f3223..c04f31d49fe 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -85,6 +85,7 @@ def _is_finite(L, fallback=True): return fallback from sage.rings.infinity import infinity + return n is not infinity @@ -316,6 +317,7 @@ class xmrange_iter: - Joel B. Mohler """ + def __init__(self, iter_list, typ=list): self.iter_list = iter_list self.typ = typ @@ -374,6 +376,7 @@ def cardinality(self): """ from sage.rings.integer import Integer from sage.rings.infinity import infinity + ans = Integer(1) found_infinity = False for L in self.iter_list: @@ -400,7 +403,7 @@ def _xmrange(sizes, typ=list): for i in sizes: if i <= 0: return - v = [0] * n # make a list of n 0's. + v = [0] * n # make a list of n 0's. v[-1] = -1 ptr_max = n - 1 ptr = ptr_max @@ -415,7 +418,7 @@ def _xmrange(sizes, typ=list): ptr -= 1 else: return - yield typ(v) # make a copy of v! + yield typ(v) # make a copy of v! def mrange(sizes, typ=list): @@ -567,6 +570,7 @@ class xmrange: - William Stein """ + def __init__(self, sizes, typ=list): self.sizes = [int(x) for x in sizes] self.typ = typ @@ -715,10 +719,10 @@ def cantor_product(*args, **kwds): from itertools import count from sage.combinat.integer_lists import IntegerListsLex - m = len(args) # numer of factors - lengths = [None] * m # None or length of factors - data = [[] for _ in range(m)] # the initial slice of each factor - iterators = [iter(a) for a in args] # the iterators + m = len(args) # numer of factors + lengths = [None] * m # None or length of factors + data = [[] for _ in range(m)] # the initial slice of each factor + iterators = [iter(a) for a in args] # the iterators repeat = int(kwds.pop('repeat', 1)) if repeat == 0: yield () @@ -740,8 +744,7 @@ def cantor_product(*args, **kwds): lengths[i] = n # iterate through what we have - ceiling = [n if lengths[i] is None else lengths[i] - 1 - for i in range(m)] * repeat + ceiling = [n if lengths[i] is None else lengths[i] - 1 for i in range(m)] * repeat for v in IntegerListsLex(n, length=mm, ceiling=ceiling, **kwds): yield tuple(data[i % m][v[i]] for i in range(mm)) diff --git a/src/sage/misc/multireplace.py b/src/sage/misc/multireplace.py index 3b70d60e50c..2c53f542901 100644 --- a/src/sage/misc/multireplace.py +++ b/src/sage/misc/multireplace.py @@ -20,6 +20,7 @@ # The simplest, lambda-based implementation # + def multiple_replace(dic, text): """ Replace in 'text' all occurrences of any key in the given @@ -37,4 +38,4 @@ def multiple_replace(dic, text): regex = re.compile("(%s)" % "|".join(re.escape(k) for k in dic)) # For each match, look-up corresponding value in dictionary - return regex.sub(lambda mo: dic[mo.string[mo.start():mo.end()]], text) + return regex.sub(lambda mo: dic[mo.string[mo.start() : mo.end()]], text) diff --git a/src/sage/misc/namespace_package.py b/src/sage/misc/namespace_package.py index e2de10b5bfb..c1aedc746fe 100644 --- a/src/sage/misc/namespace_package.py +++ b/src/sage/misc/namespace_package.py @@ -1,6 +1,7 @@ """ Utility functions for namespace packages in Sage """ + from importlib import import_module @@ -17,7 +18,7 @@ def install_doc(package, doc): 'hello' """ pkg = import_module(package) - pkg.__doc__ = doc # enable sage.package? + pkg.__doc__ = doc # enable sage.package? pkg.getdoc = lambda: doc # enable help(sage.package) diff --git a/src/sage/misc/object_multiplexer.py b/src/sage/misc/object_multiplexer.py index ceaac1b3fb2..3c5aacda1e3 100644 --- a/src/sage/misc/object_multiplexer.py +++ b/src/sage/misc/object_multiplexer.py @@ -5,6 +5,7 @@ - Martin Albrecht (2011): initial version """ + # **************************************************************************** # Copyright (C) 2011 Martin Albrecht # @@ -26,6 +27,7 @@ class MultiplexFunction: A simple wrapper object for functions that are called on a list of objects. """ + def __init__(self, multiplexer, name): """ EXAMPLES:: @@ -49,8 +51,7 @@ def __call__(self, *args, **kwds): sage: f() ('1', '1/2') """ - l = [getattr(child, self.name)(*args, **kwds) - for child in self.multiplexer.children] + l = [getattr(child, self.name)(*args, **kwds) for child in self.multiplexer.children] if all(e is None for e in l): return None return tuple(l) @@ -62,6 +63,7 @@ class Multiplex: new object implies that the same function is called on all children. """ + def __init__(self, *args): """ EXAMPLES:: diff --git a/src/sage/misc/package.py b/src/sage/misc/package.py index 9bfbc1caa86..22cd6f34026 100644 --- a/src/sage/misc/package.py +++ b/src/sage/misc/package.py @@ -113,6 +113,7 @@ def pip_remote_version(pkg, pypi_url=DEFAULT_PYPI, ignore_URLError=False): except URLError: if ignore_URLError: import warnings + warnings.warn("failed to fetch the version of pkg={!r} at {}".format(pkg, url)) return raise @@ -145,6 +146,7 @@ def spkg_type(name): """ spkg_type = None from sage.env import SAGE_PKGS + if not SAGE_PKGS: return None try: @@ -202,9 +204,9 @@ def normalize(name: str) -> str: if normalization == 'spkg': return name.lower().replace('-', '_').replace('.', '_') raise NotImplementedError(f'normalization {normalization} is not implemented') + try: - return {normalize(package['name']): package['version'] - for package in json.loads(stdout)} + return {normalize(package['name']): package['version'] for package in json.loads(stdout)} except json.decoder.JSONDecodeError: # Something went wrong while parsing the output from pip. # This may happen if pip is not correctly installed. @@ -213,6 +215,7 @@ def normalize(name: str) -> str: class PackageInfo(NamedTuple): """Represents information about a package.""" + name: str type: Optional[str] = None source: Optional[str] = None @@ -226,8 +229,7 @@ def is_installed(self) -> bool: return self.installed_version is not None -def list_packages(*pkg_types: str, pkg_sources: list[str] = ['normal', 'pip', 'script'], - local: bool = False, ignore_URLError: bool = False, exclude_pip: bool = False) -> dict[str, PackageInfo]: +def list_packages(*pkg_types: str, pkg_sources: list[str] = ['normal', 'pip', 'script'], local: bool = False, ignore_URLError: bool = False, exclude_pip: bool = False) -> dict[str, PackageInfo]: r""" Return a dictionary of information about each package. @@ -293,8 +295,7 @@ def list_packages(*pkg_types: str, pkg_sources: list[str] = ['normal', 'pip', 's if exclude_pip: pkg_sources = [s for s in pkg_sources if s != 'pip'] - pkgs = {p: PackageInfo(name=p, installed_version=v) - for p, v in installed_packages('pip' not in pkg_sources).items()} + pkgs = {p: PackageInfo(name=p, installed_version=v) for p, v in installed_packages('pip' not in pkg_sources).items()} # Add additional information based on Sage's package repository lp = [] @@ -402,8 +403,7 @@ def installed_packages(exclude_pip=True): if inst_dir is not None: try: lp = os.listdir(inst_dir) - installed.update(pkgname_split(pkgname) for pkgname in lp - if not pkgname.startswith('.')) + installed.update(pkgname_split(pkgname) for pkgname in lp if not pkgname.startswith('.')) except FileNotFoundError: pass return installed @@ -537,8 +537,7 @@ def package_manifest(package): version = installed_packages()[package] inst_dir = _spkg_inst_dirs() if inst_dir is not None: - stamp_file = os.path.join(inst_dir, - '{}-{}'.format(package, version)) + stamp_file = os.path.join(inst_dir, '{}-{}'.format(package, version)) try: with open(stamp_file) as f: return json.load(f) diff --git a/src/sage/misc/package_dir.py b/src/sage/misc/package_dir.py index 962966207dc..55e0ab70c5b 100644 --- a/src/sage/misc/package_dir.py +++ b/src/sage/misc/package_dir.py @@ -1,6 +1,7 @@ """ Recognizing package directories """ + # **************************************************************************** # Copyright (C) 2020-2022 Matthias Koeppe # @@ -89,9 +90,7 @@ def is_package_or_sage_namespace_package_dir(path): """ if os.path.exists(os.path.join(path, "__init__.py")): # ordinary package return True - if os.path.exists( - os.path.join(path, "__init__.pxd") - ): # for consistency with Cython + if os.path.exists(os.path.join(path, "__init__.pxd")): # for consistency with Cython return True fname = os.path.join(path, "all.py") if os.path.exists(fname): @@ -111,15 +110,11 @@ def cython_namespace_package_support(): import Cython.Utils orig_is_package_dir = Cython.Utils.is_package_dir - Cython.Utils.is_package_dir = Cython.Build.Cythonize.is_package_dir = ( - Cython.Build.Dependencies.is_package_dir - ) = Cython.Utils.cached_function(is_package_or_sage_namespace_package_dir) + Cython.Utils.is_package_dir = Cython.Build.Cythonize.is_package_dir = Cython.Build.Dependencies.is_package_dir = Cython.Utils.cached_function(is_package_or_sage_namespace_package_dir) try: yield finally: - Cython.Utils.is_package_dir = Cython.Build.Cythonize.is_package_dir = ( - Cython.Build.Dependencies.is_package_dir - ) = orig_is_package_dir + Cython.Utils.is_package_dir = Cython.Build.Cythonize.is_package_dir = Cython.Build.Dependencies.is_package_dir = orig_is_package_dir def walk_packages(path=None, prefix="", onerror=None): @@ -167,9 +162,7 @@ def iter_modules(path=None, prefix=""): if path is None: importers = iter_importers() elif isinstance(path, str): - raise ValueError( - "path must be None or list of paths to look for modules in" - ) + raise ValueError("path must be None or list of paths to look for modules in") else: importers = map(get_importer, path) diff --git a/src/sage/misc/pager.py b/src/sage/misc/pager.py index 84833d6135a..e5e8fc2e7e5 100644 --- a/src/sage/misc/pager.py +++ b/src/sage/misc/pager.py @@ -6,6 +6,7 @@ Any code in sage that uses a pager should use this pager. """ + # --------------------------------------------------------------------------- # Copyright (C) 2006 William Stein # @@ -17,4 +18,5 @@ def pager(): import IPython.core.page + return IPython.core.page.page diff --git a/src/sage/misc/profiler.py b/src/sage/misc/profiler.py index 37d1e76e99c..3e011a5c1b6 100644 --- a/src/sage/misc/profiler.py +++ b/src/sage/misc/profiler.py @@ -96,11 +96,11 @@ def clear(self): # _checkpoints is list of pairs (details, time), where time is a float # and details is a triple (line_number, context, message) self._checkpoints = [] - self._active_details = None # details from the last __call__() call - self._last_cputime = [None]*len(self._cputime_functions) + self._active_details = None # details from the last __call__() call + self._last_cputime = [None] * len(self._cputime_functions) def __call__(self, message=None): - """ Adds a checkpoint. """ + """Adds a checkpoint.""" entry_times = [fn() for fn in self._cputime_functions] frame = inspect.currentframe().f_back @@ -116,7 +116,7 @@ def __call__(self, message=None): del frame if self._active_details is not None: - _time = sum([entry_times[i]-self._last_cputime[i] for i in range(len(entry_times))]) + _time = sum([entry_times[i] - self._last_cputime[i] for i in range(len(entry_times))]) self._checkpoints.append((self._active_details, _time)) self._active_details = (line_number, context, message) @@ -127,12 +127,12 @@ def __call__(self, message=None): sys.stdout.flush() def __repr__(self): - """ Returns a nicely formatted table of stored checkpoints and timings. """ + """Returns a nicely formatted table of stored checkpoints and timings.""" if not self._checkpoints: return "no checkpoints defined" output = [] - for ((line_number, context, message), time_used) in self._checkpoints: + for (line_number, context, message), time_used in self._checkpoints: if message is None: # If the user hasn't given a message, we look for some # source code to print instead @@ -144,7 +144,7 @@ def __repr__(self): break if len(found) > 60: - found = found[:60] + "..." # in case the source line is really long + found = found[:60] + "..." # in case the source line is really long message = "line %d: %s" % (line_number, found) output.append("%9.3fs -- %s" % (time_used, message)) @@ -170,9 +170,10 @@ def print_last(self): break if len(found) > 60: - found = found[:60] + "..." # in case the source line is really long + found = found[:60] + "..." # in case the source line is really long message = "line %d: %s" % (line_number, found) return "%9.3fs -- %s" % (time_used, message) + # end of file diff --git a/src/sage/misc/random_testing.py b/src/sage/misc/random_testing.py index c9b53903622..bc9e92e24d6 100644 --- a/src/sage/misc/random_testing.py +++ b/src/sage/misc/random_testing.py @@ -156,6 +156,7 @@ def wrapped_fun(*args, **kwargs): print("Please include this random seed in your bug report:") print("Random seed: {}".format(used_seed)) print(repr(e)) + return wrapped_fun @@ -179,6 +180,7 @@ def check_add_commutes(trials, verbose=False): sage: check_add_commutes(1000) # long time """ from sage.rings.rational_field import QQ + for _ in range(trials): a = QQ.random_element() b = QQ.random_element() @@ -253,6 +255,7 @@ def check_add_is_mul(trials, verbose=False): AssertionError() """ from sage.rings.rational_field import QQ + for _ in range(trials): a = QQ.random_element() b = QQ.random_element() diff --git a/src/sage/misc/remote_file.py b/src/sage/misc/remote_file.py index 7e1cfef2ea7..4efe15847c4 100644 --- a/src/sage/misc/remote_file.py +++ b/src/sage/misc/remote_file.py @@ -32,6 +32,7 @@ def get_remote_file(filename, verbose=True) -> Path: print("Attempting to load remote file: " + filename) from sage.misc.temporary_file import tmp_filename + ext = os.path.splitext(filename)[1] temp_name = Path(tmp_filename(ext=ext)) # IMPORTANT -- urllib takes a long time to load, diff --git a/src/sage/misc/repr.py b/src/sage/misc/repr.py index a1401279328..585986bc3f3 100644 --- a/src/sage/misc/repr.py +++ b/src/sage/misc/repr.py @@ -43,8 +43,7 @@ def coeff_repr(c, is_latex=False): return s -def repr_lincomb(terms, is_latex=False, scalar_mult='*', strip_one=False, - repr_monomial=None, latex_scalar_mult=None): +def repr_lincomb(terms, is_latex=False, scalar_mult='*', strip_one=False, repr_monomial=None, latex_scalar_mult=None): """ Compute a string representation of a linear combination of some formal symbols. @@ -145,6 +144,7 @@ def repr_lincomb(terms, is_latex=False, scalar_mult='*', strip_one=False, def repr_monomial(monomial): return monomial._latex_() if hasattr(monomial, '_latex_') else str(monomial) + else: repr_monomial = str @@ -154,7 +154,7 @@ def repr_monomial(monomial): if scalar_mult is None: scalar_mult = "" if is_latex else "*" - for (monomial, c) in terms: + for monomial, c in terms: if c != 0: coeff = coeff_repr(c) negative = False @@ -196,5 +196,5 @@ def repr_monomial(monomial): return "0" # this can happen only if are only terms with coeff_repr(c) == "0" # elif s == "": - # return "1" # is empty string representation invalid? + # return "1" # is empty string representation invalid? return s diff --git a/src/sage/misc/rest_index_of_methods.py b/src/sage/misc/rest_index_of_methods.py index 915d7cc3fd9..fe77a268f91 100644 --- a/src/sage/misc/rest_index_of_methods.py +++ b/src/sage/misc/rest_index_of_methods.py @@ -164,8 +164,7 @@ def gen_rest_table_index(obj, names=None, sort=True, only_local_functions=True, # If input is a class/module, we list all its non-private and methods/functions if inspect.isclass(obj) or inspect.ismodule(obj): - list_of_entries, names = list_of_subfunctions( - obj, only_local_functions=only_local_functions) + list_of_entries, names = list_of_subfunctions(obj, only_local_functions=only_local_functions) else: list_of_entries = obj @@ -173,10 +172,7 @@ def gen_rest_table_index(obj, names=None, sort=True, only_local_functions=True, assert isinstance(list_of_entries, list) - s = [".. csv-table::", - " :class: contentstable", - " :widths: 30, 70", - " :delim: @\n"] + s = [".. csv-table::", " :class: contentstable", " :widths: 30, 70", " :delim: @\n"] if sort: list_of_entries.sort(key=fname) @@ -193,15 +189,11 @@ def gen_rest_table_index(obj, names=None, sort=True, only_local_functions=True, for e in list_of_entries: if inspect.ismethod(e): - link = ":meth:`~{module}.{cls}.{func}`".format( - module=e.im_class.__module__, cls=e.im_class.__name__, - func=fname(e)) + link = ":meth:`~{module}.{cls}.{func}`".format(module=e.im_class.__module__, cls=e.im_class.__name__, func=fname(e)) elif _isfunction(e) and obj_or_root_is_class: - link = ":meth:`~{module}.{cls}.{func}`".format( - module=module_name, cls=class_name, func=fname(e)) + link = ":meth:`~{module}.{cls}.{func}`".format(module=module_name, cls=class_name, func=fname(e)) elif _isfunction(e): - link = ":func:`~{module}.{func}`".format( - module=e.__module__, func=fname(e)) + link = ":func:`~{module}.{func}`".format(module=e.__module__, func=fname(e)) else: continue @@ -213,9 +205,9 @@ def gen_rest_table_index(obj, names=None, sort=True, only_local_functions=True, # Descriptions of the method/function if doc: - desc = doc.split('\n\n')[0] # first paragraph - desc = " ".join(x.strip() for x in desc.splitlines()) # concatenate lines - desc = desc.strip() # remove leading spaces + desc = doc.split('\n\n')[0] # first paragraph + desc = " ".join(x.strip() for x in desc.splitlines()) # concatenate lines + desc = desc.strip() # remove leading spaces else: desc = "NO DOCSTRING" @@ -283,14 +275,7 @@ def can_import(f): return False return True - functions = {getattr(root, name): name for name, f in root.__dict__.items() if - (not name.startswith('_') and # private functions - can_import(f) and # unresolved lazy imports - not hasattr(f, 'issue_number') and # deprecated functions - not inspect.isclass(f) and # classes - callable(getattr(f, '__func__', f)) and # e.g. GenericGraph.graphics_array_defaults - local_filter(f, name)) # possibly filter imported functions - } + functions = {getattr(root, name): name for name, f in root.__dict__.items() if (not name.startswith('_') and can_import(f) and not hasattr(f, 'issue_number') and not inspect.isclass(f) and callable(getattr(f, '__func__', f)) and local_filter(f, name))} # private functions # unresolved lazy imports # deprecated functions # classes # e.g. GenericGraph.graphics_array_defaults # possibly filter imported functions return list(functions.keys()), functions @@ -321,24 +306,22 @@ def gen_thematic_rest_table_index(root, additional_categories=None, only_local_f True """ from collections import defaultdict + if additional_categories is None: additional_categories = {} - functions, names = list_of_subfunctions(root, - only_local_functions=only_local_functions) + functions, names = list_of_subfunctions(root, only_local_functions=only_local_functions) theme_to_function = defaultdict(list) for f in functions: if hasattr(f, 'doc_index'): doc_ind = f.doc_index else: try: - doc_ind = additional_categories.get(f.__name__, - "Unsorted") + doc_ind = additional_categories.get(f.__name__, "Unsorted") except AttributeError: doc_ind = "Unsorted" theme_to_function[doc_ind].append(f) - s = ["**" + theme + "**\n\n" + gen_rest_table_index(list_of_functions, names=names, root=root) - for theme, list_of_functions in sorted(theme_to_function.items())] + s = ["**" + theme + "**\n\n" + gen_rest_table_index(list_of_functions, names=names, root=root) for theme, list_of_functions in sorted(theme_to_function.items())] return "\n\n".join(s) @@ -364,11 +347,12 @@ def doc_index(name): sage: a.doc_index 'Wouhouuuuu' """ + def hey(f): setattr(f, "doc_index", name) return f + return hey -__doc__ = __doc__.format(INDEX_OF_FUNCTIONS=gen_rest_table_index([gen_rest_table_index, - gen_thematic_rest_table_index])) +__doc__ = __doc__.format(INDEX_OF_FUNCTIONS=gen_rest_table_index([gen_rest_table_index, gen_thematic_rest_table_index])) diff --git a/src/sage/misc/sage_eval.py b/src/sage/misc/sage_eval.py index 043d73836d0..13f35d061d8 100644 --- a/src/sage/misc/sage_eval.py +++ b/src/sage/misc/sage_eval.py @@ -1,6 +1,7 @@ r""" Evaluating a String in Sage """ + # **************************************************************************** # Copyright (C) 2006 William Stein # @@ -172,6 +173,7 @@ def sage_eval(source, locals=None, cmds='', preparse=True): locals = {} import sage.all + if cmds: cmd_seq = cmds + '\n_sage_eval_returnval_ = ' + source if preparse: diff --git a/src/sage/misc/sage_input.py b/src/sage/misc/sage_input.py index 7553863325e..f2724baa950 100644 --- a/src/sage/misc/sage_input.py +++ b/src/sage/misc/sage_input.py @@ -484,6 +484,7 @@ def __call__(self, x, coerced=False): # but I think they're rare enough in Sage that it's not # worth the effort. from math import inf + if x == inf: return self.name('float')(self.name('infinity')) if x != x: @@ -496,6 +497,7 @@ def __call__(self, x, coerced=False): return SIE_literal_stringrep(self, str(x)) from sage.rings.real_mpfr import RR from sage.rings.integer_ring import ZZ + rrx = RR(x) if rrx in ZZ and abs(rrx) < (1 << 53): return self.name('float')(self.int(ZZ(rrx))) @@ -1076,7 +1078,7 @@ def prod(self, factors, simplify=False): neg = False break if isinstance(factor, SIE_literal_stringrep) and factor._sie_value == '1': - factors[i:i + 1] = [] + factors[i : i + 1] = [] else: i += 1 if len(factors) == 0: @@ -1122,7 +1124,7 @@ def sum(self, terms, simplify=False): while i < len(terms): term = terms[i] if isinstance(term, SIE_literal_stringrep) and term._sie_value == '0': - terms[i:i + 1] = [] + terms[i : i + 1] = [] else: i += 1 if len(terms) == 0: @@ -1398,8 +1400,7 @@ def __call__(self, *args, **kwargs): {call: {atomic:3}({atomic:4})} """ new_args = [self._sie_builder(arg) for arg in args] - new_kwargs = {key: self._sie_builder(val) - for key, val in kwargs.items()} + new_kwargs = {key: self._sie_builder(val) for key, val in kwargs.items()} return SIE_call(self._sie_builder, self, new_args, new_kwargs) def __getitem__(self, key): @@ -1872,8 +1873,7 @@ def __repr__(self): """ func = repr(self._sie_func) args = [repr(arg) for arg in self._sie_args] - kwargs = sorted(k + '=' + repr(v) - for k, v in self._sie_kwargs.items()) + kwargs = sorted(k + '=' + repr(v) for k, v in self._sie_kwargs.items()) all_args = ', '.join(args + kwargs) return "{call: %s(%s)}" % (func, all_args) @@ -1913,8 +1913,7 @@ def _sie_format(self, sif): """ func = sif.format(self._sie_func, _prec_attribute) args = [sif.format(arg, 0) for arg in self._sie_args] - kwargs = sorted(k + '=' + sif.format(v, 0) - for k, v in self._sie_kwargs.items()) + kwargs = sorted(k + '=' + sif.format(v, 0) for k, v in self._sie_kwargs.items()) all_args = ', '.join(args + kwargs) return ('%s(%s)' % (func, all_args), _prec_funcall) @@ -2042,6 +2041,7 @@ class SIE_getattr(SageInputExpression): sage: sie {call: {getattr: {atomic:CC}.gen}()} """ + def __init__(self, sib, obj, attr): r""" Initialize an instance of :class:`SIE_getattr`. @@ -2176,8 +2176,7 @@ def __repr__(self): {list: ({atomic:'Hello'}, {atomic:'world'})} """ kind = "list" if self._sie_is_list else "tuple" - return "{%s: (%s)}" % \ - (kind, ', '.join(repr(v) for v in self._sie_values)) + return "{%s: (%s)}" % (kind, ', '.join(repr(v) for v in self._sie_values)) def _sie_referenced(self): r""" @@ -2279,9 +2278,7 @@ def __repr__(self): sage: sib.dict({'keaton':'general', 'chan':'master'}) {dict: {{atomic:'keaton'}:{atomic:'general'}, {atomic:'chan'}:{atomic:'master'}}} """ - return "{dict: {%s}}" % \ - ', '.join(repr(key) + ':' + repr(val) - for key, val in self._sie_entries) + return "{dict: {%s}}" % ', '.join(repr(key) + ':' + repr(val) for key, val in self._sie_entries) def _sie_referenced(self): r""" @@ -2315,8 +2312,7 @@ def _sie_format(self, sif): sage: sie._sie_format(sif) ("{'carnivores':1, 'thinking':2, 'triumph':3}", 42) """ - return "{%s}" % ', '.join(sif.format(k, 0) + ':' + sif.format(v, 0) - for k, v in self._sie_entries), _prec_atomic + return "{%s}" % ', '.join(sif.format(k, 0) + ':' + sif.format(v, 0) for k, v in self._sie_entries), _prec_atomic class SIE_binary(SageInputExpression): @@ -2834,9 +2830,7 @@ def _sie_add_command(self, sif): (R, R, GF(17)['y']) """ if not self._sie_generated: - if self._sie_builder.preparse() and \ - self._sie_gens_constr is not None and \ - all(g._sie_got_preferred(sif) for g in self._sie_gens): + if self._sie_builder.preparse() and self._sie_gens_constr is not None and all(g._sie_got_preferred(sif) for g in self._sie_gens): s, _ = self._sie_gens_constr._sie_format(sif) sif._commands += '%s.<%s> = %s\n' % (self._sie_get_varname(sif), ','.join(self._sie_gen_names), s) else: @@ -3095,8 +3089,7 @@ def __repr__(self): sage: sib.import_name('sage.foo', 'happy', 'sad') {import:sage.foo/happy as sad} """ - return "{import:%s/%s%s}" % (self._sie_module_name, self._sie_object_name, - "" if self._sie_object_name == self._sie_preferred_varname else " as %s" % self._sie_preferred_varname) + return "{import:%s/%s%s}" % (self._sie_module_name, self._sie_object_name, "" if self._sie_object_name == self._sie_preferred_varname else " as %s" % self._sie_preferred_varname) def _sie_is_simple(self): r""" @@ -3162,9 +3155,7 @@ def _sie_format(self, sif): rename = '' if name != self._sie_object_name: rename = ' as ' + name - sif._commands += 'from %s import %s%s\n' % (self._sie_module_name, - self._sie_object_name, - rename) + sif._commands += 'from %s import %s%s\n' % (self._sie_module_name, self._sie_object_name, rename) return name, _prec_atomic @@ -3470,6 +3461,7 @@ def verify_same(a, b): AssertionError """ from sage.structure.element import Element + if isinstance(a, Element): assert a.parent() == b.parent() else: @@ -3524,6 +3516,7 @@ def verify_si_answer(x, answer, preparse): sage: verify_si_answer(1, 'ZZ(1)', None) """ from sage.misc.sage_eval import sage_eval + if preparse is None: verify_same(x, sage_eval(answer, preparse=True)) verify_same(x, sage_eval(answer, preparse=False)) @@ -3603,6 +3596,5 @@ def __repr__(self): return self[0] + self[1] locals = self[2] - locals_text = ''.join(' %s: %r\n' % (k, v) - for k, v in locals.items()) + locals_text = ''.join(' %s: %r\n' % (k, v) for k, v in locals.items()) return 'LOCALS:\n' + locals_text + self[0] + self[1] diff --git a/src/sage/misc/sage_timeit.py b/src/sage/misc/sage_timeit.py index b0366cc8644..4e9697527aa 100644 --- a/src/sage/misc/sage_timeit.py +++ b/src/sage/misc/sage_timeit.py @@ -57,6 +57,7 @@ class SageTimeitResult: sage: SageTimeitResult( (1, 2, 3, 4, 's') ) ) failed: TypeError: * wants int> """ + def __init__(self, stats, series=None): r""" Construction of a timing result. @@ -222,8 +223,7 @@ def sage_timeit(stmt, globals_dict=None, preparse=None, number=0, repeat=3, prec # but is there a better way to achieve that the code stmt has access # to the shell namespace? - src = timeit_.template.format(stmt=timeit_.reindent(stmt, 8), - setup='pass', init='') + src = timeit_.template.format(stmt=timeit_.reindent(stmt, 8), setup='pass', init='') code = compile(src, '', 'exec') ns = {} if not globals_dict: @@ -233,6 +233,7 @@ def sage_timeit(stmt, globals_dict=None, preparse=None, number=0, repeat=3, prec try: import sys + f = sys.stdout sys.stdout = open('/dev/null', 'w') @@ -251,6 +252,7 @@ def sage_timeit(stmt, globals_dict=None, preparse=None, number=0, repeat=3, prec sys.stdout.close() sys.stdout = f import gc + gc.enable() if seconds: diff --git a/src/sage/misc/sage_unittest.py b/src/sage/misc/sage_unittest.py index 3567c9a41d7..78ad3e0af53 100644 --- a/src/sage/misc/sage_unittest.py +++ b/src/sage/misc/sage_unittest.py @@ -155,6 +155,7 @@ def __init__(self, instance): Test suite for Integer Ring """ from sage.structure.sage_object import SageObject + if not isinstance(instance, (SageObject, PythonObjectWithTests)): instance = PythonObjectWithTests(instance) self._instance = instance @@ -168,8 +169,7 @@ def __repr__(self): """ return "Test suite for %s" % self._instance - def run(self, category=None, skip=[], catch=True, raise_on_failure=False, - **options): + def run(self, category=None, skip=[], catch=True, raise_on_failure=False, **options): """ Run all the tests from this test suite: @@ -385,8 +385,7 @@ class InstanceTester(unittest.TestCase): # all that much anyways) longMessage = False - def __init__(self, instance, elements=None, verbose=False, prefix='', - max_runs=4096, max_samples=None, **options): + def __init__(self, instance, elements=None, verbose=False, prefix='', max_runs=4096, max_samples=None, **options): """ A gadget attached to an instance providing it with testing utilities. @@ -570,6 +569,7 @@ def some_elements(self, S=None, repeat=None): """ S = S or self._elements or self._instance.some_elements() from sage.misc.misc import some_tuples + return list(some_tuples(S, repeat, self._max_runs, self._max_samples)) @@ -582,6 +582,7 @@ class PythonObjectWithTests: sage: TestSuite("bla").run() """ + def __init__(self, instance): """ EXAMPLES:: @@ -608,6 +609,7 @@ def _test_pickling(self, **options): """ tester = instance_tester(self, **options) from sage.misc.persist import loads, dumps + tester.assertEqual(loads(dumps(self._instance)), self._instance) def _test_new(self, **options): diff --git a/src/sage/misc/sagedoc.py b/src/sage/misc/sagedoc.py index 758759714e6..27e5c48a219 100644 --- a/src/sage/misc/sagedoc.py +++ b/src/sage/misc/sagedoc.py @@ -31,6 +31,7 @@ sage: os.system("sage -c \"if 'sphinx' in sys.modules: sys.exit(1)\"") 0 """ + # **************************************************************************** # Copyright (C) 2005 William Stein # @@ -58,45 +59,7 @@ # Math substitutions: don't forget the leading backslash '\\'. These # are done using regular expressions, so it works best to also make # the strings raw: r'\\blah'. -math_substitutes = [ - (r'\\to', '-->'), - (r'\\rightarrow', '-->'), - (r'\\leftarrow', '<--'), - (r'\\leftrightarrow', '<->'), - (r'\\longrightarrow', '--->'), - (r'\\longleftarrow', '<---'), - (r'\\longleftrightarrow', '<-->'), - (r'\\Rightarrow', '==>'), - (r'\\Leftarrow', '<=='), - (r'\\Leftrightarrow', '<=>'), - (r'\\Longrightarrow', '===>'), - (r'\\Longleftarrow', '<==='), - (r'\\Longleftrightarrow', '<==>'), - (r'\\colon', ':'), - (r'\\left', ''), - (r'\\right', ''), - (r'\\bigl', ''), - (r'\\bigr', ''), - (r'\\leq', '<='), - (r'\\geq', '>='), - (r'\\le', '<='), - (r'\\ge', '>='), - (r'\\cdots', '...'), - (r'\\ldots', '...'), - (r'\\dots', '...'), - (r'\\cdot', ' *'), - (r'\\ast', ' *'), - (r' \\times', ' x'), - (r'\\times', ' x'), - (r'\\backslash', '\\'), - (r'\\mapsto', ' |--> '), - (r'\\longmapsto', ' |---> '), - (r'\\lvert', '|'), - (r'\\rvert', '|'), - (r'\\mid', '|'), - (r' \\circ', ' o'), - (r'\\circ', ' o') -] +math_substitutes = [(r'\\to', '-->'), (r'\\rightarrow', '-->'), (r'\\leftarrow', '<--'), (r'\\leftrightarrow', '<->'), (r'\\longrightarrow', '--->'), (r'\\longleftarrow', '<---'), (r'\\longleftrightarrow', '<-->'), (r'\\Rightarrow', '==>'), (r'\\Leftarrow', '<=='), (r'\\Leftrightarrow', '<=>'), (r'\\Longrightarrow', '===>'), (r'\\Longleftarrow', '<==='), (r'\\Longleftrightarrow', '<==>'), (r'\\colon', ':'), (r'\\left', ''), (r'\\right', ''), (r'\\bigl', ''), (r'\\bigr', ''), (r'\\leq', '<='), (r'\\geq', '>='), (r'\\le', '<='), (r'\\ge', '>='), (r'\\cdots', '...'), (r'\\ldots', '...'), (r'\\dots', '...'), (r'\\cdot', ' *'), (r'\\ast', ' *'), (r' \\times', ' x'), (r'\\times', ' x'), (r'\\backslash', '\\'), (r'\\mapsto', ' |--> '), (r'\\longmapsto', ' |---> '), (r'\\lvert', '|'), (r'\\rvert', '|'), (r'\\mid', '|'), (r' \\circ', ' o'), (r'\\circ', ' o')] nonmath_substitutes = [ ('\\_', '_'), ('\\item', '* '), @@ -161,10 +124,11 @@ def _rmcmd(s, cmd, left='', right=''): j += 1 j -= 1 # j is position of closing '}' if j < len(s): - s = s[:i] + left + s[i + len(c):j] + right + s[j + 1:] + s = s[:i] + left + s[i + len(c) : j] + right + s[j + 1 :] else: return s + # I wanted to be cool and use regexp's, but they aren't really # useful, since really this is a parsing problem, because of # nesting of commands, etc. Since it doesn't have to be @@ -454,6 +418,7 @@ def process_dollars(s): if s.find("$") == -1: return s from sage.misc.superseded import deprecation + # find how much leading whitespace s has, for later comparison: # ignore all $ on lines which start with more whitespace. whitespace = re.match(r'\s*\S', s.lstrip('\n')) @@ -490,13 +455,11 @@ def process_dollars(s): for start, end in indices: while dollar.search(s, start, end): m = dollar.search(s, start, end) - s = s[:m.end() - 1] + "`" + s[m.end():] - deprecation(33973, - "using dollar signs to mark up math in Sage docstrings " - "is deprecated; use backticks instead") + s = s[: m.end() - 1] + "`" + s[m.end() :] + deprecation(33973, "using dollar signs to mark up math in Sage docstrings " "is deprecated; use backticks instead") while slashdollar.search(s, start, end): m = slashdollar.search(s, start, end) - s = s[:m.start()] + "$" + s[m.end():] + s = s[: m.start()] + "$" + s[m.end() :] return s @@ -574,9 +537,7 @@ def process_extlinks(s, embedded=False): m = re.search('.*<([^>]*)>', link) if m: link = m.group(1) - s = re.sub(':%s:`([^`]*)`' % key, - extlinks[key][0].replace('%s', link), - s, count=1) + s = re.sub(':%s:`([^`]*)`' % key, extlinks[key][0].replace('%s', link), s, count=1) return s @@ -601,7 +562,7 @@ def process_mathtt(s): end = s.find("}", start) if start == -1 or end == -1: break - s = s[:start] + s[start + 8:end] + s[end + 1:] + s = s[:start] + s[start + 8 : end] + s[end + 1 :] return s @@ -622,10 +583,9 @@ def process_optional_doctest_tags(s): start = 0 with io.StringIO() as output: for m in re.finditer('( *sage: *.*#.*)\n', s): - output.write(s[start:m.start(0)]) + output.write(s[start : m.start(0)]) line = m.group(1) - tags = [tag for tag in parse_optional_tags(line) - if tag not in available_software] + tags = [tag for tag in parse_optional_tags(line) if tag not in available_software] line = update_optional_tags(line, tags=tags) if not re.fullmatch(' *sage: *', line): print(line, file=output) @@ -764,7 +724,7 @@ def format(s, embedded=False): directives = [d.strip().lower() for d in first_line.split(',')] if 'noreplace' in directives or 'nodetex' in directives: - s = s[first_newline + len(os.linesep):] + s = s[first_newline + len(os.linesep) :] try: import sage.all @@ -778,10 +738,10 @@ def format(s, embedded=False): i = s[i_0:].find("<<<") if i == -1: break - j = s[i_0 + i + 3:].find('>>>') + j = s[i_0 + i + 3 :].find('>>>') if j == -1: break - obj = s[i_0 + i + 3:i_0 + i + 3 + j] + obj = s[i_0 + i + 3 : i_0 + i + 3 + j] if obj in docs: t = '' else: @@ -800,7 +760,7 @@ def format(s, embedded=False): t1 = sage.misc.sageinspect.sage_getdoc(x) t = 'Definition: ' + t0 + '\n\n' + t1 docs.add(obj) - s = s[:i_0 + i] + '\n' + t + s[i_0 + i + 6 + j:] + s = s[: i_0 + i] + '\n' + t + s[i_0 + i + 6 + j :] i_0 += i if 'nodetex' not in directives: @@ -851,10 +811,10 @@ def format_src(s): i = s.find("<<<") if i == -1: break - j = s[i + 3:].find('>>>') + j = s[i + 3 :].find('>>>') if j == -1: break - obj = s[i + 3:i + 3 + j] + obj = s[i + 3 : i + 3 + j] if obj in docs: t = '' else: @@ -864,15 +824,15 @@ def format_src(s): if t is None: print(x) t = '' - s = s[:i] + '\n' + t + s[i + 6 + j:] + s = s[:i] + '\n' + t + s[i + 6 + j :] return s ############################### -def _search_src_or_doc(what, string, extra1='', extra2='', extra3='', - extra4='', extra5='', **kwargs): + +def _search_src_or_doc(what, string, extra1='', extra2='', extra3='', extra4='', extra5='', **kwargs): r""" Search the Sage library or documentation for lines containing ``string`` and possibly some other terms. This function is used by @@ -1007,16 +967,12 @@ def _search_src_or_doc(what, string, extra1='', extra2='', extra3='', results.append(filename[strip:].lstrip("/") + '\n') else: with open(filename) as fobj: - match_list = [(lineno, line) - for lineno, line in enumerate(fobj) - if re.search(regexp, line, flags)] + match_list = [(lineno, line) for lineno, line in enumerate(fobj) if re.search(regexp, line, flags)] for extra in extra_regexps: if extra: - match_list = [s for s in match_list - if re.search(extra, s[1], re.MULTILINE | flags)] + match_list = [s for s in match_list if re.search(extra, s[1], re.MULTILINE | flags)] for num, line in match_list: - results.append('{}:{}:{}'.format( - filename[strip:].lstrip('/'), num + 1, line)) + results.append('{}:{}:{}'.format(filename[strip:].lstrip('/'), num + 1, line)) text_results = ''.join(results).rstrip() @@ -1028,19 +984,21 @@ def _search_src_or_doc(what, string, extra1='', extra2='', extra3='', # Pass through the IPython pager in a mime bundle from IPython.core.page import page + if not isinstance(text_results, str): text_results = text_results.decode('utf-8', 'replace') - page({ - 'text/plain': text_results, - # 'text/html': html_results - # don't return HTML results since they currently are not - # correctly formatted for Jupyter use - }) + page( + { + 'text/plain': text_results, + # 'text/html': html_results + # don't return HTML results since they currently are not + # correctly formatted for Jupyter use + } + ) -def search_src(string, extra1='', extra2='', extra3='', extra4='', - extra5='', **kwds): +def search_src(string, extra1='', extra2='', extra3='', extra4='', extra5='', **kwds): r""" Search Sage library source code for lines containing ``string``. The search is case-insensitive by default. @@ -1215,13 +1173,10 @@ def search_src(string, extra1='', extra2='', extra3='', extra4='', matrix/matrix0.pyx:924: Set the 2 x 2 submatrix of M, starting at row index and column matrix/matrix0.pyx:933: Set the 2 x 3 submatrix of M starting at row index and column """ - return _search_src_or_doc('src', string, extra1=extra1, extra2=extra2, - extra3=extra3, extra4=extra4, extra5=extra5, - **kwds) + return _search_src_or_doc('src', string, extra1=extra1, extra2=extra2, extra3=extra3, extra4=extra4, extra5=extra5, **kwds) -def search_doc(string, extra1='', extra2='', extra3='', extra4='', - extra5='', **kwds): +def search_doc(string, extra1='', extra2='', extra3='', extra4='', extra5='', **kwds): r""" Search Sage HTML documentation for lines containing ``string``. The search is case-insensitive by default. @@ -1258,13 +1213,10 @@ def search_doc(string, extra1='', extra2='', extra3='', extra4='', sage: all(tree_re.search(l) for l in L) True """ - return _search_src_or_doc('doc', string, extra1=extra1, extra2=extra2, - extra3=extra3, extra4=extra4, extra5=extra5, - **kwds) + return _search_src_or_doc('doc', string, extra1=extra1, extra2=extra2, extra3=extra3, extra4=extra4, extra5=extra5, **kwds) -def search_def(name, extra1='', extra2='', extra3='', extra4='', - extra5='', **kwds): +def search_def(name, extra1='', extra2='', extra3='', extra4='', extra5='', **kwds): r""" Search Sage library source code for function definitions containing ``name``. The search is case-insensitive by default. @@ -1308,9 +1260,7 @@ def search_def(name, extra1='', extra2='', extra3='', extra4='', extra5 = r'\b' + extra5 + r'\b' kwds['whole_word'] = False - return _search_src_or_doc('src', '^ *[c]?def.*%s' % name, extra1=extra1, - extra2=extra2, extra3=extra3, extra4=extra4, - extra5=extra5, **kwds) + return _search_src_or_doc('src', '^ *[c]?def.*%s' % name, extra1=extra1, extra2=extra2, extra3=extra3, extra4=extra4, extra5=extra5, **kwds) def format_search_as_html(what, results, search): @@ -1357,15 +1307,7 @@ def format_search_as_html(what, results, search): if not isinstance(search, list): search = [search] - s = [ - '', - '', - '

Search {}: {}

'.format( - what, ', '.join('"{}"'.format(s) for s in search if s.strip())), - '
', - '', - '
    ' - ] + s = ['', '', '

    Search {}: {}

    '.format(what, ', '.join('"{}"'.format(s) for s in search if s.strip())), '
    ', '', '
      '] append = s.append @@ -1457,6 +1399,7 @@ class _sage_doc: sage: browse_sage_doc(identity_matrix, 'rst')[-374:-215] # needs sage.modules '...Full MatrixSpace of 3 by 3 sparse matrices...' """ + def __init__(self): """ EXAMPLES:: @@ -1530,6 +1473,7 @@ def __call__(self, obj, output='html', view=True): from .sphinxify import sphinxify except ImportError: from html import escape + html = escape(s) else: html = sphinxify(s) @@ -1586,10 +1530,7 @@ def __call__(self, obj, output='html', view=True):
""" - html = template % {'html': html, - 'static_path': static_path, - 'title': title, - 'version': sage.version.version} + html = template % {'html': html, 'static_path': static_path, 'title': title, 'version': sage.version.version} filed.write(html) filed.close() @@ -1632,8 +1573,12 @@ def _open(self, name, testing=False): url = self._base_url + os.path.join(name, "index.html") path = os.path.join(self._base_path, name, "index.html") if not os.path.exists(path): - raise OSError("""The document '{0}' does not exist. Please build it -with 'sage -docbuild {0} html' and try again.""".format(name)) + raise OSError( + """The document '{0}' does not exist. Please build it +with 'sage -docbuild {0} html' and try again.""".format( + name + ) + ) if testing: return (url, path) @@ -1709,7 +1654,8 @@ def help(module=None): if module is not None: python_help(module) else: - print("""Welcome to Sage {}! + print( + """Welcome to Sage {}! To view the Sage tutorial in your web browser, type "tutorial()", and to view the (very detailed) Sage reference manual, type "manual()". @@ -1731,4 +1677,7 @@ def help(module=None): To enter Python's interactive online help utility, type "python_help()". To get help on a Python function, module or package, type "help(MODULE)" or -"python_help(MODULE)".""".format(sage.version.version)) +"python_help(MODULE)".""".format( + sage.version.version + ) + ) diff --git a/src/sage/misc/sagedoc_conf.py b/src/sage/misc/sagedoc_conf.py index e6f8fd9e3db..215f62c7f3e 100644 --- a/src/sage/misc/sagedoc_conf.py +++ b/src/sage/misc/sagedoc_conf.py @@ -132,6 +132,7 @@ def process_dollars(app, what, name, obj, options, docstringlines): """ if len(docstringlines) and name.find("process_dollars") == -1: from sage.misc.sagedoc import process_dollars as sagedoc_dollars + s = sagedoc_dollars("\n".join(docstringlines)) lines = s.split("\n") for i in range(len(lines)): @@ -169,6 +170,7 @@ def skip_TESTS_block(app, what, name, obj, options, docstringlines): See sage.misc.sagedoc.skip_TESTS_block for more information. """ from sage.misc.sagedoc import skip_TESTS_block as sagedoc_skip_TESTS + if not docstringlines: # No docstring, so don't do anything. See Issue #19932. return @@ -188,6 +190,7 @@ class SagemathTransform(Transform): associated with the pycon lexer, and in particular, to change "" to a blank line. """ + default_priority = 500 def apply(self): @@ -199,6 +202,7 @@ def apply(self): node.rawsource = source node[:] = [nodes.Text(source)] + # This is only used by sage.misc.sphinxify diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index c237af52c24..1886bb0735a 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -194,28 +194,34 @@ def isclassinstance(obj): """ builtin_mods = {'__builtin__', 'builtins', 'exceptions'} - return (not inspect.isclass(obj) and - hasattr(obj, '__class__') and - hasattr(obj.__class__, '__module__') and - obj.__class__.__module__ not in builtin_mods and - # Starting with Cython 3, Cython's builtin types have __module__ set - # to the shared module names like _cython_3_0_0. - not (isinstance(obj.__class__.__module__, str) and - obj.__class__.__module__.startswith('_cython_')) and - # In Cython 3.1, they have 'member_descriptor' type - 'cython_function_or_method' not in str(obj.__class__.__module__)) + return ( + not inspect.isclass(obj) + and hasattr(obj, '__class__') + and hasattr(obj.__class__, '__module__') + and obj.__class__.__module__ not in builtin_mods + and + # Starting with Cython 3, Cython's builtin types have __module__ set + # to the shared module names like _cython_3_0_0. + not (isinstance(obj.__class__.__module__, str) and obj.__class__.__module__.startswith('_cython_')) + and + # In Cython 3.1, they have 'member_descriptor' type + 'cython_function_or_method' not in str(obj.__class__.__module__) + ) # Parse strings of form "File: sage/rings/rational.pyx (starting at line 1080)" # "\ " protects a space in re.VERBOSE mode. -__embedded_position_re = re.compile(r''' +__embedded_position_re = re.compile( + r''' ^ # anchor to the beginning of the line File:\ (?P.*?) # match File: then filename \ \(starting\ at\ line\ (?P\d+)\) # match line number \n? # if there is a newline, eat it (?P.*) # the original docstring is the end \Z # anchor to the end of the string -''', re.MULTILINE | re.DOTALL | re.VERBOSE) +''', + re.MULTILINE | re.DOTALL | re.VERBOSE, +) # Parse Python identifiers __identifier_re = re.compile(r"^[^\d\W]\w*") @@ -277,17 +283,16 @@ def _extract_embedded_position(docstring): # 1) Module in the sage src tree # 2) Module compiled by Sage's inline cython() compiler from sage.misc.temporary_file import spyx_tmp + if raw_filename.startswith('sage/'): import sage from sage.env import SAGE_SRC - try_filenames = [os.path.join(directory, raw_filename.removeprefix('sage/')) - for directory in sage.__path__] + + try_filenames = [os.path.join(directory, raw_filename.removeprefix('sage/')) for directory in sage.__path__] try_filenames.append(os.path.join(SAGE_SRC, raw_filename)) # meson editable install else: try_filenames = [] - try_filenames.append( - os.path.join(spyx_tmp(), '_'.join(raw_filename.split('_')[:-1]), - raw_filename)) + try_filenames.append(os.path.join(spyx_tmp(), '_'.join(raw_filename.split('_')[:-1]), raw_filename)) for try_filename in try_filenames: if os.path.exists(try_filename): filename = try_filename @@ -349,6 +354,7 @@ class BlockFinder: This is the Python library's :class:`inspect.BlockFinder` modified to recognize Cython definitions. """ + def __init__(self): self.indent = 0 self.islambda = False @@ -365,11 +371,11 @@ def tokeneater(self, type, token, srow_scol, erow_ecol, line): if token == "lambda": self.islambda = True self.started = True - self.passline = True # skip to the end of the line + self.passline = True # skip to the end of the line elif type == tokenize.NEWLINE: - self.passline = False # stop skipping when a NEWLINE is seen + self.passline = False # stop skipping when a NEWLINE is seen self.last = srow - if self.islambda: # lambdas always end at the first NEWLINE + if self.islambda: # lambdas always end at the first NEWLINE raise inspect.EndOfBlock elif self.passline: pass @@ -402,12 +408,13 @@ def _getblock(lines): def readline(): return next(iter_lines).encode('utf-8') + try: for tok in tokenizer(readline): blockfinder.tokeneater(*tok) except (inspect.EndOfBlock, IndentationError): pass - return lines[:blockfinder.last] + return lines[: blockfinder.last] def _extract_source(lines, lineno): @@ -470,6 +477,7 @@ class SageArgSpecVisitor(ast.NodeVisitor): sage: visitor.visit(v.value) ['veni', 'vidi', 'vici'] """ + def visit_Name(self, node): """ Visit a Python AST :class:`ast.Name` node. @@ -898,37 +906,38 @@ def split_string(s, quot): if s[i] == '\\': escaped = not escaped continue - if not escaped and s[i:i + l] == quot: - return s[:i], s[i + l:] + if not escaped and s[i : i + l] == quot: + return s[:i], s[i + l :] escaped = False raise SyntaxError("EOF while scanning string literal") + # 1. s is a triple-quoted string if s.startswith('"""'): a, b = split_string(s[3:], '"""') return '"""' + a + '"""', b.strip() if s.startswith('r"""'): a, b = split_string(s[4:], '"""') - return 'r"""'+a+'"""', b.strip() + return 'r"""' + a + '"""', b.strip() if s.startswith("'''"): a, b = split_string(s[3:], "'''") - return "'''"+a+"'''", b.strip() + return "'''" + a + "'''", b.strip() if s.startswith("r'''"): a, b = split_string(s[4:], "'''") - return "r'''"+a+"'''", b.strip() + return "r'''" + a + "'''", b.strip() # 2. s is a single-quoted string if s.startswith('"'): a, b = split_string(s[1:], '"') - return '"'+a+'"', b.strip() + return '"' + a + '"', b.strip() if s.startswith("'"): a, b = split_string(s[1:], "'") - return "'"+a+"'", b.strip() + return "'" + a + "'", b.strip() if s.startswith('r"'): a, b = split_string(s[2:], '"') - return 'r"'+a+'"', b.strip() + return 'r"' + a + '"', b.strip() if s.startswith("r'"): a, b = split_string(s[2:], "'") - return "r'"+a+"'", b.strip() + return "r'" + a + "'", b.strip() # 3. s is not a string start = s[0] @@ -954,7 +963,7 @@ def split_string(s, quot): M = __identifier_re.search(s) if M is None: return s[0], s[1:].strip() - return M.group(), s[M.end():].strip() + return M.group(), s[M.end() :].strip() s = s[1:] while s: @@ -1009,9 +1018,7 @@ def _sage_getargspec_from_ast(source): vararg = getattr(ast_args.vararg, 'arg', None) kwarg = getattr(ast_args.kwarg, 'arg', None) - return inspect.FullArgSpec(args, vararg, kwarg, - tuple(defaults) if defaults else None, - kwonlyargs=[], kwonlydefaults=None, annotations={}) + return inspect.FullArgSpec(args, vararg, kwarg, tuple(defaults) if defaults else None, kwonlyargs=[], kwonlydefaults=None, annotations={}) def _sage_getargspec_cython(source): @@ -1130,7 +1137,7 @@ def _sage_getargspec_cython(source): nb_stars = 0 varargs = None keywords = None - while (i < l): + while i < l: unit = cy_units[i] if expect_default: if unit in ('=', '*', ','): @@ -1213,8 +1220,7 @@ def _sage_getargspec_cython(source): keywords = ',**' + keywords else: keywords = '**' + keywords - return _sage_getargspec_from_ast('def dummy(' + ''.join(py_units) + - varargs + keywords + '): pass') + return _sage_getargspec_from_ast('def dummy(' + ''.join(py_units) + varargs + keywords + '): pass') def sage_getfile(obj): @@ -1307,7 +1313,7 @@ def sage_getfile(obj): # but as long as either the class or its __init__ method has a # docstring, _sage_getdoc_unformatted should return correct result # see https://github.com/mesonbuild/meson-python/issues/723 - return sourcefile.removesuffix(suffix)+os.path.extsep+'pyx' + return sourcefile.removesuffix(suffix) + os.path.extsep + 'pyx' return sourcefile @@ -1351,6 +1357,7 @@ def directories(): if SAGE_SRC: yield normpath(os.path.join(SAGE_SRC, 'sage')) import sage + yield from sage.__path__ for directory in directories(): @@ -1563,6 +1570,7 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return """ from sage.misc.abstract_method import AbstractMethod from sage.misc.lazy_attribute import lazy_attribute + if inspect.isclass(obj): return sage_getargspec(obj.__call__) if isinstance(obj, (lazy_attribute, AbstractMethod)): @@ -1587,8 +1595,7 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return # Note that this may give a wrong result for the constants! try: args, varargs, varkw = inspect.getargs(obj.__code__) - return inspect.FullArgSpec(args, varargs, varkw, obj.__defaults__, - kwonlyargs=[], kwonlydefaults=None, annotations={}) + return inspect.FullArgSpec(args, varargs, varkw, obj.__defaults__, kwonlyargs=[], kwonlydefaults=None, annotations={}) except (TypeError, AttributeError): pass if isclassinstance(obj): @@ -1597,8 +1604,7 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return try: # we try to find the definition and parse it by # _sage_getargspec_ast - proxy = 'def dummy' + _grep_first_pair_of_parentheses(source) \ - + ':\n return' + proxy = 'def dummy' + _grep_first_pair_of_parentheses(source) + ':\n return' return _sage_getargspec_from_ast(proxy) except SyntaxError: # To fix trac #10860. See #11913 for more information. @@ -1608,8 +1614,7 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return base_spec = sage_getargspec(obj.func) return base_spec return sage_getargspec(obj.__class__.__call__) - if (hasattr(obj, '__objclass__') and hasattr(obj, '__name__') and - obj.__name__ == 'next'): + if hasattr(obj, '__objclass__') and hasattr(obj, '__name__') and obj.__name__ == 'next': # Handle sage.rings.ring.FiniteFieldIterator.next and similar # slot wrappers. This is mainly to suppress Sphinx warnings. return ['self'], None, None, None @@ -1647,8 +1652,7 @@ def foo(x, a='\')"', b={not (2+1==3):'bar'}): return defaults = func_obj.__defaults__ except AttributeError: defaults = None - return inspect.FullArgSpec(args, varargs, varkw, defaults, - kwonlyargs=[], kwonlydefaults=None, annotations={}) + return inspect.FullArgSpec(args, varargs, varkw, defaults, kwonlyargs=[], kwonlydefaults=None, annotations={}) def _fullargspec_to_signature(fullargspec): @@ -1718,8 +1722,7 @@ def _fullargspec_to_signature(fullargspec): parameters.append(param) for arg in fullargspec.kwonlyargs: - param = Parameter(arg, Parameter.KEYWORD_ONLY, default=Parameter.empty if fullargspec.kwonlydefaults is None else - fullargspec.kwonlydefaults.get(arg, Parameter.empty)) + param = Parameter(arg, Parameter.KEYWORD_ONLY, default=Parameter.empty if fullargspec.kwonlydefaults is None else fullargspec.kwonlydefaults.get(arg, Parameter.empty)) parameters.append(param) return Signature(parameters) @@ -1843,14 +1846,7 @@ def formatannotation(annotation, base_module=None): _formatannotation = formatannotation -def sage_formatargspec(args, varargs=None, varkw=None, defaults=None, - kwonlyargs=(), kwonlydefaults=None, annotations={}, - formatarg=str, - formatvarargs=None, - formatvarkw=None, - formatvalue=None, - formatreturns=None, - formatannotation=None): +def sage_formatargspec(args, varargs=None, varkw=None, defaults=None, kwonlyargs=(), kwonlydefaults=None, annotations={}, formatarg=str, formatvarargs=None, formatvarkw=None, formatvalue=None, formatreturns=None, formatannotation=None): """ Format an argument spec from the values returned by getfullargspec. @@ -1895,6 +1891,7 @@ def formatargandannotation(arg): if arg in annotations: result += ': ' + formatannotation(annotations[arg]) return result + specs = [] if defaults: firstdefault = len(args) - len(defaults) @@ -2152,6 +2149,7 @@ def sage_getdoc(obj, obj_name='', embedded=False): ...documentation of my class... """ import sage.misc.sagedoc + if obj is None: return '' r = sage_getdoc_original(obj) @@ -2159,10 +2157,13 @@ def sage_getdoc(obj, obj_name='', embedded=False): f = sage_getfile(obj) if f and os.path.exists(f): from sage.doctest.control import skipfile + skip = skipfile(f) if isinstance(skip, str): warn = """WARNING: the enclosing module is marked '{}', -so doctests may not pass.""".format(skip) +so doctests may not pass.""".format( + skip + ) s = warn + "\n\n" + s # Fix object naming @@ -2259,7 +2260,7 @@ class ParentMethods: splitted_name = obj.__qualname__.split('.') else: splitted_name = obj.__name__ - path = obj.__module__.split('.')+splitted_name[:-1] + path = obj.__module__.split('.') + splitted_name[:-1] name = splitted_name[-1] try: M = __import__(path.pop(0)) @@ -2305,14 +2306,14 @@ class ParentMethods: if match: # if it's at toplevel, it's already the best one if lines[i][0] == 'c': - return inspect.getblock(lines[i:]), i+base_lineno + return inspect.getblock(lines[i:]), i + base_lineno # else add whitespace to candidate list candidates.append((match.group(1), i)) if candidates: # this will sort by whitespace, and by line number, # less whitespace first candidates.sort() - return inspect.getblock(lines[candidates[0][1]:]), candidates[0][1]+base_lineno + return inspect.getblock(lines[candidates[0][1] :]), candidates[0][1] + base_lineno raise OSError('could not find class definition') if inspect.ismethod(obj): @@ -2336,7 +2337,7 @@ class ParentMethods: break lnum -= 1 - return inspect.getblock(lines[lnum:]), lnum+base_lineno + return inspect.getblock(lines[lnum:]), lnum + base_lineno raise OSError('could not find code object') @@ -2485,8 +2486,7 @@ class Element: # First, we deal with nested classes. Their name contains a dot, and we # have a special function for that purpose. # This is the case for ParentMethods of categories, for example. - if (inspect.isclass(obj) and - ('.' in obj.__name__ or '.' in getattr(obj, '__qualname__', ''))): + if inspect.isclass(obj) and ('.' in obj.__name__ or '.' in getattr(obj, '__qualname__', '')): return _sage_getsourcelines_name_with_dot(obj) # Next, we try _sage_getdoc_unformatted() @@ -2518,6 +2518,7 @@ class Element: except OSError: try: from sage.misc.temporary_file import spyx_tmp + raw_name = filename.split('/')[-1] newname = os.path.join(spyx_tmp(), '_'.join(raw_name.split('_')[:-1]), raw_name) with open(newname) as f: @@ -2528,13 +2529,13 @@ class Element: # It is possible that the source lines belong to the __init__ method, # rather than to the class. So, we try to look back and find the class # definition. - first_line = source_lines[lineno-1] - leading_blanks = len(first_line)-len(first_line.lstrip()) + first_line = source_lines[lineno - 1] + leading_blanks = len(first_line) - len(first_line.lstrip()) if first_line.lstrip().startswith('def ') and "__init__" in first_line and obj.__name__ != '__init__': ignore = False double_quote = None for lnb in range(lineno, 0, -1): - new_first_line = source_lines[lnb-1] + new_first_line = source_lines[lnb - 1] nfl_strip = new_first_line.lstrip() if nfl_strip.startswith('"""'): if double_quote is None: @@ -2548,7 +2549,7 @@ class Element: ignore = not ignore if ignore: continue - if len(new_first_line)-len(nfl_strip) < leading_blanks and nfl_strip: + if len(new_first_line) - len(nfl_strip) < leading_blanks and nfl_strip: # We are not inside a doc string. So, if the indentation # is less than the indentation of the __init__ method # then we must be at the class definition! diff --git a/src/sage/misc/sh.py b/src/sage/misc/sh.py index 968cb48cb74..2d29966b7af 100644 --- a/src/sage/misc/sh.py +++ b/src/sage/misc/sh.py @@ -12,6 +12,7 @@ class Sh: temporary) directory where the Sage worksheet process is executing. """ + def eval(self, code, globals=None, locals=None): r""" This is difficult to test because the output goes to the diff --git a/src/sage/misc/sphinxify.py b/src/sage/misc/sphinxify.py index 3bd0b12b367..f01ed3fd4a3 100644 --- a/src/sage/misc/sphinxify.py +++ b/src/sage/misc/sphinxify.py @@ -84,7 +84,8 @@ def sphinxify(docstring, format='html'): confdir = os.path.join(srcdir, 'en', 'introspect') os.makedirs(confdir) with open(os.path.join(confdir, 'conf.py'), 'w') as filed: - filed.write(r""" + filed.write( + r""" from sage.misc.sagedoc_conf import * extensions = ['sphinx.ext.autodoc', 'sphinx.ext.mathjax', 'sphinx.ext.todo', 'sphinx.ext.extlinks'] @@ -96,29 +97,33 @@ def sphinxify(docstring, format='html'): html_split_index = False html_copy_source = False -todo_include_todos = True""") +todo_include_todos = True""" + ) templatesdir = os.path.join(confdir, 'templates') os.makedirs(templatesdir) with open(os.path.join(templatesdir, 'layout.html'), 'w') as filed: - filed.write(r"""
+ filed.write( + r"""
{% block body %} {% endblock %} -
""") +
""" + ) staticdir = os.path.join(confdir, 'static') os.makedirs(staticdir) with open(os.path.join(staticdir, 'empty'), 'w') as filed: pass with open(os.path.join(srcdir, 'docutils.conf'), 'w') as filed: - filed.write(r""" + filed.write( + r""" [parsers] -smart_quotes = no""") +smart_quotes = no""" + ) doctreedir = os.path.join(srcdir, 'doctrees') confoverrides = {'html_context': {}, 'master_doc': 'docstring'} old_sys_path = list(sys.path) # Sphinx modifies sys.path # Sphinx constructor: Sphinx(srcdir, confdir, outdir, doctreedir, # buildername, confoverrides, status, warning, freshenv). - sphinx_app = Sphinx(srcdir, confdir, outdir, doctreedir, format, - confoverrides, None, None, True) + sphinx_app = Sphinx(srcdir, confdir, outdir, doctreedir, format, confoverrides, None, None, True) sphinx_app.build(None, [rst_name]) sys.path = old_sys_path @@ -136,13 +141,12 @@ def sphinxify(docstring, format='html'): # "/media/...path.../blah.png" # to # "/doc/static/reference/media/...path.../blah.png" - output = re.sub(r"""src=['"](/?\.\.)*/?media/([^"']*)['"]""", - 'src="/doc/static/reference/media/\\2"', - output) + output = re.sub(r"""src=['"](/?\.\.)*/?media/([^"']*)['"]""", 'src="/doc/static/reference/media/\\2"', output) # Remove spurious \(, \), \[, \]. output = output.replace(r'\(', '').replace(r'\)', '').replace(r'\[', '').replace(r'\]', '') else: from warnings import warn + warn("Sphinx did not produce any output", Warning) if format == 'html': output = '
%s
' % docstring @@ -159,8 +163,10 @@ def sphinxify(docstring, format='html'): if len(sys.argv) == 2: print(sphinxify(sys.argv[1])) else: - print("""Usage: + print( + """Usage: %s 'docstring' docstring -- docstring to be processed -""") +""" + ) diff --git a/src/sage/misc/superseded.py b/src/sage/misc/superseded.py index 957150bc1c7..a40bba510f7 100644 --- a/src/sage/misc/superseded.py +++ b/src/sage/misc/superseded.py @@ -13,7 +13,6 @@ --------------------- """ - ######################################################################## # Copyright (C) 2012 William Stein # @@ -305,14 +304,10 @@ def __call__(self, func): @sage_wraps(func) def wrapper(*args, **kwds): if not wrapper._already_issued: - experimental_warning(self.issue_number, - 'This class/method/function is marked as ' - 'experimental. It, its functionality or its ' - 'interface might change without a ' - 'formal deprecation.', - self.stacklevel) + experimental_warning(self.issue_number, 'This class/method/function is marked as ' 'experimental. It, its functionality or its ' 'interface might change without a ' 'formal deprecation.', self.stacklevel) wrapper._already_issued = True return func(*args, **kwds) + wrapper._already_issued = False return wrapper @@ -334,6 +329,7 @@ class __experimental_self_test: sage: _ = __experimental_self_test("B") I'm B """ + @experimental(issue_number=88888) def __init__(self, x): print("I'm " + x) @@ -349,6 +345,7 @@ class DeprecatedFunctionAlias: - Florent Hivert (2009-11-23), with the help of Mike Hansen. - Luca De Feo (2011-07-11), printing the full module path when different from old path """ + def __init__(self, issue_number, func, module, instance=None, unbound=None, *, replacement=None, replacement_rst_doc=None): r""" TESTS:: @@ -418,6 +415,7 @@ def __name__(self): # then search object that contains self as method import gc import copy + gc.collect() def is_class(gc_ref): @@ -426,6 +424,7 @@ def is_class(gc_ref): is_python_class = '__module__' in gc_ref or '__package__' in gc_ref is_cython_class = '__new__' in gc_ref return is_python_class or is_cython_class + search_for = self if (self.unbound is None) else self.unbound for ref in gc.get_referrers(search_for): if is_class(ref) and ref is not self.__dict__: @@ -459,8 +458,7 @@ def __call__(self, *args, **kwds): else: replacement = self.func.__name__ - deprecation(self.issue_number, - f"{self.__name__} is deprecated. Please use {replacement} instead.") + deprecation(self.issue_number, f"{self.__name__} is deprecated. Please use {replacement} instead.") if self.instance is None: return self.func(*args, **kwds) return self.func(self.instance, *args, **kwds) @@ -498,9 +496,7 @@ def __get__(self, inst, cls=None): if inst is None: return self # Unbound method lookup on class # Return a bound method wrapper - return DeprecatedFunctionAlias(self.issue_number, self.func, - self.__module__, instance=inst, - unbound=self) + return DeprecatedFunctionAlias(self.issue_number, self.func, self.__module__, instance=inst, unbound=self) def deprecated_function_alias(issue_number, func, *, replacement=None, replacement_rst_doc=None): @@ -569,5 +565,4 @@ def deprecated_function_alias(issue_number, func, *, replacement=None, replaceme module_name = inspect.getmodulename(frame1.f_code.co_filename) if module_name is None: module_name = '__main__' - return DeprecatedFunctionAlias(issue_number, func, module_name, - replacement=replacement, replacement_rst_doc=replacement_rst_doc) + return DeprecatedFunctionAlias(issue_number, func, module_name, replacement=replacement, replacement_rst_doc=replacement_rst_doc) diff --git a/src/sage/misc/table.py b/src/sage/misc/table.py index 4dd735fc729..1d52ed1bdfb 100644 --- a/src/sage/misc/table.py +++ b/src/sage/misc/table.py @@ -246,8 +246,8 @@ class table(SageObject): .. automethod:: _rich_repr_ """ - def __init__(self, rows=None, columns=None, header_row=False, - header_column=False, frame=False, align='left'): + + def __init__(self, rows=None, columns=None, header_row=False, header_column=False, frame=False, align='left'): r""" EXAMPLES:: @@ -305,7 +305,7 @@ def __eq__(self, other): sage: T == T2 False """ - return (self._rows == other._rows and self.options() == other.options()) + return self._rows == other._rows and self.options() == other.options() def options(self, **kwds): r""" @@ -405,11 +405,7 @@ def transpose(self): │ z ║ 3 │ 6 │ └───╨───┴───┘ """ - return table(list(zip(*self._rows)), - header_row=self._options['header_column'], - header_column=self._options['header_row'], - frame=self._options['frame'], - align=self._options['align']) + return table(list(zip(*self._rows)), header_row=self._options['header_column'], header_column=self._options['header_row'], frame=self._options['frame'], align=self._options['align']) @cached_method def _widths(self): @@ -427,7 +423,7 @@ def _widths(self): widths = [0] * nc for row in self._rows: w = [] - for (idx, x) in zip(range(nc), row): + for idx, x in zip(range(nc), row): w.append(max(widths[idx], len(str(x)))) widths = w return tuple(widths) @@ -608,7 +604,7 @@ def _latex_(self): if len(rows) == 0 or nc == 0: return "" - align_char = self._options['align'][0] # 'l', 'c', 'r' + align_char = self._options['align'][0] # 'l', 'c', 'r' if self._options['frame']: frame_char = '|' frame_str = ' \\hline' @@ -630,13 +626,11 @@ def _latex_(self): s += frame_char.join([align_char] * (nc - 1)) s += frame_char + "}" + frame_str + "\n" # first row - s += " & ".join(LatexExpr(x) if isinstance(x, (str, LatexExpr)) - else '$' + latex(x).strip() + '$' for x in rows[0]) + s += " & ".join(LatexExpr(x) if isinstance(x, (str, LatexExpr)) else '$' + latex(x).strip() + '$' for x in rows[0]) s += " \\\\" + frame_str + head_row_str + "\n" # other rows for row in rows[1:]: - s += " & ".join(LatexExpr(x) if isinstance(x, (str, LatexExpr)) - else '$' + latex(x).strip() + '$' for x in row) + s += " & ".join(LatexExpr(x) if isinstance(x, (str, LatexExpr)) else '$' + latex(x).strip() + '$' for x in row) s += " \\\\" + frame_str + "\n" s += "\\end{tabular}" return s @@ -735,6 +729,7 @@ def _html_(self):
""" from itertools import cycle + rows = self._rows header_row = self._options['header_row'] if self._options['frame']: @@ -743,12 +738,14 @@ def _html_(self): frame = '' s = StringIO() if rows: - s.writelines([ - # If the table has < 100 rows, don't truncate the output in the notebook - '
\n' if len(rows) <= 100 else '
', - '\n'.format(frame), - '\n', - ]) + s.writelines( + [ + # If the table has < 100 rows, don't truncate the output in the notebook + '
\n' if len(rows) <= 100 else '
', + '
\n'.format(frame), + '\n', + ] + ) # First row: if header_row: s.write('\n') @@ -813,7 +810,7 @@ def _html_table_row(self, file, row, header=False): elif not isinstance(row, (list, tuple)): row = [row] - align_char = self._options['align'][0] # 'l', 'c', 'r' + align_char = self._options['align'][0] # 'l', 'c', 'r' if align_char == 'l': style = 'text-align:left' diff --git a/src/sage/misc/temporary_file.py b/src/sage/misc/temporary_file.py index 41492c44f15..a05a018c693 100644 --- a/src/sage/misc/temporary_file.py +++ b/src/sage/misc/temporary_file.py @@ -12,6 +12,7 @@ - Sebastian Oehms (2021-08-07): add :class:`atomic_dir`, see :issue:`32344` """ + # **************************************************************************** # Copyright (C) 2012 Volker Braun # Copyright (C) 2012 Jeroen Demeyer @@ -41,6 +42,7 @@ # temporary directory ################################################################# + def tmp_dir(name='dir_', ext='') -> str: r""" Create and return a temporary directory in @@ -73,9 +75,7 @@ def tmp_dir(name='dir_', ext='') -> str: 0 sage: f.close() """ - tmp = tempfile.mkdtemp(prefix=name, - suffix=ext, - dir=TMP_DIR_FILENAME_BASE.name) + tmp = tempfile.mkdtemp(prefix=name, suffix=ext, dir=TMP_DIR_FILENAME_BASE.name) name = os.path.abspath(tmp) return name + os.sep @@ -84,6 +84,7 @@ def tmp_dir(name='dir_', ext='') -> str: # temporary filename ################################################################# + def tmp_filename(name='tmp_', ext='') -> str: r""" Create and return a temporary file in @@ -122,9 +123,7 @@ def tmp_filename(name='tmp_', ext='') -> str: 0 sage: f.close() """ - handle, tmp = tempfile.mkstemp(prefix=name, - suffix=ext, - dir=TMP_DIR_FILENAME_BASE.name) + handle, tmp = tempfile.mkstemp(prefix=name, suffix=ext, dir=TMP_DIR_FILENAME_BASE.name) os.close(handle) name = os.path.abspath(tmp) return name @@ -298,8 +297,8 @@ class atomic_write: sage: os.path.exists(writer.tempname) False """ - def __init__(self, target_filename, append=False, mode=0o666, - binary=False, **kwargs) -> None: + + def __init__(self, target_filename, append=False, mode=0o666, binary=False, **kwargs) -> None: """ TESTS:: @@ -408,6 +407,7 @@ def __exit__(self, exc_type, exc_val, exc_tb) -> None: # Failure: delete temporary file os.unlink(self.tempname) + ################################################################# # write to a temporary directory and move it in place ################################################################# @@ -455,6 +455,7 @@ class atomic_dir: ....: h.read() 'Second' """ + def __init__(self, target_directory) -> None: r""" TESTS:: @@ -511,6 +512,7 @@ def __exit__(self, exc_type, exc_val, exc_tb) -> None: False """ import shutil + if exc_type is None: # Success: move temporary file to target file try: diff --git a/src/sage/misc/test_class_pickling.py b/src/sage/misc/test_class_pickling.py index ed2eb62a540..21f52327e9a 100644 --- a/src/sage/misc/test_class_pickling.py +++ b/src/sage/misc/test_class_pickling.py @@ -1,4 +1,3 @@ - import copyreg @@ -58,6 +57,7 @@ class Metaclass(type): calling __eq__ defined in Metaclass True """ + def __eq__(self, other): print("calling __eq__ defined in Metaclass") return (type(self) is type(other)) and (self.reduce_args == other.reduce_args) diff --git a/src/sage/misc/test_nested_class.py b/src/sage/misc/test_nested_class.py index e7791f95a3a..09f29219140 100644 --- a/src/sage/misc/test_nested_class.py +++ b/src/sage/misc/test_nested_class.py @@ -37,6 +37,7 @@ sage: P = TestParent4() sage: TestSuite(P).run() """ + # ***************************************************************************** # Copyright (C) 2009 Nicolas M. Thiery # @@ -62,6 +63,7 @@ def __init__(self): """ from sage.categories.sets_cat import Sets + Parent.__init__(self, category=Sets()) class Element(ElementWrapper): @@ -79,6 +81,7 @@ def __init__(self): TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases """ from sage.categories.sets_cat import Sets + Parent.__init__(self, category=Sets()) class Element(ElementWrapper): @@ -95,6 +98,7 @@ def __init__(self): """ from sage.categories.sets_cat import Sets + Parent.__init__(self, category=Sets()) class Element(ElementWrapper): @@ -110,6 +114,7 @@ def __init__(self): """ from sage.categories.sets_cat import Sets + Parent.__init__(self, category=Sets()) def __eq__(self, other): @@ -153,6 +158,7 @@ class B: """ A normal external class. """ + pass @@ -162,6 +168,7 @@ class B: This class is broken and cannot be pickled. A warning is emitted during compilation. """ + pass @@ -169,6 +176,7 @@ class ABL: """ There is no problem here. """ + B = B @@ -176,6 +184,7 @@ class ALB: """ There is a nested class just below. Which can't be properly sphinxed. """ + class C: """ Internal C class. @@ -183,6 +192,7 @@ class C: Thanks to the links below this class is pickled ok. But it is sphinxed wrong: It is typeset as a link to an outer class. """ + pass @@ -194,6 +204,7 @@ class B: """ B interne """ + pass @@ -205,10 +216,12 @@ class ALBMeta(metaclass=NestedClassMetaclass): """ There is a nested class just below which is properly sphinxed. """ + class CMeta: """ B interne """ + pass diff --git a/src/sage/misc/timing.py b/src/sage/misc/timing.py index a99edd4c4e6..ebe9357db73 100644 --- a/src/sage/misc/timing.py +++ b/src/sage/misc/timing.py @@ -34,9 +34,7 @@ def cputime(t: float = 0, subprocesses: bool = False) -> float: ... def cputime(t: GlobalCputime, subprocesses: bool) -> GlobalCputime: ... -def cputime( - t: float | GlobalCputime = 0, subprocesses: bool = False -) -> float | GlobalCputime: +def cputime(t: float | GlobalCputime = 0, subprocesses: bool = False) -> float | GlobalCputime: """ Return the time in CPU seconds since Sage started, or with optional argument ``t``, return the time since ``t``. This is how diff --git a/src/sage/misc/trace.py b/src/sage/misc/trace.py index 927915a4ba5..5427f14e911 100644 --- a/src/sage/misc/trace.py +++ b/src/sage/misc/trace.py @@ -73,6 +73,7 @@ def trace(code, preparse=True): sage: gc.enable() """ from IPython.core.debugger import Pdb + pdb = Pdb() try: @@ -81,6 +82,7 @@ def trace(code, preparse=True): raise NotImplementedError("the trace command can only be run from the Sage command-line") from sage.repl.preparse import preparse + code = preparse(code) return pdb.run(code, ipython.user_ns) diff --git a/src/sage/misc/unknown.py b/src/sage/misc/unknown.py index 57e84e73e50..1225e12bfa2 100644 --- a/src/sage/misc/unknown.py +++ b/src/sage/misc/unknown.py @@ -68,6 +68,7 @@ - Florent Hivert (2010): initial version. - Ralf Stephan, Vincent Delecroix (2018-2020): redesign """ + # **************************************************************************** # Copyright (C) 2010 Florent Hivert # 2018-2020 Ralf Stefan @@ -95,6 +96,7 @@ class UnknownError(TypeError): ... UnknownError: Unknown does not evaluate in boolean context """ + pass @@ -119,6 +121,7 @@ class UnknownClass(UniqueRepresentation): sage: TestSuite(Unknown).run() """ + def __repr__(self): """ TESTS:: diff --git a/src/sage/misc/verbose.py b/src/sage/misc/verbose.py index cfc38266525..527a36d6244 100644 --- a/src/sage/misc/verbose.py +++ b/src/sage/misc/verbose.py @@ -89,6 +89,7 @@ Functions ========= """ + # ***************************************************************************** # Copyright (C) 2006, 2007 William Stein # Copyright (C) 2006 Gonzalo Tornaria @@ -142,6 +143,7 @@ def verbose(mesg='', t=0, level=1, caller_name=None): sage: set_verbose(0) """ from sage.misc.timing import cputime + if level > LEVEL: return cputime() @@ -172,8 +174,7 @@ def verbose(mesg='', t=0, level=1, caller_name=None): if '<' in short_file_name and '>' in short_file_name: s = "verbose %s (%s) %s" % (level, caller_name, mesg) else: - s = "verbose %s (%s: %s, %s) %s" % (level, lineno, - short_file_name, caller_name, mesg) + s = "verbose %s (%s: %s, %s) %s" % (level, lineno, short_file_name, caller_name, mesg) if t != 0: s = s + " (time = %s)" % cputime(t) print(s) diff --git a/src/sage/misc/viewer.py b/src/sage/misc/viewer.py index 83383a7bdb9..8a3f0c7e04e 100644 --- a/src/sage/misc/viewer.py +++ b/src/sage/misc/viewer.py @@ -150,6 +150,7 @@ class Viewer(SageObject): 'open -a /Applications/Firefox.app' sage: viewer.browser(old_browser) # restore old value """ + def _set(self, app=None, TYPE='browser'): r""" Change the default viewer. Return the current setting if the diff --git a/src/sage/modular/abvar/abvar.py b/src/sage/modular/abvar/abvar.py index c1f9775a779..b8fc779e7bf 100644 --- a/src/sage/modular/abvar/abvar.py +++ b/src/sage/modular/abvar/abvar.py @@ -64,23 +64,19 @@ from sage.structure.richcmp import richcmp_method, richcmp_not_equal, rich_to_bool from sage.structure.sequence import Sequence, Sequence_generic -lazy_import('sage.databases.cremona', - ['cremona_letter_code', 'CremonaDatabase']) +lazy_import('sage.databases.cremona', ['cremona_letter_code', 'CremonaDatabase']) from sage.modular.abvar import homspace, lseries from .morphism import HeckeOperator, Morphism, DegeneracyMap from .torsion_subgroup import RationalTorsionSubgroup, QQbarTorsionSubgroup -from .finite_subgroup import (FiniteSubgroup_lattice, FiniteSubgroup, - TorsionPoint) -from .cuspidal_subgroup import (CuspidalSubgroup, RationalCuspidalSubgroup, - RationalCuspSubgroup) +from .finite_subgroup import FiniteSubgroup_lattice, FiniteSubgroup, TorsionPoint +from .cuspidal_subgroup import CuspidalSubgroup, RationalCuspidalSubgroup, RationalCuspSubgroup @richcmp_method class ModularAbelianVariety_abstract(Parent): - def __init__(self, groups, base_field, is_simple=None, newform_level=None, - isogeny_number=None, number=None, check=True): + def __init__(self, groups, base_field, is_simple=None, newform_level=None, isogeny_number=None, number=None, check=True): """ Abstract base class for modular abelian varieties. @@ -143,8 +139,7 @@ def __init__(self, groups, base_field, is_simple=None, newform_level=None, self.__isogeny_number = isogeny_number if check and base_field not in Fields(): raise TypeError("base_field must be a field") - Parent.__init__(self, base=base_field, - category=ModularAbelianVarieties(base_field)) + Parent.__init__(self, base=base_field, category=ModularAbelianVarieties(base_field)) def groups(self): r""" @@ -184,8 +179,7 @@ def is_J0(self) -> bool: sage: (J0(23) * J0(21)).is_J0() False """ - return len(self.groups()) == 1 and isinstance(self.groups()[0], Gamma0_class) \ - and self.is_ambient() + return len(self.groups()) == 1 and isinstance(self.groups()[0], Gamma0_class) and self.is_ambient() def is_J1(self) -> bool: """ @@ -206,8 +200,7 @@ def is_J1(self) -> bool: sage: J1(23)[0].is_J1() False """ - return len(self.groups()) == 1 and isinstance(self.groups()[0], Gamma1_class) \ - and self.is_ambient() + return len(self.groups()) == 1 and isinstance(self.groups()[0], Gamma1_class) and self.is_ambient() ########################################################################## # lattice() *must* be defined by every derived class!!!! @@ -227,6 +220,7 @@ def lattice(self): ) failed: NotImplementedError: BUG -- lattice method must be defined in derived class> """ raise NotImplementedError("BUG -- lattice method must be defined in derived class") + ########################################################################### def free_module(self): @@ -436,8 +430,7 @@ def _repr_(self) -> str: sub = 'subvariety' else: sub = 'variety factor' - return "%sbelian %s %sof dimension %s of %s%s" % ( - simple, sub, label, self.dimension(), self._ambient_repr(), field) + return "%sbelian %s %sof dimension %s of %s%s" % (simple, sub, label, self.dimension(), self._ambient_repr(), field) def label(self) -> str: r""" @@ -639,8 +632,7 @@ def elliptic_curve(self): c = CremonaDatabase() if N > c.largest_conductor(): - raise RuntimeError("Elliptic curve not found" + - " in installed database") + raise RuntimeError("Elliptic curve not found" + " in installed database") isogeny_classes = c.isogeny_classes(N) curves = [EllipticCurve(x[0][0]) for x in isogeny_classes] @@ -695,6 +687,7 @@ def _isogeny_to_newform_abelian_variety(self): break from .constructor import AbelianVariety + Af = AbelianVariety(self.newform_label()) H = A.Hom(Af.ambient_variety()) m = H(Morphism(H, mat)) @@ -745,12 +738,10 @@ def _simple_isogeny(self, other): # that the two newform abelian varieties $A_f$ are identical. raise NotImplementedError("_simple_isogeny only implemented when both abelian variety have the same ambient product Jacobian") - if (self.newform_level() != other.newform_level()) or \ - (self.isogeny_number() != other.isogeny_number()): + if (self.newform_level() != other.newform_level()) or (self.isogeny_number() != other.isogeny_number()): raise ValueError("self and other do not correspond to the same newform") - return other._isogeny_to_newform_abelian_variety().complementary_isogeny() * \ - self._isogeny_to_newform_abelian_variety() + return other._isogeny_to_newform_abelian_variety().complementary_isogeny() * self._isogeny_to_newform_abelian_variety() def _Hom_(self, B, cat=None): """ @@ -799,8 +790,7 @@ def in_same_ambient_variety(self, other) -> bool: return False if self.groups() != other.groups(): return False - return (self.is_subvariety_of_ambient_jacobian() and - other.is_subvariety_of_ambient_jacobian()) + return self.is_subvariety_of_ambient_jacobian() and other.is_subvariety_of_ambient_jacobian() def modular_kernel(self): """ @@ -964,12 +954,11 @@ def intersection(self, other): # basis. LM = L.stack(M) P = LM.pivot_rows() - V = (ZZ**L.ncols()).span_of_basis([LM.row(p) for p in P]) + V = (ZZ ** L.ncols()).span_of_basis([LM.row(p) for p in P]) S = (self.lattice() + other.lattice()).saturation() n = self.lattice().rank() # Finally we project onto the L factor. - gens = [L.linear_combination_of_rows(v.list()[:n]) - for v in V.coordinate_module(S).basis()] + gens = [L.linear_combination_of_rows(v.list()[:n]) for v in V.coordinate_module(S).basis()] if A.dimension() > 0: from sage.rings.qqbar import QQbar as finitegroup_base_field @@ -1309,14 +1298,12 @@ def degeneracy_map(self, M_ls, t_ls): N = groups[i].level() if (M_ls[i] % N) and (N % M_ls[i]): raise ValueError("one level must divide the other in %s-th component" % i) - if ((max(M_ls[i], N) // min(M_ls[i], N)) % t_ls[i]): + if (max(M_ls[i], N) // min(M_ls[i], N)) % t_ls[i]: raise ValueError("each t must divide the quotient of the levels") - ls = [self.groups()[i].modular_abelian_variety().degeneracy_map(M_ls[i], t_ls[i]).matrix() - for i in range(length)] + ls = [self.groups()[i].modular_abelian_variety().degeneracy_map(M_ls[i], t_ls[i]).matrix() for i in range(length)] - new_codomain = prod([self.groups()[i]._new_group_from_level(M_ls[i]).modular_abelian_variety() - for i in range(length)]) + new_codomain = prod([self.groups()[i]._new_group_from_level(M_ls[i]).modular_abelian_variety() for i in range(length)]) M = block_diagonal_matrix(ls, subdivide=False) H = self.Hom(new_codomain) @@ -1567,8 +1554,7 @@ def project_to_factor(self, n): G = self.groups()[n] A = G.modular_abelian_variety() - index = sum([gp.modular_symbols().cuspidal_subspace().dimension() - for gp in self.groups()[0: n]]) + index = sum([gp.modular_symbols().cuspidal_subspace().dimension() for gp in self.groups()[0:n]]) H = self.Hom(A) mat = H.matrix_space()(0) @@ -1604,7 +1590,7 @@ def is_subvariety_of_ambient_jacobian(self) -> bool: try: return self.__is_sub_ambient except AttributeError: - self.__is_sub_ambient = (self.lattice().denominator() == 1) + self.__is_sub_ambient = self.lattice().denominator() == 1 return self.__is_sub_ambient def ambient_variety(self): @@ -1625,8 +1611,7 @@ def ambient_variety(self): try: return self.__ambient_variety except AttributeError: - A = ModularAbelianVariety(self.groups(), ZZ**(2 * self._ambient_dimension()), - self.base_field(), check=False) + A = ModularAbelianVariety(self.groups(), ZZ ** (2 * self._ambient_dimension()), self.base_field(), check=False) self.__ambient_variety = A return A @@ -1709,7 +1694,7 @@ def is_ambient(self) -> bool: True """ L = self.lattice() - return self.lattice() == ZZ**L.degree() + return self.lattice() == ZZ ** L.degree() def dimension(self): """ @@ -1756,8 +1741,7 @@ def conductor(self): """ if not self.base_ring() == QQ: raise ValueError("base ring must be QQ") - return prod(f.level() ** f.base_ring().degree() - for f in self.newform_decomposition('a')) + return prod(f.level() ** f.base_ring().degree() for f in self.newform_decomposition('a')) def rank(self): """ @@ -1865,8 +1849,7 @@ def is_hecke_stable(self) -> bool: True """ # b = self.modular_symbols().sturm_bound() - b = max([m.sturm_bound() - for m in self._ambient_modular_symbols_spaces()]) + b = max([m.sturm_bound() for m in self._ambient_modular_symbols_spaces()]) J = self.ambient_variety() L = self.lattice() B = self.lattice().basis() @@ -1987,8 +1970,7 @@ def newform_level(self, none_if_not_known=False): if none_if_not_known: return None level = LCM([f.level() for f in self.newform_decomposition('a')]) - groups = sorted({f.group() - for f in self.newform_decomposition('a')}) + groups = sorted({f.group() for f in self.newform_decomposition('a')}) if len(groups) == 1: groups = groups[0] self.__newform_level = level, groups @@ -2011,9 +1993,8 @@ def zero_subvariety(self): try: return self.__zero_subvariety except AttributeError: - lattice = (ZZ**(2 * self.degree())).zero_submodule() - A = ModularAbelianVariety(self.groups(), lattice, self.base_field(), - is_simple=True, check=False) + lattice = (ZZ ** (2 * self.degree())).zero_submodule() + A = ModularAbelianVariety(self.groups(), lattice, self.base_field(), is_simple=True, check=False) self.__zero_subvariety = A return A @@ -2084,7 +2065,7 @@ def _ambient_lattice(self): try: return self.__ambient_lattice except AttributeError: - self.__ambient_lattice = ZZ**(2 * self.degree()) + self.__ambient_lattice = ZZ ** (2 * self.degree()) return self.__ambient_lattice def _ambient_modular_symbols_spaces(self): @@ -2327,10 +2308,9 @@ def frobenius_polynomial(self, p, var='x'): raise ValueError("p must be prime") if not self.is_simple(): from .constructor import AbelianVariety - decomp = [AbelianVariety(f) for f in - self.newform_decomposition('a')] - return prod(s.frobenius_polynomial(p) for s in - decomp) + + decomp = [AbelianVariety(f) for f in self.newform_decomposition('a')] + return prod(s.frobenius_polynomial(p) for s in decomp) f = self.newform('a') Kf = f.base_ring() eps = f.character() @@ -2416,6 +2396,7 @@ def homology(self, base_ring=ZZ): Integral Homology of Abelian variety J0(389) of dimension 32 """ from sage.modular.abvar import homology + try: return self._homology[base_ring] except AttributeError: @@ -3047,17 +3028,14 @@ def finite_subgroup(self, X, field_of_definition=None, check=True): if A == self: X = X.lattice() elif X.is_subgroup(self): - X = (X.lattice() + - self.ambient_variety().lattice()).intersection( - self.vector_space()) + X = (X.lattice() + self.ambient_variety().lattice()).intersection(self.vector_space()) else: raise ValueError("X must be a subgroup of self") if field_of_definition is None: from sage.rings.qqbar import QQbar as field_of_definition - return FiniteSubgroup_lattice( - self, X, field_of_definition=field_of_definition, check=check) + return FiniteSubgroup_lattice(self, X, field_of_definition=field_of_definition, check=check) @cached_method def torsion_subgroup(self, n): @@ -3085,8 +3063,7 @@ def torsion_subgroup(self, n): 16 """ lattice = self.lattice().scale(1 / Integer(n)) - return FiniteSubgroup_lattice(self, lattice, - field_of_definition=self.base_field()) + return FiniteSubgroup_lattice(self, lattice, field_of_definition=self.base_field()) # ######################################################################### # Decomposition @@ -3291,6 +3268,7 @@ def decomposition(self, simple=True, bound=None): # Decompose each ambient modular symbols factor. # X = [ModularAbelianVariety_modsym(ModularSymbols(G,sign=0).cuspidal_submodule()) for G in self.groups()] from .abvar_ambient_jacobian import ModAbVar_ambient_jacobian_class + X = [ModAbVar_ambient_jacobian_class(G) for G in self.groups()] E = [A.decomposition(simple=simple, bound=bound) for A in X] i = 0 @@ -3307,9 +3285,7 @@ def decomposition(self, simple=True, bound=None): else: is_simple = None lattice = matrix(QQ, L.nrows(), i).augment(L).augment(matrix(QQ, L.nrows(), n - i - L.ncols())).row_module(ZZ) - D.append(ModularAbelianVariety(G, lattice, K, is_simple=is_simple, newform_level=B.newform_level(), - isogeny_number=B.isogeny_number(none_if_not_known=True), - number=B.degen_t(none_if_not_known=True))) + D.append(ModularAbelianVariety(G, lattice, K, is_simple=is_simple, newform_level=B.newform_level(), isogeny_number=B.isogeny_number(none_if_not_known=True), number=B.degen_t(none_if_not_known=True))) if C: i += L.ncols() elif not simple: @@ -3380,7 +3356,7 @@ def decomposition(self, simple=True, bound=None): proj = X.matrix_from_columns(range(n - L_F.rank(), n)) # Now proj is the matrix of projection that goes from # L_B to L_F, wrt the basis of those spaces. - section = proj**(-1) + section = proj ** (-1) # Now section maps L_F to L_B (tensor QQ). Now we # just take each factor of F, which corresponds to a @@ -3396,8 +3372,7 @@ def decomposition(self, simple=True, bound=None): M = M.saturation() M = M * L_B.basis_matrix() lattice = M.row_module(ZZ) - the_factor = ModularAbelianVariety(groups, lattice, K, is_simple=True, newform_level=A.newform_level(), - isogeny_number=A.isogeny_number(), number=A.degen_t()) + the_factor = ModularAbelianVariety(groups, lattice, K, is_simple=True, newform_level=A.newform_level(), isogeny_number=A.isogeny_number(), number=A.degen_t()) D.append(the_factor) ################ @@ -3851,8 +3826,7 @@ def __getitem__(self, i): class ModularAbelianVariety(ModularAbelianVariety_abstract): - def __init__(self, groups, lattice=None, base_field=QQ, is_simple=None, newform_level=None, - isogeny_number=None, number=None, check=True): + def __init__(self, groups, lattice=None, base_field=QQ, is_simple=None, newform_level=None, isogeny_number=None, number=None, check=True): r""" Create a modular abelian variety with given level and base field. @@ -3871,10 +3845,9 @@ def __init__(self, groups, lattice=None, base_field=QQ, is_simple=None, newform_ sage: J0(23) Abelian variety J0(23) of dimension 2 """ - ModularAbelianVariety_abstract.__init__(self, groups, base_field, is_simple=is_simple, newform_level=newform_level, - isogeny_number=isogeny_number, number=number, check=check) + ModularAbelianVariety_abstract.__init__(self, groups, base_field, is_simple=is_simple, newform_level=newform_level, isogeny_number=isogeny_number, number=number, check=check) if lattice is None: - lattice = ZZ**(2 * self._ambient_dimension()) + lattice = ZZ ** (2 * self._ambient_dimension()) if check: n = self._ambient_dimension() if not isinstance(lattice, FreeModule_generic): @@ -3990,7 +3963,7 @@ def groups(self): sage: type(A) """ - return (self._modular_symbols().group(), ) + return (self._modular_symbols().group(),) def lattice(self): r""" @@ -4018,7 +3991,7 @@ def lattice(self): M = self.modular_symbols() S = M.ambient_module().cuspidal_submodule() if M.dimension() == S.dimension(): - L = ZZ**M.dimension() + L = ZZ ** M.dimension() else: K0 = M.integral_structure() K1 = S.integral_structure() @@ -4423,14 +4396,9 @@ def decomposition(self, simple=True, bound=None): else: X = A.decomposition(bound=bound) for isogeny_number, B in enumerate(X): - D.extend(ModularAbelianVariety_modsym(B.degeneracy_map(M, t).image(), - is_simple=True, newform_level=(N, G), - isogeny_number=isogeny_number, - number=(t, M)) - for t in divisors(M // N)) + D.extend(ModularAbelianVariety_modsym(B.degeneracy_map(M, t).image(), is_simple=True, newform_level=(N, G), isogeny_number=isogeny_number, number=(t, M)) for t in divisors(M // N)) elif A == amb.cuspidal_submodule(): - D = [ModularAbelianVariety_modsym(B) - for B in A.decomposition(bound=bound)] + D = [ModularAbelianVariety_modsym(B) for B in A.decomposition(bound=bound)] else: D = ModularAbelianVariety_abstract.decomposition(self, simple=simple, bound=bound) D.sort() @@ -4441,8 +4409,7 @@ def decomposition(self, simple=True, bound=None): class ModularAbelianVariety_modsym(ModularAbelianVariety_modsym_abstract): - def __init__(self, modsym, lattice=None, newform_level=None, - is_simple=None, isogeny_number=None, number=None, check=True): + def __init__(self, modsym, lattice=None, newform_level=None, is_simple=None, isogeny_number=None, number=None, check=True): """ Modular abelian variety that corresponds to a Hecke stable space of cuspidal modular symbols. @@ -4464,9 +4431,7 @@ def __init__(self, modsym, lattice=None, newform_level=None, if not modsym.is_cuspidal(): raise ValueError("modsym must be cuspidal") - ModularAbelianVariety_abstract.__init__(self, (modsym.group(), ), modsym.base_ring(), - newform_level=newform_level, is_simple=is_simple, - isogeny_number=isogeny_number, number=number, check=check) + ModularAbelianVariety_abstract.__init__(self, (modsym.group(),), modsym.base_ring(), newform_level=newform_level, is_simple=is_simple, isogeny_number=isogeny_number, number=number, check=check) if lattice is not None: self._set_lattice(lattice) self.__modsym = modsym @@ -4624,7 +4589,7 @@ def _invariants_of_image_of_component_group_of_J0(self, p): 66 """ self.component_group_order(p) - return list(self.__component_group[p][1]) # make a copy + return list(self.__component_group[p][1]) # make a copy def tamagawa_number(self, p): """ @@ -4849,7 +4814,7 @@ def sqrt_poly(f): if not f.is_monic(): raise ValueError("f must be monic") try: - return prod([g**Integer(e / Integer(2)) for g, e in f.factor()]) + return prod([g ** Integer(e / Integer(2)) for g, e in f.factor()]) except TypeError: raise ValueError("f must be a perfect square") @@ -4944,8 +4909,7 @@ def factor_modsym_space_new_factors(M): """ eps = M.character() K = eps.conductor() if eps is not None else 1 - N = [M.modular_symbols_of_level(d).cuspidal_subspace().new_subspace() - for d in M.level().divisors() if d % K == 0 and (d == 11 or d >= 13)] + N = [M.modular_symbols_of_level(d).cuspidal_subspace().new_subspace() for d in M.level().divisors() if d % K == 0 and (d == 11 or d >= 13)] return [factor_new_space(A) for A in N] @@ -5017,7 +4981,7 @@ def simple_factorization_of_modsym_space(M, simple=True): # Construct the corresponding subspaces at higher level. j = 0 - for (isog, A) in enumerate(G): + for isog, A in enumerate(G): d = A.dimension() if simple: for i in range(len(T)): diff --git a/src/sage/modular/abvar/abvar_ambient_jacobian.py b/src/sage/modular/abvar/abvar_ambient_jacobian.py index 0636ce630a3..3dcf2bbf84e 100644 --- a/src/sage/modular/abvar/abvar_ambient_jacobian.py +++ b/src/sage/modular/abvar/abvar_ambient_jacobian.py @@ -8,11 +8,10 @@ sage: loads(dumps(J1(13))) == J1(13) True """ + import weakref -from .abvar import (ModularAbelianVariety_modsym_abstract, - simple_factorization_of_modsym_space, modsym_lattices, - ModularAbelianVariety_modsym) +from .abvar import ModularAbelianVariety_modsym_abstract, simple_factorization_of_modsym_space, modsym_lattices, ModularAbelianVariety_modsym from sage.misc.cachefunc import cached_method from sage.modular.modsym.modsym import ModularSymbols @@ -73,6 +72,7 @@ class ModAbVar_ambient_jacobian_class(ModularAbelianVariety_modsym_abstract): An ambient Jacobian modular abelian variety attached to a congruence subgroup. """ + def __init__(self, group) -> None: """ Create an ambient Jacobian modular abelian variety. @@ -123,8 +123,7 @@ def _repr_(self) -> str: sage: A.reset_name() """ txt = '' if self.base_field() == QQ else ' over %s' % self.base_field() - return 'Abelian variety %s of dimension %s%s' % (self._ambient_repr(), - self.dimension(), txt) + return 'Abelian variety %s of dimension %s%s' % (self._ambient_repr(), self.dimension(), txt) def _latex_(self) -> str: """ @@ -352,13 +351,7 @@ def decomposition(self, simple=True, bound=None) -> list: D = [] is_simple = True if simple else None for newform_level, isogeny_number, number, modsym, lattice in factors: - A = ModularAbelianVariety_modsym( - modsym, lattice=lattice, - newform_level=(newform_level, group), - is_simple=is_simple, - isogeny_number=isogeny_number, - number=(number, level), - check=False) + A = ModularAbelianVariety_modsym(modsym, lattice=lattice, newform_level=(newform_level, group), is_simple=is_simple, isogeny_number=isogeny_number, number=(number, level), check=False) D.append(A) # This line below could be safely deleted. It basically @@ -398,6 +391,5 @@ def newform_decomposition(self, names=None) -> list: return [S.newform(names=names) for S in self.decomposition()] Gtype = G.parent() N = G.level() - preans = (Newforms(Gtype(d), names=names) * len((N // d).divisors()) - for d in N.divisors()) + preans = (Newforms(Gtype(d), names=names) * len((N // d).divisors()) for d in N.divisors()) return [newform for li in preans for newform in li] diff --git a/src/sage/modular/abvar/abvar_newform.py b/src/sage/modular/abvar/abvar_newform.py index f66670e4649..cae2b3445d6 100644 --- a/src/sage/modular/abvar/abvar_newform.py +++ b/src/sage/modular/abvar/abvar_newform.py @@ -25,6 +25,7 @@ from .abvar import ModularAbelianVariety_modsym_abstract from sage.modular.abvar import homspace + lazy_import('sage.databases.cremona', 'cremona_letter_code') @@ -32,6 +33,7 @@ class ModularAbelianVariety_newform(ModularAbelianVariety_modsym_abstract): """ A modular abelian variety attached to a specific newform. """ + def __init__(self, f, internal_name=False): """ Create the modular abelian variety `A_f` attached to the @@ -66,9 +68,7 @@ def __init__(self, f, internal_name=False): self.__named_newforms = {variable_name: self.__f} if not internal_name: self.__named_newforms[None] = self.__f - ModularAbelianVariety_modsym_abstract.__init__(self, (f.group(),), QQ, - is_simple=True, newform_level=(f.level(), f.group()), - isogeny_number=f.number(), number=0) + ModularAbelianVariety_modsym_abstract.__init__(self, (f.group(),), QQ, is_simple=True, newform_level=(f.level(), f.group()), isogeny_number=f.number(), number=0) def _modular_symbols(self, sign=0): """ @@ -170,8 +170,7 @@ def _repr_(self) -> str: sage: AbelianVariety('37a')._repr_() 'Newform abelian subvariety 37a of dimension 1 of J0(37)' """ - return "Newform abelian subvariety %s of dimension %s of %s" % ( - self.newform_label(), self.dimension(), self._ambient_repr()) + return "Newform abelian subvariety %s of dimension %s of %s" % (self.newform_label(), self.dimension(), self._ambient_repr()) def endomorphism_ring(self): """ @@ -230,13 +229,12 @@ def _calculate_endomorphism_generators(self): d = self.dimension() T1list = self.hecke_operator(1).matrix().list() - EndVecZ = ZZ**(len(T1list)) + EndVecZ = ZZ ** (len(T1list)) V = EndVecZ.submodule([T1list]) n = 2 while V.dimension() < d: - W = EndVecZ.submodule([((self.hecke_operator(n).matrix())**i).list() - for i in range(1, d + 1)]) + W = EndVecZ.submodule([((self.hecke_operator(n).matrix()) ** i).list() for i in range(1, d + 1)]) V = V + W n += 1 if n > bound: diff --git a/src/sage/modular/abvar/constructor.py b/src/sage/modular/abvar/constructor.py index 8fa4f2b3e76..c3b5f09df3c 100644 --- a/src/sage/modular/abvar/constructor.py +++ b/src/sage/modular/abvar/constructor.py @@ -5,6 +5,7 @@ - William Stein (2007-03) """ + # ######################################################################### # Copyright (C) 2007 William Stein # # Distributed under the terms of the GNU General Public License (GPL) # @@ -95,6 +96,7 @@ def J0(N): return _get(key) except ValueError: from sage.modular.arithgroup.congroup_gamma0 import Gamma0_constructor as Gamma0 + J = Gamma0(N).modular_abelian_variety() return _saved(key, J) @@ -114,6 +116,7 @@ def J1(N): return _get(key) except ValueError: from sage.modular.arithgroup.congroup_gamma1 import Gamma1_constructor as Gamma1 + return _saved(key, Gamma1(N).modular_abelian_variety()) @@ -132,6 +135,7 @@ def JH(N, H): return _get(key) except ValueError: from sage.modular.arithgroup.congroup_gammaH import GammaH_constructor as GammaH + return _saved(key, GammaH(N, H).modular_abelian_variety()) @@ -172,6 +176,7 @@ def AbelianVariety(X): X = X.modular_symbols().cuspidal_submodule() elif isinstance(X, str): from sage.modular.modform.constructor import Newform + f = Newform(X, names='a') return ModularAbelianVariety_newform(f, internal_name=True) elif isinstance(X, sage.modular.modform.element.Newform): diff --git a/src/sage/modular/abvar/cuspidal_subgroup.py b/src/sage/modular/abvar/cuspidal_subgroup.py index 6587482d3f1..b780d6045a5 100644 --- a/src/sage/modular/abvar/cuspidal_subgroup.py +++ b/src/sage/modular/abvar/cuspidal_subgroup.py @@ -192,6 +192,7 @@ class CuspidalSubgroup(CuspidalSubgroup_generic): sage: t.order() 6 """ + def _repr_(self): """ String representation of the cuspidal subgroup. @@ -243,6 +244,7 @@ class RationalCuspSubgroup(CuspidalSubgroup_generic): sage: t.order() 6 """ + def _repr_(self): """ String representation of the cuspidal subgroup. @@ -294,6 +296,7 @@ class RationalCuspidalSubgroup(CuspidalSubgroup_generic): sage: t.order() 6 """ + def _repr_(self): """ String representation of the cuspidal subgroup. diff --git a/src/sage/modular/abvar/finite_subgroup.py b/src/sage/modular/abvar/finite_subgroup.py index 07f2c86effa..13b53a7774c 100644 --- a/src/sage/modular/abvar/finite_subgroup.py +++ b/src/sage/modular/abvar/finite_subgroup.py @@ -157,6 +157,7 @@ def __init__(self, abvar, field_of_definition=QQ) -> None: from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.modules import Modules from .abvar import ModularAbelianVariety_abstract + if field_of_definition not in Fields(): raise TypeError("field_of_definition must be a field") if not isinstance(abvar, ModularAbelianVariety_abstract): @@ -407,17 +408,17 @@ def intersection(self, other): Abelian subvariety of dimension 2 of J0(33) """ from .abvar import ModularAbelianVariety_abstract + A = self.abelian_variety() if isinstance(other, ModularAbelianVariety_abstract): amb = other B = other - M = B.lattice().scale(Integer(1)/self.exponent()) + M = B.lattice().scale(Integer(1) / self.exponent()) K = coercion_model.common_parent(self.field_of_definition(), other.base_field()) else: amb = A if not isinstance(other, FiniteSubgroup): - raise TypeError("only intersection with a finite subgroup or " - "modular abelian variety is defined") + raise TypeError("only intersection with a finite subgroup or " "modular abelian variety is defined") B = other.abelian_variety() if A.ambient_variety() != B.ambient_variety(): raise TypeError("finite subgroups must be in the same ambient product Jacobian") @@ -472,8 +473,7 @@ def __mul__(self, right): 22500000000 """ lattice = self.lattice().scale(right) - return FiniteSubgroup_lattice(self.abelian_variety(), lattice, - field_of_definition=self.field_of_definition()) + return FiniteSubgroup_lattice(self.abelian_variety(), lattice, field_of_definition=self.field_of_definition()) def __rmul__(self, left): """ @@ -554,7 +554,7 @@ def _invariants_repr(self): sage: J0(42).cuspidal_subgroup()._invariants_repr() 'with invariants [2, 2, 12, 48] ' """ - return 'with invariants %s ' % (self.invariants(), ) + return 'with invariants %s ' % (self.invariants(),) def order(self): """ @@ -875,8 +875,7 @@ def cardinality(self): class FiniteSubgroup_lattice(FiniteSubgroup): - def __init__(self, abvar, lattice, - field_of_definition=None, check=True) -> None: + def __init__(self, abvar, lattice, field_of_definition=None, check=True) -> None: """ A finite subgroup of a modular abelian variety that is defined by a given lattice. @@ -904,6 +903,7 @@ def __init__(self, abvar, lattice, from sage.rings.qqbar import QQbar as field_of_definition if check: from .abvar import ModularAbelianVariety_abstract + if not isinstance(lattice, FreeModule_generic) or lattice.base_ring() != ZZ: raise TypeError("lattice must be a free module over ZZ") if not isinstance(abvar, ModularAbelianVariety_abstract): diff --git a/src/sage/modular/abvar/homology.py b/src/sage/modular/abvar/homology.py index f2075fc7b18..d97fa13a66b 100644 --- a/src/sage/modular/abvar/homology.py +++ b/src/sage/modular/abvar/homology.py @@ -66,6 +66,7 @@ class Homology(HeckeModule_free_module): A homology group of an abelian variety, equipped with a Hecke action. """ + def hecke_polynomial(self, n, var='x'): r""" Return the `n`-th Hecke polynomial in the given variable. @@ -96,6 +97,7 @@ class Homology_abvar(Homology): """ The homology of a modular abelian variety. """ + def __init__(self, abvar, base): """ This is an abstract base class, so it is called implicitly in the @@ -115,8 +117,7 @@ def __init__(self, abvar, base): """ if base not in CommutativeRings(): raise TypeError("base ring must be a commutative ring") - HeckeModule_free_module.__init__( - self, base, abvar.level(), weight=2) + HeckeModule_free_module.__init__(self, base, abvar.level(), weight=2) self.__abvar = abvar def __richcmp__(self, other, op): @@ -134,8 +135,7 @@ def __richcmp__(self, other, op): """ if not isinstance(other, Homology_abvar): return NotImplemented - return richcmp((self.abelian_variety(), self.base_ring()), - (other.abelian_variety(), other.base_ring()), op) + return richcmp((self.abelian_variety(), self.base_ring()), (other.abelian_variety(), other.base_ring()), op) def _repr_(self) -> str: """ @@ -225,7 +225,7 @@ def free_module(self): try: return self.__free_module except AttributeError: - M = self.base_ring()**self.rank() + M = self.base_ring() ** self.rank() self.__free_module = M return M @@ -336,6 +336,7 @@ class IntegralHomology(Homology_abvar): The integral homology `H_1(A,\ZZ)` of a modular abelian variety. """ + def __init__(self, abvar): """ Create the integral homology of a modular abelian variety. @@ -403,7 +404,7 @@ def hecke_polynomial(self, n, var='x'): """ n = Integer(n) M = self.abelian_variety().modular_symbols(sign=1) - return (M.hecke_polynomial(n, var)**2).change_ring(ZZ) + return (M.hecke_polynomial(n, var) ** 2).change_ring(ZZ) class RationalHomology(Homology_abvar): @@ -411,6 +412,7 @@ class RationalHomology(Homology_abvar): The rational homology `H_1(A,\QQ)` of a modular abelian variety. """ + def __init__(self, abvar): """ Create the rational homology of a modular abelian variety. @@ -489,6 +491,7 @@ class Homology_over_base(Homology_abvar): The homology over a modular abelian variety over an arbitrary base commutative ring (not `\ZZ` or `\QQ`). """ + def __init__(self, abvar, base_ring): r""" Called when creating homology with coefficients not @@ -549,6 +552,7 @@ class Homology_submodule(Homology): """ A submodule of the homology of a modular abelian variety. """ + def __init__(self, ambient, submodule): """ Create a submodule of the homology of a modular abelian variety. @@ -577,8 +581,7 @@ def __init__(self, ambient, submodule): self.__ambient = ambient submodule = ambient.free_module().submodule(submodule) self.__submodule = submodule - HeckeModule_free_module.__init__( - self, ambient.base_ring(), ambient.level(), weight=2) + HeckeModule_free_module.__init__(self, ambient.base_ring(), ambient.level(), weight=2) def _repr_(self): """ diff --git a/src/sage/modular/abvar/homspace.py b/src/sage/modular/abvar/homspace.py index 3bcc4829de8..858170fcfa6 100644 --- a/src/sage/modular/abvar/homspace.py +++ b/src/sage/modular/abvar/homspace.py @@ -205,6 +205,7 @@ class Homspace(HomsetWithBase): """ A space of homomorphisms between two modular abelian varieties. """ + Element = morphism.Morphism def __init__(self, domain, codomain, cat): @@ -230,6 +231,7 @@ def __init__(self, domain, codomain, cat): Category of modular abelian varieties over Rational Field """ from .abvar import ModularAbelianVariety_abstract + if not isinstance(domain, ModularAbelianVariety_abstract): raise TypeError("domain must be a modular abelian variety") if not isinstance(codomain, ModularAbelianVariety_abstract): @@ -276,7 +278,7 @@ def _matrix_space(self): sage: Hom(J0(11), J0(22))._matrix_space Full MatrixSpace of 2 by 4 dense matrices over Integer Ring """ - return MatrixSpace(ZZ, 2*self.domain().dimension(), 2*self.codomain().dimension()) + return MatrixSpace(ZZ, 2 * self.domain().dimension(), 2 * self.codomain().dimension()) def _element_constructor_from_element_class(self, *args, **keywords): """ @@ -361,10 +363,10 @@ def __call__(self, M, **kwds): if M.base_ring() != ZZ: M = M.change_ring(ZZ) if side == "left": - if M.nrows() != 2*self.domain().dimension() or M.ncols() != 2*self.codomain().dimension(): + if M.nrows() != 2 * self.domain().dimension() or M.ncols() != 2 * self.codomain().dimension(): raise TypeError("matrix has wrong dimension") else: - if M.ncols() != 2*self.domain().dimension() or M.nrows() != 2*self.codomain().dimension(): + if M.ncols() != 2 * self.domain().dimension() or M.nrows() != 2 * self.codomain().dimension(): raise TypeError("matrix has wrong dimension") elif self.matrix_space().has_coerce_map_from(parent(M)): M = self.matrix_space()(M) @@ -382,8 +384,7 @@ def _repr_(self): sage: End(J)._repr_() 'Endomorphism ring of Abelian variety J0(11) of dimension 1' """ - return "Space of homomorphisms from %s to %s" %\ - (self.domain(), self.codomain()) + return "Space of homomorphisms from %s to %s" % (self.domain(), self.codomain()) def _get_matrix(self, g): """ @@ -456,7 +457,7 @@ def free_module(self): [ 0 1 -3 1 1 1 -1 0] """ self.calculate_generators() - V = ZZ**(4*self.domain().dimension() * self.codomain().dimension()) + V = ZZ ** (4 * self.domain().dimension() * self.codomain().dimension()) return V.submodule([V(m.matrix().list()) for m in self.gens()]) def gen(self, i=0): @@ -558,9 +559,8 @@ def calculate_generators(self): M = phi.matrix() Mt = psi.complementary_isogeny().matrix() - R = ZZ**(4*self.domain().dimension()*self.codomain().dimension()) - gens = R.submodule([(M*self._get_matrix(g)*Mt).list() - for g in im_gens]).saturation().basis() + R = ZZ ** (4 * self.domain().dimension() * self.codomain().dimension()) + gens = R.submodule([(M * self._get_matrix(g) * Mt).list() for g in im_gens]).saturation().basis() self._gens = tuple([self._get_matrix(g) for g in gens]) def _calculate_product_gens(self): @@ -611,7 +611,7 @@ def _calculate_product_gens(self): for sub_gen in hom_gens: sub_mat = sub_gen.matrix() M = copy(self.matrix_space().zero_matrix()) - M.set_block(sub_mat.nrows()*i, sub_mat.ncols()*j, sub_mat) + M.set_block(sub_mat.nrows() * i, sub_mat.ncols() * j, sub_mat) gens.append(phi_matrix * M * psi_t_matrix) else: @@ -629,9 +629,7 @@ def _calculate_product_gens(self): for sub_gen in Afactor.Hom(Bfactor).gens(): sub_mat = sub_gen.matrix() M = copy(self.matrix_space().zero_matrix()) - M.set_block(cur_row - sub_mat.nrows(), - cur_col - sub_mat.ncols(), - sub_mat) + M.set_block(cur_row - sub_mat.nrows(), cur_col - sub_mat.ncols(), sub_mat) gens.append(M) return gens @@ -871,7 +869,7 @@ def index_in_saturation(self): """ A = self.abelian_variety() d = A.dimension() - M = ZZ**(4*d**2) + M = ZZ ** (4 * d**2) gens = [x.matrix().list() for x in self.gens()] R = M.submodule(gens) return R.index_in_saturation() @@ -903,8 +901,7 @@ def discriminant(self): 2 """ g = self.gens() - M = matrix(ZZ, len(g), [(g[i]*g[j]).trace() - for i in range(len(g)) for j in range(len(g))]) + M = matrix(ZZ, len(g), [(g[i] * g[j]).trace() for i in range(len(g)) for j in range(len(g))]) return M.determinant() def image_of_hecke_algebra(self, check_every=1): @@ -966,7 +963,7 @@ def image_of_hecke_algebra(self, check_every=1): M = A.modular_symbols() d = A.dimension() - EndVecZ = ZZ**(4*d**2) + EndVecZ = ZZ ** (4 * d**2) if d == 1: self.__hecke_algebra_image = EndomorphismSubring(A, [[1, 0, 0, 1]]) @@ -974,11 +971,8 @@ def image_of_hecke_algebra(self, check_every=1): V = EndVecZ.submodule([A.hecke_operator(1).matrix().list()]) - for n in range(2, M.sturm_bound()+1): - if (check_every > 0 and - n % check_every == 0 and - V.dimension() == d and - V.index_in_saturation() == 1): + for n in range(2, M.sturm_bound() + 1): + if check_every > 0 and n % check_every == 0 and V.dimension() == d and V.index_in_saturation() == 1: break V += EndVecZ.submodule([A.hecke_operator(n).matrix().list()]) diff --git a/src/sage/modular/abvar/lseries.py b/src/sage/modular/abvar/lseries.py index ad085c7f827..de643c184e9 100644 --- a/src/sage/modular/abvar/lseries.py +++ b/src/sage/modular/abvar/lseries.py @@ -39,6 +39,7 @@ class Lseries(SageObject): This is a common base class for complex and `p`-adic `L`-series of modular abelian varieties. """ + def __init__(self, abvar): """ Called when creating an `L`-series. @@ -80,6 +81,7 @@ class Lseries_complex(Lseries): sage: A.lseries() Complex L-series attached to Abelian variety J0(37) of dimension 2 """ + def __call__(self, s, prec=53): """ Evaluate this complex `L`-series at `s`. @@ -135,9 +137,7 @@ def __call__(self, s, prec=53): abelian_variety = self.abelian_variety() newforms = abelian_variety.newform_decomposition('a') - factors = [newform.lseries(embedding=i, prec=prec) - for newform in newforms - for i in range(newform.base_ring().degree())] + factors = [newform.lseries(embedding=i, prec=prec) for newform in newforms for i in range(newform.base_ring().degree())] self.__factors[prec] = factors return prod(L(s) for L in factors) @@ -244,8 +244,8 @@ def vanishes_at_1(self): return False if not abelian_variety.is_simple(): from .constructor import AbelianVariety - decomp = (AbelianVariety(f) for f in - abelian_variety.newform_decomposition('a')) + + decomp = (AbelianVariety(f) for f in abelian_variety.newform_decomposition('a')) return any(S.lseries().vanishes_at_1() for S in decomp) modular_symbols = abelian_variety.modular_symbols() Phi = modular_symbols.rational_period_mapping() @@ -277,14 +277,12 @@ def rational_part(self): if self.vanishes_at_1(): return QQ(0) s = ambient_module.sturm_bound() - I = ambient_module.hecke_images(0, range(1, s+1)) - PhiTe = span([Phi(ambient_module(I[n])) - for n in range(I.nrows())], ZZ) + I = ambient_module.hecke_images(0, range(1, s + 1)) + PhiTe = span([Phi(ambient_module(I[n])) for n in range(I.nrows())], ZZ) ambient_plus = ambient_module.sign_submodule(1) ambient_plus_cusp = ambient_plus.cuspidal_submodule() - PhiH1plus = span([Phi(x) for - x in ambient_plus_cusp.integral_basis()], ZZ) + PhiH1plus = span([Phi(x) for x in ambient_plus_cusp.integral_basis()], ZZ) return PhiTe.index_in(PhiH1plus) @@ -295,6 +293,7 @@ class Lseries_padic(Lseries): """ A `p`-adic `L`-series attached to a modular abelian variety. """ + def __init__(self, abvar, p): """ Create a `p`-adic `L`-series. @@ -337,8 +336,7 @@ def __eq__(self, other): """ if not isinstance(other, Lseries_padic): return False - return (self.abelian_variety() == other.abelian_variety() and - self.__p == other.__p) + return self.abelian_variety() == other.abelian_variety() and self.__p == other.__p def __ne__(self, other): """ @@ -409,5 +407,4 @@ def _repr_(self): sage: L._repr_() '5-adic L-series attached to Simple abelian subvariety 37a(1,37) of dimension 1 of J0(37)' """ - return "%s-adic L-series attached to %s" % (self.__p, - self.abelian_variety()) + return "%s-adic L-series attached to %s" % (self.__p, self.abelian_variety()) diff --git a/src/sage/modular/abvar/morphism.py b/src/sage/modular/abvar/morphism.py index 7fb1e2aac0f..c65f3893d54 100644 --- a/src/sage/modular/abvar/morphism.py +++ b/src/sage/modular/abvar/morphism.py @@ -229,6 +229,7 @@ def kernel(self): V = (A.kernel().basis_matrix() * D.vector_space().basis_matrix()).row_module() Lambda = V.intersection(D._ambient_lattice()) from .abvar import ModularAbelianVariety + abvar = ModularAbelianVariety(D.groups(), Lambda, D.base_ring()) if Lambda.rank() == 0: @@ -312,6 +313,7 @@ def factor_out_component_group(self): R = Lprime + M from .abvar import ModularAbelianVariety + C = ModularAbelianVariety(Q.groups(), R, Q.base_field()) # We have to change the basis of the representation of A @@ -438,6 +440,7 @@ def __call__(self, X): """ from .abvar import ModularAbelianVariety_abstract from .finite_subgroup import FiniteSubgroup + if isinstance(X, TorsionPoint): return self._image_of_element(X) if isinstance(X, ModularAbelianVariety_abstract): @@ -530,8 +533,7 @@ def _image_of_finite_subgroup(self, G): """ B = G._relative_basis_matrix() * self.restrict_domain(G.abelian_variety()).matrix() * self.codomain().lattice().basis_matrix() lattice = B.row_module(ZZ) - return self.codomain().finite_subgroup(lattice, - field_of_definition=G.field_of_definition()) + return self.codomain().finite_subgroup(lattice, field_of_definition=G.field_of_definition()) def _image_of_abvar(self, A): """ @@ -576,6 +578,7 @@ def _image_of_abvar(self, A): Abelian subvariety of dimension 1 of J0(37) """ from .abvar import ModularAbelianVariety + D = self.domain() C = self.codomain() if A is D: @@ -701,6 +704,7 @@ class HeckeOperator(Morphism): """ A Hecke operator acting on a modular abelian variety. """ + def __init__(self, abvar, n, side='left'): """ Create the Hecke operator of index `n` acting on the @@ -721,6 +725,7 @@ def __init__(self, abvar, n, side='left'): Endomorphism ring of Abelian variety J0(37) of dimension 2 """ from .abvar import ModularAbelianVariety_abstract + n = ZZ(n) if n <= 0: raise ValueError("n must be positive") diff --git a/src/sage/modular/abvar/torsion_point.py b/src/sage/modular/abvar/torsion_point.py index 35b11509a75..0f844e86e5e 100644 --- a/src/sage/modular/abvar/torsion_point.py +++ b/src/sage/modular/abvar/torsion_point.py @@ -46,6 +46,7 @@ class TorsionPoint(ModuleElement): sage: type(G.0) """ + def __init__(self, parent, element, check=True): """ Initialize ``self``. @@ -226,6 +227,7 @@ def _richcmp_(self, right, op): """ A = self.parent().abelian_variety() from sage.rings.rational_field import QQ + if self.__element.change_ring(QQ) - right.__element.change_ring(QQ) in A.lattice(): return rich_to_bool(op, 0) return richcmp(self.__element, right.__element, op) diff --git a/src/sage/modular/abvar/torsion_subgroup.py b/src/sage/modular/abvar/torsion_subgroup.py index d91726624cf..bc35e789172 100644 --- a/src/sage/modular/abvar/torsion_subgroup.py +++ b/src/sage/modular/abvar/torsion_subgroup.py @@ -108,6 +108,7 @@ class RationalTorsionSubgroup(FiniteSubgroup): """ The torsion subgroup of a modular abelian variety. """ + def __init__(self, abvar): """ Create the torsion subgroup. @@ -304,7 +305,7 @@ def possible_orders(self, proof=True): N = A.level() # return the order of the cuspidal subgroup in the J0(p) case if A.is_J0() and N.is_prime(): - self._possible_orders = [QQ((A.level()-1)/12).numerator()] + self._possible_orders = [QQ((A.level() - 1) / 12).numerator()] self._possible_orders_proof_false = self._possible_orders return self._possible_orders @@ -316,17 +317,16 @@ def possible_orders(self, proof=True): # the conjectural J1(p) case if not proof and A.is_J1() and N.is_prime(): - epsilons = [epsilon for epsilon in DirichletGroup(N) - if not epsilon.is_trivial() and epsilon.is_even()] + epsilons = [epsilon for epsilon in DirichletGroup(N) if not epsilon.is_trivial() and epsilon.is_even()] bernoullis = [epsilon.bernoulli(2) for epsilon in epsilons] - self._possible_orders_proof_false = [ZZ(N/(2**(N-3))*prod(bernoullis))] + self._possible_orders_proof_false = [ZZ(N / (2 ** (N - 3)) * prod(bernoullis))] return self._possible_orders_proof_false u = self.multiple_of_order() l = self.divisor_of_order() assert u % l == 0 - O = [l * d for d in divisors(u//l)] + O = [l * d for d in divisors(u // l)] self._possible_orders = O if u == l: self._possible_orders_proof_false = O @@ -371,7 +371,7 @@ def divisor_of_order(self): # return the order of the cuspidal subgroup in the J0(p) case if A.is_J0() and N.is_prime(): - self._divisor_of_order = QQ((A.level()-1)/12).numerator() + self._divisor_of_order = QQ((A.level() - 1) / 12).numerator() return self._divisor_of_order # The elliptic curve case @@ -381,10 +381,9 @@ def divisor_of_order(self): # The J1(p) case if A.is_J1() and N.is_prime(): - epsilons = [epsilon for epsilon in DirichletGroup(N) - if not epsilon.is_trivial() and epsilon.is_even()] + epsilons = [epsilon for epsilon in DirichletGroup(N) if not epsilon.is_trivial() and epsilon.is_even()] bernoullis = [epsilon.bernoulli(2) for epsilon in epsilons] - self._divisor_of_order = ZZ(N/(2**(N-3))*prod(bernoullis)) + self._divisor_of_order = ZZ(N / (2 ** (N - 3)) * prod(bernoullis)) return self._divisor_of_order # The Gamma0 case @@ -445,7 +444,7 @@ def multiple_of_order(self, maxp=None, proof=True): # return the order of the cuspidal subgroup in the J0(p) case if A.is_J0() and N.is_prime(): - self._multiple_of_order = QQ((A.level()-1)/12).numerator() + self._multiple_of_order = QQ((A.level() - 1) / 12).numerator() self._multiple_of_order_proof_false = self._multiple_of_order return self._multiple_of_order @@ -457,10 +456,9 @@ def multiple_of_order(self, maxp=None, proof=True): # The conjectural J1(p) case if not proof and A.is_J1() and N.is_prime(): - epsilons = [epsilon for epsilon in DirichletGroup(N) - if not epsilon.is_trivial() and epsilon.is_even()] + epsilons = [epsilon for epsilon in DirichletGroup(N) if not epsilon.is_trivial() and epsilon.is_even()] bernoullis = [epsilon.bernoulli(2) for epsilon in epsilons] - self._multiple_of_order_proof_false = ZZ(N/(2**(N-3))*prod(bernoullis)) + self._multiple_of_order_proof_false = ZZ(N / (2 ** (N - 3)) * prod(bernoullis)) return self._multiple_of_order_proof_false # The Gamma0 and Gamma1 case @@ -574,24 +572,24 @@ def multiple_of_order_using_frobp(self, maxp=None): if maxp is None: X = Primes() else: - X = prime_range(maxp+1) + X = prime_range(maxp + 1) for p in X: - if (2*N) % p == 0: + if (2 * N) % p == 0: continue - if (len(A.groups()) == 1 and isinstance(A.groups()[0], Gamma0_class)): + if len(A.groups()) == 1 and isinstance(A.groups()[0], Gamma0_class): f = A.hecke_polynomial(p) - b = ZZ(f(p+1)) + b = ZZ(f(p + 1)) else: from .constructor import AbelianVariety - D = [AbelianVariety(f) for f in - A.newform_decomposition('a')] + + D = [AbelianVariety(f) for f in A.newform_decomposition('a')] b = 1 for simple in D: G = simple.newform_level()[1] if isinstance(G, Gamma0_class): f = simple.hecke_polynomial(p) - b *= ZZ(f(p+1)) + b *= ZZ(f(p + 1)) else: f = simple.newform('a') Kf = f.base_ring() @@ -609,10 +607,10 @@ def multiple_of_order_using_frobp(self, maxp=None): ap = to_Lf(f.modular_symbols(1).eigenvalue(p, name)) G_ps = ap.matrix().charpoly() - b *= ZZ(Qe(G_ps(1 + to_Lf(eps(p))*p)).norm()) + b *= ZZ(Qe(G_ps(1 + to_Lf(eps(p)) * p)).norm()) else: ap = f.modular_symbols(1).eigenvalue(p) - b *= ZZ(1 + eps(p)*p - ap) + b *= ZZ(1 + eps(p) * p - ap) if bnd == 0: bnd = b @@ -638,8 +636,7 @@ def multiple_of_order_using_frobp(self, maxp=None): # maxp is given -- record new info we get as # a gcd... try: - self.__multiple_of_order_using_frobp = \ - gcd(self.__multiple_of_order_using_frobp, bnd) + self.__multiple_of_order_using_frobp = gcd(self.__multiple_of_order_using_frobp, bnd) except AttributeError: # ... except in the case when # self.__multiple_of_order_using_frobp was never set. In this diff --git a/src/sage/modular/all.py b/src/sage/modular/all.py index 0eeb5e273a1..553400a5b8c 100644 --- a/src/sage/modular/all.py +++ b/src/sage/modular/all.py @@ -10,18 +10,13 @@ from sage.modular.abvar.all import * -from sage.modular.dirichlet import (DirichletGroup, - kronecker_character, kronecker_character_upside_down, - trivial_character) +from sage.modular.dirichlet import DirichletGroup, kronecker_character, kronecker_character_upside_down, trivial_character -from sage.modular.arithgroup.all import (Gamma0, Gamma1, GammaH, Gamma, SL2Z, - ArithmeticSubgroup_Permutation, - CongruenceSubgroup, FareySymbol) +from sage.modular.arithgroup.all import Gamma0, Gamma1, GammaH, Gamma, SL2Z, ArithmeticSubgroup_Permutation, CongruenceSubgroup, FareySymbol from sage.modular.cusps import Cusp, Cusps -from sage.modular.etaproducts import (EtaGroup, EtaProduct, EtaGroupElement, - AllCusps, CuspFamily) +from sage.modular.etaproducts import EtaGroup, EtaProduct, EtaGroupElement, AllCusps, CuspFamily lazy_import('sage.modular.multiple_zeta', ['Multizeta', 'Multizetas']) diff --git a/src/sage/modular/arithgroup/all.py b/src/sage/modular/arithgroup/all.py index 7ebb932e45d..fdfbfc3e8d9 100644 --- a/src/sage/modular/arithgroup/all.py +++ b/src/sage/modular/arithgroup/all.py @@ -7,11 +7,11 @@ from sage.modular.arithgroup.congroup_sl2z import SL2Z, SL2Z_class from sage.misc.lazy_import import lazy_import + lazy_import('sage.modular.arithgroup.arithgroup_perm', 'ArithmeticSubgroup_Permutation') -from sage.modular.arithgroup.congroup import ( - degeneracy_coset_representatives_gamma0, - degeneracy_coset_representatives_gamma1) +from sage.modular.arithgroup.congroup import degeneracy_coset_representatives_gamma0, degeneracy_coset_representatives_gamma1 from sage.modular.arithgroup.farey_symbol import Farey as FareySymbol + del lazy_import diff --git a/src/sage/modular/arithgroup/arithgroup_generic.py b/src/sage/modular/arithgroup/arithgroup_generic.py index 8adf92aded8..a688be8f6d6 100644 --- a/src/sage/modular/arithgroup/arithgroup_generic.py +++ b/src/sage/modular/arithgroup/arithgroup_generic.py @@ -151,7 +151,7 @@ def __contains__(self, x) -> bool: if not all(y in ZZ for y in x): return False a, b, c, d = map(ZZ, x) - if a*d - b*c != 1: + if a * d - b * c != 1: return False return self._contains_sl2(a, b, c, d) if parent(x) is not SL2Z: @@ -340,16 +340,16 @@ def todd_coxeter(self, G=None, on_right=True): l = SL2Z([1, 1, 0, 1]) s = SL2Z([0, -1, 1, 0]) - reps = [one] # coset representatives + reps = [one] # coset representatives reps_inv = {one: 0} # coset representatives index l_wait_back = [one] # rep with no incoming s_edge s_wait_back = [one] # rep with no incoming l_edge - l_wait = [one] # rep with no outgoing l_edge - s_wait = [one] # rep with no outgoing s_edge + l_wait = [one] # rep with no outgoing l_edge + s_wait = [one] # rep with no outgoing s_edge - l_edges = [None] # edges for l - s_edges = [None] # edges for s + l_edges = [None] # edges for l + s_edges = [None] # edges for s gens = [] @@ -360,15 +360,15 @@ def todd_coxeter(self, G=None, on_right=True): not_end = True while not_end: if on_right: - y = y*l + y = y * l else: - y = l*y + y = l * y for i in range(len(l_wait_back)): v = l_wait_back[i] if on_right: - yy = y*~v + yy = y * ~v else: - yy = ~v*y + yy = ~v * y if yy in self: l_edges[reps_inv[x]] = reps_inv[v] del l_wait_back[i] @@ -392,15 +392,15 @@ def todd_coxeter(self, G=None, on_right=True): not_end = True while not_end: if on_right: - y = y*s + y = y * s else: - y = s*y + y = s * y for i in range(len(s_wait_back)): v = s_wait_back[i] if on_right: - yy = y*~v + yy = y * ~v else: - yy = ~v*y + yy = ~v * y if yy in self: s_edges[reps_inv[x]] = reps_inv[v] del s_wait_back[i] @@ -445,6 +445,7 @@ def nu2(self) -> int: from sage.modular.arithgroup.congroup_gamma0 import Gamma0_constructor as Gamma0 from sage.modular.arithgroup.congroup_generic import CongruenceSubgroupBase + if isinstance(self, CongruenceSubgroupBase): if self.is_subgroup(Gamma0(self.level())) and Gamma0(self.level()).nu2() == 0: return 0 @@ -486,6 +487,7 @@ def nu3(self): # then self has no elliptic points either. from .all import CongruenceSubgroupBase, Gamma0 + if isinstance(self, CongruenceSubgroupBase): if self.is_subgroup(Gamma0(self.level())) and Gamma0(self.level()).nu3() == 0: return 0 @@ -645,6 +647,7 @@ def order(self): +Infinity """ from sage.rings.infinity import infinity + return infinity def reduce_cusp(self, c): @@ -697,14 +700,14 @@ def cusps(self, algorithm='default'): self._cusp_list = {} from .congroup_sl2z import SL2Z_class + if algorithm == 'default': if isinstance(self, SL2Z_class): s = [Cusp(1, 0)] else: s = self._find_cusps() elif algorithm == 'modsym': - s = sorted(self.reduce_cusp(c) - for c in self.modular_symbols().cusps()) + s = sorted(self.reduce_cusp(c) for c in self.modular_symbols().cusps()) else: raise ValueError("unknown algorithm: %s" % algorithm) @@ -775,22 +778,22 @@ def are_equivalent(self, x, y, trans=False): except NotImplementedError: pass - vx = lift_to_sl2z(x.numerator(),x.denominator(), 0) + vx = lift_to_sl2z(x.numerator(), x.denominator(), 0) dx = SL2Z([vx[2], -vx[0], vx[3], -vx[1]]) - vy = lift_to_sl2z(y.numerator(),y.denominator(), 0) + vy = lift_to_sl2z(y.numerator(), y.denominator(), 0) dy = SL2Z([vy[2], -vy[0], vy[3], -vy[1]]) for i in range(self.index()): # Note that the width of any cusp is bounded above by the index of self. # If self is congruence, then the level of self is a much better bound, but # this method is written to work with non-congruence subgroups as well, - if dy * SL2Z([1,i,0,1])*(~dx) in self: + if dy * SL2Z([1, i, 0, 1]) * (~dx) in self: if trans: - return dy * SL2Z([1,i,0,1]) * ~dx + return dy * SL2Z([1, i, 0, 1]) * ~dx return True - if (self.is_odd() and dy * SL2Z([-1,-i,0,-1]) * ~dx in self): + if self.is_odd() and dy * SL2Z([-1, -i, 0, -1]) * ~dx in self: if trans: - return dy * SL2Z([-1,-i,0,-1]) * ~dx + return dy * SL2Z([-1, -i, 0, -1]) * ~dx return True return False @@ -814,9 +817,9 @@ def cusp_data(self, c) -> tuple: w = lift_to_sl2z(c.denominator(), c.numerator(), 0) g = SL2Z([w[3], w[1], w[2], w[0]]) - for d in range(1,1+self.index()): + for d in range(1, 1 + self.index()): if g * SL2Z([1, d, 0, 1]) * (~g) in self: - return (g * SL2Z([1,d,0,1]) * (~g), d, 1) + return (g * SL2Z([1, d, 0, 1]) * (~g), d, 1) if g * SL2Z([-1, -d, 0, -1]) * (~g) in self: return (g * SL2Z([-1, -d, 0, -1]) * (~g), d, -1) raise ArithmeticError("Can't get here!") @@ -955,7 +958,7 @@ def genus(self): sage: [n for n in [1..200] if Gamma0(n).genus() == 1] [11, 14, 15, 17, 19, 20, 21, 24, 27, 32, 36, 49] """ - return ZZ(1 + (self.projective_index()) / ZZ(12) - (self.nu2())/ZZ(4) - (self.nu3())/ZZ(3) - self.ncusps()/ZZ(2)) + return ZZ(1 + (self.projective_index()) / ZZ(12) - (self.nu2()) / ZZ(4) - (self.nu3()) / ZZ(3) - self.ncusps() / ZZ(2)) def farey_symbol(self): r""" @@ -970,6 +973,7 @@ def farey_symbol(self): FareySymbol(Congruence Subgroup Gamma1(4)) """ from .farey_symbol import Farey + return Farey(self) @cached_method @@ -1182,7 +1186,7 @@ def dimension_cusp_forms(self, k=2): if k == 2: return self.genus() - return (k-1) * (self.genus() - 1) + (k // ZZ(4))*self.nu2() + (k // ZZ(3))*self.nu3() + (k // ZZ(2) - 1)*self.ncusps() + return (k - 1) * (self.genus() - 1) + (k // ZZ(4)) * self.nu2() + (k // ZZ(3)) * self.nu3() + (k // ZZ(2) - 1) * self.ncusps() # k odd @@ -1193,8 +1197,8 @@ def dimension_cusp_forms(self, k=2): e_irr = self.nirregcusps() if k > 1: - return (k-1)*(self.genus()-1) + (k // ZZ(3)) * self.nu3() + (k-2)/ZZ(2) * e_reg + (k-1)/ZZ(2) * e_irr - if e_reg > 2*self.genus() - 2: + return (k - 1) * (self.genus() - 1) + (k // ZZ(3)) * self.nu3() + (k - 2) / ZZ(2) * e_reg + (k - 1) / ZZ(2) * e_irr + if e_reg > 2 * self.genus() - 2: return ZZ.zero() raise NotImplementedError("Computation of dimensions of weight 1 cusp forms spaces not implemented in general") @@ -1276,12 +1280,14 @@ def as_permutation_group(self): from sage.modular.arithgroup.arithgroup_perm import ( EvenArithmeticSubgroup_Permutation, ) - g = EvenArithmeticSubgroup_Permutation(S2=s2_edges,S3=s3_edges,L=l_edges,R=r_edges) + + g = EvenArithmeticSubgroup_Permutation(S2=s2_edges, S3=s3_edges, L=l_edges, R=r_edges) else: from sage.modular.arithgroup.arithgroup_perm import ( OddArithmeticSubgroup_Permutation, ) - g = OddArithmeticSubgroup_Permutation(S2=s2_edges,S3=s3_edges,L=l_edges,R=r_edges) + + g = OddArithmeticSubgroup_Permutation(S2=s2_edges, S3=s3_edges, L=l_edges, R=r_edges) g.relabel() return g diff --git a/src/sage/modular/arithgroup/arithgroup_perm.py b/src/sage/modular/arithgroup/arithgroup_perm.py index 1c7ad6f9e8d..861345e171b 100644 --- a/src/sage/modular/arithgroup/arithgroup_perm.py +++ b/src/sage/modular/arithgroup/arithgroup_perm.py @@ -112,17 +112,17 @@ from sage.modular.arithgroup.congroup_sl2z import SL2Z from sage.rings.integer_ring import ZZ -Idm = SL2Z([1,0,0,1]) # identity +Idm = SL2Z([1, 0, 0, 1]) # identity -Lm = SL2Z([1,1,0,1]) # parabolic that fixes infinity -Rm = SL2Z([1,0,1,1]) # parabolic that fixes 0 -S2m = SL2Z([0,-1,1,0]) # elliptic of order 2 (fix i) -S3m = SL2Z([0,1,-1,1]) # elliptic of order 3 (fix j) +Lm = SL2Z([1, 1, 0, 1]) # parabolic that fixes infinity +Rm = SL2Z([1, 0, 1, 1]) # parabolic that fixes 0 +S2m = SL2Z([0, -1, 1, 0]) # elliptic of order 2 (fix i) +S3m = SL2Z([0, 1, -1, 1]) # elliptic of order 3 (fix j) -S2mi = SL2Z([0,1,-1,0]) # the inverse of S2m in SL(2,Z) -S3mi = SL2Z([1,-1,1,0]) # the inverse of S3m in SL(2,Z) -Lmi = SL2Z([1,-1,0,1]) # the inverse of Lm in SL(2,Z) -Rmi = SL2Z([1,0,-1,1]) # the inverse of Rm in SL(2,Z) +S2mi = SL2Z([0, 1, -1, 0]) # the inverse of S2m in SL(2,Z) +S3mi = SL2Z([1, -1, 1, 0]) # the inverse of S3m in SL(2,Z) +Lmi = SL2Z([1, -1, 0, 1]) # the inverse of Lm in SL(2,Z) +Rmi = SL2Z([1, 0, -1, 1]) # the inverse of Rm in SL(2,Z) def sl2z_word_problem(A): @@ -153,49 +153,49 @@ def sl2z_word_problem(A): # If A00 is zero if A[0, 0] == 0: - c = A[1,1] + c = A[1, 1] if c != 1: - A = A*Lm**(c-1)*Rm*Lmi - output.extend([(0,1-c),(1,-1),(0,1)]) + A = A * Lm ** (c - 1) * Rm * Lmi + output.extend([(0, 1 - c), (1, -1), (0, 1)]) else: - A = A*Rm*Lmi - output.extend([(1,-1),(0,1)]) + A = A * Rm * Lmi + output.extend([(1, -1), (0, 1)]) - if A[0, 0] < 0: # Make sure A00 is positive - A = SL2Z(-1)*A - output.extend([(1,-1), (0,1), (1,-1), (0,1), (1,-1), (0,1)]) + if A[0, 0] < 0: # Make sure A00 is positive + A = SL2Z(-1) * A + output.extend([(1, -1), (0, 1), (1, -1), (0, 1), (1, -1), (0, 1)]) - if A[0,1] < 0: # if A01 is negative make it positive - n = (-A[0,1]/A[0,0]).ceil() # n s.t. 0 <= A[0,1]+n*A[0,0] < A[0,0] - A = A*Lm**n + if A[0, 1] < 0: # if A01 is negative make it positive + n = (-A[0, 1] / A[0, 0]).ceil() # n s.t. 0 <= A[0,1]+n*A[0,0] < A[0,0] + A = A * Lm**n output.append((0, -n)) # At this point A00>0 and A01>=0 - while not (A[0,0] == 0 or A[0,1] == 0): - if A[0,0] > A[0,1]: - n = (A[0,0]/A[0,1]).floor() - A = A*SL2Z([1,0,-n,1]) + while not (A[0, 0] == 0 or A[0, 1] == 0): + if A[0, 0] > A[0, 1]: + n = (A[0, 0] / A[0, 1]).floor() + A = A * SL2Z([1, 0, -n, 1]) output.append((1, n)) - else: # A[0,0]<=A[0,1] - n = (A[0,1]/A[0,0]).floor() - A = A*SL2Z([1,-n,0,1]) + else: # A[0,0]<=A[0,1] + n = (A[0, 1] / A[0, 0]).floor() + A = A * SL2Z([1, -n, 0, 1]) output.append((0, n)) if A == SL2Z.one(): - pass # done, so don't add R^0 + pass # done, so don't add R^0 elif A[0, 0] == 0: c = A[1, 1] if c != 1: - A = A*Lm**(c-1)*Rm*Lmi - output.extend([(0,1-c),(1,-1),(0, 1)]) + A = A * Lm ** (c - 1) * Rm * Lmi + output.extend([(0, 1 - c), (1, -1), (0, 1)]) else: - A = A*Rm*Lmi - output.extend([(1,-1),(0,1)]) + A = A * Rm * Lmi + output.extend([(1, -1), (0, 1)]) else: - c = A[1,0] + c = A[1, 0] if c: - A = A*Rm**(-c) - output.append((1,c)) + A = A * Rm ** (-c) + output.append((1, c)) output.reverse() return output @@ -216,7 +216,7 @@ def eval_sl2z_word(w): mat = [Lm, Rm] w0 = Idm w1 = w - return w0 * prod((mat[a[0]]**a[1] for a in w1), Idm) + return w0 * prod((mat[a[0]] ** a[1] for a in w1), Idm) def word_of_perms(w, p1, p2): @@ -242,7 +242,7 @@ def word_of_perms(w, p1, p2): p2 = PermutationConstructor(p2) G = p1.parent() - if G != p2.parent(): # find a minimal parent + if G != p2.parent(): # find a minimal parent G2 = p2.parent() if G.has_coerce_map_from(G2): p2 = G(p2) @@ -250,16 +250,16 @@ def word_of_perms(w, p1, p2): G = G2 p1 = G(p1) else: - G = PermutationGroup([p1,p2]) + G = PermutationGroup([p1, p2]) p1 = G(p1) p2 = G(p2) M = G.identity() p = [p1, p2] - m = [p1.order(),p2.order()] + m = [p1.order(), p2.order()] - for i,j in w: - M *= p[i]**(j % m[i]) + for i, j in w: + M *= p[i] ** (j % m[i]) return M @@ -279,22 +279,20 @@ def _equalize_perms(l): sage: l [[0, 1, 2, 3], [1, 0, 2, 3], [3, 0, 1, 2]] """ - n = max(map(len,l)) + n = max(map(len, l)) if n == 0: n = 1 for p in l: p.extend(list(range(len(p), n))) + # Tedious point: in order to unpickle pickled objects from prior to patch # #11422, this function needs to accept two non-keyword arguments, to be # interpreted as L and R. Hence the order of the arguments is slightly # different from the class __init__ methods. -def ArithmeticSubgroup_Permutation( - L=None, R=None, S2=None, S3=None, - relabel=False, - check=True): +def ArithmeticSubgroup_Permutation(L=None, R=None, S2=None, S3=None, relabel=False, check=True): r""" Construct a subgroup of `\SL_2(\ZZ)` from the action of generators on its right cosets. @@ -378,49 +376,49 @@ def ArithmeticSubgroup_Permutation( L=(1,2)(3,5,4) R=(1,2)(3,4,5) """ - gens = [x for x in [S2,S3,L,R] if x is not None] + gens = [x for x in [S2, S3, L, R] if x is not None] if len(gens) == 0: S2 = S3 = L = R = '' elif len(gens) < 2: raise ValueError("Need at least two generators") if S2 is not None: - S2 = PermutationConstructor(S2,check=check) + S2 = PermutationConstructor(S2, check=check) if S3 is not None: - S3 = PermutationConstructor(S3,check=check) + S3 = PermutationConstructor(S3, check=check) if L is not None: - L = PermutationConstructor(L,check=check) + L = PermutationConstructor(L, check=check) if R is not None: - R = PermutationConstructor(R,check=check) + R = PermutationConstructor(R, check=check) if L is not None: - if R is not None: # initialize from L,R + if R is not None: # initialize from L,R if S2 is None: S2 = R * ~L * R if S3 is None: S3 = L * ~R - elif S2 is not None: # initialize from L,S2 + elif S2 is not None: # initialize from L,S2 if S3 is None: S3 = ~S2 * ~L if R is None: R = ~S2 * ~L * S2 - elif S3 is not None: # initialize from L,S3 + elif S3 is not None: # initialize from L,S3 if S2 is None: S2 = ~L * ~S3 if R is None: R = S3 * ~L * ~S3 elif R is not None: - if S2 is not None: # initialize from R, S2 + if S2 is not None: # initialize from R, S2 if L is None: L = ~S2 * ~R * S2 if S3 is None: S3 = R * ~S2 - elif S3 is not None: # initialize from R, S3 + elif S3 is not None: # initialize from R, S3 if L is None: L = ~S3 * ~R * S3 if S2 is None: S2 = ~S3 * R - else: # initialize from S2, S3 + else: # initialize from S2, S3 if L is None: L = ~S3 * ~S2 if R is None: @@ -429,12 +427,12 @@ def ArithmeticSubgroup_Permutation( if check and (L != ~S3 * ~S2 or R != S3 * S2): raise ValueError("Wrong relations between generators") - inv = S2*S2 + inv = S2 * S2 if check: - if inv != S3*S3*S3: + if inv != S3 * S3 * S3: raise ValueError("S2^2 does not equal to S3^3") - elif not (inv*inv).is_one(): + elif not (inv * inv).is_one(): raise ValueError("S2^2 = S3^3 must have order 1 or 2") # Check transitivity. This is the most expensive check, so we do it @@ -443,16 +441,16 @@ def ArithmeticSubgroup_Permutation( if not G.is_transitive(): raise ValueError("Permutations do not generate a transitive group") - s2 = [i-1 for i in S2.domain()] - s3 = [i-1 for i in S3.domain()] - l = [i-1 for i in L.domain()] - r = [i-1 for i in R.domain()] - _equalize_perms((s2,s3,l,r)) + s2 = [i - 1 for i in S2.domain()] + s3 = [i - 1 for i in S3.domain()] + l = [i - 1 for i in L.domain()] + r = [i - 1 for i in R.domain()] + _equalize_perms((s2, s3, l, r)) - if inv.is_one(): # the group is even - G = EvenArithmeticSubgroup_Permutation(s2,s3,l,r) - else: # the group is odd - G = OddArithmeticSubgroup_Permutation(s2,s3,l,r) + if inv.is_one(): # the group is even + G = EvenArithmeticSubgroup_Permutation(s2, s3, l, r) + else: # the group is odd + G = OddArithmeticSubgroup_Permutation(s2, s3, l, r) if relabel: G.relabel() @@ -530,10 +528,7 @@ def __eq__(self, other): True """ if isinstance(other, ArithmeticSubgroup_Permutation_class): - return (self.is_odd() == other.is_odd() and - self.index() == other.index() and - self.relabel(inplace=False)._S2 == other.relabel(inplace=False)._S2 and - self.relabel(inplace=False)._S3 == other.relabel(inplace=False)._S3) + return self.is_odd() == other.is_odd() and self.index() == other.index() and self.relabel(inplace=False)._S2 == other.relabel(inplace=False)._S2 and self.relabel(inplace=False)._S3 == other.relabel(inplace=False)._S3 if isinstance(other, ArithmeticSubgroup): return self == other.as_permutation_group() @@ -575,8 +570,7 @@ def __hash__(self): sage: hash(G1) == hash(G2) False """ - return hash((tuple(self.relabel(inplace=False)._S2), - tuple(self.relabel(inplace=False)._S3))) + return hash((tuple(self.relabel(inplace=False)._S2), tuple(self.relabel(inplace=False)._S3))) def _repr_(self): r""" @@ -592,8 +586,7 @@ def _repr_(self): 'Arithmetic subgroup of index 24' """ if self.index() < 20: - return "Arithmetic subgroup with permutations of right cosets\n S2=%s\n S3=%s\n L=%s\n R=%s" % ( - self.S2(), self.S3(), self.L(), self.R()) + return "Arithmetic subgroup with permutations of right cosets\n S2=%s\n S3=%s\n L=%s\n R=%s" % (self.S2(), self.S3(), self.L(), self.R()) return "Arithmetic subgroup of index %d" % self.index() @@ -615,7 +608,7 @@ def S2(self): sage: G.S2() (1,2) """ - return PermutationConstructor([i+1 for i in self._S2], check=False) + return PermutationConstructor([i + 1 for i in self._S2], check=False) def S3(self): r""" @@ -632,7 +625,7 @@ def S3(self): (1,2,3) """ - return PermutationConstructor([i+1 for i in self._S3], check=False) + return PermutationConstructor([i + 1 for i in self._S3], check=False) def L(self): r""" @@ -648,7 +641,7 @@ def L(self): sage: G.L() (1,3) """ - return PermutationConstructor([i+1 for i in self._L], check=False) + return PermutationConstructor([i + 1 for i in self._L], check=False) def R(self): r""" @@ -664,7 +657,7 @@ def R(self): sage: G.R() (2,3) """ - return PermutationConstructor([i+1 for i in self._R], check=False) + return PermutationConstructor([i + 1 for i in self._R], check=False) def perm_group(self): r""" @@ -818,7 +811,7 @@ def relabel(self, inplace=True): sage: G.relabel(inplace=False) is G True """ - if hasattr(self,'_canonical_label_group'): + if hasattr(self, '_canonical_label_group'): if inplace: if self is not self._canonical_label_group: self.__dict__ = self._canonical_label_group.__dict__ @@ -830,6 +823,7 @@ def relabel(self, inplace=True): G = self else: from copy import deepcopy + G = deepcopy(self) n = G.index() @@ -838,10 +832,10 @@ def relabel(self, inplace=True): S3 = G._S3 L = G._L R = G._R - G._S2 = [None]*n - G._S3 = [None]*n - G._L = [None]*n - G._R = [None]*n + G._S2 = [None] * n + G._S3 = [None] * n + G._L = [None] * n + G._R = [None] * n for i in range(n): G._S2[mapping[i]] = mapping[S2[i]] @@ -905,21 +899,20 @@ def _canonical_unrooted_labels(self): S3_test = [None] * n m_win = self._canonical_rooted_labels(0) - for i in range(n): # conjugation + for i in range(n): # conjugation S2_win[m_win[i]] = m_win[self._S2[i]] S3_win[m_win[i]] = m_win[self._S3[i]] - for j0 in range(1,self.index()): + for j0 in range(1, self.index()): m_test = self._canonical_rooted_labels(j0) for i in range(n): S2_test[m_test[i]] = m_test[self._S2[i]] S3_test[m_test[i]] = m_test[self._S3[i]] - for i in range(n-1): - if (S2_test[i] < S2_win[i] or - (S2_test[i] == S2_win[i] and S3_test[i] < S3_win[i])): - S2_win,S2_test = S2_test,S2_win - S3_win,S3_test = S3_test,S3_win + for i in range(n - 1): + if S2_test[i] < S2_win[i] or (S2_test[i] == S2_win[i] and S3_test[i] < S3_win[i]): + S2_win, S2_test = S2_test, S2_win + S3_win, S3_test = S3_test, S3_win m_win = m_test break @@ -1004,16 +997,16 @@ def _index_to_lr_cusp_width(self): G = self.relabel(inplace=False) l = G.L() - l_cycle_length = [None]*self.index() + l_cycle_length = [None] * self.index() for c in l.cycle_tuples(singletons=True): for i in c: - l_cycle_length[i-1] = len(c) + l_cycle_length[i - 1] = len(c) r = G.R() - r_cycle_length = [None]*self.index() + r_cycle_length = [None] * self.index() for c in r.cycle_tuples(singletons=True): for i in c: - r_cycle_length[i-1] = len(c) + r_cycle_length[i - 1] = len(c) return (l_cycle_length, r_cycle_length) @@ -1043,13 +1036,13 @@ def _contains_sl2(self, a, b, c, d): sage: m4 in P False """ - w = sl2z_word_problem([a,b,c,d]) + w = sl2z_word_problem([a, b, c, d]) - perms = [self.relabel(inplace=False)._L,self.relabel(inplace=False)._R] + perms = [self.relabel(inplace=False)._L, self.relabel(inplace=False)._R] widths = self._index_to_lr_cusp_width() k = 0 - for (i,j) in w: + for i, j in w: for _ in range(j % widths[i][k]): k = perms[i][k] @@ -1078,22 +1071,22 @@ def random_element(self, initial_steps=30): i = 0 m = SL2Z(1) for _ in range(initial_steps): - j = randint(0,1) + j = randint(0, 1) if j == 0: i = self._S2[i] - m = m*S2m + m = m * S2m else: i = self._S3[i] - m = m*S3m + m = m * S3m while i != 0: - j = randint(0,1) + j = randint(0, 1) if j == 0: i = self._S2[i] - m = m*S2m + m = m * S2m else: i = self._S3[i] - m = m*S3m + m = m * S3m return m @@ -1170,10 +1163,10 @@ def _conjugate(self, j0): s3 = self._S3 l = self._L r = self._R - ss2 = [None]*N - ss3 = [None]*N - ll = [None]*N - rr = [None]*N + ss2 = [None] * N + ss3 = [None] * N + ll = [None] * N + rr = [None] * N m = self._canonical_rooted_labels(j0) for i in range(N): @@ -1181,12 +1174,9 @@ def _conjugate(self, j0): ss3[m[i]] = m[s3[i]] ll[m[i]] = m[l[i]] rr[m[i]] = m[r[i]] - return self.__class__(ss2,ss3,ll,rr,True) + return self.__class__(ss2, ss3, ll, rr, True) - def coset_graph(self, - right_cosets=False, - s2_edges=True, s3_edges=True, l_edges=False, r_edges=False, - s2_label='s2', s3_label='s3', l_label='l', r_label='r'): + def coset_graph(self, right_cosets=False, s2_edges=True, s3_edges=True, l_edges=False, r_edges=False, s2_label='s2', s3_label='s3', l_label='l', r_label='r'): r""" Return the right (or left) coset graph. @@ -1221,14 +1211,15 @@ def coset_graph(self, Looped multi-digraph on 2 vertices """ from sage.graphs.digraph import DiGraph + res = DiGraph(multiedges=True, loops=True) res.add_vertices(list(range(self.index()))) if right_cosets: # invert the permutations - S2 = [None]*self.index() - S3 = [None]*self.index() - L = [None]*self.index() - R = [None]*self.index() + S2 = [None] * self.index() + S3 = [None] * self.index() + L = [None] * self.index() + R = [None] * self.index() for i in range(self.index()): S2[self._S2[i]] = i S3[self._S3[i]] = i @@ -1255,15 +1246,15 @@ def coset_graph(self, if l_edges: if l_label is not None: - res.add_edges((i,L[i],l_label) for i in range(self.index())) + res.add_edges((i, L[i], l_label) for i in range(self.index())) else: - res.add_edges((i,L[i]) for i in range(self.index())) + res.add_edges((i, L[i]) for i in range(self.index())) if r_edges: if r_label is not None: - res.add_edges((i,R[i],r_label) for i in range(self.index())) + res.add_edges((i, R[i], r_label) for i in range(self.index())) else: - res.add_edges((i,R[i]) for i in range(self.index())) + res.add_edges((i, R[i]) for i in range(self.index())) res.plot.options['color_by_label'] = True @@ -1325,9 +1316,10 @@ def congruence_closure(self): if self.is_even(): N = self.generalised_level() else: - N = 2*self.generalised_level() + N = 2 * self.generalised_level() from .congroup_generic import CongruenceSubgroup_constructor as CS + return CS(N, [x.matrix() for x in self.gens()]) def is_congruence(self) -> bool: @@ -1431,6 +1423,7 @@ def is_congruence(self) -> bool: True """ from sage.misc.verbose import verbose + if self.index() == 1: # the group is SL2Z (trivial case) return True @@ -1450,26 +1443,26 @@ def is_congruence(self) -> bool: # N is odd # this only gets called if self is even onehalf = ZZ(2).inverse_mod(N) # i.e. 2^(-1) mod N - rel = (R*R*L**(-onehalf))**3 + rel = (R * R * L ** (-onehalf)) ** 3 return rel.is_one() if m == 1: # N is a power of 2 onefifth = ZZ(5).inverse_mod(N) # i.e. 5^(-1) mod N - S = L**20*R**onefifth*L**(-4)*~R + S = L**20 * R**onefifth * L ** (-4) * ~R # congruence if the three below permutations are trivial - rel = (~L*R*~L) * S * (L*~R*L) * S + rel = (~L * R * ~L) * S * (L * ~R * L) * S if not rel.is_one(): verbose("Failed relation A1") return False - rel = ~S*R*S*R**(-25) + rel = ~S * R * S * R ** (-25) if not rel.is_one(): verbose("Failed relation A2") return False - rel = (S*R**5*L*~R*L)**3 * ~(L * ~R * L)**2 + rel = (S * R**5 * L * ~R * L) ** 3 * ~((L * ~R * L) ** 2) if not rel.is_one(): verbose("Failed relation A3") return False @@ -1477,48 +1470,48 @@ def is_congruence(self) -> bool: return True # e>1, m>1 - onehalf = ZZ(2).inverse_mod(m) # i.e. 2^(-1) mod m - onefifth = ZZ(5).inverse_mod(e) # i.e. 5^(-1) mod e + onehalf = ZZ(2).inverse_mod(m) # i.e. 2^(-1) mod m + onefifth = ZZ(5).inverse_mod(e) # i.e. 5^(-1) mod e c, d = CRT_basis([m, e]) # c=0 mod e, c=1 mod m; d=1 mod e, d=0 mod m a = L**c b = R**c l = L**d r = R**d - s = l**20 * r**onefifth * l**(-4) * ~r + s = l**20 * r**onefifth * l ** (-4) * ~r # Congruence if the seven permutations below are trivial: - rel = ~a*~r*a*r + rel = ~a * ~r * a * r if not rel.is_one(): verbose("Failed relation B1") return False - rel = (a*~b*a)**4 + rel = (a * ~b * a) ** 4 if not rel.is_one(): verbose("Failed relation B2") return False - rel = (a*~b*a)**2*(~a*b)**3 + rel = (a * ~b * a) ** 2 * (~a * b) ** 3 if not rel.is_one(): verbose("Failed relation B3") return False - rel = (a*~b*a)**2*(b*b*a**(-onehalf))**(-3) + rel = (a * ~b * a) ** 2 * (b * b * a ** (-onehalf)) ** (-3) if not rel.is_one(): verbose("Failed relation B4") return False - rel = (~l*r*~l)*s*(l*~r*l)*s + rel = (~l * r * ~l) * s * (l * ~r * l) * s if not rel.is_one(): verbose("Failed relation B5") return False - rel = ~s*r*s*r**(-25) + rel = ~s * r * s * r ** (-25) if not rel.is_one(): verbose("Failed relation B6") return False - rel = (l*~r*l)**2*(s*r**5*l*~r*l)**(-3) + rel = (l * ~r * l) ** 2 * (s * r**5 * l * ~r * l) ** (-3) if not rel.is_one(): verbose("Failed relation B7") return False @@ -1556,6 +1549,7 @@ def surgroups(self): [6, 3, 4, 8, 4, 8, 4, 12, 4, 6, 6, 8, 8] """ from sage.libs.gap.libgap import libgap + P = libgap(self.perm_group()) for b in P.AllBlocks(): orbit = P.Orbit(b, libgap.OnSets) @@ -1620,12 +1614,11 @@ def __reduce__(self): sage: GG.relabel(inplace=False) is GG True """ - if hasattr(self,'_canonical_label_group'): - canonical_labels = (self is self._canonical_label_group) + if hasattr(self, '_canonical_label_group'): + canonical_labels = self is self._canonical_label_group else: canonical_labels = False - return (OddArithmeticSubgroup_Permutation, - (self._S2,self._S3,self._L,self._R,canonical_labels)) + return (OddArithmeticSubgroup_Permutation, (self._S2, self._S3, self._L, self._R, canonical_labels)) def is_odd(self) -> bool: r""" @@ -1680,29 +1673,29 @@ def to_even_subgroup(self, relabel=True): # build equivalence classes in e s2 = self._S2 e = [] - e2i = [None]*N + e2i = [None] * N for i in range(N): j = s2[s2[i]] if i < j: e2i[i] = e2i[j] = len(e) - e.append((i,j)) + e.append((i, j)) # build the quotient permutations - ss2 = [None]*(N//2) - ss3 = [None]*(N//2) - ll = [None]*(N//2) - rr = [None]*(N//2) + ss2 = [None] * (N // 2) + ss3 = [None] * (N // 2) + ll = [None] * (N // 2) + rr = [None] * (N // 2) s3 = self._S3 l = self._L r = self._R - for (j0,j1) in e: + for j0, j1 in e: ss2[e2i[j0]] = e2i[s2[j0]] ss3[e2i[j0]] = e2i[s3[j0]] ll[e2i[j0]] = e2i[l[j0]] rr[e2i[j0]] = e2i[r[j0]] - G = EvenArithmeticSubgroup_Permutation(ss2,ss3,ll,rr) + G = EvenArithmeticSubgroup_Permutation(ss2, ss3, ll, rr) if relabel: G.relabel() return G @@ -1754,7 +1747,7 @@ def nirregcusps(self): sage: G.nirregcusps() 3 """ - inv = self.S2()**2 + inv = self.S2() ** 2 n = 0 for c in self.L().cycle_tuples(singletons=True): if inv(c[0]) in c: @@ -1774,12 +1767,12 @@ def nregcusps(self): sage: G.nregcusps() 2 """ - inv = self.S2()**2 + inv = self.S2() ** 2 n = 0 for c in self.L().cycle_tuples(singletons=True): if inv(c[0]) not in c: n += 1 - return n//2 + return n // 2 def cusp_widths(self, exp=False): r""" @@ -1799,7 +1792,7 @@ def cusp_widths(self, exp=False): sage: G.cusp_widths(exp=True) {1: 2, 5: 2} """ - inv = self.S2()**2 + inv = self.S2() ** 2 L = self.L() cusps = {c[0] for c in L.cycle_tuples(singletons=True)} if exp: @@ -1846,7 +1839,7 @@ def ncusps(self): sage: G.ncusps() 2 """ - inv = self.S2()**2 + inv = self.S2() ** 2 n = 0 m = 0 for c in self.L().cycle_tuples(singletons=True): @@ -1854,7 +1847,7 @@ def ncusps(self): n += 1 else: m += 1 - return n + m//2 + return n + m // 2 class EvenArithmeticSubgroup_Permutation(ArithmeticSubgroup_Permutation_class): @@ -1903,6 +1896,7 @@ class EvenArithmeticSubgroup_Permutation(ArithmeticSubgroup_Permutation_class): sage: G.genus() 0 """ + def __init__(self, S2, S3, L, R, canonical_labels=False): r""" TESTS:: @@ -1938,11 +1932,10 @@ def __reduce__(self): True """ if hasattr(self, '_canonical_label_group'): - canonical_labels = (self is self._canonical_label_group) + canonical_labels = self is self._canonical_label_group else: canonical_labels = False - return (EvenArithmeticSubgroup_Permutation, - (self._S2, self._S3, self._L, self._R, canonical_labels)) + return (EvenArithmeticSubgroup_Permutation, (self._S2, self._S3, self._L, self._R, canonical_labels)) def is_odd(self) -> bool: r""" @@ -2093,7 +2086,7 @@ def _spanning_tree_kulkarni(self, root=0, on_right=True): orientation = {x0: []} while True: # complete the current 3-loop in the tree - if s3[x0] != x0: # loop of length 3 + if s3[x0] != x0: # loop of length 3 x1 = s3[x0] x2 = s3[x1] orientation[x0].append(x1) @@ -2113,7 +2106,7 @@ def _spanning_tree_kulkarni(self, root=0, on_right=True): word_reps[x2] = ['s3'] + word_reps[x1] l.append(x1) l.append(x2) - else: # elliptic generator + else: # elliptic generator gens.append((x0, x0, 's3')) # now perform links with s while we find another guy @@ -2121,10 +2114,10 @@ def _spanning_tree_kulkarni(self, root=0, on_right=True): x1 = l.pop(randint(0, len(l) - 1)) x0 = s2[x1] - if x1 != x0: # loop of length 2 + if x1 != x0: # loop of length 2 if x0 in tree: gens.append((x1, x0, 's2')) - del l[l.index(x0)] # x0 must be in l + del l[l.index(x0)] # x0 must be in l else: orientation[x1].append(x0) orientation[x0] = [x1] @@ -2136,7 +2129,7 @@ def _spanning_tree_kulkarni(self, root=0, on_right=True): reps[x0] = S2m * reps[x1] word_reps[x0] = ['s2'] + word_reps[x1] break - else: # elliptic generator + else: # elliptic generator gens.append((x1, x1, 's2')) else: @@ -2208,18 +2201,19 @@ def _spanning_tree_verrill(self, root=0, on_right=True): s = self._S2 l = self._L else: - s = [None]*self.index() - l = [None]*self.index() + s = [None] * self.index() + l = [None] * self.index() for i in range(self.index()): s[self._S2[i]] = i l[self._L[i]] = i from sage.graphs.digraph import DiGraph - tree = DiGraph(multiedges=False,loops=False) + + tree = DiGraph(multiedges=False, loops=False) gens = [] - reps = [None]*self.index() - word_reps = [None]*self.index() + reps = [None] * self.index() + word_reps = [None] * self.index() reps[root] = SL2Z(1) word_reps[root] = '' @@ -2232,7 +2226,7 @@ def _spanning_tree_verrill(self, root=0, on_right=True): x = x0 xx = l[x] while xx != x0: - tree.add_edge(x,xx,'l') + tree.add_edge(x, xx, 'l') if on_right: reps[xx] = reps[x] * Lm word_reps[xx] = word_reps[x] + 'l' @@ -2243,24 +2237,24 @@ def _spanning_tree_verrill(self, root=0, on_right=True): x = xx xx = l[x] - gens.append((x,x0,'l')) + gens.append((x, x0, 'l')) # now perform links with s while we find another guy which will # become the new x0 while waiting: x0 = None while waiting and x0 is None: - x1 = waiting.pop(randint(0,len(waiting)-1)) + x1 = waiting.pop(randint(0, len(waiting) - 1)) x0 = s[x1] if x0 is not None: - if x1 != x0: # loop of length 2 + if x1 != x0: # loop of length 2 if x0 in tree: - gens.append((x1,x0,'s')) + gens.append((x1, x0, 's')) if x0 in waiting: - del waiting[waiting.index(x0)] # x0 must be in l + del waiting[waiting.index(x0)] # x0 must be in l else: - tree.add_edge(x1,x0,'s') + tree.add_edge(x1, x0, 's') if on_right: reps[x0] = reps[x1] * S2m word_reps[x0] = word_reps[x1] + 's' @@ -2268,13 +2262,13 @@ def _spanning_tree_verrill(self, root=0, on_right=True): reps[x0] = S2m * reps[x1] word_reps[x0] = 's' + word_reps[x1] break - else: # elliptic generator - gens.append((x1,x1,'s')) + else: # elliptic generator + gens.append((x1, x1, 's')) else: break - return tree, reps, word_reps,gens + return tree, reps, word_reps, gens def todd_coxeter_s2_s3(self): r""" @@ -2308,7 +2302,7 @@ def todd_coxeter_s2_s3(self): sage: all(reps[i]*S3*~reps[s3[i]] in G for i in range(4)) True """ - tree,reps,wreps,edges = self._spanning_tree_kulkarni() + tree, reps, wreps, edges = self._spanning_tree_kulkarni() gens = [] for e in edges: @@ -2358,7 +2352,7 @@ def todd_coxeter_l_s2(self): sage: all(reps[i]*L*~reps[l[i]] in G for i in range(4)) True """ - tree,reps,wreps,edges = self._spanning_tree_verrill() + tree, reps, wreps, edges = self._spanning_tree_verrill() gens = [] for e in edges: @@ -2416,7 +2410,7 @@ def cusp_widths(self, exp=False): sage: G.cusp_widths(exp=True) {6: 1} """ - seen = [True]*self.index() + seen = [True] * self.index() if exp: widths = {} @@ -2515,22 +2509,22 @@ def one_odd_subgroup(self, random=False): raise ValueError("Group contains an element of order 4, hence no index 2 odd subgroups") n = self.index() s2old, s3old = self.S2(), self.S3() - s2cycs = s2old.cycle_tuples() # no singletons can exist + s2cycs = s2old.cycle_tuples() # no singletons can exist s3cycs = s3old.cycle_tuples(singletons=True) s2 = PermutationConstructor([x + tuple(y + n for y in x) for x in s2cycs]) s3 = PermutationConstructor([x + tuple(y + n for y in x) for x in s3cycs]) if random is False: - return ArithmeticSubgroup_Permutation(S2=s2,S3=s3,check=False) + return ArithmeticSubgroup_Permutation(S2=s2, S3=s3, check=False) from sage.misc.prandom import randint t = [] - for i in range(1,n+1): - if randint(0,1): - t.append((i,n+i)) + for i in range(1, n + 1): + if randint(0, 1): + t.append((i, n + i)) t = PermutationConstructor(t) - return ArithmeticSubgroup_Permutation(S2=s2,S3=t*s3*t,check=False) + return ArithmeticSubgroup_Permutation(S2=s2, S3=t * s3 * t, check=False) def odd_subgroups(self): r""" @@ -2606,30 +2600,30 @@ def odd_subgroups(self): return [] n = self.index() s2old, s3old = self.S2(), self.S3() - s2cycs = s2old.cycle_tuples() # no singletons can exist + s2cycs = s2old.cycle_tuples() # no singletons can exist s3cycs = s3old.cycle_tuples(singletons=True) s2 = PermutationConstructor([x + tuple(y + n for y in x) for x in s2cycs]) s3 = PermutationConstructor([x + tuple(y + n for y in x) for x in s3cycs]) - H = ArithmeticSubgroup_Permutation(S2=s2,S3=s3) + H = ArithmeticSubgroup_Permutation(S2=s2, S3=s3) bucket = {H} res = [H] # We use a set *and* a list since checking whether an element is in a # set is very fast, but on the other hand we want the order the results # are returned to be at least somewhat canonical. - ts = [PermutationConstructor(list(range(1,1+2*n)))] + ts = [PermutationConstructor(list(range(1, 1 + 2 * n)))] - for i in range(1,n+1): + for i in range(1, n + 1): - t = PermutationConstructor([(i, n+i)], check=False) + t = PermutationConstructor([(i, n + i)], check=False) - s3c = t*s3*t + s3c = t * s3 * t if s3c == s3: # t commutes with s3; nothing to see here. continue - HH = ArithmeticSubgroup_Permutation(S2=s2,S3=s3c,check=False) + HH = ArithmeticSubgroup_Permutation(S2=s2, S3=s3c, check=False) if HH not in bucket: # Because the liftings are indexed by Hom(self, +-1) which is a @@ -2640,8 +2634,8 @@ def odd_subgroups(self): res.append(HH) ts.append(t) for tt in ts[1:-1]: - ts.append(tt*t) - res.append(ArithmeticSubgroup_Permutation(S2=s2,S3=tt*s3c*tt,check=False)) + ts.append(tt * t) + res.append(ArithmeticSubgroup_Permutation(S2=s2, S3=tt * s3c * tt, check=False)) bucket.add(res[-1]) return res @@ -2661,10 +2655,7 @@ def HsuExample10(): L=(1,4)(2,5,9,10,8)(3,7,6) R=(1,7,9,10,6)(2,3)(4,5,8) """ - return ArithmeticSubgroup_Permutation( - L="(1,4)(2,5,9,10,8)(3,7,6)", - R="(1,7,9,10,6)(2,3)(4,5,8)", - relabel=False) + return ArithmeticSubgroup_Permutation(L="(1,4)(2,5,9,10,8)(3,7,6)", R="(1,7,9,10,6)(2,3)(4,5,8)", relabel=False) def HsuExample18(): @@ -2681,7 +2672,4 @@ def HsuExample18(): L=(1,2)(3,4)(5,6,7)(8,9,10)(11,12,13,14,15,16,17,18) R=(1,12,18)(2,6,13,9,4,8,17,7)(3,16,14)(5,11)(10,15) """ - return ArithmeticSubgroup_Permutation( - L="(1,2)(3,4)(5,6,7)(8,9,10)(11,12,13,14,15,16,17,18)", - R="(1,12,18)(2,6,13,9,4,8,17,7)(3,16,14)(5,11)(10,15)", - relabel=False) + return ArithmeticSubgroup_Permutation(L="(1,2)(3,4)(5,6,7)(8,9,10)(11,12,13,14,15,16,17,18)", R="(1,12,18)(2,6,13,9,4,8,17,7)(3,16,14)(5,11)(10,15)", relabel=False) diff --git a/src/sage/modular/arithgroup/congroup_gamma.py b/src/sage/modular/arithgroup/congroup_gamma.py index 9ffb833ce94..f42f8f85c1a 100644 --- a/src/sage/modular/arithgroup/congroup_gamma.py +++ b/src/sage/modular/arithgroup/congroup_gamma.py @@ -64,6 +64,7 @@ class Gamma_class(CongruenceSubgroup): r""" The principal congruence subgroup `\Gamma(N)`. """ + def _repr_(self) -> str: """ Return the string representation of ``self``. @@ -135,7 +136,7 @@ def index(self): sage: Gamma(32041).index() 32893086819240 """ - return prod([p**(3*e-2)*(p*p-1) for (p,e) in self.level().factor()]) + return prod([p ** (3 * e - 2) * (p * p - 1) for (p, e) in self.level().factor()]) def _contains_sl2(self, a, b, c, d): r""" @@ -153,7 +154,7 @@ def _contains_sl2(self, a, b, c, d): """ N = self.level() # don't need to check d == 1 as this is automatic from det - return ((a % N == 1) and (b % N == 0) and (c % N == 0)) + return (a % N == 1) and (b % N == 0) and (c % N == 0) def ncusps(self): r""" @@ -173,7 +174,7 @@ def ncusps(self): return ZZ(1) if n == 2: return ZZ(3) - return prod([p**(2*e) - p**(2*e-2) for (p,e) in n.factor()])//2 + return prod([p ** (2 * e) - p ** (2 * e - 2) for (p, e) in n.factor()]) // 2 def nirregcusps(self): r""" @@ -200,24 +201,24 @@ def _find_cusps(self): n = self.level() C = [QQ(x) for x in range(n)] - n0 = n//2 - n1 = (n+1)//2 + n0 = n // 2 + n1 = (n + 1) // 2 for r in range(1, n1): - if r > 1 and gcd(r,n) == 1: - C.append(ZZ(r)/ZZ(n)) - if n0 == n/2 and gcd(r,n0) == 1: - C.append(ZZ(r)/ZZ(n0)) - - for s in range(2,n1): - for r in range(1, 1+n): - if GCD_list([s,r,n]) == 1: + if r > 1 and gcd(r, n) == 1: + C.append(ZZ(r) / ZZ(n)) + if n0 == n / 2 and gcd(r, n0) == 1: + C.append(ZZ(r) / ZZ(n0)) + + for s in range(2, n1): + for r in range(1, 1 + n): + if GCD_list([s, r, n]) == 1: # GCD_list is ~40x faster than gcd, since gcd wastes loads # of time initialising a Sequence type. - u,v = _lift_pair(r,s,n) - C.append(ZZ(u)/ZZ(v)) + u, v = _lift_pair(r, s, n) + C.append(ZZ(u) / ZZ(v)) - return [Cusp(x) for x in sorted(C)] + [Cusp(1,0)] + return [Cusp(x) for x in sorted(C)] + [Cusp(1, 0)] def reduce_cusp(self, c): r""" @@ -248,11 +249,11 @@ def reduce_cusp(self, c): """ N = self.level() c = Cusp(c) - u,v = c.numerator() % N, c.denominator() % N - if (v > N//2) or (2*v == N and u > N//2): - u,v = -u,-v - u,v = _lift_pair(u,v,N) - return Cusp(u,v) + u, v = c.numerator() % N, c.denominator() % N + if (v > N // 2) or (2 * v == N and u > N // 2): + u, v = -u, -v + u, v = _lift_pair(u, v, N) + return Cusp(u, v) def are_equivalent(self, x, y, trans=False): r""" @@ -267,12 +268,12 @@ def are_equivalent(self, x, y, trans=False): True """ if trans: - return CongruenceSubgroup.are_equivalent(self, x,y,trans=trans) + return CongruenceSubgroup.are_equivalent(self, x, y, trans=trans) N = self.level() - u1,v1 = (x.numerator() % N, x.denominator() % N) - u2,v2 = (y.numerator(), y.denominator()) + u1, v1 = (x.numerator() % N, x.denominator() % N) + u2, v2 = (y.numerator(), y.denominator()) - return ((u1,v1) == (u2 % N, v2 % N)) or ((u1,v1) == (-u2 % N, -v2 % N)) + return ((u1, v1) == (u2 % N, v2 % N)) or ((u1, v1) == (-u2 % N, -v2 % N)) def nu3(self): r""" diff --git a/src/sage/modular/arithgroup/congroup_gamma0.py b/src/sage/modular/arithgroup/congroup_gamma0.py index e467eaafeb0..0a9c5f0aace 100644 --- a/src/sage/modular/arithgroup/congroup_gamma0.py +++ b/src/sage/modular/arithgroup/congroup_gamma0.py @@ -39,6 +39,7 @@ def Gamma0_constructor(N): True """ from sage.modular.arithgroup.all import SL2Z + if N == 1: return SL2Z try: @@ -300,9 +301,10 @@ def coset_reps(self): ] """ from .all import SL2Z + N = self.level() - if N == 1: # P1List isn't very happy working modulo 1 - yield SL2Z([1,0,0,1]) + if N == 1: # P1List isn't very happy working modulo 1 + yield SL2Z([1, 0, 0, 1]) else: for z in P1List(N): yield SL2Z(lift_to_sl2z(z[0], z[1], N)) @@ -347,7 +349,7 @@ def generators(self, algorithm='farey'): if self.level() == 1: # we return a fixed set of generators for SL2Z, for historical # reasons, which aren't the ones the Farey symbol code gives - return [ self([0,-1,1,0]), self([1,1,0,1]) ] + return [self([0, -1, 1, 0]), self([1, 1, 0, 1])] if algorithm == "farey": return self.farey_symbol().generators() @@ -356,9 +358,10 @@ def generators(self, algorithm='farey'): from sage.modular.modsym.p1list import P1List from .congroup import generators_helper + level = self.level() - if level == 1: # P1List isn't very happy working mod 1 - return [ self([0,-1,1,0]), self([1,1,0,1]) ] + if level == 1: # P1List isn't very happy working mod 1 + return [self([0, -1, 1, 0]), self([1, 1, 0, 1])] gen_list = generators_helper(P1List(level), level) return [self(g, check=False) for g in gen_list] @@ -386,6 +389,7 @@ def gamma_h_subgroups(self): Congruence Subgroup Gamma1(12)] """ from .all import GammaH + N = self.level() R = IntegerModRing(N) return [GammaH(N, H) for H in R.multiplicative_subgroups()] @@ -418,7 +422,7 @@ def _contains_sl2(self, a, b, c, d): TypeError: matrix [ 1 0] [23 1] is not an element of Congruence Subgroup Gamma0(12) """ - return (c % self.level() == 0) + return c % self.level() == 0 def _find_cusps(self): r""" @@ -446,20 +450,20 @@ def _find_cusps(self): s = [] for d in divisors(N): - w = gcd(d, N//d) + w = gcd(d, N // d) if w == 1: if d == 1: - s.append(Cusp(1,0)) + s.append(Cusp(1, 0)) elif d == N: - s.append(Cusp(0,1)) + s.append(Cusp(0, 1)) else: - s.append(Cusp(1,d)) + s.append(Cusp(1, d)) else: for a in range(1, w): if gcd(a, w) == 1: - while gcd(a, d//w) != 1: + while gcd(a, d // w) != 1: a += w - s.append(Cusp(a,d)) + s.append(Cusp(a, d)) return sorted(s) def ncusps(self): @@ -501,7 +505,7 @@ def nu2(self): n = self.level() if n % 4 == 0: return ZZ(0) - return prod([ 1 + kronecker_symbol(-4, p) for p, _ in n.factor()]) + return prod([1 + kronecker_symbol(-4, p) for p, _ in n.factor()]) def nu3(self): r""" @@ -526,9 +530,9 @@ def nu3(self): 8 """ n = self.level() - if (n % 9 == 0): + if n % 9 == 0: return ZZ(0) - return prod([ 1 + kronecker_symbol(-3, p) for p, _ in n.factor()]) + return prod([1 + kronecker_symbol(-3, p) for p, _ in n.factor()]) def index(self): r""" @@ -547,7 +551,7 @@ def index(self): sage: Gamma0(32041).index() 32220 """ - return prod([p**e + p**(e-1) for (p,e) in self.level().factor()]) + return prod([p**e + p ** (e - 1) for (p, e) in self.level().factor()]) def dimension_new_cusp_forms(self, k=2, p=0): r""" @@ -590,8 +594,7 @@ def dimension_new_cusp_forms(self, k=2, p=0): k = ZZ(k) if not (p == 0 or N % p): - return (self.dimension_cusp_forms(k) - - 2 * self.restrict(N // p).dimension_new_cusp_forms(k)) + return self.dimension_cusp_forms(k) - 2 * self.restrict(N // p).dimension_new_cusp_forms(k) if k < 2 or k % 2: return ZZ.zero() @@ -601,10 +604,10 @@ def dimension_new_cusp_forms(self, k=2, p=0): def s0(q, a): # function s_0^# if a == 1: - return 1 - 1/q + return 1 - 1 / q if a == 2: - return 1 - 1/q - 1/q**2 - return (1 - 1/q) * (1 - 1/q**2) + return 1 - 1 / q - 1 / q**2 + return (1 - 1 / q) * (1 - 1 / q**2) def vinf(q, a): # function v_oo^# @@ -612,7 +615,7 @@ def vinf(q, a): return 0 if a == 2: return q - 2 - return q**(a/2 - 2) * (q - 1)**2 + return q ** (a / 2 - 2) * (q - 1) ** 2 def v2(q, a): # function v_2^# @@ -652,8 +655,8 @@ def v3(q, a): res = (k - 1) / 12 * N * prod(s0(q, a) for q, a in factors) res -= prod(vinf(q, a) for q, a in factors) / ZZ(2) - res += ((1 - k)/4 + k//4) * prod(v2(q, a) for q, a in factors) - res += ((1 - k)/3 + k//3) * prod(v3(q, a) for q, a in factors) + res += ((1 - k) / 4 + k // 4) * prod(v2(q, a) for q, a in factors) + res += ((1 - k) / 3 + k // 3) * prod(v3(q, a) for q, a in factors) if k == 2: res += moebius(N) return res diff --git a/src/sage/modular/arithgroup/congroup_gamma1.py b/src/sage/modular/arithgroup/congroup_gamma1.py index 281e6706410..87a88b40d46 100644 --- a/src/sage/modular/arithgroup/congroup_gamma1.py +++ b/src/sage/modular/arithgroup/congroup_gamma1.py @@ -48,6 +48,7 @@ def Gamma1_constructor(N): from .congroup_gamma0 import ( Gamma0_constructor, ) + return Gamma0_constructor(N) try: return _gamma1_cache[N] @@ -77,6 +78,7 @@ class Gamma1_class(GammaH_class): sage: Gamma1(23).dimension_cusp_forms(1) 1 """ + def __init__(self, level) -> None: r""" The congruence subgroup `\Gamma_1(N)`. @@ -208,6 +210,7 @@ def generators(self, algorithm='farey'): from sage.modular.modsym.g1list import G1list from .congroup import generators_helper + level = self.level() gen_list = generators_helper(G1list(level), level) return [self(g, check=False) for g in gen_list] @@ -234,7 +237,7 @@ def _contains_sl2(self, a, b, c, d): """ N = self.level() # don't need to check d == 1 mod N as this is automatic from det - return ((a % N == 1) and (c % N == 0)) + return (a % N == 1) and (c % N == 0) def nu2(self): r""" @@ -291,7 +294,7 @@ def ncusps(self): n = self.level() if n <= 4: return [None, 1, 2, 2, 3][n] - return ZZ(sum([phi(d)*phi(n/d)/ZZ(2) for d in n.divisors()])) + return ZZ(sum([phi(d) * phi(n / d) / ZZ(2) for d in n.divisors()])) def index(self): r""" @@ -308,7 +311,7 @@ def index(self): sage: [Gamma1(n).projective_index() for n in [1..16]] [1, 3, 4, 6, 12, 12, 24, 24, 36, 36, 60, 48, 84, 72, 96, 96] """ - return prod([p**(2*e) - p**(2*e-2) for (p,e) in self.level().factor()]) + return prod([p ** (2 * e) - p ** (2 * e - 2) for (p, e) in self.level().factor()]) ################################################################################## # Dimension formulas for Gamma1, accepting a Dirichlet character as an argument. # @@ -446,6 +449,7 @@ def dimension_cusp_forms(self, k=2, eps=None, algorithm='CohenOesterle'): if k == 1: from sage.modular.modform.weight1 import dimension_wt1_cusp_forms + return dimension_wt1_cusp_forms(eps) # now the main part @@ -454,13 +458,14 @@ def dimension_cusp_forms(self, k=2, eps=None, algorithm='CohenOesterle'): n = eps.order() dim = ZZ(0) for d in n.divisors(): - G = GammaH_constructor(N,(eps**d).kernel()) - dim = dim + moebius(d)*G.dimension_cusp_forms(k) - return dim//phi(n) + G = GammaH_constructor(N, (eps**d).kernel()) + dim = dim + moebius(d) * G.dimension_cusp_forms(k) + return dim // phi(n) if algorithm == "CohenOesterle": from sage.modular.dims import CohenOesterle - return ZZ( K(Gamma0(N).index() * (k-1)/ZZ(12)) + CohenOesterle(eps,k) ) + + return ZZ(K(Gamma0(N).index() * (k - 1) / ZZ(12)) + CohenOesterle(eps, k)) # algorithm not in ["CohenOesterle", "Quer"]: raise ValueError("Unrecognised algorithm in dimension_cusp_forms") @@ -532,17 +537,18 @@ def dimension_eis(self, k=2, eps=None, algorithm='CohenOesterle'): n = eps.order() dim = ZZ(0) for d in n.divisors(): - G = GammaH_constructor(N,(eps**d).kernel()) - dim = dim + moebius(d)*G.dimension_eis(k) - return dim//phi(n) + G = GammaH_constructor(N, (eps**d).kernel()) + dim = dim + moebius(d) * G.dimension_eis(k) + return dim // phi(n) if algorithm == "CohenOesterle": from sage.modular.dims import CohenOesterle - j = 2-k + + j = 2 - k # We use the Cohen-Oesterle formula in a subtle way to # compute dim M_k(N,eps) (see Ch. 6 of William Stein's book on # computing with modular forms). - alpha = -ZZ( K(Gamma0(N).index()*(j-1)/ZZ(12)) + CohenOesterle(eps,j) ) + alpha = -ZZ(K(Gamma0(N).index() * (j - 1) / ZZ(12)) + CohenOesterle(eps, j)) if k == 1: return alpha return alpha - self.dimension_cusp_forms(k, eps) @@ -613,13 +619,14 @@ def dimension_new_cusp_forms(self, k=2, eps=None, p=0, algorithm='CohenOesterle' if eps.is_trivial(): from .all import Gamma0 + return Gamma0(N).dimension_new_cusp_forms(k, p) from .congroup_gammaH import mumu if p == 0 or N % p != 0 or eps.conductor().valuation(p) == N.valuation(p): - D = [eps.conductor()*d for d in divisors(N//eps.conductor())] - return sum([Gamma1_constructor(M).dimension_cusp_forms(k, eps.restrict(M), algorithm)*mumu(N//M) for M in D]) - eps_p = eps.restrict(N//p) - old = Gamma1_constructor(N//p).dimension_cusp_forms(k, eps_p, algorithm) - return self.dimension_cusp_forms(k, eps, algorithm) - 2*old + D = [eps.conductor() * d for d in divisors(N // eps.conductor())] + return sum([Gamma1_constructor(M).dimension_cusp_forms(k, eps.restrict(M), algorithm) * mumu(N // M) for M in D]) + eps_p = eps.restrict(N // p) + old = Gamma1_constructor(N // p).dimension_cusp_forms(k, eps_p, algorithm) + return self.dimension_cusp_forms(k, eps, algorithm) - 2 * old diff --git a/src/sage/modular/arithgroup/congroup_gammaH.py b/src/sage/modular/arithgroup/congroup_gammaH.py index 0efc9786678..fb342767dd1 100644 --- a/src/sage/modular/arithgroup/congroup_gammaH.py +++ b/src/sage/modular/arithgroup/congroup_gammaH.py @@ -77,6 +77,7 @@ def GammaH_constructor(level, H): ArithmeticError: The generators [10] must be units modulo 14 """ from .all import SL2Z, Gamma0, Gamma1 + if level == 1: return SL2Z if H == 0: @@ -358,10 +359,7 @@ def __richcmp__(self, other, op) -> bool: [1, 5, 7, 11, 13, 17, 19, 23]] """ if isinstance(other, GammaH_class): - return richcmp((self.level(), -self.index(), - self._list_of_elements_in_H()), - (other.level(), -other.index(), - other._list_of_elements_in_H()), op) + return richcmp((self.level(), -self.index(), self._list_of_elements_in_H()), (other.level(), -other.index(), other._list_of_elements_in_H()), op) return NotImplemented def _generators_for_H(self): @@ -476,6 +474,7 @@ def generators(self, algorithm='farey'): from sage.modular.modsym.ghlist import GHlist from .congroup import generators_helper + level = self.level() gen_list = generators_helper(GHlist(self), level) return [self(g, check=False) for g in gen_list] @@ -511,8 +510,8 @@ def _coset_reduction_data_first_coord(self) -> list[tuple]: N = int(self.level()) # Get some useful fast functions for inverse and gcd - inverse_mod = get_inverse_mod(N) # optimal inverse function - gcd = get_gcd(N) # optimal gcd function + inverse_mod = get_inverse_mod(N) # optimal inverse function + gcd = get_gcd(N) # optimal gcd function # We will be filling this list in below. reduct_data = [0] * N @@ -624,8 +623,7 @@ def _coset_reduction_data(self) -> tuple[list[tuple], dict]: sage: G._coset_reduction_data() ([(0, 13, 0), (1, 1, 1), (2, 1, 1), (3, 1, 1), (4, 1, 1), (5, 1, 1), (6, 1, 1), (6, 1, 12), (5, 1, 12), (4, 1, 12), (3, 1, 12), (2, 1, 12), (1, 1, 12)], {1: [1], 13: [1, 12]}) """ - return (self._coset_reduction_data_first_coord(), - self._coset_reduction_data_second_coord()) + return (self._coset_reduction_data_first_coord(), self._coset_reduction_data_second_coord()) def _reduce_coset(self, uu, vv) -> tuple: r""" @@ -959,9 +957,9 @@ def gamma0_coset_reps(self) -> list: ] """ from .all import SL2Z + N = self.level() - return [SL2Z(lift_to_sl2z(0, d.lift(), N)) - for d in _GammaH_coset_helper(N, self._list_of_elements_in_H())] + return [SL2Z(lift_to_sl2z(0, d.lift(), N)) for d in _GammaH_coset_helper(N, self._list_of_elements_in_H())] def coset_reps(self) -> Iterator: r""" @@ -979,6 +977,7 @@ def coset_reps(self) -> Iterator: """ from sage.modular.arithgroup.congroup_sl2z import SL2Z from sage.modular.congroup import Gamma0 + reps1 = Gamma0(self.level()).coset_reps() for r in reps1: reps2 = self.gamma0_coset_reps() @@ -1007,6 +1006,7 @@ def is_subgroup(self, other) -> bool: """ from sage.modular.arithgroup.congroup_gamma0 import Gamma0_class from sage.modular.arithgroup.congroup_gamma1 import Gamma1_class + if not isinstance(other, GammaH_class): raise NotImplementedError @@ -1035,6 +1035,7 @@ def index(self): [72, 144, 144, 144, 144, 288, 288, 288, 288, 144, 288, 288, 576, 576, 144, 288, 288, 576, 576, 144, 288, 288, 576, 576, 288, 576, 1152] """ from .all import Gamma1 + return Gamma1(self.level()).index() / len(self._list_of_elements_in_H()) def nu2(self): @@ -1215,6 +1216,7 @@ def dimension_cusp_forms(self, k=2): return CongruenceSubgroup.dimension_cusp_forms(self, k) from sage.modular.modform.weight1 import dimension_wt1_cusp_forms_gH + return dimension_wt1_cusp_forms_gH(self) def dimension_new_cusp_forms(self, k=2, p=0): @@ -1244,10 +1246,8 @@ def dimension_new_cusp_forms(self, k=2, p=0): """ N = self.level() if p == 0 or N % p: - return sum(H.dimension_cusp_forms(k) * mumu(N // H.level()) - for H in self.divisor_subgroups()) - return self.dimension_cusp_forms(k) - \ - 2 * self.restrict(N // p).dimension_new_cusp_forms(k) + return sum(H.dimension_cusp_forms(k) * mumu(N // H.level()) for H in self.divisor_subgroups()) + return self.dimension_cusp_forms(k) - 2 * self.restrict(N // p).dimension_new_cusp_forms(k) def image_mod_n(self): r""" @@ -1352,6 +1352,7 @@ def characters_mod_H(self, sign=None, galois_orbits=False): return [] from sage.modular.dirichlet import DirichletGroup + chis = DirichletGroup(self.level()).galois_orbits() A = [] for U in chis: diff --git a/src/sage/modular/arithgroup/congroup_generic.py b/src/sage/modular/arithgroup/congroup_generic.py index d8da73f746a..3ec449144f1 100644 --- a/src/sage/modular/arithgroup/congroup_generic.py +++ b/src/sage/modular/arithgroup/congroup_generic.py @@ -110,6 +110,7 @@ def CongruenceSubgroup_constructor(*args): GG = _minimize_level(G) if GG in ZZ: from .all import Gamma + return Gamma(GG) return CongruenceSubgroupFromGroup(GG) @@ -142,7 +143,7 @@ def _an_element_(self): [ 3 4] """ N = self.level() - return self([1-N, -N, N, 1+N]) + return self([1 - N, -N, N, 1 + N]) def is_congruence(self) -> bool: r""" @@ -199,13 +200,12 @@ def __eq__(self, other): if self.level() == other.level() == 1: return True # shouldn't come up except with pickling/unpickling - return (self.level() == other.level() and - self.index() == other.index() and - self.image_mod_n() == other.image_mod_n()) + return self.level() == other.level() and self.index() == other.index() and self.image_mod_n() == other.image_mod_n() from sage.modular.arithgroup.arithgroup_perm import ( ArithmeticSubgroup_Permutation_class, ) + if isinstance(other, ArithmeticSubgroup_Permutation_class): return self.as_permutation_group() == other @@ -350,7 +350,7 @@ def to_even_subgroup(self): from sage.groups.matrix_gps.finitely_generated import MatrixGroup G = self.image_mod_n() - H = MatrixGroup([ g.matrix() for g in G.gens()] + [G.matrix_space()(-1)]) + H = MatrixGroup([g.matrix() for g in G.gens()] + [G.matrix_space()(-1)]) return CongruenceSubgroup_constructor(H) def _repr_(self): @@ -375,7 +375,7 @@ def index(self): sage: sage.modular.arithgroup.congroup_generic.CongruenceSubgroupFromGroup(MatrixGroup([matrix(Zmod(2), 2, [1,1,1,0])])).index() 2 """ - return prod([p**(3*e-2)*(p*p-1) for (p,e) in self.level().factor()]) // self.image_mod_n().order() + return prod([p ** (3 * e - 2) * (p * p - 1) for (p, e) in self.level().factor()]) // self.image_mod_n().order() def image_mod_n(self): r""" @@ -460,6 +460,7 @@ def modular_symbols(self, sign=0, weight=2, base_ring=QQ): Modular Symbols space of dimension 3 for Gamma_0(23) of weight 2 with sign 1 over Rational Field """ from sage.modular.modsym.modsym import ModularSymbols + return ModularSymbols(self, sign=sign, weight=weight, base_ring=base_ring) def modular_abelian_variety(self): @@ -477,6 +478,7 @@ def modular_abelian_variety(self): Abelian variety JH(11,[3]) of dimension 1 """ from sage.modular.abvar.abvar_ambient_jacobian import ModAbVar_ambient_jacobian + return ModAbVar_ambient_jacobian(self) def _new_group_from_level(self, level): @@ -514,6 +516,7 @@ def _new_group_from_level(self, level): from .congroup_gamma0 import Gamma0_class from .congroup_gamma1 import Gamma1_class from .congroup_gammaH import GammaH_class + N = self.level() if (level % N) and (N % level): raise ValueError("one level must divide the other") @@ -525,10 +528,10 @@ def _new_group_from_level(self, level): H = self._generators_for_H() if level > N: d = level // N - diffs = [ N*i for i in range(d) ] - newH = [ h + diff for h in H for diff in diffs ] + diffs = [N * i for i in range(d)] + newH = [h + diff for h in H for diff in diffs] return GammaH(level, [x for x in newH if gcd(level, x) == 1]) - return GammaH(level, [ h % level for h in H ]) + return GammaH(level, [h % level for h in H]) raise NotImplementedError diff --git a/src/sage/modular/arithgroup/congroup_sl2z.py b/src/sage/modular/arithgroup/congroup_sl2z.py index aed12db8d3f..8e2e54fd9e3 100644 --- a/src/sage/modular/arithgroup/congroup_sl2z.py +++ b/src/sage/modular/arithgroup/congroup_sl2z.py @@ -5,6 +5,7 @@ - Niles Johnson (2010-08): :issue:`3893`: ``random_element()`` should pass on ``*args`` and ``**kwds``. """ + # ############################################################################# # # Copyright (C) 2009, The Sage Group -- http://www.sagemath.org/ @@ -30,6 +31,7 @@ class SL2Z_class(Gamma0_class): The full modular group `\SL_2(\ZZ)`, regarded as a congruence subgroup of itself. """ + def __init__(self) -> None: r""" The modular group `\SL_2(\Z)`. @@ -156,7 +158,7 @@ def reduce_cusp(self, c): sage: SL2Z.reduce_cusp(Cusps(-1/4)) Infinity """ - return Cusp(1,0) + return Cusp(1, 0) def random_element(self, bound=100, *args, **kwds): r""" @@ -198,31 +200,31 @@ def random_element(self, bound=100, *args, **kwds): """ if bound <= 1: raise ValueError("bound must be greater than 1") - c = ZZ.random_element(1-bound, bound, *args, **kwds) - d = ZZ.random_element(1-bound, bound, *args, **kwds) - if gcd(c,d) != 1: # try again + c = ZZ.random_element(1 - bound, bound, *args, **kwds) + d = ZZ.random_element(1 - bound, bound, *args, **kwds) + if gcd(c, d) != 1: # try again return self.random_element(bound, *args, **kwds) - a,b,c,d = lift_to_sl2z(c,d,0) + a, b, c, d = lift_to_sl2z(c, d, 0) whi = bound wlo = bound if c > 0: - whi = min(whi, ((bound - a)/ZZ(c)).ceil()) - wlo = min(wlo, ((bound + a)/ZZ(c)).ceil()) + whi = min(whi, ((bound - a) / ZZ(c)).ceil()) + wlo = min(wlo, ((bound + a) / ZZ(c)).ceil()) elif c < 0: - whi = min(whi, ((bound + a)/ZZ(-c)).ceil()) - wlo = min(wlo, ((bound - a)/ZZ(-c)).ceil()) + whi = min(whi, ((bound + a) / ZZ(-c)).ceil()) + wlo = min(wlo, ((bound - a) / ZZ(-c)).ceil()) if d > 0: - whi = min(whi, ((bound - b)/ZZ(d)).ceil()) - wlo = min(wlo, ((bound + b)/ZZ(d)).ceil()) + whi = min(whi, ((bound - b) / ZZ(d)).ceil()) + wlo = min(wlo, ((bound + b) / ZZ(d)).ceil()) elif d < 0: - whi = min(whi, ((bound + b)/ZZ(-d)).ceil()) - wlo = min(wlo, ((bound - b)/ZZ(-d)).ceil()) + whi = min(whi, ((bound + b) / ZZ(-d)).ceil()) + wlo = min(wlo, ((bound - b) / ZZ(-d)).ceil()) - w = ZZ.random_element(1-wlo, whi, *args, **kwds) - a += c*w - b += d*w - return self([a,b,c,d]) + w = ZZ.random_element(1 - wlo, whi, *args, **kwds) + a += c * w + b += d * w + return self([a, b, c, d]) SL2Z = SL2Z_class() diff --git a/src/sage/modular/arithgroup/tests.py b/src/sage/modular/arithgroup/tests.py index 6188054c608..11947c217ac 100644 --- a/src/sage/modular/arithgroup/tests.py +++ b/src/sage/modular/arithgroup/tests.py @@ -226,8 +226,7 @@ def test_random(self): sage: Test().test_random() #random Doing random test """ - tests = [a for a in Test.__dict__ - if a[:5] == "test_" and a != "test_random"] + tests = [a for a in Test.__dict__ if a[:5] == "test_" and a != "test_random"] name = prandom.choice(tests) print("Doing random test %s" % name) Test.__dict__[name](self) @@ -301,17 +300,7 @@ def test_congruence_groups(self): if not GG.is_congruence(): raise AssertionError("Hsu congruence test failed") - methods = [ - 'index', - 'is_odd', - 'is_even', - 'is_normal', - 'ncusps', - 'nregcusps', - 'nirregcusps', - 'nu2', - 'nu3', - 'generalised_level'] + methods = ['index', 'is_odd', 'is_even', 'is_normal', 'ncusps', 'nregcusps', 'nirregcusps', 'nu2', 'nu3', 'generalised_level'] for f in methods: if getattr(G, f)() != getattr(GG, f)(): diff --git a/src/sage/modular/btquotients/all.py b/src/sage/modular/btquotients/all.py index 1e96b2db99b..682c7d9b9c3 100644 --- a/src/sage/modular/btquotients/all.py +++ b/src/sage/modular/btquotients/all.py @@ -1,3 +1,4 @@ from sage.modular.btquotients.btquotient import BruhatTitsQuotient + # from pautomorphicform import pAdicAutomorphicForms # from pautomorphicform import BruhatTitsHarmonicCocycles diff --git a/src/sage/modular/btquotients/btquotient.py b/src/sage/modular/btquotients/btquotient.py index 40c161c08ac..be9973262c6 100644 --- a/src/sage/modular/btquotients/btquotient.py +++ b/src/sage/modular/btquotients/btquotient.py @@ -64,6 +64,7 @@ from sage.rings.rational_field import QQ from sage.structure.sage_object import SageObject from sage.structure.unique_representation import UniqueRepresentation + lazy_import("sage.plot.colors", "rainbow") lazy_import('sage.algebras.quatalg.quaternion_algebra', 'QuaternionAlgebra') @@ -165,8 +166,7 @@ def __init__(self, Y, x, extrapow=0): parity = valuation % 2 v1 = Y._BT.target(e1) v = Y.fundom_rep(v1) - g, e = Y._find_equivalent_edge(e1, v.entering_edges, - valuation=valuation) + g, e = Y._find_equivalent_edge(e1, v.entering_edges, valuation=valuation) label = e.label Y._cached_decomps[e1] = (g, label, parity) @@ -193,8 +193,7 @@ def _repr_(self): sage: DoubleCosetReduction(Y,x) Double coset data (-1, [(4), (5), (-4), (-4)], 8) """ - return "Double coset data (%s, %s, %s)" % (self.sign(), - list(self.gamma), self.label) + return "Double coset data (%s, %s, %s)" % (self.sign(), list(self.gamma), self.label) def __eq__(self, other): """ @@ -328,8 +327,7 @@ def igamma(self, embedding=None, scale=1): return embedding(self.gamma) if prec > self._igamma_prec: self._igamma_prec = prec - self._cached_igamma = Y.embed_quaternion(self.gamma, exact=False, - prec=prec) + self._cached_igamma = Y.embed_quaternion(self.gamma, exact=False, prec=prec) return scale * self._cached_igamma def t(self, prec=None): @@ -372,8 +370,7 @@ def t(self, prec=None): self._cached_t = (self.igamma(tmp_prec) * e.opposite.rep).inverse() * self.x # assert self._cached_t[1, 0].valuation()>self._cached_t[1,1].valuation() tmp_prec += 1 - self._t_prec = min([xx.precision_absolute() - for xx in self._cached_t.list()]) + self._t_prec = min([xx.precision_absolute() for xx in self._cached_t.list()]) return self._cached_t @@ -418,6 +415,7 @@ class BruhatTitsTree(SageObject, UniqueRepresentation): - Marc Masdeu (2012-02-20) """ + def __init__(self, p): """ Initialize a BruhatTitsTree object for a given prime `p`. @@ -560,19 +558,19 @@ def lift(a): bigpower = p ** (1 + tmp) r = M[0, 0] if r != 0: - r /= p ** m00 + r /= p**m00 g, s, _ = xgcd(r, bigpower) r = (M[1, 0] * s) % bigpower - newM = self._Mat_22([p ** m00, 0, r, bigpower / p]) + newM = self._Mat_22([p**m00, 0, r, bigpower / p]) else: tmp = det.valuation(p) - m01 - bigpower = p ** tmp + bigpower = p**tmp r = M[0, 1] if r != 0: - r /= p ** m01 + r /= p**m01 g, s, _ = xgcd(r, bigpower) r = (ZZ(M[1, 1]) * s) % bigpower - newM = self._Mat_22([0, p ** m01, bigpower, r]) + newM = self._Mat_22([0, p**m01, bigpower, r]) newM.set_immutable() # assert self.is_in_group(M_orig.inverse()*newM, as_edge = True) return newM @@ -626,15 +624,15 @@ def lift(a): M.swap_columns(0, 1) m00 = m01 tmp = M.determinant().valuation(p) - m00 - bigpower = p ** tmp + bigpower = p**tmp r = M[0, 0] if r: - r /= p ** m00 + r /= p**m00 # r = ZZ(r) % bigpower g, s, _ = xgcd(r, bigpower) m10 = M[1, 0] % bigpower r = (m10 * s) % bigpower - newM = self._Mat_22([p ** m00, 0, r, bigpower]) + newM = self._Mat_22([p**m00, 0, r, bigpower]) newM.set_immutable() # assert self.is_in_group(M_orig.inverse()*newM, as_edge=False) return newM @@ -1118,8 +1116,8 @@ class Vertex(SageObject): - Marc Masdeu (2012-02-20) """ - def __init__(self, p, label, rep, leaving_edges=None, - entering_edges=None, determinant=None, valuation=None): + + def __init__(self, p, label, rep, leaving_edges=None, entering_edges=None, determinant=None, valuation=None): """ This initializes a structure to represent vertices of quotients of the Bruhat-Tits tree. It is useful to enrich the @@ -1243,8 +1241,8 @@ class Edge(SageObject): - Marc Masdeu (2012-02-20) """ - def __init__(self, p, label, rep, origin, target, links=None, - opposite=None, determinant=None, valuation=None): + + def __init__(self, p, label, rep, origin, target, links=None, opposite=None, determinant=None, valuation=None): """ Representation for edges of quotients of the Bruhat-Tits tree. It is useful to enrich the representation of an edge as @@ -1397,9 +1395,9 @@ class BruhatTitsQuotient(SageObject, UniqueRepresentation): - Marc Masdeu (2012-02-20) """ + @staticmethod - def __classcall__(cls, p, Nminus, Nplus=1, character=None, - use_magma=False, seed=None, magma_session=None): + def __classcall__(cls, p, Nminus, Nplus=1, character=None, use_magma=False, seed=None, magma_session=None): """ Ensure that a canonical BruhatTitsQuotient is created. @@ -1408,12 +1406,9 @@ def __classcall__(cls, p, Nminus, Nplus=1, character=None, sage: BruhatTitsQuotient(3,17) is BruhatTitsQuotient(3,17,1) True """ - return super().__classcall__(cls, p, Nminus, Nplus, - character, use_magma, - seed, magma_session) + return super().__classcall__(cls, p, Nminus, Nplus, character, use_magma, seed, magma_session) - def __init__(self, p, Nminus, Nplus=1, character=None, - use_magma=False, seed=None, magma_session=None): + def __init__(self, p, Nminus, Nplus=1, character=None, use_magma=False, seed=None, magma_session=None): """ Compute the quotient of the Bruhat-Tits tree by an arithmetic quaternionic group. @@ -1443,7 +1438,7 @@ def __init__(self, p, Nminus, Nplus=1, character=None, raise ValueError("p must be a prime") if not lev.is_squarefree(): raise ValueError("level must be squarefree") - if (gcd(lev, Nplus) > 1): + if gcd(lev, Nplus) > 1: raise ValueError("level and conductor must be coprime") # if len(Nminus.factor()) % 2 != 1: @@ -1481,7 +1476,7 @@ def __init__(self, p, Nminus, Nplus=1, character=None, self._cached_equivalent = {} self._CM_points = {} - self._V = (QQ ** 4).ambient_module().change_ring(ZZ) + self._V = (QQ**4).ambient_module().change_ring(ZZ) self._Mat_44 = MatrixSpace(ZZ, 4, 4) self._Mat_22 = MatrixSpace(ZZ, 2, 2) self._Mat_41 = MatrixSpace(ZZ, 4, 1) @@ -1491,14 +1486,8 @@ def __init__(self, p, Nminus, Nplus=1, character=None, self._extra_level = [ff[0] for ff in extra_level.factor()] self.get_extra_embedding_matrices() self._character = character - self._Xv = [self._Mat_22([1, 0, 0, 0]), - self._Mat_22([0, 1, 0, 0]), - self._Mat_22([0, 0, 1, 0]), - self._Mat_22([0, 0, 0, 1])] - self._Xe = [self._Mat_22([1, 0, 0, 0]), - self._Mat_22([0, 1, 0, 0]), - self._Mat_22([0, 0, self._p, 0]), - self._Mat_22([0, 0, 0, 1])] + self._Xv = [self._Mat_22([1, 0, 0, 0]), self._Mat_22([0, 1, 0, 0]), self._Mat_22([0, 0, 1, 0]), self._Mat_22([0, 0, 0, 1])] + self._Xe = [self._Mat_22([1, 0, 0, 0]), self._Mat_22([0, 1, 0, 0]), self._Mat_22([0, 0, self._p, 0]), self._Mat_22([0, 0, 0, 1])] def _cache_key(self): r""" @@ -1717,13 +1706,13 @@ def _compute_invariants(self): e3 = 1 mu = Nplus for f in lev.factor(): - e4 *= (1 - kronecker_symbol(-4, Integer(f[0]))) - e3 *= (1 - kronecker_symbol(-3, Integer(f[0]))) + e4 *= 1 - kronecker_symbol(-4, Integer(f[0])) + e3 *= 1 - kronecker_symbol(-3, Integer(f[0])) mu *= Integer(f[0]) - 1 for f in Nplus.factor(): - if (f[1] == 1): - e4 *= (1 + kronecker_symbol(-4, Integer(f[0]))) - e3 *= (1 + kronecker_symbol(-3, Integer(f[0]))) + if f[1] == 1: + e4 *= 1 + kronecker_symbol(-4, Integer(f[0])) + e3 *= 1 + kronecker_symbol(-3, Integer(f[0])) else: if kronecker_symbol(-4, Integer(f[0])) == 1: e4 *= 2 @@ -1877,8 +1866,7 @@ def genus(self): return self.dimension_harmonic_cocycles(2) @cached_method - def dimension_harmonic_cocycles(self, k, lev=None, Nplus=None, - character=None): + def dimension_harmonic_cocycles(self, k, lev=None, Nplus=None, character=None): r""" Compute the dimension of the space of harmonic cocycles of weight `k` on ``self``. @@ -1918,8 +1906,7 @@ def dimension_harmonic_cocycles(self, k, lev=None, Nplus=None, if not self._trivial_character: character = self._character lN = lev * Nplus - kernel = [r for r in lN.coprime_integers(lN) - if character(r) == 1] + kernel = [r for r in lN.coprime_integers(lN) if character(r) == 1] else: character = None kernel = None @@ -1934,8 +1921,7 @@ def dimension_harmonic_cocycles(self, k, lev=None, Nplus=None, f = lev.factor() if any(l[1] != 1 for l in f): - raise NotImplementedError('The level should be squarefree for ' - 'this function to work... Sorry!') + raise NotImplementedError('The level should be squarefree for ' 'this function to work... Sorry!') def GH(N, ker): return Gamma0(N) if character is None else GammaH_constructor(N, ker) @@ -1948,6 +1934,7 @@ def mumu(N): if r == 1: p *= -2 return ZZ(p) + return sum([mumu(lev // d) * GH(d * Nplus, kernel).dimension_cusp_forms(k) for d in lev.divisors()]) def Nplus(self): @@ -2161,6 +2148,7 @@ def phi(q): R = I.parent() v = q.coefficient_tuple() return R(v[0] + I * v[1] + J * v[2] + K * v[3]) + return phi def _local_splitting(self, prec): @@ -2192,9 +2180,9 @@ def _local_splitting(self, prec): v = A.invariants() a = ZZp(v[0]) b = ZZp(v[1]) - if (A.base_ring() != QQ): + if A.base_ring() != QQ: raise ValueError("must be rational quaternion algebra") - if (A.discriminant() % self._p == 0): + if A.discriminant() % self._p == 0: raise ValueError("p (=%s) must be an unramified prime" % self._p) M = MatrixSpace(ZZp, 2) @@ -2239,8 +2227,7 @@ def _compute_embedding_matrix(self, prec, force_computation=False): if self._use_magma: if not force_computation: try: - return Matrix(Zmod(self._pN), 4, 4, - self._cached_Iota0_matrix) + return Matrix(Zmod(self._pN), 4, 4, self._cached_Iota0_matrix) except AttributeError: pass @@ -2252,14 +2239,11 @@ def _compute_embedding_matrix(self, prec, force_computation=False): M, f, rho = self._magma.function_call('pMatrixRing', args=[OrdMax, self._p], params={'Precision': 2000}, nvals=3) v = [f.Image(OBasis[i]) for i in [1, 2, 3, 4]] - self._cached_Iota0_matrix = [v[kk][ii, jj].sage() - for ii in range(1, 3) - for jj in range(1, 3) - for kk in range(4)] + self._cached_Iota0_matrix = [v[kk][ii, jj].sage() for ii in range(1, 3) for jj in range(1, 3) for kk in range(4)] return Matrix(Zmod(self._pN), 4, 4, self._cached_Iota0_matrix) phi = self._local_splitting_map(prec) B = self.get_eichler_order_basis() - return column_matrix(Zmod(self._p ** prec), 4, 4, [phi(b).list() for b in B]) + return column_matrix(Zmod(self._p**prec), 4, 4, [phi(b).list() for b in B]) @cached_method def get_extra_embedding_matrices(self): @@ -2323,8 +2307,7 @@ def get_extra_embedding_matrices(self): self._magma.function_call('SetSeed', n_iters, nvals=0) self._order_is_initialized = False self._init_order() - self._compute_embedding_matrix(self._prec, - force_computation=True) + self._compute_embedding_matrix(self._prec, force_computation=True) Ord = self.get_eichler_order(magma=True) OrdMax = self.get_maximal_order(magma=True) OBasis = Ord.Basis() @@ -2333,10 +2316,7 @@ def get_extra_embedding_matrices(self): break if not success: break - mat = Matrix(GF(l), 4, 4, [v[kk][ii, jj].sage() - for ii in range(1, 3) - for jj in range(1, 3) - for kk in range(4)]) + mat = Matrix(GF(l), 4, 4, [v[kk][ii, jj].sage() for ii in range(1, 3) for jj in range(1, 3) for kk in range(4)]) extra_embeddings.append(mat) return extra_embeddings @@ -2418,7 +2398,7 @@ def get_embedding_matrix(self, prec=None, exact=False): except AttributeError: pass - self._pN = self._p ** prec + self._pN = self._p**prec self._R = Qp(self._p, prec=prec) if prec > self._prec: @@ -2471,8 +2451,7 @@ def embed_quaternion(self, g, exact=False, prec=None): True """ if exact: - return Matrix(self.get_splitting_field(), 2, 2, - (self.get_embedding_matrix(exact=True) * g).list()) + return Matrix(self.get_splitting_field(), 2, 2, (self.get_embedding_matrix(exact=True) * g).list()) A = self.get_embedding_matrix(prec=prec) * g return Matrix(self._R, 2, 2, A.list()) @@ -2525,8 +2504,7 @@ def get_edge_stabilizers(self): try: return self._edge_stabs except AttributeError: - self._edge_stabs = [self._stabilizer(e.rep, as_edge=True) - for e in self.get_edge_list()] + self._edge_stabs = [self._stabilizer(e.rep, as_edge=True) for e in self.get_edge_list()] return self._edge_stabs def get_stabilizers(self): @@ -2585,8 +2563,7 @@ def get_vertex_stabs(self): try: return self._vertex_stabs except AttributeError: - self._vertex_stabs = [self._stabilizer(v.rep, as_edge=False) - for v in self.get_vertex_list()] + self._vertex_stabs = [self._stabilizer(v.rep, as_edge=False) for v in self.get_vertex_list()] return self._vertex_stabs def get_quaternion_algebra(self): @@ -2812,11 +2789,7 @@ def _get_Up_data(self): """ E = self.get_edge_list() vec_a = self._BT.subdivide([1], 1) - return [[alpha.inverse(), - [DoubleCosetReduction(self, e.rep * alpha) for e in E] - + [DoubleCosetReduction(self, e.opposite.rep * alpha) - for e in E]] - for alpha in vec_a] + return [[alpha.inverse(), [DoubleCosetReduction(self, e.rep * alpha) for e in E] + [DoubleCosetReduction(self, e.opposite.rep * alpha) for e in E]] for alpha in vec_a] @cached_method def _get_atkin_lehner_data(self, q): @@ -2844,10 +2817,7 @@ def _get_atkin_lehner_data(self, q): p = self._p while not V: nninc += 2 - V = [g for g in self._find_elements_in_order(q * self._p ** nninc) - if prod([self._character(ZZ((v * Matrix(ZZ, 4, 1, g))[0, 0])) - / self._character(p ** (nninc // 2)) - for v in self.get_extra_embedding_matrices()]) == 1] + V = [g for g in self._find_elements_in_order(q * self._p**nninc) if prod([self._character(ZZ((v * Matrix(ZZ, 4, 1, g))[0, 0])) / self._character(p ** (nninc // 2)) for v in self.get_extra_embedding_matrices()]) == 1] beta1 = Matrix(QQ, 4, 1, V[0]) @@ -2856,9 +2826,7 @@ def _get_atkin_lehner_data(self, q): try: x = self.embed_quaternion(beta1) nn = x.determinant().valuation() - T = [beta1, - [DoubleCosetReduction(self, x.adjugate() * e.rep, - extrapow=nn) for e in E]] + T = [beta1, [DoubleCosetReduction(self, x.adjugate() * e.rep, extrapow=nn) for e in E]] success = True except (PrecisionError, NotImplementedError): self._increase_precision(10) @@ -2892,10 +2860,7 @@ def _get_hecke_data(self, l): V = [] nninc = 0 while not V: - V = [g for g in self._find_elements_in_order(l * p ** nninc) - if prod([self._character(ZZ((v * Matrix(ZZ, 4, 1, g))[0, 0])) - / self._character(p ** (nninc // 2)) - for v in self.get_extra_embedding_matrices()]) == 1] + V = [g for g in self._find_elements_in_order(l * p**nninc) if prod([self._character(ZZ((v * Matrix(ZZ, 4, 1, g))[0, 0])) / self._character(p ** (nninc // 2)) for v in self.get_extra_embedding_matrices()]) == 1] if not V: nninc += 2 @@ -2905,10 +2870,7 @@ def _get_hecke_data(self, l): alpha = Matrix(QQ, 4, 1, alpha1) alphamat = self.embed_quaternion(alpha) letters = self.get_nontorsion_generators() - letters += [g for g in self._find_elements_in_order(1) - if prod([self._character(ZZ((v * Matrix(ZZ, 4, 1, g))[0, 0])) - / self._character(p ** (nninc // 2)) - for v in self.get_extra_embedding_matrices()]) == 1] + letters += [g for g in self._find_elements_in_order(1) if prod([self._character(ZZ((v * Matrix(ZZ, 4, 1, g))[0, 0])) / self._character(p ** (nninc // 2)) for v in self.get_extra_embedding_matrices()]) == 1] def enumerate_words(v, n=None): if n is None: @@ -2944,11 +2906,9 @@ def enumerate_words(v, n=None): success = False while not success: try: - x = self.embed_quaternion(v1, prec=max(self._prec, 40), - exact=False) * alphamat + x = self.embed_quaternion(v1, prec=max(self._prec, 40), exact=False) * alphamat nn = x.determinant().valuation() - dcr = [DoubleCosetReduction(self, x.adjugate() * e.rep, - extrapow=nn) for e in E] + dcr = [DoubleCosetReduction(self, x.adjugate() * e.rep, extrapow=nn) for e in E] T.append([v1, dcr]) success = True except (PrecisionError, NotImplementedError): @@ -3171,12 +3131,12 @@ def _stabilizer(self, e, as_edge=True): vect = mat.row(jj).row() vec = vect.transpose() nrd = Integer((vect * A * vec)[0, 0] / 2) - if nrd == p ** twom: + if nrd == p**twom: g, ans = self._nebentype_check(vec, twom, E, A, flag=0) if ans: x = self._conv(g.transpose()) g.set_immutable() - stabs.append([g, m, x != p ** m]) + stabs.append([g, m, x != p**m]) if len(stabs) <= 1: return [[self.B_one(), 0, False]] return stabs @@ -3238,15 +3198,13 @@ def _nebentype_check(self, vec, twom, E, A, flag=2): vect = mat.row(jj).row() vec = vect.transpose() nrd = Integer((vect * A * vec)[0, 0] / 2) - if nrd == p ** twom: + if nrd == p**twom: g = E * vec - if prod([self._character(ZZ(pinv ** m * (v * g)[0, 0])) - for v in self.get_extra_embedding_matrices()]) == 1: + if prod([self._character(ZZ(pinv**m * (v * g)[0, 0])) for v in self.get_extra_embedding_matrices()]) == 1: return g, True return None, False - def _are_equivalent(self, v1, v2, as_edges=False, twom=None, - check_parity=False): + def _are_equivalent(self, v1, v2, as_edges=False, twom=None, check_parity=False): r""" Determine whether two vertices (or edges) of the Bruhat-Tits tree are equivalent under the arithmetic group in @@ -3302,7 +3260,7 @@ def _are_equivalent(self, v1, v2, as_edges=False, twom=None, vect = vec.transpose() nrd = Integer((vect * A * vec)[0, 0] / 2) - if nrd == p ** twom: + if nrd == p**twom: g, ans = self._nebentype_check(vec, twom, E, A) if ans: m = Integer(twom / 2) @@ -3357,8 +3315,7 @@ def _init_order(self): self._A = QuaternionAlgebra((g[0] ** 2).sage(), (g[1] ** 2).sage()) i, j, k = self._A.gens() v = [1] + list(self._A.gens()) - self._B = [self._A(sum([OBasis[tt + 1][rr + 1].sage() * v[rr] - for rr in range(4)])) for tt in range(4)] + self._B = [self._A(sum([OBasis[tt + 1][rr + 1].sage() * v[rr] for rr in range(4)])) for tt in range(4)] self._O = self._A.quaternion_order(self._B) self._Omagma = Omagma self._OMaxmagma = OMaxmagma @@ -3374,8 +3331,7 @@ def _init_order(self): self._OQuadForm = QuadraticForm(self._Mat_44([(self._B[ii] * self._B[jj].conjugate()).reduced_trace() for ii in range(4) for jj in range(4)])) self._OM = self._OQuadForm.matrix() - self._BB = Matrix(QQ, 4, 4, [[self._B[ii][jj] for ii in range(4)] - for jj in range(4)]).inverse() + self._BB = Matrix(QQ, 4, 4, [[self._B[ii][jj] for ii in range(4)] for jj in range(4)]).inverse() self._order_is_initialized = True return @@ -3445,13 +3401,11 @@ def _find_elements_in_order(self, norm, trace=None, primitive=False): [[1, 0, -2, -1], [1, 0, 1, -1]] """ OQuadForm = self.get_eichler_order_quadform() - if norm > 10 ** 3: + if norm > 10**3: verbose('Warning: norm (= %s) is quite large, this may take some time!' % norm) V = OQuadForm.vectors_by_length(norm)[norm] - W = V if not primitive else (v for v in V - if any(vi % self._p for vi in v)) - return W if trace is None else (v for v in W - if self._conv(v).reduced_trace() == trace) + W = V if not primitive else (v for v in V if any(vi % self._p for vi in v)) + return W if trace is None else (v for v in W if self._conv(v).reduced_trace() == trace) def _compute_quotient(self, check=True): r""" @@ -3506,8 +3460,7 @@ def _compute_quotient(self, check=True): num_edges = 0 self.get_embedding_matrix(prec=3) p = self._p - v0 = Vertex(p, num_verts, self._Mat_22([1, 0, 0, 1]), - determinant=1, valuation=0) + v0 = Vertex(p, num_verts, self._Mat_22([1, 0, 0, 1]), determinant=1, valuation=0) V = deque([v0]) S = Graph(0, multiedges=True, weighted=True) # noqa:F821 Sfun = Graph(0) # noqa:F821 @@ -3526,8 +3479,7 @@ def _compute_quotient(self, check=True): edge_det = e.determinant() edge_valuation = edge_det.valuation(p) - g, e1 = self._find_equivalent_edge(e, v.leaving_edges, - valuation=edge_valuation) + g, e1 = self._find_equivalent_edge(e, v.leaving_edges, valuation=edge_valuation) if e1 is not None: # The edge is old. We just update the links e1.links.append(g) @@ -3547,8 +3499,7 @@ def _compute_quotient(self, check=True): g1, v1 = self._find_equivalent_vertex(target, V, valuation=new_valuation) if v1 is None: # The vertex is also new - v1 = Vertex(p, num_verts, target, determinant=new_det, - valuation=new_valuation) + v1 = Vertex(p, num_verts, target, determinant=new_det, valuation=new_valuation) vertex_list.append(v1) num_verts += 1 # Add the vertex to the list of pending vertices @@ -3557,8 +3508,7 @@ def _compute_quotient(self, check=True): nontorsion_generators.add(g1[0]) # Add the edge to the list - new_e = Edge(p, num_edges, e, v, v1, determinant=edge_det, - valuation=edge_valuation) + new_e = Edge(p, num_edges, e, v, v1, determinant=edge_det, valuation=edge_valuation) new_e.links.append(self.B_one()) Sfun.add_edge(v.rep, target, label=num_edges) Sfun.set_vertex(target, v1) @@ -3592,8 +3542,7 @@ def _compute_quotient(self, check=True): print('Theoretical genus =', genus) raise RuntimeError if self.get_num_verts() != len(vertex_list): - raise RuntimeError('Number of vertices different ' - 'from expected.') + raise RuntimeError('Number of vertices different ' 'from expected.') self._nontorsion_generators = nontorsion_generators self._boundary = {vv.rep: vv for vv in vertex_list} @@ -3636,6 +3585,7 @@ def harmonic_cocycle_from_elliptic_curve(self, E, prec=None): True """ from .pautomorphicform import BruhatTitsHarmonicCocycles + M = BruhatTitsHarmonicCocycles(self, 2, prec=prec) q = ZZ.one() F = E.base_ring() @@ -3689,6 +3639,7 @@ def harmonic_cocycles(self, k, prec=None, basis_matrix=None, base_field=None): Harmonic cocycle with values in Sym^0 Q_31^2 """ from .pautomorphicform import BruhatTitsHarmonicCocycles + return BruhatTitsHarmonicCocycles(self, k, prec=prec, basis_matrix=basis_matrix, base_field=base_field) def padic_automorphic_forms(self, U, prec=None, t=None, R=None, overconvergent=False): @@ -3724,4 +3675,5 @@ def padic_automorphic_forms(self, U, prec=None, t=None, R=None, overconvergent=F Space of automorphic forms on Quotient of the Bruhat Tits tree of GL_2(QQ_11) with discriminant 5 and level 1 with values in Sym^0 Q_11^2 """ from .pautomorphicform import pAdicAutomorphicForms + return pAdicAutomorphicForms(self, U, prec=prec, t=t, R=R, overconvergent=overconvergent) diff --git a/src/sage/modular/btquotients/pautomorphicform.py b/src/sage/modular/btquotients/pautomorphicform.py index 32236bab61a..fea273438bd 100644 --- a/src/sage/modular/btquotients/pautomorphicform.py +++ b/src/sage/modular/btquotients/pautomorphicform.py @@ -142,9 +142,7 @@ def eval_dist_at_powseries(phi, f): K = f.parent().base_ring() if K.is_exact(): K = phi.parent().base_ring() - return sum(a * K(phi.moment(i)) - for a, i in zip(f.coefficients(), f.exponents()) - if i >= 0 and i < nmoments) + return sum(a * K(phi.moment(i)) for a, i in zip(f.coefficients(), f.exponents()) if i >= 0 and i < nmoments) class BruhatTitsHarmonicCocycleElement(HeckeModuleElement): @@ -183,6 +181,7 @@ class BruhatTitsHarmonicCocycleElement(HeckeModuleElement): - Cameron Franc (2012-02-20) - Marc Masdeu """ + def __init__(self, _parent, vec): """ Create a harmonic cocycle element. @@ -399,9 +398,7 @@ def _compute_element(self): """ R = self._R A = self.parent().basis_matrix().transpose() - B = Matrix(R, self._nE * (self.parent()._k - 1), 1, - [self._F[e].moment(ii) for e in range(self._nE) - for ii in range(self.parent()._k - 1)]) + B = Matrix(R, self._nE * (self.parent()._k - 1), 1, [self._F[e].moment(ii) for e in range(self._nE) for ii in range(self.parent()._k - 1)]) try: res = (A.solve_right(B)).transpose() except ValueError: @@ -409,16 +406,13 @@ def _compute_element(self): err = A * rest - B if err != 0: try: - if hasattr(err.parent().base_ring().an_element(), - 'valuation'): - minval = min([o.valuation() for o in err.list() - if o != 0]) + if hasattr(err.parent().base_ring().an_element(), 'valuation'): + minval = min([o.valuation() for o in err.list() if o != 0]) else: minval = sum([RR(o.norm() ** 2) for o in err.list()]) verbose('Error = %s' % minval) except AttributeError: - verbose('Warning: something did not work in the ' - 'computation') + verbose('Warning: something did not work in the ' 'computation') res = rest.transpose() return self.parent().free_module()(res.row(0)) @@ -612,6 +606,7 @@ def derivative(self, z=None, level=0, order=1): sage: b.derivative(a,level=2,order=1) (2*a + 2)*3 + 2*a*3^2 + 3^3 + a*3^4 + O(3^5) """ + def F(z): R = PolynomialRing(z.parent(), 'x,y').fraction_field() Rx = PolynomialRing(z.parent(), 'x1').fraction_field() @@ -624,10 +619,10 @@ def F(z): k = self.parent()._k V = [f] for ii in range(order): - V = [v.derivative(y) for v in V] + [k / (y - zbar) * v - for v in V] + V = [v.derivative(y) for v in V] + [k / (y - zbar) * v for v in V] k += 2 return sum([self.riemann_sum(subst(v), center, level) for v in V]) + if z is None: return F return F(z) @@ -645,6 +640,7 @@ class BruhatTitsHarmonicCocycles(AmbientHeckeModule, UniqueRepresentation): sage: M1 is M2 True """ + Element = BruhatTitsHarmonicCocycleElement @staticmethod @@ -686,9 +682,7 @@ def __classcall__(cls, X, k, prec=None, basis_matrix=None, base_field=None): - Cameron Franc (2012-02-20) - Marc Masdeu """ - return super().__classcall__(cls, X, k, prec, - basis_matrix, - base_field) + return super().__classcall__(cls, X, k, prec, basis_matrix, base_field) def __init__(self, X, k, prec=None, basis_matrix=None, base_field=None): """ @@ -714,9 +708,7 @@ def __init__(self, X, k, prec=None, basis_matrix=None, base_field=None): try: self._R = X.get_splitting_field() except AttributeError: - raise ValueError("It looks like you are not using Magma as" - " backend...and still we don't know how " - "to compute splittings in that case!") + raise ValueError("It looks like you are not using Magma as" " backend...and still we don't know how " "to compute splittings in that case!") else: pol = X.get_splitting_field().defining_polynomial().factor()[0][0] self._R = base_field.extension(pol, pol.variable_name()).absolute_field(name='r') @@ -727,9 +719,7 @@ def __init__(self, X, k, prec=None, basis_matrix=None, base_field=None): else: self._R = base_field - self._U = Symk(self._k - 2, base=self._R, act_on_left=True, - adjuster=_btquot_adjuster(), - dettwist=-ZZ((self._k - 2) // 2), act_padic=True) + self._U = Symk(self._k - 2, base=self._R, act_on_left=True, adjuster=_btquot_adjuster(), dettwist=-ZZ((self._k - 2) // 2), act_padic=True) if basis_matrix is None: self.__rank = self._X.dimension_harmonic_cocycles(self._k) @@ -742,8 +732,7 @@ def __init__(self, X, k, prec=None, basis_matrix=None, base_field=None): self._Sigma0 = self._U._act._Sigma0 - AmbientHeckeModule.__init__(self, self._R, self.__rank, - self._X.prime() * self._X.Nplus() * self._X.Nminus(), weight=self._k) + AmbientHeckeModule.__init__(self, self._R, self.__rank, self._X.prime() * self._X.Nplus() * self._X.Nminus(), weight=self._k) self._populate_coercion_lists_() def monomial_coefficients(self): @@ -810,9 +799,7 @@ def change_ring(self, new_base_ring): basis_matrix = self.basis_matrix().change_ring(new_base_ring) basis_matrix.set_immutable() - return self.__class__(self._X, self._k, prec=None, - basis_matrix=basis_matrix, - base_field=new_base_ring) + return self.__class__(self._X, self._k, prec=None, basis_matrix=basis_matrix, base_field=new_base_ring) def rank(self): r""" @@ -895,8 +882,7 @@ def _repr_(self): Space of harmonic cocycles of weight 2 on Quotient of the Bruhat Tits tree of GL_2(QQ_5) with discriminant 23 and level 1 """ - return 'Space of harmonic cocycles of weight %s on %s' % (self._k, - self._X) + return 'Space of harmonic cocycles of weight %s on %s' % (self._k, self._X) def _latex_(self): r""" @@ -971,9 +957,7 @@ def __eq__(self, other): if not isinstance(other, BruhatTitsHarmonicCocycles): return False - return (self.base_ring() == other.base_ring() and - self._X == other._X and - self._k == other._k) + return self.base_ring() == other.base_ring() and self._X == other._X and self._k == other._k def __ne__(self, other): r""" @@ -1031,8 +1015,7 @@ def _element_constructor_(self, x): if type(x) is sage.modules.free_module_element.FreeModuleElement_generic_dense: vmat = MatrixSpace(self._R, 1, self.dimension())(x) tmp = (vmat * self.ambient_module().basis_matrix()).row(0) - vec = [self._U(tmp[e * (self._k - 1):(e + 1) * (self._k - 1)]) - for e in range(len(self._E))] + vec = [self._U(tmp[e * (self._k - 1) : (e + 1) * (self._k - 1)]) for e in range(len(self._E))] return self.element_class(self, vec) if type(x) is list: @@ -1111,9 +1094,7 @@ def embed_quaternion(self, g, scale=1, exact=None): """ if exact is None: exact = self._R.is_exact() - return self._Sigma0(scale * self._X.embed_quaternion(g, exact=exact, - prec=self._prec), - check=False) + return self._Sigma0(scale * self._X.embed_quaternion(g, exact=exact, prec=self._prec), check=False) def basis_matrix(self): r""" @@ -1164,22 +1145,17 @@ def basis_matrix(self): pass n_stab_conds = len(stab_conds) - self._M = Matrix(self._R, (nV + n_stab_conds) * d, nE * d, 0, - sparse=True) + self._M = Matrix(self._R, (nV + n_stab_conds) * d, nE * d, 0, sparse=True) for v in self._V: for e in v.leaving_edges: if e.parity: continue - C = sum([self._U.acting_matrix(self.embed_quaternion(x[0]), d) - for x in e.links], - Matrix(self._R, d, d, 0)).transpose() + C = sum([self._U.acting_matrix(self.embed_quaternion(x[0]), d) for x in e.links], Matrix(self._R, d, d, 0)).transpose() self._M.set_block(v.label * d, e.label * d, C) for e in v.entering_edges: if e.parity: continue - C = sum([self._U.acting_matrix(self.embed_quaternion(x[0]), d) - for x in e.opposite.links], - Matrix(self._R, d, d, 0)).transpose() + C = sum([self._U.acting_matrix(self.embed_quaternion(x[0]), d) for x in e.opposite.links], Matrix(self._R, d, d, 0)).transpose() self._M.set_block(v.label * d, e.opposite.label * d, C) for kk in range(n_stab_conds): @@ -1189,9 +1165,7 @@ def basis_matrix(self): x1 = self._M.right_kernel().matrix() if x1.nrows() != self.rank(): - raise RuntimeError('The computed dimension does not agree with ' - 'the expectation. Consider increasing ' - 'precision!') + raise RuntimeError('The computed dimension does not agree with ' 'the expectation. Consider increasing ' 'precision!') K = [c.list() for c in x1.rows()] @@ -1237,9 +1211,9 @@ def __apply_atkin_lehner(self, q, f): for jj in range(nE): t = d1[jj] if t.label < nE: - tmp[jj] += mga * t.igamma(self.embed_quaternion, scale=p ** -t.power) * f._F[t.label] + tmp[jj] += mga * t.igamma(self.embed_quaternion, scale=p**-t.power) * f._F[t.label] else: - tmp[jj] += mga * t.igamma(self.embed_quaternion, scale=p ** -t.power) * (-f._F[t.label - nE]) + tmp[jj] += mga * t.igamma(self.embed_quaternion, scale=p**-t.power) * (-f._F[t.label - nE]) return self(tmp) @@ -1280,9 +1254,9 @@ def __apply_hecke_operator(self, l, f): for jj in range(nE): t = d1[jj] if t.label < nE: - tmp[jj] += mga * t.igamma(self.embed_quaternion, scale=p ** -t.power) * f._F[t.label] + tmp[jj] += mga * t.igamma(self.embed_quaternion, scale=p**-t.power) * f._F[t.label] else: - tmp[jj] += mga * t.igamma(self.embed_quaternion, scale=p ** -t.power) * (-f._F[t.label - nE]) + tmp[jj] += mga * t.igamma(self.embed_quaternion, scale=p**-t.power) * (-f._F[t.label - nE]) return self([factor * x for x in tmp]) def _compute_atkin_lehner_matrix(self, d): @@ -1371,10 +1345,8 @@ def __compute_operator_matrix(self, T): err = A * rest - B if err != 0: try: - if hasattr(err.parent().base_ring().an_element(), - 'valuation'): - minval = min([o.valuation() for o in err.list() - if o != 0]) + if hasattr(err.parent().base_ring().an_element(), 'valuation'): + minval = min([o.valuation() for o in err.list() if o != 0]) else: minval = sum([RR(o.norm() ** 2) for o in err.list()]) verbose('Error = %s' % minval) @@ -1384,6 +1356,7 @@ def __compute_operator_matrix(self, T): res.set_immutable() return res + # class BruhatTitsHarmonicCocyclesSubmodule(BruhatTitsHarmonicCocycles,sage.modular.hecke.submodule.HeckeSubmodule): # r""" # Submodule of a space of BruhatTitsHarmonicCocycles. @@ -1501,6 +1474,7 @@ class pAdicAutomorphicFormElement(ModuleElement): - Cameron Franc (2012-02-20) - Marc Masdeu """ + def __init__(self, parent, vec): """ Create a pAdicAutomorphicFormElement. @@ -1536,8 +1510,7 @@ def _add_(self, g): """ # Should ensure that self and g are of the same weight and on # the same curve - vec = [self._value[e] + g._value[e] - for e in range(self._num_generators)] + vec = [self._value[e] + g._value[e] for e in range(self._num_generators)] return self.parent()(vec) def _sub_(self, g): @@ -1561,8 +1534,7 @@ def _sub_(self, g): """ # Should ensure that self and g are of the same weight and on # the same curve - vec = [self._value[e] - g._value[e] - for e in range(self._num_generators)] + vec = [self._value[e] - g._value[e] for e in range(self._num_generators)] return self.parent()(vec) def _richcmp_(self, other, op): @@ -1586,8 +1558,7 @@ def _richcmp_(self, other, op): if op not in [op_EQ, op_NE]: return NotImplemented - b = all(self._value[e] == other._value[e] - for e in range(self._num_generators)) + b = all(self._value[e] == other._value[e] for e in range(self._num_generators)) if op == op_EQ: return b return not b @@ -1683,8 +1654,7 @@ def _lmul_(self, a): 16 + 16*17 + 16*17^2 + 16*17^3 + 16*17^4 + O(17^5) """ # Should ensure that 'a' is a scalar - return self.parent()([a * self._value[e] - for e in range(self._num_generators)]) + return self.parent()([a * self._value[e] for e in range(self._num_generators)]) def _repr_(self): r""" @@ -1722,8 +1692,7 @@ def valuation(self): sage: (17*a).valuation() 1 """ - return min(self._value[e].valuation() - for e in range(self._num_generators)) + return min(self._value[e].valuation() for e in range(self._num_generators)) def _improve(self, hc): r""" @@ -1853,8 +1822,7 @@ def integrate(self, f, center=1, level=0, method='moments'): for e in E: a, b, c, d = e.list() delta = e.determinant() - verbose('%s' % (R2([e[0, 1], e[0, 0]]) - / R2([e[1, 1], e[1, 0]]))) + verbose('%s' % (R2([e[0, 1], e[0, 0]]) / R2([e[1, 1], e[1, 0]]))) tmp = ((c * x + d) ** n * delta ** -ZZ(n // 2)) * f((a * x + b) / (c * x + d)) exp = R1(tmp.numerator()) / R1(tmp.denominator()) new = eval_dist_at_powseries(self.evaluate(e), exp) @@ -1991,6 +1959,7 @@ def derivative(self, z=None, level=0, method='moments', order=1): sage: (c*x + d)^4*f(x)-f((a*x + b)/(c*x + d)) O(7^5) """ + def F(z, level=level, method=method): R = PolynomialRing(z.parent(), 'x,y').fraction_field() Rx = PolynomialRing(z.parent(), 'x1').fraction_field() @@ -2003,11 +1972,10 @@ def F(z, level=level, method=method): k = self.parent()._n + 2 V = [f] for ii in range(order): - V = [v.derivative(y) for v in V] + [k / (y - zbar) * v - for v in V] + V = [v.derivative(y) for v in V] + [k / (y - zbar) * v for v in V] k += 2 - return sum(self.integrate(subst(v), center, level, method) - for v in V) + return sum(self.integrate(subst(v), center, level, method) for v in V) + if z is None: return F @@ -2122,8 +2090,7 @@ class pAdicAutomorphicForms(Module, UniqueRepresentation): Element = pAdicAutomorphicFormElement @staticmethod - def __classcall__(cls, domain, U, prec=None, t=None, R=None, - overconvergent=False): + def __classcall__(cls, domain, U, prec=None, t=None, R=None, overconvergent=False): r""" The module of (quaternionic) `p`-adic automorphic forms. @@ -2168,12 +2135,9 @@ def __classcall__(cls, domain, U, prec=None, t=None, R=None, - Cameron Franc (2012-02-20) - Marc Masdeu (2012-02-20) """ - return super().__classcall__(cls, domain, U, - prec, t, R, - overconvergent) + return super().__classcall__(cls, domain, U, prec, t, R, overconvergent) - def __init__(self, domain, U, prec=None, t=None, R=None, - overconvergent=False): + def __init__(self, domain, U, prec=None, t=None, R=None, overconvergent=False): """ Create a space of `p`-automorphic forms. @@ -2201,17 +2165,9 @@ def __init__(self, domain, U, prec=None, t=None, R=None, else: t = 0 if overconvergent: - self._U = OverconvergentDistributions(U - 2, base=self._R, - prec_cap=U - 1 + t, - act_on_left=True, - adjuster=_btquot_adjuster(), - dettwist=-ZZ((U - 2) // 2), - act_padic=True) + self._U = OverconvergentDistributions(U - 2, base=self._R, prec_cap=U - 1 + t, act_on_left=True, adjuster=_btquot_adjuster(), dettwist=-ZZ((U - 2) // 2), act_padic=True) else: - self._U = Symk(U - 2, base=self._R, act_on_left=True, - adjuster=_btquot_adjuster(), - dettwist=-ZZ((U - 2) // 2), - act_padic=True) + self._U = Symk(U - 2, base=self._R, act_on_left=True, adjuster=_btquot_adjuster(), dettwist=-ZZ((U - 2) // 2), act_padic=True) else: self._U = U self._source = domain @@ -2275,9 +2231,7 @@ def __eq__(self, other): if not isinstance(other, pAdicAutomorphicForms): return False - return (self.base_ring() == other.base_ring() and - self._source == other._source and - self._U == other._U) + return self.base_ring() == other.base_ring() and self._source == other._source and self._U == other._U def __ne__(self, other): r""" @@ -2392,8 +2346,7 @@ def _element_constructor_(self, data): F = [] Uold = data.parent()._U for ii in range(len(data._F)): - newtmp = data.parent()._Sigma0(E[ii].rep.inverse(), check=False) * Uold(data._F[ii], - normalize=False) + newtmp = data.parent()._Sigma0(E[ii].rep.inverse(), check=False) * Uold(data._F[ii], normalize=False) tmp.append(newtmp) F.append(newtmp) A = data.parent()._Sigma0(Matrix(QQ, 2, 2, [0, ~self.prime(), 1, 0]), check=False) @@ -2504,8 +2457,7 @@ def _make_invariant(self, F): m = M[ii] for v in Si: s += 1 - g = self._Sigma0(m.adjugate() * self._source.embed_quaternion(v[0], prec=self._prec).adjugate() * m, - check=False) + g = self._Sigma0(m.adjugate() * self._source.embed_quaternion(v[0], prec=self._prec).adjugate() * m, check=False) newFi += g * x newF.append((QQ(1) / s) * newFi) else: @@ -2541,8 +2493,7 @@ def _apply_Up_operator(self, f, scale=False, original_moments=None): # Save original moments if original_moments is None: - original_moments = [[fval._moments[ii] for ii in range(self._n + 1)] - for fval in f._value] + original_moments = [[fval._moments[ii] for ii in range(self._n + 1)] for fval in f._value] Tf = [] for jj in range(len(self._list)): @@ -2550,8 +2501,7 @@ def _apply_Up_operator(self, f, scale=False, original_moments=None): for gg, edge_list in HeckeData: u = edge_list[jj] tprec = 2 * (prec_cap + u.power) + 1 - r = S0(self._p ** -u.power * (u.t(tprec) * gg).adjugate(), - check=False) + r = S0(self._p**-u.power * (u.t(tprec) * gg).adjugate(), check=False) tmp += r * f._value[u.label] tmp *= factor for ii in range(self._n + 1): diff --git a/src/sage/modular/buzzard.py b/src/sage/modular/buzzard.py index 6c88bfcf172..71c1e11da3e 100644 --- a/src/sage/modular/buzzard.py +++ b/src/sage/modular/buzzard.py @@ -95,5 +95,5 @@ def buzzard_tpslopes(p, N, kmax): pari.read(buzzard_dir / "Tpprog.g") # v = pari.tpslopes(p, N, kmax).sage() v = pari('tpslopes(%s, %s, %s)' % (p, N, kmax)).sage() - v.insert(0, []) # so that v[k] = info about weight k + v.insert(0, []) # so that v[k] = info about weight k return v diff --git a/src/sage/modular/cusps.py b/src/sage/modular/cusps.py index 4fc336a12b9..5fb96249897 100644 --- a/src/sage/modular/cusps.py +++ b/src/sage/modular/cusps.py @@ -64,6 +64,7 @@ class Cusp(Element): sage: a.parent() is b.parent() True """ + def __init__(self, a, b=None, parent=None, check=True): r""" Create the cusp a/b in `\mathbb{P}^1(\QQ)`, where if b=0 @@ -176,8 +177,7 @@ def __init__(self, a, b=None, parent=None, check=True): elif isinstance(a, Rational): self.__a = a.numer() self.__b = a.denom() - elif (isinstance(a, InfinityElement) or - (isinstance(a, pari_gen) and a.type() == 't_INFINITY')): + elif isinstance(a, InfinityElement) or (isinstance(a, pari_gen) and a.type() == 't_INFINITY'): self.__a = ZZ.one() self.__b = ZZ.zero() elif isinstance(a, Cusp): @@ -464,8 +464,7 @@ def __neg__(self): """ return Cusp(-self.__a, self.__b) - def is_gamma0_equiv(self, other, N, - transformation=None) -> bool | tuple[bool, Any]: + def is_gamma0_equiv(self, other, N, transformation=None) -> bool | tuple[bool, Any]: r""" Return whether ``self`` and ``other`` are equivalent modulo the action of `\Gamma_0(N)` via linear fractional transformations. @@ -600,7 +599,7 @@ def is_gamma0_equiv(self, other, N, a = s1 * v2 - s2 * v1 assert (a % g).is_zero() # solve x*v1*v2 + a = 0 (mod N). - d, x0, y0 = (v1 * v2).xgcd(N) # x0*v1*v2 + y0*N = d = g. + d, x0, y0 = (v1 * v2).xgcd(N) # x0*v1*v2 + y0*N = d = g. # so x0*v1*v2 - g = 0 (mod N) x = -x0 * ZZ(a / g) # now x*v1*v2 + a = 0 (mod N) @@ -612,9 +611,9 @@ def is_gamma0_equiv(self, other, N, if transformation == "matrix": C = s1p * v2 - s2 * v1 if C % (M * v1 * v2) == 0: - k = - C // (M * v1 * v2) + k = -C // (M * v1 * v2) else: - k = - (C / (M * v1 * v2)).round("away") + k = -(C / (M * v1 * v2)).round("away") s1pp = s1p + k * M * v1 # C += k*M*v1*v2 # is now the smallest in absolute value @@ -633,7 +632,7 @@ def is_gamma0_equiv(self, other, N, # mainly for backwards compatibility and # for how it is used in modular symbols - A = (u2 * s1p - r2 * v1) + A = u2 * s1p - r2 * v1 if u2 != 0 and v1 != 0: A = A % (u2 * v1 * M) return (True, A) @@ -687,9 +686,9 @@ def is_gamma1_equiv(self, other, N) -> tuple[bool, int]: u2 = other.__a v2 = other.__b g = v1.gcd(N) - if ((v2 - v1) % N == 0 and (u2 - u1) % g == 0): + if (v2 - v1) % N == 0 and (u2 - u1) % g == 0: return True, 1 - if ((v2 + v1) % N == 0 and (u2 + u1) % g == 0): + if (v2 + v1) % N == 0 and (u2 + u1) % g == 0: return True, -1 return False, 0 @@ -763,6 +762,7 @@ def is_gamma_h_equiv(self, other, G) -> tuple[bool, int]: 0 """ from sage.modular.arithgroup.congroup_gammaH import GammaH_class + if not isinstance(other, Cusp): other = Cusp(other) if not isinstance(G, GammaH_class): @@ -816,11 +816,9 @@ def _acted_upon_(self, g, self_on_left): Set P^1(QQ) of all cusps """ if not self_on_left: - if (isinstance(g, Matrix) and g.base_ring() is ZZ - and g.ncols() == 2 == g.nrows()): + if isinstance(g, Matrix) and g.base_ring() is ZZ and g.ncols() == 2 == g.nrows(): a, b, c, d = g.list() - return Cusp(a * self.__a + b * self.__b, - c * self.__a + d * self.__b) + return Cusp(a * self.__a + b * self.__b, c * self.__a + d * self.__b) def apply(self, g): """ @@ -836,8 +834,7 @@ def apply(self, g): sage: Cusp(0).apply([1,-3,0,1]) -3 """ - return Cusp(g[0] * self.__a + g[1] * self.__b, - g[2] * self.__a + g[3] * self.__b) + return Cusp(g[0] * self.__a + g[1] * self.__b, g[2] * self.__a + g[3] * self.__b) def galois_action(self, t, N): r""" @@ -1007,6 +1004,7 @@ class Cusps_class(Singleton, Parent): sage: loads(C.dumps()) == C True """ + def __init__(self): r""" The set of cusps, i.e. `\mathbb{P}^1(\QQ)`. diff --git a/src/sage/modular/cusps_nf.py b/src/sage/modular/cusps_nf.py index 6eba086933b..3ce7d2fe9d3 100644 --- a/src/sage/modular/cusps_nf.py +++ b/src/sage/modular/cusps_nf.py @@ -159,6 +159,7 @@ class NFCuspsSpace(UniqueRepresentation, Parent): sage: kCusps = NFCusps(k); kCusps Set of all cusps of Number Field in a with defining polynomial x^2 + 5 """ + def __init__(self, number_field): """ See ``NFCusps`` for full documentation. @@ -313,6 +314,7 @@ def number_field(self): """ return self.__number_field + # ************************************************************************* # NFCusp class * # ************************************************************************* @@ -420,6 +422,7 @@ class NFCusp(Element): ... ValueError: Cannot coerce cusps from one field to another """ + def __init__(self, number_field, a, b=None, parent=None, lreps=None): """ Constructor of number field cusps. See ``NFCusp`` for full @@ -466,8 +469,11 @@ def __init__(self, number_field, a, b=None, parent=None, lreps=None): self.__b = R.one() elif isinstance(a, (tuple, list)): if len(a) != 2: - raise TypeError("unable to convert %r to a cusp \ - of the number field" % a) + raise TypeError( + "unable to convert %r to a cusp \ + of the number field" + % a + ) if a[1].is_zero(): self.__a = R.one() self.__b = R.zero() @@ -488,28 +494,24 @@ def __init__(self, number_field, a, b=None, parent=None, lreps=None): self.__b = R(r.denominator()) self.__a = R(r * self.__b) except (ValueError, TypeError): - raise TypeError(f"unable to convert {a} to a cusp " - "of the number field") + raise TypeError(f"unable to convert {a} to a cusp " "of the number field") else: try: r = number_field(a) self.__b = R(r.denominator()) self.__a = R(r * self.__b) except (ValueError, TypeError): - raise TypeError("unable to convert %r to a cusp " - "of the number field" % a) + raise TypeError("unable to convert %r to a cusp " "of the number field" % a) else: # 'b' is given if isinstance(b, InfinityElement): if isinstance(a, InfinityElement) or (isinstance(a, NFCusp) and a.is_infinity()): - raise TypeError("unable to convert (%r, %r) " - "to a cusp of the number field" % (a, b)) + raise TypeError("unable to convert (%r, %r) " "to a cusp of the number field" % (a, b)) self.__a = R.zero() self.__b = R.one() return if not b: if not a: - raise TypeError("unable to convert (%r, %r) " - "to a cusp of the number field" % (a, b)) + raise TypeError("unable to convert (%r, %r) " "to a cusp of the number field" % (a, b)) self.__a = R.one() self.__b = R.zero() return @@ -537,15 +539,21 @@ def __init__(self, number_field, a, b=None, parent=None, lreps=None): r = R(a) / b elif isinstance(a, (tuple, list)): if len(a) != 2: - raise TypeError("unable to convert (%r, %r) \ - to a cusp of the number field" % (a, b)) + raise TypeError( + "unable to convert (%r, %r) \ + to a cusp of the number field" + % (a, b) + ) r = R(a[0]) / (R(a[1]) * b) else: try: r = number_field(a) / b except (ValueError, TypeError): - raise TypeError("unable to convert (%r, %r) \ - to a cusp of the number field" % (a, b)) + raise TypeError( + "unable to convert (%r, %r) \ + to a cusp of the number field" + % (a, b) + ) self.__b = R(r.denominator()) self.__a = R(r * self.__b) if lreps is not None: @@ -579,8 +587,7 @@ def _repr_(self): """ if self.__b.is_zero(): return "Cusp Infinity of %s" % self.parent().number_field() - return "Cusp [%s: %s] of %s" % (self.__a, self.__b, - self.parent().number_field()) + return "Cusp [%s: %s] of %s" % (self.__a, self.__b, self.parent().number_field()) def number_field(self): """ @@ -666,8 +673,7 @@ def _number_field_element_(self): -1/3*a + 1/3 """ if self.__b.is_zero(): - raise TypeError("%s is not an element of %s" % (self, - self.number_field())) + raise TypeError("%s is not an element of %s" % (self, self.number_field())) k = self.number_field() return k(self.__a / self.__b) @@ -713,8 +719,7 @@ def _latex_(self): """ if self.__b.is_zero(): return "\\infty" - return "\\[%s: %s\\]" % (self.__a._latex_(), - self.__b._latex_()) + return "\\[%s: %s\\]" % (self.__a._latex_(), self.__b._latex_()) def _richcmp_(self, right, op): """ @@ -753,8 +758,7 @@ def _richcmp_(self, right, op): return rich_to_bool(op, 1) if right.__b.is_zero(): return rich_to_bool(op, -1) - return richcmp(self._number_field_element_(), - right._number_field_element_(), op) + return richcmp(self._number_field_element_(), right._number_field_element_(), op) def __neg__(self): """ @@ -797,8 +801,7 @@ def apply(self, g): Cusp [a: 1] of Number Field in a with defining polynomial x^2 + 23 """ k = self.number_field() - return NFCusp(k, g[0] * self.__a + g[1] * self.__b, - g[2] * self.__a + g[3] * self.__b) + return NFCusp(k, g[0] * self.__a + g[1] * self.__b, g[2] * self.__a + g[3] * self.__b) def ideal(self): """ @@ -886,7 +889,7 @@ def ABmatrix(self) -> list: a2 = self.__b g = (A * B).gens_reduced()[0] - Ainv = A**(-1) + Ainv = A ** (-1) A1 = a1 * Ainv A2 = a2 * Ainv r = A1.element_1_mod(A2) @@ -894,8 +897,7 @@ def ABmatrix(self) -> list: b2 = (r / a1) * g return [a1, b1, a2, b2] - def is_Gamma0_equivalent(self, other, N, - Transformation=False) -> bool | tuple[bool, Any]: + def is_Gamma0_equivalent(self, other, N, Transformation=False) -> bool | tuple[bool, Any]: r""" Check if cusps ``self`` and ``other`` are `\Gamma_0(N)`- equivalent. @@ -988,6 +990,7 @@ def is_Gamma0_equivalent(self, other, N, AuxCoeff[3] = u AuxCoeff[1] = w from sage.matrix.constructor import Matrix + Maux = Matrix(k, 2, AuxCoeff) M1inv = Matrix(k, 2, M1).inverse() Mtrans = Matrix(k, 2, M2) * Maux * M1inv @@ -997,6 +1000,7 @@ def is_Gamma0_equivalent(self, other, N, return False return False, 0 + # ************************************************************************* # Global functions: # - Gamma0_NFCusps --compute list of inequivalent cusps @@ -1068,11 +1072,11 @@ def Gamma0_NFCusps(N): # for every divisor of N we have to find cusps from sage.arith.misc import divisors + for d in divisors(N): # find delta prime coprime to B in inverse class of d*A # by searching in our list of auxiliary prime ideals - Lds = [P for P in Laux - if (P * d * A).is_principal() and P.is_coprime(B)] + Lds = [P for P in Laux if (P * d * A).is_principal() and P.is_coprime(B)] deltap = Lds[0] a = (deltap * d * A).gens_reduced()[0] I = d + N / d @@ -1131,9 +1135,9 @@ def number_of_Gamma0_NFCusps(N): k = N.number_field() # The number of Gamma0(N)-sub-orbits for each Gamma-orbit: from sage.arith.misc import divisors + Ugens = [k(u) for u in k.unit_group().gens()] - s = sum([len((d + N / d).invertible_residues_mod(Ugens)) - for d in divisors(N)]) + s = sum([len((d + N / d).invertible_residues_mod(Ugens)) for d in divisors(N)]) # There are h Gamma-orbits, with h class number of underlying number field. return s * k.class_number() @@ -1188,7 +1192,7 @@ def NFCusps_ideal_reps_for_levelN(N, nlists=1): for I in G.list(): check = 0 if not I.is_principal(): - Iinv = I.ideal()**(-1) + Iinv = I.ideal() ** (-1) while check < nlists: J = next(it) if (J * Iinv).is_principal() and J.is_coprime(N): diff --git a/src/sage/modular/dims.py b/src/sage/modular/dims.py index 49baec65e1f..3e5d2edab7e 100644 --- a/src/sage/modular/dims.py +++ b/src/sage/modular/dims.py @@ -83,6 +83,7 @@ def eisen(p): raise ValueError("p must be prime") return frac(p - 1, 12).numerator() + ########################################################################## # Formula of Cohen-Oesterlé for dim S_k(Gamma_1(N),eps). REF: # Springer Lecture notes in math, volume 627, pages 69--78. The @@ -123,10 +124,10 @@ def CO_delta(r, p, N, eps): return K.zero() # interesting case: p=1(mod 4). # omega is a primitive 4th root of unity mod p. - omega = (IntegerModRing(p).unit_gens()[0])**((p - 1) // 4) + omega = (IntegerModRing(p).unit_gens()[0]) ** ((p - 1) // 4) # this n is within a p-power root of a "local" 4th root of 1 modulo p. n = Mod(int(omega.crt(Mod(1, N // (p**r)))), N) - n = n**(p**(r - 1)) # this is correct now + n = n ** (p ** (r - 1)) # this is correct now t = eps(n) if t == K.one(): return K(2) @@ -168,10 +169,10 @@ def CO_nu(r, p, N, eps): return K.zero() # interesting case: p=1(mod 3) # omega is a cube root of 1 mod p. - omega = (IntegerModRing(p).unit_gens()[0])**((p - 1) // 3) + omega = (IntegerModRing(p).unit_gens()[0]) ** ((p - 1) // 3) n = Mod(omega.crt(Mod(1, N // (p**r))), N) # within a p-power root of a "local" cube root of 1 mod p. - n = n**(p**(r - 1)) # this is right now + n = n ** (p ** (r - 1)) # this is right now t = eps(n) if t == K.one(): return K(2) @@ -237,15 +238,12 @@ def _lambda(r, s, p): """ if 2 * s <= r: if r % 2 == 0: - return p**(r // 2) + p**((r // 2) - 1) - return 2 * p**((r - 1) // 2) - return 2 * p**(r - s) + return p ** (r // 2) + p ** ((r // 2) - 1) + return 2 * p ** ((r - 1) // 2) + return 2 * p ** (r - s) K = eps.base_ring() - return K(frac(-1, 2) * - prod(_lambda(r, valuation(f, p), p) for p, r in facN) + - gamma_k * K.prod(CO_delta(r, p, N, eps) for p, r in facN) + - mu_k * K.prod(CO_nu(r, p, N, eps) for p, r in facN)) + return K(frac(-1, 2) * prod(_lambda(r, valuation(f, p), p) for p, r in facN) + gamma_k * K.prod(CO_delta(r, p, N, eps) for p, r in facN) + mu_k * K.prod(CO_nu(r, p, N, eps) for p, r in facN)) #################################################################### @@ -253,6 +251,7 @@ def _lambda(r, s, p): # These have very flexible inputs. #################################################################### + def dimension_new_cusp_forms(X, k=2, p=0): """ Return the dimension of the new (or `p`-new) subspace of @@ -405,8 +404,7 @@ def dimension_cusp_forms(X, k=2): return X.dimension_cusp_forms(k) if isinstance(X, (int, Integer)): return Gamma0(X).dimension_cusp_forms(k) - raise TypeError("argument 1 must be a Dirichlet character, an integer " - "or a finite index subgroup of SL2Z") + raise TypeError("argument 1 must be a Dirichlet character, an integer " "or a finite index subgroup of SL2Z") def dimension_eis(X, k=2): @@ -525,8 +523,7 @@ def dimension_modular_forms(X, k=2): return X.dimension_modular_forms(k) if isinstance(X, dirichlet.DirichletCharacter): return Gamma1(X.modulus()).dimension_modular_forms(k, eps=X) - raise TypeError("argument 1 must be an integer, a Dirichlet character " - "or an arithmetic subgroup") + raise TypeError("argument 1 must be an integer, a Dirichlet character " "or an arithmetic subgroup") def sturm_bound(level, weight=2): diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index 6422cbb6726..05cbbb62aaa 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -168,6 +168,7 @@ class DirichletCharacter(MultiplicativeGroupElement): """ A Dirichlet character. """ + def __init__(self, parent, x, check=True) -> None: r""" Create a Dirichlet character with specified values on @@ -250,15 +251,13 @@ def __init__(self, parent, x, check=True) -> None: if isinstance(x, free_module_element.FreeModuleElement): x = parent._module(x) if any(u * v for u, v in zip(x, orders)): - raise ValueError("values (= {} modulo {}) must have additive orders dividing {}, respectively" - .format(x, parent.zeta_order(), orders)) + raise ValueError("values (= {} modulo {}) must have additive orders dividing {}, respectively".format(x, parent.zeta_order(), orders)) self.element.set_cache(x) else: R = parent.base_ring() x = tuple(map(R, x)) if R.is_exact() and any(u**v != 1 for u, v in zip(x, orders)): - raise ValueError("values (= {}) must have multiplicative orders dividing {}, respectively" - .format(x, orders)) + raise ValueError("values (= {}) must have multiplicative orders dividing {}, respectively".format(x, orders)) self.values_on_gens.set_cache(x) elif isinstance(x, free_module_element.FreeModuleElement): self.element.set_cache(x) @@ -683,7 +682,7 @@ def bernoulli(self, k, algorithm='recurrence', cache=True, **opts): # By definition, the first Bernoulli number of the trivial # character is 1/2, in contrast to the value B_1 = -1/2. ber = K.one() / 2 if k == 1 else K(bernoulli(k)) - elif self(-1) != K((-1)**k): + elif self(-1) != K((-1) ** k): ber = K.zero() elif algorithm == "recurrence": # The following code is pretty fast, at least compared to @@ -699,8 +698,7 @@ def bernoulli(self, k, algorithm='recurrence', cache=True, **opts): def S(n): return sum(v[r] * r**n for r in range(1, N)) - ber = sum(ZZ(k).binomial(j) * bernoulli(j, **opts) * - N**(j - 1) * S(k - j) for j in range(k + 1)) + ber = sum(ZZ(k).binomial(j) * bernoulli(j, **opts) * N ** (j - 1) * S(k - j) for j in range(k + 1)) elif algorithm == "definition": # This is better since it computes the same thing, but requires # no arith in a poly ring over a number field. @@ -754,11 +752,13 @@ def lfunction(self, prec=53, algorithm='pari'): if algorithm == 'pari': from sage.lfunctions.pari import lfun_character, LFunction + Z = LFunction(lfun_character(self), prec=prec) Z.rename('PARI L-function associated to %s' % self) return Z if algorithm == 'lcalc': from sage.libs.lcalc.lcalc_Lfunction import Lfunction_from_character + return Lfunction_from_character(self) raise ValueError('algorithm must be "pari" or "lcalc"') @@ -796,7 +796,7 @@ def conductor(self): # depends only on the factor of p**(r-1) on the right hand side. # Since p-1 is coprime to p, this smallest r such that the # divisibility holds equals Valuation(Order(x),p)+1. - cond = p**(valuation(self.order(), p) + 1) + cond = p ** (valuation(self.order(), p) + 1) if p == 2 and F[0][1] > 2 and self.values_on_gens()[1].multiplicative_order() != 1: cond *= 2 return Integer(cond) @@ -921,6 +921,7 @@ def fixed_field_polynomial(self, algorithm='pari'): if f == 1: from sage.misc.functional import cyclotomic_polynomial + return cyclotomic_polynomial(n, S.gen()) if d == 2: @@ -948,7 +949,7 @@ def fixed_field_polynomial(self, algorithm='pari'): for i in range(d): eta.append([]) for j in range(f): - r = g**(i + d * j) + r = g ** (i + d * j) eta[i].append(r) gen_index[r] = i @@ -1077,7 +1078,7 @@ def decomposition(self) -> list: """ D = self.parent().decomposition() vals = [[z] for z in self.values_on_gens()] - if self.modulus() % 8 == 0: # 2 factors at 2. + if self.modulus() % 8 == 0: # 2 factors at 2. vals[0].append(vals[1][0]) del vals[1] elif self.modulus() % 4 == 2: # 0 factors at 2. @@ -1216,6 +1217,7 @@ def lmfdb_page(self) -> None: sage: E.lmfdb_page() # optional -- webbrowser """ import webbrowser + lmfdb_url = 'https://www.lmfdb.org/Character/Dirichlet/{}/{}' url = lmfdb_url.format(self.modulus(), self.conrey_number()) webbrowser.open(url) @@ -1356,15 +1358,14 @@ def gauss_sum(self, a=1): if isinstance(K, sage.rings.abc.AlgebraicField): L = K zeta = L.zeta(m) - elif isinstance(K, (sage.rings.abc.NumberField_cyclotomic, - RationalField)): + elif isinstance(K, (sage.rings.abc.NumberField_cyclotomic, RationalField)): chi = chi.minimize_base_ring() n = lcm(m, G.zeta_order()) L = CyclotomicField(n) zeta = L.gen(0) ** (n // m) else: raise NotImplementedError("Gauss sums only currently implemented when the base ring is a cyclotomic field, QQ, QQbar, or a complex field") - zeta = zeta ** a + zeta = zeta**a g = L(chi(0)) z = L.one() for c in chi.values()[1:]: @@ -1433,13 +1434,14 @@ def gauss_sum_numerical(self, prec=53, a=1): def phi(t): return t + CC = K elif isinstance(K, sage.rings.abc.AlgebraicField): from sage.rings.complex_mpfr import ComplexField + CC = ComplexField(prec) phi = CC.coerce_map_from(K) - elif isinstance(K, (sage.rings.abc.NumberField_cyclotomic, - RationalField)): + elif isinstance(K, (sage.rings.abc.NumberField_cyclotomic, RationalField)): phi = K.complex_embedding(prec) CC = phi.codomain() else: @@ -1559,8 +1561,7 @@ def jacobi_sum(self, char, check=True): if self.parent() != char.parent(): raise NotImplementedError("Characters must be from the same Dirichlet Group.") - return sum([self(x) * char(1 - x) - for x in IntegerModRing(self.modulus())]) + return sum([self(x) * char(1 - x) for x in IntegerModRing(self.modulus())]) def kloosterman_sum(self, a=1, b=0): r""" @@ -1616,15 +1617,14 @@ def kloosterman_sum(self, a=1, b=0): L = CyclotomicField(m.lcm(zo)) zeta = L.gen(0) try: - self(1) * zeta**(a + b) + self(1) * zeta ** (a + b) except TypeError: - raise NotImplementedError('Kloosterman sums not implemented ' - 'over this ring') + raise NotImplementedError('Kloosterman sums not implemented ' 'over this ring') n = zeta.multiplicative_order() - zeta = zeta**(n // m) + zeta = zeta ** (n // m) for c in m.coprime_integers(m): e = Mod(c, m) - g += self(c) * zeta**int(a * e + b * e**(-1)) + g += self(c) * zeta ** int(a * e + b * e ** (-1)) return g def kloosterman_sum_numerical(self, prec=53, a=1, b=0): @@ -1660,8 +1660,7 @@ def kloosterman_sum_numerical(self, prec=53, a=1, b=0): """ G = self.parent() K = G.base_ring() - if not isinstance(K, (sage.rings.abc.NumberField_cyclotomic, - RationalField)): + if not isinstance(K, (sage.rings.abc.NumberField_cyclotomic, RationalField)): raise NotImplementedError("Kloosterman sums only currently implemented when the base ring is a cyclotomic field or QQ") phi = K.complex_embedding(prec) CC = phi.codomain() @@ -1670,7 +1669,7 @@ def kloosterman_sum_numerical(self, prec=53, a=1, b=0): zeta = CC.zeta(m) for c in m.coprime_integers(m): e = Mod(c, m) - z = zeta ** int(a * e + b * (e**(-1))) + z = zeta ** int(a * e + b * (e ** (-1))) g += phi(self(c)) * z return g @@ -1781,7 +1780,7 @@ def is_primitive(self) -> bool: sage: (a*b).is_primitive() True """ - return (self.conductor() == self.modulus()) + return self.conductor() == self.modulus() @cached_method def is_trivial(self) -> bool: @@ -1911,8 +1910,7 @@ def minimize_base_ring(self): K = IntegerModRing(p) elif self.order() <= 2: K = QQ - elif (isinstance(R, NumberField_generic) - and euler_phi(self.order()) < R.absolute_degree()): + elif isinstance(R, NumberField_generic) and euler_phi(self.order()) < R.absolute_degree(): K = CyclotomicField(self.order()) else: return self @@ -2154,8 +2152,7 @@ def element(self): if isinstance(P.base_ring(), sage.rings.abc.ComplexField): zeta = P.zeta() zeta_argument = zeta.argument() - v = M([int(round(x.argument() / zeta_argument)) - for x in self.values_on_gens()]) + v = M([int(round(x.argument() / zeta_argument)) for x in self.values_on_gens()]) else: dlog = P._zeta_dlog v = M([dlog[x] for x in self.values_on_gens()]) @@ -2437,8 +2434,8 @@ class DirichletGroupFactory(UniqueFactory): sage: loads(dumps(G)) is G True """ - def create_key(self, N, base_ring=None, zeta=None, zeta_order=None, - names=None, integral=False): + + def create_key(self, N, base_ring=None, zeta=None, zeta_order=None, names=None, integral=False): """ Create a key that uniquely determines a Dirichlet group. @@ -2515,8 +2512,7 @@ def create_key(self, N, base_ring=None, zeta=None, zeta_order=None, zeta_order = zeta.multiplicative_order() elif zeta_order is not None: if not base_ring.is_integral_domain(): - raise ValueError("base ring (= %s) must be an integral domain if only zeta_order is specified" - % base_ring) + raise ValueError("base ring (= %s) must be an integral domain if only zeta_order is specified" % base_ring) zeta_order = Integer(zeta_order) zeta = base_ring.zeta(zeta_order) @@ -2575,6 +2571,7 @@ def __init__(self, base_ring, modulus, zeta, zeta_order) -> None: False """ from sage.categories.groups import Groups + category = Groups().Commutative() if base_ring.is_integral_domain() or base_ring.is_finite(): # The group of n-th roots of unity in the base ring is @@ -2599,8 +2596,7 @@ def _module(self): sage: DirichletGroup(12)._module Vector space of dimension 2 over Ring of integers modulo 2 """ - return FreeModule(IntegerModRing(self.zeta_order()), - len(self.unit_gens())) + return FreeModule(IntegerModRing(self.zeta_order()), len(self.unit_gens())) @property def _zeta_powers(self): @@ -2695,9 +2691,7 @@ def change_ring(self, R, zeta=None, zeta_order=None): zeta = R(zeta) if isinstance(R, Map): R = R.codomain() - return DirichletGroup(self.modulus(), R, - zeta=zeta, - zeta_order=zeta_order) + return DirichletGroup(self.modulus(), R, zeta=zeta, zeta_order=zeta_order) def base_extend(self, R): """ @@ -2753,10 +2747,8 @@ def base_extend(self, R): sage: g.parent().zeta() 14 """ - if not (isinstance(R, Map) or - R.has_coerce_map_from(self.base_ring())): - raise TypeError("no coercion map from %s to %s is defined" - % (self.base_ring(), R)) + if not (isinstance(R, Map) or R.has_coerce_map_from(self.base_ring())): + raise TypeError("no coercion map from %s to %s is defined" % (self.base_ring(), R)) return self.change_ring(R) def _element_constructor_(self, x): @@ -2830,12 +2822,7 @@ def _coerce_map_from_(self, X) -> bool: sage: trivial_character(3) == DirichletGroup(3, QQ).0^2 True """ - return (isinstance(X, DirichletGroup_class) and - self.modulus() == X.modulus() and - self.base_ring().has_coerce_map_from(X.base_ring()) and - (self._zeta is None or - (X._zeta is not None and - self.base_ring()(X._zeta) in self._zeta_powers))) + return isinstance(X, DirichletGroup_class) and self.modulus() == X.modulus() and self.base_ring().has_coerce_map_from(X.base_ring()) and (self._zeta is None or (X._zeta is not None and self.base_ring()(X._zeta) in self._zeta_powers)) def __len__(self): """ @@ -2896,10 +2883,7 @@ def decomposition(self) -> list: Group of Dirichlet characters modulo 5 with values in Finite Field of size 5] """ R = self.base_ring() - return Sequence([DirichletGroup(p**r, R) - for p, r in factor(self.modulus())], - cr=True, - universe=Objects()) + return Sequence([DirichletGroup(p**r, R) for p, r in factor(self.modulus())], cr=True, universe=Objects()) def exponent(self): """ @@ -3001,7 +2985,7 @@ def galois_orbits(self, v=None, reps_only=False, sort=True, check=True): seen_so_far = set() for x in v: z = x.element() - e = tuple(z) # change when there are immutable vectors (and below) + e = tuple(z) # change when there are immutable vectors (and below) if e in seen_so_far: continue orbit = x.galois_orbit(sort=sort) diff --git a/src/sage/modular/drinfeld_modform/element.py b/src/sage/modular/drinfeld_modform/element.py index 19906692fe8..bf4a2a579b5 100644 --- a/src/sage/modular/drinfeld_modform/element.py +++ b/src/sage/modular/drinfeld_modform/element.py @@ -92,12 +92,12 @@ class DrinfeldModularFormsElement(ModuleElement): :class:`~sage.modular.drinfeld_modform.ring.DrinfeldModularForms` and access its elements using the relevant methods. """ + def __init__(self, parent, polynomial): if not isinstance(polynomial, MPolynomial): raise TypeError("input must be a multivariate polynomial") if not parent.base_ring().has_coerce_map_from(polynomial.base_ring()): - raise ValueError("unable to coerce base ring of the given " - "polynomial into Drinfeld modular form ring") + raise ValueError("unable to coerce base ring of the given " "polynomial into Drinfeld modular form ring") poly = parent._poly_ring(polynomial) self._polynomial = poly @@ -146,7 +146,7 @@ def _mul_(self, other): sage: (M.0 + M.1)*M.0 g1*g2 + g1^2 """ - return self.__class__(self.parent(), self._polynomial*other._polynomial) + return self.__class__(self.parent(), self._polynomial * other._polynomial) def _lmul_(self, c): r""" @@ -165,7 +165,7 @@ def _lmul_(self, c): sage: M.0 * 0 0 """ - return self.__class__(self.parent(), c*self._polynomial) + return self.__class__(self.parent(), c * self._polynomial) def __neg__(self): r""" @@ -411,7 +411,7 @@ def type(self): if not self.parent()._has_type: return ZZ(0) q = self.base_ring().base_ring().cardinality() - return self.polynomial().degrees()[-1] % (q-1) + return self.polynomial().degrees()[-1] % (q - 1) def weight(self): r""" diff --git a/src/sage/modular/drinfeld_modform/ring.py b/src/sage/modular/drinfeld_modform/ring.py index 96e5139eefc..9614589523b 100644 --- a/src/sage/modular/drinfeld_modform/ring.py +++ b/src/sage/modular/drinfeld_modform/ring.py @@ -188,8 +188,7 @@ class DrinfeldModularForms(Parent, UniqueRepresentation): Element = DrinfeldModularFormsElement @staticmethod - def __classcall_private__(cls, base_ring, rank=None, group=None, - has_type=False, names=None): + def __classcall_private__(cls, base_ring, rank=None, group=None, has_type=False, names=None): r""" Check input validity and return a ``DrinfeldModularForms`` object. @@ -263,11 +262,9 @@ def __classcall_private__(cls, base_ring, rank=None, group=None, TypeError: rank or names must be specified """ if not isinstance(base_ring, FractionField_generic): - raise TypeError("base ring must be a fraction field of a " - "polynomial ring") + raise TypeError("base ring must be a fraction field of a " "polynomial ring") if not isinstance(base_ring.base(), PolynomialRing_generic): - raise NotImplementedError("Drinfeld modular forms are currently " - "only implemented for A = Fq[T]") + raise NotImplementedError("Drinfeld modular forms are currently " "only implemented for A = Fq[T]") if not base_ring.characteristic(): raise ValueError("base ring characteristic must be finite") if not base_ring.base().base().is_field(): @@ -275,9 +272,8 @@ def __classcall_private__(cls, base_ring, rank=None, group=None, if not base_ring.base().base().is_finite(): raise ValueError("the ring of constants must be finite") if group is not None: # placeholder - raise NotImplementedError("Drinfeld modular forms are currently " - "only implemented for the full group") - if names is None: # default names + raise NotImplementedError("Drinfeld modular forms are currently " "only implemented for the full group") + if names is None: # default names if rank is None: raise TypeError("rank or names must be specified") rank = ZZ(rank) # check the type of rank @@ -296,13 +292,10 @@ def __classcall_private__(cls, base_ring, rank=None, group=None, g = names[0] names = [f'{g}{i}' for i in range(1, rank + 1)] elif nb_names != rank: - raise ValueError(f"the number of generators (={nb_names}) " - f"must be equal to the rank (={rank})") + raise ValueError(f"the number of generators (={nb_names}) " f"must be equal to the rank (={rank})") else: - raise TypeError("names must be None, a comma separated string " - "or a list of string") - return cls.__classcall__(cls, base_ring, rank, group, has_type, - tuple(names)) + raise TypeError("names must be None, a comma separated string " "or a list of string") + return cls.__classcall__(cls, base_ring, rank, group, has_type, tuple(names)) def __init__(self, base_ring, rank, group, has_type, names): r""" @@ -334,8 +327,7 @@ def __init__(self, base_ring, rank, group, has_type, names): degs.append((q**rank - 1) / (q - 1)) else: degs = [q**i - 1 for i in range(1, rank + 1, 1)] - self._poly_ring = PolynomialRing(base_ring, rank, names=names, - order=TermOrder('wdeglex', degs)) + self._poly_ring = PolynomialRing(base_ring, rank, names=names, order=TermOrder('wdeglex', degs)) self._assign_names(names) cat = GradedAlgebras(base_ring).Commutative() super().__init__(base=base_ring, category=cat) @@ -367,8 +359,7 @@ def _repr_(self): sage: M._repr_() 'Ring of Drinfeld modular forms of rank 3 over Fraction Field of Univariate Polynomial Ring in T over Finite Field of size 2 (using GF2X)' """ - return ("Ring of Drinfeld modular forms of rank %s over %s" - % (self._rank, self._base_ring)) + return "Ring of Drinfeld modular forms of rank %s over %s" % (self._rank, self._base_ring) def _generator_coefficient_form(self, i): r""" @@ -402,7 +393,7 @@ def _generator_coefficient_form(self, i): """ if self._has_type and i == self.rank(): q = self._base_ring.base_ring().cardinality() - return self.gen(i-1)**(q - 1) + return self.gen(i - 1) ** (q - 1) return self.gen(i - 1) def _coefficient_forms(self, a): @@ -438,12 +429,11 @@ def _coefficient_forms(self, a): gen.extend(poly_ring_gens) ore_pol_ring = OrePolynomialRing(poly_ring, Frob, 't') gen = ore_pol_ring(gen) - f = sum(c*(gen**idx) for idx, c in enumerate(a.coefficients(sparse=False))) + f = sum(c * (gen**idx) for idx, c in enumerate(a.coefficients(sparse=False))) coeff_forms = [] - for i in range(1, a.degree()*self.rank()+1): + for i in range(1, a.degree() * self.rank() + 1): form = f[i] - coeff_forms.append(form.subs({g: self._generator_coefficient_form(j+1) - for j, g in enumerate(poly_ring_gens)})) + coeff_forms.append(form.subs({g: self._generator_coefficient_form(j + 1) for j, g in enumerate(poly_ring_gens)})) return coeff_forms def coefficient_form(self, i, a=None): @@ -516,8 +506,7 @@ def coefficient_form(self, i, a=None): i = ZZ(i) if a is None: if i < 1 or i > self.rank(): - raise ValueError(f"index (={i}) must be >= 1 and <= rank " - f"(={self.rank()})") + raise ValueError(f"index (={i}) must be >= 1 and <= rank " f"(={self.rank()})") return self._generator_coefficient_form(i) try: A = self._base_ring.base() @@ -526,9 +515,8 @@ def coefficient_form(self, i, a=None): raise TypeError("unable to convert a to an element in Fq[T]") except ValueError: raise ValueError("a must be an integral element") - if i < 1 or i > a.degree()*self.rank(): - raise ValueError(f"index (={i}) must be >= 1 and <= deg(a)*rank " - f"(={a.degree()*self.rank()})") + if i < 1 or i > a.degree() * self.rank(): + raise ValueError(f"index (={i}) must be >= 1 and <= deg(a)*rank " f"(={a.degree()*self.rank()})") coeff_forms = self._coefficient_forms(a) return coeff_forms[i - 1] @@ -582,8 +570,7 @@ def coefficient_forms(self, a=None): TypeError: unable to convert a to an element in Fq[T] """ if a is None: - return [self._generator_coefficient_form(i) - for i in range(1, self.rank() + 1)] + return [self._generator_coefficient_form(i) for i in range(1, self.rank() + 1)] try: A = self._base_ring.base() a = A(a) diff --git a/src/sage/modular/etaproducts.py b/src/sage/modular/etaproducts.py index e6914efc892..8faed6ee879 100644 --- a/src/sage/modular/etaproducts.py +++ b/src/sage/modular/etaproducts.py @@ -122,7 +122,7 @@ def __init__(self, parent, rdict) -> None: sumR += rdict[d] sumDR += rdict[d] * d sumNoverDr += rdict[d] * (N // d) - prod *= (N // d)**rdict[d] + prod *= (N // d) ** rdict[d] if sumR != 0: raise ValueError("sum r_d (=%s) is not 0" % sumR) @@ -148,8 +148,7 @@ def _mul_(self, other): sage: eta1 * eta2 Eta product of level 4 : (eta_1)^24 (eta_2)^-48 (eta_4)^24 """ - newdict = {d: self._rdict.get(d, 0) + other._rdict.get(d, 0) - for d in set(self._rdict).union(other._rdict)} + newdict = {d: self._rdict.get(d, 0) + other._rdict.get(d, 0) for d in set(self._rdict).union(other._rdict)} P = self.parent() return P.element_class(P, newdict) @@ -165,8 +164,7 @@ def _div_(self, other): sage: (eta1 / eta2) * eta2 == eta1 True """ - newdict = {d: self._rdict.get(d, 0) - other._rdict.get(d, 0) - for d in set(self._rdict).union(other._rdict)} + newdict = {d: self._rdict.get(d, 0) - other._rdict.get(d, 0) for d in set(self._rdict).union(other._rdict)} P = self.parent() return P.element_class(P, newdict) @@ -223,11 +221,9 @@ def _richcmp_(self, other, op) -> bool: False """ if op in [op_EQ, op_NE]: - test = (self._N == other._N and - self._rdict == other._rdict) + test = self._N == other._N and self._rdict == other._rdict return test == (op == op_EQ) - return richcmp((self._N, sorted(self._rdict.items())), - (other._N, sorted(other._rdict.items())), op) + return richcmp((self._N, sorted(self._rdict.items())), (other._N, sorted(other._rdict.items())), op) def _short_repr(self) -> str: r""" @@ -241,8 +237,7 @@ def _short_repr(self) -> str: """ if self.degree() == 0: return "1" - return " ".join("(eta_%s)^%s" % (d, exp) - for d, exp in sorted(self._rdict.items())) + return " ".join("(eta_%s)^%s" % (d, exp) for d, exp in sorted(self._rdict.items())) def _repr_(self) -> str: r""" @@ -306,8 +301,8 @@ def q_expansion(self, n): for d in self._rdict: rd = self._rdict[d] if rd: - pr *= eta(q ** d) ** ZZ(rd) - return pr * q**(self._sumDR // 24) + pr *= eta(q**d) ** ZZ(rd) + return pr * q ** (self._sumDR // 24) def qexp(self, n): """ @@ -345,9 +340,7 @@ def order_at_cusp(self, cusp: CuspFamily) -> Integer: raise TypeError("argument (=%s) should be a CuspFamily" % cusp) if cusp.level() != self._N: raise ValueError("cusp not on right curve") - sigma = sum(ell * self._rdict[ell] / cusp.width() * - (gcd(cusp.width(), self._N // ell))**2 - for ell in self._rdict) + sigma = sum(ell * self._rdict[ell] / cusp.width() * (gcd(cusp.width(), self._N // ell)) ** 2 for ell in self._rdict) return sigma / ZZ(24) / gcd(cusp.width(), self._N // cusp.width()) def divisor(self): @@ -365,8 +358,7 @@ def divisor(self): - (c_{8,1}) - (c_{4,1}) + (c_{32,4}) + (c_{32,3}) + (c_{64,1}) + (0) + (c_{32,2}) + (c_{64,2}) + (c_{128}) + (c_{32,1}) """ - return FormalSum([(self.order_at_cusp(c), c) - for c in AllCusps(self.level())]) + return FormalSum([(self.order_at_cusp(c), c) for c in AllCusps(self.level())]) def degree(self) -> Integer: r""" @@ -381,9 +373,7 @@ def degree(self) -> Integer: sage: e.degree() 230 """ - return sum(self.order_at_cusp(c) - for c in AllCusps(self._N) - if self.order_at_cusp(c) > 0) + return sum(self.order_at_cusp(c) for c in AllCusps(self._N) if self.order_at_cusp(c) > 0) def r(self, d) -> Integer: r""" @@ -542,8 +532,7 @@ def basis(self, reduce=True) -> list: for di in divs: # generate a row of relation matrix row = [Mod(di, 24) - Mod(N, 24), Mod(N // di, 24) - Mod(1, 24)] - row.extend(Mod(12 * (N // di).valuation(p), 24) - for p in primedivs) + row.extend(Mod(12 * (N // di).valuation(p), 24) for p in primedivs) rows.append(row) M = matrix(IntegerModRing(24), rows) @@ -605,9 +594,7 @@ def reduce_basis(self, long_etas) -> list: short_etas = [] for shortvect in rred.rows(): bv = A.coordinates(shortvect) - dic = {d: sum(bv[i] * long_etas[i].r(d) - for i in range(r.nrows())) - for d in divisors(N)} + dic = {d: sum(bv[i] * long_etas[i].r(d) for i in range(r.nrows())) for d in divisors(N)} short_etas.append(self(dic)) return short_etas @@ -728,8 +715,7 @@ def AllCusps(N) -> list: if n == 1: c.append(CuspFamily(N, d)) elif n > 1: - c.extend(CuspFamily(N, d, label=str(i + 1)) - for i in range(n)) + c.extend(CuspFamily(N, d, label=str(i + 1)) for i in range(n)) return c @@ -738,6 +724,7 @@ class CuspFamily(SageObject): r""" A family of elliptic curves parametrising a region of `X_0(N)`. """ + def __init__(self, N, width, label=None) -> None: r""" Create the cusp of width d on X_0(N) corresponding to the family @@ -917,8 +904,7 @@ def qexp_eta(ps_ring, prec): return ps_ring(v, prec=prec) -def eta_poly_relations(eta_elements, degree, labels=['x1', 'x2'], - verbose=False): +def eta_poly_relations(eta_elements, degree, labels=['x1', 'x2'], verbose=False): r""" Find polynomial relations between eta products. @@ -1049,7 +1035,7 @@ def _eta_relations_helper(eta1, eta2, degree, qexp_terms, labels, verbose): rows: list[list] = [[] for _ in range(qexp_terms)] for i in indices: - func = (eta1**i[0] * eta2**i[1]).qexp(qexp_terms) + func = (eta1 ** i[0] * eta2 ** i[1]).qexp(qexp_terms) for j in range(qexp_terms): rows[j].append(func[j - pole_at_infinity]) M = matrix(rows) @@ -1061,8 +1047,6 @@ def _eta_relations_helper(eta1, eta2, degree, qexp_terms, labels, verbose): if V.dimension() >= 1: R = PolynomialRing(QQ, 2, labels) x, y = R.gens() - relations = [sum([c[v] * x**indices[v][0] * y**indices[v][1] - for v in range(len(indices))]) - for c in V.basis()] + relations = [sum([c[v] * x ** indices[v][0] * y ** indices[v][1] for v in range(len(indices))]) for c in V.basis()] id = R.ideal(relations) return id.groebner_basis() diff --git a/src/sage/modular/hecke/algebra.py b/src/sage/modular/hecke/algebra.py index 26f4b555d9f..046dd0a3e3f 100644 --- a/src/sage/modular/hecke/algebra.py +++ b/src/sage/modular/hecke/algebra.py @@ -66,7 +66,7 @@ def _heckebasis(M) -> list: [0 5]] """ d = M.rank() - WW = ZZ**(d**2) + WW = ZZ ** (d**2) MM = MatrixSpace(QQ, d) S = [] Denom = [] @@ -100,6 +100,7 @@ class HeckeAlgebra_base(CachedRepresentation, Parent): sage: CuspForms(1, 12).hecke_algebra() # indirect doctest Full Hecke algebra acting on Cuspidal subspace of dimension 1 of Modular Forms space of dimension 2 for Modular Group SL(2,Z) of weight 12 over Rational Field """ + @staticmethod def __classcall__(cls, M): r""" @@ -157,6 +158,7 @@ def __init__(self, M) -> None: if isinstance(M, tuple): M = M[0] from .module import HeckeModule_generic + if not isinstance(M, HeckeModule_generic): msg = f"M (={M}) must be a HeckeModule" raise TypeError(msg) @@ -237,17 +239,14 @@ def _element_constructor_(self, x, check=True): return x if isinstance(x, HeckeOperator): - if x.parent() == self \ - or (not self.is_anemic() and x.parent() == self.anemic_subalgebra()) \ - or (self.is_anemic() and x.parent().anemic_subalgebra() == self and gcd(x.index(), self.level()) == 1): + if x.parent() == self or (not self.is_anemic() and x.parent() == self.anemic_subalgebra()) or (self.is_anemic() and x.parent().anemic_subalgebra() == self and gcd(x.index(), self.level()) == 1): return HeckeOperator(self, x.index()) if isinstance(x, HeckeAlgebraElement): if x.parent() == self or (not self.is_anemic() and x.parent() == self.anemic_subalgebra()): if x.parent().module().basis_matrix() == self.module().basis_matrix(): return HeckeAlgebraElement_matrix(self, x.matrix()) - A = matrix([self.module().coordinate_vector(x.parent().module().gen(i)) - for i in range(x.parent().module().rank())]) + A = matrix([self.module().coordinate_vector(x.parent().module().gen(i)) for i in range(x.parent().module().rank())]) return HeckeAlgebraElement_matrix(self, ~A * x.matrix() * A) try: @@ -323,6 +322,7 @@ def one(self): [0 1] """ from .hecke_operator import HeckeAlgebraElement_matrix + A = self.matrix_space() return HeckeAlgebraElement_matrix(self, A.one()) @@ -453,8 +453,7 @@ def basis(self): continue # Lift the projected basis to a basis in the Hecke algebra. trans = proj_span.solve_left(proj_basis) - basis = [sum(c * T for c, T in zip(row, span) if c != 0) - for row in trans[:dim]] + basis = [sum(c * T for c, T in zip(row, span) if c != 0) for row in trans[:dim]] break return tuple(basis) @@ -577,6 +576,7 @@ class HeckeAlgebra_full(HeckeAlgebra_base): A full Hecke algebra (including the operators `T_n` where `n` is not assumed to be coprime to the level). """ + def _repr_(self) -> str: r""" String representation of ``self``. @@ -639,6 +639,7 @@ class HeckeAlgebra_anemic(HeckeAlgebra_base): r""" An anemic Hecke algebra, generated by Hecke operators with index coprime to the level. """ + def _repr_(self) -> str: r""" EXAMPLES:: diff --git a/src/sage/modular/hecke/all.py b/src/sage/modular/hecke/all.py index 43fadf7834e..dce1fcb44d2 100644 --- a/src/sage/modular/hecke/all.py +++ b/src/sage/modular/hecke/all.py @@ -8,8 +8,7 @@ from sage.modular.hecke.algebra import HeckeAlgebra -from sage.modular.hecke.morphism import (HeckeModuleMorphism, - HeckeModuleMorphism_matrix) +from sage.modular.hecke.morphism import HeckeModuleMorphism, HeckeModuleMorphism_matrix from sage.modular.hecke.element import HeckeModuleElement diff --git a/src/sage/modular/hecke/ambient_module.py b/src/sage/modular/hecke/ambient_module.py index 19d9d41faed..c30ed9f23b6 100644 --- a/src/sage/modular/hecke/ambient_module.py +++ b/src/sage/modular/hecke/ambient_module.py @@ -40,6 +40,7 @@ class AmbientHeckeModule(module.HeckeModule_free_module): is the base class for ambient spaces of modular forms and modular symbols, and for Brandt modules. """ + def __init__(self, base_ring, rank, level, weight, category=None): r""" Create an ambient Hecke module. @@ -55,8 +56,7 @@ def __init__(self, base_ring, rank, level, weight, category=None): if rank < 0: raise ValueError("rank (=%s) must be nonnegative" % rank) self.__rank = rank - module.HeckeModule_free_module.__init__(self, base_ring, level, - weight, category=category) + module.HeckeModule_free_module.__init__(self, base_ring, level, weight, category=category) def rank(self): """ @@ -217,8 +217,7 @@ def decomposition_matrix(self): try: return self.__decomposition_matrix_cache except AttributeError: - rows = [x.list() for A in self.decomposition() - for x in A.basis()] + rows = [x.list() for A in self.decomposition() for x in A.basis()] A = matrix_space.MatrixSpace(self.base_ring(), self.rank())(rows) self.__decomposition_matrix_cache = A return self.__decomposition_matrix_cache @@ -367,13 +366,11 @@ def degeneracy_map(self, codomain, t=1): else: err = True if err: - raise ValueError(("the level of self (=%s) must be a divisor or multiple of " - "level (=%s) and t (=%s) must be a divisor of the quotient") % (self.level(), level, t)) + raise ValueError(("the level of self (=%s) must be a divisor or multiple of " "level (=%s) and t (=%s) must be a divisor of the quotient") % (self.level(), level, t)) eps = self.character() if eps is not None and level % eps.conductor() != 0: - raise ArithmeticError("the conductor of the character of this space " - "(=%s) must be divisible by the level (=%s)" % (eps.conductor(), level)) + raise ArithmeticError("the conductor of the character of this space " "(=%s) must be divisible by the level (=%s)" % (eps.conductor(), level)) if M is None: M = self.hecke_module_of_level(level) @@ -495,6 +492,7 @@ def hecke_bound(self): 15 """ from sage.misc.verbose import verbose + try: if self.is_cuspidal(): return Gamma0(self.level()).sturm_bound(self.weight()) @@ -885,7 +883,7 @@ def old_submodule(self, p=None): else: os = self.submodule(d.image(), check=False) - self.__is_old[p] = (os == self) + self.__is_old[p] = os == self os.__is_old = {p: True} os._is_full_hecke_module = True diff --git a/src/sage/modular/hecke/degenmap.py b/src/sage/modular/hecke/degenmap.py index 887506e7559..05dc1d169a2 100644 --- a/src/sage/modular/hecke/degenmap.py +++ b/src/sage/modular/hecke/degenmap.py @@ -77,6 +77,7 @@ class DegeneracyMap(morphism.HeckeModuleMorphism_matrix): Domain: Modular Symbols space of dimension 9 for Gamma_0(33) of weight ... Codomain: Modular Symbols space of dimension 25 for Gamma_0(66) of weight ... """ + def __init__(self, matrix, domain, codomain, t): r""" Initialise a degeneracy map. diff --git a/src/sage/modular/hecke/element.py b/src/sage/modular/hecke/element.py index d1942474625..5c7c4e4f241 100644 --- a/src/sage/modular/hecke/element.py +++ b/src/sage/modular/hecke/element.py @@ -34,6 +34,7 @@ class HeckeModuleElement(ModuleElement): """ Element of a Hecke module. """ + def __init__(self, parent, x=None): """ INPUT: diff --git a/src/sage/modular/hecke/hecke_operator.py b/src/sage/modular/hecke/hecke_operator.py index 989f01124c6..655df476dce 100644 --- a/src/sage/modular/hecke/hecke_operator.py +++ b/src/sage/modular/hecke/hecke_operator.py @@ -30,6 +30,7 @@ class HeckeAlgebraElement(AlgebraElement): r""" Base class for elements of Hecke algebras. """ + def __init__(self, parent) -> None: r""" Create an element of a Hecke algebra. @@ -266,8 +267,7 @@ def decomposition(self): return self.__decomposition except AttributeError: pass - if isinstance(self, HeckeOperator) and \ - arith.gcd(self.index(), self.domain().level()) == 1: + if isinstance(self, HeckeOperator) and arith.gcd(self.index(), self.domain().level()) == 1: D = self.hecke_module_morphism().decomposition(is_diagonalizable=True) else: # TODO: There are other weaker hypotheses that imply diagonalizability. @@ -371,6 +371,7 @@ class HeckeAlgebraElement_matrix(HeckeAlgebraElement): r""" An element of the Hecke algebra represented by a matrix. """ + def __init__(self, parent, A): r""" Initialise an element from a matrix. This *must* be over the base ring @@ -402,6 +403,7 @@ def __init__(self, parent, A): """ HeckeAlgebraElement.__init__(self, parent) from sage.structure.element import Matrix + if not isinstance(A, Matrix): raise TypeError("A must be a matrix") if not A.base_ring() == self.parent().base_ring(): @@ -498,6 +500,7 @@ class DiamondBracketOperator(HeckeAlgebraElement_matrix): N\ZZ` (which need not be a unit, although if it is not, the operator will be zero). """ + def __init__(self, parent, d): r""" Standard init function. @@ -551,6 +554,7 @@ class HeckeOperator(HeckeAlgebraElement): The Hecke operator `T_n` for some `n` (which need not be coprime to the level). The matrix is not computed until it is needed. """ + def __init__(self, parent, n): """ EXAMPLES:: @@ -674,8 +678,7 @@ def _mul_(self, other): n = self.__n * other.__n else: P = set(arith.prime_divisors(self.domain().level())) - if P.issubset(set(arith.prime_divisors(self.__n))) and \ - P.issubset(set(arith.prime_divisors(other.__n))): + if P.issubset(set(arith.prime_divisors(self.__n))) and P.issubset(set(arith.prime_divisors(other.__n))): n = self.__n * other.__n if n: return HeckeOperator(self.parent(), n) diff --git a/src/sage/modular/hecke/homspace.py b/src/sage/modular/hecke/homspace.py index a8efc27ea51..5557b662749 100644 --- a/src/sage/modular/hecke/homspace.py +++ b/src/sage/modular/hecke/homspace.py @@ -28,6 +28,7 @@ class HeckeModuleHomspace(HomsetWithBase): A space of homomorphisms between two objects in the category of Hecke modules over a given base ring. """ + def __init__(self, X, Y, category=None) -> None: r""" Create the space of homomorphisms between X and Y, which must have the diff --git a/src/sage/modular/hecke/module.py b/src/sage/modular/hecke/module.py index d6b99f88e84..57ddaffb4e3 100644 --- a/src/sage/modular/hecke/module.py +++ b/src/sage/modular/hecke/module.py @@ -63,6 +63,7 @@ def __init__(self, base_ring, level, category=None) -> None: raise TypeError("base_ring must be commutative ring") from sage.categories.hecke_modules import HeckeModules + default_category = HeckeModules(base_ring) if category is None: category = default_category @@ -89,6 +90,7 @@ def __setstate__(self, state): """ if not self._is_category_initialized(): from sage.categories.hecke_modules import HeckeModules + self._init_category_(HeckeModules(state['_base'])) Module.__setstate__(self, state) @@ -127,7 +129,7 @@ def _compute_hecke_matrix_prime_power(self, p, r, **kwds): if not is_prime(p): raise ArithmeticError("p must be a prime") # T_{p^r} := T_p * T_{p^{r-1}} - eps(p)p^{k-1} T_{p^{r-2}}. - pow = p**(r - 1) + pow = p ** (r - 1) if pow not in self._hecke_matrices: # The following will force computation of T_{p^s} # for all s<=r-1, except possibly s=0. @@ -141,7 +143,7 @@ def _compute_hecke_matrix_prime_power(self, p, r, **kwds): raise NotImplementedError("either character or _compute_hecke_matrix_prime_power must be overloaded in a derived class") k = self.weight() Tpr2 = self._hecke_matrices[pow // p] - return Tp * Tpr1 - eps(p) * (p**(k - 1)) * Tpr2 + return Tp * Tpr1 - eps(p) * (p ** (k - 1)) * Tpr2 def _compute_hecke_matrix_general_product(self, F, **kwds): r""" @@ -469,6 +471,7 @@ class HeckeModule_free_module(HeckeModule_generic): """ A Hecke module modeled on a free module over a commutative ring. """ + def __init__(self, base_ring, level, weight, category=None): r""" Initialise a module. @@ -822,7 +825,7 @@ def atkin_lehner_operator(self, d=None): for p, e in factor(d): v = valuation(N, p) if e < v: - d *= p**(v - e) + d *= p ** (v - e) d = int(d) try: return self.__atkin_lehner_operator[d] @@ -881,8 +884,7 @@ def coordinate_vector(self, x): """ return self.free_module().coordinate_vector(x.element()) - def decomposition(self, bound=None, anemic=True, height_guess=1, - sort_by_basis=False, proof=None): + def decomposition(self, bound=None, anemic=True, height_guess=1, sort_by_basis=False, proof=None): """ Return the maximal decomposition of this Hecke module under the action of Hecke operators of index coprime to the level. @@ -976,15 +978,11 @@ def decomposition(self, bound=None, anemic=True, height_guess=1, t = T.hecke_operator(p).matrix() Uprime = [] for i in range(len(U)): - is_diagonalizable = (not self.base_ring().characteristic() and - self.level() % p) + is_diagonalizable = not self.base_ring().characteristic() and self.level() % p if is_rational: - X = t.decomposition_of_subspace(U[i], check_restrict=False, - algorithm='multimodular', - height_guess=height_guess, proof=proof) + X = t.decomposition_of_subspace(U[i], check_restrict=False, algorithm='multimodular', height_guess=height_guess, proof=proof) else: - X = t.decomposition_of_subspace(U[i], check_restrict=False, - is_diagonalizable=is_diagonalizable) + X = t.decomposition_of_subspace(U[i], check_restrict=False, is_diagonalizable=is_diagonalizable) for Xi in X: W, is_irred = Xi if is_irred: @@ -1009,8 +1007,8 @@ def decomposition(self, bound=None, anemic=True, height_guess=1, if anemic: self.__is_splittable_anemic = len(D) > 1 from sage.modules.free_module import EchelonMatrixKey - D.sort(key=None if not sort_by_basis - else lambda ss: EchelonMatrixKey(ss.free_module())) + + D.sort(key=None if not sort_by_basis else lambda ss: EchelonMatrixKey(ss.free_module())) D.set_immutable() self.__decomposition[key] = D for i in range(len(D)): @@ -1115,7 +1113,7 @@ def dual_eigenvector(self, names='alpha', lift=True, nz=None): R = f.parent() K = R.base_ring().extension(f, names=names) alpha = K.gen() - beta = ~alpha # multiplicative inverse of alpha + beta = ~alpha # multiplicative inverse of alpha c = [-f[0] * beta] for i in range(1, n - 1): c.append((c[i - 1] - f[i]) * beta) @@ -1128,7 +1126,7 @@ def dual_eigenvector(self, names='alpha', lift=True, nz=None): # William Stein's Ph.D. thesis, Section 3.5.3). We compute # g(t)v for a some vector v, and get an eigenvector. V = FreeModule(K, n) - t = t.change_ring(K) # coerce t to be over K. + t = t.change_ring(K) # coerce t to be over K. for j in range(n): v = V.gen(j) I = t.iterates(v, n) # iterates v, v*t, v*t^2, ... @@ -1288,7 +1286,7 @@ def eigenvalue(self, n, name='alpha'): apr1 = self.eigenvalue(pow // p, name=name) k = self.weight() apr2 = self.eigenvalue(pow // (p * p), name=name) - apow = ap * apr1 - eps(p) * (p**(k - 1)) * apr2 + apow = ap * apr1 - eps(p) * (p ** (k - 1)) * apr2 _dict_set(ev, pow, name, apow) if prod is None: prod = ev[pow][name] @@ -1510,8 +1508,7 @@ def is_submodule(self, other) -> bool: """ if not isinstance(other, HeckeModule_free_module): return False - return (self.ambient_free_module() == other.ambient_free_module() and - self.free_module().is_submodule(other.free_module())) + return self.ambient_free_module() == other.ambient_free_module() and self.free_module().is_submodule(other.free_module()) def is_splittable_anemic(self) -> bool: """ @@ -1609,8 +1606,7 @@ def projection(self): except AttributeError: i = self.factor_number() if i == -1: - raise NotImplementedError("Computation of projection only implemented " - "for decomposition factors.") + raise NotImplementedError("Computation of projection only implemented " "for decomposition factors.") A = self.ambient_hecke_module() B = A.decomposition_matrix_inverse() i = A.decomposition().index(self) diff --git a/src/sage/modular/hecke/morphism.py b/src/sage/modular/hecke/morphism.py index 909a30f1a1c..0c0175c1fbd 100644 --- a/src/sage/modular/hecke/morphism.py +++ b/src/sage/modular/hecke/morphism.py @@ -39,6 +39,7 @@ class HeckeModuleMorphism(Morphism): r""" Abstract base class for morphisms of Hecke modules. """ + pass @@ -68,6 +69,7 @@ class HeckeModuleMorphism_matrix(MatrixMorphism, HeckeModuleMorphism): ... TypeError: Incompatible composition of morphisms: domain of left morphism must be codomain of right. """ + def __init__(self, parent, A, name='', side='left') -> None: """ INPUT: @@ -134,4 +136,5 @@ def _repr_(self): name += ' ' return "Hecke module morphism %sdefined by the matrix\n%r\nDomain: %s\nCodomain: %s" % (name, self.matrix(), misc.strunc(self.domain()), misc.strunc(self.codomain())) + # __mul__ method removed by David Loeffler 2009-04-14 as it is an exact duplicate of sage.modules.matrix_morphism.__mul__ diff --git a/src/sage/modular/hecke/submodule.py b/src/sage/modular/hecke/submodule.py index ef9a5e9aeb5..81925e91d62 100644 --- a/src/sage/modular/hecke/submodule.py +++ b/src/sage/modular/hecke/submodule.py @@ -33,8 +33,8 @@ class HeckeSubmodule(module.HeckeModule_free_module): """ Submodule of a Hecke module. """ - def __init__(self, ambient, submodule, - dual_free_module=None, check=True) -> None: + + def __init__(self, ambient, submodule, dual_free_module=None, check=True) -> None: r""" Initialise a submodule of an ambient Hecke module. @@ -66,6 +66,7 @@ def __init__(self, ambient, submodule, True """ from . import ambient_module + if not isinstance(ambient, ambient_module.AmbientHeckeModule): raise TypeError("ambient must be an ambient Hecke module") if not isinstance(submodule, FreeModule_generic): @@ -79,9 +80,7 @@ def __init__(self, ambient, submodule, self.__ambient = ambient self.__submodule = submodule - module.HeckeModule_free_module.__init__(self, ambient.base_ring(), - ambient.level(), - ambient.weight()) + module.HeckeModule_free_module.__init__(self, ambient.base_ring(), ambient.level(), ambient.weight()) if dual_free_module is not None: if not isinstance(dual_free_module, FreeModule_generic): raise TypeError("dual_free_module must be a free module") @@ -100,8 +99,7 @@ def _repr_(self): sage: S._repr_() 'Rank 3 submodule of a Hecke module of level 4' """ - return "Rank %s submodule of a Hecke module of level %s" % ( - self.rank(), self.level()) + return "Rank %s submodule of a Hecke module of level %s" % (self.rank(), self.level()) def __add__(self, other): r""" @@ -380,8 +378,7 @@ def complement(self, bound=None): return C # failed miserably - raise RuntimeError("Computation of complementary space failed (cut down to rank %s, but should have cut down to rank %s)." % ( - V.rank(), A.rank() - self.rank())) + raise RuntimeError("Computation of complementary space failed (cut down to rank %s, but should have cut down to rank %s)." % (V.rank(), A.rank() - self.rank())) def degeneracy_map(self, level, t=1): """ @@ -535,8 +532,7 @@ def dual_free_module(self, bound=None, anemic=True, use_star=True): # then we compute the dual on each eigenspace, then put them # together. if len(self.star_eigenvalues()) == 2: - V = self.plus_submodule(compute_dual=False).dual_free_module() + \ - self.minus_submodule(compute_dual=False).dual_free_module() + V = self.plus_submodule(compute_dual=False).dual_free_module() + self.minus_submodule(compute_dual=False).dual_free_module() return V # At this point, we know that self is an eigenspace for star. @@ -571,8 +567,7 @@ def dual_free_module(self, bound=None, anemic=True, use_star=True): if V2.rank() == self.rank(): return V2 - raise RuntimeError("Computation of embedded dual vector space failed " - "(cut down to rank %s, but should have cut down to rank %s)." % (V.rank(), self.rank())) + raise RuntimeError("Computation of embedded dual vector space failed " "(cut down to rank %s, but should have cut down to rank %s)." % (V.rank(), self.rank())) def free_module(self): """ @@ -628,8 +623,7 @@ def intersection(self, other): 1 """ if self.ambient_hecke_module() != other.ambient_hecke_module(): - raise ArithmeticError("intersection only defined for subspaces of" - " a common ambient modular symbols space") + raise ArithmeticError("intersection only defined for subspaces of" " a common ambient modular symbols space") if other.is_ambient(): return self if self.is_ambient(): @@ -730,8 +724,7 @@ def is_submodule(self, V) -> bool: """ if not isinstance(V, module.HeckeModule_free_module): return False - return self.ambient_hecke_module() == V.ambient_hecke_module() and \ - self.free_module().is_subspace(V.free_module()) + return self.ambient_hecke_module() == V.ambient_hecke_module() and self.free_module().is_subspace(V.free_module()) def linear_combination_of_basis(self, v): """ diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index f3281a3f140..bb9bf009025 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -48,6 +48,7 @@ - [Watkins]_ """ + # **************************************************************************** # Copyright (C) 2017--2024 Frédéric Chapoton # Kiran S. Kedlaya @@ -174,7 +175,7 @@ def characteristic_polynomial_from_traces(traces, d, q, i, sign, deg=None, use_f t = PowerSeriesRing(QQ, 't').gen() ring = PolynomialRing(ZZ, 'T') - series = sum(- api * t**(i + 1) / (i + 1) for i, api in enumerate(traces)) + series = sum(-api * t ** (i + 1) / (i + 1) for i, api in enumerate(traces)) series = series.O(bound + 1).exp() coeffs = list(series) coeffs += [0] * max(0, bound + 1 - len(coeffs)) @@ -184,7 +185,7 @@ def characteristic_polynomial_from_traces(traces, d, q, i, sign, deg=None, use_f for k in range(bound + 1): data[k] = coeffs[k] for k in range(bound + 1, fulldeg + 1): - data[k] = sign * coeffs[d - k] * q**(i * (k - d / 2)) + data[k] = sign * coeffs[d - k] * q ** (i * (k - d / 2)) return ring(data) @@ -206,8 +207,7 @@ def enumerate_hypergeometric_data(d, weight=None): 112 """ bound = 2 * d * d # to make sure that phi(n) <= d - possible = [(i, euler_phi(i)) for i in range(1, bound + 1) - if euler_phi(i) <= d] + possible = [(i, euler_phi(i)) for i in range(1, bound + 1) if euler_phi(i) <= d] poids = [z[1] for z in possible] N = len(poids) vectors = WeightedIntegerVectors(d, poids) @@ -267,8 +267,7 @@ def cyclotomic_to_alpha(cyclo) -> list: sage: cyclotomic_to_alpha([2, 3]) [1/3, 1/2, 2/3] """ - alpha = [QQ((k, d)) for d in cyclo - for k in ZZ(d).coprime_integers(d)] + alpha = [QQ((k, d)) for d in cyclo for k in ZZ(d).coprime_integers(d)] return sorted(alpha) @@ -405,8 +404,7 @@ def gamma_list_to_cyclotomic(galist): for d in divisors(abs(n)): resu[d] += eps - return (sorted(d for d in resu for k in range(resu[d])), - sorted(d for d in resu for k in range(-resu[d]))) + return (sorted(d for d in resu for k in range(resu[d])), sorted(d for d in resu for k in range(-resu[d]))) class HypergeometricData: @@ -493,11 +491,9 @@ def __init__(self, cyclotomic=None, alpha_beta=None, gamma_list=None): self._sign_param = 1 else: if (deg % 2) != (0 in alpha): - self._sign_param = prod(cyclotomic_polynomial(v).disc() - for v in cyclo_down) + self._sign_param = prod(cyclotomic_polynomial(v).disc() for v in cyclo_down) else: - self._sign_param = prod(cyclotomic_polynomial(v).disc() - for v in cyclo_up) + self._sign_param = prod(cyclotomic_polynomial(v).disc() for v in cyclo_up) # --- Internals --- def __repr__(self) -> str: @@ -529,8 +525,7 @@ def __eq__(self, other) -> bool: sage: H1 == H2 False """ - return (self._alpha == other._alpha and - self._beta == other._beta) + return self._alpha == other._alpha and self._beta == other._beta def __ne__(self, other) -> bool: """ @@ -705,10 +700,8 @@ def zigzag(self, x, flip_beta=False): alpha = self._alpha beta = self._beta if flip_beta: - return (sum(1 for a in alpha if a <= x) - - sum(1 for b in beta if 1 - b <= x)) - return (sum(1 for a in alpha if a <= x) - - sum(1 for b in beta if b <= x)) + return sum(1 for a in alpha if a <= x) - sum(1 for b in beta if 1 - b <= x) + return sum(1 for a in alpha if a <= x) - sum(1 for b in beta if b <= x) def weight(self): """ @@ -857,9 +850,7 @@ def z(x): return alpha.count(x) T = polygen(ZZ, 'T') - return sum(T ** (self.zigzag(a, flip_beta=True) - z(a)) * - (T**z(a) - 1) // (T - 1) - for a in set(alpha)) + return sum(T ** (self.zigzag(a, flip_beta=True) - z(a)) * (T ** z(a) - 1) // (T - 1) for a in set(alpha)) def hodge_function(self, x): """ @@ -885,7 +876,7 @@ def hodge_function(self, x): i = 0 j = 0 k = 0 - while (i < d and i < x): + while i < d and i < x: i += hn[k] j += k * hn[k] k += 1 @@ -961,11 +952,9 @@ def E_polynomial(self, vars=None): domain = {d for g in gamma for d in divisors(g.abs())} - m_plus = {d: len([1 for g in gamma_plus if not g % d]) - for d in domain} + m_plus = {d: len([1 for g in gamma_plus if not g % d]) for d in domain} - m_minus = {d: len([1 for g in gamma_minus if not g % d]) - for d in domain} + m_minus = {d: len([1 for g in gamma_minus if not g % d]) for d in domain} if vars is None: u, v = polygens(ZZ, 'u,v') @@ -975,19 +964,13 @@ def E_polynomial(self, vars=None): uv = u * v A = u.parent() - delta_sharp_N = {d: A.sum(uqv**sum(frac(j * gi / d) for gi in gamma) - for j in d.coprime_integers(d)) - for d in domain} + delta_sharp_N = {d: A.sum(uqv ** sum(frac(j * gi / d) for gi in gamma) for j in d.coprime_integers(d)) for d in domain} loop = [(d, m_plus[d], m_minus[d]) for d in domain] - delta_sharp = sum((uqv**m - uqv**p) // (uqv - 1) * v**(ell - 1) - * delta_sharp_N[d] - for d, p, m in loop if m > p) + delta_sharp = sum((uqv**m - uqv**p) // (uqv - 1) * v ** (ell - 1) * delta_sharp_N[d] for d, p, m in loop if m > p) - delta_zero = sum((uv**min(m, p) - 1) // (uv - 1) * v**(ell - m - p) - * delta_sharp_N[d] - for d, p, m in loop) + delta_zero = sum((uv ** min(m, p) - 1) // (uv - 1) * v ** (ell - m - p) * delta_sharp_N[d] for d, p, m in loop) return (delta_sharp + delta_zero - 1).numerator() // (u * v) @@ -1092,6 +1075,7 @@ def lfunction(self, t, prec=53): 0.997734256321692 """ from sage.lfunctions.pari import lfun_hgm, LFunction + Z = LFunction(lfun_hgm(self, t), prec=prec) Z.rename('PARI L-function associated to %s' % self) return Z @@ -1178,10 +1162,8 @@ def lattice_polytope(self): m = matrix(ZZ, l, 1, self.gamma_list()) ext_ker = m.kernel().basis_matrix().insert_row(0, vector(ZZ, [1] * l)) unique_relation = ext_ker.kernel().basis()[0] - removed = next(i for i, ci in enumerate(unique_relation) - if i and abs(ci) == 1) - mat = matrix(ZZ, [v for i, v in enumerate(ext_ker) - if i and i != removed]) + removed = next(i for i, ci in enumerate(unique_relation) if i and abs(ci) == 1) + mat = matrix(ZZ, [v for i, v in enumerate(ext_ker) if i and i != removed]) return LatticePolytope(mat.transpose()) # --- Operations on data --- @@ -1266,7 +1248,7 @@ def gauss_table(self, p, f, prec): if prec1 < prec: raise KeyError except KeyError: - use_longs = (p ** prec < 2 ** 31) + use_longs = p**prec < 2**31 gtab = gauss_table(p, f, prec, use_longs) self._gauss_table[p, f] = (prec, gtab) prec1 = prec @@ -1419,8 +1401,8 @@ def padic_H_value(self, p, f, t, prec=None, cache_p=False): if 0 in alpha: return self._swap.padic_H_value(p, f, ~t, prec) - q = p ** f - if q > 2 ** 31: + q = p**f + if q > 2**31: raise ValueError("p^f cannot exceed 2^31") m: dict[int, int] = defaultdict(int) @@ -1434,7 +1416,7 @@ def padic_H_value(self, p, f, t, prec=None, cache_p=False): if prec is None: prec = ceil((self.weight() * f) / 2 + log(2 * self.degree() + 1, p)) - use_longs = (p ** prec < 2 ** 31) + use_longs = p**prec < 2**31 gamma = self._gamma_array if cache_p: @@ -1556,7 +1538,7 @@ def H_value(self, p, f, t, ring=None): raise ValueError('p not prime') if not all(x.denominator() % p for x in self._alpha + self._beta): raise NotImplementedError('p is wild') - if (t.numerator() * t.denominator() % p == 0 or (t - 1) % p == 0): + if t.numerator() * t.denominator() % p == 0 or (t - 1) % p == 0: raise NotImplementedError('p is tame') if 0 in alpha: @@ -1577,17 +1559,13 @@ def H_value(self, p, f, t, ring=None): tM = Fq(M / t) for k in range(q - 1): - if gen ** k == tM: - teich = zeta_q ** k + if gen**k == tM: + teich = zeta_q**k break - gauss_table = [gauss_sum(zeta_q ** r, Fq) for r in range(q - 1)] + gauss_table = [gauss_sum(zeta_q**r, Fq) for r in range(q - 1)] - sigma = sum(q**(D + m[0] - m[r]) * - prod(gauss_table[(-v * r) % (q - 1)]**gv - for v, gv in gamma.items()) * - teich ** r - for r in range(q - 1)) + sigma = sum(q ** (D + m[0] - m[r]) * prod(gauss_table[(-v * r) % (q - 1)] ** gv for v, gv in gamma.items()) * teich**r for r in range(q - 1)) resu = ZZ(-1) ** m[0] / (1 - q) * sigma if not ring.is_exact(): resu = resu.real_part().round() @@ -1699,10 +1677,10 @@ def euler_factor_tame_contribution(self, t, p, mo, deg=None): deg = d if deg < f: return ZZ.one() - q = p ** f - prec = ceil(deg*(self.weight()+1-mul)/2 + log(2*d + 1, p)) + q = p**f + prec = ceil(deg * (self.weight() + 1 - mul) / 2 + log(2 * d + 1, p)) k = (q - 1) // mo - flip = (f == 1 and prec == 1) + flip = f == 1 and prec == 1 gtab_prec, gtab = self.gauss_table(p, f, prec) try: p_ring = gtab[0].parent() @@ -1711,29 +1689,26 @@ def euler_factor_tame_contribution(self, t, p, mo, deg=None): M = self.M_value() teich = p_ring.teichmuller(M / t0) m = {r: self._beta.count(QQ((r, q - 1))) for r in range(q - 1)} - D = -min(self.zigzag(x, flip_beta=True) - for x in self._alpha + self._beta) + D = -min(self.zigzag(x, flip_beta=True) for x in self._alpha + self._beta) gamma = self.gamma_array() l = [] for j in range(mo): if gcd(j, mo) == 1: r = j * k - term = teich**r * ZZ(-1)**m[0] + term = teich**r * ZZ(-1) ** m[0] ct = 0 for v, gv in gamma.items(): - r1 = v * r % (q-1) + r1 = v * r % (q - 1) ct += gv * sum(r1.digits(p)) term *= p_ring(gtab[r1]) ** (-gv if flip else gv) ct //= p - 1 - term *= ZZ(-1)**ct + term *= ZZ(-1) ** ct ct += f * (D + m[0] - m[r]) l.append(term * p**ct) - traces = [0 if j % f else sum(i**(j // f) for i in l) - for j in range(1, d + 1)] + traces = [0 if j % f else sum(i ** (j // f) for i in l) for j in range(1, d + 1)] R = IntegerModRing(p**prec) traces = [R(i).lift_centered() for i in traces] - return characteristic_polynomial_from_traces(traces, d, p, 0, 1, - deg, use_fe=False) + return characteristic_polynomial_from_traces(traces, d, p, 0, 1, deg, use_fe=False) @cached_method def euler_factor(self, t, p, deg=None, cache_p=False): @@ -1954,11 +1929,10 @@ def euler_factor(self, t, p, deg=None, cache_p=False): if deg is not None: bound = min(deg, bound) - if p ** bound > 2 ** 31: + if p**bound > 2**31: raise ValueError("p^f cannot exceed 2^31") - traces = [self.padic_H_value(p, i + 1, t, cache_p=cache_p) - for i in range(bound)] + traces = [self.padic_H_value(p, i + 1, t, cache_p=cache_p) for i in range(bound)] w = self.weight() m1 = self.cyclotomic_data()[1].count(1) @@ -1970,30 +1944,30 @@ def euler_factor(self, t, p, deg=None, cache_p=False): sign = 1 if w % 2: assert m1 % 2 == 0 - u = (-1) ** (m1//2) - u *= prod(v ** gv for v, gv in self.gamma_array().items()) - c = kronecker_symbol(u, p) * p**((w-1)//2) + u = (-1) ** (m1 // 2) + u *= prod(v**gv for v, gv in self.gamma_array().items()) + c = kronecker_symbol(u, p) * p ** ((w - 1) // 2) else: - u = (-1) ** (1 + self.degree()//2 + (m1-1)//2) + u = (-1) ** (1 + self.degree() // 2 + (m1 - 1) // 2) num, den = self.defining_polynomials() x = num.parent().gen() num = num(-x) - num /= (x-1) ** num.valuation(x-1) - den /= (x-1) ** den.valuation(x-1) + num /= (x - 1) ** num.valuation(x - 1) + den /= (x - 1) ** den.valuation(x - 1) u *= 2 * num(1) / den(1) - c = kronecker_symbol(u, p) * p**(w//2) + c = kronecker_symbol(u, p) * p ** (w // 2) cpow = c for j in range(len(traces)): traces[j] -= cpow cpow *= c - tmp = 1 - c*P.gen() + tmp = 1 - c * P.gen() else: - u = (-1) ** (1+(self.degree()-1)//2) + u = (-1) ** (1 + (self.degree() - 1) // 2) num, den = self.defining_polynomials() x = num.parent().gen() den = den(-x) - num /= (x-1) ** num.valuation(x-1) - den /= (x-1) ** den.valuation(x-1) + num /= (x - 1) ** num.valuation(x - 1) + den /= (x - 1) ** den.valuation(x - 1) u *= num(1) / den(1) sign = kronecker_symbol(u, p) else: @@ -2005,11 +1979,11 @@ def euler_factor(self, t, p, deg=None, cache_p=False): if typ == "mult" and t != 1: if self.degree() % 2 == 0: ans *= tmp - if w % 2 == 0 and (t-1).valuation(p) % 2 == 0: - K = (-1) ** ((m1-1)//2)*2*prod(abs(x) for x in self.gamma_list()) - t0 = (~t-1) / p**((t-1).valuation(p)) - c = kronecker_symbol(K*t0, p) * p**(w//2) - ans *= 1 - c*P.gen() + if w % 2 == 0 and (t - 1).valuation(p) % 2 == 0: + K = (-1) ** ((m1 - 1) // 2) * 2 * prod(abs(x) for x in self.gamma_list()) + t0 = (~t - 1) / p ** ((t - 1).valuation(p)) + c = kronecker_symbol(K * t0, p) * p ** (w // 2) + ans *= 1 - c * P.gen() if deg is not None: ans = ans.truncate(deg + 1) return ans diff --git a/src/sage/modular/local_comp/liftings.py b/src/sage/modular/local_comp/liftings.py index 70b9be01df9..6864984e86a 100644 --- a/src/sage/modular/local_comp/liftings.py +++ b/src/sage/modular/local_comp/liftings.py @@ -71,7 +71,7 @@ def lift_to_gamma1(g, m, n): c2 = crt(c, 0, m, n) d2 = crt(d, 1, m, n) a3, b3, c3, d3 = (ZZ(_) for _ in lift_to_sl2z(c2, d2, m * n)) - r = (a3*b - b3*a) % m + r = (a3 * b - b3 * a) % m return [a3 + r * c3, b3 + r * d3, c3, d3] @@ -247,8 +247,7 @@ def lift_for_SL(A, N=None): ....: M = random_matrix(Zmod(p), d, algorithm='unimodular') ....: assert lift_for_SL(M).det() == 1 """ - from sage.matrix.special import (identity_matrix, diagonal_matrix, - block_diagonal_matrix) + from sage.matrix.special import identity_matrix, diagonal_matrix, block_diagonal_matrix from sage.misc.misc_c import prod ring = A.parent().base_ring() @@ -262,7 +261,7 @@ def lift_for_SL(A, N=None): if m <= 1: return identity_matrix(ZZ, m) - AZZ = A .change_ring(ZZ) + AZZ = A.change_ring(ZZ) D, U, V = AZZ.smith_form() diag = diagonal_matrix([-1] + [1] * (m - 1)) if U.det() == -1: diff --git a/src/sage/modular/local_comp/local_comp.py b/src/sage/modular/local_comp/local_comp.py index bd64c596096..bf6660354d2 100644 --- a/src/sage/modular/local_comp/local_comp.py +++ b/src/sage/modular/local_comp/local_comp.py @@ -274,7 +274,7 @@ def central_character(self): """ G = SmoothCharacterGroupQp(self.prime(), self.coefficient_field()) eps = G.from_dirichlet(self.newform().character()) - return eps / G.norm_character()**self.twist_factor() + return eps / G.norm_character() ** self.twist_factor() def __eq__(self, other): r""" @@ -294,10 +294,7 @@ def __eq__(self, other): sage: Pi == loads(dumps(Pi)) True """ - return (isinstance(other, LocalComponentBase) - and self.prime() == other.prime() - and self.newform() == other.newform() - and self.twist_factor() == other.twist_factor()) + return isinstance(other, LocalComponentBase) and self.prime() == other.prime() and self.newform() == other.newform() and self.twist_factor() == other.twist_factor() def __ne__(self, other): """ @@ -384,7 +381,7 @@ def check_tempered(self): c1, c2 = self.characters() K = c1.base_ring() p = self.prime() - w = QQbar(p)**((1 + self.twist_factor()) / 2) + w = QQbar(p) ** ((1 + self.twist_factor()) / 2) for sigma in K.embeddings(QQbar): assert sigma(c1(p)).abs() == sigma(c2(p)).abs() == w @@ -440,11 +437,7 @@ def satake_polynomial(self): """ p = self.prime() ring = PolynomialRing(self.coefficient_field(), 'X') - return ring([ - self.central_character()(p) * p, - -self.newform()[p] * p**((self.twist_factor() - self.newform().weight() + 2) / 2), - 1 - ]) + return ring([self.central_character()(p) * p, -self.newform()[p] * p ** ((self.twist_factor() - self.newform().weight() + 2) / 2), 1]) def characters(self): r""" @@ -498,7 +491,7 @@ def characters(self): """ G = SmoothCharacterGroupQp(self.prime(), self.coefficient_field()) t = ZZ((self.newform().weight() - 2 - self.twist_factor()) / 2) - chi1 = G.character(0, [self.newform()[self.prime()]]) * G.norm_character()**t + chi1 = G.character(0, [self.newform()[self.prime()]]) * G.norm_character() ** t chi2 = G.character(0, [self.prime()]) * self.central_character() / chi1 return Sequence([chi1, chi2], cr=True, universe=G) @@ -585,7 +578,7 @@ def check_tempered(self): c1 = self.characters()[0] K = c1.base_ring() p = self.prime() - w = QQbar(p)**(self.twist_factor() / ZZ(2)) + w = QQbar(p) ** (self.twist_factor() / ZZ(2)) for sigma in K.embeddings(QQbar): assert sigma(c1(p)).abs() == w @@ -733,15 +726,14 @@ def characters(self): # which is dual to the cohomological one that defines the local component. X = polygen(self.coefficient_field()) - theta_poly = X**2 - (-1)**n * tr * X + self.central_character()(g.norm()) + theta_poly = X**2 - (-1) ** n * tr * X + self.central_character()(g.norm()) verbose("theta_poly for %s is %s" % (g, theta_poly), level=1) if theta_poly.is_irreducible(): F = self.coefficient_field().extension(theta_poly, "d") G = G.base_extend(F) # roots with repetitions allowed - gvals = flatten([[y[0]] * y[1] - for y in theta_poly.roots(G.base_ring())]) + gvals = flatten([[y[0]] * y[1] for y in theta_poly.roots(G.base_ring())]) if len(gs) == 1: # This is always the case if p != 2 @@ -759,13 +751,12 @@ def characters(self): tr = (~T.rho(g0.matrix().list())).trace() X = polygen(G.base_ring()) - theta0_poly = X**2 - (-1)**n * tr * X + self.central_character()(g0.norm()) + theta0_poly = X**2 - (-1) ** n * tr * X + self.central_character()(g0.norm()) verbose("theta_poly for %s is %s" % (g0, theta_poly), level=1) if theta0_poly.is_irreducible(): F = theta0_poly.base_ring().extension(theta_poly, "e") G = G.base_extend(F) - g0vals = flatten([[y[0]] * y[1] - for y in theta0_poly.roots(G.base_ring())]) + g0vals = flatten([[y[0]] * y[1] for y in theta0_poly.roots(G.base_ring())]) pairA = [[g0vals[0], gvals[0]], [g0vals[1], gvals[1]]] pairB = [[g0vals[0], gvals[1]], [g0vals[1], gvals[0]]] @@ -786,7 +777,7 @@ def characters(self): B_fail = 1 # check the character relation from LW12 - if (not A_fail and not B_fail): + if not A_fail and not B_fail: for x in G.ideal(n).invertible_residues(): try: # test if G mod p is in Fp @@ -798,7 +789,7 @@ def characters(self): continue verbose("testing x = %s" % x, level=1) - ti = (-1)**n * (~T.rho(x.matrix().list())).trace() + ti = (-1) ** n * (~T.rho(x.matrix().list())).trace() verbose(" trace of matrix is %s" % ti, level=1) if ti != chisA[0](x) + chisA[1](x): verbose(" chisA FAILED", level=1) @@ -857,7 +848,7 @@ def characters(self): q = qs[0] t = ts[0] k = self.newform().weight() - t *= p**ZZ((k - 2 + self.twist_factor()) / 2) + t *= p ** ZZ((k - 2 + self.twist_factor()) / 2) X = polygen(self.coefficient_field()) theta_poly = X**2 - X * t + self.central_character()(q.norm()) @@ -874,7 +865,7 @@ def characters(self): assert p == 3 q = qs[1] t = ts[1] - t *= p**ZZ((k - 2 + self.twist_factor()) / 2) + t *= p ** ZZ((k - 2 + self.twist_factor()) / 2) X = polygen(G.base_ring()) theta_poly = X**2 - X * t + self.central_character()(q.norm()) @@ -908,7 +899,7 @@ def characters(self): break x = q * u verbose("testing x = %s" % x, level=1) - ti = (~T.rho(x.matrix().list())).trace() * p**ZZ((k - 2 + self.twist_factor()) / 2) + ti = (~T.rho(x.matrix().list())).trace() * p ** ZZ((k - 2 + self.twist_factor()) / 2) verbose("trace of matrix is %s" % ti, level=1) if chisA[0](x) + chisA[1](x) != ti: A_fail = 1 @@ -947,7 +938,7 @@ def check_tempered(self): c1, c2 = self.characters() K = c1.base_ring() p = self.prime() - w = QQbar(p)**self.twist_factor() + w = QQbar(p) ** self.twist_factor() for sigma in K.embeddings(QQbar): assert sigma(c1(p)).abs() == sigma(c2(p)).abs() == w diff --git a/src/sage/modular/local_comp/smoothchar.py b/src/sage/modular/local_comp/smoothchar.py index 907236bc2a4..053f28866fc 100644 --- a/src/sage/modular/local_comp/smoothchar.py +++ b/src/sage/modular/local_comp/smoothchar.py @@ -74,6 +74,7 @@ class SmoothCharacterGeneric(MultiplicativeGroupElement): A smooth (i.e. locally constant) character of `F^\times`, for `F` some finite extension of `\QQ_p`. """ + def __init__(self, parent, c, values_on_gens): r""" Standard init function. @@ -126,7 +127,7 @@ def __hash__(self): sage: D = {chi: 7}; D[chi] # indirect doctest 7 """ - return hash( (self._c, self._values_on_gens) ) + return hash((self._c, self._values_on_gens)) def _richcmp_(self, other, op): r""" @@ -260,7 +261,7 @@ def _repr_(self): 'Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 2, mapping 11*s - 10 |--> z^5, 6 |--> z^3, 5*s + 1 |--> 1, 5 |--> z + 1' """ gens = self.parent().unit_gens(self.level()) - mapst = ", ".join( str(gens[i]) + ' |--> ' + str(self._values_on_gens[i]) for i in range(len(gens)) ) + mapst = ", ".join(str(gens[i]) + ' |--> ' + str(self._values_on_gens[i]) for i in range(len(gens))) return "Character of %s, of level %s, mapping %s" % (self.parent()._field_name(), self.level(), mapst) def _mul_(self, other): @@ -368,8 +369,7 @@ def __init__(self, p, base_ring): """ if base_ring not in Rings(): raise TypeError("base ring (=%s) must be a ring" % base_ring) - Parent.__init__(self, base=base_ring, - category=Groups().Commutative()) + Parent.__init__(self, base=base_ring, category=Groups().Commutative()) if not (p in ZZ and ZZ(p).is_prime()): raise ValueError("p (=%s) must be a prime integer" % p) self._p = ZZ.coerce(p) @@ -400,8 +400,7 @@ def _element_constructor_(self, x): if x == 1: return self.character(0, [1]) P = parent(x) - if (isinstance(P, SmoothCharacterGroupGeneric) - and P.number_field().has_coerce_map_from(self.number_field())): + if isinstance(P, SmoothCharacterGroupGeneric) and P.number_field().has_coerce_map_from(self.number_field()): return self.character(x.level(), [x(v) for v in self.unit_gens(x.level())]) raise TypeError @@ -423,9 +422,7 @@ def __eq__(self, other): if not isinstance(other, SmoothCharacterGroupGeneric): return False - return (self.prime() == other.prime() and - self.number_field() == other.number_field() and - self.base_ring() == other.base_ring()) + return self.prime() == other.prime() and self.number_field() == other.number_field() and self.base_ring() == other.base_ring() def __ne__(self, other): """ @@ -494,9 +491,7 @@ def _coerce_map_from_(self, other): sage: G.character(0, [1]).base_extend(K) Character of unramified extension Q_3(s)* (s^2 + 2*s + 2 = 0), of level 0, mapping 3 |--> 1 """ - return (isinstance(other, SmoothCharacterGroupGeneric) - and other.number_field() == self.number_field() - and self.base_ring().has_coerce_map_from(other.base_ring())) + return isinstance(other, SmoothCharacterGroupGeneric) and other.number_field() == self.number_field() and self.base_ring().has_coerce_map_from(other.base_ring()) def prime(self): r""" @@ -733,7 +728,7 @@ def character(self, level, values_on_gens): assert len(S) == len(self.unit_gens(level)), "{0} images must be given".format(len(self.unit_gens(level))) n = self.exponents(level) for i in range(len(S)): - if n[i] != 0 and not S[i]**n[i] == 1: + if n[i] != 0 and not S[i] ** n[i] == 1: raise ValueError("value on generator %s (=%s) should be a root of unity of order %s" % (self.unit_gens(level)[i], S[i], n[i])) elif n[i] == 0 and not S[i].is_unit(): raise ValueError("value on uniformiser %s (=%s) should be a unit" % (self.unit_gens(level)[i], S[i])) @@ -752,7 +747,7 @@ def norm_character(self): sage: SmoothCharacterGroupUnramifiedQuadratic(2, QQ).norm_character() Character of unramified extension Q_2(s)* (s^2 + s + 1 = 0), of level 0, mapping 2 |--> 1/4 """ - return self.character(0, [1/self.ideal(1).residue_field().cardinality()]) + return self.character(0, [1 / self.ideal(1).residue_field().cardinality()]) def _an_element_(self): r""" @@ -790,7 +785,7 @@ def _test_unitgens(self, **options): for i in range(len(exps[:-1])): g = gens[i] for m in range(1, exps[i]): - if (g - 1 in I): + if g - 1 in I: T.fail("For generator g=%s, g^%s = %s = 1 mod I, but order should be %s" % (gens[i], m, g, exps[i])) g = g * gens[i] # reduce g mod I @@ -829,8 +824,8 @@ def _test_subgroupgens(self, **options): # if c > 1, n will be a prime here, so that logs below gets calculated correctly logs = [] - for idx in xmrange(len(sgs)*[n]): - y = prod( map(operator.pow, sgs, idx) ) + for idx in xmrange(len(sgs) * [n]): + y = prod(map(operator.pow, sgs, idx)) L = tuple(self.discrete_log(c, y)) if L not in logs: logs.append(L) @@ -898,6 +893,7 @@ class SmoothCharacterGroupQp(SmoothCharacterGroupGeneric): sage: G == loads(dumps(G)) True """ + def unit_gens(self, level): r""" Return a set of generators `x_1, \dots, x_d` for `\QQ_p^\times / (1 + @@ -915,7 +911,7 @@ def unit_gens(self, level): """ if level == 0: return [QQ(self.prime())] - return [QQ(x) for x in Zmod(self.prime()**level).unit_gens()] + [QQ(self.prime())] + return [QQ(x) for x in Zmod(self.prime() ** level).unit_gens()] + [QQ(self.prime())] def exponents(self, level): r""" @@ -931,7 +927,7 @@ def exponents(self, level): """ if level == 0: return [0] - return [x.multiplicative_order() for x in Zmod(self.prime()**level).unit_gens()] + [0] + return [x.multiplicative_order() for x in Zmod(self.prime() ** level).unit_gens()] + [0] def change_ring(self, ring): r""" @@ -1010,7 +1006,7 @@ def discrete_log(self, level, x): if x == 0: raise ValueError("cannot evaluate at zero") s = x.valuation(self.prime()) - return Zmod(self.prime()**level)(x / self.prime()**s).generalised_log() + [s] + return Zmod(self.prime() ** level)(x / self.prime() ** s).generalised_log() + [s] def subgroup_gens(self, level): r""" @@ -1043,7 +1039,7 @@ def subgroup_gens(self, level): elif level == 1: return self.unit_gens(level)[:-1] else: - return [1 + self.prime()**(level - 1)] + return [1 + self.prime() ** (level - 1)] def from_dirichlet(self, chi): r""" @@ -1098,7 +1094,7 @@ def quadratic_chars(self): q = 1 ram = [self.from_dirichlet(chi) for chi in DirichletGroup(self.prime() ** q, QQ) if not chi.is_trivial()] nr = self.character(0, [-1]) - return sorted([nr] + list(ram) + [f*nr for f in ram]) + return sorted([nr] + list(ram) + [f * nr for f in ram]) class SmoothCharacterGroupQuadratic(SmoothCharacterGroupGeneric): @@ -1158,23 +1154,23 @@ def discrete_log(self, level, x, gens=None): P = self.ideal(1) I = self.ideal(level) gens = [self.number_field().coerce(g) for g in gens] - i = min(i for i in range(len(gens)) if gens[i].valuation(P) == 1) # lazy! + i = min(i for i in range(len(gens)) if gens[i].valuation(P) == 1) # lazy! pi = gens[i] genvals = [] genunits = [] for g in gens: genvals.append(g.valuation(P)) - gu = g / pi**genvals[-1] + gu = g / pi ** genvals[-1] gu *= gu.denominator_ideal().element_1_mod(I) genunits.append(I.reduce(gu)) - xunit = x / pi**x.valuation(P) + xunit = x / pi ** x.valuation(P) xunit = I.reduce(xunit * xunit.denominator_ideal().element_1_mod(I)) verbose("computing log of %s in basis %s" % (xunit, genunits), level=1) dl = I.ideallog(xunit, genunits) pi_term = x.valuation(P) - sum(dl[j] * genvals[j] for j in range(len(gens))) dl[i] += pi_term X = prod(gens[j] ** dl[j] for j in range(len(gens))) - assert (X/x - 1).valuation(P) >= level + assert (X / x - 1).valuation(P) >= level return dl @cached_method @@ -1231,7 +1227,7 @@ def quotient_gens(self, n): d = len(es) A = ZZ**d - R = [A.gen(i)*es[i] for i in range(d)] + R = [A.gen(i) * es[i] for i in range(d)] r = I.smallest_integer() S = [self.discrete_log(n, ZZ(s)) for s in Zmod(r).unit_gens() + (p,)] Q = A / A.span(R + S) @@ -1246,8 +1242,8 @@ def quotient_gens(self, n): if t is None: t = self.discrete_log(n, p) vv = [vv[i] - t[i] for i in range(d)] - assert (Q(A(vv)) == v or Q(A(vv)) == -v) - qgs.append( I.reduce(prod(gs[i] ** (vv[i] % es[i]) for i in range(d-1))) * gs[-1]**vv[-1] ) + assert Q(A(vv)) == v or Q(A(vv)) == -v + qgs.append(I.reduce(prod(gs[i] ** (vv[i] % es[i]) for i in range(d - 1))) * gs[-1] ** vv[-1]) if len(qgs) == 2: x, y = qgs @@ -1280,12 +1276,12 @@ def _reduce_Qp(self, level, x): raise ValueError("%s not congruent mod %s to an elt of Qp" % (x, self.ideal(level))) Y = (y.trace() / 2) % self.ideal(level).smallest_integer() X = p**r * Y - if not (X/x - 1).valuation(self.ideal(1)) >= level: + if not (X / x - 1).valuation(self.ideal(1)) >= level: if p != 2: raise ValueError("%s not congruent mod %s to an elt of Qp" % (x, self.ideal(level))) else: - X += ZZ(2)**(r + level - 1) - if not (X/x - 1).valuation(self.ideal(1)) >= level: + X += ZZ(2) ** (r + level - 1) + if not (X / x - 1).valuation(self.ideal(1)) >= level: raise ValueError("%s not congruent mod %s to an elt of Qp" % (x, self.ideal(level))) return X @@ -1377,11 +1373,11 @@ def extend_character(self, level, chi, vals, check=True): for x in standard_gens: d = self.discrete_log(level, x, custom_gens) - chix = prod(values_on_custom_gens[i]**d[i] for i in range(len(d))) + chix = prod(values_on_custom_gens[i] ** d[i] for i in range(len(d))) values_on_standard_gens.append(chix) chiE = self.character(level, values_on_standard_gens) - if not all( chiE(qs[i]) == vals[i] for i in range(len(qs)) ) or chiE.restrict_to_Qp() != chi: + if not all(chiE(qs[i]) == vals[i] for i in range(len(qs))) or chiE.restrict_to_Qp() != chi: raise ValueError("Invalid values for extension") return chiE @@ -1437,6 +1433,7 @@ def change_ring(self, ring): # We want to make sure that both G and the base-extended version have # the same values in the cache. from copy import copy + G = SmoothCharacterGroupUnramifiedQuadratic(self.prime(), ring, self._name) try: G._cache___ideal = copy(self._cache___ideal) @@ -1492,7 +1489,7 @@ def ideal(self, c): sage: I is G.ideal(3) True """ - return self.number_field().ideal(self.prime()**c) + return self.number_field().ideal(self.prime() ** c) @cached_method def unit_gens(self, c): @@ -1541,17 +1538,17 @@ def unit_gens(self, c): return [a, K(p)] if p == 2: if c == 2: - return [a, 1 + 2*a, K(-1), K(2)] - return [a, 1 + 2*a, 1 + 4*a, K(-1), K(2)] + return [a, 1 + 2 * a, K(-1), K(2)] + return [a, 1 + 2 * a, 1 + 4 * a, K(-1), K(2)] # general case b = a I = self.ideal(c) - while b**(p**2 - 1) - 1 not in I: - b = I.reduce(b**(self.prime()**2)) - return [b, K(1 + p), 1 + a*p, K(p)] + while b ** (p**2 - 1) - 1 not in I: + b = I.reduce(b ** (self.prime() ** 2)) + return [b, K(1 + p), 1 + a * p, K(p)] def exponents(self, c): r""" @@ -1574,8 +1571,8 @@ def exponents(self, c): if c == 1: return [p**2 - 1, 0] if p == 2 and c >= 3: - return [p**2 - 1, p**(c-1), p**(c-2), 2, 0] - return [p**2 - 1, p**(c-1), p**(c-1), 0] + return [p**2 - 1, p ** (c - 1), p ** (c - 2), 2, 0] + return [p**2 - 1, p ** (c - 1), p ** (c - 1), 0] def subgroup_gens(self, level): r""" @@ -1598,7 +1595,7 @@ def subgroup_gens(self, level): elif level == 1: return self.unit_gens(level)[:-1] else: - return [1 + self.prime()**(level - 1), 1 + self.prime()**(level - 1) * self.number_field().gen()] + return [1 + self.prime() ** (level - 1), 1 + self.prime() ** (level - 1) * self.number_field().gen()] class SmoothCharacterGroupRamifiedQuadratic(SmoothCharacterGroupQuadratic): @@ -1606,6 +1603,7 @@ class SmoothCharacterGroupRamifiedQuadratic(SmoothCharacterGroupQuadratic): The group of smooth characters of `K^\times`, where `K` is a ramified quadratic extension of `\QQ_p`, and `p \ne 2`. """ + def __init__(self, prime, flag, base_ring, names='s'): r""" Standard initialisation function. @@ -1655,8 +1653,7 @@ def __init__(self, prime, flag, base_ring, names='s'): for a in range(4 * prime): if (not a % prime) or (not ZZ(a).is_squarefree()) or ((a * prime) % 4 == 1): continue - if (flag == 0 and Zmod(prime)(a).is_square()) or \ - (flag == 1 and not Zmod(prime)(a).is_square()): + if (flag == 0 and Zmod(prime)(a).is_square()) or (flag == 1 and not Zmod(prime)(a).is_square()): self._unif_sqr = a * prime break else: @@ -1705,6 +1702,7 @@ def number_field(self): Number Field in c with defining polynomial x^2 - 35 """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R, x = PolynomialRing(QQ, 'x').objgen() f = x**2 - self._unif_sqr return NumberField(f, self._name) @@ -1726,7 +1724,7 @@ def ideal(self, c): sage: I is G.ideal(3) True """ - return self.number_field().ideal([self.prime(), self.number_field().gen()])**c + return self.number_field().ideal([self.prime(), self.number_field().gen()]) ** c def unit_gens(self, c): r""" @@ -1788,7 +1786,7 @@ def exponents(self, c): return (p - 1, 0) if p > 3 or self._unif_sqr == 3 or c <= 3: d = (c + 1) // 2 - return (p**(d - 1) * (p - 1), p**(c // 2), 0) + return (p ** (d - 1) * (p - 1), p ** (c // 2), 0) # awkward case, see above return self.ideal(c).idealstar(2).gens_orders() + (0,) @@ -1810,4 +1808,4 @@ def subgroup_gens(self, level): elif level == 1: return self.unit_gens(level)[:-1] else: - return [1 + self.number_field().gen()**(level - 1)] + return [1 + self.number_field().gen() ** (level - 1)] diff --git a/src/sage/modular/local_comp/type_space.py b/src/sage/modular/local_comp/type_space.py index 208b7252bc5..66a3b91357d 100644 --- a/src/sage/modular/local_comp/type_space.py +++ b/src/sage/modular/local_comp/type_space.py @@ -49,6 +49,7 @@ def example_type_space(example_no=0): So we don't want to mark it ``# long time``. """ from sage.modular.modform.constructor import Newform as Newform_constructor + if example_no == 0: # a fairly generic example return TypeSpace(Newform_constructor('98b', names='a'), 7) @@ -143,8 +144,7 @@ def find_in_space(f, A, base_extend=False): break if D.dimension() != expected_dimension: - raise ArithmeticError("Error in find_in_space: " - + "got dimension %s (should be %s)" % (D.dimension(), expected_dimension)) + raise ArithmeticError("Error in find_in_space: " + "got dimension %s (should be %s)" % (D.dimension(), expected_dimension)) return D @@ -154,6 +154,7 @@ class TypeSpace(SageObject): The modular symbol type space associated to a newform, at a prime dividing the level. """ + ################################################# # Basic initialisation and data-access functions ################################################# @@ -174,7 +175,7 @@ def __init__(self, f, p, base_extend=True): amb = ModularSymbols(self.group(), f.weight()) self.e_space = find_in_space(f, amb, base_extend=base_extend).sign_submodule(1) R = self.e_space.base_ring() - mat = amb._action_on_modular_symbols([p**self.u(), 1, 0, p**self.u()]) + mat = amb._action_on_modular_symbols([p ** self.u(), 1, 0, p ** self.u()]) V = amb.free_module().base_extend(R) bvecs = [] for v in self.e_space.free_module().basis(): @@ -470,7 +471,7 @@ def _second_gen_unramified(self): g3 = [f * g2[0], g2[1], f**2 * g2[2], f * g2[3]] A = self.t_space.ambient() mm = A._action_on_modular_symbols(g3).restrict(self.t_space.free_module()).transpose() - return mm / ZZ(f**(self.form().weight() - 2)) + return mm / ZZ(f ** (self.form().weight() - 2)) def _rho_unramified(self, g): r""" @@ -500,6 +501,7 @@ def _rho_unramified(self, g): """ f = self.prime() ** self.u() from sage.groups.matrix_gps.linear import SL + G = SL(2, Zmod(f)) gg = G(g) s = G([1, 1, 0, 1]) @@ -538,8 +540,8 @@ def _rho_ramified(self, g): p = self.prime() assert g[2] % p == 0 gg = lift_ramified(g, p, self.u(), self.tame_level()) - g3 = [p**self.u() * gg[0], gg[1], p**(2 * self.u()) * gg[2], p**self.u() * gg[3]] - return A._action_on_modular_symbols(g3).restrict(self.t_space.free_module()).transpose() / ZZ(p**(self.u() * (self.form().weight() - 2))) + g3 = [p ** self.u() * gg[0], gg[1], p ** (2 * self.u()) * gg[2], p ** self.u() * gg[3]] + return A._action_on_modular_symbols(g3).restrict(self.t_space.free_module()).transpose() / ZZ(p ** (self.u() * (self.form().weight() - 2))) def _group_gens(self): r""" @@ -562,9 +564,8 @@ def _group_gens(self): if p == 2: return [[ZZ(1), ZZ(1), ZZ(0), ZZ(1)], [ZZ(1), ZZ(0), ZZ(p), ZZ(1)]] - a = Zmod(p**(self.u() + 1))(ZZ(Zmod(p).unit_gens()[0])) - return [[ZZ(1), ZZ(1), ZZ(0), ZZ(1)], [ZZ(1), ZZ(0), ZZ(p), ZZ(1)], - [ZZ(a), 0, 0, ZZ(~a)]] + a = Zmod(p ** (self.u() + 1))(ZZ(Zmod(p).unit_gens()[0])) + return [[ZZ(1), ZZ(1), ZZ(0), ZZ(1)], [ZZ(1), ZZ(0), ZZ(p), ZZ(1)], [ZZ(a), 0, 0, ZZ(~a)]] def _intertwining_basis(self, a): r""" @@ -681,9 +682,9 @@ def rho(self, g): raise ValueError("Representation is not supercuspidal") p = self.prime() - f = p**self.u() + f = p ** self.u() g = [ZZ(_) for _ in g] - d = (g[0] * g[3] - g[2] * g[1]) + d = g[0] * g[3] - g[2] * g[1] # g is in S(K_0) (easy case) if d % f == 1: @@ -700,29 +701,28 @@ def rho(self, g): if not (f % 8): if d % 4 == 3: - return (self.rho([-g[0], g[1], -g[2], g[3]]) * - self.t_space.star_involution().matrix().transpose()) + return self.rho([-g[0], g[1], -g[2], g[3]]) * self.t_space.star_involution().matrix().transpose() i = 0 while (d * a**i) % f != 1: i += 1 if i > f: raise ArithmeticError - return self._rho_s([a**i * g[0], g[1], a**i * g[2], g[3]]) * self._amat**(-i) + return self._rho_s([a**i * g[0], g[1], a**i * g[2], g[3]]) * self._amat ** (-i) # det(g) is not a unit - if (self.conductor() % 2 == 0): + if self.conductor() % 2 == 0: if all(x.valuation(p) > 0 for x in g): eps = self.form().character()(crt(1, p, f, self.tame_level())) - return ~eps * p**(self.form().weight() - 2) * self.rho([x // p for x in g]) + return ~eps * p ** (self.form().weight() - 2) * self.rho([x // p for x in g]) raise ArithmeticError(f"g(={g}) not in K") else: m = matrix(ZZ, 2, g) s = m.det().valuation(p) - mm = (matrix(QQ, 2, [0, -1, p, 0])**(-s) * m).change_ring(ZZ) - return self._unif_ramified()**s * self.rho(mm.list()) + mm = (matrix(QQ, 2, [0, -1, p, 0]) ** (-s) * m).change_ring(ZZ) + return self._unif_ramified() ** s * self.rho(mm.list()) def _unif_ramified(self): r""" @@ -739,7 +739,4 @@ def _unif_ramified(self): """ p = self.prime() k = self.form().weight() - return (self.t_space.atkin_lehner_operator(p).matrix().transpose() - * p ** (-(k - 2) * self.u()) - * self.t_space.diamond_bracket_matrix( - crt(1, p**self.u(), p**self.u(), self.tame_level())).transpose()) + return self.t_space.atkin_lehner_operator(p).matrix().transpose() * p ** (-(k - 2) * self.u()) * self.t_space.diamond_bracket_matrix(crt(1, p ** self.u(), p ** self.u(), self.tame_level())).transpose() diff --git a/src/sage/modular/modform/all.py b/src/sage/modular/modform/all.py index 6461e3c7083..5cd355379ff 100644 --- a/src/sage/modular/modform/all.py +++ b/src/sage/modular/modform/all.py @@ -26,4 +26,5 @@ from sage.modular.modform.element import delta_lseries from sage.modular.modform.ring import ModularFormsRing + del lazy_import diff --git a/src/sage/modular/modform/ambient.py b/src/sage/modular/modform/ambient.py index 5180b07b398..2ca85facd40 100644 --- a/src/sage/modular/modform/ambient.py +++ b/src/sage/modular/modform/ambient.py @@ -84,11 +84,11 @@ from . import submodule -class ModularFormsAmbient(space.ModularFormsSpace, - AmbientHeckeModule): +class ModularFormsAmbient(space.ModularFormsSpace, AmbientHeckeModule): """ An ambient space of modular forms. """ + def __init__(self, group, weight, base_ring, character=None, eis_only=False): """ Create an ambient space of modular forms. @@ -133,10 +133,8 @@ def _repr_(self): 'Modular Forms space of dimension 1198 for Congruence Subgroup Gamma1(20) of weight 100 over Rational Field' """ if self._eis_only: - return "Modular Forms space for %s of weight %s over %s" % ( - self.group(), self.weight(), self.base_ring()) - return "Modular Forms space of dimension %s for %s of weight %s over %s" % ( - self.dimension(), self.group(), self.weight(), self.base_ring()) + return "Modular Forms space for %s of weight %s over %s" % (self.group(), self.weight(), self.base_ring()) + return "Modular Forms space of dimension %s for %s of weight %s over %s" % (self.dimension(), self.group(), self.weight(), self.base_ring()) def _submodule_class(self): """ @@ -178,9 +176,8 @@ def change_ring(self, base_ring): 1 + q^3 + q^4 + 2*q^5 + O(q^6)] """ from . import constructor - return constructor.ModularForms(self.group(), self.weight(), - base_ring, prec=self.prec(), - eis_only=self._eis_only) + + return constructor.ModularForms(self.group(), self.weight(), base_ring, prec=self.prec(), eis_only=self._eis_only) @cached_method def dimension(self): @@ -217,6 +214,7 @@ def hecke_module_of_level(self, N): if not (N % self.level() == 0 or self.level() % N == 0): raise ValueError("N (=%s) must be a divisor or a multiple of the level of self (=%s)" % (N, self.level())) from . import constructor + return constructor.ModularForms(self.group()._new_group_from_level(N), self.weight(), self.base_ring(), prec=self.prec()) def _degeneracy_raising_matrix(self, M, t): @@ -241,6 +239,7 @@ def _degeneracy_raising_matrix(self, M, t): [0 0 0 0 0 0 0 1 0] """ from sage.matrix.matrix_space import MatrixSpace + A = MatrixSpace(self.base_ring(), self.dimension(), M.dimension()) d = M.sturm_bound() + 1 q = self.an_element().qexp(d).parent().gen() @@ -315,10 +314,7 @@ def modular_symbols(self, sign=0): Modular Symbols space of dimension 3 for Gamma_0(1) of weight 12 with sign 0 over Rational Field """ sign = Integer(sign) - return ModularSymbols(group=self.group(), - weight=self.weight(), - sign=sign, - base_ring=self.base_ring()) + return ModularSymbols(group=self.group(), weight=self.weight(), sign=sign, base_ring=self.base_ring()) @cached_method def module(self): @@ -425,6 +421,7 @@ def cuspidal_submodule(self): Congruence Subgroup Gamma1(13) of weight 2 over Rational Field """ from .cuspidal_submodule import CuspidalSubmodule + return CuspidalSubmodule(self) @cached_method @@ -557,8 +554,7 @@ def _dim_cuspidal(self): if self._eis_only: return 0 if isinstance(self.group(), Gamma1_class) and self.character() is not None: - return self.group().dimension_cusp_forms(self.weight(), - self.character()) + return self.group().dimension_cusp_forms(self.weight(), self.character()) return self.group().dimension_cusp_forms(self.weight()) @cached_method @@ -762,10 +758,10 @@ def _compute_hecke_matrix(self, n): if d == 0: return matrix(self.base_ring(), 0, 0, []) from sage.modular.all import victor_miller_basis, hecke_operator_on_basis + vmb = victor_miller_basis(k, prec=d * n + 1)[1:] Tcusp = hecke_operator_on_basis(vmb, n, k) - return Tcusp.block_sum(matrix(self.base_ring(), 1, 1, - [sigma(n, k - 1)])) + return Tcusp.block_sum(matrix(self.base_ring(), 1, 1, [sigma(n, k - 1)])) return space.ModularFormsSpace._compute_hecke_matrix(self, n) def _compute_hecke_matrix_prime_power(self, p, r): diff --git a/src/sage/modular/modform/ambient_R.py b/src/sage/modular/modform/ambient_R.py index 8ac6943e936..b760575b330 100644 --- a/src/sage/modular/modform/ambient_R.py +++ b/src/sage/modular/modform/ambient_R.py @@ -116,6 +116,7 @@ def _compute_q_expansion_basis(self, prec=None): K = self.base_ring() p = K.characteristic().prime_factors()[0] from sage.rings.finite_rings.finite_field_constructor import GF + Kp = GF(p) newB = [f.change_ring(K) for f in list(self.__M.cuspidal_subspace().q_integral_basis(prec))] A = Kp**prec @@ -131,7 +132,7 @@ def _compute_q_expansion_basis(self, prec=None): if len(newB) != self.dimension(): raise RuntimeError("The dimension of the space is %s but the basis we computed has %s elements" % (self.dimension(), len(newB))) lst = [R(f) for f in newB] - return [f/f[f.valuation()] for f in lst] + return [f / f[f.valuation()] for f in lst] # this returns a basis of q-expansions, without guaranteeing that # the first vectors form a basis of the cuspidal subspace # TODO: bring this in line with the other cases diff --git a/src/sage/modular/modform/ambient_eps.py b/src/sage/modular/modform/ambient_eps.py index 0708f188975..7cfa241f29d 100644 --- a/src/sage/modular/modform/ambient_eps.py +++ b/src/sage/modular/modform/ambient_eps.py @@ -99,6 +99,7 @@ class ModularFormsAmbient_eps(ModularFormsAmbient): """ A space of modular forms with character. """ + def __init__(self, character, weight=2, base_ring=None, eis_only=False): """ Create an ambient modular forms space with character. @@ -160,10 +161,8 @@ def _repr_(self): Modforms of level 8 """ if self._eis_only: - return "Modular Forms space of character %s and weight %s over %s" % ( - self.character()._repr_short_(), self.weight(), self.base_ring()) - return "Modular Forms space of dimension %s, character %s and weight %s over %s" % ( - self.dimension(), self.character()._repr_short_(), self.weight(), self.base_ring()) + return "Modular Forms space of character %s and weight %s over %s" % (self.character()._repr_short_(), self.weight(), self.base_ring()) + return "Modular Forms space of dimension %s, character %s and weight %s over %s" % (self.dimension(), self.character()._repr_short_(), self.weight(), self.base_ring()) @cached_method def cuspidal_submodule(self): @@ -210,7 +209,7 @@ def change_ring(self, base_ring): return self return ambient_R.ModularFormsAmbient_R(self, base_ring=base_ring) - @cached_method(key=lambda self, sign: Integer(sign)) # convert sign to an Integer before looking this up in the cache + @cached_method(key=lambda self, sign: Integer(sign)) # convert sign to an Integer before looking this up in the cache def modular_symbols(self, sign=0): """ Return corresponding space of modular symbols with given sign. @@ -234,10 +233,7 @@ def modular_symbols(self, sign=0): ValueError: sign must be -1, 0, or 1 """ sign = Integer(sign) - return modsym.ModularSymbols(self.character(), - weight=self.weight(), - sign=sign, - base_ring=self.base_ring()) + return modsym.ModularSymbols(self.character(), weight=self.weight(), sign=sign, base_ring=self.base_ring()) @cached_method def eisenstein_submodule(self): @@ -280,6 +276,7 @@ def hecke_module_of_level(self, N): over Rational Field """ from . import constructor + if N % self.level() == 0: return constructor.ModularForms(self.character().extend(N), self.weight(), self.base_ring(), prec=self.prec()) if self.level() % N == 0: @@ -299,4 +296,5 @@ def _pari_init_(self): [17, 2, Mod(9, 17), 4, t^4 + 1] """ from sage.libs.pari import pari + return pari.mfinit([self.level(), self.weight(), self.character()], 4) diff --git a/src/sage/modular/modform/ambient_g0.py b/src/sage/modular/modform/ambient_g0.py index c612949e6c9..01efd3c6e40 100644 --- a/src/sage/modular/modform/ambient_g0.py +++ b/src/sage/modular/modform/ambient_g0.py @@ -28,6 +28,7 @@ class ModularFormsAmbient_g0_Q(ambient.ModularFormsAmbient): r""" A space of modular forms for `\Gamma_0(N)` over `\QQ`. """ + def __init__(self, level, weight): r""" Create a space of modular symbols for `\Gamma_0(N)` of given @@ -56,6 +57,7 @@ def _pari_init_(self): [11, 4, 1, 4, t - 1] """ from sage.libs.pari import pari + return pari.mfinit([self.level(), self.weight()], 4) #################################################################### @@ -113,5 +115,6 @@ def _compute_atkin_lehner_matrix(self, d): """ if self.level() == 1: from sage.matrix.matrix_space import MatrixSpace + return MatrixSpace(self.base_ring(), self.rank())(1) raise NotImplementedError diff --git a/src/sage/modular/modform/ambient_g1.py b/src/sage/modular/modform/ambient_g1.py index d4eeb44e467..71bc002471f 100644 --- a/src/sage/modular/modform/ambient_g1.py +++ b/src/sage/modular/modform/ambient_g1.py @@ -54,6 +54,7 @@ class ModularFormsAmbient_gH_Q(ambient.ModularFormsAmbient): r""" A space of modular forms for the group `\Gamma_H(N)` over the rational numbers. """ + def __init__(self, group, weight, eis_only): r""" Create a space of modular forms for `\Gamma_H(N)` of integral weight over the @@ -119,8 +120,7 @@ def _compute_diamond_matrix(self, d): [ 0 0 0 0 0 0 -1 0] [ 0 0 0 0 0 0 0 -1] """ - return self.cuspidal_submodule().diamond_bracket_matrix(d).block_sum( - self.eisenstein_submodule().diamond_bracket_matrix(d)) + return self.cuspidal_submodule().diamond_bracket_matrix(d).block_sum(self.eisenstein_submodule().diamond_bracket_matrix(d)) def _compute_hecke_matrix(self, n): r""" @@ -146,6 +146,7 @@ class ModularFormsAmbient_g1_Q(ModularFormsAmbient_gH_Q): r""" A space of modular forms for the group `\Gamma_1(N)` over the rational numbers. """ + def __init__(self, level, weight, eis_only): r""" Create a space of modular forms for `\Gamma_1(N)` of integral weight over the diff --git a/src/sage/modular/modform/constructor.py b/src/sage/modular/modform/constructor.py index b1158043fd2..9775f814c7f 100644 --- a/src/sage/modular/modform/constructor.py +++ b/src/sage/modular/modform/constructor.py @@ -101,8 +101,7 @@ def canonical_parameters(group, level, weight, base_ring): if Integer(level) != group.level(): raise ValueError("group.level() and level do not match.") # normalize the case of SL2Z - if isinstance(group, arithgroup.SL2Z_class) or \ - isinstance(group, arithgroup.Gamma1_class) and group.level() == Integer(1): + if isinstance(group, arithgroup.SL2Z_class) or isinstance(group, arithgroup.Gamma1_class) and group.level() == Integer(1): group = arithgroup.Gamma0(Integer(1)) elif group is None: @@ -151,12 +150,7 @@ def ModularForms_clear_cache(): _cache = {} -def ModularForms(group=1, - weight=2, - base_ring=None, - eis_only=False, - use_cache=True, - prec=defaults.DEFAULT_PRECISION): +def ModularForms(group=1, weight=2, base_ring=None, eis_only=False, use_cache=True, prec=defaults.DEFAULT_PRECISION): r""" Create an ambient space of modular forms. @@ -302,8 +296,7 @@ def ModularForms(group=1, if base_ring is None: base_ring = QQ - if isinstance(group, (dirichlet.DirichletCharacter, - arithgroup.CongruenceSubgroupBase)): + if isinstance(group, (dirichlet.DirichletCharacter, arithgroup.CongruenceSubgroupBase)): level = group.level() else: level = group @@ -347,12 +340,10 @@ def ModularForms(group=1, raise NotImplementedError("currently the character must be over a ring of characteristic 0.") eps = eps.minimize_base_ring() if eps.is_trivial(): - return ModularForms(eps.modulus(), weight, base_ring, - use_cache=use_cache, - prec=prec) + return ModularForms(eps.modulus(), weight, base_ring, use_cache=use_cache, prec=prec) M = ModularFormsAmbient_eps(eps, weight, eis_only=eis_only) if base_ring != eps.base_ring(): - M = M.base_extend(base_ring) # ambient_R.ModularFormsAmbient_R(M, base_ring) + M = M.base_extend(base_ring) # ambient_R.ModularFormsAmbient_R(M, base_ring) if M is None: raise NotImplementedError("computation of requested space of modular forms not defined or implemented") @@ -362,11 +353,7 @@ def ModularForms(group=1, return M -def CuspForms(group=1, - weight=2, - base_ring=None, - use_cache=True, - prec=defaults.DEFAULT_PRECISION): +def CuspForms(group=1, weight=2, base_ring=None, use_cache=True, prec=defaults.DEFAULT_PRECISION): """ Create a space of cuspidal modular forms. @@ -379,15 +366,10 @@ def CuspForms(group=1, Cuspidal subspace of dimension 1 of Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field """ - return ModularForms(group, weight, base_ring, - use_cache=use_cache, prec=prec).cuspidal_submodule() + return ModularForms(group, weight, base_ring, use_cache=use_cache, prec=prec).cuspidal_submodule() -def EisensteinForms(group=1, - weight=2, - base_ring=None, - use_cache=True, - prec=defaults.DEFAULT_PRECISION): +def EisensteinForms(group=1, weight=2, base_ring=None, use_cache=True, prec=defaults.DEFAULT_PRECISION): """ Create a space of Eisenstein modular forms. @@ -401,10 +383,8 @@ def EisensteinForms(group=1, for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field """ if weight == 1: - return ModularForms(group, weight, base_ring, - use_cache=use_cache, eis_only=True, prec=prec).eisenstein_submodule() - return ModularForms(group, weight, base_ring, - use_cache=use_cache, prec=prec).eisenstein_submodule() + return ModularForms(group, weight, base_ring, use_cache=use_cache, eis_only=True, prec=prec).eisenstein_submodule() + return ModularForms(group, weight, base_ring, use_cache=use_cache, prec=prec).eisenstein_submodule() def Newforms(group, weight=2, base_ring=None, names=None): @@ -528,7 +508,7 @@ def parse_label(s): N = int(N) index = 0 for c in reversed(order): - index = 26*index + ord(c)-ord('a') + index = 26 * index + ord(c) - ord('a') if G == '' or G == 'G0': G = arithgroup.Gamma0(N) elif G == 'G1': diff --git a/src/sage/modular/modform/cuspidal_submodule.py b/src/sage/modular/modform/cuspidal_submodule.py index eae99c9f710..dc1ca06615e 100644 --- a/src/sage/modular/modform/cuspidal_submodule.py +++ b/src/sage/modular/modform/cuspidal_submodule.py @@ -49,6 +49,7 @@ class CuspidalSubmodule(ModularFormsSubmodule): """ Base class for cuspidal submodules of ambient spaces of modular forms. """ + def __init__(self, ambient_space): """ The cuspidal submodule of an ambient space of modular forms. @@ -76,6 +77,7 @@ def __init__(self, ambient_space): True """ from sage.misc.verbose import verbose + verbose('creating cuspidal submodule of %s' % ambient_space) d = ambient_space._dim_cuspidal() V = ambient_space.module() @@ -201,6 +203,7 @@ class CuspidalSubmodule_R(CuspidalSubmodule): """ Cuspidal submodule over a non-minimal base ring. """ + def _compute_q_expansion_basis(self, prec): r""" EXAMPLES:: @@ -216,6 +219,7 @@ class CuspidalSubmodule_modsym_qexp(CuspidalSubmodule): """ Cuspidal submodule with `q`-expansions calculated via modular symbols. """ + def _compute_q_expansion_basis(self, prec=None): """ Compute `q`-expansions of a basis for ``self`` (via modular symbols). @@ -299,6 +303,7 @@ class CuspidalSubmodule_level1_Q(CuspidalSubmodule): r""" Space of cusp forms of level 1 over `\QQ`. """ + def _compute_q_expansion_basis(self, prec=None): """ Compute `q`-expansions of a basis for ``self``. @@ -327,6 +332,7 @@ def _pari_init_(self): 1 """ from sage.libs.pari import pari + return pari.mfinit([self.level(), self.weight()], 1) @@ -349,8 +355,7 @@ def _compute_q_expansion_basis(self, prec=None): else: prec = Integer(prec) chi = self.character() - return [weight1.modular_ratio_to_prec(chi, f, prec) for f in - weight1.hecke_stable_subspace(chi)] + return [weight1.modular_ratio_to_prec(chi, f, prec) for f in weight1.hecke_stable_subspace(chi)] def _pari_init_(self): """ @@ -365,6 +370,7 @@ def _pari_init_(self): 1 """ from sage.libs.pari import pari + return pari.mfinit([self.level(), self.weight(), self.character()], 1) @@ -399,8 +405,7 @@ def _compute_q_expansion_basis(self, prec=None): dim = 0 for c in chars: chi = c.minimize_base_ring() - Bchi = [weight1.modular_ratio_to_prec(chi, f, prec) - for f in weight1.hecke_stable_subspace(chi) ] + Bchi = [weight1.modular_ratio_to_prec(chi, f, prec) for f in weight1.hecke_stable_subspace(chi)] if Bchi == []: continue if chi.base_ring() == QQ: @@ -430,11 +435,11 @@ def _compute_q_expansion_basis(self, prec=None): if c >= prec: verbose("Precision %s insufficient to determine basis" % prec, level=1) else: - verbose("Minimal precision for basis: %s" % (c+1), level=1) + verbose("Minimal precision for basis: %s" % (c + 1), level=1) t = big_mat[:, prec:] assert echelon_basis_mat == t * basis_mat self.__transformation_matrix = t - self._char_basis = [R(f.list(), c+1) for f in basis_mat.rows()] + self._char_basis = [R(f.list(), c + 1) for f in basis_mat.rows()] return [R(f.list(), prec) for f in echelon_basis_mat.rows() if f != 0] @@ -456,7 +461,7 @@ def _transformation_matrix(self): [ 1 0 0 0 -1 0 1] [ 0 0 1 0 0 -1 0] """ - self.q_expansion_basis() # triggers iterative computation + self.q_expansion_basis() # triggers iterative computation return self.__transformation_matrix def _compute_diamond_matrix(self, d): @@ -532,15 +537,16 @@ def _compute_hecke_matrix(self, n): chi = c.minimize_base_ring() d = weight1.dimension_wt1_cusp_forms(chi) e = chi.base_ring().degree() - H = Matrix(QQ, d*e, d*e) + H = Matrix(QQ, d * e, d * e) from .constructor import CuspForms + M = CuspForms(chi, 1).hecke_matrix(n) if e == 1: H = M else: for i in range(d): for j in range(d): - H[e*i: e*(i+1), e*j: e*(j+1)] = M[i, j].matrix().transpose() + H[e * i : e * (i + 1), e * j : e * (j + 1)] = M[i, j].matrix().transpose() A = A.block_sum(H) t = self._transformation_matrix() return t * A * ~t @@ -550,6 +556,7 @@ class CuspidalSubmodule_g0_Q(CuspidalSubmodule_modsym_qexp): r""" Space of cusp forms for `\Gamma_0(N)` over `\QQ`. """ + def _pari_init_(self): """ Conversion to Pari. @@ -564,6 +571,7 @@ def _pari_init_(self): 2 """ from sage.libs.pari import pari + return pari.mfinit([self.level(), self.weight()], 1) @@ -642,6 +650,7 @@ class CuspidalSubmodule_eps(CuspidalSubmodule_modsym_qexp): sage: f.qexp(1) O(q^1) """ + pass @@ -680,10 +689,8 @@ def _convert_matrix_from_modsyms(symbs, T): # we repeatedly use these matrices below, so we store them # once as lists to save time. - hecke_matrix_ls = [symbs.hecke_matrix(m).list() - for m in range(1, r + 1)] - hecke_image_ls = [(T * symbs.hecke_matrix(m)).list() - for m in range(1, r + 1)] + hecke_matrix_ls = [symbs.hecke_matrix(m).list() for m in range(1, r + 1)] + hecke_image_ls = [(T * symbs.hecke_matrix(m)).list() for m in range(1, r + 1)] # compute the q-expansions of some cusp forms and their # images under T_n @@ -703,5 +710,4 @@ def _convert_matrix_from_modsyms(symbs, T): bigmat = Matrix(A, basis).augment(Matrix(A, basis_images)) bigmat.echelonize() pivs = bigmat.pivots() - return bigmat.matrix_from_rows_and_columns(list(range(d)), - [r + x for x in pivs]), pivs + return bigmat.matrix_from_rows_and_columns(list(range(d)), [r + x for x in pivs]), pivs diff --git a/src/sage/modular/modform/defaults.py b/src/sage/modular/modform/defaults.py index e818030eebf..75a5be623df 100644 --- a/src/sage/modular/modform/defaults.py +++ b/src/sage/modular/modform/defaults.py @@ -9,5 +9,6 @@ # The default precision for computation and display of q-expansions of # modular forms. from sage.rings.integer import Integer + DEFAULT_PRECISION = Integer(6) DEFAULT_VARIABLE = 'q' diff --git a/src/sage/modular/modform/eis_series.py b/src/sage/modular/modform/eis_series.py index 81d9ee32c17..52dbd901d34 100644 --- a/src/sage/modular/modform/eis_series.py +++ b/src/sage/modular/modform/eis_series.py @@ -130,18 +130,18 @@ def eisenstein_series_qexp(k, prec=10, K=QQ, var='q', normalization='linear'): if k <= 0 or k % 2 == 1: raise ValueError("k must be positive and even") - a0 = - bernoulli(k) / (2*k) + a0 = -bernoulli(k) / (2 * k) if normalization == 'linear': a0den = a0.denominator() try: - a0fac = K(1/a0den) + a0fac = K(1 / a0den) except ZeroDivisionError: raise ValueError("The denominator of -B_k/(2*k) (=%s) must be invertible in the ring %s" % (a0den, K)) elif normalization == 'constant': a0num = a0.numerator() try: - a0fac = K(1/a0num) + a0fac = K(1 / a0num) except ZeroDivisionError: raise ValueError("The numerator of -B_k/(2*k) (=%s) must be invertible in the ring %s" % (a0num, K)) elif normalization == 'integral': @@ -165,7 +165,7 @@ def eisenstein_series_qexp(k, prec=10, K=QQ, var='q', normalization='linear'): # regression; the morally right fix would be to expose FLINT's # fmpz_poly_to_nmod_poly command (at least for word-sized N). if a0fac is not None: - return a0fac*R(eisenstein_series_poly(k, prec).list(), prec=prec, check=True) + return a0fac * R(eisenstein_series_poly(k, prec).list(), prec=prec, check=True) return R(eisenstein_series_poly(k, prec).list(), prec=prec, check=True) @@ -189,8 +189,7 @@ def __common_minimal_basering(chi, psi): """ chi = chi.minimize_base_ring() psi = psi.minimize_base_ring() - n = lcm(chi.base_ring().zeta().multiplicative_order(), - psi.base_ring().zeta().multiplicative_order()) + n = lcm(chi.base_ring().zeta().multiplicative_order(), psi.base_ring().zeta().multiplicative_order()) if n <= 2: K = QQ else: @@ -241,12 +240,12 @@ def __find_eisen_chars(character, k): if N % (f**2) == 0: chi = chi.minimize_base_ring() chi_inv = ~chi - for t in divisors(N//(f**2)): + for t in divisors(N // (f**2)): V.insert(0, (chi, chi_inv, t)) return V eps = character - if eps(-1) != (-1)**k: + if eps(-1) != (-1) ** k: return [] eps = eps.maximize_base_ring() G = eps.parent() @@ -284,9 +283,9 @@ def __find_eisen_chars(character, k): GR = C[R] for chi in GL: for psi in GR: - if chi*psi == eps: + if chi * psi == eps: chi0, psi0 = __common_minimal_basering(chi, psi) - for t in divisors(N//(R*L)): + for t in divisors(N // (R * L)): if k != 1 or (psi0, chi0, t) not in params: params.append((chi0, psi0, t)) return params @@ -344,7 +343,7 @@ def __find_eisen_chars_gamma1(N, k): ((1, -1), (1, 1), 4)] """ pairs = [] - s = (-1)**k + s = (-1) ** k G = DirichletGroup(N) E = list(G) parity = [c(-1) for c in E] @@ -420,10 +419,9 @@ def eisenstein_series_lseries(weight, prec=53, max_imaginary_part=0): """ # ref : https://arxiv.org/pdf/1904.00190 Example 5.3 from sage.lfunctions.pari import lfun_eisenstein, LFunction - L = LFunction(lfun_eisenstein(weight), prec=prec, - max_im=max_imaginary_part) - L.rename(f'L-series associated to the Eisenstein series E{weight} ' - 'on SL_2(Z)') + + L = LFunction(lfun_eisenstein(weight), prec=prec, max_im=max_imaginary_part) + L.rename(f'L-series associated to the Eisenstein series E{weight} ' 'on SL_2(Z)') return L diff --git a/src/sage/modular/modform/eisenstein_submodule.py b/src/sage/modular/modform/eisenstein_submodule.py index fca651e7712..c02805acc75 100644 --- a/src/sage/modular/modform/eisenstein_submodule.py +++ b/src/sage/modular/modform/eisenstein_submodule.py @@ -23,6 +23,7 @@ class EisensteinSubmodule(submodule.ModularFormsSubmodule): """ The Eisenstein submodule of an ambient space of modular forms. """ + def __init__(self, ambient_space): """ Return the Eisenstein submodule of the given space. @@ -37,13 +38,13 @@ def __init__(self, ambient_space): True """ from sage.misc.verbose import verbose + verbose('creating eisenstein submodule of %s' % ambient_space) d = ambient_space._dim_eisenstein() V = ambient_space.module() n = V.dimension() self._start_position = int(n - d) - S = V.submodule([V.gen(i) for i in range(n-d,n)], check=False, - already_echelonized=True) + S = V.submodule([V.gen(i) for i in range(n - d, n)], check=False, already_echelonized=True) submodule.ModularFormsSubmodule.__init__(self, ambient_space, S) def _repr_(self): @@ -270,9 +271,7 @@ def eisenstein_series(self): q^3 + O(q^6)] """ P = self.parameters() - E = Sequence([element.EisensteinSeries(self.change_ring(chi.base_ring()), - None, t, chi, psi) for chi, psi, t in P], - immutable=True, cr=True, universe=Objects()) + E = Sequence([element.EisensteinSeries(self.change_ring(chi.base_ring()), None, t, chi, psi) for chi, psi, t in P], immutable=True, cr=True, universe=Objects()) assert len(E) == self.dimension(), "bug in enumeration of Eisenstein series." return E @@ -328,7 +327,7 @@ def _compute_q_expansion_basis(self, prec=None, new=False): G.append(V(w)) else: # restrict scalars from L to K - r,d = cyclotomic_restriction(L,K) + r, d = cyclotomic_restriction(L, K) s = [r(x) for x in w] for i in range(d): G.append(V([x[i] for x in s])) @@ -337,7 +336,7 @@ def _compute_q_expansion_basis(self, prec=None, new=False): R = self._q_expansion_ring() X = [R(f.list(), prec) for f in W.basis()] if not new: - return X + [R(0,prec)]*(self.dimension() - len(X)) + return X + [R(0, prec)] * (self.dimension() - len(X)) return X def _q_expansion(self, element, prec): @@ -367,6 +366,7 @@ class EisensteinSubmodule_g0_Q(EisensteinSubmodule_params): r""" Space of Eisenstein forms for `\Gamma_0(N)`. """ + def _pari_init_(self): """ Conversion to Pari. @@ -380,6 +380,7 @@ def _pari_init_(self): [17, 4, 1, 3, t - 1] """ from sage.libs.pari import pari + return pari.mfinit([self.level(), self.weight()], 3) @@ -387,6 +388,7 @@ class EisensteinSubmodule_gH_Q(EisensteinSubmodule_params): r""" Space of Eisenstein forms for `\Gamma_H(N)`. """ + def _parameters_character(self): """ Return the character defining ``self``. Since ``self`` is @@ -422,10 +424,11 @@ def _convert_matrix_from_modsyms_eis(self, A): [ 0 1 -4 10] """ from .cuspidal_submodule import _convert_matrix_from_modsyms + symbs = self.modular_symbols(sign=0) d = self.rank() wrong_mat, pivs = _convert_matrix_from_modsyms(symbs, A) - c = Matrix(self.base_ring(), d, [self.basis()[i][j+1] for i in range(d) for j in pivs]) + c = Matrix(self.base_ring(), d, [self.basis()[i][j + 1] for i in range(d) for j in pivs]) return c * wrong_mat * ~c def _compute_hecke_matrix(self, n, bound=None): @@ -493,6 +496,7 @@ class EisensteinSubmodule_g1_Q(EisensteinSubmodule_gH_Q): r""" Space of Eisenstein forms for `\Gamma_1(N)`. """ + def _parameters_character(self): r""" Return the character defining ``self``. @@ -540,6 +544,7 @@ class EisensteinSubmodule_eps(EisensteinSubmodule_params): q^4 - 2*zeta3*q^7 + O(q^10), q^5 + (zeta3 + 1)*q^8 + O(q^10)] """ + def _pari_init_(self): """ Conversion to Pari. @@ -554,6 +559,7 @@ def _pari_init_(self): [27, 2, Mod(10, 27), 3, t^2 + t + 1] """ from sage.libs.pari import pari + return pari.mfinit([self.level(), self.weight(), self.character()], 3) # TODO @@ -595,7 +601,7 @@ def cyclotomic_restriction(L, K): """ if not L.has_coerce_map_from(K): M = CyclotomicField(lcm(L.zeta_order(), K.zeta_order())) - f = cyclotomic_restriction_tower(M,K) + f = cyclotomic_restriction_tower(M, K) def g(x): r""" @@ -610,9 +616,9 @@ def g(x): -zeta33^19*x """ return f(M(x)) - return g, euler_phi(M.zeta_order())//euler_phi(K.zeta_order()) - return cyclotomic_restriction_tower(L,K), \ - euler_phi(L.zeta_order())//euler_phi(K.zeta_order()) + + return g, euler_phi(M.zeta_order()) // euler_phi(K.zeta_order()) + return cyclotomic_restriction_tower(L, K), euler_phi(L.zeta_order()) // euler_phi(K.zeta_order()) def cyclotomic_restriction_tower(L, K): @@ -656,4 +662,5 @@ def z(a): zeta11 """ return R(a.polynomial()) % h + return z diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index ce91fbe348d..9f28e9340b5 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -60,10 +60,8 @@ from sage.modular.hecke import element from . import defaults -lazy_import('sage.combinat.integer_vector_weighted', - 'WeightedIntegerVectors') -lazy_import('sage.rings.number_field.number_field_morphisms', - 'NumberFieldEmbedding') +lazy_import('sage.combinat.integer_vector_weighted', 'WeightedIntegerVectors') +lazy_import('sage.rings.number_field.number_field_morphisms', 'NumberFieldEmbedding') def delta_lseries(prec=53, max_imaginary_part=0): @@ -90,8 +88,8 @@ def delta_lseries(prec=53, max_imaginary_part=0): 0.0374412812685155 """ from sage.lfunctions.pari import LFunction, lfun_delta - return LFunction(lfun_delta(), prec=prec, - max_im=max_imaginary_part) + + return LFunction(lfun_delta(), prec=prec, max_im=max_imaginary_part) class ModularForm_abstract(ModuleElement): @@ -101,6 +99,7 @@ class ModularForm_abstract(ModuleElement): instantiate one of the derived classes of this class. """ + def group(self): """ Return the group for which ``self`` is a modular form. @@ -193,11 +192,10 @@ def _pari_init_(self): """ from sage.libs.pari import pari from sage.rings.number_field.number_field_element import NumberFieldElement + M = pari(self.parent()) f = self.qexp(self.parent().sturm_bound()) - coefficients = [ - x.__pari__('t') if isinstance(x, NumberFieldElement) else x - for x in f] + coefficients = [x.__pari__('t') if isinstance(x, NumberFieldElement) else x for x in f] # we cannot compute pari(f) directly because we need to set the variable name as t return M.mflinear(M.mftobasis(coefficients + [0] * (f.prec() - len(coefficients)))) @@ -295,6 +293,7 @@ def __call__(self, x, prec=None): from sage.symbolic.constants import pi from sage.rings.imaginary_unit import I # import from here instead of sage.symbolic.constants to avoid cast to SR from sage.symbolic.expression import Expression + if isinstance(x, Expression): try: x = x.pyobject() @@ -347,6 +346,7 @@ def eval_at_tau(self, tau): from sage.rings.complex_mpfr import ComplexNumber, ComplexField from sage.rings.real_mpfr import RealNumber from sage.symbolic.expression import Expression + if isinstance(tau, Expression): try: tau = tau.pyobject() @@ -407,8 +407,7 @@ def __eq__(self, other): sage: f == loads(dumps(f)) True """ - if not isinstance(other, ModularFormElement) or \ - self.ambient_module() != other.ambient_module(): + if not isinstance(other, ModularFormElement) or self.ambient_module() != other.ambient_module(): return False return self.element() == other.element() @@ -961,18 +960,12 @@ def period(self, M, prec=53): # tau(n) <= sqrt(3)*sqrt(n) for all n >= 1 # This gives a correct but somewhat coarse lower bound on the # number of terms needed. We ignore rounding errors. - numterms = (((1 - mu_dN) * R(2)**(-prec) - / ((abs(eps - 1) + 2) * R(3).sqrt())).log() - / mu_dN.log()).ceil() + numterms = (((1 - mu_dN) * R(2) ** (-prec) / ((abs(eps - 1) + 2) * R(3).sqrt())).log() / mu_dN.log()).ceil() coeff = self.coefficients(numterms) - return sum((coeff[n - 1] / n) - * ((eps - 1) * mu_N ** n - + mu_dN ** n * (mu_d ** (n * b) - eps * mu_d ** (n * c))) - for n in range(1, numterms + 1)) + return sum((coeff[n - 1] / n) * ((eps - 1) * mu_N**n + mu_dN**n * (mu_d ** (n * b) - eps * mu_d ** (n * c))) for n in range(1, numterms + 1)) - def lseries(self, embedding=0, prec=53, max_imaginary_part=0, - max_asymp_coeffs=40): + def lseries(self, embedding=0, prec=53, max_imaginary_part=0, max_asymp_coeffs=40): r""" Return the `L`-series of the weight k cusp form `f` on `\Gamma_0(N)`. @@ -1123,15 +1116,14 @@ def lseries(self, embedding=0, prec=53, max_imaginary_part=0, # get global root number w = self.atkin_lehner_eigenvalue(N, embedding=emb) - e = ~C.gen()**l * w + e = ~C.gen() ** l * w if self.is_cuspidal(): poles = [] # cuspidal else: poles = [l] # non-cuspidal - L = Dokchitser(conductor=N, gammaV=[0, 1], weight=l, eps=e, poles=poles, - prec=prec) + L = Dokchitser(conductor=N, gammaV=[0, 1], weight=l, eps=e, poles=poles, prec=prec) # Find out how many coefficients of the Dirichlet series are needed # in order to compute to the required precision n_coeffs = L.cost() @@ -1145,15 +1137,12 @@ def lseries(self, embedding=0, prec=53, max_imaginary_part=0, v = [emb(c) for c in coeffs] w = [c.conjugate() for c in v] - L.init_coeffs(v=v, w=w, - max_imaginary_part=max_imaginary_part, - max_asymp_coeffs=max_asymp_coeffs) + L.init_coeffs(v=v, w=w, max_imaginary_part=max_imaginary_part, max_asymp_coeffs=max_asymp_coeffs) L.check_functional_equation() if K == QQ: L.rename('L-series associated to the cusp form %s' % self) else: - L.rename('L-series associated to the cusp form %s, %s=%s' - % (self, K.variable_name(), emb(K.gen()))) + L.rename('L-series associated to the cusp form %s, %s=%s' % (self, K.variable_name(), emb(K.gen()))) return L def symsquare_lseries(self, chi=None, embedding=0, prec=53): @@ -1215,6 +1204,7 @@ def symsquare_lseries(self, chi=None, embedding=0, prec=53): Sage library """ from sage.lfunctions.all import Dokchitser + weight = self.weight() C = ComplexField(prec) if self.level() != 1: @@ -1235,15 +1225,13 @@ def symsquare_lseries(self, chi=None, embedding=0, prec=53): else: assert chi.is_primitive() chi = chi.change_ring(C) - eps = chi.gauss_sum()**3 / chi.base_ring()(chi.conductor())**QQ((3, 2)) - N = chi.conductor()**3 + eps = chi.gauss_sum() ** 3 / chi.base_ring()(chi.conductor()) ** QQ((3, 2)) + N = chi.conductor() ** 3 if (chi is None) or chi.is_even(): - L = Dokchitser(N, [0, 1, -weight + 2], 2 * weight - 1, - eps, prec=prec) + L = Dokchitser(N, [0, 1, -weight + 2], 2 * weight - 1, eps, prec=prec) else: - L = Dokchitser(N, [0, 1, -weight + 1], 2 * weight - 1, - eps * C((0, 1)), prec=prec) + L = Dokchitser(N, [0, 1, -weight + 1], 2 * weight - 1, eps * C((0, 1)), prec=prec) lcoeffs_prec = L.cost() t = verbose("Computing %s coefficients of F" % lcoeffs_prec, level=1) @@ -1252,14 +1240,12 @@ def symsquare_lseries(self, chi=None, embedding=0, prec=53): # utility function for Dirichlet convolution of series def dirichlet_convolution(A, B): - return [sum(A[d - 1] * B[n // d - 1] for d in divisors(n)) - for n in range(1, 1 + min(len(A), len(B)))] + return [sum(A[d - 1] * B[n // d - 1] for d in divisors(n)) for n in range(1, 1 + min(len(A), len(B)))] # The Dirichlet series for \zeta(2 s - 2 k + 2) - riemann_series = [n**(weight - 1) if n.is_square() else 0 - for n in xsrange(1, lcoeffs_prec + 1)] + riemann_series = [n ** (weight - 1) if n.is_square() else 0 for n in xsrange(1, lcoeffs_prec + 1)] # The Dirichlet series for 1 / \zeta(s - k + 1) - mu_series = [moebius(n) * n**(weight - 1) for n in xsrange(1, lcoeffs_prec + 1)] + mu_series = [moebius(n) * n ** (weight - 1) for n in xsrange(1, lcoeffs_prec + 1)] conv_series = dirichlet_convolution(mu_series, riemann_series) dirichlet_series = dirichlet_convolution(conv_series, F_series) @@ -1276,8 +1262,7 @@ def dirichlet_convolution(A, B): pari_precode = "hhh(n) = " + str(dirichlet_series) + "[n] * " + pari_precode_chi - L.init_coeffs("hhh(k)", w="conj(hhh(k))", - pari_precode=pari_precode) + L.init_coeffs("hhh(k)", w="conj(hhh(k))", pari_precode=pari_precode) return L @@ -1331,7 +1316,7 @@ def petersson_norm(self, embedding=0, prec=53): pi = RealField(prec).pi() L = self.symsquare_lseries(prec=prec, embedding=embedding) k = self.weight() - return (ZZ(k - 1).factorial() / 2**(2 * k - 1) / pi**(k + 1)) * L(k).real_part() + return (ZZ(k - 1).factorial() / 2 ** (2 * k - 1) / pi ** (k + 1)) * L(k).real_part() def _q_expansion_bound(self, eps): r""" @@ -1375,11 +1360,10 @@ def _q_expansion_bound(self, eps): 182 """ chi = self.character() - M = lcm([self.level(), eps.conductor()**2, - chi.conductor() * eps.conductor()]) + M = lcm([self.level(), eps.conductor() ** 2, chi.conductor() * eps.conductor()]) y = QQ(self.weight()) / QQ(12) * M for p in M.prime_divisors(): - y *= (1 + 1 / QQ(p)) + y *= 1 + 1 / QQ(p) return y.ceil() @cached_method @@ -1523,6 +1507,7 @@ def __init__(self, parent, component, names, check=True): -5*zeta4 - 5 """ from .space import ModularFormsSpace + if check: if not isinstance(parent, ModularFormsSpace): raise TypeError("parent must be a space of modular forms") @@ -1600,10 +1585,10 @@ def __eq__(self, other): sage: f == g True """ - if (not isinstance(other, ModularForm_abstract) or self.weight() != other.weight()): + if not isinstance(other, ModularForm_abstract) or self.weight() != other.weight(): return False if isinstance(other, Newform): - if (self.level() != other.level() or self.character() != other.character()): + if self.level() != other.level() or self.character() != other.character(): return False # The two parents may have different Sturm bounds in case # one of them is a space of cusp forms with character @@ -1611,8 +1596,7 @@ def __eq__(self, other): # other is a space of cusp forms for Gamma1(n). It is # safe to take the smaller bound because we have checked # that the characters agree. - bound = min(self.parent().sturm_bound(), - other.parent().sturm_bound()) + bound = min(self.parent().sturm_bound(), other.parent().sturm_bound()) return self.q_expansion(bound) == other.q_expansion(bound) # other is a ModularFormElement return self.element() == other @@ -1634,6 +1618,7 @@ def abelian_variety(self): TypeError: f must have weight 2 """ from sage.modular.abvar.abvar_newform import ModularAbelianVariety_newform + return ModularAbelianVariety_newform(self) def hecke_eigenvalue_field(self): @@ -1928,7 +1913,7 @@ def _atkin_lehner_eigenvalue_from_qexp(self, Q): M = self.character().conductor() for p, e in Q.factor(): if p.divides(M): # principal series at p - l *= (p**(self.weight() - 2) / self[p])**e + l *= (p ** (self.weight() - 2) / self[p]) ** e else: # special at p l *= -self[p] return l @@ -2235,7 +2220,7 @@ def atkin_lehner_eigenvalue(self, d=None, normalization='analytic', embedding=No d = N // N.prime_to_m_part(d) d1 = d2 = d3 = 1 - for (p, e) in d.factor(): + for p, e in d.factor(): if self[p] == 0: d1 *= p**e elif self.character().conductor().valuation(p) == e: @@ -2273,9 +2258,9 @@ def atkin_lehner_eigenvalue(self, d=None, normalization='analytic', embedding=No raise ValueError("Unable to compute Gauss sum. Try specifying an embedding into a larger ring") else: G = R(1) - if not R(d**(self.weight() - 2)).is_square(): + if not R(d ** (self.weight() - 2)).is_square(): raise ValueError("Unable to compute square root. Try specifying an embedding into a larger ring") - ratio = R(d**(self.weight() - 2)).sqrt() * embedding(self.character()(crt(1, d // d0, d, N // d))) / G + ratio = R(d ** (self.weight() - 2)).sqrt() * embedding(self.character()(crt(1, d // d0, d, N // d))) / G return embedding(w) / ratio def twist(self, chi, level=None, check=True): @@ -2371,6 +2356,7 @@ def twist(self, chi, level=None, check=True): - Peter Bruin (April 2015) """ from sage.modular.all import CuspForms + R = coercion_model.common_parent(self.base_ring(), chi.base_ring()) N = self.level() epsilon = self.character() @@ -2391,13 +2377,12 @@ def twist(self, chi, level=None, check=True): continue if delta > gamma and N_epsilon_chi.valuation(q) == max(alpha, beta): continue - raise NotImplementedError('cannot calculate %s-primary part of the level of the twist of %s by %s' - % (q, self, chi)) + raise NotImplementedError('cannot calculate %s-primary part of the level of the twist of %s by %s' % (q, self, chi)) level = lcm([N, N_epsilon * N_chi, N_chi**2]) # determine the character of the twisted form G = DirichletGroup(lcm([N, chi.modulus(), level]), base_ring=R) - eps_new = (G(epsilon) * G(chi)**2).restrict(level) + eps_new = (G(epsilon) * G(chi) ** 2).restrict(level) # create an ambient space D = ModularSymbols(eps_new, self.weight(), base_ring=R, sign=1).new_submodule() @@ -2470,11 +2455,11 @@ def minimal_twist(self, p=None): # such that self x chi has level N/p^u, where u = r-c, and this # twist is minimal. candidates = [] - for chi in DirichletGroup(p**(r - c), self.base_ring()): + for chi in DirichletGroup(p ** (r - c), self.base_ring()): if not chi.is_primitive(): continue try: - g = self.twist(chi, level=N // p**(r - c)) + g = self.twist(chi, level=N // p ** (r - c)) candidates.append((g, chi)) except ValueError: continue @@ -2493,15 +2478,16 @@ def minimal_twist(self, p=None): # any more. So we use the slow, but very general, type-space # algorithm. from sage.modular.local_comp.type_space import TypeSpace + T = TypeSpace(self, p) if T.is_minimal(): return (self, DirichletGroup(1, self.base_ring())(1)) g = T.minimal_twist() epsg = g.character().extend(N) - chisq = (epsg / self.character()).restrict(p**(r // 2)) + chisq = (epsg / self.character()).restrict(p ** (r // 2)) K = coercion_model.common_parent(self.base_ring(), g.base_ring()) - chis = [chi for chi in DirichletGroup(p**(r // 2), K) if chi**2 == chisq] + chis = [chi for chi in DirichletGroup(p ** (r // 2), K) if chi ** 2 == chisq] if g.has_cm() and g.cm_discriminant().prime_divisors() == [p]: # Quicker to test g than self, because g has smaller level. @@ -2531,6 +2517,7 @@ def local_component(self, p, twist_factor=None): Smooth representation of GL_2(Q_7) with conductor 7^2 """ from sage.modular.local_comp.local_comp import LocalComponent + return LocalComponent(self, p, twist_factor) @@ -2559,6 +2546,7 @@ def __init__(self, parent, x, check=True): Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field """ from .space import ModularFormsSpace + if not isinstance(parent, ModularFormsSpace): raise TypeError("First argument must be an ambient space of modular forms.") element.HeckeModuleElement.__init__(self, parent, x) @@ -2673,15 +2661,13 @@ def __mul__(self, other): # now do the math from .constructor import ModularForms + if newchar is not None: verbose("creating a parent with char") - newparent = ModularForms(newchar, self.weight() + other.weight(), - base_ring=newchar.base_ring()) + newparent = ModularForms(newchar, self.weight() + other.weight(), base_ring=newchar.base_ring()) verbose("parent is %s" % newparent) else: - newparent = ModularForms(self.group(), - self.weight() + other.weight(), - base_ring=ZZ) + newparent = ModularForms(self.group(), self.weight() + other.weight(), base_ring=ZZ) m = newparent.sturm_bound() newqexp = self.qexp(m) * other.qexp(m) @@ -2722,21 +2708,20 @@ def _pow_int(self, n): try: eps = self.character() verbose(f"character of self is {eps}") - newchar = eps ** n + newchar = eps**n verbose(f"character of product is {newchar}") except (NotImplementedError, ValueError): newchar = None verbose("character of product not determined") from .constructor import ModularForms + if newchar is not None: verbose("creating a parent with char") - newparent = ModularForms(newchar, self.weight() * n, - base_ring=newchar.base_ring()) + newparent = ModularForms(newchar, self.weight() * n, base_ring=newchar.base_ring()) verbose(f"parent is {newparent}") else: - newparent = ModularForms(self.group(), self.weight() * n, - base_ring=ZZ) + newparent = ModularForms(self.group(), self.weight() * n, base_ring=ZZ) m = newparent.sturm_bound() newqexp = self.qexp(m) ** n @@ -2871,6 +2856,7 @@ def twist(self, chi, level=None): - Peter Bruin (2015-03-30) """ from sage.modular.all import CuspForms, ModularForms + R = coercion_model.common_parent(self.base_ring(), chi.base_ring()) N = self.level() Q = chi.modulus() @@ -2884,11 +2870,12 @@ def twist(self, chi, level=None): # See [AL1978], Proposition 3.1. level = lcm([N, epsilon.conductor() * Q, Q**2]) G = DirichletGroup(level, base_ring=R) - M = constructor(G(epsilon) * G(chi)**2, self.weight(), base_ring=R) + M = constructor(G(epsilon) * G(chi) ** 2, self.weight(), base_ring=R) else: from sage.modular.arithgroup.congroup_gamma1 import ( Gamma1_constructor as Gamma1, ) + if level is None: # See [AL1978], Proposition 3.1. level = lcm([N, Q]) * Q @@ -2903,6 +2890,7 @@ class ModularFormElement_elliptic_curve(Newform): r""" A modular form attached to an elliptic curve over `\QQ`. """ + def __init__(self, parent, E): """ Modular form attached to an elliptic curve as an element @@ -3038,6 +3026,7 @@ class EisensteinSeries(ModularFormElement): -1/7*zeta6 - 2/7 + q + (2*zeta6 - 1)*q^2 + (-3*zeta6 + 1)*q^3 + O(q^4), q + (zeta6 + 1)*q^2 + (-zeta6 + 3)*q^3 + O(q^4)] """ + def __init__(self, parent, vector, t, chi, psi): """ An Eisenstein series. @@ -3177,8 +3166,7 @@ def __compute_general_case(self, X): v.append(zero) else: m = i // t - v.append(sum([psi(d) * chi(m / d) * d ** (k - 1) - for d in divisors(m)])) + v.append(sum([psi(d) * chi(m / d) * d ** (k - 1) for d in divisors(m)])) return v @cached_method @@ -3360,6 +3348,7 @@ class GradedModularFormElement(ModuleElement): sage: M({4:f, 2:g}) 2 + 12*q + 36*q^2 + 252*q^3 + 84*q^4 + 72*q^5 + O(q^6) """ + def __init__(self, parent, forms_datum): r""" INPUT: @@ -3577,7 +3566,7 @@ def coefficients(self, X): [22812, 36552, 57680, 85686, 126744, 177408, 249246, 332172, 448926, 575736] """ if isinstance(X, (int, Integer)): - return list(self.q_expansion(X + 1))[1:X + 1] + return list(self.q_expansion(X + 1))[1 : X + 1] prec = max(X) v = self.q_expansion(prec + 1) return [v[x] for x in X] @@ -3652,6 +3641,7 @@ def __getitem__(self, weight): if weight < 0: raise ValueError("the weight must be nonnegative") return self._forms_dictionary.get(weight, self.parent().zero()) + homogeneous_component = __getitem__ # alias def __call__(self, x, prec=None): @@ -3886,6 +3876,7 @@ def is_homogeneous(self) -> bool: False """ return len(self._forms_dictionary) <= 1 + is_modular_form = is_homogeneous # alias def _homogeneous_to_polynomial(self, names, gens): @@ -3946,7 +3937,7 @@ def _homogeneous_to_polynomial(self, names, gens): # form the matrix of coefficients and list the monomials of weight k monomial_forms = [prod(M(gen) ** exp for exp, gen in zip(exps, gens)) for exps in W] - monomial_polys = [prod(poly_gen ** exp for exp, poly_gen in zip(exps, poly_parent.gens())) for exps in W] + monomial_polys = [prod(poly_gen**exp for exp, poly_gen in zip(exps, poly_parent.gens())) for exps in W] matrix_datum = M._to_matrix(monomial_forms, prec=sturm_bound) mat = Matrix(matrix_datum).transpose() @@ -4062,5 +4053,6 @@ def derivative(self, name='E2'): False """ from sage.modular.quasimodform.ring import QuasiModularForms + F = QuasiModularForms(self.group(), self.base_ring(), name)(self) return F.derivative() diff --git a/src/sage/modular/modform/half_integral.py b/src/sage/modular/modform/half_integral.py index 45192fd1558..1ad4e46d251 100644 --- a/src/sage/modular/modform/half_integral.py +++ b/src/sage/modular/modform/half_integral.py @@ -122,9 +122,9 @@ def half_integral_weight_modform_basis(chi, k, prec): chi = chi.minimize_base_ring() psi = chi.parent()(DirichletGroup(4, chi.base_ring()).gen()) - eps = chi*psi**((k+1) // 2) + eps = chi * psi ** ((k + 1) // 2) eps = eps.minimize_base_ring() - M = constructor.ModularForms(eps, (k+1)//2) + M = constructor.ModularForms(eps, (k + 1) // 2) C = M.cuspidal_subspace() B = C.basis() @@ -134,18 +134,18 @@ def half_integral_weight_modform_basis(chi, k, prec): T2 = theta2_qexp(prec) T3 = theta_qexp(prec) n = len(S) - MS = MatrixSpace(M.base_ring(), 2*n, prec) + MS = MatrixSpace(M.base_ring(), 2 * n, prec) A = copy(MS.zero_matrix()) for i in range(n): - T2f = T2*S[i] - T3f = T3*S[i] + T2f = T2 * S[i] + T3f = T3 * S[i] for j in range(prec): A[i, j] = T2f[j] - A[n+i, j] = -T3f[j] + A[n + i, j] = -T3f[j] B = A.kernel().basis() - a_vec = [sum([b[i]*S[i] for i in range(n)]) for b in B] + a_vec = [sum([b[i] * S[i] for i in range(n)]) for b in B] if len(a_vec) == 0: return [] R = a_vec[0].parent() diff --git a/src/sage/modular/modform/hecke_operator_on_qexp.py b/src/sage/modular/modform/hecke_operator_on_qexp.py index a7434561cea..6b4cb069f71 100644 --- a/src/sage/modular/modform/hecke_operator_on_qexp.py +++ b/src/sage/modular/modform/hecke_operator_on_qexp.py @@ -27,8 +27,7 @@ from .element import ModularFormElement -def hecke_operator_on_qexp(f, n, k, eps=None, - prec=None, check=True, _return_list=False): +def hecke_operator_on_qexp(f, n, k, eps=None, prec=None, check=True, _return_list=False): r""" Given the `q`-expansion `f` of a modular form with character `\varepsilon`, this function computes the image of `f` under the @@ -100,8 +99,8 @@ def hecke_operator_on_qexp(f, n, k, eps=None, if isinstance(f, ModularFormElement): # always want at least three coefficients, but not too many, unless # requested - pr = max(f.prec(), f.parent().prec(), (n+1)*3) - pr = min(pr, 100*(n+1)) + pr = max(f.prec(), f.parent().prec(), (n + 1) * 3) + pr = min(pr, 100 * (n + 1)) prec = pr // n + 1 else: prec = (f.prec() / ZZ(n)).ceil() @@ -115,12 +114,11 @@ def hecke_operator_on_qexp(f, n, k, eps=None, if k != 1 and p.is_prime() and n.is_power_of(p): # if computing T_{p^a} in characteristic p, use the simpler (and faster) # formula - v = [f[m*n] for m in range(prec)] + v = [f[m * n] for m in range(prec)] else: l = k - 1 for m in range(prec): - am = sum([eps(d) * d**l * f[m*n//(d*d)] - for d in divisors(gcd(n, m)) if (m*n) % (d*d) == 0]) + am = sum([eps(d) * d**l * f[m * n // (d * d)] for d in divisors(gcd(n, m)) if (m * n) % (d * d) == 0]) v.append(am) if _return_list: return v @@ -152,8 +150,7 @@ def _hecke_operator_on_basis(B, V, n, k, eps): ValueError: the given basis vectors must be linearly independent """ prec = V.degree() - TB = [hecke_operator_on_qexp(f, n, k, eps, prec, check=False, _return_list=True) - for f in B] + TB = [hecke_operator_on_qexp(f, n, k, eps, prec, check=False, _return_list=True) for f in B] TB = [V.coordinate_vector(w) for w in TB] return matrix(V.base_ring(), len(B), len(B), TB, sparse=False) @@ -241,6 +238,5 @@ def hecke_operator_on_basis(B, n, k, eps=None, already_echelonized=False): k = Integer(k) prec = (f.prec() - 1) // n A = R**prec - V = A.span_of_basis([g.padded_list(prec) for g in B], - already_echelonized=already_echelonized) + V = A.span_of_basis([g.padded_list(prec) for g in B], already_echelonized=already_echelonized) return _hecke_operator_on_basis(B, V, n, k, eps) diff --git a/src/sage/modular/modform/j_invariant.py b/src/sage/modular/modform/j_invariant.py index 63d1e394836..45762082fc6 100644 --- a/src/sage/modular/modform/j_invariant.py +++ b/src/sage/modular/modform/j_invariant.py @@ -33,9 +33,9 @@ def j_invariant_qexp(prec=10, K=QQ): if prec <= -1: raise ValueError("the prec must be nonnegative.") prec += 2 - g6 = -504*eisenstein_series_qexp(6, prec, K=QQ) + g6 = -504 * eisenstein_series_qexp(6, prec, K=QQ) Delta = delta_qexp(prec).change_ring(QQ) - j = (g6*g6) * (~Delta) + 1728 + j = (g6 * g6) * (~Delta) + 1728 if K != QQ: return j.change_ring(K) return j diff --git a/src/sage/modular/modform/l_series_gross_zagier.py b/src/sage/modular/modform/l_series_gross_zagier.py index d13f96ee5cc..57378356b0e 100644 --- a/src/sage/modular/modform/l_series_gross_zagier.py +++ b/src/sage/modular/modform/l_series_gross_zagier.py @@ -1,6 +1,7 @@ """ Gross-Zagier L-series """ + from sage.lfunctions.pari import lfun_generic, LFunction from sage.modular.dirichlet import kronecker_character from sage.modular.modform.l_series_gross_zagier_coeffs import gross_zagier_L_series @@ -55,15 +56,12 @@ def __init__(self, E, A, prec=53, max_imaginary_part=0) -> None: K = A.gens()[0].parent() D = K.disc() if not (K.degree() == 2 and D < 0): - raise ValueError("A is not an ideal class in an" - " imaginary quadratic field") + raise ValueError("A is not an ideal class in an" " imaginary quadratic field") Q = ideal.quadratic_form().reduced_form() - epsilon = - kronecker_character(D)(N) + epsilon = -kronecker_character(D)(N) # first compute the number of required terms - Lpari = lfun_generic(N**2 * D**2, - [0, 0, 1, 1], - weight=2, eps=epsilon) + Lpari = lfun_generic(N**2 * D**2, [0, 0, 1, 1], weight=2, eps=epsilon) L = LFunction(Lpari, prec=prec, max_im=max_imaginary_part) nterms = Integer(L.cost()) if nterms > 1e6: diff --git a/src/sage/modular/modform/numerical.py b/src/sage/modular/modform/numerical.py index 4787b06ce93..95ae4d31f9e 100644 --- a/src/sage/modular/modform/numerical.py +++ b/src/sage/modular/modform/numerical.py @@ -88,8 +88,8 @@ class NumericalEigenforms(SageObject): [4.0, 2.2360679774997894, -2.236067977499788], [6.0, -3.2360679774997894, 1.2360679774997936]] """ - def __init__(self, group, weight=2, eps=1e-20, - delta=1e-2, tp=[2, 3, 5]): + + def __init__(self, group, weight=2, eps=1e-20, delta=1e-2, tp=[2, 3, 5]): """ Create a new space of numerical eigenforms. @@ -159,8 +159,7 @@ def _repr_(self): sage: n._repr_() 'Numerical Hecke eigenvalues for Congruence Subgroup Gamma0(61) of weight 2' """ - return "Numerical Hecke eigenvalues for %s of weight %s" % ( - self._group, self._weight) + return "Numerical Hecke eigenvalues for %s of weight %s" % (self._group, self._weight) @cached_method def modular_symbols(self): @@ -173,8 +172,7 @@ def modular_symbols(self): sage: n = numerical_eigenforms(61) ; n.modular_symbols() Modular Symbols space of dimension 5 for Gamma_0(61) of weight 2 with sign 1 over Rational Field """ - M = ModularSymbols(self._group, - self._weight, sign=1) + M = ModularSymbols(self._group, self._weight, sign=1) if M.base_ring() != QQ: raise ValueError("modular forms space must be defined over QQ") return M @@ -230,6 +228,7 @@ def _eigenvectors(self): if scipy is None: import scipy import scipy.linalg + evals, eig = scipy.linalg.eig(self._hecke_matrix.numpy(), right=True, left=False) B = matrix(eig) v = [CDF(evals[i]) for i in range(len(evals))] @@ -243,7 +242,7 @@ def _eigenvectors(self): e = v[i] uniq = True for j in range(len(v)): - if uniq and i != j and abs(e-v[j]) < eps: + if uniq and i != j and abs(e - v[j]) < eps: uniq = False if uniq: w.append(i) @@ -279,7 +278,7 @@ def _easy_vector(self): """ E = self._eigenvectors() delta = self._delta - x = (CDF**E.nrows()).zero_vector() + x = (CDF ** E.nrows()).zero_vector() if E.nrows() == 0: return x @@ -311,7 +310,7 @@ def best_row(M): C = E.matrix_from_columns(zp) # best row i, f = best_row(C) - x[i] += 1 # simplistic + x[i] += 1 # simplistic e = x * E self.__easy_vector = x @@ -346,7 +345,7 @@ def phi(y): phi_x = phi(x) V = phi_x.parent() - phi_x_inv = V([a**(-1) for a in phi_x]) + phi_x_inv = V([a ** (-1) for a in phi_x]) eps = self._eps nzp = support(x, eps) x_nzp = vector(CDF, x.list_from_positions(nzp)) @@ -427,8 +426,8 @@ def phi(y): m = self.modular_symbols().ambient_module() for p in primes: t = m._compute_hecke_matrix_prime(p, nzp) - w = phi(x_nzp*t) - ans.append([w[i]*phi_x_inv[i] for i in range(w.degree())]) + w = phi(x_nzp * t) + ans.append([w[i] * phi_x_inv[i] for i in range(w.degree())]) return ans def systems_of_eigenvalues(self, bound): diff --git a/src/sage/modular/modform/ring.py b/src/sage/modular/modform/ring.py index 771bafcdb53..a4395190023 100644 --- a/src/sage/modular/modform/ring.py +++ b/src/sage/modular/modform/ring.py @@ -45,8 +45,7 @@ from .space import ModularFormsSpace -def _span_of_forms_in_weight(forms, weight, prec, - stop_dim=None, use_random=False): +def _span_of_forms_in_weight(forms, weight, prec, stop_dim=None, use_random=False): r""" Utility function. Given a nonempty list of pairs ``(k,f)``, where `k` is an integer and `f` is a power series, and a weight l, return all weight l @@ -111,12 +110,13 @@ def _span_of_forms_in_weight(forms, weight, prec, n = len(forms) R = forms[0][1].base_ring() - V = R ** prec + V = R**prec W = V.zero_submodule() shortforms = [f[1].truncate_powerseries(prec) for f in forms] # List of weights from sage.combinat.integer_vector_weighted import WeightedIntegerVectors + wts = list(WeightedIntegerVectors(weight, [f[0] for f in forms])) t = verbose("calculated weight list", t) N = len(wts) @@ -127,7 +127,7 @@ def _span_of_forms_in_weight(forms, weight, prec, shuffle(wts) for c in range(N): - w = V(prod(shortforms[i]**wts[c][i] for i in range(n)).padded_list(prec)) + w = V(prod(shortforms[i] ** wts[c][i] for i in range(n)).padded_list(prec)) if w in W: continue W = V.span(list(W.gens()) + [w]) @@ -138,8 +138,7 @@ def _span_of_forms_in_weight(forms, weight, prec, verbose("Nothing worked", t) return W - G = [V(prod(forms[i][1]**c[i] for i in range(n)).padded_list(prec)) - for c in wts] + G = [V(prod(forms[i][1] ** c[i] for i in range(n)).padded_list(prec)) for c in wts] t = verbose(f'found {N} candidates', t) W = V.span(G) verbose(f'span has dimension {W.rank()}', t) @@ -383,8 +382,7 @@ def polynomial_ring(self, names, gens=None): if gens is None: gens = self.gen_forms() degs = [f.weight() for f in gens] - return PolynomialRing(self.base_ring(), len(gens), names, - order=TermOrder('wdeglex', degs)) + return PolynomialRing(self.base_ring(), len(gens), names, order=TermOrder('wdeglex', degs)) def _generators_variables_dictionary(self, poly_parent, gens): r""" @@ -410,9 +408,7 @@ def _generators_variables_dictionary(self, poly_parent, gens): nb_var = poly_parent.ngens() nb_gens = self.ngens() if nb_var != nb_gens: - raise ValueError('the number of variables (%s) must be equal to' - ' the number of generators of the modular forms' - ' ring (%s)' % (nb_var, self.ngens())) + raise ValueError('the number of variables (%s) must be equal to' ' the number of generators of the modular forms' ' ring (%s)' % (nb_var, self.ngens())) return {poly_parent.gen(i): self(gens[i]) for i in range(nb_var)} def from_polynomial(self, polynomial, gens=None): @@ -635,8 +631,7 @@ def __richcmp__(self, other, op) -> bool: if not isinstance(other, ModularFormsRing): return NotImplemented - return richcmp((self.group(), self.base_ring()), - (other.group(), other.base_ring()), op) + return richcmp((self.group(), self.base_ring()), (other.group(), other.base_ring()), op) def _repr_(self) -> str: r""" @@ -666,8 +661,7 @@ def modular_forms_of_weight(self, weight): """ return ModularForms(self.group(), weight) - def generators(self, maxweight=8, prec=10, start_gens=[], - start_weight=2) -> list: + def generators(self, maxweight=8, prec=10, start_gens=[], start_weight=2) -> list: r""" Return a list of generators of this ring as a list of pairs `(k, f)` where `k` is an integer and `f` is a univariate power @@ -813,9 +807,7 @@ def generators(self, maxweight=8, prec=10, start_gens=[], for x in start_gens: if len(x) == 2: if x[1].prec() < prec: - raise ValueError("Requested precision cannot be higher" - " than precision of approximate starting " - "generators!") + raise ValueError("Requested precision cannot be higher" " than precision of approximate starting " "generators!") sgs.append((x[0], x[1], None)) else: sgs.append(x) @@ -906,7 +898,7 @@ def _find_generators(self, maxweight, start_gens, start_weight) -> list: (3, 1 + 12*q^2 + 64*q^3 + 60*q^4 + 160*q^6 + 384*q^7 + 252*q^8 + O(q^9), 1 + 12*q^2 + 64*q^3 + 60*q^4 + O(q^6)), (3, q + 4*q^2 + 8*q^3 + 16*q^4 + 26*q^5 + 32*q^6 + 48*q^7 + 64*q^8 + O(q^9), q + 4*q^2 + 8*q^3 + 16*q^4 + 26*q^5 + O(q^6))] """ - default_params = (start_gens == () and start_weight == 2) + default_params = start_gens == () and start_weight == 2 if default_params and self.__cached_maxweight != -1: verbose("Already know generators up to weight %s -- using those" % self.__cached_maxweight) @@ -1085,7 +1077,7 @@ def cuspidal_ideal_generators(self, maxweight=8, prec=None): if self.__cached_cusp_maxweight > -1: k = self.__cached_cusp_maxweight + 1 - verbose("Already calculated cusp gens up to weight %s -- using those" % (k-1)) + verbose("Already calculated cusp gens up to weight %s -- using those" % (k - 1)) # we may need to increase the precision of the cached cusp # generators @@ -1107,13 +1099,12 @@ def cuspidal_ideal_generators(self, maxweight=8, prec=None): for j, f, F in G: for g in self.q_expansion_basis(k - j, prec=kprec): - flist.append(g*f) + flist.append(g * f) A = self.base_ring() ** kprec W = A.span([A(f.padded_list(kprec)) for f in flist]) S = self.modular_forms_of_weight(k).cuspidal_submodule() - if (W.rank() == S.dimension() - and (self.base_ring().is_field() or W.index_in_saturation() == 1)): + if W.rank() == S.dimension() and (self.base_ring().is_field() or W.index_in_saturation() == 1): verbose("Nothing new in weight %s" % k, t) k += 1 continue @@ -1122,7 +1113,7 @@ def cuspidal_ideal_generators(self, maxweight=8, prec=None): B = S.q_integral_basis(prec=working_prec) V = A.span([A(f.change_ring(self.base_ring()).padded_list(kprec)) for f in B]) - Q = V/W + Q = V / W for q in Q.gens(): try: @@ -1201,7 +1192,7 @@ def cuspidal_submodule_q_expansion_basis(self, weight, prec=None): flist = [] for j, f, F in G: for g in self.q_expansion_basis(weight - j, prec=working_prec): - flist.append(g*f) + flist.append(g * f) A = self.base_ring() ** working_prec W = A.span([A(f.padded_list(working_prec)) for f in flist]) diff --git a/src/sage/modular/modform/space.py b/src/sage/modular/modform/space.py index ce30e09b2d4..a6315dfadb8 100644 --- a/src/sage/modular/modform/space.py +++ b/src/sage/modular/modform/space.py @@ -75,8 +75,7 @@ from sage.categories.rings import Rings from sage.structure.all import Sequence -from sage.structure.richcmp import (richcmp_method, richcmp, rich_to_bool, - richcmp_not_equal) +from sage.structure.richcmp import richcmp_method, richcmp, rich_to_bool, richcmp_not_equal from .element import ModularFormElement, Newform from . import defaults @@ -90,6 +89,7 @@ class ModularFormsSpace(hecke.HeckeModule_generic): """ A generic space of modular forms. """ + Element = ModularFormElement def __init__(self, group, weight, character, base_ring, category=None): @@ -349,7 +349,7 @@ def is_ambient(self) -> bool: sage: E.is_ambient() False """ - return False # returning True is defined in the derived AmbientSpace class. + return False # returning True is defined in the derived AmbientSpace class. def __normalize_prec(self, prec): """ @@ -473,8 +473,7 @@ def echelon_basis(self): W = self._q_expansion_module() pr = W.degree() B = self.q_echelon_basis(pr) - E = [self(F.linear_combination_of_basis(W.coordinates(f.padded_list(pr)))) - for f in B] + E = [self(F.linear_combination_of_basis(W.coordinates(f.padded_list(pr)))) for f in B] return Sequence(E, cr=True, immutable=True) @cached_method @@ -540,8 +539,7 @@ def integral_basis(self): W = self._q_expansion_module() pr = W.degree() B = self.q_integral_basis(pr) - I = [self.linear_combination_of_basis( - W.coordinates(f.padded_list(pr))) for f in B] + I = [self.linear_combination_of_basis(W.coordinates(f.padded_list(pr))) for f in B] return Sequence(I, cr=True, immutable=True) @cached_method @@ -565,7 +563,7 @@ def _q_expansion_module(self): """ prec = self.sturm_bound() C = self.q_expansion_basis(prec) - V = self.base_ring()**prec + V = self.base_ring() ** prec return V.span_of_basis([f.padded_list(prec) for f in C]) def q_expansion_basis(self, prec=None): @@ -826,10 +824,9 @@ def __add__(self, right): Modular Forms subspace of dimension 4 of Modular Forms space of dimension 9 for Congruence Subgroup Gamma0(44) of weight 2 over Rational Field """ from sage.modular.modform.submodule import ModularFormsSubmodule + if self.ambient_module() != right.ambient_module(): - raise ArithmeticError(("Sum of %s and %s not defined because " + - "they do not lie in a common ambient space.") % - (self, right)) + raise ArithmeticError(("Sum of %s and %s not defined because " + "they do not lie in a common ambient space.") % (self, right)) if self.is_ambient(): return self if right.is_ambient(): @@ -1021,6 +1018,7 @@ def _element_constructor_(self, x, check=True): if not check: from copy import copy + f = copy(x) f._set_parent(self) return f @@ -1080,6 +1078,7 @@ def _pushout_(self, other): TypeError: unsupported operand parent(s) for +: 'Modular Forms space of dimension 7 for Congruence Subgroup Gamma0(5) of weight 12 over Rational Field' and 'Modular Forms space of dimension 1 for Modular Group SL(2,Z) of weight 4 over Rational Field' """ from .ring import ModularFormsRing + if isinstance(other, ModularFormsSpace): if self.group() == other.group() and self.base_ring() == other.base_ring(): if self.weight() == other.weight(): @@ -1120,10 +1119,8 @@ def __richcmp__(self, x, op): left_ambient = self.ambient() right_ambient = x.ambient() - lx = params(left_ambient.character(), left_ambient.level(), - left_ambient.weight(), left_ambient.base_ring()) - rx = params(right_ambient.character(), right_ambient.level(), - right_ambient.weight(), right_ambient.base_ring()) + lx = params(left_ambient.character(), left_ambient.level(), left_ambient.weight(), left_ambient.base_ring()) + rx = params(right_ambient.character(), right_ambient.level(), right_ambient.weight(), right_ambient.base_ring()) if lx != rx: return richcmp_not_equal(lx, rx, op) if self.is_ambient() or x.is_ambient(): @@ -1156,6 +1153,7 @@ def span_of_basis(self, B): Modular Forms subspace of dimension 5 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field """ from .submodule import ModularFormsSubmoduleWithBasis + W = self._q_expansion_module() F = self.free_module() prec = W.degree() @@ -1205,7 +1203,7 @@ def _compute_hecke_matrix_prime(self, p, prec=None): # Initial guess -- will increase if need be. # We add on a few dimensions, so we are likely to # detect non-invariant subspaces (if they accidentally occur). - prec = p*self.dimension() + 8 + prec = p * self.dimension() + 8 try: cur, _ = self.__q_expansion_basis except AttributeError: @@ -1217,8 +1215,7 @@ def _compute_hecke_matrix_prime(self, p, prec=None): if eps is None: raise NotImplementedError try: - return hecke_operator_on_qexp.hecke_operator_on_basis(B, p, - self.weight(), eps, already_echelonized=False) + return hecke_operator_on_qexp.hecke_operator_on_basis(B, p, self.weight(), eps, already_echelonized=False) except ValueError: # Double the precision. return self._compute_hecke_matrix_prime(p, prec=2 * prec + 1) @@ -1290,9 +1287,7 @@ def basis(self): [q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6), 1 + 12/5*q + 36/5*q^2 + 48/5*q^3 + 84/5*q^4 + 72/5*q^5 + O(q^6)] """ - return Sequence([self.element_class(self, x) - for x in self.free_module().basis()], - immutable=True, cr=True) + return Sequence([self.element_class(self, x) for x in self.free_module().basis()], immutable=True, cr=True) def gen(self, n): """ @@ -1406,13 +1401,15 @@ def sturm_bound(self, M=None): if self.__sturm_bound is None: G = self.group() from sage.modular.arithgroup.congroup_gamma1 import Gamma1_class + if isinstance(G, Gamma1_class) and self.character() is not None: from sage.modular.arithgroup.congroup_gamma0 import ( Gamma0_constructor as Gamma0, ) + G = Gamma0(self.level()) # the +1 below is because O(q^prec) has precision prec. - self.__sturm_bound = G.sturm_bound(self.weight())+1 + self.__sturm_bound = G.sturm_bound(self.weight()) + 1 return self.__sturm_bound def cuspidal_submodule(self): @@ -1496,7 +1493,7 @@ def is_cuspidal(self) -> bool: sage: M.cuspidal_submodule().is_cuspidal() True """ - return (self.cuspidal_submodule() == self) + return self.cuspidal_submodule() == self @cached_method def is_eisenstein(self) -> bool: @@ -1511,7 +1508,7 @@ def is_eisenstein(self) -> bool: sage: M.eisenstein_submodule().is_eisenstein() True """ - return (self.eisenstein_submodule() == self) + return self.eisenstein_submodule() == self def new_submodule(self, p=None): """ @@ -1612,8 +1609,7 @@ def newforms(self, names=None): # In this case, we don't need a variable name, so insert # something to get passed along below names = 'a' - return [Newform(self, factors[i], names=names + str(i)) - for i in range(len(factors))] + return [Newform(self, factors[i], names=names + str(i)) for i in range(len(factors))] @cached_method def eisenstein_submodule(self): @@ -1645,7 +1641,7 @@ def eisenstein_submodule(self): else: assert E.dimension() == self.dimension() self.is_eisenstein.set_cache(True) - E.__is_cuspidal = (E.dimension() == 0) + E.__is_cuspidal = E.dimension() == 0 E.is_eisenstein.set_cache(True) return E @@ -1678,45 +1674,45 @@ def embedded_submodule(self): """ return self.free_module() -# intersect method commented out since it is a duplicate of the intersection method in sage.modular.hecke.submodule -# -- David Loeffler, 2009-04-30 -# -# def intersect(self, right): -# """ -# If self and right live in the same ambient module, return the -# intersection of self and right (as submodules). -# -# EXAMPLES:: -# -# sage: N = ModularForms(6,4); S = N.cuspidal_subspace() -# -# :: -# -# sage: N.intersect(S) -# Modular Forms subspace of dimension 1 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field -# -# :: -# -# sage: S.intersect(N) -# Modular Forms subspace of dimension 1 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field -# -# :: -# -# sage: S.intersect(N.eisenstein_subspace()) -# Modular Forms subspace of dimension 0 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field -# """ -# from sage.modular.modform.all import ModularForms -# if self.ambient_module() != right.ambient_module(): -# raise ArithmeticError("Intersection of %s and %s not defined." % -# (self, right)) -# V = self.embedded_submodule().intersection(right.embedded_submodule()) -# return ModularForms(self.ambient_module(),V) -# return self.span([ self(b) for b in V.basis() ]) - -# def _key(self): -# if self.is_ambient(): -# return self.__key -# return self.__ambient + # intersect method commented out since it is a duplicate of the intersection method in sage.modular.hecke.submodule + # -- David Loeffler, 2009-04-30 + # + # def intersect(self, right): + # """ + # If self and right live in the same ambient module, return the + # intersection of self and right (as submodules). + # + # EXAMPLES:: + # + # sage: N = ModularForms(6,4); S = N.cuspidal_subspace() + # + # :: + # + # sage: N.intersect(S) + # Modular Forms subspace of dimension 1 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field + # + # :: + # + # sage: S.intersect(N) + # Modular Forms subspace of dimension 1 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field + # + # :: + # + # sage: S.intersect(N.eisenstein_subspace()) + # Modular Forms subspace of dimension 0 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(6) of weight 4 over Rational Field + # """ + # from sage.modular.modform.all import ModularForms + # if self.ambient_module() != right.ambient_module(): + # raise ArithmeticError("Intersection of %s and %s not defined." % + # (self, right)) + # V = self.embedded_submodule().intersection(right.embedded_submodule()) + # return ModularForms(self.ambient_module(),V) + # return self.span([ self(b) for b in V.basis() ]) + + # def _key(self): + # if self.is_ambient(): + # return self.__key + # return self.__ambient def level(self): """ @@ -1803,7 +1799,7 @@ def find_in_space(self, f, forms=None, prec=None, indep=True): n = forms[0].parent().prec() else: n = prec - V = self.base_ring()**n + V = self.base_ring() ** n w = [V(g.padded_list(n)) for g in forms] if indep: B = V.span_of_basis(w) diff --git a/src/sage/modular/modform/submodule.py b/src/sage/modular/modform/submodule.py index 992b7ed6231..f16cb8a0287 100644 --- a/src/sage/modular/modform/submodule.py +++ b/src/sage/modular/modform/submodule.py @@ -30,11 +30,11 @@ import sage.modular.hecke.submodule -class ModularFormsSubmodule(ModularFormsSpace, - sage.modular.hecke.submodule.HeckeSubmodule): +class ModularFormsSubmodule(ModularFormsSpace, sage.modular.hecke.submodule.HeckeSubmodule): """ A submodule of an ambient space of modular forms. """ + def __init__(self, ambient_module, submodule, dual=None, check=False): """ INPUT: @@ -54,8 +54,7 @@ def __init__(self, ambient_module, submodule, dual=None, check=False): """ A = ambient_module sage.modular.hecke.submodule.HeckeSubmodule.__init__(self, A, submodule, check=check) - ModularFormsSpace.__init__(self, A.group(), A.weight(), - A.character(), A.base_ring()) + ModularFormsSpace.__init__(self, A.group(), A.weight(), A.character(), A.base_ring()) def _repr_(self): """ @@ -108,8 +107,7 @@ def _compute_q_expansion_basis(self, prec): O(q^5)] """ A = self.ambient_module() - return [A._q_expansion(element=f.element(), prec=prec) - for f in self.basis()] + return [A._q_expansion(element=f.element(), prec=prec) for f in self.basis()] # TODO diff --git a/src/sage/modular/modform/theta.py b/src/sage/modular/modform/theta.py index fbe34473f98..aae81b16760 100644 --- a/src/sage/modular/modform/theta.py +++ b/src/sage/modular/modform/theta.py @@ -5,6 +5,7 @@ - William Stein """ + from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.power_series_ring import PowerSeriesRing @@ -52,10 +53,10 @@ def theta2_qexp(prec=10, var='q', K=ZZ, sparse=False): v = [Integer(0)] * prec one = Integer(1) n = int(sqrt(prec)) - if n*n < prec: + if n * n < prec: n += 1 for m in range(1, n, 2): - v[m*m] = one + v[m * m] = one R = PowerSeriesRing(K, sparse=sparse, names=var) return R(v, prec=prec) @@ -100,10 +101,10 @@ def theta_qexp(prec=10, var='q', K=ZZ, sparse=False): v[0] = Integer(1) two = Integer(2) n = int(sqrt(prec)) - if n*n != prec: + if n * n != prec: n += 1 for m in range(1, n): - v[m*m] = two + v[m * m] = two R = PowerSeriesRing(K, sparse=sparse, names=var) return R(v, prec=prec) diff --git a/src/sage/modular/modform/vm_basis.py b/src/sage/modular/modform/vm_basis.py index 402e56cfbe8..b99a3fd887b 100644 --- a/src/sage/modular/modform/vm_basis.py +++ b/src/sage/modular/modform/vm_basis.py @@ -113,11 +113,11 @@ def victor_miller_basis(k, prec=10, cusp_only=False, var='q'): if k < 0: raise ValueError("k must be nonnegative") elif k == 0: - return Sequence([PowerSeriesRing(ZZ,var)(1).add_bigoh(prec)], cr=True) + return Sequence([PowerSeriesRing(ZZ, var)(1).add_bigoh(prec)], cr=True) e = k.mod(12) if e == 2: e += 12 - n = (k-e) // 12 + n = (k - e) // 12 if n == 0 and cusp_only: return Sequence([]) @@ -126,14 +126,14 @@ def victor_miller_basis(k, prec=10, cusp_only=False, var='q'): # cusp forms, which is just n, then we know the answer, and we # simply return it. if prec <= n: - q = PowerSeriesRing(ZZ,var).gen(0) + q = PowerSeriesRing(ZZ, var).gen(0) err = bigO(q**prec) - ls = [0] * (n+1) + ls = [0] * (n + 1) if not cusp_only: ls[0] = 1 + err - for i in range(1,prec): + for i in range(1, prec): ls[i] = q**i + err - for i in range(prec,n+1): + for i in range(prec, n + 1): ls[i] = err return Sequence(ls, cr=True) @@ -156,7 +156,7 @@ def victor_miller_basis(k, prec=10, cusp_only=False, var='q'): A = -A if n == 0: - return Sequence([PowerSeriesRing(ZZ,var)(A.list()).add_bigoh(prec)],cr=True) + return Sequence([PowerSeriesRing(ZZ, var)(A.list()).add_bigoh(prec)], cr=True) F6_squared = F6**2 F6_squared._unsafe_mutate_truncate(prec) @@ -170,9 +170,9 @@ def victor_miller_basis(k, prec=10, cusp_only=False, var='q'): ls = [A] * (n + 1) for i in range(1, n + 1): - ls[n-i] *= Fprod + ls[n - i] *= Fprod ls[i] *= Dprod - ls[n-i]._unsafe_mutate_truncate(prec) + ls[n - i]._unsafe_mutate_truncate(prec) ls[i]._unsafe_mutate_truncate(prec) Fprod *= F6_squared @@ -184,7 +184,7 @@ def victor_miller_basis(k, prec=10, cusp_only=False, var='q'): if cusp_only: for i in range(1, n + 1): for j in range(1, i): - ls[j] = ls[j] - ls[j][i]*ls[i] + ls[j] = ls[j] - ls[j][i] * ls[i] return Sequence([P(l.list()).add_bigoh(prec) for l in ls[1:]], cr=True) @@ -226,13 +226,12 @@ def _delta_poly(prec=10): # First compute F^2 directly by naive polynomial multiplication, # since F is very sparse. - stop = int((-1+math.sqrt(1+8*prec))/2.0) + stop = int((-1 + math.sqrt(1 + 8 * prec)) / 2.0) # make list of index/value pairs for the sparse poly - values = [(n*(n+1)//2, ((-2*n-1) if (n & 1) else (2*n+1))) - for n in range(stop + 1)] + values = [(n * (n + 1) // 2, ((-2 * n - 1) if (n & 1) else (2 * n + 1))) for n in range(stop + 1)] - for (i1, v1) in values: - for (i2, v2) in values: + for i1, v1 in values: + for i2, v2 in values: try: v[i1 + i2] += v1 * v2 except IndexError: @@ -284,10 +283,10 @@ def _delta_poly_modulo(N, prec=10): # Let F = \sum_{n >= 0} (-1)^n (2n+1) q^(floor(n(n+1)/2)). # Then delta is F^8. - stop = int((-1+math.sqrt(8*prec))/2.0) + stop = int((-1 + math.sqrt(8 * prec)) / 2.0) - for n in range(stop+1): - v[n*(n+1)//2] = ((N-1)*(2*n+1) if (n & 1) else (2*n+1)) + for n in range(stop + 1): + v[n * (n + 1) // 2] = (N - 1) * (2 * n + 1) if (n & 1) else (2 * n + 1) P = PolynomialRing(Integers(N), 'q') f = P(v) diff --git a/src/sage/modular/modform/weight1.py b/src/sage/modular/modform/weight1.py index 27a949cd020..338246b3840 100644 --- a/src/sage/modular/modform/weight1.py +++ b/src/sage/modular/modform/weight1.py @@ -95,6 +95,7 @@ def modular_ratio_to_prec(chi, qexp, prec): if prec <= qexp.prec(): return qexp.add_bigoh(prec) from sage.modular.modform.constructor import EisensteinForms, CuspForms + C = CuspForms(chi.level(), 2, base_ring=qexp.base_ring()) B = EisensteinForms(~chi, 1).gen(0).qexp(prec) qexp = qexp.add_bigoh(C.sturm_bound()) @@ -132,6 +133,7 @@ def hecke_stable_subspace(chi, aux_prime=ZZ(2)): pass from sage.modular.modform.constructor import EisensteinForms + chi = chi.minimize_base_ring() K = chi.base_ring() diff --git a/src/sage/modular/modform_hecketriangle/abstract_ring.py b/src/sage/modular/modform_hecketriangle/abstract_ring.py index 5fc8c770655..377c56a6e11 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_ring.py +++ b/src/sage/modular/modform_hecketriangle/abstract_ring.py @@ -39,9 +39,11 @@ class FormsRing_abstract(Parent): """ from .graded_ring_element import FormsRingElement + Element = FormsRingElement from .analytic_type import AnalyticType + AT = AnalyticType() def __init__(self, group, base_ring, red_hom, n): @@ -159,17 +161,14 @@ def _element_constructor_(self, el): """ from .graded_ring_element import FormsRingElement + if isinstance(el, FormsRingElement): if self.hecke_n() == infinity and el.hecke_n() == ZZ(3): el_f = el._reduce_d()._rat x, y, z, d = self.pol_ring().gens() - num_sub = el_f.numerator().subs(x=(y**2 + 3*x)/ZZ(4), - y=(9*x*y - y**3)/ZZ(8), - z=(3*z - y)/ZZ(2)) - denom_sub = el_f.denominator().subs(x=(y**2 + 3*x)/ZZ(4), - y=(9*x*y - y**3)/ZZ(8), - z=(3*z - y)/ZZ(2)) + num_sub = el_f.numerator().subs(x=(y**2 + 3 * x) / ZZ(4), y=(9 * x * y - y**3) / ZZ(8), z=(3 * z - y) / ZZ(2)) + denom_sub = el_f.denominator().subs(x=(y**2 + 3 * x) / ZZ(4), y=(9 * x * y - y**3) / ZZ(8), z=(3 * z - y) / ZZ(2)) new_num = num_sub.numerator() * denom_sub.denominator() new_denom = denom_sub.numerator() * num_sub.denominator() @@ -221,10 +220,8 @@ def _coerce_map_from_(self, S): """ from .space import FormsSpace_abstract from .functors import _common_subgroup - if (isinstance(S, FormsRing_abstract) - and self._group == _common_subgroup(self._group, S._group) - and self._analytic_type >= S._analytic_type - and self.base_ring().has_coerce_map_from(S.base_ring())): + + if isinstance(S, FormsRing_abstract) and self._group == _common_subgroup(self._group, S._group) and self._analytic_type >= S._analytic_type and self.base_ring().has_coerce_map_from(S.base_ring()): return True if isinstance(S, FormsRing_abstract): return False @@ -504,7 +501,7 @@ def contains_coeff_ring(self): True """ - return (self.AT("holo") <= self._analytic_type) + return self.AT("holo") <= self._analytic_type def construction(self): r""" @@ -518,6 +515,7 @@ def construction(self): """ from .functors import FormsRingFunctor, BaseFacade + return FormsRingFunctor(self._analytic_type, self._group, self._red_hom), BaseFacade(self._base_ring) @cached_method @@ -776,9 +774,7 @@ def diff_alg(self): # to define the operators over ZZ resp. QQ. free_alg = FreeAlgebra(QQ, 6, 'X,Y,Z,dX,dY,dZ') X, Y, Z, dX, dY, dZ = free_alg.gens() - return free_alg.g_algebra({dX * X: 1 + X * dX, - dY * Y: 1 + Y * dY, - dZ * Z: 1 + Z * dZ}) + return free_alg.g_algebra({dX * X: 1 + X * dX, dY * Y: 1 + Y * dY, dZ * Z: 1 + Z * dZ}) @cached_method def _derivative_op(self): @@ -798,12 +794,9 @@ def _derivative_op(self): X, Y, Z, dX, dY, dZ = self.diff_alg().gens() if self.hecke_n() == infinity: - return (X*Z-X*Y) * dX + ZZ(1) / 2 * (Y*Z-X) * dY \ - + ZZ(1) / 4 * (Z**2-X) * dZ + return (X * Z - X * Y) * dX + ZZ(1) / 2 * (Y * Z - X) * dY + ZZ(1) / 4 * (Z**2 - X) * dZ - return 1/self._group.n() * (X*Z-Y) * dX \ - + ZZ(1) / 2 * (Y*Z-X**(self._group.n()-1)) * dY \ - + (self._group.n()-2) / (4*self._group.n()) * (Z**2-X**(self._group.n()-2)) * dZ + return 1 / self._group.n() * (X * Z - Y) * dX + ZZ(1) / 2 * (Y * Z - X ** (self._group.n() - 1)) * dY + (self._group.n() - 2) / (4 * self._group.n()) * (Z**2 - X ** (self._group.n() - 2)) * dZ @cached_method def _serre_derivative_op(self): @@ -823,12 +816,9 @@ def _serre_derivative_op(self): X, Y, Z, dX, dY, dZ = self.diff_alg().gens() if self.hecke_n() == infinity: - return - X * Y * dX - ZZ(1) / 2 * X * dY \ - - ZZ(1) / 4 * (Z**2+X) * dZ + return -X * Y * dX - ZZ(1) / 2 * X * dY - ZZ(1) / 4 * (Z**2 + X) * dZ - return - 1/self._group.n() * Y*dX \ - - ZZ(1) / 2 * X**(self._group.n()-1) * dY \ - - (self._group.n()-2) / (4*self._group.n()) * (Z**2+X**(self._group.n()-2)) * dZ + return -1 / self._group.n() * Y * dX - ZZ(1) / 2 * X ** (self._group.n() - 1) * dY - (self._group.n() - 2) / (4 * self._group.n()) * (Z**2 + X ** (self._group.n() - 2)) * dZ @cached_method def has_reduce_hom(self) -> bool: @@ -912,7 +902,7 @@ def is_weakly_holomorphic(self) -> bool: sage: CuspForms(n=7, k=12, base_ring=AA).is_weakly_holomorphic() True """ - return (self.AT("weak", "quasi") >= self._analytic_type) + return self.AT("weak", "quasi") >= self._analytic_type def is_holomorphic(self) -> bool: r""" @@ -933,7 +923,7 @@ def is_holomorphic(self) -> bool: sage: CuspForms(n=7, k=12, base_ring=AA).is_holomorphic() True """ - return (self.AT("holo", "quasi") >= self._analytic_type) + return self.AT("holo", "quasi") >= self._analytic_type def is_cuspidal(self) -> bool: r""" @@ -953,7 +943,7 @@ def is_cuspidal(self) -> bool: sage: QuasiCuspForms(k=12).is_cuspidal() True """ - return (self.AT("cusp", "quasi") >= self._analytic_type) + return self.AT("cusp", "quasi") >= self._analytic_type def is_zerospace(self) -> bool: r""" @@ -971,7 +961,7 @@ def is_zerospace(self) -> bool: sage: CuspForms(k=12).reduce_type([]).is_zerospace() True """ - return (self.AT(["quasi"]) >= self._analytic_type) + return self.AT(["quasi"]) >= self._analytic_type def analytic_type(self): r""" @@ -1072,8 +1062,8 @@ def J_inv(self): x, y, z, d = self._pol_ring.gens() if self.hecke_n() == infinity: - return self.extend_type("weak", ring=True)(x/(x-y**2)).reduce() - return self.extend_type("weak", ring=True)(x**self._group.n()/(x**self._group.n()-y**2)).reduce() + return self.extend_type("weak", ring=True)(x / (x - y**2)).reduce() + return self.extend_type("weak", ring=True)(x ** self._group.n() / (x ** self._group.n() - y**2)).reduce() @cached_method def j_inv(self): @@ -1122,8 +1112,8 @@ def j_inv(self): x, y, z, d = self._pol_ring.gens() if self.hecke_n() == infinity: - return self.extend_type("weak", ring=True)(1/d*x/(x-y**2)).reduce() - return self.extend_type("weak", ring=True)(1/d*x**self._group.n()/(x**self._group.n()-y**2)).reduce() + return self.extend_type("weak", ring=True)(1 / d * x / (x - y**2)).reduce() + return self.extend_type("weak", ring=True)(1 / d * x ** self._group.n() / (x ** self._group.n() - y**2)).reduce() @cached_method def f_rho(self): @@ -1332,8 +1322,8 @@ def f_inf(self): x, y, z, d = self._pol_ring.gens() if self.hecke_n() == infinity: - return self.extend_type("holo", ring=True)(d*(x-y**2)).reduce() - return self.extend_type("cusp", ring=True)(d*(x**self._group.n()-y**2)).reduce() + return self.extend_type("holo", ring=True)(d * (x - y**2)).reduce() + return self.extend_type("cusp", ring=True)(d * (x ** self._group.n() - y**2)).reduce() @cached_method def G_inv(self): @@ -1410,7 +1400,7 @@ def G_inv(self): if self.hecke_n() == infinity: raise ArithmeticError("G_inv doesn't exist for n={} (it is not meromorphic at -1).".format(self._group.n())) elif ZZ(2).divides(self._group.n()): - return self.extend_type("weak", ring=True)(d*y*x**(self._group.n()/ZZ(2))/(x**self._group.n()-y**2)).reduce() + return self.extend_type("weak", ring=True)(d * y * x ** (self._group.n() / ZZ(2)) / (x ** self._group.n() - y**2)).reduce() else: raise ArithmeticError("G_inv doesn't exist for odd n(={}).".format(self._group.n())) @@ -1481,7 +1471,7 @@ def g_inv(self): raise ArithmeticError("g_inv doesn't exist for n={} (it is not meromorphic at -1).".format(self._group.n())) if ZZ(2).divides(self._group.n()): x, y, z, d = self._pol_ring.gens() - return self.extend_type("weak", ring=True)(1/d*y*x**(self._group.n()/ZZ(2))/(x**self._group.n()-y**2)).reduce() + return self.extend_type("weak", ring=True)(1 / d * y * x ** (self._group.n() / ZZ(2)) / (x ** self._group.n() - y**2)).reduce() raise ArithmeticError("g_inv doesn't exist for odd n(={}).".format(self._group.n())) @cached_method @@ -1555,7 +1545,7 @@ def E4(self): if self.hecke_n() == infinity: return self.extend_type("holo", ring=True)(x).reduce() - return self.extend_type("holo", ring=True)(x**(self._group.n()-2)).reduce() + return self.extend_type("holo", ring=True)(x ** (self._group.n() - 2)).reduce() @cached_method def E6(self): @@ -1619,8 +1609,8 @@ def E6(self): x, y, z, d = self._pol_ring.gens() if self.hecke_n() == infinity: - return self.extend_type("holo", ring=True)(x*y).reduce() - return self.extend_type("holo", ring=True)(x**(self._group.n()-3)*y).reduce() + return self.extend_type("holo", ring=True)(x * y).reduce() + return self.extend_type("holo", ring=True)(x ** (self._group.n() - 3) * y).reduce() @cached_method def Delta(self): @@ -1690,8 +1680,8 @@ def Delta(self): x, y, z, d = self._pol_ring.gens() if self.hecke_n() == infinity: - return self.extend_type("cusp", ring=True)(d*x**2*(x-y**2)).reduce() - return self.extend_type("cusp", ring=True)(d*x**(2*self._group.n()-6)*(x**self._group.n()-y**2)).reduce() + return self.extend_type("cusp", ring=True)(d * x**2 * (x - y**2)).reduce() + return self.extend_type("cusp", ring=True)(d * x ** (2 * self._group.n() - 6) * (x ** self._group.n() - y**2)).reduce() @cached_method def E2(self): @@ -1859,7 +1849,7 @@ def EisensteinSeries(self, k=None): k = self.weight() if k < 0: raise TypeError(None) - k = 2*ZZ(k/2) + k = 2 * ZZ(k / 2) # if self.ep() != ZZ(-1)**ZZ(k/2): # raise TypeError except TypeError: @@ -1868,7 +1858,7 @@ def EisensteinSeries(self, k=None): try: if k < 0: raise TypeError(None) - k = 2*ZZ(k/2) + k = 2 * ZZ(k / 2) except TypeError: raise TypeError("k={} must be a nonnegative even integer!".format(k)) @@ -1890,18 +1880,18 @@ def EisensteinSeries(self, k=None): return self.E6() # Basic variables - ep = (-ZZ(1))**(k/2) + ep = (-ZZ(1)) ** (k / 2) extended_self = self.extend_type(["holo"], ring=True) # reduced_self is a classical ModularForms space reduced_self = extended_self.reduce_type(["holo"], degree=(QQ(k), ep)) if n == infinity: l2 = ZZ.zero() - l1 = ZZ((k-(1-ep)) / ZZ(4)) + l1 = ZZ((k - (1 - ep)) / ZZ(4)) else: - num = ZZ((k-(1-ep)*n/(n-2)) * (n-2) / ZZ(4)) + num = ZZ((k - (1 - ep) * n / (n - 2)) * (n - 2) / ZZ(4)) l2 = num % n - l1 = ((num-l2)/n).numerator() + l1 = ((num - l2) / n).numerator() # If the space is one dimensional we return the normalized generator if l1 == 0: @@ -1918,6 +1908,6 @@ def EisensteinSeries(self, k=None): MFC = MFSeriesConstructor(group=self.group(), prec=prec) d = self.get_d() q = self.get_q() - q_series = MFC.EisensteinSeries_ZZ(k=k)(q/d) + q_series = MFC.EisensteinSeries_ZZ(k=k)(q / d) return extended_self(reduced_self.construct_form(q_series, check=False)).reduce() diff --git a/src/sage/modular/modform_hecketriangle/abstract_space.py b/src/sage/modular/modform_hecketriangle/abstract_space.py index 6482579905f..7b19b00c918 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_space.py +++ b/src/sage/modular/modform_hecketriangle/abstract_space.py @@ -44,6 +44,7 @@ class FormsSpace_abstract(FormsRing_abstract): """ from .element import FormsElement + Element = FormsElement def __init__(self, group, base_ring, k, ep, n): @@ -231,15 +232,16 @@ def _element_constructor_(self, el): """ from .graded_ring_element import FormsRingElement + if isinstance(el, FormsRingElement): - if (self.hecke_n() == infinity and el.hecke_n() == ZZ(3)): + if self.hecke_n() == infinity and el.hecke_n() == ZZ(3): el_f = el._reduce_d()._rat - (x,y,z,d) = self.pol_ring().gens() + (x, y, z, d) = self.pol_ring().gens() - num_sub = el_f.numerator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)) - denom_sub = el_f.denominator().subs( x=(y**2 + 3*x)/ZZ(4), y=(9*x*y - y**3)/ZZ(8), z=(3*z - y)/ZZ(2)) - new_num = num_sub.numerator()*denom_sub.denominator() - new_denom = denom_sub.numerator()*num_sub.denominator() + num_sub = el_f.numerator().subs(x=(y**2 + 3 * x) / ZZ(4), y=(9 * x * y - y**3) / ZZ(8), z=(3 * z - y) / ZZ(2)) + denom_sub = el_f.denominator().subs(x=(y**2 + 3 * x) / ZZ(4), y=(9 * x * y - y**3) / ZZ(8), z=(3 * z - y) / ZZ(2)) + new_num = num_sub.numerator() * denom_sub.denominator() + new_denom = denom_sub.numerator() * num_sub.denominator() el = self._rat_field(new_num) / self._rat_field(new_denom) elif self.group() == el.group(): @@ -253,8 +255,7 @@ def _element_constructor_(self, el): # can be changed in construct_form # resp. construct_quasi_form)) P = parent(el) - if isinstance(P, (LaurentSeriesRing, PowerSeriesRing_generic, - LazyLaurentSeriesRing, LazyPowerSeriesRing)): + if isinstance(P, (LaurentSeriesRing, PowerSeriesRing_generic, LazyLaurentSeriesRing, LazyPowerSeriesRing)): if self.is_modular(): return self.construct_form(el) return self.construct_quasi_form(el) @@ -318,22 +319,17 @@ def _coerce_map_from_(self, S): """ from .space import ZeroForm from .subspace import SubSpaceForms + if isinstance(S, ZeroForm): return True - if (isinstance(S, SubSpaceForms) - and isinstance(self, SubSpaceForms)): - if (self.ambient_space().has_coerce_map_from(S.ambient_space())): + if isinstance(S, SubSpaceForms) and isinstance(self, SubSpaceForms): + if self.ambient_space().has_coerce_map_from(S.ambient_space()): S2 = S.change_ambient_space(self.ambient_space()) return self.module().has_coerce_map_from(S2.module()) return False - if (isinstance(S, FormsSpace_abstract) - and self.graded_ring().has_coerce_map_from(S.graded_ring()) - and S.weight() == self._weight - and S.ep() == self._ep - and not isinstance(self, SubSpaceForms)): + if isinstance(S, FormsSpace_abstract) and self.graded_ring().has_coerce_map_from(S.graded_ring()) and S.weight() == self._weight and S.ep() == self._ep and not isinstance(self, SubSpaceForms): return True - return self.contains_coeff_ring() \ - and self.coeff_ring().has_coerce_map_from(S) + return self.contains_coeff_ring() and self.coeff_ring().has_coerce_map_from(S) # Since forms spaces are modules instead of rings # we have to manually define one(). @@ -446,6 +442,7 @@ def subspace(self, basis): """ from .subspace import SubSpaceForms + return SubSpaceForms(self, basis) def change_ring(self, new_base_ring): @@ -479,9 +476,10 @@ def construction(self): """ from .functors import FormsSubSpaceFunctor, FormsSpaceFunctor, BaseFacade + ambient_space_functor = FormsSpaceFunctor(self._analytic_type, self._group, self._weight, self._ep) - if (self.is_ambient()): + if self.is_ambient(): return (ambient_space_functor, BaseFacade(self._base_ring)) return (FormsSubSpaceFunctor(ambient_space_functor, self._basis), BaseFacade(self._base_ring)) @@ -527,7 +525,7 @@ def contains_coeff_ring(self): False """ - return ((self.AT("holo") <= self._analytic_type) and (self.weight() == QQ(0)) and (self.ep() == ZZ(1))) + return (self.AT("holo") <= self._analytic_type) and (self.weight() == QQ(0)) and (self.ep() == ZZ(1)) def element_from_coordinates(self, vec): r""" @@ -621,7 +619,7 @@ def homogeneous_part(self, k, ep): ValueError: QuasiMeromorphicModularForms(n=6, k=4, ep=1) over Integer Ring already is homogeneous with degree (4, 1) != (5, 1)! """ - if (k == self._weight and ep == self._ep): + if k == self._weight and ep == self._ep: return self raise ValueError("{} already is homogeneous with degree ({}, {}) != ({}, {})!".format(self, self._weight, self._ep, k, ep)) @@ -672,13 +670,13 @@ def weight_parameters(self): n = self._group.n() k = self._weight ep = self._ep - if (n == infinity): - num = (k-(1-ep)) / ZZ(4) + if n == infinity: + num = (k - (1 - ep)) / ZZ(4) else: - num = (k-(1-ep)*ZZ(n)/ZZ(n-2)) * ZZ(n-2) / ZZ(4) - if (num.is_integral()): + num = (k - (1 - ep) * ZZ(n) / ZZ(n - 2)) * ZZ(n - 2) / ZZ(4) + if num.is_integral(): num = ZZ(num) - if (n == infinity): + if n == infinity: # TODO: Figure out what to do in this case # (l1 and l2 are no longer defined in an analog/unique way) # l2 = num % ZZ(2) @@ -688,9 +686,9 @@ def weight_parameters(self): l1 = num else: l2 = num % n - l1 = ((num-l2)/n).numerator() + l1 = ((num - l2) / n).numerator() else: - raise ValueError("Invalid or non-occurring weight k={}, ep={}!".format(k,ep)) + raise ValueError("Invalid or non-occurring weight k={}, ep={}!".format(k, ep)) return (l1, l2) # TODO: this only makes sense for modular forms, @@ -742,13 +740,13 @@ def aut_factor(self, gamma, t): 13.23058830577...? + 15.71786610686...?*I """ - if (gamma.is_translation()): + if gamma.is_translation(): return ZZ(1) - if (gamma.is_reflection()): - return self._ep * (t/QQbar(I))**self._weight + if gamma.is_reflection(): + return self._ep * (t / QQbar(I)) ** self._weight L = list(gamma.word_S_T()[0]) aut_f = ZZ(1) - while (len(L) > 0): + while len(L) > 0: M = L.pop(-1) aut_f *= self.aut_factor(M, t) t = M.acton(t) @@ -797,25 +795,25 @@ def F_simple(self, order_1=ZZ.zero()): 1 + 32*q + 480*q^2 + 4480*q^3 + 29152*q^4 + O(q^5) """ - (x,y,z,d) = self.rat_field().gens() + (x, y, z, d) = self.rat_field().gens() n = self.hecke_n() - if (n == infinity): + if n == infinity: order_1 = ZZ(order_1) order_inf = self._l1 - order_1 - finf_pol = d*(x - y**2) - rat = finf_pol**order_inf * x**order_1 * y**(ZZ(1-self._ep)/ZZ(2)) + finf_pol = d * (x - y**2) + rat = finf_pol**order_inf * x**order_1 * y ** (ZZ(1 - self._ep) / ZZ(2)) else: order_inf = self._l1 order_1 = order_inf - finf_pol = d*(x**n - y**2) - rat = finf_pol**self._l1 * x**self._l2 * y**(ZZ(1-self._ep)/ZZ(2)) + finf_pol = d * (x**n - y**2) + rat = finf_pol**self._l1 * x**self._l2 * y ** (ZZ(1 - self._ep) / ZZ(2)) - if (order_inf > 0 and order_1 > 0): + if order_inf > 0 and order_1 > 0: new_space = self.extend_type("cusp") - elif (order_inf >= 0 and order_1 >= 0): + elif order_inf >= 0 and order_1 >= 0: new_space = self.extend_type("holo") else: new_space = self.extend_type("weak") @@ -934,17 +932,17 @@ def Faber_pol(self, m, order_1=ZZ.zero(), fix_d=False, d_num_prec=None): """ m = ZZ(m) - if (self.hecke_n() == infinity): + if self.hecke_n() == infinity: order_1 = ZZ(order_1) order_inf = self._l1 - order_1 else: order_inf = self._l1 order_1 = order_inf - if (m > order_inf): + if m > order_inf: raise ValueError("Invalid basis index: m = {} > {} = order_inf!".format(m, order_inf)) - prec = 2*order_inf - m + 1 + prec = 2 * order_inf - m + 1 d = self.get_d(fix_d=fix_d, d_num_prec=d_num_prec) q = self.get_q(prec=prec, fix_d=fix_d, d_num_prec=d_num_prec) @@ -953,19 +951,19 @@ def Faber_pol(self, m, order_1=ZZ.zero(), fix_d=False, d_num_prec=None): # The precision could be infinity, otherwise we could do this: # assert temp_reminder.prec() == 1 - temp_reminder = (1 / simple_qexp / q**(-m)).add_bigoh(1) + temp_reminder = (1 / simple_qexp / q ** (-m)).add_bigoh(1) fab_pol = q.parent()([]) - while (len(temp_reminder.coefficients()) > 0): + while len(temp_reminder.coefficients()) > 0: temp_coeff = temp_reminder.coefficients()[0] temp_exp = -temp_reminder.exponents()[0] - fab_pol += temp_coeff * (q/d)**temp_exp + fab_pol += temp_coeff * (q / d) ** temp_exp - temp_reminder -= temp_coeff * (J_qexp/d)**temp_exp + temp_reminder -= temp_coeff * (J_qexp / d) ** temp_exp # The first term is zero only up to numerical errors, # so we manually have to remove it - if (not d.parent().is_exact()): - temp_reminder = temp_reminder.truncate_neg(-temp_exp+1) + if not d.parent().is_exact(): + temp_reminder = temp_reminder.truncate_neg(-temp_exp + 1) return fab_pol.polynomial() @@ -1074,17 +1072,17 @@ def faber_pol(self, m, order_1=ZZ.zero(), fix_d=False, d_num_prec=None): """ m = ZZ(m) - if (self.hecke_n() == infinity): + if self.hecke_n() == infinity: order_1 = ZZ(order_1) order_inf = self._l1 - order_1 else: order_inf = self._l1 order_1 = order_inf - if (m > order_inf): + if m > order_inf: raise ValueError("Invalid basis index: m = {} > {} = order_inf!".format(m, order_inf)) - prec = 2*order_inf - m + 1 + prec = 2 * order_inf - m + 1 d = self.get_d(fix_d=fix_d, d_num_prec=d_num_prec) q = self.get_q(prec=prec, fix_d=fix_d, d_num_prec=d_num_prec) @@ -1093,19 +1091,19 @@ def faber_pol(self, m, order_1=ZZ.zero(), fix_d=False, d_num_prec=None): # The precision could be infinity, otherwise we could do this: # assert temp_reminder.prec() == 1 - temp_reminder = (1 / simple_qexp / q**(-m)).add_bigoh(1) + temp_reminder = (1 / simple_qexp / q ** (-m)).add_bigoh(1) fab_pol = q.parent()([]) - while (len(temp_reminder.coefficients()) > 0): + while len(temp_reminder.coefficients()) > 0: temp_coeff = temp_reminder.coefficients()[0] temp_exp = -temp_reminder.exponents()[0] - fab_pol += temp_coeff*q**temp_exp + fab_pol += temp_coeff * q**temp_exp - temp_reminder -= temp_coeff*j_qexp**temp_exp + temp_reminder -= temp_coeff * j_qexp**temp_exp # The first term is zero only up to numerical errors, # so we manually have to remove it if not d.parent().is_exact(): - temp_reminder = temp_reminder.truncate_neg(-temp_exp+1) + temp_reminder = temp_reminder.truncate_neg(-temp_exp + 1) return fab_pol.polynomial() @@ -1193,21 +1191,21 @@ def F_basis_pol(self, m, order_1=ZZ.zero()): (-81*x^2*y^5 - 606*x^3*y^3 - 337*x^4*y)/(1024*y^2*d - 1024*x*d) """ - (x,y,z,d) = self.rat_field().gens() + (x, y, z, d) = self.rat_field().gens() n = self._group.n() - if (n == infinity): + if n == infinity: order_1 = ZZ(order_1) order_inf = self._l1 - order_1 - finf_pol = d*(x-y**2) - jinv_pol = x/(x-y**2) - rat = finf_pol**order_inf * x**order_1 * y**(ZZ(1-self._ep)/ZZ(2)) * self.Faber_pol(m, order_1)(jinv_pol) + finf_pol = d * (x - y**2) + jinv_pol = x / (x - y**2) + rat = finf_pol**order_inf * x**order_1 * y ** (ZZ(1 - self._ep) / ZZ(2)) * self.Faber_pol(m, order_1)(jinv_pol) else: order_inf = self._l1 order_1 = order_inf - finf_pol = d*(x**n-y**2) - jinv_pol = x**n/(x**n-y**2) - rat = finf_pol**order_inf * x**self._l2 * y**(ZZ(1-self._ep)/ZZ(2)) * self.Faber_pol(m)(jinv_pol) + finf_pol = d * (x**n - y**2) + jinv_pol = x**n / (x**n - y**2) + rat = finf_pol**order_inf * x**self._l2 * y ** (ZZ(1 - self._ep) / ZZ(2)) * self.Faber_pol(m)(jinv_pol) return rat @@ -1293,17 +1291,17 @@ def F_basis(self, m, order_1=ZZ.zero()): basis_pol = self.F_basis_pol(m, order_1=order_1) - if (self.hecke_n() == infinity): - (x,y,z,d) = self.pol_ring().gens() - if (x.divides(basis_pol.numerator()) and m > 0): + if self.hecke_n() == infinity: + (x, y, z, d) = self.pol_ring().gens() + if x.divides(basis_pol.numerator()) and m > 0: new_space = self.extend_type("cusp") - elif (x.divides(basis_pol.denominator()) or m < 0): + elif x.divides(basis_pol.denominator()) or m < 0: new_space = self.extend_type("weak") else: new_space = self.extend_type("holo") - elif (m > 0): + elif m > 0: new_space = self.extend_type("cusp") - elif (m >= 0): + elif m >= 0: new_space = self.extend_type("holo") else: new_space = self.extend_type("weak") @@ -1337,7 +1335,7 @@ def _canonical_min_exp(self, min_exp, order_1): min_exp = max(min_exp, 0) order_1 = max(order_1, 0) - if (self.hecke_n() != infinity): + if self.hecke_n() != infinity: order_1 = ZZ.zero() return (min_exp, order_1) @@ -1458,6 +1456,7 @@ def quasi_part_gens(self, r=None, min_exp=0, max_exp=infinity, order_1=ZZ.zero() """ if not self.is_weakly_holomorphic(): from warnings import warn + warn("This function only determines generators of (quasi) weakly modular forms!") min_exp, order_1 = self._canonical_min_exp(min_exp, order_1) @@ -1472,9 +1471,9 @@ def quasi_part_gens(self, r=None, min_exp=0, max_exp=infinity, order_1=ZZ.zero() # how large powers of E2 we can fit in... n = self.hecke_n() if n == infinity: - max_numerator_weight = self._weight - 4*min_exp - 4*order_1 + 4 + max_numerator_weight = self._weight - 4 * min_exp - 4 * order_1 + 4 else: - max_numerator_weight = self._weight - 4*n/(n-2)*min_exp + 4 + max_numerator_weight = self._weight - 4 * n / (n - 2) * min_exp + 4 # If r is not specified we gather all generators for all possible r's if r is None: @@ -1484,12 +1483,11 @@ def quasi_part_gens(self, r=None, min_exp=0, max_exp=infinity, order_1=ZZ.zero() return tuple(gens) r = ZZ(r) - if r < 0 or 2*r > max_numerator_weight: + if r < 0 or 2 * r > max_numerator_weight: return () E2 = self.E2() - ambient_weak_space = self.graded_ring().reduce_type("weak", - degree=(self._weight-QQ(2*r), self._ep*(-1)**r)) + ambient_weak_space = self.graded_ring().reduce_type("weak", degree=(self._weight - QQ(2 * r), self._ep * (-1) ** r)) order_inf = ambient_weak_space._l1 - order_1 if max_exp == infinity: @@ -1499,8 +1497,7 @@ def quasi_part_gens(self, r=None, min_exp=0, max_exp=infinity, order_1=ZZ.zero() else: max_exp = min(ZZ(max_exp), order_inf) - return tuple(self(ambient_weak_space.F_basis(m, order_1=order_1) * E2**r) - for m in range(min_exp, max_exp + 1)) + return tuple(self(ambient_weak_space.F_basis(m, order_1=order_1) * E2**r) for m in range(min_exp, max_exp + 1)) def quasi_part_dimension(self, r=None, min_exp=0, max_exp=infinity, order_1=ZZ.zero()): r""" @@ -1559,8 +1556,9 @@ def quasi_part_dimension(self, r=None, min_exp=0, max_exp=infinity, order_1=ZZ.z [-2, -2] """ - if (not self.is_weakly_holomorphic()): + if not self.is_weakly_holomorphic(): from warnings import warn + warn("This function only determines the dimension of some (quasi) weakly subspace!") (min_exp, order_1) = self._canonical_min_exp(min_exp, order_1) @@ -1574,33 +1572,33 @@ def quasi_part_dimension(self, r=None, min_exp=0, max_exp=infinity, order_1=ZZ.z # The lower bounds on the powers of f_inf and E4 determine # how large powers of E2 we can fit in... n = self.hecke_n() - if (n == infinity): - max_numerator_weight = self._weight - 4*min_exp - 4*order_1 + 4 + if n == infinity: + max_numerator_weight = self._weight - 4 * min_exp - 4 * order_1 + 4 else: - max_numerator_weight = self._weight - 4*n/(n-2)*min_exp + 4 + max_numerator_weight = self._weight - 4 * n / (n - 2) * min_exp + 4 # If r is not specified we calculate the total dimension over all possible r's if r is None: - return sum([self.quasi_part_dimension(r=rnew, min_exp=min_exp, max_exp=max_exp, order_1=order_1) for rnew in range(QQ(max_numerator_weight/ZZ(2)).floor() + 1)]) + return sum([self.quasi_part_dimension(r=rnew, min_exp=min_exp, max_exp=max_exp, order_1=order_1) for rnew in range(QQ(max_numerator_weight / ZZ(2)).floor() + 1)]) r = ZZ(r) - if (r < 0 or 2*r > max_numerator_weight): + if r < 0 or 2 * r > max_numerator_weight: return ZZ.zero() - k = self._weight - QQ(2*r) - ep = self._ep * (-1)**r - if (n == infinity): - num = (k - (1-ep)) / ZZ(4) + k = self._weight - QQ(2 * r) + ep = self._ep * (-1) ** r + if n == infinity: + num = (k - (1 - ep)) / ZZ(4) l2 = order_1 order_inf = ZZ(num) - order_1 else: - num = ZZ((k-(1-ep)*ZZ(n)/ZZ(n-2)) * ZZ(n-2) / ZZ(4)) + num = ZZ((k - (1 - ep) * ZZ(n) / ZZ(n - 2)) * ZZ(n - 2) / ZZ(4)) l2 = num % n order_inf = ((num - l2) / n).numerator() - if (max_exp == infinity): + if max_exp == infinity: max_exp = order_inf - elif (max_exp < min_exp): + elif max_exp < min_exp: return ZZ.zero() else: max_exp = min(ZZ(max_exp), order_inf) @@ -1708,24 +1706,23 @@ def construct_form(self, laurent_series, order_1=ZZ.zero(), check=True, rational order_1 = self._canonical_min_exp(0, order_1)[1] order_inf = self._l1 - order_1 - if (laurent_series.prec() < order_inf + 1): + if laurent_series.prec() < order_inf + 1: raise ValueError("Insufficient precision: {} < {} = order_inf!".format(laurent_series.prec(), order_inf + 1)) new_series = laurent_series.add_bigoh(order_inf + 1) coefficients = new_series.coefficients() exponents = new_series.exponents() - if (len(coefficients) == 0): + if len(coefficients) == 0: return self(0) - rat = sum([coefficients[j] * self.F_basis_pol(exponents[j], order_1=order_1) - for j in range(ZZ(len(coefficients)))]) + rat = sum([coefficients[j] * self.F_basis_pol(exponents[j], order_1=order_1) for j in range(ZZ(len(coefficients)))]) el = self(rat) - if (check): + if check: prec = min(laurent_series.prec(), laurent_series.exponents()[-1] + 1) - if (el.q_expansion(prec=prec) != laurent_series): + if el.q_expansion(prec=prec) != laurent_series: raise ValueError("The Laurent series {} does not correspond to a form of {}".format(laurent_series, self.reduce_type(["weak"]))) return el @@ -1799,7 +1796,7 @@ def _quasi_form_matrix(self, min_exp=0, order_1=ZZ.zero(), incr_prec_by=0): A = matrix(coeff_ring, row_size, 0) for gen in basis: - A = A.augment(gen.q_expansion_vector(min_exp=min_exp, max_exp=prec-1)) + A = A.augment(gen.q_expansion_vector(min_exp=min_exp, max_exp=prec - 1)) # So far this case never happened but potentially A could be singular! # In this case we want to increase the row size until A has maximal @@ -1807,13 +1804,14 @@ def _quasi_form_matrix(self, min_exp=0, order_1=ZZ.zero(), incr_prec_by=0): # This is done up increasing the precision of everything by about 20% # of the column size until A has maximal rank: - if (A.rank() < column_size): - if (incr_prec_by == 0): + if A.rank() < column_size: + if incr_prec_by == 0: from sage.misc.verbose import verbose + verbose("Encountered a base change matrix with not-yet-maximal rank (rare, please report)!") - incr_prec_by += column_size//ZZ(5) + 1 + incr_prec_by += column_size // ZZ(5) + 1 return self._quasi_form_matrix(min_exp=min_exp, order_1=order_1, incr_prec_by=incr_prec_by) - if (incr_prec_by == 0): + if incr_prec_by == 0: return A # At this point the matrix has maximal rank but might be too big. @@ -1823,21 +1821,21 @@ def _quasi_form_matrix(self, min_exp=0, order_1=ZZ.zero(), incr_prec_by=0): # keep a simple correspondence to Fourier coefficients! # We start by using an initial binary search to delete some unnecessary rows: - while (A.rank() == column_size): + while A.rank() == column_size: row_size = A.dimensions()[0] # to avoid infinite loops - if (row_size == column_size): + if row_size == column_size: return A B = A - A = A.delete_rows(list(range(column_size + (row_size-column_size)//2 - 1, row_size))) + A = A.delete_rows(list(range(column_size + (row_size - column_size) // 2 - 1, row_size))) # Next we simply delete row by row. Note that A is still modified here... - while (B.rank() == column_size): + while B.rank() == column_size: A = B row_size = B.dimensions()[0] - B = B.delete_rows([row_size-1]) + B = B.delete_rows([row_size - 1]) return A @@ -2004,25 +2002,25 @@ def construct_quasi_form(self, laurent_series, order_1=ZZ.zero(), check=True, ra min_exp1 = laurent_series.exponents()[0] (min_exp, order_1) = self._canonical_min_exp(min_exp1, order_1) - if (min_exp != min_exp1): + if min_exp != min_exp1: raise ValueError("Due to the behavior at infinity the given Laurent series cannot possibly be an element of {}".format(self)) # if a q_basis is available we can construct the form much faster - if (self.q_basis.is_in_cache(min_exp=min_exp, order_1=order_1)): + if self.q_basis.is_in_cache(min_exp=min_exp, order_1=order_1): basis = self.q_basis(min_exp=min_exp, order_1=order_1) size = len(basis) - if (prec < min_exp + size): + if prec < min_exp + size: raise ValueError("Insufficient precision: {} < {}!".format(laurent_series.prec(), min_exp + size)) b = vector(self.coeff_ring(), [laurent_series[m] for m in range(min_exp, min_exp + len(basis))]) - el = self(sum([b[k]*basis[k] for k in range(len(basis))])) + el = self(sum([b[k] * basis[k] for k in range(len(basis))])) else: A = self._quasi_form_matrix(min_exp=min_exp, order_1=order_1) row_size = A.dimensions()[0] - if (prec < min_exp + row_size): + if prec < min_exp + row_size: raise ValueError("Insufficient precision: {} < {}!".format(laurent_series.prec(), min_exp + row_size)) b = vector(self.coeff_ring(), [laurent_series[m] for m in range(min_exp, min_exp + row_size)]) @@ -2039,10 +2037,10 @@ def construct_quasi_form(self, laurent_series, order_1=ZZ.zero(), check=True, ra max_exp = order_inf + 1 basis = self.quasi_part_gens(min_exp=min_exp, max_exp=max_exp, order_1=order_1) - el = self(sum([coord_vector[k]*basis[k] for k in range(len(coord_vector))])) + el = self(sum([coord_vector[k] * basis[k] for k in range(len(coord_vector))])) - if (check): - if (el.q_expansion(prec=prec) != laurent_series): + if check: + if el.q_expansion(prec=prec) != laurent_series: raise ValueError("The Laurent series {} does not correspond to a form of {}".format(laurent_series, self.reduce_type(["quasi", "weak"]))) return el @@ -2100,18 +2098,19 @@ def q_basis(self, m=None, min_exp=0, order_1=ZZ.zero()): [1 - 168*q^2 + 2304*q^3 - 19320*q^4 + O(q^5), q - 18*q^2 + 180*q^3 - 1316*q^4 + O(q^5)] """ - if (not self.is_weakly_holomorphic()): + if not self.is_weakly_holomorphic(): from warnings import warn + warn("This function only determines elements / a basis of (quasi) weakly modular forms!") (min_exp, order_1) = self._canonical_min_exp(min_exp, order_1) order_inf = self._l1 - order_1 - if (m is None): + if m is None: A = self._quasi_form_matrix(min_exp=min_exp, order_1=order_1) # If A is square it should automatically be invertible (by the previous procedures) - if (A.is_square()): + if A.is_square(): B = A.inverse() max_exp = order_inf + 1 @@ -2126,21 +2125,21 @@ def q_basis(self, m=None, min_exp=0, order_1=ZZ.zero()): return q_basis raise ValueError("Unfortunately a q_basis doesn't exist in this case (this is rare/interesting, please report)") else: - if (m < min_exp): + if m < min_exp: raise ValueError("Index out of range: m={} < {}=min_exp".format(m, min_exp)) # If the whole basis is available, then use it - if (self.q_basis.is_in_cache(min_exp=min_exp, order_1=order_1)): + if self.q_basis.is_in_cache(min_exp=min_exp, order_1=order_1): q_basis = self.q_basis(min_exp=min_exp, order_1=order_1) column_len = len(q_basis) - if (m >= column_len + min_exp): + if m >= column_len + min_exp: raise ValueError("Index out of range: m={} >= {}=dimension + min_exp".format(m, column_len + min_exp)) return q_basis[m - min_exp] row_len = self.required_laurent_prec(min_exp=min_exp, order_1=order_1) - min_exp - if (m >= row_len + min_exp): + if m >= row_len + min_exp: raise ValueError("Index out of range: m={} >= {}=required_precision + min_exp".format(m, row_len + min_exp)) A = self._quasi_form_matrix(min_exp=min_exp, order_1=order_1) @@ -2155,8 +2154,7 @@ def q_basis(self, m=None, min_exp=0, order_1=ZZ.zero()): basis = self.quasi_part_gens(min_exp=min_exp, max_exp=max_exp, order_1=order_1) column_len = A.dimensions()[1] - return self(sum([coord_vector[l] * basis[l] - for l in range(column_len)])) + return self(sum([coord_vector[l] * basis[l] for l in range(column_len)])) def rationalize_series(self, laurent_series, coeff_bound=1e-10, denom_factor=ZZ(1)): r""" @@ -2257,17 +2255,17 @@ def rationalize_series(self, laurent_series, coeff_bound=1e-10, denom_factor=ZZ( # If the coefficients already coerce to our coefficient ring # and are in polynomial form we simply return the Laurent series - if (isinstance(base_ring.base(), PolynomialRing_generic)): - if (self.coeff_ring().has_coerce_map_from(base_ring)): + if isinstance(base_ring.base(), PolynomialRing_generic): + if self.coeff_ring().has_coerce_map_from(base_ring): return laurent_series raise ValueError("The Laurent coefficients don't coerce into the coefficient ring of self!") # Else the case that the Laurent series is exact but the group is non-arithmetic # shouldn't occur (except for trivial cases) - elif (base_ring.is_exact() and not self.group().is_arithmetic()): + elif base_ring.is_exact() and not self.group().is_arithmetic(): prec = self.default_num_prec() dvalue = self.group().dvalue().n(prec) # For arithmetic groups the coefficients are exact though (so is d) - elif (base_ring.is_exact()): + elif base_ring.is_exact(): prec = self.default_num_prec() dvalue = self.group().dvalue() else: @@ -2280,24 +2278,24 @@ def rationalize_series(self, laurent_series, coeff_bound=1e-10, denom_factor=ZZ( d = self.get_d() q = self.get_q() - if (not base_ring.is_exact() and coeff_bound): + if not base_ring.is_exact() and coeff_bound: coeff_bound = base_ring(coeff_bound) num_q = laurent_series.parent().gen() - laurent_series = sum([laurent_series[i]*num_q**i for i in range(laurent_series.exponents()[0], laurent_series.exponents()[-1]+1) if laurent_series[i].abs() > coeff_bound]).add_bigoh(series_prec) + laurent_series = sum([laurent_series[i] * num_q**i for i in range(laurent_series.exponents()[0], laurent_series.exponents()[-1] + 1) if laurent_series[i].abs() > coeff_bound]).add_bigoh(series_prec) first_exp = laurent_series.exponents()[0] first_coeff = laurent_series[first_exp] - d_power = (first_coeff.abs().n(prec).log()/dvalue.n(prec).log()).round() + d_power = (first_coeff.abs().n(prec).log() / dvalue.n(prec).log()).round() - if (first_coeff < 0): + if first_coeff < 0: return -self.rationalize_series(-laurent_series, coeff_bound=coeff_bound) - if (first_exp + d_power != 0): - cor_factor = dvalue**(-(first_exp + d_power)) - return d**(first_exp + d_power) * self.rationalize_series(cor_factor * laurent_series, coeff_bound=coeff_bound) - if (base_ring.is_exact() and self.group().is_arithmetic()): + if first_exp + d_power != 0: + cor_factor = dvalue ** (-(first_exp + d_power)) + return d ** (first_exp + d_power) * self.rationalize_series(cor_factor * laurent_series, coeff_bound=coeff_bound) + if base_ring.is_exact() and self.group().is_arithmetic(): tolerance = 0 else: - tolerance = 10*ZZ(1).n(prec).ulp() + tolerance = 10 * ZZ(1).n(prec).ulp() if (first_coeff * dvalue**first_exp - ZZ(1)) > tolerance: raise ValueError("The Laurent series is not normalized correctly!") @@ -2309,22 +2307,22 @@ def denominator_estimate(m): m += cor_exp if self.group().is_arithmetic(): - return ZZ(1/dvalue)**m + return ZZ(1 / dvalue) ** m hecke_n = self.hecke_n() - bad_factors = [fac for fac in Integer(m).factorial().factor() if (fac[0] % hecke_n) not in [1, hecke_n-1] and fac[0] > 2] - bad_factorial = prod([fac[0]**fac[1] for fac in bad_factors]) + bad_factors = [fac for fac in Integer(m).factorial().factor() if (fac[0] % hecke_n) not in [1, hecke_n - 1] and fac[0] > 2] + bad_factorial = prod([fac[0] ** fac[1] for fac in bad_factors]) - return ZZ(2**(6*m) * hecke_n**(2*m) * prod([ p**m for p in prime_range(m+1) if hecke_n % p == 0 and p > 2 ]) * bad_factorial)**(cor_exp + 1) + return ZZ(2 ** (6 * m) * hecke_n ** (2 * m) * prod([p**m for p in prime_range(m + 1) if hecke_n % p == 0 and p > 2]) * bad_factorial) ** (cor_exp + 1) def rationalize_coefficient(coeff, m): # TODO: figure out a correct bound for the required precision - if (not self.group().is_arithmetic() and denominator_estimate(m).log(2).n().ceil() > prec): + if not self.group().is_arithmetic() and denominator_estimate(m).log(2).n().ceil() > prec: warn("The precision from coefficient m={} on is too low!".format(m)) rational_coeff = coeff * dvalue**m - if (base_ring.is_exact() and self.group().is_arithmetic() and rational_coeff in QQ): + if base_ring.is_exact() and self.group().is_arithmetic() and rational_coeff in QQ: rational_coeff = QQ(rational_coeff) else: int_estimate = denominator_estimate(m) * denom_factor * rational_coeff @@ -2332,8 +2330,7 @@ def rationalize_coefficient(coeff, m): return rational_coeff / d**m - return sum([rationalize_coefficient(laurent_series[m], m) * q**m - for m in range(first_exp, laurent_series.exponents()[-1] + 1)]).add_bigoh(series_prec) + return sum([rationalize_coefficient(laurent_series[m], m) * q**m for m in range(first_exp, laurent_series.exponents()[-1] + 1)]).add_bigoh(series_prec) # DEFAULT METHODS (should be overwritten in concrete classes) diff --git a/src/sage/modular/modform_hecketriangle/all.py b/src/sage/modular/modform_hecketriangle/all.py index 1c2bfeccdc6..b2e618da337 100644 --- a/src/sage/modular/modform_hecketriangle/all.py +++ b/src/sage/modular/modform_hecketriangle/all.py @@ -3,6 +3,7 @@ - Jonas Jermann (2013): initial version """ + # **************************************************************************** # Copyright (C) 2013-2014 Jonas Jermann # @@ -15,15 +16,8 @@ from sage.modular.modform_hecketriangle.series_constructor import MFSeriesConstructor -from sage.modular.modform_hecketriangle.graded_ring import (QuasiMeromorphicModularFormsRing, - QuasiWeakModularFormsRing, QuasiModularFormsRing, - QuasiCuspFormsRing, MeromorphicModularFormsRing, - WeakModularFormsRing, - ModularFormsRing, CuspFormsRing) +from sage.modular.modform_hecketriangle.graded_ring import QuasiMeromorphicModularFormsRing, QuasiWeakModularFormsRing, QuasiModularFormsRing, QuasiCuspFormsRing, MeromorphicModularFormsRing, WeakModularFormsRing, ModularFormsRing, CuspFormsRing -from sage.modular.modform_hecketriangle.space import (QuasiMeromorphicModularForms, QuasiWeakModularForms, - QuasiModularForms, QuasiCuspForms, - MeromorphicModularForms, WeakModularForms, ModularForms, - CuspForms, ZeroForm) +from sage.modular.modform_hecketriangle.space import QuasiMeromorphicModularForms, QuasiWeakModularForms, QuasiModularForms, QuasiCuspForms, MeromorphicModularForms, WeakModularForms, ModularForms, CuspForms, ZeroForm from sage.modular.modform_hecketriangle.subspace import ModularFormsSubSpace diff --git a/src/sage/modular/modform_hecketriangle/analytic_type.py b/src/sage/modular/modform_hecketriangle/analytic_type.py index 090ecd600fc..6d7e1e5c254 100644 --- a/src/sage/modular/modform_hecketriangle/analytic_type.py +++ b/src/sage/modular/modform_hecketriangle/analytic_type.py @@ -436,15 +436,11 @@ def __init__(self): P_elements = ["cusp", "holo", "weak", "mero", "quasi"] P_relations = [["cusp", "holo"], ["holo", "weak"], ["weak", "mero"]] - self._base_poset = Poset([P_elements, P_relations], cover_relations=True, - linear_extension=True, facade=False) + self._base_poset = Poset([P_elements, P_relations], cover_relations=True, linear_extension=True, facade=False) L = self._base_poset.order_ideals_lattice() - H = L._hasse_diagram.relabel(dict(enumerate(L._elements)), - inplace=False) - FiniteLatticePoset.__init__(self, hasse_diagram=H, - elements=L._elements, category=L.category(), - facade=False, key=None) + H = L._hasse_diagram.relabel(dict(enumerate(L._elements)), inplace=False) + FiniteLatticePoset.__init__(self, hasse_diagram=H, elements=L._elements, category=L.category(), facade=False, key=None) def _repr_(self): r""" @@ -519,8 +515,7 @@ def _element_constructor_(self, element): if isinstance(element, str): element = [element] if isinstance(element, (list, tuple)): - element = Set(self._base_poset.order_ideal([self._base_poset(s) - for s in element])) + element = Set(self._base_poset.order_ideal([self._base_poset(s) for s in element])) return super()._element_constructor_(element) diff --git a/src/sage/modular/modform_hecketriangle/constructor.py b/src/sage/modular/modform_hecketriangle/constructor.py index 9ecae0b39b3..b60342e16a7 100644 --- a/src/sage/modular/modform_hecketriangle/constructor.py +++ b/src/sage/modular/modform_hecketriangle/constructor.py @@ -108,10 +108,11 @@ def rational_type(f, n=ZZ(3), base_ring=ZZ): """ from .analytic_type import AnalyticType + AT = AnalyticType() # Determine whether f is zero - if (f == 0): + if f == 0: # elem, homo, k, ep, analytic_type return (True, True, QQ(0), ZZ(1), AT([])) @@ -127,19 +128,19 @@ def rational_type(f, n=ZZ(3), base_ring=ZZ): num = R(f.numerator()) denom = R(f.denominator()) - ep_num = {ZZ.one() - 2*((sum([g.exponents()[0][m] for m in [1, 2]])) % 2) for g in dhom(num).monomials()} - ep_denom = {ZZ.one() - 2*((sum([g.exponents()[0][m] for m in [1, 2]])) % 2) for g in dhom(denom).monomials()} + ep_num = {ZZ.one() - 2 * ((sum([g.exponents()[0][m] for m in [1, 2]])) % 2) for g in dhom(num).monomials()} + ep_denom = {ZZ.one() - 2 * ((sum([g.exponents()[0][m] for m in [1, 2]])) % 2) for g in dhom(denom).monomials()} - if (n == infinity): + if n == infinity: hom_num = R(num.subs(x=x**4, y=y**2, z=z**2)) hom_denom = R(denom.subs(x=x**4, y=y**2, z=z**2)) else: n = ZZ(n) - hom_num = R(num.subs(x=x**4, y=y**(2*n), z=z**(2*(n-2)))) - hom_denom = R(denom.subs(x=x**4, y=y**(2*n), z=z**(2*(n-2)))) + hom_num = R(num.subs(x=x**4, y=y ** (2 * n), z=z ** (2 * (n - 2)))) + hom_denom = R(denom.subs(x=x**4, y=y ** (2 * n), z=z ** (2 * (n - 2)))) # Determine whether the denominator of f is homogeneous - if (len(ep_denom) == 1 and dhom(hom_denom).is_homogeneous()): + if len(ep_denom) == 1 and dhom(hom_denom).is_homogeneous(): elem = True else: # elem, homo, k, ep, analytic_type @@ -149,9 +150,9 @@ def rational_type(f, n=ZZ(3), base_ring=ZZ): if len(ep_num) == 1 and dhom(hom_num).is_homogeneous(): homo = True if n == infinity: - weight = (dhom(hom_num).degree() - dhom(hom_denom).degree()) + weight = dhom(hom_num).degree() - dhom(hom_denom).degree() else: - weight = (dhom(hom_num).degree() - dhom(hom_denom).degree()) / (n-2) + weight = (dhom(hom_num).degree() - dhom(hom_denom).degree()) / (n - 2) ep = ep_num.pop() / ep_denom.pop() # TODO: decompose f (resp. its degrees) into homogeneous parts else: @@ -161,9 +162,9 @@ def rational_type(f, n=ZZ(3), base_ring=ZZ): # Note that we intentionally leave out the d-factor! if n == infinity: - finf_pol = (x-y**2) + finf_pol = x - y**2 else: - finf_pol = x**n-y**2 + finf_pol = x**n - y**2 # Determine whether f is modular if not (num.degree(z) > 0 or denom.degree(z) > 0): @@ -174,8 +175,8 @@ def rational_type(f, n=ZZ(3), base_ring=ZZ): analytic_type = analytic_type.reduce_to(["quasi", "holo"]) # Determine whether f is cuspidal in the sense that finf divides it... # Bug in singular: finf_pol.divides(1.0) fails over RR - if (not dhom(num).is_constant() and finf_pol.divides(num)): - if (n != infinity or x.divides(num)): + if not dhom(num).is_constant() and finf_pol.divides(num): + if n != infinity or x.divides(num): analytic_type = analytic_type.reduce_to(["quasi", "cusp"]) else: # -> Because of a bug with singular in some cases @@ -185,8 +186,8 @@ def rational_type(f, n=ZZ(3), base_ring=ZZ): # and dividing would/may result with an element of the quotient ring of the polynomial ring denom = denom.quo_rem(finf_pol)[0] denom = R(denom) - if (n == infinity): - while (x.divides(denom)): + if n == infinity: + while x.divides(denom): # a simple "denom /= x" is strangely not enough for non-exact rings # and dividing would/may result with an element of the quotient ring of the polynomial ring denom = denom.quo_rem(x)[0] @@ -195,7 +196,7 @@ def rational_type(f, n=ZZ(3), base_ring=ZZ): pass # Determine whether f is weakly holomorphic in the sense that at most powers of finf occur in denom - if (dhom(denom).is_constant()): + if dhom(denom).is_constant(): analytic_type = analytic_type.reduce_to(["quasi", "weak"]) return (elem, homo, weight, ep, analytic_type) @@ -264,9 +265,11 @@ def FormsSpace(analytic_type, group=3, base_ring=ZZ, k=QQ(0), ep=None): """ from .space import canonical_parameters + (group, base_ring, k, ep, n) = canonical_parameters(group, base_ring, k, ep) from .analytic_type import AnalyticType + AT = AnalyticType() analytic_type = AT(analytic_type) @@ -276,14 +279,19 @@ def FormsSpace(analytic_type, group=3, base_ring=ZZ, k=QQ(0), ep=None): if analytic_type <= AT("cusp"): if analytic_type <= AT([]): from .space import ZeroForm + return ZeroForm(group=group, base_ring=base_ring, k=k, ep=ep) from .space import CuspForms + return CuspForms(group=group, base_ring=base_ring, k=k, ep=ep) from .space import ModularForms + return ModularForms(group=group, base_ring=base_ring, k=k, ep=ep) from .space import WeakModularForms + return WeakModularForms(group=group, base_ring=base_ring, k=k, ep=ep) from .space import MeromorphicModularForms + return MeromorphicModularForms(group=group, base_ring=base_ring, k=k, ep=ep) if analytic_type <= AT(["mero", "quasi"]): if analytic_type <= AT(["weak", "quasi"]): @@ -292,18 +300,23 @@ def FormsSpace(analytic_type, group=3, base_ring=ZZ, k=QQ(0), ep=None): if analytic_type <= AT(["quasi"]): raise ValueError("There should be only non-quasi ZeroForms. That could be changed but then this exception should be removed.") from .space import ZeroForm + return ZeroForm(group=group, base_ring=base_ring, k=k, ep=ep) else: from .space import QuasiCuspForms + return QuasiCuspForms(group=group, base_ring=base_ring, k=k, ep=ep) else: from .space import QuasiModularForms + return QuasiModularForms(group=group, base_ring=base_ring, k=k, ep=ep) else: from .space import QuasiWeakModularForms + return QuasiWeakModularForms(group=group, base_ring=base_ring, k=k, ep=ep) else: from .space import QuasiMeromorphicModularForms + return QuasiMeromorphicModularForms(group=group, base_ring=base_ring, k=k, ep=ep) else: raise NotImplementedError("Analytic type not implemented.") @@ -365,9 +378,11 @@ def FormsRing(analytic_type, group=3, base_ring=ZZ, red_hom=False): """ from .graded_ring import canonical_parameters + (group, base_ring, red_hom, n) = canonical_parameters(group, base_ring, red_hom) from .analytic_type import AnalyticType + AT = AnalyticType() analytic_type = AT(analytic_type) @@ -379,15 +394,19 @@ def FormsRing(analytic_type, group=3, base_ring=ZZ, red_hom=False): raise ValueError("Analytic type Zero is not valid for forms rings.") else: from .graded_ring import CuspFormsRing + return CuspFormsRing(group=group, base_ring=base_ring, red_hom=red_hom) else: from .graded_ring import ModularFormsRing + return ModularFormsRing(group=group, base_ring=base_ring, red_hom=red_hom) else: from .graded_ring import WeakModularFormsRing + return WeakModularFormsRing(group=group, base_ring=base_ring, red_hom=red_hom) else: from .graded_ring import MeromorphicModularFormsRing + return MeromorphicModularFormsRing(group=group, base_ring=base_ring, red_hom=red_hom) elif analytic_type <= AT(["mero", "quasi"]): if analytic_type <= AT(["weak", "quasi"]): @@ -397,15 +416,19 @@ def FormsRing(analytic_type, group=3, base_ring=ZZ, red_hom=False): raise ValueError("Analytic type Zero is not valid for forms rings.") else: from .graded_ring import QuasiCuspFormsRing + return QuasiCuspFormsRing(group=group, base_ring=base_ring, red_hom=red_hom) else: from .graded_ring import QuasiModularFormsRing + return QuasiModularFormsRing(group=group, base_ring=base_ring, red_hom=red_hom) else: from .graded_ring import QuasiWeakModularFormsRing + return QuasiWeakModularFormsRing(group=group, base_ring=base_ring, red_hom=red_hom) else: from .graded_ring import QuasiMeromorphicModularFormsRing + return QuasiMeromorphicModularFormsRing(group=group, base_ring=base_ring, red_hom=red_hom) else: raise NotImplementedError("Analytic type not implemented.") diff --git a/src/sage/modular/modform_hecketriangle/element.py b/src/sage/modular/modform_hecketriangle/element.py index e36ac49027f..270bfaa1a1a 100644 --- a/src/sage/modular/modform_hecketriangle/element.py +++ b/src/sage/modular/modform_hecketriangle/element.py @@ -67,12 +67,11 @@ def __init__(self, parent, rat) -> None: if self.AT(["quasi"]) >= self._analytic_type: pass - elif not (self.is_homogeneous() and - self._weight == parent.weight() and - self._ep == parent.ep()): + elif not (self.is_homogeneous() and self._weight == parent.weight() and self._ep == parent.ep()): raise ValueError("{} does not correspond to an element of {}.".format(rat, parent)) from .subspace import SubSpaceForms + if isinstance(parent, SubSpaceForms) and (parent._module is not None): try: self.coordinate_vector() @@ -290,13 +289,13 @@ def lseries(self, num_prec=None, max_imaginary_part=0, max_asymp_coeffs=40): from sage.misc.functional import sqrt from sage.lfunctions.dokchitser import Dokchitser - if (not (self.is_modular() and self.is_holomorphic()) or self.weight() == 0): + if not (self.is_modular() and self.is_holomorphic()) or self.weight() == 0: raise NotImplementedError("L-series are only implemented for non-trivial holomorphic modular forms.") if num_prec is None: num_prec = self.parent().default_num_prec() - conductor = self.group().lam()**2 + conductor = self.group().lam() ** 2 if self.group().is_arithmetic(): conductor = ZZ(conductor) else: @@ -324,13 +323,7 @@ def lseries(self, num_prec=None, max_imaginary_part=0, max_asymp_coeffs=40): residues = [residue] - L = Dokchitser(conductor=conductor, - gammaV=gammaV, - weight=weight, - eps=eps, - poles=poles, - residues=residues, - prec=num_prec) + L = Dokchitser(conductor=conductor, gammaV=gammaV, weight=weight, eps=eps, poles=poles, residues=residues, prec=num_prec) # TODO for later: Figure out the correct coefficient growth and do L.set_coeff_growth(...) @@ -339,9 +332,7 @@ def lseries(self, num_prec=None, max_imaginary_part=0, max_asymp_coeffs=40): coeff_vector = list(self.q_expansion_vector(min_exp=0, max_exp=n_coeffs + 1, fix_d=True)) pari_precode = "coeff = {};".format(coeff_vector) - L.init_coeffs(v="coeff[k+1]", pari_precode=pari_precode, - max_imaginary_part=max_imaginary_part, - max_asymp_coeffs=max_asymp_coeffs) + L.init_coeffs(v="coeff[k+1]", pari_precode=pari_precode, max_imaginary_part=max_imaginary_part, max_asymp_coeffs=max_asymp_coeffs) L.check_functional_equation() L.rename("L-series associated to the {} form {}".format("cusp" if self.is_cuspidal() else "modular", self)) diff --git a/src/sage/modular/modform_hecketriangle/functors.py b/src/sage/modular/modform_hecketriangle/functors.py index 25a805eea8d..0d87bdfa665 100644 --- a/src/sage/modular/modform_hecketriangle/functors.py +++ b/src/sage/modular/modform_hecketriangle/functors.py @@ -85,11 +85,11 @@ def _get_base_ring(ring, var_name='d'): base_ring = ring # if (isinstance(base_ring, FractionField_generic)): # base_ring = base_ring.base() - if (base_ring.construction() and base_ring.construction()[0] == FractionFieldFunctor()): + if base_ring.construction() and base_ring.construction()[0] == FractionFieldFunctor(): base_ring = base_ring.construction()[1] - if (isinstance(base_ring, PolynomialRing_generic) and base_ring.ngens() == 1 and base_ring.variable_name() == var_name): + if isinstance(base_ring, PolynomialRing_generic) and base_ring.ngens() == 1 and base_ring.variable_name() == var_name: base_ring = base_ring.base() - if (base_ring.construction() and base_ring.construction()[0] == FractionFieldFunctor()): + if base_ring.construction() and base_ring.construction()[0] == FractionFieldFunctor(): base_ring = base_ring.construction()[1] return base_ring @@ -293,7 +293,7 @@ def merge(self, other): QuasiModularFormsRingFunctor(n=4, red_hom=True) """ - if (self == other): + if self == other: return self if isinstance(other, FormsSubSpaceFunctor): merged_ambient_space_functor = self._ambient_space_functor.merge(other._ambient_space_functor) @@ -319,9 +319,7 @@ def __eq__(self, other): sage: ss_functor1 == ss_functor2 False """ - return (type(self) is type(other) and - self._ambient_space_functor == other._ambient_space_functor and - self._generators == other._generators) + return type(self) is type(other) and self._ambient_space_functor == other._ambient_space_functor and self._generators == other._generators class FormsSpaceFunctor(ConstructionFunctor): @@ -337,6 +335,7 @@ class FormsSpaceFunctor(ConstructionFunctor): """ from .analytic_type import AnalyticType + AT = AnalyticType() rank = 10 @@ -371,6 +370,7 @@ def __init__(self, analytic_type, group, k, ep): Functor.__init__(self, Rings(), CommutativeAdditiveGroups()) from .space import canonical_parameters + (self._group, R, self._k, self._ep, n) = canonical_parameters(group, ZZ, k, ep) self._analytic_type = self.AT(analytic_type) @@ -396,7 +396,7 @@ def __call__(self, R): True """ - if (isinstance(R, BaseFacade)): + if isinstance(R, BaseFacade): R = _get_base_ring(R._ring) return FormsSpace(self._analytic_type, self._group, R, self._k, self._ep) R = BaseFacade(_get_base_ring(R)) @@ -465,7 +465,7 @@ def merge(self, other): ModularFormsRingFunctor(n=5) """ - if (self == other): + if self == other: return self if isinstance(other, FormsSubSpaceFunctor): @@ -499,11 +499,7 @@ def __eq__(self, other): sage: functor1 == functor2 False """ - return (type(self) is type(other) and - self._group == other._group and - self._analytic_type == other._analytic_type and - self._k == other._k and - self._ep == other._ep) + return type(self) is type(other) and self._group == other._group and self._analytic_type == other._analytic_type and self._k == other._k and self._ep == other._ep class FormsRingFunctor(ConstructionFunctor): @@ -519,6 +515,7 @@ class FormsRingFunctor(ConstructionFunctor): """ from .analytic_type import AnalyticType + AT = AnalyticType() rank = 10 @@ -553,6 +550,7 @@ def __init__(self, analytic_type, group, red_hom): Functor.__init__(self, Rings(), Rings()) from .graded_ring import canonical_parameters + (self._group, R, red_hom, n) = canonical_parameters(group, ZZ, red_hom) self._red_hom = bool(red_hom) self._analytic_type = self.AT(analytic_type) @@ -578,7 +576,7 @@ def __call__(self, R): False """ - if (isinstance(R, BaseFacade)): + if isinstance(R, BaseFacade): R = _get_base_ring(R._ring) return FormsRing(self._analytic_type, self._group, R, self._red_hom) R = BaseFacade(_get_base_ring(R)) @@ -598,7 +596,7 @@ def _repr_(self): QuasiMeromorphicModularFormsRingFunctor(n=6) """ - if (self._red_hom): + if self._red_hom: red_arg = ", red_hom=True" else: red_arg = "" @@ -647,7 +645,7 @@ def merge(self, other): MeromorphicModularFormsRingFunctor(n=6, red_hom=True) """ - if (self == other): + if self == other: return self if isinstance(other, FormsSubSpaceFunctor): @@ -680,10 +678,7 @@ def __eq__(self, other): sage: functor1 == functor2 False """ - return (type(self) is type(other) and - self._group == other._group and - self._analytic_type == other._analytic_type and - self._red_hom == other._red_hom) + return type(self) is type(other) and self._group == other._group and self._analytic_type == other._analytic_type and self._red_hom == other._red_hom class BaseFacade(Parent, UniqueRepresentation): diff --git a/src/sage/modular/modform_hecketriangle/graded_ring_element.py b/src/sage/modular/modform_hecketriangle/graded_ring_element.py index eace30a450c..0ddf6c92918 100644 --- a/src/sage/modular/modform_hecketriangle/graded_ring_element.py +++ b/src/sage/modular/modform_hecketriangle/graded_ring_element.py @@ -43,12 +43,13 @@ # corresponding operations (e.g. __pow__) even though the category # (and class) of the parent is in some cases not # CommutativeAlgebras but Modules -class FormsRingElement(CommutativeAlgebraElement, UniqueRepresentation, - metaclass=InheritComparisonClasscallMetaclass): +class FormsRingElement(CommutativeAlgebraElement, UniqueRepresentation, metaclass=InheritComparisonClasscallMetaclass): r""" Element of a FormsRing. """ + from .analytic_type import AnalyticType + AT = AnalyticType() @staticmethod @@ -125,8 +126,7 @@ def __init__(self, parent, rat): self._rat = rat (elem, homo, self._weight, self._ep, self._analytic_type) = rational_type(rat, parent.hecke_n(), parent.base_ring()) - if not (elem and - self._analytic_type <= parent.analytic_type()): + if not (elem and self._analytic_type <= parent.analytic_type()): raise ValueError("{} does not correspond to an element of the {}.".format(rat, parent)) super().__init__(parent) @@ -156,10 +156,9 @@ def _richcmp_(self, other, op): if self.group() == other.group(): if self.group().is_arithmetic(): - b = (self.rat().subs(d=self.group().dvalue()) == - other.rat().subs(d=other.group().dvalue())) + b = self.rat().subs(d=self.group().dvalue()) == other.rat().subs(d=other.group().dvalue()) else: - b = (self.rat() == other.rat()) + b = self.rat() == other.rat() return b == (op == op_EQ) @@ -221,7 +220,7 @@ def _qexp_repr(self): """ # For now the series constructor doesn't behave well for non exact bases... :( - if (self.group().is_arithmetic() or not self.base_ring().is_exact()): + if self.group().is_arithmetic() or not self.base_ring().is_exact(): return str(self.q_expansion_fixed_d().add_bigoh(self.parent()._disp_prec)) return str(self.q_expansion().add_bigoh(self.parent()._disp_prec)) @@ -243,7 +242,7 @@ def _latex_(self): sage: latex(QuasiModularFormsRing(n=infinity)(x*(x-y^2)*z)) # needs sage.symbolic -E_{4} f_{i}^{2} E_{2} + E_{4}^{2} E_{2} """ - if (self.hecke_n() == infinity): + if self.hecke_n() == infinity: with localvars(self.parent()._pol_ring, "E4, f_i, E2, d"): latex_str = latex(self._rat) else: @@ -1095,12 +1094,12 @@ def diff_op(self, op, new_parent=None): mon_summand = mon_summand.derivative(x, mon.degree(dX)) mon_summand = mon_summand.derivative(y, mon.degree(dY)) mon_summand = mon_summand.derivative(z, mon.degree(dZ)) - mon_summand *= x**(mon.degree(X)) - mon_summand *= y**(mon.degree(Y)) - mon_summand *= z**(mon.degree(Z)) + mon_summand *= x ** (mon.degree(X)) + mon_summand *= y ** (mon.degree(Y)) + mon_summand *= z ** (mon.degree(Z)) new_rat += op.monomial_coefficient(mon) * mon_summand res = self.parent().rat_field()(new_rat) - if (new_parent is None): + if new_parent is None: new_parent = self.parent().extend_type(["quasi", "mero"], ring=True) return new_parent(res).reduce() @@ -1330,13 +1329,13 @@ def order_at(self, tau=infinity): i = QuadraticField(-1, 'I').gen() # if tau is a point of HyperbolicPlane then we use it's coordinates in the UHP model - if (tau in HyperbolicPlane()): + if tau in HyperbolicPlane(): tau = tau.to_model('UHP').coordinates() if self.is_zero(): return infinity - if (self.is_homogeneous() and self.is_modular()): + if self.is_homogeneous() and self.is_modular(): rat = self.parent().rat_field()(self._rat) R = self.parent().pol_ring() numerator = R(rat.numerator()) @@ -1344,19 +1343,19 @@ def order_at(self, tau=infinity): x, y, z, d = R.gens() n = self.hecke_n() - if (tau == i): + if tau == i: f_pol = y # This includes the case rho=1 resp. n=infinity - elif (tau == self.group().rho() or tau == -self.group().rho().conjugate()): + elif tau == self.group().rho() or tau == -self.group().rho().conjugate(): f_pol = x # We intentionally leave out the d-factor! - elif (tau == infinity): - if (n == infinity): + elif tau == infinity: + if n == infinity: f_pol = x - y**2 else: f_pol = x**n - y**2 - elif (tau.imag() > 0): - if (self.group().in_FD(tau)): + elif tau.imag() > 0: + if self.group().in_FD(tau): raise NotImplementedError("Orders at general points (here: tau={}) are not yet implemented!".format(tau)) else: w = self.group().get_FD(tau)[1] @@ -1368,7 +1367,7 @@ def order_at(self, tau=infinity): # There seems to be a bug in Singular, for now this "try, except" is a workaround # Also numerator /= f_pol doesn't seem to return an element of R for non-exact rings... try: - while (f_pol.divides(numerator)): + while f_pol.divides(numerator): numerator = numerator.quo_rem(f_pol)[0] # numerator /= f_pol numerator = R(numerator) @@ -1376,7 +1375,7 @@ def order_at(self, tau=infinity): except TypeError: pass try: - while (f_pol.divides(denom)): + while f_pol.divides(denom): denom = denom.quo_rem(f_pol)[0] # denom /= f_pol denom = R(denom) @@ -1391,10 +1390,10 @@ def order_at(self, tau=infinity): num_val = prec_num_bound = 1 # (self.parent()._prec/ZZ(2)).ceil() denom_val = prec_denom_bound = 1 # (self.parent()._prec/ZZ(2)).ceil() - while (num_val >= prec_num_bound): + while num_val >= prec_num_bound: prec_num_bound *= 2 num_val = self.numerator().q_expansion(prec=prec_num_bound, fix_prec=True).valuation() - while (denom_val >= prec_denom_bound): + while denom_val >= prec_denom_bound: prec_denom_bound *= 2 denom_val = self.denominator().q_expansion(prec=prec_denom_bound, fix_prec=True).valuation() @@ -1531,8 +1530,9 @@ def _q_expansion_cached(self, prec, fix_d, subs_d, d_num_prec, fix_prec=False): True """ if not fix_prec: - if ((not self.is_zero()) and prec <= self.order_at(infinity)): + if (not self.is_zero()) and prec <= self.order_at(infinity): from warnings import warn + warn("precision too low to determine any coefficient!") # This should _exactly_ ensure the given precision O(q^prec): @@ -1547,13 +1547,13 @@ def _q_expansion_cached(self, prec, fix_d, subs_d, d_num_prec, fix_prec=False): formal_d = self.parent().get_d() formal_q = self.parent().get_q(prec) - if (self.hecke_n() == infinity): + if self.hecke_n() == infinity: X = SC.E4_ZZ().base_extend(formal_d.parent()) else: X = SC.f_rho_ZZ().base_extend(formal_d.parent()) Y = SC.f_i_ZZ().base_extend(formal_d.parent()) - if (self.parent().is_modular()): + if self.parent().is_modular(): # z does not appear in self._rat but we need to specialize it for # the evaluation to land in the correct parent qexp = self._rat.subs(x=X, y=Y, z=0, d=formal_d) @@ -1565,13 +1565,13 @@ def _q_expansion_cached(self, prec, fix_d, subs_d, d_num_prec, fix_prec=False): qexp = qexp(formal_q / formal_d) cur_prec = qexp.prec() - if (subs_d): + if subs_d: fix_d = subs_d d = self.parent().get_d(fix_d, d_num_prec) q = self.parent().get_q(prec, fix_d, d_num_prec) - qexp = sum([(qexp.coefficients()[m]).subs(d=d) * q**qexp.exponents()[m] for m in range(len(qexp.coefficients()))]) - if (cur_prec != infinity): + qexp = sum([(qexp.coefficients()[m]).subs(d=d) * q ** qexp.exponents()[m] for m in range(len(qexp.coefficients()))]) + if cur_prec != infinity: qexp += O(q**cur_prec) else: qexp = (qexp + O(q)).parent()(qexp) @@ -1793,15 +1793,15 @@ def q_expansion_vector(self, min_exp=None, max_exp=None, prec=None, **kwargs): (516987/(8388608*d^4), 442989/(33554432*d^5)) """ - if (max_exp is None): + if max_exp is None: max_exp = self.parent().default_prec() - 1 else: max_exp = ZZ(max_exp) - if (prec is None): + if prec is None: prec = max_exp + 1 else: prec = ZZ(prec) - if (prec < max_exp + 1): + if prec < max_exp + 1: raise ValueError("The specified precision is too low: {} < {}".format(prec, max_exp + 1)) qexp = self.q_expansion(prec=prec, **kwargs) @@ -2130,26 +2130,24 @@ def evaluate(self, tau, prec=None, num_prec=None, check=False): i = QuadraticField(-1, 'I').gen() # if tau is a point of HyperbolicPlane then we use it's coordinates in the UHP model - if (tau in HyperbolicPlane()): + if tau in HyperbolicPlane(): tau = tau.to_model('UHP').coordinates() - if (prec is None): + if prec is None: prec = self.parent().default_prec() - if (num_prec is None): + if num_prec is None: num_prec = self.parent().default_num_prec() # In case the order is known try: - if (check or tau == infinity or tau == i or - tau == self.group().rho() or - tau == -self.group().rho().conjugate()): + if check or tau == infinity or tau == i or tau == self.group().rho() or tau == -self.group().rho().conjugate(): order_tau = self.order_at(tau) if order_tau > 0: return ZZ(0) - if (order_tau < 0): + if order_tau < 0: return infinity - if (tau == infinity): + if tau == infinity: return self.q_expansion(prec=1)[0] except (TypeError, NotImplementedError): pass @@ -2160,11 +2158,11 @@ def evaluate(self, tau, prec=None, num_prec=None, check=False): tau = tau.n(num_prec) (x, y, z, d) = self.parent().rat_field().gens() - if (self.is_homogeneous() and self.is_modular()): + if self.is_homogeneous() and self.is_modular(): q_exp = self.q_expansion_fixed_d(prec=prec, d_num_prec=num_prec) (A, w) = self.group().get_FD(tau) aut_factor = self.reduce(force=True).parent().aut_factor(A, w) - if (type(q_exp) is LaurentSeries): + if type(q_exp) is LaurentSeries: return q_exp.laurent_polynomial()(exp((2 * pi * i).n(num_prec) / self.group().lam() * w)) * aut_factor return q_exp.polynomial()(exp((2 * pi * i).n(num_prec) / self.group().lam() * w)) * aut_factor if self._rat == z: @@ -2172,7 +2170,7 @@ def evaluate(self, tau, prec=None, num_prec=None, check=False): (A, w) = self.group().get_FD(tau) aut_factor = E2.parent().aut_factor(A, w) E2_wvalue = E2.q_expansion_fixed_d(prec=prec, d_num_prec=num_prec).polynomial()(exp((2 * pi * i).n(num_prec) / self.group().lam() * w)) - if (self.hecke_n() == infinity): + if self.hecke_n() == infinity: E2_cor_term = 4 * self.group().lam() / (2 * pi * i).n(num_prec) * A.c() * (A.c() * w + A.d()) else: E2_cor_term = 4 * self.group().lam() / (2 * pi * i).n(num_prec) * self.hecke_n() / (self.hecke_n() - 2) * A.c() * (A.c() * w + A.d()) @@ -2180,7 +2178,7 @@ def evaluate(self, tau, prec=None, num_prec=None, check=False): f_i = self.parent().graded_ring().f_i() E2 = self.parent().graded_ring().E2() dval = self.parent().group().dvalue().n(num_prec) - if (self.hecke_n() == infinity): + if self.hecke_n() == infinity: E4 = self.parent().graded_ring().E4() return self._rat.subs(x=E4(tau), y=f_i(tau), z=E2(tau), d=dval) f_rho = self.parent().graded_ring().f_rho() diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py index 679a00270b8..5d4a287b7a1 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py @@ -97,6 +97,7 @@ class HeckeTriangleGroupElement(MatrixGroupElement_generic): r""" Elements of HeckeTriangleGroup. """ + def __init__(self, parent, M, check=True, **kwargs): r""" An element of HeckeTriangle group given by a matrix ``M``. @@ -222,17 +223,21 @@ def _word_S_T_data(self): while True: a, b, c, d = M.list() - mshift = coerce_AA((4*a*c + b*d) / (4*c*c + d*d)) + mshift = coerce_AA((4 * a * c + b * d) / (4 * c * c + d * d)) m = (mshift / lam + half).floor() if m != zero: - res.append((one, m),) - M = T**(-m) * M + res.append( + (one, m), + ) + M = T ** (-m) * M a, b, c, d = M.list() - abs_t = coerce_AA((4*a*a + b*b) / (4*c*c + d*d)) + abs_t = coerce_AA((4 * a * a + b * b) / (4 * c * c + d * d)) if coerce_AA(abs_t) < 1: M = (-S) * M - res.append((zero, one),) + res.append( + (zero, one), + ) elif M == ID: return (tuple(res), one) elif M == -ID: @@ -470,6 +475,7 @@ def string_repr(self, method='default'): if method == "block": if self.parent().n() == infinity: from warnings import warn + warn("The case n=infinity here is not verified at all and probably wrong!") L, R, sgn = self._block_decomposition_data() @@ -491,6 +497,7 @@ def string_repr(self, method='default'): if method == "conj": if self.parent().n() == infinity: from warnings import warn + warn("The case n=infinity here is not verified at all and probably wrong!") L, R, sgn = self._block_decomposition_data() @@ -604,6 +611,7 @@ def continued_fraction(self): """ if self.parent().n() == infinity: from warnings import warn + warn("The case n=infinity here is not verified at all and probably wrong!") if self.is_identity(): @@ -634,12 +642,12 @@ def continued_fraction(self): # elif self.is_elliptic(): # r = ZZ(emb(p/lam).real().floor() + 1) else: - emb_res = emb(p/lam) + emb_res = emb(p / lam) emb_res.simplify() emb_res.exactify() r = emb_res.floor() + one L.append(r) - p = (S*TI**r).acton(p) + p = (S * TI**r).acton(p) cf_index += one preperiod_len = cf_dict[p] @@ -772,6 +780,7 @@ def _primitive_block_decomposition_data(self): """ if self.parent().n() == infinity: from warnings import warn + warn("The case n=infinity here is not verified at all and probably wrong!") G = self.parent() @@ -800,18 +809,17 @@ def _primitive_block_decomposition_data(self): if embw == QQbar.gen(): R = -R L = (zero, one) - elif (embw == -one/G.rho()): - R = R*G.T().inverse() + elif embw == -one / G.rho(): + R = R * G.T().inverse() L = (one, one) else: - raise RuntimeError("There is something wrong in the method " - "_primitive_block_decomposition_data. Please contact sage-devel@googlegroups.com") + raise RuntimeError("There is something wrong in the method " "_primitive_block_decomposition_data. Please contact sage-devel@googlegroups.com") return (L, R) # The identity case (consistent with the notation in the parabolic case): if self.is_identity(): - return (((ZZ(self.parent().n()-one), zero),), G.I()) + return (((ZZ(self.parent().n() - one), zero),), G.I()) # The hyperbolic and parabolic case: # The parabolic case is much simpler but the same algorithm @@ -849,8 +857,8 @@ def _primitive_block_decomposition_data(self): L_len = len(L) k = 0 while k < L_len - 1: - if L[k][0] == L[k+1][0]: - k_entry = L.pop(k+1) + if L[k][0] == L[k + 1][0]: + k_entry = L.pop(k + 1) L[k][1] += k_entry[1] L_len -= 1 else: @@ -858,7 +866,7 @@ def _primitive_block_decomposition_data(self): if L_len > 1 and L[-1][0] == L[0][0]: k_entry = L.pop(-1) L[0][1] += k_entry[1] - R = G.V(L[0][0])**(-k_entry[1]) + R = G.V(L[0][0]) ** (-k_entry[1]) else: R = G.I() @@ -1026,6 +1034,7 @@ def primitive_representative(self, method='block'): """ if self.parent().n() == infinity: from warnings import warn + warn("The case n=infinity here is not verified at all and probably wrong!") G = self.parent() @@ -1048,19 +1057,18 @@ def primitive_representative(self, method='block'): if method == "cf": preperiod, period = self.continued_fraction() - P = prod((G.T()**r * G.S() for r in period), G.I()) - R = prod((G.T()**r * G.S() for r in preperiod), G.I()) + P = prod((G.T() ** r * G.S() for r in period), G.I()) + R = prod((G.T() ** r * G.S() for r in preperiod), G.I()) return (P, R) if method == "block": data_list, R = self._primitive_block_decomposition_data() - P = prod((G.V(v[0])**v[1] for v in data_list), G.I()) + P = prod((G.V(v[0]) ** v[1] for v in data_list), G.I()) return (P, R) - raise ValueError("if the element is not elliptic, then method must " - "be either be 'cf' or 'block'") + raise ValueError("if the element is not elliptic, then method must " "be either be 'cf' or 'block'") def primitive_part(self, method='cf'): r""" @@ -1147,6 +1155,7 @@ def primitive_part(self, method='cf'): """ if self.parent().n() == infinity: from warnings import warn + warn("The case n=infinity here is not verified at all and probably wrong!") P, R = self.primitive_representative(method=method) @@ -1205,6 +1214,7 @@ def reduce(self, primitive=True): """ if self.parent().n() == infinity: from warnings import warn + warn("The case n=infinity here is not verified at all and probably wrong!") P, R = self.primitive_representative(method='cf') @@ -1332,6 +1342,7 @@ def primitive_power(self, method='cf'): """ if self.parent().n() == infinity: from warnings import warn + warn("The case n=infinity here is not verified at all and probably wrong!") zero = ZZ.zero() @@ -1362,17 +1373,16 @@ def primitive_power(self, method='cf'): # L = [one, ZZ(-j)] break else: - raise RuntimeError("There is a problem in the method " - "'primitive_power'. Please contact sage-devel@googlegroups.com") + raise RuntimeError("There is a problem in the method " "'primitive_power'. Please contact sage-devel@googlegroups.com") - if abs(j) < G.n()/two: + if abs(j) < G.n() / two: return j - if two*j == G.n(): + if two * j == G.n(): return j # for the cases from here on the sign has to be adjusted # to the # sign of self (in self._block_decomposition_data()) - if two*j == -G.n(): + if two * j == -G.n(): return -j if j > 0: return j - G.n() @@ -1392,7 +1402,7 @@ def primitive_power(self, method='cf'): M *= primitive_part power += 1 - return power*power_sign + return power * power_sign def block_length(self, primitive=False): r""" @@ -1491,6 +1501,7 @@ def block_length(self, primitive=False): """ if self.parent().n() == infinity: from warnings import warn + warn("The case n=infinity here is not verified at all and probably wrong!") if primitive: @@ -1631,6 +1642,7 @@ def _block_decomposition_data(self): """ if self.parent().n() == infinity: from warnings import warn + warn("The case n=infinity here is not verified at all and probably wrong!") L, R = self._primitive_block_decomposition_data() @@ -1740,6 +1752,7 @@ def block_decomposition(self): """ if self.parent().n() == infinity: from warnings import warn + warn("The case n=infinity here is not verified at all and probably wrong!") G = self.parent() @@ -1760,8 +1773,8 @@ def block_decomposition(self): P = G.S() else: P = G.U() - return ((P**L[1],), R, sgn) - return (tuple(G.V(v[0])**v[1] for v in L), R, sgn) + return ((P ** L[1],), R, sgn) + return (tuple(G.V(v[0]) ** v[1] for v in L), R, sgn) def conjugacy_type(self, ignore_sign=True, primitive=False): r""" @@ -1821,6 +1834,7 @@ def conjugacy_type(self, ignore_sign=True, primitive=False): """ if self.parent().n() == infinity: from warnings import warn + warn("The case n=infinity here is not verified at all and probably wrong!") if primitive: @@ -1877,6 +1891,7 @@ def reduced_elements(self): """ if self.parent().n() == infinity: from warnings import warn + warn("The case n=infinity here is not verified at all and probably wrong!") if self.is_identity() or self.is_elliptic(): @@ -1894,7 +1909,7 @@ def rotate(l, n): if cur_period in period_set: continue period_set.add(cur_period) - L.append(prod((G.T()**r * G.S() for r in cur_period), G.I())) + L.append(prod((G.T() ** r * G.S() for r in cur_period), G.I())) return L @@ -1967,6 +1982,7 @@ class of ``self``. """ if self.parent().n() == infinity: from warnings import warn + warn("The case n=infinity here is not verified at all and probably wrong!") if not self.is_hyperbolic(): @@ -2027,6 +2043,7 @@ def simple_fixed_point_set(self, extended=True): """ if self.parent().n() == infinity: from warnings import warn + warn("The case n=infinity here is not verified at all and probably wrong!") if self.is_identity() or self.is_elliptic(): @@ -2177,7 +2194,7 @@ def discriminant(self): sage: AA(G.V(3).discriminant()) 16.19566935808922? """ - return self.trace()**2 - 4 + return self.trace() ** 2 - 4 def is_translation(self, exclude_one=False) -> bool: r""" @@ -2331,6 +2348,7 @@ def is_primitive(self) -> bool: """ if self.parent().n() == infinity: from warnings import warn + warn("The case n=infinity here is not verified at all and probably wrong!") pow = self.primitive_power() @@ -2341,11 +2359,10 @@ def is_primitive(self) -> bool: # if this is not up-to-sign then a factor 2 should # be added before (the second) self.parent().n() - return (pow % (2*self.parent().n())).gcd(self.parent().n()) == 1 + return (pow % (2 * self.parent().n())).gcd(self.parent().n()) == 1 return abs(pow) <= 1 - def is_reduced(self, require_primitive=True, - require_hyperbolic=True) -> bool: + def is_reduced(self, require_primitive=True, require_hyperbolic=True) -> bool: r""" Return whether ``self`` is reduced. @@ -2402,6 +2419,7 @@ def is_reduced(self, require_primitive=True, """ if self.parent().n() == infinity: from warnings import warn + warn("The case n=infinity here is not verified at all and probably wrong!") if self.is_identity() or self.is_elliptic(): @@ -2476,7 +2494,7 @@ def is_simple(self) -> bool: # The last condition is/should be equivalent to: a, b, c, d = self._matrix.list() - return (coerce_AA(a) > 0 and coerce_AA(b) > 0 and coerce_AA(c) > 0 and coerce_AA(d) > 0) + return coerce_AA(a) > 0 and coerce_AA(b) > 0 and coerce_AA(c) > 0 and coerce_AA(d) > 0 def is_hecke_symmetric(self) -> bool: r""" @@ -2527,6 +2545,7 @@ def is_hecke_symmetric(self) -> bool: """ if self.parent().n() == infinity: from warnings import warn + warn("The case n=infinity here is not verified at all and probably wrong!") if self.is_identity() or self.is_elliptic(): @@ -2650,6 +2669,7 @@ def rational_period_function(self, k): """ if self.parent().n() == infinity: from warnings import warn + warn("The case n=infinity here is not verified at all and probably wrong!") if self.is_identity() or self.is_elliptic(): @@ -2663,6 +2683,7 @@ def rational_period_function(self, k): raise ValueError(f"k={k} must be an even integer!") from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + P = PolynomialRing(self.parent().base_ring(), 'z') z = P.gen() @@ -2671,13 +2692,13 @@ def rational_period_function(self, k): # L1 = [] for v in self.simple_elements(): a, b, c, d = v._matrix.list() - Q = c*z**2 + (d - a)*z - b - s += Q**(-k/ZZ(2)) + Q = c * z**2 + (d - a) * z - b + s += Q ** (-k / ZZ(2)) for v in self.inverse().simple_elements(): a, b, c, d = v._matrix.list() - Q = c*z**2 + (d - a)*z - b - s -= ZZ(-1)**(k/ZZ(2)) * Q**(-k/ZZ(2)) + Q = c * z**2 + (d - a) * z - b + s -= ZZ(-1) ** (k / ZZ(2)) * Q ** (-k / ZZ(2)) return s @@ -2818,13 +2839,13 @@ def linking_number(self): if self.is_elliptic(): if L[0] == 0: return ZZ(0) - if 2*L[1] == n: + if 2 * L[1] == n: return ZZ(0) - return ZZ(-2*L[1]) + return ZZ(-2 * L[1]) t = sum(v[1] for v in L) - u = sum((v[0]-1) for v in L) + u = sum((v[0] - 1) for v in L) - return ZZ((n-2)*t - 2*u) + return ZZ((n - 2) * t - 2 * u) def root_extension_field(self): r""" @@ -3057,8 +3078,8 @@ def fixed_points(self, embedded=False, order='default'): d = coerce_AA(d) c = coerce_AA(c) - root1 = (a-d)/(2*c) + sgn*e/(2*c) - root2 = (a-d)/(2*c) - sgn*e/(2*c) + root1 = (a - d) / (2 * c) + sgn * e / (2 * c) + root2 = (a - d) / (2 * c) - sgn * e / (2 * c) if embedded: root1.simplify() @@ -3144,11 +3165,11 @@ def acton(self, tau): """ if tau.parent() == self.parent(): - return self*tau*self.inverse() + return self * tau * self.inverse() # if tau is a point of HyperbolicPlane then we use it's coordinates in the UHP model model = None - if (tau in HyperbolicPlane()): + if tau in HyperbolicPlane(): model = tau.model() tau = tau.to_model('UHP').coordinates() @@ -3158,11 +3179,11 @@ def acton(self, tau): if c.is_zero(): result = infinity else: - result = a/c - elif c*tau + d == 0: + result = a / c + elif c * tau + d == 0: result = infinity else: - result = (a*tau + b) / (c*tau + d) + result = (a * tau + b) / (c * tau + d) if model is None: return result @@ -3204,8 +3225,8 @@ def _act_on_(self, other, self_on_left): lam """ - if (self_on_left): - if (other == infinity or other in CC or other in HyperbolicPlane()): + if self_on_left: + if other == infinity or other in CC or other in HyperbolicPlane(): return self.acton(other) return None @@ -3293,10 +3314,10 @@ def slash(self, f, tau=None, k=None): except (ValueError, TypeError, AttributeError): raise ValueError("f={} is not a rational function or a polynomial in one variable, so tau has to be specified explicitly!".format(f)) - if (tau in HyperbolicPlane()): + if tau in HyperbolicPlane(): tau = tau.to_model('UHP').coordinates() - return (self.c()*tau + self.d())**(-k) * f(self.acton(tau)) + return (self.c() * tau + self.d()) ** (-k) * f(self.acton(tau)) def as_hyperbolic_plane_isometry(self, model='UHP'): r""" @@ -3323,4 +3344,5 @@ def as_hyperbolic_plane_isometry(self, model='UHP'): in Category of hyperbolic models of Hyperbolic plane """ from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane + return HyperbolicPlane().UHP().get_isometry(self._matrix).to_model(model) diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py index 069a6c89483..00da804ef0e 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py @@ -40,8 +40,7 @@ from .hecke_triangle_group_element import HeckeTriangleGroupElement, cyclic_representative, coerce_AA -class HeckeTriangleGroup(FinitelyGeneratedMatrixGroup_generic, - UniqueRepresentation): +class HeckeTriangleGroup(FinitelyGeneratedMatrixGroup_generic, UniqueRepresentation): r""" Hecke triangle group `(2, n, \infty)`. """ @@ -99,8 +98,7 @@ def __init__(self, n): self._lam = ZZ.one() if n == 3 else ZZ(2) else: lam_symbolic = coerce_AA(E(2 * n) + ~E(2 * n)) - K = NumberField(self.lam_minpoly(), 'lam', - embedding=lam_symbolic) + K = NumberField(self.lam_minpoly(), 'lam', embedding=lam_symbolic) # self._base_ring = K.order(K.gens()) self._base_ring = K.maximal_order() self._lam = self._base_ring.gen(1) @@ -410,8 +408,7 @@ def T(self, m=1): sage: HeckeTriangleGroup(10).T().parent() Hecke triangle group for n = 10 """ - return self(matrix(self._base_ring, [[1, self._lam * m], [0, 1]]), - check=False) + return self(matrix(self._base_ring, [[1, self._lam * m], [0, 1]]), check=False) # We use cached method here to create unique instances of basic matrices # (major performance gain) @@ -521,7 +518,7 @@ def V(self, j): sage: G.V(5) == G.S() True """ - return self.U()**(j-1) * self.T() + return self.U() ** (j - 1) * self.T() def dvalue(self): r""" @@ -549,16 +546,15 @@ def dvalue(self): """ n = self._n if n == 3: - return 1 / ZZ(2**6*3**3) + return 1 / ZZ(2**6 * 3**3) if n == 4: return 1 / ZZ(2**8) if n == 6: - return 1 / ZZ(2**2*3**3) + return 1 / ZZ(2**2 * 3**3) if n == infinity: return 1 / ZZ(2**6) # reference for this formula ? - return exp(-ZZ(2)*psi1(ZZ.one()) + psi1(ZZ.one()-self.alpha()) - + psi1(ZZ.one()-self.beta()) - pi*sec(pi/self._n)) + return exp(-ZZ(2) * psi1(ZZ.one()) + psi1(ZZ.one() - self.alpha()) + psi1(ZZ.one() - self.beta()) - pi * sec(pi / self._n)) def is_arithmetic(self) -> bool: r""" @@ -638,19 +634,19 @@ def get_FD(self, z): while abs(w) < ZZ.one() or abs(w.real()) > self.lam() / ZZ(2): if abs(w) < ZZ.one(): w = self.S().acton(w) - A = S*A + A = S * A while w.real() >= self.lam() / ZZ(2): w = TI.acton(w) - A = TI*A + A = TI * A while w.real() < -self.lam() / ZZ(2): w = T.acton(w) - A = T*A + A = T * A if w.real() == self.lam() / ZZ(2): w = TI.acton(w) - A = TI*A + A = TI * A if abs(w) == ZZ.one() and w.real() > ZZ.zero(): w = S.acton(w) - A = S*A + A = S * A AI = A.inverse() @@ -878,10 +874,7 @@ def _elliptic_conj_reps(self): self._conj_prim[D] = [] self._conj_prim[D].append(self.S()) - other_reps = [self.U()**k - for k in range(-((self.n() - 1) / 2).floor(), - self.n() // 2 + 1) - if k not in [0, 1]] + other_reps = [self.U() ** k for k in range(-((self.n() - 1) / 2).floor(), self.n() // 2 + 1) if k not in [0, 1]] for v in other_reps: D = v.discriminant() @@ -959,8 +952,7 @@ def _conjugacy_representatives(self, max_block_length=0, D=None): from sage.combinat.combinat import tuples if D is not None: - max_block_length = max(AA.zero(), - coerce_AA((D + 4)/(self.lam()**2))).sqrt().floor() + max_block_length = max(AA.zero(), coerce_AA((D + 4) / (self.lam() ** 2))).sqrt().floor() else: try: max_block_length = ZZ(max_block_length) @@ -986,7 +978,7 @@ def _conjugacy_representatives(self, max_block_length=0, D=None): # We set it here to ensure that 0 is enlisted as a discriminant... # self._conj_prim[ZZ.zero()] = [] - self._conj_prim[ZZ.zero()].append(self.V(self.n()-1)) + self._conj_prim[ZZ.zero()].append(self.V(self.n() - 1)) self._elliptic_conj_reps() @@ -1034,7 +1026,7 @@ def is_cycle_of_length(seq, n) -> bool: self._conj_block[t_ZZ].add(conj_type) for el in self._conj_block[t_ZZ]: - group_el = prod([self.V(el[k][0])**el[k][1] for k in range(len(el))]) + group_el = prod([self.V(el[k][0]) ** el[k][1] for k in range(len(el))]) D = group_el.discriminant() assert coerce_AA(D) > 0 @@ -1222,8 +1214,7 @@ def is_discriminant(self, D, primitive=True) -> bool: False """ self._conjugacy_representatives(0) - t_bound = max(AA.zero(), - coerce_AA((D + 4) / (self.lam()**2))).sqrt().floor() + t_bound = max(AA.zero(), coerce_AA((D + 4) / (self.lam() ** 2))).sqrt().floor() for t in range(self._max_block_length + 1, t_bound + 1): self._conjugacy_representatives(t) @@ -1287,11 +1278,9 @@ def list_discriminants(self, D, primitive=True, hyperbolic=True, incomplete=Fals if not primitive: if hyperbolic: - L += [key for key in self._conj_nonprim - if 0 < coerce_AA(key) <= max_D and key not in L] + L += [key for key in self._conj_nonprim if 0 < coerce_AA(key) <= max_D and key not in L] else: - L += [key for key in self._conj_nonprim - if coerce_AA(key) <= max_D and key not in L] + L += [key for key in self._conj_nonprim if coerce_AA(key) <= max_D and key not in L] return sorted(L, key=coerce_AA) @@ -1409,9 +1398,9 @@ def rational_period_functions(self, k, D): R = [] if k != 0: - R.append(ZZ(1) - z**(-k)) + R.append(ZZ(1) - z ** (-k)) if k == 2: - R.append(z**(-1)) + R.append(z ** (-1)) L = self.class_representatives(D=D, primitive=True) for v in L: diff --git a/src/sage/modular/modform_hecketriangle/series_constructor.py b/src/sage/modular/modform_hecketriangle/series_constructor.py index db8b981700d..a516d954aa0 100644 --- a/src/sage/modular/modform_hecketriangle/series_constructor.py +++ b/src/sage/modular/modform_hecketriangle/series_constructor.py @@ -65,7 +65,7 @@ def __classcall__(cls, group=HeckeTriangleGroup(3), prec=ZZ(10)): sage: MFSeriesConstructor(group=5, prec=12).prec() 12 """ - if (group == infinity): + if group == infinity: group = HeckeTriangleGroup(infinity) else: try: @@ -131,8 +131,7 @@ def _repr_(self): Power series constructor for Hecke modular forms for n=5 with (basic series) precision 12 """ - return "Power series constructor for Hecke modular forms for n={} with (basic series) precision {}".\ - format(self._group.n(), self._prec) + return "Power series constructor for Hecke modular forms for n={} with (basic series) precision {}".format(self._group.n(), self._prec) def group(self): r""" @@ -204,23 +203,12 @@ def J_inv_ZZ(self): sage: MFSeriesConstructor(group=infinity, prec=3).J_inv_ZZ() q^-1 + 3/8 + 69/1024*q + O(q^2) """ + def F1(a, b): - return self._series_ring( - [ZZ.zero()] - + [rising_factorial(a, k) * rising_factorial(b, k) / (ZZ(k).factorial())**2 - * sum(ZZ.one()/(a+j) + ZZ.one()/(b+j) - ZZ(2)/ZZ(1+j) - for j in range(k)) - for k in range(1, self._prec + 1) - ], - ZZ(self._prec + 1) - ) + return self._series_ring([ZZ.zero()] + [rising_factorial(a, k) * rising_factorial(b, k) / (ZZ(k).factorial()) ** 2 * sum(ZZ.one() / (a + j) + ZZ.one() / (b + j) - ZZ(2) / ZZ(1 + j) for j in range(k)) for k in range(1, self._prec + 1)], ZZ(self._prec + 1)) def F(a, b, c): - return self._series_ring( - [rising_factorial(a, k) * rising_factorial(b, k) / rising_factorial(c, k) / ZZ(k).factorial() - for k in range(self._prec + 1)], - ZZ(self._prec + 1) - ) + return self._series_ring([rising_factorial(a, k) * rising_factorial(b, k) / rising_factorial(c, k) / ZZ(k).factorial() for k in range(self._prec + 1)], ZZ(self._prec + 1)) a = self._group.alpha() b = self._group.beta() @@ -232,7 +220,7 @@ def F(a, b, c): temp_f = (q * Phi.exp()).polynomial() new_f = temp_f.revert_series(temp_f.degree() + 1) - return ZZ.one() / (new_f + O(q**(temp_f.degree() + 1))) + return ZZ.one() / (new_f + O(q ** (temp_f.degree() + 1))) @cached_method def f_rho_ZZ(self): @@ -261,11 +249,11 @@ def f_rho_ZZ(self): q = self._series_ring.gen() n = self.hecke_n() - if (n == infinity): + if n == infinity: f_rho_ZZ = self._series_ring(1) else: - temp_expr = ((-q*self.J_inv_ZZ().derivative())**2/(self.J_inv_ZZ()*(self.J_inv_ZZ()-1))).power_series() - f_rho_ZZ = (temp_expr.log()/(n-2)).exp() + temp_expr = ((-q * self.J_inv_ZZ().derivative()) ** 2 / (self.J_inv_ZZ() * (self.J_inv_ZZ() - 1))).power_series() + f_rho_ZZ = (temp_expr.log() / (n - 2)).exp() return f_rho_ZZ @cached_method @@ -295,11 +283,11 @@ def f_i_ZZ(self): q = self._series_ring.gen() n = self.hecke_n() - if (n == infinity): - f_i_ZZ = (-q*self.J_inv_ZZ().derivative()/self.J_inv_ZZ()).power_series() + if n == infinity: + f_i_ZZ = (-q * self.J_inv_ZZ().derivative() / self.J_inv_ZZ()).power_series() else: - temp_expr = ((-q*self.J_inv_ZZ().derivative())**n/(self.J_inv_ZZ()**(n-1)*(self.J_inv_ZZ()-1))).power_series() - f_i_ZZ = (temp_expr.log()/(n-2)).exp() + temp_expr = ((-q * self.J_inv_ZZ().derivative()) ** n / (self.J_inv_ZZ() ** (n - 1) * (self.J_inv_ZZ() - 1))).power_series() + f_i_ZZ = (temp_expr.log() / (n - 2)).exp() return f_i_ZZ @cached_method @@ -329,11 +317,11 @@ def f_inf_ZZ(self): q = self._series_ring.gen() n = self.hecke_n() - if (n == infinity): - f_inf_ZZ = ((-q*self.J_inv_ZZ().derivative())**2/(self.J_inv_ZZ()**2*(self.J_inv_ZZ()-1))).power_series() + if n == infinity: + f_inf_ZZ = ((-q * self.J_inv_ZZ().derivative()) ** 2 / (self.J_inv_ZZ() ** 2 * (self.J_inv_ZZ() - 1))).power_series() else: - temp_expr = ((-q*self.J_inv_ZZ().derivative())**(2*n)/(self.J_inv_ZZ()**(2*n-2)*(self.J_inv_ZZ()-1)**n)/q**(n-2)).power_series() - f_inf_ZZ = (temp_expr.log()/(n-2)).exp()*q + temp_expr = ((-q * self.J_inv_ZZ().derivative()) ** (2 * n) / (self.J_inv_ZZ() ** (2 * n - 2) * (self.J_inv_ZZ() - 1) ** n) / q ** (n - 2)).power_series() + f_inf_ZZ = (temp_expr.log() / (n - 2)).exp() * q return f_inf_ZZ @cached_method @@ -365,10 +353,10 @@ def G_inv_ZZ(self): # the behavior at -1) if n == infinity: q = self._series_ring.gen() - temp_expr = (self.J_inv_ZZ()/self.f_inf_ZZ()*q**2).power_series() - return 1/q*self.f_i_ZZ()*(temp_expr.log()/2).exp() - if (ZZ(2).divides(n)): - return self.f_i_ZZ()*(self.f_rho_ZZ()**(ZZ(n/ZZ(2))))/self.f_inf_ZZ() + temp_expr = (self.J_inv_ZZ() / self.f_inf_ZZ() * q**2).power_series() + return 1 / q * self.f_i_ZZ() * (temp_expr.log() / 2).exp() + if ZZ(2).divides(n): + return self.f_i_ZZ() * (self.f_rho_ZZ() ** (ZZ(n / ZZ(2)))) / self.f_inf_ZZ() raise ValueError("G_inv doesn't exist for n={}.".format(self.hecke_n())) @cached_method @@ -396,7 +384,7 @@ def E4_ZZ(self): 1 + 1/4*q + 7/256*q^2 + O(q^3) """ q = self._series_ring.gen() - return ((-q*self.J_inv_ZZ().derivative())**2 / (self.J_inv_ZZ()*(self.J_inv_ZZ()-1))).power_series() + return ((-q * self.J_inv_ZZ().derivative()) ** 2 / (self.J_inv_ZZ() * (self.J_inv_ZZ() - 1))).power_series() @cached_method def E6_ZZ(self): @@ -423,7 +411,7 @@ def E6_ZZ(self): 1 - 1/8*q - 31/512*q^2 + O(q^3) """ q = self._series_ring.gen() - return ((-q*self.J_inv_ZZ().derivative())**3 / (self.J_inv_ZZ()**2*(self.J_inv_ZZ()-1))).power_series() + return ((-q * self.J_inv_ZZ().derivative()) ** 3 / (self.J_inv_ZZ() ** 2 * (self.J_inv_ZZ() - 1))).power_series() @cached_method def Delta_ZZ(self): @@ -450,7 +438,7 @@ def Delta_ZZ(self): q + 3/8*q^2 + 63/1024*q^3 + O(q^4) """ - return (self.f_inf_ZZ()**3*self.J_inv_ZZ()**2/(self.f_rho_ZZ()**6)).power_series() + return (self.f_inf_ZZ() ** 3 * self.J_inv_ZZ() ** 2 / (self.f_rho_ZZ() ** 6)).power_series() @cached_method def E2_ZZ(self): @@ -534,11 +522,11 @@ def EisensteinSeries_ZZ(self, k): try: if k < 0: raise TypeError(None) - k = 2*ZZ(k/2) + k = 2 * ZZ(k / 2) except TypeError: raise TypeError("k={} has to be a nonnegative even integer!".format(k)) - if (not self.group().is_arithmetic() or self.group().n() == infinity): + if not self.group().is_arithmetic() or self.group().n() == infinity: # Exceptional cases should be called manually (see in FormsRing_abstract) raise NotImplementedError("Eisenstein series are only supported in the finite arithmetic cases!") @@ -546,8 +534,8 @@ def EisensteinSeries_ZZ(self, k): if k == 0: return self._series_ring(1) - M = ZZ(self.group().lam()**2) - lamk = M**(ZZ(k/2)) + M = ZZ(self.group().lam() ** 2) + lamk = M ** (ZZ(k / 2)) dval = self.group().dvalue() def coeff(m): @@ -557,23 +545,23 @@ def coeff(m): if m == 0: return ZZ(1) - factor = -2*k / QQ(bernoulli(k)) / lamk - sum1 = sigma(m, k-1) + factor = -2 * k / QQ(bernoulli(k)) / lamk + sum1 = sigma(m, k - 1) if M.divides(m): - sum2 = (lamk-1) * sigma(ZZ(m/M), k-1) + sum2 = (lamk - 1) * sigma(ZZ(m / M), k - 1) else: sum2 = ZZ(0) - if (M == 1): + if M == 1: sum3 = ZZ(0) else: - if (m == 1): + if m == 1: N = ZZ(1) else: - N = ZZ(m / M**ZZ(m.valuation(M))) - sum3 = -sigma(ZZ(N), k-1) * ZZ(m/N)**(k-1) / (lamk + 1) + N = ZZ(m / M ** ZZ(m.valuation(M))) + sum3 = -sigma(ZZ(N), k - 1) * ZZ(m / N) ** (k - 1) / (lamk + 1) return factor * (sum1 + sum2 + sum3) * dval**m q = self._series_ring.gen() - return sum([coeff(m)*q**m for m in range(self.prec())]).add_bigoh(self.prec()) + return sum([coeff(m) * q**m for m in range(self.prec())]).add_bigoh(self.prec()) diff --git a/src/sage/modular/modform_hecketriangle/space.py b/src/sage/modular/modform_hecketriangle/space.py index 2e2093d4d04..3f5835914ad 100644 --- a/src/sage/modular/modform_hecketriangle/space.py +++ b/src/sage/modular/modform_hecketriangle/space.py @@ -57,17 +57,17 @@ def canonical_parameters(group, base_ring, k, ep, n=None): k = QQ(k) if ep is None: if n == infinity: - ep = (-1)**(k / 2) + ep = (-1) ** (k / 2) elif ZZ(2).divides(n): - ep = (-1)**(k*ZZ(n-2)/ZZ(4)) + ep = (-1) ** (k * ZZ(n - 2) / ZZ(4)) else: - ep = (-1)**(k*ZZ(n-2)/ZZ(2)) + ep = (-1) ** (k * ZZ(n - 2) / ZZ(2)) ep = ZZ(ep) if n == infinity: - num = (k-(1-ep)) / ZZ(4) + num = (k - (1 - ep)) / ZZ(4) else: - num = (k-(1-ep)*n/(n-2)) * (n-2) / ZZ(4) + num = (k - (1 - ep) * n / (n - 2)) * (n - 2) / ZZ(4) try: num = ZZ(num) @@ -819,8 +819,7 @@ def gens(self) -> tuple: sage: MF.gen(0) == MF.E4()*MF.f_inf() True """ - return tuple(self.F_basis(m, order_1=ZZ.one()) - for m in range(1, self.dimension() + 1)) + return tuple(self.F_basis(m, order_1=ZZ.one()) for m in range(1, self.dimension() + 1)) @cached_method def dimension(self): @@ -972,8 +971,7 @@ def _change_degree(self, k, ep): sage: MF._change_degree(14, -1) ZeroForms(n=3, k=14, ep=-1) over Integer Ring """ - return ZeroForm(group=self.group(), base_ring=self.base_ring(), - k=k, ep=ep) + return ZeroForm(group=self.group(), base_ring=self.base_ring(), k=k, ep=ep) @cached_method def gens(self) -> tuple: diff --git a/src/sage/modular/modform_hecketriangle/subspace.py b/src/sage/modular/modform_hecketriangle/subspace.py index b67c3f47bc0..e437e744048 100644 --- a/src/sage/modular/modform_hecketriangle/subspace.py +++ b/src/sage/modular/modform_hecketriangle/subspace.py @@ -288,7 +288,7 @@ def contains_coeff_ring(self): sage: subspace.contains_coeff_ring() False """ - return (super().contains_coeff_ring() and self.dimension() == 1) + return super().contains_coeff_ring() and self.dimension() == 1 @cached_method def basis(self): diff --git a/src/sage/modular/modsym/all.py b/src/sage/modular/modsym/all.py index f398a735a1e..c53336bc097 100644 --- a/src/sage/modular/modsym/all.py +++ b/src/sage/modular/modsym/all.py @@ -13,4 +13,5 @@ from sage.modular.modsym.ghlist import GHlist from sage.modular.modsym.g1list import G1list + del lazy_import diff --git a/src/sage/modular/modsym/ambient.py b/src/sage/modular/modsym/ambient.py index 50fc7bcbf92..da048841675 100644 --- a/src/sage/modular/modsym/ambient.py +++ b/src/sage/modular/modsym/ambient.py @@ -142,8 +142,8 @@ class ModularSymbolsAmbient(ModularSymbolsSpace, AmbientHeckeModule): sage: hash(ModularSymbols(11,2)) != hash(ModularSymbols(11,4)) True """ - def __init__(self, group, weight, sign, base_ring, - character=None, custom_init=None, category=None): + + def __init__(self, group, weight, sign, base_ring, character=None, custom_init=None, category=None): """ Initialize a space of modular symbols. @@ -175,9 +175,7 @@ def __init__(self, group, weight, sign, base_ring, if character is None and isinstance(group, arithgroup.Gamma0_class): character = TrivialCharacter(group.level(), base_ring) - ModularSymbolsSpace.__init__(self, group, weight, - character, sign, base_ring, - category=category) + ModularSymbolsSpace.__init__(self, group, weight, character, sign, base_ring, category=category) if custom_init is not None: custom_init(self) @@ -189,10 +187,7 @@ def __init__(self, group, weight, sign, base_ring, rank = self.rank() if formula is not None: - assert rank == formula, \ - "Computed dimension (=%s) of ambient space \"%s\" doesn't match dimension formula (=%s)!\n" % (rank, self, formula) + \ - "ModularSymbolsAmbient: group = %s, weight = %s, sign = %s, base_ring = %s, character = %s" % ( - group, weight, sign, base_ring, character) + assert rank == formula, "Computed dimension (=%s) of ambient space \"%s\" doesn't match dimension formula (=%s)!\n" % (rank, self, formula) + "ModularSymbolsAmbient: group = %s, weight = %s, sign = %s, base_ring = %s, character = %s" % (group, weight, sign, base_ring, character) AmbientHeckeModule.__init__(self, base_ring, rank, group.level(), weight, category=category) @@ -291,10 +286,10 @@ def p1list(self): self.__p1list = p1list.P1List(self.level()) return self.__p1list -# See the file relation_matrix.py -# -# def relation_matrix(self): -# raise NotImplementedError + # See the file relation_matrix.py + # + # def relation_matrix(self): + # raise NotImplementedError def compute_presentation(self): r""" @@ -304,9 +299,7 @@ def compute_presentation(self): sage: ModularSymbols(11,2).compute_presentation() # no output """ - B, basis, mod = relation_matrix.compute_presentation( - self.manin_symbols(), self.sign(), - self.base_ring()) + B, basis, mod = relation_matrix.compute_presentation(self.manin_symbols(), self.sign(), self.base_ring()) self._manin_generators = self.manin_symbols().manin_symbol_list() self._manin_basis = basis self._manin_gens_to_basis = B @@ -439,9 +432,7 @@ def _element_constructor_(self, x, computed_with_hecke=False): """ if isinstance(x, FreeModuleElement): if x.degree() != self.dimension(): - raise TypeError("Incompatible degrees: x has degree " - f"{x.degree()} but modular symbols space has " - f"dimension {self.dimension()}") + raise TypeError("Incompatible degrees: x has degree " f"{x.degree()} but modular symbols space has " f"dimension {self.dimension()}") return self.element_class(self, x) if isinstance(x, (ManinSymbol, element.ModularSymbolsElement)): @@ -559,9 +550,11 @@ def manin_symbol(self, x, check=True): if len(x) == 3: # Manin symbol of the form (i, u, v), which corresponds to [X^i*Y^(k-2-i), (u,v)]. if x[0] < 0 or x[0] > self.weight() - 2: - raise ValueError("The first entry of the tuple (=%s)\ - must be an integer between 0 and k-2 (=%s)." % ( - x, self.weight() - 2)) + raise ValueError( + "The first entry of the tuple (=%s)\ + must be an integer between 0 and k-2 (=%s)." + % (x, self.weight() - 2) + ) else: raise ValueError("x (=%s) must be of length 2 or 3" % x) # end check @@ -631,9 +624,9 @@ def _modular_symbol_0_to_alpha(self, alpha, i=0): w = 0 else: x = c[k][0] - y = c[k-1][0] + y = c[k - 1][0] z = c[k][1] - w = c[k-1][1] + w = c[k - 1][1] if k % 2 == 0: y = -y w = -w @@ -647,27 +640,27 @@ def _modular_symbol_0_to_alpha(self, alpha, i=0): # method 1: write out solution. this is currently # incorrect, because it ends up doing 0^0 in the sum, # so I'll fix it and do timings soon. -# for s in range(self.weight()-two+1): -# coeff = sum([ binomial(i,t)*binomial(self.weight()-two-i,s-t)* -# x**t * y**(i-t) * z**(s-t) * -# w**(self.weight()-two-i-s+t) for t in range(0,s) ]) -# m = coeff * self.manin_symbol((s, y, w), check=False) -# a += m + # for s in range(self.weight()-two+1): + # coeff = sum([ binomial(i,t)*binomial(self.weight()-two-i,s-t)* + # x**t * y**(i-t) * z**(s-t) * + # w**(self.weight()-two-i-s+t) for t in range(0,s) ]) + # m = coeff * self.manin_symbol((s, y, w), check=False) + # a += m # method 2 - p1 = x*X+y - p2 = z*X+w + p1 = x * X + y + p2 = z * X + w if i == 0: p1 = R(one) - if (self.weight()-2-i == 0): + if self.weight() - 2 - i == 0: p2 = R(one) - poly = (p1**i) * (p2**(self.weight()-2-i)) - for s in range(self.weight()-1): # k-2+1 = k-1 + poly = (p1**i) * (p2 ** (self.weight() - 2 - i)) + for s in range(self.weight() - 1): # k-2+1 = k-1 a += poly[s] * self.manin_symbol((s, z, w), check=False) else: for k in range(1, len(c)): u = c[k][1] - v = c[k-1][1] + v = c[k - 1][1] if k % 2 == 0: v = -v x = self.manin_symbol((i, u, v), check=False) @@ -740,10 +733,12 @@ def modular_symbol(self, x, check=True): if len(x) == 2: x = [0, x[0], x[1]] elif len(x) == 3: - if x[0] < 0 or x[0] > self.weight()-2: - raise ValueError("The first entry of the tuple (=%s)\ - must be an integer between 0 and k-2 (=%s)." % ( - x, self.weight()-2)) + if x[0] < 0 or x[0] > self.weight() - 2: + raise ValueError( + "The first entry of the tuple (=%s)\ + must be an integer between 0 and k-2 (=%s)." + % (x, self.weight() - 2) + ) else: raise ValueError("x (=%s) must be of length 2 or 3" % x) i = Integer(x[0]) @@ -794,9 +789,12 @@ def modular_symbol_sum(self, x, check=True): try: f = R(f) except TypeError: - raise ValueError("f must be coercible to a polynomial \ - over %s" % self.base_ring()) - if (not f.is_homogeneous()) or (f.degree() != self.weight()-2): + raise ValueError( + "f must be coercible to a polynomial \ + over %s" + % self.base_ring() + ) + if (not f.is_homogeneous()) or (f.degree() != self.weight() - 2): raise ValueError("f must be a homogeneous polynomial of degree k-2") alpha = Cusp(x[1]) beta = Cusp(x[2]) @@ -956,7 +954,7 @@ def _compute_hecke_matrix_prime(self, p, rows=None): [4860 0 2049] """ # note -- p doesn't have to be prime despite the function name - p = int(Integer(p)) # go through Integer so p = 2.5 gives an error. + p = int(Integer(p)) # go through Integer so p = 2.5 gives an error. if isinstance(rows, list): rows = tuple(rows) try: @@ -1063,9 +1061,9 @@ def __heilbronn_operator(self, M, H, t=1): # Apply h to the polynomial part a, b, c, d = tuple(h) # P gives the ordered coefficients of (a*X+b*Y)^i*(c*X+d*Y)^(j-i) - P = apply_to_monomial(i, k-2, a, b, c, d) + P = apply_to_monomial(i, k - 2, a, b, c, d) # Apply h to the (u,v) part of the Manin symbol - (uu, vv) = (u*a+v*c, u*b+v*d) + (uu, vv) = (u * a + v * c, u * b + v * d) # For the generalized Heilbronn operator, we through away any # symbols for which the (u,v) part of the symbol doesn't have @@ -1073,8 +1071,8 @@ def __heilbronn_operator(self, M, H, t=1): if t != 1: if uu % t != 0 or vv % t != 0: continue - uu = uu//t - vv = vv//t + uu = uu // t + vv = vv // t # Now coerce each Manin symbol # @@ -1084,7 +1082,7 @@ def __heilbronn_operator(self, M, H, t=1): # Note that we coerce in Manin symbols as tuples. for m in range(len(P)): x = M((m, uu, vv)) - z += x*P[m] + z += x * P[m] rows.append(z.element()) @@ -1101,8 +1099,7 @@ def _repr_(self): sage: m # indirect doctest Modular Symbols space of dimension 3 for Gamma_0(1) of weight 12 with sign 0 over Rational Field """ - return "Modular Symbols space of dimension %s and weight %s for %s with sign %s and character %s over %s" % ( - self.dimension(), self.weight(), self.group(), self.sign(), self.character()._repr_short_(), self.base_ring()) + return "Modular Symbols space of dimension %s and weight %s for %s with sign %s and character %s over %s" % (self.dimension(), self.weight(), self.group(), self.sign(), self.character()._repr_short_(), self.base_ring()) def _latex_(self): r""" @@ -1119,10 +1116,7 @@ def _latex_(self): sage: latex(m) \mathrm{ModSym}_{2}(\Gamma_1(7),\left[\zeta_{6}\right];\Bold{Q}(\zeta_{6})) """ - return "\\mathrm{ModSym}_{%s}(%s,%s;%s)" % (self.weight(), - latex(self.group()), - latex(list(self.character().values_on_gens())), - latex(self.base_ring())) + return "\\mathrm{ModSym}_{%s}(%s,%s;%s)" % (self.weight(), latex(self.group()), latex(list(self.character().values_on_gens())), latex(self.base_ring())) def _matrix_of_operator_on_modular_symbols(self, codomain, R): r""" @@ -1170,7 +1164,7 @@ def _matrix_of_operator_on_modular_symbols(self, codomain, R): for c, x in b.modular_symbol_rep(): for g in R: y = x.apply(g) - v += y*c + v += y * c w = codomain(v).element() rows.append(w) M = MatrixSpace(self.base_ring(), len(rows), codomain.degree(), sparse=False) @@ -1262,7 +1256,7 @@ def _compute_atkin_lehner_matrix(self, d): if self.sign() != 0: # AL operator problematic on signed spaces - if self.diamond_bracket_matrix(crt(-1, 1, d, N/d)) != 1: + if self.diamond_bracket_matrix(crt(-1, 1, d, N / d)) != 1: raise ValueError("Atkin-Lehner operator not defined on signed space (use sign=0)") W = self.group().atkin_lehner_matrix(d).list() @@ -1303,7 +1297,7 @@ def boundary_map(self): E = [x.element() for x in I] zero = self.base_ring()(0) n = int(B.dimension()) - E = sum([list(x) + [zero]*(n - len(x)) for x in E], []) + E = sum([list(x) + [zero] * (n - len(x)) for x in E], []) A = W(E) H = Hom(self, B) @@ -1563,9 +1557,11 @@ def element(self, x): """ if isinstance(x, ManinSymbol): if not x.parent().weight() == self.weight(): - raise ArithmeticError("incompatible weights: Manin symbol\ - has weight %s, but modular symbols space has weight %s" % ( - x.parent().weight(), self.weight())) + raise ArithmeticError( + "incompatible weights: Manin symbol\ + has weight %s, but modular symbols space has weight %s" + % (x.parent().weight(), self.weight()) + ) t = self.manin_symbols().index(x.tuple()) if isinstance(t, tuple): i, scalar = t @@ -1644,54 +1640,54 @@ def factorization(self): (Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 7 and level 38, weight 2, character [zeta3], sign 1, over Cyclotomic Field of order 3 and degree 2) """ -# EXAMPLES:: - -# sage: M = ModularSymbols(Gamma0(22), 2); M -# Modular Symbols space of dimension 7 for Gamma_0(22) of weight 2 with sign 0 over Rational Field -# sage: M.factorization(): -# ... print b.dimension(), b.level(), e -# 1 11 2 -# 1 11 2 -# 1 11 2 -# 1 22 1 - -# An example with sign 1:: - -# sage: M = ModularSymbols(Gamma0(22), 2, sign=1); M -# Modular Symbols space of dimension 5 for Gamma_0(22) of weight 2 with sign 1 over Rational Field -# sage: for b, e in M.factorization(): -# ... print b.dimension(), b.level(), e -# 1 11 2 -# 1 11 2 -# 1 22 1 - -# An example for Gamma1:: - -# sage: M = ModularSymbols(Gamma1(26), 2, sign=1); M -# Modular Symbols space of dimension 33 for Gamma_1(26) of weight 2 with sign 1 over Rational Field -# sage: for b, e in M.factorization(): -# ... print b.dimension(), b.level(), e -# 1 13 2 -# 1 13 2 -# 1 13 2 -# 2 13 2 -# 2 13 2 -# 2 13 2 -# 2 13 2 -# 2 13 2 -# 1 26 1 -# 1 26 1 -# 1 26 1 -# 2 26 1 -# 2 26 1 - -# An example with level divisible by a square:: - -# sage: M = ModularSymbols(Gamma0(2*9),2); M -# ??? -# sage: for b, e in M.factorization(): -# ... print b.dimension(), b.level(), e -# ??? + # EXAMPLES:: + + # sage: M = ModularSymbols(Gamma0(22), 2); M + # Modular Symbols space of dimension 7 for Gamma_0(22) of weight 2 with sign 0 over Rational Field + # sage: M.factorization(): + # ... print b.dimension(), b.level(), e + # 1 11 2 + # 1 11 2 + # 1 11 2 + # 1 22 1 + + # An example with sign 1:: + + # sage: M = ModularSymbols(Gamma0(22), 2, sign=1); M + # Modular Symbols space of dimension 5 for Gamma_0(22) of weight 2 with sign 1 over Rational Field + # sage: for b, e in M.factorization(): + # ... print b.dimension(), b.level(), e + # 1 11 2 + # 1 11 2 + # 1 22 1 + + # An example for Gamma1:: + + # sage: M = ModularSymbols(Gamma1(26), 2, sign=1); M + # Modular Symbols space of dimension 33 for Gamma_1(26) of weight 2 with sign 1 over Rational Field + # sage: for b, e in M.factorization(): + # ... print b.dimension(), b.level(), e + # 1 13 2 + # 1 13 2 + # 1 13 2 + # 2 13 2 + # 2 13 2 + # 2 13 2 + # 2 13 2 + # 2 13 2 + # 1 26 1 + # 1 26 1 + # 1 26 1 + # 2 26 1 + # 2 26 1 + + # An example with level divisible by a square:: + + # sage: M = ModularSymbols(Gamma0(2*9),2); M + # ??? + # sage: for b, e in M.factorization(): + # ... print b.dimension(), b.level(), e + # ??? try: return self._factorization except AttributeError: @@ -1757,8 +1753,7 @@ def factorization(self): A._is_simple = True D.append((A, n)) # The Eisenstein part - D.extend((E, 1) for E in - self.eisenstein_submodule().decomposition(anemic=True)) + D.extend((E, 1) for E in self.eisenstein_submodule().decomposition(anemic=True)) r = self.dimension() s = sum(A.rank() * mult for A, mult in D) @@ -1790,7 +1785,7 @@ def is_cuspidal(self) -> bool: return self.__is_cuspidal except AttributeError: S = self.ambient_hecke_module().cuspidal_submodule() - self.__is_cuspidal = (S.dimension() == self.dimension()) + self.__is_cuspidal = S.dimension() == self.dimension() return self.__is_cuspidal @cached_method @@ -2044,7 +2039,7 @@ def _compute_diamond_matrix(self, d): sage: ModularSymbols(Gamma1(13), 5).diamond_bracket_operator(6).charpoly().factor() (x^2 + 1)^8 * (x^4 - x^2 + 1)^10 """ - return self.__heilbronn_operator(self, [[d, 0, 0, d]], 1).matrix() * d**(2 - self.weight()) + return self.__heilbronn_operator(self, [[d, 0, 0, d]], 1).matrix() * d ** (2 - self.weight()) def submodule(self, M, dual_free_module=None, check=True): r""" @@ -2133,8 +2128,7 @@ def twisted_winding_element(self, i, eps): raise ValueError("i must be between 0 and k-2.") m = eps.modulus() - return self.sum(eps(a) * self.modular_symbol([i, Cusp(0), Cusp(a / m)]) - for a in m.coprime_integers(m)) + return self.sum(eps(a) * self.modular_symbol([i, Cusp(0), Cusp(a / m)]) for a in m.coprime_integers(m)) ###################################################################### # Z-module of integral modular symbols. @@ -2246,7 +2240,7 @@ def integral_structure(self, algorithm='default'): raise ValueError("unknown algorithm '%s'" % algorithm) W = B.row_module() if d != 1: - W = W.scale(1/d) + W = W.scale(1 / d) self.__integral_structure = W assert W.rank() == self.rank(), "there is a bug in computing integral structure on modular symbols" return self.__integral_structure @@ -2336,9 +2330,7 @@ class of cuspidal newforms in this ambient space. if nz is not None: R = self.hecke_images(nz, v) - return [(R * m, D[i].dual_eigenvector(names=names[i], - lift=False, nz=nz)) - for i, m in enumerate(B)] + return [(R * m, D[i].dual_eigenvector(names=names[i], lift=False, nz=nz)) for i, m in enumerate(B)] # No single i works, so we do something less uniform. ans = [] @@ -2350,8 +2342,7 @@ class of cuspidal newforms in this ambient space. else: R = self.hecke_images(nz, v) cache[nz] = R - ans.append((R * B[i], D[i].dual_eigenvector(names=names[i], - lift=False, nz=nz))) + ans.append((R * B[i], D[i].dual_eigenvector(names=names[i], lift=False, nz=nz))) return ans def __pari__(self): @@ -2407,6 +2398,7 @@ def _pari_pairing(self): return self._pari_tensor().inverse() from sage.matrix.constructor import matrix from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + P = self.__pari__() I = matrix.identity(self.rank()).__pari__() m = Integer(self.weight() - 2) @@ -2421,9 +2413,9 @@ def ev(s): i = s.i a, b, c, d = s.lift_to_sl2z() e = [R(p) for p in P.mseval(I, matrix(2, 2, [b, a, d, c]))] - g = (d * x - b)**i * (-c * x + a)**(m - i) - return [sum(f[j] * g[m - j] / m.binomial(j) for j in range(m + 1)) - for f in e] + g = (d * x - b) ** i * (-c * x + a) ** (m - i) + return [sum(f[j] * g[m - j] / m.binomial(j) for j in range(m + 1)) for f in e] + return matrix([ev(s) for s in self.manin_symbols_basis()]) def _pari_tensor(self): @@ -2468,7 +2460,8 @@ def _pari_tensor(self): if self.weight() != 2: return self._pari_pairing().inverse() from sage.matrix.constructor import matrix - gens = self.__pari__().mspathgens()[0][:self.rank()].sage() + + gens = self.__pari__().mspathgens()[0][: self.rank()].sage() # gens is a basis for the space of modular symbols of weight 2 # (in the sense of Sage), and the distinguished basis of the # corresponding PARI space of modular symbols is dual to this. @@ -2505,6 +2498,7 @@ class ModularSymbolsAmbient_wtk_g0(ModularSymbolsAmbient): sage: ModularSymbols(36,4).dimension() 36 """ + def __init__(self, N, k, sign, F, custom_init=None, category=None): r""" Initialize a space of modular symbols of weight `k` for @@ -2542,9 +2536,7 @@ def __init__(self, N, k, sign, F, custom_init=None, category=None): if sign not in [-1, 0, 1]: raise TypeError("sign must be an int in [-1,0,1]") - ModularSymbolsAmbient.__init__(self, weight=k, group=arithgroup.Gamma0(N), - sign=sign, base_ring=F, - custom_init=custom_init, category=category) + ModularSymbolsAmbient.__init__(self, weight=k, group=arithgroup.Gamma0(N), sign=sign, base_ring=F, custom_init=custom_init, category=category) def _dimension_formula(self): r""" @@ -2566,7 +2558,7 @@ def _dimension_formula(self): return 0 if k > 2: return 2 * self.group().dimension_cusp_forms(k) + self.group().ncusps() - return 2*self.group().dimension_cusp_forms(k) + self.group().ncusps() - 1 + return 2 * self.group().dimension_cusp_forms(k) + self.group().ncusps() - 1 raise NotImplementedError def _repr_(self): @@ -2579,9 +2571,7 @@ def _repr_(self): sage: M # indirect doctest Modular Symbols space of dimension 32 for Gamma_0(37) of weight 6 with sign 0 over Rational Field """ - return ("Modular Symbols space of dimension %s for Gamma_0(%s) of weight %s with sign %s " + - "over %s") % (self.dimension(), self.level(), self.weight(), self.sign(), - self.base_ring()) + return ("Modular Symbols space of dimension %s for Gamma_0(%s) of weight %s with sign %s " + "over %s") % (self.dimension(), self.level(), self.weight(), self.sign(), self.base_ring()) def _cuspidal_submodule_dimension_formula(self): r""" @@ -2656,7 +2646,7 @@ def _degeneracy_raising_matrix_1(self, M): i = s.i # We apply each matrix in H according to the above formula for h in H: - hg = h*g + hg = h * g z += M((i, hg[1, 0], hg[1, 1])) rows.append(z.element()) @@ -2697,8 +2687,7 @@ def boundary_space(self): return self.__boundary_space except AttributeError: pass - self.__boundary_space = boundary.BoundarySpace_wtk_g0( - self.level(), self.weight(), self.sign(), self.base_ring()) + self.__boundary_space = boundary.BoundarySpace_wtk_g0(self.level(), self.weight(), self.sign(), self.base_ring()) return self.__boundary_space def manin_symbols(self): @@ -2716,8 +2705,7 @@ def manin_symbols(self): try: return self.__manin_symbols except AttributeError: - self.__manin_symbols = ManinSymbolList_gamma0( - level=self.level(), weight=self.weight()) + self.__manin_symbols = ManinSymbolList_gamma0(level=self.level(), weight=self.weight()) return self.__manin_symbols def _hecke_images(self, i, v): @@ -2762,8 +2750,7 @@ def _hecke_images(self, i, v): # the kernel of the dual space corresponding to self. c = self.manin_generators()[self.manin_basis()[i]] N = self.level() - return heilbronn.hecke_images_gamma0_weight_k(c.u, c.v, c.i, N, self.weight(), - v, self.manin_gens_to_basis()) + return heilbronn.hecke_images_gamma0_weight_k(c.u, c.v, c.i, N, self.weight(), v, self.manin_gens_to_basis()) @cached_method def __pari__(self): @@ -2814,6 +2801,7 @@ class ModularSymbolsAmbient_wt2_g0(ModularSymbolsAmbient_wtk_g0): sage: ModularSymbols(Gamma0(12),2) Modular Symbols space of dimension 5 for Gamma_0(12) of weight 2 with sign 0 over Rational Field """ + def __init__(self, N, sign, F, custom_init=None, category=None): """ Initialize a space of modular symbols. @@ -2833,8 +2821,7 @@ def __init__(self, N, sign, F, custom_init=None, category=None): sage: M = ModularSymbols(Gamma0(12),2) """ - ModularSymbolsAmbient_wtk_g0.__init__(self, N=N, k=2, sign=sign, F=F, - custom_init=custom_init, category=category) + ModularSymbolsAmbient_wtk_g0.__init__(self, N=N, k=2, sign=sign, F=F, custom_init=custom_init, category=category) def _dimension_formula(self): r""" @@ -2851,7 +2838,7 @@ def _dimension_formula(self): if self.base_ring().characteristic() == 0: if self.sign() != 0: return None - return 2*self.group().dimension_cusp_forms(2) + self.group().ncusps() - 1 + return 2 * self.group().dimension_cusp_forms(2) + self.group().ncusps() - 1 raise NotImplementedError def _cuspidal_submodule_dimension_formula(self): @@ -2947,10 +2934,9 @@ def _compute_hecke_matrix_prime(self, p, rows=None): if k != -1: f, s = mod2term[k] if s != 0: - W[j, f] = W[j, f] + s*m + W[j, f] = W[j, f] + s * m tm = verbose("done making non-reduced matrix", tm) - verbose("start matrix-matrix (%s x %s) times (%s x %s) multiply to get Tp" % (W.nrows(), W.ncols(), - R.nrows(), R.ncols())) + verbose("start matrix-matrix (%s x %s) times (%s x %s) multiply to get Tp" % (W.nrows(), W.ncols(), R.nrows(), R.ncols())) if hasattr(W, '_matrix_times_matrix_dense'): Tp = W._matrix_times_matrix_dense(R) verbose("done matrix multiply and computing Hecke operator", tm) @@ -2977,8 +2963,7 @@ def boundary_space(self): return self.__boundary_space except AttributeError: pass - self.__boundary_space = boundary.BoundarySpace_wtk_g0( - self.level(), self.weight(), self.sign(), self.base_ring()) + self.__boundary_space = boundary.BoundarySpace_wtk_g0(self.level(), self.weight(), self.sign(), self.base_ring()) return self.__boundary_space def _hecke_image_of_ith_basis_vector(self, n, i): @@ -3006,8 +2991,7 @@ def _hecke_image_of_ith_basis_vector(self, n, i): """ c = self.manin_generators()[self.manin_basis()[i]] N = self.level() - I = heilbronn.hecke_images_gamma0_weight2(c.u, c.v, N, [n], - self.manin_gens_to_basis()) + I = heilbronn.hecke_images_gamma0_weight2(c.u, c.v, N, [n], self.manin_gens_to_basis()) return self(I[0]) def _hecke_images(self, i, v): @@ -3041,8 +3025,7 @@ def _hecke_images(self, i, v): # the kernel of the dual space corresponding to self. c = self.manin_generators()[self.manin_basis()[i]] N = self.level() - return heilbronn.hecke_images_gamma0_weight2(c.u, c.v, N, v, - self.manin_gens_to_basis()) + return heilbronn.hecke_images_gamma0_weight2(c.u, c.v, N, v, self.manin_gens_to_basis()) class ModularSymbolsAmbient_wtk_g1(ModularSymbolsAmbient): @@ -3095,13 +3078,7 @@ def __init__(self, level, weight, sign, F, custom_init=None, category=None): sage: M = ModularSymbols(Gamma1(7),3) """ - ModularSymbolsAmbient.__init__(self, - weight=weight, - group=arithgroup.Gamma1(level), - sign=sign, - base_ring=F, - custom_init=custom_init, - category=category) + ModularSymbolsAmbient.__init__(self, weight=weight, group=arithgroup.Gamma1(level), sign=sign, base_ring=F, custom_init=custom_init, category=category) def _dimension_formula(self): r""" @@ -3120,7 +3097,7 @@ def _dimension_formula(self): level, weight, sign = self.level(), self.weight(), self.sign() if sign != 0: return None - d = 2*self.group().dimension_cusp_forms(weight) + self.group().ncusps() + d = 2 * self.group().dimension_cusp_forms(weight) + self.group().ncusps() if level == 1 and weight % 2: return 0 if weight == 2: @@ -3142,8 +3119,7 @@ def _repr_(self): sage: M # indirect doctest Modular Symbols space of dimension 8 for Gamma_1(7) of weight 3 with sign 0 over Rational Field """ - return ("Modular Symbols space of dimension %s for Gamma_1(%s) of weight %s with sign %s over %s" - % (self.dimension(), self.level(), self.weight(), self.sign(), self.base_ring())) + return "Modular Symbols space of dimension %s for Gamma_1(%s) of weight %s with sign %s over %s" % (self.dimension(), self.level(), self.weight(), self.sign(), self.base_ring()) def _cuspidal_submodule_dimension_formula(self): r""" @@ -3239,7 +3215,7 @@ def _degeneracy_raising_matrix_1(self, M): i = s.i # We apply each matrix in H according to the above formula for h in H: - hg = h*g + hg = h * g z += M((i, hg[1, 0], hg[1, 1])) rows.append(z.element()) @@ -3259,8 +3235,7 @@ def boundary_space(self): return self.__boundary_space except AttributeError: pass - self.__boundary_space = boundary.BoundarySpace_wtk_g1( - self.level(), self.weight(), self.sign(), self.base_ring()) + self.__boundary_space = boundary.BoundarySpace_wtk_g1(self.level(), self.weight(), self.sign(), self.base_ring()) return self.__boundary_space def manin_symbols(self): @@ -3278,8 +3253,7 @@ def manin_symbols(self): try: return self.__manin_symbols except AttributeError: - self.__manin_symbols = ManinSymbolList_gamma1( - level=self.level(), weight=self.weight()) + self.__manin_symbols = ManinSymbolList_gamma1(level=self.level(), weight=self.weight()) return self.__manin_symbols @@ -3303,11 +3277,7 @@ def __init__(self, group, weight, sign, F, custom_init=None, category=None): sage: ModularSymbols(GammaH(15,[4]),2) Modular Symbols space of dimension 9 for Congruence Subgroup Gamma_H(15) with H generated by [4] of weight 2 with sign 0 over Rational Field """ - ModularSymbolsAmbient.__init__(self, - weight=weight, group=group, - sign=sign, base_ring=F, - custom_init=custom_init, - category=category) + ModularSymbolsAmbient.__init__(self, weight=weight, group=group, sign=sign, base_ring=F, custom_init=custom_init, category=category) def _dimension_formula(self): r""" @@ -3332,8 +3302,7 @@ def _repr_(self): sage: M # indirect doctest Modular Symbols space of dimension 9 for Congruence Subgroup Gamma_H(15) with H generated by [4] of weight 2 with sign 0 over Rational Field """ - return ("Modular Symbols space of dimension %s for %s of weight %s with sign %s over %s" - % (self.dimension(), self.group(), self.weight(), self.sign(), self.base_ring())) + return "Modular Symbols space of dimension %s for %s of weight %s with sign %s over %s" % (self.dimension(), self.group(), self.weight(), self.sign(), self.base_ring()) def _cuspidal_submodule_dimension_formula(self): r""" @@ -3406,8 +3375,7 @@ def boundary_space(self): return self.__boundary_space except AttributeError: pass - self.__boundary_space = boundary.BoundarySpace_wtk_gamma_h( - self.group(), self.weight(), self.sign(), self.base_ring()) + self.__boundary_space = boundary.BoundarySpace_wtk_gamma_h(self.group(), self.weight(), self.sign(), self.base_ring()) return self.__boundary_space def manin_symbols(self): @@ -3425,8 +3393,7 @@ def manin_symbols(self): try: return self.__manin_symbols except AttributeError: - self.__manin_symbols = ManinSymbolList_gamma_h( - group=self.group(), weight=self.weight()) + self.__manin_symbols = ManinSymbolList_gamma_h(group=self.group(), weight=self.weight()) return self.__manin_symbols @@ -3478,14 +3445,7 @@ def __init__(self, eps, weight, sign, base_ring, custom_init=None, category=None True """ level = eps.modulus() - ModularSymbolsAmbient.__init__(self, - weight=weight, - group=arithgroup.Gamma1(level), - sign=sign, - base_ring=base_ring, - character=eps.change_ring(base_ring), - custom_init=custom_init, - category=category) + ModularSymbolsAmbient.__init__(self, weight=weight, group=arithgroup.Gamma1(level), sign=sign, base_ring=base_ring, character=eps.change_ring(base_ring), custom_init=custom_init, category=category) def _repr_(self): r""" @@ -3498,10 +3458,7 @@ def _repr_(self): sage: M # indirect doctest Modular Symbols space of dimension 2 and level 5, weight 3, character [zeta4], sign 0, over Cyclotomic Field of order 4 and degree 2 """ - return ("Modular Symbols space of dimension %s and level %s, weight %s, character %s, sign %s, " + - "over %s") % (self.dimension(), self.level(), self.weight(), - self.character()._repr_short_(), self.sign(), - self.base_ring()) + return ("Modular Symbols space of dimension %s and level %s, weight %s, character %s, sign %s, " + "over %s") % (self.dimension(), self.level(), self.weight(), self.character()._repr_short_(), self.sign(), self.base_ring()) def _cuspidal_submodule_dimension_formula(self): r""" @@ -3584,9 +3541,9 @@ def _matrix_of_operator_on_modular_symbols(self, codomain, R, character_twist=Fa for g in R: y = x.apply(g) if character_twist: - v += y*c*eps(g[0]) + v += y * c * eps(g[0]) else: - v += y*c + v += y * c w = codomain(v).element() rows.append(w) M = MatrixSpace(self.base_ring(), len(rows), codomain.degree(), sparse=False) @@ -3680,8 +3637,7 @@ def boundary_space(self): return self.__boundary_space except AttributeError: pass - self.__boundary_space = boundary.BoundarySpace_wtk_eps( - self.character(), self.weight(), self.sign()) + self.__boundary_space = boundary.BoundarySpace_wtk_eps(self.character(), self.weight(), self.sign()) return self.__boundary_space def manin_symbols(self): @@ -3700,8 +3656,7 @@ def manin_symbols(self): try: return self.__manin_symbols except AttributeError: - self.__manin_symbols = ManinSymbolList_character( - character=self.character(), weight=self.weight()) + self.__manin_symbols = ManinSymbolList_character(character=self.character(), weight=self.weight()) return self.__manin_symbols def modular_symbols_of_level(self, N): @@ -3826,7 +3781,5 @@ def _hecke_images(self, i, v): c = self.manin_generators()[self.manin_basis()[i]] N = self.level() if chi.order() > 2: - return heilbronn.hecke_images_nonquad_character_weight2(c.u, c.v, N, - v, chi, self.manin_gens_to_basis()) - return heilbronn.hecke_images_quad_character_weight2(c.u, c.v, N, - v, chi, self.manin_gens_to_basis()) + return heilbronn.hecke_images_nonquad_character_weight2(c.u, c.v, N, v, chi, self.manin_gens_to_basis()) + return heilbronn.hecke_images_quad_character_weight2(c.u, c.v, N, v, chi, self.manin_gens_to_basis()) diff --git a/src/sage/modular/modsym/boundary.py b/src/sage/modular/modsym/boundary.py index 4eb28d6193a..2b03ab1302e 100644 --- a/src/sage/modular/modsym/boundary.py +++ b/src/sage/modular/modsym/boundary.py @@ -166,8 +166,7 @@ def _repr_(self): sage: (-6*ModularSymbols(Gamma0(11), 2).boundary_space()(Cusp(0)))._repr_() '-6*[0]' """ - return repr_lincomb([('[' + repr(self.parent()._known_gens[i]) + ']', c) - for i, c in sorted(self.__x.items())]) + return repr_lincomb([('[' + repr(self.parent()._known_gens[i]) + ']', c) for i, c in sorted(self.__x.items())]) # can't inherit arithmetic operations from HeckeModule, because basis # dimension might change! @@ -274,12 +273,7 @@ def __neg__(self): @richcmp_method class BoundarySpace(hecke.HeckeModule_generic): - def __init__(self, - group=arithgroup.Gamma0(1), - weight=2, - sign=0, - base_ring=QQ, - character=None): + def __init__(self, group=arithgroup.Gamma0(1), weight=2, sign=0, base_ring=QQ, character=None): """ Space of boundary symbols for a congruence subgroup of SL_2(Z). @@ -315,9 +309,7 @@ def __init__(self, raise TypeError("base_ring must be a commutative ring") if character is None and isinstance(group, arithgroup.Gamma0_class): character = dirichlet.TrivialCharacter(group.level(), base_ring) - (self.__group, self.__weight, self.__character, - self.__sign, self.__base_ring) = (group, weight, - character, sign, base_ring) + (self.__group, self.__weight, self.__character, self.__sign, self.__base_ring) = (group, weight, character, sign, base_ring) self._known_gens = [] self._zero_cusps = [] hecke.HeckeModule_generic.__init__(self, base_ring, group.level()) @@ -336,9 +328,7 @@ def __richcmp__(self, other, op): if type(self) is not type(other): return NotImplemented - return richcmp((self.group(), self.weight(), self.character()), - (other.group(), other.weight(), other.character()), - op) + return richcmp((self.group(), self.weight(), self.character()), (other.group(), other.weight(), other.character()), op) def _known_cusps(self) -> list: """ @@ -537,6 +527,7 @@ def __call__(self, x): TypeError: Coercion of 7 (of type ) into Space of Boundary Modular Symbols for Congruence Subgroup Gamma0(15) of weight 2 over Rational Field not (yet) defined. """ from .ambient import ModularSymbolsAmbient + if isinstance(x, int) and x == 0: return BoundarySpaceElement(self, {}) @@ -551,8 +542,7 @@ def __call__(self, x): if not isinstance(M, ModularSymbolsAmbient): raise TypeError("x (=%s) must be an element of a space of modular symbols of type ModularSymbolsAmbient" % x) if M.level() != self.level(): - raise TypeError("x (=%s) must have level %s but has level %s" % ( - x, self.level(), M.level())) + raise TypeError("x (=%s) must have level %s but has level %s" % (x, self.level(), M.level())) S = x.manin_symbol_rep() if len(S) == 0: return self(0) @@ -573,10 +563,7 @@ def _repr_(self): sage: sage.modular.modsym.boundary.BoundarySpace(Gamma0(3), 2)._repr_() 'Space of Boundary Modular Symbols of weight 2 for Congruence Subgroup Gamma0(3) with sign 0 and character [1] over Rational Field' """ - return ("Space of Boundary Modular Symbols of weight %s for" + - " %s with sign %s and character %s over %s") % ( - self.weight(), self.group(), self.sign(), - self.character()._repr_short_(), self.base_ring()) + return ("Space of Boundary Modular Symbols of weight %s for" + " %s with sign %s and character %s over %s") % (self.weight(), self.group(), self.sign(), self.character()._repr_short_(), self.base_ring()) def _cusp_index(self, cusp): """ @@ -638,11 +625,7 @@ def __init__(self, level, weight, sign, F): raise ArithmeticError("sign must be an int in [-1,0,1]") if level <= 0: raise ArithmeticError("level must be positive") - BoundarySpace.__init__(self, - weight=weight, - group=arithgroup.Gamma0(level), - sign=sign, - base_ring=F) + BoundarySpace.__init__(self, weight=weight, group=arithgroup.Gamma0(level), sign=sign, base_ring=F) def _repr_(self): """ @@ -654,8 +637,7 @@ def _repr_(self): sage: B._repr_() 'Space of Boundary Modular Symbols for Congruence Subgroup Gamma0(97) of weight 3 over Rational Field' """ - return ("Space of Boundary Modular Symbols for %s of weight %s over %s" - % (self.group(), self.weight(), self.base_ring())) + return "Space of Boundary Modular Symbols for %s of weight %s over %s" % (self.group(), self.weight(), self.base_ring()) def _coerce_cusp(self, c): """ @@ -779,11 +761,7 @@ def __init__(self, level, weight, sign, F): if level <= 0: raise ArithmeticError("level must be positive") - BoundarySpace.__init__(self, - weight=weight, - group=arithgroup.Gamma1(level), - sign=sign, - base_ring=F) + BoundarySpace.__init__(self, weight=weight, group=arithgroup.Gamma1(level), sign=sign, base_ring=F) def _repr_(self): """ @@ -794,8 +772,7 @@ def _repr_(self): sage: ModularSymbols(Gamma1(5), 3, sign=1).boundary_space()._repr_() 'Boundary Modular Symbols space for Gamma_1(5) of weight 3 over Rational Field' """ - return ("Boundary Modular Symbols space for Gamma_1(%s) of weight %s " + - "over %s") % (self.level(), self.weight(), self.base_ring()) + return ("Boundary Modular Symbols space for Gamma_1(%s) of weight %s " + "over %s") % (self.level(), self.weight(), self.base_ring()) def _is_equiv(self, c1, c2): """ @@ -931,15 +908,13 @@ def _coerce_cusp(self, c): # (-1)^k. # if sign: - if (c.is_infinity() and sign != (-1)**self.weight()) or \ - (c.is_zero() and sign == -1): + if (c.is_infinity() and sign != (-1) ** self.weight()) or (c.is_zero() and sign == -1): self._zero_cusps.append(c) del self._known_gens[-1] return self(0) - if (not c.is_infinity() and not c.is_zero()): + if not c.is_infinity() and not c.is_zero(): t, eps = self._is_equiv(c, -c) - if t and ((eps == 1 and sign == -1) or - (eps == -1 and sign != (-1)**self.weight())): + if t and ((eps == 1 and sign == -1) or (eps == -1 and sign != (-1) ** self.weight())): self._zero_cusps.append(c) del self._known_gens[-1] return self(0) @@ -985,11 +960,7 @@ def __init__(self, group, weight, sign, F): if sign not in [-1, 0, 1]: raise ArithmeticError("sign must be an int in [-1,0,1]") - BoundarySpace.__init__(self, - weight=weight, - group=group, - sign=sign, - base_ring=F) + BoundarySpace.__init__(self, weight=weight, group=group, sign=sign, base_ring=F) def _repr_(self): """ @@ -1000,8 +971,7 @@ def _repr_(self): sage: ModularSymbols(GammaH(7,[2]), 4).boundary_space()._repr_() 'Boundary Modular Symbols space for Congruence Subgroup Gamma_H(7) with H generated by [2] of weight 4 over Rational Field' """ - return ("Boundary Modular Symbols space for %s of weight %s " + - "over %s") % (self.group(), self.weight(), self.base_ring()) + return ("Boundary Modular Symbols space for %s of weight %s " + "over %s") % (self.group(), self.weight(), self.base_ring()) def _is_equiv(self, c1, c2): """ @@ -1180,15 +1150,13 @@ def _coerce_cusp(self, c): # when H is larger than {1}.) # if sign: - if (c.is_infinity() and sign != (-1)**self.weight()) or \ - (c.is_zero() and sign == -1): + if (c.is_infinity() and sign != (-1) ** self.weight()) or (c.is_zero() and sign == -1): self._zero_cusps.append(c) del self._known_gens[-1] return self(0) - if (not c.is_infinity() and not c.is_zero()): + if not c.is_infinity() and not c.is_zero(): t, eps = self._is_equiv(c, -c) - if t and ((eps == 1 and sign == -1) or - (eps == -1 and sign != (-1)**self.weight())): + if t and ((eps == 1 and sign == -1) or (eps == -1 and sign != (-1) ** self.weight())): self._zero_cusps.append(c) del self._known_gens[-1] return self(0) @@ -1227,12 +1195,7 @@ def __init__(self, eps, weight, sign=0): raise ArithmeticError("sign must be an int in [-1,0,1]") if level <= 0: raise ArithmeticError("level must be positive") - BoundarySpace.__init__(self, - weight=weight, - group=arithgroup.Gamma1(level), - sign=sign, - base_ring=eps.base_ring(), - character=eps) + BoundarySpace.__init__(self, weight=weight, group=arithgroup.Gamma1(level), sign=sign, base_ring=eps.base_ring(), character=eps) def _repr_(self): """ @@ -1243,11 +1206,7 @@ def _repr_(self): sage: ModularSymbols(DirichletGroup(6).0, 4).boundary_space()._repr_() 'Boundary Modular Symbols space of level 6, weight 4, character [-1] and dimension 0 over Rational Field' """ - return ("Boundary Modular Symbols space of level %s, weight %s, character %s " + - "and dimension %s over %s") % (self.level(), self.weight(), - self.character()._repr_short_(), - self.rank(), - self.base_ring()) + return ("Boundary Modular Symbols space of level %s, weight %s, character %s " + "and dimension %s over %s") % (self.level(), self.weight(), self.character()._repr_short_(), self.rank(), self.base_ring()) def _is_equiv(self, c1, c2): """ @@ -1396,7 +1355,7 @@ def _coerce_cusp(self, c): del self._known_gens[-1] return self(0) elif c.is_infinity(): - if sign != (-1)**self.weight(): + if sign != (-1) ** self.weight(): self._zero_cusps.append(c) del self._known_gens[-1] return self(0) diff --git a/src/sage/modular/modsym/element.py b/src/sage/modular/modsym/element.py index ecbaefe06c8..846ee376ce3 100644 --- a/src/sage/modular/modsym/element.py +++ b/src/sage/modular/modsym/element.py @@ -77,6 +77,7 @@ class ModularSymbolsElement(hecke.HeckeModuleElement): sage: x == loads(dumps(x)) True """ + def __init__(self, parent, x, check=True): """ INPUT: @@ -99,6 +100,7 @@ def __init__(self, parent, x, check=True): """ if check: from .space import ModularSymbolsSpace + if not isinstance(parent, ModularSymbolsSpace): raise TypeError("parent (= %s) must be a space of modular symbols" % parent) if not isinstance(x, sage.modules.free_module_element.FreeModuleElement): @@ -192,8 +194,7 @@ def _rmul_(self, other): ... TypeError: unsupported operand parent(s) for *: 'Modular Symbols space of dimension 8 for Gamma_0(3) of weight 12 with sign 0 over Rational Field' and 'Ring of integers modulo 17' """ - return ModularSymbolsElement(self.parent(), self.element() * other, - check=False) + return ModularSymbolsElement(self.parent(), self.element() * other, check=False) def _lmul_(self, left): r""" @@ -211,8 +212,7 @@ def _lmul_(self, left): ... TypeError: unsupported operand parent(s) for *: 'Ring of integers modulo 17' and 'Modular Symbols space of dimension 8 for Gamma_0(3) of weight 12 with sign 0 over Rational Field' """ - return ModularSymbolsElement(self.parent(), left * self.element(), - check=False) + return ModularSymbolsElement(self.parent(), left * self.element(), check=False) def _neg_(self): r""" @@ -242,11 +242,11 @@ def _sub_(self, other): """ return ModularSymbolsElement(self.parent(), self.element() - other.element(), check=False) -# this clearly hasn't worked for some time -- the method embedded_vector_space doesn't exist -- DL 2009-05-18 -# def coordinate_vector(self): -# if self.parent().is_ambient(): -# return self.element() -# return self.parent().embedded_vector_space().coordinate_vector(self.element()) + # this clearly hasn't worked for some time -- the method embedded_vector_space doesn't exist -- DL 2009-05-18 + # def coordinate_vector(self): + # if self.parent().is_ambient(): + # return self.element() + # return self.parent().embedded_vector_space().coordinate_vector(self.element()) def list(self): r""" @@ -282,8 +282,7 @@ def manin_symbol_rep(self): v = self.element() manin_symbols = A.ambient_hecke_module().manin_symbols_basis() F = formal_sum.FormalSums(A.base_ring()) - ms = F([(v[i], manin_symbols[i]) for i in range(v.degree()) - if v[i] != 0], check=False, reduce=False) + ms = F([(v[i], manin_symbols[i]) for i in range(v.degree()) if v[i] != 0], check=False, reduce=False) self.__manin_symbols = ms return self.__manin_symbols diff --git a/src/sage/modular/modsym/g1list.py b/src/sage/modular/modsym/g1list.py index f4dda91da90..0579686bae9 100644 --- a/src/sage/modular/modsym/g1list.py +++ b/src/sage/modular/modsym/g1list.py @@ -38,6 +38,7 @@ class G1list(SageObject): sage: loads(dumps(L)) == L True """ + def __init__(self, N): """ EXAMPLES:: @@ -46,8 +47,7 @@ def __init__(self, N): List of coset representatives for Gamma_1(6) in SL_2(Z) """ self.__N = N - self.__list = [(u, v) for u in range(N) for v in range(N) - if GCD(GCD(u, v), N) == 1] + self.__list = [(u, v) for u in range(N) for v in range(N) if GCD(GCD(u, v), N) == 1] def __richcmp__(self, other, op): r""" @@ -139,6 +139,7 @@ class _G1list_old_pickle(G1list): no input to the class on the initial ``__init__`` call, and the new class pickles, we need to have ``__setstate__`` handle it. """ + def __init__(self): """ For unpickling old pickles. @@ -172,5 +173,4 @@ def __setstate__(self, state): self.__dict__ = state # Default pickling is ``state = self.__dict__`` -register_unpickle_override('sage.modular.modsym.g1list', 'G1list', - _G1list_old_pickle) +register_unpickle_override('sage.modular.modsym.g1list', 'G1list', _G1list_old_pickle) diff --git a/src/sage/modular/modsym/ghlist.py b/src/sage/modular/modsym/ghlist.py index f82ae8040cc..8172d5b2064 100644 --- a/src/sage/modular/modsym/ghlist.py +++ b/src/sage/modular/modsym/ghlist.py @@ -36,6 +36,7 @@ class GHlist(SageObject): sage: loads(dumps(L)) == L True """ + def __init__(self, group) -> None: """ EXAMPLES:: @@ -48,8 +49,7 @@ def __init__(self, group) -> None: v = group._coset_reduction_data()[0] N = group.level() coset_reps = {a for a, b, _ in v if b == 1} - w = [group._reduce_coset(x * u, x * v) - for x in coset_reps for u, v in p1list.P1List(N).list()] + w = [group._reduce_coset(x * u, x * v) for x in coset_reps for u, v in p1list.P1List(N).list()] w = sorted(set(w)) self.__list = w @@ -143,6 +143,7 @@ class _GHlist_old_pickle(GHlist): no input to the class on the initial ``__init__`` call, and the new class pickles, we need to have ``__setstate__`` handle it. """ + def __init__(self) -> None: """ For unpickling old pickles. @@ -176,5 +177,4 @@ def __setstate__(self, state): self.__dict__ = state # Default pickling is ``state = self.__dict__`` -register_unpickle_override('sage.modular.modsym.ghlist', 'GHlist', - _GHlist_old_pickle) +register_unpickle_override('sage.modular.modsym.ghlist', 'GHlist', _GHlist_old_pickle) diff --git a/src/sage/modular/modsym/manin_symbol_list.py b/src/sage/modular/modsym/manin_symbol_list.py index 996627bfce1..2ceab0379d2 100644 --- a/src/sage/modular/modsym/manin_symbol_list.py +++ b/src/sage/modular/modsym/manin_symbol_list.py @@ -14,6 +14,7 @@ - :class:`ManinSymbolList_character` """ + # **************************************************************************** # Sage: Open Source Mathematical Software # @@ -77,7 +78,7 @@ def __init__(self, weight, lst): """ self._weight = weight self._symbol_list = lst - self._index = {x: i for i,x in enumerate(lst)} + self._index = {x: i for i, x in enumerate(lst)} Parent.__init__(self, category=FiniteEnumeratedSets()) def _element_constructor_(self, x): @@ -116,8 +117,7 @@ def __richcmp__(self, right, op): """ if not isinstance(right, ManinSymbolList): return NotImplemented - return richcmp((self._weight, self._symbol_list), - (right._weight, right._symbol_list), op) + return richcmp((self._weight, self._symbol_list), (right._weight, right._symbol_list), op) def symbol_list(self): """ @@ -392,6 +392,7 @@ class ManinSymbolList_group(ManinSymbolList): sage: ManinSymbolList_group(11, 2, P1List(11)) """ + def __init__(self, level, weight, syms): """ Constructor for class ManinSymbolList_group. @@ -417,8 +418,7 @@ def __init__(self, level, weight, syms): # The list returned from P1List is guaranteed to be sorted. # Thus each list constructed below is also sorted. This is # important since the index function assumes the list is sorted. - L = [(i, u, v) for i in range(weight - 2 + 1) - for u, v in syms.list()] + L = [(i, u, v) for i in range(weight - 2 + 1) for u, v in syms.list()] ManinSymbolList.__init__(self, weight, L) def level(self): @@ -568,14 +568,14 @@ def apply_T(self, j): """ k = self._weight i, u, v = self._symbol_list[j] - u, v = self.__syms.normalize(v,-u-v) - if (k-2) % 2 == 0: + u, v = self.__syms.normalize(v, -u - v) + if (k - 2) % 2 == 0: s = 1 else: s = -1 z = [] - a = Integer(k-2-i) - for j in range(k-2-i+1): + a = Integer(k - 2 - i) + for j in range(k - 2 - i + 1): m = self.index((j, u, v)) z.append((m, s * a.binomial(j))) s *= -1 @@ -611,15 +611,15 @@ def apply_TT(self, j): """ k = self._weight i, u, v = self._symbol_list[j] - u, v = self.__syms.normalize(-u-v,u) - if (k-2-i) % 2 == 0: + u, v = self.__syms.normalize(-u - v, u) + if (k - 2 - i) % 2 == 0: s = 1 else: s = -1 z = [] a = Integer(i) - for j in range(i+1): - m = self.index((k-2-i+j, u, v)) + for j in range(i + 1): + m = self.index((k - 2 - i + j, u, v)) z.append((m, s * a.binomial(j))) s *= -1 return z @@ -653,13 +653,12 @@ def apply(self, j, m): """ a, b, c, d = m[0], m[1], m[2], m[3] i, u, v = self._symbol_list[j] - P = apply_to_monomial(i, self._weight-2, a, b, c, d) - m = self.index((0, u*a+v*c, u*b+v*d)) + P = apply_to_monomial(i, self._weight - 2, a, b, c, d) + m = self.index((0, u * a + v * c, u * b + v * d)) if m == -1: return [] r = len(self.__syms) - return [(m + r*k, P[k]) for k in range(self._weight-2+1) - if P[k] != 0] + return [(m + r * k, P[k]) for k in range(self._weight - 2 + 1) if P[k] != 0] def normalize(self, x): """ @@ -691,8 +690,8 @@ def normalize(self, x): (1, 1, 1), (1, 1, 2)] """ - u,v = self.__syms.normalize(x[1],x[2]) - return (x[0],u,v) + u, v = self.__syms.normalize(x[1], x[2]) + return (x[0], u, v) class ManinSymbolList_gamma0(ManinSymbolList_group): @@ -717,6 +716,7 @@ class ManinSymbolList_gamma0(ManinSymbolList_group): sage: len(m) 36 """ + def __init__(self, level, weight): """ Constructor for a ModularSymbolList for Gamma_0(N). @@ -743,8 +743,7 @@ def __repr__(self): sage: str(M11) 'Manin Symbol List of weight 2 for Gamma0(11)' """ - return "Manin Symbol List of weight %s for Gamma0(%s)" % ( - self.weight(), self.level()) + return "Manin Symbol List of weight %s for Gamma0(%s)" % (self.weight(), self.level()) class ManinSymbolList_gamma1(ManinSymbolList_group): @@ -776,6 +775,7 @@ class ManinSymbolList_gamma1(ManinSymbolList_group): sage: m == loads(dumps(m)) True """ + def __init__(self, level, weight): r""" Constructor for a ModularSymbolList for `\Gamma_0(N)`. @@ -800,8 +800,7 @@ def __repr__(self): sage: str(M11) 'Manin Symbol List of weight 4 for Gamma1(11)' """ - return "Manin Symbol List of weight %s for Gamma1(%s)" % ( - self.weight(), self.level()) + return "Manin Symbol List of weight %s for Gamma1(%s)" % (self.weight(), self.level()) class ManinSymbolList_gamma_h(ManinSymbolList_group): @@ -836,6 +835,7 @@ class ManinSymbolList_gamma_h(ManinSymbolList_group): sage: m == loads(dumps(m)) True """ + def __init__(self, group, weight): r""" Constructor for Manin symbols for `\Gamma_H(N)`. @@ -870,8 +870,7 @@ def __repr__(self): sage: ModularSymbols(GammaH(12, [5]), 2).manin_symbols().__repr__() 'Manin Symbol List of weight 2 for Congruence Subgroup Gamma_H(12) with H generated by [5]' """ - return "Manin Symbol List of weight %s for %s" % ( - self.weight(), self.group()) + return "Manin Symbol List of weight %s for %s" % (self.weight(), self.group()) class ManinSymbolList_character(ManinSymbolList): @@ -896,6 +895,7 @@ class ManinSymbolList_character(ManinSymbolList): sage: m == loads(dumps(m)) True """ + def __init__(self, character, weight): """ Constructor for :class:`ManinSymbolList_character` objects. @@ -931,8 +931,7 @@ def __init__(self, character, weight): # The list returned from P1List is guaranteed to be sorted. # Thus each list constructed below is also sorted. This is # important since the index function assumes the list is sorted. - L = [(i, u, v) for i in range(weight - 2 + 1) - for u, v in self.__P1.list()] + L = [(i, u, v) for i in range(weight - 2 + 1) for u, v in self.__P1.list()] self.__list = L ManinSymbolList.__init__(self, weight, L) @@ -950,8 +949,7 @@ def __repr__(self): sage: str(m) # indirect doctest 'Manin Symbol List of weight 2 for Gamma1(4) with character [-1]' """ - return "Manin Symbol List of weight %s for Gamma1(%s) with character %s" % ( - self.weight(), self.level(), self.character()._repr_short_()) + return "Manin Symbol List of weight %s for Gamma1(%s) with character %s" % (self.weight(), self.level(), self.character()._repr_short_()) def level(self): """ @@ -1004,13 +1002,12 @@ def apply(self, j, m): """ a, b, c, d = m[0], m[1], m[2], m[3] i, u, v = self._symbol_list[j] - P = apply_to_monomial(i, self._weight-2, a, b, c, d) - m, s = self.index((0, u*a+v*c, u*b+v*d)) + P = apply_to_monomial(i, self._weight - 2, a, b, c, d) + m, s = self.index((0, u * a + v * c, u * b + v * d)) if m == -1 or s == 0: return [] r = len(self.__P1) - return [(m + r*k, s*P[k]) for k in range(self._weight-2+1) - if P[k] != 0] + return [(m + r * k, s * P[k]) for k in range(self._weight - 2 + 1) if P[k] != 0] def apply_S(self, j): """ @@ -1123,15 +1120,15 @@ def apply_T(self, j): """ k = self._weight i, u, v = self._symbol_list[j] - u, v, r = self.__P1.normalize_with_scalar(v,-u-v) + u, v, r = self.__P1.normalize_with_scalar(v, -u - v) r = self.__character(r) - if (k-2) % 2 == 0: + if (k - 2) % 2 == 0: s = r else: s = -r z = [] - a = Integer(k-2-i) - for j in range(k-2-i+1): + a = Integer(k - 2 - i) + for j in range(k - 2 - i + 1): m, r = self.index((j, u, v)) z.append((m, s * r * a.binomial(j))) s *= -1 @@ -1166,16 +1163,16 @@ def apply_TT(self, j): """ k = self._weight i, u, v = self._symbol_list[j] - u, v, r = self.__P1.normalize_with_scalar(-u-v,u) + u, v, r = self.__P1.normalize_with_scalar(-u - v, u) r = self.__character(r) - if (k-2-i) % 2 == 0: + if (k - 2 - i) % 2 == 0: s = r else: s = -r z = [] a = Integer(i) - for j in range(i+1): - m, r = self.index((k-2-i+j, u, v)) + for j in range(i + 1): + m, r = self.index((k - 2 - i + j, u, v)) z.append((m, s * r * a.binomial(j))) s *= -1 return z @@ -1269,19 +1266,13 @@ def normalize(self, x): ((2, 1, 3), 1), ((2, 2, 1), 1)] """ - u,v,s = self.__P1.normalize_with_scalar(x[1],x[2]) - return (x[0],u,v), self.__character(s) - - -register_unpickle_override('sage.modular.modsym.manin_symbols', - 'ManinSymbolList', ManinSymbolList) -register_unpickle_override('sage.modular.modsym.manin_symbols', - 'ManinSymbolList_group', ManinSymbolList_group) -register_unpickle_override('sage.modular.modsym.manin_symbols', - 'ManinSymbolList_gamma0', ManinSymbolList_gamma0) -register_unpickle_override('sage.modular.modsym.manin_symbols', - 'ManinSymbolList_gamma1', ManinSymbolList_gamma1) -register_unpickle_override('sage.modular.modsym.manin_symbols', - 'ManinSymbolList_gamma_h', ManinSymbolList_gamma_h) -register_unpickle_override('sage.modular.modsym.manin_symbols', - 'ManinSymbolList_character', ManinSymbolList_character) + u, v, s = self.__P1.normalize_with_scalar(x[1], x[2]) + return (x[0], u, v), self.__character(s) + + +register_unpickle_override('sage.modular.modsym.manin_symbols', 'ManinSymbolList', ManinSymbolList) +register_unpickle_override('sage.modular.modsym.manin_symbols', 'ManinSymbolList_group', ManinSymbolList_group) +register_unpickle_override('sage.modular.modsym.manin_symbols', 'ManinSymbolList_gamma0', ManinSymbolList_gamma0) +register_unpickle_override('sage.modular.modsym.manin_symbols', 'ManinSymbolList_gamma1', ManinSymbolList_gamma1) +register_unpickle_override('sage.modular.modsym.manin_symbols', 'ManinSymbolList_gamma_h', ManinSymbolList_gamma_h) +register_unpickle_override('sage.modular.modsym.manin_symbols', 'ManinSymbolList_character', ManinSymbolList_character) diff --git a/src/sage/modular/modsym/modsym.py b/src/sage/modular/modsym/modsym.py index 79723274635..1817617add7 100644 --- a/src/sage/modular/modsym/modsym.py +++ b/src/sage/modular/modsym/modsym.py @@ -189,12 +189,7 @@ def ModularSymbols_clear_cache(): _cache = {} -def ModularSymbols(group=1, - weight=2, - sign=0, - base_ring=None, - use_cache=True, - custom_init=None): +def ModularSymbols(group=1, weight=2, sign=0, base_ring=None, use_cache=True, custom_init=None): r""" Create an ambient space of modular symbols. @@ -358,6 +353,7 @@ def ModularSymbols(group=1, False """ from . import ambient + key = canonical_parameters(group, weight, sign, base_ring) if use_cache and key in _cache: @@ -370,26 +366,21 @@ def ModularSymbols(group=1, M = None if isinstance(group, arithgroup.Gamma0_class): if weight == 2: - M = ambient.ModularSymbolsAmbient_wt2_g0( - group.level(), sign, base_ring, custom_init=custom_init) + M = ambient.ModularSymbolsAmbient_wt2_g0(group.level(), sign, base_ring, custom_init=custom_init) else: - M = ambient.ModularSymbolsAmbient_wtk_g0( - group.level(), weight, sign, base_ring, custom_init=custom_init) + M = ambient.ModularSymbolsAmbient_wtk_g0(group.level(), weight, sign, base_ring, custom_init=custom_init) elif isinstance(group, arithgroup.Gamma1_class): - M = ambient.ModularSymbolsAmbient_wtk_g1(group.level(), - weight, sign, base_ring, custom_init=custom_init) + M = ambient.ModularSymbolsAmbient_wtk_g1(group.level(), weight, sign, base_ring, custom_init=custom_init) elif isinstance(group, arithgroup.GammaH_class): - M = ambient.ModularSymbolsAmbient_wtk_gamma_h(group, - weight, sign, base_ring, custom_init=custom_init) + M = ambient.ModularSymbolsAmbient_wtk_gamma_h(group, weight, sign, base_ring, custom_init=custom_init) elif isinstance(group, tuple): eps = group[0] - M = ambient.ModularSymbolsAmbient_wtk_eps(eps, - weight, sign, base_ring, custom_init=custom_init) + M = ambient.ModularSymbolsAmbient_wtk_eps(eps, weight, sign, base_ring, custom_init=custom_init) if M is None: raise NotImplementedError("computation of requested space of modular symbols not defined or implemented") diff --git a/src/sage/modular/modsym/modular_symbols.py b/src/sage/modular/modsym/modular_symbols.py index 40503f98c2e..ef66e0e3e07 100644 --- a/src/sage/modular/modsym/modular_symbols.py +++ b/src/sage/modular/modsym/modular_symbols.py @@ -50,6 +50,7 @@ class ModularSymbol(SageObject): r""" The modular symbol `X^i\cdot Y^{k-2-i}\cdot \{\alpha, \beta\}`. """ + def __init__(self, space, i, alpha, beta): """ Initialise a modular symbol. @@ -133,9 +134,7 @@ def _latex_(self): polypart = '' else: polypart = latex(self.polynomial_part()) - return "%s\\left\\{%s, %s\\right\\}" % (polypart, - latex(self.__alpha), - latex(self.__beta)) + return "%s\\left\\{%s, %s\\right\\}" % (polypart, latex(self.__alpha), latex(self.__beta)) def __richcmp__(self, other, op): """ @@ -159,9 +158,7 @@ def __richcmp__(self, other, op): """ if not isinstance(other, ModularSymbol): return NotImplemented - return richcmp((self.__space, -self.__i, self.__alpha, self.__beta), - (other.__space,-other.__i,other.__alpha,other.__beta), - op) + return richcmp((self.__space, -self.__i, self.__alpha, self.__beta), (other.__space, -other.__i, other.__alpha, other.__beta), op) def __hash__(self): """ @@ -201,7 +198,7 @@ def polynomial_part(self): X^22*Y^4 """ i = self.__i - return X**i*Y**(self.weight()-2-i) + return X**i * Y ** (self.weight() - 2 - i) def i(self): r""" @@ -321,8 +318,7 @@ def apply(self, g): coeffs = apply_to_monomial(i, k - 2, d, -b, -c, a) g_alpha = self.__alpha.apply(g) g_beta = self.__beta.apply(g) - return formal_sum.FormalSum([(coeffs[j], ModularSymbol(space, j, g_alpha, g_beta)) - for j in reversed(range(k-1)) if coeffs[j] != 0]) + return formal_sum.FormalSum([(coeffs[j], ModularSymbol(space, j, g_alpha, g_beta)) for j in reversed(range(k - 1)) if coeffs[j] != 0]) def __manin_symbol_rep(self, alpha): """ @@ -345,19 +341,17 @@ def __manin_symbol_rep(self, alpha): space = self.__space i = self.__i k = space.weight() - v = [(0,1), (1,0)] + v = [(0, 1), (1, 0)] if not alpha.is_infinity(): cf = alpha._rational_().continued_fraction() - v.extend((cf.p(k),cf.q(k)) for k in range(len(cf))) + v.extend((cf.p(k), cf.q(k)) for k in range(len(cf))) sign = 1 z = formal_sum.FormalSum(0) - for j in range(1,len(v)): - c = sign*v[j][1] - d = v[j-1][1] - coeffs = apply_to_monomial(i, k-2, sign*v[j][0], v[j-1][0], - sign*v[j][1], v[j-1][1]) - w = [(coeffs[j], ManinSymbol(space, (j, c, d))) - for j in range(k-1) if coeffs[j] != 0] + for j in range(1, len(v)): + c = sign * v[j][1] + d = v[j - 1][1] + coeffs = apply_to_monomial(i, k - 2, sign * v[j][0], v[j - 1][0], sign * v[j][1], v[j - 1][1]) + w = [(coeffs[j], ManinSymbol(space, (j, c, d))) for j in range(k - 1) if coeffs[j] != 0] z += formal_sum.FormalSum(w) sign *= -1 return z @@ -380,4 +374,4 @@ def manin_symbol_rep(self): """ alpha = self.__alpha beta = self.__beta - return -1*self.__manin_symbol_rep(alpha) + self.__manin_symbol_rep(beta) + return -1 * self.__manin_symbol_rep(alpha) + self.__manin_symbol_rep(beta) diff --git a/src/sage/modular/modsym/p1list_nf.py b/src/sage/modular/modsym/p1list_nf.py index 24e1e3346cc..3ccf8191cb9 100644 --- a/src/sage/modular/modsym/p1list_nf.py +++ b/src/sage/modular/modsym/p1list_nf.py @@ -177,6 +177,7 @@ class MSymbol(SageObject): sage: loads(dumps(alpha))==alpha True """ + def __init__(self, N, c, d=None, check=True): """ See ``MSymbol`` for full documentation. @@ -268,8 +269,7 @@ def __richcmp__(self, other, op): """ if not isinstance(other, MSymbol): raise ValueError("You can only compare with another M-symbol") - return richcmp([self.__c.list(), self.__d.list()], - [other.__c.list(), other.__d.list()], op) + return richcmp([self.__c.list(), self.__d.list()], [other.__c.list(), other.__d.list()], op) def N(self): r""" @@ -339,6 +339,7 @@ def __get_c(self): 3 """ return self.__c + c = property(__get_c) def __get_d(self): @@ -355,6 +356,7 @@ def __get_d(self): a^2 + 1 """ return self.__d + d = property(__get_d) def lift_to_sl2_Ok(self): @@ -441,14 +443,14 @@ def normalize(self, with_scalar=False): if N.is_coprime(self.c): cinv = R(self.c).inverse_mod(N) if with_scalar: - return N.reduce(self.c), MSymbol(N, 1, N.reduce(self.d*cinv)) - return MSymbol(N, 1, N.reduce(self.d*cinv)) + return N.reduce(self.c), MSymbol(N, 1, N.reduce(self.d * cinv)) + return MSymbol(N, 1, N.reduce(self.d * cinv)) if N in _level_cache: Lfacs, Lxs = _level_cache[N] else: Lfacs = [p**e for p, e in N.factor()] - Lxs = [(N/p).element_1_mod(p) for p in Lfacs] + Lxs = [(N / p).element_1_mod(p) for p in Lfacs] # Lfacs, Lxs only depend of the ideal: same lists every time we # call normalize for a given level, so we store the lists. _level_cache[N] = (Lfacs, Lxs) @@ -459,9 +461,9 @@ def normalize(self, with_scalar=False): inv = self.c.inverse_mod(p) else: inv = self.d.inverse_mod(p) - u = u + inv*Lxs[p_i] + u = u + inv * Lxs[p_i] p_i = p_i + 1 - c, d = (N.reduce(u*self.c), N.reduce(u*self.d)) + c, d = (N.reduce(u * self.c), N.reduce(u * self.d)) if (c - 1) in N: c = R(1) if with_scalar: @@ -503,6 +505,7 @@ class P1NFList(SageObject): sage: loads(dumps(P)) == P True """ + def __init__(self, N): r""" The constructor for the class P1NFList. See ``P1NFList`` for full @@ -942,7 +945,7 @@ def apply_T_alpha(self, i, alpha=1): True """ c, d = self.__list[i].tuple() - t, j = search(self.__list, self.normalize(c, alpha*c + d)) + t, j = search(self.__list, self.normalize(c, alpha * c + d)) return j def apply_J_epsilon(self, i, e1, e2=1): @@ -989,7 +992,7 @@ def apply_J_epsilon(self, i, e1, e2=1): True """ c, d = self.__list[i].tuple() - t, j = search(self.__list, self.normalize(c*e1, d*e2)) + t, j = search(self.__list, self.normalize(c * e1, d * e2)) return j @@ -1001,6 +1004,7 @@ def apply_J_epsilon(self, i, e1, e2=1): # - psi -- useful to check cardinality of the M-symbols list # ************************************************************************* + def p1NFlist(N): r""" Return a list of the normalized elements of `\mathbb{P}^1(R/N)`, where @@ -1026,6 +1030,7 @@ def p1NFlist(N): L = L + [MSymbol(N, k(1), r, check=False) for r in N.residues()] from sage.arith.misc import divisors + for D in divisors(N): if not D.is_trivial() and D != N: # we find Dp ideal coprime to N, in inverse class to D @@ -1035,16 +1040,16 @@ def p1NFlist(N): else: it = k.primes_of_degree_one_iter() Dp = next(it) - while not Dp.is_coprime(N) or not (Dp*D).is_principal(): + while not Dp.is_coprime(N) or not (Dp * D).is_principal(): Dp = next(it) - c = (D*Dp).gens_reduced()[0] + c = (D * Dp).gens_reduced()[0] # now we find all the (c,d)'s which have associated divisor D - I = D + N/D - for d in (N/D).residues(): + I = D + N / D + for d in (N / D).residues(): if I.is_coprime(d): - M = D.prime_to_idealM_part(N/D) - u = (Dp*M).element_1_mod(N/D) - d1 = u*d + (1-u) + M = D.prime_to_idealM_part(N / D) + u = (Dp * M).element_1_mod(N / D) + d1 = u * d + (1 - u) L.append(MSymbol(N, c, d1, check=False).normalize()) return L @@ -1133,25 +1138,25 @@ def lift_to_sl2_Ok(N, c, d): if c.is_zero(): # and d!=1, so won't happen for normalized M-symbols (c: d) it = k.primes_of_degree_one_iter() q = k.ideal(1) - while not (q.is_coprime(d) and (q*N).is_principal()): + while not (q.is_coprime(d) and (q * N).is_principal()): q = next(it) - m = (q*N).gens_reduced()[0] + m = (q * N).gens_reduced()[0] B = k.ideal(m).element_1_mod(k.ideal(d)) - return [(1-B)/d, -B/m, m, d] + return [(1 - B) / d, -B / m, m, d] if d.is_zero(): # and c!=1, so won't happen for normalized M-symbols (c: d) it = k.primes_of_degree_one_iter() q = k.ideal(1) - while not (q.is_coprime(c) and (q*N).is_principal()): + while not (q.is_coprime(c) and (q * N).is_principal()): q = next(it) - m = (q*N).gens_reduced()[0] + m = (q * N).gens_reduced()[0] B = k.ideal(c).element_1_mod(k.ideal(m)) - return [(1-B)/m, -B/c, c, m] + return [(1 - B) / m, -B / c, c, m] c, d = make_coprime(N, c, d) B = k.ideal(c).element_1_mod(k.ideal(d)) - b = -B/c - a = (1-B)/d + b = -B / c + a = (1 - B) / d return [a, b, c, d] @@ -1195,10 +1200,10 @@ def make_coprime(N, c, d): q = k.ideal(c).prime_to_idealM_part(d) it = k.primes_of_degree_one_iter() r = k.ideal(1) - qN = q*N - while not (r.is_coprime(c) and (r*qN).is_principal()): + qN = q * N + while not (r.is_coprime(c) and (r * qN).is_principal()): r = next(it) - m = (r*qN).gens_reduced()[0] + m = (r * qN).gens_reduced()[0] d1 = d + m return c, d1 @@ -1229,6 +1234,5 @@ def psi(N): raise ValueError("psi only defined for integral ideals") from sage.misc.misc_c import prod - return prod([(np + 1) * np**(e - 1) - for np, e in [(p.absolute_norm(), e) - for p, e in N.factor()]]) + + return prod([(np + 1) * np ** (e - 1) for np, e in [(p.absolute_norm(), e) for p, e in N.factor()]]) diff --git a/src/sage/modular/modsym/relation_matrix.py b/src/sage/modular/modsym/relation_matrix.py index f2733cecf7e..92a12e268c8 100644 --- a/src/sage/modular/modsym/relation_matrix.py +++ b/src/sage/modular/modsym/relation_matrix.py @@ -291,6 +291,7 @@ def gens_to_basis_matrix(syms, relation_matrix, mod, field, sparse): (24 x 2 sparse matrix over Finite Field of size 3, [13, 23]) """ from sage.structure.element import Matrix + if not isinstance(relation_matrix, Matrix): raise TypeError("relation_matrix must be a matrix") if not isinstance(mod, list): @@ -304,8 +305,7 @@ def gens_to_basis_matrix(syms, relation_matrix, mod, field, sparse): h = 9999999 tm = verbose("putting relation matrix in echelon form (height = %s)" % h) if h < 10: - A = relation_matrix.echelon_form(algorithm='multimodular', - height_guess=1) + A = relation_matrix.echelon_form(algorithm='multimodular', height_guess=1) else: A = relation_matrix.echelon_form() A.set_immutable() @@ -336,7 +336,7 @@ def gens_to_basis_matrix(syms, relation_matrix, mod, field, sparse): if t: B[i, l] = ONE else: - _, r = search(pivots, i) # so pivots[r] = i + _, r = search(pivots, i) # so pivots[r] = i # Set row i to -(row r of A), but where we only take # the non-pivot columns of A: B._set_row_to_negative_of_row_of_A_using_subset_of_columns(i, A, r, basis, cols_index) @@ -348,7 +348,7 @@ def gens_to_basis_matrix(syms, relation_matrix, mod, field, sparse): k = 0 for i in range(len(mod)): j, s = mod[i] - if j != i and s != 0: # ignored in the above matrix + if j != i and s != 0: # ignored in the above matrix k += 1 B.set_row_to_multiple_of_row(i, j, s) verbose("set %s rows" % k) @@ -494,6 +494,7 @@ def relation_matrix_wtk_g0(syms, sign, field, sparse): if syms._apply_S_only_0pm1() and isinstance(field, RationalField): from . import relation_matrix_pyx + mod = relation_matrix_pyx.sparse_2term_quotient_only_pm1(rels, len(syms)) else: mod = sparse_2term_quotient(rels, len(syms), field) diff --git a/src/sage/modular/modsym/space.py b/src/sage/modular/modsym/space.py index e11fb026b4c..a6d644846b2 100644 --- a/src/sage/modular/modsym/space.py +++ b/src/sage/modular/modsym/space.py @@ -40,8 +40,7 @@ from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.rational_field import QQ from sage.structure.all import Sequence, SageObject -from sage.structure.richcmp import (richcmp_method, richcmp, - rich_to_bool, richcmp_not_equal) +from sage.structure.richcmp import richcmp_method, richcmp, rich_to_bool, richcmp_not_equal from sage.modular.arithgroup.congroup_gamma0 import Gamma0_constructor as Gamma0, Gamma0_class # for Sturm bound given a character from sage.modular.hecke.module import HeckeModule_free_module @@ -398,6 +397,7 @@ def is_ambient(self) -> bool: False """ from sage.modular.modsym.ambient import ModularSymbolsAmbient + return isinstance(self, ModularSymbolsAmbient) def is_cuspidal(self) -> bool: @@ -691,7 +691,13 @@ def q_expansion_basis(self, prec=None, algorithm='default'): B1 = self._q_expansion_basis_hecke_dual(prec) B2 = self._q_expansion_basis_eigen(prec, 'alpha') if B1 != B2: - raise RuntimeError("There is a bug in q_expansion_basis -- basis computed differently with two algorithms:\n%s\n%s\n" % (B1, B2,)) + raise RuntimeError( + "There is a bug in q_expansion_basis -- basis computed differently with two algorithms:\n%s\n%s\n" + % ( + B1, + B2, + ) + ) return Sequence(B1, cr=True) raise ValueError("no algorithm '%s'" % algorithm) @@ -931,7 +937,7 @@ def _q_expansion_module(self, prec, algorithm='hecke'): return self._q_expansion_module_integral(prec) raise NotImplementedError("base ring must be a field (or ZZ).") - V = R ** prec + V = R**prec if algorithm == 'hecke' or algorithm == 'default': return V.span([f.padded_list(prec) for f in self.q_expansion_basis(prec, algorithm)]) @@ -962,9 +968,7 @@ def q_eigen_gens(d, f): else: X = self - B = [sum([q_eigen_gens(A.dimension(), f) - for f in self._q_eigenform_images(A, prec, 'zeta')], []) - for A, _ in X.factorization()] + B = [sum([q_eigen_gens(A.dimension(), f) for f in self._q_eigenform_images(A, prec, 'zeta')], []) for A, _ in X.factorization()] return V.span(sum(B, [])) @@ -1023,16 +1027,14 @@ def q_eigen_gens(d, f): # This looks like it might be really slow -- though # perhaps it's nothing compared to the time taken by # whatever computed this in the first place. - return [[(X[i].list())[j][k] for i in range(prec)] - for j in range(d) for k in range(n)] + return [[(X[i].list())[j][k] for i in range(prec)] for j in range(d) for k in range(n)] + if self.sign() == 0: X = self.plus_submodule(compute_dual=True) else: X = self - B = [sum([q_eigen_gens(A.dimension(), f) - for f in self._q_eigenform_images(A, prec, 'alpha')], []) - for A, _ in X.factorization()] + B = [sum([q_eigen_gens(A.dimension(), f) for f in self._q_eigenform_images(A, prec, 'alpha')], []) for A, _ in X.factorization()] A = QQ**prec return A.span(sum(B, [])) @@ -1167,11 +1169,11 @@ def q_eigenform_character(self, names=None): i = v.nonzero_positions()[0] K = v.base_ring() from sage.modular.dirichlet import DirichletGroup + G = DirichletGroup(self.level(), K) M = self.ambient_module() # act on right since v is a in the dual - b = [(M.diamond_bracket_matrix(u) * v)[i] / v[i] - for u in G.unit_gens()] + b = [(M.diamond_bracket_matrix(u) * v)[i] / v[i] for u in G.unit_gens()] return G(b) def q_eigenform(self, prec, names=None): @@ -1233,8 +1235,7 @@ def _q_expansion_basis_eigen(self, prec, names): # should we perhaps check at this point if self is new? f = self.q_eigenform(prec, names) R = PowerSeriesRing(self.base_ring(), 'q') - return [R([f[i][j] for i in range(prec)], prec) - for j in range(self.rank())] + return [R([f[i][j] for i in range(prec)], prec) for j in range(self.rank())] raise NotImplementedError ######################################################################### @@ -1317,6 +1318,7 @@ def _q_expansion_basis_hecke_dual(self, prec): [q + O(q^2)] """ from sage.misc.verbose import verbose + d = self.dimension_of_associated_cuspform_space() prec = Integer(prec) if prec < 1: @@ -1353,19 +1355,19 @@ def _q_expansion_basis_hecke_dual(self, prec): # ########################################################################## -# def factorization(self): -# """ -# Return a list of pairs `(S,e)` where `S` is simple -# spaces of modular symbols and self is isomorphic to the direct sum -# of the `S^e` as a module over the *anemic* Hecke algebra -# adjoin the star involution. -# -# ASSUMPTION: self is a module over the anemic Hecke algebra. -# """ -# try: -# return self._factorization -# except AttributeError: -# raise NotImplementedError + # def factorization(self): + # """ + # Return a list of pairs `(S,e)` where `S` is simple + # spaces of modular symbols and self is isomorphic to the direct sum + # of the `S^e` as a module over the *anemic* Hecke algebra + # adjoin the star involution. + # + # ASSUMPTION: self is a module over the anemic Hecke algebra. + # """ + # try: + # return self._factorization + # except AttributeError: + # raise NotImplementedError def hecke_module_of_level(self, level): r""" @@ -1890,6 +1892,7 @@ def abelian_variety(self): if not self.is_cuspidal(): raise ValueError("self must be cuspidal") from sage.modular.abvar.abvar import ModularAbelianVariety_modsym + A = ModularAbelianVariety_modsym(self, check=False) self.__modular_abelian_variety = A return A @@ -2004,8 +2007,8 @@ def integral_period_mapping(self): C = I * D if not C.is_one(): if not C.is_square(): - C = (ZZ**C.ncols()).span(C.rows()).basis_matrix() - D = D * C**(-1) + C = (ZZ ** C.ncols()).span(C.rows()).basis_matrix() + D = D * C ** (-1) D.set_immutable() R = IntegralPeriodMapping(self, D) self.__integral_period_mapping = R @@ -2077,7 +2080,7 @@ def modular_symbols_of_sign(self, sign, bound=None): if sign != 0: if self.sign() == 0: d = d // 2 - elif sign == 0: # self has nonzero sign + elif sign == 0: # self has nonzero sign d = 2 * d B = self.ambient_module().modular_symbols_of_sign(sign) p = 2 @@ -2087,7 +2090,7 @@ def modular_symbols_of_sign(self, sign, bound=None): while self.level() % p == 0: p = next_prime(p) f = self.hecke_polynomial(p) - g = prod(g for g, _ in f.factor()) # square free part + g = prod(g for g, _ in f.factor()) # square free part t = B.hecke_operator(p) s = g(t) B = s.kernel() @@ -2228,7 +2231,7 @@ def abvarquo_rational_cuspidal_subgroup(self): # Define the vector space V, which we think of as # the vector space with basis (c)-(oo), where c runs # through the finite cusp *classes*. - V = ZZ**len(P) # vector space on (c)-(oo) + V = ZZ ** len(P) # vector space on (c)-(oo) # Compute the images of the cusp classes (c)-(oo) in the # rational homology of the quotient modular abelian variety. @@ -2306,6 +2309,7 @@ def _matrix_of_galois_action(self, t, P): """ N = self.level() from sage.matrix.constructor import matrix + A = matrix(ZZ, len(P)) for i, c in enumerate(P): d = c.galois_action(t, N) @@ -2324,6 +2328,7 @@ class PeriodMapping(SageObject): To be used via the derived classes :class:`RationalPeriodMapping` and :class:`IntegralPeriodMapping`. """ + def __init__(self, modsym, A): r""" Standard initialisation function. diff --git a/src/sage/modular/modsym/subspace.py b/src/sage/modular/modsym/subspace.py index 191cabcaf45..708a9ba06a6 100644 --- a/src/sage/modular/modsym/subspace.py +++ b/src/sage/modular/modsym/subspace.py @@ -29,11 +29,11 @@ class ModularSymbolsSubspace(sage.modular.modsym.space.ModularSymbolsSpace, heck """ Subspace of ambient space of modular symbols """ + ################################ # Special Methods ################################ - def __init__(self, ambient_hecke_module, submodule, - dual_free_module=None, check=False): + def __init__(self, ambient_hecke_module, submodule, dual_free_module=None, check=False): """ INPUT: @@ -69,9 +69,7 @@ def __init__(self, ambient_hecke_module, submodule, """ self.__ambient_hecke_module = ambient_hecke_module A = ambient_hecke_module - sage.modular.modsym.space.ModularSymbolsSpace.__init__(self, A.group(), - A.weight(), - A.character(), A.sign(), A.base_ring()) + sage.modular.modsym.space.ModularSymbolsSpace.__init__(self, A.group(), A.weight(), A.character(), A.sign(), A.base_ring()) hecke.HeckeSubmodule.__init__(self, A, submodule, dual_free_module=dual_free_module, check=check) def _repr_(self): @@ -83,8 +81,7 @@ def _repr_(self): sage: ModularSymbols(24,4).cuspidal_subspace()._repr_() 'Modular Symbols subspace of dimension 16 of Modular Symbols space of dimension 24 for Gamma_0(24) of weight 4 with sign 0 over Rational Field' """ - return "Modular Symbols subspace of dimension %s of %s" % ( - self.rank(), self.ambient_module()) + return "Modular Symbols subspace of dimension %s of %s" % (self.rank(), self.ambient_module()) ################################ # Public functions @@ -317,8 +314,7 @@ def factorization(self): r = self.dimension() s = sum([A.rank() * mult for A, mult in D]) if r != s: - raise NotImplementedError("modular symbols factorization not fully implemented yet " - "-- self has dimension %s, but sum of dimensions of factors is %s" % (r, s)) + raise NotImplementedError("modular symbols factorization not fully implemented yet " "-- self has dimension %s, but sum of dimensions of factors is %s" % (r, s)) self._factorization = sage.structure.factorization.Factorization(D, cr=True) return self._factorization diff --git a/src/sage/modular/modsym/tests.py b/src/sage/modular/modsym/tests.py index 243174e8994..aa02220b513 100644 --- a/src/sage/modular/modsym/tests.py +++ b/src/sage/modular/modsym/tests.py @@ -39,8 +39,8 @@ class Test: """ Modular symbol testing class. """ - def __init__(self, levels=20, weights=4, onlyg0=False, onlyg1=False, - onlychar=False): + + def __init__(self, levels=20, weights=4, onlyg0=False, onlyg1=False, onlychar=False): """ Create a modular symbol testing object. @@ -298,8 +298,7 @@ def test_csnew_dimension(self): V = M.cuspidal_submodule().new_submodule() d = V.dimension() d2 = M._cuspidal_new_submodule_dimension_formula() - assert d == d2, \ - "Test failed for M=\"%s\", where computed dimension is %s but formula dimension is %s." % (M, d, d2) + assert d == d2, "Test failed for M=\"%s\", where computed dimension is %s but formula dimension is %s." % (M, d, d2) def test_csns_nscs(self): """ @@ -319,9 +318,7 @@ def test_csns_nscs(self): V2 = M.new_submodule().cuspidal_submodule() assert V1 == V2, "Test failed for M=\"%s\", where the new cuspidal and cuspidal new spaces are computed differently." % M d = M._cuspidal_new_submodule_dimension_formula() - assert d == V1.dimension(), \ - "Test failed for M=\"%s\", where computed dimension is %s but formula dimension is %s." % ( - M, V1.dimension(), d) + assert d == V1.dimension(), "Test failed for M=\"%s\", where computed dimension is %s but formula dimension is %s." % (M, V1.dimension(), d) def test_decomposition(self): """ @@ -368,8 +365,7 @@ def test_random(self): level = 18, weight = 4, sign = -1 Modular Symbols space of dimension 0 and level 18, weight 4, character [1, -1], sign -1, over Rational Field """ - tests = [a for a in Test.__dict__ - if a[:5] == "test_" and a != "test_random"] + tests = [a for a in Test.__dict__ if a[:5] == "test_" and a != "test_random"] name = random.choice(tests) print("Doing random test %s" % name) Test.__dict__[name](self) diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index 975d91b2d6b..779c114d977 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -205,17 +205,7 @@ # using the following convention # (3, 5) <---> (sign) * [1,0,0,1,0,0,0,0] # taken from the Maple implementation by F. Brown -B_data: list[list[tuple]] = [[], [], [(2,)], [(3,)], [], [(5,)], [], - [(7,)], [(3, 5)], [(9,)], - [(3, 7)], [(11,), (3, 3, 5)], - [(5, 7), (5, 3, 2, 2)], - [(13,), (3, 5, 5), (3, 3, 7)], - [(5, 9), (3, 11), (3, 3, 3, 5)], - [(15,), (3, 5, 7), (3, 3, 9), (5, 3, 3, 2, 2)], - [(11, 5), (13, 3), (5, 5, 3, 3), - (7, 3, 3, 3), (7, 5, 2, 2)], - [(17,), (7, 5, 5), (9, 3, 5), (9, 5, 3), - (11, 3, 3), (5, 3, 3, 3, 3), (5, 5, 3, 2, 2)]] +B_data: list[list[tuple]] = [[], [], [(2,)], [(3,)], [], [(5,)], [], [(7,)], [(3, 5)], [(9,)], [(3, 7)], [(11,), (3, 3, 5)], [(5, 7), (5, 3, 2, 2)], [(13,), (3, 5, 5), (3, 3, 7)], [(5, 9), (3, 11), (3, 3, 3, 5)], [(15,), (3, 5, 7), (3, 3, 9), (5, 3, 3, 2, 2)], [(11, 5), (13, 3), (5, 5, 3, 3), (7, 3, 3, 3), (7, 5, 2, 2)], [(17,), (7, 5, 5), (9, 3, 5), (9, 5, 3), (11, 3, 3), (5, 3, 3, 3, 3), (5, 5, 3, 2, 2)]] Words10 = Words((1, 0), infinite=False) @@ -254,8 +244,7 @@ def coproduct_iterator(paire) -> Iterator[list]: if step == 5: continue if tail[step] != start_value: - yield from coproduct_iterator((head + [last_index + step], - tail[step:])) + yield from coproduct_iterator((head + [last_index + step], tail[step:])) def composition_to_iterated(w, reverse=False) -> tuple[int, ...]: @@ -381,13 +370,13 @@ def minimize_term(w, cf): if x < y: return (w, cf) if x > y: - return (Words10(reverse_w, check=False), - -cf if len(w) % 2 else cf) + return (Words10(reverse_w, check=False), -cf if len(w) % 2 else cf) return (w, cf) # numerical values + class MultizetaValues(Singleton): """ Custom cache for numerical values of multiple zetas. @@ -423,6 +412,7 @@ class MultizetaValues(Singleton): sage: parent(M((2,3,4,5), prec=128)) Real Field with 128 bits of precision """ + def __init__(self) -> None: """ When first called, pre-compute up to weight 8 at precision 1024. @@ -650,6 +640,7 @@ class Multizetas(CombinatorialFreeModule): sage: z ζ(1,2,3) """ + def __init__(self, R) -> None: """ TESTS:: @@ -983,8 +974,7 @@ def basis_data(self, basering, n) -> Iterator: """ basis_MZV = extend_multiplicative_basis(B_data, n) W = self.basis().keys() - return (prod(self._monomial(W(compo, check=False)) - for compo in term) for term in basis_MZV) + return (prod(self._monomial(W(compo, check=False)) for compo in term) for term in basis_MZV) def basis_brown(self, n) -> list: r""" @@ -1012,8 +1002,7 @@ def basis_brown(self, n) -> list: [ζ(3,3), ζ(2,2,2)] """ W = self.basis().keys() - return [self._monomial(W(tuple(c), check=False)) - for c in IntegerVectors(n, min_part=2, max_part=3)] + return [self._monomial(W(tuple(c), check=False)) for c in IntegerVectors(n, min_part=2, max_part=3)] @cached_method def basis_filtration(self, d, reverse=False): @@ -1374,6 +1363,7 @@ def numerical_approx(self, prec=None, digits=None, algorithm=None): if prec is None: if digits: from sage.arith.numerical_approx import digits_to_bits + prec = digits_to_bits(digits) else: prec = 53 @@ -1407,6 +1397,7 @@ class Multizetas_iterated(CombinatorialFreeModule): sage: M((1,0))*M((1,0,0)) 6*I(11000) + 3*I(10100) + I(10010) """ + def __init__(self, R) -> None: """ TESTS:: @@ -1423,8 +1414,7 @@ def __init__(self, R) -> None: cat = GradedAlgebrasWithBasis(R).Commutative() if R in Domains(): cat = cat & Domains() - CombinatorialFreeModule.__init__(self, R, Words10, prefix='I', - category=cat) + CombinatorialFreeModule.__init__(self, R, Words10, prefix='I', category=cat) def _repr_(self) -> str: """ @@ -1538,9 +1528,7 @@ def half_product(self): 2*I(1100) + I(1010) """ half = self.half_product_on_basis - return self._module_morphism(self._module_morphism(half, position=0, - codomain=self), - position=1) + return self._module_morphism(self._module_morphism(half, position=0, codomain=self), position=1) def coproduct_on_basis(self, w): """ @@ -1563,7 +1551,7 @@ def coproduct_on_basis(self, w): def split_word(indices): L = self.one() for i in range(len(indices) - 1): - w = Word(seq[indices[i]:indices[i + 1] + 1]) + w = Word(seq[indices[i] : indices[i + 1] + 1]) if len(w) == 2: # this factor is one continue if len(w) <= 4 or len(w) == 6 or w[0] == w[-1]: @@ -1575,8 +1563,7 @@ def split_word(indices): resu = self.tensor_square().zero() for indices in terms: - resu += split_word(indices).tensor( - M_all(Word(seq[i] for i in indices)).regularise().simplify()) + resu += split_word(indices).tensor(M_all(Word(seq[i] for i in indices)).regularise().simplify()) return resu @lazy_attribute @@ -1641,7 +1628,7 @@ def composition_on_basis(self, w, basering=None): if basering is None: basering = self.base_ring() codomain = Multizetas(basering) - return (-1)**w.count(1) * codomain(iterated_to_composition(w)) + return (-1) ** w.count(1) * codomain(iterated_to_composition(w)) def dual_on_basis(self, w): """ @@ -1717,8 +1704,8 @@ def D_on_basis(self, k, w): it = [0] + list(w) + [1] coprod = MZV_MZV.zero() for p in range(N + 1 - k): - left = Im(it[p: p + k + 2]) - right = Im(it[:p + 1] + it[p + k + 1:]) + left = Im(it[p : p + k + 2]) + right = Im(it[: p + 1] + it[p + k + 1 :]) if left and right: coprod += left.regularise().tensor(right.regularise()) return coprod @@ -1740,11 +1727,12 @@ def D(self, k): sage: D3(elt) -6*I(100) # I(110) + 3*I(100) # I(10) """ + def map_on_basis(elt): return self.D_on_basis(k, elt) + cod = Multizetas_iterated(self.base_ring()).tensor_square() - return self.module_morphism(map_on_basis, position=0, - codomain=cod) + return self.module_morphism(map_on_basis, position=0, codomain=cod) @cached_method def phi_extended(self, w): @@ -1806,7 +1794,7 @@ def phi_extended(self, w): compo = tuple(iterated_to_composition(w)) if compo in B_data[N]: # do not forget the sign - return (-1)**len(compo) * phi_on_multiplicative_basis(compo) + return (-1) ** len(compo) * phi_on_multiplicative_basis(compo) u = compute_u_on_basis(w) rho_inverse_u = rho_inverse(u) xi = self.composition_on_basis(w, QQ) @@ -1906,8 +1894,7 @@ def simplify(self): I(100) """ summing = self.parent().sum_of_terms - return summing(minimize_term(w, cf) - for w, cf in self.monomial_coefficients().items()) + return summing(minimize_term(w, cf) for w, cf in self.monomial_coefficients().items()) def coproduct(self): """ @@ -2068,6 +2055,7 @@ class All_iterated(CombinatorialFreeModule): sage: x.regularise() -I(10) """ + def __init__(self, R) -> None: """ TESTS:: @@ -2142,8 +2130,7 @@ def _element_constructor_(self, x): W = self.basis().keys() w = W(x, check=False) # condition R1 of F. Brown - if w[0] == w[-1] or (len(w) >= 4 and - all(x == w[1] for x in w[2:-1])): + if w[0] == w[-1] or (len(w) >= 4 and all(x == w[1] for x in w[2:-1])): return self.zero() return self._monomial(w) @@ -2281,14 +2268,12 @@ def expand_on_basis(self, w): resu = self.zero() for idx in IntegerVectors(k, r): - coeff = ZZ.prod(ZZ(nj + ij - 1).binomial(ij) - for nj, ij in zip(n_zeros, idx)) + coeff = ZZ.prod(ZZ(nj + ij - 1).binomial(ij) for nj, ij in zip(n_zeros, idx)) indice = [0] for nj, ij in zip(n_zeros, idx): indice += [1] + [0] * (nj + ij - 1) - resu += coeff * self._monomial(W(tuple(indice + [1]), - check=False)) - return (-1)**k * resu # attention au signe + resu += coeff * self._monomial(W(tuple(indice + [1]), check=False)) + return (-1) ** k * resu # attention au signe @lazy_attribute def expand(self): @@ -2360,14 +2345,15 @@ def regularise(self): """ P = self.parent() step1 = P.reversal(self) # R3 - step2 = P.expand(step1) # R2 - step3 = P.dual(step2) # R4 - step4 = P.expand(step3) # R2 + step2 = P.expand(step1) # R2 + step3 = P.dual(step2) # R4 + step4 = P.expand(step3) # R2 return step4.conversion() # dans Multizetas_iterated # **************** procedures after F. Brown ************ + def coeff_phi(w): """ Return the coefficient of `f_k` in the image by ``phi``. @@ -2391,7 +2377,7 @@ def coeff_phi(w): 109/16 """ if all(x == 0 for x in w[1:]): - return -1 # beware the sign + return -1 # beware the sign k = len(w) assert k % 2 M = Multizetas_iterated(QQ) @@ -2425,7 +2411,7 @@ def phi_on_multiplicative_basis(compo): return f(2) if len(compo) == 1: - n, = compo + (n,) = compo return f(n) return compute_u_on_compo(compo) @@ -2498,7 +2484,7 @@ def D_on_compo(k, compo): """ it = composition_to_iterated(compo) M = Multizetas_iterated(QQ) - return (-1)**len(compo) * M.D_on_basis(k, it) + return (-1) ** len(compo) * M.D_on_basis(k, it) def compute_u_on_compo(compo): @@ -2522,7 +2508,7 @@ def compute_u_on_compo(compo): -75/4*f3f7 + 81/4*f5f5 + 75/8*f7f3 + 11*f2*f3f5 - 9*f2*f5f3 """ it = composition_to_iterated(compo) - return (-1)**len(compo) * compute_u_on_basis(it) + return (-1) ** len(compo) * compute_u_on_basis(it) def compute_u_on_basis(w): @@ -2558,10 +2544,8 @@ def compute_u_on_basis(w): N = len(w) xi_dict = {} for k in range(3, N, 2): - xi_dict[k] = F.sum(cf * coeff_phi(ww[0]) * M.phi_extended(tuple(ww[1])) - for ww, cf in M.D_on_basis(k, w)) - return F.sum(F.half_product(F.gen(k), xi_dict[k]) - for k in range(3, N, 2)) + xi_dict[k] = F.sum(cf * coeff_phi(ww[0]) * M.phi_extended(tuple(ww[1])) for ww, cf in M.D_on_basis(k, w)) + return F.sum(F.half_product(F.gen(k), xi_dict[k]) for k in range(3, N, 2)) @cached_function diff --git a/src/sage/modular/multiple_zeta_F_algebra.py b/src/sage/modular/multiple_zeta_F_algebra.py index b7265415de5..c7f304bedfe 100644 --- a/src/sage/modular/multiple_zeta_F_algebra.py +++ b/src/sage/modular/multiple_zeta_F_algebra.py @@ -129,7 +129,7 @@ def basis_f_odd_iterator(n, start=3) -> Iterator[tuple]: yield (n,) for k in range(start, n, 2): for word in basis_f_odd_iterator(n - k, start=start): - yield word + (k, ) + yield word + (k,) def basis_f_iterator(n, start=3) -> Iterator[tuple]: @@ -267,6 +267,7 @@ class F_algebra(CombinatorialFreeModule): sage: s = f2*f3+f5; s f5 + f2*f3 """ + def __init__(self, R, start=3) -> None: r""" Initialize ``self``. @@ -297,9 +298,7 @@ def __init__(self, R, start=3) -> None: self._start = start Indices = NonNegativeIntegers().cartesian_product(W_Odds(start)) cat = BialgebrasWithBasis(R).Commutative().Graded() - CombinatorialFreeModule.__init__(self, R, Indices, - latex_prefix='', prefix='f', - category=cat) + CombinatorialFreeModule.__init__(self, R, Indices, latex_prefix='', prefix='f', category=cat) def _repr_term(self, pw) -> str: r""" @@ -408,8 +407,7 @@ def half_product_on_basis(self, pw1, pw2): if not w1: return self.basis()[(p, w2)] letter = w1[:1] - return self.sum_of_monomials((p, letter + u) - for u in w1[1:].shuffle(w2)) + return self.sum_of_monomials((p, letter + u) for u in w1[1:].shuffle(w2)) @lazy_attribute def half_product(self): @@ -425,9 +423,7 @@ def half_product(self): f2^3*f3f5f7 + f2^3*f3f7f5 """ half = self.half_product_on_basis - return self._module_morphism(self._module_morphism(half, position=0, - codomain=self), - position=1) + return self._module_morphism(self._module_morphism(half, position=0, codomain=self), position=1) def gen(self, i): r""" @@ -457,8 +453,8 @@ def gen(self, i): return self.monomial(self._indices((0, [i]))) # now powers of f2 i = i // 2 - B = bernoulli(2 * i) * (-1)**(i - 1) - B *= ZZ(2)**(3 * i - 1) * ZZ(3)**i / ZZ(2 * i).factorial() + B = bernoulli(2 * i) * (-1) ** (i - 1) + B *= ZZ(2) ** (3 * i - 1) * ZZ(3) ** i / ZZ(2 * i).factorial() return B * f2**i def _an_element_(self): @@ -485,8 +481,7 @@ def some_elements(self) -> list: sage: F.some_elements() [0, 1, f2, f3 + f5] """ - return [self.zero(), self.one(), self.gen(2), - self.gen(3) + self.gen(5)] + return [self.zero(), self.one(), self.gen(2), self.gen(3) + self.gen(5)] def coproduct_on_basis(self, pw): r""" @@ -530,8 +525,7 @@ def coproduct_on_basis(self, pw): """ p, w = pw TS = self.tensor_square() - return TS.sum_of_monomials(((0, w[:i]), (p, w[i:])) - for i in range(len(w) + 1)) + return TS.sum_of_monomials(((0, w[:i]), (p, w[i:])) for i in range(len(w) + 1)) def degree_on_basis(self, pw): """ @@ -574,8 +568,7 @@ def homogeneous_from_vector(self, vec, N): """ if isinstance(vec, (list, tuple)): vec = vector(vec) - return self.sum(cf * self.monomial(bi) - for cf, bi in zip(vec, basis_f_iterator(N, self._start))) + return self.sum(cf * self.monomial(bi) for cf, bi in zip(vec, basis_f_iterator(N, self._start))) def _element_constructor_(self, x): r""" @@ -748,8 +741,7 @@ def homogeneous_to_vector(self): return vector(BR, []) a, b = next(iter(self))[0] N = 2 * a + sum(int(x) for x in b) - return vector(BR, [self.coefficient(b) - for b in basis_f_iterator(N, F._start)]) + return vector(BR, [self.coefficient(b) for b in basis_f_iterator(N, F._start)]) def without_f2(self): """ @@ -783,6 +775,4 @@ def single_valued(self): """ F = self.parent() no_f2 = self.without_f2() - return F.sum_of_terms(((0, w), cf) - for (a, b), cf in no_f2.coproduct() - for w in shuffle(a[1], b[1].reversal(), False)) + return F.sum_of_terms(((0, w), cf) for (a, b), cf in no_f2.coproduct() for w in shuffle(a[1], b[1].reversal(), False)) diff --git a/src/sage/modular/overconvergent/genus0.py b/src/sage/modular/overconvergent/genus0.py index 0a19c16ce3d..a6b9f9c72a4 100644 --- a/src/sage/modular/overconvergent/genus0.py +++ b/src/sage/modular/overconvergent/genus0.py @@ -235,6 +235,7 @@ # Factory function # #################### + def OverconvergentModularForms(prime, weight, radius, base_ring=QQ, prec=20, char=None): r""" Create a space of overconvergent `p`-adic modular forms of level @@ -303,6 +304,7 @@ def OverconvergentModularForms(prime, weight, radius, base_ring=QQ, prec=20, cha # Main class definition # ######################### + class OverconvergentModularFormsSpace(Module): r""" A space of overconvergent modular forms of level `\Gamma_0(p)`, @@ -367,7 +369,7 @@ def __init__(self, prime, weight, radius, base_ring, prec, char): self._cached_recurrence_matrix = None self._set_radius(radius) self._basis_cache = [self._wtchar.pAdicEisensteinSeries(self._qsr, self.prec())] - self._uniformiser = self._qsr(EtaProduct(prime, {prime: 24/ZZ(prime-1), ZZ(1): -24/ZZ(prime-1)}).qexp(self.prec())) + self._uniformiser = self._qsr(EtaProduct(prime, {prime: 24 / ZZ(prime - 1), ZZ(1): -24 / ZZ(prime - 1)}).qexp(self.prec())) for i in range(1, self.prec()): self._basis_cache.append(self._basis_cache[-1] * self._uniformiser * self._const) @@ -408,9 +410,9 @@ def _set_radius(self, radius): p = ZZ(self.prime()) - if (radius < 0 or radius > p/(p+1)): + if radius < 0 or radius > p / (p + 1): raise ValueError("radius (=%s) must be between 0 and p/(p+1)" % radius) - d = 12/(p-1)*radius + d = 12 / (p - 1) * radius if d.is_integral(): self._const = p ** ZZ(d) self._radius = radius @@ -422,7 +424,7 @@ def _set_radius(self, radius): pi = p e = d if not e.is_integral(): - raise ValueError("no element of base ring (=%s) has normalised valuation %s" % (self.base_ring(), radius * 12 / (p-1))) + raise ValueError("no element of base ring (=%s) has normalised valuation %s" % (self.base_ring(), radius * 12 / (p - 1))) self._radius = radius self._const = pi ** ZZ(e) @@ -656,7 +658,7 @@ def gen(self, i): with q-expansion O(q^4) """ - return OverconvergentModularFormElement(self, gexp=self._gsr.gen()**i) + return OverconvergentModularFormElement(self, gexp=self._gsr.gen() ** i) def _repr_(self): r""" @@ -807,11 +809,9 @@ def _element_constructor_(self, input): return self._coerce_from_ocmf(input) if isinstance(input, ModularFormElement): - if ((input.level() == 1 or input.level().prime_factors() == [self.prime()]) - and input.weight() == self.weight().k() - and input.character().primitive_character() == self.weight().chi().primitive_character()): + if (input.level() == 1 or input.level().prime_factors() == [self.prime()]) and input.weight() == self.weight().k() and input.character().primitive_character() == self.weight().chi().primitive_character(): p = ZZ(self.prime()) - nu = (input.level() == 1 and p/(p+1)) or (1 / (p + 1) * p**(2 - input.level().valuation(p))) + nu = (input.level() == 1 and p / (p + 1)) or (1 / (p + 1) * p ** (2 - input.level().valuation(p))) if self.radius() > nu: raise ValueError("Form is not overconvergent enough (form is only %s-overconvergent)" % nu) else: @@ -886,8 +886,7 @@ def _coerce_map_from_(self, other): sage: M.coerce(1) 3-adic overconvergent modular form of weight-character 0 with q-expansion 1 + O(q^20) """ - if (isinstance(other, OverconvergentModularFormsSpace) and - self.base_ring().has_coerce_map_from(other.base_ring())): + if isinstance(other, OverconvergentModularFormsSpace) and self.base_ring().has_coerce_map_from(other.base_ring()): return True return self.base_ring().has_coerce_map_from(other) @@ -1085,7 +1084,7 @@ def hecke_matrix(self, m, n, use_recurrence=False, exact_arith=False, side='left for i in range(self.prime(), n): for u in range(self.prime()): for v in range(self.prime()): - mat[i, j] = mat[i, j] + mat[i-u-1, j-v-1]*self.recurrence_matrix()[u, v] + mat[i, j] = mat[i, j] + mat[i - u - 1, j - v - 1] * self.recurrence_matrix()[u, v] else: if n * self.prime() > self.prec(): @@ -1194,7 +1193,7 @@ def eigenfunctions(self, n, F=None, exact_arith=True): eigenvalues = cp.roots(F) eigenfunctions = [] verbose("Expected %s eigenvalues, got %s" % (n, len(eigenvalues))) - for (r, d) in eigenvalues: + for r, d in eigenvalues: if d != 1: continue @@ -1203,7 +1202,7 @@ def eigenfunctions(self, n, F=None, exact_arith=True): # (bug reported to sage-support list) while F(mr.matdet()) != 0: verbose("p-adic solver returned wrong result in slope %s; refining" % r.valuation(), level=2) - r = r - cp(r)/cp.derivative()(r) + r = r - cp(r) / cp.derivative()(r) mr2 = m.__pari__() - r.__pari__() if mr2.matdet().valuation(self.prime()) > mr.matdet().valuation(self.prime()): mr = mr2 @@ -1232,13 +1231,13 @@ def eigenfunctions(self, n, F=None, exact_arith=True): gexp = self._gsr(0) for i in range(v.nrows()): - gexp += self._gsr.gen()**i * F(v[i, 0]) - gexp = gexp + O(self._gsr.gen()**int(v.nrows())) + gexp += self._gsr.gen() ** i * F(v[i, 0]) + gexp = gexp + O(self._gsr.gen() ** int(v.nrows())) if gexp[0] != 0: - gexp = gexp/gexp[0] + gexp = gexp / gexp[0] elif gexp[1] != 0: - gexp = gexp/gexp[1]/self._const + gexp = gexp / gexp[1] / self._const # This is slightly subtle. We want all eigenfunctions to have q-exps in Z_p. # Normalising the q-term to be 1 doesn't work for the Eisenstein series if # we're in the 0 component of weight-character space. But normalising the const term @@ -1304,7 +1303,7 @@ def recurrence_matrix(self, use_smithline=True): m = MM._discover_recurrence_matrix(use_smithline=True).base_extend(self.base_ring()) r = diagonal_matrix([self._const**i for i in range(self.prime())]) - self._cached_recurrence_matrix = (r**(-1)) * m * r + self._cached_recurrence_matrix = (r ** (-1)) * m * r self._cached_recurrence_matrix.set_immutable() return self._cached_recurrence_matrix @@ -1336,18 +1335,18 @@ def _discover_recurrence_matrix(self, use_smithline=True): coeffs.append(h[i] / fi[i]) h = h - coeffs[-1] * fi - fi = fi*self._uniformiser + fi = fi * self._uniformiser SmiH = f_ring(coeffs) assert SmiH.degree() == self.prime() + 1 xyring = PolynomialRing(self.base_ring(), ["x", "y"], 2) x, y = xyring.gens() - cc = self.prime() ** (-12/(self.prime() - 1)) - bigI = x*SmiH(y*cc) - y*cc*SmiH(x) - smallI = xyring(bigI / (x - cc*y)) + cc = self.prime() ** (-12 / (self.prime() - 1)) + bigI = x * SmiH(y * cc) - y * cc * SmiH(x) + smallI = xyring(bigI / (x - cc * y)) r = matrix(ZZ, self.prime(), self.prime()) for i in range(self.prime()): for j in range(self.prime()): - r[i, j] = -smallI[i+1, j+1] + r[i, j] = -smallI[i + 1, j + 1] return r # compute from U(f^j) for small j via Newton's identities # to be implemented when I can remember Newton's identities! @@ -1734,7 +1733,7 @@ def r_ord(self, r): F = pAdicField(p) # noqa:F821 for i in range(self.prec()): - ord = max(ord, 12/ZZ(p - 1)*i*(r - s) - F(self.gexp()[i]).normalized_valuation()) + ord = max(ord, 12 / ZZ(p - 1) * i * (r - s) - F(self.gexp()[i]).normalized_valuation()) return ord @@ -1777,7 +1776,7 @@ def governing_term(self, r): p = self.prime() for i in range(self.gexp().prec()): - if 12/ZZ(p - 1)*i*(r - s) - F(self.gexp()[i]).normalized_valuation() == self.r_ord(r): + if 12 / ZZ(p - 1) * i * (r - s) - F(self.gexp()[i]).normalized_valuation() == self.r_ord(r): return i raise RuntimeError("Can't get here") @@ -1832,6 +1831,7 @@ def additive_order(self): 1 """ from sage.rings.infinity import Infinity + if self.is_zero(): return ZZ(1) return Infinity diff --git a/src/sage/modular/overconvergent/hecke_series.py b/src/sage/modular/overconvergent/hecke_series.py index f02a4e747f1..18af36e3ac4 100644 --- a/src/sage/modular/overconvergent/hecke_series.py +++ b/src/sage/modular/overconvergent/hecke_series.py @@ -147,8 +147,8 @@ def low_weight_bases(N, p, m, NN, weightbound): """ generators = [] - for k in range(2,weightbound + 2, 2): - b = ModularForms(N, k, base_ring=Zmod(p ** m)).q_expansion_basis(prec=NN) + for k in range(2, weightbound + 2, 2): + b = ModularForms(N, k, base_ring=Zmod(p**m)).q_expansion_basis(prec=NN) generators.append(list(b)) return generators @@ -183,16 +183,16 @@ def random_low_weight_bases(N, p, m, NN, weightbound): sage: S[0][0].prec() 5 """ - LWB = low_weight_bases(N,p,m,NN,weightbound) + LWB = low_weight_bases(N, p, m, NN, weightbound) # this is "approximately" row reduced (it's the mod p^n reduction of a # matrix over ZZ in Hermite form) RandomLWB = [] for i in range(len(LWB)): n = len(LWB[i]) - c = random_matrix(Zmod(p ** m), n) + c = random_matrix(Zmod(p**m), n) while c.det() % p == 0: - c = random_matrix(Zmod(p ** m), n) - RandomLWB.append([ sum([c[j, k] * LWB[i][k] for k in range(n)]) for j in range(n) ]) + c = random_matrix(Zmod(p**m), n) + RandomLWB.append([sum([c[j, k] * LWB[i][k] for k in range(n)]) for j in range(n)]) return RandomLWB @@ -238,9 +238,7 @@ def low_weight_generators(N, p, m, NN): M = ModularFormsRing(N, base_ring=Zmod(p)) b = M.gen_forms(maxweight=8) weightbound = max(f.weight() for f in b) - generators = [[f.qexp(NN).change_ring(Zmod(p ** m)) - for f in b if f.weight() == k] - for k in range(2, weightbound + 2, 2)] + generators = [[f.qexp(NN).change_ring(Zmod(p**m)) for f in b if f.weight() == k] for k in range(2, weightbound + 2, 2)] return generators, weightbound @@ -271,10 +269,10 @@ def random_solution(B, K): ....: S.add(tuple(s)) """ a = [] - for i in range(B,1,-1): + for i in range(B, 1, -1): ai = ZZ.random_element((K // i) + 1) a.append(ai) - K = K - ai*i + K = K - ai * i a.append(K) a.reverse() @@ -283,6 +281,7 @@ def random_solution(B, K): # AUXILIARY CODE: ECHELON FORM + def ech_form(A, p): r""" Return echelon form of matrix ``A`` over the ring of integers modulo @@ -313,16 +312,16 @@ def ech_form(A, p): a = A.nrows() b = A.ncols() - k = 0 # position pivoting row will be swapped to + k = 0 # position pivoting row will be swapped to for j in range(b): if k < a: - pivj = k # find new pivot + pivj = k # find new pivot for i in range(k + 1, a): if valuation(A[i, j], p) < valuation(A[pivj, j], p): pivj = i - if valuation(A[pivj, j], p) < +Infinity: # else column already reduced + if valuation(A[pivj, j], p) < +Infinity: # else column already reduced A.swap_rows(pivj, k) - A.set_row_to_multiple_of_row(k, k, S(ZZ(A[k, j])/(p ** valuation(A[k, j], p))) ** (-1)) + A.set_row_to_multiple_of_row(k, k, S(ZZ(A[k, j]) / (p ** valuation(A[k, j], p))) ** (-1)) for i in range(k + 1, a): A.add_multiple_of_row(i, k, S(-ZZ(A[i, j]) / ZZ(A[k, j]))) k = k + 1 @@ -332,6 +331,7 @@ def ech_form(A, p): # *** COMPLEMENTARY SPACES FOR LEVEL N > 1 *** + def random_new_basis_modp(N, p, k, LWBModp, TotalBasisModp, elldash, bound): r""" Return a list of lists of lists ``[j, a]`` encoding a choice of basis for @@ -369,7 +369,7 @@ def random_new_basis_modp(N, p, k, LWBModp, TotalBasisModp, elldash, bound): # Case k0 + i(p-1) = 0 + 0(p-1) = 0 if k == 0: - TotalBasisModp[0,0] = 1 + TotalBasisModp[0, 0] = 1 return [[]] # Case k = k0 + i(p-1) > 0 @@ -381,7 +381,7 @@ def random_new_basis_modp(N, p, k, LWBModp, TotalBasisModp, elldash, bound): NewBasisCode = [] rk = diminus1 for i in range(1, mi + 1): - while (rk < diminus1 + i): + while rk < diminus1 + i: # take random product of basis elements exps = random_solution(bound // 2, k // 2) TotalBasisi = R(1) @@ -394,7 +394,7 @@ def random_new_basis_modp(N, p, k, LWBModp, TotalBasisModp, elldash, bound): TotalBasisModp[rk] = [TotalBasisi[j] for j in range(elldash)] TotalBasisModp.echelonize() rk = TotalBasisModp.rank() - NewBasisCode.append(TotalBasisiCode) # this choice increased the rank + NewBasisCode.append(TotalBasisiCode) # this choice increased the rank return NewBasisCode @@ -502,7 +502,7 @@ def complementary_spaces(N, p, k0, n, mdash, elldashp, elldash, modformsring, bo else: LWB, bound = low_weight_generators(N, p, mdash, elldashp) - LWBModp = [ [ f.change_ring(GF(p)).truncate_powerseries(elldash) for f in x] for x in LWB] + LWBModp = [[f.change_ring(GF(p)).truncate_powerseries(elldash) for f in x] for x in LWB] CompSpacesCode = complementary_spaces_modp(N, p, k0, n, elldash, LWBModp, bound) @@ -517,12 +517,13 @@ def complementary_spaces(N, p, k0, n, mdash, elldashp, elldash, modformsring, bo for j in range(len(CompSpacesCodemik)): l = CompSpacesCodemik[j][0] index = CompSpacesCodemik[j][1] - Wik = Wik*LWB[l][index] + Wik = Wik * LWB[l][index] Wi.append(Wik) Ws.append(Wi) return Ws + # AUXILIARY CODE: KATZ EXPANSIONS @@ -562,7 +563,7 @@ def higher_level_katz_exp(p, N, k0, m, mdash, elldash, elldashp, modformsring, b 10*q^17 + 20*q^18 + O(q^20) """ ordr = 1 / (p + 1) - S = Zmod(p ** mdash) + S = Zmod(p**mdash) Ep1 = eisenstein_series_qexp(p - 1, prec=elldashp, K=S, normalization='constant') n = floor(((p + 1) / (p - 1)) * (m + 1)) @@ -586,7 +587,7 @@ def higher_level_katz_exp(p, N, k0, m, mdash, elldash, elldashp, modformsring, b for j in range(elldashp): M[i, j] = Basis[i][j] - ech_form(M, p) # put it into echelon form + ech_form(M, p) # put it into echelon form return M, Ep1 @@ -617,6 +618,7 @@ def compute_elldash(p, N, k0, n): return ModularForms(N, k0 + n * (p - 1)).sturm_bound() + # *** DEGREE BOUND ON HECKE SERIES *** @@ -658,7 +660,8 @@ def hecke_series_degree_bound(p, N, k, m): ord = floor(((p - 1) / (p + 1)) * sum - ds[u]) u = u + 1 - return (ds[u - 1] - 1) + return ds[u - 1] - 1 + # *** MAIN FUNCTION FOR LEVEL > 1 *** @@ -731,8 +734,7 @@ def higher_level_UpGj(p, N, klist, m, modformsring, bound, extra_data=False): t = cputime() # Steps 2 and 3 - e, Ep1 = higher_level_katz_exp(p, N, k0, m, mdash, elldash, elldashp, - modformsring, bound) + e, Ep1 = higher_level_katz_exp(p, N, k0, m, mdash, elldash, elldashp, modformsring, bound) ell = dimension(transpose(e)[0].parent()) S = e[0, 0].parent() @@ -747,9 +749,9 @@ def higher_level_UpGj(p, N, klist, m, modformsring, bound, extra_data=False): verbose("done step 4a", t) t = cputime() for k in klist: - k = ZZ(k) # convert to sage integer + k = ZZ(k) # convert to sage integer kdiv = k // (p - 1) - Gkdiv = G ** kdiv + Gkdiv = G**kdiv T = matrix(S, ell, elldash) for i in range(ell): @@ -779,7 +781,7 @@ def higher_level_UpGj(p, N, klist, m, modformsring, bound, extra_data=False): A[i, j] = S(ZZ(Ti[j]) / lj) Ti = Ti - A[i, j] * ej - Alist.append(MatrixSpace(Zmod(p ** m), ell, ell)(A)) + Alist.append(MatrixSpace(Zmod(p**m), ell, ell)(A)) verbose("done step 6", t) if extra_data: @@ -789,6 +791,7 @@ def higher_level_UpGj(p, N, klist, m, modformsring, bound, extra_data=False): # *** LEVEL 1 CODE *** + def compute_Wi(k, p, h, hj, E4, E6): r""" This function computes a list `W_i` of `q`-expansions, together with an @@ -864,13 +867,13 @@ def compute_Wi(k, p, h, hj, E4, E6): # This next line is a bit of a bottleneck, particularly when m is large but # p is small. It would be good to reuse values calculated on the previous # call here somehow. - r = E6 ** (2 * d + b) * E4 ** a + r = E6 ** (2 * d + b) * E4**a - prec = E4.prec() # everything gets truncated to this precision + prec = E4.prec() # everything gets truncated to this precision # Construct basis for Wi Wi = [] - for j in range(e + 1,d + 1): + for j in range(e + 1, d + 1): # compute aj = delta^j*E6^(2*(d-j) + b)*E4^a verbose("k = %s, computing Delta^%s E6^%s E4^%s" % (k, j, 2 * (d - j) + b, a), level=2) aj = (hj * r).truncate_powerseries(prec) @@ -906,14 +909,14 @@ def katz_expansions(k0, p, ellp, mdash, n): ([1 + O(q^10), q + 6*q^2 + 27*q^3 + 98*q^4 + 65*q^5 + 37*q^6 + 81*q^7 + 85*q^8 + 62*q^9 + O(q^10)], 1 + 115*q + 35*q^2 + 95*q^3 + 20*q^4 + 115*q^5 + 105*q^6 + 60*q^7 + 25*q^8 + 55*q^9 + O(q^10)) """ - S = Zmod(p ** mdash) + S = Zmod(p**mdash) Ep1 = eisenstein_series_qexp(p - 1, ellp, K=S, normalization='constant') E4 = eisenstein_series_qexp(4, ellp, K=S, normalization='constant') E6 = eisenstein_series_qexp(6, ellp, K=S, normalization='constant') delta = delta_qexp(ellp, K=S) - h = delta / E6 ** 2 + h = delta / E6**2 hj = delta.parent()(1) e = [] @@ -922,7 +925,7 @@ def katz_expansions(k0, p, ellp, mdash, n): Ep1m1 = ~Ep1 Ep1mi = 1 for i in range(n + 1): - Wi,hj = compute_Wi(k0 + i * (p - 1), p, h, hj, E4, E6) + Wi, hj = compute_Wi(k0 + i * (p - 1), p, h, hj, E4, E6) for bis in Wi: eis = p ** floor(i / (p + 1)) * Ep1mi * bis e.append(eis) @@ -930,6 +933,7 @@ def katz_expansions(k0, p, ellp, mdash, n): return e, Ep1 + # *** MAIN FUNCTION FOR LEVEL 1 *** @@ -997,9 +1001,9 @@ def level1_UpGj(p, klist, m, extra_data=False): verbose("done step 4a", t) t = cputime() for k in klist: - k = ZZ(k) # convert to sage integer + k = ZZ(k) # convert to sage integer kdiv = k // (p - 1) - Gkdiv = G ** kdiv + Gkdiv = G**kdiv u = [] for i in range(ell): ei = e[i] @@ -1035,13 +1039,14 @@ def level1_UpGj(p, klist, m, extra_data=False): A[i, j] = S(ZZ(Ti[j]) / lj) Ti = Ti - A[i, j] * ej - Alist.append(MatrixSpace(Zmod(p ** m), ell, ell)(A)) + Alist.append(MatrixSpace(Zmod(p**m), ell, ell)(A)) verbose("done step 6", t) if extra_data: return Alist, e, ell, mdash return Alist + # *** CODE FOR GENERAL LEVEL *** @@ -1074,7 +1079,7 @@ def is_valid_weight_list(klist, p) -> None: raise ValueError("List of weights must be non-empty") k0 = klist[0] % (p - 1) for i in range(1, len(klist)): - if (klist[i] % (p-1)) != k0: + if (klist[i] % (p - 1)) != k0: raise ValueError("List of weights must be all congruent modulo p-1 = %s, but given list contains %s and %s which are not congruent" % (p - 1, klist[0], klist[i])) diff --git a/src/sage/modular/overconvergent/weightspace.py b/src/sage/modular/overconvergent/weightspace.py index 9e7a21cd25c..88da844aef0 100644 --- a/src/sage/modular/overconvergent/weightspace.py +++ b/src/sage/modular/overconvergent/weightspace.py @@ -274,9 +274,7 @@ def _coerce_map_from_(self, other): sage: W2.coerce(w) # indirect doctest 3 """ - return (isinstance(other, WeightSpace_class) - and other.prime() == self.prime() - and self.base_ring().has_coerce_map_from(other.base_ring())) + return isinstance(other, WeightSpace_class) and other.prime() == self.prime() and self.base_ring().has_coerce_map_from(other.base_ring()) def _coerce_in_wtchar(self, x): r""" @@ -365,7 +363,7 @@ def pAdicEisensteinSeries(self, ring, prec=20): if not self.is_even(): raise ValueError("Eisenstein series not defined for odd weight-characters") q = ring.gen() - s = ring(1) + 2*self.one_over_Lvalue() * sum(sum(self(d)/d for d in divisors(n)) * q**n for n in range(1, prec)) + s = ring(1) + 2 * self.one_over_Lvalue() * sum(sum(self(d) / d for d in divisors(n)) * q**n for n in range(1, prec)) return s.add_bigoh(prec) def values_on_gens(self): @@ -387,7 +385,7 @@ def values_on_gens(self): (1 + 2*11 + O(11^5), 4) """ - return ( self(self.parent()._param), self.teichmuller_type()) + return (self(self.parent()._param), self.teichmuller_type()) def is_trivial(self) -> bool: r""" @@ -542,12 +540,12 @@ def __call__(self, x): if isinstance(x, pAdicGenericElement): if x.parent().prime() != self._p: raise TypeError("x must be an integer or a %s-adic integer" % self._p) - if self._p**(x.precision_absolute()) < self._chi.conductor(): + if self._p ** (x.precision_absolute()) < self._chi.conductor(): raise PrecisionError("Precision too low") xint = x.lift() else: xint = x - if (xint % self._p == 0): + if xint % self._p == 0: return 0 return self._chi(xint) * x**self._k @@ -633,7 +631,7 @@ def teichmuller_type(self): return IntegerModRing(2).zero() return IntegerModRing(2).one() m = IntegerModRing(self._p).multiplicative_generator() - x = [y for y in IntegerModRing(self._chi.modulus()) if y == m and y**(self._p - 1) == 1] + x = [y for y in IntegerModRing(self._chi.modulus()) if y == m and y ** (self._p - 1) == 1] if len(x) != 1: raise ArithmeticError x = x[0] @@ -696,7 +694,7 @@ def __init__(self, parent, w, t): WeightCharacter.__init__(self, parent) self.t = ZZ(t) % (self._p > 2 and (self._p - 1) or 2) - # do we store w precisely? + # do we store w precisely? if (w - 1).valuation() <= 0: raise ValueError("Must send generator to something nearer 1") self.w = w @@ -744,7 +742,7 @@ def __call__(self, x): e = xx.log() / self.parent()._param.log() verbose("Exponent is %s" % e) - return teich**(self.t) * (self.w.log() * e).exp() + return teich ** (self.t) * (self.w.log() * e).exp() def teichmuller_type(self): r""" diff --git a/src/sage/modular/pollack_stevens/distributions.py b/src/sage/modular/pollack_stevens/distributions.py index 415ac07cbc9..f6e74bb0d7b 100644 --- a/src/sage/modular/pollack_stevens/distributions.py +++ b/src/sage/modular/pollack_stevens/distributions.py @@ -90,9 +90,8 @@ class OverconvergentDistributions_factory(UniqueFactory): sage: v.act_right([2,1,0,1]) (5 + 11 + O(11^5), 8 + O(11^4), 4 + O(11^3), 2 + O(11^2), 1 + O(11)) """ - def create_key(self, k, p=None, prec_cap=None, base=None, character=None, - adjuster=None, act_on_left=False, dettwist=None, - act_padic=False, implementation=None): + + def create_key(self, k, p=None, prec_cap=None, base=None, character=None, adjuster=None, act_on_left=False, dettwist=None, act_padic=False, implementation=None): """ EXAMPLES:: @@ -131,8 +130,7 @@ def create_key(self, k, p=None, prec_cap=None, base=None, character=None, if dettwist == 0: dettwist = None - return (k, p, prec_cap, base, character, adjuster, act_on_left, - dettwist, act_padic, implementation) + return (k, p, prec_cap, base, character, adjuster, act_on_left, dettwist, act_padic, implementation) def create_object(self, version, key): """ @@ -191,9 +189,8 @@ class Symk_factory(UniqueFactory): sage: v.act_right([2,1,0,1]) (32, 16, 8, 4, 2, 1, 1/2) """ - def create_key(self, k, base=None, character=None, adjuster=None, - act_on_left=False, dettwist=None, act_padic=False, - implementation=None): + + def create_key(self, k, base=None, character=None, adjuster=None, act_on_left=False, dettwist=None, act_padic=False, implementation=None): r""" Sanitize input. @@ -211,8 +208,7 @@ def create_key(self, k, base=None, character=None, adjuster=None, adjuster = _default_adjuster() if base is None: base = QQ - return (k, base, character, adjuster, act_on_left, dettwist, - act_padic, implementation) + return (k, base, character, adjuster, act_on_left, dettwist, act_padic, implementation) def create_object(self, version, key): r""" @@ -260,9 +256,8 @@ class OverconvergentDistributions_abstract(Module): sage: type(D) """ - def __init__(self, k, p=None, prec_cap=None, base=None, character=None, - adjuster=None, act_on_left=False, dettwist=None, - act_padic=False, implementation=None): + + def __init__(self, k, p=None, prec_cap=None, base=None, character=None, adjuster=None, act_on_left=False, dettwist=None, act_padic=False, implementation=None): """ See ``OverconvergentDistributions_abstract`` for full documentation. @@ -285,8 +280,7 @@ def __init__(self, k, p=None, prec_cap=None, base=None, character=None, raise TypeError("base must be a commutative ring") # from sage.rings.padics.pow_computer import PowComputer # should eventually be the PowComputer on ZpCA once that uses longs. - Dist, WeightKAction = get_dist_classes(p, prec_cap, base, - self.is_symk(), implementation) + Dist, WeightKAction = get_dist_classes(p, prec_cap, base, self.is_symk(), implementation) self.Element = Dist # if Dist is Dist_long: # self.prime_pow = PowComputer(p, prec_cap, prec_cap, prec_cap) @@ -299,11 +293,9 @@ def __init__(self, k, p=None, prec_cap=None, base=None, character=None, self._dettwist = dettwist if self.is_symk() or character is not None: - self._act = WeightKAction(self, character, adjuster, act_on_left, - dettwist, padic=act_padic) + self._act = WeightKAction(self, character, adjuster, act_on_left, dettwist, padic=act_padic) else: - self._act = WeightKAction(self, character, adjuster, act_on_left, - dettwist, padic=True) + self._act = WeightKAction(self, character, adjuster, act_on_left, dettwist, padic=True) self._populate_coercion_lists_(action_list=[self._act]) @@ -342,11 +334,7 @@ def _coerce_map_from_(self, other): sage: v == w True """ - return (isinstance(other, OverconvergentDistributions_abstract) - and other._k == self._k - and self._character == other._character - and self.base_ring().has_coerce_map_from(other.base_ring()) - and (self.is_symk() or not other.is_symk())) + return isinstance(other, OverconvergentDistributions_abstract) and other._k == self._k and self._character == other._character and self.base_ring().has_coerce_map_from(other.base_ring()) and (self.is_symk() or not other.is_symk()) def acting_matrix(self, g, M): r""" @@ -532,8 +520,7 @@ def approx_module(self, M=None): elif M > self._prec_cap: raise ValueError("M (=%s) must be less than or equal to the precision cap (=%s)" % (M, self._prec_cap)) elif M < self._prec_cap and self.is_symk(): - raise ValueError("Sym^k objects do not support approximation " - "modules") + raise ValueError("Sym^k objects do not support approximation " "modules") return self.base_ring() ** M def random_element(self, M=None, **args): @@ -567,7 +554,8 @@ def random_element(self, M=None, **args): if M is None: M = self.precision_cap() R = self.base_ring() - return self((R ** M).random_element(**args)) + return self((R**M).random_element(**args)) + # return self(self.approx_module(M).random_element()) def clear_cache(self): @@ -636,8 +624,7 @@ def _an_element_(self): class Symk_class(OverconvergentDistributions_abstract): - def __init__(self, k, base, character, adjuster, act_on_left, dettwist, - act_padic, implementation): + def __init__(self, k, base, character, adjuster, act_on_left, dettwist, act_padic, implementation): r""" EXAMPLES:: @@ -649,12 +636,7 @@ def __init__(self, k, base, character, adjuster, act_on_left, dettwist, p = base.prime() else: p = ZZ.zero() - OverconvergentDistributions_abstract.__init__(self, k, p, k + 1, - base, character, - adjuster, act_on_left, - dettwist, - act_padic, - implementation) + OverconvergentDistributions_abstract.__init__(self, k, p, k + 1, base, character, adjuster, act_on_left, dettwist, act_padic, implementation) def _an_element_(self): r""" diff --git a/src/sage/modular/pollack_stevens/fund_domain.py b/src/sage/modular/pollack_stevens/fund_domain.py index 6e43d6409fe..cf2d190866b 100644 --- a/src/sage/modular/pollack_stevens/fund_domain.py +++ b/src/sage/modular/pollack_stevens/fund_domain.py @@ -11,6 +11,7 @@ - Robert Pollack, Jonathan Hanke (2012): initial version """ + # **************************************************************************** # Copyright (C) 2012 Robert Pollack # Jonathan Hanke @@ -113,6 +114,7 @@ class PollackStevensModularDomain(SageObject): ... TypeError: unable to coerce to an integer """ + def __init__(self, N, reps, indices, rels, equiv_ind): r""" INPUT: @@ -570,6 +572,7 @@ class ManinRelations(PollackStevensModularDomain): ... ValueError: N must be a positive integer """ + def __init__(self, N): r""" Create an instance of this class. @@ -694,7 +697,7 @@ def __init__(self, N): # In the following case the ideal triangle below # the unimodular path described by coset_reps[r] # contains a point fixed by a 3-torsion element. - if (c ** 2 + d ** 2 + c * d) % N == 0: + if (c**2 + d**2 + c * d) % N == 0: # the index r is adding to our list of indexes # of generators @@ -824,7 +827,7 @@ def __init__(self, N): # Similarly, this is also done for B. # Running between the cusps between cusp1 and cusp2 - for rel in rels[r + 2: s + 2]: + for rel in rels[r + 2 : s + 2]: # Add edge relation vA.append(rel[0]) # Add negative of edge relation @@ -840,8 +843,7 @@ def __init__(self, N): equiv_ind[ky] = i self.gammas = gammas - PollackStevensModularDomain.__init__(self, N, coset_reps, gens_index, - rels, equiv_ind) + PollackStevensModularDomain.__init__(self, N, coset_reps, gens_index, rels, equiv_ind) # A list of indices of the (geometric) coset representatives whose # paths are identified by some 2-torsion element (which switches the @@ -1136,7 +1138,7 @@ def form_list_of_cusps(self): # Some convenient shortcuts P = self.P1() - sP = len(P.list()) # Size of P^1(Z/NZ) + sP = len(P.list()) # Size of P^1(Z/NZ) # Initialize some lists @@ -1146,7 +1148,7 @@ def form_list_of_cusps(self): # The ? denotes that it has not yet been checked if more cusps need # to be added between the surrounding cusps. - full_domain = False # Says that we are not done yet! + full_domain = False # Says that we are not done yet! v = [False] * sP # This initializes a list indexed by P^1(Z/NZ) which keeps track of @@ -1162,7 +1164,7 @@ def form_list_of_cusps(self): # Main Loop -- Ideal Triangle Flipping # ==================================== - while (not full_domain): + while not full_domain: full_domain = True # This loop runs through the current set of cusps @@ -1192,7 +1194,7 @@ def form_list_of_cusps(self): # Check if we need to flip (since this P1 element has not # yet been accounted for!) if not v[pos]: - v[pos] = True # Say this P1 element now occurs + v[pos] = True # Say this P1 element now occurs v[P.index(b1, -(b1 + b2))] = True # Say that the other two ideal triangle edges # also occur! @@ -1204,7 +1206,7 @@ def form_list_of_cusps(self): # element is present, the fundamental domain can be # extended no further. - if (b1 ** 2 + b2 ** 2 + b1 * b2) % N != 0: + if (b1**2 + b2**2 + b1 * b2) % N != 0: # this congruence is exactly equivalent to # gam * [0 -1; 1 -1] * gam^(-1) is in Gamma_0(N) @@ -1229,7 +1231,7 @@ def form_list_of_cusps(self): # This will keep the fundamental domain as flat as possible! # --------------------------------------------------------------- s = 1 - while s < len(C): # range over odd indices in the final list C + while s < len(C): # range over odd indices in the final list C if C[s] == "i": C[s] = "?" @@ -1476,6 +1478,7 @@ def prep_hecke_on_gen(self, l, gen, modulus=None): t = gamma * gen # In the notation above this is gam_a * D_m from .manin_map import unimod_matrices_to_infty, unimod_matrices_from_infty + v = unimod_matrices_from_infty(t[0, 0], t[1, 0]) + unimod_matrices_to_infty(t[0, 1], t[1, 1]) # This expresses t as a sum of unimodular divisors diff --git a/src/sage/modular/pollack_stevens/manin_map.py b/src/sage/modular/pollack_stevens/manin_map.py index 5ad5bfbaba0..f113f64ee82 100644 --- a/src/sage/modular/pollack_stevens/manin_map.py +++ b/src/sage/modular/pollack_stevens/manin_map.py @@ -189,6 +189,7 @@ class ManinMap: sage: f(M2Z([1,0,0,1])) (1 + O(11^2), 2 + O(11)) """ + def __init__(self, codomain, manin_relations, defining_data, check=True): """ INPUT: @@ -617,8 +618,7 @@ def apply(self, f, codomain=None, to_moments=False): codomain = self._codomain for ky, val in sd.items(): if to_moments: - D[ky] = codomain([f(val.moment(a)) - for a in range(val.precision_absolute())]) + D[ky] = codomain([f(val.moment(a)) for a in range(val.precision_absolute())]) else: D[ky] = f(val) return self.__class__(codomain, self._manin, D, check=False) @@ -761,8 +761,7 @@ def specialize(self, *args): D = {} for ky, val in self._dict.items(): D[ky] = val.specialize(*args) - return self.__class__(self._codomain.specialize(*args), self._manin, - D, check=False) + return self.__class__(self._codomain.specialize(*args), self._manin, D, check=False) def hecke(self, ell, algorithm='prep'): r""" @@ -800,8 +799,7 @@ def hecke(self, ell, algorithm='prep'): psi_g = sum((self[h] * A for h, A in M.prep_hecke_on_gen_list(ell, g)), self._codomain(0)) psi_g.normalize() psi[g] = psi_g - return self.__class__(self._codomain, self._manin, - psi, check=False).normalize() + return self.__class__(self._codomain, self._manin, psi, check=False).normalize() if algorithm == 'naive': S0N = Sigma0(self._manin.level()) psi = self._right_action(S0N([1, 0, 0, ell])) diff --git a/src/sage/modular/pollack_stevens/modsym.py b/src/sage/modular/pollack_stevens/modsym.py index 208f1fc13f2..9facdcc2ed4 100644 --- a/src/sage/modular/pollack_stevens/modsym.py +++ b/src/sage/modular/pollack_stevens/modsym.py @@ -26,6 +26,7 @@ sage: phi.values() [(-1, 0, 0), (1, 0, 0), (-9, -6, -4)] """ + # **************************************************************************** # Copyright (C) 2012 Robert Pollack # @@ -100,7 +101,7 @@ def _iterate_Up(Phi, p, M, ap, q, aq, check): # Killing eisenstein part verbose("Killing eisenstein part with q = %s" % q, level=2) k = Phi.parent().weight() - Phi = ((q ** (k + 1) + 1) * Phi - Phi.hecke(q)) + Phi = (q ** (k + 1) + 1) * Phi - Phi.hecke(q) # Iterating U_p verbose("Iterating U_p", level=2) @@ -269,8 +270,7 @@ def _richcmp_(self, other, op): if op not in [op_EQ, op_NE]: return NotImplemented - b = all(self._map[g] == other._map[g] - for g in self.parent().source().gens()) + b = all(self._map[g] == other._map[g] for g in self.parent().source().gens()) return b == (op == op_EQ) @@ -392,8 +392,7 @@ def _get_prime(self, p=None, alpha=None, allow_none=False): ValueError: you must specify a prime """ pp = self.parent().prime() - ppp = ((alpha is not None) and hasattr(alpha.parent(), 'prime') - and alpha.parent().prime()) or None + ppp = ((alpha is not None) and hasattr(alpha.parent(), 'prime') and alpha.parent().prime()) or None p = ZZ(p) or pp or ppp if not p: if not allow_none: @@ -489,8 +488,7 @@ def hecke(self, ell, algorithm='prep'): sage: all(phi.hecke(p, algorithm='naive') == phi * E.ap(p) for p in [2,3,5,101]) # long time True """ - return self.__class__(self._map.hecke(ell, algorithm), - self.parent(), construct=True) + return self.__class__(self._map.hecke(ell, algorithm), self.parent(), construct=True) def valuation(self, p=None): r""" @@ -784,8 +782,7 @@ def evaluate_twisted(self, a, chi): for b in range(1, abs(chi) + 1): if gcd(b, chi) == 1: M1 = S0p([1, (b / abs(chi)) % p**M, 0, 1]) - new_dist = m_map(M2Z([a * abs(chi) + p * b, - 1, p * abs(chi), 0])) * M1 + new_dist = m_map(M2Z([a * abs(chi) + p * b, 1, p * abs(chi), 0])) * M1 new_dist = new_dist.scale(kronecker(chi, b)).normalize() twisted_dist += new_dist return twisted_dist.normalize() @@ -814,20 +811,19 @@ def _consistency_check(self): # Test three torsion relations for g in MR.reps_with_three_torsion(): gamg = MR.three_torsion_matrix(g) - if not (f[g] * (gamg ** 2) + f[g] * gamg + f[g]).is_zero(): + if not (f[g] * (gamg**2) + f[g] * gamg + f[g]).is_zero(): raise ValueError("Three torsion relation failed with", g) # Test that the symbol adds to 0 around the boundary of the # fundamental domain t = self.parent().coefficient_module().zero() for g in MR.gens()[1:]: - if not (g in MR.reps_with_two_torsion() - or g in MR.reps_with_three_torsion()): + if not (g in MR.reps_with_two_torsion() or g in MR.reps_with_three_torsion()): t += f[g] * MR.gammas[g] - f[g] elif g in MR.reps_with_two_torsion(): t -= f[g] else: - t -= f[g] # what ?? same thing ?? + t -= f[g] # what ?? same thing ?? id = MR.gens()[0] if f[id] * MR.gammas[id] - f[id] != -t: @@ -932,8 +928,7 @@ def _find_alpha(self, p, k, M=None, ap=None, new_base_ring=None, ordinary=True, # and (alpha-1) are both at least *newM*, where newM is # obtained from self._find_extraprec prec_cap = None - verbose("testing prec_rel: newM = %s, alpha = %s" % (newM, alpha), - level=2) + verbose("testing prec_rel: newM = %s, alpha = %s" % (newM, alpha), level=2) if alpha.precision_relative() < newM: prec_cap = newM + alpha.valuation(p) + (1 if p == 2 else 0) if ordinary: @@ -1039,7 +1034,7 @@ def p_stabilize(self, p=None, M=20, alpha=None, ap=None, new_base_ring=None, ord if check: if ap is None: ap = self.base_ring()(alpha + p ** (k + 1) / alpha) - elif alpha ** 2 - ap * alpha + p ** (k + 1) != 0: + elif alpha**2 - ap * alpha + p ** (k + 1) != 0: raise ValueError("alpha must be a root of x^2 - a_p*x + p^(k+1)") if self.hecke(p) != ap * self: raise ValueError("alpha must be a root of x^2 - a_p*x + p^(k+1)") @@ -1109,8 +1104,7 @@ def completions(self, p, M): ans.append((embedded_sym, psi)) return ans - def lift(self, p=None, M=None, alpha=None, new_base_ring=None, - algorithm=None, eigensymbol=False, check=True): + def lift(self, p=None, M=None, alpha=None, new_base_ring=None, algorithm=None, eigensymbol=False, check=True): r""" Return a (`p`-adic) overconvergent modular symbol with `M` moments which lifts ``self`` up to an Eisenstein error. @@ -1234,8 +1228,7 @@ def lift(self, p=None, M=None, alpha=None, new_base_ring=None, algorithm = 'greenberg' if eigensymbol else 'stevens' elif algorithm == 'greenberg': if not eigensymbol: - raise ValueError("Greenberg's algorithm only works" - " for eigensymbols. Try 'stevens'") + raise ValueError("Greenberg's algorithm only works" " for eigensymbols. Try 'stevens'") elif algorithm != 'stevens': raise ValueError("algorithm %s not recognized" % algorithm) if eigensymbol: @@ -1306,7 +1299,7 @@ def _lift_to_OMS(self, p, M, new_base_ring, algorithm='greenberg'): # See [PS2011] section 4.1 gam = manin.three_torsion_matrix(g) mu = self._map[g].lift(p, M, new_base_ring) - D[g] = (2 * mu - mu * gam - mu * (gam ** 2)) * half + D[g] = (2 * mu - mu * gam - mu * (gam**2)) * half else: # no two or three torsion D[g] = self._map[g].lift(p, M, new_base_ring) @@ -1378,8 +1371,7 @@ def _find_aq(self, p, M, check): else: eisenloss = (aq - 1).valuation(p) if q >= 50: - raise ValueError("The symbol appears to be eisenstein -- " - "not implemented yet") + raise ValueError("The symbol appears to be eisenstein -- " "not implemented yet") return q, aq, eisenloss def _find_extraprec(self, p, M, alpha, check): @@ -1430,10 +1422,7 @@ def _find_extraprec(self, p, M, alpha, check): newM += -s return newM, eisenloss, q, aq - def p_stabilize_and_lift(self, p, M, alpha=None, ap=None, - new_base_ring=None, - ordinary=True, algorithm='greenberg', eigensymbol=False, - check=True): + def p_stabilize_and_lift(self, p, M, alpha=None, ap=None, new_base_ring=None, ordinary=True, algorithm='greenberg', eigensymbol=False, check=True): """ `p`-stabilize and lift ``self``. @@ -1496,8 +1485,7 @@ def p_stabilize_and_lift(self, p, M, alpha=None, ap=None, raise ValueError("Not enough precision in new base ring") # Now we can stabilize - self = self.p_stabilize(p=p, alpha=alpha, ap=ap, M=newM, - new_base_ring=new_base_ring, check=check) + self = self.p_stabilize(p=p, alpha=alpha, ap=ap, M=newM, new_base_ring=new_base_ring, check=check) # And use the standard lifting function for eigensymbols Phi = self._lift_to_OMS(p, newM, new_base_ring, algorithm) Phi = _iterate_Up(Phi, p=p, M=newM, ap=alpha, q=q, aq=aq, check=check) @@ -1519,8 +1507,7 @@ def reduce_precision(self, M): sage: f.reduce_precision(1) Modular symbol of level 5 with values in Space of 5-adic distributions with k=0 action and precision cap 10 """ - return self.__class__(self._map.reduce_precision(M), self.parent(), - construct=True) + return self.__class__(self._map.reduce_precision(M), self.parent(), construct=True) def precision_relative(self): r""" @@ -1566,8 +1553,7 @@ def specialize(self, new_base_ring=None): """ if new_base_ring is None: new_base_ring = self.base_ring() - return self.__class__(self._map.specialize(new_base_ring), - self.parent()._specialize_parent_space(new_base_ring), construct=True) + return self.__class__(self._map.specialize(new_base_ring), self.parent()._specialize_parent_space(new_base_ring), construct=True) def padic_lseries(self, *args, **kwds): """ @@ -1583,4 +1569,5 @@ def padic_lseries(self, *args, **kwds): O(37^6) + (4 + 37 + 36*37^2 + 19*37^3 + 21*37^4 + O(37^5))*T + O(T^2) """ from sage.modular.pollack_stevens.padic_lseries import pAdicLseries + return pAdicLseries(self, *args, **kwds) diff --git a/src/sage/modular/pollack_stevens/padic_lseries.py b/src/sage/modular/pollack_stevens/padic_lseries.py index 1e7fd9ed54c..9f3ce8a6862 100644 --- a/src/sage/modular/pollack_stevens/padic_lseries.py +++ b/src/sage/modular/pollack_stevens/padic_lseries.py @@ -153,13 +153,11 @@ def __getitem__(self, n): else: lb = log_gamma_binomial(p, gamma, n, 2 * M) if precision is None: - precision = min(j + lb[j].valuation(p) - for j in range(M, len(lb))) + precision = min(j + lb[j].valuation(p) for j in range(M, len(lb))) lb = [lb[a] for a in range(M)] for j, cjn in enumerate(lb): - temp = sum((ZZ(K.teichmuller(a)) ** (-j)) * - self._basic_integral(a, j) for a in range(1, p)) + temp = sum((ZZ(K.teichmuller(a)) ** (-j)) * self._basic_integral(a, j) for a in range(1, p)) dn += cjn * temp self._coefficients[n] = dn.add_bigoh(precision) self._coefficients[n] /= self._cinf @@ -179,10 +177,7 @@ def __eq__(self, other): if not isinstance(other, pAdicLseries): return False - return (self._symb == other._symb and - self._quadratic_twist == other._quadratic_twist and - self._gamma == other._gamma and - self._precision == other._precision) + return self._symb == other._symb and self._quadratic_twist == other._quadratic_twist and self._gamma == other._gamma and self._precision == other._precision def __ne__(self, other): r""" @@ -335,7 +330,7 @@ def interpolation_factor(self, ap, chip=1, psi=None): if psi is not None: ap = psi(ap) ap = ap * chip - sdisc = R(ap ** 2 - 4 * p).sqrt() + sdisc = R(ap**2 - 4 * p).sqrt() v0 = (R(ap) + sdisc) / 2 v1 = (R(ap) - sdisc) / 2 if v0.valuation() > 0: @@ -372,10 +367,7 @@ def _basic_integral(self, a, j): ap = ap * kronecker(D, p) K = pAdicField(p, M) symb_twisted = symb.evaluate_twisted(a, D) - return sum(ZZ(j).binomial(r) * - ((a - ZZ(K.teichmuller(a))) ** (j - r)) * - (p ** r) * - symb_twisted.moment(r) for r in range(j + 1)) / ap + return sum(ZZ(j).binomial(r) * ((a - ZZ(K.teichmuller(a))) ** (j - r)) * (p**r) * symb_twisted.moment(r) for r in range(j + 1)) / ap def log_gamma_binomial(p, gamma, n, M): @@ -404,7 +396,7 @@ def log_gamma_binomial(p, gamma, n, M): [0, 2/205, -223/42025, 95228/25845375] """ S = PowerSeriesRing(QQ, 'z') - L = S([0] + [ZZ(-1)**j / j for j in range(1, M)]) # log_p(1+z) + L = S([0] + [ZZ(-1) ** j / j for j in range(1, M)]) # log_p(1+z) loggam = L.O(M) / L(gamma - 1) # log_{gamma}(1+z)= log_p(1+z)/log_p(gamma) return binomial(loggam, n).list() diff --git a/src/sage/modular/pollack_stevens/sigma0.py b/src/sage/modular/pollack_stevens/sigma0.py index 912aa4395ad..a6528b06b09 100644 --- a/src/sage/modular/pollack_stevens/sigma0.py +++ b/src/sage/modular/pollack_stevens/sigma0.py @@ -96,6 +96,7 @@ class _default_adjuster(Sigma0ActionAdjuster): sage: TestSuite(A).run() """ + def __call__(self, g): """ EXAMPLES:: @@ -188,6 +189,7 @@ class Sigma0Element(MonoidElement): [ 1 -2] [ 0 1] """ + def __init__(self, parent, mat): r""" EXAMPLES:: @@ -331,6 +333,7 @@ class _Sigma0Embedding(Morphism): framework so that "x * y" will work if ``x`` is a matrix and ``y`` is a `\Sigma_0` element (returning a matrix, *not* a Sigma0 element). """ + def __init__(self, domain): r""" TESTS:: @@ -391,6 +394,7 @@ class Sigma0_class(Parent): [1 2] [5 1] """ + Element = Sigma0Element def __init__(self, N, base_ring, adjuster): @@ -474,9 +478,7 @@ def _coerce_map_from_(self, other): of nasty things will go wrong with scalar multiplication of distributions. Do not let this happen!) """ - return (isinstance(other, Sigma0_class) - and self.level().divides(other.level()) - and self.base_ring().has_coerce_map_from(other.base_ring())) + return isinstance(other, Sigma0_class) and self.level().divides(other.level()) and self.base_ring().has_coerce_map_from(other.base_ring()) def _element_constructor_(self, x, check=True): r""" @@ -509,7 +511,7 @@ def _element_constructor_(self, x, check=True): if check: x = self._matrix_space(x) a, b, c, d = self._adjuster(x) - for (p, e) in self._primes: + for p, e in self._primes: if c.valuation(p) < e: raise TypeError("level %s^%s does not divide %s" % (p, e, c)) if a.valuation(p) != 0: @@ -530,5 +532,4 @@ def _repr_(self): sage: S._repr_() 'Monoid Sigma0(3) with coefficients in Integer Ring' """ - return 'Monoid Sigma0(%s) with coefficients in %s' % (self.level(), - self.base_ring()) + return 'Monoid Sigma0(%s) with coefficients in %s' % (self.level(), self.base_ring()) diff --git a/src/sage/modular/pollack_stevens/space.py b/src/sage/modular/pollack_stevens/space.py index cf1f8748409..364aad738f6 100644 --- a/src/sage/modular/pollack_stevens/space.py +++ b/src/sage/modular/pollack_stevens/space.py @@ -75,8 +75,7 @@ from sage.structure.factory import UniqueFactory from .distributions import OverconvergentDistributions, Symk -from .modsym import (PSModularSymbolElement, PSModularSymbolElement_symk, - PSModularSymbolElement_dist, PSModSymAction) +from .modsym import PSModularSymbolElement, PSModularSymbolElement_symk, PSModularSymbolElement_dist, PSModSymAction from .manin_map import ManinMap from .sigma0 import Sigma0, Sigma0Element @@ -128,6 +127,7 @@ class PollackStevensModularSymbols_factory(UniqueFactory): sage: TestSuite(PollackStevensModularSymbols).run() """ + def create_key(self, group, weight=None, sign=0, base_ring=None, p=None, prec_cap=None, coefficients=None): r""" Sanitize input. @@ -153,19 +153,15 @@ def create_key(self, group, weight=None, sign=0, base_ring=None, p=None, prec_ca character = None if weight is None: - raise ValueError("you must specify a weight " - "or coefficient module") + raise ValueError("you must specify a weight " "or coefficient module") if prec_cap is None: coefficients = Symk(weight, base_ring, character) else: - coefficients = OverconvergentDistributions(weight, p, prec_cap, base_ring, - character) + coefficients = OverconvergentDistributions(weight, p, prec_cap, base_ring, character) else: if weight is not None or base_ring is not None or p is not None or prec_cap is not None: - raise ValueError("if coefficients are specified, then weight, " - "base_ring, p, and prec_cap must take their " - "default value None") + raise ValueError("if coefficients are specified, then weight, " "base_ring, p, and prec_cap must take their " "default value None") return (group, coefficients, sign) @@ -217,6 +213,7 @@ class PollackStevensModularSymbolspace(Module): sage: M = PollackStevensModularSymbols(Gamma0(2), coefficients=D, sign=1); M.sign() 1 """ + def __init__(self, group, coefficients, sign=0): r""" INPUT: @@ -300,8 +297,7 @@ def _coerce_map_from_(self, other): True """ if isinstance(other, PollackStevensModularSymbolspace): - return (other.group() == self.group() - and self.coefficient_module().has_coerce_map_from(other.coefficient_module())) + return other.group() == self.group() and self.coefficient_module().has_coerce_map_from(other.coefficient_module()) return False @@ -320,8 +316,7 @@ def _repr_(self): s = "Space of modular symbols for " else: s = "Space of overconvergent modular symbols for " - s += "%s with sign %s and values in %s" % (self.group(), self.sign(), - self.coefficient_module()) + s += "%s with sign %s and values in %s" % (self.group(), self.sign(), self.coefficient_module()) return s def source(self): @@ -707,14 +702,14 @@ def random_element(self, M=None): # p = self.prime() manin = self.source() -# # There must be a problem here with that +1 -- should be -# # variable depending on a c of some matrix We'll need to -# # divide by some power of p and so we add extra accuracy -# # here. -# if k != 0: -# MM = M + valuation(k,p) + 1 + M.exact_log(p) -# else: -# MM = M + M.exact_log(p) + 1 + # # There must be a problem here with that +1 -- should be + # # variable depending on a c of some matrix We'll need to + # # divide by some power of p and so we add extra accuracy + # # here. + # if k != 0: + # MM = M + valuation(k,p) + 1 + M.exact_log(p) + # else: + # MM = M + M.exact_log(p) + 1 # this loop runs thru all of the generators (except # (0)-(infty)) and randomly chooses a distribution to assign @@ -731,7 +726,7 @@ def random_element(self, M=None): else: if g in manin.reps_with_three_torsion(): gamg = manin.three_torsion_matrix(g) - D[g] = 2 * D[g] - D[g] * gamg - D[g] * gamg ** 2 + D[g] = 2 * D[g] - D[g] * gamg - D[g] * gamg**2 # print("post:",D[g]) # now we compute nu_infty of Prop 5.1 of [PS1] @@ -870,8 +865,7 @@ def ps_modsym_from_elliptic_curve(E, sign=0, implementation='eclib'): [-1/6, 1/3, 1/2, 1/6, -1/6, 1/3, -1/3, -1/2, -1/6, 1/6, 0, -1/6, -1/6] """ if E.base_ring() is not QQ: - raise ValueError("The elliptic curve must be defined over the " - "rationals.") + raise ValueError("The elliptic curve must be defined over the " "rationals.") sign = Integer(sign) if sign not in [0, 1, -1]: raise ValueError("The sign must be either 0, 1 or -1") @@ -1043,8 +1037,7 @@ def ps_modsym_from_simple_modsym_space(A, name='alpha'): raise ValueError("A must have positive dimension") if A.sign() == 0: - raise ValueError("A must have sign +1 or -1 (otherwise it is" - " not simple)") + raise ValueError("A must have sign +1 or -1 (otherwise it is" " not simple)") if not A.is_new(): raise ValueError("A must be new") diff --git a/src/sage/modular/quasimodform/element.py b/src/sage/modular/quasimodform/element.py index cd18e1b06f8..3e387308007 100644 --- a/src/sage/modular/quasimodform/element.py +++ b/src/sage/modular/quasimodform/element.py @@ -96,6 +96,7 @@ class QuasiModularFormsElement(ModuleElement): sage: F.polynomial() -512*E2^4*E2_1^3 + E2^4*E3_0^2 + 48*E2^4*E3_1^2 + E3_0 """ + def __init__(self, parent, polynomial) -> None: r""" INPUT: @@ -336,8 +337,7 @@ def depth(self): ValueError: the given graded quasiform is not an homogeneous element """ if not self.is_homogeneous(): - raise ValueError("the given graded quasiform is not an " - "homogeneous element") + raise ValueError("the given graded quasiform is not an " "homogeneous element") return self._polynomial.degree() def is_zero(self) -> bool: @@ -486,7 +486,7 @@ def polynomial(self, names=None): subs_dictionary = {} for idx, g in enumerate(modform_poly_gens): subs_dictionary[g] = poly_gens[idx] - return sum(f.to_polynomial().subs(subs_dictionary) * E2 ** exp for exp, f in enumerate(self._polynomial.coefficients(sparse=False))) + return sum(f.to_polynomial().subs(subs_dictionary) * E2**exp for exp, f in enumerate(self._polynomial.coefficients(sparse=False))) to_polynomial = polynomial # alias @@ -542,9 +542,9 @@ def is_homogeneous(self) -> bool: if not c.is_homogeneous(): return False if k is None: - k = c.weight() + 2*i + k = c.weight() + 2 * i continue - if c.weight() + 2*i != k: + if c.weight() + 2 * i != k: return False return True @@ -572,10 +572,8 @@ def weight(self) -> Integer: ValueError: the given graded quasiform is not an homogeneous element """ if self.is_homogeneous(): - return (self._polynomial.leading_coefficient().weight() - + 2*self._polynomial.degree()) - raise ValueError("the given graded quasiform is not an homogeneous " - "element") + return self._polynomial.leading_coefficient().weight() + 2 * self._polynomial.degree() + raise ValueError("the given graded quasiform is not an homogeneous " "element") degree = weight # alias @@ -619,9 +617,9 @@ def homogeneous_components(self) -> dict[Integer, Self]: forms = c._forms_dictionary for k in forms: try: - components[ZZ(k + 2*i)] += QM(forms[k]*(E2**i)) + components[ZZ(k + 2 * i)] += QM(forms[k] * (E2**i)) except KeyError: - components[ZZ(k + 2*i)] = QM(forms[k]*(E2**i)) + components[ZZ(k + 2 * i)] = QM(forms[k] * (E2**i)) return components def __getitem__(self, weight) -> Self | None: @@ -662,8 +660,7 @@ def __getitem__(self, weight) -> Self | None: raise KeyError("the weight must be an integer") if weight < 0: raise ValueError("the weight must be nonnegative") - return self.homogeneous_components().get(Integer(weight), - self.parent().zero()) + return self.homogeneous_components().get(Integer(weight), self.parent().zero()) homogeneous_component = __getitem__ # alias @@ -717,7 +714,7 @@ def serre_derivative(self) -> Self: E4 = QM(EisensteinForms(group=1, weight=4, base_ring=R).gen(0)) # compute the derivative of E2: q*dE2/dq - E2deriv = R(12).inverse_of_unit() * (E2 ** 2 - E4) + E2deriv = R(12).inverse_of_unit() * (E2**2 - E4) # sum the Serre derivative of each monomial of the form: f * E2^n # they are equal to: @@ -729,7 +726,7 @@ def serre_derivative(self) -> Self: if n == 0: der += QM(f.serre_derivative()) else: - A = (E2 ** n) * f.serre_derivative() + A = (E2**n) * f.serre_derivative() B = R(n) * f * E2 ** (n - 1) * E2deriv C = R(n) * u6 * E2 ** (n + 1) * f der += QM(A + B - C) diff --git a/src/sage/modular/quasimodform/ring.py b/src/sage/modular/quasimodform/ring.py index f10fc3165e9..f119c7aa2de 100644 --- a/src/sage/modular/quasimodform/ring.py +++ b/src/sage/modular/quasimodform/ring.py @@ -216,6 +216,7 @@ class QuasiModularForms(Parent, UniqueRepresentation): ... NotImplementedError: base ring other than Q are not yet supported for quasimodular forms ring """ + Element = QuasiModularFormsElement def __init__(self, group=1, base_ring=QQ, name='E2') -> None: @@ -484,8 +485,7 @@ def gens(self) -> tuple[QuasiModularFormsElement, ...]: 1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)) """ gen_list = [self.weight_2_eisenstein_series()] - gen_list.extend(self(f) - for f in self.__modular_forms_subring.gen_forms()) + gen_list.extend(self(f) for f in self.__modular_forms_subring.gen_forms()) return tuple(gen_list) generators = gens # alias @@ -688,8 +688,7 @@ def polynomial_ring(self, names=None): # F, G, H, I, J, K, FF, FG, FH,..., FFF, FFG,... # the letters E and S are reserved for basis elements of the # Eisenstein subspaces and cuspidal subspaces respectively. - pre_iter_names = (product(letters, repeat=r) - for r in range(1, len(same_weights)//len(letters) + 2)) + pre_iter_names = (product(letters, repeat=r) for r in range(1, len(same_weights) // len(letters) + 2)) iter_names = chain(*pre_iter_names) for k in same_weights: form = next(it_gens) @@ -714,8 +713,7 @@ def polynomial_ring(self, names=None): name = "".join(next(iter_names)) + str(k) names.append(name) weights.insert(0, 2) # add the weight 2 Eisenstein series - return PolynomialRing(self.base_ring(), len(weights), names, - order=TermOrder('wdeglex', weights)) + return PolynomialRing(self.base_ring(), len(weights), names, order=TermOrder('wdeglex', weights)) def from_polynomial(self, polynomial) -> QuasiModularFormsElement: r""" @@ -816,8 +814,7 @@ def basis_of_weight(self, weight) -> list[QuasiModularFormsElement]: M = self.__modular_forms_subring E2_pow = self.one() for j in range(weight // 2): - basis.extend(f * E2_pow - for f in M.modular_forms_of_weight(weight - 2*j).basis()) + basis.extend(f * E2_pow for f in M.modular_forms_of_weight(weight - 2 * j).basis()) E2_pow *= E2 if not weight % 2: basis.append(E2_pow) diff --git a/src/sage/modular/quatalg/all.py b/src/sage/modular/quatalg/all.py index 53103006057..7d27bc6a39b 100644 --- a/src/sage/modular/quatalg/all.py +++ b/src/sage/modular/quatalg/all.py @@ -1,2 +1 @@ - from sage.modular.quatalg.brandt import BrandtModule diff --git a/src/sage/modular/quatalg/brandt.py b/src/sage/modular/quatalg/brandt.py index d3e3758ec80..ee64bdbc31a 100644 --- a/src/sage/modular/quatalg/brandt.py +++ b/src/sage/modular/quatalg/brandt.py @@ -488,6 +488,7 @@ class BrandtModule_class(AmbientHeckeModule): sage: BrandtModule(3, 10) Brandt module of dimension 4 of level 3*10 of weight 2 over Rational Field """ + def __init__(self, N, M, weight, base_ring): """ INPUT: @@ -603,9 +604,7 @@ def __richcmp__(self, other, op): if not isinstance(other, BrandtModule_class): return NotImplemented - return richcmp((self.__M, self.__N, self.weight(), self.base_ring()), - (other.__M, other.__N, other.weight(), other.base_ring()), - op) + return richcmp((self.__M, self.__N, self.weight(), self.base_ring()), (other.__M, other.__N, other.weight(), other.base_ring()), op) @cached_method def quaternion_algebra(self): @@ -702,7 +701,7 @@ def cyclic_submodules(self, I, p): R = self.order_of_level_N() A = R.quaternion_algebra() B = R.basis() - V = GF(p)**4 + V = GF(p) ** 4 # step 1: Compute alpha, beta, and the matrix of their action on I/pI. # NOTE: Move this code to orders once we have it all working... @@ -758,10 +757,8 @@ def cyclic_submodules(self, I, p): # Compute the matrix of right multiplication by alpha acting on # our fixed choice of basis for this ideal. - M_alpha = (matrix([(i * alpha).coefficient_tuple() - for i in basis]) * X).change_ring(GF(p)) - M_beta = (matrix([(i * beta).coefficient_tuple() - for i in basis]) * X).change_ring(GF(p)) + M_alpha = (matrix([(i * alpha).coefficient_tuple() for i in basis]) * X).change_ring(GF(p)) + M_beta = (matrix([(i * beta).coefficient_tuple() for i in basis]) * X).change_ring(GF(p)) # step 2: Find j such that if f=I[j], then mod 2 we have span(I[0],alpha*I[i]) # has trivial intersection with span(I[j],alpha*I[j]). @@ -789,18 +786,16 @@ def cyclic_submodules(self, I, p): M2_4 = MatrixSpace(GF(p), 4) M2_2 = MatrixSpace(QQ, 2, 4) Yp = p * Y - from sage.algebras.quatalg.quaternion_algebra_cython import \ - rational_quaternions_from_integral_matrix_and_denom - for v in [f + g * (a + b * M_alpha) - for a in GF(p) for b in GF(p)] + [g]: + from sage.algebras.quatalg.quaternion_algebra_cython import rational_quaternions_from_integral_matrix_and_denom + + for v in [f + g * (a + b * M_alpha) for a in GF(p) for b in GF(p)] + [g]: v0 = v v1 = v * M_alpha v2 = v * M_beta v3 = v1 * M_beta W = M2_4([v0, v1, v2, v3], coerce=False) if W.rank() == 2: - gen_mat = Yp.stack(M2_2([v0.lift() * Y, v1.lift() * Y], - coerce=False)) + gen_mat = Yp.stack(M2_2([v0.lift() * Y, v1.lift() * Y], coerce=False)) gen_mat, d = gen_mat._clear_denom() H = gen_mat._hnf_pari(0, include_zero_rows=False) gens = tuple(rational_quaternions_from_integral_matrix_and_denom(A, H, d)) @@ -1098,9 +1093,7 @@ def _compute_hecke_matrix_brandt(self, n, sparse=False): B = self._brandt_series_vectors(2 * n + 10) m = len(B) K = self.base_ring() - return matrix(K, m, m, {(i, j): K(B[j][i][n]) - for i in range(m) - for j in range(m)}, sparse=sparse) + return matrix(K, m, m, {(i, j): K(B[j][i][n]) for i in range(m) for j in range(m)}, sparse=sparse) @cached_method def _smallest_good_prime(self): @@ -1279,8 +1272,7 @@ def _brandt_series_vectors(self, prec=None): n = len(L) # 1. Compute the theta series - theta = [[I.theta_series_vector(prec) for I in x] - for x in self._ideal_products()] + theta = [[I.theta_series_vector(prec) for I in x] for x in self._ideal_products()] # 2. Compute the number e_j e = [theta[j][j][1] for j in range(n)] @@ -1336,8 +1328,7 @@ def brandt_series(self, prec, var='q'): A = self._brandt_series_vectors(prec) R = PowerSeriesRing(QQ, var) n = len(A[0]) - return matrix(R, n, n, - [[R(x.list()[:prec], prec) for x in Y] for Y in A]) + return matrix(R, n, n, [[R(x.list()[:prec], prec) for x in Y] for Y in A]) @cached_method def eisenstein_subspace(self): @@ -1468,6 +1459,7 @@ def benchmark_magma(levels, silent=False): """ ans = [] from sage.interfaces.magma import magma + for p, M in levels: t = magma.cputime() magma.eval('HeckeOperator(BrandtModule(%s, %s),2)' % (p, M)) @@ -1507,6 +1499,7 @@ def benchmark_sage(levels, silent=False): ('sage', 97, 2, ...) """ from sage.misc.timing import cputime + ans = [] for p, M in levels: t = cputime() diff --git a/src/sage/modular/ssmod/all.py b/src/sage/modular/ssmod/all.py index 62e371a3c25..a92d6820f1a 100644 --- a/src/sage/modular/ssmod/all.py +++ b/src/sage/modular/ssmod/all.py @@ -1,7 +1,4 @@ from sage.misc.lazy_import import lazy_import -lazy_import("sage.modular.ssmod.ssmod", ['dimension_supersingular_module', - 'supersingular_j', - 'SupersingularModule', - 'supersingular_D']) +lazy_import("sage.modular.ssmod.ssmod", ['dimension_supersingular_module', 'supersingular_j', 'SupersingularModule', 'supersingular_D']) del lazy_import diff --git a/src/sage/modular/ssmod/ssmod.py b/src/sage/modular/ssmod/ssmod.py index ecafd5ab405..77ce9a0ca3b 100644 --- a/src/sage/modular/ssmod/ssmod.py +++ b/src/sage/modular/ssmod/ssmod.py @@ -140,11 +140,7 @@ def Phi2_quad(J3, ssJ1, ssJ2): ssJ1_pow2 = ssJ1**2 ssJ2_pow2 = ssJ2**2 - return J3.parent()([(-ssJ1 + 1488) * ssJ2_pow2 - + (1488 * ssJ1 + 40773375) * ssJ2 - + ssJ1_pow2 - 162000 * ssJ1 + 8748000000, - -ssJ2_pow2 + 1488 * ssJ2 + (ssJ1 - 162000), - 1]) + return J3.parent()([(-ssJ1 + 1488) * ssJ2_pow2 + (1488 * ssJ1 + 40773375) * ssJ2 + ssJ1_pow2 - 162000 * ssJ1 + 8748000000, -ssJ2_pow2 + 1488 * ssJ2 + (ssJ1 - 162000), 1]) def Phi_polys(L, x, j): @@ -335,21 +331,21 @@ def supersingular_j(FF): if FF.cardinality() != Integer(prime**2): raise ValueError("%s is not a quadratic extension" % FF) if kronecker(-1, prime) != 1: - j_invss = 1728 # (2^2 * 3)^3 + j_invss = 1728 # (2^2 * 3)^3 elif kronecker(-2, prime) != 1: - j_invss = 8000 # (2^2 * 5)^3 + j_invss = 8000 # (2^2 * 5)^3 elif kronecker(-3, prime) != 1: - j_invss = 0 # 0^3 + j_invss = 0 # 0^3 elif kronecker(-7, prime) != 1: - j_invss = 16581375 # (3 * 5 * 17)^3 + j_invss = 16581375 # (3 * 5 * 17)^3 elif kronecker(-11, prime) != 1: - j_invss = -32768 # -(2^5)^3 + j_invss = -32768 # -(2^5)^3 elif kronecker(-19, prime) != 1: - j_invss = -884736 # -(2^5 * 3)^3 + j_invss = -884736 # -(2^5 * 3)^3 elif kronecker(-43, prime) != 1: - j_invss = -884736000 # -(2^6 * 3 * 5)^3 + j_invss = -884736000 # -(2^6 * 3 * 5)^3 elif kronecker(-67, prime) != 1: - j_invss = -147197952000 # -(2^5 * 3 * 5 * 11)^3 + j_invss = -147197952000 # -(2^5 * 3 * 5 * 11)^3 elif kronecker(-163, prime) != 1: j_invss = -262537412640768000 # -(2^6 * 3 * 5 * 23 * 29)^3 else: @@ -389,6 +385,7 @@ class SupersingularModule(HeckeModule_free_module): ... NotImplementedError: supersingular modules of level > 1 not yet implemented """ + def __init__(self, prime=2, level=1, base_ring=ZZ): r""" Create a supersingular module. @@ -408,8 +405,7 @@ def __init__(self, prime=2, level=1, base_ring=ZZ): self.__finite_field = FiniteField(prime**2, 'a') self.__level = level self.__hecke_matrices = {} - HeckeModule_free_module.__init__(self, base_ring, - prime * level, weight=2) + HeckeModule_free_module.__init__(self, base_ring, prime * level, weight=2) def _repr_(self) -> str: """ @@ -420,8 +416,7 @@ def _repr_(self) -> str: sage: SupersingularModule(11)._repr_() 'Module of supersingular points on X_0(1)/F_11 over Integer Ring' """ - return "Module of supersingular points on X_0(%s)/F_%s over %s" % ( - self.__level, self.__prime, self.base_ring()) + return "Module of supersingular points on X_0(%s)/F_%s over %s" % (self.__level, self.__prime, self.base_ring()) def __richcmp__(self, other, op) -> bool: r""" @@ -438,8 +433,7 @@ def __richcmp__(self, other, op) -> bool: """ if not isinstance(other, SupersingularModule): return NotImplemented - return richcmp((self.__level, self.__prime, self.base_ring()), - (other.__level, other.__prime, other.base_ring()), op) + return richcmp((self.__level, self.__prime, self.base_ring()), (other.__level, other.__prime, other.base_ring()), op) def free_module(self): """ @@ -487,7 +481,7 @@ def free_module(self): (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0), (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)) """ - return ZZ**self.dimension() + return ZZ ** self.dimension() @cached_method def dimension(self): diff --git a/src/sage/modules/diamond_cutting.py b/src/sage/modules/diamond_cutting.py index 9894e5cb491..5b24392e6f8 100644 --- a/src/sage/modules/diamond_cutting.py +++ b/src/sage/modules/diamond_cutting.py @@ -182,8 +182,7 @@ def diamond_cut(V, GM, C, verbose=False) -> Polyhedron: L = [0] * dim # calculate the Gram matrix - q = matrix([[sum(GM[i][k] * GM[j][k] for k in range(dim)) - for j in range(dim)] for i in range(dim)]) + q = matrix([[sum(GM[i][k] * GM[j][k] for k in range(dim)) for j in range(dim)] for i in range(dim)]) if verbose: print("q:\n{}".format(q.n())) # apply Cholesky/Jacobi decomposition @@ -316,6 +315,7 @@ def calculate_voronoi_cell(basis, radius=None, verbose=False) -> Polyhedron: # Convert the basis matrix to use RDF numbers for efficiency when we # calculate the triangular matrix of the QR decomposition. from sage.rings.real_double import RDF + transposed_RDF_matrix = (basis.transpose()).change_ring(RDF) R = transposed_RDF_matrix.QR()[1] # The length of the vector formed by the diagonal entries of R is an @@ -324,19 +324,20 @@ def calculate_voronoi_cell(basis, radius=None, verbose=False) -> Polyhedron: # diamond cutting. However, the value of the `radius` keyword is # actually a squared length, so there is no square root in the # following formula. - radius = sum(R[i, i]**2 for i in range(dim[0])) + radius = sum(R[i, i] ** 2 for i in range(dim[0])) # We then divide by 4 as we will divide the basis by 2 later on. radius = ceil(radius / 4) artificial_length = None if dim[0] < dim[1]: F = basis.base_ring().fraction_field() # Introduce "artificial" basis points (representing infinity). - additional_vectors = (F**dim[1]).subspace(basis).complement().basis() + additional_vectors = (F ** dim[1]).subspace(basis).complement().basis() additional_vectors = matrix(additional_vectors) # LLL-reduce for efficiency. additional_vectors = additional_vectors.LLL() from sage.rings.real_double import RDF + # Convert the basis matrix to use RDF numbers for efficiency when we # perform the QR decomposition. transposed_RDF_matrix = additional_vectors.transpose().change_ring(RDF) @@ -345,8 +346,7 @@ def calculate_voronoi_cell(basis, radius=None, verbose=False) -> Polyhedron: # lower bound on the length of the shortest nonzero vector in the # lattice spanned by the artificial points. We square it because # value of `radius` is a squared length. - shortest_vector_lower_bound = min(R[i, i]**2 - for i in range(dim[1] - dim[0])) + shortest_vector_lower_bound = min(R[i, i] ** 2 for i in range(dim[1] - dim[0])) # We will multiply our artificial points by the following scalar in # order to make sure the squared length of the shortest # nonzero vector is greater than radius, even after the vectors @@ -371,9 +371,7 @@ def calculate_voronoi_cell(basis, radius=None, verbose=False) -> Polyhedron: if artificial_length is not None: # Remove inequalities introduced by artificial basis points. H = V.Hrepresentation() - H = [v for v in H if all(not V._is_zero(v.A() * w / 2 - v.b()) and - not V._is_zero(v.A() * (-w) / 2 - v.b()) - for w in additional_vectors)] + H = [v for v in H if all(not V._is_zero(v.A() * w / 2 - v.b()) and not V._is_zero(v.A() * (-w) / 2 - v.b()) for w in additional_vectors)] V = Polyhedron(ieqs=H) return V diff --git a/src/sage/modules/fg_pid/fgp_element.py b/src/sage/modules/fg_pid/fgp_element.py index ef0ed3320ce..a23b4bfac20 100644 --- a/src/sage/modules/fg_pid/fgp_element.py +++ b/src/sage/modules/fg_pid/fgp_element.py @@ -55,6 +55,7 @@ class FGP_Element(ModuleElement): sage: loads(dumps(Q.0)) == Q.0 True """ + def __init__(self, parent, x, check=DEBUG): """ INPUT: @@ -78,7 +79,7 @@ def __init__(self, parent, x, check=DEBUG): For full documentation, see :class:`FGP_Element`. """ if check: - assert x in parent.V(), 'The argument x='+str(x)+' is not in the covering module!' + assert x in parent.V(), 'The argument x=' + str(x) + ' is not in the covering module!' ModuleElement.__init__(self, parent) self._x = x @@ -443,6 +444,7 @@ def additive_order(self): from sage.rings.finite_rings.integer_mod import Mod from sage.rings.integer import Integer from sage.arith.functions import lcm + n = Integer(1) for vi, a in zip(v, I): if a == 0: diff --git a/src/sage/modules/fg_pid/fgp_module.py b/src/sage/modules/fg_pid/fgp_module.py index 2289b1e0a74..7f967331c33 100644 --- a/src/sage/modules/fg_pid/fgp_module.py +++ b/src/sage/modules/fg_pid/fgp_module.py @@ -226,6 +226,7 @@ import sage.misc.weak_dict from functools import reduce + _fgp_module = sage.misc.weak_dict.WeakValueDictionary() @@ -441,9 +442,8 @@ def _mul_(self, other, switch_sides=False): Finitely generated module V/W over Integer Ring with invariants (2, 4) """ if other in self.base_ring(): - return self._module_constructor(other*self.V() + self.W(), self.W()) - raise ValueError("Scalar multiplication of a module is only " + - "defined for an element of the base ring.") + return self._module_constructor(other * self.V() + self.W(), self.W()) + raise ValueError("Scalar multiplication of a module is only " + "defined for an element of the base ring.") def _repr_(self) -> str: """ @@ -981,7 +981,7 @@ def invariants(self, include_ones=False): """ D, _, _ = self._smith_form() - v = [D[i, i] for i in range(D.nrows())] + [Integer(0)] * (D.ncols()-D.nrows()) + v = [D[i, i] for i in range(D.nrows())] + [Integer(0)] * (D.ncols() - D.nrows()) w = tuple([x for x in v if x != 1]) v = tuple(v) self.invariants.set_cache(v, True) @@ -1031,11 +1031,11 @@ def smith_form_gens(self): _, _, X = self._smith_form() # Invert it to get a matrix whose rows (in terms of the basis for V) # are the gi (including 1 invariants). - Y = X**(-1) + Y = X ** (-1) # Get the basis matrix for V B = self._V.basis_matrix() # Multiply to express the gi in terms of the ambient vector space. - Z = Y*B + Z = Y * B # Make gens out of the rows of Z that correspond to non-1 invariants. v = self.invariants(include_ones=True) non1 = [i for i in range(Z.nrows()) if v[i] != 1] @@ -1086,8 +1086,7 @@ def gens_to_smith(self): [0 0 0 1 0] [0 0 0 0 1] """ - gens_to_smith = matrix(self.base_ring(), - [t.vector() for t in self.gens()]) + gens_to_smith = matrix(self.base_ring(), [t.vector() for t in self.gens()]) gens_to_smith.set_immutable() return gens_to_smith @@ -1211,11 +1210,10 @@ def gens_vector(self, x, reduce=False): x = self(x) v = x.vector() * self.smith_to_gens() from sage.rings.infinity import infinity + if reduce and self.base_ring() == ZZ: orders = [g.order() for g in self.gens()] - v = v.parent()([v[i] if orders[i] == infinity - else v[i] % orders[i] - for i in range(len(self.gens()))]) + v = v.parent()([v[i] if orders[i] == infinity else v[i] % orders[i] for i in range(len(self.gens()))]) return v def coordinate_vector(self, x, reduce=False): @@ -1310,8 +1308,7 @@ def coordinate_vector(self, x, reduce=False): if reduce and self.base_ring() == ZZ: I = self.invariants() - return b.parent()([b[i] if I[i] == 0 else b[i] % I[i] - for i in range(len(I))]) + return b.parent()([b[i] if I[i] == 0 else b[i] % I[i] for i in range(len(I))]) # Don't know (or not requested) canonical way to reduce # each entry yet, or how to compute invariants. @@ -1438,7 +1435,7 @@ def optimized(self): A = V.basis_matrix().stack(self._W.basis_matrix()) B, d = A._clear_denom() H, U = B.hermite_form(transformation=True) - Y = H.solve_left(d*self._V.basis_matrix()) + Y = H.solve_left(d * self._V.basis_matrix()) T = Y * U.matrix_from_columns(range(V.rank())) self.__T = T @@ -1753,6 +1750,7 @@ def cardinality(self): pass from sage.rings.infinity import infinity from sage.misc.misc_c import prod + v = self.invariants() self.__cardinality = infinity if 0 in v else prod(v) return self.__cardinality @@ -1796,7 +1794,7 @@ def __iter__(self): if 0 in v: raise NotImplementedError("currently self must be finite to iterate over") B = self.optimized()[0].V().basis_matrix() - V = self.base_ring()**B.nrows() + V = self.base_ring() ** B.nrows() for a in product(*[range(k) for k in v]): b = V(a) * B yield self(b) @@ -1834,6 +1832,7 @@ def construction(self): (1, 1) """ from sage.modules.module_functors import QuotientModuleFunctor + return (QuotientModuleFunctor(self._W), self._V) def is_finite(self) -> bool: @@ -1941,6 +1940,7 @@ def quotient_map(self): """ return self.coerce_map_from(self._V) + ############################################################## # Useful for testing ############################################################## @@ -1986,7 +1986,7 @@ def random_fgp_module(n, R=ZZ, finite=False): i = ZZ.random_element(max(n, 1)) A = V.span([V.random_element() for _ in range(i)], R) if not finite: - i = ZZ.random_element(i+1) + i = ZZ.random_element(i + 1) while True: B = A.span([A.random_element() for _ in range(i)], R) # Q = A/B @@ -2041,6 +2041,7 @@ def _test_morphism_0(*args, **kwds): K = phi.kernel() I = phi.image() from sage.misc.misc_c import prod + if prod(K.invariants()): assert prod(phi.domain().invariants()) % prod(K.invariants()) == 0 assert I.is_submodule(phi.codomain()) diff --git a/src/sage/modules/fg_pid/fgp_morphism.py b/src/sage/modules/fg_pid/fgp_morphism.py index cd4cd1e9745..eba9c3ecc5c 100644 --- a/src/sage/modules/fg_pid/fgp_morphism.py +++ b/src/sage/modules/fg_pid/fgp_morphism.py @@ -5,6 +5,7 @@ - William Stein, 2009 """ + # ************************************************************************* # Copyright (C) 2009 William Stein # @@ -70,6 +71,7 @@ class FGP_Morphism(Morphism): sage: loads(dumps(phi)) == phi True """ + def __init__(self, parent, phi, check=True): """ A morphism between finitely generated modules over a PID. @@ -130,9 +132,7 @@ def _repr_(self): sage: phi._repr_() 'Morphism from module over Integer Ring with invariants (4, 12) to module with invariants (4, 12) that sends the generators to [(1, 3), (0, 11)]' """ - return "Morphism from module over %s with invariants %s to module with invariants %s that sends the generators to %s" % ( - self.domain().base_ring(), self.domain().invariants(), self.codomain().invariants(), - list(self.im_gens())) + return "Morphism from module over %s with invariants %s to module with invariants %s that sends the generators to %s" % (self.domain().base_ring(), self.domain().invariants(), self.codomain().invariants(), list(self.im_gens())) @cached_method def im_gens(self): @@ -182,7 +182,7 @@ def _richcmp_(self, right, op): a = (self.domain(), self.codomain()) b = (right.domain(), right.codomain()) if a != b: - return (op == op_NE) + return op == op_NE return richcmp(self.im_gens(), right.im_gens(), op) def __add__(self, right): @@ -278,6 +278,7 @@ def __call__(self, x): True """ from .fgp_module import FGP_Module_class + if isinstance(x, FGP_Module_class): if not x.is_submodule(self.domain()): raise ValueError("x must be a submodule or element of the domain") @@ -355,6 +356,7 @@ def inverse_image(self, A): ValueError: A must be a submodule of the codomain """ from .fgp_module import FGP_Module_class + if not isinstance(A, FGP_Module_class): raise TypeError("A must be a finitely generated quotient module") if not A.is_submodule(self.codomain()): @@ -444,7 +446,7 @@ def lift(self, x): # Write back in terms of rows of B, and delete rows not corresponding to A, # since those corresponding to relations - v = (z * U)[:A.nrows()] + v = (z * U)[: A.nrows()] # Take the linear combination that v defines. y = v * self.domain().optimized()[0].V().basis_matrix() @@ -493,6 +495,7 @@ class FGP_Homset_class(Homset): sage: type(H) """ + Element = FGP_Morphism def __init__(self, X, Y, category=None): @@ -505,11 +508,14 @@ def __init__(self, X, Y, category=None): """ if category is None: from sage.modules.free_module import FreeModule_generic + if isinstance(X, FreeModule_generic) and isinstance(Y, FreeModule_generic): from sage.categories.modules_with_basis import ModulesWithBasis + category = ModulesWithBasis(X.base_ring()) else: from sage.categories.modules import Modules + category = Modules(X.base_ring()) Homset.__init__(self, X, Y, category) diff --git a/src/sage/modules/filtered_vector_space.py b/src/sage/modules/filtered_vector_space.py index 77503aa8d52..16382df1cd1 100644 --- a/src/sage/modules/filtered_vector_space.py +++ b/src/sage/modules/filtered_vector_space.py @@ -253,6 +253,7 @@ def construct_from_dim_degree(dim, max_degree, base_ring, check): raise ValueError('dimension must be an integer') dim = ZZ(dim) from sage.matrix.constructor import identity_matrix + generators = identity_matrix(base_ring, dim).columns() filtration = {} if max_degree is None: @@ -281,6 +282,7 @@ def construct_from_generators(filtration, base_ring, check): sage: construct_from_generators({1:[r]}, QQ, True) QQ^1 >= 0 in QQ^2 """ + def normalize_gen(v): return tuple(map(base_ring, v)) @@ -439,7 +441,7 @@ def make_subspace(indices): next_V = V indices.update(filtration[deg]) V = make_subspace(indices) - if V == next_V: # skip trivial filtrations + if V == next_V: # skip trivial filtrations continue filtered_subspaces.append((deg, V)) filtered_subspaces.append((minus_infinity, V)) @@ -533,8 +535,7 @@ def is_exhaustive(self) -> bool: sage: G.is_exhaustive() True """ - return self.get_degree(minus_infinity).dimension() == \ - self.ambient_vector_space().dimension() + return self.get_degree(minus_infinity).dimension() == self.ambient_vector_space().dimension() def is_separating(self) -> bool: r""" @@ -763,6 +764,7 @@ def _repr_field_name(self): if self.base_ring() == RR: return 'RR' from sage.categories.finite_fields import FiniteFields + if self.base_ring() in FiniteFields(): return 'GF({})'.format(len(self.base_ring())) raise NotImplementedError() @@ -900,8 +902,7 @@ def __eq__(self, other): if self_filt[0] != other_filt[0]: # compare degree return False - if (self_filt[1].echelonized_basis_matrix() != - other_filt[1].echelonized_basis_matrix()): + if self_filt[1].echelonized_basis_matrix() != other_filt[1].echelonized_basis_matrix(): # compare vector subspace return False return True @@ -957,19 +958,19 @@ def direct_sum(self, other): RDF^4 >= RDF^2 >= 0 """ from sage.structure.element import get_coercion_model + base_ring = get_coercion_model().common_parent(self.base_ring(), other.base_ring()) # construct the generators self_gens, self_filt = self.presentation() other_gens, other_filt = other.presentation() - generators = \ - [list(v) + [base_ring.zero()] * other.dimension() for v in self_gens] + \ - [[base_ring.zero()] * self.dimension() + list(v) for v in other_gens] + generators = [list(v) + [base_ring.zero()] * other.dimension() for v in self_gens] + [[base_ring.zero()] * self.dimension() + list(v) for v in other_gens] # construct the filtration dictionary def join_indices(self_indices, other_indices): self_indices = tuple(self_indices) other_indices = tuple(i + len(self_gens) for i in other_indices) return self_indices + other_indices + filtration = {} self_indices = set() other_indices = set() @@ -1024,8 +1025,10 @@ def tensor_product(self, other): V = self W = other from sage.structure.element import get_coercion_model + base_ring = get_coercion_model().common_parent(V.base_ring(), W.base_ring()) from sage.modules.tensor_operations import VectorCollection, TensorOperation + V_generators, V_indices = V.presentation() W_generators, W_indices = W.presentation() V_coll = VectorCollection(V_generators, base_ring, V.dimension()) @@ -1068,6 +1071,7 @@ def _power_operation(self, n, operation): QQ^1 >= 0 """ from sage.modules.tensor_operations import VectorCollection, TensorOperation + generators, indices = self.presentation() V = VectorCollection(generators, self.base_ring(), self.dimension()) T = TensorOperation([V] * n, operation) @@ -1225,12 +1229,12 @@ def random_deformation(self, epsilon=None): ....: pass """ from sage.modules.free_module_element import random_vector + R = self.base_ring() if epsilon is None: epsilon = R.one() filtration = {} for deg, filt in self._filt[1:]: - generators = [v + epsilon * random_vector(R, self.rank()) - for v in filt.echelonized_basis()] + generators = [v + epsilon * random_vector(R, self.rank()) for v in filt.echelonized_basis()] filtration[deg] = generators return FilteredVectorSpace(filtration, base_ring=R, check=True) diff --git a/src/sage/modules/fp_graded/free_element.py b/src/sage/modules/fp_graded/free_element.py index c37eed11566..9d1e501658d 100644 --- a/src/sage/modules/fp_graded/free_element.py +++ b/src/sage/modules/fp_graded/free_element.py @@ -124,8 +124,7 @@ def degree(self): raise ValueError("the zero element does not have a well-defined degree") degrees = [] try: - for g, c in zip(self.parent().generator_degrees(), - self.dense_coefficient_list()): + for g, c in zip(self.parent().generator_degrees(), self.dense_coefficient_list()): if c: degrees.append(g + c.degree()) except ValueError: diff --git a/src/sage/modules/fp_graded/free_homspace.py b/src/sage/modules/fp_graded/free_homspace.py index 34d2a93ac78..c2974dbfc85 100644 --- a/src/sage/modules/fp_graded/free_homspace.py +++ b/src/sage/modules/fp_graded/free_homspace.py @@ -49,4 +49,5 @@ class FreeGradedModuleHomspace(FPModuleHomspace): """ Homspace between two free graded modules. """ + Element = FreeGradedModuleMorphism diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index ccdd95ad90b..35365706d77 100644 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -353,8 +353,8 @@ class FreeGradedModule(CombinatorialFreeModule): sage: M.gens() (x, y, z) """ - def __classcall__(cls, algebra, generator_degrees, category=None, - names=None, prefix=None, **kwds): + + def __classcall__(cls, algebra, generator_degrees, category=None, names=None, prefix=None, **kwds): """ Normalize input to ensure a unique representation. @@ -374,6 +374,7 @@ def __classcall__(cls, algebra, generator_degrees, category=None, category = GradedModules(algebra).WithBasis().FiniteDimensional().or_subcategory(category) if names is not None: from sage.structure.category_object import normalize_names + names = normalize_names(-1, names) if len(generator_degrees) > 1: if len(names) == 1: @@ -384,10 +385,7 @@ def __classcall__(cls, algebra, generator_degrees, category=None, raise ValueError("the names do not correspond to the generators") if prefix is None: prefix = 'g' - return super().__classcall__(cls, algebra=algebra, - generator_degrees=generator_degrees, - category=category, names=names, - prefix=prefix, **kwds) + return super().__classcall__(cls, algebra=algebra, generator_degrees=generator_degrees, category=category, names=names, prefix=prefix, **kwds) def __init__(self, algebra, generator_degrees, category, names=None, **kwds): r""" @@ -422,11 +420,7 @@ def __init__(self, algebra, generator_degrees, category, names=None, **kwds): kwds['iterate_key'] = True # Call the base class constructor. - CombinatorialFreeModule.__init__(self, algebra, - basis_keys=keys, - category=category, - names=names, - **kwds) + CombinatorialFreeModule.__init__(self, algebra, basis_keys=keys, category=category, names=names, **kwds) Element = FreeGradedModuleElement @@ -460,8 +454,7 @@ def change_ring(self, algebra): True """ # We use the base class to avoid the category mixed one - return type(self).__base__(algebra, self.generator_degrees(), - prefix=self.prefix(), names=self._names) + return type(self).__base__(algebra, self.generator_degrees(), prefix=self.prefix(), names=self._names) def _repr_(self): r""" @@ -476,10 +469,7 @@ def _repr_(self): Free graded left module on 3 generators over mod 2 Steenrod algebra, milnor basis """ - return ("Free graded left module on %s generator%s over %s" - % (len(self._generator_degrees), - "" if len(self._generator_degrees) == 1 else "s", - self.base_ring())) + return "Free graded left module on %s generator%s over %s" % (len(self._generator_degrees), "" if len(self._generator_degrees) == 1 else "s", self.base_ring()) def generator_degrees(self): r""" @@ -581,8 +571,7 @@ def _element_constructor_(self, coefficients): return self.zero() A = self.base_ring() - return self._from_dict({b: A(c) for (c, b) in zip(coefficients, self._indices) if c}, - remove_zeros=False) + return self._from_dict({b: A(c) for (c, b) in zip(coefficients, self._indices) if c}, remove_zeros=False) def an_element(self, n=None): r""" @@ -672,9 +661,7 @@ def basis_elements(self, n): Sq(1,1)*m4, Sq(4)*m4) """ - return tuple([self.term(self._indices[i], coeff) - for i in range(len(self._generator_degrees)) - for coeff in self._basis_coeffs(n, i)]) + return tuple([self.term(self._indices[i], coeff) for i in range(len(self._generator_degrees)) for coeff in self._basis_coeffs(n, i)]) def _basis_coeffs(self, d, i): r""" @@ -757,8 +744,7 @@ def element_from_coordinates(self, coordinates, n): """ D = self.vector_presentation(n).dimension() if len(coordinates) != D: - raise ValueError('the given coordinate vector has incorrect length (%d); ' - 'it should have length %d' % (len(coordinates), D)) + raise ValueError('the given coordinate vector has incorrect length (%d); ' 'it should have length %d' % (len(coordinates), D)) # Performance testing using this real life example: # @@ -780,8 +766,7 @@ def element_from_coordinates(self, coordinates, n): j = 0 for i, key in enumerate(self._indices): B = self._basis_coeffs(n, i) - coeff = A.linear_combination((b, coordinates[j + ind]) - for ind, b in enumerate(B)) + coeff = A.linear_combination((b, coordinates[j + ind]) for ind, b in enumerate(B)) if coeff: ret[key] = coeff j += len(B) @@ -842,8 +827,7 @@ def vector_presentation(self, n): 4 """ m = len(self._generator_degrees) - return FreeModule(self.base_ring().base_ring(), sum(len(self._basis_coeffs(n, i)) - for i in range(m))) + return FreeModule(self.base_ring().base_ring(), sum(len(self._basis_coeffs(n, i)) for i in range(m))) __getitem__ = vector_presentation @@ -866,9 +850,7 @@ def generator(self, index): try: return self.gens()[index] except IndexError: - raise ValueError('the parent module has generators in the index ' - 'range [0, %s]; generator %s does not exist' % - (len(self.generator_degrees()) - 1, index)) + raise ValueError('the parent module has generators in the index ' 'range [0, %s]; generator %s does not exist' % (len(self.generator_degrees()) - 1, index)) gen = generator @@ -911,6 +893,7 @@ def _Hom_(self, Y, category): Set of Morphisms from Free graded left module on 2 generators ... """ from .free_homspace import FreeGradedModuleHomspace + return FreeGradedModuleHomspace(self, Y, category) def suspension(self, t): @@ -937,8 +920,7 @@ def suspension(self, t): (-4, -2, 0) """ degs = tuple(g + t for g in self.generator_degrees()) - return FreeGradedModule(algebra=self.base_ring(), - generator_degrees=degs) + return FreeGradedModule(algebra=self.base_ring(), generator_degrees=degs) def has_relations(self) -> bool: r""" diff --git a/src/sage/modules/fp_graded/free_morphism.py b/src/sage/modules/fp_graded/free_morphism.py index 68560eaf9e3..ee627745dfd 100644 --- a/src/sage/modules/fp_graded/free_morphism.py +++ b/src/sage/modules/fp_graded/free_morphism.py @@ -85,6 +85,7 @@ def __init__(self, parent, values): sage: TestSuite(g).run() """ from .free_homspace import FreeGradedModuleHomspace + if not isinstance(parent, FreeGradedModuleHomspace): raise TypeError('the parent (%s) must be a f.p. free module homset' % parent) @@ -170,8 +171,7 @@ def __call__(self, x): """ if x.parent() != self.domain(): raise ValueError('cannot evaluate morphism on element not in the domain') - value = self.codomain().linear_combination(zip(self._values, - x.dense_coefficient_list())) + value = self.codomain().linear_combination(zip(self._values, x.dense_coefficient_list())) return value def fp_module(self): diff --git a/src/sage/modules/fp_graded/homspace.py b/src/sage/modules/fp_graded/homspace.py index f9b1f725173..d0de79851ed 100644 --- a/src/sage/modules/fp_graded/homspace.py +++ b/src/sage/modules/fp_graded/homspace.py @@ -530,10 +530,7 @@ def _trivial_case(): # case above. target_degs = [r.degree() + n for r in M.relations()] - block_matrix, R = _create_relations_matrix( - N, - [r.dense_coefficient_list() for r in M.relations()], - source_degs, target_degs) + block_matrix, R = _create_relations_matrix(N, [r.dense_coefficient_list() for r in M.relations()], source_degs, target_degs) ker = R.right_kernel() @@ -544,7 +541,7 @@ def _trivial_case(): xs = [] for j, X in enumerate(block_matrix[0]): k = X.domain().dimension() - xs.append(N.element_from_coordinates(b[n:n + k], source_degs[j])) + xs.append(N.element_from_coordinates(b[n : n + k], source_degs[j])) n += k res.append(self(xs)) diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 8c04a1fa107..73d2c09b721 100644 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -136,6 +136,7 @@ class FPModule(UniqueRepresentation, IndexedGenerators, Module): sage: FPModule(E.free_graded_module([0, 1])) Free graded left module on 2 generators over The exterior algebra of rank 2 over Rational Field """ + @staticmethod def __classcall__(cls, arg0, generator_degrees=None, relations=(), names=None): r""" @@ -152,6 +153,7 @@ def __classcall__(cls, arg0, generator_degrees=None, relations=(), names=None): """ if names is not None: from sage.structure.category_object import normalize_names + names = normalize_names(-1, names) # If given a morphism, then that defines a module @@ -175,12 +177,10 @@ def __classcall__(cls, arg0, generator_degrees=None, relations=(), names=None): # Use the coefficients given for the relations and make module elements # from them. Filter out the zero elements, as they are redundant. - rels = [v for r in relations - if not (v := generator_module(r)).is_zero()] + rels = [v for r in relations if not (v := generator_module(r)).is_zero()] # The free module for the relations of the module. - relations_module = arg0.free_graded_module(tuple([r.degree() - for r in rels])) + relations_module = arg0.free_graded_module(tuple([r.degree() for r in rels])) # The module we want to model is the cokernel of the following morphism j = Hom(relations_module, generator_module)(rels) @@ -222,6 +222,7 @@ def __init__(self, j, names): Module.__init__(self, algebra, category=cat, names=names) from sage.combinat.family import Family + self._spanning_set = Family(self._indices, self.monomial) Element = FPElement @@ -382,6 +383,7 @@ def monomial(self): """ # Should use a real Map, as soon as combinatorial_classes are enumerated sets, and therefore parents from sage.categories.poor_man_map import PoorManMap + return PoorManMap(self._monomial, domain=self._indices, codomain=self, name="Term map") @cached_method @@ -452,8 +454,7 @@ def _element_constructor_(self, x): coeffs = x.monomial_coefficients() return sum(coeffs[idx] * B[idx] for idx in coeffs) raise ValueError("element is not in this module") - return self._from_dict({b: c for (c, b) in zip(x, self._indices) if c}, - remove_zeros=False) + return self._from_dict({b: c for (c, b) in zip(x, self._indices) if c}, remove_zeros=False) def _repr_(self): r""" @@ -473,11 +474,7 @@ def _repr_(self): Free graded left module on 1 generator over mod 2 Steenrod algebra, milnor basis """ - return "Finitely presented left module on %s generator%s and %s relation%s over %s"\ - % (len(self._free_module().generator_degrees()), - "" if len(self._free_module().generator_degrees()) == 1 else "s", - len(self._j.values()), "" if len(self._j.values()) == 1 else "s", - self.base_ring()) + return "Finitely presented left module on %s generator%s and %s relation%s over %s" % (len(self._free_module().generator_degrees()), "" if len(self._free_module().generator_degrees()) == 1 else "s", len(self._j.values()), "" if len(self._j.values()) == 1 else "s", self.base_ring()) def _repr_term(self, m): """ @@ -727,8 +724,7 @@ def basis_elements(self, n, verbose=False): sage: Z1.basis_elements(n=10) () """ - return tuple([self.element_from_coordinates(x, n) for - x in self.vector_presentation(n, verbose).basis()]) + return tuple([self.element_from_coordinates(x, n) for x in self.vector_presentation(n, verbose).basis()]) @cached_method def element_from_coordinates(self, coordinates, n): @@ -780,11 +776,9 @@ def element_from_coordinates(self, coordinates, n): M_n = self.vector_presentation(n) if len(coordinates) != M_n.dimension(): - raise ValueError('the given coordinate vector has incorrect length (%d); ' - 'it should have length %d' % (len(coordinates), M_n.dimension())) + raise ValueError('the given coordinate vector has incorrect length (%d); ' 'it should have length %d' % (len(coordinates), M_n.dimension())) - free_element = self._free_module().element_from_coordinates( - M_n.lift(coordinates), n) + free_element = self._free_module().element_from_coordinates(M_n.lift(coordinates), n) return self(free_element.dense_coefficient_list()) @@ -888,6 +882,7 @@ def _Hom_(self, Y, category): Set of Morphisms from Free graded left module on 2 generators ... """ from .homspace import FPModuleHomspace + if not isinstance(Y, (FPModule, FreeGradedModule)): raise ValueError('cannot create homspace between incompatible types:\n%s ->\n%s' % (self.__class__, type(Y))) if Y.base_ring() != self.base_ring(): @@ -1100,9 +1095,7 @@ def suspension(self, t): (2, 3) """ relations = tuple([r.dense_coefficient_list() for r in self._j._values]) - return type(self).__base__(self.base_ring(), - tuple([g + t for g in self._generator_degrees]), - relations) + return type(self).__base__(self.base_ring(), tuple([g + t for g in self._generator_degrees]), relations) def submodule_inclusion(self, spanning_elements): r""" @@ -1304,6 +1297,7 @@ def resolution(self, k, top_dim=None, verbose=False): , ] """ + def _print_progress(i, k): if verbose: print('Computing f_%d (%d/%d)' % (i, i, k)) @@ -1324,8 +1318,7 @@ def _print_progress(i, k): # f_1: F_1 -> F_0 _print_progress(1, k) F_1 = self._j.domain() - pres = Hom(F_1, F_0)(tuple([F_0(x.dense_coefficient_list()) - for x in self._j.values()])) + pres = Hom(F_1, F_0)(tuple([F_0(x.dense_coefficient_list()) for x in self._j.values()])) ret_complex.append(pres) @@ -1334,7 +1327,6 @@ def _print_progress(i, k): _print_progress(i, k) f = ret_complex[i - 1] - ret_complex.append(f._resolve_kernel(top_dim=top_dim, - verbose=verbose)) + ret_complex.append(f._resolve_kernel(top_dim=top_dim, verbose=verbose)) return ret_complex diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index 0049175e815..c20b207469b 100644 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -111,11 +111,9 @@ def _create_relations_matrix(module, relations, source_degs, target_degs): values = [] for b in module.basis_elements(source_degs[j]): w = r_ij * b - values.append( - target_space.zero() if w.is_zero() else w.vector_presentation()) + values.append(target_space.zero() if w.is_zero() else w.vector_presentation()) - row.append( - Hom(module.vector_presentation(source_degs[j]), target_space)(values)) + row.append(Hom(module.vector_presentation(source_degs[j]), target_space)(values)) block_matrix.append(row) @@ -218,8 +216,7 @@ def __init__(self, parent, values, check=True): # Check the homomorphism is well defined. if len(D.generator_degrees()) != len(values): - raise ValueError('the number of values must equal the number of ' - 'generators in the domain; invalid argument: %s' % values) + raise ValueError('the number of values must equal the number of ' 'generators in the domain; invalid argument: %s' % values) self._values = tuple(values) @@ -255,6 +252,7 @@ def _free_morphism(self): """ P = self.parent() from sage.modules.fp_graded.free_module import FreeGradedModule + if isinstance(P.codomain(), FreeGradedModule): Homspace = Hom(P.domain()._j.codomain(), P.codomain()) return Homspace(self._values) @@ -292,9 +290,7 @@ def change_ring(self, algebra): """ new_codomain = self.codomain().change_ring(algebra) # We have to change the ring for the values, too: - new_values = [new_codomain([algebra(a) - for a in v.dense_coefficient_list()]) - for v in self._values] + new_values = [new_codomain([algebra(a) for a in v.dense_coefficient_list()]) for v in self._values] return Hom(self.domain().change_ring(algebra), new_codomain)(new_values) def degree(self): @@ -685,8 +681,7 @@ def is_identity(self) -> bool: sage: one.is_identity() True """ - return (self.parent().is_endomorphism_set() - and self.parent().identity() == self) + return self.parent().is_endomorphism_set() and self.parent().identity() == self def __call__(self, x): r""" @@ -759,8 +754,7 @@ def _repr_defn(self): b[4] |--> Sq(4)*c[3] b[5] |--> Sq(4)*c[4] """ - s = '\n'.join(['%s |--> %s' % (x, y) for (x, y) in - zip(self.domain().generators(), self._values)]) + s = '\n'.join(['%s |--> %s' % (x, y) for (x, y) in zip(self.domain().generators(), self._values)]) return s @cached_method @@ -893,8 +887,7 @@ def vector_presentation(self, n): values = [self(e) for e in self.domain().basis_elements(n)] - return Hom(D_n, C_n)([C_n.zero() if e.is_zero() else e.vector_presentation() - for e in values]) + return Hom(D_n, C_n)([C_n.zero() if e.is_zero() else e.vector_presentation() for e in values]) def solve(self, x): r""" @@ -1139,8 +1132,7 @@ def lift(self, f, verbose=False): # It is an error to call this function with incompatible arguments. if f.codomain() is not N: - raise ValueError('the codomains of this homomorphism and the homomorphism ' - 'we are lifting over are different') + raise ValueError('the codomains of this homomorphism and the homomorphism ' 'we are lifting over are different') # The trivial map lifts over any other map. if self.is_zero(): @@ -1149,8 +1141,7 @@ def lift(self, f, verbose=False): # A non-trivial map never lifts over the trivial map. if f.is_zero(): if verbose: - print('This homomorphism cannot lift over a trivial homomorphism' - ' since it is non-trivial.') + print('This homomorphism cannot lift over a trivial homomorphism' ' since it is non-trivial.') return None xs = [f.solve(self(g)) for g in L.generators()] @@ -1159,8 +1150,7 @@ def lift(self, f, verbose=False): # hope finding a lift. if None in xs: if verbose: - print('The generators of the domain of this homomorphism do ' - 'not map into the image of the homomorphism we are lifting over.') + print('The generators of the domain of this homomorphism do ' 'not map into the image of the homomorphism we are lifting over.') return None # If L is free there are no relations to take into consideration. @@ -1188,9 +1178,7 @@ def lift(self, f, verbose=False): y = iK.solve(sum([c * x for c, x in zip(r.dense_coefficient_list(), xs)])) if y is None: if verbose: - print('The homomorphism cannot be lifted in any ' - 'way such that the relations of the domain are ' - 'respected.') + print('The homomorphism cannot be lifted in any ' 'way such that the relations of the domain are ' 'respected.') return None if y.is_zero(): @@ -1204,17 +1192,14 @@ def lift(self, f, verbose=False): if all_zero: return Hom(L, M)(xs) - block_matrix, R = _create_relations_matrix( - K, [r.dense_coefficient_list() for r in L.relations()], source_degs, target_degs) + block_matrix, R = _create_relations_matrix(K, [r.dense_coefficient_list() for r in L.relations()], source_degs, target_degs) try: solution = R.solve_right(vector(ys)) except ValueError as error: if str(error) == 'matrix equation has no solutions': if verbose: - print('The homomorphism cannot be lifted in any ' - 'way such that the relations of the domain ' - 'are respected: %s' % error) + print('The homomorphism cannot be lifted in any ' 'way such that the relations of the domain ' 'are respected: %s' % error) return None raise ValueError(error) @@ -1226,8 +1211,7 @@ def lift(self, f, verbose=False): source_dimension = block_matrix[0][j].domain().dimension() - w = K.element_from_coordinates( - solution[n:n + source_dimension], source_degree) + w = K.element_from_coordinates(solution[n : n + source_dimension], source_degree) # Subtract the solution w_i from our initial choice of lift # for the generator g_i. @@ -1331,9 +1315,7 @@ def homology(self, f, top_dim=None, verbose=False): k = self.kernel_inclusion(top_dim, verbose) f_ = f.lift(k) if f_ is None: - raise ValueError('the image of the given homomorphism is not contained ' - 'in the kernel of this homomorphism; the homology is ' - 'therefore not defined for this pair of maps') + raise ValueError('the image of the given homomorphism is not contained ' 'in the kernel of this homomorphism; the homology is ' 'therefore not defined for this pair of maps') return f_.cokernel_projection() @@ -1386,8 +1368,7 @@ def suspension(self, t): D = self.domain().suspension(t) C = self.codomain().suspension(t) - return Hom(D, C)([C(x.lift_to_free().dense_coefficient_list()) - for x in self._values]) + return Hom(D, C)([C(x.lift_to_free().dense_coefficient_list()) for x in self._values]) def cokernel_projection(self): r""" @@ -1415,18 +1396,14 @@ def cokernel_projection(self): sage: co.domain().is_trivial() False """ - new_relations = ([x.dense_coefficient_list() - for x in self.codomain().relations()] + - [x.dense_coefficient_list() for x in self._values]) + new_relations = [x.dense_coefficient_list() for x in self.codomain().relations()] + [x.dense_coefficient_list() for x in self._values] try: FPModule = self.base_ring()._fp_graded_module_class except AttributeError: from .module import FPModule - coker = FPModule(self.base_ring(), - self.codomain().generator_degrees(), - relations=tuple(new_relations)) + coker = FPModule(self.base_ring(), self.codomain().generator_degrees(), relations=tuple(new_relations)) projection = Hom(self.codomain(), coker)(coker.generators()) @@ -1744,8 +1721,7 @@ def _resolve_kernel(self, top_dim=None, verbose=False): new_generator_degrees = kernel_n.rank() * (n,) F_ = R.free_graded_module(generator_degrees + new_generator_degrees) - new_values = tuple([ - domain.element_from_coordinates(q, n) for q in kernel_n.basis()]) + new_values = tuple([domain.element_from_coordinates(q, n) for q in kernel_n.basis()]) else: Q_n = kernel_n.quotient(j.vector_presentation(n).image()) @@ -1757,8 +1733,7 @@ def _resolve_kernel(self, top_dim=None, verbose=False): new_generator_degrees = Q_n.rank() * (n,) F_ = R.free_graded_module(generator_degrees + new_generator_degrees) - new_values = tuple([ - domain.element_from_coordinates(Q_n.lift(q), n) for q in Q_n.basis()]) + new_values = tuple([domain.element_from_coordinates(Q_n.lift(q), n) for q in Q_n.basis()]) # Create a new homomorphism which is surjective onto the kernel # in all degrees less than, and including `n`. @@ -1839,8 +1814,7 @@ def _resolve_image(self, top_dim=None, verbose=False): return j degree_values = [0] + [v.degree() for v in self._values if v] - limit = (infinity if not R.dimension() < infinity else - (_top_dim(R) + max(degree_values))) + limit = infinity if not R.dimension() < infinity else (_top_dim(R) + max(degree_values)) if top_dim is not None: limit = min(top_dim, limit) @@ -1871,8 +1845,7 @@ def _resolve_image(self, top_dim=None, verbose=False): new_generator_degrees = image_n.rank() * (n,) F_ = R.free_graded_module(generator_degrees + new_generator_degrees) - new_values = tuple([ - self.codomain().element_from_coordinates(q, n) for q in image_n.basis()]) + new_values = tuple([self.codomain().element_from_coordinates(q, n) for q in image_n.basis()]) else: @@ -1886,8 +1859,7 @@ def _resolve_image(self, top_dim=None, verbose=False): new_generator_degrees = Q_n.rank() * (n,) F_ = R.free_graded_module(generator_degrees + new_generator_degrees) - new_values = tuple([ - self.codomain().element_from_coordinates(Q_n.lift(q), n) for q in Q_n.basis()]) + new_values = tuple([self.codomain().element_from_coordinates(Q_n.lift(q), n) for q in Q_n.basis()]) # Create a new homomorphism which is surjective onto the image # in all degrees less than, and including `n`. @@ -1950,9 +1922,7 @@ def fp_module(self): FPModule = self.base_ring()._fp_graded_module_class except AttributeError: from .module import FPModule - return FPModule(self.base_ring(), - self.codomain().generator_degrees(), - tuple([r.dense_coefficient_list() for r in self._values])) + return FPModule(self.base_ring(), self.codomain().generator_degrees(), tuple([r.dense_coefficient_list() for r in self._values])) @cached_function diff --git a/src/sage/modules/fp_graded/steenrod/module.py b/src/sage/modules/fp_graded/steenrod/module.py index e799fadf389..a6ba8d67f38 100644 --- a/src/sage/modules/fp_graded/steenrod/module.py +++ b/src/sage/modules/fp_graded/steenrod/module.py @@ -103,6 +103,7 @@ class SteenrodModuleMixin: """ Mixin class for common methods of the Steenrod algebra modules. """ + def profile(self): r""" Return a finite profile over which ``self`` can be defined. @@ -133,12 +134,10 @@ def profile(self): sage: X.profile() (0,) """ - elements = [coeffifient for value in self.relations() - for coeffifient in value.dense_coefficient_list()] + elements = [coeffifient for value in self.relations() for coeffifient in value.dense_coefficient_list()] elements = [a for a in elements if a not in (0, 1)] - return enveloping_profile_elements(elements, - char=self.base_ring().characteristic()) + return enveloping_profile_elements(elements, char=self.base_ring().characteristic()) def export_module_definition(self, powers_of_two_only=True): r""" @@ -226,26 +225,22 @@ def export_module_definition(self, powers_of_two_only=True): n = self.connectivity() if n == infinity: - print('The module connectivity is infinite, so there is ' + - 'nothing to export.') + print('The module connectivity is infinite, so there is ' + 'nothing to export.') return '' limit = self.base_ring().top_class().degree() + max(self.generator_degrees()) # Create a list of bases, one for every module degree we consider. - vector_space_basis = [self.basis_elements(i) - for i in range(n, limit + 1)] + vector_space_basis = [self.basis_elements(i) for i in range(n, limit + 1)] additive_generator_degrees = [] additive_generator_global_indices = [0] for dim, basis_vectors in enumerate(vector_space_basis): - additive_generator_global_indices.append( - len(basis_vectors) + additive_generator_global_indices[-1]) + additive_generator_global_indices.append(len(basis_vectors) + additive_generator_global_indices[-1]) additive_generator_degrees += len(basis_vectors) * [dim + n] # Print the degrees of the additive generators. - ret = '%d %s' % (len(additive_generator_degrees), - ' '.join('%d' % x for x in additive_generator_degrees)) + ret = '%d %s' % (len(additive_generator_degrees), ' '.join('%d' % x for x in additive_generator_degrees)) # A private function which transforms a vector in a given dimension # to a vector of global indices for the basis elements corresponding @@ -264,13 +259,12 @@ def _GetIndices(dim, vec): if powers_of_two_only: powers = [2**i for i in range(profile[0])] else: - powers = range(1, 2**profile[0]) + powers = range(1, 2 ** profile[0]) R = self.base_ring() for k in powers: Sqk = R.Sq(k) - images = [[(Sqk * x).vector_presentation() for x in D] - for D in vector_space_basis] + images = [[(Sqk * x).vector_presentation() for x in D] for D in vector_space_basis] element_index = 0 @@ -280,11 +274,7 @@ def _GetIndices(dim, vec): if im != 0 and im is not None: values = _GetIndices(dim + k, im) - ret += "\n%d %d %d %s" % ( - element_index, - k, - len(values), - " ".join("%d" % x for x in values)) + ret += "\n%d %d %d %s" % (element_index, k, len(values), " ".join("%d" % x for x in values)) element_index += 1 return ret @@ -330,6 +320,7 @@ class SteenrodFPModule(FPModule, SteenrodModuleMixin): sage: SteenrodFPModule(SteenrodAlgebra(2), (0,)) Free graded left module on 1 generator over mod 2 Steenrod algebra, milnor basis """ + def _Hom_(self, other, category=None): """ The homset from ``self`` to ``other``. @@ -349,6 +340,7 @@ def _Hom_(self, other, category=None): Set of Morphisms from Free graded left module on 2 generators ... """ from .homspace import SteenrodFPModuleHomspace + return SteenrodFPModuleHomspace(self, other, category=category) def resolution(self, k, top_dim=None, verbose=False): @@ -429,15 +421,11 @@ def resolution(self, k, top_dim=None, verbose=False): Module endomorphism of Free graded left module on 0 generators over mod 2 Steenrod algebra, milnor basis] """ algebra = self.base_ring() - finite_algebra = SteenrodAlgebra_generic(algebra.prime(), - profile=self.profile()) + finite_algebra = SteenrodAlgebra_generic(algebra.prime(), profile=self.profile()) # Change rings to the finite algebra, and call the base class # implementation of this function. - res = FPModule.resolution(self.change_ring(finite_algebra), - k, - top_dim=top_dim, - verbose=verbose) + res = FPModule.resolution(self.change_ring(finite_algebra), k, top_dim=top_dim, verbose=verbose) # Change rings back to the original Steenrod algebra. # Also convert the maps and modules from FPModule to SteenrodFPModule. @@ -470,4 +458,5 @@ def _Hom_(self, Y, category): Set of Morphisms from Free graded left module on 2 generators ... """ from sage.modules.fp_graded.steenrod.homspace import SteenrodFreeModuleHomspace + return SteenrodFreeModuleHomspace(self, Y, category) diff --git a/src/sage/modules/fp_graded/steenrod/morphism.py b/src/sage/modules/fp_graded/steenrod/morphism.py index 0f6e5a4e2b4..3534f4b487e 100644 --- a/src/sage/modules/fp_graded/steenrod/morphism.py +++ b/src/sage/modules/fp_graded/steenrod/morphism.py @@ -79,16 +79,14 @@ def profile(self): sage: one_fin.change_ring(A) == one True """ + def _flatten(f): return [c for value in f for c in value.dense_coefficient_list()] - elements = (_flatten(self.domain().relations()) - + _flatten(self.codomain().relations()) - + _flatten(self.values())) + elements = _flatten(self.domain().relations()) + _flatten(self.codomain().relations()) + _flatten(self.values()) elements = [a for a in elements if a not in (0, 1)] - return enveloping_profile_elements(elements, - char=self.base_ring().characteristic()) + return enveloping_profile_elements(elements, char=self.base_ring().characteristic()) def is_injective(self, top_dim=None, verbose=False) -> bool: r""" @@ -121,8 +119,7 @@ def is_injective(self, top_dim=None, verbose=False) -> bool: """ algebra = self.base_ring() finite_algebra = SteenrodAlgebra_generic(algebra.prime(), profile=self.profile()) - return FPModuleMorphism.is_injective(self.change_ring(finite_algebra), - top_dim=top_dim, verbose=verbose) + return FPModuleMorphism.is_injective(self.change_ring(finite_algebra), top_dim=top_dim, verbose=verbose) def kernel_inclusion(self, top_dim=None, verbose=False): r""" @@ -204,13 +201,10 @@ def cokernel_projection(self, verbose=False): False """ from .module import SteenrodFPModule - new_relations = ([x.dense_coefficient_list() - for x in self.codomain().relations()] + - [x.dense_coefficient_list() for x in self._values]) - coker = SteenrodFPModule(self.base_ring(), - self.codomain().generator_degrees(), - relations=tuple(new_relations)) + new_relations = [x.dense_coefficient_list() for x in self.codomain().relations()] + [x.dense_coefficient_list() for x in self._values] + + coker = SteenrodFPModule(self.base_ring(), self.codomain().generator_degrees(), relations=tuple(new_relations)) projection = Hom(self.codomain(), coker)(coker.generators()) @@ -392,9 +386,7 @@ def _action(self, method, *args, **kwds): f = fp_result.change_ring(self.base_ring()) M = f.domain() N = f.codomain() - new_values = [N.linear_combination(zip(N.generators(), - v.dense_coefficient_list())) - for v in f.values()] + new_values = [N.linear_combination(zip(N.generators(), v.dense_coefficient_list())) for v in f.values()] return Hom(M, N)(new_values) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 39189e0135e..9b079ba3fa6 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -231,6 +231,7 @@ class FreeModuleFactory(UniqueFactory): r""" Factory class for the finite-dimensional free modules with standard basis """ + def create_key(self, base_ring, rank, sparse=False, inner_product_matrix=None): """ TESTS:: @@ -270,17 +271,14 @@ def create_object(self, version, key): if inner_product_matrix is not None: from sage.modules.free_quadratic_module import FreeQuadraticModule + return FreeQuadraticModule(base_ring, rank, inner_product_matrix=inner_product_matrix, sparse=sparse) if not isinstance(sparse, bool): raise TypeError("Argument sparse (= %s) must be True or False" % sparse) if base_ring not in CommutativeRings(): - warn("You are constructing a free module\n" - "over a noncommutative ring. Sage does not have a concept\n" - "of left/right and both sided modules, so be careful.\n" - "It's also not guaranteed that all multiplications are\n" - "done from the right side.") + warn("You are constructing a free module\n" "over a noncommutative ring. Sage does not have a concept\n" "of left/right and both sided modules, so be careful.\n" "It's also not guaranteed that all multiplications are\n" "done from the right side.") # raise TypeError("the base_ring must be a commutative ring") if not sparse and isinstance(base_ring, sage.rings.abc.RealDoubleField): @@ -298,8 +296,7 @@ def create_object(self, version, key): if base_ring in PrincipalIdealDomains(): return FreeModule_ambient_pid(base_ring, rank, sparse=sparse) - if (isinstance(base_ring, sage.rings.abc.Order) - and base_ring.is_maximal() and base_ring.class_number() == 1): + if isinstance(base_ring, sage.rings.abc.Order) and base_ring.is_maximal() and base_ring.class_number() == 1: return FreeModule_ambient_pid(base_ring, rank, sparse=sparse) if base_ring in IntegralDomains(): @@ -311,8 +308,7 @@ def create_object(self, version, key): FreeModuleFactory_with_standard_basis = FreeModuleFactory("FreeModule") -def FreeModule(base_ring, rank_or_basis_keys=None, sparse=False, inner_product_matrix=None, *, - with_basis='standard', rank=None, basis_keys=None, **args): +def FreeModule(base_ring, rank_or_basis_keys=None, sparse=False, inner_product_matrix=None, *, with_basis='standard', rank=None, basis_keys=None, **args): r""" Create a free module over the given commutative ``base_ring``. @@ -546,13 +542,13 @@ def FreeModule(base_ring, rank_or_basis_keys=None, sparse=False, inner_product_m rank = n if rank is not None and basis_keys is not None and rank != len(basis_keys): - raise ValueError(f"inconsistent rank: should be cardinality of {basis_keys} " - f"but got {rank}") + raise ValueError(f"inconsistent rank: should be cardinality of {basis_keys} " f"but got {rank}") if not with_basis: if inner_product_matrix is not None: raise NotImplementedError from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule + if basis_keys: if not all(key in sage.rings.integer_ring.ZZ for key in basis_keys): raise NotImplementedError(f'FiniteRankFreeModule only supports integer ranges as basis_keys, got {basis_keys}') @@ -560,29 +556,24 @@ def FreeModule(base_ring, rank_or_basis_keys=None, sparse=False, inner_product_m end_index = max(basis_keys) rank = end_index - start_index + 1 # Check that the ordered list of basis_keys is the range from start_index to end_index - if (len(basis_keys) != rank - or not all(key == index - for key, index in zip(basis_keys, - range(start_index, end_index + 1)))): + if len(basis_keys) != rank or not all(key == index for key, index in zip(basis_keys, range(start_index, end_index + 1))): raise NotImplementedError(f'FiniteRankFreeModule only supports integer ranges as basis_keys, got {basis_keys}') return FiniteRankFreeModule(base_ring, rank, start_index=start_index, **args) return FiniteRankFreeModule(base_ring, rank, **args) if with_basis == 'standard': if rank is not None and basis_keys is None: - return FreeModuleFactory_with_standard_basis(base_ring, rank, sparse, - inner_product_matrix, **args) + return FreeModuleFactory_with_standard_basis(base_ring, rank, sparse, inner_product_matrix, **args) if inner_product_matrix is not None: raise NotImplementedError if rank is not None and rank != len(basis_keys): - raise ValueError(f'inconsistent basis_keys: should be of cardinality {rank}, ' - f'got {basis_keys}') + raise ValueError(f'inconsistent basis_keys: should be of cardinality {rank}, ' f'got {basis_keys}') from sage.combinat.free_module import CombinatorialFreeModule + return CombinatorialFreeModule(base_ring, basis_keys, **args) raise NotImplementedError -def VectorSpace(K, dimension_or_basis_keys=None, sparse=False, inner_product_matrix=None, *, - with_basis='standard', dimension=None, basis_keys=None, **args): +def VectorSpace(K, dimension_or_basis_keys=None, sparse=False, inner_product_matrix=None, *, with_basis='standard', dimension=None, basis_keys=None, **args): """ EXAMPLES: @@ -609,9 +600,7 @@ def VectorSpace(K, dimension_or_basis_keys=None, sparse=False, inner_product_mat raise TypeError("Argument K (= %s) must be a field." % K) if sparse not in (True, False): raise TypeError("Argument sparse (= %s) must be a boolean." % sparse) - return FreeModule(K, dimension_or_basis_keys, sparse, inner_product_matrix, - with_basis=with_basis, rank=dimension, basis_keys=basis_keys, - **args) + return FreeModule(K, dimension_or_basis_keys, sparse, inner_product_matrix, with_basis=with_basis, rank=dimension, basis_keys=basis_keys, **args) def span(gens, base_ring=None, check=True, already_echelonized=False): @@ -774,8 +763,7 @@ def span(gens, base_ring=None, check=True, already_echelonized=False): raise TypeError("generators must be given as an iterable structure") if R not in PrincipalIdealDomains(): - raise TypeError("The base_ring (= %s) must be a principal ideal " - "domain." % R) + raise TypeError("The base_ring (= %s) must be a principal ideal " "domain." % R) if not gens: return FreeModule(R, 0) x = gens[0] @@ -785,8 +773,7 @@ def span(gens, base_ring=None, check=True, already_echelonized=False): try: x = list(x) except TypeError: - raise TypeError("generators must be lists of ring elements or " - "free module elements!") + raise TypeError("generators must be lists of ring elements or " "free module elements!") M = FreeModule(R, len(x)) try: gens = [M(_) for _ in gens] @@ -796,11 +783,8 @@ def span(gens, base_ring=None, check=True, already_echelonized=False): try: gens = [M(_) for _ in gens] except TypeError: - raise ValueError("The elements of gens (= %s) must be " - "defined over base_ring (= %s) or its " - "field of fractions." % (gens, base_ring)) - return M.span(gens=gens, base_ring=base_ring, check=check, - already_echelonized=already_echelonized) + raise ValueError("The elements of gens (= %s) must be " "defined over base_ring (= %s) or its " "field of fractions." % (gens, base_ring)) + return M.span(gens=gens, base_ring=base_ring, check=check, already_echelonized=already_echelonized) def basis_seq(V, vecs): @@ -875,6 +859,7 @@ class Module_free_ambient(Module): sage: N.degree() 2 """ + def __init__(self, base_ring, degree, sparse=False, category=None): """ Initialize. @@ -891,6 +876,7 @@ def __init__(self, base_ring, degree, sparse=False, category=None): raise ValueError("degree (=%s) must be nonnegative" % degree) from sage.categories.modules_with_basis import ModulesWithBasis + modules_category = ModulesWithBasis(base_ring.category()).FiniteDimensional() try: if base_ring.is_finite() or degree == 0: @@ -1558,6 +1544,7 @@ def _eq(self, other): return False from sage.modules.quotient_module import QuotientModule_free_ambient + lq = isinstance(self, QuotientModule_free_ambient) rq = isinstance(other, QuotientModule_free_ambient) if lq or rq: @@ -1629,6 +1616,7 @@ def is_submodule(self, other) -> bool: return True from sage.modules.quotient_module import QuotientModule_free_ambient + if isinstance(other, QuotientModule_free_ambient): # if the relations agree we continue with the covers if isinstance(self, QuotientModule_free_ambient): @@ -1650,8 +1638,7 @@ def is_submodule(self, other) -> bool: return False except NotImplementedError: if not R.fraction_field().is_subring(S): - raise NotImplementedError("could not determine if %s is a " - "subring of %s" % (R, S)) + raise NotImplementedError("could not determine if %s is a " "subring of %s" % (R, S)) if not self.gens(): # self is the zero module return True @@ -1789,13 +1776,11 @@ def span(self, gens, base_ring=None, check=True, already_echelonized=False): try: M = self.ambient_module().change_ring(base_ring) except TypeError: - raise ValueError("argument base_ring (= %s) is not compatible " % base_ring + - "with the base ring (= %s)" % self.base_ring()) + raise ValueError("argument base_ring (= %s) is not compatible " % base_ring + "with the base ring (= %s)" % self.base_ring()) try: return M.span(gens) except TypeError: - raise ValueError("argument gens (= %s) is not compatible " % gens + - "with base_ring (= %s)" % base_ring) + raise ValueError("argument gens (= %s) is not compatible " % gens + "with base_ring (= %s)" % base_ring) def submodule(self, gens, check=True, already_echelonized=False): r""" @@ -1874,8 +1859,7 @@ def submodule(self, gens, check=True, already_echelonized=False): V = self.span(gens, check=check, already_echelonized=already_echelonized) if check: if not V.is_submodule(self): - raise ArithmeticError("argument gens (= %s) does not generate " - "a submodule of self" % gens) + raise ArithmeticError("argument gens (= %s) does not generate " "a submodule of self" % gens) return V def quotient_module(self, sub, check=True): @@ -1910,6 +1894,7 @@ def quotient_module(self, sub, check=True): except (TypeError, ArithmeticError): raise ArithmeticError("sub must be a subspace of self") from sage.modules.quotient_module import QuotientModule_free_ambient + return QuotientModule_free_ambient(self, sub) def __truediv__(self, sub): @@ -1949,16 +1934,18 @@ def free_resolution(self, *args, **kwds): from sage.rings.polynomial.multi_polynomial_libsingular import ( MPolynomialRing_libsingular, ) + if isinstance(self.base_ring(), MPolynomialRing_libsingular): from sage.homology.free_resolution import FiniteFreeResolution_singular + return FiniteFreeResolution_singular(self, *args, **kwds) if isinstance(self, FreeModule_generic): from sage.homology.free_resolution import FiniteFreeResolution_free_module + return FiniteFreeResolution_free_module(self, *args, **kwds) - raise NotImplementedError("the module must be a free module or " - "have the base ring be a polynomial ring using Singular") + raise NotImplementedError("the module must be a free module or " "have the base ring be a polynomial ring using Singular") def graded_free_resolution(self, *args, **kwds): r""" @@ -1984,20 +1971,22 @@ def graded_free_resolution(self, *args, **kwds): from sage.rings.polynomial.multi_polynomial_libsingular import ( MPolynomialRing_libsingular, ) + if isinstance(self.base_ring(), MPolynomialRing_libsingular): from sage.homology.graded_resolution import ( GradedFiniteFreeResolution_singular, ) + return GradedFiniteFreeResolution_singular(self, *args, **kwds) if isinstance(self, FreeModule_generic): from sage.homology.graded_resolution import ( GradedFiniteFreeResolution_free_module, ) + return GradedFiniteFreeResolution_free_module(self, *args, **kwds) - raise NotImplementedError("the module must be a free module or " - "have the base ring be a polynomial ring using Singular") + raise NotImplementedError("the module must be a free module or " "have the base ring be a polynomial ring using Singular") class FreeModule_generic(Module_free_ambient): @@ -2059,8 +2048,8 @@ class FreeModule_generic(Module_free_ambient): sage: v in V False """ - def __init__(self, base_ring, rank, degree, sparse=False, - coordinate_ring=None, category=None): + + def __init__(self, base_ring, rank, degree, sparse=False, coordinate_ring=None, category=None): """ Create the free module of given rank ``rank`` over the given base ring ``base_ring``. @@ -2082,11 +2071,7 @@ def __init__(self, base_ring, rank, degree, sparse=False, """ if base_ring not in CommutativeRings(): - warn("You are constructing a free module\n" - "over a noncommutative ring. Sage does not have a concept\n" - "of left/right and both sided modules, so be careful.\n" - "It's also not guaranteed that all multiplications are\n" - "done from the right side.") + warn("You are constructing a free module\n" "over a noncommutative ring. Sage does not have a concept\n" "of left/right and both sided modules, so be careful.\n" "It's also not guaranteed that all multiplications are\n" "done from the right side.") if coordinate_ring is None: coordinate_ring = base_ring @@ -2116,9 +2101,9 @@ def construction(self): (VectorFunctor, Multivariate Polynomial Ring in x0, x1, x2 over Rational Field) """ from sage.categories.pushout import VectorFunctor + if hasattr(self, '_inner_product_matrix'): - return VectorFunctor(self.rank(), self.is_sparse(), - self.inner_product_matrix()), self.base_ring() + return VectorFunctor(self.rank(), self.is_sparse(), self.inner_product_matrix()), self.base_ring() return VectorFunctor(self.rank(), self.is_sparse()), self.base_ring() # FIXME: what's the level of generality of FreeModuleHomspace? @@ -2126,6 +2111,7 @@ def construction(self): # See similar method for FreeModule_generic_field class def _Hom_(self, Y, category): from sage.modules.free_module_homspace import FreeModuleHomspace + return FreeModuleHomspace(self, Y, category) def dense_module(self): @@ -2284,7 +2270,7 @@ def _element_constructor_(self, x, coerce=True, copy=True, check=True): sage: N((0,0,0,1), check=False) in N True """ - if (isinstance(x, (int, sage.rings.integer.Integer)) and x == 0): + if isinstance(x, (int, sage.rings.integer.Integer)) and x == 0: return self.zero_vector() if isinstance(x, FreeModuleElement): if x.parent() is self: @@ -2330,12 +2316,12 @@ def _eq(self, other): return False # We do not want to create an inner product matrix in memory if # self and other use the dot product - if not (self._inner_product_is_dot_product() - and other._inner_product_is_dot_product()): + if not (self._inner_product_is_dot_product() and other._inner_product_is_dot_product()): # This only affects free_quadratic_modules if self.inner_product_matrix() != other.inner_product_matrix(): return False from sage.modules.quotient_module import FreeModule_ambient_field_quotient + lq = isinstance(self, FreeModule_ambient_field_quotient) rq = isinstance(other, FreeModule_ambient_field_quotient) if lq or rq: @@ -2360,6 +2346,7 @@ def _eq(self, other): # We use self.echelonized_basis_matrix() == other.echelonized_basis_matrix() # with the matrix to avoid a circular reference. from sage.rings.integer_ring import IntegerRing + if self.base_ring().is_field() or self.base_ring() is IntegerRing(): # We know that the Hermite normal form is unique here. return self.echelonized_basis_matrix() == other.echelonized_basis_matrix() @@ -2438,6 +2425,7 @@ def is_submodule(self, other) -> bool: # Not all free modules have an ambient_vector_space. pass from sage.modules.quotient_module import FreeModule_ambient_field_quotient + if isinstance(other, FreeModule_ambient_field_quotient): # if the relations agree we continue with the covers. if isinstance(self, FreeModule_ambient_field_quotient): @@ -2466,8 +2454,7 @@ def is_submodule(self, other) -> bool: return False except NotImplementedError: if not R.fraction_field().is_subring(S): - raise NotImplementedError("could not determine if %s is a " - "subring of %s" % (R, S)) + raise NotImplementedError("could not determine if %s is a " "subring of %s" % (R, S)) # now R is a subring of S if other.is_ambient() and S.is_field(): return True @@ -2483,6 +2470,7 @@ def is_submodule(self, other) -> bool: except ValueError: return False from sage.misc.flatten import flatten + return all(x in S for x in flatten(M)) return all(x in S for x in M.list()) @@ -2561,10 +2549,10 @@ def aux(length, norm, max_): for lmax in range(max_): for left in aux(pos, lnorm, lmax): for rmax in range(max_ + 1): - for right in aux(length - 1 - pos, - norm - max_ - lnorm, rmax): + for right in aux(length - 1 - pos, norm - max_ - lnorm, rmax): for mid in (+max_, -max_): yield left + (mid,) + right + n = len(G) for norm in itertools.count(0): mm = (norm + n - 1) // n @@ -2575,7 +2563,7 @@ def aux(length, norm, max_): iters = [iter(R) for _ in range(len(G))] for x in iters: - next(x) # put at 0 + next(x) # put at 0 zero = R.zero() v = [zero for _ in range(len(G))] n = 0 @@ -2588,7 +2576,7 @@ def aux(length, norm, max_): n = 0 except StopIteration: iters[n] = iter(R) # reset - next(iters[n]) # put at 0 + next(iters[n]) # put at 0 v[n] = zero n += 1 @@ -2727,10 +2715,7 @@ def basis_matrix(self, ring=None): try: A = self.__basis_matrix except AttributeError: - MAT = sage.matrix.matrix_space.MatrixSpace(self.coordinate_ring(), - len(self.basis()), - self.degree(), - sparse=self.is_sparse()) + MAT = sage.matrix.matrix_space.MatrixSpace(self.coordinate_ring(), len(self.basis()), self.degree(), sparse=self.is_sparse()) if self.is_ambient(): A = MAT.identity_matrix() else: @@ -2935,7 +2920,7 @@ def coordinate_module(self, V): B = V.basis_matrix() B = B.matrix_from_columns(self.basis_matrix().pivots()).transpose() S = A.solve_right(B).transpose() - return (self.base_ring()**S.ncols()).span_of_basis(S.rows()) + return (self.base_ring() ** S.ncols()).span_of_basis(S.rows()) def dimension(self): """ @@ -3165,10 +3150,12 @@ def hom(self, im_gens, codomain=None, **kwds): Codomain: Vector space of dimension 2 over Rational Field """ from sage.structure.element import Matrix + if codomain is None and isinstance(im_gens, Matrix): side = kwds.get("side", "left") n = im_gens.nrows() if side == "right" else im_gens.ncols() from sage.categories.pushout import pushout + R = pushout(self.base_ring(), im_gens.base_ring()) codomain = R**n return super().hom(im_gens, codomain, **kwds) @@ -3197,6 +3184,7 @@ def pseudoHom(self, twist, codomain=None): :meth:`pseudohom` """ from sage.modules.free_module_pseudohomspace import FreeModulePseudoHomspace + if codomain is None: codomain = self return FreeModulePseudoHomspace(self, codomain, twist) @@ -3586,6 +3574,7 @@ def are_linearly_dependent(self, vecs): True """ from sage.matrix.constructor import matrix + A = matrix(vecs) A.echelonize() return any(row.is_zero() for row in A.rows()) @@ -3704,7 +3693,7 @@ def _macaulay2_(self, macaulay2=None): if hasattr(self, '_inner_product_matrix'): raise NotImplementedError else: - return macaulay2(self.base_ring())**self.rank() + return macaulay2(self.base_ring()) ** self.rank() def scale(self, other): """ @@ -3828,6 +3817,7 @@ class FreeModule_generic_domain(FreeModule_generic): """ Base class for free modules over an integral domain. """ + def __init__(self, base_ring, rank, degree, sparse=False, coordinate_ring=None, category=None): """ Create a free module over an integral domain. @@ -3925,6 +3915,7 @@ class FreeModule_generic_pid(FreeModule_generic_domain): """ Base class for all free modules over a PID. """ + def __init__(self, base_ring, rank, degree, sparse=False, coordinate_ring=None, category=None): """ Create a free module over a PID. @@ -4331,26 +4322,20 @@ def span_of_basis(self, basis, base_ring=None, check=True, already_echelonized=F from sage.modules.free_module_integer import ( FreeModule_submodule_with_basis_integer, ) - return FreeModule_submodule_with_basis_integer(self.ambient_module(), - basis=basis, check=check, - already_echelonized=already_echelonized, - lll_reduce=False) + + return FreeModule_submodule_with_basis_integer(self.ambient_module(), basis=basis, check=check, already_echelonized=already_echelonized, lll_reduce=False) except TypeError: pass - return FreeModule_submodule_with_basis_pid( - self.ambient_module(), basis=basis, check=check, - already_echelonized=already_echelonized) + return FreeModule_submodule_with_basis_pid(self.ambient_module(), basis=basis, check=check, already_echelonized=already_echelonized) try: M = self.change_ring(base_ring) except TypeError: - raise ValueError("Argument base_ring (= %s) is not compatible " % base_ring + - "with the base ring (= %s)." % self.base_ring()) + raise ValueError("Argument base_ring (= %s) is not compatible " % base_ring + "with the base ring (= %s)." % self.base_ring()) try: return M.span_of_basis(basis) except TypeError: - raise ValueError("Argument gens (= %s) is not compatible " % basis + - "with base_ring (= %s)." % base_ring) + raise ValueError("Argument gens (= %s) is not compatible " % basis + "with base_ring (= %s)." % base_ring) def submodule_with_basis(self, basis, check=True, already_echelonized=False): r""" @@ -4541,6 +4526,7 @@ def quotient_module(self, sub, check=True, **kwds): raise ArithmeticError("sub must be a subspace of self") if self.base_ring() == sage.rings.integer_ring.ZZ: from sage.modules.fg_pid.fgp_module import FGP_Module + return FGP_Module(self, sub, check=False, **kwds) raise NotImplementedError("quotients of modules over rings other than fields or ZZ is not fully implemented") @@ -4550,6 +4536,7 @@ class FreeModule_generic_field(FreeModule_generic_pid): """ Base class for all free modules over fields. """ + def __init__(self, base_field, dimension, degree, sparse=False, category=None): """ Create a vector space over a field. @@ -4620,8 +4607,10 @@ def _Hom_(self, Y, category): """ if Y.base_ring().is_field(): from sage.modules import vector_space_homspace + return vector_space_homspace.VectorSpaceHomspace(self, Y, category) from sage.modules import free_module_homspace + return free_module_homspace.FreeModuleHomspace(self, Y, category) def scale(self, other): @@ -4869,13 +4858,11 @@ def span_of_basis(self, basis, base_ring=None, check=True, already_echelonized=F if isinstance(basis, FreeModule_generic): basis = basis.gens() if base_ring is None: - return FreeModule_submodule_with_basis_field( - self.ambient_module(), basis=basis, check=check, already_echelonized=already_echelonized) + return FreeModule_submodule_with_basis_field(self.ambient_module(), basis=basis, check=check, already_echelonized=already_echelonized) try: M = self.change_ring(base_ring) except TypeError: - raise ValueError("Argument base_ring (= %s) is not compatible with the base field (= %s)." % ( - base_ring, self.base_field())) + raise ValueError("Argument base_ring (= %s) is not compatible with the base field (= %s)." % (base_ring, self.base_field())) try: return M.span_of_basis(basis) except TypeError: @@ -4972,6 +4959,7 @@ def subspaces(self, dim): raise RuntimeError("Base ring must be finite.") b = self.basis_matrix() from sage.matrix.echelon_matrix import reduced_echelon_matrix_iterator + for m in reduced_echelon_matrix_iterator(self.base_ring(), dim, self.dimension(), self.is_sparse(), copy=False): yield self.subspace((m * b).rows()) @@ -5279,6 +5267,7 @@ def linear_dependence(self, vectors, zeros='left', check=True): else: raise ValueError("'zeros' keyword must be 'left' or 'right', not '%s'" % zeros) import sage.matrix.constructor + A = sage.matrix.constructor.matrix(vectors) # as rows, so get left kernel return A.left_kernel(basis=basis).basis() @@ -5352,6 +5341,7 @@ def quotient_module(self, sub, check=True): raise ArithmeticError("sub must be a subspace of self") A, L = self.__quotient_matrices(sub) from sage.modules import quotient_module + return quotient_module.FreeModule_ambient_field_quotient(self, sub, A, L) def __quotient_matrices(self, sub): @@ -5428,7 +5418,7 @@ def __quotient_matrices(self, sub): P = A.pivots() AA = A.matrix_from_columns(P) SS = S.matrix_from_columns(P) - D = SS * AA**(-1) + D = SS * AA ** (-1) # Compute the image of each basis vector for ``self`` under the # map "write an element of ``self`` in terms of the basis A" then @@ -5437,7 +5427,7 @@ def __quotient_matrices(self, sub): # Step 4. Section map # The lifting or section map - Dinv = D**(-1) + Dinv = D ** (-1) L = Dinv.matrix_from_rows(range(n - m, n)) return Q, L @@ -5515,10 +5505,12 @@ def quotient_abstract(self, sub, check=True, **kwds): # ############################################################################### + class FreeModule_ambient(FreeModule_generic): """ Ambient free module over a commutative ring. """ + def __init__(self, base_ring, rank, sparse=False, coordinate_ring=None, category=None): """ The free module of given rank over the given base_ring. @@ -5555,10 +5547,7 @@ def __init__(self, base_ring, rank, sparse=False, coordinate_ring=None, category sage: hasattr(V, '_FreeModule_ambient__basis') True """ - FreeModule_generic.__init__(self, base_ring, rank=rank, - degree=rank, sparse=sparse, - coordinate_ring=coordinate_ring, - category=category) + FreeModule_generic.__init__(self, base_ring, rank=rank, degree=rank, sparse=sparse, coordinate_ring=coordinate_ring, category=category) def __hash__(self): """ @@ -5602,15 +5591,13 @@ def _coerce_map_from_(self, M): # No forgetful map. return None if isinstance(M, FreeModule_ambient): - if (self.base_ring().has_coerce_map_from(M.base_ring()) and - self.rank() == M.rank()): + if self.base_ring().has_coerce_map_from(M.base_ring()) and self.rank() == M.rank(): # We could return M.hom(self.basis(), self), but the # complexity of this is quadratic in space and time, # since it constructs a matrix. return True elif isinstance(M, Submodule_free_ambient): - if (self.base_ring().has_coerce_map_from(M.base_ring()) and - self.rank() == M.degree()): + if self.base_ring().has_coerce_map_from(M.base_ring()) and self.rank() == M.degree(): return True return super()._coerce_map_from_(M) @@ -5745,9 +5732,9 @@ def _echelon_matrix_richcmp(self, other, op): return NotImplemented from sage.modules.quotient_module import FreeModule_ambient_field_quotient + if isinstance(other, FreeModule_ambient): - if (isinstance(other, FreeModule_ambient_field_quotient) or - isinstance(self, FreeModule_ambient_field_quotient)): + if isinstance(other, FreeModule_ambient_field_quotient) or isinstance(self, FreeModule_ambient_field_quotient): return richcmp(self, other, op) lx = self.rank() @@ -5945,10 +5932,9 @@ def change_ring(self, R): if self.base_ring() is R: return self from sage.modules.free_quadratic_module import FreeQuadraticModule_generic + if isinstance(self, FreeQuadraticModule_generic): - return FreeModule(R, self.rank(), - inner_product_matrix=self.inner_product_matrix(), - sparse=self.is_sparse()) + return FreeModule(R, self.rank(), inner_product_matrix=self.inner_product_matrix(), sparse=self.is_sparse()) return FreeModule(R, self.rank(), sparse=self.is_sparse()) def linear_combination_of_basis(self, v): @@ -6201,6 +6187,7 @@ def _sympy_(self): """ from sage.interfaces.sympy import sympy_init from sympy import ProductSet + sympy_init() return ProductSet(*([self.coordinate_ring()] * self.rank())) @@ -6211,6 +6198,7 @@ def _sympy_(self): # ############################################################################### + class FreeModule_ambient_domain(FreeModule_generic_domain, FreeModule_ambient): """ Ambient free module over an integral domain. @@ -6221,6 +6209,7 @@ class FreeModule_ambient_domain(FreeModule_generic_domain, FreeModule_ambient): Ambient free module of rank 3 over the principal ideal domain Univariate Polynomial Ring in x over Finite Field of size 5 """ + def __init__(self, base_ring, rank, sparse=False, coordinate_ring=None, category=None): """ Create the ambient free module of given rank over the given integral @@ -6273,10 +6262,8 @@ def _repr_(self): Ambient free module of rank 7 over the integral domain Univariate Polynomial Ring in x over Integer Ring """ if self.is_sparse(): - return "Ambient sparse free module of rank %s over the integral domain %s" % ( - self.rank(), self.base_ring()) - return "Ambient free module of rank %s over the integral domain %s" % ( - self.rank(), self.base_ring()) + return "Ambient sparse free module of rank %s over the integral domain %s" % (self.rank(), self.base_ring()) + return "Ambient free module of rank %s over the integral domain %s" % (self.rank(), self.base_ring()) def ambient_vector_space(self): """ @@ -6384,10 +6371,12 @@ def vector_space(self, base_field=None): # ############################################################################### + class FreeModule_ambient_pid(FreeModule_generic_pid, FreeModule_ambient_domain): """ Ambient free module over a principal ideal domain. """ + def __init__(self, base_ring, rank, sparse=False, coordinate_ring=None, category=None): """ Create the ambient free module of given rank over the given @@ -6420,10 +6409,7 @@ def __init__(self, base_ring, rank, sparse=False, coordinate_ring=None, category sage: type(v) """ - FreeModule_ambient_domain.__init__(self, base_ring=base_ring, - rank=rank, sparse=sparse, - coordinate_ring=coordinate_ring, - category=category) + FreeModule_ambient_domain.__init__(self, base_ring=base_ring, rank=rank, sparse=sparse, coordinate_ring=coordinate_ring, category=category) def _repr_(self) -> str: """ @@ -6465,10 +6451,8 @@ def _repr_(self) -> str: Ambient free module of rank 7 over the principal ideal domain Integer Ring """ if self.is_sparse(): - return "Ambient sparse free module of rank %s over the principal ideal domain %s" % ( - self.rank(), self.base_ring()) - return "Ambient free module of rank %s over the principal ideal domain %s" % ( - self.rank(), self.base_ring()) + return "Ambient sparse free module of rank %s over the principal ideal domain %s" % (self.rank(), self.base_ring()) + return "Ambient free module of rank %s over the principal ideal domain %s" % (self.rank(), self.base_ring()) ############################################################################### @@ -6477,6 +6461,7 @@ def _repr_(self) -> str: # ############################################################################### + class FreeModule_ambient_field(FreeModule_generic_field, FreeModule_ambient_pid): def __init__(self, base_field, dimension, sparse=False, category=None): """ @@ -6607,6 +6592,7 @@ def coordinates(self, v): # ############################################################################### + class FreeModule_submodule_with_basis_pid(FreeModule_generic_pid): r""" Construct a submodule of a free module over PID with a distinguished basis. @@ -6654,10 +6640,8 @@ class FreeModule_submodule_with_basis_pid(FreeModule_generic_pid): [ 1 2 3/2] [ 4 5 6] """ - def __init__(self, ambient, basis, check=True, - echelonize=False, echelonized_basis=None, - already_echelonized=False, - category=None): + + def __init__(self, ambient, basis, check=True, echelonize=False, echelonized_basis=None, already_echelonized=False, category=None): r""" See :class:`FreeModule_submodule_with_basis_pid` for documentation. @@ -6760,8 +6744,7 @@ def __init__(self, ambient, basis, check=True, try: basis = [V(x) for x in basis] except TypeError: - raise TypeError("each element of basis must be in " - "the ambient vector space") + raise TypeError("each element of basis must be in " "the ambient vector space") basis = basis_seq(V, basis) @@ -6777,6 +6760,7 @@ def __init__(self, ambient, basis, check=True, # Adapted from Module_free_ambient.__init__ from sage.categories.modules_with_basis import ModulesWithBasis + modules_category = ModulesWithBasis(R.category()).FiniteDimensional() try: if R.is_finite() or len(basis) == 0: @@ -6786,9 +6770,7 @@ def __init__(self, ambient, basis, check=True, modules_category = modules_category.Subobjects() category = modules_category.or_subcategory(category, join=True) - FreeModule_generic_pid.__init__(self, base_ring=R, coordinate_ring=R_coord, - rank=len(basis), degree=ambient.degree(), - sparse=ambient.is_sparse(), category=category) + FreeModule_generic_pid.__init__(self, base_ring=R, coordinate_ring=R_coord, rank=len(basis), degree=ambient.degree(), sparse=ambient.is_sparse(), category=category) C = self.element_class self.__basis = basis_seq(self, [C(self, x.list(), coerce=False, copy=False) for x in basis]) @@ -6886,8 +6868,7 @@ def _echelon_matrix_richcmp(self, other, op): # We use self.echelonized_basis_matrix() == other.echelonized_basis_matrix() # with the matrix to avoid a circular reference. - return richcmp(self.echelonized_basis_matrix(), - other.echelonized_basis_matrix(), op) + return richcmp(self.echelonized_basis_matrix(), other.echelonized_basis_matrix(), op) def construction(self): """ @@ -6907,6 +6888,7 @@ def construction(self): True """ from sage.categories.pushout import SubspaceFunctor + return SubspaceFunctor(self.basis()), self.ambient_module() def echelonized_basis_matrix(self): @@ -6990,7 +6972,7 @@ def _echelonized_basis(self, ambient, basis): A = self._matrix_space(len(basis))(basis) E = A.echelon_form() if d != 1: - E = E.matrix_over_field() * (~d) # divide out denominator + E = E.matrix_over_field() * (~d) # divide out denominator r = E.rank() if r < E.nrows(): E = E.matrix_from_rows(range(r)) @@ -7017,6 +6999,7 @@ def _denominator(B): 30 """ from sage.arith.functions import lcm + return lcm([x.denominator() for x in B]) def _repr_(self): @@ -7054,13 +7037,9 @@ def _repr_(self): [-1 0 0 0 0 0 0 1] """ if self.is_sparse(): - s = "Sparse free module of degree %s and rank %s over %s\n" % ( - self.degree(), self.rank(), self.base_ring()) + \ - "User basis matrix:\n%r" % self.basis_matrix() + s = "Sparse free module of degree %s and rank %s over %s\n" % (self.degree(), self.rank(), self.base_ring()) + "User basis matrix:\n%r" % self.basis_matrix() else: - s = "Free module of degree %s and rank %s over %s\n" % ( - self.degree(), self.rank(), self.base_ring()) + \ - "User basis matrix:\n%r" % self.basis_matrix() + s = "Free module of degree %s and rank %s over %s\n" % (self.degree(), self.rank(), self.base_ring()) + "User basis matrix:\n%r" % self.basis_matrix() return s def _latex_(self): @@ -7333,11 +7312,8 @@ def user_to_echelon_matrix(self): if self.base_ring().is_field(): self.__user_to_echelon_matrix = self._user_to_rref_matrix() else: - rows = sum([self.echelon_coordinates(b, check=False) - for b in self.basis()], []) - M = sage.matrix.matrix_space.MatrixSpace(self.base_ring().fraction_field(), - self.dimension(), - sparse=self.is_sparse()) + rows = sum([self.echelon_coordinates(b, check=False) for b in self.basis()], []) + M = sage.matrix.matrix_space.MatrixSpace(self.base_ring().fraction_field(), self.dimension(), sparse=self.is_sparse()) self.__user_to_echelon_matrix = M(rows) return self.__user_to_echelon_matrix @@ -7791,8 +7767,7 @@ def linear_combination_of_basis(self, v): """ R = self.base_ring() check = (not R.is_field()) and any(a not in R for a in list(v)) - return self(self.basis_matrix().linear_combination_of_rows(v), - check=check, copy=False, coerce=False) + return self(self.basis_matrix().linear_combination_of_rows(v), check=check, copy=False, coerce=False) class FreeModule_submodule_pid(FreeModule_submodule_with_basis_pid): @@ -7815,8 +7790,8 @@ class FreeModule_submodule_pid(FreeModule_submodule_with_basis_pid): sage: v = W.0 + W.1 sage: TestSuite(v).run() """ - def __init__(self, ambient, gens, check=True, already_echelonized=False, - category=None): + + def __init__(self, ambient, gens, check=True, already_echelonized=False, category=None): """ Create an embedded free module over a PID. @@ -7830,10 +7805,7 @@ def __init__(self, ambient, gens, check=True, already_echelonized=False, [1 2 3] [0 3 6] """ - FreeModule_submodule_with_basis_pid.__init__(self, ambient, basis=gens, - echelonize=True, - already_echelonized=already_echelonized, - category=category) + FreeModule_submodule_with_basis_pid.__init__(self, ambient, basis=gens, echelonize=True, already_echelonized=already_echelonized, category=category) def _repr_(self): """ @@ -7855,13 +7827,9 @@ def _repr_(self): [ 0 0 0 0 0 0 1 -1] """ if self.is_sparse(): - s = "Sparse free module of degree %s and rank %s over %s\n" % ( - self.degree(), self.rank(), self.base_ring()) + \ - "Echelon basis matrix:\n%s" % self.basis_matrix() + s = "Sparse free module of degree %s and rank %s over %s\n" % (self.degree(), self.rank(), self.base_ring()) + "Echelon basis matrix:\n%s" % self.basis_matrix() else: - s = "Free module of degree %s and rank %s over %s\n" % ( - self.degree(), self.rank(), self.base_ring()) + \ - "Echelon basis matrix:\n%s" % self.basis_matrix() + s = "Free module of degree %s and rank %s over %s\n" % (self.degree(), self.rank(), self.base_ring()) + "Echelon basis matrix:\n%s" % self.basis_matrix() return s def coordinate_vector(self, v, check=True): @@ -7971,10 +7939,8 @@ class FreeModule_submodule_with_basis_field(FreeModule_generic_field, FreeModule sage: M = K^3; W = M.span_of_basis([[1,1,x]]) sage: TestSuite(W).run() """ - def __init__(self, ambient, basis, check=True, - echelonize=False, echelonized_basis=None, - already_echelonized=False, - category=None): + + def __init__(self, ambient, basis, check=True, echelonize=False, echelonized_basis=None, already_echelonized=False, category=None): """ Create a vector space with given basis. @@ -7988,10 +7954,7 @@ def __init__(self, ambient, basis, check=True, [1 2 3] [4 5 6] """ - FreeModule_submodule_with_basis_pid.__init__( - self, ambient, basis=basis, check=check, echelonize=echelonize, - echelonized_basis=echelonized_basis, already_echelonized=already_echelonized, - category=category) + FreeModule_submodule_with_basis_pid.__init__(self, ambient, basis=basis, check=check, echelonize=echelonize, echelonized_basis=echelonized_basis, already_echelonized=already_echelonized, category=category) def _repr_(self): """ @@ -8060,13 +8023,9 @@ def _repr_(self): [ 0 0 0 1 -1] """ if self.is_sparse(): - return "Sparse vector space of degree %s and dimension %s over %s\n" % ( - self.degree(), self.dimension(), self.base_field()) + \ - "User basis matrix:\n%r" % self.basis_matrix() + return "Sparse vector space of degree %s and dimension %s over %s\n" % (self.degree(), self.dimension(), self.base_field()) + "User basis matrix:\n%r" % self.basis_matrix() - return "Vector space of degree %s and dimension %s over %s\n" % ( - self.degree(), self.dimension(), self.base_field()) + \ - "User basis matrix:\n%r" % self.basis_matrix() + return "Vector space of degree %s and dimension %s over %s\n" % (self.degree(), self.dimension(), self.base_field()) + "User basis matrix:\n%r" % self.basis_matrix() def _denominator(self, B): """ @@ -8113,13 +8072,10 @@ def _echelonized_basis(self, ambient, basis): sage: W._echelonized_basis(V,W.basis()) [(1, 0, -1/2), (0, 1, 1/2)] """ - MAT = sage.matrix.matrix_space.MatrixSpace( - base_ring=ambient.base_ring(), - nrows=len(basis), ncols=ambient.degree(), - sparse=ambient.is_sparse()) + MAT = sage.matrix.matrix_space.MatrixSpace(base_ring=ambient.base_ring(), nrows=len(basis), ncols=ambient.degree(), sparse=ambient.is_sparse()) A = MAT(basis) E = A.echelon_form() - return E.rows()[:E.rank()] + return E.rows()[: E.rank()] def is_ambient(self) -> bool: """ @@ -8167,6 +8123,7 @@ class FreeModule_submodule_field(FreeModule_submodule_with_basis_field): sage: vector(QQ, W.coordinates(v)) * W.basis_matrix() (1, 5, 9) """ + def __init__(self, ambient, gens, check=True, already_echelonized=False, category=None): """ Create an embedded vector subspace with echelonized basis. @@ -8183,11 +8140,7 @@ def __init__(self, ambient, gens, check=True, already_echelonized=False, categor """ if isinstance(gens, FreeModule_generic): gens = gens.gens() - FreeModule_submodule_with_basis_field.__init__(self, ambient, - basis=gens, check=check, - echelonize=not already_echelonized, - already_echelonized=already_echelonized, - category=category) + FreeModule_submodule_with_basis_field.__init__(self, ambient, basis=gens, check=check, echelonize=not already_echelonized, already_echelonized=already_echelonized, category=category) def _repr_(self) -> str: """ @@ -8256,12 +8209,8 @@ def _repr_(self) -> str: [ 0 0 0 1 -1] """ if self.is_sparse(): - return "Sparse vector space of degree %s and dimension %s over %s\n" % ( - self.degree(), self.dimension(), self.base_field()) + \ - "Basis matrix:\n%r" % self.basis_matrix() - return "Vector space of degree %s and dimension %s over %s\n" % ( - self.degree(), self.dimension(), self.base_field()) + \ - "Basis matrix:\n%r" % self.basis_matrix() + return "Sparse vector space of degree %s and dimension %s over %s\n" % (self.degree(), self.dimension(), self.base_field()) + "Basis matrix:\n%r" % self.basis_matrix() + return "Vector space of degree %s and dimension %s over %s\n" % (self.degree(), self.dimension(), self.base_field()) + "Basis matrix:\n%r" % self.basis_matrix() def echelon_coordinates(self, v, check=True): """ @@ -8317,7 +8266,7 @@ def echelon_coordinates(self, v, check=True): if not check: # It's really really easy. return w - if v.parent() is self: # obvious that v is really in here. + if v.parent() is self: # obvious that v is really in here. return w # the "linear_combination_of_rows" call dominates the runtime # of this function, in the check==False case when the parent @@ -8397,6 +8346,7 @@ def has_user_basis(self) -> bool: ############################################################################### + def element_class(R, is_sparse): """ The class of the vectors (elements of a free module) with base ring @@ -8426,11 +8376,14 @@ def element_class(R, is_sparse): """ import sage.rings.integer_ring + if isinstance(R, sage.rings.integer_ring.IntegerRing_class) and not is_sparse: from sage.modules.vector_integer_dense import Vector_integer_dense + return Vector_integer_dense if isinstance(R, sage.rings.rational_field.RationalField) and not is_sparse: from sage.modules.vector_rational_dense import Vector_rational_dense + return Vector_rational_dense if isinstance(R, sage.rings.abc.IntegerModRing) and not is_sparse: if R.order() == 2: @@ -8466,12 +8419,15 @@ def element_class(R, is_sparse): return Vector_complex_double_dense elif isinstance(R, CallableSymbolicExpressionRing_class) and not is_sparse: import sage.modules.vector_callable_symbolic_dense + return sage.modules.vector_callable_symbolic_dense.Vector_callable_symbolic_dense elif isinstance(R, SymbolicRing): if not is_sparse: import sage.modules.vector_symbolic_dense + return sage.modules.vector_symbolic_dense.Vector_symbolic_dense import sage.modules.vector_symbolic_sparse + return sage.modules.vector_symbolic_sparse.Vector_symbolic_sparse if is_sparse: @@ -8507,6 +8463,7 @@ class EchelonMatrixKey: sage: modules == modules_sorted True """ + def __init__(self, obj): r""" Create a container for a free module with a total ordering. diff --git a/src/sage/modules/free_module_homspace.py b/src/sage/modules/free_module_homspace.py index a496fe73bf5..da3ed1bc3e9 100644 --- a/src/sage/modules/free_module_homspace.py +++ b/src/sage/modules/free_module_homspace.py @@ -61,6 +61,7 @@ TypeError: nontrivial morphisms require a coercion map from the base ring of the domain to the base ring of the codomain """ + # **************************************************************************** # Copyright (C) 2005 William Stein # @@ -154,6 +155,7 @@ def __call__(self, A, **kwds): [(0, 0), (0, 0)] """ from . import free_module_morphism + side = kwds.get("side", "left") if not isinstance(A, Matrix): # Compute the matrix of the morphism that sends the @@ -316,6 +318,5 @@ def identity(self, side='left'): Codomain: Ambient free module of rank 5 over the principal ideal domain ... """ if self.is_endomorphism_set(): - return self(identity_matrix(self.base_ring(), self.domain().rank()), - side=side) + return self(identity_matrix(self.base_ring(), self.domain().rank()), side=side) raise TypeError("Identity map only defined for endomorphisms. Try natural_map() instead.") diff --git a/src/sage/modules/free_module_integer.py b/src/sage/modules/free_module_integer.py index 4a33ee21b51..8b967d39a91 100644 --- a/src/sage/modules/free_module_integer.py +++ b/src/sage/modules/free_module_integer.py @@ -200,9 +200,7 @@ def IntegerLattice(basis, lll_reduce=True): except TypeError: raise NotImplementedError("only integer lattices supported") - return FreeModule_submodule_with_basis_integer(ZZ**basis.ncols(), - basis=basis, - lll_reduce=lll_reduce) + return FreeModule_submodule_with_basis_integer(ZZ ** basis.ncols(), basis=basis, lll_reduce=lll_reduce) class FreeModule_submodule_with_basis_integer(FreeModule_submodule_with_basis_pid): @@ -235,9 +233,8 @@ class FreeModule_submodule_with_basis_integer(FreeModule_submodule_with_basis_pi sage: L.shortest_vector() (-1, 1, 2, -2, 0, 1, 0, -1, 2, 1) """ - def __init__(self, ambient, basis, check=True, echelonize=False, - echelonized_basis=None, already_echelonized=False, - lll_reduce=True): + + def __init__(self, ambient, basis, check=True, echelonize=False, echelonized_basis=None, already_echelonized=False, lll_reduce=True): r""" Construct a new submodule of `\ZZ^n` with a distinguished basis. @@ -305,13 +302,7 @@ def __init__(self, ambient, basis, check=True, echelonize=False, self._basis_is_LLL_reduced = True basis.set_immutable() - FreeModule_submodule_with_basis_pid.__init__(self, - ambient=ambient, - basis=basis, - check=check, - echelonize=echelonize, - echelonized_basis=echelonized_basis, - already_echelonized=already_echelonized) + FreeModule_submodule_with_basis_pid.__init__(self, ambient=ambient, basis=basis, check=check, echelonize=echelonize, echelonized_basis=echelonized_basis, already_echelonized=already_echelonized) self._reduced_basis = basis.change_ring(ZZ) @@ -588,13 +579,14 @@ def shortest_vector(self, update_reduced_basis=True, algorithm='fplll', *args, * qf = self.gram_matrix() else: B = self.reduced_basis.LLL() - qf = B*B.transpose() + qf = B * B.transpose() count, length, vectors = qf.__pari__().qfminim(m=1) v = vectors.sage().columns()[0] - w = v*B + w = v * B elif algorithm == "fplll": from fpylll import IntegerMatrix, SVP + L = IntegerMatrix.from_matrix(self.reduced_basis) w = vector(ZZ, SVP.shortest_vector(L, *args, **kwds)) @@ -694,6 +686,7 @@ def voronoi_cell(self, radius=None): B = self.reduced_basis from .diamond_cutting import calculate_voronoi_cell + return calculate_voronoi_cell(B, radius=radius) def voronoi_relevant_vectors(self): @@ -727,7 +720,7 @@ def defining_point(ieq): """ c = ieq[0] a = ieq[1:] - n = sum(y ** 2 for y in a) + n = sum(y**2 for y in a) return vector([2 * y * c / n for y in a]) return [defining_point(ieq) for ieq in V.inequality_generator()] @@ -790,7 +783,7 @@ def CVPP_2V(t, V, voronoi_cell): V = self.voronoi_relevant_vectors() t = vector(t) p = 0 - while not (ZZ(2 ** p) * voronoi_cell).contains(t): + while not (ZZ(2**p) * voronoi_cell).contains(t): p += 1 t_new = t i = p @@ -861,7 +854,7 @@ def approximate_closest_vector(self, t, delta=None, algorithm='embedding', *args (1331, 1324, 1349, 1334) """ if delta is None: - delta = ZZ(99)/ZZ(100) + delta = ZZ(99) / ZZ(100) # Bound checks on delta are performed in is_LLL_reduced if not self._reduced_basis.is_LLL_reduced(delta=delta): @@ -871,18 +864,17 @@ def approximate_closest_vector(self, t, delta=None, algorithm='embedding', *args t = vector(t) if algorithm == 'embedding': - L = matrix(QQ, B.nrows()+1, B.ncols()+1) + L = matrix(QQ, B.nrows() + 1, B.ncols() + 1) L.set_block(0, 0, B) L.set_block(B.nrows(), 0, matrix(t)) - weight = (B[-1]*B[-1]).isqrt()+1 # Norm of the largest vector + weight = (B[-1] * B[-1]).isqrt() + 1 # Norm of the largest vector L[-1, -1] = weight # The vector should be the last row but we iterate just in case for v in reversed(L.LLL(delta=delta, *args, **kwargs).rows()): if abs(v[-1]) == weight: - return t - v[:-1]*v[-1].sign() - raise ValueError('No suitable vector found in basis.' - 'This is a bug, please report it.') + return t - v[:-1] * v[-1].sign() + raise ValueError('No suitable vector found in basis.' 'This is a bug, please report it.') elif algorithm == 'nearest_plane': G = B.gram_schmidt()[0] @@ -896,8 +888,8 @@ def approximate_closest_vector(self, t, delta=None, algorithm='embedding', *args # t = x*B might not have a solution over QQ so we instead solve # the system x*B*B^T = t*B^T which will be the "closest" solution # if it does not exist, same effect as using the psuedo-inverse - sol = (B*B.T).solve_left(t*B.T) - return vector(ZZ, [QQ(x).round('even') for x in sol])*B + sol = (B * B.T).solve_left(t * B.T) + return vector(ZZ, [QQ(x).round('even') for x in sol]) * B else: raise ValueError("algorithm must be one of 'embedding', 'nearest_plane' or 'rounding_off'") @@ -951,7 +943,7 @@ def hadamard_ratio(self, use_reduced_basis=True): r = self.rank() assert r == n - ratio = (self.discriminant().sqrt() / prod([v.norm() for v in basis]))**(1/r) + ratio = (self.discriminant().sqrt() / prod([v.norm() for v in basis])) ** (1 / r) assert 0 < ratio <= 1 return ratio @@ -991,5 +983,5 @@ def gaussian_heuristic(self, exact_form=False): D = self.discriminant().sqrt() if exact_form: - return (D * gamma(1 + (r/2)))**(1/r) / pi.sqrt() - return D**(1/r) * (r/(2*pi*e)).sqrt() + return (D * gamma(1 + (r / 2))) ** (1 / r) / pi.sqrt() + return D ** (1 / r) * (r / (2 * pi * e)).sqrt() diff --git a/src/sage/modules/free_module_morphism.py b/src/sage/modules/free_module_morphism.py index d9cc7d0e71f..c610dc1f521 100644 --- a/src/sage/modules/free_module_morphism.py +++ b/src/sage/modules/free_module_morphism.py @@ -359,7 +359,7 @@ def inverse_image(self, V): # 3. Multiply Y by U then takes those same linear combinations # from step 2 above and lifts them to coefficients that define # linear combinations of the basis for the domain. - C = Y*U + C = Y * U # Finally take the linear combinations of the basis for the # domain defined by C. Together with the kernel K, this spans @@ -436,6 +436,7 @@ def lift(self, x): (1, 0) """ from .free_module_element import vector + x = self.codomain()(x) if self.side() == "right": A = self.matrix().transpose() @@ -453,7 +454,7 @@ def lift(self, x): raise NotImplementedError("base ring (%s) must have hermite_form algorithm in order to compute inverse image" % R) H, U = A.hermite_form(transformation=True, include_zero_rows=False) Y = H.solve_left(vector(self.codomain().coordinates(x))) - C = Y*U + C = Y * U try: t = self.domain().linear_combination_of_basis(C) except TypeError: @@ -615,8 +616,7 @@ def eigenspaces(self, extend=True): [0 1])] """ ev = self.eigenvectors(extend) - return [(vec[0], Sequence(vec[1]).universe().subspace(vec[1])) - for vec in ev] + return [(vec[0], Sequence(vec[1]).universe().subspace(vec[1])) for vec in ev] class BaseIsomorphism1D(Morphism): @@ -633,6 +633,7 @@ class BaseIsomorphism1D(Morphism): Multivariate Polynomial Ring in x, y over Rational Field To: Multivariate Polynomial Ring in x, y over Rational Field """ + def _repr_type(self) -> str: r""" EXAMPLES:: @@ -712,6 +713,7 @@ class BaseIsomorphism1D_to_FM(BaseIsomorphism1D): ... ValueError: basis element must be a unit """ + def __init__(self, parent, basis=None): """ TESTS:: @@ -769,6 +771,7 @@ class BaseIsomorphism1D_from_FM(BaseIsomorphism1D): ... ValueError: basis element must be a unit """ + def __init__(self, parent, basis=None): """ TESTS:: diff --git a/src/sage/modules/free_module_pseudohomspace.py b/src/sage/modules/free_module_pseudohomspace.py index 41d50f24aa2..3d06094d817 100644 --- a/src/sage/modules/free_module_pseudohomspace.py +++ b/src/sage/modules/free_module_pseudohomspace.py @@ -5,6 +5,7 @@ - Xavier Caruso, Yossef Musleh (2024-09): initial version """ + # **************************************************************************** # Copyright (C) 2024 Xavier Caruso # Yossef Musleh @@ -52,6 +53,7 @@ class FreeModulePseudoHomspace(UniqueRepresentation, HomsetWithBase): sage: h(e) (z3, 2*z3^2 + 3*z3 + 3) """ + Element = FreeModulePseudoMorphism @staticmethod diff --git a/src/sage/modules/free_module_pseudomorphism.py b/src/sage/modules/free_module_pseudomorphism.py index 9d9fb265e49..d45e9653c42 100644 --- a/src/sage/modules/free_module_pseudomorphism.py +++ b/src/sage/modules/free_module_pseudomorphism.py @@ -5,6 +5,7 @@ - Xavier Caruso, Yossef Musleh (2024-09): initial version """ + # **************************************************************************** # Copyright (C) 2024 Xavier Caruso # Yossef Musleh @@ -125,6 +126,7 @@ class FreeModulePseudoMorphism(Morphism): sage: phi(v) (2*z + 1, 6*z^2 + 4*z + 5) """ + def __init__(self, parent, f, side): """ Constructs a pseudomorphism of free modules. @@ -213,10 +215,7 @@ def __init__(self, parent, f, side): if side != "left" and side != "right": raise ValueError("the side must be either 'left' or 'right'") matrix_space = parent.matrix_space() - if ((isinstance(f, FreeModulePseudoMorphism) and f.parent() is parent) - or (isinstance(f, FreeModuleMorphism) - and f.domain() is dom and f.codomain() is codom - and parent._morphism is None and parent._derivation is None)): + if (isinstance(f, FreeModulePseudoMorphism) and f.parent() is parent) or (isinstance(f, FreeModuleMorphism) and f.domain() is dom and f.codomain() is codom and parent._morphism is None and parent._derivation is None): if f.side() == 'right': self._matrix = f.matrix().transpose() else: @@ -565,8 +564,7 @@ def _composition_(self, right, homset): Domain: Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in x over Integer Ring Codomain: Ambient free module of rank 2 over the integral domain Univariate Polynomial Ring in x over Integer Ring """ - if (isinstance(right, FreeModulePseudoMorphism) - and self._derivation is None and right._derivation is None): + if isinstance(right, FreeModulePseudoMorphism) and self._derivation is None and right._derivation is None: if self._morphism is None: morphism = right._morphism mat = right._matrix * self._matrix @@ -646,6 +644,7 @@ def ore_module(self, names=None): :mod:`sage.modules.ore_module` """ from sage.modules.ore_module import OreModule + return OreModule(self._matrix, self.parent()._ore, names=names) def _test_nonzero_equal(self, tester): diff --git a/src/sage/modules/free_quadratic_module.py b/src/sage/modules/free_quadratic_module.py index 12653c13b6a..b3d6d479908 100644 --- a/src/sage/modules/free_quadratic_module.py +++ b/src/sage/modules/free_quadratic_module.py @@ -56,6 +56,7 @@ - David Kohel (2008-06): First created (based on free_module.py) """ + # **************************************************************************** # Copyright (C) 2008 David Kohel # @@ -83,8 +84,7 @@ _cache = {} -def FreeQuadraticModule(base_ring, rank, inner_product_matrix, - sparse=False, inner_product_ring=None): +def FreeQuadraticModule(base_ring, rank, inner_product_matrix, sparse=False, inner_product_ring=None): r""" Create the free quadratic module over the given commutative ring of the given rank. @@ -168,19 +168,15 @@ def FreeQuadraticModule(base_ring, rank, inner_product_matrix, # M = ComplexDoubleQuadraticSpace_class(rank, inner_product_matrix=inner_product_matrix, sparse=False) if base_ring in Fields(): - M = FreeQuadraticModule_ambient_field( - base_ring, rank, sparse=sparse, inner_product_matrix=inner_product_matrix) + M = FreeQuadraticModule_ambient_field(base_ring, rank, sparse=sparse, inner_product_matrix=inner_product_matrix) elif base_ring in PrincipalIdealDomains(): - M = FreeQuadraticModule_ambient_pid( - base_ring, rank, sparse=sparse, inner_product_matrix=inner_product_matrix) + M = FreeQuadraticModule_ambient_pid(base_ring, rank, sparse=sparse, inner_product_matrix=inner_product_matrix) elif base_ring in IntegralDomains(): - M = FreeQuadraticModule_ambient_domain( - base_ring, rank, sparse=sparse, inner_product_matrix=inner_product_matrix) + M = FreeQuadraticModule_ambient_domain(base_ring, rank, sparse=sparse, inner_product_matrix=inner_product_matrix) else: - M = FreeQuadraticModule_ambient( - base_ring, rank, sparse=sparse, inner_product_matrix=inner_product_matrix) + M = FreeQuadraticModule_ambient(base_ring, rank, sparse=sparse, inner_product_matrix=inner_product_matrix) _cache[key] = weakref.ref(M) return M @@ -281,8 +277,8 @@ class FreeQuadraticModule_generic(free_module.FreeModule_generic): sage: M1 == M2 False """ - def __init__(self, base_ring, rank, degree, - inner_product_matrix, sparse=False) -> None: + + def __init__(self, base_ring, rank, degree, inner_product_matrix, sparse=False) -> None: """ Create the free module of given rank over the given ``base_ring``. @@ -302,8 +298,7 @@ def __init__(self, base_ring, rank, degree, [ 0 x1 0] [ 0 0 x2] """ - free_module.FreeModule_generic.__init__( - self, base_ring=base_ring, rank=rank, degree=degree, sparse=sparse) + free_module.FreeModule_generic.__init__(self, base_ring=base_ring, rank=rank, degree=degree, sparse=sparse) self._inner_product_matrix = inner_product_matrix def _dense_module(self): @@ -408,7 +403,7 @@ def discriminant(self): -1 """ r = self.rank() // 2 - return (-1)**r * self.gram_matrix().determinant() + return (-1) ** r * self.gram_matrix().determinant() def gram_matrix(self): """ @@ -559,13 +554,12 @@ def _inner_product_is_diagonal(self): return A == D -class FreeQuadraticModule_generic_pid(free_module.FreeModule_generic_pid, - FreeQuadraticModule_generic): +class FreeQuadraticModule_generic_pid(free_module.FreeModule_generic_pid, FreeQuadraticModule_generic): """ Class of all free modules over a PID. """ - def __init__(self, base_ring, rank, degree, - inner_product_matrix, sparse=False) -> None: + + def __init__(self, base_ring, rank, degree, inner_product_matrix, sparse=False) -> None: """ Create a free module over a PID. @@ -577,8 +571,7 @@ def __init__(self, base_ring, rank, degree, [2 1] [1 2] """ - free_module.FreeModule_generic_pid.__init__( - self, base_ring=base_ring, rank=rank, degree=degree, sparse=sparse) + free_module.FreeModule_generic_pid.__init__(self, base_ring=base_ring, rank=rank, degree=degree, sparse=sparse) self._inner_product_matrix = inner_product_matrix def span(self, gens, check=True, already_echelonized=False): @@ -604,9 +597,7 @@ def span(self, gens, check=True, already_echelonized=False): ... ArithmeticError: argument gens (= [(0, 1, 0)]) does not generate a submodule of self """ - return FreeQuadraticModule_submodule_pid( - self.ambient_module(), gens, inner_product_matrix=self.inner_product_matrix(), - check=check, already_echelonized=already_echelonized) + return FreeQuadraticModule_submodule_pid(self.ambient_module(), gens, inner_product_matrix=self.inner_product_matrix(), check=check, already_echelonized=already_echelonized) def span_of_basis(self, basis, check=True, already_echelonized=False): r""" @@ -647,9 +638,7 @@ def span_of_basis(self, basis, check=True, already_echelonized=False): ... ValueError: the given basis vectors must be linearly independent """ - return FreeQuadraticModule_submodule_with_basis_pid( - self.ambient_module(), basis=basis, inner_product_matrix=self.inner_product_matrix(), - check=check, already_echelonized=already_echelonized) + return FreeQuadraticModule_submodule_with_basis_pid(self.ambient_module(), basis=basis, inner_product_matrix=self.inner_product_matrix(), check=check, already_echelonized=already_echelonized) def zero_submodule(self): """ @@ -663,17 +652,15 @@ def zero_submodule(self): Echelon basis matrix: [] """ - return FreeQuadraticModule_submodule_pid( - self.ambient_module(), [], self.inner_product_matrix(), check=False) + return FreeQuadraticModule_submodule_pid(self.ambient_module(), [], self.inner_product_matrix(), check=False) -class FreeQuadraticModule_generic_field(free_module.FreeModule_generic_field, - FreeQuadraticModule_generic_pid): +class FreeQuadraticModule_generic_field(free_module.FreeModule_generic_field, FreeQuadraticModule_generic_pid): """ Base class for all free modules over fields. """ - def __init__(self, base_field, dimension, degree, - inner_product_matrix, sparse=False) -> None: + + def __init__(self, base_field, dimension, degree, inner_product_matrix, sparse=False) -> None: """ Create a vector space over a field. @@ -697,9 +684,7 @@ def __init__(self, base_field, dimension, degree, """ if base_field not in Fields(): raise TypeError(f"the base_field (={base_field}) must be a field") - free_module.FreeModule_generic_field.__init__( - self, base_field=base_field, dimension=dimension, - degree=degree, sparse=sparse) + free_module.FreeModule_generic_field.__init__(self, base_field=base_field, dimension=dimension, degree=degree, sparse=sparse) self._inner_product_matrix = inner_product_matrix def span(self, gens, check=True, already_echelonized=False): @@ -737,10 +722,7 @@ def span(self, gens, check=True, already_echelonized=False): if not isinstance(gens, (list, tuple)): raise TypeError("gens (=%s) must be a list or tuple" % gens) - return FreeQuadraticModule_submodule_field( - self.ambient_module(), gens, - inner_product_matrix=self.inner_product_matrix(), - check=check, already_echelonized=already_echelonized) + return FreeQuadraticModule_submodule_field(self.ambient_module(), gens, inner_product_matrix=self.inner_product_matrix(), check=check, already_echelonized=already_echelonized) def span_of_basis(self, basis, check=True, already_echelonized=False): r""" @@ -781,10 +763,7 @@ def span_of_basis(self, basis, check=True, already_echelonized=False): ... ValueError: the given basis vectors must be linearly independent """ - return FreeQuadraticModule_submodule_with_basis_field( - self.ambient_module(), basis=basis, - inner_product_matrix=self.inner_product_matrix(), - check=check, already_echelonized=already_echelonized) + return FreeQuadraticModule_submodule_with_basis_field(self.ambient_module(), basis=basis, inner_product_matrix=self.inner_product_matrix(), check=check, already_echelonized=already_echelonized) # ############################################################################# @@ -793,13 +772,13 @@ def span_of_basis(self, basis, check=True, already_echelonized=False): # # ############################################################################# -class FreeQuadraticModule_ambient(free_module.FreeModule_ambient, - FreeQuadraticModule_generic): + +class FreeQuadraticModule_ambient(free_module.FreeModule_ambient, FreeQuadraticModule_generic): """ Ambient free module over a commutative ring. """ - def __init__(self, base_ring, rank, - inner_product_matrix, sparse=False) -> None: + + def __init__(self, base_ring, rank, inner_product_matrix, sparse=False) -> None: """ The free module of given rank over the given ``base_ring``. @@ -846,10 +825,8 @@ def _repr_(self) -> str: Ambient sparse free module of rank 12 over Ring of integers modulo 12 """ if self.is_sparse(): - return "Ambient sparse free quadratic module of rank %s over %s\n" % (self.rank(), self.base_ring()) + \ - "Inner product matrix:\n%s" % self.inner_product_matrix() - return "Ambient free quadratic module of rank %s over %s\n" % (self.rank(), self.base_ring()) + \ - "Inner product matrix:\n%s" % self.inner_product_matrix() + return "Ambient sparse free quadratic module of rank %s over %s\n" % (self.rank(), self.base_ring()) + "Inner product matrix:\n%s" % self.inner_product_matrix() + return "Ambient free quadratic module of rank %s over %s\n" % (self.rank(), self.base_ring()) + "Inner product matrix:\n%s" % self.inner_product_matrix() def _latex_(self) -> str: r""" @@ -889,9 +866,7 @@ def _dense_module(self): sage: M is S._dense_module() True """ - return FreeQuadraticModule(base_ring=self.base_ring(), rank=self.rank(), - inner_product_matrix=self.inner_product_matrix(), - sparse=False) + return FreeQuadraticModule(base_ring=self.base_ring(), rank=self.rank(), inner_product_matrix=self.inner_product_matrix(), sparse=False) def _sparse_module(self): """ @@ -907,9 +882,7 @@ def _sparse_module(self): sage: M._sparse_module() is S True """ - return FreeQuadraticModule(base_ring=self.base_ring(), rank=self.rank(), - inner_product_matrix=self.inner_product_matrix(), - sparse=True) + return FreeQuadraticModule(base_ring=self.base_ring(), rank=self.rank(), inner_product_matrix=self.inner_product_matrix(), sparse=True) # ############################################################################# @@ -918,13 +891,13 @@ def _sparse_module(self): # # ############################################################################# -class FreeQuadraticModule_ambient_domain(free_module.FreeModule_ambient_domain, - FreeQuadraticModule_ambient): + +class FreeQuadraticModule_ambient_domain(free_module.FreeModule_ambient_domain, FreeQuadraticModule_ambient): """ Ambient free quadratic module over an integral domain. """ - def __init__(self, base_ring, rank, - inner_product_matrix, sparse=False) -> None: + + def __init__(self, base_ring, rank, inner_product_matrix, sparse=False) -> None: """ EXAMPLES:: @@ -977,12 +950,8 @@ def _repr_(self) -> str: -b^2 + 4*a*c """ if self.is_sparse(): - return "Ambient sparse free quadratic module of rank %s over the integral domain %s\n" % ( - self.rank(), self.base_ring()) + \ - "Inner product matrix:\n%s" % self.inner_product_matrix() - return "Ambient free quadratic module of rank %s over the integral domain %s\n" % ( - self.rank(), self.base_ring()) + \ - "Inner product matrix:\n%s" % self.inner_product_matrix() + return "Ambient sparse free quadratic module of rank %s over the integral domain %s\n" % (self.rank(), self.base_ring()) + "Inner product matrix:\n%s" % self.inner_product_matrix() + return "Ambient free quadratic module of rank %s over the integral domain %s\n" % (self.rank(), self.base_ring()) + "Inner product matrix:\n%s" % self.inner_product_matrix() def ambient_vector_space(self): """ @@ -997,9 +966,7 @@ def ambient_vector_space(self): try: return self.__ambient_vector_space except AttributeError: - self.__ambient_vector_space = FreeQuadraticModule( - self.base_field(), self.rank(), - inner_product_matrix=self.inner_product_matrix(), sparse=self.is_sparse()) + self.__ambient_vector_space = FreeQuadraticModule(self.base_field(), self.rank(), inner_product_matrix=self.inner_product_matrix(), sparse=self.is_sparse()) return self.__ambient_vector_space @@ -1009,14 +976,13 @@ def ambient_vector_space(self): # # ############################################################################# -class FreeQuadraticModule_ambient_pid(free_module.FreeModule_ambient_pid, - FreeQuadraticModule_generic_pid, - FreeQuadraticModule_ambient_domain): + +class FreeQuadraticModule_ambient_pid(free_module.FreeModule_ambient_pid, FreeQuadraticModule_generic_pid, FreeQuadraticModule_ambient_domain): """ Ambient free quadratic module over a principal ideal domain. """ - def __init__(self, base_ring, rank, - inner_product_matrix, sparse=False) -> None: + + def __init__(self, base_ring, rank, inner_product_matrix, sparse=False) -> None: """ Create the ambient free module of given rank over the given principal ideal domain. @@ -1083,12 +1049,8 @@ def _repr_(self) -> str: Ambient sparse free module of rank 7 over the principal ideal domain Integer Ring """ if self.is_sparse(): - return "Ambient sparse free quadratic module of rank %s over the principal ideal domain %s\n" % ( - self.rank(), self.base_ring()) + \ - "Inner product matrix:\n%s" % self.inner_product_matrix() - return "Ambient free quadratic module of rank %s over the principal ideal domain %s\n" % ( - self.rank(), self.base_ring()) + \ - "Inner product matrix:\n%s" % self.inner_product_matrix() + return "Ambient sparse free quadratic module of rank %s over the principal ideal domain %s\n" % (self.rank(), self.base_ring()) + "Inner product matrix:\n%s" % self.inner_product_matrix() + return "Ambient free quadratic module of rank %s over the principal ideal domain %s\n" % (self.rank(), self.base_ring()) + "Inner product matrix:\n%s" % self.inner_product_matrix() # ############################################################################# @@ -1097,12 +1059,10 @@ def _repr_(self) -> str: # # ############################################################################# -class FreeQuadraticModule_ambient_field(free_module.FreeModule_ambient_field, - FreeQuadraticModule_generic_field, - FreeQuadraticModule_ambient_pid): - def __init__(self, base_field, dimension, - inner_product_matrix, sparse=False) -> None: +class FreeQuadraticModule_ambient_field(free_module.FreeModule_ambient_field, FreeQuadraticModule_generic_field, FreeQuadraticModule_ambient_pid): + + def __init__(self, base_field, dimension, inner_product_matrix, sparse=False) -> None: """ Create the ambient vector space of given dimension over the given field. @@ -1136,8 +1096,7 @@ def __init__(self, base_field, dimension, [1 0] [0 1] """ - free_module.FreeModule_ambient_field.__init__( - self, base_field=base_field, dimension=dimension, sparse=sparse) + free_module.FreeModule_ambient_field.__init__(self, base_field=base_field, dimension=dimension, sparse=sparse) self._inner_product_matrix = inner_product_matrix def _repr_(self) -> str: @@ -1168,10 +1127,8 @@ def _repr_(self) -> str: Sparse vector space of dimension 7 over Rational Field """ if self.is_sparse(): - return "Ambient sparse free quadratic space of dimension %s over %s\n" % (self.rank(), self.base_ring()) + \ - "Inner product matrix:\n%s" % self.inner_product_matrix() - return "Ambient quadratic space of dimension %s over %s\n" % (self.rank(), self.base_ring()) + \ - "Inner product matrix:\n%s" % self.inner_product_matrix() + return "Ambient sparse free quadratic space of dimension %s over %s\n" % (self.rank(), self.base_ring()) + "Inner product matrix:\n%s" % self.inner_product_matrix() + return "Ambient quadratic space of dimension %s over %s\n" % (self.rank(), self.base_ring()) + "Inner product matrix:\n%s" % self.inner_product_matrix() # ############################################################################# @@ -1181,8 +1138,7 @@ def _repr_(self) -> str: # ############################################################################# -class FreeQuadraticModule_submodule_with_basis_pid(free_module.FreeModule_submodule_with_basis_pid, - FreeQuadraticModule_generic_pid): +class FreeQuadraticModule_submodule_with_basis_pid(free_module.FreeModule_submodule_with_basis_pid, FreeQuadraticModule_generic_pid): r""" An `R`-submodule of `K^n` with distinguished basis, where `K` is the fraction field of a principal ideal domain `R`. @@ -1219,9 +1175,8 @@ class FreeQuadraticModule_submodule_with_basis_pid(free_module.FreeModule_submod sage: M < V False """ - def __init__(self, ambient, basis, inner_product_matrix, - check=True, echelonize=False, echelonized_basis=None, - already_echelonized=False) -> None: + + def __init__(self, ambient, basis, inner_product_matrix, check=True, echelonize=False, echelonized_basis=None, already_echelonized=False) -> None: """ Create a free module with basis over a PID. @@ -1259,9 +1214,7 @@ def __init__(self, ambient, basis, inner_product_matrix, sage: B.intersection(C) == C.intersection(B) True """ - free_module.FreeModule_submodule_with_basis_pid.__init__( - self, ambient=ambient, basis=basis, check=check, - echelonize=echelonize, echelonized_basis=echelonized_basis, already_echelonized=already_echelonized) + free_module.FreeModule_submodule_with_basis_pid.__init__(self, ambient=ambient, basis=basis, check=check, echelonize=echelonize, echelonized_basis=echelonized_basis, already_echelonized=already_echelonized) self._inner_product_matrix = inner_product_matrix def _repr_(self) -> str: @@ -1297,15 +1250,9 @@ def _repr_(self) -> str: [-1 0 0 0 0 0 0 1] """ if self.is_sparse(): - s = "Sparse free quadratic module of degree %s and rank %s over %s\n" % ( - self.degree(), self.rank(), self.base_ring()) + \ - "Basis matrix:\n%r\n" % self.basis_matrix() + \ - "Inner product matrix:\n%r" % self.inner_product_matrix() + s = "Sparse free quadratic module of degree %s and rank %s over %s\n" % (self.degree(), self.rank(), self.base_ring()) + "Basis matrix:\n%r\n" % self.basis_matrix() + "Inner product matrix:\n%r" % self.inner_product_matrix() else: - s = "Free quadratic module of degree %s and rank %s over %s\n" % ( - self.degree(), self.rank(), self.base_ring()) + \ - "Basis matrix:\n%r\n" % self.basis_matrix() + \ - "Inner product matrix:\n%r" % self.inner_product_matrix() + s = "Free quadratic module of degree %s and rank %s over %s\n" % (self.degree(), self.rank(), self.base_ring()) + "Basis matrix:\n%r\n" % self.basis_matrix() + "Inner product matrix:\n%r" % self.inner_product_matrix() return s def _latex_(self) -> str: @@ -1319,8 +1266,7 @@ def _latex_(self) -> str: sage: M._latex_() '\\mathrm{RowSpan}_{\\Bold{Z}}\\left(\\begin{array}{rrr}\n1 & 2 & 3 \\\\\n4 & 5 & 6\n\\end{array}\\right)' """ - return "\\mathrm{RowSpan}_{%s}%s" % (latex.latex(self.base_ring()), - latex.latex(self.basis_matrix())) + return "\\mathrm{RowSpan}_{%s}%s" % (latex.latex(self.base_ring()), latex.latex(self.basis_matrix())) def change_ring(self, R): """ @@ -1369,8 +1315,7 @@ def change_ring(self, R): return M.span(B) -class FreeQuadraticModule_submodule_pid(free_module.FreeModule_submodule_pid, - FreeQuadraticModule_submodule_with_basis_pid): +class FreeQuadraticModule_submodule_pid(free_module.FreeModule_submodule_pid, FreeQuadraticModule_submodule_with_basis_pid): """ An `R`-submodule of `K^n` where `K` is the fraction field of a principal ideal domain `R`. @@ -1392,9 +1337,8 @@ class FreeQuadraticModule_submodule_pid(free_module.FreeModule_submodule_pid, sage: loads(v.dumps()) == v True """ - def __init__(self, ambient, gens, - inner_product_matrix, check=True, - already_echelonized=False) -> None: + + def __init__(self, ambient, gens, inner_product_matrix, check=True, already_echelonized=False) -> None: """ Create an embedded free module over a PID. @@ -1408,8 +1352,7 @@ def __init__(self, ambient, gens, [1 2 3] [0 3 6] """ - free_module.FreeModule_submodule_pid.__init__( - self, ambient=ambient, gens=gens, check=check, already_echelonized=already_echelonized) + free_module.FreeModule_submodule_pid.__init__(self, ambient=ambient, gens=gens, check=check, already_echelonized=already_echelonized) self._inner_product_matrix = inner_product_matrix def _repr_(self) -> str: @@ -1432,19 +1375,13 @@ def _repr_(self) -> str: [ 0 0 0 0 0 0 1 -1] """ if self.is_sparse(): - s = "Sparse free module of degree %s and rank %s over %s\n" % ( - self.degree(), self.rank(), self.base_ring()) + \ - "Echelon basis matrix:\n%s" % self.basis_matrix() + s = "Sparse free module of degree %s and rank %s over %s\n" % (self.degree(), self.rank(), self.base_ring()) + "Echelon basis matrix:\n%s" % self.basis_matrix() else: - s = "Free module of degree %s and rank %s over %s\n" % ( - self.degree(), self.rank(), self.base_ring()) + \ - "Echelon basis matrix:\n%s" % self.basis_matrix() + s = "Free module of degree %s and rank %s over %s\n" % (self.degree(), self.rank(), self.base_ring()) + "Echelon basis matrix:\n%s" % self.basis_matrix() return s -class FreeQuadraticModule_submodule_with_basis_field(free_module.FreeModule_submodule_with_basis_field, - FreeQuadraticModule_generic_field, - FreeQuadraticModule_submodule_with_basis_pid): +class FreeQuadraticModule_submodule_with_basis_field(free_module.FreeModule_submodule_with_basis_field, FreeQuadraticModule_generic_field, FreeQuadraticModule_submodule_with_basis_pid): """ An embedded vector subspace with a distinguished user basis. @@ -1490,9 +1427,8 @@ class FreeQuadraticModule_submodule_with_basis_field(free_module.FreeModule_subm sage: loads(W.dumps()) == W True """ - def __init__(self, ambient, basis, inner_product_matrix, - check=True, echelonize=False, echelonized_basis=None, - already_echelonized=False) -> None: + + def __init__(self, ambient, basis, inner_product_matrix, check=True, echelonize=False, echelonized_basis=None, already_echelonized=False) -> None: """ Create a vector space with given basis. @@ -1516,9 +1452,7 @@ def __init__(self, ambient, basis, inner_product_matrix, [0 1 0] [0 0 1] """ - free_module.FreeModule_submodule_with_basis_field.__init__( - self, ambient=ambient, basis=basis, check=check, - echelonize=echelonize, echelonized_basis=echelonized_basis, already_echelonized=already_echelonized) + free_module.FreeModule_submodule_with_basis_field.__init__(self, ambient=ambient, basis=basis, check=check, echelonize=echelonize, echelonized_basis=echelonized_basis, already_echelonized=already_echelonized) self._inner_product_matrix = inner_product_matrix def _repr_(self) -> str: @@ -1571,18 +1505,11 @@ def _repr_(self) -> str: [ 0 0 0 1 -1] """ if self.is_sparse(): - return "Sparse quadratic space of degree %s and dimension %s over %s\n" % ( - self.degree(), self.dimension(), self.base_field()) + \ - "Basis matrix:\n%r" % self.basis_matrix() + \ - "Inner product matrix:\n%r" % self.inner_product_matrix() - return "Quadratic space of degree %s and dimension %s over %s\n" % ( - self.degree(), self.dimension(), self.base_field()) + \ - "Basis matrix:\n%r\n" % self.basis_matrix() + \ - "Inner product matrix:\n%r" % self.inner_product_matrix() - - -class FreeQuadraticModule_submodule_field(free_module.FreeModule_submodule_field, - FreeQuadraticModule_submodule_with_basis_field): + return "Sparse quadratic space of degree %s and dimension %s over %s\n" % (self.degree(), self.dimension(), self.base_field()) + "Basis matrix:\n%r" % self.basis_matrix() + "Inner product matrix:\n%r" % self.inner_product_matrix() + return "Quadratic space of degree %s and dimension %s over %s\n" % (self.degree(), self.dimension(), self.base_field()) + "Basis matrix:\n%r\n" % self.basis_matrix() + "Inner product matrix:\n%r" % self.inner_product_matrix() + + +class FreeQuadraticModule_submodule_field(free_module.FreeModule_submodule_field, FreeQuadraticModule_submodule_with_basis_field): """ An embedded vector subspace with echelonized basis. @@ -1612,8 +1539,8 @@ class FreeQuadraticModule_submodule_field(free_module.FreeModule_submodule_field sage: vector(QQ, W.coordinates(v)) * W.basis_matrix() (1, 5, 9) """ - def __init__(self, ambient, gens, inner_product_matrix, check=True, - already_echelonized=False) -> None: + + def __init__(self, ambient, gens, inner_product_matrix, check=True, already_echelonized=False) -> None: """ Create an embedded vector subspace with echelonized basis. @@ -1627,8 +1554,7 @@ def __init__(self, ambient, gens, inner_product_matrix, check=True, [ 1 0 -1] [ 0 1 2] """ - free_module.FreeModule_submodule_field.__init__( - self, ambient=ambient, gens=gens, check=check, already_echelonized=already_echelonized) + free_module.FreeModule_submodule_field.__init__(self, ambient=ambient, gens=gens, check=check, already_echelonized=already_echelonized) self._inner_product_matrix = inner_product_matrix def _repr_(self) -> str: @@ -1681,11 +1607,5 @@ def _repr_(self) -> str: [ 0 0 0 1 -1] """ if self.is_sparse(): - return "Sparse quadratic space of degree %s and dimension %s over %s\n" % ( - self.degree(), self.dimension(), self.base_field()) + \ - "Basis matrix:\n%r\n" % self.basis_matrix() + \ - "Inner product matrix:\n%r" % self.inner_product_matrix() - return "Quadratic space of degree %s and dimension %s over %s\n" % ( - self.degree(), self.dimension(), self.base_field()) + \ - "Basis matrix:\n%r\n" % self.basis_matrix() + \ - "Inner product matrix:\n%r" % self.inner_product_matrix() + return "Sparse quadratic space of degree %s and dimension %s over %s\n" % (self.degree(), self.dimension(), self.base_field()) + "Basis matrix:\n%r\n" % self.basis_matrix() + "Inner product matrix:\n%r" % self.inner_product_matrix() + return "Quadratic space of degree %s and dimension %s over %s\n" % (self.degree(), self.dimension(), self.base_field()) + "Basis matrix:\n%r\n" % self.basis_matrix() + "Inner product matrix:\n%r" % self.inner_product_matrix() diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index a8642a9b729..4b7b7bf62e7 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -243,20 +243,15 @@ def IntegralLattice(data, basis=None): inner_product_matrix = matrix([[0, 1], [1, 0]]) else: from sage.combinat.root_system.cartan_matrix import CartanMatrix + inner_product_matrix = CartanMatrix(data) if basis is None: basis = matrix.identity(ZZ, inner_product_matrix.ncols()) if inner_product_matrix != inner_product_matrix.transpose(): - raise ValueError("the inner product matrix must be symmetric\n%s" - % inner_product_matrix) + raise ValueError("the inner product matrix must be symmetric\n%s" % inner_product_matrix) - A = FreeQuadraticModule(ZZ, - inner_product_matrix.ncols(), - inner_product_matrix=inner_product_matrix) - return FreeQuadraticModule_integer_symmetric(ambient=A, - basis=basis, - inner_product_matrix=A.inner_product_matrix(), - already_echelonized=False) + A = FreeQuadraticModule(ZZ, inner_product_matrix.ncols(), inner_product_matrix=inner_product_matrix) + return FreeQuadraticModule_integer_symmetric(ambient=A, basis=basis, inner_product_matrix=A.inner_product_matrix(), already_echelonized=False) def IntegralLatticeDirectSum(Lattices, return_embeddings=False): @@ -348,24 +343,15 @@ def IntegralLatticeDirectSum(Lattices, return_embeddings=False): sum_degree = [sum(degrees[:i]) for i in range(N + 1)] inner_product_list = [copy(L_i.inner_product_matrix()) for L_i in Lattices] IM = matrix.block_diagonal(inner_product_list) - ambient = FreeQuadraticModule(ZZ, - degree_tot, - inner_product_matrix=IM) - basis = [matrix.block(1, 3, [matrix.zero(dims[i], sum_degree[i]), - Lattices[i].basis_matrix(), - matrix.zero(dims[i], sum_degree[-1] - sum_degree[i+1]) - ]) for i in range(N)] + ambient = FreeQuadraticModule(ZZ, degree_tot, inner_product_matrix=IM) + basis = [matrix.block(1, 3, [matrix.zero(dims[i], sum_degree[i]), Lattices[i].basis_matrix(), matrix.zero(dims[i], sum_degree[-1] - sum_degree[i + 1])]) for i in range(N)] basis_matrix = matrix.block(N, 1, basis) ipm = ambient.inner_product_matrix() - direct_sum = FreeQuadraticModule_integer_symmetric(ambient=ambient, - basis=basis_matrix, - inner_product_matrix=ipm, - already_echelonized=False) + direct_sum = FreeQuadraticModule_integer_symmetric(ambient=ambient, basis=basis_matrix, inner_product_matrix=ipm, already_echelonized=False) if not return_embeddings: return direct_sum - sum_dims = [sum(dims[:i]) for i in range(N+1)] - phi = [Lattices[i].hom(direct_sum.basis()[sum_dims[i]:sum_dims[i+1]]) - for i in range(N)] + sum_dims = [sum(dims[:i]) for i in range(N + 1)] + phi = [Lattices[i].hom(direct_sum.basis()[sum_dims[i] : sum_dims[i + 1]]) for i in range(N)] return [direct_sum, phi] @@ -604,9 +590,7 @@ def IntegralLatticeGluing(Lattices, glue, return_embeddings=False): # Check that the gluing vectors are in the # corresponding discriminant groups ALi(g[i]) - generators = [sum(phi[i](g[i].lift()*g[i].order())/g[i].order() - for i in range(N)) - for g in glue] + generators = [sum(phi[i](g[i].lift() * g[i].order()) / g[i].order() for i in range(N)) for g in glue] glued_lattice = direct_sum.overlattice(generators) if not return_embeddings: return glued_lattice @@ -615,6 +599,7 @@ def IntegralLatticeGluing(Lattices, glue, return_embeddings=False): f = [HomSpaces[i](phi[i].matrix() * G) for i in range(N)] return [glued_lattice, f] + ############################################################################### # # Base class for Lattices @@ -643,8 +628,8 @@ class FreeQuadraticModule_integer_symmetric(FreeQuadraticModule_submodule_with_b [0 1] [1 0] """ - def __init__(self, ambient, basis, inner_product_matrix, - check=True, already_echelonized=False): + + def __init__(self, ambient, basis, inner_product_matrix, check=True, already_echelonized=False): r""" Create the integral lattice spanned by ``basis`` in the ambient space. @@ -653,20 +638,12 @@ def __init__(self, ambient, basis, inner_product_matrix, sage: L = IntegralLattice("U") sage: TestSuite(L).run() """ - FreeQuadraticModule_submodule_with_basis_pid.__init__( - self, - ambient, - basis, - inner_product_matrix, - check=check, - already_echelonized=already_echelonized) + FreeQuadraticModule_submodule_with_basis_pid.__init__(self, ambient, basis, inner_product_matrix, check=check, already_echelonized=already_echelonized) if self.determinant() == 0: - raise ValueError("lattices must be nondegenerate; " - "use FreeQuadraticModule instead") + raise ValueError("lattices must be nondegenerate; " "use FreeQuadraticModule instead") if self.gram_matrix().base_ring() is not ZZ: if self.gram_matrix().denominator() != 1: - raise ValueError("lattices must be integral; " - "use FreeQuadraticModule instead") + raise ValueError("lattices must be integral; " "use FreeQuadraticModule instead") def _mul_(self, other, switch_sides=False): r""" @@ -719,8 +696,7 @@ def _repr_(self): s += "Sparse lattice " else: s += "Lattice " - s += "of degree %s and rank %s over %s\n" % ( - self.degree(), self.rank(), self.base_ring()) + s += "of degree %s and rank %s over %s\n" % (self.degree(), self.rank(), self.base_ring()) if self.basis_matrix().is_one(): s += "Standard basis \n" else: @@ -773,7 +749,7 @@ def dual_lattice(self): sage: L.is_submodule(Ldual) # needs sage.graphs True """ - return self.span(self.gram_matrix().inverse()*self.basis_matrix()) + return self.span(self.gram_matrix().inverse() * self.basis_matrix()) def discriminant_group(self, s=0): r""" @@ -829,10 +805,11 @@ def discriminant_group(self, s=0): sage: gc.unfreeze() """ from sage.modules.torsion_quadratic_module import TorsionQuadraticModule + D = TorsionQuadraticModule(self.dual_lattice(), self) d = D.annihilator().gen() a = d.prime_to_m_part(s) - Dp_gens = [a*g for g in D.gens()] + Dp_gens = [a * g for g in D.gens()] return D.submodule(Dp_gens) def signature(self): @@ -865,6 +842,7 @@ def signature_pair(self): (2, 0) """ from sage.quadratic_forms.quadratic_form import QuadraticForm + return QuadraticForm(QQ, self.gram_matrix()).signature_vector()[:2] def direct_sum(self, M): @@ -883,19 +861,13 @@ def direct_sum(self, M): Standard basis Standard scalar product """ - IM = matrix.block_diagonal([self.inner_product_matrix(), - M.inner_product_matrix()]) - ambient = FreeQuadraticModule(ZZ, - self.degree() + M.degree(), IM) + IM = matrix.block_diagonal([self.inner_product_matrix(), M.inner_product_matrix()]) + ambient = FreeQuadraticModule(ZZ, self.degree() + M.degree(), IM) smzero = matrix.zero(self.rank(), M.degree()) mszero = matrix.zero(M.rank(), self.degree()) - basis = self.basis_matrix().augment(smzero).stack( - mszero.augment(M.basis_matrix())) + basis = self.basis_matrix().augment(smzero).stack(mszero.augment(M.basis_matrix())) ipm = ambient.inner_product_matrix() - return FreeQuadraticModule_integer_symmetric(ambient=ambient, - basis=basis, - inner_product_matrix=ipm, - already_echelonized=False) + return FreeQuadraticModule_integer_symmetric(ambient=ambient, basis=basis, inner_product_matrix=ipm, already_echelonized=False) def is_primitive(self, M) -> bool: r""" @@ -925,7 +897,7 @@ def is_primitive(self, M) -> bool: sage: (L1 + L2).index_in(U) 2 """ - return gcd((self/M).invariants()) == 0 + return gcd((self / M).invariants()) == 0 def orthogonal_complement(self, M): r""" @@ -957,11 +929,11 @@ def orthogonal_complement(self, M): Standard scalar product """ from sage.modules.free_module import FreeModule_generic + if not isinstance(M, FreeModule_generic): M = self.span(M) elif M.ambient_vector_space() != self.ambient_vector_space(): - raise ValueError("M must have the same " - "ambient vector space as this lattice") + raise ValueError("M must have the same " "ambient vector space as this lattice") K = (self.inner_product_matrix() * M.basis_matrix().transpose()).kernel() K = self.span(K.basis()) @@ -995,13 +967,9 @@ def sublattice(self, basis): ... ValueError: the basis (= [(1, -1)]) does not span a submodule """ - M = FreeQuadraticModule_integer_symmetric( - ambient=self.ambient_module(), basis=basis, - inner_product_matrix=self.inner_product_matrix(), - already_echelonized=False) + M = FreeQuadraticModule_integer_symmetric(ambient=self.ambient_module(), basis=basis, inner_product_matrix=self.inner_product_matrix(), already_echelonized=False) if not M.is_submodule(self): - raise ValueError("the basis (= %s) does not span " - "a submodule" % basis) + raise ValueError("the basis (= %s) does not span " "a submodule" % basis) return M def overlattice(self, gens): @@ -1021,10 +989,7 @@ def overlattice(self, gens): [1 2] """ basis = (self + self.span(gens)).basis() - return FreeQuadraticModule_integer_symmetric( - ambient=self.ambient_module(), basis=basis, - inner_product_matrix=self.inner_product_matrix(), - already_echelonized=False) + return FreeQuadraticModule_integer_symmetric(ambient=self.ambient_module(), basis=basis, inner_product_matrix=self.inner_product_matrix(), already_echelonized=False) def maximal_overlattice(self, p=None): r""" @@ -1063,6 +1028,7 @@ def maximal_overlattice(self, p=None): if not self.is_even() and (p is None or p == 2): raise ValueError("this lattice must be even to admit an even overlattice") from sage.rings.finite_rings.finite_field_constructor import GF + L = self if p is None: P = ZZ(self.determinant()).prime_factors() @@ -1078,8 +1044,8 @@ def maximal_overlattice(self, p=None): e = b.additive_order() v = e.valuation(2) q = b.q().lift() - delta = (q*e) % 2 - b = 2**(((e.valuation(2)+1)//2) + delta) * b.lift() + delta = (q * e) % 2 + b = 2 ** (((e.valuation(2) + 1) // 2) + delta) * b.lift() isotropic.append(b) L = L.overlattice(isotropic) D = L.discriminant_group() @@ -1114,7 +1080,7 @@ def maximal_overlattice(self, p=None): continue # go squarefree D = L.discriminant_group(p).normal_form() - isotropic = [p**((-b.q().lift().valuation(p)+1)//2) * b.lift() for b in D.gens()] + isotropic = [p ** ((-b.q().lift().valuation(p) + 1) // 2) * b.lift() for b in D.gens()] L = L.overlattice(isotropic) # now the p-discriminant_group is a vector space while True: @@ -1131,11 +1097,11 @@ def maximal_overlattice(self, p=None): k = GF(p) a = k(G[0].numerator()) b = k(G[1].numerator()) - if (-b/a).is_square(): + if (-b / a).is_square(): # solve: a*x^2 + b *y^2 = 0 - x = (-b/a).sqrt() + x = (-b / a).sqrt() y = 1 - t = ZZ(x)*gen[0] + ZZ(y)*gen[1] + t = ZZ(x) * gen[0] + ZZ(y) * gen[1] else: # or solve a*x^2 + b*y^2 + c = 0 # we know the rank is at least 3 @@ -1143,11 +1109,11 @@ def maximal_overlattice(self, p=None): # brute force to find a suitable y # very fast for y in GF(p): - x = (-c - b*y**2)/a + x = (-c - b * y**2) / a if x.is_square(): x = x.sqrt() break - t = ZZ(x)*gen[0] + ZZ(y)*gen[1] + ZZ(1)*gen[2] + t = ZZ(x) * gen[0] + ZZ(y) * gen[1] + ZZ(1) * gen[2] L = L.overlattice([t.lift()]) return L @@ -1275,33 +1241,32 @@ def orthogonal_group(self, gens=None, is_finite=None): from sage.categories.groups import Groups from sage.groups.matrix_gps.isometries import GroupOfIsometries - if gens is None and self.rank() == 0: # trivial lattice + if gens is None and self.rank() == 0: # trivial lattice gens = [] is_finite = True if gens is None: sig = self.signature_pair() if not (sig[1] == 0 or sig[0] == 0): # indefinite - raise NotImplementedError( - "currently, we can only compute generators " - "for orthogonal groups over definite lattices.") + raise NotImplementedError("currently, we can only compute generators " "for orthogonal groups over definite lattices.") # definite from sage.quadratic_forms.quadratic_form import QuadraticForm + is_finite = True # Compute transformation matrix to the ambient module. L = self.overlattice(self.ambient_module().gens()) Orthogonal = L.orthogonal_complement(self) direct_sum_basis = self.basis_matrix().stack(Orthogonal.basis_matrix()) if sig[0] == 0: # negative definite - q = QuadraticForm(ZZ, -2*self.gram_matrix()) + q = QuadraticForm(ZZ, -2 * self.gram_matrix()) else: # positive definite - q = QuadraticForm(ZZ, 2*self.gram_matrix()) + q = QuadraticForm(ZZ, 2 * self.gram_matrix()) identity = matrix.identity(Orthogonal.rank()) gens = [] for g in q.automorphism_group().gens(): # We lift the automorphism by living the orthogonal complement invariant g_directsum = matrix.block_diagonal([g.matrix().T, identity]) - g_on_L = direct_sum_basis.inverse()*g_directsum*direct_sum_basis + g_on_L = direct_sum_basis.inverse() * g_directsum * direct_sum_basis gens.append(g_on_L) deg = self.degree() base = self.ambient_vector_space().base_ring() @@ -1311,13 +1276,7 @@ def orthogonal_group(self, gens=None, is_finite=None): else: cat = Groups() D = self.discriminant_group() - G = GroupOfIsometries(deg, - base, - gens, - inv_bil, - category=cat, - invariant_submodule=self, - invariant_quotient_module=D) + G = GroupOfIsometries(deg, base, gens, inv_bil, category=cat, invariant_submodule=self, invariant_quotient_module=D) return G automorphisms = orthogonal_group @@ -1337,6 +1296,7 @@ def genus(self): Genus symbol at 2: 1^2 """ from sage.quadratic_forms.genera.genus import Genus + return Genus(self.gram_matrix()) def tensor_product(self, other, discard_basis=False): @@ -1394,9 +1354,7 @@ def tensor_product(self, other, discard_basis=False): n = self.degree() m = other.degree() ambient = FreeQuadraticModule(self.base_ring(), m * n, inner_product_matrix) - return FreeQuadraticModule_integer_symmetric(ambient=ambient, - basis=basis_matrix, - inner_product_matrix=ambient.inner_product_matrix()) + return FreeQuadraticModule_integer_symmetric(ambient=ambient, basis=basis_matrix, inner_product_matrix=ambient.inner_product_matrix()) @cached_method def quadratic_form(self): @@ -1412,6 +1370,7 @@ def quadratic_form(self): [ * 2 ] """ from sage.quadratic_forms.quadratic_form import QuadraticForm + return QuadraticForm(2 * self.gram_matrix()) @cached_method @@ -1436,6 +1395,7 @@ def minimum(self): raise ValueError("the empty set does not have a minimum") if n != 0: from sage.rings.infinity import MinusInfinity + return MinusInfinity() mpari = self.gram_matrix().__pari__().qfminim(None, 0)[1] return mpari @@ -1462,6 +1422,7 @@ def maximum(self): p, n = self.signature_pair() if p != 0: from sage.rings.infinity import PlusInfinity + return PlusInfinity() mpari = (-self.gram_matrix()).__pari__().qfminim(None, 0)[1] return -mpari @@ -1491,6 +1452,7 @@ def LLL(self): if p * n != 0: from sage.env import SAGE_EXTCODE from sage.libs.pari import pari + m = self.gram_matrix() pari.read(Path(SAGE_EXTCODE) / "pari" / "simon" / "qfsolve.gp") m = pari('qflllgram_indefgoon')(m) @@ -1542,6 +1504,7 @@ def short_vectors(self, n, **kwargs): if m != 0: e = -2 from sage.quadratic_forms.quadratic_form import QuadraticForm + q = QuadraticForm(e * self.gram_matrix()) short = q.short_vector_list_up_to_length(n, **kwargs) # (matrix(L)* B ).rows() is faster than [v * B for v in L] @@ -1571,6 +1534,7 @@ def _fplll_enumerate(self, target=None): basis = L.basis_matrix() import fpylll + gmat = fpylll.IntegerMatrix.from_matrix(L.gram_matrix()) gso = fpylll.GSO.Mat(gmat, gram=True) ok = gso.update_gso() @@ -1579,8 +1543,7 @@ def _fplll_enumerate(self, target=None): coord = None if target is not None: coord = basis.solve_left(target) - Mu = 1 + matrix([gso.get_mu(i, j) for j in range(dim)] - for i in range(dim)) + Mu = 1 + matrix([gso.get_mu(i, j) for j in range(dim)] for i in range(dim)) coord *= Mu count = 8 @@ -1767,10 +1730,10 @@ def local_modification(M, G, p, check=True): L_max = L.maximal_overlattice(p=p) # invert the gerstein operations - _, U = p_adic_normal_form(L_max.gram_matrix(), p, precision=scale+3) - B = (~L_max.basis_matrix()).change_ring(ZZ)*~U.change_ring(ZZ) + _, U = p_adic_normal_form(L_max.gram_matrix(), p, precision=scale + 3) + B = (~L_max.basis_matrix()).change_ring(ZZ) * ~U.change_ring(ZZ) - _, UM = p_adic_normal_form(M.gram_matrix(), p, precision=scale+3) + _, UM = p_adic_normal_form(M.gram_matrix(), p, precision=scale + 3) B = B * UM.change_ring(ZZ) * M.basis_matrix() # the local modification diff --git a/src/sage/modules/matrix_morphism.py b/src/sage/modules/matrix_morphism.py index c35360d1007..912a8cabb96 100644 --- a/src/sage/modules/matrix_morphism.py +++ b/src/sage/modules/matrix_morphism.py @@ -824,13 +824,10 @@ def decomposition(self, *args, **kwds): else: E = self.matrix().transpose().decomposition(*args, **kwds) if D.is_ambient(): - return Sequence([D.submodule(V, check=False) for V, _ in E], - cr=True, check=False) + return Sequence([D.submodule(V, check=False) for V, _ in E], cr=True, check=False) B = D.basis_matrix() R = D.base_ring() - return Sequence([D.submodule((V.basis_matrix() * B).row_module(R), - check=False) for V, _ in E], - cr=True, check=False) + return Sequence([D.submodule((V.basis_matrix() * B).row_module(R), check=False) for V, _ in E], cr=True, check=False) def kernel(self): """ @@ -1527,6 +1524,7 @@ class MatrixMorphism(MatrixMorphism_abstract): the matrix ``A`` if it is mutable. If ``False``, then this makes ``A`` immutable. """ + def __init__(self, parent, A, copy_matrix=True, side='left'): """ Initialize ``self``. @@ -1558,6 +1556,7 @@ def __init__(self, parent, A, copy_matrix=True, side='left'): if A.is_mutable(): if copy_matrix: from copy import copy + A = copy(A) A.set_immutable() self._matrix = A diff --git a/src/sage/modules/misc.py b/src/sage/modules/misc.py index abcdfa01a20..0da98ef6484 100644 --- a/src/sage/modules/misc.py +++ b/src/sage/modules/misc.py @@ -84,6 +84,7 @@ def gram_schmidt(B): ValueError: linearly dependent input for module version of Gram-Schmidt """ from sage.modules.free_module_element import vector + if len(B) == 0 or len(B[0]) == 0: return B, matrix(ZZ, 0, 0, []) n = len(B) diff --git a/src/sage/modules/module_functors.py b/src/sage/modules/module_functors.py index c3977183c56..33318561c5a 100644 --- a/src/sage/modules/module_functors.py +++ b/src/sage/modules/module_functors.py @@ -76,6 +76,7 @@ class QuotientModuleFunctor(ConstructionFunctor): sage: Q2 = A2 / B2 sage: q3 = Q1.an_element() + Q2.an_element() """ + rank = 5 # ranking of functor, not rank of module def __init__(self, relations): diff --git a/src/sage/modules/multi_filtered_vector_space.py b/src/sage/modules/multi_filtered_vector_space.py index 293060a2214..6de1336f419 100644 --- a/src/sage/modules/multi_filtered_vector_space.py +++ b/src/sage/modules/multi_filtered_vector_space.py @@ -152,6 +152,7 @@ def index_set(self): {1, 2} """ from sage.sets.set import Set + return Set(self._filt.keys()) def change_ring(self, base_ring): @@ -185,8 +186,7 @@ def change_ring(self, base_ring): Unfiltered RR^3 """ if not self._filt: - return MultiFilteredVectorSpace(self.dimension(), - base_ring=base_ring) + return MultiFilteredVectorSpace(self.dimension(), base_ring=base_ring) filtrations = {} for key, F in self._filt.items(): filtrations[key] = F.change_ring(base_ring) @@ -441,8 +441,7 @@ def _repr_(self): Unfiltered RR^123 """ if not self._filt: - F = FilteredVectorSpace(self.dimension(), - base_ring=self.base_ring()) + F = FilteredVectorSpace(self.dimension(), base_ring=self.base_ring()) return 'Unfiltered ' + repr(F) rows = [] min_deg, max_deg = self.min_degree(), self.max_degree() @@ -451,6 +450,7 @@ def _repr_(self): r = [str(key)] + F._repr_degrees(min_deg, max_deg - 1) rows.append(r) from sage.misc.table import table + t = table(rows) w = t._widths() lines = ['Filtrations'] @@ -527,8 +527,7 @@ def direct_sum(self, other): b: QQ^3 >= QQ^2 >= QQ^2 >= QQ^2 >= 0 """ if not self.index_set() == other.index_set(): - raise ValueError('the index sets of the two summands' - ' must be the same') + raise ValueError('the index sets of the two summands' ' must be the same') filtrations = {} for key in self.index_set(): filtrations[key] = self._filt[key] + other._filt[key] @@ -569,8 +568,7 @@ def tensor_product(self, other): b: QQ^2 >= QQ^2 >= QQ^1 >= QQ^1 >= QQ^1 >= 0 """ if not self.index_set() == other.index_set(): - raise ValueError('the index sets of the two summands' - ' must be the same') + raise ValueError('the index sets of the two summands' ' must be the same') filtrations = {} for key in self.index_set(): filtrations[key] = self._filt[key] * other._filt[key] @@ -601,8 +599,7 @@ def exterior_power(self, n): a: QQ^1 >= 0 >= 0 b: QQ^1 >= QQ^1 >= 0 """ - filtrations = {key: value.exterior_power(n) - for key, value in self._filt.items()} + filtrations = {key: value.exterior_power(n) for key, value in self._filt.items()} return MultiFilteredVectorSpace(filtrations) wedge = exterior_power @@ -630,8 +627,7 @@ def symmetric_power(self, n): a: QQ^3 >= QQ^3 >= QQ^3 >= 0 >= 0 >= 0 >= 0 >= 0 b: QQ^3 >= QQ^2 >= QQ^2 >= QQ^2 >= QQ^1 >= QQ^1 >= QQ^1 >= 0 """ - filtrations = {key: value.symmetric_power(n) - for key, value in self._filt.items()} + filtrations = {key: value.symmetric_power(n) for key, value in self._filt.items()} return MultiFilteredVectorSpace(filtrations) def dual(self): @@ -653,8 +649,7 @@ def dual(self): a: QQ^2 >= QQ^2 >= QQ^2 >= 0 >= 0 b: QQ^2 >= QQ^1 >= QQ^1 >= QQ^1 >= 0 """ - filtrations = {key: value.dual() - for key, value in self._filt.items()} + filtrations = {key: value.dual() for key, value in self._filt.items()} return MultiFilteredVectorSpace(filtrations) def shift(self, deg): @@ -676,8 +671,7 @@ def shift(self, deg): sage: V.shift(-5).support() (-5, -4, -2) """ - filtrations = {key: value.shift(deg) - for key, value in self._filt.items()} + filtrations = {key: value.shift(deg) for key, value in self._filt.items()} return MultiFilteredVectorSpace(filtrations) def random_deformation(self, epsilon=None): @@ -713,6 +707,5 @@ def random_deformation(self, epsilon=None): sage: while V.random_deformation(1/100).get_degree('b',1).matrix() == matrix([1, 0]): ....: pass """ - filtrations = {key: value.random_deformation(epsilon) - for key, value in self._filt.items()} + filtrations = {key: value.random_deformation(epsilon) for key, value in self._filt.items()} return MultiFilteredVectorSpace(filtrations) diff --git a/src/sage/modules/ore_module.py b/src/sage/modules/ore_module.py index 3d8c835435c..99c6df0591b 100644 --- a/src/sage/modules/ore_module.py +++ b/src/sage/modules/ore_module.py @@ -211,6 +211,7 @@ class ScalarAction(Action): r""" Action by scalar multiplication on Ore modules. """ + def _act_(self, a, x): r""" Return the result of the action of `a` on `x`. @@ -237,6 +238,7 @@ class OreAction(Action): Action by left multiplication of Ore polynomial rings over Ore modules. """ + def _act_(self, P, x): r""" Return the result of the action of `P` on `x`. @@ -266,6 +268,7 @@ def _act_(self, P, x): # Generic class for Ore modules ############################### + def normalize_names(names, rank): r""" Return a normalized form of ``names``. @@ -321,10 +324,10 @@ class OreModule(UniqueRepresentation, FreeModule_ambient): r""" Generic class for Ore modules. """ + Element = OreModuleElement - def __classcall_private__(cls, mat, twist, denominator=None, - names=None, category=None): + def __classcall_private__(cls, mat, twist, denominator=None, names=None, category=None): r""" Normalize the input before passing it to the init function (useful to ensure the uniqueness assumption). @@ -694,8 +697,7 @@ def rename_basis(self, names, coerce=False): rank = self.rank() names = normalize_names(names, rank) cls = self.__class__ - M = cls.__classcall__(cls, self._pseudohom._matrix, self._ore, - self._denominator, names, self._ore_category) + M = cls.__classcall__(cls, self._pseudohom._matrix, self._ore, self._denominator, names, self._ore_category) if coerce: mat = identity_matrix(self.base_ring(), rank) id = self.hom(mat, codomain=M) @@ -1025,27 +1027,27 @@ def gen(self, i): def _an_element_(self): r""" - Return an element of this Ore module. + Return an element of this Ore module. - EXAMPLES: + EXAMPLES: - When the Ore module is not zero, the returned element - is the first vector of the distinguished basis:: + When the Ore module is not zero, the returned element + is the first vector of the distinguished basis:: - sage: K. = Frac(QQ['t']) - sage: S. = OrePolynomialRing(K, K.derivation()) - sage: M. = S.quotient_module(X^2 - t) - sage: M.an_element() - u + sage: K. = Frac(QQ['t']) + sage: S. = OrePolynomialRing(K, K.derivation()) + sage: M. = S.quotient_module(X^2 - t) + sage: M.an_element() + u - On the contrary, when the Ore module vanishes, the - returned element is of course zero:: + On the contrary, when the Ore module vanishes, the + returned element is of course zero:: - sage: N = M / u - sage: N - Ore module of rank 0 over Fraction Field of Univariate Polynomial Ring in t over Rational Field twisted by d/dt - sage: N.an_element() - 0 + sage: N = M / u + sage: N + Ore module of rank 0 over Fraction Field of Univariate Polynomial Ring in t over Rational Field twisted by d/dt + sage: N.an_element() + 0 """ if self.rank() > 0: return self.gen(0) @@ -1124,6 +1126,7 @@ def _Hom_(self, codomain, category): in Category of enumerated finite dimensional Ore modules with basis over Finite Field in z of size 5^3 twisted by z |--> z^5 """ from sage.modules.ore_module_homspace import OreModule_homspace + return OreModule_homspace(self, codomain) def hom(self, im_gens, codomain=None): @@ -1234,6 +1237,7 @@ def hom(self, im_gens, codomain=None): ValueError: does not define a morphism of Ore modules """ from sage.modules.ore_module_morphism import OreModuleMorphism + if codomain is None: if isinstance(im_gens, Matrix): codomain = self @@ -1402,11 +1406,13 @@ def _span(self, gens): rows += (2 * rank - len(rows)) * [zero] M = matrix(base, rows) if hasattr(M, 'popov_form'): + def normalize(M): N = M.popov_form() for i in range(N.nrows()): for j in range(N.ncols()): M[i, j] = N[i, j] + else: normalize = M.__class__.echelonize g = f @@ -1929,10 +1935,12 @@ def __hash__(self) -> int: # Submodules ############ + class OreSubmodule(OreModule): r""" Class for submodules of Ore modules. """ + def __classcall_private__(cls, ambient, gens, saturate, names): r""" Normalize the input before passing it to the init function @@ -2013,16 +2021,14 @@ def __init__(self, ambient, submodule, names) -> None: sage: TestSuite(N).run() """ from sage.modules.ore_module_morphism import OreModuleRetraction + base = ambient.base_ring() self._ambient = ambient self._submodule = submodule C = submodule.coordinates.matrix_from_columns(range(submodule.rank)) f = ambient._pseudohom rows = [f(x) * C for x in submodule.basis.rows()] - ambient._general_class.__init__( - self, matrix(base, rows), - ambient.ore_ring(action=False), - ambient._denominator, names, ambient._ore_category) + ambient._general_class.__init__(self, matrix(base, rows), ambient.ore_ring(action=False), ambient._denominator, names, ambient._ore_category) coerce = self.hom(submodule.basis, codomain=ambient) ambient.register_coercion(coerce) self._inject = coerce.__copy__() @@ -2482,10 +2488,12 @@ def morphism_corestriction(self, f): # Quotients ########### + class OreQuotientModule(OreModule): r""" Class for quotients of Ore modules. """ + def __classcall_private__(cls, cover, gens, remove_torsion, names): r""" Normalize the input before passing it to the init function @@ -2567,6 +2575,7 @@ def __init__(self, cover, submodule, names) -> None: sage: TestSuite(N).run() """ from sage.modules.ore_module_morphism import OreModuleSection + self._cover = cover d = cover.rank() base = cover.base_ring() @@ -2575,10 +2584,7 @@ def __init__(self, cover, submodule, names) -> None: coerce = submodule.coordinates.matrix_from_columns(range(rank, d)) f = cover._pseudohom images = [f(x) for x in submodule.complement.rows()] - cover._general_class.__init__( - self, matrix(base, d - rank, d, images) * coerce, - cover.ore_ring(action=False), - cover._denominator, names, cover._ore_category) + cover._general_class.__init__(self, matrix(base, d - rank, d, images) * coerce, cover.ore_ring(action=False), cover._denominator, names, cover._ore_category) self._project = coerce = cover.hom(coerce, codomain=self) self.register_coercion(coerce) section = self._section = OreModuleSection(self, cover) diff --git a/src/sage/modules/ore_module_element.py b/src/sage/modules/ore_module_element.py index b9b55f1c887..1bd87a4ed3a 100644 --- a/src/sage/modules/ore_module_element.py +++ b/src/sage/modules/ore_module_element.py @@ -24,6 +24,7 @@ class OreModuleElement(FreeModuleElement_generic_dense): r""" A generic element of a Ore module. """ + def _repr_(self): r""" Return a string representation of this element. @@ -219,7 +220,7 @@ def image(self, integral=False): y = M._pseudohom(self) if M._denominator is not None: den = M._denominator.value() - coords = [num/den for num in y.list()] + coords = [num / den for num in y.list()] if not integral: M = M.over_fraction_field() y = M(coords) diff --git a/src/sage/modules/ore_module_homspace.py b/src/sage/modules/ore_module_homspace.py index 25addede79c..98981d2d817 100644 --- a/src/sage/modules/ore_module_homspace.py +++ b/src/sage/modules/ore_module_homspace.py @@ -28,6 +28,7 @@ class OreModule_homspace(UniqueRepresentation, HomsetWithBase): r""" Class for hom spaces between Ore modules. """ + Element = OreModuleMorphism def __init__(self, domain, codomain, category=None): diff --git a/src/sage/modules/ore_module_morphism.py b/src/sage/modules/ore_module_morphism.py index 45f66b87773..3250c98326b 100644 --- a/src/sage/modules/ore_module_morphism.py +++ b/src/sage/modules/ore_module_morphism.py @@ -273,6 +273,7 @@ class OreModuleMorphism(Morphism): r""" Generic class for morphism between Ore modules. """ + def __init__(self, parent, im_gens, check=True): r""" Initialize this Ore module. @@ -335,8 +336,7 @@ def __init__(self, parent, im_gens, check=True): sd = den / dd sc = den / dc - if (isinstance(im_gens, Element) - and base.has_coerce_map_from(im_gens.parent())): + if isinstance(im_gens, Element) and base.has_coerce_map_from(im_gens.parent()): self._matrix = MS(im_gens) elif isinstance(im_gens, Matrix): self._matrix = MS(im_gens) @@ -358,8 +358,8 @@ def __init__(self, parent, im_gens, check=True): dimc = codomain.rank() d = dimc + dimd vs = [domain(x).list() + codomain(y).list() for x, y in im_gens.items()] - if len(vs) < 2*d: - vs += (2*d - len(vs)) * [d * [zero]] + if len(vs) < 2 * d: + vs += (2 * d - len(vs)) * [d * [zero]] M = matrix(vs) M.echelonize() oldr = 0 @@ -377,7 +377,7 @@ def __init__(self, parent, im_gens, check=True): y = sc * fc(y) v = x.list() + y.list() for j in range(d): - M[i+r,j] = v[j] + M[i + r, j] = v[j] M.echelonize() oldr = r r = M.rank() @@ -601,7 +601,7 @@ def _rmul_(self, a): True """ H = self.parent() - return H(a*self._matrix, check=False) + return H(a * self._matrix, check=False) def __eq__(self, other): r""" @@ -987,6 +987,7 @@ class OreModuleRetraction(Map): Conversion (partially defined) map from an ambient module to one of its submodule. """ + def _call_(self, y): r""" TESTS:: @@ -1024,6 +1025,7 @@ class OreModuleSection(Map): Section map of the projection onto a quotient. It is not necessarily compatible with the Ore action. """ + def _call_(self, y): r""" TESTS:: diff --git a/src/sage/modules/quotient_module.py b/src/sage/modules/quotient_module.py index 4f84c469b65..5d0ef4e3e5b 100644 --- a/src/sage/modules/quotient_module.py +++ b/src/sage/modules/quotient_module.py @@ -53,6 +53,7 @@ class QuotientModule_free_ambient(Module_free_ambient): [x - y z] [ y*z x*z] """ + def __init__(self, module, sub): """ Create this quotient module of ``module`` by a submodule ``sub``. @@ -173,13 +174,12 @@ def _coerce_map_from_(self, M): [ y*z x*z] """ if isinstance(M, FreeModule_ambient): - return (self.base_ring().has_coerce_map_from(M.base_ring()) and - self.degree() == M.degree()) + return self.base_ring().has_coerce_map_from(M.base_ring()) and self.degree() == M.degree() from sage.modules.submodule import Submodule_free_ambient + if isinstance(M, Submodule_free_ambient): return self._module.has_coerce_map_from(self.ambient_module()) - if (isinstance(M, QuotientModule_free_ambient) - and M.free_cover() == self.free_cover()): + if isinstance(M, QuotientModule_free_ambient) and M.free_cover() == self.free_cover(): try: return M.free_relations().is_submodule(self.free_relations()) except NotImplementedError: @@ -302,6 +302,7 @@ def free_relations(self): # ############################################################################### + class FreeModule_ambient_field_quotient(FreeModule_ambient_field): """ A quotient `V/W` of two vector spaces as a vector space. @@ -388,6 +389,7 @@ class FreeModule_ambient_field_quotient(FreeModule_ambient_field): sage: type(loads(dumps(U)) ) """ + def __init__(self, domain, sub, quotient_matrix, lift_matrix, inner_product_matrix=None): """ Create this quotient space, from the given domain, submodule, @@ -461,10 +463,7 @@ def _repr_(self): sage: Q._repr_() # needs sage.rings.finite_rings 'Vector space quotient V/W of dimension 1 over Finite Field in a of size 3^2 where\nV: Vector space of degree 3 and dimension 2 over Finite Field in a of size 3^2\nUser basis matrix:\n[1 0 a]\n[a a 1]\nW: Vector space of degree 3 and dimension 1 over Finite Field in a of size 3^2\nBasis matrix:\n[ 1 1 a + 2]' """ - return "%s space quotient V/W of dimension %s over %s where\nV: %s\nW: %s" % ( - "Sparse vector" if self.is_sparse() else "Vector", - self.dimension(), self.base_ring(), - self.V(), self.W()) + return "%s space quotient V/W of dimension %s over %s where\nV: %s\nW: %s" % ("Sparse vector" if self.is_sparse() else "Vector", self.dimension(), self.base_ring(), self.V(), self.W()) def __hash__(self): """ @@ -587,9 +586,8 @@ def _coerce_map_from_(self, M): sage: V.coerce_map_from(QQ^2) """ from sage.modules.free_module import FreeModule_ambient - if (isinstance(M, FreeModule_ambient) - and not (isinstance(M, FreeModule_ambient_field_quotient) - and self._sub == M._sub)): + + if isinstance(M, FreeModule_ambient) and not (isinstance(M, FreeModule_ambient_field_quotient) and self._sub == M._sub): # No map between different quotients. # No map from quotient to abstract module. return None diff --git a/src/sage/modules/real_double_vector.py b/src/sage/modules/real_double_vector.py index 5430e175f11..0b6c61464be 100644 --- a/src/sage/modules/real_double_vector.py +++ b/src/sage/modules/real_double_vector.py @@ -11,6 +11,7 @@ sage: loads(dumps(v)) == v True """ + ############################################################################### # Copyright (C) 2008 Jason Grout # Distributed under the terms of the GNU General Public License (GPL) diff --git a/src/sage/modules/submodule.py b/src/sage/modules/submodule.py index b3556bd8906..1c911b5f8c0 100644 --- a/src/sage/modules/submodule.py +++ b/src/sage/modules/submodule.py @@ -86,6 +86,7 @@ class Submodule_free_ambient(Module_free_ambient): To: Ambient free module of rank 2 over the integral domain Multivariate Polynomial Ring in x, y, z over Rational Field """ + def __init__(self, ambient, gens, check=True, already_echelonized=False): r""" Initialize. @@ -205,17 +206,14 @@ def _groebner_basis_contains(self, v): ideal_gens = R.defining_ideal().gens() do_lift = True else: - from sage.rings.polynomial.multi_polynomial_ring_base import \ - MPolynomialRing_base + from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base + if isinstance(R, MPolynomialRing_base): poly_ring = R ideal_gens = [] do_lift = False else: - raise NotImplementedError( - "Gröbner basis membership test is not implemented for " - "modules over {}".format(R) - ) + raise NotImplementedError("Gröbner basis membership test is not implemented for " "modules over {}".format(R)) # Suppress "_ is no standard basis" warning from Singular opt_verb['not_warn_sb'] = True @@ -290,11 +288,7 @@ def _check_element_membership(self, x): # fall back to no check (old behavior) pass except ArithmeticError: - raise TypeError( - "element {} is not in this submodule".format( - tuple(x) - ) - ) + raise TypeError("element {} is not in this submodule".format(tuple(x))) def _repr_(self): """ @@ -323,11 +317,8 @@ def _repr_(self): [ y*z x*z] """ if isinstance(self._ambient, QuotientModule_free_ambient): - return ("Subquotient of %s\n" % self.ambient_module().free_cover() + - "Generated by the rows of the matrix:\n%s\n" % self.matrix() + - "With relations matrix:\n%s" % self._ambient.free_relations().matrix()) - return ("Submodule of %s\n" % self.ambient_module() + - "Generated by the rows of the matrix:\n%s" % self.matrix()) + return "Subquotient of %s\n" % self.ambient_module().free_cover() + "Generated by the rows of the matrix:\n%s\n" % self.matrix() + "With relations matrix:\n%s" % self._ambient.free_relations().matrix() + return "Submodule of %s\n" % self.ambient_module() + "Generated by the rows of the matrix:\n%s" % self.matrix() def matrix(self): """ @@ -343,8 +334,8 @@ def matrix(self): [ y*z x*z] """ from sage.matrix.matrix_space import MatrixSpace - MAT = MatrixSpace(self.base_ring(), len(self.gens()), self.degree(), - sparse=self.is_sparse()) + + MAT = MatrixSpace(self.base_ring(), len(self.gens()), self.degree(), sparse=self.is_sparse()) A = MAT(self.gens()) A.set_immutable() return A diff --git a/src/sage/modules/submodule_helper.py b/src/sage/modules/submodule_helper.py index a268feefb0b..28d4c8f8ea4 100644 --- a/src/sage/modules/submodule_helper.py +++ b/src/sage/modules/submodule_helper.py @@ -44,6 +44,7 @@ class SubmoduleHelper(metaclass=ClasscallMetaclass): - ``is_saturated``: a boolean; whether this submodule is saturated in the ambient space """ + def __classcall_private__(self, mat, saturate=False): r""" Dispatch to the appropriate class. @@ -80,8 +81,7 @@ def __classcall_private__(self, mat, saturate=False): base = mat.base_ring() if base in Fields(): cls = SubmoduleHelper_field - elif (isinstance(mat, Matrix_polynomial_dense) - and base.base_ring() in Fields()): + elif isinstance(mat, Matrix_polynomial_dense) and base.base_ring() in Fields(): cls = SubmoduleHelper_polynomial_ring elif base in PrincipalIdealDomains(): cls = SubmoduleHelper_PID @@ -146,6 +146,7 @@ class SubmoduleHelper_field(SubmoduleHelper): r""" Submodules over fields. """ + def __init__(self, mat, saturate): r""" Initialize this submodule. @@ -183,7 +184,7 @@ def __init__(self, mat, saturate): pivots = basis.pivots() self.basis = basis.matrix_from_rows(range(r)) self.basis.set_immutable() - self.complement = matrix(base, n-r, n) + self.complement = matrix(base, n - r, n) self.coordinates = matrix(base, n, n) indices = [] i = 0 @@ -193,11 +194,11 @@ def __init__(self, mat, saturate): i += 1 else: indices.append(j) - self.complement[j-i, j] = base.one() - self.coordinates[j, j-i+r] = base.one() + self.complement[j - i, j] = base.one() + self.coordinates[j, j - i + r] = base.one() for i in range(r): - for j in range(n-r): - self.coordinates[pivots[i], j+r] = -basis[i, indices[j]] + for j in range(n - r): + self.coordinates[pivots[i], j + r] = -basis[i, indices[j]] self.is_saturated = True @@ -206,6 +207,7 @@ class SubmoduleHelper_PID(SubmoduleHelper): Submodules over principal ideal domains (except polynomial rings to which a special class is dedicated). """ + def __init__(self, mat, saturate): r""" Initialize this submodule. @@ -252,7 +254,7 @@ def __init__(self, mat, saturate): S, U, V = mat.smith_form() r = 0 for i in range(min(S.nrows(), S.ncols())): - if S[i,i] == 0: + if S[i, i] == 0: break r += 1 self.rank = r @@ -263,10 +265,9 @@ def __init__(self, mat, saturate): self.is_saturated = True else: S = S.matrix_from_rows(range(r)) - basis = matrix(base, [[S[i,i]*W[i,j] for j in range(n)] - for i in range(r)]) + basis = matrix(base, [[S[i, i] * W[i, j] for j in range(n)] for i in range(r)]) complement = W.matrix_from_rows(range(r, n)) - self.is_saturated = all(S[i,i].is_unit() for i in range(r)) + self.is_saturated = all(S[i, i].is_unit() for i in range(r)) self.basis = basis.echelon_form() self.basis.set_immutable() self.complement = complement.echelon_form() @@ -277,6 +278,7 @@ class SubmoduleHelper_polynomial_ring(SubmoduleHelper): r""" Submodules over polynomial rings. """ + def __init__(self, mat, saturate): r""" Initialize this submodule. @@ -310,7 +312,7 @@ def __init__(self, mat, saturate): W = V.inverse().change_ring(base) r = 0 for i in range(min(S.nrows(), S.ncols())): - if S[i,i] == 0: + if S[i, i] == 0: break r += 1 mat = W.matrix_from_rows(range(r)) diff --git a/src/sage/modules/tensor_operations.py b/src/sage/modules/tensor_operations.py index 2f17640d89e..6dad8d16b6c 100644 --- a/src/sage/modules/tensor_operations.py +++ b/src/sage/modules/tensor_operations.py @@ -124,9 +124,9 @@ def antisymmetrized_coordinate_sums(dim, n): from sage.structure.formal_sum import FormalSum from sage.groups.perm_gps.permgroup_named import SymmetricGroup from sage.combinat.combination import Combinations + S_d = SymmetricGroup(n) - table = [FormalSum([[g.sign(), g(tuple(i))] for g in S_d]) - for i in Combinations(range(dim), n)] + table = [FormalSum([[g.sign(), g(tuple(i))] for g in S_d]) for i in Combinations(range(dim), n)] return tuple(table) @@ -170,6 +170,7 @@ class VectorCollection(FreeModule_ambient_field): sage: r.is_immutable() True """ + def __init__(self, vector_collection, base_ring, dim): """ EXAMPLES:: @@ -259,6 +260,7 @@ class TensorOperation(VectorCollection): sage: R_tensor_S.vectors() ((1, 0), (-1, 0), (1, 2), (-1, -2)) """ + def __init__(self, vector_collections, operation='product'): """ EXAMPLES:: @@ -420,8 +422,7 @@ def _init_symmetric(self): [((0, 0), 0), ((0, 1), 1), ((0, 2), 2), ((1, 1), 3), ((1, 2), 4), ((2, 2), 3)] """ V_list_indices = [list(range(V.n_vectors())) for V in self._V] - Sym = symmetrized_coordinate_sums(self._V[0].dimension(), - len(self._V)) + Sym = symmetrized_coordinate_sums(self._V[0].dimension(), len(self._V)) N = len(V_list_indices) for i in product(*V_list_indices): if any(i[j - 1] > i[j] for j in range(1, N)): @@ -446,6 +447,7 @@ def _init_antisymmetric(self): dim = self._V[0].degree() Alt = antisymmetrized_coordinate_sums(dim, n) from sage.combinat.combination import Combinations + for i in Combinations(range(self._V[0].n_vectors()), n): ray = self._init_power_operation_vectors(i, Alt) if ray is not None: diff --git a/src/sage/modules/torsion_quadratic_module.py b/src/sage/modules/torsion_quadratic_module.py index 28dc1dd4d6f..ea824359497 100644 --- a/src/sage/modules/torsion_quadratic_module.py +++ b/src/sage/modules/torsion_quadratic_module.py @@ -84,7 +84,7 @@ def TorsionQuadraticForm(q): Q = FreeQuadraticModule(ZZ, q.ncols(), inner_product_matrix=d**2 * q) denoms = [D[i, i].denominator() for i in range(D.ncols())] rels = Q.span(diagonal_matrix(ZZ, denoms) * U) - return TorsionQuadraticModule((1/d)*Q, (1/d)*rels, modulus=1) + return TorsionQuadraticModule((1 / d) * Q, (1 / d) * rels, modulus=1) class TorsionQuadraticModuleElement(FGP_Element): @@ -224,6 +224,7 @@ class TorsionQuadraticModule(FGP_Module_class, CachedRepresentation): [0 1 0] [0 0 1] """ + Element = TorsionQuadraticModuleElement @staticmethod @@ -313,10 +314,7 @@ def _repr_(self): [0 0 0] [0 0 0] """ - return ("Finite quadratic module over %s with invariants %s\n" - % (self.base_ring(), self.invariants()) + - "Gram matrix of the quadratic form with values in %r:\n%r" - % (self.value_module_qf(), self.gram_matrix_quadratic())) + return "Finite quadratic module over %s with invariants %s\n" % (self.base_ring(), self.invariants()) + "Gram matrix of the quadratic form with values in %r:\n%r" % (self.value_module_qf(), self.gram_matrix_quadratic()) def _module_constructor(self, V, W, check=False): r""" @@ -355,9 +353,7 @@ def _module_constructor(self, V, W, check=False): if check: # figuring out the modulus can be expensive return TorsionQuadraticModule(V, W, check=check) - return TorsionQuadraticModule(V, W, check=check, - modulus=self._modulus, - modulus_qf=self._modulus_qf) + return TorsionQuadraticModule(V, W, check=check, modulus=self._modulus, modulus_qf=self._modulus_qf) def all_submodules(self): r""" @@ -392,6 +388,7 @@ def all_submodules(self): [1/2 1]] """ from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap + invs = self.invariants() # knows how to compute all subgroups A = AbelianGroupGap(invs) @@ -440,9 +437,9 @@ def brown_invariant(self): ValueError: the torsion quadratic form must have values in QQ / 2 ZZ """ if self._modulus_qf != 2: - raise ValueError("the torsion quadratic form must have values in " - "QQ / 2 ZZ") + raise ValueError("the torsion quadratic form must have values in " "QQ / 2 ZZ") from sage.quadratic_forms.genera.normal_form import collect_small_blocks + brown = IntegerModRing(8).zero() for p in self.annihilator().gen().prime_divisors(): q = self.primary_part(p).normal_form() @@ -612,27 +609,23 @@ def genus(self, signature_pair): sage: all(g == g.discriminant_form().genus(g.signature_pair()) for g in genera) # long time True """ - from sage.quadratic_forms.genera.genus import (Genus_Symbol_p_adic_ring, - GenusSymbol_global_ring, - p_adic_symbol, - is_GlobalGenus, - _blocks) + from sage.quadratic_forms.genera.genus import Genus_Symbol_p_adic_ring, GenusSymbol_global_ring, p_adic_symbol, is_GlobalGenus, _blocks from sage.misc.misc_c import prod + s_plus = signature_pair[0] s_minus = signature_pair[1] rank = s_plus + s_minus if len(self.invariants()) > rank: - raise ValueError("this discriminant form and " + - "signature do not define a genus") + raise ValueError("this discriminant form and " + "signature do not define a genus") disc = self.cardinality() - determinant = (-1)**s_minus * disc + determinant = (-1) ** s_minus * disc local_symbols = [] for p in (2 * disc).prime_divisors(): D = self.primary_part(p) if len(D.invariants()) != 0: G_p = D.gram_matrix_quadratic().inverse() # get rid of denominators without changing the local equivalence class - G_p *= G_p.denominator()**2 + G_p *= G_p.denominator() ** 2 G_p = G_p.change_ring(ZZ) local_symbol = p_adic_symbol(G_p, p, D.invariants()[-1].valuation(p)) else: @@ -647,7 +640,7 @@ def genus(self, signature_pair): local_symbol.append([ZZ(0), rk, det, ZZ(0), ZZ(0)]) else: det = legendre_symbol(determinant.prime_to_m_part(p), p) - det = (det * prod([di[2] for di in local_symbol])) + det = det * prod([di[2] for di in local_symbol]) local_symbol.append([ZZ(0), rk, det]) local_symbol.sort() local_symbol = Genus_Symbol_p_adic_ring(p, local_symbol) @@ -687,11 +680,7 @@ def genus(self, signature_pair): block2 = [sym2[2]] # if it is odd we know det and oddity mod 4 at least else: - block2 = [b for b in _blocks(sym2[2]) if b[3] == o - and (b[2] - d) % 4 == 0 - and (b[4] - t) % 4 == 0 - and (b[2] - d) % 8 == (b[4] - t) % 8 # if the oddity is altered by 4 then so is the determinant - ] + block2 = [b for b in _blocks(sym2[2]) if b[3] == o and (b[2] - d) % 4 == 0 and (b[4] - t) % 4 == 0 and (b[2] - d) % 8 == (b[4] - t) % 8] # if the oddity is altered by 4 then so is the determinant elif self.value_module_qf().n == 2: # the form is even block0 = [b for b in _blocks(sym2[0]) if b[3] == 0] @@ -704,14 +693,13 @@ def genus(self, signature_pair): block1 = [sym2[1]] else: # the block is odd and we know det and oddity mod 4 - block1 = [b for b in _blocks(sym2[1]) - if b[3] == o - and (b[2] - d) % 4 == 0 - and (b[4] - t) % 4 == 0 - and (b[2] - d) % 8 == (b[4] - t) % 8 - # if the oddity is altered by 4 - # then so is the determinant - ] + block1 = [ + b + for b in _blocks(sym2[1]) + if b[3] == o and (b[2] - d) % 4 == 0 and (b[4] - t) % 4 == 0 and (b[2] - d) % 8 == (b[4] - t) % 8 + # if the oddity is altered by 4 + # then so is the determinant + ] # this is completely determined block2 = [sym2[2]] else: @@ -775,18 +763,15 @@ def is_genus(self, signature_pair, even=True) -> bool: rank = s_plus + s_minus signature = s_plus - s_minus D = self.cardinality() - det = (-1)**s_minus * D + det = (-1) ** s_minus * D if rank < len(self.invariants()): return False if even and self._modulus_qf != 2: - raise ValueError("the discriminant form of an even lattice has" - "values modulo 2.") + raise ValueError("the discriminant form of an even lattice has" "values modulo 2.") if (not even) and not (self._modulus == self._modulus_qf == 1): - raise ValueError("the discriminant form of an odd lattice has" - "values modulo 1.") + raise ValueError("the discriminant form of an odd lattice has" "values modulo 1.") if not even: - raise NotImplementedError("at the moment sage knows how to do this only for even genera. " + - " Help us to implement this for odd genera.") + raise NotImplementedError("at the moment sage knows how to do this only for even genera. " + " Help us to implement this for odd genera.") for p in D.prime_divisors(): # check the determinant conditions Q_p = self.primary_part(p) @@ -801,7 +786,7 @@ def is_genus(self, signature_pair, even=True) -> bool: if rank % 2 != length_p % 2: return False n = (rank - length_p) / 2 - if u % 4 != (-1)**(n % 2) * up % 4: + if u % 4 != (-1) ** (n % 2) * up % 4: return False if rank == length_p: a = QQ(1) / QQ(2) @@ -878,7 +863,7 @@ def orthogonal_group(self, gens=None, check=False): else: # see if there is an action try: - gens = [matrix(x*g for x in self.smith_form_gens()) for g in gens] + gens = [matrix(x * g for x in self.smith_form_gens()) for g in gens] except TypeError: pass # the ambient knows what to do with the generators @@ -1089,7 +1074,7 @@ def normal_form(self, partial=False): # the inverse is in normal form - so to get a normal form for the original one # it is enough to massage each 1x1 resp. 2x2 block. U = U.change_ring(Zp(p, type='fixed-mod', prec=prec)).change_ring(ZZ) - D = U * q_p * U.T * p**q_p.denominator().valuation(p) + D = U * q_p * U.T * p ** q_p.denominator().valuation(p) D = D.change_ring(Zp(p, type='fixed-mod', prec=prec)) _, U1 = _normalize(D, normal_odd=False) U = U1.change_ring(ZZ) * U @@ -1200,8 +1185,7 @@ def submodule_with_gens(self, gens): gens = tuple(self(v) for v in gens) V = self.V().submodule([v.lift() for v in gens]) + self._W W = self.W() - return TorsionQuadraticModule(V, W, gens=gens, modulus=self._modulus, - modulus_qf=self._modulus_qf, check=False) + return TorsionQuadraticModule(V, W, gens=gens, modulus=self._modulus, modulus_qf=self._modulus_qf, check=False) def twist(self, s): r""" diff --git a/src/sage/modules/vector_callable_symbolic_dense.py b/src/sage/modules/vector_callable_symbolic_dense.py index d4055f24471..00274c699a9 100644 --- a/src/sage/modules/vector_callable_symbolic_dense.py +++ b/src/sage/modules/vector_callable_symbolic_dense.py @@ -92,6 +92,7 @@ def _latex_(self): t \ {\mapsto}\ \left(\cos\left(t\right),\,\sin\left(t\right)\right) """ from sage.misc.latex import latex + ring = self.coordinate_ring() args = ring.arguments() args = [latex(arg) for arg in args] diff --git a/src/sage/modules/vector_space_homspace.py b/src/sage/modules/vector_space_homspace.py index 55ed328ddaf..1e2f9df0176 100644 --- a/src/sage/modules/vector_space_homspace.py +++ b/src/sage/modules/vector_space_homspace.py @@ -329,10 +329,12 @@ def __call__(self, A, check=True, **kwds): dimensions of the matrix were incorrect. """ from .vector_space_morphism import VectorSpaceMorphism + D = self.domain() C = self.codomain() side = kwds.get("side", "left") from sage.structure.element import Matrix + if isinstance(A, Matrix): pass elif isinstance(A, VectorSpaceMorphism): diff --git a/src/sage/modules/vector_space_morphism.py b/src/sage/modules/vector_space_morphism.py index b70b528239d..801132b6762 100644 --- a/src/sage/modules/vector_space_morphism.py +++ b/src/sage/modules/vector_space_morphism.py @@ -697,6 +697,7 @@ def linear_transformation(arg0, arg1=None, arg2=None, side='left'): from sage.matrix.constructor import matrix from sage.modules.free_module import VectorSpace from sage.modules.module import Module + try: from sage.modules.vector_callable_symbolic_dense import ( Vector_callable_symbolic_dense, @@ -747,6 +748,7 @@ def linear_transformation(arg0, arg1=None, arg2=None, side='left'): pass elif isinstance(arg2, Vector_callable_symbolic_dense): from sage.symbolic.ring import SR + args = arg2.parent().base_ring()._arguments exprs = arg2.change_ring(SR) m = len(args) @@ -923,9 +925,7 @@ def _latex_(self): '}\n\\left(\\begin{array}{rr}\n0', '&', '1', '\\\\\n2', '&', '3', '\\\\\n4', '&', '5\n\\end{array}\\right)'] """ - s = ('\\text{vector space morphism from }\n', self.domain()._latex_(), - '\\text{ to }\n', self.codomain()._latex_(), - '\\text{ represented by the matrix }\n', self.matrix()._latex_()) + s = ('\\text{vector space morphism from }\n', self.domain()._latex_(), '\\text{ to }\n', self.codomain()._latex_(), '\\text{ represented by the matrix }\n', self.matrix()._latex_()) return ''.join(s) def _repr_(self): @@ -947,8 +947,5 @@ def _repr_(self): act = "" if self.side() == "right": act = "as left-multiplication " - msg = ("Vector space morphism represented {}by the matrix:\n", - "{!r}\n", - "Domain: {}\n", - "Codomain: {}") + msg = ("Vector space morphism represented {}by the matrix:\n", "{!r}\n", "Domain: {}\n", "Codomain: {}") return ''.join(msg).format(act, m, self.domain(), self.codomain()) diff --git a/src/sage/modules/vector_symbolic_dense.py b/src/sage/modules/vector_symbolic_dense.py index e3d6524a921..b37edd2fd3f 100644 --- a/src/sage/modules/vector_symbolic_dense.py +++ b/src/sage/modules/vector_symbolic_dense.py @@ -69,6 +69,7 @@ def apply_map(phi): sage: f(v) (2, 3, 4) """ + def apply(self, *args, **kwds): """ Generic function used to implement common symbolic operations @@ -99,6 +100,7 @@ def apply(self, *args, **kwds): (sin(2*x), sin(3*x)) """ return self.apply_map(lambda x: phi(x, *args, **kwds)) + apply.__doc__ += "\nSee Expression." + phi.__name__ + "() for optional arguments." return apply @@ -108,8 +110,5 @@ class Vector_symbolic_dense(free_module_element.FreeModuleElement_generic_dense) # Add elementwise methods. -for method in ['simplify', 'simplify_factorial', - 'simplify_log', 'simplify_rational', - 'simplify_trig', 'simplify_full', 'trig_expand', - 'canonicalize_radical', 'trig_reduce']: +for method in ['simplify', 'simplify_factorial', 'simplify_log', 'simplify_rational', 'simplify_trig', 'simplify_full', 'trig_expand', 'canonicalize_radical', 'trig_reduce']: setattr(Vector_symbolic_dense, method, apply_map(getattr(Expression, method))) diff --git a/src/sage/modules/vector_symbolic_sparse.py b/src/sage/modules/vector_symbolic_sparse.py index 290aa282a85..003f54c7e28 100644 --- a/src/sage/modules/vector_symbolic_sparse.py +++ b/src/sage/modules/vector_symbolic_sparse.py @@ -71,6 +71,7 @@ def apply_map(phi): sage: f(v) (2, 3, 4) """ + def apply(self, *args, **kwds): """ Generic function used to implement common symbolic operations @@ -101,6 +102,7 @@ def apply(self, *args, **kwds): (sin(2*x), sin(3*x)) """ return self.apply_map(lambda x: phi(x, *args, **kwds)) + apply.__doc__ += "\nSee Expression." + phi.__name__ + "() for optional arguments." return apply @@ -110,8 +112,5 @@ class Vector_symbolic_sparse(free_module_element.FreeModuleElement_generic_spars # Add elementwise methods. -for method in ['simplify', 'simplify_factorial', - 'simplify_log', 'simplify_rational', - 'simplify_trig', 'simplify_full', 'trig_expand', - 'canonicalize_radical', 'trig_reduce']: +for method in ['simplify', 'simplify_factorial', 'simplify_log', 'simplify_rational', 'simplify_trig', 'simplify_full', 'trig_expand', 'canonicalize_radical', 'trig_reduce']: setattr(Vector_symbolic_sparse, method, apply_map(getattr(Expression, method))) diff --git a/src/sage/modules/with_basis/all.py b/src/sage/modules/with_basis/all.py index 6bfc5d5f6d1..c35c1ed5495 100644 --- a/src/sage/modules/with_basis/all.py +++ b/src/sage/modules/with_basis/all.py @@ -8,7 +8,9 @@ .. SEEALSO:: The category :class:`ModulesWithBasis` """ + # install the docstring of this module to the containing package from sage.misc.namespace_package import install_doc + install_doc(__package__, __doc__) del install_doc diff --git a/src/sage/modules/with_basis/cell_module.py b/src/sage/modules/with_basis/cell_module.py index 423ad42bf00..80878a3c22c 100644 --- a/src/sage/modules/with_basis/cell_module.py +++ b/src/sage/modules/with_basis/cell_module.py @@ -58,6 +58,7 @@ class CellModule(CombinatorialFreeModule): - :wikipedia:`Cellular_algebra` - http://webusers.imj-prg.fr/~bernhard.keller/ictp2006/lecturenotes/xi.pdf """ + @staticmethod def __classcall_private__(cls, A, mu, **kwds): """ @@ -88,9 +89,7 @@ def __init__(self, A, mu, **kwds): self._algebra = A self._la = mu cat = ModulesWithBasis(A.base_ring()).FiniteDimensional() - CombinatorialFreeModule.__init__(self, A.base_ring(), - A.cell_module_indices(mu), - category=cat, **kwds) + CombinatorialFreeModule.__init__(self, A.base_ring(), A.cell_module_indices(mu), category=cat, **kwds) def _repr_(self): """ @@ -117,6 +116,7 @@ def _latex_(self): W_{...}\left(...\right) """ from sage.misc.latex import latex + return "W_{{{}}}\\left({}\\right)".format(latex(self._algebra), latex(self._la)) def cellular_algebra(self): @@ -209,8 +209,7 @@ def bilinear_form(self, x, y): 8 """ R = self.base_ring() - return R.sum(self._bilinear_form_on_basis(s, t) * cx * cy - for s, cx in x for t, cy in y) + return R.sum(self._bilinear_form_on_basis(s, t) * cx * cy for s, cx in x for t, cy in y) def bilinear_form_matrix(self, ordering=None): """ @@ -236,9 +235,9 @@ def bilinear_form_matrix(self, ordering=None): if sordering != set(self.basis().keys()) or len(sordering) != len(ordering): raise ValueError("not an ordering of the basis indices") from sage.matrix.matrix_space import MatrixSpace + MS = MatrixSpace(self.base_ring(), len(ordering)) - return MS([[self._bilinear_form_on_basis(s, t) for t in ordering] - for s in ordering]) + return MS([[self._bilinear_form_on_basis(s, t) for t in ordering] for s in ordering]) @cached_method def nonzero_bilinear_form(self): @@ -263,8 +262,7 @@ def nonzero_bilinear_form(self): C = list(self.basis().keys()) # Since the bilinear form is symmetric, it is sufficient # to check on the upper triangular part - return any(self._bilinear_form_on_basis(s, t) - for i, s in enumerate(C) for t in C[i:]) + return any(self._bilinear_form_on_basis(s, t) for i, s in enumerate(C) for t in C[i:]) @cached_method def radical_basis(self): @@ -305,9 +303,7 @@ def radical(self): sage: R.basis() Finite family {} """ - radical = self.submodule(self.radical_basis(), - category=self.category().Subobjects(), - already_echelonized=True) + radical = self.submodule(self.radical_basis(), category=self.category().Subobjects(), already_echelonized=True) radical.rename("Radical of {}".format(self)) return radical @@ -382,10 +378,7 @@ def _acted_upon_(self, scalar, self_on_left=False): # scalar = scalar.cellular_involution() mc = self._monomial_coefficients scalar_mc = scalar.monomial_coefficients(copy=False) - D = linear_combination([(P._action_basis(x, k)._monomial_coefficients, - scalar_mc[x] * mc[k]) - for k in mc for x in scalar_mc], - factor_on_left=False) + D = linear_combination([(P._action_basis(x, k)._monomial_coefficients, scalar_mc[x] * mc[k]) for k in mc for x in scalar_mc], factor_on_left=False) return P._from_dict(D, remove_zeros=False) @@ -403,6 +396,7 @@ class SimpleModule(QuotientModuleWithBasis): where `\operatorname{rad}(\lambda)` is the radical of the bilinear form `\Phi_{\lambda}`. """ + def __init__(self, submodule): """ Initialize ``self``. diff --git a/src/sage/modules/with_basis/invariant.py b/src/sage/modules/with_basis/invariant.py index 29aad26c6df..1ce2816efe3 100644 --- a/src/sage/modules/with_basis/invariant.py +++ b/src/sage/modules/with_basis/invariant.py @@ -212,6 +212,7 @@ class FiniteDimensionalInvariantModule(SubmoduleWithBasis): - :arxiv:`0812.3082` - https://www.dmtcs.org/pdfpapers/dmAA0123.pdf """ + def __init__(self, M, S, action=operator.mul, side='left', *args, **kwargs): """ Initialize ``self``. @@ -241,11 +242,15 @@ def __init__(self, M, S, action=operator.mul, side='left', *args, **kwargs): raise ValueError(f"{M} is not a finite dimensional module with a distinguished basis") if side == "left": + def _invariant_map(g, x): return action(g, x) - x + elif side == "right": + def _invariant_map(g, x): return action(x, g) - x + else: raise ValueError("side must either be 'left' or 'right'") @@ -259,12 +264,7 @@ def _invariant_map(g, x): # `s*x = x` for all generators `s` of `S` basis = M.annihilator_basis(S.gens(), action=_invariant_map, side='left') - super().__init__(Family(basis), - support_order=M._compute_support_order(basis), - ambient=M, - unitriangular=False, - category=category, - *args, **kwargs) + super().__init__(Family(basis), support_order=M._compute_support_order(basis), ambient=M, unitriangular=False, category=category, *args, **kwargs) def construction(self): r""" @@ -281,10 +281,8 @@ def construction(self): Left Regular Representation of Cyclic group of order 3 as a permutation group over Integer Ring) """ from sage.categories.pushout import EquivariantSubobjectConstructionFunctor - return (EquivariantSubobjectConstructionFunctor(self._semigroup, - self._action, - self._side), - self.ambient()) + + return (EquivariantSubobjectConstructionFunctor(self._semigroup, self._action, self._side), self.ambient()) def _repr_(self): r""" @@ -325,6 +323,7 @@ def _latex_(self) -> str: if isinstance(self._ambient, Representation): M = M._module from sage.misc.latex import latex + return "\\left( {} \\right)^{{{}}}".format(latex(M), latex(self._semigroup)) def _test_invariant(self, **options): @@ -749,8 +748,7 @@ class FiniteDimensionalTwistedInvariantModule(SubmoduleWithBasis): """ @staticmethod - def __classcall_private__(cls, M, G, chi, - action=operator.mul, side='left', **kwargs): + def __classcall_private__(cls, M, G, chi, action=operator.mul, side='left', **kwargs): r""" TESTS: @@ -825,8 +823,7 @@ def __classcall_private__(cls, M, G, chi, return M.invariant_module(G, action_on_basis=action_on_basis) return M.invariant_module(G, action=action) - return super().__classcall__(cls, M, G, chi, action=operator.mul, - side='left', **kwargs) + return super().__classcall__(cls, M, G, chi, action=operator.mul, side='left', **kwargs) def __init__(self, M, G, chi, action=operator.mul, side='left', **kwargs): r""" @@ -879,21 +876,21 @@ def __init__(self, M, G, chi, action=operator.mul, side='left', **kwargs): # to action should be the group element def __sided_action__(g, x): return action(x, g) + self.__sided_action__ = __sided_action__ else: raise ValueError("side must either be 'left' or 'right'") proj_matrix = Matrix(M.dimension()) # initialize the zero-matrix for g in self._group: - proj_matrix += self._chi(g)*Matrix((self.__sided_action__(g, b)).to_vector() for b in M.basis()) + proj_matrix += self._chi(g) * Matrix((self.__sided_action__(g, b)).to_vector() for b in M.basis()) n = self._chi(self._group.identity()) # chi(1) is the dimension g = self._group.order() - self._projection_matrix = (n/g)*proj_matrix + self._projection_matrix = (n / g) * proj_matrix - self._project_ambient = M.module_morphism(matrix=self._projection_matrix, - codomain=M) + self._project_ambient = M.module_morphism(matrix=self._projection_matrix, codomain=M) category = kwargs.pop("category", M.category().Subobjects()) @@ -903,16 +900,9 @@ def __sided_action__(g, x): def proj_difference(g, x): return self._project_ambient(x) - x - basis = M.annihilator_basis(M.basis(), - action=proj_difference, - side='left') + basis = M.annihilator_basis(M.basis(), action=proj_difference, side='left') - super().__init__(Family(basis), - support_order=M._compute_support_order(basis), - ambient=M, - unitriangular=False, - category=category, - **kwargs) + super().__init__(Family(basis), support_order=M._compute_support_order(basis), ambient=M, unitriangular=False, category=category, **kwargs) def _repr_(self): r""" @@ -1004,8 +994,7 @@ def project_ambient(self, x): sage: G.rename(); M.rename() # reset names """ - if (isinstance(self._ambient, Representation) - and x.parent() is self._ambient._module): + if isinstance(self._ambient, Representation) and x.parent() is self._ambient._module: x = self._ambient._element_constructor_(x) return self._project_ambient(x) diff --git a/src/sage/modules/with_basis/morphism.py b/src/sage/modules/with_basis/morphism.py index 04124d38617..226b91ed522 100644 --- a/src/sage/modules/with_basis/morphism.py +++ b/src/sage/modules/with_basis/morphism.py @@ -113,6 +113,7 @@ from sage.categories.fields import Fields from sage.categories.modules import Modules from sage.misc.call import attrcall + # The identity function would deserve a more canonical location from sage.misc.c3_controlled import identity from sage.categories.commutative_additive_semigroups import CommutativeAdditiveSemigroups @@ -162,6 +163,7 @@ class ModuleMorphism(Morphism): - handles the proper inheritance from categories by updating the class of ``self`` upon construction. """ + def __init__(self, domain, codomain=None, category=None, affine=False): """ Initialization of module morphisms. @@ -193,8 +195,7 @@ def __init__(self, domain, codomain=None, category=None, affine=False): # False # The test below is a bit more restrictive - if (not codomain.base_ring().has_coerce_map_from(base_ring)) \ - and (not codomain.has_coerce_map_from(base_ring)): + if (not codomain.base_ring().has_coerce_map_from(base_ring)) and (not codomain.has_coerce_map_from(base_ring)): raise ValueError("codomain(=%s) should be a module over the base ring of the domain(=%s)" % (codomain, domain)) if affine: @@ -202,11 +203,13 @@ def __init__(self, domain, codomain=None, category=None, affine=False): category = Sets() else: C = Modules(base_ring) - for D in [C.WithBasis().FiniteDimensional(), - C.WithBasis(), - C, - # QQ is not in Modules(QQ)! - CommutativeAdditiveSemigroups()]: + for D in [ + C.WithBasis().FiniteDimensional(), + C.WithBasis(), + C, + # QQ is not in Modules(QQ)! + CommutativeAdditiveSemigroups(), + ]: if codomain in D and domain in D: category = D break @@ -295,8 +298,8 @@ class ModuleMorphismByLinearity(ModuleMorphism): by passing ``None`` as argument, and implementing or setting the attribute ``_on_basis`` """ - def __init__(self, domain, on_basis=None, codomain=None, category=None, - position=0, zero=None): + + def __init__(self, domain, on_basis=None, codomain=None, category=None, position=0, zero=None): """ TESTS:: @@ -319,12 +322,9 @@ def __init__(self, domain, on_basis=None, codomain=None, category=None, if on_basis is not None: self._on_basis = on_basis - self._is_module_with_basis_over_same_base_ring = \ - codomain in ModulesWithBasis(base_ring) and zero == codomain.zero() + self._is_module_with_basis_over_same_base_ring = codomain in ModulesWithBasis(base_ring) and zero == codomain.zero() - ModuleMorphism.__init__(self, domain, codomain, - category=category, - affine=(zero != codomain.zero())) + ModuleMorphism.__init__(self, domain, codomain, category=category, affine=(zero != codomain.zero())) def _richcmp_(self, other, op): r""" @@ -343,11 +343,7 @@ def _richcmp_(self, other, op): (True, False, False, False, False, False) """ if op == op_EQ: - return (self.__class__ is other.__class__ - and self._zero == other._zero - and self._on_basis == other._on_basis - and self._position == other._position - and self._is_module_with_basis_over_same_base_ring == other._is_module_with_basis_over_same_base_ring) + return self.__class__ is other.__class__ and self._zero == other._zero and self._on_basis == other._on_basis and self._position == other._position and self._is_module_with_basis_over_same_base_ring == other._is_module_with_basis_over_same_base_ring if op == op_NE: return not (self == other) return NotImplemented @@ -394,18 +390,15 @@ def __call__(self, *args): Add more tests for multi-parameter module morphisms. """ - before = args[0:self._position] - after = args[self._position + 1:len(args)] + before = args[0 : self._position] + after = args[self._position + 1 : len(args)] x = args[self._position] assert x.parent() is self.domain() mc = x.monomial_coefficients(copy=False) if self._is_module_with_basis_over_same_base_ring: - return self.codomain().linear_combination( - (self._on_basis(*(before + (index,) + after)), coeff) - for (index, coeff) in mc.items()) - return sum((coeff * self._on_basis(*(before + (index,) + after)) - for (index, coeff) in mc.items()), self._zero) + return self.codomain().linear_combination((self._on_basis(*(before + (index,) + after)), coeff) for (index, coeff) in mc.items()) + return sum((coeff * self._on_basis(*(before + (index,) + after)) for (index, coeff) in mc.items()), self._zero) # As per the specs of Map, we should in fact implement _call_. # However we currently need to abuse Map.__call__ (which strict @@ -628,8 +621,8 @@ class TriangularModuleMorphism(ModuleMorphism): sage: [phi.preimage(x[i]) for i in range(1, 4)] [-1/3*B[1] + B[2] - 1/12*B[3], 1/4*B[3], 1/3*B[1] - 1/6*B[3]] """ - def __init__(self, triangular='upper', unitriangular=False, - key=None, inverse=None, inverse_on_support=identity, invertible=None): + + def __init__(self, triangular='upper', unitriangular=False, key=None, inverse=None, inverse_on_support=identity, invertible=None): """ TESTS:: @@ -680,14 +673,11 @@ def __init__(self, triangular='upper', unitriangular=False, self._inverse = inverse if inverse_on_support == "compute": - inverse_on_support = {self._dominant_item(on_basis(i))[0]: i - for i in self.domain().basis().keys() - }.get + inverse_on_support = {self._dominant_item(on_basis(i))[0]: i for i in self.domain().basis().keys()}.get self._inverse_on_support = inverse_on_support - if invertible is None and (domain.basis().keys() == codomain.basis().keys()) and \ - (self._inverse_on_support == identity or domain in Modules.FiniteDimensional): + if invertible is None and (domain.basis().keys() == codomain.basis().keys()) and (self._inverse_on_support == identity or domain in Modules.FiniteDimensional): invertible = True self._invertible = invertible @@ -714,12 +704,7 @@ def _richcmp_(self, other, op): False """ if op == op_EQ: - return (self.__class__ is other.__class__ - and self._triangular == other._triangular - and self._unitriangular == other._unitriangular - and self._inverse_on_support == other._inverse_on_support - and self._invertible == other._invertible - and self._dominant_item == other._dominant_item) + return self.__class__ is other.__class__ and self._triangular == other._triangular and self._unitriangular == other._unitriangular and self._inverse_on_support == other._inverse_on_support and self._invertible == other._invertible and self._dominant_item == other._dominant_item if op == op_NE: return not (self == other) return NotImplemented @@ -761,17 +746,16 @@ def _test_triangular(self, **options): AssertionError: morphism is not unitriangular on 1 """ from sage.misc.lazy_format import LazyFormat + tester = self._tester(**options) on_basis = self.on_basis() for x in self.domain().basis().keys().some_elements(): # is there any better set to use ? bs, co = self._dominant_item(on_basis(x)) if self._unitriangular: - tester.assertEqual(co, self.domain().base_ring().one(), - LazyFormat("morphism is not unitriangular on %s") % x) + tester.assertEqual(co, self.domain().base_ring().one(), LazyFormat("morphism is not unitriangular on %s") % x) xback = self._inverse_on_support(bs) - tester.assertEqual(x, xback, - LazyFormat("morphism is not triangular on %s") % x) + tester.assertEqual(x, xback, LazyFormat("morphism is not triangular on %s") % x) def __invert__(self): """ @@ -849,16 +833,8 @@ def retract_dom(i): self._dominant_item(on_basis(i))[0] if self._invertible: - return self.__class__( - domain=self.codomain(), - on_basis=self._invert_on_basis, - codomain=self.domain(), category=self.category_for(), - unitriangular=self._unitriangular, triangular=self._triangular, - inverse=self, inverse_on_support=retract_dom, - invertible=self._invertible, **self._key_kwds) - return SetMorphism(Hom(self.codomain(), self.domain(), - SetsWithPartialMaps()), - self.preimage) + return self.__class__(domain=self.codomain(), on_basis=self._invert_on_basis, codomain=self.domain(), category=self.category_for(), unitriangular=self._unitriangular, triangular=self._triangular, inverse=self, inverse_on_support=retract_dom, invertible=self._invertible, **self._key_kwds) + return SetMorphism(Hom(self.codomain(), self.domain(), SetsWithPartialMaps()), self.preimage) # This should be removed and optimized as soon as triangular # morphisms not defined by linearity are available @@ -1155,8 +1131,7 @@ def cokernel_projection(self, category=None): """ codomain = self.codomain() category = ModulesWithBasis(codomain.base_ring()).or_subcategory(category) - return codomain.module_morphism(function=self.coreduced, - codomain=codomain, category=category) + return codomain.module_morphism(function=self.coreduced, codomain=codomain, category=category) class TriangularModuleMorphismByLinearity(ModuleMorphismByLinearity, TriangularModuleMorphism): @@ -1172,6 +1147,7 @@ class TriangularModuleMorphismByLinearity(ModuleMorphismByLinearity, TriangularM - :class:`ModuleMorphismByLinearity` and :class:`TriangularModuleMorphism`. """ + def __init__(self, domain, on_basis, codomain=None, category=None, **keywords): r""" TESTS:: @@ -1184,8 +1160,7 @@ def __init__(self, domain, on_basis, codomain=None, category=None, **keywords): ....: X, on_basis=on_basis, codomain=X) sage: TestSuite(phi).run(skip=["_test_nonzero_equal"]) """ - ModuleMorphismByLinearity.__init__(self, on_basis=on_basis, - domain=domain, codomain=codomain, category=category) + ModuleMorphismByLinearity.__init__(self, on_basis=on_basis, domain=domain, codomain=codomain, category=category) TriangularModuleMorphism.__init__(self, **keywords) def _richcmp_(self, other, op): @@ -1203,8 +1178,7 @@ def _richcmp_(self, other, op): True """ if op == op_EQ: - return (ModuleMorphismByLinearity._richcmp_(self, other, op) - and TriangularModuleMorphism._richcmp_(self, other, op)) + return ModuleMorphismByLinearity._richcmp_(self, other, op) and TriangularModuleMorphism._richcmp_(self, other, op) if op == op_NE: return not (self == other) return NotImplemented @@ -1223,6 +1197,7 @@ class TriangularModuleMorphismFromFunction(ModuleMorphismFromFunction, Triangula - :class:`ModuleMorphismFromFunction` and :class:`TriangularModuleMorphism`. """ + def __init__(self, domain, function, codomain=None, category=None, **keywords): r""" TESTS:: @@ -1235,9 +1210,7 @@ def __init__(self, domain, function, codomain=None, category=None, **keywords): ....: X, function=f, codomain=X) sage: TestSuite(phi).run() """ - ModuleMorphismFromFunction.__init__(self, function=function, - domain=domain, codomain=codomain, - category=category) + ModuleMorphismFromFunction.__init__(self, function=function, domain=domain, codomain=codomain, category=category) TriangularModuleMorphism.__init__(self, **keywords) @@ -1299,6 +1272,7 @@ class ModuleMorphismFromMatrix(ModuleMorphismByLinearity): Possibly implement rank, addition, multiplication, matrix, etc, from the stored matrix. """ + def __init__(self, domain, matrix, codomain=None, category=None, side='left'): r""" Initialize ``self``. @@ -1346,23 +1320,19 @@ def __init__(self, domain, matrix, codomain=None, category=None, side='left'): if not isinstance(matrix, Matrix): raise ValueError("matrix (=%s) should be a matrix" % matrix) import sage.combinat.ranker + indices = tuple(domain.basis().keys()) rank_domain = sage.combinat.ranker.rank_from_list(indices) if side == "left": matrix = matrix.transpose() if matrix.nrows() != len(indices): - raise ValueError("The dimension of the matrix (%s) does not match with the dimension of the domain (%s)" - % (matrix.nrows(), len(indices))) + raise ValueError("The dimension of the matrix (%s) does not match with the dimension of the domain (%s)" % (matrix.nrows(), len(indices))) if matrix.ncols() != codomain.dimension(): - raise ValueError("The dimension of the matrix (%s) does not match with the dimension of the codomain (%s)" - % (matrix.ncols(), codomain.dimension())) + raise ValueError("The dimension of the matrix (%s) does not match with the dimension of the codomain (%s)" % (matrix.ncols(), codomain.dimension())) self._matrix = matrix - d = {xt: codomain.from_vector(matrix.row(rank_domain(xt))) - for xt in domain.basis().keys()} + d = {xt: codomain.from_vector(matrix.row(rank_domain(xt))) for xt in domain.basis().keys()} - ModuleMorphismByLinearity.__init__(self, on_basis=d.__getitem__, - domain=domain, codomain=codomain, - category=category) + ModuleMorphismByLinearity.__init__(self, on_basis=d.__getitem__, domain=domain, codomain=codomain, category=category) def _richcmp_(self, other, op): r""" @@ -1387,11 +1357,7 @@ def _richcmp_(self, other, op): """ if op == op_EQ: # We skip the on_basis check since the matrix defines the morphism - return (self.__class__ is other.__class__ - and self._zero == other._zero - and self._position == other._position - and self._is_module_with_basis_over_same_base_ring == other._is_module_with_basis_over_same_base_ring - and self._matrix == other._matrix) + return self.__class__ is other.__class__ and self._zero == other._zero and self._position == other._position and self._is_module_with_basis_over_same_base_ring == other._is_module_with_basis_over_same_base_ring and self._matrix == other._matrix if op == op_NE: return not (self == other) return NotImplemented @@ -1435,6 +1401,7 @@ class DiagonalModuleMorphism(ModuleMorphismByLinearity): sage: phi(x[1]), phi(x[2]), phi(x[3]) (B[1], 2*B[2], 6*B[3]) """ + def __init__(self, domain, diagonal, codomain=None, category=None): r""" Initialize ``self``. @@ -1449,17 +1416,15 @@ def __init__(self, domain, diagonal, codomain=None, category=None): """ if codomain is None: raise ValueError("The codomain should be specified") - if not (domain.basis().keys() == codomain.basis().keys() and - domain.base_ring() == codomain.base_ring()): - raise ValueError("The domain and codomain should have the same base ring " - "and the same basis indexing") + if not (domain.basis().keys() == codomain.basis().keys() and domain.base_ring() == codomain.base_ring()): + raise ValueError("The domain and codomain should have the same base ring " "and the same basis indexing") from collections.abc import Callable + if not isinstance(diagonal, Callable): raise ValueError("diagonal (=%s) should be a function" % diagonal) if category is None: category = ModulesWithBasis(domain.base_ring()) - ModuleMorphismByLinearity.__init__( - self, domain=domain, codomain=codomain, category=category) + ModuleMorphismByLinearity.__init__(self, domain=domain, codomain=codomain, category=category) self._diagonal = diagonal def _richcmp_(self, other, op): @@ -1477,8 +1442,7 @@ def _richcmp_(self, other, op): False """ if op == op_EQ: - return (self.__class__ is other.__class__ - and self._diagonal == other._diagonal) + return self.__class__ is other.__class__ and self._diagonal == other._diagonal if op == op_NE: return not (self == other) return NotImplemented @@ -1517,9 +1481,7 @@ def __invert__(self): condition is *not* tested for, so using an ill defined inverse morphism will trigger arithmetic errors. """ - return self.codomain().module_morphism( - diagonal=pointwise_inverse_function(self._diagonal), - codomain=self.domain(), category=self.category_for()) + return self.codomain().module_morphism(diagonal=pointwise_inverse_function(self._diagonal), codomain=self.domain(), category=self.category_for()) def pointwise_inverse_function(f): @@ -1567,6 +1529,7 @@ class PointwiseInverseFunction(SageObject): sage: f(0), f(1), f(2), f(3) (1, 1, 1/2, 1/6) """ + def __init__(self, f): """ TESTS:: @@ -1593,8 +1556,7 @@ def __eq__(self, other): sage: f == g True """ - return (self.__class__ is other.__class__ - and self._pointwise_inverse == other._pointwise_inverse) + return self.__class__ is other.__class__ and self._pointwise_inverse == other._pointwise_inverse def __ne__(self, other): r""" diff --git a/src/sage/modules/with_basis/representation.py b/src/sage/modules/with_basis/representation.py index e5c534d84f9..e5a12bd4d35 100644 --- a/src/sage/modules/with_basis/representation.py +++ b/src/sage/modules/with_basis/representation.py @@ -44,6 +44,7 @@ class Representation_abstract: This class should come before :class:`CombinatorialFreeModule` in the MRO in order for tensor products to use the correct class. """ + def __init__(self, semigroup, side, algebra=None): """ Initialize ``self``. @@ -78,18 +79,15 @@ def __init__(self, semigroup, side, algebra=None): # No need to do anything if it is already in the MRO if mixin not in self.__class__.__mro__: from sage.structure.dynamic_class import dynamic_class + cat = self.category() # perhaps the category has not been initialized yet if not isinstance(self, cat.parent_class): - self.__class__ = dynamic_class(f"{type(self).__name__}_with_mixin", - (type(self), mixin), - doccls=type(self)) + self.__class__ = dynamic_class(f"{type(self).__name__}_with_mixin", (type(self), mixin), doccls=type(self)) else: base = self.__class__.__base__ # strip off the category dynamic class # recreate the dynamic class with adding the mixin - self.__class__ = dynamic_class(f"{base.__name__}_with_category", - (base, mixin, cat.parent_class), - doccls=base) + self.__class__ = dynamic_class(f"{base.__name__}_with_category", (base, mixin, cat.parent_class), doccls=base) def semigroup(self): """ @@ -237,6 +235,7 @@ def twisted_invariant_module(self, chi, G=None, **kwargs): True """ from sage.categories.groups import Groups + if G is None: G = self.semigroup() elif chi in Groups(): @@ -400,8 +399,7 @@ def character(self): """ G = self._semigroup B = self.basis() - chi = [sum((g * B[k])[k] for k in B.keys()) - for g in G.conjugacy_classes_representatives()] + chi = [sum((g * B[k])[k] for k in B.keys()) for g in G.conjugacy_classes_representatives()] try: return G.character(chi) except AttributeError: @@ -438,11 +436,12 @@ def brauer_character(self): if self.dimension() == 0: from sage.rings.rational_field import QQ - ccrep = [g for g in G.conjugacy_classes_representatives() - if not p.divides(g.order())] + + ccrep = [g for g in G.conjugacy_classes_representatives() if not p.divides(g.order())] return vector(QQ, [QQ.zero()] * len(ccrep)) from sage.rings.number_field.number_field import CyclotomicField + chi = [] for g in G.conjugacy_classes_representatives(): if p.divides(g.order()): @@ -462,8 +461,8 @@ def brauer_character(self): zeta = zetas[o] prim = prims[o] for deg in range(o): - if prim ** deg == la: - val += zeta ** deg + if prim**deg == la: + val += zeta**deg break chi.append(val) @@ -628,7 +627,7 @@ def check_submodule(xi, G): added = matrix([g * vec for g in G for vec in SM.rows()]) SM = SM.stack(added) SM.echelonize() - SM = SM[:SM.rank()] + SM = SM[: SM.rank()] if SM.nrows() < amb_dim: return SM return None @@ -650,18 +649,15 @@ def generate_elements(): continue SM = check_submodule(xi, gens) if SM is not None: - return self.subrepresentation([self.from_vector(v) for v in SM.rows()], - is_closed=True) + return self.subrepresentation([self.from_vector(v) for v in SM.rows()], is_closed=True) SM = check_submodule(xi.transpose(), gens_transpose) if SM is not None: # We instead want the submodule given by the orthogonal complement - return self.subrepresentation([self.from_vector(v) for v in SM.right_kernel_matrix().rows()], - is_closed=True) + return self.subrepresentation([self.from_vector(v) for v in SM.right_kernel_matrix().rows()], is_closed=True) if xi.right_kernel_matrix().nrows() == f.degree(): # good factor return None # irreducible - def subrepresentation(self, gens, check=True, already_echelonized=False, - *args, is_closed=False, **opts): + def subrepresentation(self, gens, check=True, already_echelonized=False, *args, is_closed=False, **opts): """ Construct a subrepresentation of ``self`` generated by ``gens``. @@ -685,24 +681,22 @@ def subrepresentation(self, gens, check=True, already_echelonized=False, 5 """ if not is_closed and gens: - repr_mats = [self.representation_matrix(g) - for g in self._semigroup.gens()] + repr_mats = [self.representation_matrix(g) for g in self._semigroup.gens()] amb_dim = self.dimension() SM = matrix([v._vector_() for v in gens]) SM.echelonize() - SM = SM[:SM.rank()] + SM = SM[: SM.rank()] dim = 0 while dim < SM.nrows() < amb_dim: dim = SM.nrows() added = matrix([g * vec for g in repr_mats for vec in SM.rows()]) SM = SM.stack(added) SM.echelonize() - SM = SM[:SM.rank()] + SM = SM[: SM.rank()] gens = [self.from_vector(v) for v in SM.rows()] # it might not be echelonized w.r.t. the module's basis ordering already_echelonized = False - return self.submodule(gens, *args, submodule_class=Subrepresentation, check=check, - already_echelonized=already_echelonized, **opts) + return self.submodule(gens, *args, submodule_class=Subrepresentation, check=check, already_echelonized=already_echelonized, **opts) def quotient_representation(self, subrepr, already_echelonized=False, **kwds): r""" @@ -721,8 +715,7 @@ def quotient_representation(self, subrepr, already_echelonized=False, **kwds): True """ if not isinstance(subrepr, Subrepresentation): - subrepr = self.subrepresentation(subrepr, unitriangular=True, - already_echelonized=already_echelonized) + subrepr = self.subrepresentation(subrepr, unitriangular=True, already_echelonized=already_echelonized) return QuotientRepresentation(subrepr, **kwds) @cached_method @@ -767,6 +760,7 @@ def _composition_series_data(self): [1, 1, 1, 1, 1, 1] """ from sage.data_structures.blas_dict import linear_combination + series = [self] cur = 0 # The natural condition is ``while cur < len(series)``. However, the @@ -779,12 +773,10 @@ def _composition_series_data(self): if W is None: # V is irreducible break # Construct W as a subrepresentation of ``self`` for consistency - Wp = self.subrepresentation([self(b) for b in W._basis], - already_echelonized=True, is_closed=True) + Wp = self.subrepresentation([self(b) for b in W._basis], already_echelonized=True, is_closed=True) series.append(Wp) else: - W = V.subrepresentation([V.retract(b) for b in series[cur+1]._basis], - already_echelonized=True, is_closed=True) + W = V.subrepresentation([V.retract(b) for b in series[cur + 1]._basis], already_echelonized=True, is_closed=True) Q = V.quotient_representation(W) S = Q.find_subrepresentation() @@ -795,19 +787,16 @@ def _composition_series_data(self): if V is self: S_basis = [self.element_class(self, b._monomial_coefficients) for b in S._basis] else: - S_basis = [self.element_class(self, linear_combination((V._basis[i]._monomial_coefficients, coeff) - for i, coeff in b._monomial_coefficients.items())) - for b in S._basis] + S_basis = [self.element_class(self, linear_combination((V._basis[i]._monomial_coefficients, coeff) for i, coeff in b._monomial_coefficients.items())) for b in S._basis] # Lift the basis of W', which is W as a subrepresentation of ``self`` # This is equivalent to [b.lift() for b in series[cur+1].basis()] - Wp_basis = list(series[cur+1]._basis) + Wp_basis = list(series[cur + 1]._basis) Wp = self.subrepresentation(S_basis + Wp_basis, is_closed=True) - series.insert(cur+1, Wp) + series.insert(cur + 1, Wp) if V is self: W = Wp else: - W = V.subrepresentation([V.retract(b) for b in series[cur+1]._basis], - already_echelonized=True, is_closed=True) + W = V.subrepresentation([V.retract(b) for b in series[cur + 1]._basis], already_echelonized=True, is_closed=True) Q = V.quotient_representation(W) S = Q.find_subrepresentation() @@ -826,25 +815,18 @@ def _composition_series_data(self): lift = prev.lift retract = lift.section() for W in series[2:]: - prev = prev.subrepresentation([retract(b) for b in W._basis], - already_echelonized=True, is_closed=True) + prev = prev.subrepresentation([retract(b) for b in W._basis], already_echelonized=True, is_closed=True) ret.append(prev) # Construct the lift map prev -> self data = {i: lift(prev._basis[i]) for i in prev._basis.keys()} - lift = prev.module_morphism(data.__getitem__, - codomain=self, - triangular='lower', - unitriangular=False, - key=W._support_key, - inverse_on_support='compute') + lift = prev.module_morphism(data.__getitem__, codomain=self, triangular='lower', unitriangular=False, key=W._support_key, inverse_on_support='compute') retract = lift.section() ret.append(ret[-1].subrepresentation([], is_closed=True)) # Construct the simples - simples = [ret[i].quotient_representation(ret[i+1]) - for i in range(len(ret)-2)] + simples = [ret[i].quotient_representation(ret[i + 1]) for i in range(len(ret) - 2)] simples.append(ret[-2]) return (tuple(ret), tuple(simples)) @@ -1011,8 +993,7 @@ def _acted_upon_(self, scalar, self_on_left=False): if sP is P._semigroup_algebra: if not self: return self - return P.linear_combination(((P._semigroup_action(ms, self, self_on_left), cs) - for ms, cs in scalar), not self_on_left) + return P.linear_combination(((P._semigroup_action(ms, self, self_on_left), cs) for ms, cs in scalar), not self_on_left) if P._semigroup.has_coerce_map_from(sP): scalar = P._semigroup(scalar) @@ -1091,6 +1072,7 @@ class Representation(Representation_abstract, CombinatorialFreeModule): - :wikipedia:`Group_representation` """ + def __init__(self, semigroup, module, on_basis, side='left', **kwargs): """ Initialize ``self``. @@ -1158,8 +1140,7 @@ def __init__(self, semigroup, module, on_basis, side='left', **kwargs): if 'FiniteDimensional' in module.category().axioms(): category = category.FiniteDimensional() - CombinatorialFreeModule.__init__(self, module.base_ring(), indices, category=category, - **module.print_options()) + CombinatorialFreeModule.__init__(self, module.base_ring(), indices, category=category, **module.print_options()) Representation_abstract.__init__(self, semigroup, side) def _test_representation(self, **options): @@ -1181,6 +1162,7 @@ def _test_representation(self, **options): sage: R._test_representation(max_runs=500) """ from sage.misc.functional import sqrt + tester = self._tester(**options) S = tester.some_elements() L = [] @@ -1193,9 +1175,9 @@ def _test_representation(self, **options): for y in L: for elt in S: if self._left_repr: - tester.assertEqual(x*(y*elt), (x*y)*elt) + tester.assertEqual(x * (y * elt), (x * y) * elt) else: - tester.assertEqual((elt*y)*x, elt*(y*x)) + tester.assertEqual((elt * y) * x, elt * (y * x)) def _repr_(self): """ @@ -1210,8 +1192,7 @@ def _repr_(self): Representation of Standard permutations of 4 indexed by {'v'} over Rational Field """ - return "Representation of {} indexed by {} over {}".format( - self._semigroup, self.basis().keys(), self.base_ring()) + return "Representation of {} indexed by {} over {}".format(self._semigroup, self.basis().keys(), self.base_ring()) def _repr_term(self, b): """ @@ -1316,8 +1297,7 @@ def _semigroup_action(self, g, vec, vec_on_left): """ if self._left_repr == vec_on_left: g = ~g - return self.linear_combination(((self._on_basis(g, m), c) - for m, c in vec._monomial_coefficients.items()), not vec_on_left) + return self.linear_combination(((self._on_basis(g, m), c) for m, c in vec._monomial_coefficients.items()), not vec_on_left) class Subrepresentation(Representation_abstract, SubmoduleWithBasis): @@ -1328,6 +1308,7 @@ class Subrepresentation(Representation_abstract, SubmoduleWithBasis): subrepresentation is a submodule of `R` that is closed under the action of `X`. """ + # Use the same normalization as the base class __classcall_private__ = SubmoduleWithBasis.__classcall_private__ @@ -1405,6 +1386,7 @@ class QuotientRepresentation(Representation_abstract, QuotientModuleWithBasis): The quotient of a representation by another representation, which admits a natural structure of a representation. """ + # Use the same normalization as the base class __classcall_private__ = QuotientModuleWithBasis.__classcall_private__ @@ -1448,6 +1430,7 @@ class Representation_Tensor(Representation_abstract, CombinatorialFreeModule_Ten r""" Tensor product of representations. """ + @staticmethod def __classcall_private__(cls, reps, **options): r""" @@ -1478,8 +1461,7 @@ def __classcall_private__(cls, reps, **options): assert len(reps) > 0 assert isinstance(reps[0], Representation_abstract) S = reps[0].semigroup() - if not all(isinstance(module, Representation_abstract) - and module.semigroup() == S for module in reps): + if not all(isinstance(module, Representation_abstract) and module.semigroup() == S for module in reps): return CombinatorialFreeModule_Tensor(reps, **options) R = reps[0].base_ring() if not all(module in Modules(R).WithBasis() for module in reps): @@ -1508,7 +1490,7 @@ def __init__(self, reps, **options): else: if len(sides) == 2: # mix of one side and twosided sides.remove("twosided") - side, = sides # get the unique side remaining + (side,) = sides # get the unique side remaining CombinatorialFreeModule_Tensor.__init__(self, reps, **options) Representation_abstract.__init__(self, reps[0].semigroup(), side) @@ -1534,10 +1516,8 @@ def _semigroup_action(self, g, vec, vec_on_left): """ bases = [M.basis() for M in self._sets] if vec_on_left: - return self.linear_combination((self._tensor_of_elements([B[k] * g for B, k in zip(bases, b)]), c) - for b, c in vec._monomial_coefficients.items()) - return self.linear_combination((self._tensor_of_elements([g * B[k] for B, k in zip(bases, b)]), c) - for b, c in vec._monomial_coefficients.items()) + return self.linear_combination((self._tensor_of_elements([B[k] * g for B, k in zip(bases, b)]), c) for b, c in vec._monomial_coefficients.items()) + return self.linear_combination((self._tensor_of_elements([g * B[k] for B, k in zip(bases, b)]), c) for b, c in vec._monomial_coefficients.items()) class Element(Representation_abstract.Element): pass @@ -1550,6 +1530,7 @@ class Representation_Exterior(Representation_abstract, CombinatorialFreeModule): r""" The exterior power representation (in a fixed degree). """ + def __init__(self, rep, degree=None, category=None, **options): r""" Initialize ``self``. @@ -1584,6 +1565,7 @@ def __init__(self, rep, degree=None, category=None, **options): from sage.algebras.clifford_algebra import ExteriorAlgebra from sage.algebras.clifford_algebra import CliffordAlgebraIndices from sage.rings.integer_ring import ZZ + self._degree = degree self._rep = rep R = rep.base_ring() @@ -1633,6 +1615,7 @@ def _latex_(self): \bigwedge ... """ from sage.misc.latex import latex + if self._degree is None: return "\\bigwedge " + latex(self._rep) return "\\bigwedge^{{{}}} ".format(self._degree) + latex(self._rep) @@ -1670,6 +1653,7 @@ def _ascii_art_term(self, m): 2*()/\(5,6,7) + 2*()/\(5,7,6) + 3*()/\(1,2)(3,4) """ from sage.typeset.ascii_art import ascii_art + if len(m) == 0: return ascii_art('1') wedge = '/\\' @@ -1691,9 +1675,11 @@ def _unicode_art_term(self, m): 2*()∧(5,6,7) + 2*()∧(5,7,6) + 3*()∧(1,2)(3,4) """ from sage.typeset.unicode_art import unicode_art + if len(m) == 0: return unicode_art('1') import unicodedata + wedge = unicodedata.lookup('LOGICAL AND') B = self._rep.basis() return unicode_art(*[B[self._basis_order[i]] for i in m], sep=wedge) @@ -1714,6 +1700,7 @@ def _latex_term(self, m): if len(m) == 0: return '1' from sage.misc.latex import latex + B = self._rep.basis() return " \\wedge ".join(latex(B[self._basis_order[i]]) for i in m) @@ -1755,8 +1742,7 @@ def _semigroup_action(self, g, vec, vec_on_left): -2*(1,3,2,4)(6,7)*(1,3,2,4)(5,6) + 2*(1,3,2,4)(5,6)*(1,3,2,4)(5,7) - 3*(1,4,2,3)(5,6)*(1,3,2,4)(5,6) """ - return self.linear_combination(((self._action_on_basis(g, b, vec_on_left), c) - for b, c in vec._monomial_coefficients.items()), not vec_on_left) + return self.linear_combination(((self._action_on_basis(g, b, vec_on_left), c) for b, c in vec._monomial_coefficients.items()), not vec_on_left) def _action_on_basis(self, g, b, vec_on_left): r""" @@ -1784,11 +1770,9 @@ def _action_on_basis(self, g, b, vec_on_left): """ B = self._rep.basis() if vec_on_left: - temp = self._extalg.prod(self._from_repr_to_ext(B[self._basis_order[bk]] * g) - for bk in b) + temp = self._extalg.prod(self._from_repr_to_ext(B[self._basis_order[bk]] * g) for bk in b) else: - temp = self._extalg.prod(self._from_repr_to_ext(g * B[self._basis_order[bk]]) - for bk in b) + temp = self._extalg.prod(self._from_repr_to_ext(g * B[self._basis_order[bk]]) for bk in b) return self.element_class(self, temp._monomial_coefficients) @@ -1796,6 +1780,7 @@ class Representation_ExteriorAlgebra(Representation_Exterior): r""" The exterior algebra representation. """ + def __init__(self, rep, degree=None, category=None, **options): r""" Initialize ``self``. @@ -1818,6 +1803,7 @@ def __init__(self, rep, degree=None, category=None, **options): """ R = rep.base_ring() from sage.categories.algebras_with_basis import AlgebrasWithBasis + category = AlgebrasWithBasis(R).or_subcategory(category) Representation_Exterior.__init__(self, rep, degree=degree, category=category, **options) @@ -1863,6 +1849,7 @@ class Representation_Symmetric(Representation_abstract, CombinatorialFreeModule) r""" The symmetric power representation in a fixed degree. """ + def __init__(self, rep, degree, **options): r""" Initialize ``self``. @@ -1888,6 +1875,7 @@ def __init__(self, rep, degree, **options): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.combinat.integer_vector import IntegerVectors from sage.rings.integer_ring import ZZ + self._degree = degree self._rep = rep R = rep.base_ring() @@ -1929,6 +1917,7 @@ def _latex_(self): S^{4} ... """ from sage.misc.latex import latex + return "S^{{{}}} {}".format(self._degree, latex(self._rep)) def _repr_term(self, m): @@ -1953,8 +1942,7 @@ def _repr_term(self, m): if not self._degree: return '1' B = self._rep.basis() - return '*'.join(repr(B[self._basis_order[i]]) if e == 1 else repr(B[self._basis_order[i]]) + f'^{e}' - for i,e in enumerate(m) if e) + return '*'.join(repr(B[self._basis_order[i]]) if e == 1 else repr(B[self._basis_order[i]]) + f'^{e}' for i, e in enumerate(m) if e) def _ascii_art_term(self, m): r""" @@ -1975,6 +1963,7 @@ def _ascii_art_term(self, m): 2*1 """ from sage.typeset.ascii_art import ascii_art + if not self._degree: return ascii_art('1') B = self._rep.basis() @@ -2009,6 +1998,7 @@ def _unicode_art_term(self, m): 2*1 """ from sage.typeset.unicode_art import unicode_art + if not self._degree: return unicode_art('1') B = self._rep.basis() @@ -2044,9 +2034,9 @@ def _latex_term(self, m): if not self._degree: return '1' from sage.misc.latex import latex + B = self._rep.basis() - return " ".join(latex(B[self._basis_order[i]]) if e == 1 else latex(B[self._basis_order[i]]) + f"^{{{e}}}" - for i, e in enumerate(m) if e) + return " ".join(latex(B[self._basis_order[i]]) if e == 1 else latex(B[self._basis_order[i]]) + f"^{{{e}}}" for i, e in enumerate(m) if e) def _from_repr_to_sym(self, elt): r""" @@ -2061,8 +2051,7 @@ def _from_repr_to_sym(self, elt): sage: S3L._from_repr_to_sym(sum(i*b for i,b in enumerate(L.basis(), start=1))) e0 + 2*e1 + 3*e2 + 4*e3 + 5*e4 + 6*e5 """ - return self._symalg.sum(c * self._inv_map[k] - for k, c in elt._monomial_coefficients.items()) + return self._symalg.sum(c * self._inv_map[k] for k, c in elt._monomial_coefficients.items()) def _semigroup_action(self, g, vec, vec_on_left): r""" @@ -2085,8 +2074,7 @@ def _semigroup_action(self, g, vec, vec_on_left): 3*(1,3,2,4)(5,6)*(1,3,2,4)(5,7) + 2*(1,3,2,4)(5,6)^2 + 2*(1,3,2,4)(6,7)*(1,3,2,4)(5,6) """ - return self.linear_combination(((self._action_on_basis(g, b, vec_on_left), c) - for b, c in vec._monomial_coefficients.items()), not vec_on_left) + return self.linear_combination(((self._action_on_basis(g, b, vec_on_left), c) for b, c in vec._monomial_coefficients.items()), not vec_on_left) def _action_on_basis(self, g, b, vec_on_left): r""" @@ -2114,11 +2102,9 @@ def _action_on_basis(self, g, b, vec_on_left): """ B = self._rep.basis() if vec_on_left: - temp = self._symalg.prod(self._from_repr_to_sym(B[self._basis_order[bk]] * g) ** e - for bk, e in enumerate(b)) + temp = self._symalg.prod(self._from_repr_to_sym(B[self._basis_order[bk]] * g) ** e for bk, e in enumerate(b)) else: - temp = self._symalg.prod(self._from_repr_to_sym(g * B[self._basis_order[bk]]) ** e - for bk, e in enumerate(b)) + temp = self._symalg.prod(self._from_repr_to_sym(g * B[self._basis_order[bk]]) ** e for bk, e in enumerate(b)) ind = self._indices data = {ind(mon.exponents()[0]): c for c, mon in temp} return self.element_class(self, data) @@ -2144,6 +2130,7 @@ class RegularRepresentation(Representation): - :wikipedia:`Regular_representation` """ + def __init__(self, semigroup, base_ring, side='left'): """ Initialize ``self``. @@ -2225,6 +2212,7 @@ class TrivialRepresentation(Representation_abstract, CombinatorialFreeModule): - :wikipedia:`Trivial_representation` """ + def __init__(self, semigroup, base_ring): """ Initialize ``self``. @@ -2237,6 +2225,7 @@ def __init__(self, semigroup, base_ring): """ cat = Modules(base_ring).WithBasis().FiniteDimensional() from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + indices = FiniteEnumeratedSet(['v']) CombinatorialFreeModule.__init__(self, base_ring, indices, category=cat) Representation_abstract.__init__(self, semigroup, "twosided") @@ -2252,8 +2241,7 @@ def _repr_(self): Trivial representation of Dihedral group of order 8 as a permutation group over Integer Ring """ - return "Trivial representation of {} over {}".format(self._semigroup, - self.base_ring()) + return "Trivial representation of {} over {}".format(self._semigroup, self.base_ring()) def _semigroup_action(self, g, vec, vec_on_left): r""" @@ -2344,6 +2332,7 @@ class SignRepresentation_abstract(Representation_abstract, CombinatorialFreeModu - :wikipedia:`Representation_theory_of_the_symmetric_group` """ + def __init__(self, group, base_ring, sign_function=None): """ Initialize ``self``. @@ -2377,9 +2366,7 @@ def _repr_(self): Sign representation of Dihedral group of order 8 as a permutation group over Integer Ring """ - return "Sign representation of {} over {}".format( - self._semigroup, self.base_ring() - ) + return "Sign representation of {} over {}".format(self._semigroup, self.base_ring()) def _semigroup_action(self, g, vec, vec_on_left): r""" @@ -2451,6 +2438,7 @@ class SignRepresentationPermgroup(SignRepresentation_abstract): sage: V = G.sign_representation() sage: TestSuite(V).run() """ + def _default_sign(self, elem): """ Return the sign of the element. @@ -2482,6 +2470,7 @@ class SignRepresentationMatrixGroup(SignRepresentation_abstract): sage: V = G.sign_representation() sage: TestSuite(V).run() """ + def _default_sign(self, elem): """ Return the sign of the element. @@ -2519,6 +2508,7 @@ class SignRepresentationCoxeterGroup(SignRepresentation_abstract): sage: S = W.sign_representation() sage: TestSuite(S).run() """ + def _default_sign(self, elem): """ Return the sign of the element. @@ -2558,6 +2548,7 @@ class ReflectionRepresentation(Representation_abstract, CombinatorialFreeModule) sage: all(g.matrix() == R.representation_matrix(g) for g in W) True """ + @staticmethod def __classcall_private__(cls, W, base_ring=None): r""" @@ -2592,6 +2583,7 @@ def __init__(self, W, base_ring): self._W = W rk = W.coxeter_matrix().rank() from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + indices = FiniteEnumeratedSet(range(rk)) CombinatorialFreeModule.__init__(self, base_ring, indices, prefix='e', bracket=False) Representation_abstract.__init__(self, W, "left") @@ -2653,6 +2645,7 @@ class NaturalMatrixRepresentation(Representation): - ``base_ring`` -- (optional) the base ring; the default is the base ring of the semigroup """ + @staticmethod def __classcall_private__(cls, semigroup, base_ring=None): r""" @@ -2713,6 +2706,7 @@ def _latex_(self): \Bold{F}_{2} ^{3} """ from sage.misc.latex import latex + return latex(self.base_ring()) + "^{{{}}}".format(self.dimension()) def _semigroup_action(self, g, vec, vec_on_left): @@ -2830,6 +2824,7 @@ class SchurFunctorRepresentation(Subrepresentation): sage: g * v 3*S[0] + (-2*a+5)*S[2] + 3*a*S[4] - (5*a-2)*S[6] - 6*S[7] """ + @staticmethod def __classcall_private__(cls, V, shape): r""" @@ -2846,6 +2841,7 @@ def __classcall_private__(cls, V, shape): True """ from sage.combinat.partition import _Partitions + return super().__classcall__(cls, V, _Partitions(shape)) def __init__(self, V, shape): @@ -2889,14 +2885,13 @@ def __init__(self, V, shape): else: keys = list(V.basis().keys()) - ambient = tensor([V]*d) + ambient = tensor([V] * d) cla = SymmetricGroupAlgebra(R, SymmetricGroup(d)).young_symmetrizer(shape) mc = cla.monomial_coefficients(copy=False) - gens = [ambient.sum_of_terms((tuple([k[i-1] for i in p.tuple()]), coeff) - for p, coeff in mc.items()) - for k in ambient.basis().keys()] + gens = [ambient.sum_of_terms((tuple([k[i - 1] for i in p.tuple()]), coeff) for p, coeff in mc.items()) for k in ambient.basis().keys()] support_order = ambient._compute_support_order(gens, None) from sage.sets.family import Family + gens = Family(ambient.echelon_form(gens, order=support_order)) cat = Modules(ambient.category().base_ring()).WithBasis().Subobjects() Subrepresentation.__init__(self, gens, support_order, ambient, unitriangular=False, category=cat, prefix='S') @@ -2932,6 +2927,7 @@ def _latex_(self): }}(\Bold{F}_{2} ^{4}) """ from sage.misc.latex import latex + return "\\mathbb{{S}}_{{{}}}({})".format(latex(self._shape), latex(self._module)) Element = Subrepresentation.Element diff --git a/src/sage/modules/with_basis/subquotient.py b/src/sage/modules/with_basis/subquotient.py index ab9d1f6a881..d2d9554a642 100644 --- a/src/sage/modules/with_basis/subquotient.py +++ b/src/sage/modules/with_basis/subquotient.py @@ -1,6 +1,7 @@ r""" Quotients of modules with basis """ + # **************************************************************************** # Copyright (C) 2010-2015 Florent Hivert # @@ -63,6 +64,7 @@ class QuotientModuleWithBasis(CombinatorialFreeModule): - :class:`SubmoduleWithBasis` - :class:`sage.rings.quotient_ring.QuotientRing` """ + @staticmethod def __classcall_private__(cls, submodule, category=None): r""" @@ -105,9 +107,7 @@ def __init__(self, submodule, category, *args, **opts): self._ambient = submodule.ambient() embedding = submodule.lift indices = embedding.cokernel_basis_indices() - CombinatorialFreeModule.__init__(self, - submodule.base_ring(), indices, - category=category, *args, **opts) + CombinatorialFreeModule.__init__(self, submodule.base_ring(), indices, category=category, *args, **opts) def ambient(self): r""" @@ -194,9 +194,9 @@ class SubmoduleWithBasis(CombinatorialFreeModule): - :meth:`Modules.WithBasis.ParentMethods.submodule` - :class:`QuotientModuleWithBasis` """ + @staticmethod - def __classcall_private__(cls, basis, support_order, ambient=None, - unitriangular=False, category=None, *args, **opts): + def __classcall_private__(cls, basis, support_order, ambient=None, unitriangular=False, category=None, *args, **opts): r""" Normalize the input. @@ -219,12 +219,9 @@ def __classcall_private__(cls, basis, support_order, ambient=None, if category is None and ambient.category().is_subcategory(Mod.Filtered()): default_category = default_category.Filtered() category = default_category.or_subcategory(category, join=True) - return super().__classcall__(cls, basis, tuple(support_order), - ambient, unitriangular, category, - *args, **opts) + return super().__classcall__(cls, basis, tuple(support_order), ambient, unitriangular, category, *args, **opts) - def __init__(self, basis, support_order, ambient, unitriangular, category, - *args, **opts): + def __init__(self, basis, support_order, ambient, unitriangular, category, *args, **opts): r""" Initialization. @@ -242,9 +239,7 @@ def __init__(self, basis, support_order, ambient, unitriangular, category, sage: TestSuite(Y).run() """ ring = ambient.base_ring() - CombinatorialFreeModule.__init__(self, ring, basis.keys(), - category=category.Subobjects(), - *args, **opts) + CombinatorialFreeModule.__init__(self, ring, basis.keys(), category=category.Subobjects(), *args, **opts) self._ambient = ambient self._basis = basis self._unitriangular = unitriangular @@ -298,12 +293,7 @@ def lift(self): sage: (y[0] + y[1]).lift() x[0] - x[2] """ - return self.module_morphism(self.lift_on_basis, - codomain=self._ambient, - triangular='lower', - unitriangular=self._unitriangular, - key=self._support_key, - inverse_on_support='compute') + return self.module_morphism(self.lift_on_basis, codomain=self._ambient, triangular='lower', unitriangular=self._unitriangular, key=self._support_key, inverse_on_support='compute') @lazy_attribute def reduce(self): @@ -477,6 +467,7 @@ def _common_submodules(self, other): [ 0 0 1 -1]) """ from sage.modules.free_module import FreeModule + supp_order = self._support_order A = FreeModule(self.base_ring(), len(supp_order)) U = A.submodule([A([vec[supp] for supp in supp_order]) for vec in self._basis], check=False) @@ -648,8 +639,7 @@ def __and__(self, other): UV = U & V # the intersection A = self._ambient supp = self._support_order - return A.submodule([A.element_class(A, {supp[i]: c for i, c in vec.items()}) - for vec in UV.basis()]) + return A.submodule([A.element_class(A, {supp[i]: c for i, c in vec.items()}) for vec in UV.basis()]) intersection = __and__ __rand__ = __and__ diff --git a/src/sage/monoids/all.py b/src/sage/monoids/all.py index 7b4543dd34c..51aa6951828 100644 --- a/src/sage/monoids/all.py +++ b/src/sage/monoids/all.py @@ -1,12 +1,6 @@ - from sage.monoids.free_monoid import FreeMonoid -from sage.monoids.string_monoid import (BinaryStrings, OctalStrings, HexadecimalStrings, - Radix64Strings, AlphabeticStrings) +from sage.monoids.string_monoid import BinaryStrings, OctalStrings, HexadecimalStrings, Radix64Strings, AlphabeticStrings from sage.monoids.free_abelian_monoid import FreeAbelianMonoid -from sage.monoids.string_ops import ( - strip_encoding, - frequency_distribution, - coincidence_index, - coincidence_discriminant) +from sage.monoids.string_ops import strip_encoding, frequency_distribution, coincidence_index, coincidence_discriminant diff --git a/src/sage/monoids/automatic_semigroup.py b/src/sage/monoids/automatic_semigroup.py index 7bd5c8555fa..43ebaea5ca9 100644 --- a/src/sage/monoids/automatic_semigroup.py +++ b/src/sage/monoids/automatic_semigroup.py @@ -8,6 +8,7 @@ - Nicolas M. Thiéry - Aladin Virmaux """ + # **************************************************************************** # Copyright (C) 2010-2015 Nicolas M. Thiéry # @@ -256,6 +257,7 @@ class AutomaticSemigroup(UniqueRepresentation, Parent): 2 sage: M.retract(3) # not tested: runs forever trying to find 3 """ + @staticmethod def __classcall_private__(cls, generators, ambient=None, one=None, mul=operator.mul, category=None): """ @@ -346,8 +348,7 @@ def __classcall_private__(cls, generators, ambient=None, one=None, mul=operator. category = default_category else: category = default_category & category - return super().__classcall__(cls, generators, ambient=ambient, - one=one, mul=mul, category=category) + return super().__classcall__(cls, generators, ambient=ambient, one=one, mul=mul, category=category) def __init__(self, generators, ambient, one, mul, category): """ @@ -586,6 +587,7 @@ def semigroup_generators(self): Finite family {1: 3, 2: 5} """ return self._generators + gens = semigroup_generators def __init__iter(self): @@ -1047,4 +1049,5 @@ def monoid_generators(self): Family (1, 3, 5) """ return self._generators + gens = monoid_generators diff --git a/src/sage/monoids/free_abelian_monoid.py b/src/sage/monoids/free_abelian_monoid.py index d1fa5bff1b8..d240ebd18e2 100644 --- a/src/sage/monoids/free_abelian_monoid.py +++ b/src/sage/monoids/free_abelian_monoid.py @@ -44,6 +44,7 @@ sage: x.list() [7, 2, 0, 1, 1] """ + # **************************************************************************** # Copyright (C) 2005 David Kohel # @@ -96,6 +97,7 @@ class FreeAbelianMonoidFactory(UniqueFactory): sage: loads(dumps(F)) is F True """ + def create_key(self, n, names): n = int(n) names = normalize_names(n, names) @@ -149,6 +151,7 @@ def FreeAbelianMonoid(index_set=None, names=None, **kwds): if names is not None: names = normalize_names(len(names), names) from sage.monoids.indexed_free_monoid import IndexedFreeAbelianMonoid + return IndexedFreeAbelianMonoid(index_set, names=names, **kwds) if names is None: @@ -160,6 +163,7 @@ class FreeAbelianMonoid_class(Parent): """ Free abelian monoid on `n` generators. """ + Element = FreeAbelianMonoidElement def __init__(self, n, names) -> None: @@ -283,6 +287,8 @@ def cardinality(self): """ if self.__ngens == 0: from sage.rings.integer_ring import ZZ + return ZZ.one() from sage.rings.infinity import infinity + return infinity diff --git a/src/sage/monoids/free_monoid.py b/src/sage/monoids/free_monoid.py index 41104a9fa49..4cf41054c5e 100644 --- a/src/sage/monoids/free_monoid.py +++ b/src/sage/monoids/free_monoid.py @@ -14,6 +14,7 @@ the optional ``names`` argument to the ``FreeMonoid`` function. """ + # **************************************************************************** # Copyright (C) 2005 David Kohel # @@ -78,9 +79,9 @@ class FreeMonoid(Monoid_class, UniqueRepresentation): sage: FreeMonoid(index_set=ZZ, commutative=True) Free abelian monoid indexed by Integer Ring """ + @staticmethod - def __classcall_private__(cls, index_set=None, names=None, - commutative=False, **kwds): + def __classcall_private__(cls, index_set=None, names=None, commutative=False, **kwds): r""" Construct a free monoid or a free abelian monoid, depending on the input. Also, normalize the input. @@ -116,6 +117,7 @@ def __classcall_private__(cls, index_set=None, names=None, if commutative: from sage.monoids.free_abelian_monoid import FreeAbelianMonoid + return FreeAbelianMonoid(index_set, names, **kwds) # Swap args (this works if names is None as well) @@ -132,6 +134,7 @@ def __classcall_private__(cls, index_set=None, names=None, if names is not None: names = normalize_names(-1, names) from sage.monoids.indexed_free_monoid import IndexedFreeMonoid + return IndexedFreeMonoid(index_set, names=names, **kwds) if names is None: @@ -222,11 +225,8 @@ def _element_constructor_(self, x, check=True): return x if P == self: return self.element_class(self, x._element_list, check) - if all(v in self.variable_names() - for v in P.variable_names()): - reindex = [next(j for j, w in enumerate(self.variable_names()) - if v == w) - for v in P.variable_names()] + if all(v in self.variable_names() for v in P.variable_names()): + reindex = [next(j for j, w in enumerate(self.variable_names()) if v == w) for v in P.variable_names()] elt = [(reindex[i], exp) for i, exp in x._element_list] return self.element_class(self, elt, check) if isinstance(x, (int, Integer)) and x == 1: @@ -299,4 +299,5 @@ def cardinality(self): if self.__ngens == 0: return ZZ.one() from sage.rings.infinity import infinity + return infinity diff --git a/src/sage/monoids/free_monoid_element.py b/src/sage/monoids/free_monoid_element.py index eb425cdfda4..6e0e14fddac 100644 --- a/src/sage/monoids/free_monoid_element.py +++ b/src/sage/monoids/free_monoid_element.py @@ -47,6 +47,7 @@ class FreeMonoidElement(MonoidElement): ... NotImplementedError """ + def __init__(self, F, x, check=True) -> None: """ Create the element `x` of the FreeMonoid `F`. @@ -65,11 +66,10 @@ def __init__(self, F, x, check=True) -> None: for v in x: if not (isinstance(v, tuple) and len(v) == 2): raise TypeError("x (= %s) must be a list of 2-tuples or 1" % x) - if not (isinstance(v[0], (int, Integer)) and - isinstance(v[1], (int, Integer))): + if not (isinstance(v[0], (int, Integer)) and isinstance(v[1], (int, Integer))): raise TypeError("x (= %s) must be a list of 2-tuples of integers or 1" % x) - if len(x2) > 0 and v[0] == x2[len(x2)-1][0]: - x2[len(x2)-1] = (v[0], v[1]+x2[len(x2)-1][1]) + if len(x2) > 0 and v[0] == x2[len(x2) - 1][0]: + x2[len(x2) - 1] = (v[0], v[1] + x2[len(x2) - 1][1]) else: x2.append(v) self._element_list = x2 @@ -105,8 +105,7 @@ def __iter__(self): [(a0, 1), (a1, 1), (a4, 3), (a0, 1)] """ gens = self.parent().gens() - return ((gens[index], exponent) - for (index, exponent) in self._element_list) + return ((gens[index], exponent) for (index, exponent) in self._element_list) def _repr_(self): s = "" @@ -243,7 +242,7 @@ def __call__(self, *x, **kwds): for var_index, exponent in self._element_list: replacement = x[var_index] if exponent > 1: - result *= replacement ** exponent + result *= replacement**exponent elif exponent == 1: result *= replacement return result @@ -270,11 +269,11 @@ def _mul_(self, y): elif not y_elt: z._element_list = x_elt else: - k = len(x_elt)-1 + k = len(x_elt) - 1 if x_elt[k][0] != y_elt[0][0]: z._element_list = x_elt + y_elt else: - m = (y_elt[0][0], x_elt[k][1]+y_elt[0][1]) + m = (y_elt[0][0], x_elt[k][1] + y_elt[0][1]) z._element_list = x_elt[:k] + [m] + y_elt[1:] return z @@ -379,6 +378,7 @@ def to_word(self, alph=None): :meth:`to_list` """ from sage.combinat.words.finite_word import Words + gens = self.parent().gens() if alph is None: alph = gens diff --git a/src/sage/monoids/indexed_free_monoid.py b/src/sage/monoids/indexed_free_monoid.py index 3d574d2670f..373adf4c4e3 100644 --- a/src/sage/monoids/indexed_free_monoid.py +++ b/src/sage/monoids/indexed_free_monoid.py @@ -49,6 +49,7 @@ class IndexedMonoidElement(MonoidElement): the result of :meth:`_sorted_items` (which for abelian free monoids is influenced by the order on the indexing set). """ + def __init__(self, F, x) -> None: """ Create the element ``x`` of an indexed free abelian monoid ``F``. @@ -111,9 +112,7 @@ def _repr_(self) -> str: scalar_mult = P._print_options['scalar_mult'] - return scalar_mult.join(P._repr_generator(g) - + (f'^{v}' if v != 1 else '') - for g, v in monomial) + return scalar_mult.join(P._repr_generator(g) + (f'^{v}' if v != 1 else '') for g, v in monomial) def _ascii_art_(self): r""" @@ -141,19 +140,22 @@ def _ascii_art_(self): scalar_mult = P._print_options['scalar_mult'] if all(x[1] == 1 for x in monomial): + def ascii_art_gen(m): return P._ascii_art_generator(m[0]) + else: pref = AsciiArt([P.prefix()]) def ascii_art_gen(m): if m[1] != 1: - r = (AsciiArt([" " * len(pref)]) + ascii_art(m[1])) + r = AsciiArt([" " * len(pref)]) + ascii_art(m[1]) else: r = empty_ascii_art r = r * P._ascii_art_generator(m[0]) r._baseline = r._h - 2 return r + b = ascii_art_gen(monomial[0]) for x in monomial[1:]: b = b + AsciiArt([scalar_mult]) + ascii_art_gen(x) @@ -182,9 +184,7 @@ def _latex_(self) -> str: if scalar_mult == "*": scalar_mult = " " - return scalar_mult.join(P._latex_generator(g) - + (f'^{{{v}}}' if v != 1 else '') - for g, v in monomial) + return scalar_mult.join(P._latex_generator(g) + (f'^{{{v}}}' if v != 1 else '') for g, v in monomial) def __iter__(self): """ @@ -204,8 +204,7 @@ def __iter__(self): sage: list(b*c^3*a) [(F[0], 1), (F[1], 1), (F[2], 3)] """ - return ((self.parent().gen(index), exp) - for (index, exp) in self._sorted_items()) + return ((self.parent().gen(index), exp) for (index, exp) in self._sorted_items()) def _richcmp_(self, other, op) -> bool: r""" @@ -293,8 +292,7 @@ def support(self) -> list: """ supp = {key for key, exp in self._sorted_items() if exp} try: - return sorted(supp, key=print_options['sorting_key'], - reverse=print_options['sorting_reverse']) + return sorted(supp, key=print_options['sorting_key'], reverse=print_options['sorting_reverse']) except Exception: # Sorting the output is a plus, but if we can't, no big deal return list(supp) @@ -392,6 +390,7 @@ class IndexedFreeMonoidElement(IndexedMonoidElement): """ An element of an indexed free abelian monoid. """ + def __init__(self, F, x) -> None: """ Create the element ``x`` of an indexed free abelian monoid ``F``. @@ -490,6 +489,7 @@ class IndexedFreeAbelianMonoidElement(IndexedMonoidElement): """ An element of an indexed free abelian monoid. """ + def __init__(self, F, x) -> None: """ Create the element ``x`` of an indexed free abelian monoid ``F``. @@ -529,8 +529,7 @@ def _sorted_items(self): print_options = self.parent().print_options() v = list(self._monomial.items()) try: - v.sort(key=print_options['sorting_key'], - reverse=print_options['sorting_reverse']) + v.sort(key=print_options['sorting_key'], reverse=print_options['sorting_reverse']) except Exception: # Sorting the output is a plus, but if we can't, no big deal pass return v @@ -558,8 +557,7 @@ def _mul_(self, other): sage: a*b^2*e*d F[0]*F[1]^2*F[3]*F[4] """ - return self.__class__(self.parent(), - blas.add(self._monomial, other._monomial)) + return self.__class__(self.parent(), blas.add(self._monomial, other._monomial)) def __pow__(self, n): """ @@ -584,8 +582,7 @@ def __pow__(self, n): return self if n == 0: return self.parent().one() - return self.__class__(self.parent(), - {k: v * n for k, v in self._monomial.items()}) + return self.__class__(self.parent(), {k: v * n for k, v in self._monomial.items()}) def __floordiv__(self, elt): """ @@ -691,6 +688,7 @@ class IndexedMonoid(Parent, IndexedGenerators, UniqueRepresentation): For the optional arguments that control the printing, see :class:`~sage.structure.indexed_generators.IndexedGenerators`. """ + @staticmethod def __classcall__(cls, indices, prefix=None, names=None, **kwds): """ @@ -725,11 +723,9 @@ def __classcall__(cls, indices, prefix=None, names=None, **kwds): if isinstance(latex_bracket, list): kwds['latex_bracket'] = tuple(latex_bracket) - return super().__classcall__(cls, indices, prefix, - names=names, **kwds) + return super().__classcall__(cls, indices, prefix, names=names, **kwds) - def __init__(self, indices, prefix, - category=None, names=None, **kwds) -> None: + def __init__(self, indices, prefix, category=None, names=None, **kwds) -> None: """ Initialize ``self``. @@ -892,6 +888,7 @@ class IndexedFreeMonoid(IndexedMonoid): sage: F.gen(2) * F.gen(12) X|2>*X|12> """ + def _repr_(self) -> str: """ Return a string representation of ``self``. @@ -978,6 +975,7 @@ class IndexedFreeAbelianMonoid(IndexedMonoid): Implement a subclass when the index sets is finite that utilizes vectors or the polydict monomials with the index order fixed. """ + def _repr_(self) -> str: """ Return a string representation of ``self``. diff --git a/src/sage/monoids/monoid.py b/src/sage/monoids/monoid.py index 5a59aacc318..a7aae99d21e 100644 --- a/src/sage/monoids/monoid.py +++ b/src/sage/monoids/monoid.py @@ -22,6 +22,7 @@ def __init__(self, names, category=None) -> None: sage: TestSuite(F).run() """ from sage.categories.monoids import Monoids + if category is None: cat = Monoids().FinitelyGeneratedAsMagma() else: @@ -52,4 +53,5 @@ def monoid_generators(self): Family (a, b, c, d, e) """ from sage.sets.family import Family + return Family(self.gens()) diff --git a/src/sage/monoids/string_monoid.py b/src/sage/monoids/string_monoid.py index 9dd4334b4c8..07213d4584e 100644 --- a/src/sage/monoids/string_monoid.py +++ b/src/sage/monoids/string_monoid.py @@ -108,8 +108,7 @@ def gen(self, i=0): """ n = self.ngens() if i < 0 or not i < n: - raise IndexError( - f"Argument i (= {i}) must be between 0 and {n-1}.") + raise IndexError(f"Argument i (= {i}) must be between 0 and {n-1}.") return StringMonoidElement(self, [int(i)]) @@ -117,6 +116,7 @@ def gen(self, i=0): # Specific global string monoids # **************************************************************************** + class BinaryStringMonoid(StringMonoid_class): r""" The free binary string monoid on generators `\{ 0, 1 \}`. @@ -524,39 +524,14 @@ def __init__(self): ABCDEFGHIJKLMNOPQRSTUVWXYZ """ from sage.rings.real_mpfr import RealField + RR = RealField() # The characteristic frequency probability distribution of # Robert Edward Lewand. - self._characteristic_frequency_lewand = { - "A": RR(0.08167), "B": RR(0.01492), - "C": RR(0.02782), "D": RR(0.04253), - "E": RR(0.12702), "F": RR(0.02228), - "G": RR(0.02015), "H": RR(0.06094), - "I": RR(0.06966), "J": RR(0.00153), - "K": RR(0.00772), "L": RR(0.04025), - "M": RR(0.02406), "N": RR(0.06749), - "O": RR(0.07507), "P": RR(0.01929), - "Q": RR(0.00095), "R": RR(0.05987), - "S": RR(0.06327), "T": RR(0.09056), - "U": RR(0.02758), "V": RR(0.00978), - "W": RR(0.02360), "X": RR(0.00150), - "Y": RR(0.01974), "Z": RR(0.00074)} + self._characteristic_frequency_lewand = {"A": RR(0.08167), "B": RR(0.01492), "C": RR(0.02782), "D": RR(0.04253), "E": RR(0.12702), "F": RR(0.02228), "G": RR(0.02015), "H": RR(0.06094), "I": RR(0.06966), "J": RR(0.00153), "K": RR(0.00772), "L": RR(0.04025), "M": RR(0.02406), "N": RR(0.06749), "O": RR(0.07507), "P": RR(0.01929), "Q": RR(0.00095), "R": RR(0.05987), "S": RR(0.06327), "T": RR(0.09056), "U": RR(0.02758), "V": RR(0.00978), "W": RR(0.02360), "X": RR(0.00150), "Y": RR(0.01974), "Z": RR(0.00074)} # The characteristic frequency probability distribution of # H. Beker and F. Piper. - self._characteristic_frequency_beker_piper = { - "A": RR(0.082), "B": RR(0.015), - "C": RR(0.028), "D": RR(0.043), - "E": RR(0.127), "F": RR(0.022), - "G": RR(0.020), "H": RR(0.061), - "I": RR(0.070), "J": RR(0.002), - "K": RR(0.008), "L": RR(0.040), - "M": RR(0.024), "N": RR(0.067), - "O": RR(0.075), "P": RR(0.019), - "Q": RR(0.001), "R": RR(0.060), - "S": RR(0.063), "T": RR(0.091), - "U": RR(0.028), "V": RR(0.010), - "W": RR(0.023), "X": RR(0.001), - "Y": RR(0.020), "Z": RR(0.001)} + self._characteristic_frequency_beker_piper = {"A": RR(0.082), "B": RR(0.015), "C": RR(0.028), "D": RR(0.043), "E": RR(0.127), "F": RR(0.022), "G": RR(0.020), "H": RR(0.061), "I": RR(0.070), "J": RR(0.002), "K": RR(0.008), "L": RR(0.040), "M": RR(0.024), "N": RR(0.067), "O": RR(0.075), "P": RR(0.019), "Q": RR(0.001), "R": RR(0.060), "S": RR(0.063), "T": RR(0.091), "U": RR(0.028), "V": RR(0.010), "W": RR(0.023), "X": RR(0.001), "Y": RR(0.020), "Z": RR(0.001)} alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' StringMonoid_class.__init__(self, 26, [alph[i] for i in range(26)]) @@ -769,9 +744,9 @@ def characteristic_frequency(self, table_name='beker_piper'): """ supported_tables = ["beker_piper", "lewand"] if table_name not in supported_tables: - raise ValueError( - "Table name must be either 'beker_piper' or 'lewand'.") + raise ValueError("Table name must be either 'beker_piper' or 'lewand'.") from copy import copy + if table_name == "beker_piper": return copy(self._characteristic_frequency_beker_piper) if table_name == "lewand": diff --git a/src/sage/monoids/string_monoid_element.py b/src/sage/monoids/string_monoid_element.py index fde2e9f40db..6d3f95333e4 100644 --- a/src/sage/monoids/string_monoid_element.py +++ b/src/sage/monoids/string_monoid_element.py @@ -12,6 +12,7 @@ The internal representation of elements does not use the exponential compression of FreeMonoid elements (a feature), and could be packed into words. """ + # **************************************************************************** # Copyright (C) 2007 David Kohel # @@ -45,8 +46,7 @@ def __init__(self, S, x, check=True) -> None: if check: for b in x: if not isinstance(b, (int, Integer)): - raise TypeError( - "x (= %s) must be a list of integers." % x) + raise TypeError("x (= %s) must be a list of integers." % x) self._element_list = list(x) # make copy elif isinstance(x, str): alphabet = list(self.parent().alphabet()) @@ -55,8 +55,7 @@ def __init__(self, S, x, check=True) -> None: try: b = alphabet.index(x[i]) except ValueError: - raise TypeError( - "Argument x (= %s) is not a valid string." % x) + raise TypeError("Argument x (= %s) is not a valid string." % x) self._element_list += [b] else: raise TypeError("Argument x (= %s) is of the wrong type." % x) @@ -249,9 +248,8 @@ def decoding(self, padic=False): 'A..Za..z' """ S = self.parent() - from .string_monoid import (AlphabeticStringMonoid, - BinaryStringMonoid, - HexadecimalStringMonoid) + from .string_monoid import AlphabeticStringMonoid, BinaryStringMonoid, HexadecimalStringMonoid + if isinstance(S, AlphabeticStringMonoid): return ''.join(chr(65 + i) for i in self._element_list) n = len(self) @@ -260,12 +258,12 @@ def decoding(self, padic=False): "String %s must have even length to determine a byte character string." % str(self) s = [] x = self._element_list - for k in range(n//2): - m = 2*k + for k in range(n // 2): + m = 2 * k if padic: - c = chr(x[m]+16*x[m+1]) + c = chr(x[m] + 16 * x[m + 1]) else: - c = chr(16*x[m]+x[m+1]) + c = chr(16 * x[m] + x[m + 1]) s.append(c) return ''.join(s) if isinstance(S, BinaryStringMonoid): @@ -274,16 +272,15 @@ def decoding(self, padic=False): pows = [2**i for i in range(8)] s = [] x = self._element_list - for k in range(n//8): - m = 8*k + for k in range(n // 8): + m = 8 * k if padic: - c = chr(sum([x[m+i] * pows[i] for i in range(8)])) + c = chr(sum([x[m + i] * pows[i] for i in range(8)])) else: - c = chr(sum([x[m+7-i] * pows[i] for i in range(8)])) + c = chr(sum([x[m + 7 - i] * pows[i] for i in range(8)])) s.append(c) return ''.join(s) - raise TypeError( - "Argument %s must be an alphabetic, binary, or hexadecimal string." % str(self)) + raise TypeError("Argument %s must be an alphabetic, binary, or hexadecimal string." % str(self)) def coincidence_index(self, prec=0): """ @@ -457,6 +454,7 @@ def frequency_distribution(self, length=1, prec=0): [(AB, 0.333333333333333), (BC, 0.333333333333333), (CD, 0.333333333333333)] """ from sage.probability.random_variable import DiscreteProbabilitySpace + if length not in (1, 2): raise NotImplementedError("Not implemented") if prec == 0: @@ -472,7 +470,7 @@ def frequency_distribution(self, length=1, prec=0): N = len(self) - length + 1 eps = RR(Integer(1) / N) for i in range(N): - c = self[i:i+length] + c = self[i : i + length] if c in X: X[c] += eps else: diff --git a/src/sage/monoids/string_ops.py b/src/sage/monoids/string_ops.py index 71b3ae8eee7..e1f5bff11c3 100644 --- a/src/sage/monoids/string_ops.py +++ b/src/sage/monoids/string_ops.py @@ -58,10 +58,11 @@ def frequency_distribution(S, n=1, field=None): 't ': 0.0370370370370370} """ from sage.probability.random_variable import DiscreteProbabilitySpace + if isinstance(S, tuple): S = list(S) elif isinstance(S, (str, StringMonoidElement)): - S = [S[i:i+n] for i in range(len(S)-n+1)] + S = [S[i : i + n] for i in range(len(S) - n + 1)] if field is None: field = RealField() if isinstance(S, list): @@ -94,16 +95,16 @@ def coincidence_index(S, n=1): except AttributeError: raise TypeError("Argument S (= %s) must be a string.") S = strip_encoding(S) - N = len(S)-n+1 + N = len(S) - n + 1 X: dict[str, int] = {} for i in range(N): - c = S[i:i+n] + c = S[i : i + n] if c in X: X[c] += 1 else: X[c] = 1 RR = RealField() - return RR(sum([m*(m-1) for m in X.values()]))/RR(N*(N-1)) + return RR(sum([m * (m - 1) for m in X.values()])) / RR(N * (N - 1)) def coincidence_discriminant(S, n=2): @@ -137,6 +138,6 @@ def coincidence_discriminant(S, n=2): if isinstance(S[0], StringMonoidElement): M = S[0].parent() n = M.ngens() - return sum([(XX(M([i, j]))-X1[0](M([i]))*X1[1](M([j])))**2 for i in range(n) for j in range(n)]) + return sum([(XX(M([i, j])) - X1[0](M([i])) * X1[1](M([j]))) ** 2 for i in range(n) for j in range(n)]) AZ = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' - return sum([(XX(AZ[i]+AZ[j])-X1[0](AZ[i])*X1[1](AZ[j]))**2 for i in range(26) for j in range(26)]) + return sum([(XX(AZ[i] + AZ[j]) - X1[0](AZ[i]) * X1[1](AZ[j])) ** 2 for i in range(26) for j in range(26)]) diff --git a/src/sage/monoids/trace_monoid.py b/src/sage/monoids/trace_monoid.py index 63b54bb2ff7..80eb8a0a85e 100644 --- a/src/sage/monoids/trace_monoid.py +++ b/src/sage/monoids/trace_monoid.py @@ -30,6 +30,7 @@ - Pavlo Tokariev (2019-05-31): initial version """ + # **************************************************************************** # Copyright (C) 2019 Pavlo Tokariev # @@ -89,6 +90,7 @@ class TraceMonoidElement(ElementWrapper, MonoidElement): sage: x.foata_normal_form() (b, a*d, a, b*c) """ + def _repr_(self) -> str: """ Textual representation of ``self``. @@ -220,8 +222,7 @@ def dependence_graph(self): graph = {} for i, e in enumerate(elements): - edges = [(v, i) for v in graph - if (e, elements[v]) not in independence] + edges = [(v, i) for v in graph if (e, elements[v]) not in independence] graph[i] = [] for v1, v2 in edges: graph[v1].append(v2) @@ -273,8 +274,7 @@ def hasse_diagram(self, algorithm='naive'): return self.naive_hasse_diagram() if algorithm == "min": return self.min_hasse_diagram() - raise ValueError("`alg` option must be `naive` " - f"or `min`, got `{algorithm}`.") + raise ValueError("`alg` option must be `naive` " f"or `min`, got `{algorithm}`.") def min_hasse_diagram(self): r""" @@ -468,6 +468,7 @@ class TraceMonoid(UniqueRepresentation, Monoid_class): sage: M.number_of_words(3) == len(M.words(3)) # needs sage.graphs True """ + Element = TraceMonoidElement @staticmethod @@ -665,8 +666,7 @@ def _compute_lex_normal_form(self, x): g_stack.pop() elements.append(generator) for other_gen in generators_set: - if (other_gen != generator - and (generator, other_gen) not in independence): + if other_gen != generator and (generator, other_gen) not in independence: stacks[other_gen].pop() break @@ -775,8 +775,7 @@ def dependence(self): sage: sorted(M.dependence()) [(a, a), (a, b), (b, a), (b, b), (b, c), (c, b), (c, c)] """ - return frozenset(pair for pair in product(self._free_monoid.gens(), repeat=2) - if pair not in self._independence) + return frozenset(pair for pair in product(self._free_monoid.gens(), repeat=2) if pair not in self._independence) @cached_method def dependence_graph(self): @@ -793,10 +792,7 @@ def dependence_graph(self): sage: M.dependence_graph() == Graph({a:[a,b], b:[b], c:[c,b]}) # needs sage.graphs True """ - return Graph({frozenset((e1, e2)) if e1 != e2 else (e1, e2) - for e1, e2 in self.dependence()}, loops=True, - format='list_of_edges', - immutable=True) + return Graph({frozenset((e1, e2)) if e1 != e2 else (e1, e2) for e1, e2 in self.dependence()}, loops=True, format='list_of_edges', immutable=True) @cached_method def independence_graph(self): @@ -840,8 +836,7 @@ def dependence_polynomial(self, t=None): R = PolynomialRing(ZZ, 't') t = R.gen() clique_seq = self.independence_graph().clique_polynomial().coefficients() - return ~sum((-1)**i * coeff * (t**i) - for i, coeff in enumerate(clique_seq)) + return ~sum((-1) ** i * coeff * (t**i) for i, coeff in enumerate(clique_seq)) @cached_method def number_of_words(self, length): @@ -911,10 +906,7 @@ def words(self, length): if length == 1: return frozenset(self.gens()) - return frozenset([word * suffix for word in self.words(length - 1) - for suffix in self.gens() - if not ((list(word.value)[-1][0], suffix.value) in self._independence - and list(word.value)[-1][0] > suffix.value)]) + return frozenset([word * suffix for word in self.words(length - 1) for suffix in self.gens() if not ((list(word.value)[-1][0], suffix.value) in self._independence and list(word.value)[-1][0] > suffix.value)]) def _sorted_independence(self) -> list: r""" @@ -931,8 +923,7 @@ def _sorted_independence(self) -> list: sage: M._sorted_independence() [[a, c]] """ - return sorted(sorted(x_y) - for x_y in self.independence()) + return sorted(sorted(x_y) for x_y in self.independence()) def _repr_(self) -> str: r""" @@ -946,10 +937,7 @@ def _repr_(self) -> str: Trace monoid on 4 generators ([a], [b], [c], [d]) with independence relation {{a, d}, {b, c}} """ - return ("Trace monoid on {!s} generators {!s} " - "with independence relation {{{}}}").format(self.ngens(), self.gens(), - ", ".join(f"{{{x}, {y}}}" - for (x, y) in self._sorted_independence())) + return ("Trace monoid on {!s} generators {!s} " "with independence relation {{{}}}").format(self.ngens(), self.gens(), ", ".join(f"{{{x}, {y}}}" for (x, y) in self._sorted_independence())) def _latex_(self) -> str: r""" @@ -962,10 +950,4 @@ def _latex_(self) -> str: sage: M. = TraceMonoid(I=I); latex(M) \langle a, b, c, d \mid ad=da,bc=cb \rangle """ - return "\\langle {} \\mid {} \\rangle".format( - repr(self._free_monoid.gens())[1:-1], - ",".join( - f"{v1!r}{v2!r}={v2!r}{v1!r}" - for v1, v2 in self._sorted_independence() - ) - ) + return "\\langle {} \\mid {} \\rangle".format(repr(self._free_monoid.gens())[1:-1], ",".join(f"{v1!r}{v2!r}={v2!r}{v1!r}" for v1, v2 in self._sorted_independence())) diff --git a/src/sage/numerical/all.py b/src/sage/numerical/all.py index 8b69da18652..c9e315d9279 100644 --- a/src/sage/numerical/all.py +++ b/src/sage/numerical/all.py @@ -1,11 +1,9 @@ from sage.misc.lazy_import import lazy_import -lazy_import("sage.numerical.optimize", - ["find_fit", "find_local_maximum", "find_local_minimum", - "find_root", "minimize", "minimize_constrained"]) + +lazy_import("sage.numerical.optimize", ["find_fit", "find_local_maximum", "find_local_minimum", "find_root", "minimize", "minimize_constrained"]) lazy_import("sage.numerical.mip", ["MixedIntegerLinearProgram"]) lazy_import("sage.numerical.sdp", ["SemidefiniteProgram"]) lazy_import("sage.numerical.backends.generic_backend", ["default_mip_solver"]) lazy_import("sage.numerical.backends.generic_sdp_backend", ["default_sdp_solver"]) -lazy_import("sage.numerical.interactive_simplex_method", - ["InteractiveLPProblem", "InteractiveLPProblemStandardForm"]) +lazy_import("sage.numerical.interactive_simplex_method", ["InteractiveLPProblem", "InteractiveLPProblemStandardForm"]) diff --git a/src/sage/numerical/backends/cvxopt_backend_test.py b/src/sage/numerical/backends/cvxopt_backend_test.py index 6029221fda2..99ac999c9bd 100644 --- a/src/sage/numerical/backends/cvxopt_backend_test.py +++ b/src/sage/numerical/backends/cvxopt_backend_test.py @@ -15,4 +15,5 @@ def backend(self) -> GenericBackend: def test_sage_unittest_testsuite(self, sage_object: SageObject): # TODO: Remove this test as soon as all old test methods are migrated from sage.misc.sage_unittest import TestSuite - TestSuite(sage_object).run(verbose=True, raise_on_failure=True, skip=("_test_pickling","_test_solve","_test_solve_trac_18572")) + + TestSuite(sage_object).run(verbose=True, raise_on_failure=True, skip=("_test_pickling", "_test_solve", "_test_solve_trac_18572")) diff --git a/src/sage/numerical/backends/generic_backend_test.py b/src/sage/numerical/backends/generic_backend_test.py index 64c9eb44670..d1abadfcc45 100644 --- a/src/sage/numerical/backends/generic_backend_test.py +++ b/src/sage/numerical/backends/generic_backend_test.py @@ -20,4 +20,5 @@ def test_ncols_nonnegative(self, backend: GenericBackend): def test_sage_unittest_testsuite(self, sage_object: SageObject): # TODO: Remove this test as soon as all old test methods are migrated from sage.misc.sage_unittest import TestSuite + TestSuite(sage_object).run(verbose=True, raise_on_failure=True, skip='_test_pickling') diff --git a/src/sage/numerical/backends/logging_backend.py b/src/sage/numerical/backends/logging_backend.py index e24601198b6..97a19a9e7fb 100644 --- a/src/sage/numerical/backends/logging_backend.py +++ b/src/sage/numerical/backends/logging_backend.py @@ -53,6 +53,7 @@ def _make_wrapper(backend, attr): # result: 0 0 """ + def m(self, *args, **kwdargs): funcall = _format_function_call("p." + attr, *args, **kwdargs) a = getattr(self._backend, attr) @@ -66,12 +67,9 @@ def m(self, *args, **kwdargs): if self._printing: print("# exception: {}".format(e)) if self._doctest: - self._doctest.write(" Traceback (most recent call last):\n" - " ...\n" - " MIPSolverException: {}\n".format(e)) + self._doctest.write(" Traceback (most recent call last):\n" " ...\n" " MIPSolverException: {}\n".format(e)) if self._test_method: - self._test_method.write((" with tester.assertRaises({}) as cm:\n" + - " {}\n").format(type(e).__name__, funcall)) + self._test_method.write((" with tester.assertRaises({}) as cm:\n" + " {}\n").format(type(e).__name__, funcall)) raise else: if self._printing: @@ -88,7 +86,9 @@ def m(self, *args, **kwdargs): else: self._test_method.write(" tester.assertEqual({}, {})\n".format(funcall, result)) return result + from functools import update_wrapper + update_wrapper(m, getattr(backend, attr)) return m @@ -116,8 +116,7 @@ class LoggingBackend(GenericBackend): .. :no-undoc-members: """ - def __init__(self, backend, printing=True, doctest=None, test_method=None, - base_ring=None): + def __init__(self, backend, printing=True, doctest=None, test_method=None, base_ring=None): """ See :class:`LoggingBackendFactory` for documentation. @@ -157,6 +156,7 @@ def __getattr__(self, attr): if callable(_a): # make a bound method import types + _mm = types.MethodType(_make_wrapper(self._backend, attr), self) # cache it setattr(self, attr, _mm) @@ -210,8 +210,7 @@ def _override_attr(attr): if not attr.startswith("_") and attr not in ("zero", "base_ring"): _override_attr(attr) -test_method_template = \ -r''' +test_method_template = r''' @classmethod def _test_{name}(cls, tester=None, **options): """ @@ -229,13 +228,14 @@ def _test_{name}(cls, tester=None, **options): p = cls() # fresh instance of the backend if tester is None: tester = p._tester(**options) -'''.replace("SAGE:", "sage:") # so that the above test does not get picked up by the doctester +'''.replace( + "SAGE:", "sage:" +) # so that the above test does not get picked up by the doctester from sage.rings.rational_field import QQ -def LoggingBackendFactory(solver=None, printing=True, doctest_file=None, test_method_file=None, - test_method=None, base_ring=QQ): +def LoggingBackendFactory(solver=None, printing=True, doctest_file=None, test_method_file=None, test_method=None, base_ring=QQ): """ Factory that constructs a :class:`LoggingBackend` for debugging and testing. @@ -381,8 +381,7 @@ def logging_solver(**kwds): if test_method_output is not None: test_method_output.write(test_method_template.format(name=test_method)) from sage.numerical.backends.generic_backend import get_solver - return LoggingBackend(backend=get_solver(solver=solver, **kwds), - printing=printing, doctest=doctest, test_method=test_method_output, - base_ring=base_ring) + + return LoggingBackend(backend=get_solver(solver=solver, **kwds), printing=printing, doctest=doctest, test_method=test_method_output, base_ring=base_ring) return logging_solver diff --git a/src/sage/numerical/interactive_simplex_method.py b/src/sage/numerical/interactive_simplex_method.py index 88146de801c..7217bea4061 100644 --- a/src/sage/numerical/interactive_simplex_method.py +++ b/src/sage/numerical/interactive_simplex_method.py @@ -167,6 +167,7 @@ Classes and functions --------------------- """ + # **************************************************************************** # Copyright (C) 2013 Andrey Novoseltsev # @@ -195,6 +196,7 @@ from sage.modules.free_module_element import random_vector from sage.modules.free_module_element import free_module_element as vector from sage.misc.lazy_import import lazy_import + lazy_import("sage.plot.all", ["Graphics", "arrow", "line", "point", "rainbow", "text"]) from sage.rings.infinity import Infinity from sage.rings.polynomial.polynomial_ring import polygen @@ -248,17 +250,10 @@ def _assemble_arrayl(lines, stretch=None): """ # Even simple LP problems tend to generate long output, so we prohibit # truncation in the notebook cells and hope for the best! - return LatexExpr(("" if generate_real_LaTeX else "%notruncate\n") + - ("" if stretch is None else - "\\renewcommand{\\arraystretch}{%f}\n" % stretch) + - "\\begin{array}{l}\n" + - "\\\\\n".join(lines) + - "\n\\end{array}") + return LatexExpr(("" if generate_real_LaTeX else "%notruncate\n") + ("" if stretch is None else "\\renewcommand{\\arraystretch}{%f}\n" % stretch) + "\\begin{array}{l}\n" + "\\\\\n".join(lines) + "\n\\end{array}") -def _latex_product(coefficients, variables, - separator=None, head=None, tail=None, - drop_plus=True, allow_empty=False): +def _latex_product(coefficients, variables, separator=None, head=None, tail=None, drop_plus=True, allow_empty=False): r""" Generate LaTeX code for a linear function. @@ -311,24 +306,25 @@ def _latex_product(coefficients, variables, sign = "+" if latex(c).strip().startswith("-"): sign = "-" - c = - c + c = -c if c == 1: t = latex(v) else: t = latex(c) if '+' in t or '-' in t: from sage.symbolic.ring import SR + if SR(c).operator() in [operator.add, operator.sub]: t = r"\left( " + t + r" \right)" t += " " + latex(v) entries.extend([sign, t]) - if drop_plus: # Don't start with + + if drop_plus: # Don't start with + for i, e in enumerate(entries): - if e: # The first non-empty + if e: # The first non-empty if e == "+": entries[i] = "" break - if not (allow_empty or any(entries)): # Return at least 0 + if not (allow_empty or any(entries)): # Return at least 0 entries[-1] = "0" latex_relations = {"<=": r"\leq", "==": "=", ">=": r"\geq"} if head is not None: @@ -428,7 +424,7 @@ def variable(R, v): "primal objective": "z", "dual objective": "z", "auxiliary objective": "w", - }, + }, "Vanderbei": { "primal decision": "x", "primal slack": "w", @@ -437,8 +433,8 @@ def variable(R, v): "primal objective": "zeta", "dual objective": "xi", "auxiliary objective": "xi", - }, - } + }, +} current_style = 'UAlberta' @@ -543,8 +539,7 @@ def style(new_style=None): global current_style if new_style is not None: if new_style not in available_styles: - raise ValueError("Style must be one of: {}".format( - ", ".join(available_styles.keys()))) + raise ValueError("Style must be one of: {}".format(", ".join(available_styles.keys()))) current_style = new_style return current_style @@ -631,9 +626,7 @@ class InteractiveLPProblem(SageObject): are on different sides. """ - def __init__(self, A, b, c, x='x', - constraint_type='<=', variable_type='', problem_type='max', - base_ring=None, is_primal=True, objective_constant_term=0): + def __init__(self, A, b, c, x='x', constraint_type='<=', variable_type='', problem_type='max', base_ring=None, is_primal=True, objective_constant_term=0): r""" See :class:`InteractiveLPProblem` for documentation. @@ -664,18 +657,18 @@ def __init__(self, A, b, c, x='x', if c.degree() != n: raise ValueError("A and c have incompatible dimensions") if isinstance(x, str): - x = ["{}{:d}".format(x, i) for i in range(1, n+1)] + x = ["{}{:d}".format(x, i) for i in range(1, n + 1)] else: x = [str(_) for _ in x] if len(x) != n: raise ValueError("A and x have incompatible dimensions") R = PolynomialRing(base_ring, x, order='neglex') - x = vector(R, R.gens()) # All variables as a vector + x = vector(R, R.gens()) # All variables as a vector self._Abcx = A, b, c, x self._constant_term = objective_constant_term if constraint_type in ["<=", ">=", "=="]: - constraint_type = (constraint_type, ) * m + constraint_type = (constraint_type,) * m else: constraint_type = tuple(constraint_type) if any(ct not in ["<=", ">=", "=="] for ct in constraint_type): @@ -685,7 +678,7 @@ def __init__(self, A, b, c, x='x', self._constraint_types = constraint_type if variable_type in ["<=", ">=", ""]: - variable_type = (variable_type, ) * n + variable_type = (variable_type,) * n else: variable_type = tuple(variable_type) if any(vt not in ["<=", ">=", ""] for vt in variable_type): @@ -731,13 +724,7 @@ def __eq__(self, other): sage: P == P3 False """ - return (isinstance(other, InteractiveLPProblem) and - self.Abcx() == other.Abcx() and - self._constant_term == other._constant_term and - self._problem_type == other._problem_type and - self._is_negative == other._is_negative and - self._constraint_types == other._constraint_types and - self._variable_types == other._variable_types) + return isinstance(other, InteractiveLPProblem) and self.Abcx() == other.Abcx() and self._constant_term == other._constant_term and self._problem_type == other._problem_type and self._is_negative == other._is_negative and self._constraint_types == other._constraint_types and self._variable_types == other._variable_types def _latex_(self): r""" @@ -767,25 +754,21 @@ def _latex_(self): if generate_real_LaTeX: lines[-1] += r" \setlength{\arraycolsep}{0.125em}" lines.append(r"\begin{array}{l" + "cr" * len(x) + "cl}") - head = [r"{} \{}".format("- " if self._is_negative else "", - self._problem_type)] + head = [r"{} \{}".format("- " if self._is_negative else "", self._problem_type)] if self._constant_term == 0: tail = ["", ""] elif latex(self._constant_term).strip().startswith("-"): - tail = ["-", - self._constant_term] + tail = ["-", -self._constant_term] else: tail = ["+", self._constant_term] lines.append(_latex_product(c, x, head=head, tail=tail) + r"\\") for Ai, ri, bi in zip(A.rows(), self._constraint_types, b): - lines.append(_latex_product(Ai, x, head=[""], tail=[ri, bi]) + - r" \\") + lines.append(_latex_product(Ai, x, head=[""], tail=[ri, bi]) + r" \\") lines.append(r"\end{array} \\") if set(self._variable_types) == set([">="]): lines.append(r"{} \geq 0".format(", ".join(map(latex, x)))) else: - lines.append(r",\ ".join(r"{} {} 0".format( - latex(xj), r"\geq" if vt == ">=" else r"\leq") - for xj, vt in zip(x, self._variable_types) if vt)) + lines.append(r",\ ".join(r"{} {} 0".format(latex(xj), r"\geq" if vt == ">=" else r"\leq") for xj, vt in zip(x, self._variable_types) if vt)) lines.append(r"\end{array}") return "\n".join(lines) @@ -877,14 +860,12 @@ def _solve(self): if c.is_zero(): M, S = 0, F.vertices()[0] elif self._problem_type == "max": - if any(c * vector(R, ray) > 0 for ray in F.rays()) or \ - any(c * vector(R, line) != 0 for line in F.lines()): + if any(c * vector(R, ray) > 0 for ray in F.rays()) or any(c * vector(R, line) != 0 for line in F.lines()): M, S = Infinity, None else: M, S = max((c * vector(R, v), v) for v in F.vertices()) elif self._problem_type == "min": - if any(c * vector(R, ray) < 0 for ray in F.rays()) or \ - any(c * vector(R, line) != 0 for line in F.lines()): + if any(c * vector(R, ray) < 0 for ray in F.rays()) or any(c * vector(R, line) != 0 for line in F.lines()): M, S = -Infinity, None else: M, S = min((c * vector(R, v), v) for v in F.vertices()) @@ -893,7 +874,7 @@ def _solve(self): S.set_immutable() M += self._constant_term if self._is_negative: - M = - M + M = -M return S, M def Abcx(self): @@ -969,13 +950,7 @@ def add_constraint(self, coefficients, constant_term, constraint_type='<='): problem_type = "-" + self.problem_type() else: problem_type = self.problem_type() - return InteractiveLPProblem(A, b, c, x, - constraint_type=self._constraint_types + (constraint_type,), - variable_type=self.variable_types(), - problem_type=problem_type, - base_ring=self.base_ring(), - is_primal=self._is_primal, - objective_constant_term=self.objective_constant_term()) + return InteractiveLPProblem(A, b, c, x, constraint_type=self._constraint_types + (constraint_type,), variable_type=self.variable_types(), problem_type=problem_type, base_ring=self.base_ring(), is_primal=self._is_primal, objective_constant_term=self.objective_constant_term()) def base_ring(self): r""" @@ -1118,35 +1093,27 @@ def dual(self, y=None): A, c, b, x = self.Abcx() A = A.transpose() if y is None: - y = default_variable_name( - "dual decision" if self.is_primal() else "primal decision") + y = default_variable_name("dual decision" if self.is_primal() else "primal decision") problem_type = "min" if self._problem_type == "max" else "max" constraint_type = [] for vt in self._variable_types: - if (vt == ">=" and problem_type == "min" or - vt == "<=" and problem_type == "max"): + if vt == ">=" and problem_type == "min" or vt == "<=" and problem_type == "max": constraint_type.append(">=") - elif (vt == "<=" and problem_type == "min" or - vt == ">=" and problem_type == "max"): + elif vt == "<=" and problem_type == "min" or vt == ">=" and problem_type == "max": constraint_type.append("<=") else: constraint_type.append("==") variable_type = [] for ct in self._constraint_types: - if (ct == ">=" and problem_type == "min" or - ct == "<=" and problem_type == "max"): + if ct == ">=" and problem_type == "min" or ct == "<=" and problem_type == "max": variable_type.append("<=") - elif (ct == "<=" and problem_type == "min" or - ct == ">=" and problem_type == "max"): + elif ct == "<=" and problem_type == "min" or ct == ">=" and problem_type == "max": variable_type.append(">=") else: variable_type.append("") if self._is_negative: problem_type = "-" + problem_type - return InteractiveLPProblem(A, b, c, y, - constraint_type, variable_type, problem_type, - is_primal=not self.is_primal(), - objective_constant_term=self._constant_term) + return InteractiveLPProblem(A, b, c, y, constraint_type, variable_type, problem_type, is_primal=not self.is_primal(), objective_constant_term=self._constant_term) @cached_method def feasible_set(self): @@ -1315,8 +1282,7 @@ def is_optimal(self, *x) -> bool: sage: P.is_optimal(501, -3) False """ - return (self.optimal_value() == self.objective_value(*x) and - self.is_feasible(*x)) + return self.optimal_value() == self.objective_value(*x) and self.is_feasible(*x) def n_constraints(self): r""" @@ -1424,7 +1390,7 @@ def objective_value(self, *x): 2000 """ v = self.c() * self._solution(x) + self._constant_term - return - v if self._is_negative else v + return -v if self._is_negative else v def optimal_solution(self): r""" @@ -1516,32 +1482,27 @@ def plot(self, *args, **kwds): ymax = FP.ymax() xmin, xmax, ymin, ymax = map(QQ, [xmin, xmax, ymin, ymax]) start = self.optimal_solution() - start = vector(QQ, start.n() if start is not None - else [xmin + (xmax-xmin)/2, ymin + (ymax-ymin)/2]) + start = vector(QQ, start.n() if start is not None else [xmin + (xmax - xmin) / 2, ymin + (ymax - ymin) / 2]) length = min(xmax - xmin, ymax - ymin) / 5 end = start + (c * length / c.norm()).n().change_ring(QQ) result = FP + point(start, color='black', size=50, zorder=10) result += arrow(start, end, color='black', zorder=10) - ieqs = [(xmax, -1, 0), (- xmin, 1, 0), - (ymax, 0, -1), (- ymin, 0, 1)] + ieqs = [(xmax, -1, 0), (-xmin, 1, 0), (ymax, 0, -1), (-ymin, 0, 1)] box = Polyhedron(ieqs=ieqs) d = vector([c[1], -c[0]]) for i in range(-10, 11): - level = Polyhedron(vertices=[start + i*(end-start)], lines=[d]) + level = Polyhedron(vertices=[start + i * (end - start)], lines=[d]) level = box.intersection(level) if level.vertices(): if i == 0 and self.is_bounded(): - result += line(level.vertices(), color='black', - thickness=2) + result += line(level.vertices(), color='black', thickness=2) else: - result += line(level.vertices(), color='black', - linestyle='--') + result += line(level.vertices(), color='black', linestyle='--') result.set_axes_range(xmin, xmax, ymin, ymax) result.axes_labels(FP.axes_labels()) # FIXME: should be preserved! return result - def plot_feasible_set(self, xmin=None, xmax=None, ymin=None, ymax=None, - alpha=0.2): + def plot_feasible_set(self, xmin=None, xmax=None, ymin=None, ymax=None, alpha=0.2): r""" Return a plot of the feasible set of ``self``. @@ -1585,21 +1546,19 @@ def plot_feasible_set(self, xmin=None, xmax=None, ymin=None, ymax=None, if ymax is None: ymax = max([abs(bb) for bb in b] + [v[1] for v in F.vertices()]) if ymin is None: - ymin = min([-ymax/4.0] + [v[1] for v in F.vertices()]) + ymin = min([-ymax / 4.0] + [v[1] for v in F.vertices()]) if xmax is None: - xmax = max([1.5*ymax] + [v[0] for v in F.vertices()]) + xmax = max([1.5 * ymax] + [v[0] for v in F.vertices()]) if xmin is None: - xmin = min([-xmax/4.0] + [v[0] for v in F.vertices()]) + xmin = min([-xmax / 4.0] + [v[0] for v in F.vertices()]) xmin, xmax, ymin, ymax = map(QQ, [xmin, xmax, ymin, ymax]) pad = max(xmax - xmin, ymax - ymin) / 20 - ieqs = [(xmax, -1, 0), (- xmin, 1, 0), - (ymax, 0, -1), (- ymin, 0, 1)] + ieqs = [(xmax, -1, 0), (-xmin, 1, 0), (ymax, 0, -1), (-ymin, 0, 1)] box = Polyhedron(ieqs=ieqs) F = box.intersection(F) result = Graphics() colors = rainbow(self.m() + 2) - for Ai, ri, bi, color in zip(A.rows(), self._constraint_types, - b, colors[:-2]): + for Ai, ri, bi, color in zip(A.rows(), self._constraint_types, b, colors[:-2]): border = box.intersection(Polyhedron(eqns=[[-bi] + list(Ai)])) vertices = border.vertices() if not vertices: @@ -1607,17 +1566,16 @@ def plot_feasible_set(self, xmin=None, xmax=None, ymin=None, ymax=None, label = r"${}$".format(_latex_product(Ai, x, " ", tail=[ri, bi])) result += line(vertices, color=color, legend_label=label) if ri == "<=": - ieqs = [[bi] + list(-Ai), [-bi+pad*Ai.norm().n()] + list(Ai)] + ieqs = [[bi] + list(-Ai), [-bi + pad * Ai.norm().n()] + list(Ai)] elif ri == ">=": - ieqs = [[-bi] + list(Ai), [bi+pad*Ai.norm().n()] + list(-Ai)] + ieqs = [[-bi] + list(Ai), [bi + pad * Ai.norm().n()] + list(-Ai)] else: continue - ieqs = [ [QQ(_) for _ in ieq] for ieq in ieqs] + ieqs = [[QQ(_) for _ in ieq] for ieq in ieqs] halfplane = box.intersection(Polyhedron(ieqs=ieqs)) result += halfplane.render_solid(alpha=alpha, color=color) # Same for variables, but no legend - for ni, ri, color in zip((QQ**2).gens(), self._variable_types, - colors[-2:]): + for ni, ri, color in zip((QQ**2).gens(), self._variable_types, colors[-2:]): border = box.intersection(Polyhedron(eqns=[[0] + list(ni)])) if not border.vertices(): continue @@ -1627,18 +1585,16 @@ def plot_feasible_set(self, xmin=None, xmax=None, ymin=None, ymax=None, ieqs = [[0] + list(ni), [pad] + list(-ni)] else: continue - ieqs = [ [QQ(_) for _ in ieq] for ieq in ieqs] + ieqs = [[QQ(_) for _ in ieq] for ieq in ieqs] halfplane = box.intersection(Polyhedron(ieqs=ieqs)) result += halfplane.render_solid(alpha=alpha, color=color) if F.vertices(): result += F.render_solid(alpha=alpha, color='gray') - result += text("$F$", F.center(), - fontsize=20, color='black', zorder=5) + result += text("$F$", F.center(), fontsize=20, color='black', zorder=5) result.set_axes_range(xmin, xmax, ymin, ymax) result.axes_labels(["${}$".format(latex(xi)) for xi in x]) result.legend(True) - result.set_legend_options(fancybox=True, handlelength=1.5, loc=1, - shadow=True) + result.set_legend_options(fancybox=True, handlelength=1.5, loc=1, shadow=True) result._extra_kwds["aspect_ratio"] = 1 result.set_aspect_ratio(1) return result @@ -1771,8 +1727,7 @@ def standard_form(self, transformation=False, **kwds): newc = [] newx = [] newf = [] - for vt, Aj, cj, xj, fj in zip( - self._variable_types, A.columns(), c, x, f): + for vt, Aj, cj, xj, fj in zip(self._variable_types, A.columns(), c, x, f): xj = str(xj) if vt in [">=", ""]: newA.append(Aj) @@ -1792,15 +1747,14 @@ def standard_form(self, transformation=False, **kwds): x = newx f = newf - objective_name = polygen(ZZ, kwds.get("objective_name", default_variable_name( - "primal objective" if self.is_primal() else "dual objective"))) + objective_name = polygen(ZZ, kwds.get("objective_name", default_variable_name("primal objective" if self.is_primal() else "dual objective"))) is_negative = self._is_negative constant_term = self._constant_term if self._problem_type == "min": is_negative = not is_negative - c = - c - constant_term = - constant_term - objective_name = - objective_name + c = -c + constant_term = -constant_term + objective_name = -objective_name kwds["objective_name"] = objective_name # polynomial, no longer a string kwds["problem_type"] = "-max" if is_negative else "max" kwds["is_primal"] = self.is_primal() @@ -1910,10 +1864,7 @@ class InteractiveLPProblemStandardForm(InteractiveLPProblem): (x3, x4) """ - def __init__(self, A, b, c, x='x', problem_type='max', - slack_variables=None, auxiliary_variable=None, - base_ring=None, is_primal=True, objective_name=None, - objective_constant_term=0): + def __init__(self, A, b, c, x='x', problem_type='max', slack_variables=None, auxiliary_variable=None, base_ring=None, is_primal=True, objective_name=None, objective_constant_term=0): r""" See :class:`InteractiveLPProblemStandardForm` for documentation. @@ -1926,27 +1877,17 @@ def __init__(self, A, b, c, x='x', problem_type='max', sage: TestSuite(P).run() """ if problem_type not in ("max", "-max"): - raise ValueError("problems in standard form must be of (negative) " - "maximization type") - super().__init__( - A, b, c, x, - problem_type=problem_type, - constraint_type='<=', - variable_type='>=', - base_ring=base_ring, - is_primal=is_primal, - objective_constant_term=objective_constant_term) + raise ValueError("problems in standard form must be of (negative) " "maximization type") + super().__init__(A, b, c, x, problem_type=problem_type, constraint_type='<=', variable_type='>=', base_ring=base_ring, is_primal=is_primal, objective_constant_term=objective_constant_term) n, m = self.n(), self.m() if slack_variables is None: - slack_variables = default_variable_name( - "primal slack" if is_primal else "dual slack") + slack_variables = default_variable_name("primal slack" if is_primal else "dual slack") if isinstance(slack_variables, str): if style() == "UAlberta": indices = range(n + 1, n + m + 1) if style() == 'Vanderbei': indices = range(1, m + 1) - slack_variables = ["{}{:d}".format(slack_variables, i) - for i in indices] + slack_variables = ["{}{:d}".format(slack_variables, i) for i in indices] else: slack_variables = [str(s) for s in slack_variables] if len(slack_variables) != m: @@ -1960,20 +1901,18 @@ def __init__(self, A, b, c, x='x', problem_type='max', names.pop(0) R = PolynomialRing(self.base_ring(), names, order='neglex') self._R = R - x = vector(R.gens()[-n-m:-m]) + x = vector(R.gens()[-n - m : -m]) x.set_immutable() - self._Abcx = self._Abcx[:-1] + (x, ) + self._Abcx = self._Abcx[:-1] + (x,) if objective_name is None: - objective_name = default_variable_name( - "primal objective" if is_primal else "dual objective") + objective_name = default_variable_name("primal objective" if is_primal else "dual objective") if isinstance(objective_name, Polynomial): self._objective_name = objective_name else: self._objective_name = polygen(ZZ, objective_name) @staticmethod - def random_element(m, n, bound=5, special_probability=0.2, - **kwds): + def random_element(m, n, bound=5, special_probability=0.2, **kwds): r""" Construct a random ``InteractiveLPProblemStandardForm``. @@ -2001,11 +1940,11 @@ def random_element(m, n, bound=5, special_probability=0.2, A = random_matrix(ZZ, m, n, x=-bound, y=bound).change_ring(QQ) if special_probability < random(): b = random_vector(ZZ, m, x=0, y=bound).change_ring(QQ) - else: # Allow infeasible dictionary + else: # Allow infeasible dictionary b = random_vector(ZZ, m, x=-bound, y=bound).change_ring(QQ) if special_probability < random(): c = random_vector(ZZ, n, x=-bound, y=bound).change_ring(QQ) - else: # Make dual feasible dictionary + else: # Make dual feasible dictionary c = random_vector(ZZ, n, x=-bound, y=0).change_ring(QQ) return InteractiveLPProblemStandardForm(A, b, c, **kwds) @@ -2062,22 +2001,13 @@ def add_constraint(self, coefficients, constant_term, slack_variable=None): else: problem_type = self.problem_type() if slack_variable is None: - slack_variable = default_variable_name( - "primal slack" if self._is_primal else "dual slack") + slack_variable = default_variable_name("primal slack" if self._is_primal else "dual slack") if style() == "UAlberta": index = self.n() + self.m() + 1 if style() == 'Vanderbei': index = self.m() + 1 slack_variable = "{}{:d}".format(slack_variable, index) - return InteractiveLPProblemStandardForm( - A, b, c, x, - problem_type=problem_type, - slack_variables=tuple(self.slack_variables()) + (slack_variable,), - auxiliary_variable=self.auxiliary_variable(), - base_ring=self.base_ring(), - is_primal=self._is_primal, - objective_name=self._objective_name, - objective_constant_term=self.objective_constant_term()) + return InteractiveLPProblemStandardForm(A, b, c, x, problem_type=problem_type, slack_variables=tuple(self.slack_variables()) + (slack_variable,), auxiliary_variable=self.auxiliary_variable(), base_ring=self.base_ring(), is_primal=self._is_primal, objective_name=self._objective_name, objective_constant_term=self.objective_constant_term()) def auxiliary_problem(self, objective_name=None): r""" @@ -2114,17 +2044,13 @@ def auxiliary_problem(self, objective_name=None): X = self.coordinate_ring().gens() m, n = self.m(), self.n() if len(X) == m + n: - raise ValueError("auxiliary variable is already among decision " - "ones") + raise ValueError("auxiliary variable is already among decision " "ones") F = self.base_ring() A = column_matrix(F, [-1] * m).augment(self.A()) c = vector(F, [-1] + [0] * n) if objective_name is None: objective_name = default_variable_name("auxiliary objective") - return InteractiveLPProblemStandardForm( - A, self.b(), c, - X[:-m], slack_variables=X[-m:], auxiliary_variable=X[0], - objective_name=objective_name) + return InteractiveLPProblemStandardForm(A, self.b(), c, X[:-m], slack_variables=X[-m:], auxiliary_variable=X[0], objective_name=objective_name) def auxiliary_variable(self): r""" @@ -2265,7 +2191,7 @@ def feasible_dictionary(self, auxiliary_dictionary): B = tuple(B) N = tuple(N) k = N.index(x0) - N = N[:k] + N[k+1:] + N = N[:k] + N[k + 1 :] n = len(c) A = A.matrix_from_columns(list(range(k)) + list(range(k + 1, n))) b = copy(b) @@ -2369,8 +2295,7 @@ def initial_dictionary(self): A, b, c, x = self.Abcx() x = self._R.gens() m, n = self.m(), self.n() - return LPDictionary(A, b, c, self._constant_term, x[-m:], x[-m-n:-m], - self.objective_name()) + return LPDictionary(A, b, c, self._constant_term, x[-m:], x[-m - n : -m], self.objective_name()) def inject_variables(self, scope=None, verbose=True): r""" @@ -2535,10 +2460,8 @@ def run_revised_simplex_method(self): else: v = d.objective_value() if self._is_negative: - v = - v - output.append(("The optimal value: ${}$. " - "An optimal solution: ${}$.").format( - latex(v), latex(d.basic_solution()))) + v = -v + output.append(("The optimal value: ${}$. " "An optimal solution: ${}$.").format(latex(v), latex(d.basic_solution()))) self._final_revised_dictionary = d return HtmlFragment("\n".join(output)) @@ -2593,8 +2516,7 @@ def run_simplex_method(self): d = self.initial_dictionary() if not d.is_feasible(): output.append(d._html_()) - output.append("The initial dictionary is infeasible, " - "solving auxiliary problem.") + output.append("The initial dictionary is infeasible, " "solving auxiliary problem.") # Phase I ad = self.auxiliary_problem().initial_dictionary() ad.enter(self.auxiliary_variable()) @@ -2612,10 +2534,8 @@ def run_simplex_method(self): if d.is_optimal(): v = d.objective_value() if self._is_negative: - v = - v - output.append(("The optimal value: ${}$. " - "An optimal solution: ${}$.").format( - latex(v), latex(d.basic_solution()))) + v = -v + output.append(("The optimal value: ${}$. " "An optimal solution: ${}$.").format(latex(v), latex(d.basic_solution()))) self._final_dictionary = d return HtmlFragment("\n".join(output)) @@ -2644,7 +2564,7 @@ def slack_variables(self): sage: P.slack_variables() (L, F) """ - return self._R.gens()[-self.m():] + return self._R.gens()[-self.m() :] class LPAbstractDictionary(SageObject): @@ -2854,10 +2774,9 @@ def basic_solution(self, include_slack_variables=False): vv = list(zip(self.basic_variables(), self.constant_terms())) N = self.nonbasic_variables() vv += [(v, 0) for v in N] - vv.sort() # We use neglex order + vv.sort() # We use neglex order v = [value for _, value in vv] - return vector(self.base_ring(), - v if include_slack_variables else v[:len(N)]) + return vector(self.base_ring(), v if include_slack_variables else v[: len(N)]) @abstract_method def column_coefficients(self, v): @@ -2963,9 +2882,7 @@ def dual_ratios(self): sage: D.dual_ratios() [(5/2, x1), (5, x4)] """ - return [(c / a, x) for c, a, x in zip(self.objective_coefficients(), - self.leaving_coefficients(), - self.nonbasic_variables()) if a < 0] + return [(c / a, x) for c, a, x in zip(self.objective_coefficients(), self.leaving_coefficients(), self.nonbasic_variables()) if a < 0] def enter(self, v): r""" @@ -3052,8 +2969,7 @@ def entering_coefficients(self): (1, 3) """ if self._entering is None: - raise ValueError("entering variable must be chosen to compute " - "its coefficients") + raise ValueError("entering variable must be chosen to compute " "its coefficients") return self.column_coefficients(self._entering) def is_dual_feasible(self) -> bool: @@ -3225,8 +3141,7 @@ def leaving_coefficients(self): (-2, -1) """ if self._leaving is None: - raise ValueError("leaving variable must be chosen to compute " - "its coefficients") + raise ValueError("leaving variable must be chosen to compute " "its coefficients") return self.row_coefficients(self._leaving) @abstract_method @@ -3328,8 +3243,7 @@ def possible_dual_simplex_method_steps(self): [(x3, [x1])] """ if not self.is_dual_feasible(): - raise ValueError("dual simplex method steps are applicable to " - "dual feasible dictionaries only") + raise ValueError("dual simplex method steps are applicable to " "dual feasible dictionaries only") steps = [] old_entering = self._entering self._entering = None @@ -3370,11 +3284,8 @@ def possible_entering(self): min_ratio = min(ratios)[0] return [v for r, v in ratios if r == min_ratio] if self.is_feasible(): - return [v for c, v in zip(self.objective_coefficients(), - self.nonbasic_variables()) if c > 0] - raise ValueError("entering variables can be determined for feasible " - "dictionaries or for dual feasible dictionaries " - "with a set leaving variable") + return [v for c, v in zip(self.objective_coefficients(), self.nonbasic_variables()) if c > 0] + raise ValueError("entering variables can be determined for feasible " "dictionaries or for dual feasible dictionaries " "with a set leaving variable") def possible_leaving(self): r""" @@ -3407,11 +3318,8 @@ def possible_leaving(self): min_ratio = min(ratios)[0] return [v for r, v in ratios if r == min_ratio] if self.is_dual_feasible(): - return [v for b, v in zip(self.constant_terms(), - self.basic_variables()) if b < 0] - raise ValueError("leaving variables can be determined for feasible " - "dictionaries with a set entering variable " - "or for dual feasible dictionaries") + return [v for b, v in zip(self.constant_terms(), self.basic_variables()) if b < 0] + raise ValueError("leaving variables can be determined for feasible " "dictionaries with a set entering variable " "or for dual feasible dictionaries") def possible_simplex_method_steps(self): r""" @@ -3439,8 +3347,7 @@ def possible_simplex_method_steps(self): [(x1, [x4]), (x2, [x3])] """ if not self.is_feasible(): - raise ValueError("simplex method steps are applicable to feasible " - "dictionaries only") + raise ValueError("simplex method steps are applicable to feasible " "dictionaries only") steps = [] old_entering = self._entering old_leaving = self._leaving @@ -3486,9 +3393,7 @@ def ratios(self): sage: D.ratios() [(1000, x3), (500, x4)] """ - return [(b / a, x) for b, a, x in zip(self.constant_terms(), - self.entering_coefficients(), - self.basic_variables()) if a > 0] + return [(b / a, x) for b, a, x in zip(self.constant_terms(), self.entering_coefficients(), self.basic_variables()) if a > 0] @abstract_method def row_coefficients(self, v): @@ -3595,8 +3500,7 @@ def run_dual_simplex_method(self): self.enter(min(possible)) output.append(self._html_()) if self.entering() is None: - output.append("The problem is infeasible because of " - "${}$ constraint.".format(latex(self.leaving()))) + output.append("The problem is infeasible because of " "${}$ constraint.".format(latex(self.leaving()))) break output.append(self._preupdate_output("dual")) self.update() @@ -3675,8 +3579,7 @@ def run_simplex_method(self): self.leave(min(possible)) output.append(self._html_()) if self.leaving() is None: - output.append("The problem is unbounded in ${}$ direction." - .format(latex(self.entering()))) + output.append("The problem is unbounded in ${}$ direction.".format(latex(self.entering()))) break output.append(self._preupdate_output("primal")) self.update() @@ -3771,9 +3674,7 @@ class LPDictionary(LPAbstractDictionary): True """ - def __init__(self, A, b, c, objective_value, - basic_variables, nonbasic_variables, - objective_name): + def __init__(self, A, b, c, objective_value, basic_variables, nonbasic_variables, objective_name): r""" See :class:`LPDictionary` for documentation. @@ -3853,11 +3754,11 @@ def random_element(m, n, bound=5, special_probability=0.2): A = random_matrix(ZZ, m, n, x=-bound, y=bound).change_ring(QQ) if special_probability < random(): b = random_vector(ZZ, m, x=0, y=bound).change_ring(QQ) - else: # Allow infeasible dictionary + else: # Allow infeasible dictionary b = random_vector(ZZ, m, x=-bound, y=bound).change_ring(QQ) if special_probability < random(): c = random_vector(ZZ, n, x=-bound, y=bound).change_ring(QQ) - else: # Make dual feasible dictionary + else: # Make dual feasible dictionary c = random_vector(ZZ, n, x=-bound, y=0).change_ring(QQ) x_N = list(PolynomialRing(QQ, "x", m + n + 1, order='neglex').gens()) x_N.pop(0) @@ -3899,8 +3800,7 @@ def __eq__(self, other): sage: D2 == D3 False """ - return (isinstance(other, LPDictionary) and - self._AbcvBNz == other._AbcvBNz) + return isinstance(other, LPDictionary) and self._AbcvBNz == other._AbcvBNz def _latex_(self): r""" @@ -3931,20 +3831,17 @@ def _latex_(self): lines.append(r"\renewcommand{\arraystretch}{1.5} %notruncate") if generate_real_LaTeX: lines[-1] += r" \setlength{\arraycolsep}{0.125em}" - relations = [_latex_product(-Ai, N, head=[xi, "=", bi], - drop_plus=False, allow_empty=True) + r"\\" - for xi, bi, Ai in zip(B, b, A.rows())] - objective = _latex_product(c, N, head=[z, "=", v], - drop_plus=False, allow_empty=True) + r"\\" + relations = [_latex_product(-Ai, N, head=[xi, "=", bi], drop_plus=False, allow_empty=True) + r"\\" for xi, bi, Ai in zip(B, b, A.rows())] + objective = _latex_product(c, N, head=[z, "=", v], drop_plus=False, allow_empty=True) + r"\\" if style() == "UAlberta": - lines.append(r"\begin{array}{|rcr%s|}" % ("cr"*len(N))) + lines.append(r"\begin{array}{|rcr%s|}" % ("cr" * len(N))) lines.append(r"\hline") lines.extend(relations) lines.append(r"\hline") lines.append(objective) lines.append(r"\hline") if style() == "Vanderbei": - lines.append(r"\begin{array}{rcr%s}" % ("cr"*len(N))) + lines.append(r"\begin{array}{rcr%s}" % ("cr" * len(N))) lines.append(objective) lines.append(r"\hline") lines.extend(relations) @@ -4023,8 +3920,7 @@ def add_row(self, nonbasic_coefficients, constant, basic_variable=None): if not isinstance(basic_variable, str): basic_variable = str(basic_variable) - R = PolynomialRing( - BR, list(B.base_ring().variable_names()) + [basic_variable], order='neglex') + R = PolynomialRing(BR, list(B.base_ring().variable_names()) + [basic_variable], order='neglex') B = list(B) + [basic_variable] B = map(R, B) N = map(R, N) @@ -4240,8 +4136,7 @@ def update(self): e = tuple(N).index(entering) Ale = A[l, e] if Ale == 0: - raise ValueError("incompatible choice of entering and leaving " - "variables") + raise ValueError("incompatible choice of entering and leaving " "variables") # Variables B[l] = entering N[e] = leaving @@ -4400,8 +4295,7 @@ def __init__(self, problem, basic_variables): sage: TestSuite(D).run() """ if problem.auxiliary_variable() == problem.decision_variables()[0]: - raise ValueError("revised dictionaries should not be constructed " - "for auxiliary problems") + raise ValueError("revised dictionaries should not be constructed " "for auxiliary problems") super().__init__() self._problem = problem R = problem.coordinate_ring() @@ -4439,9 +4333,7 @@ def __eq__(self, other): sage: D1 == D3 False """ - return (isinstance(other, LPRevisedDictionary) and - self._problem == other._problem and - self._x_B == other._x_B) + return isinstance(other, LPRevisedDictionary) and self._problem == other._problem and self._x_B == other._x_B def _latex_(self): r""" @@ -4489,15 +4381,14 @@ def _latex_(self): if leaving is not None: l = x_B.list().index(leaving) lines = [] - lines.append(r"\begin{array}{l|r|%s||r||r%s%s}" % ("r"*m, - "|r" if entering is not None else "", "|r" if show_ratios else "")) + lines.append(r"\begin{array}{l|r|%s||r||r%s%s}" % ("r" * m, "|r" if entering is not None else "", "|r" if show_ratios else "")) headers = ["x_B", "c_B"] if generate_real_LaTeX: headers.append(r"\multicolumn{%d}{c||}{B^{-1}}" % m) else: - headers.extend([""] * (m//2)) + headers.extend([""] * (m // 2)) headers.append(r"\mspace{-16mu} B^{-1}") - headers.extend([""] * ((m-1)//2)) + headers.extend([""] * ((m - 1) // 2)) headers.extend(["y", "B^{-1} b"]) if entering is not None: headers.append("B^{-1} A_{%s}" % latex(entering)) @@ -4553,13 +4444,10 @@ def make_line(header, terms): make_line("c_N^T - y^T A_N", self.objective_coefficients()) if leaving is not None and self.is_dual_feasible(): lines.append(r"\hline") - make_line("B^{-1}_{%s} A_N" % latex(leaving), - self.leaving_coefficients()) + make_line("B^{-1}_{%s} A_N" % latex(leaving), self.leaving_coefficients()) lines.append(r"\hline") ratios = self.dual_ratios() - make_line(r"\hbox{Ratio}", [ratios.pop(0)[0] - if ratios and ratios[0][1] == x else "" - for x in x_N]) + make_line(r"\hbox{Ratio}", [ratios.pop(0)[0] if ratios and ratios[0][1] == x else "" for x in x_N]) lines.append(r"\end{array}") bottom = "\n".join(lines) return _assemble_arrayl([top, "", bottom], 1.5) @@ -4600,13 +4488,7 @@ def _preupdate_output(self, direction): \end{array}\right) \end{equation*} """ - return HtmlFragment("\n".join([ - super()._preupdate_output(direction), - r"\begin{equation*}", - r"B_\mathrm{new}^{-1} = E^{-1} B_\mathrm{old}^{-1} = ", - latex(self.E_inverse()), - latex(self.B_inverse()), - r"\end{equation*}"])) + return HtmlFragment("\n".join([super()._preupdate_output(direction), r"\begin{equation*}", r"B_\mathrm{new}^{-1} = E^{-1} B_\mathrm{old}^{-1} = ", latex(self.E_inverse()), latex(self.B_inverse()), r"\end{equation*}"])) def A(self, v): r""" @@ -4662,8 +4544,7 @@ def A_N(self): [1 1] [3 1] """ - return column_matrix(self.problem().base_ring(), - [self.A(x) for x in self.x_N()]) + return column_matrix(self.problem().base_ring(), [self.A(x) for x in self.x_N()]) def B(self): r""" @@ -4683,8 +4564,7 @@ def B(self): [1 1] [3 1] """ - return column_matrix(self.problem().base_ring(), - [self.A(x) for x in self._x_B]) + return column_matrix(self.problem().base_ring(), [self.A(x) for x in self._x_B]) def B_inverse(self): r""" @@ -4736,12 +4616,10 @@ def E(self): [0 3] """ if self._entering is None: - raise ValueError("entering variable must be set to compute the " - "eta matrix") + raise ValueError("entering variable must be set to compute the " "eta matrix") leaving = self._leaving if leaving is None: - raise ValueError("leaving variable must be set to compute the " - "eta matrix") + raise ValueError("leaving variable must be set to compute the " "eta matrix") l = self._x_B.list().index(leaving) E = identity_matrix(self.base_ring(), self.problem().m()) E.set_column(l, self.entering_coefficients()) @@ -4773,9 +4651,8 @@ def E_inverse(self): l = self._x_B.list().index(self._leaving) d = E[l, l] if d == 0: - raise ValueError("eta matrix is not invertible due to incompatible " - "choice of entering and leaving variables") - E.set_col_to_multiple_of_col(l, l, -1/d) + raise ValueError("eta matrix is not invertible due to incompatible " "choice of entering and leaving variables") + E.set_col_to_multiple_of_col(l, l, -1 / d) E[l, l] = 1 / d return E @@ -4856,13 +4733,8 @@ def add_row(self, nonbasic_coefficients, constant, basic_variable=None): else: nbc_decision[i - 1] = coef if 0 in self.basic_indices() and not sum(nbc_slack) == -1: - raise ValueError( - "the sum of coefficients of nonbasic slack variables has to " - "be equal to -1 when inserting a row into a dictionary for " - "the auxiliary problem") - P_new = P.add_constraint(nbc_decision - nbc_slack * P.A(), - constant - nbc_slack * P.b(), - basic_variable) + raise ValueError("the sum of coefficients of nonbasic slack variables has to " "be equal to -1 when inserting a row into a dictionary for " "the auxiliary problem") + P_new = P.add_constraint(nbc_decision - nbc_slack * P.A(), constant - nbc_slack * P.b(), basic_variable) x_B = list(self.x_B()) + [P_new.slack_variables()[-1]] return P_new.revised_dictionary(*x_B) @@ -4960,8 +4832,7 @@ def c_N(self): if 0 in self.basic_indices(): return vector(R, n + 1) c_D = P.c() - return vector(R, (c_D[k - 1] if k <= n else 0 - for k in self.nonbasic_indices())) + return vector(R, (c_D[k - 1] if k <= n else 0 for k in self.nonbasic_indices())) def column_coefficients(self, v): r""" @@ -5024,13 +4895,7 @@ def dictionary(self): sage: D.dictionary() LP problem dictionary (use ...) """ - D = LPDictionary(self.B_inverse() * self.A_N(), - self.constant_terms(), - self.objective_coefficients(), - self.objective_value(), - self.basic_variables(), - self.nonbasic_variables(), - self.problem().objective_name()) + D = LPDictionary(self.B_inverse() * self.A_N(), self.constant_terms(), self.objective_coefficients(), self.objective_value(), self.basic_variables(), self.nonbasic_variables(), self.problem().objective_name()) D._entering = self._entering D._leaving = self._leaving return D @@ -5137,8 +5002,7 @@ def objective_value(self): sage: D.objective_value() 0 """ - return (self.y() * self.problem().b() + - self.problem().objective_constant_term()) + return self.y() * self.problem().b() + self.problem().objective_constant_term() def problem(self): r""" diff --git a/src/sage/numerical/knapsack.py b/src/sage/numerical/knapsack.py index c0fc724c4c6..677eca1b17b 100644 --- a/src/sage/numerical/knapsack.py +++ b/src/sage/numerical/knapsack.py @@ -277,6 +277,7 @@ def largest_less_than(self, N): ValueError: seq must be a super-increasing sequence """ from sage.functions.other import Function_floor + floor = Function_floor() # input error handling if len(self._seq) == 0: @@ -542,8 +543,7 @@ def subset_sum(self, N): return [] -def knapsack(seq, binary=True, max=1, value_only=False, solver=None, verbose=0, - *, integrality_tolerance=1e-3): +def knapsack(seq, binary=True, max=1, value_only=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Solve the knapsack problem. @@ -627,7 +627,7 @@ def knapsack(seq, binary=True, max=1, value_only=False, solver=None, verbose=0, """ reals = not isinstance(seq[0], tuple) if reals: - seq = [(x,1) for x in seq] + seq = [(x, 1) for x in seq] from sage.numerical.mip import MixedIntegerLinearProgram from sage.rings.integer_ring import ZZ @@ -655,4 +655,4 @@ def knapsack(seq, binary=True, max=1, value_only=False, solver=None, verbose=0, else: [val.extend([seq[i]] * present[i]) for i in range(len(seq))] - return [objective,val] + return [objective, val] diff --git a/src/sage/numerical/linear_tensor.py b/src/sage/numerical/linear_tensor.py index 4737b88d760..e1b9186b871 100644 --- a/src/sage/numerical/linear_tensor.py +++ b/src/sage/numerical/linear_tensor.py @@ -154,6 +154,7 @@ def LinearTensorParent(free_module_parent, linear_functions_parent): # # **************************************************************************** + class LinearTensorParent_class(Parent): r""" The parent for all linear functions over a fixed base ring. @@ -171,6 +172,7 @@ class LinearTensorParent_class(Parent): sage: LinearTensorParent_class """ + Element = LinearTensor def __init__(self, free_module, linear_functions): @@ -190,6 +192,7 @@ def __init__(self, free_module, linear_functions): self._linear_functions = linear_functions base_ring = linear_functions.base_ring() from sage.categories.modules_with_basis import ModulesWithBasis + Parent.__init__(self, base=base_ring, category=ModulesWithBasis(base_ring)) def free_module(self): @@ -231,6 +234,7 @@ def is_vector_space(self): False """ from sage.modules.free_module import FreeModule_generic + return isinstance(self.free_module(), FreeModule_generic) def is_matrix_space(self): @@ -250,6 +254,7 @@ def is_matrix_space(self): True """ from sage.matrix.matrix_space import MatrixSpace + return isinstance(self.free_module(), MatrixSpace) def linear_functions(self): diff --git a/src/sage/numerical/linear_tensor_constraints.py b/src/sage/numerical/linear_tensor_constraints.py index c53b97b9453..b9012634e57 100644 --- a/src/sage/numerical/linear_tensor_constraints.py +++ b/src/sage/numerical/linear_tensor_constraints.py @@ -19,6 +19,7 @@ [0 0 0] <= [0 x_0 + x_1 0 ] [0 0 0] [x_0 0 x_1] """ + # **************************************************************************** # Copyright (C) 2014 Volker Braun # @@ -39,6 +40,7 @@ # # *************************************************************************** + @cached_function def LinearTensorConstraintsParent(linear_functions_parent): """ @@ -76,6 +78,7 @@ def LinearTensorConstraintsParent(linear_functions_parent): # # **************************************************************************** + class LinearTensorConstraint(Element): """ Formal constraint involving two module-valued linear functions. @@ -222,6 +225,7 @@ def _ascii_art_(self): def matrix_art(m): lines = str(m).splitlines() return AsciiArt(lines, baseline=len(lines) // 2) + comparator = AsciiArt([' == ' if self.is_equation() else ' <= ']) return matrix_art(self.lhs()) + comparator + matrix_art(self.rhs()) @@ -245,15 +249,16 @@ def _repr_(self): """ if self.parent().linear_tensors().is_matrix_space(): return str(self._ascii_art_()) - comparator = (' == ' if self.is_equation() else ' <= ') + comparator = ' == ' if self.is_equation() else ' <= ' return str(self.lhs()) + comparator + str(self.rhs()) -#***************************************************************************** +# ***************************************************************************** # # Parent of linear constraints # -#***************************************************************************** +# ***************************************************************************** + class LinearTensorConstraintsParent_class(Parent): """ @@ -282,6 +287,7 @@ class LinearTensorConstraintsParent_class(Parent): sage: type(LTC) """ + Element = LinearTensorConstraint def __init__(self, linear_tensor_parent): @@ -355,8 +361,7 @@ def _repr_(self): dimension 2 over Real Double Field and Linear functions over Real Double Field """ - return 'Linear constraints in the tensor product of {0} and {1}'.format( - self.linear_tensors().free_module(), self.linear_functions()) + return 'Linear constraints in the tensor product of {0} and {1}'.format(self.linear_tensors().free_module(), self.linear_functions()) def _element_constructor_(self, left, right, equality): """ diff --git a/src/sage/numerical/optimize.py b/src/sage/numerical/optimize.py index b6fd4825ab3..a807e8769f4 100644 --- a/src/sage/numerical/optimize.py +++ b/src/sage/numerical/optimize.py @@ -101,7 +101,7 @@ def find_root(f, a, b, xtol=10e-13, rtol=2.0**-50, maxiter=100, full_output=Fals RuntimeError: f appears to have no zero on the interval """ try: - return f.find_root(a=a,b=b,xtol=xtol,rtol=rtol,maxiter=maxiter,full_output=full_output) + return f.find_root(a=a, b=b, xtol=xtol, rtol=rtol, maxiter=maxiter, full_output=full_output) except AttributeError: pass a = float(a) @@ -123,7 +123,7 @@ def find_root(f, a, b, xtol=10e-13, rtol=2.0**-50, maxiter=100, full_output=Fals raise RuntimeError("f appears to have no zero on the interval") # If we found such an s, then we just instead find # a root between left and s or s and right. - a = s # arbitrary choice -- maybe should try both and take one that works? + a = s # arbitrary choice -- maybe should try both and take one that works? elif left < 0 and right < 0: # Refine further @@ -144,20 +144,19 @@ def find_root(f, a, b, xtol=10e-13, rtol=2.0**-50, maxiter=100, full_output=Fals if (left != left) or (right != right): minval, s_1 = find_local_minimum(f, a, b) maxval, s_2 = find_local_maximum(f, a, b) - if ((minval > 0) or (maxval < 0) or - (minval != minval) or (maxval != maxval)): + if (minval > 0) or (maxval < 0) or (minval != minval) or (maxval != maxval): raise RuntimeError("f appears to have no zero on the interval") a = min(s_1, s_2) b = max(s_1, s_2) import scipy.optimize import numpy + if int(numpy.version.short_version[0]) > 1: numpy.set_printoptions(legacy="1.25") g = lambda x: float(f(x)) - brentqRes = scipy.optimize.brentq(g, a, b, - full_output=full_output, xtol=xtol, rtol=rtol, maxiter=maxiter) + brentqRes = scipy.optimize.brentq(g, a, b, full_output=full_output, xtol=xtol, rtol=rtol, maxiter=maxiter) # A check following :issue:`4942`, to ensure we actually found a root # Maybe should use a different tolerance here? # The idea is to take roughly the derivative and multiply by estimated @@ -287,6 +286,7 @@ def find_local_minimum(f, a, b, tol=1.48e-08, maxfun=500): b = float(b) import scipy.optimize import numpy + if int(numpy.version.short_version[0]) > 1: numpy.set_printoptions(legacy="1.25") @@ -294,8 +294,7 @@ def find_local_minimum(f, a, b, tol=1.48e-08, maxfun=500): return fval, xmin -def minimize(func, x0, gradient=None, hessian=None, algorithm='default', - verbose=False, **args): +def minimize(func, x0, gradient=None, hessian=None, algorithm='default', verbose=False, **args): r""" This function is an interface to a variety of algorithms for computing the minimum of a function of several variables. @@ -397,20 +396,20 @@ def minimize(func, x0, gradient=None, hessian=None, algorithm='default', from sage.structure.element import Expression from sage.ext.fast_callable import fast_callable import numpy + if int(numpy.version.short_version[0]) > 1: numpy.set_printoptions(legacy="1.25") from scipy import optimize + if isinstance(func, Expression): var_list = func.variables() var_names = [str(_) for _ in var_list] fast_f = fast_callable(func, vars=var_names, domain=float) f = lambda p: fast_f(*p) gradient_list = func.gradient() - fast_gradient_functions = [fast_callable(gradient_list[i], - vars=var_names, domain=float) - for i in range(len(gradient_list))] - gradient = lambda p: numpy.array([ a(*p) for a in fast_gradient_functions]) + fast_gradient_functions = [fast_callable(gradient_list[i], vars=var_names, domain=float) for i in range(len(gradient_list))] + gradient = lambda p: numpy.array([a(*p) for a in fast_gradient_functions]) else: f = func @@ -418,7 +417,7 @@ def minimize(func, x0, gradient=None, hessian=None, algorithm='default', if gradient is None: min = optimize.fmin(f, [float(_) for _ in x0], disp=verbose, **args) else: - min = optimize.fmin_bfgs(f, [float(_) for _ in x0],fprime=gradient, disp=verbose, **args) + min = optimize.fmin_bfgs(f, [float(_) for _ in x0], fprime=gradient, disp=verbose, **args) else: if algorithm == "simplex": min = optimize.fmin(f, [float(_) for _ in x0], disp=verbose, **args) @@ -431,12 +430,12 @@ def minimize(func, x0, gradient=None, hessian=None, algorithm='default', elif algorithm == "ncg": if isinstance(func, Expression): hess = func.hessian() - hess_fast = [ [fast_callable(a, vars=var_names, domain=float) for a in row] for row in hess] + hess_fast = [[fast_callable(a, vars=var_names, domain=float) for a in row] for row in hess] hessian = lambda p: [[a(*p) for a in row] for row in hess_fast] from numpy import dot - hessian_p = lambda p,v: dot(numpy.array(hessian(p)),v) - min = optimize.fmin_ncg(f, [float(_) for _ in x0], fprime=gradient, - fhess=hessian, fhess_p=hessian_p, disp=verbose, **args) + + hessian_p = lambda p, v: dot(numpy.array(hessian(p)), v) + min = optimize.fmin_ncg(f, [float(_) for _ in x0], fprime=gradient, fhess=hessian, fhess_p=hessian_p, disp=verbose, **args) return vector(RDF, min) @@ -536,27 +535,25 @@ def minimize_constrained(func, cons, x0, gradient=None, algorithm='default', **a from sage.structure.element import Expression from sage.ext.fast_callable import fast_callable import numpy + if int(numpy.version.short_version[0]) > 1: numpy.set_printoptions(legacy="1.25") from scipy import optimize - function_type = type(lambda x,y: x+y) + + function_type = type(lambda x, y: x + y) if isinstance(func, Expression): var_list = func.arguments() fast_f = fast_callable(func, vars=var_list, domain=float) f = lambda p: fast_f(*p) gradient_list = func.gradient() - fast_gradient_functions = [ fast_callable(gi, - vars=var_list, - domain=float) - for gi in gradient_list ] - gradient = lambda p: numpy.array([ a(*p) for a in fast_gradient_functions]) + fast_gradient_functions = [fast_callable(gi, vars=var_list, domain=float) for gi in gradient_list] + gradient = lambda p: numpy.array([a(*p) for a in fast_gradient_functions]) if isinstance(cons, Expression): fast_cons = fast_callable(cons, vars=var_list, domain=float) cons = lambda p: numpy.array([fast_cons(*p)]) elif isinstance(cons, list) and isinstance(cons[0], Expression): - fast_cons = [ fast_callable(ci, vars=var_list, domain=float) - for ci in cons ] + fast_cons = [fast_callable(ci, vars=var_list, domain=float) for ci in cons] cons = lambda p: numpy.array([a(*p) for a in fast_cons]) else: f = func @@ -659,6 +656,7 @@ def find_fit(data, model, initial_guess=None, parameters=None, variables=None, s ``lmdif`` and ``lmder`` algorithms. """ import numpy + if int(numpy.version.short_version[0]) > 1: numpy.set_printoptions(legacy="1.25") @@ -686,8 +684,7 @@ def find_fit(data, model, initial_guess=None, parameters=None, variables=None, s if data.shape[1] != len(variables) + 1: raise ValueError("each row of data needs %d entries, only %d entries given" % (len(variables) + 1, data.shape[1])) - if parameters is None or len(parameters) == 0 or \ - variables is None or len(variables) == 0: + if parameters is None or len(parameters) == 0 or variables is None or len(variables) == 0: raise ValueError("no variables given") if initial_guess is None: @@ -706,6 +703,7 @@ def find_fit(data, model, initial_guess=None, parameters=None, variables=None, s if isinstance(model, Expression): from sage.ext.fast_callable import fast_callable + var_list = variables + parameters func = fast_callable(model, vars=var_list, domain=float) else: @@ -725,12 +723,12 @@ def error_function(params, x_data, y_data): result[row] = func(*fparams) return result - y_data - x_data = data[:, 0:len(variables)] + x_data = data[:, 0 : len(variables)] y_data = data[:, -1] from scipy.optimize import leastsq - estimated_params, d = leastsq(error_function, initial_guess, - args=(x_data, y_data)) + + estimated_params, d = leastsq(error_function, initial_guess, args=(x_data, y_data)) if isinstance(estimated_params, float): estimated_params = [estimated_params] @@ -743,8 +741,7 @@ def error_function(params, x_data, y_data): return [item[0] == item[1] for item in zip(parameters, estimated_params)] -def binpacking(items, maximum=1, k=None, solver=None, verbose=0, - *, integrality_tolerance=1e-3): +def binpacking(items, maximum=1, k=None, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" Solve the bin packing problem. @@ -868,16 +865,18 @@ def binpacking(items, maximum=1, k=None, solver=None, verbose=0, if k is None: from sage.functions.other import ceil - k = ceil(sum(weight.values())/maximum) + + k = ceil(sum(weight.values()) / maximum) while True: from sage.numerical.mip import MIPSolverException + try: - return binpacking(items, k=k, maximum=maximum, solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + return binpacking(items, k=k, maximum=maximum, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) except MIPSolverException: k = k + 1 from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException + p = MixedIntegerLinearProgram(solver=solver) # Boolean variable indicating whether the ith element belongs to box b @@ -885,11 +884,11 @@ def binpacking(items, maximum=1, k=None, solver=None, verbose=0, # Capacity constraint of each bin for b in range(k): - p.add_constraint(p.sum(weight[i]*box[i,b] for i in weight) <= maximum) + p.add_constraint(p.sum(weight[i] * box[i, b] for i in weight) <= maximum) # Each item is assigned exactly one bin for i in weight: - p.add_constraint(p.sum(box[i,b] for b in range(k)) == 1) + p.add_constraint(p.sum(box[i, b] for b in range(k)) == 1) try: p.solve(log=verbose) @@ -900,8 +899,8 @@ def binpacking(items, maximum=1, k=None, solver=None, verbose=0, boxes = [[] for i in range(k)] - for i,b in box: - if box[i,b]: + for i, b in box: + if box[i, b]: boxes[b].append(weight[i] if isinstance(items, list) else i) return boxes diff --git a/src/sage/parallel/all.py b/src/sage/parallel/all.py index dbb6ba2c851..77d076f0c19 100644 --- a/src/sage/parallel/all.py +++ b/src/sage/parallel/all.py @@ -1,5 +1,5 @@ - from sage.parallel.decorate import parallel, fork from sage.misc.lazy_import import lazy_import + lazy_import('sage.parallel.parallelism', 'Parallelism') del lazy_import diff --git a/src/sage/parallel/decorate.py b/src/sage/parallel/decorate.py index 0a24f734225..a49a88b122e 100644 --- a/src/sage/parallel/decorate.py +++ b/src/sage/parallel/decorate.py @@ -54,6 +54,7 @@ class Parallel: Create a ``parallel``-decorated function. This is the object created by :func:`parallel`. """ + def __init__(self, p_iter='fork', ncpus=None, **kwds): """ EXAMPLES:: @@ -71,10 +72,12 @@ def __init__(self, p_iter='fork', ncpus=None, **kwds): if ncpus is None: from .ncpus import ncpus as compute_ncpus + ncpus = compute_ncpus() if p_iter == 'fork': from .use_fork import p_iter_fork + self.p_iter = p_iter_fork(ncpus, **kwds) elif p_iter == 'multiprocessing': self.p_iter = multiprocessing_sage.pyprocessing(ncpus) @@ -124,6 +127,7 @@ class ParallelFunction: This is typically accessed indirectly through :meth:`Parallel.__call__`. """ + def __init__(self, parallel, func): """ .. NOTE:: @@ -157,8 +161,7 @@ def __call__(self, *args, **kwds): [(((2,), {}), 4), (((3,), {}), 9)] """ if len(args) > 0 and isinstance(args[0], (list, types.GeneratorType)): - return self.parallel.p_iter(self.func, (normalize_input(a) - for a in args[0])) + return self.parallel.p_iter(self.func, (normalize_input(a) for a in args[0])) return self.func(*args, **kwds) def __get__(self, instance, owner): @@ -241,6 +244,7 @@ def _sage_argspec_(self): kwonlyargs=[], kwonlydefaults=None, annotations={}) """ from sage.misc.sageinspect import sage_getargspec + return sage_getargspec(self.func) def _sage_src_(self): @@ -261,6 +265,7 @@ def _sage_src_(self): True """ from sage.misc.sageinspect import sage_getsource + return sage_getsource(self.func) def _instancedoc_(self): @@ -431,10 +436,12 @@ def parallel(p_iter='fork', ncpus=None, **kwds): # def f(...): ... ################################################################### + class Fork: """ A ``fork`` decorator class. """ + def __init__(self, timeout=0, verbose=False): """ INPUT: @@ -470,12 +477,12 @@ def __call__(self, f): sage: h(2,3) 5 """ - P = Parallel(p_iter='fork', ncpus=1, timeout=self.timeout, - verbose=self.verbose) + P = Parallel(p_iter='fork', ncpus=1, timeout=self.timeout, verbose=self.verbose) g = P(f) def h(*args, **kwds): return list(g([(args, kwds)]))[0][1] + return h diff --git a/src/sage/parallel/map_reduce.py b/src/sage/parallel/map_reduce.py index 2e3e8b64d05..0d3f4eff583 100644 --- a/src/sage/parallel/map_reduce.py +++ b/src/sage/parallel/map_reduce.py @@ -560,22 +560,20 @@ from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet # _generic logger = logging.getLogger(__name__) -logger.__doc__ = (""" +logger.__doc__ = """ A logger for :mod:`sage.parallel.map_reduce` .. SEEALSO:: `Logging facility for Python `_ for more detail on logging and log system configuration. -""") +""" logger.setLevel(logging.WARN) # logger.setLevel(logging.INFO) # logger.setLevel(logging.DEBUG) ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) -formatter = logging.Formatter( - '[%(processName)s-%(threadName)s] (%(asctime)s.%(msecs)03.f) %(message)s', - datefmt='%H:%M:%S') +formatter = logging.Formatter('[%(processName)s-%(threadName)s] (%(asctime)s.%(msecs)03.f) %(message)s', datefmt='%H:%M:%S') ch.setFormatter(formatter) logger.addHandler(ch) @@ -604,6 +602,7 @@ def proc_number(max_proc=None): True """ from sage.parallel.ncpus import ncpus + n = ncpus() if max_proc is None: return n @@ -624,6 +623,7 @@ class AbortError(Exception): ... AbortError """ + pass @@ -636,6 +636,7 @@ class ActiveTaskCounterDarwin: do not correctly implement POSIX's semaphore semantic. So we use a shared integer with a lock. """ + def __init__(self, task_number): r""" TESTS:: @@ -770,6 +771,7 @@ class ActiveTaskCounterPosix: So there is a non negligible overhead. It will probably be worth it if we try to cythonize the code. So I'm keeping both implementations. """ + def __init__(self, task_number): r""" TESTS:: @@ -877,8 +879,7 @@ def abort(self): pass -ActiveTaskCounter = (ActiveTaskCounterDarwin if sys.platform == 'darwin' - else ActiveTaskCounterPosix) +ActiveTaskCounter = ActiveTaskCounterDarwin if sys.platform == 'darwin' else ActiveTaskCounterPosix # ActiveTaskCounter = ActiveTaskCounterDarwin # to debug Darwin implementation @@ -915,14 +916,8 @@ class RESetMapReduce: :mod:`the Map/Reduce module ` for details and examples. """ - def __init__(self, - roots=None, - children=None, - post_process=None, - map_function=None, - reduce_function=None, - reduce_init=None, - forest=None): + + def __init__(self, roots=None, children=None, post_process=None, map_function=None, reduce_function=None, reduce_init=None, forest=None): r""" TESTS:: @@ -972,12 +967,7 @@ def _forest(self): sage: f.an_element() [] """ - return RecursivelyEnumeratedSet( - self.roots(), - self.children, - post_process=self.post_process, - structure='forest', - enumeration='depth') + return RecursivelyEnumeratedSet(self.roots(), self.children, post_process=self.post_process, structure='forest', enumeration='depth') def roots(self): r""" @@ -1121,8 +1111,7 @@ def setup_workers(self, max_proc=None, reduce_locally=True): self._aborted = mp.Value(ctypes.c_bool, False, lock=False) sys.stdout.flush() sys.stderr.flush() - self._workers = [RESetMapReduceWorker(self, i, reduce_locally) - for i in range(self._nprocess)] + self._workers = [RESetMapReduceWorker(self, i, reduce_locally) for i in range(self._nprocess)] def start_workers(self): r""" @@ -1182,9 +1171,7 @@ def get_results(self, timeout=None): active_proc = self._nprocess while active_proc > 0: try: - logger.debug('Waiting on results; active_proc: {}, ' - 'timeout: {}, aborted: {}'.format( - active_proc, timeout, self._aborted.value)) + logger.debug('Waiting on results; active_proc: {}, ' 'timeout: {}, aborted: {}'.format(active_proc, timeout, self._aborted.value)) newres = self._results.get(timeout=timeout) except queue.Empty: logger.debug('Timed out waiting for results; aborting') @@ -1398,11 +1385,7 @@ def random_worker(self): victim = random.randint(0, len(self._workers) - 1) return self._workers[victim] - def run(self, - max_proc=None, - reduce_locally=True, - timeout=None, - profile=None): + def run(self, max_proc=None, reduce_locally=True, timeout=None, profile=None): r""" Run the computations. @@ -1461,6 +1444,7 @@ def run(self, self.start_workers() if timeout is not None: from threading import Timer + self._timer = Timer(timeout, self.abort) self._timer.start() self.result = self.get_results(timeout=timeout) @@ -1510,12 +1494,11 @@ def print_communication_statistics(self, blocksize=16): # https://stackoverflow.com/questions/2609518/python-nested-function-scopes). def pstat(name, start, end, istat): - res[0] += ("\n" + name + " ".join( - "%4i" % (self._stats[i][istat]) for i in range(start, end))) + res[0] += "\n" + name + " ".join("%4i" % (self._stats[i][istat]) for i in range(start, end)) + for start in range(0, self._nprocess, blocksize): end = min(start + blocksize, self._nprocess) - res[0] = ("#proc: " + - " ".join("%4i" % (i) for i in range(start, end))) + res[0] = "#proc: " + " ".join("%4i" % (i) for i in range(start, end)) pstat("reqs sent: ", start, end, 0) pstat("reqs rcvs: ", start, end, 1) pstat("- thefs: ", start, end, 2) @@ -1534,9 +1517,8 @@ def run_serial(self): 24*x^4 + 6*x^3 + 2*x^2 + x + 1 """ import functools - return functools.reduce(self.reduce_function, - (self.map_function(x) for x in self._forest), - self.reduce_init()) + + return functools.reduce(self.reduce_function, (self.map_function(x) for x in self._forest), self.reduce_init()) class RESetMapReduceWorker(mp.Process): @@ -1563,6 +1545,7 @@ class RESetMapReduceWorker(mp.Process): * ``False`` -- results are sent back after each finished branches, when the process is asking for more work. """ + def __init__(self, mapred, iproc, reduce_locally): r""" TESTS:: @@ -1689,6 +1672,7 @@ def run(self): profile = self._mapred._profile if profile is not None: import cProfile + PROFILER = cProfile.Profile() PROFILER.runcall(self.run_myself) @@ -1857,6 +1841,7 @@ class RESetMPExample(RESetMapReduce): .. SEEALSO:: This is an example of :class:`RESetMapReduce` """ + def __init__(self, maxl=9): r""" TESTS:: @@ -1868,6 +1853,7 @@ def __init__(self, maxl=9): RESetMapReduce.__init__(self) from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring import polygen + self.x = polygen(ZZ, 'x') self.maxl = maxl @@ -1901,8 +1887,7 @@ def children(self, l): sage: RESetMPExample().children([1,0]) [[2, 1, 0], [1, 2, 0], [1, 0, 2]] """ - return [l[:i] + [len(l)] + l[i:] - for i in range(len(l) + 1)] if len(l) < self.maxl else [] + return [l[:i] + [len(l)] + l[i:] for i in range(len(l) + 1)] if len(l) < self.maxl else [] def map_function(self, l): r""" @@ -1922,7 +1907,7 @@ def map_function(self, l): sage: RESetMPExample().map_function([1,0]) x^2 """ - return self.x**len(l) + return self.x ** len(l) class RESetParallelIterator(RESetMapReduce): @@ -1941,6 +1926,7 @@ class RESetParallelIterator(RESetMapReduce): sage: sum(1 for _ in S) 65535 """ + def map_function(self, z): r""" Return a singleton tuple. diff --git a/src/sage/parallel/multiprocessing_sage.py b/src/sage/parallel/multiprocessing_sage.py index ab2ee3f95ee..53fa3f367f2 100644 --- a/src/sage/parallel/multiprocessing_sage.py +++ b/src/sage/parallel/multiprocessing_sage.py @@ -68,8 +68,7 @@ def parallel_iter(processes, f, inputs): p = Pool(processes) fp = pickle_function(f) - result = p.imap_unordered(call_pickled_function, - [(fp, t) for t in inputs]) + result = p.imap_unordered(call_pickled_function, [(fp, t) for t in inputs]) yield from result p.close() p.join() diff --git a/src/sage/parallel/parallelism.py b/src/sage/parallel/parallelism.py index 6df09f58fad..e181b1b8bef 100644 --- a/src/sage/parallel/parallelism.py +++ b/src/sage/parallel/parallelism.py @@ -83,6 +83,7 @@ class Parallelism(Singleton, SageObject): sage: Parallelism().set(nproc=1) """ + def __init__(self): r""" Construct the single instance of class Parallelism (singleton model). @@ -235,8 +236,7 @@ def set(self, field=None, nproc=None): self.set(field=fi, nproc=nproc) else: if field not in self._nproc: - raise KeyError("entry for field {} is not ".format(field) + - "implemented in Parallelism") + raise KeyError("entry for field {} is not ".format(field) + "implemented in Parallelism") if nproc is None: self._nproc[field] = self._default else: @@ -274,8 +274,7 @@ def get(self, field): 4 """ if field not in self._nproc: - raise KeyError("entry for field {} is not ".format(field) + - "implemented in Parallelism()") + raise KeyError("entry for field {} is not ".format(field) + "implemented in Parallelism()") return self._nproc[field] def get_all(self): diff --git a/src/sage/parallel/use_fork.py b/src/sage/parallel/use_fork.py index bd3f789ac2b..94789fcafe7 100644 --- a/src/sage/parallel/use_fork.py +++ b/src/sage/parallel/use_fork.py @@ -48,6 +48,7 @@ class WorkerData: sage: W.starttime # random 1499330252.463206 """ + def __init__(self, input_value, starttime=None, failure=""): r""" See the class documentation for description of the inputs. @@ -89,6 +90,7 @@ class p_iter_fork: sage: X.verbose False """ + def __init__(self, ncpus, timeout=0, verbose=False, reset_interfaces=True, reseed_rng=False): """ Create a ``fork()``-based parallel iterator. @@ -216,6 +218,7 @@ def __call__(self, f, inputs): import signal from sage.misc.persist import loads from sage.misc.temporary_file import tmp_dir + dir = tmp_dir() timeout = self.timeout @@ -225,7 +228,7 @@ def __call__(self, f, inputs): seeds = [getrandbits(512) for _ in range(len(inputs))] vs = list(zip(inputs, seeds)) else: - vs = list(zip(inputs, [None]*len(inputs))) + vs = list(zip(inputs, [None] * len(inputs))) workers = {} try: while vs or workers: @@ -261,8 +264,7 @@ def __call__(self, f, inputs): for pid, W in workers.items(): if T - W.starttime > timeout: if self.verbose: - print( - "Killing subprocess %s with input %s which took too long" % (pid, W.input)) + print("Killing subprocess %s with input %s which took too long" % (pid, W.input)) os.kill(pid, signal.SIGKILL) W.failure = " (timed out)" except KeyError: @@ -350,6 +352,7 @@ def _subprocess(self, f, dir, args, kwds={}): """ import os import sys + try: from importlib import reload except ImportError: @@ -365,6 +368,7 @@ def _subprocess(self, f, dir, args, kwds={}): # pid has changed (forcing a reload of # misc). import sage.misc.misc + reload(sage.misc.misc) # The pexpect interfaces (and objects defined in them) are diff --git a/src/sage/plot/all.py b/src/sage/plot/all.py index 565aa748be4..ba09557001b 100644 --- a/src/sage/plot/all.py +++ b/src/sage/plot/all.py @@ -1,8 +1,5 @@ from sage.plot.graphics import Graphics -from sage.plot.plot import (plot, graphics_array, multi_graphics, list_plot, - parametric_plot, polar_plot, plot_loglog, plot_semilogx, - plot_semilogy, list_plot_loglog, list_plot_semilogx, - list_plot_semilogy) +from sage.plot.plot import plot, graphics_array, multi_graphics, list_plot, parametric_plot, polar_plot, plot_loglog, plot_semilogx, plot_semilogy, list_plot_loglog, list_plot_semilogx, list_plot_semilogy from sage.plot.line import line, line2d from sage.plot.arrow import arrow, arrow2d from sage.plot.bar_chart import bar_chart @@ -22,6 +19,7 @@ from sage.plot.streamline_plot import streamline_plot from sage.misc.lazy_import import lazy_import + lazy_import("sage.plot.complex_plot", ["complex_plot"]) from sage.plot.arc import arc @@ -36,4 +34,5 @@ from sage.plot.hyperbolic_arc import hyperbolic_arc from sage.plot.hyperbolic_polygon import hyperbolic_triangle, hyperbolic_polygon + lazy_import("sage.plot.hyperbolic_regular_polygon", "hyperbolic_regular_polygon") diff --git a/src/sage/plot/animate.py b/src/sage/plot/animate.py index 81afb7b8cd5..5f80caf8316 100644 --- a/src/sage/plot/animate.py +++ b/src/sage/plot/animate.py @@ -235,6 +235,7 @@ class Animation(WithEqualityById, SageObject): sage: hash(Animation()) # random 140658972348064 """ + def __init__(self, v=None, **kwds): r""" Return an animation of a sequence of plots of objects. See @@ -281,8 +282,7 @@ def _combine_kwds(self, *kwds_tuple): new_kwds.update(kwds) for name in ['xmin', 'xmax', 'ymin', 'ymax']: - values = [v for kwds in kwds_tuple - if (v := kwds.get(name, None)) is not None] + values = [v for kwds in kwds_tuple if (v := kwds.get(name, None)) is not None] if values: new_kwds[name] = getattr(builtins, name[1:])(values) return new_kwds @@ -361,9 +361,9 @@ def __add__(self, other): kwds = self._combine_kwds(self._kwds, other._kwds) - #Combine the frames + # Combine the frames m = max(len(self), len(other)) - frames = [a+b for a,b in zip(self._frames, other._frames)] + frames = [a + b for a, b in zip(self._frames, other._frames)] frames += self._frames[m:] + other._frames[m:] return Animation(frames, **kwds) @@ -494,7 +494,7 @@ def png(self, dir=None): dir = tmp_dir() i = 0 for frame in self._frames: - filename = '%s/%08d.png' % (dir,i) + filename = '%s/%08d.png' % (dir, i) try: save_image = frame.save_image except AttributeError: @@ -549,13 +549,12 @@ def graphics_array(self, ncols=3): ncols = int(ncols) frame_list = list(self._frames) n = len(frame_list) - nrows, rem = divmod(n,ncols) + nrows, rem = divmod(n, ncols) if rem > 0: nrows += 1 return plot.graphics_array(frame_list, nrows, ncols) - def gif(self, delay=20, savefile=None, iterations=0, show_path=False, - use_ffmpeg=False): + def gif(self, delay=20, savefile=None, iterations=0, show_path=False, use_ffmpeg=False): r""" Return an animated gif composed from rendering the graphics objects in ``self``. @@ -623,23 +622,14 @@ def gif(self, delay=20, savefile=None, iterations=0, show_path=False, from sage.features.ffmpeg import FFmpeg if not ImageMagick().is_present() and not FFmpeg().is_present(): - raise OSError("Error: Neither ImageMagick nor ffmpeg appear to " - "be installed. Saving an animation to a GIF file or " - "displaying an animation requires one of these " - "packages, so please install one of them and try " - "again. See www.imagemagick.org and www.ffmpeg.org " - "for more information.") + raise OSError("Error: Neither ImageMagick nor ffmpeg appear to " "be installed. Saving an animation to a GIF file or " "displaying an animation requires one of these " "packages, so please install one of them and try " "again. See www.imagemagick.org and www.ffmpeg.org " "for more information.") if use_ffmpeg or not ImageMagick().is_present(): - self.ffmpeg(savefile=savefile, show_path=show_path, - output_format='.gif', delay=delay, - iterations=iterations) + self.ffmpeg(savefile=savefile, show_path=show_path, output_format='.gif', delay=delay, iterations=iterations) else: - self._gif_from_imagemagick(savefile=savefile, show_path=show_path, - delay=delay, iterations=iterations) + self._gif_from_imagemagick(savefile=savefile, show_path=show_path, delay=delay, iterations=iterations) - def _gif_from_imagemagick(self, savefile=None, show_path=False, - delay=20, iterations=0): + def _gif_from_imagemagick(self, savefile=None, show_path=False, delay=20, iterations=0): r""" Return a movie showing an animation composed from rendering the frames in ``self``. @@ -689,6 +679,7 @@ def _gif_from_imagemagick(self, savefile=None, show_path=False, https://www.imagemagick.org/. """ from sage.features.imagemagick import ImageMagick, Magick + ImageMagick().require() if not savefile: @@ -699,26 +690,16 @@ def _gif_from_imagemagick(self, savefile=None, show_path=False, # running the command directory = self.png() - cmd = [Magick().executable, '-dispose', 'Background', - '-delay', '%s' % int(delay), '-loop', '%s' % int(iterations), - '*.png', savefile] + cmd = [Magick().executable, '-dispose', 'Background', '-delay', '%s' % int(delay), '-loop', '%s' % int(iterations), '*.png', savefile] from subprocess import run + result = run(cmd, cwd=directory, capture_output=True, text=True) # If a problem with the command occurs, print the log before # raising an error (more verbose than result.check_returncode()) if result.returncode: - print('Command "{}" returned nonzero exit status "{}" ' - '(with stderr "{}" and stdout "{}").'.format(result.args, - result.returncode, - result.stderr.strip(), - result.stdout.strip())) - raise OSError("Error: Cannot generate GIF animation. " - "The magick/convert command (ImageMagick) is present but does " - "not seem to be functional. Verify that the objects " - "passed to the animate command can be saved in PNG " - "image format. " - "See www.imagemagick.org more information.") + print('Command "{}" returned nonzero exit status "{}" ' '(with stderr "{}" and stdout "{}").'.format(result.args, result.returncode, result.stderr.strip(), result.stdout.strip())) + raise OSError("Error: Cannot generate GIF animation. " "The magick/convert command (ImageMagick) is present but does " "not seem to be functional. Verify that the objects " "passed to the animate command can be saved in PNG " "image format. " "See www.imagemagick.org more information.") if show_path: print("Animation saved to file %s." % savefile) @@ -740,7 +721,7 @@ def _rich_repr_(self, display_manager, **kwds): """ iterations = kwds.get('iterations', 0) - loop = (iterations == 0) + loop = iterations == 0 t = display_manager.types supported = display_manager.supported_output() @@ -749,7 +730,7 @@ def _rich_repr_(self, display_manager, **kwds): if t.OutputImageGif in supported: format = "gif" else: - return # No supported format could be guessed + return # No supported format could be guessed suffix = None outputType = None if format == "gif": @@ -774,15 +755,15 @@ def _rich_repr_(self, display_manager, **kwds): if format is None: raise ValueError("Unknown video format") if outputType not in supported: - return # Sorry, requested format is not supported + return # Sorry, requested format is not supported if suffix is not None: - return display_manager.graphics_from_save( - self.save, kwds, suffix, outputType) + return display_manager.graphics_from_save(self.save, kwds, suffix, outputType) # Now we save for OutputVideoBase filename = tmp_filename(ext=outputType.ext) self.save(filename, **kwds) from sage.repl.rich_output.buffer import OutputBuffer + buf = OutputBuffer.from_file(filename) return outputType(buf, loop=loop) @@ -882,11 +863,11 @@ def show(self, delay=None, iterations=None, **kwds): kwds.setdefault("iterations", iterations) from sage.repl.rich_output import get_display_manager + dm = get_display_manager() dm.display_immediately(self, **kwds) - def ffmpeg(self, savefile=None, show_path=False, output_format=None, - ffmpeg_options='', delay=None, iterations=0, pix_fmt='rgb24'): + def ffmpeg(self, savefile=None, show_path=False, output_format=None, ffmpeg_options='', delay=None, iterations=0, pix_fmt='rgb24'): r""" Return a movie showing an animation composed from rendering the frames in ``self``. @@ -964,6 +945,7 @@ def ffmpeg(self, savefile=None, show_path=False, output_format=None, sage: a.ffmpeg(output_format='gif',delay=30,iterations=5) # long time # optional -- FFmpeg """ from sage.features.ffmpeg import FFmpeg + FFmpeg().require() if savefile is None: @@ -971,7 +953,7 @@ def ffmpeg(self, savefile=None, show_path=False, output_format=None, output_format = '.mpg' else: if output_format[0] != '.': - output_format = '.'+output_format + output_format = '.' + output_format savefile = tmp_filename(ext=output_format) else: if output_format is None: @@ -1006,7 +988,7 @@ def ffmpeg(self, savefile=None, show_path=False, output_format=None, pix_fmt_cmd = '' ffmpeg_options += f' {pix_fmt_cmd}{loop_cmd}' if delay is not None and output_format != '.mpeg' and output_format != '.mpg': - early_options += ' -r %s ' % int(100/delay) + early_options += ' -r %s ' % int(100 / delay) savefile = os.path.abspath(savefile) pngdir = self.png() pngs = os.path.join(pngdir, "%08d.png") @@ -1016,16 +998,15 @@ def ffmpeg(self, savefile=None, show_path=False, output_format=None, # afterwards. Hence 'early_options' and 'ffmpeg_options' # The `-nostdin` is needed to avoid the command to hang, see # https://stackoverflow.com/questions/16523746/ffmpeg-hangs-when-run-in-background - cmd = 'cd {}; {} -nostdin -y -f image2 {} -i {} {} {}'.format( - shlex.quote(pngdir), shlex.quote(FFmpeg().absolute_filename()), - early_options, shlex.quote(pngs), ffmpeg_options, shlex.quote(savefile)) + cmd = 'cd {}; {} -nostdin -y -f image2 {} -i {} {} {}'.format(shlex.quote(pngdir), shlex.quote(FFmpeg().absolute_filename()), early_options, shlex.quote(pngs), ffmpeg_options, shlex.quote(savefile)) from subprocess import check_call, CalledProcessError, PIPE + try: if sage.misc.verbose.get_verbose() > 0: set_stderr = None else: set_stderr = PIPE - sage.misc.verbose.verbose("Executing '%s'" % cmd,level=1) + sage.misc.verbose.verbose("Executing '%s'" % cmd, level=1) sage.misc.verbose.verbose("\n---- ffmpeg output below ----\n") check_call(cmd, shell=True, stderr=set_stderr) if show_path: @@ -1092,9 +1073,7 @@ def apng(self, savefile=None, show_path=False, delay=20, iterations=0): if savefile is None: savefile = tmp_filename(ext='.png') with open(savefile, "wb") as out: - apng = APngAssembler( - out, len(self), - delay=delay, num_plays=iterations) + apng = APngAssembler(out, len(self), delay=delay, num_plays=iterations) for i in range(len(self)): png = os.path.join(pngdir, "%08d.png" % i) apng.add_frame(png) @@ -1184,8 +1163,7 @@ def save(self, filename=None, show_path=False, use_ffmpeg=False, **kwds): suffix = '.gif' if filename is None or suffix == '.gif': - self.gif(savefile=filename, show_path=show_path, - use_ffmpeg=use_ffmpeg, **kwds) + self.gif(savefile=filename, show_path=show_path, use_ffmpeg=use_ffmpeg, **kwds) elif suffix == '.sobj': SageObject.save(self, filename) if show_path: @@ -1231,6 +1209,7 @@ def interactive(self, **kwds): :ref:`threejs_viewer` """ from sage.plot.plot3d.base import Graphics3d, KeyframeAnimationGroup + # Attempt to convert frames to Graphics3d objects. g3d_frames = [] for i, frame in enumerate(self._frames): @@ -1294,12 +1273,11 @@ class APngAssembler: sage: assembleAPNG() # long time '...png' """ + magic = b"\x89PNG\x0d\x0a\x1a\x0a" - mustmatch = frozenset([b"IHDR", b"PLTE", b"bKGD", b"cHRM", b"gAMA", - b"pHYs", b"sBIT", b"tRNS"]) + mustmatch = frozenset([b"IHDR", b"PLTE", b"bKGD", b"cHRM", b"gAMA", b"pHYs", b"sBIT", b"tRNS"]) - def __init__(self, out, num_frames, - num_plays=0, delay=200, delay_denominator=100): + def __init__(self, out, num_frames, num_plays=0, delay=200, delay_denominator=100): r""" Initialize for creation of an APNG file. """ @@ -1538,7 +1516,7 @@ def _next_IDAT(self, data): exit _next_IDAT -> None """ self._fctl() - maxlen = 0x7ffffffb + maxlen = 0x7FFFFFFB while len(data) > maxlen: self._chunk(b"fdAT", self._seqno() + data[:maxlen]) data = data[maxlen:] @@ -1625,11 +1603,7 @@ def _fctl(self): """ if self._fctl_written: return - data = struct.pack( - ">4L2H2B", - self.width, self.height, 0, 0, - self.delay_numerator, self.delay_denominator, - 1, 0) + data = struct.pack(">4L2H2B", self.width, self.height, 0, 0, self.delay_numerator, self.delay_denominator, 1, 0) self._chunk(b"fcTL", self._seqno() + data) self._fctl_written = True @@ -1649,7 +1623,7 @@ def _chunk(self, ctype, cdata): sage: buf.getvalue() == b'\x89PNG\r\n\x1a\n\x00\x00\x00\x04abcdefgh\xae\xef*P' True """ - ccrc = struct.pack(">L", zlib.crc32(ctype + cdata) & 0xffffffff) + ccrc = struct.pack(">L", zlib.crc32(ctype + cdata) & 0xFFFFFFFF) clen = struct.pack(">L", len(cdata)) for d in [clen, ctype, cdata, ccrc]: self.out.write(d) @@ -1681,15 +1655,15 @@ def _hex2bin(cls, h): """ b = [] while h: - if h[0] in ' \n': # ignore whitespace + if h[0] in ' \n': # ignore whitespace h = h[1:] - elif h[0] in '0123456789abcdef': # hex byte + elif h[0] in '0123456789abcdef': # hex byte b.append(int(h[:2], 16)) h = h[2:] - elif h[0] == '.': # for chunk type + elif h[0] == '.': # for chunk type b.extend(ord(h[i]) for i in range(1, 5)) h = h[5:] - else: # for PNG magic + else: # for PNG magic b.append(ord(h[0])) h = h[1:] @@ -1716,7 +1690,6 @@ def _testData(cls, name, asFile): '...png' """ data = { - # Input 1: one PNG image, except the data makes no real sense "input1": """89 PNG 0d0a1a0a 0000000d.IHDR 00000003000000020800000000 b81f39c6 @@ -1724,7 +1697,6 @@ def _testData(cls, name, asFile): 00000007.tIME 07de061b0b2624 1f307ad5 00000008.IDAT 696d673164617461 ce8a4999 00000000.IEND ae426082""", - # Input 2: slightly different, data in two chunks "input2": """89 PNG 0d0a1a0a 0000000d.IHDR 00000003000000020800000000 b81f39c6 @@ -1732,7 +1704,6 @@ def _testData(cls, name, asFile): 00000004.IDAT 696d6732 0e69ab1d 00000004.IDAT 64617461 6694cb78 00000000.IEND ae426082""", - # Expected output 1: both images as frames of an animation "anim12": """89 PNG 0d0a1a0a 0000000d.IHDR 00000003000000020800000000 b81f39c6 @@ -1746,7 +1717,6 @@ def _testData(cls, name, asFile): 00000008.fdAT 00000002696d6732 9cfb89a3 00000008.fdAT 0000000364617461 c966c076 00000000.IEND ae426082""", - # Expected output 2: first image as fallback, second as animation "still1anim2": """89 PNG 0d0a1a0a 0000000d.IHDR 00000003000000020800000000 b81f39c6 @@ -1758,11 +1728,11 @@ def _testData(cls, name, asFile): 00000008.fdAT 00000001696d6732 db5bf373 00000008.fdAT 0000000264617461 f406e9c6 00000000.IEND ae426082""", - } d = cls._hex2bin(data[name]) if asFile: from sage.misc.temporary_file import tmp_filename + fn = tmp_filename(ext='.png') with open(fn, 'wb') as f: f.write(d) @@ -1785,12 +1755,12 @@ def _testCase1(cls, methodToTrace=None, **kwds): """ from sage.doctest.fixtures import trace_method from io import BytesIO + buf = BytesIO() apng = cls(buf, 2) if methodToTrace is not None: trace_method(apng, methodToTrace, **kwds) - apng.add_frame(cls._testData("input1", True), - delay=0x567, delay_denominator=0x1234) + apng.add_frame(cls._testData("input1", True), delay=0x567, delay_denominator=0x1234) apng.add_frame(cls._testData("input2", True)) out = buf.getvalue() assert len(out) == 217 diff --git a/src/sage/plot/arc.py b/src/sage/plot/arc.py index 5cfe801539e..81b65b6a05a 100644 --- a/src/sage/plot/arc.py +++ b/src/sage/plot/arc.py @@ -1,6 +1,7 @@ """ Arcs of circles and ellipses """ + # **************************************************************************** # Copyright (C) 2010 Vincent Delecroix <20100.delecroix@gmail.com>, # @@ -50,6 +51,7 @@ class Arc(GraphicPrimitive): sage: print(Arc(0,0,1,1,pi/4,pi/4,pi/2,{})) Arc with center (0.0,0.0) radii (1.0,1.0) angle 0.78539816339... inside the sector (0.78539816339...,1.5707963267...) """ + def __init__(self, x, y, r1, r2, angle, s1, s2, options): """ Initialize base class ``Arc``. @@ -200,8 +202,7 @@ def get_minmax_data(self): axmax = atan(-r2 / r1 * tan_angle) if axmax < 0: axmax += twopi - xmax = (r1 * cos_angle * cos(axmax) - - r2 * sin_angle * sin(axmax)) + xmax = r1 * cos_angle * cos(axmax) - r2 * sin_angle * sin(axmax) if xmax < 0: xmax = -xmax axmax = fmod(axmax + pi, twopi) @@ -211,8 +212,7 @@ def get_minmax_data(self): aymax = atan(r2 / (r1 * tan_angle)) if aymax < 0: aymax += twopi - ymax = (r1 * sin_angle * cos(aymax) + - r2 * cos_angle * sin(aymax)) + ymax = r1 * sin_angle * cos(aymax) + r2 * cos_angle * sin(aymax) if ymax < 0: ymax = -ymax aymax = fmod(aymax + pi, twopi) @@ -220,10 +220,9 @@ def get_minmax_data(self): aymin = fmod(aymax + pi, twopi) if s < twopi - epsilon: # bb determined by the sector + def is_cyclic_ordered(x1, x2, x3): - return ((x1 < x2 < x3) or - (x2 < x3 < x1) or - (x3 < x1 < x2)) + return (x1 < x2 < x3) or (x2 < x3 < x1) or (x3 < x1 < x2) x1 = cos_angle * r1 * cos(s1) - sin_angle * r2 * sin(s1) x2 = cos_angle * r1 * cos(s2) - sin_angle * r2 * sin(s2) @@ -239,9 +238,7 @@ def is_cyclic_ordered(x1, x2, x3): if is_cyclic_ordered(s1, s2, aymax): ymax = max(y1, y2) - return minmax_data([self.x + xmin, self.x + xmax], - [self.y + ymin, self.y + ymax], - dict=True) + return minmax_data([self.x + xmin, self.x + xmax], [self.y + ymin, self.y + ymax], dict=True) def _allowed_options(self): """ @@ -253,14 +250,7 @@ def _allowed_options(self): sage: p[0]._allowed_options()['alpha'] 'How transparent the figure is.' """ - return {'alpha': 'How transparent the figure is.', - 'thickness': 'How thick the border of the arc is.', - 'hue': 'The color given as a hue.', - 'rgbcolor': 'The color', - 'zorder': '2D only: The layer level in which to draw', - 'linestyle': "2D only: The style of the line, which is one of " - "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " - "respectively."} + return {'alpha': 'How transparent the figure is.', 'thickness': 'How thick the border of the arc is.', 'hue': 'The color given as a hue.', 'rgbcolor': 'The color', 'zorder': '2D only: The layer level in which to draw', 'linestyle': "2D only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively."} def _matplotlib_arc(self): """ @@ -273,12 +263,8 @@ def _matplotlib_arc(self): """ from matplotlib import patches - p = patches.Arc((self.x, self.y), - 2. * self.r1, - 2. * self.r2, - angle=fmod(self.angle, 2 * pi) * (180. / pi), - theta1=self.s1 * (180. / pi), - theta2=self.s2 * (180. / pi)) + + p = patches.Arc((self.x, self.y), 2.0 * self.r1, 2.0 * self.r2, angle=fmod(self.angle, 2 * pi) * (180.0 / pi), theta1=self.s1 * (180.0 / pi), theta2=self.s2 * (180.0 / pi)) return p def bezier_path(self): @@ -306,6 +292,7 @@ def bezier_path(self): from sage.plot.graphics import Graphics from matplotlib.path import Path import numpy as np + ma = self._matplotlib_arc() def theta_stretch(theta, scale): @@ -313,6 +300,7 @@ def theta_stretch(theta, scale): x = np.cos(theta) y = np.sin(theta) return np.rad2deg(np.arctan2(scale * y, x)) + theta1 = theta_stretch(ma.theta1, ma.width / ma.height) theta2 = theta_stretch(ma.theta2, ma.width / ma.height) @@ -325,10 +313,10 @@ def theta_stretch(theta, scale): for u in pa._path.vertices: x, y = list(u) points += [(cA * x + cC * y + cE, cB * x + cD * y + cF)] - cutlist = [points[0: 4]] + cutlist = [points[0:4]] N = 4 while N < len(points): - cutlist += [points[N: N + 3]] + cutlist += [points[N : N + 3]] N += 3 g = Graphics() opt = self.options() @@ -367,8 +355,7 @@ def _render_on_subplot(self, subplot): z = int(options.pop('zorder', 1)) p.set_zorder(z) c = to_mpl_color(options['rgbcolor']) - p.set_linestyle(get_matplotlib_linestyle(options['linestyle'], - return_type='long')) + p.set_linestyle(get_matplotlib_linestyle(options['linestyle'], return_type='long')) p.set_edgecolor(c) subplot.add_patch(p) @@ -386,8 +373,7 @@ def plot3d(self): @rename_keyword(color='rgbcolor') -@options(alpha=1, thickness=1, linestyle='solid', zorder=5, rgbcolor='blue', - aspect_ratio=1.0) +@options(alpha=1, thickness=1, linestyle='solid', zorder=5, rgbcolor='blue', aspect_ratio=1.0) def arc(center, r1, r2=None, angle=0.0, sector=(0.0, 2 * pi), **options): r""" An arc (that is a portion of a circle or an ellipse). @@ -492,12 +478,7 @@ def arc(center, r1, r2=None, angle=0.0, sector=(0.0, 2 * pi), **options): g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) if len(sector) != 2: raise ValueError("the sector must consist of two angles") - g.add_primitive(Arc( - center[0], center[1], - r1, r2, - angle, - sector[0], sector[1], - options)) + g.add_primitive(Arc(center[0], center[1], r1, r2, angle, sector[0], sector[1], options)) return g if len(center) == 3: raise NotImplementedError diff --git a/src/sage/plot/arrow.py b/src/sage/plot/arrow.py index a8c31c7b270..4c104b3abcd 100644 --- a/src/sage/plot/arrow.py +++ b/src/sage/plot/arrow.py @@ -1,6 +1,7 @@ """ Arrows """ + # *************************************************************************** # Copyright (C) 2006 Alex Clemesha , # William Stein , @@ -37,12 +38,13 @@ def __init__(self, path, options): CurveArrow from (0, 0) to (0, 0) """ import numpy as np + self.path = path - codes = [1] + (len(self.path[0])-1)*[len(self.path[0])] + codes = [1] + (len(self.path[0]) - 1) * [len(self.path[0])] vertices = self.path[0] for curve in self.path[1:]: vertices += curve - codes += (len(curve))*[len(curve)+1] + codes += (len(curve)) * [len(curve) + 1] self.codes = codes self.vertices = np.array(vertices, float) GraphicPrimitive.__init__(self, options) @@ -65,10 +67,7 @@ def get_minmax_data(self): sage: d['xmax'] 1.0 """ - return {'xmin': self.vertices[:,0].min(), - 'xmax': self.vertices[:,0].max(), - 'ymin': self.vertices[:,1].min(), - 'ymax': self.vertices[:,1].max()} + return {'xmin': self.vertices[:, 0].min(), 'xmax': self.vertices[:, 0].max(), 'ymin': self.vertices[:, 1].min(), 'ymax': self.vertices[:, 1].max()} def _allowed_options(self): """ @@ -93,19 +92,7 @@ def _allowed_options(self): ('width', 'The width of the shaft of the arrow, in points.'), ('zorder', '2-d only: The layer level in which to draw')] """ - return {'width': 'The width of the shaft of the arrow, in points.', - 'rgbcolor': 'The color as an RGB tuple.', - 'hue': 'The color given as a hue.', - 'legend_label': 'The label for this item in the legend.', - 'legend_color': 'The color of the legend text.', - 'arrowstyle': 'todo', - 'arrowsize': 'The size of the arrowhead', - 'thickness': 'The thickness of the arrow.', - 'zorder': '2-d only: The layer level in which to draw', - 'head': '2-d only: Which end of the path to draw the head (one of 0 (start), 1 (end) or 2 (both)', - 'linestyle': "2d only: The style of the line, which is one of " - "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " - "respectively."} + return {'width': 'The width of the shaft of the arrow, in points.', 'rgbcolor': 'The color as an RGB tuple.', 'hue': 'The color given as a hue.', 'legend_label': 'The label for this item in the legend.', 'legend_color': 'The color of the legend text.', 'arrowstyle': 'todo', 'arrowsize': 'The size of the arrowhead', 'thickness': 'The thickness of the arrow.', 'zorder': '2-d only: The layer level in which to draw', 'head': '2-d only: Which end of the path to draw the head (one of 0 (start), 1 (end) or 2 (both)', 'linestyle': "2d only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively."} def _repr_(self): """ @@ -153,11 +140,9 @@ def _render_on_subplot(self, subplot): color = to_mpl_color(options['rgbcolor']) from matplotlib.patches import FancyArrowPatch from matplotlib.path import Path + bpath = Path(self.vertices, self.codes) - p = FancyArrowPatch(path=bpath, - lw=width, arrowstyle='{},head_width={},head_length={}'.format(style, head_width, head_length), - fc=color, ec=color, - linestyle=get_matplotlib_linestyle(options['linestyle'], return_type='long')) + p = FancyArrowPatch(path=bpath, lw=width, arrowstyle='{},head_width={},head_length={}'.format(style, head_width, head_length), fc=color, ec=color, linestyle=get_matplotlib_linestyle(options['linestyle'], return_type='long')) p.set_zorder(options['zorder']) p.set_label(options['legend_label']) subplot.add_patch(p) @@ -179,6 +164,7 @@ class Arrow(GraphicPrimitive): sage: P Arrow from (0.0,1.0) to (2.0,3.0) """ + def __init__(self, xtail, ytail, xhead, yhead, options): """ Create an arrow graphics primitive. @@ -207,10 +193,7 @@ def get_minmax_data(self): sage: d['xmax'] 5.0 """ - return {'xmin': min(self.xtail, self.xhead), - 'xmax': max(self.xtail, self.xhead), - 'ymin': min(self.ytail, self.yhead), - 'ymax': max(self.ytail, self.yhead)} + return {'xmin': min(self.xtail, self.xhead), 'xmax': max(self.xtail, self.xhead), 'ymin': min(self.ytail, self.yhead), 'ymax': max(self.ytail, self.yhead)} def _allowed_options(self): """ @@ -237,19 +220,7 @@ def _allowed_options(self): ('width', 'The width of the shaft of the arrow, in points.'), ('zorder', '2-d only: The layer level in which to draw')] """ - return {'width': 'The width of the shaft of the arrow, in points.', - 'rgbcolor': 'The color as an RGB tuple.', - 'hue': 'The color given as a hue.', - 'arrowshorten': 'The length in points to shorten the arrow.', - 'arrowsize': 'The size of the arrowhead', - 'thickness': 'The thickness of the arrow.', - 'legend_label': 'The label for this item in the legend.', - 'legend_color': 'The color of the legend text.', - 'zorder': '2-d only: The layer level in which to draw', - 'head': '2-d only: Which end of the path to draw the head (one of 0 (start), 1 (end) or 2 (both)', - 'linestyle': "2d only: The style of the line, which is one of " - "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " - "respectively."} + return {'width': 'The width of the shaft of the arrow, in points.', 'rgbcolor': 'The color as an RGB tuple.', 'hue': 'The color given as a hue.', 'arrowshorten': 'The length in points to shorten the arrow.', 'arrowsize': 'The size of the arrowhead', 'thickness': 'The thickness of the arrow.', 'legend_label': 'The label for this item in the legend.', 'legend_color': 'The color of the legend text.', 'zorder': '2-d only: The layer level in which to draw', 'head': '2-d only: Which end of the path to draw the head (one of 0 (start), 1 (end) or 2 (both)', 'linestyle': "2d only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively."} def _plot3d_options(self, options=None): """ @@ -308,6 +279,7 @@ def plot3d(self, ztail=0, zhead=0, **kwds): 'draw line_1 diameter 2 arrow {0.0 0.0 3.0} {1.0 1.0 4.0} ' """ from sage.plot.plot3d.shapes2 import line3d + options = self._plot3d_options() options.update(kwds) return line3d([(self.xtail, self.ytail, ztail), (self.xhead, self.yhead, zhead)], arrow_head=True, **options) @@ -379,12 +351,8 @@ def _render_on_subplot(self, subplot): head_length = arrowsize * 2.0 color = to_mpl_color(options['rgbcolor']) from matplotlib.patches import FancyArrowPatch - p = FancyArrowPatch((self.xtail, self.ytail), (self.xhead, self.yhead), - lw=width, - arrowstyle='{},head_width={},head_length={}'.format(style, head_width, head_length), - shrinkA=arrowshorten_end, shrinkB=arrowshorten_end, - fc=color, ec=color, - linestyle=get_matplotlib_linestyle(options['linestyle'], return_type='long')) + + p = FancyArrowPatch((self.xtail, self.ytail), (self.xhead, self.yhead), lw=width, arrowstyle='{},head_width={},head_length={}'.format(style, head_width, head_length), shrinkA=arrowshorten_end, shrinkB=arrowshorten_end, fc=color, ec=color, linestyle=get_matplotlib_linestyle(options['linestyle'], return_type='long')) p.set_zorder(options['zorder']) p.set_label(options['legend_label']) @@ -487,12 +455,12 @@ def arrow(tailpoint=None, headpoint=None, **kwds): return arrow2d(tailpoint, headpoint, **kwds) except ValueError: from sage.plot.plot3d.shapes import arrow3d + return arrow3d(tailpoint, headpoint, **kwds) @rename_keyword(color='rgbcolor') -@options(width=2, rgbcolor=(0,0,1), zorder=2, head=1, linestyle='solid', - legend_label=None, legend_color=None) +@options(width=2, rgbcolor=(0, 0, 1), zorder=2, head=1, linestyle='solid', legend_label=None, legend_color=None) def arrow2d(tailpoint=None, headpoint=None, path=None, **options): """ If ``tailpoint`` and ``headpoint`` are provided, returns an arrow from @@ -651,6 +619,7 @@ def arrow2d(tailpoint=None, headpoint=None, path=None, **options): sage: A = arrow2d((-1,-1), (2,3), legend_label='test') """ from sage.plot.graphics import Graphics + g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) diff --git a/src/sage/plot/bar_chart.py b/src/sage/plot/bar_chart.py index f03ea65ab12..f4a8d8d9cc3 100644 --- a/src/sage/plot/bar_chart.py +++ b/src/sage/plot/bar_chart.py @@ -38,6 +38,7 @@ class BarChart(GraphicPrimitive): sage: type(g) """ + def __init__(self, ind, datalist, options): """ Initialize a ``BarChart`` primitive. @@ -80,11 +81,7 @@ def _allowed_options(self): sage: list(sorted(g._allowed_options().items())) [('hue', 'The color given as a hue.'), ('legend_label', 'The label for this item in the legend.'), ('rgbcolor', 'The color as an RGB tuple.'), ('width', 'The width of the bars'), ('zorder', 'The layer level in which to draw')] """ - return {'rgbcolor': 'The color as an RGB tuple.', - 'hue': 'The color given as a hue.', - 'legend_label': 'The label for this item in the legend.', - 'width': 'The width of the bars', - 'zorder': 'The layer level in which to draw'} + return {'rgbcolor': 'The color as an RGB tuple.', 'hue': 'The color given as a hue.', 'legend_label': 'The label for this item in the legend.', 'width': 'The width of the bars', 'zorder': 'The layer level in which to draw'} def _repr_(self): """ @@ -118,6 +115,7 @@ def _render_on_subplot(self, subplot): # it is critical to make NumPy arrays of type float below, # or bar will go boom: import numpy + ind = numpy.array(self.ind, dtype=float) datalist = numpy.array(self.datalist, dtype=float) subplot.bar(ind, datalist, color=color, width=width, label=options['legend_label']) @@ -184,9 +182,9 @@ def bar_chart(datalist, **options): # bardata = [] # cnt = 1 # for pnts in datalist: - # ind = [i+cnt/dl for i in range(len(pnts))] - # bardata.append([ind, pnts, xrange, yrange]) - # cnt += 1 + # ind = [i+cnt/dl for i in range(len(pnts))] + # bardata.append([ind, pnts, xrange, yrange]) + # cnt += 1 g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) diff --git a/src/sage/plot/bezier_path.py b/src/sage/plot/bezier_path.py index eca3c47bf16..02befa261a8 100644 --- a/src/sage/plot/bezier_path.py +++ b/src/sage/plot/bezier_path.py @@ -1,7 +1,8 @@ r""" Bezier paths """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2006 Alex Clemesha , # William Stein , # 2008 Mike Hansen , @@ -17,7 +18,7 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.plot.primitive import GraphicPrimitive_xydata from sage.misc.decorators import options, rename_keyword from sage.plot.colors import to_mpl_color @@ -46,6 +47,7 @@ class BezierPath(GraphicPrimitive_xydata): P = bezier_path([[(0,0),(.5,.5),(1,0)],[(.5,1),(0,0)]], linestyle='dashed') sphinx_plot(P) """ + def __init__(self, path, options): """ Return a graphics primitive of a path of Bezier curves. @@ -89,9 +91,9 @@ def __init__(self, path, options): code = len(curve) + (i > 0) if code < 2 or code > 4: raise ValueError('invalid input for BezierPath') - codes[k:k+len(curve)] = code + codes[k : k + len(curve)] = code k += len(curve) - codes[0] = 1 # MOVETO + codes[0] = 1 # MOVETO self.codes = codes GraphicPrimitive_xydata.__init__(self, options) @@ -112,14 +114,7 @@ def _allowed_options(self): ('thickness', 'How thick the border of the polygon is.'), ('zorder', 'The layer level in which to draw')] """ - return {'alpha': 'How transparent the line is.', - 'fill': 'Whether or not to fill the polygon.', - 'thickness': 'How thick the border of the polygon is.', - 'rgbcolor': 'The color as an RGB tuple.', - 'zorder': 'The layer level in which to draw', - 'linestyle': "The style of the line, which is one of 'dashed'," - " 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.'," - " respectively."} + return {'alpha': 'How transparent the line is.', 'fill': 'Whether or not to fill the polygon.', 'thickness': 'How thick the border of the polygon is.', 'rgbcolor': 'The color as an RGB tuple.', 'zorder': 'The layer level in which to draw', 'linestyle': "The style of the line, which is one of 'dashed'," " 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.'," " respectively."} def _plot3d_options(self, options=None): """ @@ -149,8 +144,7 @@ def _plot3d_options(self, options=None): del options['fill'] if 'linestyle' in options: if options['linestyle'] not in ('solid', '-'): - raise NotImplementedError("invalid 3d line style: '%s'" % - (options['linestyle'])) + raise NotImplementedError("invalid 3d line style: '%s'" % (options['linestyle'])) del options['linestyle'] options_3d.update(GraphicPrimitive_xydata._plot3d_options(self, options)) return options_3d @@ -189,9 +183,10 @@ def plot3d(self, z=0, **kwds): sphinx_plot(bezier3d([[(0,0,0),(1,0,0),(0,1,0),(0,1,1)]])) """ from sage.plot.plot3d.shapes2 import bezier3d + options = self._plot3d_options() options.update(kwds) - return bezier3d([[(x,y,0) for x,y in self.path[i]] for i in range(len(self.path))], **options) + return bezier3d([[(x, y, 0) for x, y in self.path[i]] for i in range(len(self.path))], **options) def _repr_(self): """ @@ -264,14 +259,11 @@ def get_minmax_data(self): sage: d['xmax'] 1.0 """ - return {'xmin': self.vertices[:,0].min(), - 'xmax': self.vertices[:,0].max(), - 'ymin': self.vertices[:,1].min(), - 'ymax': self.vertices[:,1].max()} + return {'xmin': self.vertices[:, 0].min(), 'xmax': self.vertices[:, 0].max(), 'ymin': self.vertices[:, 1].min(), 'ymax': self.vertices[:, 1].max()} @rename_keyword(color='rgbcolor') -@options(alpha=1, fill=False, thickness=1, rgbcolor=(0,0,0), zorder=2, linestyle='solid') +@options(alpha=1, fill=False, thickness=1, rgbcolor=(0, 0, 0), zorder=2, linestyle='solid') def bezier_path(path, **options): """ Return a Graphics object of a Bezier path corresponding to the @@ -393,6 +385,7 @@ def bezier_path(path, **options): [[(1, 1), (2, 3), (3, 3)], [(4, 4), (5, 5)]] """ from sage.plot.graphics import Graphics + g = Graphics() g._set_extra_kwds(g._extract_kwds_for_show(options)) g.add_primitive(BezierPath(path, options)) diff --git a/src/sage/plot/circle.py b/src/sage/plot/circle.py index a37bfa153b1..55774dca79a 100644 --- a/src/sage/plot/circle.py +++ b/src/sage/plot/circle.py @@ -1,7 +1,8 @@ """ Circles """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2006 Alex Clemesha , # William Stein , # 2008 Mike Hansen , @@ -16,7 +17,7 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from .primitive import GraphicPrimitive from sage.misc.decorators import options, rename_keyword from sage.plot.colors import to_mpl_color @@ -57,6 +58,7 @@ class Circle(GraphicPrimitive): sage: C = circle((2,3), 5) """ + def __init__(self, x, y, r, options): """ Initialize base class Circle. @@ -92,9 +94,8 @@ def get_minmax_data(self): 2.0 """ from sage.plot.plot import minmax_data - return minmax_data([self.x - self.r, self.x + self.r], - [self.y - self.r, self.y + self.r], - dict=True) + + return minmax_data([self.x - self.r, self.x + self.r], [self.y - self.r, self.y + self.r], dict=True) def _allowed_options(self): """ @@ -108,20 +109,7 @@ def _allowed_options(self): sage: p[0]._allowed_options()['facecolor'] '2D only: The color of the face as an RGB tuple.' """ - return {'alpha': 'How transparent the figure is.', - 'fill': 'Whether or not to fill the circle.', - 'legend_label': 'The label for this item in the legend.', - 'legend_color': 'The color of the legend text.', - 'thickness': 'How thick the border of the circle is.', - 'edgecolor': '2D only: The color of the edge as an RGB tuple.', - 'facecolor': '2D only: The color of the face as an RGB tuple.', - 'rgbcolor': 'The color (edge and face) as an RGB tuple.', - 'hue': 'The color given as a hue.', - 'zorder': '2D only: The layer level in which to draw', - 'linestyle': "2D only: The style of the line, which is one of " - "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " - "respectively.", - 'clip': 'Whether or not to clip the circle.'} + return {'alpha': 'How transparent the figure is.', 'fill': 'Whether or not to fill the circle.', 'legend_label': 'The label for this item in the legend.', 'legend_color': 'The color of the legend text.', 'thickness': 'How thick the border of the circle is.', 'edgecolor': '2D only: The color of the edge as an RGB tuple.', 'facecolor': '2D only: The color of the face as an RGB tuple.', 'rgbcolor': 'The color (edge and face) as an RGB tuple.', 'hue': 'The color given as a hue.', 'zorder': '2D only: The layer level in which to draw', 'linestyle': "2D only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively.", 'clip': 'Whether or not to clip the circle.'} def _repr_(self): """ @@ -159,7 +147,7 @@ def _render_on_subplot(self, subplot): ec = fc = to_mpl_color(options['rgbcolor']) p.set_edgecolor(ec) p.set_facecolor(fc) - p.set_linestyle(get_matplotlib_linestyle(options['linestyle'],return_type='long')) + p.set_linestyle(get_matplotlib_linestyle(options['linestyle'], return_type='long')) p.set_label(options['legend_label']) z = int(options.pop('zorder', 0)) p.set_zorder(z) @@ -210,26 +198,26 @@ def plot3d(self, z=0, **kwds): """ options = dict(self.options()) fill = options['fill'] - for s in ['clip', 'edgecolor', 'facecolor', 'fill', 'linestyle', - 'zorder']: + for s in ['clip', 'edgecolor', 'facecolor', 'fill', 'linestyle', 'zorder']: if s in options: del options[s] n = 50 - dt = float(2*pi/n) + dt = float(2 * pi / n) x, y, r = self.x, self.y, self.r - xdata = [x+r*cos(t*dt) for t in range(n+1)] - ydata = [y+r*sin(t*dt) for t in range(n+1)] + xdata = [x + r * cos(t * dt) for t in range(n + 1)] + ydata = [y + r * sin(t * dt) for t in range(n + 1)] if fill: from .polygon import Polygon + return Polygon(xdata, ydata, options).plot3d(z) from .line import Line - return Line(xdata, ydata, options).plot3d().translate((0,0,z)) + + return Line(xdata, ydata, options).plot3d().translate((0, 0, z)) @rename_keyword(color='rgbcolor') -@options(alpha=1, fill=False, thickness=1, edgecolor='blue', facecolor='blue', linestyle='solid', - zorder=5, legend_label=None, legend_color=None, clip=True, aspect_ratio=1.0) +@options(alpha=1, fill=False, thickness=1, edgecolor='blue', facecolor='blue', linestyle='solid', zorder=5, legend_label=None, legend_color=None, clip=True, aspect_ratio=1.0) def circle(center, radius, **options): """ Return a circle at a point center = `(x,y)` (or `(x,y,z)` and @@ -429,5 +417,4 @@ def circle(center, radius, **options): return g if len(center) == 3: return g[0].plot3d(z=center[2]) - raise ValueError('the center of a plotted circle should have ' - 'two or three coordinates') + raise ValueError('the center of a plotted circle should have ' 'two or three coordinates') diff --git a/src/sage/plot/colors.py b/src/sage/plot/colors.py index 79f97d09801..6fb185ce9ba 100644 --- a/src/sage/plot/colors.py +++ b/src/sage/plot/colors.py @@ -42,154 +42,154 @@ colors_dict = { - 'automatic' : '#add8e6', # 173, 216, 230 - 'aliceblue' : '#f0f8ff', # 240, 248, 255 - 'antiquewhite' : '#faebd7', # 250, 235, 215 - 'aqua' : '#00ffff', # 0, 255, 255 - 'aquamarine' : '#7fffd4', # 127, 255, 212 - 'azure' : '#f0ffff', # 240, 255, 255 - 'beige' : '#f5f5dc', # 245, 245, 220 - 'bisque' : '#ffe4c4', # 255, 228, 196 - 'black' : '#000000', # 0, 0, 0 - 'blanchedalmond' : '#ffebcd', # 255, 235, 205 - 'blue' : '#0000ff', # 0, 0, 255 - 'blueviolet' : '#8a2be2', # 138, 43, 226 - 'brown' : '#a52a2a', # 165, 42, 42 - 'burlywood' : '#deb887', # 222, 184, 135 - 'cadetblue' : '#5f9ea0', # 95, 158, 160 - 'chartreuse' : '#7fff00', # 127, 255, 0 - 'chocolate' : '#d2691e', # 210, 105, 30 - 'coral' : '#ff7f50', # 255, 127, 80 - 'cornflowerblue' : '#6495ed', # 100, 149, 237 - 'cornsilk' : '#fff8dc', # 255, 248, 220 - 'crimson' : '#dc143c', # 220, 20, 60 - 'cyan' : '#00ffff', # 0, 255, 255 - 'darkblue' : '#00008b', # 0, 0, 139 - 'darkcyan' : '#008b8b', # 0, 139, 139 - 'darkgoldenrod' : '#b8860b', # 184, 134, 11 - 'darkgray' : '#a9a9a9', # 169, 169, 169 - 'darkgreen' : '#006400', # 0, 100, 0 - 'darkgrey' : '#a9a9a9', # 169, 169, 169 - 'darkkhaki' : '#bdb76b', # 189, 183, 107 - 'darkmagenta' : '#8b008b', # 139, 0, 139 - 'darkolivegreen' : '#556b2f', # 85, 107, 47 - 'darkorange' : '#ff8c00', # 255, 140, 0 - 'darkorchid' : '#9932cc', # 153, 50, 204 - 'darkred' : '#8b0000', # 139, 0, 0 - 'darksalmon' : '#e9967a', # 233, 150, 122 - 'darkseagreen' : '#8fbc8f', # 143, 188, 143 - 'darkslateblue' : '#483d8b', # 72, 61, 139 - 'darkslategray' : '#2f4f4f', # 47, 79, 79 - 'darkslategrey' : '#2f4f4f', # 47, 79, 79 - 'darkturquoise' : '#00ced1', # 0, 206, 209 - 'darkviolet' : '#9400d3', # 148, 0, 211 - 'deeppink' : '#ff1493', # 255, 20, 147 - 'deepskyblue' : '#00bfff', # 0, 191, 255 - 'dimgray' : '#696969', # 105, 105, 105 - 'dimgrey' : '#696969', # 105, 105, 105 - 'dodgerblue' : '#1e90ff', # 30, 144, 255 - 'firebrick' : '#b22222', # 178, 34, 34 - 'floralwhite' : '#fffaf0', # 255, 250, 240 - 'forestgreen' : '#228b22', # 34, 139, 34 - 'fuchsia' : '#ff00ff', # 255, 0, 255 - 'gainsboro' : '#dcdcdc', # 220, 220, 220 - 'ghostwhite' : '#f8f8ff', # 248, 248, 255 - 'gold' : '#ffd700', # 255, 215, 0 - 'goldenrod' : '#daa520', # 218, 165, 32 - 'gray' : '#808080', # 128, 128, 128 - 'green' : '#008000', # 0, 128, 0 - 'greenyellow' : '#adff2f', # 173, 255, 47 - 'grey' : '#808080', # 128, 128, 128 - 'honeydew' : '#f0fff0', # 240, 255, 240 - 'hotpink' : '#ff69b4', # 255, 105, 180 - 'indianred' : '#cd5c5c', # 205, 92, 92 - 'indigo' : '#4b0082', # 75, 0, 130 - 'ivory' : '#fffff0', # 255, 255, 240 - 'khaki' : '#f0e68c', # 240, 230, 140 - 'lavender' : '#e6e6fa', # 230, 230, 250 - 'lavenderblush' : '#fff0f5', # 255, 240, 245 - 'lawngreen' : '#7cfc00', # 124, 252, 0 - 'lemonchiffon' : '#fffacd', # 255, 250, 205 - 'lightblue' : '#add8e6', # 173, 216, 230 - 'lightcoral' : '#f08080', # 240, 128, 128 - 'lightcyan' : '#e0ffff', # 224, 255, 255 - 'lightgoldenrodyellow' : '#fafad2', # 250, 250, 210 - 'lightgray' : '#d3d3d3', # 211, 211, 211 - 'lightgreen' : '#90ee90', # 144, 238, 144 - 'lightgrey' : '#d3d3d3', # 211, 211, 211 - 'lightpink' : '#ffb6c1', # 255, 182, 193 - 'lightsalmon' : '#ffa07a', # 255, 160, 122 - 'lightseagreen' : '#20b2aa', # 32, 178, 170 - 'lightskyblue' : '#87cefa', # 135, 206, 250 - 'lightslategray' : '#778899', # 119, 136, 153 - 'lightslategrey' : '#778899', # 119, 136, 153 - 'lightsteelblue' : '#b0c4de', # 176, 196, 222 - 'lightyellow' : '#ffffe0', # 255, 255, 224 - 'lime' : '#00ff00', # 0, 255, 0 - 'limegreen' : '#32cd32', # 50, 205, 50 - 'linen' : '#faf0e6', # 250, 240, 230 - 'magenta' : '#ff00ff', # 255, 0, 255 - 'maroon' : '#800000', # 128, 0, 0 - 'mediumaquamarine' : '#66cdaa', # 102, 205, 170 - 'mediumblue' : '#0000cd', # 0, 0, 205 - 'mediumorchid' : '#ba55d3', # 186, 85, 211 - 'mediumpurple' : '#9370db', # 147, 112, 219 - 'mediumseagreen' : '#3cb371', # 60, 179, 113 - 'mediumslateblue' : '#7b68ee', # 123, 104, 238 - 'mediumspringgreen' : '#00fa9a', # 0, 250, 154 - 'mediumturquoise' : '#48d1cc', # 72, 209, 204 - 'mediumvioletred' : '#c71585', # 199, 21, 133 - 'midnightblue' : '#191970', # 25, 25, 112 - 'mintcream' : '#f5fffa', # 245, 255, 250 - 'mistyrose' : '#ffe4e1', # 255, 228, 225 - 'moccasin' : '#ffe4b5', # 255, 228, 181 - 'navajowhite' : '#ffdead', # 255, 222, 173 - 'navy' : '#000080', # 0, 0, 128 - 'oldlace' : '#fdf5e6', # 253, 245, 230 - 'olive' : '#808000', # 128, 128, 0 - 'olivedrab' : '#6b8e23', # 107, 142, 35 - 'orange' : '#ffa500', # 255, 165, 0 - 'orangered' : '#ff4500', # 255, 69, 0 - 'orchid' : '#da70d6', # 218, 112, 214 - 'palegoldenrod' : '#eee8aa', # 238, 232, 170 - 'palegreen' : '#98fb98', # 152, 251, 152 - 'paleturquoise' : '#afeeee', # 175, 238, 238 - 'palevioletred' : '#db7093', # 219, 112, 147 - 'papayawhip' : '#ffefd5', # 255, 239, 213 - 'peachpuff' : '#ffdab9', # 255, 218, 185 - 'peru' : '#cd853f', # 205, 133, 63 - 'pink' : '#ffc0cb', # 255, 192, 203 - 'plum' : '#dda0dd', # 221, 160, 221 - 'powderblue' : '#b0e0e6', # 176, 224, 230 - 'purple' : '#800080', # 128, 0, 128 - 'red' : '#ff0000', # 255, 0, 0 - 'rosybrown' : '#bc8f8f', # 188, 143, 143 - 'royalblue' : '#4169e1', # 65, 105, 225 - 'saddlebrown' : '#8b4513', # 139, 69, 19 - 'salmon' : '#fa8072', # 250, 128, 114 - 'sandybrown' : '#f4a460', # 244, 164, 96 - 'seagreen' : '#2e8b57', # 46, 139, 87 - 'seashell' : '#fff5ee', # 255, 245, 238 - 'sienna' : '#a0522d', # 160, 82, 45 - 'silver' : '#c0c0c0', # 192, 192, 192 - 'skyblue' : '#87ceeb', # 135, 206, 235 - 'slateblue' : '#6a5acd', # 106, 90, 205 - 'slategray' : '#708090', # 112, 128, 144 - 'slategrey' : '#708090', # 112, 128, 144 - 'snow' : '#fffafa', # 255, 250, 250 - 'springgreen' : '#00ff7f', # 0, 255, 127 - 'steelblue' : '#4682b4', # 70, 130, 180 - 'tan' : '#d2b48c', # 210, 180, 140 - 'teal' : '#008080', # 0, 128, 128 - 'thistle' : '#d8bfd8', # 216, 191, 216 - 'tomato' : '#ff6347', # 255, 99, 71 - 'turquoise' : '#40e0d0', # 64, 224, 208 - 'violet' : '#ee82ee', # 238, 130, 238 - 'wheat' : '#f5deb3', # 245, 222, 179 - 'white' : '#ffffff', # 255, 255, 255 - 'whitesmoke' : '#f5f5f5', # 245, 245, 245 - 'yellow' : '#ffff00', # 255, 255, 0 - 'yellowgreen' : '#9acd32' # 154, 205, 50 + 'automatic': '#add8e6', # 173, 216, 230 + 'aliceblue': '#f0f8ff', # 240, 248, 255 + 'antiquewhite': '#faebd7', # 250, 235, 215 + 'aqua': '#00ffff', # 0, 255, 255 + 'aquamarine': '#7fffd4', # 127, 255, 212 + 'azure': '#f0ffff', # 240, 255, 255 + 'beige': '#f5f5dc', # 245, 245, 220 + 'bisque': '#ffe4c4', # 255, 228, 196 + 'black': '#000000', # 0, 0, 0 + 'blanchedalmond': '#ffebcd', # 255, 235, 205 + 'blue': '#0000ff', # 0, 0, 255 + 'blueviolet': '#8a2be2', # 138, 43, 226 + 'brown': '#a52a2a', # 165, 42, 42 + 'burlywood': '#deb887', # 222, 184, 135 + 'cadetblue': '#5f9ea0', # 95, 158, 160 + 'chartreuse': '#7fff00', # 127, 255, 0 + 'chocolate': '#d2691e', # 210, 105, 30 + 'coral': '#ff7f50', # 255, 127, 80 + 'cornflowerblue': '#6495ed', # 100, 149, 237 + 'cornsilk': '#fff8dc', # 255, 248, 220 + 'crimson': '#dc143c', # 220, 20, 60 + 'cyan': '#00ffff', # 0, 255, 255 + 'darkblue': '#00008b', # 0, 0, 139 + 'darkcyan': '#008b8b', # 0, 139, 139 + 'darkgoldenrod': '#b8860b', # 184, 134, 11 + 'darkgray': '#a9a9a9', # 169, 169, 169 + 'darkgreen': '#006400', # 0, 100, 0 + 'darkgrey': '#a9a9a9', # 169, 169, 169 + 'darkkhaki': '#bdb76b', # 189, 183, 107 + 'darkmagenta': '#8b008b', # 139, 0, 139 + 'darkolivegreen': '#556b2f', # 85, 107, 47 + 'darkorange': '#ff8c00', # 255, 140, 0 + 'darkorchid': '#9932cc', # 153, 50, 204 + 'darkred': '#8b0000', # 139, 0, 0 + 'darksalmon': '#e9967a', # 233, 150, 122 + 'darkseagreen': '#8fbc8f', # 143, 188, 143 + 'darkslateblue': '#483d8b', # 72, 61, 139 + 'darkslategray': '#2f4f4f', # 47, 79, 79 + 'darkslategrey': '#2f4f4f', # 47, 79, 79 + 'darkturquoise': '#00ced1', # 0, 206, 209 + 'darkviolet': '#9400d3', # 148, 0, 211 + 'deeppink': '#ff1493', # 255, 20, 147 + 'deepskyblue': '#00bfff', # 0, 191, 255 + 'dimgray': '#696969', # 105, 105, 105 + 'dimgrey': '#696969', # 105, 105, 105 + 'dodgerblue': '#1e90ff', # 30, 144, 255 + 'firebrick': '#b22222', # 178, 34, 34 + 'floralwhite': '#fffaf0', # 255, 250, 240 + 'forestgreen': '#228b22', # 34, 139, 34 + 'fuchsia': '#ff00ff', # 255, 0, 255 + 'gainsboro': '#dcdcdc', # 220, 220, 220 + 'ghostwhite': '#f8f8ff', # 248, 248, 255 + 'gold': '#ffd700', # 255, 215, 0 + 'goldenrod': '#daa520', # 218, 165, 32 + 'gray': '#808080', # 128, 128, 128 + 'green': '#008000', # 0, 128, 0 + 'greenyellow': '#adff2f', # 173, 255, 47 + 'grey': '#808080', # 128, 128, 128 + 'honeydew': '#f0fff0', # 240, 255, 240 + 'hotpink': '#ff69b4', # 255, 105, 180 + 'indianred': '#cd5c5c', # 205, 92, 92 + 'indigo': '#4b0082', # 75, 0, 130 + 'ivory': '#fffff0', # 255, 255, 240 + 'khaki': '#f0e68c', # 240, 230, 140 + 'lavender': '#e6e6fa', # 230, 230, 250 + 'lavenderblush': '#fff0f5', # 255, 240, 245 + 'lawngreen': '#7cfc00', # 124, 252, 0 + 'lemonchiffon': '#fffacd', # 255, 250, 205 + 'lightblue': '#add8e6', # 173, 216, 230 + 'lightcoral': '#f08080', # 240, 128, 128 + 'lightcyan': '#e0ffff', # 224, 255, 255 + 'lightgoldenrodyellow': '#fafad2', # 250, 250, 210 + 'lightgray': '#d3d3d3', # 211, 211, 211 + 'lightgreen': '#90ee90', # 144, 238, 144 + 'lightgrey': '#d3d3d3', # 211, 211, 211 + 'lightpink': '#ffb6c1', # 255, 182, 193 + 'lightsalmon': '#ffa07a', # 255, 160, 122 + 'lightseagreen': '#20b2aa', # 32, 178, 170 + 'lightskyblue': '#87cefa', # 135, 206, 250 + 'lightslategray': '#778899', # 119, 136, 153 + 'lightslategrey': '#778899', # 119, 136, 153 + 'lightsteelblue': '#b0c4de', # 176, 196, 222 + 'lightyellow': '#ffffe0', # 255, 255, 224 + 'lime': '#00ff00', # 0, 255, 0 + 'limegreen': '#32cd32', # 50, 205, 50 + 'linen': '#faf0e6', # 250, 240, 230 + 'magenta': '#ff00ff', # 255, 0, 255 + 'maroon': '#800000', # 128, 0, 0 + 'mediumaquamarine': '#66cdaa', # 102, 205, 170 + 'mediumblue': '#0000cd', # 0, 0, 205 + 'mediumorchid': '#ba55d3', # 186, 85, 211 + 'mediumpurple': '#9370db', # 147, 112, 219 + 'mediumseagreen': '#3cb371', # 60, 179, 113 + 'mediumslateblue': '#7b68ee', # 123, 104, 238 + 'mediumspringgreen': '#00fa9a', # 0, 250, 154 + 'mediumturquoise': '#48d1cc', # 72, 209, 204 + 'mediumvioletred': '#c71585', # 199, 21, 133 + 'midnightblue': '#191970', # 25, 25, 112 + 'mintcream': '#f5fffa', # 245, 255, 250 + 'mistyrose': '#ffe4e1', # 255, 228, 225 + 'moccasin': '#ffe4b5', # 255, 228, 181 + 'navajowhite': '#ffdead', # 255, 222, 173 + 'navy': '#000080', # 0, 0, 128 + 'oldlace': '#fdf5e6', # 253, 245, 230 + 'olive': '#808000', # 128, 128, 0 + 'olivedrab': '#6b8e23', # 107, 142, 35 + 'orange': '#ffa500', # 255, 165, 0 + 'orangered': '#ff4500', # 255, 69, 0 + 'orchid': '#da70d6', # 218, 112, 214 + 'palegoldenrod': '#eee8aa', # 238, 232, 170 + 'palegreen': '#98fb98', # 152, 251, 152 + 'paleturquoise': '#afeeee', # 175, 238, 238 + 'palevioletred': '#db7093', # 219, 112, 147 + 'papayawhip': '#ffefd5', # 255, 239, 213 + 'peachpuff': '#ffdab9', # 255, 218, 185 + 'peru': '#cd853f', # 205, 133, 63 + 'pink': '#ffc0cb', # 255, 192, 203 + 'plum': '#dda0dd', # 221, 160, 221 + 'powderblue': '#b0e0e6', # 176, 224, 230 + 'purple': '#800080', # 128, 0, 128 + 'red': '#ff0000', # 255, 0, 0 + 'rosybrown': '#bc8f8f', # 188, 143, 143 + 'royalblue': '#4169e1', # 65, 105, 225 + 'saddlebrown': '#8b4513', # 139, 69, 19 + 'salmon': '#fa8072', # 250, 128, 114 + 'sandybrown': '#f4a460', # 244, 164, 96 + 'seagreen': '#2e8b57', # 46, 139, 87 + 'seashell': '#fff5ee', # 255, 245, 238 + 'sienna': '#a0522d', # 160, 82, 45 + 'silver': '#c0c0c0', # 192, 192, 192 + 'skyblue': '#87ceeb', # 135, 206, 235 + 'slateblue': '#6a5acd', # 106, 90, 205 + 'slategray': '#708090', # 112, 128, 144 + 'slategrey': '#708090', # 112, 128, 144 + 'snow': '#fffafa', # 255, 250, 250 + 'springgreen': '#00ff7f', # 0, 255, 127 + 'steelblue': '#4682b4', # 70, 130, 180 + 'tan': '#d2b48c', # 210, 180, 140 + 'teal': '#008080', # 0, 128, 128 + 'thistle': '#d8bfd8', # 216, 191, 216 + 'tomato': '#ff6347', # 255, 99, 71 + 'turquoise': '#40e0d0', # 64, 224, 208 + 'violet': '#ee82ee', # 238, 130, 238 + 'wheat': '#f5deb3', # 245, 222, 179 + 'white': '#ffffff', # 255, 255, 255 + 'whitesmoke': '#f5f5f5', # 245, 245, 245 + 'yellow': '#ffff00', # 255, 255, 0 + 'yellowgreen': '#9acd32', # 154, 205, 50 } @@ -253,7 +253,7 @@ def html_to_float(c): h = f'{h[0]}{h[0]}{h[1]}{h[1]}{h[2]}{h[2]}' elif len(h) != 6: raise ValueError("color hex string (= '%s') must have length 3 or 6" % h) - return tuple([int(h[i:i + 2], base=16) / 255 for i in [0, 2, 4]]) + return tuple([int(h[i : i + 2], base=16) / 255 for i in [0, 2, 4]]) def rgbcolor(c, space='rgb'): @@ -620,8 +620,7 @@ def blend(self, color, fraction=0.5): color = color._rgb if isinstance(color, (list, tuple)) and len(color) == 3: color = [float(_) for _ in color] - return Color(rgbcolor([(1 - fraction) * a + fraction * b - for a, b in zip(self._rgb, color)])) + return Color(rgbcolor([(1 - fraction) * a + fraction * b for a, b in zip(self._rgb, color)])) raise TypeError(f"{color} must be a Color or float-convertible 3-tuple/list") def __add__(self, right): @@ -942,7 +941,7 @@ def html_color(self): """ return float_to_html(*self._rgb) - def lighter(self, fraction=1/3): + def lighter(self, fraction=1 / 3): """ Return a lighter "shade" of this RGB color by :meth:`blend`-ing it with white. This is **not** an inverse @@ -969,7 +968,7 @@ def lighter(self, fraction=1/3): """ return self.blend((1.0, 1.0, 1.0), fraction) - def darker(self, fraction=1/3): + def darker(self, fraction=1 / 3): """ Return a darker "shade" of this RGB color by :meth:`blend`-ing it with black. This is **not** an inverse of :meth:`lighter`. @@ -1002,6 +1001,7 @@ class ColorsDict(dict): sage: sorted(colors) ['aliceblue', 'antiquewhite', 'aqua', 'aquamarine', ...] """ + def __init__(self) -> None: """ Construct a dict-like collection of colors. The keys are the @@ -1311,6 +1311,7 @@ def get_cmap(cmap): if isinstance(cmap, str): from matplotlib import colormaps + try: return colormaps[cmap] except KeyError: @@ -1346,6 +1347,7 @@ def check_color_data(cfcm): """ cf, cm = cfcm from matplotlib.colors import Colormap + if isinstance(cm, Colormap): return cf, cm if isinstance(cf, Colormap): @@ -1361,6 +1363,7 @@ class Colormaps(MutableMapping): sage: sorted(colormaps) ['Accent', ...] """ + def __init__(self) -> None: """ Construct an empty mutable collection of color maps. @@ -1393,6 +1396,7 @@ def load_maps(self): """ if not self.maps: from matplotlib import colormaps + self.maps.update(colormaps) def __dir__(self): @@ -1410,9 +1414,7 @@ def __dir__(self): True """ self.load_maps() - methods = ['load_maps', '__dir__', '__len__', '__iter__', - '__contains__', '__getitem__', '__getattr__', - '__setitem__', '__delitem__'] + methods = ['load_maps', '__dir__', '__len__', '__iter__', '__contains__', '__getitem__', '__getattr__', '__setitem__', '__delitem__'] return dir(super()) + methods + sorted(self) def __len__(self) -> int: diff --git a/src/sage/plot/contour_plot.py b/src/sage/plot/contour_plot.py index 4482e82f33a..438b6275849 100644 --- a/src/sage/plot/contour_plot.py +++ b/src/sage/plot/contour_plot.py @@ -62,6 +62,7 @@ class ContourPlot(GraphicPrimitive): ....: plot_points=121, cmap='hsv') Graphics object consisting of 1 graphics primitive """ + def __init__(self, xy_data_array, xrange, yrange, options): """ Initialize base class ``ContourPlot``. @@ -98,6 +99,7 @@ def get_minmax_data(self): 3.0 """ from sage.plot.plot import minmax_data + return minmax_data(self.xrange, self.yrange, dict=True) def _allowed_options(self): @@ -111,24 +113,26 @@ def _allowed_options(self): sage: isinstance(C[0]._allowed_options(), dict) True """ - return {'plot_points': 'How many points to use for plotting precision', - 'cmap': """the name of a predefined colormap, + return { + 'plot_points': 'How many points to use for plotting precision', + 'cmap': """the name of a predefined colormap, a list of colors, or an instance of a matplotlib Colormap. Type: import matplotlib.cm; matplotlib.cm.datad.keys() for available colormap names.""", - 'colorbar': "Include a colorbar indicating the levels", - 'colorbar_options': "a dictionary of options for colorbars", - 'fill': 'Fill contours or not', - 'legend_label': 'The label for this item in the legend.', - 'contours': """Either an integer specifying the number of + 'colorbar': "Include a colorbar indicating the levels", + 'colorbar_options': "a dictionary of options for colorbars", + 'fill': 'Fill contours or not', + 'legend_label': 'The label for this item in the legend.', + 'contours': """Either an integer specifying the number of contour levels, or a sequence of numbers giving the actual contours to use.""", - 'linewidths': 'the width of the lines to be plotted', - 'linestyles': 'the style of the lines to be plotted', - 'labels': 'show line labels or not', - 'label_options': 'a dictionary of options for the labels', - 'zorder': 'The layer level in which to draw'} + 'linewidths': 'the width of the lines to be plotted', + 'linestyles': 'the style of the lines to be plotted', + 'labels': 'show line labels or not', + 'label_options': 'a dictionary of options for the labels', + 'zorder': 'The layer level in which to draw', + } def _repr_(self): """ @@ -156,6 +160,7 @@ def _render_on_subplot(self, subplot): Graphics object consisting of 1 graphics primitive """ from sage.rings.integer import Integer + options = self.options() fill = options['fill'] contours = options['contours'] @@ -165,8 +170,7 @@ def _render_on_subplot(self, subplot): cmap = get_cmap('gray') else: if isinstance(contours, (int, Integer)): - cmap = get_cmap([(i, i, i) - for i in xsrange(0, 1, 1 / contours)]) + cmap = get_cmap([(i, i, i) for i in xsrange(0, 1, 1 / contours)]) else: step = 1 / Integer(len(contours)) cmap = get_cmap([(i, i, i) for i in xsrange(0, 1, step)]) @@ -180,11 +184,9 @@ def _render_on_subplot(self, subplot): CSF = None if fill: if contours is None: - CSF = subplot.contourf(self.xy_data_array, cmap=cmap, - extent=(x0, x1, y0, y1)) + CSF = subplot.contourf(self.xy_data_array, cmap=cmap, extent=(x0, x1, y0, y1)) else: - CSF = subplot.contourf(self.xy_data_array, contours, cmap=cmap, - extent=(x0, x1, y0, y1), extend='both') + CSF = subplot.contourf(self.xy_data_array, contours, cmap=cmap, extent=(x0, x1, y0, y1), extend='both') linewidths = options.get('linewidths', None) if isinstance(linewidths, (int, Integer)): @@ -193,20 +195,16 @@ def _render_on_subplot(self, subplot): linewidths = tuple(int(x) for x in linewidths) from sage.plot.misc import get_matplotlib_linestyle + linestyles = options.get('linestyles', None) if isinstance(linestyles, (list, tuple)): - linestyles = [get_matplotlib_linestyle(i, 'long') - for i in linestyles] + linestyles = [get_matplotlib_linestyle(i, 'long') for i in linestyles] else: linestyles = get_matplotlib_linestyle(linestyles, 'long') if contours is None: - CS = subplot.contour(self.xy_data_array, cmap=cmap, - extent=(x0, x1, y0, y1), - linewidths=linewidths, linestyles=linestyles) + CS = subplot.contour(self.xy_data_array, cmap=cmap, extent=(x0, x1, y0, y1), linewidths=linewidths, linestyles=linestyles) else: - CS = subplot.contour(self.xy_data_array, contours, cmap=cmap, - extent=(x0, x1, y0, y1), - linewidths=linewidths, linestyles=linestyles) + CS = subplot.contour(self.xy_data_array, contours, cmap=cmap, extent=(x0, x1, y0, y1), linewidths=linewidths, linestyles=linestyles) if options.get('labels', False): label_options = options['label_options'] label_options['fontsize'] = int(label_options['fontsize']) @@ -216,6 +214,7 @@ def _render_on_subplot(self, subplot): if options.get('colorbar', False): colorbar_options = options['colorbar_options'] from matplotlib import colorbar + cax, kwds = colorbar.make_axes_gridspec(subplot, **colorbar_options) if CSF is None: cb = colorbar.Colorbar(cax, CS, **kwds) @@ -225,11 +224,8 @@ def _render_on_subplot(self, subplot): @suboptions('colorbar', orientation='vertical', format=None, spacing='uniform') -@suboptions('label', fontsize=9, colors='blue', inline=None, inline_spacing=3, - fmt="%1.2f") -@options(plot_points=100, fill=True, contours=None, linewidths=None, - linestyles=None, labels=False, frame=True, axes=False, colorbar=False, - legend_label=None, aspect_ratio=1, region=None) +@suboptions('label', fontsize=9, colors='blue', inline=None, inline_spacing=3, fmt="%1.2f") +@options(plot_points=100, fill=True, contours=None, linewidths=None, linestyles=None, labels=False, frame=True, axes=False, colorbar=False, legend_label=None, aspect_ratio=1, region=None) def contour_plot(f, xrange, yrange, **options): r""" ``contour_plot`` takes a function of two variables, `f(x,y)` @@ -887,14 +883,11 @@ def f(x, y): return cos(x) + sin(y) region = options.pop('region') ev = [f] if region is None else [f, region] - F, ranges = setup_for_eval_on_grid(ev, [xrange, yrange], - options['plot_points']) + F, ranges = setup_for_eval_on_grid(ev, [xrange, yrange], options['plot_points']) h = F[0] xrange, yrange = (r[:2] for r in ranges) - xy_data_array = [[h(x, y) for x in xsrange(*ranges[0], - include_endpoint=True)] - for y in xsrange(*ranges[1], include_endpoint=True)] + xy_data_array = [[h(x, y) for x in xsrange(*ranges[0], include_endpoint=True)] for y in xsrange(*ranges[1], include_endpoint=True)] g = Graphics() @@ -906,8 +899,7 @@ def f(x, y): return cos(x) + sin(y) if scale in ('semilogy', 'semilogx'): options['aspect_ratio'] = 'automatic' - g._set_extra_kwds(Graphics._extract_kwds_for_show(options, - ignore=['xmin', 'xmax'])) + g._set_extra_kwds(Graphics._extract_kwds_for_show(options, ignore=['xmin', 'xmax'])) # Was a single contour level explicitly given? If "contours" is # the integer 1, then there will be a single level, but we can't @@ -916,9 +908,7 @@ def f(x, y): return cos(x) + sin(y) # there's a single contour and fill=True, we fall through to let # matplotlib complain that "Filled contours require at least 2 # levels." - if (isinstance(options["contours"], (list, tuple)) - and len(options["contours"]) == 1 - and options.get("fill") is False): + if isinstance(options["contours"], (list, tuple)) and len(options["contours"]) == 1 and options.get("fill") is False: # When there's only one level (say, zero), matplotlib doesn't # handle it well. If all of the data lie on one side of that # level -- for example, if f(x,y) >= 0 for all x,y -- then it @@ -930,6 +920,7 @@ def f(x, y): return cos(x) + sin(y) # plots don't look great, but they're not empty, which is an # improvement. import numpy as np + dx = ranges[0][2] dy = ranges[1][2] z0 = options["contours"][0] @@ -978,36 +969,26 @@ def f(x, y): return cos(x) + sin(y) # Now we check if (a) all of the data lie on one side of # z0, and (b) if perturbing the data will actually help by # moving anything across z0. - if (np.all(xy_data_array >= z0) and - np.any(xy_data_array - z0 < tol)): + if np.all(xy_data_array >= z0) and np.any(xy_data_array - z0 < tol): from warnings import warn - warn("pathological contour plot of a function whose " - "values all lie on one side of the sole contour; " - "we are adding more plot points and perturbing " - "your function values.") + + warn("pathological contour plot of a function whose " "values all lie on one side of the sole contour; " "we are adding more plot points and perturbing " "your function values.") # The choice of "4" here is not based on much of anything. # It works well enough for the examples in the doctests. if not isinstance(options["plot_points"], (list, tuple)): - options["plot_points"] = (options["plot_points"], - options["plot_points"]) - options["plot_points"] = (options["plot_points"][0] * 4, - options["plot_points"][1] * 4) + options["plot_points"] = (options["plot_points"], options["plot_points"]) + options["plot_points"] = (options["plot_points"][0] * 4, options["plot_points"][1] * 4) # Re-plot with more points... - F, ranges = setup_for_eval_on_grid(ev, [xrange, yrange], - options['plot_points']) + F, ranges = setup_for_eval_on_grid(ev, [xrange, yrange], options['plot_points']) h = F[0] xrange, yrange = (r[:2] for r in ranges) # ...and a function whose values are shifted towards # z0 by "tol". - xy_data_array = [[h(x, y) - c * tol - for x in xsrange(*ranges[0], - include_endpoint=True)] - for y in xsrange(*ranges[1], - include_endpoint=True)] + xy_data_array = [[h(x, y) - c * tol for x in xsrange(*ranges[0], include_endpoint=True)] for y in xsrange(*ranges[1], include_endpoint=True)] if region is not None: import numpy @@ -1016,12 +997,7 @@ def f(x, y): return cos(x) + sin(y) m = F[1] - mask = numpy.asarray([[m(x, y) <= 0 - for x in xsrange(*ranges[0], - include_endpoint=True)] - for y in xsrange(*ranges[1], - include_endpoint=True)], - dtype=bool) + mask = numpy.asarray([[m(x, y) <= 0 for x in xsrange(*ranges[0], include_endpoint=True)] for y in xsrange(*ranges[1], include_endpoint=True)], dtype=bool) xy_data_array[mask] = numpy.ma.masked @@ -1351,10 +1327,10 @@ def f(x, y): ValueError: only one of color or rgbcolor should be specified """ from sage.structure.element import Expression + if isinstance(f, Expression) and f.is_relational(): if f.operator() != operator.eq: - raise ValueError("input to implicit plot must be function " - "or equation") + raise ValueError("input to implicit plot must be function " "or equation") f = f.lhs() - f.rhs() linewidths = options.pop('linewidth', None) linestyles = options.pop('linestyle', None) @@ -1373,25 +1349,17 @@ def f(x, y): incol = options.pop('fillcolor', 'blue') bordercol = options.pop('cmap', [None])[0] from sage.structure.element import Expression + if not isinstance(f, Expression): - return region_plot(lambda x, y: f(x, y) < 0, xrange, yrange, - borderwidth=linewidths, borderstyle=linestyles, - incol=incol, bordercol=bordercol, - **options) - return region_plot(f < 0, xrange, yrange, borderwidth=linewidths, - borderstyle=linestyles, - incol=incol, bordercol=bordercol, - **options) + return region_plot(lambda x, y: f(x, y) < 0, xrange, yrange, borderwidth=linewidths, borderstyle=linestyles, incol=incol, bordercol=bordercol, **options) + return region_plot(f < 0, xrange, yrange, borderwidth=linewidths, borderstyle=linestyles, incol=incol, bordercol=bordercol, **options) if options['fill'] is False: options.pop('fillcolor', None) - return contour_plot(f, xrange, yrange, linewidths=linewidths, - linestyles=linestyles, **options) + return contour_plot(f, xrange, yrange, linewidths=linewidths, linestyles=linestyles, **options) raise ValueError("fill=%s is not supported" % options['fill']) -@options(plot_points=100, incol='blue', outcol=None, bordercol=None, - borderstyle=None, borderwidth=None, frame=False, axes=True, - legend_label=None, aspect_ratio=1, alpha=1) +@options(plot_points=100, incol='blue', outcol=None, bordercol=None, borderstyle=None, borderwidth=None, frame=False, axes=True, legend_label=None, aspect_ratio=1, alpha=1) def region_plot(f, xrange, yrange, **options): r""" ``region_plot`` takes a boolean function of two variables, `f(x, y)` @@ -1666,35 +1634,21 @@ def region_plot(f, xrange, yrange, **options): if not isinstance(f, (list, tuple)): f = [f] - feqs = [equify(g) for g in f - if isinstance(g, Expression) and g.operator() is operator.eq - and not equify(g).is_zero()] - f = [equify(g) for g in f - if not (isinstance(g, Expression) and g.operator() is operator.eq)] + feqs = [equify(g) for g in f if isinstance(g, Expression) and g.operator() is operator.eq and not equify(g).is_zero()] + f = [equify(g) for g in f if not (isinstance(g, Expression) and g.operator() is operator.eq)] neqs = len(feqs) if neqs > 1: - warn("There are at least 2 equations; " - "If the region is degenerated to points, " - "plotting might show nothing.") + warn("There are at least 2 equations; " "If the region is degenerated to points, " "plotting might show nothing.") feqs = [sum([fn**2 for fn in feqs])] neqs = 1 if neqs and not bordercol: bordercol = incol if not f: - return implicit_plot(feqs[0], xrange, yrange, fill=False, - linewidth=borderwidth, linestyle=borderstyle, - color=bordercol, **options) - f_all, ranges = setup_for_eval_on_grid(feqs + f, - [xrange, yrange], - plot_points) + return implicit_plot(feqs[0], xrange, yrange, fill=False, linewidth=borderwidth, linestyle=borderstyle, color=bordercol, **options) + f_all, ranges = setup_for_eval_on_grid(feqs + f, [xrange, yrange], plot_points) xrange, yrange = (r[:2] for r in ranges) - xy_data_arrays = numpy.asarray([[[func(x, y) - for x in xsrange(*ranges[0], - include_endpoint=True)] - for y in xsrange(*ranges[1], - include_endpoint=True)] - for func in f_all[neqs::]], dtype=float) + xy_data_arrays = numpy.asarray([[[func(x, y) for x in xsrange(*ranges[0], include_endpoint=True)] for y in xsrange(*ranges[1], include_endpoint=True)] for func in f_all[neqs::]], dtype=float) xy_data_array = numpy.abs(xy_data_arrays.prod(axis=0)) # Now we need to set entries to negative iff all # functions were negative at that point. @@ -1702,6 +1656,7 @@ def region_plot(f, xrange, yrange, **options): xy_data_array[neg_indices] = -xy_data_array[neg_indices] from matplotlib.colors import ListedColormap + incol = rgbcolor(incol) if outcol: outcol = rgbcolor(outcol) @@ -1723,34 +1678,19 @@ def region_plot(f, xrange, yrange, **options): if scale in ('semilogy', 'semilogx'): options['aspect_ratio'] = 'automatic' - g._set_extra_kwds(Graphics._extract_kwds_for_show(options, - ignore=['xmin', 'xmax'])) + g._set_extra_kwds(Graphics._extract_kwds_for_show(options, ignore=['xmin', 'xmax'])) if neqs == 0: - g.add_primitive(ContourPlot(xy_data_array, xrange, yrange, - dict(contours=[-1e-20, 0, 1e-20], - cmap=cmap, - fill=True, **options))) + g.add_primitive(ContourPlot(xy_data_array, xrange, yrange, dict(contours=[-1e-20, 0, 1e-20], cmap=cmap, fill=True, **options))) else: - mask = numpy.asarray([[elt > 0 for elt in rows] - for rows in xy_data_array], - dtype=bool) - xy_data_array = numpy.asarray([[f_all[0](x, y) - for x in xsrange(*ranges[0], - include_endpoint=True)] - for y in xsrange(*ranges[1], - include_endpoint=True)], - dtype=float) + mask = numpy.asarray([[elt > 0 for elt in rows] for rows in xy_data_array], dtype=bool) + xy_data_array = numpy.asarray([[f_all[0](x, y) for x in xsrange(*ranges[0], include_endpoint=True)] for y in xsrange(*ranges[1], include_endpoint=True)], dtype=float) xy_data_array[mask] = None if bordercol or borderstyle or borderwidth: cmap = [rgbcolor(bordercol)] if bordercol else ['black'] linestyles = [borderstyle] if borderstyle else None linewidths = [borderwidth] if borderwidth else None - g.add_primitive(ContourPlot(xy_data_array, xrange, yrange, - dict(linestyles=linestyles, - linewidths=linewidths, - contours=[0], cmap=[bordercol], - fill=False, **options))) + g.add_primitive(ContourPlot(xy_data_array, xrange, yrange, dict(linestyles=linestyles, linewidths=linewidths, contours=[0], cmap=[bordercol], fill=False, **options))) return g @@ -1781,6 +1721,7 @@ def equify(f): """ from sage.calculus.expr import symbolic_expression from sage.structure.element import Expression + if not isinstance(f, Expression): return lambda x, y: -1 if f(x, y) else 1 diff --git a/src/sage/plot/density_plot.py b/src/sage/plot/density_plot.py index 4557c7d7d50..5144d3c00ba 100644 --- a/src/sage/plot/density_plot.py +++ b/src/sage/plot/density_plot.py @@ -3,7 +3,7 @@ Density plots """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2006 Alex Clemesha , # William Stein , # 2008 Mike Hansen , @@ -19,7 +19,7 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.plot.primitive import GraphicPrimitive from sage.misc.decorators import options from sage.plot.colors import get_cmap @@ -63,6 +63,7 @@ class DensityPlot(GraphicPrimitive): sage: density_plot(x^2 - y^3 + 10*sin(x*y), (x,-4,4), (y,-4,4), plot_points=121, cmap='hsv') Graphics object consisting of 1 graphics primitive """ + def __init__(self, xy_data_array, xrange, yrange, options): """ Initialize base class ``DensityPlot``. @@ -98,6 +99,7 @@ def get_minmax_data(self): 3.0 """ from sage.plot.plot import minmax_data + return minmax_data(self.xrange, self.yrange, dict=True) def _allowed_options(self): @@ -109,12 +111,14 @@ def _allowed_options(self): sage: isinstance(density_plot(x, (-2,3), (1,10))[0]._allowed_options(), dict) True """ - return {'plot_points': 'How many points to use for plotting precision', - 'cmap': """the name of a predefined colormap, + return { + 'plot_points': 'How many points to use for plotting precision', + 'cmap': """the name of a predefined colormap, a list of colors or an instance of a matplotlib Colormap. Type: import matplotlib.cm; matplotlib.cm.datad.keys() for available colormap names.""", - 'interpolation': 'What interpolation method to use'} + 'interpolation': 'What interpolation method to use', + } def _repr_(self): """ @@ -145,9 +149,7 @@ def _render_on_subplot(self, subplot): x0, x1 = float(self.xrange[0]), float(self.xrange[1]) y0, y1 = float(self.yrange[0]), float(self.yrange[1]) - subplot.imshow(self.xy_data_array, origin='lower', - cmap=cmap, extent=(x0,x1,y0,y1), - interpolation=options['interpolation']) + subplot.imshow(self.xy_data_array, origin='lower', cmap=cmap, extent=(x0, x1, y0, y1), interpolation=options['interpolation']) @options(plot_points=25, cmap='gray', interpolation='catrom') @@ -304,14 +306,14 @@ def f(x, y): return x**2 * cos(x*y) from sage.plot.graphics import Graphics from sage.plot.misc import setup_for_eval_on_grid from sage.rings.real_double import RDF + g, ranges = setup_for_eval_on_grid([f], [xrange, yrange], options['plot_points']) g = g[0] xrange, yrange = (r[:2] for r in ranges) - xy_data_array = [[RDF(g(x,y)) for x in xsrange(*ranges[0], include_endpoint=True)] - for y in xsrange(*ranges[1], include_endpoint=True)] + xy_data_array = [[RDF(g(x, y)) for x in xsrange(*ranges[0], include_endpoint=True)] for y in xsrange(*ranges[1], include_endpoint=True)] g = Graphics() - g._set_extra_kwds(Graphics._extract_kwds_for_show(options, ignore=['xmin','xmax'])) + g._set_extra_kwds(Graphics._extract_kwds_for_show(options, ignore=['xmin', 'xmax'])) g.add_primitive(DensityPlot(xy_data_array, xrange, yrange, options)) return g diff --git a/src/sage/plot/disk.py b/src/sage/plot/disk.py index c40a295419e..d48d4f1db44 100644 --- a/src/sage/plot/disk.py +++ b/src/sage/plot/disk.py @@ -1,6 +1,7 @@ """ Disks """ + # ***************************************************************************** # Copyright (C) 2006 Alex Clemesha , # William Stein , @@ -64,6 +65,7 @@ class Disk(GraphicPrimitive): sage: disk((2,3), 2, (0,pi/2)) Graphics object consisting of 1 graphics primitive """ + def __init__(self, point, r, angle, options): """ Initialize base class ``Disk``. @@ -111,9 +113,8 @@ def get_minmax_data(self): 5.0 """ from sage.plot.plot import minmax_data - return minmax_data([self.x - self.r, self.x + self.r], - [self.y - self.r, self.y + self.r], - dict=True) + + return minmax_data([self.x - self.r, self.x + self.r], [self.y - self.r, self.y + self.r], dict=True) def _allowed_options(self): """ @@ -128,14 +129,7 @@ def _allowed_options(self): sage: p[0]._allowed_options()['zorder'] 'The layer level in which to draw' """ - return {'alpha': 'How transparent the figure is.', - 'fill': 'Whether or not to fill the disk.', - 'legend_label': 'The label for this item in the legend.', - 'legend_color': 'The color of the legend text.', - 'thickness': 'How thick the border of the disk is.', - 'rgbcolor': 'The color as an RGB tuple.', - 'hue': 'The color given as a hue.', - 'zorder': 'The layer level in which to draw'} + return {'alpha': 'How transparent the figure is.', 'fill': 'Whether or not to fill the disk.', 'legend_label': 'The label for this item in the legend.', 'legend_color': 'The color of the legend text.', 'thickness': 'How thick the border of the disk is.', 'rgbcolor': 'The color as an RGB tuple.', 'hue': 'The color given as a hue.', 'zorder': 'The layer level in which to draw'} def _repr_(self): """ @@ -165,12 +159,12 @@ def _render_on_subplot(self, subplot): sage: p.save(f) """ from matplotlib import patches + options = self.options() - deg1 = self.rad1*(180./pi) # convert radians to degrees - deg2 = self.rad2*(180./pi) + deg1 = self.rad1 * (180.0 / pi) # convert radians to degrees + deg2 = self.rad2 * (180.0 / pi) z = int(options.pop('zorder', 0)) - p = patches.Wedge((float(self.x), float(self.y)), float(self.r), float(deg1), - float(deg2), zorder=z) + p = patches.Wedge((float(self.x), float(self.y)), float(self.r), float(deg1), float(deg2), zorder=z) a = float(options['alpha']) p.set_alpha(a) p.set_linewidth(float(options['thickness'])) @@ -227,23 +221,24 @@ def plot3d(self, z=0, **kwds): del options['zorder'] n = 50 x, y, r, rad1, rad2 = self.x, self.y, self.r, self.rad1, self.rad2 - dt = float((rad2-rad1)/n) + dt = float((rad2 - rad1) / n) xdata = [x] ydata = [y] - xdata.extend([x+r*cos(t*dt+rad1) for t in range(n+1)]) - ydata.extend([y+r*sin(t*dt+rad1) for t in range(n+1)]) + xdata.extend([x + r * cos(t * dt + rad1) for t in range(n + 1)]) + ydata.extend([y + r * sin(t * dt + rad1) for t in range(n + 1)]) xdata.append(x) ydata.append(y) if fill: from .polygon import Polygon + return Polygon(xdata, ydata, options).plot3d(z) from .line import Line + return Line(xdata, ydata, options).plot3d().translate((0, 0, z)) @rename_keyword(color='rgbcolor') -@options(alpha=1, fill=True, rgbcolor=(0, 0, 1), thickness=0, legend_label=None, - legend_color=None, aspect_ratio=1.0) +@options(alpha=1, fill=True, rgbcolor=(0, 0, 1), thickness=0, legend_label=None, legend_color=None, aspect_ratio=1.0) def disk(point, radius, angle, **options): r""" A disk (that is, a sector or wedge of a circle) with center @@ -348,6 +343,7 @@ def disk(point, radius, angle, **options): sage: D = disk((0, 0), 5, (0, pi/2), legend_label='test') """ from sage.plot.graphics import Graphics + g = Graphics() # Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'. @@ -367,5 +363,4 @@ def disk(point, radius, angle, **options): return g if len(point) == 3: return g[0].plot3d(z=point[2]) - raise ValueError('the center point of a plotted disk should have ' - 'two or three coordinates') + raise ValueError('the center point of a plotted disk should have ' 'two or three coordinates') diff --git a/src/sage/plot/ellipse.py b/src/sage/plot/ellipse.py index 3679f171089..1b77fe805ef 100644 --- a/src/sage/plot/ellipse.py +++ b/src/sage/plot/ellipse.py @@ -1,6 +1,7 @@ """ Ellipses """ + # **************************************************************************** # Copyright (C) 2010 Vincent Delecroix <20100.delecroix@gmail.com> # @@ -46,6 +47,7 @@ class Ellipse(GraphicPrimitive): sage: Ellipse(0, 0, 2, 1, pi/4, {}) Ellipse centered at (0.0, 0.0) with radii (2.0, 1.0) and angle 0.78539816339... """ + def __init__(self, x, y, r1, r2, angle, options): """ Initialize base class ``Ellipse``. @@ -112,7 +114,7 @@ def get_minmax_data(self): epsilon = 0.000001 cos_angle = cos(self.angle) - if abs(cos_angle) > 1-epsilon: + if abs(cos_angle) > 1 - epsilon: xmax = self.r1 ymax = self.r2 elif abs(cos_angle) < epsilon: @@ -121,18 +123,12 @@ def get_minmax_data(self): else: sin_angle = sin(self.angle) tan_angle = sin_angle / cos_angle - sxmax = ((self.r2*tan_angle)/self.r1)**2 - symax = (self.r2/(self.r1*tan_angle))**2 - xmax = ( - abs(self.r1 * cos_angle / sqrt(sxmax+1.)) + - abs(self.r2 * sin_angle / sqrt(1./sxmax+1.))) - ymax = ( - abs(self.r1 * sin_angle / sqrt(symax+1.)) + - abs(self.r2 * cos_angle / sqrt(1./symax+1.))) - - return minmax_data([self.x - xmax, self.x + xmax], - [self.y - ymax, self.y + ymax], - dict=True) + sxmax = ((self.r2 * tan_angle) / self.r1) ** 2 + symax = (self.r2 / (self.r1 * tan_angle)) ** 2 + xmax = abs(self.r1 * cos_angle / sqrt(sxmax + 1.0)) + abs(self.r2 * sin_angle / sqrt(1.0 / sxmax + 1.0)) + ymax = abs(self.r1 * sin_angle / sqrt(symax + 1.0)) + abs(self.r2 * cos_angle / sqrt(1.0 / symax + 1.0)) + + return minmax_data([self.x - xmax, self.x + xmax], [self.y - ymax, self.y + ymax], dict=True) def _allowed_options(self): """ @@ -146,19 +142,7 @@ def _allowed_options(self): sage: p[0]._allowed_options()['facecolor'] '2D only: The color of the face as an RGB tuple.' """ - return {'alpha':'How transparent the figure is.', - 'fill': 'Whether or not to fill the ellipse.', - 'legend_label':'The label for this item in the legend.', - 'legend_color':'The color of the legend text.', - 'thickness':'How thick the border of the ellipse is.', - 'edgecolor':'2D only: The color of the edge as an RGB tuple.', - 'facecolor':'2D only: The color of the face as an RGB tuple.', - 'rgbcolor':'The color (edge and face) as an RGB tuple.', - 'hue':'The color given as a hue.', - 'zorder':'2D only: The layer level in which to draw', - 'linestyle':"2D only: The style of the line, which is one of " - "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " - "respectively."} + return {'alpha': 'How transparent the figure is.', 'fill': 'Whether or not to fill the ellipse.', 'legend_label': 'The label for this item in the legend.', 'legend_color': 'The color of the legend text.', 'thickness': 'How thick the border of the ellipse is.', 'edgecolor': '2D only: The color of the edge as an RGB tuple.', 'facecolor': '2D only: The color of the face as an RGB tuple.', 'rgbcolor': 'The color (edge and face) as an RGB tuple.', 'hue': 'The color given as a hue.', 'zorder': '2D only: The layer level in which to draw', 'linestyle': "2D only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively."} def _repr_(self): """ @@ -193,10 +177,7 @@ def _render_on_subplot(self, subplot): from sage.plot.misc import get_matplotlib_linestyle options = self.options() - p = patches.Ellipse( - (self.x,self.y), - self.r1*2.,self.r2*2., - angle=self.angle/pi*180.) + p = patches.Ellipse((self.x, self.y), self.r1 * 2.0, self.r2 * 2.0, angle=self.angle / pi * 180.0) p.set_linewidth(float(options['thickness'])) p.set_fill(options['fill']) a = float(options['alpha']) @@ -207,7 +188,7 @@ def _render_on_subplot(self, subplot): ec = fc = to_mpl_color(options['rgbcolor']) p.set_edgecolor(ec) p.set_facecolor(fc) - p.set_linestyle(get_matplotlib_linestyle(options['linestyle'],return_type='long')) + p.set_linestyle(get_matplotlib_linestyle(options['linestyle'], return_type='long')) p.set_label(options['legend_label']) z = int(options.pop('zorder', 0)) p.set_zorder(z) @@ -229,8 +210,7 @@ def plot3d(self): @rename_keyword(color='rgbcolor') -@options(alpha=1, fill=False, thickness=1, edgecolor='blue', facecolor='blue', linestyle='solid', zorder=5, - aspect_ratio=1.0, legend_label=None, legend_color=None) +@options(alpha=1, fill=False, thickness=1, edgecolor='blue', facecolor='blue', linestyle='solid', zorder=5, aspect_ratio=1.0, legend_label=None, legend_color=None) def ellipse(center, r1, r2, angle=0, **options): """ Return an ellipse centered at a point center = ``(x,y)`` with radii = @@ -353,6 +333,7 @@ def ellipse(center, r1, r2, angle=0, **options): sage: E = ellipse((0,0), 2, 1, legend_label='test') """ from sage.plot.graphics import Graphics + g = Graphics() # Reset aspect_ratio to 'automatic' in case scale is 'semilog[xy]'. @@ -364,7 +345,7 @@ def ellipse(center, r1, r2, angle=0, **options): options['aspect_ratio'] = 'automatic' g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) - g.add_primitive(Ellipse(center[0],center[1],r1,r2,angle,options)) + g.add_primitive(Ellipse(center[0], center[1], r1, r2, angle, options)) if options['legend_label']: g.legend(True) g._legend_colors = [options['legend_color']] diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index d503ff46d8f..fcfa7086f13 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -78,15 +78,14 @@ def _parse_figsize(figsize): (5.0, 3.75) """ from matplotlib import rcParams + if isinstance(figsize, (list, tuple)): # figsize should be a pair of positive numbers if len(figsize) != 2: - raise ValueError("figsize should be a positive number or a list " - f"of two positive numbers, not {figsize}") + raise ValueError("figsize should be a positive number or a list " f"of two positive numbers, not {figsize}") figsize = (float(figsize[0]), float(figsize[1])) # floats for mpl if not (figsize[0] > 0 and figsize[1] > 0): - raise ValueError("figsize should be positive numbers, " - f"not {figsize[0]} and {figsize[1]}") + raise ValueError("figsize should be positive numbers, " f"not {figsize[0]} and {figsize[1]}") else: # in this case, figsize is a single number representing the width and # should be positive @@ -982,8 +981,7 @@ def _rich_repr_(self, display_manager, **kwds): raise ValueError('unknown graphics output preference') for file_ext, output_container in preferred: if output_container in display_manager.supported_output(): - return display_manager.graphics_from_save( - self.save, kwds, file_ext, output_container) + return display_manager.graphics_from_save(self.save, kwds, file_ext, output_container) def __str__(self): r""" @@ -1073,6 +1071,7 @@ def __setitem__(self, i, x): Graphics object consisting of 3 graphics primitives """ from sage.plot.primitive import GraphicPrimitive + if not isinstance(x, GraphicPrimitive): raise TypeError("x must be a GraphicPrimitive") self._objects[int(i)] = x @@ -1176,6 +1175,7 @@ def __add__(self, other): return self if not isinstance(other, Graphics): from sage.plot.plot3d.base import Graphics3d + if isinstance(other, Graphics3d): return self.plot3d() + other raise TypeError("other (=%s) must be a Graphics objects" % other) @@ -1188,11 +1188,9 @@ def __add__(self, other): g._legend_opts.update(self._legend_opts) g._legend_opts.update(other._legend_opts) if 'flip_x' in self._extra_kwds and 'flip_x' in other._extra_kwds: - g._extra_kwds['flip_x'] = (self._extra_kwds['flip_x'] - or other._extra_kwds['flip_x']) + g._extra_kwds['flip_x'] = self._extra_kwds['flip_x'] or other._extra_kwds['flip_x'] if 'flip_y' in self._extra_kwds and 'flip_y' in other._extra_kwds: - g._extra_kwds['flip_y'] = (self._extra_kwds['flip_y'] - or other._extra_kwds['flip_y']) + g._extra_kwds['flip_y'] = self._extra_kwds['flip_y'] or other._extra_kwds['flip_y'] if self.aspect_ratio() == 'automatic': g.set_aspect_ratio(other.aspect_ratio()) elif other.aspect_ratio() == 'automatic': @@ -1264,6 +1262,7 @@ def plot3d(self, z=0, **kwds): Graphics3d Object """ from sage.plot.plot3d.base import Graphics3dGroup + g = Graphics3dGroup([g.plot3d(**kwds) for g in self._objects]) if z: g = g.translate(0, 0, z) @@ -1366,8 +1365,7 @@ def _set_scale(self, subplot, scale=None, base=None): return ('linear', 'linear', 10, 10) if isinstance(scale, (list, tuple)): if len(scale) != 2 and len(scale) != 3: - raise ValueError("If the input is a tuple, it must be of " - "the form (scale, base) or (scale, basex, basey)") + raise ValueError("If the input is a tuple, it must be of " "the form (scale, base) or (scale, basex, basey)") if len(scale) == 2: base = scale[1] else: @@ -1375,8 +1373,7 @@ def _set_scale(self, subplot, scale=None, base=None): scale = scale[0] if scale not in ('linear', 'loglog', 'semilogx', 'semilogy'): - raise ValueError("The scale must be one of 'linear', 'loglog'," - f" 'semilogx' or 'semilogy' -- got '{scale}'") + raise ValueError("The scale must be one of 'linear', 'loglog'," f" 'semilogx' or 'semilogy' -- got '{scale}'") if isinstance(base, (list, tuple)): basex, basey = base @@ -1386,8 +1383,7 @@ def _set_scale(self, subplot, scale=None, base=None): basex = basey = base if basex <= 1 or basey <= 1: - raise ValueError("The base of the logarithm must be greater " - "than 1") + raise ValueError("The base of the logarithm must be greater " "than 1") xscale = yscale = 'linear' if scale == 'linear': @@ -1416,36 +1412,47 @@ def _set_scale(self, subplot, scale=None, base=None): # this dictionary to contain the default value for that parameter. SHOW_OPTIONS = { # axes options - 'axes': None, 'axes_labels': None, 'axes_labels_size': None, - 'axes_pad': None, 'base': None, 'scale': None, - 'xmin': None, 'xmax': None, 'ymin': None, 'ymax': None, - 'flip_x': False, 'flip_y': False, + 'axes': None, + 'axes_labels': None, + 'axes_labels_size': None, + 'axes_pad': None, + 'base': None, + 'scale': None, + 'xmin': None, + 'xmax': None, + 'ymin': None, + 'ymax': None, + 'flip_x': False, + 'flip_y': False, # Figure options - 'aspect_ratio': None, 'dpi': DEFAULT_DPI, 'fig_tight': True, - 'figsize': None, 'fontsize': None, 'frame': False, - 'title': None, 'title_pos': None, 'transparent': False, + 'aspect_ratio': None, + 'dpi': DEFAULT_DPI, + 'fig_tight': True, + 'figsize': None, + 'fontsize': None, + 'frame': False, + 'title': None, + 'title_pos': None, + 'transparent': False, # Grid options - 'gridlines': None, 'gridlinesstyle': None, - 'hgridlinesstyle': None, 'vgridlinesstyle': None, + 'gridlines': None, + 'gridlinesstyle': None, + 'hgridlinesstyle': None, + 'vgridlinesstyle': None, # Legend options - 'legend_options': {}, 'show_legend': None, + 'legend_options': {}, + 'show_legend': None, # Ticks options - 'ticks': None, 'tick_formatter': None, 'ticks_integer': False, + 'ticks': None, + 'tick_formatter': None, + 'ticks_integer': False, # Text options - 'typeset': 'default'} + 'typeset': 'default', + } # Default options for the legends: - LEGEND_OPTIONS = {'back_color': 'white', 'borderpad': 0.6, - 'borderaxespad': None, - 'columnspacing': None, - 'fancybox': False, 'font_family': 'sans-serif', - 'font_size': 'medium', 'font_style': 'normal', - 'font_variant': 'normal', 'font_weight': 'medium', - 'handlelength': 0.05, 'handletextpad': 0.5, - 'labelspacing': 0.02, 'loc': 'best', - 'markerscale': 0.6, 'ncol': 1, 'numpoints': 2, - 'shadow': True, 'title': None} + LEGEND_OPTIONS = {'back_color': 'white', 'borderpad': 0.6, 'borderaxespad': None, 'columnspacing': None, 'fancybox': False, 'font_family': 'sans-serif', 'font_size': 'medium', 'font_style': 'normal', 'font_variant': 'normal', 'font_weight': 'medium', 'handlelength': 0.05, 'handletextpad': 0.5, 'labelspacing': 0.02, 'loc': 'best', 'markerscale': 0.6, 'ncol': 1, 'numpoints': 2, 'shadow': True, 'title': None} @suboptions('legend', **LEGEND_OPTIONS) def show(self, **kwds): @@ -2145,6 +2152,7 @@ def show(self, **kwds): sage: P.show(figsize=[sqrt(2),sqrt(3)]) """ from sage.repl.rich_output import get_display_manager + dm = get_display_manager() dm.display_immediately(self, **kwds) @@ -2334,10 +2342,7 @@ def _limit_output_aspect_ratio(self, xmin, xmax, ymin, ymax): xmax = xcenter + width / 2 return {'xmin': xmin, 'xmax': xmax, 'ymin': ymin, 'ymax': ymax} - def _matplotlib_tick_formatter(self, subplot, base=(10, 10), - locator_options={}, scale=('linear', 'linear'), - tick_formatter=(None, None), ticks=(None, None), - xmax=None, xmin=None, ymax=None, ymin=None): + def _matplotlib_tick_formatter(self, subplot, base=(10, 10), locator_options={}, scale=('linear', 'linear'), tick_formatter=(None, None), ticks=(None, None), xmax=None, xmin=None, ymax=None, ymin=None): r""" Take a matplotlib subplot instance representing the graphic and set the ticks formatting. This function is only for internal use. @@ -2362,11 +2367,7 @@ def _matplotlib_tick_formatter(self, subplot, base=(10, 10), """ # This function is created to refactor some code that is repeated # in the matplotlib function - from matplotlib.ticker import (FixedLocator, Locator, - LogFormatterMathtext, - LogLocator, MaxNLocator, - MultipleLocator, - NullLocator, ScalarFormatter) + from matplotlib.ticker import FixedLocator, Locator, LogFormatterMathtext, LogLocator, MaxNLocator, MultipleLocator, NullLocator, ScalarFormatter x_locator, y_locator = ticks # ---------------------- Location of x-ticks --------------------- @@ -2384,12 +2385,11 @@ def _matplotlib_tick_formatter(self, subplot, base=(10, 10), x_locator = FixedLocator([float(x) for x in x_locator]) else: # x_locator is a number which can be made a float from sage.functions.other import ceil, floor + if floor(xmax / x_locator) - ceil(xmin / x_locator) > 1: x_locator = MultipleLocator(float(x_locator)) else: # not enough room for two major ticks - raise ValueError('Expand the range of the independent ' - 'variable to allow two multiples of your tick locator ' - '(option `ticks`).') + raise ValueError('Expand the range of the independent ' 'variable to allow two multiples of your tick locator ' '(option `ticks`).') # ---------------------- Location of y-ticks --------------------- if y_locator is None: @@ -2405,18 +2405,18 @@ def _matplotlib_tick_formatter(self, subplot, base=(10, 10), y_locator = FixedLocator([float(y) for y in y_locator]) else: # y_locator is a number which can be made a float from sage.functions.other import ceil, floor + if floor(ymax / y_locator) - ceil(ymin / y_locator) > 1: y_locator = MultipleLocator(float(y_locator)) else: # not enough room for two major ticks - raise ValueError('Expand the range of the dependent ' - 'variable to allow two multiples of your tick locator ' - '(option `ticks`).') + raise ValueError('Expand the range of the dependent ' 'variable to allow two multiples of your tick locator ' '(option `ticks`).') x_formatter, y_formatter = tick_formatter from matplotlib.ticker import FuncFormatter, FixedFormatter from sage.misc.latex import latex from sage.structure.element import Expression from .misc import _multiple_of_constant + # ---------------------- Formatting x-ticks ---------------------- if x_formatter is None: if scale[0] == 'log': @@ -2425,14 +2425,11 @@ def _matplotlib_tick_formatter(self, subplot, base=(10, 10), x_formatter = ScalarFormatter() elif isinstance(x_formatter, Expression): x_const = x_formatter - x_formatter = FuncFormatter(lambda n, pos: - _multiple_of_constant(n, pos, x_const)) + x_formatter = FuncFormatter(lambda n, pos: _multiple_of_constant(n, pos, x_const)) elif x_formatter == "latex": if scale[0] == 'log': # We need to strip out '\\mathdefault' from the string - x_formatter = FuncFormatter(lambda n, pos: - LogFormatterMathtext(base=base[0])(n, pos).replace( - "\\mathdefault", "")) + x_formatter = FuncFormatter(lambda n, pos: LogFormatterMathtext(base=base[0])(n, pos).replace("\\mathdefault", "")) else: # circumvent the problem of symbolic tick values (trac #34693) if isinstance(x_locator, FixedLocator): @@ -2440,11 +2437,8 @@ def _matplotlib_tick_formatter(self, subplot, base=(10, 10), else: x_formatter = FuncFormatter(lambda n, pos: '$%s$' % latex(n)) elif isinstance(x_formatter, (list, tuple)): - if (not isinstance(ticks[0], (list, tuple)) or - len(ticks[0]) != len(x_formatter)): - raise ValueError("If the first component of the list " - "`tick_formatter` is a list then the first component " - "of `ticks` must also be a list of equal length.") + if not isinstance(ticks[0], (list, tuple)) or len(ticks[0]) != len(x_formatter): + raise ValueError("If the first component of the list " "`tick_formatter` is a list then the first component " "of `ticks` must also be a list of equal length.") x_formatter = FixedFormatter(x_formatter) # ---------------------- Formatting y-ticks ---------------------- if y_formatter is None: @@ -2454,14 +2448,11 @@ def _matplotlib_tick_formatter(self, subplot, base=(10, 10), y_formatter = ScalarFormatter() elif isinstance(y_formatter, Expression): y_const = y_formatter - y_formatter = FuncFormatter(lambda n, pos: - _multiple_of_constant(n, pos, y_const)) + y_formatter = FuncFormatter(lambda n, pos: _multiple_of_constant(n, pos, y_const)) elif y_formatter == "latex": if scale[1] == 'log': # We need to strip out '\\mathdefault' from the string - y_formatter = FuncFormatter(lambda n, pos: - LogFormatterMathtext(base=base[1])(n, pos).replace( - "\\mathdefault", "")) + y_formatter = FuncFormatter(lambda n, pos: LogFormatterMathtext(base=base[1])(n, pos).replace("\\mathdefault", "")) else: # circumvent the problem of symbolic tick values (trac #34693) if isinstance(y_locator, FixedLocator): @@ -2469,11 +2460,8 @@ def _matplotlib_tick_formatter(self, subplot, base=(10, 10), else: y_formatter = FuncFormatter(lambda n, pos: '$%s$' % latex(n)) elif isinstance(y_formatter, (list, tuple)): - if (not isinstance(ticks[1], (list, tuple)) or - len(ticks[1]) != len(y_formatter)): - raise ValueError("If the second component of the list " - "`tick_formatter` is a list then the second component " - "of `ticks` must also be a list of equal length.") + if not isinstance(ticks[1], (list, tuple)) or len(ticks[1]) != len(y_formatter): + raise ValueError("If the second component of the list " "`tick_formatter` is a list then the second component " "of `ticks` must also be a list of equal length.") y_formatter = FixedFormatter(y_formatter) subplot.xaxis.set_major_locator(x_locator) @@ -2485,16 +2473,15 @@ def _matplotlib_tick_formatter(self, subplot, base=(10, 10), # If there are not enough ticks (2 or more) to determine that the scale # is non-linear, we throw a warning. from warnings import warn + tickwarnmsg = 'The %s-axis contains fewer than 2 ticks; ' tickwarnmsg += 'the logarithmic scale of the plot may not be apparent ' tickwarnmsg += 'to the reader.' - if (scale[0] == 'log' and not isinstance(x_locator, NullLocator) and - len(subplot.xaxis.get_ticklocs()) < 2): + if scale[0] == 'log' and not isinstance(x_locator, NullLocator) and len(subplot.xaxis.get_ticklocs()) < 2: warn(tickwarnmsg % 'x') - if (scale[1] == 'log' and not isinstance(y_locator, NullLocator) and - len(subplot.yaxis.get_ticklocs()) < 2): + if scale[1] == 'log' and not isinstance(y_locator, NullLocator) and len(subplot.yaxis.get_ticklocs()) < 2: warn(tickwarnmsg % 'y') return (subplot, x_locator, y_locator, x_formatter, y_formatter) @@ -2584,6 +2571,7 @@ def _get_vmin_vmax(self, vmin, vmax, basev, axes_pad): raise ValueError('vmin must be less than vmax') import math + if axes_pad is None: axes_pad = 1 else: @@ -2593,39 +2581,25 @@ def _get_vmin_vmax(self, vmin, vmax, basev, axes_pad): logvmax = math.log(vmax) / math.log(basev) if math.floor(logvmax) - math.ceil(logvmin) < 0: - vmax = basev**math.ceil(logvmax) - vmin = basev**math.floor(logvmin) + vmax = basev ** math.ceil(logvmax) + vmin = basev ** math.floor(logvmin) elif math.floor(logvmax) - math.ceil(logvmin) < 1: if logvmax - math.floor(logvmax) > math.ceil(logvmin) - logvmin: - vmax = basev**math.ceil(logvmax) + vmax = basev ** math.ceil(logvmax) if axes_pad > 0: - vmin -= vmin * basev**(-axes_pad) + vmin -= vmin * basev ** (-axes_pad) else: - vmin = basev**math.floor(logvmin) + vmin = basev ** math.floor(logvmin) if axes_pad > 0: - vmax += vmax * basev**(-axes_pad) + vmax += vmax * basev ** (-axes_pad) elif axes_pad > 0: # pad the axes if we haven't expanded the axes earlier. - vmin -= vmin * basev**(-axes_pad) - vmax += vmax * basev**(-axes_pad) + vmin -= vmin * basev ** (-axes_pad) + vmax += vmax * basev ** (-axes_pad) return vmin, vmax - def matplotlib(self, filename=None, - xmin=None, xmax=None, ymin=None, ymax=None, - figsize=None, figure=None, sub=None, - axes=None, axes_labels=None, axes_labels_size=None, - flip_x=False, flip_y=False, - fontsize=None, frame=False, verify=True, - aspect_ratio=None, - gridlines=None, gridlinesstyle=None, - vgridlinesstyle=None, hgridlinesstyle=None, - show_legend=None, legend_options=None, - axes_pad=None, ticks_integer=None, - tick_formatter=None, ticks=None, title=None, - title_pos=None, base=None, scale=None, - stylesheet=None, - typeset='default'): + def matplotlib(self, filename=None, xmin=None, xmax=None, ymin=None, ymax=None, figsize=None, figure=None, sub=None, axes=None, axes_labels=None, axes_labels_size=None, flip_x=False, flip_y=False, fontsize=None, frame=False, verify=True, aspect_ratio=None, gridlines=None, gridlinesstyle=None, vgridlinesstyle=None, hgridlinesstyle=None, show_legend=None, legend_options=None, axes_pad=None, ticks_integer=None, tick_formatter=None, ticks=None, title=None, title_pos=None, base=None, scale=None, stylesheet=None, typeset='default'): r""" Construct or modify a Matplotlib figure by drawing ``self`` on it. @@ -2732,14 +2706,17 @@ def matplotlib(self, filename=None, # modern fonts of TeX for math texts such as axes labels, but otherwise # adopts the default style of matplotlib from matplotlib import rcParams + rcParams['mathtext.fontset'] = 'cm' rcParams['mathtext.rm'] = 'serif' import matplotlib.pyplot as plt + if stylesheet in plt.style.available: plt.style.use(stylesheet) from sage.structure.element import Expression + # make sure both formatters typeset or both don't if not isinstance(tick_formatter, (list, tuple)): if tick_formatter == "latex" or isinstance(tick_formatter, Expression): @@ -2754,6 +2731,7 @@ def matplotlib(self, filename=None, axes = self._show_axes from matplotlib.figure import Figure + if typeset == 'type1': # Requires LaTeX, dvipng, gs to be installed. rcParams['ps.useafm'] = True rcParams['pdf.use14corefonts'] = True @@ -2763,8 +2741,7 @@ def matplotlib(self, filename=None, rcParams['pdf.use14corefonts'] = False rcParams['text.usetex'] = True elif typeset != 'default': # We won't change (maybe user-set) defaults - raise ValueError("typeset must be set to one of 'default', 'latex'," - f" or 'type1'; got '{typeset}'.") + raise ValueError("typeset must be set to one of 'default', 'latex'," f" or 'type1'; got '{typeset}'.") self.fontsize(fontsize) self.axes_labels(l=axes_labels) @@ -2810,8 +2787,7 @@ def matplotlib(self, filename=None, ymin = d['ymax' if flip_y else 'ymin'] ymax = d['ymin' if flip_y else 'ymax'] - xscale, yscale, basex, basey = self._set_scale(subplot, scale=scale, - base=base) + xscale, yscale, basex, basey = self._set_scale(subplot, scale=scale, base=base) # If any of the x-data are negative, we leave the min/max alone. if xscale == 'log' and min(xmin, xmax) > 0: @@ -2843,15 +2819,11 @@ def matplotlib(self, filename=None, if show_legend: from matplotlib.font_manager import FontProperties + lopts = {} lopts.update(legend_options) lopts.update(self._legend_opts) - prop = FontProperties( - family=lopts.pop('font_family', 'sans-serif'), - size=lopts.pop('font_size', 'medium'), - style=lopts.pop('font_style', 'normal'), - weight=lopts.pop('font_weight', 'medium'), - variant=lopts.pop('font_variant', 'normal')) + prop = FontProperties(family=lopts.pop('font_family', 'sans-serif'), size=lopts.pop('font_size', 'medium'), style=lopts.pop('font_style', 'normal'), weight=lopts.pop('font_weight', 'medium'), variant=lopts.pop('font_variant', 'normal')) color = lopts.pop('back_color', 'white') if 'loc' in lopts: loc = lopts['loc'] @@ -2861,12 +2833,14 @@ def matplotlib(self, filename=None, leg = subplot.legend(prop=prop, **lopts) if leg is None: from warnings import warn + warn("legend requested but no items are labeled") else: # color lframe = leg.get_frame() lframe.set_facecolor(color) from sage.plot.colors import to_mpl_color + for txt, color in zip(leg.get_texts(), self._legend_colors): if color is not None: txt.set_color(to_mpl_color(color)) @@ -2874,8 +2848,7 @@ def matplotlib(self, filename=None, subplot.set_xlim([xmin, xmax]) subplot.set_ylim([ymin, ymax]) - locator_options = {'nbins': 9, 'steps': [1, 2, 5, 10], - 'integer': ticks_integer} + locator_options = {'nbins': 9, 'steps': [1, 2, 5, 10], 'integer': ticks_integer} if axes is None: axes = self._show_axes @@ -2889,22 +2862,14 @@ def matplotlib(self, filename=None, # sort of what we are used to. We should eventually look at # the default one to see if we like it better. - (subplot, x_locator, y_locator, - x_formatter, y_formatter) = self._matplotlib_tick_formatter( - subplot, base=(basex, basey), - locator_options=locator_options, - scale=(xscale, yscale), - tick_formatter=tick_formatter, ticks=ticks, - xmax=xmax, xmin=xmin, ymax=ymax, ymin=ymin) + (subplot, x_locator, y_locator, x_formatter, y_formatter) = self._matplotlib_tick_formatter(subplot, base=(basex, basey), locator_options=locator_options, scale=(xscale, yscale), tick_formatter=tick_formatter, ticks=ticks, xmax=xmax, xmin=xmin, ymax=ymax, ymin=ymin) subplot.set_frame_on(True) if axes and xscale == 'linear' and yscale == 'linear': if (ymin <= 0 and ymax >= 0) or (ymax <= 0 and ymin >= 0): - subplot.axhline(color=self._axes_color, - linewidth=self._axes_width) + subplot.axhline(color=self._axes_color, linewidth=self._axes_width) if (xmin <= 0 and xmax >= 0) or (xmax <= 0 and xmin >= 0): - subplot.axvline(color=self._axes_color, - linewidth=self._axes_width) + subplot.axvline(color=self._axes_color, linewidth=self._axes_width) elif axes: ymiddle = False @@ -2983,13 +2948,7 @@ def matplotlib(self, filename=None, # sort of what we are used to. We should eventually look at # the default one to see if we like it better. - (subplot, x_locator, y_locator, - x_formatter, y_formatter) = self._matplotlib_tick_formatter( - subplot, base=(basex, basey), - locator_options=locator_options, - scale=(xscale, yscale), - tick_formatter=tick_formatter, ticks=ticks, - xmax=xmax, xmin=xmin, ymax=ymax, ymin=ymin) + (subplot, x_locator, y_locator, x_formatter, y_formatter) = self._matplotlib_tick_formatter(subplot, base=(basex, basey), locator_options=locator_options, scale=(xscale, yscale), tick_formatter=tick_formatter, ticks=ticks, xmax=xmax, xmin=xmin, ymax=ymax, ymin=ymin) # Make ticklines go on both sides of the axes # if xmiddle: @@ -3010,17 +2969,17 @@ def matplotlib(self, filename=None, # Make the zero tick labels disappear if the axes cross # inside the picture, but only if log scale is not used - if (xmiddle and ymiddle and xscale == 'linear' == yscale): + if xmiddle and ymiddle and xscale == 'linear' == yscale: from sage.plot.plot import SelectiveFormatter - subplot.yaxis.set_major_formatter(SelectiveFormatter( - subplot.yaxis.get_major_formatter(), skip_values=[0])) - subplot.xaxis.set_major_formatter(SelectiveFormatter( - subplot.xaxis.get_major_formatter(), skip_values=[0])) + + subplot.yaxis.set_major_formatter(SelectiveFormatter(subplot.yaxis.get_major_formatter(), skip_values=[0])) + subplot.xaxis.set_major_formatter(SelectiveFormatter(subplot.xaxis.get_major_formatter(), skip_values=[0])) else: for spine in subplot.spines.values(): spine.set_visible(False) from matplotlib.ticker import NullFormatter, NullLocator + subplot.xaxis.set_major_formatter(NullFormatter()) subplot.yaxis.set_major_formatter(NullFormatter()) subplot.xaxis.set_major_locator(NullLocator()) @@ -3030,32 +2989,30 @@ def matplotlib(self, filename=None, # Make minor tickmarks, unless we specify fixed ticks or no ticks # We do this change only on linear scale, otherwise matplotlib # errors out with a memory error. - from matplotlib.ticker import (AutoMinorLocator, FixedLocator, - LogLocator, NullLocator) + from matplotlib.ticker import AutoMinorLocator, FixedLocator, LogLocator, NullLocator + if isinstance(x_locator, (NullLocator, FixedLocator)): subplot.xaxis.set_minor_locator(NullLocator()) elif xscale == 'linear': subplot.xaxis.set_minor_locator(AutoMinorLocator()) else: # log scale from sage.arith.srange import srange + base_inv = 1.0 / basex subs = [float(_) for _ in srange(2 * base_inv, 1, base_inv)] - subplot.xaxis.set_minor_locator(LogLocator(base=basex, - subs=subs)) + subplot.xaxis.set_minor_locator(LogLocator(base=basex, subs=subs)) if isinstance(y_locator, (NullLocator, FixedLocator)): subplot.yaxis.set_minor_locator(NullLocator()) elif yscale == 'linear': subplot.yaxis.set_minor_locator(AutoMinorLocator()) else: # log scale from sage.arith.srange import srange + base_inv = 1.0 / basey subs = [float(_) for _ in srange(2 * base_inv, 1, base_inv)] - subplot.yaxis.set_minor_locator(LogLocator(base=basey, - subs=subs)) + subplot.yaxis.set_minor_locator(LogLocator(base=basey, subs=subs)) # Set the color and fontsize of ticks - subplot.tick_params(color=self._axes_color, - labelcolor=self._tick_label_color, - labelsize=self._fontsize, which='both') + subplot.tick_params(color=self._axes_color, labelcolor=self._tick_label_color, labelsize=self._fontsize, which='both') if gridlines is not None: if isinstance(gridlines, (list, tuple)): @@ -3066,8 +3023,7 @@ def matplotlib(self, filename=None, if gridlinesstyle is None: # Set up the default grid style - gridlinesstyle = {'color': 'black', 'linestyle': ':', - 'linewidth': 0.5} + gridlinesstyle = {'color': 'black', 'linestyle': ':', 'linewidth': 0.5} vgridstyle = gridlinesstyle.copy() if vgridlinesstyle is not None: @@ -3149,24 +3105,21 @@ def matplotlib(self, filename=None, yaxis_labelx = 1 from matplotlib.transforms import offset_copy + xlabel = subplot.xaxis.get_label() xlabel.set_horizontalalignment(xaxis_horiz) xlabel.set_verticalalignment(xaxis_vert) trans = subplot.spines[xaxis].get_transform() - labeltrans = offset_copy(trans, figure, x=xaxis_labeloffset, - y=0, units='points') - subplot.xaxis.set_label_coords(x=xaxis_labelx, - y=xaxis_labely, transform=labeltrans) + labeltrans = offset_copy(trans, figure, x=xaxis_labeloffset, y=0, units='points') + subplot.xaxis.set_label_coords(x=xaxis_labelx, y=xaxis_labely, transform=labeltrans) ylabel = subplot.yaxis.get_label() ylabel.set_horizontalalignment('center') ylabel.set_verticalalignment(yaxis_vert) ylabel.set_rotation('horizontal') trans = subplot.spines[yaxis].get_transform() - labeltrans = offset_copy(trans, figure, x=0, - y=yaxis_labeloffset, units='points') - subplot.yaxis.set_label_coords(x=yaxis_labelx, - y=yaxis_labely, transform=labeltrans) + labeltrans = offset_copy(trans, figure, x=0, y=yaxis_labeloffset, units='points') + subplot.yaxis.set_label_coords(x=yaxis_labelx, y=yaxis_labely, transform=labeltrans) # This option makes the xlim and ylim limits not take effect # todo: figure out which limits were specified, and let the @@ -3174,16 +3127,13 @@ def matplotlib(self, filename=None, # subplot.autoscale_view(tight=True) if title is not None: if title_pos is not None: - if (not isinstance(title_pos, (list, tuple)) or - len(title_pos) != 2): - raise ValueError("'title_pos' must be a list or tuple " - "of two real numbers.") + if not isinstance(title_pos, (list, tuple)) or len(title_pos) != 2: + raise ValueError("'title_pos' must be a list or tuple " "of two real numbers.") title_pos = (float(title_pos[0]), float(title_pos[1])) if (frame) or (axes_labels is None): if title_pos is not None: - subplot.set_title(title, fontsize=fontsize, - position=title_pos) + subplot.set_title(title, fontsize=fontsize, position=title_pos) else: subplot.set_title(title, fontsize=fontsize) else: @@ -3327,18 +3277,18 @@ def save(self, filename, **kwds): if ext in ['', '.sobj']: SageObject.save(self, filename) elif ext not in ALLOWED_EXTENSIONS: - raise ValueError("allowed file extensions for images are '" + - "', '".join(ALLOWED_EXTENSIONS) + "'!") + raise ValueError("allowed file extensions for images are '" + "', '".join(ALLOWED_EXTENSIONS) + "'!") else: from matplotlib import rcParams - rc_backup = (rcParams['ps.useafm'], rcParams['pdf.use14corefonts'], - rcParams['text.usetex']) # save the rcParams + + rc_backup = (rcParams['ps.useafm'], rcParams['pdf.use14corefonts'], rcParams['text.usetex']) # save the rcParams figure = self.matplotlib(**options) # You can output in PNG, PS, EPS, PDF, PGF, or SVG format, depending # on the file extension. # PGF is handled by a different backend if ext == '.pgf': from sage.features.latex import xelatex, pdflatex, lualatex + latex_implementations = [] if xelatex().is_present(): latex_implementations.append('xelatex') @@ -3347,24 +3297,22 @@ def save(self, filename, **kwds): if lualatex().is_present(): latex_implementations.append('lualatex') if not latex_implementations: - raise ValueError("Matplotlib requires either xelatex, " - "lualatex, or pdflatex.") + raise ValueError("Matplotlib requires either xelatex, " "lualatex, or pdflatex.") if latex_implementations[0] == "pdflatex": # use pdflatex and set font encoding as per # matplotlib documentation: # https://matplotlib.org/stable/users/explain/text/pgf.html # Note that pgf.preamble should be a string now, not a list - pgf_options = {"pgf.texsystem": "pdflatex", - "pgf.preamble": "\n".join([ - r"\usepackage[utf8x]{inputenc}", - r"\usepackage[T1]{fontenc}"])} + pgf_options = {"pgf.texsystem": "pdflatex", "pgf.preamble": "\n".join([r"\usepackage[utf8x]{inputenc}", r"\usepackage[T1]{fontenc}"])} else: pgf_options = { "pgf.texsystem": latex_implementations[0], } from matplotlib import rcParams + rcParams.update(pgf_options) from matplotlib.backends.backend_pgf import FigureCanvasPgf + figure.set_canvas(FigureCanvasPgf(figure)) # matplotlib looks at the file extension to see what the renderer should be. @@ -3373,6 +3321,7 @@ def save(self, filename, **kwds): # if the file extension is not '.png', then matplotlib will handle it. else: from matplotlib.backends.backend_agg import FigureCanvasAgg + figure.set_canvas(FigureCanvasAgg(figure)) # this messes up the aspect ratio! # figure.canvas.mpl_connect('draw_event', pad_for_tick_labels) @@ -3389,8 +3338,7 @@ def save(self, filename, **kwds): figure.savefig(filename, **opts) # Restore the rcParams to the original, possibly user-set values - (rcParams['ps.useafm'], rcParams['pdf.use14corefonts'], - rcParams['text.usetex']) = rc_backup + (rcParams['ps.useafm'], rcParams['pdf.use14corefonts'], rcParams['text.usetex']) = rc_backup def _latex_(self, **kwds): """ @@ -3413,6 +3361,7 @@ def _latex_(self, **kwds): with open(tmpfilename) as tmpfile: latex_list = tmpfile.readlines() from sage.misc.latex import latex + latex.add_package_to_preamble_if_available('pgf') return ''.join(latex_list) @@ -3516,6 +3465,7 @@ def inset(self, graphics, pos=None, fontsize=None): sphinx_plot(g1g2.inset(g3, pos=(0.65, 0.12, 0.25, 0.25))) """ from .multigraphics import MultiGraphics + if pos is None: pos = (0.7, 0.7, 0.2, 0.2) pos0 = (0.05, 0.05, 0.9, 0.9) diff --git a/src/sage/plot/histogram.py b/src/sage/plot/histogram.py index 7c6f8533c0d..aa28ed94192 100644 --- a/src/sage/plot/histogram.py +++ b/src/sage/plot/histogram.py @@ -1,6 +1,7 @@ """ Histograms """ + # **************************************************************************** # Distributed under the terms of the GNU General Public License (GPL) # @@ -39,6 +40,7 @@ class Histogram(GraphicPrimitive): sage: g = Histogram([[1,3,2,0], [4,4,3,3]], {}); g Histogram defined by 2 data lists """ + def __init__(self, datalist, options): """ Initialize a ``Histogram`` primitive along with @@ -51,11 +53,12 @@ def __init__(self, datalist, options): Histogram defined by a data list of size 3 """ import numpy as np + self.datalist = np.asarray(datalist, dtype=float) if 'linestyle' in options: from sage.plot.misc import get_matplotlib_linestyle - options['linestyle'] = get_matplotlib_linestyle( - options['linestyle'], return_type='long') + + options['linestyle'] = get_matplotlib_linestyle(options['linestyle'], return_type='long') if options.get('range', None): # numpy.histogram performs type checks on "range" so this must be # actual floats @@ -89,6 +92,7 @@ def get_minmax_data(self): {'xmax': 10.0, 'xmin': 3.0, 'ymax': 0.476190476190..., 'ymin': 0} """ import numpy + if int(numpy.version.short_version[0]) > 1: numpy.set_printoptions(legacy="1.25") @@ -108,7 +112,7 @@ def get_minmax_data(self): # check to see if a list of datasets if not hasattr(self.datalist[0], '__contains__'): ydata, xdata = numpy.histogram(self.datalist, **opt) - return minmax_data(xdata, [0]+list(ydata), dict=True) + return minmax_data(xdata, [0] + list(ydata), dict=True) m = {'xmax': 0, 'xmin': 0, 'ymax': 0, 'ymin': 0} if not options.get('stacked'): for d in self.datalist: @@ -141,24 +145,26 @@ def _allowed_options(self): sage: L[-1] ('zorder', 'The layer level to draw the histogram') """ - return {'color': 'The color of the face of the bars or list of colors if multiple data sets are given.', - 'edgecolor': 'The color of the border of each bar.', - 'alpha': 'How transparent the plot is', - 'hue': 'The color of the bars given as a hue.', - 'fill': '(True or False, default: ``True``) Whether to fill the bars', - 'hatch': 'What symbol to fill with - one of "/", "\\", "|", "-", "+", "x", "o", "O", ".", "*"', - 'linewidth': 'Width of the lines defining the bars', - 'linestyle': "One of 'solid' or '-', 'dashed' or '--', 'dotted' or ':', 'dashdot' or '-.'", - 'zorder': 'The layer level to draw the histogram', - 'bins': 'The number of sections in which to divide the range. Also can be a sequence of points within the range that create the partition.', - 'align': 'How the bars align inside of each bin. Acceptable values are "left", "right" or "mid".', - 'rwidth': 'The relative width of the bars as a fraction of the bin width', - 'cumulative': '(True or False) If True, then a histogram is computed in which each bin gives the counts in that bin plus all bins for smaller values. Negative values give a reversed direction of accumulation.', - 'range': 'A list [min, max] which define the range of the histogram. Values outside of this range are treated as outliers and omitted from counts.', - 'density': '(True or False) If True, the counts are normalized to form a probability density. (n/(len(x)*dbin)', - 'weights': 'A sequence of weights the same length as the data list. If supplied, then each value contributes its associated weight to the bin count.', - 'stacked': '(True or False) If True, multiple data are stacked on top of each other.', - 'label': 'A string label for each data list given.'} + return { + 'color': 'The color of the face of the bars or list of colors if multiple data sets are given.', + 'edgecolor': 'The color of the border of each bar.', + 'alpha': 'How transparent the plot is', + 'hue': 'The color of the bars given as a hue.', + 'fill': '(True or False, default: ``True``) Whether to fill the bars', + 'hatch': 'What symbol to fill with - one of "/", "\\", "|", "-", "+", "x", "o", "O", ".", "*"', + 'linewidth': 'Width of the lines defining the bars', + 'linestyle': "One of 'solid' or '-', 'dashed' or '--', 'dotted' or ':', 'dashdot' or '-.'", + 'zorder': 'The layer level to draw the histogram', + 'bins': 'The number of sections in which to divide the range. Also can be a sequence of points within the range that create the partition.', + 'align': 'How the bars align inside of each bin. Acceptable values are "left", "right" or "mid".', + 'rwidth': 'The relative width of the bars as a fraction of the bin width', + 'cumulative': '(True or False) If True, then a histogram is computed in which each bin gives the counts in that bin plus all bins for smaller values. Negative values give a reversed direction of accumulation.', + 'range': 'A list [min, max] which define the range of the histogram. Values outside of this range are treated as outliers and omitted from counts.', + 'density': '(True or False) If True, the counts are normalized to form a probability density. (n/(len(x)*dbin)', + 'weights': 'A sequence of weights the same length as the data list. If supplied, then each value contributes its associated weight to the bin count.', + 'stacked': '(True or False) If True, multiple data are stacked on top of each other.', + 'label': 'A string label for each data list given.', + } def _repr_(self) -> str: """ diff --git a/src/sage/plot/hyperbolic_arc.py b/src/sage/plot/hyperbolic_arc.py index 4aa87d4ad22..a4a968421b3 100644 --- a/src/sage/plot/hyperbolic_arc.py +++ b/src/sage/plot/hyperbolic_arc.py @@ -93,6 +93,7 @@ class HyperbolicArcCore(BezierPath): The Upper Half Model, Poincaré Disk Model, and Klein Disk model are supported. """ + def _bezier_path(self, z0, z1, model, first=False): """ Construct a bezier path from a given arc object and store it @@ -111,7 +112,8 @@ def _bezier_path(self, z0, z1, model, first=False): """ import numpy as np from sage.rings.infinity import infinity - EPSILON = 10 ** -5 + + EPSILON = 10**-5 arc0 = model.get_geodesic(z0, z1).plot()[0] @@ -119,15 +121,7 @@ def _bezier_path(self, z0, z1, model, first=False): points = arc0.vertices else: points = arc0.bezier_path()[0].vertices - if ( - ((z0.is_infinity() or z0 == infinity) - and abs(CC(points[0][0], points[0][1]) - z1) < EPSILON) - or ((z1.is_infinity() or z1 == infinity) - and abs(CC(points[1][0], points[1][1]) - z0) < EPSILON) - or (abs(CC(points[0][0], points[0][1]) - z0) >= EPSILON - and not (z0.is_infinity() or z0 == infinity or z1.is_infinity() - or z1 == infinity)) - ): + if ((z0.is_infinity() or z0 == infinity) and abs(CC(points[0][0], points[0][1]) - z1) < EPSILON) or ((z1.is_infinity() or z1 == infinity) and abs(CC(points[1][0], points[1][1]) - z0) < EPSILON) or (abs(CC(points[0][0], points[0][1]) - z0) >= EPSILON and not (z0.is_infinity() or z0 == infinity or z1.is_infinity() or z1 == infinity)): points = np.flipud(points) # order is important if first: @@ -138,7 +132,7 @@ def _bezier_path(self, z0, z1, model, first=False): N = 4 # Add new triplets while N < len(points): - self.path.append(points[N: N + 3]) + self.path.append(points[N : N + 3]) N += 3 self.last_plotted = "arc" else: @@ -151,7 +145,7 @@ def _bezier_path(self, z0, z1, model, first=False): elif self.last_plotted == "line": # actual segment is an arc # Add new triplets while N < len(points): - self.path.append(points[N: N + 3]) + self.path.append(points[N : N + 3]) N += 3 self.last_plotted = "arc" else: @@ -164,7 +158,7 @@ def _bezier_path(self, z0, z1, model, first=False): N += 1 # Add new triplets while N < len(points): - self.path.append(points[N: N + 3]) + self.path.append(points[N : N + 3]) N += 3 self.last_plotted = "arc" @@ -191,6 +185,7 @@ class HyperbolicArc(HyperbolicArcCore): sage: HyperbolicArc(0, 1/2+I*sqrt(3)/2, "UHP", {}) Hyperbolic arc (0.000000000000000, 0.500000000000000 + 0.866025403784439*I) """ + def __init__(self, A, B, model, options): """ Initialize ``self``. @@ -204,6 +199,7 @@ def __init__(self, A, B, model, options): if model == "HM": raise ValueError("the hyperboloid model is not supported") from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane + HP = HyperbolicPlane() M = getattr(HP, model)() self.A = CC(A) @@ -387,9 +383,9 @@ def hyperbolic_arc(a, b, model='UHP', **options): from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane # Check for valid points - if a[2] < 0 or a[0]**2+a[1]**2-a[2]**2 + 1 > EPSILON: + if a[2] < 0 or a[0] ** 2 + a[1] ** 2 - a[2] ** 2 + 1 > EPSILON: raise ValueError(f"{a} is not a valid point in the HM model") - if b[2] < 0 or b[0]**2+b[1]**2-b[2]**2 + 1 > EPSILON: + if b[2] < 0 or b[0] ** 2 + b[1] ** 2 - b[2] ** 2 + 1 > EPSILON: raise ValueError(f"{b} is not a valid point in the HM model") HM = HyperbolicPlane().HM() diff --git a/src/sage/plot/hyperbolic_polygon.py b/src/sage/plot/hyperbolic_polygon.py index 7ff5d170afb..7c1897158af 100644 --- a/src/sage/plot/hyperbolic_polygon.py +++ b/src/sage/plot/hyperbolic_polygon.py @@ -54,6 +54,7 @@ class HyperbolicPolygon(HyperbolicArcCore): sage: print(HyperbolicPolygon([0, 1/2, I], "UHP", {})) Hyperbolic polygon (0.000000000000000, 0.500000000000000, 1.00000000000000*I) """ + def __init__(self, pts, model, options): """ Initialize HyperbolicPolygon. @@ -69,6 +70,7 @@ def __init__(self, pts, model, options): if not pts: raise ValueError("cannot plot the empty polygon") from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane + HP = HyperbolicPlane() M = getattr(HP, model)() @@ -85,7 +87,7 @@ def __init__(self, pts, model, options): # If any Infinity vertex exist it must be the first for i, p in enumerate(pts): if p.is_infinity(): - if any(pt.is_infinity() for pt in pts[i+1:]): + if any(pt.is_infinity() for pt in pts[i + 1 :]): raise ValueError("no more than one infinite vertex allowed") pts = pts[i:] + pts[:i] break @@ -122,6 +124,7 @@ def _winding_number(vertices, point): sage: _winding_number([(0,0,4),(1,0,3),(1,1,2),(0,1,1)],(10,10,10)) 0 """ + # Helper functions def _intersects(start, end, y0): if end[1] < start[1]: @@ -137,8 +140,7 @@ def _is_left(point, edge): sides = [] wn = 0 - sides = [[vertices[i], vertices[i + 1]] for i in range(len(vertices) - 1) - if _intersects(vertices[i], vertices[i + 1], point[1])] + sides = [[vertices[i], vertices[i + 1]] for i in range(len(vertices) - 1) if _intersects(vertices[i], vertices[i + 1], point[1])] if _intersects(vertices[-1], vertices[0], point[1]): sides.append([vertices[-1], vertices[0]]) @@ -288,6 +290,7 @@ def hyperbolic_polygon(pts, model='UHP', resolution=200, **options): sphinx_plot(P) """ from sage.plot.graphics import Graphics + g = Graphics() g._set_extra_kwds(g._extract_kwds_for_show(options)) @@ -295,6 +298,7 @@ def hyperbolic_polygon(pts, model='UHP', resolution=200, **options): from sage.geometry.hyperbolic_space.hyperbolic_interface import HyperbolicPlane from sage.plot.plot3d.implicit_plot3d import implicit_plot3d from sage.symbolic.ring import SR + HM = HyperbolicPlane().HM() x, y, z = SR.var('x,y,z') arc_points = [] @@ -312,13 +316,8 @@ def hyperbolic_polygon(pts, model='UHP', resolution=200, **options): def region(x, y, z): return _winding_number(arc_points, (x, y, z)) != 0 - g = g + implicit_plot3d(x**2 + y**2 - z**2 == -1, - (x, min(xlist), max(xlist)), - (y, min(ylist), max(ylist)), - (z, 0, max(zlist)), - region=region, - plot_points=resolution, - color=options['rgbcolor']) # the less points the more jaggy the picture + + g = g + implicit_plot3d(x**2 + y**2 - z**2 == -1, (x, min(xlist), max(xlist)), (y, min(ylist), max(ylist)), (z, 0, max(zlist)), region=region, plot_points=resolution, color=options['rgbcolor']) # the less points the more jaggy the picture else: g.add_primitive(HyperbolicPolygon(pts, model, options)) if model == "PD" or model == "KM": diff --git a/src/sage/plot/hyperbolic_regular_polygon.py b/src/sage/plot/hyperbolic_regular_polygon.py index a6df71ebc11..6ae1e71925a 100644 --- a/src/sage/plot/hyperbolic_regular_polygon.py +++ b/src/sage/plot/hyperbolic_regular_polygon.py @@ -7,7 +7,7 @@ - Javier Honrubia (2016-01) """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2016 Javier Honrubia Gonzalez # # This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.matrix.constructor import matrix from sage.misc.decorators import options, rename_keyword @@ -100,6 +100,7 @@ class HyperbolicRegularPolygon(HyperbolicPolygon): ... ValueError: degenerated polygons (sides<=2) are not supported """ + def __init__(self, sides, i_angle, center, options): """ Initialize HyperbolicRegularPolygon. @@ -117,12 +118,11 @@ def __init__(self, sides, i_angle, center, options): raise ValueError("degenerated polygons (sides<=2) are not supported") if i_angle <= 0 or i_angle >= pi: raise ValueError("interior angle %s must be in (0, pi) interval" % (i_angle)) - if pi*(sides-2) - sides*i_angle <= 0: - raise ValueError("there exists no hyperbolic regular compact polygon," - " for sides={} the interior angle must be less than {}".format(sides, pi * (sides-2) / sides)) + if pi * (sides - 2) - sides * i_angle <= 0: + raise ValueError("there exists no hyperbolic regular compact polygon," " for sides={} the interior angle must be less than {}".format(sides, pi * (sides - 2) / sides)) self.sides = sides self.i_angle = i_angle - beta = 2 * pi / self.sides # compute the rotation angle to be used ahead + beta = 2 * pi / self.sides # compute the rotation angle to be used ahead alpha = self.i_angle / Integer(2) I = CC(0, 1) # compute using cosine theorem the radius of the circumscribed circle @@ -131,7 +131,7 @@ def __init__(self, sides, i_angle, center, options): # The first point will be always on the imaginary axis limited # to 8 digits for efficiency in the subsequent calculations. - z_0 = [I*(e**r).n(digits=8)] + z_0 = [I * (e**r).n(digits=8)] # Compute the dilation isometry used to move the center # from I to the imaginary part of the given center. @@ -141,9 +141,9 @@ def __init__(self, sides, i_angle, center, options): # real part of the given center. h_disp = self.center.real() - d_z_k = [z_0[0]*scale + h_disp] # d_k has the points for the polygon in the given center - z_k = z_0 # z_k has the Re(z)>0 vertices for the I centered polygon - r_z_k = [] # r_z_k has the Re(z)<0 vertices + d_z_k = [z_0[0] * scale + h_disp] # d_k has the points for the polygon in the given center + z_k = z_0 # z_k has the Re(z)>0 vertices for the I centered polygon + r_z_k = [] # r_z_k has the Re(z)<0 vertices if is_odd(self.sides): vert = (self.sides - 1) // 2 else: @@ -157,7 +157,7 @@ def __init__(self, sides, i_angle, center, options): if is_odd(self.sides): HyperbolicPolygon.__init__(self, d_z_k + r_z_k, "UHP", options) else: - z_opo = [I * (e**(-r)).n(digits=8) * scale + h_disp] + z_opo = [I * (e ** (-r)).n(digits=8) * scale + h_disp] HyperbolicPolygon.__init__(self, d_z_k + z_opo + r_z_k, "UHP", options) def _repr_(self): @@ -170,7 +170,7 @@ def _repr_(self): sage: HyperbolicRegularPolygon(5,pi/2,I, {}) Hyperbolic regular polygon (sides=5, i_angle=1/2*pi, center=1.00000000000000*I) """ - return ("Hyperbolic regular polygon (sides={}, i_angle={}, center={})".format(self.sides, self.i_angle, self.center)) + return "Hyperbolic regular polygon (sides={}, i_angle={}, center={})".format(self.sides, self.i_angle, self.center) def _i_rotation(self, z, alpha): r""" @@ -201,9 +201,8 @@ def _i_rotation(self, z, alpha): @rename_keyword(color='rgbcolor') -@options(alpha=1, fill=False, thickness=1, rgbcolor='blue', zorder=2, - linestyle='solid') -def hyperbolic_regular_polygon(sides, i_angle, center=CC(0,1), **options): +@options(alpha=1, fill=False, thickness=1, rgbcolor='blue', zorder=2, linestyle='solid') +def hyperbolic_regular_polygon(sides, i_angle, center=CC(0, 1), **options): r""" Return a hyperbolic regular polygon in the upper half model of Hyperbolic plane given the number of sides, interior angle and diff --git a/src/sage/plot/line.py b/src/sage/plot/line.py index 97bd0669d6c..4ee44d79980 100644 --- a/src/sage/plot/line.py +++ b/src/sage/plot/line.py @@ -33,6 +33,7 @@ class Line(GraphicPrimitive_xydata): sage: Line([1,2,7], [1,5,-1], {}) Line defined by 3 points """ + def __init__(self, xdata, ydata, options): """ Initialize a line graphics primitive. @@ -74,20 +75,7 @@ def _allowed_options(self): ('thickness', 'How thick the line is.'), ('zorder', 'The layer level in which to draw')] """ - return {'alpha': 'How transparent the line is.', - 'legend_color': 'The color of the legend text.', - 'legend_label': 'The label for this item in the legend.', - 'thickness': 'How thick the line is.', - 'rgbcolor': 'The color as an RGB tuple.', - 'hue': 'The color given as a hue.', - 'linestyle': "The style of the line, which is one of '--' (dashed), '-.' (dash dot), '-' (solid), 'steps', ':' (dotted).", - 'marker': "the marker symbol (see documentation for line2d for details)", - 'markersize': 'the size of the marker in points', - 'markeredgecolor': 'the color of the marker edge', - 'markeredgewidth': 'the size of the marker edge in points', - 'markerfacecolor': 'the color of the marker face', - 'zorder': 'The layer level in which to draw' - } + return {'alpha': 'How transparent the line is.', 'legend_color': 'The color of the legend text.', 'legend_label': 'The label for this item in the legend.', 'thickness': 'How thick the line is.', 'rgbcolor': 'The color as an RGB tuple.', 'hue': 'The color given as a hue.', 'linestyle': "The style of the line, which is one of '--' (dashed), '-.' (dash dot), '-' (solid), 'steps', ':' (dotted).", 'marker': "the marker symbol (see documentation for line2d for details)", 'markersize': 'the size of the marker in points', 'markeredgecolor': 'the color of the marker edge', 'markeredgewidth': 'the size of the marker edge in points', 'markerfacecolor': 'the color of the marker face', 'zorder': 'The layer level in which to draw'} def _plot3d_options(self, options=None): """ @@ -119,8 +107,7 @@ def _plot3d_options(self, options=None): del options['zorder'] if 'linestyle' in options: if options['linestyle'] not in ('-', 'solid'): - raise NotImplementedError("invalid 3d line style: '%s'" % - (options['linestyle'])) + raise NotImplementedError("invalid 3d line style: '%s'" % (options['linestyle'])) del options['linestyle'] options_3d.update(GraphicPrimitive_xydata._plot3d_options(self, options)) return options_3d @@ -143,6 +130,7 @@ def plot3d(self, z=0, **kwds): sphinx_plot(E+F) """ from sage.plot.plot3d.shapes2 import line3d + options = self._plot3d_options() options.update(kwds) return line3d([(x, y, z) for x, y in zip(self.xdata, self.ydata)], **options) @@ -250,9 +238,9 @@ def _render_on_subplot(self, subplot): Graphics object consisting of 1 graphics primitive """ from matplotlib import lines + options = dict(self.options()) - for o in ('alpha', 'legend_color', 'legend_label', 'linestyle', - 'rgbcolor', 'thickness'): + for o in ('alpha', 'legend_color', 'legend_label', 'linestyle', 'rgbcolor', 'thickness'): if o in options: del options[o] p = lines.Line2D(self.xdata, self.ydata, **options) @@ -266,8 +254,8 @@ def _render_on_subplot(self, subplot): # pulled off automatically. This (I think) is a bug in matplotlib 1.0.1 if 'linestyle' in options: from sage.plot.misc import get_matplotlib_linestyle - p.set_linestyle(get_matplotlib_linestyle(options['linestyle'], - return_type='short')) + + p.set_linestyle(get_matplotlib_linestyle(options['linestyle'], return_type='short')) subplot.add_line(p) @@ -308,12 +296,12 @@ def line(points, **kwds): return line2d(points, **kwds) except ValueError: from sage.plot.plot3d.shapes2 import line3d + return line3d(points, **kwds) @rename_keyword(color='rgbcolor') -@options(alpha=1, rgbcolor=(0, 0, 1), thickness=1, legend_label=None, - legend_color=None, aspect_ratio='automatic') +@options(alpha=1, rgbcolor=(0, 0, 1), thickness=1, legend_label=None, legend_color=None, aspect_ratio='automatic') def line2d(points, **options): r""" Create the line through the given list of points. @@ -612,6 +600,7 @@ def line2d(points, **options): """ from sage.plot.graphics import Graphics from sage.plot.plot import xydata_from_point_list + points = list(points) # make sure points is a python list if not points: return Graphics() diff --git a/src/sage/plot/matrix_plot.py b/src/sage/plot/matrix_plot.py index 3965384b90b..6606a5e3d54 100644 --- a/src/sage/plot/matrix_plot.py +++ b/src/sage/plot/matrix_plot.py @@ -1,6 +1,7 @@ """ Matrix plots """ + # **************************************************************************** # Copyright (C) 2006 Alex Clemesha , # William Stein , @@ -71,6 +72,7 @@ class MatrixPlot(GraphicPrimitive): sage: matrix_plot([[mod(i,5)^j for i in range(5)] for j in range(1,6)]) Graphics object consisting of 1 graphics primitive """ + def __init__(self, xy_data_array, xrange, yrange, options): """ Initialize base class MatrixPlot. @@ -115,15 +117,16 @@ def get_minmax_data(self): [('xmax', 4.5), ('xmin', -0.5), ('ymax', 4.5), ('ymin', -0.5)] """ from sage.plot.plot import minmax_data + xrange = self.xrange yrange = self.yrange # if xrange/yrange are not specified, add offset to the matrix so that, # for example, the square representing the (0,0) entry is centered on # the origin. if not xrange: - xrange = (-.5, self.xy_array_col - .5) + xrange = (-0.5, self.xy_array_col - 0.5) if not yrange: - yrange = (-.5, self.xy_array_row - .5) + yrange = (-0.5, self.xy_array_row - 0.5) return minmax_data(xrange, yrange, dict=True) def _allowed_options(self): @@ -136,21 +139,23 @@ def _allowed_options(self): sage: isinstance(M[0]._allowed_options(), dict) # needs sage.symbolic True """ - return {'cmap':"""the name of a predefined colormap, + return { + 'cmap': """the name of a predefined colormap, a list of colors, or an instance of a matplotlib Colormap. Type: import matplotlib.cm; matplotlib.cm.datad.keys() for available colormap names.""", - 'colorbar': "Include a colorbar indicating the levels (dense matrices only)", - 'colorbar_options': "a dictionary of options for colorbars", - 'zorder':"The layer level in which to draw", - 'marker':"The marker for sparse plots", - 'markersize':"The marker size for sparse plots", - 'norm': "The normalization function", - 'vmin': "The minimum value", - 'vmax': "The maximum value", - 'flip_y': "If False, draw the matrix with the first row on the bottom of the graph", - 'subdivisions': "If True, draw subdivisions of the matrix", - 'subdivision_options': "Options (boundaries and style) of the subdivisions"} + 'colorbar': "Include a colorbar indicating the levels (dense matrices only)", + 'colorbar_options': "a dictionary of options for colorbars", + 'zorder': "The layer level in which to draw", + 'marker': "The marker for sparse plots", + 'markersize': "The marker size for sparse plots", + 'norm': "The normalization function", + 'vmin': "The minimum value", + 'vmax': "The maximum value", + 'flip_y': "If False, draw the matrix with the first row on the bottom of the graph", + 'subdivisions': "If True, draw subdivisions of the matrix", + 'subdivision_options': "Options (boundaries and style) of the subdivisions", + } def _repr_(self): """ @@ -172,25 +177,26 @@ def _render_on_subplot(self, subplot): Graphics object consisting of 1 graphics primitive """ options = self.options() - cmap = get_cmap(options.pop('cmap',None)) + cmap = get_cmap(options.pop('cmap', None)) flip_y = options['flip_y'] norm = options['norm'] if norm == 'value': import matplotlib + norm = matplotlib.colors.NoNorm() lim = self.get_minmax_data() if options['subdivisions']: subdiv_options = options['subdivision_options'] if isinstance(subdiv_options['boundaries'], (list, tuple)): - rowsub,colsub = subdiv_options['boundaries'] + rowsub, colsub = subdiv_options['boundaries'] else: rowsub = subdiv_options['boundaries'] colsub = subdiv_options['boundaries'] if isinstance(subdiv_options['style'], (list, tuple)): - rowstyle,colstyle = subdiv_options['style'] + rowstyle, colstyle = subdiv_options['style'] else: rowstyle = subdiv_options['style'] colstyle = subdiv_options['style'] @@ -201,40 +207,33 @@ def _render_on_subplot(self, subplot): # Make line objects for subdivisions from .line import line2d + # First draw horizontal lines representing row subdivisions for y in rowsub: - y = lim['ymin'] + ((lim['ymax'] - lim['ymin']) - * y / self.xy_array_row) + y = lim['ymin'] + ((lim['ymax'] - lim['ymin']) * y / self.xy_array_row) l = line2d([(lim['xmin'], y), (lim['xmax'], y)], **rowstyle)[0] l._render_on_subplot(subplot) for x in colsub: - x = lim['xmin'] + ((lim['xmax'] - lim['xmin']) - * x / self.xy_array_col) + x = lim['xmin'] + ((lim['xmax'] - lim['xmin']) * x / self.xy_array_col) l = line2d([(x, lim['ymin']), (x, lim['ymax'])], **colstyle)[0] l._render_on_subplot(subplot) if hasattr(self.xy_data_array, 'tocoo'): # Sparse matrix -- use spy opts = options.copy() - for opt in ['vmin', 'vmax', 'norm', 'flip_y', 'subdivisions', - 'subdivision_options', 'colorbar', 'colorbar_options']: + for opt in ['vmin', 'vmax', 'norm', 'flip_y', 'subdivisions', 'subdivision_options', 'colorbar', 'colorbar_options']: del opts[opt] subplot.spy(self.xy_data_array, **opts) else: - extent = (lim['xmin'], lim['xmax'], - lim['ymax' if flip_y else 'ymin'], - lim['ymin' if flip_y else 'ymax']) - opts = {'cmap': cmap, 'interpolation': 'nearest', - 'aspect': 'equal', 'norm': norm, - 'vmin': options['vmin'], 'vmax': options['vmax'], - 'origin': ('upper' if flip_y else 'lower'), - 'extent': extent, 'zorder': options.get('zorder')} + extent = (lim['xmin'], lim['xmax'], lim['ymax' if flip_y else 'ymin'], lim['ymin' if flip_y else 'ymax']) + opts = {'cmap': cmap, 'interpolation': 'nearest', 'aspect': 'equal', 'norm': norm, 'vmin': options['vmin'], 'vmax': options['vmax'], 'origin': ('upper' if flip_y else 'lower'), 'extent': extent, 'zorder': options.get('zorder')} image = subplot.imshow(self.xy_data_array, **opts) if options.get('colorbar', False): colorbar_options = options['colorbar_options'] from matplotlib import colorbar - cax,kwds = colorbar.make_axes_gridspec(subplot, **colorbar_options) + + cax, kwds = colorbar.make_axes_gridspec(subplot, **colorbar_options) colorbar.Colorbar(cax, image, **kwds) if flip_y: @@ -245,10 +244,8 @@ def _render_on_subplot(self, subplot): @suboptions('colorbar', orientation='vertical', format=None) -@suboptions('subdivision',boundaries=None, style=None) -@options(aspect_ratio=1, axes=False, cmap='Greys', colorbar=False, - frame=True, marker='.', norm=None, flip_y=True, - subdivisions=False, ticks_integer=True, vmin=None, vmax=None) +@suboptions('subdivision', boundaries=None, style=None) +@options(aspect_ratio=1, axes=False, cmap='Greys', colorbar=False, frame=True, marker='.', norm=None, flip_y=True, subdivisions=False, ticks_integer=True, vmin=None, vmax=None) def matrix_plot(mat, xrange=None, yrange=None, **options): r""" A plot of a given matrix or 2D array. @@ -558,18 +555,18 @@ def matrix_plot(mat, xrange=None, yrange=None, **options): from sage.plot.graphics import Graphics from sage.structure.element import Matrix from sage.rings.real_double import RDF + orig_mat = mat if isinstance(mat, Matrix): sparse = mat.is_sparse() if sparse: entries = list(mat._dict().items()) try: - data = np.asarray([d for _,d in entries], dtype=float) + data = np.asarray([d for _, d in entries], dtype=float) except Exception: raise ValueError("cannot convert entries to floating point numbers") - positions = np.asarray([[row for (row,col),_ in entries], - [col for (row,col),_ in entries]], dtype=int) - mat = scipysparse.coo_matrix((data,positions), shape=(mat.nrows(), mat.ncols())) + positions = np.asarray([[row for (row, col), _ in entries], [col for (row, col), _ in entries]], dtype=int) + mat = scipysparse.coo_matrix((data, positions), shape=(mat.nrows(), mat.ncols())) else: mat = mat.change_ring(RDF).numpy() elif hasattr(mat, 'tocoo'): diff --git a/src/sage/plot/misc.py b/src/sage/plot/misc.py index 28042fbb2bb..28c5c235310 100644 --- a/src/sage/plot/misc.py +++ b/src/sage/plot/misc.py @@ -19,11 +19,7 @@ from collections.abc import Iterable -def setup_for_eval_on_grid(funcs, - ranges, - plot_points=None, - return_vars=False, - imaginary_tolerance=1e-8): +def setup_for_eval_on_grid(funcs, ranges, plot_points=None, return_vars=False, imaginary_tolerance=1e-8): r""" Calculate the necessary parameters to construct a list of points, and make the functions fast_callable. @@ -162,8 +158,7 @@ def setup_for_eval_on_grid(funcs, raise ValueError("plot_points must be either an integer or a list of integers, one for each range") plot_points = [int(p) if p >= 2 else 2 for p in plot_points] - range_steps = [abs(range[1] - range[0]) / (p - 1) - for range, p in zip(ranges, plot_points)] + range_steps = [abs(range[1] - range[0]) / (p - 1) for range, p in zip(ranges, plot_points)] if min(range_steps) == float(0): raise ValueError("plot start point and end point must be different") @@ -198,10 +193,8 @@ def try_make_fast(f): return f # Convert things like ZZ(0) into constant functions. from sage.symbolic.ring import SR - ff = fast_callable(SR(f), - vars=vars, - expect_one_var=eov, - domain=CDF) + + ff = fast_callable(SR(f), vars=vars, expect_one_var=eov, domain=CDF) return FastCallablePlotWrapper(ff, imag_tol=imaginary_tolerance) # Handle vectors, lists, tuples, etc. @@ -214,13 +207,8 @@ def try_make_fast(f): # takes more values than we have ranges if return_vars: - return (funcs, - [tuple(_range + [range_step]) - for _range, range_step in zip(ranges, range_steps)], - vars) - return (funcs, - [tuple(_range + [range_step]) - for _range, range_step in zip(ranges, range_steps)]) + return (funcs, [tuple(_range + [range_step]) for _range, range_step in zip(ranges, range_steps)], vars) + return (funcs, [tuple(_range + [range_step]) for _range, range_step in zip(ranges, range_steps)]) def unify_arguments(funcs): @@ -263,6 +251,7 @@ def unify_arguments(funcs): funcs = [funcs] from sage.structure.element import Expression + for f in funcs: if isinstance(f, Expression) and f.is_callable(): f_args = set(f.arguments()) @@ -313,6 +302,7 @@ def _multiple_of_constant(n, pos, const): from sage.misc.latex import latex from sage.rings.continued_fraction import continued_fraction from sage.rings.infinity import Infinity + cf = continued_fraction(n / const) k = 1 while cf.quotient(k) != Infinity and cf.denominator(k) < 12: @@ -403,14 +393,8 @@ def get_matplotlib_linestyle(linestyle, return_type): {'solid', 'dashed', 'dotted', dashdot', 'None'}, respectively {'-', '--', ':', '-.', ''} """ - long_to_short_dict = {'solid': '-', - 'dashed': '--', - 'dotted': ':', - 'dashdot': '-.'} - short_to_long_dict = {'-': 'solid', - '--': 'dashed', - ':': 'dotted', - '-.': 'dashdot'} + long_to_short_dict = {'solid': '-', 'dashed': '--', 'dotted': ':', 'dashdot': '-.'} + short_to_long_dict = {'-': 'solid', '--': 'dashed', ':': 'dotted', '-.': 'dashdot'} # We need this to take care of region plot. Essentially, if None is # passed, then we just return back the same thing. @@ -421,16 +405,12 @@ def get_matplotlib_linestyle(linestyle, return_type): return get_matplotlib_linestyle(linestyle.removeprefix("default"), "short") if linestyle.startswith("steps"): if linestyle.startswith("steps-mid"): - return "steps-mid" + get_matplotlib_linestyle( - linestyle.removeprefix("steps-mid"), "short") + return "steps-mid" + get_matplotlib_linestyle(linestyle.removeprefix("steps-mid"), "short") if linestyle.startswith("steps-post"): - return "steps-post" + get_matplotlib_linestyle( - linestyle.removeprefix("steps-post"), "short") + return "steps-post" + get_matplotlib_linestyle(linestyle.removeprefix("steps-post"), "short") if linestyle.startswith("steps-pre"): - return "steps-pre" + get_matplotlib_linestyle( - linestyle.removeprefix("steps-pre"), "short") - return "steps" + get_matplotlib_linestyle( - linestyle.removeprefix("steps"), "short") + return "steps-pre" + get_matplotlib_linestyle(linestyle.removeprefix("steps-pre"), "short") + return "steps" + get_matplotlib_linestyle(linestyle.removeprefix("steps"), "short") if return_type == 'short': if linestyle in short_to_long_dict.keys(): @@ -439,11 +419,7 @@ def get_matplotlib_linestyle(linestyle, return_type): return '' if linestyle in long_to_short_dict.keys(): return long_to_short_dict[linestyle] - raise ValueError("WARNING: Unrecognized linestyle '%s'. " - "Possible linestyle options are:\n{'solid', " - "'dashed', 'dotted', dashdot', 'None'}, " - "respectively {'-', '--', ':', '-.', ''}" % - (linestyle)) + raise ValueError("WARNING: Unrecognized linestyle '%s'. " "Possible linestyle options are:\n{'solid', " "'dashed', 'dotted', dashdot', 'None'}, " "respectively {'-', '--', ':', '-.', ''}" % (linestyle)) elif return_type == 'long': if linestyle in long_to_short_dict.keys(): @@ -452,11 +428,7 @@ def get_matplotlib_linestyle(linestyle, return_type): return "None" if linestyle in short_to_long_dict.keys(): return short_to_long_dict[linestyle] - raise ValueError("WARNING: Unrecognized linestyle '%s'. " - "Possible linestyle options are:\n{'solid', " - "'dashed', 'dotted', dashdot', 'None'}, " - "respectively {'-', '--', ':', '-.', ''}" % - (linestyle)) + raise ValueError("WARNING: Unrecognized linestyle '%s'. " "Possible linestyle options are:\n{'solid', " "'dashed', 'dotted', dashdot', 'None'}, " "respectively {'-', '--', ':', '-.', ''}" % (linestyle)) class FastCallablePlotWrapper(FastCallableFloatWrapper): @@ -481,6 +453,7 @@ class FastCallablePlotWrapper(FastCallableFloatWrapper): sage: fff(-1) nan """ + def __call__(self, *args): r""" Evaluate the underlying fast-callable and convert the result to diff --git a/src/sage/plot/multigraphics.py b/src/sage/plot/multigraphics.py index 9260cd838a9..c2d49e0b19a 100644 --- a/src/sage/plot/multigraphics.py +++ b/src/sage/plot/multigraphics.py @@ -124,6 +124,7 @@ class MultiGraphics(WithEqualityById, SageObject): sage: len(G) 3 """ + def __init__(self, graphics_list): r""" Initialize the attributes common to all MultiGraphics objects. @@ -147,8 +148,7 @@ def __init__(self, graphics_list): self.append(ins) # default position else: if not isinstance(ins, (list, tuple)) or len(ins) != 2: - raise TypeError("a pair (Graphics, position) is " - f"expected, not {ins}") + raise TypeError("a pair (Graphics, position) is " f"expected, not {ins}") self.append(ins[0], pos=ins[1]) def _repr_(self): @@ -206,8 +206,7 @@ def _rich_repr_(self, display_manager, **kwds): raise ValueError('unknown graphics output preference') for file_ext, output_container in preferred: if output_container in display_manager.supported_output(): - return display_manager.graphics_from_save( - self.save, kwds, file_ext, output_container) + return display_manager.graphics_from_save(self.save, kwds, file_ext, output_container) def __getitem__(self, i): r""" @@ -351,8 +350,9 @@ def matplotlib(self, figure=None, figsize=None, **kwds):
""" from matplotlib.figure import Figure + glist = self._glist - if len(glist) == 0: # for an empty MultiGraphics, we create + if len(glist) == 0: # for an empty MultiGraphics, we create glist = [Graphics()] # a 1-element list with an empty graphics # If no Matplotlib figure is provided, it is created here: if figure is None: @@ -375,8 +375,7 @@ def matplotlib(self, figure=None, figsize=None, **kwds): # Creating the Matplotlib Axes object "subplot" on the figure: subplot = self._add_subplot(figure, i) # and drawing g on it: - g.matplotlib(figure=figure, sub=subplot, verify=do_verify, - **options) + g.matplotlib(figure=figure, sub=subplot, verify=do_verify, **options) if transparent: subplot.set_facecolor('none') return figure @@ -424,26 +423,24 @@ def save(self, filename, figsize=None, **kwds): sage: graphics_array([[]]).save(F) """ from matplotlib import rcParams + ext = os.path.splitext(filename)[1].lower() if ext in ['', '.sobj']: SageObject.save(self, filename) elif ext not in ALLOWED_EXTENSIONS: - raise ValueError("allowed file extensions for images are '" + - "', '".join(ALLOWED_EXTENSIONS) + "'!") + raise ValueError("allowed file extensions for images are '" + "', '".join(ALLOWED_EXTENSIONS) + "'!") else: - rc_backup = (rcParams['ps.useafm'], rcParams['pdf.use14corefonts'], - rcParams['text.usetex']) # save the rcParams + rc_backup = (rcParams['ps.useafm'], rcParams['pdf.use14corefonts'], rcParams['text.usetex']) # save the rcParams figure = self.matplotlib(figsize=figsize, **kwds) - transparent = kwds.get('transparent', - Graphics.SHOW_OPTIONS['transparent']) - fig_tight = kwds.get('fig_tight', - Graphics.SHOW_OPTIONS['fig_tight']) + transparent = kwds.get('transparent', Graphics.SHOW_OPTIONS['transparent']) + fig_tight = kwds.get('fig_tight', Graphics.SHOW_OPTIONS['fig_tight']) dpi = kwds.get('dpi', Graphics.SHOW_OPTIONS['dpi']) # One can output in PNG, PS, EPS, PDF, PGF, or SVG format, # depending on the file extension. # PGF is handled by a different backend if ext == '.pgf': - from sage.features.latex import xelatex,pdflatex,lualatex + from sage.features.latex import xelatex, pdflatex, lualatex + latex_implementations = [] if xelatex().is_present(): latex_implementations.append('xelatex') @@ -452,21 +449,17 @@ def save(self, filename, figsize=None, **kwds): if lualatex().is_present(): latex_implementations.append('lualatex') if not latex_implementations: - raise ValueError("Matplotlib requires either xelatex, " - "lualatex, or pdflatex.") + raise ValueError("Matplotlib requires either xelatex, " "lualatex, or pdflatex.") if latex_implementations[0] == "pdflatex": # use pdflatex and set font encoding as per # Matplotlib documentation: # https://matplotlib.org/users/pgf.html#pgf-tutorial - pgf_options = {"pgf.texsystem": "pdflatex", - "pgf.preamble": [ - r"\usepackage[utf8x]{inputenc}", - r"\usepackage[T1]{fontenc}" - ]} + pgf_options = {"pgf.texsystem": "pdflatex", "pgf.preamble": [r"\usepackage[utf8x]{inputenc}", r"\usepackage[T1]{fontenc}"]} else: pgf_options = {"pgf.texsystem": latex_implementations[0]} rcParams.update(pgf_options) from matplotlib.backends.backend_pgf import FigureCanvasPgf + figure.set_canvas(FigureCanvasPgf(figure)) # Matplotlib looks at the file extension to see what the renderer # should be. The default is FigureCanvasAgg for PNG's because this @@ -475,6 +468,7 @@ def save(self, filename, figsize=None, **kwds): # Matplotlib will handle it. else: from matplotlib.backends.backend_agg import FigureCanvasAgg + figure.set_canvas(FigureCanvasAgg(figure)) if isinstance(self, GraphicsArray): # tight_layout adjusts the *subplot* parameters so ticks aren't @@ -485,8 +479,7 @@ def save(self, filename, figsize=None, **kwds): opts['bbox_inches'] = 'tight' figure.savefig(filename, **opts) # Restore the rcParams to the original, possibly user-set values - (rcParams['ps.useafm'], rcParams['pdf.use14corefonts'], - rcParams['text.usetex']) = rc_backup + (rcParams['ps.useafm'], rcParams['pdf.use14corefonts'], rcParams['text.usetex']) = rc_backup def save_image(self, filename=None, *args, **kwds): r""" @@ -607,6 +600,7 @@ def show(self, **kwds): gridlines='major') """ from sage.repl.rich_output import get_display_manager + dm = get_display_manager() dm.display_immediately(self, **kwds) @@ -773,8 +767,7 @@ def _add_subplot(self, figure, index, **options): # Note: using label=str(index) ensures that a new Axes is generated # for each element of ``self``, even if some elements share the same # positions - return figure.add_axes(self._positions[index], label=str(index), - **options) + return figure.add_axes(self._positions[index], label=str(index), **options) def position(self, index): r""" @@ -886,9 +879,9 @@ def append(self, graphics, pos=None): :meth:`inset` """ from matplotlib import rcParams + if not isinstance(graphics, Graphics): - raise TypeError("a Graphics object is expected, " - f"not {graphics}") + raise TypeError("a Graphics object is expected, " f"not {graphics}") if pos is None: # Default position: left = rcParams['figure.subplot.left'] @@ -1062,6 +1055,7 @@ class GraphicsArray(MultiGraphics): G[0] = g4 sphinx_plot(G) """ + def __init__(self, array): r""" Construct a ``GraphicsArray``. @@ -1117,8 +1111,7 @@ def __init__(self, array): """ MultiGraphics.__init__(self, []) if not isinstance(array, (list, tuple)): - raise TypeError("array must be a list of lists of Graphics " - f"objects, not {array}") + raise TypeError("array must be a list of lists of Graphics " f"objects, not {array}") array = list(array) self._rows = len(array) if self._rows > 0: @@ -1130,12 +1123,10 @@ def __init__(self, array): self._cols = 0 for row in array: # basically flatten the list if not isinstance(row, (list, tuple)) or len(row) != self._cols: - raise TypeError("array must be a list of equal-size lists of " - f"Graphics objects, not {array}") + raise TypeError("array must be a list of equal-size lists of " f"Graphics objects, not {array}") for g in row: if not isinstance(g, Graphics): - raise TypeError("every element of array must be a " - "Graphics object") + raise TypeError("every element of array must be a " "Graphics object") self._glist.append(g) # self._positions is not initialized since most of the time, it is not # not used. It is required only by the method inset(); it is then @@ -1244,8 +1235,7 @@ def append(self, g): implemented """ # Not clear if there is a way to do this - raise NotImplementedError('Appending to a graphics array is not ' - 'yet implemented') + raise NotImplementedError('Appending to a graphics array is not ' 'yet implemented') def position(self, index): r""" @@ -1285,6 +1275,7 @@ def position(self, index): # self._positions must be generated, by invoking get_position() on # each of the Axes of the Matplotlib figure corresponding to self: from matplotlib.backends.backend_agg import FigureCanvasAgg + figure = self.matplotlib() figure.set_canvas(FigureCanvasAgg(figure)) figure.tight_layout() diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index e100fded68d..bdd6eb83796 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -603,6 +603,7 @@ def f(x): return (x-3)*(x-5)*(x-7)+40 # import of line2d below is only for redirection of imports from sage.plot.line import line from sage.misc.lazy_import import lazy_import + lazy_import('sage.plot.line', 'line2d', deprecation=28717) # Currently not used - see comment immediately above about @@ -814,6 +815,7 @@ def xydata_from_point_list(points): Graphics object consisting of 1 graphics primitive """ import numbers + zero = float(0) xdata = [] @@ -838,11 +840,7 @@ def xydata_from_point_list(points): return xdata, ydata -@options(alpha=1, thickness=1, fill=False, fillcolor='automatic', - fillalpha=0.5, plot_points=200, adaptive_tolerance=0.01, - adaptive_recursion=5, detect_poles=False, exclude=None, - legend_label=None, __original_opts=True, - aspect_ratio='automatic', imaginary_tolerance=1e-8) +@options(alpha=1, thickness=1, fill=False, fillcolor='automatic', fillalpha=0.5, plot_points=200, adaptive_tolerance=0.01, adaptive_recursion=5, detect_poles=False, exclude=None, legend_label=None, __original_opts=True, aspect_ratio='automatic', imaginary_tolerance=1e-8) def plot(funcs, *args, **kwds): r""" Use plot by writing. @@ -2025,6 +2023,7 @@ def f(x): return (floor(x)+0.5) / (1-(x-0.5)**2) do_show = kwds.pop('show', False) from sage.structure.element import Vector + if kwds.get('parametric', False) and isinstance(funcs, Vector): funcs = tuple(funcs) @@ -2077,8 +2076,7 @@ def f(x): return (floor(x)+0.5) / (1-(x-0.5)**2) return G -def _plot(funcs, xrange, parametric=False, - polar=False, fill=False, label='', randomize=True, **options): +def _plot(funcs, xrange, parametric=False, polar=False, fill=False, label='', randomize=True, **options): """ Internal function which does the actual plotting. @@ -2168,15 +2166,13 @@ def _plot(funcs, xrange, parametric=False, """ from sage.plot.colors import Color from sage.plot.misc import setup_for_eval_on_grid + if funcs == []: return Graphics() orig_funcs = funcs # keep the original functions (for use in legend labels) excluded_points = [] imag_tol = options["imaginary_tolerance"] - funcs, ranges = setup_for_eval_on_grid(funcs, - [xrange], - options['plot_points'], - imaginary_tolerance=imag_tol) + funcs, ranges = setup_for_eval_on_grid(funcs, [xrange], options['plot_points'], imaginary_tolerance=imag_tol) xmin, xmax, delta = ranges[0] xrange = ranges[0][:2] # parametric_plot will be a list or tuple of two functions (f,g) @@ -2195,12 +2191,13 @@ def _plot(funcs, xrange, parametric=False, # Check to see if funcs is a list of functions that will be all plotted together. if isinstance(funcs, (list, tuple)) and not parametric: + def golden_rainbow(i, lightness=0.4): # note: sage's "blue" has hue-saturation-lightness values (2/3, 1, 1/2). g = 0.61803398875 - return Color((0.66666666666666 + i*g) % 1, 1, lightness, space='hsl') + return Color((0.66666666666666 + i * g) % 1, 1, lightness, space='hsl') - default_line_styles = ("-", "--", "-.", ":")*len(funcs) + default_line_styles = ("-", "--", "-.", ":") * len(funcs) G = Graphics() for i, h in enumerate(funcs): @@ -2323,9 +2320,7 @@ def golden_rainbow(i, lightness=0.4): elif legend_color_temp is not None: legend_color_entry = legend_color_temp - G += plot(h, xrange, polar=polar, fill=fill_entry, fillcolor=fillcolor_entry, - rgbcolor=color_entry, linestyle=linestyle_entry, - legend_label=legend_label_entry, legend_color=legend_color_entry, **options_temp) + G += plot(h, xrange, polar=polar, fill=fill_entry, fillcolor=fillcolor_entry, rgbcolor=color_entry, linestyle=linestyle_entry, legend_label=legend_label_entry, legend_color=legend_color_entry, **options_temp) return G adaptive_tolerance = options.pop('adaptive_tolerance') @@ -2356,18 +2351,14 @@ def golden_rainbow(i, lightness=0.4): raise ValueError('exclude needs to be a list of numbers or an equation') # We make sure that points plot points close to the excluded points are computed - epsilon = 0.001*(xmax - xmin) - initial_points = reduce(lambda a, b: a+b, - [[x - epsilon, x + epsilon] - for x in excluded_points], []) + epsilon = 0.001 * (xmax - xmin) + initial_points = reduce(lambda a, b: a + b, [[x - epsilon, x + epsilon] for x in excluded_points], []) else: initial_points = None # If we are a log scale plot on the x axis, do a change of variables # so we sample the range in log scale - is_log_scale = ('scale' in options.keys() and - not parametric and - options['scale'] in ['loglog', 'semilogx']) + is_log_scale = 'scale' in options.keys() and not parametric and options['scale'] in ['loglog', 'semilogx'] if is_log_scale: def f_exp(x): @@ -2378,17 +2369,9 @@ def f_exp(x): log_initial_points = None else: log_initial_points = [log(x) for x in initial_points] - data, extra_excluded = generate_plot_points( - f_exp, log_xrange, plot_points, - adaptive_tolerance, adaptive_recursion, - randomize, log_initial_points, - excluded=True, imaginary_tolerance=imag_tol) + data, extra_excluded = generate_plot_points(f_exp, log_xrange, plot_points, adaptive_tolerance, adaptive_recursion, randomize, log_initial_points, excluded=True, imaginary_tolerance=imag_tol) else: - data, extra_excluded = generate_plot_points( - f, xrange, plot_points, - adaptive_tolerance, adaptive_recursion, - randomize, initial_points, - excluded=True, imaginary_tolerance=imag_tol) + data, extra_excluded = generate_plot_points(f, xrange, plot_points, adaptive_tolerance, adaptive_recursion, randomize, initial_points, excluded=True, imaginary_tolerance=imag_tol) excluded_points += extra_excluded @@ -2442,13 +2425,7 @@ def f_exp(x): else: fill_f = fill - filldata = generate_plot_points(fill_f, - xrange, - plot_points, - adaptive_tolerance, - adaptive_recursion, - randomize, - imaginary_tolerance=imag_tol) + filldata = generate_plot_points(fill_f, xrange, plot_points, adaptive_tolerance, adaptive_recursion, randomize, imaginary_tolerance=imag_tol) filldata.reverse() filldata += data else: @@ -2458,13 +2435,7 @@ def f_exp(x): base_level = 0 if not callable(fill) and polar: - filldata = generate_plot_points(lambda x: base_level, - xrange, - plot_points, - adaptive_tolerance, - adaptive_recursion, - randomize, - imaginary_tolerance=imag_tol) + filldata = generate_plot_points(lambda x: base_level, xrange, plot_points, adaptive_tolerance, adaptive_recursion, randomize, imaginary_tolerance=imag_tol) filldata.reverse() filldata += data if not callable(fill) and not polar: @@ -2477,14 +2448,14 @@ def f_exp(x): fill_options['alpha'] = fillalpha fill_options['thickness'] = 0 if polar: - filldata = [(y*cos(x), y*sin(x)) for x, y in filldata] + filldata = [(y * cos(x), y * sin(x)) for x, y in filldata] G += polygon(filldata, **fill_options) # We need the original data to be able to exclude points in polar plots if not parametric: exclude_data = data if polar: - data = [(y*cos(x), y*sin(x)) for x, y in data] + data = [(y * cos(x), y * sin(x)) for x, y in data] detect_poles = options.pop('detect_poles', False) legend_label = options.pop('legend_label', None) @@ -2492,6 +2463,7 @@ def f_exp(x): start_index = 0 # setup for pole detection from sage.rings.real_double import RDF + epsilon = 0.0001 pole_options = {} pole_options['linestyle'] = '--' @@ -2507,23 +2479,22 @@ def f_exp(x): exclusion_point = xmax + 1 flag = True - for i in range(len(data)-1): + for i in range(len(data) - 1): x0, y0 = exclude_data[i] - x1, y1 = exclude_data[i+1] + x1, y1 = exclude_data[i + 1] # detect poles - if (not (polar or parametric)) and detect_poles \ - and ((y1 > 0 and y0 < 0) or (y1 < 0 and y0 > 0)): + if (not (polar or parametric)) and detect_poles and ((y1 > 0 and y0 < 0) or (y1 < 0 and y0 > 0)): # calculate the slope of the line segment - dy = abs(y1-y0) + dy = abs(y1 - y0) dx = x1 - x0 - alpha = (RDF(dy)/RDF(dx)).arctan() - if alpha >= RDF(pi/2) - epsilon: + alpha = (RDF(dy) / RDF(dx)).arctan() + if alpha >= RDF(pi / 2) - epsilon: G += line(data[start_index:i], **options) if detect_poles == 'show': # draw a vertical asymptote G += line([(x0, y0), (x1, y1)], **pole_options) - start_index = i+2 + start_index = i + 2 # exclude points if x0 > exclusion_point: @@ -2555,6 +2526,7 @@ def f_exp(x): # ######### misc functions ################# + @options(aspect_ratio=1.0) def parametric_plot(funcs, *args, **kwargs): r""" @@ -2763,7 +2735,7 @@ def parametric_plot(funcs, *args, **kwargs): if num_funcs == 2 and num_ranges == 1: kwargs['parametric'] = True return plot(funcs, *args, **kwargs) - if (num_funcs == 3 and num_ranges <= 2): + if num_funcs == 3 and num_ranges <= 2: return sage.plot.plot3d.parametric_plot3d.parametric_plot3d(funcs, *args, **kwargs) raise ValueError("the number of functions and the number of variable ranges is not a supported combination for a 2d or 3d parametric plots") @@ -3130,15 +3102,14 @@ def list_plot(data, plotjoined=False, **kwargs): Graphics object consisting of 1 graphics primitive """ from sage.plot.point import point + try: if not data: return Graphics() except ValueError: # numpy raises ValueError if it is not empty pass if not isinstance(plotjoined, bool): - raise TypeError("The second argument 'plotjoined' should be boolean " - "(True or False). If you meant to plot two lists 'x' " - "and 'y' against each other, use 'list_plot(list(zip(x,y)))'.") + raise TypeError("The second argument 'plotjoined' should be boolean " "(True or False). If you meant to plot two lists 'x' " "and 'y' against each other, use 'list_plot(list(zip(x,y)))'.") if isinstance(data, dict): if plotjoined: list_data = sorted(data.items()) @@ -3148,6 +3119,7 @@ def list_plot(data, plotjoined=False, **kwargs): list_enumerated = False try: from sage.rings.real_double import RDF + RDF(data[0]) data = list(enumerate(data)) list_enumerated = True @@ -3175,6 +3147,7 @@ def list_plot(data, plotjoined=False, **kwargs): # point3d() throws an IndexError on the (0,1) before it ever # gets to (1, I). from sage.rings.cc import CC + # It is not guaranteed that we enumerated the data so we have two cases if list_enumerated: data = [(z.real(), z.imag()) for z in [CC(z[1]) for z in data]] @@ -3184,6 +3157,7 @@ def list_plot(data, plotjoined=False, **kwargs): return line(data, **kwargs) return point(data, **kwargs) + # ------------------------ Graphs on log scale --------------------------- @@ -3563,7 +3537,7 @@ def reshape(v, n, m): G = Graphics() G.axes(False) if len(v) == 0: - return [[G]*m]*n + return [[G] * m] * n if not isinstance(v[0], Graphics): # a list of lists -- flatten it @@ -3571,7 +3545,7 @@ def reshape(v, n, m): # Now v should be a single list. # First, make it have the right length. - v = list(v) # do not mutate the argument + v = list(v) # do not mutate the argument for i in range(n * m - len(v)): v.append(G) @@ -3745,12 +3719,12 @@ def h(x): return sin(4*x) if nrows is None: ncols = int(ncols) nrows = length // ncols - if nrows*ncols < length or nrows == 0: + if nrows * ncols < length or nrows == 0: nrows += 1 elif ncols is None: nrows = int(nrows) ncols = length // nrows - if nrows*ncols < length or ncols == 0: + if nrows * ncols < length or ncols == 0: ncols += 1 else: assert False @@ -3862,14 +3836,12 @@ def minmax_data(xdata, ydata, dict=False) -> tuple | dict: ymin = min(ydata) if len(ydata) else -1 ymax = max(ydata) if len(ydata) else 1 if dict: - return {'xmin': xmin, 'xmax': xmax, - 'ymin': ymin, 'ymax': ymax} + return {'xmin': xmin, 'xmax': xmax, 'ymin': ymin, 'ymax': ymax} return xmin, xmax, ymin, ymax -def adaptive_refinement(f, p1, p2, adaptive_tolerance=0.01, - adaptive_recursion=5, level=0, *, excluded=False): +def adaptive_refinement(f, p1, p2, adaptive_tolerance=0.01, adaptive_recursion=5, level=0, *, excluded=False): r""" The adaptive refinement algorithm for plotting a function ``f``. See the docstring for plot for a description of the algorithm. @@ -3943,7 +3915,7 @@ def adaptive_refinement(f, p1, p2, adaptive_tolerance=0.01, if level >= adaptive_recursion: return [] - x = (p1[0] + p2[0])/2.0 + x = (p1[0] + p2[0]) / 2.0 msg = '' try: @@ -3963,27 +3935,16 @@ def adaptive_refinement(f, p1, p2, adaptive_tolerance=0.01, return [] # this distance calculation is not perfect. - if abs((p1[1] + p2[1])/2.0 - y) > adaptive_tolerance: - ref = adaptive_refinement(f, p1, (x, y), - adaptive_tolerance=adaptive_tolerance, - adaptive_recursion=adaptive_recursion, - level=level+1, - excluded=excluded) + if abs((p1[1] + p2[1]) / 2.0 - y) > adaptive_tolerance: + ref = adaptive_refinement(f, p1, (x, y), adaptive_tolerance=adaptive_tolerance, adaptive_recursion=adaptive_recursion, level=level + 1, excluded=excluded) ref += [(x, y)] - ref += adaptive_refinement(f, (x, y), p2, - adaptive_tolerance=adaptive_tolerance, - adaptive_recursion=adaptive_recursion, - level=level+1, - excluded=excluded) + ref += adaptive_refinement(f, (x, y), p2, adaptive_tolerance=adaptive_tolerance, adaptive_recursion=adaptive_recursion, level=level + 1, excluded=excluded) return ref return [] -def generate_plot_points(f, xrange, plot_points=5, adaptive_tolerance=0.01, - adaptive_recursion=5, randomize=True, - initial_points=None, *, excluded=False, - imaginary_tolerance=1e-8): +def generate_plot_points(f, xrange, plot_points=5, adaptive_tolerance=0.01, adaptive_recursion=5, randomize=True, initial_points=None, *, excluded=False, imaginary_tolerance=1e-8): r""" Calculate plot points for a function f in the interval xrange. The adaptive refinement algorithm is also automatically invoked with a @@ -4074,10 +4035,8 @@ def generate_plot_points(f, xrange, plot_points=5, adaptive_tolerance=0.01, ([(1.0, 0.0)], [0.0]) """ from sage.plot.misc import setup_for_eval_on_grid - f, ranges = setup_for_eval_on_grid(f, - [xrange], - plot_points, - imaginary_tolerance=imaginary_tolerance) + + f, ranges = setup_for_eval_on_grid(f, [xrange], plot_points, imaginary_tolerance=imaginary_tolerance) xmin, xmax, delta = ranges[0] x_values = srange(*ranges[0], include_endpoint=True) @@ -4087,15 +4046,15 @@ def generate_plot_points(f, xrange, plot_points=5, adaptive_tolerance=0.01, xi = x_values[i] # Slightly randomize the interior sample points if # randomize is true - if randomize and i > 0 and i < plot_points-1: - xi += delta*(random() - 0.5) + if randomize and i > 0 and i < plot_points - 1: + xi += delta * (random() - 0.5) x_values[i] = xi # add initial points if isinstance(initial_points, list): x_values = sorted(x_values + initial_points) - data = [None]*len(x_values) + data = [None] * len(x_values) exceptions = 0 exception_indices = [] @@ -4115,7 +4074,7 @@ def generate_plot_points(f, xrange, plot_points=5, adaptive_tolerance=0.01, if i == 0: # Given an error for left endpoint, try to move it in slightly for j in range(1, 99): - xj = xi + delta*j/100.0 + xj = xi + delta * j / 100.0 try: data[i] = (float(xj), float(f(xj))) # nan != nan @@ -4129,9 +4088,9 @@ def generate_plot_points(f, xrange, plot_points=5, adaptive_tolerance=0.01, exceptions += 1 exception_indices.append(i) - elif i == plot_points-1: # Given an error for right endpoint, try to move it in slightly + elif i == plot_points - 1: # Given an error for right endpoint, try to move it in slightly for j in range(1, 99): - xj = xi - delta*j/100.0 + xj = xi - delta * j / 100.0 try: data[i] = (float(xj), float(f(xj))) # nan != nan @@ -4158,14 +4117,11 @@ def generate_plot_points(f, xrange, plot_points=5, adaptive_tolerance=0.01, adaptive_recursion = int(adaptive_recursion) while i < len(data) - 1: - for p in adaptive_refinement(f, data[i], data[i+1], - adaptive_tolerance=adaptive_tolerance, - adaptive_recursion=adaptive_recursion, - excluded=True): + for p in adaptive_refinement(f, data[i], data[i + 1], adaptive_tolerance=adaptive_tolerance, adaptive_recursion=adaptive_recursion, excluded=True): if p[1] == "NaN": excluded_points.append(p[0]) else: - data.insert(i+1, p) + data.insert(i + 1, p) i += 1 i += 1 diff --git a/src/sage/plot/plot3d/all.py b/src/sage/plot/plot3d/all.py index 1fc801284f5..2d5eefc8fdc 100644 --- a/src/sage/plot/plot3d/all.py +++ b/src/sage/plot/plot3d/all.py @@ -1,10 +1,10 @@ - from sage.plot.plot3d.plot3d import plot3d, cylindrical_plot3d, spherical_plot3d, Spherical, SphericalElevation, Cylindrical from sage.plot.plot3d.parametric_plot3d import parametric_plot3d from sage.plot.plot3d.plot_field3d import plot_vector_field3d # We lazy_import the following modules since they import numpy which slows down sage startup from sage.misc.lazy_import import lazy_import + lazy_import("sage.plot.plot3d.implicit_plot3d", ["implicit_plot3d"]) from sage.plot.plot3d.list_plot3d import list_plot3d diff --git a/src/sage/plot/plot3d/list_plot3d.py b/src/sage/plot/plot3d/list_plot3d.py index 42fde5672df..4f40ce5636c 100644 --- a/src/sage/plot/plot3d/list_plot3d.py +++ b/src/sage/plot/plot3d/list_plot3d.py @@ -248,13 +248,11 @@ def list_plot3d(v, interpolation_type='default', point_list=None, **kwds): ValueError: we need at least 3 points to perform the interpolation """ import numpy + if isinstance(v, Matrix): - if (interpolation_type == 'default' or - interpolation_type == 'linear' and 'num_points' not in kwds): + if interpolation_type == 'default' or interpolation_type == 'linear' and 'num_points' not in kwds: return list_plot3d_matrix(v, **kwds) - data = [(i, j, v[i, j]) - for i in range(v.nrows()) - for j in range(v.ncols())] + data = [(i, j, v[i, j]) for i in range(v.nrows()) for j in range(v.ncols())] return list_plot3d_tuples(data, interpolation_type, **kwds) if isinstance(v, numpy.ndarray): @@ -264,14 +262,17 @@ def list_plot3d(v, interpolation_type='default', point_list=None, **kwds): if not v: # return empty 3d graphic from .base import Graphics3d + return Graphics3d() if len(v) == 1: # return a point from .shapes2 import point3d + return point3d(v[0], **kwds) if len(v) == 2: # return a line from .shapes2 import line3d + return line3d(v, **kwds) if isinstance(v[0], tuple) or point_list and len(v[0]) == 3: return list_plot3d_tuples(v, interpolation_type, **kwds) @@ -359,8 +360,8 @@ def list_plot3d_matrix(m, **kwds): def f(i, j): return (i, j, float(m[int(i), int(j)])) - G = ParametricSurface(f, (list(range(m.nrows())), list(range(m.ncols()))), - **kwds) + + G = ParametricSurface(f, (list(range(m.nrows())), list(range(m.ncols()))), **kwds) G._set_extra_kwds(kwds) return G @@ -534,8 +535,7 @@ def list_plot3d_tuples(v, interpolation_type, **kwds): from .plot3d import plot3d if len(v) < 3: - raise ValueError("we need at least 3 points to perform the " - "interpolation") + raise ValueError("we need at least 3 points to perform the " "interpolation") x = [float(p[0]) for p in v] y = [float(p[1]) for p in v] @@ -547,7 +547,7 @@ def list_plot3d_tuples(v, interpolation_type, **kwds): # noise to avoid the problem if needed. corr_matrix = numpy.corrcoef(x, y) if not (-0.9 <= corr_matrix[0, 1] <= 0.9): - ep = .000001 + ep = 0.000001 x = [float(p[0]) + random() * ep for p in v] y = [float(p[1]) + random() * ep for p in v] @@ -564,9 +564,7 @@ def list_plot3d_tuples(v, interpolation_type, **kwds): for j in range(i + 1, nb_points): if x[i] == x[j] and y[i] == y[j]: if z[i] != z[j]: - raise ValueError("points with same x,y coordinates" - " and different z coordinates were" - " given. Interpolation cannot handle this.") + raise ValueError("points with same x,y coordinates" " and different z coordinates were" " given. Interpolation cannot handle this.") elif z[i] == z[j]: drop_list.append(j) x = [x[i] for i in range(nb_points) if i not in drop_list] @@ -592,9 +590,7 @@ def g(x, y): z = f(x, y) return (x, y, z) - G = ParametricSurface(g, (list(numpy.r_[xmin:xmax:num_points * j]), - list(numpy.r_[ymin:ymax:num_points * j])), - **kwds) + G = ParametricSurface(g, (list(numpy.r_[xmin : xmax : num_points * j]), list(numpy.r_[ymin : ymax : num_points * j])), **kwds) G._set_extra_kwds(kwds) return G @@ -609,9 +605,7 @@ def g(x, y): z = f([x, y]).item() return (x, y, z) - G = ParametricSurface(g, (list(numpy.r_[xmin:xmax:num_points * j]), - list(numpy.r_[ymin:ymax:num_points * j])), - **kwds) + G = ParametricSurface(g, (list(numpy.r_[xmin : xmax : num_points * j]), list(numpy.r_[ymin : ymax : num_points * j])), **kwds) G._set_extra_kwds(kwds) return G @@ -622,11 +616,9 @@ def g(x, y): kx = kwds['degree'] ky = kwds['degree'] s = kwds.get('smoothing', len(x) - numpy.sqrt(2 * len(x))) - s = interpolate.bisplrep(x, y, z, [1] * len(x), xmin, xmax, - ymin, ymax, kx=kx, ky=ky, s=s) + s = interpolate.bisplrep(x, y, z, [1] * len(x), xmin, xmax, ymin, ymax, kx=kx, ky=ky, s=s) def f(x, y): return interpolate.bisplev(x, y, s) - return plot3d(f, (xmin, xmax), (ymin, ymax), - plot_points=[num_points, num_points], **kwds) + return plot3d(f, (xmin, xmax), (ymin, ymax), plot_points=[num_points, num_points], **kwds) diff --git a/src/sage/plot/plot3d/parametric_plot3d.py b/src/sage/plot/plot3d/parametric_plot3d.py index d10ba5924ce..84ec30f3849 100644 --- a/src/sage/plot/plot3d/parametric_plot3d.py +++ b/src/sage/plot/plot3d/parametric_plot3d.py @@ -11,8 +11,7 @@ @rename_keyword(alpha='opacity') -def parametric_plot3d(f, urange, vrange=None, plot_points='automatic', - boundary_style=None, **kwds): +def parametric_plot3d(f, urange, vrange=None, plot_points='automatic', boundary_style=None, **kwds): r""" Return a parametric three-dimensional space curve or surface. @@ -1054,6 +1053,7 @@ def _parametric_plot3d_curve(f, urange, plot_points, **kwds): Graphics3d Object """ from sage.plot.misc import setup_for_eval_on_grid + g, ranges = setup_for_eval_on_grid(f, [urange], plot_points) f_x, f_y, f_z = g w = [(f_x(u), f_y(u), f_z(u)) for u in xsrange(*ranges[0], include_endpoint=True)] @@ -1114,6 +1114,7 @@ def _parametric_plot3d_surface(f, urange, vrange, plot_points, boundary_style, * Graphics3d Object """ from sage.plot.misc import setup_for_eval_on_grid + g, ranges = setup_for_eval_on_grid(f, [urange, vrange], plot_points) urange = srange(*ranges[0], include_endpoint=True) vrange = srange(*ranges[1], include_endpoint=True) @@ -1121,9 +1122,7 @@ def _parametric_plot3d_surface(f, urange, vrange, plot_points, boundary_style, * if boundary_style is not None: for u in (urange[0], urange[-1]): - G += line3d([(g[0](u, v), g[1](u, v), g[2](u, v)) for v in vrange], - **boundary_style) + G += line3d([(g[0](u, v), g[1](u, v), g[2](u, v)) for v in vrange], **boundary_style) for v in (vrange[0], vrange[-1]): - G += line3d([(g[0](u, v), g[1](u, v), g[2](u, v)) for u in urange], - **boundary_style) + G += line3d([(g[0](u, v), g[1](u, v), g[2](u, v)) for u in urange], **boundary_style) return G diff --git a/src/sage/plot/plot3d/platonic.py b/src/sage/plot/plot3d/platonic.py index 57ea03ccf63..cd9d3a47140 100644 --- a/src/sage/plot/plot3d/platonic.py +++ b/src/sage/plot/plot3d/platonic.py @@ -49,7 +49,6 @@ - William Stein """ - # **************************************************************************** # Copyright (C) 2007 Robert Bradshaw # @@ -255,19 +254,15 @@ def tetrahedron(center=(0, 0, 0), size=1, **kwds): one = RR.one() sqrt2 = RR(2).sqrt() sqrt6 = RR(6).sqrt() - point_list = [(0, 0, 1), - (2*sqrt2/3, 0, -one/3), - (-sqrt2/3, sqrt6/3, -one/3), - (-sqrt2/3, -sqrt6/3, -one/3)] - face_list = [[0,1,2],[1,3,2],[0,2,3],[0,3,1]] + point_list = [(0, 0, 1), (2 * sqrt2 / 3, 0, -one / 3), (-sqrt2 / 3, sqrt6 / 3, -one / 3), (-sqrt2 / 3, -sqrt6 / 3, -one / 3)] + face_list = [[0, 1, 2], [1, 3, 2], [0, 2, 3], [0, 3, 1]] if 'aspect_ratio' not in kwds: kwds['aspect_ratio'] = [1, 1, 1] return index_face_set(face_list, point_list, enclosed=True, center=center, size=size, **kwds) @rename_keyword(alpha='opacity') -def cube(center=(0, 0, 0), size=1, color=None, frame_thickness=0, - frame_color=None, **kwds): +def cube(center=(0, 0, 0), size=1, color=None, frame_thickness=0, frame_color=None, **kwds): """ A 3D cube centered at the origin with default side lengths 1. @@ -392,16 +387,16 @@ def cube(center=(0, 0, 0), size=1, color=None, frame_thickness=0, - William Stein """ if isinstance(color, (list, tuple)) and len(color) > 0 and isinstance(color[0], (list, tuple, str)): - B = ColorCube(size=[0.5,0.5,0.5], colors=color, **kwds) + B = ColorCube(size=[0.5, 0.5, 0.5], colors=color, **kwds) else: if color is not None: kwds['color'] = color B = Box(0.5, 0.5, 0.5, **kwds) if frame_thickness > 0: if frame_color is None: - B += frame3d((-0.5,-0.5,-0.5),(0.5,0.5,0.5), thickness=frame_thickness) + B += frame3d((-0.5, -0.5, -0.5), (0.5, 0.5, 0.5), thickness=frame_thickness) else: - B += frame3d((-0.5,-0.5,-0.5),(0.5,0.5,0.5), thickness=frame_thickness, color=frame_color) + B += frame3d((-0.5, -0.5, -0.5), (0.5, 0.5, 0.5), thickness=frame_thickness, color=frame_color) return prep(B, center, size, kwds) @@ -517,34 +512,28 @@ def dodecahedron(center=(0, 0, 0), size=1, **kwds): sqrt3 = RR(3).sqrt() sqrt5 = RR(5).sqrt() R3 = RR**3 - rot = matrix(RR, [[-one / 2, -sqrt3 / 2, 0], - [sqrt3 / 2, -one / 2, 0], - [0, 0, 1]]) + rot = matrix(RR, [[-one / 2, -sqrt3 / 2, 0], [sqrt3 / 2, -one / 2, 0], [0, 0, 1]]) rot2 = rot * rot # The top Q = R3([0, 0, 1]) # The first ring - P1 = R3([2*one/3, 0, sqrt5/3]) + P1 = R3([2 * one / 3, 0, sqrt5 / 3]) # The second ring - R1 = R3([sqrt5/3, 1/sqrt3, one/3]) - R2 = R3([sqrt5/3, -1/sqrt3, one/3]) + R1 = R3([sqrt5 / 3, 1 / sqrt3, one / 3]) + R2 = R3([sqrt5 / 3, -1 / sqrt3, one / 3]) - top = [Q, P1, rot*P1, rot2*P1, R1, rot*R2, rot*R1, rot2*R2, rot2*R1, R2] + top = [Q, P1, rot * P1, rot2 * P1, R1, rot * R2, rot * R1, rot2 * R2, rot2 * R1, R2] point_list = top + [-p for p in reversed(top)] - top_faces = [[0,1,4,5,2], - [0,2,6,7,3], - [0,3,8,9,1], - [1,9,13,12,4], - [2,5,11,10,6], - [3,7,15,14,8]] - face_list = top_faces + [[19-p for p in reversed(f)] for f in top_faces] + top_faces = [[0, 1, 4, 5, 2], [0, 2, 6, 7, 3], [0, 3, 8, 9, 1], [1, 9, 13, 12, 4], [2, 5, 11, 10, 6], [3, 7, 15, 14, 8]] + face_list = top_faces + [[19 - p for p in reversed(f)] for f in top_faces] if 'aspect_ratio' not in kwds: - kwds['aspect_ratio'] = [1,1,1] + kwds['aspect_ratio'] = [1, 1, 1] return index_face_set(face_list, point_list, enclosed=True, center=center, size=size, **kwds) + # if style == 'vertices' or style == 'edges': # from sage.plot.colors import rainbow # colors = rainbow(len(vs), 'rgbtuple') diff --git a/src/sage/plot/plot3d/plot3d.py b/src/sage/plot/plot3d/plot3d.py index bdf15a85e9d..97fbc908314 100644 --- a/src/sage/plot/plot3d/plot3d.py +++ b/src/sage/plot/plot3d/plot3d.py @@ -156,6 +156,7 @@ def f(x, y): return math.exp(x/5)*math.cos(y) from sage.plot.plot3d.texture import Texture from sage.plot.plot3d.tri_plot import TrianglePlot from . import parametric_plot3d + lazy_import("sage.functions.trig", ["cos", "sin"]) @@ -174,6 +175,7 @@ class _Coordinates: - ``indep_vars`` -- list of independent variables (the parameters will be substituted for these) """ + def __init__(self, dep_var, indep_vars): """ Initialize. @@ -193,9 +195,7 @@ def __init__(self, dep_var, indep_vars): A = set(all_vars) B = set(indep_vars + [dep_var]) if A != B: - raise ValueError('variables were specified incorrectly for this ' - 'coordinate system; incorrect variables ' - 'were %s' % list(A.symmetric_difference(B))) + raise ValueError('variables were specified incorrectly for this ' 'coordinate system; incorrect variables ' 'were %s' % list(A.symmetric_difference(B))) self.dep_var = dep_var self.indep_vars = indep_vars @@ -323,24 +323,16 @@ def to_cartesian(self, func, params=None): from sage.structure.element import Expression from sage.rings.real_mpfr import RealNumber from sage.rings.integer import Integer - if params is not None and isinstance(func, (Expression, - RealNumber, - Integer)): - return self.transform(**{ - self.dep_var: func, - self.indep_vars[0]: params[0], - self.indep_vars[1]: params[1] - }) + + if params is not None and isinstance(func, (Expression, RealNumber, Integer)): + return self.transform(**{self.dep_var: func, self.indep_vars[0]: params[0], self.indep_vars[1]: params[1]}) # func might be a lambda or a Python callable; this makes it slightly # more complex. import sage.symbolic.ring + dep_var_dummy = sage.symbolic.ring.var(self.dep_var) indep_var_dummies = sage.symbolic.ring.var(','.join(self.indep_vars)) - transformation = self.transform(**{ - self.dep_var: dep_var_dummy, - self.indep_vars[0]: indep_var_dummies[0], - self.indep_vars[1]: indep_var_dummies[1] - }) + transformation = self.transform(**{self.dep_var: dep_var_dummy, self.indep_vars[0]: indep_var_dummies[0], self.indep_vars[1]: indep_var_dummies[1]}) if params is None: if callable(func): params = _find_arguments_for_callable(func) @@ -357,9 +349,8 @@ def subs_func(t): indep_var_dummies[0]: float({params[0]}), indep_var_dummies[1]: float({params[1]}) }})""" - return eval(ll, {'t': t, 'func': func, - 'dep_var_dummy': dep_var_dummy, - 'indep_var_dummies': indep_var_dummies}) + return eval(ll, {'t': t, 'func': func, 'dep_var_dummy': dep_var_dummy, 'indep_var_dummies': indep_var_dummies}) + return [subs_func(m) for m in transformation] def __repr__(self): @@ -421,7 +412,7 @@ def _find_arguments_for_callable(func): if f_args.defaults is None: params = f_args.args else: - params = f_args.args[:-len(f_args.defaults)] + params = f_args.args[: -len(f_args.defaults)] return params @@ -430,6 +421,7 @@ class _ArbitraryCoordinates(_Coordinates): """ An arbitrary coordinate system. """ + _name = "Arbitrary Coordinates" def __init__(self, custom_trans, dep_var, indep_vars): @@ -542,9 +534,7 @@ def transform(self, radius=None, azimuth=None, inclination=None): sage: T.transform(radius=var('r'), azimuth=var('theta'), inclination=var('phi')) (r*cos(theta)*sin(phi), r*sin(phi)*sin(theta), r*cos(phi)) """ - return (radius * sin(inclination) * cos(azimuth), - radius * sin(inclination) * sin(azimuth), - radius * cos(inclination)) + return (radius * sin(inclination) * cos(azimuth), radius * sin(inclination) * sin(azimuth), radius * cos(inclination)) class SphericalElevation(_Coordinates): @@ -661,9 +651,7 @@ def transform(self, radius=None, azimuth=None, elevation=None): sage: T.transform(radius=var('r'), azimuth=var('theta'), elevation=var('phi')) (r*cos(phi)*cos(theta), r*cos(phi)*sin(theta), r*sin(phi)) """ - return (radius * cos(elevation) * cos(azimuth), - radius * cos(elevation) * sin(azimuth), - radius * sin(elevation)) + return (radius * cos(elevation) * cos(azimuth), radius * cos(elevation) * sin(azimuth), radius * sin(elevation)) class Cylindrical(_Coordinates): @@ -732,9 +720,7 @@ def transform(self, radius=None, azimuth=None, height=None): sage: T.transform(radius=var('r'), azimuth=var('theta'), height=var('z')) (r*cos(theta), r*sin(theta), z) """ - return (radius * cos(azimuth), - radius * sin(azimuth), - height) + return (radius * cos(azimuth), radius * sin(azimuth), height) class TrivialTriangleFactory: @@ -743,6 +729,7 @@ class TrivialTriangleFactory: but simply returning a list of vertices for both regular and smooth triangles. """ + def triangle(self, a, b, c, color=None): """ Function emulating behavior of @@ -1075,6 +1062,7 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): if transformation is not None: params = None from sage.structure.element import Expression + # First, determine the parameters for f (from the first item of urange # and vrange, preferably). if len(urange) == 3 and len(vrange) == 3: @@ -1083,6 +1071,7 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): params = f.variables() from sage.modules.vector_callable_symbolic_dense import Vector_callable_symbolic_dense + if isinstance(transformation, (tuple, list, Vector_callable_symbolic_dense)): if len(transformation) == 3: if params is None: @@ -1112,17 +1101,12 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): else: arg1 = lambda u, v: u arg2 = lambda u, v: v - P = parametric_plot3d.parametric_plot3d((arg1, arg2, f), - urange, - vrange, - **kwds) + P = parametric_plot3d.parametric_plot3d((arg1, arg2, f), urange, vrange, **kwds) P.frame_aspect_ratio([1.0, 1.0, 0.5]) return P -def plot3d_adaptive(f, x_range, y_range, color='automatic', - grad_f=None, - max_bend=.5, max_depth=5, initial_depth=4, num_colors=128, **kwds): +def plot3d_adaptive(f, x_range, y_range, color='automatic', grad_f=None, max_bend=0.5, max_depth=5, initial_depth=4, num_colors=128, **kwds): r""" Adaptive 3d plotting of a function of two variables. @@ -1172,6 +1156,7 @@ def plot3d_adaptive(f, x_range, y_range, color='automatic', max_depth = max(max_depth, initial_depth) from sage.plot.misc import setup_for_eval_on_grid + g, ranges = setup_for_eval_on_grid(f, [x_range, y_range], plot_points=2) xmin, xmax = ranges[0][:2] ymin, ymax = ranges[1][:2] @@ -1188,9 +1173,7 @@ def plot3d_adaptive(f, x_range, y_range, color='automatic', texture = Texture(kwds) factory = TrivialTriangleFactory() - plot = TrianglePlot(factory, g, (xmin, xmax), (ymin, ymax), g=grad_f, - min_depth=initial_depth, max_depth=max_depth, - max_bend=max_bend, num_colors=None) + plot = TrianglePlot(factory, g, (xmin, xmax), (ymin, ymax), g=grad_f, min_depth=initial_depth, max_depth=max_depth, max_bend=max_bend, num_colors=None) P = IndexFaceSet(plot._objects) if isinstance(texture, (list, tuple)): @@ -1434,6 +1417,4 @@ def axes(scale=1, radius=None, **kwds): """ if radius is None: radius = scale / 100.0 - return Graphics3dGroup([arrow3d((0, 0, 0), (scale, 0, 0), radius, **kwds), - arrow3d((0, 0, 0), (0, scale, 0), radius, **kwds), - arrow3d((0, 0, 0), (0, 0, scale), radius, **kwds)]) + return Graphics3dGroup([arrow3d((0, 0, 0), (scale, 0, 0), radius, **kwds), arrow3d((0, 0, 0), (0, scale, 0), radius, **kwds), arrow3d((0, 0, 0), (0, 0, scale), radius, **kwds)]) diff --git a/src/sage/plot/plot3d/plot_field3d.py b/src/sage/plot/plot3d/plot_field3d.py index b51087d5a65..29b3103bb60 100644 --- a/src/sage/plot/plot3d/plot_field3d.py +++ b/src/sage/plot/plot3d/plot_field3d.py @@ -23,8 +23,7 @@ from sage.plot.plot import plot -def plot_vector_field3d(functions, xrange, yrange, zrange, - plot_points=5, colors='jet', center_arrows=False, **kwds): +def plot_vector_field3d(functions, xrange, yrange, zrange, plot_points=5, colors='jet', center_arrows=False, **kwds): r""" Plot a 3d vector field. @@ -135,14 +134,17 @@ def plot_vector_field3d(functions, xrange, yrange, zrange, try: import matplotlib as mpl + cm = mpl.colormaps[colors] except (TypeError, KeyError): cm = None if cm is None: if isinstance(colors, (list, tuple)): from matplotlib.colors import LinearSegmentedColormap + cm = LinearSegmentedColormap.from_list('mymap', colors) else: + def cm(x): return colors @@ -150,11 +152,9 @@ def cm(x): scaled_vectors = [v / max_len for v in vectors] if center_arrows: - G = sum(plot(v, color=cm(v.norm()), **kwds).translate(p - v / 2) - for v, p in zip(scaled_vectors, points)) + G = sum(plot(v, color=cm(v.norm()), **kwds).translate(p - v / 2) for v, p in zip(scaled_vectors, points)) G._set_extra_kwds(kwds) return G - G = sum(plot(v, color=cm(v.norm()), **kwds).translate(p) - for v, p in zip(scaled_vectors, points)) + G = sum(plot(v, color=cm(v.norm()), **kwds).translate(p) for v, p in zip(scaled_vectors, points)) G._set_extra_kwds(kwds) return G diff --git a/src/sage/plot/plot3d/revolution_plot3d.py b/src/sage/plot/plot3d/revolution_plot3d.py index a98f2ddcc32..817f3b8945f 100644 --- a/src/sage/plot/plot3d/revolution_plot3d.py +++ b/src/sage/plot/plot3d/revolution_plot3d.py @@ -278,31 +278,30 @@ def cf(u, phi): return float(2 * u / pi) % 1 # (0,0) must be handled separately for the phase value if x0 != 0 or y0 != 0: phase = atan2(y - y0, x - x0) - R = sqrt((x-x0)**2 + (y-y0)**2) - v = (R*cos(phi+phase)+x0, R*sin(phi+phase)+y0, z) + R = sqrt((x - x0) ** 2 + (y - y0) ** 2) + v = (R * cos(phi + phase) + x0, R * sin(phi + phase) + y0, z) elif parallel_axis == 'x': y0 = axis[0] z0 = axis[1] # (0,0) must be handled separately for the phase value if z0 != 0 or y0 != 0: phase = atan2(z - z0, y - y0) - R = sqrt((y-y0)**2 + (z-z0)**2) - v = (x, R*cos(phi+phase)+y0, R*sin(phi+phase)+z0) + R = sqrt((y - y0) ** 2 + (z - z0) ** 2) + v = (x, R * cos(phi + phase) + y0, R * sin(phi + phase) + z0) elif parallel_axis == 'y': x0 = axis[0] z0 = axis[1] # (0,0) must be handled separately for the phase value if z0 != 0 or x0 != 0: phase = atan2(z - z0, x - x0) - R = sqrt((x-x0)**2 + (z-z0)**2) - v = (R*cos(phi+phase)+x0, y, R*sin(phi+phase)+z0) + R = sqrt((x - x0) ** 2 + (z - z0) ** 2) + v = (R * cos(phi + phase) + x0, y, R * sin(phi + phase) + z0) if print_vector: print(v) if show_curve: - curveplot = parametric_plot3d((x, y, z), trange, thickness=2, - rgbcolor=(1, 0, 0)) + curveplot = parametric_plot3d((x, y, z), trange, thickness=2, rgbcolor=(1, 0, 0)) return parametric_plot3d(v, trange, phirange, **kwds) + curveplot return parametric_plot3d(v, trange, phirange, **kwds) diff --git a/src/sage/plot/plot3d/shapes2.py b/src/sage/plot/plot3d/shapes2.py index 3344df322b5..9a139747703 100644 --- a/src/sage/plot/plot3d/shapes2.py +++ b/src/sage/plot/plot3d/shapes2.py @@ -7,6 +7,7 @@ - William Stein and Robert Bradshaw (2008-01): Many improvements """ + # **************************************************************************** # Copyright (C) 2007 William Stein # Copyright (C) 2008 Robert Bradshaw @@ -183,8 +184,8 @@ def tetra(col): else: texture = Texture(kwds) for i in range(len(points) - 1): - line = shapes.arrow3d if i == len(points)-2 and arrow_head else shapes.LineSegment - v.append(line(points[i], points[i+1], texture=texture, radius=radius, **kwds)) + line = shapes.arrow3d if i == len(points) - 2 and arrow_head else shapes.LineSegment + v.append(line(points[i], points[i + 1], texture=texture, radius=radius, **kwds)) w = sum(v) w._set_extra_kwds(kwds) return w @@ -289,7 +290,7 @@ def bezier3d(path, **options): p0 = vector(path[0][-1]) t = SR.var('t') if len(path[0]) > 2: - B = (1-t)**3*vector(path[0][0])+3*t*(1-t)**2*vector(path[0][1])+3*t**2*(1-t)*vector(path[0][-2])+t**3*p0 + B = (1 - t) ** 3 * vector(path[0][0]) + 3 * t * (1 - t) ** 2 * vector(path[0][1]) + 3 * t**2 * (1 - t) * vector(path[0][-2]) + t**3 * p0 G = P3D.parametric_plot3d(list(B), (0, 1), color=options['color'], aspect_ratio=options['aspect_ratio'], thickness=options['thickness'], opacity=options['opacity']) else: G = line3d([path[0][0], p0], color=options['color'], thickness=options['thickness'], opacity=options['opacity']) @@ -299,7 +300,7 @@ def bezier3d(path, **options): p1 = vector(curve[0]) p2 = vector(curve[-2]) p3 = vector(curve[-1]) - B = (1-t)**3*p0+3*t*(1-t)**2*p1+3*t**2*(1-t)*p2+t**3*p3 + B = (1 - t) ** 3 * p0 + 3 * t * (1 - t) ** 2 * p1 + 3 * t**2 * (1 - t) * p2 + t**3 * p3 G += P3D.parametric_plot3d(list(B), (0, 1), color=options['color'], aspect_ratio=options['aspect_ratio'], thickness=options['thickness'], opacity=options['opacity']) else: G += line3d([p0, curve[0]], color=options['color'], thickness=options['thickness'], opacity=options['opacity']) @@ -366,6 +367,7 @@ def polygon3d(points, **options): sphinx_plot(polygon3d([[1, 2, 3], [0,1,0], [1,0,1], [3,0,0]], color=(0,1,0), alpha=0.7)) """ from sage.plot.plot3d.index_face_set import IndexFaceSet + return IndexFaceSet([range(len(points))], points, **options) @@ -400,6 +402,7 @@ def polygons3d(faces, points, **options): sphinx_plot(polygons3d(f, v, color='red')) """ from sage.plot.plot3d.index_face_set import IndexFaceSet + return IndexFaceSet(faces, points, **options) @@ -434,11 +437,7 @@ def frame3d(lower_left, upper_right, **kwds): """ x0, y0, z0 = lower_left x1, y1, z1 = upper_right - L1 = line3d([(x0, y0, z0), (x0, y1, z0), (x1, y1, z0), - (x1, y0, z0), (x0, y0, z0), # top square - (x0, y0, z1), (x0, y1, z1), (x1, y1, z1), - (x1, y0, z1), (x0, y0, z1)], # bottom square - **kwds) + L1 = line3d([(x0, y0, z0), (x0, y1, z0), (x1, y1, z0), (x1, y0, z0), (x0, y0, z0), (x0, y0, z1), (x0, y1, z1), (x1, y1, z1), (x1, y0, z1), (x0, y0, z1)], **kwds) # top square # bottom square # 3 additional lines joining top to bottom v2 = line3d([(x0, y1, z0), (x0, y1, z1)], **kwds) v3 = line3d([(x1, y0, z0), (x1, y0, z1)], **kwds) @@ -448,9 +447,7 @@ def frame3d(lower_left, upper_right, **kwds): return F -def frame_labels(lower_left, upper_right, - label_lower_left, label_upper_right, eps=1, - **kwds): +def frame_labels(lower_left, upper_right, label_lower_left, label_upper_right, eps=1, **kwds): """ Draw correct labels for a given frame in 3-D. @@ -507,11 +504,11 @@ def frame_labels(lower_left, upper_right, lx0, ly0, lz0 = label_lower_left lx1, ly1, lz1 = label_upper_right if (lx1 - lx0) <= 0 or (ly1 - ly0) <= 0 or (lz1 - lz0) <= 0: - raise ValueError("ensure the upper right labels are above " - "and to the right of the lower left labels") + raise ValueError("ensure the upper right labels are above " "and to the right of the lower left labels") # Helper function for formatting the frame labels from math import log + log10 = log(10) def nd(a): @@ -521,7 +518,7 @@ def fmt_string(a): b = a / 2.0 if b >= 1: return "%.1f" - n = max(0, 2 - nd(a/2.0)) + n = max(0, 2 - nd(a / 2.0)) return "%%.%sf" % n # Slightly faster than mean for this situation @@ -531,19 +528,19 @@ def avg(a, b): color = (0.3, 0.3, 0.3) fmt = fmt_string(lx1 - lx0) - T = Text(fmt % lx0, color=color).translate((x0, y0-eps, z0)) - T += Text(fmt % avg(lx0, lx1), color=color).translate((avg(x0, x1), y0-eps, z0)) - T += Text(fmt % lx1, color=color).translate((x1, y0-eps, z0)) + T = Text(fmt % lx0, color=color).translate((x0, y0 - eps, z0)) + T += Text(fmt % avg(lx0, lx1), color=color).translate((avg(x0, x1), y0 - eps, z0)) + T += Text(fmt % lx1, color=color).translate((x1, y0 - eps, z0)) fmt = fmt_string(ly1 - ly0) - T += Text(fmt % ly0, color=color).translate((x1+eps, y0, z0)) - T += Text(fmt % avg(ly0, ly1), color=color).translate((x1+eps, avg(y0, y1), z0)) - T += Text(fmt % ly1, color=color).translate((x1+eps, y1, z0)) + T += Text(fmt % ly0, color=color).translate((x1 + eps, y0, z0)) + T += Text(fmt % avg(ly0, ly1), color=color).translate((x1 + eps, avg(y0, y1), z0)) + T += Text(fmt % ly1, color=color).translate((x1 + eps, y1, z0)) fmt = fmt_string(lz1 - lz0) - T += Text(fmt % lz0, color=color).translate((x0-eps, y0, z0)) - T += Text(fmt % avg(lz0, lz1), color=color).translate((x0-eps, y0, avg(z0, z1))) - T += Text(fmt % lz1, color=color).translate((x0-eps, y0, z1)) + T += Text(fmt % lz0, color=color).translate((x0 - eps, y0, z0)) + T += Text(fmt % avg(lz0, lz1), color=color).translate((x0 - eps, y0, avg(z0, z1))) + T += Text(fmt % lz1, color=color).translate((x0 - eps, y0, z1)) return T @@ -629,27 +626,27 @@ def ruler(start, end, ticks=4, sub_ticks=4, absolute=False, snap=False, **kwds): dist = math.sqrt(dir.dot_product(dir)) dir /= dist - one_tick = dist/ticks * 1.414 - unit = 10 ** math.floor(math.log(dist/ticks, 10)) + one_tick = dist / ticks * 1.414 + unit = 10 ** math.floor(math.log(dist / ticks, 10)) if unit * 5 < one_tick: unit *= 5 elif unit * 2 < one_tick: unit *= 2 if dir[0]: - tick = dir.cross_product(vector(RDF, (0, 0, -dist/30))) + tick = dir.cross_product(vector(RDF, (0, 0, -dist / 30))) elif dir[1]: - tick = dir.cross_product(vector(RDF, (0, 0, dist/30))) + tick = dir.cross_product(vector(RDF, (0, 0, dist / 30))) else: - tick = vector(RDF, (dist/30, 0, 0)) + tick = vector(RDF, (dist / 30, 0, 0)) if snap: for i in range(3): - start[i] = unit * math.floor(start[i]/unit + 1e-5) - end[i] = unit * math.ceil(end[i]/unit - 1e-5) + start[i] = unit * math.floor(start[i] / unit + 1e-5) + end[i] = unit * math.ceil(end[i] / unit - 1e-5) if absolute: - if dir[0]*dir[1] or dir[1]*dir[2] or dir[0]*dir[2]: + if dir[0] * dir[1] or dir[1] * dir[2] or dir[0] * dir[2]: raise ValueError("absolute rulers only valid for axis-aligned paths") m = max(dir[0], dir[1], dir[2]) if dir[0] == m: @@ -658,24 +655,24 @@ def ruler(start, end, ticks=4, sub_ticks=4, absolute=False, snap=False, **kwds): off = start[1] else: off = start[2] - first_tick = unit * math.ceil(off/unit - 1e-5) - off + first_tick = unit * math.ceil(off / unit - 1e-5) - off else: off = 0 first_tick = 0 ruler = shapes.LineSegment(start, end, **kwds) - for k in range(1, int(sub_ticks * first_tick/unit)): - P = start + dir*(k*unit/sub_ticks) - ruler += shapes.LineSegment(P, P + tick/2, **kwds) - for d in srange(first_tick, dist + unit/(sub_ticks+1), unit): - P = start + dir*d + for k in range(1, int(sub_ticks * first_tick / unit)): + P = start + dir * (k * unit / sub_ticks) + ruler += shapes.LineSegment(P, P + tick / 2, **kwds) + for d in srange(first_tick, dist + unit / (sub_ticks + 1), unit): + P = start + dir * d ruler += shapes.LineSegment(P, P + tick, **kwds) - ruler += shapes.Text(str(d+off), **kwds).translate(P - tick) + ruler += shapes.Text(str(d + off), **kwds).translate(P - tick) if dist - d < unit: - sub_ticks = int(sub_ticks * (dist - d)/unit) + sub_ticks = int(sub_ticks * (dist - d) / unit) for k in range(1, sub_ticks): - P += dir * (unit/sub_ticks) - ruler += shapes.LineSegment(P, P + tick/2, **kwds) + P += dir * (unit / sub_ticks) + ruler += shapes.LineSegment(P, P + tick / 2, **kwds) return ruler @@ -720,13 +717,12 @@ def ruler_frame(lower_left, upper_right, ticks=4, sub_ticks=4, **kwds): from sage.plot.plot3d.shapes2 import ruler_frame sphinx_plot(ruler_frame([1,2,3],vector([2,3,4]),ticks=6, sub_ticks=2, color='red')) """ - return ruler(lower_left, (upper_right[0], lower_left[1], lower_left[2]), ticks=ticks, sub_ticks=sub_ticks, absolute=True, **kwds) \ - + ruler(lower_left, (lower_left[0], upper_right[1], lower_left[2]), ticks=ticks, sub_ticks=sub_ticks, absolute=True, **kwds) \ - + ruler(lower_left, (lower_left[0], lower_left[1], upper_right[2]), ticks=ticks, sub_ticks=sub_ticks, absolute=True, **kwds) + return ruler(lower_left, (upper_right[0], lower_left[1], lower_left[2]), ticks=ticks, sub_ticks=sub_ticks, absolute=True, **kwds) + ruler(lower_left, (lower_left[0], upper_right[1], lower_left[2]), ticks=ticks, sub_ticks=sub_ticks, absolute=True, **kwds) + ruler(lower_left, (lower_left[0], lower_left[1], upper_right[2]), ticks=ticks, sub_ticks=sub_ticks, absolute=True, **kwds) ########################### + @rename_keyword(alpha='opacity') def sphere(center=(0, 0, 0), size=1, **kwds): r""" @@ -889,6 +885,7 @@ class Point(PrimitiveObject): sage: point3d((4,3,2),size=2,color='red',opacity=.5) Graphics3d Object """ + def __init__(self, center, size=1, **kwds): """ Create the graphics primitive :class:`Point` in 3-D. @@ -941,8 +938,7 @@ def tachyon_repr(self, render_params): radius = self.size * TACHYON_PIXEL texture = self.texture.id - return (f"Sphere center {cen[0]!r} {cen[1]!r} {cen[2]!r} " - f"Rad {radius!r} {texture}") + return f"Sphere center {cen[0]!r} {cen[1]!r} {cen[2]!r} " f"Rad {radius!r} {texture}" def obj_repr(self, render_params): """ @@ -957,6 +953,7 @@ def obj_repr(self, render_params): T = render_params.transform if T is None: from . import transform + T = transform.Transformation() render_params.push_transform(~T) S = shapes.Sphere(self.size / 200.0).translate(T(self.loc)) @@ -1071,8 +1068,8 @@ class Line(PrimitiveObject): ....: for i in range(N+1)) Graphics3d Object """ - def __init__(self, points, thickness=5, corner_cutoff=0.5, - arrow_head=False, **kwds): + + def __init__(self, points, thickness=5, corner_cutoff=0.5, arrow_head=False, **kwds): """ Create the graphics primitive :class:`Line` in 3-D. @@ -1139,11 +1136,7 @@ def tachyon_repr(self, render_params): cmds.append(A.tachyon_repr(render_params)) render_params.pop_transform() else: - cmd = ('FCylinder base {pos[0]!r} {pos[1]!r} {pos[2]!r} ' - 'apex {apex[0]!r} {apex[1]!r} {apex[2]!r} ' - 'rad {radius!r} {texture}').format( - pos=(px, py, pz), apex=(x, y, z), radius=radius, - texture=self.texture.id) + cmd = ('FCylinder base {pos[0]!r} {pos[1]!r} {pos[2]!r} ' 'apex {apex[0]!r} {apex[1]!r} {apex[2]!r} ' 'rad {radius!r} {texture}').format(pos=(px, py, pz), apex=(x, y, z), radius=radius, texture=self.texture.id) cmds.append(cmd) px, py, pz = x, y, z return cmds @@ -1165,6 +1158,7 @@ def obj_repr(self, render_params): T = render_params.transform if T is None: from . import transform + T = transform.Transformation() render_params.push_transform(~T) L = line3d([T(P) for P in self.points], radius=self.thickness / 200.0, arrow_head=self.arrow_head, texture=self.texture) @@ -1265,7 +1259,7 @@ def corners(self, corner_cutoff=None, max_len=None): # no corners if max_len is not None: # forced by the maximal number of consecutive smooth points - return self.points[:-1][::max_len - 1] + return self.points[:-1][:: max_len - 1] return [self.points[0]] if max_len is None: @@ -1291,9 +1285,7 @@ def dot(x0_y0_z0, x1_y1_z1): count = 1 continue next_dir = [next[i] - cur[i] for i in range(3)] - cos_angle = (dot(prev_dir, next_dir) / - math.sqrt(dot(prev_dir, prev_dir) * - dot(next_dir, next_dir))) + cos_angle = dot(prev_dir, next_dir) / math.sqrt(dot(prev_dir, prev_dir) * dot(next_dir, next_dir)) if cos_angle <= corner_cutoff or count > max_len - 1: corners.append(cur) count = 1 @@ -1378,8 +1370,7 @@ def threejs_repr(self, render_params): thickness = float(self.thickness) if self.arrow_head: width = thickness / 2.0 - arrow = shapes.arrow3d(start=points[-2], end=points[-1], width=width, - color=color, opacity=opacity) + arrow = shapes.arrow3d(start=points[-2], end=points[-1], width=width, color=color, opacity=opacity) reprs += arrow.threejs_repr(render_params) points = points[:-1] # The arrow replaces the last line segment. if len(points) > 1: @@ -1491,6 +1482,7 @@ def point3d(v, size=5, **kwds): if l == 0: from sage.plot.plot3d.base import Graphics3d + return Graphics3d() if l == 3: diff --git a/src/sage/plot/plot3d/tachyon.py b/src/sage/plot/plot3d/tachyon.py index 77fa0b53d1d..10d3af97a6a 100644 --- a/src/sage/plot/plot3d/tachyon.py +++ b/src/sage/plot/plot3d/tachyon.py @@ -158,6 +158,7 @@ - clean up trianglefactory stuff """ + from .tri_plot import Triangle, SmoothTriangle, TriangleFactory, TrianglePlot from sage.interfaces.tachyon import tachyon_rt @@ -365,21 +366,8 @@ class Tachyon(WithEqualityById, SageObject): sage: hash(Tachyon()) # random 140658972348064 """ - def __init__(self, - xres=350, yres=350, - zoom=1.0, - antialiasing=False, - aspectratio=1.0, - raydepth=8, - camera_position=None, # default value (-3, 0, 0), - camera_center=None, # alternative equivalent name - updir=[0, 0, 1], - look_at=[0, 0, 0], - viewdir=None, - projection='PERSPECTIVE', - focallength='', - aperture='', - frustum=''): + + def __init__(self, xres=350, yres=350, zoom=1.0, antialiasing=False, aspectratio=1.0, raydepth=8, camera_position=None, camera_center=None, updir=[0, 0, 1], look_at=[0, 0, 0], viewdir=None, projection='PERSPECTIVE', focallength='', aperture='', frustum=''): # default value (-3, 0, 0), # alternative equivalent name r""" Create an instance of the Tachyon class. @@ -409,8 +397,7 @@ def __init__(self, self._objects = [] if viewdir is None: if look_at != self._camera_position: - self._viewdir = [look_at[i] - self._camera_position[i] - for i in range(3)] + self._viewdir = [look_at[i] - self._camera_position[i] for i in range(3)] else: raise ValueError('camera_position and look_at coincide') else: @@ -529,6 +516,7 @@ def _rich_repr_(self, display_manager, **kwds): filename = tmp_filename(ext='.png') self.save(filename, **kwds) from sage.repl.rich_output.buffer import OutputBuffer + buf = OutputBuffer.from_file(filename) return OutputImagePng(buf) @@ -615,6 +603,7 @@ def show(self, **kwds): ... """ from sage.repl.rich_output import get_display_manager + dm = get_display_manager() dm.display_immediately(self, **kwds) @@ -644,14 +633,26 @@ def _camera(self): """ camera_out = r""" camera - projection %s""" % (tostr(self._projection)) + projection %s""" % ( + tostr(self._projection) + ) if self._focallength != '': - camera_out = camera_out + r""" - focallength %s""" % (float(self._focallength)) + camera_out = ( + camera_out + + r""" + focallength %s""" + % (float(self._focallength)) + ) if self._aperture != '': - camera_out = camera_out + r""" - aperture %s""" % (float(self._aperture)) - camera_out = camera_out + fr""" + camera_out = ( + camera_out + + r""" + aperture %s""" + % (float(self._aperture)) + ) + camera_out = ( + camera_out + + fr""" zoom {float(self._zoom)} aspectratio {float(self._aspectratio)} antialiasing {int(self._antialiasing)} @@ -659,11 +660,19 @@ def _camera(self): center {tostr(self._camera_position)} viewdir {tostr(self._viewdir)} updir {tostr(self._updir)}""" + ) if self._frustum != '': - camera_out = camera_out + r""" - frustum %s""" % (tostr(self._frustum)) - camera_out = camera_out + r""" + camera_out = ( + camera_out + + r""" + frustum %s""" + % (tostr(self._frustum)) + ) + camera_out = ( + camera_out + + r""" end_camera""" + ) return camera_out def str(self): @@ -688,9 +697,9 @@ def str(self): {} {} {} - end_scene""".format(self._res(), - self._camera(), - '\n'.join(x.str() for x in self._objects)) + end_scene""".format( + self._res(), self._camera(), '\n'.join(x.str() for x in self._objects) + ) def light(self, center, radius, color): r""" @@ -705,9 +714,7 @@ def light(self, center, radius, color): """ self._objects.append(Light(center, radius, color)) - def texfunc(self, type=0, center=(0, 0, 0), rotate=(0, 0, 0), - scale=(1, 1, 1), - imagefile=''): + def texfunc(self, type=0, center=(0, 0, 0), rotate=(0, 0, 0), scale=(1, 1, 1), imagefile=''): r""" INPUT: @@ -741,10 +748,7 @@ def texfunc(self, type=0, center=(0, 0, 0), rotate=(0, 0, 0), raise ValueError("type must be an integer between 0 and 9") return Texfunc(type, center, rotate, scale, imagefile=imagefile).str() - def texture(self, name, ambient=0.2, diffuse=0.8, - specular=0.0, opacity=1.0, - color=(1.0, 0.0, 0.5), texfunc=0, phong=0, phongsize=.5, - phongtype='PLASTIC', imagefile=''): + def texture(self, name, ambient=0.2, diffuse=0.8, specular=0.0, opacity=1.0, color=(1.0, 0.0, 0.5), texfunc=0, phong=0, phongsize=0.5, phongtype='PLASTIC', imagefile=''): r""" INPUT: @@ -790,10 +794,7 @@ def texture(self, name, ambient=0.2, diffuse=0.8, """ if texfunc and not isinstance(texfunc, Texfunc): texfunc = self.texfunc(int(texfunc), imagefile=imagefile) - self._objects.append(Texture(name, ambient, diffuse, - specular, opacity, color, texfunc, - phong, phongsize, phongtype, - imagefile=imagefile)) + self._objects.append(Texture(name, ambient, diffuse, specular, opacity, color, texfunc, phong, phongsize, phongtype, imagefile=imagefile)) def texture_recolor(self, name, colors): r""" @@ -925,8 +926,7 @@ def triangle(self, vertex_1, vertex_2, vertex_3, texture): sage: t._objects[1].get_vertices() ([1, 2, 3], [4, 5, 6], [7, 8, 10]) """ - self._objects.append(TachyonTriangle(vertex_1, vertex_2, vertex_3, - texture)) + self._objects.append(TachyonTriangle(vertex_1, vertex_2, vertex_3, texture)) def smooth_triangle(self, vertex_1, vertex_2, vertex_3, normal_1, normal_2, normal_3, texture): r""" @@ -961,8 +961,7 @@ def fractal_landscape(self, res, scale, center, texture): """ self._objects.append(FractalLandscape(res, scale, center, texture)) - def plot(self, f, xmin_xmax, ymin_ymax, texture, grad_f=None, - max_bend=.7, max_depth=5, initial_depth=3, num_colors=None): + def plot(self, f, xmin_xmax, ymin_ymax, texture, grad_f=None, max_bend=0.7, max_depth=5, initial_depth=3, num_colors=None): r""" INPUT: @@ -1047,13 +1046,10 @@ def plot(self, f, xmin_xmax, ymin_ymax, texture, grad_f=None, (xmin, xmax) = xmin_xmax (ymin, ymax) = ymin_ymax factory = TachyonTriangleFactory(self, texture) - plot = TrianglePlot(factory, f, (xmin, xmax), (ymin, ymax), g=grad_f, - min_depth=initial_depth, max_depth=max_depth, - max_bend=max_bend, num_colors=num_colors) + plot = TrianglePlot(factory, f, (xmin, xmax), (ymin, ymax), g=grad_f, min_depth=initial_depth, max_depth=max_depth, max_bend=max_bend, num_colors=num_colors) self._objects.append(plot) - def parametric_plot(self, f, t_0, t_f, tex, r=.1, cylinders=True, - min_depth=4, max_depth=8, e_rel=.01, e_abs=.01): + def parametric_plot(self, f, t_0, t_f, tex, r=0.1, cylinders=True, min_depth=4, max_depth=8, e_rel=0.01, e_abs=0.01): r""" Plot a space curve as a series of spheres and finite cylinders. @@ -1069,10 +1065,7 @@ def parametric_plot(self, f, t_0, t_f, tex, r=.1, cylinders=True, Scene contains 482 objects. ... """ - self._objects.append( - ParametricPlot(f, t_0, t_f, tex, r=r, cylinders=cylinders, - min_depth=min_depth, max_depth=max_depth, - e_rel=.01, e_abs=.01)) + self._objects.append(ParametricPlot(f, t_0, t_f, tex, r=r, cylinders=cylinders, min_depth=min_depth, max_depth=max_depth, e_rel=0.01, e_abs=0.01)) class Light: @@ -1086,6 +1079,7 @@ class Light: sage: q._center (1.0, 1.0, 1.0) """ + def __init__(self, center, radius, color): r""" Store the center, radius and color. @@ -1125,8 +1119,7 @@ def str(self): class Texfunc: - def __init__(self, ttype=0, center=(0, 0, 0), rotate=(0, 0, 0), - scale=(1, 1, 1), imagefile=''): + def __init__(self, ttype=0, center=(0, 0, 0), rotate=(0, 0, 0), scale=(1, 1, 1), imagefile=''): r""" Create a texture function. @@ -1160,18 +1153,9 @@ def str(self): if self._ttype == 0: return "0" if self._ttype < 7 and self._ttype > 0: - return r"""%d center %s rotate %s scale %s""" % ( - self._ttype, - tostr(self._center), - tostr(self._rotate), - tostr(self._scale)) + return r"""%d center %s rotate %s scale %s""" % (self._ttype, tostr(self._center), tostr(self._rotate), tostr(self._scale)) if self._ttype < 9: - return r"""%d %s center %s rotate %s scale %s""" % ( - self._ttype, - self._imagefile, - tostr(self._center), - tostr(self._rotate), - tostr(self._scale)) + return r"""%d %s center %s rotate %s scale %s""" % (self._ttype, self._imagefile, tostr(self._center), tostr(self._rotate), tostr(self._scale)) if self._ttype == 9: return r"""%d %s center %s rotate %s scale %s uaxis 1.0 0.0 0.0 @@ -1180,16 +1164,14 @@ def str(self): self._imagefile, tostr(self._center), tostr(self._rotate), - tostr(self._scale)) + tostr(self._scale), + ) raise ValueError class Texture: - def __init__(self, name, ambient=0.2, diffuse=0.8, - specular=0.0, opacity=1.0, - color=(1.0, 0.0, 0.5), texfunc=0, - phong=0, phongsize=0, phongtype='PLASTIC', imagefile=''): + def __init__(self, name, ambient=0.2, diffuse=0.8, specular=0.0, opacity=1.0, color=(1.0, 0.0, 0.5), texfunc=0, phong=0, phongsize=0, phongtype='PLASTIC', imagefile=''): r""" Store texture information. @@ -1227,10 +1209,7 @@ def recolor(self, name, color): sage: t2ws[color_index:color_index+20] 'color 0.1 0.2 0.3 ' """ - return Texture(name, self._ambient, self._diffuse, self._specular, - self._opacity, - color, self._texfunc, self._phong, self._phongsize, - self._phongtype, self._imagefile) + return Texture(name, self._ambient, self._diffuse, self._specular, self._opacity, color, self._texfunc, self._phong, self._phongsize, self._phongtype, self._imagefile) def str(self): r""" @@ -1247,22 +1226,16 @@ def str(self): texdef {} ambient {} diffuse {} specular {} opacity {} phong {} {} phong_size {} color {} texfunc {} - """.format(self._name, - self._ambient, - self._diffuse, - self._specular, - self._opacity, - self._phongtype, - self._phong, - self._phongsize, - tostr(self._color), - self._texfunc) + """.format( + self._name, self._ambient, self._diffuse, self._specular, self._opacity, self._phongtype, self._phong, self._phongsize, tostr(self._color), self._texfunc + ) class Sphere: r""" A class for creating spheres in tachyon. """ + def __init__(self, center, radius, texture): r""" Store the center, radius, and texture information in a class. @@ -1303,6 +1276,7 @@ class Ring: r""" An annulus of zero thickness. """ + def __init__(self, center, normal, inner, outer, texture): r""" Create a ring with the given center, normal, inner radius, @@ -1336,8 +1310,9 @@ def str(self): """ return r""" ring center {} normal {} inner {} outer {} {} - """.format(tostr(self._center), tostr(self._normal), - self._inner, self._outer, self._texture) + """.format( + tostr(self._center), tostr(self._normal), self._inner, self._outer, self._texture + ) class FractalLandscape: @@ -1346,6 +1321,7 @@ class FractalLandscape: Does not seem very useful at the moment, but perhaps will be improved in the future. """ + def __init__(self, res, scale, center, texture): r""" Create a fractal landscape in tachyon. @@ -1378,14 +1354,16 @@ def str(self): """ return r""" scape res {} scale {} center {} {} - """.format(tostr(self._res, 2, int), tostr(self._scale, 2, int), - tostr(self._center), self._texture) + """.format( + tostr(self._res, 2, int), tostr(self._scale, 2, int), tostr(self._center), self._texture + ) class Cylinder: r""" An infinite cylinder. """ + def __init__(self, center, axis, radius, texture): r""" Create a cylinder with the given parameters. @@ -1419,13 +1397,16 @@ def str(self): """ return r""" cylinder center {} axis {} rad {} {} - """.format(tostr(self._center), tostr(self._axis), self._radius, self._texture) + """.format( + tostr(self._center), tostr(self._axis), self._radius, self._texture + ) class Plane: r""" An infinite plane. """ + def __init__(self, center, normal, texture): r""" Create the plane object. @@ -1463,6 +1444,7 @@ class FCylinder: r""" A finite cylinder. """ + def __init__(self, base, apex, radius, texture): r""" Create a finite cylinder object. @@ -1494,13 +1476,16 @@ def str(self): """ return r""" fcylinder base {} apex {} rad {} {} - """.format(tostr(self._center), tostr(self._axis), self._radius, self._texture) + """.format( + tostr(self._center), tostr(self._axis), self._radius, self._texture + ) class Axis_aligned_box: r""" Box with axis-aligned edges with the given min and max coordinates. """ + def __init__(self, min_p, max_p, texture): r""" Create the axis-aligned box object. @@ -1538,6 +1523,7 @@ class TachyonTriangle(Triangle): r""" Basic triangle class. """ + def str(self): r""" Return the scene string for a triangle. @@ -1559,6 +1545,7 @@ class TachyonSmoothTriangle(SmoothTriangle): r""" A triangle along with a normal vector, which is used for smoothing. """ + def str(self): r""" Return the scene string for a smoothed triangle. @@ -1581,6 +1568,7 @@ class TachyonTriangleFactory(TriangleFactory): r""" A class to produce triangles of various rendering types. """ + def __init__(self, tach, tex): r""" Initialize with tachyon instance and texture. @@ -1653,6 +1641,7 @@ class ParametricPlot: r""" Parametric plotting routines. """ + def str(self): r""" Return the tachyon string representation of the parameterized curve. @@ -1667,8 +1656,7 @@ def str(self): """ return "".join(o.str() for o in self._objects) - def __init__(self, f, t_0, t_f, tex, r=.1, cylinders=True, - min_depth=4, max_depth=8, e_rel=.01, e_abs=.01): + def __init__(self, f, t_0, t_f, tex, r=0.1, cylinders=True, min_depth=4, max_depth=8, e_rel=0.01, e_abs=0.01): r""" Create the parametric plotting class. @@ -1743,7 +1731,7 @@ def tol(self, est, val): True """ a, b, c = val - delta = sqrt((a - est[0])**2 + (b - est[1])**2 + (c - est[2])**2) + delta = sqrt((a - est[0]) ** 2 + (b - est[1]) ** 2 + (c - est[2]) ** 2) if delta < self._e_abs: return True diff --git a/src/sage/plot/plot3d/texture.py b/src/sage/plot/plot3d/texture.py index 6d60dc524a6..dad99eea86a 100644 --- a/src/sage/plot/plot3d/texture.py +++ b/src/sage/plot/plot3d/texture.py @@ -32,6 +32,7 @@ - Robert Bradshaw (2007-07-07) Initial version. """ + from textwrap import dedent from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall @@ -156,6 +157,7 @@ class Texture(WithEqualityById, SageObject, metaclass=ClasscallMetaclass): sage: hash(Texture()) # random 42 """ + @staticmethod def __classcall__(cls, id=None, **kwds): r""" @@ -258,8 +260,7 @@ def __classcall__(cls, id=None, **kwds): id = _new_global_texture_id() return typecall(cls, id, **kwds) - def __init__(self, id, color=(.4, .4, 1), opacity=1, ambient=0.5, - diffuse=1, specular=0, shininess=1, name=None, **kwds) -> None: + def __init__(self, id, color=(0.4, 0.4, 1), opacity=1, ambient=0.5, diffuse=1, specular=0, shininess=1, name=None, **kwds) -> None: r""" Construction of a texture. @@ -283,8 +284,7 @@ def __init__(self, id, color=(.4, .4, 1), opacity=1, ambient=0.5, else: if len(color) == 4: opacity = color[3] - color = tuple(float(1) if c == 1 else float(c) % 1 - for c in color[0: 3]) + color = tuple(float(1) if c == 1 else float(c) % 1 for c in color[0:3]) self.color = color self.opacity = float(opacity) @@ -355,13 +355,13 @@ def tachyon_str(self) -> str: diffuse = total_diffuse / total_color specular = total_specular / total_color - return dedent("""\ + return dedent( + """\ Texdef {id} Ambient {ambient!r} Diffuse {diffuse!r} Specular {specular!r} Opacity {opacity!r} Color {color[0]!r} {color[1]!r} {color[2]!r} - TexFunc 0""").format(id=self.id, ambient=ambient, - diffuse=diffuse, specular=specular, - opacity=self.opacity, color=self.color) + TexFunc 0""" + ).format(id=self.id, ambient=ambient, diffuse=diffuse, specular=specular, opacity=self.opacity, color=self.color) def x3d_str(self) -> str: r""" @@ -374,13 +374,7 @@ def x3d_str(self) -> str: sage: t.x3d_str() "" """ - return ( - "" - "" - "").format(color=self.color, shininess=self.shininess, - specular=self.specular[0]) + return ("" "" "").format(color=self.color, shininess=self.shininess, specular=self.specular[0]) def mtl_str(self) -> str: r""" @@ -393,7 +387,8 @@ def mtl_str(self) -> str: sage: t.mtl_str() 'newmtl texture...\nKa 0.2 0.2 0.5\nKd 0.4 0.4 1.0\nKs 0.0 0.0 0.0\nillum 1\nNs 1.0\nd 0.6' """ - return dedent("""\ + return dedent( + """\ newmtl {id} Ka {ambient[0]!r} {ambient[1]!r} {ambient[2]!r} Kd {diffuse[0]!r} {diffuse[1]!r} {diffuse[2]!r} @@ -401,10 +396,7 @@ def mtl_str(self) -> str: illum {illumination} Ns {shininess!r} d {opacity!r}""" - ).format(id=self.id, ambient=self.ambient, diffuse=self.diffuse, - specular=self.specular, - illumination=(2 if sum(self.specular) > 0 else 1), - shininess=self.shininess, opacity=self.opacity) + ).format(id=self.id, ambient=self.ambient, diffuse=self.diffuse, specular=self.specular, illumination=(2 if sum(self.specular) > 0 else 1), shininess=self.shininess, opacity=self.opacity) def jmol_str(self, obj) -> str: r""" @@ -426,7 +418,4 @@ def jmol_str(self, obj) -> str: sage: sum([dodecahedron(center=[2.5*x, 0, 0], color=(1, 0, 0, x/10)) for x in range(11)]).show(aspect_ratio=[1,1,1], frame=False, zoom=2) """ translucent = "translucent %s" % float(1 - self.opacity) if self.opacity < 1 else "" - return "color {} {} [{},{},{}]".format(obj, translucent, - int(255 * self.color[0]), - int(255 * self.color[1]), - int(255 * self.color[2])) + return "color {} {} [{},{},{}]".format(obj, translucent, int(255 * self.color[0]), int(255 * self.color[1]), int(255 * self.color[2])) diff --git a/src/sage/plot/plot3d/tri_plot.py b/src/sage/plot/plot3d/tri_plot.py index 9ad94872c62..b39213ed479 100644 --- a/src/sage/plot/plot3d/tri_plot.py +++ b/src/sage/plot/plot3d/tri_plot.py @@ -30,6 +30,7 @@ class Triangle: """ A graphical triangle class. """ + def __init__(self, a, b, c, color=0): """ a, b, c : triples (x,y,z) representing corners on a triangle in 3-space. @@ -101,6 +102,7 @@ class SmoothTriangle(Triangle): """ A class for smoothed triangles. """ + def __init__(self, a, b, c, da, db, dc, color=0): """ a, b, c : triples (x,y,z) representing corners on a triangle in 3-space @@ -171,8 +173,8 @@ def triangle(self, a, b, c, color=None): ([0, 0, 0], [0, 0, 1], [1, 1, 0]) """ if color is None: - return Triangle(a,b,c) - return Triangle(a,b,c,color) + return Triangle(a, b, c) + return Triangle(a, b, c, color) def smooth_triangle(self, a, b, c, da, db, dc, color=None): """ @@ -193,8 +195,8 @@ def smooth_triangle(self, a, b, c, da, db, dc, color=None): ([0, 0, 1], [0, 2, 0], [1, 0, 0]) """ if color is None: - return SmoothTriangle(a,b,c,da,db,dc) - return SmoothTriangle(a,b,c,da,db,dc,color) + return SmoothTriangle(a, b, c, da, db, dc) + return SmoothTriangle(a, b, c, da, db, dc, color) def get_colors(self, list): """ @@ -238,8 +240,7 @@ def str(self): """ return "".join(o.str() for o in self._objects) - def __init__(self, triangle_factory, f, min_x__max_x, min_y__max_y, g=None, - min_depth=4, max_depth=8, num_colors=None, max_bend=.3): + def __init__(self, triangle_factory, f, min_x__max_x, min_y__max_y, g=None, min_depth=4, max_depth=8, num_colors=None, max_bend=0.3): """ TESTS:: @@ -263,22 +264,25 @@ def __init__(self, triangle_factory, f, min_x__max_x, min_y__max_y, g=None, raise ValueError('plot rectangle is really a line; make sure min_x != max_x and min_y != max_y') self._num_colors = num_colors if g is None: + def fcn(x, y): - return [self._f(x,y)] + return [self._f(x, y)] + else: + def fcn(x, y): - return [self._f(x,y), self._g(x,y)] + return [self._f(x, y), self._g(x, y)] self._fcn = fcn # generate the necessary data to kick-start the recursion - mid_x = (min_x + max_x)/2 - mid_y = (min_y + max_y)/2 - sw_z = fcn(min_x,min_y) - nw_z = fcn(min_x,max_y) - se_z = fcn(max_x,min_y) - ne_z = fcn(max_x,max_y) - mid_z = fcn(mid_x,mid_y) + mid_x = (min_x + max_x) / 2 + mid_y = (min_y + max_y) / 2 + sw_z = fcn(min_x, min_y) + nw_z = fcn(min_x, max_y) + se_z = fcn(max_x, min_y) + ne_z = fcn(max_x, max_y) + mid_z = fcn(mid_x, mid_y) self._min = min(sw_z[0], nw_z[0], se_z[0], ne_z[0], mid_z[0]) self._max = max(sw_z[0], nw_z[0], se_z[0], ne_z[0], mid_z[0]) @@ -294,11 +298,11 @@ def fcn(x, y): zrange = self._max - self._min if num_colors is not None and zrange != 0: - colors = triangle_factory.get_colors([hue(float(i/num_colors)) for i in range(num_colors)]) + colors = triangle_factory.get_colors([hue(float(i / num_colors)) for i in range(num_colors)]) for o in self._objects: vertices = o.get_vertices() - avg_z = (vertices[0][2] + vertices[1][2] + vertices[2][2])/3 + avg_z = (vertices[0][2] + vertices[1][2] + vertices[2][2]) / 3 o.set_color(colors[int(num_colors * (avg_z - self._min) / zrange)]) def plot_block(self, min_x, mid_x, max_x, min_y, mid_y, max_y, sw_z, nw_z, se_z, ne_z, mid_z, depth): @@ -330,13 +334,13 @@ def plot_block(self, min_x, mid_x, max_x, min_y, mid_y, max_y, sw_z, nw_z, se_z, mid_e_z = self._fcn(max_x, mid_y) mid_s_z = self._fcn(mid_x, min_y) - next_depth = depth+1 + next_depth = depth + 1 if depth < self._min_depth: # midpoints locations of sub_squares - qtr1_x = (min_x + mid_x)/2 - qtr1_y = (min_y + mid_y)/2 - qtr3_x = (mid_x + max_x)/2 - qtr3_y = (mid_y + max_y)/2 + qtr1_x = (min_x + mid_x) / 2 + qtr1_y = (min_y + mid_y) / 2 + qtr3_x = (mid_x + max_x) / 2 + qtr3_y = (mid_y + max_y) / 2 sw_depth = next_depth nw_depth = next_depth @@ -365,38 +369,38 @@ def plot_block(self, min_x, mid_x, max_x, min_y, mid_y, max_y, sw_z, nw_z, se_z, norm_s = crossunit(se_v, sw_v) # compute the dot products of the triangle unit norms - e_sw = norm_w[0]*norm_s[0] + norm_w[1]*norm_s[1] + norm_w[2]*norm_s[2] - e_nw = norm_w[0]*norm_n[0] + norm_w[1]*norm_n[1] + norm_w[2]*norm_n[2] - e_se = norm_e[0]*norm_s[0] + norm_e[1]*norm_s[1] + norm_e[2]*norm_s[2] - e_ne = norm_e[0]*norm_n[0] + norm_e[1]*norm_n[1] + norm_e[2]*norm_n[2] + e_sw = norm_w[0] * norm_s[0] + norm_w[1] * norm_s[1] + norm_w[2] * norm_s[2] + e_nw = norm_w[0] * norm_n[0] + norm_w[1] * norm_n[1] + norm_w[2] * norm_n[2] + e_se = norm_e[0] * norm_s[0] + norm_e[1] * norm_s[1] + norm_e[2] * norm_s[2] + e_ne = norm_e[0] * norm_n[0] + norm_e[1] * norm_n[1] + norm_e[2] * norm_n[2] - if e_sw < self._max_bend*norm_s[3]*norm_w[3]: + if e_sw < self._max_bend * norm_s[3] * norm_w[3]: sw_depth = next_depth else: sw_depth = self._max_depth - if e_nw < self._max_bend*norm_n[3]*norm_w[3]: + if e_nw < self._max_bend * norm_n[3] * norm_w[3]: nw_depth = next_depth else: nw_depth = self._max_depth - if e_se < self._max_bend*norm_s[3]*norm_e[3]: + if e_se < self._max_bend * norm_s[3] * norm_e[3]: se_depth = next_depth else: se_depth = self._max_depth - if e_ne < self._max_bend*norm_n[3]*norm_e[3]: + if e_ne < self._max_bend * norm_n[3] * norm_e[3]: ne_depth = next_depth else: ne_depth = self._max_depth - qtr1_x = min_x + (.325 + random.random()/4)*(mid_x-min_x) - qtr3_x = mid_x + (.325 + random.random()/4)*(max_x-mid_x) - qtr1_y = min_y + (.325 + random.random()/4)*(mid_y-min_y) - qtr3_y = mid_y + (.325 + random.random()/4)*(max_y-mid_y) + qtr1_x = min_x + (0.325 + random.random() / 4) * (mid_x - min_x) + qtr3_x = mid_x + (0.325 + random.random() / 4) * (max_x - mid_x) + qtr1_y = min_y + (0.325 + random.random() / 4) * (mid_y - min_y) + qtr3_y = mid_y + (0.325 + random.random() / 4) * (max_y - mid_y) # function evaluated at the midpoints (possibly random) - mid_sw_z = self._fcn(qtr1_x,qtr1_y) - mid_nw_z = self._fcn(qtr1_x,qtr3_y) - mid_se_z = self._fcn(qtr3_x,qtr1_y) - mid_ne_z = self._fcn(qtr3_x,qtr3_y) + mid_sw_z = self._fcn(qtr1_x, qtr1_y) + mid_nw_z = self._fcn(qtr1_x, qtr3_y) + mid_se_z = self._fcn(qtr3_x, qtr1_y) + mid_ne_z = self._fcn(qtr3_x, qtr3_y) self.extrema([mid_w_z[0], mid_n_z[0], mid_e_z[0], mid_s_z[0], mid_sw_z[0], mid_se_z[0], mid_nw_z[0], mid_sw_z[0]]) @@ -465,7 +469,7 @@ def interface(self, n, p, p_c, q, q_c): sage: t._objects[-1].get_vertices() ((-1/4, 0, 1/16), (-1/4, 1/4, 1/8), (-3/8, 1/8, 3/16)) """ - m = [p[0]] # a sorted union of p and q + m = [p[0]] # a sorted union of p and q mpc = [p_c[0]] # centers from p_c corresponding to m mqc = [q_c[0]] # centers from q_c corresponding to m @@ -512,11 +516,11 @@ def triangulate(self, p, c): """ if self._g is None: - for i in range(len(p)-1): - self._objects.append(self._triangle_factory.triangle(p[i][0], p[i+1][0], c[i][0])) + for i in range(len(p) - 1): + self._objects.append(self._triangle_factory.triangle(p[i][0], p[i + 1][0], c[i][0])) else: - for i in range(len(p)-1): - self._objects.append(self._triangle_factory.smooth_triangle(p[i][0], p[i+1][0], c[i][0],p[i][1], p[i+1][1], c[i][1])) + for i in range(len(p) - 1): + self._objects.append(self._triangle_factory.smooth_triangle(p[i][0], p[i + 1][0], c[i][0], p[i][1], p[i + 1][1], c[i][1])) def extrema(self, list): """ @@ -535,8 +539,8 @@ def extrema(self, list): (-1, 4) """ if self._num_colors is not None: - self._min = min(list+[self._min]) - self._max = max(list+[self._max]) + self._min = min(list + [self._min]) + self._max = max(list + [self._max]) def crossunit(u, v): @@ -557,8 +561,8 @@ def crossunit(u, v): sage: crossunit([0,-1,0],[0,0,1]) (-1, 0, 0, 1.0) """ - p = (u[1]*v[2] - v[1]*u[2], u[0]*v[2] - v[0]*u[2], u[0]*v[1] - u[1]*v[0]) - l = sqrt(p[0]**2 + p[1]**2 + p[2]**2) + p = (u[1] * v[2] - v[1] * u[2], u[0] * v[2] - v[0] * u[2], u[0] * v[1] - u[1] * v[0]) + l = sqrt(p[0] ** 2 + p[1] ** 2 + p[2] ** 2) return (p[0], p[1], p[2], l) @@ -566,6 +570,7 @@ class PlotBlock: """ A container class to hold information about spatial blocks. """ + def __init__(self, left, left_c, top, top_c, right, right_c, bottom, bottom_c): """ diff --git a/src/sage/plot/plot_field.py b/src/sage/plot/plot_field.py index c79a22e389c..d123d96db2b 100644 --- a/src/sage/plot/plot_field.py +++ b/src/sage/plot/plot_field.py @@ -35,6 +35,7 @@ class PlotField(GraphicPrimitive): Primitive class that initializes the PlotField graphics type """ + def __init__(self, xpos_array, ypos_array, xvec_array, yvec_array, options): """ Create the graphics primitive PlotField. This sets options @@ -83,6 +84,7 @@ def get_minmax_data(self): 10.0 """ from sage.plot.plot import minmax_data + return minmax_data(self.xpos_array, self.ypos_array, dict=True) def _allowed_options(self): @@ -97,13 +99,7 @@ def _allowed_options(self): sage: d['pivot'] 'Where the arrow should be placed in relation to the point (tail, middle, tip)' """ - return {'plot_points': 'How many points to use for plotting precision', - 'pivot': 'Where the arrow should be placed in relation to the point (tail, middle, tip)', - 'headwidth': 'Head width as multiple of shaft width, default is 3', - 'headlength': 'head length as multiple of shaft width, default is 5', - 'headaxislength': 'head length at shaft intersection, default is 4.5', - 'zorder': 'The layer level in which to draw', - 'color': 'The color of the arrows'} + return {'plot_points': 'How many points to use for plotting precision', 'pivot': 'Where the arrow should be placed in relation to the point (tail, middle, tip)', 'headwidth': 'Head width as multiple of shaft width, default is 3', 'headlength': 'head length as multiple of shaft width, default is 5', 'headaxislength': 'head length at shaft intersection, default is 4.5', 'zorder': 'The layer level in which to draw', 'color': 'The color of the arrows'} def _repr_(self): """ @@ -137,8 +133,7 @@ def _repr_(self): 20 """ - return "PlotField defined by a {} x {} vector grid".format( - self._options['plot_points'], self._options['plot_points']) + return "PlotField defined by a {} x {} vector grid".format(self._options['plot_points'], self._options['plot_points']) def _render_on_subplot(self, subplot): """ @@ -150,9 +145,7 @@ def _render_on_subplot(self, subplot): options = self.options() quiver_options = options.copy() quiver_options.pop('plot_points') - subplot.quiver(self.xpos_array, self.ypos_array, - self.xvec_array, self.yvec_array, - angles='xy', **quiver_options) + subplot.quiver(self.xpos_array, self.ypos_array, self.xvec_array, self.yvec_array, angles='xy', **quiver_options) @options(plot_points=20, frame=True) @@ -258,8 +251,8 @@ def plot_vector_field(f_g, xrange, yrange, **options): f, g = f_g from sage.plot.graphics import Graphics from sage.plot.misc import setup_for_eval_on_grid - z, ranges = setup_for_eval_on_grid([f, g], [xrange, yrange], - options['plot_points']) + + z, ranges = setup_for_eval_on_grid([f, g], [xrange, yrange], options['plot_points']) f, g = z xpos_array, ypos_array, xvec_array, yvec_array = [], [], [], [] @@ -271,12 +264,12 @@ def plot_vector_field(f_g, xrange, yrange, **options): yvec_array.append(g(x, y)) import numpy + xvec_array = numpy.ma.masked_invalid(numpy.array(xvec_array, dtype=float)) yvec_array = numpy.ma.masked_invalid(numpy.array(yvec_array, dtype=float)) g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) - g.add_primitive(PlotField(xpos_array, ypos_array, - xvec_array, yvec_array, options)) + g.add_primitive(PlotField(xpos_array, ypos_array, xvec_array, yvec_array, options)) return g @@ -342,19 +335,20 @@ def plot_slope_field(f, xrange, yrange, **kwds): Graphics object consisting of 1 graphics primitive sage: dummy_err = numpy.seterr(**old_err) """ - slope_options = {'headaxislength': 0, - 'headlength': 1e-9, - 'pivot': 'middle'} + slope_options = {'headaxislength': 0, 'headlength': 1e-9, 'pivot': 'middle'} slope_options.update(kwds) from sage.misc.functional import sqrt from sage.misc.sageinspect import is_function_or_cython_function + if is_function_or_cython_function(f): + def norm_inverse(x, y): - return 1 / sqrt(f(x, y)**2 + 1) + return 1 / sqrt(f(x, y) ** 2 + 1) def f_normalized(x, y): return f(x, y) * norm_inverse(x, y) + else: norm_inverse = 1 / sqrt(f**2 + 1) f_normalized = f * norm_inverse diff --git a/src/sage/plot/point.py b/src/sage/plot/point.py index 24b71a0ad85..0e08e3c57f7 100644 --- a/src/sage/plot/point.py +++ b/src/sage/plot/point.py @@ -67,6 +67,7 @@ class Point(GraphicPrimitive_xydata): sage: point((3,3)) Graphics object consisting of 1 graphics primitive """ + def __init__(self, xdata, ydata, options): """ Initialize base class Point. @@ -93,16 +94,7 @@ def _allowed_options(self): sage: P[0]._allowed_options()['size'] 'How big the point is (i.e., area in points^2=(1/72 inch)^2).' """ - return {'alpha': 'How transparent the point is.', - 'faceted': 'If True color the edge of the point. (only for 2D plots)', - 'hue': 'The color given as a hue.', - 'legend_color': 'The color of the legend text', - 'legend_label': 'The label for this item in the legend.', - 'marker': 'the marker symbol for 2D plots only (see documentation of plot() for details)', - 'markeredgecolor': 'the color of the marker edge (only for 2D plots)', - 'rgbcolor': 'The color as an RGB tuple.', - 'size': 'How big the point is (i.e., area in points^2=(1/72 inch)^2).', - 'zorder': 'The layer level in which to draw'} + return {'alpha': 'How transparent the point is.', 'faceted': 'If True color the edge of the point. (only for 2D plots)', 'hue': 'The color given as a hue.', 'legend_color': 'The color of the legend text', 'legend_label': 'The label for this item in the legend.', 'marker': 'the marker symbol for 2D plots only (see documentation of plot() for details)', 'markeredgecolor': 'the color of the marker edge (only for 2D plots)', 'rgbcolor': 'The color as an RGB tuple.', 'size': 'How big the point is (i.e., area in points^2=(1/72 inch)^2).', 'zorder': 'The layer level in which to draw'} def _plot3d_options(self, options=None): """ @@ -235,6 +227,7 @@ def plot3d(self, z=0, **kwds): """ from sage.plot.plot3d.base import Graphics3dGroup from sage.plot.plot3d.shapes2 import point3d + options = self._plot3d_options() options.update(kwds) zdata = [] @@ -293,6 +286,7 @@ def _render_on_subplot(self, subplot): # three points. This is mentioned in the matplotlib 0.98 # documentation and fixes #2076 from matplotlib.colors import rgb2hex + c = rgb2hex(to_mpl_color(options['rgbcolor'])) a = float(options['alpha']) @@ -305,12 +299,10 @@ def _render_on_subplot(self, subplot): if not faceted and markeredgecolor is None: scatteroptions['edgecolors'] = 'none' elif markeredgecolor is not None: - scatteroptions['edgecolors'] = to_mpl_color( - options.pop('markeredgecolor')) + scatteroptions['edgecolors'] = to_mpl_color(options.pop('markeredgecolor')) scatteroptions['marker'] = options.pop('marker') - subplot.scatter(self.xdata, self.ydata, s=s, c=c, alpha=a, zorder=z, - label=options['legend_label'], **scatteroptions) + subplot.scatter(self.xdata, self.ydata, s=s, c=c, alpha=a, zorder=z, label=options['legend_label'], **scatteroptions) def point(points, **kwds): @@ -389,13 +381,12 @@ def point(points, **kwds): return point2d(points, **kwds) except (ValueError, TypeError): from sage.plot.plot3d.shapes2 import point3d + return point3d(points, **kwds) @rename_keyword(color='rgbcolor', pointsize='size') -@options(alpha=1, aspect_ratio='automatic', faceted=False, - legend_color=None, legend_label=None, marker='o', - markeredgecolor=None, rgbcolor=(0, 0, 1), size=10) +@options(alpha=1, aspect_ratio='automatic', faceted=False, legend_color=None, legend_label=None, marker='o', markeredgecolor=None, rgbcolor=(0, 0, 1), size=10) def point2d(points, **options): r""" A point of size ``size`` defined by point = `(x, y)`. @@ -598,14 +589,10 @@ def point2d(points, **options): if l == 0: return Graphics() if l == 2: # special case for a single 2D point - if all(isinstance(z, numbers.Real) - or (isinstance(z, Expression) and not complex(z).imag) - for z in points): + if all(isinstance(z, numbers.Real) or (isinstance(z, Expression) and not complex(z).imag) for z in points): points = [points] elif l == 3: # special case for a single 3D point - if all(isinstance(z, numbers.Real) - or (isinstance(z, Expression) and not complex(z).imag) - for z in points): + if all(isinstance(z, numbers.Real) or (isinstance(z, Expression) and not complex(z).imag) for z in points): raise TypeError('not a 2D point') xdata, ydata = xydata_from_point_list(points) diff --git a/src/sage/plot/polygon.py b/src/sage/plot/polygon.py index 0fdae59be3f..b4712430f7a 100644 --- a/src/sage/plot/polygon.py +++ b/src/sage/plot/polygon.py @@ -1,6 +1,7 @@ """ Polygons """ + # **************************************************************************** # Copyright (C) 2006 Alex Clemesha , # William Stein , @@ -67,6 +68,7 @@ class Polygon(GraphicPrimitive_xydata): sage: polygon2d([(1, 1), (0, 1), (1, 0)], fill=False, linestyle='dashed') Graphics object consisting of 1 graphics primitive """ + def __init__(self, xdata, ydata, options): """ Initialize base class Polygon. @@ -155,16 +157,7 @@ def _allowed_options(self): sage: P[0]._allowed_options()['alpha'] 'How transparent the figure is.' """ - return {'alpha': 'How transparent the figure is.', - 'thickness': 'How thick the border line is.', - 'edgecolor': 'The color for the border of filled polygons.', - 'fill': 'Whether or not to fill the polygon.', - 'legend_label': 'The label for this item in the legend.', - 'legend_color': 'The color of the legend text.', - 'linestyle': 'The style of the enclosing line.', - 'rgbcolor': 'The color as an RGB tuple.', - 'hue': 'The color given as a hue.', - 'zorder': 'The layer level in which to draw'} + return {'alpha': 'How transparent the figure is.', 'thickness': 'How thick the border line is.', 'edgecolor': 'The color for the border of filled polygons.', 'fill': 'Whether or not to fill the polygon.', 'legend_label': 'The label for this item in the legend.', 'legend_color': 'The color of the legend text.', 'linestyle': 'The style of the enclosing line.', 'rgbcolor': 'The color as an RGB tuple.', 'hue': 'The color given as a hue.', 'zorder': 'The layer level in which to draw'} def _plot3d_options(self, options=None): """ @@ -235,6 +228,7 @@ def plot3d(self, z=0, **kwds): ValueError: Incorrect number of heights given """ from sage.plot.plot3d.index_face_set import IndexFaceSet + options = self._plot3d_options() options.update(kwds) zdata = [] @@ -243,8 +237,7 @@ def plot3d(self, z=0, **kwds): else: zdata = [z] * len(self.xdata) if len(zdata) == len(self.xdata): - return IndexFaceSet([list(zip(self.xdata, self.ydata, zdata))], - **options) + return IndexFaceSet([list(zip(self.xdata, self.ydata, zdata))], **options) raise ValueError('Incorrect number of heights given') def _render_on_subplot(self, subplot): @@ -254,9 +247,9 @@ def _render_on_subplot(self, subplot): sage: P = polygon([(0,0), (1,2), (0,1), (-1,2)]) """ from matplotlib import patches + options = self.options() - p = patches.Polygon([(self.xdata[i], self.ydata[i]) - for i in range(len(self.xdata))]) + p = patches.Polygon([(self.xdata[i], self.ydata[i]) for i in range(len(self.xdata))]) p.set_linewidth(float(options['thickness'])) if 'linestyle' in options: p.set_linestyle(options['linestyle']) @@ -314,13 +307,12 @@ def polygon(points, **options): return polygon2d(points, **options) except ValueError: from sage.plot.plot3d.shapes2 import polygon3d + return polygon3d(points, **options) @rename_keyword(color='rgbcolor') -@options(alpha=1, rgbcolor=(0, 0, 1), edgecolor=None, thickness=None, - legend_label=None, legend_color=None, - aspect_ratio=1.0, fill=True) +@options(alpha=1, rgbcolor=(0, 0, 1), edgecolor=None, thickness=None, legend_label=None, legend_color=None, aspect_ratio=1.0, fill=True) def polygon2d(points, **options): r""" Return a 2-dimensional polygon defined by ``points``. @@ -535,7 +527,8 @@ def polygon2d(points, **options): """ from sage.plot.plot import xydata_from_point_list from sage.plot.graphics import Graphics - if options["thickness"] is None: # If the user did not specify thickness + + if options["thickness"] is None: # If the user did not specify thickness if options["fill"] and options["edgecolor"] is None: # If the user chose fill options["thickness"] = 0 diff --git a/src/sage/plot/primitive.py b/src/sage/plot/primitive.py index 63c8b2acb0c..fae97a9f446 100644 --- a/src/sage/plot/primitive.py +++ b/src/sage/plot/primitive.py @@ -1,7 +1,8 @@ """ Plotting primitives """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2006 Alex Clemesha , # William Stein , # 2008 Mike Hansen , @@ -16,7 +17,7 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.fast_methods import WithEqualityById from sage.structure.sage_object import SageObject from sage.misc.verbose import verbose @@ -42,6 +43,7 @@ class GraphicPrimitive(WithEqualityById, SageObject): sage: hash(circle((0,0),1)) # random 42 """ + def __init__(self, options): """ Create a base class GraphicsPrimitive. All this does is @@ -117,8 +119,7 @@ def _plot3d_options(self, options=None): del options[o] if len(options) != 0: - raise NotImplementedError("Unknown plot3d equivalent for {}".format( - ", ".join(options.keys()))) + raise NotImplementedError("Unknown plot3d equivalent for {}".format(", ".join(options.keys()))) return options_3d def set_zorder(self, zorder): @@ -174,6 +175,7 @@ def options(self): """ from sage.plot.graphics import do_verify from sage.plot.colors import hue + O = dict(self._options) if do_verify: A = self._allowed_options() @@ -182,8 +184,7 @@ def options(self): for k, Ok in O.items(): if k not in K: do_verify = False - verbose(f"WARNING: Ignoring option '{k}'={Ok}", - level=0) + verbose(f"WARNING: Ignoring option '{k}'={Ok}", level=0) t = True if t: s = "\nThe allowed options for %s are:\n" % self @@ -245,4 +246,5 @@ def get_minmax_data(self): 120.0 """ from sage.plot.plot import minmax_data + return minmax_data(self.xdata, self.ydata, dict=True) diff --git a/src/sage/plot/scatter_plot.py b/src/sage/plot/scatter_plot.py index 1b6a8eae48f..0d9d221748d 100644 --- a/src/sage/plot/scatter_plot.py +++ b/src/sage/plot/scatter_plot.py @@ -39,6 +39,7 @@ class ScatterPlot(GraphicPrimitive): sage: ScatterPlot([0,1,2], [3.5,2,5.1], {'facecolor':'white', 'marker':'s'}) Scatter plot graphics primitive on 3 data points """ + def __init__(self, xdata, ydata, options): """ Scatter plot graphics primitive. @@ -67,10 +68,7 @@ def get_minmax_data(self): sage: d['ymin'] ...1.0... """ - return {'xmin': self.xdata.min(), - 'xmax': self.xdata.max(), - 'ymin': self.ydata.min(), - 'ymax': self.ydata.max()} + return {'xmin': self.xdata.min(), 'xmax': self.xdata.max(), 'ymin': self.ydata.min(), 'ymax': self.ydata.max()} def _allowed_options(self): """ @@ -91,15 +89,7 @@ def _allowed_options(self): ('rgbcolor', 'The color as an RGB tuple.'), ('zorder', 'The layer level in which to draw.')] """ - return {'markersize': 'the size of the markers.', - 'marker': 'What shape to plot the points. See the documentation of plot() for the full list of markers.', - 'alpha': 'How transparent the marker border is.', - 'rgbcolor': 'The color as an RGB tuple.', - 'hue': 'The color given as a hue.', - 'facecolor': 'The color of the marker face.', - 'edgecolor': 'The color of the marker border.', - 'zorder': 'The layer level in which to draw.', - 'clip': 'Whether or not to clip.'} + return {'markersize': 'the size of the markers.', 'marker': 'What shape to plot the points. See the documentation of plot() for the full list of markers.', 'alpha': 'How transparent the marker border is.', 'rgbcolor': 'The color as an RGB tuple.', 'hue': 'The color given as a hue.', 'facecolor': 'The color of the marker face.', 'edgecolor': 'The color of the marker border.', 'zorder': 'The layer level in which to draw.', 'clip': 'Whether or not to clip.'} def _repr_(self): """ @@ -131,10 +121,7 @@ def _render_on_subplot(self, subplot): Graphics object consisting of 1 graphics primitive """ options = self.options() - p = subplot.scatter(self.xdata, self.ydata, alpha=options['alpha'], - zorder=options['zorder'], marker=options['marker'], - s=options['markersize'], facecolors=options['facecolor'], - edgecolors=options['edgecolor'], clip_on=options['clip']) + p = subplot.scatter(self.xdata, self.ydata, alpha=options['alpha'], zorder=options['zorder'], marker=options['marker'], s=options['markersize'], facecolors=options['facecolor'], edgecolors=options['edgecolor'], clip_on=options['clip']) if not options['clip']: self._bbox_extra_artists = [p] @@ -188,6 +175,7 @@ def scatter_plot(datalist, **options): """ import numpy from sage.plot.graphics import Graphics + g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) data = numpy.array(datalist, dtype='float') diff --git a/src/sage/plot/step.py b/src/sage/plot/step.py index a8cd8a9d2d2..d10082d063b 100644 --- a/src/sage/plot/step.py +++ b/src/sage/plot/step.py @@ -77,7 +77,7 @@ def plot_step_function(v, vertical_lines=True, **kwds): w = [] for i in range(len(v)): w.append(v[i]) - if i+1 < len(v): - w.append((v[i+1][0], v[i][1])) + if i + 1 < len(v): + w.append((v[i + 1][0], v[i][1])) return line(w, **kwds) - return sum(line([v[i], (v[i+1][0], v[i][1])], **kwds) for i in range(len(v)-1)) + return sum(line([v[i], (v[i + 1][0], v[i][1])], **kwds) for i in range(len(v) - 1)) diff --git a/src/sage/plot/streamline_plot.py b/src/sage/plot/streamline_plot.py index 761c82221af..1981b871d7b 100644 --- a/src/sage/plot/streamline_plot.py +++ b/src/sage/plot/streamline_plot.py @@ -27,6 +27,7 @@ class StreamlinePlot(GraphicPrimitive): """ Primitive class that initializes the StreamlinePlot graphics type """ + def __init__(self, xpos_array, ypos_array, xvec_array, yvec_array, options): """ Create the graphics primitive StreamlinePlot. This sets options @@ -80,6 +81,7 @@ def get_minmax_data(self): 10.0 """ from sage.plot.plot import minmax_data + return minmax_data(self.xpos_array, self.ypos_array, dict=True) def _allowed_options(self): @@ -94,11 +96,7 @@ def _allowed_options(self): sage: d['density'] 'Controls the closeness of streamlines' """ - return {'plot_points': 'How many points to use for plotting precision', - 'color': 'The color of the arrows', - 'density': 'Controls the closeness of streamlines', - 'start_points': 'Coordinates of starting points for the streamlines', - 'zorder': 'The layer level in which to draw'} + return {'plot_points': 'How many points to use for plotting precision', 'color': 'The color of the arrows', 'density': 'Controls the closeness of streamlines', 'start_points': 'Coordinates of starting points for the streamlines', 'zorder': 'The layer level in which to draw'} def _repr_(self): """ @@ -127,8 +125,7 @@ def _repr_(self): 20 """ - return "StreamlinePlot defined by a {} x {} vector grid".format( - self._options['plot_points'], self._options['plot_points']) + return "StreamlinePlot defined by a {} x {} vector grid".format(self._options['plot_points'], self._options['plot_points']) def _render_on_subplot(self, subplot): """ @@ -140,12 +137,10 @@ def _render_on_subplot(self, subplot): options = self.options() streamplot_options = options.copy() streamplot_options.pop('plot_points') - subplot.streamplot(self.xpos_array, self.ypos_array, - self.xvec_array, self.yvec_array, - **streamplot_options) + subplot.streamplot(self.xpos_array, self.ypos_array, self.xvec_array, self.yvec_array, **streamplot_options) -@options(plot_points=20, density=1., frame=True) +@options(plot_points=20, density=1.0, frame=True) def streamline_plot(f_g, xrange, yrange, **options): r""" Return a streamline plot in a vector field. @@ -274,20 +269,22 @@ def streamline_plot(f_g, xrange, yrange, **options): """ # Parse the function input if isinstance(f_g, (list, tuple)): - (f,g) = f_g + (f, g) = f_g else: from sage.misc.functional import sqrt from sage.misc.sageinspect import is_function_or_cython_function + if is_function_or_cython_function(f_g): - f = lambda x,y: 1 / sqrt(f_g(x, y)**2 + 1) - g = lambda x,y: f_g(x, y) * f(x, y) + f = lambda x, y: 1 / sqrt(f_g(x, y) ** 2 + 1) + g = lambda x, y: f_g(x, y) * f(x, y) else: f = 1 / sqrt(f_g**2 + 1) g = f_g * f from sage.plot.graphics import Graphics from sage.plot.misc import setup_for_eval_on_grid - z, ranges = setup_for_eval_on_grid([f,g], [xrange,yrange], options['plot_points']) + + z, ranges = setup_for_eval_on_grid([f, g], [xrange, yrange], options['plot_points']) f, g = z # The density values must be floats @@ -308,6 +305,7 @@ def streamline_plot(f_g, xrange, yrange, **options): yvec_array.append(yvec_row) import numpy + xpos_array = numpy.array(xpos_array, dtype=float) ypos_array = numpy.array(ypos_array, dtype=float) xvec_array = numpy.ma.masked_invalid(numpy.array(xvec_array, dtype=float)) @@ -322,6 +320,5 @@ def streamline_plot(f_g, xrange, yrange, **options): g = Graphics() g._set_extra_kwds(Graphics._extract_kwds_for_show(options)) - g.add_primitive(StreamlinePlot(xpos_array, ypos_array, - xvec_array, yvec_array, options)) + g.add_primitive(StreamlinePlot(xpos_array, ypos_array, xvec_array, yvec_array, options)) return g diff --git a/src/sage/plot/text.py b/src/sage/plot/text.py index 22bad82b1d2..f4976b6d53a 100644 --- a/src/sage/plot/text.py +++ b/src/sage/plot/text.py @@ -1,7 +1,8 @@ """ Text in plots """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2006 Alex Clemesha , # William Stein , # 2008 Mike Hansen , @@ -16,7 +17,7 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.plot.primitive import GraphicPrimitive from sage.misc.decorators import options, rename_keyword from sage.plot.colors import to_mpl_color @@ -37,6 +38,7 @@ class Text(GraphicPrimitive): sphinx_plot(text("I like Fibonacci",(3,5))) """ + def __init__(self, string, point, options): """ Initialize base class Text. @@ -72,6 +74,7 @@ def get_minmax_data(self): 1.0 """ from sage.plot.plot import minmax_data + return minmax_data([self.x], [self.y], dict=True) def _repr_(self): @@ -100,23 +103,22 @@ def _allowed_options(self): sage: T[0]._allowed_options()['rotation'] 'How to rotate the text: angle in degrees, vertical, horizontal' """ - return {'fontsize': 'How big the text is. Either the size in points or a relative size, e.g. \'smaller\', \'x-large\', etc', - 'fontstyle': 'A string either \'normal\', \'italic\' or \'oblique\'', - 'fontweight': 'A numeric value in the range 0-1000 or a string' - '\'ultralight\', \'light\', \'normal\', \'regular\', \'book\',' - '\'medium\', \'roman\', \'semibold\', \'demibold\', \'demi\',' - '\'bold,\', \'heavy\', \'extra bold\', \'black\'', - 'rgbcolor': 'The color as an RGB tuple', - 'background_color': 'The background color', - 'bounding_box': 'A dictionary specifying a bounding box', - 'hue': 'The color given as a hue', - 'alpha': 'A float (0.0 transparent through 1.0 opaque)', - 'axis_coords': 'If True use axis coordinates: (0,0) lower left and (1,1) upper right', - 'rotation': 'How to rotate the text: angle in degrees, vertical, horizontal', - 'vertical_alignment': 'How to align vertically: top, center, bottom', - 'horizontal_alignment': 'How to align horizontally: left, center, right', - 'zorder': 'The layer level in which to draw', - 'clip': 'Whether to clip or not'} + return { + 'fontsize': 'How big the text is. Either the size in points or a relative size, e.g. \'smaller\', \'x-large\', etc', + 'fontstyle': 'A string either \'normal\', \'italic\' or \'oblique\'', + 'fontweight': 'A numeric value in the range 0-1000 or a string' '\'ultralight\', \'light\', \'normal\', \'regular\', \'book\',' '\'medium\', \'roman\', \'semibold\', \'demibold\', \'demi\',' '\'bold,\', \'heavy\', \'extra bold\', \'black\'', + 'rgbcolor': 'The color as an RGB tuple', + 'background_color': 'The background color', + 'bounding_box': 'A dictionary specifying a bounding box', + 'hue': 'The color given as a hue', + 'alpha': 'A float (0.0 transparent through 1.0 opaque)', + 'axis_coords': 'If True use axis coordinates: (0,0) lower left and (1,1) upper right', + 'rotation': 'How to rotate the text: angle in degrees, vertical, horizontal', + 'vertical_alignment': 'How to align vertically: top, center, bottom', + 'horizontal_alignment': 'How to align horizontally: left, center, right', + 'zorder': 'The layer level in which to draw', + 'clip': 'Whether to clip or not', + } def _plot3d_options(self, options=None): """ @@ -139,8 +141,7 @@ def _plot3d_options(self, options=None): if s in options: options_3d[s] = options.pop(s) # TODO: figure out how to implement rather than ignore - for s in ['axis_coords', 'clip', 'horizontal_alignment', - 'rotation', 'vertical_alignment']: + for s in ['axis_coords', 'clip', 'horizontal_alignment', 'rotation', 'vertical_alignment']: if s in options: del options[s] options_3d.update(GraphicPrimitive._plot3d_options(self, options)) @@ -161,6 +162,7 @@ def plot3d(self, **kwds): (1.0, 1.0, 0) """ from sage.plot.plot3d.shapes2 import text3d + options = self._plot3d_options() options.update(kwds) return text3d(self.string, (self.x, self.y, 0), **options) @@ -212,8 +214,7 @@ def _render_on_subplot(self, subplot): @rename_keyword(color='rgbcolor') -@options(fontsize=10, rgbcolor=(0,0,1), horizontal_alignment='center', - vertical_alignment='center', axis_coords=False, clip=False) +@options(fontsize=10, rgbcolor=(0, 0, 1), horizontal_alignment='center', vertical_alignment='center', axis_coords=False, clip=False) def text(string, xy, **options): r""" Return a 2D text graphics object at the point `(x, y)`. @@ -423,6 +424,7 @@ def text(string, xy, **options): raise ValueError("use text3d instead for text in 3d") raise from sage.plot.graphics import Graphics + options['rgbcolor'] = to_mpl_color(options['rgbcolor']) point = (float(x), float(y)) g = Graphics() diff --git a/src/sage/probability/all.py b/src/sage/probability/all.py index 646f3d5a2ad..b6afdc46cb4 100644 --- a/src/sage/probability/all.py +++ b/src/sage/probability/all.py @@ -1,9 +1,3 @@ +from sage.probability.random_variable import DiscreteRandomVariable, DiscreteProbabilitySpace -from sage.probability.random_variable import ( - DiscreteRandomVariable, - DiscreteProbabilitySpace) - -from sage.probability.probability_distribution import ( - RealDistribution, - SphericalDistribution, - GeneralDiscreteDistribution) +from sage.probability.probability_distribution import RealDistribution, SphericalDistribution, GeneralDiscreteDistribution diff --git a/src/sage/probability/random_variable.py b/src/sage/probability/random_variable.py index a3d081736e1..82fb7662b89 100644 --- a/src/sage/probability/random_variable.py +++ b/src/sage/probability/random_variable.py @@ -31,6 +31,7 @@ class RandomVariable_generic(Parent): """ A random variable. """ + def __init__(self, X, RR): if not isinstance(X, ProbabilitySpace_generic): raise TypeError("Argument X (= %s) must be a probability space" % X) @@ -54,6 +55,7 @@ class DiscreteRandomVariable(RandomVariable_generic): """ A random variable on a discrete probability space. """ + def __init__(self, X, f, codomain=None, check=False): r""" Create free binary string monoid on `n` generators. @@ -70,6 +72,7 @@ def __init__(self, X, f, codomain=None, check=False): raise NotImplementedError("Not implemented") if codomain is None: from sage.rings.real_mpfr import RealField + RR = RealField() else: RR = codomain @@ -139,7 +142,7 @@ def variance(self): mu = self.expectation() var = 0 for x in self._function: - var += Omega(x) * (self(x) - mu)**2 + var += Omega(x) * (self(x) - mu) ** 2 return var def translation_variance(self, map): @@ -159,7 +162,7 @@ def translation_variance(self, map): mu = self.translation_expectation(map) var = 0 for x in Omega._function: - var += Omega(x) * (self(map(x)) - mu)**2 + var += Omega(x) * (self(map(x)) - mu) ** 2 return var def covariance(self, other): @@ -182,7 +185,7 @@ def covariance(self, other): muY = other.expectation() cov = 0 for x in self._function: - cov += Omega(x)*(self(x) - muX)*(other(x) - muY) + cov += Omega(x) * (self(x) - muX) * (other(x) - muY) return cov def translation_covariance(self, other, map): @@ -205,7 +208,7 @@ def translation_covariance(self, other, map): muY = other.translation_expectation(map) cov = 0 for x in Omega._function: - cov += Omega(x)*(self(x) - muX)*(other(map(x)) - muY) + cov += Omega(x) * (self(x) - muX) * (other(map(x)) - muY) return cov def standard_deviation(self): @@ -249,7 +252,7 @@ def correlation(self, other): sigY = other.standard_deviation() if sigX == 0 or sigY == 0: raise ValueError("Correlation not defined if standard deviations are not both nonzero.") - return cov/(sigX*sigY) + return cov / (sigX * sigY) def translation_correlation(self, other, map): """ @@ -261,7 +264,8 @@ def translation_correlation(self, other, map): sigY = other.translation_standard_deviation(map) if sigX == 0 or sigY == 0: raise ValueError("Correlation not defined if standard deviations are not both nonzero.") - return cov/(sigX*sigY) + return cov / (sigX * sigY) + ################################################################################ ################################################################################ @@ -271,6 +275,7 @@ class ProbabilitySpace_generic(RandomVariable_generic): r""" A probability space. """ + def __init__(self, domain, RR): """ A generic probability space on given domain space and codomain @@ -287,10 +292,11 @@ def domain(self): return self._domain -class DiscreteProbabilitySpace(ProbabilitySpace_generic,DiscreteRandomVariable): +class DiscreteProbabilitySpace(ProbabilitySpace_generic, DiscreteRandomVariable): r""" The discrete probability space """ + def __init__(self, X, P, codomain=None, check=False): r""" Create the discrete probability space with probabilities on the @@ -326,6 +332,7 @@ def __init__(self, X, P, codomain=None, check=False): """ if codomain is None: from sage.rings.real_mpfr import RealField + codomain = RealField() if not isinstance(codomain, sage.rings.abc.RealField) and not isinstance(codomain, RationalField): raise TypeError("Argument codomain (= %s) must be the reals or rationals" % codomain) @@ -364,9 +371,11 @@ def entropy(self): """ The entropy of the probability space. """ + def neg_xlog2x(p): if p == 0: return 0 - return -p*log(p,2) + return -p * log(p, 2) + p = self.function() return sum([neg_xlog2x(p[x]) for x in p]) diff --git a/src/sage/quadratic_forms/all.py b/src/sage/quadratic_forms/all.py index c4832168378..8ddb72b586c 100644 --- a/src/sage/quadratic_forms/all.py +++ b/src/sage/quadratic_forms/all.py @@ -6,17 +6,11 @@ from sage.quadratic_forms.quadratic_form import QuadraticForm, DiagonalQuadraticForm, quadratic_form_from_invariants -from sage.quadratic_forms.random_quadraticform import (random_quadraticform, - random_quadraticform_with_conditions, - random_ternaryqf, - random_ternaryqf_with_conditions) +from sage.quadratic_forms.random_quadraticform import random_quadraticform, random_quadraticform_with_conditions, random_ternaryqf, random_ternaryqf_with_conditions from sage.quadratic_forms.extras import least_quadratic_nonresidue, extend_to_primitive, is_triangular_number -from sage.quadratic_forms.special_values import (gamma__exact, zeta__exact, - QuadraticBernoulliNumber, - quadratic_L_function__exact, - quadratic_L_function__numerical) +from sage.quadratic_forms.special_values import gamma__exact, zeta__exact, QuadraticBernoulliNumber, quadratic_L_function__exact, quadratic_L_function__numerical from sage.quadratic_forms.genera.genus import Genus diff --git a/src/sage/quadratic_forms/binary_qf.py b/src/sage/quadratic_forms/binary_qf.py index ce9403d324b..faf714512ab 100644 --- a/src/sage/quadratic_forms/binary_qf.py +++ b/src/sage/quadratic_forms/binary_qf.py @@ -97,6 +97,7 @@ class BinaryQF(SageObject): sage: BinaryQF(1, 0, 1) x^2 + y^2 """ + def __init__(self, a, b=None, c=None): r""" Create a binary quadratic form `ax^2 + bxy + cy^2`. @@ -135,15 +136,15 @@ def __init__(self, a, b=None, c=None): 0 """ from sage.rings.polynomial.multi_polynomial import MPolynomial + if b is None and c is None: if isinstance(a, (list, tuple)) and len(a) == 3: a, b, c = a elif a == 0: a = b = c = 0 - elif (isinstance(a, MPolynomial) and a.is_homogeneous() and a.base_ring() == ZZ - and a.degree() == 2 and a.parent().ngens() == 2): + elif isinstance(a, MPolynomial) and a.is_homogeneous() and a.base_ring() == ZZ and a.degree() == 2 and a.parent().ngens() == 2: x, y = a.parent().gens() - a, b, c = (a.monomial_coefficient(mon) for mon in [x**2, x*y, y**2]) + a, b, c = (a.monomial_coefficient(mon) for mon in [x**2, x * y, y**2]) elif isinstance(a, pari_gen) and a.type() in ('t_QFI', 't_QFR', 't_QFB'): # a has 3 or 4 components a, b, c = a[0], a[1], a[2] @@ -219,7 +220,7 @@ def principal(D): D4 = D % 4 if D4 not in (0, 1): raise ValueError('discriminant must be congruent to 0 or 1 modulo 4') - return BinaryQF([1, D4, (D4-D)//4]) + return BinaryQF([1, D4, (D4 - D) // 4]) def __mul__(self, right): """ @@ -259,8 +260,7 @@ def __mul__(self, right): if isinstance(right, BinaryQF): return BinaryQF(self.__pari__().qfbcompraw(right)) # ...or a 2x2 matrix... - if (isinstance(right.parent(), MatrixSpace) - and right.nrows() == right.ncols() == 2): + if isinstance(right.parent(), MatrixSpace) and right.nrows() == right.ncols() == 2: aa, bb, cc, dd = right.list() A = self.polynomial()(aa, cc) C = self.polynomial()(bb, dd) @@ -578,12 +578,13 @@ def from_polynomial(poly): """ R = poly.parent() from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base + if not isinstance(R, MPolynomialRing_base) or R.ngens() != 2: raise TypeError(f'not a bivariate polynomial ring: {R}') if not all(mon.degree() == 2 for mon in poly.monomials()): raise ValueError('polynomial has monomials of degree != 2') x, y = R.gens() - coeffs = (poly.monomial_coefficient(mon) for mon in (x**2, x*y, y**2)) + coeffs = (poly.monomial_coefficient(mon) for mon in (x**2, x * y, y**2)) a, b, c = map(ZZ, coeffs) return BinaryQF(a, b, c) @@ -811,7 +812,7 @@ def _reduce_indef(self, transformation=False): if transformation: T = Matrix(ZZ, 2, 2, [0, -1, 1, s]) U = U * T - Q = BinaryQF(c, -b + 2*s*c, c*s*s - b*s + a) + Q = BinaryQF(c, -b + 2 * s * c, c * s * s - b * s + a) else: if b < 0: Q = BinaryQF(a, -b, c) @@ -820,7 +821,7 @@ def _reduce_indef(self, transformation=False): U = U * T else: q, r = a.quo_rem(b) - if 2*r > b: + if 2 * r > b: q, r = a.quo_rem(-b) q = -q if transformation: @@ -949,9 +950,7 @@ def reduced_form(self, transformation=False, algorithm='default'): if algorithm == 'sage': if self.discriminant() <= 0: - raise NotImplementedError('reduction of definite binary ' - 'quadratic forms is not implemented ' - 'in Sage') + raise NotImplementedError('reduction of definite binary ' 'quadratic forms is not implemented ' 'in Sage') return self._reduce_indef(transformation) if algorithm == 'pari': @@ -959,22 +958,20 @@ def reduced_form(self, transformation=False, algorithm='default'): # work around this by reducing [-a,b,-c] instead of [a,b,c]. if self.is_negative_definite(): M = Matrix.diagonal([-1, 1]) - r = (-self*M).reduced_form(transformation=transformation, algorithm=algorithm) + r = (-self * M).reduced_form(transformation=transformation, algorithm=algorithm) if transformation: - return (-r[0]*M, M*r[1]*M) - return -r*M + return (-r[0] * M, M * r[1] * M) + return -r * M if self.is_reducible(): - raise NotImplementedError('reducible forms are not ' - 'supported using PARI') + raise NotImplementedError('reducible forms are not ' 'supported using PARI') if transformation: y, g = self.__pari__().qfbredsl2() return BinaryQF(y), Matrix(ZZ, g) return BinaryQF(self.__pari__().qfbred()) - raise ValueError('unknown implementation for binary quadratic form ' - 'reduction: %s' % algorithm) + raise ValueError('unknown implementation for binary quadratic form ' 'reduction: %s' % algorithm) # Buchmann/Vollmer cycle algorithm def _RhoTau(self): @@ -994,10 +991,10 @@ def _RhoTau(self): cabs = c.abs() sign = c.sign() if cabs >= d: - s = sign * ((cabs+b) / (2*cabs)).floor() + s = sign * ((cabs + b) / (2 * cabs)).floor() else: - s = sign * ((d+b) / (2*cabs)).floor() - Q = BinaryQF(-c, -b + 2*s*c, -(a - b*s + c*s*s)) + s = sign * ((d + b) / (2 * cabs)).floor() + Q = BinaryQF(-c, -b + 2 * s * c, -(a - b * s + c * s * s)) return Q def _Rho(self): @@ -1017,10 +1014,10 @@ def _Rho(self): cabs = c.abs() sign = c.sign() if cabs >= d: - s = sign * ((cabs+b) / (2*cabs)).floor() + s = sign * ((cabs + b) / (2 * cabs)).floor() else: - s = sign * ((d+b) / (2*cabs)).floor() - Q = BinaryQF(c, -b + 2*s*c, a - b*s + c*s*s) + s = sign * ((d + b) / (2 * cabs)).floor() + Q = BinaryQF(c, -b + 2 * s * c, a - b * s + c * s * s) return Q def _Tau(self): @@ -1193,9 +1190,7 @@ def cycle(self, proper=False): raise ValueError("%s must be indefinite and reduced" % self) if self.discriminant().is_square(): # Buchmann/Vollmer assume the discriminant to be non-square - raise NotImplementedError('computation of cycles is only ' - 'implemented for non-square ' - 'discriminants') + raise NotImplementedError('computation of cycles is only ' 'implemented for non-square ' 'discriminants') if proper: # Prop 6.10.5 in Buchmann Vollmer C = list(self.cycle(proper=False)) # make a copy that we can modify @@ -1384,11 +1379,11 @@ def is_equivalent(self, other, proper=True) -> bool: assert otherred._b == b # p. 359 of Conway-Sloane [CS1999]_ # but `2b` in their notation is `b` in our notation - is_properly_equiv = ((a-ao) % b == 0) + is_properly_equiv = (a - ao) % b == 0 if proper: return is_properly_equiv g = gcd(a, b) - return is_properly_equiv or ((gcd(ao, b) == g) and ((a*ao - g**2) % (b*g) == 0)) + return is_properly_equiv or ((gcd(ao, b) == g) and ((a * ao - g**2) % (b * g) == 0)) proper_cycle = otherred.cycle(proper=True) @@ -1486,16 +1481,12 @@ def is_reduced(self) -> bool: b = self._b c = self._c if D < 0 and a > 0: - return ((-a < b <= a < c) - or (ZZ(0) <= b <= a == c)) + return (-a < b <= a < c) or (ZZ(0) <= b <= a == c) if D < 0 and a < 0: - return ((a < b <= -a < -c) - or (ZZ(0) <= b <= -a == -c)) + return (a < b <= -a < -c) or (ZZ(0) <= b <= -a == -c) # Note that a = 0 implies D > 0 here - return ((b > 0 and a*c < 0 and (a-c)**2 < D) - or (0 == a and -b < 2*c <= b) - or (0 == c and -b < 2*a <= b)) + return (b > 0 and a * c < 0 and (a - c) ** 2 < D) or (0 == a and -b < 2 * c <= b) or (0 == c and -b < 2 * a <= b) def complex_point(self): r""" @@ -1592,6 +1583,7 @@ def small_prime_value(self, Bmax=1000): """ from sage.sets.set import Set from sage.arith.srange import xsrange + B = 10 while True: llist = list(Set([self(x, y) for x in xsrange(-B, B) for y in xsrange(B)])) @@ -1750,6 +1742,7 @@ def solve_integer(self, n, *, algorithm='general', _flag=2): if self.is_reducible(): # square discriminant; not supported by PARI from sage.structure.factorization import Factorization + if isinstance(n, Factorization): n = ZZ(n.value()) else: @@ -1758,7 +1751,7 @@ def solve_integer(self, n, *, algorithm='general', _flag=2): if self._a: # https://math.stackexchange.com/a/980075 w = self.discriminant().sqrt() - r = (-self._b + (w if w != self._b else -w)) / (2*self._a) + r = (-self._b + (w if w != self._b else -w)) / (2 * self._a) p, q = r.as_integer_ratio() _, u, v = p.xgcd(q) M = Matrix(ZZ, [[v, p], [-u, q]]) @@ -1784,7 +1777,7 @@ def solve_integer(self, n, *, algorithm='general', _flag=2): y_num = n // x - Q._a * x if Q._b.divides(y_num): y = y_num // Q._b - return tuple([row[0]*x + row[1]*y for row in M.rows()]) + return tuple([row[0] * x + row[1] * y for row in M.rows()]) return None @@ -1817,6 +1810,7 @@ def form_class(self): True """ from sage.quadratic_forms.bqf_class_group import BQFClassGroup + return BQFClassGroup(self.discriminant())(self) @@ -1963,15 +1957,12 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): D4 = D % 4 if D4 == 2 or D4 == 3: raise ValueError("%s is not a discriminant" % D) - if D > 0: # Indefinite + if D > 0: # Indefinite if D.is_square(): b = D.sqrt() c = ZZ.zero() # -b/2 < a <= b/2 - form_list.extend(BinaryQF(a, b, c) - for a in xsrange((-b / 2).floor() + 1, - (b / 2).floor() + 1) - if not primitive_only or (gcd([a, b, c]) == 1)) + form_list.extend(BinaryQF(a, b, c) for a in xsrange((-b / 2).floor() + 1, (b / 2).floor() + 1) if not primitive_only or (gcd([a, b, c]) == 1)) # We follow the description of Buchmann/Vollmer 6.7.1. They # enumerate all reduced forms. We only want representatives. @@ -1986,7 +1977,7 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): for a in xsrange(Low_a, High_a + 1): if a == 0: continue - c = -A/a + c = -A / a if c in ZZ: if (not primitive_only) or gcd([a, b, c]) == 1: Q = BinaryQF(a, b, c) @@ -1998,17 +1989,17 @@ def BinaryQF_reduced_representatives(D, primitive_only=False, proper=True): Q1 = BinaryQF(-c, b, -a) form_list.append(Q) form_list.append(Q1) - else: # Definite + else: # Definite # Only iterate over positive a and over b of the same # parity as D such that 4a^2 + D <= b^2 <= a^2 - for a in xsrange(1, 1+((-D)//3).isqrt()): - a4 = 4*a - s = D + a*a4 - w = 1+(s-1).isqrt() if s > 0 else 0 + for a in xsrange(1, 1 + ((-D) // 3).isqrt()): + a4 = 4 * a + s = D + a * a4 + w = 1 + (s - 1).isqrt() if s > 0 else 0 if w % 2 != D % 2: w += 1 - for b in xsrange(w, a+1, 2): - t = b*b-D + for b in xsrange(w, a + 1, 2): + t = b * b - D if t % a4 == 0: c = t // a4 if not primitive_only or gcd([a, b, c]) == 1: diff --git a/src/sage/quadratic_forms/bqf_class_group.py b/src/sage/quadratic_forms/bqf_class_group.py index ac896d33f1f..1b2295e0767 100644 --- a/src/sage/quadratic_forms/bqf_class_group.py +++ b/src/sage/quadratic_forms/bqf_class_group.py @@ -214,8 +214,8 @@ def random_element(self): a = random_prime(B, proof=False, lbound=3) if self._disc.kronecker(a) == 1: break - b = ZZ(Mod(self._disc, 4*a).sqrt()) - c = (b**2 - self._disc) // (4*a) + b = ZZ(Mod(self._disc, 4 * a).sqrt()) + c = (b**2 - self._disc) // (4 * a) if randrange(2): b = -b return self(BinaryQF([a, b, c])) @@ -282,6 +282,7 @@ def order(self): # notion of class number. We may need the *narrow* class # number here; see PARI's documentation for qfbclassno(). from sage.rings.number_field.order import quadratic_order_class_number + return quadratic_order_class_number(self._disc) cardinality = order @@ -700,6 +701,7 @@ class representative `[a,b,c]` satisfying `f^2 \mid a` and `f \mid b` sage: proj(elt) == proj2(proj1(elt)) True """ + def __init__(self, G, H) -> None: r""" Initialize this morphism between class groups of binary diff --git a/src/sage/quadratic_forms/constructions.py b/src/sage/quadratic_forms/constructions.py index 95bd131215e..97d9dbb3244 100644 --- a/src/sage/quadratic_forms/constructions.py +++ b/src/sage/quadratic_forms/constructions.py @@ -1,6 +1,7 @@ """ Constructions of quadratic forms """ + ## # Some extra routines to make the QuadraticForm class more useful. ## @@ -44,7 +45,7 @@ def BezoutianQuadraticForm(f, g): # Check that f and g are polynomials with a common base ring if not isinstance(f, Polynomial) or not isinstance(g, Polynomial): raise TypeError("one of your inputs is not a polynomial") - if f.base_ring() != g.base_ring(): # TO DO: Change this to allow coercion! + if f.base_ring() != g.base_ring(): # TO DO: Change this to allow coercion! raise TypeError("these polynomials are not defined over the same coefficient ring") # Initialize the quadratic form @@ -55,7 +56,7 @@ def BezoutianQuadraticForm(f, g): Q = QuadraticForm(R, n) # Set the coefficients of Bezoutian - bez_poly = (f(a) * g(b) - f(b) * g(a)) // (b - a) # Truncated (exact) division here + bez_poly = (f(a) * g(b) - f(b) * g(a)) // (b - a) # Truncated (exact) division here for i in range(n): for j in range(i, n): if i == j: diff --git a/src/sage/quadratic_forms/extras.py b/src/sage/quadratic_forms/extras.py index 40ffec3280c..216f2adf9c6 100644 --- a/src/sage/quadratic_forms/extras.py +++ b/src/sage/quadratic_forms/extras.py @@ -102,7 +102,7 @@ def extend_to_primitive(A_input): """ # Deal with a list of vectors if not isinstance(A_input, Matrix): - A = matrix(A_input) # Make a matrix A with the given rows. + A = matrix(A_input) # Make a matrix A with the given rows. vec_output_flag = True else: A = A_input @@ -128,7 +128,7 @@ def extend_to_primitive(A_input): for i in range(n - k): B_new[i, n - i - 1] = 1 C = B.stack(B_new) - D = C * V**(-1) + D = C * V ** (-1) # Normalize for a positive determinant if D.det() < 0: @@ -188,6 +188,7 @@ def least_quadratic_nonresidue(p): if not p.is_prime(): raise ValueError("p must be a prime number > 2") from sage.arith.srange import xsrange + for r in xsrange(7, p): if legendre_symbol(r, p) == -1: return ZZ(r) diff --git a/src/sage/quadratic_forms/genera/genus.py b/src/sage/quadratic_forms/genera/genus.py index af4cf832431..07c4f65b6a3 100644 --- a/src/sage/quadratic_forms/genera/genus.py +++ b/src/sage/quadratic_forms/genera/genus.py @@ -81,6 +81,7 @@ def genera(sig_pair, determinant, max_scale=None, even=False) -> list: Genus symbol at 5: 1^3 125^1] """ from sage.misc.mrange import mrange_iter + # input checks determinant = ZZ(determinant) sig_pair = (ZZ(sig_pair[0]), ZZ(sig_pair[1])) @@ -174,6 +175,7 @@ def _local_genera(p, rank, det_val, max_scale, even): """ from sage.combinat.integer_lists.invlex import IntegerListsLex from sage.misc.mrange import cantor_product + scales_rks = [] # contains possibilities for scales and ranks for rkseq in IntegerListsLex(rank, length=max_scale + 1): # rank sequences # sum(rkseq) = rank @@ -289,7 +291,7 @@ def _blocks(b, even_only=False): b1 = copy(b) b1[3] = 0 b1[4] = 0 - d = (-1)**(rk // 2) % 8 + d = (-1) ** (rk // 2) % 8 for det in [d, d * (-3) % 8]: b1 = copy(b1) b1[2] = det @@ -298,21 +300,21 @@ def _blocks(b, even_only=False): if not even_only: for s in [(1, 2), (5, 6), (1, 6), (5, 2), (7, 0), (3, 4)]: b1 = copy(b) - b1[2] = s[0]*(-1)**(rk // 2 - 1) % 8 + b1[2] = s[0] * (-1) ** (rk // 2 - 1) % 8 b1[3] = 1 b1[4] = s[1] blocks.append(b1) for s in [(1, 4), (5, 0)]: b1 = copy(b) - b1[2] = s[0]*(-1)**(rk // 2 - 2) % 8 + b1[2] = s[0] * (-1) ** (rk // 2 - 2) % 8 b1[3] = 1 b1[4] = s[1] blocks.append(b1) elif rk % 2 == 1 and not even_only: # odd case for t in [1, 3, 5, 7]: - d = (-1)**(rk//2)*t % 8 - for det in [d, -3*d % 8]: + d = (-1) ** (rk // 2) * t % 8 + for det in [d, -3 * d % 8]: b1 = copy(b) b1[2] = det b1[3] = 1 @@ -359,7 +361,7 @@ def Genus(A, factored_determinant=None): """ if factored_determinant is None: D = A.determinant() - D = 2*D + D = 2 * D D = D.factor() else: D = factored_determinant * 2 @@ -444,15 +446,13 @@ def is_GlobalGenus(G) -> bool: if not is_2_adic_genus(sym): verbose(mesg="False in is_2_adic_genus(sym)", level=2) return False - if (a*b).kronecker(p) != 1: - verbose(mesg=f"False in ({a}*{b}).kronecker({p})", - level=2) + if (a * b).kronecker(p) != 1: + verbose(mesg=f"False in ({a}*{b}).kronecker({p})", level=2) return False oddity -= loc.excess() else: if a.kronecker(p) != b: - verbose(mesg=f"False in {a}.kronecker({p}) != *{b}", - level=2) + verbose(mesg=f"False in {a}.kronecker({p}) != *{b}", level=2) return False oddity += loc.excess() if oddity % 8 != 0: @@ -656,7 +656,7 @@ def canonical_2_adic_trains(genus_symbol_quintuple_list) -> list: # avoid a special case for the end of symbol # if a Jordan component has rank zero it is considered even. symbol = genus_symbol_quintuple_list - symbol.append([symbol[-1][0]+1, 0, 1, 0, 0]) # We have just modified the input globally! + symbol.append([symbol[-1][0] + 1, 0, 1, 0, 0]) # We have just modified the input globally! # Hence, we have to remove the last entry of symbol at the end. try: @@ -664,11 +664,11 @@ def canonical_2_adic_trains(genus_symbol_quintuple_list) -> list: new_train = [0] for i in range(1, len(symbol) - 1): # start a new train if there are two adjacent even symbols - prev, cur = symbol[i-1:i+1] + prev, cur = symbol[i - 1 : i + 1] if cur[0] - prev[0] > 2: trains.append(new_train) - new_train = [i] # create a new train starting at - elif (cur[0] - prev[0] == 2) and cur[3]*prev[3] == 0: + new_train = [i] # create a new train starting at + elif (cur[0] - prev[0] == 2) and cur[3] * prev[3] == 0: trains.append(new_train) new_train = [i] elif prev[3] == 0 and cur[3] == 0: @@ -764,15 +764,15 @@ def canonical_2_adic_reduction(genus_symbol_quintuple_list): trains = canonical_2_adic_trains(genus_symbol_quintuple_list) for train in trains: t = len(train) - for i in range(t-1): - t1 = train[t-i-1] + for i in range(t - 1): + t1 = train[t - i - 1] if canonical_symbol[t1][2] == -1: canonical_symbol[t1][2] = 1 - canonical_symbol[t1-1][2] *= -1 + canonical_symbol[t1 - 1][2] *= -1 for compart in compartments: - if t1-1 in compart or t1 in compart: + if t1 - 1 in compart or t1 in compart: o = canonical_symbol[compart[0]][4] - canonical_symbol[compart[0]][4] = (o+4) % 8 + canonical_symbol[compart[0]][4] = (o + 4) % 8 verbose(mesg="End sign walking: %s" % canonical_symbol, level=2) return canonical_symbol @@ -859,6 +859,7 @@ def signature_pair_of_matrix(A): ArithmeticError: given matrix is not invertible """ from sage.quadratic_forms.quadratic_form import QuadraticForm + s_vec = QuadraticForm(A.base_extend(A.base_ring().fraction_field())).signature_vector() # Check that the matrix is non-degenerate (i.e. no zero eigenvalues) @@ -924,8 +925,8 @@ def p_adic_symbol(A, p, val): F = MatrixSpace(QQ, n - r, n - r)(C * A * C.transpose()) U = F**-1 d = LCM([c.denominator() for c in U.list()]) - R = ZZ.quotient_ring(Integer(p)**(val + 3)) - u = R(d)**-1 + R = ZZ.quotient_ring(Integer(p) ** (val + 3)) + u = R(d) ** -1 MatR = MatrixSpace(R, n - r, n - r) MatZ = MatrixSpace(ZZ, n - r, n - r) U = MatZ(MatR(MatZ(U * d)) * u) @@ -933,7 +934,7 @@ def p_adic_symbol(A, p, val): # A = B*A*B.transpose() - X.transpose()*U*X X = C * A A = B * (A - X.transpose() * U * X) * B.transpose() - return [[s[0]+m0] + s[1:] for s in sym + p_adic_symbol(A, p, val)] + return [[s[0] + m0] + s[1:] for s in sym + p_adic_symbol(A, p, val)] def is_even_matrix(A) -> tuple[bool, int]: @@ -1018,34 +1019,34 @@ def split_odd(A): R = A.parent().base_ring() C = MatrixSpace(R, n0 - 1, n0)(0) u = A[i, i] - for j in range(n0-1): + for j in range(n0 - 1): if j < i: C[j, j] = 1 C[j, i] = -A[j, i] * u else: - C[j, j+1] = 1 - C[j, i] = -A[j+1, i] * u - B = C*A*C.transpose() + C[j, j + 1] = 1 + C[j, i] = -A[j + 1, i] * u + B = C * A * C.transpose() even, j = is_even_matrix(B) if even: I = A.parent()(1) # TODO: we could manually (re)construct the kernel here... if i == 0: - I[1, 0] = 1 - A[1, 0]*u + I[1, 0] = 1 - A[1, 0] * u i = 1 else: - I[0, i] = 1 - A[0, i]*u + I[0, i] = 1 - A[0, i] * u i = 0 - A = I*A*I.transpose() + A = I * A * I.transpose() u = A[i, i] - C = MatrixSpace(R, n0-1, n0)(0) - for j in range(n0-1): + C = MatrixSpace(R, n0 - 1, n0)(0) + for j in range(n0 - 1): if j < i: C[j, j] = 1 C[j, i] = -A[j, i] * u else: - C[j, j+1] = 1 - C[j, i] = -A[j+1, i] * u + C[j, j + 1] = 1 + C[j, i] = -A[j + 1, i] * u B = C * A * C.transpose() even, j = is_even_matrix(B) if even: @@ -1146,11 +1147,11 @@ def two_adic_symbol(A, val): n0 = A.nrows() # d0 = ZZ(A_8.determinant()) # no determinant over Z/8Z d0 = ZZ(R_8(MatrixSpace(ZZ, n)(A_8).determinant())) - if d0 == 0: # SANITY CHECK: The mod 8 determinant shouldn't be zero. + if d0 == 0: # SANITY CHECK: The mod 8 determinant shouldn't be zero. print("A:") print(A) assert False - even, _ = is_even_matrix(A_2) # Determine whether the matrix is even or odd. + even, _ = is_even_matrix(A_2) # Determine whether the matrix is even or odd. if even: return [[m0, n0, d0, 0, 0]] tr8 = trace_diag_mod_8(A_8) # Here we already know that A_8 is odd and diagonalizable mod 8. @@ -1182,14 +1183,14 @@ def two_adic_symbol(A, val): F = MatrixSpace(QQ, n - r, n - r)(C * A * C.transpose()) U = F**-1 d = LCM([c.denominator() for c in U.list()]) - R = ZZ.quotient_ring(Integer(2)**(val + 3)) - u = R(d)**-1 + R = ZZ.quotient_ring(Integer(2) ** (val + 3)) + u = R(d) ** -1 MatR = MatrixSpace(R, n - r, n - r) MatZ = MatrixSpace(ZZ, n - r, n - r) U = MatZ(MatR(MatZ(U * d)) * u) X = C * A - A = B * (A - X.transpose()*U*X) * B.transpose() - return [[s[0]+m0] + s[1:] for s in sym + two_adic_symbol(A, val)] + A = B * (A - X.transpose() * U * X) * B.transpose() + return [[s[0] + m0] + s[1:] for s in sym + two_adic_symbol(A, val)] class Genus_Symbol_p_adic_ring: @@ -1252,6 +1253,7 @@ class Genus_Symbol_p_adic_ring: sage: G3 = Genus_Symbol_p_adic_ring(p,s3); G3 Genus symbol at 3: 1^-3 3^1 """ + def __init__(self, prime, symbol, check=True): r""" Create the local genus symbol of given prime and local invariants. @@ -1561,6 +1563,7 @@ def automorphous_numbers(self): [1, 2, 5] """ from .normal_form import collect_small_blocks + automorphs = [] sym = self.symbol_tuple_list() G = self.gram_matrix().change_ring(ZZ) @@ -1575,7 +1578,7 @@ def automorphous_numbers(self): if I.count(r) > 2: I.remove(r) # products of all pairs - automorphs.extend(r1*r2 for r1 in I for r2 in I) + automorphs.extend(r1 * r2 for r1 in I for r2 in I) # supplement (i) for block in sym: @@ -1588,7 +1591,7 @@ def automorphous_numbers(self): u = 1 if s.prime_to_m_part(p).kronecker(p) == -1: u = up - v = (s.valuation(p) % 2) + v = s.valuation(p) % 2 sq = u * p**v automorphs1.add(sq) return list(automorphs1) @@ -1603,13 +1606,13 @@ def automorphous_numbers(self): I.append(block[0, 0]) else: # rank2 q = block[0, 1] - II += [2*q, 3*2*q, 5*2*q, 7*2*q] + II += [2 * q, 3 * 2 * q, 5 * 2 * q, 7 * 2 * q] L = I + II # We need to consider all pairs in L # since at most 2 elements are part of a pair # we need at most 2 of each type - for r in L: # remove triplicates + for r in L: # remove triplicates if L.count(r) > 2: L.remove(r) n = len(L) @@ -1620,7 +1623,7 @@ def automorphous_numbers(self): # supplement (i) for k in range(len(sym)): - s = sym[k:k+3] + s = sym[k : k + 3] if sum([b[1] for b in s if b[0] - s[0][0] < 4]) >= 3: automorphs += [ZZ.one(), ZZ(3), ZZ(5), ZZ(7)] break @@ -1800,10 +1803,10 @@ def mass(self): nI_I = ZZ.zero() # the total number of pairs of adjacent constituents f_q, # f_2q that are both of type I (odd) - for k in range(r-1): - if sym[k][3] == sym[k+1][3] == 1 and sym[k][0] + 1 == sym[k+1][0]: + for k in range(r - 1): + if sym[k][3] == sym[k + 1][3] == 1 and sym[k][0] + 1 == sym[k + 1][0]: nI_I += ZZ.one() - return m_p * ZZ(2)**(nI_I - nII) + return m_p * ZZ(2) ** (nI_I - nII) def _standard_mass(self): r""" @@ -1821,11 +1824,11 @@ def _standard_mass(self): n = self.dimension() p = self.prime() s = (n + 1) // 2 - std = 2 * QQ.prod(1 - p**(-2 * k) for k in range(1, s)) + std = 2 * QQ.prod(1 - p ** (-2 * k) for k in range(1, s)) if not n % 2: - D = ZZ(-1)**s * self.determinant() + D = ZZ(-1) ** s * self.determinant() epsilon = (4 * D).kronecker(p) - std *= (1 - epsilon * p**(-s)) + std *= 1 - epsilon * p ** (-s) return QQ.one() / std def _species_list(self) -> list: @@ -1848,7 +1851,7 @@ def _species_list(self) -> list: for k in range(len(sym)): n = ZZ(sym[k][1]) d = sym[k][2] - if n % 2 == 0 and d != ZZ(-1).kronecker(p)**(n // ZZ(2)): + if n % 2 == 0 and d != ZZ(-1).kronecker(p) ** (n // ZZ(2)): species = -n else: species = n @@ -1866,10 +1869,10 @@ def _species_list(self) -> list: else: symbols.append([k, 0, 1, 0, 0]) # avoid a case distinction - sym = [[-2, 0, 1, 0, 0], [-1, 0, 1, 0, 0]] + symbols + [[sym[-1][0]+1, 0, 1, 0, 0], [sym[-1][0] + 2, 0, 1, 0, 0]] - for k in range(1, len(sym)-1): + sym = [[-2, 0, 1, 0, 0], [-1, 0, 1, 0, 0]] + symbols + [[sym[-1][0] + 1, 0, 1, 0, 0], [sym[-1][0] + 2, 0, 1, 0, 0]] + for k in range(1, len(sym) - 1): free = True - if sym[k-1][3] == 1 or sym[k+1][3] == 1: + if sym[k - 1][3] == 1 or sym[k + 1][3] == 1: free = False n = sym[k][1] o = sym[k][4] @@ -1880,11 +1883,11 @@ def _species_list(self) -> list: else: t = (n // ZZ(2)) - ZZ.one() if free and (o == 0 or o == 1 or o == 7): - species = 2*t + species = 2 * t elif free and (o == 3 or o == 5 or o == 4): - species = -2*t + species = -2 * t else: - species = 2*t + 1 + species = 2 * t + 1 species_list.append(species) return species_list @@ -2021,7 +2024,7 @@ def determinant(self): 3 """ p = self._prime - return prod([p**(s[0] * s[1]) for s in self._symbol]) + return prod([p ** (s[0] * s[1]) for s in self._symbol]) det = determinant @@ -2177,12 +2180,12 @@ def excess(self): for s in self._symbol: if s[0] % 2 == 1 and s[2] in (3, 5): k += 1 - return Integer(sum([s[4] for s in self._symbol]) + 4*k).mod(8) + return Integer(sum([s[4] for s in self._symbol]) + 4 * k).mod(8) k = 0 for s in self._symbol: if s[0] % 2 == 1 and s[2] == -1: k += 1 - return Integer(sum([s[1] * (p**s[0]-1) for s in self._symbol]) + 4*k).mod(8) + return Integer(sum([s[1] * (p ** s[0] - 1) for s in self._symbol]) + 4 * k).mod(8) def scale(self): r""" @@ -2204,7 +2207,7 @@ def scale(self): """ if self.rank() == 0: return ZZ.zero() - return self.prime()**self._symbol[0][0] + return self.prime() ** self._symbol[0][0] def norm(self): r""" @@ -2228,7 +2231,7 @@ def norm(self): p = self.prime() if p == 2: fq = self._symbol[0] - return self.prime()**(fq[0] + 1 - fq[3]) + return self.prime() ** (fq[0] + 1 - fq[3]) return self.scale() def level(self): @@ -2243,7 +2246,7 @@ def level(self): """ if self.rank() == 0: return ZZ.one() - return self.prime()**self._symbol[-1][0] + return self.prime() ** self._symbol[-1][0] def trains(self) -> list: r""" @@ -2357,8 +2360,7 @@ def __init__(self, signature_pair, local_symbols, representative=None, check=Tru if not representative.is_symmetric(): raise ValueError("the representative must be a symmetric matrix") # check the symbols are sorted increasing by their prime - if any(local_symbols[i].prime() >= local_symbols[i+1].prime() - for i in range(len(local_symbols)-1)): + if any(local_symbols[i].prime() >= local_symbols[i + 1].prime() for i in range(len(local_symbols) - 1)): raise ValueError("the local symbols must be sorted by their primes") if local_symbols[0].prime() != 2: raise ValueError("the first symbol must be 2-adic") @@ -2570,6 +2572,7 @@ def _proper_spinor_kernel(self): Subgroup of Group of SpinorOperators at primes (2,) generated by (1, 1, f2)) """ from sage.quadratic_forms.genera.spinor_genus import SpinorOperators + syms = self.local_symbols() primes = tuple([sym.prime() for sym in syms]) A = SpinorOperators(primes) @@ -2578,9 +2581,7 @@ def _proper_spinor_kernel(self): sig = self.signature_pair_of_matrix() if sig[0] * sig[1] > 1: kernel_gens.append(A.delta(-1, prime=-1)) - kernel_gens.extend(A.delta(r, prime=sym.prime()) - for sym in syms - for r in sym.automorphous_numbers()) + kernel_gens.extend(A.delta(r, prime=sym.prime()) for sym in syms for r in sym.automorphous_numbers()) return A, A.subgroup(kernel_gens) def _improper_spinor_kernel(self): @@ -2639,6 +2640,7 @@ def spinor_generators(self, proper) -> list: [5] """ from sage.sets.primes import Primes + if proper: A, K = self._proper_spinor_kernel() else: @@ -2744,7 +2746,7 @@ def determinant(self): -24 """ _, n = self.signature_pair() - return (-1)**n * ZZ.prod(G.determinant() for G in self._local_symbols) + return (-1) ** n * ZZ.prod(G.determinant() for G in self._local_symbols) det = determinant @@ -2787,8 +2789,7 @@ def direct_sum(self, other): signature_pair = (p1 + p2, n1 + n2) primes = [s.prime() for s in self.local_symbols()] - primes.extend(s.prime() for s in other.local_symbols() - if s.prime() not in primes) + primes.extend(s.prime() for s in other.local_symbols() if s.prime() not in primes) primes.sort() local_symbols = [] for p in primes: @@ -2821,11 +2822,11 @@ def discriminant_form(self): [ 0 0 1/24] """ from sage.modules.torsion_quadratic_module import TorsionQuadraticForm + qL = [] for gs in self._local_symbols: p = gs._prime - qL.extend(_gram_from_jordan_block(p, block, True) - for block in gs.symbol_tuple_list()) + qL.extend(_gram_from_jordan_block(p, block, True) for block in gs.symbol_tuple_list()) q = matrix.block_diagonal(qL) return TorsionQuadraticForm(q) @@ -2860,6 +2861,7 @@ def rational_representative(self): QuadraticForm, quadratic_form_from_invariants, ) + sminus = self.signature_pair_of_matrix()[1] det = self.determinant() m = self.rank() @@ -2867,11 +2869,10 @@ def rational_representative(self): for sym in self._local_symbols: p = sym._prime # it is important to use the definition of Cassels here! - if QuadraticForm(QQ, 2*sym.gram_matrix()).hasse_invariant(p) == -1: + if QuadraticForm(QQ, 2 * sym.gram_matrix()).hasse_invariant(p) == -1: P.append(p) - q = quadratic_form_from_invariants(F=QQ, rk=m, det=det, - P=P, sminus=sminus) - return q.Hessian_matrix()/2 + q = quadratic_form_from_invariants(F=QQ, rk=m, det=det, P=P, sminus=sminus) + return q.Hessian_matrix() / 2 def _compute_representative(self, LLL=True): r""" @@ -2898,6 +2899,7 @@ def _compute_representative(self, LLL=True): IntegralLattice, local_modification, ) + q = self.rational_representative() # the associated quadratic form xGx.T/2 should be integral L = IntegralLattice(4 * q).maximal_overlattice() @@ -2921,6 +2923,7 @@ def _compute_representative(self, LLL=True): sig = self.signature_pair_of_matrix() if sig[0] * sig[1] != 0: from sage.env import SAGE_EXTCODE + m = pari(L) pari.read(Path(SAGE_EXTCODE) / "pari" / "simon" / "qfsolve.gp") m = pari('qflllgram_indefgoon')(m) @@ -3016,7 +3019,7 @@ def representatives(self, backend=None, algorithm=None): n = self.dimension() representatives = [] if n == 0: - return (self.representative(), ) + return (self.representative(),) if backend is None: if n > 6 and prod(self.signature_pair_of_matrix()) == 0: backend = 'magma' @@ -3036,10 +3039,10 @@ def representatives(self, backend=None, algorithm=None): if self.signature_pair_of_matrix()[1] != 0: e = -1 K = magma.Rationals() - gram = magma.Matrix(K, n, (e*self.representative()).list()) + gram = magma.Matrix(K, n, (e * self.representative()).list()) L = gram.LatticeWithGram() representatives = L.GenusRepresentatives() - representatives = [e*r.GramMatrix().sage() for r in representatives] + representatives = [e * r.GramMatrix().sage() for r in representatives] elif backend == "sage": if n == 1: return [self.representative()] @@ -3048,13 +3051,14 @@ def representatives(self, backend=None, algorithm=None): e = ZZ.one() if self.signature_pair()[0] == 0: e = ZZ(-1) - d = - 4 * self.determinant() + d = -4 * self.determinant() from sage.quadratic_forms.binary_qf import ( BinaryQF_reduced_representatives, ) + for q in BinaryQF_reduced_representatives(d, proper=False): if q[1] % 2 == 0: # we want integrality of the gram matrix - m = e*matrix(ZZ, 2, [q[0], q[1] // 2, q[1] // 2, q[2]]) + m = e * matrix(ZZ, 2, [q[0], q[1] // 2, q[1] // 2, q[2]]) if Genus(m) == self: representatives.append(m) if n > 2: @@ -3062,6 +3066,7 @@ def representatives(self, backend=None, algorithm=None): from sage.quadratic_forms.quadratic_form__neighbors import ( neighbor_iteration, ) + e = ZZ.one() if not self.is_even(): e = ZZ(2) @@ -3078,6 +3083,7 @@ def representatives(self, backend=None, algorithm=None): else: # we do a neighbor iteration from sage.sets.primes import Primes + P = Primes() # we need a prime with L_p isotropic # this is certainly the case if the lattice is even @@ -3091,7 +3097,7 @@ def representatives(self, backend=None, algorithm=None): p = P.next(p) representatives = neighbor_iteration(seeds, p, mass=Q.conway_mass(), algorithm=algorithm) representatives = [g.Hessian_matrix() for g in representatives] - representatives = [(g/e).change_ring(ZZ) for g in representatives] + representatives = [(g / e).change_ring(ZZ) for g in representatives] else: raise ValueError("unknown algorithm") for g in representatives: @@ -3150,16 +3156,17 @@ def _standard_mass(self): from sage.functions.transcendental import zeta from sage.symbolic.constants import pi from sage.symbolic.ring import SR + n = self.dimension() if n % 2 == 0: s = n // 2 else: s = (n // 2) + 1 - std = QQ(2) * pi**(-n * (n + 1) / QQ(4)) - std *= SR.prod(gamma(QQ(j) / QQ(2)) for j in range(1, n+1)) + std = QQ(2) * pi ** (-n * (n + 1) / QQ(4)) + std *= SR.prod(gamma(QQ(j) / QQ(2)) for j in range(1, n + 1)) std *= SR.prod(zeta(ZZ(2) * ZZ(k)) for k in range(1, s)) if n % 2 == 0: - D = ZZ(-1)**(s) * self.determinant() + D = ZZ(-1) ** (s) * self.determinant() std *= quadratic_L_function__exact(ZZ(s), D) d = fundamental_discriminant(D) # since quadratic_L_function__exact is different @@ -3168,7 +3175,7 @@ def _standard_mass(self): # the missing Euler factors for sym in self.local_symbols(): p = sym.prime() - std *= (1 - d.kronecker(p)*p**(-s)) + std *= 1 - d.kronecker(p) * p ** (-s) return std @cached_method @@ -3402,7 +3409,7 @@ def _gram_from_jordan_block(p, block, discr_form=False): q = q * 2**level if p != 2 and discr_form: q = matrix.identity(QQ, rk) - d = 2**(rk % 2) + d = 2 ** (rk % 2) if Integer(d).kronecker(p) != det: u = ZZ(_min_nonsquare(p)) q[0, 0] = u @@ -3418,6 +3425,7 @@ def _gram_from_jordan_block(p, block, discr_form=False): # Helper functions for mass computations + def M_p(species, p): r""" Return the diagonal factor `M_p` as a function of the species. @@ -3484,7 +3492,7 @@ def M_p(species, p): return QQ.one() n = species.abs() s = (n + 1) // ZZ(2) - mp = ZZ(2) * ZZ.prod(ZZ.one() - p**(-2 * k) for k in range(1, s)) + mp = ZZ(2) * ZZ.prod(ZZ.one() - p ** (-2 * k) for k in range(1, s)) if n % 2 == 0: - mp *= ZZ.one() - species.sign() * p**(-s) + mp *= ZZ.one() - species.sign() * p ** (-s) return QQ.one() / mp diff --git a/src/sage/quadratic_forms/genera/normal_form.py b/src/sage/quadratic_forms/genera/normal_form.py index d0081636e61..01dd3ef21f0 100644 --- a/src/sage/quadratic_forms/genera/normal_form.py +++ b/src/sage/quadratic_forms/genera/normal_form.py @@ -282,7 +282,7 @@ def p_adic_normal_form(G, p, precision=None, partial=False, debug=False): B = nondeg.stack(kernel) D = Matrix.block_diagonal([D, Matrix.zero(kernel.nrows())]) if debug: - assert B.determinant().valuation() == 0 # B is invertible! + assert B.determinant().valuation() == 0 # B is invertible! if p == 2: assert B * G * B.T == Matrix.block_diagonal(collect_small_blocks(D)) else: @@ -612,9 +612,9 @@ def _jordan_odd_adic(G): for i in range(cnt + 1, n): if D[i, cnt] != 0: c = D[i, cnt] // D[cnt, cnt] - B[i, :] += - c * B[cnt, :] - D[i, :] += - c * D[cnt, :] - D[:, i] += - c * D[:, cnt] + B[i, :] += -c * B[cnt, :] + D[i, :] += -c * D[cnt, :] + D[:, i] += -c * D[:, cnt] cnt = cnt + 1 else: # the smallest valuation is off the diagonal @@ -715,17 +715,17 @@ def _jordan_2_adic(G): # we split off a 2 x 2 block # if it is the last 2 x 2 block, there is nothing to do. if cnt != n - 2: - content = R(2 ** minval) - eqn_mat = D[cnt:cnt+2, cnt:cnt+2].list() + content = R(2**minval) + eqn_mat = D[cnt : cnt + 2, cnt : cnt + 2].list() eqn_mat = Matrix(R, 2, 2, [e // content for e in eqn_mat]) # calculate the inverse without using division inv = eqn_mat.adjugate() * eqn_mat.det().inverse_of_unit() - B1 = B[cnt:cnt+2, :] - B2 = D[cnt+2:, cnt:cnt+2] * inv + B1 = B[cnt : cnt + 2, :] + B2 = D[cnt + 2 :, cnt : cnt + 2] * inv for i in range(B2.nrows()): for j in range(B2.ncols()): B2[i, j] = B2[i, j] // content - B[cnt + 2:, :] -= B2 * B1 + B[cnt + 2 :, :] -= B2 * B1 D[cnt:, cnt:] = B[cnt:, :] * G * B[cnt:, :].transpose() cnt += 2 return D, B @@ -840,10 +840,10 @@ def _normalize(G, normal_odd=True): B[i, :] *= (v * d.inverse_of_unit()).sqrt() D = B * G * B.T for i in range(n - 1): - if D[i, i + 1] != 0: # there is a 2 x 2 block here - block = D[i:i+2, i:i+2] + if D[i, i + 1] != 0: # there is a 2 x 2 block here + block = D[i : i + 2, i : i + 2] trafo = _normalize_2x2(block) - B[i:i+2, :] = trafo * B[i:i+2, :] + B[i : i + 2, :] = trafo * B[i : i + 2, :] D = B * G * B.T return D, B @@ -895,14 +895,15 @@ def _normalize_2x2(G): """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.modules.free_module_element import vector + B = copy(G.parent().identity_matrix()) R = G.base_ring() P = PolynomialRing(R, 'x') x = P.gen() # The input must be an even block - odd1 = (G[0, 0].valuation() < G[1, 0].valuation()) - odd2 = (G[1, 1].valuation() < G[1, 0].valuation()) + odd1 = G[0, 0].valuation() < G[1, 0].valuation() + odd2 = G[1, 1].valuation() < G[1, 0].valuation() if odd1 or odd2: raise ValueError("not a valid 2 x 2 block") scale = 2 ** G[0, 1].valuation() @@ -1072,7 +1073,7 @@ def _partial_normal_form_of_block(G): """ D = copy(G) n = D.ncols() - B = copy(G.parent().identity_matrix()) # the transformation matrix + B = copy(G.parent().identity_matrix()) # the transformation matrix blocks = _get_small_block_indices(D) # collect the indices of forms of types U, V and W U = [] @@ -1324,8 +1325,7 @@ def _relations(G, n): e3 = G[2, 2].unit_part() B = Matrix(R, 3, 3, [1, 1, 1, e2, -e1, 0, e3, 0, -e1]) elif n == 3: - B = Matrix(R, 4, 4, - [1, 1, 1, 0, 1, 1, 0, 1, 1, 0, -1, -1, 0, 1, -1, -1]) + B = Matrix(R, 4, 4, [1, 1, 1, 0, 1, 1, 0, 1, 1, 0, -1, -1, 0, 1, -1, -1]) elif n == 4: raise NotImplementedError("relation 4 is not needed") elif n == 5: @@ -1333,10 +1333,7 @@ def _relations(G, n): e2 = G[3, 3].unit_part() if mod(e1, 4) != mod(e2, 4): raise ValueError("W is of the wrong type for relation 5") - B = Matrix(R, 4, [1, 0, 1, 1, - 0, 1, 1, 1, - -e2, -e2, 0, 3, - -e1, -e1, 2 * e2 + 3, -2 * e1]) + B = Matrix(R, 4, [1, 0, 1, 1, 0, 1, 1, 1, -e2, -e2, 0, 3, -e1, -e1, 2 * e2 + 3, -2 * e1]) elif n == 6: if G[0, 0].valuation() + 1 != G[1, 1].valuation(): raise ValueError("wrong scales for relation 6") @@ -1349,21 +1346,14 @@ def _relations(G, n): elif n == 8: e = G[2, 2].unit_part() if G[0, 0] == 0: - B = Matrix(R, 3, 3, [e, 0, -1, - 0, e, -1, - 2, 2, 1]) + B = Matrix(R, 3, 3, [e, 0, -1, 0, e, -1, 2, 2, 1]) else: - B = Matrix(R, 3, 3, [1, 0, 1, - 0, 1, 1, - 2 * e, 2 * e, - 3]) + B = Matrix(R, 3, 3, [1, 0, 1, 0, 1, 1, 2 * e, 2 * e, -3]) elif n == 9: e1 = G[0, 0].unit_part() e2 = G[1, 1].unit_part() e3 = G[2, 2].unit_part() - B = Matrix(R, 3, 3, [1, 0, 1, - 2 * e3, 1, -e1, - -2 * e2 * e3, 2 * e1**2 * e3 + 4 * e1 * e3**2, - e1 * e2]) + B = Matrix(R, 3, 3, [1, 0, 1, 2 * e3, 1, -e1, -2 * e2 * e3, 2 * e1**2 * e3 + 4 * e1 * e3**2, e1 * e2]) elif n == 10: e1 = G[0, 0].unit_part() e2 = G[1, 1].unit_part() @@ -1424,19 +1414,19 @@ def _two_adic_normal_forms(G, partial=False): # UVlist[k] is a list of indices of the block of scale p^k. # It contains the indices of the part of types U or V. # So it may be empty. - UVlist = [[], []] # empty lists are appended to avoid special cases. + UVlist = [[], []] # empty lists are appended to avoid special cases. # same as UVlist but contains the indices of the part of type W Wlist = [[], []] # homogeneous normal form for each part for k in range(scales[-1] - scales[0] + 1): if k + scales[0] in scales: i = scales.index(k + scales[0]) - Gk = G[h[i]:h[i + 1], h[i]:h[i + 1]] + Gk = G[h[i] : h[i + 1], h[i] : h[i + 1]] Dk, Bk, wk = _partial_normal_form_of_block(Gk) - B[h[i]:h[i + 1], :] = Bk * B[h[i]:h[i + 1], :] + B[h[i] : h[i + 1], :] = Bk * B[h[i] : h[i + 1], :] if not partial: Dk, B1k = _homogeneous_normal_form(Dk, wk) - B[h[i]:h[i + 1], :] = B1k * B[h[i]:h[i + 1], :] + B[h[i] : h[i + 1], :] = B1k * B[h[i] : h[i + 1], :] UVlist.append(list(range(h[i], h[i + 1] - wk))) Wlist.append(list(range(h[i + 1] - wk, h[i + 1]))) else: @@ -1458,7 +1448,7 @@ def _two_adic_normal_forms(G, partial=False): UVm = UVlist[k - 1] V = UVlist[k][-2:] if V and D[V[0], V[0]] == 0: - V = [] # it is U not V + V = [] # it is U not V # condition b) if Wm: if len(V) == 2: @@ -1482,8 +1472,7 @@ def _two_adic_normal_forms(G, partial=False): # 0 if there is no type V component or # 2 if there is a single type V component # a = [[0,1], [2,3], [2,5], [0,7], [0,1,1], [2,1,3], [0,7,7], [0,1,7]] - b = [[0, 5], [2, 7], [2, 1], [0, 3], - [0, 1, 5], [2, 1, 7], [0, 3, 7], [0, 1, 3]] + b = [[0, 5], [2, 7], [2, 1], [0, 3], [0, 1, 5], [2, 1, 7], [0, 3, 7], [0, 1, 3]] if x in b: w = W[-1] if x == [0, 3, 7]: diff --git a/src/sage/quadratic_forms/genera/spinor_genus.py b/src/sage/quadratic_forms/genera/spinor_genus.py index 4da6f0a2fbd..a8cdb0100ac 100644 --- a/src/sage/quadratic_forms/genera/spinor_genus.py +++ b/src/sage/quadratic_forms/genera/spinor_genus.py @@ -26,8 +26,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.groups.abelian_gps.abelian_group_gap import (AbelianGroupGap, - AbelianGroupElement_gap) +from sage.groups.abelian_gps.abelian_group_gap import AbelianGroupGap, AbelianGroupElement_gap from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -92,6 +91,7 @@ class SpinorOperators(AbelianGroupGap): sage: SpinorOperators((2, 3, 7)) Group of SpinorOperators at primes (2, 3, 7) """ + def __init__(self, primes): r""" Initialize the group of spinor operators. @@ -224,19 +224,16 @@ def delta(self, r, prime=None): if prime is None: if any(p.divides(r) for p in self._primes): raise ValueError(f"r must not be divisible by {self._primes}") - return self.prod([self.to_square_class(r, p) - for p in self._primes]) + return self.prod([self.to_square_class(r, p) for p in self._primes]) prime = ZZ(prime) if prime == -1: r = r.sign() - return self.prod([self.to_square_class(r, p) - for p in self._primes]) + return self.prod([self.to_square_class(r, p) for p in self._primes]) if prime not in self._primes: raise ValueError("prime must be among %s" % self._primes) v, u = r.val_unit(prime) pv = prime**v - y = self.prod([self.to_square_class(pv, q) - for q in self._primes if q != prime]) + y = self.prod([self.to_square_class(pv, q) for q in self._primes if q != prime]) if prime in self._primes: y *= self.to_square_class(u, p=prime) return y diff --git a/src/sage/quadratic_forms/qfsolve.py b/src/sage/quadratic_forms/qfsolve.py index 09e29e28612..5de4a1c2873 100644 --- a/src/sage/quadratic_forms/qfsolve.py +++ b/src/sage/quadratic_forms/qfsolve.py @@ -228,6 +228,7 @@ def solve(self, c=0): ... ArithmeticError: no solution found (local obstruction at some prime factor of det(self.matrix())) """ + def check_obstruction(x): """ Local helper. ``x`` is the return value of ``qfsolve``. @@ -258,7 +259,7 @@ def check_obstruction(x): # If c != 0, define a new quadratic form Q = self - c*z^2 d = self.dim() - N = matrix(self.base_ring(), d+1, d+1) + N = matrix(self.base_ring(), d + 1, d + 1) for i in range(d): for j in range(d): N[i, j] = M[i, j] @@ -274,7 +275,7 @@ def check_obstruction(x): x = x[:-1] # If z != 0, then Q(x/z) = c if z: - return x * (1/z) + return x * (1 / z) # Case 2: We found a solution self(x) = 0. Let e be any vector such # that B(x,e) != 0, where B is the bilinear form corresponding to self. @@ -282,7 +283,7 @@ def check_obstruction(x): # Let a = (c - self(e))/(2B(x,e)) and let y = e + a*x. # Then self(y) = B(e + a*x, e + a*x) = self(e) + 2B(e, a*x) # = self(e) + 2([c - self(e)]/[2B(x,e)]) * B(x,e) = c. - e = vector([1] + [0] * (d-1)) + e = vector([1] + [0] * (d - 1)) i = 0 while self.bilinear_map(x, e) == 0: e[i] = 0 @@ -293,9 +294,10 @@ def check_obstruction(x): # subspace with respect to self, which is not what we want i = next(i for i in range(d) if x[i]) from sage.quadratic_forms.quadratic_form import QuadraticForm + x = QuadraticForm(self.matrix().delete_rows([0]).delete_columns([0])).solve(c) return vector([*x[:i], 0, *x[i:]]) e[i] = 1 a = (c - self(e)) / (2 * self.bilinear_map(x, e)) - return e + a*x + return e + a * x diff --git a/src/sage/quadratic_forms/quadratic_form.py b/src/sage/quadratic_forms/quadratic_form.py index 2b080d20669..60b7aaaf253 100644 --- a/src/sage/quadratic_forms/quadratic_form.py +++ b/src/sage/quadratic_forms/quadratic_form.py @@ -100,6 +100,7 @@ def quadratic_form_from_invariants(F, rk, det, P, sminus): ValueError: invariants do not define a rational quadratic form """ from sage.arith.misc import hilbert_symbol + # normalize input if F != QQ: raise NotImplementedError('base field must be QQ. If you want this over any field, implement weak approximation.') @@ -108,7 +109,7 @@ def quadratic_form_from_invariants(F, rk, det, P, sminus): d = QQ(det).squarefree_part() sminus = ZZ(sminus) # check if the invariants define a global quadratic form - if d.sign() != (-1)**sminus: + if d.sign() != (-1) ** sminus: raise ValueError("invariants do not define a rational quadratic form") if rk == 1 and len(P) != 0: raise ValueError("invariants do not define a rational quadratic form") @@ -130,8 +131,7 @@ def quadratic_form_from_invariants(F, rk, det, P, sminus): a = ZZ.one() elif rk == 3: Pprime = [p for p in P if hilbert_symbol(-1, -d, p) == 1] - Pprime += [p for p in (2 * d).prime_divisors() - if hilbert_symbol(-1, -d, p) == -1 and p not in P] + Pprime += [p for p in (2 * d).prime_divisors() if hilbert_symbol(-1, -d, p) == -1 and p not in P] if sminus > 0: a = ZZ(-1) else: @@ -146,9 +146,7 @@ def quadratic_form_from_invariants(F, rk, det, P, sminus): S += [-1] a = QQ.hilbert_symbol_negative_at_S(S, -d) a = ZZ(a) - P = ([p for p in P if hilbert_symbol(a, -d, p) == 1] - + [p for p in (2 * a * d).prime_divisors() - if hilbert_symbol(a, -d, p) == -1 and p not in P]) + P = [p for p in P if hilbert_symbol(a, -d, p) == 1] + [p for p in (2 * a * d).prime_divisors() if hilbert_symbol(a, -d, p) == -1 and p not in P] sminus = max(0, sminus - 1) rk = rk - 1 d = a * d @@ -280,12 +278,7 @@ class QuadraticForm(SageObject): # --------------------------- # Routines to compute the p-adic local normal form - lazy_import("sage.quadratic_forms.quadratic_form__local_normal_form", [ - "find_entry_with_minimal_scale_at_prime", - "local_normal_form", - "jordan_blocks_by_scale_and_unimodular", - "jordan_blocks_in_unimodular_list_by_scale_power" - ]) + lazy_import("sage.quadratic_forms.quadratic_form__local_normal_form", ["find_entry_with_minimal_scale_at_prime", "local_normal_form", "jordan_blocks_by_scale_and_unimodular", "jordan_blocks_in_unimodular_list_by_scale_power"]) # Routines to compute local densities by counting solutions of various types from sage.quadratic_forms.quadratic_form__count_local_2 import ( @@ -344,10 +337,7 @@ class QuadraticForm(SageObject): ) # Routines to be called by the user to compute local densities - lazy_import('sage.quadratic_forms.quadratic_form__local_density_interfaces', [ - 'local_density', - 'local_primitive_density' - ]) + lazy_import('sage.quadratic_forms.quadratic_form__local_density_interfaces', ['local_density', 'local_primitive_density']) # Routines for computing with ternary forms from sage.quadratic_forms.quadratic_form__ternary_Tornaria import ( @@ -385,9 +375,7 @@ class QuadraticForm(SageObject): ) # Routines to compute the product of all local densities - lazy_import('sage.quadratic_forms.quadratic_form__siegel_product', [ - 'siegel_product' - ]) + lazy_import('sage.quadratic_forms.quadratic_form__siegel_product', ['siegel_product']) # Routines to compute p-neighbors from sage.quadratic_forms.quadratic_form__neighbors import ( @@ -406,52 +394,36 @@ class QuadraticForm(SageObject): reduced_binary_form1, reduced_ternary_form__Dickson, ) + # Wrappers for Conway-Sloane genus routines (in ./genera/) - lazy_import('sage.quadratic_forms.quadratic_form__genus', [ - 'global_genus_symbol', - 'local_genus_symbol', - 'CS_genus_symbol_list' - ]) + lazy_import('sage.quadratic_forms.quadratic_form__genus', ['global_genus_symbol', 'local_genus_symbol', 'CS_genus_symbol_list']) # Routines to compute local masses for ZZ. - lazy_import('sage.quadratic_forms.quadratic_form__mass', [ - 'shimura_mass__maximal', - 'GHY_mass__maximal' - ]) - lazy_import('sage.quadratic_forms.quadratic_form__mass__Siegel_densities', [ - 'mass__by_Siegel_densities', - 'Pall_mass_density_at_odd_prime', - 'Watson_mass_at_2', - 'Kitaoka_mass_at_2', - 'mass_at_two_by_counting_mod_power' - ]) - lazy_import('sage.quadratic_forms.quadratic_form__mass__Conway_Sloane_masses', [ - 'parity', - 'is_even', - 'is_odd', - 'conway_species_list_at_odd_prime', - 'conway_species_list_at_2', - 'conway_octane_of_this_unimodular_Jordan_block_at_2', - 'conway_diagonal_factor', - 'conway_cross_product_doubled_power', - 'conway_type_factor', - 'conway_p_mass', - 'conway_standard_p_mass', - 'conway_standard_mass', - 'conway_mass' - # conway_generic_mass, \ - # conway_p_mass_adjustment - ]) + lazy_import('sage.quadratic_forms.quadratic_form__mass', ['shimura_mass__maximal', 'GHY_mass__maximal']) + lazy_import('sage.quadratic_forms.quadratic_form__mass__Siegel_densities', ['mass__by_Siegel_densities', 'Pall_mass_density_at_odd_prime', 'Watson_mass_at_2', 'Kitaoka_mass_at_2', 'mass_at_two_by_counting_mod_power']) + lazy_import( + 'sage.quadratic_forms.quadratic_form__mass__Conway_Sloane_masses', + [ + 'parity', + 'is_even', + 'is_odd', + 'conway_species_list_at_odd_prime', + 'conway_species_list_at_2', + 'conway_octane_of_this_unimodular_Jordan_block_at_2', + 'conway_diagonal_factor', + 'conway_cross_product_doubled_power', + 'conway_type_factor', + 'conway_p_mass', + 'conway_standard_p_mass', + 'conway_standard_mass', + 'conway_mass', + # conway_generic_mass, \ + # conway_p_mass_adjustment + ], + ) # Routines to check local representability of numbers - lazy_import('sage.quadratic_forms.quadratic_form__local_representation_conditions', [ - 'local_representation_conditions', - 'is_locally_universal_at_prime', - 'is_locally_universal_at_all_primes', - 'is_locally_universal_at_all_places', - 'is_locally_represented_number_at_place', - 'is_locally_represented_number' - ]) + lazy_import('sage.quadratic_forms.quadratic_form__local_representation_conditions', ['local_representation_conditions', 'is_locally_universal_at_prime', 'is_locally_universal_at_all_primes', 'is_locally_universal_at_all_places', 'is_locally_represented_number_at_place', 'is_locally_represented_number']) # Routines to make a split local covering of the given quadratic form. from sage.quadratic_forms.quadratic_form__split_local_covering import ( @@ -462,16 +434,7 @@ class QuadraticForm(SageObject): ) # Routines to make automorphisms of the given quadratic form. - lazy_import('sage.quadratic_forms.quadratic_form__automorphisms', [ - 'basis_of_short_vectors', - 'short_vector_list_up_to_length', - 'short_primitive_vector_list_up_to_length', - '_compute_automorphisms', - 'automorphism_group', - 'automorphisms', - 'number_of_automorphisms', - 'set_number_of_automorphisms' - ]) + lazy_import('sage.quadratic_forms.quadratic_form__automorphisms', ['basis_of_short_vectors', 'short_vector_list_up_to_length', 'short_primitive_vector_list_up_to_length', '_compute_automorphisms', 'automorphism_group', 'automorphisms', 'number_of_automorphisms', 'set_number_of_automorphisms']) # Routines to test the local and global equivalence/isometry of two quadratic forms. from sage.quadratic_forms.quadratic_form__equivalence_testing import ( @@ -482,9 +445,7 @@ class QuadraticForm(SageObject): ) # Routines for solving equations of the form Q(x) = c. - lazy_import('sage.quadratic_forms.qfsolve', [ - 'solve' - ]) + lazy_import('sage.quadratic_forms.qfsolve', ['solve']) # Genus lazy_import("sage.quadratic_forms.genera.genus", ["genera"]) @@ -757,8 +718,8 @@ def _latex_(self) -> str: out_str += " * & " else: out_str += str(self[i, j]) + " & " -# if i < (n-1): -# out_str += "\\" + # if i < (n-1): + # out_str += "\\" out_str += "\\end{array} \\right]" return out_str @@ -1090,7 +1051,7 @@ def _is_even_symmetric_matrix_(self, A, R=None): raise TypeError("A is not a matrix.") ring_coerce_test = True - if R is None: # This allows us to omit the ring from the variables, and take it from the matrix + if R is None: # This allows us to omit the ring from the variables, and take it from the matrix R = A.base_ring() ring_coerce_test = False @@ -1353,14 +1314,14 @@ def from_polynomial(poly): from sage.rings.polynomial.multi_polynomial_ring_base import ( MPolynomialRing_base, ) + if not isinstance(R, MPolynomialRing_base): raise TypeError(f'not a multivariate polynomial ring: {R}') if not all(mon.degree() == 2 for mon in poly.monomials()): raise ValueError('polynomial has monomials of degree != 2') base = R.base_ring() vs = R.gens() - coeffs = [poly.monomial_coefficient(v * w) - for i, v in enumerate(vs) for w in vs[i:]] + coeffs = [poly.monomial_coefficient(v * w) for i, v in enumerate(vs) for w in vs[i:]] return QuadraticForm(base, len(vs), coeffs) def is_primitive(self) -> bool: @@ -1401,8 +1362,7 @@ def primitive(self): if self.base_ring() != ZZ: raise TypeError("the given quadratic form must be defined over ZZ") g = self.gcd() - return QuadraticForm(ZZ, self.dim(), - [x // g for x in self.coefficients()]) + return QuadraticForm(ZZ, self.dim(), [x // g for x in self.coefficients()]) def adjoint_primitive(self): """ @@ -1509,7 +1469,7 @@ def Gram_det(self): sage: Q.Gram_det() 2 """ - return self.det() / ZZ(2**self.dim()) + return self.det() / ZZ(2 ** self.dim()) def change_ring(self, R): """ @@ -1598,7 +1558,7 @@ def level(self): # Check invertibility and find the inverse try: - mat_inv = self.matrix()**(-1) + mat_inv = self.matrix() ** (-1) except ZeroDivisionError: raise TypeError("the quadratic form is degenerate") diff --git a/src/sage/quadratic_forms/quadratic_form__automorphisms.py b/src/sage/quadratic_forms/quadratic_form__automorphisms.py index 3d49cec8cd7..47075012992 100644 --- a/src/sage/quadratic_forms/quadratic_form__automorphisms.py +++ b/src/sage/quadratic_forms/quadratic_form__automorphisms.py @@ -76,8 +76,7 @@ def basis_of_short_vectors(self, show_lengths=False): vector_list_by_length[l].append(vector([-x for x in v])) # Make a matrix from the column vectors (in order of ascending length). - sorted_list = [v for i in range(len(vector_list_by_length)) - for v in vector_list_by_length[i]] + sorted_list = [v for i in range(len(vector_list_by_length)) for v in vector_list_by_length[i]] sorted_matrix = Matrix(sorted_list).transpose() # Determine a basis of vectors of minimal length @@ -177,8 +176,7 @@ def short_vector_list_up_to_length(self, len_bound, up_to_sign_flag=False): 45902280 """ if not self.is_positive_definite(): - raise ValueError("Quadratic form must be positive definite " - "in order to enumerate short vectors") + raise ValueError("Quadratic form must be positive definite " "in order to enumerate short vectors") from sage.libs.pari import pari @@ -246,8 +244,7 @@ def short_primitive_vector_list_up_to_length(self, len_bound, up_to_sign_flag=Fa full_vec_list = self.short_vector_list_up_to_length(len_bound, up_to_sign_flag) # Make a new list of the primitive vectors - prim_vec_list = [[v for v in L if GCD(v) == 1] - for L in full_vec_list] + prim_vec_list = [[v for v in L if GCD(v) == 1] for L in full_vec_list] # Return the list of primitive vectors return prim_vec_list @@ -326,6 +323,7 @@ def automorphism_group(self): from sage.matrix.matrix_space import MatrixSpace from sage.groups.matrix_gps.finitely_generated import MatrixGroup + MS = MatrixSpace(self.base_ring().fraction_field(), self.dim(), self.dim()) gens = [MS(x.sage()) for x in self.__automorphisms_pari] return MatrixGroup(gens) diff --git a/src/sage/quadratic_forms/quadratic_form__count_local_2.py b/src/sage/quadratic_forms/quadratic_form__count_local_2.py index 3805945d0f7..0c7b7dbe0b9 100644 --- a/src/sage/quadratic_forms/quadratic_form__count_local_2.py +++ b/src/sage/quadratic_forms/quadratic_form__count_local_2.py @@ -4,6 +4,7 @@ This file provides more user-friendly Python front-ends to the Cython code in :mod:`sage.quadratic_forms.count_local`. """ + ################################################################ # Methods for counting/computing the number of representations # # of a number by a quadratic form in Z/(p^k)Z of various types # @@ -70,6 +71,7 @@ def count_congruence_solutions_as_vector(self, p, k, m, zvec, nzvec): # // Front-ends for our counting routines // # ////////////////////////////////////////// + def count_congruence_solutions(self, p, k, m, zvec, nzvec): r""" Count all solutions of `Q(x) = m` (mod `p^k`) satisfying the diff --git a/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py b/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py index 1c8e6e90e9f..628cb8d8291 100644 --- a/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py +++ b/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py @@ -5,14 +5,10 @@ - Anna Haensch (2014-12-01): added test for rational isometry """ + from typing import Any -from sage.arith.misc import (hilbert_symbol, - GCD, - is_prime, - legendre_symbol, - prime_divisors, - valuation) +from sage.arith.misc import hilbert_symbol, GCD, is_prime, legendre_symbol, prime_divisors, valuation from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -22,6 +18,7 @@ # (For now, we require both forms to be positive definite.) # ############################################################################## + def is_globally_equivalent_to(self, other, return_matrix=False) -> bool | Any: r""" Determine if the current quadratic form is equivalent to the @@ -115,8 +112,7 @@ def is_globally_equivalent_to(self, other, return_matrix=False) -> bool | Any: return True -def is_locally_equivalent_to(self, other, check_primes_only=False, - force_jordan_equivalence_test=False) -> bool: +def is_locally_equivalent_to(self, other, check_primes_only=False, force_jordan_equivalence_test=False) -> bool: r""" Determine if the current quadratic form (defined over `\ZZ`) is locally equivalent to the given form over the real numbers and the @@ -225,9 +221,7 @@ def has_equivalent_Jordan_decomposition_at_prime(self, other, p) -> bool: # Deal with odd primes: Check that the Jordan component scales, dimensions, and discriminants are the same if p != 2: for i in range(len(self_jordan)): - if (self_jordan[i][0] != other_jordan[i][0]) \ - or (self_jordan[i][1].dim() != other_jordan[i][1].dim()) \ - or (legendre_symbol(self_jordan[i][1].det() * other_jordan[i][1].det(), p) != 1): + if (self_jordan[i][0] != other_jordan[i][0]) or (self_jordan[i][1].dim() != other_jordan[i][1].dim()) or (legendre_symbol(self_jordan[i][1].det() * other_jordan[i][1].det(), p) != 1): return False # All tests passed for an odd prime. @@ -237,41 +231,35 @@ def has_equivalent_Jordan_decomposition_at_prime(self, other, p) -> bool: if p == 2: # Useful definition - t = len(self_jordan) # Define t = Number of Jordan components + t = len(self_jordan) # Define t = Number of Jordan components # Check that all Jordan Invariants are the same (scale, dim, and norm) for i in range(t): - if (self_jordan[i][0] != other_jordan[i][0]) \ - or (self_jordan[i][1].dim() != other_jordan[i][1].dim()) \ - or (valuation(GCD(self_jordan[i][1].coefficients()), p) != valuation(GCD(other_jordan[i][1].coefficients()), p)): + if (self_jordan[i][0] != other_jordan[i][0]) or (self_jordan[i][1].dim() != other_jordan[i][1].dim()) or (valuation(GCD(self_jordan[i][1].coefficients()), p) != valuation(GCD(other_jordan[i][1].coefficients()), p)): return False # Use O'Meara's isometry test 93:29 on p277. # ------------------------------------------ # List of norms, scales, and dimensions for each i - scale_list = [ZZ(2)**self_jordan[i][0] for i in range(t)] - norm_list = [ZZ(2)**(self_jordan[i][0] + valuation(GCD(self_jordan[i][1].coefficients()), 2)) for i in range(t)] + scale_list = [ZZ(2) ** self_jordan[i][0] for i in range(t)] + norm_list = [ZZ(2) ** (self_jordan[i][0] + valuation(GCD(self_jordan[i][1].coefficients()), 2)) for i in range(t)] dim_list = [(self_jordan[i][1].dim()) for i in range(t)] # List of Hessian determinants and Hasse invariants for each Jordan (sub)chain # (Note: This is not the same as O'Meara's Gram determinants, but ratios are the same!) -- NOT SO GOOD... # But it matters in condition (ii), so we multiply all by 2 (instead of dividing by 2 since only square-factors matter, and it's easier.) j = 0 - self_chain_det_list = [self_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j])] - other_chain_det_list = [other_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j])] - self_hasse_chain_list = [self_jordan[j][1].scale_by_factor(ZZ(2)**self_jordan[j][0]).hasse_invariant__OMeara(2)] - other_hasse_chain_list = [other_jordan[j][1].scale_by_factor(ZZ(2)**other_jordan[j][0]).hasse_invariant__OMeara(2)] + self_chain_det_list = [self_jordan[j][1].Gram_det() * (scale_list[j] ** dim_list[j])] + other_chain_det_list = [other_jordan[j][1].Gram_det() * (scale_list[j] ** dim_list[j])] + self_hasse_chain_list = [self_jordan[j][1].scale_by_factor(ZZ(2) ** self_jordan[j][0]).hasse_invariant__OMeara(2)] + other_hasse_chain_list = [other_jordan[j][1].scale_by_factor(ZZ(2) ** other_jordan[j][0]).hasse_invariant__OMeara(2)] for j in range(1, t): - self_chain_det_list.append(self_chain_det_list[j-1] * self_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j])) - other_chain_det_list.append(other_chain_det_list[j-1] * other_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j])) - self_hasse_chain_list.append(self_hasse_chain_list[j-1] - * hilbert_symbol(self_chain_det_list[j-1], self_jordan[j][1].Gram_det(), 2) - * self_jordan[j][1].hasse_invariant__OMeara(2)) - other_hasse_chain_list.append(other_hasse_chain_list[j-1] - * hilbert_symbol(other_chain_det_list[j-1], other_jordan[j][1].Gram_det(), 2) - * other_jordan[j][1].hasse_invariant__OMeara(2)) + self_chain_det_list.append(self_chain_det_list[j - 1] * self_jordan[j][1].Gram_det() * (scale_list[j] ** dim_list[j])) + other_chain_det_list.append(other_chain_det_list[j - 1] * other_jordan[j][1].Gram_det() * (scale_list[j] ** dim_list[j])) + self_hasse_chain_list.append(self_hasse_chain_list[j - 1] * hilbert_symbol(self_chain_det_list[j - 1], self_jordan[j][1].Gram_det(), 2) * self_jordan[j][1].hasse_invariant__OMeara(2)) + other_hasse_chain_list.append(other_hasse_chain_list[j - 1] * hilbert_symbol(other_chain_det_list[j - 1], other_jordan[j][1].Gram_det(), 2) * other_jordan[j][1].hasse_invariant__OMeara(2)) # SANITY CHECK -- check that the scale powers are strictly increasing for i in range(1, len(scale_list)): @@ -282,15 +270,14 @@ def has_equivalent_Jordan_decomposition_at_prime(self, other, p) -> bool: for i in range(t - 1): # Condition (i): Check that their (unit) ratio is a square (but it suffices to check at most mod 8). - modulus = norm_list[i] * norm_list[i+1] / (scale_list[i] ** 2) + modulus = norm_list[i] * norm_list[i + 1] / (scale_list[i] ** 2) modulus = min(modulus, 8) if (modulus > 1) and (((self_chain_det_list[i] / other_chain_det_list[i]) % modulus) != 1): return False # Check O'Meara's condition (ii) when appropriate if norm_list[i + 1] % (4 * norm_list[i]) == 0: - if self_hasse_chain_list[i] * hilbert_symbol(norm_list[i] * other_chain_det_list[i], -self_chain_det_list[i], 2) \ - != other_hasse_chain_list[i] * hilbert_symbol(norm_list[i], -other_chain_det_list[i], 2): # Nipp conditions + if self_hasse_chain_list[i] * hilbert_symbol(norm_list[i] * other_chain_det_list[i], -self_chain_det_list[i], 2) != other_hasse_chain_list[i] * hilbert_symbol(norm_list[i], -other_chain_det_list[i], 2): # Nipp conditions return False # All tests passed for the prime 2. diff --git a/src/sage/quadratic_forms/quadratic_form__genus.py b/src/sage/quadratic_forms/quadratic_form__genus.py index 52468e9889a..cb6e9520e07 100644 --- a/src/sage/quadratic_forms/quadratic_form__genus.py +++ b/src/sage/quadratic_forms/quadratic_form__genus.py @@ -133,8 +133,7 @@ def CS_genus_symbol_list(self, force_recomputation=False): pass # Otherwise recompute and cache the list - list_of_CS_genus_symbols = [self.local_genus_symbol(p) - for p in prime_divisors(2 * self.det())] + list_of_CS_genus_symbols = [self.local_genus_symbol(p) for p in prime_divisors(2 * self.det())] self.__CS_genus_symbol_list = list_of_CS_genus_symbols return list_of_CS_genus_symbols diff --git a/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py b/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py index a88cf660412..8afe1ac41f0 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py +++ b/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py @@ -1,6 +1,7 @@ """ Local Density Congruence """ + ########################################################################## # Methods which compute the local densities for representing a number # by a quadratic form at a prime (possibly subject to additional @@ -118,9 +119,9 @@ def local_good_density_congruence_odd(self, p, m, Zvec, NZvec): if NZvec is None: if m % p: - total = Q_Unit_minus_Zvec.count_modp_solutions__by_Gauss_sum(p, m) * p**len(NonUnitVec_minus_Zvec) + total = Q_Unit_minus_Zvec.count_modp_solutions__by_Gauss_sum(p, m) * p ** len(NonUnitVec_minus_Zvec) else: - total = (Q_Unit_minus_Zvec.count_modp_solutions__by_Gauss_sum(p, m) - 1) * p**len(NonUnitVec_minus_Zvec) + total = (Q_Unit_minus_Zvec.count_modp_solutions__by_Gauss_sum(p, m) - 1) * p ** len(NonUnitVec_minus_Zvec) else: UnitVec_minus_ZNZvec = list(UnitVec - (Set(Zvec) + Set(NZvec))) @@ -128,14 +129,12 @@ def local_good_density_congruence_odd(self, p, m, Zvec, NZvec): Q_Unit_minus_ZNZvec = self.extract_variables(UnitVec_minus_ZNZvec) if m % p: - total = Q_Unit_minus_Zvec.count_modp_solutions__by_Gauss_sum(p, m) * p**len(NonUnitVec_minus_Zvec) \ - - Q_Unit_minus_ZNZvec.count_modp_solutions__by_Gauss_sum(p, m) * p**len(NonUnitVec_minus_ZNZvec) + total = Q_Unit_minus_Zvec.count_modp_solutions__by_Gauss_sum(p, m) * p ** len(NonUnitVec_minus_Zvec) - Q_Unit_minus_ZNZvec.count_modp_solutions__by_Gauss_sum(p, m) * p ** len(NonUnitVec_minus_ZNZvec) else: - total = (Q_Unit_minus_Zvec.count_modp_solutions__by_Gauss_sum(p, m) - 1) * p**len(NonUnitVec_minus_Zvec) \ - - (Q_Unit_minus_ZNZvec.count_modp_solutions__by_Gauss_sum(p, m) - 1) * p**len(NonUnitVec_minus_ZNZvec) + total = (Q_Unit_minus_Zvec.count_modp_solutions__by_Gauss_sum(p, m) - 1) * p ** len(NonUnitVec_minus_Zvec) - (Q_Unit_minus_ZNZvec.count_modp_solutions__by_Gauss_sum(p, m) - 1) * p ** len(NonUnitVec_minus_ZNZvec) # Return the Good-type representation density - good_density = QQ(total) / p**(n - 1) + good_density = QQ(total) / p ** (n - 1) return good_density @@ -261,8 +260,7 @@ def local_good_density_congruence_even(self, m, Zvec, NZvec): # Check for the middle off-diagonal entries else: - if (i > 0) and (i < n - 1) and (self[i, i + 1] % 8 or - self[i - 1, i] % 8): + if (i > 0) and (i < n - 1) and (self[i, i + 1] % 8 or self[i - 1, i] % 8): nz_flag = True # Remember the (vector) index if it's not part of a Jordan block of norm divisible by 8 @@ -290,8 +288,7 @@ def local_good_density_congruence_even(self, m, Zvec, NZvec): # Take cases on the existence of additional nonzero congruence conditions (mod 2) if NZvec is None: - total = (4 ** len(Z_Is8)) * (8 ** len(Is8_minus_Z)) \ - * count_all_local_good_types_normal_form(Q_Not8, 2, 3, m, list(Z_Not8), None) + total = (4 ** len(Z_Is8)) * (8 ** len(Is8_minus_Z)) * count_all_local_good_types_normal_form(Q_Not8, 2, 3, m, list(Z_Not8), None) else: ZNZ = Z + Set(NZvec) ZNZ_Not8 = Not8.intersection(ZNZ) @@ -304,16 +301,13 @@ def local_good_density_congruence_even(self, m, Zvec, NZvec): verbose("ZNZ_Is8 = " + str(ZNZ_Is8)) verbose("Is8_minus_ZNZ = " + str(Is8_minus_ZNZ)) - total = (4 ** len(Z_Is8)) * (8 ** len(Is8_minus_Z)) \ - * count_all_local_good_types_normal_form(Q_Not8, 2, 3, m, list(Z_Not8), None) \ - - (4 ** len(ZNZ_Is8)) * (8 ** len(Is8_minus_ZNZ)) \ - * count_all_local_good_types_normal_form(Q_Not8, 2, 3, m, list(ZNZ_Not8), None) + total = (4 ** len(Z_Is8)) * (8 ** len(Is8_minus_Z)) * count_all_local_good_types_normal_form(Q_Not8, 2, 3, m, list(Z_Not8), None) - (4 ** len(ZNZ_Is8)) * (8 ** len(Is8_minus_ZNZ)) * count_all_local_good_types_normal_form(Q_Not8, 2, 3, m, list(ZNZ_Not8), None) # DIAGNOSTIC verbose("total = " + str(total)) # Return the associated Good-type representation density - return QQ(total) / 8**(n - 1) + return QQ(total) / 8 ** (n - 1) def local_good_density_congruence(self, p, m, Zvec=None, NZvec=None): @@ -461,7 +455,7 @@ def local_zero_density_congruence(self, p, m, Zvec=None, NZvec=None): return 0 # Use the reduction procedure to return the result - return self.local_density_congruence(p, m / p2, None, None) / p**(self.dim() - 2) + return self.local_density_congruence(p, m / p2, None, None) / p ** (self.dim() - 2) def local_badI_density_congruence(self, p, m, Zvec=None, NZvec=None): @@ -563,19 +557,19 @@ def local_badI_density_congruence(self, p, m, Zvec=None, NZvec=None): # Compute the valuation of each index, allowing for off-diagonal terms if self[i, i] == 0: if i == 0: - val = valuation(self[i, i + 1], p) # Look at the term to the right + val = valuation(self[i, i + 1], p) # Look at the term to the right else: if i == n - 1: - val = valuation(self[i - 1, i], p) # Look at the term above + val = valuation(self[i - 1, i], p) # Look at the term above else: - val = valuation(self[i, i + 1] + self[i - 1, i], p) # Finds the valuation of the off-diagonal term since only one isn't zero + val = valuation(self[i, i + 1] + self[i - 1, i], p) # Finds the valuation of the off-diagonal term since only one isn't zero else: val = valuation(self[i, i], p) if val == 0: S0 += [i] elif val == 1: - S1_empty_flag = False # Need to have a non-empty S1 set to proceed with Bad-type I reduction... + S1_empty_flag = False # Need to have a non-empty S1 set to proceed with Bad-type I reduction... # Check that S1 is non-empty and p|m to proceed, otherwise return no solutions. if S1_empty_flag or m % p: @@ -598,15 +592,15 @@ def local_badI_density_congruence(self, p, m, Zvec=None, NZvec=None): # Make the form Qnew for the reduction procedure: # ----------------------------------------------- - Qnew = deepcopy(self) # TODO: DO THIS WITHOUT A copy() + Qnew = deepcopy(self) # TODO: DO THIS WITHOUT A copy() for i in range(n): if i in S0: Qnew[i, i] = p * Qnew[i, i] - if ((p == 2) and (i < n - 1)): + if (p == 2) and (i < n - 1): Qnew[i, i + 1] = p * Qnew[i, i + 1] else: Qnew[i, i] = Qnew[i, i] / p - if ((p == 2) and (i < n - 1)): + if (p == 2) and (i < n - 1): Qnew[i, i + 1] = Qnew[i, i + 1] / p # DIAGNOSTIC @@ -624,7 +618,7 @@ def local_badI_density_congruence(self, p, m, Zvec=None, NZvec=None): else: NZvec_geq_1 = list(Set([i for i in NZvec if i not in S0])) - return QQ(p**(1 - len(S0))) * Qnew.local_good_density_congruence(p, m / p, Zvec_geq_1, NZvec_geq_1) + return QQ(p ** (1 - len(S0))) * Qnew.local_good_density_congruence(p, m / p, Zvec_geq_1, NZvec_geq_1) def local_badII_density_congruence(self, p, m, Zvec=None, NZvec=None): @@ -709,20 +703,20 @@ def local_badII_density_congruence(self, p, m, Zvec=None, NZvec=None): # Compute the valuation of each index, allowing for off-diagonal terms if self[i, i] == 0: if i == 0: - val = valuation(self[i, i + 1], p) # Look at the term to the right + val = valuation(self[i, i + 1], p) # Look at the term to the right elif i == n - 1: - val = valuation(self[i - 1, i], p) # Look at the term above + val = valuation(self[i - 1, i], p) # Look at the term above else: - val = valuation(self[i, i + 1] + self[i - 1, i], p) # Finds the valuation of the off-diagonal term since only one isn't zero + val = valuation(self[i, i + 1] + self[i - 1, i], p) # Finds the valuation of the off-diagonal term since only one isn't zero else: val = valuation(self[i, i], p) # Sort the indices into disjoint sets by their valuation - if (val == 0): + if val == 0: S0 += [i] - elif (val == 1): + elif val == 1: S1 += [i] - elif (val >= 2): + elif val >= 2: S2plus += [i] # Check that S2 is non-empty and p^2 divides m to proceed, otherwise return no solutions. @@ -749,7 +743,7 @@ def local_badII_density_congruence(self, p, m, Zvec=None, NZvec=None): # Make the form Qnew for the reduction procedure: # ----------------------------------------------- - Qnew = deepcopy(self) # TODO: DO THIS WITHOUT A copy() + Qnew = deepcopy(self) # TODO: DO THIS WITHOUT A copy() for i in range(n): if i in S2plus: Qnew[i, i] = Qnew[i, i] / p2 @@ -770,7 +764,7 @@ def local_badII_density_congruence(self, p, m, Zvec=None, NZvec=None): diff = Qnew.local_density_congruence(p, m / p2, Zvec_geq_2, NZvec_geq_2) diff -= Qnew.local_density_congruence(p, m / p2, S2plus, NZvec_geq_2) - return QQ(p**(len(S2plus) + 2 - n)) * diff + return QQ(p ** (len(S2plus) + 2 - n)) * diff def local_bad_density_congruence(self, p, m, Zvec=None, NZvec=None): @@ -826,6 +820,7 @@ def local_bad_density_congruence(self, p, m, Zvec=None, NZvec=None): """ return self.local_badI_density_congruence(p, m, Zvec, NZvec) + self.local_badII_density_congruence(p, m, Zvec, NZvec) + ######################################################## # local_density and local_density_congruence routines # ######################################################## @@ -894,9 +889,7 @@ def local_density_congruence(self, p, m, Zvec=None, NZvec=None): sage: Q.local_density_congruence(3, 18, None, None) 4/9 """ - return self.local_good_density_congruence(p, m, Zvec, NZvec) \ - + self.local_zero_density_congruence(p, m, Zvec, NZvec) \ - + self.local_bad_density_congruence(p, m, Zvec, NZvec) + return self.local_good_density_congruence(p, m, Zvec, NZvec) + self.local_zero_density_congruence(p, m, Zvec, NZvec) + self.local_bad_density_congruence(p, m, Zvec, NZvec) def local_primitive_density_congruence(self, p, m, Zvec=None, NZvec=None): @@ -972,5 +965,4 @@ def local_primitive_density_congruence(self, p, m, Zvec=None, NZvec=None): sage: Q.local_primitive_density_congruence(3, 243, None, None) 8/27 """ - return self.local_good_density_congruence(p, m, Zvec, NZvec) \ - + self.local_bad_density_congruence(p, m, Zvec, NZvec) + return self.local_good_density_congruence(p, m, Zvec, NZvec) + self.local_bad_density_congruence(p, m, Zvec, NZvec) diff --git a/src/sage/quadratic_forms/quadratic_form__local_density_interfaces.py b/src/sage/quadratic_forms/quadratic_form__local_density_interfaces.py index 2643620e712..42a02df721f 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_density_interfaces.py +++ b/src/sage/quadratic_forms/quadratic_form__local_density_interfaces.py @@ -1,6 +1,7 @@ """ Local Density Interfaces """ + # // This is needed in the filter for primitivity... # #include "../max-min.h" @@ -49,11 +50,10 @@ def local_density(self, p, m): if n == 1: p_valuation = valuation(Q_local[0, 0], p) else: - p_valuation = min(valuation(Q_local[0, 0], p), - valuation(Q_local[0, 1], p)) + p_valuation = min(valuation(Q_local[0, 0], p), valuation(Q_local[0, 1], p)) # If m is less p-divisible than the matrix, return zero - if ((m != 0) and (valuation(m, p) < p_valuation)): # Note: The (m != 0) condition protects taking the valuation of zero. + if (m != 0) and (valuation(m, p) < p_valuation): # Note: The (m != 0) condition protects taking the valuation of zero. return QQ(0) # If the form is imprimitive, rescale it and call the local density routine @@ -122,11 +122,10 @@ def local_primitive_density(self, p, m): if n == 1: p_valuation = valuation(Q_local[0, 0], p) else: - p_valuation = min(valuation(Q_local[0, 0], p), - valuation(Q_local[0, 1], p)) + p_valuation = min(valuation(Q_local[0, 0], p), valuation(Q_local[0, 1], p)) # If m is less p-divisible than the matrix, return zero - if m != 0 and valuation(m, p) < p_valuation: # Note: The (m != 0) condition protects taking the valuation of zero. + if m != 0 and valuation(m, p) < p_valuation: # Note: The (m != 0) condition protects taking the valuation of zero. return QQ.zero() # If the form is imprimitive, rescale it and call the local density routine diff --git a/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py b/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py index f829ac40817..81ced1e5462 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py +++ b/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py @@ -460,14 +460,12 @@ def hasse_invariant(self, p): if R == QQ: for j in range(n - 1): for k in range(j + 1, n): - hasse_temp = hasse_temp * hilbert_symbol(Diag[j, j], - Diag[k, k], p) + hasse_temp = hasse_temp * hilbert_symbol(Diag[j, j], Diag[k, k], p) else: for j in range(n - 1): for k in range(j + 1, n): - hasse_temp = hasse_temp * R.hilbert_symbol(Diag[j, j], - Diag[k, k], p) + hasse_temp = hasse_temp * R.hilbert_symbol(Diag[j, j], Diag[k, k], p) return hasse_temp @@ -544,14 +542,12 @@ def hasse_invariant__OMeara(self, p): if R == QQ: for j in range(n): for k in range(j, n): - hasse_temp = hasse_temp * hilbert_symbol(Diag[j, j], - Diag[k, k], p) + hasse_temp = hasse_temp * hilbert_symbol(Diag[j, j], Diag[k, k], p) else: for j in range(n): for k in range(j, n): - hasse_temp = hasse_temp * R.hilbert_symbol(Diag[j, j], - Diag[k, k], p) + hasse_temp = hasse_temp * R.hilbert_symbol(Diag[j, j], Diag[k, k], p) return hasse_temp @@ -607,12 +603,9 @@ def is_hyperbolic(self, p) -> bool: return self.signature() == 0 if p == 2: - return (QQ(self.det() * (-1) ** m).is_padic_square(p) and - self.hasse_invariant(p) == - (-1) ** m.binomial(2)) # here -1 is hilbert_symbol(-1,-1,2) + return QQ(self.det() * (-1) ** m).is_padic_square(p) and self.hasse_invariant(p) == (-1) ** m.binomial(2) # here -1 is hilbert_symbol(-1,-1,2) - return (QQ(self.det() * (-1) ** m).is_padic_square(p) and - self.hasse_invariant(p) == 1) + return QQ(self.det() * (-1) ** m).is_padic_square(p) and self.hasse_invariant(p) == 1 def is_anisotropic(self, p) -> bool: @@ -670,8 +663,7 @@ def is_anisotropic(self, p) -> bool: return False if n == 4: - return (QQ(D).is_padic_square(p) and - (self.hasse_invariant(p) == - hilbert_symbol(-1, -1, p))) + return QQ(D).is_padic_square(p) and (self.hasse_invariant(p) == -hilbert_symbol(-1, -1, p)) if n == 3: return self.hasse_invariant(p) != hilbert_symbol(-1, -D, p) @@ -916,7 +908,7 @@ def compute_definiteness_string_by_determinants(self): return "indefinite" # Check for a change of signs in the upper r x r submatrix -- so it's indefinite - if sgn(first_coeff)**r != sgn(new_det): + if sgn(first_coeff) ** r != sgn(new_det): return "indefinite" # Here all ratios of determinants have the correct sign, so the matrix is (pos or neg) definite. diff --git a/src/sage/quadratic_forms/quadratic_form__local_normal_form.py b/src/sage/quadratic_forms/quadratic_form__local_normal_form.py index 45d17f0759a..790159342ed 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_normal_form.py +++ b/src/sage/quadratic_forms/quadratic_form__local_normal_form.py @@ -1,6 +1,7 @@ """ Local Normal Form """ + # **************************************************************************** # Copyright (C) 2007 William Stein and Jonathan Hanke # @@ -61,8 +62,8 @@ def find_entry_with_minimal_scale_at_prime(self, p): min_val = Infinity ij_index = None val_2 = valuation(2, p) - for d in range(n): # d = difference j-i - for e in range(n - d): # e is the length of the diagonal with value d. + for d in range(n): # d = difference j-i + for e in range(n - d): # e is the length of the diagonal with value d. # Compute the valuation of the entry if d == 0: @@ -167,7 +168,7 @@ def local_normal_form(self, p): # Step 3: Clear out the remaining entries # --------------------------------------- - min_scale = p ** min_val # This is the minimal valuation of the Hessian matrix entries. + min_scale = p**min_val # This is the minimal valuation of the Hessian matrix entries. # Perform cancellation over Z by ensuring divisibility if block_size == 1: @@ -180,13 +181,13 @@ def local_normal_form(self, p): if valuation(g, p) != valuation(a, p): raise RuntimeError("we have a problem with our rescaling not preserving p-integrality") - Q.multiply_variable(ZZ(a / g), j, in_place=True) # Ensures that the new b entry is divisible by a + Q.multiply_variable(ZZ(a / g), j, in_place=True) # Ensures that the new b entry is divisible by a Q.add_symmetric(ZZ(-b / g), j, 0, in_place=True) # Performs the cancellation elif block_size == 2: a1 = 2 * Q[0, 0] a2 = Q[0, 1] - b1 = Q[1, 0] # This is the same as a2 + b1 = Q[1, 0] # This is the same as a2 b2 = 2 * Q[1, 1] big_det = a1 * b2 - a2 * b1 @@ -336,7 +337,7 @@ def jordan_blocks_by_scale_and_unimodular(self, p, safe_flag=True): # Process the previous block if the valuation increased if block_scale > start_scale: - tmp_Jordan_list += [(start_scale, Q1.extract_variables(range(start_ind, i)).scale_by_factor(ZZ.one() / QQ(p)**start_scale))] + tmp_Jordan_list += [(start_scale, Q1.extract_variables(range(start_ind, i)).scale_by_factor(ZZ.one() / QQ(p) ** start_scale))] start_ind = i start_scale = block_scale @@ -344,7 +345,7 @@ def jordan_blocks_by_scale_and_unimodular(self, p, safe_flag=True): i += block_size # Add the last block - tmp_Jordan_list += [(start_scale, Q1.extract_variables(range(start_ind, n)).scale_by_factor(ZZ.one() / QQ(p)**start_scale))] + tmp_Jordan_list += [(start_scale, Q1.extract_variables(range(start_ind, n)).scale_by_factor(ZZ.one() / QQ(p) ** start_scale))] # Cache the result self.__jordan_blocks_by_scale_and_unimodular_dict[p] = tmp_Jordan_list diff --git a/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py b/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py index 985fabe707a..e6ae48f46bd 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py +++ b/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py @@ -94,6 +94,7 @@ class QuadraticFormLocalRepresentationConditions: sage: L [0] """ + def __init__(self, Q): r""" Take a :class:`QuadraticForm` and computes its local conditions (if @@ -121,8 +122,8 @@ def __init__(self, Q): raise TypeError("We require that the quadratic form be defined over ZZ (integer-values) for now.") # Basic structure initialization - self.local_repn_array = [] # List of all local conditions - self.dim = Q.dim() # We allow this to be any nonnegative integer. + self.local_repn_array = [] # List of all local conditions + self.dim = Q.dim() # We allow this to be any nonnegative integer. self.exceptional_primes = [infinity] # Deal with the special cases of 0 and 1-dimensional forms @@ -171,7 +172,7 @@ def __init__(self, Q): k = 0 repn_flag = False - while ((not repn_flag) and (m < 4 * N * p * p)): + while (not repn_flag) and (m < 4 * N * p * p): if local_normal_forms[i].local_density(p, m) > 0: tmp_local_repn_vec[j + 1] = k repn_flag = True @@ -277,9 +278,8 @@ def __eq__(self, right) -> bool: if self.dim == 0: return True if self.dim == 1: - return self.coeff == right.coeff # Compare coefficients in dimension 1 (since ZZ has only one unit square) - return ((self.exceptional_primes == right.exceptional_primes) - and (self.local_repn_array == right.local_repn_array)) + return self.coeff == right.coeff # Compare coefficients in dimension 1 (since ZZ has only one unit square) + return (self.exceptional_primes == right.exceptional_primes) and (self.local_repn_array == right.local_repn_array) def squareclass_vector(self, p) -> list: """ @@ -348,8 +348,8 @@ def local_conditions_vector_for_prime(self, p) -> list: sqclass = self.squareclass_vector(p) for i, sqi in enumerate(sqclass): - if QQ(self.coeff / sqi).is_padic_square(p): # Note:This should happen only once! - nu = valuation(self.coeff / sqi, p) / 2 # UNUSED VARIABLE ! + if QQ(self.coeff / sqi).is_padic_square(p): # Note:This should happen only once! + nu = valuation(self.coeff / sqi, p) / 2 # UNUSED VARIABLE ! else: v[i + 1] = infinity @@ -395,7 +395,7 @@ def is_universal_at_prime(self, p) -> bool: v = self.local_repn_array[0] if p != v[0]: raise RuntimeError("Error... The first vector should be for the real numbers!") - return (v[1:3] == [0, 0]) # True iff the form is indefinite + return v[1:3] == [0, 0] # True iff the form is indefinite # Check non-generic "finite" primes v = self.local_conditions_vector_for_prime(p) @@ -433,8 +433,7 @@ def is_universal_at_all_finite_primes(self) -> bool: # Check that all non-generic finite primes are universal # Omit p = "infinity" here - return all(self.is_universal_at_prime(p) - for p in self.exceptional_primes[1:]) + return all(self.is_universal_at_prime(p) for p in self.exceptional_primes[1:]) def is_universal_at_all_places(self) -> bool: r""" @@ -473,8 +472,7 @@ def is_universal_at_all_places(self) -> bool: return False # Check that all non-generic finite primes are universal - return all(self.is_universal_at_prime(p) - for p in self.exceptional_primes) + return all(self.is_universal_at_prime(p) for p in self.exceptional_primes) def is_locally_represented_at_place(self, m, p) -> bool: """ @@ -515,7 +513,7 @@ def is_locally_represented_at_place(self, m, p) -> bool: return True # 0-dim'l forms - if self.dim == 0: # Here m != 0 + if self.dim == 0: # Here m != 0 return False # 1-dim'l forms @@ -576,7 +574,7 @@ def is_locally_represented(self, m) -> bool: return True # 0-dim'l forms - if self.dim == 0: # Here m != 0 + if self.dim == 0: # Here m != 0 return False # 1-dim'l forms @@ -600,6 +598,7 @@ def is_locally_represented(self, m) -> bool: # If we got here, we're locally represented! return True + # --- End of QuadraticFormLocalRepresentationConditions Class --- diff --git a/src/sage/quadratic_forms/quadratic_form__mass.py b/src/sage/quadratic_forms/quadratic_form__mass.py index 96aa23610cd..e259a23a702 100644 --- a/src/sage/quadratic_forms/quadratic_form__mass.py +++ b/src/sage/quadratic_forms/quadratic_form__mass.py @@ -1,31 +1,15 @@ """ Shimura Mass """ + ###################################################### # Routines to compute the mass of a quadratic form # ###################################################### # Import all general mass finding routines -from sage.quadratic_forms.quadratic_form__mass__Siegel_densities import \ - mass__by_Siegel_densities, \ - Pall_mass_density_at_odd_prime, \ - Watson_mass_at_2, \ - Kitaoka_mass_at_2, \ - mass_at_two_by_counting_mod_power -from sage.quadratic_forms.quadratic_form__mass__Conway_Sloane_masses import \ - parity, \ - is_even, \ - is_odd, \ - conway_species_list_at_odd_prime, \ - conway_species_list_at_2, \ - conway_octane_of_this_unimodular_Jordan_block_at_2, \ - conway_diagonal_factor, \ - conway_cross_product_doubled_power, \ - conway_type_factor, \ - conway_p_mass, \ - conway_standard_p_mass, \ - conway_standard_mass, \ - conway_mass +from sage.quadratic_forms.quadratic_form__mass__Siegel_densities import mass__by_Siegel_densities, Pall_mass_density_at_odd_prime, Watson_mass_at_2, Kitaoka_mass_at_2, mass_at_two_by_counting_mod_power +from sage.quadratic_forms.quadratic_form__mass__Conway_Sloane_masses import parity, is_even, is_odd, conway_species_list_at_odd_prime, conway_species_list_at_2, conway_octane_of_this_unimodular_Jordan_block_at_2, conway_diagonal_factor, conway_cross_product_doubled_power, conway_type_factor, conway_p_mass, conway_standard_p_mass, conway_standard_mass, conway_mass + # conway_generic_mass, \ # conway_p_mass_adjustment diff --git a/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py b/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py index 85307fac3f5..62496984a6d 100644 --- a/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py +++ b/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py @@ -1,11 +1,8 @@ """ Conway-Sloane masses """ -from sage.arith.misc import (fundamental_discriminant, - is_prime, - kronecker as kronecker_symbol, - legendre_symbol, - prime_divisors) + +from sage.arith.misc import fundamental_discriminant, is_prime, kronecker as kronecker_symbol, legendre_symbol, prime_divisors from sage.misc.misc_c import prod from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -200,9 +197,9 @@ def conway_species_list_at_odd_prime(self, p): d = tmp_Q.det() # Determine the species - if n % 2 != 0: # Deal with odd dim'l forms + if n % 2 != 0: # Deal with odd dim'l forms species = n - elif n % 4 == 2 and p % 4 == 3: # Deal with even dim'l forms + elif n % 4 == 2 and p % 4 == 3: # Deal with even dim'l forms species = (-1) * legendre_symbol(d, p) * n else: species = legendre_symbol(d, p) * n @@ -257,10 +254,10 @@ def conway_species_list_at_2(self): # Make a list of species (including the two zero-dim'l forms missing at either end of the list of Jordan blocks) species_list = [] - if jordan_list[0].parity() == "odd": # Add an entry for the unlisted "-1" Jordan component as well. + if jordan_list[0].parity() == "odd": # Add an entry for the unlisted "-1" Jordan component as well. species_list.append(1) - for i in range(len(jordan_list)): # Add an entry for each (listed) Jordan component + for i in range(len(jordan_list)): # Add an entry for each (listed) Jordan component # Make the number 2*t in the C-S Table 1. d = jordan_list[i].dim() @@ -291,7 +288,7 @@ def conway_species_list_at_2(self): # Append the species to the list species_list.append(species) - if jordan_list[-1].is_odd(): # Add an entry for the unlisted "s_max + 1" Jordan component as well. + if jordan_list[-1].is_odd(): # Add an entry for the unlisted "s_max + 1" Jordan component as well. species_list.append(1) # Return the species list @@ -332,8 +329,8 @@ def conway_octane_of_this_unimodular_Jordan_block_at_2(self): n = self.dim() u = self[0, 0] tmp_diag_vec = [None] * n - tmp_diag_vec[0] = u # This should be an odd integer! - ind = 1 # The next index to diagonalize + tmp_diag_vec[0] = u # This should be an odd integer! + ind = 1 # The next index to diagonalize # Use u to diagonalize the form -- WHAT ARE THE POSSIBLE LOCAL NORMAL FORMS? while ind < n: @@ -355,11 +352,11 @@ def conway_octane_of_this_unimodular_Jordan_block_at_2(self): tmp_disc = b * b - a * c # Perform the diagonalization - if tmp_disc % 8 == 1: # 2xy + if tmp_disc % 8 == 1: # 2xy tmp_diag_vec[ind] = 1 tmp_diag_vec[ind + 1] = -1 ind += 2 - elif tmp_disc % 8 == 5: # 2x^2 + 2xy + 2y^2 + elif tmp_disc % 8 == 5: # 2x^2 + 2xy + 2y^2 tmp_diag_vec[0] = 3 * u tmp_diag_vec[ind] = -u tmp_diag_vec[ind + 1] = -u @@ -409,12 +406,10 @@ def conway_diagonal_factor(self, p): for s in species_list: if s == 0: pass - elif s % 2 == 1: # Note: Here always s > 0. - diag_factor = diag_factor / (2 * prod([1 - QQ(p)**(-i) - for i in range(2, s, 2)])) + elif s % 2 == 1: # Note: Here always s > 0. + diag_factor = diag_factor / (2 * prod([1 - QQ(p) ** (-i) for i in range(2, s, 2)])) else: - diag_factor = diag_factor / (2 * prod([1 - QQ(p)**(-i) - for i in range(2, abs(s), 2)])) + diag_factor = diag_factor / (2 * prod([1 - QQ(p) ** (-i) for i in range(2, abs(s), 2)])) s_sign = ZZ(s / abs(s)) diag_factor = diag_factor / (ZZ(1) - s_sign * QQ(p) ** ZZ(-abs(s) / ZZ(2))) @@ -450,9 +445,7 @@ def conway_cross_product_doubled_power(self, p): 0 """ dim_list = [J.dim() for J in self.jordan_blocks_in_unimodular_list_by_scale_power(p)] - return sum((i - j) * dimi * dim_list[j] - for i, dimi in enumerate(dim_list) - for j in range(i)) + return sum((i - j) * dimi * dim_list[j] for i, dimi in enumerate(dim_list) for j in range(i)) def conway_type_factor(self): @@ -469,10 +462,9 @@ def conway_type_factor(self): """ jordan_list = self.jordan_blocks_in_unimodular_list_by_scale_power(2) n2 = sum([J.dim() for J in jordan_list if J.is_even()]) - n11 = sum([1 for i in range(len(jordan_list) - 1) - if jordan_list[i].is_odd() and jordan_list[i + 1].is_odd()]) + n11 = sum([1 for i in range(len(jordan_list) - 1) if jordan_list[i].is_odd() and jordan_list[i + 1].is_odd()]) - return ZZ(2)**(n11 - n2) + return ZZ(2) ** (n11 - n2) def conway_p_mass(self, p): @@ -528,13 +520,13 @@ def conway_standard_p_mass(self, p): s = (n + 1) // 2 # Compute the inverse of the generic p-mass - p_mass_inv = 2 * prod([1 - p**(-i) for i in range(2, 2 * s, 2)]) + p_mass_inv = 2 * prod([1 - p ** (-i) for i in range(2, 2 * s, 2)]) if n % 2 == 0: - D = (-1)**s * self.det() * (2**n) + D = (-1) ** s * self.det() * (2**n) # We should have something like D = (-1)**s * self.det() / (2**n), but that's not an integer and here we only care about the square-class. # d = self.det() # Note: No normalizing power of 2 is needed since the power is even. # if not ((p == 2) or (d % p == 0)): - p_mass_inv *= (1 - kronecker_symbol(fundamental_discriminant(D), p) * p**(-s)) + p_mass_inv *= 1 - kronecker_symbol(fundamental_discriminant(D), p) * p ** (-s) # Return the standard p-mass return ZZ.one() / p_mass_inv @@ -567,12 +559,10 @@ def conway_standard_mass(self): else: s = (n + 1) // 2 - generic_mass = 2 * pi**((-1) * n * (n + 1) / ZZ(4)) \ - * prod([gamma__exact(j / ZZ(2)) for j in range(1, n + 1)]) \ - * prod([zeta__exact(2 * k) for k in range(1, s)]) + generic_mass = 2 * pi ** ((-1) * n * (n + 1) / ZZ(4)) * prod([gamma__exact(j / ZZ(2)) for j in range(1, n + 1)]) * prod([zeta__exact(2 * k) for k in range(1, s)]) if n % 2 == 0: - D = (-1)**s * self.det() * (2**n) + D = (-1) ** s * self.det() * (2**n) # We should have something like D = (-1)**s * self.det() / (2**n), but # that's not an integer and here we only care about the square-class. generic_mass *= quadratic_L_function__exact(s, D) @@ -617,7 +607,7 @@ def conway_mass(self): # Adjust the p-masses when p|2d d = self.det() for p in prime_divisors(2 * d): - mass *= (Q.conway_p_mass(p) / Q.conway_standard_p_mass(p)) + mass *= Q.conway_p_mass(p) / Q.conway_standard_p_mass(p) # Cache and return the (simplified) result self.__conway_mass = QQ(mass.canonicalize_radical()).abs() diff --git a/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py b/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py index db0135e5c8f..f5b434af7a1 100644 --- a/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py +++ b/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py @@ -1,6 +1,7 @@ """ Local Masses and Siegel Densities """ + ######################################################################## # Computes the local masses (rep'n densities of a form by itself) for a quadratic form over ZZ # using the papers of Pall [PSPUM VIII (1965), pp95--105] for p>2, and Watson [Mathematika @@ -67,26 +68,26 @@ def mass__by_Siegel_densities(self, odd_algorithm='Pall', even_algorithm='Watson n = self.dim() s = (n - 1) // 2 if n % 2 != 0: - char_d = squarefree_part(2 * self.det()) # Accounts for the det as a QF + char_d = squarefree_part(2 * self.det()) # Accounts for the det as a QF else: char_d = squarefree_part(self.det()) # Form the generic zeta product - generic_prod = ZZ(2) * (pi)**(-ZZ(n) * (n + 1) / 4) + generic_prod = ZZ(2) * (pi) ** (-ZZ(n) * (n + 1) / 4) ########################################## - generic_prod *= self.det()**(ZZ(n + 1) / 2) # ***** This uses the Hessian Determinant ******** + generic_prod *= self.det() ** (ZZ(n + 1) / 2) # ***** This uses the Hessian Determinant ******** ########################################## generic_prod *= prod([gamma__exact(ZZ(j) / 2) for j in range(1, n + 1)]) generic_prod *= prod([zeta__exact(ZZ(j)) for j in range(2, 2 * s + 1, 2)]) if n % 2 == 0: - generic_prod *= quadratic_L_function__exact(n // 2, ZZ(-1)**(n // 2) * char_d) + generic_prod *= quadratic_L_function__exact(n // 2, ZZ(-1) ** (n // 2) * char_d) # Determine the adjustment factors adj_prod = ZZ.one() for p in prime_divisors(2 * self.det()): # Cancel out the generic factors - p_adjustment = prod([1 - ZZ(p)**(-j) for j in range(2, 2 * s + 1, 2)]) + p_adjustment = prod([1 - ZZ(p) ** (-j) for j in range(2, 2 * s + 1, 2)]) if n % 2 == 0: - p_adjustment *= (1 - kronecker((-1)**(n // 2) * char_d, p) * ZZ(p)**(-n // 2)) + p_adjustment *= 1 - kronecker((-1) ** (n // 2) * char_d, p) * ZZ(p) ** (-n // 2) # Insert the new mass factors if p == 2: if even_algorithm == "Kitaoka": @@ -146,24 +147,24 @@ def Pall_mass_density_at_odd_prime(self, p): # Step 1: Obtain a p-adic (diagonal) local normal form, and # compute the invariants for each Jordan block. jordan_list = self.jordan_blocks_by_scale_and_unimodular(p) - modified_jordan_list = [(a, Q.dim(), Q.det()) for a, Q in jordan_list] # List of pairs (scale, det) + modified_jordan_list = [(a, Q.dim(), Q.det()) for a, Q in jordan_list] # List of pairs (scale, det) # Step 2: Compute the list of local masses for each Jordan block jordan_mass_list = [] - for (s, n, d) in modified_jordan_list: - generic_factor = prod([1 - p**(-2 * j) for j in range(1, (n - 1) // 2 + 1)]) + for s, n, d in modified_jordan_list: + generic_factor = prod([1 - p ** (-2 * j) for j in range(1, (n - 1) // 2 + 1)]) if n % 2 == 0: m = n // 2 - generic_factor *= (1 + legendre_symbol(((-1)**m) * d, p) * p**(-m)) + generic_factor *= 1 + legendre_symbol(((-1) ** m) * d, p) * p ** (-m) jordan_mass_list = jordan_mass_list + [generic_factor] - # Step 3: Compute the local mass $\al_p$ at p. + # Step 3: Compute the local mass $\al_p$ at p. MJL = modified_jordan_list s = len(modified_jordan_list) - M = [sum([MJL[j][1] for j in range(i, s)]) for i in range(s - 1)] # Note: It's s-1 since we don't need the last M. + M = [sum([MJL[j][1] for j in range(i, s)]) for i in range(s - 1)] # Note: It's s-1 since we don't need the last M. nu = sum([M[i] * MJL[i][0] * MJL[i][1] for i in range(s - 1)]) - ZZ(sum([J[0] * J[1] * (J[1] - 1) for J in MJL])) / ZZ(2) p_mass = prod(jordan_mass_list) - p_mass *= 2**(s - 1) * p**nu + p_mass *= 2 ** (s - 1) * p**nu print(jordan_list, MJL, jordan_mass_list, p_mass) @@ -198,15 +199,15 @@ def Watson_mass_at_2(self): s_max = max(scale_list) # Step 1: Compute dictionaries of the diagonal block and 2x2 block for each scale - diag_dict = {i: Null_Form for i in range(s_min - 2, s_max + 4)} # Initialize with the zero form - dim2_dict = {i: Null_Form for i in range(s_min, s_max + 4)} # Initialize with the zero form + diag_dict = {i: Null_Form for i in range(s_min - 2, s_max + 4)} # Initialize with the zero form + dim2_dict = {i: Null_Form for i in range(s_min, s_max + 4)} # Initialize with the zero form for s, L in Jordan_Blocks: i = 0 - while i < L.dim() - 1 and L[i, i + 1] == 0: # Find where the 2x2 blocks start + while i < L.dim() - 1 and L[i, i + 1] == 0: # Find where the 2x2 blocks start i += 1 if i < L.dim() - 1: - diag_dict[s] = L.extract_variables(range(i)) # Diagonal Form - dim2_dict[s + 1] = L.extract_variables(range(i, L.dim())) # Non-diagonal Form + diag_dict[s] = L.extract_variables(range(i)) # Diagonal Form + dim2_dict[s + 1] = L.extract_variables(range(i, L.dim())) # Non-diagonal Form else: diag_dict[s] = L @@ -220,8 +221,7 @@ def Watson_mass_at_2(self): else: m_dict[s + 1] = ZZ(L.dim() - 1) // ZZ(2) - nu_dict = {j: n_dict[j + 1] - 2 * m_dict[j + 1] - for j in range(s_min, s_max + 1)} + nu_dict = {j: n_dict[j + 1] - 2 * m_dict[j + 1] for j in range(s_min, s_max + 1)} nu_dict[s_max + 1] = 0 # Step 3: Compute the e_j dictionary @@ -244,14 +244,13 @@ def Watson_mass_at_2(self): eps_dict[j] = -1 # Step 4: Compute the quantities nu, q, P, E for the local mass at 2 - nu = sum([j * n_dict[j] * (ZZ(n_dict[j] + 1) / ZZ(2) + - sum([n_dict[r] for r in range(j + 1, s_max + 2)])) for j in range(s_min + 1, s_max + 2)]) + nu = sum([j * n_dict[j] * (ZZ(n_dict[j] + 1) / ZZ(2) + sum([n_dict[r] for r in range(j + 1, s_max + 2)])) for j in range(s_min + 1, s_max + 2)]) q = sum([sgn(nu_dict[j - 1] * (n_dict[j] + sgn(nu_dict[j]))) for j in range(s_min + 1, s_max + 2)]) - P = prod([prod([1 - QQ(4)**(-k) for k in range(1, m_dict[j] + 1)]) for j in range(s_min + 1, s_max + 2)]) - E = prod([ZZ(1) / ZZ(2) * (1 + eps_dict[j] * QQ(2)**(-m_dict[j])) for j in range(s_min, s_max + 3)]) + P = prod([prod([1 - QQ(4) ** (-k) for k in range(1, m_dict[j] + 1)]) for j in range(s_min + 1, s_max + 2)]) + E = prod([ZZ(1) / ZZ(2) * (1 + eps_dict[j] * QQ(2) ** (-m_dict[j])) for j in range(s_min, s_max + 3)]) # Step 5: Compute the local mass for the prime 2. - mass_at_2 = QQ(2)**(nu - q) * P / E + mass_at_2 = QQ(2) ** (nu - q) * P / E return mass_at_2 @@ -280,15 +279,15 @@ def Kitaoka_mass_at_2(self): s_max = max(scale_list) # Step 1: Compute dictionaries of the diagonal block and 2x2 block for each scale - diag_dict = {i: Null_Form for i in range(s_min - 2, s_max + 4)} # Initialize with the zero form - dim2_dict = {i: Null_Form for i in range(s_min, s_max + 4)} # Initialize with the zero form + diag_dict = {i: Null_Form for i in range(s_min - 2, s_max + 4)} # Initialize with the zero form + dim2_dict = {i: Null_Form for i in range(s_min, s_max + 4)} # Initialize with the zero form for s, L in Jordan_Blocks: i = 0 - while i < L.dim() - 1 and L[i, i + 1] == 0: # Find where the 2x2 blocks start + while i < L.dim() - 1 and L[i, i + 1] == 0: # Find where the 2x2 blocks start i += 1 if i < L.dim() - 1: - diag_dict[s] = L.extract_variables(range(i)) # Diagonal Form - dim2_dict[s + 1] = L.extract_variables(range(i, L.dim())) # Non-diagonal Form + diag_dict[s] = L.extract_variables(range(i)) # Diagonal Form + dim2_dict[s + 1] = L.extract_variables(range(i, L.dim())) # Non-diagonal Form else: diag_dict[s] = L @@ -297,30 +296,29 @@ def Kitaoka_mass_at_2(self): # Compute q := sum of the q_j q = 0 for j in range(s_min, s_max + 1): - if diag_dict[j].dim() > 0: # Check that N_j is odd (i.e. rep'ns an odd #) + if diag_dict[j].dim() > 0: # Check that N_j is odd (i.e. rep'ns an odd #) if diag_dict[j + 1].dim() == 0: - q += Jordan_Blocks[j][1].dim() # When N_{j+1} is "even", add n_j + q += Jordan_Blocks[j][1].dim() # When N_{j+1} is "even", add n_j else: - q += Jordan_Blocks[j][1].dim() + 1 # When N_{j+1} is "odd", add n_j + 1 + q += Jordan_Blocks[j][1].dim() + 1 # When N_{j+1} is "odd", add n_j + 1 # Compute P = product of the P_j P = QQ.one() for j in range(s_min, s_max + 1): tmp_m = dim2_dict[j].dim() // 2 - P *= prod(QQ.one() - QQ(4**(-k)) for k in range(1, tmp_m + 1)) + P *= prod(QQ.one() - QQ(4 ** (-k)) for k in range(1, tmp_m + 1)) # Compute the product E := prod_j (1 / E_j) E = QQ.one() for j in range(s_min - 1, s_max + 2): - if (diag_dict[j - 1].dim() == 0) and (diag_dict[j + 1].dim() == 0) and \ - ((diag_dict[j].dim() != 2) or (((diag_dict[j][0, 0] - diag_dict[j][1, 1]) % 4) != 0)): + if (diag_dict[j - 1].dim() == 0) and (diag_dict[j + 1].dim() == 0) and ((diag_dict[j].dim() != 2) or (((diag_dict[j][0, 0] - diag_dict[j][1, 1]) % 4) != 0)): # Deal with the complicated case: tmp_m = dim2_dict[j].dim() // 2 if dim2_dict[j].is_hyperbolic(2): - E *= QQ(2) / (1 + 2**(-tmp_m)) + E *= QQ(2) / (1 + 2 ** (-tmp_m)) else: - E *= QQ(2) / (1 - 2**(-tmp_m)) + E *= QQ(2) / (1 - 2 ** (-tmp_m)) else: E *= 2 @@ -334,7 +332,7 @@ def Kitaoka_mass_at_2(self): w += j * n_j * (n_k + QQ(n_j + 1) / 2) # Step 5: Compute the local mass for the prime 2. - mass_at_2 = (QQ(2)**(w - q)) * P * E + mass_at_2 = (QQ(2) ** (w - q)) * P * E return mass_at_2 @@ -367,5 +365,5 @@ def mass_at_two_by_counting_mod_power(self, k): n = self.dim() MS = MatrixSpace(R, n) - ct = sum(1 for x in mrange([2**k] * (n**2)) if Q1(MS(x)) == Q1) # Count the solutions mod 2^k - return ZZ.one() / 2 * (ZZ(ct) / ZZ(2)**(k * n * (n - 1) / 2)) + ct = sum(1 for x in mrange([2**k] * (n**2)) if Q1(MS(x)) == Q1) # Count the solutions mod 2^k + return ZZ.one() / 2 * (ZZ(ct) / ZZ(2) ** (k * n * (n - 1) / 2)) diff --git a/src/sage/quadratic_forms/quadratic_form__neighbors.py b/src/sage/quadratic_forms/quadratic_form__neighbors.py index cecf15c8eda..d94ed9a6cbb 100644 --- a/src/sage/quadratic_forms/quadratic_form__neighbors.py +++ b/src/sage/quadratic_forms/quadratic_form__neighbors.py @@ -48,7 +48,7 @@ def find_primitive_p_divisible_vector__random(self, p): if a in ZZ and (a % p == 0) and (v != 0): return v v[ZZ.random_element(n)] = ZZ.random_element(p) - # Replace a random entry and try again. + # Replace a random entry and try again. raise RuntimeError("unable to find a p divisible vector") @@ -119,7 +119,7 @@ def find_primitive_p_divisible_vector__next(self, p, v=None): for j in range(ind): w[j] = 0 else: - for j in range(ind + 1): # Clear all entries + for j in range(ind + 1): # Clear all entries w[j] = 0 if nz != 0: @@ -248,8 +248,7 @@ def find_p_neighbor_from_vec(self, p, y, return_matrix=False): return QF(Gnew) -def neighbor_iteration(seeds, p, mass=None, max_classes=None, - algorithm=None, max_neighbors=1000, verbose=False): +def neighbor_iteration(seeds, p, mass=None, max_classes=None, algorithm=None, max_neighbors=1000, verbose=False): r""" Return all classes in the `p`-neighbor graph of ``self``. @@ -309,6 +308,7 @@ def neighbor_iteration(seeds, p, mass=None, max_classes=None, """ from sage.quadratic_forms.quadratic_form import QuadraticForm from warnings import warn + p = ZZ(p) if max_classes is None: max_classes = 1000 @@ -316,18 +316,19 @@ def neighbor_iteration(seeds, p, mass=None, max_classes=None, raise ValueError("seeds must be a list of quadratic forms") if algorithm is None: n = seeds[0].dim() - if p**n > ZZ(2)**18: + if p**n > ZZ(2) ** 18: # too many lines to compute the orbits fast algorithm = 'random' else: algorithm = 'orbits' if algorithm == 'orbits': + def p_divisible_vectors(Q, max_neighbors): - yield from iter(v.lift() for v in Q.orbits_lines_mod_p(p) - if v != 0 and Q(v.lift()).valuation(p) > 0) + yield from iter(v.lift() for v in Q.orbits_lines_mod_p(p) if v != 0 and Q(v.lift()).valuation(p) > 0) elif algorithm == 'exhaustion': + def p_divisible_vectors(Q, max_neighbors): k = 0 v = Q.find_primitive_p_divisible_vector__next(p) @@ -336,13 +337,16 @@ def p_divisible_vectors(Q, max_neighbors): v = Q.find_primitive_p_divisible_vector__next(p, v) if v is not None: yield v + elif algorithm == 'random': + def p_divisible_vectors(Q, max_neighbors): k = 0 while k < max_neighbors: k += 1 v = Q.find_primitive_p_divisible_vector__random(p) yield v + else: raise ValueError("unknown algorithm") waiting_list = list(seeds) @@ -359,7 +363,7 @@ def p_divisible_vectors(Q, max_neighbors): isom_classes.append(Q_neighbor) waiting_list.append(Q_neighbor) n_isom_classes += 1 - mass_count += Q_neighbor.number_of_automorphisms()**(-1) + mass_count += Q_neighbor.number_of_automorphisms() ** (-1) if verbose: print(max_neighbors) print(len(waiting_list)) @@ -407,7 +411,8 @@ def orbits_lines_mod_p(self, p): # but in gap we act from the right!! --> transpose gens = self.automorphism_group().gens() gens = [g.matrix().transpose().change_ring(GF(p)) for g in gens] - orbs = libgap.function_factory("""function(gens, p) + orbs = libgap.function_factory( + """function(gens, p) local one, G, reps, V, n, orb; one:= One(GF(p)); G:=Group(List(gens, g -> g*one)); @@ -416,7 +421,8 @@ def orbits_lines_mod_p(self, p): orb:= OrbitsDomain(G, V, OnLines); reps:= List(orb, g->g[1]); return reps; - end;""") + end;""" + ) orbs_reps = orbs(gens, p) - M = GF(p)**self.dim() + M = GF(p) ** self.dim() return [M(m.sage()) for m in orbs_reps if not m.IsZero()] diff --git a/src/sage/quadratic_forms/quadratic_form__reduction_theory.py b/src/sage/quadratic_forms/quadratic_form__reduction_theory.py index 87323962097..81d485870c5 100644 --- a/src/sage/quadratic_forms/quadratic_form__reduction_theory.py +++ b/src/sage/quadratic_forms/quadratic_form__reduction_theory.py @@ -1,12 +1,14 @@ """ Reduction Theory """ + from copy import deepcopy from sage.matrix.constructor import matrix from sage.misc.lazy_import import lazy_import from sage.misc.mrange import mrange from sage.modules.free_module_element import vector from sage.rings.integer_ring import ZZ + lazy_import("sage.functions.all", "floor") @@ -229,6 +231,7 @@ def minkowski_reduction(self): """ from sage.quadratic_forms.quadratic_form import QuadraticForm from sage.quadratic_forms.quadratic_form import matrix + if not self.is_positive_definite(): raise TypeError("Minkowski reduction only works for positive definite forms") if self.dim() > 4: @@ -415,8 +418,7 @@ def minkowski_reduction_for_4vars__SP(self): for k in [2, 1, 0]: # TO DO: These steps are a little redundant... Q1 = Q.matrix() - c_flag = all(abs(Q1[i, l]) == abs(Q1[j, l]) - for l in range(k + 1, 4)) + c_flag = all(abs(Q1[i, l]) == abs(Q1[j, l]) for l in range(k + 1, 4)) # Condition (c) if c_flag and abs(Q1[i, k]) > abs(Q1[j, k]): @@ -459,9 +461,7 @@ def minkowski_reduction_for_4vars__SP(self): if Q[1, 2] < 0: # Test a row 1 sign change - if (Q[1, 3] <= 0 and (Q[1, 3] < 0 - or Q[1, 2] < 0 - or (Q[1, 2] == 0 and Q[1, 1] < 0))): + if Q[1, 3] <= 0 and (Q[1, 3] < 0 or Q[1, 2] < 0 or (Q[1, 2] == 0 and Q[1, 1] < 0)): Q.multiply_variable(-1, i, in_place=True) M_new = matrix(R, n, n) for r in range(4): @@ -471,9 +471,7 @@ def minkowski_reduction_for_4vars__SP(self): M_new[r, r] = 1 M = M * M_new - elif (Q[2, 3] <= 0 and ((Q[2, 3] < 0) - or Q[2, 2] < 0 - or (Q[2, 2] == 0 and Q[2, 1] < 0))): + elif Q[2, 3] <= 0 and ((Q[2, 3] < 0) or Q[2, 2] < 0 or (Q[2, 2] == 0 and Q[2, 1] < 0)): Q.multiply_variable(-1, i, in_place=True) M_new = matrix(R, n, n) for r in range(4): diff --git a/src/sage/quadratic_forms/quadratic_form__siegel_product.py b/src/sage/quadratic_forms/quadratic_form__siegel_product.py index b481f5ad073..a2b777dae17 100644 --- a/src/sage/quadratic_forms/quadratic_form__siegel_product.py +++ b/src/sage/quadratic_forms/quadratic_form__siegel_product.py @@ -11,10 +11,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.arith.misc import (bernoulli, - fundamental_discriminant, - kronecker as kronecker_symbol, - prime_divisors) +from sage.arith.misc import bernoulli, fundamental_discriminant, kronecker as kronecker_symbol, prime_divisors from sage.misc.functional import sqrt from sage.misc.verbose import verbose from sage.quadratic_forms.special_values import QuadraticBernoulliNumber @@ -82,7 +79,7 @@ def siegel_product(self, u): u = ZZ(u) n = self.dim() - d = self.det() # ??? Warning: This is a factor of 2^n larger than it should be! + d = self.det() # ??? Warning: This is a factor of 2^n larger than it should be! # DIAGNOSTIC verbose("n = " + str(n)) @@ -99,7 +96,7 @@ def siegel_product(self, u): # Make the odd generic factors if n % 2: m = (n - 1) // 2 - d1 = fundamental_discriminant(((-1)**m) * 2*d * u) # Replaced d by 2d here to compensate for the determinant + d1 = fundamental_discriminant(((-1) ** m) * 2 * d * u) # Replaced d by 2d here to compensate for the determinant f = abs(d1) # gaining an odd power of 2 by using the matrix of 2Q instead # of the matrix of Q. @@ -107,32 +104,27 @@ def siegel_product(self, u): # Make the ratio of factorials factor: [(2m)! / m!] * prod_{i=1}^m (2*i-1) factor1 = 1 - for i in range(1, m+1): - factor1 *= 2*i - 1 - for i in range(m+1, 2*m + 1): + for i in range(1, m + 1): + factor1 *= 2 * i - 1 + for i in range(m + 1, 2 * m + 1): factor1 *= i - genericfactor = factor1 * ((u / f) ** m) \ - * QQ(sqrt((2 ** n) * f) / (u * d)) \ - * abs(QuadraticBernoulliNumber(m, d1) / bernoulli(2*m)) + genericfactor = factor1 * ((u / f) ** m) * QQ(sqrt((2**n) * f) / (u * d)) * abs(QuadraticBernoulliNumber(m, d1) / bernoulli(2 * m)) # DIAGNOSTIC verbose("siegel_product Break 2. \n") # Make the even generic factor - if ((n % 2) == 0): + if (n % 2) == 0: m = n // 2 - d1 = fundamental_discriminant(((-1)**m) * d) + d1 = fundamental_discriminant(((-1) ** m) * d) f = abs(d1) # DIAGNOSTIC # cout << " mpz_class(-1)^m = " << (mpz_class(-1)^m) << " and d = " << d << endl; # cout << " f = " << f << " and d1 = " << d1 << endl; - genericfactor = m / QQ(sqrt(f*d)) \ - * ((u/2) ** (m-1)) * (f ** m) \ - / abs(QuadraticBernoulliNumber(m, d1)) \ - * (2 ** m) # This last factor compensates for using the matrix of 2*Q + genericfactor = m / QQ(sqrt(f * d)) * ((u / 2) ** (m - 1)) * (f**m) / abs(QuadraticBernoulliNumber(m, d1)) * (2**m) # This last factor compensates for using the matrix of 2*Q # return genericfactor diff --git a/src/sage/quadratic_forms/quadratic_form__split_local_covering.py b/src/sage/quadratic_forms/quadratic_form__split_local_covering.py index ccf44d31f1a..cc9efaf31e7 100644 --- a/src/sage/quadratic_forms/quadratic_form__split_local_covering.py +++ b/src/sage/quadratic_forms/quadratic_form__split_local_covering.py @@ -1,6 +1,7 @@ """ Split Local Covering """ + ####################################################################### # Routines that look for a split local covering for a given quadratic # # form in 4 variables. # @@ -85,14 +86,14 @@ def cholesky_decomposition(self, bit_prec=53): n = self.dim() R = RealField(bit_prec) MS = MatrixSpace(R, n, n) - Q = MS(R(0.5)) * MS(self.matrix()) # Initialize the real symmetric matrix A with the matrix for Q(x) = x^t * A * x + Q = MS(R(0.5)) * MS(self.matrix()) # Initialize the real symmetric matrix A with the matrix for Q(x) = x^t * A * x # DIAGNOSTIC # 2. Loop on i for i in range(n): for j in range(i + 1, n): - Q[j, i] = Q[i, j] # Is this line redundant? + Q[j, i] = Q[i, j] # Is this line redundant? Q[i, j] = Q[i, j] / Q[i, i] # 3. Main Loop @@ -187,7 +188,7 @@ def vectors_by_length(self, bound): Q = self.cholesky_decomposition() # 1. Initialize - T = n * [RDF(0)] # Note: We index the entries as 0 --> n-1 + T = n * [RDF(0)] # Note: We index the entries as 0 --> n-1 U = n * [RDF(0)] i = n - 1 T[i] = RDF(Theta_Precision) @@ -208,7 +209,7 @@ def vectors_by_length(self, bound): while not done_flag: # 3b. Main loop -- try to generate a complete vector x (when i=0) - while (i > 0): + while i > 0: T[i - 1] = T[i] - Q[i][i] * (x[i] + U[i]) * (x[i] + U[i]) i = i - 1 U[i] = 0 @@ -224,7 +225,7 @@ def vectors_by_length(self, bound): # carry if we go out of bounds -- when Z is so small that # there aren't any integral vectors between the bounds # Note: this ensures T[i-1] >= 0 in the next iteration - while (x[i] > L[i]): + while x[i] > L[i]: i += 1 x[i] += 1 @@ -385,7 +386,7 @@ def split_local_cover(self): if hasattr(self, "__split_local_cover"): if isinstance(self.__split_local_cover, QuadraticForm): # Here the computation has been done. return self.__split_local_cover - if self.__split_local_cover in ZZ: # Here it indexes the values already tried! + if self.__split_local_cover in ZZ: # Here it indexes the values already tried! current_length = self.__split_local_cover + 1 Length_Max = current_length + 5 else: diff --git a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py index 28789c7dc70..734b968b32f 100644 --- a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +++ b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py @@ -1,6 +1,7 @@ """ Tornaria methods for computing with quadratic forms """ + # **************************************************************************** # Copyright (C) 2007 Gonzalo Tornaria # @@ -11,12 +12,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.arith.misc import (CRT_vectors, - factor, - gcd, - hilbert_symbol, - kronecker as kronecker_symbol, - prime_to_m_part) +from sage.arith.misc import CRT_vectors, factor, gcd, hilbert_symbol, kronecker as kronecker_symbol, prime_to_m_part from sage.misc.functional import is_odd from sage.misc.misc_c import prod from sage.modules.free_module import FreeModule @@ -57,7 +53,7 @@ def disc(self): if is_odd(self.dim()): # This is not so good for characteristic 2. return self.base_ring()(self.det() / 2) - return (-1)**(self.dim() // 2) * self.det() + return (-1) ** (self.dim() // 2) * self.det() def content(self): @@ -130,6 +126,7 @@ def adjoint(self): [ * * 8 ] """ from sage.quadratic_forms.quadratic_form import QuadraticForm + if is_odd(self.dim()): return QuadraticForm(self.matrix().adjoint_classical() * 2) return QuadraticForm(self.matrix().adjoint_classical()) @@ -155,10 +152,10 @@ def antiadjoint(self): n = self.dim() R = self.base_ring() try: - d = R(self.disc()**(ZZ.one() / (n - 1))) + d = R(self.disc() ** (ZZ.one() / (n - 1))) if is_odd(n): - return self.adjoint().scale_by_factor(R.one() / 4 / d**(n - 2)) - return self.adjoint().scale_by_factor(R.one() / d**(n - 2)) + return self.adjoint().scale_by_factor(R.one() / 4 / d ** (n - 2)) + return self.adjoint().scale_by_factor(R.one() / d ** (n - 2)) except TypeError: raise ValueError("not an adjoint") @@ -205,7 +202,7 @@ def reciprocal(self): sage: Q.reciprocal().reciprocal() == Q True """ - return self.adjoint().primitive() . scale_by_factor(self.content()) + return self.adjoint().primitive().scale_by_factor(self.content()) def omega(self): @@ -262,7 +259,7 @@ def level__Tornaria(self): sage: DiagonalQuadraticForm(ZZ, [1,1,1,1]).level__Tornaria() 4 """ - return self.base_ring()(abs(self.disc()) / self.omega() / self.content()**self.dim()) + return self.base_ring()(abs(self.disc()) / self.omega() / self.content() ** self.dim()) def discrec(self): @@ -284,6 +281,7 @@ def discrec(self): # Rational equivalence + def hasse_conductor(self): """ Return the Hasse conductor. @@ -306,8 +304,7 @@ def hasse_conductor(self): sage: QuadraticForm(ZZ, 3, [2, -2, 0, 2, 0, 5]).hasse_conductor() # needs sage.libs.pari 10 """ - return prod([x for x, _ in factor(2 * self.level()) - if self.hasse_invariant(x) == -1]) + return prod([x for x, _ in factor(2 * self.level()) if self.hasse_invariant(x) == -1]) def clifford_invariant(self, p): @@ -386,12 +383,12 @@ def clifford_conductor(self): sage: (H + H + H + H).clifford_conductor() 1 """ - return prod([x for x, _ in factor(2 * self.level()) - if self.clifford_invariant(x) == -1]) + return prod([x for x, _ in factor(2 * self.level()) if self.clifford_invariant(x) == -1]) # Genus theory + def basiclemma(self, M): """ Find a number represented by ``self`` and coprime to `M`. @@ -588,6 +585,7 @@ def representation_vector_list(self, B, maxvectors=10**8): # zeros + def is_zero(self, v, p=0) -> bool: r""" Determine if the vector `v` is on the conic `Q(x) = 0` (mod `p`). @@ -628,7 +626,7 @@ def is_zero_nonsingular(self, v, p=0) -> bool: vm = vector(self.base_ring(), v) * self.matrix() if p != 0: vm = vm % p - return (vm != 0) + return vm != 0 def is_zero_singular(self, v, p=0) -> bool: diff --git a/src/sage/quadratic_forms/quadratic_form__theta.py b/src/sage/quadratic_forms/quadratic_form__theta.py index 4f78b59d96c..b37cc0238ba 100644 --- a/src/sage/quadratic_forms/quadratic_form__theta.py +++ b/src/sage/quadratic_forms/quadratic_form__theta.py @@ -9,6 +9,7 @@ - Gonzalo Tornaria (2010-03-23): theta series of degree 2 """ + from copy import deepcopy from sage.rings.power_series_ring import PowerSeriesRing @@ -69,6 +70,7 @@ def theta_series(self, Max=10, var_str='q', safe_flag=True): # ---- Compute the theta function by using the PARI/GP routine qfrep ---- + def theta_by_pari(self, Max, var_str='q', safe_flag=True): r""" Use PARI/GP to compute the theta function as a power series (or @@ -114,7 +116,7 @@ def theta_by_pari(self, Max, var_str='q', safe_flag=True): # Return the answer if not var_str: if safe_flag: - return deepcopy(theta_vec) # We must make a copy here to insure the integrity of the cached version! + return deepcopy(theta_vec) # We must make a copy here to insure the integrity of the cached version! return theta_vec return PowerSeriesRing(ZZ, var_str)(theta_vec, Max) @@ -177,9 +179,9 @@ def theta_by_cholesky(self, q_prec): theta = [0] * (q_prec + 1) PS = PowerSeriesRing(ZZ, 'q') - bit_prec = 53 # TO DO: Set this precision to reflect the appropriate roundoff - Cholesky = self.cholesky_decomposition(bit_prec) # error estimate, to be confident through our desired q-precision. - Q = Cholesky # <---- REDUNDANT!!! + bit_prec = 53 # TO DO: Set this precision to reflect the appropriate roundoff + Cholesky = self.cholesky_decomposition(bit_prec) # error estimate, to be confident through our desired q-precision. + Q = Cholesky # <---- REDUNDANT!!! R = RealField(bit_prec) half = R(0.5) @@ -199,13 +201,13 @@ def theta_by_cholesky(self, q_prec): done_flag = False from_step4_flag = False - from_step3_flag = True # We start by pretending this, since then we get to run through 2 and 3a once. =) + from_step3_flag = True # We start by pretending this, since then we get to run through 2 and 3a once. =) # Big loop which runs through all vectors while not done_flag: # Loop through until we get to i=1 (so we defined a vector x) - while from_step3_flag or from_step4_flag: # IMPORTANT WARNING: This replaces a do...while loop, so it may have to be adjusted! + while from_step3_flag or from_step4_flag: # IMPORTANT WARNING: This replaces a do...while loop, so it may have to be adjusted! # Go to directly to step 3 if we're coming from step 4, otherwise perform step 2. if from_step4_flag: @@ -235,15 +237,12 @@ def theta_by_cholesky(self, q_prec): # 4. Solution found (This happens when i=0) from_step4_flag = True Q_val_double = q_prec - T[0] + Q[0, 0] * (x[0] + U[0]) * (x[0] + U[0]) - Q_val = floor(Q_val_double + half) # Note: This rounds the value up, since the "round" function returns a float, but floor returns integer. + Q_val = floor(Q_val_double + half) # Note: This rounds the value up, since the "round" function returns a float, but floor returns integer. # OPTIONAL SAFETY CHECK: eps = 0.000000001 if abs(Q_val_double - Q_val) > eps: - raise RuntimeError("Oh No! We have a problem with the floating point precision... \n" - + " Q_val_double = " + str(Q_val_double) + "\n" - + " Q_val = " + str(Q_val) + "\n" - + " x = " + str(x) + "\n") + raise RuntimeError("Oh No! We have a problem with the floating point precision... \n" + " Q_val_double = " + str(Q_val_double) + "\n" + " Q_val = " + str(Q_val) + "\n" + " x = " + str(x) + "\n") if Q_val <= q_prec: theta[Q_val] += 2 @@ -303,7 +302,7 @@ def theta_series_degree_2(Q, prec) -> dict: if not Q.is_positive_definite(): raise ValueError("the quadratic form must be positive definite") try: - X = ZZ(prec - 1) # maximum discriminant + X = ZZ(prec - 1) # maximum discriminant except TypeError: raise TypeError("prec is not an integer") @@ -318,7 +317,7 @@ def theta_series_degree_2(Q, prec) -> dict: t = cputime() maxi = (X + 1) // 4 - v_list = (Q.vectors_by_length(maxi)) # assume a>0 + v_list = Q.vectors_by_length(maxi) # assume a>0 v_list = [[V(c) for c in vs] for vs in v_list] # coerce vectors into V verbose("Computed vectors_by_length", t) @@ -338,6 +337,7 @@ def theta_series_degree_2(Q, prec) -> dict: def B_v1(v): return v1_H * v2 + for v2 in v_list[c]: b = abs(B_v1(v2)) if b <= a and 4 * a * c - b * b <= X: diff --git a/src/sage/quadratic_forms/quadratic_form__variable_substitutions.py b/src/sage/quadratic_forms/quadratic_form__variable_substitutions.py index ba3b26bacaa..51a9ab55234 100644 --- a/src/sage/quadratic_forms/quadratic_form__variable_substitutions.py +++ b/src/sage/quadratic_forms/quadratic_form__variable_substitutions.py @@ -1,6 +1,7 @@ """ Variable Substitution, Multiplication, Division, Scaling """ + # **************************************************************************** # Copyright (C) 2007 William Stein and Jonathan Hanke # @@ -109,7 +110,7 @@ def multiply_variable(self, c, i, in_place=False): # Switch off-diagonal elements for k in range(self.dim()): - if (k != i): + if k != i: tmp = c * self[k, i] self[k, i] = tmp @@ -154,7 +155,7 @@ def divide_variable(self, c, i, in_place=False): # Switch off-diagonal elements for k in range(self.dim()): - if (k != i): + if k != i: tmp = self[k, i] / c self[k, i] = tmp @@ -236,10 +237,7 @@ def extract_variables(QF, var_indices): [ * 9 ] """ m = len(var_indices) - return QF.parent()(QF.base_ring(), m, - [QF[var_indices[i], var_indices[j]] - for i in range(m) - for j in range(i, m)]) + return QF.parent()(QF.base_ring(), m, [QF[var_indices[i], var_indices[j]] for i in range(m) for j in range(i, m)]) def elementary_substitution(self, c, i, j, in_place=False): # CHECK THIS!!! @@ -302,12 +300,12 @@ def elementary_substitution(self, c, i, j, in_place=False): # CHECK THIS!!! return Q # Adjust the a_{k,j} coefficients - ij_old = self[i, j] # Store this since it's overwritten, but used in the a_{j,j} computation! + ij_old = self[i, j] # Store this since it's overwritten, but used in the a_{j,j} computation! for k in range(self.dim()): if (k != i) and (k != j): ans = self[j, k] + c * self[i, k] self[j, k] = ans - elif (k == j): + elif k == j: ans = self[j, k] + c * ij_old + c * c * self[i, i] self[j, k] = ans else: diff --git a/src/sage/quadratic_forms/random_quadraticform.py b/src/sage/quadratic_forms/random_quadraticform.py index fb36812bcbd..c5b395da1c1 100644 --- a/src/sage/quadratic_forms/random_quadraticform.py +++ b/src/sage/quadratic_forms/random_quadraticform.py @@ -3,6 +3,7 @@ This file contains a set of routines to create a random quadratic form. """ + from sage.categories.rings import Rings from sage.quadratic_forms.quadratic_form import QuadraticForm from sage.quadratic_forms.ternary_qf import TernaryQF @@ -13,6 +14,7 @@ # Routines to create a random quadratic form ## ################################################ + def random_quadraticform(R, n, rand_arg_list=None): r""" Create a random quadratic form in `n` variables defined over the ring `R`. @@ -60,8 +62,7 @@ def random_quadraticform(R, n, rand_arg_list=None): if rand_arg_list is None: rand_arg_list = [] if len(rand_arg_list) > 3: - raise TypeError("the list of randomness arguments can have " - "at most 3 elements") + raise TypeError("the list of randomness arguments can have " "at most 3 elements") if R not in Rings(): raise TypeError("the first argument must be a ring") # Create a list of upper-triangular entries for the quadratic form @@ -73,8 +74,7 @@ def random_quadraticform(R, n, rand_arg_list=None): return QuadraticForm(R, n, rand_list) -def random_quadraticform_with_conditions(R, n, condition_list=[], - rand_arg_list=None): +def random_quadraticform_with_conditions(R, n, condition_list=[], rand_arg_list=None): """ Create a random quadratic form in `n` variables defined over the ring `R` satisfying a list of boolean (i.e. True/False) conditions. diff --git a/src/sage/quadratic_forms/special_values.py b/src/sage/quadratic_forms/special_values.py index ed7619e616f..e46ec3f7f79 100644 --- a/src/sage/quadratic_forms/special_values.py +++ b/src/sage/quadratic_forms/special_values.py @@ -9,10 +9,7 @@ import sage.rings.abc -from sage.arith.misc import (bernoulli, - factorial, - fundamental_discriminant, - kronecker as kronecker_symbol) +from sage.arith.misc import bernoulli, factorial, fundamental_discriminant, kronecker as kronecker_symbol from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -21,6 +18,7 @@ # ---------------- The Gamma Function ------------------ + def gamma__exact(n): r""" Return the exact value of the `\Gamma` function at an integer or @@ -91,6 +89,7 @@ def gamma__exact(n): # ------------- The Riemann Zeta Function -------------- + def zeta__exact(n): r""" Return the exact value of the Riemann Zeta function. @@ -149,13 +148,14 @@ def zeta__exact(n): if not n % 2: from sage.symbolic.constants import pi - return ZZ(-1)**(n // 2 + 1) * ZZ(2)**(n - 1) * pi**n * bernoulli(n) / factorial(n) + return ZZ(-1) ** (n // 2 + 1) * ZZ(2) ** (n - 1) * pi**n * bernoulli(n) / factorial(n) raise TypeError("n must be a critical value (i.e. even > 0 or odd < 0)") return infinity if n == 1 else QQ((-1, 2)) # ---------- Dirichlet L-functions with quadratic characters ---------- + def QuadraticBernoulliNumber(k, d): r""" Compute `k`-th Bernoulli number for the primitive @@ -192,7 +192,7 @@ def QuadraticBernoulliNumber(k, d): # Make the k-th quadratic Bernoulli number total = sum([kronecker_symbol(d1, i) * bp(i / f) for i in range(f)]) - total *= f**(k - 1) + total *= f ** (k - 1) return total @@ -241,9 +241,9 @@ def quadratic_L_function__exact(n, d): f = abs(fundamental_discriminant(d)) GS = f.sqrt() if delta == 0 else I * f.sqrt() - ans = (2 * pi / f)**n - ans *= ZZ(-1)**(1 + (n - delta) // 2) - ans *= GS # Evaluate the Gauss sum here! =0 + ans = (2 * pi / f) ** n + ans *= ZZ(-1) ** (1 + (n - delta) // 2) + ans *= GS # Evaluate the Gauss sum here! =0 ans *= QQ.one() / (2 * I**delta) ans *= QuadraticBernoulliNumber(n, d) / factorial(n) return ans @@ -296,6 +296,7 @@ def quadratic_L_function__numerical(n, d, num_terms=1000): R = n.parent() else: from sage.rings.real_mpfr import RealField + R = RealField() if n < 0: @@ -304,5 +305,5 @@ def quadratic_L_function__numerical(n, d, num_terms=1000): d1 = fundamental_discriminant(d) ans = R.zero() for i in range(1, num_terms): - ans += R(kronecker_symbol(d1, i) / R(i)**n) + ans += R(kronecker_symbol(d1, i) / R(i) ** n) return ans diff --git a/src/sage/quadratic_forms/ternary_qf.py b/src/sage/quadratic_forms/ternary_qf.py index e7cab85c9e2..4f1195f3f44 100644 --- a/src/sage/quadratic_forms/ternary_qf.py +++ b/src/sage/quadratic_forms/ternary_qf.py @@ -30,14 +30,7 @@ from sage.matrix.constructor import matrix, identity_matrix from sage.misc.prandom import randint from sage.quadratic_forms.quadratic_form import QuadraticForm -from sage.quadratic_forms.ternary import (_basic_lemma, - _find_a_ternary_qf_by_level_disc, - _find_all_ternary_qf_by_level_disc, - _find_p_neighbor_from_vec, - _find_zeros_mod_p_2, - _find_zeros_mod_p_odd, - _reduced_ternary_form_eisenstein_with_matrix, - _reduced_ternary_form_eisenstein_without_matrix) +from sage.quadratic_forms.ternary import _basic_lemma, _find_a_ternary_qf_by_level_disc, _find_all_ternary_qf_by_level_disc, _find_p_neighbor_from_vec, _find_zeros_mod_p_2, _find_zeros_mod_p_odd, _reduced_ternary_form_eisenstein_with_matrix, _reduced_ternary_form_eisenstein_without_matrix from sage.rings.finite_rings.integer_mod import mod from sage.rings.integer_ring import ZZ @@ -70,8 +63,7 @@ class TernaryQF(SageObject): sage: TestSuite(TernaryQF).run() """ - __slots__ = ['_a', '_b', '_c', '_r', '_s', '_t', - '_automorphisms', '_number_of_automorphisms'] + __slots__ = ['_a', '_b', '_c', '_r', '_s', '_t', '_automorphisms', '_number_of_automorphisms'] possible_automorphisms = None @@ -164,7 +156,7 @@ def polynomial(self, names='x,y,z'): Multivariate Polynomial Ring in x, y, z over Integer Ring """ x, y, z = polygens(ZZ, names) - return self._a * x**2 + self._b * y**2 + self._c * z**2 + self._t * x*y + self._s * x*z + self._r * y*z + return self._a * x**2 + self._b * y**2 + self._c * z**2 + self._t * x * y + self._s * x * z + self._r * y * z def _repr_(self) -> str: r""" @@ -230,8 +222,7 @@ def __call__(self, v): # Check if v has 3 cols if v.ncols() == 3: M = v.transpose() * self.matrix() * v - return TernaryQF([M[0, 0] // 2, M[1, 1] // 2, M[2, 2] // 2, - M[1, 2], M[0, 2], M[0, 1]]) + return TernaryQF([M[0, 0] // 2, M[1, 1] // 2, M[2, 2] // 2, M[1, 2], M[0, 2], M[0, 1]]) return QuadraticForm(ZZ, v.transpose() * self.matrix() * v) if isinstance(v, (Vector, list, tuple)): @@ -240,7 +231,7 @@ def __call__(self, v): raise TypeError("your vector needs to have length 3") v0, v1, v2 = v a, b, c, r, s, t = self.coefficients() - return a*v0**2 + b*v1**2 + c*v2**2 + r*v1*v2 + s*v0*v2 + t*v0*v1 + return a * v0**2 + b * v1**2 + c * v2**2 + r * v1 * v2 + s * v0 * v2 + t * v0 * v1 raise TypeError("presently we can only evaluate a quadratic form on a list, tuple, vector or matrix") @@ -260,8 +251,7 @@ def quadratic_form(self): sage: bool(QF1 == QF2) True """ - return QuadraticForm(ZZ, 3, [self._a, self._t, self._s, - self._b, self._r, self._c]) + return QuadraticForm(ZZ, 3, [self._a, self._t, self._s, self._b, self._r, self._c]) def matrix(self): r""" @@ -291,9 +281,7 @@ def matrix(self): sage: (v*M*v.column())[0]//2 28 """ - return matrix(ZZ, 3, 3, [2 * self._a, self._t, self._s, - self._t, 2 * self._b, self._r, - self._s, self._r, 2 * self._c]) + return matrix(ZZ, 3, 3, [2 * self._a, self._t, self._s, self._t, 2 * self._b, self._r, self._s, self._r, 2 * self._c]) def disc(self): r""" @@ -309,8 +297,7 @@ def disc(self): sage: Q.matrix().det() -50 """ - return (4*self._a*self._b*self._c + self._r*self._s*self._t - - self._a*self._r**2 - self._b*self._s**2 - self._c*self._t**2) + return 4 * self._a * self._b * self._c + self._r * self._s * self._t - self._a * self._r**2 - self._b * self._s**2 - self._c * self._t**2 def is_definite(self) -> bool: """ @@ -493,15 +480,13 @@ def scale_by_factor(self, k): [ * * 4/3 ] """ if k * self.content() in ZZ: - return TernaryQF([ZZ(k*self._a), ZZ(k*self._b), ZZ(k*self._c), - ZZ(k*self._r), ZZ(k*self._s), ZZ(k*self._t)]) + return TernaryQF([ZZ(k * self._a), ZZ(k * self._b), ZZ(k * self._c), ZZ(k * self._r), ZZ(k * self._s), ZZ(k * self._t)]) R = k.parent() if R not in Rings(): raise TypeError(f"{k} does not belong to a ring") - return QuadraticForm(R, 3, [k * self._a, k * self._t, k * self._s, - k * self._b, k * self._r, k * self._c]) + return QuadraticForm(R, 3, [k * self._a, k * self._t, k * self._s, k * self._b, k * self._r, k * self._c]) def reciprocal(self): """ @@ -555,13 +540,13 @@ def divisor(self): sage: Q.divisor() 4 """ - A11 = 4*self._b*self._c - self._r**2 - A22 = 4*self._a*self._c - self._s**2 - A33 = 4*self._a*self._b - self._t**2 - A23 = self._s*self._t - 2*self._a*self._r - A13 = self._r*self._t - 2*self._b*self._s - A12 = self._r*self._s - 2*self._c*self._t - m = gcd([A11, A22, A33, 2*A12, 2*A13, 2*A23]) + A11 = 4 * self._b * self._c - self._r**2 + A22 = 4 * self._a * self._c - self._s**2 + A33 = 4 * self._a * self._b - self._t**2 + A23 = self._s * self._t - 2 * self._a * self._r + A13 = self._r * self._t - 2 * self._b * self._s + A12 = self._r * self._s - 2 * self._c * self._t + m = gcd([A11, A22, A33, 2 * A12, 2 * A13, 2 * A23]) return m def __eq__(self, right) -> bool: @@ -599,13 +584,13 @@ def adjoint(self): sage: Q.adjoint().matrix() == 2*Q.matrix().adjoint_classical() True """ - A11 = 4*self._b*self._c - self._r**2 - A22 = 4*self._a*self._c - self._s**2 - A33 = 4*self._a*self._b - self._t**2 - A23 = self._s*self._t - 2*self._a*self._r - A13 = self._r*self._t - 2*self._b*self._s - A12 = self._r*self._s - 2*self._c*self._t - return TernaryQF([A11, A22, A33, 2*A23, 2*A13, 2*A12]) + A11 = 4 * self._b * self._c - self._r**2 + A22 = 4 * self._a * self._c - self._s**2 + A33 = 4 * self._a * self._b - self._t**2 + A23 = self._s * self._t - 2 * self._a * self._r + A13 = self._r * self._t - 2 * self._b * self._s + A12 = self._r * self._s - 2 * self._c * self._t + return TernaryQF([A11, A22, A33, 2 * A23, 2 * A13, 2 * A12]) def content(self): """ @@ -703,8 +688,7 @@ def is_eisenstein_reduced(self) -> bool: sage: Q.is_eisenstein_reduced() False """ - a, b, c, r, s, t = [self._a, self._b, self._c, - self._r, self._s, self._t] + a, b, c, r, s, t = [self._a, self._b, self._c, self._r, self._s, self._t] # cond 2 if not (r > 0 and t > 0 and s > 0): @@ -712,7 +696,7 @@ def is_eisenstein_reduced(self) -> bool: return False # cond 1 & 4 - if not (a <= b <= c and 0 <= a+b+r+s+t): + if not (a <= b <= c and 0 <= a + b + r + s + t): return False # cond 3 @@ -724,7 +708,7 @@ def is_eisenstein_reduced(self) -> bool: return False if b == c and abs(s) > abs(t): return False - if a+b+r+s+t == 0 and 2*a+2*s+t > 0: + if a + b + r + s + t == 0 and 2 * a + 2 * s + t > 0: return False # cond 6 @@ -739,9 +723,9 @@ def is_eisenstein_reduced(self) -> bool: # cond 7 # r, s, t > 0 - if a == t and s > 2*r: + if a == t and s > 2 * r: return False - if a == s and t > 2*r: + if a == s and t > 2 * r: return False return not (b == r and t > 2 * s) @@ -804,19 +788,19 @@ def pseudorandom_primitive_zero_mod_p(self, p): a, b, c, r, s, t = self.coefficients() while True: - r1 = randint(0, p-1) - r2 = randint(0, p-1) - alpha = (b*r1**2+t*r1+a) % p + r1 = randint(0, p - 1) + r2 = randint(0, p - 1) + alpha = (b * r1**2 + t * r1 + a) % p if alpha != 0: - beta = (2*b*r1*r2+t*r2+r*r1+s) % p - gamma = (b*r2**2+r*r2+c) % p - disc = beta**2-4*alpha*gamma + beta = (2 * b * r1 * r2 + t * r2 + r * r1 + s) % p + gamma = (b * r2**2 + r * r2 + c) % p + disc = beta**2 - 4 * alpha * gamma if mod(disc, p).is_square(): - z = (-beta+mod(disc, p).sqrt().lift())*(2*alpha).inverse_mod(p) + z = (-beta + mod(disc, p).sqrt().lift()) * (2 * alpha).inverse_mod(p) # return vector((z,r1*z+r2,1))%p - return z % p, (r1*z+r2) % p, 1 + return z % p, (r1 * z + r2) % p, 1 def find_zeros_mod_p(self, p): """ @@ -838,8 +822,7 @@ def find_zeros_mod_p(self, p): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] """ if p == 2: - return _find_zeros_mod_p_2(self._a, self._b, self._c, - self._r, self._s, self._t) + return _find_zeros_mod_p_2(self._a, self._b, self._c, self._r, self._s, self._t) v = self.pseudorandom_primitive_zero_mod_p(p) a, b, c, r, s, t = self.coefficients() @@ -892,7 +875,7 @@ def find_p_neighbor_from_vec(self, p, v, mat=False): if mat: q, M = _find_p_neighbor_from_vec(self._a, self._b, self._c, self._r, self._s, self._t, p, v, mat) M = matrix(3, M) - return TernaryQF(q), M*M.det() + return TernaryQF(q), M * M.det() return TernaryQF(_find_p_neighbor_from_vec(self._a, self._b, self._c, self._r, self._s, self._t, p, v, mat)) def find_p_neighbors(self, p, mat=False): @@ -1020,7 +1003,7 @@ def symmetry(self, v): True """ - return identity_matrix(3) - v.column()*matrix(v)*self.matrix()/self(v) + return identity_matrix(3) - v.column() * matrix(v) * self.matrix() / self(v) def automorphism_symmetries(self, A) -> list: """ @@ -1161,19 +1144,19 @@ def _border(self, n) -> bool: """ a, b, c, r, s, t = self.coefficients() if n == 1: - return (a == t) and (s == 2*r) + return (a == t) and (s == 2 * r) if n == 2: - return (a == s) and (t == 2*r) + return (a == s) and (t == 2 * r) if n == 3: - return (b == r) and (t == 2*s) + return (b == r) and (t == 2 * s) if n == 4: - return (a == -t) + return a == -t if n == 5: - return (a == -s) + return a == -s if n == 6: - return (b == -r) + return b == -r if n == 7: - return (a + b + r + s + t == 0) and (2*a + 2*s + t == 0) + return (a + b + r + s + t == 0) and (2 * a + 2 * s + t == 0) if n == 8: return (a == b) and (r == s) if n == 9: @@ -1276,58 +1259,30 @@ def _automorphisms_reduced_fast(self): if self._border(14): if self._border(9): # borders 1, 2, 9, 14 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, -1, -1, 0, 0, 1, 0, 1, 0), - (-1, -1, 0, 0, 1, 0, 0, 0, -1), - (-1, 0, -1, 0, -1, 0, 0, 0, 1), - (-1, 0, 0, 0, 0, -1, 0, -1, 0), - (1, 0, 1, 0, 0, -1, 0, 1, 0), - (1, 1, 0, 0, 0, 1, 0, -1, 0), - (1, 1, 1, 0, -1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, -1, -1, 0, 0, 1, 0, 1, 0), (-1, -1, 0, 0, 1, 0, 0, 0, -1), (-1, 0, -1, 0, -1, 0, 0, 0, 1), (-1, 0, 0, 0, 0, -1, 0, -1, 0), (1, 0, 1, 0, 0, -1, 0, 1, 0), (1, 1, 0, 0, 0, 1, 0, -1, 0), (1, 1, 1, 0, -1, 0, 0, 0, -1)] # borders 1, 2, 14 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, -1, 0, 0, 1, 0, 0, 0, -1), - (-1, 0, -1, 0, -1, 0, 0, 0, 1), - (1, 1, 1, 0, -1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, -1, 0, 0, 1, 0, 0, 0, -1), (-1, 0, -1, 0, -1, 0, 0, 0, 1), (1, 1, 1, 0, -1, 0, 0, 0, -1)] else: # borders 1 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, -1, 0, 0, 1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, -1, 0, 0, 1, 0, 0, 0, -1)] if self._border(2): # borders 2 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, -1, 0, -1, 0, 0, 0, 1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, -1, 0, -1, 0, 0, 0, 1)] if self._border(3): # borders 3 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, 0, -1, -1, 0, 0, 1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, -1, -1, 0, 0, 1)] if self._border(4): if self._border(10): if self._border(8): # borders 4, 8, 10 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, -1, 1, 0, 0, 0, -1), - (-1, 0, 0, 0, -1, 0, 0, 0, 1), - (-1, 1, 0, -1, 0, 0, 0, 0, 1), - (-1, 1, 0, 0, 1, 0, 0, 0, -1), - (0, -1, 0, -1, 0, 0, 0, 0, -1), - (0, -1, 0, 1, -1, 0, 0, 0, 1), - (0, 1, 0, -1, 1, 0, 0, 0, 1), - (0, 1, 0, 1, 0, 0, 0, 0, -1), - (1, -1, 0, 0, -1, 0, 0, 0, -1), - (1, -1, 0, 1, 0, 0, 0, 0, 1), - (1, 0, 0, 1, -1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, -1, 1, 0, 0, 0, -1), (-1, 0, 0, 0, -1, 0, 0, 0, 1), (-1, 1, 0, -1, 0, 0, 0, 0, 1), (-1, 1, 0, 0, 1, 0, 0, 0, -1), (0, -1, 0, -1, 0, 0, 0, 0, -1), (0, -1, 0, 1, -1, 0, 0, 0, 1), (0, 1, 0, -1, 1, 0, 0, 0, 1), (0, 1, 0, 1, 0, 0, 0, 0, -1), (1, -1, 0, 0, -1, 0, 0, 0, -1), (1, -1, 0, 1, 0, 0, 0, 0, 1), (1, 0, 0, 1, -1, 0, 0, 0, -1)] # borders 4, 10 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, 0, -1, 0, 0, 0, 1), - (-1, 1, 0, 0, 1, 0, 0, 0, -1), - (1, -1, 0, 0, -1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, -1, 0, 0, 0, 1), (-1, 1, 0, 0, 1, 0, 0, 0, -1), (1, -1, 0, 0, -1, 0, 0, 0, -1)] # borders 4 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (1, -1, 0, 0, -1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (1, -1, 0, 0, -1, 0, 0, 0, -1)] if self._border(5): if self._border(6): @@ -1335,284 +1290,113 @@ def _automorphisms_reduced_fast(self): if self._border(8): if self._border(15): # borders 5, 6, 7, 8, 15 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, 0, 1, -1, 0, 0, -1), - (-1, 0, 1, 0, -1, 1, 0, 0, 1), - (0, -1, 0, -1, 0, 0, 0, 0, -1), - (0, -1, 1, 1, 0, 0, 0, 0, 1), - (0, 1, -1, 1, 0, -1, 0, 0, -1), - (0, 1, 0, -1, 0, 1, 0, 0, 1), - (1, 0, -1, 0, -1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, 1, -1, 0, 0, -1), (-1, 0, 1, 0, -1, 1, 0, 0, 1), (0, -1, 0, -1, 0, 0, 0, 0, -1), (0, -1, 1, 1, 0, 0, 0, 0, 1), (0, 1, -1, 1, 0, -1, 0, 0, -1), (0, 1, 0, -1, 0, 1, 0, 0, 1), (1, 0, -1, 0, -1, 0, 0, 0, -1)] else: # borders 5, 6, 7 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, 0, 1, -1, 0, 0, -1), - (-1, 0, 1, 0, -1, 1, 0, 0, 1), - (1, 0, -1, 0, -1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, 1, -1, 0, 0, -1), (-1, 0, 1, 0, -1, 1, 0, 0, 1), (1, 0, -1, 0, -1, 0, 0, 0, -1)] elif self._border(11): # borders 5, 11 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, 0, 1, 0, 0, 0, -1), - (-1, 0, 1, 0, -1, 0, 0, 0, 1), - (1, 0, -1, 0, -1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, 1, 0, 0, 0, -1), (-1, 0, 1, 0, -1, 0, 0, 0, 1), (1, 0, -1, 0, -1, 0, 0, 0, -1)] else: # borders 5 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (1, 0, -1, 0, -1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (1, 0, -1, 0, -1, 0, 0, 0, -1)] if self._border(6): if self._border(12): if self._border(9): # borders 6, 9, 12 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, 0, -1, 0, 0, -1, 1), - (-1, 0, 0, 0, -1, 1, 0, 0, 1), - (-1, 0, 0, 0, 0, -1, 0, -1, 0), - (-1, 0, 0, 0, 0, 1, 0, 1, 0), - (-1, 0, 0, 0, 1, -1, 0, 0, -1), - (-1, 0, 0, 0, 1, 0, 0, 1, -1), - (1, 0, 0, 0, -1, 0, 0, 0, -1), - (1, 0, 0, 0, -1, 1, 0, -1, 0), - (1, 0, 0, 0, 0, -1, 0, 1, -1), - (1, 0, 0, 0, 0, 1, 0, -1, 1), - (1, 0, 0, 0, 1, -1, 0, 1, 0)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, -1, 0, 0, -1, 1), (-1, 0, 0, 0, -1, 1, 0, 0, 1), (-1, 0, 0, 0, 0, -1, 0, -1, 0), (-1, 0, 0, 0, 0, 1, 0, 1, 0), (-1, 0, 0, 0, 1, -1, 0, 0, -1), (-1, 0, 0, 0, 1, 0, 0, 1, -1), (1, 0, 0, 0, -1, 0, 0, 0, -1), (1, 0, 0, 0, -1, 1, 0, -1, 0), (1, 0, 0, 0, 0, -1, 0, 1, -1), (1, 0, 0, 0, 0, 1, 0, -1, 1), (1, 0, 0, 0, 1, -1, 0, 1, 0)] # borders 6, 12 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, 0, -1, 1, 0, 0, 1), - (-1, 0, 0, 0, 1, -1, 0, 0, -1), - (1, 0, 0, 0, -1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, -1, 1, 0, 0, 1), (-1, 0, 0, 0, 1, -1, 0, 0, -1), (1, 0, 0, 0, -1, 0, 0, 0, -1)] # borders 6 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, 0, 1, -1, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, 1, -1, 0, 0, -1)] if self._border(7): if self._border(8) and self._border(15): if self._border(16): if self._border(9): # borders 7, 8, 9, 15, 16 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, -1, 0, 1, -1, 1, 0), - (-1, 0, 0, 0, 0, -1, 0, -1, 0), - (-1, 0, 1, -1, 1, 0, -1, 0, 0), - (-1, 0, 1, 0, -1, 1, 0, 0, 1), - (-1, 1, 0, -1, 0, 0, -1, 0, 1), - (-1, 1, 0, 0, 1, 0, 0, 1, -1), - (0, -1, 0, -1, 0, 0, 0, 0, -1), - (0, -1, 0, 1, -1, 0, 0, -1, 1), - (0, -1, 1, 0, -1, 0, 1, -1, 0), - (0, -1, 1, 0, 0, 1, -1, 0, 1), - (0, 0, -1, 0, -1, 0, -1, 0, 0), - (0, 0, -1, 0, 1, -1, 1, 0, -1), - (0, 0, 1, -1, 0, 1, 0, -1, 1), - (0, 0, 1, 1, 0, 0, 0, 1, 0), - (0, 1, -1, -1, 1, 0, 0, 1, 0), - (0, 1, -1, 1, 0, -1, 0, 0, -1), - (0, 1, 0, 0, 0, 1, 1, 0, 0), - (0, 1, 0, 0, 1, -1, -1, 1, 0), - (1, -1, 0, 0, -1, 1, 0, -1, 0), - (1, -1, 0, 1, 0, -1, 1, 0, 0), - (1, 0, -1, 0, 0, -1, 0, 1, -1), - (1, 0, -1, 1, 0, 0, 1, -1, 0), - (1, 0, 0, 1, -1, 0, 1, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, -1, 0, 1, -1, 1, 0), (-1, 0, 0, 0, 0, -1, 0, -1, 0), (-1, 0, 1, -1, 1, 0, -1, 0, 0), (-1, 0, 1, 0, -1, 1, 0, 0, 1), (-1, 1, 0, -1, 0, 0, -1, 0, 1), (-1, 1, 0, 0, 1, 0, 0, 1, -1), (0, -1, 0, -1, 0, 0, 0, 0, -1), (0, -1, 0, 1, -1, 0, 0, -1, 1), (0, -1, 1, 0, -1, 0, 1, -1, 0), (0, -1, 1, 0, 0, 1, -1, 0, 1), (0, 0, -1, 0, -1, 0, -1, 0, 0), (0, 0, -1, 0, 1, -1, 1, 0, -1), (0, 0, 1, -1, 0, 1, 0, -1, 1), (0, 0, 1, 1, 0, 0, 0, 1, 0), (0, 1, -1, -1, 1, 0, 0, 1, 0), (0, 1, -1, 1, 0, -1, 0, 0, -1), (0, 1, 0, 0, 0, 1, 1, 0, 0), (0, 1, 0, 0, 1, -1, -1, 1, 0), (1, -1, 0, 0, -1, 1, 0, -1, 0), (1, -1, 0, 1, 0, -1, 1, 0, 0), (1, 0, -1, 0, 0, -1, 0, 1, -1), (1, 0, -1, 1, 0, 0, 1, -1, 0), (1, 0, 0, 1, -1, 0, 1, 0, -1)] # borders 7, 8, 15, 16 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, -1, 0, 1, -1, 1, 0), - (-1, 0, 1, 0, -1, 1, 0, 0, 1), - (0, -1, 0, -1, 0, 0, 0, 0, -1), - (0, -1, 1, 0, -1, 0, 1, -1, 0), - (0, 1, -1, 1, 0, -1, 0, 0, -1), - (0, 1, 0, 0, 1, -1, -1, 1, 0), - (1, 0, -1, 1, 0, 0, 1, -1, 0)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, -1, 0, 1, -1, 1, 0), (-1, 0, 1, 0, -1, 1, 0, 0, 1), (0, -1, 0, -1, 0, 0, 0, 0, -1), (0, -1, 1, 0, -1, 0, 1, -1, 0), (0, 1, -1, 1, 0, -1, 0, 0, -1), (0, 1, 0, 0, 1, -1, -1, 1, 0), (1, 0, -1, 1, 0, 0, 1, -1, 0)] # borders 7, 8, 15 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 1, 0, -1, 1, 0, 0, 1), - (0, -1, 0, -1, 0, 0, 0, 0, -1), - (0, 1, -1, 1, 0, -1, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 1, 0, -1, 1, 0, 0, 1), (0, -1, 0, -1, 0, 0, 0, 0, -1), (0, 1, -1, 1, 0, -1, 0, 0, -1)] if self._border(9): # borders 7, 9 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, 0, 0, -1, 0, -1, 0), - (-1, 0, 1, 0, -1, 1, 0, 0, 1), - (-1, 1, 0, 0, 1, 0, 0, 1, -1), - (1, -1, 0, 0, -1, 1, 0, -1, 0), - (1, 0, -1, 0, 0, -1, 0, 1, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, 0, -1, 0, -1, 0), (-1, 0, 1, 0, -1, 1, 0, 0, 1), (-1, 1, 0, 0, 1, 0, 0, 1, -1), (1, -1, 0, 0, -1, 1, 0, -1, 0), (1, 0, -1, 0, 0, -1, 0, 1, -1)] # borders 7 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 1, 0, -1, 1, 0, 0, 1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 1, 0, -1, 1, 0, 0, 1)] if self._border(8): if self._border(9): if self._border(10) and self._border(11) and self._border(12): # borders 8, 9, 10, 11, 12 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, 0, -1, 0, 0, 0, 1), - (-1, 0, 0, 0, 0, -1, 0, -1, 0), - (-1, 0, 0, 0, 0, 1, 0, 1, 0), - (-1, 0, 0, 0, 1, 0, 0, 0, -1), - (0, -1, 0, -1, 0, 0, 0, 0, -1), - (0, -1, 0, 0, 0, -1, 1, 0, 0), - (0, -1, 0, 0, 0, 1, -1, 0, 0), - (0, -1, 0, 1, 0, 0, 0, 0, 1), - (0, 0, -1, -1, 0, 0, 0, 1, 0), - (0, 0, -1, 0, -1, 0, -1, 0, 0), - (0, 0, -1, 0, 1, 0, 1, 0, 0), - (0, 0, -1, 1, 0, 0, 0, -1, 0), - (0, 0, 1, -1, 0, 0, 0, -1, 0), - (0, 0, 1, 0, -1, 0, 1, 0, 0), - (0, 0, 1, 0, 1, 0, -1, 0, 0), - (0, 0, 1, 1, 0, 0, 0, 1, 0), - (0, 1, 0, -1, 0, 0, 0, 0, 1), - (0, 1, 0, 0, 0, -1, -1, 0, 0), - (0, 1, 0, 0, 0, 1, 1, 0, 0), - (0, 1, 0, 1, 0, 0, 0, 0, -1), - (1, 0, 0, 0, -1, 0, 0, 0, -1), - (1, 0, 0, 0, 0, -1, 0, 1, 0), - (1, 0, 0, 0, 0, 1, 0, -1, 0)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, -1, 0, 0, 0, 1), (-1, 0, 0, 0, 0, -1, 0, -1, 0), (-1, 0, 0, 0, 0, 1, 0, 1, 0), (-1, 0, 0, 0, 1, 0, 0, 0, -1), (0, -1, 0, -1, 0, 0, 0, 0, -1), (0, -1, 0, 0, 0, -1, 1, 0, 0), (0, -1, 0, 0, 0, 1, -1, 0, 0), (0, -1, 0, 1, 0, 0, 0, 0, 1), (0, 0, -1, -1, 0, 0, 0, 1, 0), (0, 0, -1, 0, -1, 0, -1, 0, 0), (0, 0, -1, 0, 1, 0, 1, 0, 0), (0, 0, -1, 1, 0, 0, 0, -1, 0), (0, 0, 1, -1, 0, 0, 0, -1, 0), (0, 0, 1, 0, -1, 0, 1, 0, 0), (0, 0, 1, 0, 1, 0, -1, 0, 0), (0, 0, 1, 1, 0, 0, 0, 1, 0), (0, 1, 0, -1, 0, 0, 0, 0, 1), (0, 1, 0, 0, 0, -1, -1, 0, 0), (0, 1, 0, 0, 0, 1, 1, 0, 0), (0, 1, 0, 1, 0, 0, 0, 0, -1), (1, 0, 0, 0, -1, 0, 0, 0, -1), (1, 0, 0, 0, 0, -1, 0, 1, 0), (1, 0, 0, 0, 0, 1, 0, -1, 0)] if self._border(13) and self._border(14): # borders 8, 9, 13, 14 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, -1, -1, 0, 0, 1, 0, 1, 0), - (-1, -1, -1, 0, 1, 0, 1, 0, 0), - (-1, -1, -1, 1, 0, 0, 0, 0, 1), - (-1, 0, 0, 0, -1, 0, 1, 1, 1), - (-1, 0, 0, 0, 0, -1, 0, -1, 0), - (-1, 0, 0, 1, 1, 1, 0, 0, -1), - (0, -1, 0, -1, 0, 0, 0, 0, -1), - (0, -1, 0, 0, 0, -1, 1, 1, 1), - (0, -1, 0, 1, 1, 1, -1, 0, 0), - (0, 0, -1, -1, 0, 0, 1, 1, 1), - (0, 0, -1, 0, -1, 0, -1, 0, 0), - (0, 0, -1, 1, 1, 1, 0, -1, 0), - (0, 0, 1, -1, -1, -1, 1, 0, 0), - (0, 0, 1, 0, 1, 0, -1, -1, -1), - (0, 0, 1, 1, 0, 0, 0, 1, 0), - (0, 1, 0, -1, -1, -1, 0, 0, 1), - (0, 1, 0, 0, 0, 1, 1, 0, 0), - (0, 1, 0, 1, 0, 0, -1, -1, -1), - (1, 0, 0, -1, -1, -1, 0, 1, 0), - (1, 0, 0, 0, 0, 1, -1, -1, -1), - (1, 1, 1, -1, 0, 0, 0, -1, 0), - (1, 1, 1, 0, -1, 0, 0, 0, -1), - (1, 1, 1, 0, 0, -1, -1, 0, 0)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, -1, -1, 0, 0, 1, 0, 1, 0), (-1, -1, -1, 0, 1, 0, 1, 0, 0), (-1, -1, -1, 1, 0, 0, 0, 0, 1), (-1, 0, 0, 0, -1, 0, 1, 1, 1), (-1, 0, 0, 0, 0, -1, 0, -1, 0), (-1, 0, 0, 1, 1, 1, 0, 0, -1), (0, -1, 0, -1, 0, 0, 0, 0, -1), (0, -1, 0, 0, 0, -1, 1, 1, 1), (0, -1, 0, 1, 1, 1, -1, 0, 0), (0, 0, -1, -1, 0, 0, 1, 1, 1), (0, 0, -1, 0, -1, 0, -1, 0, 0), (0, 0, -1, 1, 1, 1, 0, -1, 0), (0, 0, 1, -1, -1, -1, 1, 0, 0), (0, 0, 1, 0, 1, 0, -1, -1, -1), (0, 0, 1, 1, 0, 0, 0, 1, 0), (0, 1, 0, -1, -1, -1, 0, 0, 1), (0, 1, 0, 0, 0, 1, 1, 0, 0), (0, 1, 0, 1, 0, 0, -1, -1, -1), (1, 0, 0, -1, -1, -1, 0, 1, 0), (1, 0, 0, 0, 0, 1, -1, -1, -1), (1, 1, 1, -1, 0, 0, 0, -1, 0), (1, 1, 1, 0, -1, 0, 0, 0, -1), (1, 1, 1, 0, 0, -1, -1, 0, 0)] # borders 8, 9 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, 0, 0, -1, 0, -1, 0), - (0, -1, 0, -1, 0, 0, 0, 0, -1), - (0, 0, -1, 0, -1, 0, -1, 0, 0), - (0, 0, 1, 1, 0, 0, 0, 1, 0), - (0, 1, 0, 0, 0, 1, 1, 0, 0)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, 0, -1, 0, -1, 0), (0, -1, 0, -1, 0, 0, 0, 0, -1), (0, 0, -1, 0, -1, 0, -1, 0, 0), (0, 0, 1, 1, 0, 0, 0, 1, 0), (0, 1, 0, 0, 0, 1, 1, 0, 0)] if self._border(10): if self._border(11) and self._border(12): # borders 8, 10, 11, 12 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, 0, -1, 0, 0, 0, 1), - (-1, 0, 0, 0, 1, 0, 0, 0, -1), - (0, -1, 0, -1, 0, 0, 0, 0, -1), - (0, -1, 0, 1, 0, 0, 0, 0, 1), - (0, 1, 0, -1, 0, 0, 0, 0, 1), - (0, 1, 0, 1, 0, 0, 0, 0, -1), - (1, 0, 0, 0, -1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, -1, 0, 0, 0, 1), (-1, 0, 0, 0, 1, 0, 0, 0, -1), (0, -1, 0, -1, 0, 0, 0, 0, -1), (0, -1, 0, 1, 0, 0, 0, 0, 1), (0, 1, 0, -1, 0, 0, 0, 0, 1), (0, 1, 0, 1, 0, 0, 0, 0, -1), (1, 0, 0, 0, -1, 0, 0, 0, -1)] # borders 8, 10 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, 0, -1, 0, 0, 0, 1), - (0, -1, 0, -1, 0, 0, 0, 0, -1), - (0, 1, 0, 1, 0, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, -1, 0, 0, 0, 1), (0, -1, 0, -1, 0, 0, 0, 0, -1), (0, 1, 0, 1, 0, 0, 0, 0, -1)] if self._border(14): # borders 8, 13, 14 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, -1, -1, 1, 0, 0, 0, 0, 1), - (-1, 0, 0, 1, 1, 1, 0, 0, -1), - (0, -1, 0, -1, 0, 0, 0, 0, -1), - (0, 1, 0, -1, -1, -1, 0, 0, 1), - (1, 1, 1, 0, -1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, -1, -1, 1, 0, 0, 0, 0, 1), (-1, 0, 0, 1, 1, 1, 0, 0, -1), (0, -1, 0, -1, 0, 0, 0, 0, -1), (0, 1, 0, -1, -1, -1, 0, 0, 1), (1, 1, 1, 0, -1, 0, 0, 0, -1)] # borders 8 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (0, -1, 0, -1, 0, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (0, -1, 0, -1, 0, 0, 0, 0, -1)] if self._border(9): if self._border(12): if self._border(10) and self._border(11): # borders 9, 10, 11, 12 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, 0, -1, 0, 0, 0, 1), - (-1, 0, 0, 0, 0, -1, 0, -1, 0), - (-1, 0, 0, 0, 0, 1, 0, 1, 0), - (-1, 0, 0, 0, 1, 0, 0, 0, -1), - (1, 0, 0, 0, -1, 0, 0, 0, -1), - (1, 0, 0, 0, 0, -1, 0, 1, 0), - (1, 0, 0, 0, 0, 1, 0, -1, 0)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, -1, 0, 0, 0, 1), (-1, 0, 0, 0, 0, -1, 0, -1, 0), (-1, 0, 0, 0, 0, 1, 0, 1, 0), (-1, 0, 0, 0, 1, 0, 0, 0, -1), (1, 0, 0, 0, -1, 0, 0, 0, -1), (1, 0, 0, 0, 0, -1, 0, 1, 0), (1, 0, 0, 0, 0, 1, 0, -1, 0)] # borders 9, 12 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, 0, 0, -1, 0, -1, 0), - (-1, 0, 0, 0, 0, 1, 0, 1, 0), - (1, 0, 0, 0, -1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, 0, -1, 0, -1, 0), (-1, 0, 0, 0, 0, 1, 0, 1, 0), (1, 0, 0, 0, -1, 0, 0, 0, -1)] if self._border(14): if self._border(13): # borders 9, 13, 14 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, -1, -1, 0, 0, 1, 0, 1, 0), - (-1, 0, 0, 0, 0, -1, 0, -1, 0), - (1, 1, 1, 0, -1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, -1, -1, 0, 0, 1, 0, 1, 0), (-1, 0, 0, 0, 0, -1, 0, -1, 0), (1, 1, 1, 0, -1, 0, 0, 0, -1)] # borders 9, 14 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, -1, -1, 0, 0, 1, 0, 1, 0), - (-1, 0, 0, 0, 0, -1, 0, -1, 0), - (1, 1, 1, 0, -1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, -1, -1, 0, 0, 1, 0, 1, 0), (-1, 0, 0, 0, 0, -1, 0, -1, 0), (1, 1, 1, 0, -1, 0, 0, 0, -1)] if self._border(15): # borders 9, 15, 16 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, -1, 0, 1, -1, 1, 0), - (-1, 0, 0, 0, 0, -1, 0, -1, 0), - (0, -1, 1, 0, -1, 0, 1, -1, 0), - (0, -1, 1, 0, 0, 1, -1, 0, 1), - (0, 1, -1, -1, 1, 0, 0, 1, 0), - (0, 1, -1, 1, 0, -1, 0, 0, -1), - (1, 0, 0, 1, -1, 0, 1, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, -1, 0, 1, -1, 1, 0), (-1, 0, 0, 0, 0, -1, 0, -1, 0), (0, -1, 1, 0, -1, 0, 1, -1, 0), (0, -1, 1, 0, 0, 1, -1, 0, 1), (0, 1, -1, -1, 1, 0, 0, 1, 0), (0, 1, -1, 1, 0, -1, 0, 0, -1), (1, 0, 0, 1, -1, 0, 1, 0, -1)] # borders 9 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, 0, 0, -1, 0, -1, 0)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, 0, -1, 0, -1, 0)] if self._border(10): if self._border(11) and self._border(12): # borders 10, 11, 12 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, 0, -1, 0, 0, 0, 1), - (-1, 0, 0, 0, 1, 0, 0, 0, -1), - (1, 0, 0, 0, -1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, -1, 0, 0, 0, 1), (-1, 0, 0, 0, 1, 0, 0, 0, -1), (1, 0, 0, 0, -1, 0, 0, 0, -1)] # borders 10 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, 0, -1, 0, 0, 0, 1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, -1, 0, 0, 0, 1)] if self._border(11): # borders 11 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, 0, 1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, 1, 0, 0, 0, -1)] if self._border(12): # border 12 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (1, 0, 0, 0, -1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (1, 0, 0, 0, -1, 0, 0, 0, -1)] if self._border(13) and self._border(14): # border 13, 14 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (1, 1, 1, 0, -1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (1, 1, 1, 0, -1, 0, 0, 0, -1)] if self._border(14): # border 14 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (1, 1, 1, 0, -1, 0, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (1, 1, 1, 0, -1, 0, 0, 0, -1)] if self._border(15): if self._border(16): # borders 15, 16 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (-1, 0, 0, -1, 0, 1, -1, 1, 0), - (0, -1, 1, 0, -1, 0, 1, -1, 0), - (0, 1, -1, 1, 0, -1, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, -1, 0, 1, -1, 1, 0), (0, -1, 1, 0, -1, 0, 1, -1, 0), (0, 1, -1, 1, 0, -1, 0, 0, -1)] # borders 15 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), - (0, 1, -1, 1, 0, -1, 0, 0, -1)] + return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (0, 1, -1, 1, 0, -1, 0, 0, -1)] return [(1, 0, 0, 0, 1, 0, 0, 0, 1)] @@ -1646,6 +1430,7 @@ def _automorphisms_reduced_slow(self): ] """ from itertools import product + if TernaryQF.possible_automorphisms is None: auts = (matrix(ZZ, 3, 3, m) for m in product([-1, 0, 1], repeat=9)) auts = [m for m in auts if m.det() == 1] @@ -1716,7 +1501,7 @@ def automorphisms(self, slow=True): Qr, M = self.reduced_form_eisenstein() auts = Qr.automorphisms(slow) M_inv = M.inverse() - self._automorphisms = [M*m*M_inv for m in auts] + self._automorphisms = [M * m * M_inv for m in auts] else: self._automorphisms = (-self).automorphisms() return self._automorphisms diff --git a/src/sage/quivers/algebra.py b/src/sage/quivers/algebra.py index 59505334dab..622485d1023 100644 --- a/src/sage/quivers/algebra.py +++ b/src/sage/quivers/algebra.py @@ -160,14 +160,18 @@ def __init__(self, k, P, order='negdegrevlex'): # Shortcut for _quiver.semigroup() from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis + self._quiver = P.quiver() self._semigroup = P self._ordstr = order - super().__init__(k, self._semigroup, - prefix='', - # element_class=self.Element, - category=GradedAlgebrasWithBasis(k), - bracket=False) + super().__init__( + k, + self._semigroup, + prefix='', + # element_class=self.Element, + category=GradedAlgebrasWithBasis(k), + bracket=False, + ) self._assign_names(self._semigroup.variable_names()) def order_string(self) -> str: @@ -220,9 +224,7 @@ def arrows(self): sage: A.arrows() (a, b, c) """ - return tuple(self._from_dict({index: self.base_ring().one()}, - remove_zeros=False) - for index in self._semigroup.arrows()) + return tuple(self._from_dict({index: self.base_ring().one()}, remove_zeros=False) for index in self._semigroup.arrows()) @cached_method def idempotents(self): @@ -237,9 +239,7 @@ def idempotents(self): sage: A.idempotents() (e_1, e_2, e_3, e_4) """ - return tuple(self._from_dict({index: self.base_ring().one()}, - remove_zeros=False) - for index in self._semigroup.idempotents()) + return tuple(self._from_dict({index: self.base_ring().one()}, remove_zeros=False) for index in self._semigroup.idempotents()) @cached_method def gen(self, i): @@ -261,8 +261,7 @@ def gen(self, i): sage: A.gen(5) b """ - return self._from_dict({self._semigroup.gen(i): self.base_ring().one()}, - remove_zeros=False) + return self._from_dict({self._semigroup.gen(i): self.base_ring().one()}, remove_zeros=False) def ngens(self): """ @@ -298,6 +297,7 @@ def _element_constructor_(self, x): a*c """ from sage.quivers.paths import QuiverPath + # If it's an element of another path algebra, do a linear combination # of the basis if isinstance(x, PathAlgebraElement) and isinstance(x.parent(), PathAlgebra): @@ -613,10 +613,8 @@ def linear_combination(self, iter_of_elements_coeff, factor_on_left=True): 5*e_0 + a - a*d + 2*b + 3*e_2 """ if factor_on_left: - return self.sum(coeff * element - for element, coeff in iter_of_elements_coeff) - return self.sum(element * coeff - for element, coeff in iter_of_elements_coeff) + return self.sum(coeff * element for element, coeff in iter_of_elements_coeff) + return self.sum(element * coeff for element, coeff in iter_of_elements_coeff) def homogeneous_component(self, n): """ diff --git a/src/sage/quivers/ar_quiver.py b/src/sage/quivers/ar_quiver.py index b5bc376fe70..5fa69541565 100644 --- a/src/sage/quivers/ar_quiver.py +++ b/src/sage/quivers/ar_quiver.py @@ -144,6 +144,7 @@ class AuslanderReitenQuiver(UniqueRepresentation, Parent): <1, 4> 7*v1 + 8*v2 <1, -4> 7*v1 + 6*v2 <2, 4> 6*v1 + 7*v2 <2, -4> 8*v1 + 7*v2 """ + @staticmethod def __classcall_private__(cls, quiver): """ @@ -238,14 +239,10 @@ class options(GlobalOptions): \begin{gathered} \left\langle 2, 2 \right\rangle \\ 2 v_{1} + 3 v_{2} \end{gathered} sage: AR.options._reset() """ + NAME = 'AuslanderReitenQuiver' module = 'sage.quivers.ar_quiver' - latex = dict(default='node', - description='Specifies how nodes of the AR quiver should be latexed', - values=dict(node='latex as the node description', - dimension_vector='latex as the dimension vector', - both='latex as both'), - case_sensitive=False) + latex = dict(default='node', description='Specifies how nodes of the AR quiver should be latexed', values=dict(node='latex as the node description', dimension_vector='latex as the dimension vector', both='latex as both'), case_sensitive=False) def _an_element_(self): r""" @@ -345,6 +342,7 @@ def _digraph_set_latex_options(self, G): G.set_latex_options(edge_labels=True) from sage.graphs.dot2tex_utils import have_dot2tex + if have_dot2tex(): from sage.misc.latex import LatexExpr @@ -385,10 +383,8 @@ def digraph_preprojectives(self, max_depth, with_translations=False): # convert cur to the appropriate data cur = {v: self.element_class(self, v, k) for v in cur} verts.extend(cur.values()) - edges.extend((cur[v], cur[u], l) - for u in cur for _, v, l in self._quiver.outgoing_edge_iterator(u) if v in cur) - edges.extend((prev[u], cur[v], l) for v in cur - for u, _, l in self._quiver.incoming_edge_iterator(v) if u in prev) + edges.extend((cur[v], cur[u], l) for u in cur for _, v, l in self._quiver.outgoing_edge_iterator(u) if v in cur) + edges.extend((prev[u], cur[v], l) for v in cur for u, _, l in self._quiver.incoming_edge_iterator(v) if u in prev) if with_translations: edges.extend((cur[v], prev[v], 'ART') for v in cur if v in prev) k += 1 @@ -424,10 +420,8 @@ def digraph_postinjectives(self, max_depth, with_translations=False): # convert cur to the appropriate data cur = {v: self.element_class(self, v, -k) for v in cur} verts.extend(cur.values()) - edges.extend((cur[u], cur[v], l) - for u in cur for _, v, l in self._quiver.outgoing_edge_iterator(u) if v in cur) - edges.extend((cur[v], prev[u], l) for v in cur - for u, _, l in self._quiver.incoming_edge_iterator(v) if u in prev) + edges.extend((cur[u], cur[v], l) for u in cur for _, v, l in self._quiver.outgoing_edge_iterator(u) if v in cur) + edges.extend((cur[v], prev[u], l) for v in cur for u, _, l in self._quiver.incoming_edge_iterator(v) if u in prev) if with_translations: edges.extend((prev[v], cur[v], 'ART') for v in cur if v in prev) k += 1 @@ -482,10 +476,8 @@ def digraph(self, with_translations=False): cur = {v: self.element_class(self, v, k) for v in cur} injectives.update(cur) verts.extend(cur.values()) - edges.extend((cur[v], cur[u], l) - for u in cur for _, v, l in self._quiver.outgoing_edge_iterator(u) if v in cur) - edges.extend((prev[u], cur[v], l) for v in cur - for u, _, l in self._quiver.incoming_edge_iterator(v) if u in prev) + edges.extend((cur[v], cur[u], l) for u in cur for _, v, l in self._quiver.outgoing_edge_iterator(u) if v in cur) + edges.extend((prev[u], cur[v], l) for v in cur for u, _, l in self._quiver.incoming_edge_iterator(v) if u in prev) k += 1 prev = cur cur = self._dim_vecs_level(k) @@ -595,8 +587,7 @@ def _dim_vecs_level(self, k): M = self._dim_vec_space Q = self._quiver if k == 1: - ret = {v: M._from_dict({u: ZZ(len(Q.all_paths(v, u, use_multiedges=True))) for u in Q.vertex_iterator()}) - for v in Q.vertex_iterator()} + ret = {v: M._from_dict({u: ZZ(len(Q.all_paths(v, u, use_multiedges=True))) for u in Q.vertex_iterator()}) for v in Q.vertex_iterator()} elif k > 1: if k > self._max_level: return {} @@ -620,8 +611,7 @@ def _dim_vecs_level(self, k): self._max_level = k elif k == -1: - ret = {v: M._from_dict({u: ZZ(len(Q.all_paths(u, v, use_multiedges=True))) for u in Q.vertex_iterator()}) - for v in Q.vertex_iterator()} + ret = {v: M._from_dict({u: ZZ(len(Q.all_paths(u, v, use_multiedges=True))) for u in Q.vertex_iterator()}) for v in Q.vertex_iterator()} elif k < -1: prev = self._dim_vecs_level(k + 1) @@ -678,6 +668,7 @@ class Element(Element): r""" A node in the AR quiver. """ + def __init__(self, parent, vertex, level): r""" Initialize ``self``. @@ -730,6 +721,7 @@ def _latex_(self) -> str: sage: AR.options._reset() """ from sage.misc.latex import latex + node = r"\left\langle {}, {} \right\rangle".format(latex(self._vertex), self._level) latex_option = self.parent().options.latex if latex_option == "node": diff --git a/src/sage/quivers/homspace.py b/src/sage/quivers/homspace.py index 99388a67994..0d48e933928 100644 --- a/src/sage/quivers/homspace.py +++ b/src/sage/quivers/homspace.py @@ -58,6 +58,7 @@ class QuiverHomSpace(Homset): (Homomorphism of representations of Multi-digraph on 2 vertices, Homomorphism of representations of Multi-digraph on 2 vertices) """ + Element = QuiverRepHom ########################################################################### @@ -106,8 +107,7 @@ def __init__(self, domain, codomain, category=None): # Check that the bases are compatible, and then initialise the homset: if codomain.base_ring() != domain.base_ring(): raise ValueError("representations are not over the same base ring") - Homset.__init__(self, domain, codomain, category=category, - base=domain.base_ring()) + Homset.__init__(self, domain, codomain, category=category, base=domain.base_ring()) # To compute the Hom Space we set up a 'generic' homomorphism where the # maps at each vertex are described by matrices whose entries are @@ -145,6 +145,7 @@ def __init__(self, domain, codomain, category=None): # the rows correspond to variables, and .kernel() will give a right # kernel as is needed. from sage.matrix.constructor import Matrix + coef_mat = Matrix(codomain.base_ring(), varstart[-1], eqs) # eqn keeps track of what equation we are on. If the maps X and Y are @@ -392,10 +393,8 @@ def _identity(self): True """ from sage.matrix.constructor import Matrix - maps = {v: Matrix(self._domain._spaces[v].dimension(), - self._domain._spaces[v].dimension(), - self._base.one()) - for v in self._quiver} + + maps = {v: Matrix(self._domain._spaces[v].dimension(), self._domain._spaces[v].dimension(), self._base.one()) for v in self._quiver} return self.element_class(self._domain, self._codomain, maps) ########################################################################### @@ -502,8 +501,7 @@ def gens(self) -> tuple: (Homomorphism of representations of Multi-digraph on 2 vertices, Homomorphism of representations of Multi-digraph on 2 vertices) """ - return tuple([self.element_class(self._domain, self._codomain, f) - for f in self._space.gens()]) + return tuple([self.element_class(self._domain, self._codomain, f) for f in self._space.gens()]) def coordinates(self, hom): """ @@ -604,15 +602,14 @@ def left_module(self, basis=False): True """ from sage.quivers.representation import QuiverRep + if not self._codomain.is_left_module(): raise ValueError("the codomain must be a left module") # Create the spaces spaces = {} for v in self._quiver: - im_gens = [self([self._codomain.left_edge_action((v, v), f(x)) - for x in self._domain.gens()])._vector - for f in self.gens()] + im_gens = [self([self._codomain.left_edge_action((v, v), f(x)) for x in self._domain.gens()])._vector for f in self.gens()] spaces[v] = self._space.submodule(im_gens) # Create the maps @@ -621,15 +618,13 @@ def left_module(self, basis=False): e_op = (e[1], e[0], e[2]) maps[e_op] = [] for vec in spaces[e[1]].gens(): - vec_im = spaces[e_op[1]].coordinate_vector(self([self._codomain.left_edge_action(e, self(vec)(x)) - for x in self._domain.gens()])._vector) + vec_im = spaces[e_op[1]].coordinate_vector(self([self._codomain.left_edge_action(e, self(vec)(x)) for x in self._domain.gens()])._vector) maps[e_op].append(vec_im) # Create and return the module (and the dict if desired) if basis: basis_dict = {} for v in self._quiver: - basis_dict[v] = [self.element_class(self._domain, self._codomain, vec) - for vec in spaces[v].gens()] + basis_dict[v] = [self.element_class(self._domain, self._codomain, vec) for vec in spaces[v].gens()] return (QuiverRep(self._base, self._semigroup.reverse(), spaces, maps), basis_dict) return QuiverRep(self._base, self._semigroup.reverse(), spaces, maps) diff --git a/src/sage/quivers/morphism.py b/src/sage/quivers/morphism.py index ad135780a69..b13b3f76571 100644 --- a/src/sage/quivers/morphism.py +++ b/src/sage/quivers/morphism.py @@ -222,14 +222,11 @@ def __init__(self, domain, codomain, data={}): # The only case left is that data is a QuiverRepElement else: if not isinstance(data, QuiverRepElement): - raise TypeError("input data must be dictionary, list, " - "QuiverRepElement or vector") + raise TypeError("input data must be dictionary, list, " "QuiverRepElement or vector") if not isinstance(domain, QuiverRep_with_path_basis): - raise TypeError("if data is a QuiverRepElement then domain " - "must be a QuiverRep_with_path_basis.") + raise TypeError("if data is a QuiverRepElement then domain " "must be a QuiverRep_with_path_basis.") if data not in codomain: - raise ValueError("if data is a QuiverRepElement then it must " - "be an element of codomain") + raise ValueError("if data is a QuiverRepElement then it must " "be an element of codomain") im_list = [codomain.right_edge_action(data, p) for v in domain._quiver for p in domain._bases[v]] # WARNING: This code assumes that the function QuiverRep.gens() returns @@ -241,8 +238,7 @@ def __init__(self, domain, codomain, data={}): # Get the gens of the domain and check that im_list is the right length dom_gens = domain.gens() if len(im_list) != len(dom_gens): - raise ValueError(("domain is dimension {} but only {} images" - " were supplied").format(len(dom_gens), len(im_list))) + raise ValueError(("domain is dimension {} but only {} images" " were supplied").format(len(dom_gens), len(im_list))) # Get the matrices of the maps start_index = 0 @@ -268,6 +264,7 @@ def __init__(self, domain, codomain, data={}): # Get the coordinates of the vector from sage.categories.map import Map + vector = [] for v in self._quiver: if v in maps_dict: @@ -275,8 +272,7 @@ def __init__(self, domain, codomain, data={}): try: m = maps_dict[v].matrix() except (AttributeError, ValueError): - gens_images = [codomain._spaces[v].coordinate_vector(maps_dict[v](x)) - for x in domain._spaces[v].gens()] + gens_images = [codomain._spaces[v].coordinate_vector(maps_dict[v](x)) for x in domain._spaces[v].gens()] m = Matrix(self._base_ring, domain_dims[v], codomain_dims[v], gens_images) else: m = Matrix(self._base_ring, domain_dims[v], codomain_dims[v], maps_dict[v]) @@ -335,6 +331,7 @@ def _call_(self, x): Element of quiver representation """ from sage.quivers.representation import QuiverRepElement + # Check the input if not isinstance(x, QuiverRepElement): raise ValueError("QuiverRepHom can only be called on QuiverRepElement") @@ -602,8 +599,7 @@ def __mul__(self, other): sage: (g*h).is_zero() True """ - maps = {v: other.get_matrix(v) * self.get_matrix(v) - for v in self._quiver} + maps = {v: other.get_matrix(v) * self.get_matrix(v) for v in self._quiver} return other._domain.hom(maps, self._codomain) ########################################################################### @@ -726,8 +722,7 @@ def get_matrix(self, vertex): cols = self._codomain._spaces[vertex].dimension() # Slice out the matrix and return - return Matrix(self._base_ring, rows, cols, - self._vector.list()[startdim:startdim + rows * cols]) + return Matrix(self._base_ring, rows, cols, self._vector.list()[startdim : startdim + rows * cols]) def get_map(self, vertex): """ @@ -1090,8 +1085,7 @@ def algebraic_dual(self): # Find the images in the domain and create the module # H = QuiverHomSpace(self._domain, self._quiver.free_module(self._base_ring)) - im_gens = [codomain({v: (g * self)._vector}) - for v in self._quiver for g in domain_gens[v]] + im_gens = [codomain({v: (g * self)._vector}) for v in self._quiver for g in domain_gens[v]] return domain.hom(im_gens, codomain) def direct_sum(self, maps, return_maps=False, pinch=None): diff --git a/src/sage/quivers/path_semigroup.py b/src/sage/quivers/path_semigroup.py index 2481a35e42b..35e1056ca93 100644 --- a/src/sage/quivers/path_semigroup.py +++ b/src/sage/quivers/path_semigroup.py @@ -83,6 +83,7 @@ class PathSemigroup(UniqueRepresentation, Parent): Category of infinite enumerated monoids sage: TestSuite(M).run() """ + Element = QuiverPath @staticmethod @@ -386,8 +387,7 @@ def _element_constructor_(self, data, check=True): e0 = E[path[n - 1]][1] e1 = E[path[n]][0] if e0 != e1: - raise ValueError("edge {} ends at {}, but edge {} starts at {}".format( - E[path[n - 1]][2], e0, E[path[n]][2], e1)) + raise ValueError("edge {} ends at {}, but edge {} starts at {}".format(E[path[n - 1]][2], e0, E[path[n]][2], e1)) if E[path[0]][0] != start: raise ValueError("first edge should start at vertex {}".format(start)) if E[path[-1]][1] != end: @@ -406,8 +406,7 @@ def arrows(self): sage: P.arrows() (a, b, c, d) """ - return tuple(self.element_class(self, e[0], e[1], [i]) - for i, e in enumerate(self._sorted_edges)) + return tuple(self.element_class(self, e[0], e[1], [i]) for i, e in enumerate(self._sorted_edges)) @cached_method def idempotents(self): @@ -421,8 +420,7 @@ def idempotents(self): sage: P.idempotents() (e_1, e_2, e_3) """ - return tuple(self.element_class(self, v, v, []) - for v in self._quiver.vertex_iterator()) + return tuple(self.element_class(self, v, v, []) for v in self._quiver.vertex_iterator()) def ngens(self): """ @@ -543,9 +541,11 @@ def cardinality(self): ValueError: the underlying quiver has cycles, thus, there may be an infinity of directed paths """ from sage.rings.integer_ring import ZZ + if self._quiver.is_directed_acyclic() and not self._quiver.has_loops(): return ZZ(len(self)) from sage.rings.infinity import Infinity + return Infinity def __iter__(self): @@ -779,6 +779,7 @@ def algebra(self, k, order='negdegrevlex'): 3*z*z*z + 4*z*z*x + 4*z*x*z + 2*z*x*x + 4*x*z*z + 2*x*z*x + 2*x*x*z + x*x*x + 2*z*z + z*x + x*z + 3*x*x + z + 3*x + e_1 """ from sage.quivers.algebra import PathAlgebra + return PathAlgebra(k, self, order) ########################################################################### @@ -1134,13 +1135,11 @@ def _v_to_e(path): ell = Q.edge_label(path[0], path[1]) if isinstance(ell, str): for b in _v_to_e(path[1:]): - paths.append(self([(path[0], path[1], ell)] - + list(b), check=False)) + paths.append(self([(path[0], path[1], ell)] + list(b), check=False)) else: for a in ell: for b in _v_to_e(path[1:]): - paths.append(self([(path[0], path[1], a)] - + list(b), check=False)) + paths.append(self([(path[0], path[1], a)] + list(b), check=False)) return paths # For each vertex path we append the resulting edge paths diff --git a/src/sage/quivers/representation.py b/src/sage/quivers/representation.py index cf7a34067dd..ba1e35dded1 100644 --- a/src/sage/quivers/representation.py +++ b/src/sage/quivers/representation.py @@ -588,6 +588,7 @@ class QuiverRepFactory(UniqueFactory): sage: N.dimension_vector() (0, 1, 2) """ + def create_key(self, k, P, *args, **kwds): """ Return a key for the specified module. @@ -689,12 +690,13 @@ def create_key(self, k, P, *args, **kwds): # an integer is given set it as a free module of that rank, otherwise # assume the object is a module and assign it to the vertex. from sage.rings.finite_rings.integer_mod_ring import Integers + verts = Q.vertices(sort=True) for x in verts: if x not in spaces: key.append(k**0) elif spaces[x] in Integers(): - key.append(k**spaces[x]) + key.append(k ** spaces[x]) else: key.append(spaces[x]) @@ -709,6 +711,7 @@ def create_key(self, k, P, *args, **kwds): # vertex is 1 so the space assigned to vertex v is key[2 + v] from sage.categories.morphism import Morphism from sage.matrix.constructor import Matrix + for x in P._sorted_edges: if x in maps: e = maps[x] @@ -726,13 +729,10 @@ def create_key(self, k, P, *args, **kwds): if hasattr(e, 'matrix'): key.append(e.matrix()) else: - gens_images = [key[3 + verts.index(x[1])].coordinate_vector(e(x)) - for x in key[3 + verts.index(x[0])].gens()] - key.append(Matrix(k, key[3 + verts.index(x[0])].dimension(), - key[3 + verts.index(x[1])].dimension(), gens_images)) + gens_images = [key[3 + verts.index(x[1])].coordinate_vector(e(x)) for x in key[3 + verts.index(x[0])].gens()] + key.append(Matrix(k, key[3 + verts.index(x[0])].dimension(), key[3 + verts.index(x[1])].dimension(), gens_images)) else: - key.append(Matrix(k, key[3 + verts.index(x[0])].dimension(), - key[3 + verts.index(x[1])].dimension(), e)) + key.append(Matrix(k, key[3 + verts.index(x[0])].dimension(), key[3 + verts.index(x[1])].dimension(), e)) # Make sure the matrix is immutable so it hashes key[-1].set_immutable() @@ -1044,8 +1044,7 @@ def __hash__(self): sage: h1 == hash(v) True """ - return hash(frozenset((v, tuple(self._elems[v])) - for v in self._quiver)) + return hash(frozenset((v, tuple(self._elems[v])) for v in self._quiver)) def __eq__(self, other): """ @@ -1274,6 +1273,7 @@ def copy(self): name = self.get_custom_name() return self.parent()(self._elems.copy(), name) + #################################################################### # The representations @@ -1330,6 +1330,7 @@ class QuiverRep_generic(WithEqualityById, Module): sage: TestSuite(I).run() sage: TestSuite(Q.S(ZZ,2)).run() """ + Element = QuiverRepElement ########################################################################### @@ -1385,11 +1386,12 @@ def __init__(self, k, P, spaces, maps): # an integer is given set it as a free module of that rank, otherwise # assume the object is a module and assign it to the vertex. from sage.rings.finite_rings.integer_mod_ring import Integers + for x in Q: if x not in spaces: self._spaces[x] = k**0 elif spaces[x] in Integers(): - self._spaces[x] = k**spaces[x] + self._spaces[x] = k ** spaces[x] else: self._spaces[x] = spaces[x] @@ -1413,6 +1415,7 @@ def __init__(self, k, P, spaces, maps): # zero and one of the base ring are valid inputs (one is valid only # when the domain and codomain are equal). from sage.categories.morphism import Morphism + if isinstance(e, Morphism): self._maps[x] = e else: @@ -1917,7 +1920,7 @@ def gens(self, names='v') -> tuple: (x, y, z) """ # Use names as a list if and only if it is the correct length - uselist = (len(names) == self.dimension()) + uselist = len(names) == self.dimension() i = 0 # Create bases for each space and construct QuiverRepElements from @@ -2187,8 +2190,7 @@ def quotient(self, sub, check=True): # mapped over using the original map. The codomain is set as the # quotient so sage will take care of pushing the result to the # quotient in the codomain. - maps[e] = spaces[e[0]].hom([self._maps[e](factor.lift(x)) - for x in spaces[e[0]].gens()], spaces[e[1]]) + maps[e] = spaces[e[0]].hom([self._maps[e](factor.lift(x)) for x in spaces[e[0]].gens()], spaces[e[1]]) return self._semigroup.representation(self.base_ring(), spaces, maps) @@ -2296,10 +2298,7 @@ def linear_dual(self): """ # This module is formed by taking the transpose of the edge maps. spaces = self._spaces.copy() - maps = {(e[1], e[0], e[2]): - self._spaces[e[1]].hom(self._maps[e].matrix().transpose(), - self._spaces[e[0]]) - for e in self._semigroup._sorted_edges} + maps = {(e[1], e[0], e[2]): self._spaces[e[1]].hom(self._maps[e].matrix().transpose(), self._spaces[e[0]]) for e in self._semigroup._sorted_edges} # Reverse the bases if present if hasattr(self, '_bases'): @@ -2352,6 +2351,7 @@ def algebraic_dual(self, basis=False): (7, 2, 1) """ from sage.quivers.homspace import QuiverHomSpace + return QuiverHomSpace(self, self._semigroup.free_module(self.base_ring())).left_module(basis) def Hom(self, codomain): @@ -2367,6 +2367,7 @@ def Hom(self, codomain): Dimension 2 QuiverHomSpace """ from sage.quivers.homspace import QuiverHomSpace + return QuiverHomSpace(self, codomain) def direct_sum(self, modules, return_maps=False): @@ -2449,14 +2450,14 @@ def direct_sum(self, modules, return_maps=False): raise ValueError("cannot direct sum modules with different base rings") # Get the dimensions of all spaces at each vertex - dims = {v: [x._spaces[v].dimension() for x in mods] - for v in self._quiver} + dims = {v: [x._spaces[v].dimension() for x in mods] for v in self._quiver} # Create spaces of the correct dimensions - spaces = {v: self.base_ring()**sum(dims[v]) for v in self._quiver} + spaces = {v: self.base_ring() ** sum(dims[v]) for v in self._quiver} # Take block sums of matrices to form the maps from sage.matrix.constructor import block_diagonal_matrix + maps = {} for e in self._semigroup._sorted_edges: maps[e] = block_diagonal_matrix([x._maps[e].matrix() for x in mods], subdivide=False) @@ -2469,6 +2470,7 @@ def direct_sum(self, modules, return_maps=False): # Create the inclusions and projections from sage.matrix.constructor import Matrix, block_matrix from sage.rings.integer import Integer + iota = [] pi = [] for i in range(len(mods)): @@ -2477,13 +2479,9 @@ def direct_sum(self, modules, return_maps=False): for v in self._quiver: # Create the maps using block matrices pre_dims = sum(dims[v][:i]) - post_dims = sum(dims[v][i + 1:]) - incl_maps[v] = block_matrix(1, 3, [Matrix(dims[v][i], pre_dims), - Matrix(dims[v][i], dims[v][i], Integer(1)), - Matrix(dims[v][i], post_dims)]) - proj_maps[v] = block_matrix(3, 1, [Matrix(pre_dims, dims[v][i]), - Matrix(dims[v][i], dims[v][i], Integer(1)), - Matrix(post_dims, dims[v][i])]) + post_dims = sum(dims[v][i + 1 :]) + incl_maps[v] = block_matrix(1, 3, [Matrix(dims[v][i], pre_dims), Matrix(dims[v][i], dims[v][i], Integer(1)), Matrix(dims[v][i], post_dims)]) + proj_maps[v] = block_matrix(3, 1, [Matrix(pre_dims, dims[v][i]), Matrix(dims[v][i], dims[v][i], Integer(1)), Matrix(post_dims, dims[v][i])]) # These matrices are over the integers, and get coerced # into the appropriate base ring at a later stage. # Might make trouble if the integer 1 does not coerce to @@ -2667,6 +2665,7 @@ class QuiverRep_with_path_basis(QuiverRep_generic): list under right multiplication forms the basis of the resulting representation. """ + # This class implements quiver representations whose bases correspond to # paths in the path algebra and whose maps are path multiplication. The # main advantage to having such a basis is that a homomorphism can be @@ -2724,6 +2723,7 @@ def __init__(self, k, P, basis): # Create the matrices of the maps from sage.matrix.constructor import Matrix + maps = {} for e in P._sorted_edges: arrow = P([e], check=False) @@ -2833,8 +2833,7 @@ def _left_edge_action(self, edge, element): return self.left_edge_action(edge[:-1], self.left_edge_action(edge[-1], element)) # Now we are just acting by a single edge - elems = {v: self._left_action_mats[edge][v] * element._elems[v] - for v in self._quiver} + elems = {v: self._left_action_mats[edge][v] * element._elems[v] for v in self._quiver} return self(elems) def is_left_module(self) -> bool: @@ -2893,6 +2892,7 @@ class QuiverRep_with_dual_path_basis(QuiverRep_generic): list under left deletion forms the basis of the resulting representation. """ + # This class implements quiver representations whose bases correspond to # paths in the path algebra and whose maps are edge deletion. The # main advantage to having such a basis is that a homomorphism can be @@ -2939,6 +2939,7 @@ def __init__(self, k, P, basis): # Create the matrices of the maps from sage.matrix.constructor import Matrix + maps = {} for e in P._sorted_edges: arrow = P([e], check=False) diff --git a/src/sage/repl/__init__.py b/src/sage/repl/__init__.py index 1357b584ef3..69f13ee27ec 100644 --- a/src/sage/repl/__init__.py +++ b/src/sage/repl/__init__.py @@ -2,6 +2,7 @@ # The Sage application loads it when starting up. def load_ipython_extension(*args): import sage.repl.ipython_extension + sage.repl.ipython_extension.load_ipython_extension(*args) @@ -12,4 +13,5 @@ def load_ipython_extension(*args): # So we make "%load_ext sage" work by monkey-patching the function # into the sage package upon importing sage.repl. import sage + sage.load_ipython_extension = load_ipython_extension diff --git a/src/sage/repl/all.py b/src/sage/repl/all.py index 809cea7d7e5..c5f785fce2b 100644 --- a/src/sage/repl/all.py +++ b/src/sage/repl/all.py @@ -4,11 +4,10 @@ lazy_import('sage.repl.interpreter', 'preparser') -lazy_import('sage.repl.attach', [ - 'attach', 'detach', 'attached_files', 'load_attach_path', - 'reset_load_attach_path', 'load_attach_mode']) +lazy_import('sage.repl.attach', ['attach', 'detach', 'attached_files', 'load_attach_path', 'reset_load_attach_path', 'load_attach_mode']) from sage.repl.rich_output.display_manager import get_display_manager from sage.repl.rich_output.pretty_print import pretty_print, show + del lazy_import diff --git a/src/sage/repl/configuration.py b/src/sage/repl/configuration.py index bc895b1bf60..032f207f00c 100644 --- a/src/sage/repl/configuration.py +++ b/src/sage/repl/configuration.py @@ -14,6 +14,7 @@ sage: 'sage: [False, True]' in output # needs pexpect True """ + # **************************************************************************** # Copyright (C) 2016 Volker Braun # @@ -50,6 +51,7 @@ def _doctest_mode(self): True """ from sage.doctest import DOCTEST_MODE + return DOCTEST_MODE def _allow_ansi(self): @@ -83,6 +85,7 @@ def colors(self): if not self._allow_ansi(): return 'nocolor' from sage.repl.interpreter import SageTerminalInteractiveShell + return SageTerminalInteractiveShell.colors.default() def simple_prompt(self): @@ -132,15 +135,7 @@ def default(self): # TerminalInteractiveShell (note: in fact some configs like term_title # only apply to the latter, but we can still use the same config for # both for simplicity's sake; see Issue #28289) - InteractiveShell = Config( - prompts_class=SagePrompts, - ast_node_interactivity='all', - colors=self.colors(), - simple_prompt=self.simple_prompt(), - term_title=self.term_title(), - confirm_exit=False, - separate_in='' - ) + InteractiveShell = Config(prompts_class=SagePrompts, ast_node_interactivity='all', colors=self.colors(), simple_prompt=self.simple_prompt(), term_title=self.term_title(), confirm_exit=False, separate_in='') cfg = Config( TerminalIPythonApp=Config( diff --git a/src/sage/repl/display/fancy_repr.py b/src/sage/repl/display/fancy_repr.py index 852a7c05efb..c89a00b116a 100644 --- a/src/sage/repl/display/fancy_repr.py +++ b/src/sage/repl/display/fancy_repr.py @@ -1,6 +1,7 @@ """ Representations of objects """ + # **************************************************************************** # Copyright (C) 2014 Volker Braun # @@ -87,6 +88,7 @@ def format_string(self, obj): 'Error: ObjectReprABC.__call__ is abstract' """ from sage.repl.display.pretty_print import SagePrettyPrinter + stream = StringIO() p = SagePrettyPrinter(stream, 79, '\n') ok = self(obj, p, False) @@ -206,14 +208,14 @@ def __call__(self, obj, p, cycle): # Do not print the help for matrices inside containers return False from sage.structure.element import Matrix + if not isinstance(obj, Matrix): return False from sage.matrix.constructor import options + if obj.nrows() <= options.max_rows() and obj.ncols() <= options.max_cols(): return False - p.text( - repr(obj) + " (use the '.str()' method to see the entries)" - ) + p.text(repr(obj) + " (use the '.str()' method to see the entries)") return True @@ -278,6 +280,7 @@ def __call__(self, obj, p, cycle): except Exception: import sys import traceback + objrepr = object.__repr__(obj).replace("object at", "at") exc = traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1]) exc = (''.join(exc)).strip() diff --git a/src/sage/repl/display/formatter.py b/src/sage/repl/display/formatter.py index ceea50f36eb..9857438eeab 100644 --- a/src/sage/repl/display/formatter.py +++ b/src/sage/repl/display/formatter.py @@ -99,13 +99,14 @@ def __init__(self, *args, **kwds): """ super().__init__(*args, **kwds) from sage.repl.rich_output.display_manager import get_display_manager + self.dm = get_display_manager() from sage.repl.rich_output.backend_ipython import BackendIPython + self.dm.check_backend_class(BackendIPython) pt_formatter = self.formatters[PLAIN_TEXT] - pt_formatter.observe(self._ipython_float_precision_changed, - names=['float_precision']) + pt_formatter.observe(self._ipython_float_precision_changed, names=['float_precision']) def format(self, obj, include=None, exclude=None): r""" @@ -187,9 +188,7 @@ def format(self, obj, include=None, exclude=None): # use Sage rich output for any except those native to IPython, but only # if it is not plain and dull - if (not isinstance(obj, IPYTHON_NATIVE_TYPES) and - not set(sage_format.keys()).issubset([PLAIN_TEXT]) and - not isinstance(obj, Figure)): + if not isinstance(obj, IPYTHON_NATIVE_TYPES) and not set(sage_format.keys()).issubset([PLAIN_TEXT]) and not isinstance(obj, Figure): return sage_format, sage_metadata if self.ipython_display_formatter(obj): @@ -305,12 +304,12 @@ def __call__(self, obj): '[\n[1 0] [1 0]\n[0 1], [0 1]\n]' """ from sage.doctest import DOCTEST_MODE + if DOCTEST_MODE: # Just to show that this is never executed in any other doctests in the Sage library print('---- calling ipython formatter ----') stream = StringIO() - printer = SagePrettyPrinter( - stream, self.max_width, self.newline) + printer = SagePrettyPrinter(stream, self.max_width, self.newline) printer.pretty(obj) printer.flush() return stream.getvalue() diff --git a/src/sage/repl/display/jsmol_iframe.py b/src/sage/repl/display/jsmol_iframe.py index ef5ecf1cf95..719d2d9f106 100644 --- a/src/sage/repl/display/jsmol_iframe.py +++ b/src/sage/repl/display/jsmol_iframe.py @@ -84,7 +84,9 @@ {iframe} -""".format(iframe=IFRAME_TEMPLATE) +""".format( + iframe=IFRAME_TEMPLATE +) class JSMolHtml(SageObject): @@ -116,6 +118,7 @@ def __init__(self, jmol, path_to_jsmol=None, width='100%', height='100%'): JSmol Window 500x300 """ from sage.repl.rich_output.output_graphics3d import OutputSceneJmol + if not isinstance(jmol, OutputSceneJmol): jmol = jmol._rich_repr_jmol() self._jmol = jmol @@ -152,14 +155,9 @@ def script(self): command, obj, meshfile = line.split(b' ', 3) assert command == b'pmesh' if meshfile not in [b'dots\n', b'mesh\n']: - assert (meshfile.startswith(b'"') and - meshfile.endswith(b'"\n')) + assert meshfile.startswith(b'"') and meshfile.endswith(b'"\n') meshfile = bytes_to_str(meshfile[1:-2]) # strip quotes - script += [ - 'pmesh {0} inline "'.format(bytes_to_str(obj)), - bytes_to_str(self._zip.open(meshfile).read()), - '"\n' - ] + script += ['pmesh {0} inline "'.format(bytes_to_str(obj)), bytes_to_str(self._zip.open(meshfile).read()), '"\n'] continue script += [bytes_to_str(line)] return ''.join(script) @@ -253,9 +251,7 @@ def iframe(self): """ escaped_inner_html = self.inner_html().replace('"', '"') - return IFRAME_TEMPLATE.format(width=self._width, - height=self._height, - escaped_inner_html=escaped_inner_html) + return IFRAME_TEMPLATE.format(width=self._width, height=self._height, escaped_inner_html=escaped_inner_html) def outer_html(self): """ diff --git a/src/sage/repl/display/pretty_print.py b/src/sage/repl/display/pretty_print.py index 9746a463183..e74c3193feb 100644 --- a/src/sage/repl/display/pretty_print.py +++ b/src/sage/repl/display/pretty_print.py @@ -25,9 +25,7 @@ from IPython.lib.pretty import PrettyPrinter -from sage.repl.display.fancy_repr import (TallListRepr, PlainPythonRepr, - LargeMatrixHelpRepr, - SomeIPythonRepr) +from sage.repl.display.fancy_repr import TallListRepr, PlainPythonRepr, LargeMatrixHelpRepr, SomeIPythonRepr class SagePrettyPrinter(PrettyPrinter): @@ -62,7 +60,7 @@ def toplevel(self): sage: spp.toplevel() True """ - return len(self.stack) <= 1 # only the object currently being represented + return len(self.stack) <= 1 # only the object currently being represented def __init__(self, output, max_width, newline, max_seq_length=None): """ @@ -104,8 +102,7 @@ def __init__(self, output, max_width, newline, max_seq_length=None): sage: foo """ - super().__init__(output, max_width, newline, - max_seq_length=max_seq_length) + super().__init__(output, max_width, newline, max_seq_length=max_seq_length) self.stack = [] def pretty(self, obj): diff --git a/src/sage/repl/image.py b/src/sage/repl/image.py index 76d530f9c39..9a081216f26 100644 --- a/src/sage/repl/image.py +++ b/src/sage/repl/image.py @@ -94,6 +94,7 @@ def __init__(self, mode, size, color='white'): """ # pillow does not support Sage integers as color from sage.rings.integer import Integer + if isinstance(color, Integer): color = int(color) elif isinstance(color, tuple): @@ -258,6 +259,7 @@ def show(self): sage: img.show() """ from sage.repl.rich_output import get_display_manager + dm = get_display_manager() dm.display_immediately(self) @@ -289,6 +291,7 @@ def _rich_repr_(self, display_manager, **kwds): ('GIF', types.OutputImageGif), ) from sage.repl.rich_output.buffer import OutputBuffer + for format, output_container in preferred: if output_container in display_manager.supported_output(): stream = io.BytesIO() diff --git a/src/sage/repl/inputhook.py b/src/sage/repl/inputhook.py index 4ed6d0d9711..ccfb6b7aeda 100644 --- a/src/sage/repl/inputhook.py +++ b/src/sage/repl/inputhook.py @@ -26,7 +26,7 @@ import sage.repl.attach -TIMEOUT = 0.25 # seconds +TIMEOUT = 0.25 # seconds def sage_inputhook(context): @@ -65,7 +65,7 @@ def install(): """ ip = get_ipython() if not ip: - return # Not running in ipython, e.g. doctests + return # Not running in ipython, e.g. doctests if ip._inputhook != sage_inputhook: # silence `ip.enable_gui()` useless output with contextlib.redirect_stdout(io.StringIO()): diff --git a/src/sage/repl/interface_magic.py b/src/sage/repl/interface_magic.py index 8db763a507e..94f1f828a6d 100644 --- a/src/sage/repl/interface_magic.py +++ b/src/sage/repl/interface_magic.py @@ -22,6 +22,7 @@ Note that the cell magic needs semicolons, this is required by the GAP language to separate multiple commands. """ + # Note: no magics in doctests, hence # not tested @@ -129,16 +130,8 @@ def register_all(cls, shell=None): if shell is None: shell = get_ipython() for interface in cls.all_iter(): - shell.register_magic_function( - interface.line_magic_factory(), - magic_name=interface._name, - magic_kind='line' - ) - shell.register_magic_function( - interface.cell_magic_factory(), - magic_name=interface._name, - magic_kind='cell' - ) + shell.register_magic_function(interface.line_magic_factory(), magic_name=interface._name, magic_kind='line') + shell.register_magic_function(interface.cell_magic_factory(), magic_name=interface._name, magic_kind='cell') @classmethod def find(cls, name): @@ -225,6 +218,7 @@ def line_magic(line): self._interface.interact() else: raise SyntaxError('{0} command required'.format(self._name)) + line_magic.__doc__ = LINE_DOCSTRING.format(name=self._name) return line_magic @@ -267,6 +261,7 @@ def cell_magic_factory(self): The cell magic %%gap sends multiple lines to the gap interface. ... """ + def cell_magic(line, cell): """ Evaluate cell magic. @@ -290,5 +285,6 @@ def cell_magic(line, cell): raise SyntaxError('Interface magics have no options, got "{0}"'.format(line)) output = self._interface.eval(cell) print(output) + cell_magic.__doc__ = CELL_DOCSTRING.format(name=self._name) return cell_magic diff --git a/src/sage/repl/interpreter.py b/src/sage/repl/interpreter.py index 70dd3f3cf90..8ecee06c820 100644 --- a/src/sage/repl/interpreter.py +++ b/src/sage/repl/interpreter.py @@ -158,11 +158,14 @@ # PyOS_sighandler_t PyOS_getsig(int i) pythonapi.PyOS_getsig.restype = c_void_p -pythonapi.PyOS_getsig.argtypes = c_int, +pythonapi.PyOS_getsig.argtypes = (c_int,) # PyOS_sighandler_t PyOS_setsig(int i, PyOS_sighandler_t h) pythonapi.PyOS_setsig.restype = c_void_p -pythonapi.PyOS_setsig.argtypes = c_int, c_void_p, +pythonapi.PyOS_setsig.argtypes = ( + c_int, + c_void_p, +) # TODO: This global variable _do_preparse should be associated with an @@ -217,6 +220,7 @@ def show_usage(self): sage: shell.quit() """ from sage.misc.sagedoc import help + help() def system_raw(self, cmd): @@ -266,6 +270,7 @@ def init_display_formatter(self): sage: SageNotebookInteractiveShell().init_display_formatter() # not tested """ from sage.repl.rich_output.backend_ipython import BackendIPythonNotebook + backend = BackendIPythonNotebook() backend.get_display_manager().switch_backend(backend, shell=self) @@ -294,6 +299,7 @@ def init_display_formatter(self): sage: SageTerminalInteractiveShell().init_display_formatter() # not tested """ from sage.repl.rich_output.backend_ipython import BackendIPythonCommandline + backend = BackendIPythonCommandline() backend.get_display_manager().switch_backend(backend, shell=self) @@ -303,6 +309,7 @@ def prompt_for_code(self): # https://github.com/sagemath/sage/issues/33428 # https://github.com/sagemath/sage/pull/35251 import signal + sigint = signal.getsignal(signal.SIGINT) sigint_os = pythonapi.PyOS_getsig(signal.SIGINT) text = TerminalInteractiveShell.prompt_for_code(self) @@ -341,6 +348,7 @@ def init_display_formatter(self): sage: shell.quit() """ from sage.repl.rich_output.backend_ipython import BackendIPythonCommandline + self._ipython_backend = backend = BackendIPythonCommandline() self._display_manager = backend.get_display_manager() self._doctest_backend = self._display_manager.switch_backend(backend, shell=self) @@ -476,12 +484,14 @@ def SagePreparseTransformer(lines): # Interface shell # ################### + class logstr(str): """ For use by :meth`~InterfaceShellTransformer.transform`. This provides a ``_latex_`` method which is just the string wrapped in a ``\\verb`` environment. """ + def __repr__(self): """ EXAMPLES:: @@ -540,8 +550,7 @@ def __init__(self, *args, **kwds): """ super().__init__(*args, **kwds) self.temporary_objects = set() - self._sage_import_re = re.compile(r'(?:sage|%s)\(' - % self.shell.interface.name()) + self._sage_import_re = re.compile(r'(?:sage|%s)\(' % self.shell.interface.name()) def preparse_imports_from_sage(self, line): """ @@ -592,12 +601,11 @@ def preparse_imports_from_sage(self, line): if not m: new_line.append(line[pos:]) break - expr_start, expr_end = containing_block(line, m.end() - 1, - delimiters=['()']) - expr = preparse(line[expr_start + 1:expr_end - 1]) + expr_start, expr_end = containing_block(line, m.end() - 1, delimiters=['()']) + expr = preparse(line[expr_start + 1 : expr_end - 1]) result = self.shell.interface(eval(expr, self.shell.user_ns)) self.temporary_objects.add(result) - new_line += [line[pos:m.start()], result.name()] + new_line += [line[pos : m.start()], result.name()] pos = expr_end return ' '.join(new_line) @@ -681,9 +689,7 @@ def interface_shell_embed(interface): """ cfg = sage_ipython_config.copy() - ipshell = InteractiveShellEmbed(config=cfg, - banner1='\n --> Switching to %s <--\n\n' % interface, - exit_msg='\n --> Exiting back to Sage <--\n') + ipshell = InteractiveShellEmbed(config=cfg, banner1='\n --> Switching to %s <--\n\n' % interface, exit_msg='\n --> Exiting back to Sage <--\n') ipshell.interface = interface ipshell.prompts = InterfacePrompts(interface.name()) @@ -693,9 +699,7 @@ def interface_shell_embed(interface): ipshell.prefilter_manager.checkers.pop() ipshell.ex('import sage.misc.all') - InterfaceShellTransformer(shell=ipshell, - prefilter_manager=ipshell.prefilter_manager, - config=cfg) + InterfaceShellTransformer(shell=ipshell, prefilter_manager=ipshell.prefilter_manager, config=cfg) return ipshell @@ -747,6 +751,7 @@ def get_test_shell(): # IPython TerminalApp # ####################### + class SageCrashHandler(IPAppCrashHandler): def __init__(self, app): """ @@ -769,9 +774,7 @@ def __init__(self, app): contact_name = 'sage-support' contact_email = 'sage-support@googlegroups.com' bug_tracker = 'https://github.com/sagemath/sage/issues' - CrashHandler.__init__(self, - app, contact_name, contact_email, - bug_tracker, show_crash_traceback=True) + CrashHandler.__init__(self, app, contact_name, contact_email, bug_tracker, show_crash_traceback=True) self.crash_report_fname = 'Sage_crash_report.txt' @@ -828,17 +831,14 @@ def init_shell(self): """ # Shell initialization - self.shell = self.shell_class.instance( - parent=self, - config=self.config, - profile_dir=self.profile_dir, - ipython_dir=self.ipython_dir) + self.shell = self.shell_class.instance(parent=self, config=self.config, profile_dir=self.profile_dir, ipython_dir=self.ipython_dir) self.shell.configurables.append(self) self.shell.has_sage_extensions = SAGE_EXTENSION in self.extensions # Load the %lprun extension if available try: import line_profiler + assert line_profiler # silence pyflakes except ImportError: pass diff --git a/src/sage/repl/ipython_extension.py b/src/sage/repl/ipython_extension.py index d7ef7b7d0de..94545df1b70 100644 --- a/src/sage/repl/ipython_extension.py +++ b/src/sage/repl/ipython_extension.py @@ -104,6 +104,7 @@ def crun(self, s): sage: shell.quit() """ import sage.misc.gperftools + sage.misc.gperftools.crun(s, evaluator=self.shell.ex) @line_magic @@ -301,6 +302,7 @@ def display(self, args): sage: shell.quit() """ from sage.repl.rich_output import get_display_manager + dm = get_display_manager() args = args.strip().split() if not args: @@ -318,9 +320,9 @@ def display(self, args): except ValueError: max_width = 0 if max_width <= 0: - raise ValueError( - "max width must be a positive integer") + raise ValueError("max width must be a positive integer") from sage.typeset import character_art + character_art.MAX_WIDTH = max_width dm.preferences.text = arg0 # Unset all @@ -489,6 +491,7 @@ def error(self, message): # we raise UsageError to make the interface similar to what happens when e.g. # IPython's ``%run`` gets unrecognized arguments from IPython.core.error import UsageError + raise UsageError(message) parser = ExitCatchingArgumentParser(prog="%%cython", add_help=False) @@ -497,8 +500,7 @@ def error(self, message): parser.add_argument("--use-cache", action=argparse.BooleanOptionalAction) parser.add_argument("--create-local-c-file", action=argparse.BooleanOptionalAction) parser.add_argument("--annotate", action=argparse.BooleanOptionalAction) - parser.add_argument("--view-annotate", choices=["none", "auto", "webbrowser", "displayhtml"], - nargs="?", const="auto", default="none") + parser.add_argument("--view-annotate", choices=["none", "auto", "webbrowser", "displayhtml"], nargs="?", const="auto", default="none") parser.add_argument("--sage-namespace", action=argparse.BooleanOptionalAction) parser.add_argument("--create-local-so-file", action=argparse.BooleanOptionalAction) args = parser.parse_args(shlex.split(line)) @@ -569,6 +571,7 @@ def fortran(self, line, cell): array([ 0., 1., 1., 2., 3., 5., 8., 13., 21., 34.]) """ from sage.misc.inline_fortran import fortran + return fortran(cell) @@ -602,6 +605,7 @@ def register_interface_magics(self): Register magics for each of the Sage interfaces """ from sage.repl.interface_magic import InterfaceMagic + InterfaceMagic.register_all(self.shell) @staticmethod @@ -617,6 +621,7 @@ def all_globals(): """ from sage import all_cmdline + return all_cmdline def init_environment(self): @@ -625,6 +630,7 @@ def init_environment(self): """ # import outside of cell so we don't get a traceback from sage.repl.user_globals import initialize_globals + initialize_globals(self.all_globals(), self.shell.user_ns) self.run_init() @@ -644,6 +650,7 @@ def init_inspector(self): # the global :class:`IPython.core.oinspect` module namespace. # Thus, we have to monkey-patch. import IPython.core.oinspect + IPython.core.oinspect.getdoc = LazyImport("sage.misc.sageinspect", "sage_getdoc") IPython.core.oinspect.getsource = LazyImport("sage.misc.sagedoc", "my_getsource") IPython.core.oinspect.find_file = LazyImport("sage.misc.sageinspect", "sage_getfile") @@ -732,6 +739,7 @@ def all_globals(): """ from .ipython_kernel import all_jupyter + return all_jupyter diff --git a/src/sage/repl/ipython_kernel/__main__.py b/src/sage/repl/ipython_kernel/__main__.py index a1657263bee..e7d7efdba94 100644 --- a/src/sage/repl/ipython_kernel/__main__.py +++ b/src/sage/repl/ipython_kernel/__main__.py @@ -1,3 +1,4 @@ from ipykernel.kernelapp import IPKernelApp from sage.repl.ipython_kernel.kernel import SageKernel + IPKernelApp.launch_instance(kernel_class=SageKernel) diff --git a/src/sage/repl/ipython_kernel/all_jupyter.py b/src/sage/repl/ipython_kernel/all_jupyter.py index 123eca1f6a2..a293ef5ea66 100644 --- a/src/sage/repl/ipython_kernel/all_jupyter.py +++ b/src/sage/repl/ipython_kernel/all_jupyter.py @@ -4,8 +4,7 @@ from sage.all_cmdline import * -from sage.repl.ipython_kernel.widgets_sagenb import (input_box, text_control, slider, - range_slider, checkbox, selector, input_grid, color_selector) +from sage.repl.ipython_kernel.widgets_sagenb import input_box, text_control, slider, range_slider, checkbox, selector, input_grid, color_selector from sage.repl.ipython_kernel.interact import interact from pathlib import Path diff --git a/src/sage/repl/ipython_kernel/install.py b/src/sage/repl/ipython_kernel/install.py index 028ffe5ea18..863fd8efb3e 100644 --- a/src/sage/repl/ipython_kernel/install.py +++ b/src/sage/repl/ipython_kernel/install.py @@ -65,12 +65,14 @@ def _mkdirs(self): sage: os.path.isdir(spec.nbextensions_dir) True """ + def mkdir_p(path): try: os.makedirs(path) except OSError: if not os.path.isdir(path): raise + mkdir_p(self.nbextensions_dir) mkdir_p(self.kernel_dir) @@ -129,6 +131,7 @@ def use_local_threejs(self): True """ from sage.features.threejs import Threejs + if not Threejs().is_present(): return src = os.path.dirname(os.path.dirname(Threejs().absolute_filename())) @@ -154,8 +157,10 @@ def _kernel_cmd(self): """ return [ 'python3', - '-m', 'sage.repl.ipython_kernel', - '-f', '{connection_file}', + '-m', + 'sage.repl.ipython_kernel', + '-f', + '{connection_file}', ] def kernel_spec(self): @@ -190,6 +195,7 @@ def _install_spec(self): """ jsonfile = os.path.join(self.kernel_dir, "kernel.json") import json + with open(jsonfile, 'w') as f: json.dump(self.kernel_spec(), f) @@ -210,14 +216,8 @@ def _symlink_resources(self): """ path = os.path.join(SAGE_EXTCODE, 'notebook-ipython') for filename in os.listdir(path): - self.symlink( - os.path.join(path, filename), - os.path.join(self.kernel_dir, filename) - ) - self.symlink( - SAGE_DOC, - os.path.join(self.kernel_dir, 'doc') - ) + self.symlink(os.path.join(path, filename), os.path.join(self.kernel_dir, filename)) + self.symlink(SAGE_DOC, os.path.join(self.kernel_dir, 'doc')) @classmethod def update(cls, *args, **kwds): @@ -253,28 +253,24 @@ def check(cls): sage: SageKernelSpec.check() # random """ from jupyter_client.kernelspec import NoSuchKernel, get_kernel_spec + ident = cls.identifier() try: spec = get_kernel_spec(ident) except NoSuchKernel: - warnings.warn(f'No kernel named {ident} is accessible; ' - 'check your Jupyter configuration ' - '(see https://docs.jupyter.org/en/latest/use/jupyter-directories.html).') + warnings.warn(f'No kernel named {ident} is accessible; ' 'check your Jupyter configuration ' '(see https://docs.jupyter.org/en/latest/use/jupyter-directories.html).') else: import sys from pathlib import Path from sage.features import Executable + kernel_executable_feature = Executable(name=spec.argv[0], executable=spec.argv[0]) if not kernel_executable_feature.is_present(): - warnings.warn(f'The kernel named {ident} does not seem to be runnable; ' - 'check your Jupyter configuration ' - '(see https://docs.jupyter.org/en/latest/use/jupyter-directories.html).') + warnings.warn(f'The kernel named {ident} does not seem to be runnable; ' 'check your Jupyter configuration ' '(see https://docs.jupyter.org/en/latest/use/jupyter-directories.html).') return kernel_executable = kernel_executable_feature.absolute_filename() if Path(kernel_executable).resolve() != Path(sys.executable).resolve(): - warnings.warn(f'The kernel named {ident} does not seem to correspond to this ' - 'installation of SageMath; check your Jupyter configuration ' - '(see https://docs.jupyter.org/en/latest/use/jupyter-directories.html).') + warnings.warn(f'The kernel named {ident} does not seem to correspond to this ' 'installation of SageMath; check your Jupyter configuration ' '(see https://docs.jupyter.org/en/latest/use/jupyter-directories.html).') def have_prerequisites(debug=True) -> bool: @@ -299,9 +295,11 @@ def have_prerequisites(debug=True) -> bool: """ try: from notebook.notebookapp import NotebookApp + return True except ImportError: if debug: import traceback + traceback.print_exc() return False diff --git a/src/sage/repl/ipython_kernel/interact.py b/src/sage/repl/ipython_kernel/interact.py index 8b01b6a9a4b..18110bf4438 100644 --- a/src/sage/repl/ipython_kernel/interact.py +++ b/src/sage/repl/ipython_kernel/interact.py @@ -62,6 +62,7 @@ class sage_interactive(interactive): y: Text(value='hello', description='y') z: Dropdown(description='z', options=('one', 'two', 'three'), value=None) """ + def __init__(self, *args, **kwds): """ See :class:`ipywidgets.widgets.interaction.interactive`. @@ -98,7 +99,7 @@ def __init__(self, *args, **kwds): except KeyError: pass else: - options["manual"] = (p_auto_update.default is False) + options["manual"] = p_auto_update.default is False self.__signature = sig.replace(parameters=params.values()) super().__init__(f, options, **kwds) @@ -126,8 +127,7 @@ def __repr__(self): s = "Manual interactive" if self.manual else "Interactive" widgets = [w for w in self.children if isinstance(w, ValueWidget)] n = len(widgets) - s += " function %r with %s widget%s" % (self.f, n, - "s" if n != 1 else "") + s += " function %r with %s widget%s" % (self.f, n, "s" if n != 1 else "") for w in widgets: s += "\n %s: %s" % (w._kwarg, w) return s @@ -172,8 +172,7 @@ def widget_from_single_value(cls, abbrev, *args, **kwds): if isinstance(abbrev, Matrix): from .widgets_sagenb import input_grid - return input_grid(abbrev.nrows(), abbrev.ncols(), - default=abbrev.list(), to_value=abbrev.parent()) + return input_grid(abbrev.nrows(), abbrev.ncols(), default=abbrev.list(), to_value=abbrev.parent()) if isinstance(abbrev, Color): return SageColorPicker(value=abbrev.html_color()) @@ -234,6 +233,7 @@ def n(x): if isinstance(parent(x), SymbolicRing): return x.numerical_approx() return x + abbrev = tuple(n(x) for x in abbrev) return super().widget_from_tuple(abbrev, *args, **kwds) diff --git a/src/sage/repl/ipython_kernel/kernel.py b/src/sage/repl/ipython_kernel/kernel.py index 7dcd45e0d45..231e2063440 100644 --- a/src/sage/repl/ipython_kernel/kernel.py +++ b/src/sage/repl/ipython_kernel/kernel.py @@ -16,15 +16,14 @@ import sys import warnings + with warnings.catch_warnings(): # When upstream pydevd (as opposed to the bundled version) is used # with debugpy, a PEP 420 warning is emitted. Debugpy and/or # pydevd will eventually work around this, but as of September # 2023, hiding the warning gives us more flexibility in the # versions of those packages that we can accept. - warnings.filterwarnings("ignore", - message=r".*pkg_resources\.declare_namespace", - category=DeprecationWarning) + warnings.filterwarnings("ignore", message=r".*pkg_resources\.declare_namespace", category=DeprecationWarning) from ipykernel.ipkernel import IPythonKernel from ipykernel.zmqshell import ZMQInteractiveShell @@ -80,6 +79,7 @@ def banner(self): ┌...SageMath version... """ from sage.misc.banner import banner_text + return banner_text() @property @@ -107,12 +107,17 @@ def help_links(self): from sage.features.sagemath import sagemath_doc_html if SAGE_DOC_SERVER_URL: + def doc_url(path): return f'{SAGE_DOC_SERVER_URL}/{path}' + elif sagemath_doc_html().is_present() and int(port): + def doc_url(path): return f'http://127.0.0.1:{port}/{path}' + else: + def doc_url(path): return f'https://doc.sagemath.org/{path}' @@ -213,4 +218,5 @@ def pre_handler_hook(self): """ from cysignals import init_cysignals + self.saved_sigint_handler = init_cysignals() diff --git a/src/sage/repl/ipython_kernel/widgets.py b/src/sage/repl/ipython_kernel/widgets.py index 8a8f75dbb24..ffdd896122b 100644 --- a/src/sage/repl/ipython_kernel/widgets.py +++ b/src/sage/repl/ipython_kernel/widgets.py @@ -23,15 +23,13 @@ # **************************************************************************** -from ipywidgets.widgets import (IntSlider, IntRangeSlider, - FloatSlider, FloatRangeSlider, Text, - Textarea, ColorPicker, HTMLMath, Label, - HBox, VBox, ValueWidget) +from ipywidgets.widgets import IntSlider, IntRangeSlider, FloatSlider, FloatRangeSlider, Text, Textarea, ColorPicker, HTMLMath, Label, HBox, VBox, ValueWidget from traitlets import List, Unicode, link from sage.misc.sage_eval import sage_eval from sage.repl.user_globals import get_globals from sage.misc.lazy_import import lazy_import + lazy_import("sage.plot.colors", "Color") @@ -53,6 +51,7 @@ class HTMLText(HTMLMath): sage: w.description '' """ + @property def description(self): """ @@ -106,6 +105,7 @@ class TransformWidget: sage: w.get_interact_value() 'pipi' """ + def __init__(self, *args, **kwds): """ Construct a :class:`TransformWidget`. @@ -175,6 +175,7 @@ class EvalWidget(TransformWidget): sage: w.get_interact_value() # needs sage.symbolic 2*pi """ + def get_value(self): """ Evaluate the bare widget value using :func:`sage_eval`. @@ -210,6 +211,7 @@ class TransformIntSlider(TransformWidget, IntSlider): sage: w.get_interact_value() 49 """ + pass @@ -227,6 +229,7 @@ class TransformFloatSlider(TransformWidget, FloatSlider): sage: w.get_interact_value() # needs sage.symbolic 2.6457513110645907 """ + pass @@ -245,6 +248,7 @@ class TransformIntRangeSlider(TransformWidget, IntRangeSlider): sage: w.get_interact_value() 2 """ + pass @@ -263,6 +267,7 @@ class TransformFloatRangeSlider(TransformWidget, FloatRangeSlider): sage: w.get_interact_value() 2.0 """ + pass @@ -280,6 +285,7 @@ class TransformText(TransformWidget, Text): sage: w.get_interact_value() 'hellohello' """ + pass @@ -297,6 +303,7 @@ class TransformTextarea(TransformWidget, Textarea): sage: w.get_interact_value() 'hellohello' """ + pass @@ -314,6 +321,7 @@ class EvalText(EvalWidget, Text): sage: w.get_interact_value() # needs sage.symbolic pi^2 """ + pass @@ -331,6 +339,7 @@ class EvalTextarea(EvalWidget, Textarea): sage: w.get_interact_value() # needs sage.symbolic pi^2 """ + pass @@ -344,6 +353,7 @@ class SageColorPicker(ColorPicker): sage: SageColorPicker() SageColorPicker(value='black') """ + def get_interact_value(self): """ Return a Sage :class:`Color` corresponding to the value of this @@ -378,6 +388,7 @@ class Grid(TransformWidget, HBox, ValueWidget): sage: w.get_interact_value() [['0,0', '0,1'], ['1,0', '1,1']] """ + value = List() description = Unicode() diff --git a/src/sage/repl/ipython_kernel/widgets_sagenb.py b/src/sage/repl/ipython_kernel/widgets_sagenb.py index fa520f50c14..a293cf62ed7 100644 --- a/src/sage/repl/ipython_kernel/widgets_sagenb.py +++ b/src/sage/repl/ipython_kernel/widgets_sagenb.py @@ -27,13 +27,8 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from ipywidgets.widgets import (IntSlider, IntRangeSlider, FloatSlider, - FloatRangeSlider, SelectionSlider, - Checkbox, ToggleButtons, Dropdown) -from .widgets import (TransformText, TransformTextarea, - TransformIntSlider, TransformIntRangeSlider, - TransformFloatSlider, TransformFloatRangeSlider, - EvalText, EvalTextarea, SageColorPicker, Grid) +from ipywidgets.widgets import IntSlider, IntRangeSlider, FloatSlider, FloatRangeSlider, SelectionSlider, Checkbox, ToggleButtons, Dropdown +from .widgets import TransformText, TransformTextarea, TransformIntSlider, TransformIntRangeSlider, TransformFloatSlider, TransformFloatRangeSlider, EvalText, EvalTextarea, SageColorPicker, Grid from ipywidgets.widgets.interaction import _get_min_max_value from collections.abc import Iterable, Sequence from numbers import Integral, Rational, Real @@ -275,6 +270,7 @@ def err(v): return (0, abs(v - default)) except Exception: return (1, 0) + kwds["options"] = options if default is not None: kwds["value"] = min(options, key=err) @@ -289,6 +285,7 @@ def err(v): # Change SR to RR if isinstance(p, SymbolicRing): from sage.rings.real_mpfr import RR + p = RR # Convert all inputs to the common parent @@ -582,8 +579,7 @@ def color_selector(default=(0, 0, 1), label=None, widget=None, hide_box=False): SageColorPicker(value='#19334c') """ # widget argument is silently ignored - kwds = {"value": Color(default).html_color(), - "concise": hide_box} + kwds = {"value": Color(default).html_color(), "concise": hide_box} if label is not None: kwds["description"] = label return SageColorPicker(**kwds) diff --git a/src/sage/repl/load.py b/src/sage/repl/load.py index 4dc80bfba53..d40da073ce8 100644 --- a/src/sage/repl/load.py +++ b/src/sage/repl/load.py @@ -1,6 +1,7 @@ """ Load Python, Sage, Cython, Fortran and Magma files in Sage """ + # **************************************************************************** # Copyright (C) 2006 William Stein # @@ -67,8 +68,10 @@ def load_cython(name): module. """ from sage.misc.cython import cython + mod, dir = cython(str(name), compile_message=True, use_cache=True) import sys + sys.path.append(dir) return f'from {mod} import *' @@ -246,11 +249,13 @@ def load(filename, globals, attach=False): # https://diveintopython3.net/http-web-services.html#etags raise NotImplementedError("you cannot attach a URL") from sage.misc.remote_file import get_remote_file + filename = get_remote_file(filename, verbose=False) filename = Path(filename).expanduser() from sage.repl.attach import load_attach_path + for path in load_attach_path(): fpath = (path / filename).expanduser() if fpath.is_file(): @@ -268,6 +273,7 @@ def load(filename, globals, attach=False): elif ext == '.sage': from sage.repl.attach import load_attach_mode from sage.repl.preparse import preparse_file_named, preparse_file + load_debug_mode, attach_debug_mode = load_attach_mode() if (attach and attach_debug_mode) or ((not attach) and load_debug_mode): # Preparse to a file to enable tracebacks with @@ -292,6 +298,7 @@ def load(filename, globals, attach=False): exec(load_cython(fpath), globals) elif ext in ['.f', '.f90']: from sage.misc.inline_fortran import fortran + with fpath.open() as f: fortran(f.read(), globals) elif ext == '.m': @@ -300,7 +307,7 @@ def load(filename, globals, attach=False): # further. s = globals['magma'].load(fpath) i = s.find('\n') - print(s[i + 1:]) + print(s[i + 1 :]) else: raise ValueError('unknown file extension %r for load or attach (supported extensions: .py, .pyx, .sage, .spyx, .f, .f90, .m)' % ext) @@ -332,7 +339,6 @@ def load_wrap(filename, attach=False): if isinstance(filename, Path): filename = str(filename) # Note: In Python 3, b64encode only accepts bytes, and returns bytes. - b64 = base64.b64encode(str_to_bytes(filename, FS_ENCODING, - "surrogateescape")) + b64 = base64.b64encode(str_to_bytes(filename, FS_ENCODING, "surrogateescape")) txt = 'sage.repl.load.load(sage.repl.load.base64.b64decode("{}"),globals(),{})' return txt.format(bytes_to_str(b64, 'ascii'), attach) diff --git a/src/sage/repl/preparse.py b/src/sage/repl/preparse.py index 75c004e8ad6..321727e51bd 100644 --- a/src/sage/repl/preparse.py +++ b/src/sage/repl/preparse.py @@ -478,8 +478,7 @@ class QuoteStackFrame(SimpleNamespace): Only F-strings have more than one level. """ - def __init__(self, delim, raw=False, f_string=False, braces=0, parens=0, brackets=0, - fmt_spec=False, nested_fmt_spec=False): + def __init__(self, delim, raw=False, f_string=False, braces=0, parens=0, brackets=0, fmt_spec=False, nested_fmt_spec=False): """ Create a new QuoteStackFrame. @@ -761,10 +760,10 @@ def in_literal(): if not k % 2: escaped = True # Check for end of quote. - if not escaped and code[q:q + len(quote.delim)] == quote.delim: + if not escaped and code[q : q + len(quote.delim)] == quote.delim: counter += 1 label = "L%s" % counter - literals[label] = code[start:q + len(quote.delim)] + literals[label] = code[start : q + len(quote.delim)] new_code.append("%%(%s)s" % label) q += len(quote.delim) start = q @@ -801,7 +800,7 @@ def in_literal(): newline = len(code) counter += 1 label = "L%s" % counter - literals[label] = code[q + 1:newline] + literals[label] = code[q + 1 : newline] new_code.append(code[start:q].replace('%', '%%')) new_code.append("#%%(%s)s" % label) start = q = newline @@ -820,7 +819,7 @@ def in_literal(): handle_colon = True if handle_colon: # Treat the preceding substring and the colon itself as code. - new_code.append(code[start:q + 1].replace('%', '%%')) + new_code.append(code[start : q + 1].replace('%', '%%')) start = q + 1 elif ch == '{' or ch == '}': @@ -1043,10 +1042,10 @@ def parse_ellipsis(code, preparse_step=True): raise SyntaxError("cannot start line with ellipsis") elif code[ix - 1] == '.': # '...' be valid Python in index slices - code = code[:ix - 1] + "Ellipsis" + code[ix + 2:] + code = code[: ix - 1] + "Ellipsis" + code[ix + 2 :] elif len(code) >= ix + 3 and code[ix + 2] == '.': # '...' be valid Python in index slices - code = code[:ix] + "Ellipsis" + code[ix + 3:] + code = code[:ix] + "Ellipsis" + code[ix + 3 :] else: start_list, end_list = containing_block(code, ix, ['()', '[]']) @@ -1059,15 +1058,12 @@ def parse_ellipsis(code, preparse_step=True): start_list, end_list = containing_block(code, ix, ['()', '[]']) ix = code.find('..', ix + 2, end_list) - arguments = code[start_list + 1:end_list - 1].replace('...', ',Ellipsis,').replace('..', ',Ellipsis,') + arguments = code[start_list + 1 : end_list - 1].replace('...', ',Ellipsis,').replace('..', ',Ellipsis,') arguments = re.sub(r',\s*,', ',', arguments) if preparse_step: arguments = arguments.replace(';', ', step=') range_or_iter = 'range' if code[start_list] == '[' else 'iter' - code = "%s(ellipsis_%s(%s))%s" % (code[:start_list], - range_or_iter, - arguments, - code[end_list:]) + code = "%s(ellipsis_%s(%s))%s" % (code[:start_list], range_or_iter, arguments, code[end_list:]) ix = code.find('..') return code @@ -1495,15 +1491,14 @@ def preparse_calculus(code): raise ValueError("argument names should be valid python identifiers") vars = ','.join(stripped_vars) - new_code.append(code[last_end:m.start()]) - new_code.append(';%s__tmp__=var("%s"); %s = symbolic_expression(%s).function(%s)' % - (ident, vars, func, expr, vars)) + new_code.append(code[last_end : m.start()]) + new_code.append(';%s__tmp__=var("%s"); %s = symbolic_expression(%s).function(%s)' % (ident, vars, func, expr, vars)) last_end = m.end() if last_end == 0: return code - new_code.append(code[m.end():]) + new_code.append(code[m.end() :]) return ''.join(new_code) @@ -1653,13 +1648,13 @@ def preparse_generators(code): gens = [v.strip() for v in gens.split(',')] constructor = constructor.rstrip() if len(constructor) == 0: - pass # SyntaxError will be raised by Python later + pass # SyntaxError will be raised by Python later elif constructor[-1] == ')': if '(' not in constructor: raise SyntaxError("mismatched ')'") opening = constructor.rindex('(') # Only use comma if there are already arguments to the constructor - comma = ', ' if constructor[opening + 1:-1].strip() else '' + comma = ', ' if constructor[opening + 1 : -1].strip() else '' names = "('%s',)" % "', '".join(gens) constructor = constructor[:-1] + comma + "names=%s)" % names elif constructor[-1] == ']': @@ -1668,29 +1663,27 @@ def preparse_generators(code): raise SyntaxError("mismatched ']'") opening = constructor.rindex('[') closing = constructor.index(']', opening) - if not constructor[opening + 1:closing].strip(): + if not constructor[opening + 1 : closing].strip(): names = "'" + ', '.join(gens) + "'" - constructor = constructor[:opening + 1] + names + constructor[closing:] + constructor = constructor[: opening + 1] + names + constructor[closing:] else: pass gens_tuple = "(%s,)" % ', '.join(gens) - new_code.append(code[last_end:m.start()]) - new_code.append(";%s%s%s = %s; %s = %s._first_ngens(%s)" % - (ident, obj, other_objs, constructor, gens_tuple, obj, len(gens))) + new_code.append(code[last_end : m.start()]) + new_code.append(";%s%s%s = %s; %s = %s._first_ngens(%s)" % (ident, obj, other_objs, constructor, gens_tuple, obj, len(gens))) last_end = m.end() if last_end == 0: return code - new_code.append(code[m.end():]) + new_code.append(code[m.end() :]) return ''.join(new_code) quote_state = None -def preparse(line, reset=True, do_time=False, ignore_prompts=False, - numeric_literals=True): +def preparse(line, reset=True, do_time=False, ignore_prompts=False, numeric_literals=True): r""" Preparse a line of input. @@ -1780,8 +1773,7 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, if L.startswith('...'): i = line.find('...') - return line[:i + 3] + preparse(line[i + 3:], reset=reset, - do_time=do_time, ignore_prompts=ignore_prompts) + return line[: i + 3] + preparse(line[i + 3 :], reset=reset, do_time=do_time, ignore_prompts=ignore_prompts) if ignore_prompts: # Get rid of leading sage: and >>> so that pasting of examples from @@ -1835,7 +1827,7 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, ends.append(i) while ends: i = ends.pop() - L = L[:i] + ';%s;' % L[i] + L[i + 1:] + L = L[:i] + ';%s;' % L[i] + L[i + 1 :] L = ';' + L + ';' if do_time: @@ -1853,10 +1845,7 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, if do_time: # Time keyword - L = re.sub(r';time;(\s*)(\S[^;\n]*)', - r';\1__time__ = cputime(); __wall__ = walltime(); \2; print(' + - r'"Time: CPU {:.2f} s, Wall: {:.2f} s".format(cputime(__time__), walltime(__wall__)))', - L, flags=re.MULTILINE) + L = re.sub(r';time;(\s*)(\S[^;\n]*)', r';\1__time__ = cputime(); __wall__ = walltime(); \2; print(' + r'"Time: CPU {:.2f} s, Wall: {:.2f} s".format(cputime(__time__), walltime(__wall__)))', L, flags=re.MULTILINE) # Remove extra ;'s L = L.replace(';#;', '#') @@ -1869,6 +1858,7 @@ def preparse(line, reset=True, do_time=False, ignore_prompts=False, # Apply the preparser to an entire file ###################################################### + def preparse_file(contents, globals=None, numeric_literals=True): """ Preparse ``contents`` which is input from a file such as ``.sage`` files. @@ -1949,7 +1939,7 @@ def preparse_file(contents, globals=None, numeric_literals=True): preparse_opts = dict(do_time=True, ignore_prompts=False, numeric_literals=not numeric_literals) for m in re.finditer(r'^(\s*)(load|attach) ([^(].*)$', contents, re.MULTILINE): # Preparse contents prior to the load/attach. - lines_out += preparse(contents[start:m.start()], **preparse_opts).splitlines() + lines_out += preparse(contents[start : m.start()], **preparse_opts).splitlines() # Wrap the load/attach itself. lines_out.append(m.group(1) + load_wrap(m.group(3), m.group(2) == 'attach')) # Further preparsing should start after this load/attach line. @@ -2014,18 +2004,15 @@ def implicit_mul(code, level=5): '1e3 + 0.3e-3rj' """ from keyword import iskeyword + keywords_py2 = ['print', 'exec'] def re_no_keyword(pattern, code): for _ in range(2): # do it twice in because matches do not overlap for m in reversed(list(re.finditer(pattern, code))): left, right = m.groups() - if not iskeyword(left) and not iskeyword(right) \ - and left not in keywords_py2: - code = "%s%s*%s%s" % (code[:m.start()], - left, - right, - code[m.end():]) + if not iskeyword(left) and not iskeyword(right) and left not in keywords_py2: + code = "%s%s*%s%s" % (code[: m.start()], left, right, code[m.end() :]) return code code, literals, state = strip_string_literals(code) @@ -2181,7 +2168,7 @@ def handle_encoding_declaration(contents, out): for num, line in enumerate(lines[:2]): if re.search(r"coding[:=]\s*([-\w.]+)", line): out.write(line + '\n') - return '\n'.join(lines[:num] + lines[(num + 1):]) + return '\n'.join(lines[:num] + lines[(num + 1) :]) # If we did not find any encoding hints, use explicit utf-8. # According to PEP 3120, this could be omitted. @@ -2221,6 +2208,7 @@ def preparse_file_named(name) -> Path: PosixPath('...sage.py') """ from sage.misc.temporary_file import tmp_filename + name = Path(name) assert name.suffix == '.sage' tmpfilename = Path(tmp_filename(name.stem, ext='.sage.py')) diff --git a/src/sage/repl/rich_output/__init__.py b/src/sage/repl/rich_output/__init__.py index 3a1b273112c..766873d346c 100644 --- a/src/sage/repl/rich_output/__init__.py +++ b/src/sage/repl/rich_output/__init__.py @@ -1,3 +1,2 @@ - from .display_manager import get_display_manager from .pretty_print import pretty_print diff --git a/src/sage/repl/rich_output/backend_base.py b/src/sage/repl/rich_output/backend_base.py index 449cd5fe8e1..8c861c44a63 100644 --- a/src/sage/repl/rich_output/backend_base.py +++ b/src/sage/repl/rich_output/backend_base.py @@ -94,6 +94,7 @@ def get_display_manager(self): The Sage display manager using the doctest backend """ from sage.repl.rich_output import get_display_manager + return get_display_manager() def install(self, **kwds): @@ -156,6 +157,7 @@ def default_preferences(self): * text is not specified """ from sage.repl.rich_output.preferences import DisplayPreferences + return DisplayPreferences() def supported_output(self): @@ -257,8 +259,7 @@ def _apply_pretty_printer(self, pretty_printer_class, obj): '1/2' """ stream = StringIO() - printer = pretty_printer_class( - stream, self.max_width(), self.newline()) + printer = pretty_printer_class(stream, self.max_width(), self.newline()) printer.pretty(obj) printer.flush() return stream.getvalue() @@ -310,12 +311,13 @@ def plain_text_formatter(self, obj, **kwds): '0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19' """ from sage.repl.display.pretty_print import SagePrettyPrinter + if kwds.get('concatenate', False): - plain_text = ' '.join( - self._apply_pretty_printer(SagePrettyPrinter, o) for o in obj) + plain_text = ' '.join(self._apply_pretty_printer(SagePrettyPrinter, o) for o in obj) else: plain_text = self._apply_pretty_printer(SagePrettyPrinter, obj) from sage.repl.rich_output.output_basic import OutputPlainText + return OutputPlainText(plain_text) def ascii_art_formatter(self, obj, **kwds): @@ -359,11 +361,13 @@ def ascii_art_formatter(self, obj, **kwds): '1 2 3' """ from sage.typeset.ascii_art import ascii_art + if kwds.get('concatenate', False): result = ascii_art(*obj, sep=' ') else: result = ascii_art(obj) from sage.repl.rich_output.output_basic import OutputAsciiArt + return OutputAsciiArt(str(result)) def unicode_art_formatter(self, obj, **kwds): @@ -408,11 +412,13 @@ def unicode_art_formatter(self, obj, **kwds): '1 2 3' """ from sage.typeset.unicode_art import unicode_art + if kwds.get('concatenate', False): result = unicode_art(*obj, sep=' ') else: result = unicode_art(obj) from sage.repl.rich_output.output_basic import OutputUnicodeArt + return OutputUnicodeArt(str(result)) def latex_formatter(self, obj, **kwds): @@ -466,6 +472,7 @@ def latex_formatter(self, obj, **kwds): concatenate = kwds.get('concatenate', False) from sage.misc.html import html from sage.repl.rich_output.output_browser import OutputHtml + return OutputHtml(html(obj, concatenate=concatenate, strict=True)) def set_underscore_variable(self, obj): @@ -623,6 +630,7 @@ def supported_output(self): {} """ from sage.repl.rich_output.output_basic import OutputPlainText + return set([OutputPlainText]) def display_immediately(self, plain_text, rich_output): diff --git a/src/sage/repl/rich_output/backend_doctest.py b/src/sage/repl/rich_output/backend_doctest.py index 36fe7ccf739..f2e98c7b16a 100644 --- a/src/sage/repl/rich_output/backend_doctest.py +++ b/src/sage/repl/rich_output/backend_doctest.py @@ -68,6 +68,7 @@ def default_preferences(self): * text is not specified """ from sage.repl.rich_output.preferences import DisplayPreferences + return DisplayPreferences(supplemental_plot='never') def install(self, **kwds): @@ -130,15 +131,30 @@ def supported_output(self): sage: OutputSceneJmol in backend.supported_output() True """ - return set([ - OutputPlainText, OutputAsciiArt, OutputUnicodeArt, - OutputImagePng, OutputImageGif, OutputImageJpg, - OutputImageSvg, OutputImagePdf, OutputImageDvi, - OutputSceneJmol, OutputSceneCanvas3d, OutputSceneWavefront, - OutputVideoOgg, OutputVideoWebM, OutputVideoMp4, - OutputVideoFlash, OutputVideoMatroska, OutputVideoAvi, - OutputVideoWmv, OutputVideoQuicktime, - ]) + return set( + [ + OutputPlainText, + OutputAsciiArt, + OutputUnicodeArt, + OutputImagePng, + OutputImageGif, + OutputImageJpg, + OutputImageSvg, + OutputImagePdf, + OutputImageDvi, + OutputSceneJmol, + OutputSceneCanvas3d, + OutputSceneWavefront, + OutputVideoOgg, + OutputVideoWebM, + OutputVideoMp4, + OutputVideoFlash, + OutputVideoMatroska, + OutputVideoAvi, + OutputVideoWmv, + OutputVideoQuicktime, + ] + ) def displayhook(self, plain_text, rich_output): """ @@ -172,8 +188,7 @@ def displayhook(self, plain_text, rich_output): Graphics object consisting of 1 graphics primitive """ self.validate(rich_output) - if any(isinstance(rich_output, cls) - for cls in [OutputPlainText, OutputAsciiArt, OutputLatex, OutputHtml]): + if any(isinstance(rich_output, cls) for cls in [OutputPlainText, OutputAsciiArt, OutputLatex, OutputHtml]): rich_output.print_to_stdout() else: plain_text.print_to_stdout() @@ -293,7 +308,7 @@ def validate(self, rich_output): assert data[4:8] == b'ftyp' assert data.startswith(b'\0\0\0') # See http://www.ftyps.com/ - ftyps = [data[i:i+4] for i in range(8, data[3], 4)] + ftyps = [data[i : i + 4] for i in range(8, data[3], 4)] del ftyps[1] # version number, not an ftyp expected = [b'avc1', b'iso2', b'mp41', b'mp42'] assert any(i in ftyps for i in expected) diff --git a/src/sage/repl/rich_output/backend_emacs.py b/src/sage/repl/rich_output/backend_emacs.py index b0b6c284c0a..490d9f06ff6 100644 --- a/src/sage/repl/rich_output/backend_emacs.py +++ b/src/sage/repl/rich_output/backend_emacs.py @@ -71,6 +71,7 @@ def default_preferences(self): * text is not specified """ from sage.repl.rich_output.preferences import DisplayPreferences + return DisplayPreferences() def displayhook(self, plain_text, rich_output): @@ -117,28 +118,23 @@ def displayhook(self, plain_text, rich_output): if isinstance(rich_output, OutputAsciiArt): return ({'text/plain': rich_output.ascii_art.get_str()}, {}) if isinstance(rich_output, OutputLatex): - text = "BEGIN_TEXT:" + plain_text.text.get_str() + ":END_TEXT\nBEGIN_LATEX:" + \ - rich_output.latex.get_str() + ":END_LATEX" + text = "BEGIN_TEXT:" + plain_text.text.get_str() + ":END_TEXT\nBEGIN_LATEX:" + rich_output.latex.get_str() + ":END_LATEX" return ({'text/plain': text}, {}) # TODO: perhaps handle these by returning the data inline, # e.g. base64 encoded, so that sage-mode can show inline # images for remotely running shells. if isinstance(rich_output, OutputImagePng): - msg = self.launch_viewer( - rich_output.png.filename(ext='png'), plain_text.text.get()) + msg = self.launch_viewer(rich_output.png.filename(ext='png'), plain_text.text.get()) return ({'text/plain': msg}, {}) if isinstance(rich_output, OutputImageGif): - msg = self.launch_viewer( - rich_output.gif.filename(ext='gif'), plain_text.text.get()) + msg = self.launch_viewer(rich_output.gif.filename(ext='gif'), plain_text.text.get()) return ({'text/plain': msg}, {}) if isinstance(rich_output, OutputImagePdf): - msg = self.launch_viewer( - rich_output.pdf.filename(ext='pdf'), plain_text.text.get()) + msg = self.launch_viewer(rich_output.pdf.filename(ext='pdf'), plain_text.text.get()) return ({'text/plain': msg}, {}) if isinstance(rich_output, OutputImageDvi): - msg = self.launch_viewer( - rich_output.dvi.filename(ext='dvi'), plain_text.text.get()) + msg = self.launch_viewer(rich_output.dvi.filename(ext='dvi'), plain_text.text.get()) return ({'text/plain': msg}, {}) if isinstance(rich_output, OutputSceneJmol): msg = self.launch_jmol(rich_output, plain_text.text.get()) diff --git a/src/sage/repl/rich_output/backend_ipython.py b/src/sage/repl/rich_output/backend_ipython.py index 4241fe8abf8..d364ee213ef 100644 --- a/src/sage/repl/rich_output/backend_ipython.py +++ b/src/sage/repl/rich_output/backend_ipython.py @@ -57,6 +57,7 @@ def install(self, **kwds): """ shell = kwds['shell'] from sage.repl.display.formatter import SageDisplayFormatter + shell.display_formatter = SageDisplayFormatter(parent=shell) shell.configurables.append(shell.display_formatter) @@ -145,6 +146,7 @@ def default_preferences(self): * text is not specified """ from sage.repl.rich_output.preferences import DisplayPreferences + return DisplayPreferences(supplemental_plot='never') def _repr_(self): @@ -184,12 +186,21 @@ def supported_output(self): sage: OutputLatex in supp True """ - return set([ - OutputPlainText, OutputAsciiArt, OutputUnicodeArt, OutputLatex, - OutputImagePng, OutputImageGif, - OutputImagePdf, OutputImageDvi, - OutputSceneJmol, OutputSceneWavefront, OutputSceneThreejs, - ]) + return set( + [ + OutputPlainText, + OutputAsciiArt, + OutputUnicodeArt, + OutputLatex, + OutputImagePng, + OutputImageGif, + OutputImagePdf, + OutputImageDvi, + OutputSceneJmol, + OutputSceneWavefront, + OutputSceneThreejs, + ] + ) def displayhook(self, plain_text, rich_output): """ @@ -245,20 +256,16 @@ def displayhook(self, plain_text, rich_output): if isinstance(rich_output, OutputLatex): return ({'text/plain': rich_output.latex.get_str()}, {}) if isinstance(rich_output, OutputImagePng): - msg = self.launch_viewer( - rich_output.png.filename(ext='png'), plain_text.text.get_str()) + msg = self.launch_viewer(rich_output.png.filename(ext='png'), plain_text.text.get_str()) return ({'text/plain': msg}, {}) if isinstance(rich_output, OutputImageGif): - msg = self.launch_viewer( - rich_output.gif.filename(ext='gif'), plain_text.text.get_str()) + msg = self.launch_viewer(rich_output.gif.filename(ext='gif'), plain_text.text.get_str()) return ({'text/plain': msg}, {}) if isinstance(rich_output, OutputImagePdf): - msg = self.launch_viewer( - rich_output.pdf.filename(ext='pdf'), plain_text.text.get_str()) + msg = self.launch_viewer(rich_output.pdf.filename(ext='pdf'), plain_text.text.get_str()) return ({'text/plain': msg}, {}) if isinstance(rich_output, OutputImageDvi): - msg = self.launch_viewer( - rich_output.dvi.filename(ext='dvi'), plain_text.text.get_str()) + msg = self.launch_viewer(rich_output.dvi.filename(ext='dvi'), plain_text.text.get_str()) return ({'text/plain': msg}, {}) if isinstance(rich_output, OutputSceneJmol): msg = self.launch_jmol(rich_output, plain_text.text.get_str()) @@ -267,8 +274,7 @@ def displayhook(self, plain_text, rich_output): msg = self.launch_sage3d(rich_output, plain_text.text.get_str()) return ({'text/plain': msg}, {}) if isinstance(rich_output, OutputSceneThreejs): - msg = self.launch_viewer( - rich_output.html.filename(ext='html'), plain_text.text.get_str()) + msg = self.launch_viewer(rich_output.html.filename(ext='html'), plain_text.text.get_str()) return ({'text/plain': msg}, {}) raise TypeError('rich_output type not supported') @@ -324,13 +330,14 @@ def launch_viewer(self, image_file, plain_text): base, dot_ext = os.path.splitext(image_file) ext = dot_ext.lstrip(os.path.extsep) from sage.misc.viewer import viewer + command = viewer(ext) if not command: command = viewer.browser() from sage.doctest import DOCTEST_MODE + if not DOCTEST_MODE: - os.system('{0} {1} 2>/dev/null 1>/dev/null &' - .format(command, image_file)) + os.system('{0} {1} 2>/dev/null 1>/dev/null &'.format(command, image_file)) return 'Launched {0} viewer for {1}'.format(ext, plain_text) def launch_jmol(self, output_jmol, plain_text): @@ -359,14 +366,14 @@ def launch_jmol(self, output_jmol, plain_text): """ from sage.doctest import DOCTEST_MODE from sage.interfaces.jmoldata import JmolData + jdata = JmolData() if not jdata.is_jmol_available() and not DOCTEST_MODE: raise RuntimeError('jmol cannot run, no suitable java version found') launch_script = output_jmol.launch_script_filename() jmol_cmd = 'jmol' if not DOCTEST_MODE: - os.system('{0} {1} 2>/dev/null 1>/dev/null &' - .format(jmol_cmd, launch_script)) + os.system('{0} {1} 2>/dev/null 1>/dev/null &'.format(jmol_cmd, launch_script)) return 'Launched jmol viewer for {0}'.format(plain_text) def is_in_terminal(self): @@ -472,13 +479,22 @@ def supported_output(self): sage: OutputImageGif in supp True """ - return set([ - OutputPlainText, OutputAsciiArt, OutputUnicodeArt, OutputLatex, - OutputHtml, - OutputImagePng, OutputImageGif, OutputImageJpg, - OutputImageSvg, OutputImagePdf, - OutputSceneJmol, OutputSceneThreejs, - ]) + return set( + [ + OutputPlainText, + OutputAsciiArt, + OutputUnicodeArt, + OutputLatex, + OutputHtml, + OutputImagePng, + OutputImageGif, + OutputImageJpg, + OutputImageSvg, + OutputImagePdf, + OutputSceneJmol, + OutputSceneThreejs, + ] + ) def displayhook(self, plain_text, rich_output): """ @@ -520,41 +536,69 @@ def displayhook(self, plain_text, rich_output): if isinstance(rich_output, OutputUnicodeArt): return ({'text/plain': rich_output.unicode_art.get_str()}, {}) if isinstance(rich_output, OutputLatex): - return ({'text/latex': rich_output.latex.get_str(), - 'text/plain': plain_text.text.get_str(), - }, {}) + return ( + { + 'text/latex': rich_output.latex.get_str(), + 'text/plain': plain_text.text.get_str(), + }, + {}, + ) if isinstance(rich_output, OutputHtml): - data = {'text/html': rich_output.html.get_str(), - 'text/plain': plain_text.text.get_str()} + data = {'text/html': rich_output.html.get_str(), 'text/plain': plain_text.text.get_str()} if rich_output.latex: data['text/latex'] = rich_output.latex.get_str() return (data, {}) if isinstance(rich_output, OutputImagePng): - return ({'image/png': rich_output.png.get(), - 'text/plain': plain_text.text.get_str(), - }, {}) + return ( + { + 'image/png': rich_output.png.get(), + 'text/plain': plain_text.text.get_str(), + }, + {}, + ) if isinstance(rich_output, OutputImageGif): - return ({'text/html': rich_output.html_fragment(), - 'text/plain': plain_text.text.get_str(), - }, {}) + return ( + { + 'text/html': rich_output.html_fragment(), + 'text/plain': plain_text.text.get_str(), + }, + {}, + ) if isinstance(rich_output, OutputImageJpg): - return ({'image/jpeg': rich_output.jpg.get(), - 'text/plain': plain_text.text.get_str(), - }, {}) + return ( + { + 'image/jpeg': rich_output.jpg.get(), + 'text/plain': plain_text.text.get_str(), + }, + {}, + ) if isinstance(rich_output, OutputImageSvg): - return ({'image/svg+xml': rich_output.svg.get(), - 'text/plain': plain_text.text.get_str(), - }, {}) + return ( + { + 'image/svg+xml': rich_output.svg.get(), + 'text/plain': plain_text.text.get_str(), + }, + {}, + ) if isinstance(rich_output, OutputImagePdf): - return ({'image/png': rich_output.png.get(), - 'text/plain': plain_text.text.get_str(), - }, {}) + return ( + { + 'image/png': rich_output.png.get(), + 'text/plain': plain_text.text.get_str(), + }, + {}, + ) if isinstance(rich_output, OutputSceneJmol): from sage.repl.display.jsmol_iframe import JSMolHtml + jsmol = JSMolHtml(rich_output, height=500) - return ({'text/html': jsmol.iframe(), - 'text/plain': plain_text.text.get_str(), - }, {}) + return ( + { + 'text/html': jsmol.iframe(), + 'text/plain': plain_text.text.get_str(), + }, + {}, + ) if isinstance(rich_output, OutputSceneThreejs): escaped_html = html.escape(rich_output.html.get_str()) iframe = IFRAME_TEMPLATE.format( @@ -562,9 +606,13 @@ def displayhook(self, plain_text, rich_output): width='100%', height=400, ) - return ({'text/html': iframe, - 'text/plain': plain_text.text.get_str(), - }, {}) + return ( + { + 'text/html': iframe, + 'text/plain': plain_text.text.get_str(), + }, + {}, + ) raise TypeError('rich_output type not supported') def threejs_offline_scripts(self): @@ -582,6 +630,7 @@ def threejs_offline_scripts(self): """ from sage.repl.rich_output import get_display_manager from sage.features.threejs import Threejs + CDN_script = get_display_manager().threejs_scripts(online=True) CDN_script = CDN_script.replace('', r'<\/script>').replace('\n', ' \\\n') return """ @@ -589,4 +638,6 @@ def threejs_offline_scripts(self): - """.format(Threejs().required_version(), CDN_script) + """.format( + Threejs().required_version(), CDN_script + ) diff --git a/src/sage/repl/rich_output/buffer.py b/src/sage/repl/rich_output/buffer.py index 2aea7005dfb..7ff2543c7f4 100644 --- a/src/sage/repl/rich_output/buffer.py +++ b/src/sage/repl/rich_output/buffer.py @@ -20,6 +20,7 @@ sage: type(buf.get()) is bytes True """ + # **************************************************************************** # Copyright (C) 2015 Volker Braun # @@ -132,12 +133,14 @@ def _chmod_readonly(cls, filename): 0 """ from sage.env import SAGE_SRC + filename = os.path.abspath(filename) if filename.startswith(os.path.abspath(SAGE_SRC)): # Do not change permissions on the sample rich output # files, as it will cause trouble when upgrading Sage return import stat + mode = os.stat(filename).st_mode mode = stat.S_IMODE(mode) & ~(stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH) # The file may already be read only for that user @@ -264,6 +267,7 @@ def filename(self, ext=None): if self._filename is None or not self._filename.endswith(ext): from sage.misc.temporary_file import tmp_filename + output = tmp_filename(ext=ext) else: output = self._filename @@ -278,6 +282,7 @@ def filename(self, ext=None): os.link(self._filename, output) except (OSError, AttributeError): import shutil + shutil.copy2(self._filename, output) self._chmod_readonly(output) diff --git a/src/sage/repl/rich_output/display_manager.py b/src/sage/repl/rich_output/display_manager.py index 8f3e3b3a0d6..e1bcaedb1eb 100644 --- a/src/sage/repl/rich_output/display_manager.py +++ b/src/sage/repl/rich_output/display_manager.py @@ -60,6 +60,7 @@ class DisplayException(Exception): ... DisplayException: foo """ + pass @@ -82,6 +83,7 @@ class OutputTypeException(DisplayException): ... OutputTypeException: foo """ + pass @@ -102,6 +104,7 @@ class RichReprWarning(UserWarning): ... RichReprWarning: foo """ + pass @@ -204,6 +207,7 @@ def __init__(self): assert DisplayManager._instance is None DisplayManager._instance = self from sage.repl.rich_output.backend_base import BackendSimple + self.switch_backend(BackendSimple()) @classmethod @@ -262,6 +266,7 @@ def types(self): """ import sage.repl.rich_output.output_catalog + return sage.repl.rich_output.output_catalog def switch_backend(self, backend, **kwds): @@ -297,6 +302,7 @@ def switch_backend(self, backend, **kwds): True """ from sage.repl.rich_output.backend_base import BackendBase + if not isinstance(backend, BackendBase): raise ValueError('backend must be instance of BackendBase class') supported = backend.supported_output() @@ -305,11 +311,10 @@ def switch_backend(self, backend, **kwds): try: self._backend.uninstall() except AttributeError: - pass # first time we switch + pass # first time we switch # clear caches self._output_promotions = dict() - self._supported_output = frozenset( - map(self._demote_output_class, backend.supported_output())) + self._supported_output = frozenset(map(self._demote_output_class, backend.supported_output())) # install new backend try: old_backend = self._backend @@ -412,10 +417,9 @@ def _demote_output_class(self, output_class): """ from sage.repl.rich_output.output_basic import OutputBase + if not issubclass(output_class, OutputBase): - raise OutputTypeException( - 'invalid output container type: {0} is not subclass of OutputBase' - .format(output_class)) + raise OutputTypeException('invalid output container type: {0} is not subclass of OutputBase'.format(output_class)) result = None for type_name in dir(self.types): if type_name.startswith('_'): @@ -425,16 +429,12 @@ def _demote_output_class(self, output_class): continue if issubclass(output_class, tp): if result is not None: - raise OutputTypeException( - '{0} inherits from multiple output classes' - .format(output_class)) + raise OutputTypeException('{0} inherits from multiple output classes'.format(output_class)) else: self._output_promotions[tp] = output_class result = tp if result is None: - raise OutputTypeException( - '{0} does not inherit from any known output class' - .format(output_class)) + raise OutputTypeException('{0} does not inherit from any known output class'.format(output_class)) return result def _promote_output(self, output): @@ -628,24 +628,19 @@ def _rich_output_formatter(self, obj, rich_repr_kwds): if plain_text is None: plain_text = self._backend.plain_text_formatter(obj, **rich_repr_kwds) if rich_output is None: - rich_output = self._preferred_text_formatter( - obj, plain_text=plain_text, **rich_repr_kwds) + rich_output = self._preferred_text_formatter(obj, plain_text=plain_text, **rich_repr_kwds) # promote output container types to backend-specific containers plain_text = self._promote_output(plain_text) rich_output = self._promote_output(rich_output) # check that the output container types are valid for the backend supported = self._backend.supported_output() if type(plain_text) not in supported: - raise OutputTypeException( - 'text output container not supported: {0}'.format(type(plain_text))) + raise OutputTypeException('text output container not supported: {0}'.format(type(plain_text))) if type(rich_output) not in supported: - raise OutputTypeException( - 'output container not supported: {0}'.format(type(rich_output))) + raise OutputTypeException('output container not supported: {0}'.format(type(rich_output))) return plain_text, rich_output - def graphics_from_save(self, save_function, save_kwds, - file_extension, output_container, - figsize=None, dpi=None): + def graphics_from_save(self, save_function, save_kwds, file_extension, output_container, figsize=None, dpi=None): r""" Helper to construct graphics. @@ -694,11 +689,13 @@ def graphics_from_save(self, save_function, save_kwds, '/home/user/.sage/temp/localhost.localdomain/23903/tmp_pu5woK.png' """ import os + if not file_extension.startswith(os.path.extsep): raise ValueError('file_extension must start with a period') if output_container not in self.supported_output(): raise OutputTypeException('output_container is not supported by backend') from sage.misc.temporary_file import tmp_filename + filename = tmp_filename(ext=file_extension) # Call the save_function with the right arguments kwds = dict(save_kwds) @@ -708,6 +705,7 @@ def graphics_from_save(self, save_function, save_kwds, kwds['dpi'] = dpi save_function(filename, **kwds) from sage.repl.rich_output.buffer import OutputBuffer + buf = OutputBuffer.from_file(filename) return output_container(buf) @@ -739,16 +737,18 @@ def threejs_scripts(self, online): offline threejs graphics """ from sage.features.threejs import Threejs + if online: version = Threejs().required_version() return """ - """.format(version) + """.format( + version + ) try: return self._backend.threejs_offline_scripts() except AttributeError: - raise ValueError( - 'current backend does not support offline threejs graphics') + raise ValueError('current backend does not support offline threejs graphics') def supported_output(self): """ diff --git a/src/sage/repl/rich_output/output_basic.py b/src/sage/repl/rich_output/output_basic.py index 1ca3bfe2941..9c3fcd10de6 100644 --- a/src/sage/repl/rich_output/output_basic.py +++ b/src/sage/repl/rich_output/output_basic.py @@ -191,9 +191,7 @@ def example(cls): sage: OutputAsciiArt.example().ascii_art.get_str() '[ * * * * ]\n[ ** ** * * * * * * ]\n[ ***, * , * , **, ** , *, * , * , * ]' """ - return cls('[ * * * * ]\n' - '[ ** ** * * * * * * ]\n' - '[ ***, * , * , **, ** , *, * , * , * ]') + return cls('[ * * * * ]\n' '[ ** ** * * * * * * ]\n' '[ ***, * , * , **, ** , *, * , * , * ]') def print_to_stdout(self): """ @@ -263,9 +261,7 @@ def example(cls): ⎜ 3 -1 0⎟ ⎝ -1 -1 0⎠ """ - return cls('⎛-11 0 1⎞\n' - '⎜ 3 -1 0⎟\n' - '⎝ -1 -1 0⎠') + return cls('⎛-11 0 1⎞\n' '⎜ 3 -1 0⎟\n' '⎝ -1 -1 0⎠') def print_to_stdout(self): """ @@ -331,8 +327,7 @@ def display_equation(self): sage: rich_output.display_equation() '\\begin{equation}\n1\n\\end{equation}' """ - return '\n'.join([r'\begin{equation}', self.latex.get_str(), - r'\end{equation}']) + return '\n'.join([r'\begin{equation}', self.latex.get_str(), r'\end{equation}']) def inline_equation(self): r""" @@ -371,8 +366,7 @@ def example(cls): sage: OutputLatex.example().latex.get_str() '\\newcommand{\\Bold}[1]{\\mathbf{#1}}\\int \\sin\\left(x\\right)\\,{d x}' """ - return cls(r'\newcommand{\Bold}[1]{\mathbf{#1}}' - r'\int \sin\left(x\right)\,{d x}') + return cls(r'\newcommand{\Bold}[1]{\mathbf{#1}}' r'\int \sin\left(x\right)\,{d x}') def print_to_stdout(self): r""" diff --git a/src/sage/repl/rich_output/output_browser.py b/src/sage/repl/rich_output/output_browser.py index 16aa9fa66ea..b439e437a47 100644 --- a/src/sage/repl/rich_output/output_browser.py +++ b/src/sage/repl/rich_output/output_browser.py @@ -8,8 +8,7 @@ from sage.repl.rich_output.buffer import OutputBuffer # regex to match "\[...\]" or "\(...\)" -latex_re = re.compile(r'(?P\\\[|\\\()(?P.*)(?P\\\]|\\\))', - flags=re.DOTALL) +latex_re = re.compile(r'(?P\\\[|\\\()(?P.*)(?P\\\]|\\\))', flags=re.DOTALL) class OutputHtml(OutputBase): diff --git a/src/sage/repl/rich_output/output_graphics3d.py b/src/sage/repl/rich_output/output_graphics3d.py index a69f3989bc2..38b52172e66 100644 --- a/src/sage/repl/rich_output/output_graphics3d.py +++ b/src/sage/repl/rich_output/output_graphics3d.py @@ -3,6 +3,7 @@ This module defines the rich output types for 3-d scenes. """ + # **************************************************************************** # Copyright (C) 2015 Volker Braun # @@ -67,6 +68,7 @@ def launch_script_filename(self): script SCRIPT """ from sage.misc.temporary_file import tmp_dir + basedir = tmp_dir() scene_filename = os.path.join(basedir, 'scene.spt.zip') script_filename = os.path.join(basedir, 'scene.spt') @@ -234,8 +236,7 @@ def _check_no_directory(self, filename): ValueError: must be pure filename, got directory component: /absolute/scene.mtl """ if os.path.split(filename)[0]: - raise ValueError('must be pure filename, got directory component: {0}' - .format(filename)) + raise ValueError('must be pure filename, got directory component: {0}'.format(filename)) def mtllib(self): """ @@ -259,8 +260,7 @@ def mtllib(self): marker = b'mtllib ' for line in self.obj.get().splitlines(): if line.startswith(marker): - return bytes_to_str(line[len(marker):], FS_ENCODING, - 'surrogateescape') + return bytes_to_str(line[len(marker) :], FS_ENCODING, 'surrogateescape') return 'scene.mtl' def obj_filename(self): @@ -304,6 +304,7 @@ def obj_filename(self): d 1 """ from sage.misc.temporary_file import tmp_dir + basedir = tmp_dir() obj_filename = os.path.join(basedir, 'scene.obj') mtl_filename = os.path.join(basedir, self.mtllib()) diff --git a/src/sage/repl/rich_output/output_video.py b/src/sage/repl/rich_output/output_video.py index f3c6598d7dc..e1f5d7cd5ba 100644 --- a/src/sage/repl/rich_output/output_video.py +++ b/src/sage/repl/rich_output/output_video.py @@ -3,6 +3,7 @@ This module defines the rich output types for video formats. """ + # **************************************************************************** # Copyright (C) 2015 Martin von Gagern # @@ -64,8 +65,7 @@ def example(cls): 'video/ogg' """ with importlib.resources.path(__package__, 'example' + cls.ext) as filename: - return cls(OutputBuffer.from_file(filename), - {'controls': True, 'loop': False}) + return cls(OutputBuffer.from_file(filename), {'controls': True, 'loop': False}) def html_fragment(self, url, link_attrs=''): r""" @@ -96,16 +96,9 @@ def html_fragment(self, url, link_attrs=''): } if self.loop: attrs['loop'] = 'loop' - attrs = ''.join(' {}="{}"'.format(k, v) - for k, v in sorted(attrs.items())) - txt = ('' - '

' - '' - 'Download {mimetype} video

') - return txt.format(url=url, - mimetype=self.mimetype, - attrs=attrs, - link_attrs=link_attrs) + attrs = ''.join(' {}="{}"'.format(k, v) for k, v in sorted(attrs.items())) + txt = '' '

' '' 'Download {mimetype} video

' + return txt.format(url=url, mimetype=self.mimetype, attrs=attrs, link_attrs=link_attrs) class OutputVideoOgg(OutputVideoBase): diff --git a/src/sage/repl/rich_output/preferences.py b/src/sage/repl/rich_output/preferences.py index 7e80e8a2606..b0537219815 100644 --- a/src/sage/repl/rich_output/preferences.py +++ b/src/sage/repl/rich_output/preferences.py @@ -105,8 +105,7 @@ def __init__(self, name, allowed_values, doc=None): self.underscore_name = '_{0}'.format(name) self.allowed_values = tuple(allowed_values) self.__doc__ = doc = self._make_doc(doc) - super().__init__(fget=self.getter, fset=self.setter, - fdel=self.deleter, doc=doc) + super().__init__(fget=self.getter, fset=self.setter, fdel=self.deleter, doc=doc) def _make_doc(self, doc): """ @@ -142,8 +141,7 @@ def _make_doc(self, doc): doc += '\n\n' doc += 'Allowed values:\n\n' values_doc = ['* ``None`` (default): no preference'] - values_doc.extend('* {0}'.format(repr(value)) - for value in self.allowed_values) + values_doc.extend('* {0}'.format(repr(value)) for value in self.allowed_values) return doc + '\n\n'.join(values_doc) def __repr__(self): @@ -226,8 +224,7 @@ def setter(self, prefs, value): return self.deleter(prefs) allowed = self.allowed_values if value not in allowed: - raise ValueError('value must be unset (None) or one of {0}, got {1}' - .format(allowed, value)) + raise ValueError('value must be unset (None) or one of {0}, got {1}'.format(allowed, value)) setattr(prefs, self.underscore_name, value) def deleter(self, prefs): @@ -398,7 +395,7 @@ class DisplayPreferences(PreferencesABC): ('plain', 'ascii_art', 'unicode_art', 'latex'), """ Which textual representation is preferred - """ + """, ) @@ -407,7 +404,7 @@ class DisplayPreferences(PreferencesABC): ('center', 'left'), """ Preferred mode of latex displays - """ + """, ) @@ -416,7 +413,7 @@ class DisplayPreferences(PreferencesABC): ('disable', 'vector', 'raster'), """ Preferred graphics format - """ + """, ) @@ -427,5 +424,5 @@ class DisplayPreferences(PreferencesABC): Whether to graphically display graphs and other graph-like objects that implement rich output. When not specified small objects are show graphically and large objects as textual overview. - """ + """, ) diff --git a/src/sage/repl/rich_output/pretty_print.py b/src/sage/repl/rich_output/pretty_print.py index 274f06b0ba2..bc30d4a63e6 100644 --- a/src/sage/repl/rich_output/pretty_print.py +++ b/src/sage/repl/rich_output/pretty_print.py @@ -121,6 +121,7 @@ def _concatenate_graphs(self): Graphics Array of size 1 x 4 """ import sage.graphs.graph_list as graphs_list + return graphs_list.to_graphics_array(self.args, **self.kwds) def _concatenate_graphics(self): @@ -139,6 +140,7 @@ def _concatenate_graphics(self): (2, 4) """ from sage.plot.plot import graphics_array + return graphics_array(self.args, ncols=4, **self.kwds) def pretty_print(self): diff --git a/src/sage/repl/user_globals.py b/src/sage/repl/user_globals.py index e062238f540..60eea5fe492 100644 --- a/src/sage/repl/user_globals.py +++ b/src/sage/repl/user_globals.py @@ -80,10 +80,7 @@ def _check(): RuntimeError: the user-space globals dictionary has not been initialized... """ if user_globals is None: - raise RuntimeError( - "the user-space globals dictionary has not been initialized. " - "Use initialize_globals() or set_globals() or use a different " - "function which doesn't need these globals") + raise RuntimeError("the user-space globals dictionary has not been initialized. " "Use initialize_globals() or set_globals() or use a different " "function which doesn't need these globals") def get_globals(): @@ -158,6 +155,7 @@ def initialize_globals(all, g=None): if key[0] != '_': user_globals[key] = getattr(all, key) from sage.misc.lazy_import import clean_namespace + clean_namespace(user_globals) diff --git a/src/sage/rings/abc.pyi b/src/sage/rings/abc.pyi index 42411dfd616..4caaec6e6e7 100644 --- a/src/sage/rings/abc.pyi +++ b/src/sage/rings/abc.pyi @@ -1,24 +1,13 @@ from collections.abc import Callable from typing import Union -def abc(f: Callable | None = None, optional: bool = False) -> Callable: - ... +def abc(f: Callable | None = None, optional: bool = False) -> Callable: ... class ABC: - def __init__(self, f: Callable, optional: bool = False) -> None: - ... + def __init__(self, f: Callable, optional: bool = False) -> None: ... + def __repr__(self) -> str: ... + def _sage_src_lines_(self) -> Union[str, int]: ... + def __get__(self, instance: object, cls: type) -> Union[Callable, NotImplementedError]: ... + def is_optional(self) -> bool: ... - def __repr__(self) -> str: - ... - - def _sage_src_lines_(self) -> Union[str, int]: - ... - - def __get__(self, instance: object, cls: type) -> Union[Callable, NotImplementedError]: - ... - - def is_optional(self) -> bool: - ... - -def abstract_methods_of_class(cls: type) -> dict[str, list[str]]: - ... +def abstract_methods_of_class(cls: type) -> dict[str, list[str]]: ... diff --git a/src/sage/rings/algebraic_closure_finite_field.py b/src/sage/rings/algebraic_closure_finite_field.py index 2a1a5ba8cf7..3ef9ef0f296 100644 --- a/src/sage/rings/algebraic_closure_finite_field.py +++ b/src/sage/rings/algebraic_closure_finite_field.py @@ -74,6 +74,7 @@ class AlgebraicClosureFiniteFieldElement(FieldElement): sage: type(F.gen(2)) """ + def __init__(self, parent, value): """ TESTS:: @@ -91,6 +92,7 @@ def __init__(self, parent, value): n = value.parent().degree() else: from sage.rings.integer import Integer + n = Integer(1) self._value = parent._subfield(n).coerce(value) self._level = n @@ -185,7 +187,7 @@ def __pow__(self, exp): sage: z12**13 z12^8 + z12^7 + z12^6 + z12^4 + z12^2 + z12 """ - return self.__class__(self.parent(), self._value ** exp) + return self.__class__(self.parent(), self._value**exp) def _add_(self, right): """ @@ -349,7 +351,7 @@ def sqrt(self, all=False): x = self._value if not x.is_square(): l = self._level - x = F.inclusion(l, 2*l)(x) + x = F.inclusion(l, 2 * l)(x) sqrt = x.sqrt(extend=False, all=all) if all: return [self.__class__(F, y) for y in sqrt] @@ -373,6 +375,7 @@ def nth_root(self, n): This function could probably be made faster. """ from sage.rings.integer import Integer + F = self.parent() x = self._value n = Integer(n) @@ -380,7 +383,7 @@ def nth_root(self, n): # In order to be smart we look for the smallest subfield that # actually contains the root. for d in n.divisors(): - xx = F.inclusion(l, d*l)(x) + xx = F.inclusion(l, d * l)(x) try: y = xx.nth_root(n, extend=False) except ValueError: @@ -545,6 +548,7 @@ class AlgebraicClosureFiniteField_generic(Field): sage: GF(3).algebraic_closure().is_finite() False """ + def __init__(self, base_ring, name, category=None): """ TESTS:: @@ -554,8 +558,7 @@ def __init__(self, base_ring, name, category=None): sage: F Algebraic closure of Finite Field of size 5 """ - Field.__init__(self, base_ring=base_ring, names=name, - normalize=False, category=category) + Field.__init__(self, base_ring=base_ring, names=name, normalize=False, category=category) def __eq__(self, other): """ @@ -574,8 +577,7 @@ def __eq__(self, other): return True if type(self) is not type(other): return False - return ((self.base_ring(), self.variable_name(), self.category()) == - (other.base_ring(), other.variable_name(), other.category())) + return (self.base_ring(), self.variable_name(), self.category()) == (other.base_ring(), other.variable_name(), other.category()) def __ne__(self, other): """ @@ -744,11 +746,8 @@ def _subfield(self, n): if n == 1: return self.base_ring() from sage.rings.finite_rings.finite_field_constructor import FiniteField - return FiniteField(self.base_ring().cardinality() ** n, - name=self.variable_name() + str(n), - prefix=self.variable_name(), - modulus=self._get_polynomial(n), - check_irreducible=False) + + return FiniteField(self.base_ring().cardinality() ** n, name=self.variable_name() + str(n), prefix=self.variable_name(), modulus=self._get_polynomial(n), check_irreducible=False) def subfield(self, n): """ @@ -772,7 +771,7 @@ def subfield(self, n): Defn: z4 |--> z4) """ Fn = self._subfield(n) - return Fn, Fn.hom( (self.gen(n),), check=False) + return Fn, Fn.hom((self.gen(n),), check=False) def inclusion(self, m, n): """ @@ -797,7 +796,7 @@ def inclusion(self, m, n): # check=False is required to avoid "coercion hell": an # infinite loop in checking the morphism involving # polynomial_compiled.pyx on the modulus(). - return self._subfield(m).hom( (self._get_im_gen(m, n),), check=False) + return self._subfield(m).hom((self._get_im_gen(m, n),), check=False) raise ValueError("subfield of degree %s not contained in subfield of degree %s" % (m, n)) def ngens(self): @@ -812,6 +811,7 @@ def ngens(self): +Infinity """ from sage.rings.infinity import Infinity + return Infinity def gen(self, n): @@ -848,6 +848,7 @@ def gens(self) -> AbstractFamily: """ from sage.sets.family import Family from sage.sets.positive_integers import PositiveIntegers + return Family(PositiveIntegers(), self.gen) def _first_ngens(self, n): @@ -899,7 +900,7 @@ def some_elements(self): sage: F.some_elements() (1, z2, z3 + 1) """ - return (self(1), self.gen(2), 1+self.gen(3)) + return (self(1), self.gen(2), 1 + self.gen(3)) def _roots_univariate_polynomial(self, p, ring=None, multiplicities=None, algorithm=None): r""" @@ -939,7 +940,7 @@ def _roots_univariate_polynomial(self, p, ring=None, multiplicities=None, algori new_coeffs = [self.inclusion(c[0].degree(), l)(c[1]) for c in coeffs] polys = [(g, m, l, phi) for g, m in P(new_coeffs).factor()] - roots = [] # a list of pair (root,multiplicity) + roots = [] # a list of pair (root,multiplicity) while polys: g, m, l, phi = polys.pop() @@ -977,6 +978,7 @@ def _factor_univariate_polynomial(self, p, **kwds): ....: assert p.factor().prod() == p, "error in the factorization of p={}".format(p) """ from sage.structure.factorization import Factorization + R = p.parent() return Factorization([(R([-root, self.one()]), m) for root, m in p.roots()], unit=p[p.degree()]) @@ -1007,6 +1009,7 @@ class AlgebraicClosureFiniteField_pseudo_conway(WithEqualityById, AlgebraicClosu sage: F3 == F5 False """ + def __init__(self, base_ring, name, category=None, lattice=None, use_database=True): """ INPUT: @@ -1062,6 +1065,7 @@ def __init__(self, base_ring, name, category=None, lattice=None, use_database=Tr if not (isinstance(base_ring, FiniteField) and base_ring.is_prime_field()): raise NotImplementedError('algebraic closures of finite fields are only implemented for prime fields') from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice + p = base_ring.characteristic() if lattice is None: lattice = PseudoConwayLattice(p, use_database) @@ -1099,7 +1103,7 @@ def _get_im_gen(self, m, n): p = self.characteristic() if m == 1: return self._subfield(n).one() - return self._subfield(n).gen() ** ((p**n - 1)//(p**m - 1)) + return self._subfield(n).gen() ** ((p**n - 1) // (p**m - 1)) def AlgebraicClosureFiniteField(base_ring, name, category=None, implementation=None, **kwds): @@ -1137,6 +1141,7 @@ def AlgebraicClosureFiniteField(base_ring, name, category=None, implementation=N """ if category is None: from sage.categories.fields import Fields + category = Fields().Infinite() if implementation is None: @@ -1144,5 +1149,4 @@ def AlgebraicClosureFiniteField(base_ring, name, category=None, implementation=N if implementation == 'pseudo_conway': return AlgebraicClosureFiniteField_pseudo_conway(base_ring, name, category, **kwds) - raise ValueError('unknown implementation for algebraic closure of finite field: %s' - % implementation) + raise ValueError('unknown implementation for algebraic closure of finite field: %s' % implementation) diff --git a/src/sage/rings/all.py b/src/sage/rings/all.py index 1e5d9aa0c15..7178ed8b01a 100644 --- a/src/sage/rings/all.py +++ b/src/sage/rings/all.py @@ -1,6 +1,7 @@ """ Rings """ + # **************************************************************************** # Copyright (C) 2005 William Stein # @@ -13,19 +14,16 @@ from sage.misc.lazy_import import lazy_import # Ring base classes -from sage.rings.ring import (Ring, Field, CommutativeRing, IntegralDomain, - PrincipalIdealDomain) +from sage.rings.ring import Ring, Field, CommutativeRing, IntegralDomain, PrincipalIdealDomain lazy_import("sage.rings.ring", "DedekindDomain") # Ring element base classes -from sage.structure.element import (CommutativeAlgebraElement, - RingElement, CommutativeRingElement, IntegralDomainElement, - DedekindDomainElement, PrincipalIdealDomainElement, - EuclideanDomainElement, FieldElement) +from sage.structure.element import CommutativeAlgebraElement, RingElement, CommutativeRingElement, IntegralDomainElement, DedekindDomainElement, PrincipalIdealDomainElement, EuclideanDomainElement, FieldElement # Ideals from sage.rings.ideal import Ideal + ideal = Ideal # Quotient @@ -41,11 +39,13 @@ # Rational numbers from sage.rings.rational_field import RationalField, QQ from sage.rings.rational import Rational + Rationals = RationalField # Integers modulo n. from sage.rings.finite_rings.integer_mod_ring import IntegerModRing, Zmod from sage.rings.finite_rings.integer_mod import IntegerMod, Mod, mod + Integers = IntegerModRing # Finite fields @@ -71,8 +71,8 @@ from sage.rings.semirings.all import * # Real numbers -from sage.rings.real_mpfr import (RealField, RR, - create_RealNumber as RealNumber) # this is used by the preparser to wrap real literals -- very important. +from sage.rings.real_mpfr import RealField, RR, create_RealNumber as RealNumber # this is used by the preparser to wrap real literals -- very important. + Reals = RealField from sage.rings.real_double import RealDoubleField, RDF, RealDoubleElement @@ -86,24 +86,19 @@ # Algebraic numbers -from sage.rings.qqbar import (AlgebraicRealField, AA, - AlgebraicReal, - AlgebraicField, QQbar, - AlgebraicNumber, - number_field_elements_from_algebraics) +from sage.rings.qqbar import AlgebraicRealField, AA, AlgebraicReal, AlgebraicField, QQbar, AlgebraicNumber, number_field_elements_from_algebraics from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField, E # Intervals -from sage.rings.real_mpfi import (RealIntervalField, - RIF, - RealInterval) +from sage.rings.real_mpfi import RealIntervalField, RIF, RealInterval # Complex numbers from sage.rings.complex_mpfr import ComplexField from sage.rings.complex_mpfr import create_ComplexNumber as ComplexNumber + Complexes = ComplexField from sage.rings.complex_interval_field import ComplexIntervalField -from sage.rings.complex_interval import (create_ComplexIntervalFieldElement as ComplexIntervalFieldElement) +from sage.rings.complex_interval import create_ComplexIntervalFieldElement as ComplexIntervalFieldElement from sage.rings.complex_double import ComplexDoubleField, ComplexDoubleElement, CDF @@ -120,10 +115,8 @@ from sage.rings.laurent_series_ring import LaurentSeriesRing # Lazy Laurent series ring -lazy_import('sage.rings.lazy_series_ring', ['LazyLaurentSeriesRing', 'LazyPowerSeriesRing', - 'LazySymmetricFunctions', 'LazyDirichletSeriesRing']) -lazy_import('sage.rings.lazy_series_ring', 'LazyPseudoDifferentialOperatorRing', - as_="PseudoDifferentialOperatorRing") +lazy_import('sage.rings.lazy_series_ring', ['LazyLaurentSeriesRing', 'LazyPowerSeriesRing', 'LazySymmetricFunctions', 'LazyDirichletSeriesRing']) +lazy_import('sage.rings.lazy_series_ring', 'LazyPseudoDifferentialOperatorRing', as_="PseudoDifferentialOperatorRing") # Lazy combinatorial species lazy_import('sage.rings.lazy_species', 'LazyCombinatorialSpecies') @@ -142,6 +135,7 @@ # Fraction field from sage.rings.fraction_field import FractionField + Frac = FractionField # Localization @@ -163,8 +157,7 @@ from sage.rings.fast_arith import prime_range # continued fractions -from sage.rings.continued_fraction import (continued_fraction, - continued_fraction_list) +from sage.rings.continued_fraction import continued_fraction, continued_fraction_list # asymptotic ring from sage.rings.asymptotic.all import * diff --git a/src/sage/rings/asymptotic/all.py b/src/sage/rings/asymptotic/all.py index 27e4d289212..b8108a20261 100644 --- a/src/sage/rings/asymptotic/all.py +++ b/src/sage/rings/asymptotic/all.py @@ -1,5 +1,5 @@ from sage.misc.lazy_import import lazy_import + lazy_import('sage.rings.asymptotic.asymptotic_ring', 'AsymptoticRing') -lazy_import('sage.rings.asymptotic.asymptotic_expansion_generators', - 'asymptotic_expansions') +lazy_import('sage.rings.asymptotic.asymptotic_expansion_generators', 'asymptotic_expansions') del lazy_import diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 481b83c2415..c0e579b991d 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -178,18 +178,18 @@ def Stirling(var, precision=None, skip_constant_factor=False): if precision < 3: raise ValueError("precision must be at least 3") - log_Stirling = AsymptoticExpansionGenerators.log_Stirling( - var, precision=precision, skip_constant_summand=True) + log_Stirling = AsymptoticExpansionGenerators.log_Stirling(var, precision=precision, skip_constant_summand=True) - P = log_Stirling.parent().change_parameter( - growth_group='(e^({n}*log({n})))^QQ * (e^{n})^QQ * {n}^QQ * log({n})^QQ'.format(n=var)) + P = log_Stirling.parent().change_parameter(growth_group='(e^({n}*log({n})))^QQ * (e^{n})^QQ * {n}^QQ * log({n})^QQ'.format(n=var)) from sage.functions.log import exp + result = exp(P(log_Stirling)) if not skip_constant_factor: from sage.symbolic.ring import SR + SCR = SR.subring(no_variables=True) - result *= (2*SCR('pi')).sqrt() + result *= (2 * SCR('pi')).sqrt() return result @@ -276,14 +276,16 @@ def log_Stirling(var, precision=None, skip_constant_summand=False): """ if not skip_constant_summand: from sage.symbolic.ring import SR + coefficient_ring = SR.subring(no_variables=True) else: from sage.rings.rational_field import QQ + coefficient_ring = QQ from .asymptotic_ring import AsymptoticRing - A = AsymptoticRing(growth_group='{n}^ZZ * log({n})^ZZ'.format(n=var), - coefficient_ring=coefficient_ring) + + A = AsymptoticRing(growth_group='{n}^ZZ * log({n})^ZZ'.format(n=var), coefficient_ring=coefficient_ring) n = A.gen() if precision is None: @@ -298,10 +300,9 @@ def log_Stirling(var, precision=None, skip_constant_summand=False): if precision >= 3: result += log(n) / 2 if precision >= 4 and not skip_constant_summand: - result += log(2*coefficient_ring('pi')) / 2 + result += log(2 * coefficient_ring('pi')) / 2 - result += AsymptoticExpansionGenerators._log_StirlingNegativePowers_( - var, precision - 4) + result += AsymptoticExpansionGenerators._log_StirlingNegativePowers_(var, precision - 4) if precision < 1: result += (n * log(n)).O() @@ -347,8 +348,7 @@ def _log_StirlingNegativePowers_(var, precision): from .asymptotic_ring import AsymptoticRing from sage.rings.rational_field import QQ - A = AsymptoticRing(growth_group='{n}^ZZ'.format(n=var), - coefficient_ring=QQ) + A = AsymptoticRing(growth_group='{n}^ZZ'.format(n=var), coefficient_ring=QQ) if precision < 0: return A.zero() n = A.gen() @@ -356,10 +356,8 @@ def _log_StirlingNegativePowers_(var, precision): from sage.arith.misc import bernoulli from sage.arith.srange import srange - result = sum((bernoulli(k) / k / (k-1) / n**(k-1) - for k in srange(2, 2*precision + 2, 2)), - A.zero()) - return result + (1 / n**(2*precision + 1)).O() + result = sum((bernoulli(k) / k / (k - 1) / n ** (k - 1) for k in srange(2, 2 * precision + 2, 2)), A.zero()) + return result + (1 / n ** (2 * precision + 1)).O() @staticmethod def HarmonicNumber(var, precision=None, skip_constant_summand=False): @@ -425,14 +423,16 @@ def HarmonicNumber(var, precision=None, skip_constant_summand=False): """ if not skip_constant_summand: from sage.symbolic.ring import SR + coefficient_ring = SR.subring(no_variables=True) else: from sage.rings.rational_field import QQ + coefficient_ring = QQ from .asymptotic_ring import AsymptoticRing - A = AsymptoticRing(growth_group='{n}^ZZ * log({n})^ZZ'.format(n=var), - coefficient_ring=coefficient_ring) + + A = AsymptoticRing(growth_group='{n}^ZZ * log({n})^ZZ'.format(n=var), coefficient_ring=coefficient_ring) n = A.gen() if precision is None: @@ -444,13 +444,15 @@ def HarmonicNumber(var, precision=None, skip_constant_summand=False): result += log(n) if precision >= 2 and not skip_constant_summand: from sage.symbolic.constants import euler_gamma + result += coefficient_ring(euler_gamma) if precision >= 3: result += 1 / (2 * n) from sage.arith.srange import srange from sage.arith.misc import bernoulli - for k in srange(2, 2*precision - 4, 2): + + for k in srange(2, 2 * precision - 4, 2): result += -bernoulli(k) / k / n**k if precision < 1: @@ -460,7 +462,7 @@ def HarmonicNumber(var, precision=None, skip_constant_summand=False): elif precision == 2: result += (1 / n).O() else: - result += (1 / n**(2*precision - 4)).O() + result += (1 / n ** (2 * precision - 4)).O() return result @@ -553,42 +555,39 @@ def Binomial_kn_over_n(var, k, precision=None, skip_constant_factor=False): sage: set_series_precision(20) # restore series precision default """ from sage.symbolic.ring import SR + SCR = SR.subring(no_variables=True) try: SCR.coerce(k) except TypeError as e: from .misc import combine_exceptions - raise combine_exceptions( - TypeError('Cannot use k={}.'.format(k)), e) + + raise combine_exceptions(TypeError('Cannot use k={}.'.format(k)), e) if precision is None: precision = series_precision() - S = AsymptoticExpansionGenerators._log_StirlingNegativePowers_( - var, precision=max(precision - 2,0)) + S = AsymptoticExpansionGenerators._log_StirlingNegativePowers_(var, precision=max(precision - 2, 0)) n = S.parent().gen() - result = (S.subs(n=k*n) - S.subs(n=(k-1)*n) - S).exp() + result = (S.subs(n=k * n) - S.subs(n=(k - 1) * n) - S).exp() from sage.rings.rational_field import QQ - P = S.parent().change_parameter( - growth_group='(QQ_+)^{n} * {n}^QQ'.format(n=var), - coefficient_ring=QQ) + P = S.parent().change_parameter(growth_group='(QQ_+)^{n} * {n}^QQ'.format(n=var), coefficient_ring=QQ) n = P.gen() - b = k**k / (k-1)**(k-1) + b = k**k / (k - 1) ** (k - 1) if b.parent() is SR: b = SCR(b).canonicalize_radical() result *= n.rpow(b) - result *= n**(-QQ((1, 2))) + result *= n ** (-QQ((1, 2))) if not skip_constant_factor: - result *= (k/((k-1)*2*SCR('pi'))).sqrt() + result *= (k / ((k - 1) * 2 * SCR('pi'))).sqrt() return result @staticmethod - def SingularityAnalysis(var, zeta=1, alpha=0, beta=0, delta=0, - precision=None, normalized=True): + def SingularityAnalysis(var, zeta=1, alpha=0, beta=0, delta=0, precision=None, normalized=True): r""" Return the asymptotic expansion of the coefficients of a power series with specified pole and logarithmic singularity. @@ -890,8 +889,7 @@ def SingularityAnalysis(var, zeta=1, alpha=0, beta=0, delta=0, """ from itertools import islice, count from .asymptotic_ring import AsymptoticRing - from .growth_group import ExponentialGrowthGroup, \ - MonomialGrowthGroup, GenericNonGrowthGroup + from .growth_group import ExponentialGrowthGroup, MonomialGrowthGroup, GenericNonGrowthGroup from sage.arith.misc import falling_factorial from sage.categories.cartesian_product import cartesian_product from sage.functions.other import binomial @@ -904,7 +902,7 @@ def SingularityAnalysis(var, zeta=1, alpha=0, beta=0, delta=0, SCR = SR.subring(no_variables=True) s = SR.var('s') - iga = 1/gamma(alpha) + iga = 1 / gamma(alpha) if iga.parent() is SR: try: iga = SCR(iga) @@ -922,9 +920,9 @@ def inverse_gamma_derivative(shift, r): at alpha-shift. """ if r == 0: - result = iga*falling_factorial(alpha-1, shift) + result = iga * falling_factorial(alpha - 1, shift) else: - result = limit((1/gamma(s)).diff(s, r), s=alpha-shift) + result = limit((1 / gamma(s)).diff(s, r), s=alpha - shift) try: return coefficient_ring(result) @@ -949,8 +947,7 @@ def inverse_gamma_derivative(shift, r): groups = [] non_growth_groups = [] if zeta != 1: - E = ExponentialGrowthGroup.factory((~zeta).parent(), var, - return_factors=True) + E = ExponentialGrowthGroup.factory((~zeta).parent(), var, return_factors=True) for factor in E: if isinstance(factor, GenericNonGrowthGroup): non_growth_groups.append(factor) @@ -961,8 +958,7 @@ def inverse_gamma_derivative(shift, r): groups.append(MonomialGrowthGroup(beta.parent(), 'log({})'.format(var))) groups.extend(non_growth_groups) group = cartesian_product(groups) - A = AsymptoticRing(growth_group=group, coefficient_ring=coefficient_ring, - default_prec=precision) + A = AsymptoticRing(growth_group=group, coefficient_ring=coefficient_ring, default_prec=precision) n = A.gen() if zeta == 1: @@ -970,7 +966,7 @@ def inverse_gamma_derivative(shift, r): else: exponential_factor = A(n.rpow(~zeta)) - polynomial_factor = A(n**(alpha-1)) + polynomial_factor = A(n ** (alpha - 1)) if beta != 0: log_n = n.log() @@ -982,13 +978,10 @@ def inverse_gamma_derivative(shift, r): logarithmic_factor = 1 if beta in ZZ and beta >= 0: - it = ((k, r) - for k in count() - for r in srange(beta+1)) + it = ((k, r) for k in count() for r in srange(beta + 1)) k_max = precision else: - it = ((0, r) - for r in count()) + it = ((0, r) for r in count()) k_max = 0 it = reversed(list(islice(it, int(precision) + 1))) @@ -998,22 +991,18 @@ def inverse_gamma_derivative(shift, r): beta_denominator = 0 L = _sa_coefficients_lambda_(max(1, k_max), beta=beta_denominator) k, r = next(it) - result = (n**(-k) * log_n**(-r)).O() + result = (n ** (-k) * log_n ** (-r)).O() if alpha in ZZ and beta == 0: if alpha > 0 and alpha <= precision: result = A(0) elif alpha <= 0 and precision > 0: from .misc import NotImplementedOZero + raise NotImplementedOZero(A, exact_part=A.zero()) for k, r in it: - result += binomial(beta, r) * \ - sum(L[(k, ell)] * (-1)**ell * - inverse_gamma_derivative(ell, r) - for ell in srange(k, 2*k+1) - if (k, ell) in L) * \ - n**(-k) * log_n**(-r) + result += binomial(beta, r) * sum(L[(k, ell)] * (-1) ** ell * inverse_gamma_derivative(ell, r) for ell in srange(k, 2 * k + 1) if (k, ell) in L) * n ** (-k) * log_n ** (-r) result *= exponential_factor * polynomial_factor * logarithmic_factor @@ -1138,21 +1127,20 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): from sage.rings.integer_ring import ZZ from sage.rings.asymptotic.asymptotic_ring import AsymptoticRing from sage.arith.srange import srange + y, u = SR.var('y'), SR.var('u') one_half = QQ((1, 2)) - if phi(QQ.zero()).is_zero() or phi(u) == phi(0) + u*phi(u).diff(u)(u=0): + if phi(QQ.zero()).is_zero() or phi(u) == phi(0) + u * phi(u).diff(u)(u=0): raise ValueError('the function phi does not satisfy the requirements') if tau is None: tau = _fundamental_constant_implicit_function_(phi=phi) def H(y): - return tau/phi(tau) - y/phi(y) + return tau / phi(tau) - y / phi(y) - A = AsymptoticRing(growth_group='{Z}^QQ'.format(Z=var), - coefficient_ring=SR, - default_prec=precision) + A = AsymptoticRing(growth_group='{Z}^QQ'.format(Z=var), coefficient_ring=SR, default_prec=precision) if precision is None: precision = ZZ(A.default_prec) Z = A.gen() @@ -1161,25 +1149,21 @@ def ansatz(prec=precision): if prec < 1: return A.one().O() if prec == 1: - return ((1/Z)**one_half).O() - return (-(2*tau/phi(tau)/H(y).diff(y, 2)(y=tau)).sqrt() * (1/Z)**one_half - + sum(SR("d{}".format(j)) * (1/Z)**(j * one_half) for j in srange(2, prec)) - + ((1/Z)**(prec * one_half)).O()) + return ((1 / Z) ** one_half).O() + return -(2 * tau / phi(tau) / H(y).diff(y, 2)(y=tau)).sqrt() * (1 / Z) ** one_half + sum(SR("d{}".format(j)) * (1 / Z) ** (j * one_half) for j in srange(2, prec)) + ((1 / Z) ** (prec * one_half)).O() # we compare coefficients between a "single" Z and the # following expansion, this allows us to compute the constants d_j z = SR.var('z') - z_expansion = sum(H(z).diff(z, k)(z=tau)/k.factorial() * - ansatz(prec=precision+2-k)**k - for k in srange(2, precision)) + ((1/Z)**(precision * one_half)).O() + z_expansion = sum(H(z).diff(z, k)(z=tau) / k.factorial() * ansatz(prec=precision + 2 - k) ** k for k in srange(2, precision)) + ((1 / Z) ** (precision * one_half)).O() solution_dict = dict() - for k in srange(2, precision-1): - coef = z_expansion.monomial_coefficient((1/Z)**((k+1) * one_half)) + for k in srange(2, precision - 1): + coef = z_expansion.monomial_coefficient((1 / Z) ** ((k + 1) * one_half)) current_var = SR.var('d{k}'.format(k=k)) solution_dict[current_var] = coef.subs(solution_dict).simplify_rational().solve(current_var)[0].rhs() - return A(tau) + ansatz(prec=precision-1).map_coefficients(lambda term: term.subs(solution_dict).simplify_rational()) + return A(tau) + ansatz(prec=precision - 1).map_coefficients(lambda term: term.subs(solution_dict).simplify_rational()) @staticmethod @experimental(20050) @@ -1258,13 +1242,11 @@ def ImplicitExpansionPeriodicPart(var, phi, period, tau=None, precision=None): tau = _fundamental_constant_implicit_function_(phi=phi) tau_p = tau**period - aperiodic_expansion = asymptotic_expansions.ImplicitExpansion(var, - phi=lambda u: phi(u**(1/period))**period, - tau=tau_p, precision=precision) + aperiodic_expansion = asymptotic_expansions.ImplicitExpansion(var, phi=lambda u: phi(u ** (1 / period)) ** period, tau=tau_p, precision=precision) rho = tau / phi(tau) Z = aperiodic_expansion.parent().gen() - return 1/rho * (aperiodic_expansion/(1 - 1/Z))**(1/period) + return 1 / rho * (aperiodic_expansion / (1 - 1 / Z)) ** (1 / period) @staticmethod def InverseFunctionAnalysis(var, phi, tau=None, period=1, precision=None): @@ -1370,14 +1352,12 @@ def InverseFunctionAnalysis(var, phi, tau=None, period=1, precision=None): rho = tau / phi(tau) if period == 1: - expansion = asymptotic_expansions.ImplicitExpansion(var=var, phi=phi, - tau=tau, precision=precision) + expansion = asymptotic_expansions.ImplicitExpansion(var=var, phi=phi, tau=tau, precision=precision) return expansion._singularity_analysis_(var, zeta=rho, precision=precision) - expansion = asymptotic_expansions.ImplicitExpansionPeriodicPart(var=var, phi=phi, - period=period, tau=tau, precision=precision) + expansion = asymptotic_expansions.ImplicitExpansionPeriodicPart(var=var, phi=phi, period=period, tau=tau, precision=precision) growth = expansion._singularity_analysis_(var, zeta=rho**period, precision=precision) n = growth.parent().gen() - return growth.subs({n: (n-1)/period}) + return growth.subs({n: (n - 1) / period}) def _fundamental_constant_implicit_function_(phi): @@ -1410,9 +1390,9 @@ def _fundamental_constant_implicit_function_(phi): 1/2*sqrt(2) """ from sage.symbolic.ring import SR + u = SR.var('u') - positive_solution = [s for s in (phi(u) - u*phi(u).diff(u)).solve(u) - if s.rhs() > 0] + positive_solution = [s for s in (phi(u) - u * phi(u).diff(u)).solve(u) if s.rhs() > 0] if len(positive_solution) == 1: return positive_solution[0].rhs() raise ValueError('fundamental constant tau could not be determined') @@ -1467,10 +1447,8 @@ def _sa_coefficients_lambda_(K, beta=0): v = V.gen() t = LazyPowerSeriesRing(V, names='t').gen() - S = (t - (1 + 1/v + beta) * (1 + v*t).log()).exp() - return {(k + L.valuation(), ell): c - for ell, L in enumerate(S[:2 * K - 1]) - for k, c in enumerate(L.list())} + S = (t - (1 + 1 / v + beta) * (1 + v * t).log()).exp() + return {(k + L.valuation(), ell): c for ell, L in enumerate(S[: 2 * K - 1]) for k, c in enumerate(L.list())} # Easy access to the asymptotic expansions generators from the command line: diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index ea96228c56d..95f638ca11f 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -562,6 +562,7 @@ class AsymptoticExpansion(CommutativeAlgebraElement): :doc:`term_monoid`, :mod:`~sage.data_structures.mutable_poset`. """ + def __init__(self, parent, summands, simplify=True, convert=True): r""" See :class:`AsymptoticExpansion` for more information. @@ -678,9 +679,9 @@ def __init__(self, parent, summands, simplify=True, convert=True): super().__init__(parent=parent) from sage.data_structures.mutable_poset import MutablePoset + if not isinstance(summands, MutablePoset): - raise TypeError('Summands %s are not in a mutable poset as expected ' - 'when creating an element of %s.' % (summands, parent)) + raise TypeError('Summands %s are not in a mutable poset as expected ' 'when creating an element of %s.' % (summands, parent)) if convert: from .misc import combine_exceptions @@ -693,9 +694,8 @@ def convert_terms(element): except ZeroCoefficientError: return None except (ValueError, TypeError) as e: - raise combine_exceptions( - ValueError('Cannot include %s with parent %s in %s' % - (element, element.parent(), parent)), e) + raise combine_exceptions(ValueError('Cannot include %s with parent %s in %s' % (element, element.parent(), parent)), e) + new_summands = summands.copy() new_summands.map(convert_terms, topological=True, reverse=True) self._summands_ = new_summands @@ -870,13 +870,13 @@ def has_same_summands(self, other) -> bool: if other is None: return False from sage.structure.element import have_same_parent + if have_same_parent(self, other): return self._has_same_summands_(other) from sage.structure.element import get_coercion_model - return get_coercion_model().bin_op(self, other, - lambda self, other: - self._has_same_summands_(other)) + + return get_coercion_model().bin_op(self, other, lambda self, other: self._has_same_summands_(other)) def _has_same_summands_(self, other) -> bool: r""" @@ -904,9 +904,7 @@ def _has_same_summands_(self, other) -> bool: """ if len(self.summands) != len(other.summands): return False - return all(s == o for s, o in - zip(self.summands.elements_topological(), - other.summands.elements_topological())) + return all(s == o for s, o in zip(self.summands.elements_topological(), other.summands.elements_topological())) def _simplify_(self): r""" @@ -963,12 +961,11 @@ def _repr_(self, latex=False): """ if latex: from sage.misc.latex import latex as latex_repr + f = latex_repr else: f = repr - s = ' + '.join(f(elem) for elem in - self.summands.elements_topological(reverse=True, - key=repr)) + s = ' + '.join(f(elem) for elem in self.summands.elements_topological(reverse=True, key=repr)) s = s.replace('+ -', '- ') if not s: return '0' @@ -1012,6 +1009,7 @@ def show(self): zeta(3)*(e^x)^(-1/2)*x^42 """ from sage.repl.rich_output.pretty_print import pretty_print + pretty_print(self) def monomial_coefficient(self, monomial): @@ -1128,8 +1126,7 @@ def _add_(self, other): sage: O(x) + x O(x) """ - return self.parent()(self.summands.union(other.summands), - simplify=True, convert=False) + return self.parent()(self.summands.union(other.summands), simplify=True, convert=False) def _sub_(self, other): r""" @@ -1181,8 +1178,7 @@ def _mul_term_(self, term): O(x^3) """ simplify = not term.is_exact() - return self.parent()(self.summands.mapped(lambda element: term * element), - simplify=simplify, convert=False) + return self.parent()(self.summands.mapped(lambda element: term * element), simplify=simplify, convert=False) def _mul_(self, other): r""" @@ -1217,9 +1213,7 @@ def _mul_(self, other): sage: _.parent() Asymptotic Ring over Integer Ring """ - return sum(iter(self._mul_term_(term_other) for - term_other in other.summands.elements()), - self.parent().zero()) + return sum(iter(self._mul_term_(term_other) for term_other in other.summands.elements()), self.parent().zero()) def _lmul_(self, other): r""" @@ -1341,20 +1335,15 @@ def __invert__(self, precision=None): are several maximal elements s, t. """ if not self.summands: - raise ZeroDivisionError( - 'Cannot invert {} in {}.'.format(self, self.parent())) + raise ZeroDivisionError('Cannot invert {} in {}.'.format(self, self.parent())) (imax_elem, x) = self._main_term_relative_error_(return_inverse_main_term=True) one = x.parent().one() if x: import itertools - result = AsymptoticExpansion._power_series_( - coefficients=itertools.repeat(one), - start=one, - ratio=-x, - ratio_start=one, - precision=precision) + + result = AsymptoticExpansion._power_series_(coefficients=itertools.repeat(one), start=one, ratio=-x, ratio_start=one, precision=precision) else: result = one @@ -1408,6 +1397,7 @@ def convert_terms(element): return element T = self.parent().term_monoid('O') return T(element) + convert_terms.count = 0 summands.map(convert_terms, topological=True, reverse=True) return self.parent()(summands, simplify=True, convert=False) @@ -1456,10 +1446,7 @@ def error_part(self): O(x) + O(y) """ parent = self.parent() - return sum((parent(term) - for term in self.summands.elements_topological() - if not term.is_exact()), - parent.zero()) + return sum((parent(term) for term in self.summands.elements_topological() if not term.is_exact()), parent.zero()) def __pow__(self, exponent, precision=None): r""" @@ -1598,6 +1585,7 @@ def __pow__(self, exponent, precision=None): w^(1.414213562373095?) """ from .misc import strip_symbolic + exponent = strip_symbolic(exponent) if not self.summands: @@ -1606,11 +1594,9 @@ def __pow__(self, exponent, precision=None): if exponent > 0: return self.parent().zero() if exponent < 0: - raise ZeroDivisionError('Cannot take %s to the negative exponent %s.' % - (self, exponent)) + raise ZeroDivisionError('Cannot take %s to the negative exponent %s.' % (self, exponent)) else: - raise NotImplementedError('Taking %s to the exponent %s not implemented.' % - (self, exponent)) + raise NotImplementedError('Taking %s to the exponent %s not implemented.' % (self, exponent)) elif exponent == 0: return self.parent().one() @@ -1624,13 +1610,13 @@ def __pow__(self, exponent, precision=None): return exponent.rpow(base=element.coefficient, precision=precision) try: - return self.parent()._create_element_in_extension_( - element ** exponent, element.parent()) + return self.parent()._create_element_in_extension_(element**exponent, element.parent()) except (ArithmeticError, TypeError, ValueError): if not isinstance(exponent, AsymptoticExpansion): raise from sage.rings.integer_ring import ZZ + try: exponent = ZZ(exponent) except (TypeError, ValueError): @@ -1639,6 +1625,7 @@ def __pow__(self, exponent, precision=None): return super().__pow__(exponent) from sage.rings.rational_field import QQ + try: exponent = QQ(exponent) except (TypeError, ValueError): @@ -1647,13 +1634,13 @@ def __pow__(self, exponent, precision=None): return self.__pow_number__(exponent, precision=precision) from sage.structure.element import Expression + if isinstance(exponent, Expression) and exponent.is_constant(): return self.__pow_number__(exponent, precision=precision) if isinstance(exponent, AsymptoticExpansion) and len(self.summands) != 1: try: - return self.__pow_number__(exponent, precision=precision, - check_convergence=True) + return self.__pow_number__(exponent, precision=precision, check_convergence=True) except NoConvergenceError: pass @@ -1661,8 +1648,8 @@ def __pow__(self, exponent, precision=None): return (exponent * self.log(precision=precision)).exp(precision=precision) except (TypeError, ValueError, ZeroDivisionError) as e: from .misc import combine_exceptions - raise combine_exceptions( - ValueError('Cannot take %s to the exponent %s.' % (self, exponent)), e) + + raise combine_exceptions(ValueError('Cannot take %s to the exponent %s.' % (self, exponent)), e) pow = __pow__ @@ -1765,18 +1752,13 @@ def __pow_number__(self, exponent, precision=None, check_convergence=False): if exponent.is_zero(): return self.parent().one() if exponent < 0: - raise ZeroDivisionError( - 'Cannot take {} to the negative ' - 'exponent {}.'.format(self, exponent)) + raise ZeroDivisionError('Cannot take {} to the negative ' 'exponent {}.'.format(self, exponent)) else: - raise ValueError( - 'Possible division by zero, since sign of the exponent ' - '{} cannot be determined.'.format(exponent)) + raise ValueError('Possible division by zero, since sign of the exponent ' '{} cannot be determined.'.format(exponent)) elif len(self.summands) == 1: element = next(self.summands.elements()) - return self.parent()._create_element_in_extension_( - element**exponent, element.parent()) + return self.parent()._create_element_in_extension_(element**exponent, element.parent()) try: (max_elem, x) = self._main_term_relative_error_() @@ -1789,7 +1771,7 @@ def __pow_number__(self, exponent, precision=None, check_convergence=False): if not (x * exponent).is_little_o_of_one(): raise NoConvergenceError - pmax = self.parent()(max_elem)**exponent + pmax = self.parent()(max_elem) ** exponent import itertools @@ -1807,12 +1789,7 @@ def binomials(a): one = x.parent().one() - result = AsymptoticExpansion._power_series_( - coefficients=binomials(exponent), - start=one, - ratio=x, - ratio_start=one, - precision=precision) + result = AsymptoticExpansion._power_series_(coefficients=binomials(exponent), start=one, ratio=x, ratio_start=one, precision=precision) return result * pmax @@ -1849,6 +1826,7 @@ def sqrt(self, precision=None): True """ from sage.rings.rational_field import QQ + return self.pow(QQ((1, 2)), precision=precision) def O(self): @@ -1886,9 +1864,9 @@ def O(self): """ if not self.summands: from .misc import NotImplementedOZero + raise NotImplementedOZero(self.parent(), exact_part=self.parent().zero()) - return sum(self.parent().create_summand('O', growth=element) - for element in self.summands.maximal_elements()) + return sum(self.parent().create_summand('O', growth=element) for element in self.summands.maximal_elements()) def log(self, base=None, precision=None, locals=None): r""" @@ -1996,9 +1974,7 @@ def log(self, base=None, precision=None, locals=None): if self.is_one(): return P.zero() element = next(self.summands.elements()) - return sum(P._create_element_in_extension_(l, element.parent()) - for l in element.log_term(base=base, - locals=locals)) + return sum(P._create_element_in_extension_(l, element.parent()) for l in element.log_term(base=base, locals=locals)) (max_elem, x) = self._main_term_relative_error_() geom = -x @@ -2006,13 +1982,7 @@ def log(self, base=None, precision=None, locals=None): from sage.rings.integer_ring import ZZ import itertools - result = - AsymptoticExpansion._power_series_( - coefficients=iter(1 / ZZ(k) - for k in itertools.count(2)), - start=geom, - ratio=geom, - ratio_start=geom, - precision=precision) + result = -AsymptoticExpansion._power_series_(coefficients=iter(1 / ZZ(k) for k in itertools.count(2)), start=geom, ratio=geom, ratio_start=geom, precision=precision) if base: result = result / log(base) @@ -2150,16 +2120,11 @@ def rpow(self, base, precision=None, locals=None): # next: try to take the exponential function of the large elements try: - large_result = P.prod( - P._create_element_in_extension_(term.rpow(base), - term.parent()) - for term in large_terms) + large_result = P.prod(P._create_element_in_extension_(term.rpow(base), term.parent()) for term in large_terms) except (TypeError, ValueError) as e: from .misc import combine_exceptions - raise combine_exceptions( - ValueError('Cannot construct the power of %s to the ' - 'exponent %s in %s.' % - (base, self, self.parent())), e) + + raise combine_exceptions(ValueError('Cannot construct the power of %s to the ' 'exponent %s in %s.' % (base, self, self.parent())), e) # then: expand expr_o @@ -2182,12 +2147,7 @@ def inverted_factorials(): f /= ZZ(k) yield f - result = AsymptoticExpansion._power_series_( - coefficients=inverted_factorials(), - start=P.one(), - ratio=geom, - ratio_start=P.one(), - precision=precision) + result = AsymptoticExpansion._power_series_(coefficients=inverted_factorials(), start=P.one(), ratio=geom, ratio_start=P.one(), precision=precision) return result * large_result @@ -2242,21 +2202,17 @@ def _main_term_relative_error_(self, return_inverse_main_term=False): max_elem = tuple(self.summands.maximal_elements()) if len(max_elem) != 1: - raise ValueError('Cannot determine main term of {} since there ' - 'are several maximal elements {}.'.format( - self, ', '.join(str(e) for e in - sorted(max_elem, key=str)))) + raise ValueError('Cannot determine main term of {} since there ' 'are several maximal elements {}.'.format(self, ', '.join(str(e) for e in sorted(max_elem, key=str)))) max_elem = max_elem[0] imax_elem = ~max_elem if imax_elem.parent() is max_elem.parent(): new_self = self else: - new_self = self.parent()._create_element_in_extension_( - imax_elem, max_elem.parent()).parent()(self) + new_self = self.parent()._create_element_in_extension_(imax_elem, max_elem.parent()).parent()(self) one = new_self.parent().one() - x = - one + new_self._mul_term_(imax_elem) + x = -one + new_self._mul_term_(imax_elem) if return_inverse_main_term: return (imax_elem, x) @@ -2565,23 +2521,16 @@ def subs(self, rules=None, domain=None, **kwds): if isinstance(rules, dict): for k, v in rules.items(): if not isinstance(k, str) and k not in gens: - raise TypeError('Cannot substitute %s in %s ' - 'since it is neither an ' - 'asymptotic expansion ' - 'nor a string (but a %s).' % - (k, self, type(k))) + raise TypeError('Cannot substitute %s in %s ' 'since it is neither an ' 'asymptotic expansion ' 'nor a string (but a %s).' % (k, self, type(k))) k = str(k) if k in locals and locals[k] != v: - raise ValueError('Cannot substitute in %s: ' - 'duplicate key %s.' % (self, k)) + raise ValueError('Cannot substitute in %s: ' 'duplicate key %s.' % (self, k)) locals[k] = v elif rules is not None: - raise TypeError('Substitution rules %s have to be a dictionary.' % - (rules,)) + raise TypeError('Substitution rules %s have to be a dictionary.' % (rules,)) # fill up missing rules - gens_str = tuple(str(g) - for g in self.parent().growth_group.gens_monomial()) + gens_str = tuple(str(g) for g in self.parent().growth_group.gens_monomial()) for sg, g in zip(gens_str, gens): locals.setdefault(sg, g) @@ -2589,13 +2538,10 @@ def subs(self, rules=None, domain=None, **kwds): for k in locals: sk = str(k) if sk not in gens_str and not sk.startswith('_'): - raise ValueError('Cannot substitute %s in %s ' - 'since it is not a generator of %s.' % - (k, self, self.parent())) + raise ValueError('Cannot substitute %s in %s ' 'since it is not a generator of %s.' % (k, self, self.parent())) # determine 0 and 1 - if domain is None and \ - ('_zero_' not in locals or '_one_' not in locals): + if domain is None and ('_zero_' not in locals or '_one_' not in locals): P = self.parent() for sg in gens_str: G = locals[sg].parent() @@ -2612,16 +2558,9 @@ def subs(self, rules=None, domain=None, **kwds): return self._substitute_(locals) except (ArithmeticError, TypeError, ValueError) as e: from .misc import combine_exceptions - rules = '{' + ', '.join( - '%s: %s' % (k, v) - for k, v in sorted(locals.items(), - key=lambda k: str(k[0])) - if not k.startswith('_') and - not any(k == sg and v is g for sg, g in zip(gens_str, gens)) - ) + '}' - raise combine_exceptions( - TypeError('Cannot apply the substitution rules %s on %s ' - 'in %s.' % (rules, self, self.parent())), e) + + rules = '{' + ', '.join('%s: %s' % (k, v) for k, v in sorted(locals.items(), key=lambda k: str(k[0])) if not k.startswith('_') and not any(k == sg and v is g for sg, g in zip(gens_str, gens))) + '}' + raise combine_exceptions(TypeError('Cannot apply the substitution rules %s on %s ' 'in %s.' % (rules, self, self.parent())), e) def _substitute_(self, rules): r""" @@ -2661,16 +2600,15 @@ def _substitute_(self, rules): if not self.summands: return rules['_zero_'] from sage.symbolic.operators import add_vararg + try: - return add_vararg( - *tuple(s._substitute_(rules) - for s in self.summands.elements_topological())) + return add_vararg(*tuple(s._substitute_(rules) for s in self.summands.elements_topological())) except (ArithmeticError, TypeError, ValueError) as e: from .misc import substitute_raise_exception + substitute_raise_exception(self, e) - def compare_with_values(self, variable, function, values, - rescaled=True, ring=RIF): + def compare_with_values(self, variable, function, values, rescaled=True, ring=RIF): """ Compute the (rescaled) difference between this asymptotic expansion and the given values. @@ -2791,14 +2729,15 @@ def compare_with_values(self, variable, function, values, expr = function vars = expr.variables() if len(vars) > 1: - raise NotImplementedError("expression {} has more than one " - "variable".format(expr)) + raise NotImplementedError("expression {} has more than one " "variable".format(expr)) elif len(vars) == 1: v = vars[0] def function(arg): return expr.subs({v: arg}) + else: + def function(arg): return expr @@ -2816,18 +2755,13 @@ def function(arg): else: raise NotImplementedError(f"unsupported error term: {error}") error_growth = error_terms[0].growth - points = [(k, ring((main.subs({variable: k}) - function(k)) / - (error_coeff * error_growth._substitute_( - {str(variable): k, '_one_': ZZ.one()})))) - for k in values] + points = [(k, ring((main.subs({variable: k}) - function(k)) / (error_coeff * error_growth._substitute_({str(variable): k, '_one_': ZZ.one()})))) for k in values] else: - points = [(k, ring(main.subs({variable: k}) - function(k))) - for k in values] + points = [(k, ring(main.subs({variable: k}) - function(k))) for k in values] return points - def plot_comparison(self, variable, function, values, rescaled=True, - ring=RIF, relative_tolerance=0.025, **kwargs): + def plot_comparison(self, variable, function, values, rescaled=True, ring=RIF, relative_tolerance=0.025, **kwargs): r""" Plot the (rescaled) difference between this asymptotic expansion and the given values. @@ -2906,13 +2840,12 @@ def plot_comparison(self, variable, function, values, rescaled=True, Graphics object consisting of 1 graphics primitive """ from sage.plot.plot import list_plot - points = self.compare_with_values(variable, function, - values, rescaled=rescaled, ring=ring) + + points = self.compare_with_values(variable, function, values, rescaled=rescaled, ring=ring) if isinstance(ring, sage.rings.abc.RealIntervalField): if not all(p[1].relative_diameter() <= relative_tolerance for p in points): - raise ValueError('Numerical noise is too high, the ' - 'comparison is inaccurate') + raise ValueError('Numerical noise is too high, the ' 'comparison is inaccurate') # RIFs cannot be plotted, they need to be converted to RR # (see #15011). @@ -2966,11 +2899,10 @@ def symbolic_expression(self, R=None): """ if R is None: from sage.symbolic.ring import SR + R = SR - return self.substitute({g: R(R.var(str(g))) - for g in self.parent().gens()}, - domain=R) + return self.substitute({g: R(R.var(str(g))) for g in self.parent().gens()}, domain=R) _symbolic_ = symbolic_expression # will be used by SR._element_constructor_ @@ -3010,9 +2942,9 @@ def map_coefficients(self, f, new_coefficient_ring=None): Exact Term Monoid n^ZZ with coefficients in Integer Ring. > *previous* TypeError: no conversion of this rational to integer """ + def mapping(term): - T = term.parent().change_parameter( - coefficient_ring=new_coefficient_ring) + T = term.parent().change_parameter(coefficient_ring=new_coefficient_ring) if hasattr(term, 'coefficient'): c = f(term.coefficient) if c.is_zero(): @@ -3105,23 +3037,20 @@ def factorial(self): return self.parent().one() assert len(self.summands) == 1 element = next(self.summands.elements()) - return self.parent()._create_element_in_extension_( - element._factorial_(), element.parent()) + return self.parent()._create_element_in_extension_(element._factorial_(), element.parent()) if len(vars) == 1: - from .asymptotic_expansion_generators import \ - asymptotic_expansions + from .asymptotic_expansion_generators import asymptotic_expansions + var = vars[0] - S = asymptotic_expansions.Stirling( - var, precision=self.parent().default_prec) + S = asymptotic_expansions.Stirling(var, precision=self.parent().default_prec) from sage.structure.element import get_coercion_model + cm = get_coercion_model() P = cm.common_parent(self, S) return S.subs({var: P.coerce(self)}) - raise ValueError( - 'Cannot build the factorial of {} since it is not ' - 'univariate.'.format(self)) + raise ValueError('Cannot build the factorial of {} since it is not ' 'univariate.'.format(self)) def variable_names(self): r""" @@ -3149,10 +3078,9 @@ def variable_names(self): sage: (2^m + m^4).variable_names() ('m',) """ - vars = sorted(sum(iter(s.variable_names() - for s in self.summands), - tuple())) + vars = sorted(sum(iter(s.variable_names() for s in self.summands), tuple())) from itertools import groupby + return tuple(v for v, _ in groupby(vars)) def _singularity_analysis_(self, var, zeta, precision=None): @@ -3217,6 +3145,7 @@ def _singularity_analysis_(self, var, zeta, precision=None): The error term O(0) means 0 for sufficiently large n. """ from .misc import NotImplementedOZero + OZeroEncountered = False if precision is None: @@ -3225,17 +3154,14 @@ def _singularity_analysis_(self, var, zeta, precision=None): result = 0 for s in self.summands: try: - contribution = s._singularity_analysis_( - var=var, zeta=zeta, - precision=precision) + contribution = s._singularity_analysis_(var=var, zeta=zeta, precision=precision) except NotImplementedOZero as ozero: OZeroEncountered = True result += ozero.exact_part else: result += contribution - if OZeroEncountered and (isinstance(result, int) and result == 0 - or result.is_exact()): + if OZeroEncountered and (isinstance(result, int) and result == 0 or result.is_exact()): raise NotImplementedOZero(var=var, exact_part=result) return result @@ -3267,16 +3193,11 @@ def limit(self): :meth:`is_little_o_of_one` """ - non_o_one_terms = [term for term in self.summands - if not term.is_little_o_of_one()] + non_o_one_terms = [term for term in self.summands if not term.is_little_o_of_one()] if not non_o_one_terms: return self.parent().base_ring()(0) - if ( - len(non_o_one_terms) == 1 - and non_o_one_terms[0].growth.is_one() - and non_o_one_terms[0].is_exact() - ): + if len(non_o_one_terms) == 1 and non_o_one_terms[0].growth.is_one() and non_o_one_terms[0].is_exact(): return non_o_one_terms[0].coefficient raise ValueError(f"Cannot determine limit of {self}") @@ -3322,9 +3243,9 @@ def B(self, valid_from=0): """ if not self.summands: from .misc import NotImplementedBZero + raise NotImplementedBZero(self.parent(), exact_part=self.parent().zero()) - return sum(self.parent().create_summand('B', growth=element, valid_from=valid_from) - for element in self.summands.elements()) + return sum(self.parent().create_summand('B', growth=element, valid_from=valid_from) for element in self.summands.elements()) class AsymptoticRing(Parent, UniqueRepresentation, WithLocals): @@ -3454,10 +3375,7 @@ class AsymptoticRing(Parent, UniqueRepresentation, WithLocals): Element = AsymptoticExpansion @staticmethod - def __classcall__(cls, growth_group=None, coefficient_ring=None, - names=None, category=None, default_prec=None, - term_monoid_factory=None, - locals=None): + def __classcall__(cls, growth_group=None, coefficient_ring=None, names=None, category=None, default_prec=None, term_monoid_factory=None, locals=None): r""" Normalize the input in order to ensure a unique representation of the parent. @@ -3553,6 +3471,7 @@ def __classcall__(cls, growth_group=None, coefficient_ring=None, if isinstance(growth_group, str): from .growth_group import GrowthGroup + growth_group = GrowthGroup(growth_group) if growth_group is None: @@ -3567,18 +3486,18 @@ def __classcall__(cls, growth_group=None, coefficient_ring=None, def format_names(N): return ('s ' if len(N) != 1 else ' ') + ', '.join("'%s'" % n for n in N) + if names and not strgens: - raise ValueError('%s does not provide any generators but name%s given.' % - (growth_group, format_names(names))) + raise ValueError('%s does not provide any generators but name%s given.' % (growth_group, format_names(names))) elif names is not None and len(names) == 1 and len(strgens) == 1: pass elif names is not None and names != strgens: - raise ValueError('Name%s do not coincide with generator%s of %s.' % - (format_names(names), format_names(strgens), growth_group)) + raise ValueError('Name%s do not coincide with generator%s of %s.' % (format_names(names), format_names(strgens), growth_group)) if category is None: from sage.categories.commutative_algebras import CommutativeAlgebras from sage.categories.rings import Rings + category = CommutativeAlgebras(Rings()) if default_prec is None: @@ -3586,20 +3505,15 @@ def format_names(N): if term_monoid_factory is None: from .term_monoid import DefaultTermMonoidFactory + term_monoid_factory = DefaultTermMonoidFactory if locals is not None: locals = cls._convert_locals_(locals) - return super().__classcall__(cls, growth_group, coefficient_ring, - category=category, - default_prec=default_prec, - term_monoid_factory=term_monoid_factory, - locals=locals) + return super().__classcall__(cls, growth_group, coefficient_ring, category=category, default_prec=default_prec, term_monoid_factory=term_monoid_factory, locals=locals) - def __init__(self, growth_group, coefficient_ring, - category, default_prec, - term_monoid_factory, locals): + def __init__(self, growth_group, coefficient_ring, category, default_prec, term_monoid_factory, locals): r""" See :class:`AsymptoticRing` for more information. @@ -3624,8 +3538,7 @@ def __init__(self, growth_group, coefficient_ring, self._default_prec_ = default_prec self._term_monoid_factory_ = term_monoid_factory self._locals_ = locals - super().__init__(base=coefficient_ring, - category=category) + super().__init__(base=coefficient_ring, category=category) @property def growth_group(self): @@ -3752,8 +3665,7 @@ def change_parameter(self, **kwds): sage: A.change_parameter(coefficient_ring=None) is A True """ - parameters = ('growth_group', 'coefficient_ring', 'default_prec', - 'term_monoid_factory') + parameters = ('growth_group', 'coefficient_ring', 'default_prec', 'term_monoid_factory') values = {} category = self.category() values['category'] = category @@ -3766,9 +3678,9 @@ def change_parameter(self, **kwds): values[parameter] = default if isinstance(values['growth_group'], str): from .growth_group import GrowthGroup + values['growth_group'] = GrowthGroup(values['growth_group']) - if all(values[parameter] is getattr(self, parameter) - for parameter in parameters) and values['category'] is category and values['locals'] is locals: + if all(values[parameter] is getattr(self, parameter) for parameter in parameters) and values['category'] is category and values['locals'] is locals: return self return self._underlying_class()(**values) @@ -3787,9 +3699,8 @@ def _create_empty_summands_(): """ from sage.data_structures.mutable_poset import MutablePoset from .term_monoid import can_absorb, absorption - return MutablePoset(key=lambda element: element.growth, - can_merge=can_absorb, - merge=absorption) + + return MutablePoset(key=lambda element: element.growth, can_merge=can_absorb, merge=absorption) def _create_element_in_extension_(self, term, old_term_parent=None): r""" @@ -3830,9 +3741,7 @@ def _create_element_in_extension_(self, term, old_term_parent=None): else: # Insert an 'if' here once terms can have different # coefficient rings, as this will be for L-terms. - parent = self.change_parameter( - growth_group=term.parent().growth_group, - coefficient_ring=term.parent().coefficient_ring) + parent = self.change_parameter(growth_group=term.parent().growth_group, coefficient_ring=term.parent().coefficient_ring) return parent(term, simplify=False, convert=False) def _element_constructor_(self, data, simplify=True, convert=True): @@ -3956,6 +3865,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): (in Integer Ring) nor growth (in Growth Group m^ZZ). """ from sage.data_structures.mutable_poset import MutablePoset + if isinstance(data, MutablePoset): return self.element_class(self, data, simplify=simplify, convert=convert) @@ -3963,27 +3873,23 @@ def _element_constructor_(self, data, simplify=True, convert=True): return data if isinstance(data, AsymptoticExpansion): - return self.element_class(self, data.summands, - simplify=simplify, convert=convert) + return self.element_class(self, data.summands, simplify=simplify, convert=convert) from .term_monoid import GenericTerm + if isinstance(data, GenericTerm): data = (data,) if isinstance(data, (list, tuple)): if not all(isinstance(elem, GenericTerm) for elem in data): - raise TypeError('Not all list entries of %s ' - 'are asymptotic terms, so cannot create an ' - 'asymptotic expansion in %s.' % (data, self)) + raise TypeError('Not all list entries of %s ' 'are asymptotic terms, so cannot create an ' 'asymptotic expansion in %s.' % (data, self)) summands = AsymptoticRing._create_empty_summands_() summands.union_update(data) - return self.element_class(self, summands, - simplify=simplify, convert=convert) + return self.element_class(self, summands, simplify=simplify, convert=convert) if not data: summands = AsymptoticRing._create_empty_summands_() - return self.element_class(self, summands, - simplify=simplify, convert=False) + return self.element_class(self, summands, simplify=simplify, convert=False) try: P = data.parent() @@ -3994,6 +3900,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): if isinstance(P, SymbolicRing): from sage.symbolic.operators import add_vararg + if data.operator() == add_vararg: summands = [] for summand in data.operands(): @@ -4002,53 +3909,39 @@ def _element_constructor_(self, data, simplify=True, convert=True): try: summands.append(self.create_summand('exact', summand)) except ValueError as e: - raise combine_exceptions( - ValueError('Symbolic expression %s is not in %s.' % - (data, self)), e) + raise combine_exceptions(ValueError('Symbolic expression %s is not in %s.' % (data, self)), e) return sum(summands, self.zero()) elif isinstance(P, PolynomialRing_generic): p = P.gen() try: - return sum(iter(self.create_summand('exact', growth=p**i, - coefficient=c) - for i, c in enumerate(data)), - self.zero()) + return sum(iter(self.create_summand('exact', growth=p**i, coefficient=c) for i, c in enumerate(data)), self.zero()) except ValueError as e: - raise combine_exceptions( - ValueError('Polynomial %s is not in %s' % (data, self)), e) + raise combine_exceptions(ValueError('Polynomial %s is not in %s' % (data, self)), e) elif isinstance(P, MPolynomialRing_base): try: - return sum(iter(self.create_summand('exact', growth=g, coefficient=c) - for c, g in iter(data)), - self.zero()) + return sum(iter(self.create_summand('exact', growth=g, coefficient=c) for c, g in iter(data)), self.zero()) except ValueError as e: - raise combine_exceptions( - ValueError('Polynomial %s is not in %s' % (data, self)), e) + raise combine_exceptions(ValueError('Polynomial %s is not in %s' % (data, self)), e) elif isinstance(P, (PowerSeriesRing_generic, LazyPowerSeriesRing)): - raise NotImplementedError( - 'cannot convert %s from the %s to an asymptotic expansion ' - 'in %s, since growths at other points than +oo are not yet ' - 'supported' % (data, P, self)) + raise NotImplementedError('cannot convert %s from the %s to an asymptotic expansion ' 'in %s, since growths at other points than +oo are not yet ' 'supported' % (data, P, self)) # Delete lines above as soon as we can deal with growths # other than the that at going to +oo. from sage.rings.infinity import PlusInfinity + p = P.gen() try: result = self(data.polynomial()) except ValueError as e: - raise combine_exceptions( - ValueError('Powerseries %s is not in %s' % (data, self)), e) + raise combine_exceptions(ValueError('Powerseries %s is not in %s' % (data, self)), e) prec = data.precision_absolute() if prec < PlusInfinity(): try: result += self.create_summand('O', growth=p**prec) except ValueError as e: - raise combine_exceptions( - ValueError('Powerseries %s is not in %s' % - (data, self)), e) + raise combine_exceptions(ValueError('Powerseries %s is not in %s' % (data, self)), e) return result return self.create_summand('exact', data) @@ -4093,6 +3986,7 @@ def _coerce_map_from_(self, R): True """ from sage.data_structures.mutable_poset import MutablePoset + if R == MutablePoset: return if self.coefficient_ring.has_coerce_map_from(R): @@ -4100,8 +3994,7 @@ def _coerce_map_from_(self, R): if self.growth_group.has_coerce_map_from(R): return True if isinstance(R, AsymptoticRing): - if self.growth_group.has_coerce_map_from(R.growth_group) and \ - self.coefficient_ring.has_coerce_map_from(R.coefficient_ring): + if self.growth_group.has_coerce_map_from(R.growth_group) and self.coefficient_ring.has_coerce_map_from(R.coefficient_ring): return True def _repr_(self) -> str: @@ -4140,8 +4033,7 @@ def _an_element_(self): """ E = self.term_monoid('exact') O = self.term_monoid('O') - return self(E.an_element(), simplify=False, convert=False)**3 + \ - self(O.an_element(), simplify=False, convert=False) + return self(E.an_element(), simplify=False, convert=False) ** 3 + self(O.an_element(), simplify=False, convert=False) def some_elements(self): r""" @@ -4168,12 +4060,10 @@ def some_elements(self): z^(3/2) + O(z^(-2))) """ from sage.misc.mrange import cantor_product + E = self.term_monoid('exact') O = self.term_monoid('O') - return iter(self(e, simplify=False, convert=False)**3 + - self(o, simplify=False, convert=False) - for e, o in cantor_product(E.some_elements(), - O.some_elements())) + return iter(self(e, simplify=False, convert=False) ** 3 + self(o, simplify=False, convert=False) for e, o in cantor_product(E.some_elements(), O.some_elements())) def gens(self) -> tuple: r""" @@ -4198,10 +4088,7 @@ def gens(self) -> tuple: sage: B.gens() (y, z) """ - return tuple(self.create_summand('exact', - growth=g, - coefficient=self.coefficient_ring(1)) - for g in self.growth_group.gens_monomial()) + return tuple(self.create_summand('exact', growth=g, coefficient=self.coefficient_ring(1)) for g in self.growth_group.gens_monomial()) def gen(self, n=0): r""" @@ -4235,9 +4122,7 @@ def ngens(self): """ return len(self.growth_group.gens_monomial()) - def coefficients_of_generating_function(self, function, singularities, precision=None, - return_singular_expansions=False, - error_term=None): + def coefficients_of_generating_function(self, function, singularities, precision=None, return_singular_expansions=False, error_term=None): r""" Return the asymptotic growth of the coefficients of some generating function by means of Singularity Analysis. @@ -4354,8 +4239,7 @@ def coefficients_of_generating_function(self, function, singularities, precision OZeroEncountered = False - A = AsymptoticRing('T^QQ * log(T)^QQ', coefficient_ring=SR, - default_prec=precision) + A = AsymptoticRing('T^QQ * log(T)^QQ', coefficient_ring=SR, default_prec=precision) T = A.gen() if error_term is None: @@ -4367,9 +4251,7 @@ def coefficients_of_generating_function(self, function, singularities, precision singular_expansions[singularity] = singular_expansion try: - contribution = singular_expansion._singularity_analysis_( - var='Z', zeta=singularity, - precision=precision).subs(Z=self.gen()) + contribution = singular_expansion._singularity_analysis_(var='Z', zeta=singularity, precision=precision).subs(Z=self.gen()) except NotImplementedOZero as ozero: OZeroEncountered = True result += ozero.exact_part.subs(Z=self.gen()) @@ -4381,12 +4263,9 @@ def coefficients_of_generating_function(self, function, singularities, precision if return_singular_expansions: from collections import namedtuple - SingularityAnalysisResult = namedtuple( - 'SingularityAnalysisResult', - ['asymptotic_expansion', 'singular_expansions']) - return SingularityAnalysisResult( - asymptotic_expansion=result, - singular_expansions=singular_expansions) + + SingularityAnalysisResult = namedtuple('SingularityAnalysisResult', ['asymptotic_expansion', 'singular_expansions']) + return SingularityAnalysisResult(asymptotic_expansion=result, singular_expansions=singular_expansions) return result def create_summand(self, type, data=None, **kwds): @@ -4464,6 +4343,7 @@ def create_summand(self, type, data=None, **kwds): no 'coefficient' specified. """ from .term_monoid import ZeroCoefficientError + TM = self.term_monoid(type) if data is None: @@ -4472,8 +4352,7 @@ def create_summand(self, type, data=None, **kwds): except KeyError: raise TypeError("Neither 'data' nor 'growth' are specified.") if type == 'exact' and kwds.get('coefficient') is None: - raise TypeError("Cannot create exact term: only 'growth' " - "but no 'coefficient' specified.") + raise TypeError("Cannot create exact term: only 'growth' " "but no 'coefficient' specified.") try: return self(TM(data, **kwds), simplify=False, convert=False) @@ -4527,11 +4406,7 @@ def construction(self): sage: A.construction()[0].cls """ - return (AsymptoticRingFunctor(self.growth_group, - default_prec=self.default_prec, - category=self.category(), - cls=self._underlying_class()), - self.coefficient_ring) + return (AsymptoticRingFunctor(self.growth_group, default_prec=self.default_prec, category=self.category(), cls=self._underlying_class()), self.coefficient_ring) @staticmethod def B(expression, valid_from=0): @@ -4607,10 +4482,7 @@ class AsymptoticRingFunctor(ConstructionFunctor): rank = 13 - def __init__(self, growth_group, - default_prec=None, category=None, - term_monoid_factory=None, locals=None, - cls=None): + def __init__(self, growth_group, default_prec=None, category=None, term_monoid_factory=None, locals=None, cls=None): r""" See :class:`AsymptoticRingFunctor` for details. @@ -4632,6 +4504,7 @@ def __init__(self, growth_group, self._locals_ = locals from sage.categories.commutative_rings import CommutativeRings + super().__init__(CommutativeRings(), CommutativeRings()) def _repr_(self) -> str: @@ -4654,8 +4527,7 @@ def _repr_(self) -> str: sage: A.construction() (MyAsymptoticRing, Rational Field) """ - return '{}<{}>'.format(self.cls.__name__, - self.growth_group._repr_(condense=True)) + return '{}<{}>'.format(self.cls.__name__, self.growth_group._repr_(condense=True)) def _apply_functor(self, coefficient_ring): r""" @@ -4697,10 +4569,8 @@ def _apply_functor(self, coefficient_ring): sage: 1/(QQ(1)+n) n^(-1) - n^(-2) + n^(-3) + O(n^(-4)) """ - kwds = {'growth_group': self.growth_group, - 'coefficient_ring': coefficient_ring} - parameters = ('category', 'default_prec', - 'term_monoid_factory', 'locals') + kwds = {'growth_group': self.growth_group, 'coefficient_ring': coefficient_ring} + parameters = ('category', 'default_prec', 'term_monoid_factory', 'locals') for parameter in parameters: value = getattr(self, '_{}_'.format(parameter)) if value is not None: @@ -4769,24 +4639,22 @@ def merge(self, other): if isinstance(other, AsymptoticRingFunctor) and self.cls == other.cls: from sage.structure.element import get_coercion_model + cm = get_coercion_model() try: G = cm.common_parent(self.growth_group, other.growth_group) except TypeError: pass else: - if (self._default_prec_ is None - and other._default_prec_ is None): + if self._default_prec_ is None and other._default_prec_ is None: default_prec = None elif self._default_prec_ is None: default_prec = other._default_prec_ elif other._default_prec_ is None: default_prec = self._default_prec_ else: - default_prec = min(self._default_prec_, - other._default_prec_) - if (self._category_ is None - and other._category_ is None): + default_prec = min(self._default_prec_, other._default_prec_) + if self._category_ is None and other._category_ is None: category = None elif self._category_ is None: category = other._category_ @@ -4795,11 +4663,7 @@ def merge(self, other): else: category = self._category_ | other._category_ - return AsymptoticRingFunctor( - G, - default_prec=default_prec, - category=category, - cls=self.cls) + return AsymptoticRingFunctor(G, default_prec=default_prec, category=category, cls=self.cls) def __eq__(self, other) -> bool: r""" @@ -4822,11 +4686,7 @@ def __eq__(self, other) -> bool: sage: F_X == F_Y False """ - return (type(self) is type(other) - and self.growth_group == other.growth_group - and self._default_prec_ == other._default_prec_ - and self._category_ == other._category_ - and self.cls == other.cls) + return type(self) is type(other) and self.growth_group == other.growth_group and self._default_prec_ == other._default_prec_ and self._category_ == other._category_ and self.cls == other.cls def __ne__(self, other) -> bool: r""" diff --git a/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py b/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py index 94a054d601a..7f4d1f7bca2 100644 --- a/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +++ b/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py @@ -185,6 +185,7 @@ Classes and Methods =================== """ + # **************************************************************************** # Copyright (C) 2008 Alexander Raichev # Copyright (C) 2014, 2016 Daniel Krenn @@ -342,9 +343,9 @@ def __init__(self, parent, numerator, denominator_factored, reduce=True): super().__init__(parent) from sage.rings.semirings.non_negative_integer_semiring import NN + self._numerator = parent._numerator_ring(numerator) - self._denominator_factored = [(parent._denominator_ring(d), NN(n)) - for d, n in denominator_factored] + self._denominator_factored = [(parent._denominator_ring(d), NN(n)) for d, n in denominator_factored] R = self.denominator_ring if numerator in R and reduce: @@ -405,7 +406,7 @@ def denominator(self): x^3*y^2 + 2*x^3*y + x^2*y^2 + x^3 - 2*x^2*y - x*y^2 - 3*x^2 - 2*x*y - y^2 + 3*x + 2*y - 1 """ - return prod(q ** e for q, e in self.denominator_factored()) + return prod(q**e for q, e in self.denominator_factored()) def denominator_factored(self): r""" @@ -503,6 +504,7 @@ def dimension(self): """ from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base + R = self.denominator_ring if isinstance(R, (PolynomialRing_generic, MPolynomialRing_base)): return R.ngens() @@ -630,8 +632,7 @@ def _eq_(self, other): 'FractionWithFactoredDenominatorRing_with_category.element_class' object has no attribute '_lt_' """ - return (self.numerator() * other.denominator() == - other.numerator() * self.denominator()) + return self.numerator() * other.denominator() == other.numerator() * self.denominator() def _total_order_key_(self): r""" @@ -669,9 +670,7 @@ def _total_order_key_(self): sage: bool(h._total_order_key_() < i._total_order_key_()) False """ - return (len(self.denominator_factored()), - self.denominator(), - self.numerator()) + return (len(self.denominator_factored()), self.denominator(), self.numerator()) def univariate_decomposition(self): r""" @@ -856,7 +855,7 @@ def nullstellensatz_certificate(self): """ R = self.denominator_ring df = self.denominator_factored() - J = R.ideal([q ** e for q, e in df]) + J = R.ideal([q**e for q, e in df]) if R.one() in J: return R.one().lift(J) return None @@ -932,9 +931,7 @@ def nullstellensatz_decomposition(self): p = self.numerator() df = self.denominator_factored() m = len(df) - iteration1 = FractionWithFactoredDenominatorSum( - [self.parent()(p * L[i], [df[j] for j in range(m) if j != i]) - for i in range(m) if L[i] != 0]) + iteration1 = FractionWithFactoredDenominatorSum([self.parent()(p * L[i], [df[j] for j in range(m) if j != i]) for i in range(m) if L[i] != 0]) # Now decompose each FFPD of iteration1. for r in iteration1: @@ -1006,7 +1003,7 @@ def algebraic_dependence_certificate(self): R = self.denominator_ring df = self.denominator_factored() if not df: - return R.ideal() # The zero ideal. + return R.ideal() # The zero ideal. m = len(df) F = R.base_ring() Xs = list(R.gens()) @@ -1025,12 +1022,11 @@ def algebraic_dependence_certificate(self): Vs = [str(x) for x in Xs] + Ss + Ts RR = PolynomialRing(F, Vs) Xs = RR.gens()[:d] - Ss = RR.gens()[d: d + m] - Ts = RR.gens()[d + m: d + 2 * m] + Ss = RR.gens()[d : d + m] + Ts = RR.gens()[d + m : d + 2 * m] # Compute the appropriate elimination ideal. - J = RR.ideal([Ss[j] - RR(df[j][0]) for j in range(m)] + - [Ss[j] ** df[j][1] - Ts[j] for j in range(m)]) + J = RR.ideal([Ss[j] - RR(df[j][0]) for j in range(m)] + [Ss[j] ** df[j][1] - Ts[j] for j in range(m)]) J = J.elimination_ideal(Xs + Ss) # Coerce J into the polynomial ring in the indeterminates Ts[m:]. @@ -1118,7 +1114,7 @@ def algebraic_dependence_decomposition(self, whole_and_parts=True): p = self.numerator() df = self.denominator_factored() m = len(df) - g = J.gens()[0] # An annihilating polynomial for df. + g = J.gens()[0] # An annihilating polynomial for df. new_vars = J.ring().gens() # Note that each new_vars[j] corresponds to df[j] such that # g([q**e for q, e in df]) = 0. @@ -1128,13 +1124,12 @@ def algebraic_dependence_decomposition(self, whole_and_parts=True): # each with < m distinct denominator factors. gg = (g.lt() - g) / (g.lc()) numers = map(prod, zip(gg.coefficients(), gg.monomials())) - e = list(g.lt().exponents())[0: m] + e = list(g.lt().exponents())[0:m] denoms = [(new_vars[j], e[0][j] + 1) for j in range(m)] # Write r in terms of new_vars, # cancel factors in the denominator, and combine like terms. FFPD = FractionWithFactoredDenominatorRing(J.ring()) - iteration1_temp = FractionWithFactoredDenominatorSum( - [FFPD(a, denoms) for a in numers])._combine_like_terms_() + iteration1_temp = FractionWithFactoredDenominatorSum([FFPD(a, denoms) for a in numers])._combine_like_terms_() # Substitute in df. qpowsub = {new_vars[j]: df[j][0] ** df[j][1] for j in range(m)} iteration1 = FractionWithFactoredDenominatorSum() @@ -1339,8 +1334,7 @@ def cohomology_decomposition(self): Par = self.parent() # Compute Jacobian determinants for qs. - dets = [R(jacobian(qs, x).determinant()) - for x in var_sets_n] + dets = [R(jacobian(qs, x).determinant()) for x in var_sets_n] # Get a Nullstellensatz certificate for qs and dets. if self.dimension() == 1: @@ -1381,9 +1375,7 @@ def cohomology_decomposition(self): if L[n + k] == 0: continue # Compute Jacobian in the Symbolic Ring. - jac = jacobian([SR(p * L[n + k])] + - [SR(qs[j]) for j in range(n) if j != J], - [SR(xx) for xx in x]) + jac = jacobian([SR(p * L[n + k])] + [SR(qs[j]) for j in range(n) if j != J], [SR(xx) for xx in x]) det = jac.determinant() # The parity epsilon from [AY1983, eq. (17.11)] does not # enter this computation, since we do not order the @@ -1465,27 +1457,22 @@ def asymptotic_decomposition(self, alpha, asy_var=None): # Cauchy differential form generated by each element of decomp. if asy_var is None: asy_var = var('r') - cauchy_stuff = prod([X[j] ** (-alpha[j] * asy_var - 1) - for j in range(d)]) + cauchy_stuff = prod([X[j] ** (-alpha[j] * asy_var - 1) for j in range(d)]) decomp2 = FractionWithFactoredDenominatorSum() for f in decomp1: - ff = self.parent()(f.numerator() * cauchy_stuff, - f.denominator_factored()) + ff = self.parent()(f.numerator() * cauchy_stuff, f.denominator_factored()) decomp2.extend(ff.cohomology_decomposition()) decomp2 = decomp2._combine_like_terms_() # Divide out cauchy_stuff from integrands. decomp3 = FractionWithFactoredDenominatorSum() for f in decomp2: - ff = self.parent()((f.numerator() / - cauchy_stuff).simplify_full().collect(asy_var), - f.denominator_factored()) + ff = self.parent()((f.numerator() / cauchy_stuff).simplify_full().collect(asy_var), f.denominator_factored()) decomp3.append(ff) return decomp3 - def asymptotics(self, p, alpha, N, asy_var=None, numerical=0, - verbose=False): + def asymptotics(self, p, alpha, N, asy_var=None, numerical=0, verbose=False): r""" Return the asymptotics in the given direction. @@ -1610,7 +1597,7 @@ def asymptotics(self, p, alpha, N, asy_var=None, numerical=0, X = list(R.gens()) alpha = list(alpha) df = self.denominator_factored() - n = len(df) # Number of smooth factors + n = len(df) # Number of smooth factors # Find greatest i such that X[i] is a convenient coordinate, # that is, such that for all (h, e) in df, we have @@ -1623,15 +1610,12 @@ def asymptotics(self, p, alpha, N, asy_var=None, numerical=0, if n == 1: # Smooth point. - return self.asymptotics_smooth(p, alpha, N, asy_var, coordinate, - numerical, verbose=verbose) + return self.asymptotics_smooth(p, alpha, N, asy_var, coordinate, numerical, verbose=verbose) # Multiple point. - return self.asymptotics_multiple(p, alpha, N, asy_var, coordinate, - numerical, verbose=verbose) + return self.asymptotics_multiple(p, alpha, N, asy_var, coordinate, numerical, verbose=verbose) - def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, - numerical=0, verbose=False): + def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, numerical=0, verbose=False): r""" Return the asymptotics in the given direction of a smooth point. @@ -1757,13 +1741,12 @@ def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, # I'll just past the code from the multiple point case. if d == 1: det = jacobian(H, X).subs(p).determinant().abs() - exp_scale = prod([(p[X[i]] ** (-alpha[i])).subs(p) - for i in range(d)]) + exp_scale = prod([(p[X[i]] ** (-alpha[i])).subs(p) for i in range(d)]) subexp_part = -G.subs(p) / (det * prod(p.values())) if numerical: exp_scale = exp_scale.n(digits=numerical) subexp_part = subexp_part.n(digits=numerical) - return (exp_scale ** asy_var * subexp_part, exp_scale, subexp_part) + return (exp_scale**asy_var * subexp_part, exp_scale, subexp_part) # If p is a tuple of rationals, then compute with it directly. # Otherwise, compute symbolically and plug in p at the end. @@ -1778,7 +1761,7 @@ def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, if verbose: print("Creating auxiliary functions...") # Implicit functions. - h = function('h')(*tuple(X[:d - 1])) + h = function('h')(*tuple(X[: d - 1])) U = function('U')(*tuple(X)) # All other functions are defined in terms of h, U, and # explicit functions. @@ -1792,9 +1775,7 @@ def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, e = {X[i]: P[X[i]] * exp(I * T[i]) for i in range(d - 1)} ht = h.subs(e) At = A.subs(e) - Phit = (-log(P[X[d - 1]] * ht) + - I * sum([alpha[i] / alpha[d - 1] * T[i] - for i in range(d - 1)])) + Phit = -log(P[X[d - 1]] * ht) + I * sum([alpha[i] / alpha[d - 1] * T[i] for i in range(d - 1)]) Tstar = {t: ZZ.zero() for t in T} # Store h and U and all their derivatives evaluated at P. atP = P.copy() @@ -1804,13 +1785,12 @@ def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, # and store in atP. # Keep a copy of unevaluated h derivatives for use in the case # d = 2 and v > 2 below. - hderivs1 = {} # First derivatives of h. + hderivs1 = {} # First derivatives of h. for i in range(d - 1): - s = solve(diff(H.subs({X[d - 1]: ZZ.one() / h}), X[i]), - diff(h, X[i]))[0].rhs().simplify() + s = solve(diff(H.subs({X[d - 1]: ZZ.one() / h}), X[i]), diff(h, X[i]))[0].rhs().simplify() hderivs1.update({diff(h, X[i]): s}) atP.update({diff(h, X[i]).subs(P): s.subs(P).subs(atP)}) - hderivs = diff_all(h, X[0: d - 1], 2 * N, sub=hderivs1, rekey=h) + hderivs = diff_all(h, X[0 : d - 1], 2 * N, sub=hderivs1, rekey=h) for k in hderivs: atP.update({k.subs(P): hderivs[k].subs(atP)}) @@ -1837,8 +1817,7 @@ def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, Uderivs[diff(U, list(s)).subs(P)] = ZZ.zero() elif k > 0 and k < 2 * N: all_zero = True - Uderivs = diff_prod(Hderivs, U, Hcheck, X, - range(1, k + 1), end, Uderivs, atP) + Uderivs = diff_prod(Hderivs, U, Hcheck, X, range(1, k + 1), end, Uderivs, atP) # Check for a nonzero U derivative. if any(Uderivs.values()): all_zero = False @@ -1850,11 +1829,9 @@ def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, Uderivs.update({diff(U, list(s)).subs(P): ZZ.zero()}) else: # Have to compute the rest of the derivatives. - Uderivs = diff_prod(Hderivs, U, Hcheck, X, - range(k + 1, 2 * N + 1), end, Uderivs, atP) + Uderivs = diff_prod(Hderivs, U, Hcheck, X, range(k + 1, 2 * N + 1), end, Uderivs, atP) else: - Uderivs = diff_prod(Hderivs, U, Hcheck, X, - range(1, 2 * N + 1), end, Uderivs, atP) + Uderivs = diff_prod(Hderivs, U, Hcheck, X, range(1, 2 * N + 1), end, Uderivs, atP) atP.update(Uderivs) # In general, this algorithm is not designed to handle the case of a @@ -1870,18 +1847,15 @@ def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, v += 1 if v > 2 * N: # Then need to compute more derivatives of h for atP. - hderivs.update({diff(h, X[0], v): - diff(hderivs[diff(h, X[0], v - 1)], - X[0]).subs(hderivs1)}) - atP.update({diff(h, X[0], v).subs(P): - hderivs[diff(h, X[0], v)].subs(atP)}) + hderivs.update({diff(h, X[0], v): diff(hderivs[diff(h, X[0], v - 1)], X[0]).subs(hderivs1)}) + atP.update({diff(h, X[0], v).subs(P): hderivs[diff(h, X[0], v)].subs(atP)}) Phitderiv = diff(Phitderiv, T[0]) splat = Phitderiv.subs(Tstar).subs(atP).subs(p).simplify() if d == 2 and v > 2: t = T[0] # Simplify variable names. a = splat / factorial(v) - Phitu = Phit - a * t ** v + Phitu = Phit - a * t**v # Compute all partial derivatives of At and Phitu # up to orders 2*(N - 1) and 2*(N - 1) + v, respectively, @@ -1896,17 +1870,11 @@ def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, AA = function('AA')(t) BB = function('BB')(t) if v.mod(2) == 0: - At_derivs = diff_all(At, T, 2 * N - 2, sub=hderivs1, - sub_final=[Tstar, atP], rekey=AA) - Phitu_derivs = diff_all(Phitu, T, 2 * N - 2 + v, - sub=hderivs1, sub_final=[Tstar, atP], - zero_order=v + 1, rekey=BB) + At_derivs = diff_all(At, T, 2 * N - 2, sub=hderivs1, sub_final=[Tstar, atP], rekey=AA) + Phitu_derivs = diff_all(Phitu, T, 2 * N - 2 + v, sub=hderivs1, sub_final=[Tstar, atP], zero_order=v + 1, rekey=BB) else: - At_derivs = diff_all(At, T, N - 1, sub=hderivs1, - sub_final=[Tstar, atP], rekey=AA) - Phitu_derivs = diff_all(Phitu, T, N - 1 + v, - sub=hderivs1, sub_final=[Tstar, atP], - zero_order=v + 1, rekey=BB) + At_derivs = diff_all(At, T, N - 1, sub=hderivs1, sub_final=[Tstar, atP], rekey=AA) + Phitu_derivs = diff_all(Phitu, T, N - 1 + v, sub=hderivs1, sub_final=[Tstar, atP], zero_order=v + 1, rekey=BB) AABB_derivs = At_derivs AABB_derivs.update(Phitu_derivs) AABB_derivs[AA] = At.subs(Tstar).subs(atP) @@ -1919,26 +1887,13 @@ def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, L = [] if v.mod(2) == 0: for k in range(N): - L.append(sum([(-1) ** l * gamma((2 * k + v * l + 1) / v) / - (factorial(l) * factorial(2 * k + v * l)) * - DD[(k, l)] for l in range(2 * k + 1)])) - chunk = (a ** (-1 / v) / (pi * v) * - sum([alpha[d - 1] ** (-(2 * k + 1) / v) * - L[k] * asy_var ** (-(2 * k + 1) / v) - for k in range(N)])) + L.append(sum([(-1) ** l * gamma((2 * k + v * l + 1) / v) / (factorial(l) * factorial(2 * k + v * l)) * DD[(k, l)] for l in range(2 * k + 1)])) + chunk = a ** (-1 / v) / (pi * v) * sum([alpha[d - 1] ** (-(2 * k + 1) / v) * L[k] * asy_var ** (-(2 * k + 1) / v) for k in range(N)]) else: zeta = exp(I * pi / (2 * v)) for k in range(N): - L.append(sum([(-1) ** l * gamma((k + v * l + 1) / v) / - (factorial(l) * factorial(k + v * l)) * - (zeta ** (k + v * l + 1) + - (-1) ** (k + v * l) * - zeta ** (-(k + v * l + 1))) * - DD[(k, l)] for l in range(k + 1)])) - chunk = (abs(a) ** (-1 / v) / (2 * pi * v) * - sum([alpha[d - 1] ** (-(k + 1) / v) * - L[k] * asy_var ** (-(k + 1) / v) - for k in range(N)])) + L.append(sum([(-1) ** l * gamma((k + v * l + 1) / v) / (factorial(l) * factorial(k + v * l)) * (zeta ** (k + v * l + 1) + (-1) ** (k + v * l) * zeta ** (-(k + v * l + 1))) * DD[(k, l)] for l in range(k + 1)])) + chunk = abs(a) ** (-1 / v) / (2 * pi * v) * sum([alpha[d - 1] ** (-(k + 1) / v) * L[k] * asy_var ** (-(k + 1) / v) for k in range(N)]) # Asymptotics for d >= 2 case. # A singular Phit''(Tstar) will cause a crash in this case. @@ -1946,8 +1901,7 @@ def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, Phit1 = jacobian(Phit, T).subs(hderivs1) a = jacobian(Phit1, T).subs(hderivs1).subs(Tstar).subs(atP) a_inv = a.inverse() - Phitu = (Phit - (1 / QQ(2)) * matrix([T]) * - a * matrix([T]).transpose()) + Phitu = Phit - (1 / QQ(2)) * matrix([T]) * a * matrix([T]).transpose() Phitu = Phitu[0][0] # Compute all partial derivatives of At and Phitu up to # orders 2 * N-2 and 2 * N, respectively. @@ -1962,11 +1916,9 @@ def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, if verbose: print("Computing derivatives of more auxiliary functions...") AA = function('AA')(*tuple(T)) - At_derivs = diff_all(At, T, 2 * N - 2, sub=hderivs1, - sub_final=[Tstar, atP], rekey=AA) + At_derivs = diff_all(At, T, 2 * N - 2, sub=hderivs1, sub_final=[Tstar, atP], rekey=AA) BB = function('BB')(*tuple(T)) - Phitu_derivs = diff_all(Phitu, T, 2 * N, sub=hderivs1, - sub_final=[Tstar, atP], rekey=BB, zero_order=3) + Phitu_derivs = diff_all(Phitu, T, 2 * N, sub=hderivs1, sub_final=[Tstar, atP], rekey=BB, zero_order=3) AABB_derivs = At_derivs AABB_derivs.update(Phitu_derivs) AABB_derivs[AA] = At.subs(Tstar).subs(atP) @@ -1978,34 +1930,22 @@ def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, # Plug above into asymptotic formula. L = [] for k in range(N): - L.append(sum([DD[(0, k, l)] / ((-1) ** k * 2 ** (l + k) * - factorial(l) * factorial(l + k)) - for l in range(2 * k + 1)])) - chunk = sum([(2 * pi) ** ((1 - d) / Integer(2)) * - a.determinant() ** (-ZZ.one() / Integer(2)) * - alpha[d - 1] ** ((ZZ.one() - d) / Integer(2) - k) * - L[k] * - asy_var ** ((ZZ.one() - d) / Integer(2) - k) - for k in range(N)]) + L.append(sum([DD[(0, k, l)] / ((-1) ** k * 2 ** (l + k) * factorial(l) * factorial(l + k)) for l in range(2 * k + 1)])) + chunk = sum([(2 * pi) ** ((1 - d) / Integer(2)) * a.determinant() ** (-ZZ.one() / Integer(2)) * alpha[d - 1] ** ((ZZ.one() - d) / Integer(2) - k) * L[k] * asy_var ** ((ZZ.one() - d) / Integer(2) - k) for k in range(N)]) chunk = chunk.subs(p).simplify() coeffs = chunk.coefficients(asy_var) coeffs.reverse() coeffs = coeffs[:N] if numerical: - subexp_part = sum([co[0].subs(p).n(digits=numerical) * - asy_var ** co[1] for co in coeffs]) - exp_scale = prod([(P[X[i]] ** (-alpha[i])).subs(p) - for i in range(d)]).n(digits=numerical) + subexp_part = sum([co[0].subs(p).n(digits=numerical) * asy_var ** co[1] for co in coeffs]) + exp_scale = prod([(P[X[i]] ** (-alpha[i])).subs(p) for i in range(d)]).n(digits=numerical) else: - subexp_part = sum([co[0].subs(p) * asy_var ** co[1] - for co in coeffs]) - exp_scale = prod([(P[X[i]] ** (-alpha[i])).subs(p) - for i in range(d)]) - return (exp_scale ** asy_var * subexp_part, exp_scale, subexp_part) - - def asymptotics_multiple(self, p, alpha, N, asy_var, coordinate=None, - numerical=0, verbose=False): + subexp_part = sum([co[0].subs(p) * asy_var ** co[1] for co in coeffs]) + exp_scale = prod([(P[X[i]] ** (-alpha[i])).subs(p) for i in range(d)]) + return (exp_scale**asy_var * subexp_part, exp_scale, subexp_part) + + def asymptotics_multiple(self, p, alpha, N, asy_var, coordinate=None, numerical=0, verbose=False): r""" Return the asymptotics in the given direction of a multiple point nondegenerate for ``alpha``. @@ -2139,13 +2079,12 @@ def asymptotics_multiple(self, p, alpha, N, asy_var, coordinate=None, # Case n = d. if n == d: det = jacobian(H, X).subs(P).determinant().abs() - exp_scale = prod([(P[X[i]] ** (-alpha[i])).subs(P) - for i in range(d)]) + exp_scale = prod([(P[X[i]] ** (-alpha[i])).subs(P) for i in range(d)]) subexp_part = G.subs(P) / (det * prod(P.values())) if numerical: exp_scale = exp_scale.n(digits=numerical) subexp_part = subexp_part.n(digits=numerical) - return (exp_scale ** asy_var * subexp_part, exp_scale, subexp_part) + return (exp_scale**asy_var * subexp_part, exp_scale, subexp_part) # Case n < d. # If P is a tuple of rationals, then compute with it directly. @@ -2172,35 +2111,29 @@ def asymptotics_multiple(self, p, alpha, N, asy_var, coordinate=None, thetastar = {t: ZZ.zero() for t in T} thetastar.update(Sstar) # Create implicit functions. - h = [function('h' + str(j))(*tuple(X[:d - 1])) for j in range(n)] + h = [function('h' + str(j))(*tuple(X[: d - 1])) for j in range(n)] U = function('U')(*tuple(X)) # All other functions are defined in terms of h, U, and # explicit functions. Hcheck = prod([X[d - 1] - ZZ.one() / h[j] for j in range(n)]) Gcheck = -G / U * prod([-h[j] / X[d - 1] for j in range(n)]) - A = [(-1) ** (n - 1) * X[d - 1] ** (-n + j) * - diff(Gcheck.subs({X[d - 1]: ZZ.one() / X[d - 1]}), X[d - 1], j) - for j in range(n)] + A = [(-1) ** (n - 1) * X[d - 1] ** (-n + j) * diff(Gcheck.subs({X[d - 1]: ZZ.one() / X[d - 1]}), X[d - 1], j) for j in range(n)] e = {X[i]: P[X[i]] * exp(I * T[i]) for i in range(d - 1)} ht = [hh.subs(e) for hh in h] - hsumt = (sum([S[j] * ht[j] for j in range(n - 1)]) + - (ZZ.one() - sum(S)) * ht[n - 1]) + hsumt = sum([S[j] * ht[j] for j in range(n - 1)]) + (ZZ.one() - sum(S)) * ht[n - 1] At = [AA.subs(e).subs({X[d - 1]: hsumt}) for AA in A] - Phit = (-log(P[X[d - 1]] * hsumt) + - I * sum([alpha[i] / alpha[d - 1] * T[i] - for i in range(d - 1)])) + Phit = -log(P[X[d - 1]] * hsumt) + I * sum([alpha[i] / alpha[d - 1] * T[i] for i in range(d - 1)]) # atP Stores h and U and all their derivatives evaluated at C. atP = P.copy() atP.update({hh.subs(P): ZZ.one() / P[X[d - 1]] for hh in h}) # Compute the derivatives of h up to order 2 * N and evaluate at P. - hderivs1 = {} # First derivatives of h. - for (i, j) in xmrange([d - 1, n], tuple): - s = solve(diff(H[j].subs({X[d - 1]: ZZ.one() / h[j]}), X[i]), - diff(h[j], X[i]))[0].rhs().simplify() + hderivs1 = {} # First derivatives of h. + for i, j in xmrange([d - 1, n], tuple): + s = solve(diff(H[j].subs({X[d - 1]: ZZ.one() / h[j]}), X[i]), diff(h[j], X[i]))[0].rhs().simplify() hderivs1.update({diff(h[j], X[i]): s}) atP.update({diff(h[j], X[i]).subs(P): s.subs(P).subs(atP)}) - hderivs = diff_all(h, X[0:d - 1], 2 * N, sub=hderivs1, rekey=h) + hderivs = diff_all(h, X[0 : d - 1], 2 * N, sub=hderivs1, rekey=h) for k in hderivs: atP.update({k.subs(P): hderivs[k].subs(atP)}) @@ -2225,8 +2158,7 @@ def asymptotics_multiple(self, p, alpha, N, asy_var, coordinate=None, Uderivs[diff(U, list(s)).subs(P)] = ZZ.zero() elif k > 0 and k < 2 * N - 2 + m - 1: all_zero = True - Uderivs = diff_prod(Hprodderivs, U, Hcheck, X, - range(1, k + 1), end, Uderivs, atP) + Uderivs = diff_prod(Hprodderivs, U, Hcheck, X, range(1, k + 1), end, Uderivs, atP) # Check for a nonzero U derivative. if any(Uderivs.values()): all_zero = False @@ -2237,18 +2169,14 @@ def asymptotics_multiple(self, p, alpha, N, asy_var, coordinate=None, Uderivs.update({diff(U, list(s)).subs(P): ZZ.zero()}) else: # Have to compute the rest of the derivatives. - Uderivs = diff_prod(Hprodderivs, U, Hcheck, X, - range(k + 1, 2 * N - 2 + m), end, - Uderivs, atP) + Uderivs = diff_prod(Hprodderivs, U, Hcheck, X, range(k + 1, 2 * N - 2 + m), end, Uderivs, atP) else: - Uderivs = diff_prod(Hprodderivs, U, Hcheck, X, - range(1, 2 * N - 2 + m), end, Uderivs, atP) + Uderivs = diff_prod(Hprodderivs, U, Hcheck, X, range(1, 2 * N - 2 + m), end, Uderivs, atP) atP.update(Uderivs) Phit1 = jacobian(Phit, T + S).subs(hderivs1) a = jacobian(Phit1, T + S).subs(hderivs1).subs(thetastar).subs(atP) a_inv = a.inverse() - Phitu = (Phit - (1 / Integer(2)) * matrix([T + S]) * a * - matrix([T + S]).transpose()) + Phitu = Phit - (1 / Integer(2)) * matrix([T + S]) * a * matrix([T + S]).transpose() Phitu = Phitu[0][0] # Compute all partial derivatives of At and Phitu up to orders 2 * N - 2 @@ -2262,11 +2190,9 @@ def asymptotics_multiple(self, p, alpha, N, asy_var, coordinate=None, if verbose: print("Computing derivatives of more auxiliary functions...") AA = [function('A' + str(j))(*tuple(T + S)) for j in range(n)] - At_derivs = diff_all(At, T + S, 2 * N - 2, sub=hderivs1, - sub_final=[thetastar, atP], rekey=AA) + At_derivs = diff_all(At, T + S, 2 * N - 2, sub=hderivs1, sub_final=[thetastar, atP], rekey=AA) BB = function('BB')(*tuple(T + S)) - Phitu_derivs = diff_all(Phitu, T + S, 2 * N, sub=hderivs1, - sub_final=[thetastar, atP], rekey=BB, zero_order=3) + Phitu_derivs = diff_all(Phitu, T + S, 2 * N, sub=hderivs1, sub_final=[thetastar, atP], rekey=BB, zero_order=3) AABB_derivs = At_derivs AABB_derivs.update(Phitu_derivs) for j in range(n): @@ -2277,40 +2203,22 @@ def asymptotics_multiple(self, p, alpha, N, asy_var, coordinate=None, print("Computing second-order differential operator actions...") DD = diff_op(AA, BB, AABB_derivs, T + S, a_inv, n, N) L = {} - for (j, k) in product(range(min(n, N)), range(max(0, N - 1 - n), N)): + for j, k in product(range(min(n, N)), range(max(0, N - 1 - n), N)): if j + k <= N - 1: - L[(j, k)] = sum([DD[(j, k, l)] / ((-1) ** k * 2 ** (k + l) * - factorial(l) * - factorial(k + l)) - for l in range(2 * k + 1)]) - det = (a.determinant() ** (-1 / Integer(2)) * - (2 * pi) ** ((n - d) / Integer(2))) - chunk = det * sum([(alpha[d - 1] * asy_var) ** ((n - d) / - Integer(2) - q) * - sum([L[(j, k)] * binomial(n - 1, j) * - stirling_number1(n - j, n + k - q) * - (-1) ** (q - j - k) - for (j, k) in product(range(min(n - 1, q) + 1), - range(max(0, q - n), - q + 1)) - if j + k <= q]) - for q in range(N)]) + L[(j, k)] = sum([DD[(j, k, l)] / ((-1) ** k * 2 ** (k + l) * factorial(l) * factorial(k + l)) for l in range(2 * k + 1)]) + det = a.determinant() ** (-1 / Integer(2)) * (2 * pi) ** ((n - d) / Integer(2)) + chunk = det * sum([(alpha[d - 1] * asy_var) ** ((n - d) / Integer(2) - q) * sum([L[(j, k)] * binomial(n - 1, j) * stirling_number1(n - j, n + k - q) * (-1) ** (q - j - k) for (j, k) in product(range(min(n - 1, q) + 1), range(max(0, q - n), q + 1)) if j + k <= q]) for q in range(N)]) chunk = chunk.subs(P).simplify() coeffs = chunk.coefficients(asy_var) coeffs.reverse() coeffs = coeffs[:N] if numerical: - subexp_part = sum([co[0].subs(p).n(digits=numerical) * - asy_var ** co[1] - for co in coeffs]) - exp_scale = prod([(P[X[i]] ** (-alpha[i])).subs(p) - for i in range(d)]).n(digits=numerical) + subexp_part = sum([co[0].subs(p).n(digits=numerical) * asy_var ** co[1] for co in coeffs]) + exp_scale = prod([(P[X[i]] ** (-alpha[i])).subs(p) for i in range(d)]).n(digits=numerical) else: - subexp_part = sum([co[0].subs(p) * asy_var ** co[1] - for co in coeffs]) - exp_scale = prod([(P[X[i]] ** (-alpha[i])).subs(p) - for i in range(d)]) - return (exp_scale ** asy_var * subexp_part, exp_scale, subexp_part) + subexp_part = sum([co[0].subs(p) * asy_var ** co[1] for co in coeffs]) + exp_scale = prod([(P[X[i]] ** (-alpha[i])).subs(p) for i in range(d)]) + return (exp_scale**asy_var * subexp_part, exp_scale, subexp_part) def _crit_cone_combo(self, p, alpha, coordinate=None): r""" @@ -2422,8 +2330,7 @@ def grads(self, p): d = self.dimension() H = [h for (h, e) in self.denominator_factored()] n = len(H) - return [tuple([diff(H[i], X[j]).subs(p) for j in range(d)]) - for i in range(n)] + return [tuple([diff(H[i], X[j]).subs(p) for j in range(d)]) for i in range(n)] def log_grads(self, p): r""" @@ -2470,8 +2377,7 @@ def log_grads(self, p): d = self.dimension() H = [h for (h, e) in self.denominator_factored()] n = len(H) - return [tuple([(X[j] * diff(H[i], X[j])).subs(p) for j in range(d)]) - for i in range(n)] + return [tuple([(X[j] * diff(H[i], X[j])).subs(p) for j in range(d)]) for i in range(n)] def critical_cone(self, p, coordinate=None): r""" @@ -2700,7 +2606,7 @@ def smooth_critical_ideal(self, alpha): # Expand K by the variables of alpha if there are any. indets = [a for a in alpha if a not in K and a in SR] - indets = sorted(set(indets), key=str) # Delete duplicates in indets. + indets = sorted(set(indets), key=str) # Delete duplicates in indets. if indets: L = PolynomialRing(K, indets).fraction_field() S = R.change_ring(L) @@ -2712,10 +2618,7 @@ def smooth_critical_ideal(self, alpha): # Find smooth, critical points for alpha. X = S.gens() Hred = S(Hred) - J = S.ideal([Hred] + - [alpha[d - 1] * X[i] * diff(Hred, X[i]) - - alpha[i] * X[d - 1] * diff(Hred, X[d - 1]) - for i in range(d - 1)]) + J = S.ideal([Hred] + [alpha[d - 1] * X[i] * diff(Hred, X[i]) - alpha[i] * X[d - 1] * diff(Hred, X[d - 1]) for i in range(d - 1)]) return S.ideal(J.groebner_basis()) def maclaurin_coefficients(self, multi_indices, numerical=0): @@ -2816,8 +2719,7 @@ def maclaurin_coefficients(self, multi_indices, numerical=0): coeffs[tuple(nu)] = val return coeffs - def relative_error(self, approx, alpha, interval, exp_scale=Integer(1), - digits=10): + def relative_error(self, approx, alpha, interval, exp_scale=Integer(1), digits=10): r""" Return the relative error between the values of the Maclaurin coefficients of ``self`` with multi-indices ``r alpha`` for ``r`` in @@ -2887,17 +2789,15 @@ def relative_error(self, approx, alpha, interval, exp_scale=Integer(1), mac_approx = {} stats = [] for r in interval: - exp_s_r = exp_scale ** r + exp_s_r = exp_scale**r beta = tuple(r * alpha) mac[beta] = (mac[beta] / exp_s_r).n(digits=digits) - mac_approx[beta] = [(f.subs({av: r}) / exp_s_r).n(digits=digits) - for f in approx] + mac_approx[beta] = [(f.subs({av: r}) / exp_s_r).n(digits=digits) for f in approx] stats_row = [beta, mac[beta], mac_approx[beta]] if mac[beta] == 0: stats_row.extend([None for a in mac_approx[beta]]) else: - stats_row.append([(mac[beta] - a) / mac[beta] - for a in mac_approx[beta]]) + stats_row.append([(mac[beta] - a) / mac[beta] for a in mac_approx[beta]]) stats.append(tuple(stats_row)) return stats @@ -3004,12 +2904,9 @@ def __classcall_private__(cls, denominator_ring, numerator_ring=None, category=N if numerator_ring is None: numerator_ring = denominator_ring if not numerator_ring.has_coerce_map_from(denominator_ring): - raise ValueError('numerator ring {} has no coercion map from the ' - 'denominator ring {}'.format( - numerator_ring, denominator_ring)) + raise ValueError('numerator ring {} has no coercion map from the ' 'denominator ring {}'.format(numerator_ring, denominator_ring)) category = Rings().Commutative().or_subcategory(category) - return super().__classcall__(cls, denominator_ring, - numerator_ring, category) + return super().__classcall__(cls, denominator_ring, numerator_ring, category) def __init__(self, denominator_ring, numerator_ring=None, category=None): r""" @@ -3041,8 +2938,7 @@ def _repr_(self) -> str: Ring of fractions with factored denominator over Multivariate Polynomial Ring in X, Y over Integer Ring """ - return ("Ring of fractions with factored denominator " - "over {!r}".format(self.base())) + return "Ring of fractions with factored denominator " "over {!r}".format(self.base()) def base_ring(self): r""" @@ -3087,16 +2983,14 @@ def _element_constructor_(self, *args, **kwargs): reduce = kwargs.pop('reduce', None) if kwargs: - raise ValueError('Unknown keyword arguments ' - '%s given' % (kwargs,)) + raise ValueError('Unknown keyword arguments ' '%s given' % (kwargs,)) # process arguments if len(args) > 2: raise ValueError('too many arguments given') elif not args: - raise ValueError('No argument given. ' - 'We are in serious troubles...') + raise ValueError('No argument given. ' 'We are in serious troubles...') # At this point we have one or two input arguments. @@ -3117,12 +3011,11 @@ def _element_constructor_(self, *args, **kwargs): denominator_factored = [] from sage.rings.semirings.non_negative_integer_semiring import NN + try: - denominator_factored = sorted( - (R(d[0]), NN(d[1])) for d in denominator_factored) + denominator_factored = sorted((R(d[0]), NN(d[1])) for d in denominator_factored) except TypeError: - raise TypeError('factored denominator is not well-formed ' - 'or of wrong type') + raise TypeError('factored denominator is not well-formed ' 'or of wrong type') # From now on we only have one input argument; # it's called x and has parent P. @@ -3166,6 +3059,7 @@ def _element_constructor_(self, *args, **kwargs): from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base + if isinstance(R, (PolynomialRing_generic, MPolynomialRing_base)): if not R(q).is_unit(): # Factor denominator @@ -3182,10 +3076,7 @@ def _element_constructor_(self, *args, **kwargs): numerator = p / q denominator_factored = [] - return self.element_class(self, - numerator=numerator, - denominator_factored=denominator_factored, - reduce=reduce) + return self.element_class(self, numerator=numerator, denominator_factored=denominator_factored, reduce=reduce) def _coerce_map_from_(self, P): r""" @@ -3230,10 +3121,12 @@ def _coerce_map_from_(self, P): return True from sage.rings.fraction_field import FractionField_generic + if isinstance(P, FractionField_generic): B = P.base() from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base + if isinstance(B, (PolynomialRing_generic, MPolynomialRing_base)) and self.base().has_coerce_map_from(B): return True @@ -3253,6 +3146,7 @@ def _an_element_(self): (42, [(x, 3)]) """ from sage.rings.semirings.non_negative_integer_semiring import NN + return self(NN.an_element(), [(self.base().an_element(), NN(3))]) Element = FractionWithFactoredDenominator @@ -3309,8 +3203,8 @@ def __eq__(self, other) -> bool: True """ from operator import methodcaller - return (sorted(self, key=methodcaller('_total_order_key_')) == - sorted(other, key=methodcaller('_total_order_key_'))) + + return sorted(self, key=methodcaller('_total_order_key_')) == sorted(other, key=methodcaller('_total_order_key_')) def __ne__(self, other) -> bool: r""" @@ -3411,8 +3305,7 @@ def whole_and_parts(self): b = p whole += a parts.append(r.parent()(b, r.denominator_factored(), reduce=False)) - return FractionWithFactoredDenominatorSum( - [r.parent()(whole, ())] + parts) # r.parent() is not the nicest here + return FractionWithFactoredDenominatorSum([r.parent()(whole, ())] + parts) # r.parent() is not the nicest here def _combine_like_terms_(self): r""" @@ -3452,6 +3345,7 @@ def _combine_like_terms_(self): return self from operator import methodcaller + # Combine like terms. FFPDs = sorted(self, key=methodcaller('_total_order_key_')) new_FFPDs = [] @@ -3611,8 +3505,7 @@ def diff_prod(f_derivs, u, g, X, interval, end, uderivs, atc): new_var = SR.temp_var() new_vars.append(new_var) D[diff(u, t).subs(atc)] = new_var - eqns = [lhs[i] == rhs[i].subs(uderivs).subs(D) - for i in range(len(lhs))] + eqns = [lhs[i] == rhs[i].subs(uderivs).subs(D) for i in range(len(lhs))] variables = D.values() sol = solve(eqns, *variables, solution_dict=True) uderivs.update(subs_all(D, sol[ZZ.zero()])) @@ -3700,8 +3593,7 @@ def subs_all(f, sub, simplify=False): return g -def diff_all(f, V, n, ending=[], sub=None, sub_final=None, - zero_order=0, rekey=None): +def diff_all(f, V, n, ending=[], sub=None, sub_final=None, zero_order=0, rekey=None): r""" Return a dictionary of representative mixed partial derivatives of `f` from order 1 up to order `n` with respect to the @@ -3912,7 +3804,7 @@ def diff_op(A, B, AB_derivs, V, M, r, N): if j + k < N: for l in range(2 * k + 1): for s in combinations_with_replacement(V, 2 * (k + l)): - DF = diff(A[j] * B ** l, list(s)).subs(AB_derivs) + DF = diff(A[j] * B**l, list(s)).subs(AB_derivs) product_derivs[(j, k, l) + s] = DF # Second, compute DD^(k+l)(A[j]*B^l)(p) and store values in dictionary. @@ -3934,7 +3826,7 @@ def diff_op(A, B, AB_derivs, V, M, r, N): idx = (j, k, l) + diff_seq(V, t) if product_derivs[idx] != ZZ.zero(): MM = ZZ.one() - for (a, b) in t: + for a, b in t: MM *= M[a][b] if a != b: MM *= Integer(2) @@ -4035,16 +3927,11 @@ def diff_op_simple(A, B, AB_derivs, x, v, a, N): if v.mod(Integer(2)) == ZZ.zero(): for k in range(N): for l in range(2 * k + 1): - DD[(k, l)] = ((a ** (-ZZ.one() / v)) ** (2 * k + v * l) * - diff(A * B ** l, x, - 2 * k + v * l).subs(AB_derivs)) + DD[(k, l)] = (a ** (-ZZ.one() / v)) ** (2 * k + v * l) * diff(A * B**l, x, 2 * k + v * l).subs(AB_derivs) else: for k in range(N): for l in range(k + 1): - DD[(k, l)] = ((abs(a) ** (-ZZ.one() / v) * I * - a / abs(a)) ** (k + v * l) * - diff(A * B ** l, x, - k + v * l).subs(AB_derivs)) + DD[(k, l)] = (abs(a) ** (-ZZ.one() / v) * I * a / abs(a)) ** (k + v * l) * diff(A * B**l, x, k + v * l).subs(AB_derivs) return DD diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index c5517f328a9..d3074859174 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -217,6 +217,7 @@ Classes and Methods =================== """ + # *************************************************************************** # Copyright (C) 2014--2015 Benjamin Hackl # 2014--2015 Daniel Krenn @@ -230,6 +231,7 @@ from collections import namedtuple from sage.misc.lazy_import import lazy_import + lazy_import('sage.rings.asymptotic.growth_group_cartesian', 'CartesianProductGrowthGroups') from sage.categories.pushout import ConstructionFunctor @@ -237,8 +239,7 @@ from sage.structure.factory import UniqueFactory from sage.structure.parent import Parent from sage.structure.sage_object import SageObject -from sage.structure.unique_representation import (CachedRepresentation, - UniqueRepresentation) +from sage.structure.unique_representation import CachedRepresentation, UniqueRepresentation from sage.structure.richcmp import richcmp_by_eq_and_lt import sage.rings.abc from .misc import WithLocals @@ -317,6 +318,7 @@ class Variable(CachedRepresentation, SageObject): sage: v = Variable('(e^(n*log(n)))', ignore=('e',)); repr(v), v.variable_names() ('e^(n*log(n))', ('n',)) """ + def __init__(self, var, repr=None, latex_name=None, ignore=None): r""" See :class:`Variable` for details. @@ -360,10 +362,7 @@ def __init__(self, var, repr=None, latex_name=None, ignore=None): from sage.symbolic.ring import SR if repr is None: - var_bases = tuple(i for i in sum(iter( - self.extract_variable_names(v) - if not isidentifier(v) else (v,) - for v in var), tuple()) if i not in ignore) + var_bases = tuple(i for i in sum(iter(self.extract_variable_names(v) if not isidentifier(v) else (v,) for v in var), tuple()) if i not in ignore) var_repr = ', '.join(var) if latex_name is None: latex_name = ', '.join(latex(SR(v)) for v in var if v) @@ -380,8 +379,7 @@ def __init__(self, var, repr=None, latex_name=None, ignore=None): latex_name = latex(var_repr) if len(var_bases) != len(set(var_bases)): - raise ValueError('Variable names %s are not pairwise distinct.' % - (var_bases,)) + raise ValueError('Variable names %s are not pairwise distinct.' % (var_bases,)) self.var_bases = var_bases self.var_repr = var_repr @@ -579,6 +577,7 @@ def extract_variable_names(s): ('a', 'b', 'c', 'd') """ from sage.symbolic.ring import SR + if s == '': return () return tuple(str(s) for s in SR(s).variables()) @@ -618,10 +617,12 @@ def _substitute_(self, rules): > *previous* ZeroDivisionError: rational division by zero """ from sage.misc.sage_eval import sage_eval + try: return sage_eval(self.var_repr, locals=rules) except (ArithmeticError, TypeError, ValueError) as e: from .misc import substitute_raise_exception + substitute_raise_exception(self, e) @@ -637,6 +638,7 @@ class PartialConversionValueError(ValueError): The remaining argument passed on to :python:`ValueError`. """ + def __init__(self, element, *args, **kwds): r""" See :exc:`PartialConversionValueError` for more information. @@ -675,6 +677,7 @@ class PartialConversionElement(SageObject): elements of :mod:`cartesian products of growth groups `. """ + def __init__(self, growth_group, raw_element): r""" See :class:`PartialConversionElement` for more information. @@ -699,9 +702,8 @@ def _repr_(self): element with parameter -42 (Integer Ring) in Growth Group QQ^n """ from sage.structure.element import parent - return 'element with parameter {} ({}) in {}'.format(self.raw_element, - parent(self.raw_element), - self.growth_group) + + return 'element with parameter {} ({}) in {}'.format(self.raw_element, parent(self.raw_element), self.growth_group) def split(self): r""" @@ -735,8 +737,8 @@ def split(self): here = self.growth_group.element_class(self.growth_group, raw_here) except PartialConversionValueError as e: from .misc import combine_exceptions - raise combine_exceptions( - ValueError('cannot split {}'.format(self)), e) + + raise combine_exceptions(ValueError('cannot split {}'.format(self)), e) other = PartialConversionElement(self.growth_group, raw_other) return here, other @@ -876,19 +878,13 @@ def _log_(self, base=None): log_factor = self.log_factor(base=base) if not log_factor: - raise ArithmeticError('%s is zero, ' - 'which is not contained in %s.' % - (log_string(self, base), self.parent())) + raise ArithmeticError('%s is zero, ' 'which is not contained in %s.' % (log_string(self, base), self.parent())) if len(log_factor) != 1: - raise ArithmeticError('Calculating %s results in a sum, ' - 'which is not contained in %s.' % - (log_string(self, base), self.parent())) + raise ArithmeticError('Calculating %s results in a sum, ' 'which is not contained in %s.' % (log_string(self, base), self.parent())) g, c = log_factor[0] if c != 1: - raise ArithmeticError('When calculating %s a factor %s != 1 ' - 'appeared, which is not contained in %s.' % - (log_string(self, base), c, self.parent())) + raise ArithmeticError('When calculating %s a factor %s != 1 ' 'appeared, which is not contained in %s.' % (log_string(self, base), c, self.parent())) return g @@ -959,13 +955,11 @@ def _log_factor_(self, base=None, locals=None): log_factor = self._log_factor_(base=base, locals=locals) for g, c in log_factor: - if hasattr(g, 'parent') and \ - isinstance(g.parent(), GenericGrowthGroup): + if hasattr(g, 'parent') and isinstance(g.parent(), GenericGrowthGroup): continue from .misc import log_string - raise ArithmeticError('Cannot build %s since %s ' - 'is not in %s.' % (log_string(self, base), - g, self.parent())) + + raise ArithmeticError('Cannot build %s since %s ' 'is not in %s.' % (log_string(self, base), g, self.parent())) return log_factor @@ -1049,8 +1043,7 @@ def _rpow_(self, base): Asymptotic Ring over Symbolic Constants Subring """ if base == 0: - raise ValueError('%s is not an allowed base for calculating the ' - 'power to %s.' % (base, self)) + raise ValueError('%s is not an allowed base for calculating the ' 'power to %s.' % (base, self)) var = str(self) @@ -1060,8 +1053,8 @@ def _rpow_(self, base): if base == 'e': from sage.rings.integer_ring import ZZ from .misc import repr_op - MM = MonomialGrowthGroup(ZZ, repr_op('e', '^', var), - ignore_variables=('e',)) + + MM = MonomialGrowthGroup(ZZ, repr_op('e', '^', var), ignore_variables=('e',)) element = MM(raw_element=ZZ(1)) else: EEUU = ExponentialGrowthGroup.factory(base.parent(), var) @@ -1070,7 +1063,7 @@ def _rpow_(self, base): except AttributeError: factors = (EEUU,) if len(factors) == 1: - EE, = factors + (EE,) = factors element = EE(raw_element=base) else: EE, UU = factors @@ -1083,9 +1076,8 @@ def _rpow_(self, base): return self.parent().one() * element except (TypeError, ValueError) as e: from .misc import combine_exceptions, repr_op - raise combine_exceptions( - ArithmeticError('Cannot construct %s in %s' % - (repr_op(base, '^', var), self.parent())), e) + + raise combine_exceptions(ArithmeticError('Cannot construct %s in %s' % (repr_op(base, '^', var), self.parent())), e) class GenericGrowthElement(MultiplicativeGroupElement): @@ -1154,13 +1146,8 @@ def __init__(self, parent, raw_element): except (TypeError, ValueError) as e: from .misc import combine_exceptions from sage.structure.element import parent as parent_function - raise combine_exceptions( - PartialConversionValueError( - PartialConversionElement(parent, raw_element), - '{} ({}) is not in {}'.format(raw_element, - parent_function(raw_element), - parent.base())), - e) + + raise combine_exceptions(PartialConversionValueError(PartialConversionElement(parent, raw_element), '{} ({}) is not in {}'.format(raw_element, parent_function(raw_element), parent.base())), e) self._check_() @@ -1268,8 +1255,7 @@ def __invert__(self): sage: ~P.an_element() x^(-1) """ - raise NotImplementedError('Inversion of %s not implemented ' - '(in this abstract method).' % (self,)) + raise NotImplementedError('Inversion of %s not implemented ' '(in this abstract method).' % (self,)) _richcmp_ = richcmp_by_eq_and_lt("_eq_", "_lt_") @@ -1413,8 +1399,7 @@ def _log_factor_(self, base=None, locals=None): NotImplementedError: Cannot determine logarithmized factorization of GenericGrowthElement(1/2) in abstract base class. """ - raise NotImplementedError('Cannot determine logarithmized factorization ' - 'of %s in abstract base class.' % (self,)) + raise NotImplementedError('Cannot determine logarithmized factorization ' 'of %s in abstract base class.' % (self,)) rpow = _rpow_ @@ -1439,8 +1424,7 @@ def _rpow_element_(self, base): ... ValueError: Cannot compute 2 to the generic element 3^x. """ - raise ValueError('Cannot compute %s to the generic element %s.' % - (base, self)) + raise ValueError('Cannot compute %s to the generic element %s.' % (base, self)) def factors(self): r""" @@ -1483,9 +1467,8 @@ def _substitute_(self, rules): Growth Group Generic(ZZ). """ from .misc import substitute_raise_exception - substitute_raise_exception(self, TypeError( - 'Cannot substitute in the abstract ' - 'base class %s.' % (self.parent(),))) + + substitute_raise_exception(self, TypeError('Cannot substitute in the abstract ' 'base class %s.' % (self.parent(),))) def variable_names(self): r""" @@ -1553,8 +1536,7 @@ def _singularity_analysis_(self, var, zeta, precision): NotImplementedError: singularity analysis of GenericGrowthElement(2) not implemented """ - raise NotImplementedError('singularity analysis of {} ' - 'not implemented '.format(self)) + raise NotImplementedError('singularity analysis of {} ' 'not implemented '.format(self)) def _find_minimum_(self, valid_from): r""" @@ -1615,6 +1597,7 @@ class GenericGrowthGroup(UniqueRepresentation, Parent, WithLocals): :class:`MonomialGrowthGroup`, :class:`ExponentialGrowthGroup` """ + # TODO: implement some sort of 'assume', where basic assumptions # for the variables can be stored. --> within the Cartesian product @@ -1627,9 +1610,7 @@ class GenericGrowthGroup(UniqueRepresentation, Parent, WithLocals): from sage.categories.magmas import Magmas from sage.categories.additive_magmas import AdditiveMagmas - _determine_category_subcategory_mapping_ = [ - (Sets(), Sets(), True), - (Posets(), Posets(), False)] + _determine_category_subcategory_mapping_ = [(Sets(), Sets(), True), (Posets(), Posets(), False)] _determine_category_axiom_mapping_ = [] @@ -1701,8 +1682,8 @@ def __classcall__(cls, base, var=None, category=None, ignore_variables=None): TypeError: Asymptotic Ring over Rational Field is not a valid base. """ from .asymptotic_ring import AsymptoticRing - if not isinstance(base, Parent) or \ - isinstance(base, AsymptoticRing): + + if not isinstance(base, Parent) or isinstance(base, AsymptoticRing): raise TypeError('%s is not a valid base.' % (base,)) if var is None: @@ -1712,11 +1693,8 @@ def __classcall__(cls, base, var=None, category=None, ignore_variables=None): if category is None: from .misc import transform_category - category = transform_category( - base.category(), - cls._determine_category_subcategory_mapping_, - cls._determine_category_axiom_mapping_, - initial_category=cls._initial_category_(base)) + + category = transform_category(base.category(), cls._determine_category_subcategory_mapping_, cls._determine_category_axiom_mapping_, initial_category=cls._initial_category_(base)) return super().__classcall__(cls, base, var, category) @@ -1743,13 +1721,13 @@ def _initial_category_(base): True """ from sage.categories.posets import Posets + # The following block can be removed once #19269 is fixed. from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic - if base is ZZ or base is QQ or \ - isinstance(base, PolynomialRing_generic) and \ - (base.base_ring() is ZZ or base.base_ring() is QQ): + + if base is ZZ or base is QQ or isinstance(base, PolynomialRing_generic) and (base.base_ring() is ZZ or base.base_ring() is QQ): return Posets() return None @@ -1843,6 +1821,7 @@ def _repr_short_(self): Growth Group Generic(QQ, a, b) """ from .misc import parent_to_repr_short + vars = ', '.join(self._var_.variable_names()) if vars: vars = ', ' + vars @@ -1944,8 +1923,7 @@ def some_elements(self): z^(2/3), z^(-2/3), z^(3/2), z^(-3/2), z^(4/5), z^(-4/5), z^(5/4), z^(-5/4), ...) """ - return iter(self.element_class(self, e) - for e in self.base().some_elements()) + return iter(self.element_class(self, e) for e in self.base().some_elements()) def _create_element_in_extension_(self, raw_element): r""" @@ -1970,8 +1948,7 @@ def _create_element_in_extension_(self, raw_element): if raw_element.parent() is self.base(): parent = self else: - parent = self._underlying_class()(raw_element.parent(), self._var_, - category=self.category()) + parent = self._underlying_class()(raw_element.parent(), self._var_, category=self.category()) return parent(raw_element=raw_element) def le(self, left, right): @@ -2122,8 +2099,7 @@ def _element_constructor_(self, data, raw_element=None): try: raw_element = self.base()(data._raw_element_) except (TypeError, ValueError) as e: - raise combine_exceptions( - ValueError('%s is not in %s.' % (data, self)), e) + raise combine_exceptions(ValueError('%s is not in %s.' % (data, self)), e) elif isinstance(data, GenericGrowthElement): if data.is_one(): @@ -2131,15 +2107,9 @@ def _element_constructor_(self, data, raw_element=None): elif isinstance(data, PartialConversionElement): if data.growth_group is self: - raise PartialConversionValueError( - data, - 'no conversion of {}: this was already unsuccessful ' - 'earlier'.format(data)) + raise PartialConversionValueError(data, 'no conversion of {}: this was already unsuccessful ' 'earlier'.format(data)) if not data.is_compatible(self): - raise TypeError( - 'cannot (partially) convert {} because its ' - 'growth group {} is not compatible to this ' - 'growth group {}'.format(data.raw_element, data.growth_group, self)) + raise TypeError('cannot (partially) convert {} because its ' 'growth group {} is not compatible to this ' 'growth group {}'.format(data.raw_element, data.growth_group, self)) raw_element = data.raw_element else: @@ -2148,9 +2118,7 @@ def _element_constructor_(self, data, raw_element=None): if raw_element is None: raise ValueError('%s is not in %s.' % (data, self)) elif not isinstance(data, int) or data != 0: - raise ValueError('input is ambiguous: ' - '%s as well as raw_element=%s ' - 'are specified' % (data, raw_element)) + raise ValueError('input is ambiguous: ' '%s as well as raw_element=%s ' 'are specified' % (data, raw_element)) return self.element_class(self, raw_element) @@ -2361,13 +2329,12 @@ def _pushout_(self, other): Growth Group x^ZZ * y^ZZ sage: sage.structure.element.coercion_traceback() # not tested """ - if not isinstance(other, GenericGrowthGroup) and \ - not (other.construction() is not None and - isinstance(other.construction()[0], AbstractGrowthGroupFunctor)): + if not isinstance(other, GenericGrowthGroup) and not (other.construction() is not None and isinstance(other.construction()[0], AbstractGrowthGroupFunctor)): return if set(self.variable_names()).isdisjoint(set(other.variable_names())): from sage.categories.cartesian_product import cartesian_product + return cartesian_product([self, other]) def gens_monomial(self) -> tuple: @@ -2525,6 +2492,7 @@ def extended_by_non_growth_group(self): Growth Group CBF^x * UU_RBF^x """ from sage.categories.cartesian_product import cartesian_product + return cartesian_product((self, self.non_growth_group())) def non_growth_group(self): @@ -2688,6 +2656,7 @@ class DecreasingGrowthElementError(ValueError): The remaining arguments are passed on to :python:`ValueError`. """ + def __init__(self, element, *args, **kwds): r""" See :exc:`DecreasingGrowthElementError` for more information. @@ -2791,6 +2760,7 @@ def _repr_(self, latex=False): """ if latex: from sage.misc.latex import latex as latex_repr + f = latex_repr else: f = repr @@ -2805,10 +2775,8 @@ def _repr_(self, latex=False): if self.exponent == 1: return var if latex: - return repr_op(var, '^', latex=True) + \ - '{' + latex_repr(self.exponent)._latex_() + '}' - if self.exponent in ZZ and self.exponent > 0 \ - or isidentifier(str(self.exponent)): + return repr_op(var, '^', latex=True) + '{' + latex_repr(self.exponent)._latex_() + '}' + if self.exponent in ZZ and self.exponent > 0 or isidentifier(str(self.exponent)): return repr_op(var, '^') + str(self.exponent) return repr_op(var, '^') + '(' + str(self.exponent) + ')' @@ -2926,8 +2894,8 @@ def __pow__(self, exponent): x^42 """ from .misc import strip_symbolic - return self.parent()._create_element_in_extension_( - self.exponent * strip_symbolic(exponent)) + + return self.parent()._create_element_in_extension_(self.exponent * strip_symbolic(exponent)) def _log_factor_(self, base=None, locals=None): r""" @@ -2988,15 +2956,15 @@ def _log_factor_(self, base=None, locals=None): var = str(self.parent()._var_) from .misc import split_str_by_op + split = split_str_by_op(var, '^') if len(split) == 2: b, e = split - if base is None and b == 'e' or \ - base is not None and b == str(base): + if base is None and b == 'e' or base is not None and b == str(base): return ((e, coefficient),) if var.startswith('exp('): - assert (var[-1] == ')') + assert var[-1] == ')' v = var[4:-1] else: v = 'log(%s)' % (var,) @@ -3069,6 +3037,7 @@ def _rpow_element_(self, base, locals=None): new_var = var[4:-1] if base == 'e': from sage.rings.integer_ring import ZZ + M = MonomialGrowthGroup(ZZ, new_var) return M(raw_element=ZZ(1)) log = self.parent().locals(locals)['log'] @@ -3139,6 +3108,7 @@ def _substitute_(self, rules): return self.parent()._var_._substitute_(rules) ** self.exponent except (ArithmeticError, TypeError, ValueError) as e: from .misc import substitute_raise_exception + substitute_raise_exception(self, e) def _singularity_analysis_(self, var, zeta, precision): @@ -3191,24 +3161,16 @@ def _singularity_analysis_(self, var, zeta, precision): from sage.rings.integer_ring import ZZ if self.parent()._var_.is_monomial(): - from sage.rings.asymptotic.asymptotic_expansion_generators import \ - asymptotic_expansions - return asymptotic_expansions.SingularityAnalysis( - var=var, zeta=zeta, alpha=self.exponent, beta=0, delta=0, - precision=precision) + from sage.rings.asymptotic.asymptotic_expansion_generators import asymptotic_expansions + + return asymptotic_expansions.SingularityAnalysis(var=var, zeta=zeta, alpha=self.exponent, beta=0, delta=0, precision=precision) if self.parent().gens_logarithmic(): if self.exponent not in ZZ: - raise NotImplementedError( - 'singularity analysis of {} not implemented ' - 'since exponent {} is not an integer'.format( - self, self.exponent)) - from sage.rings.asymptotic.asymptotic_expansion_generators import \ - asymptotic_expansions - return asymptotic_expansions.SingularityAnalysis( - var=var, zeta=zeta, alpha=0, beta=ZZ(self.exponent), delta=0, - precision=precision, normalized=False) - raise NotImplementedError( - 'singularity analysis of {} not implemented'.format(self)) + raise NotImplementedError('singularity analysis of {} not implemented ' 'since exponent {} is not an integer'.format(self, self.exponent)) + from sage.rings.asymptotic.asymptotic_expansion_generators import asymptotic_expansions + + return asymptotic_expansions.SingularityAnalysis(var=var, zeta=zeta, alpha=0, beta=ZZ(self.exponent), delta=0, precision=precision, normalized=False) + raise NotImplementedError('singularity analysis of {} not implemented'.format(self)) def _find_minimum_(self, valid_from): r""" @@ -3316,16 +3278,9 @@ class MonomialGrowthGroup(GenericGrowthGroup): from sage.categories.magmas import Magmas from sage.categories.additive_magmas import AdditiveMagmas - _determine_category_subcategory_mapping_ = [ - (Sets(), Sets(), True), - (Posets(), Posets(), False), - (AdditiveMagmas(), Magmas(), False)] + _determine_category_subcategory_mapping_ = [(Sets(), Sets(), True), (Posets(), Posets(), False), (AdditiveMagmas(), Magmas(), False)] - _determine_category_axiom_mapping_ = [ - ('AdditiveAssociative', 'Associative', False), - ('AdditiveUnital', 'Unital', False), - ('AdditiveInverse', 'Inverse', False), - ('AdditiveCommutative', 'Commutative', False)] + _determine_category_axiom_mapping_ = [('AdditiveAssociative', 'Associative', False), ('AdditiveUnital', 'Unital', False), ('AdditiveInverse', 'Inverse', False), ('AdditiveCommutative', 'Commutative', False)] def _repr_short_(self): r""" @@ -3350,6 +3305,7 @@ def _repr_short_(self): 'a^QQ[x]' """ from .misc import parent_to_repr_short, repr_op + return repr_op(self._var_, '^', parent_to_repr_short(self.base())) def _convert_(self, data): @@ -3458,13 +3414,14 @@ def _convert_(self, data): if var not in str(data): return # this has to end here from sage.symbolic.ring import SR + return self._convert_(SR(data)) from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic - from sage.rings.polynomial.multi_polynomial_ring_base import \ - MPolynomialRing_base + from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base from sage.rings.power_series_ring import PowerSeriesRing_generic import operator + if isinstance(P, SymbolicRing): if data.operator() == operator.pow: base, exponent = data.operands() @@ -3477,12 +3434,13 @@ def _convert_(self, data): elif isinstance(P, PowerSeriesRing_generic): if hasattr(data, 'variables') and len(data.variables()) == 1: from sage.rings.integer_ring import ZZ + if data.is_monomial() and data.precision_absolute() not in ZZ: if var == str(data.variables()[0]): return data.degree() - elif len(P.variable_names()) == 1 and \ - var == str(data.variable()[0]): + elif len(P.variable_names()) == 1 and var == str(data.variable()[0]): from sage.rings.integer_ring import ZZ + if data.is_monomial() and data.precision_absolute() not in ZZ: return data.degree() @@ -3514,6 +3472,7 @@ def _split_raw_element_(raw_element): (3, 4) """ from sage.functions.other import real, imag + return real(raw_element), imag(raw_element) def gens_monomial(self) -> tuple: @@ -3590,11 +3549,7 @@ def construction(self): return MonomialGrowthGroupFunctor(self._var_), self.base() @classmethod - def factory(cls, - base, var, - extend_by_non_growth_group=False, - return_factors=False, - **kwds): + def factory(cls, base, var, extend_by_non_growth_group=False, return_factors=False, **kwds): r""" Create a monomial growth group. @@ -3663,6 +3618,7 @@ def non_growth_group(self): Growth Group n^(ZZ*I) """ from sage.groups.misc_gps.imaginary_groups import ImaginaryGroup + J = ImaginaryGroup(self.base()) return self._non_growth_group_class_(J, self._var_) @@ -3714,6 +3670,7 @@ def __init__(self, var): MonomialGrowthGroup[x] """ from sage.categories.commutative_additive_monoids import CommutativeAdditiveMonoids + super().__init__(var, CommutativeAdditiveMonoids()) def _apply_functor(self, base): @@ -3789,9 +3746,8 @@ def _check_(self): """ if not self.base > 0: from sage.structure.element import parent - raise PartialConversionValueError( - PartialConversionElement(self.parent(), self.base), - 'base {} ({}) must be positive'.format(self.base, parent(self.base))) + + raise PartialConversionValueError(PartialConversionElement(self.parent(), self.base), 'base {} ({}) must be positive'.format(self.base, parent(self.base))) @property def base(self): @@ -3849,6 +3805,7 @@ def _repr_(self, latex=False): """ if latex: from sage.misc.latex import latex as latex_repr + f = latex_repr else: f = repr @@ -3859,8 +3816,7 @@ def _repr_(self, latex=False): if self.base.is_one(): return '1' if latex: - return repr_op(latex_repr(self.base)._latex_(), '^', latex=True) + \ - '{' + latex_repr(var)._latex_() + '}' + return repr_op(latex_repr(self.base)._latex_(), '^', latex=True) + '{' + latex_repr(var)._latex_() + '}' return repr_op(str(self.base), '^', var) def _latex_(self): @@ -4002,8 +3958,8 @@ def __pow__(self, exponent): Growth Group QQ^x * x^ZZ * Signs^x """ from .misc import strip_symbolic - return self.parent()._create_element_in_extension_( - self.base ** strip_symbolic(exponent)) + + return self.parent()._create_element_in_extension_(self.base ** strip_symbolic(exponent)) def _log_factor_(self, base=None, locals=None): r""" @@ -4050,8 +4006,7 @@ def _log_factor_(self, base=None, locals=None): if self.is_one(): return tuple() b = self.base - if base is None and hasattr(b, 'is_monomial') and b.is_monomial() and \ - b.variable_name() == 'e': + if base is None and hasattr(b, 'is_monomial') and b.is_monomial() and b.variable_name() == 'e': coefficient = b.valuation() elif base is None and str(b) == 'e': coefficient = self.parent().base().one() @@ -4127,6 +4082,7 @@ def _substitute_(self, rules): return self.base ** self.parent()._var_._substitute_(rules) except (ArithmeticError, TypeError, ValueError) as e: from .misc import substitute_raise_exception + substitute_raise_exception(self, e) @@ -4178,17 +4134,9 @@ class ExponentialGrowthGroup(GenericGrowthGroup): from sage.categories.groups import Groups from sage.categories.division_rings import DivisionRings - _determine_category_subcategory_mapping_ = [ - (Sets(), Sets(), True), - (Posets(), Posets(), False), - (Magmas(), Magmas(), False), - (DivisionRings(), Groups(), False)] + _determine_category_subcategory_mapping_ = [(Sets(), Sets(), True), (Posets(), Posets(), False), (Magmas(), Magmas(), False), (DivisionRings(), Groups(), False)] - _determine_category_axiom_mapping_ = [ - ('Associative', 'Associative', False), - ('Unital', 'Unital', False), - ('Inverse', 'Inverse', False), - ('Commutative', 'Commutative', False)] + _determine_category_axiom_mapping_ = [('Associative', 'Associative', False), ('Unital', 'Unital', False), ('Inverse', 'Inverse', False), ('Commutative', 'Commutative', False)] def __init__(self, base, *args, **kwds): r""" @@ -4216,12 +4164,7 @@ def __init__(self, base, *args, **kwds): super().__init__(base, *args, **kwds) if isinstance(base, SymbolicRing) and not self._an_element_base_() > 0: - warn("When using the Exponential {}, make " - "assumptions on the used symbolic elements.\n" - "In particular, use something like " - "'assume(SR.an_element() > 0)' to make " - "coercions work properly.".format(self), - RuntimeWarning, 2) + warn("When using the Exponential {}, make " "assumptions on the used symbolic elements.\n" "In particular, use something like " "'assume(SR.an_element() > 0)' to make " "coercions work properly.".format(self), RuntimeWarning, 2) def _repr_short_(self): r""" @@ -4244,6 +4187,7 @@ def _repr_short_(self): 'QQ[x]^a' """ from .misc import parent_to_repr_short, repr_op + return repr_op(parent_to_repr_short(self.base()), '^', self._var_) def _convert_(self, data): @@ -4331,8 +4275,7 @@ def _convert_(self, data): return # this has to end here if s.endswith('^' + var): - return self.base()(s.replace('^' + var, '') - .replace('(', '').replace(')', '')) + return self.base()(s.replace('^' + var, '').replace('(', '').replace(')', '')) return # end of parsing import operator @@ -4349,6 +4292,7 @@ def _convert_(self, data): return base ** (exponent / P(var)) elif isinstance(op, Function_exp): from sage.functions.log import exp + base = exp(1) exponent = data.operands()[0] if str(exponent) == var: @@ -4451,23 +4395,17 @@ def _split_raw_element_(base): else: P = base.parent() - if P in (ZZ, QQ, AA) or isinstance(P, (SymbolicRing, - sage.rings.abc.RealField, - sage.rings.abc.RealIntervalField, - sage.rings.abc.RealBallField)): + if P in (ZZ, QQ, AA) or isinstance(P, (SymbolicRing, sage.rings.abc.RealField, sage.rings.abc.RealIntervalField, sage.rings.abc.RealBallField)): if base > 0: return base, None if base < 0: return -base, -1 - elif isinstance(P, (sage.rings.abc.ComplexField, - sage.rings.abc.ComplexIntervalField, - sage.rings.abc.ComplexBallField)): + elif isinstance(P, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexIntervalField, sage.rings.abc.ComplexBallField)): size = abs(base) direction = base / size return size, direction - raise ValueError('cannot split {} ({}) into ' - 'abs and arg'.format(base, parent(base))) + raise ValueError('cannot split {} ({}) into ' 'abs and arg'.format(base, parent(base))) def _an_element_(self): r""" @@ -4519,8 +4457,7 @@ def some_elements(self): sage: tuple(GrowthGroup('(QQ_+)^z').some_elements()) ((1/2)^z, 2^z, 1, 42^z, (2/3)^z, (3/2)^z, ...) """ - return iter(self.element_class(self, e) - for e in self.base().some_elements() if e > 0) + return iter(self.element_class(self, e) for e in self.base().some_elements() if e > 0) def gens(self) -> tuple: r""" @@ -4557,11 +4494,7 @@ def construction(self): return ExponentialGrowthGroupFunctor(self._var_), self.base() @classmethod - def factory(cls, - base, var, - extend_by_non_growth_group=True, - return_factors=False, - **kwds): + def factory(cls, base, var, extend_by_non_growth_group=True, return_factors=False, **kwds): r""" Create an exponential growth group. @@ -4617,15 +4550,11 @@ def factory(cls, elif extend_by_non_growth_group: if base == QQbar or isinstance(base, NumberField_cyclotomic): EE = cls(AA, var, **kwds) - UU = cls._non_growth_group_class_( - ArgumentGroup(domain=base), var) + UU = cls._non_growth_group_class_(ArgumentGroup(domain=base), var) groups = (EE, UU) - elif isinstance(base, (sage.rings.abc.ComplexField, - sage.rings.abc.ComplexIntervalField, - sage.rings.abc.ComplexBallField)): + elif isinstance(base, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexIntervalField, sage.rings.abc.ComplexBallField)): EE = cls(base._real_field(), var, **kwds) - UU = cls._non_growth_group_class_( - ArgumentGroup(exponents=base._real_field()), var) + UU = cls._non_growth_group_class_(ArgumentGroup(exponents=base._real_field()), var) groups = (EE, UU) else: EE = cls(base, var, **kwds) @@ -4664,6 +4593,7 @@ def non_growth_group(self): Growth Group UU_RBF^x """ from sage.groups.misc_gps.argument_groups import ArgumentGroup + UU = ArgumentGroup(domain=self.base()) return self._non_growth_group_class_(UU, self._var_) @@ -4715,6 +4645,7 @@ def __init__(self, var): ExponentialGrowthGroup[x] """ from sage.categories.monoids import Monoids + super().__init__(var, Monoids()) def _apply_functor(self, base): @@ -4797,11 +4728,11 @@ def _initial_category_(base): Category of posets """ from sage.categories.posets import Posets + return Posets() -class ExponentialNonGrowthElement(GenericNonGrowthElement, - ExponentialGrowthElement): +class ExponentialNonGrowthElement(GenericNonGrowthElement, ExponentialGrowthElement): r""" An element of :class:`ExponentialNonGrowthGroup`. """ @@ -4824,8 +4755,7 @@ def _check_(self): pass -class ExponentialNonGrowthGroup(GenericNonGrowthGroup, - ExponentialGrowthGroup): +class ExponentialNonGrowthGroup(GenericNonGrowthGroup, ExponentialGrowthGroup): r""" A growth group whose base is an :mod:`argument group `. @@ -4914,16 +4844,15 @@ def _apply_functor(self, base): return ExponentialNonGrowthGroup(base, self.var) -class MonomialNonGrowthElement(GenericNonGrowthElement, - MonomialGrowthElement): +class MonomialNonGrowthElement(GenericNonGrowthElement, MonomialGrowthElement): r""" An element of :class:`MonomialNonGrowthGroup`. """ + pass -class MonomialNonGrowthGroup(GenericNonGrowthGroup, - MonomialGrowthGroup): +class MonomialNonGrowthGroup(GenericNonGrowthGroup, MonomialGrowthGroup): r""" A growth group whose base is an :mod:`imaginary group `. @@ -4994,9 +4923,7 @@ def _apply_functor(self, base): return MonomialNonGrowthGroup(base, self.var) -GrowthGroupFactor = namedtuple('GrowthGroupFactor', - ['cls', 'base', 'var', - 'extend_by_non_growth_group']) +GrowthGroupFactor = namedtuple('GrowthGroupFactor', ['cls', 'base', 'var', 'extend_by_non_growth_group']) class GrowthGroupFactory(UniqueFactory): @@ -5235,8 +5162,7 @@ def create_key_and_extra_args(self, specification, **kwds): kwds.setdefault('ignore_variables', ('e',)) - sfactors = split_str_by_op( - ' '.join(specification.split()).replace('**', '^'), '*') + sfactors = split_str_by_op(' '.join(specification.split()).replace('**', '^'), '*') def remove_parentheses(s: str) -> str: while s.startswith('(') and s.endswith(')'): @@ -5246,42 +5172,36 @@ def remove_parentheses(s: str) -> str: def has_l_property(s, properties, invert=False) -> tuple[str, bool]: for p in properties: if s.startswith(p): - return s[len(p):].strip(), not invert + return s[len(p) :].strip(), not invert return s, invert def has_r_property(s, properties, invert=False) -> tuple[str, bool]: for p in properties: if s.endswith(p): - return s[:-len(p)].strip(), not invert + return s[: -len(p)].strip(), not invert return s, invert factors = [] for factor in sfactors: if '^' not in factor: - raise ValueError("'{}' is not a valid substring of '{}' describing " - "a growth group.".format(factor, specification)) + raise ValueError("'{}' is not a valid substring of '{}' describing " "a growth group.".format(factor, specification)) split = split_str_by_op(factor, '^') if len(split) != 2: - raise ValueError("'{}' is an ambiguous substring of a growth group " - "description of '{}'. Use parentheses to make it " - "unique.".format(factor, ' * '.join(sfactors))) + raise ValueError("'{}' is an ambiguous substring of a growth group " "description of '{}'. Use parentheses to make it " "unique.".format(factor, ' * '.join(sfactors))) b, e = split b = remove_parentheses(b) e = remove_parentheses(e) - b, extend_B_by_non_growth_group = has_r_property( - b, ['_+'], invert=True) - e, extend_E_by_non_growth_group = has_r_property( - e, ['[I]', '[i]'], invert=False) + b, extend_B_by_non_growth_group = has_r_property(b, ['_+'], invert=True) + e, extend_E_by_non_growth_group = has_r_property(e, ['[I]', '[i]'], invert=False) e, l_E_only_imaginary_group = has_l_property(e, ['I*', 'I *']) e, r_E_only_imaginary_group = has_r_property(e, ['*I', '* I']) E_only_imaginary_group = l_E_only_imaginary_group or r_E_only_imaginary_group if E_only_imaginary_group and extend_E_by_non_growth_group: - raise ValueError("'{}' is not a valid substring of '{}' describing " - "a growth group.".format(factor, specification)) + raise ValueError("'{}' is not a valid substring of '{}' describing " "a growth group.".format(factor, specification)) try: B = repr_short_to_parent(b) @@ -5298,27 +5218,16 @@ def has_r_property(s, properties, invert=False) -> tuple[str, bool]: if B is None and E is None: from .misc import combine_exceptions - raise combine_exceptions( - ValueError("'{}' is not a valid substring of {} describing " - "a growth group.".format(factor, ' * '.join(sfactors))), - exc_b, exc_e) + + raise combine_exceptions(ValueError("'{}' is not a valid substring of {} describing " "a growth group.".format(factor, ' * '.join(sfactors))), exc_b, exc_e) elif B is None and E is not None: if E_only_imaginary_group: E = ImaginaryGroup(E) - factors.append(GrowthGroupFactor( - cls=MonomialGrowthGroup, - base=E, - var=b, - extend_by_non_growth_group=extend_E_by_non_growth_group)) + factors.append(GrowthGroupFactor(cls=MonomialGrowthGroup, base=E, var=b, extend_by_non_growth_group=extend_E_by_non_growth_group)) elif B is not None and E is None: - factors.append(GrowthGroupFactor( - cls=ExponentialGrowthGroup, - base=B, - var=e, - extend_by_non_growth_group=extend_B_by_non_growth_group)) + factors.append(GrowthGroupFactor(cls=ExponentialGrowthGroup, base=B, var=e, extend_by_non_growth_group=extend_B_by_non_growth_group)) else: - raise ValueError("'{}' is an ambiguous substring of a growth group " - "description of '{}'.".format(factor, ' * '.join(factors))) + raise ValueError("'{}' is an ambiguous substring of a growth group " "description of '{}'.".format(factor, ' * '.join(factors))) return tuple(factors), kwds @@ -5335,12 +5244,7 @@ def create_object(self, version, factors, **kwds): groups = [] non_growth_groups = [] for factor in factors: - grps = factor.cls.factory( - factor.base, - factor.var, - extend_by_non_growth_group=factor.extend_by_non_growth_group, - return_factors=True, - **kwds) + grps = factor.cls.factory(factor.base, factor.var, extend_by_non_growth_group=factor.extend_by_non_growth_group, return_factors=True, **kwds) for grp in grps: if isinstance(grp, GenericNonGrowthGroup): non_growth_groups.append(grp) @@ -5352,6 +5256,7 @@ def create_object(self, version, factors, **kwds): return groups[0] from sage.categories.cartesian_product import cartesian_product + return cartesian_product(groups) diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 5a7ab0c0d89..7b608e34dff 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -172,6 +172,7 @@ class CartesianProductFactory(UniqueFactory): sage: cartesian_product([G1, G2], category=G.category()) is G True """ + def create_key_and_extra_args(self, growth_groups, category, **kwds): r""" Given the arguments and keywords, create a key that uniquely @@ -190,6 +191,7 @@ def create_key_and_extra_args(self, growth_groups, category, **kwds): # CartesianProductPosets automatically add Posets() to their categories from sage.categories.category import Category from sage.categories.posets import Posets + if not isinstance(category, tuple): category = (category,) category = Category.join(category + (Posets(),)) @@ -217,20 +219,17 @@ def create_object(self, version, args, **kwds): # check if all groups have a variable if not all(v for v, _ in vg): - raise NotImplementedError('Growth groups %s have no variable.' % - tuple(g for g in growth_groups - if not g.variable_names())) + raise NotImplementedError('Growth groups %s have no variable.' % tuple(g for g in growth_groups if not g.variable_names())) # sort by variables from itertools import groupby, product - vgs = tuple((v, tuple(gs)) for v, gs in - groupby(sorted(vg, key=lambda k: k[0]), key=lambda k: k[0])) + + vgs = tuple((v, tuple(gs)) for v, gs in groupby(sorted(vg, key=lambda k: k[0]), key=lambda k: k[0])) # check whether variables are pairwise disjoint for u, w in product(iter(v for v, _ in vgs), repeat=2): if u != w and not set(u).isdisjoint(set(w)): - raise ValueError('The growth groups %s need to have pairwise ' - 'disjoint or equal variables.' % (growth_groups,)) + raise ValueError('The growth groups %s need to have pairwise ' 'disjoint or equal variables.' % (growth_groups,)) # build Cartesian products u_groups = list() @@ -310,11 +309,10 @@ def __init__(self, sets, category, **kwds): order = kwds.pop('order') CartesianProductPoset.__init__(self, sets, category, order, **kwds) - vars = sum(iter(factor.variable_names() - for factor in self.cartesian_factors()), - tuple()) + vars = sum(iter(factor.variable_names() for factor in self.cartesian_factors()), tuple()) from itertools import groupby from .growth_group import Variable + Vars = Variable(tuple(v for v, _ in groupby(vars)), repr=self._repr_short_()) GenericGrowthGroup.__init__(self, sets[0], Vars, self.category(), **kwds) @@ -346,9 +344,7 @@ def some_elements(self): x^(2/3)*log(x)^(-4)*(6/7)^y, x^(-2/3)*log(x)^5*(7/6)^y) """ - return iter( - self(c) for c in - zip(*tuple(F.some_elements() for F in self.cartesian_factors()))) + return iter(self(c) for c in zip(*tuple(F.some_elements() for F in self.cartesian_factors()))) def _create_element_in_extension_(self, element): r""" @@ -382,14 +378,12 @@ def _create_element_in_extension_(self, element): """ factors = self.cartesian_factors() if len(element) != len(factors): - raise ValueError('Cannot create %s as a Cartesian product like %s.' % - (element, self)) + raise ValueError('Cannot create %s as a Cartesian product like %s.' % (element, self)) if all(n.parent() is f for n, f in zip(element, factors)): parent = self else: - parent = self._underlying_class()(tuple(n.parent() for n in element), - category=self.category()) + parent = self._underlying_class()(tuple(n.parent() for n in element), category=self.category()) return parent(element) def _element_constructor_(self, data): @@ -473,8 +467,8 @@ def convert_factors(data, raw_data): return self._convert_factors_(data) except ValueError as e: from .misc import combine_exceptions - raise combine_exceptions( - ValueError('%s is not in %s.' % (raw_data, self)), e) + + raise combine_exceptions(ValueError('%s is not in %s.' % (raw_data, self)), e) if data == 1: return self.one() @@ -487,6 +481,7 @@ def convert_factors(data, raw_data): elif isinstance(data, str): from .misc import split_str_by_op + return convert_factors(split_str_by_op(data, '*'), data) elif hasattr(data, 'parent'): @@ -497,6 +492,7 @@ def convert_factors(data, raw_data): if P is SR: from sage.symbolic.operators import mul_vararg + if data.operator() == mul_vararg: return convert_factors(data.operands(), data) @@ -573,29 +569,19 @@ def get_factors(data): try: element, todo = e.element.split() except NotImplementedError as nie: - raise combine_exceptions( - ValueError('cannot split {}: no splitting ' - 'implemented'.format(e.element)), - nie) + raise combine_exceptions(ValueError('cannot split {}: no splitting ' 'implemented'.format(e.element)), nie) except ValueError as ve: - raise combine_exceptions( - ValueError('cannot split {} after failed ' - 'conversion into element of ' - '{}'.format(e.element, factor)), - ve) + raise combine_exceptions(ValueError('cannot split {} after failed ' 'conversion into element of ' '{}'.format(e.element, factor)), ve) assert todo is not None result.append((factor, element)) data = todo except (ValueError, TypeError) as error: errors.append(error) if not result: - raise combine_exceptions( - ValueError('%s is not in any of the factors of %s' % (data, self)), - *errors) + raise combine_exceptions(ValueError('%s is not in any of the factors of %s' % (data, self)), *errors) return result - return prod(self.cartesian_injection(*fs) - for f in factors for fs in get_factors(f)) + return prod(self.cartesian_injection(*fs) for f in factors for fs in get_factors(f)) def cartesian_injection(self, factor, element): r""" @@ -616,8 +602,7 @@ def cartesian_injection(self, factor, element): sage: G.cartesian_injection(G.cartesian_factors()[1], 'y^7') y^7 """ - return self(tuple((f.one() if f != factor else element) - for f in self.cartesian_factors())) + return self(tuple((f.one() if f != factor else element) for f in self.cartesian_factors())) def _coerce_map_from_(self, S): r""" @@ -647,8 +632,7 @@ def _coerce_map_from_(self, S): else: factors = (S,) - if all(any(g.has_coerce_map_from(f) for g in self.cartesian_factors()) - for f in factors): + if all(any(g.has_coerce_map_from(f) for g in self.cartesian_factors()) for f in factors): return True def _pushout_(self, other): @@ -735,23 +719,20 @@ def _pushout_(self, other): Ofactors = other.cartesian_factors() elif isinstance(other, GenericGrowthGroup): Ofactors = (other,) - elif (other.construction() is not None and - isinstance(other.construction()[0], AbstractGrowthGroupFunctor)): + elif other.construction() is not None and isinstance(other.construction()[0], AbstractGrowthGroupFunctor): Ofactors = (other,) else: return def pushout_univariate_factors(self, other, var, Sfactors, Ofactors): try: - return bidirectional_merge_sorted( - Sfactors, Ofactors, - lambda f: (f._underlying_class(), f._var_.var_repr)) + return bidirectional_merge_sorted(Sfactors, Ofactors, lambda f: (f._underlying_class(), f._var_.var_repr)) except RuntimeError: pass cm = get_coercion_model() try: - Z = cm.common_parent(*Sfactors+Ofactors) + Z = cm.common_parent(*Sfactors + Ofactors) return (Z,), (Z,) except TypeError: pass @@ -764,18 +745,13 @@ def subfactors(F): yield f try: - return bidirectional_merge_sorted( - tuple(subfactors(Sfactors)), tuple(subfactors(Ofactors)), - lambda f: (f._underlying_class(), f._var_.var_repr)) + return bidirectional_merge_sorted(tuple(subfactors(Sfactors)), tuple(subfactors(Ofactors)), lambda f: (f._underlying_class(), f._var_.var_repr)) except RuntimeError: pass from sage.structure.coerce_exceptions import CoercionException - raise CoercionException( - 'Cannot construct the pushout of %s and %s: The factors ' - 'with variables %s are not overlapping, ' - 'no common parent was found, and ' - 'splitting the factors was unsuccessful.' % (self, other, var)) + + raise CoercionException('Cannot construct the pushout of %s and %s: The factors ' 'with variables %s are not overlapping, ' 'no common parent was found, and ' 'splitting the factors was unsuccessful.' % (self, other, var)) # A wrapper around an iterator that stores additional intermediate data. # This deviates slightly from the iterator protocol: @@ -796,6 +772,7 @@ def next_custom(self): self.factors = tuple() from itertools import groupby + S = it(groupby(Sfactors, key=lambda k: k.variable_names())) O = it(groupby(Ofactors, key=lambda k: k.variable_names())) @@ -814,17 +791,15 @@ def next_custom(self): newO.extend(O.factors) O.next_custom() else: - SL, OL = pushout_univariate_factors(self, other, S.var, - S.factors, O.factors) + SL, OL = pushout_univariate_factors(self, other, S.var, S.factors, O.factors) newS.extend(SL) newO.extend(OL) S.next_custom() O.next_custom() - assert (len(newS) == len(newO)) + assert len(newS) == len(newO) - if (len(Sfactors) == len(newS) and - len(Ofactors) == len(newO)): + if len(Sfactors) == len(newS) and len(Ofactors) == len(newO): # We had already all factors in each of self and # other, thus splitting it in subproblems (one for # each factor) is the strategy to use. If a pushout is @@ -834,6 +809,7 @@ def next_custom(self): from sage.categories.pushout import pushout from sage.categories.cartesian_product import cartesian_product + return pushout(cartesian_product(newS), cartesian_product(newO)) def gens_monomial(self) -> tuple: @@ -860,10 +836,7 @@ def gens_monomial(self) -> tuple: sage: all(g.parent() == G for g in G.gens_monomial()) True """ - return sum(iter( - tuple(self.cartesian_injection(factor, g) for g in factor.gens_monomial()) - for factor in self.cartesian_factors()), - tuple()) + return sum(iter(tuple(self.cartesian_injection(factor, g) for g in factor.gens_monomial()) for factor in self.cartesian_factors()), tuple()) def variable_names(self): r""" @@ -877,15 +850,15 @@ def variable_names(self): sage: GrowthGroup('x^ZZ * log(x)^ZZ * y^QQ * log(z)^ZZ').variable_names() ('x', 'y', 'z') """ - vars = sum(iter(factor.variable_names() - for factor in self.cartesian_factors()), - tuple()) + vars = sum(iter(factor.variable_names() for factor in self.cartesian_factors()), tuple()) from itertools import groupby + return tuple(v for v, _ in groupby(vars)) class Element(CartesianProductPoset.Element): from .growth_group import _is_lt_one_ + is_lt_one = _is_lt_one_ def _repr_(self, latex=False): @@ -909,6 +882,7 @@ def _repr_(self, latex=False): """ if latex: from sage.misc.latex import latex as latex_repr + f = latex_repr else: f = repr @@ -962,8 +936,7 @@ def __pow__(self, exponent): sage: (x^(21/5) * log(x)^7)^(1/42) # indirect doctest x^(1/10)*log(x)^(1/6) """ - return self.parent()._create_element_in_extension_( - tuple(x ** exponent for x in self.cartesian_factors())) + return self.parent()._create_element_in_extension_(tuple(x**exponent for x in self.cartesian_factors())) def factors(self): r""" @@ -1002,12 +975,10 @@ def factors(self): sage: G.one().factors() () """ - return sum(iter(f.factors() - for f in self.cartesian_factors() - if not f.is_one()), - tuple()) + return sum(iter(f.factors() for f in self.cartesian_factors() if not f.is_one()), tuple()) from .growth_group import _log_factor_, _log_ + log = _log_ log_factor = _log_factor_ @@ -1051,20 +1022,14 @@ def try_create_growth(g): return g try: - return sum(iter(tuple((try_create_growth(g), c) - for g, c in - factor._log_factor_(base=base, - locals=locals)) - for factor in self.cartesian_factors() - if factor != factor.parent().one()), - tuple()) + return sum(iter(tuple((try_create_growth(g), c) for g, c in factor._log_factor_(base=base, locals=locals)) for factor in self.cartesian_factors() if factor != factor.parent().one()), tuple()) except (ArithmeticError, TypeError, ValueError) as e: from .misc import combine_exceptions - raise combine_exceptions( - ArithmeticError('Cannot build log(%s) in %s.' % - (self, self.parent())), e) + + raise combine_exceptions(ArithmeticError('Cannot build log(%s) in %s.' % (self, self.parent())), e) from .growth_group import _rpow_ + rpow = _rpow_ def _rpow_element_(self, base): @@ -1100,6 +1065,7 @@ def _rpow_element_(self, base): if len(factors) != 1: raise ValueError # calling method has to deal with it... from .growth_group import MonomialGrowthGroup + factor = factors[0] if not isinstance(factor.parent(), MonomialGrowthGroup): raise ValueError # calling method has to deal with it... @@ -1161,8 +1127,7 @@ def __invert__(self): sage: (~g).parent() Growth Group QQ^x * x^ZZ """ - return self.parent()._create_element_in_extension_( - tuple(~x for x in self.cartesian_factors())) + return self.parent()._create_element_in_extension_(tuple(~x for x in self.cartesian_factors())) def _substitute_(self, rules): r""" @@ -1202,12 +1167,12 @@ def _substitute_(self, rules): if self.is_one(): return rules['_one_'] from sage.symbolic.operators import mul_vararg + try: - return mul_vararg( - *tuple(x._substitute_(rules) - for x in self.cartesian_factors())) + return mul_vararg(*tuple(x._substitute_(rules) for x in self.cartesian_factors())) except (ArithmeticError, TypeError, ValueError) as e: from .misc import substitute_raise_exception + substitute_raise_exception(self, e) def _singularity_analysis_(self, var, zeta, precision): @@ -1268,39 +1233,25 @@ def _singularity_analysis_(self, var, zeta, precision): if len(factors) == 0: from .asymptotic_expansion_generators import asymptotic_expansions from .misc import NotImplementedOZero + raise NotImplementedOZero(var=var, exact_part=0) elif len(factors) == 1: - return factors[0]._singularity_analysis_( - var=var, zeta=zeta, precision=precision) + return factors[0]._singularity_analysis_(var=var, zeta=zeta, precision=precision) elif len(factors) == 2: from .growth_group import MonomialGrowthGroup from sage.rings.integer_ring import ZZ a, b = factors - if all(isinstance(f.parent(), MonomialGrowthGroup) - for f in factors) \ - and a.parent().gens_monomial() \ - and b.parent().gens_logarithmic() \ - and a.parent().variable_name() == \ - b.parent().variable_name(): + if all(isinstance(f.parent(), MonomialGrowthGroup) for f in factors) and a.parent().gens_monomial() and b.parent().gens_logarithmic() and a.parent().variable_name() == b.parent().variable_name(): if b.exponent not in ZZ: - raise NotImplementedError( - 'singularity analysis of {} not implemented ' - 'since exponent {} of {} is not an integer'.format( - self, b.exponent, b.parent().gen())) - - from sage.rings.asymptotic.asymptotic_expansion_generators import \ - asymptotic_expansions - return asymptotic_expansions.SingularityAnalysis( - var=var, zeta=zeta, alpha=a.exponent, - beta=ZZ(b.exponent), delta=0, - precision=precision, normalized=False) - raise NotImplementedError( - 'singularity analysis of {} not implemented'.format(self)) + raise NotImplementedError('singularity analysis of {} not implemented ' 'since exponent {} of {} is not an integer'.format(self, b.exponent, b.parent().gen())) + + from sage.rings.asymptotic.asymptotic_expansion_generators import asymptotic_expansions + + return asymptotic_expansions.SingularityAnalysis(var=var, zeta=zeta, alpha=a.exponent, beta=ZZ(b.exponent), delta=0, precision=precision, normalized=False) + raise NotImplementedError('singularity analysis of {} not implemented'.format(self)) else: - raise NotImplementedError( - 'singularity analysis of {} not yet implemented ' - 'since it has more than two factors'.format(self)) + raise NotImplementedError('singularity analysis of {} not yet implemented ' 'since it has more than two factors'.format(self)) def variable_names(self): r""" @@ -1323,10 +1274,9 @@ def variable_names(self): sage: G('m^0').variable_names() () """ - vars = sum(iter(factor.variable_names() - for factor in self.factors()), - tuple()) + vars = sum(iter(factor.variable_names() for factor in self.factors()), tuple()) from itertools import groupby + return tuple(v for v, _ in groupby(vars)) CartesianProduct = CartesianProductGrowthGroups @@ -1383,6 +1333,7 @@ class MultivariateProduct(GenericProduct): :class:`UnivariateProduct`, :class:`GenericProduct`. """ + def __init__(self, sets, category, **kwargs): r""" diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 740529a374e..5201b3b7916 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -90,17 +90,17 @@ def extract(s): e_se = e e_se.__traceback__ = None - raise combine_exceptions( - ValueError("Cannot create a parent out of '%s'." % (s,)), - e_ag, e_se) + raise combine_exceptions(ValueError("Cannot create a parent out of '%s'." % (s,)), e_ag, e_se) P = extract(s) from sage.misc.lazy_import import LazyImport + if type(P) is LazyImport: P = P._get_object() from sage.structure.parent import Parent + if not isinstance(P, Parent): raise ValueError("'%s' does not describe a parent." % (s,)) return P @@ -158,10 +158,7 @@ def abbreviate(P): return P._repr_short_() except AttributeError: pass - abbreviations = {ZZ: 'ZZ', QQ: 'QQ', SR: 'SR', - RR: 'RR', CC: 'CC', - RIF: 'RIF', CIF: 'CIF', - RBF: 'RBF', CBF: 'CBF'} + abbreviations = {ZZ: 'ZZ', QQ: 'QQ', SR: 'SR', RR: 'RR', CC: 'CC', RIF: 'RIF', CIF: 'CIF', RBF: 'RBF', CBF: 'CBF'} try: return abbreviations[P] except KeyError: @@ -253,6 +250,7 @@ def split_str_by_op(string, op, strip_parentheses=True): sage: split_str_by_op('(e^(n*log(n)))^SR.subring(no_variables=True)', '*') ('(e^(n*log(n)))^SR.subring(no_variables=True)',) """ + def is_balanced(s): open = 0 for l in s: @@ -267,16 +265,14 @@ def is_balanced(s): factors = [] balanced = True if string and op is not None and string.startswith(op): - raise ValueError("'%s' is invalid since it starts with a '%s'." % - (string, op)) + raise ValueError("'%s' is invalid since it starts with a '%s'." % (string, op)) for s in string.split(op): if not s: factors[-1] += op balanced = False continue if not s.strip(): - raise ValueError("'%s' is invalid since a '%s' follows a '%s'." % - (string, op, op)) + raise ValueError("'%s' is invalid since a '%s' follows a '%s'." % (string, op, op)) if not balanced: s = factors.pop() + (op if op else '') + s balanced = is_balanced(s) @@ -393,8 +389,8 @@ def combine_exceptions(e, *f): >> *previous* TypeError: Inner. """ import re - msg = ('\n *previous* ' + - '\n *and* '.join("%s: %s" % (ff.__class__.__name__, str(ff)) for ff in f)) + + msg = '\n *previous* ' + '\n *and* '.join("%s: %s" % (ff.__class__.__name__, str(ff)) for ff in f) msg = re.sub(r'^([>]* \*previous\*)', r'>\1', msg, flags=re.MULTILINE) msg = re.sub(r'^([>]* \*and\*)', r'>\1', msg, flags=re.MULTILINE) msg = str(e.args if len(e.args) > 1 else e.args[0]) + msg @@ -423,9 +419,7 @@ def substitute_raise_exception(element, e): Exception: Cannot substitute in x in Symbolic Ring. > *previous* Exception: blub """ - raise combine_exceptions( - type(e)('Cannot substitute in %s in %s.' % - (element, element.parent())), e) + raise combine_exceptions(type(e)('Cannot substitute in %s in %s.' % (element, element.parent())), e) def bidirectional_merge_overlapping(A, B, key=None): @@ -520,8 +514,7 @@ def bidirectional_merge_overlapping(A, B, key=None): def find_overlapping_index(A, B): if len(B) > len(A) - 2: raise StopIteration - matches = iter(i for i in range(1, len(A) - len(B)) - if A[i:i+len(B)] == B) + matches = iter(i for i in range(1, len(A) - len(B)) if A[i : i + len(B)] == B) return next(matches) def find_mergedoverlapping_index(A, B): @@ -532,8 +525,7 @@ def find_mergedoverlapping_index(A, B): Adapted from https://stackoverflow.com/a/30056066/1052778. """ - matches = iter(i for i in range(min(len(A), len(B)), 0, -1) - if A[-i:] == B[:i]) + matches = iter(i for i in range(min(len(A), len(B)), 0, -1) if A[-i:] == B[:i]) return next(matches, 0) i = find_mergedoverlapping_index(Akeys, Bkeys) @@ -549,14 +541,14 @@ def find_mergedoverlapping_index(A, B): except StopIteration: pass else: - return A, A[:i] + B + A[i+len(B):] + return A, A[:i] + B + A[i + len(B) :] try: i = find_overlapping_index(Bkeys, Akeys) except StopIteration: pass else: - return B[:i] + A + B[i+len(A):], B + return B[:i] + A + B[i + len(A) :], B raise ValueError('Input does not have an overlap.') @@ -667,10 +659,7 @@ def bidirectional_merge_sorted(A, B, key=None): Akeys = tuple(key(a) for a in A) Bkeys = tuple(key(b) for b in B) - matches = tuple((i, j) - for i, a in enumerate(Akeys) - for j, b in enumerate(Bkeys) - if a == b) + matches = tuple((i, j) for i, a in enumerate(Akeys) for j, b in enumerate(Bkeys) if a == b) if not matches: raise RuntimeError('no common elements') @@ -682,17 +671,17 @@ def bidirectional_merge_sorted(A, B, key=None): if not all(a <= b for a, b in zip(last, current)): raise RuntimeError('sorting in lists not compatible') if last[0] == current[0]: - resultA.extend(B[last[1]:current[1]]) - resultB.extend(B[last[1]:current[1]]) + resultA.extend(B[last[1] : current[1]]) + resultB.extend(B[last[1] : current[1]]) elif last[1] == current[1]: - resultA.extend(A[last[0]:current[0]]) - resultB.extend(A[last[0]:current[0]]) + resultA.extend(A[last[0] : current[0]]) + resultB.extend(A[last[0] : current[0]]) else: raise RuntimeError('sorting not unique') if current != end: resultA.append(A[current[0]]) resultB.append(B[current[1]]) - last = (current[0]+1, current[1]+1) + last = (current[0] + 1, current[1] + 1) return (resultA, resultB) @@ -771,6 +760,7 @@ class NotImplementedOZero(NotImplementedError): which is raised when the result is O(0) which means 0 for sufficiently large values of the variable. """ + def __init__(self, asymptotic_ring=None, var=None, exact_part=0): r""" INPUT: @@ -817,10 +807,7 @@ def __init__(self, asymptotic_ring=None, var=None, exact_part=0): if var is None: var = ', '.join(str(g) for g in asymptotic_ring.gens()) - message = ('got {}\n'.format(('{} + '.format(exact_part) if exact_part else '') - + 'O(0)') + - 'The error term O(0) ' - 'means 0 for sufficiently large {}.'.format(var)) + message = 'got {}\n'.format(('{} + '.format(exact_part) if exact_part else '') + 'O(0)') + 'The error term O(0) ' 'means 0 for sufficiently large {}.'.format(var) if asymptotic_ring is not None and isinstance(exact_part, int) and exact_part == 0: exact_part = asymptotic_ring.zero() @@ -835,6 +822,7 @@ class NotImplementedBZero(NotImplementedError): which is raised when the result is B(0) which means 0 for sufficiently large values of the variable. """ + def __init__(self, asymptotic_ring=None, var=None, exact_part=0): r""" INPUT: @@ -888,10 +876,7 @@ def __init__(self, asymptotic_ring=None, var=None, exact_part=0): if var is None: var = ', '.join(str(g) for g in asymptotic_ring.gens()) - message = ('got {}\n'.format(('{} + '.format(exact_part) if exact_part else '') - + 'B(0)') + - 'The error term B(0) ' - 'means 0 for sufficiently large {}.'.format(var)) + message = 'got {}\n'.format(('{} + '.format(exact_part) if exact_part else '') + 'B(0)') + 'The error term B(0) ' 'means 0 for sufficiently large {}.'.format(var) if asymptotic_ring is not None and isinstance(exact_part, int) and exact_part == 0: exact_part = asymptotic_ring.zero() @@ -900,9 +885,7 @@ def __init__(self, asymptotic_ring=None, var=None, exact_part=0): super().__init__(message) -def transform_category(category, - subcategory_mapping, axiom_mapping, - initial_category=None): +def transform_category(category, subcategory_mapping, axiom_mapping, initial_category=None): r""" Transform ``category`` to a new category according to the given mappings. @@ -1009,6 +992,7 @@ def transform_category(category, """ if initial_category is None: from sage.categories.objects import Objects + result = Objects() else: result = initial_category @@ -1017,16 +1001,14 @@ def transform_category(category, if category.is_subcategory(A): result &= B elif mandatory: - raise ValueError('%s is not a subcategory of %s.' % - (category, A)) + raise ValueError('%s is not a subcategory of %s.' % (category, A)) axioms = category.axioms() for A, B, mandatory in axiom_mapping: if A in axioms: result = result._with_axiom(B) elif mandatory: - raise ValueError('%s does not have axiom %s.' % - (category, A)) + raise ValueError('%s does not have axiom %s.' % (category, A)) return result @@ -1049,6 +1031,7 @@ class Locals(dict): sage: locals['log'] """ + def __getitem__(self, key): r""" Return an item. @@ -1135,8 +1118,8 @@ def default_locals(self): """ from sage.functions.log import log - return { - 'log': log} + + return {'log': log} class WithLocals(SageObject): @@ -1153,6 +1136,7 @@ class WithLocals(SageObject): sage: A.locals() {'a': 42} """ + @staticmethod def _convert_locals_(locals): r""" diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index 4d6e9e2ad78..ee97ff906fc 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -209,6 +209,7 @@ Classes and Methods =================== """ + # ***************************************************************************** # Copyright (C) 2014--2015 Benjamin Hackl # 2014--2015 Daniel Krenn @@ -415,8 +416,7 @@ def construction(self): :meth:`TermWithCoefficient.construction`, :meth:`GenericTermMonoid.from_construction` """ - return (self.__class__, {'parent': self.parent(), - 'growth': self.growth}) + return (self.__class__, {'parent': self.parent(), 'growth': self.growth}) def _mul_(self, other): r""" @@ -479,8 +479,7 @@ def __invert__(self): NotImplementedError: Inversion of Generic Term with growth x^2 not implemented (in this abstract method). """ - raise NotImplementedError('Inversion of %s not implemented ' - '(in this abstract method).' % (self,)) + raise NotImplementedError('Inversion of %s not implemented ' '(in this abstract method).' % (self,)) def __pow__(self, exponent): r""" @@ -510,8 +509,7 @@ def __pow__(self, exponent): NotImplementedError: Taking powers of Generic Term with growth z not implemented (in this abstract method). """ - raise NotImplementedError('Taking powers of %s not implemented ' - '(in this abstract method).' % (self,)) + raise NotImplementedError('Taking powers of %s not implemented ' '(in this abstract method).' % (self,)) def _calculate_pow_test_zero_(self, exponent): r""" @@ -557,12 +555,11 @@ def _calculate_pow_test_zero_(self, exponent): zero = self.parent().coefficient_ring.zero() try: - zero ** exponent + zero**exponent except (TypeError, ValueError, ZeroDivisionError) as e: from .misc import combine_exceptions - raise combine_exceptions( - ZeroDivisionError('Cannot take %s to exponent %s.' % - (self, exponent)), e) + + raise combine_exceptions(ZeroDivisionError('Cannot take %s to exponent %s.' % (self, exponent)), e) return self._calculate_pow_(exponent) def _calculate_pow_(self, exponent, new_coefficient=None): @@ -604,11 +601,11 @@ def _calculate_pow_(self, exponent, new_coefficient=None): (implicit) coefficients in Integer Ring does not support coefficients. """ try: - g = self.growth ** exponent + g = self.growth**exponent except (ValueError, TypeError, ZeroDivisionError) as e: from .misc import combine_exceptions - raise combine_exceptions( - ValueError('Cannot take %s to the exponent %s.' % (self, exponent)), e) + + raise combine_exceptions(ValueError('Cannot take %s to the exponent %s.' % (self, exponent)), e) return self.parent()._create_element_in_extension_(g, new_coefficient) @@ -740,9 +737,7 @@ def absorb(self, other, check=True): from sage.structure.element import get_coercion_model - return get_coercion_model().bin_op(self, other, - lambda left, right: - left._absorb_(right)) + return get_coercion_model().bin_op(self, other, lambda left, right: left._absorb_(right)) def _absorb_(self, other): r""" @@ -845,8 +840,7 @@ def log_term(self, base=None, locals=None): :meth:`ExactTerm.log_term`, :meth:`OTerm.log_term`. """ - raise NotImplementedError('This method is not implemented in this ' - 'abstract base class.') + raise NotImplementedError('This method is not implemented in this ' 'abstract base class.') def _log_growth_(self, base=None, locals=None): r""" @@ -879,10 +873,7 @@ def _log_growth_(self, base=None, locals=None): :meth:`ExactTerm.log_term`, :meth:`OTerm.log_term`. """ - return tuple(self.parent()._create_element_in_extension_(g, c) - for g, c in - self.growth.log_factor(base=base, - locals=locals)) + return tuple(self.parent()._create_element_in_extension_(g, c) for g, c in self.growth.log_factor(base=base, locals=locals)) _richcmp_ = richcmp_by_eq_and_lt("_eq_", "_lt_") @@ -1122,8 +1113,7 @@ def is_little_o_of_one(self): is o(1) in the abstract base class TermWithCoefficient Monoid x^ZZ with coefficients in Rational Field. """ - raise NotImplementedError('Cannot check whether %s is o(1) in the ' - 'abstract base class %s.' % (self, self.parent())) + raise NotImplementedError('Cannot check whether %s is o(1) in the ' 'abstract base class %s.' % (self, self.parent())) def rpow(self, base): r""" @@ -1149,8 +1139,7 @@ def rpow(self, base): Generic Term with growth x*log(x) in the abstract base class GenericTerm Monoid x^ZZ * log(x)^ZZ with (implicit) coefficients in Rational Field. """ - raise NotImplementedError('Cannot take %s to the exponent %s in the ' - 'abstract base class %s.' % (base, self, self.parent())) + raise NotImplementedError('Cannot take %s to the exponent %s in the ' 'abstract base class %s.' % (base, self, self.parent())) def _repr_(self): r""" @@ -1224,9 +1213,8 @@ def _substitute_(self, rules): GenericTerm Monoid x^ZZ with (implicit) coefficients in Integer Ring. """ from .misc import substitute_raise_exception - substitute_raise_exception(self, TypeError( - 'Cannot substitute in the abstract ' - 'base class %s.' % (self.parent(),))) + + substitute_raise_exception(self, TypeError('Cannot substitute in the abstract ' 'base class %s.' % (self.parent(),))) def variable_names(self): r""" @@ -1270,8 +1258,7 @@ def _factorial_(self): NotImplementedError: Cannot build the factorial of Generic Term with growth x^(1/2). """ - raise NotImplementedError( - 'Cannot build the factorial of {}.'.format(self)) + raise NotImplementedError('Cannot build the factorial of {}.'.format(self)) def _singularity_analysis_(self, var, zeta, precision): r""" @@ -1305,8 +1292,7 @@ def _singularity_analysis_(self, var, zeta, precision): NotImplementedError: singularity analysis of Generic Term with growth x not implemented """ - raise NotImplementedError('singularity analysis of {} ' - 'not implemented '.format(self)) + raise NotImplementedError('singularity analysis of {} ' 'not implemented '.format(self)) class GenericTermMonoid(UniqueRepresentation, Parent, WithLocals): @@ -1356,9 +1342,7 @@ class GenericTermMonoid(UniqueRepresentation, Parent, WithLocals): Element = GenericTerm @staticmethod - def __classcall__(cls, term_monoid_factory, - growth_group, coefficient_ring, - category=None): + def __classcall__(cls, term_monoid_factory, growth_group, coefficient_ring, category=None): r""" Normalize the input in order to ensure a unique representation of the parent. @@ -1411,10 +1395,10 @@ def __classcall__(cls, term_monoid_factory, if category is None: from sage.categories.monoids import Monoids from sage.categories.posets import Posets + category = Monoids() & Posets() - return super().__classcall__( - cls, term_monoid_factory, growth_group, coefficient_ring, category) + return super().__classcall__(cls, term_monoid_factory, growth_group, coefficient_ring, category) def __init__(self, term_monoid_factory, growth_group, coefficient_ring, category): r""" @@ -1510,9 +1494,7 @@ def term_monoid(self, type): True """ TermMonoid = self.term_monoid_factory - return TermMonoid(type, - growth_group=self.growth_group, - coefficient_ring=self.coefficient_ring) + return TermMonoid(type, growth_group=self.growth_group, coefficient_ring=self.coefficient_ring) @property def growth_group(self): @@ -1583,8 +1565,7 @@ def change_parameter(self, growth_group=None, coefficient_ring=None): growth_group = self.growth_group if coefficient_ring is None: coefficient_ring = self.coefficient_ring - if self.growth_group is growth_group and \ - self.coefficient_ring is coefficient_ring: + if self.growth_group is growth_group and self.coefficient_ring is coefficient_ring: return self return self.term_monoid_factory(self, growth_group, coefficient_ring) @@ -1605,8 +1586,7 @@ def _repr_(self): sage: GenericTermMonoid(TermMonoid, GrowthGroup('x^ZZ'), QQ)._repr_() 'GenericTerm Monoid x^ZZ with (implicit) coefficients in Rational Field' """ - return 'GenericTerm Monoid %s with (implicit) coefficients in %s' % \ - (self.growth_group._repr_short_(), self.coefficient_ring) + return 'GenericTerm Monoid %s with (implicit) coefficients in %s' % (self.growth_group._repr_short_(), self.coefficient_ring) def _coerce_map_from_(self, S): r""" @@ -1660,8 +1640,7 @@ def _coerce_map_from_(self, S): False """ if isinstance(S, self.__class__): - if self.growth_group.has_coerce_map_from(S.growth_group) and \ - self.coefficient_ring.has_coerce_map_from(S.coefficient_ring): + if self.growth_group.has_coerce_map_from(S.growth_group) and self.coefficient_ring.has_coerce_map_from(S.coefficient_ring): return True def _element_constructor_(self, data, **kwds): @@ -1777,33 +1756,26 @@ def _element_constructor_(self, data, **kwds): if isinstance(data, GenericTerm): return self.from_construction(data.construction(), **kwds) if isinstance(data, int) and data == 0: - raise ValueError('No input specified. Cannot continue ' - 'creating an element of %s.' % (self,)) + raise ValueError('No input specified. Cannot continue ' 'creating an element of %s.' % (self,)) from .misc import combine_exceptions + coefficient = kwds.pop('coefficient', None) if coefficient is not None: growth = data if 'growth' in kwds: raise ValueError(f"Argument 'growth={kwds['growth']}' is ambiguous.") - return self.from_construction((None, - {'growth': growth, - 'coefficient': coefficient}), - **kwds) + return self.from_construction((None, {'growth': growth, 'coefficient': coefficient}), **kwds) try: growth, coefficient = self._split_growth_and_coefficient_(data) except ValueError as e: - raise combine_exceptions( - ValueError('%s is not in %s.' % (data, self)), e) + raise combine_exceptions(ValueError('%s is not in %s.' % (data, self)), e) if 'growth' in kwds: raise ValueError(f"Argument 'growth={kwds['growth']}' is ambiguous.") - return self.from_construction((None, - {'growth': growth, - 'coefficient': coefficient}), - **kwds) + return self.from_construction((None, {'growth': growth, 'coefficient': coefficient}), **kwds) def _validate_growth_or_error_(self, kwds_construction): r""" @@ -1861,8 +1833,8 @@ def _validate_growth_or_error_(self, kwds_construction): except (ValueError, TypeError) as e: growth = kwds_construction['growth'] from .misc import combine_exceptions - raise combine_exceptions( - ValueError(f'Growth {growth} is not valid in {self}.'), e) + + raise combine_exceptions(ValueError(f'Growth {growth} is not valid in {self}.'), e) kwds_construction['growth'] = growth def _validate_coefficient_or_error_(self, kwds_construction): @@ -1923,10 +1895,8 @@ def _validate_coefficient_or_error_(self, kwds_construction): element_name = self.Element.__name__ growth = kwds_construction['growth'] from .misc import combine_exceptions - raise combine_exceptions( - ValueError(f'Cannot create {element_name}({growth}) ' - f'since given coefficient {coefficient} ' - f'is not valid in {self}.'), e) + + raise combine_exceptions(ValueError(f'Cannot create {element_name}({growth}) ' f'since given coefficient {coefficient} ' f'is not valid in {self}.'), e) if 'coefficient' in kwds_construction: kwds_construction['coefficient'] = coefficient @@ -1989,8 +1959,7 @@ def _convert_construction_(self, kwds_construction): """ coefficient = kwds_construction.pop('coefficient', None) if coefficient is not None and coefficient != self.coefficient_ring.one(): - raise ValueError('Coefficient %s is not 1, but %s does not ' - 'support coefficients.' % (coefficient, self)) + raise ValueError('Coefficient %s is not 1, but %s does not ' 'support coefficients.' % (coefficient, self)) if 'parent' in kwds_construction and isinstance(kwds_construction['parent'], BTermMonoid): try: @@ -2097,16 +2066,10 @@ def _create_element_in_extension_(self, growth, coefficient): sage: T._create_element_in_extension_(G.an_element(), 3/2).parent() Exact Term Monoid z^ZZ with coefficients in Rational Field """ - if (growth.parent() is self.growth_group) and \ - (coefficient is None or coefficient.parent() is self.coefficient_ring): + if (growth.parent() is self.growth_group) and (coefficient is None or coefficient.parent() is self.coefficient_ring): parent = self else: - parent = self._underlying_class()(self.term_monoid_factory, - growth.parent(), - coefficient.parent() - if coefficient is not None - else self.coefficient_ring, - category=self.category()) + parent = self._underlying_class()(self.term_monoid_factory, growth.parent(), coefficient.parent() if coefficient is not None else self.coefficient_ring, category=self.category()) return parent(growth, coefficient=coefficient) def _split_growth_and_coefficient_(self, data): @@ -2181,11 +2144,10 @@ def _split_growth_and_coefficient_(self, data): except (ValueError, TypeError): pass - raise ValueError('Factor %s of %s is neither a coefficient (in %s) ' - 'nor growth (in %s).' % - (f, data, coefficient_ring, growth_group)) + raise ValueError('Factor %s of %s is neither a coefficient (in %s) ' 'nor growth (in %s).' % (f, data, coefficient_ring, growth_group)) from sage.misc.misc_c import prod + growth = prod(growths) if growths else growth_group.one() coefficient = prod(coefficients) if coefficients else coefficient_ring.one() return (growth, coefficient) @@ -2211,6 +2173,7 @@ def _get_factors_(self, data): """ if isinstance(data, str): from .misc import split_str_by_op + return split_str_by_op(data, '*') try: @@ -2219,8 +2182,10 @@ def _get_factors_(self, data): return (data,) from sage.symbolic.ring import SymbolicRing + if isinstance(P, SymbolicRing): from sage.symbolic.operators import mul_vararg + if data.operator() == mul_vararg: return tuple(data.operands()) @@ -2362,6 +2327,7 @@ def _repr_(self, latex=False): """ if latex: from sage.misc.latex import latex as latex_repr + f = latex_repr else: f = repr @@ -2442,6 +2408,7 @@ def __pow__(self, exponent): > *previous* ZeroDivisionError: rational division by zero """ from .misc import strip_symbolic + return self._calculate_pow_test_zero_(strip_symbolic(exponent)) def can_absorb(self, other): @@ -2651,11 +2618,8 @@ def rpow(self, base): return self if base == 1: P = self.parent() - return P.term_monoid_factory('exact', - P.growth_group, - P.coefficient_ring).one() - raise ValueError('Cannot take %s to the exponent %s in %s' % - (base, self, self.parent())) + return P.term_monoid_factory('exact', P.growth_group, P.coefficient_ring).one() + raise ValueError('Cannot take %s to the exponent %s in %s' % (base, self, self.parent())) def _substitute_(self, rules): r""" @@ -2703,6 +2667,7 @@ def _substitute_(self, rules): g = self.growth._substitute_(rules) except (ArithmeticError, TypeError, ValueError) as e: from .misc import substitute_raise_exception + substitute_raise_exception(self, e) try: @@ -2728,6 +2693,7 @@ def _substitute_(self, rules): return O(g) except (ArithmeticError, TypeError, ValueError) as e: from .misc import substitute_raise_exception + substitute_raise_exception(self, e) def _factorial_(self): @@ -2750,9 +2716,7 @@ def _factorial_(self): since it has growth != 1. """ if not self.growth.is_one(): - raise ValueError( - 'Cannot build the factorial of {} since it has growth ' - '!= 1.'.format(self)) + raise ValueError('Cannot build the factorial of {} since it has growth ' '!= 1.'.format(self)) return self @@ -2785,8 +2749,7 @@ def _singularity_analysis_(self, var, zeta, precision): sage: T('x^(-1)')._singularity_analysis_('n', 2, precision=3) O((1/2)^n*n^(-2)) """ - return self.growth._singularity_analysis_( - var=var, zeta=zeta, precision=0) + return self.growth._singularity_analysis_(var=var, zeta=zeta, precision=0) class OTermMonoid(GenericTermMonoid): @@ -2930,9 +2893,14 @@ def _coerce_map_from_(self, S): sage: OT_ZZ.has_coerce_map_from(ET) # indirect doctest True """ - if isinstance(S, (ExactTermMonoid, BTermMonoid,)): - if self.growth_group.has_coerce_map_from(S.growth_group) and \ - self.coefficient_ring.has_coerce_map_from(S.coefficient_ring): + if isinstance( + S, + ( + ExactTermMonoid, + BTermMonoid, + ), + ): + if self.growth_group.has_coerce_map_from(S.growth_group) and self.coefficient_ring.has_coerce_map_from(S.coefficient_ring): return True else: return super()._coerce_map_from_(S) @@ -2951,8 +2919,7 @@ def _repr_(self): sage: TermMonoid('O', G, QQ)._repr_() 'O-Term Monoid x^ZZ with implicit coefficients in Rational Field' """ - return 'O-Term Monoid %s with implicit coefficients in %s' % \ - (self.growth_group._repr_short_(), self.coefficient_ring) + return 'O-Term Monoid %s with implicit coefficients in %s' % (self.growth_group._repr_short_(), self.coefficient_ring) class TermWithCoefficient(GenericTerm): @@ -3031,12 +2998,9 @@ def __init__(self, parent, growth, coefficient): try: coefficient = parent.coefficient_ring(coefficient) except (ValueError, TypeError): - raise ValueError('%s is not a coefficient in %s.' % - (coefficient, parent)) + raise ValueError('%s is not a coefficient in %s.' % (coefficient, parent)) if coefficient == 0: - raise ZeroCoefficientError( - 'Zero coefficient %s is not allowed in %s.' % - (coefficient, parent)) + raise ZeroCoefficientError('Zero coefficient %s is not allowed in %s.' % (coefficient, parent)) self.coefficient = coefficient @@ -3090,8 +3054,7 @@ def _repr_(self): sage: T(x^2, coefficient=5)._repr_() 'Term with coefficient 5 and growth x^2' """ - return 'Term with coefficient %s and growth %s' % \ - (self.coefficient, self.growth) + return 'Term with coefficient %s and growth %s' % (self.coefficient, self.growth) def _repr_product_(self, latex=False): r""" @@ -3118,6 +3081,7 @@ def _repr_product_(self, latex=False): """ if latex: from sage.misc.latex import latex as latex_repr + f = latex_repr else: f = repr @@ -3141,6 +3105,7 @@ def _repr_product_(self, latex=False): if latex: import re + s = re.sub(r'([0-9])\s+([0-9])', r'\1 \\cdot \2', s) return s @@ -3187,8 +3152,7 @@ def _mul_(self, other): sage: t1 * t2 6*x^5 """ - return self.parent()(self.growth * other.growth, - coefficient=self.coefficient * other.coefficient) + return self.parent()(self.growth * other.growth, coefficient=self.coefficient * other.coefficient) def _calculate_pow_(self, exponent): r""" @@ -3231,13 +3195,11 @@ def _calculate_pow_(self, exponent): interval strictly containing zero """ try: - c = self.coefficient ** exponent + c = self.coefficient**exponent except (TypeError, ValueError, ZeroDivisionError) as e: from .misc import combine_exceptions - raise combine_exceptions( - ArithmeticError('Cannot take %s to the exponent %s in %s since its ' - 'coefficient %s cannot be taken to this exponent.' % - (self, exponent, self.parent(), self.coefficient)), e) + + raise combine_exceptions(ArithmeticError('Cannot take %s to the exponent %s in %s since its ' 'coefficient %s cannot be taken to this exponent.' % (self, exponent, self.parent(), self.coefficient)), e) return super()._calculate_pow_(exponent, new_coefficient=c) def _log_coefficient_(self, base=None, locals=None): @@ -3288,9 +3250,7 @@ def _log_coefficient_(self, base=None, locals=None): if self.coefficient.is_one(): return tuple() log = self.parent().locals(locals)['log'] - return (self.parent()._create_element_in_extension_( - self.parent().growth_group.one(), - log(self.coefficient, base=base)),) + return (self.parent()._create_element_in_extension_(self.parent().growth_group.one(), log(self.coefficient, base=base)),) def _eq_(self, other): r""" @@ -3387,8 +3347,7 @@ def _repr_(self): sage: TermWithCoefficientMonoid(TermMonoid, GrowthGroup('x^ZZ'), QQ)._repr_() 'TermWithCoefficient Monoid x^ZZ with coefficients in Rational Field' """ - return 'TermWithCoefficient Monoid %s with coefficients in %s' % \ - (self.growth_group._repr_short_(), self.coefficient_ring) + return 'TermWithCoefficient Monoid %s with coefficients in %s' % (self.growth_group._repr_short_(), self.coefficient_ring) def _validate_coefficient_or_error_(self, kwds_construction): r""" @@ -3444,8 +3403,7 @@ def _validate_coefficient_or_error_(self, kwds_construction): if coefficient is None: element_name = self.Element.__name__ growth = kwds_construction['growth'] - raise ValueError(f'Cannot create {element_name}({growth}) ' - f'since no coefficient is given.') + raise ValueError(f'Cannot create {element_name}({growth}) ' f'since no coefficient is given.') super()._validate_coefficient_or_error_(kwds_construction) def _default_kwds_construction_(self): @@ -3529,8 +3487,7 @@ def _an_element_(self): sage: TermMonoid('exact', G, QQ).an_element() # indirect doctest 1/2*x """ - return self(self.growth_group.an_element(), - coefficient=self.coefficient_ring.an_element()) + return self(self.growth_group.an_element(), coefficient=self.coefficient_ring.an_element()) def some_elements(self): r""" @@ -3552,9 +3509,8 @@ def some_elements(self): z^(-2), -z^2, 2*z^(-1/2), -2*z^(1/2)) """ from sage.misc.mrange import cantor_product - return (self(g, coefficient=c) for g, c in cantor_product( - self.growth_group.some_elements(), - (c for c in self.coefficient_ring.some_elements() if c != 0))) + + return (self(g, coefficient=c) for g, c in cantor_product(self.growth_group.some_elements(), (c for c in self.coefficient_ring.some_elements() if c != 0))) class ExactTerm(TermWithCoefficient): @@ -3724,8 +3680,7 @@ def __invert__(self): try: c = ~self.coefficient except ZeroDivisionError: - raise ZeroDivisionError('Cannot invert %s since its coefficient %s ' - 'cannot be inverted.' % (self, self.coefficient)) + raise ZeroDivisionError('Cannot invert %s since its coefficient %s ' 'cannot be inverted.' % (self, self.coefficient)) g = ~self.growth return self.parent()._create_element_in_extension_(g, c) @@ -3753,6 +3708,7 @@ def __pow__(self, exponent): sqrt(2)*z^(1/2) """ from .misc import strip_symbolic + return self._calculate_pow_(strip_symbolic(exponent)) def can_absorb(self, other): @@ -3882,8 +3838,7 @@ def log_term(self, base=None, locals=None): :meth:`OTerm.log_term`. """ - return (self._log_coefficient_(base=base, locals=locals) - + self._log_growth_(base=base, locals=locals)) + return self._log_coefficient_(base=base, locals=locals) + self._log_growth_(base=base, locals=locals) def is_constant(self): r""" @@ -4027,12 +3982,10 @@ def rpow(self, base): if self.is_constant(): if not hasattr(base, 'parent'): base = P.coefficient_ring(base) - return P._create_element_in_extension_( - P.growth_group.one(), base ** self.coefficient) + return P._create_element_in_extension_(P.growth_group.one(), base**self.coefficient) - elem = P._create_element_in_extension_( - self.growth.rpow(base), P.coefficient_ring.one()) - return elem ** self.coefficient + elem = P._create_element_in_extension_(self.growth.rpow(base), P.coefficient_ring.one()) + return elem**self.coefficient def _substitute_(self, rules): r""" @@ -4073,6 +4026,7 @@ def _substitute_(self, rules): g = self.growth._substitute_(rules) except (ArithmeticError, TypeError, ValueError) as e: from .misc import substitute_raise_exception + substitute_raise_exception(self, e) c = self.coefficient @@ -4081,6 +4035,7 @@ def _substitute_(self, rules): return c * g except (ArithmeticError, TypeError, ValueError) as e: from .misc import substitute_raise_exception + substitute_raise_exception(self, e) def _factorial_(self): @@ -4105,13 +4060,11 @@ def _factorial_(self): since it has growth != 1. """ if not self.growth.is_one(): - raise ValueError( - 'Cannot build the factorial of {} since it has growth ' - '!= 1.'.format(self)) + raise ValueError('Cannot build the factorial of {} since it has growth ' '!= 1.'.format(self)) from sage.functions.other import factorial - return self.parent()._create_element_in_extension_( - self.growth, factorial(self.coefficient)) + + return self.parent()._create_element_in_extension_(self.growth, factorial(self.coefficient)) def _singularity_analysis_(self, var, zeta, precision): r""" @@ -4147,8 +4100,7 @@ def _singularity_analysis_(self, var, zeta, precision): NotImplementedOZero: got O(0) The error term O(0) means 0 for sufficiently large n. """ - return self.coefficient * self.growth._singularity_analysis_( - var=var, zeta=zeta, precision=precision) + return self.coefficient * self.growth._singularity_analysis_(var=var, zeta=zeta, precision=precision) class ExactTermMonoid(TermWithCoefficientMonoid): @@ -4261,8 +4213,7 @@ def _repr_(self): sage: TermMonoid('exact', G, QQ)._repr_() 'Exact Term Monoid x^ZZ with coefficients in Rational Field' """ - return 'Exact Term Monoid %s with coefficients in %s' % \ - (self.growth_group._repr_short_(), self.coefficient_ring) + return 'Exact Term Monoid %s with coefficients in %s' % (self.growth_group._repr_short_(), self.coefficient_ring) class BTerm(TermWithCoefficient): @@ -4320,6 +4271,7 @@ class BTerm(TermWithCoefficient): sage: T(x^3*y^2, coefficient=42, valid_from={'x': 10, 'y': 20}) B(42*x^3*y^2, x >= 10, y >= 20) """ + def __init__(self, parent, growth, valid_from, **kwds): r""" See :class:`BTerm` for more information. @@ -4445,11 +4397,9 @@ def _repr_(self, latex=False): B(4*x^2, x >= 10, y >= 15) """ if latex: - valid_from_string = ', '.join(fr'{variable} \ge {value}' - for variable, value in self.valid_from.items()) + valid_from_string = ', '.join(fr'{variable} \ge {value}' for variable, value in self.valid_from.items()) return fr'B_{{{valid_from_string}}}\left({self._repr_product_(latex=True)}\right)' - valid_from_string = ''.join(f', {variable} >= {value}' - for variable, value in self.valid_from.items()) + valid_from_string = ''.join(f', {variable} >= {value}' for variable, value in self.valid_from.items()) return f'B({self._repr_product_()}{valid_from_string})' def _latex_(self): @@ -4506,13 +4456,8 @@ def _mul_(self, other): sage: BTM(n^5, coefficient=21, valid_from={'n': 3}) * OTM(n) O(n^6) """ - valid_from = { - var: max(self.valid_from.get(var, 0), other.valid_from.get(var, 0)) - for var in set().union(self.valid_from, other.valid_from) - } - return self.parent()(self.growth * other.growth, - coefficient=self.coefficient * other.coefficient, - valid_from=valid_from) + valid_from = {var: max(self.valid_from.get(var, 0), other.valid_from.get(var, 0)) for var in set().union(self.valid_from, other.valid_from)} + return self.parent()(self.growth * other.growth, coefficient=self.coefficient * other.coefficient, valid_from=valid_from) def can_absorb(self, other): r""" @@ -4611,11 +4556,11 @@ def _absorb_(self, other): valid_from_new = {} for variable_name in set().union(self.valid_from.keys(), other.valid_from.keys()): if variable_name in self.valid_from and other.valid_from: - valid_from_new[variable_name] = (max(self.valid_from[variable_name], other.valid_from[variable_name])) + valid_from_new[variable_name] = max(self.valid_from[variable_name], other.valid_from[variable_name]) elif variable_name in self.valid_from: - valid_from_new[variable_name] = (self.valid_from[variable_name]) + valid_from_new[variable_name] = self.valid_from[variable_name] elif variable_name in other.valid_from: - valid_from_new[variable_name] = (other.valid_from[variable_name]) + valid_from_new[variable_name] = other.valid_from[variable_name] q = self.growth / other.growth coeff_new = self.coefficient + (other.coefficient / q._find_minimum_(valid_from_new)) return self.parent()(self.growth, valid_from=valid_from_new, coefficient=coeff_new) @@ -4650,6 +4595,7 @@ class BTermMonoid(TermWithCoefficientMonoid): sage: BT is BTermMonoid(TermMonoid, G, QQ) True """ + __init__ = experimental(issue_number=31922)(GenericTermMonoid.__init__) # enable the category framework for elements @@ -4669,8 +4615,7 @@ def _repr_(self): sage: TermMonoid('B', G, QQ)._repr_() 'B-Term Monoid x^ZZ with coefficients in Rational Field' """ - return (f'B-Term Monoid {self.growth_group._repr_short_()} with ' - f'coefficients in {self.coefficient_ring}') + return f'B-Term Monoid {self.growth_group._repr_short_()} with ' f'coefficients in {self.coefficient_ring}' def _default_kwds_construction_(self): r""" @@ -4698,8 +4643,7 @@ def _default_kwds_construction_(self): """ defaults = {} defaults.update(super()._default_kwds_construction_()) - defaults.update( - {'valid_from': {v: 0 for v in self.growth_group.variable_names()}}) + defaults.update({'valid_from': {v: 0 for v in self.growth_group.variable_names()}}) return defaults def _convert_construction_(self, kwds_construction): @@ -4820,8 +4764,7 @@ def _coerce_map_from_(self, S): True """ if isinstance(S, (ExactTermMonoid,)): - if self.growth_group.has_coerce_map_from(S.growth_group) and \ - self.coefficient_ring.has_coerce_map_from(S.coefficient_ring): + if self.growth_group.has_coerce_map_from(S.growth_group) and self.coefficient_ring.has_coerce_map_from(S.coefficient_ring): return True else: return super()._coerce_map_from_(S) @@ -4842,10 +4785,8 @@ def _an_element_(self): B(x, x >= 42) """ from sage.rings.semirings.non_negative_integer_semiring import NN - return self(self.growth_group.an_element(), - coefficient=self.coefficient_ring.an_element(), - valid_from={v: NN.an_element() - for v in self.growth_group.variable_names()}) + + return self(self.growth_group.an_element(), coefficient=self.coefficient_ring.an_element(), valid_from={v: NN.an_element() for v in self.growth_group.variable_names()}) def some_elements(self): r""" @@ -4878,13 +4819,8 @@ def some_elements(self): from itertools import cycle from sage.misc.mrange import cantor_product from sage.rings.semirings.non_negative_integer_semiring import NN - return (self(g, - coefficient=c, - valid_from={v: f for v in self.growth_group.variable_names()}) - for (g, c), f in zip(cantor_product( - self.growth_group.some_elements(), - (c for c in self.coefficient_ring.some_elements() if c != 0)), - cycle(NN.some_elements()))) + + return (self(g, coefficient=c, valid_from={v: f for v in self.growth_group.variable_names()}) for (g, c), f in zip(cantor_product(self.growth_group.some_elements(), (c for c in self.coefficient_ring.some_elements() if c != 0)), cycle(NN.some_elements()))) class TermMonoidFactory(UniqueRepresentation, UniqueFactory): @@ -5007,10 +4943,7 @@ class TermMonoidFactory(UniqueRepresentation, UniqueFactory): running ._test_some_elements() . . . pass """ - def __init__(self, name, - exact_term_monoid_class=None, - O_term_monoid_class=None, - B_term_monoid_class=None): + def __init__(self, name, exact_term_monoid_class=None, O_term_monoid_class=None, B_term_monoid_class=None): r""" See :class:`TermMonoidFactory` for more information. @@ -5053,10 +4986,7 @@ def __init__(self, name, B_term_monoid_class = BTermMonoid self.BTermMonoid = B_term_monoid_class - def create_key_and_extra_args(self, term_monoid, - growth_group=None, coefficient_ring=None, - asymptotic_ring=None, - **kwds): + def create_key_and_extra_args(self, term_monoid, growth_group=None, coefficient_ring=None, asymptotic_ring=None, **kwds): r""" Given the arguments and keyword, create a key that uniquely determines this object. @@ -5099,31 +5029,27 @@ def create_key_and_extra_args(self, term_monoid, elif term_monoid == 'B': term_class = self.BTermMonoid else: - raise ValueError("Term specification '%s' has to be either 'exact', 'O', 'B' " - "or an instance of an existing term." % term_monoid) + raise ValueError("Term specification '%s' has to be either 'exact', 'O', 'B' " "or an instance of an existing term." % term_monoid) - if asymptotic_ring is not None and \ - (growth_group is not None or coefficient_ring is not None): - raise ValueError("Input ambiguous: asymptotic ring %s as well as " - "growth group %s or coefficient ring %s are given." % - (asymptotic_ring, growth_group, coefficient_ring)) + if asymptotic_ring is not None and (growth_group is not None or coefficient_ring is not None): + raise ValueError("Input ambiguous: asymptotic ring %s as well as " "growth group %s or coefficient ring %s are given." % (asymptotic_ring, growth_group, coefficient_ring)) if asymptotic_ring is not None: growth_group = asymptotic_ring.growth_group coefficient_ring = asymptotic_ring.coefficient_ring from .growth_group import GenericGrowthGroup + if not isinstance(growth_group, GenericGrowthGroup): if isinstance(growth_group, str): from .growth_group import GrowthGroup + growth_group = GrowthGroup(growth_group) else: - raise ValueError('{} has to be an asymptotic growth ' - 'group'.format(growth_group)) + raise ValueError('{} has to be an asymptotic growth ' 'group'.format(growth_group)) if coefficient_ring is None: - raise ValueError("A coefficient ring has to be specified to " - "create a term monoid of type '%s'" % (term_monoid,)) + raise ValueError("A coefficient ring has to be specified to " "create a term monoid of type '%s'" % (term_monoid,)) return (term_class, growth_group, coefficient_ring), kwds @@ -5169,10 +5095,7 @@ def _cache_key(self): , ) """ - return (TermMonoidFactory, - self._name, - self.ExactTermMonoid, - self.OTermMonoid) + return (TermMonoidFactory, self._name, self.ExactTermMonoid, self.OTermMonoid) def __hash__(self): r""" diff --git a/src/sage/rings/bernmm.pyi b/src/sage/rings/bernmm.pyi index 20b8d0b558f..11248778627 100644 --- a/src/sage/rings/bernmm.pyi +++ b/src/sage/rings/bernmm.pyi @@ -1,7 +1,4 @@ from sage.rings.rational import Rational -def bernmm_bern_rat(k: int, num_threads: int = 1) -> Rational: - ... - -def bernmm_bern_modp(p: int, k: int) -> int: - ... +def bernmm_bern_rat(k: int, num_threads: int = 1) -> Rational: ... +def bernmm_bern_modp(p: int, k: int) -> int: ... diff --git a/src/sage/rings/bernoulli_mod_p.pyi b/src/sage/rings/bernoulli_mod_p.pyi index 7ea4f52fd72..89aa8eff1a7 100644 --- a/src/sage/rings/bernoulli_mod_p.pyi +++ b/src/sage/rings/bernoulli_mod_p.pyi @@ -1,9 +1,3 @@ - -def verify_bernoulli_mod_p(data: list[int]) -> bool: - ... - -def bernoulli_mod_p(p: int) -> list[int]: - ... - -def bernoulli_mod_p_single(p: int, k: int) -> int: - ... +def verify_bernoulli_mod_p(data: list[int]) -> bool: ... +def bernoulli_mod_p(p: int) -> list[int]: ... +def bernoulli_mod_p_single(p: int, k: int) -> int: ... diff --git a/src/sage/rings/big_oh.py b/src/sage/rings/big_oh.py index 55a4d2c3f94..445c25032b0 100644 --- a/src/sage/rings/big_oh.py +++ b/src/sage/rings/big_oh.py @@ -159,8 +159,7 @@ def O(*x, **kwds): if len(x) > 1: if isinstance(x[0], multi_power_series_ring_element.MPowerSeries): return multi_power_series_ring_element.MO(x, **kwds) - raise ArithmeticError("O(%s) not defined" % - (', '.join(str(e) for e in x),)) + raise ArithmeticError("O(%s) not defined" % (', '.join(str(e) for e in x),)) x = x[0] @@ -169,11 +168,9 @@ def O(*x, **kwds): if isinstance(x, Polynomial): if x.parent().ngens() != 1: - raise NotImplementedError("completion only currently defined " - "for univariate polynomials") + raise NotImplementedError("completion only currently defined " "for univariate polynomials") if not x.is_monomial(): - raise NotImplementedError("completion only currently defined " - "for the maximal ideal (x)") + raise NotImplementedError("completion only currently defined " "for the maximal ideal (x)") if isinstance(x, (int, Integer, Rational)): # p-adic number @@ -193,10 +190,8 @@ def O(*x, **kwds): if not p.is_prime(): raise ArithmeticError("x must be prime power") if r >= 0: - return Zp(p, prec=max(r, 20), - type='capped-rel')(0, absprec=r, **kwds) - return Qp(p, prec=max(r, 20), - type='capped-rel')(0, absprec=r, **kwds) + return Zp(p, prec=max(r, 20), type='capped-rel')(0, absprec=r, **kwds) + return Qp(p, prec=max(r, 20), type='capped-rel')(0, absprec=r, **kwds) if isinstance(x, PuiseuxSeries): # note that add_bigoh() of PuiseuxSeries adapts the precision @@ -206,6 +201,7 @@ def O(*x, **kwds): from sage.rings.padics.padic_ZZ_pX_FM_element import pAdicZZpXFMElement from sage.rings.padics.padic_fixed_mod_element import pAdicFixedModElement + if isinstance(x, (pAdicZZpXFMElement, pAdicFixedModElement)): # fixed modulus elements does not keep track of their own precision, # we must return zero (that said it is not recommended to use O() diff --git a/src/sage/rings/cfinite_sequence.py b/src/sage/rings/cfinite_sequence.py index 76bea21b192..3604260a2ea 100644 --- a/src/sage/rings/cfinite_sequence.py +++ b/src/sage/rings/cfinite_sequence.py @@ -169,8 +169,7 @@ def CFiniteSequences(base_ring, names=None, category=None): return CFiniteSequences_generic(polynomial_ring, category) -class CFiniteSequence(FieldElement, - metaclass=InheritComparisonClasscallMetaclass): +class CFiniteSequence(FieldElement, metaclass=InheritComparisonClasscallMetaclass): r""" Create a C-finite sequence given its ordinary generating function. @@ -250,6 +249,7 @@ class CFiniteSequence(FieldElement, ... NotImplementedError: Multidimensional o.g.f. not implemented. """ + @staticmethod def __classcall_private__(cls, ogf): r""" @@ -676,7 +676,7 @@ def __getitem__(self, key): x = P.gen() while n: nden = den(-x) - num = P((num * nden).list()[n % 2::2]) + num = P((num * nden).list()[n % 2 :: 2]) den = P((den * nden).list()[::2]) n //= 2 return wp + num[0] / den[0] @@ -860,6 +860,7 @@ def closed_form(self, n='n'): from sage.rings.qqbar import QQbar from sage.symbolic.ring import SR + n = SR(n) expr = SR.zero() @@ -883,7 +884,7 @@ def closed_form(self, n='n'): for k, a in enumerate(part.numerator()): a = -QQbar(a) if k % 2 else QQbar(a) bino = binomial(n + m - k, m) - c += bino * SR((a * b**(k - m - 1)).radical_expression()) + c += bino * SR((a * b ** (k - m - 1)).radical_expression()) expr += c.expand() * r**n @@ -940,8 +941,7 @@ def __init__(self, polynomial_ring, category): self._fraction_field = FractionField(self._polynomial_ring) if category is None: category = Rings().Commutative() - Parent.__init__(self, base_ring, names=self._polynomial_ring.gens(), - category=category) + Parent.__init__(self, base_ring, names=self._polynomial_ring.gens(), category=category) def _repr_(self): r""" @@ -1168,10 +1168,7 @@ def from_recurrence(self, coefficients, values): co = coefficients[::-1] + [0] * (len(values) - deg) R = self.polynomial_ring() den = R([-1] + co[:deg]) - num = R([-values[0]] + - [-values[n] + sum(values[k] * co[n - 1 - k] - for k in range(n)) - for n in range(1, len(values))]) + num = R([-values[0]] + [-values[n] + sum(values[k] * co[n - 1 - k] for k in range(n)) for n in range(1, len(values))]) return self(num / den) def guess(self, sequence, algorithm='sage'): @@ -1223,6 +1220,7 @@ def guess(self, sequence, algorithm='sage'): if algorithm == 'bm': from sage.matrix.berlekamp_massey import berlekamp_massey + if len(sequence) < 2: raise ValueError('sequence too short for guessing') R = PowerSeriesRing(QQ, 'x') @@ -1237,13 +1235,15 @@ def guess(self, sequence, algorithm='sage'): if algorithm == 'pari': if len(sequence) < 6: raise ValueError('sequence too short for guessing') - pari("ggf(v)=local(l,m,p,q,B);l=length(v);B=l\\2;\ + pari( + "ggf(v)=local(l,m,p,q,B);l=length(v);B=l\\2;\ if(B<3,return(0));m=matrix(B,B,x,y,v[x-y+B+1]);\ q=qflll(m,4)[1];if(length(q)==0,return(0));\ p=sum(k=1,B,x^(k-1)*q[k,1]);\ q=Pol(Pol(vector(l,n,v[l-n+1]))*p+O(x^(B+1)));\ if(polcoeff(p,0)<0,q=-q;p=-p);q=q/p;p=Ser(q+O(x^(l+1)));\ - for(m=1,l,if(polcoeff(p,m-1)!=v[m],return(0)));q") + for(m=1,l,if(polcoeff(p,m-1)!=v[m],return(0)));q" + ) pari_guess = pari("ggf")(sequence) num = S(pari_guess.numerator().Vec().sage()[::-1]) den = S(pari_guess.denominator().Vec().sage()[::-1]) @@ -1254,6 +1254,7 @@ def guess(self, sequence, algorithm='sage'): from sage.matrix.constructor import matrix from sage.arith.misc import integer_ceil as ceil from numpy import trim_zeros + seq = sequence[:] while seq and sequence[-1] == 0: seq.pop() @@ -1264,7 +1265,7 @@ def guess(self, sequence, algorithm='sage'): raise ValueError('sequence too short for guessing') hl = ceil(ZZ(l) / 2) - A = matrix([sequence[k: k + hl] for k in range(hl)]) + A = matrix([sequence[k : k + hl] for k in range(hl)]) K = A.kernel() if K.dimension() == 0: return 0 diff --git a/src/sage/rings/complex_arb.pyi b/src/sage/rings/complex_arb.pyi index 8a62b2009cf..794129372d1 100644 --- a/src/sage/rings/complex_arb.pyi +++ b/src/sage/rings/complex_arb.pyi @@ -6,32 +6,16 @@ from sage.rings.real_arb import RealBall from sage.structure.element import RingElement from sage.rings.ring import Field -def ComplexIntervalFieldElement_to_acb(target: acb_t, source: ComplexIntervalFieldElement) -> None: - ... - -def acb_to_ComplexIntervalFieldElement(target: ComplexIntervalFieldElement, source: acb_t) -> int: - ... +def ComplexIntervalFieldElement_to_acb(target: acb_t, source: ComplexIntervalFieldElement) -> None: ... +def acb_to_ComplexIntervalFieldElement(target: ComplexIntervalFieldElement, source: acb_t) -> int: ... class ComplexBall(RingElement): value: acb_t - def _new(self) -> 'ComplexBall': - ... - - def _add_(self, other: Any) -> Any: - ... - - def _mul_(self, other: Any) -> Any: - ... - - def _complex_mpfi_(self, parent: Any) -> ComplexIntervalFieldElement: - ... - - def real(self) -> RealBall: - ... - - def imag(self) -> RealBall: - ... - - def pow(self, expo: Any, analytic: Any = None) -> Any: - ... + def _new(self) -> 'ComplexBall': ... + def _add_(self, other: Any) -> Any: ... + def _mul_(self, other: Any) -> Any: ... + def _complex_mpfi_(self, parent: Any) -> ComplexIntervalFieldElement: ... + def real(self) -> RealBall: ... + def imag(self) -> RealBall: ... + def pow(self, expo: Any, analytic: Any = None) -> Any: ... diff --git a/src/sage/rings/complex_double.pyi b/src/sage/rings/complex_double.pyi index a14dc0a8778..f82fd44fe84 100644 --- a/src/sage/rings/complex_double.pyi +++ b/src/sage/rings/complex_double.pyi @@ -6,17 +6,9 @@ from sage.structure.element import FieldElement class ComplexDoubleElement(FieldElement): _complex: gsl_complex - def _new_c(self, x: gsl_complex) -> 'ComplexDoubleElement': - ... + def _new_c(self, x: gsl_complex) -> 'ComplexDoubleElement': ... + def _add_(self, other: Any) -> Any: ... + def _mul_(self, other: Any) -> Any: ... + def _pow_(self, other: Any) -> Any: ... - def _add_(self, other: Any) -> Any: - ... - - def _mul_(self, other: Any) -> Any: - ... - - def _pow_(self, other: Any) -> Any: - ... - -def new_ComplexDoubleElement() -> ComplexDoubleElement: - ... +def new_ComplexDoubleElement() -> ComplexDoubleElement: ... diff --git a/src/sage/rings/complex_interval.pyi b/src/sage/rings/complex_interval.pyi index 072a7e8534e..c2c459ae7e6 100644 --- a/src/sage/rings/complex_interval.pyi +++ b/src/sage/rings/complex_interval.pyi @@ -11,8 +11,5 @@ class ComplexIntervalFieldElement(FieldElement): _prec: mpfr_prec_t _multiplicative_order: Any - def _new(self) -> 'ComplexIntervalFieldElement': - ... - - def _new_real(self) -> RealIntervalFieldElement: - ... + def _new(self) -> 'ComplexIntervalFieldElement': ... + def _new_real(self) -> RealIntervalFieldElement: ... diff --git a/src/sage/rings/complex_interval_field.py b/src/sage/rings/complex_interval_field.py index 51b623f6d58..e234dd3e7c0 100644 --- a/src/sage/rings/complex_interval_field.py +++ b/src/sage/rings/complex_interval_field.py @@ -197,9 +197,7 @@ def __init__(self, prec=53) -> None: self._prec = int(prec) from sage.categories.fields import Fields - Field.__init__( - self, self.real_field(), ("I",), False, category=Fields().Infinite() - ) + Field.__init__(self, self.real_field(), ("I",), False, category=Fields().Infinite()) self._populate_coercion_lists_(convert_method_name="_complex_mpfi_") def __reduce__(self): diff --git a/src/sage/rings/complex_mpc.pyi b/src/sage/rings/complex_mpc.pyi index cc2730d1700..452a68d8fb0 100644 --- a/src/sage/rings/complex_mpc.pyi +++ b/src/sage/rings/complex_mpc.pyi @@ -8,14 +8,9 @@ class MPComplexNumber(FieldElement): value: mpc_t init: bool - def _new(self) -> 'MPComplexNumber': - ... - - def _add_(self, other: Any) -> Any: - ... - - def _mul_(self, other: Any) -> Any: - ... + def _new(self) -> 'MPComplexNumber': ... + def _add_(self, other: Any) -> Any: ... + def _mul_(self, other: Any) -> Any: ... class MPComplexField_class(Field): _prec: int @@ -24,8 +19,5 @@ class MPComplexField_class(Field): __real_field: Any __imag_field: Any - def _new(self) -> MPComplexNumber: - ... - - def _an_element_(self) -> MPComplexNumber: - ... + def _new(self) -> MPComplexNumber: ... + def _an_element_(self) -> MPComplexNumber: ... diff --git a/src/sage/rings/complex_mpfr.pyi b/src/sage/rings/complex_mpfr.pyi index 818cd59d45d..9416c017d51 100644 --- a/src/sage/rings/complex_mpfr.pyi +++ b/src/sage/rings/complex_mpfr.pyi @@ -10,17 +10,8 @@ class ComplexNumber(FieldElement): _prec: mpfr_prec_t _multiplicative_order: Any - def _add_(self, other: Any) -> Any: - ... - - def _mul_(self, other: Any) -> Any: - ... - - def abs_c(self) -> RealNumber: - ... - - def norm_c(self) -> RealNumber: - ... - - def _new(self) -> 'ComplexNumber': - ... + def _add_(self, other: Any) -> Any: ... + def _mul_(self, other: Any) -> Any: ... + def abs_c(self) -> RealNumber: ... + def norm_c(self) -> RealNumber: ... + def _new(self) -> 'ComplexNumber': ... diff --git a/src/sage/rings/continued_fraction.py b/src/sage/rings/continued_fraction.py index 7282e3cea87..7b50f9eda51 100644 --- a/src/sage/rings/continued_fraction.py +++ b/src/sage/rings/continued_fraction.py @@ -189,6 +189,7 @@ - Vincent Delecroix (2014): cleaning, refactorisation, documentation from the old implementation in ``contfrac`` (:issue:`14567`). """ + # **************************************************************************** # Copyright (C) 2007 William Stein # Copyright (C) 2014-2020 Vincent Delecroix <20100.delecroix@gmail.com> @@ -337,6 +338,7 @@ class ContinuedFraction_base(SageObject): sum or product, rely on the optional method :meth:`value` (and not on convergents) and may fail at execution if it is not implemented. """ + def __init__(self): r""" INPUT: @@ -436,6 +438,7 @@ def str(self, nterms=10, unicode=False, join=True): if unicode: import unicodedata + frac = unicodedata.lookup('BOX DRAWINGS LIGHT HORIZONTAL') else: frac = '-' @@ -487,6 +490,7 @@ def _ascii_art_(self): 4 """ from sage.typeset.ascii_art import AsciiArt + return AsciiArt(self.str(unicode=False, join=False)) def _unicode_art_(self): @@ -503,6 +507,7 @@ def _unicode_art_(self): 4 """ from sage.typeset.unicode_art import UnicodeArt + return UnicodeArt(self.str(unicode=True, join=False)) def _latex_(self, nterms=10): @@ -699,7 +704,7 @@ def _mpfr_(self, R): p_odd = self.numerator(2 * k + 1) q_even = self.denominator(2 * k) q_odd = self.denominator(2 * k + 1) - m_even = (p_even << N) // q_even # floor((2^N p_even) / q_even) + m_even = (p_even << N) // q_even # floor((2^N p_even) / q_even) m_odd = (p_odd << N + q_odd - 1) // q_odd # ceil((2^N p_odd) / q_odd) while m_odd - m_even > 1: k += 1 @@ -726,16 +731,16 @@ def _mpfr_(self, R): # in order to find the nearest approximation we possibly need to # augment our precision on convergents. while True: - assert not (p_odd << (N+1) <= (2*m_odd-1) * q_odd) or not (p_even << (N+1) >= (2*m_even+1) * q_even) - if p_odd << (N+1) <= (2*m_odd-1) * q_odd: + assert not (p_odd << (N + 1) <= (2 * m_odd - 1) * q_odd) or not (p_even << (N + 1) >= (2 * m_even + 1) * q_even) + if p_odd << (N + 1) <= (2 * m_odd - 1) * q_odd: return R(sgn * m_even) >> N - if p_even << (N+1) >= (2*m_even+1) * q_even: + if p_even << (N + 1) >= (2 * m_even + 1) * q_even: return R(sgn * m_odd) >> N k += 1 - p_even = self.numerator(2*k) - p_odd = self.numerator(2*k+1) - q_even = self.denominator(2*k) - q_odd = self.denominator(2*k+1) + p_even = self.numerator(2 * k) + p_odd = self.numerator(2 * k + 1) + q_even = self.denominator(2 * k) + q_odd = self.denominator(2 * k + 1) elif rnd == 'RNDU' or rnd == 'RNDA': # round up return R(sgn * m_odd) >> N elif rnd == 'RNDD' or rnd == 'RNDZ': # round down @@ -755,6 +760,7 @@ def __float__(self): -0.043701799485861184 """ from sage.rings.real_mpfr import RR + return float(self._mpfr_(RR)) def numerator(self, n): @@ -781,13 +787,13 @@ def numerator(self, n): raise ValueError("n must be at least -2") for k in range(len(p), n + 3): - x = self.quotient(k-2) + x = self.quotient(k - 2) if x is Infinity and k != 2: return p[-1] - p.append(x*p[k-1] + p[k-2]) - q.append(x*q[k-1] + q[k-2]) + p.append(x * p[k - 1] + p[k - 2]) + q.append(x * q[k - 1] + q[k - 2]) - return p[n+2] + return p[n + 2] p = numerator @@ -806,10 +812,10 @@ def denominator(self, n): sage: c.denominator(152) 1255341492699841451528811722575401081588363886480089431843026103930863337221076748 """ - self.numerator(n) # ! silent computation of qn - if len(self._qn) < n+3: + self.numerator(n) # ! silent computation of qn + if len(self._qn) < n + 3: return self._qn[-1] - return self._qn[n+2] + return self._qn[n + 2] q = denominator @@ -851,10 +857,9 @@ def convergents(self): from itertools import count from sage.misc.lazy_list import lazy_list - return lazy_list(self.numerator(n) / self.denominator(n) - for n in count()) - return [self.numerator(n) / self.denominator(n) - for n in range(len(self))] + + return lazy_list(self.numerator(n) / self.denominator(n) for n in count()) + return [self.numerator(n) / self.denominator(n) for n in range(len(self))] def quotients(self): r""" @@ -879,6 +884,7 @@ def quotients(self): from itertools import count from sage.misc.lazy_list import lazy_list + return lazy_list(self.quotient(n) for n in count()) return [self.quotient(n) for n in range(len(self))] @@ -1148,6 +1154,7 @@ def numerical_approx(self, prec=None, digits=None, algorithm=None): 1.28102513329556981555293038097590 """ from sage.arith.numerical_approx import digits_to_bits, numerical_approx_generic + if prec is None: prec = digits_to_bits(digits) return numerical_approx_generic(self, prec) @@ -1256,6 +1263,7 @@ def apply_homography(self, a, b, c, d, forward_value=False): value = (a * x + b) / (c * x + d) from sage.misc.lazy_list import lazy_list + return continued_fraction(lazy_list(_i), value) def __neg__(self): @@ -1299,6 +1307,7 @@ class ContinuedFraction_periodic(ContinuedFraction_base): for the period. In the purely periodic case ``_x1`` is empty while in the rational case ``_x2`` is the tuple ``(0,)``. """ + def __init__(self, x1, x2=None, check=True): r""" INPUT: @@ -1393,7 +1402,7 @@ def quotient(self, n): raise ValueError("n (=%d) should be positive" % n) if n < len(self._x1): return self._x1[n] - return self._x2[(n-len(self._x1)) % len(self._x2)] + return self._x2[(n - len(self._x1)) % len(self._x2)] def length(self): r""" @@ -1468,8 +1477,7 @@ def __richcmp__(self, other, op): False """ if isinstance(other, ContinuedFraction_periodic): - n = max(len(self._x1) + 2 * len(self._x2), - len(other._x1) + 2 * len(other._x2)) + n = max(len(self._x1) + 2 * len(self._x2), len(other._x1) + 2 * len(other._x2)) for i in range(n): a = self.quotient(i) b = other.quotient(i) @@ -1562,14 +1570,15 @@ def value(self): # q1 x^2 + (q0 - p1) x - p0 = 0 from sage.misc.functional import squarefree_part from sage.rings.number_field.number_field import QuadraticField - D = (q0-p1)**2 + 4*q1*p0 + + D = (q0 - p1) ** 2 + 4 * q1 * p0 DD = squarefree_part(D) Q = QuadraticField(DD, 'sqrt%d' % DD) - x = ((p1 - q0) + (D/DD).sqrt() * Q.gen()) / (2*q1) + x = ((p1 - q0) + (D / DD).sqrt() * Q.gen()) / (2 * q1) # we add the preperiod p0, q0, p1, q1 = last_two_convergents(self._x1) - return (p1*x + p0) / (q1*x + q0) + return (p1 * x + p0) / (q1 * x + q0) def _repr_(self): r""" @@ -1641,7 +1650,7 @@ def _rational_(self): if self._x2[0] is not Infinity: raise ValueError("this is not a rational!") n = len(self) - return self.numerator(n-1) / self.denominator(n-1) + return self.numerator(n - 1) / self.denominator(n - 1) def _latex_(self): r""" @@ -1680,7 +1689,7 @@ def _latex_(self): s = str(v[0]) + '\n' for i in range(1, len(v)): s += '+ \\frac{\\displaystyle 1}{\\displaystyle %s\n' % v[i] - s += '}'*(len(v)-1) + s += '}' * (len(v) - 1) return s def __invert__(self): @@ -1805,6 +1814,7 @@ class ContinuedFraction_real(ContinuedFraction_base): sage: cf.value() # needs sage.symbolic e """ + def __init__(self, x): r""" INPUT: @@ -1819,6 +1829,7 @@ def __init__(self, x): self._x0 = x from .real_mpfi import RealIntervalField + self._xa = RealIntervalField(53)(self._x0) # an approximation of the last element of the orbit under the # Gauss map @@ -1962,11 +1973,12 @@ def quotient(self, n): if len(self._quotients) > 1 and n >= len(self._quotients) and self._quotients[-1] == 0: return ZZ_0 - for k in range(len(self._quotients), n+1): + for k in range(len(self._quotients), n + 1): if x.lower().is_infinity() or x.upper().is_infinity() or x.lower().floor() != x.upper().floor(): def orbit(z): - return -(self.denominator(k-2)*z-self.numerator(k-2))/(self.denominator(k-1)*z-self.numerator(k-1)) + return -(self.denominator(k - 2) * z - self.numerator(k - 2)) / (self.denominator(k - 1) * z - self.numerator(k - 1)) + x = x.parent()(orbit(self._x0)) # It may happen that the above line fails to give an @@ -1974,11 +1986,12 @@ def orbit(z): # examples). In that case, we augment the precision. while x.lower().is_infinity() or x.upper().is_infinity() or x.lower().floor() != x.upper().floor(): from .real_mpfi import RealIntervalField + self._prec = x.parent().prec() + 100 x = RealIntervalField(self._prec)(orbit(self._x0)) self._quotients.append(x.unique_floor()) - x = (x - x.unique_floor()) + x = x - x.unique_floor() if not x: self._quotients.append(ZZ_0) return ZZ_0 @@ -2037,6 +2050,7 @@ class ContinuedFraction_infinite(ContinuedFraction_base): fraction evaluates to 1.718281828459046? in Real Interval Field with 53 bits of precision. """ + def __init__(self, w, value=None, check=True): r""" INPUT: @@ -2089,16 +2103,15 @@ def __init__(self, w, value=None, check=True): try: k = Integer(w[i]) except (TypeError, ValueError): - raise ValueError("the sequence must consist of" - " integers") + raise ValueError("the sequence must consist of" " integers") self.quotient = self._Integer_quotient if not k and i: - raise ValueError("only the first partial quotient can" - " be null") + raise ValueError("only the first partial quotient can" " be null") if check and value is not None: from sage.rings.real_mpfi import RealIntervalField + R = RealIntervalField(53) x = R(value) y = R(self) @@ -2215,6 +2228,7 @@ def value(self): if self._value is not None: return self._value from sage.rings.real_lazy import RLF + if self._w[0] < 0: return -RLF(-self) return RLF(self) @@ -2234,6 +2248,7 @@ def __neg__(self): [-1; 5, 9, 16, 8, 2, 15, 13, 13, 15, 2, 8, 16, 9, 4, 1, 0, 1, 4, 9...] """ from sage.combinat.words.word import Word + _w = self._w if _w[1] == 1: _w = Word((-_w[0] - 1, _w[2] + 1)).concatenate(Word(_w[3:])) @@ -2311,8 +2326,7 @@ def check_and_reduce_pair(x1, x2=None): return tuple(y1), tuple(y2) -def continued_fraction_list(x, type='std', partial_convergents=False, - bits=None, nterms=None): +def continued_fraction_list(x, type='std', partial_convergents=False, bits=None, nterms=None): r""" Return the (finite) continued fraction of ``x`` as a list. @@ -2448,6 +2462,7 @@ def continued_fraction_list(x, type='std', partial_convergents=False, if bits is not None: from .real_mpfi import RealIntervalField + x = RealIntervalField(bits)(x) if type == "hj": @@ -2480,11 +2495,10 @@ def continued_fraction_list(x, type='std', partial_convergents=False, RealLiteral = () if isinstance(x, RealLiteral): from sage.rings.real_mpfi import RealIntervalField + x = RealIntervalField(x.prec())(x) if isinstance(x.parent(), (sage.rings.abc.RealIntervalField, sage.rings.abc.RealBallField)): - cf = continued_fraction(rat_interval_cf_list( - x.lower().exact_rational(), - x.upper().exact_rational())) + cf = continued_fraction(rat_interval_cf_list(x.lower().exact_rational(), x.upper().exact_rational())) if cf is None: try: @@ -2501,11 +2515,11 @@ def continued_fraction_list(x, type='std', partial_convergents=False, limit = cf.length() else: import warnings + warnings.warn("the continued fraction of %s seems infinite, return only the first 20 terms" % x) limit = 20 if partial_convergents: - return ([cf.quotient(i) for i in range(limit)], - [(cf.numerator(i), cf.denominator(i)) for i in range(limit)]) + return ([cf.quotient(i) for i in range(limit)], [(cf.numerator(i), cf.denominator(i)) for i in range(limit)]) return [cf.quotient(i) for i in range(limit)] @@ -2658,12 +2672,12 @@ def continued_fraction(x, value=None): # input for infinite partial quotient expansion from sage.misc.lazy_list import lazy_list_generic + if isinstance(x, (lazy_list_generic, InfiniteWord_class)): return ContinuedFraction_infinite(x, value) if isinstance(x, Word_class): - raise ValueError("word with unknown length cannot be converted " - "to continued fractions") + raise ValueError("word with unknown length cannot be converted " "to continued fractions") # input for numbers # TODO: the approach used below might be not what the user expects as we @@ -2678,6 +2692,7 @@ def continued_fraction(x, value=None): # sage: a in QQ # False from .rational_field import QQ + if x in QQ: return QQ(x).continued_fraction() @@ -2689,6 +2704,7 @@ def continued_fraction(x, value=None): if is_real is False: from .real_mpfi import RealIntervalField + # we cannot rely on the answer of .is_real() for elements of the # symbolic ring. The thing below is a dirty temporary hack. RIF = RealIntervalField(53) diff --git a/src/sage/rings/continued_fraction_gosper.py b/src/sage/rings/continued_fraction_gosper.py index 193f01b09bf..a4246ddb486 100644 --- a/src/sage/rings/continued_fraction_gosper.py +++ b/src/sage/rings/continued_fraction_gosper.py @@ -20,6 +20,7 @@ Implement the more general version for `(axy + bx + cy + d) / (exy + fx + gy + h)` which would allow to handle the product of two continued fractions. """ + # **************************************************************************** # Copyright (C) 2006 Miroslav Kovar # Copyright (C) 2020 Vincent Delecroix <20100.delecroix@gmail.com> @@ -40,6 +41,7 @@ class gosper_iterator: Iterable for the partial quotients of `(a*x+b)/(c*x+d)`, where `a, b, c, d` are integers, and `x` is a continued fraction. """ + def __init__(self, a, b, c, d, x): """ Construct the class. @@ -70,6 +72,7 @@ def __init__(self, a, b, c, d, x): [] """ from sage.rings.continued_fraction import ContinuedFraction_periodic + self.a = a self.b = b self.c = c @@ -134,7 +137,7 @@ def __next__(self): self.states.add(current_state) self.states_to_currently_emitted[current_state] = self.currently_emitted - if (self.c == 0 and self.d == 0): + if self.c == 0 and self.d == 0: raise StopIteration ub = self.bound(self.a, self.c) diff --git a/src/sage/rings/derivation.py b/src/sage/rings/derivation.py index d92d6ab9698..93263390c8a 100644 --- a/src/sage/rings/derivation.py +++ b/src/sage/rings/derivation.py @@ -220,6 +220,7 @@ class RingDerivationModule(Module, UniqueRepresentation): """ A class for modules of derivations over a commutative ring. """ + def __init__(self, domain, codomain, twist=None): """ Initialize this module of derivation. @@ -266,17 +267,14 @@ def __init__(self, domain, codomain, twist=None): if codomain in Rings().Commutative() and codomain.has_coerce_map_from(domain): defining_morphism = codomain.coerce_map_from(domain) - elif (isinstance(codomain,Map) - and codomain.category_for().is_subcategory(Rings()) - and codomain.domain().has_coerce_map_from(domain)): + elif isinstance(codomain, Map) and codomain.category_for().is_subcategory(Rings()) and codomain.domain().has_coerce_map_from(domain): if codomain.domain() is domain: defining_morphism = codomain else: defining_morphism = codomain * codomain.domain().coerce_map_from(domain) codomain = defining_morphism.codomain() else: - raise TypeError("the codomain must be an algebra over the domain" - " or a morphism with the correct domain") + raise TypeError("the codomain must be an algebra over the domain" " or a morphism with the correct domain") if twist is not None: if not (isinstance(twist, Map) and twist.category_for().is_subcategory(Rings())): @@ -284,14 +282,12 @@ def __init__(self, domain, codomain, twist=None): if twist.domain() is not domain: map = twist.domain().coerce_map_from(domain) if map is None: - raise TypeError("the domain of the derivation must coerce" - " to the domain of the twisting homomorphism") + raise TypeError("the domain of the derivation must coerce" " to the domain of the twisting homomorphism") twist = twist * map if twist.codomain() is not codomain: map = codomain.coerce_map_from(twist.codomain()) if map is None: - raise TypeError("the codomain of the twisting homomorphism" - " must coerce to the codomain of the derivation") + raise TypeError("the codomain of the twisting homomorphism" " must coerce to the codomain of the derivation") twist = map * twist # We check if the twisting morphism is the defining morphism try: @@ -321,19 +317,15 @@ def __init__(self, domain, codomain, twist=None): if twist is not None: self.Element = RingDerivationWithTwist_generic if domain.is_field(): - self._gens = [ 1 ] - self._basis = [ 1 ] - elif (domain is ZZ or domain in NumberFields() or domain in FiniteFields() - or isinstance(domain, IntegerModRing_generic) - or (isinstance(domain, pAdicGeneric) and (domain.is_field() or domain.absolute_e() == 1))): + self._gens = [1] + self._basis = [1] + elif domain is ZZ or domain in NumberFields() or domain in FiniteFields() or isinstance(domain, IntegerModRing_generic) or (isinstance(domain, pAdicGeneric) and (domain.is_field() or domain.absolute_e() == 1)): self.Element = RingDerivationWithoutTwist_zero - self._gens = [ ] - self._basis = [ ] - self._dual_basis = [ ] + self._gens = [] + self._basis = [] + self._dual_basis = [] self._constants = (domain, True) - elif (isinstance(domain, (PolynomialRing_generic, MPolynomialRing_base, PowerSeriesRing_generic, LaurentSeriesRing)) - or (isinstance(domain, FractionField_generic) - and isinstance(domain.ring(), (PolynomialRing_generic, MPolynomialRing_base)))): + elif isinstance(domain, (PolynomialRing_generic, MPolynomialRing_base, PowerSeriesRing_generic, LaurentSeriesRing)) or (isinstance(domain, FractionField_generic) and isinstance(domain.ring(), (PolynomialRing_generic, MPolynomialRing_base))): self._base_derivation = RingDerivationModule(domain.base_ring(), defining_morphism) self.Element = RingDerivationWithoutTwist_function try: @@ -371,8 +363,7 @@ def __init__(self, domain, codomain, twist=None): modulus = domain.modulus() for der in self._base_derivation.gens(): if der(modulus) != 0: - raise NotImplementedError("derivations over quotient rings" - " are not fully supported") + raise NotImplementedError("derivations over quotient rings" " are not fully supported") self.Element = RingDerivationWithoutTwist_quotient try: self._gens = self._base_derivation.gens() @@ -387,10 +378,8 @@ def __init__(self, domain, codomain, twist=None): self._constants = (constants, False) # can we do better? elif isinstance(domain, QuotientRing_generic): self._base_derivation = RingDerivationModule(domain.cover_ring(), defining_morphism) - if any(der(modulus) != 0 for modulus in domain.defining_ideal().gens() - for der in self._base_derivation.gens()): - raise NotImplementedError("derivations over quotient rings" - " are not fully supported") + if any(der(modulus) != 0 for modulus in domain.defining_ideal().gens() for der in self._base_derivation.gens()): + raise NotImplementedError("derivations over quotient rings" " are not fully supported") self.Element = RingDerivationWithoutTwist_quotient try: self._gens = self._base_derivation.gens() @@ -405,12 +394,14 @@ def __init__(self, domain, codomain, twist=None): self._constants = (constants, False) # can we do better? elif isinstance(domain, RationalFunctionField): from sage.rings.function_field.derivations_rational import FunctionFieldDerivation_rational + self.Element = FunctionFieldDerivation_rational - self._gens = self._basis = [ None ] - self._dual_basis = [ domain.gen() ] + self._gens = self._basis = [None] + self._dual_basis = [domain.gen()] elif isinstance(domain, FunctionField): if domain.is_separable(): from sage.rings.function_field.derivations_polymod import FunctionFieldDerivation_separable + self._base_derivation = RingDerivationModule(domain.base_ring(), defining_morphism) self.Element = FunctionFieldDerivation_separable try: @@ -424,12 +415,13 @@ def __init__(self, domain, codomain, twist=None): pass else: from sage.rings.function_field.derivations_polymod import FunctionFieldDerivation_inseparable + M, f, self._t = domain.separable_model() self._base_derivation = RingDerivationModule(M, defining_morphism * f) self._d = self._base_derivation(None) self.Element = FunctionFieldDerivation_inseparable - self._gens = self._basis = [ None ] - self._dual_basis = [ f(M.base_ring().gen()) ] + self._gens = self._basis = [None] + self._dual_basis = [f(M.base_ring().gen())] else: raise NotImplementedError("derivations over this ring is not implemented") if self._basis is None: @@ -753,8 +745,7 @@ def ring_of_constants(self): Rational Field """ if not self._constants[1]: - raise NotImplementedError("the computation of the ring of constants" - " is not implemented for this derivation module") + raise NotImplementedError("the computation of the ring of constants" " is not implemented for this derivation module") return self._constants[0] def random_element(self, *args, **kwds): @@ -770,7 +761,7 @@ def random_element(self, *args, **kwds): """ if self._gens is None: raise NotImplementedError("generators are not implemented for this derivation module") - return self([ self._codomain.random_element(*args, **kwds) for _ in range(len(self._gens)) ]) + return self([self._codomain.random_element(*args, **kwds) for _ in range(len(self._gens))]) def some_elements(self): r""" @@ -806,6 +797,7 @@ class RingDerivation(ModuleElement): sage: f(x*y) 2*x + y """ + def __call__(self, x): """ Return the image of ``x`` under this derivation. @@ -867,6 +859,7 @@ class RingDerivationWithoutTwist(RingDerivation): """ An abstract class for untwisted derivations. """ + def _repr_(self): r""" Return a string representation of this derivation. @@ -1166,7 +1159,7 @@ def pth_power(self): p = parent.domain().characteristic() if not p.is_prime(): raise TypeError("the domain of the derivation must have positive and prime characteristic") - arg = [ ] + arg = [] for x in parent.dual_basis(): res = x for _ in range(p): @@ -1330,6 +1323,7 @@ class RingDerivationWithoutTwist_zero(RingDerivationWithoutTwist): It is used when the parent is the zero derivation module (e.g., when its domain is ``ZZ``, ``QQ``, a finite field, etc.) """ + def __init__(self, parent, arg=None): """ Initialize this derivation. @@ -1522,6 +1516,7 @@ class RingDerivationWithoutTwist_wrapper(RingDerivationWithoutTwist): computation rules for derivations. It is used for derivations over fraction fields and quotient rings. """ + def __init__(self, parent, arg=None): """ Initialize this derivation. @@ -1664,6 +1659,7 @@ class RingDerivationWithoutTwist_function(RingDerivationWithoutTwist): are either polynomials, rational fractions, power series or Laurent series. """ + def __init__(self, parent, arg=None): """ Initialize this derivation. @@ -1690,8 +1686,7 @@ def __init__(self, parent, arg=None): arg = arg[0] if not arg: pass - elif (isinstance(arg, RingDerivationWithoutTwist_function) - and parent.has_coerce_map_from(arg.parent())): + elif isinstance(arg, RingDerivationWithoutTwist_function) and parent.has_coerce_map_from(arg.parent()): self._base_derivation = parent._base_derivation(arg._base_derivation) self._images = [codomain(x) for x in arg._images] elif isinstance(arg, (tuple, list)): @@ -1735,7 +1730,7 @@ def _add_(self, other): d/dx + d/dy """ base_derivation = self._base_derivation + other._base_derivation - im = [ self._images[i] + other._images[i] for i in range(self.parent().domain().ngens()) ] + im = [self._images[i] + other._images[i] for i in range(self.parent().domain().ngens())] return type(self)(self.parent(), [base_derivation] + im) def _sub_(self, other): @@ -1751,7 +1746,7 @@ def _sub_(self, other): d/dx - d/dy """ base_derivation = self._base_derivation - other._base_derivation - im = [ self._images[i] - other._images[i] for i in range(self.parent().domain().ngens()) ] + im = [self._images[i] - other._images[i] for i in range(self.parent().domain().ngens())] return type(self)(self.parent(), [base_derivation] + im) def _rmul_(self, factor): @@ -1769,7 +1764,7 @@ def _rmul_(self, factor): """ factor = self.parent().codomain()(factor) base_derivation = factor * self._base_derivation - im = [ factor*x for x in self._images ] + im = [factor * x for x in self._images] return type(self)(self.parent(), [base_derivation] + im) def _lmul_(self, factor): @@ -1809,7 +1804,7 @@ def _call_(self, x): v = defining_morphism(den) up = num.map_coefficients(self._base_derivation, codomain)(*domain.gens()) vp = den.map_coefficients(self._base_derivation, codomain)(*domain.gens()) - res = (up*v - u*vp) / (v*v) + res = (up * v - u * vp) / (v * v) else: res = x.map_coefficients(self._base_derivation, codomain)(*domain.gens()) for i in range(len(self._images)): @@ -1864,6 +1859,7 @@ class RingDerivationWithoutTwist_fraction_field(RingDerivationWithoutTwist_wrapp """ This class handles derivations over fraction fields. """ + def __hash__(self): """ Return a hash of this derivation. @@ -1897,13 +1893,14 @@ def _call_(self, x): v = defining_morphism(den) up = self._base_derivation(u) vp = self._base_derivation(v) - return (up*v - u*vp) / (v*v) + return (up * v - u * vp) / (v * v) class RingDerivationWithoutTwist_quotient(RingDerivationWithoutTwist_wrapper): """ This class handles derivations over quotient rings. """ + def __hash__(self): """ Return a hash of this derivation. @@ -1940,6 +1937,7 @@ class RingDerivationWithTwist_generic(RingDerivation): morphism of the codomain over the domain) for a scalar `\lambda` varying in the codomain. """ + def __init__(self, parent, scalar=0): """ Initialize this derivation. @@ -2161,7 +2159,7 @@ def list(self): sage: f.list() [x + y] """ - return [ self._scalar ] + return [self._scalar] def precompose(self, morphism): r""" @@ -2201,8 +2199,7 @@ def precompose(self, morphism): raise TypeError("the given ring does not coerce to the domain of the derivation") elif not (isinstance(morphism, Map) and morphism.category_for().is_subcategory(Rings())): raise TypeError("you must give a homomorphism of rings") - M = RingDerivationModule(morphism.domain(), parent.defining_morphism() * morphism, - parent.twisting_morphism() * morphism) + M = RingDerivationModule(morphism.domain(), parent.defining_morphism() * morphism, parent.twisting_morphism() * morphism) return M(self._scalar) def postcompose(self, morphism): @@ -2243,8 +2240,7 @@ def postcompose(self, morphism): raise TypeError("the codomain of the derivation does not coerce to the given ring") elif not (isinstance(morphism, Map) and morphism.category_for().is_subcategory(Rings())): raise TypeError("you must give a homomorphism of rings") - M = RingDerivationModule(parent.domain(), morphism * parent.defining_morphism(), - morphism * parent.twisting_morphism()) + M = RingDerivationModule(parent.domain(), morphism * parent.defining_morphism(), morphism * parent.twisting_morphism()) return M(morphism(self._scalar)) def _richcmp_(self, other, op): diff --git a/src/sage/rings/factorint.pyi b/src/sage/rings/factorint.pyi index 454ba0669ec..7d0cfdecc0d 100644 --- a/src/sage/rings/factorint.pyi +++ b/src/sage/rings/factorint.pyi @@ -1,12 +1,4 @@ - -def aurifeuillian(n: int, m: int, F: int | None = None, check: bool = True) -> list[int]: - ... - -def factor_aurifeuillian(n: int, check: bool = True) -> list[int]: - ... - -def factor_cunningham(m: int, proof: bool | None = None) -> int: - ... - -def factor_trial_division(m: int, limit: int = 9223372036854775807) -> int: - ... +def aurifeuillian(n: int, m: int, F: int | None = None, check: bool = True) -> list[int]: ... +def factor_aurifeuillian(n: int, check: bool = True) -> list[int]: ... +def factor_cunningham(m: int, proof: bool | None = None) -> int: ... +def factor_trial_division(m: int, limit: int = 9223372036854775807) -> int: ... diff --git a/src/sage/rings/factorint_flint.pyi b/src/sage/rings/factorint_flint.pyi index 39e368dc15c..6d51d1b2a79 100644 --- a/src/sage/rings/factorint_flint.pyi +++ b/src/sage/rings/factorint_flint.pyi @@ -1,3 +1 @@ - -def factor_using_flint(n: int) -> list[tuple[int, int]]: - ... +def factor_using_flint(n: int) -> list[tuple[int, int]]: ... diff --git a/src/sage/rings/factorint_pari.pyi b/src/sage/rings/factorint_pari.pyi index 4b0e9f6020d..959baa06d64 100644 --- a/src/sage/rings/factorint_pari.pyi +++ b/src/sage/rings/factorint_pari.pyi @@ -1,4 +1,3 @@ from typing import Union -def factor_using_pari(n: Union[int, Integer], int_: bool = False, debug_level: int = 0, proof: bool | None = None) -> list[tuple[Union[int, Integer], int]]: - ... +def factor_using_pari(n: Union[int, Integer], int_: bool = False, debug_level: int = 0, proof: bool | None = None) -> list[tuple[Union[int, Integer], int]]: ... diff --git a/src/sage/rings/fast_arith.pyi b/src/sage/rings/fast_arith.pyi index 01923753e09..941a3572920 100644 --- a/src/sage/rings/fast_arith.pyi +++ b/src/sage/rings/fast_arith.pyi @@ -1,65 +1,25 @@ - -def prime_range(start: int, stop: int | None = None, algorithm: str | None = None, py_ints: bool = False) -> list[int]: - ... +def prime_range(start: int, stop: int | None = None, algorithm: str | None = None, py_ints: bool = False) -> list[int]: ... class arith_int: - def abs_int(self, x: int) -> int: - ... - - def sign_int(self, n: int) -> int: - ... - - def c_gcd_int(self, a: int, b: int) -> int: - ... - - def gcd_int(self, a: int, b: int) -> int: - ... - - def c_xgcd_int(self, a: int, b: int) -> tuple[int, int, int]: - ... - - def xgcd_int(self, a: int, b: int) -> tuple[int, int, int]: - ... - - def c_inverse_mod_int(self, a: int, m: int) -> int: - ... - - def inverse_mod_int(self, a: int, m: int) -> int: - ... - - def c_rational_recon_int(self, a: int, m: int) -> tuple[int, int]: - ... - - def rational_recon_int(self, a: int, m: int) -> tuple[int, int]: - ... + def abs_int(self, x: int) -> int: ... + def sign_int(self, n: int) -> int: ... + def c_gcd_int(self, a: int, b: int) -> int: ... + def gcd_int(self, a: int, b: int) -> int: ... + def c_xgcd_int(self, a: int, b: int) -> tuple[int, int, int]: ... + def xgcd_int(self, a: int, b: int) -> tuple[int, int, int]: ... + def c_inverse_mod_int(self, a: int, m: int) -> int: ... + def inverse_mod_int(self, a: int, m: int) -> int: ... + def c_rational_recon_int(self, a: int, m: int) -> tuple[int, int]: ... + def rational_recon_int(self, a: int, m: int) -> tuple[int, int]: ... class arith_llong: - def abs_longlong(self, x: int) -> int: - ... - - def sign_longlong(self, n: int) -> int: - ... - - def c_gcd_longlong(self, a: int, b: int) -> int: - ... - - def gcd_longlong(self, a: int, b: int) -> int: - ... - - def c_xgcd_longlong(self, a: int, b: int) -> tuple[int, int, int]: - ... - - def xgcd_longlong(self, a: int, b: int) -> tuple[int, int, int]: - ... - - def c_inverse_mod_longlong(self, a: int, m: int) -> int: - ... - - def inverse_mod_longlong(self, a: int, m: int) -> int: - ... - - def c_rational_recon_longlong(self, a: int, m: int) -> tuple[int, int]: - ... - - def rational_recon_longlong(self, a: int, m: int) -> tuple[int, int]: - ... + def abs_longlong(self, x: int) -> int: ... + def sign_longlong(self, n: int) -> int: ... + def c_gcd_longlong(self, a: int, b: int) -> int: ... + def gcd_longlong(self, a: int, b: int) -> int: ... + def c_xgcd_longlong(self, a: int, b: int) -> tuple[int, int, int]: ... + def xgcd_longlong(self, a: int, b: int) -> tuple[int, int, int]: ... + def c_inverse_mod_longlong(self, a: int, m: int) -> int: ... + def inverse_mod_longlong(self, a: int, m: int) -> int: ... + def c_rational_recon_longlong(self, a: int, m: int) -> tuple[int, int]: ... + def rational_recon_longlong(self, a: int, m: int) -> tuple[int, int]: ... diff --git a/src/sage/rings/finite_rings/all.py b/src/sage/rings/finite_rings/all.py index 6d8699c7b25..239e0337f48 100644 --- a/src/sage/rings/finite_rings/all.py +++ b/src/sage/rings/finite_rings/all.py @@ -20,4 +20,5 @@ from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.rings.finite_rings.conway_polynomials import conway_polynomial, exists_conway_polynomial + GF = FiniteField diff --git a/src/sage/rings/finite_rings/conway_polynomials.py b/src/sage/rings/finite_rings/conway_polynomials.py index bf1fb0a5b0b..7bb928d931c 100644 --- a/src/sage/rings/finite_rings/conway_polynomials.py +++ b/src/sage/rings/finite_rings/conway_polynomials.py @@ -96,7 +96,7 @@ def exists_conway_polynomial(p, n): False """ try: - return ConwayPolynomials().has_polynomial(p,n) + return ConwayPolynomials().has_polynomial(p, n) except ImportError: return False @@ -158,6 +158,7 @@ class PseudoConwayLattice(WithEqualityById, SageObject): sage: P != P False """ + def __init__(self, p, use_database=True): """ TESTS:: @@ -177,6 +178,7 @@ def __init__(self, p, use_database=True): """ self.p = p from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + self.ring = PolynomialRing(FiniteField(p), 'x') if use_database: try: @@ -184,8 +186,7 @@ def __init__(self, p, use_database=True): except ImportError: self.nodes = {} else: - self.nodes = {n: self.ring(C.polynomial(p, n)) - for n in C.degrees(p)} + self.nodes = {n: self.ring(C.polynomial(p, n)) for n in C.degrees(p)} else: self.nodes = {} @@ -235,8 +236,7 @@ def polynomial(self, n): # TODO: something like the following # gcds = [n.gcd(d) for d in self.nodes.keys()] # xi = { m: (...) for m in gcds } - xi = {q: self.polynomial(n//q).any_root(K, n//q, assume_squarefree=True, assume_equal_deg=True) - for q in n.prime_divisors()} + xi = {q: self.polynomial(n // q).any_root(K, n // q, assume_squarefree=True, assume_equal_deg=True) for q in n.prime_divisors()} # The following is needed to ensure that in the concrete instantiation # of the "new" extension all previous choices are compatible. @@ -244,9 +244,9 @@ def polynomial(self, n): # Construct a compatible element having order the lcm of orders q, x = xi.popitem() - v = p**(n//q) - 1 + v = p ** (n // q) - 1 for q, xitem in xi.items(): - w = p**(n//q) - 1 + w = p ** (n // q) - 1 g, alpha, beta = v.xgcd(w) x = x**beta * xitem**alpha v = v.lcm(w) @@ -256,13 +256,13 @@ def polynomial(self, n): g = r // v # Iterate through g-th roots of x until a primitive one is found z = x.nth_root(g) - root = K.multiplicative_generator()**v + root = K.multiplicative_generator() ** v while z.multiplicative_order() != r: z *= root # The following should work but tries to create a huge list # whose length overflows Python's ints for large parameters - #Z = x.nth_root(g, all=True) - #for z in Z: + # Z = x.nth_root(g, all=True) + # for z in Z: # if z.multiplicative_order() == r: # break f = z.minimal_polynomial() @@ -286,7 +286,7 @@ def check_consistency(self, n): K = FiniteField(p**n, modulus=self.polynomial(n), names='a') a = K.gen() for m in n.divisors(): - assert (a**((p**n-1)//(p**m-1))).minimal_polynomial() == self.polynomial(m) + assert (a ** ((p**n - 1) // (p**m - 1))).minimal_polynomial() == self.polynomial(m) def _find_pow_of_frobenius(p, n, x, y): @@ -316,6 +316,7 @@ def _find_pow_of_frobenius(p, n, x, y): 11 """ from .integer_mod import mod + for i in range(n): if x == y: break @@ -410,11 +411,12 @@ def _frobenius_shift(K, generators, check_only=False): n = K.degree() compatible = {} from .integer_mod import mod + for m in n.divisors(): compatible[m] = {} for q, x in generators.items(): - for m in (n//q).divisors(): - compatible[m][q] = x**((p**(n//q)-1)//(p**m-1)) + for m in (n // q).divisors(): + compatible[m][q] = x ** ((p ** (n // q) - 1) // (p**m - 1)) if check_only: for m in n.divisors(): try: @@ -431,18 +433,17 @@ def _frobenius_shift(K, generators, check_only=False): crt[(i, j)] = [] for m in n.divisors(): mqlist = sorted(compatible[m].keys()) - for k in range(1,len(mqlist)): + for k in range(1, len(mqlist)): j = qlist.index(mqlist[k]) - i = qlist.index(mqlist[k-1]) - crt[(i,j)].append(_find_pow_of_frobenius(p, m, compatible[m][qlist[j]], compatible[m][qlist[i]])) + i = qlist.index(mqlist[k - 1]) + crt[(i, j)].append(_find_pow_of_frobenius(p, m, compatible[m][qlist[j]], compatible[m][qlist[i]])) for i, j in list(crt): - L = crt[(i,j)] + L = crt[(i, j)] running = mod(0, 1) for a in L: running = _crt_non_coprime(running, a) - crt[(i,j)] = [(mod(running, qq**(running.modulus().valuation(qq))), - running.modulus().valuation(qq)) for qq in qlist] - crt[(j,i)] = [(-a, level) for a, level in crt[(i,j)]] + crt[(i, j)] = [(mod(running, qq ** (running.modulus().valuation(qq))), running.modulus().valuation(qq)) for qq in qlist] + crt[(j, i)] = [(-a, level) for a, level in crt[(i, j)]] # Let x_j be the power of Frobenius we apply to generators[qlist[j]], for 0 < j < len(qlist) # We have some direct conditions on the x_j: x_j reduces to each entry in crt[(0,j)]. # But we also have the equations x_j - x_i reduces to each entry in crt[(i,j)]. @@ -453,15 +454,16 @@ def _frobenius_shift(K, generators, check_only=False): # We can set x_0=0 everywhere, can get an initial setting of x_j from the c_0j. # We go through prime by prime. import bisect + frob_powers = [mod(0, 1) for _ in qlist] def find_leveller(qindex, level, x, xleveled, searched, i): searched[i] = True crt_possibles = [] - for j in range(1,len(qlist)): + for j in range(1, len(qlist)): if i == j: continue - if crt[(i,j)][qindex][1] >= level: + if crt[(i, j)][qindex][1] >= level: if xleveled[j]: return [j] if j not in searched: @@ -477,16 +479,16 @@ def propagate_levelling(qindex, level, x, xleveled, i): for j in range(1, len(qlist)): if i == j: continue - if not xleveled[j] and crt[(i,j)][qindex][1] >= level: - newxj = x[i][0] + crt[(i,j)][qindex][0] - x[j] = (newxj, min(x[i][1], crt[(i,j)][qindex][1])) + if not xleveled[j] and crt[(i, j)][qindex][1] >= level: + newxj = x[i][0] + crt[(i, j)][qindex][0] + x[j] = (newxj, min(x[i][1], crt[(i, j)][qindex][1])) xleveled[j] = True propagate_levelling(qindex, level, x, xleveled, j) for qindex in range(len(qlist)): q = qlist[qindex] # We include the initial 0 to match up our indexing with crt. - x = [0] + [crt[(0,j)][qindex] for j in range(1,len(qlist))] + x = [0] + [crt[(0, j)][qindex] for j in range(1, len(qlist))] # We first check that our equations are consistent and # determine which powers of q occur as moduli. levels = [] @@ -494,16 +496,16 @@ def propagate_levelling(qindex, level, x, xleveled, i): for i in range(j): # we need crt[(0,j)] = crt[(0,i)] + crt[(i,j)] if i != 0: - assert x[j][0] == x[i][0] + crt[(i,j)][qindex][0] - level = crt[(i,j)][qindex][1] + assert x[j][0] == x[i][0] + crt[(i, j)][qindex][0] + level = crt[(i, j)][qindex][1] if level > 0: - ins = bisect.bisect_left(levels,level) + ins = bisect.bisect_left(levels, level) if ins == len(levels): levels.append(level) elif levels[ins] != level: levels.insert(ins, level) for level in levels: - xleveled = [0] + [x[i][1] >= level for i in range(1,len(qlist))] + xleveled = [0] + [x[i][1] >= level for i in range(1, len(qlist))] while True: try: i = xleveled.index(False, 1) @@ -516,18 +518,18 @@ def propagate_levelling(qindex, level, x, xleveled, i): propagate_levelling(qindex, level, x, xleveled, i) else: levelling_path.append(i) - for m in range(1,len(path)): + for m in range(1, len(path)): # This point on the path may have already # been leveled in a previous propagation. if not xleveled[path[m]]: - newx = x[path[m-1]][0] + crt[(path[m-1],path[m])][qindex][0] - x[path[m]] = (newx, min(x[path[m-1]][1], crt[(path[m-1],path[m])][qindex][1])) + newx = x[path[m - 1]][0] + crt[(path[m - 1], path[m])][qindex][0] + x[path[m]] = (newx, min(x[path[m - 1]][1], crt[(path[m - 1], path[m])][qindex][1])) xleveled[path[m]] = True propagate_levelling(qindex, level, x, xleveled, path[m]) except ValueError: break - for j in range(1,len(qlist)): + for j in range(1, len(qlist)): frob_powers[j] = frob_powers[j].crt(x[j][0]) for j in range(1, len(qlist)): - generators[qlist[j]] = generators[qlist[j]]**(p**(-frob_powers[j]).lift()) + generators[qlist[j]] = generators[qlist[j]] ** (p ** (-frob_powers[j]).lift()) _frobenius_shift(K, generators, check_only=True) diff --git a/src/sage/rings/finite_rings/finite_field_constructor.py b/src/sage/rings/finite_rings/finite_field_constructor.py index 5abf92074e1..1b13bae764a 100644 --- a/src/sage/rings/finite_rings/finite_field_constructor.py +++ b/src/sage/rings/finite_rings/finite_field_constructor.py @@ -499,6 +499,7 @@ class FiniteFieldFactory(UniqueFactory): sage: GF(5, 2) is GF((5, 2)) True """ + def __init__(self, *args, **kwds): """ Initialization. @@ -511,11 +512,7 @@ def __init__(self, *args, **kwds): super().__init__(*args, **kwds) @rename_keyword(impl='implementation') - def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, - implementation=None, proof=None, - check_prime: bool = True, check_irreducible: bool = True, - prefix=None, repr=None, elem_cache=None, - **kwds): + def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, implementation=None, proof=None, check_prime: bool = True, check_irreducible: bool = True, prefix=None, repr=None, elem_cache=None, **kwds): """ EXAMPLES:: @@ -657,6 +654,7 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, from sage.structure.proof.proof import WithProof from sage.structure.proof.all import arithmetic + if proof is None: proof = arithmetic() with WithProof('arithmetic', proof): @@ -722,6 +720,7 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, # a modulus of None is a shorthand for x-1. if modulus is not None or implementation != 'modn': from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(FiniteField(p), 'x') if modulus is None: modulus = R.irreducible_element(n) @@ -739,7 +738,7 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, if modulus.degree() != n: raise ValueError("the degree of the modulus does not equal the degree of the field") # If modulus is x - 1 for implementation="modn", set it to None - if implementation == 'modn' and modulus.list() == [-1,1]: + if implementation == 'modn' and modulus.list() == [-1, 1]: modulus = None if modulus is None: check_irreducible = False @@ -750,7 +749,7 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, if repr is None: repr = 'poly' if elem_cache is None: - elem_cache = (order < 500) + elem_cache = order < 500 else: # This has the effect of ignoring these keywords repr = None @@ -821,7 +820,7 @@ def create_object(self, version, key, **kwds): # We can set the defaults here to be those for givaro # as they are otherwise ignored repr = 'poly' - elem_cache = (order < 500) + elem_cache = order < 500 check_prime = check_irreducible = False elif len(key) == 8: # For backward compatibility of pickles (see trac #21433) @@ -839,6 +838,7 @@ def create_object(self, version, key, **kwds): order, name, modulus, implementation, p, n, proof, prefix, repr, elem_cache, check_prime, check_irreducible = key from sage.structure.proof.proof import WithProof + with WithProof('arithmetic', proof): if check_prime and not p.is_prime(): raise ValueError("the order of a finite field must be a prime power") @@ -849,6 +849,7 @@ def create_object(self, version, key, **kwds): if n != 1: raise ValueError("the 'modn' implementation requires a prime order") from .finite_field_prime_modn import FiniteField_prime_modn + # Using a check option here is probably a worthwhile # compromise since this constructor is simple and used a # huge amount. @@ -864,9 +865,11 @@ def create_object(self, version, key, **kwds): K = FiniteField_givaro(order, name, modulus, repr, elem_cache) elif implementation == 'ntl': from .finite_field_ntl_gf2e import FiniteField_ntl_gf2e + K = FiniteField_ntl_gf2e(order, name, modulus) elif implementation == 'pari_ffelt' or implementation == 'pari': from .finite_field_pari_ffelt import FiniteField_pari_ffelt + K = FiniteField_pari_ffelt(p, modulus, name) else: raise ValueError("no such finite field implementation: %r" % implementation) diff --git a/src/sage/rings/finite_rings/finite_field_givaro.py b/src/sage/rings/finite_rings/finite_field_givaro.py index e9904a80acd..c1bf13ca3a7 100644 --- a/src/sage/rings/finite_rings/finite_field_givaro.py +++ b/src/sage/rings/finite_rings/finite_field_givaro.py @@ -6,7 +6,7 @@ used as minimal polynomial. """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2010-2012 David Roe # Copyright (C) 2012 Travis Scrimshaw # Copyright (C) 2013 Peter Bruin @@ -17,7 +17,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.integer import Integer @@ -101,6 +101,7 @@ class FiniteField_givaro(FiniteField): sage: GF(1009, implementation='givaro', modulus='conway').modulus() x + 998 """ + def __init__(self, q, name='a', modulus=None, repr='poly', cache=False): """ Initialize ``self``. @@ -132,9 +133,11 @@ def __init__(self, q, name='a', modulus=None, repr='poly', cache=False): raise ValueError("q must be < 2^16") from .finite_field_constructor import GF + FiniteField.__init__(self, GF(p), name, normalize=False) from sage.rings.polynomial.polynomial_element import Polynomial + if not isinstance(modulus, Polynomial): raise TypeError("modulus must be a polynomial") @@ -202,7 +205,7 @@ def _repr_option(self, key): False """ if key == 'element_is_atomic': - return self._cache.repr != 0 # 0 means repr='poly' + return self._cache.repr != 0 # 0 means repr='poly' return super()._repr_option(key) def random_element(self, *args, **kwds): @@ -424,6 +427,7 @@ def prime_subfield(self): return self._prime_subfield except AttributeError: from .finite_field_constructor import GF + self._prime_subfield = GF(self.characteristic()) return self._prime_subfield @@ -513,6 +517,7 @@ def __iter__(self): [0, a, a + 1, 1] """ from .element_givaro import FiniteField_givaro_iterator + return FiniteField_givaro_iterator(self._cache) def a_times_b_plus_c(self, a, b, c): @@ -610,4 +615,5 @@ def frobenius_endomorphism(self, n=1): - Xavier Caruso (2012-06-29) """ from sage.rings.finite_rings.hom_finite_field_givaro import FrobeniusEndomorphism_givaro + return FrobeniusEndomorphism_givaro(self, n) diff --git a/src/sage/rings/finite_rings/finite_field_ntl_gf2e.py b/src/sage/rings/finite_rings/finite_field_ntl_gf2e.py index efc7b56feeb..76abadf112a 100644 --- a/src/sage/rings/finite_rings/finite_field_ntl_gf2e.py +++ b/src/sage/rings/finite_rings/finite_field_ntl_gf2e.py @@ -2,7 +2,7 @@ Finite fields of characteristic 2 """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2011 David Roe # Copyright (C) 2012 Travis Scrimshaw # Copyright (C) 2013 Peter Bruin @@ -13,7 +13,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.rings.finite_rings.finite_field_base import FiniteField from sage.libs.pari import pari @@ -35,9 +35,11 @@ def late_import(): global Cache_ntl_gf2e, GF, GF2 import sage.rings.finite_rings.element_ntl_gf2e + Cache_ntl_gf2e = sage.rings.finite_rings.element_ntl_gf2e.Cache_ntl_gf2e import sage.rings.finite_rings.finite_field_constructor + GF = sage.rings.finite_rings.finite_field_constructor.GF GF2 = GF(2) @@ -127,6 +129,7 @@ def __init__(self, q, names='a', modulus=None, repr='poly'): FiniteField.__init__(self, GF2, names, normalize=True) from sage.rings.polynomial.polynomial_element import Polynomial + if not isinstance(modulus, Polynomial): raise TypeError("modulus must be a polynomial") diff --git a/src/sage/rings/finite_rings/finite_field_pari_ffelt.py b/src/sage/rings/finite_rings/finite_field_pari_ffelt.py index d17cca3570e..b492083ea17 100644 --- a/src/sage/rings/finite_rings/finite_field_pari_ffelt.py +++ b/src/sage/rings/finite_rings/finite_field_pari_ffelt.py @@ -7,14 +7,14 @@ finite_field_ext_pari.py by William Stein et al. """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2013 Peter Bruin # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from cypari2.handle_error import PariError @@ -100,6 +100,7 @@ class FiniteField_pari_ffelt(FiniteField): sage: loads(K.dumps()) == K True """ + def __init__(self, p, modulus, name=None): """ Create a finite field of characteristic `p` defined by the @@ -252,4 +253,4 @@ def _pari_frobenius(self, k=1): i += 1 fi = self.__pari_frobenius_powers[-1].ffcompomap(f1) self.__pari_frobenius_powers.append(fi) - return self.__pari_frobenius_powers[k-1] + return self.__pari_frobenius_powers[k - 1] diff --git a/src/sage/rings/finite_rings/finite_field_prime_modn.py b/src/sage/rings/finite_rings/finite_field_prime_modn.py index 6fe42c54770..4c5fa2756d4 100644 --- a/src/sage/rings/finite_rings/finite_field_prime_modn.py +++ b/src/sage/rings/finite_rings/finite_field_prime_modn.py @@ -13,7 +13,7 @@ sage: TestSuite(k).run() """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2006 William Stein # Copyright (C) 2008 Martin Albrecht # @@ -22,10 +22,11 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#*****************************************************************************` +# *****************************************************************************` from sage.rings.finite_rings.finite_field_base import FiniteField as FiniteField_generic from sage.categories.finite_fields import FiniteFields + _FiniteFields = FiniteFields() from sage.rings.finite_rings import integer_mod_ring @@ -50,6 +51,7 @@ class FiniteField_prime_modn(FiniteField_generic, integer_mod_ring.IntegerModRin sage: FiniteField(next_prime(1000)) # needs sage.rings.finite_rings Finite Field of size 1009 """ + def __init__(self, p, check=True, modulus=None): """ Return a new finite field of order `p` where `p` is prime. @@ -140,9 +142,8 @@ def _coerce_map_from_(self, S): return integer_mod.Integer_to_IntegerMod(self) if isinstance(S, IntegerModRing_generic): from .residue_field import ResidueField_generic - if (S.characteristic() % self.characteristic() == 0 and - (not isinstance(S, ResidueField_generic) or - S.degree() == 1)): + + if S.characteristic() % self.characteristic() == 0 and (not isinstance(S, ResidueField_generic) or S.degree() == 1): try: return integer_mod.IntegerMod_to_IntegerMod(S, self) except TypeError: @@ -167,6 +168,7 @@ def _convert_map_from_(self, R): To: Finite Field of size 3 """ from sage.rings.padics.padic_generic import pAdicGeneric, ResidueReductionMap + if isinstance(R, pAdicGeneric) and R.residue_field() is self: return ResidueReductionMap._create_(R, self) @@ -365,6 +367,4 @@ def degree(self): return Integer(1) -register_unpickle_override( - 'sage.rings.finite_field_prime_modn', 'FiniteField_prime_modn', - FiniteField_prime_modn) +register_unpickle_override('sage.rings.finite_field_prime_modn', 'FiniteField_prime_modn', FiniteField_prime_modn) diff --git a/src/sage/rings/finite_rings/galois_group.py b/src/sage/rings/finite_rings/galois_group.py index 880aea93c76..0536a37a6c1 100644 --- a/src/sage/rings/finite_rings/galois_group.py +++ b/src/sage/rings/finite_rings/galois_group.py @@ -58,6 +58,7 @@ class GaloisGroup_GF(GaloisGroup_cyc): r""" The Galois group of a finite field. """ + Element = GaloisGroup_GFElement def __init__(self, field): diff --git a/src/sage/rings/finite_rings/homset.py b/src/sage/rings/finite_rings/homset.py index ccff9dbabc5..8de0ce51f50 100644 --- a/src/sage/rings/finite_rings/homset.py +++ b/src/sage/rings/finite_rings/homset.py @@ -48,11 +48,12 @@ class FiniteFieldHomset(RingHomset_generic): """ Set of homomorphisms with domain a given finite field. """ -# def __init__(self, R, S, category=None): -# if category is None: -# from sage.categories.finite_fields import FiniteFields -# category = FiniteFields() -# RingHomset_generic.__init__(self, R, S, category) + + # def __init__(self, R, S, category=None): + # if category is None: + # from sage.categories.finite_fields import FiniteFields + # category = FiniteFields() + # RingHomset_generic.__init__(self, R, S, category) def __call__(self, im_gens, base_map=None, check=True): """ @@ -115,17 +116,15 @@ def __call__(self, im_gens, base_map=None, check=True): if self.domain().degree() == 1: from sage.rings.finite_rings.hom_prime_finite_field import FiniteFieldHomomorphism_prime - return FiniteFieldHomomorphism_prime(self, im_gens, - base_map=base_map, check=check) + + return FiniteFieldHomomorphism_prime(self, im_gens, base_map=base_map, check=check) if isinstance(self.codomain(), FiniteField): - return FiniteFieldHomomorphism_generic(self, im_gens, - base_map=base_map, check=check) + return FiniteFieldHomomorphism_generic(self, im_gens, base_map=base_map, check=check) # Currently, FiniteFieldHomomorphism_generic does not work if # the codomain is not derived from the finite field base class; # in that case, we have to fall back to the generic # implementation for rings - return RingHomomorphism_im_gens(self, im_gens, - base_map=base_map, check=check) + return RingHomomorphism_im_gens(self, im_gens, base_map=base_map, check=check) def _repr_(self): """ @@ -336,9 +335,11 @@ def _an_element_(self): return L.coerce_map_from(K) if not K.degree().divides(L.degree()): from sage.categories.sets_cat import EmptySetError + raise EmptySetError('no homomorphisms from %s to %s' % (K, L)) return K.hom([K.modulus().any_root(L)]) from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.rings.finite_field_morphism', 'FiniteFieldHomset', FiniteFieldHomset) diff --git a/src/sage/rings/finite_rings/integer_mod_ring.py b/src/sage/rings/finite_rings/integer_mod_ring.py index 477dc4a7ef9..c6bc3bcdacd 100644 --- a/src/sage/rings/finite_rings/integer_mod_ring.py +++ b/src/sage/rings/finite_rings/integer_mod_ring.py @@ -79,9 +79,11 @@ from sage.libs.pari import pari from cypari2.handle_error import PariError except ImportError: + class PariError(Exception): pass + from sage.misc.cachefunc import cached_method from sage.structure.factory import UniqueFactory @@ -203,6 +205,7 @@ class IntegerModFactory(UniqueFactory): sage: IntegerModRing._cache.clear() """ + def get_object(self, version, key, extra_args): out = super().get_object(version, key, extra_args) category = extra_args.get('category', None) @@ -224,6 +227,7 @@ def create_key_and_extra_args(self, order=0, is_field=False, category=None): """ if is_field: from sage.categories.fields import Fields + return order, {'category': Fields()} return order, {} @@ -251,6 +255,7 @@ def create_object(self, version, order, **kwds): from sage.categories.noetherian_rings import NoetherianRings from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.category import JoinCategory + default_category = JoinCategory((NoetherianRings(), FiniteEnumeratedSets())) ZZ = integer_ring.IntegerRing() @@ -275,12 +280,10 @@ def _unit_gens_primepowercase(p, r): return [] if r == 2: return [(integer_mod.Mod(3, 4), integer.Integer(2))] - return [(integer_mod.Mod(-1, pr), integer.Integer(2)), - (integer_mod.Mod(5, pr), integer.Integer(2**(r - 2)))] + return [(integer_mod.Mod(-1, pr), integer.Integer(2)), (integer_mod.Mod(5, pr), integer.Integer(2 ** (r - 2)))] # odd prime - return [(integer_mod.Mod(primitive_root(pr, check=False), pr), - integer.Integer(p**(r - 1) * (p - 1)))] + return [(integer_mod.Mod(primitive_root(pr, check=False), pr), integer.Integer(p ** (r - 1) * (p - 1)))] @richcmp_method @@ -423,6 +426,7 @@ class IntegerModRing_generic(quotient_ring.QuotientRing_generic, sage.rings.abc. sage: a**(10^62) 61 """ + def __init__(self, order, cache=None, category=None): """ Create with the command ``IntegerModRing(order)``. @@ -467,9 +471,7 @@ def __init__(self, order, cache=None, category=None): # name 'x' is used because it's also used for the ring of # integers: see the __init__ method for IntegerRing_class in # sage/rings/integer_ring.pyx. - quotient_ring.QuotientRing_generic.__init__(self, ZZ, ZZ.ideal(order), - names=('x',), - category=category) + quotient_ring.QuotientRing_generic.__init__(self, ZZ, ZZ.ideal(order), names=('x',), category=category) # We want that the ring is its own base ring. self._base = self if cache is None: @@ -571,9 +573,10 @@ def list_of_elements_of_multiplicative_group(self) -> list: [0] """ import sage.rings.fast_arith as a - if self.__order <= 46340: # todo: don't hard code + + if self.__order <= 46340: # todo: don't hard code gcd = a.arith_int().gcd_int - elif self.__order <= 2147483647: # todo: don't hard code + elif self.__order <= 2147483647: # todo: don't hard code gcd = a.arith_llong().gcd_longlong else: raise NotImplementedError("list_of_elements_of_multiplicative_group() is not implemented for large moduli") @@ -607,8 +610,7 @@ def multiplicative_subgroups(self): sage: IntegerModRing(3).multiplicative_subgroups() # optional - gap_package_polycyclic ((2,), ()) """ - return tuple(tuple(g.value() for g in H.gens()) - for H in self.unit_group().subgroups()) + return tuple(tuple(g.value() for g in H.gens()) for H in self.unit_group().subgroups()) def is_integral_domain(self, proof=None): """ @@ -712,6 +714,7 @@ def is_field(self, proof=None): sage: IntegerModRing._cache.clear() """ from sage.categories.fields import Fields + if not proof: if self.category().is_subcategory(Fields()): return True @@ -721,12 +724,7 @@ def is_field(self, proof=None): self._factory_data[3]['category'] = Fields() else: if self.category().is_subcategory(Fields()): - raise ValueError(("THIS SAGE SESSION MIGHT BE SERIOUSLY COMPROMISED!\n" - "The order {} is not prime, but this ring has been put\n" - "into the category of fields. This may already have consequences\n" - "in other parts of Sage. Either it was a mistake of the user,\n" - "or a probabilistic primality test has failed.\n" - "In the latter case, please inform the developers.").format(self.order())) + raise ValueError(("THIS SAGE SESSION MIGHT BE SERIOUSLY COMPROMISED!\n" "The order {} is not prime, but this ring has been put\n" "into the category of fields. This may already have consequences\n" "in other parts of Sage. Either it was a mistake of the user,\n" "or a probabilistic primality test has failed.\n" "In the latter case, please inform the developers.").format(self.order())) return is_prime @cached_method @@ -754,6 +752,7 @@ def field(self): if not self.is_field(): raise ValueError("self must be a field") from . import finite_field_constructor + k = finite_field_constructor.FiniteField(self.order()) self.__field = k return k @@ -930,8 +929,7 @@ def square_roots_of_one(self): v = [self(1), self(3)] else: # n >= 8 half_ord = n // 2 - v = [self(1), self(-1), - self(half_ord - 1), self(half_ord + 1)] + v = [self(1), self(-1), self(half_ord - 1), self(half_ord + 1)] else: v = [self(1), self(-1)] else: @@ -948,6 +946,7 @@ def square_roots_of_one(self): # Now combine in all possible ways using the CRT basis = CRT_basis(moduli) from sage.misc.mrange import cartesian_product_iterator + v = [] for x in cartesian_product_iterator(vmod): # x is a specific choice of roots modulo each prime power divisor @@ -987,9 +986,9 @@ def factored_unit_order(self): """ ans = [] from sage.structure.factorization import Factorization + for p, e in self.factored_order(): - ans.append(Factorization([(p, e - 1)]) * - factor(p - 1, int_=(self.__order < 2**31))) + ans.append(Factorization([(p, e - 1)]) * factor(p - 1, int_=(self.__order < 2**31))) return ans def characteristic(self): @@ -1144,6 +1143,7 @@ def _element_constructor_(self, x): except TypeError: if isinstance(x, GapElement): from sage.libs.gap.libgap import libgap + return libgap(x).sage() raise # Continue up with the original TypeError @@ -1249,6 +1249,7 @@ def _convert_map_from_(self, other): To: Ring of integers modulo 81 """ from sage.rings.padics.padic_generic import pAdicGeneric, ResidueReductionMap + if isinstance(other, pAdicGeneric) and other.degree() == 1: p = other.prime() N = self.cardinality() @@ -1468,6 +1469,7 @@ def unit_group(self, algorithm='sage'): ValueError: unknown algorithm 'bogus' for computing the unit group """ from sage.groups.abelian_gps.values import AbelianGroupWithValues + if algorithm == 'sage': n = self.order() gens = [] @@ -1638,7 +1640,7 @@ def _lift_residue_field_root(p, e, f, fprime, root): # Unique lift, use Newton iteration prec = 1 while True: - prec = min(2*prec, e) + prec = min(2 * prec, e) Zp_prec = Zmod(p**prec) root = Zp_prec(root.lift()) deriv = fprime(root) @@ -1931,10 +1933,7 @@ def _roots_univariate_polynomial(self, f, ring=None, multiplicities=True, algori if multiplicities: if deg < 0 or not self.is_field(): - raise NotImplementedError( - "root finding with multiplicities for this polynomial not" - " implemented (try the multiplicities=False option)" - ) + raise NotImplementedError("root finding with multiplicities for this polynomial not" " implemented (try the multiplicities=False option)") # Roots of non-zero polynomial over finite fields by factorization return f.change_ring(f.base_ring().field()).roots(multiplicities=multiplicities) @@ -1991,9 +1990,7 @@ def _roots_univariate_polynomial(self, f, ring=None, multiplicities=True, algori this_prime_power = [] for root in mod_p_roots: - this_prime_power.extend( - self._lift_residue_field_root(p, e, fpe, fpe_prime, root) - ) + this_prime_power.extend(self._lift_residue_field_root(p, e, fpe, fpe_prime, root)) prime_power_roots.append(this_prime_power) # Combine using Chinese Remainder Theorem @@ -2002,7 +1999,7 @@ def _roots_univariate_polynomial(self, f, ring=None, multiplicities=True, algori for res in cartesian_product_iterator(prime_power_roots): root = self.zero() for c, x in zip(ppwr_basis, res): - root += c*x.lift() + root += c * x.lift() result.append(root) return result @@ -2049,6 +2046,7 @@ def degree(self): # Register unpickling methods for backward compatibility. from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.rings.integer_mod_ring', 'IntegerModRing_generic', IntegerModRing_generic) diff --git a/src/sage/rings/finite_rings/maps_finite_field.py b/src/sage/rings/finite_rings/maps_finite_field.py index a6bc70ad81d..a866a5f4a29 100644 --- a/src/sage/rings/finite_rings/maps_finite_field.py +++ b/src/sage/rings/finite_rings/maps_finite_field.py @@ -9,7 +9,7 @@ - Kwankyu Lee (2017-11-07): initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2017 Kwankyu # # This program is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.morphism import Morphism @@ -27,6 +27,7 @@ class FiniteFieldVectorSpaceIsomorphism(Morphism): Base class of the vector space isomorphism between a finite field and a vector space over a subfield of the finite field. """ + def _repr_(self): """ Return the string representation of this isomorphism @@ -76,6 +77,7 @@ class MorphismVectorSpaceToFiniteField(FiniteFieldVectorSpaceIsomorphism): """ Isomorphisms from vector spaces to finite fields. """ + def __init__(self, V, K, C): """ Initialize. @@ -117,9 +119,9 @@ def _call_(self, v): [1, z6, z6^2] """ E = self.codomain() # = GF((p^n)^m) - V = self.domain() # = GF(p^n)^m + V = self.domain() # = GF(p^n)^m m = V.dimension() - F = V.base_ring() # = GF(p^n) + F = V.base_ring() # = GF(p^n) n = F.degree() if m == n == 1: @@ -128,7 +130,7 @@ def _call_(self, v): # expand v as a vector over GF(p) w = self._C.row_ambient_module()() for i in range(m): - w[i*n:(i+1)*n] = v[i]._vector_() + w[i * n : (i + 1) * n] = v[i]._vector_() return E(w * self._C) @@ -136,6 +138,7 @@ class MorphismFiniteFieldToVectorSpace(FiniteFieldVectorSpaceIsomorphism): """ Isomorphisms from finite fields to vector spaces """ + def __init__(self, K, V, C): """ Initialize. @@ -178,11 +181,11 @@ def _call_(self, e): sage: psi(E.gen()) (0, 1, 0) """ - V = self.codomain() # = GF(p^n)^m + V = self.codomain() # = GF(p^n)^m m = V.dimension() - F = V.base_ring() # = GF(p^n) + F = V.base_ring() # = GF(p^n) n = F.degree() w = e._vector_() * self._C if F.degree() > 1: - return V([F(w[i*n:(i+1)*n]) for i in range(m)]) + return V([F(w[i * n : (i + 1) * n]) for i in range(m)]) return w diff --git a/src/sage/rings/fraction_field.py b/src/sage/rings/fraction_field.py index 25c29443b60..779a17d39e2 100644 --- a/src/sage/rings/fraction_field.py +++ b/src/sage/rings/fraction_field.py @@ -67,6 +67,7 @@ 1 1 """ + # **************************************************************************** # # Sage: Open Source Mathematical Software @@ -146,9 +147,8 @@ class FractionField_generic(ring.Field): """ The fraction field of an integral domain. """ - def __init__(self, R, - element_class=fraction_field_element.FractionFieldElement, - category=QuotientFields()): + + def __init__(self, R, element_class=fraction_field_element.FractionFieldElement, category=QuotientFields()): """ Create the fraction field of the integral domain ``R``. @@ -331,19 +331,17 @@ def wrapper(x): # special treatment for localizations from sage.rings.localization import Localization + if isinstance(S, Localization): parent = S.Hom(self) return parent.__make_element_class__(FractionFieldEmbedding)(S, self, category=parent.homset_category()) # Number fields also need to be handled separately. if isinstance(S, NumberField): - return CallableConvertMap(S, self, - self._number_field_to_frac_of_ring_of_integers, - parent_as_first_arg=False) + return CallableConvertMap(S, self, self._number_field_to_frac_of_ring_of_integers, parent_as_first_arg=False) # special treatment for LaurentPolynomialRings - if (isinstance(S, LaurentPolynomialRing_generic) and - self._R.fraction_field().has_coerce_map_from(S.base_ring())): + if isinstance(S, LaurentPolynomialRing_generic) and self._R.fraction_field().has_coerce_map_from(S.base_ring()): def converter(x, y=None): if y is None: @@ -351,15 +349,14 @@ def converter(x, y=None): xnum, xden = x._fraction_pair() ynum, yden = y._fraction_pair() return self._element_class(self, xnum * yden, xden * ynum) + return CallableConvertMap(S, self, converter, parent_as_first_arg=False) - if (isinstance(S, FractionField_generic) and - self._R.has_coerce_map_from(S.ring())): + if isinstance(S, FractionField_generic) and self._R.has_coerce_map_from(S.ring()): return CallableConvertMap(S, self, wrapper, parent_as_first_arg=False) if self._R.has_coerce_map_from(S): - return CallableConvertMap(S, self, self._element_class, - parent_as_first_arg=True) + return CallableConvertMap(S, self, self._element_class, parent_as_first_arg=True) return None @@ -388,7 +385,7 @@ def _number_field_to_frac_of_ring_of_integers(self, x): sage: F(1/a) (a^4 - 3*a^3 + 2424*a^2 + 2)/232 """ - f = x.polynomial() # Polynomial over QQ + f = x.polynomial() # Polynomial over QQ d = f.denominator() # Integer return self._element_class(self, numerator=d * x, denominator=d) @@ -726,18 +723,19 @@ def _element_constructor_(self, x, y=None, coerce=True): if parent(x) is self: return x from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(self.ring(), PolynomialRing_generic): from sage.rings.power_series_ring_element import PowerSeries from sage.rings.laurent_series_ring_element import LaurentSeries + if isinstance(x, PowerSeries): from sage.misc.superseded import deprecation - deprecation( - 39485, - "Previously conversion from power series to rational function field truncates " - "instead of gives an approximation. Use .truncate() to recover the old behavior") + + deprecation(39485, "Previously conversion from power series to rational function field truncates " "instead of gives an approximation. Use .truncate() to recover the old behavior") x = x.laurent_series() if isinstance(x, LaurentSeries): from sage.rings.infinity import infinity + if x.prec() == infinity: return self(x.laurent_polynomial()) return self._convert_from_finite_precision_laurent_series(x) @@ -758,12 +756,14 @@ def _element_constructor_(self, x, y=None, coerce=True): if isinstance(x, str): from sage.misc.sage_eval import sage_eval + try: x = sage_eval(x, self.gens_dict_recursive()) except NameError: raise TypeError("unable to evaluate {!r} in {}".format(x, self)) if isinstance(y, str): from sage.misc.sage_eval import sage_eval + try: y = sage_eval(y, self.gens_dict_recursive()) except NameError: @@ -816,8 +816,7 @@ def resolve_fractions(x, y): try: x, y = resolve_fractions(x0, y0) except (AttributeError, TypeError): - raise TypeError("cannot convert {!r}/{!r} to an element of {}".format( - x0, y0, self)) + raise TypeError("cannot convert {!r}/{!r} to an element of {}".format(x0, y0, self)) try: return self._element_class(self, x, y, coerce=coerce) except TypeError: @@ -839,6 +838,7 @@ def construction(self): True """ from sage.categories.pushout import FractionField + return FractionField(), self.ring() def __eq__(self, other): @@ -987,9 +987,7 @@ def random_element(self, *args, **kwds): sage: while f.numerator().degree() != 5: ....: f = F.random_element(degree=5) """ - return self._element_class(self, self._R.random_element(*args, **kwds), - self._R._random_nonzero_element(*args, **kwds), - coerce=False, reduce=True) + return self._element_class(self, self._R.random_element(*args, **kwds), self._R._random_nonzero_element(*args, **kwds), coerce=False, reduce=True) def some_elements(self): r""" @@ -1012,10 +1010,7 @@ def some_elements(self): 2] """ ret = [self.zero(), self.one()] - ret.extend(self(a) / self(b) - for a in self._R.some_elements() - for b in self._R.some_elements() - if a != b and self(a) and self(b)) + ret.extend(self(a) / self(b) for a in self._R.some_elements() for b in self._R.some_elements() if a != b and self(a) and self(b)) return ret def _gcd_univariate_polynomial(self, f, g): @@ -1062,8 +1057,8 @@ class FractionField_1poly_field(FractionField_generic): Many of the functions here are included for coherence with number fields. """ - def __init__(self, R, - element_class=fraction_field_element.FractionFieldElement_1poly_field): + + def __init__(self, R, element_class=fraction_field_element.FractionFieldElement_1poly_field): """ Just change the default for ``element_class``. @@ -1145,6 +1140,7 @@ def function_field(self): :meth:`sage.rings.function_field.RationalFunctionField.field` """ from sage.rings.function_field.constructor import FunctionField + return FunctionField(self.base_ring(), names=self.variable_name()) def _coerce_map_from_(self, R): @@ -1167,10 +1163,13 @@ def _coerce_map_from_(self, R): from sage.rings.function_field.function_field_rational import ( RationalFunctionField, ) + if isinstance(R, RationalFunctionField) and self.variable_name() == R.variable_name() and self.base_ring() is R.constant_base_field(): from sage.categories.homset import Hom + parent = Hom(R, self) from sage.rings.function_field.maps import FunctionFieldToFractionField + return parent.__make_element_class__(FunctionFieldToFractionField)(parent) return super()._coerce_map_from_(R) @@ -1204,6 +1203,7 @@ class FractionFieldEmbedding(DefaultConvertMap_unique): sage: R.is_subring(R.fraction_field()) True """ + def is_surjective(self): r""" Return whether this map is surjective. @@ -1245,6 +1245,7 @@ def section(self): """ from sage.categories.homset import Hom from sage.categories.sets_with_partial_maps import SetsWithPartialMaps + parent = Hom(self.codomain(), self.domain(), SetsWithPartialMaps()) return parent.__make_element_class__(FractionFieldEmbeddingSection)(self) @@ -1301,6 +1302,7 @@ class FractionFieldEmbeddingSection(Section): True sage: TestSuite(f).run() """ + def _call_(self, x, check=True): r""" Evaluate this map at ``x``. diff --git a/src/sage/rings/fraction_field_FpT.pyi b/src/sage/rings/fraction_field_FpT.pyi index 2689984577b..e6d859f2e77 100644 --- a/src/sage/rings/fraction_field_FpT.pyi +++ b/src/sage/rings/fraction_field_FpT.pyi @@ -1,7 +1,6 @@ from typing import Any -def is_FpTElement(x: Any) -> bool: - ... +def is_FpTElement(x: Any) -> bool: ... class FpTElement: _numer: Any @@ -9,95 +8,39 @@ class FpTElement: initialized: bool p: int - def __init__(self, parent: Any, numer: Any, denom: Any = 1, coerce: bool = True, reduce: bool = True) -> None: - ... - - def _new_c(self) -> 'FpTElement': - ... - - def _copy_c(self) -> 'FpTElement': - ... - - def numer(self) -> Any: - ... - - def numerator(self) -> Any: - ... - - def denom(self) -> Any: - ... - - def denominator(self) -> Any: - ... - - def __call__(self, *args: Any, **kwds: Any) -> 'FpTElement': - ... - - def subs(self, in_dict: dict | None = None, *args: Any, **kwds: Any) -> 'FpTElement': - ... - - def valuation(self, v: Any) -> int: - ... - - def factor(self) -> Any: - ... - - def _repr_(self) -> str: - ... - - def _latex_(self) -> str: - ... - - def _richcmp_(self, other: 'FpTElement', op: int) -> bool: - ... - - def __hash__(self) -> int: - ... - - def __neg__(self) -> 'FpTElement': - ... - - def __invert__(self) -> 'FpTElement': - ... - - def _add_(self, other: 'FpTElement') -> 'FpTElement': - ... - - def _sub_(self, other: 'FpTElement') -> 'FpTElement': - ... - - def _mul_(self, other: 'FpTElement') -> 'FpTElement': - ... - - def _div_(self, other: 'FpTElement') -> 'FpTElement': - ... - - def next(self) -> 'FpTElement': - ... - - def _sqrt_or_None(self) -> 'FpTElement | None': - ... - - def is_square(self) -> bool: - ... - - def sqrt(self, extend: bool = True, all: bool = False) -> 'FpTElement | list[FpTElement]': - ... - - def __pow__(self, e: int, dummy: Any) -> 'FpTElement': - ... + def __init__(self, parent: Any, numer: Any, denom: Any = 1, coerce: bool = True, reduce: bool = True) -> None: ... + def _new_c(self) -> 'FpTElement': ... + def _copy_c(self) -> 'FpTElement': ... + def numer(self) -> Any: ... + def numerator(self) -> Any: ... + def denom(self) -> Any: ... + def denominator(self) -> Any: ... + def __call__(self, *args: Any, **kwds: Any) -> 'FpTElement': ... + def subs(self, in_dict: dict | None = None, *args: Any, **kwds: Any) -> 'FpTElement': ... + def valuation(self, v: Any) -> int: ... + def factor(self) -> Any: ... + def _repr_(self) -> str: ... + def _latex_(self) -> str: ... + def _richcmp_(self, other: 'FpTElement', op: int) -> bool: ... + def __hash__(self) -> int: ... + def __neg__(self) -> 'FpTElement': ... + def __invert__(self) -> 'FpTElement': ... + def _add_(self, other: 'FpTElement') -> 'FpTElement': ... + def _sub_(self, other: 'FpTElement') -> 'FpTElement': ... + def _mul_(self, other: 'FpTElement') -> 'FpTElement': ... + def _div_(self, other: 'FpTElement') -> 'FpTElement': ... + def next(self) -> 'FpTElement': ... + def _sqrt_or_None(self) -> 'FpTElement | None': ... + def is_square(self) -> bool: ... + def sqrt(self, extend: bool = True, all: bool = False) -> 'FpTElement | list[FpTElement]': ... + def __pow__(self, e: int, dummy: Any) -> 'FpTElement': ... class FpT: INTEGER_LIMIT: int - def __init__(self, R: Any, names: Any = None) -> None: - ... - - def __iter__(self) -> 'FpT_iter': - ... - - def iter(self, bound: Any = None, start: Any = None) -> 'FpT_iter': - ... + def __init__(self, R: Any, names: Any = None) -> None: ... + def __iter__(self) -> 'FpT_iter': ... + def iter(self, bound: Any = None, start: Any = None) -> 'FpT_iter': ... class FpT_iter: parent: Any @@ -105,113 +48,56 @@ class FpT_iter: cur: FpTElement g: Any - def __init__(self, parent: Any, degree: int | None = None, start: FpTElement = None) -> None: - ... - - def __cinit__(self, parent: Any, *args: Any, **kwds: Any) -> None: - ... - - def __dealloc__(self) -> None: - ... - - def __iter__(self) -> 'FpT_iter': - ... - - def __next__(self) -> FpTElement: - ... + def __init__(self, parent: Any, degree: int | None = None, start: FpTElement = None) -> None: ... + def __cinit__(self, parent: Any, *args: Any, **kwds: Any) -> None: ... + def __dealloc__(self) -> None: ... + def __iter__(self) -> 'FpT_iter': ... + def __next__(self) -> FpTElement: ... class Polyring_FpT_coerce: p: int - def __init__(self, R: Any) -> None: - ... - - def _extra_slots(self) -> dict: - ... - - def _update_slots(self, _slots: dict) -> None: - ... - - def _call_(self, _x: Any) -> FpTElement: - ... - - def _call_with_args(self, _x: Any, args: tuple = (), kwds: dict = {}) -> FpTElement: - ... - - def section(self) -> 'FpT_Polyring_section': - ... + def __init__(self, R: Any) -> None: ... + def _extra_slots(self) -> dict: ... + def _update_slots(self, _slots: dict) -> None: ... + def _call_(self, _x: Any) -> FpTElement: ... + def _call_with_args(self, _x: Any, args: tuple = (), kwds: dict = {}) -> FpTElement: ... + def section(self) -> 'FpT_Polyring_section': ... class FpT_Polyring_section: p: int - def __init__(self, f: Polyring_FpT_coerce) -> None: - ... - - def _extra_slots(self) -> dict: - ... - - def _update_slots(self, _slots: dict) -> None: - ... - - def _call_(self, _x: Any) -> Any: - ... + def __init__(self, f: Polyring_FpT_coerce) -> None: ... + def _extra_slots(self) -> dict: ... + def _update_slots(self, _slots: dict) -> None: ... + def _call_(self, _x: Any) -> Any: ... class Fp_FpT_coerce: p: int - def __init__(self, R: Any) -> None: - ... - - def _extra_slots(self) -> dict: - ... - - def _update_slots(self, _slots: dict) -> None: - ... - - def _call_(self, _x: Any) -> FpTElement: - ... - - def _call_with_args(self, _x: Any, args: tuple = (), kwds: dict = {}) -> FpTElement: - ... - - def section(self) -> 'FpT_Fp_section': - ... + def __init__(self, R: Any) -> None: ... + def _extra_slots(self) -> dict: ... + def _update_slots(self, _slots: dict) -> None: ... + def _call_(self, _x: Any) -> FpTElement: ... + def _call_with_args(self, _x: Any, args: tuple = (), kwds: dict = {}) -> FpTElement: ... + def section(self) -> 'FpT_Fp_section': ... class FpT_Fp_section: p: int - def __init__(self, f: Fp_FpT_coerce) -> None: - ... - - def _extra_slots(self) -> dict: - ... - - def _update_slots(self, _slots: dict) -> None: - ... - - def _call_(self, _x: Any) -> Any: - ... + def __init__(self, f: Fp_FpT_coerce) -> None: ... + def _extra_slots(self) -> dict: ... + def _update_slots(self, _slots: dict) -> None: ... + def _call_(self, _x: Any) -> Any: ... class ZZ_FpT_coerce: p: int - def __init__(self, R: Any) -> None: - ... - - def _extra_slots(self) -> dict: - ... - - def _update_slots(self, _slots: dict) -> None: - ... - - def _call_(self, _x: Any) -> FpTElement: - ... - - def _call_with_args(self, _x: Any, args: tuple = (), kwds: dict = {}) -> FpTElement: - ... - - def section(self) -> Any: - ... + def __init__(self, R: Any) -> None: ... + def _extra_slots(self) -> dict: ... + def _update_slots(self, _slots: dict) -> None: ... + def _call_(self, _x: Any) -> FpTElement: ... + def _call_with_args(self, _x: Any, args: tuple = (), kwds: dict = {}) -> FpTElement: ... + def section(self) -> Any: ... -def unpickle_FpT_element(K: Any, numer: Any, denom: Any) -> FpTElement: - ... +def unpickle_FpT_element(K: Any, numer: Any, denom: Any) -> FpTElement: ... diff --git a/src/sage/rings/fraction_field_element.pyi b/src/sage/rings/fraction_field_element.pyi index 4152598bbba..4a78509ac1b 100644 --- a/src/sage/rings/fraction_field_element.pyi +++ b/src/sage/rings/fraction_field_element.pyi @@ -1,139 +1,55 @@ from typing import Any, Union -def is_FractionFieldElement(x: Any) -> bool: - ... +def is_FractionFieldElement(x: Any) -> bool: ... class FractionFieldElement: _numerator: Any _denominator: Any _is_reduced: bool - def __init__(self, parent: Any, numerator: Any, denominator: Any = 1, coerce: bool = True, reduce: bool = True) -> None: - ... - - def _im_gens_(self, codomain: Any, im_gens: Any, base_map: Any = None) -> Any: - ... - - def reduce(self) -> None: - ... - - def __copy__(self) -> 'FractionFieldElement': - ... - - def numerator(self) -> Any: - ... - - def denominator(self) -> Any: - ... - - def is_square(self, root: bool = False) -> Union[bool, tuple[bool, Any]]: - ... - - def nth_root(self, n: int) -> 'FractionFieldElement': - ... - - def __hash__(self) -> int: - ... - - def __call__(self, *x: Any, **kwds: Any) -> 'FractionFieldElement': - ... - - def subs(self, in_dict: dict | None = None, *args: Any, **kwds: Any) -> 'FractionFieldElement': - ... - - def _is_atomic(self) -> bool: - ... - - def _repr_(self) -> str: - ... - - def _latex_(self) -> str: - ... - - def _magma_init_(self, magma: Any) -> str: - ... - - def _add_(self, right: 'FractionFieldElement') -> 'FractionFieldElement': - ... - - def _mul_(self, right: 'FractionFieldElement') -> 'FractionFieldElement': - ... - - def _div_(self, right: 'FractionFieldElement') -> 'FractionFieldElement': - ... - - def __int__(self) -> int: - ... - - def __float__(self) -> float: - ... - - def __complex__(self) -> complex: - ... - - def _rational_(self) -> 'FractionFieldElement': - ... - - def _conversion(self, R: Any) -> 'FractionFieldElement': - ... - - def __pow__(self, right: int, dummy: Any) -> 'FractionFieldElement': - ... - - def __neg__(self) -> 'FractionFieldElement': - ... - - def __abs__(self) -> 'FractionFieldElement': - ... - - def __invert__(self) -> 'FractionFieldElement': - ... - - def _richcmp_(self, other: 'FractionFieldElement', op: int) -> bool: - ... - - def valuation(self, v: Any = None) -> int: - ... - - def __bool__(self) -> bool: - ... - - def is_zero(self) -> bool: - ... - - def is_one(self) -> bool: - ... - - def _symbolic_(self, ring: Any) -> 'FractionFieldElement': - ... - - def __reduce__(self) -> tuple: - ... - - def _evaluate_polynomial(self, pol: Any) -> 'FractionFieldElement': - ... - - def specialization(self, D: Any = None, phi: Any = None) -> 'FractionFieldElement': - ... + def __init__(self, parent: Any, numerator: Any, denominator: Any = 1, coerce: bool = True, reduce: bool = True) -> None: ... + def _im_gens_(self, codomain: Any, im_gens: Any, base_map: Any = None) -> Any: ... + def reduce(self) -> None: ... + def __copy__(self) -> 'FractionFieldElement': ... + def numerator(self) -> Any: ... + def denominator(self) -> Any: ... + def is_square(self, root: bool = False) -> Union[bool, tuple[bool, Any]]: ... + def nth_root(self, n: int) -> 'FractionFieldElement': ... + def __hash__(self) -> int: ... + def __call__(self, *x: Any, **kwds: Any) -> 'FractionFieldElement': ... + def subs(self, in_dict: dict | None = None, *args: Any, **kwds: Any) -> 'FractionFieldElement': ... + def _is_atomic(self) -> bool: ... + def _repr_(self) -> str: ... + def _latex_(self) -> str: ... + def _magma_init_(self, magma: Any) -> str: ... + def _add_(self, right: 'FractionFieldElement') -> 'FractionFieldElement': ... + def _mul_(self, right: 'FractionFieldElement') -> 'FractionFieldElement': ... + def _div_(self, right: 'FractionFieldElement') -> 'FractionFieldElement': ... + def __int__(self) -> int: ... + def __float__(self) -> float: ... + def __complex__(self) -> complex: ... + def _rational_(self) -> 'FractionFieldElement': ... + def _conversion(self, R: Any) -> 'FractionFieldElement': ... + def __pow__(self, right: int, dummy: Any) -> 'FractionFieldElement': ... + def __neg__(self) -> 'FractionFieldElement': ... + def __abs__(self) -> 'FractionFieldElement': ... + def __invert__(self) -> 'FractionFieldElement': ... + def _richcmp_(self, other: 'FractionFieldElement', op: int) -> bool: ... + def valuation(self, v: Any = None) -> int: ... + def __bool__(self) -> bool: ... + def is_zero(self) -> bool: ... + def is_one(self) -> bool: ... + def _symbolic_(self, ring: Any) -> 'FractionFieldElement': ... + def __reduce__(self) -> tuple: ... + def _evaluate_polynomial(self, pol: Any) -> 'FractionFieldElement': ... + def specialization(self, D: Any = None, phi: Any = None) -> 'FractionFieldElement': ... class FractionFieldElement_1poly_field(FractionFieldElement): - def __init__(self, parent: Any, numerator: Any, denominator: Any = 1, coerce: bool = True, reduce: bool = True) -> None: - ... - - def normalize_leading_coefficients(self) -> None: - ... - - def is_integral(self) -> bool: - ... - - def support(self) -> Any: - ... - - def reduce(self) -> None: - ... - -def make_element(parent: Any, numerator: Any, denominator: Any) -> FractionFieldElement: - ... - -def make_element_old(parent: Any, cdict: dict) -> FractionFieldElement: - ... + def __init__(self, parent: Any, numerator: Any, denominator: Any = 1, coerce: bool = True, reduce: bool = True) -> None: ... + def normalize_leading_coefficients(self) -> None: ... + def is_integral(self) -> bool: ... + def support(self) -> Any: ... + def reduce(self) -> None: ... + +def make_element(parent: Any, numerator: Any, denominator: Any) -> FractionFieldElement: ... +def make_element_old(parent: Any, cdict: dict) -> FractionFieldElement: ... diff --git a/src/sage/rings/function_field/constructor.py b/src/sage/rings/function_field/constructor.py index 6d1f83767e1..a9a7e76dd76 100644 --- a/src/sage/rings/function_field/constructor.py +++ b/src/sage/rings/function_field/constructor.py @@ -76,6 +76,7 @@ class FunctionFieldFactory(UniqueFactory): sage: K is N False """ + def create_key(self, F, names): """ Given the arguments and keywords, create a key that uniquely @@ -103,11 +104,14 @@ def create_object(self, version, key, **extra_args): """ if key[0].is_finite(): from .function_field_rational import RationalFunctionField_global + return RationalFunctionField_global(key[0], names=key[1]) if key[0].characteristic() == 0: from .function_field_rational import RationalFunctionField_char_zero + return RationalFunctionField_char_zero(key[0], names=key[1]) from .function_field_rational import RationalFunctionField + return RationalFunctionField(key[0], names=key[1]) @@ -142,6 +146,7 @@ class FunctionFieldExtensionFactory(UniqueFactory): sage: L is M # needs sage.rings.function_field True """ + def create_key(self, polynomial, names): """ Given the arguments and keywords, create a key that uniquely @@ -209,5 +214,4 @@ def create_object(self, version, key, **extra_args): return function_field_polymod.FunctionField_polymod(f, names) -FunctionFieldExtension = FunctionFieldExtensionFactory( - "sage.rings.function_field.constructor.FunctionFieldExtension") +FunctionFieldExtension = FunctionFieldExtensionFactory("sage.rings.function_field.constructor.FunctionFieldExtension") diff --git a/src/sage/rings/function_field/derivations.py b/src/sage/rings/function_field/derivations.py index dc5c91c9553..049433a3ad9 100644 --- a/src/sage/rings/function_field/derivations.py +++ b/src/sage/rings/function_field/derivations.py @@ -54,6 +54,7 @@ class FunctionFieldDerivation(RingDerivationWithoutTwist): sage: d d/dx """ + def __init__(self, parent) -> None: r""" Initialize a derivation. diff --git a/src/sage/rings/function_field/derivations_polymod.py b/src/sage/rings/function_field/derivations_polymod.py index 26f2ec4ea12..2e1d98de526 100644 --- a/src/sage/rings/function_field/derivations_polymod.py +++ b/src/sage/rings/function_field/derivations_polymod.py @@ -39,6 +39,7 @@ class FunctionFieldDerivation_separable(FunctionFieldDerivation): sage: L.derivation() d/dx """ + def __init__(self, parent, d) -> None: """ Initialize a derivation. @@ -286,6 +287,7 @@ class FunctionFieldHigherDerivation(Map): From: Rational function field in x over Finite Field of size 2 To: Rational function field in x over Finite Field of size 2 """ + def __init__(self, field) -> None: """ Initialize. @@ -386,6 +388,7 @@ class RationalFunctionFieldHigherDerivation_global(FunctionFieldHigherDerivation sage: h(x^2, 2) 1 """ + def __init__(self, field) -> None: """ Initialize. @@ -444,6 +447,7 @@ def _derive(self, f, i, separating_element=None): def derivative(f): return f.derivative() + else: x = separating_element xderinv = ~(x.derivative()) @@ -504,6 +508,7 @@ def _prime_power_representation(self, f, separating_element=None): def derivative(f): return f.derivative() + else: x = separating_element xderinv = ~(x.derivative()) @@ -523,8 +528,7 @@ def derivative(f): b = a j = p - 2 while j >= 0: - b[j] -= sum(binomial(i, j) * b[i] * x**(i - j) - for i in range(j + 1, p)) + b[j] -= sum(binomial(i, j) * b[i] * x ** (i - j) for i in range(j + 1, p)) j -= 1 # Step 3 return [self._pth_root(c) for c in b] @@ -550,11 +554,9 @@ def _pth_root(self, c): R = K._field.ring() poly = c.numerator() - num = R([self._pth_root_func(poly[i]) - for i in range(0, poly.degree() + 1, p)]) + num = R([self._pth_root_func(poly[i]) for i in range(0, poly.degree() + 1, p)]) poly = c.denominator() - den = R([self._pth_root_func(poly[i]) - for i in range(0, poly.degree() + 1, p)]) + den = R([self._pth_root_func(poly[i]) for i in range(0, poly.degree() + 1, p)]) return K.element_class(K, num / den) @@ -601,8 +603,7 @@ def __init__(self, field) -> None: y = field.gen() # matrix for pth power map; used in _prime_power_representation method - self.__pth_root_matrix = matrix([(y**(i * p)).list() - for i in range(field.degree())]).transpose() + self.__pth_root_matrix = matrix([(y ** (i * p)).list() for i in range(field.degree())]).transpose() # cache computed higher derivatives to speed up later computations self._cache = {} @@ -655,6 +656,7 @@ def _derive(self, f, i, separating_element=None): def derivative(f): return f.derivative() + else: x = separating_element xderinv = ~(x.derivative()) @@ -701,8 +703,7 @@ def derive(f, i): b = a j = p - 2 while j >= 0: - b[j] -= sum(binomial(k, j) * b[k] * x**(k - j) - for k in range(j + 1, p)) + b[j] -= sum(binomial(k, j) * b[k] * x ** (k - j) for k in range(j + 1, p)) j -= 1 lambdas = [self._pth_root(c) for c in b] @@ -744,6 +745,7 @@ def _prime_power_representation(self, f, separating_element=None): def derivative(f): return f.derivative() + else: x = separating_element xderinv = ~(x.derivative()) @@ -763,8 +765,7 @@ def derivative(f): b = a j = p - 2 while j >= 0: - b[j] -= sum(binomial(i, j) * b[i] * x**(i - j) - for i in range(j + 1, p)) + b[j] -= sum(binomial(i, j) * b[i] * x ** (i - j) for i in range(j + 1, p)) j -= 1 # Step 3 return [self._pth_root(c) for c in b] @@ -789,11 +790,9 @@ def _pth_root(self, c): coeffs = [] for d in self.__pth_root_matrix.solve_right(vector(c.list())): poly = d.numerator() - num = K([self._pth_root_func(poly[i]) - for i in range(0, poly.degree() + 1, p)]) + num = K([self._pth_root_func(poly[i]) for i in range(0, poly.degree() + 1, p)]) poly = d.denominator() - den = K([self._pth_root_func(poly[i]) - for i in range(0, poly.degree() + 1, p)]) + den = K([self._pth_root_func(poly[i]) for i in range(0, poly.degree() + 1, p)]) coeffs.append(num / den) return self._field(coeffs) @@ -825,6 +824,7 @@ class FunctionFieldHigherDerivation_char_zero(FunctionFieldHigherDerivation): sage: h(h(h(e,1),1),1) == 3*2*h(e,3) True """ + def __init__(self, field) -> None: """ Initialize. diff --git a/src/sage/rings/function_field/derivations_rational.py b/src/sage/rings/function_field/derivations_rational.py index fa8990cc564..525e5433b6f 100644 --- a/src/sage/rings/function_field/derivations_rational.py +++ b/src/sage/rings/function_field/derivations_rational.py @@ -31,6 +31,7 @@ class FunctionFieldDerivation_rational(FunctionFieldDerivation): sage: K.derivation() d/dx """ + def __init__(self, parent, u=None) -> None: """ Initialize a derivation. diff --git a/src/sage/rings/function_field/differential.py b/src/sage/rings/function_field/differential.py index c60a1af8996..6f5b834c170 100644 --- a/src/sage/rings/function_field/differential.py +++ b/src/sage/rings/function_field/differential.py @@ -93,6 +93,7 @@ class FunctionFieldDifferential(ModuleElement): sage: y.differential() # needs sage.rings.function_field ((21/4*x/(x^7 + 27/4))*y^2 + ((3/2*x^7 + 9/4)/(x^8 + 27/4*x))*y + 7/2*x^4/(x^7 + 27/4)) d(x) """ + def __init__(self, parent, f, t=None) -> None: """ Initialize the differential `fdt`. @@ -403,8 +404,7 @@ def valuation(self, place): """ F = self.parent().function_field() x = F.base_field().gen() - return (self._f.valuation(place) + 2 * min(F(x).valuation(place), 0) - + F.different().valuation(place)) + return self._f.valuation(place) + 2 * min(F(x).valuation(place), 0) + F.different().valuation(place) def residue(self, place): """ @@ -467,7 +467,7 @@ def residue(self, place): r = g.valuation(place) if r >= 0: return R.zero() - g_shifted = g * s**(-r) + g_shifted = g * s ** (-r) c = g_shifted.higher_derivative(-r - 1, s) return to_R(c) @@ -507,6 +507,7 @@ class FunctionFieldDifferential_global(FunctionFieldDifferential): sage: y.differential() # needs sage.rings.finite_rings sage.rings.function_field (x*y^2 + 1/x*y) d(x) """ + def cartier(self): r""" Return the image of the differential by the Cartier operator. @@ -578,6 +579,7 @@ class DifferentialsSpace(UniqueRepresentation, Parent): sage: (y^2).differential() (2*y) d(y) """ + Element = FunctionFieldDifferential def __init__(self, field, category=None) -> None: @@ -725,6 +727,7 @@ class DifferentialsSpace_global(DifferentialsSpace): sage: L.space_of_differentials() # needs sage.rings.finite_rings sage.rings.function_field Space of differentials of Function field in y defined by y^3 + x^3*y + x """ + Element = FunctionFieldDifferential_global diff --git a/src/sage/rings/function_field/divisor.py b/src/sage/rings/function_field/divisor.py index d00b3a3fe37..cd664b6aede 100644 --- a/src/sage/rings/function_field/divisor.py +++ b/src/sage/rings/function_field/divisor.py @@ -150,6 +150,7 @@ class FunctionFieldDivisor(ModuleElement): + 3*Place (x, (1/(x^3 + x^2 + x))*y^2) - 6*Place (x + 1, y + 1) """ + def __init__(self, parent: DivisorGroup, data: dict[FunctionFieldPlace, Integer | int]) -> None: """ Initialize. @@ -678,7 +679,7 @@ def function_space(self): basis, coordinates = self._function_space() n = len(basis) - V = k ** n + V = k**n def from_V(v): return sum(v[i] * basis[i] for i in range(n)) @@ -783,7 +784,7 @@ def differential_space(self): fbasis, coordinates = self._differential_space() n = len(fbasis) - V = k ** n + V = k**n def from_V(v): f = sum(v[i] * fbasis[i] for i in range(n)) @@ -973,6 +974,7 @@ class DivisorGroup(UniqueRepresentation, Parent): sage: F.divisor_group() Divisor group of Function field in y defined by y^2 + 4*x^3 + 4 """ + Element = FunctionFieldDivisor def __init__(self, field) -> None: @@ -1111,6 +1113,7 @@ def effective_divisors(self, of_degree=None, max_degree=None, avoid: Container[F places.append([P for P in self._field.places(d) if P not in avoid]) from sage.combinat.integer_vector_weighted import WeightedIntegerVectors + weighted_vectors = WeightedIntegerVectors(of_degree, range(1, of_degree + 1)) for weights in weighted_vectors: component_divisors = [] diff --git a/src/sage/rings/function_field/drinfeld_modules/action.py b/src/sage/rings/function_field/drinfeld_modules/action.py index 953d8bc9d1c..41ca076702a 100644 --- a/src/sage/rings/function_field/drinfeld_modules/action.py +++ b/src/sage/rings/function_field/drinfeld_modules/action.py @@ -156,9 +156,7 @@ def _latex_(self) -> str: sage: latex(action) \text{Action{ }on{ }}\Bold{F}_{11^{2}}\text{{ }induced{ }by{ }}\phi: T \mapsto τ^{3} + z """ - return f'\\text{{Action{{ }}on{{ }}}}' \ - f'{latex(self._base)}\\text{{{{ }}' \ - f'induced{{ }}by{{ }}}}{latex(self._drinfeld_module)}' + return f'\\text{{Action{{ }}on{{ }}}}' f'{latex(self._base)}\\text{{{{ }}' f'induced{{ }}by{{ }}}}{latex(self._drinfeld_module)}' def _repr_(self) -> str: r""" @@ -176,8 +174,7 @@ def _repr_(self) -> str: sage: action Action on Finite Field in z of size 11^2 induced by Drinfeld module defined by T |--> τ^3 + z """ - return f'Action on {self._base} induced by ' \ - f'{self._drinfeld_module}' + return f'Action on {self._base} induced by ' f'{self._drinfeld_module}' def drinfeld_module(self): r""" diff --git a/src/sage/rings/function_field/drinfeld_modules/carlitz_module.py b/src/sage/rings/function_field/drinfeld_modules/carlitz_module.py index 11882c396c4..75faa4c4c50 100644 --- a/src/sage/rings/function_field/drinfeld_modules/carlitz_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/carlitz_module.py @@ -89,8 +89,7 @@ def CarlitzModule(A, base=None): ... ValueError: function ring base must coerce into base field """ - if (not isinstance(A, PolynomialRing_generic) - or A.base_ring() not in FiniteFields()): + if not isinstance(A, PolynomialRing_generic) or A.base_ring() not in FiniteFields(): raise TypeError('the function ring must be defined over a finite field') if base is None: K = A.fraction_field() @@ -233,8 +232,7 @@ def carlitz_factorial(A, n): ... TypeError: the function ring must be defined over a finite field """ - if (not isinstance(A, PolynomialRing_generic) - or A.base_ring() not in FiniteFields()): + if not isinstance(A, PolynomialRing_generic) or A.base_ring() not in FiniteFields(): raise TypeError('the function ring must be defined over a finite field') T = A.gen() q = A.base_ring().cardinality() @@ -243,7 +241,7 @@ def carlitz_factorial(A, n): j = 1 while n > 0: n, c = n.quo_rem(q) - D = D**q * (T**(q**j) - T) + D = D**q * (T ** (q**j) - T) ans *= D**c j += 1 return ans @@ -291,8 +289,7 @@ def carlitz_bernoulli(A, n): sage: carlitz_bernoulli(B, 2) 2*X^3 + X """ - if (not isinstance(A, PolynomialRing_generic) - or A.base_ring() not in FiniteFields()): + if not isinstance(A, PolynomialRing_generic) or A.base_ring() not in FiniteFields(): raise TypeError('the function ring must be defined over a finite field') q = A.base_ring().cardinality() if q not in carlitz_series: diff --git a/src/sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py b/src/sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py index 22736da5327..6a6a147e72e 100644 --- a/src/sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py @@ -118,6 +118,7 @@ class DrinfeldModule_charzero(DrinfeldModule): sage: phi(T) z^2*τ^2 + τ + z """ + @cached_method def _compute_coefficient_exp(self, k): r""" @@ -149,7 +150,7 @@ def _compute_coefficient_exp(self, k): c = self._base.zero() for i in range(k): j = k - i - c += self._compute_coefficient_exp(i) * self._compute_coefficient_log(j)**(q**i) + c += self._compute_coefficient_exp(i) * self._compute_coefficient_log(j) ** (q**i) return -c def exponential(self, prec=Infinity, name='z'): @@ -273,8 +274,8 @@ def _compute_coefficient_log(self, k): for i in range(k): j = k - i if j < r + 1: - c += self._compute_coefficient_log(i) * self._gen[j]**(q**i) - return c / (T - T**(q**k)) + c += self._compute_coefficient_log(i) * self._gen[j] ** (q**i) + return c / (T - T ** (q**k)) def logarithm(self, prec=Infinity, name='z'): r""" @@ -380,7 +381,7 @@ def _compute_goss_polynomial(self, n, q, poly_ring, X): if n <= q - 1: return X**n if n % q == 0: - return self.goss_polynomial(n // q)**q + return self.goss_polynomial(n // q) ** q # General case pol = poly_ring.zero() m = q @@ -450,6 +451,7 @@ class DrinfeldModule_rational(DrinfeldModule_charzero): sage: type(C) """ + def coefficient_in_function_ring(self, n): r""" Return the `n`-th coefficient of this Drinfeld module as diff --git a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py index 153a250de3b..2579a2afad0 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -547,11 +547,9 @@ def __classcall_private__(cls, function_ring, gen, A_field=None, name='τ'): # here and in the category constructor, which is not ideal. # Check domain is Fq[T] if not isinstance(function_ring, PolynomialRing_generic): - raise NotImplementedError('function ring must be a polynomial ' - 'ring') + raise NotImplementedError('function ring must be a polynomial ' 'ring') function_ring_base = function_ring.base_ring() - if not function_ring_base.is_field() \ - or not function_ring_base.is_finite(): + if not function_ring_base.is_field() or not function_ring_base.is_finite(): raise TypeError('function ring base must be a finite field') # Check all possible input types for gen @@ -571,11 +569,9 @@ def __classcall_private__(cls, function_ring, gen, A_field=None, name='τ'): except AttributeError: pass else: - raise TypeError('generator must be list of coefficients or Ore ' - 'polynomial') + raise TypeError('generator must be list of coefficients or Ore ' 'polynomial') # The coefficients are in a base field that has coercion from Fq: - if not (hasattr(A_field, 'has_coerce_map_from') and - A_field.has_coerce_map_from(function_ring.base_ring())): + if not (hasattr(A_field, 'has_coerce_map_from') and A_field.has_coerce_map_from(function_ring.base_ring())): raise ValueError('function ring base must coerce into base field') # Build the category @@ -601,16 +597,17 @@ def __classcall_private__(cls, function_ring, gen, A_field=None, name='τ'): # Instantiate the appropriate class: if A_field.is_finite(): from sage.rings.function_field.drinfeld_modules.finite_drinfeld_module import DrinfeldModule_finite + return DrinfeldModule_finite(gen, category) if isinstance(A_field, FractionField_generic): ring = A_field.ring() - if (isinstance(ring, PolynomialRing_generic) - and ring.base_ring() is function_ring_base - and base_morphism(T) == ring.gen()): + if isinstance(ring, PolynomialRing_generic) and ring.base_ring() is function_ring_base and base_morphism(T) == ring.gen(): from .charzero_drinfeld_module import DrinfeldModule_rational + return DrinfeldModule_rational(gen, category) if not category._characteristic: from .charzero_drinfeld_module import DrinfeldModule_charzero + return DrinfeldModule_charzero(gen, category) return cls.__classcall__(cls, gen, category) @@ -741,6 +738,7 @@ def _Hom_(self, other, category): True """ from sage.rings.function_field.drinfeld_modules.homset import DrinfeldModuleHomset + return DrinfeldModuleHomset(self, other, category) def _latex_(self) -> str: @@ -769,8 +767,7 @@ def _latex_(self) -> str: """ if self.get_custom_name() is not None: return latex_variable_name(self.get_custom_name()) - return f'\\phi: {latex(self._function_ring.gen())} \\mapsto ' \ - f'{latex(self._gen)}' + return f'\\phi: {latex(self._function_ring.gen())} \\mapsto ' f'{latex(self._gen)}' def _repr_(self) -> str: r""" @@ -786,8 +783,7 @@ def _repr_(self) -> str: sage: phi Drinfeld module defined by T |--> z12^5*τ^2 + z12^3*τ + 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 """ - return f'Drinfeld module defined by {self._function_ring.gen()} ' \ - f'|--> {self._gen}' + return f'Drinfeld module defined by {self._function_ring.gen()} ' f'|--> {self._gen}' def _test_category(self, **options) -> None: """ @@ -813,8 +809,7 @@ def _test_category(self, **options) -> None: SageObject._test_category(self, tester=tester) category = self.category() # Tests that self inherits methods from the categories - tester.assertTrue(isinstance(self, category.parent_class), - _LazyString("category of %s improperly initialized", (self,), {})) + tester.assertTrue(isinstance(self, category.parent_class), _LazyString("category of %s improperly initialized", (self,), {})) def __hash__(self) -> int: r""" @@ -866,6 +861,7 @@ def action(self): 0 """ from sage.rings.function_field.drinfeld_modules.action import DrinfeldModuleAction + return DrinfeldModuleAction(self) def basic_j_invariant_parameters(self, coeff_indices=None, nonzero=False): @@ -981,8 +977,7 @@ def basic_j_invariant_parameters(self, coeff_indices=None, nonzero=False): r = self._gen.degree() if coeff_indices is None: if nonzero: - coeff_indices = [k for k, g in enumerate( - self.coefficients(sparse=False)[1:-1], start=1) if g] + coeff_indices = [k for k, g in enumerate(self.coefficients(sparse=False)[1:-1], start=1) if g] else: coeff_indices = list(range(1, r)) # Check if coeff_indices is valid: @@ -992,8 +987,7 @@ def basic_j_invariant_parameters(self, coeff_indices=None, nonzero=False): raise TypeError('coefficients indices must be integers') if max(coeff_indices) >= r or min(coeff_indices) <= 0: raise ValueError(f'indices must be > 0 and < {r}') - if not all(coeff_indices[i] < coeff_indices[i + 1] for i in - range(len(coeff_indices) - 1)): + if not all(coeff_indices[i] < coeff_indices[i + 1] for i in range(len(coeff_indices) - 1)): raise ValueError('indices must be distinct and sorted') if nonzero: coeff_indices = [k for k in coeff_indices if self._gen[k]] @@ -1013,8 +1007,7 @@ def basic_j_invariant_parameters(self, coeff_indices=None, nonzero=False): lower_bounds[idx + 1] = 1 # Create inequalities of the form # delta_i <= (q^r - 1)/(q^{gcd(i,r)} - 1) - upper_bounds = [Integer((q**r - 1) / (q**(gcd(i, r)) - 1))]\ - + [0] * (len(coeff_indices) + 1) + upper_bounds = [Integer((q**r - 1) / (q ** (gcd(i, r)) - 1))] + [0] * (len(coeff_indices) + 1) upper_bounds[idx + 1] = -1 inequalities.extend((lower_bounds, upper_bounds)) equation.append(1 - q**r) @@ -1094,8 +1087,7 @@ def basic_j_invariants(self, nonzero=False): sage: J_phi[((1, 2), (7, 4, 1))] T^11 + 3*T^10 + T^9 + 4*T^8 + T^7 + 2*T^6 + 2*T^4 + 3*T^3 + 2*T^2 + 3 """ - return {parameter: self.j_invariant(parameter, check=False) - for parameter in self.basic_j_invariant_parameters(nonzero=nonzero)} + return {parameter: self.j_invariant(parameter, check=False) for parameter in self.basic_j_invariant_parameters(nonzero=nonzero)} def coefficient(self, n): r""" @@ -1279,8 +1271,7 @@ def height(self): """ try: if self.characteristic().is_zero(): - raise ValueError('height is only defined for prime ' - 'function field characteristic') + raise ValueError('height is only defined for prime ' 'function field characteristic') else: p = self.characteristic() return Integer(self(p).valuation() // p.degree()) @@ -1424,7 +1415,7 @@ def is_isomorphic(self, other, absolutely=False) -> bool: # u^e = ue # u^(q^i - 1) = ai/bi e, s, t = e.xgcd(q**i - 1) - ue = ue**s * (ai / bi)**t + ue = ue**s * (ai / bi) ** t for i in range(1, r + 1): if A[i]: f = (q**i - 1) // e @@ -1464,6 +1455,7 @@ def is_finite(self) -> bool: False """ from sage.rings.function_field.drinfeld_modules.finite_drinfeld_module import DrinfeldModule_finite + return isinstance(self, DrinfeldModule_finite) def j_invariant(self, parameter=None, check=True): @@ -1679,50 +1671,39 @@ def j_invariant(self, parameter=None, check=True): q = self._Fq.order() if parameter is None: if r != 2: - raise TypeError("parameter must not be None " - "if the rank is greater than 2") - return self._gen[1]**(q + 1) / self._gen[2] + raise TypeError("parameter must not be None " "if the rank is greater than 2") + return self._gen[1] ** (q + 1) / self._gen[2] if parameter in ZZ: parameter = ZZ(parameter) if parameter <= 0 or parameter >= r: - raise ValueError("integer parameter must be >= 1 and < the " - f"rank (={r})") - dk = Integer((q**r - 1) / (q**gcd(parameter, r) - 1)) - dr = Integer((q**parameter - 1) / (q**gcd(parameter, r) - 1)) - return self._gen[parameter]**dk / self._gen[-1]**dr + raise ValueError("integer parameter must be >= 1 and < the " f"rank (={r})") + dk = Integer((q**r - 1) / (q ** gcd(parameter, r) - 1)) + dr = Integer((q**parameter - 1) / (q ** gcd(parameter, r) - 1)) + return self._gen[parameter] ** dk / self._gen[-1] ** dr if isinstance(parameter, (tuple, list)): if len(parameter) != 2: raise ValueError("list or tuple parameter must be of length 2") - if not isinstance(parameter[0], (tuple, list)) \ - or not isinstance(parameter[1], (tuple, list)): - raise TypeError("list or tuple parameter must contain tuples " - "or lists") - if not len(parameter[0]) < r or\ - not len(parameter[1]) == len(parameter[0]) + 1: - raise ValueError("components of tuple or list parameter have " - "incorrect length") + if not isinstance(parameter[0], (tuple, list)) or not isinstance(parameter[1], (tuple, list)): + raise TypeError("list or tuple parameter must contain tuples " "or lists") + if not len(parameter[0]) < r or not len(parameter[1]) == len(parameter[0]) + 1: + raise ValueError("components of tuple or list parameter have " "incorrect length") try: # Check parameter's type parameter_0 = [ZZ(p) for p in parameter[0]] parameter_1 = [ZZ(p) for p in parameter[1]] except TypeError: - raise TypeError("components of tuple or list parameter must " - "contain only integers") + raise TypeError("components of tuple or list parameter must " "contain only integers") # Check that the weight-0 condition is satisfied: # d_1 (q - 1) + ... + d_{r-1} (q^{r-1} - 1) # = d_r (q^r - 1) if check: right = parameter_1[-1] * (q**r - 1) - left = sum(parameter_1[i] * (q**(parameter_0[i]) - 1) for i in - range(len(parameter_0))) + left = sum(parameter_1[i] * (q ** (parameter_0[i]) - 1) for i in range(len(parameter_0))) if left != right: - raise ValueError("parameter does not satisfy the " - "weight-0 condition") + raise ValueError("parameter does not satisfy the " "weight-0 condition") else: - raise TypeError("parameter must be a tuple or a list of " - "length 2 or an integer") - num = prod(self._gen[k]**d - for k, d in zip(parameter_0, parameter_1[:-1])) - return num / (self._gen[-1]**parameter_1[-1]) + raise TypeError("parameter must be a tuple or a list of " "length 2 or an integer") + num = prod(self._gen[k] ** d for k, d in zip(parameter_0, parameter_1[:-1])) + return num / (self._gen[-1] ** parameter_1[-1]) def jk_invariants(self): r""" @@ -2134,4 +2115,4 @@ def frobenius_relative(self, n=1): d = self.characteristic().degree() if d < 0: raise ValueError("the characteristic of the Drinfeld module must be nonzero") - return self.hom(tau**(n * d)) + return self.hom(tau ** (n * d)) diff --git a/src/sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py b/src/sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py index b5f6600ea24..a8f87d10214 100644 --- a/src/sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py @@ -201,33 +201,26 @@ def _frobenius_matrix_crystalline(self): drin_coeffs = self.coefficients(sparse=False) poly_K = PolynomialRing(K, name=str(A.gen())) matrix_poly_K = MatrixSpace(poly_K, r, r) - mu_coeffs = ((poly_K.gen() - drin_coeffs[0])**(n + 1)) \ - .coefficients(sparse=False) + mu_coeffs = ((poly_K.gen() - drin_coeffs[0]) ** (n + 1)).coefficients(sparse=False) def companion(order): # + [1] is required to satisfy formatting for companion matrix - M = matrix_poly_K(companion_matrix([(drin_coeffs[i] / drin_coeffs[r]) - .frobenius(qdeg * order) - for i in range(r)] + [1], format='top')) + M = matrix_poly_K(companion_matrix([(drin_coeffs[i] / drin_coeffs[r]).frobenius(qdeg * order) for i in range(r)] + [1], format='top')) M[0, r - 1] += poly_K.gen() / drin_coeffs[r].frobenius(qdeg * order) return M companion_initial = prod([companion(i) for i in range(nrem, 0, -1)]) - companion_step = prod([companion(i) - for i in range(nstar + nrem, nrem, -1)]) + companion_step = prod([companion(i) for i in range(nstar + nrem, nrem, -1)]) reduced_companions = [] for k in range(nquo - 1, 0, -1): M = Matrix(poly_K, r, r) - modulus = poly_K([c.frobenius(qdeg * (-k * nstar % n)) - for c in mu_coeffs]) + modulus = poly_K([c.frobenius(qdeg * (-k * nstar % n)) for c in mu_coeffs]) for i, row in enumerate(companion_step): for j, entry in enumerate(row): reduction = entry % modulus - M[i, j] = poly_K([c.frobenius(qdeg * (k * nstar)) - for c in reduction - .coefficients(sparse=False)]) + M[i, j] = poly_K([c.frobenius(qdeg * (k * nstar)) for c in reduction.coefficients(sparse=False)]) reduced_companions.append(M) - return (prod(reduced_companions) * companion_step * companion_initial) + return prod(reduced_companions) * companion_step * companion_initial def frobenius_endomorphism(self): r""" @@ -490,9 +483,7 @@ def _frobenius_charpoly_CSA(self): n = self._base_degree_over_constants r = self.rank() lc = chi[0][r] - coeffs = [A([K(chi[i][j] / lc).in_base() - for i in range((r - j) * n // r + 1)]) - for j in range(r + 1)] + coeffs = [A([K(chi[i][j] / lc).in_base() for i in range((r - j) * n // r + 1)]) for j in range(r + 1)] return PolynomialRing(A, name='X')(coeffs) def _frobenius_charpoly_crystalline(self): @@ -618,8 +609,7 @@ def _frobenius_charpoly_gekeler(self): for i in range(r - 1): block_shifts.append(block_shifts[-1] + shifts[i]) # Compute the images \phi_T^i for i = 0 .. n. - gen_powers = [self(A.gen()**i).coefficients(sparse=False) - for i in range(n + 1)] + gen_powers = [self(A.gen() ** i).coefficients(sparse=False) for i in range(n + 1)] sys, vec = Matrix(K, rows, cols), vector(K, rows) vec[rows - 1] = -1 for j in range(r): @@ -632,9 +622,7 @@ def _frobenius_charpoly_gekeler(self): # The system is solved over K, but the coefficients should all # be in Fq We project back into Fq here. sol_Fq = [K(x).vector()[0] for x in sol] - char_poly = [[sol_Fq[block_shifts[i] + j] - for j in range(shifts[i])] - for i in range(r)] + char_poly = [[sol_Fq[block_shifts[i] + j] for j in range(shifts[i])] for i in range(r)] return PolynomialRing(A, name='X')(char_poly + [1]) def _frobenius_charpoly_motive(self): @@ -751,9 +739,7 @@ def frobenius_norm(self): r = self.rank() p = self.characteristic() norm = K(self.coefficients()[-1]).norm() - self._frobenius_norm = (-1) ** (n * r - n - r) \ - * norm**(-1) \ - * p ** (n // p.degree()) + self._frobenius_norm = (-1) ** (n * r - n - r) * norm ** (-1) * p ** (n // p.degree()) return self._frobenius_norm def frobenius_trace(self, algorithm=None): @@ -881,8 +867,7 @@ def frobenius_trace(self, algorithm=None): if self._frobenius_trace is not None: return self._frobenius_trace if self._frobenius_charpoly is not None: - self._frobenius_trace = -self._frobenius_charpoly \ - .coefficients(sparse=False)[-2] + self._frobenius_trace = -self._frobenius_charpoly.coefficients(sparse=False)[-2] return self._frobenius_trace if self.rank() < self._base_degree_over_constants: algorithm = 'crystalline' @@ -1070,8 +1055,7 @@ def is_isogenous(self, psi): raise TypeError("input must be a Drinfeld module") if self.category() != psi.category(): raise TypeError("Drinfeld modules are not in the same category") - return self.rank() == psi.rank() \ - and self.frobenius_charpoly() == psi.frobenius_charpoly() + return self.rank() == psi.rank() and self.frobenius_charpoly() == psi.frobenius_charpoly() def is_supersingular(self): r""" diff --git a/src/sage/rings/function_field/drinfeld_modules/homset.py b/src/sage/rings/function_field/drinfeld_modules/homset.py index 7636cf64055..ff5272066b1 100644 --- a/src/sage/rings/function_field/drinfeld_modules/homset.py +++ b/src/sage/rings/function_field/drinfeld_modules/homset.py @@ -72,6 +72,7 @@ class DrinfeldModuleMorphismAction(Action): To: Drinfeld module defined by T |--> (2*z^2 + 4*z + 4)*τ^2 + (z^2 + 4*z + 3)*τ + z Defn: τ + 2 """ + def __init__(self, A, H, is_left, op) -> None: r""" Initialize this action. @@ -239,6 +240,7 @@ class DrinfeldModuleHomset(Homset): sage: frobenius_endomorphism in H False """ + Element = DrinfeldModuleMorphism def __init__(self, X, Y, category=None, check=True) -> None: @@ -273,8 +275,7 @@ def __init__(self, X, Y, category=None, check=True) -> None: if category is None: category = X.category() if check: - if X.category() != Y.category() \ - or not isinstance(X.category(), DrinfeldModules): + if X.category() != Y.category() or not isinstance(X.category(), DrinfeldModules): raise ValueError('Drinfeld modules must be in the same category') if category != X.category(): raise ValueError('category should be DrinfeldModules') @@ -304,10 +305,7 @@ def _latex_(self) -> str: sage: latex(H) \text{Set{ }of{ }Drinfeld{ }module{ }morphisms{ }from{ }(gen){ }}2 τ^{2} + z_{6} τ + z_{6}\text{{ }to{ }(gen){ }}2 τ^{2} + \left(2 z_{6}^{5} + 2 z_{6}^{4} + 2 z_{6} + 1\right) τ + z_{6} """ - return f'\\text{{Set{{ }}of{{ }}Drinfeld{{ }}module{{ }}morphisms' \ - f'{{ }}from{{ }}(gen){{ }}}}{latex(self.domain().gen())}' \ - f'\\text{{{{ }}to{{ }}(gen){{ }}}}'\ - f'{latex(self.codomain().gen())}' + return f'\\text{{Set{{ }}of{{ }}Drinfeld{{ }}module{{ }}morphisms' f'{{ }}from{{ }}(gen){{ }}}}{latex(self.domain().gen())}' f'\\text{{{{ }}to{{ }}(gen){{ }}}}' f'{latex(self.codomain().gen())}' def _repr_(self) -> str: r""" @@ -324,8 +322,7 @@ def _repr_(self) -> str: sage: H Set of Drinfeld module morphisms from (gen) 2*τ^2 + z6*τ + z6 to (gen) 2*τ^2 + (2*z6^5 + 2*z6^4 + 2*z6 + 1)*τ + z6 """ - return f'Set of Drinfeld module morphisms from (gen) '\ - f'{self.domain().gen()} to (gen) {self.codomain().gen()}' + return f'Set of Drinfeld module morphisms from (gen) ' f'{self.domain().gen()} to (gen) {self.codomain().gen()}' def __contains__(self, x) -> bool: r""" @@ -605,7 +602,7 @@ def _A_basis(self): for i in range(d): zs.append(x) x *= zq - zq = zq ** q + zq = zq**q # We compute the linear system to solve rows = [] @@ -710,7 +707,7 @@ def _Fq_basis(self, degree): frob_matrices = [identity_matrix(Fq, n)] + [Matrix(Fq, n) for _ in range(d + r)] for i, elem in enumerate(K_basis): for k in range(1, d + r + 1): - elem = elem ** q + elem = elem**q v = elem.vector() for j in range(n): frob_matrices[k][i, j] = v[j] @@ -722,8 +719,7 @@ def _Fq_basis(self, degree): # We represent multiplication and Frobenius # as operators acting on K as a vector space # over Fq - oper = K(phiT[k - i] ** (q**i)).matrix() \ - - frob_matrices[k - i] * K(psiT[k - i]).matrix() + oper = K(phiT[k - i] ** (q**i)).matrix() - frob_matrices[k - i] * K(psiT[k - i]).matrix() for j in range(n): for l in range(n): sys[k * n + j, i * n + l] = oper[l, j] @@ -733,9 +729,7 @@ def _Fq_basis(self, degree): basis = [] tau = domain.ore_polring().gen() for basis_elem in sol: - ore_poly = sum([sum([K_basis[j].backend() * basis_elem[i * n + j] - for j in range(n)]) * (tau**i) - for i in range(d + 1)]) + ore_poly = sum([sum([K_basis[j].backend() * basis_elem[i * n + j] for j in range(n)]) * (tau**i) for i in range(d + 1)]) basis.append(self(ore_poly)) return basis @@ -937,8 +931,7 @@ def basis_over_frobenius(self): # relation defining morphisms of Drinfeld modules # These are elements of K, expanded in terms of # K_basis. - poly = K(phiT[i]**(q**k) * K_basis[j] - - psiT[i] * K_basis[j]**(q**i)).polynomial() + poly = K(phiT[i] ** (q**k) * K_basis[j] - psiT[i] * K_basis[j] ** (q**i)).polynomial() deg = (i + k) // n row = n * (i + k - n * deg) col = k * n + j diff --git a/src/sage/rings/function_field/drinfeld_modules/morphism.py b/src/sage/rings/function_field/drinfeld_modules/morphism.py index ea409d91e96..9dd1d401959 100644 --- a/src/sage/rings/function_field/drinfeld_modules/morphism.py +++ b/src/sage/rings/function_field/drinfeld_modules/morphism.py @@ -29,8 +29,7 @@ from sage.matrix.constructor import matrix -class DrinfeldModuleMorphism(Morphism, UniqueRepresentation, - metaclass=InheritComparisonClasscallMetaclass): +class DrinfeldModuleMorphism(Morphism, UniqueRepresentation, metaclass=InheritComparisonClasscallMetaclass): r""" This class represents Drinfeld `\GF{q}[T]`-module morphisms. @@ -123,6 +122,7 @@ class DrinfeldModuleMorphism(Morphism, UniqueRepresentation, sage: DrinfeldModuleMorphism(Hom(phi, psi), ore_pol) is morphism True """ + @staticmethod def __classcall_private__(cls, parent, x): """ @@ -165,6 +165,7 @@ def __classcall_private__(cls, parent, x): TypeError: parent should be a DrinfeldModuleHomset """ from sage.rings.function_field.drinfeld_modules.homset import DrinfeldModuleHomset + if not isinstance(parent, DrinfeldModuleHomset): raise TypeError('parent should be a DrinfeldModuleHomset') domain = parent.domain() @@ -257,12 +258,8 @@ def _repr_(self) -> str: if self.is_identity(): return f'Identity morphism of {self._domain}' if self.is_endomorphism(): - return f'Endomorphism of {self._domain}\n' \ - f' Defn: {self._ore_polynomial}' - return f'Drinfeld Module morphism:\n' \ - f' From: {self._domain}\n' \ - f' To: {self._codomain}\n' \ - f' Defn: {self._ore_polynomial}' + return f'Endomorphism of {self._domain}\n' f' Defn: {self._ore_polynomial}' + return f'Drinfeld Module morphism:\n' f' From: {self._domain}\n' f' To: {self._codomain}\n' f' Defn: {self._ore_polynomial}' def __hash__(self) -> int: r""" @@ -609,8 +606,7 @@ def right_gcd(self, other): :meth:`left_lcm` """ - if (not isinstance(other, DrinfeldModuleMorphism) - or other.domain() is not self.domain()): + if not isinstance(other, DrinfeldModuleMorphism) or other.domain() is not self.domain(): raise ValueError("the two morphisms must have the same domain") u = self.ore_polynomial().right_gcd(other.ore_polynomial()) return self.domain().hom(u) @@ -657,8 +653,7 @@ def left_lcm(self, other): :meth:`right_gcd` """ - if (not isinstance(other, DrinfeldModuleMorphism) - or other.domain() is not self.domain()): + if not isinstance(other, DrinfeldModuleMorphism) or other.domain() is not self.domain(): raise ValueError("the two morphisms must have the same domain") u = self._ore_polynomial.left_lcm(other._ore_polynomial) return self.domain().hom(u) diff --git a/src/sage/rings/function_field/element.pyi b/src/sage/rings/function_field/element.pyi index a4f4c573611..e43e15ce445 100644 --- a/src/sage/rings/function_field/element.pyi +++ b/src/sage/rings/function_field/element.pyi @@ -6,74 +6,27 @@ class FunctionFieldElement(FieldElement): _x: Any _matrix: Any - def __reduce__(self) -> Any: - ... - - def _new_c(self) -> 'FunctionFieldElement': - ... - - def __pari__(self) -> Any: - ... - - def _latex_(self) -> str: - ... - - def subs(self, in_dict: dict | None = None, **kwds: Any) -> 'FunctionFieldElement': - ... - - def matrix(self, base: Any = None) -> Any: - ... - - def trace(self) -> Any: - ... - - def norm(self) -> Any: - ... - - def degree(self) -> int: - ... - - def characteristic_polynomial(self, *args: Any, **kwds: Any) -> Any: - ... - - def minimal_polynomial(self, *args: Any, **kwds: Any) -> Any: - ... - - def is_integral(self) -> bool: - ... - - def differential(self) -> Any: - ... - - def derivative(self) -> Any: - ... - - def higher_derivative(self, i: int, separating_element: Any = None) -> Any: - ... - - def divisor(self) -> Any: - ... - - def divisor_of_zeros(self) -> Any: - ... - - def divisor_of_poles(self) -> Any: - ... - - def zeros(self) -> list[Any]: - ... - - def poles(self) -> list[Any]: - ... - - def valuation(self, place: Any) -> int: - ... - - def evaluate(self, place: Any) -> Any: - ... - - def is_nth_power(self, n: int) -> bool: - ... - - def nth_root(self, n: int) -> 'FunctionFieldElement': - ... + def __reduce__(self) -> Any: ... + def _new_c(self) -> 'FunctionFieldElement': ... + def __pari__(self) -> Any: ... + def _latex_(self) -> str: ... + def subs(self, in_dict: dict | None = None, **kwds: Any) -> 'FunctionFieldElement': ... + def matrix(self, base: Any = None) -> Any: ... + def trace(self) -> Any: ... + def norm(self) -> Any: ... + def degree(self) -> int: ... + def characteristic_polynomial(self, *args: Any, **kwds: Any) -> Any: ... + def minimal_polynomial(self, *args: Any, **kwds: Any) -> Any: ... + def is_integral(self) -> bool: ... + def differential(self) -> Any: ... + def derivative(self) -> Any: ... + def higher_derivative(self, i: int, separating_element: Any = None) -> Any: ... + def divisor(self) -> Any: ... + def divisor_of_zeros(self) -> Any: ... + def divisor_of_poles(self) -> Any: ... + def zeros(self) -> list[Any]: ... + def poles(self) -> list[Any]: ... + def valuation(self, place: Any) -> int: ... + def evaluate(self, place: Any) -> Any: ... + def is_nth_power(self, n: int) -> bool: ... + def nth_root(self, n: int) -> 'FunctionFieldElement': ... diff --git a/src/sage/rings/function_field/element_polymod.pyi b/src/sage/rings/function_field/element_polymod.pyi index fad1851c92a..9e6783556ba 100644 --- a/src/sage/rings/function_field/element_polymod.pyi +++ b/src/sage/rings/function_field/element_polymod.pyi @@ -4,47 +4,18 @@ from sage.structure.element import FieldElement from sage.rings.function_field.element import FunctionFieldElement class FunctionFieldElement_polymod(FunctionFieldElement): - def __init__(self, parent: Any, x: Any, reduce: bool = True) -> None: - ... - - def element(self) -> Any: - ... - - def _repr_(self) -> str: - ... - - def __bool__(self) -> bool: - ... - - def __hash__(self) -> int: - ... - - def _richcmp_(self, other: Any, op: int) -> Any: - ... - - def _add_(self, right: Any) -> Any: - ... - - def _sub_(self, right: Any) -> Any: - ... - - def _mul_(self, right: Any) -> Any: - ... - - def _div_(self, right: Any) -> Any: - ... - - def __invert__(self) -> Any: - ... - - def list(self) -> list: - ... - - def nth_root(self, n: int) -> FunctionFieldElement: - ... - - def is_nth_power(self, n: int) -> bool: - ... - - def _pth_root(self) -> FunctionFieldElement: - ... + def __init__(self, parent: Any, x: Any, reduce: bool = True) -> None: ... + def element(self) -> Any: ... + def _repr_(self) -> str: ... + def __bool__(self) -> bool: ... + def __hash__(self) -> int: ... + def _richcmp_(self, other: Any, op: int) -> Any: ... + def _add_(self, right: Any) -> Any: ... + def _sub_(self, right: Any) -> Any: ... + def _mul_(self, right: Any) -> Any: ... + def _div_(self, right: Any) -> Any: ... + def __invert__(self) -> Any: ... + def list(self) -> list: ... + def nth_root(self, n: int) -> FunctionFieldElement: ... + def is_nth_power(self, n: int) -> bool: ... + def _pth_root(self) -> FunctionFieldElement: ... diff --git a/src/sage/rings/function_field/element_rational.pyi b/src/sage/rings/function_field/element_rational.pyi index 5c8473ff810..f9f06cadca8 100644 --- a/src/sage/rings/function_field/element_rational.pyi +++ b/src/sage/rings/function_field/element_rational.pyi @@ -2,65 +2,24 @@ from typing import Any from sage.rings.function_field.element import FunctionFieldElement class FunctionFieldElement_rational(FunctionFieldElement): - def __init__(self, parent: Any, x: Any, reduce: bool = True) -> None: - ... - - def __pari__(self) -> Any: - ... - - def element(self) -> Any: - ... - - def list(self) -> list: - ... - - def _repr_(self) -> str: - ... - - def __bool__(self) -> bool: - ... - - def __hash__(self) -> int: - ... - - def _richcmp_(self, other: Any, op: int) -> Any: - ... - - def _add_(self, right: Any) -> Any: - ... - - def _sub_(self, right: Any) -> Any: - ... - - def _mul_(self, right: Any) -> Any: - ... - - def _div_(self, right: Any) -> Any: - ... - - def numerator(self) -> Any: - ... - - def denominator(self) -> Any: - ... - - def valuation(self, place: Any) -> int: - ... - - def is_square(self) -> bool: - ... - - def sqrt(self, all: bool = False) -> Any: - ... - - def is_nth_power(self, n: int) -> bool: - ... - - def nth_root(self, n: int) -> FunctionFieldElement: - ... - - def factor(self) -> Any: - ... - - def inverse_mod(self, I: Any) -> Any: - ... + def __init__(self, parent: Any, x: Any, reduce: bool = True) -> None: ... + def __pari__(self) -> Any: ... + def element(self) -> Any: ... + def list(self) -> list: ... + def _repr_(self) -> str: ... + def __bool__(self) -> bool: ... + def __hash__(self) -> int: ... + def _richcmp_(self, other: Any, op: int) -> Any: ... + def _add_(self, right: Any) -> Any: ... + def _sub_(self, right: Any) -> Any: ... + def _mul_(self, right: Any) -> Any: ... + def _div_(self, right: Any) -> Any: ... + def numerator(self) -> Any: ... + def denominator(self) -> Any: ... + def valuation(self, place: Any) -> int: ... + def is_square(self) -> bool: ... + def sqrt(self, all: bool = False) -> Any: ... + def is_nth_power(self, n: int) -> bool: ... + def nth_root(self, n: int) -> FunctionFieldElement: ... + def factor(self) -> Any: ... + def inverse_mod(self, I: Any) -> Any: ... diff --git a/src/sage/rings/function_field/extensions.py b/src/sage/rings/function_field/extensions.py index ffd653d9a7f..418f84ebe6b 100644 --- a/src/sage/rings/function_field/extensions.py +++ b/src/sage/rings/function_field/extensions.py @@ -69,6 +69,7 @@ class FunctionFieldExtension(RingExtension_generic): """ Abstract base class of function field extensions. """ + pass @@ -82,6 +83,7 @@ class ConstantFieldExtension(FunctionFieldExtension): - ``k_ext`` -- an extension of `k` """ + def __init__(self, F, k_ext) -> None: """ Initialize. diff --git a/src/sage/rings/function_field/function_field.py b/src/sage/rings/function_field/function_field.py index 33d9d3b05ec..71a0d2146f5 100644 --- a/src/sage/rings/function_field/function_field.py +++ b/src/sage/rings/function_field/function_field.py @@ -267,6 +267,7 @@ class FunctionField(Field): sage: K Rational function field in x over Rational Field """ + _differentials_space = LazyImport('sage.rings.function_field.differential', 'DifferentialsSpace') def __init__(self, base_field, names, category=FunctionFields()) -> None: @@ -284,6 +285,7 @@ def __init__(self, base_field, names, category=FunctionFields()) -> None: # allow conversion into the constant base field from .maps import FunctionFieldConversionToConstantBaseField + to_constant_base_field = FunctionFieldConversionToConstantBaseField(Hom(self, self.constant_base_field())) # the conversion map must not keep the field alive if that is the only reference to it to_constant_base_field._make_weak_references() @@ -452,6 +454,7 @@ def extension(self, f, names=None): True """ from . import constructor + return constructor.FunctionFieldExtension(f.change_ring(self), names) def order_with_basis(self, basis, check: bool = True): @@ -500,6 +503,7 @@ def order_with_basis(self, basis, check: bool = True): ValueError: the identity element must be in the module spanned by basis (x, x*y + x^2, 2/3*y^2) """ from .order_basis import FunctionFieldOrder_basis + return FunctionFieldOrder_basis(tuple([self(a) for a in basis]), check=check) def order(self, x, check: bool = True): @@ -591,6 +595,7 @@ def order_infinite_with_basis(self, basis, check: bool = True): ValueError: the identity element must be in the module spanned by basis (1/x, 1/x*y, 1/x^2*y^2) """ from .order_basis import FunctionFieldOrderInfinite_basis + return FunctionFieldOrderInfinite_basis(tuple([self(g) for g in basis]), check=check) def order_infinite(self, x, check: bool = True): @@ -680,6 +685,7 @@ def _coerce_map_from_(self, source): 2*t + 1 """ from .order import FunctionFieldOrder_base + if isinstance(source, FunctionFieldOrder_base): K = source.fraction_field() if K is self: @@ -742,6 +748,7 @@ def _test_derivation(self, **options) -> None: except ImportError: return from itertools import product + # Non-zero tester.assertFalse(d.is_zero()) # Well-defined @@ -784,6 +791,7 @@ def _convert_map_from_(self, R): base_conversion = self.convert_map_from(R.base_field()) if base_conversion is not None: from sage.categories.morphism import SetMorphism + return base_conversion * SetMorphism(R.Hom(R.base_field()), R._to_base_field) def _intermediate_fields(self, base): @@ -982,6 +990,7 @@ def valuation(self, prime) -> FunctionFieldValuation_base: (x)-adic valuation """ from sage.rings.function_field.valuation import FunctionFieldValuation + return FunctionFieldValuation(self, prime) def space_of_differentials(self): @@ -1078,6 +1087,7 @@ def divisor_group(self) -> DivisorGroup: Divisor group of Function field in y defined by y^3 + (4*x^3 + 1)/(x^3 + 3) """ from .divisor import DivisorGroup + return DivisorGroup(self) def place_set(self) -> PlaceSet: @@ -1100,6 +1110,7 @@ def place_set(self) -> PlaceSet: Set of places of Function field in y defined by y^2 + y + (x^2 + 1)/x """ from .place import PlaceSet + return PlaceSet(self) @cached_method @@ -1200,6 +1211,7 @@ def completion(self, place, name=None, prec=None, gen_name=None) -> FunctionFiel True """ from .maps import FunctionFieldCompletion + return FunctionFieldCompletion(self, place, name=name, prec=prec, gen_name=gen_name) def hilbert_symbol(self, a, b, P) -> Integer: @@ -1280,8 +1292,7 @@ def hilbert_symbol(self, a, b, P) -> Integer: raise NotImplementedError('only supported for global function fields') if self.characteristic() == 2: - raise ValueError('Hilbert symbol is only defined for' - ' odd characteristic function fields') + raise ValueError('Hilbert symbol is only defined for' ' odd characteristic function fields') if not (a in self and b in self): raise ValueError('a and b must be elements of the function field') @@ -1311,11 +1322,11 @@ def hilbert_symbol(self, a, b, P) -> Integer: e = (k.order() - 1) // 2 # Use Euler's criterion to compute the powers of Legendre symbols - a_rd_pw = a0**(v_b * e) - b_rd_pw = b0**(v_a * e) + a_rd_pw = a0 ** (v_b * e) + b_rd_pw = b0 ** (v_a * e) # Finally, put the result together and transform it into the correct output - res = k(-1)**(v_a * v_b * e) * a_rd_pw * b_rd_pw + res = k(-1) ** (v_a * v_b * e) * a_rd_pw * b_rd_pw return Integer(1) if res.is_one() else Integer(-1) @@ -1338,6 +1349,7 @@ def extension_constant_field(self, k) -> ConstantFieldExtension: Finite Field in z4 of size 2^4 """ from .extensions import ConstantFieldExtension + return ConstantFieldExtension(self, k) def places_finite(self, degree=1) -> list[FunctionFieldPlace]: @@ -1418,7 +1430,7 @@ def get_place(self, degree) -> FunctionFieldPlace | None: Place (x^7 + x + 1, y + x^6 + x^5 + x^4 + x^3 + x) sage: L.get_place(8) """ - if (place := self.get_finite_place(degree)): + if place := self.get_finite_place(degree): return place return self.get_infinite_place(degree) @@ -1493,29 +1505,28 @@ def jacobian(self, model: str = 'hess', base_div: FunctionFieldPlace | FunctionF if model.startswith('km'): from .jacobian_khuri_makdisi import Jacobian as JacobianKhuriMakdisi + if model == 'km' or model.endswith('large'): if base_div is None: base_div = (2 * g + 1) * base_place if not base_div.degree() >= 2 * g + 1: - raise ValueError("Khuri-Makdisi large model requires base divisor of degree " - "at least 2*g + 1 for genus g") + raise ValueError("Khuri-Makdisi large model requires base divisor of degree " "at least 2*g + 1 for genus g") return JacobianKhuriMakdisi(self, base_div, model='large', curve=curve) if model.endswith('medium'): if base_div is None: base_div = (2 * g + 1) * base_place if not base_div.degree() >= 2 * g + 1: - raise ValueError("Khuri-Makdisi medium model requires base divisor of degree " - "at least 2*g + 1 for genus g") + raise ValueError("Khuri-Makdisi medium model requires base divisor of degree " "at least 2*g + 1 for genus g") return JacobianKhuriMakdisi(self, base_div, model='medium', curve=curve) if model.endswith('small'): if base_div is None: base_div = (g + 1) * base_place if not base_div.degree() >= g + 1: - raise ValueError("Khuri-Makdisi small model requires base divisor of degree " - "at least g + 1 for genus g") + raise ValueError("Khuri-Makdisi small model requires base divisor of degree " "at least g + 1 for genus g") return JacobianKhuriMakdisi(self, base_div, model='small', curve=curve) elif model == 'hess': from .jacobian_hess import Jacobian as JacobianHess + if base_div is None: base_div = g * base_place if base_div.degree() != g: @@ -1523,6 +1534,7 @@ def jacobian(self, model: str = 'hess', base_div: FunctionFieldPlace | FunctionF return JacobianHess(self, base_div, curve=curve) elif model == 'unique_hess': from .jacobian_unique_hess import Jacobian as JacobianUniqueHess + if base_div is None: base_div = self.get_infinite_place(1) if base_div is None: diff --git a/src/sage/rings/function_field/function_field_polymod.py b/src/sage/rings/function_field/function_field_polymod.py index 82f39fb0b7a..4b46f1e4d4c 100644 --- a/src/sage/rings/function_field/function_field_polymod.py +++ b/src/sage/rings/function_field/function_field_polymod.py @@ -116,6 +116,7 @@ class FunctionField_polymod(FunctionField): False False """ + Element = FunctionFieldElement_polymod def __init__(self, polynomial, names, category=None) -> None: @@ -155,10 +156,11 @@ def __init__(self, polynomial, names, category=None) -> None: Polynomial Ring in t over Rational Field """ from sage.rings.polynomial.polynomial_element import Polynomial + if polynomial.parent().ngens() > 1 or not isinstance(polynomial, Polynomial): raise TypeError("polynomial must be univariate a polynomial") if names is None: - names = (polynomial.variable_name(), ) + names = (polynomial.variable_name(),) elif names != polynomial.variable_name(): polynomial = polynomial.change_variable_name(names) if polynomial.degree() <= 0: @@ -170,10 +172,10 @@ def __init__(self, polynomial, names, category=None) -> None: self._base_field = base_field self._polynomial = polynomial - FunctionField.__init__(self, base_field, names=names, - category=FunctionFields().or_subcategory(category)) + FunctionField.__init__(self, base_field, names=names, category=FunctionFields().or_subcategory(category)) from .place_polymod import FunctionFieldPlace_polymod + self._place_class = FunctionFieldPlace_polymod self._hash = hash(polynomial) @@ -429,8 +431,7 @@ def monic_integral_model(self, names=None): if self.base_field() is not self.rational_function_field(): L, from_L, to_L = self.simple_model() ret, ret_to_L, L_to_ret = L.monic_integral_model(names) - from_ret = ret.hom([from_L(ret_to_L(ret.gen())), - from_L(ret_to_L(ret.base_field().gen()))]) + from_ret = ret.hom([from_L(ret_to_L(ret.gen())), from_L(ret_to_L(ret.base_field().gen()))]) to_ret = self.hom([L_to_ret(to_L(k.gen())) for k in self._intermediate_fields(self.rational_function_field())]) return ret, from_ret, to_ret if self.polynomial().is_monic() and all(c.denominator().is_one() for c in self.polynomial()): @@ -565,6 +566,7 @@ def degree(self, base=None) -> Integer: base = self.base_field() if base is self: from sage.rings.integer_ring import ZZ + return ZZ(1) return self._polynomial.degree() * self.base_field().degree(base) @@ -592,8 +594,7 @@ def _latex_(self) -> str: sage: latex(L) \text{Function field in } y \text{ defined by } y^{5} - 2 x y + \frac{-x^{4} - 1}{x} """ - return (fr"\text{{Function field in }} {self.variable_name()} " - fr"\text{{ defined by }} {self._polynomial._latex_()}") + return fr"\text{{Function field in }} {self.variable_name()} " fr"\text{{ defined by }} {self._polynomial._latex_()}" def base_field(self): """ @@ -803,6 +804,7 @@ def free_module(self, base=None, basis=None, map: bool = True): if basis is not None: raise NotImplementedError from .maps import MapFunctionFieldToVectorSpace, MapVectorSpaceToFunctionField + if base is None: base = self.base_field() degree = self.degree(base) @@ -825,6 +827,7 @@ def maximal_order(self): Maximal order of Function field in y defined by y^5 - 2*x*y + (-x^4 - 1)/x """ from .order_polymod import FunctionFieldMaximalOrder_polymod + return FunctionFieldMaximalOrder_polymod(self) def maximal_order_infinite(self): @@ -849,6 +852,7 @@ def maximal_order_infinite(self): Maximal infinite order of Function field in y defined by y^2 + y + (x^2 + 1)/x """ from .order_polymod import FunctionFieldMaximalOrderInfinite_polymod + return FunctionFieldMaximalOrderInfinite_polymod(self) def different(self): @@ -1012,9 +1016,11 @@ def hom(self, im_gens, base_morphism=None): codomain = im_gens[0].parent() if base_morphism is not None: from sage.categories.pushout import pushout + codomain = pushout(codomain, base_morphism.codomain()) from .maps import FunctionFieldMorphism_polymod + return FunctionFieldMorphism_polymod(self.Hom(codomain), im_gens[0], base_morphism) @cached_method @@ -1036,22 +1042,19 @@ def genus(self): # a ring of transcendental degree 2 over a prime field not a ring of # transcendental degree 1 over a rational function field of one variable - if (isinstance(self._base_field, RationalFunctionField) and - self._base_field.constant_field().is_prime_field()): + if isinstance(self._base_field, RationalFunctionField) and self._base_field.constant_field().is_prime_field(): from sage.interfaces.singular import singular # making the auxiliary ring which only has polynomials # with integral coefficients. - tmpAuxRing = PolynomialRing(self._base_field.constant_field(), - str(self._base_field.gen()) + ',' + str(self._ring.gen())) + tmpAuxRing = PolynomialRing(self._base_field.constant_field(), str(self._base_field.gen()) + ',' + str(self._ring.gen())) intMinPoly, d = self._make_monic_integral(self._polynomial) curveIdeal = tmpAuxRing.ideal(intMinPoly) singular.lib('normal.lib') # loading genus method in Singular return int(curveIdeal._singular_().genus()) - raise NotImplementedError("computation of genus over non-prime " - "constant fields not implemented yet") + raise NotImplementedError("computation of genus over non-prime " "constant fields not implemented yet") def _simple_model(self, name='v'): r""" @@ -1141,9 +1144,9 @@ def _simple_model(self, name='v'): L = M.base_field() K = L.base_field() - assert (isinstance(K, RationalFunctionField)) - assert (K is not L) - assert (L is not M) + assert isinstance(K, RationalFunctionField) + assert K is not L + assert L is not M if not K.constant_field().is_perfect(): raise NotImplementedError("simple_model() only implemented over perfect constant fields") @@ -1178,6 +1181,7 @@ def _simple_model(self, name='v'): V, V_to_M, M_to_V = M.free_module(K) V, V_to_N, N_to_V = N.free_module(K) from sage.matrix.matrix_space import MatrixSpace + MS = MatrixSpace(V.base_field(), V.dimension()) # the power basis of v over K B = [M_to_V(v**i) for i in range(V.dimension())] @@ -1309,16 +1313,14 @@ def simple_model(self, name=None): base = self.base_field() base_, from_base_, to_base_ = base.simple_model() self_ = base_.extension(self.polynomial().map_coefficients(to_base_), names=(name,)) - gens_in_base_ = [to_base_(k.gen()) - for k in base._intermediate_fields(base.rational_function_field())] + gens_in_base_ = [to_base_(k.gen()) for k in base._intermediate_fields(base.rational_function_field())] to_self_ = self.hom([self_.gen()] + gens_in_base_) from_self_ = self_.hom([self.gen(), from_base_(base_.gen())]) # now collapse self_/base_/K(x) ret, ret_to_self_, self__to_ret = self_._simple_model(name) ret_to_self = ret.hom(from_self_(ret_to_self_(ret.gen()))) - gens_in_ret = [self__to_ret(to_self_(k.gen())) - for k in self._intermediate_fields(self.rational_function_field())] + gens_in_ret = [self__to_ret(to_self_(k.gen())) for k in self._intermediate_fields(self.rational_function_field())] self_to_ret = self.hom(gens_in_ret) return ret, ret_to_self, self_to_ret @@ -1547,6 +1549,7 @@ def separable_model(self, names=None): return ret, f, t # otherwise, the polynomial of L must be separable in the other variable from .constructor import FunctionField + K = FunctionField(self.constant_base_field(), names=(names[1],)) # construct a field isomorphic to L on top of K @@ -1554,10 +1557,10 @@ def separable_model(self, names=None): if names[0] == names[1]: raise ValueError("names of generators must be distinct") from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(self.constant_base_field(), names=names) S = R.remove_var(names[1]) - f = R(L.polynomial().change_variable_name(names[1]).map_coefficients( - lambda c: c.numerator().change_variable_name(names[0]), S)) + f = R(L.polynomial().change_variable_name(names[1]).map_coefficients(lambda c: c.numerator().change_variable_name(names[0]), S)) f = f.polynomial(R.gen(0)).change_ring(K) f /= f.leading_coefficient() # f must be separable in the other variable (otherwise it would factor) @@ -1660,6 +1663,7 @@ class FunctionField_simple(FunctionField_polymod): Function fields defined by irreducible and separable polynomials over rational function fields. """ + @cached_method def _inversion_isomorphism(self): r""" @@ -1998,6 +2002,7 @@ class FunctionField_char_zero(FunctionField_simple): sage: L.characteristic() 0 """ + @cached_method def higher_derivation(self): """ @@ -2018,6 +2023,7 @@ def higher_derivation(self): To: Function field in y defined by y^3 + (-x^3 + 1)/(x^3 - 2) """ from .derivations_polymod import FunctionFieldHigherDerivation_char_zero + return FunctionFieldHigherDerivation_char_zero(self) @@ -2052,6 +2058,7 @@ class FunctionField_global(FunctionField_simple): sage: L.genus() # needs sage.rings.finite_rings 0 """ + _differentials_space = LazyImport('sage.rings.function_field.differential', 'DifferentialsSpace_global') def __init__(self, polynomial, names) -> None: @@ -2080,6 +2087,7 @@ def maximal_order(self): (1, 1/x^4*y, 1/x^11*y^2 + 1/x^2, 1/x^15*y^3 + 1/x^6*y) """ from .order_polymod import FunctionFieldMaximalOrder_global + return FunctionFieldMaximalOrder_global(self) @cached_method @@ -2102,6 +2110,7 @@ def higher_derivation(self): To: Function field in y defined by y^3 + (4*x^3 + 1)/(x^3 + 3) """ from .derivations_polymod import FunctionFieldHigherDerivation_global + return FunctionFieldHigherDerivation_global(self) def places(self, degree=1) -> list[FunctionFieldPlace_polymod]: @@ -2252,12 +2261,13 @@ def L_polynomial(self, name='t'): 2*t^2 + t + 1 """ from sage.rings.integer_ring import ZZ + q = self.constant_field().order() g = self.genus() B = [len(self.places(i + 1)) for i in range(g)] N = [sum(d * B[d - 1] for d in ZZ(i + 1).divisors()) for i in range(g)] - S = [N[i] - q**(i + 1) - 1 for i in range(g)] + S = [N[i] - q ** (i + 1) - 1 for i in range(g)] a = [1] for i in range(1, g + 1): @@ -2345,6 +2355,7 @@ def _singular_normal(ideal): singular_function, ) from sage.libs.singular.function import lib as singular_lib + singular_lib('normal.lib') normal = singular_function('normal') @@ -2428,6 +2439,7 @@ def _maximal_order_basis(self) -> tuple[FunctionFieldElement]: return tuple(self(hom(b) / hom(s)) for b in singular_basis) from sage.env import SAGE_EXTCODE + lib(SAGE_EXTCODE + '/singular/function_field/core.lib') normalize = singular_function('core_normalize') @@ -2474,7 +2486,7 @@ def _maximal_order_basis(self) -> tuple[FunctionFieldElement]: # that is, the function field. The integral closure of k[x] # is then obtained by multiplying these generators with powers of y # as the equation order itself is an integral extension of k[x]. - d = ~ pols[-1] + d = ~pols[-1] _basis = [] for f in pols: b = d * f @@ -2514,6 +2526,7 @@ def equation_order(self): Order in Function field in y defined by y^3 - x^6 - 2*x^5 - 3*x^4 - 2*x^3 - x^2 """ from .order_basis import FunctionFieldOrder_basis + a = self.gen() basis = [a**i for i in range(self.degree())] return FunctionFieldOrder_basis(tuple(basis)) @@ -2541,9 +2554,8 @@ def primitive_integal_element_infinite(self): y = self.gen() x = self.base_field().gen() - cf = max([(f[i].numerator().degree() / (n - i)).ceil() for i in range(n) - if f[i] != 0]) - return y * x**(-cf) + cf = max([(f[i].numerator().degree() / (n - i)).ceil() for i in range(n) if f[i] != 0]) + return y * x ** (-cf) @cached_method def equation_order_infinite(self): @@ -2567,6 +2579,7 @@ def equation_order_infinite(self): Infinite order in Function field in y defined by y^3 - x^6 - 2*x^5 - 3*x^4 - 2*x^3 - x^2 """ from .order_basis import FunctionFieldOrderInfinite_basis + b = self.primitive_integal_element_infinite() basis = [b**i for i in range(self.degree())] return FunctionFieldOrderInfinite_basis(tuple(basis)) @@ -2578,6 +2591,7 @@ class FunctionField_char_zero_integral(FunctionField_char_zero, FunctionField_in separable polynomial, integral over the maximal order of the base rational function field with a finite constant field. """ + pass @@ -2587,4 +2601,5 @@ class FunctionField_global_integral(FunctionField_global, FunctionField_integral integral over the maximal order of the base rational function field with a finite constant field. """ + pass diff --git a/src/sage/rings/function_field/function_field_rational.py b/src/sage/rings/function_field/function_field_rational.py index fc53c7b6fda..b5936f2ca29 100644 --- a/src/sage/rings/function_field/function_field_rational.py +++ b/src/sage/rings/function_field/function_field_rational.py @@ -132,6 +132,7 @@ class RationalFunctionField(FunctionField): + Place (x, y + 1) - Place (x + i, y) """ + Element = FunctionFieldElement_rational def __init__(self, constant_field, names, category=None) -> None: @@ -158,7 +159,7 @@ def __init__(self, constant_field, names, category=None) -> None: if names is None: raise ValueError("variable name must be specified") elif not isinstance(names, tuple): - names = (names, ) + names = (names,) if not constant_field.is_field(): raise TypeError("constant_field must be a field") @@ -167,6 +168,7 @@ def __init__(self, constant_field, names, category=None) -> None: FunctionField.__init__(self, self, names=names, category=FunctionFields().or_subcategory(category)) from .place_rational import FunctionFieldPlace_rational + self._place_class = FunctionFieldPlace_rational R = constant_field[names[0]] @@ -176,10 +178,12 @@ def __init__(self, constant_field, names, category=None) -> None: hom = Hom(self._field, self) from .maps import FractionFieldToFunctionField + self.register_coercion(hom.__make_element_class__(FractionFieldToFunctionField)(hom.domain(), hom.codomain())) from sage.categories.morphism import SetMorphism from sage.categories.sets_with_partial_maps import SetsWithPartialMaps + R.register_conversion(SetMorphism(self.Hom(R, SetsWithPartialMaps()), self._to_polynomial)) self._gen = self(R.gen()) @@ -198,6 +202,7 @@ def __reduce__(self): Rational function field in x over Rational Field """ from .constructor import FunctionField + return FunctionField, (self._constant_field, self._names) def __hash__(self) -> int: @@ -224,8 +229,7 @@ def _repr_(self) -> str: sage: K._repr_() 'Rational function field in t over Rational Field' """ - return "Rational function field in %s over %s" % ( - self.variable_name(), self._constant_field) + return "Rational function field in %s over %s" % (self.variable_name(), self._constant_field) def _element_constructor_(self, x) -> FunctionFieldElement_rational: r""" @@ -350,8 +354,7 @@ def _to_bivariate_polynomial(self, f): v = f.list() denom = lcm([a.denominator() for a in v]) S = denom.parent() - x, t = S.base_ring()['%s,%s' % (f.parent().variable_name(), - self.variable_name())].gens() + x, t = S.base_ring()['%s,%s' % (f.parent().variable_name(), self.variable_name())].gens() phi = S.hom([t]) return sum([phi((denom * v[i]).numerator()) * x**i for i in range(len(v))]), denom @@ -427,12 +430,13 @@ def _factor_univariate_polynomial(self, f, proof=None): # undo any variable substitution that we introduced for the bivariate polynomial if old_variable_name != a.variable_name(): a = a.change_variable_name(old_variable_name) - unit *= (c**e) + unit *= c**e if a.is_unit(): unit *= a**e else: w.append((a, e)) from sage.structure.factorization import Factorization + return Factorization(w, unit=unit) @cached_method @@ -509,6 +513,7 @@ def free_module(self, base=None, basis=None, map: bool = True): if basis is not None: raise NotImplementedError from .maps import MapFunctionFieldToVectorSpace, MapVectorSpaceToFunctionField + if base is None: base = self elif base is not self: @@ -556,6 +561,7 @@ def degree(self, base=None) -> Integer: elif base is not self: raise ValueError("base must be the rational function field itself") from sage.rings.integer_ring import ZZ + return ZZ(1) def gen(self, n=0): @@ -653,6 +659,7 @@ def hom(self, im_gens, base_morphism=None): if base_morphism is None and not R.has_coerce_map_from(self.constant_field()): raise ValueError("you must specify a morphism on the base field") from .maps import FunctionFieldMorphism_rational + return FunctionFieldMorphism_rational(self.Hom(R), x, base_morphism) def field(self): @@ -689,6 +696,7 @@ def maximal_order(self): Maximal order of Rational function field in t over Rational Field """ from .order_rational import FunctionFieldMaximalOrder_rational + return FunctionFieldMaximalOrder_rational(self) equation_order = maximal_order @@ -710,6 +718,7 @@ def maximal_order_infinite(self): Maximal infinite order of Rational function field in t over Rational Field """ from .order_rational import FunctionFieldMaximalOrderInfinite_rational + return FunctionFieldMaximalOrderInfinite_rational(self) equation_order_infinite = maximal_order_infinite @@ -796,6 +805,7 @@ def change_variable_name(self, name): id = Hom(self, self).identity() return self, id, id from .constructor import FunctionField + ret = FunctionField(self.constant_base_field(), name) return ret, ret.hom(self.gen()), self.hom(ret.gen()) @@ -827,6 +837,7 @@ class RationalFunctionField_char_zero(RationalFunctionField): """ Rational function fields of characteristic zero. """ + @cached_method def higher_derivation(self): """ @@ -844,6 +855,7 @@ def higher_derivation(self): [x^9, 9*x^8, 36*x^7, 84*x^6, 126*x^5, 126*x^4, 84*x^3, 36*x^2, 9*x, 1] """ from .derivations_polymod import FunctionFieldHigherDerivation_char_zero + return FunctionFieldHigherDerivation_char_zero(self) @@ -851,6 +863,7 @@ class RationalFunctionField_global(RationalFunctionField): """ Rational function field over finite fields. """ + _differentials_space = LazyImport('sage.rings.function_field.differential', 'DifferentialsSpace_global') def places(self, degree=1): @@ -974,4 +987,5 @@ def higher_derivation(self): [x^7, 2*x^6, x^5, 0, 0, x^2, 2*x, 1, 0, 0] """ from .derivations_polymod import RationalFunctionFieldHigherDerivation_global + return RationalFunctionFieldHigherDerivation_global(self) diff --git a/src/sage/rings/function_field/function_field_test.py b/src/sage/rings/function_field/function_field_test.py index 3187d8d3e12..be0e87f0acb 100644 --- a/src/sage/rings/function_field/function_field_test.py +++ b/src/sage/rings/function_field/function_field_test.py @@ -72,14 +72,7 @@ def T(F): # # https://github.com/pytest-dev/pytest/issues/349 # -pairs = [("J", None), - ("K", 16), - ("L", 2), - ("M", 1), - ("N", 1), - ("O", None), - ("T", None), - ("S", 8)] +pairs = [("J", None), ("K", 16), ("L", 2), ("M", 1), ("N", 1), ("O", None), ("T", None), ("S", 8)] @pytest.mark.parametrize("ff,max_runs", pairs) diff --git a/src/sage/rings/function_field/hermite_form_polynomial.pyi b/src/sage/rings/function_field/hermite_form_polynomial.pyi index 2108b8871d9..a7f16043655 100644 --- a/src/sage/rings/function_field/hermite_form_polynomial.pyi +++ b/src/sage/rings/function_field/hermite_form_polynomial.pyi @@ -1,5 +1,4 @@ from typing import Optional from sage.matrix.matrix import Matrix -def reversed_hermite_form(mat: Matrix, transformation: bool = False) -> Optional[Matrix]: - ... +def reversed_hermite_form(mat: Matrix, transformation: bool = False) -> Optional[Matrix]: ... diff --git a/src/sage/rings/function_field/ideal.py b/src/sage/rings/function_field/ideal.py index 4d948804974..ae94643226f 100644 --- a/src/sage/rings/function_field/ideal.py +++ b/src/sage/rings/function_field/ideal.py @@ -117,6 +117,7 @@ class FunctionFieldIdeal(Element): sage: O.ideal(x^3 + 1) Ideal (x^3 + 1) of Maximal order of Rational function field in x over Finite Field of size 7 """ + def __init__(self, ring) -> None: """ Initialize. @@ -148,7 +149,7 @@ def _repr_short(self) -> str: if self.is_zero(): return "(0)" - return "(%s)" % (', '.join([repr(g) for g in self.gens_reduced()]), ) + return "(%s)" % (', '.join([repr(g) for g in self.gens_reduced()]),) def _repr_(self) -> str: """ @@ -263,11 +264,8 @@ def gens_reduced(self): gens = self.gens() if len(gens) == 1: return gens - candidate_gensets = [genset for genset in powerset(gens) - if self.parent()(genset) == self] - candidate_gensets.sort(key=lambda item: (len(item), - len(repr(item)), - item)) + candidate_gensets = [genset for genset in powerset(gens) if self.parent()(genset) == self] + candidate_gensets.sort(key=lambda item: (len(item), len(repr(item)), item)) return candidate_gensets[0] def ring(self): @@ -544,7 +542,7 @@ def divisor_of_poles(self): raise ValueError("not defined for zero ideal") F = self.ring().fraction_field() - data = {prime.place(): - multiplicity for prime, multiplicity in self._factor() if multiplicity < 0} + data = {prime.place(): -multiplicity for prime, multiplicity in self._factor() if multiplicity < 0} return divisor(F, data) @@ -572,6 +570,7 @@ class FunctionFieldIdeal_module(FunctionFieldIdeal, Ideal_generic): sage: I^2 Ideal (x^3 + 1, (-x^3 - 1)*y) of Order in Function field in y defined by y^2 - x^3 - 1 """ + def __init__(self, ring, module) -> None: """ Initialize. @@ -841,6 +840,7 @@ class FunctionFieldIdealInfinite(FunctionFieldIdeal): """ Base class of ideals of maximal infinite orders """ + pass @@ -863,6 +863,7 @@ class FunctionFieldIdealInfinite_module(FunctionFieldIdealInfinite, Ideal_generi sage: O.ideal(y) Ideal (x^3 + 1, -y) of Order in Function field in y defined by y^2 - x^3 - 1 """ + def __init__(self, ring, module) -> None: """ Initialize. @@ -947,8 +948,7 @@ def __eq__(self, other): if self.ring() != other.ring(): raise ValueError("rings must be the same") - return (self.module().is_submodule(other.module()) and - other.module().is_submodule(self.module())) + return self.module().is_submodule(other.module()) and other.module().is_submodule(self.module()) def module(self): """ diff --git a/src/sage/rings/function_field/ideal_polymod.py b/src/sage/rings/function_field/ideal_polymod.py index 4393253dfd7..4ff0b8c1f62 100644 --- a/src/sage/rings/function_field/ideal_polymod.py +++ b/src/sage/rings/function_field/ideal_polymod.py @@ -52,6 +52,7 @@ class FunctionFieldIdeal_polymod(FunctionFieldIdeal): sage: O.ideal(y) Ideal (y) of Maximal order of Function field in y defined by y^2 + x^3*y + x """ + def __init__(self, ring, hnf, denominator=1) -> None: """ Initialize. @@ -380,14 +381,14 @@ def _mul_(self, other): vecs = list(p * self._hnf) + [mul(q, v) for v in self._hnf] elif self._gens_two_vecs is not None: if len(self._gens_two_vecs) == 1: - g1, = self._gens_two_vecs + (g1,) = self._gens_two_vecs vecs = list(g1 * other._hnf) else: g1, g2 = self._gens_two_vecs vecs = list(g1 * other._hnf) + [mul(g2, v) for v in other._hnf] elif other._gens_two_vecs is not None: if len(other._gens_two_vecs) == 1: - g1, = other._gens_two_vecs + (g1,) = other._gens_two_vecs vecs = list(g1 * self._hnf) else: g1, g2 = other._gens_two_vecs @@ -597,8 +598,7 @@ def _gens_over_base(self): sage: I._gens_over_base ([x, y], x) """ - gens = [sum([c1 * c2 for c1, c2 in zip(row, self._ring.basis())]) - for row in self._hnf] + gens = [sum([c1 * c2 for c1, c2 in zip(row, self._ring.basis())]) for row in self._hnf] return gens, self._denominator def gens(self) -> tuple: @@ -904,7 +904,7 @@ def valuation(self, ideal): val = min([c.valuation(p) for c in h]) i = self._ramification_index * val while True: - ppow = p ** val + ppow = p**val h = (matrix(n, [c // ppow for c in h]) * B).list() val = min([c.valuation(p) for c in h]) if val.is_zero(): @@ -1005,6 +1005,7 @@ class FunctionFieldIdeal_global(FunctionFieldIdeal_polymod): sage: O.ideal(y) Ideal (y) of Maximal order of Function field in y defined by y^2 + x^3*y + x """ + def __init__(self, ring, hnf, denominator=1) -> None: """ Initialize. @@ -1051,7 +1052,7 @@ def __pow__(self, mod): I = matrix.identity(R, n) if len(self._gens_two_vecs) == 1: - p, = self._gens_two_vecs + (p,) = self._gens_two_vecs ppow = p**mod J = [ppow * v for v in I] else: @@ -1201,8 +1202,7 @@ def _gens_two(self) -> tuple: R = hnf.base_ring() - basis = [sum(c1 * c2 for c1, c2 in zip(row, O.basis())) - for row in hnf] + basis = [sum(c1 * c2 for c1, c2 in zip(row, O.basis())) for row in hnf] n = len(basis) alpha = None @@ -1268,6 +1268,7 @@ class FunctionFieldIdealInfinite_polymod(FunctionFieldIdealInfinite): Ideal (1/x^4*y^2) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4 """ + def __init__(self, ring, ideal) -> None: """ Initialize this ideal. @@ -1402,7 +1403,7 @@ def __pow__(self, n): Ideal (1/x^3) of Maximal infinite order of Function field in y defined by y^3 + y^2 + 2*x^4 """ - return FunctionFieldIdealInfinite_polymod(self._ring, self._ideal ** n) + return FunctionFieldIdealInfinite_polymod(self._ring, self._ideal**n) def __invert__(self): """ @@ -1432,7 +1433,7 @@ def __invert__(self): Ideal (1) of Maximal infinite order of Function field in y defined by y^2 + y + (x^2 + 1)/x """ - return FunctionFieldIdealInfinite_polymod(self._ring, ~ self._ideal) + return FunctionFieldIdealInfinite_polymod(self._ring, ~self._ideal) def _richcmp_(self, other, op): """ diff --git a/src/sage/rings/function_field/ideal_rational.py b/src/sage/rings/function_field/ideal_rational.py index 8c74da12ea2..802e98a5de2 100644 --- a/src/sage/rings/function_field/ideal_rational.py +++ b/src/sage/rings/function_field/ideal_rational.py @@ -40,6 +40,7 @@ class FunctionFieldIdeal_rational(FunctionFieldIdeal): sage: I = O.ideal(1/(x^2+x)); I Ideal (1/(x^2 + x)) of Maximal order of Rational function field in x over Rational Field """ + def __init__(self, ring, gen) -> None: """ Initialize. @@ -365,6 +366,7 @@ class FunctionFieldIdealInfinite_rational(FunctionFieldIdealInfinite): sage: Oinf.ideal(x) Ideal (x) of Maximal infinite order of Rational function field in x over Finite Field of size 2 """ + def __init__(self, ring, gen) -> None: """ Initialize. diff --git a/src/sage/rings/function_field/jacobian_base.py b/src/sage/rings/function_field/jacobian_base.py index 09b454be4ad..4f5720c5950 100644 --- a/src/sage/rings/function_field/jacobian_base.py +++ b/src/sage/rings/function_field/jacobian_base.py @@ -194,6 +194,7 @@ class JacobianPoint_finite_field_base(JacobianPoint_base): """ Points of Jacobians over finite fields. """ + def additive_order(self): """ Return the order of this point. @@ -292,6 +293,7 @@ class JacobianGroupFunctor(ConstructionFunctor): sage: F JacobianGroupFunctor """ + rank = 20 def __init__(self, base_field, field) -> None: @@ -384,6 +386,7 @@ class JacobianGroup_base(Parent): sage: J.group() Group of rational points of Jacobian over Finite Field of size 7 (Hess model) """ + _embedding_map_class: type[Map] | None = None def __init__(self, parent, function_field: FunctionField, base_div: FunctionFieldDivisor) -> None: @@ -540,6 +543,7 @@ class JacobianGroup_finite_field_base(JacobianGroup_base): sage: J.group() Group of rational points of Jacobian over Finite Field of size 7 (Hess model) """ + def _bound_on_order(self): """ Return an upper bound on the order of the abelian group. @@ -591,7 +595,8 @@ def order(self, algorithm='numeric'): if algorithm == 'numeric': # numeric method - fast but might be inaccurate by numerical noise from sage.rings.qqbar import AlgebraicField - h = Integer(math.prod([(1 - a**(-b))**m for a, m in f.change_ring(AlgebraicField()).roots()])) + + h = Integer(math.prod([(1 - a ** (-b)) ** m for a, m in f.change_ring(AlgebraicField()).roots()])) return h # algebraic method - slow @@ -686,6 +691,7 @@ class Jacobian_base(Parent): sage: F.jacobian() Jacobian of Function field in y defined by y^2 + y + (x^2 + 1)/x (Hess model) """ + def __init__(self, function_field: FunctionField, base_div: FunctionFieldDivisor | FunctionFieldPlace, **kwds) -> None: """ Initialize. @@ -702,9 +708,7 @@ def __init__(self, function_field: FunctionField, base_div: FunctionFieldDivisor self._system: dict[Field, tuple[JacobianGroup_base, Field]] = {} self._base_place = None self._curve = kwds.get('curve') - super().__init__(category=Jacobians(function_field.constant_base_field()), - base=function_field.constant_base_field(), - facade=True) + super().__init__(category=Jacobians(function_field.constant_base_field()), base=function_field.constant_base_field(), facade=True) def _repr_(self) -> str: """ diff --git a/src/sage/rings/function_field/jacobian_hess.py b/src/sage/rings/function_field/jacobian_hess.py index eb230e43792..2e91c023a02 100644 --- a/src/sage/rings/function_field/jacobian_hess.py +++ b/src/sage/rings/function_field/jacobian_hess.py @@ -115,6 +115,7 @@ class JacobianPoint(JacobianPoint_base): sage: -(dS.divisor() + ds.divisor()) == pl True """ + def __init__(self, parent, dS, ds) -> None: """ Initialize. @@ -350,6 +351,7 @@ class JacobianPoint_finite_field(JacobianPoint, JacobianPoint_finite_field_base) """ Points of Jacobians over finite fields """ + pass @@ -380,6 +382,7 @@ class JacobianGroupEmbedding(Map): To: Group of rational points of Jacobian over Finite Field in z3 of size 17^3 (Hess model) """ + def __init__(self, base_group, extension_group) -> None: """ Initialize. @@ -491,6 +494,7 @@ class JacobianGroup(UniqueRepresentation, JacobianGroup_base): Group of rational points of Jacobian over Finite Field of size 17 (Hess model) """ + Element = JacobianPoint _embedding_map_class = JacobianGroupEmbedding @@ -556,15 +560,12 @@ def _element_constructor_(self, x): return self.zero() if isinstance(x, FunctionFieldPlace): - if (self._base_place is not None - and x in self._function_field.place_set() - and x.degree() == 1): + if self._base_place is not None and x in self._function_field.place_set() and x.degree() == 1: x = x - self._base_place else: x = x.divisor() - if (isinstance(x, FunctionFieldDivisor) - and x in self._function_field.divisor_group()): + if isinstance(x, FunctionFieldDivisor) and x in self._function_field.divisor_group(): if x.degree() == 0: return self.point(x) if x.is_effective(): @@ -690,6 +691,7 @@ class JacobianGroup_finite_field(JacobianGroup, JacobianGroup_finite_field_base) To: Group of rational points of Jacobian over Finite Field in z3 of size 17^3 (Hess model) """ + Element = JacobianPoint_finite_field def __init__(self, parent, function_field, base_div) -> None: @@ -839,6 +841,7 @@ class Jacobian(Jacobian_base, UniqueRepresentation): Jacobian of Projective Plane Curve over Finite Field of size 17 defined by x^3 - y^2*z + 5*z^3 (Hess model) """ + def __init__(self, function_field, base_div, **kwds) -> None: """ Initialize. diff --git a/src/sage/rings/function_field/jacobian_khuri_makdisi.py b/src/sage/rings/function_field/jacobian_khuri_makdisi.py index dc5d737fc95..18bab288b4f 100644 --- a/src/sage/rings/function_field/jacobian_khuri_makdisi.py +++ b/src/sage/rings/function_field/jacobian_khuri_makdisi.py @@ -168,6 +168,7 @@ class JacobianPoint(JacobianPoint_base): [0 0 0 0 0 1 0 0 5] [0 0 0 0 0 0 1 0 4] """ + def __init__(self, parent, w) -> None: """ Initialize. @@ -480,6 +481,7 @@ class JacobianGroupEmbedding(Map): To: Group of rational points of Jacobian over Finite Field in z2 of size 5^2 (Khuri-Makdisi large model) """ + def __init__(self, base_group, extension_group) -> None: """ Initialize. @@ -572,6 +574,7 @@ class JacobianGroup(UniqueRepresentation, JacobianGroup_base): Group of rational points of Jacobian over Finite Field of size 7 (Khuri-Makdisi large model) """ + Element = JacobianPoint _embedding_map_class = JacobianGroupEmbedding @@ -719,15 +722,12 @@ def _element_constructor_(self, x): return self.zero() if isinstance(x, FunctionFieldPlace): - if (self._base_place is not None - and x in self._function_field.place_set() - and x.degree() == 1): + if self._base_place is not None and x in self._function_field.place_set() and x.degree() == 1: x = x - self._base_place else: x = x.divisor() - if (isinstance(x, FunctionFieldDivisor) - and x in self._function_field.divisor_group()): + if isinstance(x, FunctionFieldDivisor) and x in self._function_field.divisor_group(): if x.degree() == 0: return self.point(x) if x.is_effective(): @@ -827,6 +827,7 @@ class JacobianGroup_finite_field(JacobianGroup, JacobianGroup_finite_field_base) To: Group of rational points of Jacobian over Finite Field in z2 of size 7^2 (Khuri-Makdisi large model) """ + Element = JacobianPoint_finite_field def __init__(self, parent, function_field, base_div) -> None: @@ -953,6 +954,7 @@ class Jacobian(UniqueRepresentation, Jacobian_base): Jacobian of Projective Plane Curve over Finite Field of size 7 defined by x^3 - y^2*z - 2*z^3 (Khuri-Makdisi large model) """ + def __init__(self, function_field, base_div, model, **kwds) -> None: """ Initialize. diff --git a/src/sage/rings/function_field/jacobian_unique_hess.py b/src/sage/rings/function_field/jacobian_unique_hess.py index 1778ca97ecc..75bcb04bf92 100644 --- a/src/sage/rings/function_field/jacobian_unique_hess.py +++ b/src/sage/rings/function_field/jacobian_unique_hess.py @@ -64,6 +64,7 @@ from .function_field import FunctionField from .ideal import FunctionFieldIdeal from .ideal import FunctionFieldIdealInfinite as InfiniteIdeal + FiniteIdeal: TypeAlias = FunctionFieldIdeal # For readability when we specifically mean a finite ideal @@ -76,8 +77,7 @@ class JacobianPoint(JacobianPoint_base): of this class are hashable. """ - def __init__(self, parent: JacobianGroup, finite_ideal: FiniteIdeal, - infinite_ideal: InfiniteIdeal) -> None: + def __init__(self, parent: JacobianGroup, finite_ideal: FiniteIdeal, infinite_ideal: InfiniteIdeal) -> None: super().__init__(parent) # self._r is determined by the two ideals, but it is computed during # reduction and is useful in a few utility methods so we store it. @@ -476,7 +476,7 @@ def __init__(self, function_field: FunctionField, base_div: FunctionFieldDivisor else: raise TypeError('base_div must be a divisor or a place') - #reveal_type(self._A) + # reveal_type(self._A) self._cache_infinite_ideals = cache_infinite_ideals diff --git a/src/sage/rings/function_field/maps.py b/src/sage/rings/function_field/maps.py index a70dbb6c8dc..99af8688e21 100644 --- a/src/sage/rings/function_field/maps.py +++ b/src/sage/rings/function_field/maps.py @@ -58,10 +58,14 @@ from sage.rings.infinity import infinity from sage.rings.morphism import RingHomomorphism -lazy_import("sage.rings.function_field.derivations", ( - "FunctionFieldDerivation", - "FunctionFieldHigherDerivation", -), deprecation=35230) +lazy_import( + "sage.rings.function_field.derivations", + ( + "FunctionFieldDerivation", + "FunctionFieldHigherDerivation", + ), + deprecation=35230, +) class FunctionFieldVectorSpaceIsomorphism(Morphism): @@ -76,6 +80,7 @@ class FunctionFieldVectorSpaceIsomorphism(Morphism): sage: isinstance(f, sage.rings.function_field.maps.FunctionFieldVectorSpaceIsomorphism) True """ + def _repr_(self) -> str: """ Return the string representation of this isomorphism. @@ -155,8 +160,8 @@ def _richcmp_(self, other, op): return NotImplemented from sage.structure.richcmp import richcmp - return richcmp((self.domain(), self.codomain()), - (other.domain(), other.codomain()), op) + + return richcmp((self.domain(), self.codomain()), (other.domain(), other.codomain()), op) def __hash__(self) -> int: r""" @@ -190,6 +195,7 @@ class MapVectorSpaceToFunctionField(FunctionFieldVectorSpaceIsomorphism): From: Vector space of dimension 2 over Rational function field in x over Rational Field To: Function field in y defined by y^2 - x*y + 4*x^3 """ + def __init__(self, V, K) -> None: """ EXAMPLES:: @@ -244,6 +250,7 @@ def _call_(self, v): from itertools import product from sage.misc.misc_c import prod + exponents = product(*[range(d) for d in degrees]) basis = [prod(g**e for g, e in zip(gens, es)) for es in exponents] @@ -294,6 +301,7 @@ class MapFunctionFieldToVectorSpace(FunctionFieldVectorSpaceIsomorphism): From: Function field in y defined by y^2 - x*y + 4*x^3 To: Vector space of dimension 2 over Rational function field in x over Rational Field """ + def __init__(self, K, V) -> None: """ Initialize. @@ -346,6 +354,7 @@ def _call_(self, x): fields = self._K._intermediate_fields(self._V.base_field()) fields.pop() from itertools import chain + for k in fields: ret = chain.from_iterable([y.list() for y in ret]) ret = list(ret) @@ -364,6 +373,7 @@ class FunctionFieldMorphism(RingHomomorphism): Function Field endomorphism of Rational function field in x over Rational Field Defn: x |--> 1/x """ + def __init__(self, parent, im_gen, base_morphism) -> None: """ Initialize. @@ -429,6 +439,7 @@ class FunctionFieldMorphism_polymod(FunctionFieldMorphism): sage: f(y).charpoly('y') y^3 + 6*x^3 + x """ + def __init__(self, parent, im_gen, base_morphism) -> None: """ Initialize. @@ -472,6 +483,7 @@ class FunctionFieldMorphism_rational(FunctionFieldMorphism): """ Morphism from a rational function field to a function field. """ + def __init__(self, parent, im_gen, base_morphism) -> None: """ Initialize. @@ -537,6 +549,7 @@ class FunctionFieldConversionToConstantBaseField(Map): From: Rational function field in x over Rational Field To: Rational Field """ + def __init__(self, parent) -> None: """ Initialize. @@ -602,6 +615,7 @@ class FunctionFieldToFractionField(FunctionFieldVectorSpaceIsomorphism): True sage: TestSuite(f).run() """ + def _call_(self, f): r""" Return the value of this map at ``f``. @@ -659,6 +673,7 @@ class FractionFieldToFunctionField(FunctionFieldVectorSpaceIsomorphism): True sage: TestSuite(f).run() """ + def _call_(self, f): r""" Return the value of this morphism at ``f``. @@ -742,6 +757,7 @@ class FunctionFieldCompletion(Map): b + b*t + b*t^3 + b*t^4 + (b + 1)*t^5 + (b + 1)*t^7 + b*t^9 + b*t^11 + b*t^12 + b*t^13 + b*t^15 + b*t^16 + (b + 1)*t^17 + (b + 1)*t^19 + O(t^20) """ + def __init__(self, field, place, name=None, prec=None, gen_name=None) -> None: """ Initialize. @@ -770,11 +786,13 @@ def __init__(self, field, place, name=None, prec=None, gen_name=None) -> None: if prec == infinity: from sage.rings.lazy_series_ring import LazyLaurentSeriesRing + codomain = LazyLaurentSeriesRing(k, name) self._precision = infinity else: # prec < infinity: # if prec is None, the Laurent series ring provides default precision from sage.rings.laurent_series_ring import LaurentSeriesRing + codomain = LaurentSeriesRing(k, name=name, default_prec=prec) self._precision = codomain.default_prec() @@ -862,7 +880,7 @@ def _expand(self, f, prec=None): sep = place.local_uniformizer() val = f.valuation(place) - e = f * sep**(-val) + e = f * sep ** (-val) coeffs = [to_k(der._derive(e, i, sep)) for i in range(prec)] return self.codomain()(coeffs, val).add_bigoh(prec + val) @@ -896,7 +914,7 @@ def _expand_lazy(self, f): sep = place.local_uniformizer() val = f.valuation(place) - e = f * sep**(-val) + e = f * sep ** (-val) def coeff(s, n): return to_k(der._derive(e, n - val, sep)) @@ -923,6 +941,7 @@ class FunctionFieldRingMorphism(SetMorphism): """ Ring homomorphism. """ + def _repr_(self) -> str: """ Return the string representation of the map. @@ -951,6 +970,7 @@ class FunctionFieldLinearMap(SetMorphism): """ Linear map to function fields. """ + def _repr_(self) -> str: """ Return the string representation of the map. @@ -978,6 +998,7 @@ class FunctionFieldLinearMapSection(SetMorphism): """ Section of linear map from function fields. """ + def _repr_(self) -> str: """ Return the string representation of the map. diff --git a/src/sage/rings/function_field/order.py b/src/sage/rings/function_field/order.py index cec5004c2a7..afdb10db054 100644 --- a/src/sage/rings/function_field/order.py +++ b/src/sage/rings/function_field/order.py @@ -132,6 +132,7 @@ class FunctionFieldOrder_base(CachedRepresentation, Parent): sage: F.maximal_order() Maximal order of Rational function field in y over Rational Field """ + def __init__(self, field, ideal_class=FunctionFieldIdeal, category=None) -> None: """ Initialize. @@ -218,6 +219,7 @@ class FunctionFieldOrder(FunctionFieldOrder_base): """ Base class for orders in function fields. """ + def _repr_(self) -> str: """ Return the string representation. @@ -234,6 +236,7 @@ class FunctionFieldOrderInfinite(FunctionFieldOrder_base): """ Base class for infinite orders in function fields. """ + def _repr_(self) -> str: """ EXAMPLES:: @@ -248,6 +251,7 @@ class FunctionFieldMaximalOrder(UniqueRepresentation, FunctionFieldOrder): """ Base class of maximal orders of function fields. """ + def _repr_(self) -> str: """ Return the string representation of the order. @@ -276,6 +280,7 @@ class FunctionFieldMaximalOrderInfinite(FunctionFieldMaximalOrder, FunctionField """ Base class of maximal infinite orders of function fields. """ + def _repr_(self) -> str: """ EXAMPLES:: diff --git a/src/sage/rings/function_field/order_basis.py b/src/sage/rings/function_field/order_basis.py index b19907db5ff..430ff8bf64e 100644 --- a/src/sage/rings/function_field/order_basis.py +++ b/src/sage/rings/function_field/order_basis.py @@ -70,6 +70,7 @@ class FunctionFieldOrder_basis(FunctionFieldOrder): ... ValueError: basis (y, y, y^3, y^4, 2*x*y + (x^4 + 1)/x) is not linearly independent """ + def __init__(self, basis, check: bool = True) -> None: """ Initialize. @@ -355,6 +356,7 @@ class FunctionFieldOrderInfinite_basis(FunctionFieldOrderInfinite): sage: O.basis() (1/x*y + 1, 1/x*y, 1/x^2*y^2, 1/x^3*y^3) """ + def __init__(self, basis, check: bool = True) -> None: """ Initialize. @@ -381,6 +383,7 @@ def __init__(self, basis, check: bool = True) -> None: R = field.base_field().maximal_order_infinite() W = V.span_of_basis([to(v) for v in basis]) from sage.modules.free_module import FreeModule + M = FreeModule(R, W.dimension()) self._basis = tuple(basis) self._ambient_space = W diff --git a/src/sage/rings/function_field/order_polymod.py b/src/sage/rings/function_field/order_polymod.py index 59a9dd6d54e..720db430ae6 100644 --- a/src/sage/rings/function_field/order_polymod.py +++ b/src/sage/rings/function_field/order_polymod.py @@ -74,8 +74,7 @@ def __init__(self, field, ideal_class=FunctionFieldIdeal_polymod) -> None: n = len(basis) self._mtable = [] for i in range(n): - row = [self._coordinate_vector(basis[i] * basis[j]) - for j in range(n)] + row = [self._coordinate_vector(basis[i] * basis[j]) for j in range(n)] self._mtable.append(row) zero = vector(R._ring, n * [0]) @@ -90,6 +89,7 @@ def mul_vecs(f, g): continue s += f[i] * g[j] * self._mtable[i][j] return s + self._mul_vecs = mul_vecs # We prepare for using Kummer's theorem to decompose primes. Note @@ -112,7 +112,7 @@ def mul_vecs(f, g): gen_vec_pow.append(g) # find places where {1,gen,...,gen^(n-1)} is not integral basis - W = V.span_of_basis([to(gen ** i) for i in range(phi.degree())]) + W = V.span_of_basis([to(gen**i) for i in range(phi.degree())]) supp = [] for g in basis: @@ -631,9 +631,7 @@ def decomposition(self, ideal): # Given an element of the function field expressed as a K-vector times # the basis of this order, construct the n n-by-n matrices that show # how to multiply by each of the basis elements. - matrices = [matrix(o, [self.coordinate_vector(b1 * b2) - for b1 in self.basis()]) - for b2 in self.basis()] + matrices = [matrix(o, [self.coordinate_vector(b1 * b2) for b1 in self.basis()]) for b2 in self.basis()] # Let O denote the maximal order self. When reduced modulo p, # matrices_reduced give the multiplication matrices used to form the @@ -719,6 +717,7 @@ class FunctionFieldMaximalOrderInfinite_polymod(FunctionFieldMaximalOrderInfinit sage: L.maximal_order_infinite() # needs sage.rings.finite_rings Maximal infinite order of Function field in y defined by y^2 + y + (x^2 + 1)/x """ + def __init__(self, field, category=None) -> None: """ Initialize. @@ -918,7 +917,7 @@ def ideal_with_gens_over_base(self, gens): i = 0 while d[i].is_zero(): i += 1 - d = x ** i + d = x**i # find the largest n such that I + (xO)^n stabilizes h1 = h @@ -1040,8 +1039,7 @@ def different(self): defined by y^2 + y + (x^2 + 1)/x """ T = self._codifferent_matrix() - codiff_gens = [sum([ci * bi for ci, bi in zip(c, self.basis())]) - for c in T.inverse().columns()] + codiff_gens = [sum([ci * bi for ci, bi in zip(c, self.basis())]) for c in T.inverse().columns()] codiff = self.ideal_with_gens_over_base(codiff_gens) return ~codiff @@ -1162,7 +1160,7 @@ def p_radical(self, prime): # exp = q^j should be at least extension degree where q is # the order of the residue field o/p - q = F.constant_base_field().order()**p.degree() + q = F.constant_base_field().order() ** p.degree() exp = q while exp <= F.degree(): exp = exp**q @@ -1224,8 +1222,7 @@ def decomposition(self, ideal): mtable = [] for i in range(n): - row = [V([to(e) for e in self._mtable[i][j]]) - for j in range(n)] + row = [V([to(e) for e in self._mtable[i][j]]) for j in range(n)] mtable.append(row) if p not in self._kummer_places: @@ -1257,8 +1254,7 @@ def decomposition(self, ideal): # p and qgen generates the prime; modulo pO, qgenb generates the prime qgenb = [to(qgen[i]) for i in range(n)] - m = [sum(qgenb[j] * mtable[i][j] for j in range(n)) - for i in range(n)] + m = [sum(qgenb[j] * mtable[i][j] for j in range(n)) for i in range(n)] beta = [fr(coeff) for coeff in matrix(m).left_kernel().basis()[0]] prime.is_prime.set_cache(True) @@ -1329,8 +1325,7 @@ def div(Ib, Jb): # Algorithm 6.2.5 of [Coh1993] def mul(Ib, Jb): - m = [mul_vec(v1, v2) - for v1 in Ib for v2 in Jb] + m = [mul_vec(v1, v2) for v1 in Ib for v2 in Jb] h = matrix(m).echelon_form() return cut_last_zero_rows(h) @@ -1393,7 +1388,7 @@ def split(h): continue break - minpol = X**len(sol) - P(list(sol)) + minpol = X ** len(sol) - P(list(sol)) # The minimal polynomial of a has only linear factors and at least two # of them. We set f to the first factor and g to the product of the rest. diff --git a/src/sage/rings/function_field/order_rational.py b/src/sage/rings/function_field/order_rational.py index 85d2abc36e9..3390ebe7698 100644 --- a/src/sage/rings/function_field/order_rational.py +++ b/src/sage/rings/function_field/order_rational.py @@ -45,6 +45,7 @@ class FunctionFieldMaximalOrder_rational(FunctionFieldMaximalOrder): sage: R = K.maximal_order(); R Maximal order of Rational function field in t over Finite Field of size 19 """ + def __init__(self, field) -> None: """ Initialize. @@ -55,8 +56,7 @@ def __init__(self, field) -> None: sage: O = K.maximal_order() sage: TestSuite(O).run(skip='_test_gcd_vs_xgcd') """ - FunctionFieldMaximalOrder.__init__(self, field, ideal_class=FunctionFieldIdeal_rational, - category=EuclideanDomains()) + FunctionFieldMaximalOrder.__init__(self, field, ideal_class=FunctionFieldIdeal_rational, category=EuclideanDomains()) self._populate_coercion_lists_(coerce_list=[field._ring]) @@ -329,13 +329,16 @@ def to_K(f): return sum((sigma(c) * beta_pow[i] for i, c in enumerate(coeffs)), K.zero()) if r == 1: # take care of the prime field case + def fr_K(g): co = W.coordinates(V(g), check=False) return R([k(co[j]) for j in range(s)]) + else: + def fr_K(g): co = W.coordinates(V(g), check=False) - return R([k(co[i:i + r]) for i in range(0, r * s, r)]) + return R([k(co[i : i + r]) for i in range(0, r * s, r)]) return K, fr_K, to_K @@ -447,6 +450,7 @@ class FunctionFieldMaximalOrderInfinite_rational(FunctionFieldMaximalOrderInfini sage: R = K.maximal_order_infinite(); R Maximal infinite order of Rational function field in t over Finite Field of size 19 """ + def __init__(self, field, category=None) -> None: """ Initialize. @@ -461,8 +465,7 @@ def __init__(self, field, category=None) -> None: sage: O = K.maximal_order_infinite() sage: TestSuite(O).run(skip='_test_gcd_vs_xgcd') """ - FunctionFieldMaximalOrderInfinite.__init__(self, field, ideal_class=FunctionFieldIdealInfinite_rational, - category=PrincipalIdealDomains().or_subcategory(category)) + FunctionFieldMaximalOrderInfinite.__init__(self, field, ideal_class=FunctionFieldIdealInfinite_rational, category=PrincipalIdealDomains().or_subcategory(category)) self._populate_coercion_lists_(coerce_list=[field.constant_base_field()]) def _element_constructor_(self, f): @@ -562,8 +565,7 @@ def ideal(self, *gens): K = self.function_field() gens = [K(g) for g in gens] try: - d = max(g.numerator().degree() - g.denominator().degree() - for g in gens if g != 0) + d = max(g.numerator().degree() - g.denominator().degree() for g in gens if g != 0) gen = K.gen() ** d except ValueError: # all gens are zero gen = K.zero() diff --git a/src/sage/rings/function_field/place.py b/src/sage/rings/function_field/place.py index 43a07c02dde..a42b22f6c81 100644 --- a/src/sage/rings/function_field/place.py +++ b/src/sage/rings/function_field/place.py @@ -90,6 +90,7 @@ class FunctionFieldPlace(Element): sage: L.places_finite()[0] # needs sage.rings.function_field Place (x, y) """ + def __init__(self, parent, prime) -> None: """ Initialize the place. @@ -210,6 +211,7 @@ def _neg_(self) -> FunctionFieldDivisor: + Place (1/x, 1/x^3*y^2 + 1/x^2*y + 1) """ from .divisor import divisor + return divisor(self.function_field(), {self: -1}) def _add_(self, other) -> FunctionFieldDivisor: @@ -315,6 +317,7 @@ def divisor(self, multiplicity=1): Place (x + 1, y) """ from .divisor import divisor + return divisor(self.function_field(), {self: multiplicity}) @@ -333,6 +336,7 @@ class PlaceSet(UniqueRepresentation, Parent): sage: L.place_set() # needs sage.rings.function_field Set of places of Function field in y defined by y^3 + x^3*y + x """ + Element = FunctionFieldPlace def __init__(self, field) -> None: diff --git a/src/sage/rings/function_field/place_polymod.py b/src/sage/rings/function_field/place_polymod.py index 14dc8284269..eeaf29613c2 100644 --- a/src/sage/rings/function_field/place_polymod.py +++ b/src/sage/rings/function_field/place_polymod.py @@ -27,6 +27,7 @@ class FunctionFieldPlace_polymod(FunctionFieldPlace): """ Places of extensions of function fields. """ + def place_below(self): """ Return the place lying below the place. @@ -204,7 +205,7 @@ def dim_RR(M): i, j = j, i ideg, jdeg = jdeg, ideg - coeff = - mat[i, c].lc() / mat[j, c].lc() + coeff = -mat[i, c].lc() / mat[j, c].lc() s = coeff * one.shift(ideg - jdeg) mat.add_multiple_of_row(i, j, s) @@ -234,7 +235,7 @@ def dim_RR(M): V, fr, to = F.vector_space() - prime_inv = ~ self.prime_ideal() + prime_inv = ~self.prime_ideal() I = O.ideal(1) J = Oinf.ideal(1) @@ -596,6 +597,7 @@ def from_W(e): def to_W(e): return vector(K(e)) + else: K = k.extension(deg, name=name) @@ -626,7 +628,7 @@ def from_K(e): p = prime.prime_below().gen().numerator() beta = prime._beta alpha = ~p * sum(c1 * c2 for c1, c2 in zip(beta, Obasis)) - alpha_powered_by_ramification_index = alpha ** prime._ramification_index + alpha_powered_by_ramification_index = alpha**prime._ramification_index def to_K(f): if f not in O: diff --git a/src/sage/rings/function_field/place_rational.py b/src/sage/rings/function_field/place_rational.py index baf683909d4..15102d7b3bb 100644 --- a/src/sage/rings/function_field/place_rational.py +++ b/src/sage/rings/function_field/place_rational.py @@ -21,6 +21,7 @@ class FunctionFieldPlace_rational(FunctionFieldPlace): """ Places of rational function fields. """ + def degree(self): """ Return the degree of the place. @@ -134,6 +135,7 @@ def to_K(f): if n_deg == d_deg: return n.lc() / d.lc() raise TypeError("not in the valuation ring") + else: O = F.maximal_order() K, from_K, _to_K = O._residue_field(prime, name=name) diff --git a/src/sage/rings/function_field/valuation.py b/src/sage/rings/function_field/valuation.py index 86082007c3a..0ed7ebe0c52 100644 --- a/src/sage/rings/function_field/valuation.py +++ b/src/sage/rings/function_field/valuation.py @@ -189,6 +189,7 @@ class FunctionFieldValuationFactory(UniqueFactory): See :meth:`sage.rings.function_field.function_field.FunctionField.valuation` for further examples. """ + def create_key_and_extra_args(self, domain, prime): r""" Create a unique key which identifies the valuation given by ``prime`` @@ -216,6 +217,7 @@ def create_key_and_extra_args(self, domain, prime): False """ from sage.categories.function_fields import FunctionFields + if domain not in FunctionFields(): raise ValueError("Domain must be a function field.") @@ -226,6 +228,7 @@ def create_key_and_extra_args(self, domain, prime): return self.create_key_and_extra_args_from_valuation_on_isomorphic_field(domain, prime[0], prime[1], prime[2]) from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace + if prime.parent() is DiscretePseudoValuationSpace(domain): # prime is already a valuation of the requested domain # if we returned (domain, prime), we would break caching @@ -249,6 +252,7 @@ def create_key_and_extra_args(self, domain, prime): base_valuation = domain.base_field().valuation(prime) return self.create_key_and_extra_args_from_valuation(domain, base_valuation) from sage.rings.ideal import Ideal_generic + if isinstance(prime, Ideal_generic): raise NotImplementedError("a place cannot be given by an ideal yet") @@ -287,6 +291,7 @@ def create_key_and_extra_args_from_place(self, domain, generator): # we construct the corresponding valuation on the polynomial ring # with v(generator) = 1 from sage.rings.valuation.gauss_valuation import GaussValuation + valuation = GaussValuation(domain._ring, TrivialValuation(domain.constant_base_field())).augmentation(generator, 1) return self.create_key_and_extra_args(domain, valuation) if generator == ~domain.gen(): @@ -362,10 +367,12 @@ def create_key_and_extra_args_from_valuation_on_isomorphic_field(self, domain, v sage: w = v.extension(L) # indirect doctest # needs sage.rings.function_field """ from sage.categories.function_fields import FunctionFields + if valuation.domain() not in FunctionFields(): raise ValueError("valuation must be defined over an isomorphic function field but %r is not a function field" % (valuation.domain(),)) from sage.categories.homset import Hom + if to_valuation_domain not in Hom(domain, valuation.domain()): raise ValueError("to_valuation_domain must map from %r to %r but %r maps from %r to %r" % (domain, valuation.domain(), to_valuation_domain, to_valuation_domain.domain(), to_valuation_domain.codomain())) if from_valuation_domain not in Hom(valuation.domain(), domain): @@ -408,6 +415,7 @@ def create_object(self, version, key, **extra_args): """ domain, valuation = key from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace + parent = DiscretePseudoValuationSpace(domain) if isinstance(valuation, tuple) and len(valuation) == 3: @@ -421,6 +429,7 @@ def create_object(self, version, key, **extra_args): return parent.__make_element_class__(InfiniteRationalFunctionFieldValuation)(parent) from sage.structure.dynamic_class import dynamic_class + clazz = RationalFunctionFieldMappedValuation if valuation.is_discrete_valuation(): clazz = dynamic_class("RationalFunctionFieldMappedValuation_discrete", (clazz, DiscreteValuation)) @@ -440,6 +449,7 @@ def create_object(self, version, key, **extra_args): # valuation corresponds to a finite place return parent.__make_element_class__(FiniteRationalFunctionFieldValuation)(parent, valuation) from sage.structure.dynamic_class import dynamic_class + clazz = NonClassicalRationalFunctionFieldValuation if valuation.is_discrete_valuation(): clazz = dynamic_class("NonClassicalRationalFunctionFieldValuation_discrete", (clazz, DiscreteFunctionFieldValuation_base)) @@ -482,6 +492,7 @@ class DiscreteFunctionFieldValuation_base(DiscreteValuation): sage: isinstance(v, DiscreteFunctionFieldValuation_base) True """ + def extensions(self, L): r""" Return the extensions of this valuation to ``L``. @@ -546,6 +557,7 @@ def extensions(self, L): """ K = self.domain() from sage.categories.function_fields import FunctionFields + if L is K: return [self] if L in FunctionFields(): @@ -558,12 +570,14 @@ def extensions(self, L): if any(self(c) < 0 for c in G.coefficients()): # rewrite L = K[u]/(H) with H integral and compute the extensions from sage.rings.valuation.gauss_valuation import GaussValuation + g = GaussValuation(G.parent(), self) y_to_u, u_to_y, H = g.monic_integral_model(G) M = K.extension(H, names=L.variable_names()) H_extensions = self.extensions(M) from sage.rings.morphism import RingHomomorphism_im_gens + if isinstance(y_to_u, RingHomomorphism_im_gens) and isinstance(u_to_y, RingHomomorphism_im_gens): return [L.valuation((w, L.hom([M(y_to_u(y_to_u.domain().gen()))]), M.hom([L(u_to_y(u_to_y.domain().gen()))]))) for w in H_extensions] raise NotImplementedError @@ -572,6 +586,7 @@ def extensions(self, L): # recursively call this method for the tower of fields from functools import reduce from operator import add + A = [base_valuation.extensions(L) for base_valuation in self.extensions(L.base())] return reduce(add, A, []) if L.constant_base_field() is not K.constant_base_field() and K.constant_base_field().is_subring(L): @@ -592,6 +607,7 @@ class RationalFunctionFieldValuation_base(FunctionFieldValuation_base): sage: isinstance(v, RationalFunctionFieldValuation_base) True """ + @cached_method def element_with_valuation(self, s): r""" @@ -616,7 +632,7 @@ def element_with_valuation(self, s): return super().element_with_valuation(s) a, b = self.value_group()._element_with_valuation(constant_valuation.value_group(), s) - ret = self.uniformizer()**a * constant_valuation.element_with_valuation(constant_valuation.value_group().gen() * b) + ret = self.uniformizer() ** a * constant_valuation.element_with_valuation(constant_valuation.value_group().gen() * b) return self.simplify(ret, error=s) @@ -634,6 +650,7 @@ class ClassicalFunctionFieldValuation_base(DiscreteFunctionFieldValuation_base): sage: isinstance(v, ClassicalFunctionFieldValuation_base) True """ + def _test_classical_residue_field(self, **options) -> None: r""" Check correctness of the residue field of a discrete valuation at a @@ -680,6 +697,7 @@ class InducedRationalFunctionFieldValuation_base(FunctionFieldValuation_base): sage: K. = FunctionField(QQ) sage: v = K.valuation(x^2 + 1) # indirect doctest """ + def __init__(self, parent, base_valuation) -> None: r""" TESTS:: @@ -791,6 +809,7 @@ def _repr_(self) -> str: """ from sage.rings.valuation.augmented_valuation import AugmentedValuation_base from sage.rings.valuation.gauss_valuation import GaussValuation + if isinstance(self._base_valuation, AugmentedValuation_base): if self._base_valuation._base_valuation == GaussValuation(self.domain()._ring, TrivialValuation(self.domain().constant_base_field())): if self._base_valuation._mu == 1: @@ -818,11 +837,8 @@ def extensions(self, L): return [self] from sage.categories.function_fields import FunctionFields - if (L in FunctionFields() - and K.is_subring(L) - and L.base() is L - and L.constant_base_field() is not K.constant_base_field() - and K.constant_base_field().is_subring(L.constant_base_field())): + + if L in FunctionFields() and K.is_subring(L) and L.base() is L and L.constant_base_field() is not K.constant_base_field() and K.constant_base_field().is_subring(L.constant_base_field()): # The above condition checks whether L is an extension of K that # comes from an extension of the field of constants # Condition "L.base() is L" is important so we do not call this @@ -907,6 +923,7 @@ def simplify(self, f, error=None, force: bool = False): error = self(f) if force else self.upper_bound(f) from sage.rings.infinity import infinity + if error is infinity: return f @@ -990,6 +1007,7 @@ class FiniteRationalFunctionFieldValuation(InducedRationalFunctionFieldValuation sage: q = L.valuation(x^6 - t); q (x^6 + 2*t)-adic valuation """ + def __init__(self, parent, base_valuation) -> None: r""" TESTS:: @@ -1017,6 +1035,7 @@ class NonClassicalRationalFunctionFieldValuation(InducedRationalFunctionFieldVal sage: w = K.valuation(v); w # indirect doctest 2-adic valuation """ + def __init__(self, parent, base_valuation) -> None: r""" TESTS: @@ -1091,6 +1110,7 @@ class FunctionFieldFromLimitValuation(FiniteExtensionFromLimitValuation, Discret sage: w = v.extension(L); w # needs sage.rings.function_field (x - 1)-adic valuation """ + def __init__(self, parent, approximant, G, approximants) -> None: r""" TESTS:: @@ -1153,6 +1173,7 @@ class FunctionFieldMappedValuation_base(FunctionFieldValuation_base, MappedValua sage: v = K.valuation(1/x); v Valuation at the infinite place """ + def __init__(self, parent, base_valuation, to_base_valuation_domain, from_base_valuation_domain) -> None: r""" TESTS:: @@ -1217,6 +1238,7 @@ def scale(self, scalar): 3 * (x)-adic valuation (in Rational function field in x over Finite Field of size 2 after x |--> 1/x) """ from sage.rings.rational_field import QQ + if scalar in QQ and scalar > 0 and scalar != 1: return self.domain().valuation((self._base_valuation.scale(scalar), self._to_base, self._from_base)) return super().scale(scalar) @@ -1268,6 +1290,7 @@ class FunctionFieldMappedValuationRelative_base(FunctionFieldMappedValuation_bas sage: v = K.valuation(1/x); v Valuation at the infinite place """ + def __init__(self, parent, base_valuation, to_base_valuation_domain, from_base_valuation_domain) -> None: r""" TESTS:: @@ -1313,6 +1336,7 @@ class RationalFunctionFieldMappedValuation(FunctionFieldMappedValuationRelative_ [ Gauss valuation induced by 2-adic valuation, v(x) = 1 ] (in Rational function field in x over Rational Field after x |--> 1/x) """ + def __init__(self, parent, base_valuation, to_base_valuation_doain, from_base_valuation_domain) -> None: r""" TESTS:: @@ -1339,6 +1363,7 @@ class InfiniteRationalFunctionFieldValuation(FunctionFieldMappedValuationRelativ sage: K. = FunctionField(QQ) sage: v = K.valuation(1/x) # indirect doctest """ + def __init__(self, parent) -> None: r""" TESTS:: @@ -1396,6 +1421,7 @@ class FunctionFieldExtensionMappedValuation(FunctionFieldMappedValuationRelative sage: isinstance(w, FunctionFieldExtensionMappedValuation) # needs sage.rings.function_field True """ + def _repr_(self) -> str: r""" Return a printable representation of this valuation. @@ -1417,7 +1443,7 @@ def _repr_(self) -> str: [[ Valuation at the infinite place, v(y + 1) = 2 ]-adic valuation, [ Valuation at the infinite place, v(y - 1) = 2 ]-adic valuation] """ - assert (self.domain().base() is not self.domain()) + assert self.domain().base() is not self.domain() if repr(self._base_valuation) == repr(self.restriction(self.domain().base())): return repr(self._base_valuation) return super()._repr_() diff --git a/src/sage/rings/function_field/valuation_ring.py b/src/sage/rings/function_field/valuation_ring.py index 673af072c90..8e2e2437c7d 100644 --- a/src/sage/rings/function_field/valuation_ring.py +++ b/src/sage/rings/function_field/valuation_ring.py @@ -89,6 +89,7 @@ class FunctionFieldValuationRing(UniqueRepresentation, Parent): sage: p.valuation_ring() Valuation ring at Place (x, x*y) """ + def __init__(self, field, place, category=None) -> None: """ Initialize. diff --git a/src/sage/rings/generic.py b/src/sage/rings/generic.py index 6b08073f737..fdf6d3bf8b8 100644 --- a/src/sage/rings/generic.py +++ b/src/sage/rings/generic.py @@ -86,6 +86,7 @@ class ProductTree: (32589158477190044730, 70746471270782959), (2305567963945518424753102147331756070,)] """ + def __init__(self, leaves): r""" Initialize a product tree having the given ring elements @@ -100,7 +101,7 @@ def __init__(self, leaves): V = tuple(leaves) self.layers = [V] while len(V) > 1: - V = tuple(prod(V[i:i+2]) for i in range(0,len(V),2)) + V = tuple(prod(V[i : i + 2]) for i in range(0, len(V), 2)) self.layers.append(V) def __len__(self): @@ -239,15 +240,15 @@ def interpolation(self, xs): """ if self._crt_bases is None: from sage.arith.misc import CRT_basis + self._crt_bases = [] for V in self.layers[:-1]: - B = tuple(CRT_basis(V[i:i+2]) for i in range(0, len(V), 2)) + B = tuple(CRT_basis(V[i : i + 2]) for i in range(0, len(V), 2)) self._crt_bases.append(B) if len(xs) != len(self.layers[0]): raise ValueError('number of given elements must equal the number of leaves') for basis, layer in zip(self._crt_bases, self.layers[1:]): - xs = [sum(c*x for c, x in zip(cs, xs[2*i:2*i+2])) % mod - for i, (cs, mod) in enumerate(zip(basis, layer))] + xs = [sum(c * x for c, x in zip(cs, xs[2 * i : 2 * i + 2])) % mod for i, (cs, mod) in enumerate(zip(basis, layer))] assert len(xs) == 1 return xs[0] @@ -300,6 +301,7 @@ def prod_with_derivative(pairs): sage: prod_with_derivative(zip(us, vs)) (442943981574522759, 104645261461514994) """ + class _aux: def __init__(self, f, df): self.f, self.df = f, df diff --git a/src/sage/rings/homset.py b/src/sage/rings/homset.py index 0435b5c1ef9..08ec1e24f4d 100644 --- a/src/sage/rings/homset.py +++ b/src/sage/rings/homset.py @@ -30,6 +30,7 @@ def RingHomset(R, S, category=None): """ if isinstance(R, quotient_ring.QuotientRing_nc): from .polynomial.polynomial_quotient_ring import PolynomialQuotientRing_generic + if not isinstance(R, PolynomialQuotientRing_generic): # backwards compatibility return RingHomset_quo_ring(R, S, category=category) return RingHomset_generic(R, S, category=category) @@ -142,6 +143,7 @@ def _element_constructor_(self, x, check=True, base_map=None): True """ from sage.categories.map import Map + # Case 0: the homomorphism is given by images of generators if not (isinstance(x, Map) and x.category_for().is_subcategory(Rings())): return morphism.RingHomomorphism_im_gens(self, x, base_map=base_map, check=check) @@ -157,8 +159,7 @@ def _element_constructor_(self, x, check=True, base_map=None): return morphism.RingHomomorphism_from_base(self, x.underlying_map()) # Case 2: unique extension via fraction field try: - if (isinstance(x, morphism.RingHomomorphism_im_gens) and - x.domain().fraction_field().has_coerce_map_from(self.domain())): + if isinstance(x, morphism.RingHomomorphism_im_gens) and x.domain().fraction_field().has_coerce_map_from(self.domain()): return morphism.RingHomomorphism_im_gens(self, x.im_gens()) except (TypeError, ValueError): pass @@ -168,8 +169,7 @@ def _element_constructor_(self, x, check=True, base_map=None): except (TypeError, ValueError): pass # Case 4: the homomorphism is induced from the base ring - if (self.domain() != self.domain().base() - or self.codomain() != self.codomain().base()): + if self.domain() != self.domain().base() or self.codomain() != self.codomain().base(): x = self.domain().base().Hom(self.codomain().base())(x) return morphism.RingHomomorphism_from_base(self, x) raise ValueError(f'cannot convert {x} to an element of {self}') diff --git a/src/sage/rings/ideal.py b/src/sage/rings/ideal.py index 810bcb6d3c3..078acd7a770 100644 --- a/src/sage/rings/ideal.py +++ b/src/sage/rings/ideal.py @@ -11,6 +11,7 @@ If `R` is non-commutative, the former creates a left and the latter a right ideal, and ``R*[a,b,...]*R`` creates a two-sided ideal. """ + # **************************************************************************** # Copyright (C) 2005 William Stein # @@ -199,9 +200,8 @@ def Ideal(*args, **kwds): if inferred_field and not isinstance(I, Ideal_fractional): # trac 32320 import warnings - warnings.warn(f'Constructing an ideal in {R}, which is a field.' - ' Did you intend to take numerators first?' - ' This warning can be muted by passing the base ring to Ideal() explicitly.') + + warnings.warn(f'Constructing an ideal in {R}, which is a field.' ' Did you intend to take numerators first?' ' This warning can be muted by passing the base ring to Ideal() explicitly.') return I @@ -212,6 +212,7 @@ class Ideal_generic(MonoidElement): See :func:`Ideal()`. """ + def __init__(self, ring, gens, coerce=True, **kwds) -> None: """ Initialize this ideal. @@ -341,9 +342,11 @@ def _richcmp_(self, other, op): return rich_to_bool(op, 1) # self.is_zero() is already False from sage.rings.integer_ring import ZZ + if self.ring().base_ring() is ZZ: - #assert self.ring().implementation() != "singular" + # assert self.ring().implementation() != "singular" from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + Rs = PolynomialRing(ZZ, self.ring().variable_names(), implementation="singular") Is = Rs.ideal(self.gens()) Js = Rs.ideal(other.gens()) @@ -524,6 +527,7 @@ def apply_morphism(self, phi): Fractional ideal (2, a + 1) """ from sage.categories.morphism import Morphism + if not isinstance(phi, Morphism): raise TypeError("phi must be a morphism") # delegate: morphisms know how to apply themselves to ideals @@ -539,9 +543,8 @@ def _latex_(self): \left(3\right)\Bold{Z} """ from sage.misc import latex - return '\\left(%s\\right)%s' % (", ".join(latex.latex(g) - for g in self.gens()), - latex.latex(self.ring())) + + return '\\left(%s\\right)%s' % (", ".join(latex.latex(g) for g in self.gens()), latex.latex(self.ring())) def ring(self): """ @@ -601,7 +604,7 @@ def reduce(self, f): sage: parent(ZZ.ideal(5).reduce(17)) Integer Ring """ - return f # default + return f # default def gens(self): # -> tuple | PolynomialSequence """ @@ -699,6 +702,7 @@ def is_maximal(self): False """ from sage.rings.integer_ring import ZZ + R = self.ring() if hasattr(R, 'cover_ring') and R.cover_ring() is ZZ: # The following test only works for quotients of Z/nZ: for @@ -763,7 +767,7 @@ def is_primary(self, P=None): except (NotImplementedError, ValueError): raise NotImplementedError if P is None: - return (len(ass) == 1) + return len(ass) == 1 return (len(ass) == 1) and (ass[0] == P) def primary_decomposition(self): @@ -824,6 +828,7 @@ def is_prime(self): For general rings, uses the list of associated primes. """ from sage.rings.integer_ring import ZZ + R = self.ring() if hasattr(R, 'cover_ring') and R.cover_ring() is ZZ and R.is_finite(): # For quotient rings of ZZ, prime is the same as maximal. @@ -984,6 +989,7 @@ def category(self): over Integer Ring """ import sage.categories.all + return sage.categories.all.Ideals(self.__ring) def __add__(self, other): @@ -1065,8 +1071,7 @@ def _mul_(self, other): sage: I._mul_(J) Ideal (x^3*y, x^2*y^2, x^3*z, x^2*y*z, x^4, x^3*y) of Multivariate Polynomial Ring in x, y, z over Rational Field """ - return self.ring().ideal([z for x in self.gens() for y in other.gens() - if (z := x * y)]) + return self.ring().ideal([z for x in self.gens() for y in other.gens() if (z := x * y)]) def __rmul__(self, other): """ @@ -1086,8 +1091,7 @@ def __rmul__(self, other): except (TypeError, ArithmeticError, ValueError): pass other = self.ring().ideal(other) - return self.ring().ideal([z for x in self.gens() for y in other.gens() - if (z := y * x)]) + return self.ring().ideal([z for x in self.gens() for y in other.gens() if (z := y * x)]) def norm(self): """ @@ -1191,6 +1195,7 @@ def _macaulay2_init_(self, macaulay2=None): """ if macaulay2 is None: from sage.interfaces.macaulay2 import macaulay2 as m2_default + macaulay2 = m2_default R = self.ring() @@ -1217,6 +1222,7 @@ def free_resolution(self, *args, **kwds): if not self.is_principal(): raise NotImplementedError("the ideal must be a principal ideal") from sage.homology.free_resolution import FiniteFreeResolution_free_module + return FiniteFreeResolution_free_module(self, *args, **kwds) def graded_free_resolution(self, *args, **kwds): @@ -1234,6 +1240,7 @@ def graded_free_resolution(self, *args, **kwds): S(0) <-- S(-3) <-- 0 """ from sage.homology.graded_resolution import GradedFiniteFreeResolution_free_module + return GradedFiniteFreeResolution_free_module(self, *args, **kwds) @@ -1243,6 +1250,7 @@ class Ideal_principal(Ideal_generic): See :func:`Ideal()`. """ + # now Ideal_principal takes a list. # def __init__(self, ring, gen): # Ideal_generic.__init__(self, ring, [gen]) @@ -1456,6 +1464,7 @@ class Ideal_pid(Ideal_principal): sage: I Principal ideal (8) of Integer Ring """ + def __add__(self, other): """ Add the two ideals. @@ -1584,7 +1593,7 @@ def is_prime(self): if self.is_zero(): # PIDs are integral domains by definition return True g = self.gen() - if g.is_one(): # The ideal (1) is never prime + if g.is_one(): # The ideal (1) is never prime return False if hasattr(g, 'is_irreducible'): return g.is_irreducible() @@ -1674,6 +1683,7 @@ def residue_field(self): if not self.is_prime(): raise ValueError("The ideal (%s) is not prime" % self) from sage.rings.integer_ring import ZZ + if self.ring() is ZZ: return ZZ.residue_field(self, check=False) raise NotImplementedError("residue_field() is only implemented for ZZ and rings of integers of number fields.") @@ -1696,6 +1706,7 @@ class Ideal_fractional(Ideal_generic): See :func:`Ideal()`. """ + def _repr_(self): """ Return a string representation of ``self``. @@ -1710,6 +1721,7 @@ def _repr_(self): """ return "Fractional ideal %s of %s" % (self._repr_short(), self.ring()) + # constructors for standard (benchmark) ideals, written uppercase as # these are constructors @@ -1767,6 +1779,7 @@ def Cyclic(R, n=None, homog=False, singular=None): if singular is None: from sage.interfaces.singular import singular as singular_default + singular = singular_default singular.lib("polylib") @@ -1811,6 +1824,7 @@ def Katsura(R, n=None, homog=False, singular=None): Ideal (x - 1) of Multivariate Polynomial Ring in x over Rational Field """ from .rational_field import RationalField + if n: if n > R.ngens(): raise ArithmeticError("n must be <= R.ngens().") @@ -1819,6 +1833,7 @@ def Katsura(R, n=None, homog=False, singular=None): if singular is None: from sage.interfaces.singular import singular as singular_default + singular = singular_default singular.lib("polylib") R2 = R.change_ring(RationalField()) @@ -1863,6 +1878,7 @@ def FieldIdeal(R): """ q = R.base_ring().order() import sage.rings.infinity + if q is sage.rings.infinity.infinity: raise TypeError("Cannot construct field ideal for R.base_ring().order()==infinity") return R.ideal([x**q - x for x in R.gens()]) diff --git a/src/sage/rings/ideal_monoid.py b/src/sage/rings/ideal_monoid.py index a4dc253f1ea..ff6fa766482 100644 --- a/src/sage/rings/ideal_monoid.py +++ b/src/sage/rings/ideal_monoid.py @@ -71,8 +71,7 @@ def __init__(self, R): cat = Monoids() if R.is_commutative(): cat = cat.Commutative() - Parent.__init__(self, base=sage.rings.integer_ring.ZZ, - category=cat) + Parent.__init__(self, base=sage.rings.integer_ring.ZZ, category=cat) self._populate_coercion_lists_() def _repr_(self): diff --git a/src/sage/rings/imaginary_unit.py b/src/sage/rings/imaginary_unit.py index ae78b38d6c8..7ffc96c3270 100644 --- a/src/sage/rings/imaginary_unit.py +++ b/src/sage/rings/imaginary_unit.py @@ -1,4 +1,3 @@ - from sage.rings.number_field.number_field import GaussianField I = GaussianField().gen() diff --git a/src/sage/rings/infinity.py b/src/sage/rings/infinity.py index 8417c6bd886..310d8676448 100644 --- a/src/sage/rings/infinity.py +++ b/src/sage/rings/infinity.py @@ -207,6 +207,7 @@ sage: m.rows() # needs sage.modules [(+Infinity)] """ + # **************************************************************************** # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -582,8 +583,7 @@ def __init__(self): True """ cat = Semirings().Commutative() - Parent.__init__(self, self, names=('oo',), normalize=False, - category=cat) + Parent.__init__(self, self, names=('oo',), normalize=False, category=cat) def ngens(self) -> int: """ @@ -945,6 +945,7 @@ def _sympy_(self): True """ import sympy + return sympy.zoo def _richcmp_(self, other, op) -> bool: @@ -969,6 +970,7 @@ class SignError(ArithmeticError): """ Sign error exception. """ + pass @@ -1243,10 +1245,10 @@ def _coerce_map_from_(self, R) -> bool: True """ from sage.structure.coerce import parent_is_real_numerical + if parent_is_real_numerical(R): return True - return isinstance(R, (sage.rings.abc.RealIntervalField, - sage.rings.abc.RealBallField)) + return isinstance(R, (sage.rings.abc.RealIntervalField, sage.rings.abc.RealBallField)) def _pushout_(self, other): r""" @@ -1610,6 +1612,7 @@ def _sympy_(self): True """ import sympy + return -sympy.oo def _gap_init_(self) -> str: @@ -1709,6 +1712,7 @@ def _sympy_(self): True """ import sympy + return sympy.oo def _gap_init_(self) -> str: @@ -1777,6 +1781,7 @@ def check_comparison(ring): """ from sage.rings.rational_field import QQ + elements = [-1e3, 99.9999, 0, 1, 100000] try: from sage.symbolic.ring import SR @@ -1790,7 +1795,7 @@ def check_comparison(ring): try: z = ring(z) except (ValueError, TypeError): - continue # ignore if z is not in ring + continue # ignore if z is not in ring msg = 'testing {} in {}: id = {}, {}, {}'.format(z, ring, id(z), id(infinity), id(minus_infinity)) assert minus_infinity < z, msg assert z > minus_infinity, msg diff --git a/src/sage/rings/integer.pyi b/src/sage/rings/integer.pyi index 5d81a21b2b7..5d56583b1a0 100644 --- a/src/sage/rings/integer.pyi +++ b/src/sage/rings/integer.pyi @@ -7,62 +7,26 @@ from sage.categories.morphism import Morphism class Integer(EuclideanDomainElement): value: __mpz_struct[1] - def set_from_mpz(self, value: mpz_t) -> None: - ... - - def hash_c(self) -> int: - ... - - def __pari__(self) -> object: - ... - - def _shift_helper(self, y: object, sign: int) -> object: - ... - - def _add_(self, other: object) -> object: - ... - - def _mul_(self, other: object) -> object: - ... - - def _pow_(self, other: object) -> object: - ... - - def _and(self, other: 'Integer') -> 'Integer': - ... - - def _or(self, other: 'Integer') -> 'Integer': - ... - - def _xor(self, other: 'Integer') -> 'Integer': - ... - - def _exact_log_log2_iter(self, m: 'Integer') -> int: - ... - - def _exact_log_mpfi_log(self, m: object) -> int: - ... - - def _valuation(self, p: 'Integer') -> RingElement: - ... - - def _val_unit(self, p: 'Integer') -> object: - ... - - def _divide_knowing_divisible_by(self, right: 'Integer') -> 'Integer': - ... - - def _is_power_of(self, n: 'Integer') -> bool: - ... - - def _pseudoprime_is_prime(self, proof: object) -> bool: - ... - -def mpz_set_str_python(z: mpz_ptr, s: str, base: int) -> int: - ... - -def smallInteger(value: int) -> 'Integer': - ... + def set_from_mpz(self, value: mpz_t) -> None: ... + def hash_c(self) -> int: ... + def __pari__(self) -> object: ... + def _shift_helper(self, y: object, sign: int) -> object: ... + def _add_(self, other: object) -> object: ... + def _mul_(self, other: object) -> object: ... + def _pow_(self, other: object) -> object: ... + def _and(self, other: 'Integer') -> 'Integer': ... + def _or(self, other: 'Integer') -> 'Integer': ... + def _xor(self, other: 'Integer') -> 'Integer': ... + def _exact_log_log2_iter(self, m: 'Integer') -> int: ... + def _exact_log_mpfi_log(self, m: object) -> int: ... + def _valuation(self, p: 'Integer') -> RingElement: ... + def _val_unit(self, p: 'Integer') -> object: ... + def _divide_knowing_divisible_by(self, right: 'Integer') -> 'Integer': ... + def _is_power_of(self, n: 'Integer') -> bool: ... + def _pseudoprime_is_prime(self, proof: object) -> bool: ... + +def mpz_set_str_python(z: mpz_ptr, s: str, base: int) -> int: ... +def smallInteger(value: int) -> 'Integer': ... _small_primes_table: list[bool] diff --git a/src/sage/rings/integer_fake.pyi b/src/sage/rings/integer_fake.pyi index a8f2b601191..c49a37c56bb 100644 --- a/src/sage/rings/integer_fake.pyi +++ b/src/sage/rings/integer_fake.pyi @@ -1,8 +1,5 @@ from cpython.ref import PyTypeObject from sage.libs.gmp.types import mpz_ptr -def Integer_AS_MPZ(x: object) -> mpz_ptr: - ... - -def is_Integer(x: object) -> bool: - ... +def Integer_AS_MPZ(x: object) -> mpz_ptr: ... +def is_Integer(x: object) -> bool: ... diff --git a/src/sage/rings/integer_ring.pyi b/src/sage/rings/integer_ring.pyi index 1cc5b747b9c..0ab9f002c45 100644 --- a/src/sage/rings/integer_ring.pyi +++ b/src/sage/rings/integer_ring.pyi @@ -4,135 +4,52 @@ from sage.rings.ring import CommutativeRing from sage.rings.integer import Integer from sage.libs.gmp.types import mpz_t -def is_IntegerRing(x: Any) -> bool: - ... +def is_IntegerRing(x: Any) -> bool: ... class IntegerRing_class(CommutativeRing): - def __init__(self) -> None: - ... - - def __reduce__(self) -> tuple: - ... - - def __hash__(self) -> int: - ... - - def __richcmp__(self, right: Any, op: int) -> bool: - ... - - def _repr_(self) -> str: - ... - - def _latex_(self) -> str: - ... - - def __getitem__(self, x: Any) -> Any: - ... - - def range(self, start: Any, end: Optional[Any] = None, step: Optional[Any] = None) -> list[Integer]: - ... - - def __iter__(self) -> Any: - ... - - def _coerce_map_from_(self, S: Any) -> Optional[Any]: - ... - - def random_element(self, x: Optional[Any] = None, y: Optional[Any] = None, distribution: Optional[str] = None) -> Integer: - ... - - def _randomize_mpz(self, value: mpz_t, x: Optional[Any], y: Optional[Any], distribution: Optional[str]) -> int: - ... - - def _is_valid_homomorphism_(self, codomain: Any, im_gens: list[Any], base_map: Optional[Any] = None) -> bool: - ... - - def _repr_option(self, key: str) -> Any: - ... - - def is_field(self, proof: bool = True) -> bool: - ... - - def fraction_field(self) -> Any: - ... - - def extension(self, poly: Any, names: Any, **kwds: Any) -> Any: - ... - - def quotient(self, I: Any, names: Optional[Any] = None, **kwds: Any) -> Any: - ... - - def residue_field(self, prime: Any, check: bool = True, names: Optional[Any] = None) -> Any: - ... - - def gens(self) -> tuple[Integer]: - ... - - def gen(self, n: int = 0) -> Integer: - ... - - def ngens(self) -> int: - ... - - def degree(self) -> int: - ... - - def absolute_degree(self) -> int: - ... - - def characteristic(self) -> Integer: - ... - - def krull_dimension(self) -> int: - ... - - def completion(self, p: Any, prec: int, extras: Optional[dict] = {}) -> Any: - ... - - def order(self) -> Any: - ... - - def zeta(self, n: int = 2) -> Integer: - ... - - def parameter(self) -> Integer: - ... - - def _roots_univariate_polynomial(self, p: Any, ring: Optional[Any] = None, multiplicities: bool = True, algorithm: Optional[str] = None) -> list[Union[tuple[Integer, int], Integer]]: - ... - - def _gap_init_(self) -> str: - ... - - def _fricas_init_(self) -> str: - ... - - def _magma_init_(self, magma: Any) -> str: - ... - - def _macaulay2_init_(self, macaulay2: Optional[Any] = None) -> str: - ... - - def _polymake_init_(self) -> str: - ... - - def _sympy_(self) -> Any: - ... - - def _sage_input_(self, sib: Any, coerced: bool) -> Any: - ... - - def valuation(self, p: Any) -> Any: - ... - - def from_bytes(self, input_bytes: Any, byteorder: str = 'big', is_signed: bool = False) -> Integer: - ... + def __init__(self) -> None: ... + def __reduce__(self) -> tuple: ... + def __hash__(self) -> int: ... + def __richcmp__(self, right: Any, op: int) -> bool: ... + def _repr_(self) -> str: ... + def _latex_(self) -> str: ... + def __getitem__(self, x: Any) -> Any: ... + def range(self, start: Any, end: Optional[Any] = None, step: Optional[Any] = None) -> list[Integer]: ... + def __iter__(self) -> Any: ... + def _coerce_map_from_(self, S: Any) -> Optional[Any]: ... + def random_element(self, x: Optional[Any] = None, y: Optional[Any] = None, distribution: Optional[str] = None) -> Integer: ... + def _randomize_mpz(self, value: mpz_t, x: Optional[Any], y: Optional[Any], distribution: Optional[str]) -> int: ... + def _is_valid_homomorphism_(self, codomain: Any, im_gens: list[Any], base_map: Optional[Any] = None) -> bool: ... + def _repr_option(self, key: str) -> Any: ... + def is_field(self, proof: bool = True) -> bool: ... + def fraction_field(self) -> Any: ... + def extension(self, poly: Any, names: Any, **kwds: Any) -> Any: ... + def quotient(self, I: Any, names: Optional[Any] = None, **kwds: Any) -> Any: ... + def residue_field(self, prime: Any, check: bool = True, names: Optional[Any] = None) -> Any: ... + def gens(self) -> tuple[Integer]: ... + def gen(self, n: int = 0) -> Integer: ... + def ngens(self) -> int: ... + def degree(self) -> int: ... + def absolute_degree(self) -> int: ... + def characteristic(self) -> Integer: ... + def krull_dimension(self) -> int: ... + def completion(self, p: Any, prec: int, extras: Optional[dict] = {}) -> Any: ... + def order(self) -> Any: ... + def zeta(self, n: int = 2) -> Integer: ... + def parameter(self) -> Integer: ... + def _roots_univariate_polynomial(self, p: Any, ring: Optional[Any] = None, multiplicities: bool = True, algorithm: Optional[str] = None) -> list[Union[tuple[Integer, int], Integer]]: ... + def _gap_init_(self) -> str: ... + def _fricas_init_(self) -> str: ... + def _magma_init_(self, magma: Any) -> str: ... + def _macaulay2_init_(self, macaulay2: Optional[Any] = None) -> str: ... + def _polymake_init_(self) -> str: ... + def _sympy_(self) -> Any: ... + def _sage_input_(self, sib: Any, coerced: bool) -> Any: ... + def valuation(self, p: Any) -> Any: ... + def from_bytes(self, input_bytes: Any, byteorder: str = 'big', is_signed: bool = False) -> Integer: ... ZZ = IntegerRing_class() Z = ZZ -def IntegerRing() -> IntegerRing_class: - ... - -def crt_basis(X: list[Integer], xgcd: Optional[Any] = None) -> list[Integer]: - ... +def IntegerRing() -> IntegerRing_class: ... +def crt_basis(X: list[Integer], xgcd: Optional[Any] = None) -> list[Integer]: ... diff --git a/src/sage/rings/invariants/all.py b/src/sage/rings/invariants/all.py index eb0cce3175f..ff5b1167cf3 100644 --- a/src/sage/rings/invariants/all.py +++ b/src/sage/rings/invariants/all.py @@ -1,2 +1,3 @@ from sage.misc.lazy_import import lazy_import + lazy_import('sage.rings.invariants.invariant_theory', 'invariant_theory') diff --git a/src/sage/rings/invariants/invariant_theory.py b/src/sage/rings/invariants/invariant_theory.py index 80e22af51f6..6cb7269a749 100644 --- a/src/sage/rings/invariants/invariant_theory.py +++ b/src/sage/rings/invariants/invariant_theory.py @@ -265,30 +265,32 @@ def transvectant(f, g, h=1, scale='default'): raise ValueError('all input forms must be in the same polynomial ring') x = f._variables[0] y = f._variables[1] - degree = f._d + g._d - 2*h + degree = f._d + g._d - 2 * h if h > f._d or h > g._d: tv = R(0) else: from sage.functions.other import binomial, factorial + if scale == 'default': - scalar = factorial(f._d-h) * factorial(g._d-h) \ - * R(factorial(f._d)*factorial(g._d))**(-1) + scalar = factorial(f._d - h) * factorial(g._d - h) * R(factorial(f._d) * factorial(g._d)) ** (-1) elif scale == 'none': scalar = 1 else: raise ValueError('unknown scale type: %s' % scale) def diff(j): - df = f.form().derivative(x, j).derivative(y, h-j) - dg = g.form().derivative(x, h-j).derivative(y, j) - return (-1)**j * binomial(h, j) * df * dg - tv = scalar * sum([diff(j) for j in range(h+1)]) + df = f.form().derivative(x, j).derivative(y, h - j) + dg = g.form().derivative(x, h - j).derivative(y, j) + return (-1) ** j * binomial(h, j) * df * dg + + tv = scalar * sum([diff(j) for j in range(h + 1)]) if tv.parent() is not R: S = tv.parent() x = S(x) y = S(y) return AlgebraicForm(2, degree, tv, x, y) + ###################################################################### @@ -355,15 +357,19 @@ def _jacobian_determinant(self, *args): x^6*y^3 - x^3*y^6 - x^6 + y^6 + x^3 - y^3 """ if self._homogeneous: + def diff(p, d): return [p.derivative(x) for x in self._variables] + else: + def diff(p, d): variables = self._variables[0:-1] grad = [p.derivative(x) for x in variables] - dp_dz = d*p - sum(x*dp_dx for x, dp_dx in zip(variables, grad)) + dp_dz = d * p - sum(x * dp_dx for x, dp_dx in zip(variables, grad)) grad.append(dp_dz) return grad + jac = [diff(p, d) for p, d in args] return matrix(self._ring, jac).det() @@ -443,6 +449,7 @@ def is_homogeneous(self): ###################################################################### + class AlgebraicForm(FormsBase): """ The base class of algebraic forms (i.e. homogeneous polynomials). @@ -524,11 +531,10 @@ def __init__(self, n, d, polynomial, *args, **kwds): variables = _guess_variables(polynomial, *args) if len(variables) == n: pass - elif len(variables) == n-1: + elif len(variables) == n - 1: variables = variables + (None,) else: - raise ValueError('need '+str(n)+' or ' + - str(n-1)+' variables, got '+str(variables)) + raise ValueError('need ' + str(n) + ' or ' + str(n - 1) + ' variables, got ' + str(variables)) ring = polynomial.parent() homogeneous = variables[-1] is not None super().__init__(n, homogeneous, ring, variables) @@ -553,14 +559,11 @@ def _check(self): degrees.update(self._polynomial.exponents()) else: for e in self._polynomial.exponents(): - deg = sum([ e[R.gens().index(x)] - for x in self._variables if x is not None ]) + deg = sum([e[R.gens().index(x)] for x in self._variables if x is not None]) degrees.add(deg) if self._homogeneous and len(degrees) > 1: raise ValueError('polynomial is not homogeneous') - if degrees == set() or \ - (self._homogeneous and degrees == set([self._d])) or \ - (not self._homogeneous and max(degrees) <= self._d): + if degrees == set() or (self._homogeneous and degrees == set([self._d])) or (not self._homogeneous and max(degrees) <= self._d): return raise ValueError('polynomial is of the wrong degree') @@ -598,6 +601,7 @@ def _check_covariant(self, method_name, g=None, invariant=False): """ assert self._homogeneous from sage.matrix.constructor import vector, random_matrix + if g is None: F = self._ring.base_ring() g = random_matrix(F, self._n, algorithm='unimodular') @@ -651,15 +655,12 @@ def _repr_(self): 'Binary quintic given by x^5 + y^5' """ s = '' - ary = ['Unary', 'Binary', 'Ternary', 'Quaternary', 'Quinary', - 'Senary', 'Septenary', 'Octonary', 'Nonary', 'Denary'] + ary = ['Unary', 'Binary', 'Ternary', 'Quaternary', 'Quinary', 'Senary', 'Septenary', 'Octonary', 'Nonary', 'Denary'] try: - s += ary[self._n-1] + s += ary[self._n - 1] except IndexError: s += 'Algebraic' - ic = ['constant form', 'monic', 'quadratic', 'cubic', 'quartic', 'quintic', - 'sextic', 'septimic', 'octavic', 'nonic', 'decimic', - 'undecimic', 'duodecimic'] + ic = ['constant form', 'monic', 'quadratic', 'cubic', 'quartic', 'quintic', 'sextic', 'septimic', 'octavic', 'nonic', 'decimic', 'undecimic', 'duodecimic'] s += ' ' if self._d < 0: s += 'form of degree {}'.format(self._d) @@ -740,12 +741,13 @@ def homogenized(self, var='h'): variables = [R(_) for _ in self._variables[0:-1]] + [R(var)] except AttributeError: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(self._ring.base_ring(), [str(self._ring.gen(0)), str(var)]) polynomial = R(self._polynomial).homogenize(var) variables = R.gens() if polynomial.total_degree() < self._d: k = self._d - polynomial.total_degree() - polynomial = polynomial * R(var)**k + polynomial = polynomial * R(var) ** k return self.__class__(self._n, self._d, polynomial, variables) def _extract_coefficients(self, monomials): @@ -824,6 +826,7 @@ def mono_to_tuple(mono): def coeff_tuple_iter(): for i, c in enumerate(self._polynomial): yield (c, (i,)) + else: # Multivariate polynomials, mixing variables and coefficients ! def mono_to_tuple(mono): @@ -910,16 +913,17 @@ def transformed(self, g): transform = g else: from sage.modules.free_module_element import vector + v = vector(self._ring, self._variables) - g_v = vector(self._ring, g*v) + g_v = vector(self._ring, g * v) transform = {v[i]: g_v[i] for i in range(self._n)} # The covariant of the transformed polynomial - return self.__class__(self._n, self._d, - self.form().subs(transform), self.variables()) + return self.__class__(self._n, self._d, self.form().subs(transform), self.variables()) ###################################################################### + class QuadraticForm(AlgebraicForm): """ Invariant theory of a multivariate quadratic form. @@ -995,7 +999,7 @@ def from_invariants(cls, discriminant, x, z, *args, **kwargs): Binary quadratic with coefficients (1, -1/4, 0) """ coeffs = reconstruction.binary_quadratic_coefficients_from_invariants(discriminant, *args, **kwargs) - polynomial = sum([coeffs[i]*x**(2-i)*z**i for i in range(3)]) + polynomial = sum([coeffs[i] * x ** (2 - i) * z**i for i in range(3)]) return cls(2, 2, polynomial, *args) @cached_method @@ -1031,8 +1035,7 @@ def prod(a, b): return a * b squares = tuple(prod(x, x) for x in var) - mixed = tuple([prod(var[i], var[j]) for i in range(self._n) - for j in range(i + 1, self._n)]) + mixed = tuple([prod(var[i], var[j]) for i in range(self._n) for j in range(i + 1, self._n)]) return squares + mixed @cached_method @@ -1087,8 +1090,8 @@ def scaled_coeffs(self): (a, b, c, 1/2*d, 1/2*e, 1/2*f) """ coeff = self.coeffs() - squares = coeff[0:self._n] - mixed = tuple( c/2 for c in coeff[self._n:] ) + squares = coeff[0 : self._n] + mixed = tuple(c / 2 for c in coeff[self._n :]) return squares + mixed @cached_method @@ -1122,7 +1125,7 @@ def matrix(self): A[i, i] = coeff[i] ij = self._n for i in range(self._n): - for j in range(i+1, self._n): + for j in range(i + 1, self._n): A[i, j] = coeff[ij] A[j, i] = coeff[ij] ij += 1 @@ -1154,10 +1157,11 @@ def discriminant(self): 4*a*b*c - c*d^2 - b*e^2 + d*e*f - a*f^2 """ from sage.misc.functional import is_odd - A = 2*self._matrix_() + + A = 2 * self._matrix_() if is_odd(self._n): return A.det() / 2 - return (-1)**(self._n//2) * A.det() + return (-1) ** (self._n // 2) * A.det() @cached_method def invariants(self, type='discriminant'): @@ -1185,8 +1189,7 @@ def invariants(self, type='discriminant'): """ if type == 'discriminant': return (self.discriminant(),) - raise ValueError('unknown type of invariants {} for a binary' - ' quadratic'.format(type)) + raise ValueError('unknown type of invariants {} for a binary' ' quadratic'.format(type)) @cached_method def dual(self): @@ -1251,7 +1254,7 @@ def dual(self): if self._homogeneous: var = self._variables else: - var = self._variables[0:-1] + (1, ) + var = self._variables[0:-1] + (1,) n = self._n p = sum(Aadj[i, j] * var[i] * var[j] for i in range(n) for j in range(n)) return invariant_theory.quadratic_form(p, self.variables()) @@ -1286,13 +1289,15 @@ def as_QuadraticForm(self): X^2 + 2*X*Y + Y^2 + 3*X*Z + Z^2 """ R = self._ring - B = 2*self._matrix_() + B = 2 * self._matrix_() import sage.quadratic_forms.quadratic_form + return sage.quadratic_forms.quadratic_form.QuadraticForm(R, B) ###################################################################### + class BinaryQuartic(AlgebraicForm): """ Invariant theory of a binary quartic. @@ -1351,7 +1356,7 @@ def monomials(self): x0 = self._x x1 = self._y if self._homogeneous: - return (x1**4, x1**3*x0, x1**2*x0**2, x1*x0**3, x0**4) + return (x1**4, x1**3 * x0, x1**2 * x0**2, x1 * x0**3, x0**4) return (self._ring.one(), x0, x0**2, x0**3, x0**4) @cached_method @@ -1412,7 +1417,7 @@ def scaled_coeffs(self): (a0, a1, a2, a3, a4) """ coeff = self.coeffs() - return (coeff[0], coeff[1]/4, coeff[2]/6, coeff[3]/4, coeff[4]) + return (coeff[0], coeff[1] / 4, coeff[2] / 6, coeff[3] / 4, coeff[4]) @cached_method def EisensteinD(self): @@ -1439,7 +1444,7 @@ def EisensteinD(self): """ a = self.scaled_coeffs() assert len(a) == 5 - return a[0]*a[4]+3*a[2]**2-4*a[1]*a[3] + return a[0] * a[4] + 3 * a[2] ** 2 - 4 * a[1] * a[3] @cached_method def EisensteinE(self): @@ -1466,7 +1471,7 @@ def EisensteinE(self): """ a = self.scaled_coeffs() assert len(a) == 5 - return a[0]*a[3]**2 + a[1]**2*a[4] - a[0]*a[2]*a[4] - 2*a[1]*a[2]*a[3] + a[2]**3 + return a[0] * a[3] ** 2 + a[1] ** 2 * a[4] - a[0] * a[2] * a[4] - 2 * a[1] * a[2] * a[3] + a[2] ** 3 @cached_method def g_covariant(self): @@ -1511,11 +1516,7 @@ def g_covariant(self): xpow = [x0**4, x0**3 * x1, x0**2 * x1**2, x0 * x1**3, x1**4] else: xpow = [x0**4, x0**3, x0**2, x0, self._ring.one()] - return (a1**2 - a0*a2)*xpow[0] + \ - (2*a1*a2 - 2*a0*a3)*xpow[1] + \ - (3*a2**2 - 2*a1*a3 - a0*a4)*xpow[2] + \ - (2*a2*a3 - 2*a1*a4)*xpow[3] + \ - (a3**2 - a2*a4)*xpow[4] + return (a1**2 - a0 * a2) * xpow[0] + (2 * a1 * a2 - 2 * a0 * a3) * xpow[1] + (3 * a2**2 - 2 * a1 * a3 - a0 * a4) * xpow[2] + (2 * a2 * a3 - 2 * a1 * a4) * xpow[3] + (a3**2 - a2 * a4) * xpow[4] @cached_method def h_covariant(self): @@ -1564,21 +1565,15 @@ def h_covariant(self): x0 = self._x x1 = self._y if self._homogeneous: - xpow = [x0**6, x0**5 * x1, x0**4 * x1**2, x0**3 * x1**3, - x0**2 * x1**4, x0 * x1**5, x1**6] + xpow = [x0**6, x0**5 * x1, x0**4 * x1**2, x0**3 * x1**3, x0**2 * x1**4, x0 * x1**5, x1**6] else: xpow = [x0**6, x0**5, x0**4, x0**3, x0**2, x0, x0.parent().one()] - return (-2*a3**3 + 3*a2*a3*a4 - a1*a4**2) * xpow[0] + \ - (-6*a2*a3**2 + 9*a2**2*a4 - 2*a1*a3*a4 - a0*a4**2) * xpow[1] + \ - 5 * (-2*a1*a3**2 + 3*a1*a2*a4 - a0*a3*a4) * xpow[2] + \ - 10 * (-a0*a3**2 + a1**2*a4) * xpow[3] + \ - 5 * (2*a1**2*a3 - 3*a0*a2*a3 + a0*a1*a4) * xpow[4] + \ - (6*a1**2*a2 - 9*a0*a2**2 + 2*a0*a1*a3 + a0**2*a4) * xpow[5] + \ - (2*a1**3 - 3*a0*a1*a2 + a0**2*a3) * xpow[6] + return (-2 * a3**3 + 3 * a2 * a3 * a4 - a1 * a4**2) * xpow[0] + (-6 * a2 * a3**2 + 9 * a2**2 * a4 - 2 * a1 * a3 * a4 - a0 * a4**2) * xpow[1] + 5 * (-2 * a1 * a3**2 + 3 * a1 * a2 * a4 - a0 * a3 * a4) * xpow[2] + 10 * (-a0 * a3**2 + a1**2 * a4) * xpow[3] + 5 * (2 * a1**2 * a3 - 3 * a0 * a2 * a3 + a0 * a1 * a4) * xpow[4] + (6 * a1**2 * a2 - 9 * a0 * a2**2 + 2 * a0 * a1 * a3 + a0**2 * a4) * xpow[5] + (2 * a1**3 - 3 * a0 * a1 * a2 + a0**2 * a3) * xpow[6] ###################################################################### + class BinaryQuintic(AlgebraicForm): """ Invariant theory of a binary quintic form. @@ -1665,7 +1660,7 @@ def from_invariants(cls, invariants, x, z, *args, **kwargs): Binary quintic with coefficients (0, 1, 0, 0, 1, 0) """ coeffs = reconstruction.binary_quintic_coefficients_from_invariants(invariants, *args, **kwargs) - polynomial = sum([coeffs[i]*x**i*z**(5-i) for i in range(6)]) + polynomial = sum([coeffs[i] * x**i * z ** (5 - i) for i in range(6)]) return cls(2, 5, polynomial, *args) @cached_method @@ -1691,7 +1686,7 @@ def monomials(self): x0 = self._x x1 = self._y if self._homogeneous: - return (x1**5, x1**4*x0, x1**3*x0**2, x1**2*x0**3, x1*x0**4, x0**5) + return (x1**5, x1**4 * x0, x1**3 * x0**2, x1**2 * x0**3, x1 * x0**4, x0**5) return (self._ring.one(), x0, x0**2, x0**3, x0**4, x0**5) @cached_method @@ -1752,8 +1747,7 @@ def scaled_coeffs(self): (a0, a1, a2, a3, a4, a5) """ coeff = self.coeffs() - return (coeff[0], coeff[1] / 5, coeff[2] / 10, coeff[3] / 10, - coeff[4] / 5, coeff[5]) + return (coeff[0], coeff[1] / 5, coeff[2] / 10, coeff[3] / 10, coeff[4] / 5, coeff[5]) @cached_method def H_covariant(self, as_form=False): @@ -2277,8 +2271,7 @@ def invariants(self, type='clebsch'): return self.clebsch_invariants(as_tuple=True) if type == 'arithmetic': return self.arithmetic_invariants(as_tuple=True) - raise ValueError('unknown type of invariants {} for a binary' - ' quintic'.format(type)) + raise ValueError('unknown type of invariants {} for a binary' ' quintic'.format(type)) @cached_method def clebsch_invariants(self, as_tuple=False): @@ -2307,8 +2300,7 @@ def clebsch_invariants(self, as_tuple=False): -148978972828696847376/30517578125) """ if self._ring.characteristic() in [2, 3, 5]: - raise NotImplementedError('no invariants implemented for fields ' - 'of characteristic 2, 3 or 5') + raise NotImplementedError('no invariants implemented for fields ' 'of characteristic 2, 3 or 5') # todo: add support else: invariants = {} @@ -2317,8 +2309,7 @@ def clebsch_invariants(self, as_tuple=False): invariants['C'] = self.C_invariant() invariants['R'] = self.R_invariant() if as_tuple: - return (invariants['A'], invariants['B'], invariants['C'], - invariants['R']) + return (invariants['A'], invariants['B'], invariants['C'], invariants['R']) return invariants @cached_method @@ -2370,12 +2361,10 @@ def arithmetic_invariants(self): R = self._ring clebsch = self.clebsch_invariants() invariants = {} - invariants['I4'] = R(2)**-1*5**4*clebsch['A'] - invariants['I8'] = 5**5 * (R(2)**-1*47*clebsch['A']**2 - - 2**2*clebsch['B']) - invariants['I12'] = 5**10 * (R(2)**-1*3*clebsch['A']**3 - - 2**5*R(3)**-1*clebsch['C']) - invariants['I18'] = 2**8*R(3)**-1*5**15 * clebsch['R'] + invariants['I4'] = R(2) ** -1 * 5**4 * clebsch['A'] + invariants['I8'] = 5**5 * (R(2) ** -1 * 47 * clebsch['A'] ** 2 - 2**2 * clebsch['B']) + invariants['I12'] = 5**10 * (R(2) ** -1 * 3 * clebsch['A'] ** 3 - 2**5 * R(3) ** -1 * clebsch['C']) + invariants['I18'] = 2**8 * R(3) ** -1 * 5**15 * clebsch['R'] return invariants @cached_method @@ -2415,10 +2404,8 @@ def canonical_form(self, reduce_gcd=False): """ clebsch = self.clebsch_invariants(as_tuple=True) if reduce_gcd: - return invariant_theory.binary_form_from_invariants(5, clebsch, - variables=self.variables(), scaling='coprime') - return invariant_theory.binary_form_from_invariants(5, clebsch, - variables=self.variables(), scaling='normalized') + return invariant_theory.binary_form_from_invariants(5, clebsch, variables=self.variables(), scaling='coprime') + return invariant_theory.binary_form_from_invariants(5, clebsch, variables=self.variables(), scaling='normalized') ###################################################################### @@ -2451,13 +2438,7 @@ def _covariant_conic(A_scaled_coeffs, B_scaled_coeffs, monomials): """ a0, b0, c0, h0, g0, f0 = A_scaled_coeffs a1, b1, c1, h1, g1, f1 = B_scaled_coeffs - return ( - (b0*c1+c0*b1-2*f0*f1) * monomials[0] + - (a0*c1+c0*a1-2*g0*g1) * monomials[1] + - (a0*b1+b0*a1-2*h0*h1) * monomials[2] + - 2*(f0*g1+g0*f1 - c0*h1-h0*c1) * monomials[3] + - 2*(h0*f1+f0*h1 - b0*g1-g0*b1) * monomials[4] + - 2*(g0*h1+h0*g1 - a0*f1-f0*a1) * monomials[5] ) + return (b0 * c1 + c0 * b1 - 2 * f0 * f1) * monomials[0] + (a0 * c1 + c0 * a1 - 2 * g0 * g1) * monomials[1] + (a0 * b1 + b0 * a1 - 2 * h0 * h1) * monomials[2] + 2 * (f0 * g1 + g0 * f1 - c0 * h1 - h0 * c1) * monomials[3] + 2 * (h0 * f1 + f0 * h1 - b0 * g1 - g0 * b1) * monomials[4] + 2 * (g0 * h1 + h0 * g1 - a0 * f1 - f0 * a1) * monomials[5] ###################################################################### @@ -2520,8 +2501,8 @@ def monomials(self): R = self._ring x, y, z = self._x, self._y, self._z if self._homogeneous: - return (x**2, y**2, z**2, x*y, x*z, y*z) - return (x**2, y**2, R.one(), x*y, x, y) + return (x**2, y**2, z**2, x * y, x * z, y * z) + return (x**2, y**2, R.one(), x * y, x, y) @cached_method def coeffs(self): @@ -2578,7 +2559,7 @@ def scaled_coeffs(self): """ F = self._ring.base_ring() a200, a020, a002, a110, a101, a011 = self.coeffs() - return (a200, a020, a002, a110/F(2), a101/F(2), a011/F(2)) + return (a200, a020, a002, a110 / F(2), a101 / F(2), a011 / F(2)) def covariant_conic(self, other): """ @@ -2626,12 +2607,12 @@ def covariant_conic(self, other): [ f_*g + f*g_ - c_*h - c*h_ a_*c + a*c_ - 2*g*g_ -a_*f - a*f_ + g_*h + g*h_] [-b_*g - b*g_ + f_*h + f*h_ -a_*f - a*f_ + g_*h + g*h_ a_*b + a*b_ - 2*h*h_] """ - return _covariant_conic(self.scaled_coeffs(), other.scaled_coeffs(), - self.monomials()) + return _covariant_conic(self.scaled_coeffs(), other.scaled_coeffs(), self.monomials()) ###################################################################### + class TernaryCubic(AlgebraicForm): """ Invariant theory of a ternary cubic. @@ -2694,10 +2675,8 @@ def monomials(self): R = self._ring x, y, z = self._x, self._y, self._z if self._homogeneous: - return (x**3, y**3, z**3, x**2*y, x**2*z, x*y**2, - y**2*z, x*z**2, y*z**2, x*y*z) - return (x**3, y**3, R.one(), x**2*y, x**2, x*y**2, - y**2, x, y, x*y) + return (x**3, y**3, z**3, x**2 * y, x**2 * z, x * y**2, y**2 * z, x * z**2, y * z**2, x * y * z) + return (x**3, y**3, R.one(), x**2 * y, x**2, x * y**2, y**2, x, y, x * y) @cached_method def coeffs(self): @@ -2765,10 +2744,7 @@ def scaled_coeffs(self): """ a = self.coeffs() F = self._ring.base_ring() - return (a[0], a[1], a[2], - 1/F(3)*a[3], 1/F(3)*a[4], 1/F(3)*a[5], - 1/F(3)*a[6], 1/F(3)*a[7], 1/F(3)*a[8], - 1/F(6)*a[9]) + return (a[0], a[1], a[2], 1 / F(3) * a[3], 1 / F(3) * a[4], 1 / F(3) * a[5], 1 / F(3) * a[6], 1 / F(3) * a[7], 1 / F(3) * a[8], 1 / F(6) * a[9]) def S_invariant(self): """ @@ -2782,13 +2758,7 @@ def S_invariant(self): -1/1296 """ a, b, c, a2, a3, b1, b3, c1, c2, m = self.scaled_coeffs() - S = (a*b*c*m-(b*c*a2*a3+c*a*b1*b3+a*b*c1*c2) - - m*(a*b3*c2+b*c1*a3+c*a2*b1) - + (a*b1*c2**2+a*c1*b3**2+b*a2*c1**2+b*c2*a3**2+c*b3*a2**2+c*a3*b1**2) - - m**4+2*m**2*(b1*c1+c2*a2+a3*b3) - - 3*m*(a2*b3*c1+a3*b1*c2) - - (b1**2*c1**2+c2**2*a2**2+a3**2*b3**2) - + (c2*a2*a3*b3+a3*b3*b1*c1+b1*c1*c2*a2)) + S = a * b * c * m - (b * c * a2 * a3 + c * a * b1 * b3 + a * b * c1 * c2) - m * (a * b3 * c2 + b * c1 * a3 + c * a2 * b1) + (a * b1 * c2**2 + a * c1 * b3**2 + b * a2 * c1**2 + b * c2 * a3**2 + c * b3 * a2**2 + c * a3 * b1**2) - m**4 + 2 * m**2 * (b1 * c1 + c2 * a2 + a3 * b3) - 3 * m * (a2 * b3 * c1 + a3 * b1 * c2) - (b1**2 * c1**2 + c2**2 * a2**2 + a3**2 * b3**2) + (c2 * a2 * a3 * b3 + a3 * b3 * b1 * c1 + b1 * c1 * c2 * a2) return S def T_invariant(self): @@ -2808,37 +2778,36 @@ def T_invariant(self): -t^6 - t^3 + 1 """ a, b, c, a2, a3, b1, b3, c1, c2, m = self.scaled_coeffs() - T = (a**2*b**2*c**2-6*a*b*c*(a*b3*c2+b*c1*a3+c*a2*b1) - - 20*a*b*c*m**3+12*a*b*c*m*(b1*c1+c2*a2+a3*b3) - + 6*a*b*c*(a2*b3*c1+a3*b1*c2) + - 4*(a**2*b*c2**3+a**2*c*b3**3+b**2*c*a3**3 + - b**2*a*c1**3+c**2*a*b1**3+c**2*b*a2**3) - + 36*m**2*(b*c*a2*a3+c*a*b1*b3+a*b*c1*c2) - - 24*m*(b*c*b1*a3**2+b*c*c1*a2**2+c*a*c2*b1**2+c*a*a2*b3**2+a*b*a3*c2**2 + - a*b*b3*c1**2) - - 3*(a**2*b3**2*c2**2+b**2*c1**2*a3**2+c**2*a2**2*b1**2) + - 18*(b*c*b1*c1*a2*a3+c*a*c2*a2*b3*b1+a*b*a3*b3*c1*c2) - - 12*(b*c*c2*a3*a2**2+b*c*b3*a2*a3**2+c*a*c1*b3*b1**2 + - c*a*a3*b1*b3**2+a*b*a2*c1*c2**2+a*b*b1*c2*c1**2) - - 12*m**3*(a*b3*c2+b*c1*a3+c*a2*b1) - + 12*m**2*(a*b1*c2**2+a*c1*b3**2+b*a2*c1**2 + - b*c2*a3**2+c*b3*a2**2+c*a3*b1**2) - - 60*m*(a*b1*b3*c1*c2+b*c1*c2*a2*a3+c*a2*a3*b1*b3) - + 12*m*(a*a2*b3*c2**2+a*a3*c2*b3**2+b*b3*c1*a3**2 + - b*b1*a3*c1**2+c*c1*a2*b1**2+c*c2*b1*a2**2) - + 6*(a*b3*c2+b*c1*a3+c*a2*b1)*(a2*b3*c1+a3*b1*c2) - + 24*(a*b1*b3**2*c1**2+a*c1*c2**2*b1**2+b*c2*c1**2*a2**2 - + b*a2*a3**2*c2**2+c*a3*a2**2*b3**2+c*b3*b1**2*a3**2) - - 12*(a*a2*b1*c2**3+a*a3*c1*b3**3+b*b3*c2*a3**3+b*b1*a2*c1**3 - + c*c1*a3*b1**3+c*c2*b3*a2**3) - - 8*m**6+24*m**4*(b1*c1+c2*a2+a3*b3)-36*m**3*(a2*b3*c1+a3*b1*c2) - - 12*m**2*(b1*c1*c2*a2+c2*a2*a3*b3+a3*b3*b1*c1) - - 24*m**2*(b1**2*c1**2+c2**2*a2**2+a3**2*b3**2) - + 36*m*(a2*b3*c1+a3*b1*c2)*(b1*c1+c2*a2+a3*b3) - + 8*(b1**3*c1**3+c2**3*a2**3+a3**3*b3**3) - - 27*(a2**2*b3**2*c1**2+a3**2*b1**2*c2**2)-6*b1*c1*c2*a2*a3*b3 - - 12*(b1**2*c1**2*c2*a2+b1**2*c1**2*a3*b3+c2**2*a2**2*a3*b3 + - c2**2*a2**2*b1*c1+a3**2*b3**2*b1*c1+a3**2*b3**2*c2*a2)) + T = ( + a**2 * b**2 * c**2 + - 6 * a * b * c * (a * b3 * c2 + b * c1 * a3 + c * a2 * b1) + - 20 * a * b * c * m**3 + + 12 * a * b * c * m * (b1 * c1 + c2 * a2 + a3 * b3) + + 6 * a * b * c * (a2 * b3 * c1 + a3 * b1 * c2) + + 4 * (a**2 * b * c2**3 + a**2 * c * b3**3 + b**2 * c * a3**3 + b**2 * a * c1**3 + c**2 * a * b1**3 + c**2 * b * a2**3) + + 36 * m**2 * (b * c * a2 * a3 + c * a * b1 * b3 + a * b * c1 * c2) + - 24 * m * (b * c * b1 * a3**2 + b * c * c1 * a2**2 + c * a * c2 * b1**2 + c * a * a2 * b3**2 + a * b * a3 * c2**2 + a * b * b3 * c1**2) + - 3 * (a**2 * b3**2 * c2**2 + b**2 * c1**2 * a3**2 + c**2 * a2**2 * b1**2) + + 18 * (b * c * b1 * c1 * a2 * a3 + c * a * c2 * a2 * b3 * b1 + a * b * a3 * b3 * c1 * c2) + - 12 * (b * c * c2 * a3 * a2**2 + b * c * b3 * a2 * a3**2 + c * a * c1 * b3 * b1**2 + c * a * a3 * b1 * b3**2 + a * b * a2 * c1 * c2**2 + a * b * b1 * c2 * c1**2) + - 12 * m**3 * (a * b3 * c2 + b * c1 * a3 + c * a2 * b1) + + 12 * m**2 * (a * b1 * c2**2 + a * c1 * b3**2 + b * a2 * c1**2 + b * c2 * a3**2 + c * b3 * a2**2 + c * a3 * b1**2) + - 60 * m * (a * b1 * b3 * c1 * c2 + b * c1 * c2 * a2 * a3 + c * a2 * a3 * b1 * b3) + + 12 * m * (a * a2 * b3 * c2**2 + a * a3 * c2 * b3**2 + b * b3 * c1 * a3**2 + b * b1 * a3 * c1**2 + c * c1 * a2 * b1**2 + c * c2 * b1 * a2**2) + + 6 * (a * b3 * c2 + b * c1 * a3 + c * a2 * b1) * (a2 * b3 * c1 + a3 * b1 * c2) + + 24 * (a * b1 * b3**2 * c1**2 + a * c1 * c2**2 * b1**2 + b * c2 * c1**2 * a2**2 + b * a2 * a3**2 * c2**2 + c * a3 * a2**2 * b3**2 + c * b3 * b1**2 * a3**2) + - 12 * (a * a2 * b1 * c2**3 + a * a3 * c1 * b3**3 + b * b3 * c2 * a3**3 + b * b1 * a2 * c1**3 + c * c1 * a3 * b1**3 + c * c2 * b3 * a2**3) + - 8 * m**6 + + 24 * m**4 * (b1 * c1 + c2 * a2 + a3 * b3) + - 36 * m**3 * (a2 * b3 * c1 + a3 * b1 * c2) + - 12 * m**2 * (b1 * c1 * c2 * a2 + c2 * a2 * a3 * b3 + a3 * b3 * b1 * c1) + - 24 * m**2 * (b1**2 * c1**2 + c2**2 * a2**2 + a3**2 * b3**2) + + 36 * m * (a2 * b3 * c1 + a3 * b1 * c2) * (b1 * c1 + c2 * a2 + a3 * b3) + + 8 * (b1**3 * c1**3 + c2**3 * a2**3 + a3**3 * b3**3) + - 27 * (a2**2 * b3**2 * c1**2 + a3**2 * b1**2 * c2**2) + - 6 * b1 * c1 * c2 * a2 * a3 * b3 + - 12 * (b1**2 * c1**2 * c2 * a2 + b1**2 * c1**2 * a3 * b3 + c2**2 * a2**2 * a3 * b3 + c2**2 * a2**2 * b1 * c1 + a3**2 * b3**2 * b1 * c1 + a3**2 * b3**2 * c2 * a2) + ) return T @cached_method @@ -2877,12 +2846,12 @@ def polar_conic(self): else: x, y, z = (self._x, self._y, 1) F = self._ring.base_ring() - A00 = 3*x*a30 + y*a21 + z*a20 - A11 = x*a12 + 3*y*a03 + z*a02 - A22 = x*a10 + y*a01 + 3*z*a00 - A01 = x*a21 + y*a12 + 1/F(2)*z*a11 - A02 = x*a20 + 1/F(2)*y*a11 + z*a10 - A12 = 1/F(2)*x*a11 + y*a02 + z*a01 + A00 = 3 * x * a30 + y * a21 + z * a20 + A11 = x * a12 + 3 * y * a03 + z * a02 + A22 = x * a10 + y * a01 + 3 * z * a00 + A01 = x * a21 + y * a12 + 1 / F(2) * z * a11 + A02 = x * a20 + 1 / F(2) * y * a11 + z * a10 + A12 = 1 / F(2) * x * a11 + y * a02 + z * a01 return matrix(self._ring, [[A00, A01, A02], [A01, A11, A12], [A02, A12, A22]]) @cached_method @@ -2912,17 +2881,15 @@ def Hessian(self): x, y, z = self.variables() else: x, y, z = self._x, self._y, 1 - Uxx = 6*x*a30 + 2*y*a21 + 2*z*a20 - Uxy = 2*x*a21 + 2*y*a12 + z*a11 - Uxz = 2*x*a20 + y*a11 + 2*z*a10 - Uyy = 2*x*a12 + 6*y*a03 + 2*z*a02 - Uyz = x*a11 + 2*y*a02 + 2*z*a01 - Uzz = 2*x*a10 + 2*y*a01 + 6*z*a00 - H = matrix(self._ring, [[Uxx, Uxy, Uxz], - [Uxy, Uyy, Uyz], - [Uxz, Uyz, Uzz]]) + Uxx = 6 * x * a30 + 2 * y * a21 + 2 * z * a20 + Uxy = 2 * x * a21 + 2 * y * a12 + z * a11 + Uxz = 2 * x * a20 + y * a11 + 2 * z * a10 + Uyy = 2 * x * a12 + 6 * y * a03 + 2 * z * a02 + Uyz = x * a11 + 2 * y * a02 + 2 * z * a01 + Uzz = 2 * x * a10 + 2 * y * a01 + 6 * z * a00 + H = matrix(self._ring, [[Uxx, Uxy, Uxz], [Uxy, Uyy, Uyz], [Uxz, Uyz, Uzz]]) F = self._ring.base_ring() - return 1/F(216) * H.det() + return 1 / F(216) * H.det() def Theta_covariant(self): r""" @@ -2948,14 +2915,12 @@ def Theta_covariant(self): 6952 """ U_conic = self.polar_conic().adjugate() - U_coeffs = (U_conic[0, 0], U_conic[1, 1], U_conic[2, 2], - U_conic[0, 1], U_conic[0, 2], U_conic[1, 2]) + U_coeffs = (U_conic[0, 0], U_conic[1, 1], U_conic[2, 2], U_conic[0, 1], U_conic[0, 2], U_conic[1, 2]) H_conic = TernaryCubic(3, 3, self.Hessian(), self.variables()).polar_conic().adjugate() - H_coeffs = (H_conic[0, 0], H_conic[1, 1], H_conic[2, 2], - H_conic[0, 1], H_conic[0, 2], H_conic[1, 2]) + H_coeffs = (H_conic[0, 0], H_conic[1, 1], H_conic[2, 2], H_conic[0, 1], H_conic[0, 2], H_conic[1, 2]) quadratic = TernaryQuadratic(3, 2, self._ring.zero(), self.variables()) F = self._ring.base_ring() - return 1/F(9) * _covariant_conic(U_coeffs, H_coeffs, quadratic.monomials()) + return 1 / F(9) * _covariant_conic(U_coeffs, H_coeffs, quadratic.monomials()) def J_covariant(self): """ @@ -2974,10 +2939,7 @@ def J_covariant(self): x^6*y^3 - x^3*y^6 - x^6 + y^6 + x^3 - y^3 """ F = self._ring.base_ring() - return 1 / F(9) * self._jacobian_determinant( - [self.form(), 3], - [self.Hessian(), 3], - [self.Theta_covariant(), 6]) + return 1 / F(9) * self._jacobian_determinant([self.form(), 3], [self.Hessian(), 3], [self.Theta_covariant(), 6]) def syzygy(self, U, S, T, H, Theta, J): r""" @@ -3011,15 +2973,12 @@ def syzygy(self, U, S, T, H, Theta, J): sage: cubic.syzygy(U, S, T, H, Theta, J) 0 """ - return ( -J**2 + 4*Theta**3 + T*U**2*Theta**2 + - Theta*(-4*S**3*U**4 + 2*S*T*U**3*H - 72*S**2*U**2*H**2 - - 18*T*U*H**3 + 108*S*H**4) - - 16*S**4*U**5*H - 11*S**2*T*U**4*H**2 - 4*T**2*U**3*H**3 - + 54*S*T*U**2*H**4 - 432*S**2*U*H**5 - 27*T*H**6 ) + return -(J**2) + 4 * Theta**3 + T * U**2 * Theta**2 + Theta * (-4 * S**3 * U**4 + 2 * S * T * U**3 * H - 72 * S**2 * U**2 * H**2 - 18 * T * U * H**3 + 108 * S * H**4) - 16 * S**4 * U**5 * H - 11 * S**2 * T * U**4 * H**2 - 4 * T**2 * U**3 * H**3 + 54 * S * T * U**2 * H**4 - 432 * S**2 * U * H**5 - 27 * T * H**6 ###################################################################### + class SeveralAlgebraicForms(FormsBase): """ The base class of multiple algebraic forms (i.e. homogeneous polynomials). @@ -3115,10 +3074,9 @@ def _repr_(self): if self.n_forms() == 1: return self.get_form(0)._repr_() if self.n_forms() == 2: - return 'Joint ' + self.get_form(0)._repr_().lower() + \ - ' and ' + self.get_form(1)._repr_().lower() + return 'Joint ' + self.get_form(0)._repr_().lower() + ' and ' + self.get_form(1)._repr_().lower() s = 'Joint ' - for i in range(self.n_forms()-1): + for i in range(self.n_forms() - 1): s += self.get_form(i)._repr_().lower() + ', ' s += 'and ' + self.get_form(-1)._repr_().lower() return s @@ -3230,11 +3188,12 @@ def _check_covariant(self, method_name, g=None, invariant=False): """ assert self._homogeneous from sage.matrix.constructor import vector, random_matrix + if g is None: F = self._ring.base_ring() g = random_matrix(F, self._n, algorithm='unimodular') v = vector(self.variables()) - g_v = g*v + g_v = g * v transform = {v[i]: g_v[i] for i in range(self._n)} # The covariant of the transformed form transformed = [f.transformed(transform) for f in self._forms] @@ -3251,6 +3210,7 @@ def _check_covariant(self, method_name, g=None, invariant=False): ###################################################################### + class TwoAlgebraicForms(SeveralAlgebraicForms): def first(self): @@ -3300,6 +3260,7 @@ def second(self): ###################################################################### + class TwoTernaryQuadratics(TwoAlgebraicForms): """ Invariant theory of two ternary quadratics. @@ -3382,9 +3343,7 @@ def _Theta_helper(self, scaled_coeffs_1, scaled_coeffs_2): """ a00, a11, a22, a01, a02, a12 = scaled_coeffs_1 b00, b11, b22, b01, b02, b12 = scaled_coeffs_2 - return -a12**2*b00 + a11*a22*b00 + 2*a02*a12*b01 - 2*a01*a22*b01 - \ - a02**2*b11 + a00*a22*b11 - 2*a11*a02*b02 + 2*a01*a12*b02 + \ - 2*a01*a02*b12 - 2*a00*a12*b12 - a01**2*b22 + a00*a11*b22 + return -(a12**2) * b00 + a11 * a22 * b00 + 2 * a02 * a12 * b01 - 2 * a01 * a22 * b01 - a02**2 * b11 + a00 * a22 * b11 - 2 * a11 * a02 * b02 + 2 * a01 * a12 * b02 + 2 * a01 * a02 * b12 - 2 * a00 * a12 * b12 - a01**2 * b22 + a00 * a11 * b22 def Theta_invariant(self): r""" @@ -3451,10 +3410,7 @@ def J_covariant(self): 984553030871*y^3 + 543715345505/2*x^2 - 3065093506021/2*x*y + 755263948570*y^2 - 1118430692650*x - 509948695327/4*y + 3369951531745/8 """ - return self._jacobian_determinant( - (self.first().polynomial(), 2), - (self.second().polynomial(), 2), - (self.F_covariant(), 2)) + return self._jacobian_determinant((self.first().polynomial(), 2), (self.second().polynomial(), 2), (self.F_covariant(), 2)) def syzygy(self, Delta, Theta, Theta_prime, Delta_prime, S, S_prime, F, J): """ @@ -3496,24 +3452,12 @@ def syzygy(self, Delta, Theta, Theta_prime, Delta_prime, S, S_prime, F, J): 1/64*x^2 + 1 """ R = self._ring.base_ring() - return (J**2 / R(64) - + F**3 - - 2 * F**2 * Theta*S_prime - - 2 * F**2 * Theta_prime*S - + F * S**2 * (Delta_prime * Theta + Theta_prime**2) - + F * S_prime**2 * (Delta * Theta_prime + Theta**2) - + 3 * F * S * S_prime * (Theta*Theta_prime - Delta*Delta_prime) - + S**3 * (Delta_prime**2 * Delta - Theta * Theta_prime * Delta_prime) - + S_prime**3 * (Delta**2 * Delta_prime - Theta_prime * Theta * Delta) - + S**2 * S_prime * ( - Delta_prime * Delta * Theta_prime - Theta * Theta_prime**2) - + S * S_prime**2 * ( - Delta * Delta_prime * Theta - Theta_prime * Theta**2) - ) + return J**2 / R(64) + F**3 - 2 * F**2 * Theta * S_prime - 2 * F**2 * Theta_prime * S + F * S**2 * (Delta_prime * Theta + Theta_prime**2) + F * S_prime**2 * (Delta * Theta_prime + Theta**2) + 3 * F * S * S_prime * (Theta * Theta_prime - Delta * Delta_prime) + S**3 * (Delta_prime**2 * Delta - Theta * Theta_prime * Delta_prime) + S_prime**3 * (Delta**2 * Delta_prime - Theta_prime * Theta * Delta) + S**2 * S_prime * (Delta_prime * Delta * Theta_prime - Theta * Theta_prime**2) + S * S_prime**2 * (Delta * Delta_prime * Theta - Theta_prime * Theta**2) ###################################################################### + class TwoQuaternaryQuadratics(TwoAlgebraicForms): """ Invariant theory of two quaternary quadratics. @@ -3601,19 +3545,64 @@ def _Theta_helper(self, scaled_coeffs_1, scaled_coeffs_2): """ a0, a1, a2, a3, b0, b1, b2, b3, b4, b5 = scaled_coeffs_1 A0, A1, A2, A3, B0, B1, B2, B3, B4, B5 = scaled_coeffs_2 - return a1*a2*a3*A0 - a3*b3**2*A0 - a2*b4**2*A0 + 2*b3*b4*b5*A0 - a1*b5**2*A0 \ - + a0*a2*a3*A1 - a3*b1**2*A1 - a2*b2**2*A1 + 2*b1*b2*b5*A1 - a0*b5**2*A1 \ - + a0*a1*a3*A2 - a3*b0**2*A2 - a1*b2**2*A2 + 2*b0*b2*b4*A2 - a0*b4**2*A2 \ - + a0*a1*a2*A3 - a2*b0**2*A3 - a1*b1**2*A3 + 2*b0*b1*b3*A3 - a0*b3**2*A3 \ - - 2*a2*a3*b0*B0 + 2*a3*b1*b3*B0 + 2*a2*b2*b4*B0 - 2*b2*b3*b5*B0 \ - - 2*b1*b4*b5*B0 + 2*b0*b5**2*B0 - 2*a1*a3*b1*B1 + 2*a3*b0*b3*B1 \ - - 2*b2*b3*b4*B1 + 2*b1*b4**2*B1 + 2*a1*b2*b5*B1 - 2*b0*b4*b5*B1 \ - - 2*a1*a2*b2*B2 + 2*b2*b3**2*B2 + 2*a2*b0*b4*B2 - 2*b1*b3*b4*B2 \ - + 2*a1*b1*b5*B2 - 2*b0*b3*b5*B2 + 2*a3*b0*b1*B3 - 2*a0*a3*b3*B3 \ - + 2*b2**2*b3*B3 - 2*b1*b2*b4*B3 - 2*b0*b2*b5*B3 + 2*a0*b4*b5*B3 \ - + 2*a2*b0*b2*B4 - 2*b1*b2*b3*B4 - 2*a0*a2*b4*B4 + 2*b1**2*b4*B4 \ - - 2*b0*b1*b5*B4 + 2*a0*b3*b5*B4 + 2*a1*b1*b2*B5 - 2*b0*b2*b3*B5 \ - - 2*b0*b1*b4*B5 + 2*a0*b3*b4*B5 - 2*a0*a1*b5*B5 + 2*b0**2*b5*B5 + return ( + a1 * a2 * a3 * A0 + - a3 * b3**2 * A0 + - a2 * b4**2 * A0 + + 2 * b3 * b4 * b5 * A0 + - a1 * b5**2 * A0 + + a0 * a2 * a3 * A1 + - a3 * b1**2 * A1 + - a2 * b2**2 * A1 + + 2 * b1 * b2 * b5 * A1 + - a0 * b5**2 * A1 + + a0 * a1 * a3 * A2 + - a3 * b0**2 * A2 + - a1 * b2**2 * A2 + + 2 * b0 * b2 * b4 * A2 + - a0 * b4**2 * A2 + + a0 * a1 * a2 * A3 + - a2 * b0**2 * A3 + - a1 * b1**2 * A3 + + 2 * b0 * b1 * b3 * A3 + - a0 * b3**2 * A3 + - 2 * a2 * a3 * b0 * B0 + + 2 * a3 * b1 * b3 * B0 + + 2 * a2 * b2 * b4 * B0 + - 2 * b2 * b3 * b5 * B0 + - 2 * b1 * b4 * b5 * B0 + + 2 * b0 * b5**2 * B0 + - 2 * a1 * a3 * b1 * B1 + + 2 * a3 * b0 * b3 * B1 + - 2 * b2 * b3 * b4 * B1 + + 2 * b1 * b4**2 * B1 + + 2 * a1 * b2 * b5 * B1 + - 2 * b0 * b4 * b5 * B1 + - 2 * a1 * a2 * b2 * B2 + + 2 * b2 * b3**2 * B2 + + 2 * a2 * b0 * b4 * B2 + - 2 * b1 * b3 * b4 * B2 + + 2 * a1 * b1 * b5 * B2 + - 2 * b0 * b3 * b5 * B2 + + 2 * a3 * b0 * b1 * B3 + - 2 * a0 * a3 * b3 * B3 + + 2 * b2**2 * b3 * B3 + - 2 * b1 * b2 * b4 * B3 + - 2 * b0 * b2 * b5 * B3 + + 2 * a0 * b4 * b5 * B3 + + 2 * a2 * b0 * b2 * B4 + - 2 * b1 * b2 * b3 * B4 + - 2 * a0 * a2 * b4 * B4 + + 2 * b1**2 * b4 * B4 + - 2 * b0 * b1 * b5 * B4 + + 2 * a0 * b3 * b5 * B4 + + 2 * a1 * b1 * b2 * B5 + - 2 * b0 * b2 * b3 * B5 + - 2 * b0 * b1 * b4 * B5 + + 2 * a0 * b3 * b4 * B5 + - 2 * a0 * a1 * b5 * B5 + + 2 * b0**2 * b5 * B5 + ) def Theta_invariant(self): r""" @@ -3669,24 +3658,89 @@ def Phi_invariant(self): """ a0, a1, a2, a3, b0, b1, b2, b3, b4, b5 = self.get_form(0).scaled_coeffs() A0, A1, A2, A3, B0, B1, B2, B3, B4, B5 = self.get_form(1).scaled_coeffs() - return a2*a3*A0*A1 - b5**2*A0*A1 + a1*a3*A0*A2 - b4**2*A0*A2 + a0*a3*A1*A2 \ - - b2**2*A1*A2 + a1*a2*A0*A3 - b3**2*A0*A3 + a0*a2*A1*A3 - b1**2*A1*A3 \ - + a0*a1*A2*A3 - b0**2*A2*A3 - 2*a3*b0*A2*B0 + 2*b2*b4*A2*B0 - 2*a2*b0*A3*B0 \ - + 2*b1*b3*A3*B0 - a2*a3*B0**2 + b5**2*B0**2 - 2*a3*b1*A1*B1 + 2*b2*b5*A1*B1 \ - - 2*a1*b1*A3*B1 + 2*b0*b3*A3*B1 + 2*a3*b3*B0*B1 - 2*b4*b5*B0*B1 - a1*a3*B1**2 \ - + b4**2*B1**2 - 2*a2*b2*A1*B2 + 2*b1*b5*A1*B2 - 2*a1*b2*A2*B2 + 2*b0*b4*A2*B2 \ - + 2*a2*b4*B0*B2 - 2*b3*b5*B0*B2 - 2*b3*b4*B1*B2 + 2*a1*b5*B1*B2 - a1*a2*B2**2 \ - + b3**2*B2**2 - 2*a3*b3*A0*B3 + 2*b4*b5*A0*B3 + 2*b0*b1*A3*B3 - 2*a0*b3*A3*B3 \ - + 2*a3*b1*B0*B3 - 2*b2*b5*B0*B3 + 2*a3*b0*B1*B3 - 2*b2*b4*B1*B3 \ - + 4*b2*b3*B2*B3 - 2*b1*b4*B2*B3 - 2*b0*b5*B2*B3 - a0*a3*B3**2 + b2**2*B3**2 \ - - 2*a2*b4*A0*B4 + 2*b3*b5*A0*B4 + 2*b0*b2*A2*B4 - 2*a0*b4*A2*B4 \ - + 2*a2*b2*B0*B4 - 2*b1*b5*B0*B4 - 2*b2*b3*B1*B4 + 4*b1*b4*B1*B4 \ - - 2*b0*b5*B1*B4 + 2*a2*b0*B2*B4 - 2*b1*b3*B2*B4 - 2*b1*b2*B3*B4 \ - + 2*a0*b5*B3*B4 - a0*a2*B4**2 + b1**2*B4**2 + 2*b3*b4*A0*B5 - 2*a1*b5*A0*B5 \ - + 2*b1*b2*A1*B5 - 2*a0*b5*A1*B5 - 2*b2*b3*B0*B5 - 2*b1*b4*B0*B5 \ - + 4*b0*b5*B0*B5 + 2*a1*b2*B1*B5 - 2*b0*b4*B1*B5 + 2*a1*b1*B2*B5 \ - - 2*b0*b3*B2*B5 - 2*b0*b2*B3*B5 + 2*a0*b4*B3*B5 - 2*b0*b1*B4*B5 \ - + 2*a0*b3*B4*B5 - a0*a1*B5**2 + b0**2*B5**2 + return ( + a2 * a3 * A0 * A1 + - b5**2 * A0 * A1 + + a1 * a3 * A0 * A2 + - b4**2 * A0 * A2 + + a0 * a3 * A1 * A2 + - b2**2 * A1 * A2 + + a1 * a2 * A0 * A3 + - b3**2 * A0 * A3 + + a0 * a2 * A1 * A3 + - b1**2 * A1 * A3 + + a0 * a1 * A2 * A3 + - b0**2 * A2 * A3 + - 2 * a3 * b0 * A2 * B0 + + 2 * b2 * b4 * A2 * B0 + - 2 * a2 * b0 * A3 * B0 + + 2 * b1 * b3 * A3 * B0 + - a2 * a3 * B0**2 + + b5**2 * B0**2 + - 2 * a3 * b1 * A1 * B1 + + 2 * b2 * b5 * A1 * B1 + - 2 * a1 * b1 * A3 * B1 + + 2 * b0 * b3 * A3 * B1 + + 2 * a3 * b3 * B0 * B1 + - 2 * b4 * b5 * B0 * B1 + - a1 * a3 * B1**2 + + b4**2 * B1**2 + - 2 * a2 * b2 * A1 * B2 + + 2 * b1 * b5 * A1 * B2 + - 2 * a1 * b2 * A2 * B2 + + 2 * b0 * b4 * A2 * B2 + + 2 * a2 * b4 * B0 * B2 + - 2 * b3 * b5 * B0 * B2 + - 2 * b3 * b4 * B1 * B2 + + 2 * a1 * b5 * B1 * B2 + - a1 * a2 * B2**2 + + b3**2 * B2**2 + - 2 * a3 * b3 * A0 * B3 + + 2 * b4 * b5 * A0 * B3 + + 2 * b0 * b1 * A3 * B3 + - 2 * a0 * b3 * A3 * B3 + + 2 * a3 * b1 * B0 * B3 + - 2 * b2 * b5 * B0 * B3 + + 2 * a3 * b0 * B1 * B3 + - 2 * b2 * b4 * B1 * B3 + + 4 * b2 * b3 * B2 * B3 + - 2 * b1 * b4 * B2 * B3 + - 2 * b0 * b5 * B2 * B3 + - a0 * a3 * B3**2 + + b2**2 * B3**2 + - 2 * a2 * b4 * A0 * B4 + + 2 * b3 * b5 * A0 * B4 + + 2 * b0 * b2 * A2 * B4 + - 2 * a0 * b4 * A2 * B4 + + 2 * a2 * b2 * B0 * B4 + - 2 * b1 * b5 * B0 * B4 + - 2 * b2 * b3 * B1 * B4 + + 4 * b1 * b4 * B1 * B4 + - 2 * b0 * b5 * B1 * B4 + + 2 * a2 * b0 * B2 * B4 + - 2 * b1 * b3 * B2 * B4 + - 2 * b1 * b2 * B3 * B4 + + 2 * a0 * b5 * B3 * B4 + - a0 * a2 * B4**2 + + b1**2 * B4**2 + + 2 * b3 * b4 * A0 * B5 + - 2 * a1 * b5 * A0 * B5 + + 2 * b1 * b2 * A1 * B5 + - 2 * a0 * b5 * A1 * B5 + - 2 * b2 * b3 * B0 * B5 + - 2 * b1 * b4 * B0 * B5 + + 4 * b0 * b5 * B0 * B5 + + 2 * a1 * b2 * B1 * B5 + - 2 * b0 * b4 * B1 * B5 + + 2 * a1 * b1 * B2 * B5 + - 2 * b0 * b3 * B2 * B5 + - 2 * b0 * b2 * B3 * B5 + + 2 * a0 * b4 * B3 * B5 + - 2 * b0 * b1 * B4 * B5 + + 2 * a0 * b3 * B4 * B5 + - a0 * a1 * B5**2 + + b0**2 * B5**2 + ) def _T_helper(self, scaled_coeffs_1, scaled_coeffs_2): """ @@ -3707,50 +3761,176 @@ def _T_helper(self, scaled_coeffs_1, scaled_coeffs_2): # flip: a0<->a1, b1<->b3, b2<->b4 def T00(a0, a1, a2, a3, b0, b1, b2, b3, b4, b5, A0, A1, A2, A3, B0, B1, B2, B3, B4, B5): - return a0*a3*A0*A1*A2 - b2**2*A0*A1*A2 + a0*a2*A0*A1*A3 - b1**2*A0*A1*A3 \ - + a0*a1*A0*A2*A3 - b0**2*A0*A2*A3 - a0*a3*A2*B0**2 + b2**2*A2*B0**2 \ - - a0*a2*A3*B0**2 + b1**2*A3*B0**2 - 2*b0*b1*A3*B0*B1 + 2*a0*b3*A3*B0*B1 \ - - a0*a3*A1*B1**2 + b2**2*A1*B1**2 - a0*a1*A3*B1**2 + b0**2*A3*B1**2 \ - - 2*b0*b2*A2*B0*B2 + 2*a0*b4*A2*B0*B2 - 2*b1*b2*A1*B1*B2 + 2*a0*b5*A1*B1*B2 \ - - a0*a2*A1*B2**2 + b1**2*A1*B2**2 - a0*a1*A2*B2**2 + b0**2*A2*B2**2 \ - + 2*b0*b1*A0*A3*B3 - 2*a0*b3*A0*A3*B3 + 2*a0*a3*B0*B1*B3 - 2*b2**2*B0*B1*B3 \ - + 2*b1*b2*B0*B2*B3 - 2*a0*b5*B0*B2*B3 + 2*b0*b2*B1*B2*B3 - 2*a0*b4*B1*B2*B3 \ - - 2*b0*b1*B2**2*B3 + 2*a0*b3*B2**2*B3 - a0*a3*A0*B3**2 + b2**2*A0*B3**2 \ - + 2*b0*b2*A0*A2*B4 - 2*a0*b4*A0*A2*B4 + 2*b1*b2*B0*B1*B4 - 2*a0*b5*B0*B1*B4 \ - - 2*b0*b2*B1**2*B4 + 2*a0*b4*B1**2*B4 + 2*a0*a2*B0*B2*B4 - 2*b1**2*B0*B2*B4 \ - + 2*b0*b1*B1*B2*B4 - 2*a0*b3*B1*B2*B4 - 2*b1*b2*A0*B3*B4 + 2*a0*b5*A0*B3*B4 \ - - a0*a2*A0*B4**2 + b1**2*A0*B4**2 + 2*b1*b2*A0*A1*B5 - 2*a0*b5*A0*A1*B5 \ - - 2*b1*b2*B0**2*B5 + 2*a0*b5*B0**2*B5 + 2*b0*b2*B0*B1*B5 - 2*a0*b4*B0*B1*B5 \ - + 2*b0*b1*B0*B2*B5 - 2*a0*b3*B0*B2*B5 + 2*a0*a1*B1*B2*B5 - 2*b0**2*B1*B2*B5 \ - - 2*b0*b2*A0*B3*B5 + 2*a0*b4*A0*B3*B5 - 2*b0*b1*A0*B4*B5 + 2*a0*b3*A0*B4*B5 \ - - a0*a1*A0*B5**2 + b0**2*A0*B5**2 + return ( + a0 * a3 * A0 * A1 * A2 + - b2**2 * A0 * A1 * A2 + + a0 * a2 * A0 * A1 * A3 + - b1**2 * A0 * A1 * A3 + + a0 * a1 * A0 * A2 * A3 + - b0**2 * A0 * A2 * A3 + - a0 * a3 * A2 * B0**2 + + b2**2 * A2 * B0**2 + - a0 * a2 * A3 * B0**2 + + b1**2 * A3 * B0**2 + - 2 * b0 * b1 * A3 * B0 * B1 + + 2 * a0 * b3 * A3 * B0 * B1 + - a0 * a3 * A1 * B1**2 + + b2**2 * A1 * B1**2 + - a0 * a1 * A3 * B1**2 + + b0**2 * A3 * B1**2 + - 2 * b0 * b2 * A2 * B0 * B2 + + 2 * a0 * b4 * A2 * B0 * B2 + - 2 * b1 * b2 * A1 * B1 * B2 + + 2 * a0 * b5 * A1 * B1 * B2 + - a0 * a2 * A1 * B2**2 + + b1**2 * A1 * B2**2 + - a0 * a1 * A2 * B2**2 + + b0**2 * A2 * B2**2 + + 2 * b0 * b1 * A0 * A3 * B3 + - 2 * a0 * b3 * A0 * A3 * B3 + + 2 * a0 * a3 * B0 * B1 * B3 + - 2 * b2**2 * B0 * B1 * B3 + + 2 * b1 * b2 * B0 * B2 * B3 + - 2 * a0 * b5 * B0 * B2 * B3 + + 2 * b0 * b2 * B1 * B2 * B3 + - 2 * a0 * b4 * B1 * B2 * B3 + - 2 * b0 * b1 * B2**2 * B3 + + 2 * a0 * b3 * B2**2 * B3 + - a0 * a3 * A0 * B3**2 + + b2**2 * A0 * B3**2 + + 2 * b0 * b2 * A0 * A2 * B4 + - 2 * a0 * b4 * A0 * A2 * B4 + + 2 * b1 * b2 * B0 * B1 * B4 + - 2 * a0 * b5 * B0 * B1 * B4 + - 2 * b0 * b2 * B1**2 * B4 + + 2 * a0 * b4 * B1**2 * B4 + + 2 * a0 * a2 * B0 * B2 * B4 + - 2 * b1**2 * B0 * B2 * B4 + + 2 * b0 * b1 * B1 * B2 * B4 + - 2 * a0 * b3 * B1 * B2 * B4 + - 2 * b1 * b2 * A0 * B3 * B4 + + 2 * a0 * b5 * A0 * B3 * B4 + - a0 * a2 * A0 * B4**2 + + b1**2 * A0 * B4**2 + + 2 * b1 * b2 * A0 * A1 * B5 + - 2 * a0 * b5 * A0 * A1 * B5 + - 2 * b1 * b2 * B0**2 * B5 + + 2 * a0 * b5 * B0**2 * B5 + + 2 * b0 * b2 * B0 * B1 * B5 + - 2 * a0 * b4 * B0 * B1 * B5 + + 2 * b0 * b1 * B0 * B2 * B5 + - 2 * a0 * b3 * B0 * B2 * B5 + + 2 * a0 * a1 * B1 * B2 * B5 + - 2 * b0**2 * B1 * B2 * B5 + - 2 * b0 * b2 * A0 * B3 * B5 + + 2 * a0 * b4 * A0 * B3 * B5 + - 2 * b0 * b1 * A0 * B4 * B5 + + 2 * a0 * b3 * A0 * B4 * B5 + - a0 * a1 * A0 * B5**2 + + b0**2 * A0 * B5**2 + ) def T01(a0, a1, a2, a3, b0, b1, b2, b3, b4, b5, A0, A1, A2, A3, B0, B1, B2, B3, B4, B5): - return a3*b0*A0*A1*A2 - b2*b4*A0*A1*A2 + a2*b0*A0*A1*A3 - b1*b3*A0*A1*A3 \ - + a0*a1*A2*A3*B0 - b0**2*A2*A3*B0 - a3*b0*A2*B0**2 + b2*b4*A2*B0**2 \ - - a2*b0*A3*B0**2 + b1*b3*A3*B0**2 - b0*b1*A1*A3*B1 + a0*b3*A1*A3*B1 \ - - a1*b1*A3*B0*B1 + b0*b3*A3*B0*B1 - a3*b0*A1*B1**2 + b2*b4*A1*B1**2 \ - - b0*b2*A1*A2*B2 + a0*b4*A1*A2*B2 - a1*b2*A2*B0*B2 + b0*b4*A2*B0*B2 \ - - b2*b3*A1*B1*B2 - b1*b4*A1*B1*B2 + 2*b0*b5*A1*B1*B2 - a2*b0*A1*B2**2 \ - + b1*b3*A1*B2**2 + a1*b1*A0*A3*B3 - b0*b3*A0*A3*B3 + b0*b1*A3*B0*B3 \ - - a0*b3*A3*B0*B3 - a0*a1*A3*B1*B3 + b0**2*A3*B1*B3 + 2*a3*b0*B0*B1*B3 \ - - 2*b2*b4*B0*B1*B3 + b2*b3*B0*B2*B3 + b1*b4*B0*B2*B3 - 2*b0*b5*B0*B2*B3 \ - + a1*b2*B1*B2*B3 - b0*b4*B1*B2*B3 - a1*b1*B2**2*B3 + b0*b3*B2**2*B3 \ - - a3*b0*A0*B3**2 + b2*b4*A0*B3**2 + b0*b2*B2*B3**2 - a0*b4*B2*B3**2 \ - + a1*b2*A0*A2*B4 - b0*b4*A0*A2*B4 + b0*b2*A2*B0*B4 - a0*b4*A2*B0*B4 \ - + b2*b3*B0*B1*B4 + b1*b4*B0*B1*B4 - 2*b0*b5*B0*B1*B4 - a1*b2*B1**2*B4 \ - + b0*b4*B1**2*B4 - a0*a1*A2*B2*B4 + b0**2*A2*B2*B4 + 2*a2*b0*B0*B2*B4 \ - - 2*b1*b3*B0*B2*B4 + a1*b1*B1*B2*B4 - b0*b3*B1*B2*B4 - b2*b3*A0*B3*B4 \ - - b1*b4*A0*B3*B4 + 2*b0*b5*A0*B3*B4 - b0*b2*B1*B3*B4 + a0*b4*B1*B3*B4 \ - - b0*b1*B2*B3*B4 + a0*b3*B2*B3*B4 - a2*b0*A0*B4**2 + b1*b3*A0*B4**2 \ - + b0*b1*B1*B4**2 - a0*b3*B1*B4**2 + b2*b3*A0*A1*B5 + b1*b4*A0*A1*B5 \ - - 2*b0*b5*A0*A1*B5 - b2*b3*B0**2*B5 - b1*b4*B0**2*B5 + 2*b0*b5*B0**2*B5 \ - + b0*b2*A1*B1*B5 - a0*b4*A1*B1*B5 + a1*b2*B0*B1*B5 - b0*b4*B0*B1*B5 \ - + b0*b1*A1*B2*B5 - a0*b3*A1*B2*B5 + a1*b1*B0*B2*B5 - b0*b3*B0*B2*B5 \ - - a1*b2*A0*B3*B5 + b0*b4*A0*B3*B5 - b0*b2*B0*B3*B5 + a0*b4*B0*B3*B5 \ - + a0*a1*B2*B3*B5 - b0**2*B2*B3*B5 - a1*b1*A0*B4*B5 + b0*b3*A0*B4*B5 \ - - b0*b1*B0*B4*B5 + a0*b3*B0*B4*B5 + a0*a1*B1*B4*B5 - b0**2*B1*B4*B5 \ - - a0*a1*B0*B5**2 + b0**2*B0*B5**2 + return ( + a3 * b0 * A0 * A1 * A2 + - b2 * b4 * A0 * A1 * A2 + + a2 * b0 * A0 * A1 * A3 + - b1 * b3 * A0 * A1 * A3 + + a0 * a1 * A2 * A3 * B0 + - b0**2 * A2 * A3 * B0 + - a3 * b0 * A2 * B0**2 + + b2 * b4 * A2 * B0**2 + - a2 * b0 * A3 * B0**2 + + b1 * b3 * A3 * B0**2 + - b0 * b1 * A1 * A3 * B1 + + a0 * b3 * A1 * A3 * B1 + - a1 * b1 * A3 * B0 * B1 + + b0 * b3 * A3 * B0 * B1 + - a3 * b0 * A1 * B1**2 + + b2 * b4 * A1 * B1**2 + - b0 * b2 * A1 * A2 * B2 + + a0 * b4 * A1 * A2 * B2 + - a1 * b2 * A2 * B0 * B2 + + b0 * b4 * A2 * B0 * B2 + - b2 * b3 * A1 * B1 * B2 + - b1 * b4 * A1 * B1 * B2 + + 2 * b0 * b5 * A1 * B1 * B2 + - a2 * b0 * A1 * B2**2 + + b1 * b3 * A1 * B2**2 + + a1 * b1 * A0 * A3 * B3 + - b0 * b3 * A0 * A3 * B3 + + b0 * b1 * A3 * B0 * B3 + - a0 * b3 * A3 * B0 * B3 + - a0 * a1 * A3 * B1 * B3 + + b0**2 * A3 * B1 * B3 + + 2 * a3 * b0 * B0 * B1 * B3 + - 2 * b2 * b4 * B0 * B1 * B3 + + b2 * b3 * B0 * B2 * B3 + + b1 * b4 * B0 * B2 * B3 + - 2 * b0 * b5 * B0 * B2 * B3 + + a1 * b2 * B1 * B2 * B3 + - b0 * b4 * B1 * B2 * B3 + - a1 * b1 * B2**2 * B3 + + b0 * b3 * B2**2 * B3 + - a3 * b0 * A0 * B3**2 + + b2 * b4 * A0 * B3**2 + + b0 * b2 * B2 * B3**2 + - a0 * b4 * B2 * B3**2 + + a1 * b2 * A0 * A2 * B4 + - b0 * b4 * A0 * A2 * B4 + + b0 * b2 * A2 * B0 * B4 + - a0 * b4 * A2 * B0 * B4 + + b2 * b3 * B0 * B1 * B4 + + b1 * b4 * B0 * B1 * B4 + - 2 * b0 * b5 * B0 * B1 * B4 + - a1 * b2 * B1**2 * B4 + + b0 * b4 * B1**2 * B4 + - a0 * a1 * A2 * B2 * B4 + + b0**2 * A2 * B2 * B4 + + 2 * a2 * b0 * B0 * B2 * B4 + - 2 * b1 * b3 * B0 * B2 * B4 + + a1 * b1 * B1 * B2 * B4 + - b0 * b3 * B1 * B2 * B4 + - b2 * b3 * A0 * B3 * B4 + - b1 * b4 * A0 * B3 * B4 + + 2 * b0 * b5 * A0 * B3 * B4 + - b0 * b2 * B1 * B3 * B4 + + a0 * b4 * B1 * B3 * B4 + - b0 * b1 * B2 * B3 * B4 + + a0 * b3 * B2 * B3 * B4 + - a2 * b0 * A0 * B4**2 + + b1 * b3 * A0 * B4**2 + + b0 * b1 * B1 * B4**2 + - a0 * b3 * B1 * B4**2 + + b2 * b3 * A0 * A1 * B5 + + b1 * b4 * A0 * A1 * B5 + - 2 * b0 * b5 * A0 * A1 * B5 + - b2 * b3 * B0**2 * B5 + - b1 * b4 * B0**2 * B5 + + 2 * b0 * b5 * B0**2 * B5 + + b0 * b2 * A1 * B1 * B5 + - a0 * b4 * A1 * B1 * B5 + + a1 * b2 * B0 * B1 * B5 + - b0 * b4 * B0 * B1 * B5 + + b0 * b1 * A1 * B2 * B5 + - a0 * b3 * A1 * B2 * B5 + + a1 * b1 * B0 * B2 * B5 + - b0 * b3 * B0 * B2 * B5 + - a1 * b2 * A0 * B3 * B5 + + b0 * b4 * A0 * B3 * B5 + - b0 * b2 * B0 * B3 * B5 + + a0 * b4 * B0 * B3 * B5 + + a0 * a1 * B2 * B3 * B5 + - b0**2 * B2 * B3 * B5 + - a1 * b1 * A0 * B4 * B5 + + b0 * b3 * A0 * B4 * B5 + - b0 * b1 * B0 * B4 * B5 + + a0 * b3 * B0 * B4 * B5 + + a0 * a1 * B1 * B4 * B5 + - b0**2 * B1 * B4 * B5 + - a0 * a1 * B0 * B5**2 + + b0**2 * B0 * B5**2 + ) t00 = T00(a0, a1, a2, a3, b0, b1, b2, b3, b4, b5, A0, A1, A2, A3, B0, B1, B2, B3, B4, B5) t11 = T00(a1, a2, a3, a0, b3, b4, b0, b5, b1, b2, A1, A2, A3, A0, B3, B4, B0, B5, B1, B2) @@ -3767,8 +3947,7 @@ def T01(a0, a1, a2, a3, b0, b1, b2, b3, b4, b5, A0, A1, A2, A3, B0, B1, B2, B3, else: w, x, y = self._variables[0:3] z = self._ring.one() - return t00*w*w + 2*t01*w*x + 2*t02*w*y + 2*t30*w*z + t11*x*x + 2*t12*x*y \ - + 2*t13*x*z + t22*y*y + 2*t23*y*z + t33*z*z + return t00 * w * w + 2 * t01 * w * x + 2 * t02 * w * y + 2 * t30 * w * z + t11 * x * x + 2 * t12 * x * y + 2 * t13 * x * z + t22 * y * y + 2 * t23 * y * z + t33 * z * z def T_covariant(self): """ @@ -3832,11 +4011,7 @@ def J_covariant(self): * (a3*A2 - a2*A3) * (a3*A1 - a1*A3) * (a3*A0 - a0*A3) """ F = self._ring.base_ring() - return 1/F(16) * self._jacobian_determinant( - [self.first().form(), 2], - [self.second().form(), 2], - [self.T_covariant(), 4], - [self.T_prime_covariant(), 4]) + return 1 / F(16) * self._jacobian_determinant([self.first().form(), 2], [self.second().form(), 2], [self.T_covariant(), 4], [self.T_prime_covariant(), 4]) def syzygy(self, Delta, Theta, Phi, Theta_prime, Delta_prime, U, V, T, T_prime, J): """ @@ -3879,64 +4054,33 @@ def syzygy(self, Delta, Theta, Phi, Theta_prime, Delta_prime, U, V, T, T_prime, sage: biquadratic.syzygy(1, 1, 1, 1, 1, 1, 1, 1, 1, x) -x^2 + 1 """ - return -J**2 + \ - Delta * T**4 - Theta * T**3*T_prime + Phi * T**2*T_prime**2 \ - - Theta_prime * T*T_prime**3 + Delta_prime * T_prime**4 + \ - ( (Theta_prime**2 - 2*Delta_prime*Phi) * T_prime**3 - - (Theta_prime*Phi - 3*Theta*Delta_prime) * T_prime**2*T + - (Theta*Theta_prime - 4*Delta*Delta_prime) * T_prime*T**2 - - (Delta*Theta_prime) * T**3 - ) * U + \ - ( (Theta**2 - 2*Delta*Phi)*T**3 - - (Theta*Phi - 3*Theta_prime*Delta)*T**2*T_prime + - (Theta*Theta_prime - 4*Delta*Delta_prime)*T*T_prime**2 - - (Delta_prime*Theta)*T_prime**3 - ) * V + \ - ( (Delta*Phi*Delta_prime) * T**2 + - (3*Delta*Theta_prime*Delta_prime - Theta*Phi*Delta_prime) * T*T_prime + - (2*Delta*Delta_prime**2 - 2*Theta*Theta_prime*Delta_prime - + Phi**2*Delta_prime) * T_prime**2 - ) * U**2 + \ - ( (Delta*Theta*Delta_prime + 2*Delta*Phi*Theta_prime - Theta**2*Theta_prime) * T**2 + - (4*Delta*Phi*Delta_prime - 3*Theta**2*Delta_prime - - 3*Delta*Theta_prime**2 + Theta*Phi*Theta_prime) * T*T_prime + - (Delta*Theta_prime*Delta_prime + 2*Delta_prime*Phi*Theta - - Theta*Theta_prime**2) * T_prime**2 - ) * U*V + \ - ( (2*Delta**2*Delta_prime - 2*Delta*Theta*Theta_prime + Delta*Phi**2) * T**2 + - (3*Delta*Theta*Delta_prime - Delta*Phi*Theta_prime) * T*T_prime + - Delta*Phi*Delta_prime * T_prime**2 - ) * V**2 + \ - ( (-Delta*Theta*Delta_prime**2) * T + - (-2*Delta*Phi*Delta_prime**2 + Theta**2*Delta_prime**2) * T_prime - ) * U**3 + \ - ( (4*Delta**2*Delta_prime**2 - Delta*Theta*Theta_prime*Delta_prime - - 2*Delta*Phi**2*Delta_prime + Theta**2*Phi*Delta_prime) * T + - (-5*Delta*Theta*Delta_prime**2 + Delta*Phi*Theta_prime*Delta_prime - + 2*Theta**2*Theta_prime*Delta_prime - Theta*Phi**2*Delta_prime) * T_prime - ) * U**2*V + \ - ( (-5*Delta**2*Theta_prime*Delta_prime + Delta*Theta*Phi*Delta_prime - + 2*Delta*Theta*Theta_prime**2 - Delta*Phi**2*Theta_prime) * T + - (4*Delta**2*Delta_prime**2 - Delta*Theta*Theta_prime*Delta_prime - - 2*Delta*Phi**2*Delta_prime + Delta*Phi*Theta_prime**2) * T_prime - ) * U*V**2 + \ - ( (-2*Delta**2*Phi*Delta_prime + Delta**2*Theta_prime**2) * T + - (-Delta**2*Theta_prime*Delta_prime) * T_prime - ) * V**3 + \ - (Delta**2*Delta_prime**3) * U**4 + \ - (-3*Delta**2*Theta_prime*Delta_prime**2 + 3*Delta*Theta*Phi*Delta_prime**2 - - Theta**3*Delta_prime**2) * U**3*V + \ - (-3*Delta**2*Phi*Delta_prime**2 + 3*Delta*Theta**2*Delta_prime**2 - + 3*Delta**2*Theta_prime**2*Delta_prime - - 3*Delta*Theta*Phi*Theta_prime*Delta_prime - + Delta*Phi**3*Delta_prime) * U**2*V**2 + \ - (-3*Delta**2*Theta*Delta_prime**2 + 3*Delta**2*Phi*Theta_prime*Delta_prime - - Delta**2*Theta_prime**3) * U*V**3 + \ - (Delta**3*Delta_prime**2) * V**4 + return ( + -(J**2) + + Delta * T**4 + - Theta * T**3 * T_prime + + Phi * T**2 * T_prime**2 + - Theta_prime * T * T_prime**3 + + Delta_prime * T_prime**4 + + ((Theta_prime**2 - 2 * Delta_prime * Phi) * T_prime**3 - (Theta_prime * Phi - 3 * Theta * Delta_prime) * T_prime**2 * T + (Theta * Theta_prime - 4 * Delta * Delta_prime) * T_prime * T**2 - (Delta * Theta_prime) * T**3) * U + + ((Theta**2 - 2 * Delta * Phi) * T**3 - (Theta * Phi - 3 * Theta_prime * Delta) * T**2 * T_prime + (Theta * Theta_prime - 4 * Delta * Delta_prime) * T * T_prime**2 - (Delta_prime * Theta) * T_prime**3) * V + + ((Delta * Phi * Delta_prime) * T**2 + (3 * Delta * Theta_prime * Delta_prime - Theta * Phi * Delta_prime) * T * T_prime + (2 * Delta * Delta_prime**2 - 2 * Theta * Theta_prime * Delta_prime + Phi**2 * Delta_prime) * T_prime**2) * U**2 + + ((Delta * Theta * Delta_prime + 2 * Delta * Phi * Theta_prime - Theta**2 * Theta_prime) * T**2 + (4 * Delta * Phi * Delta_prime - 3 * Theta**2 * Delta_prime - 3 * Delta * Theta_prime**2 + Theta * Phi * Theta_prime) * T * T_prime + (Delta * Theta_prime * Delta_prime + 2 * Delta_prime * Phi * Theta - Theta * Theta_prime**2) * T_prime**2) * U * V + + ((2 * Delta**2 * Delta_prime - 2 * Delta * Theta * Theta_prime + Delta * Phi**2) * T**2 + (3 * Delta * Theta * Delta_prime - Delta * Phi * Theta_prime) * T * T_prime + Delta * Phi * Delta_prime * T_prime**2) * V**2 + + ((-Delta * Theta * Delta_prime**2) * T + (-2 * Delta * Phi * Delta_prime**2 + Theta**2 * Delta_prime**2) * T_prime) * U**3 + + ((4 * Delta**2 * Delta_prime**2 - Delta * Theta * Theta_prime * Delta_prime - 2 * Delta * Phi**2 * Delta_prime + Theta**2 * Phi * Delta_prime) * T + (-5 * Delta * Theta * Delta_prime**2 + Delta * Phi * Theta_prime * Delta_prime + 2 * Theta**2 * Theta_prime * Delta_prime - Theta * Phi**2 * Delta_prime) * T_prime) * U**2 * V + + ((-5 * Delta**2 * Theta_prime * Delta_prime + Delta * Theta * Phi * Delta_prime + 2 * Delta * Theta * Theta_prime**2 - Delta * Phi**2 * Theta_prime) * T + (4 * Delta**2 * Delta_prime**2 - Delta * Theta * Theta_prime * Delta_prime - 2 * Delta * Phi**2 * Delta_prime + Delta * Phi * Theta_prime**2) * T_prime) * U * V**2 + + ((-2 * Delta**2 * Phi * Delta_prime + Delta**2 * Theta_prime**2) * T + (-(Delta**2) * Theta_prime * Delta_prime) * T_prime) * V**3 + + (Delta**2 * Delta_prime**3) * U**4 + + (-3 * Delta**2 * Theta_prime * Delta_prime**2 + 3 * Delta * Theta * Phi * Delta_prime**2 - Theta**3 * Delta_prime**2) * U**3 * V + + (-3 * Delta**2 * Phi * Delta_prime**2 + 3 * Delta * Theta**2 * Delta_prime**2 + 3 * Delta**2 * Theta_prime**2 * Delta_prime - 3 * Delta * Theta * Phi * Theta_prime * Delta_prime + Delta * Phi**3 * Delta_prime) * U**2 * V**2 + + (-3 * Delta**2 * Theta * Delta_prime**2 + 3 * Delta**2 * Phi * Theta_prime * Delta_prime - Delta**2 * Theta_prime**3) * U * V**3 + + (Delta**3 * Delta_prime**2) * V**4 + ) ###################################################################### + class InvariantTheoryFactory: """ Factory object for invariants of multilinear forms. @@ -4331,42 +4475,34 @@ def binary_form_from_invariants(self, degree, invariants, variables=None, as_for from sage.rings.fraction_field import FractionField from sage.structure.sequence import Sequence from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + K = FractionField(Sequence(list(invariants)).universe()) if variables is None: x, z = PolynomialRing(K, 'x,z').gens() elif len(variables) == 2: x, z = variables else: - raise ValueError('incorrect number of variables provided, ' - 'exactly two variables should be provided') + raise ValueError('incorrect number of variables provided, ' 'exactly two variables should be provided') if degree == 2: if len(invariants) == 1: if as_form: - return QuadraticForm.from_invariants(invariants[0], x, z, - *args, **kwargs) - return reconstruction.binary_quadratic_coefficients_from_invariants( - invariants[0], *args, **kwargs) - raise ValueError('incorrect number of invariants provided, ' - 'only one invariant should be provided') + return QuadraticForm.from_invariants(invariants[0], x, z, *args, **kwargs) + return reconstruction.binary_quadratic_coefficients_from_invariants(invariants[0], *args, **kwargs) + raise ValueError('incorrect number of invariants provided, ' 'only one invariant should be provided') elif degree == 3: if len(invariants) == 1: if as_form: raise NotImplementedError('no class for binary cubics implemented') else: - return reconstruction.binary_cubic_coefficients_from_invariants( - invariants[0], *args, **kwargs) + return reconstruction.binary_cubic_coefficients_from_invariants(invariants[0], *args, **kwargs) else: - raise ValueError('incorrect number of invariants provided, only ' - 'one invariant should be provided') + raise ValueError('incorrect number of invariants provided, only ' 'one invariant should be provided') elif degree == 5: if as_form: - return BinaryQuintic.from_invariants(invariants, x, z, - *args, **kwargs) - return reconstruction.binary_quintic_coefficients_from_invariants( - invariants, *args, **kwargs) + return BinaryQuintic.from_invariants(invariants, x, z, *args, **kwargs) + return reconstruction.binary_quintic_coefficients_from_invariants(invariants, *args, **kwargs) else: - raise NotImplementedError('no reconstruction for binary forms of ' - 'degree {} implemented'.format(degree)) + raise NotImplementedError('no reconstruction for binary forms of ' 'degree {} implemented'.format(degree)) def ternary_quadratic(self, quadratic, *args, **kwds): """ diff --git a/src/sage/rings/invariants/reconstruction.py b/src/sage/rings/invariants/reconstruction.py index b64f7acbaa4..6118ed06c21 100644 --- a/src/sage/rings/invariants/reconstruction.py +++ b/src/sage/rings/invariants/reconstruction.py @@ -50,12 +50,11 @@ def binary_quadratic_coefficients_from_invariants(discriminant, invariant_choice (1, 0, 0) """ if invariant_choice not in ['default', 'discriminant']: - raise ValueError('unknown choice of invariants {} for a binary ' - 'quadratic'.format(invariant_choice)) + raise ValueError('unknown choice of invariants {} for a binary ' 'quadratic'.format(invariant_choice)) if discriminant == 0: return (1, 0, 0) try: - return (1, 0, -discriminant/4) + return (1, 0, -discriminant / 4) except ZeroDivisionError: return (0, 1, 0) @@ -97,11 +96,9 @@ def binary_cubic_coefficients_from_invariants(discriminant, invariant_choice='de ValueError: no unique reconstruction possible for binary cubics with a double root """ if invariant_choice not in ['default', 'discriminant']: - raise ValueError('unknown choice of invariants {} for a binary cubic' - .format(invariant_choice)) + raise ValueError('unknown choice of invariants {} for a binary cubic'.format(invariant_choice)) if discriminant == 0: - raise ValueError('no unique reconstruction possible for binary ' - 'cubics with a double root') + raise ValueError('no unique reconstruction possible for binary ' 'cubics with a double root') else: return (0, 1, -1, 0) @@ -245,28 +242,28 @@ def binary_quintic_coefficients_from_invariants(invariants, K=None, invariant_ch ValueError: unknown scaling option 'unknown' """ if invariant_choice not in ['default', 'clebsch']: - raise ValueError('unknown choice of invariants {} for a binary quintic' - .format(invariant_choice)) + raise ValueError('unknown choice of invariants {} for a binary quintic'.format(invariant_choice)) if scaling not in ['none', 'normalized', 'coprime']: raise ValueError("unknown scaling option '%s'" % scaling) if scaling == 'coprime': if len(invariants) == 3: - invariants = _reduce_invariants(invariants, [1,2,3]) + invariants = _reduce_invariants(invariants, [1, 2, 3]) elif len(invariants) == 4: - invariants = _reduce_invariants(invariants, [2,4,6,9]) + invariants = _reduce_invariants(invariants, [2, 4, 6, 9]) A, B, C = invariants[0:3] if K is None: from sage.rings.fraction_field import FractionField + K = FractionField(A.parent()) if K.characteristic() in [2, 3, 5]: - raise NotImplementedError('no reconstruction of binary quintics ' - 'implemented for fields of characteristic 2, 3 or 5') - M = 2*A*B - 3*C - N = K(2)**-1 * (A*C-B**2) - R2 = -K(2)**-1 * (A*N**2-2*B*M*N+C*M**2) + raise NotImplementedError('no reconstruction of binary quintics ' 'implemented for fields of characteristic 2, 3 or 5') + M = 2 * A * B - 3 * C + N = K(2) ** -1 * (A * C - B**2) + R2 = -K(2) ** -1 * (A * N**2 - 2 * B * M * N + C * M**2) scale = [1, 1, 1, 1, 1, 1] from sage.arith.misc import binomial from sage.misc.functional import sqrt + if len(invariants) == 3: if R2.is_square(): R = sqrt(R2) @@ -277,18 +274,15 @@ def binary_quintic_coefficients_from_invariants(invariants, K=None, invariant_ch M, N = R2**3 * M, R2**4 * N R = R2**5 elif len(invariants) == 4: - if invariants[3]**2 != R2: - raise ValueError('provided invariants do not satisfy the syzygy ' - 'for Clebsch invariants of a binary quintic') + if invariants[3] ** 2 != R2: + raise ValueError('provided invariants do not satisfy the syzygy ' 'for Clebsch invariants of a binary quintic') R = invariants[3] else: - raise ValueError('incorrect number of invariants provided, this ' - 'method requires 3 or 4 invariants') + raise ValueError('incorrect number of invariants provided, this ' 'method requires 3 or 4 invariants') if M == 0: if N == 0: if A == 0: - raise ValueError('no unique reconstruction possible for ' - 'quintics with a treefold linear factor') + raise ValueError('no unique reconstruction possible for ' 'quintics with a treefold linear factor') else: if B == 0: return (1, 0, 0, 0, 0, 1) @@ -299,56 +293,57 @@ def binary_quintic_coefficients_from_invariants(invariants, K=None, invariant_ch return (1, 0, 0, 0, 1, 0) if scaling == 'normalized': # scaling z by (R/A**3) - scale = [(-N)**-5*A**6*(R/A**3)**i for i in range(6)] + scale = [(-N) ** -5 * A**6 * (R / A**3) ** i for i in range(6)] D = -N Delta = C a = [0] - a.append((2*K(3)**-1*A**2-B)*N*B*K(2)**-1 - N**2*K(2)**-1) - B0 = 2*K(3)**-1*A*R - B1 = A*N*B*K(3)**-1 - C0 = 2*K(3)**-1*R - C1 = B*N + a.append((2 * K(3) ** -1 * A**2 - B) * N * B * K(2) ** -1 - N**2 * K(2) ** -1) + B0 = 2 * K(3) ** -1 * A * R + B1 = A * N * B * K(3) ** -1 + C0 = 2 * K(3) ** -1 * R + C1 = B * N else: # case corresponding to using alpha and beta as coordinates if R == 0: if A == 0: - return (1,0,10,0,-15,0) + return (1, 0, 10, 0, -15, 0) if scaling == 'normalized': # scaling x by A and z by sqrt(A) - scale = [ (-M)**(-5)*sqrt(A)**(12+i) for i in range(6) ] + scale = [(-M) ** (-5) * sqrt(A) ** (12 + i) for i in range(6)] else: if A == 0: if B == 0: - return (1,0,0,1,0,0) + return (1, 0, 0, 1, 0, 0) if scaling == 'normalized': # scaling y by R/B**2 - scale = [ (-M)**(-3)*(R/B**2)**i for i in range(6) ] + scale = [(-M) ** (-3) * (R / B**2) ** i for i in range(6)] elif scaling == 'normalized': # scaling y by R/A**4 - scale = [ (-M)**(-3)*(R/A**4)**i for i in range(6) ] + scale = [(-M) ** (-3) * (R / A**4) ** i for i in range(6)] D = -M Delta = A a = [0] - a.append((2*K(3)**-1*A**2-B)*(N*A-M*B)*K(2)**-1 - - M*(N*K(2)**-1-M*A*K(3)**-1)) + a.append((2 * K(3) ** -1 * A**2 - B) * (N * A - M * B) * K(2) ** -1 - M * (N * K(2) ** -1 - M * A * K(3) ** -1)) B0 = R - B1 = K(2)**-1*(N*A-M*B) + B1 = K(2) ** -1 * (N * A - M * B) C0 = 0 C1 = -M - a[0] = (2*K(3)**-1*A**2-B)*R - a.append(-D*B0 - K(2)**-1*Delta*a[0]) - a.append(-D*B1 - K(2)**-1*Delta*a[1]) - a.append(D**2*C0 + D*Delta*B0 + K(4)**-1*Delta**2*a[0]) - a.append(D**2*C1 + D*Delta*B1 + K(4)**-1*Delta**2*a[1]) - coeffs = tuple([K((-1)**i*binomial(5,i)*scale[5-i]*a[i]) for i in range(6)]) + a[0] = (2 * K(3) ** -1 * A**2 - B) * R + a.append(-D * B0 - K(2) ** -1 * Delta * a[0]) + a.append(-D * B1 - K(2) ** -1 * Delta * a[1]) + a.append(D**2 * C0 + D * Delta * B0 + K(4) ** -1 * Delta**2 * a[0]) + a.append(D**2 * C1 + D * Delta * B1 + K(4) ** -1 * Delta**2 * a[1]) + coeffs = tuple([K((-1) ** i * binomial(5, i) * scale[5 - i] * a[i]) for i in range(6)]) if scaling == 'coprime': from sage.arith.misc import gcd - return tuple([coeffs[i]/gcd(coeffs) for i in range(6)]) + + return tuple([coeffs[i] / gcd(coeffs) for i in range(6)]) return coeffs ###################################################################### + def _reduce_invariants(invariants, weights): """ Reduce a list of invariants of given weights. @@ -377,14 +372,16 @@ def _reduce_invariants(invariants, weights): [3, 75, 250] """ from sage.rings.integer_ring import ZZ + factors = [dict(I.factor()) for I in invariants] scalar = ZZ(1) n = len(weights) from sage.arith.misc import gcd + for prime in gcd(invariants).factor(): p = prime[0] for D in factors: if p not in D: D[p] = 0 - scalar = scalar*p**min([factors[i][p]//weights[i] for i in range(n)]) - return [invariants[i]*scalar**-weights[i] for i in range(n)] + scalar = scalar * p ** min([factors[i][p] // weights[i] for i in range(n)]) + return [invariants[i] * scalar ** -weights[i] for i in range(n)] diff --git a/src/sage/rings/khuri_makdisi.pyi b/src/sage/rings/khuri_makdisi.pyi index 84e13b949e4..f6d295b4654 100644 --- a/src/sage/rings/khuri_makdisi.pyi +++ b/src/sage/rings/khuri_makdisi.pyi @@ -1,8 +1,7 @@ from typing import Any from sage.matrix.matrix import Matrix -def listcat(l: list[list[Any]]) -> list[Any]: - ... +def listcat(l: list[list[Any]]) -> list[Any]: ... class KhuriMakdisi_base: wL: Matrix @@ -10,47 +9,23 @@ class KhuriMakdisi_base: d0: int g: int - def mu_image(self, wd: Matrix, we: Matrix, mu_mat: Matrix, expected_dim: int = 0) -> Matrix: - ... - - def mu_preimage(self, we: Matrix, wde: Matrix, mu_mat: Matrix, expected_codim: int = 0) -> Matrix: - ... - - def negate(self, wd: Matrix) -> Matrix: - ... - - def add(self, wd1: Matrix, wd2: Matrix) -> Matrix: - ... - - def subtract(self, wd1: Matrix, wd2: Matrix) -> Matrix: - ... - - def multiple(self, wd: Matrix, n: int) -> Matrix: - ... - - def zero_divisor(self) -> Matrix: - ... + def mu_image(self, wd: Matrix, we: Matrix, mu_mat: Matrix, expected_dim: int = 0) -> Matrix: ... + def mu_preimage(self, we: Matrix, wde: Matrix, mu_mat: Matrix, expected_codim: int = 0) -> Matrix: ... + def negate(self, wd: Matrix) -> Matrix: ... + def add(self, wd1: Matrix, wd2: Matrix) -> Matrix: ... + def subtract(self, wd1: Matrix, wd2: Matrix) -> Matrix: ... + def multiple(self, wd: Matrix, n: int) -> Matrix: ... + def zero_divisor(self) -> Matrix: ... class KhuriMakdisi_large(KhuriMakdisi_base): mu_mat33: Matrix - def __init__(self, V: Any, mu: Any, w0: Matrix, d0: int, g: int) -> None: - ... - - def equal(self, wd: Matrix, we: Matrix) -> bool: - ... - - def _add(self, wd: Matrix, we: Matrix) -> Matrix: - ... - - def _flip(self, wd: Matrix) -> Matrix: - ... - - def addflip(self, wd1: Matrix, wd2: Matrix) -> Matrix: - ... - - def add_divisor(self, wd1: Matrix, wd2: Matrix, d1: int, d2: int) -> Matrix: - ... + def __init__(self, V: Any, mu: Any, w0: Matrix, d0: int, g: int) -> None: ... + def equal(self, wd: Matrix, we: Matrix) -> bool: ... + def _add(self, wd: Matrix, we: Matrix) -> Matrix: ... + def _flip(self, wd: Matrix) -> Matrix: ... + def addflip(self, wd1: Matrix, wd2: Matrix) -> Matrix: ... + def add_divisor(self, wd1: Matrix, wd2: Matrix, d1: int, d2: int) -> Matrix: ... class KhuriMakdisi_medium(KhuriMakdisi_base): wV1: Matrix @@ -61,17 +36,10 @@ class KhuriMakdisi_medium(KhuriMakdisi_base): mu_mat31: Matrix mu_mat32: Matrix - def __init__(self, V: Any, mu: Any, w0: Matrix, d0: int, g: int) -> None: - ... - - def equal(self, wd: Matrix, we: Matrix) -> bool: - ... - - def addflip(self, wd1: Matrix, wd2: Matrix) -> Matrix: - ... - - def add_divisor(self, wd1: Matrix, wd2: Matrix, d1: int, d2: int) -> Matrix: - ... + def __init__(self, V: Any, mu: Any, w0: Matrix, d0: int, g: int) -> None: ... + def equal(self, wd: Matrix, we: Matrix) -> bool: ... + def addflip(self, wd1: Matrix, wd2: Matrix) -> Matrix: ... + def add_divisor(self, wd1: Matrix, wd2: Matrix, d1: int, d2: int) -> Matrix: ... class KhuriMakdisi_small(KhuriMakdisi_base): wV2: Matrix @@ -86,17 +54,8 @@ class KhuriMakdisi_small(KhuriMakdisi_base): mu_mat42: Matrix mu_mat43: Matrix - def __init__(self, V: Any, mu: Any, w0: Matrix, d0: int, g: int) -> None: - ... - - def equal(self, wd: Matrix, we: Matrix) -> bool: - ... - - def addflip(self, wd1: Matrix, wd2: Matrix) -> Matrix: - ... - - def negate(self, wd: Matrix) -> Matrix: - ... - - def add_divisor(self, wd1: Matrix, wd2: Matrix, d1: int, d2: int) -> Matrix: - ... + def __init__(self, V: Any, mu: Any, w0: Matrix, d0: int, g: int) -> None: ... + def equal(self, wd: Matrix, we: Matrix) -> bool: ... + def addflip(self, wd1: Matrix, wd2: Matrix) -> Matrix: ... + def negate(self, wd: Matrix) -> Matrix: ... + def add_divisor(self, wd1: Matrix, wd2: Matrix, d1: int, d2: int) -> Matrix: ... diff --git a/src/sage/rings/laurent_series_ring.py b/src/sage/rings/laurent_series_ring.py index a7bbc961b69..abc7f4dda11 100644 --- a/src/sage/rings/laurent_series_ring.py +++ b/src/sage/rings/laurent_series_ring.py @@ -17,6 +17,7 @@ * :func:`sage.misc.defaults.set_series_precision` """ + # **************************************************************************** # Copyright (C) 2006 William Stein # 2007 Robert Bradshaw @@ -174,6 +175,7 @@ class LaurentSeriesRing(UniqueRepresentation, Parent): ....: else: ....: print("wrong coercion {}".format(P)) """ + Element = LaurentSeries @staticmethod @@ -262,9 +264,7 @@ def __init__(self, power_series): self._power_series_ring = power_series self._one_element = self.element_class(self, power_series.one()) - Parent.__init__(self, base_ring, - names=power_series.variable_names(), - category=category) + Parent.__init__(self, base_ring, names=power_series.variable_names(), category=category) def base_extend(self, R): """ @@ -305,12 +305,11 @@ def fraction_field(self): """ from sage.categories.fields import Fields from sage.categories.integral_domains import IntegralDomains + if self in Fields(): return self if self in IntegralDomains(): - return LaurentSeriesRing(self.base_ring().fraction_field(), - self.variable_names(), - self.default_prec()) + return LaurentSeriesRing(self.base_ring().fraction_field(), self.variable_names(), self.default_prec()) raise ValueError('must be an integral domain') def change_ring(self, R): @@ -323,9 +322,7 @@ def change_ring(self, R): sage: R.default_prec() 4 """ - return LaurentSeriesRing(R, self.variable_names(), - default_prec=self.default_prec(), - sparse=self.is_sparse()) + return LaurentSeriesRing(R, self.variable_names(), default_prec=self.default_prec(), sparse=self.is_sparse()) def is_sparse(self): """ @@ -545,20 +542,17 @@ def _element_constructor_(self, x, n=0, prec=infinity): x = self.power_series_ring()(x) elif isinstance(x, pari_gen): t = x.type() - if t == "t_RFRAC": # Rational function - x = self(self.polynomial_ring()(x.numerator())) / \ - self(self.polynomial_ring()(x.denominator())) + if t == "t_RFRAC": # Rational function + x = self(self.polynomial_ring()(x.numerator())) / self(self.polynomial_ring()(x.denominator())) return (x << n).add_bigoh(prec) - if t == "t_SER": # Laurent series + if t == "t_SER": # Laurent series n += x._valp() bigoh = n + x.length() x = self(self.polynomial_ring()(x.Vec())) return (x << n).add_bigoh(bigoh) # General case, pretend to be a polynomial return (self(self.polynomial_ring()(x)) << n).add_bigoh(prec) - elif (isinstance(x, FractionFieldElement) - and (x.base_ring() is self.base_ring() or x.base_ring() == self.base_ring()) - and isinstance(x.numerator(), (Polynomial, MPolynomial))): + elif isinstance(x, FractionFieldElement) and (x.base_ring() is self.base_ring() or x.base_ring() == self.base_ring()) and isinstance(x.numerator(), (Polynomial, MPolynomial)): x = self(x.numerator()) / self(x.denominator()) return (x << n).add_bigoh(prec) elif isinstance(x, (LazyPowerSeries, LazyLaurentSeries)): @@ -571,14 +565,13 @@ def _element_constructor_(self, x, n=0, prec=infinity): x = x.add_bigoh(prec) elif isinstance(x, Expression): from sage.symbolic.expression import SymbolicSeries + if isinstance(x, SymbolicSeries): v = x.default_variable() if str(v) == self.variable_name(): R = self.base_ring() g = self.gen() - return sum( - (R(a)*g**ZZ(e) for a, e in x.coefficients(v, sparse=True)), self.zero() - ).add_bigoh(x.degree(x.default_variable())) + return sum((R(a) * g ** ZZ(e) for a, e in x.coefficients(v, sparse=True)), self.zero()).add_bigoh(x.degree(x.default_variable())) raise TypeError("can only convert series into ring with same variable name") return self.element_class(self, x, n).add_bigoh(prec) @@ -606,9 +599,7 @@ def random_element(self, algorithm='default'): """ if algorithm == 'default': shift = ZZ.random_element() - return self([self.base_ring().random_element() - for k in range(self.default_prec())], - shift).O(shift + self.default_prec()) + return self([self.base_ring().random_element() for k in range(self.default_prec())], shift).O(shift + self.default_prec()) raise ValueError("algorithm cannot be %s" % algorithm) def construction(self): @@ -642,6 +633,7 @@ def construction(self): """ from sage.categories.pushout import CompletionFunctor from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + L = LaurentPolynomialRing(self.base_ring(), self._names[0]) return CompletionFunctor(self._names[0], self.default_prec()), L @@ -713,15 +705,11 @@ def _coerce_map_from_(self, P): True """ from sage.rings.fraction_field import FractionField_generic + A = self.base_ring() if isinstance(P, FractionField_generic) and A.is_field(): return self.has_coerce_map_from(P.base()) - if (isinstance(P, (LaurentSeriesRing, LazyLaurentSeriesRing, - LaurentPolynomialRing_generic, - PowerSeriesRing_generic, LazyPowerSeriesRing, - PolynomialRing_generic)) - and P.variable_name() == self.variable_name() - and A.has_coerce_map_from(P.base_ring())): + if isinstance(P, (LaurentSeriesRing, LazyLaurentSeriesRing, LaurentPolynomialRing_generic, PowerSeriesRing_generic, LazyPowerSeriesRing, PolynomialRing_generic)) and P.variable_name() == self.variable_name() and A.has_coerce_map_from(P.base_ring()): return True def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): @@ -886,8 +874,8 @@ def polynomial_ring(self): Univariate Polynomial Ring in x over Rational Field """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - return PolynomialRing(self.base_ring(), self.variable_name(), - sparse=self.is_sparse()) + + return PolynomialRing(self.base_ring(), self.variable_name(), sparse=self.is_sparse()) def laurent_polynomial_ring(self): r""" @@ -901,8 +889,8 @@ def laurent_polynomial_ring(self): Univariate Laurent Polynomial Ring in x over Rational Field """ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing - return LaurentPolynomialRing(self.base_ring(), self.variable_name(), - sparse=self.is_sparse()) + + return LaurentPolynomialRing(self.base_ring(), self.variable_name(), sparse=self.is_sparse()) def power_series_ring(self): r""" diff --git a/src/sage/rings/laurent_series_ring_element.pyi b/src/sage/rings/laurent_series_ring_element.pyi index 29d7ea64079..0fe150c1136 100644 --- a/src/sage/rings/laurent_series_ring_element.pyi +++ b/src/sage/rings/laurent_series_ring_element.pyi @@ -1,7 +1,6 @@ import builtins from typing import Any - class LaurentSeriesRingElement: def __init__(self, parent: Any, f: Any, n: int = 0) -> None: ... def __reduce__(self) -> tuple: ... @@ -10,9 +9,7 @@ class LaurentSeriesRingElement: def is_zero(self) -> bool: ... def is_monomial(self) -> bool: ... def __bool__(self) -> bool: ... - def _im_gens_( - self, codomain: Any, im_gens: builtins.list[Any], base_map: Any | None = None - ) -> LaurentSeriesRingElement: ... + def _im_gens_(self, codomain: Any, im_gens: builtins.list[Any], base_map: Any | None = None) -> LaurentSeriesRingElement: ... def _normalize(self) -> None: ... def _repr_(self) -> str: ... def verschiebung(self, n: int) -> LaurentSeriesRingElement: ... @@ -28,9 +25,7 @@ class LaurentSeriesRingElement: def residue(self) -> Any: ... def exponents(self) -> builtins.list[int]: ... def laurent_polynomial(self) -> Any: ... - def lift_to_precision( - self, absprec: int | None = None - ) -> LaurentSeriesRingElement: ... + def lift_to_precision(self, absprec: int | None = None) -> LaurentSeriesRingElement: ... def __setitem__(self, n: int, value: Any) -> None: ... def _unsafe_mutate(self, i: int, value: Any) -> None: ... def _add_(self, right_m: Any) -> LaurentSeriesRingElement: ... diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index d6772d2e6b3..237bf92135f 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -238,31 +238,7 @@ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.categories.tensor import tensor -from sage.data_structures.stream import ( - Stream_add, - Stream_cauchy_mul, - Stream_cauchy_mul_commutative, - Stream_sub, - Stream_compose, - Stream_cauchy_compose, - Stream_lmul, - Stream_rmul, - Stream_neg, - Stream_cauchy_invert, - Stream_map_coefficients, - Stream_zero, - Stream_exact, - Stream_uninitialized, - Stream_shift, - Stream_truncated, - Stream_function, - Stream_derivative, - Stream_integral, - Stream_dirichlet_convolve, - Stream_dirichlet_invert, - Stream_plethysm, - Stream_pseudo_diff_mul -) +from sage.data_structures.stream import Stream_add, Stream_cauchy_mul, Stream_cauchy_mul_commutative, Stream_sub, Stream_compose, Stream_cauchy_compose, Stream_lmul, Stream_rmul, Stream_neg, Stream_cauchy_invert, Stream_map_coefficients, Stream_zero, Stream_exact, Stream_uninitialized, Stream_shift, Stream_truncated, Stream_function, Stream_derivative, Stream_integral, Stream_dirichlet_convolve, Stream_dirichlet_invert, Stream_plethysm, Stream_pseudo_diff_mul class LazyModuleElement(Element): @@ -304,6 +280,7 @@ class LazyModuleElement(Element): sage: R[0:10] [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] """ + def __init__(self, parent, coeff_stream): """ Initialize the series. @@ -404,6 +381,7 @@ def __getitem__(self, n): step = n.step if n.step is not None else 1 if n.stop is None: from sage.misc.lazy_list import lazy_list + return lazy_list(lambda k: R(self._coeff_stream[start + k * step])) return [R(self._coeff_stream[k]) for k in range(start, n.stop, step)] @@ -463,12 +441,12 @@ def coefficients(self, n=None): return [] from itertools import repeat, chain, islice from sage.misc.lazy_list import lazy_list + # prepare a generator of the nonzero coefficients P = self.parent() if isinstance(coeff_stream, Stream_exact): if coeff_stream._constant: - coeffs = chain((c for c in coeff_stream._initial_coefficients if c), - repeat(coeff_stream._constant)) + coeffs = chain((c for c in coeff_stream._initial_coefficients if c), repeat(coeff_stream._constant)) else: coeffs = (c for c in coeff_stream._initial_coefficients if c) else: @@ -483,6 +461,7 @@ def coefficients(self, n=None): if isinstance(self, LazyPowerSeries) and self.parent()._arity == 1: from sage.misc.superseded import deprecation + deprecation(32367, 'the method coefficients now only returns the nonzero coefficients. Use __getitem__ instead.') if P._internal_poly_ring.base_ring() is not P._laurent_poly_ring: @@ -587,18 +566,13 @@ def map_coefficients(self, f): else: func = f if isinstance(coeff_stream, Stream_exact): - initial_coefficients = [func(i) if i else 0 - for i in coeff_stream._initial_coefficients] + initial_coefficients = [func(i) if i else 0 for i in coeff_stream._initial_coefficients] c = func(coeff_stream._constant) if coeff_stream._constant else 0 if not any(initial_coefficients) and not c: return P.zero() - coeff_stream = Stream_exact(initial_coefficients, - order=coeff_stream._approximate_order, - degree=coeff_stream._degree, - constant=P.base_ring()(c)) + coeff_stream = Stream_exact(initial_coefficients, order=coeff_stream._approximate_order, degree=coeff_stream._degree, constant=P.base_ring()(c)) return P.element_class(P, coeff_stream) - coeff_stream = Stream_map_coefficients(self._coeff_stream, func, - P.is_sparse()) + coeff_stream = Stream_map_coefficients(self._coeff_stream, func, P.is_sparse()) return P.element_class(P, coeff_stream) def truncate(self, d): @@ -696,14 +670,10 @@ def restrict(self, min_degree=None, max_degree=None): if isinstance(self._coeff_stream, Stream_exact): degree = self._coeff_stream._degree if degree <= min_degree: - coeff_stream = Stream_exact([], - order=v, - constant=self._coeff_stream._constant) + coeff_stream = Stream_exact([], order=v, constant=self._coeff_stream._constant) else: - initial_coefficients = self._coeff_stream._initial_coefficients[min_degree-degree:] - coeff_stream = Stream_exact(initial_coefficients, - order=v, - constant=self._coeff_stream._constant) + initial_coefficients = self._coeff_stream._initial_coefficients[min_degree - degree :] + coeff_stream = Stream_exact(initial_coefficients, order=v, constant=self._coeff_stream._constant) else: coeff_stream = Stream_truncated(self._coeff_stream, 0, v) else: @@ -711,8 +681,7 @@ def restrict(self, min_degree=None, max_degree=None): v = self._coeff_stream._approximate_order else: v = max(self._coeff_stream._approximate_order, min_degree) - initial_coefficients = [self._coeff_stream[i] - for i in range(v, max_degree + 1)] + initial_coefficients = [self._coeff_stream[i] for i in range(v, max_degree + 1)] if not any(initial_coefficients): coeff_stream = Stream_zero() else: @@ -897,8 +866,7 @@ def shift(self, n): if isinstance(self._coeff_stream, Stream_shift): n += self._coeff_stream._shift if n: - if (P._minimal_valuation is not None - and P._minimal_valuation > self._coeff_stream._approximate_order + n): + if P._minimal_valuation is not None and P._minimal_valuation > self._coeff_stream._approximate_order + n: coeff_stream = Stream_truncated(self._coeff_stream._series, n, P._minimal_valuation) else: coeff_stream = Stream_shift(self._coeff_stream._series, n) @@ -910,16 +878,13 @@ def shift(self, n): valuation = self._coeff_stream._approximate_order + n if P._minimal_valuation is not None and P._minimal_valuation > valuation: # We need to truncate some terms - init_coeff = init_coeff[P._minimal_valuation-valuation:] + init_coeff = init_coeff[P._minimal_valuation - valuation :] if not init_coeff and not self._coeff_stream._constant: return P.zero() degree = max(degree, P._minimal_valuation) valuation = P._minimal_valuation - coeff_stream = Stream_exact(init_coeff, - constant=self._coeff_stream._constant, - order=valuation, degree=degree) - elif (P._minimal_valuation is not None - and P._minimal_valuation > self._coeff_stream._approximate_order + n): + coeff_stream = Stream_exact(init_coeff, constant=self._coeff_stream._constant, order=valuation, degree=degree) + elif P._minimal_valuation is not None and P._minimal_valuation > self._coeff_stream._approximate_order + n: coeff_stream = Stream_truncated(self._coeff_stream, n, P._minimal_valuation) else: coeff_stream = Stream_shift(self._coeff_stream, n) @@ -1065,8 +1030,7 @@ def _richcmp_(self, other, op): if self._coeff_stream == other._coeff_stream: return True - if (not self.parent().options['secure'] - and self.parent().options['halting_precision'] is None): + if not self.parent().options['secure'] and self.parent().options['halting_precision'] is None: return False if self._coeff_stream != other._coeff_stream: @@ -1077,12 +1041,11 @@ def _richcmp_(self, other, op): if prec is None: raise ValueError("undecidable") # at least one of the approximate orders is not infinity - m = min(self._coeff_stream._approximate_order, - other._coeff_stream._approximate_order) + m = min(self._coeff_stream._approximate_order, other._coeff_stream._approximate_order) return all(self[i] == other[i] for i in range(m, m + prec)) if op is op_NE: - ret = (self == other) + ret = self == other if ret is None: return ret return not ret @@ -1585,9 +1548,7 @@ def define(self, s): sage: f 1 + 3*x + 16*x^2 + 87*x^3 + 607*x^4 + 4518*x^5 + 30549*x^6 + O(x^7) """ - if (not isinstance(self._coeff_stream, Stream_uninitialized) - or self._coeff_stream._target is not None - or self._coeff_stream._eqs is not None): + if not isinstance(self._coeff_stream, Stream_uninitialized) or self._coeff_stream._target is not None or self._coeff_stream._eqs is not None: raise ValueError("series already defined") if not isinstance(s, LazyModuleElement): @@ -1699,6 +1660,7 @@ def _latex_(self): + O(z^{3}) """ from sage.misc.latex import latex + if isinstance(self._coeff_stream, Stream_zero): return latex('0') if self._coeff_stream.is_uninitialized(): @@ -1722,6 +1684,7 @@ def _ascii_art_(self): sage: L.options._reset() """ from sage.typeset.ascii_art import ascii_art, AsciiArt + if isinstance(self._coeff_stream, Stream_zero): return AsciiArt('0') if self._coeff_stream.is_uninitialized(): @@ -1745,6 +1708,7 @@ def _unicode_art_(self): sage: L.options._reset() """ from sage.typeset.unicode_art import unicode_art, UnicodeArt + if isinstance(self._coeff_stream, Stream_zero): return UnicodeArt('0') if self._coeff_stream.is_uninitialized(): @@ -1893,23 +1857,16 @@ def _add_(self, other): return other if isinstance(right, Stream_zero): return self - if (isinstance(left, Stream_exact) - and isinstance(right, Stream_exact)): + if isinstance(left, Stream_exact) and isinstance(right, Stream_exact): approximate_order = min(left.order(), right.order()) degree = max(left._degree, right._degree) - initial_coefficients = [left[i] + right[i] - for i in range(approximate_order, degree)] + initial_coefficients = [left[i] + right[i] for i in range(approximate_order, degree)] constant = left._constant + right._constant if not any(initial_coefficients) and not constant: return P.zero() - coeff_stream = Stream_exact(initial_coefficients, - constant=constant, - degree=degree, - order=approximate_order) + coeff_stream = Stream_exact(initial_coefficients, constant=constant, degree=degree, order=approximate_order) return P.element_class(P, coeff_stream) - return P.element_class(P, Stream_add(self._coeff_stream, - other._coeff_stream, - P.is_sparse())) + return P.element_class(P, Stream_add(self._coeff_stream, other._coeff_stream, P.is_sparse())) def _sub_(self, other): """ @@ -1973,23 +1930,18 @@ def _sub_(self, other): if isinstance(left, Stream_zero): return -other P = self.parent() - if (isinstance(left, Stream_exact) and isinstance(right, Stream_exact)): + if isinstance(left, Stream_exact) and isinstance(right, Stream_exact): approximate_order = min(left.order(), right.order()) degree = max(left._degree, right._degree) initial_coefficients = [left[i] - right[i] for i in range(approximate_order, degree)] constant = left._constant - right._constant if not any(initial_coefficients) and not constant: return P.zero() - coeff_stream = Stream_exact(initial_coefficients, - constant=constant, - degree=degree, - order=approximate_order) + coeff_stream = Stream_exact(initial_coefficients, constant=constant, degree=degree, order=approximate_order) return P.element_class(P, coeff_stream) if left == right: return P.zero() - return P.element_class(P, Stream_sub(self._coeff_stream, - other._coeff_stream, - P.is_sparse())) + return P.element_class(P, Stream_sub(self._coeff_stream, other._coeff_stream, P.is_sparse())) def _acted_upon_(self, scalar, self_on_left): r""" @@ -2176,15 +2128,10 @@ def _acted_upon_(self, scalar, self_on_left): initial_coefficients = [scalar * val for val in init_coeffs] if not any(initial_coefficients) and not c: return P.zero() - return P.element_class(P, Stream_exact(initial_coefficients, - order=v, - constant=c, - degree=coeff_stream._degree)) + return P.element_class(P, Stream_exact(initial_coefficients, order=v, constant=c, degree=coeff_stream._degree)) if self_on_left or R in Rings().Commutative(): - return P.element_class(P, Stream_lmul(coeff_stream, scalar, - P.is_sparse())) - return P.element_class(P, Stream_rmul(coeff_stream, scalar, - P.is_sparse())) + return P.element_class(P, Stream_lmul(coeff_stream, scalar, P.is_sparse())) + return P.element_class(P, Stream_rmul(coeff_stream, scalar, P.is_sparse())) def _neg_(self): """ @@ -2239,10 +2186,7 @@ def _neg_(self): if isinstance(coeff_stream, Stream_exact): initial_coefficients = [-v for v in coeff_stream._initial_coefficients] constant = -coeff_stream._constant - coeff_stream = Stream_exact(initial_coefficients, - constant=constant, - degree=coeff_stream._degree, - order=coeff_stream.order()) + coeff_stream = Stream_exact(initial_coefficients, constant=constant, degree=coeff_stream._degree, order=coeff_stream.order()) return P.element_class(P, coeff_stream) # -(-f) = f if isinstance(coeff_stream, Stream_neg): @@ -2263,8 +2207,9 @@ def exp(self): 1 + 1/(2^s) + 1/(3^s) + 3/2/4^s + 1/(5^s) + 2/6^s + 1/(7^s) + O(1/(8^s)) """ from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - f = P(coefficients=lambda n: 1/factorial(ZZ(n)), valuation=0) + f = P(coefficients=lambda n: 1 / factorial(ZZ(n)), valuation=0) return f(self) def log(self): @@ -2279,9 +2224,10 @@ def log(self): 1/(2^s) + 1/(3^s) + 1/2/4^s + 1/(5^s) + 1/(7^s) + 1/3/8^s + O(1/(9^s)) """ from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - f = P(coefficients=lambda n: ((-1) ** (n + 1))/ZZ(n), valuation=1) - return f(self-1) + f = P(coefficients=lambda n: ((-1) ** (n + 1)) / ZZ(n), valuation=1) + return f(self - 1) # trigonometric functions @@ -2311,8 +2257,9 @@ def sin(self): True """ from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - c = lambda n: (n % 2)/factorial(ZZ(n)) if n % 4 == 1 else -(n % 2)/factorial(ZZ(n)) + c = lambda n: (n % 2) / factorial(ZZ(n)) if n % 4 == 1 else -(n % 2) / factorial(ZZ(n)) f = P(coefficients=c, valuation=1) return f(self) @@ -2337,8 +2284,9 @@ def cos(self): True """ from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - c = lambda n: 1/factorial(ZZ(n)) if n % 4 == 0 else (n % 2 - 1)/factorial(ZZ(n)) + c = lambda n: 1 / factorial(ZZ(n)) if n % 4 == 0 else (n % 2 - 1) / factorial(ZZ(n)) f = P(coefficients=c, valuation=0) return f(self) @@ -2455,13 +2403,15 @@ def arcsin(self): True """ from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) def f(n): n = ZZ(n) if n % 2: - return factorial(n-1)/((4**((n-1)/2))*(factorial((n-1)/2)**2)*n) + return factorial(n - 1) / ((4 ** ((n - 1) / 2)) * (factorial((n - 1) / 2) ** 2) * n) return ZZ.zero() + return P(f, valuation=1)(self) def arccos(self): @@ -2492,7 +2442,8 @@ def arccos(self): True """ from sage.symbolic.constants import pi - return self.parent()(pi/2) - self.arcsin() + + return self.parent()(pi / 2) - self.arcsin() def arctan(self): r""" @@ -2516,15 +2467,17 @@ def arctan(self): True """ from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) def f(n): n = ZZ(n) if n % 4 == 1: - return 1/n + return 1 / n if n % 2 == 0: return ZZ.zero() - return -1/n + return -1 / n + return P(f, valuation=1)(self) def arccot(self): @@ -2555,7 +2508,8 @@ def arccot(self): True """ from sage.symbolic.constants import pi - return self.parent()(pi/2) - self.arctan() + + return self.parent()(pi / 2) - self.arctan() # hyperbolic functions @@ -2582,9 +2536,9 @@ def sinh(self): True """ from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - f = P(coefficients=lambda n: 1/factorial(ZZ(n)) if n % 2 else ZZ.zero(), - valuation=1) + f = P(coefficients=lambda n: 1 / factorial(ZZ(n)) if n % 2 else ZZ.zero(), valuation=1) return f(self) def cosh(self): @@ -2609,9 +2563,9 @@ def cosh(self): True """ from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - f = P(coefficients=lambda n: ZZ.zero() if n % 2 else 1/factorial(ZZ(n)), - valuation=0) + f = P(coefficients=lambda n: ZZ.zero() if n % 2 else 1 / factorial(ZZ(n)), valuation=0) return f(self) def tanh(self): @@ -2637,6 +2591,7 @@ def tanh(self): """ from sage.arith.misc import bernoulli from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) def f(n): @@ -2645,6 +2600,7 @@ def f(n): h = 4 ** ((n + 1) // 2) return bernoulli(n + 1) * h * (h - 1) / factorial(n + 1) return ZZ.zero() + return P(f, valuation=1)(self) def coth(self): @@ -2668,13 +2624,15 @@ def coth(self): """ from sage.arith.misc import bernoulli from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) def f(n): n = ZZ(n) if n % 2: - return ((2 ** (n + 1)) * bernoulli(n + 1))/factorial(n + 1) + return ((2 ** (n + 1)) * bernoulli(n + 1)) / factorial(n + 1) return ZZ.zero() + return P(f, valuation=-1)(self) def sech(self): @@ -2700,13 +2658,15 @@ def sech(self): """ from sage.combinat.combinat import euler_number from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) def f(n): n = ZZ(n) if n % 2: return ZZ.zero() - return euler_number(n)/factorial(n) + return euler_number(n) / factorial(n) + return P(f, valuation=0)(self) def csch(self): @@ -2731,13 +2691,15 @@ def csch(self): """ from sage.arith.misc import bernoulli from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) def f(n): n = ZZ(n) if n % 2: - return 2 * (1 - ZZ(2) ** n) * bernoulli(n + 1)/factorial(n + 1) + return 2 * (1 - ZZ(2) ** n) * bernoulli(n + 1) / factorial(n + 1) return ZZ.zero() + return P(f, valuation=-1)(self) # inverse hyperbolic functions @@ -2769,14 +2731,16 @@ def arcsinh(self): True """ from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) def f(n): n = ZZ(n) if n % 2: h = (n - 1) // 2 - return ZZ(-1) ** h * factorial(n - 1)/(ZZ(4) ** h * factorial(h) ** 2 * n) + return ZZ(-1) ** h * factorial(n - 1) / (ZZ(4) ** h * factorial(h) ** 2 * n) return ZZ.zero() + return P(f, valuation=1)(self) def arctanh(self): @@ -2806,8 +2770,9 @@ def arctanh(self): True """ from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - f = P(coefficients=lambda n: 1/ZZ(n) if n % 2 else ZZ.zero(), valuation=1) + f = P(coefficients=lambda n: 1 / ZZ(n) if n % 2 else ZZ.zero(), valuation=1) return f(self) def hypergeometric(self, a, b): @@ -2841,6 +2806,7 @@ def hypergeometric(self, a, b): """ from .lazy_series_ring import LazyLaurentSeriesRing from sage.arith.misc import rising_factorial + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) def coeff(n, c): @@ -2848,8 +2814,8 @@ def coeff(n, c): for term in range(len(c)): num *= rising_factorial(c[term], n) return num - f = P(coefficients=lambda n: coeff(n, a) / (coeff(n, b) * factorial(ZZ(n))), - valuation=0) + + f = P(coefficients=lambda n: coeff(n, a) / (coeff(n, b) * factorial(ZZ(n))), valuation=0) return f(self) # === named special functions === @@ -2879,6 +2845,7 @@ def q_pochhammer(self, q=None): O(z^7) """ from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) f = P.q_pochhammer(q) return f(self) @@ -2906,6 +2873,7 @@ def euler(self): O(q^7) """ from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) phi = P.euler() return phi(self) @@ -2928,6 +2896,7 @@ def jacobi_theta(self, w, a=0, b=0): O(q^7) """ from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "q", sparse=self.parent()._sparse) phi = P.jacobi_theta(w=w, a=a, b=b) return phi(self) @@ -2969,6 +2938,7 @@ def polylog(self, s): - :wikipedia:`Polylogarithm` """ from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) phi = P.polylog(s=s) return phi(self) @@ -3050,6 +3020,7 @@ def __pow__(self, n): return generic_power(self, n) from .lazy_series_ring import LazyLaurentSeriesRing + P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) if n in QQ or n in self.base_ring(): @@ -3137,6 +3108,7 @@ class LazyCauchyProductSeries(LazyModuleElement): sage: f 1 + z + z^2 + O(z^3) """ + def valuation(self): r""" Return the valuation of ``self``. @@ -3255,33 +3227,21 @@ def _mul_(self, other): # Check some trivial products if isinstance(left, Stream_zero) or isinstance(right, Stream_zero): return P.zero() - if (isinstance(left, Stream_exact) - and left._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) - and left.order() == 0 - and not left._constant): + if isinstance(left, Stream_exact) and left._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) and left.order() == 0 and not left._constant: return other # self == 1 - if (isinstance(right, Stream_exact) - and right._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) - and right.order() == 0 - and not right._constant): + if isinstance(right, Stream_exact) and right._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) and right.order() == 0 and not right._constant: return self # right == 1 - if ((isinstance(left, Stream_cauchy_invert) and left._series == right) - or (isinstance(right, Stream_cauchy_invert) and right._series == left)): + if (isinstance(left, Stream_cauchy_invert) and left._series == right) or (isinstance(right, Stream_cauchy_invert) and right._series == left): return P.one() # The product is exact if and only if both factors are exact # and one of the factors has eventually 0 coefficients: # (p + a x^d/(1-x))(q + b x^e/(1-x)) # = p q + (a x^d q + b x^e p)/(1-x) + a b x^(d+e)/(1-x)^2 # TODO: this is not true in characteristic 2 - if (isinstance(left, Stream_exact) - and isinstance(right, Stream_exact) - and not (left._constant and right._constant)): + if isinstance(left, Stream_exact) and isinstance(right, Stream_exact) and not (left._constant and right._constant): il = left._initial_coefficients ir = right._initial_coefficients - initial_coefficients = [sum(il[k]*ir[n-k] - for k in range(max(n - len(ir) + 1, 0), - min(len(il) - 1, n) + 1)) - for n in range(len(il) + len(ir) - 1)] + initial_coefficients = [sum(il[k] * ir[n - k] for k in range(max(n - len(ir) + 1, 0), min(len(il) - 1, n) + 1)) for n in range(len(il) + len(ir) - 1)] lv = left.order() rv = right.order() # The coefficients of the series (a * x^d * q)/(1-x) are @@ -3291,18 +3251,18 @@ def _mul_(self, other): if right._constant: d = right._degree c = left._constant # this is zero - initial_coefficients.extend([c]*(d - rv - len(ir))) + initial_coefficients.extend([c] * (d - rv - len(ir))) # left._constant must be 0 and thus len(il) >= 1 - for k in range(len(il)-1): + for k in range(len(il) - 1): c += il[k] * right._constant initial_coefficients[d - rv + k] += c c += il[-1] * right._constant elif left._constant: d = left._degree c = right._constant # this is zero - initial_coefficients.extend([c]*(d - lv - len(il))) + initial_coefficients.extend([c] * (d - lv - len(il))) # left._constant must be 0 and thus len(il) >= 1 - for k in range(len(ir)-1): + for k in range(len(ir) - 1): c += left._constant * ir[k] initial_coefficients[d - lv + k] += c c += left._constant * ir[-1] @@ -3310,9 +3270,7 @@ def _mul_(self, other): c = left._constant # this is zero if not any(initial_coefficients) and not c: return P.zero() - coeff_stream = Stream_exact(initial_coefficients, - order=lv + rv, - constant=c) + coeff_stream = Stream_exact(initial_coefficients, order=lv + rv, constant=c) return P.element_class(P, coeff_stream) if P in Rings().Commutative(): @@ -3438,13 +3396,12 @@ def __pow__(self, n): return self cs = self._coeff_stream - if (isinstance(cs, Stream_exact) and not cs._constant and n in QQ - and (n > 0 or len(cs._initial_coefficients) == 1)): + if isinstance(cs, Stream_exact) and not cs._constant and n in QQ and (n > 0 or len(cs._initial_coefficients) == 1): n = QQ(n) ret = None poly_part = cs._polynomial_part(P._internal_poly_ring) try: - ret = poly_part ** n + ret = poly_part**n ret = P._internal_poly_ring(ret) except (ValueError, TypeError): pass @@ -3460,22 +3417,14 @@ def __pow__(self, n): val = ret.valuation() deg = ret.degree() + 1 initial_coefficients = [ret[i] for i in range(val, deg)] - return P.element_class(P, Stream_exact(initial_coefficients, - constant=cs._constant, - degree=deg, - order=val)) - - if (n in QQ and n not in ZZ - and not cs.is_uninitialized() - and (cs._approximate_order > 0 - or self.valuation() < 0 - or self[self.valuation()] != 1)): + return P.element_class(P, Stream_exact(initial_coefficients, constant=cs._constant, degree=deg, order=val)) + + if n in QQ and n not in ZZ and not cs.is_uninitialized() and (cs._approximate_order > 0 or self.valuation() < 0 or self[self.valuation()] != 1): n = QQ(n) BR = self.base_ring() val = self.valuation() new_val = n * cs.order() - if (new_val not in ZZ - or (P._minimal_valuation is not None and P._minimal_valuation > new_val)): + if new_val not in ZZ or (P._minimal_valuation is not None and P._minimal_valuation > new_val): raise ValueError("unable to take the {} power".format(n)) if P._arity == 1: @@ -3487,8 +3436,8 @@ def __pow__(self, n): return P(BR(lc**n) * LazyModuleElement.__pow__(temp, n).shift(new_val)) else: lc = self[val] - lcp = P._laurent_poly_ring(lc ** n) - offset = ZZ(val*n) + lcp = P._laurent_poly_ring(lc**n) + offset = ZZ(val * n) # Since arity > 1, the exact case will be handled above. sparse = P._sparse @@ -3499,8 +3448,7 @@ def __pow__(self, n): lci = ~lc # We unroll the construction from LazyModuleElement.__pow__(). # This is done because we want elements in the fraction field of _Laurent_poly_ring - f = Stream_function(lambda k: prod(n - i for i in range(k)) * lci**k / ZZ(k).factorial(), - is_sparse=P._sparse, approximate_order=0) + f = Stream_function(lambda k: prod(n - i for i in range(k)) * lci**k / ZZ(k).factorial(), is_sparse=P._sparse, approximate_order=0) cs = Stream_cauchy_compose(f, cs, is_sparse=sparse) if lcp != 1: cs = Stream_rmul(cs, lcp, is_sparse=sparse) @@ -3578,9 +3526,7 @@ def __invert__(self): """ P = self.parent() coeff_stream = self._coeff_stream - if (P._minimal_valuation is not None - and (coeff_stream._approximate_order > 0 - or not coeff_stream.is_uninitialized() and not coeff_stream[0])): + if P._minimal_valuation is not None and (coeff_stream._approximate_order > 0 or not coeff_stream.is_uninitialized() and not coeff_stream[0]): raise ZeroDivisionError("cannot divide by a series of positive valuation") # the inverse is exact if and only if coeff_stream corresponds to one of @@ -3593,34 +3539,25 @@ def __invert__(self): i = ~coeff_stream._constant v = -coeff_stream.order() c = P._internal_poly_ring.base_ring().zero() - coeff_stream = Stream_exact((i, -i), - order=v, - constant=c) + coeff_stream = Stream_exact((i, -i), order=v, constant=c) return P.element_class(P, coeff_stream) if len(initial_coefficients) == 1 and not coeff_stream._constant: i = ~initial_coefficients[0] v = -coeff_stream.order() c = P._internal_poly_ring.base_ring().zero() - coeff_stream = Stream_exact((i,), - order=v, - constant=c) + coeff_stream = Stream_exact((i,), order=v, constant=c) return P.element_class(P, coeff_stream) - if (len(initial_coefficients) == 2 - and not (initial_coefficients[0] + initial_coefficients[1]) - and not coeff_stream._constant): + if len(initial_coefficients) == 2 and not (initial_coefficients[0] + initial_coefficients[1]) and not coeff_stream._constant: v = -coeff_stream.order() c = ~initial_coefficients[0] - coeff_stream = Stream_exact((), - order=v, - constant=c) + coeff_stream = Stream_exact((), order=v, constant=c) return P.element_class(P, coeff_stream) # (f^-1)^-1 = f if isinstance(coeff_stream, Stream_cauchy_invert): return P.element_class(P, coeff_stream._series) - coeff_stream_inverse = Stream_cauchy_invert(coeff_stream, - approximate_order=P._minimal_valuation) + coeff_stream_inverse = Stream_cauchy_invert(coeff_stream, approximate_order=P._minimal_valuation) return P.element_class(P, coeff_stream_inverse) def _div_(self, other): @@ -3749,32 +3686,24 @@ def _div_(self, other): right = other._coeff_stream # right == 1 - if (isinstance(right, Stream_exact) - and right._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) - and right.order() == 0 - and not right._constant): + if isinstance(right, Stream_exact) and right._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) and right.order() == 0 and not right._constant: return self # self is right if left == right: return P.one() - if (P._minimal_valuation is not None - and left._true_order - and left._approximate_order < right._approximate_order): + if P._minimal_valuation is not None and left._true_order and left._approximate_order < right._approximate_order: F = P.fraction_field() num = F.element_class(F, left) den = F.element_class(F, right) return num / den R = P._internal_poly_ring - if (isinstance(left, Stream_exact) - and isinstance(right, Stream_exact) - and hasattr(R.base_ring(), "fraction_field") - and hasattr(R, "_gcd_univariate_polynomial")): + if isinstance(left, Stream_exact) and isinstance(right, Stream_exact) and hasattr(R.base_ring(), "fraction_field") and hasattr(R, "_gcd_univariate_polynomial"): z = R.gen() - num = left._polynomial_part(R) * (1-z) + left._constant * z**left._degree - den = right._polynomial_part(R) * (1-z) + right._constant * z**right._degree + num = left._polynomial_part(R) * (1 - z) + left._constant * z**left._degree + den = right._polynomial_part(R) * (1 - z) + right._constant * z**right._degree # num / den is not necessarily reduced, but gcd and // seems to work: # sage: a = var("a"); R. = SR[] # sage: (a*z - a)/(z - 1) @@ -3791,15 +3720,10 @@ def _div_(self, other): # dividing by z^k d = den[exponents[0]] v = num.valuation() - initial_coefficients = [num[i] / d - for i in range(v, num.degree() + 1)] + initial_coefficients = [num[i] / d for i in range(v, num.degree() + 1)] order = v - den.valuation() - return P.element_class(P, Stream_exact(initial_coefficients, - order=order, - constant=0)) - if (len(exponents) == 2 - and exponents[0] + 1 == exponents[1] - and den[exponents[0]] == -den[exponents[1]]): + return P.element_class(P, Stream_exact(initial_coefficients, order=order, constant=0)) + if len(exponents) == 2 and exponents[0] + 1 == exponents[1] and den[exponents[0]] == -den[exponents[1]]: # dividing by z^k (1-z) quo, rem = num.quo_rem(den) # rem is a unit, i.e., in the Laurent case c*z^v @@ -3811,21 +3735,15 @@ def _div_(self, other): d = quo.degree() m = d - v + 1 if m > 0: - quo += R([constant]*m).shift(v) + quo += R([constant] * m).shift(v) v = d + 1 if quo: order = quo.valuation() else: order = 0 initial_coefficients = [quo[i] for i in range(order, quo.degree() + 1)] - return P.element_class(P, Stream_exact(initial_coefficients, - order=order, - degree=v, - constant=constant)) - return P.element_class(P, Stream_exact([], - order=v, - degree=v, - constant=constant)) + return P.element_class(P, Stream_exact(initial_coefficients, order=order, degree=v, constant=constant)) + return P.element_class(P, Stream_exact([], order=v, degree=v, constant=constant)) # we cannot pass the approximate order here, even when # P._minimal_valuation is zero, because we allow division by @@ -3918,20 +3836,17 @@ def exp(self): coeff_stream = self._coeff_stream # coefficients must not be checked here, it prevents # us from using self.define in some cases! - if ((not coeff_stream.is_uninitialized()) - and any(coeff_stream[i] for i in range(coeff_stream._approximate_order, 1))): + if (not coeff_stream.is_uninitialized()) and any(coeff_stream[i] for i in range(coeff_stream._approximate_order, 1)): raise ValueError("can only compose with a positive valuation series") # WARNING: d_self need not be a proper element of P, e.g. for # multivariate power series # We make the streams dense, because all coefficients have to be computed anyway - d_self = Stream_function(lambda n: (n + 1) * coeff_stream[n + 1], - False, 0) + d_self = Stream_function(lambda n: (n + 1) * coeff_stream[n + 1], False, 0) f = P.undefined(valuation=0) # d_self and f._coeff_stream always commute, the coefficients # of the product are of the form sum_{k=1}^n a_k a_{n+1-k}. d_self_f = Stream_cauchy_mul_commutative(d_self, f._coeff_stream, False) - int_d_self_f = Stream_function(lambda n: d_self_f[n-1] / R(n) if n else R.one(), - False, 0) + int_d_self_f = Stream_function(lambda n: d_self_f[n - 1] / R(n) if n else R.one(), False, 0) f._coeff_stream.define(int_d_self_f) return f @@ -3971,21 +3886,15 @@ def log(self): coeff_stream = self._coeff_stream # coefficients must not be checked here, it prevents # us from using self.define in some cases! - if ((not coeff_stream.is_uninitialized()) - and (any(coeff_stream[i] for i in range(coeff_stream._approximate_order, 0)) - or coeff_stream[0] != R.one())): + if (not coeff_stream.is_uninitialized()) and (any(coeff_stream[i] for i in range(coeff_stream._approximate_order, 0)) or coeff_stream[0] != R.one()): raise ValueError("can only compose with a positive valuation series") # WARNING: d_self need not be a proper element of P, e.g. for # multivariate power series - d_self = Stream_function(lambda n: R(n + 1) * coeff_stream[n + 1], - P.is_sparse(), 0) + d_self = Stream_function(lambda n: R(n + 1) * coeff_stream[n + 1], P.is_sparse(), 0) coeff_stream_inverse = Stream_cauchy_invert(coeff_stream) # d_self and coeff_stream_inverse always commute - d_self_quo_self = Stream_cauchy_mul_commutative(d_self, - coeff_stream_inverse, - P.is_sparse()) - int_d_self_quo_self = Stream_function(lambda n: d_self_quo_self[n-1] / R(n), - P.is_sparse(), 1) + d_self_quo_self = Stream_cauchy_mul_commutative(d_self, coeff_stream_inverse, P.is_sparse()) + int_d_self_quo_self = Stream_function(lambda n: d_self_quo_self[n - 1] / R(n), P.is_sparse(), 1) return P.element_class(P, int_d_self_quo_self) @@ -4060,6 +3969,7 @@ class LazyLaurentSeries(LazyCauchyProductSeries): sage: f = 1 / (1 - z - z^2) sage: TestSuite(f).run() """ + def is_square(self, root=False): r""" Return whether this lazy series is a square. @@ -4096,7 +4006,7 @@ def is_square(self, root=False): else: P = self.parent() z = P.gen() - unit_part = self * z**(-v) + unit_part = self * z ** (-v) if not unit_part.coefficient(0).is_square(): if root: @@ -4109,7 +4019,7 @@ def is_square(self, root=False): if root: if v == 0: return True, sqrt_unit - return True, sqrt_unit * z**(v // 2) + return True, sqrt_unit * z ** (v // 2) return True except (ValueError, ArithmeticError): @@ -4136,7 +4046,7 @@ def is_unit(self) -> bool: sage: (z^3 + 4 - z^-2).is_unit() True """ - if self.is_zero(): # now 0 != 1 + if self.is_zero(): # now 0 != 1 return False a = self[self.valuation()] return a.is_unit() @@ -4466,6 +4376,7 @@ def __call__(self, g): """ # Find a good parent for the result from sage.structure.element import get_coercion_model + cm = get_coercion_model() P = cm.common_parent(self.base_ring(), parent(g)) @@ -4474,9 +4385,7 @@ def __call__(self, g): return P.zero() # g = 0 case - if ((not isinstance(g, LazyModuleElement) and not g) - or (isinstance(g, LazyModuleElement) - and isinstance(g._coeff_stream, Stream_zero))): + if (not isinstance(g, LazyModuleElement) and not g) or (isinstance(g, LazyModuleElement) and isinstance(g._coeff_stream, Stream_zero)): if self._coeff_stream._approximate_order >= 0: return P(self[0]) # Perhaps we just don't yet know if the valuation is nonnegative @@ -4497,9 +4406,7 @@ def __call__(self, g): # g also has finite length, compose the polynomials # We optimize composition when g is not a Dirichlet series # by composing the polynomial parts explicitly - if (isinstance(g, LazyCauchyProductSeries) - and isinstance(g._coeff_stream, Stream_exact) - and not g._coeff_stream._constant): + if isinstance(g, LazyCauchyProductSeries) and isinstance(g._coeff_stream, Stream_exact) and not g._coeff_stream._constant: R = P._laurent_poly_ring g_poly = g._coeff_stream._polynomial_part(R) try: @@ -4512,9 +4419,7 @@ def __call__(self, g): val = ret.valuation() deg = ret.degree() + 1 initial_coefficients = [ret[i] for i in range(val, deg)] - coeff_stream = Stream_exact(initial_coefficients, - constant=P.base_ring().zero(), - degree=deg, order=val) + coeff_stream = Stream_exact(initial_coefficients, constant=P.base_ring().zero(), degree=deg, order=val) return P.element_class(P, coeff_stream) # Return the sum since g is not known to be finite or we do not get a Laurent polynomial @@ -4527,7 +4432,7 @@ def __call__(self, g): v = poly.valuation() if d >= 0: ind = max(0, v) - gp = P.one() if ind == 0 else g ** ind + gp = P.one() if ind == 0 else g**ind for i in range(ind, d): if poly[i]: ret += poly[i] * gp @@ -4536,7 +4441,7 @@ def __call__(self, g): if v < 0: gi = ~g ind = min(d, -1) - gp = gi if ind == -1 else gi ** -ind + gp = gi if ind == -1 else gi**-ind for i in range(ind, v, -1): if poly[i]: ret += poly[i] * gp @@ -4549,8 +4454,10 @@ def __call__(self, g): # Check to see if it belongs to a polynomial ring # that we can extend to a lazy series ring from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(P, PolynomialRing_generic): from sage.rings.lazy_series_ring import LazyLaurentSeriesRing + R = LazyLaurentSeriesRing(P.base_ring(), P.variable_names(), P.is_sparse()) g = R(P(g)) return self(g) @@ -4561,25 +4468,21 @@ def __call__(self, g): # Perhaps we just don't yet know if the valuation is positive if g._coeff_stream._approximate_order <= 0: - if (not g._coeff_stream.is_uninitialized() - and any(g._coeff_stream[i] for i in range(g._coeff_stream._approximate_order, 1))): + if not g._coeff_stream.is_uninitialized() and any(g._coeff_stream[i] for i in range(g._coeff_stream._approximate_order, 1)): raise ValueError("can only compose with a positive valuation series") g._coeff_stream._approximate_order = 1 if not isinstance(g, LazyCauchyProductSeries): if isinstance(g, LazyDirichletSeries): if g._coeff_stream._approximate_order == 1: - if (not g._coeff_stream.is_uninitialized() - and g._coeff_stream[1] != 0): + if not g._coeff_stream.is_uninitialized() and g._coeff_stream[1] != 0: raise ValueError("can only compose with a positive valuation series") g._coeff_stream._approximate_order = 2 # we assume that the valuation of self[i](g) is at least i coeff_stream = Stream_compose(self._coeff_stream, g, P._sparse) else: - coeff_stream = Stream_cauchy_compose(self._coeff_stream, - g._coeff_stream, - P.is_sparse()) + coeff_stream = Stream_cauchy_compose(self._coeff_stream, g._coeff_stream, P.is_sparse()) return P.element_class(P, coeff_stream) @@ -4728,26 +4631,21 @@ def revert(self): # we cannot assume that the last initial coefficient # and the constant differ, see stream.Stream_exact # TODO: provide example or remove this claim - if (coeff_stream._degree == 1 + len(coeff_stream._initial_coefficients) - and coeff_stream._constant == -R.one() - and all(c == -R.one() for c in coeff_stream._initial_coefficients)): + if coeff_stream._degree == 1 + len(coeff_stream._initial_coefficients) and coeff_stream._constant == -R.one() and all(c == -R.one() for c in coeff_stream._initial_coefficients): # self = -z/(1-z); self.revert() = -z/(1-z) return self else: raise ValueError("compositional inverse does not exist") else: - if (coeff_stream.order() == -1 - and coeff_stream._degree == 0): + if coeff_stream.order() == -1 and coeff_stream._degree == 0: # self = a/z; self.revert() = a/z return self - if (coeff_stream.order() >= 0 - and coeff_stream._degree == 2): + if coeff_stream.order() >= 0 and coeff_stream._degree == 2: # self = a + b*z; self.revert() = -a/b + 1/b * z a = coeff_stream[0] b = coeff_stream[1] - coeff_stream = Stream_exact((-a/b, 1/b), - order=0) + coeff_stream = Stream_exact((-a / b, 1 / b), order=0) return P.element_class(P, coeff_stream) if coeff_stream.order() != 1: @@ -4842,31 +4740,21 @@ def derivative(self, *args): coeff_stream = self._coeff_stream if isinstance(coeff_stream, Stream_zero): return self - if (isinstance(coeff_stream, Stream_exact) - and not coeff_stream._constant): + if isinstance(coeff_stream, Stream_exact) and not coeff_stream._constant: if coeff_stream._approximate_order >= 0 and coeff_stream._degree <= order: return P.zero() if vars: - coeffs = [prod(i-k for k in range(order)) * c.derivative(vars) - for i, c in enumerate(coeff_stream._initial_coefficients, - coeff_stream._approximate_order)] + coeffs = [prod(i - k for k in range(order)) * c.derivative(vars) for i, c in enumerate(coeff_stream._initial_coefficients, coeff_stream._approximate_order)] else: - coeffs = [prod(i-k for k in range(order)) * c - for i, c in enumerate(coeff_stream._initial_coefficients, - coeff_stream._approximate_order)] + coeffs = [prod(i - k for k in range(order)) * c for i, c in enumerate(coeff_stream._initial_coefficients, coeff_stream._approximate_order)] if not any(coeffs): return P.zero() - coeff_stream = Stream_exact(coeffs, - order=coeff_stream._approximate_order - order, - constant=coeff_stream._constant) + coeff_stream = Stream_exact(coeffs, order=coeff_stream._approximate_order - order, constant=coeff_stream._constant) return P.element_class(P, coeff_stream) - coeff_stream = Stream_derivative(self._coeff_stream, order, - P.is_sparse()) + coeff_stream = Stream_derivative(self._coeff_stream, order, P.is_sparse()) if vars: - coeff_stream = Stream_map_coefficients(coeff_stream, - lambda c: c.derivative(vars), - P.is_sparse()) + coeff_stream = Stream_map_coefficients(coeff_stream, lambda c: c.derivative(vars), P.is_sparse()) return P.element_class(P, coeff_stream) def integral(self, variable=None, *, constants=None): @@ -4970,8 +4858,7 @@ def integral(self, variable=None, *, constants=None): if constants is None: constants = [zero] * ZZ(variable) elif ZZ(variable) != len(constants): - raise ValueError("the number of integrations does not match" - " the number of integration constants") + raise ValueError("the number of integrations does not match" " the number of integration constants") variable = None if constants is None: constants = [] @@ -4985,27 +4872,21 @@ def integral(self, variable=None, *, constants=None): coeff_stream = self._coeff_stream if isinstance(coeff_stream, Stream_zero): if any(constants): - coeff_stream = Stream_exact([c / ZZ.prod(k for k in range(1, i+1)) - for i, c in enumerate(constants)], - order=0, - constant=zero) + coeff_stream = Stream_exact([c / ZZ.prod(k for k in range(1, i + 1)) for i, c in enumerate(constants)], order=0, constant=zero) return P.element_class(P, coeff_stream) return self - if (isinstance(coeff_stream, Stream_exact) and not coeff_stream._constant): - coeffs = [c / ZZ.prod(k for k in range(1, i+1)) - for i, c in enumerate(constants)] + if isinstance(coeff_stream, Stream_exact) and not coeff_stream._constant: + coeffs = [c / ZZ.prod(k for k in range(1, i + 1)) for i, c in enumerate(constants)] if coeff_stream._approximate_order < 0: ic = coeff_stream._initial_coefficients ao = coeff_stream._approximate_order - if nints > -ao or any(ic[-ao-nints:-ao]): + if nints > -ao or any(ic[-ao - nints : -ao]): raise ValueError(f"cannot integrate {nints} times the series {self}") if variable is not None: - coeffs = [c.integral(variable) / ZZ.prod(i+k for k in range(1, nints+1)) - for i, c in enumerate(ic[:-ao-nints], ao)] + coeffs + coeffs = [c.integral(variable) / ZZ.prod(i + k for k in range(1, nints + 1)) for i, c in enumerate(ic[: -ao - nints], ao)] + coeffs else: - coeffs = [c / ZZ.prod(i+k for k in range(1, nints+1)) - for i, c in enumerate(ic[:-ao-nints], ao)] + coeffs + coeffs = [c / ZZ.prod(i + k for k in range(1, nints + 1)) for i, c in enumerate(ic[: -ao - nints], ao)] + coeffs ic = ic[-ao:] val = ao + nints @@ -5016,11 +4897,9 @@ def integral(self, variable=None, *, constants=None): val = 0 ao = coeff_stream._approximate_order if variable: - coeffs += [c.integral(variable) / ZZ.prod(i+k for k in range(1, nints+1)) - for i, c in enumerate(ic, ao)] + coeffs += [c.integral(variable) / ZZ.prod(i + k for k in range(1, nints + 1)) for i, c in enumerate(ic, ao)] else: - coeffs += [c / ZZ.prod(i+k for k in range(1, nints+1)) - for i, c in enumerate(ic, ao)] + coeffs += [c / ZZ.prod(i + k for k in range(1, nints + 1)) for i, c in enumerate(ic, ao)] if not any(coeffs): return P.zero() coeff_stream = Stream_exact(coeffs, order=val, constant=zero) @@ -5030,9 +4909,7 @@ def integral(self, variable=None, *, constants=None): coeff_stream = Stream_integral(coeff_stream, constants, P.is_sparse()) if variable is not None: - coeff_stream = Stream_map_coefficients(coeff_stream, - lambda c: c.integral(variable), - P.is_sparse()) + coeff_stream = Stream_map_coefficients(coeff_stream, lambda c: c.integral(variable), P.is_sparse()) return P.element_class(P, coeff_stream) def approximate_series(self, prec, name=None): @@ -5073,10 +4950,12 @@ def approximate_series(self, prec, name=None): if self.valuation() < 0: from sage.rings.laurent_series_ring import LaurentSeriesRing + R = LaurentSeriesRing(S.base_ring(), name=name) n = self.valuation() return R([self[i] for i in range(n, prec)], n).add_bigoh(prec) from sage.rings.power_series_ring import PowerSeriesRing + R = PowerSeriesRing(S.base_ring(), name=name) return R([self[i] for i in range(prec)]).add_bigoh(prec) @@ -5147,6 +5026,7 @@ def polynomial(self, degree=None, name=None): if isinstance(self._coeff_stream, Stream_zero): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + return PolynomialRing(S.base_ring(), name=name).zero() if degree is None: @@ -5165,6 +5045,7 @@ def polynomial(self, degree=None, name=None): n = self.valuation() return R([self[i] for i in range(n, m)]).shift(n) from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(S.base_ring(), name=name) return R([self[i] for i in range(m)]) @@ -5228,6 +5109,7 @@ class LazyPowerSeries(LazyCauchyProductSeries): sage: g == f True """ + def is_unit(self) -> bool: """ Return whether this element is a unit in the ring. @@ -5248,7 +5130,7 @@ def is_unit(self) -> bool: sage: (-1 + 2*x + 3*x*y).is_unit() True """ - if self.is_zero(): # now 0 != 1 + if self.is_zero(): # now 0 != 1 return False return self[0].is_unit() @@ -5267,6 +5149,7 @@ def exponential(self): 1 + x + 1/2*x^2 + 1/6*x^3 + 1/24*x^4 + 1/120*x^5 + 1/720*x^6 + O(x^7) """ from sage.misc.superseded import deprecation + deprecation(32367, 'the method exponential is deprecated. Use exp instead.') return self.exp() @@ -5287,6 +5170,7 @@ def compute_coefficients(self, i): 1 + 2*z + 3*z^2 + 3*z^3 + 3*z^4 + O(z^5) """ from sage.misc.superseded import deprecation + deprecation(32367, "the method compute_coefficients obsolete and has no effect.") def _im_gens_(self, codomain, im_gens, base_map=None): @@ -5515,6 +5399,7 @@ def __call__(self, *g): # Find a good parent for the result from sage.structure.element import get_coercion_model + cm = get_coercion_model() P = cm.common_parent(self.base_ring(), *[parent(h) for h in g]) @@ -5524,15 +5409,11 @@ def __call__(self, *g): return P.zero() # g = (0, ..., 0) - if all((not isinstance(h, LazyModuleElement) and not h) - or (isinstance(h, LazyModuleElement) - and isinstance(h._coeff_stream, Stream_zero)) - for h in g): + if all((not isinstance(h, LazyModuleElement) and not h) or (isinstance(h, LazyModuleElement) and isinstance(h._coeff_stream, Stream_zero)) for h in g): return P(self[0]) # f has finite length and f != 0 - if (isinstance(coeff_stream, Stream_exact) - and not coeff_stream._constant): + if isinstance(coeff_stream, Stream_exact) and not coeff_stream._constant: # constant polynomial poly = self.polynomial() if poly.is_constant(): @@ -5546,12 +5427,14 @@ def __call__(self, *g): from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing_univariate from sage.rings.lazy_series_ring import LazySeriesRing + if not isinstance(P, LazySeriesRing): if fP._laurent_poly_ring.has_coerce_map_from(P): S = fP._laurent_poly_ring P = fP if isinstance(P, (PolynomialRing_generic, MPolynomialRing_base)): from sage.rings.lazy_series_ring import LazyPowerSeriesRing + S = P try: sparse = S.is_sparse() @@ -5560,6 +5443,7 @@ def __call__(self, *g): P = LazyPowerSeriesRing(S.base_ring(), S.variable_names(), sparse) elif isinstance(P, LaurentPolynomialRing_univariate): from sage.rings.lazy_series_ring import LazyLaurentSeriesRing + S = P P = LazyLaurentSeriesRing(S.base_ring(), S.variable_names(), fP.is_sparse()) else: @@ -5587,9 +5471,7 @@ def __call__(self, *g): if not isinstance(g0, LazyCauchyProductSeries): return P.element_class(P, Stream_compose(coeff_stream, g0, P._sparse)) - return P.element_class(P, Stream_cauchy_compose(coeff_stream, - g0._coeff_stream, - P.is_sparse())) + return P.element_class(P, Stream_cauchy_compose(coeff_stream, g0._coeff_stream, P.is_sparse())) # The arity is at least 2 gv = min(h._coeff_stream._approximate_order for h in g) @@ -5608,8 +5490,7 @@ def coefficient(n): return r sorder = coeff_stream._approximate_order - return P.element_class(P, Stream_function(coefficient, - P._sparse, sorder * gv)) + return P.element_class(P, Stream_function(coefficient, P._sparse, sorder * gv)) compose = __call__ @@ -5754,9 +5635,7 @@ def revert(self): R = P.base_ring() # we cannot assume that the last initial coefficient # and the constant differ, see stream.Stream_exact - if (coeff_stream._degree == 1 + len(coeff_stream._initial_coefficients) - and coeff_stream._constant == -R.one() - and all(c == -R.one() for c in coeff_stream._initial_coefficients)): + if coeff_stream._degree == 1 + len(coeff_stream._initial_coefficients) and coeff_stream._constant == -R.one() and all(c == -R.one() for c in coeff_stream._initial_coefficients): # self = -z/(1-z); self.revert() = -z/(1-z) return self else: @@ -5766,8 +5645,7 @@ def revert(self): # self = a + b*z; self.revert() = -a/b + 1/b * z a = coeff_stream[0] b = coeff_stream[1] - coeff_stream = Stream_exact((-a/b, 1/b), - order=0) + coeff_stream = Stream_exact((-a / b, 1 / b), order=0) return P.element_class(P, coeff_stream) if coeff_stream.order() != 1: @@ -5911,46 +5789,34 @@ def derivative(self, *args): v = gen_vars + vars d = -len(gen_vars) - if isinstance(coeff_stream, Stream_exact): # the constant should be 0 + if isinstance(coeff_stream, Stream_exact): # the constant should be 0 ao = coeff_stream._approximate_order val = max(ao + d, 0) - coeffs = [R(c).derivative(v) for c in coeff_stream._initial_coefficients[val-(ao+d):]] + coeffs = [R(c).derivative(v) for c in coeff_stream._initial_coefficients[val - (ao + d) :]] if any(coeffs): coeff_stream = Stream_exact(coeffs, order=val, constant=coeff_stream._constant) return P.element_class(P, coeff_stream) return P.zero() - coeff_stream = Stream_map_coefficients(coeff_stream, - lambda c: R(c).derivative(v), - P.is_sparse()) + coeff_stream = Stream_map_coefficients(coeff_stream, lambda c: R(c).derivative(v), P.is_sparse()) coeff_stream = Stream_shift(coeff_stream, d) return P.element_class(P, coeff_stream) - if (isinstance(coeff_stream, Stream_exact) - and not coeff_stream._constant): + if isinstance(coeff_stream, Stream_exact) and not coeff_stream._constant: if coeff_stream._degree <= order: return P.zero() if vars: - coeffs = [prod(i-k for k in range(order)) * c.derivative(vars) - for i, c in enumerate(coeff_stream._initial_coefficients, - coeff_stream._approximate_order)] + coeffs = [prod(i - k for k in range(order)) * c.derivative(vars) for i, c in enumerate(coeff_stream._initial_coefficients, coeff_stream._approximate_order)] else: - coeffs = [prod(i-k for k in range(order)) * c - for i, c in enumerate(coeff_stream._initial_coefficients, - coeff_stream._approximate_order)] + coeffs = [prod(i - k for k in range(order)) * c for i, c in enumerate(coeff_stream._initial_coefficients, coeff_stream._approximate_order)] if not any(coeffs): return P.zero() - coeff_stream = Stream_exact(coeffs, - order=coeff_stream._approximate_order - order, - constant=coeff_stream._constant) + coeff_stream = Stream_exact(coeffs, order=coeff_stream._approximate_order - order, constant=coeff_stream._constant) return P.element_class(P, coeff_stream) - coeff_stream = Stream_derivative(self._coeff_stream, order, - P.is_sparse()) + coeff_stream = Stream_derivative(self._coeff_stream, order, P.is_sparse()) if vars: - coeff_stream = Stream_map_coefficients(coeff_stream, - lambda c: c.derivative(vars), - P.is_sparse()) + coeff_stream = Stream_map_coefficients(coeff_stream, lambda c: c.derivative(vars), P.is_sparse()) return P.element_class(P, coeff_stream) def adams_operator(self, p): @@ -6182,15 +6048,13 @@ def integral(self, variable=None, *, constants=None): else: shift = 0 - if isinstance(coeff_stream, Stream_exact): # constant is 0 because arity is at least 2 + if isinstance(coeff_stream, Stream_exact): # constant is 0 because arity is at least 2 ao = coeff_stream._approximate_order coeffs = [R(c).integral(variable) for c in coeff_stream._initial_coefficients] - coeff_stream = Stream_exact(coeffs, order=ao+shift, constant=coeff_stream._constant) + coeff_stream = Stream_exact(coeffs, order=ao + shift, constant=coeff_stream._constant) return P.element_class(P, coeff_stream) - coeff_stream = Stream_map_coefficients(coeff_stream, - lambda c: c.integral(variable), - P.is_sparse()) + coeff_stream = Stream_map_coefficients(coeff_stream, lambda c: c.integral(variable), P.is_sparse()) if shift: coeff_stream = Stream_shift(coeff_stream, 1) return P.element_class(P, coeff_stream) @@ -6212,8 +6076,7 @@ def integral(self, variable=None, *, constants=None): if constants is None: constants = [zero] * ZZ(variable) elif ZZ(variable) != len(constants): - raise ValueError("the number of integrations does not match" - " the number of integration constants") + raise ValueError("the number of integrations does not match" " the number of integration constants") variable = None if constants is None: constants = [] @@ -6226,26 +6089,20 @@ def integral(self, variable=None, *, constants=None): if isinstance(coeff_stream, Stream_zero): if any(constants): - coeff_stream = Stream_exact([c / ZZ.prod(k for k in range(1, i+1)) - for i, c in enumerate(constants)], - order=0, - constant=zero) + coeff_stream = Stream_exact([c / ZZ.prod(k for k in range(1, i + 1)) for i, c in enumerate(constants)], order=0, constant=zero) return P.element_class(P, coeff_stream) return self - if (isinstance(coeff_stream, Stream_exact) and not coeff_stream._constant): - coeffs = [c / ZZ.prod(k for k in range(1, i+1)) - for i, c in enumerate(constants)] + if isinstance(coeff_stream, Stream_exact) and not coeff_stream._constant: + coeffs = [c / ZZ.prod(k for k in range(1, i + 1)) for i, c in enumerate(constants)] coeffs += [zero] * coeff_stream._approximate_order ic = coeff_stream._initial_coefficients ao = coeff_stream._approximate_order if variable: - coeffs += [c.integral(variable) / ZZ.prod(i+k for k in range(1, nints+1)) - for i, c in enumerate(ic, ao)] + coeffs += [c.integral(variable) / ZZ.prod(i + k for k in range(1, nints + 1)) for i, c in enumerate(ic, ao)] else: - coeffs += [c / ZZ.prod(i+k for k in range(1, nints+1)) - for i, c in enumerate(ic, ao)] + coeffs += [c / ZZ.prod(i + k for k in range(1, nints + 1)) for i, c in enumerate(ic, ao)] if not any(coeffs): return P.zero() coeff_stream = Stream_exact(coeffs, order=0, constant=zero) @@ -6255,9 +6112,7 @@ def integral(self, variable=None, *, constants=None): coeff_stream = Stream_integral(coeff_stream, constants, P.is_sparse()) if variable is not None: - coeff_stream = Stream_map_coefficients(coeff_stream, - lambda c: c.integral(variable), - P.is_sparse()) + coeff_stream = Stream_map_coefficients(coeff_stream, lambda c: c.integral(variable), P.is_sparse()) return P.element_class(P, coeff_stream) def _format_series(self, formatter, format_strings=False): @@ -6304,6 +6159,7 @@ def _format_series(self, formatter, format_strings=False): from sage.misc.repr import repr_lincomb from sage.typeset.symbols import ascii_left_parenthesis, ascii_right_parenthesis from sage.typeset.symbols import unicode_left_parenthesis, unicode_right_parenthesis + if formatter == repr: poly = repr_lincomb([(1, m) for m in mons + bigO], strip_one=True) elif formatter == latex: @@ -6312,21 +6168,23 @@ def _format_series(self, formatter, format_strings=False): if atomic_repr: poly = ascii_art(*(mons + bigO), sep=" + ") else: + def parenthesize(m): a = ascii_art(m) h = a.height() - return ascii_art(ascii_left_parenthesis.character_art(h), - a, ascii_right_parenthesis.character_art(h)) + return ascii_art(ascii_left_parenthesis.character_art(h), a, ascii_right_parenthesis.character_art(h)) + poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep=" + ") elif formatter == unicode_art: if atomic_repr: poly = unicode_art(*(mons + bigO), sep=" + ") else: + def parenthesize(m): a = unicode_art(m) h = a.height() - return unicode_art(unicode_left_parenthesis.character_art(h), - a, unicode_right_parenthesis.character_art(h)) + return unicode_art(unicode_left_parenthesis.character_art(h), a, unicode_right_parenthesis.character_art(h)) + poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep=" + ") return poly @@ -6380,6 +6238,7 @@ def polynomial(self, degree=None, names=None): -z^2 + z """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + S = self.parent() if names is None: names = S.variable_names() @@ -6388,8 +6247,7 @@ def polynomial(self, degree=None, names=None): return R.zero() if degree is None: - if (isinstance(self._coeff_stream, Stream_exact) - and not self._coeff_stream._constant): + if isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: m = self._coeff_stream._degree else: raise ValueError("not a polynomial") @@ -6433,9 +6291,10 @@ def add_bigoh(self, prec): over Rational Field """ from sage.rings.power_series_ring import PowerSeriesRing + P = self.parent() PSR = PowerSeriesRing(P.base_ring(), names=P.variable_names()) - return PSR(self.polynomial(degree=prec-1), prec=prec) + return PSR(self.polynomial(degree=prec - 1), prec=prec) O = add_bigoh @@ -6495,6 +6354,7 @@ class LazyPowerSeries_gcd_mixin: """ A lazy power series that also implements the GCD algorithm. """ + def gcd(self, other): r""" Return the greatest common divisor of ``self`` and ``other``. @@ -6601,9 +6461,7 @@ def xgcd(self, f): # we multiply f by the generator to avoid any cancellations unit = (self + f.shift(1)).shift(-val) unit = ~unit - return (x**val, - unit, - unit * x) + return (x**val, unit, unit * x) unit = ~unit return (x**val, unit, unit) @@ -6612,6 +6470,7 @@ class LazyCompletionGradedAlgebraElement(LazyCauchyProductSeries): """ An element of a completion of a graded algebra that is computed lazily. """ + def _format_series(self, formatter, format_strings=False): r""" Return nonzero ``self`` formatted by ``formatter``. @@ -6659,6 +6518,7 @@ def _format_series(self, formatter, format_strings=False): from sage.misc.repr import repr_lincomb from sage.typeset.symbols import ascii_left_parenthesis, ascii_right_parenthesis from sage.typeset.symbols import unicode_left_parenthesis, unicode_right_parenthesis + if formatter == repr: poly = repr_lincomb([(1, m) for m in mons + bigO], strip_one=True) elif formatter == latex: @@ -6667,21 +6527,23 @@ def _format_series(self, formatter, format_strings=False): if atomic_repr: poly = ascii_art(*(mons + bigO), sep=" + ") else: + def parenthesize(m): a = ascii_art(m) h = a.height() - return ascii_art(ascii_left_parenthesis.character_art(h), - a, ascii_right_parenthesis.character_art(h)) + return ascii_art(ascii_left_parenthesis.character_art(h), a, ascii_right_parenthesis.character_art(h)) + poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep=" + ") elif formatter == unicode_art: if atomic_repr: poly = unicode_art(*(mons + bigO), sep=" + ") else: + def parenthesize(m): a = unicode_art(m) h = a.height() - return unicode_art(unicode_left_parenthesis.character_art(h), - a, unicode_right_parenthesis.character_art(h)) + return unicode_art(unicode_left_parenthesis.character_art(h), a, unicode_right_parenthesis.character_art(h)) + poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep=" + ") return poly @@ -6696,6 +6558,7 @@ class LazySymmetricFunction(LazyCompletionGradedAlgebraElement): sage: s = SymmetricFunctions(ZZ).s() # needs sage.modules sage: L = LazySymmetricFunctions(s) # needs sage.modules """ + def is_unit(self): """ Return whether this element is a unit in the ring. @@ -6715,7 +6578,7 @@ def is_unit(self): sage: L(2 + 3*m[1]).is_unit() True """ - if self.is_zero(): # now 0 != 1 + if self.is_zero(): # now 0 != 1 return False return self[0].is_unit() @@ -6859,6 +6722,7 @@ def __call__(self, *args): # Find a good parent for the result from sage.structure.element import get_coercion_model + cm = get_coercion_model() P = cm.common_parent(self.base_ring(), *[parent(h) for h in args]) @@ -6867,10 +6731,7 @@ def __call__(self, *args): return P.zero() # g = (0, ..., 0) - if all((not isinstance(h, LazyModuleElement) and not h) - or (isinstance(h, LazyModuleElement) - and isinstance(h._coeff_stream, Stream_zero)) - for h in args): + if all((not isinstance(h, LazyModuleElement) and not h) or (isinstance(h, LazyModuleElement) and isinstance(h._coeff_stream, Stream_zero)) for h in args): f = self[0] # FIXME: TypeError: unable to convert 0 to a rational if f: @@ -6879,15 +6740,13 @@ def __call__(self, *args): if len(args) == 1: g = args[0] - if (isinstance(self._coeff_stream, Stream_exact) - and not self._coeff_stream._constant): + if isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: if not isinstance(g, LazySymmetricFunction): f = self.symmetric_function() return f(g) - if (isinstance(g._coeff_stream, Stream_exact) - and not g._coeff_stream._constant): + if isinstance(g._coeff_stream, Stream_exact) and not g._coeff_stream._constant: f = self.symmetric_function() gs = g.symmetric_function() return P(f(gs)) @@ -6896,12 +6755,12 @@ def __call__(self, *args): R = P._laurent_poly_ring else: from sage.rings.lazy_series_ring import LazySymmetricFunctions + R = g.parent() P = LazySymmetricFunctions(R) g = P(g) - if not (isinstance(self._coeff_stream, Stream_exact) - and not self._coeff_stream._constant): + if not (isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant): if g._coeff_stream._approximate_order == 0: if not g._coeff_stream.is_uninitialized() and g[0]: raise ValueError("can only compose with a positive valuation series") @@ -6910,9 +6769,8 @@ def __call__(self, *args): if P._arity == 1: ps = R.realization_of().p() else: - ps = tensor([R._sets[0].realization_of().p()]*P._arity) - coeff_stream = Stream_plethysm(self._coeff_stream, g._coeff_stream, - P.is_sparse(), ps, R) + ps = tensor([R._sets[0].realization_of().p()] * P._arity) + coeff_stream = Stream_plethysm(self._coeff_stream, g._coeff_stream, P.is_sparse(), ps, R) return P.element_class(P, coeff_stream) raise NotImplementedError("only implemented for arity 1") @@ -7002,15 +6860,12 @@ def revert(self): if isinstance(coeff_stream, Stream_zero): raise ValueError("compositional inverse does not exist") R = P._laurent_poly_ring - if (isinstance(coeff_stream, Stream_exact) - and coeff_stream.order() >= 0 - and coeff_stream._degree == 2): + if isinstance(coeff_stream, Stream_exact) and coeff_stream.order() >= 0 and coeff_stream._degree == 2: # self = a + b * p_1; self.revert() = -a/b + 1/b * p_1 a = coeff_stream[0] b = coeff_stream[1][Partition([1])] X = R(Partition([1])) - coeff_stream = Stream_exact((-a/b, 1/b * X), - order=0) + coeff_stream = Stream_exact((-a / b, 1 / b * X), order=0) return P.element_class(P, coeff_stream) # TODO: coefficients should not be checked here, it prevents @@ -7146,9 +7001,7 @@ def derivative_with_respect_to_p1(self, n=1): if P._arity != 1: raise ValueError("arity must be equal to 1") - coeff_stream = Stream_map_coefficients(self._coeff_stream, - lambda c: c.derivative_with_respect_to_p1(n), - P.is_sparse()) + coeff_stream = Stream_map_coefficients(self._coeff_stream, lambda c: c.derivative_with_respect_to_p1(n), P.is_sparse()) coeff_stream = Stream_shift(coeff_stream, -n) return P.element_class(P, coeff_stream) @@ -7171,9 +7024,7 @@ def suspension(self): s[1] + s[2] + s[3] + s[4] + s[5] + ... """ P = self.parent() - coeff_stream = Stream_map_coefficients(self._coeff_stream, - lambda c: (-1)**(c.degree() + 1) * c.omega(), - P.is_sparse()) + coeff_stream = Stream_map_coefficients(self._coeff_stream, lambda c: (-1) ** (c.degree() + 1) * c.omega(), P.is_sparse()) return P.element_class(P, coeff_stream) def functorial_composition(self, *args): @@ -7298,8 +7149,8 @@ def functorial_composition(self, *args): if len(args) != self.parent()._arity: raise ValueError("arity must be equal to the number of arguments provided") from sage.combinat.sf.sfa import SymmetricFunctionAlgebra_generic - if not all(isinstance(g, (LazySymmetricFunction, SymmetricFunctionAlgebra_generic.Element)) - or not g for g in args): + + if not all(isinstance(g, (LazySymmetricFunction, SymmetricFunctionAlgebra_generic.Element)) or not g for g in args): raise ValueError("all arguments must be (possibly lazy) symmetric functions") if len(args) == 1: @@ -7309,6 +7160,7 @@ def functorial_composition(self, *args): R = P._laurent_poly_ring else: from sage.rings.lazy_series_ring import LazySymmetricFunctions + R = g.parent() P = LazySymmetricFunctions(R) g = P(g) @@ -7323,7 +7175,7 @@ def g_cycle_type(s, n): # with cycle type s, which is a partition of n if not n: if g[0]: - return Partition([1]*ZZ(g[0].coefficient([]))) + return Partition([1] * ZZ(g[0].coefficient([]))) return Partition([]) g_n = g[n] @@ -7334,8 +7186,7 @@ def g_cycle_type(s, n): res = [] # k is the length of a cycle in G[sigma], and # n! g_n([1]*n) is the number of elements in G[n] - for k in range(1, 1 + min(lcm(s), - ZZ(factorial(n) * g_n.coefficient([1]*n)))): + for k in range(1, 1 + min(lcm(s), ZZ(factorial(n) * g_n.coefficient([1] * n)))): e = 0 for d in divisors(k): m = moebius(d) @@ -7509,8 +7360,8 @@ def arithmetic_product(self, *args): if len(args) != self.parent()._arity: raise ValueError("arity must be equal to the number of arguments provided") from sage.combinat.sf.sfa import SymmetricFunctionAlgebra_generic - if not all(isinstance(g, (LazySymmetricFunction, SymmetricFunctionAlgebra_generic.Element)) - or not g for g in args): + + if not all(isinstance(g, (LazySymmetricFunction, SymmetricFunctionAlgebra_generic.Element)) or not g for g in args): raise ValueError("all arguments must be (possibly lazy) symmetric functions") if len(args) == 1: @@ -7518,21 +7369,16 @@ def arithmetic_product(self, *args): P = g.parent() # f = 0 or g = (0, ..., 0) - if (isinstance(self._coeff_stream, Stream_zero) - or (not isinstance(g, LazyModuleElement) and not g) - or (isinstance(g, LazyModuleElement) - and isinstance(g._coeff_stream, Stream_zero))): + if isinstance(self._coeff_stream, Stream_zero) or (not isinstance(g, LazyModuleElement) and not g) or (isinstance(g, LazyModuleElement) and isinstance(g._coeff_stream, Stream_zero)): return P.zero() - if (isinstance(self._coeff_stream, Stream_exact) - and not self._coeff_stream._constant): + if isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: if not isinstance(g, LazySymmetricFunction): f = self.symmetric_function() return f.arithmetic_product(g) - if (isinstance(g._coeff_stream, Stream_exact) - and not g._coeff_stream._constant): + if isinstance(g._coeff_stream, Stream_exact) and not g._coeff_stream._constant: f = self.symmetric_function() gs = g.symmetric_function() return P(f.arithmetic_product(gs)) @@ -7541,6 +7387,7 @@ def arithmetic_product(self, *args): R = P._laurent_poly_ring else: from sage.rings.lazy_series_ring import LazySymmetricFunctions + R = g.parent() P = LazySymmetricFunctions(R) g = P(g) @@ -7550,13 +7397,11 @@ def arithmetic_product(self, *args): # TODO: this should be done lazily if possible c = R.zero() if self[0]: - if (isinstance(g._coeff_stream, Stream_exact) - and not g._coeff_stream._constant): + if isinstance(g._coeff_stream, Stream_exact) and not g._coeff_stream._constant: gs = g.symmetric_function() c += self[0].arithmetic_product(gs) if g[0]: - if (isinstance(self._coeff_stream, Stream_exact) - and not self._coeff_stream._constant): + if isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: fs = self.symmetric_function() c += fs.arithmetic_product(g[0]) @@ -7569,8 +7414,7 @@ def coefficient(n): if not n: return c index_set = ((d, n // d) for d in divisors(n)) - return sum(f[i].arithmetic_product(g[j]) - for i, j in index_set if f[i] and g[j]) + return sum(f[i].arithmetic_product(g[j]) for i, j in index_set if f[i] and g[j]) coeff_stream = Stream_function(coefficient, P._sparse, 0) return P.element_class(P, coeff_stream) @@ -7632,8 +7476,7 @@ def symmetric_function(self, degree=None): return R.zero() if degree is None: - if (isinstance(self._coeff_stream, Stream_exact) - and not self._coeff_stream._constant): + if isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: m = self._coeff_stream._degree else: raise ValueError("not a symmetric function") @@ -7664,6 +7507,7 @@ class LazyDirichletSeries(LazyModuleElement): sage: g == f True """ + def is_unit(self): """ Return whether this element is a unit in the ring. @@ -7684,7 +7528,7 @@ def is_unit(self): sage: D([3, 2]).is_unit() True """ - if self.is_zero(): # now 0 != 1 + if self.is_zero(): # now 0 != 1 return False return self[1].is_unit() @@ -7712,6 +7556,7 @@ def valuation(self): if isinstance(self._coeff_stream, Stream_zero): return self._coeff_stream.order() from sage.functions.log import log + return log(ZZ(self._coeff_stream.order())) def _mul_(self, other): @@ -7772,20 +7617,14 @@ def _mul_(self, other): return self if isinstance(right, Stream_zero): return other - if (isinstance(left, Stream_exact) - and not left._constant - and left._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) - and left.order() == 1): + if isinstance(left, Stream_exact) and not left._constant and left._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) and left.order() == 1: return other # self == 1 - if (isinstance(right, Stream_exact) - and not right._constant - and right._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) - and right.order() == 1): + if isinstance(right, Stream_exact) and not right._constant and right._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) and right.order() == 1: return self # other == 1 coeff = Stream_dirichlet_convolve(left, right, P.is_sparse()) # Performing exact arithmetic is slow because the series grow large # very quickly as we are multiplying the degree - #if (isinstance(left, Stream_exact) and not left._constant + # if (isinstance(left, Stream_exact) and not left._constant # and isinstance(right, Stream_exact) and not right._constant): # # Product of finite length Dirichlet series, # # so the result has finite length @@ -7825,8 +7664,7 @@ def __invert__(self): ZeroDivisionError: rational division by zero """ P = self.parent() - return P.element_class(P, Stream_dirichlet_invert(self._coeff_stream, - P.is_sparse())) + return P.element_class(P, Stream_dirichlet_invert(self._coeff_stream, P.is_sparse())) def __call__(self, p): r""" @@ -7900,17 +7738,17 @@ def __call__(self, p): # Special behavior for finite series if isinstance(coeff_stream, Stream_exact): from sage.rings.cc import CC + if not coeff_stream._constant: try: - return sum(self[k] * ~(ZZ(k)**p) - for k in range(1, coeff_stream._degree)) + return sum(self[k] * ~(ZZ(k) ** p) for k in range(1, coeff_stream._degree)) except (ValueError, TypeError, ArithmeticError): pass elif p in CC: from sage.functions.transcendental import zeta + C = coeff_stream._constant - ret = sum((self[k] - C) * ~(ZZ(k)**p) - for k in range(1, coeff_stream._degree)) + ret = sum((self[k] - C) * ~(ZZ(k) ** p) for k in range(1, coeff_stream._degree)) return ret + C * zeta(p) R = PolynomialRing(ZZ, P.variable_name()) @@ -7928,6 +7766,7 @@ def coefficient(m): return coeff_stream[n] * n ** (-b) except ValueError: return ZZ.zero() + R = P._internal_poly_ring.base_ring() return P.element_class(P, Stream_function(coefficient, P._sparse, 1)) @@ -7990,6 +7829,7 @@ def _format_series(self, formatter, format_strings=False): from sage.typeset.unicode_art import unicode_art from sage.typeset.ascii_art import ascii_art from sage.misc.repr import repr_lincomb + if formatter == repr: poly = repr_lincomb([(1, mo) for mo in mons + bigO], strip_one=True) elif formatter == latex: @@ -8004,11 +7844,12 @@ def _format_series(self, formatter, format_strings=False): if atomic_repr: poly = formatter(*(mons + bigO), sep=" + ") else: + def parenthesize(m): a = formatter(m) h = a.height() - return formatter(left_paren.character_art(h), - a, right_paren.character_art(h)) + return formatter(left_paren.character_art(h), a, right_paren.character_art(h)) + poly = formatter(*([parenthesize(mo) for mo in mons] + bigO), sep=" + ") return poly @@ -8018,6 +7859,7 @@ class LazyPseudoDifferentialOperator(LazyModuleElement): """ A pseudo-differential operator whose coefficients are computed lazily. """ + def _latex_(self): r""" Return a latex representation of ``self``. @@ -8074,6 +7916,7 @@ def _latex_(self): + \frac{\partial^{2}}{(\partial x)^{2}}f\left(x\right) """ from sage.misc.latex import latex + if isinstance(self._coeff_stream, Stream_zero): return latex('0') if self._coeff_stream.is_uninitialized(): @@ -8172,9 +8015,9 @@ def _format_series(self, formatter, format_strings=False): base = "D{}".format(repr(P._variable)) ret = ret.replace("PARTIAL^-1", base) - ret = ret.replace("PARTIAL^-", base+"^") - ret = ret.replace("PARTIAL^", base+"^-") - ret = ret.replace("PARTIAL", base+"^-1") + ret = ret.replace("PARTIAL^-", base + "^") + ret = ret.replace("PARTIAL^", base + "^-") + ret = ret.replace("PARTIAL", base + "^-1") return ret def valuation(self): @@ -8250,26 +8093,21 @@ def _mul_(self, other): # Check some trivial products if isinstance(left, Stream_zero) or isinstance(right, Stream_zero): return P.zero() - if (isinstance(left, Stream_exact) and left.order() == 0 - and len(left._initial_coefficients) == 1 and (not left._constant)): - c, = left._initial_coefficients + if isinstance(left, Stream_exact) and left.order() == 0 and len(left._initial_coefficients) == 1 and (not left._constant): + (c,) = left._initial_coefficients if left._initial_coefficients[0] == P._internal_poly_ring.base_ring().one(): return other # self == 1 # left has no derivatives if isinstance(right, Stream_exact): initial_coefficients = [c * val for val in right._initial_coefficients] - coeff_stream = Stream_exact(initial_coefficients, order=right.order(), - constant=right._constant) + coeff_stream = Stream_exact(initial_coefficients, order=right.order(), constant=right._constant) else: coeff_stream = Stream_rmul(right, c, P.is_sparse()) return P.element_class(P, coeff_stream) - if (isinstance(right, Stream_exact) and (not right._constant) - and right._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) - and right.order() == 0): + if isinstance(right, Stream_exact) and (not right._constant) and right._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) and right.order() == 0: return self # right == 1 - if (isinstance(left, Stream_exact) and isinstance(right, Stream_exact) - and (not right._constant)): + if isinstance(left, Stream_exact) and isinstance(right, Stream_exact) and (not right._constant): # Strictly speaking, if both elements are finite sums with coefficients # of other being polynomials (i.e., \partial_x^N c(x) = 0 for some N), # or the differentials are all positive on left, then the resulting @@ -8280,20 +8118,16 @@ def _mul_(self, other): if not any(c.derivative(P._variable) for c in right._initial_coefficients): il = left._initial_coefficients ir = right._initial_coefficients - initial_coefficients = [sum(il[k]*ir[n-k] - for k in range(max(n - len(ir) + 1, 0), - min(len(il) - 1, n) + 1)) - for n in range(len(il) + len(ir) - 1)] + initial_coefficients = [sum(il[k] * ir[n - k] for k in range(max(n - len(ir) + 1, 0), min(len(il) - 1, n) + 1)) for n in range(len(il) + len(ir) - 1)] lv = left.order() rv = right.order() if not any(initial_coefficients): return P.zero() - coeff_stream = Stream_exact(initial_coefficients, - order=lv+rv, - constant=left._constant) + coeff_stream = Stream_exact(initial_coefficients, order=lv + rv, constant=left._constant) return P.element_class(P, coeff_stream) if left._degree <= 1: from sage.functions.other import binomial + R = P._internal_poly_ring dx = R.gen() lpd = left._polynomial_part(R).dict() @@ -8302,17 +8136,14 @@ def _mul_(self, other): temp = R.zero() for deg, a in lpd.items(): for i in range(len(ir)): - temp += R([a * binomial(-deg,j) * ir[i].derivative(P._variable, j) - for j in range(-deg,-1,-1)]).shift(-(rv+i)) - #temp += (a * R.sum(binomial(-deg,j) * ir[i].derivative(P._variable, j) * dx**(-deg-j) + temp += R([a * binomial(-deg, j) * ir[i].derivative(P._variable, j) for j in range(-deg, -1, -1)]).shift(-(rv + i)) + # temp += (a * R.sum(binomial(-deg,j) * ir[i].derivative(P._variable, j) * dx**(-deg-j) # for j in range(-deg+1))).shift(-(rv+i)) if not temp: return P.zero() initial_coefficients = list(temp) initial_coefficients.reverse() - coeff_stream = Stream_exact(initial_coefficients, - order=left.order()+rv, - constant=left._constant) + coeff_stream = Stream_exact(initial_coefficients, order=left.order() + rv, constant=left._constant) return P.element_class(P, coeff_stream) coeff_stream = Stream_pseudo_diff_mul(left, right, P._variable, P.is_sparse()) @@ -8365,16 +8196,15 @@ def __invert__(self): X = P._variable BR = P._laurent_poly_ring if len(cs._initial_coefficients) == 1 and cs.order() == 0: # in the base ring - coeff, = BR(cs._initial_coefficients) + (coeff,) = BR(cs._initial_coefficients) return P.element_class(P, Stream_exact([coeff.inverse_of_unit()], 0)) # generic case - if (all(not BR(coeff).derivative(X) for coeff in cs._initial_coefficients) - and not BR(cs._constant).derivative(X)): + if all(not BR(coeff).derivative(X) for coeff in cs._initial_coefficients) and not BR(cs._constant).derivative(X): return LazyCauchyProductSeries.__invert__(self) X = P.undefined(valuation=-self.valuation()) - P.define_implicitly([X], [X*self - 1]) + P.define_implicitly([X], [X * self - 1]) return X def is_unit(self): @@ -8395,7 +8225,7 @@ def is_unit(self): sage: f.is_unit() True """ - if self.is_zero(): # now 0 != 1 + if self.is_zero(): # now 0 != 1 return False return self[self.valuation()].is_unit() @@ -8436,11 +8266,9 @@ def __pow__(self, n): BR = P._laurent_poly_ring lc = temp[0] cs = self._coeff_stream - if (isinstance(cs, Stream_exact) and (not cs._constant) - and len(cs._initial_coefficients) == 1): + if isinstance(cs, Stream_exact) and (not cs._constant) and len(cs._initial_coefficients) == 1: # This is known to be a monomial (which is not 1) - return P.element_class(P, Stream_exact([BR(lc**n)], order=ZZ(val*n), - constant=cs._constant)) + return P.element_class(P, Stream_exact([BR(lc**n)], order=ZZ(val * n), constant=cs._constant)) assert lc and temp.valuation() == 0 # should be the leading coefficient if lc == BR.one(): @@ -8483,7 +8311,7 @@ def nth_root(self, n): try: lcr = lc.nth_root(n) except AttributeError: - lcr = BR(lc ** ~n) + lcr = BR(lc**~n) # We are effectively implementing this: # X = P.undefined(valuation=self.valuation()/n) @@ -8497,13 +8325,15 @@ def nth_root(self, n): # TODO: Compute an explicit formula for each coefficient so we do not # need to solve the system of equations (recursively). from sage.symbolic.ring import SR + DUMMY = SR.var("DUMMY") from sage.rings.lazy_series_ring import LazyPseudoDifferentialOperatorRing from sage.symbolic.function_factory import function as SRfunc + generic = LazyPseudoDifferentialOperatorRing(DUMMY) v = val // n F = generic(lambda n: SRfunc(f"DUM{n-v}")(DUMMY), valuation=v) - temp = F ** n + temp = F**n computed = {F[v]: lcr} def coefficient(n): @@ -8512,15 +8342,14 @@ def coefficient(n): if n == v: return lcr i = n - v - if F[v+i-1] not in computed: - coefficient(n-1) - if F[v+i] in computed: - return computed[F[v+i]] - computed[F[v+i]] = 0 - computed.update({F[v+i-j].derivative(DUMMY, j): computed[F[v+i-j].derivative(DUMMY, j-1)].derivative(P._variable) - for j in range(1,i+1)}) - computed[F[v+i]] = (self[val+i] - SR(temp[val+i]).substitute(computed)) * divcoeff - return BR(computed[F[v+i]]) + if F[v + i - 1] not in computed: + coefficient(n - 1) + if F[v + i] in computed: + return computed[F[v + i]] + computed[F[v + i]] = 0 + computed.update({F[v + i - j].derivative(DUMMY, j): computed[F[v + i - j].derivative(DUMMY, j - 1)].derivative(P._variable) for j in range(1, i + 1)}) + computed[F[v + i]] = (self[val + i] - SR(temp[val + i]).substitute(computed)) * divcoeff + return BR(computed[F[v + i]]) # We make the result dense as we need to compute all coefficients anyways cs = Stream_function(coefficient, False, v) @@ -8574,6 +8403,4 @@ def star(self): m = infinity mone = -ZZ.one() R = P._laurent_poly_ring - return P.sum(lambda k: (P.element_class(P, Stream_exact([R.one()], constant=R.zero(), order=k)) - * P(mone**k * self[k])), - self.valuation(), m) + return P.sum(lambda k: (P.element_class(P, Stream_exact([R.one()], constant=R.zero(), order=k)) * P(mone**k * self[k])), self.valuation(), m) diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index dd2b5cb7eb9..cff8ae3ffdd 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -65,8 +65,7 @@ from sage.categories.unique_factorization_domains import UniqueFactorizationDomains from sage.categories.integral_domains import IntegralDomains from sage.categories.fields import Fields -from sage.categories.complete_discrete_valuation import (CompleteDiscreteValuationFields, - CompleteDiscreteValuationRings) +from sage.categories.complete_discrete_valuation import CompleteDiscreteValuationFields, CompleteDiscreteValuationRings from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute @@ -75,24 +74,10 @@ from sage.rings.infinity import infinity from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.lazy_series import (LazyModuleElement, - LazyLaurentSeries, - LazyPowerSeries, - LazyPowerSeries_gcd_mixin, - LazyCompletionGradedAlgebraElement, - LazySymmetricFunction, - LazyDirichletSeries, - LazyPseudoDifferentialOperator) +from sage.rings.lazy_series import LazyModuleElement, LazyLaurentSeries, LazyPowerSeries, LazyPowerSeries_gcd_mixin, LazyCompletionGradedAlgebraElement, LazySymmetricFunction, LazyDirichletSeries, LazyPseudoDifferentialOperator from sage.structure.global_options import GlobalOptions -from sage.data_structures.stream import ( - Stream_zero, - Stream_function, - Stream_iterator, - Stream_exact, - Stream_uninitialized, - Stream_taylor -) +from sage.data_structures.stream import Stream_zero, Stream_function, Stream_iterator, Stream_exact, Stream_uninitialized, Stream_taylor from types import GeneratorType @@ -101,6 +86,7 @@ class LazySeriesRing(UniqueRepresentation, Parent): """ Abstract base class for lazy series. """ + _twisted_base_ring_multiplication = False # This will never be called directly (as it is an ABC), but we copy it @@ -118,6 +104,7 @@ def __classcall_private__(cls, base_ring, names, sparse=True, *args, **kwds): True """ from sage.structure.category_object import normalize_names + names = normalize_names(-1, names) return super().__classcall__(cls, base_ring, names, sparse, *args, **kwds) @@ -515,8 +502,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No coeff_stream = Stream_exact([], order=degree, constant=constant) return self.element_class(self, coeff_stream) initial_coefficients = [x[i] for i in range(x.valuation(), x.degree() + 1)] - coeff_stream = Stream_exact(initial_coefficients, - order=x.valuation(), degree=degree, constant=constant) + coeff_stream = Stream_exact(initial_coefficients, order=x.valuation(), degree=degree, constant=constant) return self.element_class(self, coeff_stream) # Handle when it is a lazy series @@ -540,15 +526,14 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No x_val = x._coeff_stream.order() if not valuation: valuation = x_val - initial_coefficients = [x[x_val+i] for i in range(degree-valuation)] + initial_coefficients = [x[x_val + i] for i in range(degree - valuation)] if not any(initial_coefficients): if not constant: return self.zero() # We learned some stuff about x; pass it along x._coeff_stream._approximate_order += len(initial_coefficients) initial_coefficients = [] - coeff_stream = Stream_exact(initial_coefficients, - order=valuation, degree=degree, constant=constant) + coeff_stream = Stream_exact(initial_coefficients, order=valuation, degree=degree, constant=constant) return self.element_class(self, coeff_stream) # We are just possibly shifting the result @@ -578,10 +563,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No else: valuation += len(coeffs) coeffs = [] - return self(coeffs, - degree=stream._degree, - constant=BR(stream._constant), - valuation=valuation) + return self(coeffs, degree=stream._degree, constant=BR(stream._constant), valuation=valuation) elif x.parent()._arity == 1: return self.element_class(self, stream) raise ValueError(f"unable to convert {x} into {self}") @@ -1062,19 +1044,11 @@ def define_implicitly(self, series, equations, max_lookahead=1): sage: A O(x^7) """ - s = [a[0]._coeff_stream if isinstance(a, (tuple, list)) - else a._coeff_stream - for a in series] - ics = [a[1] if isinstance(a, (tuple, list)) - else [] - for a in series] + s = [a[0]._coeff_stream if isinstance(a, (tuple, list)) else a._coeff_stream for a in series] + ics = [a[1] if isinstance(a, (tuple, list)) else [] for a in series] eqs = [eq._coeff_stream for eq in equations] for f, ic in zip(s, ics): - f.define_implicitly(s, ic, eqs, - self.base_ring(), - self._internal_poly_ring.base_ring(), - self._terms_of_degree, - max_lookahead=max_lookahead) + f.define_implicitly(s, ic, eqs, self.base_ring(), self._internal_poly_ring.base_ring(), self._terms_of_degree, max_lookahead=max_lookahead) class options(GlobalOptions): r""" @@ -1121,20 +1095,13 @@ class options(GlobalOptions): sage: LazyLaurentSeriesRing.options.display_length 7 """ + NAME = 'lazy series rings' module = 'sage.rings.lazy_series_ring' - display_length = dict(default=7, - description='the number of coefficients to display from the valuation', - checker=lambda x: x in ZZ and x > 0) - constant_length = dict(default=3, - description='the number of coefficients to display for nonzero constant series', - checker=lambda x: x in ZZ and x > 0) - halting_precision = dict(default=None, - description='the number of coefficients, beginning with the approximate valuation, to check in equality tests', - checker=lambda x: x is None or x in ZZ and x > 0) - secure = dict(default=False, - description='whether to raise an error when a comparison is unknown', - checker=lambda x: x is True or x is False) + display_length = dict(default=7, description='the number of coefficients to display from the valuation', checker=lambda x: x in ZZ and x > 0) + constant_length = dict(default=3, description='the number of coefficients to display for nonzero constant series', checker=lambda x: x in ZZ and x > 0) + halting_precision = dict(default=None, description='the number of coefficients, beginning with the approximate valuation, to check in equality tests', checker=lambda x: x is None or x in ZZ and x > 0) + secure = dict(default=False, description='whether to raise an error when a comparison is unknown', checker=lambda x: x is True or x is False) @cached_method def one(self): @@ -1259,8 +1226,7 @@ def _coerce_map_from_(self, S): if R.has_coerce_map_from(S): return True - if (isinstance(S, LazySeriesRing) - and self._laurent_poly_ring.has_coerce_map_from(S._laurent_poly_ring)): + if isinstance(S, LazySeriesRing) and self._laurent_poly_ring.has_coerce_map_from(S._laurent_poly_ring): return True return None @@ -1411,10 +1377,11 @@ def prod(self, f, a=None, b=infinity, add_one=False): elif a in ZZ: if b != infinity: if add_one: - return super().prod(self.one() + f(i) for i in range(a, b+1)) - return super().prod(f(i) for i in range(a, b+1)) + return super().prod(self.one() + f(i) for i in range(a, b + 1)) + return super().prod(f(i) for i in range(a, b + 1)) from sage.sets.non_negative_integers import NonNegativeIntegers - it = (f(i+a) for i in NonNegativeIntegers()) + + it = (f(i + a) for i in NonNegativeIntegers()) else: it = (f(i) for i in a) @@ -1425,6 +1392,7 @@ def prod(self, f, a=None, b=infinity, add_one=False): data = it from sage.data_structures.stream import Stream_infinite_product + coeff_stream = Stream_infinite_product(data) return self.element_class(self, coeff_stream) @@ -1505,13 +1473,15 @@ def sum(self, f, a=None, b=infinity): it = f elif a in ZZ: if b != infinity: - return super().sum(f(i) for i in range(a, b+1)) + return super().sum(f(i) for i in range(a, b + 1)) from sage.sets.non_negative_integers import NonNegativeIntegers - it = (f(i+a) for i in NonNegativeIntegers()) + + it = (f(i + a) for i in NonNegativeIntegers()) else: it = (f(i) for i in a) from sage.data_structures.stream import Stream_infinite_sum + coeff_stream = Stream_infinite_sum(it) return self.element_class(self, coeff_stream) @@ -1568,6 +1538,7 @@ def _test_div(self, **options): :class:`TestSuite` """ from sage.misc.misc import some_tuples + tester = self._tester(**options) elements = list(tester.some_elements()) @@ -1618,14 +1589,7 @@ def _test_revert(self, **options): # of x should always succeed, except if the series is # 'exact' or if it has negative valuation vx = x.valuation() - if (vx != 1 - and not (isinstance(x._coeff_stream, Stream_exact) - and ((vx == 0 - and x._coeff_stream._degree == 2 - and not x._coeff_stream._constant) - or (vx == -1 - and x._coeff_stream._degree == 0 - and not x._coeff_stream._constant)))): + if vx != 1 and not (isinstance(x._coeff_stream, Stream_exact) and ((vx == 0 and x._coeff_stream._degree == 2 and not x._coeff_stream._constant) or (vx == -1 and x._coeff_stream._degree == 0 and not x._coeff_stream._constant))): continue try: y = x.revert() @@ -1637,9 +1601,7 @@ def _test_revert(self, **options): except NotImplementedError: pass except (ValueError, TypeError): - tester.assertFalse(vx == 1 and x[vx].is_unit(), - ("the series %s should be reversible " - "- its valuation is one and its leading coefficient is a unit") % x) + tester.assertFalse(vx == 1 and x[vx].is_unit(), ("the series %s should be reversible " "- its valuation is one and its leading coefficient is a unit") % x) else: count += 1 e1 = y(x) @@ -1872,6 +1834,7 @@ class LazyLaurentSeriesRing(LazySeriesRing): sage: L.options._reset() """ + Element = LazyLaurentSeries # Follow the "generic" normalization @@ -1980,6 +1943,7 @@ def _latex_(self): \Bold{F}_{2} (\!(z)\!) """ from sage.misc.latex import latex + return latex(self.base_ring()) + r"(\!({})\!)".format(self.variable_name()) @cached_method @@ -2042,10 +2006,7 @@ def _an_element_(self): sage: L.an_element() z^-2 + z^3 + z^4 + z^5 + O(z^6) """ - return self(self._laurent_poly_ring.an_element(), - valuation=-2, - degree=3, - constant=self.base_ring().an_element()) + return self(self._laurent_poly_ring.an_element(), valuation=-2, degree=3, constant=self.base_ring().an_element()) def some_elements(self): """ @@ -2078,11 +2039,7 @@ def some_elements(self): z^-2 + z^-1 + z + z^2 + z^4 + O(z^5)] """ z = self.gen() - elts = [self.zero(), self.one(), z, (z-3)*(z**-2+2+z)**2, self.an_element(), - (1 - 2*z**-3)/(1 - z + 3*z**2), - self(lambda n: n**2, valuation=-2), - self(lambda n: n**2, valuation=1), - self([3, 2, 1], valuation=1, constant=1)] + elts = [self.zero(), self.one(), z, (z - 3) * (z**-2 + 2 + z) ** 2, self.an_element(), (1 - 2 * z**-3) / (1 - z + 3 * z**2), self(lambda n: n**2, valuation=-2), self(lambda n: n**2, valuation=1), self([3, 2, 1], valuation=1, constant=1)] return elts def series(self, coefficient, valuation, degree=None, constant=None): @@ -2160,16 +2117,14 @@ def series(self, coefficient, valuation, degree=None, constant=None): constant = self.base_ring().zero() if degree is None: degree = valuation + len(coefficient) - coeff_stream = Stream_exact(coefficient, order=valuation, - constant=constant, degree=degree) + coeff_stream = Stream_exact(coefficient, order=valuation, constant=constant, degree=degree) return self.element_class(self, coeff_stream) if degree is not None and valuation > degree and constant: raise ValueError('inappropriate valuation') t = None - t = self(lambda n: coefficient(t, n), valuation=valuation, - constant=constant, degree=degree) + t = self(lambda n: coefficient(t, n), valuation=valuation, constant=constant, degree=degree) return t def _monomial(self, c, n): @@ -2335,11 +2290,13 @@ def q_pochhammer(self, q=None): if q not in self.base_ring(): raise ValueError("q must be in the base ring") from sage.arith.misc import binomial + qP = q.parent() one = qP.one() def coeff(n): - return (-1)**n * q**binomial(n, 2) / qP.prod(one - q**i for i in range(1, n+1)) + return (-1) ** n * q ** binomial(n, 2) / qP.prod(one - q**i for i in range(1, n + 1)) + return self(coefficients=coeff, valuation=0) def euler(self): @@ -2378,12 +2335,14 @@ def euler(self): - :wikipedia:`Euler_function` """ + def coeff(n): k = ZZ(24 * n + 1) m, rem = k.sqrtrem() if rem: return ZZ.zero() return (-1) ** ((m + 1) // 6) + return self(coefficients=coeff, valuation=0) def jacobi_theta(self, w, a=0, b=0): @@ -2595,32 +2554,36 @@ def jacobi_theta(self, w, a=0, b=0): - :wikipedia:`Theta_function` """ if a == 0 and b == 0: + def coeff(n): if n == 0: return ZZ.one() nrt, rem = ZZ(n).sqrtrem() - return (w**(2*nrt) + w**(-2*nrt)) if not rem else ZZ.zero() + return (w ** (2 * nrt) + w ** (-2 * nrt)) if not rem else ZZ.zero() if a == 0 and b == 1: + def coeff(n): if n == 0: return ZZ.one() nrt, rem = ZZ(n).sqrtrem() - return (-1)**nrt * (w**(2*nrt) + w**(-2*nrt)) if not rem else ZZ.zero() + return (-1) ** nrt * (w ** (2 * nrt) + w ** (-2 * nrt)) if not rem else ZZ.zero() if a == 1 and b == 0: + def coeff(n): if n == 0: return w + ~w nrt, rem = ZZ(n).sqrtrem() - return (w**(2*nrt+1) + w**(-2*nrt-1)) if rem == nrt else ZZ.zero() + return (w ** (2 * nrt + 1) + w ** (-2 * nrt - 1)) if rem == nrt else ZZ.zero() if a == 1 and b == 1: + def coeff(n): if n == 0: return w + ~w nrt, rem = ZZ(n).sqrtrem() - return (-1)**nrt * (w**(2*nrt+1) + w**(-2*nrt-1)) if rem == nrt else ZZ.zero() + return (-1) ** nrt * (w ** (2 * nrt + 1) + w ** (-2 * nrt - 1)) if rem == nrt else ZZ.zero() return self(coefficients=coeff, valuation=0) @@ -2701,6 +2664,7 @@ def dilog(self): """ return self.polylog(2) + ###################################################################### @@ -2722,6 +2686,7 @@ class LazyPowerSeriesRing(LazySeriesRing): sage: L. = LazyPowerSeriesRing(QQ); L Multivariate Lazy Taylor Series Ring in x, y over Rational Field """ + Element = LazyPowerSeries # Follow the "generic" normalization @@ -2813,17 +2778,14 @@ def __init__(self, base_ring, names, sparse=True, category=None): if mixin_gcd: from sage.structure.dynamic_class import dynamic_class - self.Element = dynamic_class( - f"{self.Element.__name__}_gcd", - (self.Element, LazyPowerSeries_gcd_mixin), - doccls=self.Element) + + self.Element = dynamic_class(f"{self.Element.__name__}_gcd", (self.Element, LazyPowerSeries_gcd_mixin), doccls=self.Element) if base_ring.is_zero(): category = category.Finite() else: category = category.Infinite() - Parent.__init__(self, base=base_ring, names=names, - category=category) + Parent.__init__(self, base=base_ring, names=names, category=category) def construction(self): """ @@ -2839,11 +2801,10 @@ def construction(self): Sparse Univariate Polynomial Ring in t over Integer Ring) """ from sage.categories.pushout import CompletionFunctor + if self._arity == 1: - return (CompletionFunctor(self._names[0], infinity), - self._laurent_poly_ring) - return (CompletionFunctor(self._names, infinity), - self._laurent_poly_ring) + return (CompletionFunctor(self._names[0], infinity), self._laurent_poly_ring) + return (CompletionFunctor(self._names, infinity), self._laurent_poly_ring) def _repr_(self): """ @@ -2871,6 +2832,7 @@ def _latex_(self): \Bold{F}_{2} [\![z]\!] """ from sage.misc.latex import latex + generators_rep = ", ".join(self.variable_names()) return latex(self.base_ring()) + r"[\![{}]\!]".format(generators_rep) @@ -2911,8 +2873,7 @@ def _terms_of_degree(self, n, R): """ if self._arity == 1: return [R.one()] - return [m.change_ring(R) - for m in self._internal_poly_ring.base_ring().monomials_of_degree(n)] + return [m.change_ring(R) for m in self._internal_poly_ring.base_ring().monomials_of_degree(n)] @cached_method def gen(self, n=0): @@ -3097,8 +3058,8 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No if valuation < 0: raise ValueError("the valuation of a Taylor series must be nonnegative") # TODO: the following is nonsense, think of an iterator -# if self._arity > 1 and valuation != 0: -# raise ValueError(f"valuation must not be specified for multivariate Taylor series (for {x}), but was set to {valuation}") + # if self._arity > 1 and valuation != 0: + # raise ValueError(f"valuation must not be specified for multivariate Taylor series (for {x}), but was set to {valuation}") elif self._arity > 1: valuation = 0 @@ -3126,10 +3087,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No coeff_stream = Stream_zero() else: if not x: - coeff_stream = Stream_exact([], - order=valuation, - degree=degree, - constant=constant) + coeff_stream = Stream_exact([], order=valuation, degree=degree, constant=constant) return self.element_class(self, coeff_stream) if self._arity == 1: @@ -3144,10 +3102,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No d = max(p_dict.keys()) p_list = [p_dict.get(i, 0) for i in range(v, d + 1)] - coeff_stream = Stream_exact(p_list, - order=v, - constant=constant, - degree=degree) + coeff_stream = Stream_exact(p_list, order=v, constant=constant, degree=degree) return self.element_class(self, coeff_stream) if isinstance(x, LazyPowerSeries): @@ -3164,10 +3119,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No else: valuation += len(coeffs) coeffs = [] - return self(coeffs, - degree=stream._degree, - constant=constant, - valuation=valuation) + return self(coeffs, degree=stream._degree, constant=constant, valuation=valuation) return self.element_class(self, stream) # Check if we can realize the input as a rational function @@ -3193,21 +3145,19 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No p = [BR(c) for c in p] else: p = [R(c) for c in p] - if not all(e.is_homogeneous() and e.degree() == i - for i, e in enumerate(p, valuation)): + if not all(e.is_homogeneous() and e.degree() == i for i, e in enumerate(p, valuation)): raise ValueError("coefficients must be homogeneous polynomials of the correct degree") - coeff_stream = Stream_exact(p, - order=valuation, - constant=constant, - degree=degree) + coeff_stream = Stream_exact(p, order=valuation, constant=constant, degree=degree) return self.element_class(self, coeff_stream) if check and self._arity > 1: if callable(x): + def y(n): e = R(x(n)) if not e or e.is_homogeneous() and e.degree() == n: return e raise ValueError("coefficient %s at degree %s is not a homogeneous polynomial" % (e, n)) + coeff_stream = Stream_function(y, self._sparse, valuation) else: coeff_stream = Stream_iterator(map(R, _skip_leading_zeros(x)), valuation) @@ -3233,8 +3183,7 @@ def _an_element_(self): x """ if self._arity == 1: - return self(self._laurent_poly_ring.an_element(), - constant=self.base_ring().an_element()) + return self(self._laurent_poly_ring.an_element(), constant=self.base_ring().an_element()) return self(self._laurent_poly_ring.an_element()) def uniformizer(self): @@ -3326,11 +3275,11 @@ def some_elements(self): z = self.gen(0) elts = [self.zero(), self.one(), self.an_element()] if self._arity == 1: - elts.extend([(z-3)*(2+z)**2, (1 - 2*z**3)/(1 - z + 3*z**2), self(lambda n: n**2)]) + elts.extend([(z - 3) * (2 + z) ** 2, (1 - 2 * z**3) / (1 - z + 3 * z**2), self(lambda n: n**2)]) else: PR = self._laurent_poly_ring sum_gens = PR.sum(PR.gens()) - elts.extend([(z-3)*(2+z)**2, (1 - 2*z**3)/(1 - z + 3*z**2), self(lambda n: sum_gens**n)]) + elts.extend([(z - 3) * (2 + z) ** 2, (1 - 2 * z**3) / (1 - z + 3 * z**2), self(lambda n: sum_gens**n)]) return elts def taylor(self, f): @@ -3403,9 +3352,7 @@ def taylor(self, f): def taylor_expand(deg): if deg == 0: return BR(f(**subs)) - return R.sum(BR(f.diff(*sum(([g] * e for g, e in zip(args, al)), []))(**subs) - / ZZ.prod(factorial(a) for a in al)) - * R.monomial(*al) for al in integer_vectors_nk_fast_iter(deg, ell)) + return R.sum(BR(f.diff(*sum(([g] * e for g, e in zip(args, al)), []))(**subs) / ZZ.prod(factorial(a) for a in al)) * R.monomial(*al) for al in integer_vectors_nk_fast_iter(deg, ell)) coeff_stream = Stream_function(taylor_expand, self._sparse, self._minimal_valuation) else: @@ -3456,6 +3403,7 @@ class LazyCompletionGradedAlgebra(LazySeriesRing): + (S[1,1,1,2]+S[1,2,2]-S[2,1,1,1]-S[2,2,1]) + (S[1,1,1,1,2]+S[1,1,2,2]-S[2,1,1,1,1]-S[2,2,1,1]) + O^7 """ + Element = LazyCompletionGradedAlgebraElement def __init__(self, basis, sparse=True, category=None): @@ -3557,6 +3505,7 @@ def _latex_(self): \text{\texttt{Symmetric{ }Functions{ }over{ }Finite{ }Field{ }of{ }size{ }2{ }in{ }the{ }Schur{ }basis}} """ from sage.misc.latex import latex + return latex(self._laurent_poly_ring) def _monomial(self, c, n): @@ -3606,15 +3555,13 @@ def _terms_of_degree(self, n, R): from sage.combinat.integer_vector import IntegerVectors from sage.misc.mrange import cartesian_product_iterator from sage.categories.tensor import tensor + B = self._internal_poly_ring.base_ring() B = B.change_ring(R) if self._arity == 1: return list(B.homogeneous_component_basis(n)) - return [tensor(m) - for c in IntegerVectors(n, self._arity) - for m in cartesian_product_iterator([F.homogeneous_component_basis(p) - for F, p in zip(B.tensor_factors(), c)])] + return [tensor(m) for c in IntegerVectors(n, self._arity) for m in cartesian_product_iterator([F.homogeneous_component_basis(p) for F, p in zip(B.tensor_factors(), c)])] def _element_constructor_(self, x=None, valuation=None, degree=None, constant=None, check=True): r""" @@ -3725,16 +3672,14 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No d = max(p_dict) p_list = [p_dict.get(i, 0) for i in range(v, d + 1)] - coeff_stream = Stream_exact(p_list, - order=v, - constant=self.base_ring().zero(), - degree=degree) + coeff_stream = Stream_exact(p_list, order=v, constant=self.base_ring().zero(), degree=degree) return self.element_class(self, coeff_stream) if isinstance(x, self.Element): return self.element_class(self, x._coeff_stream) if self._arity == 1: + def check_homogeneous_of_degree(f, d): if not f: return @@ -3745,7 +3690,9 @@ def check_homogeneous_of_degree(f, d): except ValueError: raise ValueError("coefficient %s should be an element of homogeneous degree %s" % (f, d)) raise ValueError("coefficient %s should be an element of homogeneous degree %s but has degree %s" % (f, d, d1)) + else: + def check_homogeneous_of_degree(f, d): if not f: return @@ -3769,22 +3716,17 @@ def check_homogeneous_of_degree(f, d): p = [R(e) for e in x] for i, e in enumerate(p, valuation): check_homogeneous_of_degree(e, i) - coeff_stream = Stream_exact(p, - order=valuation, - constant=self._laurent_poly_ring.zero(), - degree=degree) + coeff_stream = Stream_exact(p, order=valuation, constant=self._laurent_poly_ring.zero(), degree=degree) return self.element_class(self, coeff_stream) if callable(x): if degree is not None: p = [R(x(i)) for i in range(valuation, degree)] for i, e in enumerate(p, valuation): check_homogeneous_of_degree(e, i) - coeff_stream = Stream_exact(p, - order=valuation, - constant=self._laurent_poly_ring.zero(), - degree=degree) + coeff_stream = Stream_exact(p, order=valuation, constant=self._laurent_poly_ring.zero(), degree=degree) return self.element_class(self, coeff_stream) if check: + def y(n): e = R(x(n)) check_homogeneous_of_degree(e, n) @@ -3853,6 +3795,7 @@ def some_elements(self): return elts + ###################################################################### @@ -3879,11 +3822,13 @@ class LazySymmetricFunctions(LazyCompletionGradedAlgebra): Symmetric Functions over Integer Ring in the Schur basis # Symmetric Functions over Integer Ring in the monomial basis """ + Element = LazySymmetricFunction ###################################################################### + class LazyDirichletSeriesRing(LazySeriesRing): r""" The ring of lazy Dirichlet series. @@ -3946,6 +3891,7 @@ class LazyDirichletSeriesRing(LazySeriesRing): sage: L in PrincipalIdealDomains False """ + Element = LazyDirichletSeries # Follow the "generic" normalization @@ -3967,6 +3913,7 @@ def _laurent_poly_ring(self): True """ from sage.symbolic.ring import SR + return SR def __init__(self, base_ring, names, sparse=True, category=None): @@ -3999,8 +3946,7 @@ def __init__(self, base_ring, names, sparse=True, category=None): elif base_ring in Rings().Commutative(): category = category.Commutative() category = category.Infinite() - Parent.__init__(self, base=base_ring, names=names, - category=category) + Parent.__init__(self, base=base_ring, names=names, category=category) def _repr_(self): """ @@ -4209,10 +4155,7 @@ def some_elements(self): """ R = self.base_ring() some_numbers = [c for c, _ in zip(R.some_elements(), range(9))] - elts = [self.zero(), self.one(), self.an_element(), - self(some_numbers), - self(some_numbers, constant=R.an_element()), - self(lambda n: n**2)] + elts = [self.zero(), self.one(), self.an_element(), self(some_numbers), self(some_numbers, constant=R.an_element()), self(lambda n: n**2)] return elts def _monomial(self, c, n): @@ -4279,7 +4222,7 @@ def polylogarithm(self, z): """ if self._arity != 1: raise ValueError("must has arity 1") - return self(coefficients=lambda n: z ** n) + return self(coefficients=lambda n: z**n) polylog = polylogarithm @@ -4383,6 +4326,7 @@ class LazyPseudoDifferentialOperatorRing(LazySeriesRing): (-diff(u(x), x, x) + 2*diff(v(x), x))*Dx + (-2/3*u(x)*diff(u(x), x) - 2/3*diff(u(x), x, x, x) + diff(v(x), x, x)) """ + _twisted_base_ring_multiplication = True Element = LazyPseudoDifferentialOperator @@ -4449,6 +4393,7 @@ def __init__(self, variable, sparse, base_ring): category = category.Infinite() from sage.structure.category_object import normalize_names + try: names = normalize_names(1, (str(variable),)) names += ("d" + names[0],) @@ -4484,6 +4429,7 @@ def _latex_(self): \Bold{Q}[t] (\!(\partial_{t}^{-1})\!) """ from sage.misc.latex import latex + v = latex(self._variable) CR = latex(self.base_ring()) return CR + r"(\!(\partial_{{{}}}^{{-1}})\!)".format(v) diff --git a/src/sage/rings/lazy_species.py b/src/sage/rings/lazy_species.py index 951bbc0478f..295c5d0eba9 100644 --- a/src/sage/rings/lazy_species.py +++ b/src/sage/rings/lazy_species.py @@ -61,6 +61,7 @@ sage: B.truncate(6) 1 + X + E_2(X^2) + (P_5+5*X*E_2(X^2)) """ + from sage.arith.misc import divisors, multinomial from sage.functions.other import binomial, factorial from sage.libs.gap.libgap import libgap @@ -68,18 +69,10 @@ from sage.misc.misc_c import prod from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.rings.lazy_series import (LazyCompletionGradedAlgebraElement, - LazyModuleElement) -from sage.rings.lazy_series_ring import (LazyCompletionGradedAlgebra, - LazyPowerSeriesRing, - LazySymmetricFunctions) -from sage.rings.species import (_label_sets, - _SymmetricGroup, - PolynomialSpecies) -from sage.data_structures.stream import (Stream_zero, - Stream_exact, - Stream_truncated, - Stream_function) +from sage.rings.lazy_series import LazyCompletionGradedAlgebraElement, LazyModuleElement +from sage.rings.lazy_series_ring import LazyCompletionGradedAlgebra, LazyPowerSeriesRing, LazySymmetricFunctions +from sage.rings.species import _label_sets, _SymmetricGroup, PolynomialSpecies +from sage.data_structures.stream import Stream_zero, Stream_exact, Stream_truncated, Stream_function from sage.categories.tensor import tensor from sage.combinat.integer_vector import IntegerVectors from sage.combinat.subset import subsets @@ -89,10 +82,7 @@ from sage.combinat.set_partition import SetPartitions from sage.graphs.graph_generators import graphs from sage.groups.perm_gps.permgroup import PermutationGroup -from sage.groups.perm_gps.permgroup_named import (AlternatingGroup, - CyclicPermutationGroup, - DihedralGroup, - SymmetricGroup) +from sage.groups.perm_gps.permgroup_named import AlternatingGroup, CyclicPermutationGroup, DihedralGroup, SymmetricGroup from sage.modules.free_module_element import vector from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.structure.element import parent @@ -160,8 +150,9 @@ def weighted_compositions(n, d, weight_multiplicities, _w0=0): if _w0 > d: return from sage.combinat.integer_lists.invlex import IntegerListsBackend_invlex + for s in range(n + 1): - for c in weighted_compositions(n - s, d - s * (_w0 + 1), weight_multiplicities, _w0=_w0+1): + for c in weighted_compositions(n - s, d - s * (_w0 + 1), weight_multiplicities, _w0=_w0 + 1): m = weight_multiplicities[_w0] for v in IntegerListsBackend_invlex(s, length=m)._iter(): yield v + c @@ -216,10 +207,10 @@ def weighted_vector_compositions(n_vec, d, weight_multiplicities_vec): """ k = len(n_vec) from sage.combinat.integer_lists.invlex import IntegerListsBackend_invlex + for d_vec in IntegerListsBackend_invlex(d, length=k)._iter(): - yield from itertools.product(*map(weighted_compositions, - n_vec, d_vec, - weight_multiplicities_vec)) + yield from itertools.product(*map(weighted_compositions, n_vec, d_vec, weight_multiplicities_vec)) + ###################################################################### @@ -248,6 +239,7 @@ class LazyCombinatorialSpeciesElement(LazyCompletionGradedAlgebraElement): sage: all(coefficient(m) == E_inv[m] for m in range(10)) True """ + def isotype_generating_series(self): r""" Return the isotype generating series of ``self``. @@ -279,15 +271,17 @@ def isotype_generating_series(self): + O(X,Y)^7 """ P = self.parent() - L = LazyPowerSeriesRing(P.base_ring().fraction_field(), - P._laurent_poly_ring._indices._indices.variable_names()) + L = LazyPowerSeriesRing(P.base_ring().fraction_field(), P._laurent_poly_ring._indices._indices.variable_names()) if P._arity == 1: + def coefficient(n): return sum(self[n].coefficients()) + else: + def coefficient(n): - return sum(c * P.base_ring().prod(v ** d for v, d in zip(L.gens(), M.grade())) - for M, c in self[n].monomial_coefficients().items()) + return sum(c * P.base_ring().prod(v**d for v, d in zip(L.gens(), M.grade())) for M, c in self[n].monomial_coefficients().items()) + return L(coefficient) def generating_series(self): @@ -323,17 +317,17 @@ def generating_series(self): + O(X,Y)^8 """ P = self.parent() - L = LazyPowerSeriesRing(P.base_ring().fraction_field(), - P._laurent_poly_ring._indices._indices.variable_names()) + L = LazyPowerSeriesRing(P.base_ring().fraction_field(), P._laurent_poly_ring._indices._indices.variable_names()) if P._arity == 1: + def coefficient(n): - return sum(c / M.permutation_group()[0].cardinality() - for M, c in self[n].monomial_coefficients().items()) + return sum(c / M.permutation_group()[0].cardinality() for M, c in self[n].monomial_coefficients().items()) + else: + def coefficient(n): - return sum(c / M.permutation_group()[0].cardinality() - * P.base_ring().prod(v ** d for v, d in zip(L.gens(), M.grade())) - for M, c in self[n].monomial_coefficients().items()) + return sum(c / M.permutation_group()[0].cardinality() * P.base_ring().prod(v**d for v, d in zip(L.gens(), M.grade())) for M, c in self[n].monomial_coefficients().items()) + return L(coefficient) def cycle_index_series(self): @@ -368,14 +362,13 @@ def cycle_index_series(self): L = LazySymmetricFunctions(p) def coefficient(n): - return sum(c * M.permutation_group()[0].cycle_index() - for M, c in self[n].monomial_coefficients().items()) + return sum(c * M.permutation_group()[0].cycle_index() for M, c in self[n].monomial_coefficients().items()) + else: L = LazySymmetricFunctions(tensor([p for _ in range(P._arity)])) def coefficient(n): - return sum(c * M.cycle_index() - for M, c in self[n].monomial_coefficients().items()) + return sum(c * M.cycle_index() for M, c in self[n].monomial_coefficients().items()) return L(coefficient) @@ -513,11 +506,9 @@ def _test_structures(self, tester=None, max_size=5, **options): if P._arity == 1: labels = list(range(n)) s = list(self.structures(labels)) - tester.assertEqual(len(s), len(set(s)), - f"structures for {labels} are {s}, which is not a set") + tester.assertEqual(len(s), len(set(s)), f"structures for {labels} are {s}, which is not a set") coeff = self.generating_series()[n] - tester.assertEqual(len(s) / factorial(n), coeff, - f"the number of structures for {labels} is {len(s)}, but the generating series gives {coeff}") + tester.assertEqual(len(s) / factorial(n), coeff, f"the number of structures for {labels} is {len(s)}, but the generating series gives {coeff}") else: label_shapes = IntegerVectors(n, length=P._arity) for shape in label_shapes: @@ -525,9 +516,7 @@ def _test_structures(self, tester=None, max_size=5, **options): s = list(self.structures(*labels)) tester.assertEqual(len(s), len(set(s)), f"structures for {labels} are {s}, which is not a set") coeff = self.generating_series()[n].coefficient(list(shape)) - tester.assertEqual(len(s) / ZZ.prod(factorial(k) for k in shape), - coeff, - f"the number of structures for {labels} is {len(s)}, but the generating series gives {coeff}") + tester.assertEqual(len(s) / ZZ.prod(factorial(k) for k in shape), coeff, f"the number of structures for {labels} is {len(s)}, but the generating series gives {coeff}") def isotypes(self, *shape): r""" @@ -596,20 +585,16 @@ def _test_isotypes(self, tester=None, max_size=5, **options): for n in range(max_size): if P._arity == 1: s = list(self.isotypes(n)) - tester.assertEqual(len(s), len(set(s)), - f"isotypes for {n} are {s}, which is not a set") + tester.assertEqual(len(s), len(set(s)), f"isotypes for {n} are {s}, which is not a set") coeff = self.isotype_generating_series()[n] - tester.assertEqual(len(s), coeff, - f"the number of isotypes for {n} is {len(s)}, but the generating series gives {coeff}") + tester.assertEqual(len(s), coeff, f"the number of isotypes for {n} is {len(s)}, but the generating series gives {coeff}") else: shapes = IntegerVectors(n, length=P._arity) for shape in shapes: s = list(self.isotypes(*shape)) - tester.assertEqual(len(s), len(set(s)), - f"isotypes for {shape} are {s}, which is not a set") + tester.assertEqual(len(s), len(set(s)), f"isotypes for {shape} are {s}, which is not a set") coeff = self.isotype_generating_series()[n].coefficient(list(shape)) - tester.assertEqual(len(s), coeff, - f"the number of isotypes for {shape} is {len(s)}, but the generating series gives {coeff}") + tester.assertEqual(len(s), coeff, f"the number of isotypes for {shape} is {len(s)}, but the generating series gives {coeff}") def polynomial(self, degree=None, names=None): r""" @@ -642,8 +627,7 @@ def polynomial(self, degree=None, names=None): return R.zero() if degree is None: - if (isinstance(self._coeff_stream, Stream_exact) - and not self._coeff_stream._constant): + if isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: m = self._coeff_stream._degree else: raise ValueError("not a polynomial species") @@ -730,6 +714,7 @@ def __call__(self, *args): raise ValueError("arity of must be equal to the number of arguments provided") # Find a good parent for the result from sage.structure.element import get_coercion_model + cm = get_coercion_model() P = cm.common_parent(self.base_ring(), *[parent(g) for g in args]) # f = 0 @@ -737,16 +722,11 @@ def __call__(self, *args): return P.zero() # args = (0, ..., 0) - if all((not isinstance(g, LazyModuleElement) and not g) - or (isinstance(g, LazyModuleElement) - and isinstance(g._coeff_stream, Stream_zero)) - for g in args): + if all((not isinstance(g, LazyModuleElement) and not g) or (isinstance(g, LazyModuleElement) and isinstance(g._coeff_stream, Stream_zero)) for g in args): return P(self[0]) # f is a constant polynomial - if (isinstance(self._coeff_stream, Stream_exact) - and not self._coeff_stream._constant - and self._coeff_stream._degree == 1): + if isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant and self._coeff_stream._degree == 1: c = self._coeff_stream[0] B = c.parent() if B is ZZ or B is QQ or B == self.base_ring(): @@ -784,15 +764,12 @@ def revert(self): if isinstance(coeff_stream, Stream_zero): raise ValueError("compositional inverse does not exist") R = P._laurent_poly_ring - if (isinstance(coeff_stream, Stream_exact) - and coeff_stream.order() >= 0 - and coeff_stream._degree == 2): + if isinstance(coeff_stream, Stream_exact) and coeff_stream.order() >= 0 and coeff_stream._degree == 2: # self = a + b * X; self.revert() = -a/b + 1/b * X a = coeff_stream[0] b = coeff_stream[1].coefficients()[0] X = R(_SymmetricGroup(1)) # as a polynomial species - coeff_stream = Stream_exact((-a/b, 1/b * X), - order=0) + coeff_stream = Stream_exact((-a / b, 1 / b * X), order=0) return P.element_class(P, coeff_stream) # TODO: coefficients should not be checked here, it prevents @@ -846,11 +823,10 @@ def combinatorial_logarithm(self): A1 = M1._indices def E(mu): - return M1({A1(_SymmetricGroup(e)): a - for e, a in enumerate(mu.to_exp(), 1) if a}) + return M1({A1(_SymmetricGroup(e)): a for e, a in enumerate(mu.to_exp(), 1) if a}) def pi(mu): - return (-1)**(len(mu)-1) * multinomial(mu.to_exp()) / len(mu) + return (-1) ** (len(mu) - 1) * multinomial(mu.to_exp()) / len(mu) F = P.undefined() @@ -1116,6 +1092,7 @@ class LazyCombinatorialSpeciesElementGeneratingSeriesMixin: sage: TestSuite(F(L)).run(skip=['_test_category', '_test_pickling']) """ + def isotype_generating_series(self): r""" Return the isotype generating series of ``self``. @@ -1136,8 +1113,7 @@ def isotype_generating_series(self): 645490122795799841856164638490742749440 """ P = self.parent() - L = LazyPowerSeriesRing(P.base_ring().fraction_field(), - P._laurent_poly_ring._indices._indices.variable_names()) + L = LazyPowerSeriesRing(P.base_ring().fraction_field(), P._laurent_poly_ring._indices._indices.variable_names()) cis = self.cycle_index_series() one = ZZ.one() @@ -1148,10 +1124,7 @@ def isotype_generating_series(self): parents = cis.parent()._laurent_poly_ring.tensor_factors() def coefficient(n): - return sum(c * prod(S(la).principal_specialization(one, one) - * v**la.size() - for v, S, la in zip(vars, parents, M)) - for M, c in cis[n].monomial_coefficients().items()) + return sum(c * prod(S(la).principal_specialization(one, one) * v ** la.size() for v, S, la in zip(vars, parents, M)) for M, c in cis[n].monomial_coefficients().items()) return L(coefficient) @@ -1169,8 +1142,7 @@ def generating_series(self): 1 + X + X^2 + 4/3*X^3 + 8/3*X^4 + 128/15*X^5 + 2048/45*X^6 """ P = self.parent() - L = LazyPowerSeriesRing(P.base_ring().fraction_field(), - P._laurent_poly_ring._indices._indices.variable_names()) + L = LazyPowerSeriesRing(P.base_ring().fraction_field(), P._laurent_poly_ring._indices._indices.variable_names()) cis = self.cycle_index_series() one = ZZ.one() @@ -1181,10 +1153,7 @@ def generating_series(self): parents = cis.parent()._laurent_poly_ring.tensor_factors() def coefficient(n): - return sum(c * prod(S(la).exponential_specialization(one, one) - * v**la.size() - for v, S, la in zip(vars, parents, M)) - for M, c in cis[n].monomial_coefficients().items()) + return sum(c * prod(S(la).exponential_specialization(one, one) * v ** la.size() for v, S, la in zip(vars, parents, M)) for M, c in cis[n].monomial_coefficients().items()) return L(coefficient) @@ -1299,6 +1268,7 @@ def structures(self, *labels): sage: list((X*Y).structures([1], [2])) [((X, ((1,),)), (Y, ((2,),)))] """ + def dissections(s): for subset in subsets(s): subset_set = set(subset) @@ -1306,8 +1276,7 @@ def dissections(s): labels = _label_sets(self.parent()._arity, labels) for d in itertools.product(*[dissections(u) for u in labels]): - yield from itertools.product(self._left.structures(*[U for U, _ in d]), - self._right.structures(*[V for _, V in d])) + yield from itertools.product(self._left.structures(*[U for U, _ in d]), self._right.structures(*[V for _, V in d])) def generating_series(self): r""" @@ -1338,8 +1307,7 @@ def isotype_generating_series(self): return self._left.isotype_generating_series() * self._right.isotype_generating_series() -class CompositionSpeciesElement(LazyCombinatorialSpeciesElementGeneratingSeriesMixin, - LazyCombinatorialSpeciesElement): +class CompositionSpeciesElement(LazyCombinatorialSpeciesElementGeneratingSeriesMixin, LazyCombinatorialSpeciesElement): def __init__(self, left, *args): r""" Initialize the composition of species. @@ -1361,6 +1329,7 @@ def __init__(self, left, *args): fP = left.parent() # Find a good parent for the result from sage.structure.element import get_coercion_model + cm = get_coercion_model() P = cm.common_parent(left.base_ring(), *[parent(g) for g in args]) @@ -1384,8 +1353,7 @@ def coeff(g, i): return c # args_flat and weights contain one list for each g - weight_exp = [lazy_list(lambda j, g=g: len(coeff(g, j+1))) - for g in args] + weight_exp = [lazy_list(lambda j, g=g: len(coeff(g, j + 1))) for g in args] def flat(g): # function needed to work around python's scoping rules @@ -1408,17 +1376,12 @@ def coefficient(n): lF[M.grade()] += L._from_dict({M: c}) for mc, F in lF.items(): for degrees in weighted_vector_compositions(mc, n, weight_exp): - args_flat = [list(a[0:len(degrees[j])]) - for j, a in enumerate(args_flat1)] - multiplicities = [c for alpha, g_flat in zip(degrees, args_flat) - for d, (_, c) in zip(alpha, g_flat) if d] - molecules = [M for alpha, g_flat in zip(degrees, args_flat) - for d, (M, _) in zip(alpha, g_flat) if d] + args_flat = [list(a[0 : len(degrees[j])]) for j, a in enumerate(args_flat1)] + multiplicities = [c for alpha, g_flat in zip(degrees, args_flat) for d, (_, c) in zip(alpha, g_flat) if d] + molecules = [M for alpha, g_flat in zip(degrees, args_flat) for d, (M, _) in zip(alpha, g_flat) if d] non_zero_degrees = [[d for d in alpha if d] for alpha in degrees] names = ["X%s" % i for i in range(len(molecules))] - FX = F._compose_with_weighted_singletons(names, - multiplicities, - non_zero_degrees) + FX = F._compose_with_weighted_singletons(names, multiplicities, non_zero_degrees) FG = [(M(*molecules), c) for M, c in FX] result += R.sum_of_terms(FG) return result @@ -1537,6 +1500,7 @@ def __init__(self, left, *args, algorithm): """ # Find a good parent for the result from sage.structure.element import get_coercion_model + cm = get_coercion_model() P = cm.common_parent(left.base_ring(), *[parent(g) for g in args]) @@ -1547,8 +1511,7 @@ def __init__(self, left, *args, algorithm): if algorithm == "orbits": coeff_stream = Stream_function(self._coefficient, P._sparse, 0) elif algorithm == "subgroups": - coeff_stream = Stream_function(self._coefficient_subgroups, - P._sparse, 0) + coeff_stream = Stream_function(self._coefficient_subgroups, P._sparse, 0) else: raise ValueError(f"{algorithm} is not a known algorithm, use 'orbits' or 'subgroups'") super().__init__(P, coeff_stream) @@ -1579,33 +1542,25 @@ def _coefficient_subgroups(self, n): S_n = _SymmetricGroup(n) G_n = G[n].monomial_coefficients(copy=False) - if not G_n or (len(G_n) == 1 - and next(iter(G_n)).permutation_group()[0] == S_n): + if not G_n or (len(G_n) == 1 and next(iter(G_n)).permutation_group()[0] == S_n): # we act trivially on G[n] f_N = left.generating_series()[N] * factorial(N) return f_N * R(S_n) M = libgap.TableOfMarks(S_n) m = libgap.MarksTom(M).Length().sage() - C_n = [libgap.RepresentativeTom(M, i+1) for i in range(m)] - l_G = [H.gap() - for g, c in G_n.items() if (H := g.permutation_group()[0]) != S_n - for _ in range(c)] + C_n = [libgap.RepresentativeTom(M, i + 1) for i in range(m)] + l_G = [H.gap() for g, c in G_n.items() if (H := g.permutation_group()[0]) != S_n for _ in range(c)] act = libgap.FactorCosetAction(S_n, l_G) C_N = [libgap.Image(act, H) for H in C_n] coeffs = vector([ZZ.zero()] * m) for h, c in left[N]: - f = [fixed_points_factorized(N, - [(A._dis, e) for A, e in h._monomial.items()], - B) - for B in C_N] + f = [fixed_points_factorized(N, [(A._dis, e) for A, e in h._monomial.items()], B) for B in C_N] v = libgap.DecomposedFixedPointVector(M, f).sage() - coeffs += c * vector(v + [0]*(m - len(v))) + coeffs += c * vector(v + [0] * (m - len(v))) - return sum(coeff * F for coeff, H in zip(coeffs, C_n) - if coeff and (F := R(PermutationGroup(gap_group=H, - domain=range(1, n+1))))) + return sum(coeff * F for coeff, H in zip(coeffs, C_n) if coeff and (F := R(PermutationGroup(gap_group=H, domain=range(1, n + 1))))) def _coefficient(self, n): r""" @@ -1633,8 +1588,7 @@ def _coefficient(self, n): S_n = _SymmetricGroup(n) G_n = G[n].monomial_coefficients(copy=False) - if not G_n or (len(G_n) == 1 - and next(iter(G_n)).permutation_group()[0] == S_n): + if not G_n or (len(G_n) == 1 and next(iter(G_n)).permutation_group()[0] == S_n): # we act trivially on G[n] f_N = left.generating_series()[N] * factorial(N) return f_N * R(S_n) @@ -1644,9 +1598,7 @@ def _coefficient(self, n): def get_G_action(): # the test "!= S_n" can be removed once we have GAP 4.15.1 - l_G = [H - for g, c in G_n.items() if (H := g.permutation_group()[0]) != S_n - for _ in range(c)] + l_G = [H for g, c in G_n.items() if (H := g.permutation_group()[0]) != S_n for _ in range(c)] act = libgap.FactorCosetAction(S_n, l_G) return libgap.MappingGeneratorsImages(act) @@ -1668,8 +1620,7 @@ def get_G_action(): while U: u = U.pop() OS = libgap.OrbitStabilizer(S_n, u, G_action[0], f_images) - summands.append(PermutationGroup(gap_group=OS["stabilizer"], - domain=S_n.domain())) + summands.append(PermutationGroup(gap_group=OS["stabilizer"], domain=S_n.domain())) U.difference_update(OS["orbit"].sage()) result += c * sum(map(R, summands)) @@ -1722,6 +1673,7 @@ def __init__(self, F, G): """ # Find a good parent for the result from sage.structure.element import get_coercion_model + cm = get_coercion_model() P = cm.common_parent(F.base_ring(), parent(G)) if P._arity != 1: @@ -1737,12 +1689,12 @@ def coefficient(n): for m1, c1 in F[k]: D1, _ = m1.permutation_group() if D1.is_trivial(): - result += c1 * G[n//k](R.term(m1)) + result += c1 * G[n // k](R.term(m1)) else: - for m2, c2 in G[n//k]: + for m2, c2 in G[n // k]: D2, _ = m2.permutation_group() D = D1.gap().DirectProduct(D2) - X = libgap.Cartesian(list(range(1, k+1)), list(range(k+1, k+n//k+1))) + X = libgap.Cartesian(list(range(1, k + 1)), list(range(k + 1, k + n // k + 1))) hom = libgap.ActionHomomorphism(D, X, libgap.OnTuples, "surjective") result += c1 * c2 * R(PermutationGroup(gap_group=libgap.Image(hom))) return result @@ -1772,6 +1724,7 @@ def __init__(self, left, other): """ # Find a good parent for the result from sage.structure.element import get_coercion_model + cm = get_coercion_model() P = cm.common_parent(left.base_ring(), parent(other)) R = P._laurent_poly_ring @@ -1796,6 +1749,7 @@ def __classcall_private__(cls, base_ring, names, sparse=True): True """ from sage.structure.category_object import normalize_names + names = normalize_names(-1, names) if len(names) == 1: return LazyCombinatorialSpeciesUnivariate(base_ring, names, sparse) @@ -1859,8 +1813,7 @@ def __init__(self, base_ring, names, sparse): """ super().__init__(PolynomialSpecies(base_ring, names)) self._arity = len(names) - self.options._add_option('rename', - {'link_to': (self._laurent_poly_ring._indices._indices.options, 'rename')}) + self.options._add_option('rename', {'link_to': (self._laurent_poly_ring._indices._indices.options, 'rename')}) class LazyCombinatorialSpeciesUnivariate(LazyCombinatorialSpecies): @@ -2002,8 +1955,7 @@ class LazyCombinatorialSpeciesMultivariate(LazyCombinatorialSpecies): pass -class SetSpecies(LazyCombinatorialSpeciesElement, UniqueRepresentation, - metaclass=InheritComparisonClasscallMetaclass): +class SetSpecies(LazyCombinatorialSpeciesElement, UniqueRepresentation, metaclass=InheritComparisonClasscallMetaclass): def __init__(self, parent): r""" Initialize the species of sets. @@ -2061,8 +2013,7 @@ def generating_series(self): 1 + X + 1/2*X^2 + 1/6*X^3 + 1/24*X^4 + 1/120*X^5 + 1/720*X^6 + O(X^7) """ P = self.parent() - L = LazyPowerSeriesRing(P.base_ring().fraction_field(), - P._laurent_poly_ring._indices._indices.variable_names()) + L = LazyPowerSeriesRing(P.base_ring().fraction_field(), P._laurent_poly_ring._indices._indices.variable_names()) return L.gen().exp() def isotype_generating_series(self): @@ -2079,8 +2030,7 @@ def isotype_generating_series(self): 1 + X + X^2 + O(X^3) """ P = self.parent() - L = LazyPowerSeriesRing(P.base_ring().fraction_field(), - P._laurent_poly_ring._indices._indices.variable_names()) + L = LazyPowerSeriesRing(P.base_ring().fraction_field(), P._laurent_poly_ring._indices._indices.variable_names()) return L(constant=1) def cycle_index_series(self): @@ -2099,8 +2049,7 @@ def cycle_index_series(self): return L(lambda n: h[n]) -class CycleSpecies(LazyCombinatorialSpeciesElement, UniqueRepresentation, - metaclass=InheritComparisonClasscallMetaclass): +class CycleSpecies(LazyCombinatorialSpeciesElement, UniqueRepresentation, metaclass=InheritComparisonClasscallMetaclass): def __init__(self, parent): r""" Initialize the species of cycles. @@ -2169,9 +2118,8 @@ def generating_series(self): X + 1/2*X^2 + 1/3*X^3 + 1/4*X^4 + 1/5*X^5 + 1/6*X^6 + 1/7*X^7 + O(X^8) """ P = self.parent() - L = LazyPowerSeriesRing(P.base_ring().fraction_field(), - P._laurent_poly_ring._indices._indices.variable_names()) - return -(L.one()-L.gen()).log() + L = LazyPowerSeriesRing(P.base_ring().fraction_field(), P._laurent_poly_ring._indices._indices.variable_names()) + return -(L.one() - L.gen()).log() def isotype_generating_series(self): r""" @@ -2187,13 +2135,11 @@ def isotype_generating_series(self): X + X^2 + X^3 + O(X^4) """ P = self.parent() - L = LazyPowerSeriesRing(P.base_ring().fraction_field(), - P._laurent_poly_ring._indices._indices.variable_names()) + L = LazyPowerSeriesRing(P.base_ring().fraction_field(), P._laurent_poly_ring._indices._indices.variable_names()) return L(constant=1, valuation=1) -class PolygonSpecies(LazyCombinatorialSpeciesElement, UniqueRepresentation, - metaclass=InheritComparisonClasscallMetaclass): +class PolygonSpecies(LazyCombinatorialSpeciesElement, UniqueRepresentation, metaclass=InheritComparisonClasscallMetaclass): def __init__(self, parent): r""" Initialize the species of polygons. @@ -2224,8 +2170,7 @@ def _repr_(self): return "Polygon species" -class OrientedSetSpecies(LazyCombinatorialSpeciesElement, UniqueRepresentation, - metaclass=InheritComparisonClasscallMetaclass): +class OrientedSetSpecies(LazyCombinatorialSpeciesElement, UniqueRepresentation, metaclass=InheritComparisonClasscallMetaclass): def __init__(self, parent): r""" Initialize the species of oriented sets. @@ -2247,6 +2192,7 @@ def Eo(n): if n > 2: return A(AlternatingGroup(n), check=False) return M(AlternatingGroup(n), check=False) + S = parent(Eo) super().__init__(parent, S._coeff_stream) @@ -2262,8 +2208,7 @@ def _repr_(self): return "Oriented Set species" -class ChainSpecies(LazyCombinatorialSpeciesElement, UniqueRepresentation, - metaclass=InheritComparisonClasscallMetaclass): +class ChainSpecies(LazyCombinatorialSpeciesElement, UniqueRepresentation, metaclass=InheritComparisonClasscallMetaclass): def __init__(self, parent): r""" Initialize the species of chains. @@ -2283,9 +2228,9 @@ def coefficient(n): if not n: return P.one() if n % 2: - gen = [(i, i+1) for i in range(2, n+1, 2)] + gen = [(i, i + 1) for i in range(2, n + 1, 2)] else: - gen = [(i, i+1) for i in range(1, n+1, 2)] + gen = [(i, i + 1) for i in range(1, n + 1, 2)] return P(PermutationGroup([gen])) S = parent(coefficient) @@ -2323,7 +2268,7 @@ def structures(self, labels): for a, b in itertools.combinations(labels, 2): ia = labels.index(a) ib = labels.index(b) - rest = labels[:ia] + labels[ia+1:ib] + labels[ib+1:] + rest = labels[:ia] + labels[ia + 1 : ib] + labels[ib + 1 :] for pi in itertools.permutations(rest): yield (a,) + pi + (b,) @@ -2341,8 +2286,7 @@ def generating_series(self): 1 + X + 1/2*X^2 + 1/2*X^3 + 1/2*X^4 + 1/2*X^5 + 1/2*X^6 """ P = self.parent() - L = LazyPowerSeriesRing(P.base_ring().fraction_field(), - P._laurent_poly_ring._indices._indices.variable_names()) + L = LazyPowerSeriesRing(P.base_ring().fraction_field(), P._laurent_poly_ring._indices._indices.variable_names()) x = L.gen() return (1 / (1 - x) + 1 + x) / 2 @@ -2360,8 +2304,7 @@ def isotype_generating_series(self): 1 + X + X^2 + X^3 """ P = self.parent() - L = LazyPowerSeriesRing(P.base_ring().fraction_field(), - P._laurent_poly_ring._indices._indices.variable_names()) + L = LazyPowerSeriesRing(P.base_ring().fraction_field(), P._laurent_poly_ring._indices._indices.variable_names()) return L(constant=1) def cycle_index_series(self): @@ -2395,9 +2338,7 @@ def coefficient(n): return L(coefficient) -class GraphSpecies(LazyCombinatorialSpeciesElementGeneratingSeriesMixin, - LazyCombinatorialSpeciesElement, UniqueRepresentation, - metaclass=InheritComparisonClasscallMetaclass): +class GraphSpecies(LazyCombinatorialSpeciesElementGeneratingSeriesMixin, LazyCombinatorialSpeciesElement, UniqueRepresentation, metaclass=InheritComparisonClasscallMetaclass): def __init__(self, parent): r""" Initialize the species of simple graphs. @@ -2454,9 +2395,8 @@ def generating_series(self): 1 + X + X^2 + 4/3*X^3 + 8/3*X^4 + 128/15*X^5 + 2048/45*X^6 """ P = self.parent() - L = LazyPowerSeriesRing(P.base_ring().fraction_field(), - P._laurent_poly_ring._indices._indices.variable_names()) - return L(lambda n: 2**binomial(n, 2) / factorial(n)) + L = LazyPowerSeriesRing(P.base_ring().fraction_field(), P._laurent_poly_ring._indices._indices.variable_names()) + return L(lambda n: 2 ** binomial(n, 2) / factorial(n)) def cycle_index_series(self): r""" @@ -2482,11 +2422,8 @@ def cycle_index_series(self): def a(sigma): rho = sigma.to_exp() - res1 = ZZ.sum(ZZ(i+1)._gcd(ZZ(j+1)) * rho[i] * rho[j] - for i in range(len(rho)) - for j in range(i+1, len(rho))) - res2 = ZZ.sum(ZZ(i+1) * rho[i]**2 - for i in range(len(rho))) + res1 = ZZ.sum(ZZ(i + 1)._gcd(ZZ(j + 1)) * rho[i] * rho[j] for i in range(len(rho)) for j in range(i + 1, len(rho))) + res2 = ZZ.sum(ZZ(i + 1) * rho[i] ** 2 for i in range(len(rho))) res3 = ZZ.sum(rho[::2]) return ZZ(2) ** (res1 + (res2 - res3) / 2) / sigma.centralizer_size() @@ -2496,8 +2433,7 @@ def coefficient(n): return L(coefficient) -class SetPartitionSpecies(CompositionSpeciesElement, UniqueRepresentation, - metaclass=InheritComparisonClasscallMetaclass): +class SetPartitionSpecies(CompositionSpeciesElement, UniqueRepresentation, metaclass=InheritComparisonClasscallMetaclass): def __init__(self, parent): r""" Initialize the species of set partitions. @@ -2586,8 +2522,7 @@ def generating_series(self): 1 + X + X^2 + 5/6*X^3 + 5/8*X^4 + 13/30*X^5 + 203/720*X^6 + O(X^7) """ P = self.parent() - L = LazyPowerSeriesRing(P.base_ring().fraction_field(), - P._laurent_poly_ring._indices._indices.variable_names()) + L = LazyPowerSeriesRing(P.base_ring().fraction_field(), P._laurent_poly_ring._indices._indices.variable_names()) return L(lambda n: SetPartitions(n).cardinality() / factorial(n)) def isotype_generating_series(self): @@ -2602,8 +2537,7 @@ def isotype_generating_series(self): 1 + X + 2*X^2 + 3*X^3 + 5*X^4 + 7*X^5 + 11*X^6 + O(X^7) """ P = self.parent() - L = LazyPowerSeriesRing(P.base_ring().fraction_field(), - P._laurent_poly_ring._indices._indices.variable_names()) + L = LazyPowerSeriesRing(P.base_ring().fraction_field(), P._laurent_poly_ring._indices._indices.variable_names()) return L(lambda n: Partitions(n).cardinality()) @@ -2652,8 +2586,7 @@ def isotypes(self, *shape): [] """ n = sum(shape) - if ((self._min is None or self._min <= n) - and (self._max is None or n <= self._max)): + if (self._min is None or self._min <= n) and (self._max is None or n <= self._max): yield from self._F.isotypes(*shape) def structures(self, *labels): @@ -2670,8 +2603,7 @@ def structures(self, *labels): [{{1, 2, 3}}, {{1, 2}, {3}}, {{1, 3}, {2}}, {{1}, {2, 3}}, {{1}, {2}, {3}}] """ n = sum(map(len, labels)) - if ((self._min is None or self._min <= n) - and (self._max is None or n <= self._max)): + if (self._min is None or self._min <= n) and (self._max is None or n <= self._max): yield from self._F.structures(*labels) def generating_series(self): @@ -2721,6 +2653,7 @@ def cycle_index_series(self): """ return self._F.cycle_index_series().restrict(self._min, self._max) + ###################################################################### # helpers for functorial composition ###################################################################### @@ -2783,9 +2716,7 @@ def weighted_partitions_by_capacity(weights, capacities): bins = [[] for _ in range(M)] sums = [0] * M - earlier_same_block = [[i for i in range(j) - if block_id[i] == block_id[j]] - for j in range(M)] + earlier_same_block = [[i for i in range(j) if block_id[i] == block_id[j]] for j in range(M)] stack = [] pos = 0 @@ -2817,8 +2748,7 @@ def weighted_partitions_by_capacity(weights, capacities): for j in range(next_bin, M): if sums[j] + w > caps[j]: continue - if not (bins[j] - or all(bins[i] for i in earlier_same_block[j])): + if not (bins[j] or all(bins[i] for i in earlier_same_block[j])): continue bins[j].append(item) @@ -2917,21 +2847,18 @@ def fixed_points_factorized(n, lA, B): [0 0 0 1] """ if libgap.IsTrivial(B): - return factorial(n) / prod(libgap.Size(A_i).sage() ** e_i - for A_i, e_i in lA) + return factorial(n) / prod(libgap.Size(A_i).sage() ** e_i for A_i, e_i in lA) # sanitize lA - only necessary to drop the condition that A_i is # directly indecomposable lA = [(A_i, e_i) for A_i, e_i in lA if not libgap.IsTrivial(A_i).sage()] degree = ZZ(n) - sum(e_i * libgap.NrMovedPoints(A_i).sage() for A_i, e_i in lA) if degree: lA.append((libgap.SymmetricGroup(1), degree)) - capacities = [(max(ZZ.one(), libgap.NrMovedPoints(A_i).sage()), - e_i) for A_i, e_i in lA] + capacities = [(max(ZZ.one(), libgap.NrMovedPoints(A_i).sage()), e_i) for A_i, e_i in lA] lA_flat = [A_i for A_i, e_i in lA for _ in range(e_i)] - orbits = libgap.Orbits(B, list(range(1, n+1))).sage() + orbits = libgap.Orbits(B, list(range(1, n + 1))).sage() orbit_sizes = [len(o) for o in orbits] - assignments = weighted_partitions_by_capacity(orbit_sizes, - capacities) + assignments = weighted_partitions_by_capacity(orbit_sizes, capacities) total_count = ZZ.zero() for f in assignments: pts = [tuple(sorted(p for j in b for p in orbits[j])) for b in f] diff --git a/src/sage/rings/localization.py b/src/sage/rings/localization.py index 9df18ff88d3..09434238cd7 100644 --- a/src/sage/rings/localization.py +++ b/src/sage/rings/localization.py @@ -159,7 +159,6 @@ - Sebastian Oehms 2022-03-05: fix some corner cases and add :meth:`factor` (:issue:`33463`) """ - # **************************************************************************** # Copyright (C) 2019 Sebastian Oehms # @@ -233,6 +232,7 @@ def normalize_extra_units(base_ring, add_units, warning=True): # if :meth:`is_unit` or :meth:`factor` are not available we can't do any more. if warning: from warnings import warn + warn('Localization may not be represented uniquely') add_units_result = add_units break @@ -407,7 +407,8 @@ def factor(self, proof=None): P = self.parent() fac = [(P(f), e) for (f, e) in F] from sage.structure.factorization import Factorization - return Factorization(fac, unit=~P(den)*F.unit()) + + return Factorization(fac, unit=~P(den) * F.unit()) def _im_gens_(self, codomain, im_gens, base_map=None): """ @@ -524,6 +525,7 @@ def _rational_(self): Number Field in t with defining polynomial x^2 + x + 1 """ from sage.rings.rational_field import QQ + if not self._value.parent() == QQ: raise ValueError('{} is not a rational'.format(self)) return self._value @@ -544,6 +546,7 @@ def _integer_(self, Z=None): True """ from sage.rings.rational_field import QQ + if not self._value.parent() == QQ: raise ValueError('{} is not a rational'.format(self)) return self._value._integer_(Z=Z) @@ -682,8 +685,7 @@ def __init__(self, base_ring, extra_units, names=None, normalize=True, category= if isinstance(base_ring, Localization): # don't allow recursive constructions - extra_units = [u for u in extra_units - if ~u not in base_ring._extra_units] # :issue:`33463` + extra_units = [u for u in extra_units if ~u not in base_ring._extra_units] # :issue:`33463` extra_units += base_ring._extra_units base_ring = base_ring.base_ring() diff --git a/src/sage/rings/monomials.py b/src/sage/rings/monomials.py index 93ccac6f651..adbbc22ba1c 100644 --- a/src/sage/rings/monomials.py +++ b/src/sage/rings/monomials.py @@ -18,8 +18,8 @@ def _monomials(gens, R, n, i): if len(gens) == 1: b = gens[0] v = [R(1)] - for _ in range(n[0]-1): - v.append(v[-1]*b) + for _ in range(n[0] - 1): + v.append(v[-1] * b) return v z = gens[i] w = list(gens) @@ -28,9 +28,9 @@ def _monomials(gens, R, n, i): del nn[i] v = monomials(w, nn) k = len(v) - for _ in range(n[i]-1): + for _ in range(n[i] - 1): for j in range(k): - v.append(v[j]*z) + v.append(v[j] * z) z *= gens[i] return v @@ -62,7 +62,7 @@ def monomials(v, n): [1, z, y, y*z, y^2, y^2*z, x, x*z, x*y, x*y*z, x*y^2, x*y^2*z] """ - if (len(v) != len(n)): + if len(v) != len(n): raise ValueError("inputs must be of the same length.") if len(v) == 0: return [] diff --git a/src/sage/rings/multi_power_series_ring.py b/src/sage/rings/multi_power_series_ring.py index b98e7ebbec0..72de5efca41 100644 --- a/src/sage/rings/multi_power_series_ring.py +++ b/src/sage/rings/multi_power_series_ring.py @@ -217,12 +217,12 @@ from sage.rings.laurent_series_ring import LaurentSeriesRing from sage.categories.commutative_rings import CommutativeRings from sage.categories.integral_domains import IntegralDomains + _CommutativeRings = CommutativeRings() _IntegralDomains = IntegralDomains() -lazy_import('sage.rings.lazy_series_ring', ('LazyPowerSeriesRing', - 'LazyLaurentSeriesRing')) +lazy_import('sage.rings.lazy_series_ring', ('LazyPowerSeriesRing', 'LazyLaurentSeriesRing')) class MPowerSeriesRing_generic(PowerSeriesRing_generic, Nonexact): @@ -240,6 +240,7 @@ class MPowerSeriesRing_generic(PowerSeriesRing_generic, Nonexact): For usage and examples, see above, and :meth:`PowerSeriesRing`. """ + # ## methods from PowerSeriesRing_generic that we *don't* override: # # variable_names_recursive : works just fine @@ -265,8 +266,7 @@ class MPowerSeriesRing_generic(PowerSeriesRing_generic, Nonexact): Element = MPowerSeries @staticmethod - def __classcall__(cls, base_ring, num_gens, name_list, - order='negdeglex', default_prec=10, sparse=False): + def __classcall__(cls, base_ring, num_gens, name_list, order='negdeglex', default_prec=10, sparse=False): """ Preprocessing of arguments: The term order can be given as string or as a :class:`~sage.rings.polynomial.term_order.TermOrder` instance. @@ -279,11 +279,9 @@ def __classcall__(cls, base_ring, num_gens, name_list, True """ order = TermOrder(order, num_gens) - return super().__classcall__(cls, base_ring, num_gens, name_list, - order, default_prec, sparse) + return super().__classcall__(cls, base_ring, num_gens, name_list, order, default_prec, sparse) - def __init__(self, base_ring, num_gens, name_list, - order='negdeglex', default_prec=10, sparse=False) -> None: + def __init__(self, base_ring, num_gens, name_list, order='negdeglex', default_prec=10, sparse=False) -> None: """ Initialize a multivariate power series ring. See PowerSeriesRing for complete documentation. @@ -351,9 +349,7 @@ def __init__(self, base_ring, num_gens, name_list, # Multivariate power series rings inherit from power series rings. But # apparently we can not call their initialisation. Instead, initialise # Parent and Nonexact: - Parent.__init__(self, base=base_ring, names=name_list, - category=_IntegralDomains if base_ring in - _IntegralDomains else _CommutativeRings) + Parent.__init__(self, base=base_ring, names=name_list, category=_IntegralDomains if base_ring in _IntegralDomains else _CommutativeRings) Nonexact.__init__(self, default_prec) # underlying polynomial ring in which to represent elements @@ -366,8 +362,7 @@ def __init__(self, base_ring, num_gens, name_list, self._bg_indeterminate = self._bg_power_series_ring.gen() self._is_sparse = sparse - self._params = (base_ring, num_gens, name_list, - order, default_prec, sparse) + self._params = (base_ring, num_gens, name_list, order, default_prec, sparse) self._populate_coercion_lists_() def _repr_(self) -> str: @@ -496,12 +491,11 @@ def construction(self): True """ from sage.categories.pushout import CompletionFunctor + extras = {'order': self.term_order(), 'num_gens': self.ngens()} if self.is_sparse(): extras['sparse'] = True - return (CompletionFunctor(self._names, self.default_prec(), - extras=extras), - self._poly_ring()) + return (CompletionFunctor(self._names, self.default_prec(), extras=extras), self._poly_ring()) def change_ring(self, R): """ @@ -623,9 +617,7 @@ def _coerce_impl(self, f): True """ P = f.parent() - if isinstance(P, (PolynomialRing_generic, MPolynomialRing_base, - PowerSeriesRing_generic, MPowerSeriesRing_generic, - LazyPowerSeriesRing)): + if isinstance(P, (PolynomialRing_generic, MPolynomialRing_base, PowerSeriesRing_generic, MPowerSeriesRing_generic, LazyPowerSeriesRing)): if set(P.variable_names()).issubset(set(self.variable_names())): if self.has_coerce_map_from(P.base_ring()): return self(f) @@ -702,8 +694,7 @@ def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None) -> bool: if all(v == 0 for v in im_gens): return True - if isinstance(codomain, (PowerSeriesRing_generic, MPowerSeriesRing_generic, LazyPowerSeriesRing, - LaurentSeriesRing, LazyLaurentSeriesRing)): + if isinstance(codomain, (PowerSeriesRing_generic, MPowerSeriesRing_generic, LazyPowerSeriesRing, LaurentSeriesRing, LazyLaurentSeriesRing)): try: B = all(v.valuation() > 0 or v.is_nilpotent() for v in im_gens) except NotImplementedError: @@ -787,8 +778,7 @@ def _coerce_map_from_(self, P): sage: R.has_coerce_map_from(L) True """ - if isinstance(P, (MPolynomialRing_base, MPowerSeriesRing_generic, LazyPowerSeriesRing, - PolynomialRing_generic, PowerSeriesRing_generic)): + if isinstance(P, (MPolynomialRing_base, MPowerSeriesRing_generic, LazyPowerSeriesRing, PolynomialRing_generic, PowerSeriesRing_generic)): if set(P.variable_names()).issubset(set(self.variable_names())): if self.has_coerce_map_from(P.base_ring()): return True @@ -829,6 +819,7 @@ def _element_constructor_(self, f, prec=None): except AttributeError: prec = infinity from sage.rings.lazy_series import LazyPowerSeries + if isinstance(f, LazyPowerSeries): if prec is infinity: try: @@ -1087,5 +1078,4 @@ def unpickle_multi_power_series_ring_v0(base_ring, num_gens, names, order, defau sage: loads(dumps(P)) == P # indirect doctest True """ - return PowerSeriesRing(base_ring, num_gens=num_gens, names=names, - order=order, default_prec=default_prec, sparse=sparse) + return PowerSeriesRing(base_ring, num_gens=num_gens, names=names, order=order, default_prec=default_prec, sparse=sparse) diff --git a/src/sage/rings/multi_power_series_ring_element.py b/src/sage/rings/multi_power_series_ring_element.py index c4fa8a6d6b6..6af87bc86e1 100644 --- a/src/sage/rings/multi_power_series_ring_element.py +++ b/src/sage/rings/multi_power_series_ring_element.py @@ -147,6 +147,7 @@ - Niles Johnson (07/2010): initial code - Simon King (08/2012): Use category and coercion framework, :issue:`13412` """ + # **************************************************************************** # Copyright (C) 2010 Niles Johnson # @@ -345,9 +346,7 @@ def __init__(self, parent, x=0, prec=infinity, is_gen=False, check=False): # test whether x coerces to background univariate # power series ring of parent - if isinstance(xparent, (PowerSeriesRing_generic, - MPowerSeriesRing_generic, - LazyPowerSeriesRing)): + if isinstance(xparent, (PowerSeriesRing_generic, MPowerSeriesRing_generic, LazyPowerSeriesRing)): # x is either a multivariate or univariate power series # # test whether x coerces directly to designated parent @@ -381,11 +380,10 @@ def __init__(self, parent, x=0, prec=infinity, is_gen=False, check=False): else: try: x = parent._poly_ring(x) - #self._value = x + # self._value = x self._bg_value = parent._send_to_bg(x).add_bigoh(prec) except (TypeError, AttributeError): - raise TypeError("Input does not coerce to any of the " - "expected rings.") + raise TypeError("Input does not coerce to any of the " "expected rings.") self._go_to_fg = parent._send_to_fg self._prec = self._bg_value.prec() @@ -404,7 +402,7 @@ def __reduce__(self): sage: loads(dumps(f)) == f True """ - return self.__class__, (self._parent,self._bg_value,self._prec) + return self.__class__, (self._parent, self._bg_value, self._prec) def __call__(self, *x, **kwds): """ @@ -472,7 +470,7 @@ def __call__(self, *x, **kwds): if self.prec() is infinity: newprec = infinity else: - newprec = self.prec()*min(valn_list) + newprec = self.prec() * min(valn_list) return self.parent()(self._value().subs(sub_dict)).add_bigoh(newprec) def _subs_formal(self, *x, **kwds): @@ -536,7 +534,7 @@ def _subs_formal(self, *x, **kwds): if base_map is None: base_map = lambda t: t for m, c in self.monomial_coefficients().items(): - y += base_map(c)*prod([x[i]**m[i] for i in range(n) if m[i] != 0]) + y += base_map(c) * prod([x[i] ** m[i] for i in range(n) if m[i] != 0]) if self.prec() == infinity: return y return y.add_bigoh(self.prec()) @@ -572,10 +570,7 @@ def _repr_(self): """ if self._prec == infinity: return "%s" % self._value() - return "%(val)s + O(%(gens)s)^%(prec)s" \ - % {'val':self._value(), - 'gens':', '.join(str(g) for g in self.parent().gens()), - 'prec':self._prec} + return "%(val)s + O(%(gens)s)^%(prec)s" % {'val': self._value(), 'gens': ', '.join(str(g) for g in self.parent().gens()), 'prec': self._prec} def _latex_(self): """ @@ -607,10 +602,7 @@ def _latex_(self): """ if self._prec == infinity: return "%s" % self._value()._latex_() - return "%(val)s + O(%(gens)s)^{%(prec)s}" \ - % {'val':self._value()._latex_(), - 'gens':', '.join(g._latex_() for g in self.parent().gens()), - 'prec':self._prec} + return "%(val)s + O(%(gens)s)^{%(prec)s}" % {'val': self._value()._latex_(), 'gens': ', '.join(g._latex_() for g in self.parent().gens()), 'prec': self._prec} def _im_gens_(self, codomain, im_gens, base_map=None): """ @@ -677,13 +669,10 @@ def __getitem__(self, n): """ if type(n) is tuple: if sum(n) >= self.prec(): - raise IndexError("Cannot return the coefficients of terms of " + - "total degree greater than or equal to " + - "precision of self.") + raise IndexError("Cannot return the coefficients of terms of " + "total degree greater than or equal to " + "precision of self.") return self._bg_value[sum(n)][n] if n >= self.prec(): - raise IndexError("Cannot return terms of total degree greater " + - "than or equal to precision of self.") + raise IndexError("Cannot return terms of total degree greater " + "than or equal to precision of self.") return self.parent(self._bg_value[n]) def __invert__(self): @@ -985,7 +974,7 @@ def quo_rem(self, other, precision=None): self = self.add_bigoh(precision) self_prec = self.prec() rem = parent.zero().add_bigoh(self_prec) - quo = parent.zero().add_bigoh(self_prec-other.valuation()) + quo = parent.zero().add_bigoh(self_prec - other.valuation()) while self: # Loop invariants: # ``(the original value of self) - self == quo * other + rem`` @@ -1005,15 +994,15 @@ def quo_rem(self, other, precision=None): # up to the minimum of the precision of either side of this # equality and the precision of self. self_tt = self.trailing_monomial() - #assert self_tt + # assert self_tt if not other_tt.divides(self_tt): self -= self_tt rem += self_tt else: - d = self_tt//other_tt + d = self_tt // other_tt self -= d * other quo += d - quo = quo.add_bigoh(self.prec()-other_tt.degree()) + quo = quo.add_bigoh(self.prec() - other_tt.degree()) return quo, rem def _div_(self, denom_r): @@ -1059,7 +1048,7 @@ def _div_(self, denom_r): sage: ((a+b)*f) / (a+b) == f # needs sage.libs.singular True """ - if denom_r.is_unit(): # faster if denom_r is a unit + if denom_r.is_unit(): # faster if denom_r is a unit return self.parent(self._bg_value * ~denom_r._bg_value) quo, rem = self.quo_rem(denom_r) if rem: @@ -1292,7 +1281,7 @@ def V(self, n): """ cd = self.coefficients() Vs = sum(v * k**n for k, v in cd.items()) - return Vs.add_bigoh(self.prec()*n) + return Vs.add_bigoh(self.prec() * n) def prec(self): """ @@ -1473,8 +1462,7 @@ def is_nilpotent(self): """ if self.prec() < infinity and self.valuation() > 0: return True - return (self == self.constant_coefficient() and - self.base_ring()(self.constant_coefficient()).is_nilpotent()) + return self == self.constant_coefficient() and self.base_ring()(self.constant_coefficient()).is_nilpotent() def degree(self): """ @@ -1590,10 +1578,11 @@ def derivative(self, *args): 0 + O(a, b)^0 """ from sage.misc.derivative import derivative_parse + R = self.parent() - variables = [ x.polynomial() for x in derivative_parse(args) ] + variables = [x.polynomial() for x in derivative_parse(args)] deriv = self.polynomial().derivative(variables) - new_prec = max(self.prec()-len(variables), 0) + new_prec = max(self.prec() - len(variables), 0) return R(deriv) + R.O(new_prec) def integral(self, *args): @@ -1662,6 +1651,7 @@ def integral(self, *args): ZeroDivisionError: inverse of Mod(0, 3) does not exist """ from sage.misc.derivative import derivative_parse + res = self for v in derivative_parse(args): res = res._integral(v) @@ -1719,9 +1709,8 @@ def _integral(self, xx): raise ValueError("%s is not a variable" % xx) xxe = xx.exponents()[0] pos = [i for i, c in enumerate(xxe) if c != 0][0] # get the position of the variable - res = {mon.eadd(xxe): R(co / (mon[pos]+1)) - for mon, co in self.monomial_coefficients().items()} - return P( res ).add_bigoh(self.prec()+1) + res = {mon.eadd(xxe): R(co / (mon[pos] + 1)) for mon, co in self.monomial_coefficients().items()} + return P(res).add_bigoh(self.prec() + 1) def ogf(self): """ @@ -1786,7 +1775,7 @@ def list(self): NotImplementedError: Multivariate power series do not have list of coefficients; use 'coefficients' to get a dict of coefficients. """ - #return [self.parent(c) for c in self._bg_value.list()] + # return [self.parent(c) for c in self._bg_value.list()] raise NotImplementedError("Multivariate power series do not have list of coefficients; use 'coefficients' to get a dict of coefficients.") def variable(self): @@ -1954,12 +1943,13 @@ def exp(self, prec=infinity): exp_c = self.base_ring().one() else: from sage.functions.log import exp + exp_c = exp(c) x = self._bg_value - c if x.is_zero(): return exp_c val = x.valuation() - assert (val >= 1) + assert val >= 1 prec = min(prec, self.prec()) if isinstance(prec, InfinityElement): @@ -1967,11 +1957,11 @@ def exp(self, prec=infinity): n_inv_factorial = R.base_ring().one() x_pow_n = Rbg.one() exp_x = Rbg.one().add_bigoh(prec) - for n in range(1,prec//val+1): + for n in range(1, prec // val + 1): x_pow_n = (x_pow_n * x).add_bigoh(prec) n_inv_factorial /= n exp_x += x_pow_n * n_inv_factorial - result_bg = exp_c*exp_x + result_bg = exp_c * exp_x if result_bg.base_ring() is not self.base_ring(): R = R.change_ring(self.base_ring().fraction_field()) @@ -2051,19 +2041,20 @@ def log(self, prec=infinity): log_c = self.base_ring().zero() else: from sage.functions.log import log + log_c = log(c) - x = 1 - self._bg_value/c + x = 1 - self._bg_value / c if x.is_zero(): return log_c val = x.valuation() - assert (val >= 1) + assert val >= 1 prec = min(prec, self.prec()) if isinstance(prec, InfinityElement): prec = R.default_prec() x_pow_n = Rbg.one() log_x = Rbg.zero().add_bigoh(prec) - for n in range(1,prec//val+1): + for n in range(1, prec // val + 1): x_pow_n = (x_pow_n * x).add_bigoh(prec) log_x += x_pow_n / n result_bg = log_c - log_x @@ -2113,6 +2104,7 @@ class MO: sage: w^2 1 + 2*a + O(a, b, c)^2 """ + def __init__(self, x): """ Initialize ``self``. @@ -2138,4 +2130,4 @@ def __pow__(self, prec): parent = self._vars[0].parent() if self._vars != parent.gens(): raise NotImplementedError - return self._vars[0].parent()(0,prec) + return self._vars[0].parent()(0, prec) diff --git a/src/sage/rings/number_field/S_unit_solver.py b/src/sage/rings/number_field/S_unit_solver.py index 95bca918bd7..d38f0291ea1 100644 --- a/src/sage/rings/number_field/S_unit_solver.py +++ b/src/sage/rings/number_field/S_unit_solver.py @@ -151,11 +151,10 @@ def c3_func(SUK, prec=106): c1 = R(1) # guarantees final c1 >= 1 for U in Possible_U: # first, build the matrix C_{i,U} - columns_of_C = [column_Log(SUK, unit, U, prec) - for unit in SUK.fundamental_units()] + columns_of_C = [column_Log(SUK, unit, U, prec) for unit in SUK.fundamental_units()] C = matrix(SUK.rank(), SUK.rank(), columns_of_C) # Is it invertible? - if abs(C.determinant()) > 10**(-10): + if abs(C.determinant()) > 10 ** (-10): poss_c1 = C.inverse().apply_map(abs).norm(Infinity) c1 = R(max(poss_c1, c1)) return R(0.9999999) / (c1 * SUK.rank()) @@ -237,7 +236,7 @@ def beta_k(betas_and_ns) -> list: good_pair = pair break for pair in betas_and_ns: - if (abs(pair[1]) != 0 and abs(pair[1]) < abs(good_pair[1])): + if abs(pair[1]) != 0 and abs(pair[1]) < abs(good_pair[1]): good_pair = pair return good_pair @@ -274,8 +273,7 @@ def mus(SUK, v) -> list: return betas good_pair = beta_k(beta_and_ns) - temp = [(beta[0]**good_pair[1]) * (good_pair[0]**(-beta[1])) - for beta in beta_and_ns] + temp = [(beta[0] ** good_pair[1]) * (good_pair[0] ** (-beta[1])) for beta in beta_and_ns] temp.remove(1) return temp @@ -325,7 +323,7 @@ def possible_mu0s(SUK, v) -> list: sigma_tilde = -(sum([n_r[0] * n_r[1] for n_r in n_rs])) if sigma_tilde % nk == 0: beta_rs = zip(betas, rs) - temp_prod = prod([beta_r[0]**beta_r[1] for beta_r in beta_rs]) * betak**(sigma_tilde/nk) + temp_prod = prod([beta_r[0] ** beta_r[1] for beta_r in beta_rs]) * betak ** (sigma_tilde / nk) for alpha0 in SUK.roots_of_unity(): if alpha0 * temp_prod not in mu0s: mu0s.append(alpha0 * temp_prod) @@ -370,7 +368,7 @@ def Yu_a1_kappa1_c1(p, dK, ep) -> tuple: a1 = 16 kappa1 = 20 else: - a1 = 8*(p-1)/(p-2) + a1 = 8 * (p - 1) / (p - 2) kappa1 = 10 # Next we compute c(1), which has more cases to consider. @@ -597,11 +595,11 @@ def Yu_C1_star(n, v, prec=106): C1 = R(1) C1 *= c_paren_1 C1 *= a_paren_1**n - C1 *= (n**n * (n+1)**(n+1))/factorial(n) - C1 *= p**fp/(q**u) - C1 *= (dK / (fp * R(p).log()))**(n+2) + C1 *= (n**n * (n + 1) ** (n + 1)) / factorial(n) + C1 *= p**fp / (q**u) + C1 *= (dK / (fp * R(p).log())) ** (n + 2) C1 *= R(max(dK, exp(1))).log() - C1 *= max(R(exp(4)*(n+1)*dK).log(), ep, fp * R(p).log()) + C1 *= max(R(exp(4) * (n + 1) * dK).log(), ep, fp * R(p).log()) return R((n + 1) * C1) @@ -658,7 +656,7 @@ def Yu_bound(SUK, v, prec=106): current_Omega_prime = Omega_prime(dK, v, [mu0] + mu_free_gens[:], prec) largest_Omega_prime = max(current_Omega_prime, largest_Omega_prime) C1star = Yu_C1_star(n, v, prec) - return max(exp(R(2))/R(2).log(), largest_Omega_prime * C1star) + return max(exp(R(2)) / R(2).log(), largest_Omega_prime * C1star) # K and v don't satisfy the theorem hypotheses, and we must move to a quadratic extension L. # For justification of this next bound, see [AKMRVW]. @@ -685,7 +683,7 @@ def Yu_bound(SUK, v, prec=106): current_Omega_prime = Omega_prime(dL, vL, [mu0] + mu_free_gens[:], prec) largest_Omega_prime = max(current_Omega_prime, largest_Omega_prime) C1star = Yu_C1_star(n, vL, prec) - return max(exp(R(2))/R(2).log(), e_vL_v * largest_Omega_prime * C1star) + return max(exp(R(2)) / R(2).log(), e_vL_v * largest_Omega_prime * C1star) def K0_func(SUK, A, prec=106): @@ -725,11 +723,11 @@ def K0_func(SUK, A, prec=106): e_l = v_l.residue_class_degree() Norm_v_l = v_l.absolute_norm() - c5_l = c3/(e_l * R(Norm_v_l).log()) + c5_l = c3 / (e_l * R(Norm_v_l).log()) c8_l = Yu_bound(SUK, v_l, prec) - K0_l = (2 * c8_l)/(e_l * c5_l) * R(c8_l / (e_l * c5_l)).log() + K0_l = (2 * c8_l) / (e_l * c5_l) * R(c8_l / (e_l * c5_l)).log() K0 = max(K0, K0_l) @@ -771,8 +769,8 @@ def c11_func(SUK, v, A, prec=106): """ R = RealField(prec) if is_real_place(v): - return R(4*c4_func(SUK, v, A, prec)).log() / c3_func(SUK, prec) - return 2*R(4*(c4_func(SUK, v, A, prec)).sqrt()).log() / c3_func(SUK, prec) + return R(4 * c4_func(SUK, v, A, prec)).log() / c3_func(SUK, prec) + return 2 * R(4 * (c4_func(SUK, v, A, prec)).sqrt()).log() / c3_func(SUK, prec) def c13_func(SUK, v, prec=106): @@ -821,7 +819,7 @@ def c13_func(SUK, v, prec=106): raise TypeError('Place must be infinite') if is_real_place(v): return c3_func(SUK, prec) - return c3_func(SUK, prec)/2 + return c3_func(SUK, prec) / 2 def K1_func(SUK, v, A, prec=106): @@ -862,9 +860,9 @@ def K1_func(SUK, v, A, prec=106): # [Sma1995]_ p. 825 if is_real_place(v): - c11 = R(4*c4_func(SUK, v, A, prec)).log() / c3_func(SUK, prec) + c11 = R(4 * c4_func(SUK, v, A, prec)).log() / c3_func(SUK, prec) else: - c11 = 2*(R(4*(c4_func(SUK, v, A, prec)).sqrt()).log()) / c3_func(SUK, prec) + c11 = 2 * (R(4 * (c4_func(SUK, v, A, prec)).sqrt()).log()) / c3_func(SUK, prec) # [Sma1995]_ p. 825 if is_real_place(v): @@ -875,11 +873,11 @@ def K1_func(SUK, v, A, prec=106): # [Sma1998]_ p. 225, Theorem A.1 d = SUK.number_field().degree() t = SUK.rank() - Baker_C = R(18 * factorial(t+2) * (t+1)**(t+2) * (32*d)**(t+3) * R(2*(t+1) * d).log()) + Baker_C = R(18 * factorial(t + 2) * (t + 1) ** (t + 2) * (32 * d) ** (t + 3) * R(2 * (t + 1) * d).log()) def hprime(SUK, alpha, v): # [Sma1998]_ p. 225 - return R(max(alpha.global_height(), 1/SUK.number_field().degree(), abs(v(alpha).log()) / SUK.number_field().degree())) + return R(max(alpha.global_height(), 1 / SUK.number_field().degree(), abs(v(alpha).log()) / SUK.number_field().degree())) # [Sma1995]_ p. 825 and [Sma1998]_ p. 225, Theorem A.1 c14 = Baker_C * prod([hprime(SUK, alpha, v) for alpha in SUK.gens_values()]) @@ -887,7 +885,7 @@ def hprime(SUK, alpha, v): # [Sma1995]_ p. 825 c13 = c13_func(SUK, v, prec) w = len(SUK.roots_of_unity()) - c15 = (2/c13)*(c12.log()+c14*(((t+1)*w*c14/c13).log())) + c15 = (2 / c13) * (c12.log() + c14 * (((t + 1) * w * c14 / c13).log())) return max([c11, c15]) @@ -941,15 +939,15 @@ def minimal_vector(A, y, prec=106): R = RealField(prec) n = len(y) - c1 = 2**(n-1) + c1 = 2 ** (n - 1) ALLL = A.LLL() ALLLinv = ALLL.inverse() - ybrace = [abs(R(a-a.round())) for a in y * ALLLinv if (a-a.round()) != 0] + ybrace = [abs(R(a - a.round())) for a in y * ALLLinv if (a - a.round()) != 0] v = ALLL.rows()[0] if len(ybrace) == 0: return v.dot_product(v) / c1 - sigma = ybrace[len(ybrace)-1] + sigma = ybrace[len(ybrace) - 1] return v.dot_product(v) * sigma / c1 @@ -998,9 +996,9 @@ def reduction_step_complex_case(place, B0, list_of_gens, torsion_gen, c13): real_part_log_gens = [R(CF(place(g).log()).real_part()) for g in list_of_gens] imag_part_log_gens = [R(CF(place(g).log()).imag_part()) for g in list_of_gens] real_part_log_gens += [R(0)] - imag_part_log_gens += [2*R.pi()/w] + imag_part_log_gens += [2 * R.pi() / w] - abs_log_parts = [abs(part) for part in real_part_log_gens]+[abs(part) for part in imag_part_log_gens] + abs_log_parts = [abs(part) for part in real_part_log_gens] + [abs(part) for part in imag_part_log_gens] max_part_log = max(abs_log_parts) npi = [] @@ -1008,7 +1006,7 @@ def reduction_step_complex_case(place, B0, list_of_gens, torsion_gen, c13): # if this list is empty, we have to take a special case for i in range(len(real_part_log_gens)): lg = real_part_log_gens[i] - if abs(lg) > 2**(-place.codomain().precision()): + if abs(lg) > 2 ** (-place.codomain().precision()): npi.append(i) # someday make this a separate function if not npi: @@ -1017,14 +1015,14 @@ def reduction_step_complex_case(place, B0, list_of_gens, torsion_gen, c13): C = ZZ(1) S = n * B0**2 - T = (n+w+n*w)*B0 / 2 + T = (n + w + n * w) * B0 / 2 finish = False while not finish: - A = identity_matrix(ZZ, n+1) + A = identity_matrix(ZZ, n + 1) A[n] = vector([(g * C).round() for g in imag_part_log_gens]) if A.is_singular(): - C = ZZ(2*C) + C = ZZ(2 * C) else: # We have to work with rows because of the .LLL() function @@ -1034,33 +1032,33 @@ def reduction_step_complex_case(place, B0, list_of_gens, torsion_gen, c13): l = minimal_vector(A, zero_vector(ZZ, n + 1)) # Checking hypotheses of Lemma 5.3 in our paper: - if l <= T**2+S: - C = ZZ(2*C) + if l <= T**2 + S: + C = ZZ(2 * C) # Need to check precision: must be at least two more than the number of digits in largest entry in A to ensure that we get true rounding-- - if prec < R(C*max_part_log).log()/R(2).log()+3: + if prec < R(C * max_part_log).log() / R(2).log() + 3: return 0, True else: # Need to check precision: must be at least two more than the number of digits in largest entry in A to ensure that we get true rounding-- - if prec < R(C*max_part_log).log()/R(2).log()+3: + if prec < R(C * max_part_log).log() / R(2).log() + 3: return 0, True - Bnew = ((R(C * 2).log() - ((l**2-S).sqrt()-T)).log() / c13).round() + Bnew = ((R(C * 2).log() - ((l**2 - S).sqrt() - T)).log() / c13).round() finish = True return max(4, w, Bnew), False elif is_real_place(place): # this is the case when we are working with a real embedding, we get savings here C = R(1) - S = (n-1) * B0**2 + S = (n - 1) * B0**2 w = place.domain().number_of_roots_of_unity() - T = (n*B0+1)/R(2) + T = (n * B0 + 1) / R(2) finish = False while not finish: - A = copy(identity_matrix(ZZ, n+1)) + A = copy(identity_matrix(ZZ, n + 1)) # We redefine the imaginary parts in case any generator was negative - new_imag_part_log_gens = [0 for i in imag_part_log_gens[:-1]]+[imag_part_log_gens[-1]] - A[n-1] = vector([(g*C).round() for g in real_part_log_gens]) - A[n] = vector([(g*C).round() for g in new_imag_part_log_gens]) + new_imag_part_log_gens = [0 for i in imag_part_log_gens[:-1]] + [imag_part_log_gens[-1]] + A[n - 1] = vector([(g * C).round() for g in real_part_log_gens]) + A[n] = vector([(g * C).round() for g in new_imag_part_log_gens]) if A.is_singular(): C *= 2 @@ -1073,13 +1071,13 @@ def reduction_step_complex_case(place, B0, list_of_gens, torsion_gen, c13): if l <= T**2 + S: C *= 2 # Need to check precision: must be at least two more than the number of digits in largest entry in A to ensure that we get true rounding-- - if prec < R(C*max_part_log).log()/R(2).log()+3: + if prec < R(C * max_part_log).log() / R(2).log() + 3: return 0, True else: # Need to check precision: must be at least two more than the number of digits in largest entry in A to ensure that we get true rounding-- - if prec < R(C*max_part_log).log()/R(2).log()+3: + if prec < R(C * max_part_log).log() / R(2).log() + 3: return 0, True - Bnew = ((R(C * 2).log() - ((l-S).sqrt()-T).log()) / c13).round() + Bnew = ((R(C * 2).log() - ((l - S).sqrt() - T).log()) / c13).round() finish = True return max(4, w, Bnew), False @@ -1087,26 +1085,26 @@ def reduction_step_complex_case(place, B0, list_of_gens, torsion_gen, c13): # the case when the real part is not 0 for all log(a_i), see Lemma 5.2 in [AKMRVW] C = R(1) - S = (n-1) * B0**2 + S = (n - 1) * B0**2 w = place.domain().number_of_roots_of_unity() - T = (n+w+n*w)*B0/R(2).sqrt() + T = (n + w + n * w) * B0 / R(2).sqrt() finish = False # we reorder the generators to that the real part of the last non-torsion generator is not 0: - if n-1 not in npi: + if n - 1 not in npi: new_last_gen_index = npi[0] - old_last_gen_real = real_part_log_gens[n-1] - old_last_gen_imag = imag_part_log_gens[n-1] - real_part_log_gens[n-1] = real_part_log_gens[new_last_gen_index] - imag_part_log_gens[n-1] = imag_part_log_gens[new_last_gen_index] + old_last_gen_real = real_part_log_gens[n - 1] + old_last_gen_imag = imag_part_log_gens[n - 1] + real_part_log_gens[n - 1] = real_part_log_gens[new_last_gen_index] + imag_part_log_gens[n - 1] = imag_part_log_gens[new_last_gen_index] real_part_log_gens[new_last_gen_index] = old_last_gen_real imag_part_log_gens[new_last_gen_index] = old_last_gen_imag while not finish: - A = copy(identity_matrix(ZZ, n+1)) - A[n-1] = vector([(g*C).round() for g in real_part_log_gens]) - A[n] = vector([(g*C).round() for g in imag_part_log_gens]) + A = copy(identity_matrix(ZZ, n + 1)) + A[n - 1] = vector([(g * C).round() for g in real_part_log_gens]) + A[n] = vector([(g * C).round() for g in imag_part_log_gens]) if A.is_singular(): C *= 2 @@ -1119,13 +1117,13 @@ def reduction_step_complex_case(place, B0, list_of_gens, torsion_gen, c13): if l <= T**2 + S: C *= 2 # Need to check precision: must be at least two more than the number of digits in largest entry in A to ensure that we get true rounding-- - if prec < R(C*max_part_log).log()/R(2).log()+3: + if prec < R(C * max_part_log).log() / R(2).log() + 3: return 0, True else: # Need to check precision: must be at least two more than the number of digits in largest entry in A to ensure that we get true rounding-- - if prec < R(C*max_part_log).log()/R(2).log()+3: + if prec < R(C * max_part_log).log() / R(2).log() + 3: return 0, True - Bnew = ((R(C * 2).log() - ((l-S).sqrt()-T).log()) / c13).round() + Bnew = ((R(C * 2).log() - ((l - S).sqrt() - T).log()) / c13).round() finish = True return max(4, w, Bnew), False @@ -1168,7 +1166,7 @@ def cx_LLL_bound(SUK, A, prec=106): cx_bound = K1_func(SUK, v, A, prec_v) new_bound, inc_prec = reduction_step_complex_case(v, cx_bound, SUK.fundamental_units(), SUK.zeta(), c13_LLL) counter = 0 - while abs(cx_bound - new_bound) > .5*cx_bound and counter < 15: + while abs(cx_bound - new_bound) > 0.5 * cx_bound and counter < 15: # We fear a loop that is not convergent, this is the purpose of the counter # Repeat complex LLL until we get essentially no change from it cx_bound = min(cx_bound, new_bound) @@ -1240,19 +1238,18 @@ def log_p(a, prime, prec): # a positive integer, and let tilde(a):=a(prime2)^k. Then log_p(a)=log_p(tilde(a))-k(log_p(prime2)), where the series representations # of these two logs will have smaller coefficients. - primes = [(-(a.valuation(pr)), pr) - for pr in K.primes_above(p) if a.valuation(pr) < 0] + primes = [(-(a.valuation(pr)), pr) for pr in K.primes_above(p) if a.valuation(pr) < 0] local_terms = [] for val, pr in primes: # for its pair in primes we find an element in K such that it is divisible only by pr and not by any other ideal above p. Then we take this element in the correct exponent if pr.is_principal(): - local_terms.append(pr.gens_reduced()[0]**val) + local_terms.append(pr.gens_reduced()[0] ** val) else: - local_terms.append(pr.gens()[1]**val) + local_terms.append(pr.gens()[1] ** val) - return log_p_series_part(a*prod(local_terms), prime, prec) - sum([log_p_series_part(b, prime, prec) for b in local_terms]) + return log_p_series_part(a * prod(local_terms), prime, prec) - sum([log_p_series_part(b, prime, prec) for b in local_terms]) def log_p_series_part(a, prime, prec): @@ -1313,25 +1310,19 @@ def log_p_series_part(a, prime, prec): # since later we divide by p^t, we must increase the precision by t at this point. m = (gamma - 1).valuation(prime) / e n = Integer(1) - step = 10 ** (R(prec).log()/R(10).log()).floor() - while n < (R(n).log()/R(p).log() + prec)/m: + step = 10 ** (R(prec).log() / R(10).log()).floor() + while n < (R(n).log() / R(p).log() + prec) / m: n += step # could use smaller stepsize to get actual smallest integer n, however this seems to run faster. - w = (R(prec).log()/R(p).log()).floor() - gamma = sum([ZZ(gi % (p**(prec+w))) * g**i - if gi.valuation(p) >= 0 else - ZZ((gi * p**(-gi.valuation(p))) % (p**(prec+w-gi.valuation(p)))) * p**(gi.valuation(p)) * g**i - for i, gi in enumerate(gamma) if gi != 0]) + w = (R(prec).log() / R(p).log()).floor() + gamma = sum([ZZ(gi % (p ** (prec + w))) * g ** i if gi.valuation(p) >= 0 else ZZ((gi * p ** (-gi.valuation(p))) % (p ** (prec + w - gi.valuation(p)))) * p ** (gi.valuation(p)) * g**i for i, gi in enumerate(gamma) if gi != 0]) beta = 0 delta = 1 - gamma - for i in range(1, n+1): + for i in range(1, n + 1): beta -= delta / i - delta *= (1 - gamma) - delta = sum([ZZ(di % (p**(prec+w))) * g**b - if di.valuation(p) >= 0 else - ZZ((di * p**(-di.valuation(p))) % (p**(prec + w - di.valuation(p)))) * p**(di.valuation(p)) * g**b - for b, di in enumerate(delta) if di != 0]) + delta *= 1 - gamma + delta = sum([ZZ(di % (p ** (prec + w))) * g ** b if di.valuation(p) >= 0 else ZZ((di * p ** (-di.valuation(p))) % (p ** (prec + w - di.valuation(p)))) * p ** (di.valuation(p)) * g**b for b, di in enumerate(delta) if di != 0]) beta = beta / (order * p**t) # we try to make the coefficients small @@ -1340,8 +1331,8 @@ def log_p_series_part(a, prime, prec): for i, b in enumerate(beta.list()): val = b.valuation(p) if val < 0: - t = b * p**(-val) - t = ZZ(mod(t, p**(prec-val))) + t = b * p ** (-val) + t = ZZ(mod(t, p ** (prec - val))) t = t * p**val else: t = ZZ(mod(b, p**prec)) @@ -1455,7 +1446,7 @@ def embedding_to_Kp(a, prime, prec): gen = K.gen() f = K(a).lift() - return K(sum([b*gen**j for j, b in enumerate(f.mod(g))])) + return K(sum([b * gen**j for j, b in enumerate(f.mod(g))])) def p_adic_LLL_bound_one_prime(prime, B0, M, M_logp, m0, c3, prec=106): @@ -1520,7 +1511,7 @@ def p_adic_LLL_bound_one_prime(prime, B0, M, M_logp, m0, c3, prec=106): sage: increase_prec False """ - if any(g.valuation(prime) != 0 for g in M+[m0]): + if any(g.valuation(prime) != 0 for g in M + [m0]): raise ValueError('There is an element with nonzero valuation') K = prime.ring() @@ -1529,13 +1520,13 @@ def p_adic_LLL_bound_one_prime(prime, B0, M, M_logp, m0, c3, prec=106): f = prime.residue_class_degree() e = prime.absolute_ramification_index() R = RealField(prec) - c5 = c3 / (f*e*R(p).log()) + c5 = c3 / (f * e * R(p).log()) theta = K.gen() # if M is empty then it is easy to give an upper bound if not M: if m0 != 1: - return max(4, w, R(max(R(p).log()*f*(m0-1).valuation(prime)/c3, 0)).floor()), False + return max(4, w, R(max(R(p).log() * f * (m0 - 1).valuation(prime) / c3, 0)).floor()), False return 0, False # we evaluate the p-adic logarithms of m0 and we embed it in the completion of K with respect to prime @@ -1560,18 +1551,18 @@ def p_adic_LLL_bound_one_prime(prime, B0, M, M_logp, m0, c3, prec=106): # In one very extreme case (p = 2 and all other constants as small as possible), # low_bound = 1/c5 is not quite enough to give strict inequality. So we add 1 to be safe. - low_bound = (1/c5).round() + 1 + low_bound = (1 / c5).round() + 1 for a in m0_logp: if a != 0 and c8 > a.valuation(p): - B1 = (c8 + ordp_Disc/2) / c5 + B1 = (c8 + ordp_Disc / 2) / c5 if B1 > low_bound: return max(4, w, RR(B1).floor()), False return max(4, w, low_bound), False c8 = min([a.valuation(p) for a in m0_logp] + [c8]) - B = [g/lam for g in M_logp] + B = [g / lam for g in M_logp] b0 = m0_logp / lam - c9 = c8 + ordp_Disc/2 + c9 = c8 + ordp_Disc / 2 # We evaluate 'u' and we construct the matrix A @@ -1591,13 +1582,13 @@ def p_adic_LLL_bound_one_prime(prime, B0, M, M_logp, m0, c3, prec=106): A21[i] = vector([mod(b[j], p**u) for j in range(m)]) A = block_matrix([[A11, A12], [A21.transpose(), A22]]) - y = zero_vector(ZZ, n+m) + y = zero_vector(ZZ, n + m) for i in range(m): - y[i+n] = -mod(b0[i], p**u) + y[i + n] = -mod(b0[i], p**u) # This refers to c10 from Smart c10squared = minimal_vector(A.transpose(), y) if c10squared > n * B0**2: - B2 = (u+c9) / c5 + B2 = (u + c9) / c5 if B2 > low_bound: return max(4, w, R(B2).floor()), False return max(4, w, low_bound), False @@ -1895,7 +1886,7 @@ def construct_rfv_to_ev(rfv_dictionary, q, d, verbose=False) -> dict: for exponent_vector in rfv_dictionary: residue_field_vector = rfv_dictionary[exponent_vector] - rf_vector_start = (residue_field_vector[0], ) + rf_vector_start = (residue_field_vector[0],) rf_vector_end = residue_field_vector[1:] P[rf_vector_start].append([exponent_vector, rf_vector_end]) @@ -1918,9 +1909,9 @@ def construct_rfv_to_ev(rfv_dictionary, q, d, verbose=False) -> dict: # # During the construction, we look for impossible entries for S-unit solutions, and drop them from the dictionary as needed. - for j in range(d-1): + for j in range(d - 1): if verbose: - print("Constructing ", j, " th place of the residue field vectors, out of ", d-1, " total.") + print("Constructing ", j, " th place of the residue field vectors, out of ", d - 1, " total.") P_new = {} garbage = {} @@ -1947,9 +1938,9 @@ def construct_rfv_to_ev(rfv_dictionary, q, d, verbose=False) -> dict: for rf_vector_start in P_new: # the final entry of rf_vector_start or rf_vector_complement_start must be < (q+3)/2. # No loss to insist that it is rf_vector_start. - if rf_vector_start[-1] < (q+3)/2: + if rf_vector_start[-1] < (q + 3) / 2: # we find the complement to rf_vector_start: - rf_vector_complement_start = tuple([q+1-j for j in rf_vector_start]) + rf_vector_complement_start = tuple([q + 1 - j for j in rf_vector_start]) if P_new[rf_vector_start] == [] or P_new[rf_vector_complement_start] == []: # these can't be solutions. Mark them for deletion. garbage[rf_vector_start] = True @@ -2097,14 +2088,14 @@ def drop_vector(ev, p, q, complement_ev_dict) -> bool: # returns True if it is OK to drop exp_vec given the current comp_exp_vec dictionary associated to some q. # returns False otherwise # loop over the possible compatible vectors in the other modulus - g = gcd(p-1, q-1) - for compatible_exp_vec in compatible_vectors(ev, p-1, q-1, g): + g = gcd(p - 1, q - 1) + for compatible_exp_vec in compatible_vectors(ev, p - 1, q - 1, g): # do they appear in the other dictionary? if compatible_exp_vec in complement_ev_dict[q]: # OK, but the complements need to be compatible, too! ev_complement_list = complement_ev_dict[p][ev] for ev_comp in ev_complement_list: - for compatible_cv in compatible_vectors(ev_comp, p-1, q-1, g): + for compatible_cv in compatible_vectors(ev_comp, p - 1, q - 1, g): if compatible_cv in complement_ev_dict[q][compatible_exp_vec]: return False return True @@ -2211,9 +2202,9 @@ def epsilon_q(a, i): # returns the value of rho_j^a_j inside the # residue field of Qi. (Necessarily isomorphic to F_q.) # rho_images[i][j] == rho[j] modulo Q[i] - eps_value = rho_images[i][0]**a[0] + eps_value = rho_images[i][0] ** a[0] for j in range(1, rho_length): - eps_value *= rho_images[i][j]**a[j] + eps_value *= rho_images[i][j] ** a[j] return eps_value if verbose: @@ -2231,7 +2222,7 @@ def epsilon_q(a, i): # This should consist of all vectors (a0,...,a_{t-1}), where # a0 is in the range 0 .. w_0 - 1 and # aj is in the range 0 .. q - 2 (for j > 0) - ranges = [range(w0)] + [range(q-1) for _ in range(rho_length-1)] + ranges = [range(w0)] + [range(q - 1) for _ in range(rho_length - 1)] ev_iterator = itertools.product(*ranges) # With the iterator built, we construct the exponent vector to residue field dictionary. @@ -2250,10 +2241,10 @@ def epsilon_q(a, i): # we only consider those evs which are compatible with the mod q0 - 1 vectors. # Loop over exponent vectors modulo q0 - 1 - g = gcd(q0-1, q-1) + g = gcd(q0 - 1, q - 1) for exp_vec_mod_q0 in comp_exp_vec[q0]: # Loop only over exponent vectors modulo q-1 which are compatible with exp_vec_mod_q0 - for exp_vec in compatible_vectors(exp_vec_mod_q0, q0-1, q-1, g): + for exp_vec in compatible_vectors(exp_vec_mod_q0, q0 - 1, q - 1, g): # fill the dictionary with the residue field vectors using the evaluation function. ev_to_rfv_dict[exp_vec] = [epsilon_q(exp_vec, i) for i in range(nK)] @@ -2296,9 +2287,9 @@ def epsilon_q(a, i): if verbose: print("Size of comp_exp_vec[p] is: ", old_size_p, ".") - cv_size = ((q-1)/gcd(p-1, q-1)) ** (rho_length - 1) + cv_size = ((q - 1) / gcd(p - 1, q - 1)) ** (rho_length - 1) print("Length of compatible_vectors: ", cv_size, ".") - print("Product: ", old_size_p*cv_size) + print("Product: ", old_size_p * cv_size) for exp_vec in list(comp_exp_vec[p]): if drop_vector(exp_vec, p, q, comp_exp_vec): @@ -2313,7 +2304,7 @@ def epsilon_q(a, i): if verbose: print("Size of comp_exp_vec[q] is: ", old_size_q, ".") - cv_size = ((p - 1) / gcd(p - 1, q - 1))**(rho_length - 1) + cv_size = ((p - 1) / gcd(p - 1, q - 1)) ** (rho_length - 1) print("Length of compatible_vectors: ", cv_size, ".") print("Product: ", old_size_q * cv_size) @@ -2367,9 +2358,7 @@ def compatible_vectors_check(a0, a1, g, l) -> bool: False """ # exponent vectors must agree exactly in the 0th coordinate. - return a0[0] == a1[0] and all((x0 - x1) % g == 0 - for x0, x1 in zip(itertools.islice(a0, 1, l), - itertools.islice(a1, 1, l))) + return a0[0] == a1[0] and all((x0 - x1) % g == 0 for x0, x1 in zip(itertools.islice(a0, 1, l), itertools.islice(a1, 1, l))) def compatible_vectors(a, m0, m1, g): @@ -2412,8 +2401,7 @@ def compatible_vectors(a, m0, m1, g): 27 """ # recall that the 0th entry must be an exact match. - ranges = [[a[0]]] + [range(a[i] % g, (a[i] % g) + m1, g) - for i in range(1, len(a))] + ranges = [[a[0]]] + [range(a[i] % g, (a[i] % g) + m1, g) for i in range(1, len(a))] return itertools.product(*ranges) @@ -2474,9 +2462,7 @@ def compatible_systems(split_prime_list, complement_exp_vec_dict): l = len(exp_vec) for comp_vec in complement_exp_vec_dict[q][exp_vec]: for old_system in old_systems: - if all((compatible_vectors_check(exp_vec, exp_vec_qj, g, l) and - compatible_vectors_check(comp_vec, comp_vec_qj, g, l)) - for g, (exp_vec_qj, comp_vec_qj) in zip(gcds, old_system)): + if all((compatible_vectors_check(exp_vec, exp_vec_qj, g, l) and compatible_vectors_check(comp_vec, comp_vec_qj, g, l)) for g, (exp_vec_qj, comp_vec_qj) in zip(gcds, old_system)): # build the new system and append it to the list. new_system = old_system + [[exp_vec, comp_vec]] system_list.append(new_system) @@ -2636,8 +2622,7 @@ def clean_sfs(sfs_list) -> list: return new_sfs -def sieve_below_bound(K, S, bound=10, bump=10, - split_primes_list=[], verbose=False): +def sieve_below_bound(K, S, bound=10, bump=10, split_primes_list=[], verbose=False): r""" Return all solutions to the `S`-unit equation `x + y = 1` over `K` with exponents below the given bound. diff --git a/src/sage/rings/number_field/all.py b/src/sage/rings/number_field/all.py index f6fadbc6c93..235dc943bd6 100644 --- a/src/sage/rings/number_field/all.py +++ b/src/sage/rings/number_field/all.py @@ -1,7 +1,4 @@ - -from sage.rings.number_field.number_field import (NumberField, NumberFieldTower, - CyclotomicField, QuadraticField, - is_real_place) +from sage.rings.number_field.number_field import NumberField, NumberFieldTower, CyclotomicField, QuadraticField, is_real_place from sage.rings.number_field.number_field_element import NumberFieldElement from sage.rings.number_field.order import EquationOrder, GaussianIntegers, EisensteinIntegers @@ -10,10 +7,8 @@ lazy_import('sage.rings.number_field.totallyreal', 'enumerate_totallyreal_fields_prim') lazy_import('sage.rings.number_field.totallyreal_data', 'hermite_constant') -lazy_import('sage.rings.number_field.totallyreal_rel', - 'enumerate_totallyreal_fields_all') -lazy_import('sage.rings.number_field.totallyreal_rel', - 'enumerate_totallyreal_fields_rel') +lazy_import('sage.rings.number_field.totallyreal_rel', 'enumerate_totallyreal_fields_all') +lazy_import('sage.rings.number_field.totallyreal_rel', 'enumerate_totallyreal_fields_rel') from sage.rings.number_field.unit_group import UnitGroup diff --git a/src/sage/rings/number_field/bdd_height.py b/src/sage/rings/number_field/bdd_height.py index f37d890fcb1..10d103f1666 100644 --- a/src/sage/rings/number_field/bdd_height.py +++ b/src/sage/rings/number_field/bdd_height.py @@ -191,8 +191,7 @@ def bdd_height_iq(K, height_bound): for n in range(class_number): this_ideal = class_group_reps[n] this_ideal_norm = class_group_rep_norms[n] - gens = [g for i in range(1, int(height_bound + 1)) - for g in bdd_ideals[i * this_ideal_norm] if g in this_ideal] + gens = [g for i in range(1, int(height_bound + 1)) for g in bdd_ideals[i * this_ideal_norm] if g in this_ideal] generator_lists.append(gens) # Build all the output numbers @@ -437,11 +436,11 @@ def rational_in(x, y): if z == 0: n = 1 else: - n = RR(1/z).ceil() + 1 - if RR(n*y).ceil() is n*y: # WHAT !? - m = n*y - 1 + n = RR(1 / z).ceil() + 1 + if RR(n * y).ceil() is n * y: # WHAT !? + m = n * y - 1 else: - m = RR(n*y).floor() + m = RR(n * y).floor() return m / n def delta_approximation(x, delta): @@ -481,7 +480,7 @@ def log_height_for_generators_approx(alpha, beta, Lambda): log_ga = vector_delta_approximation(log_map(alpha), delta) log_gb = vector_delta_approximation(log_map(beta), delta) arch_sum = sum([max(log_ga[k], log_gb[k]) for k in range(r + 1)]) - return (arch_sum - norm_log) + return arch_sum - norm_log def packet_height(n, pair, u): r""" @@ -494,12 +493,12 @@ def packet_height(n, pair, u): Log_gj = lambda_gens_approx[gens[j]] Log_u_gi = vector(Log_gi) + unit_log_dict[u] arch_sum = sum([max(Log_u_gi[k], Log_gj[k]) for k in range(r + 1)]) - return (arch_sum - class_group_rep_norm_log_approx[n]) + return arch_sum - class_group_rep_norm_log_approx[n] # Step 1 # Computes ideal class representative and their rational approx norm - t = theta / (3*B) - delta_1 = t / (6*r+12) + t = theta / (3 * B) + delta_1 = t / (6 * r + 12) class_group_reps = [] class_group_rep_norms = [] @@ -552,19 +551,19 @@ def packet_height(n, pair, u): gens = generator_lists[n] l = len(gens) for i in range(l): - for j in range(i+1, l): + for j in range(i + 1, l): if K.ideal(gens[i], gens[j]) == class_group_reps[n]: relevant_pairs.append([i, j]) - gen_height_approx_dictionary[(n, i, j)] = log_height_for_generators_approx(gens[i], gens[j], t/6) + gen_height_approx_dictionary[(n, i, j)] = log_height_for_generators_approx(gens[i], gens[j], t / 6) relevant_pair_lists.append(relevant_pairs) # Step 5 - b = rational_in(t/12 + RR(B).log(), t/4 + RR(B).log()) + b = rational_in(t / 12 + RR(B).log(), t / 4 + RR(B).log()) maximum = 0 for n in range(class_number): for p in relevant_pair_lists[n]: maximum = max(maximum, gen_height_approx_dictionary[(n, p[0], p[1])]) - d_tilde = b + t/6 + maximum + d_tilde = b + t / 6 + maximum # Step 6 # computes fundamental units and their value under log map @@ -580,12 +579,12 @@ def packet_height(n, pair, u): # Step 7 # Variables needed for rational approximation - lambda_tilde = (t/12) / (d_tilde*r*(1+m)) - delta_tilde = min(lambda_tilde/((r**2)*((m**2)+m*lambda_tilde)), 1/(r**2)) - M = d_tilde * (upper_bound+lambda_tilde*RR(r).sqrt()) + lambda_tilde = (t / 12) / (d_tilde * r * (1 + m)) + delta_tilde = min(lambda_tilde / ((r**2) * ((m**2) + m * lambda_tilde)), 1 / (r**2)) + M = d_tilde * (upper_bound + lambda_tilde * RR(r).sqrt()) M = RR(M).ceil() d_tilde = RR(d_tilde) - delta_2 = min(delta_tilde, (t/6)/(r*(r+1)*M)) + delta_2 = min(delta_tilde, (t / 6) / (r * (r + 1) * M)) # Step 8, 9 # Computes relevant points in polytope @@ -606,18 +605,18 @@ def packet_height(n, pair, u): # Computes unit height unit_height_dict = {} U_copy = copy(U) - inter_bound = b - (5*t)/12 + inter_bound = b - (5 * t) / 12 for u in U: - u_log = sum([u[j]*vector(fund_unit_log_approx[j]) for j in range(r)]) + u_log = sum([u[j] * vector(fund_unit_log_approx[j]) for j in range(r)]) unit_log_dict[u] = u_log u_height = sum([max(u_log[k], 0) for k in range(r + 1)]) unit_height_dict[u] = u_height if u_height < inter_bound: U0.append(u) - if inter_bound <= u_height < b - (t/12): + if inter_bound <= u_height < b - (t / 12): U0_tilde.append(u) - if u_height > t/12 + d_tilde: + if u_height > t / 12 + d_tilde: U_copy.remove(u) U = U_copy @@ -629,14 +628,14 @@ def packet_height(n, pair, u): for pair in relevant_pair_lists[n]: i = pair[0] j = pair[1] - u_height_bound = b + gen_height_approx_dictionary[(n, i, j)] + t/4 + u_height_bound = b + gen_height_approx_dictionary[(n, i, j)] + t / 4 for u in U: if unit_height_dict[u] < u_height_bound: candidate_height = packet_height(n, pair, u) - if candidate_height <= b - 7*t/12: + if candidate_height <= b - 7 * t / 12: L0.append([n, pair, u]) relevant_tuples.add(u) - elif candidate_height < b + t/4: + elif candidate_height < b + t / 4: L0_tilde.append([n, pair, u]) relevant_tuples.add(u) @@ -646,7 +645,7 @@ def packet_height(n, pair, u): for u in relevant_tuples: unit = K.one() for k in range(r): - unit *= fund_units[k]**u[k] + unit *= fund_units[k] ** u[k] tuple_to_unit_dict[u] = unit # Step 14 diff --git a/src/sage/rings/number_field/class_group.py b/src/sage/rings/number_field/class_group.py index f206e17a7a5..5fd4293bd10 100644 --- a/src/sage/rings/number_field/class_group.py +++ b/src/sage/rings/number_field/class_group.py @@ -69,6 +69,7 @@ class FractionalIdealClass(AbelianGroupWithValuesElement): sage: c.gens() (2, 1/2*w - 1/2) """ + def __init__(self, parent, element, ideal=None): """ Return the ideal class of this fractional ideal. @@ -298,6 +299,7 @@ def representative_prime(self, norm_bound=1000): Cl = self.parent() K = Cl.number_field() from sage.rings.real_mpfr import RR + for P in K.primes_of_bounded_norm_iter(RR(norm_bound)): if Cl(P) == c: return P @@ -433,6 +435,7 @@ class ClassGroup(AbelianGroupWithValues_class): sage: c.exponents() (1, 0) """ + Element = FractionalIdealClass def __init__(self, gens_orders, names, number_field, gens, proof=True): @@ -446,8 +449,7 @@ def __init__(self, gens_orders, names, number_field, gens, proof=True): sage: G = K.class_group() sage: TestSuite(G).run() """ - AbelianGroupWithValues_class.__init__(self, gens_orders, names, gens, - values_group=number_field.ideal_monoid()) + AbelianGroupWithValues_class.__init__(self, gens_orders, names, gens, values_group=number_field.ideal_monoid()) self._proof_flag = proof self._number_field = number_field @@ -648,6 +650,7 @@ class SClassGroup(ClassGroup): sage: CS.gen(1) # random Fractional S-ideal class (31, a + 24) """ + Element = SFractionalIdealClass def __init__(self, gens_orders, names, number_field, gens, S, proof=True): @@ -665,8 +668,7 @@ def __init__(self, gens_orders, names, number_field, gens, S, proof=True): sage: K.S_class_group([K.ideal(13, a + 8)]) S-class group of order 4 with structure C2 x C2 of Number Field in a with defining polynomial x^2 + 105 with a = 10.24695076595960?*I """ - AbelianGroupWithValues_class.__init__(self, gens_orders, names, gens, - values_group=number_field.ideal_monoid()) + AbelianGroupWithValues_class.__init__(self, gens_orders, names, gens, values_group=number_field.ideal_monoid()) self._proof_flag = proof self._number_field = number_field self._S = S diff --git a/src/sage/rings/number_field/galois_group.py b/src/sage/rings/number_field/galois_group.py index fb943b33d29..1d9754faa8d 100644 --- a/src/sage/rings/number_field/galois_group.py +++ b/src/sage/rings/number_field/galois_group.py @@ -134,7 +134,7 @@ def _pol_galgp(self, algorithm=None): """ algorithm = self._get_algorithm(algorithm) f = self._field.absolute_polynomial() - pari_group = (self._type != "gap") # while GaloisGroup_v1 is deprecated + pari_group = self._type != "gap" # while GaloisGroup_v1 is deprecated return f.galois_group(pari_group=pari_group, algorithm=algorithm) @cached_method(key=_alg_key) @@ -752,8 +752,8 @@ def ramification_breaks(self, P): ramdata = self._ramgroups(P) n = len(ramdata) from sage.sets.set import Set - return Set([i - 1 for i in range(n - 1) - if ramdata[i][1] != ramdata[i + 1][1]] + [n - 2]) + + return Set([i - 1 for i in range(n - 1) if ramdata[i][1] != ramdata[i + 1][1]] + [n - 2]) def artin_symbol(self, P): r""" @@ -862,6 +862,7 @@ class GaloisGroup_subgroup(GaloisSubgroup_perm): sage: G.artin_symbol(P) () """ + @lazy_attribute def _pari_data(self): """ @@ -952,7 +953,7 @@ def fixed_field(self, name=None, polred=None, threshold=None): x = v[1] if polred is None: index = G.order() // self.order() - polred = (index <= 8) + polred = index <= 8 if polred: f = x.minpoly() bitsize = ZZ(QQ(f[0]).numerator().nbits() + QQ(f[0]).denominator().nbits()) @@ -991,6 +992,7 @@ class GaloisGroupElement(PermutationGroupElement): sage: G[4](G[4](G[4](v))) 1/18*y^4 """ + @cached_method def as_hom(self): r""" diff --git a/src/sage/rings/number_field/homset.py b/src/sage/rings/number_field/homset.py index dd04721f714..eaa8705aad3 100644 --- a/src/sage/rings/number_field/homset.py +++ b/src/sage/rings/number_field/homset.py @@ -15,9 +15,7 @@ from sage.misc.cachefunc import cached_method from sage.rings.homset import RingHomset_generic -from sage.rings.number_field.morphism import (NumberFieldHomomorphism_im_gens, - RelativeNumberFieldHomomorphism_from_abs, - CyclotomicFieldHomomorphism_im_gens) +from sage.rings.number_field.morphism import NumberFieldHomomorphism_im_gens, RelativeNumberFieldHomomorphism_from_abs, CyclotomicFieldHomomorphism_im_gens from sage.rings.integer import Integer from sage.rings.finite_rings.integer_mod_ring import Zmod from sage.structure.sequence import Sequence @@ -52,6 +50,7 @@ def __init__(self, R, S, category=None): if category is None: from sage.categories.fields import Fields from sage.categories.number_fields import NumberFields + if S in NumberFields(): category = NumberFields() elif S in Fields(): @@ -104,16 +103,20 @@ def _element_constructor_(self, x, check=True): return self.element_class(self, x, check=check) from sage.categories.number_fields import NumberFields from sage.categories.rings import Rings - if (x.parent() == self or - (x.domain() == self.domain() and x.codomain() == self.codomain() and - # This would be the better check, however it returns False currently: - # self.homset_category().is_full_subcategory(x.category_for()) - # So we check instead that this is a morphism anywhere between - # Rings and NumberFields where the hom spaces do not change. - NumberFields().is_subcategory(self.homset_category()) and - self.homset_category().is_subcategory(Rings()) and - NumberFields().is_subcategory(x.category_for()) and - x.category_for().is_subcategory(Rings()))): + + if x.parent() == self or ( + x.domain() == self.domain() + and x.codomain() == self.codomain() + and + # This would be the better check, however it returns False currently: + # self.homset_category().is_full_subcategory(x.category_for()) + # So we check instead that this is a morphism anywhere between + # Rings and NumberFields where the hom spaces do not change. + NumberFields().is_subcategory(self.homset_category()) + and self.homset_category().is_subcategory(Rings()) + and NumberFields().is_subcategory(x.category_for()) + and x.category_for().is_subcategory(Rings()) + ): return self.element_class(self, x.im_gens(), check=False) def _an_element_(self): @@ -139,8 +142,8 @@ def _an_element_(self): if len(L) != 0: return L[0] from sage.categories.sets_cat import EmptySetError - raise EmptySetError("There is no morphism from {} to {}".format( - self.domain(), self.codomain())) + + raise EmptySetError("There is no morphism from {} to {}".format(self.domain(), self.codomain())) def _repr_(self): r""" @@ -377,8 +380,7 @@ def _element_constructor_(self, x, base_map=None, check=True): if x.codomain() != self.codomain(): raise ValueError("codomain of absolute homomorphism must be codomain of this homset.") return self.element_class(self, x) - if (isinstance(x, RelativeNumberFieldHomomorphism_from_abs) - and x.parent() == self): + if isinstance(x, RelativeNumberFieldHomomorphism_from_abs) and x.parent() == self: return self.element_class(self, x.abs_hom()) if base_map is None: base_map = self.default_base_hom() @@ -561,8 +563,7 @@ def _element_constructor_(self, x, check=True): sage: (x^2 + a).change_ring(phi) x^2 + b """ - if (isinstance(x, CyclotomicFieldHomomorphism_im_gens) - and x.parent() == self): + if isinstance(x, CyclotomicFieldHomomorphism_im_gens) and x.parent() == self: return self.element_class(self, x.im_gens()) return self.element_class(self, x, check=check) diff --git a/src/sage/rings/number_field/maps.py b/src/sage/rings/number_field/maps.py index 689ac6079bd..eba8a5316b9 100644 --- a/src/sage/rings/number_field/maps.py +++ b/src/sage/rings/number_field/maps.py @@ -24,7 +24,7 @@ x^6 - 3*x^5 + 6*x^4 - 11*x^3 + 12*x^2 + 3*x + 1 """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2008 William Stein # # Distributed under the terms of the GNU General Public License (GPL) @@ -37,7 +37,7 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.map import Map from sage.categories.homset import Hom @@ -63,6 +63,7 @@ class NumberFieldIsomorphism(Map): sage: isinstance(fr, sage.rings.number_field.maps.NumberFieldIsomorphism) True """ + def _repr_type(self) -> str: r""" EXAMPLES:: @@ -204,6 +205,7 @@ class MapNumberFieldToVectorSpace(Map): sage: type(to) """ + def __init__(self, K, V): r""" Standard initialisation function. @@ -278,6 +280,7 @@ class MapRelativeVectorSpaceToRelativeNumberField(NumberFieldIsomorphism): sage: (to * fr)(V([1, 2])) == V([1, 2]) True """ + def __init__(self, V, K): r""" @@ -414,6 +417,7 @@ class NameChangeMap(NumberFieldIsomorphism): (, ) """ + def __init__(self, K, L): r""" EXAMPLES:: @@ -543,6 +547,7 @@ class MapAbsoluteToRelativeNumberField(NumberFieldIsomorphism): r""" See :class:`~MapRelativeToAbsoluteNumberField` for examples. """ + def __init__(self, A, R): r""" EXAMPLES:: @@ -651,6 +656,7 @@ class MapRelativeNumberFieldToVectorSpace(NumberFieldIsomorphism): sage: to(L.gen()), fr(to(L.gen())) == L.gen() ((0, 1, 0, 0, 0, 0, 0, 0), True) """ + def __init__(self, L, V, to_K, to_V): r""" EXAMPLES:: diff --git a/src/sage/rings/number_field/morphism.py b/src/sage/rings/number_field/morphism.py index 29ecfefb321..170076fe9ff 100644 --- a/src/sage/rings/number_field/morphism.py +++ b/src/sage/rings/number_field/morphism.py @@ -79,10 +79,8 @@ def __invert__(self): raise TypeError("Can only invert isomorphisms") V, V_into_K, _ = K.vector_space() _, _, L_into_W = L.vector_space() - linear_inverse = ~V.hom([(L_into_W * self * V_into_K)(b) - for b in V.basis()]) - return L.hom([(V_into_K * linear_inverse * L_into_W)(b) - for b in [L.gen()]]) + linear_inverse = ~V.hom([(L_into_W * self * V_into_K)(b) for b in V.basis()]) + return L.hom([(V_into_K * linear_inverse * L_into_W)(b) for b in [L.gen()]]) def preimage(self, y): r""" @@ -124,24 +122,25 @@ def preimage(self, y): # try to get the cached transformation matrix and vector space isomorphisms if they exist try: - M,LtoV,VtoK = self._transformation_data + M, LtoV, VtoK = self._transformation_data except Exception: # get the identifications of K and L with vector spaces over Q - V,VtoL,LtoV = self.codomain().absolute_vector_space() - V,VtoK,KtoV = self.domain().absolute_vector_space() + V, VtoL, LtoV = self.codomain().absolute_vector_space() + V, VtoK, KtoV = self.domain().absolute_vector_space() # construct the transformation matrix from K to L by making the columns be the image of the basis of V_K in V_L using the homomorphism from sage.matrix.constructor import matrix from sage.rings.rational_field import QQ + M = matrix(QQ, [LtoV(self(VtoK(e))) for e in V.basis()]).transpose() - self._transformation_data = (M,LtoV,VtoK) + self._transformation_data = (M, LtoV, VtoK) # get the coordinate vector of y, solve the linear system, pass to domain - yvec = LtoV(y) # pass from a point in L to its vector space representation + yvec = LtoV(y) # pass from a point in L to its vector space representation try: - xvec = M.solve_right(yvec) # solve the linear system, throws an exception if there is no solution + xvec = M.solve_right(yvec) # solve the linear system, throws an exception if there is no solution except ValueError: raise ValueError("Element '{}' is not in the image of this homomorphism.".format(y)) - return VtoK(xvec) # pass from the vector space representation of K back to a point in K + return VtoK(xvec) # pass from the vector space representation of K back to a point in K class RelativeNumberFieldHomomorphism_from_abs(RingHomomorphism): @@ -244,8 +243,7 @@ def _repr_defn(self): """ D = self.domain() ig = self.im_gens() - return '\n'.join('%s |--> %s' % (D.gen(i), ig[i]) - for i in range(D.ngens())) + return '\n'.join('%s |--> %s' % (D.gen(i), ig[i]) for i in range(D.ngens())) def _call_(self, x): r""" diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 74a54f563b0..58bd2aa24f6 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -224,9 +224,7 @@ def proof_flag(t): return get_flag(t, "number_field") -def NumberField(polynomial, name=None, check=True, names=None, embedding=None, - latex_name=None, assume_disc_small=False, maximize_at_primes=None, structure=None, - *, latex_names=None, **kwds): +def NumberField(polynomial, name=None, check=True, names=None, embedding=None, latex_name=None, assume_disc_small=False, maximize_at_primes=None, structure=None, *, latex_names=None, **kwds): r""" Return *the* number field (or tower of number fields) defined by the irreducible ``polynomial``. @@ -607,6 +605,7 @@ class NumberFieldFactory(UniqueFactory): From: Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? To: Number Field in b with defining polynomial x^2 - 2) """ + def create_key_and_extra_args(self, polynomial, name, check, embedding, latex_name, assume_disc_small, maximize_at_primes, structure): r""" Create a unique key for the number field specified by the parameters. @@ -679,10 +678,9 @@ def create_object(self, version, key, check): if isinstance(base, NumberField_generic): from sage.rings.number_field.number_field_rel import NumberField_relative + # Relative number fields do not support embeddings. - return NumberField_relative(base, polynomial, name[0], latex_name, - check=check, embedding=None, - structure=structure) + return NumberField_relative(base, polynomial, name[0], latex_name, check=check, embedding=None, structure=structure) if polynomial.degree() == 2: return NumberField_quadratic(polynomial, name, latex_name, check, embedding, assume_disc_small=assume_disc_small, maximize_at_primes=maximize_at_primes, structure=structure) return NumberField_absolute(polynomial, name, latex_name, check, embedding, assume_disc_small=assume_disc_small, maximize_at_primes=maximize_at_primes, structure=structure) @@ -1119,6 +1117,7 @@ class CyclotomicFieldFactory(UniqueFactory): sage: cf9(z3) zeta9^3 """ + def create_key(self, n=0, names=None, embedding=True): r""" Create the unique key for the cyclotomic field specified by the @@ -1156,6 +1155,7 @@ def create_object(self, version, key, **extra_args): n, names, embedding = key if n == 0: from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField + return UniversalCyclotomicField() return NumberField_cyclotomic(n, names, embedding=embedding) @@ -1275,10 +1275,8 @@ class NumberField_generic(WithEqualityById, number_field_base.NumberField): ....: elt = f.q_eigenform(10, 'alpha')[3] ....: assert elt.is_integral() """ - def __init__(self, polynomial, name, latex_name, - check=True, embedding=None, category=None, - assume_disc_small=False, maximize_at_primes=None, - structure=None) -> None: + + def __init__(self, polynomial, name, latex_name, check=True, embedding=None, category=None, assume_disc_small=False, maximize_at_primes=None, structure=None) -> None: """ Create a number field. @@ -1400,6 +1398,7 @@ def _convert_map_from_(self, other): i - a """ from sage.categories.map import Map + if self._structure is not None: structure = self.structure() if len(structure) >= 2: @@ -1534,6 +1533,7 @@ def construction(self): """ from sage.categories.pushout import AlgebraicExtensionFunctor from sage.rings.rational_field import QQ + names = self.variable_names() polys = [] embeddings = [] @@ -1546,8 +1546,7 @@ def construction(self): structures.append(K._structure) latex_names.append(K.latex_variable_names()[0]) K = K.base_field() - return (AlgebraicExtensionFunctor(polys, names, embeddings, structures, - latex_names=latex_names), QQ) + return (AlgebraicExtensionFunctor(polys, names, embeddings, structures, latex_names=latex_names), QQ) def _element_constructor_(self, x, check=True): r""" @@ -1676,9 +1675,7 @@ def _element_constructor_(self, x, check=True): K = x.parent() if K is self: return x - if isinstance(x, (OrderElement_absolute, - OrderElement_relative, - OrderElement_quadratic)): + if isinstance(x, (OrderElement_absolute, OrderElement_relative, OrderElement_quadratic)): L = K.number_field() if L is self: return self._element_class(self, x) @@ -1704,8 +1701,8 @@ def _element_constructor_(self, x, check=True): var = self.absolute_polynomial().variable_name() if check and self.pari_polynomial(var) != self.absolute_polynomial().monic(): from warnings import warn - warn("interpreting PARI polynomial %s relative to the defining polynomial %s of the PARI number field" - % (x, self.pari_polynomial())) + + warn("interpreting PARI polynomial %s relative to the defining polynomial %s of the PARI number field" % (x, self.pari_polynomial())) beta = self._pari_absolute_structure()[2] x = x(beta).lift() else: # constant polynomial @@ -1721,8 +1718,7 @@ def _element_constructor_(self, x, check=True): return self._convert_from_str(s.replace('!', '')) if isinstance(x, str): return self._convert_from_str(x) - if isinstance(x, (tuple, list, - sage.modules.free_module_element.FreeModuleElement)): + if isinstance(x, (tuple, list, sage.modules.free_module_element.FreeModuleElement)): if len(x) != self.relative_degree(): raise ValueError("Length must be equal to the degree of this number field") base = self.base_ring() @@ -1796,8 +1792,7 @@ def _convert_non_number_field_element(self, x): if isinstance(x, (int, Rational, Integer, pari_gen, list)): return self._element_class(self, x) - if isinstance(x, sage.rings.polynomial.polynomial_quotient_ring_element.PolynomialQuotientRingElement)\ - and (x in self.polynomial_quotient_ring()): + if isinstance(x, sage.rings.polynomial.polynomial_quotient_ring_element.PolynomialQuotientRingElement) and (x in self.polynomial_quotient_ring()): y = self.polynomial_ring().gen() return x.lift().subs({y: self.gen()}) @@ -1866,6 +1861,7 @@ def _convert_from_qqbar(self, x): # Try all embeddings from F into self from sage.rings.qqbar import QQbar + for F_to_self in F.embeddings(self): z = F_to_self(y) # Check whether the diagram commutes @@ -1949,6 +1945,7 @@ def _Hom_(self, codomain, category=None): raise TypeError from sage.rings.number_field.homset import NumberFieldHomset + return NumberFieldHomset(self, codomain, category) @cached_method @@ -2046,8 +2043,7 @@ def primitive_element(self): self.__primitive_element = from_K(K.gen()) return self.__primitive_element - def random_element(self, num_bound=None, den_bound=None, - integral_coefficients=False, distribution=None): + def random_element(self, num_bound=None, den_bound=None, integral_coefficients=False, distribution=None): r""" Return a random element of this number field. @@ -2119,9 +2115,7 @@ def random_element(self, num_bound=None, den_bound=None, if integral_coefficients: den_bound = 1 - return self._zero_element._random_element(num_bound=num_bound, - den_bound=den_bound, - distribution=distribution) + return self._zero_element._random_element(num_bound=num_bound, den_bound=den_bound, distribution=distribution) def subfield(self, alpha, name=None, names=None): r""" @@ -2408,6 +2402,7 @@ def subfield_from_elements(self, alpha, name=None, polred=True, threshold=None): # Saturate with multiplication from sage.modules.free_module import VectorSpace + V = VectorSpace(QQ, self.degree()) vecs = [a.vector() for a in alpha] U = V.subspace(vecs) @@ -2445,6 +2440,7 @@ def subfield_from_elements(self, alpha, name=None, polred=True, threshold=None): p = gen.minpoly() if polred: from sage.rings.qqbar import do_polred + if threshold: fwd, _, q = do_polred(p, threshold) else: @@ -2459,6 +2455,7 @@ def subfield_from_elements(self, alpha, name=None, polred=True, threshold=None): # express the elements in the basis 1, new_gen, new_gen^2, ..., new_gen^(deg-1) from sage.matrix.constructor import matrix + M = matrix(QQ, [(new_gen**i).vector() for i in range(d)]) new_alpha = [K(M.solve_left(elt.vector())) for elt in alpha] @@ -2534,11 +2531,11 @@ def quadratic_defect(self, a, p, check=True): 3 """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + if a not in self: raise TypeError(str(a) + " must be an element of " + str(self)) if not self == QQ and not p.parent() == self.ideal_monoid(): - raise TypeError(str(p) + " is not a prime ideal in " - + str(self.ideal_monoid())) + raise TypeError(str(p) + " is not a prime ideal in " + str(self.ideal_monoid())) if check and not p.is_prime(): raise ValueError(str(p) + " must be prime") if a.is_zero(): @@ -2564,7 +2561,7 @@ def quadratic_defect(self, a, p, check=True): f = x**2 + x while w < u and not w % 2: s = F.lift(q((a - 1) / pi**w).sqrt()) - a = a / (1 + s * (pi**(w / 2)))**2 + a = a / (1 + s * (pi ** (w / 2))) ** 2 w = (a - 1).valuation(p) if w < u and w % 2: return v + w @@ -2775,19 +2772,17 @@ def is_CM(self) -> bool: # Return cached answer if available try: return self.__is_CM - except (AttributeError): + except AttributeError: pass # Then, deal with simple cases if is_odd(self.absolute_degree()): self.__is_CM = False return False - if isinstance( - self, sage.rings.number_field.number_field.NumberField_quadratic): - self.__is_CM = (self.discriminant() < 0) + if isinstance(self, sage.rings.number_field.number_field.NumberField_quadratic): + self.__is_CM = self.discriminant() < 0 return self.__is_CM - if isinstance( - self, sage.rings.number_field.number_field.NumberField_cyclotomic): + if isinstance(self, sage.rings.number_field.number_field.NumberField_cyclotomic): self.__is_CM = True return True if not self.is_totally_imaginary(): @@ -2861,12 +2856,11 @@ def complex_conjugation(self): # Return cached answer if available try: return self.__complex_conjugation - except (AttributeError): + except AttributeError: pass # Then, deal with simple cases - if isinstance( - self, sage.rings.number_field.number_field.NumberField_quadratic): + if isinstance(self, sage.rings.number_field.number_field.NumberField_quadratic): disc = self.discriminant() if disc > 0: self.__complex_conjugation = self.coerce_map_from(self) @@ -2876,8 +2870,7 @@ def complex_conjugation(self): iy = a - r / 2 self.__complex_conjugation = self.hom([a - 2 * iy], check=False) return self.__complex_conjugation - if isinstance( - self, sage.rings.number_field.number_field.NumberField_cyclotomic): + if isinstance(self, sage.rings.number_field.number_field.NumberField_cyclotomic): zeta = self.gen() self.__complex_conjugation = self.hom([zeta ** (-1)], check=False) return self.__complex_conjugation @@ -2891,13 +2884,12 @@ def complex_conjugation(self): # In the remaining case, self.is_CM() should have cached __max_tot_real_sub try: F, phi = self.__max_tot_real_sub - except (AttributeError): + except AttributeError: F, phi = self.maximal_totally_real_subfield() if self.is_absolute(): K_rel = self.relativize(phi, self.variable_name() * 2) to_abs, from_abs = K_rel.structure() - self.__complex_conjugation = K_rel.automorphisms()[1].pre_compose( - from_abs).post_compose(to_abs) + self.__complex_conjugation = K_rel.automorphisms()[1].pre_compose(from_abs).post_compose(to_abs) self.__complex_conjugation = self.hom([self.__complex_conjugation(self.gen())], check=False) return self.__complex_conjugation if self.is_CM_extension(): @@ -2994,18 +2986,16 @@ def maximal_totally_real_subfield(self): try: return self.__max_tot_real_sub - except (AttributeError): + except AttributeError: pass - if isinstance( - self, sage.rings.number_field.number_field.NumberField_quadratic): + if isinstance(self, sage.rings.number_field.number_field.NumberField_quadratic): if self.discriminant() > 0: self.__max_tot_real_sub = [self, self.coerce_map_from(self)] return self.__max_tot_real_sub self.__max_tot_real_sub = [QQ, self.coerce_map_from(QQ)] return self.__max_tot_real_sub - if isinstance( - self, sage.rings.number_field.number_field.NumberField_cyclotomic): + if isinstance(self, sage.rings.number_field.number_field.NumberField_cyclotomic): zeta = self.gen() self.__max_tot_real_sub = self.subfield(zeta + zeta ** (-1)) return self.__max_tot_real_sub @@ -3241,6 +3231,7 @@ def algebraic_closure(self): Algebraic Field """ from sage.rings.qqbar import QQbar + return QQbar @cached_method @@ -3315,7 +3306,7 @@ def conductor(self, check_abelian=True): if is_odd(c): m *= 2 else: - m *= p**(e.valuation(p) + 1) + m *= p ** (e.valuation(p) + 1) return m def dirichlet_group(self) -> list: @@ -3412,8 +3403,7 @@ def _latex_(self) -> str: \Bold{Q}[\theta_{25}]/(\theta_{25}^{25} + \theta_{25} + 1) """ latex_name = self.latex_variable_names()[0] - return "%s[%s]/(%s)" % (latex(QQ), latex_name, - self.polynomial()._latex_(latex_name)) + return "%s[%s]/(%s)" % (latex(QQ), latex_name, self.polynomial()._latex_(latex_name)) def _ideal_class_(self, n=0): """ @@ -3530,11 +3520,7 @@ def idealchinese(self, ideals, residues): """ factorizations = [I.factor() for I in ideals] y = [a for a, f in zip(residues, factorizations) for _ in f] - x = pari.Mat([ - pari.Col([p.pari_prime(), k]) - for f in factorizations - for p, k in f - ]).mattranspose() + x = pari.Mat([pari.Col([p.pari_prime(), k]) for f in factorizations for p, k in f]).mattranspose() r = self.pari_nf().idealchinese(x, y) return self(r) @@ -3644,8 +3630,7 @@ def ideals_of_bdd_norm(self, bound): [[1], [2, 2], [3, 3], [4, 4, 4], [], [6, 6, 6, 6], [], [8, 8, 8, 8], [9, 9, 9], []] """ hnf_ideals = self.pari_nf().ideallist(bound) - return {i + 1: [self.ideal(hnf) for hnf in hnf_ideals[i]] - for i in range(bound)} + return {i + 1: [self.ideal(hnf) for hnf in hnf_ideals[i]] for i in range(bound)} def primes_above(self, x, degree=None): r""" @@ -3746,8 +3731,7 @@ def primes_above(self, x, degree=None): """ if degree is not None: degree = ZZ(degree) - facs = sorted((id.residue_class_degree(), id.absolute_norm(), id) - for id in self.prime_factors(x)) + facs = sorted((id.residue_class_degree(), id.absolute_norm(), id) for id in self.prime_factors(x)) if degree is None: return [id for d, n, id in facs] return [id for d, n, id in facs if d == degree] @@ -3903,10 +3887,10 @@ def primes_of_bounded_norm(self, B): return [] from sage.rings.fast_arith import prime_range + if self is QQ: return prime_range(B + 1, algorithm='pari_isprime') - P = (pp for p in prime_range(B + 1, algorithm='pari_isprime') - for pp in self.primes_above(p)) + P = (pp for p in prime_range(B + 1, algorithm='pari_isprime') for pp in self.primes_above(p)) P = [p for p in P if p.norm() <= B] P.sort(key=lambda P: (P.norm(), P)) return P @@ -3954,6 +3938,7 @@ def primes_of_bounded_norm_iter(self, B): return from sage.rings.fast_arith import prime_range + if self is QQ: for p in prime_range(B + 1, algorithm='pari_isprime'): yield p @@ -4006,6 +3991,7 @@ def primes_of_degree_one_iter(self, num_integer_primes=10000, max_iterations=100 from sage.rings.number_field.small_primes_of_degree_one import ( Small_primes_of_degree_one_iter, ) + return Small_primes_of_degree_one_iter(self, num_integer_primes, max_iterations) def primes_of_degree_one_list(self, n, num_integer_primes=10000, max_iterations=100): @@ -4176,15 +4162,16 @@ def _pari_absolute_structure(self): # doing g = g(x/scalar) in linear time from itertools import accumulate from operator import mul + # scalar^i - powers = accumulate([1/scalar] + [scalar] * g.degree(), mul) + powers = accumulate([1 / scalar] + [scalar] * g.degree(), mul) # need to double reverse - g = g.parent()([c*p for c, p in zip(g.reverse(), powers)]).reverse() + g = g.parent()([c * p for c, p in zip(g.reverse(), powers)]).reverse() g /= g.content() assert g.leading_coefficient() == 1 f = g._pari_with_name('y') y = f.variable() - alpha = (y/scalar).Mod(f) + alpha = (y / scalar).Mod(f) beta = alpha.modreverse() return f, alpha, beta @@ -4497,11 +4484,7 @@ def _gap_init_(self) -> str: E = 'E' if x != 'E' else 'F' R = G(self.base_ring()) - return ( - f'CallFuncList(function() local {x},{E}; {x}:=Indeterminate({R.name()},"{x}"); ' - f'{E}:=AlgebraicExtension({R.name()},{self.polynomial()!r},"{self.gen()}"); ' - f'return {E}; end,[])' - ) + return f'CallFuncList(function() local {x},{E}; {x}:=Indeterminate({R.name()},"{x}"); ' f'{E}:=AlgebraicExtension({R.name()},{self.polynomial()!r},"{self.gen()}"); ' f'return {E}; end,[])' def _libgap_(self): """ @@ -4548,6 +4531,7 @@ def _libgap_(self): raise NotImplementedError("Currently, only simple algebraic extensions are implemented in libgap") from sage.libs.gap.libgap import libgap + return libgap.AlgebraicExtension(self.base_ring(), self.polynomial(), str(self.gen())) def characteristic(self): @@ -4732,8 +4716,7 @@ def S_class_group(self, S, proof=None, names='c'): Slist = list(zip([g.ideal() for g in C.gens()], C.invariants())) else: Slist = self._S_class_group_and_units(tuple(S), proof=proof)[1] - return SClassGroup(tuple(s[1] for s in Slist), names, self, - tuple(s[0] for s in Slist), tuple(S)) + return SClassGroup(tuple(s[1] for s in Slist), names, self, tuple(s[0] for s in Slist), tuple(S)) def S_units(self, S, proof=True): """ @@ -4907,6 +4890,7 @@ def _S_class_group_quotient_matrix(self, S): True """ from sage.matrix.constructor import matrix + S_clgp_gens = self._S_class_group_and_units(S)[1] a = len(S_clgp_gens) c = self.class_group().ngens() @@ -5067,6 +5051,7 @@ def selmer_generators(self, S, m, proof=True, orders=False): card_S = len(S) if card_S != 0: from sage.matrix.constructor import Matrix + H = self.class_group() gen_ords = [g.order() for g in H.gens()] pari_ords = pari(gen_ords).Col() @@ -5137,8 +5122,9 @@ def selmer_group_iterator(self, S, m, proof=True): KSgens, ords = self.selmer_generators(S=S, m=m, proof=proof, orders=True) one = self.one() from sage.misc.mrange import cartesian_product_iterator + for ev in cartesian_product_iterator([range(o) for o in ords]): - yield prod([p ** e for p, e in zip(KSgens, ev)], one) + yield prod([p**e for p, e in zip(KSgens, ev)], one) def selmer_space(self, S, p, proof=None): r""" @@ -5240,6 +5226,7 @@ def selmer_space(self, S, p, proof=None): Number Field in b with defining polynomial x^2 + 1 over its base field """ from sage.rings.number_field.selmer_group import pSelmerGroup + return pSelmerGroup(self, S, p, proof) def composite_fields(self, other, names=None, both_maps=False, preserve_embedding=True): @@ -5478,6 +5465,7 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin if subfields_have_embeddings: try: from sage.categories.pushout import pushout + ambient_field = pushout(self.coerce_embedding().codomain(), other.coerce_embedding().codomain()) except sage.structure.coerce_exceptions.CoercionException: ambient_field = None @@ -5551,7 +5539,7 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin for r, _, _, k in C: r = R(r) k = ZZ(k) - embedding = other.coerce_embedding()(b) + k*self.coerce_embedding()(a) + embedding = other.coerce_embedding()(b) + k * self.coerce_embedding()(a) poly_vals.append(r(embedding).abs()) i = poly_vals.index(min(poly_vals)) C = [C[i]] @@ -5579,7 +5567,7 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin else: k = ZZ(k) if subfields_have_embeddings: - embedding = other.coerce_embedding()(b) + k*self.coerce_embedding()(a) + embedding = other.coerce_embedding()(b) + k * self.coerce_embedding()(a) F = NumberField(r, names[i], check=False, embedding=embedding) i += 1 if both_maps: @@ -5603,10 +5591,10 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin other_to_F = other.hom([b_in_F]) else: other_abs_to_F = other_abs.hom([b_in_F]) - other_to_F = RelativeNumberFieldHomomorphism_from_abs(other.Hom(F), other_abs_to_F*to_other_abs) + other_to_F = RelativeNumberFieldHomomorphism_from_abs(other.Hom(F), other_abs_to_F * to_other_abs) if d == m: self_to_F = self.hom([self.gen()]) - other_to_F = RelativeNumberFieldHomomorphism_from_abs(other.Hom(self), (~self.hom([a_in_F]))*other_abs_to_F*to_other_abs) + other_to_F = RelativeNumberFieldHomomorphism_from_abs(other.Hom(self), (~self.hom([a_in_F])) * other_abs_to_F * to_other_abs) F = self k = None i -= 1 @@ -5777,7 +5765,7 @@ def trace_dual_basis(self, b): M = self.trace_pairing(b) if not M.is_invertible(): raise ValueError('Not a basis of the number field.') - return [sum([v[i]*b[i] for i in range(len(b))]) for v in M.inverse()] + return [sum([v[i] * b[i] for i in range(len(b))]) for v in M.inverse()] def elements_of_norm(self, n, proof=None) -> list: """ @@ -6107,6 +6095,7 @@ def gen(self, n=0): X = self.__polynomial.parent().gen() else: from sage.rings.polynomial.polynomial_ring import polygen + X = polygen(QQ) self.__gen = self._element_class(self, X) return self.__gen @@ -6133,10 +6122,11 @@ def _generator_matrix(self): a = x d = self.relative_degree() v = x.list() - for n in range(d-1): + for n in range(d - 1): a *= x v += a.list() from sage.matrix.matrix_space import MatrixSpace + M = MatrixSpace(self.base_ring(), d) ret = M(v) ret.set_immutable() @@ -6305,6 +6295,7 @@ def galois_group(self, algorithm='pari', names=None, gc_numbering=None): Galois group 10T22 (S(5)[x]2) with order 240 of t^5 - t + a """ from .galois_group import GaloisGroup_v2 + return GaloisGroup_v2(self, algorithm=algorithm, names=names, gc_numbering=gc_numbering, _type=type) def _normalize_prime_list(self, v): @@ -6542,6 +6533,7 @@ def reduced_basis(self, prec=None): flag = 1 if pari.version() >= (2, 17) else 0 if self.is_totally_real(): from sage.matrix.constructor import matrix + M = matrix(ZZ, d, d, [[(x * y).trace() for x in ZK] for y in ZK]) T = pari(M).qflllgram(flag=flag) else: @@ -6625,17 +6617,15 @@ def reduced_gram_matrix(self, prec=None): from sage.matrix.constructor import matrix from sage.misc.flatten import flatten + d = self.absolute_degree() if self.is_totally_real(): B = self.reduced_basis() - self.__reduced_gram_matrix = matrix(ZZ, d, d, - [[(x * y).trace() for x in B] - for y in B]) + self.__reduced_gram_matrix = matrix(ZZ, d, d, [[(x * y).trace() for x in B] for y in B]) else: M = self.minkowski_embedding(prec=prec) - T = matrix(d, flatten([a.vector().list() - for a in self.reduced_basis(prec=prec)])) + T = matrix(d, flatten([a.vector().list() for a in self.reduced_basis(prec=prec)])) A = M * T.transpose() self.__reduced_gram_matrix = A.transpose() * A if prec is None: @@ -6684,7 +6674,7 @@ def _positive_integral_elements_with_trace(self, C): B = self.reduced_basis() T = self.reduced_gram_matrix() - P = pari(T).qfminim((C[1]**2) * 0.5, 10**6)[2] + P = pari(T).qfminim((C[1] ** 2) * 0.5, 10**6)[2] S = [] for p in P: @@ -6810,7 +6800,7 @@ def polynomial(self): """ return self.__polynomial - def defining_polynomial(self): # do not overload this -- overload polynomial instead + def defining_polynomial(self): # do not overload this -- overload polynomial instead r""" Return the defining polynomial of this number field. @@ -6893,6 +6883,7 @@ def regulator(self, proof=None): return self.__regulator except AttributeError: from sage.rings.real_mpfr import RealField + k = self.pari_bnf(proof) self.__regulator = RealField(53)(k.bnf_get_reg()) return self.__regulator @@ -6960,6 +6951,7 @@ def residue_field(self, prime, names=None, check=True): if check and not prime.is_prime(): raise ValueError("%s is not a prime ideal" % prime) from sage.rings.finite_rings.residue_field import ResidueField + return ResidueField(prime, names=names, check=False) def signature(self): @@ -6992,10 +6984,11 @@ def trace_pairing(self, v): [ 0 -6] """ import sage.matrix.matrix_space + A = sage.matrix.matrix_space.MatrixSpace(self.base_ring(), len(v))(0) for i in range(len(v)): for j in range(i, len(v)): - t = (self(v[i]*v[j])).trace() + t = (self(v[i] * v[j])).trace() A[i, j] = t A[j, i] = t return A @@ -7450,6 +7443,7 @@ def S_unit_solutions(self, S=[], prec=106, include_exponents=False, include_boun 6 """ from .S_unit_solver import solve_S_unit_equation + return solve_S_unit_equation(self, S, prec, include_exponents, include_bound, proof) def zeta(self, n=2, all=False): @@ -7551,7 +7545,7 @@ def zeta(self, n=2, all=False): w = w.sage() zeta_w = K(zeta_w) if not w % n: - zeta_n = zeta_w**(w // n) + zeta_n = zeta_w ** (w // n) if all: return [zeta_n**i for i in n.coprime_integers(n)] return zeta_n @@ -7763,10 +7757,9 @@ def solve_CRT(self, reslist, Ilist, check=True): r = Ilist[0].element_1_mod(Ilist[1]) except TypeError: raise ArithmeticError("ideals in solve_CRT() must be pairwise coprime") - x = ((1-r)*reslist[0]+r*reslist[1]).mod(prod(Ilist)) + x = ((1 - r) * reslist[0] + r * reslist[1]).mod(prod(Ilist)) else: # n>2;, use induction / recursion - x = self.solve_CRT([reslist[0], self.solve_CRT(reslist[1:], Ilist[1:])], - [Ilist[0], prod(Ilist[1:])], check=check) + x = self.solve_CRT([reslist[0], self.solve_CRT(reslist[1:], Ilist[1:])], [Ilist[0], prod(Ilist[1:])], check=check) if check and not all(x - xi in Ii for xi, Ii in zip(reslist, Ilist)): raise RuntimeError("Error in number field solve_CRT()") return self(x) @@ -7858,6 +7851,7 @@ def valuation(self, prime): :meth:`pAdicGeneric.valuation() ` """ from sage.rings.padics.padic_valuation import pAdicValuation + return pAdicValuation(self, prime) def some_elements(self): @@ -7895,7 +7889,7 @@ def some_elements(self): for numerator in polynomials: for denominator in polynomials: if denominator: - some_element = numerator/denominator + some_element = numerator / denominator if some_element not in elements: elements.append(some_element) @@ -7920,6 +7914,7 @@ def lmfdb_page(self): """ import webbrowser from urllib.parse import quote + lmfdb_url = 'https://www.lmfdb.org/NumberField/?jump={}' poly = self.absolute_polynomial() f = poly.parent().change_var('x')(poly) @@ -8096,8 +8091,7 @@ def maximal_order(self, v=None, assume_maximal='non-maximal-non-unique'): class NumberField_absolute(NumberField_generic): - def __init__(self, polynomial, name, latex_name=None, check=True, embedding=None, - assume_disc_small=False, maximize_at_primes=None, structure=None): + def __init__(self, polynomial, name, latex_name=None, check=True, embedding=None, assume_disc_small=False, maximize_at_primes=None, structure=None): r""" Function to initialize an absolute number field. @@ -8110,8 +8104,7 @@ def __init__(self, polynomial, name, latex_name=None, check=True, embedding=None sage: TestSuite(K).run() """ - NumberField_generic.__init__(self, polynomial, name, latex_name, check, embedding, - assume_disc_small=assume_disc_small, maximize_at_primes=maximize_at_primes, structure=structure) + NumberField_generic.__init__(self, polynomial, name, latex_name, check, embedding, assume_disc_small=assume_disc_small, maximize_at_primes=maximize_at_primes, structure=structure) self._element_class = NumberFieldElement_absolute self._zero_element = self._element_class(self, 0) self._one_element = self._element_class(self, 1) @@ -8275,6 +8268,7 @@ def _coerce_from_other_number_field(self, x): # exponent of floating-point numbers from sage.rings.complex_mpfr import ComplexField from sage.rings.real_mpfr import RealField + CC = ComplexField(53) RR = RealField(53) @@ -8318,9 +8312,9 @@ def _coerce_from_other_number_field(self, x): # Compute half Fujiwara's bound on the roots of f n = f.degree() - log_half_root_bound = log2abs(f[0]/2)/n + log_half_root_bound = log2abs(f[0] / 2) / n for i in range(1, n): - bd = log2abs(f[i])/(n-i) + bd = log2abs(f[i]) / (n - i) log_half_root_bound = max(bd, log_half_root_bound) # Twice the bound on the roots of f, in other words an upper # bound for the distance between two roots. @@ -8329,13 +8323,13 @@ def _coerce_from_other_number_field(self, x): # using the fact that the discriminant of f is the product of # all root distances. # We use pari to compute the discriminant to work around #11872. - log_root_diff = log2abs(pari(f).poldisc())*0.5 - (n*(n-1)*0.5 - 1.0)*log_double_root_bound + log_root_diff = log2abs(pari(f).poldisc()) * 0.5 - (n * (n - 1) * 0.5 - 1.0) * log_double_root_bound # Let eps be 1/128 times the minimal root distance. # This implies: If two roots of f are at distance <= eps, then # they are equal. The factor 128 is arbitrary, it is an extra # safety margin. eps = (log_root_diff - 7.0).exp2() - are_roots_equal = lambda a, b: (a-b).abs() <= eps + are_roots_equal = lambda a, b: (a - b).abs() <= eps if F is CC: # Adjust the precision of F, sufficient to represent all # the temporaries in the computation with a precision @@ -8343,7 +8337,7 @@ def _coerce_from_other_number_field(self, x): H = [log_double_root_bound - 1.0] for e in [x] + ys: H += [log2abs(c) for c in e.polynomial().coefficients()] - prec = (max(H) + RR(n+1).log2() - log_root_diff).ceil() + 12 + n + prec = (max(H) + RR(n + 1).log2() - log_root_diff).ceil() + 12 + n F = ComplexField(prec=prec) Kgen = F(Kgen) Lgen = F(Lgen) @@ -8488,6 +8482,7 @@ def __iter__(self): zeta5^3 - 1, -zeta5 + 1] """ from sage.categories.sets_cat import cartesian_product + M, f, g = self.free_module() # We iterate over the Cartesian product since the free module does # not iterate using the diagonal embedding. @@ -8744,8 +8739,7 @@ def optimized_subfields(self, degree=0, name=None, both_maps=True): To: Number Field in a6 with defining polynomial x^4 + 1 Defn: a |--> -1/2*a6^3 + a6^2 - 1/2*a6)] """ - return self._subfields_helper(degree=degree, name=name, - both_maps=both_maps, optimize=True) + return self._subfields_helper(degree=degree, name=name, both_maps=both_maps, optimize=True) def change_names(self, names): r""" @@ -8826,8 +8820,7 @@ def subfields(self, degree=0, name=None): sage: sorted([F.discriminant() for F, _, _ in K.subfields()]) [-8, -4, 1, 8, 256] """ - return self._subfields_helper(degree=degree, name=name, - both_maps=True, optimize=False) + return self._subfields_helper(degree=degree, name=name, both_maps=True, optimize=False) def _subfields_helper(self, degree=0, name=None, both_maps=True, optimize=False): """ @@ -8910,7 +8903,7 @@ def _subfields_helper(self, degree=0, name=None, both_maps=True, optimize=False) g = K['x'](self.polynomial()) a = from_K(K.gen()) for root in g.roots(multiplicities=False): - to_K = self.hom([root]) # check=False here ?? + to_K = self.hom([root]) # check=False here ?? if to_K(a) == K.gen(): break else: @@ -8935,9 +8928,8 @@ def _maximal_order(self, v=(), assume_maximal=None): B = [self(b, check=False) for b in self._pari_integral_basis(v=v)] from sage.rings.number_field.order import absolute_order_from_module_generators - return absolute_order_from_module_generators(B, check_integral=False, check_rank=False, - check_is_ring=False, is_maximal=assume_maximal, - is_maximal_at=v) + + return absolute_order_from_module_generators(B, check_integral=False, check_rank=False, check_is_ring=False, is_maximal=assume_maximal, is_maximal_at=v) def order(self, *args, **kwds): r""" @@ -9042,6 +9034,7 @@ def _order(self, gens, **kwds): True """ from sage.rings.number_field.order import absolute_order_from_ring_generators + return absolute_order_from_ring_generators(gens, **kwds) @cached_method(key=lambda self, base, basis, map: (base or self.base_ring(), basis, map)) @@ -9094,7 +9087,7 @@ def free_module(self, base=None, basis=None, map=True): return super().free_module(base=base, basis=basis, map=map) if basis is not None or base is not QQ: raise NotImplementedError - V = QQ**self.degree() + V = QQ ** self.degree() if not map: return V from_V = maps.MapVectorSpaceToNumberField(V, self) @@ -9398,10 +9391,9 @@ def embeddings(self, K): # Convert these to conjugates of self.gen(). P = self._pari_absolute_structure()[1].lift() conj = sorted([self(P(g.Mod(f))) for g in conj]) - v = [self.hom([e]) for e in conj] # check=False here? + v = [self.hom([e]) for e in conj] # check=False here? put_natural_embedding_first(v) - return Sequence(v, cr=(v != []), immutable=True, - check=False, universe=self.Hom(self)) + return Sequence(v, cr=(v != []), immutable=True, check=False, universe=self.Hom(self)) if K.characteristic() != 0: return Sequence([], immutable=True, check=False, universe=self.Hom(K)) @@ -9411,8 +9403,7 @@ def embeddings(self, K): # If there is an embedding that preserves variable names # then it is most natural, so we put it first. put_natural_embedding_first(v) - return Sequence(v, cr=bool(v), immutable=True, - check=False, universe=self.Hom(K)) + return Sequence(v, cr=bool(v), immutable=True, check=False, universe=self.Hom(K)) def minkowski_embedding(self, B=None, prec=None): r""" @@ -9478,10 +9469,10 @@ def minkowski_embedding(self, B=None, prec=None): places = self.places(prec=prec) if B is None: - B = [(self.gen(0))**i for i in range(n)] + B = [(self.gen(0)) ** i for i in range(n)] A = ZZ['x'] - f = A.gen(0)**2 - 2 + f = A.gen(0) ** 2 - 2 sqrt2 = f.roots(R)[1][0] d = {} @@ -9492,9 +9483,9 @@ def minkowski_embedding(self, B=None, prec=None): d[(row, col)] = places[row](B[col]) for i in range(s): - z = places[r+i](B[col]) - d[(r+2*i, col)] = z.real()*sqrt2 - d[(r+2*i+1, col)] = z.imag()*sqrt2 + z = places[r + i](B[col]) + d[(r + 2 * i, col)] = z.real() * sqrt2 + d[(r + 2 * i + 1, col)] = z.imag() * sqrt2 return sage.matrix.all.matrix(d) @@ -9543,6 +9534,7 @@ def logarithmic_embedding(self, prec=53): sage: f(7) (1.94591014905531, 1.94591014905531, 1.94591014905531, 1.94591014905531) """ + def closure_map(x, prec=53): """ The function closure of the logarithmic embedding. @@ -9553,6 +9545,7 @@ def closure_map(x, prec=53): r = r1 + r2 - 1 from sage.rings.real_mpfr import RealField + Reals = RealField(prec) if x == 0: @@ -9652,6 +9645,7 @@ def places(self, all_complex=False, prec=None): elif prec == Infinity: from sage.rings.qqbar import AA, QQbar + R = AA C = QQbar @@ -9671,16 +9665,13 @@ def places(self, all_complex=False, prec=None): real_intervals = [x[0] for x in self.defining_polynomial().roots(R)] if prec is None: - real_places = [self.hom([i.center()], check=False) - for i in real_intervals] + real_places = [self.hom([i.center()], check=False) for i in real_intervals] - complex_places = [self.hom([i.center()], check=False) - for i in all_intervals if i.imag() > 0] + complex_places = [self.hom([i.center()], check=False) for i in all_intervals if i.imag() > 0] else: real_places = [self.hom([i], check=False) for i in real_intervals] - complex_places = [self.hom([i], check=False) - for i in all_intervals if i.imag() > 0] + complex_places = [self.hom([i], check=False) for i in all_intervals if i.imag() > 0] return real_places + complex_places @@ -9701,7 +9692,7 @@ def real_places(self, prec=None): To: Real Field with 106 bits of precision Defn: alpha |--> 1.626576561697785743211232345494] """ - return self.places(prec=prec)[0:self.signature()[0]] + return self.places(prec=prec)[0 : self.signature()[0]] def abs_val(self, v, iota, prec=None): r""" @@ -9745,12 +9736,12 @@ def abs_val(self, v, iota, prec=None): try: p = v.smallest_integer() iota_ideal = self.ideal(self(iota)) - exponent = - v.residue_class_degree() * iota_ideal.valuation(v) + exponent = -v.residue_class_degree() * iota_ideal.valuation(v) return R(p**exponent) except AttributeError: if is_real_place(v): return R(v(iota).abs()) - return R(v(iota).abs()**2) + return R(v(iota).abs() ** 2) def relativize(self, alpha, names, structure=None): r""" @@ -9953,6 +9944,7 @@ def relativize(self, alpha, names, structure=None): from sage.categories.map import Map from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector + if isinstance(alpha, Map): # alpha better be a morphism with codomain self if alpha.codomain() != self: @@ -9961,6 +9953,7 @@ def relativize(self, alpha, names, structure=None): alpha = alpha(L.gen()) # relativize over phi's domain if L is QQ: from sage.rings.polynomial.polynomial_ring import polygen + f = polygen(QQ) else: f = L.defining_polynomial() # = alpha.minpoly() @@ -9979,15 +9972,14 @@ def relativize(self, alpha, names, structure=None): a = self.gen() # we will find a linear relation between small powers of a over L - basis = [a**i * b for i in range(extdeg) - for b in map(L_into_self, L.power_basis())] + basis = [a**i * b for i in range(extdeg) for b in map(L_into_self, L.power_basis())] basis.append(a**extdeg) # this one makes the basis no longer a basis mat = matrix([b.vector() for b in basis]) soln_space = mat.left_kernel(mat.row_space()(0)) # the solution space is one dimensional and the last entry is nonzero # because a satisfies no smaller linear relation assert soln_space.dimension() == 1 - (reln, ) = soln_space.basis() + (reln,) = soln_space.basis() assert reln[-1] != 0 reln = reln * ~reln[-1] @@ -10003,6 +9995,7 @@ def relativize(self, alpha, names, structure=None): if structure is None: from sage.rings.number_field.structure import RelativeFromAbsolute + structure = RelativeFromAbsolute(self, alpha) if L is QQ: return L.extension(f, names[0]) @@ -10326,14 +10319,15 @@ def hilbert_symbol(self, a, b, P=None): from sage.categories.map import Map from sage.categories.rings import Rings + if isinstance(P, Map) and P.category_for().is_subcategory(Rings()): # P is a morphism of Rings if P.domain() is not self: raise ValueError("Domain of P (=%s) should be self (=%s) in self.hilbert_symbol" % (P, self)) codom = P.codomain() from sage.rings.qqbar import AA, QQbar - if isinstance(codom, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField, sage.rings.abc.ComplexIntervalField)) or \ - codom is QQbar: + + if isinstance(codom, (sage.rings.abc.ComplexField, sage.rings.abc.ComplexDoubleField, sage.rings.abc.ComplexIntervalField)) or codom is QQbar: if P(self.gen()).imag() == 0: raise ValueError("Possibly real place (=%s) given as complex embedding in hilbert_symbol. Is it real or complex?" % P) return 1 @@ -10435,15 +10429,12 @@ def hilbert_symbol_negative_at_S(self, S, b, check=True): if not p.is_prime(): raise ValueError("not a prime ideal") if self.quadratic_defect(b, p) == infinity.Infinity: - raise ValueError(f"{b} is a square in the completion " - f"with respect to {p}") + raise ValueError(f"{b} is a square in the completion " f"with respect to {p}") else: if p not in self.real_places(): - raise ValueError("entries of the list must be " - "prime ideals or real places") + raise ValueError("entries of the list must be " "prime ideals or real places") if p(b) > 0: - raise ValueError(f"{b} is a square in the completion " - f"with respect to {p}") + raise ValueError(f"{b} is a square in the completion " f"with respect to {p}") # L is the list of primes that we need to consider, b must have # nonzero valuation for each prime in L, this is the set S' @@ -10454,8 +10445,7 @@ def hilbert_symbol_negative_at_S(self, S, b, check=True): L.append(P) # This adds some infinite places to L - L.extend(sigma for sigma in self.real_places() - if sigma(b) < 0 and sigma not in S) + L.extend(sigma for sigma in self.real_places() if sigma(b) < 0 and sigma not in S) Cl = self.class_group(proof=False) U = self.unit_group(proof=False).gens() SL = S + L @@ -10470,7 +10460,7 @@ def hilbert_symbol_negative_at_S(self, S, b, check=True): # represented as 1 and a Hilbert symbol of 1 # is represented as 0 V = VectorSpace(GF(2), len(SL)) - v = V([1]*len(S) + [0]*len(L)) + v = V([1] * len(S) + [0] * len(L)) # The algorithm terminates when the vector v is in the # subspace of V generated by the image of the phi map @@ -10485,11 +10475,11 @@ def phi(x): # abelian groups in sage do not yet have homomorphisms... Cl_additive = AdditiveAbelianGroup(Cl.gens_orders()) n = len(Cl_additive.gens()) - A = AdditiveAbelianGroup([0]*(len(P)+1)) + A = AdditiveAbelianGroup([0] * (len(P) + 1)) PCl = [] for p in P: pr = Cl(p).exponents() - pr = Cl_additive.sum([Cl_additive.gens()[i]*pr[i] for i in range(n)]) + pr = Cl_additive.sum([Cl_additive.gens()[i] * pr[i] for i in range(n)]) PCl.append(pr) # search through all the primes @@ -10499,13 +10489,13 @@ def phi(x): if Q in P: continue pr = Cl(Q).exponents() - pr = Cl_additive.sum([Cl_additive.gens()[i]*pr[i] for i in range(n)]) + pr = Cl_additive.sum([Cl_additive.gens()[i] * pr[i] for i in range(n)]) # compute the kernel K = A.hom(PCl + [pr]).kernel().gens() K = [A(k) for k in K] # generate it by a list of ideals Pq = P + [Q] - K = [prod([Pq[i]**k[i] for i in range(len(Pq))]) for k in K] + K = [prod([Pq[i] ** k[i] for i in range(len(Pq))]) for k in K] # the ideals are principal # find a single generator for each K = [k.gens_reduced(proof=False)[0] for k in K] @@ -10518,7 +10508,7 @@ def phi(x): break J = list(U) + K l = W.solve_left(v) - a = prod([J[i]**l[i] for i in range(len(J))]) + a = prod([J[i] ** l[i] for i in range(len(J))]) # let us double check the result if check: assert phi(a) == v, "oops" @@ -10681,6 +10671,7 @@ def elements_of_bounded_height(self, **kwds): - Raman Raghukul (2018) """ from sage.rings.number_field.bdd_height import bdd_height, bdd_height_iq + r1, r2 = self.signature() r = r1 + r2 - 1 B = kwds.pop('bound') @@ -10713,11 +10704,9 @@ def _factor_univariate_polynomial(self, poly, **kwargs): """ if self.degree() == 1: factors = poly.change_ring(QQ).factor() - return Factorization([(p.change_ring(self), e) - for p, e in factors], self(factors.unit())) + return Factorization([(p.change_ring(self), e) for p, e in factors], self(factors.unit())) if poly.is_term(): - return Factorization([(poly.parent().gen(), poly.degree())], - poly.leading_coefficient()) + return Factorization([(poly.parent().gen(), poly.degree())], poly.leading_coefficient()) # Convert the polynomial we want to factor to PARI f = poly._pari_with_name() @@ -10791,6 +10780,7 @@ class NumberField_cyclotomic(NumberField_absolute, sage.rings.abc.NumberField_cy sage: type(cf3(z1)) """ + def __init__(self, n, names, embedding=None, assume_disc_small=False, maximize_at_primes=None): """ A cyclotomic field, i.e., a field obtained by adjoining an `n`-th @@ -10833,13 +10823,7 @@ def __init__(self, n, names, embedding=None, assume_disc_small=False, maximize_a else: latex_name = latex_variable_name(names[0]) self.__n = n = Integer(n) - NumberField_absolute.__init__(self, f, - name=names, - latex_name=latex_name, - check=False, - embedding=embedding, - assume_disc_small=assume_disc_small, - maximize_at_primes=maximize_at_primes) + NumberField_absolute.__init__(self, f, name=names, latex_name=latex_name, check=False, embedding=embedding, assume_disc_small=assume_disc_small, maximize_at_primes=maximize_at_primes) if n % 2: self.__zeta_order = 2 * n else: @@ -10868,7 +10852,7 @@ def __init__(self, n, names, embedding=None, assume_disc_small=False, maximize_a self._D = ZZ(-3) one_half = QQ((1, 2)) if n == 3: - self._NumberField_generic__gen = self._element_class(self, (one_half-1, one_half)) + self._NumberField_generic__gen = self._element_class(self, (one_half - 1, one_half)) else: self._NumberField_generic__gen = self._element_class(self, (one_half, one_half)) @@ -11007,6 +10991,7 @@ def _libgap_(self): CF(8) """ from sage.libs.gap.libgap import libgap + return libgap.CyclotomicField(self.__n) def _repr_(self) -> str: @@ -11193,7 +11178,7 @@ def _coerce_map_from_(self, K): True """ if isinstance(K, NumberField_cyclotomic): - if (self.coerce_embedding() is None or K.coerce_embedding() is None): + if self.coerce_embedding() is None or K.coerce_embedding() is None: return None ambient_field = self.coerce_embedding().codomain() if not ambient_field.has_coerce_map_from(K.coerce_embedding().codomain()): @@ -11205,7 +11190,7 @@ def _coerce_map_from_(self, K): if Kn == 2 and n == 1: # see #12632 return number_field_morphisms.NumberFieldEmbedding(K, self, -self.gen()) - if Kn % 4 == 2 and (Kn//2).divides(n): + if Kn % 4 == 2 and (Kn // 2).divides(n): e = self._log_gen(ambient_field(-K.gen())) return number_field_morphisms.NumberFieldEmbedding(K, self, -self.gen() ** e) return None @@ -11297,11 +11282,11 @@ def _log_gen(self, x): x = CDF(x) gen = CDF(gen) # Let zeta = e^(2*pi*i/n) - two_pi = 2*RDF.pi() - a = (n * x.arg() / two_pi).round() # x = zeta^a - b = (n * gen.arg() / two_pi).round() # gen = zeta^b - e = mod(a/b, n).lift() # e is the expected result - if abs(gen**e-x) < 1/n: # a sanity check + two_pi = 2 * RDF.pi() + a = (n * x.arg() / two_pi).round() # x = zeta^a + b = (n * gen.arg() / two_pi).round() # gen = zeta^b + e = mod(a / b, n).lift() # e is the expected result + if abs(gen**e - x) < 1 / n: # a sanity check return e else: # NOTE: this can be *very* slow! @@ -11398,7 +11383,7 @@ def _coerce_from_other_cyclotomic_field(self, x, only_canonical=False): return x n = K._n() m = self._n() - if m % n == 0: # easy case + if m % n == 0: # easy case # pass this off to a method in the element class # it can be done very quickly and easily by the # Cython<->NTL interface there @@ -11421,7 +11406,7 @@ def _coerce_from_other_cyclotomic_field(self, x, only_canonical=False): z = y for r in range(y.multiplicative_order()): if z == x: - return self.zeta(m)**(r+1) + return self.zeta(m) ** (r + 1) z *= y raise TypeError("cannot coerce %s into %s" % (x, self)) return self._element_class(self, x) @@ -11510,6 +11495,7 @@ def _Hom_(self, codomain, category=None): raise TypeError from sage.rings.number_field.homset import CyclotomicFieldHomset + return CyclotomicFieldHomset(self, codomain, category) def is_galois(self) -> bool: @@ -11639,8 +11625,7 @@ def embeddings(self, K): v = [self.hom([z**i], check=False) for i in X] else: v = [] - return Sequence(v, cr=True, immutable=True, - check=False, universe=self.Hom(K)) + return Sequence(v, cr=True, immutable=True, check=False, universe=self.Hom(K)) def complex_embeddings(self, prec=53): r""" @@ -11740,8 +11725,8 @@ def different(self): for f in factors: p = f[0] r = f[1] - e = (r*p - r - 1)*p**(r-1) - D *= self.ideal(z**(n/p**r) - 1)**e + e = (r * p - r - 1) * p ** (r - 1) + D *= self.ideal(z ** (n / p**r) - 1) ** e self.__different = D return self.__different @@ -11775,7 +11760,7 @@ def discriminant(self, v=None): deg = self.degree() d = ZZ.one() # so that CyclotomicField(1).disc() has the right type factors = n.factor() - for (p, r) in factors: + for p, r in factors: e = (r * p - r - 1) * deg // (p - 1) d *= p**e sign = 1 @@ -11960,12 +11945,11 @@ def zeta(self, n=None, all=False): if n % 2 == 0 and m % 2 == 1: # In the n-th cyclotomic field, n odd, there are # actually 2*n-th roots of unity, so we include them. - z = -z**((m+1)//2) # -z + z = -(z ** ((m + 1) // 2)) # -z m = 2 * m if m % n != 0: - raise ValueError("%s does not divide order of generator (%s)" % - (n, self.zeta_order())) - a = z**(m // n) + raise ValueError("%s does not divide order of generator (%s)" % (n, self.zeta_order())) + a = z ** (m // n) if not all: return a @@ -12025,8 +12009,8 @@ class NumberField_quadratic(NumberField_absolute, sage.rings.abc.NumberField_qua sage: QuadraticField(-4, 'b') Number Field in b with defining polynomial x^2 + 4 with b = 2*I """ - def __init__(self, polynomial, name=None, latex_name=None, check=True, embedding=None, - assume_disc_small=False, maximize_at_primes=None, structure=None): + + def __init__(self, polynomial, name=None, latex_name=None, check=True, embedding=None, assume_disc_small=False, maximize_at_primes=None, structure=None): """ Create a quadratic number field. @@ -12057,17 +12041,15 @@ def __init__(self, polynomial, name=None, latex_name=None, check=True, embedding sage: floor(phi) # needs sage.symbolic 1 """ - NumberField_absolute.__init__(self, polynomial, name=name, check=check, - embedding=embedding, latex_name=latex_name, - assume_disc_small=assume_disc_small, maximize_at_primes=maximize_at_primes, structure=structure) + NumberField_absolute.__init__(self, polynomial, name=name, check=check, embedding=embedding, latex_name=latex_name, assume_disc_small=assume_disc_small, maximize_at_primes=maximize_at_primes, structure=structure) self._standard_embedding = True # set the generator and element class c, b, a = (QQ(t) for t in self.defining_polynomial().list()) - Dpoly = b*b - 4*a*c + Dpoly = b * b - 4 * a * c D = (Dpoly.numer() * Dpoly.denom()).squarefree_part(bound=10000) self._D = D - parts = -b/(2*a), (Dpoly/D).sqrt()/(2*a) + parts = -b / (2 * a), (Dpoly / D).sqrt() / (2 * a) if a.is_one() and b.is_zero() and c.is_one(): self._element_class = NumberFieldElement_gaussian @@ -12359,6 +12341,7 @@ def hilbert_class_polynomial(self, name='x'): raise NotImplementedError("Hilbert class polynomial is not implemented for real quadratic fields.") from sage.schemes.elliptic_curves.cm import hilbert_class_polynomial as HCP + return QQ[name](HCP(D)) def number_of_roots_of_unity(self): @@ -12619,7 +12602,7 @@ def refine_embedding(e, prec=None): old_root = e(K.gen()) if prec is None: - prec = 2*prec_old + prec = 2 * prec_old elif prec_old >= prec: return e @@ -12727,7 +12710,7 @@ def _splitting_classes_gens_(K, m, d): def map_Zmstar_to_Zm(h): li = h.list() - return prod(unit_gens[i]**li[i] for i in range(len(unit_gens))) + return prod(unit_gens[i] ** li[i] for i in range(len(unit_gens))) Hgens = [] H = Zmstar.subgroup([]) diff --git a/src/sage/rings/number_field/number_field_base.pyi b/src/sage/rings/number_field/number_field_base.pyi index 845b10a93be..a7ad8e2ac2a 100644 --- a/src/sage/rings/number_field/number_field_base.pyi +++ b/src/sage/rings/number_field/number_field_base.pyi @@ -1,44 +1,18 @@ from typing import Any -def number_field_base(x: Any) -> bool: - ... +def number_field_base(x: Any) -> bool: ... class NumberField: - def _pushout_(self, other: Any) -> Any: - ... - - def ring_of_integers(self, *args: Any, **kwds: Any) -> Any: - ... - - def OK(self, *args: Any, **kwds: Any) -> Any: - ... - - def maximal_order(self) -> Any: - ... - - def is_absolute(self) -> bool: - ... - - def signature(self) -> tuple[int, int]: - ... - - def degree(self) -> int: - ... - - def discriminant(self) -> int: - ... - - def minkowski_bound(self) -> Any: - ... - - def bach_bound(self) -> Any: - ... - - def _init_embedding_approx(self) -> None: - ... - - def _get_embedding_approx(self, i: int) -> Any: - ... - - def _matrix_charpoly(self, M: Any, var: str) -> Any: - ... + def _pushout_(self, other: Any) -> Any: ... + def ring_of_integers(self, *args: Any, **kwds: Any) -> Any: ... + def OK(self, *args: Any, **kwds: Any) -> Any: ... + def maximal_order(self) -> Any: ... + def is_absolute(self) -> bool: ... + def signature(self) -> tuple[int, int]: ... + def degree(self) -> int: ... + def discriminant(self) -> int: ... + def minkowski_bound(self) -> Any: ... + def bach_bound(self) -> Any: ... + def _init_embedding_approx(self) -> None: ... + def _get_embedding_approx(self, i: int) -> Any: ... + def _matrix_charpoly(self, M: Any, var: str) -> Any: ... diff --git a/src/sage/rings/number_field/number_field_ideal.py b/src/sage/rings/number_field/number_field_ideal.py index 2311841497f..29d1aa233ee 100644 --- a/src/sage/rings/number_field/number_field_ideal.py +++ b/src/sage/rings/number_field/number_field_ideal.py @@ -94,6 +94,7 @@ class NumberFieldIdeal(Ideal_generic): sage: I.norm() 1/6 """ + def __init__(self, field, gens, coerce=True): """ INPUT: @@ -114,12 +115,14 @@ def __init__(self, field, gens, coerce=True): True """ from .number_field import NumberField_generic + if not isinstance(field, NumberField_generic): raise TypeError("field (=%s) must be a number field." % field) if len(gens) == 1 and isinstance(gens[0], (list, tuple)): gens = gens[0] from cypari2.gen import Gen as pari_gen + if len(gens) == 1 and isinstance(gens[0], pari_gen): # Init from PARI gens = gens[0] @@ -162,8 +165,7 @@ def _magma_init_(self, magma): ans = magma(g) * O for g in self.gens()[1:]: ans += magma(g) * O - return '+'.join('%s * %s' % (g._magma_init_(magma), O.name()) - for g in self.gens()) + return '+'.join('%s * %s' % (g._magma_init_(magma), O.name()) for g in self.gens()) def __hash__(self): """ @@ -588,7 +590,7 @@ def pari_hnf(self): except AttributeError: nf = self.number_field().pari_nf() self.__pari_hnf = nf.idealhnf(0) - hnflist = [ nf.idealhnf(x) for x in self.gens() ] + hnflist = [nf.idealhnf(x) for x in self.gens()] for ideal in hnflist: self.__pari_hnf = nf.idealadd(self.__pari_hnf, ideal) return self.__pari_hnf @@ -920,14 +922,13 @@ def integral_split(self): else: factors = self.factor() denom_list = [p_e for p_e in factors if p_e[1] < 0] - denominator = prod([ p.smallest_integer()**(-e) - for (p,e) in denom_list ]) + denominator = prod([p.smallest_integer() ** (-e) for (p, e) in denom_list]) ## Get a list of the primes dividing the denominator - plist = [ p.smallest_integer() for (p,e) in denom_list ] + plist = [p.smallest_integer() for (p, e) in denom_list] for p in plist: - while denominator % p == 0 and (self*(denominator/p)).is_integral(): + while denominator % p == 0 and (self * (denominator / p)).is_integral(): denominator //= p - self.__integral_split = (self*denominator, denominator) + self.__integral_split = (self * denominator, denominator) return self.__integral_split def intersection(self, other): @@ -1260,6 +1261,7 @@ def S_ideal_class_log(self, S): """ from sage.modules.free_module_element import vector from sage.rings.finite_rings.integer_mod_ring import Zmod + v = vector(ZZ, self.ideal_class_log()) if all(P.is_principal() for P in S): L = v.list() @@ -1431,17 +1433,17 @@ def smallest_integer(self): return ZZ(0) # There is no need for caching since pari_hnf() is already cached. - q = self.pari_hnf()[0,0] # PARI integer or rational + q = self.pari_hnf()[0, 0] # PARI integer or rational return ZZ(q.numerator()) - #Old code by John Cremona, 2008-10-30, using the new coordinates() - #function instead of factorization. + # Old code by John Cremona, 2008-10-30, using the new coordinates() + # function instead of factorization. # - #Idea: We write 1 as a Q-linear combination of the Z-basis of self, - #and return the denominator of this vector. + # Idea: We write 1 as a Q-linear combination of the Z-basis of self, + # and return the denominator of this vector. # - #self.__smallest_integer = self.coordinates(1).denominator() - #return self.__smallest_integer + # self.__smallest_integer = self.coordinates(1).denominator() + # return self.__smallest_integer def valuation(self, p): r""" @@ -1583,7 +1585,7 @@ def random_element(self, *args, **kwds): basis = self.basis() else: basis = self.absolute_ideal().basis() - return self.number_field()(sum([ZZ.random_element(*args, **kwds)*a for a in basis])) + return self.number_field()(sum([ZZ.random_element(*args, **kwds) * a for a in basis])) def artin_symbol(self): r""" @@ -1675,15 +1677,16 @@ def residue_symbol(self, e, m, check=True): if rootorder % m: raise ValueError("The residue symbol to that power is not defined for the number field") if not self.is_prime(): - return prod(Q.residue_symbol(e,m,check=False)**i for Q, i in self.factor()) + return prod(Q.residue_symbol(e, m, check=False) ** i for Q, i in self.factor()) k = self.residue_field() try: r = k(e) except TypeError: raise ValueError("Element and ideal must be in a common number field") - r = k(r**((k.order()-1)/m)) - resroot = primroot**(rootorder/m) + r = k(r ** ((k.order() - 1) / m)) + resroot = primroot ** (rootorder / m) from sage.groups.generic import discrete_log + j = discrete_log(k(r), k(resroot), ord=m) return resroot**j @@ -1740,6 +1743,7 @@ def _quadratic_form(self): K = self.number_field() if K.degree() == 2: from sage.quadratic_forms.binary_qf import BinaryQF + gens = self.gens_reduced() if len(gens) == 1: u, v = K.ring_of_integers().basis() @@ -1750,8 +1754,7 @@ def _quadratic_form(self): alpha, beta = beta, alpha N = self.norm() a = alpha.norm() // N - b = ZZ(alpha * beta.galois_conjugate() + - beta * alpha.galois_conjugate()) // N + b = ZZ(alpha * beta.galois_conjugate() + beta * alpha.galois_conjugate()) // N c = beta.norm() // N return BinaryQF([a, b, c]) @@ -1775,13 +1778,12 @@ def basis_to_module(B, K): [3 0 1 0] """ V, from_V, to_V = K.absolute_vector_space() - M = ZZ**(V.dimension()) + M = ZZ ** (V.dimension()) C = [to_V(K(b)) for b in B] return M.span_of_basis(C) -class NumberFieldFractionalIdeal(MultiplicativeGroupElement, NumberFieldIdeal, - Ideal_fractional): +class NumberFieldFractionalIdeal(MultiplicativeGroupElement, NumberFieldIdeal, Ideal_fractional): r""" A fractional ideal in a number field. @@ -1804,6 +1806,7 @@ class NumberFieldFractionalIdeal(MultiplicativeGroupElement, NumberFieldIdeal, sage: isinstance(I, Ideal_fractional) True """ + def __init__(self, field, gens, coerce=True): """ INPUT: @@ -1818,6 +1821,7 @@ def __init__(self, field, gens, coerce=True): Fractional ideal (7) """ from .number_field import NumberField_generic + if not isinstance(field, NumberField_generic): raise TypeError("field (=%s) must be a number field." % field) @@ -1825,7 +1829,7 @@ def __init__(self, field, gens, coerce=True): raise ValueError("gens must have length at least 1 (zero ideal is not a fractional ideal)") if len(gens) == 1 and isinstance(gens[0], (list, tuple)): gens = gens[0] - if misc.exists(gens,bool)[0]: + if misc.exists(gens, bool)[0]: NumberFieldIdeal.__init__(self, field, gens) else: raise ValueError("gens must have a nonzero element (zero ideal is not a fractional ideal)") @@ -1917,8 +1921,8 @@ def factor(self): F = K.pari_nf().idealfactor(self.pari_hnf()) A = [] for j in range(len(F[0])): - I = K.ideal(F[j,0]) - A.append((I,ZZ(F[j,1]))) + I = K.ideal(F[j, 0]) + A.append((I, ZZ(F[j, 1]))) self.__factorization = Factorization(A) return self.__factorization @@ -1984,9 +1988,8 @@ def __invert__(self): Fractional ideal (1) """ nf = self.number_field().pari_nf() - hnf = nf.idealdiv(self.number_field().ideal(1).pari_hnf(), - self.pari_hnf()) - I = self.number_field().ideal(NumberFieldIdeal._NumberFieldIdeal__elements_from_hnf(self,hnf)) + hnf = nf.idealdiv(self.number_field().ideal(1).pari_hnf(), self.pari_hnf()) + I = self.number_field().ideal(NumberFieldIdeal._NumberFieldIdeal__elements_from_hnf(self, hnf)) I.__pari_hnf = hnf return I @@ -2138,7 +2141,8 @@ def reduce(self, f): Rbasis = R.basis() n = len(Rbasis) from sage.matrix.matrix_space import MatrixSpace - M = MatrixSpace(ZZ,n)([R.coordinates(y) for y in self.basis()]) + + M = MatrixSpace(ZZ, n)([R.coordinates(y) for y in self.basis()]) D = M.hermite_form() d = [D[i, i] for i in range(n)] @@ -2148,9 +2152,9 @@ def reduce(self, f): for i in range(n): q, r = ZZ(v[i]).quo_rem(d[i]) # v is a vector of rationals, we want division of integers - if 2*r > d[i]: + if 2 * r > d[i]: q = q + 1 - v = v - q*D[i] + v = v - q * D[i] return sum([v[i] * Rbasis[i] for i in range(n)]) @@ -2210,11 +2214,12 @@ def residues(self): Rbasis = R.basis() n = len(Rbasis) from sage.matrix.matrix_space import MatrixSpace + M = MatrixSpace(ZZ, n)([R.coordinates(_) for _ in self.basis()]) D = M.hermite_form() d = [D[i, i] for i in range(n)] - coord_ranges = [list(range((-di+2)//2,(di+2)//2)) for di in d] + coord_ranges = [list(range((-di + 2) // 2, (di + 2) // 2)) for di in d] combo = lambda c: sum(c[i] * Rbasis[i] for i in range(n)) return xmrange_iter(coord_ranges, combo) @@ -2363,11 +2368,10 @@ def invertible_residues_mod(self, subgp_gens=[], reduce=True): A, U, V = M.smith_form() V = V.inverse() - new_basis = [prod([g[j]**(V[i, j] % invs[j]) for j in range(n)]) for i in range(n)] + new_basis = [prod([g[j] ** (V[i, j] % invs[j]) for j in range(n)]) for i in range(n)] if reduce: - combo = lambda c: self.small_residue(prod(new_basis[i] ** c[i] - for i in range(n))) + combo = lambda c: self.small_residue(prod(new_basis[i] ** c[i] for i in range(n))) else: combo = lambda c: prod(new_basis[i] ** c[i] for i in range(n)) @@ -2402,7 +2406,7 @@ def denominator(self): return self._denom_ideal except AttributeError: pass - self._denom_ideal = (self + self.number_field().unit_ideal())**(-1) + self._denom_ideal = (self + self.number_field().unit_ideal()) ** (-1) return self._denom_ideal def numerator(self): @@ -2489,7 +2493,7 @@ def is_coprime(self, other) -> bool: if self.is_integral() and other.is_integral(): if gcd(ZZ(self.absolute_norm()), ZZ(other.absolute_norm())) == 1: return True - return self+other == one + return self + other == one # This special case is necessary since the zero ideal is not a # fractional ideal! if other.absolute_norm() == 0: @@ -2498,7 +2502,7 @@ def is_coprime(self, other) -> bool: N1 = self.numerator() D2 = other.denominator() N2 = other.numerator() - return N1+N2 == one and N1+D2 == one and D1+N2 == one and D1+D2 == one + return N1 + N2 == one and N1 + D2 == one and D1 + N2 == one and D1 + D2 == one def idealcoprime(self, J): """ @@ -2612,6 +2616,7 @@ def _pari_bid_(self, flag=1): [2, [2]] """ from cypari2.handle_error import PariError + try: bid = self._bid if flag == 2: @@ -2685,10 +2690,12 @@ def idealstar(self, flag=1): if flag == 2 or flag == 0: from sage.groups.abelian_gps.values import AbelianGroupWithValues + g = G.bid_get_gen() AG = AbelianGroupWithValues(tuple(map(k, g)), inv, values_group=k) else: from sage.groups.abelian_gps.abelian_group import AbelianGroup + AG = AbelianGroup(inv) return AG @@ -2772,9 +2779,9 @@ def ideallog(self, x, gens=None, check=True): # calculate ideal log w.r.t. standard gens - #Now it is important to call _pari_bid_() with flag=2 to make sure - #we fix a basis, since the log would be different for a different - #choice of basis. + # Now it is important to call _pari_bid_() with flag=2 to make sure + # we fix a basis, since the log would be different for a different + # choice of basis. L = [ZZ(_) for _ in k.pari_nf().ideallog(x, self._pari_bid_(2))] if gens is None: @@ -2796,19 +2803,20 @@ def ideallog(self, x, gens=None, check=True): # minimal. mat = matrix(ZZ, [self.ideallog(_) for _ in gens]).augment(identity_matrix(ZZ, len(gens))) - mat = mat.stack( diagonal_matrix(ZZ, invs).augment(zero_matrix(ZZ, len(invs), len(gens)))) + mat = mat.stack(diagonal_matrix(ZZ, invs).augment(zero_matrix(ZZ, len(invs), len(gens)))) hmat = mat.hermite_form() - A = hmat[0:len(invs), 0:len(invs)] + A = hmat[0 : len(invs), 0 : len(invs)] if A != identity_matrix(len(invs)): raise ValueError("Given elements do not generate unit group -- they generate a subgroup of index %s" % A.det()) - B = hmat[0:len(invs), len(invs):] - C = hmat[len(invs):, len(invs):] - M = (matrix(ZZ, L) * B) + B = hmat[0 : len(invs), len(invs) :] + C = hmat[len(invs) :, len(invs) :] + M = matrix(ZZ, L) * B N = block_matrix(2, 2, [[identity_matrix(1), M], [zero_matrix(len(gens), 1), C]], subdivide=False) ans = N.hermite_form()[0, 1:].list() if check: from sage.rings.finite_rings.integer_mod_ring import Zmod + Z_norm = Zmod(self.norm().numerator()) # norm is an integer ? t = 1 for gi, ai in zip(gens, ans): @@ -2921,7 +2929,7 @@ def euler_phi(self): if not self.is_integral(): raise ValueError("euler_phi only defined for integral ideals") it = ((p.absolute_norm(), e) for p, e in self.factor()) - return prod((np - 1) * np**(e - 1) for np, e in it) + return prod((np - 1) * np ** (e - 1) for np, e in it) def prime_to_S_part(self, S): r""" @@ -2967,7 +2975,7 @@ def prime_to_S_part(self, S): a = self for p in S: n = a.valuation(p) - a = a*p**(-n) + a = a * p ** (-n) return a def is_S_unit(self, S): @@ -3079,7 +3087,7 @@ def prime_to_idealM_part(self, M): G = self + M I = self while not G.is_trivial(): - I = I/G + I = I / G G = I + G return I @@ -3279,6 +3287,7 @@ class QuotientMap: domain is the appropriate valuation ring. For examples, see :meth:`~sage.rings.number_field.number_field_ideal.NumberFieldFractionalIdeal.residue_field`. """ + def __init__(self, K, M_OK_change, Q, I): """ Initialize this QuotientMap. @@ -3318,7 +3327,7 @@ def __call__(self, x): """ v = self.__to_L(x) w = v * self.__M_OK_change - return self.__Q( list(w) ) + return self.__Q(list(w)) def __repr__(self): r""" @@ -3340,6 +3349,7 @@ class LiftMap: Class to hold data needed by lifting maps from residue fields to number field orders. """ + def __init__(self, OK, M_OK_map, Q, I): """ Initialize this LiftMap. @@ -3386,7 +3396,7 @@ def __call__(self, x): w = v.lift() # Write back in terms of K z = (w * self.__M_OK_map).list() - return self.__OK(sum(z[i] * self.__Kgen ** i for i in range(len(z)))) + return self.__OK(sum(z[i] * self.__Kgen**i for i in range(len(z)))) def __repr__(self): r""" @@ -3455,7 +3465,7 @@ def quotient_char_p(I, p): # in terms of the basis for OK. M_OK_mat = M_OK.basis_matrix() - M_OK_change = M_OK_mat**(-1) + M_OK_change = M_OK_mat ** (-1) B_I_in_terms_of_M = M_I.basis_matrix() * M_OK_change # Step 2. Define "M_OK mod p" to just be (F_p)^n and diff --git a/src/sage/rings/number_field/number_field_ideal_rel.py b/src/sage/rings/number_field/number_field_ideal_rel.py index 4db920482b1..35ab78ee2dc 100644 --- a/src/sage/rings/number_field/number_field_ideal_rel.py +++ b/src/sage/rings/number_field/number_field_ideal_rel.py @@ -40,6 +40,7 @@ from sage.rings import rational_field from sage.rings import integer_ring + QQ = rational_field.RationalField() ZZ = integer_ring.IntegerRing() @@ -77,6 +78,7 @@ class NumberFieldFractionalIdeal_rel(NumberFieldFractionalIdeal): ... The following tests failed: _test_category """ + def _richcmp_(self, other, op): """ Compare an ideal of a relative number field to something else. @@ -198,7 +200,7 @@ def absolute_ideal(self, names='a'): except AttributeError: self.__absolute_ideal = {} L = self.number_field().absolute_field(names) - genlist = [L(x.polynomial() ) for x in self.gens() ] + genlist = [L(x.polynomial()) for x in self.gens()] M = L.ideal(genlist) self.__absolute_ideal[names] = M return M @@ -717,7 +719,7 @@ def relative_ramification_index(self): if self.is_prime(): abs_index = self.absolute_ramification_index() base_ideal = self.ideal_below() - return ZZ(abs_index/base_ideal.absolute_ramification_index()) + return ZZ(abs_index / base_ideal.absolute_ramification_index()) raise ValueError("the fractional ideal (= %s) is not prime" % self) def ramification_index(self): @@ -778,6 +780,7 @@ def residues(self): abs_ideal = self.absolute_ideal() from_abs = abs_ideal.number_field().structure()[0] from sage.misc.mrange import xmrange_iter + abs_residues = abs_ideal.residues() return xmrange_iter(abs_residues.iter_list, lambda c: from_abs(abs_residues.typ(c))) diff --git a/src/sage/rings/number_field/number_field_rel.py b/src/sage/rings/number_field/number_field_rel.py index a34b9fe5cad..a11a1d97e26 100644 --- a/src/sage/rings/number_field/number_field_rel.py +++ b/src/sage/rings/number_field/number_field_rel.py @@ -63,6 +63,7 @@ - Robert Harron (2012-08): added is_CM_extension - Julian Rüth (2014-04): absolute number fields are unique parents """ + # **************************************************************************** # Copyright (C) 2004-2009 William Stein # 2014-2022 Julian Rüth @@ -166,8 +167,8 @@ class NumberField_relative(NumberField_generic): sage: loads(dumps(M)) is M True """ - def __init__(self, base, polynomial, name, - latex_name=None, names=None, check=True, embedding=None, structure=None): + + def __init__(self, base, polynomial, name, latex_name=None, names=None, check=True, embedding=None, structure=None): r""" Initialization. @@ -299,9 +300,7 @@ def __init__(self, base, polynomial, name, names = (name,) + base.variable_names() self._assign_names(tuple(names), normalize=False) - NumberField_generic.__init__(self, self.absolute_polynomial(), name=None, - latex_name=latex_name, check=False, - embedding=embedding, structure=structure) + NumberField_generic.__init__(self, self.absolute_polynomial(), name=None, latex_name=latex_name, check=False, embedding=embedding, structure=structure) self._zero_element = self(0) self._one_element = self(1) @@ -431,7 +430,7 @@ def subfields(self, degree=0, name=None): for K, from_K, to_K in abs_subfields: from_K = K.hom([from_abs(from_K(K.gen()))]) if to_K is not None: - to_K = RelativeNumberFieldHomomorphism_from_abs(self.Hom(K), to_K*to_abs) + to_K = RelativeNumberFieldHomomorphism_from_abs(self.Hom(K), to_K * to_abs) ans.append((K, from_K, to_K)) ans = Sequence(ans, immutable=True, cr=bool(ans)) return ans @@ -473,8 +472,7 @@ def gens(self) -> tuple: sage: NumberField([x, x^2 - 3], 'a').gens() (0, a1) """ - return ((self._gen_relative(),) + - tuple(map(self, self.base_field().gens()))) + return (self._gen_relative(),) + tuple(map(self, self.base_field().gens())) def _first_ngens(self, n): """ @@ -631,12 +629,12 @@ def composite_fields(self, other, names=None, both_maps=False, preserve_embeddin rets = [] for F, self_abs_to_F, other_to_F, k in abs_composites: - self_to_F = RelativeNumberFieldHomomorphism_from_abs(self.Hom(F), self_abs_to_F*to_self_abs) + self_to_F = RelativeNumberFieldHomomorphism_from_abs(self.Hom(F), self_abs_to_F * to_self_abs) if F.absolute_degree() == m: if other.is_absolute(): - other_to_F = other.hom([(from_self_abs*(~self_abs_to_F)*other_to_F)(other.gen())]) + other_to_F = other.hom([(from_self_abs * (~self_abs_to_F) * other_to_F)(other.gen())]) else: - other_to_F = RelativeNumberFieldHomomorphism_from_abs(self.Hom(self), from_self_abs*(~self_abs_to_F)*other_to_F) + other_to_F = RelativeNumberFieldHomomorphism_from_abs(self.Hom(self), from_self_abs * (~self_abs_to_F) * other_to_F) self_to_F = RelativeNumberFieldHomomorphism_from_abs(self.Hom(self), from_self_abs) F = self rets.append([F, self_to_F, other_to_F, None]) @@ -749,6 +747,7 @@ def _Hom_(self, codomain, category=None): raise TypeError("{} is not suitable as codomain for homomorphisms from {}".format(codomain, self)) from sage.rings.number_field.homset import RelativeNumberFieldHomset + return RelativeNumberFieldHomset(self, codomain, category) def _latex_(self): @@ -765,8 +764,7 @@ def _latex_(self): '( \\Bold{Q}[a]/(a^{3} - 2) )[b]/(b^{2} + b + a)' """ latex_name = self.latex_variable_names()[0] - return "( %s )[%s]/(%s)" % (latex(self.base_field()), latex_name, - self.relative_polynomial()._latex_(latex_name)) + return "( %s )[%s]/(%s)" % (latex(self.base_field()), latex_name, self.relative_polynomial()._latex_(latex_name)) def _coerce_from_other_number_field(self, x): """ @@ -948,8 +946,8 @@ def _convert_non_number_field_element(self, x): x = R(x.list()) # this should work for base_ring()['x'] and QQ['base']['ext'] x = self.polynomial_ring()(x) - f = R( [ K(coeff) for coeff in x.list() ] ) - return self._element_class(self, f(self.gen()).polynomial() ) + f = R([K(coeff) for coeff in x.list()]) + return self._element_class(self, f(self.gen()).polynomial()) # Anything else: use the code for generic number fields return super()._convert_non_number_field_element(x) @@ -1030,8 +1028,7 @@ def _element_constructor_(self, x, check=True): # to an absolute element. if isinstance(x, pari_gen) and x.type() == "t_POLMOD": modulus = x.mod() - if (modulus == self.pari_relative_polynomial() - or modulus == self.pari_absolute_base_polynomial()): + if modulus == self.pari_relative_polynomial() or modulus == self.pari_absolute_base_polynomial(): x = self._pari_rnfeq()._eltreltoabs(x.liftpol()) check = False return NumberField_generic._element_constructor_(self, x, check=check) @@ -1328,7 +1325,7 @@ def is_CM_extension(self) -> bool: try: return self.__is_CM_extension - except (AttributeError): + except AttributeError: pass if self.relative_degree() == 2: @@ -1375,14 +1372,14 @@ def free_module(self, base=None, basis=None, map=True): if base is None: base = self.base_field() if base is self.base_field(): - V = self.base_field()**self.relative_degree() + V = self.base_field() ** self.relative_degree() if not map: return V fr = maps.MapRelativeVectorSpaceToRelativeNumberField(V, self) to = maps.MapRelativeNumberFieldToRelativeVectorSpace(self, V) elif base is QQ: if not map: - return QQ**self.absolute_degree() + return QQ ** self.absolute_degree() K = self.absolute_field('a') from_K, to_K = K.structure() V, from_V, to_V = K.free_module() @@ -1624,8 +1621,9 @@ def _pari_relative_structure(self): # PARI's rnfpolredbest() does not always return a # polynomial with integral coefficients in this case. from sage.libs.pari import pari + g = f.variable() - alpha = -f[0]/f[1] + alpha = -f[0] / f[1] beta = pari(0).Mod(f) else: g, alpha = self._pari_base_nf().rnfpolredbest(f, flag=1) @@ -1851,7 +1849,7 @@ def absolute_polynomial_ntl(self): self.__abs_denominator_ntl = ntl_ZZ() den = self.absolute_polynomial().denominator() self.__abs_denominator_ntl.set_from_sage_int(ZZ(den)) - self.__abs_polynomial_ntl = ntl_ZZX((self.absolute_polynomial()*den).list()) + self.__abs_polynomial_ntl = ntl_ZZX((self.absolute_polynomial() * den).list()) return (self.__abs_polynomial_ntl, self.__abs_denominator_ntl) @cached_method @@ -2113,11 +2111,9 @@ def automorphisms(self): a = self_into_L(self.gen()) abs_base_gens = [self_into_L(_) for _ in self.base_field().gens()] - v = sorted([self.hom([L_into_self(aa(a))]) for aa in aas - if all(aa(g) == g for g in abs_base_gens)]) + v = sorted([self.hom([L_into_self(aa(a))]) for aa in aas if all(aa(g) == g for g in abs_base_gens)]) put_natural_embedding_first(v) - self.__automorphisms = Sequence(v, cr=bool(v), immutable=True, - check=False, universe=self.Hom(self)) + self.__automorphisms = Sequence(v, cr=bool(v), immutable=True, check=False, universe=self.Hom(self)) return self.__automorphisms def logarithmic_embedding(self, prec=53): @@ -2159,6 +2155,7 @@ def logarithmic_embedding(self, prec=53): (2.19722457733622, 2.19722457733622, 2.19722457733622, 2.19722457733622, 2.19722457733622, 2.19722457733622, 2.19722457733622, 2.19722457733622) """ + def closure_map(x, prec=53): """ The function closure of the logarithmic embedding. @@ -2169,6 +2166,7 @@ def closure_map(x, prec=53): r = r1 + r2 - 1 from sage.rings.real_mpfr import RealField + Reals = RealField(prec) if x == 0: @@ -2269,7 +2267,7 @@ def relative_different(self): """ I = self.absolute_different() J = self.ideal(self.base_field().absolute_different().gens()) - return I/J + return I / J def different(self): """ @@ -2694,8 +2692,7 @@ def NumberField_relative_v1(base_field, poly, name, latex_name, canonical_embedd sage: NumberField_relative_v1(CyclotomicField(3), x^2 + 7, 'a', 'a') Number Field in a with defining polynomial x^2 + 7 over its base field """ - return NumberField(poly.change_ring(base_field), name, check=False, - embedding=canonical_embedding, latex_name=latex_name) + return NumberField(poly.change_ring(base_field), name, check=False, embedding=canonical_embedding, latex_name=latex_name) NumberField_extension_v1 = NumberField_relative_v1 # historical reasons only diff --git a/src/sage/rings/number_field/order.py b/src/sage/rings/number_field/order.py index 6f9839780a2..5594db6d1ed 100644 --- a/src/sage/rings/number_field/order.py +++ b/src/sage/rings/number_field/order.py @@ -113,7 +113,7 @@ def quadratic_order_class_number(disc): depending on the size of the discriminant. """ # cutoffs from PARI documentation - if disc < -10**25 or disc > 10**10: + if disc < -(10**25) or disc > 10**10: h = pari.quadclassunit(disc)[0] else: h = pari.qfbclassno(disc) @@ -461,6 +461,7 @@ def EquationOrder(f, names, **kwds): ValueError: each generator must be integral """ from sage.rings.number_field.number_field import NumberField + R = ZZ['x'] if isinstance(f, (list, tuple)): for g in f: @@ -541,11 +542,10 @@ def __init__(self, K): """ self._K = K cat = IntegralDomains() & NoetherianRings() - Parent.__init__(self, base=ZZ, names=K.variable_names(), - normalize=False, category=cat) + Parent.__init__(self, base=ZZ, names=K.variable_names(), normalize=False, category=cat) self._populate_coercion_lists_(embedding=self.number_field()) if self.absolute_degree() == 2: - self.is_maximal() # cache + self.is_maximal() # cache def fractional_ideal(self, *args, **kwds): """ @@ -604,6 +604,7 @@ def ideal(self, *args, **kwds): if 'future' in kwds: del kwds['future'] from sage.rings.number_field.order_ideal import NumberFieldOrderIdeal + return NumberFieldOrderIdeal(self, *args, **kwds) def _coerce_map_from_(self, R): @@ -865,6 +866,7 @@ def coordinates(self, x): M = self.__basis_matrix_inverse except AttributeError: from sage.matrix.constructor import Matrix + self.__basis_matrix_inverse = Matrix([to_V(b) for b in self.basis()]).inverse() M = self.__basis_matrix_inverse return to_V(K(x)) * M @@ -909,6 +911,7 @@ def free_module(self): except AttributeError: pass from sage.rings.number_field.number_field_ideal import basis_to_module + M = basis_to_module(self.basis(), self.number_field()) self.__free_module = M return M @@ -948,7 +951,7 @@ def ring_generators(self): K = self._K n = [] V, from_V, to_V = self._K.absolute_vector_space() - A = ZZ**K.absolute_degree() + A = ZZ ** K.absolute_degree() remaining = [x for x in self.basis() if x != 1] gens = [] while remaining: @@ -1077,8 +1080,7 @@ def residue_field(self, prime, names=None, check=False): if self.is_maximal(): return self.number_field().residue_field(prime, names, check=check) - raise NotImplementedError("residue fields of non-maximal orders " - "are not yet supported") + raise NotImplementedError("residue fields of non-maximal orders " "are not yet supported") def fraction_field(self): """ @@ -1426,8 +1428,7 @@ def random_element(self, *args, **kwds): sage: A.random_element().parent() is A True """ - return sum([ZZ.random_element(*args, **kwds) * a - for a in self.basis()]) + return sum([ZZ.random_element(*args, **kwds) * a for a in self.basis()]) def absolute_degree(self): r""" @@ -1505,6 +1506,7 @@ def valuation(self, p): :meth:`pAdicGeneric.valuation() ` """ from sage.rings.padics.padic_valuation import pAdicValuation + return pAdicValuation(self, p) def some_elements(self): @@ -1544,6 +1546,7 @@ def some_elements(self): elements.append(self(a)) return elements + # def absolute_polynomial(self): # """ # Return the absolute polynomial of this order, which is just the absolute polynomial of the number field. @@ -1623,7 +1626,7 @@ def __init__(self, K, module_rep): Order.__init__(self, K) if self.absolute_degree() == 2: - self.discriminant() # cache + self.discriminant() # cache def _element_constructor_(self, x): r""" @@ -2697,9 +2700,7 @@ def each_is_integral(v): return all(x.is_integral() for x in v) -def absolute_order_from_ring_generators(gens, check_is_integral=True, - check_rank=True, is_maximal=None, - allow_subfield=False): +def absolute_order_from_ring_generators(gens, check_is_integral=True, check_rank=True, is_maximal=None, allow_subfield=False): """ INPUT: @@ -2760,18 +2761,10 @@ def absolute_order_from_ring_generators(gens, check_is_integral=True, gens = Sequence(gens) n = [x.absolute_minpoly().degree() for x in gens] module_gens = monomials(gens, n) - return absolute_order_from_module_generators(module_gens, - check_integral=False, - check_is_ring=False, - check_rank=check_rank, - is_maximal=is_maximal, - allow_subfield=allow_subfield) - - -def absolute_order_from_module_generators(gens, - check_integral=True, check_rank=True, - check_is_ring=True, is_maximal=None, - allow_subfield=False, is_maximal_at=()): + return absolute_order_from_module_generators(module_gens, check_integral=False, check_is_ring=False, check_rank=check_rank, is_maximal=is_maximal, allow_subfield=allow_subfield) + + +def absolute_order_from_module_generators(gens, check_integral=True, check_rank=True, check_is_ring=True, is_maximal=None, allow_subfield=False, is_maximal_at=()): r""" INPUT: @@ -2884,7 +2877,7 @@ def absolute_order_from_module_generators(gens, K = K.number_field() V, from_V, to_V = K.vector_space() mod_gens = [to_V(x) for x in gens] - ambient = ZZ**V.dimension() + ambient = ZZ ** V.dimension() W = ambient.span(mod_gens) if allow_subfield: @@ -2906,7 +2899,7 @@ def absolute_order_from_module_generators(gens, gens = [K(x) for x in gens] V, from_V, to_V = K.vector_space() mod_gens = [to_V(x) for x in gens] - ambient = ZZ**V.dimension() + ambient = ZZ ** V.dimension() W = ambient.span(mod_gens) elif check_rank: @@ -2920,12 +2913,7 @@ def absolute_order_from_module_generators(gens, return AbsoluteOrder(K, W, check=False, is_maximal=is_maximal, is_maximal_at=is_maximal_at) -def relative_order_from_ring_generators(gens, - check_is_integral=True, - check_rank=True, - is_maximal=None, - allow_subfield=False, - is_maximal_at=()): +def relative_order_from_ring_generators(gens, check_is_integral=True, check_rank=True, is_maximal=None, allow_subfield=False, is_maximal_at=()): """ INPUT: @@ -2971,12 +2959,7 @@ def relative_order_from_ring_generators(gens, n = [a.absolute_minpoly().degree() for a in gens] absolute_order_module_gens = monomials(module_gens, n) - abs_order = absolute_order_from_module_generators(absolute_order_module_gens, - check_integral=False, - check_is_ring=False, - check_rank=check_rank, - is_maximal=is_maximal, - is_maximal_at=is_maximal_at) + abs_order = absolute_order_from_module_generators(absolute_order_module_gens, check_integral=False, check_is_ring=False, check_rank=check_rank, is_maximal=is_maximal, is_maximal_at=is_maximal_at) return RelativeOrder(K, abs_order, check=False) @@ -3004,6 +2987,7 @@ def GaussianIntegers(names='I', latex_name='i'): """ from sage.rings.complex_double import CDF from sage.rings.number_field.number_field import NumberField + f = ZZ['x']([1, 0, 1]) nf = NumberField(f, names, embedding=CDF(0, 1), latex_name=latex_name) return nf.ring_of_integers() @@ -3035,6 +3019,7 @@ def EisensteinIntegers(names='omega'): """ from sage.rings.complex_double import CDF from sage.rings.number_field.number_field import NumberField + f = ZZ['x']([1, 1, 1]) nf = NumberField(f, names, embedding=CDF(-0.5, 0.8660254037844386)) return nf.ring_of_integers() diff --git a/src/sage/rings/number_field/order_ideal.py b/src/sage/rings/number_field/order_ideal.py index 541d6802850..dc504b481ca 100644 --- a/src/sage/rings/number_field/order_ideal.py +++ b/src/sage/rings/number_field/order_ideal.py @@ -111,6 +111,7 @@ class NumberFieldOrderIdeal_generic(Ideal_generic): r""" An ideal of a not necessarily maximal order in a number field. """ + def __init__(self, O, gens, *, coerce=True): r""" Ideals of not necessarily maximal orders. @@ -139,7 +140,7 @@ def __init__(self, O, gens, *, coerce=True): gens = Sequence(gens, O) _, from_V, to_V = O.number_field().absolute_vector_space() - span = [to_V(a*g) for a in O.basis() for g in gens] + span = [to_V(a * g) for a in O.basis() for g in gens] self._module = O.free_module().submodule(span) basis = [O(from_V(v)) for v in self._module.basis()] @@ -280,7 +281,7 @@ def _positive_sqrt(R, D): """ if D.is_zero(): return R.zero() - sqrtD, = (s for s in R(D).sqrt(all=True) if s.real() > 0 or s.imag() > 0) + (sqrtD,) = (s for s in R(D).sqrt(all=True) if s.real() > 0 or s.imag() > 0) return sqrtD @@ -342,15 +343,16 @@ def _gens_from_bqf(O, Q): raise ValueError('order and form must have the same discriminant') a, b, c = Q sqrtD = _positive_sqrt(O.number_field(), D) - g = (- b + sqrtD) / 2 + g = (-b + sqrtD) / 2 t = sqrtD if a < 0 else 1 - return a*t, g*t + return a * t, g * t class NumberFieldOrderIdeal_quadratic(NumberFieldOrderIdeal_generic): r""" An ideal of a not necessarily maximal order in a *quadratic* number field. """ + def __init__(self, O, gens, *, coerce=True): r""" Ideals of *quadratic* orders are implemented by a specialized @@ -371,6 +373,7 @@ class because they have some extra features not present in True """ from sage.quadratic_forms.binary_qf import BinaryQF + if isinstance(gens, BinaryQF): gens = _gens_from_bqf(O, gens) coerce = False @@ -443,15 +446,15 @@ def gens_two(self) -> tuple: """ O = self.ring() if self.is_zero(): - return (O.zero(),)*2 - M = self._module & (ZZ**2).submodule([(1,0)]) - (N,_), = M.gens() - NOgens = [N*g for g in O.free_module().basis()] + return (O.zero(),) * 2 + M = self._module & (ZZ**2).submodule([(1, 0)]) + ((N, _),) = M.gens() + NOgens = [N * g for g in O.free_module().basis()] Q = self._module / self._module.submodule(NOgens) if Q.invariants(): assert len(Q.invariants()) == 1 _, from_V, _ = O.number_field().absolute_vector_space() - alpha, = (from_V(g.lift()) for g in Q.gens()) + (alpha,) = (from_V(g.lift()) for g in Q.gens()) else: alpha = 0 return tuple(map(O, (N, alpha))) @@ -614,7 +617,7 @@ def is_equivalent(self, other, narrow=False) -> bool: if other.is_zero(): return False gs = (self * other.conjugate()).gens_reduced() - assert len(gs) in (1,2) + assert len(gs) in (1, 2) if len(gs) > 1: return False if narrow: @@ -730,27 +733,28 @@ class group on ideals to the class group on quadratic forms. """ if self.is_zero(): if basis: - return BinaryQF(0), (self.ring().zero(),)*2 + return BinaryQF(0), (self.ring().zero(),) * 2 return BinaryQF(0) O = self.ring() sqrtD = _positive_sqrt(O.number_field(), O.discriminant()) # find a "good" ZZ-basis of the ideal - M = self._module.basis_matrix()[:,::-1] - M = M.row_space(ZZ).basis_matrix()[:,::-1] + M = self._module.basis_matrix()[:, ::-1] + M = M.row_space(ZZ).basis_matrix()[:, ::-1] beta, alpha = map(O, M.rows()) assert alpha in QQ if QQ(alpha * (beta - beta.galois_conjugate()) / sqrtD) < 0: alpha = -alpha # compute the (reduced) norm form of the ideal - A,B = (g.matrix() for g in (alpha, beta)) - x,y = polygens(QQ, 'x,y') - Q = (x*A - y*B).determinant() / self.norm() + A, B = (g.matrix() for g in (alpha, beta)) + x, y = polygens(QQ, 'x,y') + Q = (x * A - y * B).determinant() / self.norm() Q = Q.change_ring(ZZ) from sage.quadratic_forms.binary_qf import BinaryQF + Q = BinaryQF(Q) assert Q.discriminant() == O.discriminant() return (Q, (alpha, -beta)) if basis else Q @@ -774,28 +778,29 @@ def _random_for_testing(): from sage.rings.number_field.number_field import QuadraticField from sage.arith.misc import primes from sage.rings.finite_rings.integer_mod_ring import Zmod + while True: d = ZZ(choice((-1, +1)) * randrange(1, 10**5)) if not d.is_square(): break - K,t = QuadraticField(d).objgen() - g, = K.ring_of_integers().ring_generators() + K, t = QuadraticField(d).objgen() + (g,) = K.ring_of_integers().ring_generators() f = randrange(1, 100) - O = K.order(f*g) + O = K.order(f * g) assert O.discriminant() == f**2 * K.discriminant() - poly = (f*g).minpoly() + poly = (f * g).minpoly() base = [] for l in primes(1000): vs = poly.roots(ring=Zmod(l), multiplicities=False) - base += [NumberFieldOrderIdeal(O, [l, f*g-ZZ(v)]) for v in vs] + base += [NumberFieldOrderIdeal(O, [l, f * g - ZZ(v)]) for v in vs] def random_ideal(): I = NumberFieldOrderIdeal(O, [1]) for _ in range(randrange(20)): J = choice(base) - I = NumberFieldOrderIdeal(O, [x*y for x in I.gens() for y in J.gens()]) + I = NumberFieldOrderIdeal(O, [x * y for x in I.gens() for y in J.gens()]) return I return O, random_ideal diff --git a/src/sage/rings/number_field/selmer_group.py b/src/sage/rings/number_field/selmer_group.py index a940c95731d..37ac4e2bddb 100644 --- a/src/sage/rings/number_field/selmer_group.py +++ b/src/sage/rings/number_field/selmer_group.py @@ -124,13 +124,13 @@ def _coords_in_C_p(I, C, p): ValueError: The 3rd power of Fractional ideal (2, a + 1) is not principal """ cyclic_orders = C.gens_orders() - non_p_indices = [i for i,n in enumerate(cyclic_orders) if not p.divides(n)] - p_indices = [(i, n // p) for i,n in enumerate(cyclic_orders) if p.divides(n)] + non_p_indices = [i for i, n in enumerate(cyclic_orders) if not p.divides(n)] + p_indices = [(i, n // p) for i, n in enumerate(cyclic_orders) if p.divides(n)] coords = C(I).exponents() if all(coords[i] == 0 for i in non_p_indices) and all(coords[i] % n == 0 for i, n in p_indices): return [(coords[i] // n) % p for i, n in p_indices] - raise ValueError("The {} power of {} is not principal".format(p.ordinal_str(),I)) + raise ValueError("The {} power of {} is not principal".format(p.ordinal_str(), I)) def _coords_in_C_mod_p(I, C, p): @@ -228,11 +228,11 @@ def _root_ideal(I, C, p): # are dividing the coordinate vector by p in the appropriate sense if not all(p.divides(ci) for ci, n in zip(coords, cyclic_orders) if p.divides(n)): - raise ValueError("The ideal class of {} is not a {} power".format(I,p.ordinal_str())) + raise ValueError("The ideal class of {} is not a {} power".format(I, p.ordinal_str())) w = [ci // p if p.divides(n) else (ci / p) % n for ci, n in zip(coords, cyclic_orders)] - return prod([gen ** wi for wi, gen in zip(w, cyclic_gens)], C.number_field().ideal(1)) + return prod([gen**wi for wi, gen in zip(w, cyclic_gens)], C.number_field().ideal(1)) def coords_in_U_mod_p(u, U, p): @@ -279,7 +279,7 @@ def coords_in_U_mod_p(u, U, p): [1, 2, 0] """ coords = U.log(u) - start = 1 - int(p.divides(U.zeta_order())) # 0 or 1 + start = 1 - int(p.divides(U.zeta_order())) # 0 or 1 return [c % p for c in coords[start:]] @@ -340,12 +340,13 @@ class is a `p`-th power; Fractional ideal (5, a + 3)] """ from sage.matrix.constructor import Matrix + M = Matrix(GF(p), [_coords_in_C_mod_p(P, C, p) for P in S]) k = M.left_kernel() - bas = [prod([P ** bj.lift() for P, bj in zip(S, b.list())], - C.number_field().ideal(1)) for b in k.basis()] + bas = [prod([P ** bj.lift() for P, bj in zip(S, b.list())], C.number_field().ideal(1)) for b in k.basis()] return bas, k.coordinate_vector + # The main function @@ -542,7 +543,7 @@ def pSelmerGroup(K, S, p, proof=None, debug=False): hK = 1 if K == QQ else K.class_number(proof=proof) C = K.class_group() if K == QQ else K.class_group(proof=proof) - hKp = (hK % p == 0) # flag whether the class number is divisible by p + hKp = hK % p == 0 # flag whether the class number is divisible by p if K == QQ: if p == 2: @@ -556,21 +557,19 @@ def pSelmerGroup(K, S, p, proof=None, debug=False): ulist = ulist[1:] if debug: - print("{} generators in ulist = {}".format(len(ulist),ulist)) + print("{} generators in ulist = {}".format(len(ulist), ulist)) # Step 2. The class group contribution: generators of the p'th # powers of ideals generating the p-torsion in the class group. # These have valuation divisible by p everywhere. if hKp: - betalist = [_ideal_generator(c ** n) - for c, n in zip(C.gens_ideals(), C.gens_orders()) - if n % p == 0] + betalist = [_ideal_generator(c**n) for c, n in zip(C.gens_ideals(), C.gens_orders()) if n % p == 0] else: betalist = [] if debug: - print("{} generators in betalist = {}".format(len(betalist),betalist)) + print("{} generators in betalist = {}".format(len(betalist), betalist)) # Step 3. The part depending on S: one generator for each ideal A # in a basis of those ideals supported on S (modulo p'th powers of @@ -585,7 +584,7 @@ def pSelmerGroup(K, S, p, proof=None, debug=False): T, f = basis_for_p_cokernel(S, C, p) alphalist = [_ideal_generator(I / _root_ideal(I, C, p) ** p) for I in T] else: - f = lambda x:x + f = lambda x: x alphalist = [_ideal_generator(P) for P in S] if debug: @@ -605,7 +604,7 @@ def pSelmerGroup(K, S, p, proof=None, debug=False): # Define the easy map from KSp into K^*: def from_KSp(v): - return prod([g ** vi for g, vi in zip(KSp_gens, v)], K(1)) + return prod([g**vi for g, vi in zip(KSp_gens, v)], K(1)) # Define the hard map from (a subgroup of) K^* to KSp: @@ -627,15 +626,15 @@ def to_KSp(a): # ideals T above. Find the exponents of the P_i in S in A: S_vals = [F(a.valuation(P)) for P in S] - avec = list(f(S_vals)) # coordinates of A w.r.t ideals in T (mod p'th powers) - a1 = prod((alpha ** e for alpha, e in zip(alphalist,avec)), K(1)) + avec = list(f(S_vals)) # coordinates of A w.r.t ideals in T (mod p'th powers) + a1 = prod((alpha**e for alpha, e in zip(alphalist, avec)), K(1)) a /= a1 if debug: - print("alpha component is {} with coords {}".format(a1,avec)) + print("alpha component is {} with coords {}".format(a1, avec)) if K == QQ: - print("continuing with quotient {} whose ideal should be a {}'th power: {}".format(a,p,a.factor())) + print("continuing with quotient {} whose ideal should be a {}'th power: {}".format(a, p, a.factor())) else: - print("continuing with quotient {} whose ideal should be a {}'th power: {}".format(a,p,K.ideal(a).factor())) + print("continuing with quotient {} whose ideal should be a {}'th power: {}".format(a, p, K.ideal(a).factor())) # 2. Now (a) is a p'th power, say (a)=B^p. # Find B and the exponents of [B] w.r.t. basis of C[p]: @@ -646,15 +645,15 @@ def to_KSp(a): assert all(v % p == 0 for v in vals) one = K(1) if K == QQ else K.ideal(1) aa = a.abs() if K == QQ else K.ideal(a) - B = prod((P ** (v // p) for P, v in zip(supp,vals)), one) + B = prod((P ** (v // p) for P, v in zip(supp, vals)), one) if debug: - assert B ** p == aa + assert B**p == aa print("B={}".format(B)) print("a={}".format(a)) if hKp: bvec = _coords_in_C_p(B, C, p) - a2 = prod((beta ** e for beta, e in zip(betalist, bvec)), K(1)) + a2 = prod((beta**e for beta, e in zip(betalist, bvec)), K(1)) a /= a2 supp = a.support() vals = [a.valuation(P) for P in supp] @@ -662,13 +661,13 @@ def to_KSp(a): assert all(v % p == 0 for v in vals) B = prod((P ** (v // p) for P, v in zip(supp, vals)), one) if debug: - assert B ** p == aa + assert B**p == aa else: bvec = [] a2 = 1 if debug: - print("beta component is {} with coords {}".format(a2,bvec)) + print("beta component is {} with coords {}".format(a2, bvec)) print("continuing with quotient {} which should be a p'th power times a unit".format(a)) # 3. Now (a) = (c)^p for some c, so a/c^p is a unit @@ -681,12 +680,12 @@ def to_KSp(a): a3 = B if K == QQ else _ideal_generator(B) if debug: print("a3={}".format(a3)) - a /= a3 ** p + a /= a3**p if debug: - print("dividing by {}th power of {}".format(p,a3)) + print("dividing by {}th power of {}".format(p, a3)) print("continuing with quotient {} which should be a unit".format(a)) - #4. Now a is a unit + # 4. Now a is a unit # NB not a.is_unit which is true for all a in K^*. One could # also test K.ring_of_integers()(a).is_unit(). @@ -703,7 +702,7 @@ def to_KSp(a): else: cvec = [] else: - cvec = coords_in_U_mod_p(a,U,p) + cvec = coords_in_U_mod_p(a, U, p) if debug: print("gamma component has coords {}".format(cvec)) diff --git a/src/sage/rings/number_field/small_primes_of_degree_one.py b/src/sage/rings/number_field/small_primes_of_degree_one.py index 541130e8a71..3c40fc4b4aa 100644 --- a/src/sage/rings/number_field/small_primes_of_degree_one.py +++ b/src/sage/rings/number_field/small_primes_of_degree_one.py @@ -78,7 +78,7 @@ - Maarten Derickx (2017): fixed a bug with number fields not generated by an integral element """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2008 William Stein # # Distributed under the terms of the GNU General Public License (GPL) @@ -91,7 +91,7 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.rings.integer_ring import ZZ @@ -117,6 +117,7 @@ class Small_primes_of_degree_one_iter: - Nick Alexander """ + def __init__(self, field, num_integer_primes=10000, max_iterations=100): r""" Construct a new iterator of small degree one primes. @@ -130,11 +131,12 @@ def __init__(self, field, num_integer_primes=10000, max_iterations=100): """ self._field = field self._poly = self._field.absolute_field('b').defining_polynomial() - self._poly = ZZ['x'](self._poly.denominator() * self._poly()) # make integer polynomial + self._poly = ZZ['x'](self._poly.denominator() * self._poly()) # make integer polynomial self._lc = self._poly.leading_coefficient() # this uses that [ O_K : Z[a] ]^2 = | disc(f(x)) / disc(O_K) | from sage.libs.pari import pari + self._prod_of_small_primes = ZZ(pari('TEMPn = %s; TEMPps = primes(TEMPn); prod(X = 1, TEMPn, TEMPps[X])' % num_integer_primes)) self._prod_of_small_primes //= self._prod_of_small_primes.gcd(self._poly.discriminant() * self._lc) @@ -180,9 +182,9 @@ def _lengthen_queue(self): n = next(self._integer_iter) g = self._prod_of_small_primes.gcd(self._poly(n)) self._prod_of_small_primes //= g - self._queue = self._queue + [ (p, n) for p in g.prime_divisors() ] + self._queue = self._queue + [(p, n) for p in g.prime_divisors()] count += 1 - self._queue.sort() # sorts in ascending order + self._queue.sort() # sorts in ascending order def __next__(self): r""" diff --git a/src/sage/rings/number_field/splitting_field.py b/src/sage/rings/number_field/splitting_field.py index 98be5221a54..8b13df8ba5c 100644 --- a/src/sage/rings/number_field/splitting_field.py +++ b/src/sage/rings/number_field/splitting_field.py @@ -7,7 +7,7 @@ - Jeroen Demeyer (2014-01-03): added ``abort_degree`` argument, :issue:`15626` """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2014 Jeroen Demeyer # # This program is free software: you can redistribute it and/or modify @@ -15,7 +15,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.rings.integer import Integer from sage.arith.misc import factorial @@ -42,6 +42,7 @@ class SplittingFieldAbort(Exception): ... SplittingFieldAbort: degree of splitting field equals 12 """ + def __init__(self, div, mult): self.degree_divisor = div self.degree_multiple = mult @@ -64,6 +65,7 @@ class SplittingData: field containing the current field `K` and all roots of other polynomials inside the list `L` with ``dm`` less than this ``dm``. """ + def __init__(self, _pol, _dm): self.pol = _pol self.dm = Integer(_dm) @@ -410,7 +412,7 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No rel_degree_divisor = rel_degree_divisor.lcm(splitting.poldegree()) # Check for early aborts - abort_rel_degree = abort_degree//absolute_degree + abort_rel_degree = abort_degree // absolute_degree if abort_rel_degree and rel_degree_divisor > abort_rel_degree: raise SplittingFieldAbort(absolute_degree * rel_degree_divisor, degree_multiple) @@ -436,7 +438,7 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No # If the Galois group is contained in A_n, then mq_alt is # also the degree multiple over the current field K. # Here, we have equality if the Galois group is A_n. - mq_alt = mq.gcd(fac//2) + mq_alt = mq.gcd(fac // 2) # If we are over Q, then use PARI's polgalois() to compute # these degrees exactly. @@ -447,23 +449,23 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No pass else: mq = Integer(G[0]) - mq_alt = mq//2 if (G[1] == -1) else mq + mq_alt = mq // 2 if (G[1] == -1) else mq # In degree 4, use the cubic resolvent to refine the # degree bounds. if d == 4 and mq >= 12: # mq equals 12 or 24 # Compute cubic resolvent - a0, a1, a2, a3, a4 = (q/q.pollead()).Vecrev() + a0, a1, a2, a3, a4 = (q / q.pollead()).Vecrev() assert a4 == 1 - cubicpol = pari([4*a0*a2 - a1*a1 - a0*a3*a3, a1*a3 - 4*a0, -a2, 1]).Polrev() + cubicpol = pari([4 * a0 * a2 - a1 * a1 - a0 * a3 * a3, a1 * a3 - 4 * a0, -a2, 1]).Polrev() cubicfactors = Kpol.nffactor(cubicpol)[0] - if len(cubicfactors) == 1: # A4 or S4 + if len(cubicfactors) == 1: # A4 or S4 # After adding a root of the cubic resolvent, # the degree of the extension defined by q # is a factor 3 smaller. L.append(SplittingData(cubicpol, 3)) rel_degree_divisor = rel_degree_divisor.lcm(3) - mq = mq//3 # 4 or 8 + mq = mq // 3 # 4 or 8 mq_alt = 4 elif len(cubicfactors) == 2: # C4 or D8 # The irreducible degree 2 factor is @@ -471,7 +473,7 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No discpol = cubicfactors[1] L.append(SplittingData(discpol, 2)) mq = mq_alt = 4 - else: # C2 x C2 + else: # C2 x C2 mq = mq_alt = 4 if mq > mq_alt >= 3: @@ -506,7 +508,7 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No # Sort according to degree to handle low degrees first L.sort(key=lambda x: x.key()) verbose("SplittingData to handle: %s" % [s._repr_tuple() for s in L]) - verbose("Bounds for absolute degree: [%s, %s]" % (degree_divisor,degree_multiple)) + verbose("Bounds for absolute degree: [%s, %s]" % (degree_divisor, degree_multiple)) # Check consistency if degree_multiple % degree_divisor != 0: @@ -538,12 +540,12 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No if denom == 1: break denom = pari(denom.factor().radical_value()) - Mpol = (Mpol*(denom**Mpol.poldegree())).subst("x", pari([0,1/denom]).Polrev("x")) + Mpol = (Mpol * (denom ** Mpol.poldegree())).subst("x", pari([0, 1 / denom]).Polrev("x")) Mpol /= Mpol.content() Mdiv *= denom # We are finished for sure if we hit the degree bound - finished = (Mpol.poldegree() >= degree_multiple) + finished = Mpol.poldegree() >= degree_multiple if simplify_all or (simplify and not finished): # Find a simpler defining polynomial Lpol for Mpol @@ -557,9 +559,9 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No Lpol = Mpol.change_variable_name("y") MtoL = pari("'y") - NtoL = MtoL/Mdiv + NtoL = MtoL / Mdiv KtoL = KtoN.lift().subst("x", NtoL).Mod(Lpol) - Kpol = Lpol # New Kpol (for next iteration) + Kpol = Lpol # New Kpol (for next iteration) verbose("New field: %s" % Kpol, t) if map: t = cputime() @@ -578,11 +580,11 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No # First add f divided by the linear factor we obtained, # mg is the new degree multiple. - mg = splitting.dm//f.poldegree() + mg = splitting.dm // f.poldegree() if mg > 1: g = [c.subst("y", KtoL).Mod(Lpol) for c in f.Vecrev().lift()] g = pari(g).Polrev() - g /= pari([k*KtoL - NtoL, 1]).Polrev() # divide linear factor + g /= pari([k * KtoL - NtoL, 1]).Polrev() # divide linear factor Lred.append(SplittingData(g, mg)) for splitting in Lold: @@ -596,7 +598,7 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No verbose("Converted polynomials to new field", t, level=2) # Convert Kpol to Sage and construct the absolute number field - Kpol = PolynomialRing(RationalField(), name=poly.variable_name())(Kpol/Kpol.pollead()) + Kpol = PolynomialRing(RationalField(), name=poly.variable_name())(Kpol / Kpol.pollead()) K = NumberField(Kpol, name) if map: return K, F.hom(Fgen, K) diff --git a/src/sage/rings/number_field/structure.py b/src/sage/rings/number_field/structure.py index 212d8e2a6f0..24a77bb8eed 100644 --- a/src/sage/rings/number_field/structure.py +++ b/src/sage/rings/number_field/structure.py @@ -44,7 +44,7 @@ - Julian Rueth (2014-04-03): initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2014 Julian Rueth # # This program is free software: you can redistribute it and/or modify @@ -52,7 +52,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.structure.unique_representation import UniqueRepresentation @@ -90,6 +90,7 @@ class NumberFieldStructure(UniqueRepresentation): sage: KK is LL False """ + def __init__(self, other): """ Initialization. @@ -163,6 +164,7 @@ class NameChange(NumberFieldStructure): sage: [id(v) for v in gc.get_objects() if id(v) == u] [] """ + def create_structure(self, field): r""" Return a pair of isomorphisms which send the generator of ``field`` to @@ -179,6 +181,7 @@ def create_structure(self, field): To: Number Field in a with defining polynomial x^4 + x^3 + x^2 + x + 1) """ from . import maps + return maps.NameChangeMap(field, self.other), maps.NameChangeMap(self.other, field) @@ -200,6 +203,7 @@ class AbsoluteFromRelative(NumberFieldStructure): sage: AbsoluteFromRelative(L) """ + def create_structure(self, field): r""" Return a pair of isomorphisms which go from ``field`` to ``other`` and @@ -219,6 +223,7 @@ def create_structure(self, field): To: Number Field in c with defining polynomial x^4 - 10*x^2 + 1) """ from . import maps + return maps.MapAbsoluteToRelativeNumberField(field, self.other), maps.MapRelativeToAbsoluteNumberField(self.other, field) @@ -240,6 +245,7 @@ class RelativeFromAbsolute(NumberFieldStructure): sage: RelativeFromAbsolute(QQ, 1/2) """ + def __init__(self, other, gen): r""" Initialization. @@ -316,6 +322,7 @@ class RelativeFromRelative(NumberFieldStructure): sage: RelativeFromRelative(L) """ + def create_structure(self, field): r""" Return a pair of isomorphisms which go from ``field`` to the relative @@ -365,13 +372,13 @@ def create_structure(self, field): # First, we construct the isomorphism from other to field by embedding # other.base_field() into field. - gf = g*f + gf = g * f base = other.base_field() base_to_field = base.Hom(field)([h(gf(other.gen(1)))]) other_to_field = other.Hom(field)([h(gf(other.gen()))], base_map=base_to_field) # And its inverse, essentially the same construction: - f_g_ = f_*g_ + f_g_ = f_ * g_ base = field.base_field() base_to_other = base.Hom(other)([f_g_(h_(field.gen(1)))]) field_to_other = field.Hom(other)([f_g_(h_(field.gen()))], base_map=base_to_other) diff --git a/src/sage/rings/number_field/totallyreal_phc.py b/src/sage/rings/number_field/totallyreal_phc.py index 1da9b3b04d9..99f01c91336 100644 --- a/src/sage/rings/number_field/totallyreal_phc.py +++ b/src/sage/rings/number_field/totallyreal_phc.py @@ -45,9 +45,9 @@ def coefficients_to_power_sums(n, m, a): sage: coefficients_to_power_sums(5,4,[1,5,7,9,8]) [5, -8, 46, -317, 2158] """ - S = [n] + [0]*m - for k in range(1,m+1): - S[k] = -sum([a[n-i]*S[k-i] for i in range(1,k)])-k*a[n-k] + S = [n] + [0] * m + for k in range(1, m + 1): + S[k] = -sum([a[n - i] * S[k - i] for i in range(1, k)]) - k * a[n - k] return S @@ -88,7 +88,7 @@ def __lagrange_bounds_phc(n, m, a, tmpfile=None): """ # Compute power sums. - S = coefficients_to_power_sums(n,m,a) + S = coefficients_to_power_sums(n, m, a) # Look for phc. fi, fo = os.popen2('which phc') @@ -111,13 +111,13 @@ def __lagrange_bounds_phc(n, m, a, tmpfile=None): # then there are at most m-1 distinct values amongst the x_i. # Therefore we must solve the implied equations for each partition of n-1 # into m-1 parts. - for P in sage.combinat.partition.Partitions(n-1,length=m-1): + for P in sage.combinat.partition.Partitions(n - 1, length=m - 1): f = open(tmpfile, 'w') # First line: number of variables/equations f.write('%d' % m + '\n') # In the next m-1 lines, write the equation S_j(x) = S[j] - for j in range(1,m+1): - for i in range(m-1): + for j in range(1, m + 1): + for i in range(m - 1): f.write('%d' % P[i] + '*x%d' % i + '**%d' % j + ' + ') f.write('xn**%d' % j + ' - (%d' % S[j] + ');\n') f.close() @@ -132,7 +132,7 @@ def __lagrange_bounds_phc(n, m, a, tmpfile=None): posl = f_str.rfind('xn', 0, pos) f_str_split = f_str[posl:pos].split() crits += [float(f_str_split[2])] - pos = f_str.find('= real ', pos+1) + pos = f_str.find('= real ', pos + 1) if len(crits) > 0: output_data += [[P, min(crits), max(crits)]] diff --git a/src/sage/rings/number_field/totallyreal_rel.py b/src/sage/rings/number_field/totallyreal_rel.py index a88f2d584f2..895b47681fe 100644 --- a/src/sage/rings/number_field/totallyreal_rel.py +++ b/src/sage/rings/number_field/totallyreal_rel.py @@ -157,6 +157,7 @@ def integral_elements_in_box(K, C): import numpy import numpy.linalg + L = numpy.array([[v(b) for b in B] for v in Foo]) Linv = numpy.linalg.inv(L) Vi = [[C[0][0]], [C[0][1]]] @@ -166,33 +167,34 @@ def integral_elements_in_box(K, C): j = 0 while j < 2**d: for i in range(d): - if V[i, j] < V[i, j+1]: + if V[i, j] < V[i, j + 1]: V[i, j] = math.floor(V[i, j]) - V[i, j+1] = math.ceil(V[i, j+1]) + V[i, j + 1] = math.ceil(V[i, j + 1]) else: V[i, j] = math.ceil(V[i, j]) - V[i, j+1] = math.floor(V[i, j+1]) + V[i, j + 1] = math.floor(V[i, j + 1]) j += 2 - W0 = (Linv*numpy.array([Vi[0]] * d)).transpose() - W = (Linv*numpy.array([Vi[2**i] for i in range(d)])).transpose() + W0 = (Linv * numpy.array([Vi[0]] * d)).transpose() + W = (Linv * numpy.array([Vi[2**i] for i in range(d)])).transpose() for j in range(d): for i in range(d): - if W[i,j] < W0[i,j]: - W[i,j] = math.floor(W[i,j]) - W0[i,j] = math.ceil(W0[i,j]) + if W[i, j] < W0[i, j]: + W[i, j] = math.floor(W[i, j]) + W0[i, j] = math.ceil(W0[i, j]) else: - W[i,j] = math.ceil(W[i,j]) - W0[i,j] = math.floor(W0[i,j]) - M = [[int(V[i,j]) for i in range(V.shape[0])] for j in range(V.shape[1])] - M += [[int(W0[i,j]) for j in range(W0.shape[0])] for i in range(W0.shape[0])] - M += [[int(W[i,j]) for j in range(W.shape[1])] for i in range(W.shape[0])] + W[i, j] = math.ceil(W[i, j]) + W0[i, j] = math.floor(W0[i, j]) + M = [[int(V[i, j]) for i in range(V.shape[0])] for j in range(V.shape[1])] + M += [[int(W0[i, j]) for j in range(W0.shape[0])] for i in range(W0.shape[0])] + M += [[int(W[i, j]) for j in range(W.shape[1])] for i in range(W.shape[0])] from sage.matrix.constructor import matrix - M = (matrix(IntegerRing(),len(M),len(M[0]), M).transpose()).columns() + + M = (matrix(IntegerRing(), len(M), len(M[0]), M).transpose()).columns() i = 0 while i < len(M): - j = i+1 + j = i + 1 while j < len(M): if M[i] == M[j]: M.pop(j) @@ -201,6 +203,7 @@ def integral_elements_in_box(K, C): i += 1 from sage.geometry.lattice_polytope import LatticePolytope + P = LatticePolytope(M) try: @@ -211,18 +214,17 @@ def integral_elements_in_box(K, C): S = [] for p in pts: theta = sum(a * b for a, b in zip(p.list(), B)) - if all((C[i][0] <= Foo[i](theta) <= C[i][1]) - for i in range(d)): + if all((C[i][0] <= Foo[i](theta) <= C[i][1]) for i in range(d)): S.append(theta) return S -#******************************************************************************** +# ******************************************************************************** # Main class -#******************************************************************************** +# ******************************************************************************** -eps_global = 10**(-6) +eps_global = 10 ** (-6) class tr_data_rel: @@ -261,15 +263,15 @@ def __init__(self, F, m, B, a=None): sage: T = sage.rings.number_field.totallyreal_rel.tr_data_rel(F, 2, 2000) """ if a is None: # don't make the stupid noob mistake of putting a=[] - a = [] # in the function signature above. + a = [] # in the function signature above. # Initialize constants. self.m = m d = F.degree() self.d = d - self.n = n = m*d + self.n = n = m * d self.B = B - self.gamma = hermite_constant(self.n-self.d) + self.gamma = hermite_constant(self.n - self.d) self.F = F self.Z_F = F.maximal_order() @@ -277,8 +279,8 @@ def __init__(self, F, m, B, a=None): self.dF = abs(F.disc()) self.Fx = PolynomialRing(F, 'xF') - self.beta = [[]]*m - self.gnk = [[]]*m + self.beta = [[]] * m + self.gnk = [[]] * m self.trace_elts = [] @@ -287,30 +289,29 @@ def __init__(self, F, m, B, a=None): # Initialize variables. if not a: # No starting input, all polynomials will be found; initialize to zero. - self.a = [0]*m + [1] - self.amaxvals = [[]]*m - anm1s = [[i] for i in range(m//2+1)] - for i in range(1,self.d): + self.a = [0] * m + [1] + self.amaxvals = [[]] * m + anm1s = [[i] for i in range(m // 2 + 1)] + for i in range(1, self.d): for j in range(len(anm1s)): anm1s[j] = [anm1s[j] + [i] for i in range(m)] anm1s = sum(anm1s, []) anm1s = [sum([Z_Fbasis[i] * aa[i] for i in range(self.d)]) for aa in anm1s] # Minimize trace in class. import numpy + for i in range(len(anm1s)): - Q = [[v(m*x) for v in self.Foo] + [0] for x in Z_Fbasis] + [[v(anm1s[i]) for v in self.Foo] + [10**6]] + Q = [[v(m * x) for v in self.Foo] + [0] for x in Z_Fbasis] + [[v(anm1s[i]) for v in self.Foo] + [10**6]] pari_string = '[' + ';'.join(','.join("%s" % ii for ii in row) for row in zip(*Q)) + ']' adj = pari(pari_string).qflll()[self.d] - anm1s[i] += sum([m*Z_Fbasis[ii]*int(adj[ii])//int(adj[self.d]) for ii in range(self.d)]) + anm1s[i] += sum([m * Z_Fbasis[ii] * int(adj[ii]) // int(adj[self.d]) for ii in range(self.d)]) - self.amaxvals[m-1] = anm1s - self.a[m-1] = self.amaxvals[m-1].pop() - self.k = m-2 + self.amaxvals[m - 1] = anm1s + self.a[m - 1] = self.amaxvals[m - 1].pop() + self.k = m - 2 - bl = math.ceil(1.7719*self.n) - br = max([1./m*(am1**2).trace() + - self.gamma*(1./(m**d)*self.B/self.dF)**(1./(self.n-d)) - for am1 in anm1s]) + bl = math.ceil(1.7719 * self.n) + br = max([1.0 / m * (am1**2).trace() + self.gamma * (1.0 / (m**d) * self.B / self.dF) ** (1.0 / (self.n - d)) for am1 in anm1s]) br = math.floor(br) T2s = self.F._positive_integral_elements_with_trace([bl, br]) self.trace_elts.append([bl, br, T2s]) @@ -320,35 +321,32 @@ def __init__(self, F, m, B, a=None): # The value of k is the largest index of the coefficients of a which is # currently unknown; e.g., if k == -1, then we can iterate # over polynomials, and if k == n-1, then we have finished iterating. - if a[len(a)-1] != 1: - raise ValueError("a[len(a)-1](=%s) must be 1 so polynomial is monic" % a[len(a)-1]) + if a[len(a) - 1] != 1: + raise ValueError("a[len(a)-1](=%s) must be 1 so polynomial is monic" % a[len(a) - 1]) raise NotImplementedError("These have not been checked.") - k = m-len(a) + k = m - len(a) self.k = k - a = [0]*(k+1) + a - self.amaxvals = [[]]*m - for i in range(n+1): + a = [0] * (k + 1) + a + self.amaxvals = [[]] * m + for i in range(n + 1): self.a[i] = a[i] # Bounds come from an application of Lagrange multipliers in degrees 2,3. - self.b_lower = [-1./m*(v(self.a[m-1]) + - (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo] - self.b_upper = [-1./m*(v(self.a[m-1]) - - (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo] + self.b_lower = [-1.0 / m * (v(self.a[m - 1]) + (m - 1.0) * math.sqrt(v(self.a[m - 1]) ** 2 - 2.0 * (1 + 1.0 / (m - 1)) * v(self.a[m - 2]))) for v in self.Foo] + self.b_upper = [-1.0 / m * (v(self.a[m - 1]) - (m - 1.0) * math.sqrt(v(self.a[m - 1]) ** 2 - 2.0 * (1 + 1.0 / (m - 1)) * v(self.a[m - 2]))) for v in self.Foo] if k < m - 2: - bminmax = [lagrange_degree_3(n,v(self.a[m-1]),v(self.a[m-2]),v(self.a[m-3])) for v in self.Foo] + bminmax = [lagrange_degree_3(n, v(self.a[m - 1]), v(self.a[m - 2]), v(self.a[m - 3])) for v in self.Foo] self.b_lower = bminmax[0] self.b_upper = bminmax[1] # Annoying, but must reverse coefficients for numpy. - gnk = [binomial(j,k+2)*a[j] for j in range(k+2,n+1)] - self.beta[k+1] = [[self.b_lower] + numpy.roots([v(gnk[i]) for i in range(len(gnk))].reverse()).tolist().sort() + [self.b_upper] for v in self.Foo] + gnk = [binomial(j, k + 2) * a[j] for j in range(k + 2, n + 1)] + self.beta[k + 1] = [[self.b_lower] + numpy.roots([v(gnk[i]) for i in range(len(gnk))].reverse()).tolist().sort() + [self.b_upper] for v in self.Foo] # Now to really initialize gnk. - self.gnk[k+1] = [[0] + [binomial(j,k+1)*v(a[j]) - for j in range(k+2,m+1)] for v in self.Foo] + self.gnk[k + 1] = [[0] + [binomial(j, k + 1) * v(a[j]) for j in range(k + 2, m + 1)] for v in self.Foo] else: # Bad input! raise ValueError("a has length %s > m+1" % len(a)) @@ -404,10 +402,10 @@ def incr(self, f_out, verbose=False, haltk=0): k -= 1 # If we are working through an initialization routine, treat that. - elif haltk and k == haltk-1: + elif haltk and k == haltk - 1: if len(self.maxvals[k]) == 0: k += 1 - while k <= m-1 and len(self.amaxvals[k]) == 0: + while k <= m - 1 and len(self.amaxvals[k]) == 0: k += 1 if k < m: self.a[k] = self.amaxvals[k].pop() @@ -416,7 +414,7 @@ def incr(self, f_out, verbose=False, haltk=0): # If in the previous step we finished all possible values of # the lastmost coefficient, so we must compute bounds on the next coefficient. # Recall k == n-1 implies iteration is complete. - while k < m-1: + while k < m - 1: # maxoutflag flags a required abort along the way maxoutflag = False @@ -430,9 +428,8 @@ def incr(self, f_out, verbose=False, haltk=0): if k == m - 2: # We only know the value of a[n-1], the trace. - bl = max(math.ceil(1.7719*self.n), ((self.a[m-1]**2).trace()*1./m)) - br = 1./m*(self.a[m-1]**2).trace() + \ - self.gamma*(1./(m**d)*self.B/self.dF)**(1./(self.n-d)) + bl = max(math.ceil(1.7719 * self.n), ((self.a[m - 1] ** 2).trace() * 1.0 / m)) + br = 1.0 / m * (self.a[m - 1] ** 2).trace() + self.gamma * (1.0 / (m**d) * self.B / self.dF) ** (1.0 / (self.n - d)) br = math.floor(br) # Check for trivially empty. @@ -453,21 +450,20 @@ def incr(self, f_out, verbose=False, haltk=0): trace_elts_found = True if verbose >= 2: print(" found copy!") - T2s.extend(theta for theta in tre[2] - if bl <= theta.trace() <= br) + T2s.extend(theta for theta in tre[2] if bl <= theta.trace() <= br) break if not trace_elts_found: - T2s = self.F._positive_integral_elements_with_trace([bl,br]) - self.trace_elts.append([bl,br,T2s]) + T2s = self.F._positive_integral_elements_with_trace([bl, br]) + self.trace_elts.append([bl, br, T2s]) # Now ensure that T2 satisfies the correct parity condition am2s = [] for t2 in T2s: - am2 = (self.a[m-1]**2-t2)/2 + am2 = (self.a[m - 1] ** 2 - t2) / 2 if am2.is_integral(): ispositive = True for v in self.Foo: - ispositive = ispositive and v((m-1)*self.a[m-1]**2-2*m*am2) > 0 + ispositive = ispositive and v((m - 1) * self.a[m - 1] ** 2 - 2 * m * am2) > 0 if ispositive: am2s.append(am2) @@ -481,24 +477,22 @@ def incr(self, f_out, verbose=False, haltk=0): maxoutflag = 1 break - self.amaxvals[m-2] = am2s - self.a[m-2] = self.amaxvals[m-2].pop() + self.amaxvals[m - 2] = am2s + self.a[m - 2] = self.amaxvals[m - 2].pop() # Initialize the second derivative. - self.b_lower = [-1./m*(v(self.a[m-1]) + - (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo] - self.b_upper = [-1./m*(v(self.a[m-1]) - - (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo] - self.beta[k] = [[self.b_lower[i], -self.Foo[i](self.a[m-1])/m, self.b_upper[i]] for i in range(d)] - self.gnk[k] = [0, (m-1)*self.a[m-1], m*(m-1)/2] + self.b_lower = [-1.0 / m * (v(self.a[m - 1]) + (m - 1.0) * math.sqrt(v(self.a[m - 1]) ** 2 - 2.0 * (1 + 1.0 / (m - 1)) * v(self.a[m - 2]))) for v in self.Foo] + self.b_upper = [-1.0 / m * (v(self.a[m - 1]) - (m - 1.0) * math.sqrt(v(self.a[m - 1]) ** 2 - 2.0 * (1 + 1.0 / (m - 1)) * v(self.a[m - 2]))) for v in self.Foo] + self.beta[k] = [[self.b_lower[i], -self.Foo[i](self.a[m - 1]) / m, self.b_upper[i]] for i in range(d)] + self.gnk[k] = [0, (m - 1) * self.a[m - 1], m * (m - 1) / 2] if verbose >= 2: print(" betak:", self.beta[k]) else: # Compute the roots of the derivative. - self.gnk[k+1][0] = self.a[k+1] - gnk = self.gnk[k+1] - self.beta[k] = [numpy.roots([v(gnk[len(gnk)-1-i]) for i in range(len(gnk))]).tolist() for v in self.Foo] + self.gnk[k + 1][0] = self.a[k + 1] + gnk = self.gnk[k + 1] + self.beta[k] = [numpy.roots([v(gnk[len(gnk) - 1 - i]) for i in range(len(gnk))]).tolist() for v in self.Foo] try: for i in range(d): @@ -510,13 +504,13 @@ def incr(self, f_out, verbose=False, haltk=0): break # Check for double roots - for i in range(len(self.beta[k][0])-1): - if abs(self.beta[k][0][i] - self.beta[k][0][i+1]) < 2*eps_global: + for i in range(len(self.beta[k][0]) - 1): + if abs(self.beta[k][0][i] - self.beta[k][0][i + 1]) < 2 * eps_global: # This happens reasonably infrequently, so calling # the Python routine should be sufficiently fast... - f = self.Fx(self.gnk[k+1]) - df = self.Fx(self.gnk[k+2]) - if gcd(f,df) != 1: + f = self.Fx(self.gnk[k + 1]) + df = self.Fx(self.gnk[k + 2]) + if gcd(f, df) != 1: if verbose: print(" gnk has multiple factor!") maxoutflag = True @@ -524,14 +518,12 @@ def incr(self, f_out, verbose=False, haltk=0): if maxoutflag: break - if k == m-3: - self.b_lower = [-1./m*(v(self.a[m-1]) + - (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo] - self.b_upper = [-1./m*(v(self.a[m-1]) - - (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo] - elif k == m-4: + if k == m - 3: + self.b_lower = [-1.0 / m * (v(self.a[m - 1]) + (m - 1.0) * math.sqrt(v(self.a[m - 1]) ** 2 - 2.0 * (1 + 1.0 / (m - 1)) * v(self.a[m - 2]))) for v in self.Foo] + self.b_upper = [-1.0 / m * (v(self.a[m - 1]) - (m - 1.0) * math.sqrt(v(self.a[m - 1]) ** 2 - 2.0 * (1 + 1.0 / (m - 1)) * v(self.a[m - 2]))) for v in self.Foo] + elif k == m - 4: # New bounds from Lagrange multiplier in degree 3. - bminmax = [lagrange_degree_3(m,v(self.a[m-1]),v(self.a[m-2]),v(self.a[m-3])) for v in self.Foo] + bminmax = [lagrange_degree_3(m, v(self.a[m - 1]), v(self.a[m - 2]), v(self.a[m - 3])) for v in self.Foo] self.b_lower = [bminmax[i][0] for i in range(len(bminmax))] self.b_upper = [bminmax[i][1] for i in range(len(bminmax))] @@ -541,15 +533,11 @@ def incr(self, f_out, verbose=False, haltk=0): print(" betak:", self.beta[k]) # Compute next g_(m-(k+1)), k times the formal integral of g_(m-k). - self.gnk[k] = [self.F.primitive_element()*0] + [self.gnk[k+1][i-1]*(k+1)/i for i in range(1,m-k+1)] + self.gnk[k] = [self.F.primitive_element() * 0] + [self.gnk[k + 1][i - 1] * (k + 1) / i for i in range(1, m - k + 1)] gnk = self.gnk[k] - gnks = [[v(gnk[len(gnk)-1-i]) - for i in range(len(gnk))] - for v in self.Foo] - gnkm1 = self.gnk[k+1] - gnkm1s = [[v(gnkm1[len(gnkm1)-1-i]) - for i in range(len(gnkm1))] - for v in self.Foo] + gnks = [[v(gnk[len(gnk) - 1 - i]) for i in range(len(gnk))] for v in self.Foo] + gnkm1 = self.gnk[k + 1] + gnkm1s = [[v(gnkm1[len(gnkm1) - 1 - i]) for i in range(len(gnkm1))] for v in self.Foo] mk = m - (k + 1) if verbose >= 2: @@ -559,21 +547,15 @@ def incr(self, f_out, verbose=False, haltk=0): # Compute upper and lower bounds which guarantee one retains # a polynomial with all real roots. betak = self.beta[k] - akmin = [-numpy.polyval(gnks[j], betak[j][mk+1]) - - abs(numpy.polyval(gnkm1s[j], betak[j][mk+1]))*eps_global for j in range(self.d)] - for i in range(1,(mk+1)//2+1): + akmin = [-numpy.polyval(gnks[j], betak[j][mk + 1]) - abs(numpy.polyval(gnkm1s[j], betak[j][mk + 1])) * eps_global for j in range(self.d)] + for i in range(1, (mk + 1) // 2 + 1): # Use the fact that f(z) <= f(x)+|f'(x)|eps if |x-z| < eps # for sufficiently small eps, f(z) = 0, and f''(z) < 0. - akmin = [max(akmin[j], - -numpy.polyval(gnks[j], betak[j][mk+1-2*i]) - - abs(numpy.polyval(gnkm1s[j], betak[j][mk+1-2*i])*eps_global)) for j in range(self.d)] + akmin = [max(akmin[j], -numpy.polyval(gnks[j], betak[j][mk + 1 - 2 * i]) - abs(numpy.polyval(gnkm1s[j], betak[j][mk + 1 - 2 * i]) * eps_global)) for j in range(self.d)] - akmax = [-numpy.polyval(gnks[j], betak[j][mk]) + - abs(numpy.polyval(gnkm1s[j], betak[j][mk]))*eps_global for j in range(self.d)] - for i in range(1, mk//2+1): - akmax = [min(akmax[j], - -numpy.polyval(gnks[j], betak[j][mk-2*i]) + - abs(numpy.polyval(gnkm1s[j], betak[j][mk-2*i])*eps_global)) for j in range(self.d)] + akmax = [-numpy.polyval(gnks[j], betak[j][mk]) + abs(numpy.polyval(gnkm1s[j], betak[j][mk])) * eps_global for j in range(self.d)] + for i in range(1, mk // 2 + 1): + akmax = [min(akmax[j], -numpy.polyval(gnks[j], betak[j][mk - 2 * i]) + abs(numpy.polyval(gnkm1s[j], betak[j][mk - 2 * i]) * eps_global)) for j in range(self.d)] if verbose >= 2: print(" akmin:", akmin) @@ -588,12 +570,9 @@ def incr(self, f_out, verbose=False, haltk=0): if maxoutflag: break - self.amaxvals[k] = integral_elements_in_box(self.F, [[akmin[i],akmax[i]] for i in range(d)]) + self.amaxvals[k] = integral_elements_in_box(self.F, [[akmin[i], akmax[i]] for i in range(d)]) if k == 0: - a0s = [0, -sum([self.a[i] for i in range(1,m+1)]), - -sum([self.a[i]*(-1)**i for i in range(1,m+1)]), - -sum([self.a[i]*2**i for i in range(1,m+1)]), - -sum([self.a[i]*(-2)**i for i in range(1,m+1)])] + a0s = [0, -sum([self.a[i] for i in range(1, m + 1)]), -sum([self.a[i] * (-1) ** i for i in range(1, m + 1)]), -sum([self.a[i] * 2**i for i in range(1, m + 1)]), -sum([self.a[i] * (-2) ** i for i in range(1, m + 1)])] for a0 in a0s: try: self.amaxvals[0].remove(a0) @@ -634,9 +613,8 @@ def incr(self, f_out, verbose=False, haltk=0): # Main routine # **************************************************************************** -def enumerate_totallyreal_fields_rel(F, m, B, a=[], verbose=0, - return_seqs=False, - return_pari_objects=True): + +def enumerate_totallyreal_fields_rel(F, m, B, a=[], verbose=0, return_seqs=False, return_pari_objects=True): r""" This function enumerates (primitive) totally real field extensions of degree `m>1` of the totally real field F with discriminant `d \leq B`; @@ -726,26 +704,26 @@ def enumerate_totallyreal_fields_rel(F, m, B, a=[], verbose=0, m = Integer(m) except TypeError: raise TypeError("cannot coerce m (= %s) to an integer" % m) - if (m < 1): + if m < 1: raise ValueError("m must be at least 1.") - n = F.degree()*m + n = F.degree() * m # Initialize - S = {} # dictionary of the form {(d, fabs): f, ...} + S = {} # dictionary of the form {(d, fabs): f, ...} dB_odlyzko = odlyzko_bound_totallyreal(n) - dB = math.ceil(40000*dB_odlyzko**n) - counts = [0,0,0,0] + dB = math.ceil(40000 * dB_odlyzko**n) + counts = [0, 0, 0, 0] # Trivial case if m == 1: g = pari(F.defining_polynomial()).polrecip().Vec() if return_seqs: - return [[0,0,0,0], [1, [-1, 1], g]] + return [[0, 0, 0, 0], [1, [-1, 1], g]] if return_pari_objects: return [[1, g, pari('xF-1')]] Px = PolynomialRing(QQ, 'xF') - return [[ZZ(1), [QQ(_) for _ in g], Px.gen()-1]] + return [[ZZ(1), [QQ(_) for _ in g], Px.gen() - 1]] if verbose: saveout = sys.stdout @@ -753,17 +731,16 @@ def enumerate_totallyreal_fields_rel(F, m, B, a=[], verbose=0, fsock = open(verbose, 'w') sys.stdout = fsock # Else, print to screen - f_out = [0]*m + [1] + f_out = [0] * m + [1] T = tr_data_rel(F, m, B, a) if verbose == 2: - T.incr(f_out,verbose) + T.incr(f_out, verbose) else: T.incr(f_out) Fx = PolynomialRing(F, 'xF') - nfF = pari(str(F.defining_polynomial()).replace('x', - str(F.primitive_element()))) + nfF = pari(str(F.defining_polynomial()).replace('x', str(F.primitive_element()))) parit = pari(str(F.primitive_element())) while f_out[m] != 0: @@ -774,7 +751,7 @@ def enumerate_totallyreal_fields_rel(F, m, B, a=[], verbose=0, f_str = '' for i in range(len(f_out)): f_str += '(' + str(f_out[i]) + ')*x^' + str(i) - if i < len(f_out)-1: + if i < len(f_out) - 1: f_str += '+' nf = pari(f_str) if nf.poldegree('t') == 0: @@ -783,10 +760,10 @@ def enumerate_totallyreal_fields_rel(F, m, B, a=[], verbose=0, if nf[n] == -1: nf *= -1 d = nf.poldisc() - #counts[0] += 1 + # counts[0] += 1 if d > 0 and nf.polsturm() == n: da = int_has_small_square_divisor(Integer(d)) - if d > dB or d <= B*da: + if d > dB or d <= B * da: counts[1] += 1 if nf.polisirreducible(): counts[2] += 1 @@ -798,7 +775,7 @@ def enumerate_totallyreal_fields_rel(F, m, B, a=[], verbose=0, # Find a minimal lattice element counts[3] += 1 - ng = pari([nf,zk]).polredabs() + ng = pari([nf, zk]).polredabs() # Check if K is contained in the list. if (d, ng) in S: @@ -824,23 +801,23 @@ def enumerate_totallyreal_fields_rel(F, m, B, a=[], verbose=0, else: print("is not totally real") if verbose == 2: - T.incr(f_out,verbose=verbose) + T.incr(f_out, verbose=verbose) else: T.incr(f_out) # In the application of Smyth's theorem above, we exclude finitely # many possibilities which we must now throw back in. if m == 2: - if Fx([-1,1,1]).is_irreducible(): - K = F.extension(Fx([-1,1,1]), 'tK') + if Fx([-1, 1, 1]).is_irreducible(): + K = F.extension(Fx([-1, 1, 1]), 'tK') Kabs = K.absolute_field('tKabs') Kabs_pari = pari(Kabs.defining_polynomial()) d = K.absolute_discriminant() if abs(d) <= B: ng = Kabs_pari.polredabs() - S[(d, ng)] = Fx([-1,1,1]) + S[(d, ng)] = Fx([-1, 1, 1]) elif F.degree() == 2: - for ff in [[1,-7,13,-7,1],[1,-8,14,-7,1]]: + for ff in [[1, -7, 13, -7, 1], [1, -8, 14, -7, 1]]: f = Fx(ff).factor()[0][0] K = F.extension(f, 'tK') Kabs = K.absolute_field('tKabs') @@ -871,8 +848,7 @@ def enumerate_totallyreal_fields_rel(F, m, B, a=[], verbose=0, if verbose: print("=" * 80) print("Polynomials tested: {}".format(counts[0])) - print("Polynomials with discriminant with large enough square" - " divisor: {}".format(counts[1])) + print("Polynomials with discriminant with large enough square" " divisor: {}".format(counts[1])) print("Irreducible polynomials: {}".format(counts[2])) print("Polynomials with nfdisc <= B: {}".format(counts[3])) for i in range(len(S)): @@ -883,18 +859,14 @@ def enumerate_totallyreal_fields_rel(F, m, B, a=[], verbose=0, # Make sure to return elements that belong to Sage if return_seqs: - return [[ZZ(x) for x in counts], - [[s[0], [QQ(x) for x in s[1].polrecip().Vec()], - s[2].coefficients(sparse=False)] - for s in S]] + return [[ZZ(x) for x in counts], [[s[0], [QQ(x) for x in s[1].polrecip().Vec()], s[2].coefficients(sparse=False)] for s in S]] if return_pari_objects: return S Px = PolynomialRing(QQ, 'x') return [[s[0], Px([QQ(_) for _ in s[1].list()]), s[2]] for s in S] -def enumerate_totallyreal_fields_all(n, B, verbose=0, return_seqs=False, - return_pari_objects=True): +def enumerate_totallyreal_fields_all(n, B, verbose=0, return_seqs=False, return_pari_objects=True): r""" Enumerate *all* totally real fields of degree ``n`` with discriminant at most ``B``, primitive or otherwise. @@ -958,20 +930,20 @@ def enumerate_totallyreal_fields_all(n, B, verbose=0, return_seqs=False, raise ValueError("Only implemented for n = p*q with p,q prime") for d in div_n: if 1 < d < n: - Sds = enumerate_totallyreal_fields_prim(d, int(math.floor((1.*B)**(1.*d/n))), verbose=verbose) + Sds = enumerate_totallyreal_fields_prim(d, int(math.floor((1.0 * B) ** (1.0 * d / n))), verbose=verbose) for i in range(len(Sds)): if verbose: print("=" * 80) print("Taking F =", Sds[i][1]) F = NumberField(ZZx(Sds[i][1]), 't') - T = enumerate_totallyreal_fields_rel(F, n/d, B, verbose=verbose, return_seqs=return_seqs) + T = enumerate_totallyreal_fields_rel(F, n / d, B, verbose=verbose, return_seqs=return_seqs) if return_seqs: for k in range(4): counts[k] += T[0][k] - S += [[t[0],pari(t[1]).Polrev()] for t in T[1]] + S += [[t[0], pari(t[1]).Polrev()] for t in T[1]] else: - S += [[t[0],t[1]] for t in T] - for E in enumerate_totallyreal_fields_prim(n/d, int(math.floor((1.*B)**(1./d)/(1.*Sds[i][0])**(n*1./d**2)))): + S += [[t[0], t[1]] for t in T] + for E in enumerate_totallyreal_fields_prim(n / d, int(math.floor((1.0 * B) ** (1.0 / d) / (1.0 * Sds[i][0]) ** (n * 1.0 / d**2)))): for EF in F.composite_fields(NumberField(ZZx(E[1]), 'u')): if EF.degree() == n and EF.disc() <= B: S.append([EF.disc(), pari(EF.absolute_polynomial())]) @@ -988,8 +960,7 @@ def enumerate_totallyreal_fields_all(n, B, verbose=0, return_seqs=False, # Else, print to screen print("=" * 80) print("Polynomials tested: {}".format(counts[0])) - print("Polynomials with discriminant with large enough square" - " divisor: {}".format(counts[1])) + print("Polynomials with discriminant with large enough square" " divisor: {}".format(counts[1])) print("Irreducible polynomials: {}".format(counts[2])) print("Polynomials with nfdisc <= B: {}".format(counts[3])) for i in range(len(S)): @@ -1000,10 +971,8 @@ def enumerate_totallyreal_fields_all(n, B, verbose=0, return_seqs=False, # Make sure to return elements that belong to Sage if return_seqs: - return [[ZZ(_) for _ in counts], - [[ZZ(s[0]), [QQ(_) for _ in s[1].polrecip().Vec()]] for s in S]] + return [[ZZ(_) for _ in counts], [[ZZ(s[0]), [QQ(_) for _ in s[1].polrecip().Vec()]] for s in S]] if return_pari_objects: return S Px = PolynomialRing(QQ, 'x') - return [[ZZ(s[0]), Px([QQ(_) for _ in s[1].list()])] - for s in S] + return [[ZZ(s[0]), Px([QQ(_) for _ in s[1].list()])] for s in S] diff --git a/src/sage/rings/number_field/unit_group.py b/src/sage/rings/number_field/unit_group.py index 9f86d1ff0eb..83b768ac034 100644 --- a/src/sage/rings/number_field/unit_group.py +++ b/src/sage/rings/number_field/unit_group.py @@ -150,6 +150,7 @@ - John Cremona """ + # **************************************************************************** # Copyright (C) 2009 William Stein, John Cremona # @@ -223,6 +224,7 @@ class UnitGroup(AbelianGroupWithValues_class): sage: SUK.log(21*z) (25, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1) """ + # This structure is not a parent in the usual sense. The # "elements" are NumberFieldElement_absolute. Instead, they should # derive from AbelianGroupElement and coerce into @@ -347,21 +349,21 @@ def __init__(self, number_field, proof=True, S=None): self.__S_unit_data = pK.bnfunits(pS) # TODO: converting the factored matrix representation of bnfunits into polynomial # form is a *big* waste of time - su = [pK.nfbasistoalg(pK.nffactorback(z)) for z in self.__S_unit_data[0][0:len(S)]] + su = [pK.nfbasistoalg(pK.nffactorback(z)) for z in self.__S_unit_data[0][0 : len(S)]] su = [K(u, check=False) for u in su] else: su = [] - self.__nfu = len(fu) # number of fundamental units - self.__nsu = len(su) # number of S-units - self.__ntu = pK.bnf_get_tu()[0] # order of torsion + self.__nfu = len(fu) # number of fundamental units + self.__nsu = len(su) # number of S-units + self.__ntu = pK.bnf_get_tu()[0] # order of torsion self.__rank = self.__nfu + self.__nsu # Put the torsion unit first, then fundamental units then S-units gens = [K(pK.bnf_get_tu()[1], check=False)] + fu + su # Construct the abstract group: - gens_orders = tuple([ZZ(self.__ntu)]+[ZZ(0)]*(self.__rank)) + gens_orders = tuple([ZZ(self.__ntu)] + [ZZ(0)] * (self.__rank)) AbelianGroupWithValues_class.__init__(self, gens_orders, 'u', gens, number_field) def _element_constructor_(self, u): @@ -404,7 +406,7 @@ def _element_constructor_(self, u): try: u = K(u) except TypeError: - raise ValueError("%s is not an element of %s" % (u,K)) + raise ValueError("%s is not an element of %s" % (u, K)) if self.__S: m = pK.bnfisunit(pari(u), self.__S_unit_data).mattranspose() if m.ncols() == 0: @@ -415,10 +417,10 @@ def _element_constructor_(self, u): m = pK.bnfisunit(pari(u)).mattranspose() # convert column matrix to a list: - m = [ZZ(m[0,i].sage()) for i in range(m.ncols())] + m = [ZZ(m[0, i].sage()) for i in range(m.ncols())] # NOTE: pari ordering for the units is (S-units, fundamental units, torsion unit) - m = [m[-1]] + m[self.__nsu:-1] + m[:self.__nsu] + m = [m[-1]] + m[self.__nsu : -1] + m[: self.__nsu] return self.element_class(self, m) @@ -434,7 +436,7 @@ def rank(self): sage: SUK = UnitGroup(K, S=2); SUK.rank() 6 """ - return self.ngens()-1 + return self.ngens() - 1 def _repr_(self): """ @@ -454,13 +456,8 @@ def _repr_(self): with S = (Fractional ideal (a),) """ if self.__S: - return 'S-unit group with structure %s of %s with S = %s' % ( - self._group_notation(self.gens_orders()), - self.number_field(), - self.primes()) - return 'Unit group with structure %s of %s' % ( - self._group_notation(self.gens_orders()), - self.number_field()) + return 'S-unit group with structure %s of %s with S = %s' % (self._group_notation(self.gens_orders()), self.number_field(), self.primes()) + return 'Unit group with structure %s of %s' % (self._group_notation(self.gens_orders()), self.number_field()) def fundamental_units(self): """ @@ -576,7 +573,7 @@ def zeta(self, n=2, all=False): return [K(-1)] return K(-1) if n.divides(N): - z = self.torsion_generator().value() ** (N//n) + z = self.torsion_generator().value() ** (N // n) if all: return [z**i for i in n.coprime_integers(n)] return z @@ -709,5 +706,4 @@ def exp(self, exponents): sage: SUK.log(u) == v True """ - return prod((u**e for u, e in zip(self.gens_values(), exponents)), - self.number_field().one()) + return prod((u**e for u, e in zip(self.gens_values(), exponents)), self.number_field().one()) diff --git a/src/sage/rings/numbers_abc.py b/src/sage/rings/numbers_abc.py index 18f794d66c5..7f092eed354 100644 --- a/src/sage/rings/numbers_abc.py +++ b/src/sage/rings/numbers_abc.py @@ -47,7 +47,7 @@ True """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2015 Jeroen Demeyer # # This program is free software: you can redistribute it and/or modify @@ -55,4 +55,4 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** diff --git a/src/sage/rings/padics/eisenstein_extension_generic.py b/src/sage/rings/padics/eisenstein_extension_generic.py index e8f3b693d64..c67a0e1c1e1 100644 --- a/src/sage/rings/padics/eisenstein_extension_generic.py +++ b/src/sage/rings/padics/eisenstein_extension_generic.py @@ -35,7 +35,7 @@ def __init__(self, poly, prec, print_mode, names, element_class): sage: B. = A.ext(x^2+7) # indirect doctest # needs sage.libs.ntl sage.rings.padics """ pAdicExtensionGeneric.__init__(self, poly, prec, print_mode, names, element_class) - #self._precompute() + # self._precompute() def _extension_type(self): """ @@ -133,16 +133,16 @@ def residue_ring(self, n): return self.ground_ring().residue_ring(1) raise NotImplementedError - #def discriminant(self, K=None): + # def discriminant(self, K=None): # if K is self: # return 1 # else: # raise NotImplementedError - #def automorphisms(self): + # def automorphisms(self): # raise NotImplementedError - #def galois_group(self): + # def galois_group(self): # r""" # Returns the Galois group of ``self``'s fraction field over Qp. # """ @@ -153,10 +153,10 @@ def residue_ring(self, n): # ## # raise NotImplementedError - #def is_abelian(self): + # def is_abelian(self): # raise NotImplementedError - #def is_normal(self): + # def is_normal(self): # raise NotImplementedError def gen(self, n=0): @@ -173,7 +173,7 @@ def gen(self, n=0): """ if n != 0: raise IndexError("only one generator") - return self([0,1]) + return self([0, 1]) def uniformizer_pow(self, n): """ @@ -222,6 +222,7 @@ def _uniformizer_print(self): """ return self.variable_name() + # def has_pth_root(self): # raise NotImplementedError diff --git a/src/sage/rings/padics/factory.py b/src/sage/rings/padics/factory.py index e54842b1015..30493c9455d 100644 --- a/src/sage/rings/padics/factory.py +++ b/src/sage/rings/padics/factory.py @@ -79,19 +79,19 @@ from sage.structure.factorization import Factorization from sage.structure.factory import UniqueFactory -#This imports all of the classes used in the ext_table below. +# This imports all of the classes used in the ext_table below. ext_table = {} ext_table['e', pAdicFieldCappedRelative] = EisensteinExtensionFieldCappedRelative ext_table['e', pAdicRingCappedAbsolute] = EisensteinExtensionRingCappedAbsolute ext_table['e', pAdicRingCappedRelative] = EisensteinExtensionRingCappedRelative ext_table['e', pAdicRingFixedMod] = EisensteinExtensionRingFixedMod -#ext_table['e', pAdicRingFloatingPoint] = EisensteinExtensionRingFloatingPoint -#ext_table['e', pAdicFieldFloatingPoint] = EisensteinExtensionFieldFloatingPoint -#ext_table['p', pAdicFieldCappedRelative] = pAdicGeneralExtensionFieldCappedRelative -#ext_table['p', pAdicRingCappedAbsolute] = pAdicGeneralExtensionRingCappedAbsolute -#ext_table['p', pAdicRingCappedRelative] = pAdicGeneralExtensionRingCappedRelative -#ext_table['p', pAdicRingFixedMod] = pAdicGeneralExtensionRingFixedMod +# ext_table['e', pAdicRingFloatingPoint] = EisensteinExtensionRingFloatingPoint +# ext_table['e', pAdicFieldFloatingPoint] = EisensteinExtensionFieldFloatingPoint +# ext_table['p', pAdicFieldCappedRelative] = pAdicGeneralExtensionFieldCappedRelative +# ext_table['p', pAdicRingCappedAbsolute] = pAdicGeneralExtensionRingCappedAbsolute +# ext_table['p', pAdicRingCappedRelative] = pAdicGeneralExtensionRingCappedRelative +# ext_table['p', pAdicRingFixedMod] = pAdicGeneralExtensionRingFixedMod ext_table['u', pAdicFieldCappedRelative] = UnramifiedExtensionFieldCappedRelative ext_table['u', pAdicRingCappedAbsolute] = UnramifiedExtensionRingCappedAbsolute ext_table['u', pAdicRingCappedRelative] = UnramifiedExtensionRingCappedRelative @@ -244,7 +244,7 @@ def get_key_base(p, prec, type, print_mode, names, ram_name, print_pos, print_se prec = Integer(prec) if prec is None: if type == 'lattice-cap': - prec = (DEFAULT_PREC, 2*DEFAULT_PREC) + prec = (DEFAULT_PREC, 2 * DEFAULT_PREC) else: prec = DEFAULT_PREC print_ram_name = ram_name @@ -283,7 +283,7 @@ def get_key_base(p, prec, type, print_mode, names, ram_name, print_pos, print_se # We eliminate irrelevant print options (e.g. print_pos if p = 2) if p == 2 or print_mode in {'digits', 'digits-unicode'}: - print_pos = True # we want this hard-coded so that we don't get duplicate parents if the keys differ. + print_pos = True # we want this hard-coded so that we don't get duplicate parents if the keys differ. if print_mode in {'digits', 'digits-unicode'}: print_ram_name = None print_alphabet = print_alphabet[:p] @@ -319,6 +319,7 @@ def get_key_base(p, prec, type, print_mode, names, ram_name, print_pos, print_se key = (p, prec, type, print_mode, name, print_pos, print_sep, tuple(print_alphabet), print_max_terms, show_prec, label) return key + ####################################################################################################### # # p-adic Fields @@ -726,10 +727,8 @@ class Qp_class(UniqueFactory): sage: K = Qp(15, check=False); a = K(999); a 9 + 6*15 + 4*15^2 + O(15^20) """ - def create_key(self, p, prec=None, type='capped-rel', print_mode=None, - names=None, ram_name=None, print_pos=None, - print_sep=None, print_alphabet=None, print_max_terms=None, show_prec=None, check=True, - label=None): # specific to Lattice precision + + def create_key(self, p, prec=None, type='capped-rel', print_mode=None, names=None, ram_name=None, print_pos=None, print_sep=None, print_alphabet=None, print_max_terms=None, show_prec=None, check=True, label=None): # specific to Lattice precision r""" Create a key from input parameters for ``Qp``. @@ -748,7 +747,7 @@ def create_key(self, p, prec=None, type='capped-rel', print_mode=None, print_alphabet = print_max_terms print_max_terms = check check = True - if label is not None and type not in ['lattice-cap','lattice-float']: + if label is not None and type not in ['lattice-cap', 'lattice-float']: raise ValueError("label keyword only supported for lattice precision") return get_key_base(p, prec, type, print_mode, names, ram_name, print_pos, print_sep, print_alphabet, print_max_terms, show_prec, check, ['capped-rel', 'floating-point', 'lattice-cap', 'lattice-float', 'relaxed'], label) @@ -772,12 +771,10 @@ def create_object(self, version, key): label = None else: p, prec, type, print_mode, name, print_pos, print_sep, print_alphabet, print_max_terms, show_prec, label = key - if (version[0] < 4 or (len(version) > 1 and version[0] == 4 and version[1] < 5) or - (len(version) > 2 and version[0] == 4 and version[1] == 5 and version[2] < 3)): + if version[0] < 4 or (len(version) > 1 and version[0] == 4 and version[1] < 5) or (len(version) > 2 and version[0] == 4 and version[1] == 5 and version[2] < 3): # keys changed in order to reduce irrelevant duplications: e.g. two Qps with print_mode 'series' # that are identical except for different 'print_alphabet' now return the same object. - key = get_key_base(p, prec, type, print_mode, name, None, print_pos, print_sep, print_alphabet, - print_max_terms, None, False, ['capped-rel', 'fixed-mod', 'capped-abs']) + key = get_key_base(p, prec, type, print_mode, name, None, print_pos, print_sep, print_alphabet, print_max_terms, None, False, ['capped-rel', 'fixed-mod', 'capped-abs']) try: obj = self._cache[version, key]() if obj is not None: @@ -790,37 +787,21 @@ def create_object(self, version, key): if type == 'capped-rel': if print_mode == 'terse': - return pAdicFieldCappedRelative(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_terse_terms': print_max_terms, 'show_prec': show_prec}, name, - category=_Fields) - return pAdicFieldCappedRelative(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name, - category=_Fields) + return pAdicFieldCappedRelative(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, 'ram_name': name, 'max_terse_terms': print_max_terms, 'show_prec': show_prec}, name, category=_Fields) + return pAdicFieldCappedRelative(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name, category=_Fields) if type == 'floating-point': if print_mode == 'terse': - return pAdicFieldFloatingPoint(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_terse_terms': print_max_terms, 'show_prec': show_prec}, name, - category=_Fields) - return pAdicFieldFloatingPoint(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name, - category=_Fields) + return pAdicFieldFloatingPoint(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, 'ram_name': name, 'max_terse_terms': print_max_terms, 'show_prec': show_prec}, name, category=_Fields) + return pAdicFieldFloatingPoint(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name, category=_Fields) if type == 'relaxed': if print_mode == 'terse': - return pAdicFieldRelaxed(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_terse_terms': print_max_terms, 'show_prec': show_prec}, name, - category=_Fields) - return pAdicFieldRelaxed(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name, - category=_Fields) + return pAdicFieldRelaxed(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, 'ram_name': name, 'max_terse_terms': print_max_terms, 'show_prec': show_prec}, name, category=_Fields) + return pAdicFieldRelaxed(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name, category=_Fields) if type[:8] == 'lattice-': subtype = type[8:] if print_mode == 'terse': - return pAdicFieldLattice(p, prec, subtype, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_terse_terms': print_max_terms, 'show_prec': show_prec}, name, label, - category=_Fields) - return pAdicFieldLattice(p, prec, subtype, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name, label, - category=_Fields) + return pAdicFieldLattice(p, prec, subtype, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, 'ram_name': name, 'max_terse_terms': print_max_terms, 'show_prec': show_prec}, name, label, category=_Fields) + return pAdicFieldLattice(p, prec, subtype, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name, label, category=_Fields) raise ValueError("unexpected type") @@ -831,10 +812,8 @@ def create_object(self, version, key): # Qq -- unramified extensions ###################################################### -def Qq(q, prec=None, type='capped-rel', modulus=None, names=None, - print_mode=None, ram_name=None, res_name=None, print_pos=None, - print_sep=None, print_max_ram_terms=None, - print_max_unram_terms=None, print_max_terse_terms=None, show_prec=None, check=True, implementation='FLINT'): + +def Qq(q, prec=None, type='capped-rel', modulus=None, names=None, print_mode=None, ram_name=None, res_name=None, print_pos=None, print_sep=None, print_max_ram_terms=None, print_max_unram_terms=None, print_max_terse_terms=None, show_prec=None, check=True, implementation='FLINT'): r""" Given a prime power `q = p^n`, return the unique unramified extension of `\QQ_p` of degree `n`. @@ -1345,7 +1324,7 @@ def Qq(q, prec=None, type='capped-rel', modulus=None, names=None, if not isinstance(q, tuple): q = tuple(q) - p,k = q + p, k = q if not isinstance(p, Integer): p = Integer(p) if not isinstance(k, Integer): @@ -1358,8 +1337,7 @@ def Qq(q, prec=None, type='capped-rel', modulus=None, names=None, if prec is not None and not isinstance(prec, Integer): prec = Integer(prec) - base = Qp(p=p, prec=prec, type=type, print_mode=print_mode, names=ram_name, print_pos=print_pos, - print_sep=print_sep, print_max_terms=print_max_ram_terms, show_prec=show_prec, check=check) + base = Qp(p=p, prec=prec, type=type, print_mode=print_mode, names=ram_name, print_pos=print_pos, print_sep=print_sep, print_max_terms=print_max_ram_terms, show_prec=show_prec, check=check) if k == 1: return base @@ -1378,13 +1356,10 @@ def Qq(q, prec=None, type='capped-rel', modulus=None, names=None, if modulus is None: from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF + modulus = GF((p, k), res_name).modulus().change_ring(ZZ) - return ExtensionFactory(base=base, modulus=modulus, prec=prec, print_mode=print_mode, - names=names, res_name=res_name, ram_name=ram_name, print_pos=print_pos, - print_sep=print_sep, print_max_ram_terms=print_max_ram_terms, - print_max_unram_terms=print_max_unram_terms, - print_max_terse_terms=print_max_terse_terms, show_prec=show_prec, check=check, - unram=True, implementation=implementation) + return ExtensionFactory(base=base, modulus=modulus, prec=prec, print_mode=print_mode, names=names, res_name=res_name, ram_name=ram_name, print_pos=print_pos, print_sep=print_sep, print_max_ram_terms=print_max_ram_terms, print_max_unram_terms=print_max_unram_terms, print_max_terse_terms=print_max_terse_terms, show_prec=show_prec, check=check, unram=True, implementation=implementation) + ###################################################### # Short constructor names for different types @@ -1498,6 +1473,7 @@ def QpER(p, prec=None, halt=None, secure=False, *args, **kwds): """ return Qp(p, (prec, halt, secure), 'relaxed', *args, **kwds) + ####################################################################################################### # # p-adic Rings @@ -1945,10 +1921,8 @@ class Zp_class(UniqueFactory): sage: a + b 1 + 5 + O(5^10) """ - def create_key(self, p, prec=None, type='capped-rel', print_mode=None, - names=None, ram_name=None, print_pos=None, print_sep=None, print_alphabet=None, - print_max_terms=None, show_prec=None, check=True, - label=None): + + def create_key(self, p, prec=None, type='capped-rel', print_mode=None, names=None, ram_name=None, print_pos=None, print_sep=None, print_alphabet=None, print_max_terms=None, show_prec=None, check=True, label=None): r""" Create a key from input parameters for ``Zp``. @@ -1979,12 +1953,9 @@ def create_key(self, p, prec=None, type='capped-rel', print_mode=None, print_alphabet = print_max_terms print_max_terms = check check = True - if label is not None and type not in ['lattice-cap','lattice-float']: + if label is not None and type not in ['lattice-cap', 'lattice-float']: raise ValueError("label keyword only supported for lattice precision") - return get_key_base(p, prec, type, print_mode, names, ram_name, print_pos, print_sep, print_alphabet, - print_max_terms, show_prec, check, - ['capped-rel', 'fixed-mod', 'capped-abs', 'floating-point', 'lattice-cap', 'lattice-float', 'relaxed'], - label=label) + return get_key_base(p, prec, type, print_mode, names, ram_name, print_pos, print_sep, print_alphabet, print_max_terms, show_prec, check, ['capped-rel', 'fixed-mod', 'capped-abs', 'floating-point', 'lattice-cap', 'lattice-float', 'relaxed'], label=label) def create_object(self, version, key): r""" @@ -1997,8 +1968,7 @@ def create_object(self, version, key): sage: Zp.create_object((3,4,2),(5, 41, 'capped-rel', 'series', '5', True, '|', (), -1)) 5-adic Ring with capped relative precision 41 """ - if (version[0] < 3 or (len(version) > 1 and version[0] == 3 and version[1] < 2) or - (len(version) > 2 and version[0] == 3 and version[1] == 2 and version[2] < 3)): + if version[0] < 3 or (len(version) > 1 and version[0] == 3 and version[1] < 2) or (len(version) > 2 and version[0] == 3 and version[1] == 2 and version[2] < 3): p, prec, type, print_mode, name = key print_pos, print_sep, print_alphabet, print_max_terms = None, None, None, None elif version[0] < 8: @@ -2007,12 +1977,10 @@ def create_object(self, version, key): label = None else: p, prec, type, print_mode, name, print_pos, print_sep, print_alphabet, print_max_terms, show_prec, label = key - if (version[0] < 4 or (len(version) > 1 and version[0] == 4 and version[1] < 5) or - (len(version) > 2 and version[0] == 4 and version[1] == 5 and version[2] < 3)): + if version[0] < 4 or (len(version) > 1 and version[0] == 4 and version[1] < 5) or (len(version) > 2 and version[0] == 4 and version[1] == 5 and version[2] < 3): # keys changed in order to reduce irrelevant duplications: e.g. two Zps with print_mode 'series' # that are identical except for different 'print_alphabet' now return the same object. - key = get_key_base(p, prec, type, print_mode, name, None, print_pos, print_sep, print_alphabet, - print_max_terms, None, False, ['capped-rel', 'fixed-mod', 'capped-abs', 'lattice-cap', 'lattice-float', 'relaxed']) + key = get_key_base(p, prec, type, print_mode, name, None, print_pos, print_sep, print_alphabet, print_max_terms, None, False, ['capped-rel', 'fixed-mod', 'capped-abs', 'lattice-cap', 'lattice-float', 'relaxed']) try: obj = self._cache[version, key]() if obj is not None: @@ -2021,24 +1989,18 @@ def create_object(self, version, key): pass p, prec, type, print_mode, name, print_pos, print_sep, print_alphabet, print_max_terms, show_prec, label = key if type == 'capped-rel': - return pAdicRingCappedRelative(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name) + return pAdicRingCappedRelative(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name) if type == 'fixed-mod': - return pAdicRingFixedMod(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name) + return pAdicRingFixedMod(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name) if type == 'capped-abs': - return pAdicRingCappedAbsolute(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name) + return pAdicRingCappedAbsolute(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name) if type == 'floating-point': - return pAdicRingFloatingPoint(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name) + return pAdicRingFloatingPoint(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name) if type == 'relaxed': - return pAdicRingRelaxed(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name) + return pAdicRingRelaxed(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name) if type[:8] == 'lattice-': subtype = type[8:] - return pAdicRingLattice(p, prec, subtype, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name, label) + return pAdicRingLattice(p, prec, subtype, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name, label) raise ValueError("unexpected type") @@ -2049,10 +2011,8 @@ def create_object(self, version, key): # Zq -- unramified extensions ###################################################### -def Zq(q, prec=None, type='capped-rel', modulus=None, names=None, - print_mode=None, ram_name=None, res_name=None, print_pos=None, - print_sep=None, print_max_ram_terms=None, - print_max_unram_terms=None, print_max_terse_terms=None, show_prec=None, check=True, implementation='FLINT'): + +def Zq(q, prec=None, type='capped-rel', modulus=None, names=None, print_mode=None, ram_name=None, res_name=None, print_pos=None, print_sep=None, print_max_ram_terms=None, print_max_unram_terms=None, print_max_terse_terms=None, show_prec=None, check=True, implementation='FLINT'): r""" Given a prime power `q = p^n`, return the unique unramified extension of `\ZZ_p` of degree `n`. @@ -2568,7 +2528,7 @@ def Zq(q, prec=None, type='capped-rel', modulus=None, names=None, F = [(Integer(q[0][0]), Integer(q[0][1]))] if not F[0][0].is_prime() or F[0][1] <= 0: raise ValueError("q must be a prime power") - q = F[0][0]**F[0][1] + q = F[0][0] ** F[0][1] else: q = Integer(q) F = q.factor() @@ -2579,8 +2539,8 @@ def Zq(q, prec=None, type='capped-rel', modulus=None, names=None, if isinstance(names, (list, tuple)): names = names[0] from sage.structure.element import Expression - if not (modulus is None or isinstance(modulus, (Polynomial, - Expression))): + + if not (modulus is None or isinstance(modulus, (Polynomial, Expression))): raise TypeError("modulus must be a polynomial") if names is not None and not isinstance(names, str): names = str(names) @@ -2591,10 +2551,8 @@ def Zq(q, prec=None, type='capped-rel', modulus=None, names=None, raise ValueError("q must be a prime power") else: F = q - q = F[0][0]**F[0][1] - base = Zp(p=F[0][0], prec=prec, type=type, print_mode=print_mode, names=ram_name, - print_pos=print_pos, print_sep=print_sep, print_max_terms=print_max_ram_terms, - show_prec=show_prec, check=False) + q = F[0][0] ** F[0][1] + base = Zp(p=F[0][0], prec=prec, type=type, print_mode=print_mode, names=ram_name, print_pos=print_pos, print_sep=print_sep, print_max_terms=print_max_ram_terms, show_prec=show_prec, check=False) if F[0][1] == 1: return base if names is None: @@ -2603,15 +2561,12 @@ def Zq(q, prec=None, type='capped-rel', modulus=None, names=None, res_name = names + '0' if modulus is None: from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF + if ram_name is None: ram_name = str(F[0][0]) modulus = GF(q, res_name).modulus().change_ring(ZZ) - return ExtensionFactory(base=base, modulus=modulus, prec=prec, print_mode=print_mode, - names=names, res_name=res_name, ram_name=ram_name, print_pos=print_pos, - print_sep=print_sep, print_max_ram_terms=print_max_ram_terms, - print_max_unram_terms=print_max_unram_terms, - print_max_terse_terms=print_max_terse_terms, show_prec=show_prec, check=check, - unram=True, implementation=implementation) + return ExtensionFactory(base=base, modulus=modulus, prec=prec, print_mode=print_mode, names=names, res_name=res_name, ram_name=ram_name, print_pos=print_pos, print_sep=print_sep, print_max_ram_terms=print_max_ram_terms, print_max_unram_terms=print_max_unram_terms, print_max_terse_terms=print_max_terse_terms, show_prec=show_prec, check=check, unram=True, implementation=implementation) + ###################################################### # Short constructor names for different types @@ -3243,6 +3198,7 @@ def ZpER(p, prec=None, halt=None, secure=False, *args, **kwds): # ####################################################################################################### + class pAdicExtension_class(UniqueFactory): r""" A class for creating extensions of `p`-adic rings and fields. @@ -3256,12 +3212,8 @@ class pAdicExtension_class(UniqueFactory): sage: W.precision_cap() 12 """ - def create_key_and_extra_args(self, base, modulus, prec=None, print_mode=None, - names=None, var_name=None, res_name=None, - unram_name=None, ram_name=None, print_pos=None, - print_sep=None, print_alphabet=None, print_max_ram_terms=None, - print_max_unram_terms=None, print_max_terse_terms=None, - show_prec=None, check=True, unram=False, implementation='FLINT'): + + def create_key_and_extra_args(self, base, modulus, prec=None, print_mode=None, names=None, var_name=None, res_name=None, unram_name=None, ram_name=None, print_pos=None, print_sep=None, print_alphabet=None, print_max_ram_terms=None, print_max_unram_terms=None, print_max_terse_terms=None, show_prec=None, check=True, unram=False, implementation='FLINT'): r""" Create a key from input parameters for :class:`pAdicExtension`. @@ -3320,6 +3272,7 @@ def create_key_and_extra_args(self, base, modulus, prec=None, print_mode=None, print_max_terse_terms = base._printer._max_terse_terms() show_prec = _canonicalize_show_prec(base._prec_type(), print_mode, show_prec) from sage.structure.element import Expression + if check: if isinstance(modulus, Expression): if len(modulus.variables()) != 1: @@ -3389,7 +3342,7 @@ def create_key_and_extra_args(self, base, modulus, prec=None, print_mode=None, prec = min([c.precision_absolute() for c in approx_modulus.list() if not c._is_exact_zero()] + [base.precision_cap()]) * e elif prec > base.precision_cap() * e: raise ValueError("Precision cannot be larger than that of base ring; you may want to call the change method on the base ring.") - approx_modulus = truncate_to_prec(exact_modulus, base, (prec/e).ceil() + 1) + approx_modulus = truncate_to_prec(exact_modulus, base, (prec / e).ceil() + 1) else: if unram_name is None: unram_name = names + '_u' @@ -3400,10 +3353,8 @@ def create_key_and_extra_args(self, base, modulus, prec=None, print_mode=None, names = (names, res_name, unram_name, ram_name) polytype = 'p' if polytype == 'e': - implementation = "NTL" # for testing - FLINT ramified extensions not implemented yet - key = (polytype, base, exact_modulus, names, prec, print_mode, print_pos, - print_sep, tuple(print_alphabet), print_max_ram_terms, print_max_unram_terms, - print_max_terse_terms, show_prec, implementation) + implementation = "NTL" # for testing - FLINT ramified extensions not implemented yet + key = (polytype, base, exact_modulus, names, prec, print_mode, print_pos, print_sep, tuple(print_alphabet), print_max_ram_terms, print_max_unram_terms, print_max_terse_terms, show_prec, implementation) return key, {'approx_modulus': approx_modulus} def create_object(self, version, key, approx_modulus=None, shift_seed=None): @@ -3424,21 +3375,19 @@ def create_object(self, version, key, approx_modulus=None, shift_seed=None): key = list(key) key.append('NTL') if version[0] < 8: - (polytype, base, premodulus, approx_modulus, names, prec, halt, print_mode, print_pos, print_sep, - print_alphabet, print_max_ram_terms, print_max_unram_terms, print_max_terse_terms, implementation) = key + (polytype, base, premodulus, approx_modulus, names, prec, halt, print_mode, print_pos, print_sep, print_alphabet, print_max_ram_terms, print_max_unram_terms, print_max_terse_terms, implementation) = key from sage.structure.element import Expression + if isinstance(premodulus, Expression): exact_modulus = premodulus.polynomial(base.exact_field()) elif isinstance(premodulus, Polynomial): exact_modulus = premodulus.change_ring(base.exact_field()) show_prec = None else: - (polytype, base, exact_modulus, names, prec, print_mode, print_pos, - print_sep, print_alphabet, print_max_ram_terms, print_max_unram_terms, - print_max_terse_terms, show_prec, implementation) = key + (polytype, base, exact_modulus, names, prec, print_mode, print_pos, print_sep, print_alphabet, print_max_ram_terms, print_max_unram_terms, print_max_terse_terms, show_prec, implementation) = key if polytype in ('e', 're'): unif = exact_modulus.base_ring()(base.uniformizer()) - shift_seed = (-exact_modulus[:exact_modulus.degree()] / unif).change_ring(base) + shift_seed = (-exact_modulus[: exact_modulus.degree()] / unif).change_ring(base) if not krasner_check(exact_modulus, prec): raise ValueError("polynomial does not determine a unique extension. Please specify more precision or use parameter check=False.") @@ -3447,10 +3396,7 @@ def create_object(self, version, key, approx_modulus=None, shift_seed=None): if polytype == 'p': raise NotImplementedError("Extensions by general polynomials not yet supported. Please use an unramified or Eisenstein polynomial.") T = ext_table[polytype, type(base.ground_ring_of_tower()).__base__] - return T(exact_modulus, approx_modulus, prec, - {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'max_ram_terms': print_max_ram_terms, 'max_unram_terms': print_max_unram_terms, 'max_terse_terms': print_max_terse_terms, 'show_prec': show_prec}, - shift_seed, names, implementation) + return T(exact_modulus, approx_modulus, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, 'max_ram_terms': print_max_ram_terms, 'max_unram_terms': print_max_unram_terms, 'max_terse_terms': print_max_terse_terms, 'show_prec': show_prec}, shift_seed, names, implementation) ExtensionFactory = pAdicExtension = pAdicExtension_class("pAdicExtension") @@ -3460,6 +3406,7 @@ def create_object(self, version, key, approx_modulus=None, shift_seed=None): # Helper functions for the Extension Factory ###################################################### + def split(poly, prec): r""" Given a polynomial ``poly`` and a desired precision ``prec``, computes @@ -3510,7 +3457,7 @@ def truncate_to_prec(poly, R, absprec): sage: truncate_to_prec(f, R, 5) (1 + O(5^5))*x^4 + (3 + O(5^5))*x^3 + O(5^5)*x^2 + O(5^5)*x + O(5^4) """ - return R[poly.variable_name()]([R(a, absprec=absprec) for a in poly.list()]) # Is this quite right? We don't want flat necessarily... + return R[poly.variable_name()]([R(a, absprec=absprec) for a in poly.list()]) # Is this quite right? We don't want flat necessarily... def krasner_check(poly, prec): @@ -3555,7 +3502,7 @@ def is_eisenstein(poly) -> bool: """ if poly[0].valuation() != 1: return False - return not any(c.valuation() < 1 for c in poly.list()[1:poly.degree()]) + return not any(c.valuation() < 1 for c in poly.list()[1 : poly.degree()]) def is_unramified(poly) -> bool: @@ -3579,7 +3526,7 @@ def is_unramified(poly) -> bool: """ if poly[0].valuation() > 0: return False - if any(c.valuation() < 0 for c in poly.list()[1:poly.degree()]): + if any(c.valuation() < 0 for c in poly.list()[1 : poly.degree()]): return False F = poly.parent().change_ring(poly.base_ring().residue_class_field())(poly).factor() return len(F) == 1 and F[0][1] == 1 diff --git a/src/sage/rings/padics/generic_nodes.py b/src/sage/rings/padics/generic_nodes.py index 7fa676af3e9..3f221e183ce 100644 --- a/src/sage/rings/padics/generic_nodes.py +++ b/src/sage/rings/padics/generic_nodes.py @@ -19,7 +19,7 @@ # the License, or (at your option) any later version. # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.rings.padics.local_generic import LocalGeneric from sage.rings.padics.padic_generic import pAdicGeneric @@ -216,19 +216,18 @@ def _test_distributivity(self, **options): tester = self._tester(**options) S = tester.some_elements() from sage.misc.misc import some_tuples - for x,y,z in some_tuples(S, 3, tester._max_runs): + + for x, y, z in some_tuples(S, 3, tester._max_runs): yz_prec = min(y.precision_absolute(), z.precision_absolute()) yz_val = (y + z).valuation() try: - prec = min(x.valuation() + yz_val + min(x.precision_relative(), yz_prec - yz_val), - x.valuation() + y.valuation() + (x * y).precision_relative(), - x.valuation() + z.valuation() + (x * z).precision_relative()) + prec = min(x.valuation() + yz_val + min(x.precision_relative(), yz_prec - yz_val), x.valuation() + y.valuation() + (x * y).precision_relative(), x.valuation() + z.valuation() + (x * z).precision_relative()) except SignError: pass else: if prec > -infinity: # only check left distributivity, since multiplication commutative - tester.assertTrue((x * (y + z)).is_equal_to((x * y) + (x * z),prec)) + tester.assertTrue((x * (y + z)).is_equal_to((x * y) + (x * z), prec)) def _test_additive_associativity(self, **options): r""" @@ -257,6 +256,7 @@ def _test_additive_associativity(self, **options): tester = self._tester(**options) S = tester.some_elements() from sage.misc.misc import some_tuples + for x, y, z in some_tuples(S, 3, tester._max_runs): tester.assertTrue(((x + y) + z).is_equal_to(x + (y + z), min(x.precision_absolute(), y.precision_absolute(), z.precision_absolute()))) @@ -314,6 +314,7 @@ class pAdicLatticeGeneric(pAdicGeneric): sage: R._prec_type() 'lattice-float' """ + def __init__(self, p, prec, print_mode, names, label=None, category=None): """ Initialization. @@ -333,6 +334,7 @@ def __init__(self, p, prec, print_mode, names, label=None, category=None): 'float' """ from sage.rings.padics.lattice_precision import pRational + self._approx_zero = pRational(p, 0) self._approx_one = pRational(p, 1) self._approx_minusone = pRational(p, -1) @@ -675,10 +677,10 @@ def convert_multiple(self, *elts): elt_other.append(x) # We create the elements - ans = len(elts)*[None] + ans = len(elts) * [None] selfprec = self._precision # First the elements with precision lattice - for (prec, L) in elt_by_prec.items(): + for prec, L in elt_by_prec.items(): if prec is selfprec: # Here, we use the _copy method in order # to be sharp on precision @@ -725,6 +727,7 @@ class pAdicRelaxedGeneric(pAdicGeneric): sage: R._prec_type() # needs sage.libs.flint 'relaxed' """ + def _get_element_class(self, name=None): r""" Return the class handling an element of type ``name``. @@ -1003,11 +1006,11 @@ def some_elements(self, unbounded=False): p = self(self.prime()) a = self.gen() one = self.one() - L = [self.zero(), one, p, a, (one+p+p).inverse_of_unit(), p-p**2] + L = [self.zero(), one, p, a, (one + p + p).inverse_of_unit(), p - p**2] if self.is_field(): - L.extend([~(p-p-a),p**(-20)]) + L.extend([~(p - p - a), p ** (-20)]) if not unbounded: - L = [ x.at_precision_absolute() for x in L ] + L = [x.at_precision_absolute() for x in L] return L def unknown(self, start_val=0, digits=None): @@ -1175,7 +1178,7 @@ def teichmuller_system(self): ...66666666666666666666] """ R = self.residue_class_field() - return [ self.teichmuller(ZZ(i)) for i in R if i != 0 ] + return [self.teichmuller(ZZ(i)) for i in R if i != 0] class pAdicRingGeneric(pAdicGeneric, sage.rings.abc.pAdicRing): @@ -1263,13 +1266,14 @@ def _xgcd_univariate_polynomial(self, f, g): ((3 + O(3^2))*x + 1 + O(3), 1 + O(3), 0) """ from sage.misc.stopgap import stopgap + stopgap("Extended gcd computations over p-adic fields are performed using the standard Euclidean algorithm which might produce mathematically incorrect results in some cases.", 13439) base_ring = f.base_ring() fracfield = base_ring.fraction_field() f_field = f.change_ring(fracfield) g_field = g.change_ring(fracfield) - xgcd = fracfield._xgcd_univariate_polynomial(f_field,g_field) + xgcd = fracfield._xgcd_univariate_polynomial(f_field, g_field) lcm = base_ring(1) for f in xgcd: for i in f: @@ -1314,34 +1318,34 @@ def is_field(self, proof=True): """ return True - #def class_field(self, group=None, map=None, generators=None): + # def class_field(self, group=None, map=None, generators=None): # raise NotImplementedError - #def composite(self, subfield1, subfield2): + # def composite(self, subfield1, subfield2): # raise NotImplementedError - #def norm_equation(self): + # def norm_equation(self): # raise NotImplementedError - #def norm_group(self): + # def norm_group(self): # raise NotImplementedError - #def norm_group_discriminant(self, group=None, map=None, generators=None): + # def norm_group_discriminant(self, group=None, map=None, generators=None): # raise NotImplementedError - #def number_of_extensions(self, degree, discriminant=None, e=None, f=None): + # def number_of_extensions(self, degree, discriminant=None, e=None, f=None): # raise NotImplementedError - #def list_of_extensions(self, degree, discriminant=None, e=None, f=None): + # def list_of_extensions(self, degree, discriminant=None, e=None, f=None): # raise NotImplementedError - #def subfield(self, list): + # def subfield(self, list): # raise NotImplementedError - #def subfield_lattice(self): + # def subfield_lattice(self): # raise NotImplementedError - #def subfields_of_degree(self, n): + # def subfields_of_degree(self, n): # raise NotImplementedError @@ -1409,7 +1413,8 @@ def construction(self, forbid_frac_field=False): (Completion[5, prec=(20, 40, True)], Integer Ring) """ from sage.categories.pushout import CompletionFunctor - extras = {'print_mode':self._printer.dict(), 'type':self._prec_type(), 'names':self._names} + + extras = {'print_mode': self._printer.dict(), 'type': self._prec_type(), 'names': self._names} if hasattr(self, '_label'): extras['label'] = self._label if self._prec_type() == "relaxed": @@ -1438,24 +1443,24 @@ def random_element(self, algorithm='default'): sage: ZpFM(5,6).random_element().parent() is ZpFM(5,6) True """ - if (algorithm == 'default'): + if algorithm == 'default': if self.is_capped_relative(): i = 0 a_i = ZZ.random_element(self.prime()) while a_i.is_zero(): i += 1 a_i = ZZ.random_element(self.prime()) - return self((self.prime()**i)*(a_i + self.prime()*ZZ.random_element(self.prime_pow.pow_Integer_Integer(self.precision_cap()-1)))) + return self((self.prime() ** i) * (a_i + self.prime() * ZZ.random_element(self.prime_pow.pow_Integer_Integer(self.precision_cap() - 1)))) return self(ZZ.random_element(self.prime_pow.pow_Integer_Integer(self.precision_cap()))) raise NotImplementedError("Don't know %s algorithm" % algorithm) - #def unit_group(self): + # def unit_group(self): # raise NotImplementedError - #def unit_group_gens(self): + # def unit_group_gens(self): # raise NotImplementedError - #def principal_unit_group(self): + # def principal_unit_group(self): # raise NotImplementedError @@ -1478,7 +1483,7 @@ def composite(self, subfield1, subfield2): sage: K = Qp(17); K.composite(K, K) is K True """ - #should be overridden for extension fields + # should be overridden for extension fields if (subfield1 is self) and (subfield2 is self): return self raise ValueError("Arguments must be subfields of self.") @@ -1581,8 +1586,9 @@ def construction(self, forbid_frac_field=False): (Completion[5, prec=(20, 40, True)], Rational Field) """ from sage.categories.pushout import FractionField, CompletionFunctor + if forbid_frac_field: - extras = {'print_mode':self._printer.dict(), 'type':self._prec_type(), 'names':self._names} + extras = {'print_mode': self._printer.dict(), 'type': self._prec_type(), 'names': self._names} if hasattr(self, '_label'): extras['label'] = self._label if self._prec_type() == "relaxed": diff --git a/src/sage/rings/padics/lattice_precision.py b/src/sage/rings/padics/lattice_precision.py index f0e557786c6..c160956c62e 100644 --- a/src/sage/rings/padics/lattice_precision.py +++ b/src/sage/rings/padics/lattice_precision.py @@ -107,6 +107,7 @@ class pRational: sage: z.valuation() 4 """ + def __init__(self, p, x, exponent=0, valuation=None): r""" Construct the element ``x * p^exponent``. @@ -168,21 +169,21 @@ def reduce(self, prec): exp = self.exponent if x.parent() is ZZ: if prec > exp: - x = x % (self.p ** (prec-exp)) + x = x % (self.p ** (prec - exp)) else: x = 0 elif x.parent() is QQ: num = x.numerator() denom = x.denominator() valdenom = denom.valuation(self.p) - denom //= self.p ** valdenom + denom //= self.p**valdenom exp -= valdenom if prec > exp: modulo = self.p ** (prec - exp) # probably we should use Newton iteration instead # (but it is actually slower for now - Python implementation) _, inv, _ = denom.xgcd(modulo) - x = (num*inv) % modulo + x = (num * inv) % modulo else: x = 0 if self.x == 0: @@ -215,7 +216,7 @@ def reduce_relative(self, prec): v = self.valuation() if v is Infinity: return self - return self.reduce(prec+v) + return self.reduce(prec + v) def normalize(self): r""" @@ -235,7 +236,7 @@ def normalize(self): else: val = self.valuation() exp = self.exponent - self.x /= self.p ** (val-exp) + self.x /= self.p ** (val - exp) if self.x in ZZ: self.x = ZZ(self.x) self.exponent = val @@ -324,8 +325,8 @@ def __add__(self, other): else: val = None if sexp < oexp: - return self.__class__(p, self.x + other.x * p**(oexp-sexp), sexp, valuation=val) - return self.__class__(p, self.x * p**(sexp-oexp) + other.x, oexp, valuation=val) + return self.__class__(p, self.x + other.x * p ** (oexp - sexp), sexp, valuation=val) + return self.__class__(p, self.x * p ** (sexp - oexp) + other.x, oexp, valuation=val) def __sub__(self, other): r""" @@ -428,15 +429,12 @@ def _quo_rem(self, other): sval = self.exponent diff = sval - oval if sx == 0: - return (self.__class__(self.p, 0, 0, valuation=Infinity), - self.__class__(self.p, 0, 0, valuation=Infinity)) + return (self.__class__(self.p, 0, 0, valuation=Infinity), self.__class__(self.p, 0, 0, valuation=Infinity)) if sval >= oval: - return (self.__class__(self.p, sx / ox, diff, valuation=diff), - self.__class__(self.p, 0, 0, valuation=Infinity)) - pd = self.p**(-diff) + return (self.__class__(self.p, sx / ox, diff, valuation=diff), self.__class__(self.p, 0, 0, valuation=Infinity)) + pd = self.p ** (-diff) sred = sx % pd - return (self.__class__(self.p, (sx - sred)/(pd*ox), 0), - self.__class__(self.p, sred, sval, valuation=sval)) + return (self.__class__(self.p, (sx - sred) / (pd * ox), 0), self.__class__(self.p, sred, sval, valuation=sval)) def __lshift__(self, n): r""" @@ -495,7 +493,7 @@ def unit_part(self): raise ValueError("the unit part of zero is not defined") p = self.p val = self.valuation() - x = self.x / (p ** (val-self.exponent)) + x = self.x / (p ** (val - self.exponent)) return self.__class__(p, x, 0, valuation=0) def xgcd(self, other): @@ -527,10 +525,10 @@ def xgcd(self, other): oexp = other.exponent if sexp < oexp: a = ZZ(self.x) - b = ZZ(other.x * (p ** (oexp-sexp))) + b = ZZ(other.x * (p ** (oexp - sexp))) exp = sexp else: - a = ZZ(self.x * (p ** (sexp-oexp))) + a = ZZ(self.x * (p ** (sexp - oexp))) b = ZZ(other.x) exp = oexp d, u, v = a.xgcd(b) @@ -555,7 +553,7 @@ def value(self): sage: x.value() 15802368 """ - return (self.p ** self.exponent) * self.x + return (self.p**self.exponent) * self.x def list(self, prec): r""" @@ -591,7 +589,7 @@ def list(self, prec): if val is Infinity: return [] p = self.p - x = ZZ(self.x * p**(self.exponent - val)) + x = ZZ(self.x * p ** (self.exponent - val)) l = [] for _ in range(val, prec): x, digit = x.quo_rem(p) @@ -622,6 +620,7 @@ class DifferentialPrecisionGeneric(SageObject): sage: R.precision() Precision lattice on 0 objects (label: init) """ + def __init__(self, p, label): r""" TESTS:: @@ -1099,9 +1098,9 @@ def tracked_elements(self, values=True, dead=True): WeakProxy#..., WeakProxy#...] """ - ret = [ ref for ref in self._elements if dead or ref() is not None] + ret = [ref for ref in self._elements if dead or ref() is not None] if values: - ret = [ ref() for ref in ret ] + ret = [ref() for ref in ret] return ret # History @@ -1133,8 +1132,8 @@ def history_enable(self): :meth:`history`, :meth:`history_disable`, :meth:`history_clear` """ if self._history is None: - self._history_init = ( len(self._elements), list(self._marked_for_deletion) ) - self._history = [ ] + self._history_init = (len(self._elements), list(self._marked_for_deletion)) + self._history = [] def history_disable(self): r""" @@ -1209,8 +1208,8 @@ def history_clear(self): """ if self._history is None: raise ValueError("History is not tracked") - self._history_init = ( len(self._elements), list(self._marked_for_deletion) ) - self._history = [ ] + self._history_init = (len(self._elements), list(self._marked_for_deletion)) + self._history = [] def _format_history(self, time, status, timings): r""" @@ -1431,13 +1430,13 @@ def history(self, compact=True, separate_reduce=False, timings=True, output_type # r : partial reduction # R : full Hermite reduction (n, mark) = self._history_init - status = n*['o'] + status = n * ['o'] for index in mark: status[index] = '~' - hist = [ self._format_history(-1, status, timings) ] + hist = [self._format_history(-1, status, timings)] oldevent = '' total_time = 0 - for (event, index, tme) in self._history: + for event, index, tme in self._history: if event == 'partial reduce' or event == 'full reduce': if separate_reduce: if status: @@ -1517,8 +1516,8 @@ def timings(self, action=None): """ if self._history is None: raise ValueError("History is not tracked") - tme_by_event = { 'add': 0, 'del': 0, 'mark': 0, 'partial reduce': 0, 'full reduce': 0 } - for (event, _, tme) in self._history: + tme_by_event = {'add': 0, 'del': 0, 'mark': 0, 'partial reduce': 0, 'full reduce': 0} + for event, _, tme in self._history: tme_by_event[event] += tme if action is None: return tme_by_event @@ -1553,6 +1552,7 @@ class PrecisionLattice(UniqueRepresentation, DifferentialPrecisionGeneric): sage: R.precision() Precision lattice on 0 objects (label: init) """ + def __init__(self, p, label): r""" TESTS:: @@ -1564,7 +1564,7 @@ def __init__(self, p, label): """ DifferentialPrecisionGeneric.__init__(self, p, label) self._repr_type = "Precision lattice" - self._capped = { } + self._capped = {} # We need to copy this method. # Indeed otherwise it is inherited from UniqueRepresentation @@ -1656,21 +1656,21 @@ def reduce(self, index=0, partial=False): sage: R.precision().del_elements() # indirect doctest """ n = len(self._elements) - if index >= n-1: + if index >= n - 1: return if partial: # Partial reduction # Cost: O(m^2) with m = n-index tme = walltime() - diffval = (n-index) * [0] - for j in range(n-1, index, -1): + diffval = (n - index) * [0] + for j in range(n - 1, index, -1): col = self._matrix[self._elements[j]] - prec = col[j].valuation() - diffval[j-index] + prec = col[j].valuation() - diffval[j - index] for i in range(index, j): col[i] = col[i].reduce(prec) col[i].normalize() dval = col[i].valuation() - prec - diffval[i-index] = min(dval, diffval[i-index]) + diffval[i - index] = min(dval, diffval[i - index]) # We update history if self._history is not None: self._history.append(('partial reduce', index, walltime(tme))) @@ -1678,7 +1678,7 @@ def reduce(self, index=0, partial=False): # Full Hermite reduction # Cost: O(m^3) with m = n-index tme = walltime() - for j in range(index+1, n): + for j in range(index + 1, n): # In what follows, we assume that col[j] is a power of p col = self._matrix[self._elements[j]] valpivot = col[j].valuation() @@ -1689,9 +1689,9 @@ def reduce(self, index=0, partial=False): continue col[i] = reduced col[i].normalize() - for j2 in range(j+1, n): + for j2 in range(j + 1, n): col2 = self._matrix[self._elements[j2]] - col2[i] -= scalar*col2[i] + col2[i] -= scalar * col2[i] col2[i].normalize() # We update history if self._history is not None: @@ -1854,18 +1854,18 @@ def del_elements(self, threshold=None): for i in range(index, n): ref = self._elements[i] col = self._matrix[ref] - if col[i].valuation() < col[i+1].valuation(): + if col[i].valuation() < col[i + 1].valuation(): self._capped[ref], capped = capped, capped or self._capped[ref] else: capped = capped or self._capped[ref] - d, u, v = col[i].xgcd(col[i+1]) - up, vp = col[i+1]/d, col[i]/d + d, u, v = col[i].xgcd(col[i + 1]) + up, vp = col[i + 1] / d, col[i] / d col[i] = d - del col[i+1] - for j in range(i+1, n): + del col[i + 1] + for j in range(i + 1, n): col = self._matrix[self._elements[j]] - col[i], col[i+1] = u*col[i] + v*col[i+1], up*col[i] - vp*col[i+1] + col[i], col[i + 1] = u * col[i] + v * col[i + 1], up * col[i] - vp * col[i + 1] # We update history if self._history is not None: @@ -1934,20 +1934,20 @@ def _lift_to_precision(self, x, prec): vals = sorted(rows_by_val) vals.append(prec) - for t in range(len(vals)-1): - v, w = vals[t], vals[t+1] + for t in range(len(vals) - 1): + v, w = vals[t], vals[t + 1] rows = rows_by_val[v] piv = max(rows) for i in rows: if i == piv: continue # We clear the entry on the i-th row - scalar = (col[i]/col[piv]).reduce(prec-v) - for j in range(piv,n): + scalar = (col[i] / col[piv]).reduce(prec - v) + for j in range(piv, n): col_cur = self._matrix[self._elements[j]] - col_cur[i] -= scalar*col_cur[piv] + col_cur[i] -= scalar * col_cur[piv] # We rescale the piv-th row - for j in range(piv,n): + for j in range(piv, n): col_cur = self._matrix[self._elements[j]] col_cur[piv] <<= w - v # Now the entry on the piv-th row has valuation w @@ -2117,12 +2117,13 @@ def precision_lattice(self, elements=None): val = 0 for ref in elements: col = self._matrix[ref] - row = [ x.value() for x in col ] - valcol = min([ x.valuation() for x in col ]) + row = [x.value() for x in col] + valcol = min([x.valuation() for x in col]) val = min(valcol, val) - row += (n-len(row)) * [ZZ(0)] + row += (n - len(row)) * [ZZ(0)] rows.append(row) from sage.matrix.constructor import matrix + M = matrix(rows).transpose() if val < 0: M *= self._p ** (-val) @@ -2131,7 +2132,7 @@ def precision_lattice(self, elements=None): n = len(elements) M = M.submatrix(0, 0, n, n) if val < 0: - M *= self._p ** val + M *= self._p**val return M @@ -2143,6 +2144,7 @@ class PrecisionModule(UniqueRepresentation, DifferentialPrecisionGeneric): The precision module (which is not necessarily a lattice) is stored as a matrix whose rows are generators. """ + def __init__(self, p, label, prec): r""" Initialize this precision module. @@ -2346,7 +2348,7 @@ def _new_element(self, x, dx, bigoh, dx_mode='linear_combination'): x_ref = pAdicLatticeElementWeakProxy(x, self._record_collected_element) col = n * [self._approx_zero] if dx_mode == 'linear_combination': - expected_vals = n * [ Infinity ] + expected_vals = n * [Infinity] for elt, scalar in dx: ref = pAdicLatticeElementWeakProxy(elt) if not isinstance(scalar, pRational): @@ -2429,7 +2431,7 @@ def del_elements(self, threshold=None): if index == 0: length_before = 0 else: - length_before = len(self._matrix[self._elements[index-1]]) + length_before = len(self._matrix[self._elements[index - 1]]) length = len(self._matrix[ref]) if length > length_before: self._marked_for_deletion.append(index) @@ -2439,8 +2441,7 @@ def del_elements(self, threshold=None): # if the column is not a pivot, we erase it without delay # (btw, is it a good idea?) del self._elements[index] - self._marked_for_deletion = [i if i < index else i - 1 - for i in self._marked_for_deletion] + self._marked_for_deletion = [i if i < index else i - 1 for i in self._marked_for_deletion] if self._history is not None: self._history.append(('del', index, walltime(tme))) del self._collected_references[:count] @@ -2487,23 +2488,23 @@ def del_elements(self, threshold=None): break # col is the column of index "end" # its size is (length + 1) - d, u, v = col[length-1].xgcd(col[length]) - up, vp = col[length]/d, col[length-1]/d - col[length-1] = d.reduce_relative(self._internal_prec) + d, u, v = col[length - 1].xgcd(col[length]) + up, vp = col[length] / d, col[length - 1] / d + col[length - 1] = d.reduce_relative(self._internal_prec) del col[length] start = end + 1 for j in range(start, n): col = self._matrix[self._elements[j]] - a1 = u*col[length-1] - a2 = v*col[length] + a1 = u * col[length - 1] + a2 = v * col[length] a = a1 + a2 - b1 = up*col[length-1] + b1 = up * col[length - 1] b2 = vp * col[length] b = b1 + b2 if a.valuation() > min(a1.valuation(), a2.valuation()) + self._zero_cap: - col[length-1] = self._approx_zero + col[length - 1] = self._approx_zero else: - col[length-1] = a.reduce_relative(self._internal_prec) + col[length - 1] = a.reduce_relative(self._internal_prec) if b.valuation() > min(b1.valuation(), b2.valuation()) + self._zero_cap: col[length] = self._approx_zero else: @@ -2574,19 +2575,19 @@ def _lift_to_precision(self, x, prec): vals = sorted(rows_by_val) vals.append(prec) - for t in range(len(vals)-1): - v, w = vals[t], vals[t+1] + for t in range(len(vals) - 1): + v, w = vals[t], vals[t + 1] rows = rows_by_val[v] piv = max(rows) for i in rows: if i == piv: continue # We clear the entry on the i-th row - scalar = (col[i]/col[piv]).reduce(prec-v) + scalar = (col[i] / col[piv]).reduce(prec - v) for j in range(n): col_cur = self._matrix[self._elements[j]] if len(col_cur) > piv: - col_cur[i] -= scalar*col_cur[piv] + col_cur[i] -= scalar * col_cur[piv] col_cur[i] = col_cur[i].reduce_relative(self._internal_prec) # We rescale the piv-th row # (if w is Infinity, we delete it) @@ -2652,7 +2653,7 @@ def _precision_absolute(self, x): col = self._matrix[ref] if len(col) == 0: return Infinity - return min( [ c.valuation() for c in col ] ) + return min([c.valuation() for c in col]) def precision_lattice(self, elements=None): r""" @@ -2706,16 +2707,17 @@ def precision_lattice(self, elements=None): else: elements = list_of_padics(elements) n = len(self._elements) - rows = [ ] + rows = [] val = 0 for ref in elements: col = self._matrix[ref] - row = [ x.value() for x in col ] - valcol = min([ x.valuation() for x in col ]) + row = [x.value() for x in col] + valcol = min([x.valuation() for x in col]) val = min(valcol, val) - row += (n-len(row)) * [ZZ(0)] + row += (n - len(row)) * [ZZ(0)] rows.append(row) from sage.matrix.constructor import matrix + M = matrix(rows).transpose() if val < 0: M *= self._p ** (-val) @@ -2726,11 +2728,11 @@ def precision_lattice(self, elements=None): raise PrecisionError("the differential is not surjective") for i in range(n): v = M[i, i].valuation(self._p) - M[i, i] = self._p ** v + M[i, i] = self._p**v M.echelonize() M = M.submatrix(0, 0, n, n) if val < 0: - M *= self._p ** val + M *= self._p**val return M @@ -2761,6 +2763,7 @@ class pAdicLatticeElementWeakProxy: sage: isinstance(proxy, pAdicLatticeElementWeakProxy) True """ + _next_id = 0 def __init__(self, element, callback=None): @@ -2780,6 +2783,7 @@ def __init__(self, element, callback=None): pAdicLatticeElementWeakProxy._next_id += 1 self._id = element._proxy_id from weakref import ref + proxy_callback = callback if callback is not None: proxy_callback = lambda _: callback(self) @@ -2865,8 +2869,9 @@ def list_of_padics(elements): WeakProxy#...] """ from sage.rings.padics.padic_lattice_element import pAdicLatticeElement + if isinstance(elements, pAdicLatticeElement): - return [ pAdicLatticeElementWeakProxy(elements) ] + return [pAdicLatticeElementWeakProxy(elements)] try: if elements.parent().is_sparse(): elements = elements.coefficients() @@ -2874,7 +2879,7 @@ def list_of_padics(elements): pass if not isinstance(elements, list): elements = list(elements) - ans = [ ] + ans = [] for x in elements: ans += list_of_padics(x) return ans diff --git a/src/sage/rings/padics/local_generic.py b/src/sage/rings/padics/local_generic.py index 228f9317d5a..44644837df0 100644 --- a/src/sage/rings/padics/local_generic.py +++ b/src/sage/rings/padics/local_generic.py @@ -74,8 +74,7 @@ def __init__(self, base, prec, names, element_class, category=None): category = category.Metric().Complete().Infinite() if default_category is not None: category = check_default_category(default_category, category) - Parent.__init__(self, base=base, names=(names,), - normalize=False, category=category) + Parent.__init__(self, base=base, names=(names,), normalize=False, category=category) def is_capped_relative(self) -> bool: r""" @@ -405,10 +404,13 @@ def change(self, **kwds): def get_unramified_modulus(q, res_name): from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF + return GF(q, res_name).modulus().change_ring(ZZ) + n = None q = None from .padic_base_generic import pAdicBaseGeneric + if 'q' in kwds and isinstance(self.base_ring(), pAdicBaseGeneric): q = kwds.pop('q') if not isinstance(q, Integer): @@ -427,6 +429,7 @@ def get_unramified_modulus(q, res_name): cur_mode = self._printer._print_mode() cur_show_prec = self._printer._show_prec() from .factory import _canonicalize_show_prec + if cur_show_prec == _canonicalize_show_prec(cur_type, cur_mode): kwds['show_prec'] = _canonicalize_show_prec(new_type, kwds['mode']) else: @@ -435,9 +438,9 @@ def get_unramified_modulus(q, res_name): curpstr = str(self.prime()) functor_dict = getattr(functor, "extras", getattr(functor, "kwds", None)) # If we are switching to 'digits', or changing p, need to ensure a large enough alphabet. - if 'alphabet' not in kwds and (kwds.get('mode') == 'digits' or - (functor_dict['print_mode'].get('mode') == 'digits' and p > getattr(functor, "p", p))): + if 'alphabet' not in kwds and (kwds.get('mode') == 'digits' or (functor_dict['print_mode'].get('mode') == 'digits' and p > getattr(functor, "p", p))): from .padic_printing import _printer_defaults + kwds['alphabet'] = _printer_defaults.alphabet()[:p] # For fraction fields of fixed-mod rings, we need to explicitly set show_prec = False if 'field' in kwds and 'type' not in kwds: @@ -500,6 +503,7 @@ def get_unramified_modulus(q, res_name): # Create an unramified extension base = functor(ring) from .factory import ExtensionFactory + modulus = modulus.change_ring(base) return ExtensionFactory(base=base, premodulus=modulus, names=names, res_name=res_name, unram=True, implementation=implementation) else: @@ -513,6 +517,7 @@ def get_unramified_modulus(q, res_name): kwds['prec'] = baseprec functor.precs = [prec] from sage.rings.padics.padic_base_generic import pAdicBaseGeneric + if 'names' in kwds: functor.names = [kwds.pop('names')] modulus = None @@ -647,8 +652,10 @@ def defining_polynomial(self, var='x', exact=False): Univariate Polynomial Ring in x over Integer Ring """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + if exact: from sage.rings.integer_ring import ZZ + return PolynomialRing(ZZ, var).gen() return PolynomialRing(self, var).gen() @@ -1010,11 +1017,11 @@ def maximal_unramified_subextension(self): """ return self.inertia_subring() -# def get_extension(self): -# r""" -# Return the trivial extension of self. -# """ -# raise NotImplementedError + # def get_extension(self): + # r""" + # Return the trivial extension of self. + # """ + # raise NotImplementedError def uniformiser(self): r""" @@ -1073,8 +1080,9 @@ def _test_add_bigoh(self, **options): for x in tester.some_elements(): tester.assertEqual(x.add_bigoh(x.precision_absolute()), x) from sage.rings.infinity import infinity + tester.assertEqual(x.add_bigoh(infinity), x) - tester.assertEqual(x.add_bigoh(x.precision_absolute()+1), x) + tester.assertEqual(x.add_bigoh(x.precision_absolute() + 1), x) y = x.add_bigoh(0) tester.assertIs(y.parent(), self) @@ -1084,7 +1092,7 @@ def _test_add_bigoh(self, **options): elif self.is_capped_relative() or self.is_lattice_prec(): tester.assertLessEqual(y.precision_absolute(), 0) elif self.is_fixed_mod() or self.is_floating_point(): - tester.assertGreaterEqual((x-y).valuation(), 0) + tester.assertGreaterEqual((x - y).valuation(), 0) # if absprec < 0, then the result is in the fraction field (see #13591) y = x.add_bigoh(-1) @@ -1094,7 +1102,7 @@ def _test_add_bigoh(self, **options): # make sure that we handle very large values correctly if self._prec_type() not in ['lattice-float', 'relaxed']: # no cap in these models - absprec = Integer(2)**1000 + absprec = Integer(2) ** 1000 tester.assertEqual(x.add_bigoh(absprec), x) def _test_residue(self, **options): @@ -1113,6 +1121,7 @@ def _test_residue(self, **options): errors = [] if x.precision_absolute() <= 0: from .precision_error import PrecisionError + errors.append(PrecisionError) if x.valuation() < 0: errors.append(ValueError) @@ -1124,7 +1133,7 @@ def _test_residue(self, **options): # residue() is in `Z/pZ` which is not identical to the residue field `F_p` tester.assertEqual(y.parent().cardinality(), self.residue_field().cardinality()) z = self(y) - tester.assertGreater((x-z).valuation(), 0) + tester.assertGreater((x - z).valuation(), 0) for x in self.residue_field().some_elements(): y = self(x) @@ -1179,12 +1188,12 @@ def _matrix_flatten_precision(self, M): for j in range(m): M[i, j] <<= s for j in range(m): - prec = min(M[i,j].precision_absolute() for i in range(n)) + prec = min(M[i, j].precision_absolute() for i in range(n)) if prec is Infinity or prec == cap: continue shift_cols[j] = s = cap - prec for i in range(n): - M[i,j] <<= s + M[i, j] <<= s return shift_rows, shift_cols def _matrix_smith_form(self, M, transformation, integral, exact): @@ -1298,6 +1307,7 @@ def _matrix_smith_form(self, M, transformation, integral, exact): from sage.rings.infinity import infinity from .precision_error import PrecisionError from copy import copy + n = M.nrows() m = M.ncols() if m > n: @@ -1325,8 +1335,8 @@ def _matrix_smith_form(self, M, transformation, integral, exact): else: raise NotImplementedError("Smith normal form over this subring") ## the difference between ball_prec and inexact_ring is just for lattice precision. - ball_prec = R._prec_type() in ['capped-rel','capped-abs'] - inexact_ring = R._prec_type() not in ['fixed-mod','floating-point'] + ball_prec = R._prec_type() in ['capped-rel', 'capped-abs'] + inexact_ring = R._prec_type() not in ['fixed-mod', 'floating-point'] if not integral: shift_rows, shift_cols = self._matrix_flatten_precision(S) @@ -1334,14 +1344,15 @@ def _matrix_smith_form(self, M, transformation, integral, exact): precS = min(x.precision_absolute() for x in S.list()) if transformation: from sage.matrix.special import identity_matrix - left = identity_matrix(R,n) - right = identity_matrix(R,m) - if ball_prec and precS is infinity: # capped-rel and M = 0 exactly + left = identity_matrix(R, n) + right = identity_matrix(R, m) + + if ball_prec and precS is infinity: # capped-rel and M = 0 exactly return (smith, left, right) if transformation else smith val = -infinity - for piv in range(m): # m <= n + for piv in range(m): # m <= n curval = infinity pivi = pivj = piv # allzero tracks whether every possible pivot is zero. @@ -1354,12 +1365,12 @@ def _matrix_smith_form(self, M, transformation, integral, exact): # deduce the exact smith form even with some elementary divisors zero: # if the bottom right block consists entirely of exact zeros. allexact = True - for i in range(piv,n): - for j in range(piv,m): - Sij = S[i,j] + for i in range(piv, n): + for j in range(piv, m): + Sij = S[i, j] v = Sij.valuation() allzero = allzero and Sij.is_zero() - if exact: # we only care in this case + if exact: # we only care in this case allexact = allexact and Sij.precision_absolute() is infinity if v < curval: pivi = i @@ -1375,7 +1386,7 @@ def _matrix_smith_form(self, M, transformation, integral, exact): if inexact_ring and not allzero and val >= precS: if ball_prec: raise PrecisionError("not enough precision to compute Smith normal form") - precS = min([ S[i,j].precision_absolute() for i in range(piv,n) for j in range(piv,m) ]) + precS = min([S[i, j].precision_absolute() for i in range(piv, n) for j in range(piv, m)]) if val >= precS: raise PrecisionError("not enough precision to compute Smith normal form") @@ -1383,9 +1394,9 @@ def _matrix_smith_form(self, M, transformation, integral, exact): if exact: if allexact: # We need to finish checking allexact since we broke out of the loop early - for i in range(i,n): - for j in range(piv,m): - allexact = allexact and S[i,j].precision_absolute() is infinity + for i in range(i, n): + for j in range(piv, m): + allexact = allexact and S[i, j].precision_absolute() is infinity if not allexact: break else: @@ -1396,32 +1407,32 @@ def _matrix_smith_form(self, M, transformation, integral, exact): break # We swap the lowest valuation pivot into position - S.swap_rows(pivi,piv) - S.swap_columns(pivj,piv) + S.swap_rows(pivi, piv) + S.swap_columns(pivj, piv) if transformation: - left.swap_rows(pivi,piv) - right.swap_columns(pivj,piv) + left.swap_rows(pivi, piv) + right.swap_columns(pivj, piv) # ... and clear out this row and column. Note that we # will deal with precision later, thus the call to lift_to_precision - smith[piv,piv] = self(1) << val - inv = (S[piv,piv] >> val).inverse_of_unit() + smith[piv, piv] = self(1) << val + inv = (S[piv, piv] >> val).inverse_of_unit() if ball_prec: inv = inv.lift_to_precision() - for i in range(piv+1,n): - scalar = -inv * Z(S[i,piv] >> val) + for i in range(piv + 1, n): + scalar = -inv * Z(S[i, piv] >> val) if ball_prec: scalar = scalar.lift_to_precision() - S.add_multiple_of_row(i,piv,scalar,piv+1) + S.add_multiple_of_row(i, piv, scalar, piv + 1) if transformation: - left.add_multiple_of_row(i,piv,scalar) + left.add_multiple_of_row(i, piv, scalar) if transformation: - left.rescale_row(piv,inv) - for j in range(piv+1,m): - scalar = -inv * Z(S[piv,j] >> val) + left.rescale_row(piv, inv) + for j in range(piv + 1, m): + scalar = -inv * Z(S[piv, j] >> val) if ball_prec: scalar = scalar.lift_to_precision() - right.add_multiple_of_column(j,piv,scalar) + right.add_multiple_of_column(j, piv, scalar) else: # We use piv as an upper bound on a range below, and need to set it correctly # in the case that we didn't break out of the loop @@ -1432,32 +1443,32 @@ def _matrix_smith_form(self, M, transformation, integral, exact): # with valuation at least precS if ball_prec and exact and transformation: for j in range(n): - delta = min(left[i,j].valuation() - smith[i,i].valuation() for i in range(piv)) + delta = min(left[i, j].valuation() - smith[i, i].valuation() for i in range(piv)) if delta is not infinity: for i in range(n): - left[i,j] = left[i,j].add_bigoh(precS + delta) + left[i, j] = left[i, j].add_bigoh(precS + delta) ## Otherwise, we update the precision on smith if ball_prec and not exact: smith = smith.apply_map(lambda x: x.add_bigoh(precS)) ## We now have to adjust the elementary divisors (and precision) in the non-integral case if not integral: for i in range(piv): - v = smith[i,i].valuation() + v = smith[i, i].valuation() if transformation: for j in range(n): - left[i,j] >>= v + left[i, j] >>= v if exact: - smith[i,i] = self(1) + smith[i, i] = self(1) else: for j in range(m): - smith[i,j] >>= v + smith[i, j] >>= v if transformation: for i in range(n): for j in range(n): - left[i,j] <<= shift_rows[j] + left[i, j] <<= shift_rows[j] for i in range(m): for j in range(m): - right[i,j] <<= shift_cols[i] + right[i, j] <<= shift_cols[i] if transformation: return smith, left, right return smith @@ -1476,19 +1487,20 @@ def _test_matrix_smith(self, **options): from itertools import chain from sage.matrix.matrix_space import MatrixSpace from .precision_error import PrecisionError - matrices = chain(*[MatrixSpace(self, n, m).some_elements() for n in (1,3,7) for m in (1,4,7)]) + + matrices = chain(*[MatrixSpace(self, n, m).some_elements() for n in (1, 3, 7) for m in (1, 4, 7)]) for M in tester.some_elements(matrices): bases = [self] if self is not self.integer_ring(): bases.append(self.integer_ring()) for base in bases: try: - S,U,V = M.smith_form(integral=base) + S, U, V = M.smith_form(integral=base) except PrecisionError: continue - if self.is_exact() or self._prec_type() not in ['fixed-mod','floating-point']: - tester.assertEqual(U*M*V, S) + if self.is_exact() or self._prec_type() not in ['fixed-mod', 'floating-point']: + tester.assertEqual(U * M * V, S) tester.assertEqual(U.nrows(), U.ncols()) tester.assertEqual(U.base_ring(), base) @@ -1500,7 +1512,7 @@ def _test_matrix_smith(self, **options): if not d.is_zero(): tester.assertTrue(d.unit_part().is_one()) - for (d,dd) in zip(S.diagonal(), S.diagonal()[1:]): + for d, dd in zip(S.diagonal(), S.diagonal()[1:]): tester.assertTrue(d.divides(dd)) def _matrix_determinant(self, M): @@ -1577,10 +1589,10 @@ def _matrix_determinant(self, M): # For 2x2 matrices, we use the formula if n == 2: - return M[0,0]*M[1,1] - M[0,1]*M[1,0] + return M[0, 0] * M[1, 1] - M[0, 1] * M[1, 0] R = M.base_ring() - track_precision = R._prec_type() in ['capped-rel','capped-abs'] + track_precision = R._prec_type() in ['capped-rel', 'capped-abs'] S = copy(M) shift_rows, shift_cols = self._matrix_flatten_precision(S) @@ -1593,9 +1605,9 @@ def _matrix_determinant(self, M): for piv in range(n): pivi = pivj = piv curval = S[pivi, pivj].valuation() - for i in range(piv,n): - for j in range(piv,n): - v = S[i,j].valuation() + for i in range(piv, n): + for j in range(piv, n): + v = S[i, j].valuation() if v < curval: pivi = i pivj = j @@ -1606,26 +1618,26 @@ def _matrix_determinant(self, M): continue break val = curval - if S[pivi,pivj] == 0: + if S[pivi, pivj] == 0: if track_precision: - return R(0, valdet + (n-piv)*val - shift) + return R(0, valdet + (n - piv) * val - shift) return R(0) valdet += val - S.swap_rows(pivi,piv) + S.swap_rows(pivi, piv) if pivi > piv: sign = -sign - S.swap_columns(pivj,piv) + S.swap_columns(pivj, piv) if pivj > piv: sign = -sign - det *= S[piv,piv] - inv = ~(S[piv,piv] >> val) - for i in range(piv+1,n): - scalar = -inv * (S[i,piv] >> val) + det *= S[piv, piv] + inv = ~(S[piv, piv] >> val) + for i in range(piv + 1, n): + scalar = -inv * (S[i, piv] >> val) if track_precision: scalar = scalar.lift_to_precision() - S.add_multiple_of_row(i,piv,scalar) + S.add_multiple_of_row(i, piv, scalar) if track_precision: relprec = +Infinity @@ -1633,14 +1645,14 @@ def _matrix_determinant(self, M): for i in range(n): prec = Infinity for j in range(n): - prec = min(prec, S[i,j].precision_absolute()) - prec -= S[i,i].valuation() + prec = min(prec, S[i, j].precision_absolute()) + prec -= S[i, i].valuation() relprec = min(prec, relprec) if prec < 0: relprec_neg += prec if relprec_neg < 0: relprec = relprec_neg - det = (sign*det).add_bigoh(valdet+relprec) + det = (sign * det).add_bigoh(valdet + relprec) else: - det = sign*det + det = sign * det return det >> shift diff --git a/src/sage/rings/padics/misc.py b/src/sage/rings/padics/misc.py index 3ce3f4f39f9..198cf7be69e 100644 --- a/src/sage/rings/padics/misc.py +++ b/src/sage/rings/padics/misc.py @@ -14,6 +14,7 @@ - Ander Steele - Kiran Kedlaya (modified gauss_sum 2017/09) """ + # **************************************************************************** # Copyright (C) 2007-2013 David Roe # William Stein @@ -124,22 +125,22 @@ def gauss_sum(a, p, f, prec=20, factored=False, algorithm='pari', parent=None): from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing q = p**f - a = a % (q-1) + a = a % (q - 1) if parent is None: R = Zp(p, prec) else: R = parent out = -R.one() if a != 0: - t = R(1/(q-1)) + t = R(1 / (q - 1)) for i in range(f): - out *= (a*t).gamma(algorithm) - a = (a*p) % (q-1) + out *= (a * t).gamma(algorithm) + a = (a * p) % (q - 1) s = sum(a.digits(base=p)) if factored: return s, out X = PolynomialRing(R, name='X').gen() - pi = R.ext(X**(p - 1) + p, names='pi').gen() + pi = R.ext(X ** (p - 1) + p, names='pi').gen() out *= pi**s return out @@ -202,13 +203,7 @@ def precprint(prec_type, prec_cap, p): sage: precprint('fixed-mod', 1, 17) 'of fixed modulus 17^1' """ - precD = {'capped-rel':'with capped relative precision %s' % prec_cap, - 'capped-abs':'with capped absolute precision %s' % prec_cap, - 'floating-point':'with floating precision %s' % prec_cap, - 'fixed-mod':'of fixed modulus %s^%s' % (p, prec_cap), - 'lattice-cap':'with lattice-cap precision', - 'lattice-float':'with lattice-float precision', - 'relaxed':'handled with relaxed arithmetics'} + precD = {'capped-rel': 'with capped relative precision %s' % prec_cap, 'capped-abs': 'with capped absolute precision %s' % prec_cap, 'floating-point': 'with floating precision %s' % prec_cap, 'fixed-mod': 'of fixed modulus %s^%s' % (p, prec_cap), 'lattice-cap': 'with lattice-cap precision', 'lattice-float': 'with lattice-float precision', 'relaxed': 'handled with relaxed arithmetics'} return precD[prec_type] diff --git a/src/sage/rings/padics/padic_base_generic.py b/src/sage/rings/padics/padic_base_generic.py index b47df80e84f..fd624d33512 100644 --- a/src/sage/rings/padics/padic_base_generic.py +++ b/src/sage/rings/padics/padic_base_generic.py @@ -8,7 +8,7 @@ - David Roe """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2007-2013 David Roe # William Stein # @@ -17,7 +17,7 @@ # the License, or (at your option) any later version. # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -44,6 +44,7 @@ def __init__(self, p, prec, print_mode, names, element_class, category=None): """ if self.is_relaxed(): from sage.rings.padics.pow_computer_flint import PowComputer_flint + self.prime_pow = PowComputer_flint(p, 1, 1, 1, self.is_field()) else: self.prime_pow = PowComputer(p, max(min(prec - 1, 30), 1), prec, self.is_field(), self._prec_type()) @@ -153,6 +154,7 @@ def exact_field(self): Rational Field """ from sage.rings.rational_field import QQ + return QQ def exact_ring(self): @@ -165,6 +167,7 @@ def exact_ring(self): Integer Ring """ from sage.rings.integer_ring import ZZ + return ZZ def is_isomorphic(self, ring) -> bool: @@ -328,7 +331,7 @@ def has_pth_root(self): sage: Zp(17).has_pth_root() False """ - return (self.prime() == 2) + return self.prime() == 2 def has_root_of_unity(self, n): r""" @@ -353,7 +356,7 @@ def has_root_of_unity(self, n): sage: R.has_root_of_unity(11) False """ - if (self.prime() == 2): + if self.prime() == 2: return n.divides(2) return n.divides(self.prime() - 1) @@ -378,7 +381,7 @@ def zeta(self, n=None): sage: R.zeta(12) 8 + 24*37 + 37^2 + 29*37^3 + 23*37^4 + O(37^5) """ - if (self.prime() == 2): + if self.prime() == 2: if (n is None) or (n == 2): return self(-1) if n == 1: @@ -386,6 +389,7 @@ def zeta(self, n=None): raise ValueError("No, %sth root of unity in self" % n) else: from sage.rings.finite_rings.finite_field_constructor import GF + return self.teichmuller(GF(self.prime()).zeta(n).lift()) def zeta_order(self): @@ -399,7 +403,7 @@ def zeta_order(self): sage: Zp(2).zeta_order() 2 """ - if (self.prime() == 2): + if self.prime() == 2: return 2 return self.prime() - 1 @@ -440,18 +444,19 @@ def plot(self, max_points=2500, **args): from sage.misc.mrange import cartesian_product_iterator from sage.rings.real_double import RDF from sage.plot.point import point as points + p = self.prime() - phi = 2*RDF.pi()/p + phi = 2 * RDF.pi() / p V = RDF**2 - vs = [V([(phi*t).sin(), (phi*t).cos()]) for t in range(p)] + vs = [V([(phi * t).sin(), (phi * t).cos()]) for t in range(p)] all = [] depth = max(RDF(max_points).log(p).floor(), 1) - scale = min(RDF(1.5/p), 1/RDF(3)) - pts = [vs]*depth + scale = min(RDF(1.5 / p), 1 / RDF(3)) + pts = [vs] * depth if depth == 1 and 23 < p < max_points: - extras = int(max_points/p) - if p/extras > 5: - pts = [vs]*depth + [vs[::extras]] + extras = int(max_points / p) + if p / extras > 5: + pts = [vs] * depth + [vs[::extras]] for digits in cartesian_product_iterator(pts): p = sum([v * scale**n for n, v in enumerate(digits)]) all.append(tuple(p)) diff --git a/src/sage/rings/padics/padic_base_leaves.py b/src/sage/rings/padics/padic_base_leaves.py index 66fdc30d670..780d02dd169 100644 --- a/src/sage/rings/padics/padic_base_leaves.py +++ b/src/sage/rings/padics/padic_base_leaves.py @@ -176,7 +176,7 @@ class names.:: sage: TestSuite(R).run() # needs sage.geometry.polyhedron """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2008 David Roe # William Stein # @@ -185,7 +185,7 @@ class names.:: # the License, or (at your option) any later version. # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.rings.integer_ring import ZZ from sage.rings.padics.generic_nodes import ( pAdicCappedAbsoluteRingGeneric, @@ -211,6 +211,7 @@ class pAdicRingCappedRelative(pAdicRingBaseGeneric, pAdicCappedRelativeRingGener An implementation of the `p`-adic integers with capped relative precision. """ + def __init__(self, p, prec, print_mode, names, category=None): """ Initialization. @@ -274,13 +275,12 @@ def _coerce_map_from_(self, R): sage: K.has_coerce_map_from(ZpCA(17,40)) False """ - #if isinstance(R, pAdicRingRelaxed) and R.prime() == self.prime(): + # if isinstance(R, pAdicRingRelaxed) and R.prime() == self.prime(): # return True if isinstance(R, pAdicRingCappedRelative) and R.prime() == self.prime(): if R.precision_cap() < self.precision_cap(): return True - if (R.precision_cap() == self.precision_cap() and - self._printer.richcmp_modes(R._printer, op_LE)): + if R.precision_cap() == self.precision_cap() and self._printer.richcmp_modes(R._printer, op_LE): return True def _convert_map_from_(self, R): @@ -295,12 +295,14 @@ def _convert_map_from_(self, R): To: 7-adic Ring with capped relative precision 20 """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing_generic + if isinstance(R, IntegerModRing_generic): N = R.cardinality() p = self.prime() n = N.exact_log(p) if N == p**n: from sage.rings.padics.padic_generic import ResidueLiftingMap + return ResidueLiftingMap._create_(R, self) @@ -308,6 +310,7 @@ class pAdicRingCappedAbsolute(pAdicRingBaseGeneric, pAdicCappedAbsoluteRingGener r""" An implementation of the `p`-adic integers with capped absolute precision. """ + def __init__(self, p, prec, print_mode, names, category=None): """ Initialization. @@ -371,15 +374,14 @@ def _coerce_map_from_(self, R): sage: K.has_coerce_map_from(Zp(17,40)) True """ - #if isinstance(R, pAdicRingRelaxed) and R.prime() == self.prime(): + # if isinstance(R, pAdicRingRelaxed) and R.prime() == self.prime(): # return True if isinstance(R, pAdicRingCappedRelative) and R.prime() == self.prime(): return True if isinstance(R, pAdicRingCappedAbsolute) and R.prime() == self.prime(): if R.precision_cap() < self.precision_cap(): return True - if (R.precision_cap() == self.precision_cap() and - self._printer.richcmp_modes(R._printer, op_LE)): + if R.precision_cap() == self.precision_cap() and self._printer.richcmp_modes(R._printer, op_LE): return True def _convert_map_from_(self, R): @@ -394,12 +396,14 @@ def _convert_map_from_(self, R): To: 7-adic Ring with capped absolute precision 20 """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing_generic + if isinstance(R, IntegerModRing_generic): N = R.cardinality() p = self.prime() n = N.exact_log(p) if N == p**n: from sage.rings.padics.padic_generic import ResidueLiftingMap + return ResidueLiftingMap._create_(R, self) def _magma_init_(self, magma): @@ -421,6 +425,7 @@ class pAdicRingFloatingPoint(pAdicRingBaseGeneric, pAdicFloatingPointRingGeneric An implementation of the `p`-adic integers with floating point precision. """ + def __init__(self, p, prec, print_mode, names, category=None): """ Initialization. @@ -502,12 +507,14 @@ def _convert_map_from_(self, R): To: 7-adic Ring with floating precision 20 """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing_generic + if isinstance(R, IntegerModRing_generic): N = R.cardinality() p = self.prime() n = N.exact_log(p) if N == p**n: from sage.rings.padics.padic_generic import ResidueLiftingMap + return ResidueLiftingMap._create_(R, self) @@ -515,6 +522,7 @@ class pAdicRingFixedMod(pAdicRingBaseGeneric, pAdicFixedModRingGeneric): r""" An implementation of the `p`-adic integers using fixed modulus. """ + def __init__(self, p, prec, print_mode, names, category=None): """ Initialization. @@ -587,13 +595,12 @@ def _coerce_map_from_(self, R): sage: K.has_coerce_map_from(Zp(17,40)) False """ - #if isinstance(R, pAdicRingRelaxed) and R.prime() == self.prime(): + # if isinstance(R, pAdicRingRelaxed) and R.prime() == self.prime(): # return True if isinstance(R, pAdicRingFixedMod) and R.prime() == self.prime(): if R.precision_cap() > self.precision_cap(): return True - if (R.precision_cap() == self.precision_cap() and - self._printer.richcmp_modes(R._printer, op_LE)): + if R.precision_cap() == self.precision_cap() and self._printer.richcmp_modes(R._printer, op_LE): return True def _convert_map_from_(self, R): @@ -608,12 +615,14 @@ def _convert_map_from_(self, R): To: 7-adic Ring of fixed modulus 7^20 """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing_generic + if isinstance(R, IntegerModRing_generic): N = R.cardinality() p = self.prime() n = N.exact_log(p) if N == p**n: from sage.rings.padics.padic_generic import ResidueLiftingMap + return ResidueLiftingMap._create_(R, self) def _magma_init_(self, magma): @@ -709,15 +718,14 @@ def _coerce_map_from_(self, R): sage: K.has_coerce_map_from(Zp(17,40)) True """ - #if isinstance(R, pAdicRingRelaxed) or isinstance(R, pAdicFieldRelaxed) and R.prime() == self.prime(): + # if isinstance(R, pAdicRingRelaxed) or isinstance(R, pAdicFieldRelaxed) and R.prime() == self.prime(): # return True if isinstance(R, (pAdicRingCappedRelative, pAdicRingCappedAbsolute)) and R.prime() == self.prime(): return True if isinstance(R, pAdicFieldCappedRelative) and R.prime() == self.prime(): if R.precision_cap() < self.precision_cap(): return True - if (R.precision_cap() == self.precision_cap() and - self._printer.richcmp_modes(R._printer, op_LE)): + if R.precision_cap() == self.precision_cap() and self._printer.richcmp_modes(R._printer, op_LE): return True def _convert_map_from_(self, R): @@ -732,12 +740,14 @@ def _convert_map_from_(self, R): To: 7-adic Field with capped relative precision 20 """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing_generic + if isinstance(R, IntegerModRing_generic): N = R.cardinality() p = self.prime() n = N.exact_log(p) if N == p**n: from sage.rings.padics.padic_generic import ResidueLiftingMap + return ResidueLiftingMap._create_(R, self) def _magma_init_(self, magma): @@ -770,10 +780,10 @@ def random_element(self, algorithm='default'): sage: Qp(17,6).random_element().parent() is Qp(17,6) True """ - if (algorithm == 'default'): + if algorithm == 'default': k = ZZ.random_element() - a = ZZ.random_element(self.prime()**self.precision_cap()) - return self(self.prime()**k * a, absprec=k + self.precision_cap()) + a = ZZ.random_element(self.prime() ** self.precision_cap()) + return self(self.prime() ** k * a, absprec=k + self.precision_cap()) raise NotImplementedError("Don't know %s algorithm" % algorithm) @@ -782,6 +792,7 @@ class pAdicFieldFloatingPoint(pAdicFieldBaseGeneric, pAdicFloatingPointFieldGene An implementation of the `p`-adic rationals with floating point precision. """ + def __init__(self, p, prec, print_mode, names, category=None): """ Initialization. @@ -866,14 +877,17 @@ def _convert_map_from_(self, R): To: 7-adic Field with floating precision 20 """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing_generic + if isinstance(R, IntegerModRing_generic): N = R.cardinality() p = self.prime() n = N.exact_log(p) if N == p**n: from sage.rings.padics.padic_generic import ResidueLiftingMap + return ResidueLiftingMap._create_(R, self) + # Lattice precision ################### @@ -913,6 +927,7 @@ class pAdicRingLattice(pAdicLatticeGeneric, pAdicRingBaseGeneric): sage: R 2-adic Ring with lattice-cap precision (label: init) """ + def __init__(self, p, prec, subtype, print_mode, names, label=None, category=None): """ Initialization. @@ -1043,6 +1058,7 @@ class pAdicFieldLattice(pAdicLatticeGeneric, pAdicFieldBaseGeneric): sage: R 2-adic Field with lattice-cap precision (label: init) """ + def __init__(self, p, prec, subtype, print_mode, names, label=None, category=None): """ Initialization. @@ -1142,7 +1158,8 @@ def random_element(self, prec=None, integral=False): x = ZZ.random_element(p**prec) relcap = x.valuation(p) + self._prec_cap_relative prec = min(relcap, prec) - return self._element_class(self, x*(p**val), prec=prec) + return self._element_class(self, x * (p**val), prec=prec) + # Relaxed ######### @@ -1168,6 +1185,7 @@ class pAdicRingRelaxed(pAdicRelaxedGeneric, pAdicRingBaseGeneric): sage: type(R) # needs sage.libs.flint """ + def __init__(self, p, prec, print_mode, names, category=None): """ Initialization. @@ -1180,6 +1198,7 @@ def __init__(self, p, prec, print_mode, names, category=None): sage: TestSuite(R).run(skip=['_test_log', '_test_matrix_smith']) """ from sage.rings.padics import padic_relaxed_element + self._default_prec, self._halting_prec, self._secure = prec pAdicRingBaseGeneric.__init__(self, p, self._default_prec, print_mode, names, padic_relaxed_element.pAdicRelaxedElement, category=category) self._element_class_module = padic_relaxed_element @@ -1206,6 +1225,7 @@ class pAdicFieldRelaxed(pAdicRelaxedGeneric, pAdicFieldBaseGeneric): sage: type(R) # needs sage.libs.flint """ + def __init__(self, p, prec, print_mode, names, category=None): """ Initialization. @@ -1218,6 +1238,7 @@ def __init__(self, p, prec, print_mode, names, category=None): sage: TestSuite(K).run(skip=['_test_log', '_test_matrix_smith']) """ from sage.rings.padics import padic_relaxed_element + self._default_prec, self._halting_prec, self._secure = prec pAdicFieldBaseGeneric.__init__(self, p, self._default_prec, print_mode, names, padic_relaxed_element.pAdicRelaxedElement, category=category) self._element_class_module = padic_relaxed_element diff --git a/src/sage/rings/padics/padic_extension_generic.py b/src/sage/rings/padics/padic_extension_generic.py index 3d979f18e29..37f38be9241 100644 --- a/src/sage/rings/padics/padic_extension_generic.py +++ b/src/sage/rings/padics/padic_extension_generic.py @@ -9,7 +9,7 @@ - David Roe """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2007-2013 David Roe # William Stein # @@ -18,7 +18,7 @@ # the License, or (at your option) any later version. # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** import sage.rings.abc @@ -54,7 +54,7 @@ def __init__(self, poly, prec, print_mode, names, element_class): sage: f = x^5 + 75*x^3 - 15*x^2 +125*x - 5 sage: W. = R.ext(f) # indirect doctest """ - #type checking done in factory + # type checking done in factory self._given_poly = poly R = poly.base_ring() # We'll deal with the different names better later. @@ -177,7 +177,7 @@ def _repr_(self, do_latex=False): if f == 1: subscript = str(p) else: - subscript = "%s^{%s}" % (p,f) + subscript = "%s^{%s}" % (p, f) return "%s_{%s}" % (letter, subscript) return "%s[%s]" % (self.base_ring()._repr_(do_latex=True), self.latex_name()) if type != "": @@ -262,10 +262,7 @@ def __eq__(self, other): if not isinstance(other, pAdicExtensionGeneric): return False - return (self.ground_ring() == other.ground_ring() and - self.defining_polynomial() == other.defining_polynomial() and - self.precision_cap() == other.precision_cap() and - self._printer.richcmp_modes(other._printer, op_EQ)) + return self.ground_ring() == other.ground_ring() and self.defining_polynomial() == other.defining_polynomial() and self.precision_cap() == other.precision_cap() and self._printer.richcmp_modes(other._printer, op_EQ) def __ne__(self, other): """ @@ -295,19 +292,18 @@ def __hash__(self): True """ # _printer is not hashable, hence not taken into account - return hash((self.ground_ring(), self.defining_polynomial(exact=True), - self.precision_cap())) + return hash((self.ground_ring(), self.defining_polynomial(exact=True), self.precision_cap())) - #def absolute_discriminant(self): + # def absolute_discriminant(self): # raise NotImplementedError - #def discriminant(self): + # def discriminant(self): # raise NotImplementedError - #def is_abelian(self): + # def is_abelian(self): # raise NotImplementedError - #def is_normal(self): + # def is_normal(self): # raise NotImplementedError def defining_polynomial(self, var=None, exact=False): @@ -457,7 +453,7 @@ def ground_ring_of_tower(self): return self.ground_ring() return self.ground_ring().ground_ring_of_tower() - #def is_isomorphic(self, ring): + # def is_isomorphic(self, ring): # raise NotImplementedError def polynomial_ring(self): @@ -471,7 +467,7 @@ def polynomial_ring(self): """ return self._given_poly.parent() - #def teichmuller(self, x, prec=None): + # def teichmuller(self, x, prec=None): # if prec is None: # prec = self.precision_cap() # x = self(x, prec) @@ -530,16 +526,12 @@ def construction(self, forbid_frac_field=False): True """ from sage.categories.pushout import AlgebraicExtensionFunctor as AEF, FractionField as FF + if not forbid_frac_field and self.is_field(): return (FF(), self.integer_ring()) - return (AEF([self.defining_polynomial(exact=True)], - [self.variable_name()], - precs=[self.precision_cap()], - print_mode=self._printer.dict(), - implementations=[self._implementation]), - self.base_ring()) - - #def hasGNB(self): + return (AEF([self.defining_polynomial(exact=True)], [self.variable_name()], precs=[self.precision_cap()], print_mode=self._printer.dict(), implementations=[self._implementation]), self.base_ring()) + + # def hasGNB(self): # raise NotImplementedError def random_element(self): @@ -559,10 +551,7 @@ def random_element(self): sage: W.random_element().parent() is W True """ - return reduce(lambda x,y: x+y, - [self.ground_ring().random_element() * self.gen()**i for i in - range(self.modulus().degree())], - 0) + return reduce(lambda x, y: x + y, [self.ground_ring().random_element() * self.gen() ** i for i in range(self.modulus().degree())], 0) @cached_method(key=(lambda self, base, basis, map: (base or self.base_ring(), map))) def free_module(self, base=None, basis=None, map=True): @@ -639,21 +628,22 @@ def free_module(self, base=None, basis=None, map=True): to_V = ToV.__make_element_class__(to_V)(ToV) return V, from_V, to_V - #def unit_group(self): + # def unit_group(self): # raise NotImplementedError - #def unit_group_gens(self): + # def unit_group_gens(self): # raise NotImplementedError - #def principal_unit_group(self): + # def principal_unit_group(self): # raise NotImplementedError - #def zeta(self, n=None): + # def zeta(self, n=None): # raise NotImplementedError - #def zeta_order(self): + # def zeta_order(self): # raise NotImplementedError + # We could have used morphisms in the category # FiniteDimensionalModulesWithBasis over Qp(p) # But currently if you try to add this category @@ -679,6 +669,7 @@ class pAdicModuleIsomorphism(Map): sage: isinstance(fr, pAdicModuleIsomorphism) True """ + def _repr_type(self): r""" EXAMPLES:: @@ -738,6 +729,7 @@ class MapFreeModuleToOneStep(pAdicModuleIsomorphism): sage: V, fr, to = K.free_module() sage: TestSuite(fr).run(skip=['_test_nonzero_equal']) # skipped since Qq(125) doesn't have dimension() """ + def _call_(self, x): """ EXAMPLES:: @@ -773,6 +765,7 @@ class MapOneStepToFreeModule(pAdicModuleIsomorphism): sage: V, fr, to = K.free_module() sage: TestSuite(to).run() """ + def _call_(self, x): """ EXAMPLES:: @@ -801,6 +794,7 @@ class MapFreeModuleToTwoStep(pAdicModuleIsomorphism): sage: V, fr, to = L.free_module(base=Qp(5)) sage: TestSuite(fr).run(skip=['_test_nonzero_equal']) # skipped since L doesn't have dimension() """ + def _call_(self, x): """ EXAMPLES:: @@ -818,7 +812,7 @@ def _call_(self, x): x = list(x) n = len(x) d = n // L.relative_degree() - v = [U(x[i:i+d]) for i in range(0,n,d)] + v = [U(x[i : i + d]) for i in range(0, n, d)] return L(v) def _call_with_args(self, x, args=(), kwds={}): @@ -848,6 +842,7 @@ class MapTwoStepToFreeModule(pAdicModuleIsomorphism): sage: V, fr, to = L.free_module(base=Qp(5)) sage: TestSuite(to).run() """ + def _call_(self, x): """ EXAMPLES:: @@ -889,6 +884,7 @@ class DefPolyConversion(Morphism): sage: f = S.convert_map_from(R) sage: TestSuite(f).run() """ + def _call_(self, x): """ Use the polynomial associated to the element to do the conversion. diff --git a/src/sage/rings/padics/padic_extension_leaves.py b/src/sage/rings/padics/padic_extension_leaves.py index d17563712fb..c809d722274 100644 --- a/src/sage/rings/padics/padic_extension_leaves.py +++ b/src/sage/rings/padics/padic_extension_leaves.py @@ -9,7 +9,7 @@ - David Roe """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2008 David Roe # William Stein # @@ -18,7 +18,7 @@ # the License, or (at your option) any later version. # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.lazy_import import lazy_import from sage.rings.integer_ring import ZZ @@ -30,24 +30,20 @@ from .unramified_extension_generic import UnramifiedExtensionGeneric from .eisenstein_extension_generic import EisensteinExtensionGeneric -#from padic_general_extension_generic import pAdicGeneralExtensionGeneric - -from .generic_nodes import pAdicCappedRelativeRingGeneric, \ - pAdicCappedRelativeFieldGeneric, \ - pAdicCappedAbsoluteRingGeneric, \ - pAdicFixedModRingGeneric, \ - pAdicFloatingPointRingGeneric, \ - pAdicFloatingPointFieldGeneric - -#from unramified_extension_absolute_element import UnramifiedExtensionAbsoluteElement -#from unramified_extension_capped_relative_element import UnramifiedExtensionCappedRelativeElement -#from unramified_extension_lazy_element import UnramifiedExtensionRelaxedElement -#from eisenstein_extension_absolute_element import EisensteinExtensionAbsoluteElement -#from eisenstein_extension_capped_relative_element import EisensteinExtensionCappedRelativeElement -#from eisenstein_extension_lazy_element import EisensteinExtensionRelaxedElement -#from padic_general_extension_absolute_element import pAdicGeneralExtensionAbsoluteElement -#from padic_general_extension_capped_relative_element import pAdicGeneralExtensionCappedRelativeElement -#from padic_general_extension_lazy_element import pAdicGeneralExtensionRelaxedElement + +# from padic_general_extension_generic import pAdicGeneralExtensionGeneric + +from .generic_nodes import pAdicCappedRelativeRingGeneric, pAdicCappedRelativeFieldGeneric, pAdicCappedAbsoluteRingGeneric, pAdicFixedModRingGeneric, pAdicFloatingPointRingGeneric, pAdicFloatingPointFieldGeneric + +# from unramified_extension_absolute_element import UnramifiedExtensionAbsoluteElement +# from unramified_extension_capped_relative_element import UnramifiedExtensionCappedRelativeElement +# from unramified_extension_lazy_element import UnramifiedExtensionRelaxedElement +# from eisenstein_extension_absolute_element import EisensteinExtensionAbsoluteElement +# from eisenstein_extension_capped_relative_element import EisensteinExtensionCappedRelativeElement +# from eisenstein_extension_lazy_element import EisensteinExtensionRelaxedElement +# from padic_general_extension_absolute_element import pAdicGeneralExtensionAbsoluteElement +# from padic_general_extension_capped_relative_element import pAdicGeneralExtensionCappedRelativeElement +# from padic_general_extension_lazy_element import pAdicGeneralExtensionRelaxedElement try: from .padic_ZZ_pX_FM_element import pAdicZZpXFMElement @@ -103,6 +99,7 @@ class UnramifiedExtensionRingCappedRelative(UnramifiedExtensionGeneric, pAdicCap sage: R. = ZqCR(27,1000) # needs sage.libs.ntl sage: TestSuite(R).run(skip='_test_log',max_runs=4) # needs sage.libs.ntl """ + def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation='FLINT'): r""" A capped relative representation of `\ZZ_q`. @@ -137,7 +134,7 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp self._exact_modulus = exact_modulus self._implementation = implementation if implementation == 'NTL': - ntl_poly = ntl_ZZ_pX([a.lift() for a in poly.list()], poly.base_ring().prime()**prec) + ntl_poly = ntl_ZZ_pX([a.lift() for a in poly.list()], poly.base_ring().prime() ** prec) if prec <= 30: self.prime_pow = PowComputer_ext_maker(poly.base_ring().prime(), prec, prec, prec, False, ntl_poly, "small", "u") else: @@ -151,6 +148,7 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp UnramifiedExtensionGeneric.__init__(self, poly, prec, print_mode, names, element_class) if implementation != 'NTL': from .qadic_flint_CR import pAdicCoercion_ZZ_CR, pAdicConvert_QQ_CR + self.register_coercion(pAdicCoercion_ZZ_CR(self)) self.register_conversion(pAdicConvert_QQ_CR(self)) @@ -162,6 +160,7 @@ class UnramifiedExtensionFieldCappedRelative(UnramifiedExtensionGeneric, pAdicCa sage: R. = QqCR(27,1000) # needs sage.libs.ntl sage: TestSuite(R).run(skip='_test_log',max_runs=4) # needs sage.libs.ntl """ + def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation='FLINT'): r""" A representation of `\QQ_q`. @@ -197,7 +196,7 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp self._exact_modulus = exact_modulus self._implementation = implementation if implementation == 'NTL': - ntl_poly = ntl_ZZ_pX([a.lift() for a in poly.list()], poly.base_ring().prime()**prec) + ntl_poly = ntl_ZZ_pX([a.lift() for a in poly.list()], poly.base_ring().prime() ** prec) if prec <= 30: self.prime_pow = PowComputer_ext_maker(poly.base_ring().prime(), prec, prec, prec, True, ntl_poly, "small", "u") else: @@ -211,6 +210,7 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp UnramifiedExtensionGeneric.__init__(self, poly, prec, print_mode, names, element_class) if implementation != 'NTL': from .qadic_flint_CR import pAdicCoercion_ZZ_CR, pAdicCoercion_QQ_CR + self.register_coercion(pAdicCoercion_ZZ_CR(self)) self.register_coercion(pAdicCoercion_QQ_CR(self)) @@ -233,9 +233,11 @@ def _coerce_map_from_(self, R): """ if isinstance(R, UnramifiedExtensionRingCappedRelative) and R.fraction_field() is self: from sage.rings.padics.qadic_flint_CR import pAdicCoercion_CR_frac_field + return pAdicCoercion_CR_frac_field(R, self) if isinstance(R, UnramifiedExtensionRingCappedAbsolute) and R.fraction_field() is self: from sage.rings.padics.qadic_flint_CA import pAdicCoercion_CA_frac_field + return pAdicCoercion_CA_frac_field(R, self) return super()._coerce_map_from_(R) @@ -248,6 +250,7 @@ class UnramifiedExtensionRingCappedAbsolute(UnramifiedExtensionGeneric, pAdicCap sage: R. = ZqCA(27,1000) # needs sage.libs.flint sage: TestSuite(R).run(skip='_test_log',max_runs=4) # needs sage.libs.flint """ + def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation='FLINT'): r""" A capped absolute representation of `ZZ_q`. @@ -283,7 +286,7 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp self._exact_modulus = exact_modulus self._implementation = implementation if implementation == 'NTL': - ntl_poly = ntl_ZZ_pX([a.lift() for a in poly.list()], poly.base_ring().prime()**prec) + ntl_poly = ntl_ZZ_pX([a.lift() for a in poly.list()], poly.base_ring().prime() ** prec) if prec <= 30: self.prime_pow = PowComputer_ext_maker(poly.base_ring().prime(), prec, prec, prec, True, ntl_poly, "small", "u") else: @@ -297,6 +300,7 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp UnramifiedExtensionGeneric.__init__(self, poly, prec, print_mode, names, element_class) if implementation != 'NTL': from .qadic_flint_CA import pAdicCoercion_ZZ_CA, pAdicConvert_QQ_CA + self.register_coercion(pAdicCoercion_ZZ_CA(self)) self.register_conversion(pAdicConvert_QQ_CA(self)) @@ -308,6 +312,7 @@ class UnramifiedExtensionRingFixedMod(UnramifiedExtensionGeneric, pAdicFixedModR sage: R. = ZqFM(27,1000) # needs sage.libs.flint sage: TestSuite(R).run(skip='_test_log',max_runs=4) # long time # needs sage.libs.flint """ + def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation='FLINT'): """ A fixed modulus representation of Zq. @@ -341,21 +346,22 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp self._exact_modulus = exact_modulus self._implementation = implementation if implementation == 'NTL': - ntl_poly = ntl_ZZ_pX([a.lift() for a in poly.list()], poly.base_ring().prime()**prec) + ntl_poly = ntl_ZZ_pX([a.lift() for a in poly.list()], poly.base_ring().prime() ** prec) self.prime_pow = PowComputer_ext_maker(poly.base_ring().prime(), max(min(prec - 1, 30), 1), prec, prec, False, ntl_poly, "FM", "u") element_class = pAdicZZpXFMElement else: Zpoly = _make_integral_poly(exact_modulus, poly.base_ring().prime(), prec) - cache_limit = 0 # prevents caching + cache_limit = 0 # prevents caching self.prime_pow = PowComputer_flint_maker(poly.base_ring().prime(), cache_limit, prec, prec, False, Zpoly, prec_type='fixed-mod') element_class = qAdicFixedModElement UnramifiedExtensionGeneric.__init__(self, poly, prec, print_mode, names, element_class) if implementation != 'NTL': from .qadic_flint_FM import pAdicCoercion_ZZ_FM, pAdicConvert_QQ_FM + self.register_coercion(pAdicCoercion_ZZ_FM(self)) self.register_conversion(pAdicConvert_QQ_FM(self)) - #def coerce_map_explicit(self, S): + # def coerce_map_explicit(self, S): # from sage.rings.padics.morphism import Morphism_ZZ_UnrFM, Morphism_ZpFM_UnrFM # if S is ZZ: # return Morphism_ZZ_UnrFM(self) @@ -371,6 +377,7 @@ class UnramifiedExtensionRingFloatingPoint(UnramifiedExtensionGeneric, pAdicFloa sage: R. = ZqFP(27,10000); R == loads(dumps(R)) # needs sage.libs.flint True """ + def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation='FLINT'): r""" A floating point representation of `\ZZ_q`. @@ -416,6 +423,7 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp self.prime_pow = PowComputer_flint_maker(poly.base_ring().prime(), cache_limit, prec, prec, False, Zpoly, prec_type='floating-point') UnramifiedExtensionGeneric.__init__(self, poly, prec, print_mode, names, qAdicFloatingPointElement) from .qadic_flint_FP import pAdicCoercion_ZZ_FP, pAdicConvert_QQ_FP + self.register_coercion(pAdicCoercion_ZZ_FP(self)) self.register_conversion(pAdicConvert_QQ_FP(self)) @@ -427,6 +435,7 @@ class UnramifiedExtensionFieldFloatingPoint(UnramifiedExtensionGeneric, pAdicFlo sage: R. = QqFP(27,10000); R == loads(dumps(R)) # needs sage.libs.flint True """ + def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation='FLINT'): r""" A representation of `\QQ_q`. @@ -466,6 +475,7 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp self.prime_pow = PowComputer_flint_maker(poly.base_ring().prime(), cache_limit, prec, prec, True, Zpoly, prec_type='floating-point') UnramifiedExtensionGeneric.__init__(self, poly, prec, print_mode, names, qAdicFloatingPointElement) from .qadic_flint_FP import pAdicCoercion_ZZ_FP, pAdicCoercion_QQ_FP + self.register_coercion(pAdicCoercion_ZZ_FP(self)) self.register_coercion(pAdicCoercion_QQ_FP(self)) @@ -484,6 +494,7 @@ def _coerce_map_from_(self, R): """ if isinstance(R, UnramifiedExtensionRingFloatingPoint) and R.fraction_field() is self: from sage.rings.padics.qadic_flint_FP import pAdicCoercion_FP_frac_field + return pAdicCoercion_FP_frac_field(R, self) return super()._coerce_map_from_(R) @@ -497,6 +508,7 @@ class EisensteinExtensionRingCappedRelative(EisensteinExtensionGeneric, pAdicCap sage: W. = R.ext(f) # needs sage.libs.ntl sage.rings.padics sage: TestSuite(R).run(skip='_test_log',max_runs=4) # needs sage.geometry.polyhedron """ + def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation='NTL'): r""" A capped relative representation of an Eisenstein extension of `\ZZ_p`. @@ -533,8 +545,8 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp 9 """ unram_prec = (prec + poly.degree() - 1) // poly.degree() - ntl_poly = ntl_ZZ_pX([a.lift() for a in poly.list()], poly.base_ring().prime()**unram_prec) - shift_poly = ntl_ZZ_pX([a.lift() for a in shift_seed.list()], shift_seed.base_ring().prime()**unram_prec) + ntl_poly = ntl_ZZ_pX([a.lift() for a in poly.list()], poly.base_ring().prime() ** unram_prec) + shift_poly = ntl_ZZ_pX([a.lift() for a in shift_seed.list()], shift_seed.base_ring().prime() ** unram_prec) if unram_prec <= 30: self.prime_pow = PowComputer_ext_maker(poly.base_ring().prime(), unram_prec, unram_prec, prec, False, ntl_poly, "small", "e", shift_poly) else: @@ -553,6 +565,7 @@ class EisensteinExtensionFieldCappedRelative(EisensteinExtensionGeneric, pAdicCa sage: W. = R.ext(f) # needs sage.libs.ntl sage: TestSuite(R).run(skip='_test_log',max_runs=4) # needs sage.geometry.polyhedron """ + def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation='NTL'): r""" A capped relative representation of an Eisenstein extension of `\QQ_p`. @@ -590,8 +603,8 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp """ # Currently doesn't support polynomials with non-integral coefficients unram_prec = (prec + poly.degree() - 1) // poly.degree() - ntl_poly = ntl_ZZ_pX([a.lift() for a in poly.list()], poly.base_ring().prime()**unram_prec) - shift_poly = ntl_ZZ_pX([a.lift() for a in shift_seed.list()], shift_seed.base_ring().prime()**unram_prec) + ntl_poly = ntl_ZZ_pX([a.lift() for a in poly.list()], poly.base_ring().prime() ** unram_prec) + shift_poly = ntl_ZZ_pX([a.lift() for a in shift_seed.list()], shift_seed.base_ring().prime() ** unram_prec) if unram_prec <= 30: self.prime_pow = PowComputer_ext_maker(poly.base_ring().prime(), unram_prec, unram_prec, prec, True, ntl_poly, "small", "e", shift_poly) else: @@ -610,6 +623,7 @@ class EisensteinExtensionRingCappedAbsolute(EisensteinExtensionGeneric, pAdicCap sage: W. = R.ext(f) # needs sage.libs.ntl sage.rings.padics sage: TestSuite(R).run(skip='_test_log',max_runs=4) # needs sage.geometry.polyhedron """ + def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation): r""" A capped absolute representation of an Eisenstein extension of `\ZZ_p`. @@ -646,8 +660,8 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp 9 """ unram_prec = (prec + poly.degree() - 1) // poly.degree() - ntl_poly = ntl_ZZ_pX([a.lift() for a in poly.list()], poly.base_ring().prime()**unram_prec) - shift_poly = ntl_ZZ_pX([a.lift() for a in shift_seed.list()], shift_seed.base_ring().prime()**unram_prec) + ntl_poly = ntl_ZZ_pX([a.lift() for a in poly.list()], poly.base_ring().prime() ** unram_prec) + shift_poly = ntl_ZZ_pX([a.lift() for a in shift_seed.list()], shift_seed.base_ring().prime() ** unram_prec) if unram_prec <= 30: self.prime_pow = PowComputer_ext_maker(poly.base_ring().prime(), unram_prec, unram_prec, prec, False, ntl_poly, "small", "e", shift_poly) else: @@ -666,6 +680,7 @@ class EisensteinExtensionRingFixedMod(EisensteinExtensionGeneric, pAdicFixedModR sage: W. = R.ext(f) # needs sage.libs.ntl sage.rings.padics sage: TestSuite(R).run(skip='_test_log',max_runs=4) # needs sage.geometry.polyhedron """ + def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, implementation='NTL'): r""" A fixed modulus representation of an eisenstein extension of `\ZZ_p`. @@ -702,9 +717,8 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp 9 """ unram_prec = (prec + poly.degree() - 1) // poly.degree() - ntl_poly = ntl_ZZ_pX([a.lift() for a in poly.list()], poly.base_ring().prime()**unram_prec) - shift_poly = ntl_ZZ_pX([a.lift() for a in shift_seed.list()], - shift_seed.base_ring().prime()**unram_prec) + ntl_poly = ntl_ZZ_pX([a.lift() for a in poly.list()], poly.base_ring().prime() ** unram_prec) + shift_poly = ntl_ZZ_pX([a.lift() for a in shift_seed.list()], shift_seed.base_ring().prime() ** unram_prec) # deal with prec not a multiple of e better. self.prime_pow = PowComputer_ext_maker(poly.base_ring().prime(), max(min(unram_prec - 1, 30), 1), unram_prec, prec, False, ntl_poly, "FM", "e", shift_poly) self._shift_seed = shift_seed @@ -728,7 +742,7 @@ def fraction_field(self): """ raise TypeError("This implementation of the p-adic ring does not support fields of fractions.") - #def coerce_map_explicit(self, S): + # def coerce_map_explicit(self, S): # from sage.rings.padics.morphism import Morphism_ZZ_EisFM, Morphism_ZpFM_EisFM # if S is ZZ: # return Morphism_ZZ_EisFM(self) diff --git a/src/sage/rings/padics/padic_generic.py b/src/sage/rings/padics/padic_generic.py index ed8fb2d2ad1..d19443be141 100644 --- a/src/sage/rings/padics/padic_generic.py +++ b/src/sage/rings/padics/padic_generic.py @@ -83,11 +83,11 @@ def some_elements(self): p = self(self.prime()) a = self.gen() one = self.one() - L = [self.zero(), one, p, (one+p+p).inverse_of_unit(), p-p**2] + L = [self.zero(), one, p, (one + p + p).inverse_of_unit(), p - p**2] if a != p: L.extend([a, (one + a + p).inverse_of_unit()]) if self.is_field(): - L.extend([~(p-p-a),p**(-20)]) + L.extend([~(p - p - a), p ** (-20)]) return L def _modified_print_mode(self, print_mode): @@ -121,9 +121,7 @@ def _modified_print_mode(self, print_mode): print_mode = {} elif isinstance(print_mode, str): print_mode = {'mode': print_mode} - for option in ['mode', 'pos', 'ram_name', 'unram_name', 'var_name', - 'max_ram_terms', 'max_unram_terms', 'max_terse_terms', - 'sep', 'alphabet', 'show_prec']: + for option in ['mode', 'pos', 'ram_name', 'unram_name', 'var_name', 'max_ram_terms', 'max_unram_terms', 'max_terse_terms', 'sep', 'alphabet', 'show_prec']: if option not in print_mode: print_mode[option] = self._printer.dict()[option] return print_mode @@ -287,6 +285,7 @@ def residue_class_field(self): Finite Field of size 3 """ from sage.rings.finite_rings.finite_field_constructor import GF + return GF(self.prime()) def residue_field(self): @@ -314,7 +313,8 @@ def residue_ring(self, n): Ring of integers modulo 1331 """ from sage.rings.finite_rings.integer_mod_ring import Zmod - return Zmod(self.prime()**n) + + return Zmod(self.prime() ** n) def residue_system(self): r""" @@ -345,6 +345,7 @@ def _fraction_field_key(self, print_mode=None): """ if print_mode is not None: from sage.misc.superseded import deprecation + deprecation(23227, "Use the change method if you want to change print options in fraction_field()") return tuple(sorted(print_mode.items())) @@ -476,6 +477,7 @@ def integer_ring(self, print_mode=None): if print_mode is None: return self.change(field=False, check=False) from sage.misc.superseded import deprecation + deprecation(23227, "Use the change method if you want to change print options in integer_ring()") return self.change(field=False, **print_mode) @@ -571,29 +573,28 @@ def teichmuller_system(self): """ R = self.residue_class_field() prec = self.precision_cap() - return [self.teichmuller(self(i).lift_to_precision(prec)) - for i in R if i != 0] - -# def different(self): -# raise NotImplementedError - -# def automorphisms(self): -# r""" -# Returns the group of automorphisms of `\ZZ_p`, i.e. the trivial group. -# """ -# raise NotImplementedError - -# def galois_group(self): -# r""" -# Returns the Galois group of `\ZZ_p`, i.e. the trivial group. -# """ -# raise NotImplementedError - -# def hasGNB(self): -# r""" -# Returns whether or not `\ZZ_p` has a Gauss Normal Basis. -# """ -# raise NotImplementedError + return [self.teichmuller(self(i).lift_to_precision(prec)) for i in R if i != 0] + + # def different(self): + # raise NotImplementedError + + # def automorphisms(self): + # r""" + # Returns the group of automorphisms of `\ZZ_p`, i.e. the trivial group. + # """ + # raise NotImplementedError + + # def galois_group(self): + # r""" + # Returns the Galois group of `\ZZ_p`, i.e. the trivial group. + # """ + # raise NotImplementedError + + # def hasGNB(self): + # r""" + # Returns whether or not `\ZZ_p` has a Gauss Normal Basis. + # """ + # raise NotImplementedError def extension(self, modulus, prec=None, names=None, print_mode=None, implementation='FLINT', **kwds): r""" @@ -612,15 +613,9 @@ def extension(self, modulus, prec=None, names=None, print_mode=None, implementat if isinstance(modulus, list): if len(modulus) == 0: return self - return self.extension(modulus[-1], prec=prec[-1], - names=names[-1], - implementation=implementation[-1], - print_mode=print_mode, **kwds).extension( - modulus[:-1], prec=prec[:-1], - names=names[:-1], - implementation=implementation[:-1], - print_mode=print_mode, **kwds) + return self.extension(modulus[-1], prec=prec[-1], names=names[-1], implementation=implementation[-1], print_mode=print_mode, **kwds).extension(modulus[:-1], prec=prec[:-1], names=names[:-1], implementation=implementation[:-1], print_mode=print_mode, **kwds) from sage.rings.padics.factory import ExtensionFactory + if print_mode is None: print_mode = {} elif isinstance(print_mode, str): @@ -709,11 +704,11 @@ def _test_add(self, **options): for x in elements: y = x + self.zero() - tester.assertEqual(y,x) - tester.assertEqual(y.precision_absolute(),x.precision_absolute()) - tester.assertEqual(y.precision_relative(),x.precision_relative()) + tester.assertEqual(y, x) + tester.assertEqual(y.precision_absolute(), x.precision_absolute()) + tester.assertEqual(y.precision_relative(), x.precision_relative()) - for x,y in some_tuples(elements, 2, tester._max_runs): + for x, y in some_tuples(elements, 2, tester._max_runs): z = x + y tester.assertIs(z.parent(), self) zprec = min(x.precision_absolute(), y.precision_absolute()) @@ -721,11 +716,11 @@ def _test_add(self, **options): tester.assertGreaterEqual(z.precision_absolute(), zprec) elif not self.is_floating_point(): tester.assertEqual(z.precision_absolute(), zprec) - tester.assertGreaterEqual(z.valuation(), min(x.valuation(),y.valuation())) + tester.assertGreaterEqual(z.valuation(), min(x.valuation(), y.valuation())) if x.valuation() != y.valuation(): - tester.assertEqual(z.valuation(), min(x.valuation(),y.valuation())) - tester.assertTrue(y.is_equal_to(z-x,zprec)) - tester.assertTrue(x.is_equal_to(z-y,zprec)) + tester.assertEqual(z.valuation(), min(x.valuation(), y.valuation())) + tester.assertTrue(y.is_equal_to(z - x, zprec)) + tester.assertTrue(x.is_equal_to(z - y, zprec)) def _test_sub(self, **options): r""" @@ -752,7 +747,7 @@ def _test_sub(self, **options): tester.assertEqual(y.precision_absolute(), x.precision_absolute()) tester.assertEqual(y.precision_relative(), x.precision_relative()) - for x,y in some_tuples(elements, 2, tester._max_runs): + for x, y in some_tuples(elements, 2, tester._max_runs): z = x - y tester.assertIs(z.parent(), self) zprec = min(x.precision_absolute(), y.precision_absolute()) @@ -760,11 +755,11 @@ def _test_sub(self, **options): tester.assertGreaterEqual(z.precision_absolute(), zprec) elif not self.is_floating_point(): tester.assertEqual(z.precision_absolute(), zprec) - tester.assertGreaterEqual(z.valuation(), min(x.valuation(),y.valuation())) + tester.assertGreaterEqual(z.valuation(), min(x.valuation(), y.valuation())) if x.valuation() != y.valuation(): - tester.assertEqual(z.valuation(), min(x.valuation(),y.valuation())) - tester.assertTrue((-y).is_equal_to(z - x,zprec)) - tester.assertTrue(x.is_equal_to(z + y,zprec)) + tester.assertEqual(z.valuation(), min(x.valuation(), y.valuation())) + tester.assertTrue((-y).is_equal_to(z - x, zprec)) + tester.assertTrue(x.is_equal_to(z + y, zprec)) def _test_invert(self, **options): """ @@ -823,7 +818,7 @@ def _test_mul(self, **options): tester = self._tester(**options) elements = list(tester.some_elements()) - for x,y in some_tuples(elements, 2, tester._max_runs): + for x, y in some_tuples(elements, 2, tester._max_runs): z = x * y tester.assertIs(z.parent(), self) if self.is_capped_relative() or self.is_floating_point(): @@ -852,7 +847,7 @@ def _test_div(self, **options): tester = self._tester(**options) elements = list(tester.some_elements()) - for x,y in some_tuples(elements, 2, tester._max_runs): + for x, y in some_tuples(elements, 2, tester._max_runs): try: z = x / y except (ZeroDivisionError, PrecisionError, ValueError): @@ -862,7 +857,7 @@ def _test_div(self, **options): tester.assertTrue(y.is_zero()) else: try: - xx = z*y + xx = z * y except ZeroDivisionError: tester.assertTrue(self.is_floating_point() and (z.is_zero() or y.is_zero())) else: @@ -894,12 +889,12 @@ def _test_neg(self, **options): for x in tester.some_elements(): y = -x tester.assertIs(y.parent(), self) - tester.assertTrue((x+y).is_zero()) - tester.assertEqual(y.valuation(),x.valuation()) - tester.assertEqual(x.precision_absolute(),y.precision_absolute()) - tester.assertEqual(x.precision_relative(),y.precision_relative()) - tester.assertEqual(x.is_zero(),y.is_zero()) - tester.assertEqual(x.is_unit(),y.is_unit()) + tester.assertTrue((x + y).is_zero()) + tester.assertEqual(y.valuation(), x.valuation()) + tester.assertEqual(x.precision_absolute(), y.precision_absolute()) + tester.assertEqual(x.precision_relative(), y.precision_relative()) + tester.assertEqual(x.is_zero(), y.is_zero()) + tester.assertEqual(x.is_unit(), y.is_unit()) def _test_shift(self, **options): """ @@ -923,7 +918,7 @@ def _test_shift(self, **options): else: cap = self.precision_cap() k = self.residue_field() - for v in range(min(cap,10)): + for v in range(min(cap, 10)): if self.is_capped_absolute() or self.is_fixed_mod(): prec = cap - v else: @@ -939,12 +934,12 @@ def _test_shift(self, **options): if x._is_exact_zero() or self.is_field(): tester.assertEqual(x, y) else: - for i in range(min(v,prec)): + for i in range(min(v, prec)): tester.assertEqual(k(y.expansion(i)), 0) - for i in range(v,prec): + for i in range(v, prec): tester.assertEqual(y.expansion(i), x.expansion(i)) xx = y + (x % b) - tester.assertTrue(xx.is_equal_to(x,prec)) + tester.assertTrue(xx.is_equal_to(x, prec)) def _test_log(self, **options): r""" @@ -980,10 +975,10 @@ def _test_log(self, **options): if self.is_capped_absolute() or self.is_capped_relative(): # In the fixed modulus setting, rounding errors may occur for x, y, b in tester.some_elements(repeat=3): - if (x*y).is_zero(): + if (x * y).is_zero(): continue r1 = x.log(pi_branch=b) + y.log(pi_branch=b) - r2 = (x*y).log(pi_branch=b) + r2 = (x * y).log(pi_branch=b) tester.assertEqual(r1, r2) p = self.prime() @@ -995,9 +990,9 @@ def _test_log(self, **options): else: a = p * x.unit_part() b = a.exp().log() - c = (1+a).log().exp() + c = (1 + a).log().exp() tester.assertEqual(a, b) - tester.assertEqual(1+a, c) + tester.assertEqual(1 + a, c) def _test_teichmuller(self, **options): r""" @@ -1028,9 +1023,9 @@ def _test_teichmuller(self, **options): except (NotImplementedError, AttributeError): pass if self.is_relaxed(): - tester.assertTrue(y.is_equal_at_precision(y**self.residue_field().order(), self.default_prec())) + tester.assertTrue(y.is_equal_at_precision(y ** self.residue_field().order(), self.default_prec())) else: - tester.assertEqual(y**self.residue_field().order(), y) + tester.assertEqual(y ** self.residue_field().order(), y) def _test_convert_residue_field(self, **options): r""" @@ -1126,6 +1121,7 @@ def frobenius_endomorphism(self, n=1): True """ from .morphism import FrobeniusEndomorphism_padics + return FrobeniusEndomorphism_padics(self, n) def _test_elements_eq_transitive(self, **options): @@ -1183,6 +1179,7 @@ def valuation(self): :meth:`Order.valuation() ` """ from sage.rings.padics.padic_valuation import pAdicValuation + return pAdicValuation(self) def _primitive_qth_root_of_unity(self, exponent): @@ -1216,11 +1213,11 @@ def _primitive_qth_root_of_unity(self, exponent): n = len(self._qth_roots_of_unity) # We check if the result is cached - if exponent < n-1: - return self._qth_roots_of_unity[exponent][0], exponent, self._qth_roots_of_unity[exponent+1] + if exponent < n - 1: + return self._qth_roots_of_unity[exponent][0], exponent, self._qth_roots_of_unity[exponent + 1] zeta, accuracy = self._qth_roots_of_unity[-1] if accuracy is not Infinity: - return self._qth_roots_of_unity[-2][0], n-2, (zeta, accuracy) + return self._qth_roots_of_unity[-2][0], n - 2, (zeta, accuracy) # It is not, so we compute it while accuracy is Infinity and n <= exponent + 1: @@ -1229,34 +1226,34 @@ def _primitive_qth_root_of_unity(self, exponent): p = self.prime() e = self.absolute_e() k = self.residue_field() - if e % (p-1) != 0: + if e % (p - 1) != 0: # No pth root of unity in this ring zeta = accuracy = None else: rho = -k(self(p).expansion(e)) try: - r = rho.nth_root(p-1) + r = rho.nth_root(p - 1) except ValueError: # No pth root of unity in this ring zeta = accuracy = None else: # We compute a primitive pth root of unity - m = e // (p-1) + m = e // (p - 1) prec = self.precision_cap() + e * (1 + m.valuation(p)) ring = self.change(prec=prec) zeta = 1 + (ring(r).lift_to_precision() << m) - curprec = m*p + 1 + curprec = m * p + 1 while curprec < prec: curprec -= e - curprec = min(2*curprec + e, p*curprec) - zeta = zeta.lift_to_precision(min(prec,curprec)) + curprec = min(2 * curprec + e, p * curprec) + zeta = zeta.lift_to_precision(min(prec, curprec)) zeta += zeta * (1 - zeta**p) // p else: zeta, accuracy = zeta._inverse_pth_root() assert accuracy is not None self._qth_roots_of_unity.append((zeta, accuracy)) n += 1 - return self._qth_roots_of_unity[-2][0], n-2, self._qth_roots_of_unity[-1] + return self._qth_roots_of_unity[-2][0], n - 2, self._qth_roots_of_unity[-1] def primitive_root_of_unity(self, n=None, order=False): r""" @@ -1325,13 +1322,13 @@ def primitive_root_of_unity(self, n=None, order=False): if m == 1: zeta = qthzeta else: - zeta = self(k.multiplicative_generator() ** ((c-1) // m)) - invm = self(1/m) + zeta = self(k.multiplicative_generator() ** ((c - 1) // m)) + invm = self(1 / m) curprec = 1 while curprec < prec: curprec *= 2 - zeta = zeta.lift_to_precision(min(prec,curprec)) - zeta += invm * zeta * (1 - qthzeta*zeta**m) + zeta = zeta.lift_to_precision(min(prec, curprec)) + zeta += invm * zeta * (1 - qthzeta * zeta**m) if order: return zeta, m * p**s @@ -1393,7 +1390,7 @@ def roots_of_unity(self, n=None): ....: raise ValueError """ zeta, order = self.primitive_root_of_unity(n, order=True) - return [ zeta**i for i in range(order) ] + return [zeta**i for i in range(order)] def _roots_univariate_polynomial(self, P, ring, multiplicities, algorithm, secure=False): r""" @@ -1571,8 +1568,8 @@ def _roots_univariate_polynomial(self, P, ring, multiplicities, algorithm, secur K = ring.fraction_field() roots = P.change_ring(K)._roots(secure, 0, None) if multiplicities: - return [ (ring(root), m) for (root, m) in roots ] - return [ ring(root) for (root, m) in roots ] + return [(ring(root), m) for (root, m) in roots] + return [ring(root) for (root, m) in roots] class ResidueReductionMap(Morphism): @@ -1591,6 +1588,7 @@ class ResidueReductionMap(Morphism): From: 5-adic Unramified Extension Ring in a defined by x^3 + 3*x + 3 To: Finite Field in a0 of size 5^3 """ + @staticmethod def _create_(R, k): r""" @@ -1611,11 +1609,14 @@ def _create_(R, k): """ if R.is_field(): from sage.categories.sets_with_partial_maps import SetsWithPartialMaps + cat = SetsWithPartialMaps() else: from sage.categories.rings import Rings + cat = Rings() from sage.categories.homset import Hom + kfield = R.residue_field() N = k.cardinality() q = kfield.cardinality() @@ -1716,6 +1717,7 @@ def _richcmp_(self, other, op): return NotImplemented return richcmp((self.domain(), self.codomain()), (other.domain(), other.codomain()), op) + # A class for the Teichmüller lift would also be reasonable.... @@ -1735,6 +1737,7 @@ class ResidueLiftingMap(Morphism): From: Finite Field in a0 of size 5^3 To: 5-adic Unramified Extension Ring in a defined by x^3 + 3*x + 3 """ + @staticmethod def _create_(k, R): r""" @@ -1753,6 +1756,7 @@ def _create_(k, R): """ from sage.categories.sets_cat import Sets from sage.categories.homset import Hom + kfield = R.residue_field() N = k.cardinality() q = kfield.cardinality() @@ -1790,7 +1794,7 @@ def _call_(self, x): else: lift = K(x.polynomial().list(), unram_n) return R(lift, self._n) - #unram_n = (self._n - 1) // R.absolute_e() + 1 + # unram_n = (self._n - 1) // R.absolute_e() + 1 raise NotImplementedError def _call_with_args(self, x, args=(), kwds={}): @@ -1804,7 +1808,7 @@ def _call_with_args(self, x, args=(), kwds={}): 1 + 2 + 2^2 + O(2^5) """ R = self.codomain() - kwds = dict(kwds) # we're changing it + kwds = dict(kwds) # we're changing it if args: args = (min(args[0], self._n),) + args[1:] absprec = args[0] diff --git a/src/sage/rings/padics/padic_lattice_element.py b/src/sage/rings/padics/padic_lattice_element.py index 6eb8ff50b0e..10e2c970723 100644 --- a/src/sage/rings/padics/padic_lattice_element.py +++ b/src/sage/rings/padics/padic_lattice_element.py @@ -91,6 +91,7 @@ class pAdicLatticeElement(pAdicGenericElement): sage: x 1 + O(2^10) """ + def __init__(self, parent, x, prec=None, dx=[], dx_mode='linear_combination', valuation=None, check=True, reduce=True): r""" TESTS:: @@ -299,15 +300,17 @@ def residue(self, absprec=1, field=None, check_prec=True): if self.valuation() < 0: raise ValueError("element must have nonnegative valuation in order to compute residue") if field is None: - field = (absprec == 1) + field = absprec == 1 elif field and absprec != 1: raise ValueError("field keyword may only be set at precision 1") p = self._parent.prime() if field: from sage.rings.finite_rings.finite_field_constructor import GF + ring = GF(p) else: from sage.rings.finite_rings.integer_mod_ring import Integers + ring = Integers(p**absprec) return ring(self.value()) @@ -511,7 +514,7 @@ def is_equal_to(self, other, prec): sage: z - x 2^7 + O(2^10) """ - return (self-other).is_zero(prec) + return (self - other).is_zero(prec) def _add_(self, other): r""" @@ -540,8 +543,7 @@ def _add_(self, other): if self._parent._zero_cap is not None: if x.valuation() >= min(self._value.valuation(), other._value.valuation()) + self._parent._zero_cap: x = self._parent._approx_zero - dx = [ [self, self._parent._approx_one], - [other, self._parent._approx_one] ] + dx = [[self, self._parent._approx_one], [other, self._parent._approx_one]] return self.__class__(self._parent, x, dx=dx, check=False) def _sub_(self, other): @@ -562,8 +564,7 @@ def _sub_(self, other): if self._parent._zero_cap is not None: if x.valuation() >= min(self._value.valuation(), other._value.valuation()) + self._parent._zero_cap: x = self._parent._approx_zero - dx = [ [self, self._parent._approx_one], - [other, self._parent._approx_minusone] ] + dx = [[self, self._parent._approx_one], [other, self._parent._approx_minusone]] return self.__class__(self._parent, x, dx=dx, check=False) def _mul_(self, other): @@ -596,8 +597,7 @@ def _mul_(self, other): x_self = self._value x_other = other._value x = x_self * x_other - dx = [ [self, x_other], - [other, x_self ] ] + dx = [[self, x_other], [other, x_self]] return self.__class__(self._parent, x, dx=dx, check=False) def _div_(self, other): @@ -639,8 +639,7 @@ def _div_(self, other): x_other = other._value x = x_self / x_other # dx = (1/other)*dself - (self/other^2)*dother - dx = [ [self, self._parent._approx_one/x_other], - [other, -x_self/(x_other*x_other)] ] + dx = [[self, self._parent._approx_one / x_other], [other, -x_self / (x_other * x_other)]] return self.__class__(self._parent.fraction_field(), x, dx=dx, check=False) def __invert__(self): @@ -675,7 +674,7 @@ def __invert__(self): x_self = self._value x = self._parent._approx_one / x_self # dx = -(1/self^2)*dself - dx = [ [self, self._parent._approx_minusone/(x_self*x_self)] ] + dx = [[self, self._parent._approx_minusone / (x_self * x_self)]] return self.__class__(self._parent.fraction_field(), x, dx=dx, check=False) def _quo_rem(self, other): @@ -748,7 +747,7 @@ def add_bigoh(self, prec): field = self._parent.fraction_field() return self._copy(field).add_bigoh(prec) x = self._value - dx = [ [self, self._parent._approx_one ] ] + dx = [[self, self._parent._approx_one]] return self.__class__(self._parent, x, prec, dx=dx, check=False) def lift_to_precision(self, prec=None, infer_precision=False): @@ -829,8 +828,8 @@ def lift_to_precision(self, prec=None, infer_precision=False): :meth:`lift_to_precision` of the precision object """ - #from warnings import warn - #warn("use lift_to_precision with extreme caution in the framework of lattice precision") + # from warnings import warn + # warn("use lift_to_precision with extreme caution in the framework of lattice precision") parent = self._parent if infer_precision: cap = min(parent.precision_cap_absolute(), parent.precision_cap_relative() + self._value.valuation()) @@ -969,6 +968,7 @@ def __lshift__(self, n): 3*5^3 + 5^4 + O(5^23) """ from sage.rings.padics.generic_nodes import pAdicRingBaseGeneric + parent = self._parent p = parent.prime() if isinstance(parent, pAdicRingBaseGeneric): @@ -978,7 +978,7 @@ def __lshift__(self, n): x = self._value * powp if isinstance(parent, pAdicRingBaseGeneric): x -= x.reduce(0) - dx = [ [self, powp] ] + dx = [[self, powp]] return self.__class__(parent, x, dx=dx, check=False) def unit_part(self): @@ -1117,9 +1117,10 @@ def _copy(self, parent=None): except AttributeError: raise TypeError("parent must share the same precision object") from sage.rings.padics.generic_nodes import pAdicRingBaseGeneric + if isinstance(parent, pAdicRingBaseGeneric) and self.valuation() < 0: raise ValueError("element of negative valuation cannot be converted to the integer ring") - dx = [ [ self, self._parent._approx_one ] ] + dx = [[self, self._parent._approx_one]] return self.__class__(parent, self._value, dx=dx, check=False) def __copy__(self): @@ -1188,7 +1189,7 @@ def expansion(self, n=None, lift_mode='simple', start_val=None): if n < val: return ZZ(0) try: - return expansion[n-val] + return expansion[n - val] except KeyError: raise PrecisionError("the digit in position %s is not determined" % n) if start_val is None: @@ -1197,8 +1198,8 @@ def expansion(self, n=None, lift_mode='simple', start_val=None): else: start_val = 0 if start_val > val: - return expansion[start_val-val:] - return (val-start_val)*[ZZ(0)] + expansion + return expansion[start_val - val :] + return (val - start_val) * [ZZ(0)] + expansion def dist(self, other): r""" @@ -1227,7 +1228,7 @@ def dist(self, other): p = self._parent.prime() if x.is_zero(): return ZZ(0) - return p**(-x.valuation()) + return p ** (-x.valuation()) class pAdicLatticeCapElement(pAdicLatticeElement): diff --git a/src/sage/rings/padics/padic_lattice_element_test.py b/src/sage/rings/padics/padic_lattice_element_test.py index 3b3095c8018..ff43efac8f4 100644 --- a/src/sage/rings/padics/padic_lattice_element_test.py +++ b/src/sage/rings/padics/padic_lattice_element_test.py @@ -3,6 +3,7 @@ # ZpLC, ZpLF, QpLC, and QpLF all raise FutureWarnings from warnings import catch_warnings, filterwarnings + filterwarnings("ignore", category=FutureWarning) @@ -33,7 +34,7 @@ def R4(): # # https://github.com/pytest-dev/pytest/issues/349 # -elements = ( "R1", "R2", "R3", "R4" ) +elements = ("R1", "R2", "R3", "R4") @pytest.mark.parametrize("e", elements) @@ -48,7 +49,4 @@ def test_padic_lattice_element(e, request): e = request.getfixturevalue(e) # Only do a few runs, _test_matrix_smith() in particular is slow. - TestSuite(e).run(verbose=True, - raise_on_failure=True, - skip="_test_teichmuller", - max_runs=8) + TestSuite(e).run(verbose=True, raise_on_failure=True, skip="_test_teichmuller", max_runs=8) diff --git a/src/sage/rings/padics/padic_valuation.py b/src/sage/rings/padics/padic_valuation.py index eca4b1b2c67..e4817da0be1 100644 --- a/src/sage/rings/padics/padic_valuation.py +++ b/src/sage/rings/padics/padic_valuation.py @@ -41,14 +41,15 @@ The theory used here was originally developed in [Mac1936I]_ and [Mac1936II]_. An overview can also be found in Chapter 4 of [Rüt2014]_. """ -#***************************************************************************** + +# ***************************************************************************** # Copyright (C) 2013-2020 Julian Rüth # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.rings.valuation.valuation import DiscreteValuation from sage.rings.valuation.value_group import DiscreteValueSemigroup from sage.rings.valuation.mapped_valuation import FiniteExtensionFromLimitValuation @@ -115,6 +116,7 @@ class PadicValuationFactory(UniqueFactory): :meth:`RationalField.valuation() `, :meth:`IntegerRing_class.valuation() `. """ + def create_key_and_extra_args(self, R, prime=None, approximants=None): r""" Create a unique key identifying the valuation of ``R`` with respect to @@ -154,9 +156,11 @@ def create_key_for_integers(self, R, prime): 2-adic valuation """ from sage.rings.integer_ring import ZZ + if prime is None: raise ValueError("prime must be specified for this ring") from sage.rings.valuation.valuation import DiscretePseudoValuation + if isinstance(prime, DiscretePseudoValuation): prime = prime.uniformizer() if prime not in ZZ or not ZZ(prime).is_prime(): @@ -198,6 +202,7 @@ def create_key_and_extra_args_for_number_field(self, R, prime, approximants): from sage.rings.number_field.number_field_ideal import NumberFieldFractionalIdeal from sage.rings.valuation.valuation import DiscretePseudoValuation + if isinstance(prime, DiscretePseudoValuation): return self.create_key_and_extra_args_for_number_field_from_valuation(R, prime, prime, approximants=approximants) if prime in K: @@ -245,6 +250,7 @@ def create_key_and_extra_args_for_number_field_from_valuation(self, R, v, prime, if v.domain() is not K: v = K.valuation(v) from sage.rings.valuation.gauss_valuation import GaussValuation + v = GaussValuation(G.parent(), v) if v.domain() != G.parent(): # Then, we lift valuations defined on polynomial rings which are @@ -256,7 +262,7 @@ def create_key_and_extra_args_for_number_field_from_valuation(self, R, v, prime, else: raise NotImplementedError("cannot rewrite %r which is defined on %r as a pseudo-valuation on %r" % (v, v.domain(), G.parent())) - assert (v.domain() is G.parent()) + assert v.domain() is G.parent() # To obtain uniqueness of p-adic valuations, we need a canonical # description of v. We consider all extensions of vK to L and select @@ -325,6 +331,7 @@ def create_key_and_extra_args_for_number_field_from_ideal(self, R, I, prime): # their polynomial() defined over the rationals so we need to turn them # into polynomials over K[x] explicitly. from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + gens = I.gens() gens = [PolynomialRing(K, 'x')(list(g.vector())) for g in gens] @@ -360,12 +367,14 @@ def _normalize_number_field_data(self, R): """ from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_generic from sage.rings.number_field.number_field_base import NumberField + if isinstance(R.fraction_field(), NumberField): L = R.fraction_field() G = L.relative_polynomial() K = L.base_ring() elif isinstance(R, PolynomialQuotientRing_generic): from sage.categories.number_fields import NumberFields + if R.base_ring().fraction_field() not in NumberFields(): raise NotImplementedError("cannot normalize quotients over %r" % (R.base_ring(),)) L = R.fraction_field() @@ -391,14 +400,15 @@ def create_object(self, version, key, **extra_args): from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_generic from sage.rings.number_field.number_field_base import NumberField + R = key[0] parent = DiscretePseudoValuationSpace(R) if isinstance(R, pAdicGeneric): - assert (len(key) == 1) + assert len(key) == 1 return parent.__make_element_class__(pAdicValuation_padic)(parent) if R is ZZ or R is QQ: prime = key[1] - assert (len(key) == 2) + assert len(key) == 2 return parent.__make_element_class__(pAdicValuation_int)(parent, prime) v = key[1] approximants = extra_args['approximants'] @@ -448,6 +458,7 @@ class pAdicValuation_base(DiscreteValuation): sage: TestSuite(QQ.valuation(5)).run() # long time # needs sage.geometry.polyhedron sage: TestSuite(Zp(5).valuation()).run() # long time # needs sage.geometry.polyhedron """ + def __init__(self, parent, p): r""" TESTS:: @@ -459,6 +470,7 @@ def __init__(self, parent, p): DiscreteValuation.__init__(self, parent) from sage.rings.integer_ring import ZZ + self._p = ZZ(p) def p(self): @@ -557,6 +569,7 @@ def is_unramified(self, G, include_steps=False, assume_squarefree=False): R = G.parent() from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if not isinstance(R, PolynomialRing_generic) or R.base_ring() is not self.domain() or not G.is_monic(): raise ValueError("G must be a monic univariate polynomial over the domain of this valuation") if not assume_squarefree and not G.is_squarefree(): @@ -564,7 +577,7 @@ def is_unramified(self, G, include_steps=False, assume_squarefree=False): from sage.rings.valuation.gauss_valuation import GaussValuation - steps = [ GaussValuation(R, self) ] + steps = [GaussValuation(R, self)] while True: v = steps[-1] if v.E() > 1: @@ -652,6 +665,7 @@ def is_totally_ramified(self, G, include_steps=False, assume_squarefree=False): R = G.parent() from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if not isinstance(R, PolynomialRing_generic) or R.base_ring() is not self.domain() or not G.is_monic(): raise ValueError("G must be a monic univariate polynomial over the domain of this valuation") if not assume_squarefree and not G.is_squarefree(): @@ -659,7 +673,7 @@ def is_totally_ramified(self, G, include_steps=False, assume_squarefree=False): from sage.rings.valuation.gauss_valuation import GaussValuation - steps = [ GaussValuation(R, self) ] + steps = [GaussValuation(R, self)] while True: v = steps[-1] if v.F() > 1: @@ -775,6 +789,7 @@ def extensions(self, ring): return pAdicValuation(domain_fraction_field, self).extensions(ring) if self.domain().is_subring(ring): from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_generic + if isinstance(ring, PolynomialQuotientRing_generic): if isinstance(self.domain(), PolynomialQuotientRing_generic): if self.domain().modulus() == ring.modulus(): @@ -782,11 +797,13 @@ def extensions(self, ring): return [pAdicValuation(ring, base._initial_approximation) for base in base_extensions] if ring.base_ring() is self.domain(): from sage.categories.integral_domains import IntegralDomains + if ring in IntegralDomains(): return self._extensions_to_quotient(ring) elif self.domain().is_subring(ring.base_ring()): return sum([w.extensions(ring) for w in self.extensions(ring.base_ring())], []) from sage.rings.number_field.number_field_base import NumberField + if isinstance(ring.fraction_field(), NumberField): if ring.base_ring().fraction_field() is self.domain().fraction_field(): approximants = self.mac_lane_approximants(ring.fraction_field().relative_polynomial().change_ring(self.domain()), assume_squarefree=True, require_incomparability=True) @@ -825,9 +842,10 @@ def value_semigroup(self): Additive Abelian Semigroup generated by 1/2 """ from sage.categories.fields import Fields + v = self(self.uniformizer()) if self.domain() in Fields(): - return DiscreteValueSemigroup([-v,v]) + return DiscreteValueSemigroup([-v, v]) return DiscreteValueSemigroup([v]) @@ -848,6 +866,7 @@ class pAdicValuation_padic(pAdicValuation_base): sage: TestSuite(v).run() # long time # needs sage.geometry.polyhedron """ + def __init__(self, parent): """ TESTS:: @@ -932,6 +951,7 @@ def element_with_valuation(self, v): """ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ + v = QQ(v) if v not in self.value_semigroup(): raise ValueError("%r is not in the value semigroup of %r" % (v, self)) @@ -1036,6 +1056,7 @@ def simplify(self, x, error=None, force=False): if error is None: error = self(x) from sage.rings.infinity import infinity + if error is infinity: return x # we need to scale by the ramification index because p-adics use a @@ -1057,6 +1078,7 @@ class pAdicValuation_int(pAdicValuation_base): sage: TestSuite(v).run() # long time # needs sage.geometry.polyhedron """ + def _repr_(self): """ Return a printable representation of this valuation. @@ -1112,6 +1134,7 @@ def residue_ring(self): Finite Field of size 3 """ from sage.rings.finite_rings.finite_field_constructor import GF + return GF(self.p()) def _ge_(self, other): @@ -1153,7 +1176,7 @@ def _relative_size(self, x): 11 """ x = self.domain().coerce(x) - return (x.numerator().nbits() + x.denominator().nbits())//self.p().nbits() + return (x.numerator().nbits() + x.denominator().nbits()) // self.p().nbits() def simplify(self, x, error=None, force=False, size_heuristic_bound=32): r""" @@ -1205,6 +1228,7 @@ def simplify(self, x, error=None, force=False, size_heuristic_bound=32): if error is None: error = v from sage.rings.infinity import infinity + if error is infinity: return x if error < v: @@ -1212,10 +1236,11 @@ def simplify(self, x, error=None, force=False, size_heuristic_bound=32): from sage.rings.rational_field import QQ from sage.rings.padics.factory import Qp + precision_ring = Qp(self.p(), QQ(error).floor() + 1 - v) reduced = precision_ring(x) lift = (reduced >> v).lift() - best = self.domain()(lift) * self.p()**v + best = self.domain()(lift) * self.p() ** v if self._relative_size(x) < self._relative_size(best): best = x @@ -1225,21 +1250,23 @@ def simplify(self, x, error=None, force=False, size_heuristic_bound=32): # get the uniqueness properties but we do not need them actually. # This is certainly slower than the implementation in Cython. from sage.categories.fields import Fields - m = self.p()**(QQ(error).floor() + 1 - v) + + m = self.p() ** (QQ(error).floor() + 1 - v) if self.domain() in Fields(): r = (m, lift) s = (0, 1) while r[1]: qq, rr = r[0].quo_rem(r[1]) r = r[1], rr - s = s[1], s[0] - qq*s[1] + s = s[1], s[0] - qq * s[1] from sage.arith.misc import GCD as gcd + if s[1] != 0 and gcd(s[1], r[1]) == 1: - rational = self.domain()(r[1]) / self.domain()(s[1]) * self.p()**v + rational = self.domain()(r[1]) / self.domain()(s[1]) * self.p() ** v if self._relative_size(rational) < self._relative_size(best): best = rational - assert (self(x-best) > error) + assert self(x - best) > error return best @@ -1285,11 +1312,13 @@ def inverse(self, x, precision): return self.domain().one() from sage.rings.infinity import infinity + if self(x) > 0 or precision is infinity: raise ValueError("element has no approximate inverse in this ring") from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ + return self.domain()(ZZ(x).inverse_mod(self.p() ** QQ(precision).ceil())) @@ -1313,6 +1342,7 @@ class pAdicFromLimitValuation(FiniteExtensionFromLimitValuation, pAdicValuation_ sage: v.shift(1, -1).parent() # needs sage.rings.number_field Number Field in I with defining polynomial x^2 + 1 with I = 1*I """ + def __init__(self, parent, approximant, G, approximants): r""" TESTS:: @@ -1401,12 +1431,15 @@ def _fraction_field(ring): Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^2 + 1 """ from sage.categories.fields import Fields + if ring in Fields(): return ring from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_generic + if isinstance(ring, PolynomialQuotientRing_generic): from sage.categories.integral_domains import IntegralDomains + if ring in IntegralDomains(): return ring.base().change_ring(ring.base_ring().fraction_field()).quo(ring.modulus()) return ring.fraction_field() diff --git a/src/sage/rings/padics/precision_error.py b/src/sage/rings/padics/precision_error.py index 3dcf4b08d8e..adb22f8b3c3 100644 --- a/src/sage/rings/padics/precision_error.py +++ b/src/sage/rings/padics/precision_error.py @@ -9,14 +9,14 @@ - David Roe """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2008 David Roe # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** class PrecisionError(ArithmeticError): diff --git a/src/sage/rings/padics/relative_extension_leaves.py b/src/sage/rings/padics/relative_extension_leaves.py index cff11a5173c..44da045136e 100644 --- a/src/sage/rings/padics/relative_extension_leaves.py +++ b/src/sage/rings/padics/relative_extension_leaves.py @@ -8,7 +8,7 @@ This file contains the parent classes for such extensions. """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2017 David Roe # # Distributed under the terms of the GNU General Public License (GPL) @@ -16,7 +16,7 @@ # the License, or (at your option) any later version. # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.homset import Hom from sage.categories.morphism import Morphism @@ -55,6 +55,7 @@ class pAdicRelativeBaseringInjection(Morphism): From: 5-adic Unramified Extension Field in a defined by x^3 + 3*x + 3 To: 5-adic Eisenstein Extension Field in w defined by x^3 + 15*a*x - 5*a^2 - 5 over its base field """ + def __init__(self, R, S): """ Initialization. @@ -72,6 +73,7 @@ def __init__(self, R, S): Morphism.__init__(self, Hom(R, S)) else: from sage.categories.sets_with_partial_maps import SetsWithPartialMaps + Morphism.__init__(self, Hom(R, S, SetsWithPartialMaps())) def _call_(self, x): @@ -88,7 +90,7 @@ def _call_(self, x): a + (4*a^2 + 4*a + 3)*w^3 + (a + 2)*w^4 + (2*a^2 + 4*a + 2)*w^5 + O(w^6) """ if x.is_zero(): - return self.codomain()(0,x.precision_absolute()) + return self.codomain()(0, x.precision_absolute()) return self.codomain()([x]) def _call_with_args(self, x, args=(), kwds={}): @@ -140,6 +142,7 @@ class pAdicRelativeBaseringSection(Morphism): From: 2-adic Eisenstein Extension Field in w defined by x^4 + 2*a*x^2 - 16*x - 6 over its base field To: 2-adic Unramified Extension Field in a defined by x^10 + x^6 + x^5 + x^3 + x^2 + x + 1 """ + def __init__(self, S, R): """ Initialization. @@ -153,6 +156,7 @@ def __init__(self, S, R): """ from sage.categories.sets_with_partial_maps import SetsWithPartialMaps + Morphism.__init__(self, Hom(S, R, SetsWithPartialMaps())) def _call_(self, x): @@ -206,6 +210,7 @@ class RelativeRamifiedExtensionRingFixedMod(EisensteinExtensionGeneric, pAdicFix sage: w^4 + 2*a*w^2 - 16*w - 6*a == 0 True """ + def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, names, implementation): """ Initialization. @@ -219,7 +224,7 @@ def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, """ self._exact_modulus = exact_modulus unram_prec = (prec + approx_modulus.degree() - 1) // approx_modulus.degree() - KFP = approx_modulus.base_ring().change(prec=unram_prec+1) + KFP = approx_modulus.base_ring().change(prec=unram_prec + 1) self.prime_pow = PowComputer_relative_maker(approx_modulus.base_ring().prime(), max(min(unram_prec - 1, 30), 1), unram_prec, prec, False, exact_modulus.change_ring(KFP), shift_seed.change_ring(KFP), 'fixed-mod') self._implementation = 'Polynomial' EisensteinExtensionGeneric.__init__(self, approx_modulus, prec, print_mode, names, RelativeRamifiedFixedModElement) @@ -227,6 +232,7 @@ def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, pAdicCoercion_ZZ_FM, pAdicConvert_QQ_FM, ) + self.register_coercion(pAdicCoercion_ZZ_FM(self)) self.register_coercion(pAdicRelativeBaseringInjection(approx_modulus.base_ring(), self)) self.register_conversion(pAdicConvert_QQ_FM(self)) @@ -245,6 +251,7 @@ class RelativeRamifiedExtensionRingCappedAbsolute(EisensteinExtensionGeneric, pA sage: w^4 + 2*a*w^2 - 16*w - 6*a == 0 True """ + def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, names, implementation): """ Initialization. @@ -266,6 +273,7 @@ def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, pAdicCoercion_ZZ_CA, pAdicConvert_QQ_CA, ) + self.register_coercion(pAdicCoercion_ZZ_CA(self)) self.register_coercion(pAdicRelativeBaseringInjection(approx_modulus.base_ring(), self)) self.register_conversion(pAdicConvert_QQ_CA(self)) @@ -284,6 +292,7 @@ class RelativeRamifiedExtensionRingCappedRelative(EisensteinExtensionGeneric, pA sage: w^4 + 2*a*w^2 - 16*w - 6*a == 0 True """ + def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, names, implementation): """ Initialization. @@ -305,6 +314,7 @@ def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, pAdicCoercion_ZZ_CR, pAdicConvert_QQ_CR, ) + self.register_coercion(pAdicCoercion_ZZ_CR(self)) self.register_coercion(pAdicRelativeBaseringInjection(approx_modulus.base_ring(), self)) self.register_conversion(pAdicConvert_QQ_CR(self)) @@ -323,6 +333,7 @@ class RelativeRamifiedExtensionFieldCappedRelative(EisensteinExtensionGeneric, p sage: w^4 + 2*a*w^2 - 16*w - 6*a == 0 True """ + def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, names, implementation): """ Initialization. @@ -344,6 +355,7 @@ def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, pAdicCoercion_QQ_CR, pAdicCoercion_ZZ_CR, ) + self.register_coercion(pAdicCoercion_ZZ_CR(self)) self.register_coercion(pAdicRelativeBaseringInjection(approx_modulus.base_ring(), self)) # We also want to convert down to the ring of integers: this is used in teichmuller expansion @@ -364,6 +376,7 @@ class RelativeRamifiedExtensionRingFloatingPoint(EisensteinExtensionGeneric, pAd sage: w^4 + 2*a*w^2 - 16*w - 6*a == 0 True """ + def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, names, implementation): """ Initialization. @@ -385,6 +398,7 @@ def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, pAdicCoercion_ZZ_FP, pAdicConvert_QQ_FP, ) + self.register_coercion(pAdicCoercion_ZZ_FP(self)) self.register_coercion(pAdicRelativeBaseringInjection(approx_modulus.base_ring(), self)) self.register_conversion(pAdicConvert_QQ_FP(self)) @@ -403,6 +417,7 @@ class RelativeRamifiedExtensionFieldFloatingPoint(EisensteinExtensionGeneric, pA sage: w^4 + 2*a*w^2 - 16*w - 6*a == 0 True """ + def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, names, implementation): """ Initialization. @@ -424,6 +439,7 @@ def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, pAdicCoercion_QQ_FP, pAdicCoercion_ZZ_FP, ) + self.register_coercion(pAdicCoercion_ZZ_FP(self)) self.register_coercion(pAdicRelativeBaseringInjection(approx_modulus.base_ring(), self)) # We also want to convert down to the ring of integers: this is used in teichmuller expansion diff --git a/src/sage/rings/padics/unramified_extension_generic.py b/src/sage/rings/padics/unramified_extension_generic.py index e9771fd4dd5..60197467740 100644 --- a/src/sage/rings/padics/unramified_extension_generic.py +++ b/src/sage/rings/padics/unramified_extension_generic.py @@ -29,6 +29,7 @@ class UnramifiedExtensionGeneric(pAdicExtensionGeneric): r""" An unramified extension of `\QQ_p` or `\ZZ_p`. """ + def __init__(self, poly, prec, print_mode, names, element_class): """ Initialize ``self``. @@ -46,10 +47,10 @@ def __init__(self, poly, prec, print_mode, names, element_class): sage: R. = Zq(27) # indirect doctest # needs sage.libs.ntl """ - #base = poly.base_ring() - #if base.is_field(): + # base = poly.base_ring() + # if base.is_field(): # self._PQR = pqr.PolynomialQuotientRing_field(poly.parent(), poly, name = names) - #else: + # else: # self._PQR = pqr.PolynomialQuotientRing_domain(poly.parent(), poly, name = names) pAdicExtensionGeneric.__init__(self, poly, prec, print_mode, names, element_class) self._res_field = GF(self.prime_pow.pow_Integer_Integer(poly.degree()), name=names[1], modulus=poly.change_ring(poly.base_ring().residue_field())) @@ -92,10 +93,10 @@ def absolute_f(self): """ return self.modulus().degree() * self.base_ring().absolute_f() - #def extension(self, *args, **kwds): + # def extension(self, *args, **kwds): # raise NotImplementedError - #def get_extension(self): + # def get_extension(self): # raise NotImplementedError def residue_class_field(self): @@ -107,10 +108,10 @@ def residue_class_field(self): sage: R. = Zq(125); R.residue_class_field() # needs sage.libs.ntl Finite Field in a0 of size 5^3 """ - #should eventually take advantage of finite field - #\code{extension} or finite field - #\code{unramified_extension_of_degree} over the automatic - #coercion base. + # should eventually take advantage of finite field + # \code{extension} or finite field + # \code{unramified_extension_of_degree} over the automatic + # coercion base. return self._res_field def residue_ring(self, n): @@ -154,10 +155,10 @@ def discriminant(self, K=None): return 1 raise NotImplementedError - #def automorphisms(self): + # def automorphisms(self): # raise NotImplementedError - #def galois_group(self): + # def galois_group(self): # r""" # Returns the Galois group of ``self``'s fraction field over Qp. # """ @@ -169,7 +170,7 @@ def discriminant(self, K=None): # from sage.groups.perm_gps.permgroup import CyclicPermutationGroup # return CyclicPermutationGroup(self.modulus().degree()) - #def is_abelian(self): + # def is_abelian(self): # return True def is_galois(self, K=None): @@ -206,7 +207,7 @@ def gen(self, n=0): """ if n != 0: raise IndexError("only one generator") - return self([0,1]) + return self([0, 1]) @cached_method def _frob_gen(self, arithmetic=True): @@ -223,8 +224,8 @@ def _frob_gen(self, arithmetic=True): exp = p a = self.gen() if not arithmetic: - exp = p**(self.absolute_degree() - 1) - approx = (self(a.residue()**exp)).lift_to_precision(self.precision_cap()) #first approximation + exp = p ** (self.absolute_degree() - 1) + approx = (self(a.residue() ** exp)).lift_to_precision(self.precision_cap()) # first approximation f = self.defining_polynomial() g = f.derivative() while f(approx) != 0: # hensel lift frobenius(a) diff --git a/src/sage/rings/padics/witt_vector.py b/src/sage/rings/padics/witt_vector.py index 0618f715afb..de8aa9effa7 100644 --- a/src/sage/rings/padics/witt_vector.py +++ b/src/sage/rings/padics/witt_vector.py @@ -55,6 +55,7 @@ class WittVector(CommutativeRingElement): sage: TestSuite(w).run() """ + def __init__(self, parent, vec=None): """ Common class for all kinds of Witt vectors. @@ -92,13 +93,10 @@ def __init__(self, parent, vec=None): self._int_to_vector(vec, parent) elif isinstance(vec, (tuple, list, WittVector)): if len(vec) < self._prec: - raise ValueError(f"{vec} has not the correct length, " - "expected length has to be at least " - f"{self._prec}") + raise ValueError(f"{vec} has not the correct length, " "expected length has to be at least " f"{self._prec}") self._coordinates = tuple(B(vec[i]) for i in range(self._prec)) else: - raise ValueError(f"{vec} cannot be interpreted as a Witt " - "vector") + raise ValueError(f"{vec} cannot be interpreted as a Witt " "vector") else: self._coordinates = (B(0) for i in range(self._prec)) CommutativeRingElement.__init__(self, parent) @@ -164,15 +162,13 @@ def __invert__(self): if self == P.one(): return self if self._prec.is_one(): - return P((self[0]**-1,)) + return P((self[0] ** -1,)) if P.coefficient_ring().characteristic() == P.prime(): - res = P([self[0]**-1] - + [P.coefficient_ring().zero() - for _ in range(self._prec - 1)]) + res = P([self[0] ** -1] + [P.coefficient_ring().zero() for _ in range(self._prec - 1)]) for _ in range(log(self._prec, 2).n().ceil()): - res = 2*res - self*res*res + res = 2 * res - self * res * res return res @@ -180,19 +176,18 @@ def __invert__(self): # to (1, 0, 0, ...), and solve. poly_ring = PolynomialRing(P.coefficient_ring(), 'x') x = poly_ring.gen() - inv_vec = ([self[0]**-1] - + [poly_ring.zero() for _ in range(self._prec - 1)]) + inv_vec = [self[0] ** -1] + [poly_ring.zero() for _ in range(self._prec - 1)] # We'll fill this in one-by-one from sage.rings.padics.witt_vector_ring import WittVectorRing + W = WittVectorRing(poly_ring, p=P.prime(), prec=self._prec) for i in range(1, self._prec): inv_vec[i] = x prod_vec = (W(self._coordinates) * W(inv_vec)).coordinates() poly = prod_vec[i] try: - inv_vec[i] = (-poly.constant_coefficient() - / poly.monomial_coefficient(x)) + inv_vec[i] = -poly.constant_coefficient() / poly.monomial_coefficient(x) except ZeroDivisionError: raise ArithmeticError(f"inverse of {self} does not exist") try: @@ -254,10 +249,7 @@ def _int_to_vector(self, k, parent): self._coordinates = tuple(R.zero() for i in range(self._prec)) else: Z = Zp(p, prec=self._prec, type='fixed-mod') - self._coordinates = tuple(R( - Z(k).teichmuller_expansion(i).residue().polynomial()) - ** (p**i) - for i in range(self._prec)) + self._coordinates = tuple(R(Z(k).teichmuller_expansion(i).residue().polynomial()) ** (p**i) for i in range(self._prec)) return should_negate = False @@ -267,19 +259,13 @@ def _int_to_vector(self, k, parent): vec_k = [k] for n in range(1, self._prec): - total = ( - k - k**(p**n) - - sum(p**(n-i) * vec_k[n-i]**(p**i) for i in range(1, n)) - ) + total = k - k ** (p**n) - sum(p ** (n - i) * vec_k[n - i] ** (p**i) for i in range(1, n)) total //= p**n vec_k.append(total) if should_negate: if p == 2: - vec_k = ( - parent(vec_k) - * parent(tuple(-1 for _ in range(self._prec))) - ).coordinates() + vec_k = (parent(vec_k) * parent(tuple(-1 for _ in range(self._prec)))).coordinates() else: vec_k = (-x for x in vec_k) @@ -475,6 +461,7 @@ class WittVector_phantom(WittVector): sage: w = W.random_element() sage: TestSuite(w).run() """ + def __init__(self, parent, vec=None, phantom=None): """ Initialises ``self`` from the data. @@ -493,9 +480,7 @@ def __init__(self, parent, vec=None, phantom=None): base = R if isinstance(R, (PolynomialRing_generic, MPolynomialRing_base)): base = R.base() - base_lift = QqFP(base.cardinality(), prec=self._prec, - modulus=base.modulus(), names=(base.variable_name(),), - res_name=base.variable_name()) + base_lift = QqFP(base.cardinality(), prec=self._prec, modulus=base.modulus(), names=(base.variable_name(),), res_name=base.variable_name()) lift = base_lift if isinstance(R, (PolynomialRing_generic, MPolynomialRing_base)): lift = R.change_ring(base_lift) @@ -518,9 +503,7 @@ def __init__(self, parent, vec=None, phantom=None): self._phantom = self._prec * [y] elif isinstance(vec, (tuple, list, WittVector)): if len(vec) < self._prec: - raise ValueError(f"{vec} has not the correct length, " - "expected length has to be at least " - f"{self._prec}") + raise ValueError(f"{vec} has not the correct length, " "expected length has to be at least " f"{self._prec}") # We compute the phantom components self._coordinates = tuple(R(vec[i]) for i in range(self._prec)) x = [lift(v) for v in self._coordinates] @@ -528,7 +511,7 @@ def __init__(self, parent, vec=None, phantom=None): for n in range(1, self._prec): for i in range(n): x[i] = x[i] ** p - self._phantom.append(sum(x[i] * p**i for i in range(n+1))) + self._phantom.append(sum(x[i] * p**i for i in range(n + 1))) self._powers = None else: raise ValueError(f"{vec} cannot be interpreted as a Witt vector") @@ -547,7 +530,7 @@ def __getitem__(self, i): """ if i < 0 or i >= self._prec: raise IndexError("index out of the truncated Witt vector range") - self._compute_vector(i+1) + self._compute_vector(i + 1) return self._coordinates[i] def _add_(self, other): @@ -750,8 +733,7 @@ def phantom(self, lift=False): """ if lift: return tuple(self._phantom) - return tuple(self.parent().coefficient_ring()(x) - for x in self._phantom) + return tuple(self.parent().coefficient_ring()(x) for x in self._phantom) class WittVector_finotti(WittVector): @@ -769,6 +751,7 @@ class WittVector_finotti(WittVector): sage: w = W.random_element() sage: TestSuite(w).run() """ + def _add_(self, other): """ Return the sum of ``self`` and ``other``. @@ -823,14 +806,12 @@ def _mul_(self, other): return other from sage.rings.padics.witt_vector_ring import fast_char_p_power + p = P.prime() G = [[self[0] * other[0]]] for n in range(1, self._prec): - G_n = [fast_char_p_power(self[0], p**n) * other[n], - fast_char_p_power(other[0], p**n) * self[n]] - G_n.extend(fast_char_p_power(self[i], p**(n - i)) - * fast_char_p_power(other[n - i], p**i) - for i in range(1, n)) + G_n = [fast_char_p_power(self[0], p**n) * other[n], fast_char_p_power(other[0], p**n) * self[n]] + G_n.extend(fast_char_p_power(self[i], p ** (n - i)) * fast_char_p_power(other[n - i], p**i) for i in range(1, n)) G_n.extend(P._eta_bar(G[i], n - i) for i in range(n)) G.append(G_n) prod_vec = tuple(sum(G[i]) for i in range(self._prec)) @@ -854,6 +835,7 @@ class WittVector_pinvertible(WittVector): sage: TestSuite(w).run() """ + def _add_(self, other): """ Return the sum of ``self`` and ``other``. @@ -877,11 +859,7 @@ def _add_(self, other): p = P.prime() # we know p is a unit in this case! sum_vec = [self[0] + other[0]] for n in range(1, self._prec): - next_sum = self[n] + other[n] + \ - sum((self[i]**(p**(n - i)) + other[i]**(p**(n - i)) - - sum_vec[i]**(p**(n - i))) - / p**(n - i) - for i in range(n)) + next_sum = self[n] + other[n] + sum((self[i] ** (p ** (n - i)) + other[i] ** (p ** (n - i)) - sum_vec[i] ** (p ** (n - i))) / p ** (n - i) for i in range(n)) sum_vec.append(next_sum) return P(sum_vec) @@ -911,11 +889,7 @@ def _mul_(self, other): p = P.prime() # we know p is a unit in this case! prod_vec = [self[0] * other[0]] for n in range(1, self._prec): - next_prod = ( - sum(p**i * self[i]**(p**(n - i)) for i in range(n + 1)) * - sum(p**i * other[i]**(p**(n - i)) for i in range(n + 1)) - - sum(p**i * prod_vec[i]**(p**(n - i)) for i in range(n)) - ) / p**n + next_prod = (sum(p**i * self[i] ** (p ** (n - i)) for i in range(n + 1)) * sum(p**i * other[i] ** (p ** (n - i)) for i in range(n + 1)) - sum(p**i * prod_vec[i] ** (p ** (n - i)) for i in range(n))) / p**n prod_vec.append(next_prod) return P(prod_vec) @@ -936,6 +910,7 @@ class WittVector_standard(WittVector): sage: w = W.random_element() sage: TestSuite(w).run() """ + def _add_(self, other): """ Return the sum of ``self`` and ``other``. @@ -958,8 +933,7 @@ def _add_(self, other): s = P.sum_polynomials() # note here this is tuple addition, i.e. concatenation - sum_vec = tuple(s[i](*(self._coordinates + other.coordinates())) - for i in range(self._prec)) + sum_vec = tuple(s[i](*(self._coordinates + other.coordinates())) for i in range(self._prec)) return P(sum_vec) @@ -987,7 +961,6 @@ def _mul_(self, other): p = P.prod_polynomials() # note here this is tuple addition, i.e. concatenation - prod_vec = tuple(p[i](*(self._coordinates + other.coordinates())) - for i in range(self._prec)) + prod_vec = tuple(p[i](*(self._coordinates + other.coordinates())) for i in range(self._prec)) return P(prod_vec) diff --git a/src/sage/rings/padics/witt_vector_ring.py b/src/sage/rings/padics/witt_vector_ring.py index b9bbb9740f8..6a3a5595892 100644 --- a/src/sage/rings/padics/witt_vector_ring.py +++ b/src/sage/rings/padics/witt_vector_ring.py @@ -245,6 +245,7 @@ class WittVectorRing(Parent, UniqueRepresentation): sage: type(W) """ + def __classcall_private__(cls, coefficient_ring, prec=1, p=None, algorithm=None): r""" Construct the ring of truncated Witt vectors from the parameters. @@ -267,8 +268,7 @@ def __classcall_private__(cls, coefficient_ring, prec=1, p=None, algorithm=None) if p is None: if char not in Primes(): - raise ValueError(f"{coefficient_ring} has non-prime " - "characteristic and no prime was supplied") + raise ValueError(f"{coefficient_ring} has non-prime " "characteristic and no prime was supplied") p = char elif p not in Primes(): raise ValueError(f"p must be a prime number, here {p} was given") @@ -276,11 +276,7 @@ def __classcall_private__(cls, coefficient_ring, prec=1, p=None, algorithm=None) match algorithm: case None: if p == char: - if (coefficient_ring in Fields().Finite() - or isinstance(coefficient_ring, - PolynomialRing_generic) - and coefficient_ring.base() - in Fields().Finite()): + if coefficient_ring in Fields().Finite() or isinstance(coefficient_ring, PolynomialRing_generic) and coefficient_ring.base() in Fields().Finite(): child = WittVectorRing_phantom else: child = WittVectorRing_finotti @@ -297,8 +293,7 @@ def __classcall_private__(cls, coefficient_ring, prec=1, p=None, algorithm=None) case 'standard': child = WittVectorRing_standard case _: - raise ValueError("algorithm must be one of None, 'standard', " - "'p_invertible', 'finotti', 'phantom'") + raise ValueError("algorithm must be one of None, 'standard', " "'p_invertible', 'finotti', 'phantom'") return child.__classcall__(child, coefficient_ring, prec, p) @@ -329,8 +324,7 @@ def __init__(self, coefficient_ring, prec, prime, algorithm) -> None: if coefficient_ring.base_ring() is coefficient_ring: base = self else: - base = WittVectorRing(coefficient_ring.base_ring(), prec=prec, - p=prime, algorithm=algorithm) + base = WittVectorRing(coefficient_ring.base_ring(), prec=prec, p=prime, algorithm=algorithm) names = tuple('V' + x for x in coefficient_ring.variable_names()) @@ -351,7 +345,7 @@ def __iter__(self) -> Iterator: yield self(t) def _coerce_map_from_(self, S): - """" + """ " Check whether there is a coerce map from ``S``. EXAMPLES:: @@ -397,15 +391,8 @@ def _coerce_map_from_(self, S): sage: W.has_coerce_map_from(WittVectorRing(ZZ, p=3, prec=3)) # indirect doctest False """ - if (isinstance(S, WittVectorRing) - and S.precision() >= self._prec and S.prime() == self._prime - and self._coefficient_ring.has_coerce_map_from( - S.coefficient_ring())): - return (any(isinstance(S, rng) for rng in self._always_coerce) - or (S.precision() != self._prec - or S.coefficient_ring() is not self._coefficient_ring) - and any(isinstance(S, rng) - for rng in self._coerce_when_different)) + if isinstance(S, WittVectorRing) and S.precision() >= self._prec and S.prime() == self._prime and self._coefficient_ring.has_coerce_map_from(S.coefficient_ring()): + return any(isinstance(S, rng) for rng in self._always_coerce) or (S.precision() != self._prec or S.coefficient_ring() is not self._coefficient_ring) and any(isinstance(S, rng) for rng in self._coerce_when_different) if S is ZZ: return True @@ -442,7 +429,7 @@ def _generate_witt_polynomials(self, coefficient_ring, prec, p): # # Remark: Since when is SIXTEEN bits sufficient for anyone??? # - if p**(prec - 1) >= 2**16: + if p ** (prec - 1) >= 2**16: implementation = 'generic' else: implementation = 'singular' @@ -454,21 +441,19 @@ def _generate_witt_polynomials(self, coefficient_ring, prec, p): x_vars = x_y_vars[:prec] y_vars = x_y_vars[prec:] - self._sum_polynomials = [0]*(prec) + self._sum_polynomials = [0] * (prec) for n in range(prec): s_n = x_vars[n] + y_vars[n] for i in range(n): - s_n += ((x_vars[i]**(p**(n-i)) + y_vars[i]**(p**(n-i)) - - self._sum_polynomials[i]**(p**(n-i))) / p**(n-i)) + s_n += (x_vars[i] ** (p ** (n - i)) + y_vars[i] ** (p ** (n - i)) - self._sum_polynomials[i] ** (p ** (n - i))) / p ** (n - i) self._sum_polynomials[n] = R(s_n) - self._prod_polynomials = [x_vars[0] * y_vars[0]] + [0]*(prec-1) + self._prod_polynomials = [x_vars[0] * y_vars[0]] + [0] * (prec - 1) for n in range(1, prec): - x_poly = sum([p**i * x_vars[i]**(p**(n-i)) for i in range(n+1)]) - y_poly = sum([p**i * y_vars[i]**(p**(n-i)) for i in range(n+1)]) - p_poly = sum([p**i * self._prod_polynomials[i]**(p**(n-i)) - for i in range(n)]) - p_n = (x_poly*y_poly - p_poly) // p**n + x_poly = sum([p**i * x_vars[i] ** (p ** (n - i)) for i in range(n + 1)]) + y_poly = sum([p**i * y_vars[i] ** (p ** (n - i)) for i in range(n + 1)]) + p_poly = sum([p**i * self._prod_polynomials[i] ** (p ** (n - i)) for i in range(n)]) + p_n = (x_poly * y_poly - p_poly) // p**n self._prod_polynomials[n] = p_n R = PolynomialRing(ZZ, x_var_names, implementation=implementation) @@ -476,19 +461,18 @@ def _generate_witt_polynomials(self, coefficient_ring, prec, p): self._frob_polynomials = [] if not prec.is_one(): - self._frob_polynomials = [x_vars[0]**p + p*x_vars[1]] + self._frob_polynomials = [x_vars[0] ** p + p * x_vars[1]] for n in range(2, prec): - x_poly = sum([p**i * x_vars[i]**(p**(n-i)) for i in range(n+1)]) - p_poly = sum([p**i * self._frob_polynomials[i]**(p**(n-1-i)) - for i in range(n-1)]) - self._frob_polynomials.append((x_poly - p_poly) / p**(n-1)) + x_poly = sum([p**i * x_vars[i] ** (p ** (n - i)) for i in range(n + 1)]) + p_poly = sum([p**i * self._frob_polynomials[i] ** (p ** (n - 1 - i)) for i in range(n - 1)]) + self._frob_polynomials.append((x_poly - p_poly) / p ** (n - 1)) S = PolynomialRing(coefficient_ring, x_y_vars) for n in range(prec): self._sum_polynomials[n] = S(self._sum_polynomials[n]) self._prod_polynomials[n] = S(self._prod_polynomials[n]) S = PolynomialRing(coefficient_ring, x_vars) - for n in range(prec-1): + for n in range(prec - 1): self._frob_polynomials[n] = S(self._frob_polynomials[n]) def _latex_(self) -> str: @@ -506,8 +490,7 @@ def _latex_(self) -> str: sage: latex(W) W_{1}\left(\Bold{F}_{3}[t]\right) """ - return "W_{%s}\\left(%s\\right)" % (latex(self._prec), - latex(self._coefficient_ring)) + return "W_{%s}\\left(%s\\right)" % (latex(self._prec), latex(self._coefficient_ring)) def _repr_(self) -> str: """ @@ -518,8 +501,7 @@ def _repr_(self) -> str: sage: WittVectorRing(QQ, p=2, prec=5) Ring of truncated 2-typical Witt vectors of length 5 over Rational Field """ - return f"Ring of truncated {self._prime}-typical Witt vectors of "\ - f"length {self._prec} over {self._coefficient_ring}" + return f"Ring of truncated {self._prime}-typical Witt vectors of " f"length {self._prec} over {self._coefficient_ring}" def cardinality(self): """ @@ -532,7 +514,7 @@ def cardinality(self): sage: WittVectorRing(QQ, p=2).cardinality() +Infinity """ - return self._coefficient_ring.cardinality()**(self._prec) + return self._coefficient_ring.cardinality() ** (self._prec) def characteristic(self): """ @@ -554,7 +536,7 @@ def characteristic(self): # This is Jacob Dennerlein's Corollary 3.3. in "Computational # Aspects of Mixed Characteristic Witt Vectors" (preprint) - return p**(self._prec-1) * self._coefficient_ring.characteristic() + return p ** (self._prec - 1) * self._coefficient_ring.characteristic() def coefficient_ring(self): """ @@ -620,12 +602,11 @@ def frobenius_polynomials(self, variables=None): [T0^3 + 3*T1, -3*T0^6*T1 - 9*T0^3*T1^2 - 8*T1^3 + 3*T2] """ if not hasattr(self, '_frob_polynomials'): - self._generate_witt_polynomials(self._coefficient_ring, self._prec, - self._prime) + self._generate_witt_polynomials(self._coefficient_ring, self._prec, self._prime) if variables is None: return self._frob_polynomials.copy() R = PolynomialRing(self._coefficient_ring, variables) - return [R(self._frob_polynomials[i]) for i in range(self._prec-1)] + return [R(self._frob_polynomials[i]) for i in range(self._prec - 1)] def gen(self, n=0): """ @@ -782,8 +763,7 @@ def is_integral_domain(self, proof=True): sage: W.is_integral_domain(proof=False) False """ - return (self._prec.is_one() and - self._coefficient_ring.is_integral_domain(proof=proof)) + return self._prec.is_one() and self._coefficient_ring.is_integral_domain(proof=proof) def is_integrally_closed(self): """ @@ -806,8 +786,7 @@ def is_integrally_closed(self): ... NotImplementedError """ - return (self._prec.is_one() and - self._coefficient_ring.is_integrally_closed()) + return self._prec.is_one() and self._coefficient_ring.is_integrally_closed() def is_prime_field(self): r""" @@ -917,8 +896,7 @@ def prod_polynomials(self, variables=None): [T0*U0, T1*U0^2 + T0^2*U1 + 2*T1*U1] """ if not hasattr(self, '_prod_polynomials'): - self._generate_witt_polynomials(self._coefficient_ring, self._prec, - self._prime) + self._generate_witt_polynomials(self._coefficient_ring, self._prec, self._prime) if variables is None: return self._prod_polynomials.copy() R = PolynomialRing(self._coefficient_ring, variables) @@ -941,8 +919,7 @@ def random_element(self, *args, **kwds): (x^5 - 2*x^4 - 4*x^3 - 2*x^2 + 1, -x^5 + 2*x^4 - x - 1, -x^5 + 7*x^4 + 3*x^3 - 24*x^2 - 1) """ - return self(tuple(self._coefficient_ring.random_element(*args, **kwds) - for _ in range(self._prec))) + return self(tuple(self._coefficient_ring.random_element(*args, **kwds) for _ in range(self._prec))) def sum_polynomials(self, variables=None): """ @@ -968,8 +945,7 @@ def sum_polynomials(self, variables=None): -X0^3*Y0 - 2*X0^2*Y0^2 - X0*Y0^3 + X0*X1*Y0 + X0*Y0*Y1 - X1*Y1 + X2 + Y2] """ if not hasattr(self, '_sum_polynomials'): - self._generate_witt_polynomials(self._coefficient_ring, self._prec, - self._prime) + self._generate_witt_polynomials(self._coefficient_ring, self._prec, self._prime) if variables is None: return self._sum_polynomials.copy() R = PolynomialRing(self._coefficient_ring, variables) @@ -988,7 +964,7 @@ def teichmuller_lift(self, x): """ if x not in self._coefficient_ring: raise TypeError(f"{x} not in {self._coefficient_ring}") - return self((x,) + tuple(0 for _ in range(self._prec-1))) + return self((x,) + tuple(0 for _ in range(self._prec - 1))) def verschiebung(self, extend=False): """ @@ -1035,6 +1011,7 @@ class WittVectorRing_finotti(WittVectorRing): ... ValueError: the 'finotti' algorithm only works for coefficients rings of characteristic p """ + Element = WittVector_finotti def __init__(self, coefficient_ring, prec, prime) -> None: @@ -1052,24 +1029,21 @@ def __init__(self, coefficient_ring, prec, prime) -> None: sage: TestSuite(W).run() """ if coefficient_ring.characteristic() != prime: - raise ValueError("the 'finotti' algorithm only works for " - "coefficients rings of characteristic p") + raise ValueError("the 'finotti' algorithm only works for " "coefficients rings of characteristic p") if isinstance(coefficient_ring, MPolynomialRing_base): - self._always_coerce = [WittVectorRing_finotti, - WittVectorRing_phantom, - WittVectorRing_standard] + self._always_coerce = [WittVectorRing_finotti, WittVectorRing_phantom, WittVectorRing_standard] self._coerce_when_different = [] else: - self._always_coerce = [WittVectorRing_finotti, - WittVectorRing_standard] + self._always_coerce = [WittVectorRing_finotti, WittVectorRing_standard] self._coerce_when_different = [WittVectorRing_phantom] import numpy as np - R = Zp(prime, prec=prec+1, type='fixed-mod') + + R = Zp(prime, prec=prec + 1, type='fixed-mod') v_p = ZZ.valuation(prime) table = [[0]] - for k in range(1, prec+1): + for k in range(1, prec + 1): pk = prime**k row = np.empty(pk, dtype=int) row[0] = 0 @@ -1078,9 +1052,9 @@ def __init__(self, coefficient_ring, prec, prime) -> None: val = v_p(i) # Instead of calling binomial each time, we compute the # coefficients recursively. This is MUCH faster. - next_bin = prev_bin * (pk - (i-1)) // i + next_bin = prev_bin * (pk - (i - 1)) // i prev_bin = next_bin - series = R(-next_bin // prime**(k-val)) + series = R(-next_bin // prime ** (k - val)) for _ in range(val): temp = series % prime series = (series - R.teichmuller(temp)) // prime @@ -1118,22 +1092,18 @@ def _eta_bar(self, vec, eta_index): if len(vec) == 2: # Here we have to check if we've pre-computed already x, y = vec - scriptN = [[None] for _ in range(k+1)] # each list starts with + scriptN = [[None] for _ in range(k + 1)] # each list starts with # None, so that indexing matches paper # calculate first N_t scriptN's - for t in range(1, k+1): + for t in range(1, k + 1): for i in range(1, p**t): - scriptN[t].append(self._binomial_table[t][i] - * fast_char_p_power(x, i) - * fast_char_p_power(y, p**t - i)) - indexN = [p**i - 1 for i in range(k+1)] - for t in range(2, k+1): + scriptN[t].append(self._binomial_table[t][i] * fast_char_p_power(x, i) * fast_char_p_power(y, p**t - i)) + indexN = [p**i - 1 for i in range(k + 1)] + for t in range(2, k + 1): for i in range(1, t): # append scriptN_{t, N_t+l} - next_scriptN = self._eta_bar( - scriptN[t-i][1:indexN[t-i]+t-i], i - ) + next_scriptN = self._eta_bar(scriptN[t - i][1 : indexN[t - i] + t - i], i) scriptN[t].append(next_scriptN) return sum(scriptN[k][1:]) @@ -1144,14 +1114,14 @@ def _eta_bar(self, vec, eta_index): v_2 = vec[m:] s_1 = sum(v_1) s_2 = sum(v_2) - scriptM = [[] for _ in range(k+1)] - for t in range(1, k+1): + scriptM = [[] for _ in range(k + 1)] + for t in range(1, k + 1): scriptM[t].append(self._eta_bar(v_1, t)) scriptM[t].append(self._eta_bar(v_2, t)) scriptM[t].append(self._eta_bar((s_1, s_2), t)) - for t in range(2, k+1): + for t in range(2, k + 1): for s in range(1, t): - result = self._eta_bar(scriptM[t-s], s) + result = self._eta_bar(scriptM[t - s], s) scriptM[t].append(result) return sum(scriptM[k]) @@ -1176,6 +1146,7 @@ class WittVectorRing_phantom(WittVectorRing): ... ValueError: the 'phantom' algorithm only works when the coefficient ring is a finite field of char. p, or a polynomial ring on that field """ + Element = WittVector_phantom def __init__(self, coefficient_ring, prec, prime) -> None: @@ -1192,28 +1163,19 @@ def __init__(self, coefficient_ring, prec, prime) -> None: sage: TestSuite(W).run() """ - msg = "the 'phantom' algorithm only works when the coefficient ring is"\ - " a finite field of char. p, or a polynomial ring on that field" + msg = "the 'phantom' algorithm only works when the coefficient ring is" " a finite field of char. p, or a polynomial ring on that field" if coefficient_ring.characteristic() != prime: raise ValueError(msg) - if not (coefficient_ring in Fields().Finite() or - (isinstance(coefficient_ring, (PolynomialRing_generic, - MPolynomialRing_base)) and - coefficient_ring.base() in Fields().Finite())): + if not (coefficient_ring in Fields().Finite() or (isinstance(coefficient_ring, (PolynomialRing_generic, MPolynomialRing_base)) and coefficient_ring.base() in Fields().Finite())): raise ValueError(msg) - if (coefficient_ring in Fields().Finite() - or isinstance(coefficient_ring, - PolynomialRing_generic)): - self._always_coerce = [WittVectorRing_finotti, - WittVectorRing_phantom, - WittVectorRing_standard] + if coefficient_ring in Fields().Finite() or isinstance(coefficient_ring, PolynomialRing_generic): + self._always_coerce = [WittVectorRing_finotti, WittVectorRing_phantom, WittVectorRing_standard] self._coerce_when_different = [] else: - self._always_coerce = [WittVectorRing_phantom, - WittVectorRing_standard] + self._always_coerce = [WittVectorRing_phantom, WittVectorRing_standard] self._coerce_when_different = [WittVectorRing_finotti] super().__init__(coefficient_ring, prec, prime, "phantom") @@ -1239,6 +1201,7 @@ class WittVectorRing_pinvertible(WittVectorRing): ... ValueError: the 'p_invertible' algorithm only works when p is a unit in the ring of coefficients """ + Element = WittVector_pinvertible def __init__(self, coefficient_ring, prec, prime) -> None: @@ -1256,11 +1219,9 @@ def __init__(self, coefficient_ring, prec, prime) -> None: sage: TestSuite(W).run() """ if not coefficient_ring(prime).is_unit(): - raise ValueError("the 'p_invertible' algorithm only works when p " - "is a unit in the ring of coefficients") + raise ValueError("the 'p_invertible' algorithm only works when p " "is a unit in the ring of coefficients") - self._always_coerce = [WittVectorRing_pinvertible, - WittVectorRing_standard] + self._always_coerce = [WittVectorRing_pinvertible, WittVectorRing_standard] self._coerce_when_different = [] super().__init__(coefficient_ring, prec, prime, "p_invertible") @@ -1281,6 +1242,7 @@ class WittVectorRing_standard(WittVectorRing): sage: W Ring of truncated 3-typical Witt vectors of length 3 over Finite Field of size 3 """ + Element = WittVector_standard def __init__(self, coefficient_ring, prec, prime) -> None: @@ -1334,6 +1296,7 @@ class WittVectorFrobeniusMorphism(RingHomomorphism): sage: TestSuite(frob).run(skip="_test_category") """ + def __init__(self, domain, truncate=False): """ INPUT: @@ -1382,8 +1345,7 @@ def __init__(self, domain, truncate=False): prec = domain.precision() if prec.is_one(): - raise ValueError("the ring of Witt vectors must have " - "precision at least 2 when truncate=True") + raise ValueError("the ring of Witt vectors must have " "precision at least 2 when truncate=True") if isinstance(domain, WittVectorRing_finotti): algorithm = "finotti" @@ -1398,8 +1360,7 @@ def __init__(self, domain, truncate=False): algorithm = "standard" self._call_ = self._call_standard - codomain = WittVectorRing(coeff_ring, prec=prec-1, - p=domain.prime(), algorithm=algorithm) + codomain = WittVectorRing(coeff_ring, prec=prec - 1, p=domain.prime(), algorithm=algorithm) super().__init__(Hom(domain, codomain)) @@ -1488,8 +1449,7 @@ def _call_standard(self, x): """ W = self.domain() Wcod = self.codomain() - return Wcod([W.frobenius_polynomials()[i](x.coordinates()) - for i in range(Wcod.precision())]) + return Wcod([W.frobenius_polynomials()[i](x.coordinates()) for i in range(Wcod.precision())]) def _latex_(self) -> str: r""" @@ -1521,8 +1481,7 @@ def _repr_(self) -> str: """ if self.domain() is self.codomain(): return f"Frobenius endomorphism on the {self.domain()}" - return f"Frobenius homomorphism from the {self.domain()} to the "\ - f"{self.codomain()}" + return f"Frobenius homomorphism from the {self.domain()} to the " f"{self.codomain()}" class WittVectorVerschiebung(RingMap): @@ -1547,6 +1506,7 @@ class WittVectorVerschiebung(RingMap): sage: TestSuite(V).run(skip="_test_category") """ + def __init__(self, domain, extend=False): """ INPUT: @@ -1595,8 +1555,7 @@ def __init__(self, domain, extend=False): self._call_ = self._call_extend algorithm = "standard" - codomain = WittVectorRing(domain.coefficient_ring(), prec=prec+1, - p=domain.prime(), algorithm=algorithm) + codomain = WittVectorRing(domain.coefficient_ring(), prec=prec + 1, p=domain.prime(), algorithm=algorithm) else: if isinstance(domain, WittVectorRing_phantom): @@ -1668,8 +1627,7 @@ def _call_phantom_extend(self, x): Wcod = self.codomain() p = Wcod.prime() phantom = x.phantom(lift=True) - return Wcod(phantom=((phantom[0].parent().zero(),) - + tuple(p*c for c in phantom))) + return Wcod(phantom=((phantom[0].parent().zero(),) + tuple(p * c for c in phantom))) def _call_phantom_no_extend(self, x): """ @@ -1691,8 +1649,7 @@ def _call_phantom_no_extend(self, x): W = self.domain() p = W.prime() phantom = x.phantom(lift=True) - return W(phantom=((phantom[0].parent().zero(),) - + tuple(p*c for c in phantom[:-1]))) + return W(phantom=((phantom[0].parent().zero(),) + tuple(p * c for c in phantom[:-1]))) def _latex_(self) -> str: r""" @@ -1723,5 +1680,4 @@ def _repr_(self) -> str: """ if self.domain() is self.codomain(): return f"Verschiebung map on the {self.domain()}" - return f"Verschiebung map from the {self.domain()} to the "\ - f"{self.codomain()}" + return f"Verschiebung map from the {self.domain()} to the " f"{self.codomain()}" diff --git a/src/sage/rings/pari_ring.py b/src/sage/rings/pari_ring.py index b27e22e06e6..e31baf26402 100644 --- a/src/sage/rings/pari_ring.py +++ b/src/sage/rings/pari_ring.py @@ -7,6 +7,7 @@ - Simon King (2011-08-24): Use UniqueRepresentation, element_class and proper initialisation of elements. """ + # **************************************************************************** # Copyright (C) 2004 William Stein # @@ -28,6 +29,7 @@ class Pari(RingElement): """ Element of Pari pseudo-ring. """ + def __init__(self, x, parent=None) -> None: """ EXAMPLES:: @@ -126,7 +128,7 @@ def __pow__(self, other): """ if other not in PariRing(): other = Pari(other) - return self.__class__(self.__x ** other.__x, parent=_inst) + return self.__class__(self.__x**other.__x, parent=_inst) def __invert__(self): """ @@ -168,6 +170,7 @@ class PariRing(Singleton, Parent): sage: loads(R.dumps()) is R True """ + Element = Pari def __init__(self): @@ -216,6 +219,7 @@ def random_element(self, x=None, y=None, distribution=None): True """ from sage.rings.integer_ring import ZZ + return self(ZZ.random_element(x, y, distribution)) def zeta(self): diff --git a/src/sage/rings/polynomial/all.py b/src/sage/rings/polynomial/all.py index f2295443420..c17202a208f 100644 --- a/src/sage/rings/polynomial/all.py +++ b/src/sage/rings/polynomial/all.py @@ -1,6 +1,7 @@ """ Polynomials """ + # **************************************************************************** # Copyright (C) 2005 William Stein # @@ -39,6 +40,7 @@ # Laurent Polynomial Rings from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + lazy_import('sage.rings.polynomial.omega', 'MacMahonOmega') # Infinite Polynomial Rings @@ -52,7 +54,5 @@ from sage.rings.polynomial.cyclotomic import cyclotomic_value # Integer-valued Univariate Polynomial Ring -lazy_import('sage.rings.polynomial.integer_valued_polynomials', - 'IntegerValuedPolynomialRing') -lazy_import('sage.rings.polynomial.q_integer_valued_polynomials', - 'QuantumValuedPolynomialRing') +lazy_import('sage.rings.polynomial.integer_valued_polynomials', 'IntegerValuedPolynomialRing') +lazy_import('sage.rings.polynomial.q_integer_valued_polynomials', 'QuantumValuedPolynomialRing') diff --git a/src/sage/rings/polynomial/binary_form_reduce.py b/src/sage/rings/polynomial/binary_form_reduce.py index 55564bf5c0c..3961498d5c3 100644 --- a/src/sage/rings/polynomial/binary_form_reduce.py +++ b/src/sage/rings/polynomial/binary_form_reduce.py @@ -174,19 +174,18 @@ def covariant_z0(F, z0_cov=False, prec=53, emb=None, error_limit=0.000001): PR = PolynomialRing(K, 'x,y') x, y = PR.gens() # finds Stoll and Cremona's Q_0 - q = sum([(1/(dF(r).abs()**(2/(n-2)))) * ((x-(r*y)) * (x-(r.conjugate()*y))) - for r in roots]) + q = sum([(1 / (dF(r).abs() ** (2 / (n - 2)))) * ((x - (r * y)) * (x - (r.conjugate() * y))) for r in roots]) # this is Q_0 , always positive def as long as F has distinct roots A = q.monomial_coefficient(x**2) B = q.monomial_coefficient(x * y) C = q.monomial_coefficient(y**2) # need positive root try: - z = ((-B + ((B**2)-(4*A*C)).sqrt()) / (2 * A)) + z = (-B + ((B**2) - (4 * A * C)).sqrt()) / (2 * A) except ValueError: raise ValueError("not enough precision") if z.imag() < 0: - z = (-B - ((B**2)-(4*A*C)).sqrt()) / (2 * A) + z = (-B - ((B**2) - (4 * A * C)).sqrt()) / (2 * A) if z0_cov: FM = f # for Julia's invariant @@ -196,6 +195,7 @@ def covariant_z0(F, z0_cov=False, prec=53, emb=None, error_limit=0.000001): z = CF(z) FM = F(list(mat * vector(R.gens()))).subs({R.gen(1): 1}).univariate_polynomial() from sage.rings.polynomial.complex_roots import complex_roots + L1 = complex_roots(FM, min_prec=prec) L = [] # making sure multiplicity isn't too large using convergence conditions in paper @@ -208,7 +208,7 @@ def covariant_z0(F, z0_cov=False, prec=53, emb=None, error_limit=0.000001): c = RCF.zero() u, t = RCF.gens() for l in L: - denom = ((t - l) * (t - l.conjugate()) + u**2) + denom = (t - l) * (t - l.conjugate()) + u**2 a += u**2 / denom c += (t - l.real()) / denom # Newton's Method, to find solutions. Error bound is less than diameter of our z @@ -225,13 +225,12 @@ def covariant_z0(F, z0_cov=False, prec=53, emb=None, error_limit=0.000001): NJinv = NJ.inverse() # inverse for CIF matrix seems to return fractions not CIF elements, fix them if NJinv.base_ring() != CF: - NJinv = matrix(CF, 2, 2, [CF(zw.numerator() / zw.denominator()) - for zw in NJinv.list()]) + NJinv = matrix(CF, 2, 2, [CF(zw.numerator() / zw.denominator()) for zw in NJinv.list()]) w = z - v0 = v0 - NJinv*G.subs({u: v0[0], t: v0[1]}) - z = v0[1].constant_coefficient() + v0[0].constant_coefficient()*CF.gen(0) - err = z.diameter() # precision - zz = (w - z).abs().lower() # difference in w and z + v0 = v0 - NJinv * G.subs({u: v0[0], t: v0[1]}) + z = v0[1].constant_coefficient() + v0[0].constant_coefficient() * CF.gen(0) + err = z.diameter() # precision + zz = (w - z).abs().lower() # difference in w and z # despite there is no break, this happens if err > error_limit or err.is_NaN(): raise ValueError("accuracy of Newton's root not within tolerance(%s > %s), increase precision" % (err, error_limit)) @@ -244,10 +243,10 @@ def covariant_z0(F, z0_cov=False, prec=53, emb=None, error_limit=0.000001): FM = FM.change_ring(ComplexField(prec=prec)) tF = z.real() uF = z.imag() - th = FM.lc().abs()**2 + th = FM.lc().abs() ** 2 for r, ex in FM.roots(): for _ in range(ex): - th = th * ((((r-tF).abs())**2 + uF**2)/uF) + th = th * ((((r - tF).abs()) ** 2 + uF**2) / uF) # undo shift and invert (if needed) # since F \cdot m ~ m^(-1)\cdot z @@ -290,6 +289,7 @@ def epsinv(F, target, prec=53, target_tol=0.001, z=None, emb=None): sage: epsinv(-2*x^3 + 2*x^2*y + 3*x*y^2 + 127*y^3, 31.5022020249597) # tol 1e-12 4.02520895942207 """ + def RQ(delta): # this is the quotient R(F_0,z)/R(F_0,z(F)) for a generic z # at distance delta from j. See Lemma 4.2 in [HS2018]. @@ -301,8 +301,7 @@ def epsF(delta): pol = RQ(delta) # get R quotient in terms of z S = PolynomialRing(C, 'v') g = S([(i - d) * pol[i - d] for i in range(2 * d + 1)]) # take derivative - drts = [e for e in g.roots(ring=C, multiplicities=False) - if (e.norm() - 1).abs() < 0.1] + drts = [e for e in g.roots(ring=C, multiplicities=False) if (e.norm() - 1).abs() < 0.1] # find min return min([pol(r / r.abs()).real() for r in drts]) @@ -319,8 +318,7 @@ def epsF(delta): f = F.subs({R.gen(1): 1}).univariate_polynomial() # now we have a single variable polynomial - if (max(ex for p, ex in f.roots(ring=C)) >= QQ(d)/2 or - f.degree() < QQ(d)/2): + if max(ex for p, ex in f.roots(ring=C)) >= QQ(d) / 2 or f.degree() < QQ(d) / 2: raise ValueError('cannot have root with multiplicity >= deg(F)/2') R = RealField(prec=prec) @@ -329,18 +327,18 @@ def epsF(delta): # compute phi_1, ..., phi_k # first find F_0 and its roots # this change of variables on f moves z(f) to j, i.e. produces F_0 - rts = f(z.imag()*t + z.real()).roots(ring=C) + rts = f(z.imag() * t + z.real()).roots(ring=C) phis = [] # stereographic projection of roots for r, e in rts: - phis.extend([[2*r.real()/(r.norm()+1), (r.norm()-1)/(r.norm()+1)]]) + phis.extend([[2 * r.real() / (r.norm() + 1), (r.norm() - 1) / (r.norm() + 1)]]) if d != f.degree(): # include roots at infinity phis.extend([(d - f.degree()) * [0, 1]]) # for writing RQ in terms of generic z to minimize LC = LaurentSeriesRing(C, 'u', default_prec=2 * d + 2) u = LC.gen(0) - cost = (u + u**(-1)) / 2 - sint = (u - u**(-1)) / (2 * C.gen(0)) + cost = (u + u ** (-1)) / 2 + sint = (u - u ** (-1)) / (2 * C.gen(0)) # first find an interval containing the desired value # then use regula falsi on log eps_F @@ -360,7 +358,7 @@ def epsF(delta): logt = target.log() l2 = (vu.log() - logt).n(prec=prec) l1 = (vl.log() - logt).n(prec=prec) - dn = (dl*l2 - du*l1)/(l2 - l1) + dn = (dl * l2 - du * l1) / (l2 - l1) vn = epsF(dn) dl = du vl = vu @@ -416,16 +414,16 @@ def get_bound_poly(F, prec=53, norm_type='norm', emb=None): else: compF = F n = F.degree() - assert (n > 2), "degree 2 polynomial" + assert n > 2, "degree 2 polynomial" z0F, thetaF = covariant_z0(compF, prec=prec, emb=emb) if norm_type == 'norm': # euclidean norm squared - normF = (sum([abs(i)**2 for i in compF.coefficients()])) - target = (2**(n - 1)) * normF / thetaF + normF = sum([abs(i) ** 2 for i in compF.coefficients()]) + target = (2 ** (n - 1)) * normF / thetaF elif norm_type == 'height': hF = exp(max([c.global_height(prec=prec) for c in F.coefficients()])) # height - target = (2**(n - 1)) * (n + 1) * (hF**2) / thetaF + target = (2 ** (n - 1)) * (n + 1) * (hF**2) / thetaF else: raise ValueError('type must be norm or height') return cosh(epsinv(F, target, prec=prec)) @@ -497,6 +495,7 @@ def smallest_poly(F, prec=53, norm_type='norm', emb=None): -x^5*y^2 - 24*x^3*y^4 - 3*x^2*y^5 - 2*x*y^6 + 16*y^7, [ 1 0] ) """ + def insert_item(pts, item, index): # binary insertion to maintain list of points left to consider N = len(pts) @@ -519,12 +518,13 @@ def insert_item(pts, item, index): def coshdelta(z): # The cosh of the hyperbolic distance from z = t+uj to j - return (z.norm() + 1)/(2*z.imag()) # reduce in the sense of Cremona-Stoll + return (z.norm() + 1) / (2 * z.imag()) # reduce in the sense of Cremona-Stoll + G = F MG = matrix(ZZ, 2, 2, [1, 0, 0, 1]) x, y = G.parent().gens() if norm_type == 'norm': - current_size = sum([abs(i)**2 for i in G.coefficients()]) # euclidean norm squared + current_size = sum([abs(i) ** 2 for i in G.coefficients()]) # euclidean norm squared elif norm_type == 'height': # height current_size = exp(max([c.global_height(prec=prec) for c in G.coefficients()])) else: @@ -532,6 +532,7 @@ def coshdelta(z): v0, th = covariant_z0(G, prec=prec, emb=emb) rep = 2 * CC.gen(0) # representative point in fundamental domain from math import isnan + if isnan(v0.abs()): raise ValueError("invalid covariant: %s" % v0) R = get_bound_poly(G, prec=prec, norm_type=norm_type) @@ -552,7 +553,7 @@ def coshdelta(z): # check if it is smaller. If so, we can improve the bound count += 1 if norm_type == 'norm': - new_size = sum([abs(i)**2 for i in G.coefficients()]) # euclidean norm squared + new_size = sum([abs(i) ** 2 for i in G.coefficients()]) # euclidean norm squared else: # height new_size = exp(max([c.global_height(prec=prec) for c in G.coefficients()])) if new_size < current_size: @@ -561,19 +562,19 @@ def coshdelta(z): R = get_bound_poly(G, norm_type=norm_type, prec=prec, emb=emb) # add new points to check - if label != 1 and min((rep+1).norm(), (rep-1).norm()) >= 1: # don't undo S + if label != 1 and min((rep + 1).norm(), (rep - 1).norm()) >= 1: # don't undo S # the 2nd condition is equivalent to |\Re(-1/rep)| <= 1/2 # this means that rep can have resulted from an inversion step in # the shift-and-invert procedure, so don't invert # do inversion z = -1 / v - new_pt = [G.subs({x: -y, y: x}), z, -1/rep, M*S, coshdelta(z), 1] + new_pt = [G.subs({x: -y, y: x}), z, -1 / rep, M * S, coshdelta(z), 1] pts = insert_item(pts, new_pt, 4) if label != 3: # don't undo TI # do right shift z = v - 1 - new_pt = [G.subs({x: x + y}), z, rep-1, M*T, coshdelta(z), 2] + new_pt = [G.subs({x: x + y}), z, rep - 1, M * T, coshdelta(z), 2] pts = insert_item(pts, new_pt, 4) if label != 2: # don't undo T # do left shift diff --git a/src/sage/rings/polynomial/complex_roots.py b/src/sage/rings/polynomial/complex_roots.py index eca937fc68a..8cef4a83831 100644 --- a/src/sage/rings/polynomial/complex_roots.py +++ b/src/sage/rings/polynomial/complex_roots.py @@ -28,7 +28,7 @@ (0.181232444469876? + 1.083954101317711?*I, 1)] """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2007 Carl Witty # # This program is free software: you can redistribute it and/or modify @@ -36,7 +36,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from copy import copy @@ -126,12 +126,12 @@ def column_disjoint(): def row_disjoint(): for a in range(len(row)): - for b in range(a+1, len(row)): + for b in range(a + 1, len(row)): if row[a].overlaps(row[b]): return False return True - for (y_imag, y) in column: + for y_imag, y in column: if prev_imag is not None and y_imag > prev_imag: if not row_disjoint(): return False @@ -270,7 +270,7 @@ def complex_roots(p, skip_squarefree=False, retval='interval', min_prec=0): all_rts = [] ok = True - for (factor, exp) in factors: + for factor, exp in factors: cfac = CCX(factor) rts = cfac.roots(multiplicities=False) # Make sure the number of roots we found is the degree. If @@ -297,7 +297,7 @@ def complex_roots(p, skip_squarefree=False, retval='interval', min_prec=0): return [(QQbar.polynomial_root(fac, rt), mult) for (rt, fac, mult) in all_rts] if retval == 'algebraic_real': rts = [] - for (rt, fac, mult) in all_rts: + for rt, fac, mult in all_rts: qqbar_rt = QQbar.polynomial_root(fac, rt) if qqbar_rt.imag().is_zero(): rts.append((AA(qqbar_rt), mult)) diff --git a/src/sage/rings/polynomial/convolution.py b/src/sage/rings/polynomial/convolution.py index 89dfc55b53d..b5ed0ac63ba 100644 --- a/src/sage/rings/polynomial/convolution.py +++ b/src/sage/rings/polynomial/convolution.py @@ -39,6 +39,7 @@ - William Stein: editing the docstrings for inclusion in Sage. """ + # **************************************************************************** # Copyright (C) 2007 William Stein # David Harvey @@ -78,7 +79,7 @@ def convolution(L1, L2): """ if not L1 or not L2: raise ValueError("cannot compute convolution of empty lists") - if len(L1) <= 100 and len(L2) <= 100: # very arbitrary cutoff + if len(L1) <= 100 and len(L2) <= 100: # very arbitrary cutoff return _convolution_naive(L1, L2) return _convolution_fft(L1, L2) @@ -112,9 +113,7 @@ def _convolution_naive(L1, L2): m1 = len(L1) m2 = len(L2) - return [sum([L1[i] * L2[k - i] - for i in range(max(0, k - m2 + 1), min(k + 1, m1))]) - for k in range(m1 + m2 - 1)] + return [sum([L1[i] * L2[k - i] for i in range(max(0, k - m2 + 1), min(k + 1, m1))]) for k in range(m1 + m2 - 1)] def _negaconvolution_naive(L1, L2): @@ -138,9 +137,7 @@ def _negaconvolution_naive(L1, L2): assert len(L1) == len(L2) N = len(L1) - return [sum([L1[i] * L2[j - i] for i in range(j + 1)]) - - sum([L1[i] * L2[N + j - i] - for i in range(j + 1, N)]) for j in range(N)] + return [sum([L1[i] * L2[j - i] for i in range(j + 1)]) - sum([L1[i] * L2[N + j - i] for i in range(j + 1, N)]) for j in range(N)] # ------------------------------------------------------------------- @@ -158,10 +155,7 @@ def _forward_butterfly(L1, L2, r): assert 0 <= r <= len(L1) K = len(L1) - return [L1[i] - L2[i + K - r] for i in range(r)] + \ - [L1[i] + L2[i - r] for i in range(r, K)], \ - [L1[i] + L2[i + K - r] for i in range(r)] + \ - [L1[i] - L2[i - r] for i in range(r, K)] + return [L1[i] - L2[i + K - r] for i in range(r)] + [L1[i] + L2[i - r] for i in range(r, K)], [L1[i] + L2[i + K - r] for i in range(r)] + [L1[i] - L2[i - r] for i in range(r, K)] def _inverse_butterfly(L1, L2, r): @@ -175,9 +169,7 @@ def _inverse_butterfly(L1, L2, r): assert 0 <= r <= len(L1) K = len(L1) - return [L1[i] + L2[i] for i in range(K)], \ - [L1[i] - L2[i] for i in range(r, K)] + \ - [L2[i] - L1[i] for i in range(r)] + return [L1[i] + L2[i] for i in range(K)], [L1[i] - L2[i] for i in range(r, K)] + [L2[i] - L1[i] for i in range(r)] def _fft(L, K, start, depth, root): @@ -199,8 +191,7 @@ def _fft(L, K, start, depth, root): # reduce mod (x^(D/2) - y^root) and mod (x^(D/2) + y^root) for i in range(half): - L[start + i], L[start2 + i] = \ - _forward_butterfly(L[start + i], L[start2 + i], root) + L[start + i], L[start2 + i] = _forward_butterfly(L[start + i], L[start2 + i], root) # recurse into each half if depth >= 2: @@ -223,8 +214,8 @@ def _ifft(L, K, start, depth, root): # CRT together (x^(D/2) - y^root) and mod (x^(D/2) + y^root) for i in range(half): - L[start + i], L[start2 + i] = \ - _inverse_butterfly(L[start + i], L[start2 + i], root) + L[start + i], L[start2 + i] = _inverse_butterfly(L[start + i], L[start2 + i], root) + # ------------------------------------------------------------------- # splitting and recombining routines @@ -263,9 +254,7 @@ def _combine(L, m, k): """ M = 1 << m half_K = 1 << (k - 1) - return [L[0][j] for j in range(half_K)] + \ - [L[i + 1][j] + L[i][j + half_K] - for i in range(M - 1) for j in range(half_K)] + return [L[0][j] for j in range(half_K)] + [L[i + 1][j] + L[i][j + half_K] for i in range(M - 1) for j in range(half_K)] def _nega_combine(L, m, k): @@ -276,9 +265,7 @@ def _nega_combine(L, m, k): """ M = 1 << m half_K = 1 << (k - 1) - return [L[0][j] - L[M - 1][j + half_K] for j in range(half_K)] + \ - [L[i + 1][j] + L[i][j + half_K] - for i in range(M - 1) for j in range(half_K)] + return [L[0][j] - L[M - 1][j + half_K] for j in range(half_K)] + [L[i + 1][j] + L[i][j + half_K] for i in range(M - 1) for j in range(half_K)] # ------------------------------------------------------------------- @@ -291,7 +278,7 @@ def _negaconvolution(L1, L2, n): L1 and L2 must both have length `2^n`. """ - if n <= 3: # arbitrary cutoff + if n <= 3: # arbitrary cutoff return _negaconvolution_naive(L1, L2) return _negaconvolution_fft(L1, L2, n) diff --git a/src/sage/rings/polynomial/flatten.py b/src/sage/rings/polynomial/flatten.py index 926170cb375..4337df0b9f4 100644 --- a/src/sage/rings/polynomial/flatten.py +++ b/src/sage/rings/polynomial/flatten.py @@ -77,6 +77,7 @@ class FlatteningMorphism(Morphism): sage: f(p).parent() Multivariate Polynomial Ring in x, y, s, t, X over Rational Field """ + def __init__(self, domain): """ The Python constructor. @@ -396,14 +397,13 @@ def _call_(self, p): for l in range(len(self._intermediate_rings)): R, univariate = self._intermediate_rings[-1 - l] idx = index[l + 1] - sub_exp = (cur_exp[index[l]] if univariate - else cur_exp[index[l]:idx]) + sub_exp = cur_exp[index[l]] if univariate else cur_exp[index[l] : idx] if l == 0: newpol[l][sub_exp] = p[cur_exp] else: newpol[l][sub_exp] = newpol[l - 1] newpol[l - 1] = {} - if (i == len(expo) - 1 or expo[i + 1][idx:] != cur_exp[idx:]): + if i == len(expo) - 1 or expo[i + 1][idx:] != cur_exp[idx:]: newpol[l] = R(newpol[l], check=False) else: break @@ -534,14 +534,11 @@ def __init__(self, domain, D): # Construct unflattened codomain R new_vars = [] R = domain - while isinstance(R, (PolynomialRing_generic, - MPolynomialRing_base, - FractionField_generic)): + while isinstance(R, (PolynomialRing_generic, MPolynomialRing_base, FractionField_generic)): if isinstance(R, FractionField_generic): # We've hit base_ring, so set _sub_specialization and exit the loop field_over = R.base() - applicable_vars = {key: val for key, val in D.items() - if key not in flat.gens()} + applicable_vars = {key: val for key, val in D.items() if key not in flat.gens()} # If there are any variables in D to set in _sub_specialization if applicable_vars: # Coerce the generators to be in the right ring @@ -561,7 +558,7 @@ def __init__(self, domain, D): # We're still in the polynomials, so keep track of the tower old = R.gens() new = [t for t in old if t not in D] - force_multivariate = ((len(old) == 1) and isinstance(R, MPolynomialRing_base)) + force_multivariate = (len(old) == 1) and isinstance(R, MPolynomialRing_base) new_vars.append((new, force_multivariate, old)) R = R.base_ring() @@ -660,6 +657,7 @@ class FractionSpecializationMorphism(Morphism): """ A specialization morphism for fraction fields over (stacked) polynomial rings """ + def __init__(self, domain, D): """ Initialize the morphism with a domain and dictionary of specializations. diff --git a/src/sage/rings/polynomial/groebner_fan.py b/src/sage/rings/polynomial/groebner_fan.py index 79703e8b53e..e9a5fd72b3d 100644 --- a/src/sage/rings/polynomial/groebner_fan.py +++ b/src/sage/rings/polynomial/groebner_fan.py @@ -56,6 +56,7 @@ - Anders N. Jensen; *Gfan, a software system for Groebner fans*; http://home.math.au.dk/jensen/software/gfan/gfan.html """ + from subprocess import PIPE, Popen import pexpect import re @@ -71,6 +72,7 @@ from sage.rings.integer_ring import ZZ from sage.modules.free_module_element import vector from sage.misc.lazy_import import lazy_import + lazy_import("sage.plot.all", ["line", "Graphics", "polygon"]) lazy_import("sage.plot.plot3d.shapes2", "line3d") from sage.geometry.polyhedron.constructor import Polyhedron @@ -96,7 +98,7 @@ def prefix_check(str_list) -> bool: for index1, string1 in enumerate(str_list): for index2, string2 in enumerate(str_list): if index1 != index2: - if string1[:len(string2)] == string2: + if string1[: len(string2)] == string2: return False return True @@ -170,9 +172,7 @@ def __init__(self, gfan_polyhedral_cone, ring=QQ) -> None: sage: a.facets() [[0, 0, 1], [0, 1, 0], [1, 0, 0]] """ - cone_keys = ['AMBIENT_DIM', 'DIM', 'IMPLIED_EQUATIONS', - 'LINEALITY_DIM', 'LINEALITY_SPACE', 'FACETS', - 'RELATIVE_INTERIOR_POINT'] + cone_keys = ['AMBIENT_DIM', 'DIM', 'IMPLIED_EQUATIONS', 'LINEALITY_DIM', 'LINEALITY_SPACE', 'FACETS', 'RELATIVE_INTERIOR_POINT'] poly_lines = gfan_polyhedral_cone.split('\n') self.cone_dict = {} cur_key = None @@ -301,10 +301,7 @@ def __init__(self, gfan_polyhedral_fan, parameter_indices=None) -> None: """ if parameter_indices is None: parameter_indices = [] - fan_keys = ['AMBIENT_DIM', 'DIM', 'LINEALITY_DIM', 'RAYS', 'N_RAYS', - 'LINEALITY_SPACE', 'ORTH_LINEALITY_SPACE', 'F_VECTOR', - 'CONES', 'MAXIMAL_CONES', 'PURE', 'SIMPLICIAL', - 'MULTIPLICITIES'] + fan_keys = ['AMBIENT_DIM', 'DIM', 'LINEALITY_DIM', 'RAYS', 'N_RAYS', 'LINEALITY_SPACE', 'ORTH_LINEALITY_SPACE', 'F_VECTOR', 'CONES', 'MAXIMAL_CONES', 'PURE', 'SIMPLICIAL', 'MULTIPLICITIES'] poly_lines = gfan_polyhedral_fan.split('\n') self.fan_dict = {} cur_key = None @@ -648,8 +645,7 @@ def verts_for_normal(normal, poly) -> list: class TropicalPrevariety(PolyhedralFan): - def __init__(self, gfan_polyhedral_fan, polynomial_system, poly_ring, - parameters=None) -> None: + def __init__(self, gfan_polyhedral_fan, polynomial_system, poly_ring, parameters=None) -> None: """ This class is a subclass of the PolyhedralFan class, with some additional methods for tropical prevarieties. @@ -675,8 +671,7 @@ def __init__(self, gfan_polyhedral_fan, polynomial_system, poly_ring, if parameters is not None: allvars = poly_ring.gens() parameter_indices = [allvars.index(q) for q in parameters] - PolyhedralFan.__init__(self, gfan_polyhedral_fan, - parameter_indices=parameter_indices) + PolyhedralFan.__init__(self, gfan_polyhedral_fan, parameter_indices=parameter_indices) self._polynomial_system = polynomial_system self._parameters = parameters @@ -713,7 +708,7 @@ def initial_form_systems(self) -> list: verts = verts_for_normal(repray, poly) nform = 0 for x in verts: - factorlist = [pvars[i]**x[i] for i in range(nvars)] + factorlist = [pvars[i] ** x[i] for i in range(nvars)] temp_monomial = prod(factorlist) nform += poly.monomial_coefficient(temp_monomial) * temp_monomial iforms.append(nform) @@ -765,8 +760,7 @@ def ideal_to_gfan_format(input_ring, polys) -> str: sage: ideal_to_gfan_format(P,I.gens()) 'Q[x11, x12, x13, x14, x15, x21, x22, x23, x24, x25, x31, x32, x33, x34, x35]{-x12*x21+x11*x22,-x13*x21+x11*x23,-x14*x21+x11*x24,-x15*x21+x11*x25,-x13*x22+x12*x23,-x14*x22+x12*x24,-x15*x22+x12*x25,-x14*x23+x13*x24,-x15*x23+x13*x25,-x15*x24+x14*x25,-x12*x31+x11*x32,-x13*x31+x11*x33,-x14*x31+x11*x34,-x15*x31+x11*x35,-x13*x32+x12*x33,-x14*x32+x12*x34,-x15*x32+x12*x35,-x14*x33+x13*x34,-x15*x33+x13*x35,-x15*x34+x14*x35,-x22*x31+x21*x32,-x23*x31+x21*x33,-x24*x31+x21*x34,-x25*x31+x21*x35,-x23*x32+x22*x33,-x24*x32+x22*x34,-x25*x32+x22*x35,-x24*x33+x23*x34,-x25*x33+x23*x35,-x25*x34+x24*x35}' """ - ideal_gen_str = "{" + ",".join(str(poly).replace(" ", "").replace("'", "") - for poly in polys) + "}" + ideal_gen_str = "{" + ",".join(str(poly).replace(" ", "").replace("'", "") for poly in polys) + "}" ring_str = ring_to_gfan_format(input_ring) output = ring_str + ideal_gen_str return output @@ -949,8 +943,7 @@ def _gfan_ideal(self) -> str: sage: G._gfan_ideal() 'Q[x, y, z]{x^2*y-z,y^2*z-x,x*z^2-y}' """ - return ideal_to_gfan_format(self.ring(), - self.__ideal.gens()) + return ideal_to_gfan_format(self.ring(), self.__ideal.gens()) def weight_vectors(self) -> list: """ @@ -968,8 +961,7 @@ def weight_vectors(self) -> list: sage: len(g4.weight_vectors()) 23 """ - gfan_processes = Popen(['gfan', '_weightvector', '-m'], - stdin=PIPE, stdout=PIPE, stderr=PIPE) + gfan_processes = Popen(['gfan', '_weightvector', '-m'], stdin=PIPE, stdout=PIPE, stderr=PIPE) b_ans, _ = gfan_processes.communicate(input=self.gfan().encode("utf8")) s_ans = b_ans.decode() vect = re.compile(r"\([0-9,/\s]*\)") @@ -1053,8 +1045,7 @@ def reduced_groebner_bases(self): G = G.split(']')[1] G = G.replace('{{', '').replace('}}', '').split('},{') S = self.__ring - return [ReducedGroebnerBasis(self, [S(f) for f in G[i].split(',')], - G[i]) for i in range(len(G))] + return [ReducedGroebnerBasis(self, [S(f) for f in G[i].split(',')], G[i]) for i in range(len(G))] @cached_method def _gfan_mod(self) -> str: @@ -1190,8 +1181,7 @@ def homogeneity_space(self): """ return self.gfan(cmd='homogeneityspace') - def render(self, file=None, larger=False, shift=0, rgbcolor=(0, 0, 0), - polyfill=True, scale_colors=True): + def render(self, file=None, larger=False, shift=0, rgbcolor=(0, 0, 0), polyfill=True, scale_colors=True): """ Render a Groebner fan as sage graphics or save as an xfig file. @@ -1275,9 +1265,7 @@ def render(self, file=None, larger=False, shift=0, rgbcolor=(0, 0, 0), sp2.append(y) sp3 = [] for j in range(len(sp2)): - temp = [[float(sp2[j][i]) / 1200.0, - float(sp2[j][i + 1]) / 1200.0] - for i in range(0, len(sp2[j]) - 1, 2)] + temp = [[float(sp2[j][i]) / 1200.0, float(sp2[j][i + 1]) / 1200.0] for i in range(0, len(sp2[j]) - 1, 2)] sp3.append(temp) r_lines = Graphics() for x in sp3: @@ -1290,7 +1278,7 @@ def render(self, file=None, larger=False, shift=0, rgbcolor=(0, 0, 0), vmaxs = [max([q[i] for q in vals]) for i in (0, 1, 2)] for i in (0, 1, 2): if vmaxs[i] == vmins[i]: - vmaxs[i] = vmins[i] + .01 + vmaxs[i] = vmins[i] + 0.01 for index, sp in enumerate(sp3): col = [1 - (vals[index][i] - vmins[i]) / (vmaxs[i] - vmins[i]) for i in (0, 1, 2)] r_lines += polygon(sp, rgbcolor=col) @@ -1301,9 +1289,9 @@ def render(self, file=None, larger=False, shift=0, rgbcolor=(0, 0, 0), vmin = min(vals) vmax = max(vals) if vmin == vmax: - vmax = vmin + .01 + vmax = vmin + 0.01 for index, sp in enumerate(sp3): - r_lines += polygon(sp, hue=.1 + .6 * (vals[index] - vmin) / (vmax - vmin)) + r_lines += polygon(sp, hue=0.1 + 0.6 * (vals[index] - vmin) / (vmax - vmin)) else: for index, sp in enumerate(sp3): r_lines += polygon(sp, hue=vals[index]) @@ -1433,19 +1421,14 @@ def render3d(self, verbose=False): g_cones_facets = [q.facets() for q in g_cones] g_cones_ieqs = [self._cone_to_ieq(q) for q in g_cones_facets] # Now the cones are intersected with a plane: - cone_info = [Polyhedron(ieqs=q, eqns=[[1, -1, -1, -1, -1]]) - for q in g_cones_ieqs] + cone_info = [Polyhedron(ieqs=q, eqns=[[1, -1, -1, -1, -1]]) for q in g_cones_ieqs] # This is really just for debugging if verbose: for x in cone_info: - print(x.inequalities() + ([1, 1, 0, 0, 0], [1, 0, 1, 0, 0], - [1, 0, 0, 1, 0], [1, 0, 0, 0, 1])) + print(x.inequalities() + ([1, 1, 0, 0, 0], [1, 0, 1, 0, 0], [1, 0, 0, 1, 0], [1, 0, 0, 0, 1])) print(x.equations()) print() - cone_info = [Polyhedron(ieqs=x.inequalities() + - ([1, 1, 0, 0, 0], [1, 0, 1, 0, 0], - [1, 0, 0, 1, 0], [1, 0, 0, 0, 1]), - eqns=x.equations()) for x in cone_info] + cone_info = [Polyhedron(ieqs=x.inequalities() + ([1, 1, 0, 0, 0], [1, 0, 1, 0, 0], [1, 0, 0, 1, 0], [1, 0, 0, 0, 1]), eqns=x.equations()) for x in cone_info] all_lines = [] for cone_data in cone_info: try: @@ -1474,8 +1457,7 @@ def _gfan_stats(self) -> dict: 'Number of reduced Groebner bases': 3, 'Number of variables': 2} """ - s = self.gfan(cmd='stats', - I=self._gfan_reduced_groebner_bases().replace(' ', ',')) + s = self.gfan(cmd='stats', I=self._gfan_reduced_groebner_bases().replace(' ', ',')) d = {} for v in s.split('\n'): if v: @@ -1613,8 +1595,7 @@ def interactive(self, *args, **kwds): self[0].interactive(*args, **kwds) @cached_method - def tropical_intersection(self, parameters=None, symmetry_generators=None, - *args, **kwds): + def tropical_intersection(self, parameters=None, symmetry_generators=None, *args, **kwds): """ Return information about the tropical intersection of the polynomials defining the ideal. @@ -1672,8 +1653,7 @@ def tropical_intersection(self, parameters=None, symmetry_generators=None, allvars = self.ring().gens() truevars = [q for q in allvars if q not in parameters] base_ring = self.ring().base_ring() - new_ring = PolynomialRing(base_ring, len(truevars), - ",".join(str(q) for q in truevars)) + new_ring = PolynomialRing(base_ring, len(truevars), ",".join(str(q) for q in truevars)) old_polys = self.ideal().gens() new_polys = [] sub = {v: 1 for v in parameters} @@ -1686,8 +1666,7 @@ def tropical_intersection(self, parameters=None, symmetry_generators=None, cmd = cmd + ' --symmetryExploit' id_str = id_str + '{' + symmetry_generators + '}' f = self.gfan(cmd=cmd, I=id_str) - pf = TropicalPrevariety(f, self.ideal().gens(), self.ring(), - parameters=parameters) + pf = TropicalPrevariety(f, self.ideal().gens(), self.ring(), parameters=parameters) pf._gfan_output = f return pf @@ -1793,8 +1772,7 @@ def _gfan(self): """ return self.__groebner_fan - def interactive(self, latex=False, flippable=False, wall=False, - inequalities=False, weight=False): + def interactive(self, latex=False, flippable=False, wall=False, inequalities=False, weight=False): """ Do an interactive walk of the Groebner fan starting at this reduced Groebner basis. diff --git a/src/sage/rings/polynomial/ideal.py b/src/sage/rings/polynomial/ideal.py index bf575cb0339..4913d9797ca 100644 --- a/src/sage/rings/polynomial/ideal.py +++ b/src/sage/rings/polynomial/ideal.py @@ -6,7 +6,7 @@ - David Roe (2009-12-14) -- initial version. """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2009 David Roe # William Stein # @@ -15,7 +15,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.rings.ideal import Ideal_pid @@ -24,6 +24,7 @@ class Ideal_1poly_field(Ideal_pid): """ An ideal in a univariate polynomial ring over a field. """ + def residue_class_degree(self): """ Return the degree of the generator of this ideal. @@ -57,6 +58,7 @@ def residue_field(self, names=None, check=True): raise ValueError("%s is not a prime ideal" % self) from sage.rings.finite_rings.residue_field import ResidueField + return ResidueField(self, names, check=False) def groebner_basis(self, algorithm=None): @@ -84,6 +86,7 @@ def groebner_basis(self, algorithm=None): """ gb = self.gens_reduced() from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence_generic + return PolynomialSequence_generic([gb], self.ring(), immutable=True) def change_ring(self, R): diff --git a/src/sage/rings/polynomial/infinite_polynomial_element.py b/src/sage/rings/polynomial/infinite_polynomial_element.py index e331dd7eb14..5f1f3dcf931 100644 --- a/src/sage/rings/polynomial/infinite_polynomial_element.py +++ b/src/sage/rings/polynomial/infinite_polynomial_element.py @@ -113,8 +113,7 @@ from sage.structure.richcmp import richcmp -class InfinitePolynomial(CommutativePolynomial, - metaclass=InheritComparisonClasscallMetaclass): +class InfinitePolynomial(CommutativePolynomial, metaclass=InheritComparisonClasscallMetaclass): """ Create an element of a Polynomial Ring with a Countably Infinite Number of Variables. @@ -205,6 +204,7 @@ def __classcall_private__(cls, A, p): """ from sage.structure.element import parent + if hasattr(A, '_P'): if parent(p) is A._P or (A._P.base_ring().has_coerce_map_from(parent(p))): return InfinitePolynomial_dense(A, p) @@ -212,11 +212,13 @@ def __classcall_private__(cls, A, p): from sage.rings.polynomial.multi_polynomial_ring import ( MPolynomialRing_polydict, ) + if isinstance(A._P, MPolynomialRing_polydict): from sage.misc.sage_eval import sage_eval from sage.rings.polynomial.infinite_polynomial_ring import ( GenDictWithBasering, ) + p = sage_eval(repr(p), GenDictWithBasering(A._P, A._P.gens_dict())) return InfinitePolynomial_dense(A, p) # Now there remains to fight the oddities and bugs of libsingular. @@ -232,6 +234,7 @@ def __classcall_private__(cls, A, p): from sage.rings.polynomial.infinite_polynomial_ring import ( GenDictWithBasering, ) + # the base ring may be a function field, therefore # we need GenDictWithBasering return InfinitePolynomial_dense(A, sage_eval(repr(p), GenDictWithBasering(A._P, A._P.gens_dict()))) @@ -247,6 +250,7 @@ def __classcall_private__(cls, A, p): from sage.rings.polynomial.infinite_polynomial_ring import ( GenDictWithBasering, ) + # the base ring may be a function field, therefore # we need GenDictWithBasering return InfinitePolynomial_dense(A, sage_eval(repr(p), GenDictWithBasering(A._P, A._P.gens_dict()))) @@ -739,17 +743,17 @@ def monomial_coefficients(self, copy=None): p = self._p R_gens = p.parent().gens() if P.ngens() > 1: + def gen_to_index(g): j, i = P.varname_key(str(g)) return -j, i + else: + def gen_to_index(g): return P.varname_key(str(g))[1] - return {B._from_dict({gen_to_index(g): e - for e, g in zip(m, R_gens)}, - coerce=False, remove_zeros=True): c - for m, c in p.monomial_coefficients().items()} + return {B._from_dict({gen_to_index(g): e for e, g in zip(m, R_gens)}, coerce=False, remove_zeros=True): c for m, c in p.monomial_coefficients().items()} def exponents(self): """ @@ -847,7 +851,7 @@ def max_index(self): sage: X(10).max_index() -1 """ - return max([Integer(str(X).split('_')[1]) for X in self.variables()]+[-1]) + return max([Integer(str(X).split('_')[1]) for X in self.variables()] + [-1]) def _rmul_(self, left): """ @@ -915,6 +919,7 @@ def _div_(self, x): OUTP = self.parent().tensor_with_ring(divisor.base_ring()) return OUTP(self) * OUTP(divisor) from sage.rings.fraction_field_element import FractionFieldElement + field = self.parent().fraction_field() # there remains a problem in reduction return FractionFieldElement(field, self, x, reduce=False) @@ -943,11 +948,7 @@ def factor(self, proof=None): """ P = self.parent() f = self._p.factor(proof=proof) - return Factorization([(InfinitePolynomial(P, p), e) for p, e in f], - unit=f.unit(), - cr=f._cr(), - sort=False, - simplify=False) + return Factorization([(InfinitePolynomial(P, p), e) for p, e in f], unit=f.unit(), cr=f._cr(), sort=False, simplify=False) @cached_method def lm(self): @@ -966,8 +967,7 @@ def lm(self): if self._p == 0: return self if hasattr(self._p, 'variable_name'): # if it is univariate - return InfinitePolynomial(self.parent(), - self._p.parent().gen() ** max(self._p.exponents())) + return InfinitePolynomial(self.parent(), self._p.parent().gen() ** max(self._p.exponents())) return self # if it is scalar @cached_method @@ -1006,7 +1006,7 @@ def lt(self): if self._p == 0: return self if hasattr(self._p, 'variable_name'): # if it is univariate - return InfinitePolynomial(self.parent(), self._p.leading_coefficient()*self._p.parent().gen()**max(self._p.exponents())) + return InfinitePolynomial(self.parent(), self._p.leading_coefficient() * self._p.parent().gen() ** max(self._p.exponents())) return self # if it is scalar def tail(self): @@ -1020,7 +1020,7 @@ def tail(self): sage: p.tail() 2*x_10*y_30 """ - return self-self.lt() + return self - self.lt() def squeezed(self): """ @@ -1039,8 +1039,7 @@ def squeezed(self): sage: p.squeezed() x_2*y_4 + x_1*y_3 """ - Indices = set([0] + [Integer(str(Y).split('_')[1]) - for Y in self.variables()]) + Indices = set([0] + [Integer(str(Y).split('_')[1]) for Y in self.variables()]) Indices = sorted(Indices) def P(n): @@ -1087,6 +1086,7 @@ def footprint(self): # get the pairs (shift,exponent) of the leading monomial, indexed by the variable names Vars = self._p.parent().variable_names() from sage.rings.polynomial.multi_polynomial import MPolynomial_libsingular + if isinstance(self._p, MPolynomial_libsingular): L = [(Vars[i].split('_'), e) for i, e in enumerate(self._p.lm().exponents(as_ETuples=False)[0]) if e] elif hasattr(self._p, 'lm'): @@ -1098,11 +1098,11 @@ def footprint(self): else: # it is a univariate polynomial -- this should never happen, but just in case... L = [(Vars[0].split('_'), self._p.degree())] for t in L: - n = t[0][0] # the variable *n*ame + n = t[0][0] # the variable *n*ame s = int(t[0][1]) # the variable *s*hift if s not in self._footprint: - self._footprint[s] = [0]*l - self._footprint[s][P._name_dict[n]] = t[1] # the exponent + self._footprint[s] = [0] * l + self._footprint[s][P._name_dict[n]] = t[1] # the exponent self._has_footprint = True return self._footprint @@ -1173,7 +1173,7 @@ def symmetric_cancellation_order(self, other): ltsmall = olt # Case 1: one of the Infinite Polynomials is scalar. if not Fsmall: - return (rawcmp, 1, ltbig/ltsmall) + return (rawcmp, 1, ltbig / ltsmall) # "not Fbig" is now impossible, because we only consider *global* monomial orderings. # These are the occurring shifts: Lsmall = sorted(Fsmall.keys()) @@ -1227,6 +1227,7 @@ def symmetric_cancellation_order(self, other): if Expo[g]: OUT *= PARENT.gen(g)[shift] ** Expo[g] from sage.combinat.permutation import Permutation + return (rawcmp, Permutation(P[1:]), OUT) # Essentials for Buchberger @@ -1300,9 +1301,10 @@ def reduce(self, I, tailreduce=False, report=None): polynomial). """ from sage.rings.polynomial.symmetric_reduction import SymmetricReductionStrategy + if hasattr(I, 'gens'): I = I.gens() - if (not I): + if not I: return self I = list(I) S = SymmetricReductionStrategy(self.parent(), I, tailreduce) @@ -1345,9 +1347,11 @@ def stretch(self, k): sage: a.stretch(2000) x_6000 + x_4000 """ + def P(n): - return k*n - return self ** P + return k * n + + return self**P def __iter__(self): """ @@ -1361,9 +1365,7 @@ def __iter__(self): sage: list(a) [(2, x_1), (1, x_0), (1, y_1*y_0)] """ - return iter((coefficient, - self.__class__(self.parent(), monomial)) - for coefficient, monomial in self._p) + return iter((coefficient, self.__class__(self.parent(), monomial)) for coefficient, monomial in self._p) class InfinitePolynomial_sparse(InfinitePolynomial): @@ -1392,6 +1394,7 @@ class InfinitePolynomial_sparse(InfinitePolynomial): Multivariate Polynomial Ring in b_100, b_0, c_4, c_0 over Univariate Polynomial Ring in a over Rational Field """ + def __call__(self, *args, **kwargs): """ EXAMPLES:: @@ -1435,12 +1438,14 @@ def __call__(self, *args, **kwargs): V.sort(key=self.parent().varname_key, reverse=True) if V: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(self._p.base_ring(), V, order=self.parent()._order) else: return self res = R(self._p)(*args, **kwargs) try: from sage.misc.sage_eval import sage_eval + return sage_eval(repr(res), self.parent().gens_dict()) except Exception: return res @@ -1461,6 +1466,7 @@ def _common_polynomial_ring(self, x): VarList = sorted(VarList, key=self.parent().varname_key, reverse=True) if VarList: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(self._p.base_ring(), VarList, order=self.parent()._order) else: # TODO: this is currently dead code @@ -1591,7 +1597,7 @@ def __pow__(self, n): """ P = self.parent() if callable(n): - if (self._p.parent() == self._p.base_ring()): + if self._p.parent() == self._p.base_ring(): return self if not (hasattr(self._p, 'variables') and self._p.variables()): return self @@ -1601,6 +1607,7 @@ def __pow__(self, n): def p(m): return n(m) if 0 < m <= l else m + else: # Permutation group element p = n @@ -1611,7 +1618,7 @@ def q(s): if not newVars: return self copyVars = copy.copy(newVars) - newVars = list(set(list(self._p.parent().variable_names())+newVars)) + newVars = list(set(list(self._p.parent().variable_names()) + newVars)) newVars.sort(key=self.parent().varname_key, reverse=True) if newVars == list(self._p.parent().variable_names()): newR = self._p.parent() @@ -1619,6 +1626,7 @@ def q(s): from sage.rings.polynomial.polynomial_ring_constructor import ( PolynomialRing, ) + newR = PolynomialRing(self._p.base_ring(), newVars, order=P._order) mapR = self._p.parent().hom(copyVars, newR) return InfinitePolynomial_sparse(self.parent(), mapR(self._p)) @@ -1688,10 +1696,10 @@ def _richcmp_(self, x, op): # may be widely different, and the sage coercion # system can't guess what order we want. from sage.structure.element import parent + R1 = parent(self._p) R2 = parent(x._p) - if ((hasattr(R1, 'has_coerce_map_from') and R1.has_coerce_map_from(R2)) - or (hasattr(R2, 'has_coerce_map_from') and R2.has_coerce_map_from(R1))): + if (hasattr(R1, 'has_coerce_map_from') and R1.has_coerce_map_from(R2)) or (hasattr(R2, 'has_coerce_map_from') and R2.has_coerce_map_from(R1)): return richcmp(self._p, x._p, op) R = self._common_polynomial_ring(x) if (self._p.parent() is self._p.base_ring()) or not self._p.parent().gens(): @@ -1751,8 +1759,7 @@ def quo_rem(self, x): R = self._common_polynomial_ring(x) result = R(self._p).quo_rem(R(x._p)) - return (InfinitePolynomial_sparse(self.parent(), result[0]), - InfinitePolynomial_sparse(self.parent(), result[1])) + return (InfinitePolynomial_sparse(self.parent(), result[0]), InfinitePolynomial_sparse(self.parent(), result[1])) def monomial_coefficient(self, mon): """ @@ -2064,7 +2071,7 @@ def __pow__(self, n): """ P = self.parent() if callable(n): - if (self._p.parent() == self._p.base_ring()): + if self._p.parent() == self._p.base_ring(): return self if not (hasattr(self._p, 'variables') and self._p.variables()): return self @@ -2074,12 +2081,13 @@ def __pow__(self, n): def p(m): return n(m) if 0 < m <= l else m + else: # Permutation group element p = n # determine whether the maximal index must be raised oldMax = P._max - newMax = max([p(X) for X in range(oldMax+1)]+[oldMax]) + newMax = max([p(X) for X in range(oldMax + 1)] + [oldMax]) if newMax > P._max: P.gen()[newMax] self._p = P._P(self._p) @@ -2092,7 +2100,7 @@ def p(m): blocklength = sh nM = sh + 1 for i in range(P.ngens()): - newVars.extend([PPgens[sh-p(j)] for j in range(blocklength, -1, -1)]) + newVars.extend([PPgens[sh - p(j)] for j in range(blocklength, -1, -1)]) sh += nM mapR = PP.hom(newVars, PP) return InfinitePolynomial_dense(P, mapR(self._p)) @@ -2143,8 +2151,7 @@ def quo_rem(self, x): x._p = P._P(x._p) result = (self._p).quo_rem(x._p) - return (InfinitePolynomial_dense(P, result[0]), - InfinitePolynomial_dense(P, result[1])) + return (InfinitePolynomial_dense(P, result[0]), InfinitePolynomial_dense(P, result[1])) def monomial_coefficient(self, mon): """ diff --git a/src/sage/rings/polynomial/infinite_polynomial_ring.py b/src/sage/rings/polynomial/infinite_polynomial_ring.py index 7e4b539b0e8..030680c7820 100644 --- a/src/sage/rings/polynomial/infinite_polynomial_ring.py +++ b/src/sage/rings/polynomial/infinite_polynomial_ring.py @@ -242,6 +242,7 @@ sage: a.constant_coefficient() y + 1 """ + # **************************************************************************** # Copyright (C) 2009 Simon King and # Mike Hansen , @@ -278,6 +279,7 @@ ############################################################### # Ring Factory framework + class InfinitePolynomialRingFactory(UniqueFactory): """ A factory for creating infinite polynomial ring elements. It @@ -303,6 +305,7 @@ class InfinitePolynomialRingFactory(UniqueFactory): sage: X is loads(dumps(X)) True """ + def create_key(self, R, names=('x',), order='lex', implementation='dense'): """ Create a key which uniquely defines the infinite polynomial ring. @@ -370,6 +373,7 @@ def create_object(self, version, key): # By now, we have different unique keys, based on construction functors C, R = key from sage.categories.pushout import CompositeConstructionFunctor, InfinitePolynomialFunctor + if isinstance(C, CompositeConstructionFunctor): F = C.all[-1] if len(C.all) > 1: @@ -389,6 +393,7 @@ def create_object(self, version, key): ############################################################## # An auxiliary dictionary-like class that returns variables + class InfiniteGenDict: """ A dictionary-like class that is suitable for usage in ``sage_eval``. @@ -412,6 +417,7 @@ class InfiniteGenDict: sage: sage_eval('3*a_3*b_5-1/2*a_7', D._D[0]) -1/2*a_7 + 3*a_3*b_5 """ + def __init__(self, Gens): """ INPUT: @@ -518,6 +524,7 @@ class GenDictWithBasering: sage: sage_eval('3*a_3*b_5-1/2*a_7', D) -1/2*a_7 + 3*a_3*b_5 """ + def __init__(self, parent, start): """ INPUT: @@ -620,6 +627,7 @@ def __getitem__(self, k): ############################################################## # The sparse implementation + class InfinitePolynomialRing_sparse(CommutativeRing): r""" Sparse implementation of Infinite Polynomial Rings. @@ -664,6 +672,7 @@ class InfinitePolynomialRing_sparse(CommutativeRing): See :mod:`~sage.rings.polynomial.infinite_polynomial_ring` for more details. """ + def __init__(self, R, names, order): """ INPUT: @@ -737,6 +746,7 @@ def __init__(self, R, names, order): # polynomial of an element of self is actually a *multi*variate # polynomial ring. from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + if len(names) == 1: VarList = [names[0] + '_0', names[0] + '_1'] else: @@ -753,12 +763,10 @@ def __init__(self, R, names, order): from sage.rings.semirings.non_negative_integer_semiring import NN from sage.categories.cartesian_product import cartesian_product from sage.combinat.free_module import CombinatorialFreeModule + category = polynomial_default_category(R.category(), Infinity) CommutativeRing.__init__(self, R, category=category) - self._indices = cartesian_product([CombinatorialFreeModule(ZZ, - basis_keys=NN, - prefix=v) - for v in names]) + self._indices = cartesian_product([CombinatorialFreeModule(ZZ, basis_keys=NN, prefix=v) for v in names]) self._populate_coercion_lists_() def monomial(self, m): @@ -781,9 +789,9 @@ def monomial(self, m): """ V = self.gens() if len(V) > 1: - return prod(V[j][i]**e for (j, i), e in m) + return prod(V[j][i] ** e for (j, i), e in m) v = V[0] - return prod(v[i]**e for i, e in m) + return prod(v[i] ** e for i, e in m) def __repr__(self): """ @@ -807,6 +815,7 @@ def _latex_(self): \Bold{Q}[x_{\ast}, y_{\ast}] """ from sage.misc.latex import latex + vars = ', '.join(latex(X) for X in self.gens()) return f"{latex(self.base_ring())}[{vars}]" @@ -834,6 +843,7 @@ def one(self): 1 """ from sage.rings.polynomial.infinite_polynomial_element import InfinitePolynomial + return InfinitePolynomial(self, self._base(1)) ##################### @@ -887,6 +897,7 @@ def _coerce_map_from_(self, S): """ # Use Construction Functors! from sage.categories.pushout import pushout + try: # the following line should not test "pushout is self", but # only "pushout == self", since we also allow coercion from @@ -947,9 +958,11 @@ def _element_constructor_(self, x): a_0 """ from sage.rings.polynomial.infinite_polynomial_element import InfinitePolynomial + # In many cases, the easiest solution is to "simply" evaluate # the string representation. from sage.misc.sage_eval import sage_eval + if isinstance(x, str): try: x = sage_eval(x, self.gens_dict()) @@ -975,6 +988,7 @@ def _element_constructor_(self, x): # First, try interpretation in the base ring. try: from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict + if isinstance(self._base, MPolynomialRing_polydict): x = sage_eval(repr(), next(self.gens_dict())) else: @@ -998,6 +1012,7 @@ def _element_constructor_(self, x): # direct conversion will only be used if the underlying polynomials are libsingular. from sage.rings.polynomial.multi_polynomial import MPolynomial_libsingular + # try interpretation in self._P, if we have a dense implementation if hasattr(self, '_P'): if x.parent() is self._P: @@ -1008,6 +1023,7 @@ def _element_constructor_(self, x): # applications!), we do it "nicely". Otherwise, we have to use sage_eval. if isinstance(x, MPolynomial_libsingular): from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular + if isinstance(self._P, MPolynomialRing_libsingular): if xmaxind == -1: # Otherwise, x has been an InfinitePolynomial # We infer the correct variable shift. @@ -1076,9 +1092,11 @@ def _element_constructor_(self, x): raise ValueError("cannot convert {} into an element of {}; the variables are not admissible".format(x, self)) from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(self._base, VarList, order=self._order) if isinstance(x, MPolynomial_libsingular): # everything else is so buggy that it's even not worth to try. from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular + if isinstance(R, MPolynomialRing_libsingular): try: # Problem: If there is only a partial overlap in the variables @@ -1340,6 +1358,7 @@ def _ideal_class_(self, n=0): """ import sage.rings.polynomial.symmetric_ideal + return sage.rings.polynomial.symmetric_ideal.SymmetricIdeal def characteristic(self): @@ -1390,6 +1409,7 @@ def krull_dimension(self, *args, **kwds): +Infinity """ from sage.rings.infinity import Infinity + return Infinity def order(self): @@ -1404,6 +1424,7 @@ def order(self): +Infinity """ from sage.rings.infinity import Infinity + return Infinity # Other bases @@ -1418,6 +1439,7 @@ def key_basis(self): Key polynomial basis over Finite Field of size 2 """ from sage.combinat.key_polynomial import KeyPolynomialBasis + return KeyPolynomialBasis(self) @@ -1498,6 +1520,7 @@ def _latex_(self): \mathit{x1}_{3} """ from sage.misc.latex import latex_variable_name + return latex_variable_name(self._name + '_ast') def __getitem__(self, i): @@ -1520,6 +1543,7 @@ def __getitem__(self, i): P = self._parent from sage.rings.polynomial.infinite_polynomial_element import InfinitePolynomial_dense, InfinitePolynomial_sparse from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + OUT = self._output.get(i) if hasattr(P, '_P'): if i <= P._max: @@ -1532,8 +1556,7 @@ def __getitem__(self, i): return self._output[i] # Calculate all of the new names needed try: - names = [[name + '_' + str(j) for name in P._names] - for j in range(i + 1)] + names = [[name + '_' + str(j) for name in P._names] for j in range(i + 1)] except OverflowError: raise IndexError("variable index is too big - consider using the sparse implementation") names = reduce(operator.add, names) @@ -1582,6 +1605,7 @@ def __str__(self): ############################################################## # The dense implementation + class InfinitePolynomialRing_dense(InfinitePolynomialRing_sparse): """ Dense implementation of Infinite Polynomial Rings. @@ -1590,6 +1614,7 @@ class InfinitePolynomialRing_dense(InfinitePolynomialRing_sparse): from which this class inherits, it keeps a polynomial ring that comprises all elements that have been created so far. """ + def __init__(self, R, names, order): """ EXAMPLES:: diff --git a/src/sage/rings/polynomial/integer_valued_polynomials.py b/src/sage/rings/polynomial/integer_valued_polynomials.py index c226d0d82ab..8906c95f3f8 100644 --- a/src/sage/rings/polynomial/integer_valued_polynomials.py +++ b/src/sage/rings/polynomial/integer_valued_polynomials.py @@ -5,6 +5,7 @@ - Frédéric Chapoton (2023-03): Initial version """ + # *************************************************************************** # Copyright (C) 2013 Frédéric Chapoton # @@ -75,6 +76,7 @@ class IntegerValuedPolynomialRing(UniqueRepresentation, Parent): ... TypeError: argument R must be a commutative ring """ + def __init__(self, R) -> None: """ TESTS:: @@ -138,8 +140,7 @@ def super_categories(self) -> list: """ A = self.base() category = Algebras(A.base_ring()).Commutative().Filtered() - return [A.Realizations(), - category.Realizations().WithBasis()] + return [A.Realizations(), category.Realizations().WithBasis()] class ParentMethods: def _repr_(self) -> str: @@ -388,6 +389,7 @@ def content(self): 0 """ from sage.arith.misc import gcd + return gcd(self._monomial_coefficients.values()) class Shifted(CombinatorialFreeModule, BindableClass): @@ -456,6 +458,7 @@ class Shifted(CombinatorialFreeModule, BindableClass): sage: 1 - S[2] * S[2] / 2 S[0] - 1/2*S[2] + 3*S[3] - 3*S[4] """ + def __init__(self, A) -> None: r""" Initialize ``self``. @@ -467,11 +470,7 @@ def __init__(self, A) -> None: in the shifted basis sage: TestSuite(F).run() """ - CombinatorialFreeModule.__init__(self, A.base_ring(), - NonNegativeIntegers(), - category=A.Bases(), - prefix='S', - latex_prefix=r"\mathbb{S}") + CombinatorialFreeModule.__init__(self, A.base_ring(), NonNegativeIntegers(), category=A.Bases(), prefix='S', latex_prefix=r"\mathbb{S}") def _realization_name(self) -> str: r""" @@ -505,8 +504,7 @@ def product_on_basis(self, n1, n2): j, i = i, j R = self.base_ring() - return self._from_dict({i + j - k: R((-1)**k * i.binomial(k) * (i + j - k).binomial(i)) - for k in range(i + 1)}) + return self._from_dict({i + j - k: R((-1) ** k * i.binomial(k) * (i + j - k).binomial(i)) for k in range(i + 1)}) def _from_binomial_basis(self, i): """ @@ -528,8 +526,7 @@ def _from_binomial_basis(self, i): """ i = ZZ(i) R = self.base_ring() - return self._from_dict({k: R((-1)**(i - k) * i.binomial(k)) - for k in range(i + 1)}) + return self._from_dict({k: R((-1) ** (i - k) * i.binomial(k)) for k in range(i + 1)}) def from_h_vector(self, h): """ @@ -550,8 +547,7 @@ def from_h_vector(self, h): S[2] + S[4] """ d = len(h) - 1 - m = matrix(QQ, d + 1, d + 1, - lambda j, i: (-1)**(d - j) * binomial(d - i, d - j)) + m = matrix(QQ, d + 1, d + 1, lambda j, i: (-1) ** (d - j) * binomial(d - i, d - j)) R = self.base_ring() v = vector(R, [h[i] for i in range(d + 1)]) return self._from_dict(dict(enumerate(m * v))) @@ -681,8 +677,7 @@ def _coerce_map_from_(self, R): if isinstance(R, IntegerValuedPolynomialRing.Shifted): return self.base_ring().has_coerce_map_from(R.base_ring()) if isinstance(R, IntegerValuedPolynomialRing.Binomial): - return R.module_morphism(self._from_binomial_basis, - codomain=self) + return R.module_morphism(self._from_binomial_basis, codomain=self) return self.base_ring().has_coerce_map_from(R) def _poly(self, i): @@ -783,12 +778,10 @@ def variable_shift(self, k=1): A = self.parent() def on_basis(n): - return {A._indices(j): binomial(k + n - 1 - j, n - j) - for j in range(n + 1)} + return {A._indices(j): binomial(k + n - 1 - j, n - j) for j in range(n + 1)} mc = self._monomial_coefficients - ret = linear_combination((on_basis(index), coeff) - for index, coeff in mc.items()) + ret = linear_combination((on_basis(index), coeff) for index, coeff in mc.items()) return A.element_class(A, ret) def derivative_at_minus_one(self): @@ -825,10 +818,8 @@ def h_vector(self) -> vector: (0, 1, 4, 1) """ d = ZZ(max(self.support(), default=-1)) - m = matrix(QQ, d + 1, d + 1, - lambda j, i: (-1)**(d - j) * (d - i).binomial(d - j)) - v = vector(self.base_ring(), - [self.coefficient(i) for i in range(d + 1)]) + m = matrix(QQ, d + 1, d + 1, lambda j, i: (-1) ** (d - j) * (d - i).binomial(d - j)) + v = vector(self.base_ring(), [self.coefficient(i) for i in range(d + 1)]) return m * v def h_polynomial(self): @@ -889,7 +880,7 @@ def fraction(self): ring_t = PolynomialRing(self.parent().base_ring(), 't') t = ring_t.gen() numer = ring_t({d - 1 - i: v[i] for i in range(d)}) - return numer / (1 - t)**d + return numer / (1 - t) ** d S = Shifted @@ -968,6 +959,7 @@ class Binomial(CombinatorialFreeModule, BindableClass): sage: F(4/3) 4/3*B[0] """ + def __init__(self, A) -> None: r""" Initialize ``self``. @@ -979,10 +971,7 @@ def __init__(self, A) -> None: in the binomial basis sage: TestSuite(F).run() """ - CombinatorialFreeModule.__init__(self, A.base_ring(), - NonNegativeIntegers(), - latex_prefix='', - category=A.Bases()) + CombinatorialFreeModule.__init__(self, A.base_ring(), NonNegativeIntegers(), latex_prefix='', category=A.Bases()) def _realization_name(self) -> str: r""" @@ -1016,9 +1005,7 @@ def product_on_basis(self, n1, n2): j, i = i, j R = self.base_ring() - return self._from_dict({i + j - k: - R(binomial(i, k) * binomial(i + j - k, i)) - for k in range(i + 1)}) + return self._from_dict({i + j - k: R(binomial(i, k) * binomial(i + j - k, i)) for k in range(i + 1)}) def _from_shifted_basis(self, i): """ @@ -1040,8 +1027,7 @@ def _from_shifted_basis(self, i): """ i = ZZ(i) R = self.base_ring() - return self._from_dict({k: R(i.binomial(k)) - for k in range(i + 1)}) + return self._from_dict({k: R(i.binomial(k)) for k in range(i + 1)}) def _element_constructor_(self, x): r""" @@ -1164,8 +1150,7 @@ def _coerce_map_from_(self, R): if isinstance(R, IntegerValuedPolynomialRing.Binomial): return self.base_ring().has_coerce_map_from(R.base_ring()) if isinstance(R, IntegerValuedPolynomialRing.Shifted): - return R.module_morphism(self._from_shifted_basis, - codomain=self) + return R.module_morphism(self._from_shifted_basis, codomain=self) return self.base_ring().has_coerce_map_from(R) def _poly(self, i): @@ -1218,12 +1203,10 @@ def variable_shift(self, k=1): A = self.parent() def on_basis(n): - return {A._indices(j): binomial(k, n - j) - for j in range(n + 1)} + return {A._indices(j): binomial(k, n - j) for j in range(n + 1)} mc = self._monomial_coefficients - ret = linear_combination((on_basis(index), coeff) - for index, coeff in mc.items()) + ret = linear_combination((on_basis(index), coeff) for index, coeff in mc.items()) return A.element_class(A, ret) B = Binomial diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 227a360a0db..8bf0c2c9c59 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -27,7 +27,7 @@ from sage.arith.misc import GCD -class LaurentPolynomialIdeal( Ideal_generic ): +class LaurentPolynomialIdeal(Ideal_generic): def __init__(self, ring, gens, coerce=True, hint=None) -> None: r""" Create an ideal in a Laurent polynomial ring. @@ -168,11 +168,11 @@ def _richcmp_(self, right_r, op): True """ if op in (op_EQ, op_NE): - if set(self.gens()) == set(right_r.gens()): # Early abort - return (op == op_EQ) - return ((self.polynomial_ideal() == right_r.polynomial_ideal()) == (op == op_EQ)) + if set(self.gens()) == set(right_r.gens()): # Early abort + return op == op_EQ + return (self.polynomial_ideal() == right_r.polynomial_ideal()) == (op == op_EQ) if op == op_LE: - if all(f in right_r.gens() for f in self.gens()): # Early abort + if all(f in right_r.gens() for f in self.gens()): # Early abort return True return self.polynomial_ideal(saturate=False) <= right_r.polynomial_ideal() if op == op_GE: @@ -208,7 +208,7 @@ def __contains__(self, f) -> bool: g = f.__reduce__()[1][1] else: g = f.__reduce__()[1][0] - return (g in self.polynomial_ideal()) + return g in self.polynomial_ideal() def gens_reduced(self) -> tuple: """ @@ -322,12 +322,10 @@ def apply_coeff_map(self, f, new_base_ring=None, forward_hint=True): else: R = ring.change_ring(new_base_ring) if forward_hint: - apply_to_hint = lambda x,f=f: x.map_coefficients(f) + apply_to_hint = lambda x, f=f: x.map_coefficients(f) else: apply_to_hint = None - return self.apply_map(lambda x,f=f: - x.map_coefficients(f, new_base_ring=new_base_ring), - new_ring=R, apply_to_hint=apply_to_hint) + return self.apply_map(lambda x, f=f: x.map_coefficients(f, new_base_ring=new_base_ring), new_ring=R, apply_to_hint=apply_to_hint) def toric_coordinate_change(self, M, forward_hint=True): """ @@ -350,8 +348,7 @@ def toric_coordinate_change(self, M, forward_hint=True): apply_to_hint = lambda x, M=M, R=R: R(x).toric_coordinate_change(M).monomial_reduction()[0] else: apply_to_hint = None - return self.apply_map(lambda x, M=M: x.toric_coordinate_change(M), - apply_to_hint=apply_to_hint) + return self.apply_map(lambda x, M=M: x.toric_coordinate_change(M), apply_to_hint=apply_to_hint) def __add__(self, other): """ diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index 1cc33283198..7572be637ca 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -29,6 +29,7 @@ - David Roe (2008-2-23): created - David Loeffler (2009-07-10): cleaned up docstrings """ + # **************************************************************************** # Copyright (C) 2008 David Roe , # William Stein , @@ -213,7 +214,7 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): R = PolynomialRing(base_ring, *args, **kwds) if R in _cache: - return _cache[R] # put () here to re-enable weakrefs + return _cache[R] # put () here to re-enable weakrefs if isinstance(R, PolynomialRing_generic): # univariate case @@ -292,8 +293,7 @@ def get(T, i): def extract(T, indices): return tuple(get(T, i) for i in indices) - remaining = sorted(set(range(len(next(iter(D))))) - - set(indices) - set(group_by)) + remaining = sorted(set(range(len(next(iter(D))))) - set(indices) - set(group_by)) result = {} for K, V in D.items(): if not all(r == 0 for r in extract(K, remaining)): @@ -362,8 +362,7 @@ def value(d, R): return {k: value(v, P.base_ring()) for k, v in D.items()} except (ValueError, TypeError): pass - return sum(P({k: 1}) * value(v, P) - for k, v in D.items()).monomial_coefficients() + return sum(P({k: 1}) * value(v, P) for k, v in D.items()).monomial_coefficients() def from_fraction_field(L, x): @@ -419,6 +418,7 @@ def __init__(self, R): raise ValueError("must be 1 generator") LaurentPolynomialRing_generic.__init__(self, R) from sage.rings.integer_ring import IntegerRing + self._indices = IntegerRing() Element = LaurentPolynomial_univariate @@ -502,6 +502,7 @@ def _element_constructor_(self, x): from sage.structure.element import Expression from sage.rings.fraction_field_element import FractionFieldElement from sage.rings.localization import LocalizationElement + if isinstance(x, Expression): return x.laurent_polynomial(ring=self) @@ -572,6 +573,7 @@ def __init__(self, R): LaurentPolynomialRing_generic.__init__(self, R) from sage.modules.free_module import FreeModule from sage.rings.integer_ring import IntegerRing + self._indices = FreeModule(IntegerRing(), R.ngens()) Element = LazyImport('sage.rings.polynomial.laurent_polynomial_mpair', 'LaurentPolynomial_mpair') @@ -623,6 +625,7 @@ def monomial(self, *exponents): TypeError: tuple key (-1, 2, 3) must have same length as ngens (= 2) """ from sage.rings.polynomial.polydict import ETuple + if len(exponents) == 1 and isinstance((e := exponents[0]), (tuple, ETuple)): exponents = e @@ -738,8 +741,8 @@ def _element_constructor_(self, x, mon=None): P = parent(x) if P is self.polynomial_ring(): from sage.rings.polynomial.polydict import ETuple - return self.element_class(self, x, - mon=ETuple({}, int(self.ngens()))) + + return self.element_class(self, x, mon=ETuple({}, int(self.ngens()))) if isinstance(x, Expression): return x.laurent_polynomial(ring=self) @@ -757,6 +760,7 @@ def _element_constructor_(self, x, mon=None): x = _split_laurent_polynomial_dict_(self, P, d) elif P is self.base_ring(): from sage.rings.polynomial.polydict import ETuple + mz = ETuple({}, int(self.ngens())) return self.element_class(self, {mz: x}, mz) elif x.is_constant() and self.has_coerce_map_from(P.base_ring()): diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py index cc8887a748b..fc4fa13b1ad 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring_base.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring_base.py @@ -48,6 +48,7 @@ class LaurentPolynomialRing_generic(Parent): and Category of infinite sets sage: TestSuite(R).run() """ + def __init__(self, R) -> None: """ EXAMPLES:: @@ -60,16 +61,14 @@ def __init__(self, R) -> None: self._R = R names = R.variable_names() self._one_element = self.element_class(self, R.one()) - Parent.__init__(self, base=R.base_ring(), names=names, - category=R.category()) + Parent.__init__(self, base=R.base_ring(), names=names, category=R.category()) ernames = [] for n in names: ernames.append(n) ernames.append(n + "inv") ER = PolynomialRing(R.base_ring(), ernames) self._extended_ring = ER - self._extended_ring_ideal = ER.ideal([ER.gen(2*i) * ER.gen(2*i+1) - 1 - for i in range(self._n)]) + self._extended_ring_ideal = ER.ideal([ER.gen(2 * i) * ER.gen(2 * i + 1) - 1 for i in range(self._n)]) def ngens(self): """ @@ -246,9 +245,11 @@ def completion(self, p=None, prec=20, extras=None): if p is None or str(p) == self._names[0] and self._n == 1: if prec == float('inf'): from sage.rings.lazy_series_ring import LazyLaurentSeriesRing + sparse = self.polynomial_ring().is_sparse() return LazyLaurentSeriesRing(self.base_ring(), names=(self._names[0],), sparse=sparse) from sage.rings.laurent_series_ring import LaurentSeriesRing + R = self.polynomial_ring().completion(self._names[0], prec) return LaurentSeriesRing(R) @@ -293,8 +294,7 @@ def _coerce_map_from_(self, R): f = self._coerce_map_via([self._R], R) if f is not None: return f - if (isinstance(R, LaurentPolynomialRing_generic) - and self._R.has_coerce_map_from(R._R)): + if isinstance(R, LaurentPolynomialRing_generic) and self._R.has_coerce_map_from(R._R): return self._generic_coerce_map(R) def __eq__(self, right) -> bool: @@ -398,6 +398,7 @@ def ideal(self, *args, **kwds): Ideal (-t, 1) of Univariate Laurent Polynomial Ring in t over Integer Ring """ from sage.rings.polynomial.laurent_polynomial_ideal import LaurentPolynomialIdeal + return LaurentPolynomialIdeal(self, *args, **kwds) def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None) -> bool: @@ -621,7 +622,7 @@ def random_element(self, min_valuation=-2, max_degree=2, *args, **kwds): raise ValueError("`max_degree` must be greater than or equal to `min_valuation`") # Sample a polynomial in the base ring of degree `max_degree - min_valuation` - abs_deg = (max_degree - min_valuation) + abs_deg = max_degree - min_valuation f_rand = self._R.random_element(degree=abs_deg, *args, **kwds) # Cast this polynomial back the ``self`` diff --git a/src/sage/rings/polynomial/msolve.py b/src/sage/rings/polynomial/msolve.py index 911b91a34f0..832b5c4a7b0 100644 --- a/src/sage/rings/polynomial/msolve.py +++ b/src/sage/rings/polynomial/msolve.py @@ -40,26 +40,20 @@ def _run_msolve(ideal, options): """ base = ideal.base_ring() - if not (base is QQ or isinstance(base, FiniteField) and - base.is_prime_field() and base.characteristic() < 2**31): + if not (base is QQ or isinstance(base, FiniteField) and base.is_prime_field() and base.characteristic() < 2**31): raise NotImplementedError(f"unsupported base field: {base}") # Run msolve drlpolring = ideal.ring().change_ring(order='degrevlex') polys = ideal.change_ring(drlpolring).gens() - with tempfile.NamedTemporaryFile(mode='w', - encoding='ascii', - delete_on_close=False) as msolve_in: + with tempfile.NamedTemporaryFile(mode='w', encoding='ascii', delete_on_close=False) as msolve_in: print(",".join(drlpolring.variable_names()), file=msolve_in) print(base.characteristic(), file=msolve_in) - print(*(pol._repr_().replace(" ", "") for pol in polys), - sep=',\n', file=msolve_in) + print(*(pol._repr_().replace(" ", "") for pol in polys), sep=',\n', file=msolve_in) msolve_in.close() command = [msolve().absolute_filename(), "-f", msolve_in.name] + options - msolve_out = subprocess.run(command, - capture_output=True, - text=True) + msolve_out = subprocess.run(command, capture_output=True, text=True) msolve_out.check_returncode() return msolve_out.stdout @@ -230,11 +224,9 @@ def variety(ideal, ring, *, proof=True): if ring is None: ring = base if not ring.has_coerce_map_from(base): - raise ValueError( - f"no coercion from base field {base} to output ring {ring}") + raise ValueError(f"no coercion from base field {base} to output ring {ring}") - if isinstance(ring, (RealIntervalField_class, RealBallField, - RealField_class, RealDoubleField_class)): + if isinstance(ring, (RealIntervalField_class, RealBallField, RealField_class, RealDoubleField_class)): parameterization = False options = ["-p", str(ring.precision())] else: @@ -264,19 +256,18 @@ def variety(ideal, ring, *, proof=True): def to_poly(p, d=1, *, upol=PolynomialRing(base, 't')): assert len(p[1]) == p[0] + 1 or p == [-1, [0]] - return upol(p[1])/d + return upol(p[1]) / d try: char, nvars, deg, vars, _, [one, [elim, den, param]] = data[1] except (IndexError, ValueError): - raise NotImplementedError( - f"unsupported msolve output format: {data}") + raise NotImplementedError(f"unsupported msolve output format: {data}") assert char == ideal.base_ring().characteristic() assert one.is_one() assert len(vars) == nvars ringvars = out_ring.variable_names() - assert sorted(vars[:len(ringvars)]) == sorted(ringvars) - vars = [out_ring(name) for name in vars[:len(ringvars)]] + assert sorted(vars[: len(ringvars)]) == sorted(ringvars) + vars = [out_ring(name) for name in vars[: len(ringvars)]] elim = to_poly(elim) # Criterion suggested by Mohab Safey El Din to avoid cases where there # is no rational parameterization or where the one returned by msolve @@ -301,8 +292,7 @@ def to_poly(p, d=1, *, upol=PolynomialRing(base, 't')): else: if len(data[1]) < 2 or len(data[1]) != data[1][0] + 1: - raise NotImplementedError( - f"unsupported msolve output format: {data}") + raise NotImplementedError(f"unsupported msolve output format: {data}") if isinstance(ring, (RealIntervalField_class, RealBallField)): to_out_ring = ring else: @@ -310,8 +300,6 @@ def to_poly(p, d=1, *, upol=PolynomialRing(base, 't')): myRIF = RealIntervalField(ring.precision()) to_out_ring = lambda iv: ring.coerce(myRIF(iv).center()) vars = out_ring.gens() - variety = [[to_out_ring(iv) for iv in point] - for l in data[1][1:] - for point in l] + variety = [[to_out_ring(iv) for iv in point] for l in data[1][1:] for point in l] return [KeyConvertingDict(out_ring, zip(vars, point)) for point in variety] diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index 79542c42e12..bd16f873556 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -37,6 +37,7 @@ ....: + (a0*b2 - a1*b3 + a2*b0 + a3*b1)^2 + (a0*b3 + a1*b2 - a2*b1 + a3*b0)^2) True """ + # **************************************************************************** # # Sage: Open Source Mathematical Software @@ -94,6 +95,7 @@ class MPolynomial_element(MPolynomial): them. This is not ideal because of the presence of inexact zeros, see :issue:`35174`. """ + def __init__(self, parent, x): """ EXAMPLES:: @@ -183,7 +185,7 @@ def __call__(self, *x, **kwds): y = K(0) one = K(1) for m, c in self.element().dict().items(): - y += c * prod((v ** e for v, e in zip(x, m) if e), one) + y += c * prod((v**e for v, e in zip(x, m) if e), one) return y def _richcmp_(self, right, op): @@ -215,8 +217,7 @@ def _richcmp_(self, right, op): sage: x^4*y^7*z^1 < x^4*y^2*z^3 # needs sage.rings.number_field False """ - return self.__element.rich_compare(right.__element, op, - self.parent().term_order().sortkey) + return self.__element.rich_compare(right.__element, op, self.parent().term_order().sortkey) def _im_gens_(self, codomain, im_gens, base_map=None): """ @@ -244,8 +245,8 @@ def _im_gens_(self, codomain, im_gens, base_map=None): if base_map is None: # Just use conversion base_map = codomain - for (m,c) in self.element().dict().items(): - y += base_map(c)*prod([ im_gens[i]**m[i] for i in range(n) if m[i] ]) + for m, c in self.element().dict().items(): + y += base_map(c) * prod([im_gens[i] ** m[i] for i in range(n) if m[i]]) return y def number_of_terms(self): @@ -421,6 +422,7 @@ class MPolynomial_polydict(Polynomial_singular_repr, MPolynomial_element): Multivariate polynomials implemented in pure python using polydicts. """ + def __init__(self, parent, x): """ EXAMPLES:: @@ -451,7 +453,7 @@ def _new_constant_poly(self, x, P): sage: x._new_constant_poly(R.base_ring()(2),R) 2 """ - return MPolynomial_polydict(P, {P._zero_tuple:x}) + return MPolynomial_polydict(P, {P._zero_tuple: x}) def _repr_(self): """ @@ -472,9 +474,7 @@ def _repr_(self): except AttributeError: key = None atomic = self.parent().base_ring()._repr_option('element_is_atomic') - return self.element().poly_repr(self.parent().variable_names(), - atomic_coefficients=atomic, - sortkey=key) + return self.element().poly_repr(self.parent().variable_names(), atomic_coefficients=atomic, sortkey=key) def _latex_(self): r""" @@ -493,8 +493,7 @@ def _latex_(self): except AttributeError: key = None atomic = self.parent().base_ring()._repr_option('element_is_atomic') - return self.element().latex(self.parent().latex_variable_names(), - atomic_coefficients=atomic, sortkey=key) + return self.element().latex(self.parent().latex_variable_names(), atomic_coefficients=atomic, sortkey=key) def _repr_with_changed_varnames(self, varnames): """ @@ -510,8 +509,7 @@ def _repr_with_changed_varnames(self, varnames): except AttributeError: key = None atomic = self.parent().base_ring()._repr_option('element_is_atomic') - return self.element().poly_repr(varnames, - atomic_coefficients=atomic, sortkey=key) + return self.element().poly_repr(varnames, atomic_coefficients=atomic, sortkey=key) def _macaulay2_(self, macaulay2=None): """ @@ -532,6 +530,7 @@ def _macaulay2_(self, macaulay2=None): """ if macaulay2 is None: from sage.interfaces.macaulay2 import macaulay2 as m2_default + macaulay2 = m2_default m2_parent = macaulay2(self.parent()) macaulay2.use(m2_parent) @@ -893,7 +892,7 @@ def __getitem__(self, x): try: x = tuple(x) except TypeError: - x = (x, ) + x = (x,) try: return self.element()[x] except KeyError: @@ -1075,6 +1074,7 @@ def global_height(self, prec=None): if self.is_zero(): from sage.rings.real_mpfr import RealField + return RealField(prec).zero() from sage.categories.number_fields import NumberFields @@ -1082,14 +1082,16 @@ def global_height(self, prec=None): K = self.base_ring() if K in NumberFields() or isinstance(K, (sage.rings.abc.Order, sage.rings.integer_ring.IntegerRing_class)): from sage.schemes.projective.projective_space import ProjectiveSpace - Pr = ProjectiveSpace(K, self.number_of_terms()-1) + + Pr = ProjectiveSpace(K, self.number_of_terms() - 1) return Pr.point(self.coefficients()).global_height(prec=prec) if isinstance(K, sage.rings.abc.AlgebraicField): from sage.rings.qqbar import number_field_elements_from_algebraics K_pre, P, phi = number_field_elements_from_algebraics(list(self.coefficients())) from sage.schemes.projective.projective_space import ProjectiveSpace - Pr = ProjectiveSpace(K_pre, len(P)-1) + + Pr = ProjectiveSpace(K_pre, len(P) - 1) return Pr.point(P).global_height(prec=prec) raise TypeError("Must be over a Numberfield or a Numberfield Order.") @@ -1355,7 +1357,7 @@ def is_gen(self) -> bool: """ elt = self.element() if len(elt) == 1: - (e, c), = elt.dict().items() + ((e, c),) = elt.dict().items() return e.nonzero_values() == [1] and c.is_one() return False @@ -1484,8 +1486,7 @@ def monomials(self): """ ring = self.parent() one = ring.base_ring().one() - return [MPolynomial_polydict(ring, polydict.PolyDict({m: one}, check=False)) - for m in self._exponents] + return [MPolynomial_polydict(ring, polydict.PolyDict({m: one}, check=False)) for m in self._exponents] def constant_coefficient(self): """ @@ -1501,10 +1502,10 @@ def constant_coefficient(self): sage: f.constant_coefficient() 0 """ - #v = (0,)*int(self.parent().ngens()) + # v = (0,)*int(self.parent().ngens()) d = self.element().dict() try: - return d[polydict.ETuple({},self.parent().ngens())] + return d[polydict.ETuple({}, self.parent().ngens())] except KeyError: return self.parent().base_ring().zero() @@ -1582,7 +1583,7 @@ def univariate_polynomial(self, R=None): if not self.is_univariate(): raise TypeError("polynomial must involve at most one variable") - #construct ring if None + # construct ring if None if R is None: # constant, we just pick first variable from parent if self.is_constant(): @@ -1593,24 +1594,25 @@ def univariate_polynomial(self, R=None): monomial_coefficients = self._MPolynomial_element__element.dict() if not self.is_constant(): - var_idx = self.degrees().nonzero_positions()[0] #variable + var_idx = self.degrees().nonzero_positions()[0] # variable else: - var_idx = 0 #constant + var_idx = 0 # constant if len(monomial_coefficients) == 0: return R(0) - #construct list - lookup = [0,] * len(next(iter(monomial_coefficients))) + # construct list + lookup = [ + 0, + ] * len(next(iter(monomial_coefficients))) coefficients = [] - for degree in range(max(m[var_idx] - for m in monomial_coefficients.keys()) + 1): + for degree in range(max(m[var_idx] for m in monomial_coefficients.keys()) + 1): lookup[var_idx] = int(degree) try: - coefficients.append( monomial_coefficients[ polydict.ETuple(lookup) ] ) #if we find something, add the coefficient + coefficients.append(monomial_coefficients[polydict.ETuple(lookup)]) # if we find something, add the coefficient except KeyError: - coefficients.append( 0 ) #else add zero + coefficients.append(0) # else add zero - #construct polynomial + # construct polynomial return R(coefficients) def variables(self): @@ -1731,7 +1733,7 @@ def lm(self): R = self.parent() f = self._MPolynomial_element__element.lcmt(R.term_order().greater_tuple) one = R.base_ring().one() - self.__lm = MPolynomial_polydict(R,polydict.PolyDict({f: one}, check=False)) + self.__lm = MPolynomial_polydict(R, polydict.PolyDict({f: one}, check=False)) return self.__lm def lc(self): @@ -1753,7 +1755,7 @@ def lc(self): return self.base_ring()._zero_element R = self.parent() f = self._MPolynomial_element__element.dict() - self.__lc = f[self._MPolynomial_element__element.lcmt( R.term_order().greater_tuple )] + self.__lc = f[self._MPolynomial_element__element.lcmt(R.term_order().greater_tuple)] return self.__lc def lt(self): @@ -1903,8 +1905,7 @@ def _derivative(self, var=None): if index == -1: # var is not a generator; do term-by-term differentiation recursively # var may be, for example, a generator of the base ring - d = {e: x._derivative(var) - for e, x in self.monomial_coefficients().items()} + d = {e: x._derivative(var) for e, x in self.monomial_coefficients().items()} d = polydict.PolyDict(d, check=False) d.remove_zeros() return MPolynomial_polydict(P, d) @@ -1975,8 +1976,7 @@ def integral(self, var=None): Multivariate Polynomial Ring in y, z over Univariate Polynomial Ring in x over Rational Field """ if var is None: - raise ValueError("must specify which variable to integrate " - "with respect to") + raise ValueError("must specify which variable to integrate " "with respect to") # TODO: # calling the coercion model bin_op is much more accurate than using the @@ -1999,8 +1999,7 @@ def integral(self, var=None): if index == -1: # var is not a generator; do term-by-term integration recursively # var may be, for example, a generator of the base ring - d = {e: x.integral(var) - for e, x in self.monomial_coefficients().items()} + d = {e: x.integral(var) for e, x in self.monomial_coefficients().items()} d = polydict.PolyDict(d, check=False) d.remove_zeros() else: @@ -2127,9 +2126,9 @@ def factor(self, proof=None): if R.ngens() == 0: base_ring = self.base_ring() if base_ring.is_field(): - return Factorization([],unit=self.base_ring()(self)) + return Factorization([], unit=self.base_ring()(self)) F = base_ring(self).factor() - return Factorization([(R(f),m) for f,m in F], unit=F.unit()) + return Factorization([(R(f), m) for f, m in F], unit=F.unit()) base_ring = self.base_ring() if hasattr(base_ring, '_factor_multivariate_polynomial'): @@ -2149,6 +2148,7 @@ def factor(self, proof=None): if proof is None: from sage.structure.proof.proof import get_flag + proof = get_flag(subsystem='polynomial') if proof: raise NotImplementedError("Provably correct factorization not implemented. Disable this error by wrapping your code in a `with proof.WithProof('polynomial', False):` block.") @@ -2157,8 +2157,7 @@ def factor(self, proof=None): S = self._singular_().factorize() factors = S[1] exponents = S[2] - v = sorted([(R(factors[i + 1]), Integer(exponents[i + 1])) - for i in range(len(factors))]) + v = sorted([(R(factors[i + 1]), Integer(exponents[i + 1])) for i in range(len(factors))]) unit = R(1) for i in range(len(v)): if v[i][0].is_unit(): @@ -2249,12 +2248,12 @@ def quo_rem(self, right): f = self.parent().flattening_morphism() if f.domain() != f.codomain(): g = f.section() - q,r = f(self).quo_rem(f(right)) + q, r = f(self).quo_rem(f(right)) return g(q), g(r) raise else: X = self._singular_().division(right._singular_()) - return R(X[1][1,1]), R(X[2][1]) + return R(X[1][1, 1]), R(X[2][1]) @handle_AA_and_QQbar def resultant(self, other, variable=None): @@ -2448,7 +2447,7 @@ def reduce(self, I): plm = p.lm() gilm = gi.lm() if P.monomial_divides(gilm, plm): - quot = p.lc()/gi.lc() * P.monomial_quotient(plm, gilm) + quot = p.lc() / gi.lc() * P.monomial_quotient(plm, gilm) p -= quot * gi break else: @@ -2462,6 +2461,7 @@ def reduce(self, I): # Useful for some geometry code. ############################################################### + def degree_lowest_rational_function(r, x): r""" Return the difference of valuations of ``r`` with respect to variable ``x``. @@ -2503,6 +2503,7 @@ def degree_lowest_rational_function(r, x): -1 """ from sage.rings.fraction_field import FractionField + F = FractionField(r.parent()) r = F(r) f = r.numerator().polynomial(x) diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index bd0600bd8a5..144c9f50b27 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -249,16 +249,14 @@ from sage.rings.integer_ring import ZZ from sage.rings.noncommutative_ideals import Ideal_nc from sage.rings.qqbar_decorators import handle_AA_and_QQbar -from sage.structure.richcmp import (op_EQ, op_GE, op_GT, op_LE, op_LT, op_NE, - rich_to_bool, richcmp_method) +from sage.structure.richcmp import op_EQ, op_GE, op_GT, op_LE, op_LT, op_NE, rich_to_bool, richcmp_method from sage.structure.sequence import Sequence, Sequence_generic try: from sage.interfaces.expect import StdOutContext from sage.interfaces.singular import singular as singular_default from sage.interfaces.singular import singular_gb_standard_options - from sage.libs.singular.standard_options import \ - libsingular_gb_standard_options + from sage.libs.singular.standard_options import libsingular_gb_standard_options except ImportError: singular_gb_standard_options = libsingular_gb_standard_options = MethodDecorator @@ -280,6 +278,7 @@ class RequireField(MethodDecorator): This decorator is used automatically internally so the user does not need to use it manually. """ + def __call__(self, *args, **kwds): """ EXAMPLES:: @@ -401,13 +400,12 @@ def _groebner_basis_magma(self, deg_bound=None, prot=False, magma=magma_default) print("Highest degree reached during computation: %2d." % log_parser.max_deg) # TODO: rewrite this to be much more sophisticated in multi-level nested cases. - mgb = [str(mgb[i+1]) for i in range(len(mgb))] + mgb = [str(mgb[i + 1]) for i in range(len(mgb))] if R.base_ring().degree() > 1: a = str(R.base_ring().gen()) - mgb = [e.replace("$.1",a) for e in mgb] + mgb = [e.replace("$.1", a) for e in mgb] - from sage.rings.polynomial.multi_polynomial_sequence import \ - PolynomialSequence + from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence return PolynomialSequence([R(e) for e in mgb], R, immutable=True) @@ -436,10 +434,11 @@ def syzygy_module(self): ALGORITHM: Uses Singular's syz command """ from sage.libs.singular.function_factory import ff + syz = ff.syz from sage.matrix.constructor import matrix - #return self._singular_().syz().transpose().sage_matrix(self.ring()) + # return self._singular_().syz().transpose().sage_matrix(self.ring()) S = syz(self) return matrix(self.ring(), S) @@ -502,8 +501,8 @@ def _groebner_basis_libsingular(self, algorithm='groebner', *args, **kwds): from sage.libs.singular.function import singular_function from sage.libs.singular.function_factory import ff from sage.libs.singular.option import opt - from sage.rings.polynomial.multi_polynomial_ideal_libsingular import ( - slimgb_libsingular, std_libsingular) + from sage.rings.polynomial.multi_polynomial_ideal_libsingular import slimgb_libsingular, std_libsingular + groebner = ff.groebner if get_verbose() >= 2: @@ -562,25 +561,25 @@ def _groebner_cover(self): from sage.rings.fraction_field import FractionField_generic from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + F = self.base_ring() - if (not isinstance(F, FractionField_generic) or - not isinstance(F.ring(), (MPolynomialRing_base, PolynomialRing_generic))): + if not isinstance(F, FractionField_generic) or not isinstance(F.ring(), (MPolynomialRing_base, PolynomialRing_generic)): raise TypeError("the base ring must be a field with parameters") from sage.arith.functions import lcm from sage.libs.singular.function import lib, singular_function + lib("grobcov.lib") grobcov = singular_function("grobcov") - polynomials = [f * lcm([c.denominator() for c in f.coefficients()]) - for f in self.gens()] + polynomials = [f * lcm([c.denominator() for c in f.coefficients()]) for f in self.gens()] return grobcov(self.ring().ideal(polynomials)) -class MPolynomialIdeal_singular_repr( - MPolynomialIdeal_singular_base_repr): +class MPolynomialIdeal_singular_repr(MPolynomialIdeal_singular_base_repr): """ An ideal in a multivariate polynomial ring, which has an underlying Singular ring associated to it. """ + def _singular_(self, singular=None): """ Return Singular ideal corresponding to this ideal. @@ -884,7 +883,7 @@ def associated_primes(self, algorithm='sy'): Computational Approach To Commutative Algebra. Springer, New York 1993. """ - return [P for _,P in self.complete_primary_decomposition(algorithm)] + return [P for _, P in self.complete_primary_decomposition(algorithm)] def is_prime(self, **kwds): r""" @@ -1058,9 +1057,9 @@ def triangular_decomposition(self, algorithm=None, singular=None): if algorithm is None: algorithm = "singular:triangL" - if algorithm in ("singular:triangL","singular:triangLfak","singular:triangM"): + if algorithm in ("singular:triangL", "singular:triangLfak", "singular:triangM"): f = singular_function(algorithm[9:]) - Tbar = f(I, attributes={I:{'isSB':1}}) + Tbar = f(I, attributes={I: {'isSB': 1}}) else: raise TypeError("algorithm '%s' unknown" % algorithm) @@ -1138,9 +1137,10 @@ def dimension(self, singular=None): return self.__dimension try: from sage.libs.singular.function_factory import ff + dim = ff.dim - v = MPolynomialIdeal(self.ring(),self.groebner_basis()) - self.__dimension = Integer(dim(v, attributes={v:{'isSB':1}})) + v = MPolynomialIdeal(self.ring(), self.groebner_basis()) + self.__dimension = Integer(dim(v, attributes={v: {'isSB': 1}})) except TypeError: try: v = self._groebner_basis_singular_raw() @@ -1152,6 +1152,7 @@ def dimension(self, singular=None): # See Chapter 9, Section 1 of Cox, Little, O'Shea's # "Ideals, Varieties, and Algorithms" from sage.sets.set import Set + gb = toy_buchberger.buchberger_improved(self) if self.ring().one() in gb: self.__dimension = Integer(-1) @@ -1164,7 +1165,7 @@ def dimension(self, singular=None): for j in range(len(ring_vars)): for i in range(len(lms)): if lms[i].degree(ring_vars[j]) > 0: - var_lms[i] += Set([j+1]) + var_lms[i] += Set([j + 1]) # compute intersections of M_j and J # we assume that the iterator starts with the empty set, # then iterates through all subsets of order 1, @@ -1240,11 +1241,13 @@ def vector_space_dimension(self): gb = R.ideal(self.groebner_basis()) from sage.libs.singular.function_factory import ff + vdim = ff.vdim - vd = Integer(vdim(gb, attributes={gb:{'isSB':1}})) + vd = Integer(vdim(gb, attributes={gb: {'isSB': 1}})) if vd == -1: from sage.rings.infinity import Infinity + return Infinity return vd @@ -1294,13 +1297,14 @@ def _groebner_basis_ginv(self, algorithm='TQ', criteria='CritPartially', divisio st = ginv.SystemType("Polynomial") - term_order_map = {'degrevlex':"DegRevLex",'lex':"Lex"} + term_order_map = {'degrevlex': "DegRevLex", 'lex': "Lex"} try: im = ginv.MonomInterface(term_order_map[T.name()], st, list(P.variable_names())) except KeyError: raise NotImplementedError("Term order '%s' not supported by Sage's GINV interface or GINV" % T.term_order()) from sage.rings.rational_field import QQ + if K is QQ: ic = ginv.CoeffInterface("GmpQ", st) elif K.order() <= 2**16 and K.order().is_prime(): @@ -1375,12 +1379,11 @@ def _groebner_basis_singular(self, algorithm='groebner', *args, **kwds): This method is called by the :meth:`.groebner_basis` method and the user usually doesn't need to bother with this one. """ - from sage.rings.polynomial.multi_polynomial_sequence import \ - PolynomialSequence + from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence R = self.ring() S = self._groebner_basis_singular_raw(algorithm=algorithm, *args, **kwds) - S = PolynomialSequence([R(S[i+1]) for i in range(len(S))], R, immutable=True) + S = PolynomialSequence([R(S[i + 1]) for i in range(len(S))], R, immutable=True) return S @cached_method @@ -1409,41 +1412,43 @@ def _groebner_basis_singular_raw(self, algorithm='groebner', singular=None, *arg """ if singular is None: singular = singular_default - #try: + # try: # return self.__gb_singular - #except AttributeError: + # except AttributeError: # pass # singular options are preserved by @singular_gb_standard_options, # so we don't need to do that here too from sage.libs.singular.option import _options_py_to_singular - S = self._singular_() # for degBound, we need to ensure - # that a ring is defined + + S = self._singular_() # for degBound, we need to ensure + # that a ring is defined if get_verbose() >= 2: kwds['prot'] = True for o, v in kwds.items(): - o = _options_py_to_singular.get(o,o) + o = _options_py_to_singular.get(o, o) if v: - if o in ['degBound','multBound']: - singular.eval(o+'=%d' % v) + if o in ['degBound', 'multBound']: + singular.eval(o + '=%d' % v) else: singular.option(o) else: - if o in ['degBound','multBound']: - singular.eval(o+'=0') + if o in ['degBound', 'multBound']: + singular.eval(o + '=0') else: - singular.option("no"+o) + singular.option("no" + o) obj = self._singular_() - prot = kwds.get('prot',False) + prot = kwds.get('prot', False) if prot == "sage": if algorithm == 'slimgb': warn("'slimgb' does not print sufficient information for prot='sage' to work reliably, the highest degree reached might be too low.") from sage.interfaces.singular import SingularGBLogPrettyPrinter - log_parser = SingularGBLogPrettyPrinter(verbosity=get_verbose()+1) + + log_parser = SingularGBLogPrettyPrinter(verbosity=get_verbose() + 1) else: log_parser = None @@ -1535,6 +1540,7 @@ def genus(self): 3 """ from sage.libs.singular.function_factory import ff + genus = ff.normal__lib.genus return Integer(genus(self)) @@ -1603,6 +1609,7 @@ def intersection(self, *others): raise TypeError("Intersection is only available for ideals of the same ring.") from sage.libs.singular.function_factory import ff + intersect = ff.intersect K = intersect(self, *others) @@ -1630,6 +1637,7 @@ def minimal_associated_primes(self): Uses Singular. """ from sage.libs.singular.function_factory import ff + minAssGTZ = ff.primdec__lib.minAssGTZ M = minAssGTZ(self) @@ -1680,14 +1688,15 @@ def radical(self): of Multivariate Polynomial Ring in x, y, z over Finite Field of size 37 """ from sage.libs.singular.function_factory import ff + radical = ff.primdec__lib.radical r = radical(self) S = self.ring() - #I = self._singular_() - #I.parent().lib('primdec.lib') - #r = I.radical() + # I = self._singular_() + # I.parent().lib('primdec.lib') + # r = I.radical() return S.ideal(r) @@ -1723,11 +1732,11 @@ def integral_closure(self, p=0, r=True, singular=None): Uses libSINGULAR. """ - from sage.rings.polynomial.multi_polynomial_sequence import \ - PolynomialSequence + from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence R = self.ring() from sage.libs.singular.function_factory import ff + normalI = ff.reesclos__lib.normalI ret = PolynomialSequence(normalI(self, p, int(r))[0], R, immutable=True) return ret @@ -1774,10 +1783,11 @@ def syzygy_module(self): (0, 0) """ from sage.libs.singular.function_factory import ff + syz = ff.syz from sage.matrix.constructor import matrix - #return self._singular_().syz().transpose().sage_matrix(self.ring()) + # return self._singular_().syz().transpose().sage_matrix(self.ring()) S = syz(self) return matrix(self.ring(), S) @@ -1812,11 +1822,11 @@ def free_resolution(self, *args, **kwds): ... NotImplementedError: the ring must be a polynomial ring using Singular """ - from sage.rings.polynomial.multi_polynomial_libsingular import \ - MPolynomialRing_libsingular + from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular + if isinstance(self.ring(), MPolynomialRing_libsingular): - from sage.homology.free_resolution import \ - FiniteFreeResolution_singular + from sage.homology.free_resolution import FiniteFreeResolution_singular + return FiniteFreeResolution_singular(self, *args, **kwds) raise NotImplementedError("the ring must be a polynomial ring using Singular") @@ -1853,11 +1863,11 @@ def graded_free_resolution(self, *args, **kwds): ... NotImplementedError: the ring must be a polynomial ring using Singular """ - from sage.rings.polynomial.multi_polynomial_libsingular import \ - MPolynomialRing_libsingular + from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular + if isinstance(self.ring(), MPolynomialRing_libsingular): - from sage.homology.graded_resolution import \ - GradedFiniteFreeResolution_singular + from sage.homology.graded_resolution import GradedFiniteFreeResolution_singular + return GradedFiniteFreeResolution_singular(self, *args, **kwds) raise NotImplementedError("the ring must be a polynomial ring using Singular") @@ -2031,6 +2041,7 @@ def basis_is_groebner(self, singular=None): from sage.libs.singular.function_factory import ff from sage.libs.singular.option import opt_verb_ctx from sage.matrix.constructor import matrix + sing_reduce = ff.reduce syz = ff.syz @@ -2052,15 +2063,15 @@ def basis_is_groebner(self, singular=None): if singular is None: singular = singular_default R._singular_().set_ring() - F = singular( tuple(self.gens()), "module" ) - LTF = singular( [f.lt() for f in self.gens()] , "module" ) + F = singular(tuple(self.gens()), "module") + LTF = singular([f.lt() for f in self.gens()], "module") M = (F * LTF.syz()).reduce(self._singular_()) for i in range(M.ncols()): - if int(singular.eval("%s[1,%s+1]!=0" % (M.name(),i))): + if int(singular.eval("%s[1,%s+1]!=0" % (M.name(), i))): return False - self._singular_().attrib('isSB',1) + self._singular_().attrib('isSB', 1) return True @require_field @@ -2137,8 +2148,8 @@ def transformed_basis(self, algorithm='gwalk', other_ring=None, singular=None): sage: J = Ideal(I.transformed_basis('fglm', other_ring=S)) # known bug sage: J # known bug """ - from sage.rings.polynomial.multi_polynomial_sequence import \ - PolynomialSequence + from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence + R = self.ring() if self.basis_is_groebner(): @@ -2146,11 +2157,12 @@ def transformed_basis(self, algorithm='gwalk', other_ring=None, singular=None): else: I = R.ideal(self.groebner_basis()) - if algorithm in ("gwalk","awalk1","awalk2","twalk","fwalk"): + if algorithm in ("gwalk", "awalk1", "awalk2", "twalk", "fwalk"): from sage.libs.singular.function import lib, singular_function + lib("grwalk.lib") gb = singular_function(algorithm)(I) - return PolynomialSequence(R, sorted(gb,reverse=True), immutable=True) + return PolynomialSequence(R, sorted(gb, reverse=True), immutable=True) if algorithm == "fglm": # new ring @@ -2162,11 +2174,11 @@ def transformed_basis(self, algorithm='gwalk', other_ring=None, singular=None): singular = singular_default Rs = singular(R) Is = singular(I) - Is.attrib('isSB',1) + Is.attrib('isSB', 1) singular(nR).set_ring() - nIs = singular.fglm(Rs,Is) + nIs = singular.fglm(Rs, Is) - return PolynomialSequence(nR, sorted([nR(f) for f in nIs],reverse=True), immutable=True) + return PolynomialSequence(nR, sorted([nR(f) for f in nIs], reverse=True), immutable=True) raise TypeError("cannot convert basis with given algorithm") @@ -2251,14 +2263,13 @@ def elimination_ideal(self, variables, algorithm=None, *args, **kwds): if v not in gens: raise ValueError("not a ring variable: %s" % v) - if (algorithm is None or algorithm.lower() == 'libsingular' - or algorithm == 'libsingular:eliminate'): + if algorithm is None or algorithm.lower() == 'libsingular' or algorithm == 'libsingular:eliminate': return self._elimination_ideal_libsingular(variables) if algorithm.lower() == 'giac' or algorithm == 'giac:eliminate': from sage.libs.giac import groebner_basis as groebner_basis_libgiac - return groebner_basis_libgiac( - self, elim_variables=variables, *args, **kwds).ideal() + + return groebner_basis_libgiac(self, elim_variables=variables, *args, **kwds).ideal() raise NameError("Algorithm '%s' unknown." % algorithm) @@ -2276,11 +2287,12 @@ def _elimination_ideal_libsingular(self, variables): Polynomial Ring in x, y, t, s, z over Rational Field """ from sage.libs.singular.function_factory import ff + eliminate = ff.eliminate R = self.ring() - Is = MPolynomialIdeal(R,self.groebner_basis()) - return MPolynomialIdeal(R, eliminate(Is, prod(variables)) ) + Is = MPolynomialIdeal(R, self.groebner_basis()) + return MPolynomialIdeal(R, eliminate(Is, prod(variables))) @handle_AA_and_QQbar @libsingular_gb_standard_options @@ -2350,6 +2362,7 @@ def quotient(self, J): raise TypeError("base rings do not match") from sage.libs.singular.function_factory import ff + quotient = ff.quotient return R.ideal(quotient(self, J)) @@ -2590,6 +2603,7 @@ def variety(self, ring=None, *, algorithm='triangular_decomposition', proof=True return self._variety_triangular_decomposition(ring) if algorithm == "msolve": from . import msolve + return msolve.variety(self, ring, proof=proof) raise ValueError(f"unknown algorithm {algorithm!r}") @@ -2753,8 +2767,8 @@ def _variety(T, V, v=None): for root in roots: vbar = v.copy() vbar[variable] = root - Tbar = [ f.subs({variable:root}) for f in T ] - _variety(Tbar,V,vbar) + Tbar = [f.subs({variable: root}) for f in T] + _variety(Tbar, V, vbar) return V @@ -2784,10 +2798,10 @@ def _variety(T, V, v=None): raise TypeError("Local/unknown orderings not supported by 'toy_buchberger' implementation.") from sage.misc.converting_dict import KeyConvertingDict + V = [] for t in T: - V.extend(KeyConvertingDict(P, v) - for v in _variety([P(f) for f in t], [])) + V.extend(KeyConvertingDict(P, v) for v in _variety([P(f) for f in t], [])) return V @require_field @@ -2895,6 +2909,7 @@ def hilbert_polynomial(self, algorithm='sage'): raise TypeError("ideal must be homogeneous") if algorithm == 'sage': from sage.misc.misc_c import prod + hilbert_poincare = self.hilbert_series() denom = hilbert_poincare.denominator() if denom.degree() == 0: @@ -2906,11 +2921,11 @@ def hilbert_polynomial(self, algorithm='sage'): # the form (1 - t)^s, need to scale numerator scalar = ~(denom[0] * (s - 1).factorial()) st = s - 1 + t - out = scalar * sum(c * prod(st - n - nu for nu in range(s - 1)) - for n, c in enumerate(numerator)) + out = scalar * sum(c * prod(st - n - nu for nu in range(s - 1)) for n, c in enumerate(numerator)) return t.parent().zero() + out if algorithm == 'singular': from sage.libs.singular.function_factory import ff + hilbPoly = ff.polylib__lib.hilbPoly hp = hilbPoly(self) @@ -3024,11 +3039,10 @@ def hilbert_series(self, grading=None, algorithm='sage'): n = self.ring().ngens() if grading is None: - return self.hilbert_numerator(algorithm='singular') / (1 - t)**n + return self.hilbert_numerator(algorithm='singular') / (1 - t) ** n # The check that ``grading`` is valid input is done by ``hilbert_numerator()`` - return (self.hilbert_numerator(algorithm='singular', grading=grading) - / prod((1 - t**a) for a in grading)) + return self.hilbert_numerator(algorithm='singular', grading=grading) / prod((1 - t**a) for a in grading) raise ValueError("'algorithm' must be one of 'sage' or 'singular'") @require_field @@ -3125,6 +3139,7 @@ def hilbert_numerator(self, grading=None, algorithm='sage'): return first_hilbert_series(gb, grading) if algorithm == 'singular': from sage.libs.singular.function_factory import ff + hilb = ff.hilb gb = self.groebner_basis() @@ -3137,7 +3152,7 @@ def hilbert_numerator(self, grading=None, algorithm='sage'): hs = hilb(gb, 1, tuple(grading), attributes={gb: {'isSB': 1}}) else: hs = hilb(gb, 1, attributes={gb: {'isSB': 1}}) - return sum(ZZ(hs[i]) * t**i for i in range(len(hs)-1)) + return sum(ZZ(hs[i]) * t**i for i in range(len(hs) - 1)) raise ValueError("'algorithm' must be one of 'sage' or 'singular'") @require_field @@ -3191,26 +3206,24 @@ def _normal_basis_libsingular(self, degree, weights=None): sage: I.normal_basis() [k, 1] """ - from sage.rings.polynomial.multi_polynomial_ideal_libsingular import \ - kbase_libsingular - from sage.rings.polynomial.multi_polynomial_sequence import \ - PolynomialSequence + from sage.rings.polynomial.multi_polynomial_ideal_libsingular import kbase_libsingular + from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence + gb = self._groebner_basis_libsingular() J = self.ring().ideal(gb) if weights is None or degree is None: res = kbase_libsingular(J, degree) else: from sage.libs.singular.function_factory import ff - res = ff.weightKB(J, -1 if degree is None else degree, - tuple(weights), attributes={J: {'isSB': 1}}) + + res = ff.weightKB(J, -1 if degree is None else degree, tuple(weights), attributes={J: {'isSB': 1}}) if len(res) == 1 and res[0].is_zero(): res = [] return PolynomialSequence(self.ring(), res, immutable=True) @require_field @handle_AA_and_QQbar - def normal_basis(self, degree=None, algorithm='libsingular', - singular=None): + def normal_basis(self, degree=None, algorithm='libsingular', singular=None): """ Return a vector space basis of the quotient ring of this ideal. @@ -3280,8 +3293,7 @@ def normal_basis(self, degree=None, algorithm='libsingular', sage: S.ideal(x^6 + y^3 + z^2).normal_basis(6, algorithm='singular') # needs sage.rings.finite_rings [x^4*y, x^2*y^2, y^3, x^3*z, x*y*z, z^2] """ - from sage.rings.polynomial.multi_polynomial_sequence import \ - PolynomialSequence + from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence weights = tuple(x.degree() for x in self.ring().gens()) if all(w == 1 for w in weights): @@ -3298,8 +3310,7 @@ def normal_basis(self, degree=None, algorithm='libsingular', elif weights is None: res = singular.kbase(R.ideal(gb), int(degree)) else: - res = singular.weightKB(R.ideal(gb), int(degree), - singular(weights, type='intvec')) + res = singular.weightKB(R.ideal(gb), int(degree), singular(weights, type='intvec')) return PolynomialSequence(R, [R(f) for f in res], immutable=True) @@ -3378,8 +3389,7 @@ def _groebner_basis_macaulay2(self, strategy=None): ... ValueError: unsupported Macaulay2 strategy """ - from sage.rings.polynomial.multi_polynomial_sequence import \ - PolynomialSequence + from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence I = self._macaulay2_() if strategy == "gb" or strategy is None: @@ -3390,10 +3400,10 @@ def _groebner_basis_macaulay2(self, strategy=None): m2G = I.groebnerBasis('Strategy=>"MGB"') else: raise ValueError("unsupported Macaulay2 strategy") - G = str(m2G.external_string()).replace('\n','') + G = str(m2G.external_string()).replace('\n', '') i = G.rfind('{{') j = G.rfind('}}') - G = G[i+2:j].split(',') + G = G[i + 2 : j].split(',') R = self.ring() B = [R(f) for f in G] B = PolynomialSequence(self.ring(), B, immutable=True) @@ -3484,6 +3494,7 @@ def __call_singular(self, cmd, arg=None): [x, y, z] """ from sage.libs.singular.function import singular_function + fun = singular_function(cmd) if arg is None: return fun(self, ring=self.ring()) @@ -3551,8 +3562,9 @@ def std(self): """ if self.side() == 'twosided': return self.twostd() - return self.ring().ideal( self.__call_singular('std'), side=self.side()) -# return self.__call_singular('std') + return self.ring().ideal(self.__call_singular('std'), side=self.side()) + + # return self.__call_singular('std') def groebner_basis(self): r""" @@ -3579,6 +3591,7 @@ def groebner_basis(self): [z^2 - 1, y*z - y, x*z + x, y^2, 2*x*y - z - 1, x^2] """ from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence + return PolynomialSequence(self.std()) def elimination_ideal(self, variables): @@ -3610,12 +3623,14 @@ def elimination_ideal(self, variables): ALGORITHM: Uses Singular's ``eliminate`` command """ from sage.misc.misc_c import prod + if self.side() == 'twosided': J = self.twostd() else: J = self return J.ring().ideal(J.__call_singular('eliminate', prod(variables)), side=self.side()) -# return self.__call_singular('std') + + # return self.__call_singular('std') @cached_method def twostd(self): @@ -3637,11 +3652,12 @@ def twostd(self): ALGORITHM: Uses Singular's ``twostd`` command """ - return self.ring().ideal( self.__call_singular('twostd'), side='twosided') -# return self.__call_singular('twostd') + return self.ring().ideal(self.__call_singular('twostd'), side='twosided') + + # return self.__call_singular('twostd') -# def syz(self): -# return self.__call_singular('syz') + # def syz(self): + # return self.__call_singular('syz') @cached_method def _groebner_strategy(self): @@ -3664,6 +3680,7 @@ def _groebner_strategy(self): This function is mainly used internally. """ from sage.libs.singular.groebner_strategy import NCGroebnerStrategy + return NCGroebnerStrategy(self.std()) def reduce(self, p): @@ -3780,10 +3797,11 @@ def syzygy_module(self): if self.side() == 'twosided': warn("The result of this Syzygy computation is one-sided (left)!") from sage.libs.singular.function_factory import ff + syz = ff.syz from sage.matrix.constructor import matrix - #return self._singular_().syz().transpose().sage_matrix(self.ring()) + # return self._singular_().syz().transpose().sage_matrix(self.ring()) S = syz(self) return matrix(self.ring(), S) @@ -3833,10 +3851,7 @@ def is_homogeneous(self) -> bool: @richcmp_method -class MPolynomialIdeal(MPolynomialIdeal_singular_repr, - MPolynomialIdeal_macaulay2_repr, - MPolynomialIdeal_magma_repr, - Ideal_generic): +class MPolynomialIdeal(MPolynomialIdeal_singular_repr, MPolynomialIdeal_macaulay2_repr, MPolynomialIdeal_magma_repr, Ideal_generic): def __init__(self, ring, gens, coerce=True): r""" Create an ideal in a multivariate polynomial ring. @@ -3889,8 +3904,8 @@ def gens(self) -> Sequence_generic: sage: I.gens() [x, y + 1] """ - from sage.rings.polynomial.multi_polynomial_sequence import \ - PolynomialSequence + from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence + return PolynomialSequence(self.ring(), Ideal_generic.gens(self), immutable=True) @property @@ -4088,13 +4103,13 @@ def __richcmp__(self, other, op): elif len(other_new._gb_by_ordering): o, r = next(iter(other_new._gb_by_ordering.items())) l = self.change_ring(R.change_ring(order=o)).gens() - else: # use easy GB otherwise + else: # use easy GB otherwise newR = R.change_ring(order='degrevlex') l = self.change_ring(newR).gens() r = other_new.change_ring(newR).groebner_basis() # remember this Groebner basis for future reference other_new._gb_by_ordering['degrevlex'] = r - except AttributeError: # e.g. quotient rings + except AttributeError: # e.g. quotient rings r = other_new.groebner_basis() return all(f.reduce(r) == 0 for f in l) @@ -4103,15 +4118,14 @@ def __richcmp__(self, other, op): # first check whether the GBs are cached already if op in [op_EQ, op_NE, op_LT]: try: - if (other_new.groebner_basis.is_in_cache() - or self.groebner_basis().is_in_cache()): + if other_new.groebner_basis.is_in_cache() or self.groebner_basis().is_in_cache(): l = self.groebner_basis() r = other_new.groebner_basis() - else: # use easy GB otherwise + else: # use easy GB otherwise newR = R.change_ring(order='degrevlex') l = self.change_ring(newR).groebner_basis() r = other_new.change_ring(newR).groebner_basis() - except AttributeError: # e.g. quotient rings + except AttributeError: # e.g. quotient rings l = self.groebner_basis() r = other_new.groebner_basis() contained = all(f.reduce(r) == 0 for f in l) @@ -4151,8 +4165,8 @@ def groebner_fan(self, is_groebner_basis=False, symmetry=None, verbose=False): useful info during computations """ from sage.rings.polynomial import groebner_fan - return groebner_fan.GroebnerFan(self, is_groebner_basis=is_groebner_basis, - symmetry=symmetry, verbose=verbose) + + return groebner_fan.GroebnerFan(self, is_groebner_basis=is_groebner_basis, symmetry=symmetry, verbose=verbose) @cached_method(do_pickle=True) @handle_AA_and_QQbar @@ -4612,10 +4626,8 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal ... NotImplementedError: msolve only supports the degrevlex order (use transformed_basis()) """ - from sage.rings.polynomial.multi_polynomial_sequence import \ - PolynomialSequence - from sage.rings.polynomial.polynomial_ring_constructor import \ - PolynomialRing + from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing if algorithm.lower() == "magma": algorithm = "magma:GroebnerBasis" @@ -4651,13 +4663,8 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal # with one variable and then go back. Rt = PolynomialRing(B, 't', 1) It = Rt.ideal([Rt(g) for g in self.gens()]) - gb = [R(g) for g in It.groebner_basis( - algorithm=algorithm, - deg_bound=deg_bound, mult_bound=mult_bound, - prot=prot, *args, **kwds)] - elif (R.term_order().is_global() - and isinstance(B, sage.rings.abc.IntegerModRing) - and not B.is_field()): + gb = [R(g) for g in It.groebner_basis(algorithm=algorithm, deg_bound=deg_bound, mult_bound=mult_bound, prot=prot, *args, **kwds)] + elif R.term_order().is_global() and isinstance(B, sage.rings.abc.IntegerModRing) and not B.is_field(): verbose("Warning: falling back to very slow toy implementation.", level=0) ch = B.characteristic() @@ -4676,7 +4683,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal elif algorithm.startswith('libsingular:'): if prot == "sage": warn("The libsingular interface does not support prot='sage', reverting to 'prot=True'.") - gb = self._groebner_basis_libsingular(algorithm[len('libsingular:'):], deg_bound=deg_bound, mult_bound=mult_bound, prot=prot, *args, **kwds) + gb = self._groebner_basis_libsingular(algorithm[len('libsingular:') :], deg_bound=deg_bound, mult_bound=mult_bound, prot=prot, *args, **kwds) elif algorithm.startswith("macaulay2:"): gb = self._groebner_basis_macaulay2(strategy=algorithm.split(":")[1], *args, **kwds) elif algorithm == 'magma:GroebnerBasis': @@ -4691,20 +4698,21 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal if algorithm == 'ginv': gb = self._groebner_basis_ginv(*args, **kwds) elif ":" in algorithm: - ginv,alg = algorithm.split(":") + ginv, alg = algorithm.split(":") gb = self._groebner_basis_ginv(algorithm=alg, *args, **kwds) else: raise NameError("Algorithm '%s' unknown." % algorithm) elif algorithm == 'giac:gbasis': from sage.libs.giac import groebner_basis as groebner_basis_libgiac + gb = groebner_basis_libgiac(self, prot=prot, *args, **kwds) elif algorithm == 'msolve': if self.ring().term_order() != 'degrevlex': - raise NotImplementedError("msolve only supports the degrevlex order " - "(use transformed_basis())") + raise NotImplementedError("msolve only supports the degrevlex order " "(use transformed_basis())") if not (deg_bound is mult_bound is None) or prot: raise NotImplementedError("unsupported options for msolve") from . import msolve + return msolve.groebner_basis_degrevlex(self, *args, **kwds) else: raise NameError("Algorithm '%s' unknown." % algorithm) @@ -4714,7 +4722,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal _gb = [] for f in gb: if f.lc(): - _gb.append(f*f.lc()**(-1)) + _gb.append(f * f.lc() ** (-1)) else: _gb.append(f) gb = _gb @@ -4759,6 +4767,7 @@ def groebner_cover(self): 1: [1]} """ from sage.schemes.affine.affine_space import AffineSpace + gc = self._groebner_cover() F = self.base_ring() A = AffineSpace(F.base_ring(), F.ngens(), list(F.gens_dict())) @@ -5127,7 +5136,7 @@ def degree_of_semi_regularity(self): semi-regular sequences see [BFS2004]_. """ degs = [f.degree() for f in self.gens() if f != 0] # we ignore zeroes - m, n = self.ngens(), len(set(sum([f.variables() for f in self.gens()],()))) + m, n = self.ngens(), len(set(sum([f.variables() for f in self.gens()], ()))) if m <= n: raise ValueError("This function requires an overdefined system of polynomials.") @@ -5136,7 +5145,7 @@ def degree_of_semi_regularity(self): from sage.rings.rational_field import QQ z = PowerSeriesRing(QQ, 'z', default_prec=sum(degs)).gen() - s = prod([1-z**d for d in degs]) / (1-z)**n + s = prod([1 - z**d for d in degs]) / (1 - z) ** n for dreg in range(sum(degs)): if s[dreg] <= 0: return ZZ(dreg) @@ -5228,32 +5237,32 @@ def plot(self, *args, **kwds): for e in args: if not isinstance(e, (tuple, list)) or len(e) != 3: raise TypeError("Optional parameter must be list or tuple or length 3.") - v,mi,ma = e + v, mi, ma = e if v not in variables: raise TypeError("Optional parameter must contain variable of ideal generator.") vi = variables.index(v) - V[vi] = v,mi,ma + V[vi] = v, mi, ma # now check whether we should find boundaries for var_index in range(2): if V[var_index][1] is None: v, mi, ma = variables[var_index], -10, 10 for i in range(mi, ma): - poly = f.subs({v:i}).univariate_polynomial().change_ring(RR) + poly = f.subs({v: i}).univariate_polynomial().change_ring(RR) if not poly or len(poly.roots()) > 0: mi = i - 1 break for i in range(ma, mi, -1): - poly = f.subs({v:i}).univariate_polynomial().change_ring(RR) + poly = f.subs({v: i}).univariate_polynomial().change_ring(RR) if not poly or len(poly.roots()) > 0: ma = i + 1 break V[var_index] = variables[var_index], mi, ma - kwds.setdefault("plot_points",200) + kwds.setdefault("plot_points", 200) return implicit_plot(f, V[0], V[1], **kwds) def random_element(self, degree, compute_gb=False, *args, **kwds): @@ -5349,7 +5358,7 @@ def random_element(self, degree, compute_gb=False, *args, **kwds): d = degree - f.degree() if d >= 0: h = R.random_element(degree=d, *args, **kwds) - r += h*f + r += h * f return r @require_field @@ -5521,8 +5530,7 @@ def weil_restriction(self): Based on a Singular implementation by Michael Brickenstein """ - from sage.rings.polynomial.polynomial_ring_constructor import \ - PolynomialRing + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing R = self.ring() nvars = R.ngens() @@ -5552,8 +5560,7 @@ def weil_restriction(self): map_ideal = [a] variables = iter(intermediate_ring.gens()[1:]) - map_ideal.extend(sum([a**i * next(variables) for i in range(r)]) - for _ in range(nvars)) + map_ideal.extend(sum([a**i * next(variables) for i in range(r)]) for _ in range(nvars)) myminpoly = myminpoly(*map_ideal) l = [f(*map_ideal).reduce([myminpoly]) for f in l] @@ -5569,8 +5576,7 @@ def weil_restriction(self): result += reversed(t) # eliminate parameter - new_var_names = [str(var) + "%d" % i for var in R.gens() - for i in range(r)] + new_var_names = [str(var) + "%d" % i for var in R.gens() for i in range(r)] result_ring = PolynomialRing(k, nvars * r, new_var_names) @@ -5593,6 +5599,7 @@ class MPolynomialIdeal_quotient(QuotientRingIdeal_generic, MPolynomialIdeal): of Multivariate Polynomial Ring in x, y, z, w over Rational Field by the ideal (x*y - z^2, y^2 - w^2) """ + def reduce(self, f): r""" Reduce an element modulo a Gröbner basis for this ideal. diff --git a/src/sage/rings/polynomial/multi_polynomial_ring.py b/src/sage/rings/polynomial/multi_polynomial_ring.py index 0d09ed5e9dc..34c527ea298 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring.py +++ b/src/sage/rings/polynomial/multi_polynomial_ring.py @@ -50,6 +50,7 @@ (Multivariate Polynomial Ring in x, y, z over Finite Field of size 5, (x, y, z)) """ + # **************************************************************************** # Copyright (C) 2005 William Stein # @@ -80,6 +81,7 @@ class MPolynomialRing_macaulay2_repr: """ A mixin class for polynomial rings that support conversion to Macaulay2. """ + def _macaulay2_init_(self, macaulay2=None): """ EXAMPLES:: @@ -89,9 +91,9 @@ def _macaulay2_init_(self, macaulay2=None): """ if macaulay2 is None: from sage.interfaces.macaulay2 import macaulay2 as m2_default + macaulay2 = m2_default - return macaulay2._macaulay2_input_ring(self.base_ring(), self.gens(), - self.term_order().macaulay2_str()) + return macaulay2._macaulay2_input_ring(self.base_ring(), self.gens(), self.term_order().macaulay2_str()) class MPolynomialRing_polydict(MPolynomialRing_macaulay2_repr, PolynomialRing_singular_repr, MPolynomialRing_base): @@ -105,11 +107,14 @@ class MPolynomialRing_polydict(MPolynomialRing_macaulay2_repr, PolynomialRing_si sage: loads(R.dumps()) == R True """ + from sage.rings.polynomial.multi_polynomial_element import MPolynomial_polydict as Element_hidden + # should be just Element, once polynomial use new coercion framework def __init__(self, base_ring, n, names, order): from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular + order = TermOrder(order, n) # MPolynomialRing_base.__init__() normally initialises the base ring, # but it also needs the generators to construct a coercion map from the @@ -144,10 +149,7 @@ def __eq__(self, other): """ if not isinstance(other, MPolynomialRing_base): return False - return ((self.base_ring(), self.ngens(), - self.variable_names(), self.term_order()) == - (other.base_ring(), other.ngens(), - other.variable_names(), other.term_order())) + return (self.base_ring(), self.ngens(), self.variable_names(), self.term_order()) == (other.base_ring(), other.ngens(), other.variable_names(), other.term_order()) def __ne__(self, other): """ @@ -169,8 +171,7 @@ def __hash__(self): sage: h = hash(PolynomialRing(Integers(8), 'x', 3)) """ - return hash((self.base_ring(), self.ngens(), - self.variable_names(), self.term_order())) + return hash((self.base_ring(), self.ngens(), self.variable_names(), self.term_order())) def _element_constructor_(self, x=0, check=True): """ @@ -446,14 +447,11 @@ def _element_constructor_(self, x=0, check=True): D[i] = K(a) return MPolynomial_polydict(self, D) - if (set(P.variable_names()).issubset(set(self.variable_names())) - and self.base_ring().has_coerce_map_from(P.base_ring())): + if set(P.variable_names()).issubset(set(self.variable_names())) and self.base_ring().has_coerce_map_from(P.base_ring()): # If the named variables are a superset of the input, map the variables by name return MPolynomial_polydict(self, self._extract_polydict(x)) - return MPolynomial_polydict(self, - x._mpoly_dict_recursive(self.variable_names(), - self.base_ring())) + return MPolynomial_polydict(self, x._mpoly_dict_recursive(self.variable_names(), self.base_ring())) if isinstance(x, MPolynomial_libsingular): P = x.parent() @@ -476,19 +474,14 @@ def _element_constructor_(self, x=0, check=True): D[i] = K(a) return MPolynomial_polydict(self, D) - if (set(P.variable_names()).issubset(set(self.variable_names())) - and self.base_ring().has_coerce_map_from(P.base_ring())): + if set(P.variable_names()).issubset(set(self.variable_names())) and self.base_ring().has_coerce_map_from(P.base_ring()): # If the named variables are a superset of the input, map the variables by name return MPolynomial_polydict(self, self._extract_polydict(x)) - return MPolynomial_polydict(self, - x._mpoly_dict_recursive(self.variable_names(), - self.base_ring())) + return MPolynomial_polydict(self, x._mpoly_dict_recursive(self.variable_names(), self.base_ring())) if isinstance(x, polynomial_element.Polynomial): - return MPolynomial_polydict(self, - x._mpoly_dict_recursive(self.variable_names(), - self.base_ring())) + return MPolynomial_polydict(self, x._mpoly_dict_recursive(self.variable_names(), self.base_ring())) if isinstance(x, PolyDict): return MPolynomial_polydict(self, x) @@ -497,8 +490,7 @@ def _element_constructor_(self, x=0, check=True): K = self.base_ring() return MPolynomial_polydict(self, {i: K(a) for i, a in x.items()}) - if (isinstance(x, fraction_field_element.FractionFieldElement) - and x.parent().ring() == self): + if isinstance(x, fraction_field_element.FractionFieldElement) and x.parent().ring() == self: if x.denominator() == 1: return x.numerator() @@ -516,6 +508,7 @@ def _element_constructor_(self, x=0, check=True): if isinstance(x, str): from sage.misc.sage_eval import sage_eval + try: x = sage_eval(x, self.gens_dict_recursive()) except NameError: @@ -546,7 +539,7 @@ def _element_constructor_(self, x=0, check=True): if d.type() == 't_INFINITY': return self.zero() v = self.gens_dict_recursive()[str(x.variable())] - return sum(self(x[i]) * v ** i for i in range(d + 1)) + return sum(self(x[i]) * v**i for i in range(d + 1)) if isinstance(x, dict): return MPolynomial_polydict(self, x) @@ -694,13 +687,12 @@ def monomial_lcm(self, f, g): """ one = self.base_ring().one() - f, = f.monomial_coefficients() - g, = g.monomial_coefficients() + (f,) = f.monomial_coefficients() + (g,) = g.monomial_coefficients() length = len(f) - res = {i: max(f[i], g[i]) - for i in f.common_nonzero_positions(g)} + res = {i: max(f[i], g[i]) for i in f.common_nonzero_positions(g)} return self(PolyDict({ETuple(res, length): one})) @@ -797,11 +789,10 @@ def monomial_divides(self, a, b): if not a: raise ZeroDivisionError - a, = a.monomial_coefficients() - b, = b.monomial_coefficients() + (a,) = a.monomial_coefficients() + (b,) = b.monomial_coefficients() - return all(b[i] >= a[i] - for i in b.common_nonzero_positions(a)) + return all(b[i] >= a[i] for i in b.common_nonzero_positions(a)) def monomial_pairwise_prime(self, h, g): r""" @@ -891,7 +882,7 @@ def addwithcarry(tempvector, maxvector, pos): one = self.base_ring().one() M = list() - v, = t.monomial_coefficients() + (v,) = t.monomial_coefficients() maxvector = list(v) tempvector = [0] * len(maxvector) @@ -929,6 +920,7 @@ def sum(self, terms): # NOTE: here we should be using self.element_class but # polynomial rings are not yet compliant with categories... from sage.rings.polynomial.multi_polynomial_element import MPolynomial_polydict + return MPolynomial_polydict(self, elt) diff --git a/src/sage/rings/polynomial/multi_polynomial_sequence.py b/src/sage/rings/polynomial/multi_polynomial_sequence.py index 389687afd5a..a7cac8d2df7 100644 --- a/src/sage/rings/polynomial/multi_polynomial_sequence.py +++ b/src/sage/rings/polynomial/multi_polynomial_sequence.py @@ -178,8 +178,7 @@ try: from sage.interfaces.singular import singular, singular_gb_standard_options - from sage.libs.singular.standard_options import \ - libsingular_gb_standard_options + from sage.libs.singular.standard_options import libsingular_gb_standard_options except ImportError: singular = None singular_gb_standard_options = libsingular_gb_standard_options = MethodDecorator @@ -284,18 +283,14 @@ def PolynomialSequence(arg1, arg2=None, immutable=False, cr=False, cr_str=None): ) """ from sage.structure.element import Matrix + try: from sage.rings.polynomial.pbori.pbori import BooleanMonomialMonoid except ImportError: BooleanMonomialMonoid = () def is_ring(r): - return (isinstance(r, (MPolynomialRing_base, - NCPolynomialRing_plural, - BooleanMonomialMonoid, - InfinitePolynomialRing_sparse)) - or (isinstance(r, QuotientRing_nc) - and isinstance(r.cover_ring(), MPolynomialRing_base))) + return isinstance(r, (MPolynomialRing_base, NCPolynomialRing_plural, BooleanMonomialMonoid, InfinitePolynomialRing_sparse)) or (isinstance(r, QuotientRing_nc) and isinstance(r.cover_ring(), MPolynomialRing_base)) if is_ring(arg1): ring, gens = arg1, arg2 @@ -352,10 +347,11 @@ def is_ring(r): except TypeError: nested = True from itertools import chain + if nested: parts = tuple(tuple(ring(f) for f in part) for part in chain([e], gens)) else: - parts = tuple(chain([e2], map(ring, gens))), + parts = (tuple(chain([e2], map(ring, gens))),) except StopIteration: parts = ((),) @@ -410,8 +406,7 @@ def __init__(self, parts, ring, immutable=False, cr=False, cr_str=None): 2*a*b + 2*b*c + 2*c*d - b, b^2 + 2*a*c + 2*b*d - c] """ - Sequence_generic.__init__(self, sum(parts, tuple()), ring, check=False, immutable=immutable, - cr=cr, cr_str=cr_str, use_sage_types=True) + Sequence_generic.__init__(self, sum(parts, tuple()), ring, check=False, immutable=immutable, cr=cr, cr_str=cr_str, use_sage_types=True) self._ring = ring self._parts = parts @@ -760,13 +755,7 @@ def coefficients_monomials(self, order=None, sparse=True): raise ValueError("order argument does not contain all monomials") return A, vector(v) - def macaulay_matrix(self, degree, - homogeneous=False, - variables=None, - return_indices=False, - remove_zero=False, - reverse_column_order=False, - row_order=None): + def macaulay_matrix(self, degree, homogeneous=False, variables=None, return_indices=False, remove_zero=False, reverse_column_order=False, row_order=None): r""" Return the Macaulay matrix of degree ``degree`` for this sequence of polynomials. @@ -964,8 +953,7 @@ def macaulay_matrix(self, degree, if str(x) not in vars_names_base_ring: raise ValueError("the variables must be in the polynomial ring") try: - R = PolynomialRing(F, variables, - order=S.term_order()) + R = PolynomialRing(F, variables, order=S.term_order()) except ValueError: raise ValueError("impossible to use the original term order (most likely because it was a block order). Please specify the term order for the subring") @@ -1009,7 +997,7 @@ def macaulay_matrix(self, degree, # order the rows with TOP else: R_monomials_useful = [] - for i in range(degree, target_degree-self.minimal_degree()+1): + for i in range(degree, target_degree - self.minimal_degree() + 1): R_monomials_useful += R_monomials_of_degree[i] R_monomials_useful.sort() for mon in R_monomials_useful: @@ -1030,8 +1018,7 @@ def macaulay_matrix(self, degree, R_monomials_useful += R_monomials_of_degree[deg] R_monomials_useful.sort() for mon in R_monomials_useful: - row_indices += [(mon, i) for i in range(m) - if mon.degree() + self[i].degree() <= target_degree] + row_indices += [(mon, i) for i in range(m) if mon.degree() + self[i].degree() <= target_degree] # compute sorted list of monomials that index the columns if remove_zero: @@ -1041,14 +1028,13 @@ def macaulay_matrix(self, degree, if homogeneous: column_indices = S_monomials_of_degree[target_degree] else: - column_indices = [mon for deg in range(target_degree + 1) - for mon in S_monomials_of_degree[deg]] + column_indices = [mon for deg in range(target_degree + 1) for mon in S_monomials_of_degree[deg]] column_indices.sort(reverse=not reverse_column_order) dict_columns = {mon.exponents()[0]: j for (j, mon) in enumerate(column_indices)} # actually build the Macaulay matrix macaulay_mat = matrix(F, len(row_indices), len(column_indices)) - for (ii, (mrow, i)) in enumerate(row_indices): + for ii, (mrow, i) in enumerate(row_indices): # in row ii, we put coefficients of the multiple mrow * self[i] poly = mrow * self[i] for mon, coeff in poly.iterator_exp_coeff(): @@ -1264,6 +1250,7 @@ def connection_graph(self): False """ from sage.graphs.graph import Graph + g = Graph() for f in self: g.add_clique(f.variables()) @@ -1310,6 +1297,7 @@ def connected_components(self): # Use a union-find data structure to encode relationships between # variables, i.e., that they belong to a same polynomial from sage.sets.disjoint_set import DisjointSet + DS = DisjointSet(set().union(*vss)) for u, *vs in vss: for v in vs: @@ -1341,6 +1329,7 @@ def _groebner_strategy(self): Multivariate Polynomial Ring in x, y, z over Finite Field of size 127 """ from sage.libs.singular.groebner_strategy import GroebnerStrategy + return GroebnerStrategy(self.ideal()) def maximal_degree(self): @@ -1398,8 +1387,7 @@ def __reduce__(self): sage: hash(f) == hash(loads(dumps(f))) True """ - return PolynomialSequence, (self._ring, self._parts, self._is_immutable, - self._Sequence_generic__cr, self._Sequence_generic__cr_str) + return PolynomialSequence, (self._ring, self._parts, self._is_immutable, self._Sequence_generic__cr, self._Sequence_generic__cr_str) @singular_gb_standard_options @libsingular_gb_standard_options @@ -1471,10 +1459,8 @@ def reduced(self): sage: F.reduced() [y^3 + z, x*y + (1 + 2 + O(2^20))*z, x*z - z] """ - from sage.rings.polynomial.multi_polynomial_ideal_libsingular import \ - interred_libsingular - from sage.rings.polynomial.multi_polynomial_libsingular import \ - MPolynomialRing_libsingular + from sage.rings.polynomial.multi_polynomial_ideal_libsingular import interred_libsingular + from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular R = self.ring() @@ -1487,11 +1473,11 @@ def reduced(self): ret = [] for f in self._singular_().interred(): f = R(f) - ret.append(f.lc()**(-1) * f) # lead coeffs are not reduced by interred + ret.append(f.lc() ** (-1) * f) # lead coeffs are not reduced by interred s.option("set", o) except TypeError: - from sage.rings.polynomial.toy_buchberger import \ - inter_reduction + from sage.rings.polynomial.toy_buchberger import inter_reduction + ret = inter_reduction(self) ret = sorted(ret, reverse=True) @@ -1651,16 +1637,14 @@ def eliminate_linear_variables(self, maxlength=Infinity, skip=None, return_reduc This is called "massaging" in [BCJ2007]_. """ - from sage.rings.polynomial.multi_polynomial_ring_base import \ - BooleanPolynomialRing_base + from sage.rings.polynomial.multi_polynomial_ring_base import BooleanPolynomialRing_base R = self.ring() if not isinstance(R, BooleanPolynomialRing_base): raise NotImplementedError("Only BooleanPolynomialRing's are supported.") - from sage.rings.polynomial.pbori.ll import (eliminate, ll_encode, - ll_red_nf_redsb) + from sage.rings.polynomial.pbori.ll import eliminate, ll_encode, ll_red_nf_redsb from sage.rings.polynomial.pbori.pbori import gauss_on_polys F = self @@ -1677,6 +1661,7 @@ def eliminate_linear_variables(self, maxlength=Infinity, skip=None, return_reduc else: # slower, more flexible solution if skip is None: + def skip(lm, tail): return False @@ -1738,23 +1723,23 @@ def _groebner_strategy(self): sage: F._groebner_strategy() """ - from sage.rings.polynomial.multi_polynomial_ring_base import \ - BooleanPolynomialRing_base + from sage.rings.polynomial.multi_polynomial_ring_base import BooleanPolynomialRing_base R = self.ring() if not isinstance(R, BooleanPolynomialRing_base): from sage.libs.singular.groebner_strategy import GroebnerStrategy + return GroebnerStrategy(self.ideal()) from sage.rings.polynomial.pbori.pbori import GroebnerStrategy + g = GroebnerStrategy(R) for p in self: g.add_as_you_wish(p) g.reduction_strategy.opt_red_tail = True return g - def solve(self, algorithm='polybori', n=1, - eliminate_linear_variables=True, verbose=False, **kwds): + def solve(self, algorithm='polybori', n=1, eliminate_linear_variables=True, verbose=False, **kwds): r""" Find solutions of this boolean polynomial system. @@ -1860,8 +1845,7 @@ def solve(self, algorithm='polybori', n=1, if eliminate_linear_variables: T, reductors = self.eliminate_linear_variables(return_reductors=True) if T.variables() != (): - from sage.rings.polynomial.pbori.pbori import \ - BooleanPolynomialRing + from sage.rings.polynomial.pbori.pbori import BooleanPolynomialRing R_solving = BooleanPolynomialRing(T.nvariables(), [str(_) for _ in list(T.variables())]) S = PolynomialSequence(R_solving, [R_solving(f) for f in T]) @@ -1879,6 +1863,7 @@ def solve(self, algorithm='polybori', n=1, elif algorithm == "sat": from sage.sat.boolean_polynomials import solve as solve_sat + if verbose: solutions = solve_sat(S, n=n, s_verbosity=1, **kwds) else: @@ -1908,8 +1893,7 @@ def key_convert(x): new_solution[var] = val solutions.append(new_solution) else: - solutions = [KeyConvertingDict(key_convert, sol) - for sol in solutions] + solutions = [KeyConvertingDict(key_convert, sol) for sol in solutions] for r in reductors: for sol in solutions: @@ -1947,14 +1931,12 @@ def reduced(self): ....: assert g[i].lt() not in t.divisors() """ - from sage.rings.polynomial.multi_polynomial_ring_base import \ - BooleanPolynomialRing_base + from sage.rings.polynomial.multi_polynomial_ring_base import BooleanPolynomialRing_base R = self.ring() if isinstance(R, BooleanPolynomialRing_base): - from sage.rings.polynomial.pbori.interred import \ - interred as inter_red + from sage.rings.polynomial.pbori.interred import interred as inter_red l = [p for p in self if not p == 0] l = sorted(inter_red(l, completely=True), reverse=True) @@ -2007,8 +1989,7 @@ def coefficients_monomials(self, order=None, sparse=True): """ from sage.modules.free_module_element import vector from sage.matrix.constructor import matrix - from sage.rings.polynomial.multi_polynomial_ring_base import \ - BooleanPolynomialRing_base + from sage.rings.polynomial.multi_polynomial_ring_base import BooleanPolynomialRing_base if order is None: v = sorted(self.monomials(), reverse=True) @@ -2083,6 +2064,7 @@ def weil_restriction(self): Polynomial Sequence with 240 Polynomials in 80 Variables """ from sage.rings.ideal import FieldIdeal + J = self.ideal().weil_restriction() J += FieldIdeal(J.ring()) return PolynomialSequence(J) diff --git a/src/sage/rings/polynomial/omega.py b/src/sage/rings/polynomial/omega.py index 0062efc2b37..ba6f126b87e 100644 --- a/src/sage/rings/polynomial/omega.py +++ b/src/sage/rings/polynomial/omega.py @@ -39,6 +39,7 @@ Functions ========= """ + # **************************************************************************** # Copyright (C) 2016 Daniel Krenn # @@ -53,8 +54,7 @@ from sage.misc.cachefunc import cached_function -def MacMahonOmega(var, expression, denominator=None, op=operator.ge, - Factorization_sort=False, Factorization_simplify=True): +def MacMahonOmega(var, expression, denominator=None, op=operator.ge, Factorization_sort=False, Factorization_simplify=True): r""" Return `\Omega_{\mathrm{op}}` of ``expression`` with respect to ``var``. @@ -271,10 +271,8 @@ def MacMahonOmega(var, expression, denominator=None, op=operator.ge, if denominator is None: if isinstance(expression, Factorization): - numerator = expression.unit() * \ - prod(f**e for f, e in expression if e > 0) - denominator = tuple(f for f, e in expression if e < 0 - for _ in range(-e)) + numerator = expression.unit() * prod(f**e for f, e in expression if e > 0) + denominator = tuple(f for f, e in expression if e < 0 for _ in range(-e)) else: numerator = expression.numerator() denominator = expression.denominator() @@ -288,12 +286,9 @@ def MacMahonOmega(var, expression, denominator=None, op=operator.ge, if not isinstance(denominator, Factorization): denominator = factor(denominator) if not denominator.is_integral(): - raise ValueError(f'factorization {denominator} of ' - 'the denominator contains negative exponents') + raise ValueError(f'factorization {denominator} of ' 'the denominator contains negative exponents') numerator *= ZZ.one() / denominator.unit() - factors_denominator = tuple(factor - for factor, exponent in denominator - for _ in range(exponent)) + factors_denominator = tuple(factor for factor, exponent in denominator for _ in range(exponent)) # at this point we have numerator/factors_denominator P = var.parent() @@ -302,8 +297,7 @@ def MacMahonOmega(var, expression, denominator=None, op=operator.ge, L0 = L.base_ring() elif var in P.gens(): var = repr(var) - L0 = LaurentPolynomialRing( - P.base_ring(), tuple(v for v in P.variable_names() if v != var)) + L0 = LaurentPolynomialRing(P.base_ring(), tuple(v for v in P.variable_names() if v != var)) L = LaurentPolynomialRing(L0, var) var = L.gen() else: @@ -333,16 +327,11 @@ def MacMahonOmega(var, expression, denominator=None, op=operator.ge, raise NotImplementedError(f'cannot handle factor {fac}') numerator = L(numerator) / prod(to_numerator) - result_numerator, result_factors_denominator = \ - _Omega_(numerator.monomial_coefficients(), decoded_factors) + result_numerator, result_factors_denominator = _Omega_(numerator.monomial_coefficients(), decoded_factors) if result_numerator == 0: return Factorization([], unit=result_numerator) - return Factorization([(result_numerator, 1)] + - [(f, -1) for f in other_factors] + - [(1 - f, -1) for f in result_factors_denominator], - sort=Factorization_sort, - simplify=Factorization_simplify) + return Factorization([(result_numerator, 1)] + [(f, -1) for f in other_factors] + [(1 - f, -1) for f in result_factors_denominator], sort=Factorization_sort, simplify=Factorization_simplify) def _simplify_(numerator, terms) -> tuple: @@ -463,8 +452,7 @@ def _Omega_(A, decoded_factors): if numerator == 0: factors_denominator = () - return _simplify_(numerator, - tuple(f.subs(rules) for f in factors_denominator)) + return _simplify_(numerator, tuple(f.subs(rules) for f in factors_denominator)) @cached_function @@ -556,6 +544,7 @@ def Omega_ge(a, exponents): (1, (z0,)) """ import logging + logger = logging.getLogger(__name__) logger.info('Omega_ge: a=%s, exponents=%s', a, exponents) @@ -575,12 +564,10 @@ def Omega_ge(a, exponents): L = LaurentPolynomialRing(B, ('t',) + z_names, len(z_names) + 1) t = L.gens()[0] Z = LaurentPolynomialRing(ZZ, z_names, len(z_names)) - powers = {i: L(zeta**(ellcm//i)) for i in rou} + powers = {i: L(zeta ** (ellcm // i)) for i in rou} powers[2] = L(-1) powers[1] = L(1) - exponents_and_values = tuple( - (e, tuple(powers[abs(e)]**j * z for j in range(abs(e)))) - for z, e in zip(L.gens()[1:], exponents)) + exponents_and_values = tuple((e, tuple(powers[abs(e)] ** j * z for j in range(abs(e)))) for z, e in zip(L.gens()[1:], exponents)) x = tuple(v for e, v in exponents_and_values if e > 0) y = tuple(v for e, v in exponents_and_values if e < 0) @@ -598,9 +585,9 @@ def subs_e(e): assert e[p] % exponent == 0 e[p] = e[p] // exponent return tuple(e) + parent = expression.parent() - return parent({subs_e(e): c - for e, c in expression.monomial_coefficients().items()}) + return parent({subs_e(e): c for e, c in expression.monomial_coefficients().items()}) def de_power(expression): expression = Z(expression) @@ -611,8 +598,7 @@ def de_power(expression): return expression logger.debug('Omega_ge: preparing denominator') - factors_denominator = tuple(de_power(1 - factor) - for factor in _Omega_factors_denominator_(x, y)) + factors_denominator = tuple(de_power(1 - factor) for factor in _Omega_factors_denominator_(x, y)) logger.debug('Omega_ge: preparing numerator') numerator = de_power(_Omega_numerator_(a, x, y, t)) @@ -727,17 +713,14 @@ def _Omega_numerator_(a, x, y, t): xy = x_flat + y_flat import logging + logger = logging.getLogger(__name__) logger.info('Omega_numerator: a=%s, n=%s, m=%s', a, n, m) if m == 0: - result = 1 - (prod(_Omega_factors_denominator_(x, y)) * - sum(homogeneous_symmetric_function(j, xy) - for j in srange(-a)) - if a < 0 else 0) + result = 1 - (prod(_Omega_factors_denominator_(x, y)) * sum(homogeneous_symmetric_function(j, xy) for j in srange(-a)) if a < 0 else 0) elif n == 0: - result = sum(homogeneous_symmetric_function(j, xy) - for j in srange(a+1)) + result = sum(homogeneous_symmetric_function(j, xy) for j in srange(a + 1)) else: result = _Omega_numerator_P_(a, x_flat[:-1], y_flat, t).subs({t: x_flat[-1]}) L = t.parent() @@ -786,6 +769,7 @@ def _Omega_numerator_P_(a, x, y, t): # Caching occurs in :func:`Omega_ge`. import logging + logger = logging.getLogger(__name__) from sage.arith.srange import srange @@ -794,27 +778,21 @@ def _Omega_numerator_P_(a, x, y, t): n = len(x) if n == 0: x0 = t - result = x0**(-a) + \ - (prod(1 - x0*yy for yy in y) * - sum(homogeneous_symmetric_function(j, y) * (1-x0**(j-a)) - for j in srange(a)) - if a > 0 else 0) + result = x0 ** (-a) + (prod(1 - x0 * yy for yy in y) * sum(homogeneous_symmetric_function(j, y) * (1 - x0 ** (j - a)) for j in srange(a)) if a > 0 else 0) else: - Pprev = _Omega_numerator_P_(a, x[:n-1], y, t) - x2 = x[n-1] + Pprev = _Omega_numerator_P_(a, x[: n - 1], y, t) + x2 = x[n - 1] logger.debug('Omega_numerator: P(%s): substituting...', n) x1 = t p1 = Pprev p2 = Pprev.subs({t: x2}) logger.debug('Omega_numerator: P(%s): preparing...', n) - dividend = x1 * (1-x2) * prod(1 - x2*yy for yy in y) * p1 - \ - x2 * (1-x1) * prod(1 - x1*yy for yy in y) * p2 + dividend = x1 * (1 - x2) * prod(1 - x2 * yy for yy in y) * p1 - x2 * (1 - x1) * prod(1 - x1 * yy for yy in y) * p2 logger.debug('Omega_numerator: P(%s): dividing...', n) q, r = dividend.quo_rem(x1 - x2) assert r == 0 result = q - logger.debug('Omega_numerator: P(%s) has %s terms', n, - result.number_of_terms()) + logger.debug('Omega_numerator: P(%s) has %s terms', n, result.number_of_terms()) return result @@ -896,16 +874,12 @@ def _Omega_factors_denominator_(x, y): () """ import logging + logger = logging.getLogger(__name__) from sage.misc.misc_c import prod - result = tuple(prod(1 - xx for xx in gx) for gx in x) + \ - sum(((prod(1 - xx*yy for xx in gx for yy in gy),) - if len(gx) != len(gy) - else tuple(prod(1 - xx*yy for xx in gx) for yy in gy) - for gx in x for gy in y), - ()) + result = tuple(prod(1 - xx for xx in gx) for gx in x) + sum(((prod(1 - xx * yy for xx in gx for yy in gy),) if len(gx) != len(gy) else tuple(prod(1 - xx * yy for xx in gx) for yy in gy) for gx in x for gy in y), ()) logger.info('Omega_denominator: %s factors', len(result)) return result @@ -940,9 +914,9 @@ def partition(items, predicate=bool): ((0, 2, 4, 6, 8), (1, 3, 5, 7, 9)) """ from itertools import tee + a, b = tee((predicate(item), item) for item in items) - return ((item for pred, item in a if not pred), - (item for pred, item in b if pred)) + return ((item for pred, item in a if not pred), (item for pred, item in b if pred)) def homogeneous_symmetric_function(j, x): @@ -975,5 +949,4 @@ def homogeneous_symmetric_function(j, x): from sage.combinat.integer_vector import IntegerVectors from sage.misc.misc_c import prod - return sum(prod(xx**pp for xx, pp in zip(x, p)) - for p in IntegerVectors(j, length=len(x))) + return sum(prod(xx**pp for xx, pp in zip(x, p)) for p in IntegerVectors(j, length=len(x))) diff --git a/src/sage/rings/polynomial/ore_function_element.py b/src/sage/rings/polynomial/ore_function_element.py index 60f3918b9f6..7cab06fb1d7 100644 --- a/src/sage/rings/polynomial/ore_function_element.py +++ b/src/sage/rings/polynomial/ore_function_element.py @@ -29,6 +29,7 @@ class OreFunction(AlgebraElement): r""" An element in a Ore function field. """ + def __init__(self, parent, numerator, denominator=None, simplify=True): r""" Initialize this element. @@ -61,8 +62,8 @@ def __init__(self, parent, numerator, denominator=None, simplify=True): s = denominator.leading_coefficient() if s != 1: s = ~s - numerator = s*numerator - denominator = s*denominator + numerator = s * numerator + denominator = s * denominator self._numerator = numerator self._denominator = denominator else: @@ -663,6 +664,7 @@ class ConstantOreFunctionSection(Map): twisted by a |--> a^5 To: Finite Field in a of size 5^3 """ + def _call_(self, x): r""" Return `x` viewed in the base field, @@ -698,6 +700,7 @@ class OreFunctionBaseringInjection(Morphism): This class is needed by the coercion system. """ + def __init__(self, domain, codomain): r""" Initialize this morphism. @@ -713,9 +716,8 @@ def __init__(self, domain, codomain): From: Fraction Field of Univariate Polynomial Ring in t over Rational Field To: Ore Function Field in x over Fraction Field of Univariate Polynomial Ring in t over Rational Field twisted by t |--> t + 1 """ - assert codomain.base_ring() is domain, \ - "the domain of the injection must be the base ring of the Ore function field" - Morphism.__init__(self, Hom(domain,codomain)) + assert codomain.base_ring() is domain, "the domain of the injection must be the base ring of the Ore function field" + Morphism.__init__(self, Hom(domain, codomain)) self._an_element = codomain.gen() self._repr_type_str = "Ore Function base injection" @@ -785,6 +787,7 @@ def section(self): # Ore functions over Ore function field with finite index center ################################################################ + class OreFunction_with_large_center(OreFunction): r""" A special class for elements of Ore function fields whose @@ -803,6 +806,7 @@ class OreFunction_with_large_center(OreFunction): sage: # TestSuite(f).run() """ + def reduced_trace(self, var=None): r""" Return the reduced trace of this element. @@ -861,7 +865,7 @@ def reduced_trace(self, var=None): denominator = self._denominator.reduced_norm(var) cofactor, _ = ring(denominator).right_quo_rem(self._denominator) numerator = (cofactor * self._numerator).reduced_trace(var) - return numerator/denominator + return numerator / denominator def reduced_norm(self, var=None): r""" @@ -914,4 +918,4 @@ def reduced_norm(self, var=None): """ numerator = self._numerator.reduced_norm(var) denominator = self._denominator.reduced_norm(var) - return numerator/denominator + return numerator / denominator diff --git a/src/sage/rings/polynomial/ore_function_field.py b/src/sage/rings/polynomial/ore_function_field.py index 1a03623a034..5c19c2cb6d6 100644 --- a/src/sage/rings/polynomial/ore_function_field.py +++ b/src/sage/rings/polynomial/ore_function_field.py @@ -144,7 +144,6 @@ - Xavier Caruso (2020-05) """ - # *************************************************************************** # Copyright (C) 2020 Xavier Caruso # @@ -177,10 +176,12 @@ # Generic implementation of Ore function fields ############################################### + class OreFunctionField(Parent, UniqueRepresentation): r""" A class for fraction fields of Ore polynomial rings. """ + Element = None def __init__(self, ring, category=None): @@ -198,6 +199,7 @@ def __init__(self, ring, category=None): """ if self.Element is None: import sage.rings.polynomial.ore_function_element + self.Element = sage.rings.polynomial.ore_function_element.OreFunction if not isinstance(ring, OrePolynomialRing): raise TypeError("not a Ore Polynomial Ring") @@ -214,8 +216,7 @@ def __init__(self, ring, category=None): category = Algebras(base).Commutative().or_subcategory(category) else: category = Algebras(base).or_subcategory(category) - Parent.__init__(self, base=base, names=ring.variable_name(), - normalize=True, category=category) + Parent.__init__(self, base=base, names=ring.variable_name(), normalize=True, category=category) def _element_constructor_(self, *args, **kwds): r""" @@ -331,6 +332,7 @@ def _latex_(self): \Bold{F}_{7}\left(x\right) """ from sage.misc.latex import latex + s = "%s\\left(%s" % (latex(self.base_ring()), self.latex_variable_names()[0]) twist = self._ring._latex_twist() if twist != "": @@ -672,11 +674,13 @@ def fraction_field(self): # Special classes for twisting morphisms with finite order ########################################################## + class SectionOreFunctionCenterInjection(Section): r""" Section of the canonical injection of the center of a Ore function field into this field """ + def __init__(self, embed): r""" Initialize this map. @@ -753,6 +757,7 @@ class OreFunctionCenterInjection(RingHomomorphism): Canonical injection of the center of a Ore function field into this field. """ + def __init__(self, domain, codomain, ringembed): r""" Initialize this morphism. @@ -850,6 +855,7 @@ class OreFunctionField_with_large_center(OreFunctionField): """ A specialized class for Ore polynomial fields whose center has finite index. """ + def __init__(self, ring, category=None): r""" Initialize this Ore function field. diff --git a/src/sage/rings/polynomial/ore_polynomial_ring.py b/src/sage/rings/polynomial/ore_polynomial_ring.py index 8587fe9c798..41199e6de5d 100644 --- a/src/sage/rings/polynomial/ore_polynomial_ring.py +++ b/src/sage/rings/polynomial/ore_polynomial_ring.py @@ -69,6 +69,7 @@ # Generic implementation of Ore polynomial rings ################################################# + class OrePolynomialRing(UniqueRepresentation, Parent): r""" Construct and return the globally unique Ore polynomial ring with the @@ -273,6 +274,7 @@ class OrePolynomialRing(UniqueRepresentation, Parent): - Sparse Ore Polynomial Ring - Multivariate Ore Polynomial Ring """ + Element = None _fraction_field_class = None @@ -337,8 +339,7 @@ def __classcall_private__(cls, base_ring, twist=None, names=None, sparse=False, if twist is None: morphism = derivation = None elif isinstance(twist, Morphism): - if (twist.domain() is not base_ring - or twist.codomain() is not base_ring): + if twist.domain() is not base_ring or twist.codomain() is not base_ring: raise TypeError("the twisting morphism must be an endomorphism of base_ring (=%s)" % base_ring) if twist.is_identity(): morphism = None @@ -346,8 +347,7 @@ def __classcall_private__(cls, base_ring, twist=None, names=None, sparse=False, morphism = twist derivation = None elif isinstance(twist, RingDerivation): - if (twist.domain() is not base_ring - or twist.codomain() is not base_ring): + if twist.domain() is not base_ring or twist.codomain() is not base_ring: raise TypeError("the twisting derivation must be an endomorphism of base_ring (=%s)" % base_ring) morphism = twist.parent().twisting_morphism() if twist: @@ -375,6 +375,7 @@ def __classcall_private__(cls, base_ring, twist=None, names=None, sparse=False, raise NotImplementedError("sparse Ore polynomial rings are not implemented") from sage.rings.polynomial import skew_polynomial_ring + constructors = [] if derivation is None: if base_ring in _Fields: @@ -430,9 +431,11 @@ def __init__(self, base_ring, morphism, derivation, name, sparse, category=None) """ if self.Element is None: import sage.rings.polynomial.ore_polynomial_element + self.Element = sage.rings.polynomial.ore_polynomial_element.OrePolynomial_generic_dense if self._fraction_field_class is None: from sage.rings.polynomial.ore_function_field import OreFunctionField + self._fraction_field_class = OreFunctionField self.__is_sparse = sparse self._morphism = morphism @@ -443,8 +446,7 @@ def __init__(self, base_ring, morphism, derivation, name, sparse, category=None) else: cat = Algebras(base_ring) category = cat.or_subcategory(category) - Parent.__init__(self, base_ring, names=name, - normalize=True, category=category) + Parent.__init__(self, base_ring, names=name, normalize=True, category=category) def __reduce__(self): r""" @@ -513,6 +515,7 @@ def build(check): if a.is_zero(): return P.zero() return C(self, [a], check=check, construct=construct) + if P is self: return a if P is self.base_ring(): @@ -526,6 +529,7 @@ def build(check): if isinstance(a, str): try: from sage.misc.parser import LookupNameMaker, Parser + R = self.base_ring() p = Parser(Integer, R, LookupNameMaker({self.variable_name(): self.gen()}, R)) return self(p.parse(a)) @@ -666,6 +670,7 @@ def _latex_twist(self): """ from sage.misc.latex import latex + s = "" if self._morphism is not None: s += latex(self._morphism) @@ -716,6 +721,7 @@ def _latex_(self) -> str: \Bold{Q}[t]\left[\delta ; \frac{d}{dt} \right] """ from sage.misc.latex import latex + s = "%s\\left[%s" % (latex(self.base_ring()), self.latex_variable_names()[0]) twist = self._latex_twist() if twist != "": @@ -746,8 +752,7 @@ def change_var(self, var): twist = self._morphism else: twist = self._derivation - return OrePolynomialRing(self.base_ring(), twist, names=var, - sparse=self.__is_sparse, polcast=False) + return OrePolynomialRing(self.base_ring(), twist, names=var, sparse=self.__is_sparse, polcast=False) def characteristic(self): r""" @@ -841,7 +846,7 @@ def twisting_morphism(self, n=1): """ if self._morphism is not None: try: - return self._morphism ** n + return self._morphism**n except TypeError as e: if n < 0: raise NotImplementedError("inversion of the twisting morphism %s" % self._morphism) @@ -1280,6 +1285,7 @@ def quotient_module(self, P, names=None): """ from sage.matrix.special import companion_matrix from sage.modules.ore_module import OreModule, OreAction + coeffs = self(P).right_monic().list() f = companion_matrix(coeffs, format='bottom') M = OreModule(f, self, names=names) diff --git a/src/sage/rings/polynomial/padics/polynomial_padic.py b/src/sage/rings/polynomial/padics/polynomial_padic.py index e595650cd0e..15f6b1f8368 100644 --- a/src/sage/rings/polynomial/padics/polynomial_padic.py +++ b/src/sage/rings/polynomial/padics/polynomial_padic.py @@ -11,7 +11,7 @@ polynomials. """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2007 David Roe # Copyright (C) 2013 Jeroen Demeyer # @@ -19,7 +19,7 @@ # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** import re from sage.rings.padics.precision_error import PrecisionError @@ -62,8 +62,8 @@ def _repr(self, name=None): name = self.parent().variable_name() for n in reversed(range(m)): x = y = str(coeffs[n]) - if n == m-1 or x != "0": - if n != m-1: + if n == m - 1 or x != "0": + if n != m - 1: s += " + " if y.find("-") == 0: y = y[1:] @@ -77,8 +77,8 @@ def _repr(self, name=None): var = "" s += x + var s = s.replace(" + -", " - ") - s = re.sub(r' 1\*',' ', s) - s = re.sub(r' -1\*',' -', s) + s = re.sub(r' 1\*', ' ', s) + s = re.sub(r' -1\*', ' -', s) if s == " ": return "0" return s[1:] @@ -249,8 +249,7 @@ def factor(self): absprec = min([x.precision_absolute() for x in self_normal]) if self_normal.discriminant().valuation() >= absprec: - raise PrecisionError( - "p-adic factorization not well-defined since the discriminant is zero up to the requestion p-adic precision") + raise PrecisionError("p-adic factorization not well-defined since the discriminant is zero up to the requestion p-adic precision") G = self_normal.__pari__().factorpadic(self.base_ring().prime(), absprec) return _pari_padic_factorization_to_sage(G, self.parent(), self.leading_coefficient()) diff --git a/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py b/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py index 27adabadc7e..5d723a6aa16 100644 --- a/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py +++ b/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py @@ -66,6 +66,7 @@ def __init__(self, parent, x=None, check=True, is_gen=False, construct=False, ab self._polygon = None parentbr = parent.base_ring() from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + if construct: (self._poly, self._valbase, self._relprecs, self._normalized, self._valaddeds, self._list) = x # the last two of these may be None return @@ -224,8 +225,7 @@ def _comp_list(self): self._list = [] polylist = self._poly.list() polylen = len(polylist) - self._list = [self.base_ring()(polylist[i], absprec=self._relprecs[i]) << self._valbase for i in range(polylen)] \ - + [self.base_ring()(0, absprec=self._relprecs[i] + self._valbase) for i in range(polylen, len(self._relprecs))] + self._list = [self.base_ring()(polylist[i], absprec=self._relprecs[i]) << self._valbase for i in range(polylen)] + [self.base_ring()(0, absprec=self._relprecs[i] + self._valbase) for i in range(polylen, len(self._relprecs))] while self._list and self._list[-1]._is_exact_zero(): self._list.pop() @@ -247,50 +247,50 @@ def _adjust_prec_info(self, absprec=infinity, relprec=infinity): """ return -# min = sage.rings.padics.misc.min -# slen = len(self._relprec) -# if isinstance(absprec, list): -# alen = len(absprec) -# elif absprec is infinity: -# alen = 0 -# absprec = [] -# else: -# alen = 1 -# if isinstance(relprec, list): -# rlen = len(relprec) -# elif relprec is infinity: -# rlen = 0 -# relprec = [] -# else: -# rlen = 1 -# preclen = max(slen, rlen, alen) -# if not isinstance(absprec, list): -# absprec = [absprec] * preclen -# if not isinstance(relprec, list): -# relprec = [relprec] * preclen -# vallist = [c.valuation(self.base_ring().prime()) + self._val for c in self._poly.list()] ####### -# vmin = min(vallist) -# amin = min(absprec) -# if amin < vmin: -# vmin = amin -# if vmin < self._val: -# vadjust = - -# if not isinstance(absprec, list): -# self._val = min(vallist + [absprec]) -# absprec = [absprec] * preclen -# else: -# self._val = padics.misc.min(vallist + absprec) -# absprec = absprec + [infinity] * (preclen - len(absprec)) -# if self._val is infinity: -# self._relprec = [] -# return -# if not isinstance(relprec, list): -# relprec = [relprec] * preclen -# else: -# relprec = relprec + [parent.base_ring().precision_cap()] * (preclen - len(relprec)) -# self._relprec = [min(a, v + r) - self._val for (a, r, v) in zip(absprec, relprec, vallist)] -# Remember to normalize at the end if self._normalized is true because you need to reduce mod p^n + # min = sage.rings.padics.misc.min + # slen = len(self._relprec) + # if isinstance(absprec, list): + # alen = len(absprec) + # elif absprec is infinity: + # alen = 0 + # absprec = [] + # else: + # alen = 1 + # if isinstance(relprec, list): + # rlen = len(relprec) + # elif relprec is infinity: + # rlen = 0 + # relprec = [] + # else: + # rlen = 1 + # preclen = max(slen, rlen, alen) + # if not isinstance(absprec, list): + # absprec = [absprec] * preclen + # if not isinstance(relprec, list): + # relprec = [relprec] * preclen + # vallist = [c.valuation(self.base_ring().prime()) + self._val for c in self._poly.list()] ####### + # vmin = min(vallist) + # amin = min(absprec) + # if amin < vmin: + # vmin = amin + # if vmin < self._val: + # vadjust = + + # if not isinstance(absprec, list): + # self._val = min(vallist + [absprec]) + # absprec = [absprec] * preclen + # else: + # self._val = padics.misc.min(vallist + absprec) + # absprec = absprec + [infinity] * (preclen - len(absprec)) + # if self._val is infinity: + # self._relprec = [] + # return + # if not isinstance(relprec, list): + # relprec = [relprec] * preclen + # else: + # relprec = relprec + [parent.base_ring().precision_cap()] * (preclen - len(relprec)) + # self._relprec = [min(a, v + r) - self._val for (a, r, v) in zip(absprec, relprec, vallist)] + # Remember to normalize at the end if self._normalized is true because you need to reduce mod p^n def _getprecpoly(self, n): one = Integer(1) @@ -300,8 +300,7 @@ def _getvalpoly(self, n): one = Integer(1) if self._valaddeds is None: self._comp_valaddeds() - return self._poly.parent()([(0 if (c is infinity) else (one << (n * c))) for c in self._valaddeds] + - [(0 if (c is infinity) else (one << (n * c))) for c in self._relprecs[len(self._valaddeds):]]) + return self._poly.parent()([(0 if (c is infinity) else (one << (n * c))) for c in self._valaddeds] + [(0 if (c is infinity) else (one << (n * c))) for c in self._relprecs[len(self._valaddeds) :]]) def list(self, copy=True): """ @@ -408,8 +407,7 @@ def __getitem__(self, n): return self.base_ring().zero() if self._list is not None: return self._list[n] - return self.base_ring()(self.base_ring().prime_pow(self._valbase) - * self._poly[n], absprec=self._valbase + self._relprecs[n]) + return self.base_ring()(self.base_ring().prime_pow(self._valbase) * self._poly[n], absprec=self._valbase + self._relprecs[n]) def _add_(self, right): """ @@ -437,13 +435,7 @@ def _add_(self, right): else: baseval = self._valbase # Currently we don't reduce the coefficients of the answer modulo the appropriate power of p or normalize - return Polynomial_padic_capped_relative_dense(self.parent(), - (selfpoly + rightpoly, - baseval, - [min(a + self._valbase - baseval, b + right._valbase - baseval) - for (a, b) in zip(_extend_by_infinity(self._relprecs, max(len(self._relprecs), len(right._relprecs))), - _extend_by_infinity(right._relprecs, max(len(self._relprecs), len(right._relprecs))))], - False, None, None), construct=True) + return Polynomial_padic_capped_relative_dense(self.parent(), (selfpoly + rightpoly, baseval, [min(a + self._valbase - baseval, b + right._valbase - baseval) for (a, b) in zip(_extend_by_infinity(self._relprecs, max(len(self._relprecs), len(right._relprecs))), _extend_by_infinity(right._relprecs, max(len(self._relprecs), len(right._relprecs))))], False, None, None), construct=True) def _sub_(self, right): """ @@ -471,13 +463,7 @@ def _sub_(self, right): else: baseval = self._valbase # Currently we don't reduce the coefficients of the answer modulo the appropriate power of p or normalize - return Polynomial_padic_capped_relative_dense(self.parent(), - (selfpoly - rightpoly, - baseval, - [min(a + self._valbase - baseval, b + right._valbase - baseval) - for (a, b) in zip(_extend_by_infinity(self._relprecs, max(len(self._relprecs), len(right._relprecs))), - _extend_by_infinity(right._relprecs, max(len(self._relprecs), len(right._relprecs))))], - False, None, None), construct=True) + return Polynomial_padic_capped_relative_dense(self.parent(), (selfpoly - rightpoly, baseval, [min(a + self._valbase - baseval, b + right._valbase - baseval) for (a, b) in zip(_extend_by_infinity(self._relprecs, max(len(self._relprecs), len(right._relprecs))), _extend_by_infinity(right._relprecs, max(len(self._relprecs), len(right._relprecs))))], False, None, None), construct=True) def _mul_(self, right): r""" @@ -788,8 +774,7 @@ def degree(self, secure=False): self._normalize() deg = Integer(self._poly.degree()) if secure and deg < self.prec_degree(): - raise PrecisionError("the leading coefficient is " - "indistinguishable from 0") + raise PrecisionError("the leading coefficient is " "indistinguishable from 0") return deg def prec_degree(self): @@ -977,19 +962,19 @@ def reverse(self, degree=None): True """ n = self._poly.degree() if degree is None else degree - zzlist = self._poly.list()[:(n + 1)] + [0] * (n - self._poly.degree()) + zzlist = self._poly.list()[: (n + 1)] + [0] * (n - self._poly.degree()) zzlist.reverse() - relprec = self._relprecs[:(n + 1)] + [infinity] * (n - self.prec_degree()) + relprec = self._relprecs[: (n + 1)] + [infinity] * (n - self.prec_degree()) relprec.reverse() if self._valaddeds is None: valadded = None else: - valadded = self._valaddeds[:(n + 1)] + [infinity] * (n - self.prec_degree()) + valadded = self._valaddeds[: (n + 1)] + [infinity] * (n - self.prec_degree()) valadded.reverse() if self._list is None: L = None else: - L = self._list[:(n + 1)] + [self.base_ring()(0)] * (n - self.prec_degree()) + L = self._list[: (n + 1)] + [self.base_ring()(0)] * (n - self.prec_degree()) L.reverse() return Polynomial_padic_capped_relative_dense(self.parent(), (self._poly.parent()(zzlist), self._valbase, relprec, self._normalized, valadded, L), construct=True) @@ -1070,8 +1055,7 @@ def _quo_rem_naive(self, right): f = self.base_extend(K) g = right.base_extend(K) if g == 0: - raise ZeroDivisionError("cannot divide by a polynomial " - "indistinguishable from 0") + raise ZeroDivisionError("cannot divide by a polynomial " "indistinguishable from 0") x = f.parent().gen() quo = f.parent()(0) while f.degree() >= g.degree(): @@ -1091,8 +1075,7 @@ def _quo_rem_list(self, right, secure): - Xavier Caruso (2013-03) """ if right.is_zero(): - raise ZeroDivisionError("cannot divide by a polynomial " - "indistinguishable from 0") + raise ZeroDivisionError("cannot divide by a polynomial " "indistinguishable from 0") a = self.list() da = len(a) - 1 b = right.list() @@ -1107,6 +1090,7 @@ def _quo_rem_list(self, right, secure): q.reverse() K = self.base_ring().fraction_field() from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + parent = PolynomialRing(K, name=self.parent().variable_name()) return parent(q), parent(a[:db]) @@ -1171,11 +1155,10 @@ def newton_polygon(self): if self._valaddeds is None: self._comp_valaddeds() from sage.geometry.newton_polygon import NewtonPolygon + valbase = self._valbase - polygon = NewtonPolygon([(x, val + valbase) - for x, val in enumerate(self._valaddeds)]) - polygon_prec = NewtonPolygon([(x, val + valbase) - for x, val in enumerate(self._relprecs)]) + polygon = NewtonPolygon([(x, val + valbase) for x, val in enumerate(self._valaddeds)]) + polygon_prec = NewtonPolygon([(x, val + valbase) for x, val in enumerate(self._relprecs)]) vertices = polygon.vertices(copy=False) vertices_prec = polygon_prec.vertices(copy=False) @@ -1186,7 +1169,7 @@ def newton_polygon(self): if vertices[-1][0] < vertices_prec[-1][0]: raise PrecisionError("The leading coefficient has not enough precision") - for (x, y) in vertices: + for x, y in vertices: if polygon_prec(x) <= y: raise PrecisionError("The coefficient of %s^%s has not enough precision" % (self.parent().variable_name(), x)) return polygon @@ -1233,7 +1216,7 @@ def is_eisenstein(self, secure=False): compval = 1 - self._valbase valaddeds = self._valaddeds relprecs = self._relprecs - if relprecs[0] <= compval: # not enough precision + if relprecs[0] <= compval: # not enough precision if valaddeds[0] < relprecs[0]: return False raise PrecisionError("Not enough precision on the constant coefficient") @@ -1241,7 +1224,7 @@ def is_eisenstein(self, secure=False): if valaddeds[0] != compval: return False for i in range(1, deg): - if relprecs[i] < compval: # not enough precision + if relprecs[i] < compval: # not enough precision if valaddeds[i] < relprecs[i]: return False if secure: diff --git a/src/sage/rings/polynomial/padics/polynomial_padic_flat.py b/src/sage/rings/polynomial/padics/polynomial_padic_flat.py index d26f7e10e71..aeae4338241 100644 --- a/src/sage/rings/polynomial/padics/polynomial_padic_flat.py +++ b/src/sage/rings/polynomial/padics/polynomial_padic_flat.py @@ -55,8 +55,7 @@ def __init__(self, parent, x=None, check=True, is_gen=False, construct=False, ab m = min(m, v[i].precision_absolute()) x = v else: - m = sage.rings.padics.misc.min(a.precision_absolute() - for a in x.values()) + m = sage.rings.padics.misc.min(a.precision_absolute() for a in x.values()) if absprec is not None: m = min(m, absprec) Polynomial_generic_dense.__init__(self, parent, x, absprec=m) diff --git a/src/sage/rings/polynomial/pbori/__init__.py b/src/sage/rings/polynomial/pbori/__init__.py index c32dd4a2a68..31dcf11428f 100644 --- a/src/sage/rings/polynomial/pbori/__init__.py +++ b/src/sage/rings/polynomial/pbori/__init__.py @@ -32,6 +32,7 @@ Electronic Proceedings of the MEGA 2007 - Effective Methods in Algebraic Geometry, Strobl, Austria, June 2007. http://www.ricam.oeaw.ac.at/mega2007/electronic/electronic.html """ + from .PyPolyBoRi import Ring, Polynomial, Monomial, Variable # Get all-inclusive groebner routine diff --git a/src/sage/rings/polynomial/pbori/blocks.py b/src/sage/rings/polynomial/pbori/blocks.py index d9b8f46f390..39873f39816 100644 --- a/src/sage/rings/polynomial/pbori/blocks.py +++ b/src/sage/rings/polynomial/pbori/blocks.py @@ -15,6 +15,7 @@ class Block: (start_index,...,start_index+size-1), it is the preferred block type for simple one-dimensional variable sets """ + def __init__(self, var_name, size, start_index=0, reverse=False): indices = range(start_index, start_index + size) if reverse: @@ -40,8 +41,7 @@ def register(self, start, context): ring_context = ring_context.wrapped ring = ring_context['r'] - var_func = VariableBlock(self.size, self.start_index, start, self. - reverse, ring) + var_func = VariableBlock(self.size, self.start_index, start, self.reverse, ring) var_func.__name__ = self.var_name context[self.var_name] = var_func @@ -52,8 +52,8 @@ class AlternatingBlock: schemes,where base names vary, e.g. a(0),b(0),a(1),b(1),a(2),b(2) """ - def __init__(self, var_names, size_per_variable, start_index=0, - reverse=False): + + def __init__(self, var_names, size_per_variable, start_index=0, reverse=False): self.var_names = var_names self.size_per_variable = size_per_variable self.reverse = reverse @@ -85,8 +85,8 @@ def __init__(self, ring, index2pos, size): self.size = size def __call__(self, idx): - return self.ring.variable(self.index2pos[idx] * self.size + - var_pos + start) + return self.ring.variable(self.index2pos[idx] * self.size + var_pos + start) + ring_context = context while isinstance(ring_context, PrefixedDictProxy): ring_context = ring_context.wrapped @@ -94,7 +94,7 @@ def __call__(self, idx): return var_factory(ring, self.index2pos, len(self.var_names)) - for (var_pos, n) in enumerate(self.var_names): + for var_pos, n in enumerate(self.var_names): var_func = gen_var_func(var_pos) var_func.__name__ = n context[n] = var_func @@ -103,16 +103,14 @@ def __call__(self, idx): def shift(f, i): def g(j): return f(i + j) + g.__name__ = f.__name__ return g class AdderBlock(AlternatingBlock): - def __init__(self, adder_bits, sums='s', carries='c', input1='a', - input2='b', start_index=0): - AlternatingBlock.__init__(self, (sums, carries, input1, input2), - adder_bits, start_index=start_index, - reverse=True) + def __init__(self, adder_bits, sums='s', carries='c', input1='a', input2='b', start_index=0): + AlternatingBlock.__init__(self, (sums, carries, input1, input2), adder_bits, start_index=start_index, reverse=True) self.input1 = input1 self.input2 = input2 self.sums = sums @@ -135,8 +133,7 @@ def register(self, start, context): carries.append(c) last = c - self.add_results = [a(i) + b(i) + carries[i] - for i in range(self.adder_bits)] + self.add_results = [a(i) + b(i) + carries[i] for i in range(self.adder_bits)] self.carries_polys = carries[1:] # def s(i): @@ -167,17 +164,17 @@ class HigherOrderBlock: start_index_tuple : the multi-indices will be of the form start_index_tuple + a, where a is a multi-index with nonnegative components """ - def __init__(self, var_name, size_tuple, start_index_tuple=None, - reverse=False): + + def __init__(self, var_name, size_tuple, start_index_tuple=None, reverse=False): if start_index_tuple is None: - start_index_tuple = len(size_tuple) * (0, ) + start_index_tuple = len(size_tuple) * (0,) cart = [()] assert len(size_tuple) == len(start_index_tuple) outer_indices = reversed(range(len(size_tuple))) for i in outer_indices: s_i = start_index_tuple[i] s = size_tuple[i] - cart = [(j, ) + c for j in range(s_i, s_i + s) for c in cart] + cart = [(j,) + c for j in range(s_i, s_i + s) for c in cart] if reverse: cart.reverse() self.cart = cart @@ -197,18 +194,15 @@ def __len__(self): def register(self, start, context): def var_func(*indices): return Variable(self.cart2index[indices] + start) + var_func.__name__ = self.var_name context[self.var_name] = var_func class InOutBlock: - def __init__(self, out_size, in_size, output='out', input='in', - in_start_index=0, out_start_index=0, - out_reverse=False, in_reverse=False): - self.output = Block(var_name=output, start_index=out_start_index, - size=out_size, reverse=out_reverse) - self.input = Block(var_name=input, start_index=in_start_index, - size=in_size, reverse=in_reverse) + def __init__(self, out_size, in_size, output='out', input='in', in_start_index=0, out_start_index=0, out_reverse=False, in_reverse=False): + self.output = Block(var_name=output, start_index=out_start_index, size=out_size, reverse=out_reverse) + self.input = Block(var_name=input, start_index=in_start_index, size=in_size, reverse=in_reverse) self.out_start_index = out_start_index self.in_start_index = in_start_index @@ -227,27 +221,21 @@ def __len__(self): def register(self, start, context): self.output.register(start, context) self.input.register(start + len(self.output), context) - self.out_vars = shift(context[self.output.var_name], self. - out_start_index) + self.out_vars = shift(context[self.output.var_name], self.out_start_index) self.in_vars = shift(context[self.input.var_name], self.in_start_index) class MultiBlock: - def __init__(self, sizes=None, var_names=["v"], - start_indices=[], reverses=None): + def __init__(self, sizes=None, var_names=["v"], start_indices=[], reverses=None): if reverses is None: reverses = [] if sizes is None: sizes = [] - self.start_indices = start_indices + [0] * (len(var_names) - - len(start_indices)) + self.start_indices = start_indices + [0] * (len(var_names) - len(start_indices)) reverses += [False] * (len(var_names) - len(reverses)) sizes += [1] * (len(var_names) - len(sizes)) - self.blocks = [Block(var_name=var_names[idx], size=sizes[idx], - start_index=self.start_indices[idx], - reverse=reverses[idx]) - for idx in range(len(var_names))] + self.blocks = [Block(var_name=var_names[idx], size=sizes[idx], start_index=self.start_indices[idx], reverse=reverses[idx]) for idx in range(len(var_names))] def __iter__(self): return chain(*self.blocks) @@ -265,9 +253,7 @@ def register(self, start, context): bl.register(start + offset, context) offset += len(bl) - self.vars = [shift(context[self.blocks[idx].var_name], - self.start_indices[idx]) - for idx in range(len(self.blocks))] + self.vars = [shift(context[self.blocks[idx].var_name], self.start_indices[idx]) for idx in range(len(self.blocks))] class PrefixedDictProxy: @@ -322,10 +308,9 @@ def register(self, start, context): bl.register(start + offset, context) offset += len(bl) - for ((con1, indices1), (con2, indices2)) in self.combinations: + for (con1, indices1), (con2, indices2) in self.combinations: for idx in range(min(len(indices1), len(indices2))): - self.connections += [context[con1](indices1[idx]) + context[ - con2](indices2[idx])] + self.connections += [context[con1](indices1[idx]) + context[con2](indices2[idx])] def implement(self, equations): for bl in self.blocks: @@ -342,8 +327,7 @@ def __init__(self, ifpart, thenpart, supposed_to_be_valid=True): self.supposedToBeValid = supposed_to_be_valid def __str__(self): - return ("If(AND(" + ", ".join(f"{p} == 0" for p in self.ifpart) + - ")), THEN " + ", ".join(f"{p} == 0" for p in self.thenpart)) + return "If(AND(" + ", ".join(f"{p} == 0" for p in self.ifpart) + ")), THEN " + ", ".join(f"{p} == 0" for p in self.thenpart) def if_then(i, t, supposed_to_be_valid=True): @@ -368,6 +352,7 @@ def declare_ring(blocks, context=None): the variable blocks x and y in the context dictionary ``globals()``, which consists of the global variables of the python module """ + def canonicalize(blocks): for elt in blocks: if isinstance(elt, str): @@ -384,7 +369,7 @@ def canonicalize(blocks): r = Ring(n, names=canonicalize(blocks)) context["internalVariable"] = VariableFactory(r) -# context["Monomial"] = MonomialFactory(r) + # context["Monomial"] = MonomialFactory(r) context["r"] = r declare_block_scheme(blocks, context) return r @@ -458,10 +443,7 @@ def main_test(): print(list(ablock)) # second test - declare_block_scheme([Block(var_name="x", size=100), - HigherOrderBlock("y", (3, 4, 11, 2)), - AlternatingBlock(["a", "b", "c"], 100)], - dic) + declare_block_scheme([Block(var_name="x", size=100), HigherOrderBlock("y", (3, 4, 11, 2)), AlternatingBlock(["a", "b", "c"], 100)], dic) x = dic['x'] a, b, c = dic['a'], dic['b'], dic['c'] for i in range(10): @@ -474,10 +456,7 @@ def main_test(): print(a(0), a(1), a(2), b(0), b(1), c(0)) # third test - declare_block_scheme([Block(var_name="x", size=100, reverse=True), - HigherOrderBlock("y", (3, 4, 11, 2), reverse=True), - AlternatingBlock(["a", "b", "c"], 100, reverse=True)], - dic) + declare_block_scheme([Block(var_name="x", size=100, reverse=True), HigherOrderBlock("y", (3, 4, 11, 2), reverse=True), AlternatingBlock(["a", "b", "c"], 100, reverse=True)], dic) x = dic['x'] a, b, c = dic['a'], dic['b'], dic['c'] for i in range(10): diff --git a/src/sage/rings/polynomial/pbori/cnf.py b/src/sage/rings/polynomial/pbori/cnf.py index 216b1d7b13a..79e43d6c90c 100644 --- a/src/sage/rings/polynomial/pbori/cnf.py +++ b/src/sage/rings/polynomial/pbori/cnf.py @@ -56,6 +56,7 @@ def choose(s): for i in reversed(indices): res = ite(i, res, self.empty_set) return next(iter(res)) + while not rest.empty(): l = choose(rest) l_variables = set(l.variables()) @@ -64,6 +65,7 @@ def get_val(var): if var in l_variables: return 1 return 0 + block_dict = {v: get_val(v) for v in variables} l = l.set() @@ -94,8 +96,7 @@ def clauses(self, f): # we form an expression for a var configuration *not* lying in the # block it is evaluated to 0 by f, iff it is not lying in any zero # block of f+1 - return [{variable: 1 - value for variable, value in b.items()} - for b in self.zero_blocks(f + 1)] + return [{variable: 1 - value for variable, value in b.items()} for b in self.zero_blocks(f + 1)] def polynomial_clauses(self, f): r""" @@ -121,8 +122,8 @@ def product(l): # please care about the order of these multiplications for # performance return res - return [product([variable + value for (variable, value) - in b.items()]) for b in self.clauses(f)] + + return [product([variable + value for (variable, value) in b.items()]) for b in self.clauses(f)] def to_dimacs_index(self, v): return v.index() + 1 @@ -134,9 +135,7 @@ def get_sign(value): return -1 items = sorted(c.items(), reverse=True) - return " ".join([str(v) for v in [ - get_sign(value) * self.to_dimacs_index(variable) - for (variable, value) in items] + [0]]) + return " ".join([str(v) for v in [get_sign(value) * self.to_dimacs_index(variable) for (variable, value) in items] + [0]]) def dimacs_encode_polynomial(self, p): r""" @@ -169,8 +168,7 @@ def dimacs_cnf(self, polynomial_system): sage: e.dimacs_cnf([r.variable(0)*r.variable(1)*r.variable(2), r.variable(1)+r.variable(0)]) 'c cnf generated by PolyBoRi\np cnf 3 3\n-1 -2 -3 0\n1 -2 0\n-1 2 0' """ - clauses_list = [c for p in polynomial_system for c in self. - dimacs_encode_polynomial(p)] + clauses_list = [c for p in polynomial_system for c in self.dimacs_encode_polynomial(p)] res = ["c cnf generated by PolyBoRi"] r = polynomial_system[0].ring() n_variables = r.n_variables() @@ -234,6 +232,5 @@ def dimacs_cnf(self, polynomial_system): """ uv = list(used_vars_set(polynomial_system).variables()) res = super().dimacs_cnf(polynomial_system) - res += "\n" + "\n".join(f"c v {self.to_dimacs_index(v)} {v}" - for v in uv) + res += "\n" + "\n".join(f"c v {self.to_dimacs_index(v)} {v}" for v in uv) return res diff --git a/src/sage/rings/polynomial/pbori/fglm.py b/src/sage/rings/polynomial/pbori/fglm.py index e12e5458c78..47718fc783b 100644 --- a/src/sage/rings/polynomial/pbori/fglm.py +++ b/src/sage/rings/polynomial/pbori/fglm.py @@ -55,8 +55,7 @@ def vars_real_divisors(monomial, monomial_set): sage: vars_real_divisors(x(1)*x(2)*x(3),b) {{x(1),x(2)}} """ - return BooleSet(Polynomial(monomial_set.divisors_of(monomial)). - graded_part(monomial.deg() - 1)) + return BooleSet(Polynomial(monomial_set.divisors_of(monomial)).graded_part(monomial.deg() - 1)) def m_k_plus_one(completed_elements, variables): @@ -87,5 +86,4 @@ def m_k_plus_one(completed_elements, variables): sage: m_k_plus_one(r2(s).set(),r2(variables).set()) x(1)*x(3) """ - return sorted(completed_elements.cartesian_product(variables).diff( - completed_elements))[0] + return sorted(completed_elements.cartesian_product(variables).diff(completed_elements))[0] diff --git a/src/sage/rings/polynomial/pbori/frontend.py b/src/sage/rings/polynomial/pbori/frontend.py index c50108e2cda..79b50053bc0 100644 --- a/src/sage/rings/polynomial/pbori/frontend.py +++ b/src/sage/rings/polynomial/pbori/frontend.py @@ -42,6 +42,7 @@ def block_scheme_names(blocks): """ context = {} from .blocks import declare_block_scheme + declare_block_scheme(blocks, context) return list(context.keys()) @@ -56,11 +57,16 @@ def declare_ring(blocks, context=None): context = global_context return orig_declare_ring(blocks, context) + declare_ring.__doc__ = orig_declare_ring.__doc__ global_context["declare_ring"] = declare_ring - print(ipbname + """ -- The interactive command line tool of PolyBoRi/BRiAL %s -""" % global_context.get("polybori_version", '')) + print( + ipbname + + """ -- The interactive command line tool of PolyBoRi/BRiAL %s +""" + % global_context.get("polybori_version", '') + ) # Here come the defaults diff --git a/src/sage/rings/polynomial/pbori/gbcore.py b/src/sage/rings/polynomial/pbori/gbcore.py index 1900b0e4414..dfc41cdda2d 100644 --- a/src/sage/rings/polynomial/pbori/gbcore.py +++ b/src/sage/rings/polynomial/pbori/gbcore.py @@ -27,7 +27,7 @@ def get_options_from_function(f): argnames, varargs, varopts, defaults = getargspec(f)[:4] - return dict(zip(argnames[-len(defaults):], defaults)) + return dict(zip(argnames[-len(defaults) :], defaults)) def filter_oldstyle_options(**options): @@ -90,8 +90,7 @@ def change_order_heuristic(d): I = d["I"] if not I: return d - switch_table = {OrderCode.lp: OrderCode.dp_asc, OrderCode.dlex: OrderCode. - dp_asc} + switch_table = {OrderCode.lp: OrderCode.dp_asc, OrderCode.dlex: OrderCode.dp_asc} if "other_ordering_first" not in d: # TODO after ll situation might look much different, so heuristic is on # wrong place @@ -144,8 +143,8 @@ def want_la(): if n_used_vars < bound: return True return False - if not (("faugere" in d and not d["faugere"]) or - ("noro" in d and d["noro"])): + + if not (("faugere" in d and not d["faugere"]) or ("noro" in d and d["noro"])): if ("faugere" in d and d["faugere"]) or want_la(): d["faugere"] = True @@ -169,7 +168,7 @@ def __call__(self, *args, **kwds): heuristic = True with contextlib.suppress(KeyError): heuristic = complete_dict["heuristic"] - for (k, v) in zip(self.argnames, args): + for k, v in zip(self.argnames, args): complete_dict[k] = v if heuristic: complete_dict = self.heuristicFunction(complete_dict) @@ -180,8 +179,7 @@ def __init__(self, f, heuristic_function): if hasattr(f, "options"): self.options = f.options else: - self.options = dict(zip(self.argnames[-len(self.defaults):], self. - defaults)) + self.options = dict(zip(self.argnames[-len(self.defaults) :], self.defaults)) self.heuristicFunction = heuristic_function self.f = f self.__doc__ = f.__doc__ @@ -192,6 +190,7 @@ def make_wrapper(f): wrapped = HeuristicalFunction(f, heuristic_function) wrapped.__name__ = f.__name__ return wrapped + return make_wrapper @@ -200,15 +199,12 @@ def clean_polys_pre(I): return (list({p for p in wrap if not p.is_zero()}), None) -def gb_with_pre_post_option(option, pre=None, - post=None, if_not_option=(), - default=False): +def gb_with_pre_post_option(option, pre=None, post=None, if_not_option=(), default=False): def make_wrapper(f): def wrapper(I, **kwds): prot = kwds.get("prot", False) for o in if_not_option: - if (o in kwds and kwds[o]) or (o not in kwds and - groebner_basis.options[o]): + if (o in kwds and kwds[o]) or (o not in kwds and groebner_basis.options[o]): option_set = False if "option_set" not in locals(): option_set = kwds.get(option, default) @@ -221,18 +217,17 @@ def wrapper(I, **kwds): print("preprocessing for option:", option) local_symbols = copy(locals()) - I, state = pre(**{k: v for (k, v) in local_symbols.items() - if k in pre_args}) + I, state = pre(**{k: v for (k, v) in local_symbols.items() if k in pre_args}) I = f(I, **kwds) if option_set and post: post_args = getargspec(post)[0] if prot: print("postprocessing for option:", option) local_symbols = copy(locals()) - I = post(**{k: v for (k, v) in local_symbols.items() - if k in post_args}) + I = post(**{k: v for (k, v) in local_symbols.items() if k in post_args}) return I + wrapper.__name__ = f.__name__ wrapper.__doc__ = f.__doc__ if hasattr(f, "options"): @@ -243,6 +238,7 @@ def wrapper(I, **kwds): wrapper.options[option] = default return wrapper + return make_wrapper @@ -278,8 +274,7 @@ def llfirst_pre(I, prot): def ll_constants_pre(I): ll_res = [] - while any(p.lex_lead_deg() == 1 and (p + p.lex_lead()).constant() - for p in I): + while any(p.lex_lead_deg() == 1 and (p + p.lex_lead()).constant() for p in I): I_new = [] ll = [] leads = set() @@ -337,17 +332,17 @@ def variety_size_from_gb(I): I = [p for p in I if not p.is_zero()] if not I: return 1 -# # TODO Here's something wrong! See the example with 5 solutions. -# # (reverting for now) -# number_of_used_vars = used_vars_set(I).deg() -# leads = set([p.lead() for p in I]) -# minimal_leads = BooleSet(leads).minimal_elements() -# number_of_used_vars_minimal_leads =\ -# minimal_leads.vars().deg() -# standard_monomials =\ -# minimal_leads.include_divisors().diff(minimal_leads) -# return standard_monomials.size_double()*\ -# 2**(number_of_used_vars-number_of_used_vars_minimal_leads) + # # TODO Here's something wrong! See the example with 5 solutions. + # # (reverting for now) + # number_of_used_vars = used_vars_set(I).deg() + # leads = set([p.lead() for p in I]) + # minimal_leads = BooleSet(leads).minimal_elements() + # number_of_used_vars_minimal_leads =\ + # minimal_leads.vars().deg() + # standard_monomials =\ + # minimal_leads.include_divisors().diff(minimal_leads) + # return standard_monomials.size_double()*\ + # 2**(number_of_used_vars-number_of_used_vars_minimal_leads) sm = Monomial(used_vars_set(I)).divisors() for p in I: @@ -377,8 +372,7 @@ def other_ordering_pre(I, option_set, kwds): try: new_ring = old_ring.clone(ordering=options["switch_to"]) - kwds = {k: options[k] for k in options - if k not in ("other_ordering_first", "switch_to", "I")} + kwds = {k: options[k] for k in options if k not in ("other_ordering_first", "switch_to", "I")} kwds["redsb"] = True I = groebner_basis([new_ring(poly) for poly in I], **kwds) variety_size = variety_size_from_gb(I) @@ -423,13 +417,7 @@ def llfirst_post(I, state, prot, kwds): I = list(chain(I, eliminated)) # redsb just for safety, as don't know how option is set kwds = copy(kwds) - kwds.update( - {'llfirst': False, - 'llfirstonthefly': False, - 'll_constants': False, - 'deg_bound': False, - 'other_ordering_first': False, - 'eliminate_identical_variables': False, 'redsb': True}) + kwds.update({'llfirst': False, 'llfirstonthefly': False, 'll_constants': False, 'deg_bound': False, 'other_ordering_first': False, 'eliminate_identical_variables': False, 'redsb': True}) I = groebner_basis(I, **kwds) return I @@ -459,6 +447,7 @@ def incremental_pre(I, prot, kwds): def sort_key(p): p = Polynomial(p) return (p.navigation().value(), -p.deg()) + I = sorted(I, key=sort_key) inc_sys = [] kwds = copy(kwds) @@ -508,50 +497,24 @@ def my_sort_key(l): @gb_with_pre_post_option("clean_arguments", pre=clean_polys_pre, default=True) -@gb_with_pre_post_option("easy_linear_polynomials", - pre=easy_linear_polynomials_pre, default=True) -@gb_with_pre_post_option("result_to_list", post=result_to_list_post, - default=True) +@gb_with_pre_post_option("easy_linear_polynomials", pre=easy_linear_polynomials_pre, default=True) +@gb_with_pre_post_option("result_to_list", post=result_to_list_post, default=True) @with_heuristic(interpolation_gb_heuristic) -@gb_with_pre_post_option("invert", pre=invert_all_pre, - post=invert_all_post, default=False) -@gb_with_pre_post_option("gauss_on_linear", pre=gauss_on_linear_pre, - default=True) -@gb_with_pre_post_option("ll_constants", pre=ll_constants_pre, - post=ll_constants_post, default=True) -@gb_with_pre_post_option("eliminate_identical_variables", - pre=eliminate_identical_variables_pre, - post=llfirst_post, default=True) +@gb_with_pre_post_option("invert", pre=invert_all_pre, post=invert_all_post, default=False) +@gb_with_pre_post_option("gauss_on_linear", pre=gauss_on_linear_pre, default=True) +@gb_with_pre_post_option("ll_constants", pre=ll_constants_pre, post=ll_constants_post, default=True) +@gb_with_pre_post_option("eliminate_identical_variables", pre=eliminate_identical_variables_pre, post=llfirst_post, default=True) @with_heuristic(ll_heuristic) -@gb_with_pre_post_option("llfirst", if_not_option=["llfirstonthefly"], - pre=llfirst_pre, post=llfirst_post, default=False) -@gb_with_pre_post_option("llfirstonthefly", pre=llfirstonthefly_pre, - post=llfirst_post, default=False) +@gb_with_pre_post_option("llfirst", if_not_option=["llfirstonthefly"], pre=llfirst_pre, post=llfirst_post, default=False) +@gb_with_pre_post_option("llfirstonthefly", pre=llfirstonthefly_pre, post=llfirst_post, default=False) @gb_with_pre_post_option("incremental", pre=incremental_pre) @with_heuristic(change_order_heuristic) -@gb_with_pre_post_option("other_ordering_first", if_not_option=[ - "interpolation_gb"], pre=other_ordering_pre, default=False) +@gb_with_pre_post_option("other_ordering_first", if_not_option=["interpolation_gb"], pre=other_ordering_pre, default=False) @with_heuristic(linear_algebra_heuristic) -@gb_with_pre_post_option("fix_deg_bound", if_not_option=["interpolation_gb"], - post=fix_deg_bound_post, default=True) -@gb_with_pre_post_option("minsb", post=minsb_post, - if_not_option=["redsb", "deg_bound", - "interpolation_gb", - "convert_with_fglm_from_ring"], - default=True) -@gb_with_pre_post_option("redsb", post=redsb_post, - if_not_option=["deg_bound", "interpolation_gb", - "convert_with_fglm_from_ring"], - default=True) -def groebner_basis(I, heuristic=True, unique_ideal_generator=False, - interpolation_gb=False, clean_and_restart_algorithm=False, - convert_with_fglm_from_ring=None, - convert_with_fglm_to_ring=None, - fglm_bound=40000, - modified_linear_algebra=True, preprocessor=None, - deg_bound=False, - implementation='Python', full_prot=False, prot=False, - draw_matrices=False, preprocess_only=False, **impl_options): +@gb_with_pre_post_option("fix_deg_bound", if_not_option=["interpolation_gb"], post=fix_deg_bound_post, default=True) +@gb_with_pre_post_option("minsb", post=minsb_post, if_not_option=["redsb", "deg_bound", "interpolation_gb", "convert_with_fglm_from_ring"], default=True) +@gb_with_pre_post_option("redsb", post=redsb_post, if_not_option=["deg_bound", "interpolation_gb", "convert_with_fglm_from_ring"], default=True) +def groebner_basis(I, heuristic=True, unique_ideal_generator=False, interpolation_gb=False, clean_and_restart_algorithm=False, convert_with_fglm_from_ring=None, convert_with_fglm_to_ring=None, fglm_bound=40000, modified_linear_algebra=True, preprocessor=None, deg_bound=False, implementation='Python', full_prot=False, prot=False, draw_matrices=False, preprocess_only=False, **impl_options): """Computes a Groebner basis of a given ideal I, w.r.t options.""" if not I: @@ -590,52 +553,41 @@ def groebner_basis(I, heuristic=True, unique_ideal_generator=False, for p in I: print(p) import sys + sys.exit(0) def call_algorithm(I, max_generators=None): - return implementation(I, - deg_bound=deg_bound, - full_prot=full_prot, - prot=prot, - max_generators=max_generators, - draw_matrices=draw_matrices, - **filter_newstyle_options(implementation, - **impl_options)) + return implementation(I, deg_bound=deg_bound, full_prot=full_prot, prot=prot, max_generators=max_generators, draw_matrices=draw_matrices, **filter_newstyle_options(implementation, **impl_options)) if clean_and_restart_algorithm: - for max_generators in [1000, 10000, 50000, 100000, 200000, 300000, - 400000, None]: + for max_generators in [1000, 10000, 50000, 100000, 200000, 300000, 400000, None]: try: return call_algorithm(I, max_generators=max_generators) except GeneratorLimitExceeded as e: I = list(e.strat.all_generators()) del e.strat if prot: - print("generator limit exceeded:", max_generators, - "restarting algorithm") + print("generator limit exceeded:", max_generators, "restarting algorithm") else: return call_algorithm(I) def build_groebner_basis_doc_string(): - additional_options_from_buchberger = filter_oldstyle_options( - **get_options_from_function(symmGB_F2_python)) + additional_options_from_buchberger = filter_oldstyle_options(**get_options_from_function(symmGB_F2_python)) for k in list(additional_options_from_buchberger): if k in groebner_basis.options: del additional_options_from_buchberger[k] gdoc = groebner_basis.__doc__ gdoc += "\nOptions are:\n" - gdoc += "\n".join(k + " : " + repr(groebner_basis.options[k]) - for k in groebner_basis.options) + gdoc += "\n".join(k + " : " + repr(groebner_basis.options[k]) for k in groebner_basis.options) gdoc += """ Turn off heuristic by setting heuristic=False Additional options come from the actual buchberger implementation. In case of our standard Python implementation these are the following: """ - gdoc += "\n".join(k + " : " + repr(additional_options_from_buchberger[k]) - for k in additional_options_from_buchberger) + gdoc += "\n".join(k + " : " + repr(additional_options_from_buchberger[k]) for k in additional_options_from_buchberger) groebner_basis.__doc__ = gdoc diff --git a/src/sage/rings/polynomial/pbori/interpolate.py b/src/sage/rings/polynomial/pbori/interpolate.py index 7502267291f..0aab8122af9 100644 --- a/src/sage/rings/polynomial/pbori/interpolate.py +++ b/src/sage/rings/polynomial/pbori/interpolate.py @@ -40,13 +40,11 @@ def bench_interpolate(degree, nvariables, points): c1 = clock() res2 = interpolate_smallest_lex(p, q) c2 = clock() - print("finished interpolate_smallest_lex(p,q),len:", len(res2), - "time", c2 - c1) + print("finished interpolate_smallest_lex(p,q),len:", len(res2), "time", c2 - c1) c1 = clock() res1 = interpolate(p, q) c2 = clock() - print("finished interpolate(p,q)" + len("_smallest_lex") * " " + ",len:", - res1.set().size_double(), "time:", c2 - c1) + print("finished interpolate(p,q)" + len("_smallest_lex") * " " + ",len:", res1.set().size_double(), "time:", c2 - c1) return res2 @@ -95,26 +93,20 @@ def lex_groebner_basis_points(points, variables): def lex_groebner_basis_for_polynomial_via_variety(p): variables = p.vars_as_monomial() - return lex_groebner_basis_points(p.zeros_in(variables.divisors()), - variables) + return lex_groebner_basis_points(p.zeros_in(variables.divisors()), variables) if __name__ == '__main__': nvariables = 100 r = declare_ring([Block("x", nvariables)]) - for number_of_points in (100, 500, 1000, 2000, 3000, - 4000, 5000, 10000, - 20000, 50000, 100000): + for number_of_points in (100, 500, 1000, 2000, 3000, 4000, 5000, 10000, 20000, 50000, 100000): print("----------") print("number_of_points:", number_of_points) print("generate points") - points = gen_random_poly(r, number_of_points, - nvariables, - [Variable(i, r) for i in range(nvariables)]) + points = gen_random_poly(r, number_of_points, nvariables, [Variable(i, r) for i in range(nvariables)]) print("points generated") bench_interpolate(nvariables, nvariables, points) vars_mon = Monomial(r) for i in reversed(range(nvariables)): vars_mon = vars_mon * Variable(i, r) - print(len(variety_lex_leading_terms(points, vars_mon)), - "elements in groebner basis") + print(len(variety_lex_leading_terms(points, vars_mon)), "elements in groebner basis") diff --git a/src/sage/rings/polynomial/pbori/ll.py b/src/sage/rings/polynomial/pbori/ll.py index 5d574d5906f..db37db0f5c1 100644 --- a/src/sage/rings/polynomial/pbori/ll.py +++ b/src/sage/rings/polynomial/pbori/ll.py @@ -52,10 +52,8 @@ def ll_encode(polys, reduce=False, prot=False, reduce_by_linear=True): if (not reduce) and reduce_by_linear: linear_polys = [p for p in polys if p.deg() == 1] if linear_polys: - linear_ll = ll_encode(linear_polys, reduce=True, - reduce_by_linear=False) - polys = [p.lex_lead() + ll_red_nf_redsb(p + p.lex_lead(), - linear_ll) for p in polys] + linear_ll = ll_encode(linear_polys, reduce=True, reduce_by_linear=False) + polys = [p.lex_lead() + ll_red_nf_redsb(p + p.lex_lead(), linear_ll) for p in polys] reduce = ll_red_nf_redsb if reduce else None reductors = Polynomial(polys[0].ring().one()).set() if polys else None @@ -74,8 +72,7 @@ def ll_encode(polys, reduce=False, prot=False, reduce_by_linear=True): return reductors -def eliminate(polys, on_the_fly=False, prot=False, reduction_function=None, - optimized=True): +def eliminate(polys, on_the_fly=False, prot=False, reduction_function=None, optimized=True): r""" There exists an optimized variant, which reorders the variable in a different ring. """ @@ -97,8 +94,10 @@ def eliminate(polys, on_the_fly=False, prot=False, reduction_function=None, else: rest.append(p) if not linear_leads: + def identity(p): return p + return (linear_leads, identity, rest) if reduction_function is None: if on_the_fly: @@ -110,13 +109,12 @@ def identity(p): reduction_function = ll_red_nf_redsb if optimized: - llnf, reduced_list = eliminate_ll_ranked(linear_leads, rest, - reduction_function=reduction_function, - reduce_ll_system=(not on_the_fly), - prot=prot) + llnf, reduced_list = eliminate_ll_ranked(linear_leads, rest, reduction_function=reduction_function, reduce_ll_system=(not on_the_fly), prot=prot) else: + def llnf(p): return reduction_function(p, reductors) + reduced_list = [] reductors = ll_encode(linear_leads, reduce=(not on_the_fly), prot=prot) for p in rest: @@ -131,30 +129,29 @@ def llnf(p): def construct_map_by_indices(to_ring, idx_mapping): v = BoolePolynomialVector((max(idx_mapping.keys()) + 1) * [to_ring.zero()]) - for (from_idx, to_idx) in idx_mapping.items(): + for from_idx, to_idx in idx_mapping.items(): val = to_ring.variable(to_idx) v[from_idx] = val return v -def eliminate_ll_ranked(ll_system, to_reduce, - reduction_function=ll_red_nf_noredsb, - reduce_ll_system=False, prot=False): +def eliminate_ll_ranked(ll_system, to_reduce, reduction_function=ll_red_nf_noredsb, reduce_ll_system=False, prot=False): assert ll_system from_ring = ll_system[0].ring() ll_ranks = rank(ll_system) - add_vars = set(used_vars_set(to_reduce).variables()).difference(ll_ranks. - keys()) + add_vars = set(used_vars_set(to_reduce).variables()).difference(ll_ranks.keys()) for v in add_vars: ll_ranks[v] = -1 # pushing variables ignored by ll to the front means, # that the routines will quickly eliminate them # and they won't give any overhead + def sort_key(v): return (ll_ranks[v], v.index()) + sorted_vars = sorted(ll_ranks.keys(), key=sort_key) def var_index(v): @@ -166,7 +163,7 @@ def var_index(v): var_names = [str(v) for v in sorted_vars] try: - for (i, v) in enumerate(sorted_vars): + for i, v in enumerate(sorted_vars): assert var_names[i] == str(v), (var_names[i], v, var_index(v), i) finally: @@ -185,12 +182,11 @@ def map_back(p): return substitute_variables(from_ring, map_back_vec, p) try: - ll_opt_encoded = ll_encode([map_from(p) for p in ll_system], - prot=False, - reduce=reduce_ll_system) + ll_opt_encoded = ll_encode([map_from(p) for p in ll_system], prot=False, reduce=reduce_ll_system) def llnf(p): return map_back(reduction_function(map_from(p), ll_opt_encoded)) + opt_eliminated = [llnf(p) for p in to_reduce] finally: pass @@ -240,6 +236,7 @@ def __init__(self, to_ring, from_ring): sage: mapping(x(1)+1) x(1) + 1 """ + def vars(ring): return [ring.variable(i) for i in range(ring.n_variables())] diff --git a/src/sage/rings/polynomial/pbori/nf.py b/src/sage/rings/polynomial/pbori/nf.py index 0b8e74cd2dd..647b5f2f4ce 100644 --- a/src/sage/rings/polynomial/pbori/nf.py +++ b/src/sage/rings/polynomial/pbori/nf.py @@ -62,8 +62,7 @@ def build_and_print_matrices(v, strat): v.append(p2) polys_in_mat.append(p) treated = treated.union(p.set()) - m2i = {v: k - for k, v in enumerate(list(Polynomial(BooleSet(treated)).terms()))} + m2i = {v: k for k, v in enumerate(list(Polynomial(BooleSet(treated)).terms()))} polys_in_mat.sort(key=Polynomial.lead, reverse=True) polys_in_mat = [[m2i[t] for t in p.terms()] for p in polys_in_mat] @@ -104,6 +103,7 @@ def multiply_polynomials(l, ring): def sort_key(p): return p.navigation().value() + l = sorted(l, key=sort_key) res = Polynomial(ring.one()) for p in l: @@ -213,18 +213,7 @@ def high_probability_polynomials_trick(p, strat): strat.add_as_you_wish(c) -def symmGB_F2_python(G, deg_bound=1000000000000, over_deg_bound=0, - use_faugere=False, use_noro=False, - opt_lazy=True, opt_red_tail=True, - max_growth=2.0, step_factor=1.0, - implications=False, prot=False, - full_prot=False, selection_size=1000, opt_exchange=True, - opt_allow_recursion=False, ll=False, - opt_linear_algebra_in_last_block=True, - max_generators=None, - red_tail_deg_growth=True, matrix_prefix='mat', - modified_linear_algebra=True, draw_matrices=False, - easy_linear_polynomials=True): +def symmGB_F2_python(G, deg_bound=1000000000000, over_deg_bound=0, use_faugere=False, use_noro=False, opt_lazy=True, opt_red_tail=True, max_growth=2.0, step_factor=1.0, implications=False, prot=False, full_prot=False, selection_size=1000, opt_exchange=True, opt_allow_recursion=False, ll=False, opt_linear_algebra_in_last_block=True, max_generators=None, red_tail_deg_growth=True, matrix_prefix='mat', modified_linear_algebra=True, draw_matrices=False, easy_linear_polynomials=True): if use_noro and use_faugere: raise ValueError('both use_noro and use_faugere specified') @@ -236,8 +225,7 @@ def add_to_basis(strat, p): if prot: if full_prot: print(p) - print("Result: ", "deg:", p.deg(), "lm: ", - p.lead(), "el: ", p.elength()) + print("Result: ", "deg:", p.deg(), "lm: ", p.lead(), "el: ", p.elength()) if easy_linear_polynomials and p.lead_deg() > 2: lin = easy_linear_polynomials_func(p) for q in lin: @@ -264,8 +252,7 @@ def add_to_basis(strat, p): strat.enabled_log = prot strat.reduction_strategy.opt_ll = ll strat.opt_modified_linear_algebra = modified_linear_algebra - strat.opt_linear_algebra_in_last_block = ( - opt_linear_algebra_in_last_block) + strat.opt_linear_algebra_in_last_block = opt_linear_algebra_in_last_block strat.opt_red_by_reduced = False # True strat.reduction_strategy.opt_red_tail_deg_growth = red_tail_deg_growth @@ -290,7 +277,7 @@ def add_to_basis(strat, p): print("Current Degree:", strat.top_sugar()) if (strat.top_sugar() > deg_bound) and (over_deg_bound <= 0): return strat - if (strat.top_sugar() > deg_bound): + if strat.top_sugar() > deg_bound: ps = strat.some_spolys_in_next_degree(over_deg_bound) over_deg_bound -= len(ps) else: @@ -313,10 +300,7 @@ def add_to_basis(strat, p): print("(", strat.npairs(), ")") if prot: print("start reducing") - print("Chain Crit. : ", strat.chain_criterions, "VC:", strat. - variable_chain_criterions, "EASYP", strat. - easy_product_criterions, "EXTP", strat. - extended_product_criterions) + print("Chain Crit. : ", strat.chain_criterions, "VC:", strat.variable_chain_criterions, "EASYP", strat.easy_product_criterions, "EXTP", strat.extended_product_criterions) print(len(ps), "spolys added") if use_noro or use_faugere: @@ -330,20 +314,15 @@ def add_to_basis(strat, p): else: v = BoolePolynomialVector() for p in ps: - rp = Polynomial(mod_mon_set( - BooleSet(p.set()), - strat.reduction_strategy.monomials)) + rp = Polynomial(mod_mon_set(BooleSet(p.set()), strat.reduction_strategy.monomials)) if not rp.is_zero(): v.append(rp) if len(v) > 100: - res = parallel_reduce(v, strat, int(step_factor * 10), - max_growth) + res = parallel_reduce(v, strat, int(step_factor * 10), max_growth) elif len(v) > 10: - res = parallel_reduce(v, strat, int(step_factor * 30), - max_growth) + res = parallel_reduce(v, strat, int(step_factor * 30), max_growth) else: - res = parallel_reduce(v, strat, int(step_factor * 100), - max_growth) + res = parallel_reduce(v, strat, int(step_factor * 100), max_growth) if prot: print("end reducing") @@ -360,6 +339,7 @@ def add_to_basis(strat, p): def sort_key(p): return p.lead() + res_cp = sorted(res, key=sort_key) for p in res_cp: @@ -386,13 +366,10 @@ def step(strat, trace, var, val): print("npairs", strat.npairs()) strat = GroebnerStrategy(strat) print("npairs", strat.npairs()) - strat.add_generator_delayed(Polynomial( - Monomial(Variable(var, strat.r)) + val)) - strat = symmGB_F2_python(strat, prot=True, deg_bound=2, - over_deg_bound=10) + strat.add_generator_delayed(Polynomial(Monomial(Variable(var, strat.r)) + val)) + strat = symmGB_F2_python(strat, prot=True, deg_bound=2, over_deg_bound=10) if var <= vars_start: - strat = symmGB_F2_python(strat, prot=True, opt_lazy=False, - opt_red_tail=False) + strat = symmGB_F2_python(strat, prot=True, opt_lazy=False, opt_red_tail=False) if strat.containsOne(): pass else: @@ -409,6 +386,7 @@ def branch(strat, trace, var): var -= 1 step(strat, trace, var, 0) step(strat, trace, var, 1) + if G: strat = GroebnerStrategy(G[0].ring()) # strat.add_generator(G[0]) @@ -434,8 +412,7 @@ def step(strat, trace, proof_path, pos, val): strat.add_generator_delayed(plug_p) print("npairs", strat.npairs()) print("pos:", pos) - strat = symmGB_F2_python(strat, deg_bound=deg_bound, opt_lazy=False, - over_deg_bound=over_deg_bound, prot=True) + strat = symmGB_F2_python(strat, deg_bound=deg_bound, opt_lazy=False, over_deg_bound=over_deg_bound, prot=True) print("npairs", strat.npairs()) pos = pos + 1 if pos >= len(proof_path): @@ -459,6 +436,7 @@ def branch(strat, trace, proof_path, pos): step(strat, trace, proof_path, pos, 0) step(strat, trace, proof_path, pos, 1) + strat = GroebnerStrategy(G[0].ring()) strat.add_generator(Polynomial(G[0])) for g in G[1:]: @@ -466,8 +444,7 @@ def branch(strat, trace, proof_path, pos): branch(strat, [], proof_path, 0) -def GPS_with_suggestions(G, deg_bound, over_deg_bound, opt_lazy=True, - opt_red_tail=True, initial_bb=True): +def GPS_with_suggestions(G, deg_bound, over_deg_bound, opt_lazy=True, opt_red_tail=True, initial_bb=True): def step(strat, trace, var, val): print(trace) plug_p = val + var @@ -478,9 +455,7 @@ def step(strat, trace, var, val): strat.add_generator_delayed(plug_p) print("npairs", strat.npairs()) - strat = symmGB_F2_python(strat, deg_bound=deg_bound, - opt_lazy=opt_lazy, - over_deg_bound=over_deg_bound, prot=True) + strat = symmGB_F2_python(strat, deg_bound=deg_bound, opt_lazy=opt_lazy, over_deg_bound=over_deg_bound, prot=True) if not strat.containsOne(): branch(strat, trace) @@ -491,8 +466,7 @@ def branch(strat, trace): if index < 0: uv = set(used_vars_set(strat)) - lv = {next(iter(p.lead())).index() - for p in strat if p.lead_deg() == 1} + lv = {next(iter(p.lead())).index() for p in strat if p.lead_deg() == 1} candidates = uv.difference(lv) if candidates: index = next(iter(candidates)).index() @@ -512,6 +486,7 @@ def branch(strat, trace): def sort_crit(p): return (p.lead(), p.deg(), p.elength()) + if not G: return strat = GroebnerStrategy(G[0].ring()) @@ -535,10 +510,7 @@ def sort_crit(p): for g in G: strat.add_as_you_wish(g) if initial_bb: - strat = symmGB_F2_python(strat, deg_bound=max(deg_bound, - first_deg_bound), - opt_lazy=opt_lazy, over_deg_bound=0, - prot=True) + strat = symmGB_F2_python(strat, deg_bound=max(deg_bound, first_deg_bound), opt_lazy=opt_lazy, over_deg_bound=0, prot=True) strat.opt_lazy = opt_lazy print("INITIALIZED") branch(strat, []) @@ -558,8 +530,7 @@ def step(strat, trace, proof_path, pos, choice): print("npairs", strat.npairs()) print("pos:", pos) - strat = symmGB_F2_python(strat, deg_bound=deg_bound, - over_deg_bound=over_deg_bound, prot=True) + strat = symmGB_F2_python(strat, deg_bound=deg_bound, over_deg_bound=over_deg_bound, prot=True) print("npairs", strat.npairs()) pos = pos + 1 if pos >= len(proof_path): @@ -590,17 +561,7 @@ def branch(strat, trace, proof_path, pos): branch(strat, [], proof_path, 0) -def symmGB_F2_C(G, opt_exchange=True, - deg_bound=1000000000000, opt_lazy=False, - over_deg_bound=0, opt_red_tail=True, - max_growth=2.0, step_factor=1.0, - implications=False, prot=False, - full_prot=False, selection_size=1000, - opt_allow_recursion=False, use_noro=False, use_faugere=False, - ll=False, opt_linear_algebra_in_last_block=True, - max_generators=None, red_tail_deg_growth=True, - modified_linear_algebra=True, matrix_prefix='', - draw_matrices=False): +def symmGB_F2_C(G, opt_exchange=True, deg_bound=1000000000000, opt_lazy=False, over_deg_bound=0, opt_red_tail=True, max_growth=2.0, step_factor=1.0, implications=False, prot=False, full_prot=False, selection_size=1000, opt_allow_recursion=False, use_noro=False, use_faugere=False, ll=False, opt_linear_algebra_in_last_block=True, max_generators=None, red_tail_deg_growth=True, modified_linear_algebra=True, matrix_prefix='', draw_matrices=False): if use_noro: raise NotImplementedError("noro not implemented for symmgb") if isinstance(G, list): @@ -615,8 +576,7 @@ def symmGB_F2_C(G, opt_exchange=True, strat.opt_exchange = opt_exchange strat.reduction_strategy.opt_ll = ll strat.opt_allow_recursion = opt_allow_recursion - strat.opt_linear_algebra_in_last_block = ( - opt_linear_algebra_in_last_block) + strat.opt_linear_algebra_in_last_block = opt_linear_algebra_in_last_block strat.enabled_log = prot strat.opt_modified_linear_algebra = modified_linear_algebra strat.matrix_prefix = matrix_prefix @@ -662,6 +622,7 @@ def normal_form(poly, ideal, reduced=True): def _test(): import doctest + doctest.testmod() diff --git a/src/sage/rings/polynomial/pbori/parallel.py b/src/sage/rings/polynomial/pbori/parallel.py index 23f4303918c..66bfe736363 100644 --- a/src/sage/rings/polynomial/pbori/parallel.py +++ b/src/sage/rings/polynomial/pbori/parallel.py @@ -5,6 +5,7 @@ Created by Michael Brickenstein on 2008-10-31. Copyright 2008 The PolyBoRi Team """ + import copyreg import os from zlib import compress, decompress @@ -94,6 +95,7 @@ def find_navs(nav): nodes.add(nav) find_navs(nav.then_branch()) find_navs(nav.else_branch()) + for f in l: f_nav = f.set().navigation() find_navs(f_nav) @@ -155,7 +157,7 @@ def from_fast_pickable(l, r) -> list: i2poly = {0: r.zero(), 1: r.one()} indices, terms = l - for i in range(len(terms) - 1, -1, - 1): + for i in range(len(terms) - 1, -1, -1): v, t, e = terms[i] t = i2poly[t] e = i2poly[e] @@ -178,14 +180,14 @@ def _encode_polynomial(poly): def pickle_polynomial(self): - return (_decode_polynomial, (_encode_polynomial(self), )) + return (_decode_polynomial, (_encode_polynomial(self),)) copyreg.pickle(Polynomial, pickle_polynomial) def pickle_bset(self): - return (BooleSet, (Polynomial(self), )) + return (BooleSet, (Polynomial(self),)) copyreg.pickle(BooleSet, pickle_bset) @@ -252,8 +254,7 @@ def _encode_ring(ring): else: nvars = ring.n_variables() data = (nvars, ring.get_order_code()) - varnames = '\n'.join(str(ring.variable(idx)) - for idx in range(nvars)) + varnames = '\n'.join(str(ring.variable(idx)) for idx in range(nvars)) blocks = list(ring.blocks()) code = (identifier, data, compress(varnames), blocks[:-1]) _polybori_parallel_rings[identifier] = (WeakRingRef(ring), code) @@ -262,7 +263,7 @@ def _encode_ring(ring): def pickle_ring(self): - return (_decode_ring, (_encode_ring(self), )) + return (_decode_ring, (_encode_ring(self),)) copyreg.pickle(Ring, pickle_ring) @@ -297,8 +298,7 @@ def groebner_basis_first_finished(I, *l): from multiprocessing import Pool pool = Pool(processes=len(l)) - it = pool.imap_unordered(_calculate_gb_with_keywords, - [(I, kwds) for kwds in l]) + it = pool.imap_unordered(_calculate_gb_with_keywords, [(I, kwds) for kwds in l]) res = next(it) pool.terminate() diff --git a/src/sage/rings/polynomial/pbori/randompoly.py b/src/sage/rings/polynomial/pbori/randompoly.py index 4cbec0e10b0..b224bb01165 100644 --- a/src/sage/rings/polynomial/pbori/randompoly.py +++ b/src/sage/rings/polynomial/pbori/randompoly.py @@ -41,14 +41,14 @@ def helper(samples): return Polynomial(m) assert samples >= 2 return helper(samples // 2) + helper(samples - samples // 2) + p = Polynomial(ring.zero()) while len(p) < l: p = Polynomial(p.set().union(helper(l - len(p)).set())) return p -def sparse_random_system(ring, number_of_polynomials, variables_per_polynomial, - degree, random_seed=None): +def sparse_random_system(ring, number_of_polynomials, variables_per_polynomial, degree, random_seed=None): r""" Generate a sparse random system. @@ -78,13 +78,8 @@ def sparse_random_system(ring, number_of_polynomials, variables_per_polynomial, solutions = ll_encode(solutions) res = [] while len(res) < number_of_polynomials: - variables_as_monomial = Monomial( - random_generator.sample( - variables, - variables_per_polynomial) - ) - p = Polynomial(random_set(variables_as_monomial, 2 ** ( - variables_per_polynomial - 1))) + variables_as_monomial = Monomial(random_generator.sample(variables, variables_per_polynomial)) + p = Polynomial(random_set(variables_as_monomial, 2 ** (variables_per_polynomial - 1))) p = sum([p.graded_part(i) for i in range(degree + 1)]) if p.deg() == degree: res.append(p) @@ -101,9 +96,7 @@ def sparse_random_system_data_file_content(number_of_variables, **kwds): "declare_ring(['x'+str(i) for in range(10)])\nideal=\\\n[...]\n\n" """ dummy_dict = {} - r = declare_ring(['x' + str(i) for i in range(number_of_variables)], - dummy_dict) + r = declare_ring(['x' + str(i) for i in range(number_of_variables)], dummy_dict) polynomials = sparse_random_system(r, **kwds) polynomials = pformat(polynomials) - return "declare_ring(['x'+str(i) for in range({})])\nideal=\\\n{}\n\n".format( - number_of_variables, polynomials) + return "declare_ring(['x'+str(i) for in range({})])\nideal=\\\n{}\n\n".format(number_of_variables, polynomials) diff --git a/src/sage/rings/polynomial/pbori/rank.py b/src/sage/rings/polynomial/pbori/rank.py index 98d0a1727c9..f3805f7754f 100644 --- a/src/sage/rings/polynomial/pbori/rank.py +++ b/src/sage/rings/polynomial/pbori/rank.py @@ -20,6 +20,7 @@ def do_rank(v): return res[v] my_res = res[v] = max((do_rank(p) + 1 for p in parents[v]), default=0) return my_res + for v in parents: do_rank(v) return res diff --git a/src/sage/rings/polynomial/pbori/specialsets.py b/src/sage/rings/polynomial/pbori/specialsets.py index 6d77f70f08e..1efcc79d8a6 100644 --- a/src/sage/rings/polynomial/pbori/specialsets.py +++ b/src/sage/rings/polynomial/pbori/specialsets.py @@ -55,7 +55,7 @@ def all_monomials_of_degree_d(d, variables): res = Monomial(deg_variables) for i in range(1, len(variables) - d + 1): - deg_variables = variables[-d - i:-i] + deg_variables = variables[-d - i : -i] res = Polynomial(res) nav = res.navigation() navs = [] @@ -63,7 +63,7 @@ def all_monomials_of_degree_d(d, variables): navs.append(BooleSet(nav, ring)) nav = nav.then_branch() acc = Polynomial(1, ring) - for (nav, v) in reversed(zip(navs, deg_variables)): + for nav, v in reversed(zip(navs, deg_variables)): acc = if_then_else(v, acc, nav) res = acc return res.set() @@ -84,6 +84,7 @@ def power_set(variables): if __name__ == '__main__': from .blocks import Block, declare_ring + r = declare_ring([Block("x", 10000)], globals()) print(list(all_monomials_of_degree_d(0, [Variable(i) for i in range(100)]))) print(list(all_monomials_of_degree_d(1, [Variable(i) for i in range(10)]))) @@ -96,18 +97,11 @@ def power_set(variables): print(list(power_set([Variable(i) for i in range(4)]))) print(list(power_set())) # every monomial in the first 8 var, which is at most linear in the first 5 - print(list(mod_mon_set( - power_set([Variable(i) for i in range(8)]), - all_monomials_of_degree_d(2, [Variable(i) for i in range(5)])))) + print(list(mod_mon_set(power_set([Variable(i) for i in range(8)]), all_monomials_of_degree_d(2, [Variable(i) for i in range(5)])))) # specialized normal form computation - print(Polynomial( - mod_mon_set( - (x(1) * x(2) + x(1) + 1).set(), - all_monomials_of_degree_d(2, [Variable(i) for i in range(1000)])))) - print(list(mod_mon_set( - power_set([Variable(i) for i in range(50)]), - all_monomials_of_degree_d(2, [Variable(i) for i in range(1000)])))) + print(Polynomial(mod_mon_set((x(1) * x(2) + x(1) + 1).set(), all_monomials_of_degree_d(2, [Variable(i) for i in range(1000)])))) + print(list(mod_mon_set(power_set([Variable(i) for i in range(50)]), all_monomials_of_degree_d(2, [Variable(i) for i in range(1000)])))) def monomial_from_indices(ring, indices): diff --git a/src/sage/rings/polynomial/polynomial_element_generic.py b/src/sage/rings/polynomial/polynomial_element_generic.py index 43adf8b2a0d..1573f39e42c 100644 --- a/src/sage/rings/polynomial/polynomial_element_generic.py +++ b/src/sage/rings/polynomial/polynomial_element_generic.py @@ -82,6 +82,7 @@ class Polynomial_generic_sparse(Polynomial): sage: (s + T)**2 s^2 + 2*Tbar*s + 4 """ + def __init__(self, parent, x=None, check=True, is_gen=False, construct=False): """ TESTS:: @@ -119,7 +120,7 @@ def __init__(self, parent, x=None, check=True, is_gen=False, construct=False): x = y check = True elif not isinstance(x, dict): - x = {0: x} # constant polynomials + x = {0: x} # constant polynomials if check: self.__coeffs = {} for i, z in x.items(): @@ -268,15 +269,14 @@ def _derivative(self, var=None): if var is not None and var != P.gen(): try: # call _derivative() recursively on coefficients - return P({n:self.__coeffs[n]._derivative(var) - for n in self.__coeffs}) + return P({n: self.__coeffs[n]._derivative(var) for n in self.__coeffs}) except AttributeError: raise ValueError('cannot differentiate with respect to {}'.format(var)) # compute formal derivative with respect to generator d = {} for n, c in self.__coeffs.items(): - d[n-1] = n*c + d[n - 1] = n * c if -1 in d: del d[-1] return P(d) @@ -335,16 +335,17 @@ def integral(self, var=None): import operator from sage.structure.element import coercion_model as cm + try: Q = cm.bin_op(R.one(), ZZ.one(), operator.truediv).parent() except TypeError: - F = (R.base_ring().one()/ZZ.one()).parent() + F = (R.base_ring().one() / ZZ.one()).parent() Q = R.change_ring(F) if var is not None and var != R.gen(): - return Q({k:v.integral(var) for k,v in self.__coeffs.items()}, check=False) + return Q({k: v.integral(var) for k, v in self.__coeffs.items()}, check=False) - return Q({ k+1:v/(k+1) for k,v in self.__coeffs.items()}, check=False) + return Q({k + 1: v / (k + 1) for k, v in self.__coeffs.items()}, check=False) def _dict_unsafe(self): """ @@ -392,9 +393,9 @@ def _repr(self, name=None): name = self.parent().variable_name() atomic_repr = self.parent().base_ring()._repr_option('element_is_atomic') coeffs = sorted(self.__coeffs.items()) - for (n, x) in reversed(coeffs): + for n, x in reversed(coeffs): if x: - if n != m-1: + if n != m - 1: s += " + " x = y = repr(x) if y.find("-") == 0: @@ -402,14 +403,14 @@ def _repr(self, name=None): if not atomic_repr and n > 0 and (y.find("+") != -1 or y.find("-") != -1): x = "(%s)" % x if n > 1: - var = "*%s^%s" % (name,n) + var = "*%s^%s" % (name, n) elif n == 1: var = "*%s" % name else: var = "" - s += "%s%s" % (x,var) + s += "%s%s" % (x, var) s = s.replace(" + -", " - ") - s = s.replace(" 1*"," ") + s = s.replace(" 1*", " ") s = s.replace(" -1*", " -") if s == " ": return "0" @@ -478,8 +479,7 @@ def __getitem__(self, n): d = self.degree() + 1 if stop is None or stop > d: stop = d - v = {key: val for key, val in self.__coeffs.items() - if key < stop} + v = {key: val for key, val in self.__coeffs.items() if key < stop} return self.parent()(v) try: @@ -536,7 +536,7 @@ def list(self, copy=True): [0, 17, 15, 0, 0, 13] """ zero = self.base_ring().zero() - v = [zero] * (self.degree()+1) + v = [zero] * (self.degree() + 1) for n, x in self.__coeffs.items(): v[n] = x return v @@ -592,7 +592,7 @@ def _add_(self, right): """ output = dict(self.__coeffs) - for (index, coeff) in right.__coeffs.items(): + for index, coeff in right.__coeffs.items(): if index in output: output[index] += coeff else: @@ -612,8 +612,8 @@ def _neg_(self): sage: -a -x^10000000 """ - output = { } - for (index, coeff) in self.__coeffs.items(): + output = {} + for index, coeff in self.__coeffs.items(): output[index] = -coeff output = self.parent()(output, check=False) return output @@ -633,8 +633,8 @@ def _mul_(self, right): """ output = {} - for (index1, coeff1) in self.__coeffs.items(): - for (index2, coeff2) in right.__coeffs.items(): + for index1, coeff1 in self.__coeffs.items(): + for index2, coeff2 in right.__coeffs.items(): product = coeff1 * coeff2 index = index1 + index2 if index in output: @@ -662,7 +662,7 @@ def _rmul_(self, left): """ output = {} - for (index, coeff) in self.__coeffs.items(): + for index, coeff in self.__coeffs.items(): output[index] = left * coeff output = self.parent()(output, check=False) @@ -685,7 +685,7 @@ def _lmul_(self, right): """ output = {} - for (index, coeff) in self.__coeffs.items(): + for index, coeff in self.__coeffs.items(): output[index] = coeff * right output = self.parent()(output, check=False) @@ -790,10 +790,10 @@ def shift(self, n): if n == 0: return self if n > 0: - output = {index+n: coeff for index, coeff in self.__coeffs.items()} + output = {index + n: coeff for index, coeff in self.__coeffs.items()} return self.parent()(output, check=False) if n < 0: - output = {index+n:coeff for index, coeff in self.__coeffs.items() if index + n >= 0} + output = {index + n: coeff for index, coeff in self.__coeffs.items() if index + n >= 0} return self.parent()(output, check=False) @coerce_binop @@ -899,11 +899,11 @@ def quo_rem(self, other): except TypeError: raise ArithmeticError("Division non exact (consider coercing to polynomials over the fraction field)") e = rem.degree() - d - quo += c*R.one().shift(e) + quo += c * R.one().shift(e) # we know that the leading coefficient of rem vanishes # thus we avoid doing a useless computation - rem = rem[:rem.degree()] - c*other[:d].shift(e) - return (quo,rem) + rem = rem[: rem.degree()] - c * other[:d].shift(e) + return (quo, rem) @coerce_binop def gcd(self, other, algorithm=None): @@ -980,16 +980,15 @@ def gcd(self, other, algorithm=None): # sd = self.degree() od = other.degree() - if ((sd < 100 or len(self.__coeffs)/sd > .06) - and (od < 100 or len(other.__coeffs)/od > .06)): + if (sd < 100 or len(self.__coeffs) / sd > 0.06) and (od < 100 or len(other.__coeffs) / od > 0.06): implementation = "FLINT" else: implementation = "NTL" - D = PolynomialRing(S.base_ring(),'x',implementation=implementation) + D = PolynomialRing(S.base_ring(), 'x', implementation=implementation) g = D(self).gcd(D(other)) return S(g) if algorithm == "generic": - return Polynomial.gcd(self,other) + return Polynomial.gcd(self, other) raise ValueError("Unknown algorithm '%s'" % algorithm) def reverse(self, degree=None): @@ -1011,9 +1010,9 @@ def reverse(self, degree=None): """ if degree is None: degree = self.degree() - if not isinstance(degree, (int,Integer)): + if not isinstance(degree, (int, Integer)): raise ValueError("degree argument must be a nonnegative integer, got %s" % degree) - d = {degree-k: v for k,v in self.__coeffs.items() if degree >= k} + d = {degree - k: v for k, v in self.__coeffs.items() if degree >= k} return self.parent()(d, check=False) def truncate(self, n): @@ -1078,9 +1077,7 @@ def is_unit(self): return self[0].is_unit() -class Polynomial_generic_field(Polynomial_singular_repr, - Polynomial_generic_domain, - EuclideanDomainElement): +class Polynomial_generic_field(Polynomial_singular_repr, Polynomial_generic_domain, EuclideanDomainElement): @coerce_binop def quo_rem(self, other): @@ -1108,8 +1105,8 @@ def quo_rem(self, other): R = A Q = P.zero() while R.degree() >= B.degree(): - aaa = R.leading_coefficient()/B.leading_coefficient() - diff_deg = R.degree()-B.degree() + aaa = R.leading_coefficient() / B.leading_coefficient() + diff_deg = R.degree() - B.degree() Q += P(aaa).shift(diff_deg) # We know that S*B exactly cancels the leading coefficient of R. # Thus, we skip the computation of this leading coefficient. @@ -1117,7 +1114,7 @@ def quo_rem(self, other): # inexact fields, the leading coefficient might not end up # exactly equal to zero; and for AA/QQbar, verifying that # the coefficient is exactly zero triggers exact computation. - R = R[:R.degree()] - (aaa*B[:B.degree()]).shift(diff_deg) + R = R[: R.degree()] - (aaa * B[: B.degree()]).shift(diff_deg) return (Q, R) @@ -1132,6 +1129,7 @@ class Polynomial_generic_sparse_field(Polynomial_generic_sparse, Polynomial_gene sage: loads(f.dumps()) == f True """ + def __init__(self, parent, x=None, check=True, is_gen=False, construct=False): Polynomial_generic_sparse.__init__(self, parent, x, check, is_gen) @@ -1145,6 +1143,7 @@ def __init__(self, parent, x=None, check=True, is_gen=False, construct=False): # Over discrete valuation rings and fields ########################################## + class Polynomial_generic_cdv(Polynomial_generic_domain): """ A generic class for polynomials over complete discrete @@ -1154,6 +1153,7 @@ class Polynomial_generic_cdv(Polynomial_generic_domain): - Xavier Caruso (2013-03) """ + def newton_slopes(self, repetition=True): """ Return a list of the Newton slopes of this polynomial. @@ -1221,8 +1221,9 @@ def newton_polygon(self): """ d = self.degree() from sage.geometry.newton_polygon import NewtonPolygon - polygon = NewtonPolygon([(x, self[x].valuation()) for x in range(d+1)]) - polygon_prec = NewtonPolygon([ (x, self[x].precision_absolute()) for x in range(d+1) ]) + + polygon = NewtonPolygon([(x, self[x].valuation()) for x in range(d + 1)]) + polygon_prec = NewtonPolygon([(x, self[x].precision_absolute()) for x in range(d + 1)]) vertices = polygon.vertices(copy=False) vertices_prec = polygon_prec.vertices(copy=False) if len(vertices_prec) > 0: @@ -1231,7 +1232,7 @@ def newton_polygon(self): elif vertices[-1][0] < vertices_prec[-1][0]: raise PrecisionError("last term with non-infinite valuation must have determined valuation") else: - for (x, y) in vertices: + for x, y in vertices: if polygon_prec(x) <= y: raise PrecisionError("The coefficient of %s^%s has not enough precision" % (self.parent().variable_name(), x)) return polygon @@ -1327,7 +1328,7 @@ def _factor_of_degree(self, deg): Precision is not optimal, and can be improved. """ coeffs = self.list() - a = coeffs[:deg+1] + a = coeffs[: deg + 1] # The leading coefficient need to be known at finite precision # in order to ensure that the while loop below terminates if a[deg].precision_absolute() is Infinity: @@ -1415,7 +1416,7 @@ def factor_of_slope(self, slope=None): div = self._factor_of_degree(deg_last) if deg_first > 0: div2 = div._factor_of_degree(deg_first) - div,_ = div.quo_rem(div2) + div, _ = div.quo_rem(div2) return div.monic() def slope_factorization(self): @@ -1461,16 +1462,16 @@ def slope_factorization(self): P = ~unit * self deg_first = vertices[0][0] - factors = [ ] + factors = [] if deg_first > 0: P >>= deg_first factors.append((self._parent.gen(), deg_first)) if len(vertices) > 2: - for i in range(1, len(vertices)-1): + for i in range(1, len(vertices) - 1): deg = vertices[i][0] - div = P._factor_of_degree(deg-deg_first) - factors.append((div,1)) - P,_ = P.quo_rem(div) + div = P._factor_of_degree(deg - deg_first) + factors.append((div, 1)) + P, _ = P.quo_rem(div) deg_first = deg if len(vertices) > 1: factors.append((P, 1)) @@ -1511,15 +1512,16 @@ def _roots(self, secure, minval, hint): (1 + O(2^10), 2)] """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + K = self.base_ring() Pk = PolynomialRing(K.residue_field(), names='xbar') x = self.parent().gen() # Trivial cases if self.degree() == 0: - return [ ] + return [] if self.degree() == 1: - return [ (-self[0]/self[1], 1) ] + return [(-self[0] / self[1], 1)] # We consider the case where zero is a (possibly multiple) root i = 0 @@ -1528,21 +1530,21 @@ def _roots(self, secure, minval, hint): if secure and i > 1: raise PrecisionError("not enough precision to determine the number of roots") if i == 0: - roots = [ ] + roots = [] P = self else: vali = self[i].valuation() - prec = min((self[j].precision_absolute()-vali) / (i-j) for j in range(i)) + prec = min((self[j].precision_absolute() - vali) / (i - j) for j in range(i)) if prec is not Infinity: prec = prec.ceil() - roots = [ (K(0,prec), i) ] - P = self // self[:i+1] # we do not shift because we need to track precision here + roots = [(K(0, prec), i)] + P = self // self[: i + 1] # we do not shift because we need to track precision here # We use Newton polygon and slope factorisation to find roots vertices = P.newton_polygon().vertices(copy=False) deg = 0 for i in range(1, len(vertices)): - deg_left, val_left = vertices[i-1] + deg_left, val_left = vertices[i - 1] deg_right, val_right = vertices[i] slope = (val_right - val_left) / (deg_left - deg_right) if slope not in ZZ or slope < minval: @@ -1562,13 +1564,13 @@ def _roots(self, secure, minval, hint): deg = deg_right val = F[0].valuation() if hint is None or slope != minval: - Fbar = Pk([ F[j] >> (val - j*slope) for j in range(F.degree()+1) ]) - rootsbar = [ r for (r, _) in Fbar.roots() ] + Fbar = Pk([F[j] >> (val - j * slope) for j in range(F.degree() + 1)]) + rootsbar = [r for (r, _) in Fbar.roots()] if not rootsbar: continue rbar = rootsbar.pop() shift = K(rbar).lift_to_precision() << slope # probably we should choose a better lift - roots += [(r+shift, m) for (r, m) in F(x+shift)._roots(secure, slope, [r-rbar for r in rootsbar])] # recursive call + roots += [(r + shift, m) for (r, m) in F(x + shift)._roots(secure, slope, [r - rbar for r in rootsbar])] # recursive call return roots @@ -1616,5 +1618,5 @@ class Polynomial_generic_sparse_cdvf(Polynomial_generic_sparse_cdv, Polynomial_g pass else: from sage.misc.persist import register_unpickle_override - register_unpickle_override('sage.rings.polynomial.polynomial_element_generic', - 'Polynomial_rational_dense', Polynomial_rational_flint) + + register_unpickle_override('sage.rings.polynomial.polynomial_element_generic', 'Polynomial_rational_dense', Polynomial_rational_flint) diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring.py b/src/sage/rings/polynomial/polynomial_quotient_ring.py index 223664d135f..a1302c04247 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring.py @@ -25,7 +25,7 @@ -0.2500000000000000*y^2 + 0.5000000000000000*y """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2005, 2006 William Stein # 2016 Julian Rüth # @@ -34,7 +34,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** import sage.rings.rational_field @@ -170,6 +170,7 @@ class PolynomialQuotientRingFactory(UniqueFactory): sage: R.quotient_by_principal_ideal(f) Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^2 - 1 """ + def create_key(self, ring, polynomial, names=None): r""" Return a unique description of the quotient ring specified by the @@ -240,10 +241,11 @@ def create_object(self, version, key): R = ring.base_ring() from sage.categories.fields import Fields from sage.categories.integral_domains import IntegralDomains + if R in IntegralDomains(): try: is_irreducible = polynomial.is_irreducible() - except NotImplementedError: # is_irreducible sometimes not implemented + except NotImplementedError: # is_irreducible sometimes not implemented pass else: if is_irreducible: @@ -322,6 +324,7 @@ class PolynomialQuotientRing_generic(QuotientRing_generic): sage: TestSuite(Q).run() # needs sage.rings.number_field sage: TestSuite(a).run() """ + Element = PolynomialQuotientRingElement def __init__(self, ring, polynomial, name=None, category=None): @@ -455,10 +458,10 @@ def _element_constructor_(self, x): """ if not isinstance(x, str): try: - return self.element_class(self, self.__ring(x) , check=True) + return self.element_class(self, self.__ring(x), check=True) except TypeError: - xlift = getattr(x,'lift',None) - if xlift is not None: # duck typing for quotient ring elements + xlift = getattr(x, 'lift', None) + if xlift is not None: # duck typing for quotient ring elements return self.element_class(self, self.__ring(x.lift()), check=False) # The problem with the string representation is that it could in principle # mix elements of self with elements of self's cover ring. We therefore @@ -466,7 +469,8 @@ def _element_constructor_(self, x): # Interpretation in self has priority over interpretation in self.__ring try: from sage.misc.sage_eval import sage_eval - out = sage_eval(x, GenDictWithBasering(self,self.gens_dict())) + + out = sage_eval(x, GenDictWithBasering(self, self.gens_dict())) if out.parent() is not self: return self(out) return out @@ -518,9 +522,10 @@ def _coerce_map_from_(self, R): try: if not self.__polynomial.divides(R.modulus()): return False - except (ZeroDivisionError,ArithmeticError): + except (ZeroDivisionError, ArithmeticError): return False from sage.categories.homset import Hom + parent = Hom(R, self, category=self.category()._meet_(R.category())) return parent.__make_element_class__(PolynomialQuotientRing_coercion)(R, self, category=parent.homset_category()) @@ -619,8 +624,7 @@ def __eq__(self, other): """ if not isinstance(other, PolynomialQuotientRing_generic): return False - return (self.polynomial_ring() == other.polynomial_ring() and - self.modulus() == other.modulus()) + return self.polynomial_ring() == other.polynomial_ring() and self.modulus() == other.modulus() def __ne__(self, other): """ @@ -690,15 +694,14 @@ def _singular_init_(self, S=None): from sage.interfaces.singular import singular as S Rpoly = S(self.polynomial_ring()) Rpoly.set_ring() - modulus = S(self.modulus()) # should live in Rpoly + modulus = S(self.modulus()) # should live in Rpoly Rtmp = S(self.polynomial_ring().change_var(self.variable_name())) Rtmp.set_ring() - self.__singular = S("ideal(fetch(%s,%s))" % (Rpoly.name(),modulus.name()),"qring") + self.__singular = S("ideal(fetch(%s,%s))" % (Rpoly.name(), modulus.name()), "qring") return self.__singular def _repr_(self): - return "Univariate Quotient Polynomial Ring in %s over %s with modulus %s" % ( - self.variable_name(), self.base_ring(), self.modulus()) + return "Univariate Quotient Polynomial Ring in %s over %s with modulus %s" % (self.variable_name(), self.base_ring(), self.modulus()) def construction(self): """ @@ -722,11 +725,12 @@ def construction(self): -- Simon King (2010-05) """ from sage.categories.pushout import QuotientFunctor + Cover = self.__ring kwds = {} if Cover in CommutativeRings(): kwds['domain'] = kwds['codomain'] = CommutativeRings() - return QuotientFunctor([self.modulus()]*Cover, self.variable_names(), **kwds), Cover + return QuotientFunctor([self.modulus()] * Cover, self.variable_names(), **kwds), Cover @cached_method def base_ring(self): @@ -798,12 +802,14 @@ def cardinality(self): """ if not self.is_finite(): from sage.rings.infinity import Infinity + return Infinity f = self.modulus() # Two cases where the quotient is finite (see is_finite()) # 1) R[x]/(1) if f.degree() == 0: from sage.rings.integer_ring import ZZ + return ZZ.one() # 2) F[x]/(f) where F is finite return self.base_ring().cardinality() ** f.degree() @@ -1007,6 +1013,7 @@ def is_field(self, proof=True): if ret: from sage.categories.fields import Fields + self._refine_category_(Fields()) return ret @@ -1066,6 +1073,7 @@ def is_integral_domain(self, proof=True): that the modulus is irreducible. """ from sage.categories.integral_domains import IntegralDomains + if self.category().is_subcategory(IntegralDomains()): return True ret = self.base_ring().is_integral_domain(proof) @@ -1079,6 +1087,7 @@ def is_integral_domain(self, proof=True): ret = False else: from sage.categories.gcd_domains import GcdDomains + if self.base_ring() in GcdDomains(): # if the base ring is a GCD domain, the conditions are sufficient ret = True @@ -1167,6 +1176,7 @@ def number_field(self): if not isinstance(self.base_ring(), sage.rings.rational_field.RationalField): raise NotImplementedError("Computation of number field only implemented for quotients of the polynomial ring over the rational field.") from sage.rings.number_field.number_field import NumberField + return NumberField(self.modulus(), self.variable_name()) def polynomial_ring(self): @@ -1213,8 +1223,7 @@ def random_element(self, degree=None, *args, **kwds): if degree is None: degree = self.degree() - 1 - return self(self.polynomial_ring().random_element( - degree=degree, *args, **kwds)) + return self(self.polynomial_ring().random_element(degree=degree, *args, **kwds)) @cached_method def _S_decomposition(self, S): @@ -1258,16 +1267,16 @@ def _S_decomposition(self, S): 2 """ from sage.rings.number_field.number_field_base import NumberField + K = self.base_ring() if not isinstance(K, NumberField) or not self.__polynomial.is_squarefree(): raise NotImplementedError from sage.rings.ideal import Ideal_generic + for p in S: # second check due to inconsistency over QQ - see # 7596 - if not (isinstance(p, Ideal_generic) - and (p.ring() is K or p.ring() is K.ring_of_integers()) - and p.is_prime()): + if not (isinstance(p, Ideal_generic) and (p.ring() is K or p.ring() is K.ring_of_integers()) and p.is_prime()): raise TypeError("S must be a list of prime ideals of the base field.") F = self.__polynomial.factor() @@ -1290,8 +1299,7 @@ def _S_decomposition(self, S): for p in S: # next line looks a bit silly, # due to inconsistency over QQ - see # 7596 - abs_gens = [D_abs.structure()[1](g) - for g in D.ideal(p.gens()).gens()] + abs_gens = [D_abs.structure()[1](g) for g in D.ideal(p.gens()).gens()] S_abs += [pp for pp, _ in D_abs.ideal(abs_gens).factor()] iso_classes.append((D_abs, S_abs)) isos.append((D_abs.embeddings(D_abs)[0], j)) @@ -1461,7 +1469,7 @@ def S_class_group(self, S, proof=True): ideal_gens = [] for ideal_gen in clgp_gen.gens(): rel_ideal_gen = back_to_rel(phi(ideal_gen)) - prod_ideal_gen = [0]*i + [rel_ideal_gen.lift()] + [0]*(n - i - 1) + prod_ideal_gen = [0] * i + [rel_ideal_gen.lift()] + [0] * (n - i - 1) poly_ideal_gen = self(crt(prod_ideal_gen, moduli)) ideal_gens.append(poly_ideal_gen) clgp_gens.append((tuple(ideal_gens), gen_order)) @@ -1666,7 +1674,7 @@ def S_units(self, S, proof=True): for unit in component_S_units[isos[i][1]]: mul_order = unit.multiplicative_order() rel_unit = back_to_rel(phi(unit)) - prod_unit = [1]*i + [rel_unit.lift()] + [1]*(n - i - 1) + prod_unit = [1] * i + [rel_unit.lift()] + [1] * (n - i - 1) poly_unit = self(crt(prod_unit, moduli)) units.append((poly_unit, mul_order)) @@ -1802,7 +1810,7 @@ def selmer_generators(self, S, m, proof=True): for gen in component_selmer_groups[isos[i][1]]: rel_gen = back_to_rel(phi(gen)) - prod_gen = [1]*i + [rel_gen.lift()] + [1]*(n - i - 1) + prod_gen = [1] * i + [rel_gen.lift()] + [1] * (n - i - 1) poly_gen = self(crt(prod_gen, moduli)) gens.append(poly_gen) @@ -1835,7 +1843,7 @@ def _factor_multivariate_polynomial(self, f, proof=True): g = f.map_coefficients(to_isomorphic_ring) F = g.factor() unit = f.parent(from_isomorphic_ring(F.unit().constant_coefficient())) - return Factorization([(factor.map_coefficients(from_isomorphic_ring), e) for factor,e in F], unit=unit) + return Factorization([(factor.map_coefficients(from_isomorphic_ring), e) for factor, e in F], unit=unit) def _factor_univariate_polynomial(self, f): r""" @@ -1870,12 +1878,12 @@ def _factor_univariate_polynomial(self, f): if f.degree() == 0: return Factorization(unit=unit) if f.degree() == 1: - return Factorization([(f,1)], unit=unit) + return Factorization([(f, 1)], unit=unit) from_isomorphic_ring, to_isomorphic_ring, isomorphic_ring = self._isomorphic_ring() g = f.map_coefficients(to_isomorphic_ring) F = g.factor() unit *= g.parent()(F.unit()).map_coefficients(from_isomorphic_ring) - return Factorization([(factor.map_coefficients(from_isomorphic_ring), e) for factor,e in F], unit=unit) + return Factorization([(factor.map_coefficients(from_isomorphic_ring), e) for factor, e in F], unit=unit) @cached_method def _isomorphic_ring(self): @@ -1943,16 +1951,12 @@ def _isomorphic_ring(self): self._refine_category_(isomorphic_quotient.category()) homspace = Hom(isomorphic_quotient, self) - from_isomorphic_quotient = homspace.__make_element_class__(SetMorphism)(homspace, - lambda f: f.lift().map_coefficients(isomorphic_base_to_base)(self.gen())) + from_isomorphic_quotient = homspace.__make_element_class__(SetMorphism)(homspace, lambda f: f.lift().map_coefficients(isomorphic_base_to_base)(self.gen())) homspace = Hom(self, isomorphic_quotient) - to_isomorphic_quotient = homspace.__make_element_class__(SetMorphism)(homspace, - lambda f: f.lift().map_coefficients(base_to_isomorphic_base)(isomorphic_quotient.gen())) + to_isomorphic_quotient = homspace.__make_element_class__(SetMorphism)(homspace, lambda f: f.lift().map_coefficients(base_to_isomorphic_base)(isomorphic_quotient.gen())) - return (from_isomorphic_quotient * isomorphic_ring_to_isomorphic_quotient, - isomorphic_quotient_to_isomorphic_ring * to_isomorphic_quotient, - isomorphic_ring) + return (from_isomorphic_quotient * isomorphic_ring_to_isomorphic_quotient, isomorphic_quotient_to_isomorphic_ring * to_isomorphic_quotient, isomorphic_ring) if self.modulus().degree() == 1: # this quotient is a trivial extension of the base ring, we can just @@ -1966,6 +1970,7 @@ def _isomorphic_ring(self): # So we just check some important special cases here (note that # integral domains is already handled elsewhere.) from sage.categories.fields import Fields + if isomorphic_ring in Fields(): self._refine_category_(Fields()) @@ -1980,6 +1985,7 @@ def _isomorphic_ring(self): # the underlying prime field N = self.cardinality() from sage.rings.finite_rings.finite_field_constructor import GF + isomorphic_ring = GF(N) # the map to GF(N) maps our generator to a root of our modulus in the isomorphic_ring @@ -1989,29 +1995,28 @@ def _isomorphic_ring(self): gen = modulus.any_root(assume_squarefree=True, degree=1, assume_equal_deg=True) homspace = Hom(self, isomorphic_ring) - to_isomorphic_ring = homspace.__make_element_class__(SetMorphism)(homspace, - lambda f: f.lift().map_coefficients(base_to_isomorphic_ring)(gen)) + to_isomorphic_ring = homspace.__make_element_class__(SetMorphism)(homspace, lambda f: f.lift().map_coefficients(base_to_isomorphic_ring)(gen)) # For the map from GF(N) we need to figure out where the primitive # element of GF(N) goes. We write down a basis of self over GF(p), # send it to isomorphic_ring, and solve the linear equation which # writes the primitive element of GF(N) as a linear combination of # that basis. - basis = [self.gen()**i*self.base_ring().gen()**j - for i in range(self.degree()) - for j in range(self.base_ring().degree())] - assert (len(basis) == isomorphic_ring.degree()) + basis = [self.gen() ** i * self.base_ring().gen() ** j for i in range(self.degree()) for j in range(self.base_ring().degree())] + assert len(basis) == isomorphic_ring.degree() from sage.matrix.constructor import matrix + A = matrix([to_isomorphic_ring(b)._vector_() for b in basis]) - assert (A.is_square()) + assert A.is_square() # solve x*A = (0,1,0,…,0) x = A.solve_left(A.column_space().basis()[1]) - primitive_element = sum(c*b for c,b in zip(x.list(), basis)) + primitive_element = sum(c * b for c, b in zip(x.list(), basis)) from_isomorphic_ring = isomorphic_ring.hom([primitive_element], check=False) return from_isomorphic_ring, to_isomorphic_ring, isomorphic_ring from sage.categories.number_fields import NumberFields + if self.base_ring() in NumberFields(): try: isomorphic_ring = self.base_ring().extension(self.modulus(), names=self.variable_names()) @@ -2055,6 +2060,7 @@ def _test_isomorphic_ring(self, **options): from sage.categories.fields import Fields from sage.categories.integral_domains import IntegralDomains + if ring.category().is_subcategory(IntegralDomains()): category = IntegralDomains() if ring.category().is_subcategory(Fields()): @@ -2102,6 +2108,7 @@ class PolynomialQuotientRing_coercion(DefaultConvertMap_unique): sage: f == g True """ + def is_injective(self): r""" Return whether this coercion is injective. @@ -2118,11 +2125,10 @@ def is_injective(self): sage: f.is_injective() True """ - if (self.domain().modulus().change_ring(self.codomain().base_ring()) == self.codomain().modulus() - and self.domain().modulus().leading_coefficient().is_unit()): + if self.domain().modulus().change_ring(self.codomain().base_ring()) == self.codomain().modulus() and self.domain().modulus().leading_coefficient().is_unit(): if self.codomain().base_ring().coerce_map_from(self.domain().base_ring()).is_injective(): return True - return self.domain().modulus().degree() == 0 # domain and codomain are the zero ring + return self.domain().modulus().degree() == 0 # domain and codomain are the zero ring return super().is_injective() def is_surjective(self): @@ -2191,6 +2197,7 @@ class PolynomialQuotientRing_domain(PolynomialQuotientRing_generic, CommutativeR sage: loads(xbar.dumps()) == xbar True """ + def __init__(self, ring, polynomial, name=None, category=None): r""" Initialize ``self``. @@ -2324,6 +2331,7 @@ class PolynomialQuotientRing_field(PolynomialQuotientRing_domain, Field): sage: loads(xbar.dumps()) == xbar True """ + def __init__(self, ring, polynomial, name=None, category=None): r""" Initialize ``self``. @@ -2406,6 +2414,7 @@ def complex_embeddings(self, prec=53): 0.92103906697304693634806949137 + 3.0755331188457794473265418086*I] """ from sage.rings.complex_mpfr import ComplexField + CC = ComplexField(prec) v = self.modulus().roots(multiplicities=False, ring=CC) return [self.hom([a], check=False) for a in v] diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py index bb8a29b2d3d..90ebf95df42 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py @@ -75,7 +75,7 @@ - William Stein """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2005, 2007 William Stein # # This program is free software: you can redistribute it and/or modify @@ -83,7 +83,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.structure.element import CommutativeRingElement from sage.structure.richcmp import richcmp @@ -105,6 +105,7 @@ class PolynomialQuotientRingElement(polynomial_singular_interface.Polynomial_sin sage: (singular(xi)*singular(xi)).NF('std(0)') # needs sage.libs.singular -1 """ + def __init__(self, parent, polynomial, check=True): """ Create an element of the quotient of a polynomial ring. @@ -145,9 +146,9 @@ def __init__(self, parent, polynomial, check=True): Q = P(0) X = P.gen() while R.degree() >= B.degree(): - S = P(R.leading_coefficient()/B.leading_coefficient()) * X**(R.degree()-B.degree()) + S = P(R.leading_coefficient() / B.leading_coefficient()) * X ** (R.degree() - B.degree()) Q = Q + S - R = R - S*B + R = R - S * B polynomial = R self._polynomial = polynomial @@ -259,8 +260,7 @@ def _sub_(self, right): sage: int(1) - a -a + 1 """ - return self.__class__(self.parent(), - self._polynomial - right._polynomial, check=False) + return self.__class__(self.parent(), self._polynomial - right._polynomial, check=False) def _add_(self, right): """ @@ -275,8 +275,7 @@ def _add_(self, right): sage: int(1) + a a + 1 """ - return self.__class__(self.parent(), - self._polynomial + right._polynomial, check=False) + return self.__class__(self.parent(), self._polynomial + right._polynomial, check=False) def _div_(self, right): """ @@ -505,35 +504,35 @@ def field_extension(self, names): - William Stein (2006-08-06) """ - #TODO: is the return order backwards from the magma convention? - -## We do another example over $\ZZ$:: -## -## sage: R. = ZZ['x'] -## sage: S. = R.quo(x^3 - 2) -## sage: F., g, h = a.field_extension() -## sage: h(b^2 + 3) -## a^2 + 3 -## sage: g(x^2 + 2) -## a^2 + 2 -## -## Note that the homomorphism is not defined on the entire -## ''domain''. (Allowing creation of such functions may be -## disallowed in a future version of Sage.):: <----- INDEED! -## -## sage: h(1/3) -## Traceback (most recent call last): -## ... -## TypeError: Unable to coerce rational (=1/3) to an Integer. -## -## Note that the parent ring must be an integral domain:: -## -## sage: R. = GF(25,'b')['x'] -## sage: S. = R.quo(x^3 - 2) -## sage: F, g, h = a.field_extension() -## Traceback (most recent call last): -## ... -## ValueError: polynomial must be irreducible + # TODO: is the return order backwards from the magma convention? + + ## We do another example over $\ZZ$:: + ## + ## sage: R. = ZZ['x'] + ## sage: S. = R.quo(x^3 - 2) + ## sage: F., g, h = a.field_extension() + ## sage: h(b^2 + 3) + ## a^2 + 3 + ## sage: g(x^2 + 2) + ## a^2 + 2 + ## + ## Note that the homomorphism is not defined on the entire + ## ''domain''. (Allowing creation of such functions may be + ## disallowed in a future version of Sage.):: <----- INDEED! + ## + ## sage: h(1/3) + ## Traceback (most recent call last): + ## ... + ## TypeError: Unable to coerce rational (=1/3) to an Integer. + ## + ## Note that the parent ring must be an integral domain:: + ## + ## sage: R. = GF(25,'b')['x'] + ## sage: S. = R.quo(x^3 - 2) + ## sage: F, g, h = a.field_extension() + ## Traceback (most recent call last): + ## ... + ## ValueError: polynomial must be irreducible R = self.parent() x = R.gen() @@ -544,6 +543,7 @@ def field_extension(self, names): f = R.hom([alpha], F, check=False) from sage.rings.number_field.number_field_rel import NumberField_relative + if isinstance(F, NumberField_relative): base_map = F.base_field().hom([R.base_ring().gen()]) @@ -626,7 +626,7 @@ def list(self, copy=True): v = self._polynomial.list(copy=False) R = self.parent() n = R.degree() - return v + [R.base_ring()(0)]*(n - len(v)) + return v + [R.base_ring()(0)] * (n - len(v)) def matrix(self): """ @@ -654,10 +654,11 @@ def matrix(self): a = R(1) d = R.degree() for _ in range(d): - v += (a*self).list() + v += (a * self).list() a *= x S = R.base_ring() import sage.matrix.matrix_space + M = sage.matrix.matrix_space.MatrixSpace(S, d) self.__matrix = M(v) return self.__matrix diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 4e05e2bda9c..597246d7782 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -185,8 +185,7 @@ class PolynomialRing_generic(Ring): Univariate polynomial ring over a ring. """ - def __init__(self, base_ring, name=None, sparse=False, implementation=None, - element_class=None, category=None): + def __init__(self, base_ring, name=None, sparse=False, implementation=None, element_class=None, category=None): """ EXAMPLES:: @@ -259,11 +258,13 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, from sage.rings.polynomial.polynomial_element_generic import ( Polynomial_generic_sparse, ) + self._polynomial_class = Polynomial_generic_sparse else: from sage.rings.polynomial.polynomial_element import ( Polynomial_generic_dense, ) + self._polynomial_class = Polynomial_generic_dense self.Element = self._polynomial_class self.__cyclopoly_cache = {} @@ -272,6 +273,7 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, from sage.rings.semirings.non_negative_integer_semiring import ( NonNegativeIntegerSemiring, ) + self._indices = NonNegativeIntegerSemiring() self._populate_coercion_lists_(convert_method_name='_polynomial_') @@ -279,11 +281,11 @@ def __reduce__(self): from sage.rings.polynomial.polynomial_ring_constructor import ( unpickle_PolynomialRing, ) + args = (self.base_ring(), self.variable_names(), None, self.is_sparse()) return unpickle_PolynomialRing, args - def _element_constructor_(self, x=None, check=True, is_gen=False, - construct=False, **kwds): + def _element_constructor_(self, x=None, check=True, is_gen=False, construct=False, **kwds): r""" Convert ``x`` into this univariate polynomial ring, possibly non-canonically. @@ -391,8 +393,7 @@ def _element_constructor_(self, x=None, check=True, is_gen=False, if isinstance(x, (list, tuple)): return C(self, x, check=check, is_gen=False, construct=construct) if isinstance(x, range): - return C(self, list(x), check=check, is_gen=False, - construct=construct) + return C(self, list(x), check=check, is_gen=False, construct=construct) if isinstance(x, Element): P = x.parent() if P is self: @@ -406,11 +407,9 @@ def _element_constructor_(self, x=None, check=True, is_gen=False, # zeroes are not stripped, because O(5)==0, but still it must # not be forgotten. It should be the job of the __init__ method # to decide whether to strip or not to strip. - return C(self, [x], check=False, is_gen=False, - construct=construct) + return C(self, [x], check=False, is_gen=False, construct=construct) if P == self.base_ring(): - return C(self, [x], check=True, is_gen=False, - construct=construct) + return C(self, [x], check=True, is_gen=False, construct=construct) if isinstance(x, sage.interfaces.abc.SingularElement) and self._has_singular: self._singular_().set_ring() try: @@ -420,6 +419,7 @@ def _element_constructor_(self, x=None, check=True, is_gen=False, elif isinstance(x, str): try: from sage.misc.parser import LookupNameMaker, Parser + R = self.base_ring() p = Parser(Integer, R, LookupNameMaker({self.variable_name(): self.gen()}, R)) return self(p.parse(x)) @@ -493,8 +493,7 @@ def _implementation_names(cls, implementation, base_ring, sparse=False): """ names = cls._implementation_names_impl(implementation, base_ring, sparse) if names is NotImplemented: - raise ValueError("unknown implementation %r for %s polynomial rings over %r" % - (implementation, "sparse" if sparse else "dense", base_ring)) + raise ValueError("unknown implementation %r for %s polynomial rings over %r" % (implementation, "sparse" if sparse else "dense", base_ring)) assert isinstance(names, list) assert implementation in names return names @@ -562,13 +561,16 @@ def some_elements(self): # Doing things this way is a little robust against rings where # 2 might not convert in one = R.one() - return [self.gen(), - self.zero(), self(one), self(R.an_element()), # elements of the base ring - self([one,2*one,one]), # a square - self([0,0,0,one]), # a power but not a square - self([-one,0,one]), # a reducible element - self([one,0,one]), # an irreducible element - self([2*one,0,2*one]), # an element with non-trivial content + return [ + self.gen(), + self.zero(), + self(one), + self(R.an_element()), # elements of the base ring + self([one, 2 * one, one]), # a square + self([0, 0, 0, one]), # a power but not a square + self([-one, 0, one]), # a reducible element + self([one, 0, one]), # an irreducible element + self([2 * one, 0, 2 * one]), # an element with non-trivial content ] def monomials_of_degree(self, degree): @@ -587,7 +589,7 @@ def monomials_of_degree(self, degree): sage: mons [x^2] """ - return [self.gen()**degree] + return [self.gen() ** degree] @cached_method def flattening_morphism(self): @@ -606,9 +608,11 @@ def flattening_morphism(self): Identity endomorphism of Univariate Polynomial Ring in x over Rational Field """ from .multi_polynomial_ring import MPolynomialRing_base + base = self.base_ring() if isinstance(base, (PolynomialRing_generic, MPolynomialRing_base)): from .flatten import FlatteningMorphism + return FlatteningMorphism(self) return IdentityMorphism(self) @@ -658,11 +662,11 @@ def completion(self, p=None, prec=20, extras=None): if p is None or str(p) == self._names[0]: if prec == float('inf'): from sage.rings.lazy_series_ring import LazyPowerSeriesRing - return LazyPowerSeriesRing(self.base_ring(), names=(self._names[0],), - sparse=self.is_sparse()) + + return LazyPowerSeriesRing(self.base_ring(), names=(self._names[0],), sparse=self.is_sparse()) from sage.rings.power_series_ring import PowerSeriesRing - return PowerSeriesRing(self.base_ring(), name=self._names[0], - default_prec=prec, sparse=self.is_sparse()) + + return PowerSeriesRing(self.base_ring(), name=self._names[0], default_prec=prec, sparse=self.is_sparse()) raise NotImplementedError("cannot complete %s with respect to %s" % (self, p)) @@ -830,10 +834,12 @@ def _coerce_map_from_(self, P): from sage.rings.polynomial.polynomial_ring_homomorphism import ( PolynomialRingHomomorphism_from_base, ) + return PolynomialRingHomomorphism_from_base(RingHomset(P, self), f) # Last, we consider multivariate polynomial rings: from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base + if isinstance(P, MPolynomialRing_base) and self.variable_name() in P.variable_names(): P_ = P.remove_var(self.variable_name()) return self.base_ring() != P_ and self.base_ring().has_coerce_map_from(P_) @@ -934,8 +940,7 @@ def _sage_input_(self, sib, coerced): base = sib(self.base_ring()) sie = base[self.variable_name()] gens_syntax = sib.empty_subscript(base) - return sib.parent_with_gens(self, sie, self.variable_names(), 'R', - gens_syntax=gens_syntax) + return sib.parent_with_gens(self, sie, self.variable_names(), 'R', gens_syntax=gens_syntax) def _macaulay2_init_(self, macaulay2=None): """ @@ -959,6 +964,7 @@ def _macaulay2_init_(self, macaulay2=None): """ if macaulay2 is None: from sage.interfaces.macaulay2 import macaulay2 as m2_default + macaulay2 = m2_default return macaulay2._macaulay2_input_ring(self.base_ring(), self.gens()) @@ -989,7 +995,7 @@ def __hash__(self): return self._cached_hash except AttributeError: pass - h = self._cached_hash = hash((self.base_ring(),self.variable_name())) + h = self._cached_hash = hash((self.base_ring(), self.variable_name())) return h def _repr_(self): @@ -997,8 +1003,7 @@ def _repr_(self): return self._cached_repr except AttributeError: pass - s = "Univariate Polynomial Ring in %s over %s" % ( - self.variable_name(), self.base_ring()) + s = "Univariate Polynomial Ring in %s over %s" % (self.variable_name(), self.base_ring()) if self.is_sparse(): s = "Sparse " + s self._cached_repr = s @@ -1130,7 +1135,7 @@ def _mpoly_base_ring(self, variables=None): if var not in variables: return self try: - return self.base_ring()._mpoly_base_ring(variables[:variables.index(var)]) + return self.base_ring()._mpoly_base_ring(variables[: variables.index(var)]) except AttributeError: return self.base_ring() @@ -1188,6 +1193,7 @@ def cyclotomic_polynomial(self, n): return self.gen() - 1 else: from .cyclotomic import cyclotomic_coeffs + return self(cyclotomic_coeffs(n), check=True) @cached_method @@ -1213,7 +1219,7 @@ def gen(self, n=0): """ if n != 0: raise IndexError("generator n not defined") - return self.element_class(self, [0,1], is_gen=True) + return self.element_class(self, [0, 1], is_gen=True) def gens_dict(self) -> dict: """ @@ -1512,7 +1518,7 @@ def _monics_degree(self, of_degree): Refer to monics() for full documentation. """ base = self.base_ring() - for coeffs in sage.misc.mrange.xmrange_iter([[base.one()]]+[base]*of_degree): + for coeffs in sage.misc.mrange.xmrange_iter([[base.one()]] + [base] * of_degree): # Each iteration returns a *new* list! # safe to mutate the return coeffs.reverse() @@ -1533,7 +1539,7 @@ def _polys_degree(self, of_degree): base0 = base.zero() for leading_coeff in base: if leading_coeff != base0: - for lt1 in sage.misc.mrange.xmrange_iter([base]*(of_degree)): + for lt1 in sage.misc.mrange.xmrange_iter([base] * (of_degree)): # Each iteration returns a *new* list! # safe to mutate the return coeffs = [leading_coeff] + lt1 @@ -1545,7 +1551,7 @@ def _polys_max(self, max_degree): Refer to polynomials() for full documentation. """ base = self.base_ring() - for coeffs in sage.misc.mrange.xmrange_iter([base]*(max_degree+1)): + for coeffs in sage.misc.mrange.xmrange_iter([base] * (max_degree + 1)): # Each iteration returns a *new* list! # safe to mutate the return coeffs.reverse() @@ -1577,6 +1583,7 @@ def _Karatsuba_threshold(self): if isinstance(base_ring, MatrixSpace): return 0 from sage.rings.fraction_field import FractionField_generic + if isinstance(base_ring, FractionField_generic): return 1 << 60 # Generic default value @@ -1678,9 +1685,9 @@ def polynomials(self, of_degree=None, max_degree=None): if self.base_ring().order() is sage.rings.infinity.infinity: raise NotImplementedError if of_degree is not None and max_degree is None: - return self._polys_degree( of_degree ) + return self._polys_degree(of_degree) if max_degree is not None and of_degree is None: - return self._polys_max( max_degree ) + return self._polys_max(max_degree) raise ValueError("you should pass exactly one of of_degree and max_degree") def monics(self, of_degree=None, max_degree=None): @@ -1737,9 +1744,9 @@ def monics(self, of_degree=None, max_degree=None): if self.base_ring().order() is sage.rings.infinity.infinity: raise NotImplementedError if of_degree is not None and max_degree is None: - return self._monics_degree( of_degree ) + return self._monics_degree(of_degree) if max_degree is not None and of_degree is None: - return self._monics_max( max_degree ) + return self._monics_max(max_degree) raise ValueError("you should pass exactly one of of_degree and max_degree") @@ -1751,8 +1758,8 @@ class PolynomialRing_commutative(PolynomialRing_generic): """ Univariate polynomial ring over a commutative ring. """ - def __init__(self, base_ring, name=None, sparse=False, implementation=None, - element_class=None, category=None): + + def __init__(self, base_ring, name=None, sparse=False, implementation=None, element_class=None, category=None): if base_ring not in _CommutativeRings: raise TypeError("Base ring %s must be a commutative ring." % repr(base_ring)) # We trust that, if a category is given, that it is useful. @@ -1761,9 +1768,7 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, else: defaultcat = polynomial_default_category(base_ring.category(), 1) category = check_default_category(defaultcat, category) - PolynomialRing_generic.__init__(self, base_ring, name=name, - sparse=sparse, implementation=implementation, - element_class=element_class, category=category) + PolynomialRing_generic.__init__(self, base_ring, name=name, sparse=sparse, implementation=implementation, element_class=element_class, category=category) def quotient_by_principal_ideal(self, f, names=None, **kwds): """ @@ -1803,6 +1808,7 @@ def quotient_by_principal_ideal(self, f, names=None, **kwds): True """ from sage.rings.ideal import Ideal + I = Ideal(f) if I.is_zero(): return self @@ -1810,6 +1816,7 @@ def quotient_by_principal_ideal(self, f, names=None, **kwds): from sage.rings.polynomial.polynomial_quotient_ring import ( PolynomialQuotientRing, ) + return PolynomialQuotientRing(self, f, names, **kwds) def weyl_algebra(self): @@ -1825,6 +1832,7 @@ def weyl_algebra(self): True """ from sage.algebras.weyl_algebra import DifferentialWeylAlgebra + return DifferentialWeylAlgebra(self) def _roots_univariate_polynomial(self, p, ring=None, multiplicities=True, algorithm=None, degree_bound=None): @@ -1871,15 +1879,14 @@ def _roots_univariate_polynomial(self, p, ring=None, multiplicities=True, algori roots = p._roots_from_factorization(p.factor(), multiplicities) if degree_bound is not None: if multiplicities: - roots = [(r,m) for (r,m) in roots if r.degree() <= degree_bound] + roots = [(r, m) for (r, m) in roots if r.degree() <= degree_bound] else: roots = [r for r in roots if r.degree() <= degree_bound] return roots class PolynomialRing_integral_domain(PolynomialRing_commutative, PolynomialRing_singular_repr, CommutativeRing): - def __init__(self, base_ring, name='x', sparse=False, implementation=None, - element_class=None, category=None): + def __init__(self, base_ring, name='x', sparse=False, implementation=None, element_class=None, category=None): """ TESTS:: @@ -1919,9 +1926,7 @@ def __init__(self, base_ring, name='x', sparse=False, implementation=None, raise continue break - PolynomialRing_commutative.__init__(self, base_ring, name=name, - sparse=sparse, implementation=implementation, - element_class=element_class, category=category) + PolynomialRing_commutative.__init__(self, base_ring, name=name, sparse=sparse, implementation=implementation, element_class=element_class, category=category) self._has_singular = can_convert_to_singular(self) @cached_method(key=lambda self, d, q, sign, lead: (d, q, sign, tuple([x if isinstance(x, (tuple, list)) else (x, 0) for x in lead]) if isinstance(lead, (tuple, list)) else ((lead, 0)))) @@ -2035,6 +2040,7 @@ def weil_polynomials(self, d, q, sign=1, lead=1): if not (R is ZZ or R is QQ): raise ValueError("Weil polynomials have integer coefficients") from sage.rings.polynomial.weil.weil_polynomials import WeilPolynomials + return list(WeilPolynomials(d, q, sign, lead, polring=self)) @staticmethod @@ -2103,13 +2109,11 @@ def construction(self): # PolynomialRing. if 'NTL' in self._implementation_repr: implementation = 'NTL' - return categories.pushout.PolynomialFunctor(self.variable_name(), sparse=self.is_sparse(), - implementation=implementation), self.base_ring() + return categories.pushout.PolynomialFunctor(self.variable_name(), sparse=self.is_sparse(), implementation=implementation), self.base_ring() class PolynomialRing_field(PolynomialRing_integral_domain): - def __init__(self, base_ring, name='x', sparse=False, implementation=None, - element_class=None, category=None): + def __init__(self, base_ring, name='x', sparse=False, implementation=None, element_class=None, category=None): """ TESTS:: @@ -2134,6 +2138,7 @@ def __init__(self, base_ring, name='x', sparse=False, implementation=None, sage: x^(10^20) # this should be fast # needs sage.rings.finite_rings x^100000000000000000000 """ + def _element_class(): if element_class: return element_class @@ -2141,12 +2146,14 @@ def _element_class(): from sage.rings.polynomial.polynomial_element_generic import ( Polynomial_generic_sparse_field, ) + return Polynomial_generic_sparse_field if isinstance(base_ring, rational_field.RationalField): try: from sage.rings.polynomial.polynomial_rational_flint import ( Polynomial_rational_flint, ) + return Polynomial_rational_flint except ImportError: pass @@ -2155,20 +2162,24 @@ def _element_class(): from sage.rings.polynomial.polynomial_number_field import ( Polynomial_absolute_number_field_dense, ) + return Polynomial_absolute_number_field_dense from sage.rings.polynomial.polynomial_number_field import ( Polynomial_relative_number_field_dense, ) + return Polynomial_relative_number_field_dense elif isinstance(base_ring, sage.rings.abc.RealField): try: from .polynomial_real_mpfr_dense import PolynomialRealDense + return PolynomialRealDense except ImportError: pass elif isinstance(base_ring, sage.rings.abc.RealBallField): try: from sage.rings.polynomial.polynomial_real_arb import Polynomial_real_arb + return Polynomial_real_arb except ImportError: pass @@ -2177,12 +2188,14 @@ def _element_class(): from sage.rings.polynomial.polynomial_complex_arb import ( Polynomial_complex_arb, ) + return Polynomial_complex_arb except ImportError: pass from sage.rings.polynomial.polynomial_element_generic import ( Polynomial_generic_dense_field, ) + return Polynomial_generic_dense_field if category is None: @@ -2190,9 +2203,7 @@ def _element_class(): else: cat = category & PrincipalIdealDomains() - PolynomialRing_integral_domain.__init__(self, base_ring, name=name, - sparse=sparse, implementation=implementation, - element_class=_element_class(), category=cat) + PolynomialRing_integral_domain.__init__(self, base_ring, name=name, sparse=sparse, implementation=implementation, element_class=_element_class(), category=cat) def _ideal_class_(self, n=0): """ @@ -2206,6 +2217,7 @@ def _ideal_class_(self, n=0): """ from sage.rings.polynomial.ideal import Ideal_1poly_field + return Ideal_1poly_field def divided_difference(self, points, full_table=False): @@ -2286,16 +2298,15 @@ def divided_difference(self, points, full_table=False): n = len(points) F = [[points[i][1]] for i in range(n)] for i in range(1, n): - for j in range(1, i+1): - numer = F[i][j-1] - F[i-1][j-1] - denom = points[i][0] - points[i-j][0] + for j in range(1, i + 1): + numer = F[i][j - 1] - F[i - 1][j - 1] + denom = points[i][0] - points[i - j][0] F[i].append(numer / denom) if full_table: return F return [F[i][i] for i in range(n)] - def lagrange_polynomial(self, points, algorithm='divided_difference', - previous_row=None): + def lagrange_polynomial(self, points, algorithm='divided_difference', previous_row=None): r""" Return the Lagrange interpolation polynomial through the given points. @@ -2464,22 +2475,22 @@ def lagrange_polynomial(self, points, algorithm='divided_difference', return self.zero() F = self.divided_difference(points) - P = self.coerce(F[n-1]) - for i in range(n-2, -1, -1): - P *= (var - points[i][0]) + P = self.coerce(F[n - 1]) + for i in range(n - 2, -1, -1): + P *= var - points[i][0] P += F[i] return P # Evaluate using the definition of Lagrange interpolation # polynomial by means of divided difference. This is slow # compared to that above, which is in nested form. -# P = 0 -# for i in range(n): -# prod = 1 -# for j in range(i): -# prod *= (var - points[j][0]) -# P += (F[i] * prod) -# return P + # P = 0 + # for i in range(n): + # prod = 1 + # for j in range(i): + # prod *= (var - points[j][0]) + # P += (F[i] * prod) + # return P # using Neville's method for recursively generating the # Lagrange interpolation polynomial @@ -2490,7 +2501,7 @@ def lagrange_polynomial(self, points, algorithm='divided_difference', M = len(previous_row) # During the computation, P keeps track of the previous row, # and Q keeps track of the current row - P = previous_row + [None] * (N - M) # use results of previous computation if available + P = previous_row + [None] * (N - M) # use results of previous computation if available Q = [None] * N for i in range(M, N): Q[0] = self.coerce(points[i][1]) # start populating the current row @@ -2498,11 +2509,12 @@ def lagrange_polynomial(self, points, algorithm='divided_difference', numer = (var - points[i - j][0]) * Q[j - 1] - (var - points[i][0]) * P[j - 1] denom = points[i][0] - points[i - j][0] Q[j] = numer / denom - P, Q = Q, P # the current row is complete, reuse the old P to hold the next row - return P # return the last row in the Neville table + P, Q = Q, P # the current row is complete, reuse the old P to hold the next row + return P # return the last row in the Neville table if algorithm == "pari": from sage.libs.pari import pari + positions = pari([a for a, b in points]) values = pari([b for a, b in points]) return self(pari.polinterpolate(positions, values)) @@ -2545,6 +2557,7 @@ def fraction_field(self): x^8 + 16*x^6 + 4*x^4 + x^2 + 11 """ from sage.rings.fraction_field import FractionField_1poly_field + return FractionField_1poly_field(self) @@ -2558,6 +2571,7 @@ class PolynomialRing_dense_finite_field(PolynomialRing_field): sage: type(R) # needs sage.rings.finite_rings """ + def __init__(self, base_ring, name='x', element_class=None, implementation=None): """ TESTS:: @@ -2594,8 +2608,7 @@ def __init__(self, base_ring, name='x', element_class=None, implementation=None) self._modulus = ntl_ZZ_pEContext(ntl_ZZ_pX(list(base_ring.modulus()), p)) element_class = Polynomial_ZZ_pEX break - PolynomialRing_field.__init__(self, base_ring, sparse=False, name=name, - implementation=implementation, element_class=element_class) + PolynomialRing_field.__init__(self, base_ring, sparse=False, name=name, implementation=implementation, element_class=element_class) @staticmethod def _implementation_names_impl(implementation, base_ring, sparse): @@ -2668,12 +2681,12 @@ def irreducible_element(self, n, algorithm=None): if algorithm == "random": while True: - f = self.gen()**n + self.random_element(degree=(0, n - 1)) + f = self.gen() ** n + self.random_element(degree=(0, n - 1)) if f.is_irreducible(): return f elif algorithm == "first_lexicographic": - for g in self.polynomials(max_degree=n-1): - f = self.gen()**n + g + for g in self.polynomials(max_degree=n - 1): + f = self.gen() ** n + g if f.is_irreducible(): return f else: @@ -2722,6 +2735,7 @@ def _roth_ruckenstein(self, p, degree_bound, precision): sage: Px._roth_ruckenstein(p, 1, 2) [(4*x + 16, 2), (2*x + 13, 2), (15*x + 4, 2), (x + 1, 2)] """ + def roth_rec(p, lam, k, g): r""" Recursive core method for Roth-Ruckenstein algorithm. @@ -2739,8 +2753,8 @@ def roth_rec(p, lam, k, g): val = min(c.valuation() for c in p) if precision: k = k - val - T = p.map_coefficients(lambda c:c.shift(-val)) - Ty = T.map_coefficients(lambda c:c[0]).change_ring(F) + T = p.map_coefficients(lambda c: c.shift(-val)) + Ty = T.map_coefficients(lambda c: c[0]).change_ring(F) if Ty.is_zero() or (precision and k <= 0): if precision: solutions.append((g, lam)) @@ -2749,12 +2763,12 @@ def roth_rec(p, lam, k, g): return roots = Ty.roots(multiplicities=False) for gamma in roots: - g_new = g + gamma*x**lam + g_new = g + gamma * x**lam if lam < degree_bound: - Tg = T(x*y + gamma) - roth_rec(Tg , lam+1, k, g_new) + Tg = T(x * y + gamma) + roth_rec(Tg, lam + 1, k, g_new) elif precision: - solutions.append((g_new, lam+1)) + solutions.append((g_new, lam + 1)) elif p(gamma).is_zero(): solutions.append(g_new) return @@ -2838,6 +2852,7 @@ def _alekhnovich(self, p, degree_bound, precision=None, dc_threshold=None): - Johan Rosenkilde (2015) -- Original implementation - Bruno Grenet (August 2016) -- Incorporation into SageMath and polishing """ + def alekh_rec(p, k, degree_bound, lvl): r""" Recursive core method for Alekhnovich algorithm. @@ -2850,34 +2865,34 @@ def alekh_rec(p, k, degree_bound, lvl): - ``lvl`` -- the level in the recursion tree """ if k <= 0: - return [ (self.zero(),0) ] + return [(self.zero(), 0)] if degree_bound < 0: # The only possible root of (current) p, if any, is y = 0 if p(0).is_zero() or p(0).valuation() >= k: - return [ (self.zero(),0) ] + return [(self.zero(), 0)] return [] if k == 1 or degree_bound == 0: - #Either one coefficient left to be computed, or p has only one coefficient + # Either one coefficient left to be computed, or p has only one coefficient py = self([c[0] for c in p.list()]) # py = p(x=0, y) if py.is_zero(): - return [ (self.zero(), 0) ] + return [(self.zero(), 0)] roots = py.roots(multiplicities=False) - return [ (self(r),1) for r in roots ] + return [(self(r), 1) for r in roots] if k < dc_threshold: # Run Roth-Ruckenstein return self._roth_ruckenstein(p, degree_bound=degree_bound, precision=k) - p = p.map_coefficients(lambda c:c.truncate(k)) - half_roots = alekh_rec(p, k//2, degree_bound, lvl+1) + p = p.map_coefficients(lambda c: c.truncate(k)) + half_roots = alekh_rec(p, k // 2, degree_bound, lvl + 1) whole_roots = [] - for (hi, di) in half_roots: - QhatT = p(hi + y*x**di) + for hi, di in half_roots: + QhatT = p(hi + y * x**di) if not QhatT: - whole_roots.append((hi,di)) + whole_roots.append((hi, di)) else: val = min(c.valuation() for c in QhatT) - Qhat = QhatT.map_coefficients(lambda c:c.shift(-val)) - sec_half = alekh_rec(Qhat, k-val, degree_bound - di, lvl+1) - whole_roots.extend([ (hi + hij.shift(di), di+dij) for (hij, dij) in sec_half ]) + Qhat = QhatT.map_coefficients(lambda c: c.shift(-val)) + sec_half = alekh_rec(Qhat, k - val, degree_bound - di, lvl + 1) + whole_roots.extend([(hi + hij.shift(di), di + dij) for (hij, dij) in sec_half]) return whole_roots x = self.gen() @@ -2886,7 +2901,7 @@ def alekh_rec(p, k, degree_bound, lvl): # If precision is not given, find actual roots. To be sure, precision then # needs to be more than wdeg{1,degree_bound}(Q) since a root might have degree degree_bound. if precision is None: - k = 1 + max( p[i].degree() + degree_bound*i for i in range(1+p.degree())) + k = 1 + max(p[i].degree() + degree_bound * i for i in range(1 + p.degree())) else: k = precision @@ -2894,7 +2909,7 @@ def alekh_rec(p, k, degree_bound, lvl): if precision is None: roots = [] - for hi,_ in mod_roots: + for hi, _ in mod_roots: if p(hi).is_zero(): roots.append(hi) return roots @@ -2949,7 +2964,7 @@ def _roots_univariate_polynomial(self, p, ring=None, multiplicities=False, algor if l == 0: return [] dl = p[l].degree() - degree_bound = max((p[i].degree() - dl)//(l - i) for i in range(l) if p[i]) + degree_bound = max((p[i].degree() - dl) // (l - i) for i in range(l) if p[i]) if algorithm is None: algorithm = "Alekhnovich" @@ -2967,8 +2982,8 @@ class PolynomialRing_cdvr(PolynomialRing_integral_domain): r""" A class for polynomial ring over complete discrete valuation rings """ - def __init__(self, base_ring, name=None, sparse=False, implementation=None, - element_class=None, category=None): + + def __init__(self, base_ring, name=None, sparse=False, implementation=None, element_class=None, category=None): r""" TESTS:: @@ -2987,23 +3002,23 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, from sage.rings.polynomial.polynomial_element_generic import ( Polynomial_generic_sparse_cdvr, ) + element_class = Polynomial_generic_sparse_cdvr else: from sage.rings.polynomial.polynomial_element_generic import ( Polynomial_generic_dense_cdvr, ) + element_class = Polynomial_generic_dense_cdvr - PolynomialRing_integral_domain.__init__(self, base_ring, name, sparse, - implementation=implementation, - element_class=element_class, category=category) + PolynomialRing_integral_domain.__init__(self, base_ring, name, sparse, implementation=implementation, element_class=element_class, category=category) class PolynomialRing_cdvf(PolynomialRing_cdvr, PolynomialRing_field): """ A class for polynomial ring over complete discrete valuation fields """ - def __init__(self, base_ring, name=None, sparse=False, implementation=None, - element_class=None, category=None): + + def __init__(self, base_ring, name=None, sparse=False, implementation=None, element_class=None, category=None): r""" TESTS:: @@ -3022,25 +3037,24 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, from sage.rings.polynomial.polynomial_element_generic import ( Polynomial_generic_sparse_cdvf, ) + element_class = Polynomial_generic_sparse_cdvf else: from sage.rings.polynomial.polynomial_element_generic import ( Polynomial_generic_dense_cdvf, ) + element_class = Polynomial_generic_dense_cdvf - PolynomialRing_field.__init__(self, base_ring, name, sparse, - implementation=implementation, element_class=element_class, - category=category) + PolynomialRing_field.__init__(self, base_ring, name, sparse, implementation=implementation, element_class=element_class, category=category) class PolynomialRing_dense_padic_ring_generic(PolynomialRing_cdvr): r""" A class for dense polynomial ring over `p`-adic rings """ + def __init__(self, base_ring, name=None, implementation=None, element_class=None, category=None): - PolynomialRing_cdvr.__init__(self, base_ring, sparse=False, name=name, - implementation=implementation, element_class=element_class, - category=category) + PolynomialRing_cdvr.__init__(self, base_ring, sparse=False, name=name, implementation=implementation, element_class=element_class, category=category) @staticmethod def _implementation_names_impl(implementation, base_ring, sparse): @@ -3066,10 +3080,9 @@ class PolynomialRing_dense_padic_field_generic(PolynomialRing_cdvf): r""" A class for dense polynomial ring over `p`-adic fields """ + def __init__(self, base_ring, name=None, implementation=None, element_class=None, category=None): - PolynomialRing_cdvf.__init__(self, base_ring, sparse=False, name=name, - implementation=implementation, element_class=element_class, - category=category) + PolynomialRing_cdvf.__init__(self, base_ring, sparse=False, name=name, implementation=implementation, element_class=element_class, category=category) @staticmethod def _implementation_names_impl(implementation, base_ring, sparse): @@ -3103,14 +3116,12 @@ def __init__(self, base_ring, name=None, implementation=None, element_class=None """ if element_class is None: - from sage.rings.polynomial.padics.\ - polynomial_padic_capped_relative_dense import ( + from sage.rings.polynomial.padics.polynomial_padic_capped_relative_dense import ( Polynomial_padic_capped_relative_dense, ) + element_class = Polynomial_padic_capped_relative_dense - PolynomialRing_dense_padic_ring_generic.__init__(self, base_ring, name=name, - implementation=implementation, - element_class=element_class, category=category) + PolynomialRing_dense_padic_ring_generic.__init__(self, base_ring, name=name, implementation=implementation, element_class=element_class, category=category) class PolynomialRing_dense_padic_ring_capped_absolute(PolynomialRing_dense_padic_ring_generic): @@ -3128,10 +3139,9 @@ def __init__(self, base_ring, name=None, implementation=None, element_class=None from sage.rings.polynomial.padics.polynomial_padic_flat import ( Polynomial_padic_flat, ) + element_class = Polynomial_padic_flat - PolynomialRing_dense_padic_ring_generic.__init__(self, base_ring, name=name, - implementation=implementation, - element_class=element_class, category=category) + PolynomialRing_dense_padic_ring_generic.__init__(self, base_ring, name=name, implementation=implementation, element_class=element_class, category=category) class PolynomialRing_dense_padic_ring_fixed_mod(PolynomialRing_dense_padic_ring_generic): @@ -3150,10 +3160,9 @@ def __init__(self, base_ring, name=None, implementation=None, element_class=None from sage.rings.polynomial.padics.polynomial_padic_flat import ( Polynomial_padic_flat, ) + element_class = Polynomial_padic_flat - PolynomialRing_dense_padic_ring_generic.__init__(self, base_ring, name=name, - implementation=implementation, - element_class=element_class, category=category) + PolynomialRing_dense_padic_ring_generic.__init__(self, base_ring, name=name, implementation=implementation, element_class=element_class, category=category) class PolynomialRing_dense_padic_field_capped_relative(PolynomialRing_dense_padic_field_generic): @@ -3168,19 +3177,16 @@ def __init__(self, base_ring, name=None, implementation=None, element_class=None """ if element_class is None: - from sage.rings.polynomial.padics.\ - polynomial_padic_capped_relative_dense import ( + from sage.rings.polynomial.padics.polynomial_padic_capped_relative_dense import ( Polynomial_padic_capped_relative_dense, ) + element_class = Polynomial_padic_capped_relative_dense - PolynomialRing_dense_padic_field_generic.__init__(self, base_ring, name=name, - implementation=implementation, - element_class=element_class, category=category) + PolynomialRing_dense_padic_field_generic.__init__(self, base_ring, name=name, implementation=implementation, element_class=element_class, category=category) class PolynomialRing_dense_mod_n(PolynomialRing_commutative): - def __init__(self, base_ring, name=None, element_class=None, - implementation=None, category=None): + def __init__(self, base_ring, name=None, element_class=None, implementation=None, category=None): """ TESTS:: @@ -3239,8 +3245,7 @@ def __init__(self, base_ring, name=None, element_class=None, self._implementation_repr = ' (using NTL)' break - PolynomialRing_commutative.__init__(self, base_ring, name=name, implementation=implementation, - element_class=element_class, category=category) + PolynomialRing_commutative.__init__(self, base_ring, name=name, implementation=implementation, element_class=element_class, category=category) @staticmethod def _implementation_names_impl(implementation, base_ring, sparse): @@ -3354,9 +3359,7 @@ def residue_field(self, ideal, names=None): return ideal.residue_field(names) -class PolynomialRing_dense_mod_p(PolynomialRing_dense_finite_field, - PolynomialRing_dense_mod_n, - PolynomialRing_singular_repr): +class PolynomialRing_dense_mod_p(PolynomialRing_dense_finite_field, PolynomialRing_dense_mod_n, PolynomialRing_singular_repr): def __init__(self, base_ring, name='x', implementation=None, element_class=None, category=None): """ TESTS:: @@ -3425,11 +3428,9 @@ def __init__(self, base_ring, name='x', implementation=None, element_class=None, self._implementation_repr = ' (using GF2X)' break - category = check_default_category(PrincipalIdealDomains(), - category) + category = check_default_category(PrincipalIdealDomains(), category) - PolynomialRing_dense_mod_n.__init__(self, base_ring, name=name, implementation=implementation, - element_class=element_class, category=category) + PolynomialRing_dense_mod_n.__init__(self, base_ring, name=name, implementation=implementation, element_class=element_class, category=category) self._has_singular = can_convert_to_singular(self) @@ -3572,7 +3573,7 @@ def irreducible_element(self, n, algorithm=None): if algorithm is None: if n == 1: - return self((-1,1)) # Polynomial x - 1 + return self((-1, 1)) # Polynomial x - 1 if exists_conway_polynomial(p, n): algorithm = "conway" elif p == 2: @@ -3610,6 +3611,7 @@ def irreducible_element(self, n, algorithm=None): elif algorithm == "minimal_weight": if p == 2: from .polynomial_gf2x import GF2X_BuildSparseIrred_list + return self(GF2X_BuildSparseIrred_list(n)) raise NotImplementedError("'minimal_weight' option only implemented for p = 2") elif algorithm == "random": @@ -3647,8 +3649,7 @@ def fraction_field(self): pass else: p = self.base_ring().characteristic() - if (issubclass(self.element_class, Polynomial_zmod_flint) - and 2 < p < FpT.INTEGER_LIMIT): + if issubclass(self.element_class, Polynomial_zmod_flint) and 2 < p < FpT.INTEGER_LIMIT: return FpT(self) return super().fraction_field() @@ -3717,4 +3718,5 @@ def polygens(base_ring, names='x', *args): (x0, x1, x2, x3) """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + return PolynomialRing(base_ring, names, *args).gens() diff --git a/src/sage/rings/polynomial/polynomial_ring_constructor.py b/src/sage/rings/polynomial/polynomial_ring_constructor.py index 5eeecba1d17..a820fb72438 100644 --- a/src/sage/rings/polynomial/polynomial_ring_constructor.py +++ b/src/sage/rings/polynomial/polynomial_ring_constructor.py @@ -11,6 +11,7 @@ rings but rather quotients of them (see module :mod:`sage.rings.polynomial.pbori` for more details). """ + # **************************************************************************** # Copyright (C) 2006 William Stein # @@ -26,12 +27,14 @@ try: from sage.rings.padics import padic_base_leaves except ImportError: + class padic_base_leaves: pAdicFieldCappedRelative = () pAdicRingCappedRelative = () pAdicRingCappedAbsolute = () pAdicRingFixedMod = () + import sage.misc.weak_dict import sage.rings.abc from sage.categories.commutative_rings import CommutativeRings @@ -668,6 +671,7 @@ def PolynomialRing(base_ring, *args, **kwds): Multivariate Polynomial Ring in x0, x1 over The Infinity Ring """ from sage.rings.semirings.tropical_semiring import TropicalSemiring + if base_ring not in Rings() and not isinstance(base_ring, TropicalSemiring): raise TypeError("base_ring {!r} must be a ring or the tropical semiring".format(base_ring)) @@ -838,10 +842,12 @@ def _single_variate(base_ring, name, sparse=None, implementation=None, order=Non # Generic implementations if constructor is None: from sage.rings.semirings.tropical_semiring import TropicalSemiring + if isinstance(base_ring, TropicalSemiring): from sage.rings.semirings.tropical_polynomial import ( TropicalPolynomialSemiring, ) + constructor = TropicalPolynomialSemiring elif base_ring not in _CommutativeRings: constructor = polynomial_ring.PolynomialRing_generic @@ -860,8 +866,7 @@ def _single_variate(base_ring, name, sparse=None, implementation=None, order=Non # Only use names which are not supported by the specialized class. if specialized is not None: - implementation_names = [n for n in implementation_names - if specialized._implementation_names_impl(n, base_ring, sparse) is NotImplemented] + implementation_names = [n for n in implementation_names if specialized._implementation_names_impl(n, base_ring, sparse) is NotImplemented] if implementation is not None: kwds["implementation"] = implementation @@ -881,6 +886,7 @@ def _multi_variate(base_ring, names, sparse=None, order='degrevlex', implementat raise NotImplementedError("a dense representation of multivariate polynomials is not supported") from sage.rings.polynomial.term_order import TermOrder + n = len(names) order = TermOrder(order, n) @@ -902,6 +908,7 @@ def _multi_variate(base_ring, names, sparse=None, order='degrevlex', implementat from sage.rings.polynomial.multi_polynomial_libsingular import ( MPolynomialRing_libsingular, ) + R = MPolynomialRing_libsingular(base_ring, n, names, order) except (ImportError, TypeError, NotImplementedError): if implementation is not None: @@ -920,10 +927,12 @@ def _multi_variate(base_ring, names, sparse=None, order='degrevlex', implementat from sage.rings.semirings.tropical_semiring import TropicalSemiring from . import multi_polynomial_ring + if isinstance(base_ring, TropicalSemiring): from sage.rings.semirings.tropical_mpolynomial import ( TropicalMPolynomialSemiring, ) + constructor = TropicalMPolynomialSemiring elif base_ring in _Domains: constructor = multi_polynomial_ring.MPolynomialRing_polydict_domain @@ -1089,11 +1098,13 @@ def BooleanPolynomialRing_constructor(n=None, names=None, order='lex'): return R from sage.rings.polynomial.pbori.pbori import BooleanPolynomialRing + R = BooleanPolynomialRing(n, names, order) _save_in_cache(key, R) return R + ############################################################################ # END (Factory function for making polynomial rings) ############################################################################ diff --git a/src/sage/rings/polynomial/polynomial_singular_interface.py b/src/sage/rings/polynomial/polynomial_singular_interface.py index 16f566336c2..3dc8fcadb8d 100644 --- a/src/sage/rings/polynomial/polynomial_singular_interface.py +++ b/src/sage/rings/polynomial/polynomial_singular_interface.py @@ -17,6 +17,7 @@ sage: f = (a^3 + 2*b^2*a)^7; f a^21 + 2*a^7*b^14 """ + ################################################################# # # Sage: Open Source Mathematical Software @@ -78,14 +79,14 @@ def _do_singular_init_(singular, base_ring, char, _vars, order): # singular converts to bits from base_10 in mpr_complex.cc by: # size_t bits = 1 + (size_t) ((float)digits * 3.5); precision = base_ring.precision() - digits = (2*precision + 4) // 7 + digits = (2 * precision + 4) // 7 return make_ring(f"(real,{digits},0)"), None if isinstance(base_ring, sage.rings.abc.ComplexField): # singular converts to bits from base_10 in mpr_complex.cc by: # size_t bits = 1 + (size_t) ((float)digits * 3.5); precision = base_ring.precision() - digits = (2*precision + 4) // 7 + digits = (2 * precision + 4) // 7 return make_ring(f"(complex,{digits},0,I)"), None if isinstance(base_ring, sage.rings.abc.RealDoubleField): @@ -111,7 +112,7 @@ def _do_singular_init_(singular, base_ring, char, _vars, order): gen = str(base_ring.gen()) R = make_ring(f"({char},{gen})") - minpoly = str(base_ring.modulus()).replace("x",gen).replace(" ","") + minpoly = str(base_ring.modulus()).replace("x", gen).replace(" ", "") if singular.eval('minpoly') != f"({minpoly})": singular.eval(f"minpoly={minpoly}") minpoly = singular.eval('minpoly')[1:-1] @@ -123,10 +124,10 @@ def _do_singular_init_(singular, base_ring, char, _vars, order): gen = str(base_ring.gen()) poly = base_ring.polynomial() poly_gen = str(poly.parent().gen()) - poly_str = str(poly).replace(poly_gen,gen) + poly_str = str(poly).replace(poly_gen, gen) R = make_ring(f"({char},{gen})") - minpoly = poly_str.replace(" ","") + minpoly = poly_str.replace(" ", "") if singular.eval('minpoly') != f"({minpoly})": singular.eval(f"minpoly={minpoly}") minpoly = singular.eval('minpoly')[1:-1] @@ -151,16 +152,16 @@ def _do_singular_init_(singular, base_ring, char, _vars, order): R = make_ring(f"({base_char},{gens})") - base_ring.__minpoly = (str(B.modulus()).replace("x",ext_gen)).replace(" ","") + base_ring.__minpoly = (str(B.modulus()).replace("x", ext_gen)).replace(" ", "") singular.eval('setring ' + R._name) from sage.misc.stopgap import stopgap + stopgap("Denominators of fraction field elements are sometimes dropped without warning.", 17696) return singular(f"std(ideal({base_ring.__minpoly}))", type='qring'), None - elif isinstance(base_ring, RationalFunctionField) \ - and base_ring.constant_field().is_prime_field(): + elif isinstance(base_ring, RationalFunctionField) and base_ring.constant_field().is_prime_field(): gen = str(base_ring.gen()) return make_ring(f"({base_ring.characteristic()},{gen})"), None @@ -175,6 +176,7 @@ class PolynomialRing_singular_repr: polynomial rings which support conversion from and to Singular rings. """ + def _singular_(self, singular=None): r""" Return a Singular ring for this polynomial ring. @@ -331,8 +333,7 @@ def _singular_(self, singular=None): R._check_valid() if self.base_ring() is ZZ or self.base_ring().is_prime_field(): return R - if isinstance(self.base_ring(), FiniteField) or \ - (isinstance(self.base_ring(), NumberField) and self.base_ring().is_absolute()): + if isinstance(self.base_ring(), FiniteField) or (isinstance(self.base_ring(), NumberField) and self.base_ring().is_absolute()): R.set_ring() # sorry for that, but needed for minpoly if singular.eval('minpoly') != f"({self.__minpoly})": singular.eval(f"minpoly={self.__minpoly}") @@ -437,21 +438,15 @@ def can_convert_to_singular(R): return False base_ring = R.base_ring() - if (base_ring is ZZ - or isinstance(base_ring, (RationalField, - sage.rings.abc.IntegerModRing, - sage.rings.abc.RealField, sage.rings.abc.ComplexField, - sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField))): + if base_ring is ZZ or isinstance(base_ring, (RationalField, sage.rings.abc.IntegerModRing, sage.rings.abc.RealField, sage.rings.abc.ComplexField, sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField)): return True if isinstance(base_ring, FiniteField): return base_ring.characteristic() <= 2147483647 if isinstance(base_ring, NumberField): return base_ring.is_absolute() - if (isinstance(base_ring, sage.rings.fraction_field.FractionField_generic) - and isinstance(base_ring.base(), (PolynomialRing_general, MPolynomialRing_base))): + if isinstance(base_ring, sage.rings.fraction_field.FractionField_generic) and isinstance(base_ring.base(), (PolynomialRing_general, MPolynomialRing_base)): B = base_ring.base_ring() - return (B.is_prime_field() or B is ZZ - or (isinstance(B, FiniteField) and B.characteristic() <= 2147483647)) + return B.is_prime_field() or B is ZZ or (isinstance(B, FiniteField) and B.characteristic() <= 2147483647) if isinstance(base_ring, RationalFunctionField): return base_ring.constant_field().is_prime_field() return False @@ -468,6 +463,7 @@ class Polynomial_singular_repr: Due to the incompatibility of Python extension classes and multiple inheritance, this just defers to module-level functions. """ + def _singular_(self, singular=None): if singular is None: from sage.interfaces.singular import singular diff --git a/src/sage/rings/polynomial/q_integer_valued_polynomials.py b/src/sage/rings/polynomial/q_integer_valued_polynomials.py index e8141dd7d3e..5f458a47d0c 100644 --- a/src/sage/rings/polynomial/q_integer_valued_polynomials.py +++ b/src/sage/rings/polynomial/q_integer_valued_polynomials.py @@ -7,6 +7,7 @@ - Frédéric Chapoton (2024-03): Initial version """ + # **************************************************************************** # Copyright (C) 2024 Frédéric Chapoton # @@ -67,7 +68,7 @@ def q_int_x(n, q=None): else: ring_q = q.parent() x = polygen(ring_q, 'x') - return q_int(n - 1, q) + q**(n - 1) * x + return q_int(n - 1, q) + q ** (n - 1) * x def q_binomial_x(m, n, q=None): @@ -110,8 +111,7 @@ def q_binomial_x(m, n, q=None): ring = PolynomialRing(ring_q.fraction_field(), 'x') if n == 0: return ring.one() - return ring.prod(q_int_x(m + 2 - i, q) / q_int(i, q) - for i in range(1, n + 1)) + return ring.prod(q_int_x(m + 2 - i, q) / q_int(i, q) for i in range(1, n + 1)) class QuantumValuedPolynomialRing(UniqueRepresentation, Parent): @@ -180,6 +180,7 @@ class QuantumValuedPolynomialRing(UniqueRepresentation, Parent): S[0] - (1/2*q^-3)*S[2] + (1/2*q^-4+q^-3+q^-2+1/2*q^-1)*S[3] - (1/2*q^-4+1/2*q^-3+q^-2+1/2*q^-1+1/2)*S[4] """ + @staticmethod def __classcall_private__(cls, R, q=None) -> None: """ @@ -287,8 +288,7 @@ def super_categories(self) -> list: """ A = self.base() category = Algebras(A.base_ring()).Commutative().Filtered() - return [A.Realizations(), - category.Realizations().WithBasis()] + return [A.Realizations(), category.Realizations().WithBasis()] class ParentMethods: def ground_ring(self): @@ -543,6 +543,7 @@ class Shifted(CombinatorialFreeModule, BindableClass): \sum_{k=0}^{n_1} (-1)^k q^{\binom{k}{2} - n_1 * n_2} \genfrac{[}{]}{0pt}{}{n_1}{k}_q \genfrac{[}{]}{0pt}{}{n_1+n_2-k}{n_1}_q S[n_1 + n_2 - k]. """ + def __init__(self, A): r""" Initialize ``self``. @@ -554,11 +555,7 @@ def __init__(self, A): in the shifted basis sage: TestSuite(F).run() # not tested """ - CombinatorialFreeModule.__init__(self, A.base_ring(), - NonNegativeIntegers(), - category=A.Bases(), - prefix="S", - latex_prefix=r"\mathbb{S}") + CombinatorialFreeModule.__init__(self, A.base_ring(), NonNegativeIntegers(), category=A.Bases(), prefix="S", latex_prefix=r"\mathbb{S}") def _an_element_(self): """ @@ -572,8 +569,7 @@ def _an_element_(self): """ NonNeg = self.basis().keys() ring = self.base_ring() - return self.element_class(self, {NonNeg(0): ring(2), - NonNeg(2): ring(4)}) + return self.element_class(self, {NonNeg(0): ring(2), NonNeg(2): ring(4)}) def _realization_name(self) -> str: r""" @@ -604,11 +600,7 @@ def product_on_basis(self, n1, n2): if j < i: j, i = i, j q = self.q() - return self._from_dict({i + j - k: (-1)**k - * q_binomial(i, k) - * q_binomial(i + j - k, i) - * q**(binomial(k, 2) - i * j) - for k in range(i + 1)}) + return self._from_dict({i + j - k: (-1) ** k * q_binomial(i, k) * q_binomial(i + j - k, i) * q ** (binomial(k, 2) - i * j) for k in range(i + 1)}) def _from_binomial_basis(self, i): """ @@ -632,9 +624,7 @@ def _from_binomial_basis(self, i): i = ZZ(i) R = self.base_ring() q = self.q() - return self._from_dict({k: R((-1)**(i - k) * q_binomial(i, k)) - * q**(-i**2 + binomial(i - k, 2)) - for k in range(i + 1)}) + return self._from_dict({k: R((-1) ** (i - k) * q_binomial(i, k)) * q ** (-(i**2) + binomial(i - k, 2)) for k in range(i + 1)}) def from_h_vector(self, hv): """ @@ -657,11 +647,7 @@ def from_h_vector(self, hv): ring = self.base_ring() q = self.q() d = len(hv) - 1 - m = matrix(ring, d + 1, d + 1, - [(-1)**(d - j) * q_binomial(d - i, d - j, q) * - q**(-d * (d - i) + binomial(d - j, 2)) - for j in range(d + 1) - for i in range(d + 1)]) + m = matrix(ring, d + 1, d + 1, [(-1) ** (d - j) * q_binomial(d - i, d - j, q) * q ** (-d * (d - i) + binomial(d - j, 2)) for j in range(d + 1) for i in range(d + 1)]) v = vector(ring, [hv[i] for i in range(d + 1)]) return sum(ring(c) * B[i] for i, c in enumerate(m * v)) @@ -788,8 +774,7 @@ def _coerce_map_from_(self, R) -> bool: if isinstance(R, QuantumValuedPolynomialRing.Shifted): return self.base_ring().has_coerce_map_from(R.base_ring()) if isinstance(R, QuantumValuedPolynomialRing.Binomial): - return R.module_morphism(self._from_binomial_basis, - codomain=self) + return R.module_morphism(self._from_binomial_basis, codomain=self) return self.base_ring().has_coerce_map_from(R) def _poly(self, i): @@ -872,13 +857,10 @@ def variable_shift(self, k=1): q = A.q() def on_basis(n): - return {A._indices(j): q**(k * j) - * q_binomial(k + n - 1 - j, n - j) - for j in range(n + 1)} + return {A._indices(j): q ** (k * j) * q_binomial(k + n - 1 - j, n - j) for j in range(n + 1)} mc = self._monomial_coefficients - ret = linear_combination((on_basis(index), coeff) - for index, coeff in mc.items()) + ret = linear_combination((on_basis(index), coeff) for index, coeff in mc.items()) return A.element_class(A, ret) def derivative_at_minus_one(self): @@ -923,10 +905,8 @@ def h_vector(self): q = self.parent().q() def fn(j, i): - return ((-1)**(d - j) * - q**(binomial(d - j + i + 1, 2) - - binomial(i + 1, 2)) * - q_binomial(d - i, d - j)) + return (-1) ** (d - j) * q ** (binomial(d - j + i + 1, 2) - binomial(i + 1, 2)) * q_binomial(d - i, d - j) + m = matrix(ring, d + 1, d + 1, fn) v = vector(ring, [self.coefficient(i) for i in range(d + 1)]) return m * v @@ -976,7 +956,7 @@ def fraction(self): frac_R = R.fraction_field() q, t = R.gens() denom = R.prod(1 - q**i * t for i in range(d)) - numer = sum(frac_R(v[i]) * t**(d - 1 - i) for i in range(d)) + numer = sum(frac_R(v[i]) * t ** (d - 1 - i) for i in range(d)) return numer / denom S = Shifted @@ -996,6 +976,7 @@ class Binomial(CombinatorialFreeModule, BindableClass): \sum_{k=0}^{n_1} q^{(k-n_1)(k-n_2)} \genfrac{[}{]}{0pt}{}{n_1}{k}_q \genfrac{[}{]}{0pt}{}{n_1+n_2-k}{n_1}_q B[n_1 + n_2 - k]. """ + def __init__(self, A) -> None: r""" Initialize ``self``. @@ -1007,11 +988,7 @@ def __init__(self, A) -> None: in the binomial basis sage: TestSuite(F).run() # not tested """ - CombinatorialFreeModule.__init__(self, A.base_ring(), - NonNegativeIntegers(), - category=A.Bases(), - prefix="B", - latex_prefix=r"\mathbb{B}") + CombinatorialFreeModule.__init__(self, A.base_ring(), NonNegativeIntegers(), category=A.Bases(), prefix="B", latex_prefix=r"\mathbb{B}") def _realization_name(self) -> str: r""" @@ -1045,11 +1022,7 @@ def product_on_basis(self, n1, n2): j, i = i, j q = self.q() - return self._from_dict({i + j - k: - q_binomial(i, k) - * q_binomial(i + j - k, i) - * q**((k - i) * (k - j)) - for k in range(i + 1)}) + return self._from_dict({i + j - k: q_binomial(i, k) * q_binomial(i + j - k, i) * q ** ((k - i) * (k - j)) for k in range(i + 1)}) def _from_shifted_basis(self, i): """ @@ -1072,9 +1045,7 @@ def _from_shifted_basis(self, i): i = ZZ(i) R = self.base_ring() q = self.q() - return self._from_dict({k: R(q_binomial(i, k)) - * q**(k**2) - for k in range(i + 1)}) + return self._from_dict({k: R(q_binomial(i, k)) * q ** (k**2) for k in range(i + 1)}) def _element_constructor_(self, x): r""" @@ -1197,8 +1168,7 @@ def _coerce_map_from_(self, R): if isinstance(R, QuantumValuedPolynomialRing.Binomial): return self.base_ring().has_coerce_map_from(R.base_ring()) if isinstance(R, QuantumValuedPolynomialRing.Shifted): - return R.module_morphism(self._from_shifted_basis, - codomain=self) + return R.module_morphism(self._from_shifted_basis, codomain=self) return self.base_ring().has_coerce_map_from(R) def _poly(self, i): @@ -1251,13 +1221,10 @@ def variable_shift(self, k=1): q = A.q() def on_basis(n): - return {A._indices(j): q**((k + j - n) * j) - * q_binomial(k, n - j) - for j in range(n + 1)} + return {A._indices(j): q ** ((k + j - n) * j) * q_binomial(k, n - j) for j in range(n + 1)} mc = self._monomial_coefficients - ret = linear_combination((on_basis(index), coeff) - for index, coeff in mc.items()) + ret = linear_combination((on_basis(index), coeff) for index, coeff in mc.items()) return A.element_class(A, ret) B = Binomial diff --git a/src/sage/rings/polynomial/skew_polynomial_ring.py b/src/sage/rings/polynomial/skew_polynomial_ring.py index e0f97cea789..6db6b85204b 100644 --- a/src/sage/rings/polynomial/skew_polynomial_ring.py +++ b/src/sage/rings/polynomial/skew_polynomial_ring.py @@ -60,6 +60,7 @@ # Helper functions + def _base_ring_to_fraction_field(S): r""" Return the unique skew polynomial ring over the fraction field of @@ -189,10 +190,7 @@ def _lagrange_polynomial(R, eval_pts, values): if l == 1: if eval_pts[0].is_zero(): # This is due to linear dependence among the eval_pts. - raise ValueError("the given evaluation points are linearly dependent" - " over the fixed field of the twisting morphism," - " so a Lagrange polynomial could not be determined" - " (and might not exist)") + raise ValueError("the given evaluation points are linearly dependent" " over the fixed field of the twisting morphism," " so a Lagrange polynomial could not be determined" " (and might not exist)") return (values[0] / eval_pts[0]) * R.one() t = l // 2 A = eval_pts[:t] @@ -209,6 +207,7 @@ def _lagrange_polynomial(R, eval_pts, values): # Generic implementation of skew polynomial rings ################################################# + class SkewPolynomialRing(OrePolynomialRing): def __init__(self, base_ring, morphism, derivation, name, sparse, category=None): r""" @@ -242,6 +241,7 @@ def __init__(self, base_ring, morphism, derivation, name, sparse, category=None) raise NotImplementedError if self.Element is None: import sage.rings.polynomial.skew_polynomial_element + self.Element = sage.rings.polynomial.skew_polynomial_element.SkewPolynomial_generic_dense OrePolynomialRing.__init__(self, base_ring, morphism, None, name, sparse, category) @@ -358,6 +358,7 @@ def lagrange_polynomial(self, points): # Special classes for twisting morphisms with finite order ########################################################## + class SectionSkewPolynomialCenterInjection(Section): r""" Section of the canonical injection of the center of a skew @@ -372,6 +373,7 @@ class SectionSkewPolynomialCenterInjection(Section): sage: sigma = iota.section() sage: TestSuite(sigma).run(skip=['_test_category']) """ + def _call_(self, x): r""" Return `x` viewed as an element of the center. @@ -445,6 +447,7 @@ class SkewPolynomialCenterInjection(RingHomomorphism): sage: iota = S.convert_map_from(Z) sage: TestSuite(iota).run(skip=['_test_category']) """ + def __init__(self, domain, codomain, embed, order): r""" Initialize this morphism. @@ -551,6 +554,7 @@ class SkewPolynomialRing_finite_order(SkewPolynomialRing): - :class:`sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing` - :mod:`sage.rings.polynomial.skew_polynomial_finite_order` """ + def __init__(self, base_ring, morphism, derivation, name, sparse, category=None): r""" Initialize this skew polynomial ring. @@ -580,9 +584,11 @@ def __init__(self, base_ring, morphism, derivation, name, sparse, category=None) """ if self.Element is None: import sage.rings.polynomial.skew_polynomial_finite_order + self.Element = sage.rings.polynomial.skew_polynomial_finite_order.SkewPolynomial_finite_order_dense if self._fraction_field_class is None: from sage.rings.polynomial.ore_function_field import OreFunctionField_with_large_center + self._fraction_field_class = OreFunctionField_with_large_center SkewPolynomialRing.__init__(self, base_ring, morphism, derivation, name, sparse, category) self._order = morphism.order() @@ -738,6 +744,7 @@ def center(self, name=None, names=None, default=False): # Special class for skew polynomial over finite fields ###################################################### + class SkewPolynomialRing_finite_field(SkewPolynomialRing_finite_order): r""" A specialized class for skew polynomial rings over finite fields. @@ -752,6 +759,7 @@ class SkewPolynomialRing_finite_field(SkewPolynomialRing_finite_order): Add methods related to center of skew polynomial ring, irreducibility, karatsuba multiplication and factorization. """ + def __init__(self, base_ring, morphism, derivation, names, sparse, category=None): r""" This method is a constructor for a general, dense univariate skew polynomial ring @@ -782,6 +790,7 @@ def __init__(self, base_ring, morphism, derivation, names, sparse, category=None """ if self.Element is None: import sage.rings.polynomial.skew_polynomial_finite_field + self.Element = sage.rings.polynomial.skew_polynomial_finite_field.SkewPolynomial_finite_field_dense SkewPolynomialRing_finite_order.__init__(self, base_ring, morphism, derivation, names, sparse, category) self._matrix_retraction = None @@ -823,7 +832,7 @@ def _new_retraction_map(self, seed=None): if seed is None: seed = k.random_element() self._seed_retraction = seed - trace = [ ] + trace = [] elt = seed for _ in range(k.degree()): x = elt @@ -878,4 +887,4 @@ def _retraction(self, x, newmap=False, seed=None): # Better to return the retraction map but more difficult if newmap or seed is not None or self._matrix_retraction is None: self._new_retraction_map() - return (self._matrix_retraction*self.base_ring()(x)._vector_())[0] + return (self._matrix_retraction * self.base_ring()(x)._vector_())[0] diff --git a/src/sage/rings/polynomial/symmetric_ideal.py b/src/sage/rings/polynomial/symmetric_ideal.py index 094fbcd67b9..84b1320f8b9 100644 --- a/src/sage/rings/polynomial/symmetric_ideal.py +++ b/src/sage/rings/polynomial/symmetric_ideal.py @@ -40,6 +40,7 @@ sage: Q(p)*x[2] == Q(p)*x[1]*x[3]*x[5] True """ + # **************************************************************************** # Copyright (C) 2009 Simon King # @@ -220,6 +221,7 @@ def _latex_(self): \left(x_{1} y_{2}\right)\Bold{Q}[x_{\ast}, y_{\ast}][\mathfrak{S}_{\infty}] """ from sage.misc.latex import latex + return r'\left({}\right){}[\mathfrak{{S}}_{{\infty}}]'.format(", ".join(latex(g) for g in self.gens()), latex(self.ring())) def _contains_(self, p): @@ -272,11 +274,12 @@ def __mul__(self, other): oN = max((X.max_index() for X in other.gens()), default=1) from sage.combinat.permutation import Permutation + P = Permutation(list(range(2, sN + oN + 1)) + [1]) oGen = list(other.gens()) SymL = oGen for i in range(sN): - oGen = [X ** P for X in oGen] + oGen = [X**P for X in oGen] SymL = SymL + oGen # Now, SymL contains all necessary permutations of the second factor OUT = [] @@ -410,14 +413,14 @@ def reduce(self, I, tailreduce=False): if I in self.ring(): # we want to reduce a polynomial by self return self.ring()(I).reduce(self) from sage.rings.polynomial.symmetric_reduction import SymmetricReductionStrategy + if hasattr(I, 'gens'): I = I.gens() - if (not I): + if not I: return self I = list(I) S = SymmetricReductionStrategy(self.ring(), I, tailreduce) - return SymmetricIdeal(self.ring(), [S.reduce(X) for X in self.gens()], - coerce=False) + return SymmetricIdeal(self.ring(), [S.reduce(X) for X in self.gens()], coerce=False) def interreduction(self, tailreduce=True, sorted=False, report=None, RStrat=None): """ @@ -496,8 +499,7 @@ def interreduction(self, tailreduce=True, sorted=False, report=None, RStrat=None if P.is_unit(): # self generates all of self.ring() if RStrat is not None: RStrat.add_generator(PARENT(1)) - return SymmetricIdeal(self.ring(), [self.ring().one()], - coerce=False) + return SymmetricIdeal(self.ring(), [self.ring().one()], coerce=False) TODO.append(P) if not sorted: TODO = list(set(TODO)) @@ -509,8 +511,7 @@ def interreduction(self, tailreduce=True, sorted=False, report=None, RStrat=None if P.is_unit(): # self generates all of PARENT if RStrat is not None: RStrat.add_generator(PARENT.one()) - return SymmetricIdeal(PARENT, [PARENT.one()], - coerce=False) + return SymmetricIdeal(PARENT, [PARENT.one()], coerce=False) VarList = VarList.union(P._p.parent().variable_names()) VarList = list(VarList) if not VarList: @@ -520,6 +521,7 @@ def interreduction(self, tailreduce=True, sorted=False, report=None, RStrat=None if report is not None: print('Symmetric interreduction') from sage.rings.polynomial.symmetric_reduction import SymmetricReductionStrategy + if RStrat is None: RStrat = SymmetricReductionStrategy(self.ring(), tailreduce=tailreduce) GroundState = RStrat.gens() @@ -533,8 +535,7 @@ def interreduction(self, tailreduce=True, sorted=False, report=None, RStrat=None p = RStrat.reduce(TODO[i], report=report) if p._p != 0: if p.is_unit(): # self generates all of self.ring() - return SymmetricIdeal(self.ring(), [self.ring().one()], - coerce=False) + return SymmetricIdeal(self.ring(), [self.ring().one()], coerce=False) RStrat.add_generator(p, good_input=True) DONE.append(p) else: @@ -546,6 +547,7 @@ def interreduction(self, tailreduce=True, sorted=False, report=None, RStrat=None else: if len(TODO) == len(DONE): import copy + bla = copy.copy(TODO) bla.sort() if bla == DONE: @@ -633,10 +635,10 @@ def symmetrisation(self, N=None, tailreduce=False, report=None, use_full_group=F if hasattr(R, '_max') and R._max < N: R.gen()[N] if report is not None: - print("Symmetrise %d polynomials at level %d" % - (len(newOUT.gens()), N)) + print("Symmetrise %d polynomials at level %d" % (len(newOUT.gens()), N)) if use_full_group: from sage.combinat.permutation import Permutations + NewGens = [] Gens = self.gens() for P in Permutations(N): @@ -644,8 +646,8 @@ def symmetrisation(self, N=None, tailreduce=False, report=None, use_full_group=F return (NewGens * R).interreduction(tailreduce=tailreduce, report=report) from sage.combinat.permutation import Permutation from sage.rings.polynomial.symmetric_reduction import SymmetricReductionStrategy - RStrat = SymmetricReductionStrategy(self.ring(), OUT.gens(), - tailreduce=tailreduce) + + RStrat = SymmetricReductionStrategy(self.ring(), OUT.gens(), tailreduce=tailreduce) while newOUT.gens() != OUT.gens(): OUT = newOUT PermutedGens = list(OUT.gens()) @@ -659,8 +661,7 @@ def symmetrisation(self, N=None, tailreduce=False, report=None, use_full_group=F if p._p != 0: PermutedGens.append(p) RStrat.add_generator(p, good_input=True) - newOUT = (PermutedGens * R).interreduction(tailreduce=tailreduce, - report=report) + newOUT = (PermutedGens * R).interreduction(tailreduce=tailreduce, report=report) return OUT def symmetric_basis(self): @@ -928,8 +929,7 @@ def groebner_basis(self, tailreduce=False, reduced=True, algorithm=None, report= PARENT = self.ring() if PARENT.base_ring() not in Fields(): raise TypeError("The base ring (= %s) must be a field" % PARENT.base_ring()) - OUT = self.symmetrisation(tailreduce=tailreduce, report=report, - use_full_group=use_full_group) + OUT = self.symmetrisation(tailreduce=tailreduce, report=report, use_full_group=use_full_group) if report is not None: print("Symmetrisation done") VarList = set() @@ -942,6 +942,7 @@ def groebner_basis(self, tailreduce=False, reduced=True, algorithm=None, report= if not VarList: return Sequence([PARENT(0)], PARENT, check=False) from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + N = max((int(X.split('_')[1]) for X in VarList), default=1) while True: @@ -959,8 +960,7 @@ def groebner_basis(self, tailreduce=False, reduced=True, algorithm=None, report= CommonR = PolynomialRing(PARENT._base, VarList, order=PARENT._order) try: # working around one libsingular bug and one libsingular oddity - DenseIdeal = [CommonR(P._p) if ((CommonR is P._p.parent()) or CommonR.ngens() != P._p.parent().ngens()) else CommonR(repr(P._p)) - for P in OUT.gens()] * CommonR + DenseIdeal = [CommonR(P._p) if ((CommonR is P._p.parent()) or CommonR.ngens() != P._p.parent().ngens()) else CommonR(repr(P._p)) for P in OUT.gens()] * CommonR except Exception: if report is not None: print("working around a libsingular bug") @@ -975,9 +975,7 @@ def groebner_basis(self, tailreduce=False, reduced=True, algorithm=None, report= print("->", len(newOUT.gens()), 'generators') # Symmetrise out to the next index: N += 1 - newOUT = newOUT.symmetrisation(N=N, tailreduce=tailreduce, - report=report, - use_full_group=use_full_group) + newOUT = newOUT.symmetrisation(N=N, tailreduce=tailreduce, report=report, use_full_group=use_full_group) if [X.lm() for X in OUT.gens()] == [X.lm() for X in newOUT.gens()]: if reduced: if tailreduce: diff --git a/src/sage/rings/polynomial/term_order.py b/src/sage/rings/polynomial/term_order.py index 1e2d5f0a9d8..1c2aba8341a 100644 --- a/src/sage/rings/polynomial/term_order.py +++ b/src/sage/rings/polynomial/term_order.py @@ -359,6 +359,7 @@ - Simon King (2011-06-06): added termorder_from_singular """ + # *************************************************************************** # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -370,37 +371,36 @@ from sage.structure.sage_object import SageObject print_name_mapping = { - 'lex' : 'Lexicographic', - 'invlex' : 'Inverse lexicographic', - 'degrevlex' : 'Degree reverse lexicographic', - 'deglex' : 'Degree lexicographic', - 'neglex' : 'Negative lexicographic', - 'negdegrevlex' : 'Negative degree reverse lexicographic', - 'negdeglex' : 'Negative degree lexicographic', - 'degneglex' : 'Degree negative lexicographic', - 'wdegrevlex' : 'Weighted degree reverse lexicographic', - 'wdeglex' : 'Weighted degree lexicographic', - 'negwdegrevlex' : 'Negative weighted degree reverse lexicographic', - 'negwdeglex' : 'Negative weighted degree lexicographic', + 'lex': 'Lexicographic', + 'invlex': 'Inverse lexicographic', + 'degrevlex': 'Degree reverse lexicographic', + 'deglex': 'Degree lexicographic', + 'neglex': 'Negative lexicographic', + 'negdegrevlex': 'Negative degree reverse lexicographic', + 'negdeglex': 'Negative degree lexicographic', + 'degneglex': 'Degree negative lexicographic', + 'wdegrevlex': 'Weighted degree reverse lexicographic', + 'wdeglex': 'Weighted degree lexicographic', + 'negwdegrevlex': 'Negative weighted degree reverse lexicographic', + 'negwdeglex': 'Negative weighted degree lexicographic', } singular_name_mapping = { - 'lex' : 'lp', - 'invlex' : 'ip', - 'degrevlex' : 'dp', - 'deglex' : 'Dp', - 'neglex' : 'ls', - 'negdegrevlex' : 'ds', - 'negdeglex' : 'Ds', - 'degneglex' : '(a(1:%(ngens)i),ls(%(ngens)i))', - 'wdegrevlex' : 'wp', - 'wdeglex' : 'Wp', - 'negwdegrevlex' : 'ws', - 'negwdeglex' : 'Ws', + 'lex': 'lp', + 'invlex': 'ip', + 'degrevlex': 'dp', + 'deglex': 'Dp', + 'neglex': 'ls', + 'negdegrevlex': 'ds', + 'negdeglex': 'Ds', + 'degneglex': '(a(1:%(ngens)i),ls(%(ngens)i))', + 'wdegrevlex': 'wp', + 'wdeglex': 'Wp', + 'negwdegrevlex': 'ws', + 'negwdeglex': 'Ws', } -inv_singular_name_mapping = dict(zip(singular_name_mapping.values(), - singular_name_mapping)) +inv_singular_name_mapping = dict(zip(singular_name_mapping.values(), singular_name_mapping)) macaulay2_name_mapping = { 'lex': 'Lex', @@ -409,8 +409,7 @@ 'deglex': 'GLex', } -inv_macaulay2_name_mapping = dict(zip(macaulay2_name_mapping.values(), - macaulay2_name_mapping)) +inv_macaulay2_name_mapping = dict(zip(macaulay2_name_mapping.values(), macaulay2_name_mapping)) magma_name_mapping = { 'lex': '"lex"', @@ -418,8 +417,7 @@ 'deglex': '"glex"', } -inv_magma_name_mapping = dict(zip(magma_name_mapping.values(), - magma_name_mapping)) +inv_magma_name_mapping = dict(zip(magma_name_mapping.values(), magma_name_mapping)) lex_description = r""" Lexicographic (lex) term order. @@ -525,20 +523,20 @@ """ description_mapping = { - 'lex' : lex_description, - 'invlex' : invlex_description, - 'degrevlex' : degrevlex_description, - 'deglex' : deglex_description, - 'neglex' : neglex_description, - 'negdegrevlex' : negdegrevlex_description, - 'negdeglex' : negdeglex_description, - 'degneglex' : degneglex_description, - 'wdeglex' : wdeglex_description, - 'wdegrevlex' : wdegrevlex_description, - 'negwdegrevlex' : negwdegrevlex_description, - 'negwdeglex' : negwdeglex_description, - 'matrix' : matrix_description, - 'block' : block_description, + 'lex': lex_description, + 'invlex': invlex_description, + 'degrevlex': degrevlex_description, + 'deglex': deglex_description, + 'neglex': neglex_description, + 'negdegrevlex': negdegrevlex_description, + 'negdeglex': negdeglex_description, + 'degneglex': degneglex_description, + 'wdeglex': wdeglex_description, + 'wdegrevlex': wdegrevlex_description, + 'negwdegrevlex': negwdegrevlex_description, + 'negwdeglex': negwdeglex_description, + 'matrix': matrix_description, + 'block': block_description, } @@ -549,6 +547,7 @@ class TermOrder(SageObject): See ``sage.rings.polynomial.term_order`` for details on supported term orders. """ + def __setstate__(self, dict): """ Translate old pickled TermOrder objects. @@ -699,11 +698,9 @@ def __init__(self, name='lex', n=0, force=False) -> None: if not name.is_block_order() and not name.is_weighted_degree_order(): self._length = n if self._length != 0: - self._singular_str = (self._singular_str - % dict(ngens=self._length)) + self._singular_str = self._singular_str % dict(ngens=self._length) elif self._length != n: - raise ValueError("the length of the given term order ({}) differs from the number of variables ({})" - .format(self._length, n)) + raise ValueError("the length of the given term order ({}) differs from the number of variables ({})".format(self._length, n)) return if isinstance(name, str): @@ -841,8 +838,9 @@ def __init__(self, name='lex', n=0, force=False) -> None: elif isinstance(name, tuple): # name represents a matrix if not n: from math import sqrt + n = int(sqrt(len(name))) - if n*n != len(name): + if n * n != len(name): raise ValueError(f"{name} does not specify a square matrix") int_str = ','.join(str(int(e)) for e in name) @@ -854,6 +852,7 @@ def __init__(self, name='lex', n=0, force=False) -> None: self._magma_str = '"weight",[%s]' % (int_str,) from sage.matrix.constructor import matrix + self._matrix = matrix(n, name) # defined only for matrix term order self._matrix.set_immutable() self._weights = name[:n] # the first row of the matrix gives weights @@ -939,8 +938,7 @@ def sortkey_matrix(self, f) -> tuple: sage: y > x^3 # needs sage.rings.number_field False """ - return tuple(sum(l * r for l, r in zip(row, f)) - for row in self._matrix) + return tuple(sum(l * r for l, r in zip(row, f)) for row in self._matrix) def sortkey_lex(self, f) -> tuple: """ @@ -1016,8 +1014,7 @@ def sortkey_degrevlex(self, f) -> tuple: sage: x > 1 # needs sage.rings.number_field True """ - return (sum(f.nonzero_values(sort=False)), - f.reversed().emul(-1)) # tuple(-v for v in f.reversed())) + return (sum(f.nonzero_values(sort=False)), f.reversed().emul(-1)) # tuple(-v for v in f.reversed())) def sortkey_neglex(self, f) -> tuple: """ @@ -1055,8 +1052,7 @@ def sortkey_negdegrevlex(self, f) -> tuple: sage: x > 1 # needs sage.rings.number_field False """ - return (-sum(f.nonzero_values(sort=False)), - tuple(-v for v in f.reversed())) + return (-sum(f.nonzero_values(sort=False)), tuple(-v for v in f.reversed())) def sortkey_negdeglex(self, f) -> tuple: """ @@ -1114,8 +1110,7 @@ def sortkey_wdegrevlex(self, f) -> tuple: sage: x^2 > y^3 # needs sage.rings.number_field True """ - return (sum(l * r for l, r in zip(f, self._weights)), - tuple(-v for v in f.reversed())) + return (sum(l * r for l, r in zip(f, self._weights)), tuple(-v for v in f.reversed())) def sortkey_wdeglex(self, f) -> tuple: """ @@ -1175,8 +1170,7 @@ def sortkey_negwdegrevlex(self, f) -> tuple: sage: x^2 > y^3 # needs sage.rings.number_field True """ - return (-sum(l * r for l, r in zip(f, self._weights)), - tuple(-v for v in f.reversed())) + return (-sum(l * r for l, r in zip(f, self._weights)), tuple(-v for v in f.reversed())) def sortkey_block(self, f) -> tuple: """ @@ -1207,7 +1201,7 @@ def sortkey_block(self, f) -> tuple: key = tuple() n = 0 for block in self: - r = getattr(block, "sortkey_" + block.name())(f[n:n + len(block)]) + r = getattr(block, "sortkey_" + block.name())(f[n : n + len(block)]) key += tuple(r) n += len(block) return key @@ -1584,8 +1578,8 @@ def greater_tuple_block(self, f, g): n = 0 for block in self: keyfn = getattr(block, "sortkey_" + block.name()) - f_key = keyfn(f[n:n + len(block)]) - g_key = keyfn(g[n:n + len(block)]) + f_key = keyfn(f[n : n + len(block)]) + g_key = keyfn(g[n : n + len(block)]) if f_key != g_key: if f_key < g_key: return g @@ -1761,12 +1755,10 @@ def singular_str(self) -> str: singular_str = singular_str[1:-1] # remove parenthesis split_pattern = r"([^(),]+(?:\([^()]*\)[^(),]*)*)" # regex to split by outermost commas singular_str_blocks = re.findall(split_pattern, singular_str) - if (self._singular_ringorder_column < 0 or - self._singular_ringorder_column >= 2*len(singular_str_blocks)+2): + if self._singular_ringorder_column < 0 or self._singular_ringorder_column >= 2 * len(singular_str_blocks) + 2: singular_str_blocks.append("C") else: - singular_str_blocks.insert(self._singular_ringorder_column // 2, - "C" if self._singular_ringorder_column % 2 == 0 else "c") + singular_str_blocks.insert(self._singular_ringorder_column // 2, "C" if self._singular_ringorder_column % 2 == 0 else "c") return "(" + ",".join(singular_str_blocks) + ")" return self._singular_str @@ -1947,13 +1939,7 @@ def __eq__(self, other): except Exception: return False - return (self._name == other._name - and self._blocks == other._blocks - and (not self.is_block_order() - or all(len(t1) == len(t2) for (t1, t2) in zip(self._blocks, other._blocks))) - and self._weights == other._weights - and self._matrix == other._matrix - and self._singular_ringorder_column == other._singular_ringorder_column) + return self._name == other._name and self._blocks == other._blocks and (not self.is_block_order() or all(len(t1) == len(t2) for (t1, t2) in zip(self._blocks, other._blocks))) and self._weights == other._weights and self._matrix == other._matrix and self._singular_ringorder_column == other._singular_ringorder_column def __ne__(self, other): """ @@ -2088,8 +2074,7 @@ def is_global(self) -> bool: sage: T.is_global() True """ - if self.name() in ('lex', 'degrevlex', 'deglex', 'degneglex', - 'wdegrevlex', 'wdeglex', 'invlex'): + if self.name() in ('lex', 'degrevlex', 'deglex', 'degneglex', 'wdegrevlex', 'wdeglex', 'invlex'): return True if self.name() == 'block': return all(t.is_global() for t in self.blocks()) @@ -2113,9 +2098,7 @@ def is_local(self) -> bool: sage: T.is_local() False """ - if (self.name() in ('neglex', 'negdegrevlex', 'negdeglex', - 'negwdegrevlex', 'negwdeglex') or - self.singular_str() in ('ls', 'ds', 'Ds', 'ws', 'Ws')): + if self.name() in ('neglex', 'negdegrevlex', 'negdeglex', 'negwdegrevlex', 'negwdeglex') or self.singular_str() in ('ls', 'ds', 'Ds', 'ws', 'Ws'): return True if self.name() == 'block': return all(t.is_local() for t in self.blocks()) @@ -2223,6 +2206,7 @@ def termorder_from_singular(S): x^2 """ from sage.rings.integer_ring import ZZ + singular = S T = singular('ringlist(basering)[3]') order = [] @@ -2235,12 +2219,13 @@ def termorder_from_singular(S): weights_one_block = all(w == 1 for w in weights) continue elif blocktype == 'c': - ringorder_column = 2*idx + 1 + ringorder_column = 2 * idx + 1 elif blocktype == 'C': if idx < len(T) - 1: # skip Singular default - ringorder_column = 2*idx + ringorder_column = 2 * idx elif blocktype == 'M': from sage.matrix.constructor import matrix + coefs = list(block[2].sage()) n = ZZ(len(coefs)).sqrt() order.append(TermOrder(matrix(n, coefs))) @@ -2249,11 +2234,9 @@ def termorder_from_singular(S): n = ZZ(singular.eval("size(%s[2])" % block.name())) order.append(TermOrder('degneglex', n)) elif blocktype[0] in ['w', 'W']: - order.append(TermOrder(inv_singular_name_mapping[blocktype], - list(block[2].sage()))) + order.append(TermOrder(inv_singular_name_mapping[blocktype], list(block[2].sage()))) else: - order.append(TermOrder(inv_singular_name_mapping[blocktype], - ZZ(singular.eval("size(%s[2])" % block.name())))) + order.append(TermOrder(inv_singular_name_mapping[blocktype], ZZ(singular.eval("size(%s[2])" % block.name())))) weights_one_block = False if not order: diff --git a/src/sage/rings/polynomial/toy_buchberger.py b/src/sage/rings/polynomial/toy_buchberger.py index 79ffefe98d9..568a6a18189 100644 --- a/src/sage/rings/polynomial/toy_buchberger.py +++ b/src/sage/rings/polynomial/toy_buchberger.py @@ -163,7 +163,7 @@ def spol(f, g): x^2*y - z^3 + x^2 - z^2 """ fg_lcm = LCM(LM(f), LM(g)) - return fg_lcm//LT(f)*f - fg_lcm//LT(g)*g + return fg_lcm // LT(f) * f - fg_lcm // LT(g) * g def buchberger(F): @@ -325,15 +325,9 @@ def update(G, B, h): while C: (h, g) = C.pop() - lcm_divides = lambda rhs: R.monomial_divides(LCM(LM(h), LM(rhs[1])), - LCM(LM(h), LM(g))) + lcm_divides = lambda rhs: R.monomial_divides(LCM(LM(h), LM(rhs[1])), LCM(LM(h), LM(g))) - if R.monomial_pairwise_prime(LM(h), LM(g)) or \ - ( - not any(lcm_divides(f) for f in C) - and - not any(lcm_divides(f) for f in D) - ): + if R.monomial_pairwise_prime(LM(h), LM(g)) or (not any(lcm_divides(f) for f in C) and not any(lcm_divides(f) for f in D)): D.add((h, g)) E = set() @@ -347,9 +341,7 @@ def update(G, B, h): while B: g1, g2 = B.pop() - if not R.monomial_divides(LM(h), LCM(LM(g1), LM(g2))) or \ - R.monomial_lcm(LM(g1), LM(h)) == LCM(LM(g1), LM(g2)) or \ - R.monomial_lcm(LM(h), LM(g2)) == LCM(LM(g1), LM(g2)): + if not R.monomial_divides(LM(h), LCM(LM(g1), LM(g2))) or R.monomial_lcm(LM(g1), LM(h)) == LCM(LM(g1), LM(g2)) or R.monomial_lcm(LM(h), LM(g2)) == LCM(LM(g1), LM(g2)): B_new.add((g1, g2)) B_new = B_new.union(E) @@ -385,8 +377,7 @@ def select(P): sage: select(pairs) [x^3 - z - 1, -y + z^3 - 1] """ - return min(P, key=lambda fi_fj: LCM(LM(fi_fj[0]), - LM(fi_fj[1])).total_degree()) + return min(P, key=lambda fi_fj: LCM(LM(fi_fj[0]), LM(fi_fj[1])).total_degree()) def inter_reduction(Q): @@ -437,5 +428,5 @@ def inter_reduction(Q): Q.add(h) if Qbar == Q: if base_ring.is_field(): - return set(f.lc()**(-1) * f for f in Qbar) + return set(f.lc() ** (-1) * f for f in Qbar) return Qbar diff --git a/src/sage/rings/polynomial/toy_d_basis.py b/src/sage/rings/polynomial/toy_d_basis.py index bc60a56d2a4..6bb72ade783 100644 --- a/src/sage/rings/polynomial/toy_d_basis.py +++ b/src/sage/rings/polynomial/toy_d_basis.py @@ -115,6 +115,7 @@ - Martin Albrecht (2008-08): initial version """ + from sage.rings.integer_ring import ZZ from sage.arith.functions import lcm from sage.arith.misc import XGCD as xgcd, GCD as gcd @@ -233,10 +234,7 @@ def divides_ZZ(x, y): f1, f2 = select(C) C.remove((f1, f2)) lcm_lmf1_lmf2 = LCM(LM(f1), LM(f2)) - if not any(divides(LM(g), lcm_lmf1_lmf2) and - divides_ZZ(LC(g), LC(f1)) and - divides_ZZ(LC(g), LC(f2)) - for g in G): + if not any(divides(LM(g), lcm_lmf1_lmf2) and divides_ZZ(LC(g), LC(f1)) and divides_ZZ(LC(g), LC(f2)) for g in G): h = gpol(f1, f2) h0 = h.reduce(G) if h0.lc() < 0: @@ -336,12 +334,10 @@ def lt_divides(x, y): return R.monomial_divides(LM(h), LM(g)) and LC(h).divides(LC(g)) def lt_pairwise_prime(x, y): - return (R.monomial_pairwise_prime(LM(x), LM(y)) - and gcd(LC(x), LC(y)) == 1) + return R.monomial_pairwise_prime(LM(x), LM(y)) and gcd(LC(x), LC(y)) == 1 def lcm_divides(f, g1, h): - return (R.monomial_divides(LCM(LM(h), LM(f[1])), LCM(LM(h), LM(g1))) - and lcm(LC(h), LC(f[1])).divides(lcm(LC(h), LC(g1)))) + return R.monomial_divides(LCM(LM(h), LM(f[1])), LCM(LM(h), LM(g1))) and lcm(LC(h), LC(f[1])).divides(lcm(LC(h), LC(g1))) C = set((h, g) for g in G) @@ -349,9 +345,7 @@ def lcm_divides(f, g1, h): while C: (h, g1) = C.pop() - if (lt_pairwise_prime(h, g1) or - (not any(lcm_divides(f, g1, h) for f in C) and - not any(lcm_divides(f, g1, h) for f in D))): + if lt_pairwise_prime(h, g1) or (not any(lcm_divides(f, g1, h) for f in C) and not any(lcm_divides(f, g1, h) for f in D)): D.add((h, g1)) E = set() @@ -366,9 +360,7 @@ def lcm_divides(f, g1, h): g1, g2 = B.pop() lcm_12 = lcm(LC(g1), LC(g2)) * LCM(LM(g1), LM(g2)) - if (not lt_divides(lcm_12, h) or - lcm(LC(g1), LC(h)) * R.monomial_lcm(LM(g1), LM(h)) == lcm_12 or - lcm(LC(h), LC(g2)) * R.monomial_lcm(LM(h), LM(g2)) == lcm_12): + if not lt_divides(lcm_12, h) or lcm(LC(g1), LC(h)) * R.monomial_lcm(LM(g1), LM(h)) == lcm_12 or lcm(LC(h), LC(g2)) * R.monomial_lcm(LM(h), LM(g2)) == lcm_12: B_new.add((g1, g2)) B_new = B_new.union(E) diff --git a/src/sage/rings/polynomial/toy_variety.py b/src/sage/rings/polynomial/toy_variety.py index d805e7cd7da..6f9e6407a89 100644 --- a/src/sage/rings/polynomial/toy_variety.py +++ b/src/sage/rings/polynomial/toy_variety.py @@ -107,6 +107,7 @@ def coefficient_matrix(polys): :meth:`sage.rings.polynomial.multi_polynomial_sequence.PolynomialSequence_generic.coefficient_matrix()` in the future. """ from sage.matrix.constructor import matrix + R = polys[0].base_ring() mons = set() for each in polys: @@ -217,6 +218,7 @@ def linear_representation(p, polys): [3, 32001, 1] """ from sage.matrix.constructor import diagonal_matrix + R = p.base_ring() M = coefficient_matrix(polys + [p]).augment(diagonal_matrix(R, [1 for each in range(len(polys) + 1)])) M.echelonize() diff --git a/src/sage/rings/polynomial/weil/all.py b/src/sage/rings/polynomial/weil/all.py index bb0a807c3da..480a4fb71d7 100644 --- a/src/sage/rings/polynomial/weil/all.py +++ b/src/sage/rings/polynomial/weil/all.py @@ -1,3 +1,4 @@ from sage.misc.lazy_import import lazy_import + lazy_import('sage.rings.polynomial.weil.weil_polynomials', 'WeilPolynomials') del lazy_import diff --git a/src/sage/rings/power_series_ring.py b/src/sage/rings/power_series_ring.py index 7a32090915d..d244d9bb00f 100644 --- a/src/sage/rings/power_series_ring.py +++ b/src/sage/rings/power_series_ring.py @@ -176,9 +176,7 @@ lazy_import('sage.rings.lazy_series_ring', 'LazyPowerSeriesRing') -def PowerSeriesRing(base_ring, name=None, arg2=None, names=None, - sparse=False, default_prec=None, order='negdeglex', - num_gens=None, implementation=None): +def PowerSeriesRing(base_ring, name=None, arg2=None, names=None, sparse=False, default_prec=None, order='negdeglex', num_gens=None, implementation=None): r""" Create a univariate or multivariate power series ring over a given (commutative) base ring. @@ -361,17 +359,14 @@ def PowerSeriesRing(base_ring, name=None, arg2=None, names=None, if names is None and name is not None: names = name if isinstance(names, (tuple, list)) and len(names) > 1 or (isinstance(names, str) and ',' in names): - return _multi_variate(base_ring, num_gens=arg2, names=names, - order=order, default_prec=default_prec, sparse=sparse) + return _multi_variate(base_ring, num_gens=arg2, names=names, order=order, default_prec=default_prec, sparse=sparse) # examples for second case: # PowerSeriesRing(QQ,3,'t') if arg2 is None and num_gens is not None: arg2 = names names = num_gens - if (isinstance(arg2, str) and - isinstance(names, (int, integer.Integer))): - return _multi_variate(base_ring, num_gens=names, names=arg2, - order=order, default_prec=default_prec, sparse=sparse) + if isinstance(arg2, str) and isinstance(names, (int, integer.Integer)): + return _multi_variate(base_ring, num_gens=names, names=arg2, order=order, default_prec=default_prec, sparse=sparse) # univariate case: the arguments to PowerSeriesRing used to be # (base_ring, name=None, default_prec=20, names=None, sparse=False), @@ -379,6 +374,7 @@ def PowerSeriesRing(base_ring, name=None, arg2=None, names=None, # deprecated, and will eventually be removed. if default_prec is None and arg2 is None: from sage.misc.defaults import series_precision + default_prec = series_precision() elif arg2 is not None: default_prec = arg2 @@ -412,21 +408,17 @@ def PowerSeriesRing(base_ring, name=None, arg2=None, names=None, raise TypeError("variable name must be a string or None") if base_ring in _Fields: - R = PowerSeriesRing_over_field(base_ring, name, default_prec, - sparse=sparse, implementation=implementation) + R = PowerSeriesRing_over_field(base_ring, name, default_prec, sparse=sparse, implementation=implementation) elif base_ring in _IntegralDomains: - R = PowerSeriesRing_domain(base_ring, name, default_prec, - sparse=sparse, implementation=implementation) + R = PowerSeriesRing_domain(base_ring, name, default_prec, sparse=sparse, implementation=implementation) elif base_ring in _CommutativeRings: - R = PowerSeriesRing_generic(base_ring, name, default_prec, - sparse=sparse, implementation=implementation) + R = PowerSeriesRing_generic(base_ring, name, default_prec, sparse=sparse, implementation=implementation) else: raise TypeError("base_ring must be a commutative ring") return R -def _multi_variate(base_ring, num_gens=None, names=None, - order='negdeglex', default_prec=None, sparse=False): +def _multi_variate(base_ring, num_gens=None, names=None, order='negdeglex', default_prec=None, sparse=False): """ Construct multivariate power series ring. """ @@ -448,8 +440,8 @@ def _multi_variate(base_ring, num_gens=None, names=None, if base_ring not in commutative_rings.CommutativeRings(): raise TypeError("base_ring must be a commutative ring") from sage.rings.multi_power_series_ring import MPowerSeriesRing_generic - R = MPowerSeriesRing_generic(base_ring, num_gens, names, - order=order, default_prec=default_prec, sparse=sparse) + + R = MPowerSeriesRing_generic(base_ring, num_gens, names, order=order, default_prec=default_prec, sparse=sparse) return R @@ -462,8 +454,7 @@ class PowerSeriesRing_generic(UniqueRepresentation, Parent, Nonexact): A power series ring. """ - def __init__(self, base_ring, name=None, default_prec=None, sparse=False, - implementation=None, category=None) -> None: + def __init__(self, base_ring, name=None, default_prec=None, sparse=False, implementation=None, category=None) -> None: """ Initialize a power series ring. @@ -530,7 +521,7 @@ def __init__(self, base_ring, name=None, default_prec=None, sparse=False, else: implementation = 'poly' R = PolynomialRing(base_ring, name, sparse=sparse) - elif implementation not in ['pari', 'mpoly']: # see :issue:`28996` + elif implementation not in ['pari', 'mpoly']: # see :issue:`28996` R = PolynomialRing(base_ring, name, sparse=sparse, implementation=implementation) implementation = 'poly' else: @@ -540,10 +531,10 @@ def __init__(self, base_ring, name=None, default_prec=None, sparse=False, self.__is_sparse = sparse if default_prec is None: from sage.misc.defaults import series_precision + default_prec = series_precision() elif default_prec < 0: - raise ValueError("default_prec (= %s) must be nonnegative" - % default_prec) + raise ValueError("default_prec (= %s) must be nonnegative" % default_prec) if implementation == 'poly': self.Element = power_series_poly.PowerSeries_poly @@ -555,13 +546,12 @@ def __init__(self, base_ring, name=None, default_prec=None, sparse=False, self.Element = power_series_mpoly.PowerSeries_mpoly elif implementation == 'pari': from .power_series_pari import PowerSeries_pari + self.Element = PowerSeries_pari else: raise ValueError('unknown power series implementation: %r' % implementation) - Parent.__init__(self, base=base_ring, names=name, - category=getattr(self, '_default_category', - _CommutativeRings)) + Parent.__init__(self, base=base_ring, names=name, category=getattr(self, '_default_category', _CommutativeRings)) Nonexact.__init__(self, default_prec) if implementation == 'pari': self.__generator = self.element_class(self, R.gen().__pari__()) @@ -582,6 +572,7 @@ def variable_names_recursive(self, depth=None): """ if depth is None: from sage.rings.infinity import infinity + depth = infinity if depth <= 0: @@ -682,9 +673,7 @@ def _coerce_map_from_(self, S): """ if self.base_ring().has_coerce_map_from(S): return True - if (isinstance(S, (PolynomialRing_generic, PowerSeriesRing_generic, LazyPowerSeriesRing)) - and self.base_ring().has_coerce_map_from(S.base_ring()) - and self.variable_names() == S.variable_names()): + if isinstance(S, (PolynomialRing_generic, PowerSeriesRing_generic, LazyPowerSeriesRing)) and self.base_ring().has_coerce_map_from(S.base_ring()) and self.variable_names() == S.variable_names(): return True def _magma_init_(self, magma): @@ -826,23 +815,23 @@ def _element_constructor_(self, f, prec=infinity, check=True): return self(f.power_series(), prec, check=check) elif isinstance(f, MagmaElement) and str(f.Type()) == 'RngSerPowElt': v = sage_eval(f.Eltseq()) # could use .sage() ? - return self(v) * (self.gen(0)**f.Valuation()) + return self(v) * (self.gen(0) ** f.Valuation()) elif isinstance(f, FractionFieldElement): if self.base_ring().has_coerce_map_from(f.parent()): return self.element_class(self, [f], prec, check=check) num = self.element_class(self, f.numerator(), prec, check=check) den = self.element_class(self, f.denominator(), prec, check=check) - return self.coerce(num/den) + return self.coerce(num / den) elif isinstance(f, Expression): from sage.symbolic.expression import SymbolicSeries + if isinstance(f, SymbolicSeries): if str(f.default_variable()) == self.variable_name(): - return self.element_class(self, f.list(), - f.degree(f.default_variable()), - check=check) + return self.element_class(self, f.list(), f.degree(f.default_variable()), check=check) raise TypeError("Can only convert series into ring with same variable name.") else: from sage.rings.lazy_series import LazyPowerSeries + if isinstance(f, LazyPowerSeries): if prec is infinity: try: @@ -872,6 +861,7 @@ def construction(self): True """ from sage.categories.pushout import CompletionFunctor + if self.is_sparse(): extras = {'sparse': True} else: @@ -974,7 +964,7 @@ def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): homomorphism. """ if im_gens[0] == 0: - return True # this is allowed. + return True # this is allowed. if base_map is None and not codomain.has_coerce_map_from(self.base_ring()): return False v = im_gens[0] @@ -1198,7 +1188,7 @@ def random_element(self, prec=None, *args, **kwds): """ if prec is None: prec = self.default_prec() - return self(self.__poly_ring.random_element(prec-1, *args, **kwds), prec) + return self(self.__poly_ring.random_element(prec - 1, *args, **kwds), prec) def __contains__(self, x) -> bool: """ @@ -1303,8 +1293,7 @@ def laurent_series_ring(self): except AttributeError: from .laurent_series_ring import LaurentSeriesRing - self.__laurent_series_ring = LaurentSeriesRing( - self.base_ring(), self.variable_name(), default_prec=self.default_prec(), sparse=self.is_sparse()) + self.__laurent_series_ring = LaurentSeriesRing(self.base_ring(), self.variable_name(), default_prec=self.default_prec(), sparse=self.is_sparse()) return self.__laurent_series_ring @@ -1353,8 +1342,10 @@ def _get_action_(self, other, op, self_is_left): Right action by Integer Ring on Power Series Ring in t over Rational Field """ import operator + if op is operator.floordiv and self_is_left and self.base_ring().has_coerce_map_from(other): from sage.rings.power_series_poly import BaseRingFloorDivAction + # Floor division by coefficient. return BaseRingFloorDivAction(other, self, is_left=False) return super()._get_action_(other, op, self_is_left) diff --git a/src/sage/rings/puiseux_series_ring.py b/src/sage/rings/puiseux_series_ring.py index 52b2279c1c7..427fe46b643 100644 --- a/src/sage/rings/puiseux_series_ring.py +++ b/src/sage/rings/puiseux_series_ring.py @@ -14,7 +14,6 @@ - :wikipedia:`Puiseux_series` """ - # **************************************************************************** # Copyright (c) 2016 Chris Swierczewski # @@ -56,6 +55,7 @@ class PuiseuxSeriesRing(UniqueRepresentation, Parent): sage: f.add_bigoh(1) y^(-5/6) + O(y) """ + @staticmethod def __classcall__(cls, *args, **kwds): r""" @@ -106,9 +106,7 @@ def __init__(self, laurent_series): cat = laurent_series.category() if base_ring in Fields(): cat &= Fields() - Parent.__init__(self, base_ring, - names=laurent_series.variable_names(), - category=cat) + Parent.__init__(self, base_ring, names=laurent_series.variable_names(), category=cat) def _repr_(self) -> str: """ @@ -224,6 +222,7 @@ def fraction_field(self): """ from sage.categories.integral_domains import IntegralDomains from sage.categories.fields import Fields + if self in Fields(): return self if self in IntegralDomains(): @@ -357,8 +356,7 @@ def _element_constructor_(self, x, e=1, prec=infinity): l = self._laurent_series_ring(x) e = 1 # 4. x is a Laurent or power series with the same base ring - elif (isinstance(x, (LaurentSeries, PowerSeries)) - and P is self.base_ring()): + elif isinstance(x, (LaurentSeries, PowerSeries)) and P is self.base_ring(): l = self._laurent_series_ring(x) # 5. everything else: try to coerce to laurent series ring else: @@ -409,10 +407,7 @@ def _coerce_map_from_(self, P): # Laurent series rings, power series rings, and polynomial rings with # the same variable name and the base rings are coercible - if (isinstance(P, (PuiseuxSeriesRing, LaurentSeriesRing, - PowerSeriesRing_generic, LazyPowerSeriesRing)) - and P.variable_name() == self.variable_name() - and A.has_coerce_map_from(P.base_ring())): + if isinstance(P, (PuiseuxSeriesRing, LaurentSeriesRing, PowerSeriesRing_generic, LazyPowerSeriesRing)) and P.variable_name() == self.variable_name() and A.has_coerce_map_from(P.base_ring()): return True # # other Puiseux series rings with the same variable name and diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index dcd1d87f90a..a86db99d4f2 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -644,9 +644,7 @@ class AlgebraicField_common(sage.rings.abc.AlgebraicField_common): class options(GlobalOptions): NAME = 'AlgebraicField' - display_format = dict(default='decimal', - values=dict(decimal='Always display a decimal approximation', - radical='Display using radicals (if possible)')) + display_format = dict(default='decimal', values=dict(decimal='Always display a decimal approximation', radical='Display using radicals (if possible)')) def default_interval_prec(self): r""" @@ -967,9 +965,7 @@ def _factor_multivariate_polynomial(self, f, proof=True): numfield_polynomial_flat = numfield.polynomial()(nf_gen) - polynomial_flat = sum(flat_ring({(0,) + tuple(k): 1}) - * v.polynomial()(nf_gen) - for k, v in numfield_f.monomial_coefficients().items()) + polynomial_flat = sum(flat_ring({(0,) + tuple(k): 1}) * v.polynomial()(nf_gen) for k, v in numfield_f.monomial_coefficients().items()) norm_flat = polynomial_flat.resultant(numfield_polynomial_flat, nf_gen) norm_f = norm_flat((0,) + norm_ring.gens()) @@ -1114,6 +1110,7 @@ def __init__(self): True """ from sage.categories.fields import Fields + AlgebraicField_common.__init__(self, self, ('x',), normalize=False, category=Fields().Infinite()) self._populate_coercion_lists_([ZZ, QQ]) @@ -1261,6 +1258,7 @@ def completion(self, p, prec, extras={}): """ if p == infinity.Infinity: from sage.rings.real_field import create_RealField + return create_RealField(prec, **extras) raise NotImplementedError @@ -1309,7 +1307,7 @@ def gens(self) -> tuple: sage: AA.gens() (1,) """ - return (self(1), ) + return (self(1),) def gen(self, n=0): r""" @@ -1546,10 +1544,8 @@ def _factor_univariate_polynomial(self, f): cr = [(r, e) for r, e in f.roots(QQbar) if r.imag() > 0] from sage.structure.factorization import Factorization - return Factorization( - [(f.parent()([-r, 1]), e) for r, e in rr] + - [(f.parent()([r.norm(), -2 * r.real(), 1]), e) for r, e in cr], - unit=f.leading_coefficient()) + + return Factorization([(f.parent()([-r, 1]), e) for r, e in rr] + [(f.parent()([r.norm(), -2 * r.real(), 1]), e) for r, e in cr], unit=f.leading_coefficient()) # Create the globally unique AlgebraicRealField object. @@ -1622,6 +1618,7 @@ def __init__(self): True """ from sage.categories.fields import Fields + AlgebraicField_common.__init__(self, AA, ('I',), normalize=False, category=Fields().Infinite()) self._populate_coercion_lists_([ZZ, QQ]) @@ -1741,6 +1738,7 @@ def completion(self, p, prec, extras={}): """ if p == infinity.Infinity: from sage.rings.real_field import create_RealField + return create_RealField(prec, **extras).complex_field() raise NotImplementedError @@ -1768,6 +1766,7 @@ def construction(self): """ from sage.categories.pushout import AlgebraicClosureFunctor from sage.rings.rational_field import QQ + return (AlgebraicClosureFunctor(), QQ) def gens(self) -> tuple: @@ -1980,6 +1979,7 @@ def random_element(self, poly_degree=2, *args, **kwds): """ import sage.misc.prandom from sage.rings.integer_ring import ZZ + try: poly_degree = ZZ(poly_degree) except TypeError: @@ -2076,8 +2076,8 @@ def _factor_univariate_polynomial(self, f): (5) * (x - 16) * (x - 5) * (x - 1.959674775249769?) * (x - 1.427050983124843? - 3.665468789467727?*I) * (x - 1.427050983124843? + 3.665468789467727?*I) * (x + 0.9549150281252629? - 0.8652998037182486?*I) * (x + 0.9549150281252629? + 0.8652998037182486?*I) * (x + 1.927050983124843? - 1.677599044300515?*I) * (x + 1.927050983124843? + 1.677599044300515?*I) * (x + 2.959674775249769?) * (x + 6.545084971874737? - 7.106423590645660?*I) * (x + 6.545084971874737? + 7.106423590645660?*I) """ from sage.structure.factorization import Factorization - return Factorization([(f.parent()([-r, 1]), e) for r, e in f.roots()], - unit=f.leading_coefficient()) + + return Factorization([(f.parent()([-r, 1]), e) for r, e in f.roots()], unit=f.leading_coefficient()) # Create the globally unique AlgebraicField object. @@ -2164,7 +2164,7 @@ def rational_exact_root(r, d): (den_rt, den_exact) = den.nth_root(d, truncate_mode=1) if not den_exact: return None - return (num_rt / den_rt) + return num_rt / den_rt def clear_denominators(poly): @@ -2471,9 +2471,7 @@ def conjugate_shrink(v): return v -def number_field_elements_from_algebraics(numbers, minimal=False, - same_field=False, - embedded=False, name='a', prec=53): +def number_field_elements_from_algebraics(numbers, minimal=False, same_field=False, embedded=False, name='a', prec=53): r""" Given a sequence of elements of either ``AA`` or ``QQbar`` (or a mixture), computes a number field containing all of these @@ -2907,8 +2905,7 @@ def mk_algebraic(x): # if the default embedding is different from what is expected then modify the field if embedded != (fld.coerce_embedding() is not None): # creates the modified field - modified_field = NumberField(fld.defining_polynomial(), fld.variable_name(), - embedding=exact_generator if embedded else None) + modified_field = NumberField(fld.defining_polynomial(), fld.variable_name(), embedding=exact_generator if embedded else None) # embeds the numbers inter_hom = fld.hom([modified_field.gen(0)]) @@ -2989,8 +2986,7 @@ def cmp_elements_with_same_minpoly(a, b, p): real = ar.union(br) imag = ai.union(bi) - oroots = [r for r in roots if r._value.real().overlaps(real) - and r._value.imag().overlaps(imag)] + oroots = [r for r in roots if r._value.real().overlaps(real) and r._value.imag().overlaps(imag)] if not oroots: raise RuntimeError('a = {}\nb = {}\np = {}'.format(a, b, p)) if len(oroots) == 1: @@ -3001,8 +2997,7 @@ def cmp_elements_with_same_minpoly(a, b, p): # test whether we have a conjugated pair (in which situation # real part are equal) imag = ai.abs().union(bi.abs()) - oroots = [r for r in roots if r._value.real().overlaps(real) - and r._value.imag().abs().overlaps(imag)] + oroots = [r for r in roots if r._value.real().overlaps(real) and r._value.imag().abs().overlaps(imag)] if len(oroots) == 2 and not oroots[0]._value.imag().contains_zero(): # There is a complex conjugate pair of roots matching both # descriptors, so compare by imaginary value. @@ -3029,6 +3024,7 @@ class AlgebraicGeneratorRelation(SageObject): A simple class for maintaining relations in the lattice of algebraic extensions. """ + def __init__(self, child1, child1_poly, child2, child2_poly, parent): r""" EXAMPLES:: @@ -3087,7 +3083,7 @@ def __init__(self, field, root): """ self._field = field self._pari_field = None - self._trivial = (field is QQ) + self._trivial = field is QQ self._root = root self._root_as_algebraic = (QQbar if root.is_complex() else AA)(root) self._unions = {} @@ -3189,8 +3185,7 @@ def _repr_(self): """ if self._trivial: return 'Trivial generator' - return '%s with %s in %s' % (self._field, self._field.gen(), - self._root._interval_fast(53)) + return '%s with %s in %s' % (self._field, self._field.gen(), self._root._interval_fast(53)) def root_as_algebraic(self): r""" @@ -3368,13 +3363,12 @@ def find_fn(p, prec): if_poly = ifield['x', 'y'] ip = if_poly(p) return ip(other._root._interval_fast(prec), self._root._interval_fast(prec)) + my_factor = find_zero_result(find_fn, factors_sage) if my_factor.degree(x) == 1 and my_factor.coefficient(x) == 1: value = (-my_factor + x).univariate_polynomial(QQy) - rel = AlgebraicGeneratorRelation(self, QQy_y, - other, value, - self) + rel = AlgebraicGeneratorRelation(self, QQy_y, other, value, self) self._unions[other] = rel other._unions[self] = rel return rel.parent @@ -3396,13 +3390,11 @@ def find_fn(p, prec): def intv_fn(prec): return conjugate_expand(red_elt(self._root._interval_fast(prec) * k + other._root._interval_fast(prec))) + new_intv = conjugate_shrink(isolating_interval(intv_fn, red_pol)) new_gen = AlgebraicGenerator(new_nf, ANRoot(QQx(red_pol), new_intv)) - rel = AlgebraicGeneratorRelation(self, self_pol_sage(red_back_x), - other, - (QQx_x - k * self_pol_sage)(red_back_x), - new_gen) + rel = AlgebraicGeneratorRelation(self, self_pol_sage(red_back_x), other, (QQx_x - k * self_pol_sage)(red_back_x), new_gen) self._unions[other] = rel other._unions[self] = rel return new_gen @@ -3454,7 +3446,7 @@ def super_poly(self, super, checked=None): continue if self is u.child1: return u.child1_poly(poly) - assert (self is u.child2) + assert self is u.child2 return u.child2_poly(poly) return None @@ -3502,7 +3494,7 @@ def __call__(self, elt): return elt.field_element_value() gen = elt.generator() sp = gen.super_poly(self) - assert (sp is not None) + assert sp is not None return self._field(elt.field_element_value().polynomial()(sp)) @@ -3519,6 +3511,7 @@ class ANDescr(SageObject): ``ANDescr`` and all of its subclasses are for internal use, and should not be used directly. """ + def is_simple(self) -> bool: r""" Check whether this descriptor represents a value with the same @@ -3723,8 +3716,7 @@ def __init__(self, parent, x): 22/7 """ sage.structure.element.FieldElement.__init__(self, parent) - if isinstance(x, (int, sage.rings.integer.Integer, - sage.rings.rational.Rational)): + if isinstance(x, (int, sage.rings.integer.Integer, sage.rings.rational.Rational)): self._descr = ANRational(x) elif isinstance(x, ANDescr): self._descr = x @@ -3822,6 +3814,7 @@ def _latex_(self): sage: AA.options.display_format = 'decimal' """ from sage.misc.latex import latex + if isinstance(self._descr, ANRational): return latex(self._descr._value) if isinstance(self._descr, ANExtensionElement) and self._descr._generator is QQbar_I_generator: @@ -3883,8 +3876,7 @@ def _sage_input_(self, sib, coerce): sage: sqrt(QQbar(7))._sage_input_(sib, False) {call: {getattr: {atomic:QQbar}.polynomial_root}({call: {getattr: {atomic:AA}.common_polynomial}({binop:- {binop:** {gen:x {constr_parent: {subscr: {atomic:QQbar}[{atomic:'x'}]} with gens: ('x',)}} {atomic:2}} {atomic:7}})}, {call: {atomic:CIF}({call: {atomic:RIF}({call: {atomic:RR}({atomic:2.6457513110645903})}, {call: {atomic:RR}({atomic:2.6457513110645907})})}, {call: {atomic:RIF}({call: {atomic:RR}({atomic:0})})})})} """ - (v, complicated) = \ - self._descr.handle_sage_input(sib, coerce, self.parent() is QQbar) + (v, complicated) = self._descr.handle_sage_input(sib, coerce, self.parent() is QQbar) if complicated or True: sib.id_cache(self, v, 'v') return v @@ -4777,8 +4769,7 @@ def interval(self, field): """ target = RR(1.0) >> field.prec() val = self.interval_diameter(target) - if (isinstance(field, (RealIntervalField_class, RealBallField)) - and isinstance(val, ComplexIntervalFieldElement)): + if isinstance(field, (RealIntervalField_class, RealBallField)) and isinstance(val, ComplexIntervalFieldElement): if val.imag().is_zero(): return field(val.real()) if self.imag().is_zero(): @@ -4853,8 +4844,7 @@ def radical_expression(self): return self itv = interval_field(self._value) while True: - candidates = [root for root in roots - if interval_field(root).overlaps(itv)] + candidates = [root for root in roots if interval_field(root).overlaps(itv)] if len(candidates) == 1: return candidates[0] roots = candidates @@ -4897,6 +4887,7 @@ class AlgebraicNumber(AlgebraicNumber_base): .. automethod:: _richcmp_ """ + def __init__(self, x): r""" Initialize this AlgebraicNumber object. @@ -4919,7 +4910,7 @@ def __reduce__(self): sage: loads(dumps(t)) == t True """ - return (AlgebraicNumber, (self._descr, )) + return (AlgebraicNumber, (self._descr,)) def _richcmp_(self, other, op): r""" @@ -5069,9 +5060,7 @@ def _richcmp_(self, other, op): return bool(other) == (op == op_NE) if isinstance(od, ANRational) and not od._value: return bool(self) == (op == op_NE) - if (isinstance(sd, ANExtensionElement) and - isinstance(od, ANExtensionElement) and - sd._generator is od._generator): + if isinstance(sd, ANExtensionElement) and isinstance(od, ANExtensionElement) and sd._generator is od._generator: return sd._value == od._value if op == op_EQ else sd._value != od._value # case 2: possibly equal or conjugate values @@ -5460,6 +5449,7 @@ class AlgebraicReal(AlgebraicNumber_base): .. automethod:: _richcmp_ """ + def __init__(self, x): """ Create an algebraic real from x, possibly taking the real part of x. @@ -5537,7 +5527,7 @@ def __reduce__(self): sage: loads(dumps(t)) == t # needs sage.symbolic True """ - return (AlgebraicReal, (self._descr, )) + return (AlgebraicReal, (self._descr,)) def _richcmp_(self, other, op): """ @@ -5604,9 +5594,7 @@ def _richcmp_(self, other, op): return bool(other) == (op == op_NE) if type(od) is ANRational and not od._value: return bool(self) == (op == op_NE) - if (type(sd) is ANExtensionElement and - type(od) is ANExtensionElement and - sd._generator is od._generator): + if type(sd) is ANExtensionElement and type(od) is ANExtensionElement and sd._generator is od._generator: return sd._value == od._value if op == op_EQ else sd._value != od._value # Only compare the minimal polynomials if they have been computed # as otherwise it calls exactify(). @@ -6088,8 +6076,7 @@ def interval_exact(self, field): top = val.upper() prbot = pbot.parent()(bot) prtop = ptop.parent()(top) - if bot == top or (bot.nextabove() == top and - prbot < pbot and ptop < prtop): + if bot == top or (bot.nextabove() == top and prbot < pbot and ptop < prtop): return val # Even 40 extra bits of precision are not enough to prove that @@ -6105,8 +6092,7 @@ def interval_exact(self, field): top = val.upper() prbot = pbot.parent()(bot) prtop = ptop.parent()(top) - if bot == top or (bot.nextabove() == top and - prbot < pbot and ptop < prtop): + if bot == top or (bot.nextabove() == top and prbot < pbot and ptop < prtop): return val self._more_precision() @@ -6386,6 +6372,7 @@ class AlgebraicNumberPowQQAction(Action): sage: (AA(2)^(1/2)-AA(2)^(1/2))^(1/2) 0 """ + def __init__(self, G, S): """ EXAMPLES:: @@ -6442,7 +6429,7 @@ def _act_(self, e, x): if rt is not None: if x._descr._value < 0: if S is AA: - return AlgebraicReal(ANRational((-rt)**n)) + return AlgebraicReal(ANRational((-rt) ** n)) z = QQbar.zeta(2 * d)._pow_int(n) return z * AlgebraicNumber(ANRational(rt**n)) return S(ANRational(rt**n)) @@ -6450,7 +6437,7 @@ def _act_(self, e, x): if S is AA: # Result lies in AA pow_n = x._pow_int(n) - poly = AAPoly.gen()**d - pow_n + poly = AAPoly.gen() ** d - pow_n range = pow_n.interval_fast(RIF) if d % 2 == 0: result_min = 0 @@ -6465,7 +6452,7 @@ def _act_(self, e, x): val = x._interval_fast(prec) abs_val = abs(val) if abs_val.relative_diameter() < RR_1_10: - target_abs = abs_val ** e + target_abs = abs_val**e if target_abs.relative_diameter() < RR_1_10: # val definitely doesn't contain zero, it's safe to take argument argument = val.argument() @@ -6493,12 +6480,11 @@ def _act_(self, e, x): break pow_n = x**n - poly = QQbarPoly.gen()**d - pow_n + poly = QQbarPoly.gen() ** d - pow_n prec = target_abs.prec() target_real = 0 if argument_is_pi and d == 2 else target_arg.cos() * target_abs - target = ComplexIntervalField(prec)(target_real, - target_arg.sin() * target_abs) + target = ComplexIntervalField(prec)(target_real, target_arg.sin() * target_abs) return AlgebraicNumber(ANRoot(poly, target)) @@ -6519,8 +6505,7 @@ def __init__(self, x): sage: polygen(QQbar) / int(3) 1/3*x """ - if isinstance(x, (sage.rings.integer.Integer, - sage.rings.rational.Rational)): + if isinstance(x, (sage.rings.integer.Integer, sage.rings.rational.Rational)): self._value = x elif isinstance(x, int): self._value = ZZ(x) @@ -6538,7 +6523,7 @@ def __reduce__(self): sage: loads(dumps(t)) == t True """ - return (ANRational, (self._value, )) + return (ANRational, (self._value,)) def _repr_(self): r""" @@ -6818,7 +6803,7 @@ def __reduce__(self): sage: loads(dumps(v)) == v True """ - return (AlgebraicPolynomialTracker, (self._poly, )) + return (AlgebraicPolynomialTracker, (self._poly,)) def _sage_input_(self, sib, coerce): r""" @@ -6919,6 +6904,7 @@ def complex_roots(self, prec, multiplicity): p = p.derivative() from sage.rings.polynomial.complex_roots import complex_roots + roots_mult = complex_roots(p, min_prec=prec) roots = [rt for (rt, mult) in roots_mult if mult == 1] self._roots_cache[multiplicity] = (prec, roots) @@ -7022,6 +7008,7 @@ class ANRoot(ANDescr): root of a polynomial with algebraic coefficients. This class is private, and should not be used directly. """ + def __init__(self, poly, interval, multiplicity=1): r""" Initialize this ``ANRoot`` object. @@ -7278,9 +7265,7 @@ def _real_refine_interval(self, interval, prec): while True: assert l == interval.lower() assert u == interval.upper() - assert pl.contains_zero() or \ - pu.contains_zero() or \ - pl.unique_sign() != pu.unique_sign() + assert pl.contains_zero() or pu.contains_zero() or pl.unique_sign() != pu.unique_sign() # Use a simple algorithm: # Try an interval Newton-Raphson step. If this does not add at @@ -7568,10 +7553,11 @@ def exactify(self): def find_fn(factor, prec): return factor(self._interval_fast(prec)) + my_factor = find_zero_result(find_fn, qpf) # Factoring always returns monic polynomials over the rationals - assert (my_factor.is_monic()) + assert my_factor.is_monic() if my_factor.degree() == 1: return ANRational(-my_factor[0]) @@ -7584,6 +7570,7 @@ def find_fn(factor, prec): def intv_fn(rif): return conjugate_expand(red_elt(self._interval_fast(rif) * den)) + new_intv = conjugate_shrink(isolating_interval(intv_fn, red_pol)) root = ANRoot(QQx(red_pol), new_intv) new_gen = AlgebraicGenerator(field, root) @@ -7611,9 +7598,10 @@ def find_fn(factor, prec): if_poly = ComplexIntervalField(prec)['x'] ip = if_poly(v) return ip(self_val) + my_factor = find_zero_result(find_fn, fpf) - assert (my_factor.is_monic()) + assert my_factor.is_monic() if my_factor.degree() == 1: return ANExtensionElement(gen, -my_factor[0]) @@ -7645,12 +7633,13 @@ def find_fn(factor, prec): def intv_fn(prec): return conjugate_expand(red_elt(gen._interval_fast(prec) * k + self._interval_fast(prec) * den)) + new_intv = conjugate_shrink(isolating_interval(intv_fn, red_pol)) root = ANRoot(QQx(red_pol), new_intv) new_gen = AlgebraicGenerator(new_nf, root) red_back_a = red_back(new_nf.gen()) - new_poly = ((QQx_x - k * self_pol_sage)(red_back_a) / den) + new_poly = (QQx_x - k * self_pol_sage)(red_back_a) / den return ANExtensionElement(new_gen, new_poly) def _more_precision(self): @@ -7734,10 +7723,7 @@ def __reduce__(self): def _repr_(self): fgen = self._generator._field.gen() sgen = str(fgen) - return '%s where %s = 0 and %s in %s' % (self._value, - self._generator.field().polynomial()._repr(name=sgen), - sgen, - self._generator._interval_fast(53)) + return '%s where %s = 0 and %s in %s' % (self._value, self._generator.field().polynomial()._repr(name=sgen), sgen, self._generator._interval_fast(53)) def handle_sage_input(self, sib, coerce, is_qqbar): r""" @@ -7777,7 +7763,7 @@ def handle_sage_input(self, sib, coerce, is_qqbar): ({call: {atomic:QQbar}({binop:+ {atomic:1} {atomic:I}})}, True) """ if self._generator is QQbar_I_generator: - assert (is_qqbar) + assert is_qqbar re, im = self._value.list() im_part = sib.prod([sib(im, True), sib.name('I')], simplify=True) v = sib.sum([sib(re, True), im_part], simplify=True) @@ -7798,7 +7784,7 @@ def handle_sage_input(self, sib, coerce, is_qqbar): for i in range(len(coeffs) - 1, -1, -1): if i > 0: if i > 1: - rt_pow = rt**sib.int(i) + rt_pow = rt ** sib.int(i) else: rt_pow = rt terms.append(sib.prod((coeffs[i], rt_pow), simplify=True)) @@ -7861,7 +7847,7 @@ def is_simple(self) -> bool: try: return self._is_simple except AttributeError: - self._is_simple = (self.minpoly().degree() == self.generator().field().degree()) + self._is_simple = self.minpoly().degree() == self.generator().field().degree() return self._is_simple def generator(self): @@ -8509,9 +8495,7 @@ def handle_sage_input(self, sib, coerce, is_qqbar): arg1_is_qqbar = arg1.parent() is QQbar arg2_is_qqbar = arg2.parent() is QQbar - result_is_qqbar = \ - (arg1_is_qqbar and not arg1_coerced) or \ - (arg2_is_qqbar and not arg2_coerced) + result_is_qqbar = (arg1_is_qqbar and not arg1_coerced) or (arg2_is_qqbar and not arg2_coerced) v1 = sib(arg1, arg1_coerced) v2 = sib(arg2, arg2_coerced) @@ -8758,9 +8742,7 @@ def an_binop_element(a, b, op): # instanciation of the multimethod dispatch _binop_algo[ANRational, ANRational] = an_binop_rational -_binop_algo[ANRational, ANExtensionElement] = \ - _binop_algo[ANExtensionElement, ANRational] = \ - _binop_algo[ANExtensionElement, ANExtensionElement] = an_binop_element +_binop_algo[ANRational, ANExtensionElement] = _binop_algo[ANExtensionElement, ANRational] = _binop_algo[ANExtensionElement, ANExtensionElement] = an_binop_element for t1 in (ANRational, ANRoot, ANExtensionElement, ANUnaryExpr, ANBinaryExpr): for t2 in (ANUnaryExpr, ANBinaryExpr, ANRoot): @@ -8792,7 +8774,7 @@ def _init_qqbar(): AA_0 = AA.zero() QQbar_I_nf = GaussianField() - QQbar_I_generator = AlgebraicGenerator(QQbar_I_nf, ANRoot(AAPoly.gen()**2 + 1, CIF(0, 1))) + QQbar_I_generator = AlgebraicGenerator(QQbar_I_nf, ANRoot(AAPoly.gen() ** 2 + 1, CIF(0, 1))) QQbar_I = AlgebraicNumber(ANExtensionElement(QQbar_I_generator, QQbar_I_nf.gen())) AA_hash_offset = AA(~ZZ(123456789)) @@ -8820,7 +8802,7 @@ def get_AA_golden_ratio(): global AA_golden_ratio if AA_golden_ratio is None: AA_golden_ratio_nf = NumberField(ZZX_x**2 - ZZX_x - 1, 'phi') - AA_golden_ratio_generator = AlgebraicGenerator(AA_golden_ratio_nf, ANRoot(AAPoly.gen()**2 - AAPoly.gen() - 1, RIF(1.618, 1.6181))) + AA_golden_ratio_generator = AlgebraicGenerator(AA_golden_ratio_nf, ANRoot(AAPoly.gen() ** 2 - AAPoly.gen() - 1, RIF(1.618, 1.6181))) AA_golden_ratio = AlgebraicReal(ANExtensionElement(AA_golden_ratio_generator, AA_golden_ratio_nf.gen())) return AA_golden_ratio diff --git a/src/sage/rings/qqbar_decorators.py b/src/sage/rings/qqbar_decorators.py index e3339877bf7..3337f15e33a 100644 --- a/src/sage/rings/qqbar_decorators.py +++ b/src/sage/rings/qqbar_decorators.py @@ -90,10 +90,7 @@ def wrapper(*args, **kwds): from sage.rings.ideal import Ideal, Ideal_generic from sage.rings.abc import AlgebraicField_common - if not any(isinstance(a, (Polynomial, MPolynomial, Ideal_generic)) - and isinstance(a.base_ring(), AlgebraicField_common) - or isinstance(a, PolynomialSequence_generic) - and isinstance(a.ring().base_ring(), AlgebraicField_common) for a in args): + if not any(isinstance(a, (Polynomial, MPolynomial, Ideal_generic)) and isinstance(a.base_ring(), AlgebraicField_common) or isinstance(a, PolynomialSequence_generic) and isinstance(a.ring().base_ring(), AlgebraicField_common) for a in args): return func(*args, **kwds) polynomials = [] @@ -112,6 +109,7 @@ def wrapper(*args, **kwds): # same_field=True might trigger an exception otherwise. from sage.rings.qqbar import number_field_elements_from_algebraics + numfield, new_elems, morphism = number_field_elements_from_algebraics(orig_elems, same_field=True, minimal=True) elem_dict = dict(zip(orig_elems, new_elems)) @@ -124,12 +122,11 @@ def forward_map(item): if isinstance(item, MPolynomial): return item.map_coefficients(elem_dict.__getitem__, new_base_ring=numfield) if isinstance(item, PolynomialSequence_generic): - return PolynomialSequence(map(forward_map, item), - immutable=item.is_immutable()) + return PolynomialSequence(map(forward_map, item), immutable=item.is_immutable()) if isinstance(item, list): return list(map(forward_map, item)) if isinstance(item, dict): - return {k: forward_map(v) for k,v in item.items()} + return {k: forward_map(v) for k, v in item.items()} if isinstance(item, tuple): return tuple(map(forward_map, item)) if isinstance(item, set): @@ -144,8 +141,7 @@ def reverse_map(item): if isinstance(item, MPolynomial): return item.map_coefficients(morphism) if isinstance(item, PolynomialSequence_generic): - return PolynomialSequence(map(reverse_map, item), - immutable=item.is_immutable()) + return PolynomialSequence(map(reverse_map, item), immutable=item.is_immutable()) if isinstance(item, list): return list(map(reverse_map, item)) if isinstance(item, tuple): diff --git a/src/sage/rings/quotient_ring.py b/src/sage/rings/quotient_ring.py index 4d50c28f7d3..77278a91b74 100644 --- a/src/sage/rings/quotient_ring.py +++ b/src/sage/rings/quotient_ring.py @@ -99,6 +99,7 @@ sage: Q2.is_commutative() True """ + # **************************************************************************** # Copyright (C) 2005 William Stein # @@ -285,6 +286,7 @@ def QuotientRing(R, I, names=None, **kwds): # 2. We want to support quotients of free algebras by homogeneous two-sided ideals. from sage.rings.finite_rings.integer_mod_ring import Integers from sage.rings.integer_ring import ZZ + if R not in _Rings: raise TypeError("R must be a ring") is_commutative = R in _CommRings @@ -299,10 +301,12 @@ def QuotientRing(R, I, names=None, **kwds): from sage.rings.polynomial.polynomial_ring_constructor import ( BooleanPolynomialRing_constructor as BooleanPolynomialRing, ) + kwds.pop('implementation') return BooleanPolynomialRing(R.ngens(), names=names, **kwds) # workaround to silence warning from #34806 from sage.rings.abc import Order + if isinstance(R, Order): if not R.is_maximal(): raise NotImplementedError('only implemented for maximal orders') @@ -410,6 +414,7 @@ class QuotientRing_nc(Parent): sage: T.gens() (0, d) """ + Element = quotient_ring_element.QuotientRingElement def __init__(self, R, I, names, category=None): @@ -441,6 +446,7 @@ def __init__(self, R, I, names, category=None): raise TypeError("The first argument must be a ring, but %s is not" % R) # workaround to silence warning from #34806 from sage.rings.abc import Order + if isinstance(R, Order): M = R.number_field().ideal_monoid() else: @@ -500,6 +506,7 @@ def construction(self): # Is there a better generic way to distinguish between things like Z/pZ as a field and Z/pZ as a ring? from sage.rings.ring import Field + try: names = self.variable_names() except ValueError: @@ -508,11 +515,8 @@ def construction(self): except ValueError: names = None if self in _CommRings: - return QuotientFunctor(self.__I, names=names, domain=_CommRings, - codomain=_CommRings, - as_field=isinstance(self, Field)), self.__R - return QuotientFunctor(self.__I, names=names, - as_field=isinstance(self, Field)), self.__R + return QuotientFunctor(self.__I, names=names, domain=_CommRings, codomain=_CommRings, as_field=isinstance(self, Field)), self.__R + return QuotientFunctor(self.__I, names=names, as_field=isinstance(self, Field)), self.__R def _repr_(self): """ @@ -586,6 +590,7 @@ def is_commutative(self) -> bool: except (AttributeError, NotImplementedError): pass from sage.rings.infinity import Infinity + if self.ngens() == Infinity: raise NotImplementedError("This quotient ring has an infinite number of generators.") for i in range(self.ngens()): @@ -637,6 +642,7 @@ def cover(self): return self.__cover except AttributeError: from . import morphism + pi = morphism.RingHomomorphism_cover(self.__R.Hom(self)) lift = self.lifting_map() pi._set_lift(lift) @@ -705,6 +711,7 @@ def lifting_map(self): except AttributeError: pass from .morphism import RingMap_lift + m = RingMap_lift(self, self.__R) self.__lift = m return m @@ -953,6 +960,7 @@ def ideal(self, *gens, **kwds): from sage.rings.polynomial.multi_polynomial_ring_base import ( MPolynomialRing_base, ) + if not (isinstance(self.__R, MPolynomialRing_base) and self.__R._has_singular): # pass through return super().ideal(gens, **kwds) @@ -1113,8 +1121,7 @@ def __richcmp__(self, other, op): """ if not isinstance(other, QuotientRing_nc): return NotImplemented - return richcmp((self.cover_ring(), self.defining_ideal().gens()), - (other.cover_ring(), other.defining_ideal().gens()), op) + return richcmp((self.cover_ring(), self.defining_ideal().gens()), (other.cover_ring(), other.defining_ideal().gens()), op) def ngens(self): r""" @@ -1195,8 +1202,7 @@ def gens(self) -> tuple: sage: S.gens() (xbar, ybar) """ - return tuple(self(self.__R.gen(i)) - for i in range(self.cover_ring().ngens())) + return tuple(self(self.__R.gen(i)) for i in range(self.cover_ring().ngens())) def _singular_(self, singular=None): """ @@ -1364,8 +1370,7 @@ def __init__(self, R, I, names, category=None): if R not in _CommRings: raise TypeError("This class is for quotients of commutative rings only.\n For non-commutative rings, use ") if not self._is_category_initialized(): - category = check_default_category(_CommutativeRingsQuotients, - category) + category = check_default_category(_CommutativeRingsQuotients, category) QuotientRing_nc.__init__(self, R, I, names, category=category) def _macaulay2_init_(self, macaulay2=None): @@ -1422,6 +1427,7 @@ def _macaulay2_init_(self, macaulay2=None): """ if macaulay2 is None: from sage.interfaces.macaulay2 import macaulay2 as m2_default + macaulay2 = m2_default I = self.defining_ideal()._macaulay2_(macaulay2) return I.ring()._operator('/', I) diff --git a/src/sage/rings/quotient_ring_element.py b/src/sage/rings/quotient_ring_element.py index a55ed50671d..e74e7bb041f 100644 --- a/src/sage/rings/quotient_ring_element.py +++ b/src/sage/rings/quotient_ring_element.py @@ -81,6 +81,7 @@ class QuotientRingElement(RingElement): sage: (a^3 + b^2).lift() -x*y^2 + y^2 """ + def __init__(self, parent, rep, reduce=True): """ An element of a quotient ring `R/I`. See @@ -180,6 +181,7 @@ def is_unit(self): if self.__rep.is_unit(): return True from sage.categories.fields import Fields + if self.parent() in Fields(): return not self.is_zero() try: @@ -210,6 +212,7 @@ def _repr_(self): Sq(1) """ from sage.structure.parent_gens import localvars + P = self.parent() R = P.cover_ring() # We print by temporarily (and safely!) changing the variable @@ -240,6 +243,7 @@ def _latex_(self): a """ from sage.structure.parent_gens import localvars + P = self.parent() R = P.cover_ring() # see _repr_ above for the idea @@ -446,8 +450,7 @@ def _div_(self, right): try: XY = L.lift((R,) + tuple(B)) except ValueError: - raise ArithmeticError("Division failed. The numerator is not " - "a multiple of the denominator.") + raise ArithmeticError("Division failed. The numerator is not " "a multiple of the denominator.") return P(XY[0]) def _im_gens_(self, codomain, im_gens, base_map=None): @@ -539,6 +542,7 @@ def _rational_(self): """ from sage.rings.rational_field import QQ + return QQ(self.lift()) def __neg__(self): @@ -591,7 +595,7 @@ def __invert__(self): try: inv = self.__rep.inverse_mod(self.parent().defining_ideal()) except NotImplementedError: - return self.parent().one()/self + return self.parent().one() / self return self.__class__(self.parent(), inv) def __float__(self): @@ -907,6 +911,7 @@ def _macaulay2_(self, macaulay2=None): """ if macaulay2 is None: from sage.interfaces.macaulay2 import macaulay2 as m2_default + macaulay2 = m2_default m2_parent = self.parent()._macaulay2_(macaulay2) macaulay2.use(m2_parent) diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index 716808a8e8f..eb665e6ed16 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -130,6 +130,7 @@ class RationalField(Singleton, number_field_base.NumberField): sage: QQ(RealField(45)(t)) 1/5 """ + def __new__(cls): """ This method actually is not needed for using :class:`RationalField`. @@ -144,6 +145,7 @@ def __new__(cls): return QQ except BaseException: from sage.rings.number_field.number_field_base import NumberField + return NumberField.__new__(cls) def __init__(self): @@ -231,9 +233,8 @@ def __init__(self): """ from sage.categories.basic import QuotientFields from sage.categories.number_fields import NumberFields - Parent.__init__(self, base=self, - category=[QuotientFields().Metric(), - NumberFields()]) + + Parent.__init__(self, base=self, category=[QuotientFields().Metric(), NumberFields()]) self._assign_names(('x',), normalize=False) # ????? self._populate_coercion_lists_(init_no_parent=True) @@ -317,6 +318,7 @@ def construction(self): from sage.categories.pushout import FractionField from . import integer_ring + return FractionField(), integer_ring.ZZ def completion(self, p, prec, extras={}): @@ -331,10 +333,13 @@ def completion(self, p, prec, extras={}): 5-adic Field with capped relative precision 15 """ from sage.rings.infinity import Infinity + if p == Infinity: from sage.rings.real_field import create_RealField + return create_RealField(prec, **extras) from sage.rings.padics.factory import Qp + return Qp(p, prec, **extras) def _coerce_map_from_(self, S): @@ -368,8 +373,10 @@ def _coerce_map_from_(self, S): """ global ZZ from . import rational + if ZZ is None: from . import integer_ring + ZZ = integer_ring.ZZ if S is ZZ: return rational.Z_to_Q() @@ -378,9 +385,11 @@ def _coerce_map_from_(self, S): if ZZ.has_coerce_map_from(S): return rational.Z_to_Q() * ZZ._internal_coerce_map_from(S) from sage.rings.localization import Localization + if isinstance(S, Localization): if S.fraction_field() is self: from sage.structure.coerce_maps import CallableConvertMap + return CallableConvertMap(S, self, lambda x: x._value, parent_as_first_arg=False) def _is_valid_homomorphism_(self, codomain, im_gens, base_map=None): @@ -430,10 +439,10 @@ def __iter__(self): height = height + 1 for other in range(1, height): if height.gcd(other) == 1: - yield self(other/height) - yield self(-other/height) - yield self(height/other) - yield self(-height/other) + yield self(other / height) + yield self(-other / height) + yield self(height / other) + yield self(-height / other) def __truediv__(self, I): """ @@ -446,6 +455,7 @@ def __truediv__(self, I): """ from sage.groups.additive_abelian.qmodnz import QmodnZ from sage.rings.ideal import Ideal_generic + if I is ZZ: return QmodnZ(1) if isinstance(I, Ideal_generic) and I.base_ring() is ZZ: @@ -499,10 +509,10 @@ def range_by_height(self, start, end=None): yield self(-1) for other in ZZ.range(1, height): if height.gcd(other) == 1: - yield self(other/height) - yield self(-other/height) - yield self(height/other) - yield self(-height/other) + yield self(other / height) + yield self(-other / height) + yield self(height / other) + yield self(-height / other) def primes_of_bounded_norm_iter(self, B): r""" @@ -536,6 +546,7 @@ def primes_of_bounded_norm_iter(self, B): return from sage.arith.misc import primes + yield from primes(B + 1) def discriminant(self): @@ -632,8 +643,7 @@ def automorphisms(self): [Ring endomorphism of Rational Field Defn: 1 |--> 1] """ - return Sequence([self.hom(1, self)], cr=True, immutable=False, - check=False) + return Sequence([self.hom(1, self)], cr=True, immutable=False, check=False) def places(self, all_complex=False, prec=None): r""" @@ -670,6 +680,7 @@ def places(self, all_complex=False, prec=None): Defn: 1 |--> 1.0000000000000000000000000000000000000000000000000000000000] """ from sage.rings.infinity import Infinity + if prec is None: if all_complex: from sage.rings.cc import CC as domain @@ -687,9 +698,11 @@ def places(self, all_complex=False, prec=None): from sage.rings.qqbar import AA as domain elif all_complex: from sage.rings.complex_mpfr import ComplexField + domain = ComplexField(prec) else: from sage.rings.real_mpfr import RealField + domain = RealField(prec) return [self.hom([domain(1)])] @@ -711,6 +724,7 @@ def complex_embedding(self, prec=53): Defn: 1 |--> 1.0000 """ from . import complex_mpfr + CC = complex_mpfr.ComplexField(prec) return self.hom([CC(1)]) @@ -736,6 +750,7 @@ def residue_field(self, p, check=True): Residue field of Integers modulo 1000000007 """ from sage.rings.finite_rings.residue_field import ResidueField + return ResidueField(ZZ.ideal(p), check=check) def hilbert_symbol_negative_at_S(self, S, b, check=True): @@ -851,15 +866,12 @@ def hilbert_symbol_negative_at_S(self, S, b, check=True): for p in S: if p != infty: if check and not is_prime(p): - raise ValueError("all entries in list must be prime" - " or -1 for infinite place") + raise ValueError("all entries in list must be prime" " or -1 for infinite place") R = Qp(p) if R(b).is_square(): - raise ValueError("second argument must be a nonsquare with" - " respect to every finite prime in the list") + raise ValueError("second argument must be a nonsquare with" " respect to every finite prime in the list") elif b > 0: - raise ValueError("if the infinite place is in the list, " - "the second argument must be negative") + raise ValueError("if the infinite place is in the list, " "the second argument must be negative") # L is the list of primes that we need to consider, b must have # nonzero valuation for each prime in L, this is the set S' # in Kirschmer's algorithm @@ -878,7 +890,7 @@ def hilbert_symbol_negative_at_S(self, S, b, check=True): # symbol is negative for all primes in S and positive # at all primes in S' V = VectorSpace(GF(2), len(P)) - v = V([1]*len(S) + [0]*len(L)) + v = V([1] * len(S) + [0] * len(L)) # Compute the map phi of Hilbert symbols at all the primes # in S and S' @@ -886,10 +898,10 @@ def hilbert_symbol_negative_at_S(self, S, b, check=True): # represented as 1 and a Hilbert symbol of 1 # is represented as 0 def phi(x): - v = [(1-hilbert_symbol(x, b, p))//2 for p in P] + v = [(1 - hilbert_symbol(x, b, p)) // 2 for p in P] return V(v) - M = matrix(GF(2), [phi(p) for p in P+[-1]]) + M = matrix(GF(2), [phi(p) for p in P + [-1]]) # We search through all the primes for q in Primes(): # Only look at this prime if it is not in our list @@ -905,7 +917,7 @@ def phi(x): break Pq = P + [-1] + [q] l = W.solve_left(v) - a = self.prod([Pq[i]**ZZ(l[i]) for i in range(l.degree())]) + a = self.prod([Pq[i] ** ZZ(l[i]) for i in range(l.degree())]) if check: assert phi(a) == v, "oops" return a @@ -919,7 +931,7 @@ def gens(self) -> tuple: sage: QQ.gens() (1,) """ - return (self(1), ) + return (self(1),) def gen(self, n=0): r""" @@ -1017,6 +1029,7 @@ def maximal_order(self): Integer Ring """ from .integer_ring import ZZ + return ZZ def number_field(self): @@ -1068,6 +1081,7 @@ def extension(self, poly, names, **kwds): -5 """ from sage.rings.number_field.number_field import NumberField + return NumberField(poly, names=names, **kwds) def algebraic_closure(self): @@ -1080,6 +1094,7 @@ def algebraic_closure(self): Algebraic Field """ from sage.rings.qqbar import QQbar + return QQbar def order(self): @@ -1092,6 +1107,7 @@ def order(self): +Infinity """ from sage.rings.infinity import Infinity + return Infinity def polynomial(self): @@ -1107,6 +1123,7 @@ def polynomial(self): x """ from sage.rings.polynomial.polynomial_ring import polygen + return polygen(self) defining_polynomial = polynomial @@ -1152,15 +1169,15 @@ def some_elements(self): """ yield self.an_element() yield -self.an_element() - yield 1/self.an_element() - yield -1/self.an_element() + yield 1 / self.an_element() + yield -1 / self.an_element() yield self(0) yield self(1) yield self(-1) yield self(42) for n in range(1, 24): - a = 2*n - b = (2*n + 1)**(n//10 + 1) + a = 2 * n + b = (2 * n + 1) ** (n // 10 + 1) yield Rational((a, b)) yield Rational((-a, b)) yield Rational((b, a)) @@ -1217,6 +1234,7 @@ def random_element(self, num_bound=None, den_bound=None, *args, **kwds): global ZZ if ZZ is None: from . import integer_ring + ZZ = integer_ring.ZZ if num_bound is None: num = ZZ.random_element(*args, **kwds) @@ -1230,10 +1248,10 @@ def random_element(self, num_bound=None, den_bound=None, *args, **kwds): den_bound = num_bound if den_bound < 1: den_bound = 2 - num = ZZ.random_element(-num_bound, num_bound+1, *args, **kwds) - den = ZZ.random_element(1, den_bound+1, *args, **kwds) + num = ZZ.random_element(-num_bound, num_bound + 1, *args, **kwds) + den = ZZ.random_element(1, den_bound + 1, *args, **kwds) while den == 0: - den = ZZ.random_element(1, den_bound+1, *args, **kwds) + den = ZZ.random_element(1, den_bound + 1, *args, **kwds) return self((num, den)) def zeta(self, n=2): @@ -1358,6 +1376,7 @@ def selmer_group_iterator(self, S, m, proof=True): from itertools import product from sage.misc.misc_c import prod + for ev in product(*[range(o) for o in ords]): yield prod((p**e for p, e in zip(KSgens, ev)), one) @@ -1442,6 +1461,7 @@ def selmer_space(self, S, p, proof=None): at all primes in [5, 7] """ from sage.rings.number_field.selmer_group import pSelmerGroup + return pSelmerGroup(self, S, p) def quadratic_defect(self, a, p, check=True): @@ -1471,6 +1491,7 @@ def quadratic_defect(self, a, p, check=True): """ from sage.arith.misc import legendre_symbol from sage.rings.infinity import Infinity + if a not in self: raise TypeError(str(a) + " must be an element of " + str(self)) if p.parent() == ZZ.ideal_monoid(): @@ -1575,6 +1596,7 @@ def _sympy_(self): from sympy import Rationals from sage.interfaces.sympy import sympy_init + sympy_init() return Rationals @@ -1639,6 +1661,7 @@ def _factor_univariate_polynomial(self, f): F = [(P(g).monic(), int(e)) for g, e in zip(*G)] from sage.structure.factorization import Factorization + return Factorization(F, f.leading_coefficient()) def valuation(self, p): @@ -1658,6 +1681,7 @@ def valuation(self, p): :meth:`IntegerRing_class.valuation() ` """ from sage.rings.padics.padic_valuation import pAdicValuation + return pAdicValuation(self, p) diff --git a/src/sage/rings/real_field.py b/src/sage/rings/real_field.py index b5ac10b2162..8c6f100b87a 100644 --- a/src/sage/rings/real_field.py +++ b/src/sage/rings/real_field.py @@ -42,15 +42,20 @@ def create_RealField(prec=53, type='MPFR', rnd='RNDN', sci_not=0): """ if type == "RDF": from .real_double import RDF + return RDF if type == "Interval": from .real_mpfi import RealIntervalField + return RealIntervalField(prec, sci_not) if type == "Ball": from .real_arb import RealBallField + return RealBallField(prec) if type == "RLF": from .real_lazy import RLF + return RLF from .real_mpfr import RealField + return RealField(prec, sci_not, rnd) diff --git a/src/sage/rings/ring.pyi b/src/sage/rings/ring.pyi index 2b19c01a6d6..ac5013096e1 100644 --- a/src/sage/rings/ring.pyi +++ b/src/sage/rings/ring.pyi @@ -67,13 +67,9 @@ class Field(CommutativeRing): _default_category: Category = _Fields class Algebra(Ring): - def __init__( - self, base_ring: Parent[Any] | object, *args: object, **kwds: object - ) -> None: ... + def __init__(self, base_ring: Parent[Any] | object, *args: object, **kwds: object) -> None: ... class CommutativeAlgebra(CommutativeRing): - def __init__( - self, base_ring: Parent[Any] | object, *args: object, **kwds: object - ) -> None: ... + def __init__(self, base_ring: Parent[Any] | object, *args: object, **kwds: object) -> None: ... def is_Ring(x: object) -> bool: ... diff --git a/src/sage/rings/ring_extension_homset.py b/src/sage/rings/ring_extension_homset.py index 1ba55906d9c..18c7c1f3475 100644 --- a/src/sage/rings/ring_extension_homset.py +++ b/src/sage/rings/ring_extension_homset.py @@ -15,7 +15,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#**************************************************************************** +# **************************************************************************** from sage.rings.homset import RingHomset_generic from sage.rings.ring_extension_morphism import RingExtensionHomomorphism @@ -38,6 +38,7 @@ class RingExtensionHomset(RingHomset_generic): sage: type(H) <... 'sage.rings.ring_extension_homset.RingExtensionHomset_with_category'> """ + def __call__(self, *args, **kwargs): r""" Return the morphism in this parent defined by the diff --git a/src/sage/rings/semirings/non_negative_integer_semiring.py b/src/sage/rings/semirings/non_negative_integer_semiring.py index 4fc0309a44d..41d95bd15a0 100644 --- a/src/sage/rings/semirings/non_negative_integer_semiring.py +++ b/src/sage/rings/semirings/non_negative_integer_semiring.py @@ -1,6 +1,7 @@ r""" Non Negative Integer Semiring """ + # **************************************************************************** # Copyright (C) 2010 Nicolas Borie # @@ -60,6 +61,7 @@ class NonNegativeIntegerSemiring(NonNegativeIntegers): sage: x+3 18 """ + def __init__(self): r""" TESTS:: @@ -70,8 +72,7 @@ def __init__(self): Category of facade infinite enumerated commutative semirings sage: TestSuite(NN).run() """ - NonNegativeIntegers.__init__(self, category=(Semirings().Commutative(), - InfiniteEnumeratedSets())) + NonNegativeIntegers.__init__(self, category=(Semirings().Commutative(), InfiniteEnumeratedSets())) def _repr_(self) -> str: r""" diff --git a/src/sage/rings/semirings/tropical_matrix.py b/src/sage/rings/semirings/tropical_matrix.py index 681711bd984..167e62607b7 100644 --- a/src/sage/rings/semirings/tropical_matrix.py +++ b/src/sage/rings/semirings/tropical_matrix.py @@ -34,6 +34,7 @@ class Matrix_tropical_dense(Matrix_generic_dense): sage: isinstance(M, Matrix_tropical_dense) True """ + def extremum_cycle_mean(self): r""" Return the extremal (that is, minimal if the addition is max @@ -93,18 +94,17 @@ def extremum_cycle_mean(self): raise TypeError("matrix must be square") if self.is_zero(): return T.zero() - v = matrix(1, n, n*[T.one()]) + v = matrix(1, n, n * [T.one()]) vs = [v] for _ in range(n): v = v * self vs.append(v) - w = [vs[n][0,j].lift() for j in range(n)] + w = [vs[n][0, j].lift() for j in range(n)] if T._use_min: f, fp = max, min else: f, fp = min, max - ans = fp(f((w[j] - vs[k][0,j].lift()) / (n-k) for k in range(n)) - for j in range(n) if w[j] is not infinity) + ans = fp(f((w[j] - vs[k][0, j].lift()) / (n - k) for k in range(n)) for j in range(n) if w[j] is not infinity) return T(ans) def weak_transitive_closure(self): @@ -183,11 +183,11 @@ def weak_transitive_closure(self): for j in range(n): if j == p: continue - G[i,j] += G[i,p] * G[p,j] + G[i, j] += G[i, p] * G[p, j] if i == j: - if T._use_min and G[i,i].lift() < 0: + if T._use_min and G[i, i].lift() < 0: raise ValueError("negative cycle exists") - if not T._use_min and G[i,i].lift() > 0: + if not T._use_min and G[i, i].lift() > 0: raise ValueError("positive cycle exists") return G diff --git a/src/sage/rings/semirings/tropical_mpolynomial.py b/src/sage/rings/semirings/tropical_mpolynomial.py index d1017cac389..9cc4dce8cb8 100644 --- a/src/sage/rings/semirings/tropical_mpolynomial.py +++ b/src/sage/rings/semirings/tropical_mpolynomial.py @@ -179,6 +179,7 @@ class TropicalMPolynomial(MPolynomial_polydict): ... ArithmeticError: cannot negate any non-infinite element """ + def subs(self, fixed=None, **kwds): r""" Fix some given variables in ``self`` and return the changed @@ -293,8 +294,7 @@ def plot3d(self, color='random'): from sage.symbolic.relation import solve if len(self.parent().variable_names()) != 2: - raise NotImplementedError("can only plot the graph of tropical " - "multivariate polynomial in two variables") + raise NotImplementedError("can only plot the graph of tropical " "multivariate polynomial in two variables") tv = self.tropical_variety() axes = tv._axes() edge = set() @@ -310,7 +310,7 @@ def plot3d(self, color='random'): else: valid_int = RealSet(comp[1][0]).intersection(RealSet(comp[1][1])) for i, eqn in enumerate(comp[0]): - j = (i+1) % 2 + j = (i + 1) % 2 if not eqn.is_numeric(): for k in range(2): sol = solve(eqn == axes[i][k], v) @@ -329,14 +329,13 @@ def plot3d(self, color='random'): # Calculate the value of polynomial at each marked point variables = self.parent().gens() - terms = [a*variables[0]**b[0] * variables[1]**b[1] for a, b in zip(self.coefficients(), self.exponents())] + terms = [a * variables[0] ** b[0] * variables[1] ** b[1] for a, b in zip(self.coefficients(), self.exponents())] point_terms = {} for mark in marks: mark_terms = [] value = self(T(mark[0]), T(mark[1])) value_terms = [term(T(mark[0]), T(mark[1])) for term in terms] - mark_terms.extend(terms[i] for i in range(len(terms)) - if value_terms[i] == value) + mark_terms.extend(terms[i] for i in range(len(terms)) if value_terms[i] == value) point_terms[(R(mark[0]), R(mark[1]), value.lift())] = mark_terms # Plot the points that attained its value at one term only @@ -674,9 +673,7 @@ def _repr_(self): except AttributeError: key = None atomic = self.parent().base_ring()._repr_option('element_is_atomic') - s = self.element().poly_repr(self.parent().variable_names(), - atomic_coefficients=atomic, - sortkey=key) + s = self.element().poly_repr(self.parent().variable_names(), atomic_coefficients=atomic, sortkey=key) if self.monomials()[-1].is_constant(): if self.monomial_coefficient(self.parent()(0)) < 0: s = s.replace(" - ", " + -") @@ -734,6 +731,7 @@ class TropicalMPolynomialSemiring(UniqueRepresentation, Parent): sage: f * R.one() == f True """ + def __init__(self, base_semiring, n, names, order): r""" Initialize ``self``. @@ -746,6 +744,7 @@ def __init__(self, base_semiring, n, names, order): """ from sage.categories.semirings import Semirings from sage.rings.semirings.tropical_semiring import TropicalSemiring + if not isinstance(base_semiring, TropicalSemiring): raise ValueError(f"{base_semiring} is not a tropical semiring") Parent.__init__(self, base=base_semiring, names=names, category=Semirings()) @@ -768,7 +767,7 @@ def term_order(self): Element = TropicalMPolynomial def _element_constructor_(self, x): - r"""" + r""" " Convert ``x`` into ``self``. INPUT: @@ -799,6 +798,7 @@ def _element_constructor_(self, x): Polynomial Semiring in x, y over Rational Field """ from sage.rings.polynomial.multi_polynomial import MPolynomial + if isinstance(x, TropicalMPolynomial): if x.parent() is not self: raise ValueError(f"can not convert {x} to {self}") @@ -858,13 +858,10 @@ def _repr_(self): Field with 53 bits of precision """ if self._ngens == 0: - return (f"Multivariate Tropical Polynomial Semiring in no variables" - f" over {self.base_ring().base_ring()}") - return (f"Multivariate Tropical Polynomial Semiring in {', '.join(self.variable_names())}" - f" over {self.base_ring().base_ring()}") + return f"Multivariate Tropical Polynomial Semiring in no variables" f" over {self.base_ring().base_ring()}" + return f"Multivariate Tropical Polynomial Semiring in {', '.join(self.variable_names())}" f" over {self.base_ring().base_ring()}" - def random_element(self, degree=2, terms=None, choose_degree=False, - *args, **kwargs): + def random_element(self, degree=2, terms=None, choose_degree=False, *args, **kwargs): r""" Return a random multivariate tropical polynomial from ``self``. @@ -900,11 +897,10 @@ def random_element(self, degree=2, terms=None, choose_degree=False, True """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(self.base().base_ring(), self.variable_names()) - f = R.random_element(degree=degree, terms=terms, choose_degree=choose_degree, - *args, **kwargs) - new_dict = {key: self.base()(value) - for key, value in f.monomial_coefficients().items()} + f = R.random_element(degree=degree, terms=terms, choose_degree=choose_degree, *args, **kwargs) + new_dict = {key: self.base()(value) for key, value in f.monomial_coefficients().items()} return self.element_class(self, new_dict) def gen(self, n=0): @@ -961,4 +957,5 @@ def ngens(self): 10 """ from sage.rings.integer_ring import ZZ + return ZZ(self._ngens) diff --git a/src/sage/rings/semirings/tropical_polynomial.py b/src/sage/rings/semirings/tropical_polynomial.py index 364e698a39e..2fe8ce7fa51 100644 --- a/src/sage/rings/semirings/tropical_polynomial.py +++ b/src/sage/rings/semirings/tropical_polynomial.py @@ -165,6 +165,7 @@ class TropicalPolynomial(Polynomial_generic_sparse): ... ArithmeticError: cannot negate any non-infinite element """ + def roots(self): r""" Return the list of all tropical roots of ``self``, counted with @@ -208,6 +209,7 @@ def roots(self): [+infinity, +infinity, +infinity] """ from itertools import combinations + tropical_roots = [] data = self.monomial_coefficients() R = self.parent().base() @@ -220,12 +222,12 @@ def roots(self): dict_coeff = {i: c.lift() for i, c in data.items()} for comb in combinations(dict_coeff, 2): index1, index2 = comb[0], comb[1] - root = (dict_coeff[index1]-dict_coeff[index2]) / (index2-index1) - val_root = dict_coeff[index1] + index1*root + root = (dict_coeff[index1] - dict_coeff[index2]) / (index2 - index1) + val_root = dict_coeff[index1] + index1 * root check_maks = True for key in dict_coeff: if key not in comb: - val = dict_coeff[key] + key*root + val = dict_coeff[key] + key * root if R._use_min: if val < val_root: check_maks = False @@ -234,7 +236,7 @@ def roots(self): check_maks = False break if check_maks: - order = abs(index1-index2) + order = abs(index1 - index2) if root not in dict_root: dict_root[root] = order elif order > dict_root[root]: @@ -323,6 +325,7 @@ def factor(self): (3) * 0 """ from sage.structure.factorization import Factorization + unit = self.monomial_coefficients()[self.degree()] if self != self.split_form() or not self.roots(): factor = [(self * self.parent(-unit.lift()), 1)] @@ -335,8 +338,7 @@ def factor(self): roots_order[root] += 1 else: roots_order[root] = 1 - factors = [(R([root, 0]), roots_order[root]) - for root in roots_order] + factors = [(R([root, 0]), roots_order[root]) for root in roots_order] return Factorization(factors, unit=unit) def piecewise_function(self): @@ -385,7 +387,7 @@ def piecewise_function(self): if len(data) == 1: gradient = list(data)[0] intercept = data[gradient].lift() - f = intercept + gradient*x + f = intercept + gradient * x return f unique_root = sorted(set(self.roots())) @@ -395,9 +397,9 @@ def piecewise_function(self): if i == 0: test_number = R(unique_root[i] - 1) elif i == len(unique_root): - test_number = R(unique_root[i-1] + 1) + test_number = R(unique_root[i - 1] + 1) else: - test_number = R((unique_root[i]+unique_root[i-1]) / 2) + test_number = R((unique_root[i] + unique_root[i - 1]) / 2) terms = {i: c * test_number**i for i, c in data.items()} if R._use_min: critical = min(terms.values()) @@ -414,21 +416,21 @@ def piecewise_function(self): # To make sure all roots is included in the domain if i == 0: interval = RealSet.unbounded_below_closed(unique_root[i]) - piecewise_linear = (interval, intercept + gradient*x) + piecewise_linear = (interval, intercept + gradient * x) domain.append(interval) elif i == len(unique_root): - if domain[i-1][0].upper_closed(): - interval = RealSet.unbounded_above_open(unique_root[i-1]) + if domain[i - 1][0].upper_closed(): + interval = RealSet.unbounded_above_open(unique_root[i - 1]) else: - interval = RealSet.unbounded_above_closed(unique_root[i-1]) - piecewise_linear = (interval, intercept + gradient*x) + interval = RealSet.unbounded_above_closed(unique_root[i - 1]) + piecewise_linear = (interval, intercept + gradient * x) domain.append(interval) else: - if domain[i-1][0].upper_closed(): - interval = RealSet((unique_root[i-1], unique_root[i])) + if domain[i - 1][0].upper_closed(): + interval = RealSet((unique_root[i - 1], unique_root[i])) else: - interval = RealSet([unique_root[i-1], unique_root[i]]) - piecewise_linear = (interval, intercept + gradient*x) + interval = RealSet([unique_root[i - 1], unique_root[i]]) + piecewise_linear = (interval, intercept + gradient * x) domain.append(interval) pieces.append(piecewise_linear) @@ -514,12 +516,13 @@ def plot(self, xmin=None, xmax=None): ValueError: xmin = 5 should be less than xmax = 3 """ from sage.plot.plot import plot + f = self.piecewise_function() if (xmin is None) and (xmax is None): roots = sorted(self.roots()) if (not roots) or (self.parent().base().zero() in roots): return plot(f, xmin=-1, xmax=1) - return plot(f, xmin=roots[0]-1, xmax=roots[-1]+1) + return plot(f, xmin=roots[0] - 1, xmax=roots[-1] + 1) if xmin is None or xmax is None: raise ValueError("expected 2 inputs for xmin and xmax, but got 1") elif xmin >= xmax: @@ -538,6 +541,7 @@ def _repr_(self): (-1)*x^3 + 2*x^2 + (-1)*x + (-3) """ import re + if not self.monomial_coefficients(): return str(self.parent().base().zero()) @@ -550,8 +554,8 @@ def replace_negatives(expr): if s[0] == v: s = "1*" + s s = s.replace(" - ", " + -") - s = s.replace(" + "+v, " + 1*"+v) - s = s.replace("-"+v, "-1*"+v) + s = s.replace(" + " + v, " + 1*" + v) + s = s.replace("-" + v, "-1*" + v) s = replace_negatives(s) return s @@ -575,7 +579,7 @@ def _latex_(self): x = coeffs[n] x = x._latex_() if x != self.parent().base().zero()._latex_(): - if n != m-1: + if n != m - 1: s += " + " if x.find("-") == 0: x = "\\left(" + x + "\\right)" @@ -619,6 +623,7 @@ class TropicalPolynomialSemiring(UniqueRepresentation, Parent): sage: f * R.one() == f True """ + @staticmethod def __classcall_private__(cls, base_semiring, names): """ @@ -656,6 +661,7 @@ def __init__(self, base_semiring, names): """ from sage.categories.semirings import Semirings from sage.rings.semirings.tropical_semiring import TropicalSemiring + if not isinstance(base_semiring, TropicalSemiring): raise ValueError(f"{base_semiring} is not a tropical semiring") Parent.__init__(self, base=base_semiring, names=names, category=Semirings()) @@ -742,8 +748,7 @@ def _repr_(self): sage: R. = PolynomialRing(T); R Univariate Tropical Polynomial Semiring in abc over Integer Ring """ - return (f"Univariate Tropical Polynomial Semiring in {self.variable_name()}" - f" over {self.base_ring().base_ring()}") + return f"Univariate Tropical Polynomial Semiring in {self.variable_name()}" f" over {self.base_ring().base_ring()}" def gen(self, n=0): """ @@ -795,6 +800,7 @@ def ngens(self): 1 """ from sage.rings.integer_ring import ZZ + return ZZ.one() def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): @@ -843,6 +849,7 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): True """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(self.base().base_ring(), self.variable_names()) f = R.random_element(degree=degree, monic=monic, *args, **kwds) new_dict = f.monomial_coefficients() @@ -947,14 +954,14 @@ def interpolation(self, points): roots = {} R = self.base() if R._use_min: - point_order = range(len(points)-1, 0, -1) + point_order = range(len(points) - 1, 0, -1) else: - point_order = range(len(points)-1) + point_order = range(len(points) - 1) for i in point_order: if R._use_min: - slope = (points[i-1][1]-points[i][1]) / (points[i-1][0]-points[i][0]) + slope = (points[i - 1][1] - points[i][1]) / (points[i - 1][0] - points[i][0]) else: - slope = (points[i+1][1]-points[i][1]) / (points[i+1][0]-points[i][0]) + slope = (points[i + 1][1] - points[i][1]) / (points[i + 1][0] - points[i][0]) if not slope.is_integer(): raise ValueError("the slope is not an integer") if slope < all_slope[-1]: @@ -969,7 +976,7 @@ def interpolation(self, points): result = self.one() for root, order in roots.items(): - result *= self([root, 0])**order + result *= self([root, 0]) ** order test_value = result(R(points[0][0])) unit = R(points[0][1] - test_value.lift()) result *= unit diff --git a/src/sage/rings/semirings/tropical_variety.py b/src/sage/rings/semirings/tropical_variety.py index 41d9137f2ba..55af0d2a9a6 100644 --- a/src/sage/rings/semirings/tropical_variety.py +++ b/src/sage/rings/semirings/tropical_variety.py @@ -164,6 +164,7 @@ class TropicalVariety(UniqueRepresentation, SageObject): [(t1 - 1/2, t2, t3, t1), [t2 - 9/2 <= t1, t1 <= t3 + 1/2, t2 - 5 <= t3], 1], [(2*t1 - t2 + 4, t2, t3, t1), [t1 <= min(1/2*t2 + 1/2*t3 - 2, t2 - 9/2)], 1]] """ + def __init__(self, poly): r""" Initialize ``self``. @@ -199,8 +200,7 @@ def __init__(self, poly): self._poly = poly self._hypersurface = [] tropical_roots = [] - variables = [SR.var(name) - for name in poly.parent().variable_names()] + variables = [SR.var(name) for name in poly.parent().variable_names()] # Convert each term to its linear function linear_eq = {} @@ -258,8 +258,7 @@ def __init__(self, poly): xy_interval.append(parameter_solution[0]) tropical_roots.append(xy_interval) # Calculate the order - index_diff = [abs(ai - bi) - for ai, bi in zip(keys[0], keys[1])] + index_diff = [abs(ai - bi) for ai, bi in zip(keys[0], keys[1])] order = gcd(index_diff) temp_order.append(order) temp_keys.append(keys) @@ -350,6 +349,7 @@ def number_of_components(self): 13 """ from sage.rings.integer_ring import ZZ + return ZZ(len(self._hypersurface)) def _repr_(self): @@ -630,7 +630,7 @@ def weight_vectors(self): is_unique = False break subs_dict = {} - while len(subs_dict) != dim-2 and subs_index < dim: + while len(subs_dict) != dim - 2 and subs_index < dim: eq1 = eqn[subs_index].subs(subs_dict) vib = None for unk in eq1.variables(): @@ -697,7 +697,7 @@ def weight_vectors(self): normal_vec = vec_matrix.det() temp_nor = [QQ(diff(normal_vec, tvar)) for tvar in t_vars] normal_vec = vector(temp_nor) - normal_vec *= 1/gcd(normal_vec) + normal_vec *= 1 / gcd(normal_vec) # Calculate the weight vector temp_final = [t_vars] @@ -712,7 +712,7 @@ def weight_vectors(self): WV[k].append(weight_vec) balance = False - for i in range(1, len(WV[k])+1): + for i in range(1, len(WV[k]) + 1): for j in combinations(range(len(WV[k])), i): test_vectors = list(WV[k]) for idx in j: @@ -753,6 +753,7 @@ class TropicalSurface(TropicalVariety): [(t1, 0, t2), [t2 <= 0, t1 <= 0], 1], [(t1, t2, 0), [t1 <= 0, t2 <= 0], 1]] """ + def _axes(self): r""" Set the default axes for ``self``. @@ -838,14 +839,14 @@ def _axes(self): temp_u.add(sol[0][0].rhs()) u_set = u_set.union(temp_u) v_set = v_set.union(temp_v) - axes = [[min(u_set)-1, max(u_set)+1], [min(v_set)-1, max(v_set)+1]] + axes = [[min(u_set) - 1, max(u_set) + 1], [min(v_set) - 1, max(v_set) + 1]] # Calculate the z-axis step = 10 - du = (axes[0][1]-axes[0][0]) / step - dv = (axes[1][1]-axes[1][0]) / step - u_range = srange(axes[0][0], axes[0][1]+du, du) - v_range = srange(axes[1][0], axes[1][1]+dv, dv) + du = (axes[0][1] - axes[0][0]) / step + dv = (axes[1][1] - axes[1][0]) / step + u_range = srange(axes[0][0], axes[0][1] + du, du) + v_range = srange(axes[1][0], axes[1][1] + dv, dv) zmin, zmax = None, None for comp in self._hypersurface: for u in u_range: @@ -927,7 +928,7 @@ def _polygon_vertices(self): poly_verts[index].add(tuple(vertex)) def find_edge_vertices(i): - j = (i+1) % 2 + j = (i + 1) % 2 if i == 0: # interval for t1 interval = interval1 else: # interval for t2 @@ -1159,6 +1160,7 @@ class TropicalCurve(TropicalVariety): p3 = p1 * p2 sphinx_plot(p3.tropical_variety().plot()) """ + def _axes(self): """ Set the default axes for ``self``. @@ -1215,7 +1217,7 @@ def _axes(self): ymin = vertex[1] elif vertex[1] > ymax: ymax = vertex[1] - return [[xmin-1, xmax+1], [ymin-1, ymax+1]] + return [[xmin - 1, xmax + 1], [ymin - 1, ymax + 1]] def vertices(self): r""" @@ -1341,7 +1343,7 @@ def weight_vectors(self): dx = diff(comp[0][0], par) dy = diff(comp[0][1], par) multiplier = gcd(QQ(dx), QQ(dy)) - temp_vectors.append(vector([dx/multiplier, dy/multiplier])) + temp_vectors.append(vector([dx / multiplier, dy / multiplier])) # Calculate the weight vectors of each vertex cov = self._vertices_components() @@ -1350,7 +1352,7 @@ def weight_vectors(self): vectors = [] for comp in cov[vertex]: weight = self._hypersurface[comp[0]][2] - vectors.append(weight*comp[1]*temp_vectors[comp[0]]) + vectors.append(weight * comp[1] * temp_vectors[comp[0]]) result[vertex] = vectors return result @@ -1449,7 +1451,7 @@ def genus(self): for component in self._hypersurface: if len(component[1]) == 1: unbounded += 1 - return trivalent//2 - unbounded//2 + 1 + return trivalent // 2 - unbounded // 2 + 1 def contribution(self): r""" @@ -1498,7 +1500,7 @@ def contribution(self): index2 = voc[vertex][1][0] w1 = self._hypersurface[index1][2] w2 = self._hypersurface[index2][2] - det = u1[0]*u2[1] - u1[1]*u2[0] + det = u1[0] * u2[1] - u1[1] * u2[0] result *= w1 * w2 * abs(det) return result @@ -1655,15 +1657,13 @@ def plot(self): else: lower = interval[0].lower() upper = interval[0].upper() - midpoint = (lower+upper) / 2 + midpoint = (lower + upper) / 2 if (lower == infinity) and (upper == infinity): midpoint = 0 - plot = parametric_plot(parametric_function, (var, -large_int, - large_int), color='red') + plot = parametric_plot(parametric_function, (var, -large_int, large_int), color='red') else: - plot = parametric_plot(parametric_function, (var, lower, upper), - color='red') + plot = parametric_plot(parametric_function, (var, lower, upper), color='red') # Add the order if it is greater than or equal to 2 if component[2] > 1: @@ -1671,8 +1671,7 @@ def plot(self): for eq in component[0]: value = eq.subs(**{str(var): midpoint}) point.append(value) - text_order = text(str(order), (point[0], point[1]), - fontsize=16, color='black') + text_order = text(str(order), (point[0], point[1]), fontsize=16, color='black') combined_plot += plot + text_order else: combined_plot += plot @@ -1681,8 +1680,7 @@ def plot(self): axes = self._axes() xmin, xmax = axes[0][0], axes[0][1] ymin, ymax = axes[1][0], axes[1][1] - combined_plot.set_axes_range(xmin=xmin, xmax=xmax, - ymin=ymin, ymax=ymax) + combined_plot.set_axes_range(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax) return combined_plot def _repr_(self): diff --git a/src/sage/rings/species.py b/src/sage/rings/species.py index 20d1a687323..e8bbd3422ae 100644 --- a/src/sage/rings/species.py +++ b/src/sage/rings/species.py @@ -57,8 +57,7 @@ from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.misc.misc_c import prod from sage.modules.free_module_element import vector -from sage.monoids.indexed_free_monoid import (IndexedFreeAbelianMonoid, - IndexedFreeAbelianMonoidElement) +from sage.monoids.indexed_free_monoid import IndexedFreeAbelianMonoid, IndexedFreeAbelianMonoidElement from sage.rings.rational_field import QQ from sage.rings.infinity import Infinity from sage.rings.integer import Integer @@ -71,8 +70,7 @@ from sage.structure.global_options import GlobalOptions from sage.structure.parent import Parent from sage.structure.richcmp import op_LT, op_LE, op_EQ, op_NE, op_GT, op_GE -from sage.structure.unique_representation import (UniqueRepresentation, - WithPicklingByInitArgs) +from sage.structure.unique_representation import UniqueRepresentation, WithPicklingByInitArgs GAP_FAIL = libgap.eval('fail') # for each key (currently size and orbit-sizes) a list of canonical @@ -138,10 +136,7 @@ def _label_sets(arity, labels): return [tuple(U) for U in label_sets_sorted] -class AtomicSpeciesElement(WithEqualityById, - Element, - WithPicklingByInitArgs, - metaclass=InheritComparisonClasscallMetaclass): +class AtomicSpeciesElement(WithEqualityById, Element, WithPicklingByInitArgs, metaclass=InheritComparisonClasscallMetaclass): r""" An atomic species. @@ -156,6 +151,7 @@ class AtomicSpeciesElement(WithEqualityById, where `k` is the arity, representing the assignment of each element of the domain of ``dis`` to a sort """ + @staticmethod def __classcall__(cls, parent, G, dompart): r""" @@ -263,7 +259,7 @@ class of subgroups conjugate to ``G``, together with the dis, mp = new_dis() lookup_dis = _dis_cache[key] = [dis] - dompart = [[ZZ(e ** mp) for e in b] for b in dompart] + dompart = [[ZZ(e**mp) for e in b] for b in dompart] mc = tuple([len(b) for b in dompart]) key = (mc, dis) if key in parent._cache: @@ -279,7 +275,7 @@ class of subgroups conjugate to ``G``, together with the # dompart and by elm._dompart are the same elm_domain = list(chain(*map(sorted, elm._dompart))) mp = libgap.MappingPermListList(elm_domain, domain) - if all(g ** mp in dis_gap for g in dis_gens): + if all(g**mp in dis_gap for g in dis_gens): return elm else: lookup = parent._cache[key] = [] @@ -330,8 +326,7 @@ def _repr_(self): P._renamed.add(self._tc) P._rename(self._tc) renamed = True - if (self._tc not in P._renamed_set_like - and self._tc <= P.options.rename()): + if self._tc not in P._renamed_set_like and self._tc <= P.options.rename(): P._renamed.add(self._tc) P._renamed_set_like.add(self._tc) _atomic_set_like_species(self._tc, P._names) @@ -342,8 +337,7 @@ def _repr_(self): if self.parent()._arity == 1: return "{" + f"{self._dis.gens()}" + "}" - dompart = ', '.join("{" + repr(sorted(b))[1:-1] + "}" - for b in self._dompart) + dompart = ', '.join("{" + repr(sorted(b))[1:-1] + "}" for b in self._dompart) return "{" + f"{self._dis.gens()}: ({dompart})" + "}" def grade(self): @@ -404,9 +398,7 @@ def __lt__(self, other) -> bool: # the arities match because the parents are equal if self._mc != other._mc: # X should come before Y - return (sum(self._mc) < sum(other._mc) - or (sum(self._mc) == sum(other._mc) - and self._mc > other._mc)) + return sum(self._mc) < sum(other._mc) or (sum(self._mc) == sum(other._mc) and self._mc > other._mc) S = _SymmetricGroup(sum(self._mc)).young_subgroup(self._mc) # conjugate self and other to match S g = list(chain.from_iterable(self._dompart)) @@ -522,14 +514,10 @@ def __call__(self, *args): for i, v in enumerate(dompart): for k in v: Mlist[k - 1] = args[i] - starts = list(accumulate([sum(M.grade()) for M in Mlist], - initial=0)) + starts = list(accumulate([sum(M.grade()) for M in Mlist], initial=0)) # gens from self - gens = [[tuple([k + starts[i - 1] for i in cyc]) - for cyc in gen.cycle_tuples() - for k in range(1, sum(Mlist[cyc[0] - 1].grade()) + 1)] - for gen in G.gens()] + gens = [[tuple([k + starts[i - 1] for i in cyc]) for cyc in gen.cycle_tuples() for k in range(1, sum(Mlist[cyc[0] - 1].grade()) + 1)] for gen in G.gens()] # gens from M_i and dompart P = args[0].parent() @@ -538,9 +526,7 @@ def __call__(self, *args): K, K_dompart = M.permutation_group() for i, v in enumerate(K_dompart): pi[i].extend([start + k for k in v]) - gens.extend([tuple([start + k for k in cyc]) - for cyc in gen.cycle_tuples()] - for gen in K.gens()) + gens.extend([tuple([start + k for k in cyc]) for cyc in gen.cycle_tuples()] for gen in K.gens()) H = PermutationGroup(gens, domain=range(1, starts[-1] + 1)) return P._indices(H, pi, check=False) @@ -555,6 +541,7 @@ class AtomicSpecies(UniqueRepresentation, Parent): - ``names`` -- an iterable of strings for the sorts of the species """ + class options(GlobalOptions): r""" Set and display the options for species. @@ -595,11 +582,10 @@ class options(GlobalOptions): sage: L.options._reset() """ + NAME = 'species' module = 'sage.rings.species' - rename = dict(default=12, - description='the maximal size of set like species to rename', - checker=lambda x: x is Infinity or x in ZZ and x >= 0) + rename = dict(default=12, description='the maximal size of set like species to rename', checker=lambda x: x is Infinity or x in ZZ and x >= 0) @staticmethod def __classcall__(cls, names): @@ -773,8 +759,7 @@ def _element_constructor_(self, G, pi=None, check=True): if check: if not set(pi).issubset(range(self._arity)): raise ValueError(f"keys of pi (={pi.keys()}) must be in range({self._arity})") - if (sum(len(p) for p in pi.values()) != len(G.domain()) - or set(chain.from_iterable(pi.values())) != set(G.domain())): + if sum(len(p) for p in pi.values()) != len(G.domain()) or set(chain.from_iterable(pi.values())) != set(G.domain()): raise ValueError(f"values of pi (={pi.values()}) must partition the domain of G (={G.domain()})") dompart = [pi.get(s, []) for s in range(self._arity)] elm = self.element_class(self, G, dompart) @@ -806,13 +791,10 @@ def _rename(self, n): Eo_4(Y) """ from sage.groups.perm_gps.permgroup import PermutationGroup - from sage.groups.perm_gps.permgroup_named import (AlternatingGroup, - CyclicPermutationGroup, - DihedralGroup, - SymmetricGroup) + from sage.groups.perm_gps.permgroup_named import AlternatingGroup, CyclicPermutationGroup, DihedralGroup, SymmetricGroup for s in range(self._arity): - pi = {s: range(1, n+1)} + pi = {s: range(1, n + 1)} if n == 1: self(_SymmetricGroup(1), pi, check=False).rename(self._names[s]) @@ -834,8 +816,7 @@ def _rename(self, n): self(AlternatingGroup(n), pi, check=False).rename(f"Eo_{n}" + sort) if n >= 4 and not n % 2: - gens = [[(i, n-i+1) for i in range(1, n//2 + 1)], - [(i, i+1) for i in range(1, n, 2)]] + gens = [[(i, n - i + 1) for i in range(1, n // 2 + 1)], [(i, i + 1) for i in range(1, n, 2)]] self(PermutationGroup(gens), pi, check=False).rename(f"Pb_{n}" + sort) def __contains__(self, x) -> bool: @@ -888,8 +869,7 @@ def __contains__(self, x) -> bool: return False if not set(pi).issubset(range(self._arity)): return False - if (sum(len(p) for p in pi.values()) != len(G.domain()) - or set(chain.from_iterable(pi.values())) != set(G.domain())): + if sum(len(p) for p in pi.values()) != len(G.domain()) or set(chain.from_iterable(pi.values())) != set(G.domain()): return False for orbit in G.orbits(): if not any(set(orbit).issubset(p) for p in pi.values()): @@ -949,9 +929,8 @@ def graded_component(self, mc): raise ValueError("invalid degree") S = _SymmetricGroup(sum(mc)).young_subgroup(mc) domain = S.domain() - pi = {i: domain[sum(mc[:i]): sum(mc[:i+1])] for i in range(len(mc))} - return Set([self(G, pi, check=False) for G in S.conjugacy_classes_subgroups() - if len(G.disjoint_direct_product_decomposition()) <= 1]) + pi = {i: domain[sum(mc[:i]) : sum(mc[: i + 1])] for i in range(len(mc))} + return Set([self(G, pi, check=False) for G in S.conjugacy_classes_subgroups() if len(G.disjoint_direct_product_decomposition()) <= 1]) def _an_element_(self): """ @@ -1054,29 +1033,24 @@ def _stabilizer_subgroups(G, X, a, side='right', check=True): if not a(h * g, x) == a(g, a(h, x)): raise ValueError(f"The given function is not a left group action: g={g}, h={h}, x={x} do not satisfy the condition") - g_orbits = [orbit_decomposition(X_set, lambda x: a(g, x)) - for g in G.gens()] + g_orbits = [orbit_decomposition(X_set, lambda x: a(g, x)) for g in G.gens()] elif side == "right": if check: for g, h, x in product(G, G, X): if not a(x, h * g) == a(a(x, h), g): raise ValueError(f"The given function is not a right group action: g={g}, h={h}, x={x} do not satisfy the condition") - g_orbits = [orbit_decomposition(X_set, lambda x: a(x, g)) - for g in G.gens()] + g_orbits = [orbit_decomposition(X_set, lambda x: a(x, g)) for g in G.gens()] else: raise ValueError(f"The argument side must be 'left' or 'right' but is {side}") - gens = [PermutationGroupElement([tuple([to_gap[x] for x in o]) - for o in g_orbit]) - for g_orbit in g_orbits] + gens = [PermutationGroupElement([tuple([to_gap[x] for x in o]) for o in g_orbit]) for g_orbit in g_orbits] result = [] M = set(range(1, len(to_gap) + 1)) while M: p = M.pop() OS = libgap.OrbitStabilizer(G, p, G.gens(), gens) - result.append(PermutationGroup(gap_group=OS["stabilizer"], - domain=G.domain())) + result.append(PermutationGroup(gap_group=OS["stabilizer"], domain=G.domain())) M.difference_update(OS["orbit"].sage()) return result @@ -1098,6 +1072,7 @@ class MolecularSpecies(IndexedFreeAbelianMonoid): sage: M(G, {0: [5,6], 1: [1,2,3,4]}) E_2(X)*E_2(Y^2) """ + @staticmethod def __classcall__(cls, names): """ @@ -1133,8 +1108,7 @@ def __init__(self, names) -> None: """ indices = AtomicSpecies(names) category = Monoids().Commutative() & SetsWithGrading().Infinite() - IndexedFreeAbelianMonoid.__init__(self, indices, prefix='', - bracket=False, category=category) + IndexedFreeAbelianMonoid.__init__(self, indices, prefix='', bracket=False, category=category) self._arity = indices._arity def _repr_(self): @@ -1289,9 +1263,7 @@ def _element_constructor_(self, G, pi=None, check=True): if side not in ['left', 'right']: raise ValueError(f"the side must be 'right' or 'left', but is {side}") dompart = [sorted(pi.get(s, [])) for s in range(self._arity)] - S = PermutationGroup([tuple(b) for b in dompart if len(b) > 2] - + [(b[0], b[1]) for b in dompart if len(b) > 1], - domain=list(chain(*dompart))) + S = PermutationGroup([tuple(b) for b in dompart if len(b) > 2] + [(b[0], b[1]) for b in dompart if len(b) > 1], domain=list(chain(*dompart))) H = _stabilizer_subgroups(S, X, a, side=side, check=check) if len(H) > 1: raise ValueError("action is not transitive") @@ -1325,12 +1297,9 @@ def _element_constructor_(self, G, pi=None, check=True): # the following appears to be slower # H_gap = libgap.Action(G, [G._domain_to_gap[i] for i in component], libgap.OnPoints) # H = PermutationGroup(gap_group=H_gap, domain=component) - gens = [[cyc for cyc in gen.cycle_tuples() if cyc[0] in component] - for gen in G.gens()] - H = PermutationGroup([gen for gen in gens if gen], - domain=component) - pi_H = {k: [e for e in v if e in component] - for k, v in pi.items()} + gens = [[cyc for cyc in gen.cycle_tuples() if cyc[0] in component] for gen in G.gens()] + H = PermutationGroup([gen for gen in gens if gen], domain=component) + pi_H = {k: [e for e in v if e in component] for k, v in pi.items()} a = self._indices(H, pi_H, check=check) elm *= self.gen(a) return elm @@ -1392,7 +1361,7 @@ def graded_component(self, mc): raise ValueError("invalid degree") S = _SymmetricGroup(sum(mc)).young_subgroup(mc) domain = S.domain() - pi = {i: domain[sum(mc[:i]): sum(mc[:i+1])] for i in range(len(mc))} + pi = {i: domain[sum(mc[:i]) : sum(mc[: i + 1])] for i in range(len(mc))} return Set([self(G, pi, check=False) for G in S.conjugacy_classes_subgroups()]) class Element(IndexedFreeAbelianMonoidElement): @@ -1412,6 +1381,7 @@ class Element(IndexedFreeAbelianMonoidElement): sage: C3 = M(CyclicPermutationGroup(3)) sage: TestSuite(X*C3).run() """ + @cached_method def grade(self): r""" @@ -1506,9 +1476,7 @@ def _richcmp_(self, other, op): # the arities match because the parents are equal if self.grade() != other.grade(): # X should come before Y - return (sum(self.grade()) < sum(other.grade()) - or (sum(self.grade()) == sum(other.grade()) - and self.grade() > other.grade())) + return sum(self.grade()) < sum(other.grade()) or (sum(self.grade()) == sum(other.grade()) and self.grade() > other.grade()) S = _SymmetricGroup(sum(self.grade())).young_subgroup(self.grade()) # conjugate self and other to match S @@ -1588,19 +1556,18 @@ def permutation_group(self): sage: F.permutation_group()[0].domain() {1, 2} """ + def shift_gens(gens, n): """ Given a list of generators ``gens``, increase every element of the domain by ``n``. """ - return tuple([tuple([tuple([n + e for e in cyc]) - for cyc in gen.cycle_tuples()]) - for gen in gens]) + return tuple([tuple([tuple([n + e for e in cyc]) for cyc in gen.cycle_tuples()]) for gen in gens]) factors = list(self) if not factors: k = self.parent()._arity - return _SymmetricGroup(0), tuple([frozenset()]*k) + return _SymmetricGroup(0), tuple([frozenset()] * k) if len(factors) == 1: A, n = factors[0] @@ -1611,35 +1578,27 @@ def shift_gens(gens, n): if n % 2 == 1: # split off a single monomial a = list(A._monomial)[0] # as atomic species - b, b_dompart = (A ** (n-1)).permutation_group() + b, b_dompart = (A ** (n - 1)).permutation_group() gens = a._dis.gens() + shift_gens(b.gens(), a._tc) - new_dompart = tuple([frozenset(list(p_a) + [a._tc + e for e in p_b]) - for p_a, p_b in zip(a._dompart, b_dompart)]) + new_dompart = tuple([frozenset(list(p_a) + [a._tc + e for e in p_b]) for p_a, p_b in zip(a._dompart, b_dompart)]) domain = range(1, n * a._tc + 1) else: f, f_dompart = (A ** (n // 2)).permutation_group() tc = sum(len(p) for p in f_dompart) gens = f.gens() + shift_gens(f.gens(), tc) - new_dompart = tuple([frozenset(list(p) + [tc + e for e in p]) - for p in f_dompart]) + new_dompart = tuple([frozenset(list(p) + [tc + e for e in p]) for p in f_dompart]) domain = range(1, 2 * tc + 1) G = PermutationGroup(gens, domain=domain) return G, new_dompart - f_dompart_list = [(A ** n).permutation_group() for A, n in factors] + f_dompart_list = [(A**n).permutation_group() for A, n in factors] f_list = [f for f, _ in f_dompart_list] dompart_list = [f_dompart for _, f_dompart in f_dompart_list] - tc_list = list(accumulate([sum(len(b) for b in f_dompart) - for f_dompart in dompart_list], - initial=0)) - gens = [gen - for f, tc in zip(f_list, tc_list) - for gen in shift_gens(f.gens(), tc) if gen] # gen is a tuple - G = PermutationGroup(gens, domain=range(1, tc_list[-1]+1)) - new_dompart = tuple([frozenset(chain(*[[tc + e for e in p] - for p, tc in zip(f_dompart, tc_list)])) - for f_dompart in zip(*dompart_list)]) + tc_list = list(accumulate([sum(len(b) for b in f_dompart) for f_dompart in dompart_list], initial=0)) + gens = [gen for f, tc in zip(f_list, tc_list) for gen in shift_gens(f.gens(), tc) if gen] # gen is a tuple + G = PermutationGroup(gens, domain=range(1, tc_list[-1] + 1)) + new_dompart = tuple([frozenset(chain(*[[tc + e for e in p] for p, tc in zip(f_dompart, tc_list)])) for f_dompart in zip(*dompart_list)]) return G, new_dompart @@ -1707,7 +1666,7 @@ def cycle_index(self, parent=None): k = self.parent()._arity if parent is None: p = SymmetricFunctions(QQ).powersum() - parent = tensor([p]*k) + parent = tensor([p] * k) elif parent not in Modules.WithBasis: raise ValueError("`parent` should be a module with basis indexed by partitions") base_ring = parent.base_ring() @@ -1721,13 +1680,9 @@ def cycle_type(g): cycle_type = [[] for _ in range(k)] for c in tuples: cycle_type[pi[c[0]]].append(len(c)) - return tuple([_Partitions(sorted(c, reverse=True)) - for c in cycle_type]) + return tuple([_Partitions(sorted(c, reverse=True)) for c in cycle_type]) - return (parent.sum_of_terms([cycle_type(C.an_element()), - base_ring(C.cardinality())] - for C in G.conjugacy_classes()) - / G.cardinality()) + return parent.sum_of_terms([cycle_type(C.an_element()), base_ring(C.cardinality())] for C in G.conjugacy_classes()) / G.cardinality() def __call__(self, *args): r""" @@ -1862,13 +1817,11 @@ def structures(self, *labels): # TODO: maybe OrderedSetPartitions should not raise # an error if the second argument is a composition, # but not of the right size - dissections = [OrderedSetPartitions(l, [mc[i] for mc in sizes]) - for i, l in enumerate(labels)] + dissections = [OrderedSetPartitions(l, [mc[i] for mc in sizes]) for i, l in enumerate(labels)] except ValueError: return for d in product(*dissections): - yield from product(*[a.structures(*[l[i] for l in d]) - for i, a in enumerate(atoms)]) + yield from product(*[a.structures(*[l[i] for l in d]) for i, a in enumerate(atoms)]) class PolynomialSpeciesElement(CombinatorialFreeModule.Element): @@ -1887,6 +1840,7 @@ class PolynomialSpeciesElement(CombinatorialFreeModule.Element): sage: TestSuite(E2*X + C3).run() """ + def is_constant(self): """ Return ``True`` if this is a constant polynomial species. @@ -2011,9 +1965,8 @@ def tilde(self): result_m = P_one for a, e in m: G, pi = a.permutation_group() - result_a = P.sum(P(G.centralizer(g), pi) - for g in G.conjugacy_classes_representatives()) - result_m *= result_a ** e + result_a = P.sum(P(G.centralizer(g), pi) for g in G.conjugacy_classes_representatives()) + result_m *= result_a**e result += c * result_m return result @@ -2084,8 +2037,7 @@ def hadamard_product(self, other): g = list(chain.from_iterable(dompart)) conj_L = PermutationGroupElement(g).inverse() G = libgap.ConjugateGroup(G, conj_L) - pi = {i: range(x - mc[i] + 1, x + 1) - for i, x in enumerate(accumulate(mc))} + pi = {i: range(x - mc[i] + 1, x + 1) for i, x in enumerate(accumulate(mc))} for R, d in other: if mc != R.grade(): continue @@ -2158,8 +2110,7 @@ def _compose_with_singletons(self, names, args): # TODO: possibly check that all args are compositions, # and that sums match cardinalities comp = list(chain.from_iterable(args)) - pi = {i: range(x - comp[i] + 1, x + 1) - for i, x in enumerate(accumulate(comp))} + pi = {i: range(x - comp[i] + 1, x + 1) for i, x in enumerate(accumulate(comp))} S_down = _SymmetricGroup(sum(comp)).young_subgroup(comp) P = PolynomialSpecies(self.parent().base_ring(), names) @@ -2179,8 +2130,7 @@ def _compose_with_singletons(self, names, args): # sum over double coset representatives. summand = P.zero() for tau, _ in taus: - H = libgap.Intersection(libgap.ConjugateGroup(G, tau.Inverse()), - S_down) + H = libgap.Intersection(libgap.ConjugateGroup(G, tau.Inverse()), S_down) K = PermutationGroup(gap_group=H, domain=range(1, tc + 1)) summand += P(K, pi, check=False) result += c * summand @@ -2307,8 +2257,7 @@ def _compose_with_weighted_singletons(self, names, multiplicities, degrees): left = self._compose_with_singletons(names, degrees) P = left.parent() - right = P._exponential(multiplicities, - list(chain.from_iterable(degrees))) + right = P._exponential(multiplicities, list(chain.from_iterable(degrees))) return left.hadamard_product(right) def __call__(self, *args): @@ -2390,12 +2339,9 @@ def __call__(self, *args): result = P0.zero() for mc in F_degrees: F = P.sum_of_terms((M, c) for M, c in self if M.grade() == mc) - for degrees in cartesian_product([IntegerVectors(d, length=len(arg)) - for d, arg in zip(mc, args)]): + for degrees in cartesian_product([IntegerVectors(d, length=len(arg)) for d, arg in zip(mc, args)]): # each degree is a weak composition of the degree of F in sort i - FX = F._compose_with_weighted_singletons(names, - multiplicities, - degrees) + FX = F._compose_with_weighted_singletons(names, multiplicities, degrees) FG = [(M(*molecules), c) for M, c in FX] result += P0.sum_of_terms(FG) return result @@ -2421,13 +2367,11 @@ def factor(self): 2 * 3 """ # find the set of atoms and fix an order - atoms = list(set(a for m in self.monomial_coefficients() - for a in m.support())) + atoms = list(set(a for m in self.monomial_coefficients() for a in m.support())) R = PolynomialRing(self.base_ring(), "x", len(atoms)) var_dict = dict(zip(atoms, R.gens())) # create the polynomial - poly = R.sum(c * R.prod(var_dict[a] ** e for a, e in m.dict().items()) - for m, c in self) + poly = R.sum(c * R.prod(var_dict[a] ** e for a, e in m.dict().items()) for m, c in self) factors = poly.factor() unit = self.base_ring()(factors.unit()) P = self.parent() @@ -2436,10 +2380,7 @@ def factor(self): def _from_etuple(e): return M.element_class(M, {a: i for a, i in zip(atoms, e) if i}) - factors = [(P.sum_of_terms((_from_etuple(mon), c) - for mon, c in factor.monomial_coefficients().items()), - exponent) - for factor, exponent in factors] + factors = [(P.sum_of_terms((_from_etuple(mon), c) for mon, c in factor.monomial_coefficients().items()), exponent) for factor, exponent in factors] return Factorization(factors, unit=unit, sort=False) def structures(self, *labels): @@ -2499,6 +2440,7 @@ class PolynomialSpecies(CombinatorialFreeModule): sage: P(G, ([1,2], [3,4,5])) E_2(X)*E_3(Y) """ + def __classcall__(cls, base_ring, names): r""" Normalize the arguments. @@ -2531,10 +2473,7 @@ def __init__(self, base_ring, names) -> None: """ # should we pass a category to basis_keys? category = GradedAlgebrasWithBasis(base_ring).Commutative() - CombinatorialFreeModule.__init__(self, base_ring, - basis_keys=MolecularSpecies(names), - category=category, - prefix='', bracket=False) + CombinatorialFreeModule.__init__(self, base_ring, basis_keys=MolecularSpecies(names), category=category, prefix='', bracket=False) self._arity = len(names) def _repr_(self): @@ -2692,12 +2631,9 @@ def _element_constructor_(self, G, pi=None, check=True): if side not in ['left', 'right']: raise ValueError(f"the side must be 'right' or 'left', but is {side}") dompart = [sorted(pi.get(s, [])) for s in range(self._arity)] - S = PermutationGroup([tuple(b) for b in dompart if len(b) > 2] - + [(b[0], b[1]) for b in dompart if len(b) > 1], - domain=list(chain(*dompart))) + S = PermutationGroup([tuple(b) for b in dompart if len(b) > 2] + [(b[0], b[1]) for b in dompart if len(b) > 1], domain=list(chain(*dompart))) Hs = _stabilizer_subgroups(S, X, a, side=side, check=check) - return self.sum_of_terms((self._indices(H, pi, check=check), ZZ.one()) - for H in Hs) + return self.sum_of_terms((self._indices(H, pi, check=check), ZZ.one()) for H in Hs) if isinstance(G, PermutationGroup_generic): if pi is None: @@ -2726,8 +2662,7 @@ def _first_ngens(self, n): X + 2*Y """ B = self.basis() - return tuple([B[i] for grade in IntegerVectors(1, length=self._arity) - for i in self._indices.graded_component(grade)]) + return tuple([B[i] for grade in IntegerVectors(1, length=self._arity) for i in self._indices.graded_component(grade)]) def change_ring(self, R): r""" @@ -2858,10 +2793,7 @@ def _powersum(self, s, n): raise ValueError("n must be a positive integer") if n == 1: return self(_SymmetricGroup(1), {s: [1]}, check=False) - return (ZZ(n) * self(_SymmetricGroup(n), {s: range(1, n+1)}, check=False) - - sum(self(_SymmetricGroup(i), {s: range(1, i+1)}, check=False) - * self._powersum(s, n-i) - for i in range(1, n))) + return ZZ(n) * self(_SymmetricGroup(n), {s: range(1, n + 1)}, check=False) - sum(self(_SymmetricGroup(i), {s: range(1, i + 1)}, check=False) * self._powersum(s, n - i) for i in range(1, n)) def _exponential(self, multiplicities, degrees): r""" @@ -2923,6 +2855,7 @@ def _exponential(self, multiplicities, degrees): sage: P._exponential([1], [0]).parent() Polynomial species in X over Rational Field """ + def stretch(c, k): r""" Substitute in ``c`` all variables appearing in the @@ -2930,7 +2863,7 @@ def stretch(c, k): """ if callable(c): B = self.base_ring() - return c(*[g ** k for g in B.gens() if g != B.one()]) + return c(*[g**k for g in B.gens() if g != B.one()]) return c def factor(s, c, d): @@ -2939,13 +2872,9 @@ def factor(s, c, d): We use Proposition 2 in [Labelle2008]_. """ - return self.sum(~ mu.centralizer_size() - * self.prod(stretch(c, k) - * self._powersum(s, k) for k in mu) - for mu in Partitions(d)) + return self.sum(~mu.centralizer_size() * self.prod(stretch(c, k) * self._powersum(s, k) for k in mu) for mu in Partitions(d)) - return self.prod(factor(s, multiplicities[s], degrees[s]) - for s in range(self._arity)) + return self.prod(factor(s, multiplicities[s], degrees[s]) for s in range(self._arity)) Element = PolynomialSpeciesElement @@ -2983,28 +2912,23 @@ def _atomic_set_like_species(n, names): M = MolecularSpecies(names) A = AtomicSpecies(names) if n == 1: - return tuple([M({A(_SymmetricGroup(1), {s: [1]}, check=False): ZZ.one()}, - check=False) - for s in range(M._arity)]) + return tuple([M({A(_SymmetricGroup(1), {s: [1]}, check=False): ZZ.one()}, check=False) for s in range(M._arity)]) result = [] for d in divisors(n): if d == 1: continue if d == n: - result.extend(M({A(_SymmetricGroup(n), {s: range(1, n+1)}, check=False): ZZ.one()}, - check=False) - for s in range(M._arity)) + result.extend(M({A(_SymmetricGroup(n), {s: range(1, n + 1)}, check=False): ZZ.one()}, check=False) for s in range(M._arity)) continue - E_d = M1({A1(_SymmetricGroup(d), check=False): ZZ.one()}, - check=False) + E_d = M1({A1(_SymmetricGroup(d), check=False): ZZ.one()}, check=False) l = [] w = [] for degree in range(1, n // d + 1): a_degree = _atomic_set_like_species(degree, names) l.extend(a_degree) - w.extend([degree]*len(a_degree)) + w.extend([degree] * len(a_degree)) for a in WeightedIntegerVectors(n // d, w): - G = prod(F ** e for F, e in zip(l, a)) + G = prod(F**e for F, e in zip(l, a)) F = E_d(G) # TODO: can we make this faster? F.support()[0].rename(f"E_{d}({G})") result.append(F) diff --git a/src/sage/rings/tate_algebra.py b/src/sage/rings/tate_algebra.py index d19ebed1ecd..758691f21c5 100644 --- a/src/sage/rings/tate_algebra.py +++ b/src/sage/rings/tate_algebra.py @@ -119,7 +119,6 @@ - Xavier Caruso, Thibaut Verron (2018-09) """ - # *************************************************************************** # Copyright (C) 2018 Xavier Caruso # Thibaut Verron @@ -153,6 +152,7 @@ # Factory ######### + class TateAlgebraFactory(UniqueFactory): r""" Construct a Tate algebra over a `p`-adic field. @@ -243,6 +243,7 @@ class TateAlgebraFactory(UniqueFactory): - Xavier Caruso, Thibaut Verron (2018-09) """ + def create_key(self, base, prec=None, log_radii=ZZ(0), names=None, order='degrevlex'): """ Create a key from the input parameters. @@ -309,7 +310,7 @@ def create_key(self, base, prec=None, log_radii=ZZ(0), names=None, order='degrev raise ValueError("the number of radii does not match the number of variables") else: try: - log_radii = [ ZZ(r) for r in log_radii ] + log_radii = [ZZ(r) for r in log_radii] except TypeError: raise NotImplementedError("only integral log_radii are implemented") order = TermOrder(order, ngens) @@ -338,6 +339,7 @@ def create_object(self, version, key): # Parent for terms ################## + class TateTermMonoid(Monoid_class, UniqueRepresentation): r""" A base class for Tate algebra terms. @@ -348,6 +350,7 @@ class TateTermMonoid(Monoid_class, UniqueRepresentation): Those terms form a pre-ordered monoid, with term multiplication and the term order of the parent Tate algebra. """ + Element = TateAlgebraTerm def __init__(self, A): @@ -399,8 +402,7 @@ def _repr_(self): """ if self._ngens == 0: return "Monoid of terms over %s" % self._base - vars = ", ".join("%s (val >= %s)" % (var, -r) - for var, r in zip(self._names, self._log_radii)) + vars = ", ".join("%s (val >= %s)" % (var, -r) for var, r in zip(self._names, self._log_radii)) return "Monoid of terms in %s over %s" % (vars, self._base) def _latex_(self): @@ -666,7 +668,7 @@ def some_elements(self): sage: T.some_elements() [...00000000010, ...0000000001*x, ...0000000001*y, ...00000000010*x*y] """ - elts = [ self(self._field.uniformizer()) ] + list(self.gens()) + elts = [self(self._field.uniformizer())] + list(self.gens()) elts.append(prod(elts)) return elts @@ -674,6 +676,7 @@ def some_elements(self): # Tate algebras ############### + class TateAlgebra_generic(Parent): def __init__(self, field, prec, log_radii, names, order, integral=False): """ @@ -690,6 +693,7 @@ def __init__(self, field, prec, log_radii, names, order, integral=False): """ from sage.misc.latex import latex_variable_name from sage.rings.polynomial.polynomial_ring_constructor import _multi_variate + self.element_class = TateAlgebraElement self._field = field self._cap = prec @@ -706,19 +710,17 @@ def __init__(self, field, prec, log_radii, names, order, integral=False): base = field.integer_ring() else: base = field - Parent.__init__(self, base=base, names=names, - category=Algebras(base).Commutative()) + Parent.__init__(self, base=base, names=names, category=Algebras(base).Commutative()) self._polynomial_ring = _multi_variate(field, names, order=order) one = field.one() self._parent_terms = TateTermMonoid(self) - self._oneterm = self._parent_terms(one, ETuple([0]*self._ngens)) + self._oneterm = self._parent_terms(one, ETuple([0] * self._ngens)) if integral: # This needs to be update if log_radii are allowed to be non-integral self._gens = [self.element_class(self, (one << log_radii[i]) * self._polynomial_ring.gen(i)) for i in range(self._ngens)] self._integer_ring = self else: - self._gens = [self.element_class(self, g) - for g in self._polynomial_ring.gens()] + self._gens = [self.element_class(self, g) for g in self._polynomial_ring.gens()] self._integer_ring = TateAlgebra_generic(field, prec, log_radii, names, order, integral=True) self._integer_ring._rational_ring = self._rational_ring = self @@ -806,9 +808,7 @@ def _coerce_map_from_(self, R): Rbase = R.base_ring() logs = self._log_radii Rlogs = R.log_radii() - if (base.has_coerce_map_from(Rbase) - and self._names == R.variable_names() - and self._order == R.term_order()): + if base.has_coerce_map_from(Rbase) and self._names == R.variable_names() and self._order == R.term_order(): ratio = base.absolute_e() // Rbase.absolute_e() return all(logs[i] == ratio * Rlogs[i] for i in range(self._ngens)) return False @@ -860,7 +860,7 @@ def _pushout_(self, R): base = pushout(self._base, R) ratio = base.absolute_e() // self._base.absolute_e() cap = ratio * self._cap - log_radii = [ ratio * r for r in self._log_radii ] + log_radii = [ratio * r for r in self._log_radii] A = TateAlgebra(base, cap, log_radii, self._names, self._order) if base.is_field(): return A @@ -886,6 +886,7 @@ def _ideal_class_(self, n=0): The argument ``n`` is disregarded in the current implementation. """ from sage.rings.tate_algebra_ideal import TateAlgebraIdeal + return TateAlgebraIdeal def prime(self): @@ -981,8 +982,8 @@ def some_elements(self): ...0000000001*y + ...00000000010*x*y, ...00000000100*x*y] """ - terms = [ self.zero() ] + [ self(t) for t in self.monoid_of_terms().some_elements() ] - return [ terms[i] + terms[j] for i in range(len(terms)) for j in range(i, len(terms)) ] + terms = [self.zero()] + [self(t) for t in self.monoid_of_terms().some_elements()] + return [terms[i] + terms[j] for i in range(len(terms)) for j in range(i, len(terms))] def _repr_(self): """ @@ -998,8 +999,7 @@ def _repr_(self): sage: A.integer_ring() Integer ring of the Tate Algebra in x (val >= 0), y (val >= 0) over 2-adic Field with capped relative precision 10 """ - vars = ", ".join("%s (val >= %s)" % (var, -r) - for var, r in zip(self._names, self._log_radii)) + vars = ", ".join("%s (val >= %s)" % (var, -r) for var, r in zip(self._names, self._log_radii)) if self._integral: return "Integer ring of the Tate Algebra in %s over %s" % (vars, self._field) return "Tate Algebra in %s over %s" % (vars, self._field) @@ -1022,6 +1022,7 @@ def _latex_(self): '\\Bold{Q}_{2}\\{u_{1},u_{2}\\}_{(1,2)}' """ from sage.misc.latex import latex + s = r"%s\{%s\}" % (latex(self._field), ",".join(self._latex_names)) if self._integral: s += r"^{\circ}" diff --git a/src/sage/rings/tests.py b/src/sage/rings/tests.py index 52ec76cbac4..3332c41b249 100644 --- a/src/sage/rings/tests.py +++ b/src/sage/rings/tests.py @@ -30,6 +30,7 @@ def prime_finite_field(): """ from sage.rings.integer_ring import ZZ from sage.rings.finite_rings.finite_field_constructor import GF + return GF(ZZ.random_element(x=2, y=10**20 - 12).next_prime()) @@ -51,6 +52,7 @@ def finite_field(): """ from sage.rings.integer_ring import ZZ from sage.rings.finite_rings.finite_field_constructor import GF + p = ZZ.random_element(x=2, y=10**6 - 18).next_prime() d = ZZ.random_element(x=1, y=20) return GF(p**d, 'a') @@ -75,6 +77,7 @@ def small_finite_field(): """ from sage.rings.integer_ring import ZZ from sage.rings.finite_rings.finite_field_constructor import GF + while True: q = ZZ.random_element(x=2, y=2**16) if q.is_prime_power(): @@ -95,6 +98,7 @@ def integer_mod_ring(): """ from sage.rings.integer_ring import ZZ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing + n = ZZ.random_element(x=2, y=50000) return IntegerModRing(n) @@ -112,6 +116,7 @@ def padic_field(): """ from sage.rings.integer_ring import ZZ from sage.rings.padics.factory import Qp + prec = ZZ.random_element(x=10, y=100) p = ZZ.random_element(x=2, y=10**4 - 30).next_prime() return Qp(p, prec) @@ -129,8 +134,9 @@ def quadratic_number_field(): """ from sage.rings.integer_ring import ZZ from sage.rings.number_field.number_field import QuadraticField + while True: - d = ZZ.random_element(x=-10**5, y=10**5) + d = ZZ.random_element(x=-(10**5), y=10**5) if not d.is_square(): return QuadraticField(d, 'a') @@ -149,13 +155,13 @@ def absolute_number_field(maxdeg=10): """ from sage.rings.integer_ring import ZZ from sage.rings.number_field.number_field import NumberField + R = ZZ['x'] while True: - f = R.random_element(degree=ZZ.random_element(x=1, y=maxdeg), - x=-100, y=100) + f = R.random_element(degree=ZZ.random_element(x=1, y=maxdeg), x=-100, y=100) if f.degree() <= 0: continue - f = f + R.gen()**(f.degree() + 1) # make monic + f = f + R.gen() ** (f.degree() + 1) # make monic if f.is_irreducible(): return NumberField(f, 'a') @@ -189,6 +195,7 @@ def relative_number_field(n=2, maxdeg=2): sage: _ = relative_number_field(3) # needs sage.rings.number_field """ from sage.rings.integer_ring import ZZ + K = absolute_number_field(maxdeg) n -= 1 var = 'aa' @@ -196,12 +203,11 @@ def relative_number_field(n=2, maxdeg=2): R1 = K['x'] while n >= 1: while True: - f = R.random_element(degree=ZZ.random_element(x=1, y=maxdeg), - x=-100, y=100) + f = R.random_element(degree=ZZ.random_element(x=1, y=maxdeg), x=-100, y=100) if f.degree() <= 0: continue f = f * f.denominator() # bug trac #4781 - f = f + R.gen()**maxdeg # make monic + f = f + R.gen() ** maxdeg # make monic if R1(f).is_irreducible(): break K = K.extension(f, var) @@ -238,13 +244,9 @@ def rings0(): from sage.rings.integer_ring import IntegerRing from sage.rings.rational_field import RationalField - v = [(IntegerRing, 'ring of integers'), - (RationalField, 'field of rational numbers'), - (integer_mod_ring, 'integers modulo n for n at most 50000')] + v = [(IntegerRing, 'ring of integers'), (RationalField, 'field of rational numbers'), (integer_mod_ring, 'integers modulo n for n at most 50000')] try: - v += [(prime_finite_field, 'a prime finite field with cardinality at most 10^20'), - (finite_field, 'finite field with degree at most 20 and prime at most 10^6'), - (small_finite_field, 'finite field with cardinality at most 2^16')] + v += [(prime_finite_field, 'a prime finite field with cardinality at most 10^20'), (finite_field, 'finite field with degree at most 20 and prime at most 10^6'), (small_finite_field, 'finite field with cardinality at most 2^16')] except ImportError: pass @@ -254,9 +256,7 @@ def rings0(): pass try: - v += [(quadratic_number_field, 'a quadratic number field'), - (absolute_number_field, 'an absolute number field of degree at most 10'), - (relative_number_field, 'a tower of at most 2 extensions each of degree at most 2')] + v += [(quadratic_number_field, 'a quadratic number field'), (absolute_number_field, 'an absolute number field of degree at most 10'), (relative_number_field, 'a tower of at most 2 extensions each of degree at most 2')] except ImportError: pass @@ -290,22 +290,16 @@ def rings1(): from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.integer_ring import ZZ - v = [(lambda: PolynomialRing(next(X), names='x'), - 'univariate polynomial ring over level 0 ring'), - (lambda: PowerSeriesRing(next(X), names='x'), - 'univariate power series ring over level 0 ring')] + v = [(lambda: PolynomialRing(next(X), names='x'), 'univariate polynomial ring over level 0 ring'), (lambda: PowerSeriesRing(next(X), names='x'), 'univariate power series ring over level 0 ring')] try: from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing except ImportError: pass else: - v += [(lambda: LaurentPolynomialRing(next(X), names='x'), - 'univariate Laurent polynomial ring over level 0 ring')] + v += [(lambda: LaurentPolynomialRing(next(X), names='x'), 'univariate Laurent polynomial ring over level 0 ring')] - v += [(lambda: PolynomialRing(next(X), abs(ZZ.random_element(x=2, y=10)), - names='x'), - 'multivariate polynomial ring in between 2 and 10 variables over a level 0 ring')] + v += [(lambda: PolynomialRing(next(X), abs(ZZ.random_element(x=2, y=10)), names='x'), 'multivariate polynomial ring in between 2 and 10 variables over a level 0 ring')] return v @@ -426,10 +420,7 @@ def check_random_arith(level=MAX_LEVEL, trials=1): @random_testing -def check_karatsuba_multiplication(base_ring, maxdeg1, maxdeg2, - ref_mul=lambda f, g: f._mul_generic(g), - base_ring_random_elt_args=[], - numtests=10, verbose=False): +def check_karatsuba_multiplication(base_ring, maxdeg1, maxdeg2, ref_mul=lambda f, g: f._mul_generic(g), base_ring_random_elt_args=[], numtests=10, verbose=False): """ Test univariate Karatsuba multiplication against other multiplication algorithms. @@ -482,6 +473,7 @@ def check_karatsuba_multiplication(base_ring, maxdeg1, maxdeg2, from sage.misc.prandom import randint from sage.misc.sage_input import sage_input from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + threshold = randint(0, min(maxdeg1, maxdeg2)) R = PolynomialRing(base_ring, 'x') if verbose: diff --git a/src/sage/rings/universal_cyclotomic_field.py b/src/sage/rings/universal_cyclotomic_field.py index 5384233a920..98fa208c630 100644 --- a/src/sage/rings/universal_cyclotomic_field.py +++ b/src/sage/rings/universal_cyclotomic_field.py @@ -202,10 +202,8 @@ def late_import(): global gap, gap3, libgap global GapElement_Integer, GapElement_Rational, GapElement_Cyclotomic from sage.libs.gap.libgap import libgap - from sage.libs.gap.element import (GapElement_Integer, - GapElement_Rational, - GapElement_Cyclotomic) - from sage.interfaces import (gap, gap3) + from sage.libs.gap.element import GapElement_Integer, GapElement_Rational, GapElement_Cyclotomic + from sage.interfaces import gap, gap3 def UCF_sqrt_int(N, UCF): @@ -239,11 +237,11 @@ def UCF_sqrt_int(N, UCF): res = UCF.one() if N > 0 else UCF.zeta(4) for p, e in N.factor(): if p == 2: - res *= (UCF.zeta(8) + UCF.zeta(8, 7))**e + res *= (UCF.zeta(8) + UCF.zeta(8, 7)) ** e else: - res *= UCF.sum(UCF.zeta(p, n**2) for n in range(p))**e + res *= UCF.sum(UCF.zeta(p, n**2) for n in range(p)) ** e if p % 4 == 3: - res *= (UCF.zeta(4))**e + res *= (UCF.zeta(4)) ** e return res @@ -266,6 +264,7 @@ class UCFtoQQbar(Morphism): sage: complex(UCF.one()/2) (0.5+0j) """ + def __init__(self, UCF): r""" INPUT: @@ -393,6 +392,7 @@ def __eq__(self, other) -> bool: """ if parent(self) is not parent(other): from sage.structure.element import coercion_model as cm + try: self, other = cm.canonical_coercion(self, other) except TypeError: @@ -533,6 +533,7 @@ def _symbolic_(self, R): I + 1 """ from sage.symbolic.constants import pi, I + k = ZZ(self._obj.Conductor()) coeffs = self._obj.CoeffsCyc(k).sage() s = R.zero() @@ -596,6 +597,7 @@ def to_cyclotomic_field(self, R=None): zeta4 + 1 """ from sage.rings.number_field.number_field import CyclotomicField + k = ZZ(self._obj.Conductor()) Rcan = CyclotomicField(k) if R is None: @@ -653,6 +655,7 @@ def __float__(self) -> float: 1.246979603717467 """ from sage.rings.real_mpfr import RR + return float(RR(self)) def __complex__(self): @@ -705,7 +708,7 @@ def _eval_complex_(self, R): k = ZZ(self._obj.Conductor()) coeffs = self._obj.CoeffsCyc(k).sage() zeta = R.zeta(k) - s = sum(coeffs[i] * zeta ** i for i in range(k)) + s = sum(coeffs[i] * zeta**i for i in range(k)) if self.is_real(): return R(s.real()) return s @@ -781,6 +784,7 @@ def _richcmp_(self, other, op) -> bool: o = other.imag_part() from sage.rings.real_mpfi import RealIntervalField + prec = 53 R = RealIntervalField(prec) sa = s._eval_real_(R) @@ -1000,7 +1004,7 @@ def _pow_(self, other): num = other.numerator() den = other.denominator() if den.is_one(): - return self ** num + return self**num if den == 2 and self._obj.IsRat(): return self.sqrt() ** num raise NotImplementedError("no powering implemented beyond square root of rationals") @@ -1104,8 +1108,7 @@ def sqrt(self, extend=True, all=False): if self._obj.IsInt(): return UCF_sqrt_int(D, UCF) - return UCF_sqrt_int(D.numerator(), UCF) / \ - UCF_sqrt_int(D.denominator(), UCF) + return UCF_sqrt_int(D.numerator(), UCF) / UCF_sqrt_int(D.denominator(), UCF) # root of unity k = self._obj.Conductor() @@ -1180,8 +1183,7 @@ def galois_conjugates(self, n=None) -> list: n = k if n is None else ZZ(n) if not k.divides(n): raise ValueError("n = {} must be a multiple of the conductor ({})".format(n, k)) - return [P.element_class(P, obj.GaloisCyc(i)) - for i in n.coprime_integers(n)] + return [P.element_class(P, obj.GaloisCyc(i)) for i in n.coprime_integers(n)] def __abs__(self): """ @@ -1235,8 +1237,7 @@ def norm_of_galois_extension(self): """ obj = self._obj k = obj.Conductor().sage() - return libgap.Product(libgap([obj.GaloisCyc(i) for i in range(k) - if k.gcd(i) == 1])).sage() + return libgap.Product(libgap([obj.GaloisCyc(i) for i in range(k) if k.gcd(i) == 1])).sage() def minpoly(self, var='x'): r""" @@ -1287,6 +1288,7 @@ class UniversalCyclotomicField(UniqueRepresentation, sage.rings.abc.UniversalCyc `\QQ` in the sense that any Abelian Galois extension of `\QQ` is also a subfield of the universal cyclotomic field. """ + Element = UniversalCyclotomicFieldElement @staticmethod @@ -1315,6 +1317,7 @@ def __init__(self, names=None): False """ from sage.categories.fields import Fields + Parent.__init__(self, base=QQ, category=Fields().Infinite()) self._populate_coercion_lists_(embedding=UCFtoQQbar(self)) late_import() @@ -1353,9 +1356,7 @@ def some_elements(self) -> tuple: sage: all(parent(x) is UniversalCyclotomicField() for x in _) True """ - return (self.zero(), self.one(), -self.one(), - self.gen(3, 1), - self.gen(7, 1) - self(2) / self(3) * self.gen(7, 2)) + return (self.zero(), self.one(), -self.one(), self.gen(3, 1), self.gen(7, 1) - self(2) / self(3) * self.gen(7, 2)) def _repr_(self) -> str: r""" @@ -1441,7 +1442,7 @@ def gen(self, n, k=1): sage: UCF.zeta(6) -E(3)^2 """ - return self.element_class(self, libgap.E(n)**k) + return self.element_class(self, libgap.E(n) ** k) zeta = gen @@ -1532,14 +1533,15 @@ def _element_constructor_(self, elt): # late import to avoid slowing down the above conversions import sage.rings.abc + P = parent(elt) if isinstance(P, sage.rings.abc.NumberField_cyclotomic): if isinstance(elt, NumberFieldElement_base): from sage.rings.number_field.number_field import CyclotomicField + n = P.gen().multiplicative_order() elt = CyclotomicField(n)(elt) - return sum(c * self.gen(n, i) - for i, c in enumerate(elt._coefficients())) + return sum(c * self.gen(n, i) for i, c in enumerate(elt._coefficients())) if hasattr(elt, '_algebraic_'): return elt._algebraic_(self) @@ -1567,6 +1569,7 @@ def _coerce_map_from_(self, other): if other is ZZ or other is QQ: return True import sage.rings.abc + if isinstance(other, sage.rings.abc.NumberField_cyclotomic): return True @@ -1678,8 +1681,7 @@ def _factor_univariate_polynomial(self, f): m = p.is_cyclotomic(certificate=True) if not m: raise NotImplementedError('no known factorization for this polynomial') - factors.extend((x - UCF.zeta(m, i), e) - for i in m.coprime_integers(m)) + factors.extend((x - UCF.zeta(m, i), e) for i in m.coprime_integers(m)) return Factorization(factors, unit) diff --git a/src/sage/rings/valuation/augmented_valuation.py b/src/sage/rings/valuation/augmented_valuation.py index 3c035d2be40..72713946d9e 100644 --- a/src/sage/rings/valuation/augmented_valuation.py +++ b/src/sage/rings/valuation/augmented_valuation.py @@ -135,6 +135,7 @@ Augmentations are described originally in [Mac1936I]_ and [Mac1936II]_. An overview can also be found in Chapter 4 of [Rüt2014]_. """ + # **************************************************************************** # Copyright (C) 2013-2017 Julian Rüth # @@ -176,6 +177,7 @@ class AugmentedValuationFactory(UniqueFactory): sage: ww._base_valuation is v True """ + def create_key(self, base_valuation, phi, mu, check=True): r""" Create a key which uniquely identifies the valuation over @@ -231,6 +233,7 @@ def create_object(self, version, key): base_valuation, phi, mu = key from .valuation_space import DiscretePseudoValuationSpace + parent = DiscretePseudoValuationSpace(base_valuation.domain()) if mu is not infinity: if base_valuation.is_trivial(): @@ -272,6 +275,7 @@ class AugmentedValuation_base(InductiveValuation): sage: TestSuite(w).run() # long time sage: TestSuite(ww).run() # long time """ + def __init__(self, parent, v, phi, mu): r""" TESTS:: @@ -527,6 +531,7 @@ def extensions(self, ring): return [self] from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(ring, PolynomialRing_generic): # univariate base_valuations = self._base_valuation.extensions(ring) phi = self.phi().change_ring(ring.base_ring()) @@ -566,6 +571,7 @@ def restriction(self, ring): if ring.is_subring(self.domain().base_ring()): return base from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(ring, PolynomialRing_generic): # univariate return base.augmentation(self.phi().change_ring(ring.base_ring()), self._mu) return super().restriction(ring) @@ -598,7 +604,7 @@ def is_gauss_valuation(self): sage: w.is_gauss_valuation() False """ - assert (self._mu > 0) + assert self._mu > 0 return False def monic_integral_model(self, G): @@ -643,6 +649,7 @@ def _ge_(self, other): False """ from .gauss_valuation import GaussValuation_generic + if other.is_trivial(): return other.is_discrete_valuation() if isinstance(other, GaussValuation_generic): @@ -775,6 +782,7 @@ def change_domain(self, ring): [ Gauss valuation induced by 2-adic valuation, v(x) = 1 ] """ from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(ring, PolynomialRing_generic) and ring.variable_name() == self.domain().variable_name(): return self._base_valuation.change_domain(ring).augmentation(self.phi().change_ring(ring.base_ring()), self._mu, check=False) return super().change_domain(ring) @@ -791,6 +799,7 @@ class FinalAugmentedValuation(AugmentedValuation_base, FinalInductiveValuation): sage: v = GaussValuation(R, valuations.TrivialValuation(QQ)) sage: w = v.augmentation(x, 1) """ + def __init__(self, parent, v, phi, mu): r""" TESTS:: @@ -1058,6 +1067,7 @@ def lift(self, F): from sage.rings.function_field.element_polymod import FunctionFieldElement_polymod from sage.rings.number_field.number_field_element import NumberFieldElement_relative from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + if isinstance(F, PolynomialQuotientRingElement): G = F.lift() elif isinstance(F, FunctionFieldElement_polymod): @@ -1066,7 +1076,7 @@ def lift(self, F): G = PolynomialRing(F.base_ring(), 'x')(list(F)) else: G = F.polynomial() - assert (G(self._residue_field_generator()) == F) + assert G(self._residue_field_generator()) == F F = G.change_variable_name(self._base_valuation.residue_ring().variable_name()) H = self._base_valuation.lift(F) @@ -1083,6 +1093,7 @@ class NonFinalAugmentedValuation(AugmentedValuation_base, NonFinalInductiveValua sage: v = GaussValuation(R, QQ.valuation(2)) sage: w = v.augmentation(x^2 + x + 1, 1) """ + def __init__(self, parent, v, phi, mu): r""" TESTS:: @@ -1120,6 +1131,7 @@ def residue_ring(self): Univariate Polynomial Ring in x over Finite Field of size 2 (using ...) """ from sage.categories.fields import Fields + if self.domain().base() not in Fields(): raise NotImplementedError("only implemented for polynomial rings over fields") @@ -1228,7 +1240,7 @@ def reduce(self, f, check=True, degree_bound=None, coefficients=None, valuations if coefficients is None: coefficients = self.coefficients(f) if degree_bound is not None: - coefficients = islice(coefficients, 0, tau*degree_bound + 1, 1) + coefficients = islice(coefficients, 0, tau * degree_bound + 1, 1) coefficients = list(coefficients) if valuations is None: @@ -1240,7 +1252,7 @@ def reduce(self, f, check=True, degree_bound=None, coefficients=None, valuations for i, c in enumerate(coefficients): if i % tau != 0: if check: - v = self._base_valuation(c) + i*self._mu + v = self._base_valuation(c) + i * self._mu assert v != 0 # this can not happen for an augmented valuation if v < 0: raise ValueError("f must not have negative valuation") @@ -1248,26 +1260,23 @@ def reduce(self, f, check=True, degree_bound=None, coefficients=None, valuations # the validity of the coefficients with i % tau == 0 is checked by # the recursive call to reduce below # replace f_i by f_i Q^{i tau} - if i//tau >= len(valuations): + if i // tau >= len(valuations): # we do not know the correct valuation of the coefficient, but # the computation is faster if we know that the coefficient # has positive valuation - valuations.append(self._base_valuation.lower_bound(c) + i*self._mu) - v = valuations[i//tau] + valuations.append(self._base_valuation.lower_bound(c) + i * self._mu) + v = valuations[i // tau] if v is infinity or v > 0: coefficients[i] = self.domain().zero() - valuations[i//tau] = infinity + valuations[i // tau] = infinity else: - coefficients[i] = c * self._Q(i//tau) - valuations[i//tau] -= i*self._mu + coefficients[i] = c * self._Q(i // tau) + valuations[i // tau] -= i * self._mu coefficients = coefficients[::tau] # recursively reduce the f_i Q^{i tau} - C = [self._base_valuation.reduce(c, check=False)(self._residue_field_generator()) - if valuations[i] is not infinity - else self._base_valuation.residue_ring().zero() - for i, c in enumerate(coefficients)] + C = [self._base_valuation.reduce(c, check=False)(self._residue_field_generator()) if valuations[i] is not infinity else self._base_valuation.residue_ring().zero() for i, c in enumerate(coefficients)] # reduce the Q'^i phi^i return self.residue_ring()(C) @@ -1363,6 +1372,7 @@ def lift(self, F, report_coefficients=False): F = self.residue_ring().coerce(F) from sage.categories.fields import Fields + if self.domain().base_ring() not in Fields(): raise NotImplementedError("only implemented for polynomial rings over fields") @@ -1377,16 +1387,12 @@ def lift(self, F, report_coefficients=False): # in the last step of reduce, the f_iQ^i are reduced, and evaluated at # the generator of the residue field # here, we undo this: - coeffs = [R0(c if self.psi().degree() == 1 - else list(c._vector_() if hasattr(c, '_vector_') - else c.list())) - for c in F.coefficients(sparse=False)] + coeffs = [R0(c if self.psi().degree() == 1 else list(c._vector_() if hasattr(c, '_vector_') else c.list())) for c in F.coefficients(sparse=False)] coeffs = [self._base_valuation.lift(c) for c in coeffs] # now the coefficients correspond to the expansion with (f_iQ^i)(Q^{-1} phi)^i # now we undo the factors of Q^i (the if else is necessary to handle the case when mu is infinity, i.e., when _Q_reciprocal() is undefined) - coeffs = [(c if i == 0 else c*self._Q_reciprocal(i)).map_coefficients(_lift_to_maximal_precision) - for i, c in enumerate(coeffs)] + coeffs = [(c if i == 0 else c * self._Q_reciprocal(i)).map_coefficients(_lift_to_maximal_precision) for i, c in enumerate(coeffs)] # reduce the coefficients mod phi; the part that exceeds phi has no effect on the reduction of the coefficient coeffs = [next(self.coefficients(c)) for c in coeffs] @@ -1396,7 +1402,7 @@ def lift(self, F, report_coefficients=False): RR = self.domain().change_ring(self.domain()) tau = self.value_group().index(self._base_valuation.value_group()) - ret = RR(coeffs)(self.phi()**tau) + ret = RR(coeffs)(self.phi() ** tau) ret = ret.map_coefficients(_lift_to_maximal_precision) return ret @@ -1452,6 +1458,7 @@ def lift_to_key(self, F, check=True): F = self.residue_ring().coerce(F) from sage.categories.fields import Fields + if self.domain().base_ring() not in Fields(): raise NotImplementedError("only implemented for polynomial rings over fields") @@ -1479,7 +1486,7 @@ def lift_to_key(self, F, check=True): coefficients[-2] %= self.phi() tau = self.value_group().index(self._base_valuation.value_group()) vf = self._mu * tau * F.degree() - ret = self.domain().change_ring(self.domain())(coefficients)(self.phi()**tau) + ret = self.domain().change_ring(self.domain())(coefficients)(self.phi() ** tau) ret = self.simplify(ret, error=vf, force=True) ret = ret.map_coefficients(_lift_to_maximal_precision) assert (ret == self.phi()) == (F == F.parent().gen()) @@ -1503,7 +1510,7 @@ def _Q(self, e): """ tau = self.value_group().index(self._base_valuation.value_group()) v = self._mu * tau - return self._pow(self.equivalence_unit(v), e, error=v*e, effective_degree=0) + return self._pow(self.equivalence_unit(v), e, error=v * e, effective_degree=0) @cached_method def _Q_reciprocal(self, e=1): @@ -1525,12 +1532,12 @@ def _Q_reciprocal(self, e=1): tau = self.value_group().index(self._base_valuation.value_group()) v = -self._mu * tau - ret = self._pow(self._Q_reciprocal(1), e, error=v*e, effective_degree=0) + ret = self._pow(self._Q_reciprocal(1), e, error=v * e, effective_degree=0) assert self.is_equivalence_unit(ret) # essentially this checks that the reduction of Q'*phi^tau is the # generator of the residue field - assert self._base_valuation.reduce(self._Q(e)*ret)(self._residue_field_generator()).is_one() + assert self._base_valuation.reduce(self._Q(e) * ret)(self._residue_field_generator()).is_one() return ret @@ -1548,6 +1555,7 @@ class FiniteAugmentedValuation(AugmentedValuation_base, FiniteInductiveValuation sage: v = GaussValuation(S) sage: w = v.augmentation(x^2 + x + u, 1/2) """ + def __init__(self, parent, v, phi, mu): r""" EXAMPLES:: @@ -1650,7 +1658,7 @@ def valuations(self, f, coefficients=None, call_error=False): if v is infinity: yield v else: - ret = v + i*self._mu + ret = v + i * self._mu if call_error: if lowest_valuation is infinity or ret < lowest_valuation: lowest_valuation = ret @@ -1741,10 +1749,7 @@ def simplify(self, f, error=None, force=False, effective_degree=None, size_heuri if phiadic or self.phi() == self.phi().parent().gen(): coefficients = list(self.coefficients(f)) valuations = list(self.valuations(f, coefficients=coefficients)) - return self.domain().change_ring(self.domain())([ - 0 if valuations[i] > error - else self._base_valuation.simplify(c, error=error-i*self._mu, force=force, phiadic=True) - for (i, c) in enumerate(coefficients)])(self.phi()) + return self.domain().change_ring(self.domain())([0 if valuations[i] > error else self._base_valuation.simplify(c, error=error - i * self._mu, force=force, phiadic=True) for (i, c) in enumerate(coefficients)])(self.phi()) # We iterate through the coefficients of the polynomial (in the # usual x-adic way) starting from the leading coefficient and try # to replace the coefficient with a simpler one recursively. @@ -1753,12 +1758,11 @@ def simplify(self, f, error=None, force=False, effective_degree=None, size_heuri for i in range(f.degree(), -1, -1): j = i // self.phi().degree() - coefficients = list(islice(f.list(), int(j * self.phi().degree()), - int(i) + 1)) + coefficients = list(islice(f.list(), int(j * self.phi().degree()), int(i) + 1)) g = self.domain()(coefficients) - ng = self._base_valuation.simplify(g, error=error-j*self._mu, force=force, phiadic=False) + ng = self._base_valuation.simplify(g, error=error - j * self._mu, force=force, phiadic=False) if g != ng: - f -= (g - ng)*self.phi()**j + f -= (g - ng) * self.phi() ** j return f def lower_bound(self, f): @@ -1845,6 +1849,7 @@ class FinalFiniteAugmentedValuation(FiniteAugmentedValuation, FinalAugmentedValu sage: v = GaussValuation(R, valuations.TrivialValuation(QQ)) sage: w = v.augmentation(x, 1) """ + def __init__(self, parent, v, phi, mu): r""" TESTS:: @@ -1871,6 +1876,7 @@ class NonFinalFiniteAugmentedValuation(FiniteAugmentedValuation, NonFinalAugment sage: v = GaussValuation(R, QQ.valuation(2)) sage: w = v.augmentation(x, 1) """ + def __init__(self, parent, v, phi, mu): r""" TESTS:: @@ -1898,6 +1904,7 @@ class InfiniteAugmentedValuation(FinalAugmentedValuation, InfiniteInductiveValua sage: v = GaussValuation(R, QQ.valuation(2)) sage: w = v.augmentation(x, infinity) """ + def __init__(self, parent, v, phi, mu): r""" TESTS:: diff --git a/src/sage/rings/valuation/developing_valuation.py b/src/sage/rings/valuation/developing_valuation.py index 5a45d8c58a5..238d9212fc7 100644 --- a/src/sage/rings/valuation/developing_valuation.py +++ b/src/sage/rings/valuation/developing_valuation.py @@ -39,6 +39,7 @@ sage: list(w.coefficients(f)) [x + 1, 1] """ + # **************************************************************************** # Copyright (C) 2013-2025 Julian Rüth # @@ -68,6 +69,7 @@ class DevelopingValuation(DiscretePseudoValuation): sage: TestSuite(v).run() # long time # needs sage.geometry.polyhedron """ + def __init__(self, parent, phi): r""" TESTS:: @@ -82,6 +84,7 @@ def __init__(self, parent, phi): domain = parent.domain() from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if not isinstance(domain, PolynomialRing_generic) or not domain.ngens() == 1: raise TypeError("domain must be a univariate polynomial ring but %r is not" % (domain,)) @@ -184,10 +187,8 @@ def _pow(self, f, e, error, effective_degree): if e == 1: return self.simplify(f, error=error) if e % 2 == 0: - return self._pow(self.simplify(f*f, error=error*2/e, effective_degree=effective_degree*2/e), - e//2, error=error, effective_degree=effective_degree) - return self.simplify(f*self._pow(f, e-1, error=error*(e-1)/e, effective_degree=effective_degree*(e-1)/e), - error=error, effective_degree=effective_degree) + return self._pow(self.simplify(f * f, error=error * 2 / e, effective_degree=effective_degree * 2 / e), e // 2, error=error, effective_degree=effective_degree) + return self.simplify(f * self._pow(f, e - 1, error=error * (e - 1) / e, effective_degree=effective_degree * (e - 1) / e), error=error, effective_degree=effective_degree) def coefficients(self, f): r""" @@ -268,6 +269,7 @@ def newton_polygon(self, f, valuations=None): f = self.domain().coerce(f) from sage.geometry.newton_polygon import NewtonPolygon + if valuations is None: valuations = self.valuations(f) return NewtonPolygon(list(enumerate(valuations))) @@ -300,6 +302,7 @@ def _call_(self, f): f = self.domain().coerce(f) from sage.rings.infinity import infinity + if f.is_zero(): return infinity diff --git a/src/sage/rings/valuation/gauss_valuation.py b/src/sage/rings/valuation/gauss_valuation.py index 7ffe578f653..ff351a2112d 100644 --- a/src/sage/rings/valuation/gauss_valuation.py +++ b/src/sage/rings/valuation/gauss_valuation.py @@ -34,6 +34,7 @@ sage: w(2*T + 1) 0 """ + # **************************************************************************** # Copyright (C) 2013-2017 Julian Rüth # @@ -75,6 +76,7 @@ class GaussValuationFactory(UniqueFactory): sage: w(x + 2) 0 """ + def create_key(self, domain, v=None): r""" Normalize and check the parameters to create a Gauss valuation. @@ -89,6 +91,7 @@ def create_key(self, domain, v=None): ValueError: the domain of v must be the base ring of domain but 2-adic valuation is not defined over Integer Ring but over Rational Field """ from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if not isinstance(domain, PolynomialRing_generic): raise TypeError("GaussValuations can only be created over polynomial rings but %r is not a polynomial ring" % (domain,)) if not domain.ngens() == 1: @@ -117,6 +120,7 @@ def create_object(self, version, key, **extra_args): """ domain, v = key from sage.rings.valuation.valuation_space import DiscretePseudoValuationSpace + parent = DiscretePseudoValuationSpace(domain) return parent.__make_element_class__(GaussValuation_generic)(parent, v) @@ -150,6 +154,7 @@ class GaussValuation_generic(NonFinalInductiveValuation): sage: TestSuite(v).run() # long time # needs sage.geometry.polyhedron """ + def __init__(self, parent, v): """ TESTS:: @@ -257,6 +262,7 @@ def valuations(self, f, coefficients=None, call_error=False): from sage.rings.infinity import infinity from sage.rings.rational_field import QQ + if f == self.domain().gen(): yield infinity yield QQ(0) @@ -380,8 +386,7 @@ def lift(self, F): :meth:`reduce` """ F = self.residue_ring().coerce(F) - return F.map_coefficients(self._base_valuation.lift, - self._base_valuation.domain()) + return F.map_coefficients(self._base_valuation.lift, self._base_valuation.domain()) def lift_to_key(self, F): """ @@ -474,6 +479,7 @@ def E(self): 1 """ from sage.rings.integer_ring import ZZ + return ZZ.one() def F(self): @@ -490,6 +496,7 @@ def F(self): 1 """ from sage.rings.integer_ring import ZZ + return ZZ.one() def change_domain(self, ring): @@ -505,6 +512,7 @@ def change_domain(self, ring): Gauss valuation induced by 2-adic valuation """ from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(ring, PolynomialRing_generic) and ring.ngens() == 1: base_valuation = self._base_valuation.change_domain(ring.base_ring()) return GaussValuation(self.domain().change_ring(ring.base_ring()), base_valuation) @@ -523,6 +531,7 @@ def extensions(self, ring): [Gauss valuation induced by 2-adic valuation] """ from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(ring, PolynomialRing_generic) and ring.ngens() == 1: if self.domain().is_subring(ring): return [GaussValuation(ring, w) for w in self._base_valuation.extensions(ring.base_ring())] @@ -543,6 +552,7 @@ def restriction(self, ring): if ring.is_subring(self.domain().base_ring()): return self._base_valuation.restriction(ring) from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(ring, PolynomialRing_generic) and ring.ngens() == 1: if ring.base().is_subring(self.domain().base()): return GaussValuation(ring, self._base_valuation.restriction(ring.base())) @@ -645,6 +655,7 @@ def _ge_(self, other): if isinstance(other, GaussValuation_generic): return self._base_valuation >= other._base_valuation from .augmented_valuation import AugmentedValuation_base + if isinstance(other, AugmentedValuation_base): return False if other.is_trivial(): @@ -663,6 +674,7 @@ def scale(self, scalar): Gauss valuation induced by 3 * 2-adic valuation """ from sage.rings.rational_field import QQ + if scalar in QQ and scalar > 0 and scalar != 1: return GaussValuation(self.domain(), self._base_valuation.scale(scalar)) return super().scale(scalar) @@ -766,6 +778,7 @@ def lower_bound(self, f): 1 """ from sage.rings.infinity import infinity + coefficients = f.coefficients(sparse=True) coefficients.reverse() ret = infinity @@ -796,5 +809,6 @@ def upper_bound(self, f): coefficients = f.coefficients(sparse=True) if not coefficients: from sage.rings.infinity import infinity + return infinity return self._base_valuation.upper_bound(coefficients[-1]) diff --git a/src/sage/rings/valuation/inductive_valuation.py b/src/sage/rings/valuation/inductive_valuation.py index fa2861cc808..11c62dd4dca 100644 --- a/src/sage/rings/valuation/inductive_valuation.py +++ b/src/sage/rings/valuation/inductive_valuation.py @@ -27,6 +27,7 @@ Inductive valuations are originally discussed in [Mac1936I]_ and [Mac1936II]_. An introduction is also given in Chapter 4 of [Rüt2014]_. """ + # **************************************************************************** # Copyright (C) 2016-2018 Julian Rüth # @@ -56,6 +57,7 @@ class InductiveValuation(DevelopingValuation): sage: TestSuite(v).run() # long time # needs sage.geometry.polyhedron """ + def is_equivalence_unit(self, f, valuations=None): r""" Return whether the polynomial ``f`` is an equivalence unit, i.e., an @@ -375,6 +377,7 @@ def _test_element_with_valuation_inductive_valuation(self, **options): # this is often not possible unless the underlying ring of # constants is a field from sage.categories.fields import Fields + if self.domain().base() not in Fields(): continue raise @@ -402,6 +405,7 @@ def _test_EF(self, **options): for w, v in zip(chain, chain[1:]): from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ + if w(w.phi()) is infinity: tester.assertEqual(w.E(), v.E()) tester.assertIn(w.E(), ZZ) @@ -450,6 +454,7 @@ def _test_equivalence_unit(self, **options): # this is often not possible unless the underlying ring of # constants is a field from sage.categories.fields import Fields + if self.domain().base() not in Fields(): continue raise @@ -490,6 +495,7 @@ def _test_equivalence_reciprocal(self, **options): # this is often not possible unless the underlying ring of # constants is a field from sage.categories.fields import Fields + if self.domain().base() not in Fields(): continue raise @@ -510,10 +516,8 @@ def _test_inductive_valuation_inheritance(self, **options): sage: v._test_inductive_valuation_inheritance() """ tester = self._tester(**options) - tester.assertNotEqual(isinstance(self, InfiniteInductiveValuation), - isinstance(self, FiniteInductiveValuation)) - tester.assertNotEqual(isinstance(self, FinalInductiveValuation), - isinstance(self, NonFinalInductiveValuation)) + tester.assertNotEqual(isinstance(self, InfiniteInductiveValuation), isinstance(self, FiniteInductiveValuation)) + tester.assertNotEqual(isinstance(self, FinalInductiveValuation), isinstance(self, NonFinalInductiveValuation)) class FiniteInductiveValuation(InductiveValuation, DiscreteValuation): @@ -527,6 +531,7 @@ class FiniteInductiveValuation(InductiveValuation, DiscreteValuation): sage: R. = QQ[] sage: v = GaussValuation(R, valuations.TrivialValuation(QQ)) """ + def __init__(self, parent, phi): r""" TESTS:: @@ -553,6 +558,7 @@ def extensions(self, other): [Trivial valuation on Rational Field] """ from sage.categories.function_fields import FunctionFields + if other in FunctionFields() and other.ngens() == 1: # extend to K[x] and from there to K(x) v = self.extension(self.domain().change_ring(self.domain().base().fraction_field())) @@ -573,6 +579,7 @@ class NonFinalInductiveValuation(FiniteInductiveValuation, DiscreteValuation): sage: v = GaussValuation(S) sage: v = v.augmentation(x^2 + x + u, 1) """ + def __init__(self, parent, phi): r""" TESTS:: @@ -642,6 +649,7 @@ def augmentation(self, phi, mu, check=True): :mod:`~sage.rings.valuation.augmented_valuation` """ from .augmented_valuation import AugmentedValuation + return AugmentedValuation(self, phi, mu, check) def mac_lane_step(self, G, principal_part_bound=None, assume_squarefree=False, assume_equivalence_irreducible=False, report_degree_bounds_and_caches=False, coefficients=None, valuations=None, check=True, allow_equivalent_key=True): @@ -756,6 +764,7 @@ def mac_lane_step(self, G, principal_part_bound=None, assume_squarefree=False, a from itertools import islice from sage.misc.verbose import verbose + verbose("Augmenting %s towards %s" % (self, G), level=10) if not G.is_monic(): @@ -764,14 +773,12 @@ def mac_lane_step(self, G, principal_part_bound=None, assume_squarefree=False, a if coefficients is None: coefficients = self.coefficients(G) if principal_part_bound: - coefficients = islice(coefficients, 0, - int(principal_part_bound) + 1, 1) + coefficients = islice(coefficients, 0, int(principal_part_bound) + 1, 1) coefficients = list(coefficients) if valuations is None: valuations = self.valuations(G, coefficients=coefficients) if principal_part_bound: - valuations = islice(valuations, 0, - int(principal_part_bound) + 1, 1) + valuations = islice(valuations, 0, int(principal_part_bound) + 1, 1) valuations = list(valuations) if check and min(valuations) < 0: @@ -784,6 +791,7 @@ def mac_lane_step(self, G, principal_part_bound=None, assume_squarefree=False, a raise ValueError("G must be squarefree") from sage.rings.infinity import infinity + assert self(G) is not infinity # this is a valuation and G is nonzero ret = [] @@ -842,17 +850,16 @@ def mac_lane_step(self, G, principal_part_bound=None, assume_squarefree=False, a w_coefficients = w.coefficients(G) if principal_part_bound: - w_coefficients = islice(w_coefficients, 0, - int(principal_part_bound) + 1, 1) + w_coefficients = islice(w_coefficients, 0, int(principal_part_bound) + 1, 1) w_coefficients = list(w_coefficients) w_valuations = w.valuations(G, coefficients=w_coefficients) if principal_part_bound: - w_valuations = islice(w_valuations, 0, - int(principal_part_bound) + 1, 1) + w_valuations = islice(w_valuations, 0, int(principal_part_bound) + 1, 1) w_valuations = list(w_valuations) from sage.geometry.newton_polygon import NewtonPolygon + NP = NewtonPolygon(w.newton_polygon(G, valuations=w_valuations).vertices(), last_slope=0) verbose("Newton-Polygon for v(phi)=%s : %s" % (self(phi), NP), level=11) @@ -866,8 +873,7 @@ def mac_lane_step(self, G, principal_part_bound=None, assume_squarefree=False, a for i, slope in enumerate(slopes): verbose("Slope = %s" % slope, level=12) new_mu = old_mu - slope - new_valuations = [val - (j * slope if slope is not -infinity else (0 if j == 0 else -infinity)) - for j, val in enumerate(w_valuations)] + new_valuations = [val - (j * slope if slope is not -infinity else (0 if j == 0 else -infinity)) for j, val in enumerate(w_valuations)] if phi.degree() == self.phi().degree(): assert new_mu > self(phi), "the valuation of the key polynomial must increase when the degree stagnates" # phi has already been simplified internally by the @@ -880,6 +886,7 @@ def mac_lane_step(self, G, principal_part_bound=None, assume_squarefree=False, a assert slope is -infinity or 0 in w.newton_polygon(G).slopes(repetition=False) from sage.rings.integer_ring import ZZ + assert (phi.degree() / self.phi().degree()) in ZZ degree_bound = multiplicities[slope] * phi.degree() assert degree_bound <= G.degree() @@ -1007,7 +1014,7 @@ def is_minimal(self, f, assume_equivalence_irreducible=False): F = self.reduce(f, check=False) assert not F.is_constant() return F.is_irreducible() - assert (self(f) <= 0) # f is monic + assert self(f) <= 0 # f is monic # f is not minimal: # Let g be f stripped of its leading term, i.e., g = f - x^n. # Then g and f are equivalent with respect to this valuation @@ -1023,10 +1030,7 @@ def is_minimal(self, f, assume_equivalence_irreducible=False): tau = self.value_group().index(self._base_valuation.value_group()) # see Theorem 9.4 of [Mac1936II] - return list(self.valuations(f))[-1] == self(f) and \ - list(self.coefficients(f))[-1].is_constant() and \ - list(self.valuations(f))[0] == self(f) and \ - tau.divides(len(list(self.coefficients(f))) - 1) + return list(self.valuations(f))[-1] == self(f) and list(self.coefficients(f))[-1].is_constant() and list(self.valuations(f))[0] == self(f) and tau.divides(len(list(self.coefficients(f))) - 1) def _equivalence_reduction(self, f, coefficients=None, valuations=None, degree_bound=None): r""" @@ -1068,10 +1072,10 @@ def _equivalence_reduction(self, f, coefficients=None, valuations=None, degree_b if phi_divides: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(f.parent(), 'phi') f = R(coefficients[phi_divides:])(self.phi()) - valuations = [vv - self.mu() * phi_divides - for vv in valuations[phi_divides:]] + valuations = [vv - self.mu() * phi_divides for vv in valuations[phi_divides:]] coefficients = coefficients[phi_divides:] valuation = min(valuations) @@ -1079,9 +1083,8 @@ def _equivalence_reduction(self, f, coefficients=None, valuations=None, degree_b R = next(self.coefficients(R)) fR_valuations = [vv - valuation for vv in valuations] from sage.rings.infinity import infinity - fR_coefficients = [next(self.coefficients(c * R)) - if vv is not infinity and vv == 0 else 0 - for c, vv in zip(coefficients, fR_valuations)] + + fR_coefficients = [next(self.coefficients(c * R)) if vv is not infinity and vv == 0 else 0 for c, vv in zip(coefficients, fR_valuations)] return valuation, phi_divides, self.reduce(f * R, check=False, degree_bound=degree_bound, coefficients=fR_coefficients, valuations=fR_valuations) @@ -1253,6 +1256,7 @@ def equivalence_decomposition(self, f, assume_not_equivalence_unit=False, coeffi raise ValueError("equivalence decomposition of zero is not defined") from sage.structure.factorization import Factorization + if not assume_not_equivalence_unit and self.is_equivalence_unit(f): return Factorization([], unit=f, sort=False) @@ -1261,12 +1265,12 @@ def equivalence_decomposition(self, f, assume_not_equivalence_unit=False, coeffi domain = self.domain().change_ring(nonfractions.fraction_field()) v = self.extension(domain) ret = v.equivalence_decomposition(v.domain()(f)) - return Factorization([(self._eliminate_denominators(g), e) - for (g, e) in ret], unit=self._eliminate_denominators(ret.unit()), sort=False) + return Factorization([(self._eliminate_denominators(g), e) for (g, e) in ret], unit=self._eliminate_denominators(ret.unit()), sort=False) valuation, phi_divides, F = self._equivalence_reduction(f, coefficients=coefficients, valuations=valuations, degree_bound=degree_bound) F = F.factor() from sage.misc.verbose import verbose + verbose("%s factors as %s = %s in reduction" % (f, F.prod(), F), level=20) unit = self.domain().one() @@ -1277,9 +1281,10 @@ def equivalence_decomposition(self, f, assume_not_equivalence_unit=False, coeffi if compute_unit: from sage.misc.misc_c import prod - unit *= self.lift(self.residue_ring()(prod([psi.leading_coefficient()**e for psi, e in F]))) + + unit *= self.lift(self.residue_ring()(prod([psi.leading_coefficient() ** e for psi, e in F]))) if not self.is_gauss_valuation(): - unit *= prod([self._Q_reciprocal(e*psi.degree()) for psi, e in F]) + unit *= prod([self._Q_reciprocal(e * psi.degree()) for psi, e in F]) unit = self.simplify(unit, effective_degree=0, force=True) # A potential speedup that we tried to implement here: @@ -1288,8 +1293,7 @@ def equivalence_decomposition(self, f, assume_not_equivalence_unit=False, coeffi # constant coefficient of f[0]. Doing so saved a few invocations of # mac_lane_step but in the end made hardly any difference. - F = [(self.lift_to_key(psi / psi.leading_coefficient()), e) - for psi, e in F] + F = [(self.lift_to_key(psi / psi.leading_coefficient()), e) for psi, e in F] if phi_divides: for i, (g, e) in enumerate(F): @@ -1349,6 +1353,7 @@ def minimal_representative(self, f): f = self.domain().coerce(f) from sage.categories.fields import Fields + if self.domain().base_ring() not in Fields(): raise NotImplementedError("only implemented for polynomial rings over fields") @@ -1364,8 +1369,7 @@ def minimal_representative(self, f): g = h * f vg = self(g) - coeffs = [c if v == vg else c.parent().zero() - for v, c in zip(self.valuations(g), self.coefficients(g))] + coeffs = [c if v == vg else c.parent().zero() for v, c in zip(self.valuations(g), self.coefficients(g))] coeffs[degree] = self.domain().base_ring().one() ret = sum([c * self._phi**i for i, c in enumerate(coeffs)]) @@ -1374,6 +1378,7 @@ def minimal_representative(self, f): assert self.is_minimal(ret) from sage.structure.factorization import Factorization + ret = Factorization([(ret, 1)], unit=e, sort=False) assert self.is_equivalent(ret.prod(), f) # this might fail because of leading zeros @@ -1469,13 +1474,7 @@ def _eliminate_denominators(self, f): nonfraction_valuation = self.restriction(nonfractions) # if this fails then there is no equivalent polynomial in the domain of this valuation - ret = g.map_coefficients( - lambda c: c.numerator() * nonfraction_valuation.inverse(c.denominator(), - valuation - + nonfraction_valuation(c.denominator()) - - nonfraction_valuation(c.numerator()) - + nonfraction_valuation.value_group().gen()), - nonfractions) + ret = g.map_coefficients(lambda c: c.numerator() * nonfraction_valuation.inverse(c.denominator(), valuation + nonfraction_valuation(c.denominator()) - nonfraction_valuation(c.numerator()) + nonfraction_valuation.value_group().gen()), nonfractions) assert w.is_equivalent(f, ret) return ret @@ -1521,6 +1520,7 @@ def _test_lift_to_key(self, **options): self.residue_ring() except NotImplementedError: from sage.categories.fields import Fields + if self.domain().base() in Fields(): raise return @@ -1532,6 +1532,7 @@ def _test_lift_to_key(self, **options): f = self.lift_to_key(F) except NotImplementedError: from sage.categories.fields import Fields + if self.domain().base() in Fields(): raise continue @@ -1541,6 +1542,7 @@ def _test_lift_to_key(self, **options): # check that augmentation produces a valuation with roots of F # in the residue ring from sage.rings.infinity import infinity + w = self.augmentation(f, infinity) F = F.change_ring(w.residue_ring()) roots = F.roots(multiplicities=False) @@ -1604,6 +1606,7 @@ class InfiniteInductiveValuation(FinalInductiveValuation, InfiniteDiscretePseudo sage: v = GaussValuation(R, QQ.valuation(2)) sage: w = v.augmentation(x^2 + x + 1, infinity) """ + def __init__(self, parent, base_valuation): r""" TESTS:: @@ -1633,6 +1636,7 @@ def change_domain(self, ring): 2-adic valuation """ from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_generic + if isinstance(ring, PolynomialQuotientRing_generic) and ring.base() is self.domain() and ring.modulus() == self.phi(): return self.restriction(self.domain().base())._extensions_to_quotient(ring, approximants=[self])[0] return super().change_domain(ring) diff --git a/src/sage/rings/valuation/limit_valuation.py b/src/sage/rings/valuation/limit_valuation.py index e1eed558a6b..ff9df8c515e 100644 --- a/src/sage/rings/valuation/limit_valuation.py +++ b/src/sage/rings/valuation/limit_valuation.py @@ -69,6 +69,7 @@ Limits of inductive valuations are discussed in [Mac1936I]_ and [Mac1936II]_. An overview can also be found in Section 4.6 of [Rüt2014]_. """ + # **************************************************************************** # Copyright (C) 2016-2017 Julian Rüth # @@ -104,6 +105,7 @@ class LimitValuationFactory(UniqueFactory): sage: w(x) +Infinity """ + def create_key(self, base_valuation, G): r""" Create a key from the parameters of this valuation. @@ -141,6 +143,7 @@ def create_object(self, version, key): """ base_valuation, G = key from .valuation_space import DiscretePseudoValuationSpace + parent = DiscretePseudoValuationSpace(base_valuation.domain()) return parent.__make_element_class__(MacLaneLimitValuation)(parent, base_valuation, G) @@ -178,6 +181,7 @@ class LimitValuation_generic(DiscretePseudoValuation): True sage: TestSuite(w._base_valuation).run() # long time # needs sage.rings.function_field """ + def __init__(self, parent, approximation): r""" TESTS:: @@ -334,6 +338,7 @@ def _repr_(self): """ from sage.rings.infinity import infinity from .augmented_valuation import AugmentedValuation_base + if self._initial_approximation(self._G) is not infinity: if isinstance(self._initial_approximation, AugmentedValuation_base): return repr(self._initial_approximation)[:-1] + ", … ]" @@ -360,6 +365,7 @@ class MacLaneLimitValuation(LimitValuation_generic, InfiniteDiscretePseudoValuat sage: u = v._base_valuation; u [ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2 , … ] """ + def __init__(self, parent, approximation, G): r""" TESTS:: @@ -393,10 +399,10 @@ def extensions(self, ring): if self.domain() is ring: return [self] from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(ring, PolynomialRing_generic) and self.domain().base_ring().is_subring(ring.base_ring()): if self.domain().base_ring().fraction_field() is ring.base_ring(): - return [LimitValuation(self._initial_approximation.change_domain(ring), - self._G.change_ring(ring.base_ring()))] + return [LimitValuation(self._initial_approximation.change_domain(ring), self._G.change_ring(ring.base_ring()))] # we need to recompute the mac lane approximants over this base # ring because it could split differently pass @@ -463,6 +469,7 @@ def _call_(self, f): self._improve_approximation_for_call(f) if self._G.divides(f): from sage.rings.infinity import infinity + return infinity return self._approximation(f) @@ -492,17 +499,13 @@ def _improve_approximation(self): [ Gauss valuation induced by 2-adic valuation, v(t + 1) = 1/2, v(t^2 + 1) = +Infinity ] """ from sage.rings.infinity import infinity + if self._approximation(self._G) is infinity: # an infinite valuation can not be improved further return - approximations = self._approximation.mac_lane_step(self._G, - assume_squarefree=True, - assume_equivalence_irreducible=True, - check=False, - principal_part_bound=1 if self._approximation.E() * self._approximation.F() == self._approximation.phi().degree() else None, - report_degree_bounds_and_caches=True) - assert (len(approximations) == 1) + approximations = self._approximation.mac_lane_step(self._G, assume_squarefree=True, assume_equivalence_irreducible=True, check=False, principal_part_bound=1 if self._approximation.E() * self._approximation.F() == self._approximation.phi().degree() else None, report_degree_bounds_and_caches=True) + assert len(approximations) == 1 self._approximation, _, _, self._next_coefficients, self._next_valuations = approximations[0] def _improve_approximation_for_call(self, f): @@ -557,6 +560,7 @@ def _improve_approximation_for_call(self, f): for all future computations.) """ from sage.rings.infinity import infinity + if self._approximation(self._approximation.phi()) is infinity: # an infinite valuation can not be improved further return @@ -632,11 +636,13 @@ def residue_ring(self): """ R = self._initial_approximation.residue_ring() from sage.categories.fields import Fields + if R in Fields(): # the approximation ends in v(phi)=infty return R from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic - assert (isinstance(R, PolynomialRing_generic)) + + assert isinstance(R, PolynomialRing_generic) return R.base_ring() def _ge_(self, other): @@ -677,8 +683,7 @@ def _ge_(self, other): # If the valuations are comparable, they must approximate the # same factor of G (see the documentation of LimitValuation: # the approximation must *uniquely* single out a valuation.) - return (self._initial_approximation >= other._initial_approximation - or self._initial_approximation <= other._initial_approximation) + return self._initial_approximation >= other._initial_approximation or self._initial_approximation <= other._initial_approximation return super()._ge_(other) @@ -740,6 +745,7 @@ def _weakly_separating_element(self, other): sage: u.separating_element([ww,w,v,uu]) # not tested, takes forever """ from .scaled_valuation import ScaledValuation_generic + v = self.restriction(self.domain().base()) if isinstance(v, ScaledValuation_generic): v = v._base_valuation @@ -751,7 +757,7 @@ def _weakly_separating_element(self, other): # phi of the initial approximant must be good enough to separate it # from any other approximant of an extension ret = self._initial_approximation.phi() - assert (self(ret) > other(ret)) # I could not come up with an example where this fails + assert self(ret) > other(ret) # I could not come up with an example where this fails return ret # if the valuations are sane, it should be possible to separate # them with constants diff --git a/src/sage/rings/valuation/mapped_valuation.py b/src/sage/rings/valuation/mapped_valuation.py index f5a221730fd..b69f66af9b2 100644 --- a/src/sage/rings/valuation/mapped_valuation.py +++ b/src/sage/rings/valuation/mapped_valuation.py @@ -21,6 +21,7 @@ - Julian Rüth (2016-11-10): initial version """ + # **************************************************************************** # Copyright (C) 2016-2017 Julian Rüth # @@ -51,6 +52,7 @@ class MappedValuation_base(DiscretePseudoValuation): sage: TestSuite(w).run() # long time # needs sage.rings.function_field """ + def __init__(self, parent, base_valuation): r""" .. TODO:: @@ -384,6 +386,7 @@ class FiniteExtensionFromInfiniteValuation(MappedValuation_base, DiscreteValuati sage: w = v.extension(L); w (x)-adic valuation """ + def __init__(self, parent, base_valuation): r""" TESTS:: @@ -416,8 +419,7 @@ def _eq_(self, other): sage: w == ww # indirect doctest True """ - return (isinstance(other, FiniteExtensionFromInfiniteValuation) - and self._base_valuation == other._base_valuation) + return isinstance(other, FiniteExtensionFromInfiniteValuation) and self._base_valuation == other._base_valuation def restriction(self, ring): r""" @@ -571,6 +573,7 @@ class FiniteExtensionFromLimitValuation(FiniteExtensionFromInfiniteValuation): [ (x - 1)-adic valuation, v(y - 1) = 1 ]-adic valuation] """ + def __init__(self, parent, approximant, G, approximants): r""" EXAMPLES: @@ -593,6 +596,7 @@ def __init__(self, parent, approximant, G, approximants): self._approximants = approximants from .limit_valuation import LimitValuation + limit = LimitValuation(approximant, G) FiniteExtensionFromInfiniteValuation.__init__(self, parent, limit) @@ -606,21 +610,23 @@ def _repr_(self): 2-adic valuation """ from .limit_valuation import MacLaneLimitValuation + if isinstance(self._base_valuation, MacLaneLimitValuation): # print the minimal information that singles out this valuation from all approximants - assert (self._base_valuation._initial_approximation in self._approximants) + assert self._base_valuation._initial_approximation in self._approximants approximants = [v.augmentation_chain()[::-1] for v in self._approximants] augmentations = self._base_valuation._initial_approximation.augmentation_chain()[::-1] unique_approximant = None for l in range(len(augmentations)): - if len([a for a in approximants if a[:l + 1] == augmentations[:l + 1]]) == 1: - unique_approximant = augmentations[:l + 1] + if len([a for a in approximants if a[: l + 1] == augmentations[: l + 1]]) == 1: + unique_approximant = augmentations[: l + 1] break - assert (unique_approximant is not None) + assert unique_approximant is not None if unique_approximant[0].is_gauss_valuation(): unique_approximant[0] = unique_approximant[0].restriction(unique_approximant[0].domain().base_ring()) if len(unique_approximant) == 1: return repr(unique_approximant[0]) from .augmented_valuation import AugmentedValuation_base + return "[ %s ]-adic valuation" % (", ".join("v(%r) = %r" % (v._phi, v._mu) if (isinstance(v, AugmentedValuation_base) and v.domain() == self._base_valuation.domain()) else repr(v) for v in unique_approximant)) return "%s-adic valuation" % (self._base_valuation) diff --git a/src/sage/rings/valuation/mapped_valuation_test.py b/src/sage/rings/valuation/mapped_valuation_test.py index dcc8a9ba11d..731a462d375 100644 --- a/src/sage/rings/valuation/mapped_valuation_test.py +++ b/src/sage/rings/valuation/mapped_valuation_test.py @@ -18,7 +18,7 @@ def w(): return v.extensions(L) -@pytest.mark.parametrize("idx", [0,1]) +@pytest.mark.parametrize("idx", [0, 1]) def test_finite_extension_from_limit_valuation_w(w, idx): r""" Run the ``TestSuite()`` for two examples given in the @@ -27,6 +27,4 @@ def test_finite_extension_from_limit_valuation_w(w, idx): from sage.misc.sage_unittest import TestSuite # fewer max_runs, these are kind of slow - TestSuite(w[idx]).run(verbose=True, - raise_on_failure=True, - max_runs=512) + TestSuite(w[idx]).run(verbose=True, raise_on_failure=True, max_runs=512) diff --git a/src/sage/rings/valuation/scaled_valuation.py b/src/sage/rings/valuation/scaled_valuation.py index 01c89df66ef..ec42d0b97ea 100644 --- a/src/sage/rings/valuation/scaled_valuation.py +++ b/src/sage/rings/valuation/scaled_valuation.py @@ -10,6 +10,7 @@ - Julian Rüth (2016-11-10): initial version """ + # **************************************************************************** # Copyright (C) 2016-2017 Julian Rüth # @@ -33,6 +34,7 @@ class ScaledValuationFactory(UniqueFactory): sage: 3*ZZ.valuation(2) # indirect doctest 3 * 2-adic valuation """ + def create_key(self, base, s): r""" Create a key which uniquely identifies a valuation. @@ -44,6 +46,7 @@ def create_key(self, base, s): """ from sage.rings.infinity import infinity from sage.rings.rational_field import QQ + if s is infinity or s not in QQ or s <= 0: # for these values we can not return a TrivialValuation() in # create_object() because that would override that instance's @@ -77,6 +80,7 @@ def create_object(self, version, key): assert not isinstance(base, ScaledValuation_generic) from .valuation_space import DiscretePseudoValuationSpace + parent = DiscretePseudoValuationSpace(base.domain()) return parent.__make_element_class__(ScaledValuation_generic)(parent, base, s) @@ -97,6 +101,7 @@ class ScaledValuation_generic(DiscreteValuation): sage: TestSuite(v).run() # long time # needs sage.geometry.polyhedron """ + def __init__(self, parent, base_valuation, s): r""" .. TODO:: diff --git a/src/sage/rings/valuation/trivial_valuation.py b/src/sage/rings/valuation/trivial_valuation.py index a8c2ff16618..f4aa3480404 100644 --- a/src/sage/rings/valuation/trivial_valuation.py +++ b/src/sage/rings/valuation/trivial_valuation.py @@ -12,6 +12,7 @@ sage: v(1) 0 """ + # **************************************************************************** # Copyright (C) 2016-2017 Julian Rüth # @@ -37,6 +38,7 @@ class TrivialValuationFactory(UniqueFactory): sage: v(1) 0 """ + def __init__(self, clazz, parent, *args, **kwargs): r""" TESTS:: @@ -58,7 +60,7 @@ def create_key(self, domain): sage: valuations.TrivialValuation(QQ) is valuations.TrivialValuation(QQ) # indirect doctest True """ - return domain, + return (domain,) def create_object(self, version, key, **extra_args): r""" @@ -69,7 +71,7 @@ def create_object(self, version, key, **extra_args): sage: valuations.TrivialValuation(QQ) # indirect doctest Trivial valuation on Rational Field """ - domain, = key + (domain,) = key parent = self._parent(domain) return parent.__make_element_class__(self._class)(parent) @@ -87,6 +89,7 @@ class TrivialDiscretePseudoValuation_base(DiscretePseudoValuation): sage: TestSuite(v).run() # long time """ + def uniformizer(self): r""" Return a uniformizing element for this valuation. @@ -139,6 +142,7 @@ class TrivialDiscretePseudoValuation(TrivialDiscretePseudoValuation_base, Infini sage: TestSuite(v).run() # long time """ + def __init__(self, parent): r""" TESTS:: @@ -164,6 +168,7 @@ def _call_(self, x): +Infinity """ from sage.rings.infinity import infinity + return infinity def _repr_(self): @@ -259,6 +264,7 @@ class TrivialDiscreteValuation(TrivialDiscretePseudoValuation_base, DiscreteValu sage: TestSuite(v).run() # long time """ + def __init__(self, parent): r""" TESTS:: @@ -284,6 +290,7 @@ def _call_(self, x): 0 """ from sage.rings.infinity import infinity + return infinity if x == 0 else self.codomain().zero() def _repr_(self): @@ -310,6 +317,7 @@ def value_group(self): Trivial Additive Abelian Group """ from .value_group import DiscreteValueGroup + return DiscreteValueGroup(0) def residue_ring(self): diff --git a/src/sage/rings/valuation/valuation.py b/src/sage/rings/valuation/valuation.py index 4de40db9b3f..36349e1054d 100644 --- a/src/sage/rings/valuation/valuation.py +++ b/src/sage/rings/valuation/valuation.py @@ -44,6 +44,7 @@ sage: w.augmentation(x, infinity) [ Gauss valuation induced by 2-adic valuation, v(x) = +Infinity ] """ + # **************************************************************************** # Copyright (C) 2013-2017 Julian Rüth # @@ -77,6 +78,7 @@ class DiscretePseudoValuation(Morphism): sage: TestSuite(v).run() # long time """ + def __init__(self, parent): r""" TESTS:: @@ -104,6 +106,7 @@ def is_equivalent(self, f, g): True """ from sage.rings.infinity import infinity + if self(f) is infinity: return self(g) is infinity @@ -244,6 +247,7 @@ def _ge_(self, other): if self == other: return True from .scaled_valuation import ScaledValuation_generic + if isinstance(other, ScaledValuation_generic): return other <= self raise NotImplementedError("Operator not implemented for this valuation") @@ -265,8 +269,7 @@ def _test_valuation_inheritance(self, **options): sage: QQ.valuation(2)._test_valuation_inheritance() """ tester = self._tester(**options) - tester.assertNotEqual(isinstance(self, InfiniteDiscretePseudoValuation), - isinstance(self, DiscreteValuation)) + tester.assertNotEqual(isinstance(self, InfiniteDiscretePseudoValuation), isinstance(self, DiscreteValuation)) class InfiniteDiscretePseudoValuation(DiscretePseudoValuation): @@ -289,6 +292,7 @@ class InfiniteDiscretePseudoValuation(DiscretePseudoValuation): True sage: TestSuite(w).run() # long time """ + def is_discrete_valuation(self): r""" Return whether this valuation is a discrete valuation. @@ -324,6 +328,7 @@ class NegativeInfiniteDiscretePseudoValuation(InfiniteDiscretePseudoValuation): sage: TestSuite(w).run() # long time """ + def is_negative_pseudo_valuation(self): r""" Return whether this valuation attains the value `-\infty`. @@ -362,6 +367,7 @@ class DiscreteValuation(DiscretePseudoValuation): True sage: TestSuite(w).run() # long time """ + def is_discrete_valuation(self): r""" Return whether this valuation is a discrete valuation. @@ -675,6 +681,7 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru raise ValueError("G must be defined over the domain of this valuation") from sage.misc.verbose import verbose + verbose("Approximants of %r on %r towards %r" % (self, self.domain(), G), level=3) from sage.rings.valuation.gauss_valuation import GaussValuation @@ -715,28 +722,30 @@ def create_children(node): new_leafs = [] if node.forced_leaf: return new_leafs - augmentations = node.valuation.mac_lane_step(G, - report_degree_bounds_and_caches=True, - coefficients=node.coefficients, - valuations=node.valuations, - check=False, - # We do not want to see augmentations that are - # already part of other branches of the tree of - # valuations for obvious performance reasons and - # also because the principal_part_bound would be - # incorrect for these. - allow_equivalent_key=node.valuation.is_gauss_valuation(), - # The length of an edge in the Newton polygon in - # one MacLane step bounds the length of the - # principal part (i.e., the part with negative - # slopes) of the Newton polygons in the next - # MacLane step. Therefore, mac_lane_step does not - # need to compute valuations for coefficients - # beyond that bound as they do not contribute any - # augmentations. - principal_part_bound=node.principal_part_bound) + augmentations = node.valuation.mac_lane_step( + G, + report_degree_bounds_and_caches=True, + coefficients=node.coefficients, + valuations=node.valuations, + check=False, + # We do not want to see augmentations that are + # already part of other branches of the tree of + # valuations for obvious performance reasons and + # also because the principal_part_bound would be + # incorrect for these. + allow_equivalent_key=node.valuation.is_gauss_valuation(), + # The length of an edge in the Newton polygon in + # one MacLane step bounds the length of the + # principal part (i.e., the part with negative + # slopes) of the Newton polygons in the next + # MacLane step. Therefore, mac_lane_step does not + # need to compute valuations for coefficients + # beyond that bound as they do not contribute any + # augmentations. + principal_part_bound=node.principal_part_bound, + ) for w, bound, principal_part_bound, coefficients, valuations in augmentations: - ef = bound == w.E()*w.F() + ef = bound == w.E() * w.F() new_leafs.append(MacLaneApproximantNode(w, node, ef, principal_part_bound, coefficients, valuations)) for leaf in new_leafs: if is_sufficient(leaf, [l for l in new_leafs if l is not leaf]): @@ -747,19 +756,15 @@ def reduce_tree(v, w): return v + w from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet - tree = RecursivelyEnumeratedSet([seed], - successors=create_children, - structure='forest', - enumeration='breadth') + + tree = RecursivelyEnumeratedSet([seed], successors=create_children, structure='forest', enumeration='breadth') # this is a tad faster but annoying for profiling / debugging if algorithm == 'parallel': - nodes = tree.map_reduce(map_function=lambda x: [x], - reduce_init=[]) + nodes = tree.map_reduce(map_function=lambda x: [x], reduce_init=[]) elif algorithm == 'serial': from sage.parallel.map_reduce import RESetMapReduce - nodes = RESetMapReduce(forest=tree, - map_function=lambda x: [x], - reduce_init=[]).run_serial() + + nodes = RESetMapReduce(forest=tree, map_function=lambda x: [x], reduce_init=[]).run_serial() else: raise NotImplementedError(algorithm) leafs = {node.valuation for node in nodes} @@ -806,8 +811,8 @@ def _pow(self, x, e, error): if e == 1: return self.simplify(x, error=error) if e % 2 == 0: - return self._pow(self.simplify(x*x, error=error*2/e), e//2, error=error) - return self.simplify(x*self._pow(x, e-1, error=error*(e-1)/e), error=error) + return self._pow(self.simplify(x * x, error=error * 2 / e), e // 2, error=error) + return self.simplify(x * self._pow(x, e - 1, error=error * (e - 1) / e), error=error) def mac_lane_approximant(self, G, valuation, approximants=None): r""" @@ -894,6 +899,7 @@ def mac_lane_approximant(self, G, valuation, approximants=None): # Check that valuation is an approximant for a valuation # on domain that extends its restriction to the base field. from sage.rings.infinity import infinity + if valuation(G) is not infinity: v = valuation while not v.is_gauss_valuation(): @@ -997,6 +1003,7 @@ def montes_factorization(self, G, assume_squarefree=False, required_precision=No """ if required_precision is None: from sage.rings.infinity import infinity + required_precision = infinity R = G.parent() @@ -1012,6 +1019,7 @@ def montes_factorization(self, G, assume_squarefree=False, required_precision=No ret = [w.phi() for w in W] from sage.structure.factorization import Factorization + return Factorization([(g, 1) for g in ret], simplify=False) def _ge_(self, other): @@ -1052,6 +1060,7 @@ class MacLaneApproximantNode: sage: v.extension(GaussianIntegers()) # indirect doctest 3-adic valuation """ + def __init__(self, valuation, parent, ef, principal_part_bound, coefficients, valuations): r""" TESTS:: diff --git a/src/sage/rings/valuation/valuation_space.py b/src/sage/rings/valuation/valuation_space.py index cb5a35032f5..6303415f225 100644 --- a/src/sage/rings/valuation/valuation_space.py +++ b/src/sage/rings/valuation/valuation_space.py @@ -43,6 +43,7 @@ sage: v = valuations.TrivialPseudoValuation(QQ) sage: v._test_category() """ + # **************************************************************************** # Copyright (C) 2016-2017 Julian Rüth # @@ -100,6 +101,7 @@ class DiscretePseudoValuationSpace(UniqueRepresentation, Homset): sage: TestSuite(H).run() # long time """ + def __init__(self, domain) -> None: r""" TESTS:: @@ -109,6 +111,7 @@ def __init__(self, domain) -> None: True """ from .value_group import DiscreteValuationCodomain + # A valuation is a map from an additive semigroup to an additive semigroup, however, it # does not preserve that structure. It is therefore only a morphism in the category of sets. from sage.categories.sets_cat import Sets @@ -117,6 +120,7 @@ def __init__(self, domain) -> None: Homset.__init__(self, domain, DiscreteValuationCodomain(), category=Sets()) from sage.categories.domains import Domains + if domain not in Domains(): raise ValueError("domain must be an integral domain") @@ -141,6 +145,7 @@ def _abstract_element_class(self): """ class_name = "%s._abstract_element_class" % self.__class__.__name__ from sage.structure.dynamic_class import dynamic_class + return dynamic_class(class_name, (super()._abstract_element_class, self.__class__.ElementMethods)) def _get_action_(self, S, op, self_on_left): @@ -158,6 +163,7 @@ def _get_action_(self, S, op, self_on_left): from sage.rings.infinity import InfinityRing from sage.rings.rational_field import QQ from sage.rings.integer_ring import ZZ + if op == mul and (S is InfinityRing or S is QQ or S is ZZ): return ScaleAction(S, self, not self_on_left, op) return None @@ -173,6 +179,7 @@ def _an_element_(self): Trivial pseudo-valuation on Rational Field """ from .trivial_valuation import TrivialPseudoValuation + return TrivialPseudoValuation(self.domain()) def _repr_(self): @@ -204,6 +211,7 @@ def __contains__(self, x) -> bool: # which entirely relies on a proper implementation of # _element_constructor_ and coercion maps from sage.structure.parent import Parent + return Parent.__contains__(self, x) def __call__(self, x): @@ -221,6 +229,7 @@ def __call__(self, x): # which entirely relies on a proper implementation of # _element_constructor_ and coercion maps from sage.structure.parent import Parent + return Parent.__call__(self, x) def _element_constructor_(self, x): @@ -293,6 +302,7 @@ class ElementMethods: sage: m = H.__make_element_class__(DiscretePseudoValuation)(H) sage: m._test_category() """ + def is_discrete_pseudo_valuation(self): r""" Return whether this valuation is a discrete pseudo-valuation. @@ -329,6 +339,7 @@ def is_negative_pseudo_valuation(self): False """ from sage.categories.fields import Fields + if self.is_discrete_valuation(): return False if self.domain() in Fields(): @@ -351,6 +362,7 @@ def is_trivial(self): False """ from sage.rings.infinity import infinity + if self(self.domain().one()) is infinity: # the constant infinity return True @@ -402,6 +414,7 @@ def value_group(self): ValueError: The trivial pseudo-valuation that is infinity everywhere does not have a value group. """ from .value_group import DiscreteValueGroup + return DiscreteValueGroup(self(self.uniformizer())) def value_semigroup(self): @@ -437,8 +450,10 @@ def value_semigroup(self): Additive Abelian Semigroup generated by 1, 5/3 """ from sage.categories.fields import Fields + if self.domain() in Fields(): from .value_group import DiscreteValueSemigroup + # return the semigroup generated by the elements of the group return DiscreteValueSemigroup([]) + self.value_group() raise NotImplementedError("cannot determine value semigroup of %r" % (self,)) @@ -456,6 +471,7 @@ def element_with_valuation(self, s): """ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ + s = QQ.coerce(s) if s not in self.value_semigroup(): raise ValueError("s must be in the value semigroup of this valuation but %r is not in %r" % (s, self.value_semigroup())) @@ -510,11 +526,14 @@ def residue_field(self): """ ret = self.residue_ring() from sage.categories.fields import Fields + if ret in Fields(): return ret from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(ret, PolynomialRing_generic): from sage.rings.function_field.constructor import FunctionField + return FunctionField(ret.base_ring().fraction_field(), names=(ret.variable_name(),)) return ret.fraction_field() @@ -658,11 +677,14 @@ def scale(self, scalar): +Infinity """ from sage.rings.infinity import infinity + if scalar is infinity: from .trivial_valuation import TrivialPseudoValuation + return TrivialPseudoValuation(self.domain()) if scalar == 0: from .trivial_valuation import TrivialValuation + return TrivialValuation(self.domain()) if scalar == 1: return self @@ -672,10 +694,12 @@ def scale(self, scalar): return self from .scaled_valuation import ScaledValuation_generic + if isinstance(self, ScaledValuation_generic): return self._base_valuation.scale(scalar * self._scale) from .scaled_valuation import ScaledValuation + return ScaledValuation(self, scalar) def separating_element(self, others): @@ -729,14 +753,15 @@ def separating_element(self, others): # construct an element which approximates a unit with respect to others[i] # and has negative valuation with respect to others[:i] from sage.rings.semirings.non_negative_integer_semiring import NN + for r in iter(NN): # When we enter this loop we are essentially out of # luck. The size of the coefficients is likely going # through the roof here and this is not going to # terminate in reasonable time. - factor = (ret**r)/(1+ret**r) + factor = (ret**r) / (1 + ret**r) ret = factor * delta - if all(other(ret) < 0 for other in others[:i+1]): + if all(other(ret) < 0 for other in others[: i + 1]): break return ret @@ -788,7 +813,7 @@ def _strictly_separating_element(self, other): if nn == 0: # the above becomes b != 0 and a/b > d/n b = 1 - a = (d/n + 1).floor() + a = (d / n + 1).floor() else: # Since n,nn,d,dd are all nonnegative this is essentially equivalent to # a/b > d/n and b/a > nn/dd @@ -796,29 +821,30 @@ def _strictly_separating_element(self, other): # dd/nn > a/b > d/n assert dd / nn > d / n from sage.rings.continued_fraction import continued_fraction + ab_cf = [] dn_cf = continued_fraction(d / n) ddnn_cf = continued_fraction(dd / nn) - for i, (x,y) in enumerate(zip(dn_cf, ddnn_cf)): + for i, (x, y) in enumerate(zip(dn_cf, ddnn_cf)): if x == y: ab_cf.append(x) elif x < y: - if y > x+1 or len(ddnn_cf) > i+1: - ab_cf.append(x+1) + if y > x + 1 or len(ddnn_cf) > i + 1: + ab_cf.append(x + 1) else: # the expansion of dd/nn is ending, so we can't append x+1 - ab_cf.extend([x,1,1]) + ab_cf.extend([x, 1, 1]) elif y < x: - if x > y+1 or len(dn_cf) > i+1: - ab_cf.append(y+1) + if x > y + 1 or len(dn_cf) > i + 1: + ab_cf.append(y + 1) else: - ab_cf.extend([y,1,1]) + ab_cf.extend([y, 1, 1]) ab = continued_fraction(ab_cf).value() - a,b = ab.numerator(), ab.denominator() + a, b = ab.numerator(), ab.denominator() ret = self.domain()(numerator**a / denominator**b) - assert (self(ret) > 0) - assert (other(ret) < 0) + assert self(ret) > 0 + assert other(ret) < 0 return ret def _weakly_separating_element(self, other): @@ -884,6 +910,7 @@ def shift(self, x, s): x^2 """ from sage.rings.integer_ring import ZZ + x = self.domain().coerce(x) s = self.value_group()(s) if s == 0: @@ -891,10 +918,10 @@ def shift(self, x, s): s = ZZ(s / self.value_group().gen()) if s > 0: - return x * self.uniformizer()**s + return x * self.uniformizer() ** s # s < 0 if ~self.uniformizer() in self.domain(): - return self.domain()(x / self.uniformizer()**(-s)) + return self.domain()(x / self.uniformizer() ** (-s)) for i in range(-s): if self(x) < 0: raise NotImplementedError("cannot compute general shifts over non-fields which contain elements of negative valuation") @@ -1039,6 +1066,7 @@ def _test_is_negative_pseudo_valuation(self, **options): X = self.domain().some_elements() for x in tester.some_elements(X): from sage.rings.infinity import infinity + tester.assertNotEqual(self(x), -infinity) def _test_bounds(self, **options): @@ -1077,6 +1105,7 @@ def _test_simplify(self, **options): # non-fields) computation of the residue ring is often # difficult and not very interesting from sage.categories.fields import Fields + if self.domain() not in Fields(): return raise @@ -1093,12 +1122,13 @@ def _test_simplify(self, **options): S = self.value_group().some_elements() from itertools import product - for x,s in tester.some_elements(product(X, S)): + + for x, s in tester.some_elements(product(X, S)): y = self.simplify(x, error=s) if self.domain().is_exact(): - tester.assertGreaterEqual(self(x-y), s) + tester.assertGreaterEqual(self(x - y), s) elif hasattr(y, 'precision_absolute'): - tester.assertGreaterEqual(self(x-y), min(s, y.precision_absolute())) + tester.assertGreaterEqual(self(x - y), min(s, y.precision_absolute())) def _test_shift(self, **options): r""" @@ -1122,14 +1152,16 @@ def _test_shift(self, **options): X = self.domain().some_elements() S = self.value_group().some_elements() from itertools import product - for x,s in tester.some_elements(product(X, S)): + + for x, s in tester.some_elements(product(X, S)): if self(x) < 0 and ~self.uniformizer() not in self.domain(): # it is not clear what a shift should be in this case continue y = self.shift(x, s) if s >= 0: - tester.assertGreaterEqual(self(y),self(x)) + tester.assertGreaterEqual(self(y), self(x)) from sage.categories.fields import Fields + if self.domain().is_exact() and self.domain() in Fields(): # the shift here sometimes fails if elements implement # __floordiv__ incorrectly, see #23971 @@ -1150,8 +1182,8 @@ def _test_scale(self, **options): from sage.rings.infinity import infinity from .trivial_valuation import TrivialValuation, TrivialPseudoValuation - tester.assertEqual(QQ(0)*self, TrivialValuation(self.domain())) - tester.assertEqual(infinity*self, TrivialPseudoValuation(self.domain())) + tester.assertEqual(QQ(0) * self, TrivialValuation(self.domain())) + tester.assertEqual(infinity * self, TrivialPseudoValuation(self.domain())) for s in tester.some_elements(QQ.some_elements()): if s < 0: @@ -1183,6 +1215,7 @@ def _test_add(self, **options): tester = self._tester(**options) S = self.domain().some_elements() from itertools import product + for x, y in tester.some_elements(product(S, S)): tester.assertGreaterEqual(self(x + y), min(self(x), self(y))) if self(x) != self(y): @@ -1199,6 +1232,7 @@ def _test_infinite_zero(self, **options): """ tester = self._tester(**options) from sage.rings.infinity import infinity + tester.assertEqual(self(self.domain().zero()), infinity) def _test_mul(self, **options): @@ -1212,6 +1246,7 @@ def _test_mul(self, **options): """ from sage.rings.infinity import infinity from itertools import product + tester = self._tester(**options) S = self.domain().some_elements() infis = {infinity, -infinity} @@ -1246,6 +1281,7 @@ def _test_no_infinite_units(self, **options): return from sage.rings.infinity import infinity + tester = self._tester(**options) for x in tester.some_elements(self.domain().some_elements()): if self(x) is infinity: @@ -1261,6 +1297,7 @@ def _test_value_group(self, **options): sage: v._test_value_group() """ from sage.rings.infinity import infinity + tester = self._tester(**options) # check consistency of trivial valuations first if self.is_trivial(): @@ -1333,6 +1370,7 @@ def _test_residue_ring(self, **options): # non-fields) computation of the residue ring is often # difficult and not very interesting from sage.categories.fields import Fields + if self.domain() not in Fields(): return raise @@ -1364,6 +1402,7 @@ def _test_reduce(self, **options): # non-fields) computation of the residue ring is often # difficult and not very interesting from sage.categories.fields import Fields + if self.domain() not in Fields(): return raise @@ -1402,6 +1441,7 @@ def _test_lift(self, **options): # non-fields) computation of the residue ring is often # difficult and not very interesting from sage.categories.fields import Fields + if self.domain() not in Fields(): return raise @@ -1466,6 +1506,7 @@ def _test_no_infinite_nonzero(self, **options): return from sage.rings.infinity import infinity + tester = self._tester(**options) for x in tester.some_elements(self.domain().some_elements()): if self(x) is infinity: @@ -1488,6 +1529,7 @@ def _test_residue_field(self, **options): self.residue_field() except ValueError: from sage.categories.fields import Fields + # a discrete valuation on a field has a residue field tester.assertNotIn(self.domain(), Fields()) return @@ -1496,6 +1538,7 @@ def _test_residue_field(self, **options): # non-fields) computation of the residue ring is often # difficult and not very interesting from sage.categories.fields import Fields + if self.domain() not in Fields(): return raise @@ -1533,6 +1576,7 @@ def _test_ge(self, **options): return from .trivial_valuation import TrivialPseudoValuation, TrivialValuation + tester.assertGreaterEqual(self, TrivialValuation(self.domain())) tester.assertLessEqual(self, TrivialPseudoValuation(self.domain())) @@ -1553,6 +1597,7 @@ def _test_le(self, **options): return from .trivial_valuation import TrivialPseudoValuation, TrivialValuation + tester.assertLessEqual(TrivialValuation(self.domain()), self) tester.assertGreaterEqual(TrivialPseudoValuation(self.domain()), self) @@ -1569,6 +1614,7 @@ def _test_inverse(self, **options): for x in tester.some_elements(self.domain().some_elements()): from sage.rings.infinity import infinity + for prec in (0, 1, 42, infinity): try: y = self.inverse(x, prec) @@ -1597,6 +1643,7 @@ class ScaleAction(Action): sage: v.parent().get_action(ZZ, mul, self_on_left=False) Left action by Integer Ring on Discrete pseudo-valuations on Rational Field """ + def _act_(self, s, v): r""" Let ``s`` act on ``v``. diff --git a/src/sage/rings/valuation/value_group.py b/src/sage/rings/valuation/value_group.py index e79374615b4..665cc6b8c56 100644 --- a/src/sage/rings/valuation/value_group.py +++ b/src/sage/rings/valuation/value_group.py @@ -15,6 +15,7 @@ sage: v.value_semigroup() Additive Abelian Semigroup generated by 1 """ + # **************************************************************************** # Copyright (C) 2013-2018 Julian Rüth # @@ -47,6 +48,7 @@ class DiscreteValuationCodomain(UniqueRepresentation, Parent): sage: TestSuite(C).run() # long time """ + def __init__(self): r""" TESTS:: @@ -57,6 +59,7 @@ def __init__(self): """ from sage.sets.finite_enumerated_set import FiniteEnumeratedSet from sage.categories.additive_monoids import AdditiveMonoids + UniqueRepresentation.__init__(self) Parent.__init__(self, facade=(QQ, FiniteEnumeratedSet([infinity, -infinity])), category=AdditiveMonoids()) @@ -134,6 +137,7 @@ class DiscreteValueGroup(UniqueRepresentation, Parent): sage: TestSuite(D2).run() # long time sage: TestSuite(D3).run() # long time """ + @staticmethod def __classcall__(cls, generator): r""" @@ -158,6 +162,7 @@ def __init__(self, generator): True """ from sage.categories.modules import Modules + self._generator = generator # We can not set the facade to DiscreteValuationCodomain since there @@ -235,6 +240,7 @@ def __add__(self, other): if isinstance(other, DiscreteValueSemigroup): return other + self from sage.structure.element import Element + if isinstance(other, Element) and QQ.has_coerce_map_from(other.parent()): return self + DiscreteValueGroup(other) raise ValueError("`other` must be a DiscreteValueGroup or a rational number") @@ -382,11 +388,11 @@ def _element_with_valuation(self, subgroup, s): raise ValueError("s must be in the value group but %r is not in %r." % (s, self)) i = self.index(subgroup) - x = s/self.gen() + x = s / self.gen() a = x % i - if abs(a-i) < a: + if abs(a - i) < a: a -= i - b = (x-a)/i + b = (x - a) / i return a, b @@ -415,6 +421,7 @@ class DiscreteValueSemigroup(UniqueRepresentation, Parent): sage: TestSuite(D2).run() # long time # needs sage.geometry.polyhedron sage: TestSuite(D3).run() # long time # needs sage.numerical.mip """ + @staticmethod def __classcall__(cls, generators): r""" @@ -449,6 +456,7 @@ def __classcall__(cls, generators): if g == h: continue from sage.rings.semirings.non_negative_integer_semiring import NN + if h / g in NN: simplified_generators.remove(h) break @@ -464,6 +472,7 @@ def __init__(self, generators): True """ from sage.categories.additive_magmas import AdditiveMagmas + self._generators = generators category = AdditiveMagmas().AdditiveAssociative().AdditiveUnital() @@ -500,23 +509,25 @@ def _solve_linear_program(self, target): if len(self._generators) == 1: from sage.rings.semirings.non_negative_integer_semiring import NN + exp = target / self._generators[0] if exp not in NN: return None return {0: exp} - if len(self._generators) == 2 and self._generators[0] == - self._generators[1]: + if len(self._generators) == 2 and self._generators[0] == -self._generators[1]: from sage.rings.integer_ring import ZZ + exp = target / self._generators[0] if exp not in ZZ: return None return {0: exp, 1: 0} from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException + P = MixedIntegerLinearProgram(maximization=False, solver='ppl') x = P.new_variable(integer=True, nonnegative=True) - constraint = sum([g * x[i] - for i, g in enumerate(self._generators)]) == target + constraint = sum([g * x[i] for i, g in enumerate(self._generators)]) == target P.add_constraint(constraint) P.set_objective(None) try: @@ -595,6 +606,7 @@ def __add__(self, other): if isinstance(other, DiscreteValueGroup): return DiscreteValueSemigroup(self._generators + (other._generator, -other._generator)) from sage.structure.element import Element + if isinstance(other, Element) and QQ.has_coerce_map_from(other.parent()): return self + DiscreteValueSemigroup(other) raise ValueError("`other` must be a DiscreteValueGroup, a DiscreteValueSemigroup or a rational number") @@ -620,7 +632,7 @@ def _mul_(self, other, switch_sides=False): Trivial Additive Abelian Semigroup """ other = QQ.coerce(other) - return DiscreteValueSemigroup([g*other for g in self._generators]) + return DiscreteValueSemigroup([g * other for g in self._generators]) def gens(self) -> tuple: r""" @@ -649,9 +661,9 @@ def some_elements(self): return yield from self._generators from sage.rings.integer_ring import ZZ - for x in (ZZ**len(self._generators)).some_elements(): - yield QQ.coerce(sum([abs(c) * g - for c, g in zip(x, self._generators)])) + + for x in (ZZ ** len(self._generators)).some_elements(): + yield QQ.coerce(sum([abs(c) * g for c, g in zip(x, self._generators)])) def is_trivial(self): r""" diff --git a/src/sage/sandpiles/examples.py b/src/sage/sandpiles/examples.py index a25f5ea1509..e18a72c2045 100644 --- a/src/sage/sandpiles/examples.py +++ b/src/sage/sandpiles/examples.py @@ -49,6 +49,7 @@ class SandpileExamples: [-1 -1 3 -1] [-1 -1 -1 3] """ + def __call__(self): r""" If ``sandpiles()`` is executed, return a helpful message. @@ -63,8 +64,7 @@ def __call__(self): Complete, Cycle, Diamond, Fan, Grid, House, Wheel """ print('Try sandpiles.FOO() where FOO is in the list:\n') - print(" " + ", ".join(str(i) for i in dir(sandpiles) - if i[0] != '_')) + print(" " + ", ".join(str(i) for i in dir(sandpiles) if i[0] != '_')) def Complete(self, n): """ @@ -146,10 +146,10 @@ def Fan(self, n, deg_three_verts=False): """ f = graphs.WheelGraph(n) if n > 2: - f.delete_edge(1, n-1) + f.delete_edge(1, n - 1) if deg_three_verts: f.allow_multiple_edges(True) - f.add_edges([(0, 1), (0, n-1)]) + f.add_edges([(0, 1), (0, n - 1)]) return Sandpile(f, 0) if n == 1: return Sandpile(f, 0) @@ -179,10 +179,10 @@ def Grid(self, m, n): sage: s.dict() {(0, 0): {(1, 1): 4}, (1, 1): {(0, 0): 4}} """ - G = graphs.Grid2dGraph(m+2, n+2) + G = graphs.Grid2dGraph(m + 2, n + 2) G.allow_multiple_edges(True) # to ensure each vertex ends up with degree 4 - V = [(i, j) for i in [0, m+1] for j in range(n+2)] - V += [(i, j) for j in [0, n+1] for i in range(m+2)] + V = [(i, j) for i in [0, m + 1] for j in range(n + 2)] + V += [(i, j) for j in [0, n + 1] for i in range(m + 2)] G.merge_vertices(V) return Sandpile(G, (0, 0)) diff --git a/src/sage/sandpiles/sandpile.py b/src/sage/sandpiles/sandpile.py index c9640f0b76a..f14bcc33153 100644 --- a/src/sage/sandpiles/sandpile.py +++ b/src/sage/sandpiles/sandpile.py @@ -355,6 +355,7 @@ from sage.symbolic.constants import I, pi from sage.symbolic.ring import SR from sage.features.four_ti_2 import FourTi2Executable + lazy_import("sage.plot.colors", "rainbow") @@ -370,6 +371,7 @@ def _sandpile_help(cls, usage, verbose=True): # in the string, take the sentence to be the empty string. If the # latter occurs, something should be changed. from sage.misc.sagedoc import detex + methods = [] for attr in sorted(vars(cls)): if attr[0] != '_': @@ -407,6 +409,7 @@ class Sandpile(DiGraph): """ Class for Dhar's abelian sandpile model. """ + @staticmethod def version(): r""" @@ -496,10 +499,15 @@ def help(verbose=True): zero_config -- The all-zero configuration. zero_div -- The all-zero divisor. """ - _sandpile_help(Sandpile, dedent("""\ + _sandpile_help( + Sandpile, + dedent( + """\ For detailed help with any method FOO listed below, - enter "Sandpile.FOO?" or enter "S.FOO?" for any Sandpile S."""), - verbose=verbose) + enter "Sandpile.FOO?" or enter "S.FOO?" for any Sandpile S.""" + ), + verbose=verbose, + ) def __init__(self, g, sink=None) -> None: r""" @@ -603,7 +611,7 @@ def __init__(self, g, sink=None) -> None: if p == -1: name = name + ' sandpile graph' else: - name = name[:p] + 'sandpile graph' + name[p + 5:] + name = name[:p] + 'sandpile graph' + name[p + 5 :] self._name = name else: self._name = 'sandpile graph' @@ -620,8 +628,7 @@ def __init__(self, g, sink=None) -> None: else: vi = {v: i for i, v in enumerate(g.vertices(sort=True))} ad = g.weighted_adjacency_matrix() - g = {v: {w: ad[vi[v], vi[w]] for w in g.neighbor_iterator(v)} - for v in g} + g = {v: {w: ad[vi[v], vi[w]] for w in g.neighbor_iterator(v)} for v in g} else: raise SyntaxError(g) @@ -1309,8 +1316,7 @@ def _set_recurrents(self): """ if self.name() == 'Complete sandpile graph': n = self.n_vertices() - self._recurrents = [SandpileConfig(self, [n - 1 - i for i in p]) - for p in ParkingFunctions(n - 1)] + self._recurrents = [SandpileConfig(self, [n - 1 - i for i in p]) for p in ParkingFunctions(n - 1)] elif self.name() == 'Cycle sandpile graph': n = self.n_vertices() one = [1] * (n - 2) @@ -1441,8 +1447,7 @@ def _set_group_gens(self): """ D, U, _ = self.reduced_laplacian().transpose().smith_form() F = U.inverse() - self._group_gens = [SandpileConfig(self, [Integer(j) for j in F.column(i)]).equivalent_recurrent() - for i in range(F.nrows()) if D[i][i] != 1] + self._group_gens = [SandpileConfig(self, [Integer(j) for j in F.column(i)]).equivalent_recurrent() for i in range(F.nrows()) if D[i][i] != 1] def group_gens(self, verbose=True) -> list: r""" @@ -1687,8 +1692,7 @@ def avalanche_polynomial(self, multivariable=True): if multivariable: return deepcopy(self._avalanche_polynomial) X = self._avalanche_polynomial.parent().gens() - return self._avalanche_polynomial.subs({X[i]: X[0] - for i in range(1, self.n_vertices() - 1)}) + return self._avalanche_polynomial.subs({X[i]: X[0] for i in range(1, self.n_vertices() - 1)}) def nonspecial_divisors(self, verbose=True) -> list: r""" @@ -1757,8 +1761,7 @@ def canonical_divisor(self): The underlying graph must be undirected. """ if self.is_undirected(): - return SandpileDivisor(self, [self.laplacian()[i][i] - 2 - for i in range(self.n_vertices())]) + return SandpileDivisor(self, [self.laplacian()[i][i] - 2 for i in range(self.n_vertices())]) raise TypeError("only for undirected graphs") def _set_invariant_factors(self): @@ -1811,8 +1814,7 @@ def _set_hilbert_function(self): self._h_vector = [v.count(i) for i in range(self._postulation + 1)] self._hilbert_function = [1] for i in range(self._postulation): - self._hilbert_function.append(self._hilbert_function[i] - + self._h_vector[i + 1]) + self._hilbert_function.append(self._hilbert_function[i] + self._h_vector[i + 1]) def h_vector(self): r""" @@ -1954,7 +1956,7 @@ def _set_jacobian_representatives(self): result = [] for r in self.superstables(): D = {v: r[v] for v in self._nonsink_vertices} - D[self._sink] = - r.deg() + D[self._sink] = -r.deg() result.append(SandpileDivisor(self, D)) self._jacobian_representatives = result else: @@ -2089,8 +2091,7 @@ def stable_configs(self, smax=None): else: c = SandpileConfig(self, smax) if c > self.max_stable(): - smax = [min(c[v], self.max_stable()[v]) - for v in self.nonsink_vertices()] + smax = [min(c[v], self.max_stable()[v]) for v in self.nonsink_vertices()] else: smax = c.values() for c in IntegerVectorsIterator(smax): @@ -2236,13 +2237,13 @@ def _set_stationary_density(self): t = myR(t) dt = derivative(t, y).subs(y=1) t = t.subs(y=1) - self._stationary_density = (self.n_edges()/2 + dt/t)/self.n_vertices() + self._stationary_density = (self.n_edges() / 2 + dt / t) / self.n_vertices() else: sink_deg = self.out_degree(self.sink()) h = vector(ZZ, self.h_vector()) m = self.max_stable().deg() - d = vector(ZZ, range(m, m-len(h), -1)) - self._stationary_density = (h*d/self.group_order() + sink_deg)/self.n_vertices() + d = vector(ZZ, range(m, m - len(h), -1)) + self._stationary_density = (h * d / self.group_order() + sink_deg) / self.n_vertices() def stationary_density(self): r""" @@ -2290,7 +2291,7 @@ def all_k_div(self, k): sage: S.all_k_div(7) {0: 7, 1: 7, 2: 7, 3: 7, 4: 7} """ - return SandpileDivisor(self, [k]*self.n_vertices()) + return SandpileDivisor(self, [k] * self.n_vertices()) def zero_div(self): r""" @@ -2428,6 +2429,7 @@ def _set_ideal(self): True """ from sage.libs.singular.function_factory import ff + try: sat = ff.elim__lib.sat_with_exp except NameError: @@ -2539,8 +2541,8 @@ def _set_resolution(self): for j in range(self._betti[i]): row = new[j].transpose().sage_matrix(self._ring) row = list(row[0]) - if len(row) < self._betti[i-1]: - row += [zero]*(self._betti[i-1]-len(row)) + if len(row) < self._betti[i - 1]: + row += [zero] * (self._betti[i - 1] - len(row)) syz_mat.append(row) syz_mat = matrix(self._ring, syz_mat).transpose() result.append(syz_mat) @@ -2587,7 +2589,7 @@ def resolution(self, verbose=False): """ if verbose: return self._resolution - r = ['R^'+str(i) for i in self._betti] + r = ['R^' + str(i) for i in self._betti] return ' <-- '.join(r) def _set_groebner(self): @@ -2650,8 +2652,7 @@ def betti(self, verbose=True): [1, 6, 9, 4] """ if verbose: - print(singular.eval('print(betti(%s), "betti")' % - self._singular_resolution.name())) + print(singular.eval('print(betti(%s), "betti")' % self._singular_resolution.name())) else: return self._betti @@ -2692,8 +2693,7 @@ def solve(self): v = [singular.var(i) for i in range(1, int(singular.nvars(self._ring)))] vars_ = '({})'.format(','.join(str(i) for i in v)) - L = singular.subst(self._ideal, - singular.var(singular.nvars(self._ring)), 1) + L = singular.subst(self._ideal, singular.var(singular.nvars(self._ring)), 1) _ = singular.ring(0, vars_, 'lp') K = singular.fetch(self._ring, L) K = singular.groebner(K) @@ -2804,6 +2804,7 @@ class SandpileConfig(dict): r""" Class for configurations on a sandpile. """ + @staticmethod def help(verbose=True): r""" @@ -2854,7 +2855,10 @@ def help(verbose=True): unstable -- The unstable vertices. values -- The values of the configuration as a list. """ - _sandpile_help(SandpileConfig, dedent("""\ + _sandpile_help( + SandpileConfig, + dedent( + """\ Shortcuts for SandpileConfig operations: ~c -- stabilize c & d -- add and stabilize @@ -2863,8 +2867,10 @@ def help(verbose=True): (taking inverse if k is negative) For detailed help with any method FOO listed below, - enter "SandpileConfig.FOO?" or enter "c.FOO?" for any SandpileConfig c."""), - verbose=verbose) + enter "SandpileConfig.FOO?" or enter "c.FOO?" for any SandpileConfig c.""" + ), + verbose=verbose, + ) def __init__(self, S, c) -> None: r""" @@ -3040,9 +3046,7 @@ def __add__(self, other): sage: c + d {1: 4, 2: 4} """ - return SandpileConfig(self.sandpile(), - [i + j for i, j in zip(self.values(), - other.values())]) + return SandpileConfig(self.sandpile(), [i + j for i, j in zip(self.values(), other.values())]) def __sub__(self, other): r""" @@ -3111,8 +3115,7 @@ def __neg__(self): sage: -c {1: -1, 2: -2} """ - return SandpileConfig(self._sandpile, - [-self[v] for v in self._vertices]) + return SandpileConfig(self._sandpile, [-self[v] for v in self._vertices]) # recurrent addition or multiplication on the right by an integer def __mul__(self, other): @@ -3149,8 +3152,7 @@ def __mul__(self, other): if isinstance(other, SandpileConfig): return (self + other).equivalent_recurrent() if isinstance(other, Integer): - return SandpileConfig(self.sandpile(), - [other * i for i in self.values()]) + return SandpileConfig(self.sandpile(), [other * i for i in self.values()]) raise TypeError(other) def __rmul__(self, other): @@ -3174,8 +3176,7 @@ def __rmul__(self, other): sage: 3*c == c*3 True """ - return SandpileConfig(self.sandpile(), - [other * i for i in self.values()]) + return SandpileConfig(self.sandpile(), [other * i for i in self.values()]) def __le__(self, other) -> bool: r""" @@ -3484,8 +3485,7 @@ def unstable(self) -> list: sage: c.unstable() [2, 3] """ - return [v for v in self._vertices - if self[v] >= self._sandpile.out_degree(v)] + return [v for v in self._vertices if self[v] >= self._sandpile.out_degree(v)] def fire_unstable(self): r""" @@ -3704,7 +3704,7 @@ def order(self): True """ v = vector(self.values()) - w = v * self._sandpile.reduced_laplacian().dense_matrix()**(-1) + w = v * self._sandpile.reduced_laplacian().dense_matrix() ** (-1) return lcm([i.denominator() for i in w]) def is_stable(self) -> bool: @@ -3801,14 +3801,14 @@ def _set_is_recurrent(self) -> None: True """ if '_recurrents' in self._sandpile.__dict__: - self._is_recurrent = (self in self._sandpile._recurrents) + self._is_recurrent = self in self._sandpile._recurrents elif '_equivalent_recurrent' in self.__dict__: - self._is_recurrent = (self._equivalent_recurrent == self) + self._is_recurrent = self._equivalent_recurrent == self else: # add the burning configuration to config b = self._sandpile._burning_config c = ~(self + b) - self._is_recurrent = (c == self) + self._is_recurrent = c == self def is_recurrent(self) -> bool: r""" @@ -3892,9 +3892,9 @@ def _set_is_superstable(self) -> None: True """ if '_superstables' in self._sandpile.__dict__: - self._is_superstable = (self in self._sandpile._superstables) + self._is_superstable = self in self._sandpile._superstables elif '_equivalent_superstable' in self.__dict__: - self._is_superstable = (self._equivalent_superstable[0] == self) + self._is_superstable = self._equivalent_superstable[0] == self else: self._is_superstable = self.dualize().is_recurrent() @@ -4048,6 +4048,7 @@ def show(self, sink=True, colors=True, heights=False, directed=None, **kwds): # SandpileDivisor Class # ############################################### + class SandpileDivisor(dict): r""" Class for divisors on a sandpile. @@ -4101,10 +4102,15 @@ def help(verbose=True): weierstrass_pts -- The Weierstrass points (vertices). weierstrass_rank_seq -- The Weierstrass rank sequence at the given vertex. """ - _sandpile_help(SandpileDivisor, dedent("""\ + _sandpile_help( + SandpileDivisor, + dedent( + """\ For detailed help with any method FOO listed below, - enter "SandpileDivisor.FOO?" or enter "D.FOO?" for any SandpileDivisor D."""), - verbose=verbose) + enter "SandpileDivisor.FOO?" or enter "D.FOO?" for any SandpileDivisor D.""" + ), + verbose=verbose, + ) def __init__(self, S, D) -> None: r""" @@ -4301,9 +4307,7 @@ def __add__(self, other): sage: D + E {0: 4, 1: 4, 2: 4} """ - return SandpileDivisor(self.sandpile(), - [i + j for i, j in zip(self.values(), - other.values())]) + return SandpileDivisor(self.sandpile(), [i + j for i, j in zip(self.values(), other.values())]) def __mul__(self, other): r""" @@ -4326,8 +4330,7 @@ def __mul__(self, other): sage: 3*D == D*3 True """ - return SandpileDivisor(self.sandpile(), - [i * other for i in self.values()]) + return SandpileDivisor(self.sandpile(), [i * other for i in self.values()]) def __rmul__(self, other): r""" @@ -4350,7 +4353,7 @@ def __rmul__(self, other): sage: 3*D == D*3 True """ - return SandpileDivisor(self.sandpile(), [other*i for i in self.values()]) + return SandpileDivisor(self.sandpile(), [other * i for i in self.values()]) def __radd__(self, other): r""" @@ -4676,8 +4679,7 @@ def unstable(self) -> list: sage: D.unstable() [1, 2] """ - return [v for v in self._vertices if - self[v] >= self._sandpile.out_degree(v)] + return [v for v in self._vertices if self[v] >= self._sandpile.out_degree(v)] def fire_unstable(self): r""" @@ -4926,27 +4928,27 @@ def _set_linear_system(self) -> None: lin_sys_log = lin_sys + '.log' with open(lin_sys_mat, 'w') as mat_file: - mat_file.write(str(n)+' ') - mat_file.write(str(n)+'\n') + mat_file.write(str(n) + ' ') + mat_file.write(str(n) + '\n') for r in L: mat_file.write(''.join(map(str, r))) mat_file.write('\n') # relations file with open(lin_sys_rel, 'w') as rel_file: rel_file.write('1 ') - rel_file.write(str(n)+'\n') - rel_file.write('>'*n) + rel_file.write(str(n) + '\n') + rel_file.write('>' * n) rel_file.write('\n') # right-hand side file with open(lin_sys_rhs, 'w') as rhs_file: rhs_file.write('1 ') - rhs_file.write(str(n)+'\n') + rhs_file.write(str(n) + '\n') rhs_file.write(''.join(str(-i) for i in self.values())) rhs_file.write('\n') # sign file with open(lin_sys_sign, 'w') as sign_file: sign_file.write('1 ') - sign_file.write(str(n)+'\n') + sign_file.write(str(n) + '\n') """ Conjecture: taking only 1s just below is OK, i.e., looking for solutions with nonnegative entries. The @@ -4956,22 +4958,25 @@ def _set_linear_system(self) -> None: nonnegative solution. What if the vector in the kernel does not have full support though? """ - sign_file.write('2'*n) # so maybe a 1 could go here + sign_file.write('2' * n) # so maybe a 1 could go here sign_file.write('\n') # compute import os import shlex + try: path_to_zsolve = FourTi2Executable('zsolve').absolute_filename() os.system(shlex.quote(path_to_zsolve) + ' -q ' + lin_sys + ' > ' + lin_sys_log) # process the results zhom_file = open(lin_sys_zhom) except OSError: - print(""" + print( + """ ********************************** *** This method requires 4ti2. *** ********************************** - """) + """ + ) return # first, the cone generators (the homogeneous points) a = zhom_file.read() @@ -4986,8 +4991,7 @@ def _set_linear_system(self) -> None: b = b.split('\n') num_inhomog = int(b[0].split()[0]) inhomog = [map(int, i.split()) for i in b[1:-1]] - self._linear_system = {'num_homog': num_homog, 'homog': homog, - 'num_inhomog': num_inhomog, 'inhomog': inhomog} + self._linear_system = {'num_homog': num_homog, 'homog': homog, 'num_inhomog': num_inhomog, 'inhomog': inhomog} def _set_polytope(self) -> None: r""" @@ -5094,8 +5098,7 @@ def _set_effective_div(self) -> None: S = self.sandpile() myL = S.laplacian().transpose().delete_columns([S._sink_ind]) dv = vector(ZZ, self.values()) - self._effective_div = [SandpileDivisor(S, list(dv - myL*i)) - for i in self._polytope_integer_pts] + self._effective_div = [SandpileDivisor(S, list(dv - myL * i)) for i in self._polytope_integer_pts] def effective_div(self, verbose=True, with_firing_vectors=False) -> list: r""" @@ -5159,11 +5162,10 @@ def effective_div(self, verbose=True, with_firing_vectors=False) -> list: S = self.sandpile() eff = deepcopy(self._effective_div) if with_firing_vectors: - fv = [vector(list(i)[:S._sink_ind] + [0] + list(i)[S._sink_ind:]) - for i in self._polytope_integer_pts] + fv = [vector(list(i)[: S._sink_ind] + [0] + list(i)[S._sink_ind :]) for i in self._polytope_integer_pts] if verbose and with_firing_vectors: return list(zip(eff, fv)) - if verbose: # verbose without firing vectors + if verbose: # verbose without firing vectors return eff if with_firing_vectors: # not verbose but with firing vectors return list(zip([i.values() for i in eff], fv)) @@ -5332,10 +5334,10 @@ def _set_r_of_D(self, verbose=False): # standard basis vectors e = [] for i in range(n): - v = vector([0]*n) + v = vector([0] * n) v[i] += 1 e.append(v) - level = [vector([0]*n)] + level = [vector([0] * n)] while True: r += 1 if verbose: @@ -5478,8 +5480,7 @@ def _set_weierstrass_pts(self): sage: '_weierstrass_pts' in D.__dict__ True """ - self._weierstrass_pts = tuple([v for v in self.sandpile().vertices(sort=True) - if self.is_weierstrass_pt(v)]) + self._weierstrass_pts = tuple([v for v in self.sandpile().vertices(sort=True) if self.is_weierstrass_pt(v)]) def weierstrass_pts(self, with_rank_seq=False): r""" @@ -5731,7 +5732,7 @@ def _set_life(self): result.append(newD) oldD = deepcopy(newD) else: - self._life = result[result.index(newD):] + self._life = result[result.index(newD) :] return def is_alive(self, cycle=False): @@ -5847,6 +5848,7 @@ def show(self, heights=True, directed=None, **kwds): # Some test graphs # ####################################### + def sandlib(selector=None): r""" Return the sandpile identified by ``selector``. If no argument is @@ -5876,37 +5878,13 @@ def sandlib(selector=None): """ # The convention is for the sink to be zero. sandpiles = { - 'generic': {'description': 'generic digraph with 6 vertices', - 'graph': {0: {}, 1: {0: 1, 3: 1, 4: 1}, - 2: {0: 1, 3: 1, 5: 1}, - 3: {2: 1, 5: 1}, 4: {1: 1, 3: 1}, - 5: {2: 1, 3: 1}}}, - 'kite': {'description': 'generic undirected graphs with 5 vertices', - 'graph': {0: {}, 1: {0: 1, 2: 1, 3: 1}, - 2: {1: 1, 3: 1, 4: 1}, 3: {1: 1, 2: 1, 4: 1}, - 4: {2: 1, 3: 1}}}, - 'riemann-roch1': {'description': 'directed graph with postulation 9 and 3 maximal weight superstables', - 'graph': {0: {1: 3, 3: 1}, - 1: {0: 2, 2: 2, 3: 2}, - 2: {0: 1, 1: 1}, - 3: {0: 3, 1: 1, 2: 1}}}, - 'riemann-roch2': {'description': 'directed graph with a superstable not majorized by a maximal superstable', - 'graph': {0: {}, - 1: {0: 1, 2: 1}, - 2: {0: 1, 3: 1}, - 3: {0: 1, 1: 1, 2: 1}}}, - 'gor': {'description': 'Gorenstein but not a complete intersection', - 'graph': {0: {}, - 1: {0: 1, 2: 1, 3: 4}, - 2: {3: 5}, - 3: {1: 1, 2: 1}}}, - 'ci1': {'description': 'complete intersection, non-DAG but equivalent to a DAG', - 'graph': {0: {}, 1: {2: 2}, 2: {0: 4, 1: 1}}}, - 'genus2': {'description': 'Undirected graph of genus 2', - 'graph': {0: [1, 2], - 1: [0, 2, 3], - 2: [0, 1, 3], - 3: [1, 2]}}, + 'generic': {'description': 'generic digraph with 6 vertices', 'graph': {0: {}, 1: {0: 1, 3: 1, 4: 1}, 2: {0: 1, 3: 1, 5: 1}, 3: {2: 1, 5: 1}, 4: {1: 1, 3: 1}, 5: {2: 1, 3: 1}}}, + 'kite': {'description': 'generic undirected graphs with 5 vertices', 'graph': {0: {}, 1: {0: 1, 2: 1, 3: 1}, 2: {1: 1, 3: 1, 4: 1}, 3: {1: 1, 2: 1, 4: 1}, 4: {2: 1, 3: 1}}}, + 'riemann-roch1': {'description': 'directed graph with postulation 9 and 3 maximal weight superstables', 'graph': {0: {1: 3, 3: 1}, 1: {0: 2, 2: 2, 3: 2}, 2: {0: 1, 1: 1}, 3: {0: 3, 1: 1, 2: 1}}}, + 'riemann-roch2': {'description': 'directed graph with a superstable not majorized by a maximal superstable', 'graph': {0: {}, 1: {0: 1, 2: 1}, 2: {0: 1, 3: 1}, 3: {0: 1, 1: 1, 2: 1}}}, + 'gor': {'description': 'Gorenstein but not a complete intersection', 'graph': {0: {}, 1: {0: 1, 2: 1, 3: 4}, 2: {3: 5}, 3: {1: 1, 2: 1}}}, + 'ci1': {'description': 'complete intersection, non-DAG but equivalent to a DAG', 'graph': {0: {}, 1: {2: 2}, 2: {0: 4, 1: 1}}}, + 'genus2': {'description': 'Undirected graph of genus 2', 'graph': {0: [1, 2], 1: [0, 2, 3], 2: [0, 1, 3], 3: [1, 2]}}, } if selector is None: print() @@ -5924,6 +5902,7 @@ def sandlib(selector=None): # Some useful functions # ################################################# + def triangle_sandpile(n): r""" A triangular sandpile. Each nonsink vertex has out-degree six. The @@ -5944,25 +5923,25 @@ def triangle_sandpile(n): """ T = {(-1, -1): {}} for i in range(n): - for j in range(n-i): + for j in range(n - i): T[(i, j)] = {} - if i < n-j-1: - T[(i, j)][(i+1, j)] = 1 - T[(i, j)][(i, j+1)] = 1 + if i < n - j - 1: + T[(i, j)][(i + 1, j)] = 1 + T[(i, j)][(i, j + 1)] = 1 if i > 0: - T[(i, j)][(i-1, j+1)] = 1 - T[(i, j)][(i-1, j)] = 1 + T[(i, j)][(i - 1, j + 1)] = 1 + T[(i, j)][(i - 1, j)] = 1 if j > 0: - T[(i, j)][(i, j-1)] = 1 - T[(i, j)][(i+1, j-1)] = 1 + T[(i, j)][(i, j - 1)] = 1 + T[(i, j)][(i + 1, j - 1)] = 1 d = len(T[(i, j)]) if d < 6: - T[(i, j)][(-1, -1)] = 6-d + T[(i, j)][(-1, -1)] = 6 - d T = Sandpile(T, (-1, -1)) pos = {} for x in T.nonsink_vertices(): coords = list(x) - coords[0] += QQ(1)/2*coords[1] + coords[0] += QQ(1) / 2 * coords[1] pos[x] = tuple(coords) pos[(-1, -1)] = (-1, -1) T.set_pos(pos) @@ -5996,11 +5975,11 @@ def aztec_sandpile(n): aztec_sandpile = {} half = QQ((1, 2)) for i in xsrange(n): - for j in xsrange(n-i): - aztec_sandpile[(half+i, half+j)] = {} - aztec_sandpile[(-half-i, half+j)] = {} - aztec_sandpile[(half+i, -half-j)] = {} - aztec_sandpile[(-half-i, -half-j)] = {} + for j in xsrange(n - i): + aztec_sandpile[(half + i, half + j)] = {} + aztec_sandpile[(-half - i, half + j)] = {} + aztec_sandpile[(half + i, -half - j)] = {} + aztec_sandpile[(-half - i, -half - j)] = {} non_sinks = list(aztec_sandpile) aztec_sandpile[(0, 0)] = {} for vert in non_sinks: @@ -6008,16 +5987,16 @@ def aztec_sandpile(n): x = vert[0] y = vert[1] if weight < n: - aztec_sandpile[vert] = {(x+1, y): 1, (x, y+1): 1, (x-1, y): 1, (x, y-1): 1} + aztec_sandpile[vert] = {(x + 1, y): 1, (x, y + 1): 1, (x - 1, y): 1, (x, y - 1): 1} else: - if (x+1, y) in aztec_sandpile: - aztec_sandpile[vert][(x+1, y)] = 1 - if (x, y+1) in aztec_sandpile: - aztec_sandpile[vert][(x, y+1)] = 1 - if (x-1, y) in aztec_sandpile: - aztec_sandpile[vert][(x-1, y)] = 1 - if (x, y-1) in aztec_sandpile: - aztec_sandpile[vert][(x, y-1)] = 1 + if (x + 1, y) in aztec_sandpile: + aztec_sandpile[vert][(x + 1, y)] = 1 + if (x, y + 1) in aztec_sandpile: + aztec_sandpile[vert][(x, y + 1)] = 1 + if (x - 1, y) in aztec_sandpile: + aztec_sandpile[vert][(x - 1, y)] = 1 + if (x, y - 1) in aztec_sandpile: + aztec_sandpile[vert][(x, y - 1)] = 1 if len(aztec_sandpile[vert]) < 4: out_degree = 4 - len(aztec_sandpile[vert]) aztec_sandpile[vert][(0, 0)] = out_degree @@ -6085,8 +6064,8 @@ def glue_graphs(g, h, glue_g, glue_h): if i != g_sink: new_edges = {} for j in g[i]: - new_edges['x'+str(j)] = g[i][j] - k['x'+str(i)] = new_edges + new_edges['x' + str(j)] = g[i][j] + k['x' + str(i)] = new_edges for i in h: if i != h_sink: new_edges = {} @@ -6094,18 +6073,18 @@ def glue_graphs(g, h, glue_g, glue_h): if j == h_sink: new_edges['sink'] = h[i][j] else: - new_edges['y'+str(j)] = h[i][j] - k['y'+str(i)] = new_edges + new_edges['y' + str(j)] = h[i][j] + k['y' + str(i)] = new_edges # now handle the glue vertex (old g sink) new_edges = {} for i in glue_g: - new_edges['x'+str(i)] = glue_g[i] + new_edges['x' + str(i)] = glue_g[i] for i in glue_h: if i == h_sink: new_edges['sink'] = glue_h[i] else: - new_edges['y'+str(i)] = glue_h[i] - k['x'+str(g_sink)] = new_edges + new_edges['y' + str(i)] = glue_h[i] + k['x' + str(g_sink)] = new_edges return k @@ -6265,6 +6244,7 @@ def partition_sandpile(S, p) -> Sandpile: total: 1 6 8 3 """ from itertools import combinations + g = Graph() g.add_vertices(tuple(i) for i in p) for u, v in combinations(g, 2): @@ -6331,21 +6311,21 @@ def wilmes_algorithm(M): if M.matrix_over_field().is_invertible(): L = matrix(ZZ, M) U = matrix(ZZ, [sum(i) for i in L]).smith_form()[2].transpose() - L = U*M - for k in range(1, M.nrows()-1): - sm = matrix(ZZ, [i[k-1] for i in L[k:]]).smith_form()[2].transpose() + L = U * M + for k in range(1, M.nrows() - 1): + sm = matrix(ZZ, [i[k - 1] for i in L[k:]]).smith_form()[2].transpose() U = identity_matrix(ZZ, k).block_sum(sm) - L = U*L + L = U * L L[k] = -L[k] if L[-1][-2] > 0: L[-1] = -L[-1] - for k in range(M.nrows()-2, -1, -1): - for i in range(k+2, M.nrows()): - while L[k][i-1] > 0: + for k in range(M.nrows() - 2, -1, -1): + for i in range(k + 2, M.nrows()): + while L[k][i - 1] > 0: L[k] = L[k] + L[i] - v = -L[k+1] - for i in range(k+2, M.nrows()): - v = abs(L[i, i-1])*v + v[i-1]*L[i] + v = -L[k + 1] + for i in range(k + 2, M.nrows()): + v = abs(L[i, i - 1]) * v + v[i - 1] * L[i] while L[k, k] <= 0 or L[k, -1] > 0: L[k] = L[k] + v return L diff --git a/src/sage/sat/all.py b/src/sage/sat/all.py index ad1a0ec2c14..0ee0b255a83 100644 --- a/src/sage/sat/all.py +++ b/src/sage/sat/all.py @@ -1,3 +1,4 @@ from sage.misc.lazy_import import lazy_import + lazy_import('sage.sat.solvers.satsolver', 'SAT') del lazy_import diff --git a/src/sage/sat/boolean_polynomials.py b/src/sage/sat/boolean_polynomials.py index 1699e728608..dc59c8a25c6 100644 --- a/src/sage/sat/boolean_polynomials.py +++ b/src/sage/sat/boolean_polynomials.py @@ -245,8 +245,7 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): from sage.sat.solvers import CryptoMiniSat as solver if not isinstance(solver, SatSolver): - solver_kwds = {k[2:]: v for k, v in kwds.items() - if k.startswith("s_")} + solver_kwds = {k[2:]: v for k, v in kwds.items() if k.startswith("s_")} solver = solver(**solver_kwds) @@ -256,8 +255,7 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): from sage.sat.converters.polybori import CNFEncoder as converter if not isinstance(converter, ANF2CNFConverter): - converter_kwds = {k[2:]: v for k, v in kwds.items() - if k.startswith("c_")} + converter_kwds = {k[2:]: v for k, v in kwds.items() if k.startswith("c_")} converter = converter(solver, P, **converter_kwds) @@ -358,8 +356,7 @@ def learn(F, converter=None, solver=None, max_learnt_length=3, interreduction=Fa if solver is None: from sage.sat.solvers.cryptominisat import CryptoMiniSat as solver - solver_kwds = {k[2:]: v for k, v in kwds.items() - if k.startswith("s_")} + solver_kwds = {k[2:]: v for k, v in kwds.items() if k.startswith("s_")} solver = solver(**solver_kwds) @@ -368,8 +365,7 @@ def learn(F, converter=None, solver=None, max_learnt_length=3, interreduction=Fa if converter is None: from sage.sat.converters.polybori import CNFEncoder as converter - converter_kwds = {k[2:]: v for k, v in kwds.items() - if k.startswith("c_")} + converter_kwds = {k[2:]: v for k, v in kwds.items() if k.startswith("c_")} converter = converter(solver, P, **converter_kwds) diff --git a/src/sage/sat/converters/polybori.py b/src/sage/sat/converters/polybori.py index f346e10a788..30fd586f873 100644 --- a/src/sage/sat/converters/polybori.py +++ b/src/sage/sat/converters/polybori.py @@ -56,6 +56,7 @@ class CNFEncoder(ANF2CNFConverter): .. automethod:: __init__ .. automethod:: __call__ """ + def __init__(self, solver, ring, max_vars_sparse=6, use_xor_clauses=None, cutting_number=6, random_seed=16): """ Construct ANF to CNF converter over ``ring`` passing clauses to ``solver``. @@ -280,16 +281,13 @@ def clauses_sparse(self, f): # any zero block of f+1 blocks = self.zero_blocks(f + 1) - C = [{variable: 1 - value for variable, value in b.items()} - for b in blocks] + C = [{variable: 1 - value for variable, value in b.items()} for b in blocks] def to_dimacs_index(v): return v.index() + 1 def clause(c): - return [to_dimacs_index(variable) - if value == 1 else -to_dimacs_index(variable) - for variable, value in c.items()] + return [to_dimacs_index(variable) if value == 1 else -to_dimacs_index(variable) for variable, value in c.items()] data = (clause(c) for c in C) for d in sorted(data): @@ -329,7 +327,7 @@ def clauses_dense(self, f): """ equal_zero = not bool(f.constant_coefficient()) - f = (f - f.constant_coefficient()) + f = f - f.constant_coefficient() f = [self.monomial(m) for m in f] if self.use_xor_clauses: @@ -466,12 +464,12 @@ def split_xor(self, monomial_list, equal_zero): c = self.cutting_number nm = len(monomial_list) - step = ceil((c-2)/ZZ(nm) * nm) + step = ceil((c - 2) / ZZ(nm) * nm) M = [] new_variables = [] for j in range(0, nm, step): - m = new_variables + monomial_list[j:j+step] + m = new_variables + monomial_list[j : j + step] if (j + step) < nm: new_variables = [self.var(None)] m += new_variables diff --git a/src/sage/sat/solvers/cryptominisat.py b/src/sage/sat/solvers/cryptominisat.py index ad3b9cce6fc..93302083a8b 100644 --- a/src/sage/sat/solvers/cryptominisat.py +++ b/src/sage/sat/solvers/cryptominisat.py @@ -47,6 +47,7 @@ class CryptoMiniSat(SatSolver): sage: from sage.sat.solvers.cryptominisat import CryptoMiniSat sage: solver = CryptoMiniSat() """ + def __init__(self, verbosity=0, confl_limit=None, threads=None) -> None: r""" Construct a new CryptoMiniSat instance. @@ -61,13 +62,13 @@ def __init__(self, verbosity=0, confl_limit=None, threads=None) -> None: """ if threads is None: from sage.parallel.ncpus import ncpus + threads = ncpus() if confl_limit is None: from sys import maxsize + confl_limit = maxsize - self._solver = Solver(verbose=int(verbosity), - confl_limit=int(confl_limit), - threads=int(threads)) + self._solver = Solver(verbose=int(verbosity), confl_limit=int(confl_limit), threads=int(threads)) self._nvars = 0 self._clauses = [] @@ -292,4 +293,5 @@ def clauses(self, filename=None): if filename is None: return self._clauses from sage.sat.solvers.dimacs import DIMACS + DIMACS.render_dimacs(self._clauses, filename, self.nvars()) diff --git a/src/sage/sat/solvers/dimacs.py b/src/sage/sat/solvers/dimacs.py index 6fd46776d02..a61fb82e35f 100644 --- a/src/sage/sat/solvers/dimacs.py +++ b/src/sage/sat/solvers/dimacs.py @@ -21,6 +21,7 @@ Classes and Methods ------------------- """ + ############################################################################## # Copyright (C) 2012 Martin Albrecht # Distributed under the terms of the GNU General Public License (GPL) @@ -573,6 +574,7 @@ class RSat(DIMACS): sage: solver() # optional - rsat False """ + command = "rsat {input} -v -s" @@ -638,6 +640,7 @@ class Glucose(DIMACS): s SATISFIABLE v -1 -2 ... 100 0 """ + command = "glucose -verb=0 -model {input}" @@ -702,6 +705,7 @@ class GlucoseSyrup(DIMACS): s SATISFIABLE v -1 -2 ... 100 0 """ + command = "glucose-syrup -model -verb=0 {input}" diff --git a/src/sage/sat/solvers/picosat.py b/src/sage/sat/solvers/picosat.py index d9d73abcf97..887f1035244 100644 --- a/src/sage/sat/solvers/picosat.py +++ b/src/sage/sat/solvers/picosat.py @@ -40,6 +40,7 @@ class PicoSAT(SatSolver): sage: from sage.sat.solvers.picosat import PicoSAT sage: solver = PicoSAT() # optional - pycosat """ + def __init__(self, verbosity=0, prop_limit=0): r""" Construct a new PicoSAT instance. @@ -161,8 +162,7 @@ def __call__(self, assumptions=None): """ # import pycosat # self._solve = pycosat.solve - sol = self._solve(self._clauses, verbose=self._verbosity, - prop_limit=self._prop_limit, vars=self._nvars) + sol = self._solve(self._clauses, verbose=self._verbosity, prop_limit=self._prop_limit, vars=self._nvars) # sol = pycosat.solve(self._clauses) if sol == 'UNSAT': return False @@ -222,4 +222,5 @@ def clauses(self, filename=None): if filename is None: return self._clauses from sage.sat.solvers.dimacs import DIMACS + DIMACS.render_dimacs(self._clauses, filename, self.nvars()) diff --git a/src/sage/sat/solvers/sat_lp.py b/src/sage/sat/solvers/sat_lp.py index a4c7eb60e71..bf000d2f963 100644 --- a/src/sage/sat/solvers/sat_lp.py +++ b/src/sage/sat/solvers/sat_lp.py @@ -103,8 +103,7 @@ def add_clause(self, lits): if 0 in lits: raise ValueError("0 should not appear in the clause: {}".format(lits)) p = self._LP - p.add_constraint(p.sum(self._vars[x] if x > 0 else 1-self._vars[-x] for x in lits) - >= 1) + p.add_constraint(p.sum(self._vars[x] if x > 0 else 1 - self._vars[-x] for x in lits) >= 1) def __call__(self): """ diff --git a/src/sage/schemes/affine/affine_homset.py b/src/sage/schemes/affine/affine_homset.py index 5927a777db4..6a9663faf17 100644 --- a/src/sage/schemes/affine/affine_homset.py +++ b/src/sage/schemes/affine/affine_homset.py @@ -48,6 +48,7 @@ # Affine varieties # ******************************************************************* + class SchemeHomset_points_spec(SchemeHomset_generic): """ Set of rational points of an affine variety. @@ -62,6 +63,7 @@ class SchemeHomset_points_spec(SchemeHomset_generic): sage: SchemeHomset_points_spec(Spec(QQ), Spec(QQ)) Set of rational points of Spectrum of Rational Field """ + def _element_constructor_(self, *args, **kwds): """ The element constructor. @@ -115,6 +117,7 @@ class SchemeHomset_polynomial_affine_space(SchemeHomset_generic): From: Affine Space of dimension 2 over Rational Field To: Affine Space of dimension 2 over Rational Field """ + def identity(self): """ The identity morphism of this homset. @@ -132,6 +135,7 @@ def identity(self): """ if self.is_endomorphism_set(): from sage.schemes.generic.morphism import SchemeMorphism_polynomial_id + return SchemeMorphism_polynomial_id(self.domain()) raise TypeError("identity map is only defined for endomorphisms") @@ -140,6 +144,7 @@ def identity(self): # Affine varieties # ******************************************************************* + class SchemeHomset_points_affine(SchemeHomset_points): """ Set of rational points of an affine variety. @@ -263,7 +268,8 @@ def points(self, **kwds): numerical = True verbose("Warning: computations in the numerical fields are inexact;points may be computed partially or incorrectly.", level=0) from sage.rings.real_mpfr import RR - zero_tol = RR(kwds.pop('zero_tolerance', 10**(-10))) + + zero_tol = RR(kwds.pop('zero_tolerance', 10 ** (-10))) if zero_tol <= 0: raise ValueError("tolerance must be positive") else: @@ -307,8 +313,8 @@ def points(self, **kwds): good = 1 else: L = L.factor() - # the linear factors give the possible rational values of - # this coordinate + # the linear factors give the possible rational values of + # this coordinate for pol, pow in L: if pol.degree() == 1 and len(pol.variables()) == 1: good = 1 @@ -316,8 +322,7 @@ def points(self, **kwds): varindex = R.gens().index(r) # add this coordinates information to # each dictionary entry - P.update({R.gen(varindex): - -pol.constant_coefficient() / pol.monomial_coefficient(r)}) + P.update({R.gen(varindex): -pol.constant_coefficient() / pol.monomial_coefficient(r)}) new_points.append(copy(P)) else: new_points.append(P) @@ -348,14 +353,17 @@ def points(self, **kwds): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.affine.affine_rational_point import enum_affine_rational_field + return enum_affine_rational_field(self, B) if R in NumberFields(): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.affine.affine_rational_point import enum_affine_number_field + return enum_affine_number_field(self, bound=B, tolerance=tol, precision=prec) if isinstance(R, FiniteField): from sage.schemes.affine.affine_rational_point import enum_affine_finite_field + return enum_affine_finite_field(self) raise TypeError("unable to enumerate points over %s" % R) @@ -431,6 +439,7 @@ def numerical_points(self, F=None, **kwds): ValueError: tolerance must be positive """ from sage.schemes.affine.affine_space import AffineSpace_generic + if F is None: from sage.rings.cc import CC as F if F not in Fields() or not hasattr(F, 'precision'): @@ -450,7 +459,8 @@ def numerical_points(self, F=None, **kwds): # if X zero-dimensional from sage.rings.real_mpfr import RR - zero_tol = RR(kwds.pop('zero_tolerance', 10**(-10))) + + zero_tol = RR(kwds.pop('zero_tolerance', 10 ** (-10))) if zero_tol <= 0: raise ValueError("tolerance must be positive") rat_points = [] @@ -482,8 +492,7 @@ def numerical_points(self, F=None, **kwds): r = L.variables()[0] var = RF.gen(RF.gens().index(r)) - for pol in L.univariate_polynomial().roots(ring=F, - multiplicities=False): + for pol in L.univariate_polynomial().roots(ring=F, multiplicities=False): P[var] = pol new_points.append(copy(P)) good = True diff --git a/src/sage/schemes/affine/affine_morphism.py b/src/sage/schemes/affine/affine_morphism.py index 614e927b0d9..7150efca79b 100644 --- a/src/sage/schemes/affine/affine_morphism.py +++ b/src/sage/schemes/affine/affine_morphism.py @@ -89,6 +89,7 @@ class SchemeMorphism_polynomial_affine_space(SchemeMorphism_polynomial): To: Projective Space of dimension 2 over Rational Field Defn: Defined on coordinates by sending (x, y) to (x : y : 1) """ + def __init__(self, parent, polys, check=True): r""" Initialize. @@ -254,6 +255,7 @@ def __call__(self, x, check=True): (a + 1, a) """ from sage.schemes.affine.affine_point import SchemeMorphism_point_affine + if check: if not isinstance(x, SchemeMorphism_point_affine) or self.domain() != x.codomain(): try: @@ -373,16 +375,12 @@ def _fastpolys(self): if self._is_prime_finite_field: prime = polys[0].base_ring().characteristic() degree = max(poly_numerator.degree(), poly_denominator.degree()) - height = max([abs(c.lift()) - for c in poly_numerator.coefficients()] - + [abs(c.lift()) - for c in poly_denominator.coefficients()]) - num_terms = max(len(poly_numerator.coefficients()), - len(poly_denominator.coefficients())) + height = max([abs(c.lift()) for c in poly_numerator.coefficients()] + [abs(c.lift()) for c in poly_denominator.coefficients()]) + num_terms = max(len(poly_numerator.coefficients()), len(poly_denominator.coefficients())) largest_value = num_terms * height * (prime - 1) ** degree # If the calculations will not overflow the float data type use domain float # Else use domain integer - if largest_value < (2 ** sys.float_info.mant_dig): + if largest_value < (2**sys.float_info.mant_dig): fastpolys[0].append(fast_callable(poly_numerator, domain=float)) fastpolys[1].append(fast_callable(poly_denominator, domain=float)) else: @@ -601,12 +599,12 @@ def homogenize(self, n): if self.codomain().is_projective(): L = [self[i].denominator() for i in range(M + 1)] - l = [prod(L[:j] + L[j + 1:M + 1]) for j in range(M + 1)] + l = [prod(L[:j] + L[j + 1 : M + 1]) for j in range(M + 1)] F = [S(R(self[i].numerator() * l[i]).subs(D)) for i in range(M + 1)] else: # clear the denominators if a rational function L = [self[i].denominator() for i in range(M)] - l = [prod(L[:j] + L[j + 1:M]) for j in range(M)] + l = [prod(L[:j] + L[j + 1 : M]) for j in range(M)] F = [S(R(self[i].numerator() * l[i]).subs(D)) for i in range(M)] F.insert(ind[1], S(R(prod(L)).subs(D))) # coerce in case l is a constant @@ -622,7 +620,7 @@ def homogenize(self, n): # homogenize d = max([F[i].degree() for i in range(M + 1)]) - F = [F[i].homogenize(str(newvar)) * newvar**(d - F[i].degree()) for i in range(M + 1)] + F = [F[i].homogenize(str(newvar)) * newvar ** (d - F[i].degree()) for i in range(M + 1)] return H(F) @@ -665,6 +663,7 @@ def as_dynamical_system(self): True """ from sage.dynamics.arithmetic_dynamics.generic_ds import DynamicalSystem + if isinstance(self, DynamicalSystem): return self if not self.domain() == self.codomain(): @@ -672,6 +671,7 @@ def as_dynamical_system(self): from sage.dynamics.arithmetic_dynamics.affine_ds import DynamicalSystem_affine from sage.dynamics.arithmetic_dynamics.affine_ds import DynamicalSystem_affine_field from sage.dynamics.arithmetic_dynamics.affine_ds import DynamicalSystem_affine_finite_field + R = self.base_ring() if R not in _Fields: return DynamicalSystem_affine(list(self), self.domain()) @@ -1206,12 +1206,9 @@ def reduce_base_field(self): """ g = self.homogenize(0).reduce_base_field().dehomogenize(0) from sage.schemes.affine.affine_space import AffineSpace - new_domain = AffineSpace(g.domain().base_ring(), - self.domain().dimension_relative(), - self.domain().variable_names()) - new_codomain = AffineSpace(g.codomain().base_ring(), - self.codomain().dimension_relative(), - self.codomain().variable_names()) + + new_domain = AffineSpace(g.domain().base_ring(), self.domain().dimension_relative(), self.domain().variable_names()) + new_codomain = AffineSpace(g.codomain().base_ring(), self.codomain().dimension_relative(), self.codomain().variable_names()) R = new_domain.coordinate_ring() H = Hom(new_domain, new_codomain) if isinstance(g[0], FractionFieldElement): @@ -1369,6 +1366,7 @@ class SchemeMorphism_polynomial_affine_subscheme_field(SchemeMorphism_polynomial """ Morphisms from subschemes of affine spaces defined over fields. """ + @cached_method def representatives(self): """ diff --git a/src/sage/schemes/affine/affine_point.py b/src/sage/schemes/affine/affine_point.py index a5fbef5da54..46378e5dbc7 100644 --- a/src/sage/schemes/affine/affine_point.py +++ b/src/sage/schemes/affine/affine_point.py @@ -34,6 +34,7 @@ # coordinates. # -------------------------------------------------------------------- + class SchemeMorphism_point_affine(SchemeMorphism_point): """ A rational point on an affine scheme. @@ -53,6 +54,7 @@ class SchemeMorphism_point_affine(SchemeMorphism_point): sage: A(1, 2) (1, 2) """ + def __init__(self, X, v, check=True): """ The Python constructor. @@ -69,6 +71,7 @@ def __init__(self, X, v, check=True): SchemeMorphism.__init__(self, X) if check: from sage.categories.commutative_rings import CommutativeRings + if isinstance(v, SchemeMorphism): v = list(v) else: @@ -194,6 +197,7 @@ def global_height(self, prec=None): """ if self.domain().base_ring() == ZZ: from sage.rings.real_mpfr import RealField + if prec is None: R = RealField() else: @@ -315,6 +319,7 @@ def weil_restriction(self): return self # create a CoordinateFunction that gets the relative coordinates in terms of powers from sage.rings.number_field.number_field_element import CoordinateFunction + v = L.gen() V, from_V, to_V = L.relative_vector_space() h = L(1) @@ -367,6 +372,7 @@ def intersection_multiplicity(self, X): TypeError: this point must be a point on an affine subscheme """ from sage.schemes.affine.affine_space import AffineSpace_generic + if isinstance(self.codomain(), AffineSpace_generic): raise TypeError("this point must be a point on an affine subscheme") return self.codomain().intersection_multiplicity(X, self) @@ -392,6 +398,7 @@ def multiplicity(self): 2 """ from sage.schemes.affine.affine_space import AffineSpace_generic + if isinstance(self.codomain(), AffineSpace_generic): raise TypeError("this point must be a point on an affine subscheme") return self.codomain().multiplicity(self) diff --git a/src/sage/schemes/affine/affine_rational_point.py b/src/sage/schemes/affine/affine_rational_point.py index 034637c8862..b30a72cf80a 100644 --- a/src/sage/schemes/affine/affine_rational_point.py +++ b/src/sage/schemes/affine/affine_rational_point.py @@ -108,6 +108,7 @@ def enum_affine_rational_field(X, B): - Raman Raghukul 2018: updated. """ from sage.schemes.affine.affine_space import AffineSpace_generic + if isinstance(X, Scheme): if not isinstance(X.ambient_space(), AffineSpace_generic): raise TypeError("ambient space must be affine space over the rational field") @@ -213,6 +214,7 @@ def enum_affine_number_field(X, **kwds): tol = kwds.pop('tolerance', 1e-2) prec = kwds.pop('precision', 53) from sage.schemes.affine.affine_space import AffineSpace_generic + if isinstance(X, Scheme): if not isinstance(X.ambient_space(), AffineSpace_generic): raise TypeError("ambient space must be affine space over a number field") @@ -287,6 +289,7 @@ def enum_affine_finite_field(X): - John Cremona and Charlie Turner (06-2010) """ from sage.schemes.affine.affine_space import AffineSpace_generic + if isinstance(X, Scheme): if not isinstance(X.ambient_space(), AffineSpace_generic): raise TypeError("ambient space must be affine space over a finite field") diff --git a/src/sage/schemes/affine/affine_space.py b/src/sage/schemes/affine/affine_space.py index 040483232ed..88245bd0a80 100644 --- a/src/sage/schemes/affine/affine_space.py +++ b/src/sage/schemes/affine/affine_space.py @@ -25,21 +25,15 @@ from sage.structure.category_object import normalize_names from sage.schemes.generic.scheme import AffineScheme from sage.schemes.generic.ambient_space import AmbientSpace -from sage.schemes.affine.affine_homset import (SchemeHomset_points_affine, - SchemeHomset_polynomial_affine_space) -from sage.schemes.affine.affine_morphism import (SchemeMorphism_polynomial_affine_space, - SchemeMorphism_polynomial_affine_space_field, - SchemeMorphism_polynomial_affine_space_finite_field) -from sage.schemes.affine.affine_point import (SchemeMorphism_point_affine, - SchemeMorphism_point_affine_field, - SchemeMorphism_point_affine_finite_field) +from sage.schemes.affine.affine_homset import SchemeHomset_points_affine, SchemeHomset_polynomial_affine_space +from sage.schemes.affine.affine_morphism import SchemeMorphism_polynomial_affine_space, SchemeMorphism_polynomial_affine_space_field, SchemeMorphism_polynomial_affine_space_finite_field +from sage.schemes.affine.affine_point import SchemeMorphism_point_affine, SchemeMorphism_point_affine_field, SchemeMorphism_point_affine_finite_field from sage.misc.persist import register_unpickle_override _Fields = Fields() -def AffineSpace(n, R=None, names=None, ambient_projective_space=None, - default_embedding_index=None): +def AffineSpace(n, R=None, names=None, ambient_projective_space=None, default_embedding_index=None): r""" Return affine space of dimension ``n`` over the ring ``R``. @@ -111,13 +105,12 @@ def AffineSpace(n, R=None, names=None, ambient_projective_space=None, names = normalize_names(n, names) if default_embedding_index is not None and ambient_projective_space is None: from sage.schemes.projective.projective_space import ProjectiveSpace + ambient_projective_space = ProjectiveSpace(n, R) if R in _Fields: if isinstance(R, FiniteField): - return AffineSpace_finite_field(n, R, names, - ambient_projective_space, default_embedding_index) - return AffineSpace_field(n, R, names, - ambient_projective_space, default_embedding_index) + return AffineSpace_finite_field(n, R, names, ambient_projective_space, default_embedding_index) + return AffineSpace_field(n, R, names, ambient_projective_space, default_embedding_index) return AffineSpace_generic(n, R, names, ambient_projective_space, default_embedding_index) @@ -161,6 +154,7 @@ class AffineSpace_generic(AmbientSpace, AffineScheme): sage: AffineSpace(0) Affine Space of dimension 0 over Integer Ring """ + def __init__(self, n, R, names, ambient_projective_space, default_embedding_index): """ EXAMPLES:: @@ -273,8 +267,7 @@ def __eq__(self, right): """ if not isinstance(right, AffineSpace_generic): return False - return (self.dimension_relative() == right.dimension_relative() and - self.coordinate_ring() == right.coordinate_ring()) + return self.dimension_relative() == right.dimension_relative() and self.coordinate_ring() == right.coordinate_ring() def __ne__(self, other): """ @@ -493,6 +486,7 @@ def _check_satisfies_equations(self, v): raise TypeError('the list v=%s must have %s components' % (v, n)) R = self.base_ring() from sage.structure.sequence import Sequence + if not Sequence(v).universe() == R: raise TypeError('the components of v=%s must be elements of %s' % (v, R)) return True @@ -576,8 +570,7 @@ def __mul__(self, right): if isinstance(right, AffineSpace_generic): if self is right: return self.__pow__(2) - return AffineSpace(self.dimension_relative() + right.dimension_relative(), - self.base_ring(), self.variable_names() + right.variable_names()) + return AffineSpace(self.dimension_relative() + right.dimension_relative(), self.base_ring(), self.variable_names() + right.variable_names()) if isinstance(right, AlgebraicScheme_subscheme): AS = self * right.ambient_space() CR = AS.coordinate_ring() @@ -585,8 +578,7 @@ def __mul__(self, right): phi = self.ambient_space().coordinate_ring().hom(list(CR.gens()[:n]), CR) psi = right.ambient_space().coordinate_ring().hom(list(CR.gens()[n:]), CR) - return AS.subscheme([phi(t) for t in self.defining_polynomials()] + - [psi(t) for t in right.defining_polynomials()]) + return AS.subscheme([phi(t) for t in self.defining_polynomials()] + [psi(t) for t in right.defining_polynomials()]) raise TypeError('%s must be an affine space or affine subscheme' % right) @@ -641,9 +633,7 @@ def coordinate_ring(self): return self._coordinate_ring except AttributeError: pass - self._coordinate_ring = PolynomialRing(self.base_ring(), - self.dimension_relative(), - names=self.variable_names()) + self._coordinate_ring = PolynomialRing(self.base_ring(), self.dimension_relative(), names=self.variable_names()) return self._coordinate_ring def _validate(self, polynomials): @@ -748,6 +738,7 @@ def projective_embedding(self, i=None, PP=None): PP = self._ambient_projective_space else: from sage.schemes.projective.projective_space import ProjectiveSpace + PP = ProjectiveSpace(n, self.base_ring()) elif PP.dimension_relative() != n: raise ValueError("projective Space must be of dimension %s" % (n)) @@ -804,8 +795,7 @@ def subscheme(self, X, **kwds): sage: X.dimension() 0 """ - from sage.schemes.affine.affine_subscheme import (AlgebraicScheme_subscheme_affine, - AlgebraicScheme_subscheme_affine_field) + from sage.schemes.affine.affine_subscheme import AlgebraicScheme_subscheme_affine, AlgebraicScheme_subscheme_affine_field if self.base_ring().is_field(): return AlgebraicScheme_subscheme_affine_field(self, X, **kwds) @@ -1034,7 +1024,7 @@ def points_of_bounded_height(self, **kwds): else: raise NotImplementedError("self must be affine space over a number field.") bound = kwds.pop('bound') - B = bound**self.base_ring().absolute_degree() # convert to relative height + B = bound ** self.base_ring().absolute_degree() # convert to relative height n = self.dimension_relative() R = self.base_ring() @@ -1124,6 +1114,7 @@ def curve(self, F): Affine Curve over Rational Field defined by -x^4 + y, -y^5 + z """ from sage.schemes.curves.constructor import Curve + return Curve(F, self) def line_through(self, p, q): @@ -1233,6 +1224,4 @@ def _morphism(self, *args, **kwds): # fix the pickles from moving affine_space.py -register_unpickle_override('sage.schemes.generic.affine_space', - 'AffineSpace_generic', - AffineSpace_generic) +register_unpickle_override('sage.schemes.generic.affine_space', 'AffineSpace_generic', AffineSpace_generic) diff --git a/src/sage/schemes/affine/affine_subscheme.py b/src/sage/schemes/affine/affine_subscheme.py index 4ba5011bdd6..f8fb3f21d2d 100644 --- a/src/sage/schemes/affine/affine_subscheme.py +++ b/src/sage/schemes/affine/affine_subscheme.py @@ -50,8 +50,8 @@ class AlgebraicScheme_subscheme_affine(AlgebraicScheme_subscheme): Closed subscheme of Affine Space of dimension 3 over Rational Field defined by: x^2 - y*z """ - def __init__(self, A, polynomials, embedding_center=None, - embedding_codomain=None, embedding_images=None): + + def __init__(self, A, polynomials, embedding_center=None, embedding_codomain=None, embedding_images=None): """ EXAMPLES:: @@ -62,11 +62,9 @@ def __init__(self, A, polynomials, embedding_center=None, """ AlgebraicScheme_subscheme.__init__(self, A, polynomials) if embedding_images is not None: - self._embedding_morphism = self.hom(embedding_images, - embedding_codomain) + self._embedding_morphism = self.hom(embedding_images, embedding_codomain) elif A._ambient_projective_space is not None: - self._embedding_morphism = self.projective_embedding( - A._default_embedding_index, A._ambient_projective_space) + self._embedding_morphism = self.projective_embedding(A._default_embedding_index, A._ambient_projective_space) if embedding_center is not None: self._embedding_center = self.point(embedding_center) @@ -328,7 +326,7 @@ def is_smooth(self, point=None) -> bool: except AttributeError: pass sing_dim = self.Jacobian().dimension() - self._smooth = (sing_dim == -1) + self._smooth = sing_dim == -1 return self._smooth def intersection_multiplicity(self, X, P): @@ -416,12 +414,13 @@ def intersection_multiplicity(self, X, P): Jloc = R.ideal([f(chng_coords) for f in J.gens()]) # compute the intersection multiplicity with Serre's Tor formula using Singular from sage.interfaces.singular import singular + singular.lib("homolog.lib") i = 0 s = 0 t = sum(singular.Tor(i, Iloc, Jloc).std().hilb(2).sage()) while t != 0: - s += (-1)**i * t + s += (-1) ** i * t i += 1 t = sum(singular.Tor(i, Iloc, Jloc).std().hilb(2).sage()) return s @@ -504,6 +503,7 @@ class AlgebraicScheme_subscheme_affine_field(AlgebraicScheme_subscheme_affine): """ Algebraic subschemes of projective spaces defined over fields. """ + def _morphism(self, *args, **kwds): r""" Construct a morphism determined by action on points of ``self``. diff --git a/src/sage/schemes/berkovich/berkovich_cp_element.py b/src/sage/schemes/berkovich/berkovich_cp_element.py index e2dd15cac86..6e53f63b6bc 100644 --- a/src/sage/schemes/berkovich/berkovich_cp_element.py +++ b/src/sage/schemes/berkovich/berkovich_cp_element.py @@ -55,6 +55,7 @@ class Berkovich_Element(Element): """ The parent class for any element of a Berkovich space. """ + pass @@ -89,6 +90,7 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= """ from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.fraction_field_element import FractionFieldElement_1poly_field + self._type = None # if radius is a list or a tuple, this is a type 4 point @@ -97,9 +99,7 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= if not isinstance(center, (list, tuple)): raise TypeError("center was passed a list but radius was not a list") if len(radius) != len(center): - raise ValueError("the same number of centers and radii " - "must be specified to create " - "a type IV point") + raise ValueError("the same number of centers and radii " "must be specified to create " "a type IV point") self._center_lst = list(center) self._radius_lst = list(radius) self._prec = len(self._radius_lst) @@ -113,6 +113,7 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= elif isinstance(center, Element) and isinstance(radius, Element): from sage.rings.polynomial.multi_polynomial import MPolynomial + if isinstance(center, MPolynomial): try: center = center.univariate_polynomial() @@ -120,10 +121,8 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= raise TypeError('center was %s, a multivariable polynomial' % center) # check if the radius and the center are functions - center_func_check = center.parent() in FunctionFields() or \ - isinstance(center, (Polynomial, FractionFieldElement_1poly_field, Expression)) - radius_func_check = radius.parent() in FunctionFields() or \ - isinstance(radius, (Polynomial, FractionFieldElement_1poly_field, Expression)) + center_func_check = center.parent() in FunctionFields() or isinstance(center, (Polynomial, FractionFieldElement_1poly_field, Expression)) + radius_func_check = radius.parent() in FunctionFields() or isinstance(radius, (Polynomial, FractionFieldElement_1poly_field, Expression)) if center_func_check: # check that both center and radii are supported univariate function @@ -132,8 +131,7 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= if error_check: if isinstance(center, Expression): if len(center.variables()) != 1: - raise ValueError("an expression with %s " % (len(center.variables())) + - "variables cannot define the centers approximating a type IV point") + raise ValueError("an expression with %s " % (len(center.variables())) + "variables cannot define the centers approximating a type IV point") else: # we do this since .subs is currently buggy for polynomials but not expressions center_expr_check = True @@ -141,8 +139,7 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= raise TypeError("center was passed a function but radius was not a function") if isinstance(radius, Expression): if len(radius.variables()) != 1: - raise ValueError("an expression with %s " % (len(radius.variables())) + - "variables cannot define the radii approximating a type IV point") + raise ValueError("an expression with %s " % (len(radius.variables())) + "variables cannot define the radii approximating a type IV point") else: radius_expr_check = True else: @@ -201,19 +198,16 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= # we convert to scheme over a padic field center = ProjectiveSpace(center.scheme().base_ring().fraction_field(), 1)(center) if center.scheme().base_ring().prime() != self._p: - raise ValueError("center must be an element of " + - "%s not %s" % self._base_space, center.scheme()) + raise ValueError("center must be an element of " + "%s not %s" % self._base_space, center.scheme()) elif center not in self._base_space: try: center = (self._base_space)(center) except (TypeError, ValueError): raise ValueError('could not convert %s to %s' % (center, self._base_space)) if center.scheme().ambient_space() != center.scheme(): - raise ValueError("the center of a point of Berkovich space over " + - "P^1(Cp(%s)) must be a point of Cp not %s" % (self._p, center.scheme())) + raise ValueError("the center of a point of Berkovich space over " + "P^1(Cp(%s)) must be a point of Cp not %s" % (self._p, center.scheme())) if center == (center.scheme())((1, 0)): - raise ValueError("the center of a disk approximating a type IV point of Berkovich " + - "space cannot be centered at %s" % ((center.scheme())((1, 0)))) + raise ValueError("the center of a disk approximating a type IV point of Berkovich " + "space cannot be centered at %s" % ((center.scheme())((1, 0)))) # since we are over a field, we can normalize coordinates. all code assumes normalized coordinates center.normalize_coordinates() # make sure the radius coerces into the reals @@ -223,16 +217,14 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= elif RR.has_coerce_map_from(radius.parent()): radius = RR(radius) else: - raise TypeError("the radius of a disk approximating a type IV point" + - "must coerce into the real numbers, %s does not coerce" % (radius)) + raise TypeError("the radius of a disk approximating a type IV point" + "must coerce into the real numbers, %s does not coerce" % (radius)) if i != 0: # check containment for the sequence of disks previous_center = self._center_lst[i - 1] previous_radius = self._radius_lst[i - 1] dist = self._custom_abs(center[0] - previous_center[0]) if previous_radius < radius or dist > previous_radius: - raise ValueError("sequence of disks does not define a type IV point as " + - "containment is not proper") + raise ValueError("sequence of disks does not define a type IV point as " + "containment is not proper") self._center_lst[i] = center self._radius_lst[i] = radius return @@ -266,21 +258,18 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= radius = RR(radius) self._radius_lst[i] = radius else: - raise ValueError("the radius of a disk approximating a type IV point must " + - "coerce into the real numbers, %s does not coerce" % (radius)) + raise ValueError("the radius of a disk approximating a type IV point must " + "coerce into the real numbers, %s does not coerce" % (radius)) if i != 0: # check containment for the sequence of disks previous_center = self._center_lst[i - 1] previous_radius = self._radius_lst[i - 1] dist = self._custom_abs(center - previous_center) if previous_radius < radius or dist > previous_radius: - raise ValueError("sequence of disks does not define a type IV point as " + - "containment is not proper") + raise ValueError("sequence of disks does not define a type IV point as " + "containment is not proper") self._center_lst[i] = center self._radius_lst[i] = radius return - raise ValueError("bad value %s passed to space_type. Do not initialize " % (space_type) + - "Berkovich_Element_Cp directly") + raise ValueError("bad value %s passed to space_type. Do not initialize " % (space_type) + "Berkovich_Element_Cp directly") # the point must now be type 1, 2, or 3, so we check that the center is of the appropriate type if error_check: @@ -306,16 +295,14 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= except (TypeError, ValueError): raise ValueError('could not convert %s to %s' % center, field_scheme) if center.scheme().base_ring().prime() != self._p: - raise ValueError("center must be an element of " + - "%s not %s" % self._base_space, center.scheme()) + raise ValueError("center must be an element of " + "%s not %s" % self._base_space, center.scheme()) elif center not in self._base_space: try: center = (self._base_space)(center) except (TypeError, ValueError): raise ValueError('could not convert %s to %s' % (center, self._base_space)) if center.scheme().ambient_space() is not center.scheme(): - raise ValueError("the center of a point of projective Berkovich space cannot be " + - "a point of %s" % (center.scheme())) + raise ValueError("the center of a point of projective Berkovich space cannot be " + "a point of %s" % (center.scheme())) # since we are over a field, we normalize coordinates center.normalize_coordinates() elif space_type == 'affine': @@ -338,8 +325,7 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= except (TypeError, ValueError): raise ValueError('could not convert %s to %s' % (center, self._base_space)) else: - raise ValueError("bad value %s passed to space_type. Do not initialize " % (space_type) + - "Berkovich_Element_Cp directly") + raise ValueError("bad value %s passed to space_type. Do not initialize " % (space_type) + "Berkovich_Element_Cp directly") self._center = center @@ -383,8 +369,7 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= self._radius = radius except TypeError: if len(radius.variables()) == 1: - raise ValueError('radius univariate function but center is constant. ' + - 'this does not define a type IV point') + raise ValueError('radius univariate function but center is constant. ' + 'this does not define a type IV point') raise TypeError("symbolic radius must be a real number") if (not isinstance(radius, RealNumber)) and power is None: if RR.has_coerce_map_from(radius.parent()): @@ -434,8 +419,8 @@ def _custom_abs(self, x): if x.valuation(self._ideal) == Infinity: return 0 if self._ideal in QQ: - return self.prime()**(-x.valuation(self._ideal)) - return self.prime()**(-x.valuation(self._ideal) / self._ideal.absolute_ramification_index()) + return self.prime() ** (-x.valuation(self._ideal)) + return self.prime() ** (-x.valuation(self._ideal) / self._ideal.absolute_ramification_index()) def center_function(self): """ @@ -654,6 +639,7 @@ def diameter(self, basepoint=Infinity): if self._radius_func is None: return self._radius_lst[-1] from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(QQ, names='x') x = R.gens()[0] if isinstance(self._radius_func, Expression): @@ -662,6 +648,7 @@ def diameter(self, basepoint=Infinity): else: radius_expr = self._radius_func(x) from sage.symbolic.ring import SymbolicRing as SR + radius_expr = SR(RR)(radius_expr) return radius_expr.limit(x='oo') return self._radius @@ -715,9 +702,7 @@ def path_distance_metric(self, other): if self == other: return 0 return RR(Infinity) - return 2 * self.join(other).diameter().log(self.prime()) \ - - self.diameter().log(self.prime()) \ - - other.diameter().log(other.prime()) + return 2 * self.join(other).diameter().log(self.prime()) - self.diameter().log(self.prime()) - other.diameter().log(other.prime()) big_metric = path_distance_metric @@ -767,8 +752,7 @@ def Hsia_kernel(self, other, basepoint): if basepoint.type_of_point() == 1: if self == basepoint or other == basepoint: return RR(Infinity) - return self.spherical_kernel(other) / \ - (self.spherical_kernel(basepoint) * other.spherical_kernel(basepoint)) + return self.spherical_kernel(other) / (self.spherical_kernel(basepoint) * other.spherical_kernel(basepoint)) def small_metric(self, other): r""" @@ -827,8 +811,7 @@ def small_metric(self, other): new_other = other.involution_map() else: new_other = other - return 2 * new_self.join(new_other, gauss).diameter() \ - - new_self.diameter() - new_other.diameter() + return 2 * new_self.join(new_other, gauss).diameter() - new_self.diameter() - new_other.diameter() def potential_kernel(self, other, basepoint): """ @@ -911,7 +894,7 @@ def spherical_kernel(self, other): dist = gauss_point.path_distance_metric(w) if dist == Infinity: return 0 - return self.prime()**(-dist) + return self.prime() ** (-dist) def Hsia_kernel_infinity(self, other): r""" @@ -1042,20 +1025,12 @@ def _repr_(self): if self._type == 1: return "Type I point centered at " + format(self._center) if self._type == 2: - return "Type II point centered at " \ - + format(self._center) \ - + " of radius %s^%s" % (self._p, self._power) + return "Type II point centered at " + format(self._center) + " of radius %s^%s" % (self._p, self._power) if self._type == 3: - return "Type III point centered at " \ - + format(self._center) + " of radius " \ - + format(self._radius) + return "Type III point centered at " + format(self._center) + " of radius " + format(self._radius) if self._center_func is not None and self._radius_func is not None: - return "Type IV point of precision %s " % self._prec + \ - "with centers given by %s and radii given by %s"\ - % (self._center_func, self._radius_func) - return "Type IV point of precision %s, approximated " % self._prec + \ - "by disks centered at %s ... with radii %s ..." \ - % (self._center_lst[:min(self._prec, 2)], self._radius_lst[:min(self._prec, 2)]) + return "Type IV point of precision %s " % self._prec + "with centers given by %s and radii given by %s" % (self._center_func, self._radius_func) + return "Type IV point of precision %s, approximated " % self._prec + "by disks centered at %s ... with radii %s ..." % (self._center_lst[: min(self._prec, 2)], self._radius_lst[: min(self._prec, 2)]) def _latex_(self): r""" @@ -1072,13 +1047,10 @@ def _latex_(self): if self._type == 1: text = r"the point %s of } \Bold{C}_%s" % (self._center, self._p) elif self._type in [2, 3]: - text = r"the disk centered at %s of radius %s in } \Bold{C}_%s" \ - % (self._center, self._radius, self._p) + text = r"the disk centered at %s of radius %s in } \Bold{C}_%s" % (self._center, self._radius, self._p) else: - text = "the sequence of disks with centers %s } " % self._center_lst[:2] + \ - r"\ldots \text{ and radii %s } \ldots" % self._radius_lst[:2] - return r"\text{type %s Point of }" % (self._type) \ - + latex(self.parent()) + r"\text{equivalent to " + text + text = "the sequence of disks with centers %s } " % self._center_lst[:2] + r"\ldots \text{ and radii %s } \ldots" % self._radius_lst[:2] + return r"\text{type %s Point of }" % (self._type) + latex(self.parent()) + r"\text{equivalent to " + text class Berkovich_Element_Cp_Affine(Berkovich_Element_Cp): @@ -1258,8 +1230,7 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, error_check if isinstance(center, Berkovich_Element_Cp_Projective): raise TypeError('use as_affine_point to convert to affine Berkovich space') - Berkovich_Element_Cp.__init__(self, parent=parent, center=center, radius=radius, power=power, - prec=prec, space_type='affine', error_check=error_check) + Berkovich_Element_Cp.__init__(self, parent=parent, center=center, radius=radius, power=power, prec=prec, space_type='affine', error_check=error_check) def as_projective_point(self): r""" @@ -1292,6 +1263,7 @@ def as_projective_point(self): and radii given by 40.0000000000000*pi/x """ from sage.schemes.berkovich.berkovich_space import Berkovich_Cp_Projective + new_space = Berkovich_Cp_Projective(self.parent().base_ring(), self.parent().ideal()) if self.type_of_point() == 1: return new_space(self.center()) @@ -1692,7 +1664,7 @@ def involution_map(self): power = self.power() return self.parent()(ZZ(0), power=-power) return self.parent()(ZZ(0), RR(1 / radius)) - return self.parent()(1 / self.center(), RR(radius / (self._custom_abs(self.center())**2))) + return self.parent()(1 / self.center(), RR(radius / (self._custom_abs(self.center()) ** 2))) new_center_lst = [] new_radius_lst = [] @@ -1703,7 +1675,7 @@ def involution_map(self): continue else: new_center = 1 / self.center()[i] - new_radius = self.radius()[i] / (self._custom_abs(self.center()[i])**2) + new_radius = self.radius()[i] / (self._custom_abs(self.center()[i]) ** 2) new_center_lst.append(new_center) new_radius_lst.append(new_radius) if not new_center_lst: @@ -1895,8 +1867,7 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, error_check if isinstance(center, Berkovich_Element_Cp_Affine): raise TypeError('use as_projective_point to convert to projective Berkovich space') - Berkovich_Element_Cp.__init__(self, parent=parent, center=center, radius=radius, power=power, - prec=prec, space_type='projective', error_check=error_check) + Berkovich_Element_Cp.__init__(self, parent=parent, center=center, radius=radius, power=power, prec=prec, space_type='projective', error_check=error_check) def as_affine_point(self): """ @@ -1933,6 +1904,7 @@ def as_affine_point(self): if self.center()[1] == 0: raise ValueError('cannot convert infinity to affine Berkovich space') from sage.schemes.berkovich.berkovich_space import Berkovich_Cp_Affine + new_space = Berkovich_Cp_Affine(self.parent().base_ring(), self.parent().ideal()) if self.type_of_point() in [1, 2, 3]: center = self.center()[0] @@ -2345,9 +2317,7 @@ def join(self, other, basepoint=Infinity): # case where none of the points are comparable dist_b_s = self._custom_abs(self.center()[0] - basepoint.center()[0]) dist_b_o = self._custom_abs(other.center()[0] - basepoint.center()[0]) - return self.parent()(basepoint.center(), - min(max(dist_b_o, other.radius(), basepoint.radius()), - max(dist_b_s, self.radius(), basepoint.radius()))) + return self.parent()(basepoint.center(), min(max(dist_b_o, other.radius(), basepoint.radius()), max(dist_b_s, self.radius(), basepoint.radius()))) # case where self and basepoint are comparable if b_ge_s: @@ -2456,7 +2426,7 @@ def involution_map(self): power = self.power() return self.parent()(ZZ(0), power=-power) return self.parent()(ZZ(0), 1 / self.radius()) - return self.parent()(1 / self.center()[0], self.radius() / (self._custom_abs(self.center()[0])**2)) + return self.parent()(1 / self.center()[0], self.radius() / (self._custom_abs(self.center()[0]) ** 2)) new_center_lst = [] new_radius_lst = [] @@ -2467,7 +2437,7 @@ def involution_map(self): continue else: new_center = 1 / self.center()[i][0] - new_radius = self.radius()[i] / (self._custom_abs(self.center()[i][0])**2) + new_radius = self.radius()[i] / (self._custom_abs(self.center()[i][0]) ** 2) new_center_lst.append(new_center) new_radius_lst.append(new_radius) if not new_center_lst: @@ -2549,16 +2519,14 @@ def contained_in_interval(self, start, end): if self == infty: if start == zero or end == zero: return end == infty or start == infty - return (self.involution_map()).contained_in_interval(start.involution_map(), - end.involution_map()) + return (self.involution_map()).contained_in_interval(start.involution_map(), end.involution_map()) if start == infty or end == infty: if self == zero: return end == zero or start == zero if start == zero or end == zero: gauss = self.parent()(ZZ(0), ZZ(1)) return self.contained_in_interval(start, gauss) or self.contained_in_interval(gauss, end) - return self.involution_map().contained_in_interval(start.involution_map(), - end.involution_map()) + return self.involution_map().contained_in_interval(start.involution_map(), end.involution_map()) join = start.join(end) j_ge_s = join.gt(self) or join == self s_ge_start = self.gt(start) or self == start diff --git a/src/sage/schemes/berkovich/berkovich_space.py b/src/sage/schemes/berkovich/berkovich_space.py index 54205020718..9493391ac35 100644 --- a/src/sage/schemes/berkovich/berkovich_space.py +++ b/src/sage/schemes/berkovich/berkovich_space.py @@ -39,8 +39,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.schemes.affine.affine_space import AffineSpace_generic -from sage.schemes.berkovich.berkovich_cp_element import (Berkovich_Element_Cp_Affine, - Berkovich_Element_Cp_Projective) +from sage.schemes.berkovich.berkovich_cp_element import Berkovich_Element_Cp_Affine, Berkovich_Element_Cp_Projective from sage.schemes.projective.projective_space import ProjectiveSpace_ring, ProjectiveSpace from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation @@ -52,6 +51,7 @@ class Berkovich(UniqueRepresentation, Parent): """ The parent class for any Berkovich space """ + pass @@ -405,8 +405,7 @@ def __init__(self, base, ideal=None): if not isinstance(ideal, NumberFieldFractionalIdeal): raise ValueError('ideal was not an ideal of a number field') if ideal.number_field() != base: - raise ValueError('passed number field ' + - '%s but ideal was an ideal of %s' % (base, ideal.number_field())) + raise ValueError('passed number field ' + '%s but ideal was an ideal of %s' % (base, ideal.number_field())) prime = ideal.smallest_integer() else: if ideal not in QQ: @@ -420,8 +419,7 @@ def __init__(self, base, ideal=None): ideal = None self._base_type = 'padic field' else: - raise ValueError("base of Berkovich Space must be a padic field " - "or a number field") + raise ValueError("base of Berkovich Space must be a padic field " "or a number field") self._ideal = ideal self._p = prime Parent.__init__(self, base=base, category=TopologicalSpaces()) @@ -445,10 +443,8 @@ def _repr_(self): Number Field in a with defining polynomial z^2 + 1 """ if self._base_type == 'padic field': - return "Affine Berkovich line over Cp(%s) of precision %s" % (self.prime(), - self.base().precision_cap()) - return "Affine Berkovich line over Cp(%s), with base %s" % (self.prime(), - self.base()) + return "Affine Berkovich line over Cp(%s) of precision %s" % (self.prime(), self.base().precision_cap()) + return "Affine Berkovich line over Cp(%s), with base %s" % (self.prime(), self.base()) def _latex_(self): r""" @@ -599,8 +595,7 @@ def __init__(self, base, ideal=None): raise ValueError("base of projective Berkovich space must be projective space") if not isinstance(base.base_ring(), sage.rings.abc.pAdicField): if base.base_ring() not in NumberFields(): - raise ValueError("base of projective Berkovich space must be " - "projective space over Qp or a number field") + raise ValueError("base of projective Berkovich space must be " "projective space over Qp or a number field") else: if ideal is None: raise ValueError('passed a number field but not an ideal') @@ -608,8 +603,7 @@ def __init__(self, base, ideal=None): if not isinstance(ideal, NumberFieldFractionalIdeal): raise ValueError('ideal was not a number field ideal') if ideal.number_field() != base.base_ring(): - raise ValueError('passed number field ' + - '%s but ideal was an ideal of %s' % (base.base_ring(), ideal.number_field())) + raise ValueError('passed number field ' + '%s but ideal was an ideal of %s' % (base.base_ring(), ideal.number_field())) prime = ideal.smallest_integer() else: if ideal not in QQ: @@ -623,8 +617,7 @@ def __init__(self, base, ideal=None): ideal = None self._base_type = 'padic field' if base.dimension_relative() != 1: - raise ValueError("base of projective Berkovich space must be " - "projective space of dimension 1 over Qp or a number field") + raise ValueError("base of projective Berkovich space must be " "projective space of dimension 1 over Qp or a number field") self._p = prime self._ideal = ideal Parent.__init__(self, base=base, category=TopologicalSpaces()) @@ -678,10 +671,8 @@ def _repr_(self): with base Number Field in a with defining polynomial x^2 + 1 """ if self._base_type == 'padic field': - return "Projective Berkovich line over Cp(%s) of precision %s" % (self.prime(), - self.base().base_ring().precision_cap()) - return "Projective Berkovich line over Cp(%s), with base %s" % (self.prime(), - self.base().base_ring()) + return "Projective Berkovich line over Cp(%s) of precision %s" % (self.prime(), self.base().base_ring().precision_cap()) + return "Projective Berkovich line over Cp(%s), with base %s" % (self.prime(), self.base().base_ring()) def _latex_(self): r""" diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index c5be7521313..b60bf224574 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -143,8 +143,7 @@ from sage.rings.rational_field import RationalField from sage.schemes.affine.affine_space import AffineSpace, AffineSpace_generic -from sage.schemes.affine.affine_subscheme import (AlgebraicScheme_subscheme_affine, - AlgebraicScheme_subscheme_affine_field) +from sage.schemes.affine.affine_subscheme import AlgebraicScheme_subscheme_affine, AlgebraicScheme_subscheme_affine_field lazy_import('sage.interfaces.singular', 'singular') lazy_import('sage.rings.number_field.number_field', 'NumberField') @@ -152,13 +151,7 @@ from .curve import Curve_generic -from .point import (AffineCurvePoint_field, - AffinePlaneCurvePoint_field, - AffinePlaneCurvePoint_finite_field, - IntegralAffineCurvePoint, - IntegralAffineCurvePoint_finite_field, - IntegralAffinePlaneCurvePoint, - IntegralAffinePlaneCurvePoint_finite_field) +from .point import AffineCurvePoint_field, AffinePlaneCurvePoint_field, AffinePlaneCurvePoint_finite_field, IntegralAffineCurvePoint, IntegralAffineCurvePoint_finite_field, IntegralAffinePlaneCurvePoint, IntegralAffinePlaneCurvePoint_finite_field from .closed_point import IntegralAffineCurveClosedPoint @@ -269,6 +262,7 @@ def projective_closure(self, i=0, PP=None): True """ from .constructor import Curve + return Curve(AlgebraicScheme_subscheme_affine.projective_closure(self, i, PP)) @@ -400,23 +394,23 @@ def local_coordinates(self, pt, n): R0 = PolynomialRing(F, 2 * n + 2, names=[str(x), str(y), "t"] + astr) vars0 = R0.gens() t = vars0[2] - yt = y0*t**0+add([vars0[i]*t**(i-2) for i in range(3, 2*n+2)]) - xt = x0+t + yt = y0 * t**0 + add([vars0[i] * t ** (i - 2) for i in range(3, 2 * n + 2)]) + xt = x0 + t ft = f(xt, yt) S = singular - S.eval('ring s = '+str(p)+','+str(R0.gens())+',lp;') - S.eval('poly f = '+str(ft) + ';') + S.eval('ring s = ' + str(p) + ',' + str(R0.gens()) + ',lp;') + S.eval('poly f = ' + str(ft) + ';') c = S('coeffs(%s, t)' % ft) N = int(c.size()) - b = ','.join("%s[%s,1]" % (c.name(), i) for i in range(2, N//2-4)) + b = ','.join("%s[%s,1]" % (c.name(), i) for i in range(2, N // 2 - 4)) cmd = 'ideal I = ' + b S.eval(cmd) - S.eval('short=0') # print using *'s and ^'s. + S.eval('short=0') # print using *'s and ^'s. c = S.eval('slimgb(I)') d = c.split("=") d = d[1:] - d[len(d)-1] += "\n" - e = [xx[:xx.index("\n")] for xx in d] + d[len(d) - 1] += "\n" + e = [xx[: xx.index("\n")] for xx in d] vals = [] for x in e: for y in vars0: @@ -424,14 +418,14 @@ def local_coordinates(self, pt, n): if x.replace(str(y), ""): i = x.find("-") if i > 0: - vals.append([eval(x[1:i]), x[:i], F(eval(x[i+1:]))]) + vals.append([eval(x[1:i]), x[:i], F(eval(x[i + 1 :]))]) i = x.find("+") if i > 0: - vals.append([eval(x[1:i]), x[:i], -F(eval(x[i+1:]))]) + vals.append([eval(x[1:i]), x[:i], -F(eval(x[i + 1 :]))]) else: vals.append([eval(str(y)[1:]), str(y), F(0)]) vals.sort() - return [x0 + t, y0 + add(v[2] * t**(j + 1) for j, v in enumerate(vals))] + return [x0 + t, y0 + add(v[2] * t ** (j + 1) for j, v in enumerate(vals))] def plot(self, *args, **kwds): r""" @@ -668,8 +662,8 @@ def tangents(self, P, factor=True): coords = [vars[0] + P[0], vars[1] + P[1]] f = f(coords) coords = [vars[0] - P[0], vars[1] - P[1]] # coords to change back with - deriv = [f.derivative(vars[0], i).derivative(vars[1], r-i)([0, 0]) for i in range(r+1)] - T = sum([binomial(r, i)*deriv[i]*(vars[0])**i*(vars[1])**(r-i) for i in range(r+1)]) + deriv = [f.derivative(vars[0], i).derivative(vars[1], r - i)([0, 0]) for i in range(r + 1)] + T = sum([binomial(r, i) * deriv[i] * (vars[0]) ** i * (vars[1]) ** (r - i) for i in range(r + 1)]) if not factor: return [T(coords)] if isinstance(self.base_ring(), sage.rings.abc.AlgebraicField): @@ -692,11 +686,11 @@ def tangents(self, P, factor=True): if T.degree(vars[0]) > 0: T = T(vars[0], 1) roots = T.univariate_polynomial().roots() - fact.extend([vars[0] - roots[i][0]*vars[1] for i in range(len(roots))]) + fact.extend([vars[0] - roots[i][0] * vars[1] for i in range(len(roots))]) else: T = T(1, vars[1]) roots = T.univariate_polynomial().roots() - fact.extend([vars[1] - roots[i][0]*vars[0] for i in range(len(roots))]) + fact.extend([vars[1] - roots[i][0] * vars[0] for i in range(len(roots))]) return [ff(coords) for ff in fact] return [ll[0](coords) for ll in T.factor()] @@ -821,13 +815,14 @@ def rational_parameterization(self): # affine patch corresponding to the first coordinate being nonzero. Thus para[0] will not be # the zero polynomial, and dehomogenization won't change this H = Hom(A_line, C) - return H([para[1]/para[0], para[2]/para[0]]) + return H([para[1] / para[0], para[2] / para[0]]) class AffineCurve_field(AffineCurve, AlgebraicScheme_subscheme_affine_field): """ Affine curves over fields. """ + _point = AffineCurvePoint_field def __init__(self, A, X): @@ -1015,9 +1010,7 @@ def projection(self, indices, AS=None): indices = [int(i) for i in indices] # type checking indices.sort() if indices[0] < 0 or indices[-1] > n - 1: - raise ValueError("index values must be between 0 and one " - "minus the dimension of the ambient space " - "of this curve") + raise ValueError("index values must be between 0 and one " "minus the dimension of the ambient space " "of this curve") # construct the projection map if AS is None: AA2 = AffineSpace(self.base_ring(), len(indices)) @@ -1031,7 +1024,7 @@ def projection(self, indices, AS=None): removecoords.pop(indices[i]) J = self.defining_ideal().elimination_ideal(removecoords) K = Hom(AA.coordinate_ring(), AA2.coordinate_ring()) - ll = [0]*(n) + ll = [0] * (n) for i in range(len(indices)): ll[indices[i]] = AA2.gens()[i] phi = K(ll) @@ -1319,7 +1312,7 @@ def blowup(self, P=None): A = self.ambient_space() n = A.dimension_relative() if P is None: - P = A([0]*n) + P = A([0] * n) try: self(P) except TypeError: @@ -1336,8 +1329,8 @@ def blowup(self, P=None): for i in range(n): if str(A.gens()[i])[0] == 's' and len(str(A.gens()[i])) > rf: rf = len(str(A.gens()[i])) - var_names = [str(A.gens()[i]) for i in range(n)] + ['s'*rf + str(i) for i in range(n)] - R = PolynomialRing(A.base_ring(), 2*n, var_names) + var_names = [str(A.gens()[i]) for i in range(n)] + ['s' * rf + str(i) for i in range(n)] + R = PolynomialRing(A.base_ring(), 2 * n, var_names) # move the defining polynomials of this curve into R H = Hom(A.coordinate_ring(), R) psi = H([R.gens()[i] for i in range(n)]) @@ -1354,14 +1347,14 @@ def blowup(self, P=None): coords = list(R.gens()) for j in range(n): if j != i: - coords[j] = (R.gens()[i] - P[i])*R.gens()[j + n] + P[j] + coords[j] = (R.gens()[i] - P[i]) * R.gens()[j + n] + P[j] c_polys = [f(coords) for f in n_polys] - var_names = list(R.gens())[n:2*n] + var_names = list(R.gens())[n : 2 * n] var_names.pop(i) var_names.insert(0, R.gens()[i]) c_A = AffineSpace(R.base_ring(), n, var_names) H = Hom(R, c_A.coordinate_ring()) - coords = [0]*(2*n) + coords = [0] * (2 * n) coords[i] = c_A.gens()[0] t = 1 for j in range(n): @@ -1398,10 +1391,10 @@ def blowup(self, P=None): homvars = list(AA.gens()) homvars.pop(0) homvars.insert(i, 1) - coords = [(vars[0] - P[i])*homvars[j] + P[j]] + coords = [(vars[0] - P[i]) * homvars[j] + P[j]] for t in range(n): if t != j: - coords.append(homvars[t]/homvars[j]) + coords.append(homvars[t] / homvars[j]) maps.append(H(coords)) t_maps.append(maps) # create the restrictions of the projection map @@ -1411,7 +1404,7 @@ def blowup(self, P=None): H = Hom(patches[i], self) homvars = list(p_A.gens())[1:n] homvars.insert(i, 1) - coords = [(p_A.gens()[0] - P[i])*homvars[j] + P[j] for j in range(n)] + coords = [(p_A.gens()[0] - P[i]) * homvars[j] + P[j] for j in range(n)] proj_maps.append(H(coords)) return (tuple(patches), tuple(t_maps), tuple(proj_maps)) @@ -1560,6 +1553,7 @@ def resolution_of_singularities(self, extend=False): def extension(self): F = self.base_ring() from sage.rings.qqbar import QQbar + pts = self.change_ring(F.embeddings(QQbar)[0]).rational_points() L = [t for pt in pts for t in pt] K = number_field_elements_from_algebraics(L)[0] @@ -1569,7 +1563,8 @@ def extension(self): return F.embeddings(K)[0] # make sure the defining polynomial variable names are the same for K, N N = NumberField(K.defining_polynomial().parent()(F.defining_polynomial()), str(K.gen())) - return N.composite_fields(K, both_maps=True)[0][1]*F.embeddings(N)[0] + return N.composite_fields(K, both_maps=True)[0][1] * F.embeddings(N)[0] + # find the set of singular points of this curve # in the case that the base field is a number field, extend it as needed (if extend == True) C = self @@ -1592,9 +1587,7 @@ def extension(self): if C.is_smooth(): raise TypeError("this curve is already nonsingular") else: - raise TypeError("this curve has no singular points over " - "its base field. If working over " - "a number field use extend=True") + raise TypeError("this curve has no singular points over " "its base field. If working over " "a number field use extend=True") not_resolved = True t = 0 # loop through the patches and blow up each until no patch has singular points @@ -1669,8 +1662,7 @@ def extension(self): b_data = [B[0][i]] # projection map and its inverse t_pi = B[2][i] - coords = [(BC.ambient_space().gens()[j] - pts[0][j]) / (BC.ambient_space().gens()[i] - pts[0][i]) - for j in range(n)] + coords = [(BC.ambient_space().gens()[j] - pts[0][j]) / (BC.ambient_space().gens()[i] - pts[0][i]) for j in range(n)] coords.pop(i) coords.insert(0, BC.ambient_space().gens()[i]) H = Hom(BC, B[0][i]) @@ -1685,10 +1677,10 @@ def extension(self): b_data.append(L) # update transition maps of each other element of res for j in range(len(res)): - new_t_map = t_pi_inv*old_maps[j] + new_t_map = t_pi_inv * old_maps[j] res[j][1].insert(t + i, new_t_map) # create the projection map - b_data.append(pi*t_pi) + b_data.append(pi * t_pi) # singular points # translate the singular points of the parent patch (other than that which was the center of the # blow up) by the inverse of the first projection map @@ -1756,8 +1748,7 @@ def tangent_line(self, p): from sage.schemes.curves.constructor import Curve # translate to p - I0 = [poly.subs({x: x - c for x, c in zip(gens, p)}) - for poly in Tp.defining_polynomials()] + I0 = [poly.subs({x: x - c for x, c in zip(gens, p)}) for poly in Tp.defining_polynomials()] return Curve(I0, A) @@ -1766,6 +1757,7 @@ class AffinePlaneCurve_field(AffinePlaneCurve, AffineCurve_field): """ Affine plane curves over fields. """ + _point = AffinePlaneCurvePoint_field def has_vertical_asymptote(self) -> bool: @@ -1872,6 +1864,7 @@ def fundamental_group(self, simplified=True, puiseux=True): Finitely presented group < x0, x1 | > """ from sage.schemes.curves.zariski_vankampen import fundamental_group_from_braid_mon + bm = self.braid_monodromy() if not bm: f = self.defining_polynomial() @@ -1881,9 +1874,7 @@ def fundamental_group(self, simplified=True, puiseux=True): d = d0 + f0.degree(x) else: d = bm[0].parent().strands() - G = fundamental_group_from_braid_mon(bm, degree=d, - simplified=simplified, - puiseux=puiseux) + G = fundamental_group_from_braid_mon(bm, degree=d, simplified=simplified, puiseux=puiseux) if simplified: G = G.simplified() return G @@ -1926,11 +1917,12 @@ def braid_monodromy(self): NotImplementedError: the base field must have an embedding to the algebraic field """ from sage.schemes.curves.zariski_vankampen import braid_monodromy + F = self.base_ring() from sage.rings.qqbar import QQbar + if QQbar.coerce_map_from(F) is None: - raise NotImplementedError("the base field must have an embedding" - " to the algebraic field") + raise NotImplementedError("the base field must have an embedding" " to the algebraic field") f = self.defining_polynomial() return braid_monodromy(f)[0] @@ -1949,6 +1941,7 @@ def riemann_surface(self, **kwargs): with 53 bits of precision """ from sage.schemes.riemann_surfaces.riemann_surface import RiemannSurface + S = RiemannSurface(self.defining_polynomial(), **kwargs) S._curve = self return S @@ -1958,6 +1951,7 @@ class AffinePlaneCurve_finite_field(AffinePlaneCurve_field): """ Affine plane curves over finite fields. """ + _point = AffinePlaneCurvePoint_finite_field # CHECK WHAT ASSUMPTIONS ARE MADE REGARDING AFFINE VS. PROJECTIVE MODELS!!! @@ -2092,8 +2086,7 @@ def rational_points(self, algorithm='enum'): # with the expect interface could crop up. Also, this is vastly # faster (and more robust). v = singular('POINTS').sage_flattened_str_list() - pnts = [self(int(v[3*i]), int(v[3*i+1])) - for i in range(len(v)//3) if int(v[3*i+2])] + pnts = [self(int(v[3 * i]), int(v[3 * i + 1])) for i in range(len(v) // 3) if int(v[3 * i + 2])] # remove multiple points return sorted(set(pnts)) @@ -2110,6 +2103,7 @@ class IntegralAffineCurve(AffineCurve_field): """ Base class for integral affine curves. """ + _point = IntegralAffineCurvePoint _closed_point = IntegralAffineCurveClosedPoint @@ -2436,7 +2430,9 @@ def evaluate(f): while coeffs: v = v * Z + coeffs.pop()._x return FR(v) + else: + def evaluate(f): return FR(f._x) @@ -2644,7 +2640,7 @@ def place_to_closed_point(self, place): prod = 1 for i in range(R.ngens()): - prod *= coords[i]**e[i] + prod *= coords[i] ** e[i] vec = to_V(to_k(prod)) # represent as a vector mat = matrix(basis_vecs) try: @@ -2749,8 +2745,7 @@ def places_on(self, point): gs = [phi(g) for g in point.prime_ideal().gens()] fs = [g for g in gs if not g.is_zero()] f = fs.pop() - return [p for p in f.zeros() - if all(f.valuation(p) > 0 for f in fs)] + return [p for p in f.zeros() if all(f.valuation(p) > 0 for f in fs)] def parametric_representation(self, place, name=None): """ @@ -2813,6 +2808,7 @@ class IntegralAffineCurve_finite_field(IntegralAffineCurve): sage: C.function_field() Function field in z defined by z^3 + 10*x """ + _point = IntegralAffineCurvePoint_finite_field def places(self, degree=1): @@ -2926,4 +2922,5 @@ class IntegralAffinePlaneCurve_finite_field(AffinePlaneCurve_finite_field, Integ sage: C.function_field() Function field in y defined by y^5 + x*y + x^5 + 1 """ + _point = IntegralAffinePlaneCurvePoint_finite_field diff --git a/src/sage/schemes/curves/closed_point.py b/src/sage/schemes/curves/closed_point.py index 384487a4fd0..a6ea277f831 100644 --- a/src/sage/schemes/curves/closed_point.py +++ b/src/sage/schemes/curves/closed_point.py @@ -81,6 +81,7 @@ class CurveClosedPoint(SchemeTopologicalPoint_prime_ideal): """ Base class of closed points of curves. """ + pass @@ -112,6 +113,7 @@ class IntegralCurveClosedPoint(CurveClosedPoint): Point (x + 1, y + a), Point (x + 1, y + (a + 1))] """ + def __init__(self, curve, prime_ideal, degree): """ Initialize. @@ -262,6 +264,7 @@ class IntegralAffineCurveClosedPoint(IntegralCurveClosedPoint): """ Closed points of affine curves. """ + def rational_point(self): """ Return the rational point if this closed point is of degree `1`. @@ -352,6 +355,7 @@ class IntegralProjectiveCurveClosedPoint(IntegralCurveClosedPoint): """ Closed points of projective plane curves. """ + def rational_point(self): """ Return the rational point if this closed point is of degree `1`. diff --git a/src/sage/schemes/curves/constructor.py b/src/sage/schemes/curves/constructor.py index 29b6acf1108..db36e3d91ba 100644 --- a/src/sage/schemes/curves/constructor.py +++ b/src/sage/schemes/curves/constructor.py @@ -58,25 +58,9 @@ from sage.schemes.weighted_projective.weighted_projective_space import WeightedProjectiveSpace_ring from sage.schemes.plane_conics.constructor import Conic -from .projective_curve import (ProjectiveCurve, - ProjectivePlaneCurve, - ProjectiveCurve_field, - ProjectivePlaneCurve_field, - ProjectivePlaneCurve_finite_field, - IntegralProjectiveCurve, - IntegralProjectiveCurve_finite_field, - IntegralProjectivePlaneCurve, - IntegralProjectivePlaneCurve_finite_field) - -from .affine_curve import (AffineCurve, - AffinePlaneCurve, - AffineCurve_field, - AffinePlaneCurve_field, - AffinePlaneCurve_finite_field, - IntegralAffineCurve, - IntegralAffineCurve_finite_field, - IntegralAffinePlaneCurve, - IntegralAffinePlaneCurve_finite_field) +from .projective_curve import ProjectiveCurve, ProjectivePlaneCurve, ProjectiveCurve_field, ProjectivePlaneCurve_field, ProjectivePlaneCurve_finite_field, IntegralProjectiveCurve, IntegralProjectiveCurve_finite_field, IntegralProjectivePlaneCurve, IntegralProjectivePlaneCurve_finite_field + +from .affine_curve import AffineCurve, AffinePlaneCurve, AffineCurve_field, AffinePlaneCurve_field, AffinePlaneCurve_finite_field, IntegralAffineCurve, IntegralAffineCurve_finite_field, IntegralAffinePlaneCurve, IntegralAffinePlaneCurve_finite_field from .weighted_projective_curve import WeightedProjectiveCurve @@ -288,8 +272,7 @@ def Curve(F, A=None): A._coordinate_ring = P elif F.parent().ngens() == 1: if not F.is_zero(): - raise ValueError("defining polynomial of curve must be zero " - "if the ambient space is of dimension 1") + raise ValueError("defining polynomial of curve must be zero " "if the ambient space is of dimension 1") A = AffineSpace(1, P.base_ring(), names=P.variable_names()) A._coordinate_ring = P diff --git a/src/sage/schemes/curves/curve.py b/src/sage/schemes/curves/curve.py index 52d19ae6c37..21a47235f1b 100644 --- a/src/sage/schemes/curves/curve.py +++ b/src/sage/schemes/curves/curve.py @@ -52,6 +52,7 @@ class Curve_generic(AlgebraicScheme_subscheme): sage: loads(C.dumps()) == C True """ + def _repr_(self): """ Return a string representation of this curve. @@ -71,8 +72,7 @@ def _repr_(self): if self.defining_ideal().is_zero() and self.ambient_space().dimension() == 1: return "{} Line over {}".format(self._repr_type(), self.base_ring()) polys = ', '.join(str(x) for x in self.defining_polynomials()) - return "{} Curve over {} defined by {}".format(self._repr_type(), - self.base_ring(), polys) + return "{} Curve over {} defined by {}".format(self._repr_type(), self.base_ring(), polys) def _repr_type(self) -> str: r""" @@ -107,8 +107,7 @@ def _latex_(self): \text{Affine Plane curve over $\Bold{Q}$ defined by $-x^{3} + y^{2} - 17 x + y$} """ - if (self.defining_ideal().is_zero() - and self.ambient_space().dimension() == 1): + if self.defining_ideal().is_zero() and self.ambient_space().dimension() == 1: ambient_type, ring = self._repr_type(), latex(self.base_ring()) return fr"\text{{{ambient_type} line over ${ring}$}}" ambient_type, ring = self._repr_type(), latex(self.base_ring()) @@ -266,6 +265,7 @@ def union(self, other): x^2 - x*y - x*z + y*z """ from .constructor import Curve + return Curve(AlgebraicScheme_subscheme.union(self, other)) __add__ = union @@ -493,8 +493,7 @@ def intersection_points(self, C, F=None): F = self.base_ring() if X.dimension() == 0 or F in FiniteFields(): return X.rational_points(F=F) - raise NotImplementedError("the intersection must have dimension " - "zero or (={}) must be a finite field".format(F)) + raise NotImplementedError("the intersection must have dimension " "zero or (={}) must be a finite field".format(F)) def change_ring(self, R): r""" diff --git a/src/sage/schemes/curves/plane_curve_arrangement.py b/src/sage/schemes/curves/plane_curve_arrangement.py index ce208daf514..33bd9f04de4 100644 --- a/src/sage/schemes/curves/plane_curve_arrangement.py +++ b/src/sage/schemes/curves/plane_curve_arrangement.py @@ -72,6 +72,7 @@ class PlaneCurveArrangementElement(Element): """ An ordered plane curve arrangement. """ + def __init__(self, parent, curves, check=True) -> None: """ Construct a plane curve arrangement. @@ -100,8 +101,7 @@ def __init__(self, parent, curves, check=True) -> None: projective = all(isinstance(h, ProjectivePlaneCurve) for h in curves) if not (affine or projective): raise ValueError("not all elements are curves") - if not all(h.ambient_space() is parent.ambient_space() - for h in curves): + if not all(h.ambient_space() is parent.ambient_space() for h in curves): raise ValueError("not all curves are in the same ambient space") def __getitem__(self, i): @@ -193,12 +193,9 @@ def _repr_(self) -> str: if not self: return 'Empty curve arrangement in {}'.format(self.parent().ambient_space()) if len(self) < 5: - curves = ', '.join(h.defining_polynomial()._repr_() - for h in self._curves) - return 'Arrangement ({}) in {}'.format(curves, - self.parent().ambient_space()) - return 'Arrangement of {} curves in {}'.format(len(self), - self.parent().ambient_space()) + curves = ', '.join(h.defining_polynomial()._repr_() for h in self._curves) + return 'Arrangement ({}) in {}'.format(curves, self.parent().ambient_space()) + return 'Arrangement of {} curves in {}'.format(len(self), self.parent().ambient_space()) def _richcmp_(self, other, op) -> bool: """ @@ -279,7 +276,7 @@ def deletion(self, curves): Traceback (most recent call last): ... ValueError: curve is not in the arrangement - """ + """ parent = self.parent() curves = parent(curves) planes = list(self) @@ -429,6 +426,7 @@ class AffinePlaneCurveArrangementElement(PlaneCurveArrangementElement): """ An ordered affine plane curve arrangement. """ + def __init__(self, parent, curves, check=True) -> None: """ Construct an ordered affine plane curve arrangement. @@ -451,8 +449,7 @@ def __init__(self, parent, curves, check=True) -> None: if check: if not all(isinstance(h, AffinePlaneCurve) for h in curves): raise ValueError("not all elements are curves") - if not all(h.ambient_space() is self.parent().ambient_space() - for h in curves): + if not all(h.ambient_space() is self.parent().ambient_space() for h in curves): raise ValueError("not all curves are in the same ambient space") self._braid_monodromy_non_vertical = None self._braid_monodromy_vertical = None @@ -468,8 +465,7 @@ def __init__(self, parent, curves, check=True) -> None: self._meridians_simpl_vertical = None self._vertical_lines_in_braid_mon = None - def fundamental_group(self, simplified=True, vertical=True, - projective=False): + def fundamental_group(self, simplified=True, vertical=True, projective=False): r""" Return the fundamental group of the complement of the union of affine plane curves in `\CC^2`. @@ -566,11 +562,7 @@ def fundamental_group(self, simplified=True, vertical=True, bd = (bm, st, self._vertical_lines_in_braid_mon, d1) else: bd = None - G, dic = fundamental_group_arrangement(L, simplified=simplified, - puiseux=True, - projective=projective, - vertical=vertical, - braid_data=bd) + G, dic = fundamental_group_arrangement(L, simplified=simplified, puiseux=True, projective=projective, vertical=vertical, braid_data=bd) if simplified and vertical: self._fundamental_group_simpl_vertical = G self._meridians_simpl_vertical = dic @@ -677,8 +669,7 @@ def braid_monodromy(self, vertical=True): if not K.is_subring(QQbar): raise TypeError('the base field is not in QQbar') L = self.defining_polynomials() - bm, dic, dv, d1 = braid_monodromy(prod(L), arrangement=L, - vertical=vertical) + bm, dic, dv, d1 = braid_monodromy(prod(L), arrangement=L, vertical=vertical) if vertical: self._braid_monodromy_vertical = bm self._strands_vertical = dic @@ -776,6 +767,7 @@ class ProjectivePlaneCurveArrangementElement(PlaneCurveArrangementElement): """ An ordered projective plane curve arrangement. """ + def __init__(self, parent, curves, check=True): """ Construct an ordered projective plane curve arrangement. @@ -798,8 +790,7 @@ def __init__(self, parent, curves, check=True): if check: if not all(isinstance(h, ProjectivePlaneCurve) for h in curves): raise ValueError("not all elements are curves") - if not all(h.ambient_space() is self.parent().ambient_space() - for h in curves): + if not all(h.ambient_space() is self.parent().ambient_space() for h in curves): raise ValueError("not all curves are in the same ambient space") self._fundamental_group_nonsimpl = None self._fundamental_group_simpl = None @@ -881,14 +872,14 @@ def fundamental_group(self, simplified=True): return G if infinity_in_C: j = C.curves().index(infinity) - C = H(C.curves()[:j] + C.curves()[j + 1:]) + C = H(C.curves()[:j] + C.curves()[j + 1 :]) infinity_divides = False for j, c in enumerate(C): g = c.defining_polynomial() infinity_divides = z.divides(g) if infinity_divides: h = R(g / z) - C = H(C.curves()[:j] + (h, ) + C.curves()[j + 1:]) + C = H(C.curves()[:j] + (h,) + C.curves()[j + 1 :]) break affine = AffinePlaneCurveArrangements(K, names=('u', 'v')) u, v = affine.gens() @@ -899,8 +890,7 @@ def fundamental_group(self, simplified=True): changes = any(g.degree(v) < g.degree() > 1 for g in affines) C_affine = affine(affines) proj = not (infinity_divides or infinity_in_C) - G = C_affine.fundamental_group(simplified=simplified, vertical=True, - projective=proj) + G = C_affine.fundamental_group(simplified=simplified, vertical=True, projective=proj) dic = C_affine.meridians(simplified=simplified, vertical=True) if infinity_in_C: dic1 = {} @@ -988,6 +978,7 @@ class PlaneCurveArrangements(UniqueRepresentation, Parent): Arrangement (x, y^2, x - 1, y - 1) in Affine Space of dimension 2 over Rational Field """ + Element = PlaneCurveArrangementElement @staticmethod @@ -1116,10 +1107,10 @@ def _element_constructor_(self, *args, **kwds): True sage: L(y, x) == A False - """ + """ if len(args) == 1: if not isinstance(args[0], (tuple, list)): - arg = (args[0], ) + arg = (args[0],) else: arg = tuple(args[0]) else: @@ -1131,13 +1122,13 @@ def _element_constructor_(self, *args, **kwds): try: ambient = h.ambient_space() if ambient == ambient_space: - curves += (h, ) + curves += (h,) else: raise TypeError('the curves do not have the same ambient space') except AttributeError: try: h = R(h) - curves += (Curve(h), ) + curves += (Curve(h),) except TypeError: raise TypeError('elements are not curves') return self.element_class(self, curves) @@ -1231,6 +1222,7 @@ class AffinePlaneCurveArrangements(PlaneCurveArrangements): Arrangement (x, y^2, x - 1, y - 1) in Affine Space of dimension 2 over Rational Field """ + Element = AffinePlaneCurveArrangementElement def ambient_space(self): @@ -1263,6 +1255,7 @@ class ProjectivePlaneCurveArrangements(PlaneCurveArrangements): Arrangement (x, y^2, x - z, y - z) in Projective Space of dimension 2 over Rational Field """ + Element = ProjectivePlaneCurveArrangementElement def ambient_space(self): diff --git a/src/sage/schemes/curves/point.py b/src/sage/schemes/curves/point.py index 35759171c91..44ed255e4ed 100644 --- a/src/sage/schemes/curves/point.py +++ b/src/sage/schemes/curves/point.py @@ -32,16 +32,15 @@ # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.schemes.affine.affine_point import (SchemeMorphism_point_affine_field, - SchemeMorphism_point_affine_finite_field) -from sage.schemes.projective.projective_point import (SchemeMorphism_point_projective_field, - SchemeMorphism_point_projective_finite_field) +from sage.schemes.affine.affine_point import SchemeMorphism_point_affine_field, SchemeMorphism_point_affine_finite_field +from sage.schemes.projective.projective_point import SchemeMorphism_point_projective_field, SchemeMorphism_point_projective_finite_field class ProjectiveCurvePoint_field(SchemeMorphism_point_projective_field): """ Point of a projective curve over a field. """ + def is_singular(self) -> bool: r""" Return whether this point is a singular point of the projective curve it is on. @@ -64,6 +63,7 @@ class ProjectivePlaneCurvePoint_field(ProjectiveCurvePoint_field): """ Point of a projective plane curve over a field. """ + def multiplicity(self): r""" Return the multiplicity of this point with respect to the projective @@ -157,11 +157,11 @@ def is_transverse(self, D) -> bool: return self.codomain().is_transverse(D, self) -class ProjectivePlaneCurvePoint_finite_field(ProjectivePlaneCurvePoint_field, - SchemeMorphism_point_projective_finite_field): +class ProjectivePlaneCurvePoint_finite_field(ProjectivePlaneCurvePoint_field, SchemeMorphism_point_projective_finite_field): """ Point of a projective plane curve over a finite field. """ + pass @@ -190,8 +190,7 @@ def closed_point(self): break ai = hcoords[i] xi = S.gen(i) - hgens = [ai * S.gen(j) - hcoords[j] * xi - for j in range(S.ngens()) if j != i] + hgens = [ai * S.gen(j) - hcoords[j] * xi for j in range(S.ngens()) if j != i] return curve._closed_point(curve, S.ideal(hgens), degree=1) def places(self): @@ -231,6 +230,7 @@ class IntegralProjectiveCurvePoint_finite_field(IntegralProjectiveCurvePoint): """ Point of an integral projective curve over a finite field. """ + pass @@ -238,6 +238,7 @@ class IntegralProjectivePlaneCurvePoint(IntegralProjectiveCurvePoint, Projective """ Point of an integral projective plane curve over a field. """ + pass @@ -245,6 +246,7 @@ class IntegralProjectivePlaneCurvePoint_finite_field(ProjectivePlaneCurvePoint_f """ Point of an integral projective plane curve over a finite field. """ + pass @@ -274,6 +276,7 @@ class AffinePlaneCurvePoint_field(AffineCurvePoint_field): """ Point of an affine plane curve over a field. """ + def multiplicity(self): r""" Return the multiplicity of this point with respect to the affine curve it is on. @@ -373,6 +376,7 @@ class AffinePlaneCurvePoint_finite_field(AffinePlaneCurvePoint_field, SchemeMorp """ Point of an affine plane curve over a finite field. """ + pass @@ -380,6 +384,7 @@ class IntegralAffineCurvePoint(AffineCurvePoint_field): """ Point of an integral affine curve. """ + def closed_point(self): """ Return the closed point that corresponds to this rational point. @@ -445,6 +450,7 @@ class IntegralAffineCurvePoint_finite_field(IntegralAffineCurvePoint): """ Point of an integral affine curve over a finite field. """ + pass @@ -452,6 +458,7 @@ class IntegralAffinePlaneCurvePoint(IntegralAffineCurvePoint, AffinePlaneCurvePo """ Point of an integral affine plane curve. """ + pass @@ -459,4 +466,5 @@ class IntegralAffinePlaneCurvePoint_finite_field(AffinePlaneCurvePoint_finite_fi """ Point of an integral affine plane curve over a finite field. """ + pass diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 518c0bd75e1..bdeace202c1 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -279,6 +279,7 @@ def affine_patch(self, i, AA=None): True """ from .constructor import Curve + return Curve(AlgebraicScheme_subscheme_projective.affine_patch(self, i, AA)) def projection(self, P=None, PS=None): @@ -487,14 +488,14 @@ def projection(self, P=None, PS=None): else: PP2 = PS H = Hom(self, PP2) - coords = [PP.gens()[i] - Q[i]/Q[j]*PP.gens()[j] for i in range(n + 1)] + coords = [PP.gens()[i] - Q[i] / Q[j] * PP.gens()[j] for i in range(n + 1)] coords.pop(j) psi = H(coords) # compute image of psi via elimination # first construct the image of this curve by the change of coordinates. This can be found by composing the # defining polynomials of this curve with the polynomials defining the inverse of the change of coordinates - invcoords = [Q[i]*PP.gens()[j] + PP.gens()[i] for i in range(n + 1)] - invcoords[j] = Q[j]*PP.gens()[j] + invcoords = [Q[i] * PP.gens()[j] + PP.gens()[i] for i in range(n + 1)] + invcoords[j] = Q[j] * PP.gens()[j] id = PP.coordinate_ring().ideal([f(invcoords) for f in self.defining_polynomials()]) J = id.elimination_ideal(PP.gens()[j]) K = Hom(PP.coordinate_ring(), PP2.coordinate_ring()) @@ -723,28 +724,28 @@ def local_coordinates(self, pt, n): p = F.characteristic() x0 = F(pt[0]) y0 = F(pt[1]) - astr = ["a"+str(i) for i in range(1, 2*n)] + astr = ["a" + str(i) for i in range(1, 2 * n)] x, y = R.gens() R0 = PolynomialRing(F, 2 * n + 2, names=[str(x), str(y), "t"] + astr) vars0 = R0.gens() t = vars0[2] - yt = y0*t**0 + add([vars0[i]*t**(i-2) for i in range(3, 2*n+2)]) - xt = x0+t + yt = y0 * t**0 + add([vars0[i] * t ** (i - 2) for i in range(3, 2 * n + 2)]) + xt = x0 + t ft = f(xt, yt) S = singular - S.eval('ring s = '+str(p)+','+str(R0.gens())+',lp;') - S.eval('poly f = '+str(ft)) - cmd = 'matrix c = coeffs ('+str(ft)+',t)' + S.eval('ring s = ' + str(p) + ',' + str(R0.gens()) + ',lp;') + S.eval('poly f = ' + str(ft)) + cmd = 'matrix c = coeffs (' + str(ft) + ',t)' S.eval(cmd) N = int(S.eval('size(c)')) - b = ','.join("c[{},1]".format(i) for i in range(2, N//2 - 4)) + b = ','.join("c[{},1]".format(i) for i in range(2, N // 2 - 4)) cmd = 'ideal I = ' + b S.eval(cmd) c = S.eval('slimgb(I)') d = c.split("=") d = d[1:] - d[len(d)-1] += "\n" - e = [xx[:xx.index("\n")] for xx in d] + d[len(d) - 1] += "\n" + e = [xx[: xx.index("\n")] for xx in d] vals = [] for x in e: for y in vars0: @@ -752,14 +753,14 @@ def local_coordinates(self, pt, n): if x.replace(str(y), ""): i = x.find("-") if i > 0: - vals.append([eval(x[1:i]), x[:i], F(eval(x[i+1:]))]) + vals.append([eval(x[1:i]), x[:i], F(eval(x[i + 1 :]))]) i = x.find("+") if i > 0: - vals.append([eval(x[1:i]), x[:i], -F(eval(x[i+1:]))]) + vals.append([eval(x[1:i]), x[:i], -F(eval(x[i + 1 :]))]) else: vals.append([eval(str(y)[1:]), str(y), F(0)]) vals.sort() - return [x0 + t, y0 + add(v[2] * t**(j + 1) for j, v in enumerate(vals))] + return [x0 + t, y0 + add(v[2] * t ** (j + 1) for j, v in enumerate(vals))] def plot(self, *args, **kwds): """ @@ -813,6 +814,7 @@ def plot(self, *args, **kwds): # last projective coordinate being nonzero patch = kwds.pop('patch', self.ngens() - 1) from .constructor import Curve + C = Curve(self.affine_patch(patch)) return C.plot(*args, **kwds) @@ -892,7 +894,7 @@ def is_singular(self, P=None) -> bool: """ if P is None: poly = self.defining_polynomial() - return poly.parent().ideal(poly.gradient()+[poly]).dimension() > 0 + return poly.parent().ideal(poly.gradient() + [poly]).dimension() > 0 return not self.is_smooth(P) def degree(self): @@ -1094,10 +1096,10 @@ def quadratic_transform(self): PP = self.ambient_space() R = PP.coordinate_ring() L = R.gens() - coords = [L[1]*L[2], L[0]*L[2], L[0]*L[1]] + coords = [L[1] * L[2], L[0] * L[2], L[0] * L[1]] G = self.defining_polynomial()(coords) # remove the component of the curve corresponding to the exceptional divisor - degs = [G.degree()]*len(L) + degs = [G.degree()] * len(L) for F in G.monomials(): for i in range(len(L)): degs[i] = min(F.degree(L[i]), degs[i]) @@ -1216,12 +1218,12 @@ def excellent_position(self, Q): i = 0 while Q[i] == 0: i += 1 - coords = [PP.gens()[j] + Q[j]/Q[i]*PP.gens()[i] for j in range(3)] + coords = [PP.gens()[j] + Q[j] / Q[i] * PP.gens()[i] for j in range(3)] coords[i] = PP.gens()[i] - accoords = [PP.gens()[j] - Q[j]/Q[i]*PP.gens()[i] for j in range(3)] # coords used in map construction + accoords = [PP.gens()[j] - Q[j] / Q[i] * PP.gens()[i] for j in range(3)] # coords used in map construction accoords[i] = PP.gens()[i] baseC = PP.curve(self.defining_polynomial()(coords)) - P = [0]*3 + P = [0] * 3 P[i] = 1 P = PP(P) l = [0, 1, 2] @@ -1232,10 +1234,10 @@ def excellent_position(self, Q): while not good: a = a + 1 # find points to map to (1 : 0 : 0) and (0 : 1 : 0), not on the curve - Px = [0]*3 + Px = [0] * 3 Px[l[0]] = a Px[l[1]] = 1 - Py = [0]*3 + Py = [0] * 3 Py[l[0]] = -a Py[l[1]] = 1 Py[i] = 1 @@ -1249,7 +1251,7 @@ def excellent_position(self, Q): M = matrix([[Px[j], Py[j], P[j]] for j in range(3)]) # M defines a change of coordinates sending (1 : 0 : 0) to Py, (0 : 1 : 0) to Px, (0 : 0 : 1) to P; the # inverse of the transformation we want, used to create the new defining polynomial - coords = [sum([M.row(j)[k]*PP.gens()[k] for k in range(3)]) for j in range(3)] + coords = [sum([M.row(j)[k] * PP.gens()[k] for k in range(3)]) for j in range(3)] C = PP.curve(baseC.defining_polynomial()(coords)) # check tangents at (0 : 0 : 1) T = C.tangents(PP([0, 0, 1]), factor=False)[0] @@ -1276,12 +1278,10 @@ def excellent_position(self, Q): # shared power of the corresponding variable before doing the resultant computations if j == 0: div_pow = min(e[1] for e in npoly.exponents()) - npoly = PP.coordinate_ring()({(v0, v1 - div_pow, v2): g - for (v0, v1, v2), g in npoly.monomial_coefficients().items()}) + npoly = PP.coordinate_ring()({(v0, v1 - div_pow, v2): g for (v0, v1, v2), g in npoly.monomial_coefficients().items()}) else: div_pow = min(e[0] for e in npoly.exponents()) - npoly = PP.coordinate_ring()({(v0 - div_pow, v1, v2): g - for (v0, v1, v2), g in npoly.monomial_coefficients().items()}) + npoly = PP.coordinate_ring()({(v0 - div_pow, v1, v2): g for (v0, v1, v2), g in npoly.monomial_coefficients().items()}) # check the degree again if npoly.degree() != d - r: need_continue = True @@ -1322,7 +1322,7 @@ def excellent_position(self, Q): good = True # coords for map M = M.inverse() - accoords2 = [sum([M.row(j)[k]*PP.gens()[k] for k in range(3)]) for j in range(3)] + accoords2 = [sum([M.row(j)[k] * PP.gens()[k] for k in range(3)]) for j in range(3)] H = Hom(self, C) phi = H([f(accoords) for f in accoords2]) return phi @@ -1461,7 +1461,8 @@ def extension(self): return F.embeddings(K)[0] # make sure the defining polynomial variable names are the same for K, N N = NumberField(K.defining_polynomial().parent()(F.defining_polynomial()), str(K.gen())) - return N.composite_fields(K, both_maps=True)[0][1]*F.embeddings(N)[0] + return N.composite_fields(K, both_maps=True)[0][1] * F.embeddings(N)[0] + if self.base_ring() not in NumberFields(): raise NotImplementedError("the base ring of this curve must be a number field") if not self.is_irreducible(): @@ -1488,12 +1489,12 @@ def extension(self): temp_exc = C.excellent_position(pts[0]) temp_qua = temp_exc.codomain().quadratic_transform() C = temp_qua.codomain() - phi = temp_qua*temp_exc*phi + phi = temp_qua * temp_exc * phi # transform the old points for i in range(len(pts) - 1, -1, -1): # find image if it is a point the composition map is defined on try: - temp_pt = (temp_qua*temp_exc)(temp_exc.domain()(pts[i])) + temp_pt = (temp_qua * temp_exc)(temp_exc.domain()(pts[i])) pts.pop(i) if PP(list(temp_pt)) not in [PP(list(tpt)) for tpt in pts]: pts.append(temp_pt) @@ -1576,6 +1577,7 @@ class ProjectiveCurve_field(ProjectiveCurve, AlgebraicScheme_subscheme_projectiv """ Projective curves over fields. """ + _point = ProjectiveCurvePoint_field def __init__(self, A, X, category=None): @@ -1715,6 +1717,7 @@ class ProjectivePlaneCurve_field(ProjectivePlaneCurve, ProjectiveCurve_field): """ Projective plane curves over fields. """ + _point = ProjectivePlaneCurvePoint_field def arithmetic_genus(self): @@ -1808,11 +1811,12 @@ def fundamental_group(self): Finitely presented group < | > """ from sage.schemes.curves.zariski_vankampen import fundamental_group + F = self.base_ring() from sage.rings.qqbar import QQbar + if QQbar.coerce_map_from(F) is None: - raise NotImplementedError("the base field must have an embedding" - " to the algebraic field") + raise NotImplementedError("the base field must have an embedding" " to the algebraic field") g = self.defining_polynomial() ring = self.ambient_space().affine_patch(2).coordinate_ring() if g.degree() == 1: @@ -1909,6 +1913,7 @@ class ProjectivePlaneCurve_finite_field(ProjectivePlaneCurve_field): """ Projective plane curves over finite fields """ + _point = ProjectivePlaneCurvePoint_finite_field def rational_points_iterator(self): @@ -1987,6 +1992,7 @@ def rational_points_iterator(self): g = self.defining_polynomial() K = g.parent().base_ring() from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(K, 'X') X = R.gen() one = K.one() @@ -2056,9 +2062,12 @@ def _points_via_singular(self, sort=True): try: X1 = f.Adj_div() except (TypeError, RuntimeError) as s: - raise RuntimeError(str(s) + "\n\n ** Unable to use the\ + raise RuntimeError( + str(s) + + "\n\n ** Unable to use the\ Brill-Noether Singular package to\ - compute all points (see above).") + compute all points (see above)." + ) X2 = singular.NSplaces(1, X1) R = X2[5][1][1] @@ -2070,8 +2079,7 @@ def _points_via_singular(self, sort=True): # the expect interface could crop up. Also, this is vastly # faster (and more robust). v = singular('POINTS').sage_flattened_str_list() - pnts = [self(int(v[3*i]), int(v[3*i+1]), int(v[3*i+2])) - for i in range(len(v)//3)] + pnts = [self(int(v[3 * i]), int(v[3 * i + 1]), int(v[3 * i + 2])) for i in range(len(v) // 3)] # singular always dehomogenizes with respect to the last variable # so if this variable divides the curve equation, we need to add # points at infinity @@ -2156,12 +2164,12 @@ def riemann_roch_basis(self, D): # faster (and more robust). v = [v[i].partition(',') for i in range(len(v))] - pnts = [(int(v[i][0]), int(v[i][2])-1) for i in range(len(v))] + pnts = [(int(v[i][0]), int(v[i][2]) - 1) for i in range(len(v))] # retrieve coordinates of rational points R = X2[5][1][1] R.set_ring() v = singular('POINTS').sage_flattened_str_list() - coords = [self(int(v[3*i]), int(v[3*i+1]), int(v[3*i+2])) for i in range(len(v)//3)] + coords = [self(int(v[3 * i]), int(v[3 * i + 1]), int(v[3 * i + 2])) for i in range(len(v) // 3)] # build correct representation of D for singular Dcoeffs = [] for x in pnts: @@ -2177,7 +2185,7 @@ def riemann_roch_basis(self, D): LG = [X.split(',\n') for X in LG.sage_structured_str_list()] x, y, z = self.ambient_space().coordinate_ring().gens() vars = {'x': x, 'y': y, 'z': z} - V = [(sage_eval(a, vars)/sage_eval(b, vars)) for a, b in LG] + V = [(sage_eval(a, vars) / sage_eval(b, vars)) for a, b in LG] return V def rational_points(self, algorithm='enum', sort=True): @@ -2274,9 +2282,12 @@ def rational_points(self, algorithm='enum', sort=True): S_enum = self.rational_points(algorithm='enum') S_bn = self.rational_points(algorithm='bn') if S_enum != S_bn: - raise RuntimeError("Bug in rational_points -- different\ + raise RuntimeError( + "Bug in rational_points -- different\ algorithms give different answers for\ - curve %s!" % self) + curve %s!" + % self + ) return S_enum raise ValueError(f"No algorithm '{algorithm}' known") @@ -2391,6 +2402,7 @@ def random_element(self): from sage.schemes.hyperelliptic_curves.hyperelliptic_finite_field import ( HyperellipticCurve_finite_field, ) + if not isinstance(self, (EllipticCurve_finite_field, HyperellipticCurve_finite_field)): raise NotImplementedError("only implemented for elliptic and hyperelliptic curves over finite fields") @@ -2398,6 +2410,7 @@ def random_element(self): n = 2 * k.order() + 1 from sage.rings.integer_ring import ZZ + while True: # Choose the point at infinity with probability 1/(2q + 1) i = ZZ.random_element(n) @@ -2417,6 +2430,7 @@ class IntegralProjectiveCurve(ProjectiveCurve_field): """ Integral projective curve. """ + _point = IntegralProjectiveCurvePoint _closed_point = IntegralProjectiveCurveClosedPoint @@ -2577,7 +2591,7 @@ def function(self, f): if num.degree() != den.degree(): raise ValueError("not define a function on the curve") - return phi(num)/phi(den) + return phi(num) / phi(den) def coordinate_functions(self, i=None): """ @@ -2599,7 +2613,7 @@ def coordinate_functions(self, i=None): if i is None: return coords inv = ~coords[i] - return tuple([coords[j]*inv for j in range(len(coords)) if j != i]) + return tuple([coords[j] * inv for j in range(len(coords)) if j != i]) def pull_from_function_field(self, f): """ @@ -2740,7 +2754,7 @@ def _singularities(self): if denom: funcs = [] for p in S._first_ngens(i) + sing.defining_polynomials(): - f = to_F(p)/denom**p.degree() + f = to_F(p) / denom ** p.degree() if not f.is_zero(): funcs.append(f) @@ -2816,7 +2830,7 @@ def place_to_closed_point(self, place): imin = vals.index(min(vals)) R = S.remove_var(S.gen(imin)) hcoords = self._coordinate_functions - coords = [hcoords[i]/hcoords[imin] for i in range(S.ngens()) if i != imin] + coords = [hcoords[i] / hcoords[imin] for i in range(S.ngens()) if i != imin] k, from_k, to_k = place.residue_field() V, from_V, to_V = k.vector_space(F.constant_base_field(), map=True) @@ -2844,7 +2858,7 @@ def place_to_closed_point(self, place): e[-1] = d + 1 else: e[j] -= 1 - e[j-1] += 1 + e[j - 1] += 1 m = R.monomial(*e) if any(g.divides(m) for g in gens_lts): @@ -2852,7 +2866,7 @@ def place_to_closed_point(self, place): prod = 1 for i in range(R.ngens()): - prod *= coords[i]**e[i] + prod *= coords[i] ** e[i] vec = to_V(to_k(prod)) # represent as a vector mat = matrix(basis_vecs) try: @@ -2917,11 +2931,10 @@ def places_on(self, point): phi = self._map_to_function_field denom = self._coordinate_functions[i] - gs = [phi(f) / denom**f.degree() for f in prime.gens()] + gs = [phi(f) / denom ** f.degree() for f in prime.gens()] fs = [g for g in gs if not g.is_zero()] f = fs.pop() - return [p for p in f.zeros() - if all(f.valuation(p) > 0 for f in fs)] + return [p for p in f.zeros() if all(f.valuation(p) > 0 for f in fs)] def jacobian(self, model, base_div=None, **kwargs): """ @@ -2992,6 +3005,7 @@ class IntegralProjectiveCurve_finite_field(IntegralProjectiveCurve): Point (x + 2*z, y - z), Point (x - 2*z, y - 2*z)] """ + _point = IntegralProjectiveCurvePoint_finite_field def places(self, degree=1): @@ -3101,8 +3115,8 @@ def L_polynomial(self, name='t'): f = R.one() for p, places in self._singularities: for place in places: - f = f * (1 - T**place.degree()) - f = f // (1 - T**p.degree()) + f = f * (1 - T ** place.degree()) + f = f // (1 - T ** p.degree()) return L * f @@ -3138,7 +3152,7 @@ def number_of_rational_points(self, r=1): Lp = R(Lp) f = R(Lp / L, prec=r) - n = f[r-1] + q**r + 1 + n = f[r - 1] + q**r + 1 return n @@ -3147,8 +3161,7 @@ class IntegralProjectivePlaneCurve(IntegralProjectiveCurve, ProjectivePlaneCurve _point = IntegralProjectivePlaneCurvePoint -class IntegralProjectivePlaneCurve_finite_field(IntegralProjectiveCurve_finite_field, - ProjectivePlaneCurve_finite_field): +class IntegralProjectivePlaneCurve_finite_field(IntegralProjectiveCurve_finite_field, ProjectivePlaneCurve_finite_field): """ Integral projective plane curve over a finite field. @@ -3169,6 +3182,7 @@ class IntegralProjectivePlaneCurve_finite_field(IntegralProjectiveCurve_finite_f sage: Cb.function_field() Function field in y defined by y^2 + 2*x^5 + 2*x^4 + x^3 + x + 1 """ + _point = IntegralProjectivePlaneCurvePoint_finite_field @@ -3194,12 +3208,11 @@ def Hasse_bounds(q, genus=1): (999999999999998000000000000058, 1000000000000002000000000000058) """ if genus == 1: - rq = (4*q).isqrt() + rq = (4 * q).isqrt() else: - rq = (4*(genus**2)*q).isqrt() - return (q+1-rq, q+1+rq) + rq = (4 * (genus**2) * q).isqrt() + return (q + 1 - rq, q + 1 + rq) # Fix pickles from changing class names and plane_curves folder name -register_unpickle_override('sage.schemes.plane_curves.projective_curve', - 'ProjectiveCurve_generic', ProjectivePlaneCurve) +register_unpickle_override('sage.schemes.plane_curves.projective_curve', 'ProjectiveCurve_generic', ProjectivePlaneCurve) diff --git a/src/sage/schemes/curves/weighted_projective_curve.py b/src/sage/schemes/curves/weighted_projective_curve.py index af74b9d0e69..614bf16cbb9 100644 --- a/src/sage/schemes/curves/weighted_projective_curve.py +++ b/src/sage/schemes/curves/weighted_projective_curve.py @@ -100,14 +100,9 @@ def projective_curve(self): from sage.schemes.projective.projective_space import ProjectiveSpace WP = self.ambient_space() - PP = ProjectiveSpace( - WP.dimension_relative(), WP.base_ring(), WP.variable_names() - ) + PP = ProjectiveSpace(WP.dimension_relative(), WP.base_ring(), WP.variable_names()) PP_ring = PP.coordinate_ring() - subs_dict = { - name: var**weight - for (name, var), weight in zip(WP.gens_dict().items(), WP.weights()) - } + subs_dict = {name: var**weight for (name, var), weight in zip(WP.gens_dict().items(), WP.weights())} wp_polys = self.defining_polynomials() pp_polys = [PP_ring(poly.subs(**subs_dict)) for poly in wp_polys] @@ -144,9 +139,7 @@ def affine_patch(self, i, AA=None): from .constructor import Curve projective_curve = self.projective_curve() - return Curve( - AlgebraicScheme_subscheme_projective.affine_patch(projective_curve, i, AA) - ) + return Curve(AlgebraicScheme_subscheme_projective.affine_patch(projective_curve, i, AA)) def riemann_surface(self, **kwargs): r""" diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index d4d343f23da..353cb5e7191 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -112,8 +112,7 @@ def braid_from_piecewise(strands): interpolai = xauxi + (yauxi - xauxi) * (i - aaux) / (baux - aaux) totalpoints[j].append([interpolar, interpolai]) else: - totalpoints[j].append([val[indices[j]][1], - val[indices[j]][2]]) + totalpoints[j].append([val[indices[j]][1], val[indices[j]][2]]) indices[j] = indices[j] + 1 i = min(val[indices[k]][0] for k, val in enumerate(L)) @@ -142,8 +141,7 @@ def sgn(x, y): for k in range(j): if l2j < l2[k]: t = (l1j[0] - l1[k][0]) / ((l2[k][0] - l2j[0]) + (l1j[0] - l1[k][0])) - s = sgn(l1[k][1] * (1 - t) + t * l2[k][1], - l1j[1] * (1 - t) + t * l2j[1]) + s = sgn(l1[k][1] * (1 - t) + t * l2[k][1], l1j[1] * (1 - t) + t * l2j[1]) cruces.append([t, k, j, s]) if cruces: cruces.sort() @@ -151,16 +149,14 @@ def sgn(x, y): while cruces: # we select the crosses in the same t crucesl = [c for c in cruces if c[0] == cruces[0][0]] - crossesl = [(P(c[2] + 1) - P(c[1] + 1), c[1], c[2], c[3]) - for c in crucesl] - cruces = cruces[len(crucesl):] + crossesl = [(P(c[2] + 1) - P(c[1] + 1), c[1], c[2], c[3]) for c in crucesl] + cruces = cruces[len(crucesl) :] while crossesl: crossesl.sort() c = crossesl.pop(0) braid.append(c[3] * min(map(P, [c[1] + 1, c[2] + 1]))) P = G(Permutation([(c[1] + 1, c[2] + 1)])) * P - crossesl = [(P(cr[2] + 1) - P(cr[1] + 1), - cr[1], cr[2], cr[3]) for cr in crossesl] + crossesl = [(P(cr[2] + 1) - P(cr[1] + 1), cr[1], cr[2], cr[3]) for cr in crossesl] B = BraidGroup(len(L)) return B(braid) @@ -204,8 +200,7 @@ def discrim_pairs(f, g): return pol_ring(f.discriminant(y)) return pol_ring(f.resultant(g, y)) - pairs = [(f, None) for f in pols] + [tuple(t) for t - in combinations(pols, 2)] + pairs = [(f, None) for f in pols] + [tuple(t) for t in combinations(pols, 2)] fdiscrim = discrim_pairs(pairs) rts = () poly = 1 @@ -256,18 +251,13 @@ def corrected_voronoi_diagram(points) -> VoronoiDiagram: point_coordinates = [(p.real(), p.imag()) for p in points] while True: RF = RealField(prec) - apprpoints = {(QQ(RF(p[0])), QQ(RF(p[1]))): p - for p in point_coordinates} + apprpoints = {(QQ(RF(p[0])), QQ(RF(p[1]))): p for p in point_coordinates} added_points = 3 * max(map(abs, flatten(apprpoints))) + 1 - configuration = list(apprpoints.keys()) + [(added_points, 0), - (-added_points, 0), - (0, added_points), - (0, -added_points)] + configuration = list(apprpoints.keys()) + [(added_points, 0), (-added_points, 0), (0, added_points), (0, -added_points)] V = VoronoiDiagram(configuration) valid = True for r in V.regions().items(): - if (not r[1].rays() and - not r[1].interior_contains(apprpoints[r[0].affine()])): + if not r[1].rays() and not r[1].interior_contains(apprpoints[r[0].affine()]): prec += 53 valid = False break @@ -358,8 +348,7 @@ def orient_circuit(circuit, convex=False, precision=53, verbose=False) -> tuple: prec = precision while True: CIF = ComplexIntervalField(prec) - totalangle = sum((CIF(*vectors[i]) / CIF(*vectors[i - 1])).argument() - for i in range(len(vectors))) + totalangle = sum((CIF(*vectors[i]) / CIF(*vectors[i - 1])).argument() for i in range(len(vectors))) if totalangle < 0: return tuple(reversed(circuit_vertex)) if totalangle > 0: @@ -458,12 +447,9 @@ def voronoi_cells(V, vertical_lines=frozenset()) -> tuple: points = [p for p in V.regions().keys() if V.regions()[p].is_compact()] compact_regions = [regions[p] for p in points] vertical_regions = {} - non_compact_regions = [reg for reg in V.regions().values() - if not reg.is_compact()] - G = Graph([u.vertices() for v in compact_regions for u in v.faces(1)], - format='list_of_edges') - E = Graph([u.vertices() for v in non_compact_regions for u in v.faces(1) - if u.is_compact()], format='list_of_edges') + non_compact_regions = [reg for reg in V.regions().values() if not reg.is_compact()] + G = Graph([u.vertices() for v in compact_regions for u in v.faces(1)], format='list_of_edges') + E = Graph([u.vertices() for v in non_compact_regions for u in v.faces(1) if u.is_compact()], format='list_of_edges') p = next(E.vertex_iterator()) EC = orient_circuit(E.eulerian_circuit()) DG = Graph() @@ -564,8 +550,8 @@ def followstrand(f, factors, x0, x1, y0a, prec=53) -> list[tuple]: ci = c.imag() coefsfactors += list(cr.endpoints()) coefsfactors += list(ci.endpoints()) - from sage.libs.sirocco import (contpath, contpath_mp, - contpath_comps, contpath_mp_comps) + from sage.libs.sirocco import contpath, contpath_mp, contpath_comps, contpath_mp_comps + try: if prec == 53: if factors: @@ -729,16 +715,14 @@ def roots_interval(f, x0) -> dict: IF = ComplexIntervalField(prec) CF = ComplexField(prec) divisor = 4 - diam = min((CF(r) - CF(r0)).abs() - for r0 in roots[:i] + roots[i + 1:]) / divisor + diam = min((CF(r) - CF(r0)).abs() for r0 in roots[:i] + roots[i + 1 :]) / divisor envelop = IF(diam) * IF((-1, 1), (-1, 1)) while newton(fx, r, r + envelop) not in r + envelop: prec += 53 IF = ComplexIntervalField(prec) CF = ComplexField(prec) divisor *= 2 - diam = min((CF(r) - CF(r0)).abs() - for r0 in roots[:i] + roots[i + 1:]) / divisor + diam = min((CF(r) - CF(r0)).abs() for r0 in roots[:i] + roots[i + 1 :]) / divisor envelop = IF(diam) * IF((-1, 1), (-1, 1)) qapr = QQ(CF(r).real()) + QQbar.gen() * QQ(CF(r).imag()) if qapr not in r + envelop: @@ -886,18 +870,15 @@ def braid_in_segment(glist, x0, x1, precision={}): while True: CIFp = ComplexIntervalField(precision1[f]) intervals[f] = [r.interval(CIFp) for r in y0sf] - if not any(a.overlaps(b) for a, b in - combinations(intervals[f], 2)): + if not any(a.overlaps(b) for a, b in combinations(intervals[f], 2)): break precision1[f] *= 2 strands = [] for f in glist: for i in intervals[f]: - aux = followstrand(f, [p for p in glist if p != f], - x0, x1, i.center(), precision1[f]) + aux = followstrand(f, [p for p in glist if p != f], x0, x1, i.center(), precision1[f]) strands.append(aux) - complexstrands = [[(QQ(a[0]), QQ(a[1]), QQ(a[2])) for a in b] - for b in strands] + complexstrands = [[(QQ(a[0]), QQ(a[1]), QQ(a[2])) for a in b] for b in strands] centralbraid = braid_from_piecewise(complexstrands) initialstrands = [] finalstrands = [] @@ -910,8 +891,7 @@ def braid_in_segment(glist, x0, x1, precision={}): matched = 0 for center, interval in initialintervals.items(): if ip in interval: - initialstrands.append([(0, center.real(), center.imag()), - (1, cs[0][1], cs[0][2])]) + initialstrands.append([(0, center.real(), center.imag()), (1, cs[0][1], cs[0][2])]) matched += 1 if matched != 1: precision1 = {f: precision1[f] * 2 for f in glist} @@ -920,8 +900,7 @@ def braid_in_segment(glist, x0, x1, precision={}): matched = 0 for center, interval in finalintervals.items(): if fp in interval: - finalstrands.append([(0, cs[-1][1], cs[-1][2]), - (1, center.real(), center.imag())]) + finalstrands.append([(0, cs[-1][1], cs[-1][2]), (1, center.real(), center.imag())]) matched += 1 if matched != 1: precision1 = {f: precision1[f] * 2 for f in glist} @@ -932,8 +911,7 @@ def braid_in_segment(glist, x0, x1, precision={}): return initialbraid * centralbraid * finalbraid -def geometric_basis(G, E, EC0, p, dual_graph, - vertical_regions={}) -> tuple[list, dict]: +def geometric_basis(G, E, EC0, p, dual_graph, vertical_regions={}) -> tuple[list, dict]: r""" Return a geometric basis, based on a vertex. @@ -994,7 +972,7 @@ def geometric_basis(G, E, EC0, p, dual_graph, {0: 0, 1: 3, 2: 1, 3: 2, 4: 4} """ i = EC0.index(p) - EC = EC0[i:-1] + EC0[:i + 1] + EC = EC0[i:-1] + EC0[: i + 1] # A counterclockwise eulerian circuit on the boundary, # starting and ending at p if G.size() == E.size(): @@ -1011,17 +989,13 @@ def geometric_basis(G, E, EC0, p, dual_graph, Internal = G.subgraph(vertices=InternalVertices, edges=InternalEdges) for i, ECi in enumerate(EC): # q and r are the points we will cut through if ECi in Internal: - EI = [v for v in E if v in - Internal.connected_component_containing_vertex(ECi, sort=True) - and v != ECi] + EI = [v for v in E if v in Internal.connected_component_containing_vertex(ECi, sort=True) and v != ECi] if EI: q = ECi connecting_path = list(EC[:i]) break if EC[-i] in Internal: - EI = [v for v in E if v in - Internal.connected_component_containing_vertex(EC[-i], sort=True) - and v != EC[-i]] + EI = [v for v in E if v in Internal.connected_component_containing_vertex(EC[-i], sort=True) and v != EC[-i]] if EI: q = EC[-i] connecting_path = list(reversed(EC[-i:])) @@ -1029,13 +1003,13 @@ def geometric_basis(G, E, EC0, p, dual_graph, # Precompute distances from q in E and I E_dist_q = E.shortest_path_lengths(q) I_dist_q = Internal.shortest_path_lengths(q) - distancequotients = [(E_dist_q[v]**2 / I_dist_q[v], v) for v in EI] + distancequotients = [(E_dist_q[v] ** 2 / I_dist_q[v], v) for v in EI] r = max(distancequotients)[1] cutpath = Internal.shortest_path(q, r) for i, v in enumerate(cutpath): if i > 0 and v in EC: r = v - cutpath = cutpath[:i + 1] + cutpath = cutpath[: i + 1] break qi = EC.index(q) ri = EC.index(r) @@ -1063,8 +1037,7 @@ def geometric_basis(G, E, EC0, p, dual_graph, E1.add_edge(cutpath[i], cutpath[i + 1], None) E2.add_edge(cutpath[i], cutpath[i + 1], None) Gd = copy(dual_graph) - to_delete = [e for e in Gd.edges(sort=True) if e[2][0] in cutpath and - e[2][1] in cutpath] + to_delete = [e for e in Gd.edges(sort=True) if e[2][0] in cutpath and e[2][1] in cutpath] Gd.delete_edges(to_delete) Gd1, Gd2 = Gd.connected_components_subgraphs() edges_2 = [] @@ -1072,20 +1045,16 @@ def geometric_basis(G, E, EC0, p, dual_graph, for reg in Gd2.vertices(sort=True): vertices_2 += reg[1][:-1] reg_circuit = reg[1] - edges_2 += [(v1, reg_circuit[i + 1]) - for i, v1 in enumerate(reg_circuit[:-1])] - edges_2 += [(v1, reg_circuit[i - 1]) - for i, v1 in enumerate(reg_circuit[1:])] + edges_2 += [(v1, reg_circuit[i + 1]) for i, v1 in enumerate(reg_circuit[:-1])] + edges_2 += [(v1, reg_circuit[i - 1]) for i, v1 in enumerate(reg_circuit[1:])] G2 = G.subgraph(vertices=vertices_2, edges=edges_2) edges_1 = [] vertices_1 = [] for reg in Gd1.vertices(sort=True): vertices_1 += reg[1] reg_circuit = reg[1] + (reg[1][0],) - edges_1 += [(v1, reg_circuit[i + 1]) - for i, v1 in enumerate(reg_circuit[:-1])] - edges_1 += [(v1, reg_circuit[i - 1]) - for i, v1 in enumerate(reg_circuit[1:])] + edges_1 += [(v1, reg_circuit[i + 1]) for i, v1 in enumerate(reg_circuit[:-1])] + edges_1 += [(v1, reg_circuit[i - 1]) for i, v1 in enumerate(reg_circuit[1:])] G1 = G.subgraph(vertices=vertices_1, edges=edges_1) if EC[qi + 1] in G2: G1, G2 = G2, G1 @@ -1093,10 +1062,10 @@ def geometric_basis(G, E, EC0, p, dual_graph, if qi < ri: EC1 = [EC[j] for j in range(qi, ri)] + list(reversed(cutpath)) - EC2 = cutpath + list(EC[ri + 1: -1] + EC[: qi + 1]) + EC2 = cutpath + list(EC[ri + 1 : -1] + EC[: qi + 1]) else: EC1 = list(EC[qi:] + EC[1:ri]) + list(reversed(cutpath)) - EC2 = cutpath + list(EC[ri + 1:qi + 1]) + EC2 = cutpath + list(EC[ri + 1 : qi + 1]) gb1, vd1 = geometric_basis(G1, E1, EC1, q, Gd1, vertical_regions=vertical_regions) gb2, vd2 = geometric_basis(G2, E2, EC2, q, Gd2, vertical_regions=vertical_regions) @@ -1106,8 +1075,7 @@ def geometric_basis(G, E, EC0, p, dual_graph, for j in vd2.keys(): vd[j] = vd2[j] + m reverse_connecting = list(reversed(connecting_path)) - resul = [connecting_path + path + reverse_connecting - for path in gb1 + gb2] + resul = [connecting_path + path + reverse_connecting for path in gb1 + gb2] for r in resul: i = 0 while i < len(r) - 2: @@ -1292,10 +1260,8 @@ def braid_monodromy(f, arrangement=(), vertical=False) -> tuple: indices_v = vertical_lines_in_braidmon(arrangement1) else: indices_v = [] - arrangement_h = tuple(f0 for j, f0 in enumerate(arrangement1) - if j not in indices_v) - arrangement_v = tuple(f0 for j, f0 in enumerate(arrangement1) - if j in indices_v) + arrangement_h = tuple(f0 for j, f0 in enumerate(arrangement1) if j not in indices_v) + arrangement_v = tuple(f0 for j, f0 in enumerate(arrangement1) if j in indices_v) glist = tuple(fc[0] for f0 in arrangement_h for fc in f0.factor()) g = f.parent()(prod(glist)) d = g.degree(y) @@ -1320,8 +1286,7 @@ def braid_monodromy(f, arrangement=(), vertical=False) -> tuple: vl_list.sort() vl = frozenset(vl_list) if not disc: - vertical_braids = {i: transversal[f0] - for i, f0 in enumerate(transversal)} + vertical_braids = {i: transversal[f0] for i, f0 in enumerate(transversal)} if d > 1: result = [BraidGroup(d).one() for p in transversal] else: @@ -1362,8 +1327,7 @@ def braid_monodromy(f, arrangement=(), vertical=False) -> tuple: end_braid_computation = False while not end_braid_computation: try: - braidscomputed = braid_in_segment([(glist, seg[0], seg[1]) - for seg in segs]) + braidscomputed = braid_in_segment([(glist, seg[0], seg[1]) for seg in segs]) segsbraids = {} for braidcomputed in braidscomputed: seg = (braidcomputed[0][0][1], braidcomputed[0][0][2]) @@ -1521,7 +1485,7 @@ def braid2rels(L) -> list: br0 = B0([j - k for j in T]) br0_left = leftnormalform(br0) q, r = ZZ(br0_left[0][0]).quo_rem(2) - br1 = B0.delta()**r * prod(map(B0, br0_left[1:]), B0.one()) + br1 = B0.delta() ** r * prod(map(B0, br0_left[1:]), B0.one()) cox = prod(F0.gens()) U0 = [cox**q * (f0 * br1) / cox**q / f0 for f0 in F0.gens()[:-1]] U = [tuple(sign(k1) * (abs(k1) + k) for k1 in br.Tietze()) for br in U0] @@ -1552,9 +1516,7 @@ def relation(x, b): return x * b / x -def fundamental_group_from_braid_mon(bm, degree=None, - simplified=True, projective=False, - puiseux=True, vertical=[]): +def fundamental_group_from_braid_mon(bm, degree=None, simplified=True, projective=False, puiseux=True, vertical=[]): r""" Return a presentation of the fundamental group computed from a braid monodromy. @@ -1634,7 +1596,7 @@ def fundamental_group_from_braid_mon(bm, degree=None, return Fv / [(1, j, -1, -j) for j in range(2, d + v + 1)] bmh = [br for j, br in enumerate(bm) if j not in vertical0] if not puiseux: - relations_h = (relation([(x, b) for x in F.gens() for b in bmh])) + relations_h = relation([(x, b) for x in F.gens() for b in bmh]) rel_h = [r[1] for r in relations_h] else: conjugate_desc = conjugate_positive_form_p(bmh) @@ -1657,7 +1619,7 @@ def fundamental_group_from_braid_mon(bm, degree=None, l1 = d + j + 1 br = bm[k] rnf = rightnormalform(br) - rnf1 = rnf[: -1] + rnf1 = rnf[:-1] xp = rnf[-1][0] if rnf1: elt = prod(B(m) for m in rnf1) @@ -1795,15 +1757,10 @@ def fundamental_group(f, simplified=True, projective=False, puiseux=True): d = g.degree(y) else: d = bm[0].parent().strands() - return fundamental_group_from_braid_mon(bm, degree=d, - simplified=simplified, - projective=projective, - puiseux=puiseux) + return fundamental_group_from_braid_mon(bm, degree=d, simplified=simplified, projective=projective, puiseux=puiseux) -def fundamental_group_arrangement(flist, simplified=True, projective=False, - puiseux=True, vertical=False, - braid_data=None): +def fundamental_group_arrangement(flist, simplified=True, projective=False, puiseux=True, vertical=False, braid_data=None): r""" Compute the fundamental group of the complement of a curve defined by a list of polynomials with the extra information @@ -1910,11 +1867,9 @@ def fundamental_group_arrangement(flist, simplified=True, projective=False, x, y = R.gens() flist1 = tuple(flist) if vertical and vertical_lines_in_braidmon(flist1): - infinity = all(Curve(g).is_vertical_line() or - g.degree(y) == g.degree() for g in flist1) + infinity = all(Curve(g).is_vertical_line() or g.degree(y) == g.degree() for g in flist1) else: - infinity = any(Curve(g).has_vertical_asymptote() or - Curve(g).is_vertical_line() for g in flist1) + infinity = any(Curve(g).has_vertical_asymptote() or Curve(g).is_vertical_line() for g in flist1) if not infinity: infinity = all(g.degree(y) == g.degree() for g in flist1) if braid_data: @@ -1930,10 +1885,7 @@ def fundamental_group_arrangement(flist, simplified=True, projective=False, vert_lines.sort() for i, j in enumerate(vert_lines): dic[d1 + i] = dv[j] - g = fundamental_group_from_braid_mon(bm, degree=d1, simplified=False, - projective=projective, - puiseux=puiseux, - vertical=vert_lines) + g = fundamental_group_from_braid_mon(bm, degree=d1, simplified=False, projective=projective, puiseux=puiseux, vertical=vert_lines) if simplified: hom = g.simplification_isomorphism() else: diff --git a/src/sage/schemes/cyclic_covers/charpoly_frobenius.py b/src/sage/schemes/cyclic_covers/charpoly_frobenius.py index 649e565e797..86cebd47903 100644 --- a/src/sage/schemes/cyclic_covers/charpoly_frobenius.py +++ b/src/sage/schemes/cyclic_covers/charpoly_frobenius.py @@ -9,6 +9,7 @@ # ***************************************************************************** from sage.rings.integer_ring import ZZ from sage.misc.lazy_import import lazy_import + lazy_import("sage.functions.log", "log") @@ -209,7 +210,7 @@ def charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a=1, known_factor= degree = len(charpoly_prec) - 1 mod = [0] * (degree + 1) for i in range(len(charpoly_prec)): - mod[-i] = p**charpoly_prec[-i] + mod[-i] = p ** charpoly_prec[-i] cp[-i] = cp[-i] % mod[-i] # figure out the sign @@ -227,12 +228,12 @@ def charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a=1, known_factor= # note, if degree is even, the middle coefficient will not help us determine the sign for i in range((degree + 1) // 2): # Note: degree*weight is even - p_power = p**min( + p_power = p ** min( charpoly_prec[i], charpoly_prec[degree - i] + ((a * (degree - 2 * i) * weight) // 2), ) if cp[i] % p_power != 0 and cp[degree - i] % p_power != 0: - other = cp[degree - i] * p**((a * (degree - 2 * i) * weight) // 2) + other = cp[degree - i] * p ** ((a * (degree - 2 * i) * weight) // 2) if (cp[i] + other) % p_power == 0: sign = -1 else: @@ -246,7 +247,7 @@ def charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a=1, known_factor= # note, this includes the middle coefficient if degree is even halfdegree = degree // 2 + 1 - cp[0] = sign * p**((a * degree * weight) // 2) + cp[0] = sign * p ** ((a * degree * weight) // 2) # Note: degree*weight is even # calculate the i-th power sum of the roots and correct cp along the way @@ -258,13 +259,7 @@ def charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a=1, known_factor= # e[k] = cp[degree - k] if (k%2 ==0) else -cp[degree - k] if k > 0: # verify if p^charpoly_prec[degree - k] > 2*degree/k * q^(w*k/2) - assert ( - log(k, p) + charpoly_prec[degree - k] - > log(2 * degree, p) + a * 0.5 * weight * k - ), ( - "log(k)/log(p) + charpoly_prec[degree - k] <= log(2*degree)/log(p) + a*0.5*weight*k, k = %d" - % k - ) + assert log(k, p) + charpoly_prec[degree - k] > log(2 * degree, p) + a * 0.5 * weight * k, "log(k)/log(p) + charpoly_prec[degree - k] <= log(2*degree)/log(p) + a*0.5*weight*k, k = %d" % k fix_e = known_factor[:] fix_e.reverse() @@ -280,7 +275,7 @@ def charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a=1, known_factor= # s[k] = \sum x_i ^k for k>0 s = [None] * (halfdegree) res = [None] * len(charpoly_prec) - res[0] = sign * p**((a * degree * weight) // 2) + res[0] = sign * p ** ((a * degree * weight) // 2) # Note: degree*weight is even res[-1] = 1 @@ -291,8 +286,8 @@ def charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a=1, known_factor= # e[k] correct modulo mod[degree - k] # S = sum (-1)^i e[k-i] * s[i] # s[k] = (-1)^(k-1) (k*e[k] + S) ==> (-1)^(k-1) s[k] - S = k*e[k] - S = sum((-1)**i * e[k - i] * s[i] for i in range(1, k)) - s[k] = (-1)**(k - 1) * (S + k * e[k]) + S = sum((-1) ** i * e[k - i] * s[i] for i in range(1, k)) + s[k] = (-1) ** (k - 1) * (S + k * e[k]) # hence s[k] is correct modulo k*mod[degree - k] localmod = k * mod[degree - k] # s[k] += (-1)**k * fix_power_sum[k] @@ -301,17 +296,17 @@ def charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a=1, known_factor= # |x_i| = p^(w*0.5) # => s[k] <= degree*p^(a*w*k*0.5) # recall, 2*degree*p^(a*w*k*0.5) /k < mod[degree - k] - if s[k]**2 > degree**2 * p**(a * weight * k): + if s[k] ** 2 > degree**2 * p ** (a * weight * k): s[k] = -(-s[k] % localmod) # now correct e[k] with: # (-1)^(k-1) s[k] - S = k*e[k] - e[k] = (-S + (-1)**(k - 1) * s[k]) // k - assert (-S + (-1)**(k - 1) * s[k]) % k == 0 + e[k] = (-S + (-1) ** (k - 1) * s[k]) // k + assert (-S + (-1) ** (k - 1) * s[k]) % k == 0 res[degree - k] = e[k] if not k % 2 else -e[k] # Note: degree*weight is even - res[k] = sign * res[degree - k] * p**((a * (degree - 2 * k) * weight) // 2) + res[k] = sign * res[degree - k] * p ** ((a * (degree - 2 * k) * weight) // 2) # fix e[k + 1] if k + 1 < halfdegree: e[k + 1] -= sum([fix_e[k + 1 - i] * e[i] for i in range(k + 1)]) diff --git a/src/sage/schemes/cyclic_covers/constructor.py b/src/sage/schemes/cyclic_covers/constructor.py index 9a417676bdd..c3fe2684248 100644 --- a/src/sage/schemes/cyclic_covers/constructor.py +++ b/src/sage/schemes/cyclic_covers/constructor.py @@ -109,22 +109,14 @@ def CyclicCover(r, f, names=None, check_smooth=True): f = P(f) if check_smooth: if P(r) == 0: - raise ValueError( - "As the characteristic divides the order of the cover, " - "this model is not smooth." - ) + raise ValueError("As the characteristic divides the order of the cover, " "this model is not smooth.") try: smooth = f.is_squarefree() except NotImplementedError as err: - raise NotImplementedError( - str(err) + "Use " "check_smooth=False to skip this check." - ) + raise NotImplementedError(str(err) + "Use " "check_smooth=False to skip this check.") if not smooth: - raise ValueError( - "Not a smooth Cyclic Cover of P^1: " - "singularity in the provided affine patch." - ) + raise ValueError("Not a smooth Cyclic Cover of P^1: " "singularity in the provided affine patch.") R = P.base_ring() if names is None: names = ["x", "y"] diff --git a/src/sage/schemes/cyclic_covers/cycliccover_finite_field.py b/src/sage/schemes/cyclic_covers/cycliccover_finite_field.py index 7b00cceec7f..36fb17de14c 100644 --- a/src/sage/schemes/cyclic_covers/cycliccover_finite_field.py +++ b/src/sage/schemes/cyclic_covers/cycliccover_finite_field.py @@ -103,9 +103,7 @@ def _N0_nodenominators(p, g, n): sage: sage.schemes.cyclic_covers.cycliccover_finite_field._N0_nodenominators(4999, 4, 5) 11 """ - return max( - ceil(log(2 * (2 * g) / ZZ(i), p) + (n * i) / ZZ(2)) for i in range(1, g + 1) - ) + return max(ceil(log(2 * (2 * g) / ZZ(i), p) + (n * i) / ZZ(2)) for i in range(1, g + 1)) class CyclicCover_finite_field(cycliccover_generic.CyclicCover_generic): @@ -148,10 +146,7 @@ def _init_frob(self, desired_prec=None): """ def _N0_RH(): - return ceil( - log(2 * binomial(2 * self._genus, self._genus), self._p) - + self._genus * self._n / ZZ(2) - ) + return ceil(log(2 * binomial(2 * self._genus, self._genus), self._p) + self._genus * self._n / ZZ(2)) def _find_N0(): if self._nodenominators: @@ -192,10 +187,7 @@ def right_side_log(n): # our basis choice doesn't always give an integral matrix if self._epsilon == 0: - self._extraprec = floor( - log(self._r, self._p) - + log((2 * self._genus + (self._delta - 2)) / self._delta, self._p) - ) + self._extraprec = floor(log(self._r, self._p) + log((2 * self._genus + (self._delta - 2)) / self._delta, self._p)) else: self._extraprec = floor(log(self._r * 2 - 1, self._p)) @@ -220,9 +212,7 @@ def right_side_log(n): if not self._plarge: # we might have some denominators showing up during horizontal # and vertical reductions - self._extraworkingprec += 2 * ceil( - log(self._d * self._r * (self._N0 + self._epsilon), self._p) - ) + self._extraworkingprec += 2 * ceil(log(self._d * self._r * (self._N0 + self._epsilon), self._p)) # Rings if self._plarge and self._nodenominators: @@ -230,7 +220,7 @@ def right_side_log(n): # IntegerModRing is significantly faster than Zq self._Zq = IntegerModRing(self._p**self._N) if self._sqrtp: - self._Zq0 = IntegerModRing(self._p**(self._N - 1)) + self._Zq0 = IntegerModRing(self._p ** (self._N - 1)) self._Qq = Qq(self._p, prec=self._N, type='capped-rel') self._w = 1 else: @@ -262,12 +252,7 @@ def right_side_log(n): self._flift = self._Zqx([elt.lift() for elt in self._f.list()]) self._frobf = self._Zqx(self._flift.list()) else: # When n > 1, need to be more careful with the lift - self._flift = self._Zqx( - [ - elt.polynomial().change_ring(ZZ)(self._Zq.gen()) - for elt in self._f.list() - ] - ) + self._flift = self._Zqx([elt.polynomial().change_ring(ZZ)(self._Zq.gen()) for elt in self._f.list()]) self._frobf = self._Zqx([elt.frobenius() for elt in self._flift.list()]) @@ -315,10 +300,7 @@ def _divide_vector(self, D, vect, R): if not R.is_field(): vectQq = vector( self._Qq, - [ - m * self._Qq(elt).lift_to_precision(self._Qq.precision_cap()) - for elt in vect - ], + [m * self._Qq(elt).lift_to_precision(self._Qq.precision_cap()) for elt in vect], ) return vector(R, [R(elt) for elt in vectQq]) return vector(R, [(m * elt).lift_to_precision() for elt in vect]) @@ -420,17 +402,7 @@ def _extend_frobpow(power): _extend_frobpow(N0) r = self._r - Dj = [ - self._Zq( - sum( - [ - (-1) ** (k - l) * binomial(k, l) * binomial(-ZZ(j) / r, k) - for k in range(l, N0) - ] - ) - ) - for l in range(N0) - ] + Dj = [self._Zq(sum([(-1) ** (k - l) * binomial(k, l) * binomial(-ZZ(j) / r, k) for k in range(l, N0)])) for l in range(N0)] frobij = matrix(self._Zq, self._d * (N0 - 1) + 1, N0) for s in range(N0): for l in range(self._d * s + 1): @@ -526,20 +498,12 @@ def _horizontal_matrix_reduction(self, s): M1 = matrix( self._Zq, self._d, - lambda m, n: m1 - if m == n + 1 - else self._r * f_co[m] - if n == self._d - 1 - else 0, + lambda m, n: m1 if m == n + 1 else self._r * f_co[m] if n == self._d - 1 else 0, ) M0 = matrix( self._Zq, self._d, - lambda m, n: m0 - if m == n + 1 - else (self._r - s) * m * f_co[m] - if n == self._d - 1 - else 0, + lambda m, n: m0 if m == n + 1 else (self._r - s) * m * f_co[m] if n == self._d - 1 else 0, ) return ((m0, m1), (M0, M1)) @@ -584,20 +548,16 @@ def _vertical_matrix_reduction(self, s0): """ d = self._d - f_co = ( - [0 for i in range(d - 2)] + self._flift.list() + [0 for i in range(d - 1)] - ) - fd_co = ( - [0 for i in range(d - 1)] + self._dflift.list() + [0 for i in range(d)] - ) + f_co = [0 for i in range(d - 2)] + self._flift.list() + [0 for i in range(d - 1)] + fd_co = [0 for i in range(d - 1)] + self._dflift.list() + [0 for i in range(d)] - rows = [f_co[d - 2 - i:-i - 1] for i in range(d - 1)] - rows += [fd_co[d - 1 - i:-i - 1] for i in range(d)] + rows = [f_co[d - 2 - i : -i - 1] for i in range(d - 1)] + rows += [fd_co[d - 1 - i : -i - 1] for i in range(d)] m = matrix(rows).transpose().inverse() a_foo = m[0:d, 0:d] - b_foo = m[d - 1:2 * d - 1, 0:d] + b_foo = m[d - 1 : 2 * d - 1, 0:d] a_foo = matrix(d, d, lambda i, j: 1 if i == j and i != d - 1 else 0) * a_foo foo = matrix(d, d, lambda i, j: j if i == j - 1 else 0) bp_foo = foo * b_foo @@ -666,10 +626,7 @@ def _reduce_vector_horizontal_BSGS(self, G, e, s): if G == 0: return G if self._verbose > 2: - print( - "_reduce_vector_horizontal_BSGS(self, %s, %s, %s)" - % (vector(self._Qq, G), e, s) - ) + print("_reduce_vector_horizontal_BSGS(self, %s, %s, %s)" % (vector(self._Qq, G), e, s)) assert (e + 1) % self._p == 0 (m0, m1), (M0, M1) = self._horizontal_matrix_reduction(s) vect = vector(self._Zq, G) @@ -697,10 +654,7 @@ def _reduce_vector_horizontal_BSGS(self, G, e, s): vect = Di * (Mi * vect.change_ring(self._Zq)) if self._verbose > 2: - print( - "done _reduce_vector_horizontal_BSGS(self, %s, %s, %s)" - % (vector(self._Qq, G), e, s) - ) + print("done _reduce_vector_horizontal_BSGS(self, %s, %s, %s)" % (vector(self._Qq, G), e, s)) print("return %s\n" % (vector(self._Qq, vect),)) return vect @@ -787,10 +741,7 @@ def _reduce_vector_horizontal_plain(self, G, e, s, k=1): True """ if self._verbose > 2: - print( - "_reduce_vector_horizontal_plain(self, G = %s, e = %s, s = %s, k = %s)" - % (vector(self._Qq, G), e, s, k) - ) + print("_reduce_vector_horizontal_plain(self, G = %s, e = %s, s = %s, k = %s)" % (vector(self._Qq, G), e, s, k)) if G == 0: return G (m0, m1), (M0, M1) = self._horizontal_matrix_reduction(s) @@ -812,10 +763,7 @@ def _reduce_vector_horizontal_plain(self, G, e, s, k=1): vect = self._divide_vector(D, vect, self._Zq) if self._verbose > 2: - print( - "done _reduce_vector_horizontal_plain(self, %s, %s, %s, %s)" - % (vector(self._Qq, G), e, s, k) - ) + print("done _reduce_vector_horizontal_plain(self, %s, %s, %s, %s)" % (vector(self._Qq, G), e, s, k)) print("return %s\n" % (vector(self._Qq, vect),)) return vect @@ -854,10 +802,7 @@ def _reduce_vector_vertical_plain(G, s0, s, k=1): `G y^{-(r*s + s0)} dx \cong H y^{-(r*(s -k) + s0)} dx` """ if self._verbose > 2: - print( - "_reduce_vector_vertical(self, G = %s, s0 = %s, s = %s, k = %s)" - % (vector(self._Qq, G), s0, s, k) - ) + print("_reduce_vector_vertical(self, G = %s, s0 = %s, s = %s, k = %s)" % (vector(self._Qq, G), s0, s, k)) (m0, m1), (M0, M1) = self._vertical_matrix_reduction(s0) vect = vector(self._Zq, G) @@ -876,10 +821,7 @@ def _reduce_vector_vertical_plain(G, s0, s, k=1): vect = self._divide_vector(D, vect, self._Zq) if self._verbose > 2: - print( - "done _reduce_vector_vertical(self, %s, %s, %s)" - % (vector(self._Qq, G), s, k) - ) + print("done _reduce_vector_vertical(self, %s, %s, %s)" % (vector(self._Qq, G), s, k)) print("return %s\n" % (vector(self._Qq, vect),)) return vect @@ -929,10 +871,7 @@ def _initialize_fat_vertical(self, s0, max_upper_target): iD = 1 / self._Zq(D.lift() / self._p) MV[l] = matrix( self._Zq, - [ - [iD * ZZ(elt.lift() / self._p) for elt in row] - for row in MV[l].rows() - ], + [[iD * ZZ(elt.lift() / self._p) for elt in row] for row in MV[l].rows()], ) else: MV[l] *= 1 / D @@ -985,9 +924,7 @@ def _frob(self, i, j, N0): for s in reversed(range(N0)): if self._sqrtp: # (i + 1) <= d - self._initialize_fat_horizontal( - p * j + p * r * s, d * s + (d - 2) + 1 - ) # d * (s + 1) ) + self._initialize_fat_horizontal(p * j + p * r * s, d * s + (d - 2) + 1) # d * (s + 1) ) # G represents G(x) * x^(p ** l - 1) y^(-p(j + r*s)) /dx G = vector(self._Zq, d) for ell in reversed(range(1, d * s + (i + 1) + 1)): @@ -1056,9 +993,10 @@ def _frobenius_matrix_p(N0): for j in range(1, self._r): s0 = (j * self._p) % self._r for i in range(self._d - 1): - m[(s0 - 1) * (self._d - 1):s0 * (self._d - 1), - i + (j - 1) * (self._d - 1), - ] = self._frob(i, j + self._epsilon * self._r, N0) + m[ + (s0 - 1) * (self._d - 1) : s0 * (self._d - 1), + i + (j - 1) * (self._d - 1), + ] = self._frob(i, j + self._epsilon * self._r, N0) return m self._init_frob(N) @@ -1069,9 +1007,7 @@ def _frobenius_matrix_p(N0): current = FrobP total = FrobP for i in range(self._n - 1): - current = matrix( - [[entry.frobenius() for entry in row] for row in current] - ) + current = matrix([[entry.frobenius() for entry in row] for row in current]) total = total * current total = matrix([[elt.add_bigoh(self._N0) for elt in row] for row in total]) return total @@ -1251,11 +1187,11 @@ def _denominator(): phi = euler_phi(i) G = IntegerModRing(i) ki = G(self._q).multiplicative_order() - denom = denom * (T ** ki - 1) ** (phi // ki) + denom = denom * (T**ki - 1) ** (phi // ki) return denom # Non-monic x = PolynomialRing(self._Fq, "x").gen() - f = x ** self._delta - lc + f = x**self._delta - lc L = f.splitting_field("a") roots = [r for r, _ in f.change_ring(L).roots()] roots_dict = {r: i for i, r in enumerate(roots)} @@ -1276,9 +1212,7 @@ def _denominator(): if min_val >= 0: prec = _N0_nodenominators(self._p, self._genus, self._n) - charpoly_prec = [prec + i for i in reversed(range(1, self._genus + 1))] + [ - prec - ] * (self._genus + 1) + charpoly_prec = [prec + i for i in reversed(range(1, self._genus + 1))] + [prec] * (self._genus + 1) cp = charpoly_frobenius(F, charpoly_prec, self._p, 1, self._n, denom.list()) return R(cp) cp = F.charpoly().reverse() @@ -1288,7 +1222,7 @@ def _denominator(): cp = cp.padded_list(self._genus + 1) cpZZ = [None for _ in range(2 * self._genus + 1)] cpZZ[0] = 1 - cpZZ[-1] = self._p ** self._genus + cpZZ[-1] = self._p**self._genus for i in range(1, self._genus + 1): cmod = cp[i] bound = binomial(2 * self._genus, i) * self._p ** (i * self._n * 0.5) diff --git a/src/sage/schemes/cyclic_covers/cycliccover_generic.py b/src/sage/schemes/cyclic_covers/cycliccover_generic.py index 99fa53b543d..6e74e00dae0 100644 --- a/src/sage/schemes/cyclic_covers/cycliccover_generic.py +++ b/src/sage/schemes/cyclic_covers/cycliccover_generic.py @@ -173,11 +173,7 @@ def __eq__(self, other): if not isinstance(other, CyclicCover_generic): return False - return ( - (self.base_ring() == other.base_ring()) - and (self._r == other._r) - and (self._f == other._f) - ) + return (self.base_ring() == other.base_ring()) and (self._r == other._r) and (self._f == other._f) def __ne__(self, other): """ diff --git a/src/sage/schemes/elliptic_curves/BSD.py b/src/sage/schemes/elliptic_curves/BSD.py index 00c6d0bd9e4..151bf4b2717 100644 --- a/src/sage/schemes/elliptic_curves/BSD.py +++ b/src/sage/schemes/elliptic_curves/BSD.py @@ -24,6 +24,7 @@ class BSD_data: Tate-Shafarevich group for the Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field """ + def __init__(self) -> None: self.curve = None self.two_tor_rk = None @@ -186,6 +187,7 @@ def native_two_isogeny_descent_work(E, two_tor_rk) -> tuple: (1, 1, 0, 0, None) """ from sage.schemes.elliptic_curves.descent_two_isogeny import two_descent_by_two_isogeny + result_two_descent = [ZZ(n) for n in two_descent_by_two_isogeny(E)] # safety check that all numbers in the result are powers of two if not all(n.is_power_of(2) for n in result_two_descent): @@ -243,8 +245,7 @@ def heegner_index_work(E) -> tuple: return I, D -def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, - return_BSD=False): +def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, return_BSD=False): r""" Attempt to prove the Birch and Swinnerton-Dyer conjectural formula for `E`, returning a list of primes `p` for which this @@ -455,6 +456,7 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, """ if proof is None: from sage.structure.proof.proof import get_flag + proof = get_flag(proof, "elliptic_curve") else: proof = bool(proof) @@ -498,7 +500,7 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, BSD.bounds[2] = (sha2_lower_bd, sha2_upper_bd) else: BSD.rank = BSD.curve.rank(use_database=True) - sha2_upper_bd -= (BSD.rank - rank_lower_bd) + sha2_upper_bd -= BSD.rank - rank_lower_bd BSD.bounds[2] = (sha2_lower_bd, sha2_upper_bd) if verbosity > 0: print("Unable to compute the rank exactly -- used database.") @@ -507,6 +509,7 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, # an open problem to show that L^r(E,1)/(Reg*Omega) is # rational for any curve with r >= 2. from sage.sets.primes import Primes + BSD.primes = Primes() if return_BSD: BSD.rank = rank_lower_bd @@ -594,10 +597,12 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, # p is inert in K BSD.primes.append(p) - kolyvagin_primes.extend(p for p in heegner_primes - # p is good for E and inert in K - if p >= 5 and D_E % p and D_K % p - and len(K.factor(p)) == 1) + kolyvagin_primes.extend( + p + for p in heegner_primes + # p is good for E and inert in K + if p >= 5 and D_E % p and D_K % p and len(K.factor(p)) == 1 + ) for p in prime_divisors(BSD.sha_an): if p >= 5 and D_K % p and len(K.factor(p)) == 1: @@ -750,7 +755,7 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, for D in BSD.heegner_index_upper_bound: M = BSD.heegner_index_upper_bound[D] ord_p_bound = 0 - while p**(ord_p_bound + 1) <= M**2: + while p ** (ord_p_bound + 1) <= M**2: ord_p_bound += 1 # now ord_p_bound is one on I_K!!! ord_p_bound *= 2 # by Kolyvagin, now ord_p_bound is one on #Sha @@ -838,7 +843,7 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, if verbosity > 0: print(' p = %d: Trying harder for Heegner index' % p) obt = 0 - while p**(BSD.sha_an.ord(p) / 2 + 1) <= M and max_height < 22: + while p ** (BSD.sha_an.ord(p) / 2 + 1) <= M and max_height < 22: if verbosity > 2: print(' trying max_height =', max_height) old_bound = M @@ -864,7 +869,7 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, BSD.heegner_index_upper_bound[D] = min(M, BSD.heegner_index_upper_bound[D]) low, upp = BSD.bounds[p] expn = 0 - while p**(expn + 1) <= M: + while p ** (expn + 1) <= M: expn += 1 if 2 * expn < upp: upp = 2 * expn @@ -894,7 +899,7 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, if verbosity > 2: print(' trying max_height =', max_height) old_bound = M - if p**(BSD.sha_an.ord(p) / 2 + 1) > M or max_height >= 22: + if p ** (BSD.sha_an.ord(p) / 2 + 1) > M or max_height >= 22: break M, _, exact = BSD.curve.heegner_index_bound(D, max_height=max_height, secs_dc=secs_hi) if M == -1: @@ -918,7 +923,7 @@ def prove_BSD(E, verbosity=0, two_desc='mwrank', proof=None, secs_hi=5, BSD.heegner_index_upper_bound[D] = M low, upp = BSD.bounds[p] expn = 0 - while p**(expn + 1) <= M: + while p ** (expn + 1) <= M: expn += 1 if 2 * expn < upp: upp = 2 * expn diff --git a/src/sage/schemes/elliptic_curves/Qcurves.py b/src/sage/schemes/elliptic_curves/Qcurves.py index 992be3b219f..bc5cd5ef927 100644 --- a/src/sage/schemes/elliptic_curves/Qcurves.py +++ b/src/sage/schemes/elliptic_curves/Qcurves.py @@ -8,6 +8,7 @@ The code here implements the algorithm of Cremona and Najman presented in [CrNa2020]_. """ + ############################################################################## # Copyright (C) 2020-2021 John Cremona # @@ -324,8 +325,7 @@ def is_Q_curve(E, maxp=100, certificate=False, verbose=False): level = lcm(core_degs) if level.is_squarefree(): r = len(level.prime_divisors()) - cert = {'CM': ZZ(0), 'core_poly': f, 'rho': rho, - 'r': r, 'N': level, 'core_degs': core_degs} + cert = {'CM': ZZ(0), 'core_poly': f, 'rho': rho, 'r': r, 'N': level, 'core_degs': core_degs} return True, cert print("No central curve found") else: @@ -445,6 +445,7 @@ def Step4Test(E, B, oldB=0, verbose=False): (True, 0) """ from sage.arith.misc import primes + K = E.base_field() NN = E.conductor().norm() for p in primes(B): @@ -471,7 +472,7 @@ def Step4Test(E, B, oldB=0, verbose=False): # else compare a_P^2-4*N(P) which should have the same squarefree part: - discs = [(Ei.trace_of_frobenius()**2 - 4 * P.norm()).squarefree_part() for P, Ei in zip(Plist, EmodP)] + discs = [(Ei.trace_of_frobenius() ** 2 - 4 * P.norm()).squarefree_part() for P, Ei in zip(Plist, EmodP)] if any(d != discs[0] for d in discs[1:]): if verbose: print("No: inconsistency at the {} ordinary primes dividing {} ".format(len(Plist), p)) diff --git a/src/sage/schemes/elliptic_curves/addition_formulas_ring.py b/src/sage/schemes/elliptic_curves/addition_formulas_ring.py index 78dffcfe939..6b121360704 100644 --- a/src/sage/schemes/elliptic_curves/addition_formulas_ring.py +++ b/src/sage/schemes/elliptic_curves/addition_formulas_ring.py @@ -67,27 +67,43 @@ def _add(E, P, Q): # by caching common subexpressions. This could almost certainly be # sped up significantly with some more serious optimization effort. - XYdif = X1*Y2 - X2*Y1 - XYsum = X1*Y2 + X2*Y1 - XZdif = X1*Z2 - X2*Z1 - XZsum = X1*Z2 + X2*Z1 - YZdif = Y1*Z2 - Y2*Z1 - YZsum = Y1*Z2 + Y2*Z1 + XYdif = X1 * Y2 - X2 * Y1 + XYsum = X1 * Y2 + X2 * Y1 + XZdif = X1 * Z2 - X2 * Z1 + XZsum = X1 * Z2 + X2 * Z1 + YZdif = Y1 * Z2 - Y2 * Z1 + YZsum = Y1 * Z2 + Y2 * Z1 a1sq, a2sq, a3sq, a4sq = (a**2 for a in (a1, a2, a3, a4)) - X31 = XYdif*YZsum+XZdif*Y1*Y2+a1*X1*X2*YZdif+a1*XYdif*XZsum-a2*X1*X2*XZdif+a3*XYdif*Z1*Z2+a3*XZdif*YZsum-a4*XZsum*XZdif-3*a6*XZdif*Z1*Z2 + X31 = XYdif * YZsum + XZdif * Y1 * Y2 + a1 * X1 * X2 * YZdif + a1 * XYdif * XZsum - a2 * X1 * X2 * XZdif + a3 * XYdif * Z1 * Z2 + a3 * XZdif * YZsum - a4 * XZsum * XZdif - 3 * a6 * XZdif * Z1 * Z2 - Y31 = -3*X1*X2*XYdif-Y1*Y2*YZdif-2*a1*XZdif*Y1*Y2+(a1sq+3*a2)*X1*X2*YZdif-(a1sq+a2)*XYsum*XZdif+(a1*a2-3*a3)*X1*X2*XZdif-(2*a1*a3+a4)*XYdif*Z1*Z2+a4*XZsum*YZdif+(a1*a4-a2*a3)*XZsum*XZdif+(a3sq+3*a6)*YZdif*Z1*Z2+(3*a1*a6-a3*a4)*XZdif*Z1*Z2 + Y31 = -3 * X1 * X2 * XYdif - Y1 * Y2 * YZdif - 2 * a1 * XZdif * Y1 * Y2 + (a1sq + 3 * a2) * X1 * X2 * YZdif - (a1sq + a2) * XYsum * XZdif + (a1 * a2 - 3 * a3) * X1 * X2 * XZdif - (2 * a1 * a3 + a4) * XYdif * Z1 * Z2 + a4 * XZsum * YZdif + (a1 * a4 - a2 * a3) * XZsum * XZdif + (a3sq + 3 * a6) * YZdif * Z1 * Z2 + (3 * a1 * a6 - a3 * a4) * XZdif * Z1 * Z2 - Z31 = 3*X1*X2*XZdif-YZsum*YZdif+a1*XYdif*Z1*Z2-a1*XZdif*YZsum+a2*XZsum*XZdif-a3*YZdif*Z1*Z2+a4*XZdif*Z1*Z2 + Z31 = 3 * X1 * X2 * XZdif - YZsum * YZdif + a1 * XYdif * Z1 * Z2 - a1 * XZdif * YZsum + a2 * XZsum * XZdif - a3 * YZdif * Z1 * Z2 + a4 * XZdif * Z1 * Z2 yield (X31, Y31, Z31) - X32 = Y1*Y2*XYsum+a1*(2*X1*Y2+X2*Y1)*X2*Y1+a1sq*X1*X2**2*Y1-a2*X1*X2*XYsum-a1*a2*X1**2*X2**2+a3*X2*Y1*(YZsum+Y2*Z1)+a1*a3*X1*X2*YZdif-a1*a3*XYsum*XZdif-a4*X1*X2*YZsum-a4*XYsum*XZsum-a1sq*a3*X1**2*X2*Z2-a1*a4*X1*X2*(X1*Z2+XZsum)-a2*a3*X1*X2**2*Z1-a3sq*X1*Z2*(Y2*Z1+YZsum)-3*a6*XYsum*Z1*Z2-3*a6*XZsum*YZsum-a1*a3sq*X1*Z2*(XZsum+X2*Z1)-3*a1*a6*X1*Z2*(XZsum+X2*Z1)-a3*a4*(X1*Z2+XZsum)*X2*Z1-b8*YZsum*Z1*Z2-a1*b8*X1*Z1*Z2**2-a3**3*XZsum*Z1*Z2-3*a3*a6*(XZsum+X2*Z1)*Z1*Z2-a3*b8*Z1**2*Z2**2 - - Y32 = Y1**2*Y2**2+a1*X2*Y1**2*Y2+(a1*a2-3*a3)*X1*X2**2*Y1+a3*Y1**2*Y2*Z2-(a2sq-3*a4)*X1**2*X2**2+(a1*a4-a2*a3)*(2*X1*Z2+X2*Z1)*X2*Y1+(a1sq*a4-2*a1*a2*a3+3*a3sq)*X1**2*X2*Z2-(a2*a4-9*a6)*X1*X2*XZsum+(3*a1*a6-a3*a4)*(XZsum+X2*Z1)*Y1*Z2+(3*a1sq*a6-2*a1*a3*a4+a2*a3sq+3*a2*a6-a4sq)*X1*Z2*(XZsum+X2*Z1)+(3*a2*a6-a4sq)*X2*Z1*(2*X1*Z2+Z1*X2)+(a1**3*a6-a1sq*a3*a4+a1*a2*a3sq-a1*a4sq+4*a1*a2*a6-a3**3-3*a3*a6)*Y1*Z1*Z2**2+(a1**4*a6-a1**3*a3*a4+5*a1sq*a2*a6+a1sq*a2*a3sq-a1*a2*a3*a4-a1*a3**3-3*a1*a3*a6-a1sq*a4sq+a2sq*a3sq-a2*a4sq+4*a2sq*a6-a3**2*a4-3*a4*a6)*X1*Z1*Z2**2+(a1sq*a2*a6-a1*a2*a3*a4+3*a1*a3*a6+a2sq*a3sq-a2*a4sq+4*a2sq*a6-2*a3sq*a4-3*a4*a6)*X2*Z1**2*Z2+(a1**3*a3*a6-a1sq*a3sq*a4+a1sq*a4*a6+a1*a2*a3**3+4*a1*a2*a3*a6-2*a1*a3*a4sq+a2*a3sq*a4+4*a2*a4*a6-a3**4-6*a3**2*a6-a4**3-9*a6**2)*Z1**2*Z2**2 - - Z32 = 3*X1*X2*XYsum+Y1*Y2*YZsum+3*a1*X1**2*X2**2+a1*(2*X1*Y2+Y1*X2)*Y1*Z2+a1sq*X1*Z2*(2*X2*Y1+X1*Y2)+a2*X1*X2*YZsum+a2*XYsum*XZsum+a1**3*X1**2*X2*Z2+a1*a2*X1*X2*(2*X1*Z2+X2*Z1)+3*a3*X1*X2**2*Z1+a3*Y1*Z2*(YZsum+Y2*Z1)+2*a1*a3*X1*Z2*YZsum+2*a1*a3*X2*Y1*Z1*Z2+a4*XYsum*Z1*Z2+a4*XZsum*YZsum+(a1sq*a3+a1*a4)*X1*Z2*(XZsum+X2*Z1)+a2*a3*X2*Z1*(2*X1*Z2+X2*Z1)+a3sq*Y1*Z1*Z2**2+(a3sq+3*a6)*YZsum*Z1*Z2+a1*a3sq*(2*X1*Z2+X2*Z1)*Z1*Z2+3*a1*a6*X1*Z1*Z2**2+a3*a4*(XZsum+X2*Z1)*Z1*Z2+(a3**3+3*a3*a6)*Z1**2*Z2**2 + X32 = Y1 * Y2 * XYsum + a1 * (2 * X1 * Y2 + X2 * Y1) * X2 * Y1 + a1sq * X1 * X2**2 * Y1 - a2 * X1 * X2 * XYsum - a1 * a2 * X1**2 * X2**2 + a3 * X2 * Y1 * (YZsum + Y2 * Z1) + a1 * a3 * X1 * X2 * YZdif - a1 * a3 * XYsum * XZdif - a4 * X1 * X2 * YZsum - a4 * XYsum * XZsum - a1sq * a3 * X1**2 * X2 * Z2 - a1 * a4 * X1 * X2 * (X1 * Z2 + XZsum) - a2 * a3 * X1 * X2**2 * Z1 - a3sq * X1 * Z2 * (Y2 * Z1 + YZsum) - 3 * a6 * XYsum * Z1 * Z2 - 3 * a6 * XZsum * YZsum - a1 * a3sq * X1 * Z2 * (XZsum + X2 * Z1) - 3 * a1 * a6 * X1 * Z2 * (XZsum + X2 * Z1) - a3 * a4 * (X1 * Z2 + XZsum) * X2 * Z1 - b8 * YZsum * Z1 * Z2 - a1 * b8 * X1 * Z1 * Z2**2 - a3**3 * XZsum * Z1 * Z2 - 3 * a3 * a6 * (XZsum + X2 * Z1) * Z1 * Z2 - a3 * b8 * Z1**2 * Z2**2 + + Y32 = ( + Y1**2 * Y2**2 + + a1 * X2 * Y1**2 * Y2 + + (a1 * a2 - 3 * a3) * X1 * X2**2 * Y1 + + a3 * Y1**2 * Y2 * Z2 + - (a2sq - 3 * a4) * X1**2 * X2**2 + + (a1 * a4 - a2 * a3) * (2 * X1 * Z2 + X2 * Z1) * X2 * Y1 + + (a1sq * a4 - 2 * a1 * a2 * a3 + 3 * a3sq) * X1**2 * X2 * Z2 + - (a2 * a4 - 9 * a6) * X1 * X2 * XZsum + + (3 * a1 * a6 - a3 * a4) * (XZsum + X2 * Z1) * Y1 * Z2 + + (3 * a1sq * a6 - 2 * a1 * a3 * a4 + a2 * a3sq + 3 * a2 * a6 - a4sq) * X1 * Z2 * (XZsum + X2 * Z1) + + (3 * a2 * a6 - a4sq) * X2 * Z1 * (2 * X1 * Z2 + Z1 * X2) + + (a1**3 * a6 - a1sq * a3 * a4 + a1 * a2 * a3sq - a1 * a4sq + 4 * a1 * a2 * a6 - a3**3 - 3 * a3 * a6) * Y1 * Z1 * Z2**2 + + (a1**4 * a6 - a1**3 * a3 * a4 + 5 * a1sq * a2 * a6 + a1sq * a2 * a3sq - a1 * a2 * a3 * a4 - a1 * a3**3 - 3 * a1 * a3 * a6 - a1sq * a4sq + a2sq * a3sq - a2 * a4sq + 4 * a2sq * a6 - a3**2 * a4 - 3 * a4 * a6) * X1 * Z1 * Z2**2 + + (a1sq * a2 * a6 - a1 * a2 * a3 * a4 + 3 * a1 * a3 * a6 + a2sq * a3sq - a2 * a4sq + 4 * a2sq * a6 - 2 * a3sq * a4 - 3 * a4 * a6) * X2 * Z1**2 * Z2 + + (a1**3 * a3 * a6 - a1sq * a3sq * a4 + a1sq * a4 * a6 + a1 * a2 * a3**3 + 4 * a1 * a2 * a3 * a6 - 2 * a1 * a3 * a4sq + a2 * a3sq * a4 + 4 * a2 * a4 * a6 - a3**4 - 6 * a3**2 * a6 - a4**3 - 9 * a6**2) * Z1**2 * Z2**2 + ) + + Z32 = 3 * X1 * X2 * XYsum + Y1 * Y2 * YZsum + 3 * a1 * X1**2 * X2**2 + a1 * (2 * X1 * Y2 + Y1 * X2) * Y1 * Z2 + a1sq * X1 * Z2 * (2 * X2 * Y1 + X1 * Y2) + a2 * X1 * X2 * YZsum + a2 * XYsum * XZsum + a1**3 * X1**2 * X2 * Z2 + a1 * a2 * X1 * X2 * (2 * X1 * Z2 + X2 * Z1) + 3 * a3 * X1 * X2**2 * Z1 + a3 * Y1 * Z2 * (YZsum + Y2 * Z1) + 2 * a1 * a3 * X1 * Z2 * YZsum + 2 * a1 * a3 * X2 * Y1 * Z1 * Z2 + a4 * XYsum * Z1 * Z2 + a4 * XZsum * YZsum + (a1sq * a3 + a1 * a4) * X1 * Z2 * (XZsum + X2 * Z1) + a2 * a3 * X2 * Z1 * (2 * X1 * Z2 + X2 * Z1) + a3sq * Y1 * Z1 * Z2**2 + (a3sq + 3 * a6) * YZsum * Z1 * Z2 + a1 * a3sq * (2 * X1 * Z2 + X2 * Z1) * Z1 * Z2 + 3 * a1 * a6 * X1 * Z1 * Z2**2 + a3 * a4 * (XZsum + X2 * Z1) * Z1 * Z2 + (a3**3 + 3 * a3 * a6) * Z1**2 * Z2**2 yield (X32, Y32, Z32) diff --git a/src/sage/schemes/elliptic_curves/all.py b/src/sage/schemes/elliptic_curves/all.py index df527315527..17f16e5046b 100644 --- a/src/sage/schemes/elliptic_curves/all.py +++ b/src/sage/schemes/elliptic_curves/all.py @@ -17,24 +17,17 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.schemes.elliptic_curves.constructor import (EllipticCurve, - EllipticCurve_from_c4c6, - EllipticCurve_from_j, - EllipticCurve_from_cubic, - EllipticCurves_with_good_reduction_outside_S) +from sage.schemes.elliptic_curves.constructor import EllipticCurve, EllipticCurve_from_c4c6, EllipticCurve_from_j, EllipticCurve_from_cubic, EllipticCurves_with_good_reduction_outside_S from sage.misc.lazy_import import lazy_import + lazy_import('sage.schemes.elliptic_curves.jacobian', 'Jacobian') lazy_import('sage.schemes.elliptic_curves.ell_finite_field', 'special_supersingular_curve') -lazy_import('sage.schemes.elliptic_curves.ell_rational_field', - ['cremona_curves', 'cremona_optimal_curves']) +lazy_import('sage.schemes.elliptic_curves.ell_rational_field', ['cremona_curves', 'cremona_optimal_curves']) from sage.schemes.elliptic_curves.ell_finite_field import EllipticCurve_with_prime_order -from sage.schemes.elliptic_curves.cm import (cm_orders, - cm_j_invariants, - cm_j_invariants_and_orders, - hilbert_class_polynomial) +from sage.schemes.elliptic_curves.cm import cm_orders, cm_j_invariants, cm_j_invariants_and_orders, hilbert_class_polynomial lazy_import('sage.schemes.elliptic_curves.ec_database', 'elliptic_curves') @@ -45,4 +38,5 @@ lazy_import('sage.schemes.elliptic_curves.mod_poly', 'classical_modular_polynomial') from sage.schemes.elliptic_curves.heegner import heegner_points, heegner_point + del lazy_import diff --git a/src/sage/schemes/elliptic_curves/cardinality.py b/src/sage/schemes/elliptic_curves/cardinality.py index e187e7bccd0..64e9150eac5 100644 --- a/src/sage/schemes/elliptic_curves/cardinality.py +++ b/src/sage/schemes/elliptic_curves/cardinality.py @@ -157,8 +157,8 @@ def _cardinality_with_j_invariant_1728(self): # unity, so the traces are 2*pi, -2*pi, 0, -pi, +pi; # -pi, +pi. delta = self.discriminant() - discube = (delta**((q - 1) // 3) == k(1)) - pi = (-2)**(d // 2) + discube = delta ** ((q - 1) // 3) == k(1) + pi = (-2) ** (d // 2) if discube: a = k.gen() b = a @@ -192,7 +192,7 @@ def _cardinality_with_j_invariant_1728(self): u = delta.sqrt() if not u.is_square(): u = -u - tr = ((self.a3()**2 + self.a6()) / u).trace() + tr = ((self.a3() ** 2 + self.a6()) / u).trace() if tr == 0: t = 0 else: @@ -214,9 +214,9 @@ def _cardinality_with_j_invariant_1728(self): A4 = self.a4() - self.a1() * self.a3() # = -b4 = 2*b4 if A4.is_square(): u = A4.sqrt() - t = (-3)**(d // 2) + t = (-3) ** (d // 2) i = k(-1).sqrt() - A6 = self.a3()**2 + self.a6() # = b6 + A6 = self.a3() ** 2 + self.a6() # = b6 if (A6 / (i * u * A4)).trace() == 0: t *= 2 else: @@ -234,8 +234,8 @@ def _cardinality_with_j_invariant_1728(self): if d % 2: t = 0 else: - t = (-p)**(d // 2) - w = (self.c4() / k(48))**((q - 1) // 4) + t = (-p) ** (d // 2) + w = (self.c4() / k(48)) ** ((q - 1) // 4) if w == 1: t = 2 * t elif w == -1: @@ -255,7 +255,7 @@ def _cardinality_with_j_invariant_1728(self): a, b = -b, a if (a + b + 1) % 4 == 0: a, b = -a, -b - pi = a + b * i # Now pi=a+b*i with (a,b)=(1,0),(3,2) mod 4 + pi = a + b * i # Now pi=a+b*i with (a,b)=(1,0),(3,2) mod 4 # Lift to Frobenius for [0,0,0,-1,0] over GF(p^d): if d > 1: @@ -263,7 +263,7 @@ def _cardinality_with_j_invariant_1728(self): a, b = pi.list() # Compute appropriate quartic twist: - w = (self.c4() / k(48))**((q - 1) // 4) + w = (self.c4() / k(48)) ** ((q - 1) // 4) if w == 1: t = 2 * a elif w == -1: @@ -323,8 +323,8 @@ def _cardinality_with_j_invariant_0(self): if d % 2: t = 0 else: - t = (-p)**(d // 2) - w = (self.c6() / k(-864))**((q - 1) // 6) + t = (-p) ** (d // 2) + w = (self.c6() / k(-864)) ** ((q - 1) // 6) if w == 1: t = 2 * t elif w == -1: @@ -352,18 +352,18 @@ def _cardinality_with_j_invariant_0(self): a, b = pi.list() # Compute appropriate sextic twist: - w = (self.c6() / k(-864))**((q - 1) // 6) + w = (self.c6() / k(-864)) ** ((q - 1) // 6) if w == 1: t = 2 * a + b # = Trace(pi) elif w == -1: t = -2 * a - b # = Trace(-pi) elif w == z: - t = a - b # = Trace(pi*zeta6) + t = a - b # = Trace(pi*zeta6) elif w == z**2: t = -a - 2 * b # = Trace(pi*zeta6**2) elif w == z**4: - t = b - a # = Trace(pi*zeta6**4) + t = b - a # = Trace(pi*zeta6**4) elif w == z**5: t = a + 2 * b # = Trace(pi*zeta6**5) @@ -387,8 +387,7 @@ def cardinality_exhaustive(self): sage: E.cardinality_exhaustive() 64 """ - self._order = Integer(1 + sum(len(self.lift_x(x, all=True)) - for x in self.base_field())) + self._order = Integer(1 + sum(len(self.lift_x(x, all=True)) for x in self.base_field())) return self._order @@ -451,21 +450,21 @@ def cardinality_bsgs(self, verbose=False): # kmin=kmax. if q > 2**10: - N1 = ZZ(2)**sum([e for P, e in E1._p_primary_torsion_basis(2)]) - N2 = ZZ(2)**sum([e for P, e in E2._p_primary_torsion_basis(2)]) + N1 = ZZ(2) ** sum([e for P, e in E1._p_primary_torsion_basis(2)]) + N2 = ZZ(2) ** sum([e for P, e in E2._p_primary_torsion_basis(2)]) if q > 2**20: - N1 *= ZZ(3)**sum([e for P, e in E1._p_primary_torsion_basis(3)]) - N2 *= ZZ(3)**sum([e for P, e in E2._p_primary_torsion_basis(3)]) + N1 *= ZZ(3) ** sum([e for P, e in E1._p_primary_torsion_basis(3)]) + N2 *= ZZ(3) ** sum([e for P, e in E2._p_primary_torsion_basis(3)]) if q > 2**40: - N1 *= ZZ(5)**sum([e for P, e in E1._p_primary_torsion_basis(5)]) - N2 *= ZZ(5)**sum([e for P, e in E2._p_primary_torsion_basis(5)]) + N1 *= ZZ(5) ** sum([e for P, e in E1._p_primary_torsion_basis(5)]) + N2 *= ZZ(5) ** sum([e for P, e in E2._p_primary_torsion_basis(5)]) # We now know that t=q+1 (mod N1) and t=-(q+1) (mod N2) a = q1 M = N1 g, u, v = M.xgcd(N2) # g==u*M+v*N2 if N2 > g: a = (a * v * N2 - q1 * u * M) // g - M *= (N2 // g) # = lcm(M,N2) + M *= N2 // g # = lcm(M,N2) a = a % M if verbose: print("(a,M)=", (a, M)) @@ -497,7 +496,7 @@ def cardinality_bsgs(self, verbose=False): if n > g: # update congruence a (mod M) with q+1 (mod n) a = (a * v * n + q1 * u * M) // g - M *= (n // g) # = lcm(M,n) + M *= n // g # = lcm(M,n) a = a % M if verbose: print("(a,M)=", (a, M)) @@ -521,7 +520,7 @@ def cardinality_bsgs(self, verbose=False): if n > g: # update congruence a (mod M) with -(q+1) (mod n) a = (a * v * n - q1 * u * M) // g - M *= (n // g) # = lcm(M,n) + M *= n // g # = lcm(M,n) a = a % M if verbose: print("(a,M)=", (a, M)) diff --git a/src/sage/schemes/elliptic_curves/cm.py b/src/sage/schemes/elliptic_curves/cm.py index ca882826b4c..e031d7fcf60 100644 --- a/src/sage/schemes/elliptic_curves/cm.py +++ b/src/sage/schemes/elliptic_curves/cm.py @@ -115,10 +115,12 @@ def hilbert_class_polynomial(D, algorithm=None): if algorithm == "arb": import sage.libs.arb.arith + return sage.libs.arb.arith.hilbert_class_polynomial(D) if algorithm == "magma": from sage.interfaces.magma import magma + magma.eval("R := PolynomialRing(IntegerRing())") f = str(magma.eval("HilbertClassPolynomial(%s)" % D)) return IntegerRing()['x'](f) @@ -153,11 +155,11 @@ def hilbert_class_polynomial(D, algorithm=None): # # independently of j", where k_2 \approx 10.163. - h = len(rqf) # class number - c1 = 3.05682737291380 # log(2*10.63) - c2 = sum([1/RR(qf[0]) for qf in rqf], RR(0)) + h = len(rqf) # class number + c1 = 3.05682737291380 # log(2*10.63) + c2 = sum([1 / RR(qf[0]) for qf in rqf], RR(0)) prec = c2 * RR(3.142) * RR(D).abs().sqrt() + h * c1 # bound on log - prec = prec * 1.45 # bound on log_2 (1/log(2) = 1.44..) + prec = prec * 1.45 # bound on log_2 (1/log(2) = 1.44..) prec = 10 + prec.ceil() # allow for rounding error # set appropriate precision for further computing @@ -169,7 +171,7 @@ def hilbert_class_polynomial(D, algorithm=None): for qf in rqf: a, b, c = list(qf) tau = (b + Dsqrt) / (a << 1) - pol *= (t - elliptic_j(tau)) + pol *= t - elliptic_j(tau) coeffs = [cof.real().round() for cof in pol.coefficients(sparse=False)] return IntegerRing()['x'](coeffs) @@ -252,11 +254,10 @@ def is_HCP(f, check_monic_irreducible=True): from sage.rings.finite_rings.finite_field_constructor import GF h = f.degree() - h2list = [d for d in h.divisors() - if (d-h) % 2 == 0 and d.prime_to_m_part(2) == 1] - pmin = 33 * (h**2 * (RR(h+2).log().log()+2)**2).ceil() + h2list = [d for d in h.divisors() if (d - h) % 2 == 0 and d.prime_to_m_part(2) == 1] + pmin = 33 * (h**2 * (RR(h + 2).log().log() + 2) ** 2).ceil() # Guarantees 4*p > |D| for fundamental D under GRH - p = pmin-1 + p = pmin - 1 n = 0 from sage.arith.misc import next_prime from sage.schemes.elliptic_curves.constructor import EllipticCurve @@ -330,6 +331,7 @@ def OrderClassNumber(D0, h0, f): ps = f.prime_divisors() from sage.misc.misc_c import prod from sage.arith.misc import kronecker as kronecker_symbol + n = (f // prod(ps)) * prod(p - kronecker_symbol(D0, p) for p in ps) if D0 == -3: # assert h0 == 1 and n % 3 == 0 @@ -439,20 +441,7 @@ def cm_j_invariants_and_orders(K, proof=None): (-3, 6, 31710790944000*a^2 + 39953093016000*a + 50337742902000)] """ if K == QQ: - return [(ZZ(d), ZZ(f), ZZ(j)) for d, f, j in [ - (-3, 3, -12288000), - (-3, 2, 54000), - (-3, 1, 0), - (-4, 2, 287496), - (-4, 1, 1728), - (-7, 2, 16581375), - (-7, 1, -3375), - (-8, 1, 8000), - (-11, 1, -32768), - (-19, 1, -884736), - (-43, 1, -884736000), - (-67, 1, -147197952000), - (-163, 1, -262537412640768000)]] + return [(ZZ(d), ZZ(f), ZZ(j)) for d, f, j in [(-3, 3, -12288000), (-3, 2, 54000), (-3, 1, 0), (-4, 2, 287496), (-4, 1, 1728), (-7, 2, 16581375), (-7, 1, -3375), (-8, 1, 8000), (-11, 1, -32768), (-19, 1, -884736), (-43, 1, -884736000), (-67, 1, -147197952000), (-163, 1, -262537412640768000)]] # Get the list of CM orders that could possibly have Hilbert class # polynomial F(x) with a root in K. If F(x) has a root alpha in K, @@ -460,10 +449,9 @@ def cm_j_invariants_and_orders(K, proof=None): # F(x) divides [K:QQ]. n = K.absolute_degree() T = discriminants_with_bounded_class_number(n, proof=proof) - dlist = sorted(sum((Dflist for h,Dflist in T.items() if h.divides(n)), [])) + dlist = sorted(sum((Dflist for h, Dflist in T.items() if h.divides(n)), [])) - return [(D, f, j) for D, f in dlist - for j in hilbert_class_polynomial(D*f*f).roots(K, multiplicities=False)] + return [(D, f, j) for D, f in dlist for j in hilbert_class_polynomial(D * f * f).roots(K, multiplicities=False)] @cached_function @@ -523,6 +511,7 @@ def cm_orders(h, proof=None): # be stored in hDf_dict), and return just those with class number h. return discriminants_with_bounded_class_number(h, proof=proof)[h] + # Table from Mark Watkins paper "Class numbers of imaginary quadratic fields". # WAS extracted this by cutting/pasting from the pdf, and running this program: @@ -539,33 +528,108 @@ def cm_orders(h, proof=None): # fields. These are all *unconditional* (not dependent on GRH). -watkins_table = {1: (163, 9), 2: (427, 18), 3: (907, 16), 4: (1555, 54), 5: (2683, 25), - 6: (3763, 51), 7: (5923, 31), 8: (6307, 131), 9: (10627, 34), 10: - (13843, 87), 11: (15667, 41), 12: (17803, 206), 13: (20563, 37), 14: - (30067, 95), 15: (34483, 68), 16: (31243, 322), 17: (37123, 45), 18: - (48427, 150), 19: (38707, 47), 20: (58507, 350), 21: (61483, 85), 22: - (85507, 139), 23: (90787, 68), 24: (111763, 511), 25: (93307, 95), 26: - (103027, 190), 27: (103387, 93), 28: (126043, 457), 29: (166147, 83), - 30: (134467, 255), 31: (133387, 73), 32: (164803, 708), 33: (222643, 101), - 34: (189883, 219), 35: (210907, 103), 36: (217627, 668), 37: - (158923, 85), 38: (289963, 237), 39: (253507, 115), 40: (260947, 912), - 41: (296587, 109), 42: (280267, 339), 43: (300787, 106), 44: (319867, 691), - 45: (308323, 154), 46: (462883, 268), 47: (375523, 107), 48: - (335203, 1365), 49: (393187, 132), 50: (389467, 345), 51: (546067, 159), - 52: (439147, 770), 53: (425107, 114), 54: (532123, 427), 55: (452083,163), - 56: (494323, 1205), 57: (615883, 179), 58: (586987, 291), - 59:(474307, 128), 60: (662803, 1302), 61: (606643, 132), 62: (647707, 323), - 63: (991027, 216), 64: (693067, 1672), 65: (703123, 164), 66: (958483, 530), - 67: (652723, 120), 68: (819163, 976), 69: (888427, 209), 70:(811507, 560), - 71: (909547, 150), 72: (947923, 1930), 73: (886867, 119), - 74: (951043, 407), 75: (916507, 237), 76: (1086187, 1075), 77: (1242763, 216), - 78: (1004347, 561), 79: (1333963, 175), 80: (1165483, 2277), 81: (1030723, 228), - 82: (1446547, 402), 83: (1074907, 150), 84: (1225387,1715), - 85: (1285747, 221), 86: (1534723, 472), 87: (1261747, 222), - 88:(1265587, 1905), 89: (1429387, 192), 90: (1548523, 801), - 91: (1391083,214), 92: (1452067, 1248), 93: (1475203, 262), 94: (1587763, 509), - 95:(1659067, 241), 96: (1684027, 3283), 97: (1842523, 185), 98: (2383747,580), - 99: (1480627, 289), 100: (1856563, 1736)} +watkins_table = { + 1: (163, 9), + 2: (427, 18), + 3: (907, 16), + 4: (1555, 54), + 5: (2683, 25), + 6: (3763, 51), + 7: (5923, 31), + 8: (6307, 131), + 9: (10627, 34), + 10: (13843, 87), + 11: (15667, 41), + 12: (17803, 206), + 13: (20563, 37), + 14: (30067, 95), + 15: (34483, 68), + 16: (31243, 322), + 17: (37123, 45), + 18: (48427, 150), + 19: (38707, 47), + 20: (58507, 350), + 21: (61483, 85), + 22: (85507, 139), + 23: (90787, 68), + 24: (111763, 511), + 25: (93307, 95), + 26: (103027, 190), + 27: (103387, 93), + 28: (126043, 457), + 29: (166147, 83), + 30: (134467, 255), + 31: (133387, 73), + 32: (164803, 708), + 33: (222643, 101), + 34: (189883, 219), + 35: (210907, 103), + 36: (217627, 668), + 37: (158923, 85), + 38: (289963, 237), + 39: (253507, 115), + 40: (260947, 912), + 41: (296587, 109), + 42: (280267, 339), + 43: (300787, 106), + 44: (319867, 691), + 45: (308323, 154), + 46: (462883, 268), + 47: (375523, 107), + 48: (335203, 1365), + 49: (393187, 132), + 50: (389467, 345), + 51: (546067, 159), + 52: (439147, 770), + 53: (425107, 114), + 54: (532123, 427), + 55: (452083, 163), + 56: (494323, 1205), + 57: (615883, 179), + 58: (586987, 291), + 59: (474307, 128), + 60: (662803, 1302), + 61: (606643, 132), + 62: (647707, 323), + 63: (991027, 216), + 64: (693067, 1672), + 65: (703123, 164), + 66: (958483, 530), + 67: (652723, 120), + 68: (819163, 976), + 69: (888427, 209), + 70: (811507, 560), + 71: (909547, 150), + 72: (947923, 1930), + 73: (886867, 119), + 74: (951043, 407), + 75: (916507, 237), + 76: (1086187, 1075), + 77: (1242763, 216), + 78: (1004347, 561), + 79: (1333963, 175), + 80: (1165483, 2277), + 81: (1030723, 228), + 82: (1446547, 402), + 83: (1074907, 150), + 84: (1225387, 1715), + 85: (1285747, 221), + 86: (1534723, 472), + 87: (1261747, 222), + 88: (1265587, 1905), + 89: (1429387, 192), + 90: (1548523, 801), + 91: (1391083, 214), + 92: (1452067, 1248), + 93: (1475203, 262), + 94: (1587763, 509), + 95: (1659067, 241), + 96: (1684027, 3283), + 97: (1842523, 185), + 98: (2383747, 580), + 99: (1480627, 289), + 100: (1856563, 1736), +} # Table from Janis Klaise [Klaise2012]_ @@ -584,26 +648,108 @@ def cm_orders(h, proof=None): # order with class number h, and n is the number of such orders. # These are all *unconditional* (not dependent on GRH). -klaise_table = {1: (163, 13), 2: (427, 29), 3: (907, 25), 4: (1555, 84), 5: (2683, 29), 6: (4075, 101), - 7: (5923, 38), 8: (7987, 208), 9: (10627, 55), 10: (13843, 123), 11: (15667, 46), - 12: (19723, 379), 13: (20563, 43), 14: (30067, 134), 15: (34483, 95), 16: (35275, 531), - 17: (37123, 50), 18: (48427, 291), 19: (38707, 59), 20: (58843, 502), 21: (61483, 118), - 22: (85507, 184), 23: (90787, 78), 24: (111763, 1042), 25: (93307, 101), 26: (103027, 227), - 27: (103387, 136), 28: (126043, 623), 29: (166147, 94), 30: (137083, 473), 31: (133387, 83), - 32: (164803, 1231), 33: (222643, 158), 34: (189883, 262), 35: (210907, 111), 36: (217627, 1306), - 37: (158923, 96), 38: (289963, 284), 39: (253507, 162), 40: (274003, 1418), 41: (296587, 125), - 42: (301387, 596), 43: (300787, 123), 44: (319867, 911), 45: (308323, 231), 46: (462883, 330), - 47: (375523, 117), 48: (335203, 2895), 49: (393187, 146), 50: (389467, 445), 51: (546067, 217), - 52: (457867, 1006), 53: (425107, 130), 54: (532123, 812), 55: (452083, 177), 56: (494323, 1812), - 57: (615883, 237), 58: (586987, 361), 59: (474307, 144), 60: (662803, 2361), 61: (606643, 149), - 62: (647707, 386), 63: (991027, 311), 64: (693067, 2919), 65: (703123, 192), 66: (958483, 861), - 67: (652723, 145), 68: (819163, 1228), 69: (888427, 292), 70: (821683, 704), 71: (909547, 176), - 72: (947923, 4059), 73: (886867, 137), 74: (951043, 474), 75: (916507, 353), 76: (1086187, 1384), - 77: (1242763, 236), 78: (1004347, 925), 79: (1333963, 200), 80: (1165483, 3856), 81: (1030723, 339), - 82: (1446547, 487), 83: (1074907, 174), 84: (1225387, 2998), 85: (1285747, 246), 86: (1534723, 555), - 87: (1261747, 313), 88: (1265587, 2771), 89: (1429387, 206), 90: (1548523, 1516), 91: (1391083, 249), - 92: (1452067, 1591), 93: (1475203, 354), 94: (1587763, 600), 95: (1659067, 273), 96: (1684027, 7276), - 97: (1842523, 208), 98: (2383747, 710), 99: (1480627, 396), 100: (1856563, 2311)} +klaise_table = { + 1: (163, 13), + 2: (427, 29), + 3: (907, 25), + 4: (1555, 84), + 5: (2683, 29), + 6: (4075, 101), + 7: (5923, 38), + 8: (7987, 208), + 9: (10627, 55), + 10: (13843, 123), + 11: (15667, 46), + 12: (19723, 379), + 13: (20563, 43), + 14: (30067, 134), + 15: (34483, 95), + 16: (35275, 531), + 17: (37123, 50), + 18: (48427, 291), + 19: (38707, 59), + 20: (58843, 502), + 21: (61483, 118), + 22: (85507, 184), + 23: (90787, 78), + 24: (111763, 1042), + 25: (93307, 101), + 26: (103027, 227), + 27: (103387, 136), + 28: (126043, 623), + 29: (166147, 94), + 30: (137083, 473), + 31: (133387, 83), + 32: (164803, 1231), + 33: (222643, 158), + 34: (189883, 262), + 35: (210907, 111), + 36: (217627, 1306), + 37: (158923, 96), + 38: (289963, 284), + 39: (253507, 162), + 40: (274003, 1418), + 41: (296587, 125), + 42: (301387, 596), + 43: (300787, 123), + 44: (319867, 911), + 45: (308323, 231), + 46: (462883, 330), + 47: (375523, 117), + 48: (335203, 2895), + 49: (393187, 146), + 50: (389467, 445), + 51: (546067, 217), + 52: (457867, 1006), + 53: (425107, 130), + 54: (532123, 812), + 55: (452083, 177), + 56: (494323, 1812), + 57: (615883, 237), + 58: (586987, 361), + 59: (474307, 144), + 60: (662803, 2361), + 61: (606643, 149), + 62: (647707, 386), + 63: (991027, 311), + 64: (693067, 2919), + 65: (703123, 192), + 66: (958483, 861), + 67: (652723, 145), + 68: (819163, 1228), + 69: (888427, 292), + 70: (821683, 704), + 71: (909547, 176), + 72: (947923, 4059), + 73: (886867, 137), + 74: (951043, 474), + 75: (916507, 353), + 76: (1086187, 1384), + 77: (1242763, 236), + 78: (1004347, 925), + 79: (1333963, 200), + 80: (1165483, 3856), + 81: (1030723, 339), + 82: (1446547, 487), + 83: (1074907, 174), + 84: (1225387, 2998), + 85: (1285747, 246), + 86: (1534723, 555), + 87: (1261747, 313), + 88: (1265587, 2771), + 89: (1429387, 206), + 90: (1548523, 1516), + 91: (1391083, 249), + 92: (1452067, 1591), + 93: (1475203, 354), + 94: (1587763, 600), + 95: (1659067, 273), + 96: (1684027, 7276), + 97: (1842523, 208), + 98: (2383747, 710), + 99: (1480627, 396), + 100: (1856563, 2311), +} def largest_fundamental_disc_with_class_number(h): @@ -715,15 +861,14 @@ class number `h` is also the largest discriminant, but this is not except KeyError: raise NotImplementedError("largest discriminant not available for class number %s" % h) + # This dict has class numbers h as keys, the value at h is a complete # list of pairs (D0,f) such that D=D0*f**2 has class number h. We # initialise it with h=1 only; other values will be added by calls to # discriminants_with_bounded_class_number(). -hDf_dict = {ZZ(1): [(ZZ(D), ZZ(h)) for D,h in - [(-3, 1), (-3, 2), (-3, 3), (-4, 1), (-4, 2), (-7, 1), (-7, 2), - (-8, 1), (-11, 1), (-19, 1), (-43, 1), (-67, 1), (-163, 1)]]} +hDf_dict = {ZZ(1): [(ZZ(D), ZZ(h)) for D, h in [(-3, 1), (-3, 2), (-3, 3), (-4, 1), (-4, 2), (-7, 1), (-7, 2), (-8, 1), (-11, 1), (-19, 1), (-43, 1), (-67, 1), (-163, 1)]]} def discriminants_with_bounded_class_number(hmax, B=None, proof=None): @@ -782,24 +927,25 @@ def discriminants_with_bounded_class_number(hmax, B=None, proof=None): # Easy case where we have already computed and cached the relevant values if hDf_dict and hmax <= max(hDf_dict): - T = {h:Dflist for h,Dflist in hDf_dict.items() if h <= hmax} + T = {h: Dflist for h, Dflist in hDf_dict.items() if h <= hmax} if B: for h in T: - T[h] = [Df for Df in T[h] if Df[0].abs()*Df[1]**2 <= B] + T[h] = [Df for Df in T[h] if Df[0].abs() * Df[1] ** 2 <= B] return T # imports that are needed only for this function from sage.arith.srange import xsrange from sage.structure.proof.proof import get_flag + proof = get_flag(proof, 'number_field') if B is None: if hmax <= 100: # Determine how far we have to go by applying Watkins + Klaise's results. - v = [largest_disc_with_class_number(h) for h in range(1, hmax+1)] - B = max([b for b,_ in v]) - #print("Testing all discriminants up to {}".format(B)) - count = [0] + [cnt for _,cnt in v] + v = [largest_disc_with_class_number(h) for h in range(1, hmax + 1)] + B = max([b for b, _ in v]) + # print("Testing all discriminants up to {}".format(B)) + count = [0] + [cnt for _, cnt in v] else: raise ValueError("if hmax>100 you must specify a discriminant bound B") else: @@ -830,41 +976,42 @@ def discriminants_with_bounded_class_number(hmax, B=None, proof=None): # update it with fundamental ones. from collections import defaultdict + T = defaultdict(set) h_dict = {} for h, Dflist in hDf_dict.items(): - for D0,f in Dflist: - h_dict[D0*f**2] = h + for D0, f in Dflist: + h_dict[D0 * f**2] = h if not count: - Dflist = [Df for Df in Dflist if Df[0].abs()*Df[1]**2 <= B] + Dflist = [Df for Df in Dflist if Df[0].abs() * Df[1] ** 2 <= B] T[h] = set(Dflist) # We do not need to certify the class number from :pari:`qfbclassno` for discriminants under 2*10^10 - if B < 2*10**10: + if B < 2 * 10**10: proof = False - for D in xsrange(-3, -B-1, -1): + for D in xsrange(-3, -B - 1, -1): if not D.is_discriminant(): continue D0 = D.squarefree_part() if D0 % 4 != 1: D0 *= 4 - f = (D//D0).isqrt() + f = (D // D0).isqrt() # Now D0 is the fundamental discriminant and f the conductor if D in h_dict: h = h_dict[D] else: - if f == 1: # D itself is fundamental + if f == 1: # D itself is fundamental h = D.class_number(proof) h_dict[D] = h else: - h = OrderClassNumber(D0,h_dict[D0],f) + h = OrderClassNumber(D0, h_dict[D0], f) # If the class number of this order is within the range, then store (D0,f) if h <= hmax: - T[h].add((D0,f)) + T[h].add((D0, f)) # sort each list of (D,f) pairs by (|D|,f) @@ -972,7 +1119,7 @@ def is_cm_j_invariant(j, algorithm='CremonaSutherland', method=None): if j in ZZ: j = ZZ(j) - table = {jj: (d,f) for d,f,jj in cm_j_invariants_and_orders(QQ)} + table = {jj: (d, f) for d, f, jj in cm_j_invariants_and_orders(QQ)} if j in table: return True, table[j] return False, None @@ -985,7 +1132,7 @@ def is_cm_j_invariant(j, algorithm='CremonaSutherland', method=None): # Next we find its minimal polynomial of j: if j.parent().absolute_degree() == 2: - jpol = j.absolute_minpoly() # no algorithm parameter + jpol = j.absolute_minpoly() # no algorithm parameter else: jpol = j.absolute_minpoly(algorithm='pari') @@ -1011,9 +1158,9 @@ def is_cm_j_invariant(j, algorithm='CremonaSutherland', method=None): if algorithm in ['exhaustive', 'old']: if h > 100: raise NotImplementedError("CM data only available for class numbers up to 100") - for d,f in cm_orders(h): - if jpol == hilbert_class_polynomial(d*f**2): - return (True, (d,f)) + for d, f in cm_orders(h): + if jpol == hilbert_class_polynomial(d * f**2): + return (True, (d, f)) return (False, None) if algorithm not in ['reduction', 'new']: @@ -1035,10 +1182,11 @@ def is_cm_j_invariant(j, algorithm='CremonaSutherland', method=None): # integral model: from sage.schemes.elliptic_curves.constructor import EllipticCurve + E = EllipticCurve(j=j).integral_model() D = E.discriminant() prime_bound = 1000 # test primes of degree 1 up to this norm - max_primes = 20 # test at most this many primes + max_primes = 20 # test at most this many primes num_prime = 0 cmd = 0 cmf = 0 @@ -1059,28 +1207,28 @@ def is_cm_j_invariant(j, algorithm='CremonaSutherland', method=None): for P in K.primes_of_degree_one_iter(prime_bound): if num_prime > max_primes: - if cmd: # we have a candidate CM field already + if cmd: # we have a candidate CM field already break - else: # we need to try more primes + else: # we need to try more primes max_primes *= 2 - if D.valuation(P) > 0: # skip bad primes + if D.valuation(P) > 0: # skip bad primes continue aP = E.reduction(P).trace_of_frobenius() - if aP == 0: # skip supersingular primes + if aP == 0: # skip supersingular primes continue num_prime += 1 - DP = aP**2 - 4*P.norm() + DP = aP**2 - 4 * P.norm() dP = DP.squarefree_part() - fP = ZZ(DP//dP).isqrt() - if cmd == 0: # first one, so store d and f + fP = ZZ(DP // dP).isqrt() + if cmd == 0: # first one, so store d and f cmd = dP cmf = fP - elif cmd != dP: # inconsistent with previous + elif cmd != dP: # inconsistent with previous return (False, None) - else: # consistent d, so update f + else: # consistent d, so update f cmf = cmf.gcd(fP) - if cmd == 0: # no conclusion, we found no degree 1 primes, revert to default algorithm + if cmd == 0: # no conclusion, we found no degree 1 primes, revert to default algorithm return is_cm_j_invariant(j) # it looks like cm by disc cmd * f**2 where f divides cmf @@ -1092,9 +1240,9 @@ def is_cm_j_invariant(j, algorithm='CremonaSutherland', method=None): # Now we must check if h(cmd*f**2)==h for f|cmf; if so we check # whether j is a root of the associated Hilbert class polynomial. h0 = cmd.class_number() - for f in cmf.divisors(): # only positive divisors - if h != OrderClassNumber(cmd,h0,f): + for f in cmf.divisors(): # only positive divisors + if h != OrderClassNumber(cmd, h0, f): continue - if jpol == hilbert_class_polynomial(cmd*f**2): + if jpol == hilbert_class_polynomial(cmd * f**2): return (True, (cmd, f)) return (False, None) diff --git a/src/sage/schemes/elliptic_curves/constructor.py b/src/sage/schemes/elliptic_curves/constructor.py index c0240b5801d..aa7b351e7c6 100644 --- a/src/sage/schemes/elliptic_curves/constructor.py +++ b/src/sage/schemes/elliptic_curves/constructor.py @@ -315,9 +315,7 @@ class EllipticCurveFactory(UniqueFactory): TypeError: invalid input to EllipticCurve constructor """ - def create_key_and_extra_args( - self, x=None, y=None, j=None, minimal_twist=True, **kwds - ): + def create_key_and_extra_args(self, x=None, y=None, j=None, minimal_twist=True, **kwds): r""" Return a ``UniqueFactory`` key and possibly extra parameters. @@ -422,18 +420,14 @@ def create_key_and_extra_args( except (ZeroDivisionError, ValueError, TypeError): raise ValueError("First parameter must be a ring containing %s" % j) elif x is not None: - raise ValueError( - "First parameter (if present) must be a ring when j is specified" - ) + raise ValueError("First parameter (if present) must be a ring when j is specified") x = coefficients_from_j(j, minimal_twist) if isinstance(x, Expression) and x.is_relational(): import operator if x.operator() != operator.eq: - raise ValueError( - "no symbolic relations other than equalities are allowed" - ) + raise ValueError("no symbolic relations other than equalities are allowed") x = x.lhs() - x.rhs() if isinstance(parent(x), SymbolicRing): @@ -532,10 +526,7 @@ def create_object(self, version, key, *, names=None, **kwds): from .ell_padic_field import EllipticCurve_padic_field return EllipticCurve_padic_field(R, x) - if isinstance(R, FiniteField) or ( - isinstance(R, sage.rings.abc.IntegerModRing) - and R.characteristic().is_prime() - ): + if isinstance(R, FiniteField) or (isinstance(R, sage.rings.abc.IntegerModRing) and R.characteristic().is_prime()): from .ell_finite_field import EllipticCurve_finite_field return EllipticCurve_finite_field(R, x) @@ -548,9 +539,7 @@ def create_object(self, version, key, *, names=None, **kwds): return EllipticCurve_generic(R, x) -EllipticCurve = EllipticCurveFactory( - "sage.schemes.elliptic_curves.constructor.EllipticCurve" -) +EllipticCurve = EllipticCurveFactory("sage.schemes.elliptic_curves.constructor.EllipticCurve") def _parse_multivariate_defining_equation(g): @@ -842,9 +831,7 @@ def coefficients_from_j(j, minimal_twist=True): with CremonaDatabase() as D: if min_cond <= D.largest_conductor(): - sorter = lambda E: parse_cremona_label( - E.label(), numerical_class_code=True - ) + sorter = lambda E: parse_cremona_label(E.label(), numerical_class_code=True) else: sorter = lambda E: E.ainvs() Elist.sort(key=sorter) @@ -1208,19 +1195,13 @@ def EllipticCurve_from_cubic(F, P=None, morphism=True): try: CP = C(P) except (TypeError, ValueError): - raise TypeError( - "{} does not define a point on a projective curve over {} defined by {}".format( - P, K, F - ) - ) + raise TypeError("{} does not define a point on a projective curve over {} defined by {}".format(P, K, F)) x, y, z = R.gens() # Test whether P is a flex; if not test whether there are any rational flexes: - hessian = Matrix( - [[F.derivative(v1, v2) for v1 in R.gens()] for v2 in R.gens()] - ).det() + hessian = Matrix([[F.derivative(v1, v2) for v1 in R.gens()] for v2 in R.gens()]).det() if P and hessian(P) == 0: flex_point = P else: @@ -1281,9 +1262,7 @@ def EllipticCurve_from_cubic(F, P=None, morphism=True): else: # Second case: no flexes if not P: - raise ValueError( - "A point must be given when the cubic has no rational flexes" - ) + raise ValueError("A point must be given when the cubic has no rational flexes") L = tangent_at_smooth_point(C, P) Qlist = [Q for Q in C.intersection(Curve(L)).rational_points() if C(Q) != CP] # assert Qlist @@ -1344,9 +1323,7 @@ def EllipticCurve_from_cubic(F, P=None, morphism=True): # Construct the morphism - return WeierstrassTransformationWithInverse( - C, E, fwd_defining_poly, fwd_post, inv_defining_poly, inv_post - ) + return WeierstrassTransformationWithInverse(C, E, fwd_defining_poly, fwd_post, inv_defining_poly, inv_post) def tangent_at_smooth_point(C, P): @@ -1454,11 +1431,7 @@ def chord_and_tangent(F, P): C = Curve(F) P = C(P) except (TypeError, ValueError): - raise TypeError( - "{} does not define a point on a projective curve over {} defined by {}".format( - P, K, F - ) - ) + raise TypeError("{} does not define a point on a projective curve over {} defined by {}".format(P, K, F)) L = Curve(tangent_at_smooth_point(C, P)) Qlist = [Q for Q in C.intersection(L).rational_points() if Q != P] diff --git a/src/sage/schemes/elliptic_curves/ec_database.py b/src/sage/schemes/elliptic_curves/ec_database.py index 263e4ba930c..6c1b390915e 100644 --- a/src/sage/schemes/elliptic_curves/ec_database.py +++ b/src/sage/schemes/elliptic_curves/ec_database.py @@ -131,6 +131,7 @@ def rank(self, rank, tors=0, n=10, labels=False): [] """ from sage.features.databases import DatabaseEllcurves + db = DatabaseEllcurves() data = Path(db.absolute_filename()).parent / f'rank{rank}' try: diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index 44cd1ccefec..5e5641fb1c8 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -96,8 +96,7 @@ from sage.schemes.elliptic_curves.constructor import EllipticCurve from sage.schemes.elliptic_curves.ell_generic import EllipticCurve_generic -from sage.schemes.elliptic_curves.weierstrass_morphism \ - import WeierstrassIsomorphism, _isomorphisms, baseWI, negation_morphism +from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism, _isomorphisms, baseWI, negation_morphism # # Private function for parsing input to determine the type of @@ -262,8 +261,8 @@ def compute_codomain_formula(E, v, w): """ a1, a2, a3, a4, a6 = E.a_invariants() - A4 = a4 - 5*v - A6 = a6 - (a1**2 + 4*a2)*v - 7*w + A4 = a4 - 5 * v + A6 = a6 - (a1**2 + 4 * a2) * v - 7 * w return EllipticCurve([a1, a2, a3, A4, A6]) @@ -299,7 +298,7 @@ def compute_vw_kohel_even_deg1(x0, y0, a1, a2, a4): sage: compute_vw_kohel_even_deg1(x0, y0, a1, a2, a4) (18, 9) """ - v = 3*x0**2 + 2*a2*x0 + a4 - a1*y0 + v = 3 * x0**2 + 2 * a2 * x0 + a4 - a1 * y0 w = x0 * v return v, w @@ -336,9 +335,9 @@ def compute_vw_kohel_even_deg3(b2, b4, s1, s2, s3): sage: compute_vw_kohel_even_deg3(b2, b4, s1, s2, s3) (4, 7) """ - temp1 = s1**2 - 2*s2 - v = 3*temp1 + (b2*s1 + 3*b4)/2 - w = 3*(s1**3 - 3*s1*s2 + 3*s3) + (b2*temp1 + b4*s1)/2 + temp1 = s1**2 - 2 * s2 + v = 3 * temp1 + (b2 * s1 + 3 * b4) / 2 + w = 3 * (s1**3 - 3 * s1 * s2 + 3 * s3) + (b2 * temp1 + b4 * s1) / 2 return v, w @@ -376,8 +375,8 @@ def compute_vw_kohel_odd(b2, b4, b6, s1, s2, s3, n): sage: compute_vw_kohel_odd(b2,b4,b6,s1,s2,s3,3) (7, 1) """ - v = 6*(s1**2 - 2*s2) + b2*s1 + n*b4 - w = 10*(s1**3 - 3*s1*s2 + 3*s3) + 2*b2*(s1**2 - 2*s2) + 3*b4*s1 + n*b6 + v = 6 * (s1**2 - 2 * s2) + b2 * s1 + n * b4 + w = 10 * (s1**3 - 3 * s1 * s2 + 3 * s3) + 2 * b2 * (s1**2 - 2 * s2) + 3 * b4 * s1 + n * b6 return v, w @@ -428,7 +427,7 @@ def compute_codomain_kohel(E, kernel): """ # First set up the polynomial ring base_field = E.base_ring() - poly_ring = PolynomialRing(base_field,'x') + poly_ring = PolynomialRing(base_field, 'x') try: psi = poly_ring(kernel) @@ -438,16 +437,16 @@ def compute_codomain_kohel(E, kernel): # next determine the even / odd part of the isogeny psi_2tor = two_torsion_part(E, psi) - if psi_2tor.degree() != 0: # even degree case + if psi_2tor.degree() != 0: # even degree case - psi_quo = psi//psi_2tor + psi_quo = psi // psi_2tor if psi_quo.degree() != 0: raise NotImplementedError("Kohel's algorithm currently only supports cyclic isogenies (except for [2])") n = psi_2tor.degree() - if n == 1: # degree divisible exactly by 2 + if n == 1: # degree divisible exactly by 2 a1, a2, a3, a4, a6 = E.a_invariants() @@ -455,9 +454,9 @@ def compute_codomain_kohel(E, kernel): # determine y0 if base_field.characteristic() == 2: - y0 = (x0**3 + a2*x0**2 + a4*x0 + a6).sqrt() + y0 = (x0**3 + a2 * x0**2 + a4 * x0 + a6).sqrt() else: - y0 = -(a1*x0 + a3)/2 + y0 = -(a1 * x0 + a3) / 2 # now (x0,y0) is the 2-torsion point in the kernel @@ -516,7 +515,7 @@ def two_torsion_part(E, psi): sage: two_torsion_part(E, x + 13) x + 13 """ - x = psi.parent().gen() # NB psi is univariate but could be constant + x = psi.parent().gen() # NB psi is univariate but could be constant psi_2 = E.two_division_polynomial(x) return psi.gcd(psi_2) @@ -946,8 +945,8 @@ class EllipticCurveIsogeny(EllipticCurveHom): # algebraic structs # __base_field = None - __poly_ring = None # univariate in x over __base_field - __mpoly_ring = None # __base_field[x][y], internal use only + __poly_ring = None # univariate in x over __base_field + __mpoly_ring = None # __base_field[x][y], internal use only # # Rational Maps @@ -965,9 +964,9 @@ class EllipticCurveIsogeny(EllipticCurveHom): __kernel_list = None # list of elements in the kernel - __kernel_polynomial = None # polynomial with roots at x values for x-coordinate of points in the kernel + __kernel_polynomial = None # polynomial with roots at x values for x-coordinate of points in the kernel - __inner_kernel_polynomial = None # the inner kernel polynomial (ignoring preisomorphism) + __inner_kernel_polynomial = None # the inner kernel polynomial (ignoring preisomorphism) # # member variables common to Velu's formula @@ -983,9 +982,9 @@ class EllipticCurveIsogeny(EllipticCurveHom): # # member variables specific to Kohel's algorithm. # - __psi = None # psi polynomial - __phi = None # phi polynomial - __omega = None # omega polynomial, an element of k[x][y] + __psi = None # psi polynomial + __phi = None # phi polynomial + __omega = None # omega polynomial, an element of k[x][y] # # Python Special Functions @@ -1081,7 +1080,7 @@ def __init__(self, E, kernel, codomain=None, degree=None, model=None, check=True self._set_pre_isomorphism(pre_isom) if post_isom is not None: - self.__set_post_isomorphism(old_codomain, post_isom) #(trac #7096) + self.__set_post_isomorphism(old_codomain, post_isom) # (trac #7096) # Inheritance house keeping self.__perform_inheritance_housekeeping() @@ -1471,7 +1470,7 @@ def _latex_(self): sage: phi._latex_() '\\left( \\frac{x^{2} + 11 x + 7}{x + 11} , \\frac{x^{2} y + 5 x y + 12 y}{x^{2} + 5 x + 2} \\right)' """ - fx,fy = self.rational_maps() + fx, fy = self.rational_maps() return fr'\left( {fx._latex_()} , {fy._latex_()} \right)' ########################### @@ -1675,8 +1674,7 @@ def __initialize_rational_maps(self, precomputed_maps=None): else: X_map, Y_map = precomputed_maps # cannot coerce directly in xfield for some reason - X_map = self.__poly_ring(X_map.numerator()) \ - / self.__poly_ring(X_map.denominator()) + X_map = self.__poly_ring(X_map.numerator()) / self.__poly_ring(X_map.denominator()) if self.__prei_ratl_maps is not None: prei_X_map, prei_Y_map = self.__prei_ratl_maps @@ -1736,15 +1734,15 @@ def __set_pre_isomorphism(self, domain, isomorphism): # calculate the isomorphism as a rational map. u, r, s, t = (self.__base_field(c) for c in isomorphism.tuple()) - uinv = 1/u + uinv = 1 / u uinv2 = uinv**2 - uinv3 = uinv*uinv2 + uinv3 = uinv * uinv2 x = self.__poly_ring.gen() - y = self.__xyfield.gen(1) # not mpoly_ring.gen(1) else we end - # up in K(x)[y] and trouble ensues + y = self.__xyfield.gen(1) # not mpoly_ring.gen(1) else we end + # up in K(x)[y] and trouble ensues - self.__prei_ratl_maps = (x - r) * uinv2, (y - s*(x-r) - t) * uinv3 + self.__prei_ratl_maps = (x - r) * uinv2, (y - s * (x - r) - t) * uinv3 if self.__kernel_polynomial is not None: ker_poly = self.__kernel_polynomial @@ -1778,14 +1776,14 @@ def __set_post_isomorphism(self, codomain, isomorphism): # calculate the isomorphism as a rational map. u, r, s, t = (self.__base_field(c) for c in isomorphism.tuple()) - uinv = 1/u + uinv = 1 / u uinv2 = uinv**2 - uinv3 = uinv*uinv2 + uinv3 = uinv * uinv2 x = self.__poly_ring.gen() y = self.__xyfield.gen(1) - self.__posti_ratl_maps = (x - r) * uinv2, (y - s*(x-r) - t) * uinv3 + self.__posti_ratl_maps = (x - r) * uinv2, (y - s * (x - r) - t) * uinv3 self.__perform_inheritance_housekeeping() @@ -1841,6 +1839,7 @@ def __setup_post_isomorphism(self, codomain, model): raise ValueError("cannot specify a codomain curve and model name simultaneously") from sage.schemes.elliptic_curves.ell_field import compute_model + codomain = compute_model(oldE2, model) else: # codomain is not None @@ -1921,8 +1920,7 @@ def all_multiples(itr, terminal): kernel_set = {self._domain(0)} for P in kernel_gens: - kernel_set.update(R for Q in tuple(kernel_set) - for R in all_multiples(P,Q)) + kernel_set.update(R for Q in tuple(kernel_set) for R in all_multiples(P, Q)) self._degree = Integer(len(kernel_set)) self.__kernel_list = list(kernel_set) @@ -1949,20 +1947,20 @@ def __update_kernel_data(self, xQ, yQ): """ a1, a2, a3, a4, _ = self._domain.a_invariants() - gxQ = (3*xQ + 2*a2)*xQ + a4 - a1*yQ - gyQ = -2*yQ - a1*xQ - a3 + gxQ = (3 * xQ + 2 * a2) * xQ + a4 - a1 * yQ + gyQ = -2 * yQ - a1 * xQ - a3 uQ = gyQ**2 - if 2*yQ == -a1*xQ - a3: # Q is 2-torsion + if 2 * yQ == -a1 * xQ - a3: # Q is 2-torsion vQ = gxQ - else: # Q is not 2-torsion - vQ = 2*gxQ - a1*gyQ + else: # Q is not 2-torsion + vQ = 2 * gxQ - a1 * gyQ self.__kernel_mod_sign[xQ] = yQ, gxQ, gyQ, vQ, uQ self.__v += vQ - self.__w += uQ + xQ*vQ + self.__w += uQ + xQ * vQ def __init_from_kernel_point(self, ker): r""" @@ -2089,18 +2087,18 @@ def __velu_sum_helper(xQ, Qvalues, a1, a3, x, y): t1 = x - xQ inv_t1 = t1**-1 inv_t1_2 = inv_t1**2 - inv_t1_3 = inv_t1_2*inv_t1 + inv_t1_3 = inv_t1_2 * inv_t1 - tX = vQ*inv_t1 + uQ*(inv_t1_2) + tX = vQ * inv_t1 + uQ * (inv_t1_2) - tY0 = uQ*(2*y + a1*x + a3) - tY1 = vQ*(a1*t1 + y - yQ) - tY2 = a1*uQ - gxQ*gyQ + tY0 = uQ * (2 * y + a1 * x + a3) + tY1 = vQ * (a1 * t1 + y - yQ) + tY2 = a1 * uQ - gxQ * gyQ # Without this explicit coercion, tY ends up in K(x)[y] # instead of K(x,y), and trouble ensues! F = FractionField(y.parent()) - tY = tY0*F(inv_t1_3) + (tY1 + tY2)*F(inv_t1_2) + tY = tY0 * F(inv_t1_3) + (tY1 + tY2) * F(inv_t1_2) return tX, tY @@ -2131,7 +2129,7 @@ def __compute_via_velu_numeric(self, xP, yP): if xP in self.__kernel_mod_sign: return () - return self.__compute_via_velu(xP,yP) + return self.__compute_via_velu(xP, yP) def __compute_via_velu(self, xP, yP): r""" @@ -2219,7 +2217,7 @@ def __initialize_rational_maps_via_velu(self): """ x = self.__poly_ring.gen() y = self.__xyfield.gen(1) - return self.__compute_via_velu(x,y) + return self.__compute_via_velu(x, y) def __init_kernel_polynomial_velu(self): r""" @@ -2245,6 +2243,7 @@ def __init_kernel_polynomial_velu(self): invX = x from sage.misc.misc_c import prod + psi = prod([x - invX(xQ) for xQ in self.__kernel_mod_sign.keys()]) # building the list is not redundant; this is slightly faster self.__kernel_polynomial = poly_ring(psi) @@ -2296,16 +2295,16 @@ def __init_from_kernel_polynomial(self, kernel_polynomial): # psi_G = two_torsion_part(E, psi).monic() - if psi_G.degree() != 0: # even degree case + if psi_G.degree() != 0: # even degree case - psi_quo = psi//psi_G + psi_quo = psi // psi_G if psi_quo.degree() != 0: raise NotImplementedError("Kohel's algorithm currently only supports cyclic isogenies (except for [2])") phi, omega, v, w, _, d = self.__init_even_kernel_polynomial(E, psi_G) - else: # odd degree case + else: # odd degree case phi, omega, v, w, _, d = self.__init_odd_kernel_polynomial(E, psi) @@ -2402,8 +2401,8 @@ def __init_even_kernel_polynomial(self, E, psi_G): if self.__check and E.division_polynomial(2, x=self.__poly_ring.gen()) % psi_G != 0: raise ValueError(f"the polynomial {psi_G} does not define a finite subgroup of {E}") - n = psi_G.degree() # 1 or 3 - d = n+1 # 2 or 4 + n = psi_G.degree() # 1 or 3 + d = n + 1 # 2 or 4 a1, a2, a3, a4, a6 = E.a_invariants() b2, b4, _, _ = E.b_invariants() @@ -2415,14 +2414,14 @@ def __init_even_kernel_polynomial(self, E, psi_G): # determine y0 if self.__base_field.characteristic() == 2: - y0 = (x0**3 + a2*x0**2 + a4*x0 + a6).sqrt() + y0 = (x0**3 + a2 * x0**2 + a4 * x0 + a6).sqrt() else: - y0 = -(a1*x0 + a3)/2 + y0 = -(a1 * x0 + a3) / 2 - v,w = compute_vw_kohel_even_deg1(x0, y0, a1, a2, a4) + v, w = compute_vw_kohel_even_deg1(x0, y0, a1, a2, a4) - phi = (x*psi_G + v)*psi_G - omega = (y*psi_G**2 - v*(a1*psi_G + (y - y0)))*psi_G + phi = (x * psi_G + v) * psi_G + omega = (y * psi_G**2 - v * (a1 * psi_G + (y - y0))) * psi_G elif n == 3: s1 = -psi_G[n - 1] @@ -2432,17 +2431,17 @@ def __init_even_kernel_polynomial(self, E, psi_G): psi_G_pr = psi_G.derivative() psi_G_prpr = psi_G_pr.derivative() - phi = (psi_G_pr**2) + (-2*psi_G_prpr + (4*x - s1))*psi_G + phi = (psi_G_pr**2) + (-2 * psi_G_prpr + (4 * x - s1)) * psi_G phi_pr = phi.derivative(x) - psi_2 = 2*y + a1*x + a3 + psi_2 = 2 * y + a1 * x + a3 - omega = (psi_2*(phi_pr*psi_G - phi*psi_G_pr) - (a1*phi + a3*psi_G)*psi_G)/2 + omega = (psi_2 * (phi_pr * psi_G - phi * psi_G_pr) - (a1 * phi + a3 * psi_G) * psi_G) / 2 phi *= psi_G omega *= psi_G - v,w = compute_vw_kohel_even_deg3(b2, b4, s1, s2, s3) + v, w = compute_vw_kohel_even_deg3(b2, b4, s1, s2, s3) else: raise ValueError(f"input polynomial must have degree 1 or 3, not {n}") @@ -2516,11 +2515,12 @@ def __init_odd_kernel_polynomial(self, E, psi): to Elliptic Curve defined by y^2 + y = x^3 - 57772164980*x - 5344733777551611 over Rational Field """ n = psi.degree() - d = 2*n + 1 + d = 2 * n + 1 # check if the polynomial really divides the torsion polynomial : if self.__check: from .isogeny_small_degree import is_kernel_polynomial + if not is_kernel_polynomial(E, d, psi): raise ValueError(f"the polynomial {psi} does not define a finite subgroup of {E}") @@ -2528,11 +2528,11 @@ def __init_odd_kernel_polynomial(self, E, psi): s1 = s2 = s3 = 0 if 1 <= n: - s1 = -psi[n-1] + s1 = -psi[n - 1] if 2 <= n: - s2 = psi[n-2] + s2 = psi[n - 2] if 3 <= n: - s3 = -psi[n-3] + s3 = -psi[n - 3] # initializing these allows us to calculate E2. v, w = compute_vw_kohel_odd(b2, b4, b6, s1, s2, s3, n) @@ -2544,8 +2544,7 @@ def __init_odd_kernel_polynomial(self, E, psi): x = self.__poly_ring.gen() - phi = (4*x**3 + b2*x**2 + 2*b4*x + b6)*(psi_pr**2 - psi_prpr*psi) \ - - (6*x**2 + b2*x + b4)*psi_pr*psi + (d*x - 2*s1)*psi**2 + phi = (4 * x**3 + b2 * x**2 + 2 * b4 * x + b6) * (psi_pr**2 - psi_prpr * psi) - (6 * x**2 + b2 * x + b4) * psi_pr * psi + (d * x - 2 * s1) * psi**2 phi_pr = phi.derivative(x) @@ -2603,12 +2602,12 @@ def __compute_omega_fast(self, E, psi, psi_pr, phi, phi_pr): x = self.__poly_ring.gen() y = self.__mpoly_ring.gen() - psi_2 = 2*y + a1*x + a3 + psi_2 = 2 * y + a1 * x + a3 # The formula in Kohel's thesis has some typos: # Notably, the first plus sign should be a minus # as it is below. - return phi_pr*psi*psi_2/2 - phi*psi_pr*psi_2 - (a1*phi + a3*psi**2)*psi/2 + return phi_pr * psi * psi_2 / 2 - phi * psi_pr * psi_2 - (a1 * phi + a3 * psi**2) * psi / 2 def __compute_omega_general(self, E, psi, psi_pr, phi, phi_pr): r""" @@ -2674,7 +2673,7 @@ def __compute_omega_general(self, E, psi, psi_pr, phi, phi_pr): n = psi.degree() d = 2 * n + 1 - s1 = -psi[n-1] if n > 0 else 0 + s1 = -psi[n - 1] if n > 0 else 0 psi_prpr = 0 cur_x_pow = 1 @@ -2688,24 +2687,19 @@ def __compute_omega_general(self, E, psi, psi_pr, phi, phi_pr): from sage.arith.misc import binomial for j in range(n - 1): - psi_prpr += binomial(j+2, 2) * psi[j+2] * cur_x_pow + psi_prpr += binomial(j + 2, 2) * psi[j + 2] * cur_x_pow cur_x_pow = x * cur_x_pow psi_prprpr = 0 cur_x_pow = 1 for j in range(n - 2): - psi_prprpr += (3 * binomial(j+3, 3)) * psi[j+3] * cur_x_pow + psi_prprpr += (3 * binomial(j + 3, 3)) * psi[j + 3] * cur_x_pow cur_x_pow = x * cur_x_pow psi_2 = 2 * y + a1 * x + a3 - omega = phi_pr*psi*y - phi*psi_pr*psi_2 \ - + ((a1*x + a3)*(psi_2**2)*(psi_prpr*psi_pr-psi_prprpr*psi) - + (a1*psi_2**2 - 3*(a1*x + a3)*(6*x**2 + b2*x + b4))*psi_prpr*psi - + (a1*x**3 + 3*a3*x**2 + (2*a2*a3 - a1*a4)*x + (a3*a4 - 2*a1*a6))*psi_pr**2 - + (-(3*a1*x**2 + 6*a3*x + (-a1*a4 + 2*a2*a3)) - + (a1*x + a3)*(d*x - 2*s1) )*psi_pr*psi + (a1*s1 + a3*n)*psi**2) * psi + omega = phi_pr * psi * y - phi * psi_pr * psi_2 + ((a1 * x + a3) * (psi_2**2) * (psi_prpr * psi_pr - psi_prprpr * psi) + (a1 * psi_2**2 - 3 * (a1 * x + a3) * (6 * x**2 + b2 * x + b4)) * psi_prpr * psi + (a1 * x**3 + 3 * a3 * x**2 + (2 * a2 * a3 - a1 * a4) * x + (a3 * a4 - 2 * a1 * a6)) * psi_pr**2 + (-(3 * a1 * x**2 + 6 * a3 * x + (-a1 * a4 + 2 * a2 * a3)) + (a1 * x + a3) * (d * x - 2 * s1)) * psi_pr * psi + (a1 * s1 + a3 * n) * psi**2) * psi return omega @@ -2760,9 +2754,9 @@ def __compute_via_kohel(self, xP, yP): a = self.__phi(xP) omega0 = self.__omega[0] omega1 = self.__omega[1] - b = omega0(xP) + omega1(xP)*yP + b = omega0(xP) + omega1(xP) * yP c = self.__psi(xP) - return a/c**2, b/c**3 + return a / c**2, b / c**3 def __initialize_rational_maps_via_kohel(self): r""" @@ -3031,7 +3025,7 @@ def _set_pre_isomorphism(self, preWI): isom = preWI domain = WIdom else: - isom = self.__pre_isomorphism*preWI + isom = self.__pre_isomorphism * preWI domain = WIdom self.__clear_cached_values() @@ -3094,7 +3088,7 @@ def _set_post_isomorphism(self, postWI): isom = postWI codomain = WIcod else: - isom = postWI*self.__post_isomorphism + isom = postWI * self.__post_isomorphism codomain = WIcod self.__clear_cached_values() @@ -3275,16 +3269,17 @@ def dual(self): from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite - if F(d) == 0: # inseparable dual! + if F(d) == 0: # inseparable dual! p = F.characteristic() k = d.valuation(p) from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius + frob = EllipticCurveHom_frobenius(self._codomain, k) dsep = d // p**k if dsep > 1: - #TODO: We could also use resultants here; this is much + # TODO: We could also use resultants here; this is much # faster in some cases (but seems worse in general). # Presumably there should be a wrapper function that # decides on the fly which method to use. @@ -3310,6 +3305,7 @@ def dual(self): phi_hat = EllipticCurveHom_composite.from_factors([frob, sep]) from sage.schemes.elliptic_curves.hom import find_post_isomorphism + mult = self._domain.scalar_multiplication(d) rhs = phi_hat * self corr = find_post_isomorphism(mult, rhs) @@ -3320,7 +3316,7 @@ def dual(self): # this should take care of the case when the isogeny is # not normalized. u = self.scaling_factor() - E2 = E2pr.change_weierstrass_model(u/F(d), 0, 0, 0) + E2 = E2pr.change_weierstrass_model(u / F(d), 0, 0, 0) phi_hat = EllipticCurveIsogeny(E1, None, E2, d) # assert phi_hat.scaling_factor() == 1 @@ -3417,7 +3413,7 @@ def compute_isogeny_bmss(E1, E2, l): if E2.a1() or E2.a2() or E2.a3(): raise ValueError('E2 must be a short Weierstrass curve') char = E1.base_ring().characteristic() - if char != 0 and char < 4*l + 4: + if char != 0 and char < 4 * l + 4: raise ValueError('characteristic must be at least 4*degree+4') Rx, x = E1.base_ring()["x"].objgen() # Compute C = 1/(1 + Ax^4 + Bx^6) mod x^4l @@ -3460,7 +3456,7 @@ def compute_isogeny_bmss(E1, E2, l): if not Q.is_square(): raise ValueError(f"the two curves are not linked by a cyclic normalized isogeny of degree {l}") Q = Q.sqrt() - ker = Rx(Q).reverse(degree=l//2) + ker = Rx(Q).reverse(degree=l // 2) return ker.monic() @@ -3538,41 +3534,41 @@ def compute_isogeny_stark(E1, E2, ell): K = E1.base_field() R, x = PolynomialRing(K, 'x').objgen() - wp1 = E1.weierstrass_p(prec=4*ell+4) #BMSS2006 claim 2*ell is enough, but it is not M09 - wp2 = E2.weierstrass_p(prec=4*ell+4) + wp1 = E1.weierstrass_p(prec=4 * ell + 4) # BMSS2006 claim 2*ell is enough, but it is not M09 + wp2 = E2.weierstrass_p(prec=4 * ell + 4) # viewed them as power series in Z = z^2 Z = LaurentSeriesRing(K, 'Z').gen() - pe1 = pe2 = 1/Z - for i in range(2*ell + 1): - pe1 += wp1[2*i] * Z**i - pe2 += wp2[2*i] * Z**i - pe1 = pe1.add_bigoh(2*ell+3) - pe2 = pe2.add_bigoh(2*ell+3) + pe1 = pe2 = 1 / Z + for i in range(2 * ell + 1): + pe1 += wp1[2 * i] * Z**i + pe2 += wp2[2 * i] * Z**i + pe1 = pe1.add_bigoh(2 * ell + 3) + pe2 = pe2.add_bigoh(2 * ell + 3) n = 1 q = [R.one(), R.zero()] T = pe2 - while q[n].degree() < ell-1: + while q[n].degree() < ell - 1: n += 1 a_n = 0 r = -T.valuation() while 0 <= r: t_r = T[-r] a_n = a_n + t_r * x**r - T = T - t_r*pe1**r + T = T - t_r * pe1**r r = -T.valuation() - q_n = a_n*q[n-1] + q[n-2] + q_n = a_n * q[n - 1] + q[n - 2] q.append(q_n) - if n == ell+1 or T == 0: + if n == ell + 1 or T == 0: if T == 0 or T.valuation() < 2: raise ValueError(f"the two curves are not linked by a cyclic normalized isogeny of degree {ell}") break - T = 1/T + T = 1 / T qn = q[n] qn /= qn.leading_coefficient() @@ -3675,7 +3671,7 @@ def compute_isogeny_kernel_polynomial(E1, E2, ell, algorithm=None): char = E1.base_ring().characteristic() # This could be 4l+4 according to Stark/BMSS alone, but # weierstrass_p() currently only works for p-2 >= 4l+4. - if char != 0 and char < 4*ell + 6: + if char != 0 and char < 4 * ell + 6: # No good algorithm available... See :issue:`38481`. algorithm = 'bruteforce' else: @@ -3789,9 +3785,9 @@ def compute_intermediate_curves(E1, E2): # as the resulting isomorphisms would not be normalised (u=1) c4, c6 = E1.c_invariants() - E1w = EllipticCurve([0, 0, 0, -c4/48, -c6/864]) + E1w = EllipticCurve([0, 0, 0, -c4 / 48, -c6 / 864]) c4, c6 = E2.c_invariants() - E2w = EllipticCurve([0, 0, 0, -c4/48, -c6/864]) + E2w = EllipticCurve([0, 0, 0, -c4 / 48, -c6 / 864]) # We cannot even just use pre_iso = E1.isomorphism_to(E1w) since # it may have u=-1; similarly for E2 @@ -3900,6 +3896,7 @@ def compute_sequence_of_maps(E1, E2, ell): return pre_isom, post_isom, E1pr, E2pr, ker_poly + # Utility functions for manipulating isogeny degree matrices @@ -3944,7 +3941,7 @@ def fill_isogeny_matrix(M): n = M.nrows() M0 = copy(M) for i in range(n): - M0[i,i] = 1 + M0[i, i] = 1 def fix(d): return d if d != 0 else Infinity @@ -3953,7 +3950,7 @@ def fix2(d): return d if d != Infinity else 0 def pr(M1, M2): - return Matrix([[fix2(min([fix(M1[i,k]*M2[k,j]) for k in range(n)])) for i in range(n)] for j in range(n)]) + return Matrix([[fix2(min([fix(M1[i, k] * M2[k, j]) for k in range(n)])) for i in range(n)] for j in range(n)]) M1 = M0 M2 = pr(M0, M1) @@ -4008,9 +4005,9 @@ def unfill_isogeny_matrix(M): M1 = copy(M) zero = Integer(0) for i in range(n): - M1[i,i] = zero + M1[i, i] = zero for j in range(i): - if not M1[i,j].is_prime(): - M1[i,j] = zero - M1[j,i] = zero + if not M1[i, j].is_prime(): + M1[i, j] = zero + M1[j, i] = zero return M1 diff --git a/src/sage/schemes/elliptic_curves/ell_egros.py b/src/sage/schemes/elliptic_curves/ell_egros.py index df09cf2bf50..fb52eb9084b 100644 --- a/src/sage/schemes/elliptic_curves/ell_egros.py +++ b/src/sage/schemes/elliptic_curves/ell_egros.py @@ -114,9 +114,7 @@ def is_possible_j(j, S=[]): True """ j = QQ(j) - return (j.is_zero() and 3 in S) or (j == 1728) \ - or (j.is_S_integral(S) and j.prime_to_S_part(S).is_nth_power(3) - and (j - 1728).prime_to_S_part(S).abs().is_square()) + return (j.is_zero() and 3 in S) or (j == 1728) or (j.is_S_integral(S) and j.prime_to_S_part(S).is_nth_power(3) and (j - 1728).prime_to_S_part(S).abs().is_square()) def curve_key(E1): @@ -141,6 +139,7 @@ def curve_key(E1): """ try: from sage.databases.cremona import parse_cremona_label, class_to_int + N, l, k = parse_cremona_label(E1.label()) return (N, 0, class_to_int(l), k) except LookupError: @@ -386,6 +385,7 @@ def egros_get_j(S=[], proof=None, verbose=False): if proof is None: from sage.structure.proof.proof import get_flag + proof = get_flag(proof, "elliptic_curve") else: proof = bool(proof) @@ -396,7 +396,7 @@ def egros_get_j(S=[], proof=None, verbose=False): SS = [-1] + S jlist = [] - nw = 6**len(S) * 2 + nw = 6 ** len(S) * 2 if verbose: print("Finding possible j invariants for S = ", S) diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index 759e63bbabe..e62ded9c8d1 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -4,6 +4,7 @@ This module defines the class :class:`EllipticCurve_field`, based on :class:`EllipticCurve_generic`, for elliptic curves over general fields. """ + # ***************************************************************************** # Copyright (C) 2006 William Stein # @@ -48,6 +49,7 @@ def __init__(self, R, data, category=None) -> None: Category of abelian varieties over Finite Field of size 101 """ from sage.categories.schemes import AbelianVarieties + if category is None: category = AbelianVarieties(R) super().__init__(R, data, category=category) @@ -211,12 +213,12 @@ def quadratic_twist(self, D=None): if char != 2: b2, b4, b6, b8 = self.b_invariants() # E is isomorphic to [0,b2,0,8*b4,16*b6] - return EllipticCurve(K, [0, b2*D, 0, 8*b4*D**2, 16*b6*D**3]) + return EllipticCurve(K, [0, b2 * D, 0, 8 * b4 * D**2, 16 * b6 * D**3]) # now char==2 if self.j_invariant() != 0: # iff a1!=0 a1, a2, a3, a4, a6 = self.ainvs() - E0 = self.change_weierstrass_model(a1, a3/a1, 0, (a1**2*a4+a3**2)/a1**3) + E0 = self.change_weierstrass_model(a1, a3 / a1, 0, (a1**2 * a4 + a3**2) / a1**3) # which has the form = [1,A2,0,0,A6] assert E0.a1() == K(1) assert E0.a3() == K(0) @@ -445,6 +447,7 @@ def is_quadratic_twist(self, other): True """ from sage.schemes.elliptic_curves.ell_generic import EllipticCurve_generic + E = self F = other if not isinstance(E, EllipticCurve_generic) or not isinstance(F, EllipticCurve_generic): @@ -477,23 +480,23 @@ def is_quadratic_twist(self, other): c4F, c6F = F.c_invariants() if j == 0: - um = c6E/c6F + um = c6E / c6F x = polygen(K) - ulist = (x**3-um).roots(multiplicities=False) + ulist = (x**3 - um).roots(multiplicities=False) if not ulist: D = zero else: D = ulist[0] elif j == 1728: - um = c4E/c4F + um = c4E / c4F x = polygen(K) - ulist = (x**2-um).roots(multiplicities=False) + ulist = (x**2 - um).roots(multiplicities=False) if not ulist: D = zero else: D = ulist[0] else: - D = (c6E*c4F)/(c6F*c4E) + D = (c6E * c4F) / (c6F * c4E) # Normalization of output: @@ -544,6 +547,7 @@ def is_quartic_twist(self, other): True """ from sage.schemes.elliptic_curves.ell_generic import EllipticCurve_generic + E = self F = other if not isinstance(E, EllipticCurve_generic) or not isinstance(F, EllipticCurve_generic): @@ -613,6 +617,7 @@ def is_sextic_twist(self, other): True """ from sage.schemes.elliptic_curves.ell_generic import EllipticCurve_generic + E = self F = other if not isinstance(E, EllipticCurve_generic) or not isinstance(F, EllipticCurve_generic): @@ -804,9 +809,9 @@ def descend_to(self, K, f=None) -> list: # list of d in K such that t/d is in L*^2 except AttributeError: raise NotImplementedError("Not implemented over %s" % L) - c = -27*jK/(jK-1728) # =-27c4^3/c6^2 - a4list = [c*d**2 for d in dlist] - a6list = [2*a4*d for a4, d in zip(a4list, dlist)] + c = -27 * jK / (jK - 1728) # =-27c4^3/c6^2 + a4list = [c * d**2 for d in dlist] + a6list = [2 * a4 * d for a4, d in zip(a4list, dlist)] Elist = [EllipticCurve([0, 0, 0, a4, a6]) for a4, a6 in zip(a4list, a6list)] if K is QQ: @@ -1043,8 +1048,8 @@ def division_field(self, n, names='t', map=False, **kwds): # The Galois group of the X-coordinates is a subgroup of GL(2,n)/{-1,+1}. if F in NumberFields(): from sage.misc.misc_c import prod - deg_mult = F.degree() * prod(l * (l+1) * (l-1)**2 * l**(4*(e-1)) - for l, e in n.factor()) // 2 + + deg_mult = F.degree() * prod(l * (l + 1) * (l - 1) ** 2 * l ** (4 * (e - 1)) for l, e in n.factor()) // 2 K, F_to_K = f.splitting_field(names, degree_multiple=deg_mult, map=True, **kwds) elif F in FiniteFields(): K, F_to_K = f.splitting_field('u', map=True, **kwds) @@ -1289,7 +1294,7 @@ def torsion_subgroup(self, n, *, extend=False, algorithm=None): if algorithm == 'divpoly': accP = accQ = E.zero() - for l,m in n.factor(): + for l, m in n.factor(): pts = filter(bool, E.zero().division_points(l)) try: P = Pl = next(pts) @@ -1328,7 +1333,7 @@ def torsion_subgroup(self, n, *, extend=False, algorithm=None): # We're in luck! Strategy: https://ia.cr/2025/477 §5.5 q = F.order() - z = F.primitive_element()**(q//l) + z = F.primitive_element() ** (q // l) profile = lambda U: tuple(B.tate_pairing(U, l, 1, q=q).log(z, order=l) for B in (Pl, Ql)) from sage.rings.finite_rings.integer_mod_ring import Zmod @@ -1339,8 +1344,8 @@ def torsion_subgroup(self, n, *, extend=False, algorithm=None): ker = mat.left_kernel() if not ker: break - ker, = tuple(ker.basis()) - P, P._order = P + ker[1]/ker[0] * Q, P._order + (ker,) = tuple(ker.basis()) + P, P._order = P + ker[1] / ker[0] * Q, P._order P = P.division_points(l)[0] if P._order < Q._order: @@ -1364,10 +1369,10 @@ def torsion_subgroup(self, n, *, extend=False, algorithm=None): if P._order < Q._order: P, Q = Q, P -# if __debug__: -# from sage.groups.generic import has_order -# -# assert has_order(P.weil_pairing(Q, P._order), Q._order, operation='*') + # if __debug__: + # from sage.groups.generic import has_order + # + # assert has_order(P.weil_pairing(Q, P._order), Q._order, operation='*') accP, accP._order = accP + P, accP._order.lcm(P._order) accQ, accQ._order = accQ + Q, accQ._order.lcm(Q._order) @@ -1375,6 +1380,7 @@ def torsion_subgroup(self, n, *, extend=False, algorithm=None): gens = list(filter(bool, [accP, accQ])) from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper + return AdditiveAbelianGroupWrapper(E.point_homset(), gens, [pt.order() for pt in gens]) raise ValueError(f'unknown algorithm {algorithm!r}') @@ -1540,8 +1546,10 @@ def _Hom_(self, other, category=None): """ if isinstance(other, ell_generic.EllipticCurve_generic) and self.base_ring() == other.base_ring(): from . import homset + return homset.EllipticCurveHomset(self, other, category=category) from sage.schemes.generic.homset import SchemeHomset_generic + return SchemeHomset_generic(self, other, category=category) def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, algorithm=None, velu_sqrt_bound=None): @@ -1839,9 +1847,11 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al raise TypeError('cannot pass "degree" and "algorithm" parameters simultaneously') if algorithm == "velusqrt": from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt + return EllipticCurveHom_velusqrt(self, kernel, codomain=codomain, model=model) if algorithm == "factored": from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite + return EllipticCurveHom_composite(self, kernel, codomain=codomain, model=model, velu_sqrt_bound=velu_sqrt_bound) if algorithm == "traditional": return EllipticCurveIsogeny(self, kernel, codomain, degree, model, check=check) @@ -1851,6 +1861,7 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al kernel_is_list = isinstance(kernel, (list, tuple)) if kernel_is_list and kernel[0] in self and len(kernel) > 1: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite + return EllipticCurveHom_composite(self, kernel, codomain=codomain, model=model, velu_sqrt_bound=velu_sqrt_bound) if not kernel_is_list or (len(kernel) == 1 and kernel[0] in self): @@ -1863,14 +1874,17 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al if known_order and kernel._order.is_pseudoprime(): if not velu_sqrt_bound: from sage.schemes.elliptic_curves.hom_velusqrt import _velu_sqrt_bound + velu_sqrt_bound = _velu_sqrt_bound.get() if kernel._order > velu_sqrt_bound: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt + return EllipticCurveHom_velusqrt(self, kernel, codomain=codomain, model=model) # Otherwise fall back to the standard case elif known_order: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite + return EllipticCurveHom_composite(self, kernel, codomain=codomain, model=model, velu_sqrt_bound=velu_sqrt_bound) try: return EllipticCurveIsogeny(self, kernel, codomain, degree, model, check=check) @@ -1967,6 +1981,7 @@ def period_lattice(self): IndexError: list index out of range """ from sage.schemes.elliptic_curves.period_lattice import PeriodLattice_ell + return PeriodLattice_ell(self) def kernel_polynomial_from_point(self, P, *, algorithm=None): @@ -2093,7 +2108,8 @@ def kernel_polynomial_from_point(self, P, *, algorithm=None): if algorithm == 'basic': from sage.groups.generic import multiples - Qs = multiples(P, l//2, P) + + Qs = multiples(P, l // 2, P) x = polygen(S) f = prod(x - Q.xy()[0] for Q in Qs) return f.change_ring(R) @@ -2180,10 +2196,11 @@ def kernel_polynomial_from_divisor(self, f, l, *, check=True): if l == 2: return f - if not f.degree().divides(l//2): + if not f.degree().divides(l // 2): raise ValueError(f'given polynomial does not define a rational {l}-isogeny') from sage.schemes.elliptic_curves.isogeny_small_degree import _least_semi_primitive + a = _least_semi_primitive(l) def mul_a(x): @@ -2193,7 +2210,7 @@ def x_mod(g): return g.parent().quotient(g).gen() fs = [f] - m = l//2//f.degree() + m = l // 2 // f.degree() for i in range(1, m): fs.append(mul_a(x_mod(fs[-1])).minpoly()) @@ -2477,6 +2494,7 @@ def isogenies_prime_degree(self, l=None, max_l=31) -> list: if l is None: from sage.rings.fast_arith import prime_range + L = prime_range(max_l + 1) else: try: @@ -2487,6 +2505,7 @@ def isogenies_prime_degree(self, l=None, max_l=31) -> list: L = [ZZ(d) for d in l] from .isogeny_small_degree import isogenies_prime_degree + return sum([isogenies_prime_degree(self, d) for d in L], []) def isogenies_degree(self, n, *, _intermediate=False): @@ -2611,6 +2630,7 @@ def isogenies_degree(self, n, *, _intermediate=False): sage: list(E.isogenies_degree(product(prime_range(3, 53)) * 53)) [] """ + def compute_key(phi): """ Data used in ``hash(phi)`` excluding the expensive ``.kernel_polynomial``. @@ -2708,6 +2728,7 @@ def is_isogenous(self, other, field=None) -> bool: NotImplementedError: Only implemented for isomorphic curves over general fields. """ from .ell_generic import EllipticCurve_generic + if not isinstance(other, EllipticCurve_generic): raise ValueError("Second argument is not an Elliptic Curve.") if self.is_isomorphic(other): @@ -2757,6 +2778,7 @@ def weierstrass_p(self, prec=20, algorithm=None): + 3539374016033/7723451736000*z^16 + 413306031683977/1289540602350000*z^18 + O(z^20) """ from .ell_wp import weierstrass_p + return weierstrass_p(self, prec=prec, algorithm=algorithm) def hasse_invariant(self): @@ -2829,8 +2851,8 @@ def hasse_invariant(self): R = k['x'] x = R.gen() E = self.short_weierstrass_model() - f = (x**3+E.a4()*x+E.a6())**((p-1)//2) - return f.coefficients(sparse=False)[p-1] + f = (x**3 + E.a4() * x + E.a6()) ** ((p - 1) // 2) + return f.coefficients(sparse=False)[p - 1] def isogeny_ell_graph(self, l, directed=True, label_by_j=False): """ @@ -3001,15 +3023,13 @@ class of curves. If the j-invariant is not unique in the isogeny labels = [] # list of vertex labels for i, E in enumerate(Es): if 0 < curve_max < len(Es): - warn('Isogeny graph contains more than ' - + str(curve_max) + ' curves.') + warn('Isogeny graph contains more than ' + str(curve_max) + ' curves.') curve_max = 0 r = [0] * len(Es) # adjacency matrix row for I in E.isogenies_prime_degree(l): C = I.codomain() - j = next((k for k, F in enumerate(Es) if C.is_isomorphic(F)), - -1) # index of curve isomorphic to codomain of isogeny + j = next((k for k, F in enumerate(Es) if C.is_isomorphic(F)), -1) # index of curve isomorphic to codomain of isogeny if j >= 0: r[j] += 1 else: @@ -3041,8 +3061,7 @@ class of curves. If the j-invariant is not unique in the isogeny else: from sage.graphs.graph import Graph as GraphType - G = GraphType(A, format='adjacency_matrix', - data_structure='static_sparse') + G = GraphType(A, format='adjacency_matrix', data_structure='static_sparse') # inplace relabelling is necessary for static_sparse graphs GL = G.relabel(labels, inplace=False) return GL @@ -3132,6 +3151,7 @@ def compute_model(E, name): if name == 'minimal': from sage.rings.number_field.number_field_base import NumberField + if not isinstance(E.base_field(), NumberField): raise ValueError('can only compute minimal model for curves over number fields') return E.global_minimal_model(semi_global=True) @@ -3199,6 +3219,7 @@ def point_of_order(E, n): sage: Q.order() 4 """ + # Construct the field extension defined by the given polynomial, # in such a way that the result is recognized by Sage as a field. def ffext(poly): diff --git a/src/sage/schemes/elliptic_curves/ell_finite_field.py b/src/sage/schemes/elliptic_curves/ell_finite_field.py index a7a87d344d5..befa3fbee3e 100644 --- a/src/sage/schemes/elliptic_curves/ell_finite_field.py +++ b/src/sage/schemes/elliptic_curves/ell_finite_field.py @@ -231,6 +231,7 @@ def points(self): return self.__points from sage.structure.sequence import Sequence + v = self._points_via_group_structure() v.sort() self.__points = Sequence(v, immutable=True) @@ -508,8 +509,7 @@ def cardinality(self, algorithm=None, extension_degree=1): self._order = N return N - from .cardinality import (cardinality_bsgs, - cardinality_exhaustive, _cardinality_subfield) + from .cardinality import cardinality_bsgs, cardinality_exhaustive, _cardinality_subfield order = cardinality # alias @@ -619,20 +619,22 @@ def division_field(self, n, names='t', map=False, **kwds): F = self.base_field() if self.is_supersingular(): - n = n.prime_to_m_part(F.characteristic()) # p-torsion is trivial + n = n.prime_to_m_part(F.characteristic()) # p-torsion is trivial if n.is_one(): ext = 1 elif n == 2: ext = 3 if self.two_torsion_rank() == 0 else 2 if self.two_torsion_rank() == 1 else 1 else: from sage.rings.finite_rings.integer_mod import Mod + if (pi := self.frobenius()) in ZZ: ext = Mod(pi, n).multiplicative_order() else: - m = next(m for m in range(1,7) if not (pi**m)[1] % n) + m = next(m for m in range(1, 7) if not (pi**m)[1] % n) ext = m * Mod((pi**m)[0], n).multiplicative_order() else: + def van_tuyl(N): if not N.is_prime(): # currently not implemented here; defer to general implementation @@ -641,16 +643,17 @@ def van_tuyl(N): chi = self.frobenius_polynomial() chi_mod_N = chi.change_ring(GF(N)) - if (roots := chi_mod_N.roots(multiplicities=False)): + if roots := chi_mod_N.roots(multiplicities=False): if len(roots) == 1: # repeated root assert F(N) dstar = roots[0].multiplicative_order() from sage.rings.qqbar import QQbar - gamma, delta = (r for r,m in chi.roots(ring=QQbar) for _ in range(m)) - if (N**2).divides(1 + F.cardinality()**dstar - gamma**dstar - delta**dstar): - l = lcm(f.degree() for f,_ in self.division_polynomial(N).factor()) - if dstar in (l, 2*l): + + gamma, delta = (r for r, m in chi.roots(ring=QQbar) for _ in range(m)) + if (N**2).divides(1 + F.cardinality() ** dstar - gamma**dstar - delta**dstar): + l = lcm(f.degree() for f, _ in self.division_polynomial(N).factor()) + if dstar in (l, 2 * l): return dstar return N * dstar @@ -658,7 +661,7 @@ def van_tuyl(N): return GF(N).extension(chi_mod_N, 'U').gen().multiplicative_order() - ext = lcm(van_tuyl(f**e) for f,e in n.factor()) + ext = lcm(van_tuyl(f**e) for f, e in n.factor()) return F.extension(ext, names=names, map=map, **kwds) @@ -710,7 +713,7 @@ def frobenius_polynomial(self): (x + 5)^2 """ x = polygen(ZZ) - return x**2-self.trace_of_frobenius()*x+self.base_field().cardinality() + return x**2 - self.trace_of_frobenius() * x + self.base_field().cardinality() def frobenius_order(self): r""" @@ -1115,27 +1118,27 @@ def abelian_group(self): if len(gens) == 2: P, Q = gens - n = self.cardinality() # cached - n1 = P.order() # cached - n2 = n//n1 - assert not n1 * Q # PARI should guarantee this + n = self.cardinality() # cached + n1 = P.order() # cached + n2 = n // n1 + assert not n1 * Q # PARI should guarantee this k = n1.prime_to_m_part(n2) - Q *= k # don't need; kill that part - nQ = n2 * generic.order_from_multiple(n2*Q, n1//k//n2) + Q *= k # don't need; kill that part + nQ = n2 * generic.order_from_multiple(n2 * Q, n1 // k // n2) - S = n//nQ * P + S = n // nQ * P T = n2 * Q - S.set_order(nQ//n2, check=False) # for .log() + S.set_order(nQ // n2, check=False) # for .log() x = T.log(S) - Q -= x * n1//nQ * P + Q -= x * n1 // nQ * P - assert not n2 * Q # by construction + assert not n2 * Q # by construction Q.set_order(n2, check=False) gens = P, Q - orders = [T.order() for T in gens] # cached + orders = [T.order() for T in gens] # cached self.gens.set_cache(gens) return AdditiveAbelianGroupWrapper(self.point_homset(), gens, orders) @@ -1323,7 +1326,7 @@ def torsion_subgroup(self, n, *, extend=False, algorithm=None): for step in range(999): # check P,Q is a basis of the subgroup with ord(Q) | ord(P) assert Q._order.divides(P._order) -# assert generic.has_order(P.weil_pairing(Q, P._order), Q._order, operation='*') + # assert generic.has_order(P.weil_pairing(Q, P._order), Q._order, operation='*') if n.divides(Q._order): P *= P._order // n @@ -1337,7 +1340,7 @@ def torsion_subgroup(self, n, *, extend=False, algorithm=None): cof = N.prime_to_m_part(n) T = cof * E.random_point() - T.set_order(multiple=N//cof, check=False) + T.set_order(multiple=N // cof, check=False) # extend P using T as much as possible m, k1, k2 = xlcm(P._order, T._order) @@ -1371,9 +1374,9 @@ def torsion_subgroup(self, n, *, extend=False, algorithm=None): assert hasattr(P, '_order') assert hasattr(Q, '_order') -# if P and Q: -# assert Q._order.divides(P._order) -# assert generic.has_order(P.weil_pairing(Q, P._order), Q._order, operation='*') + # if P and Q: + # assert Q._order.divides(P._order) + # assert generic.has_order(P.weil_pairing(Q, P._order), Q._order, operation='*') gens = list(filter(bool, [P, Q])) return AdditiveAbelianGroupWrapper(E.point_homset(), gens, [pt._order for pt in gens]) @@ -1478,6 +1481,7 @@ def is_isogenous(self, other, field=None, proof=True): False """ from .ell_generic import EllipticCurve_generic + if not isinstance(other, EllipticCurve_generic): raise ValueError("Second argument is not an Elliptic Curve.") if self.is_isomorphic(other): @@ -1488,13 +1492,11 @@ def is_isogenous(self, other, field=None, proof=True): if self.base_field().degree() == other.base_field().degree(): return self.cardinality() == other.cardinality() - if self.base_field().degree() == gcd(self.base_field().degree(), - other.base_field().degree()): - return self.cardinality(extension_degree=other.base_field().degree()//self.base_field().degree()) == other.cardinality() + if self.base_field().degree() == gcd(self.base_field().degree(), other.base_field().degree()): + return self.cardinality(extension_degree=other.base_field().degree() // self.base_field().degree()) == other.cardinality() - if other.base_field().degree() == gcd(self.base_field().degree(), - other.base_field().degree()): - return other.cardinality(extension_degree=self.base_field().degree()//other.base_field().degree()) == self.cardinality() + if other.base_field().degree() == gcd(self.base_field().degree(), other.base_field().degree()): + return other.cardinality(extension_degree=self.base_field().degree() // other.base_field().degree()) == self.cardinality() raise ValueError("Curves have different base fields: use the field parameter.") else: @@ -1896,7 +1898,7 @@ def height_above_floor(self, ell, e): # is that Frobenius must be of the form phi o [p^k] where phi is # a purely inseparable isogeny of degree 1 or p, hence this [p^k] # can always be divided out while retaining an endomorphism. - assert self.base_field().cardinality().valuation(ell) >= 2*e + assert self.base_field().cardinality().valuation(ell) >= 2 * e return e # In the supersingular case, the j-invariant alone does not determine @@ -1933,22 +1935,23 @@ def height_above_floor(self, ell, e): x = polygen(F) from sage.rings.polynomial.polynomial_ring import polygens from sage.schemes.elliptic_curves.mod_poly import classical_modular_polynomial + X, Y = polygens(F, 'X,Y') phi = classical_modular_polynomial(ell)(X, Y) - j1 = phi([x,j]).roots(multiplicities=False) + j1 = phi([x, j]).roots(multiplicities=False) nj1 = len(j1) on_floor = self.two_torsion_rank() < 2 if ell == 2 else nj1 <= ell if on_floor: return ZZ.zero() - if e == 1 or nj1 != ell+1: # double roots can only happen at the surface + if e == 1 or nj1 != ell + 1: # double roots can only happen at the surface return e if nj1 < 3: return ZZ.zero() - j0 = [j,j,j] + j0 = [j, j, j] h = ZZ.one() while True: for i in range(3): - r = (phi([x,j1[i]])//(x-j0[i])).roots(multiplicities=False) + r = (phi([x, j1[i]]) // (x - j0[i])).roots(multiplicities=False) if not r: return h j0[i] = j1[i] @@ -2009,25 +2012,26 @@ def endomorphism_discriminant_from_class_number(self, h): D0 = D1.squarefree_part() if D0 % 4 != 1: D0 *= 4 - v = ZZ(D1//D0).isqrt() + v = ZZ(D1 // D0).isqrt() h0 = D0.class_number() if h % h0: raise ValueError("Incorrect class number {}".format(h)) from sage.schemes.elliptic_curves.cm import OrderClassNumber - cs = [v//f for f in v.divisors() if OrderClassNumber(D0,h0,f) == h] # cofactors c=v/f compatible with h(f**2D0)=h + + cs = [v // f for f in v.divisors() if OrderClassNumber(D0, h0, f) == h] # cofactors c=v/f compatible with h(f**2D0)=h if not cs: raise ValueError("Incorrect class number {}".format(h)) if len(cs) == 1: - return (v//cs[0])**2 * D0 + return (v // cs[0]) ** 2 * D0 L = sorted(set(sum([c.prime_factors() for c in cs], []))) for ell in L: - e = self.height_above_floor(ell,v.valuation(ell)) + e = self.height_above_floor(ell, v.valuation(ell)) cs = [c for c in cs if c.valuation(ell) == e] if not cs: raise ValueError("Incorrect class number {}".format(h)) if len(cs) == 1: - return (v//cs[0])**2 * D0 + return (v // cs[0]) ** 2 * D0 raise ValueError("Incorrect class number {}".format(h)) def endomorphism_order(self): @@ -2086,9 +2090,9 @@ def endomorphism_order(self): f0 = O.conductor() f = 1 - for l,e in f0.factor(): + for l, e in f0.factor(): h = self.height_above_floor(l, e) - f *= l**(e-h) + f *= l ** (e - h) K = O.number_field() return K.order_of_conductor(f) @@ -2411,7 +2415,7 @@ def curves_with_j_1728(K): return curves_with_j_0_char3(K) q = K.cardinality() if q % 4 == 3: - return [EllipticCurve(K, [a,0]) for a in [1,-1]] + return [EllipticCurve(K, [a, 0]) for a in [1, -1]] # Now we have genuine quartic twists, find D generating K* mod 4th powers q2 = (q - 1) // 2 D = K.gen() @@ -2486,9 +2490,7 @@ def curves_with_j_0_char2(K): if not K.is_finite() or K.characteristic() != 2: raise ValueError("field must be finite of characteristic 2") if K.degree() % 2: - return [EllipticCurve(K, [0, 0, 1, 0, 0]), - EllipticCurve(K, [0, 0, 1, 1, 0]), - EllipticCurve(K, [0, 0, 1, 1, 1])] + return [EllipticCurve(K, [0, 0, 1, 0, 0]), EllipticCurve(K, [0, 0, 1, 1, 0]), EllipticCurve(K, [0, 0, 1, 1, 1])] # find a,b,c,d,e such that # a is not a cube, i.e. a**((q-1)//3)!=1 # Tr(b)=1 @@ -2497,22 +2499,21 @@ def curves_with_j_0_char2(K): # X^2+a^2*X+e irreducible a = b = c = d = e = None x = polygen(K) - q3 = (K.cardinality()-1)//3 + q3 = (K.cardinality() - 1) // 3 while not a or a**q3 == 1: a = K.random_element() - asq = a*a + asq = a * a while not b or not b.trace(): b = K.random_element() - c = K.one() # OK if degree is 2 mod 4 + c = K.one() # OK if degree is 2 mod 4 if K.degree() % 4 == 0: - while (x**4+x+c).roots(): + while (x**4 + x + c).roots(): c = K.random_element() - while not d or (x**2+a*x+d).roots(): + while not d or (x**2 + a * x + d).roots(): d = K.random_element() - while not e or (x**2+asq*x+e).roots(): + while not e or (x**2 + asq * x + e).roots(): e = K.random_element() - return [EllipticCurve(K, ai) for ai in - [[0,0,1,0,0], [0,0,1,0,b], [0,0,1,c,0], [0,0,a,0,0], [0,0,a,0,d], [0,0,asq,0,0], [0,0,asq,0,e]]] + return [EllipticCurve(K, ai) for ai in [[0, 0, 1, 0, 0], [0, 0, 1, 0, b], [0, 0, 1, c, 0], [0, 0, a, 0, 0], [0, 0, a, 0, d], [0, 0, asq, 0, 0], [0, 0, asq, 0, e]]] def curves_with_j_0_char3(K): @@ -2587,24 +2588,23 @@ def curves_with_j_0_char3(K): b = K.random_element() if K.degree() % 2: - return [EllipticCurve(K, a4a6) for a4a6 in - [[1,0], [-1,0], [-1,b], [-1,-b]]] + return [EllipticCurve(K, a4a6) for a4a6 in [[1, 0], [-1, 0], [-1, b], [-1, -b]]] # find a, i, c where: # a generates K* mod 4th powers, i.e. non-square, # i^2=-1 # c with x^3+a^2*x+c irreducible a = K.gen() - q2 = (K.cardinality()-1)//2 + q2 = (K.cardinality() - 1) // 2 while not a or a**q2 == 1: a = K.random_element() x = polygen(K) - i = (x**2+1).roots()[0][0] + i = (x**2 + 1).roots()[0][0] c = None - while not c or (x**3 + a**2*x + c).roots(): + while not c or (x**3 + a**2 * x + c).roots(): c = K.random_element() - return [EllipticCurve(K, a4a6) for a4a6 in - [[1,0], [1,i*b], [a,0], [a**2,0], [a**2,c], [a**3,0]]] + return [EllipticCurve(K, a4a6) for a4a6 in [[1, 0], [1, i * b], [a, 0], [a**2, 0], [a**2, c], [a**3, 0]]] + # dict to hold precomputed coefficient vectors of supersingular j values (excluding 0, 1728): @@ -2740,7 +2740,7 @@ def supersingular_j_polynomial(p, use_cache=True): if not p.is_prime(): raise ValueError("p (=%s) should be a prime number" % p) - J = polygen(GF(p),'j') + J = polygen(GF(p), 'j') if p < 13: return J.parent().one() if use_cache: @@ -2749,10 +2749,11 @@ def supersingular_j_polynomial(p, use_cache=True): return J.parent()(supersingular_j_polynomials[p]) from sage.misc.misc_c import prod - m = (p-1)//2 - X,T = PolynomialRing(GF(p),2,names=['X','T']).gens() - H = sum(binomial(m, i) ** 2 * T ** i for i in range(m + 1)) - F = T**2 * (T-1)**2 * X - 256*(T**2-T+1)**3 + + m = (p - 1) // 2 + X, T = PolynomialRing(GF(p), 2, names=['X', 'T']).gens() + H = sum(binomial(m, i) ** 2 * T**i for i in range(m + 1)) + F = T**2 * (T - 1) ** 2 * X - 256 * (T**2 - T + 1) ** 3 R = F.resultant(H, T) R = prod([fi for fi, e in R([J, 0]).factor()]) if R(0) == 0: @@ -2874,15 +2875,15 @@ def is_j_supersingular(j, proof=True): P = E.random_element() if n is None: # not yet decided between p+1 and p-1 - pP = p*P + pP = p * P if pP[0] != P[0]: # i.e. pP is neither P nor -P return False if pP[1] == P[1]: # then p*P == P != -P n = p - 1 - else: # then p*P == -P != P + else: # then p*P == -P != P n = p + 1 else: - if not (n*P).is_zero(): + if not (n * P).is_zero(): return False # when proof is False we return True for any curve which passes @@ -3078,6 +3079,7 @@ def special_supersingular_curve(F, q=None, *, endomorphism=False): if q is not None: from sage.arith.misc import hilbert_conductor + if p.divides(q) or hilbert_conductor(-q, -p) != p: raise ValueError('invalid choice of q') @@ -3093,7 +3095,8 @@ def special_supersingular_curve(F, q=None, *, endomorphism=False): q = 2 else: from sage.arith.misc import legendre_symbol - for q in map(ZZ, range(3,p,4)): + + for q in map(ZZ, range(3, p, 4)): if not q.is_prime(): continue if legendre_symbol(-q, p) == -1: @@ -3104,27 +3107,28 @@ def special_supersingular_curve(F, q=None, *, endomorphism=False): from sage.arith.misc import fundamental_discriminant from sage.schemes.elliptic_curves.cm import hilbert_class_polynomial + H = hilbert_class_polynomial(fundamental_discriminant(-q)) j = H.change_ring(GF(p)).any_root() if j.is_zero(): if p == 2: - ainvs = [0,0,1,0,0] + ainvs = [0, 0, 1, 0, 0] elif p == 3: - ainvs = [1,0] + ainvs = [1, 0] else: - ainvs = [0,1] + ainvs = [0, 1] elif j == 1728: - ainvs = [1,0] + ainvs = [1, 0] else: - a = 27 * j / (4 * (1728-j)) - ainvs = [a,-a] + a = 27 * j / (4 * (1728 - j)) + ainvs = [a, -a] E = EllipticCurve(F, ainvs) if ZZ(2).divides(deg): - k = deg//2 - E.set_order((p**k - (-1)**k)**2) + k = deg // 2 + E.set_order((p**k - (-1) ** k) ** 2) else: - E.set_order(p**deg - (-1)**deg) + E.set_order(p**deg - (-1) ** deg) if not endomorphism: return E @@ -3136,8 +3140,7 @@ def special_supersingular_curve(F, q=None, *, endomorphism=False): try: endo = iso * E.isogeny(None, iso.domain(), degree=q) except NotImplementedError: - endos = (iso*phi for phi in E.isogenies_degree(q) - for iso in phi.codomain().isomorphisms(E)) + endos = (iso * phi for phi in E.isogenies_degree(q) for iso in phi.codomain().isomorphisms(E)) endo = next(endo for endo in endos if endo.trace().is_zero()) endo._degree = ZZ(q) @@ -3493,19 +3496,14 @@ def EllipticCurve_with_prime_order(N): raise ValueError("input order is not a prime") if N == 2: - yield from [ - EllipticCurve(GF(2), [1, 0, 1, 0, 1]), - EllipticCurve(GF(3), [0, 2, 0, 0, 2]), - EllipticCurve(GF(5), [2, 0]) - ] + yield from [EllipticCurve(GF(2), [1, 0, 1, 0, 1]), EllipticCurve(GF(3), [0, 2, 0, 0, 2]), EllipticCurve(GF(5), [2, 0])] return # We start with small primes directly to accelerate the search. Note that # 1000 is a magic constant, it's just fast enough to compute without # sacrificing much speed. # The if-then-else term is (-1)^((p - 1) / 2) * p in [BS2007]_ page 5. - S = [(-p if p % 4 == 3 else p) for p in prime_range(3, min(1000, 4 * N)) - if legendre_symbol(N, p) == 1] + S = [(-p if p % 4 == 3 else p) for p in prime_range(3, min(1000, 4 * N)) if legendre_symbol(N, p) == 1] def abs_products_under(bound): """ @@ -3514,6 +3512,7 @@ def abs_products_under(bound): distinct elements in ``S`` in ascending order. """ import heapq + hq = [(1, 1, -1)] while hq: abs_n, n, idx = heapq.heappop(hq) @@ -3562,8 +3561,7 @@ def abs_products_under(bound): x, _ = sol for p_i in [N + 1 - x, N + 1 + x]: if is_prime(p_i): - verbose(f"Computing the Hilbert class polynomial H_{D}", - level=2) + verbose(f"Computing the Hilbert class polynomial H_{D}", level=2) H = hilbert_class_polynomial(D) K = GF(p_i) for j0 in H.roots(ring=K, multiplicities=False): diff --git a/src/sage/schemes/elliptic_curves/ell_generic.py b/src/sage/schemes/elliptic_curves/ell_generic.py index 943dd311a0c..e5589254169 100644 --- a/src/sage/schemes/elliptic_curves/ell_generic.py +++ b/src/sage/schemes/elliptic_curves/ell_generic.py @@ -103,6 +103,7 @@ class EllipticCurve_generic(WithEqualityById, plane_curve.ProjectivePlaneCurve): sage: -5*P (179051/80089 : -91814227/22665187 : 1) """ + def __init__(self, K, ainvs, category=None) -> None: r""" Construct an elliptic curve from Weierstrass `a`-coefficients. @@ -147,8 +148,7 @@ def __init__(self, K, ainvs, category=None) -> None: PP = projective_space.ProjectiveSpace(2, K, names='xyz') x, y, z = PP.coordinate_ring().gens() a1, a2, a3, a4, a6 = ainvs - f = y**2*z + (a1*x + a3*z)*y*z \ - - (x**3 + a2*x**2*z + a4*x*z**2 + a6*z**3) + f = y**2 * z + (a1 * x + a3 * z) * y * z - (x**3 + a2 * x**2 * z + a4 * x * z**2 + a6 * z**3) plane_curve.ProjectivePlaneCurve.__init__(self, PP, f, category=category) self.__divpolys = ({}, {}, {}) @@ -255,7 +255,7 @@ def _equation_string(self): s += " + 1" elif b[4]: s += " + %s" % a[4] - return s.replace("+ -","- ") + return s.replace("+ -", "- ") def _repr_(self): """ @@ -305,15 +305,16 @@ def _latex_(self): 'y^2 + \\phi y = x^{3} + \\left(27 \\phi - 43\\right) x - 80 \\phi + 128 ' """ from sage.rings.polynomial.polynomial_ring import polygen + a = self.ainvs() x, y = polygen(self.base_ring(), 'x, y') s = "y^2" if a[0] or a[2]: - s += " + " + (a[0]*x*y + a[2]*y)._latex_() + s += " + " + (a[0] * x * y + a[2] * y)._latex_() s += " = " - s += (x**3 + a[1]*x**2 + a[3]*x + a[4])._latex_() + s += (x**3 + a[1] * x**2 + a[3] * x + a[4])._latex_() s += " " - s = s.replace("+ -","- ") + s = s.replace("+ -", "- ") return s def _pari_init_(self): @@ -327,8 +328,7 @@ def _pari_init_(self): sage: E._pari_init_() 'ellinit([0/1,0/1,0/1,1/1,1/1])' """ - return 'ellinit([%s])' % (','.join(x._pari_init_() - for x in self.ainvs())) + return 'ellinit([%s])' % (','.join(x._pari_init_() for x in self.ainvs())) def _magma_init_(self, magma): """ @@ -355,8 +355,7 @@ def _magma_init_(self, magma): over Univariate rational function field over Rational Field """ kmn = magma(self.base_ring())._ref() - return 'EllipticCurve([%s|%s])' % (kmn,','.join(x._magma_init_(magma) - for x in self.ainvs())) + return 'EllipticCurve([%s|%s])' % (kmn, ','.join(x._magma_init_(magma) for x in self.ainvs())) def _symbolic_(self, SR): r""" @@ -442,7 +441,7 @@ def _symbolic_(self, SR): """ a = [SR(x) for x in self.a_invariants()] x, y = SR.var('x, y') - return y**2 + a[0]*x*y + a[2]*y == x**3 + a[1]*x**2 + a[3]*x + a[4] + return y**2 + a[0] * x * y + a[2] * y == x**3 + a[1] * x**2 + a[3] * x + a[4] def __contains__(self, P) -> bool: """ @@ -582,9 +581,9 @@ def __call__(self, *args, **kwds): """ if len(args) == 1 and args[0] == 0: R = self.base_ring() - return self.point([R(0),R(1),R(0)], check=False) + return self.point([R(0), R(1), R(0)], check=False) P = args[0] - if isinstance(P, groups.AdditiveAbelianGroupElement) and isinstance(P.parent(),ell_torsion.EllipticCurveTorsionSubgroup): + if isinstance(P, groups.AdditiveAbelianGroupElement) and isinstance(P.parent(), ell_torsion.EllipticCurveTorsionSubgroup): return self(P.element()) if isinstance(args[0], ell_point.EllipticCurvePoint): if P.curve() is self: @@ -651,7 +650,7 @@ def _reduce_point(self, R, p): return R.curve().change_ring(GF(p))(0) x, y = R.xy() d = lcm(x.denominator(), y.denominator()) - return R.curve().change_ring(GF(p))([x*d, y*d, d]) + return R.curve().change_ring(GF(p))([x * d, y * d, d]) def is_x_coord(self, x): r""" @@ -716,12 +715,12 @@ def is_x_coord(self, x): fx = ((x + a2) * x + a4) * x + a6 if a1.is_zero() and a3.is_zero(): return fx.is_square() - b = (a1*x + a3) + b = a1 * x + a3 if K.characteristic() == 2: R = PolynomialRing(K, 'y') - F = R([-fx,b,1]) + F = R([-fx, b, 1]) return bool(F.roots()) - D = b*b + 4*fx + D = b * b + 4 * fx return D.is_square() def lift_x(self, x, all=False, extend=False): @@ -925,25 +924,25 @@ def lift_x(self, x, all=False, extend=False): L = E.base_ring() x = L(x) else: - raise TypeError("Unable to construct a point with x in {} over {}".format(L,K)) + raise TypeError("Unable to construct a point with x in {} over {}".format(L, K)) # Now E is defined over L, possibly an extension of K, and x is in L a1, a2, a3, a4, a6 = E.ainvs() - b = (a1*x + a3) + b = a1 * x + a3 f = ((x + a2) * x + a4) * x + a6 # If possible find the associated y coordinates in L: if K.characteristic() == 2: R = PolynomialRing(L, 'y') - F = R([-f,b,1]) + F = R([-f, b, 1]) ys = F.roots(L, multiplicities=False) else: - D = b*b+4*f + D = b * b + 4 * f ys = [] if D.is_square(): # avoid automatic creation of sqrts - ys = [(-b+d)/2 for d in D.sqrt(all=True)] + ys = [(-b + d) / 2 for d in D.sqrt(all=True)] ys.sort() # ensure deterministic behavior @@ -966,11 +965,11 @@ def lift_x(self, x, all=False, extend=False): if K.characteristic() != 2: # else we already defined F R = PolynomialRing(L, 'y') - F = R([-f,b,1]) + F = R([-f, b, 1]) M = L.fraction_field().extension(F, names='y') EM = E.change_ring(M) y1 = M.gen() - y2 = -b-y1 + y2 = -b - y1 if y2 == y1: ys = [y1] else: @@ -1058,7 +1057,7 @@ def is_on_curve(self, x, y) -> bool: False """ a = self.ainvs() - return y**2 + a[0]*x*y + a[2]*y == x**3 + a[1]*x**2 + a[3]*x + a[4] + return y**2 + a[0] * x * y + a[2] * y == x**3 + a[1] * x**2 + a[3] * x + a[4] def is_exact(self): """ @@ -1210,10 +1209,7 @@ def b_invariants(self): - William Stein (2005-04-25) """ a1, a2, a3, a4, a6 = self.ainvs() - return (a1*a1 + 4*a2, - a1*a3 + 2*a4, - a3**2 + 4*a6, - a1**2 * a6 + 4*a2*a6 - a1*a3*a4 + a2*a3**2 - a4**2) + return (a1 * a1 + 4 * a2, a1 * a3 + 2 * a4, a3**2 + 4 * a6, a1**2 * a6 + 4 * a2 * a6 - a1 * a3 * a4 + a2 * a3**2 - a4**2) def b2(self): r""" @@ -1294,8 +1290,7 @@ def c_invariants(self): """ b2, b4, b6, b8 = self.b_invariants() # note: c6 is wrong in Silverman, but right in Cremona - return (b2**2 - 24*b4, - -b2**3 + 36*b2*b4 - 216*b6) + return (b2**2 - 24 * b4, -(b2**3) + 36 * b2 * b4 - 216 * b6) def c4(self): r""" @@ -1343,7 +1338,7 @@ def discriminant(self): 1 """ b2, b4, b6, b8 = self.b_invariants() - return -b2**2*b8 - 8*b4**3 - 27*b6**2 + 9*b2*b4*b6 + return -(b2**2) * b8 - 8 * b4**3 - 27 * b6**2 + 9 * b2 * b4 * b6 @cached_method def j_invariant(self): @@ -1578,8 +1573,8 @@ def scale_curve(self, u): over Fraction Field of Univariate Polynomial Ring in u over Rational Field """ if isinstance(u, int): - u = self.base_ring()(u) # because otherwise 1/u would round! - return self.change_weierstrass_model(1/u, 0, 0, 0) + u = self.base_ring()(u) # because otherwise 1/u would round! + return self.change_weierstrass_model(1 / u, 0, 0, 0) def isomorphism(self, u, r=0, s=0, t=0, *, is_codomain=False): r""" @@ -1665,48 +1660,49 @@ def isomorphism(self, u, r=0, s=0, t=0, *, is_codomain=False): - :meth:`scale_curve` """ from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism - if is_codomain: - return WeierstrassIsomorphism(None, (u,r,s,t), self) - return WeierstrassIsomorphism(self, (u,r,s,t)) -# ########################################################### -# -# Explanation of the division (also known as torsion) polynomial -# functions in Sage. -# -# The main user function division_polynomial() (also aliased as -# torsion_polynomial()) is used to compute polynomials whose roots -# determine the m-torsion points on the curve. Three options are -# available, which effect the result when m is even and also the -# parent ring of the returned value. The function can return either a -# polynomial or the evaluation of that polynomial at a point, -# depending on the input. Values are cached. -# -# The options are controlled by the value of the parameter -# two_torsion_multiplicity, which may be 0, 1 or 2. If it is 0 or 2, -# then a univariate polynomial will be returned (or evaluated at the -# parameter x if x is not None). This is the polynomial whose roots -# are the values of x(P) at the nonzero points P where m*P=0 -# (when two_torsion_multiplicity==2), or the points where m*P=0 but -# 2*P\not=0 (when two_torsion_multiplicity==0). -# -# If two_torsion_multiplicity==1, then a bivariate polynomial is -# returned, which (as a function on the curve) has a simple zero at -# each nonzero point P such that m*P=0. When m is odd this is a -# polynomial in x alone, but is still returned as an element of a -# polynomial ring in two variables; when m is even it has a factor -# 2y+a_1x+a_3. In this case if the parameter x is not None then it -# should be a tuple of length 2, or a point P on the curve, and the -# returned value is the value of the bivariate polynomial at this -# point. -# -# Comparison with Magma: Magma's function DivisionPolynomial(E,m) -# returns a triple of univariate polynomials f,g,h where f is -# \code{E.division_polynomial(m,two_torsion_multiplicity=2)}, g is -# \code{E.division_polynomial(m,two_torsion_multiplicity=0)} and h -# is the quotient, so that h=1 when m is odd. - -# ########################################################### + if is_codomain: + return WeierstrassIsomorphism(None, (u, r, s, t), self) + return WeierstrassIsomorphism(self, (u, r, s, t)) + + # ########################################################### + # + # Explanation of the division (also known as torsion) polynomial + # functions in Sage. + # + # The main user function division_polynomial() (also aliased as + # torsion_polynomial()) is used to compute polynomials whose roots + # determine the m-torsion points on the curve. Three options are + # available, which effect the result when m is even and also the + # parent ring of the returned value. The function can return either a + # polynomial or the evaluation of that polynomial at a point, + # depending on the input. Values are cached. + # + # The options are controlled by the value of the parameter + # two_torsion_multiplicity, which may be 0, 1 or 2. If it is 0 or 2, + # then a univariate polynomial will be returned (or evaluated at the + # parameter x if x is not None). This is the polynomial whose roots + # are the values of x(P) at the nonzero points P where m*P=0 + # (when two_torsion_multiplicity==2), or the points where m*P=0 but + # 2*P\not=0 (when two_torsion_multiplicity==0). + # + # If two_torsion_multiplicity==1, then a bivariate polynomial is + # returned, which (as a function on the curve) has a simple zero at + # each nonzero point P such that m*P=0. When m is odd this is a + # polynomial in x alone, but is still returned as an element of a + # polynomial ring in two variables; when m is even it has a factor + # 2y+a_1x+a_3. In this case if the parameter x is not None then it + # should be a tuple of length 2, or a point P on the curve, and the + # returned value is the value of the bivariate polynomial at this + # point. + # + # Comparison with Magma: Magma's function DivisionPolynomial(E,m) + # returns a triple of univariate polynomials f,g,h where f is + # \code{E.division_polynomial(m,two_torsion_multiplicity=2)}, g is + # \code{E.division_polynomial(m,two_torsion_multiplicity=0)} and h + # is the quotient, so that h=1 when m is odd. + + # ########################################################### def division_polynomial_0(self, n, x=None): r""" @@ -1856,26 +1852,26 @@ def poly(n): except KeyError: pass if n == -2: - ret = poly(-1)**2 + ret = poly(-1) ** 2 elif n == -1: - ret = 4*x**3 + b2*x**2 + 2*b4*x + b6 + ret = 4 * x**3 + b2 * x**2 + 2 * b4 * x + b6 elif n <= 0: raise ValueError("n must be a positive integer (or -1 or -2)") elif n == 1 or n == 2: ret = x.parent().one() elif n == 3: - ret = 3*x**4 + b2*x**3 + 3*b4*x**2 + 3*b6*x + b8 + ret = 3 * x**4 + b2 * x**3 + 3 * b4 * x**2 + 3 * b6 * x + b8 elif n == 4: - ret = -poly(-2) + (6*x**2 + b2*x + b4) * poly(3) + ret = -poly(-2) + (6 * x**2 + b2 * x + b4) * poly(3) elif n % 2 == 0: - m = (n-2) // 2 - ret = poly(m+1) * (poly(m+3) * poly(m)**2 - poly(m-1) * poly(m+2)**2) + m = (n - 2) // 2 + ret = poly(m + 1) * (poly(m + 3) * poly(m) ** 2 - poly(m - 1) * poly(m + 2) ** 2) else: - m = (n-1) // 2 + m = (n - 1) // 2 if m % 2 == 0: - ret = poly(-2) * poly(m+2) * poly(m)**3 - poly(m-1) * poly(m+1)**3 + ret = poly(-2) * poly(m + 2) * poly(m) ** 3 - poly(m - 1) * poly(m + 1) ** 3 else: - ret = poly(m+2) * poly(m)**3 - poly(-2) * poly(m-1) * poly(m+1)**3 + ret = poly(m + 2) * poly(m) ** 3 - poly(-2) * poly(m - 1) * poly(m + 1) ** 3 cache[n] = ret return ret @@ -1909,7 +1905,7 @@ def two_division_polynomial(self, x=None): sage: E.two_division_polynomial().roots() # needs sage.rings.finite_rings [(2, 1), (2*a, 1), (a + 2, 1)] """ - return self.division_polynomial_0(-1,x) + return self.division_polynomial_0(-1, x) def division_polynomial(self, m, x=None, two_torsion_multiplicity=2, force_evaluate=None): r""" @@ -2085,13 +2081,9 @@ def division_polynomial(self, m, x=None, two_torsion_multiplicity=2, force_evalu # January 2022 (using Sage version 9.5.rc0). elif x in self.base_ring(): evaluate = m < 100 - elif isinstance(x, PolynomialQuotientRingElement) and x.lift().is_gen() \ - and x.lift().base_ring() is self.base_ring(): + elif isinstance(x, PolynomialQuotientRingElement) and x.lift().is_gen() and x.lift().base_ring() is self.base_ring(): d = x.parent().modulus().degree() - evaluate = m < 220 or \ - (d < 10 and m < 420) or (d < 15 and m < 340) or \ - (d < 30 and m < 280) or (d < 100 and m < 250) or \ - m <= min(250, d) + evaluate = m < 220 or (d < 10 and m < 420) or (d < 15 and m < 340) or (d < 30 and m < 280) or (d < 100 and m < 250) or m <= min(250, d) # Check if we should (attempt to) compute the result by simply # evaluating a cached polynomial at the given input. @@ -2109,7 +2101,7 @@ def division_polynomial(self, m, x=None, two_torsion_multiplicity=2, force_evalu should_cache = x is None if two_torsion_multiplicity == 1: - x,y = x if x is not None else (None,None) + x, y = x if x is not None else (None, None) if evaluate and m in self.__divpolys[0]: f = self.__divpolys[0][m](x) @@ -2121,10 +2113,10 @@ def division_polynomial(self, m, x=None, two_torsion_multiplicity=2, force_evalu f *= self.division_polynomial_0(-1, x) elif two_torsion_multiplicity == 1: if x is y is None: - x,y = polygens(self.base_ring(), 'x,y') + x, y = polygens(self.base_ring(), 'x,y') f = f(x) if m % 2 == 0: - f *= 2*y + self.a1()*x + self.a3() + f *= 2 * y + self.a1() * x + self.a3() if should_cache: self.__divpolys[two_torsion_multiplicity][m] = f @@ -2245,12 +2237,12 @@ def _multiple_x_numerator(self, n, x=None): if n == 1: return xx - polys = self.division_polynomial_0([-2,-1,n-1,n,n+1], x) + polys = self.division_polynomial_0([-2, -1, n - 1, n, n + 1], x) if n % 2 == 0: - ret = xx * polys[1] * polys[3]**2 - polys[2] * polys[4] + ret = xx * polys[1] * polys[3] ** 2 - polys[2] * polys[4] else: - ret = xx * polys[3]**2 - polys[1] * polys[2] * polys[4] + ret = xx * polys[3] ** 2 - polys[1] * polys[2] * polys[4] if cache is not None: cache[n] = ret @@ -2337,7 +2329,7 @@ def _multiple_x_denominator(self, n, x=None): else: cache = None - ret = self.division_polynomial_0(n, x)**2 + ret = self.division_polynomial_0(n, x) ** 2 if n % 2 == 0: ret *= self.division_polynomial_0(-1, x) @@ -2502,10 +2494,10 @@ def multiplication_by_m(self, m, x_only=False): x = polygen(self.base_ring(), 'x') else: from sage.rings.finite_rings.finite_field_base import FiniteField as FiniteField_generic + if p != 0 and m % p == 0 and not isinstance(self.base_ring(), FiniteField_generic): # TODO: Implement the correct formula? - raise NotImplementedError("multiplication by integer not coprime to p " - "is only implemented for curves over finite fields") + raise NotImplementedError("multiplication by integer not coprime to p " "is only implemented for curves over finite fields") x, y = polygens(self.base_ring(), 'x,y') # Special case of multiplication by 1 is easy. @@ -2519,7 +2511,7 @@ def multiplication_by_m(self, m, x_only=False): if m == -1: if not x_only: - return (x, -y-a1*x-a3) + return (x, -y - a1 * x - a3) return x # If we only require the x coordinate, it is faster to use the recursive formula @@ -2531,8 +2523,7 @@ def multiplication_by_m(self, m, x_only=False): # the x-coordinate does not depend on the sign of m. The work # here is done by functions defined earlier: - mx = (x.parent()(self._multiple_x_numerator(m.abs(), x)) - / x.parent()(self._multiple_x_denominator(m.abs(), x))) + mx = x.parent()(self._multiple_x_numerator(m.abs(), x)) / x.parent()(self._multiple_x_denominator(m.abs(), x)) if x_only: return mx @@ -2540,10 +2531,10 @@ def multiplication_by_m(self, m, x_only=False): # Consideration of the invariant differential # w=dx/(2*y+a1*x+a3) shows that m*w = d(mx)/(2*my+a1*mx+a3) # and hence 2*my+a1*mx+a3 = (1/m)*(2*y+a1*x+a3)*d(mx)/dx - my = ((2*y+a1*x+a3)*mx.derivative(x)/m - a1*mx-a3)/2 + my = ((2 * y + a1 * x + a3) * mx.derivative(x) / m - a1 * mx - a3) / 2 if v_p > 0: - isog = self.multiplication_by_p_isogeny()**v_p + isog = self.multiplication_by_p_isogeny() ** v_p fx, fy = isog.rational_maps() # slow... mx = mx.subs(x=fx) @@ -2605,6 +2596,7 @@ def scalar_multiplication(self, m): (-4*x^7 + 8*x^6*y - 28*x^6 - 12*x^5*y - 420*x^5 - 660*x^4*y + 5020*x^4 + 4840*x^3*y - 7568*x^3 - 14520*x^2*y - 42108*x^2 + 20328*x*y + 143264*x - 10648*y - 122452)/(64*x^6 - 96*x^5 - 2076*x^4 + 5456*x^3 + 14520*x^2 - 63888*x + 58564)) """ from sage.schemes.elliptic_curves.hom_scalar import EllipticCurveHom_scalar + return EllipticCurveHom_scalar(self, m) def frobenius_isogeny(self, n=1): @@ -2641,6 +2633,7 @@ def frobenius_isogeny(self, n=1): if not p: raise ValueError('Frobenius isogeny only exists in positive characteristic') from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius + return EllipticCurveHom_frobenius(self, n) def identity_morphism(self): @@ -2658,6 +2651,7 @@ def identity_morphism(self): True """ from sage.schemes.elliptic_curves.weierstrass_morphism import identity_morphism + return identity_morphism(self) def isomorphism_to(self, other): @@ -2850,8 +2844,7 @@ def isomorphisms(self, other, field=None): if field is not None: self = self.change_ring(field) other = other.change_ring(field) - return sorted(wm.WeierstrassIsomorphism(self, urst, other) - for urst in wm._isomorphisms(self, other)) + return sorted(wm.WeierstrassIsomorphism(self, urst, other) for urst in wm._isomorphisms(self, other)) def is_isomorphic(self, other, field=None): """ @@ -2985,6 +2978,7 @@ def short_weierstrass_model(self, complete_cube=True): True """ from . import constructor + K = self.base_ring() # any curve of the form y^2 = x^3 +.. is singular in characteristic 2 @@ -2993,25 +2987,25 @@ def short_weierstrass_model(self, complete_cube=True): # in characteristic 3 we can complete the square but we can only complete the cube if b2 is 0 if K.characteristic() == 3: - b2, b4, b6,_ = self.b_invariants() + b2, b4, b6, _ = self.b_invariants() if complete_cube and b2 != 0: - raise ValueError("short_weierstrass_model(): no short model for %s (characteristic is %s)" % (self,K.characteristic())) + raise ValueError("short_weierstrass_model(): no short model for %s (characteristic is %s)" % (self, K.characteristic())) else: - return constructor.EllipticCurve([0,b2,0,8*b4,16*b6]) + return constructor.EllipticCurve([0, b2, 0, 8 * b4, 16 * b6]) - a1,a2,a3,_,_ = self.a_invariants() + a1, a2, a3, _, _ = self.a_invariants() if complete_cube: if a1 == 0 and a2 == 0 and a3 == 0: return self b2, b4, b6, _ = self.b_invariants() if b2 == 0: - return constructor.EllipticCurve([0,0,0,8*b4,16*b6]) + return constructor.EllipticCurve([0, 0, 0, 8 * b4, 16 * b6]) c4, c6 = self.c_invariants() - return constructor.EllipticCurve([0,0,0,-27*c4, -54*c6]) + return constructor.EllipticCurve([0, 0, 0, -27 * c4, -54 * c6]) if a1 == 0 and a3 == 0: return self b2, b4, b6, _ = self.b_invariants() - return constructor.EllipticCurve([0,b2,0,8*b4,16*b6]) + return constructor.EllipticCurve([0, b2, 0, 8 * b4, 16 * b6]) def montgomery_model(self, twisted=False, morphism=False): r""" @@ -3184,9 +3178,7 @@ def montgomery_model(self, twisted=False, morphism=False): R = self.base_ring() P = PolynomialRing(R, 'v') - sols = [(r, s) - for r in P([b, a, 0, 1]).roots(multiplicities=False) - for s in P([3 * r**2 + a, 0, -1]).roots(multiplicities=False)] + sols = [(r, s) for r in P([b, a, 0, 1]).roots(multiplicities=False) for s in P([3 * r**2 + a, 0, -1]).roots(multiplicities=False)] if not sols: raise ValueError(f'{self} has no Montgomery model') @@ -3201,13 +3193,14 @@ def montgomery_model(self, twisted=False, morphism=False): if B != 1: raise ValueError(f'{self} has no untwisted Montgomery model') from sage.schemes.elliptic_curves.constructor import EllipticCurve + E = EllipticCurve([0, A, 0, 1, 0]) if morphism: return E, self.isomorphism_to(E) return E P2, (x, y, z) = self.ambient_space().objgens() - f = B * y**2*z - x * (x * (x + A*z) + z**2) + f = B * y**2 * z - x * (x * (x + A * z) + z**2) C = plane_curve.ProjectivePlaneCurve(P2, f) if not morphism: @@ -3224,8 +3217,8 @@ def montgomery_model(self, twisted=False, morphism=False): iso = [f(*wmap) for f in iso_maps] inv = [f(*inv_maps) for f in winv] - from sage.schemes.elliptic_curves.weierstrass_transform \ - import WeierstrassTransformationWithInverse as WTI + from sage.schemes.elliptic_curves.weierstrass_transform import WeierstrassTransformationWithInverse as WTI + iso = WTI(self, C, iso, 1, inv, s**-3) return C, iso @@ -3319,11 +3312,11 @@ def plot(self, xmin=None, xmax=None, components='both', **args): def f1(z): # Internal function for plotting first branch of the curve - return (-(a1*z + a3) + sqrt(abs(d(z))))/2 + return (-(a1 * z + a3) + sqrt(abs(d(z)))) / 2 def f2(z): # Internal function for plotting second branch of the curve - return (-(a1*z + a3) - sqrt(abs(d(z))))/2 + return (-(a1 * z + a3) - sqrt(abs(d(z)))) / 2 r = sorted(d.roots(RR, multiplicities=False)) if components == 'bounded' and len(r) == 1: @@ -3337,7 +3330,7 @@ def f2(z): if xmin is None or xmax is None: xmins = [] xmaxs = [] - if components in ['both','bounded'] and len(r) > 1: + if components in ['both', 'bounded'] and len(r) > 1: xmins.append(r[0]) xmaxs.append(r[1]) @@ -3345,12 +3338,12 @@ def f2(z): # that we should compute both of the following when # components=='both' and len(r) > 1 and take the maximum # generated xmax. - if components == 'unbounded' or components == 'both' and (len(r) == 1 or r[2] - r[1] > 3*(r[1] - r[0])): + if components == 'unbounded' or components == 'both' and (len(r) == 1 or r[2] - r[1] > 3 * (r[1] - r[0])): flex = sorted(self.division_polynomial(3).roots(RR, multiplicities=False)) flex = flex[-1] xmins.append(r[-1]) # The doubling here is an aesthetic choice - xmaxs.append(flex + 2*(flex - r[-1])) + xmaxs.append(flex + 2 * (flex - r[-1])) elif components == 'both': # First the easy part. xmins.append(r[-1]) @@ -3367,28 +3360,27 @@ def f2(z): x = R.gen() if a1 == 0: # a horizontal tangent line can only occur at a root of - Ederiv = 3*x**2 + 2*a2*x + a4 + Ederiv = 3 * x**2 + 2 * a2 * x + a4 else: # y' = 0 ==> y = (3*x^2 + 2*a2*x + a4) / a1 - y = (3*x**2 + 2*a2*x + a4) / a1 - Ederiv = y**2 + a1*x*y + a3*y - (x**3 + a2*x**2 + a4*x + a6) - critx = [a for a in Ederiv.roots(RR, multiplicities=False) - if r[0] < a < r[1]] + y = (3 * x**2 + 2 * a2 * x + a4) / a1 + Ederiv = y**2 + a1 * x * y + a3 * y - (x**3 + a2 * x**2 + a4 * x + a6) + critx = [a for a in Ederiv.roots(RR, multiplicities=False) if r[0] < a < r[1]] if not critx: raise RuntimeError("No horizontal tangent lines on bounded component") # The 2.5 here is an aesthetic choice ymax = 2.5 * max([f1(a) for a in critx]) ymin = 2.5 * min([f2(a) for a in critx]) - top_branch = ymax**2 + a1*x*ymax + a3*ymax - (x**3 + a2*x**2 + a4*x + a6) - bottom_branch = ymin**2 + a1*x*ymin + a3*ymin - (x**3 + a2*x**2 + a4*x + a6) - xmaxs.append(max(top_branch.roots(RR,multiplicities=False) + bottom_branch.roots(RR,multiplicities=False))) + top_branch = ymax**2 + a1 * x * ymax + a3 * ymax - (x**3 + a2 * x**2 + a4 * x + a6) + bottom_branch = ymin**2 + a1 * x * ymin + a3 * ymin - (x**3 + a2 * x**2 + a4 * x + a6) + xmaxs.append(max(top_branch.roots(RR, multiplicities=False) + bottom_branch.roots(RR, multiplicities=False))) xmins = min(xmins) xmaxs = max(xmaxs) span = xmaxs - xmins if xmin is None: - xmin = xmins - .02*span + xmin = xmins - 0.02 * span if xmax is None: - xmax = xmaxs + .02*span + xmax = xmaxs + 0.02 * span elif xmin >= xmax: raise ValueError("xmin must be less than xmax") @@ -3396,15 +3388,15 @@ def f2(z): if components in ['unbounded', 'both'] and xmax > r[-1]: # one real root; 1 component if xmin <= r[-1]: - I.append((r[-1],xmax,'<')) + I.append((r[-1], xmax, '<')) else: - I.append((xmin, xmax,'=')) - if components in ['bounded','both'] and len(r) > 1 and (xmin < r[1] or xmax > r[0]): + I.append((xmin, xmax, '=')) + if components in ['bounded', 'both'] and len(r) > 1 and (xmin < r[1] or xmax > r[0]): if xmin <= r[0]: if xmax >= r[1]: - I.append((r[0],r[1],'o')) + I.append((r[0], r[1], 'o')) else: - I.append((r[0],xmax,'<')) + I.append((r[0], xmax, '<')) elif xmax >= r[1]: I.append((xmin, r[1], '>')) else: @@ -3415,10 +3407,10 @@ def f2(z): from sage.plot.plot import generate_plot_points g = Graphics() - plot_points = int(args.pop('plot_points',200)) - adaptive_tolerance = args.pop('adaptive_tolerance',0.01) - adaptive_recursion = args.pop('adaptive_recursion',5) - randomize = args.pop('randomize',True) + plot_points = int(args.pop('plot_points', 200)) + adaptive_tolerance = args.pop('adaptive_tolerance', 0.01) + adaptive_recursion = args.pop('adaptive_recursion', 5) + randomize = args.pop('randomize', True) for j in range(len(I)): a, b, shape = I[j] v = generate_plot_points(f1, (a, b), plot_points, adaptive_tolerance, adaptive_recursion, randomize) @@ -3519,6 +3511,7 @@ def _p_primary_torsion_basis(self, p, m=None): if m is None: from sage.rings.infinity import Infinity + m = Infinity if m == 0: @@ -3591,7 +3584,7 @@ def _p_primary_torsion_basis(self, p, m=None): P1, P2 = P2, P1 pts = pts2 else: - for Q in generic.multiples(P2, p-1, P1 + P2, operation='+'): + for Q in generic.multiples(P2, p - 1, P1 + P2, operation='+'): # Q runs through P1+a*P2 for a=1,2,...,p-1 pts = Q.division_points(p) if pts: @@ -3622,7 +3615,7 @@ def _p_primary_torsion_basis(self, p, m=None): return [[P1, n], [P2, k]] pts = P1.division_points(p) if not pts: - for Q in generic.multiples(P2, p-1, P1+P2, operation='+'): + for Q in generic.multiples(P2, p - 1, P1 + P2, operation='+'): # Q runs through P1+a*P2 for a=1,2,...,p-1 pts = Q.division_points(p) if pts: @@ -3720,6 +3713,7 @@ def pari_curve(self): """ from sage.categories.number_fields import NumberFields from sage.libs.pari import pari + if self.base_ring() in NumberFields(): return pari.ellinit(self.a_invariants(), self.base_ring()) return pari.ellinit(self.a_invariants()) diff --git a/src/sage/schemes/elliptic_curves/ell_local_data.py b/src/sage/schemes/elliptic_curves/ell_local_data.py index 25c1ec68972..afb65270541 100644 --- a/src/sage/schemes/elliptic_curves/ell_local_data.py +++ b/src/sage/schemes/elliptic_curves/ell_local_data.py @@ -77,6 +77,7 @@ - Chris Wuthrich: more documentation 2010-01 """ + # **************************************************************************** # Copyright (C) 2005 William Stein # @@ -258,7 +259,7 @@ def __init__(self, E, P, proof=None, algorithm='pari', globally=False): """ self._curve = E K = E.base_field() - p = check_prime(K,P) # error handling done in that function + p = check_prime(K, P) # error handling done in that function if algorithm != "pari" and algorithm != "generic": raise ValueError("algorithm must be one of 'pari', 'generic'") @@ -278,7 +279,7 @@ def __init__(self, E, P, proof=None, algorithm='pari', globally=False): self._Emin_reduced = Eint.minimal_model() self._val_disc = self._Emin_reduced.discriminant().valuation(p) if self._fp > 0: - self._reduction_type = Eint.ap(p) # = 0,-1 or +1 + self._reduction_type = Eint.ap(p) # = 0,-1 or +1 else: self._Emin, _, self._val_disc, self._fp, self._KS, self._cp, self._split = self._tate(proof, globally) if self._fp > 0: @@ -306,8 +307,8 @@ def __repr__(self): """ red_type = "good" if self._reduction_type is not None: - red_type = ["bad non-split multiplicative","bad additive","bad split multiplicative"][1+self._reduction_type] - return "Local data at %s:\nReduction type: %s\nLocal minimal model: %s\nMinimal discriminant valuation: %s\nConductor exponent: %s\nKodaira Symbol: %s\nTamagawa Number: %s" % (self._prime,red_type,self.minimal_model(),self._val_disc,self._fp,self._KS,self._cp) + red_type = ["bad non-split multiplicative", "bad additive", "bad split multiplicative"][1 + self._reduction_type] + return "Local data at %s:\nReduction type: %s\nLocal minimal model: %s\nMinimal discriminant valuation: %s\nConductor exponent: %s\nKodaira Symbol: %s\nTamagawa Number: %s" % (self._prime, red_type, self.minimal_model(), self._val_disc, self._fp, self._KS, self._cp) def minimal_model(self, reduce=True): """ @@ -790,15 +791,16 @@ def _tate(self, proof=None, globally=False): # case (Simon King, github issue #8800). from sage.categories.pushout import pushout, CoercionException + try: - if hasattr(F.p.ring(), 'maximal_order'): # it is not ZZ + if hasattr(F.p.ring(), 'maximal_order'): # it is not ZZ pushout(F.p.ring().maximal_order(), K) pinv = lambda x: F.lift(~F(x)) - proot = lambda x,e: F.lift(F(x).nth_root(e, extend=False, all=True)[0]) + proot = lambda x, e: F.lift(F(x).nth_root(e, extend=False, all=True)[0]) preduce = lambda x: F.lift(F(x)) - except CoercionException: # the pushout does not exist, we need conversion + except CoercionException: # the pushout does not exist, we need conversion pinv = lambda x: K(F.lift(~F(x))) - proot = lambda x,e: K(F.lift(F(x).nth_root(e, extend=False, all=True)[0])) + proot = lambda x, e: K(F.lift(F(x).nth_root(e, extend=False, all=True)[0])) preduce = lambda x: K(F.lift(F(x))) def _pquadroots(a, b, c): @@ -810,8 +812,8 @@ def _pquadroots(a, b, c): if a == 0: return (b != 0) or (c == 0) if p == 2: - return len(PolynomialRing(F, "x")([c,b,a]).roots()) > 0 - return (b**2 - 4*a*c).is_square() + return len(PolynomialRing(F, "x")([c, b, a]).roots()) > 0 + return (b**2 - 4 * a * c).is_square() def _pcubicroots(b, c, d): r""" @@ -819,7 +821,7 @@ def _pcubicroots(b, c, d): b*x^2 + c*x + d` modulo `P`, counting multiplicities """ - return sum([rr[1] for rr in PolynomialRing(F, 'x')([F(d), F(c), F(b), F(1)]).roots()],0) + return sum([rr[1] for rr in PolynomialRing(F, 'x')([F(d), F(c), F(b), F(1)]).roots()], 0) if p == 2: halfmodp = OK(Integer(0)) @@ -828,20 +830,20 @@ def _pcubicroots(b, c, d): A = E.a_invariants() A = [0, A[0], A[1], A[2], A[3], 0, A[4]] - indices = [1,2,3,4,6] + indices = [1, 2, 3, 4, 6] if min([pval(a) for a in A if a != 0]) < 0: verbose("Non-integral model at P: valuations are %s; making integral" % ([pval(a) for a in A if a != 0]), t, 1) e = 0 for i in range(7): if A[i] != 0: - e = max(e, (-pval(A[i])/i).ceil()) + e = max(e, (-pval(A[i]) / i).ceil()) pie = pi**e for i in range(7): if A[i] != 0: A[i] *= pie**i verbose("P-integral model is %s, with valuations %s" % ([A[i] for i in indices], [pval(A[i]) for i in indices]), t, 1) - split = None # only relevant for multiplicative reduction + split = None # only relevant for multiplicative reduction (a1, a2, a3, a4, a6) = (A[1], A[2], A[3], A[4], A[6]) while True: @@ -856,17 +858,17 @@ def _pcubicroots(b, c, d): cp = 1 fp = 0 KS = KodairaSymbol("I0") - break #return + break # return # Otherwise, we change coordinates so that p | a3, a4, a6 if p == 2: if pdiv(b2): r = proot(a4, 2) - t = proot(((r + a2)*r + a4)*r + a6, 2) + t = proot(((r + a2) * r + a4) * r + a6, 2) else: temp = pinv(a1) r = temp * a3 - t = temp * (a4 + r*r) + t = temp * (a4 + r * r) elif p == 3: if pdiv(b2): r = proot(-b6, 3) @@ -877,7 +879,7 @@ def _pcubicroots(b, c, d): if pdiv(c4): r = -pinv(12) * b2 else: - r = -pinv(12*c4) * (c6 + b2 * c4) + r = -pinv(12 * c4) * (c6 + b2 * c4) t = -halfmodp * (a1 * r + a3) r = preduce(r) t = preduce(t) @@ -911,7 +913,7 @@ def _pcubicroots(b, c, d): cp = 1 KS = KodairaSymbol("I%s" % val_disc) fp = 1 - break #return + break # return # Additive reduction @@ -920,39 +922,39 @@ def _pcubicroots(b, c, d): KS = KodairaSymbol("II") fp = val_disc cp = 1 - break #return + break # return if pval(b8) < 3: ## Type III KS = KodairaSymbol("III") fp = val_disc - 1 cp = 2 - break #return + break # return if pval(b6) < 3: ## Type IV cp = 1 - a3t = preduce(a3/pi) - a6t = preduce(a6/pi2) + a3t = preduce(a3 / pi) + a6t = preduce(a6 / pi2) if _pquadroots(1, a3t, -a6t): cp = 3 KS = KodairaSymbol("IV") fp = val_disc - 2 - break #return + break # return # If our curve is none of these types, we change coords so that # p | a1, a2; p^2 | a3, a4; p^3 | a6 if p == 2: - s = proot(a2, 2) # so s^2=a2 (mod pi) - t = pi*proot(a6/pi2, 2) # so t^2=a6 (mod pi^3) + s = proot(a2, 2) # so s^2=a2 (mod pi) + t = pi * proot(a6 / pi2, 2) # so t^2=a6 (mod pi^3) elif p == 3: - s = a1 # so a1'=2s+a1=3a1=0 (mod pi) - t = a3 # so a3'=2t+a3=3a3=0 (mod pi^2) + s = a1 # so a1'=2s+a1=3a1=0 (mod pi) + t = a3 # so a3'=2t+a3=3a3=0 (mod pi^2) else: - s = -a1*halfmodp # so a1'=2s+a1=0 (mod pi) - t = -a3*halfmodp # so a3'=2t+a3=0 (mod pi^2) + s = -a1 * halfmodp # so a1'=2s+a1=0 (mod pi) + t = -a3 * halfmodp # so a3'=2t+a3=0 (mod pi^2) C = C.rst_transform(0, s, t) (a1, a2, a3, a4, a6) = C.a_invariants() - verbose("After second transform %s\n[a1, a2, a3, a4, a6] = %s\nValuations: %s" % ([0, s, t], [a1,a2,a3,a4,a6],[pval(a1),pval(a2),pval(a3),pval(a4),pval(a6)]), t, 2) + verbose("After second transform %s\n[a1, a2, a3, a4, a6] = %s\nValuations: %s" % ([0, s, t], [a1, a2, a3, a4, a6], [pval(a1), pval(a2), pval(a3), pval(a4), pval(a6)]), t, 2) if pval(a1) == 0: raise RuntimeError("p does not divide a1 after second transform!") if pval(a2) == 0: @@ -968,14 +970,14 @@ def _pcubicroots(b, c, d): # Analyze roots of the cubic T^3 + bT^2 + cT + d = 0 mod P, where # b = a2/p, c = a4/p^2, d = a6/p^3 - b = preduce(a2/pi) - c = preduce(a4/pi2) - d = preduce(a6/pi3) - bb = b*b - cc = c*c - bc = b*c - w = 27*d*d - bb*cc + 4*b*bb*d - 18*bc*d + 4*c*cc - x = 3*c - bb + b = preduce(a2 / pi) + c = preduce(a4 / pi2) + d = preduce(a6 / pi3) + bb = b * b + cc = c * c + bc = b * c + w = 27 * d * d - bb * cc + 4 * b * bb * d - 18 * bc * d + 4 * c * cc + x = 3 * c - bb if pdiv(w): if pdiv(x): sw = 3 @@ -990,7 +992,7 @@ def _pcubicroots(b, c, d): KS = KodairaSymbol("I0*") cp = 1 + _pcubicroots(b, c, d) fp = val_disc - 4 - break #return + break # return elif sw == 2: ## One double root - Type I*m for some m verbose("One double root", t, 1) @@ -1000,7 +1002,7 @@ def _pcubicroots(b, c, d): elif p == 3: r = c * pinv(b) else: - r = (bc - 9*d)*pinv(2*x) + r = (bc - 9 * d) * pinv(2 * x) r = pi * preduce(r) C = C.rst_transform(r, 0, 0) (a1, a2, a3, a4, a6) = C.a_invariants() @@ -1014,48 +1016,48 @@ def _pcubicroots(b, c, d): while True: a2t = preduce(a2 / pi) a3t = preduce(a3 / my) - a4t = preduce(a4 / (pi*mx)) - a6t = preduce(a6 / (mx*my)) - if pdiv(a3t*a3t + 4*a6t): + a4t = preduce(a4 / (pi * mx)) + a6t = preduce(a6 / (mx * my)) + if pdiv(a3t * a3t + 4 * a6t): if p == 2: - t = my*proot(a6t, 2) + t = my * proot(a6t, 2) else: - t = my*preduce(-a3t*halfmodp) + t = my * preduce(-a3t * halfmodp) C = C.rst_transform(0, 0, t) (a1, a2, a3, a4, a6) = C.a_invariants() my *= pi iy += 1 a2t = preduce(a2 / pi) - a3t = preduce(a3/my) - a4t = preduce(a4/(pi*mx)) - a6t = preduce(a6/(mx*my)) - if pdiv(a4t*a4t - 4*a6t*a2t): + a3t = preduce(a3 / my) + a4t = preduce(a4 / (pi * mx)) + a6t = preduce(a6 / (mx * my)) + if pdiv(a4t * a4t - 4 * a6t * a2t): if p == 2: - r = mx*proot(a6t*pinv(a2t), 2) + r = mx * proot(a6t * pinv(a2t), 2) else: - r = mx*preduce(-a4t*pinv(2*a2t)) + r = mx * preduce(-a4t * pinv(2 * a2t)) C = C.rst_transform(r, 0, 0) (a1, a2, a3, a4, a6) = C.a_invariants() mx *= pi - ix += 1 # and stay in loop + ix += 1 # and stay in loop else: if _pquadroots(a2t, a4t, a6t): cp = 4 else: cp = 2 - break # exit loop + break # exit loop else: if _pquadroots(1, a3t, -a6t): cp = 4 else: cp = 2 break - KS = KodairaSymbol("I%s*" % (ix+iy-5)) + KS = KodairaSymbol("I%s*" % (ix + iy - 5)) fp = val_disc - ix - iy + 1 - break #return - else: # sw == 3 + break # return + else: # sw == 3 ## The cubic has a triple root verbose("Triple root", t, 1) ## First we change coordinates so that T = 0 mod p @@ -1065,28 +1067,28 @@ def _pcubicroots(b, c, d): r = proot(-d, 3) else: r = -b * pinv(3) - r = pi*preduce(r) + r = pi * preduce(r) C = C.rst_transform(r, 0, 0) (a1, a2, a3, a4, a6) = C.a_invariants() - verbose("After third transform %s\n[a1,a2,a3,a4,a6] = %s\nValuations: %s" % ([r,0,0],[a1,a2,a3,a4,a6],[pval(ai) for ai in [a1,a2,a3,a4,a6]]), t, 2) - if min(pval(ai) for ai in [a1,a2,a3,a4,a6]) < 0: + verbose("After third transform %s\n[a1,a2,a3,a4,a6] = %s\nValuations: %s" % ([r, 0, 0], [a1, a2, a3, a4, a6], [pval(ai) for ai in [a1, a2, a3, a4, a6]]), t, 2) + if min(pval(ai) for ai in [a1, a2, a3, a4, a6]) < 0: raise RuntimeError("Non-integral model after third transform!") if pval(a2) < 2 or pval(a4) < 3 or pval(a6) < 4: raise RuntimeError("Cubic after transform does not have a triple root at 0") - a3t = preduce(a3/pi2) - a6t = preduce(a6/pi4) + a3t = preduce(a3 / pi2) + a6t = preduce(a6 / pi4) # We test for Type IV* - if not pdiv(a3t*a3t + 4*a6t): + if not pdiv(a3t * a3t + 4 * a6t): cp = 3 if _pquadroots(1, a3t, -a6t) else 1 KS = KodairaSymbol("IV*") fp = val_disc - 6 - break #return + break # return # Now change coordinates so that p^3|a3, p^5|a6 if p == 2: - t = -pi2*proot(a6t, 2) + t = -pi2 * proot(a6t, 2) else: - t = pi2*preduce(-a3t*halfmodp) + t = pi2 * preduce(-a3t * halfmodp) C = C.rst_transform(0, 0, t) (a1, a2, a3, a4, a6) = C.a_invariants() @@ -1096,22 +1098,22 @@ def _pcubicroots(b, c, d): KS = KodairaSymbol("III*") fp = val_disc - 7 cp = 2 - break #return + break # return if pval(a6) < 6: ## Type II* KS = KodairaSymbol("II*") fp = val_disc - 8 cp = 1 - break #return + break # return if pi_neg is None: if principal_flag: pi_neg = pi else: pi_neg = K.uniformizer(P, 'negative') - pi_neg2 = pi_neg*pi_neg - pi_neg3 = pi_neg*pi_neg2 - pi_neg4 = pi_neg*pi_neg3 - pi_neg6 = pi_neg4*pi_neg2 + pi_neg2 = pi_neg * pi_neg + pi_neg3 = pi_neg * pi_neg2 + pi_neg4 = pi_neg * pi_neg3 + pi_neg6 = pi_neg4 * pi_neg2 a1 /= pi_neg a2 /= pi_neg2 a3 /= pi_neg3 diff --git a/src/sage/schemes/elliptic_curves/ell_modular_symbols.py b/src/sage/schemes/elliptic_curves/ell_modular_symbols.py index c1682b01569..099112ecbe5 100644 --- a/src/sage/schemes/elliptic_curves/ell_modular_symbols.py +++ b/src/sage/schemes/elliptic_curves/ell_modular_symbols.py @@ -72,7 +72,7 @@ - John Cremona (2016): reworked eclib interface """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2007 William Stein # # Distributed under the terms of the GNU General Public License (GPL) @@ -85,12 +85,9 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** -from sage.arith.misc import (kronecker as kronecker_symbol, - next_prime, - prime_divisors, - valuation) +from sage.arith.misc import kronecker as kronecker_symbol, next_prime, prime_divisors, valuation from sage.databases.cremona import parse_cremona_label from sage.misc.verbose import verbose from sage.modular.cusps import Cusps @@ -218,8 +215,7 @@ def _repr_(self): Modular symbol with sign -1 over Rational Field attached to Elliptic Curve defined by y^2 + y = x^3 + x^2 over Rational Field """ - return "Modular symbol with sign %s over %s attached to %s" % ( - self._sign, self._base_ring, self._E) + return "Modular symbol with sign %s over %s attached to %s" % (self._sign, self._base_ring, self._E) class ModularSymbolECLIB(ModularSymbol): @@ -335,7 +331,7 @@ def __init__(self, E, sign, nap=1000): raise TypeError('sign must -1 or 1') self._sign = ZZ(sign) self._E = E - self._scaling = 1 if E.discriminant() > 0 else ZZ(1)/2 + self._scaling = 1 if E.discriminant() > 0 else ZZ(1) / 2 self._implementation = "eclib" self._base_ring = QQ # The ECModularSymbol class must be initialized with sign=0 to compute minus symbols @@ -372,6 +368,7 @@ def __call__(self, r, base_at_infinity=True): 1/5 """ from sage.rings.rational import Rational + if r != oo: r = Rational(r) r = r.numer() % r.denom() / r.denom() @@ -464,12 +461,12 @@ def __init__(self, E, sign, normalize='L_ratio'): self._find_scaling_period() # will reset _e and _scaling else: self._e *= self._scaling - elif normalize == "period" : - self._find_scaling_period() # this will set _e and _scaling + elif normalize == "period": + self._find_scaling_period() # this will set _e and _scaling elif normalize == "none": self._scaling = 1 self._e = self._modsym.dual_eigenvector() - else : + else: raise ValueError("no normalization %s known for modular symbols" % normalize) def _find_scaling_L_ratio(self): @@ -547,56 +544,56 @@ def _find_scaling_L_ratio(self): ....: assert ED.lseries().L_ratio()*ED.real_components() * etaD == md """ E = self._E - self._scaling = 1 # initial value, may be changed later. + self._scaling = 1 # initial value, may be changed later. self._failed_to_scale = False - if self._sign == 1 : + if self._sign == 1: at0 = self(0) - if at0 != 0 : + if at0 != 0: l1 = self.__lalg__(1) if at0 != l1: - verbose('scale modular symbols by %s' % (l1/at0)) - self._scaling = l1/at0 - else : + verbose('scale modular symbols by %s' % (l1 / at0)) + self._scaling = l1 / at0 + else: # if [0] = 0, we can still hope to scale it correctly by considering twists of E - Dlist = [5,8,12,13,17,21,24,28,29, 33, 37, 40, 41, 44, 53, 56, 57, 60, 61, 65, 69, 73, 76, 77, 85, 88, 89, 92, 93, 97] # a list of positive fundamental discriminants + Dlist = [5, 8, 12, 13, 17, 21, 24, 28, 29, 33, 37, 40, 41, 44, 53, 56, 57, 60, 61, 65, 69, 73, 76, 77, 85, 88, 89, 92, 93, 97] # a list of positive fundamental discriminants j = 0 at0 = 0 # computes [0]+ for the twist of E by D until one value is nonzero - while j < 30 and at0 == 0 : + while j < 30 and at0 == 0: D = Dlist[j] # the following line checks if the twist of the newform of E by D is a newform # this is to avoid that we 'twist back' - if all( valuation(E.conductor(),ell) <= valuation(D,ell) for ell in prime_divisors(D) ) : - at0 = sum([kronecker_symbol(D,u) * self(ZZ(u)/D) for u in range(1,abs(D))]) + if all(valuation(E.conductor(), ell) <= valuation(D, ell) for ell in prime_divisors(D)): + at0 = sum([kronecker_symbol(D, u) * self(ZZ(u) / D) for u in range(1, abs(D))]) j += 1 - if j == 30 and at0 == 0: # curves like "121b1", "225a1", "225e1", "256a1", "256b1", "289a1", "361a1", "400a1", "400c1", "400h1", "441b1", "441c1", "441d1", "441f1 .. will arrive here + if j == 30 and at0 == 0: # curves like "121b1", "225a1", "225e1", "256a1", "256b1", "289a1", "361a1", "400a1", "400c1", "400h1", "441b1", "441c1", "441d1", "441f1 .. will arrive here print("Warning : Could not normalize the modular symbols, maybe all further results will be multiplied by -1 and a power of 2") self._failed_to_scale = True - else : + else: l1 = self.__lalg__(D) if at0 != l1: - verbose('scale modular symbols by %s found at D=%s ' % (l1/at0,D), level=2) - self._scaling = l1/at0 + verbose('scale modular symbols by %s found at D=%s ' % (l1 / at0, D), level=2) + self._scaling = l1 / at0 - else : # that is when sign = -1 - Dlist = [-3,-4,-7,-8,-11,-15,-19,-20,-23,-24, -31, -35, -39, -40, -43, -47, -51, -52, -55, -56, -59, -67, -68, -71, -79, -83, -84, -87, -88, -91] # a list of negative fundamental discriminants + else: # that is when sign = -1 + Dlist = [-3, -4, -7, -8, -11, -15, -19, -20, -23, -24, -31, -35, -39, -40, -43, -47, -51, -52, -55, -56, -59, -67, -68, -71, -79, -83, -84, -87, -88, -91] # a list of negative fundamental discriminants j = 0 at0 = 0 - while j < 30 and at0 == 0 : + while j < 30 and at0 == 0: # computes [0]+ for the twist of E by D until one value is nonzero D = Dlist[j] - if all( valuation(E.conductor(),ell) <= valuation(D,ell) for ell in prime_divisors(D) ) : - at0 = - sum([kronecker_symbol(D,u) * self(ZZ(u)/D) for u in range(1,abs(D))]) + if all(valuation(E.conductor(), ell) <= valuation(D, ell) for ell in prime_divisors(D)): + at0 = -sum([kronecker_symbol(D, u) * self(ZZ(u) / D) for u in range(1, abs(D))]) j += 1 - if j == 30 and at0 == 0: # no more hope for a normalization + if j == 30 and at0 == 0: # no more hope for a normalization print("Warning : Could not normalize the modular symbols, maybe all further results will be multiplied by -1 and a power of 2") self._failed_to_scale = True - else : + else: l1 = self.__lalg__(D) if at0 != l1: - verbose('scale modular symbols by %s' % (l1/at0)) - self._scaling = l1/at0 + verbose('scale modular symbols by %s' % (l1 / at0)) + self._scaling = l1 / at0 def __lalg__(self, D): r""" @@ -619,6 +616,7 @@ def __lalg__(self, D): 5/2 """ from sage.misc.functional import sqrt + # the computation of the L-value could take a lot of time, # but then the conductor is so large # that the computation of modular symbols for E took even longer @@ -628,10 +626,10 @@ def __lalg__(self, D): lv = ED.lseries().L_ratio() # this is L(ED,1) divided by the Néron period omD of ED lv *= ED.real_components() # now it is by the least positive period omD = ED.period_lattice().basis()[0] - if D > 0 : + if D > 0: om = E.period_lattice().basis()[0] q = sqrt(D) * omD / om * 8 - else : + else: om = E.period_lattice().basis()[1].imag() if E.real_components() == 1: om *= 2 @@ -684,18 +682,18 @@ def _find_scaling_period(self): self._e = P.matrix().transpose().row(0) self._e /= 2 E = self._E - try : + try: crla = parse_cremona_label(E.label()) - except RuntimeError: # raised when curve is outside of the table + except RuntimeError: # raised when curve is outside of the table print("Warning : Could not normalize the modular symbols, maybe all further results will be multiplied by a rational number.") self._scaling = 1 - else : + else: cr0 = Integer(crla[0]).str() + crla[1] + '1' E0 = EllipticCurve(cr0) if self._sign == 1: - q = E0.period_lattice().basis()[0]/E.period_lattice().basis()[0] + q = E0.period_lattice().basis()[0] / E.period_lattice().basis()[0] else: - q = E0.period_lattice().basis()[1].imag()/E.period_lattice().basis()[1].imag() + q = E0.period_lattice().basis()[1].imag() / E.period_lattice().basis()[1].imag() if E0.real_components() == 1: q *= 2 if E.real_components() == 1: @@ -726,7 +724,7 @@ def _call_with_caching(self, r): self.__cache = {} except KeyError: pass - w = self._ambient_modsym([oo,r]).element() + w = self._ambient_modsym([oo, r]).element() c = (self._e).dot_product(w) self.__cache[r] = c return c diff --git a/src/sage/schemes/elliptic_curves/ell_number_field.py b/src/sage/schemes/elliptic_curves/ell_number_field.py index 83b5797981f..d77ae8353f6 100644 --- a/src/sage/schemes/elliptic_curves/ell_number_field.py +++ b/src/sage/schemes/elliptic_curves/ell_number_field.py @@ -115,6 +115,7 @@ class EllipticCurve_number_field(EllipticCurve_field): y^2 + i*x*y + (i+1)*y = x^3 + (i-1)*x^2 + (24*i+15)*x + (14*i+35) over Number Field in i with defining polynomial x^2 + 1 """ + def __init__(self, K, ainvs): r""" EXAMPLES: @@ -165,8 +166,7 @@ def base_extend(self, R): E._known_points = [E([R(_) for _ in P.xy()]) for P in self._known_points if not P.is_zero()] return E - def simon_two_descent(self, verbose=0, lim1=2, lim3=4, limtriv=2, - maxprob=20, limbigprime=30, known_points=None): + def simon_two_descent(self, verbose=0, lim1=2, lim3=4, limtriv=2, maxprob=20, limbigprime=30, known_points=None): r""" Return lower and upper bounds on the rank of the Mordell-Weil group `E(K)` and a list of points. @@ -290,8 +290,7 @@ def simon_two_descent(self, verbose=0, lim1=2, lim3=4, limtriv=2, # time (when known_points may have increased) will not cause # another execution of simon_two_descent. try: - result = self._simon_two_descent_data[lim1, lim3, limtriv, - maxprob, limbigprime] + result = self._simon_two_descent_data[lim1, lim3, limtriv, maxprob, limbigprime] if verbose == 0: return result except AttributeError: @@ -300,13 +299,10 @@ def simon_two_descent(self, verbose=0, lim1=2, lim3=4, limtriv=2, pass from .gp_simon import simon_two_descent - t = simon_two_descent(self, verbose=verbose, - lim1=lim1, lim3=lim3, limtriv=limtriv, - maxprob=maxprob, limbigprime=limbigprime, - known_points=known_points) - self._simon_two_descent_data[lim1,lim3,limtriv,maxprob,limbigprime] = t - self._known_points.extend([P for P in t[2] - if P not in self._known_points]) + + t = simon_two_descent(self, verbose=verbose, lim1=lim1, lim3=lim3, limtriv=limtriv, maxprob=maxprob, limbigprime=limbigprime, known_points=known_points) + self._simon_two_descent_data[lim1, lim3, limtriv, maxprob, limbigprime] = t + self._known_points.extend([P for P in t[2] if P not in self._known_points]) return t def height_pairing_matrix(self, points=None, precision=None, normalised=True): @@ -393,6 +389,7 @@ def height_pairing_matrix(self, points=None, precision=None, normalised=True): else: RR = RealField(precision) from sage.matrix.matrix_space import MatrixSpace + M = MatrixSpace(RR, r) mat = M() for j in range(r): @@ -573,10 +570,9 @@ def local_integral_model(self, *P): E = E.local_integral_model(Pi) return E ai = self.a_invariants() - e = min((ai[i].valuation(P) / [1, 2, 3, 4, 6][i]) - for i in range(5)).floor() + e = min((ai[i].valuation(P) / [1, 2, 3, 4, 6][i]) for i in range(5)).floor() pi = self.base_field().uniformizer(P, 'negative') - return EllipticCurve([ai[i]/pi**(e*[1,2,3,4,6][i]) for i in range(5)]) + return EllipticCurve([ai[i] / pi ** (e * [1, 2, 3, 4, 6][i]) for i in range(5)]) def is_global_integral_model(self): r""" @@ -664,14 +660,12 @@ def global_integral_model(self): """ K = self.base_field() ai = self.a_invariants() - Ps = {ff[0] for a in ai if not a.is_integral() - for ff in a.denominator_ideal().factor()} + Ps = {ff[0] for a in ai if not a.is_integral() for ff in a.denominator_ideal().factor()} for P in Ps: pi = K.uniformizer(P, 'positive') - e = min((ai[i].valuation(P)/[1,2,3,4,6][i]) - for i in range(5)).floor() + e = min((ai[i].valuation(P) / [1, 2, 3, 4, 6][i]) for i in range(5)).floor() if e < 0: - ai = [ai[i]/pi**(e*[1,2,3,4,6][i]) for i in range(5)] + ai = [ai[i] / pi ** (e * [1, 2, 3, 4, 6][i]) for i in range(5)] if all(a.is_integral() for a in ai): break for z in ai: @@ -804,30 +798,30 @@ def _scale_by_units(self): if r1 + r2 == 1: # unit rank is 0 return self - degs = [1]*r1 + [2]*r2 + degs = [1] * r1 + [2] * r2 fu = K.units() c4, c6 = self.c_invariants() from sage.matrix.constructor import Matrix from sage.modules.free_module_element import vector - prec = 1000 # initial value, will be increased if necessary + prec = 1000 # initial value, will be increased if necessary ok = False while not ok: embs = K.places(prec=prec) c4s = [e(c4) for e in embs] c6s = [e(c6) for e in embs] - U = Matrix([[e(u).abs().log()*d for d,e in zip(degs,embs)] for u in fu]) - v = vector([(x4.abs().nth_root(4)+x6.abs().nth_root(6)).log()*d for x4,x6,d in zip(c4s,c6s,degs)]) - w = -(U*U.transpose()).inverse()*U*v + U = Matrix([[e(u).abs().log() * d for d, e in zip(degs, embs)] for u in fu]) + v = vector([(x4.abs().nth_root(4) + x6.abs().nth_root(6)).log() * d for x4, x6, d in zip(c4s, c6s, degs)]) + w = -(U * U.transpose()).inverse() * U * v try: es = [e.round() for e in w] ok = True except ValueError: prec *= 2 - u = prod([uj**ej for uj,ej in zip(fu,es)]) + u = prod([uj**ej for uj, ej in zip(fu, es)]) return self.scale_curve(u) def local_data(self, P=None, proof=None, algorithm='pari', globally=False): @@ -923,6 +917,7 @@ def local_data(self, P=None, proof=None, algorithm='pari', globally=False): """ if proof is None: import sage.structure.proof.proof + # We use the "number_field" flag because the actual proof dependence is in PARI's number field functions. proof = sage.structure.proof.proof.get_flag(None, "number_field") @@ -931,9 +926,10 @@ def local_data(self, P=None, proof=None, algorithm='pari', globally=False): return [self._get_local_data(pr, proof) for pr in primes] from sage.schemes.elliptic_curves.ell_local_data import check_prime - P = check_prime(self.base_field(),P) - return self._get_local_data(P,proof,algorithm,globally) + P = check_prime(self.base_field(), P) + + return self._get_local_data(P, proof, algorithm, globally) def _get_local_data(self, P, proof, algorithm='pari', globally=False): r""" @@ -996,6 +992,7 @@ def _get_local_data(self, P, proof, algorithm='pari', globally=False): except KeyError: pass from sage.schemes.elliptic_curves.ell_local_data import EllipticCurveLocalData + self._local_data[P, proof, algorithm, globally] = EllipticCurveLocalData(self, P, proof, algorithm, globally) return self._local_data[P, proof, algorithm, globally] @@ -1042,6 +1039,7 @@ def local_minimal_model(self, P, proof=None, algorithm='pari'): """ if proof is None: import sage.structure.proof.proof + # We use the "number_field" flag because the actual proof dependence is in PARI's number field functions. proof = sage.structure.proof.proof.get_flag(None, "number_field") @@ -1268,6 +1266,7 @@ def tamagawa_number(self, P, proof=None): """ if proof is None: import sage.structure.proof.proof + # We use the "number_field" flag because the actual proof dependence is in PARI's number field functions. proof = sage.structure.proof.proof.get_flag(None, "number_field") @@ -1290,8 +1289,7 @@ def tamagawa_numbers(self) -> list: sage: eK.tamagawa_numbers() [4, 6, 1] """ - return [self.tamagawa_number(p) - for p in self.conductor().prime_factors()] + return [self.tamagawa_number(p) for p in self.conductor().prime_factors()] def tamagawa_exponent(self, P, proof=None): r""" @@ -1321,6 +1319,7 @@ def tamagawa_exponent(self, P, proof=None): """ if proof is None: import sage.structure.proof.proof + # We use the "number_field" flag because the actual proof dependence is in PARI's number field functions. proof = sage.structure.proof.proof.get_flag(None, "number_field") @@ -1433,7 +1432,7 @@ def tamagawa_product_bsd(self): p = pp.smallest_integer() f = pp.residue_class_degree() v = uu.valuation(pp) - uu_abs_val = p**(f*v) + uu_abs_val = p ** (f * v) pr *= cv * uu_abs_val return pr @@ -1470,6 +1469,7 @@ def kodaira_symbol(self, P, proof=None): """ if proof is None: import sage.structure.proof.proof + # We use the "number_field" flag because the actual proof dependence is in PARI's number field functions. proof = sage.structure.proof.proof.get_flag(None, "number_field") @@ -1522,9 +1522,7 @@ def conductor(self): # K == QQ it has to be ZZ.ideal(1). K = self.base_field() N = ZZ.ideal(1) if K is QQ else K.fractional_ideal(1) - self._conductor = prod([d.prime()**d.conductor_valuation() - for d in self.local_data()], - N) + self._conductor = prod([d.prime() ** d.conductor_valuation() for d in self.local_data()], N) return self._conductor def minimal_discriminant_ideal(self): @@ -1584,7 +1582,7 @@ def minimal_discriminant_ideal(self): # differently to (fractional) ideals of other number fields. if not dat: return self.base_field().ideal(1) - return prod([d.prime()**d.discriminant_valuation() for d in dat]) + return prod([d.prime() ** d.discriminant_valuation() for d in dat]) def non_minimal_primes(self): r""" @@ -1632,7 +1630,7 @@ def non_minimal_primes(self): if self.base_field() is QQ: primes = [P.gen() for P in primes] vals = [d.discriminant_valuation() for d in dat] - return [P for P,v in zip(primes,vals) if D.valuation(P) > v] + return [P for P, v in zip(primes, vals) if D.valuation(P) > v] def is_global_minimal_model(self): r""" @@ -1734,8 +1732,7 @@ def global_minimality_class(self): dat = self.local_data() primes = [d.prime() for d in dat] vals = [d.discriminant_valuation() for d in dat] - I = prod([P**((D.valuation(P)-v)//12) for P,v in zip(primes,vals)], - K.ideal(1)) + I = prod([P ** ((D.valuation(P) - v) // 12) for P, v in zip(primes, vals)], K.ideal(1)) return Cl(I) def has_global_minimal_model(self) -> bool: @@ -1886,6 +1883,7 @@ def global_minimal_model(self, proof=None, semi_global=False): """ if proof is None: import sage.structure.proof.proof + # We use the "number_field" flag because the actual proof dependence is in PARI's number field functions. proof = sage.structure.proof.proof.get_flag(None, "number_field") @@ -1893,9 +1891,10 @@ def global_minimal_model(self, proof=None, semi_global=False): if self.base_ring().class_number() == 1: E = self.global_integral_model() for P in E.base_ring()(E.discriminant()).support(): - E = E.local_data(P,proof, globally=True).minimal_model() + E = E.local_data(P, proof, globally=True).minimal_model() else: from .kraus import semi_global_minimal_model + E, P = semi_global_minimal_model(self) return E._scale_by_units()._reduce_model() @@ -2047,6 +2046,7 @@ def torsion_subgroup(self, n=None, **kwds): if n is None: if not hasattr(self, '_cached_torsion_subgroup'): from .ell_torsion import EllipticCurveTorsionSubgroup + self._cached_torsion_subgroup = EllipticCurveTorsionSubgroup(self) return self._cached_torsion_subgroup @@ -2170,7 +2170,7 @@ def torsion_points(self): (1 : 0 : 1)] """ T = self.torsion_subgroup() # cached - return sorted(T.points()) # these are also cached in T + return sorted(T.points()) # these are also cached in T def rank_bounds(self, **kwds): r""" @@ -2491,6 +2491,7 @@ def period_lattice(self, embedding): -0.14934463314391922099120107422 - 2.0661954627294548995621225062*I) """ from sage.schemes.elliptic_curves.period_lattice import PeriodLattice_ell + return PeriodLattice_ell(self, embedding) def real_components(self, embedding): @@ -2541,7 +2542,8 @@ def real_components(self, embedding): from sage.rings.number_field.number_field import refine_embedding from sage.rings.infinity import Infinity - e = refine_embedding(embedding,Infinity) + + e = refine_embedding(embedding, Infinity) return 2 if e(self.discriminant()) > 0 else 1 @@ -2561,6 +2563,7 @@ def height_function(self): """ if not hasattr(self, '_height_function'): from sage.schemes.elliptic_curves.height import EllipticCurveCanonicalHeight + self._height_function = EllipticCurveCanonicalHeight(self) return self._height_function @@ -2958,6 +2961,7 @@ class number is only `3` is that the class also contains three return self._isoclass except AttributeError: from sage.schemes.elliptic_curves.isogeny_class import IsogenyClass_EC_NumberField + self._isoclass = IsogenyClass_EC_NumberField(self, reducible_primes=reducible_primes, algorithm=algorithm, minimal_models=minimal_models) return self._isoclass @@ -3058,19 +3062,17 @@ def isogenies_prime_degree(self, l=None, algorithm='Billerey', minimal_models=Tr if l is None: from .isogeny_class import possible_isogeny_degrees + L = possible_isogeny_degrees(self) return self.isogenies_prime_degree(L, minimal_models=minimal_models) - isogs = sum([self.isogenies_prime_degree(p, minimal_models=minimal_models) for p in l], - []) + isogs = sum([self.isogenies_prime_degree(p, minimal_models=minimal_models) for p in l], []) if self.has_rational_cm(): # eliminate any endomorphisms and repeated codomains isogs = [phi for phi in isogs if not self.is_isomorphic(phi.codomain())] codoms = [phi.codomain() for phi in isogs] - isogs = [phi for i, phi in enumerate(isogs) - if not any(E.is_isomorphic(codoms[i]) - for E in codoms[:i])] + isogs = [phi for i, phi in enumerate(isogs) if not any(E.is_isomorphic(codoms[i]) for E in codoms[:i])] return isogs def is_isogenous(self, other, proof=True, maxnorm=100): @@ -3220,17 +3222,16 @@ def is_isogenous(self, other, proof=True, maxnorm=100): # We first try the easiest cases: primes for which X_0(l) has genus 0: for l in [2, 3, 5, 7, 13]: - if any(E2.is_isomorphic(f.codomain()) - for f in E1.isogenies_prime_degree(l)): + if any(E2.is_isomorphic(f.codomain()) for f in E1.isogenies_prime_degree(l)): return True # Next we try the primes for which X_0^+(l) has genus 0 for # which isogeny-finding is faster than in general: from .isogeny_small_degree import hyperelliptic_primes + for l in hyperelliptic_primes: - if any(E2.is_isomorphic(f.codomain()) - for f in E1.isogenies_prime_degree(l)): + if any(E2.is_isomorphic(f.codomain()) for f in E1.isogenies_prime_degree(l)): return True # Next we try looking modulo some more primes: @@ -3249,7 +3250,7 @@ def is_isogenous(self, other, proof=True, maxnorm=100): return any(E2.is_isomorphic(E3) for E3 in E1.isogeny_class().curves) - raise NotImplementedError("Curves appear to be isogenous (same conductor, isogenous modulo all primes of norm up to %s), but no isogeny has been constructed." % (10*maxnorm)) + raise NotImplementedError("Curves appear to be isogenous (same conductor, isogenous modulo all primes of norm up to %s), but no isogeny has been constructed." % (10 * maxnorm)) def isogeny_degree(self, other): """ @@ -3303,8 +3304,7 @@ def isogeny_degree(self, other): except ValueError: return ZZ.zero() - def reducible_primes(self, algorithm='Billerey', max_l=None, - num_l=None, verbose=False): + def reducible_primes(self, algorithm='Billerey', max_l=None, num_l=None, verbose=False): r""" Return a finite set of primes `\ell` for which `E` has a K-rational `\ell`-isogeny. @@ -3374,6 +3374,7 @@ def reducible_primes(self, algorithm='Billerey', max_l=None, [] """ from sage.schemes.elliptic_curves.isogeny_class import possible_isogeny_degrees + return possible_isogeny_degrees(self, max_l=max_l, num_l=num_l, exact=True, verbose=verbose) def lll_reduce(self, points, height_matrix=None, precision=None): @@ -3498,8 +3499,7 @@ def lll_reduce(self, points, height_matrix=None, precision=None): if height_matrix is None: height_matrix = self.height_pairing_matrix(points, precision) U = height_matrix.__pari__().lllgram().sage() - new_points = [sum([U[j, i]*points[j] for j in range(r)]) - for i in range(r)] + new_points = [sum([U[j, i] * points[j] for j in range(r)]) for i in range(r)] return new_points, U def galois_representation(self): @@ -3534,6 +3534,7 @@ def galois_representation(self): [5] """ from .gal_reps_number_field import GaloisRepresentation + return GaloisRepresentation(self) @cached_method @@ -3576,10 +3577,11 @@ def cm_discriminant(self): -108 """ from sage.schemes.elliptic_curves.cm import is_cm_j_invariant + flag, df = is_cm_j_invariant(self.j_invariant()) if flag: d, f = df - return d*f**2 + return d * f**2 # no CM return ZZ.zero() @@ -3715,8 +3717,7 @@ def has_rational_cm(self, field=None) -> bool: if self.base_field().embeddings(field): D = field(D) return D.is_square() - raise ValueError("Error in has_rational_cm: %s is not an extension field of %s" - % (field,self.base_field())) + raise ValueError("Error in has_rational_cm: %s is not an extension field of %s" % (field, self.base_field())) @cached_method def is_Q_curve(self, maxp=100, certificate=False, verbose=False): @@ -3861,11 +3862,10 @@ def is_Q_curve(self, maxp=100, certificate=False, verbose=False): 'rho': 1} """ from sage.schemes.elliptic_curves.Qcurves import is_Q_curve as isQ + return isQ(self, maxp, certificate, verbose) - def saturation(self, points, verbose=False, - max_prime=0, one_prime=0, odd_primes_only=False, - lower_ht_bound=None, reg=None, debug=False): + def saturation(self, points, verbose=False, max_prime=0, one_prime=0, odd_primes_only=False, lower_ht_bound=None, reg=None, debug=False): r""" Given a list of rational points on `E` over `K`, compute the saturation in `E(K)` of the subgroup they generate. @@ -4032,15 +4032,16 @@ def saturation(self, points, verbose=False, sat_reg = reg from sage.rings.fast_arith import prime_range + if full_saturation: if lower_ht_bound is None: # TODO (robertwb): verify this for rank > 1 if verbose: print("Computing lower height bound..") - lower_ht_bound = self.height_function().min(.1, 5) ** n + lower_ht_bound = self.height_function().min(0.1, 5) ** n if verbose: print("..done: %s" % lower_ht_bound) - index_bound = (reg/lower_ht_bound).sqrt() + index_bound = (reg / lower_ht_bound).sqrt() if index_bound < 2: if verbose: print("Saturation index bound < 2, points are saturated already.") @@ -4052,7 +4053,7 @@ def saturation(self, points, verbose=False, if one_prime: prime_list = [one_prime] else: - prime_list = prime_range(max_prime+1) + prime_list = prime_range(max_prime + 1) if odd_primes_only and 2 in prime_list: prime_list.remove(2) @@ -4062,6 +4063,7 @@ def saturation(self, points, verbose=False, # reset whenever the point list changes. from sage.schemes.elliptic_curves.saturation import EllipticCurveSaturator + saturator = EllipticCurveSaturator(self, verbose) for p in prime_list: if full_saturation and (p > index_bound): @@ -4192,6 +4194,7 @@ def rational_points(self, **kwds): (a : 0 : 1) """ from sage.schemes.curves.constructor import Curve + # we change E to be a plain curve to allow the generic rational # points code to reduce mod any prime, whereas an EllipticCurve # can only be base changed to good primes. diff --git a/src/sage/schemes/elliptic_curves/ell_padic_field.py b/src/sage/schemes/elliptic_curves/ell_padic_field.py index c0216dd44f1..80e744461b3 100644 --- a/src/sage/schemes/elliptic_curves/ell_padic_field.py +++ b/src/sage/schemes/elliptic_curves/ell_padic_field.py @@ -175,9 +175,7 @@ def local_coordinates_at_nonweierstrass(self, P, prec=20, name="t"): d = P[1] if d.is_zero(): - raise ValueError( - f"P = {P} is a Weierstrass point. Use local_coordinates_at_weierstrass instead!" - ) + raise ValueError(f"P = {P} is a Weierstrass point. Use local_coordinates_at_weierstrass instead!") pol = self.hyperelliptic_polynomials()[0] L = PowerSeriesRing(self.base_ring(), name, default_prec=prec) @@ -229,9 +227,7 @@ def local_coordinates_at_weierstrass(self, P, prec=20, name="t"): """ # Ensure the input point is Weierstrass if not P[1].is_zero(): - raise ValueError( - f"P = {P} is not a finite Weierstrass point. Use local_coordinates_at_nonweierstrass instead!" - ) + raise ValueError(f"P = {P} is not a finite Weierstrass point. Use local_coordinates_at_nonweierstrass instead!") if P[2].is_zero(): raise ValueError(f"P = {P} is the point at infinity. Use local_coordinates_at_infinity instead!") @@ -415,9 +411,7 @@ def local_analytic_interpolation(self, P, Q): raise ValueError(f"{P} and {Q} are not in the same residue disc") disc = self.residue_disc(P) t = PowerSeriesRing(self.base_ring(), "t", prec).gen(0) - if disc == self.change_ring(self.base_ring().residue_field())( - 0, 1, 0 - ): # Infinite disc + if disc == self.change_ring(self.base_ring().residue_field())(0, 1, 0): # Infinite disc x, y = self.local_coordinates_at_infinity(2 * prec) return (x * t**3, y * t**3, t**3) if disc[1] != 0: # non-Weierstrass disc @@ -459,9 +453,7 @@ def weierstrass_points(self): f, h = self.hyperelliptic_polynomials() if not h.is_zero(): raise NotImplementedError() - return [self((0, 1, 0))] + [ - self((x, 0, 1)) for x in f.roots(multiplicities=False) - ] + return [self((0, 1, 0))] + [self((x, 0, 1)) for x in f.roots(multiplicities=False)] def is_in_weierstrass_disc(self, P): """ @@ -592,9 +584,7 @@ def residue_disc(self, P): try: HF = self.change_ring(F) except ValueError: - raise ValueError( - "The base change of the elliptic curve to the residue field is not well-defined." - ) + raise ValueError("The base change of the elliptic curve to the residue field is not well-defined.") if P == self(0, 1, 0): return HF(0, 1, 0) @@ -663,9 +653,7 @@ def tiny_integrals(self, F, P, Q): except TypeError: # if f is a constant, not callable f_dt = f * dt if x.valuation() != -2: - I = sum( - f_dt[n] / (n + 1) for n in range(f_dt.degree() + 1) - ) # \int_0^1 f dt + I = sum(f_dt[n] / (n + 1) for n in range(f_dt.degree() + 1)) # \int_0^1 f dt else: If_dt = f_dt.integral().laurent_polynomial() I = If_dt(Q[0] / Q[1]) - If_dt(P[0] / P[1]) @@ -817,14 +805,7 @@ def coleman_integrals_on_basis(self, P, Q, algorithm=None): offset = (2 - 1) * max(TPv, TQv) if offset == +Infinity: offset = (2 - 1) * min(TPv, TQv) - if ( - offset > prec - and (xTPv < 0 or xTQv < 0) - and ( - self.residue_disc(P) == self.change_ring(GF(p))(0, 1, 0) - or self.residue_disc(Q) == self.change_ring(GF(p))(0, 1, 0) - ) - ): + if offset > prec and (xTPv < 0 or xTQv < 0) and (self.residue_disc(P) == self.change_ring(GF(p))(0, 1, 0) or self.residue_disc(Q) == self.change_ring(GF(p))(0, 1, 0)): newprec = offset + prec K = pAdicField(p, newprec) A = PolynomialRing(RationalField(), "x") @@ -849,9 +830,7 @@ def coleman_integrals_on_basis(self, P, Q, algorithm=None): try: M_frob, forms = self._frob_calc except AttributeError: - M_frob, forms = self._frob_calc = ( - monsky_washnitzer.matrix_of_frobenius_hyperelliptic(self) - ) + M_frob, forms = self._frob_calc = monsky_washnitzer.matrix_of_frobenius_hyperelliptic(self) R = forms[0].base_ring() try: if PP is None: @@ -988,44 +967,18 @@ def coleman_integral(self, w, P, Q, algorithm="None"): return 0 if f == 0: return sum([vec[i] * basis_values[i] for i in range(dim)]) - if ( - w._coeff(x, -y) * x.derivative() / (-2 * y) - + w._coeff(x, y) * x.derivative() / (2 * y) - == 0 - ): - return ( - self.coleman_integral( - w, self(Q[0], -Q[1]), self(Q[0], Q[1]), algorithm - ) - / 2 - ) - raise ValueError( - "The differential is not odd: use coleman_integral_from_weierstrass_via_boundary" - ) + if w._coeff(x, -y) * x.derivative() / (-2 * y) + w._coeff(x, y) * x.derivative() / (2 * y) == 0: + return self.coleman_integral(w, self(Q[0], -Q[1]), self(Q[0], Q[1]), algorithm) / 2 + raise ValueError("The differential is not odd: use coleman_integral_from_weierstrass_via_boundary") elif self.is_weierstrass(Q): if f == 0: return sum([vec[i] * basis_values[i] for i in range(dim)]) - if ( - w._coeff(x, -y) * x.derivative() / (-2 * y) - + w._coeff(x, y) * x.derivative() / (2 * y) - == 0 - ): - return ( - -self.coleman_integral( - w, self(P[0], -P[1]), self(P[0], P[1]), algorithm - ) - / 2 - ) - raise ValueError( - "The differential is not odd: use coleman_integral_from_weierstrass_via_boundary" - ) + if w._coeff(x, -y) * x.derivative() / (-2 * y) + w._coeff(x, y) * x.derivative() / (2 * y) == 0: + return -self.coleman_integral(w, self(P[0], -P[1]), self(P[0], P[1]), algorithm) / 2 + raise ValueError("The differential is not odd: use coleman_integral_from_weierstrass_via_boundary") else: - return ( - f(Q[0], Q[1]) - - f(P[0], P[1]) - + sum([vec[i] * basis_values[i] for i in range(dim)]) - ) # this is just a dot product... + return f(Q[0], Q[1]) - f(P[0], P[1]) + sum([vec[i] * basis_values[i] for i in range(dim)]) # this is just a dot product... def curve_over_ram_extn(self, deg): r""" @@ -1210,9 +1163,7 @@ def S_to_Q(self, S, Q): try: M_frob, forms = self._frob_calc except AttributeError: - M_frob, forms = self._frob_calc = ( - monsky_washnitzer.matrix_of_frobenius_hyperelliptic(self) - ) + M_frob, forms = self._frob_calc = monsky_washnitzer.matrix_of_frobenius_hyperelliptic(self) try: HJ = self._curve_over_ram_extn K = HJ.base_ring() @@ -1229,12 +1180,8 @@ def S_to_Q(self, S, Q): else: P = self(ZZ(FS[0].expansion(0)), ZZ(FS[1].expansion(0))) x, y = self.local_coord(P, prec2) - integrals = [ - (x**i * x.derivative() / (2 * y)).integral() for i in range(dim) - ] - S_to_FS = vector( - [I.polynomial()(FS[1]) - I.polynomial()(S[1]) for I in integrals] - ) + integrals = [(x**i * x.derivative() / (2 * y)).integral() for i in range(dim)] + S_to_FS = vector([I.polynomial()(FS[1]) - I.polynomial()(S[1]) for I in integrals]) if HJ(Q[0], Q[1]) == HJ(FQ): FQ_to_Q = V(dim * [0]) else: diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index 1b08dacd5f8..515d9c2a182 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -151,8 +151,7 @@ from sage.schemes.curves.projective_curve import Hasse_bounds from sage.schemes.elliptic_curves.constructor import EllipticCurve -from sage.schemes.projective.projective_point import (SchemeMorphism_point_projective_ring, - SchemeMorphism_point_abelian_variety_field) +from sage.schemes.projective.projective_point import SchemeMorphism_point_projective_ring, SchemeMorphism_point_abelian_variety_field lazy_import('sage.rings.padics.factory', 'Qp') lazy_import('sage.schemes.generic.morphism', 'SchemeMorphism') @@ -164,11 +163,11 @@ PariError = () -class EllipticCurvePoint(AdditiveGroupElement, - SchemeMorphism_point_projective_ring): +class EllipticCurvePoint(AdditiveGroupElement, SchemeMorphism_point_projective_ring): """ A point on an elliptic curve. """ + def __init__(self, *args, **kwds): r""" Initialize this elliptic-curve point. @@ -290,10 +289,11 @@ def _add_(self, other): # integers as well as of univariate polynomial rings over fields. if isinstance(R, QuotientRing_generic): from sage.categories.euclidean_domains import EuclideanDomains + if R.cover_ring() in EuclideanDomains(): I = R.defining_ideal() if I.ngens() == 1: - mod, = I.gens() + (mod,) = I.gens() a1, a2, a3, a4, a6 = E.ainvs() x1, y1, z1 = map(R, self) @@ -304,9 +304,9 @@ def _add_(self, other): mod_2nd = mod.gcd(z1.lift()) mod //= mod_2nd - xz, zx = x1*z2, x2*z1 - yz, zy = y1*z2, y2*z1 - zz = z1*z2 + xz, zx = x1 * z2, x2 * z1 + yz, zy = y1 * z2, y2 * z1 + zz = z1 * z2 # addition num_add = yz - zy @@ -316,13 +316,14 @@ def _add_(self, other): # doubling if not mod_dbl.is_one(): - num_dbl = (3*x1 + 2*a2*z1) * x1 + (a4*z1 - a1*y1) * z1 - den_dbl = (2*y1 + a1*x1 + a3*z1) * z1 + num_dbl = (3 * x1 + 2 * a2 * z1) * x1 + (a4 * z1 - a1 * y1) * z1 + den_dbl = (2 * y1 + a1 * x1 + a3 * z1) * z1 else: num_dbl = den_dbl = 0 if mod_dbl.gcd(mod_add).is_one(): from sage.arith.misc import CRT_vectors + if mod_dbl.is_one(): num, den = num_add, den_add elif mod_add.is_one(): @@ -331,8 +332,8 @@ def _add_(self, other): num, den = CRT_vectors([(num_add, den_add), (num_dbl, den_dbl)], [mod_add, mod_dbl]) den2 = den**2 - x3 = ((num + a1*den)*zz*num - (xz + zx + a2*zz)*den2) * den - y3 = ((2*xz + zx + (a2 - a1**2)*zz)*num + (a1*(xz + zx + a2*zz) - a3*zz - yz)*den) * den2 - (num + 2*a1*den)*zz*num**2 + x3 = ((num + a1 * den) * zz * num - (xz + zx + a2 * zz) * den2) * den + y3 = ((2 * xz + zx + (a2 - a1**2) * zz) * num + (a1 * (xz + zx + a2 * zz) - a3 * zz - yz) * den) * den2 - (num + 2 * a1 * den) * zz * num**2 z3 = zz * den * den2 pt = x3.lift(), y3.lift(), z3.lift() @@ -354,7 +355,7 @@ def _add_(self, other): pts.append(pt) assert len(pts) == 2, 'bug in elliptic-curve point addition' - #TODO: If the base ring has trivial Picard group, it is known + # TODO: If the base ring has trivial Picard group, it is known # that some linear combination of the two vectors is a valid # projective point (whose coordinates generate the unit ideal). # Below, we simply try random linear combinations until we @@ -400,7 +401,7 @@ def _neg_(self): E = self.curve() a1, _, a3, _, _ = E.a_invariants() x, y, z = self - return E.point([x, -y - a1*x - a3*z, z], check=False) + return E.point([x, -y - a1 * x - a3 * z, z], check=False) def _sub_(self, other): """ @@ -476,8 +477,7 @@ def __bool__(self): return bool(self[2]) -class EllipticCurvePoint_field(EllipticCurvePoint, - SchemeMorphism_point_abelian_variety_field): +class EllipticCurvePoint_field(EllipticCurvePoint, SchemeMorphism_point_abelian_variety_field): """ A point on an elliptic curve over a field. The point has coordinates in the base field. @@ -562,6 +562,7 @@ class EllipticCurvePoint_field(EllipticCurvePoint, sage: P.codomain() == P.curve() # needs sage.rings.number_field True """ + def __init__(self, curve, v, check=True): """ Constructor for a point on an elliptic curve. @@ -736,9 +737,9 @@ def __pari__(self): sage: pari(E).elladd(O, P) [Mod(1, 11), Mod(2, 11)] """ - x,y,z = self._coords + x, y, z = self._coords if z: - return pari([x/z, y/z]) + return pari([x / z, y / z]) return pari([0]) def order(self, algorithm=None): @@ -829,12 +830,8 @@ def _compute_order(self, algorithm): lb = ub + 1 sqrt_ub *= 4 elif algorithm is None: - raise NotImplementedError( - "default algorithm not available for order of a point on " - "an elliptic curve over general fields; you may try algorithm=generic_small " - "if you are sure the order is finite and small") - raise NotImplementedError(f"algorithm {algorithm!r} not implemented for " - "order of a point on an elliptic curve over general fields") + raise NotImplementedError("default algorithm not available for order of a point on " "an elliptic curve over general fields; you may try algorithm=generic_small " "if you are sure the order is finite and small") + raise NotImplementedError(f"algorithm {algorithm!r} not implemented for " "order of a point on an elliptic curve over general fields") additive_order = order @@ -942,12 +939,12 @@ def has_order(self, n) -> bool: sage: E(0).has_order(Factorization([])) True """ - if hasattr(self, '_order'): # already known + if hasattr(self, '_order'): # already known if not isinstance(n, Integer): n = n.value() return self._order == n ret = generic.has_order(self, n, operation='+') - if ret and not hasattr(self, '_order'): # known now; cache + if ret and not hasattr(self, '_order'): # known now; cache if not isinstance(n, Integer): n = n.value() self._order = n @@ -1097,18 +1094,18 @@ def _add_(self, other): x1, y1 = self.xy() x2, y2 = other.xy() - if x1 == x2 and y1 == -y2 - a1*x2 - a3: + if x1 == x2 and y1 == -y2 - a1 * x2 - a3: return E(0) # point at infinity try: if x1 == x2 and y1 == y2: - m = (3*x1*x1 + 2*a2*x1 + a4 - a1*y1) / (2*y1 + a1*x1 + a3) + m = (3 * x1 * x1 + 2 * a2 * x1 + a4 - a1 * y1) / (2 * y1 + a1 * x1 + a3) else: m = (y1 - y2) / (x1 - x2) except ZeroDivisionError as ex: try: - d = next(d for d in (x1 - x2, 2*y1 + a1*x1 + a3) if d and not d.is_unit()) - m, = d.parent().defining_ideal().gens() + d = next(d for d in (x1 - x2, 2 * y1 + a1 * x1 + a3) if d and not d.is_unit()) + (m,) = d.parent().defining_ideal().gens() f1 = d.lift().gcd(m) f2 = m // f1 assert m == f1 * f2 @@ -1117,8 +1114,8 @@ def _add_(self, other): else: raise ZeroDivisionError(f'Inverse of {d} does not exist (characteristic = {m} = {f1}*{f2})') - x3 = -x1 - x2 - a2 + m*(m+a1) - y3 = -y1 - a3 - a1*x3 + m*(x1-x3) + x3 = -x1 - x2 - a2 + m * (m + a1) + y3 = -y1 - a3 - a1 * x3 + m * (x1 - x3) # See trac #4820 for why we need to coerce 1 into the base ring here: return E.point([x3, y3, E.base_ring().one()], check=False) @@ -1151,7 +1148,7 @@ def _neg_(self): return self E, x, y = self.curve(), self[0], self[1] # See trac #4820 for why we need to coerce 1 into the base ring here: - return E.point([x, -y - E.a1()*x - E.a3(), E.base_ring().one()], check=False) + return E.point([x, -y - E.a1() * x - E.a3(), E.base_ring().one()], check=False) def xy(self): """ @@ -1173,7 +1170,7 @@ def xy(self): """ if self[2].is_one(): return self[0], self[1] - return self[0]/self[2], self[1]/self[2] + return self[0] / self[2], self[1] / self[2] def x(self): """ @@ -1195,7 +1192,7 @@ def x(self): """ if self[2].is_one(): return self[0] - return self[0]/self[2] + return self[0] / self[2] def y(self): """ @@ -1217,7 +1214,7 @@ def y(self): """ if self[2].is_one(): return self[1] - return self[1]/self[2] + return self[1] / self[2] def is_divisible_by(self, m): """ @@ -1320,7 +1317,7 @@ def is_divisible_by(self, m): except NotImplementedError: pass - P_is_2_torsion = (P == -P) + P_is_2_torsion = P == -P g = P.division_points(m, poly_only=True) if not P_is_2_torsion: @@ -1498,7 +1495,7 @@ def division_points(self, m, poly_only=False): m = Integer(m) # Check for trivial cases of m = 1, -1 and 0. if m == 1 or m == -1: - return [m*self] + return [m * self] if m == 0: if self == 0: # then every point Q is a solution, but... return [self] @@ -1515,7 +1512,7 @@ def division_points(self, m, poly_only=False): E = self.curve() P = self nP = -P - P_is_2_torsion = (P == nP) + P_is_2_torsion = P == nP # If self is the 0, then self is a solution, and the correct # poly is the m'th division polynomial @@ -1524,7 +1521,7 @@ def division_points(self, m, poly_only=False): g = E.division_polynomial(m) else: # The poly g here is 0 at x(Q) iff x(m*Q) = x(P). - g = E._multiple_x_numerator(m) - P[0]*E._multiple_x_denominator(m) + g = E._multiple_x_numerator(m) - P[0] * E._multiple_x_denominator(m) # When 2*P=0, then -Q is a solution iff Q is. For even m, # no 2-torsion point is a solution, so that g is the @@ -1537,18 +1534,18 @@ def division_points(self, m, poly_only=False): if P_is_2_torsion: if m % 2 == 0: # This computes g.sqrt() which is not implemented - g = g.gcd(g.derivative())*g.leading_coefficient().sqrt() + g = g.gcd(g.derivative()) * g.leading_coefficient().sqrt() - # When 2*P!=0, then for each solution Q to m*Q=P, -Q is - # not a solution (and points of order 2 are not - # solutions). Hence the roots of g are distinct and each - # gives rise to precisely one solution Q. + # When 2*P!=0, then for each solution Q to m*Q=P, -Q is + # not a solution (and points of order 2 are not + # solutions). Hence the roots of g are distinct and each + # gives rise to precisely one solution Q. else: g0 = g.variables()[0] - P[0] g = g // g0 - g = g.gcd(g.derivative())*g.leading_coefficient().sqrt() - g = g0*g + g = g.gcd(g.derivative()) * g.leading_coefficient().sqrt() + g = g0 * g if poly_only: return g @@ -1558,7 +1555,7 @@ def division_points(self, m, poly_only=False): # Make a point on the curve with this x coordinate. Q = E.lift_x(x) nQ = -Q - mQ = m*Q + mQ = m * Q # if P==-P then Q works iff -Q works, so we include # both unless they are equal: if P_is_2_torsion: @@ -1908,6 +1905,7 @@ def set_order(self, value=None, *, multiple=None, check=True): return from sage.groups.generic import order_from_multiple + value = order_from_multiple(self, multiple, check=check) check = False @@ -1994,15 +1992,15 @@ def _line_(self, R, Q): elif self != R: if self[0] == R[0]: return Q[0] - self[0] - l = (R[1] - self[1])/(R[0] - self[0]) + l = (R[1] - self[1]) / (R[0] - self[0]) return Q[1] - self[1] - l * (Q[0] - self[0]) else: a1, a2, a3, a4, a6 = self.curve().a_invariants() - numerator = (3*self[0]**2 + 2*a2*self[0] + a4 - a1*self[1]) - denominator = (2*self[1] + a1*self[0] + a3) + numerator = 3 * self[0] ** 2 + 2 * a2 * self[0] + a4 - a1 * self[1] + denominator = 2 * self[1] + a1 * self[0] + a3 if denominator == 0: return Q[0] - self[0] - l = numerator/denominator + l = numerator / denominator return Q[1] - self[1] - l * (Q[0] - self[0]) def _miller_(self, Q, n): @@ -2169,21 +2167,21 @@ def _miller_(self, Q, n): nbin = n.bits() i = n.nbits() - 2 while i > -1: - S = 2*V + S = 2 * V ell = V._line_(V, Q) vee = S._line_(-S, Q) - t = (t**2)*(ell/vee) + t = (t**2) * (ell / vee) V = S if nbin[i] == 1: - S = V+self + S = V + self ell = V._line_(self, Q) vee = S._line_(-S, Q) - t = t*(ell/vee) + t = t * (ell / vee) V = S - i = i-1 + i = i - 1 if n_is_negative: vee = V._line_(-V, Q) - t = 1/(t*vee) + t = 1 / (t * vee) return t def weil_pairing(self, Q, n, algorithm=None): @@ -2319,7 +2317,7 @@ def weil_pairing(self, Q, n, algorithm=None): algorithm = 'sage' if algorithm == 'pari': - if pari.ellmul(E,P,n) != [0] or pari.ellmul(E,Q,n) != [0]: + if pari.ellmul(E, P, n) != [0] or pari.ellmul(E, Q, n) != [0]: raise ValueError("points must both be n-torsion") return E.base_field()(pari.ellweilpairing(E, P, Q, n)) @@ -2327,7 +2325,7 @@ def weil_pairing(self, Q, n, algorithm=None): raise ValueError('unknown algorithm') # Test if P, Q are both in E[n] - if n*P or n*Q: + if n * P or n * Q: raise ValueError("points must both be n-torsion") one = E.base_field().one() @@ -2369,7 +2367,7 @@ def weil_pairing(self, Q, n, algorithm=None): # n = d try: - return ((-1)**n.test_bit(0))*(P._miller_(Q, n)/Q._miller_(P, n)) + return ((-1) ** n.test_bit(0)) * (P._miller_(Q, n) / Q._miller_(P, n)) except ZeroDivisionError: return one @@ -2570,7 +2568,7 @@ def tate_pairing(self, Q, n, k, q=None): else: raise ValueError("Unexpected field degree: set keyword argument q equal to the size of the base field (big field is GF(q^%s))." % k) # The user has supplied q, so we check here that it's a sensible value - elif Mod(q, n)**k != 1: + elif Mod(q, n) ** k != 1: raise ValueError("n does not divide (q^k - 1) for the supplied value of q") if pari.ellmul(E, P, n) != [0]: @@ -2582,7 +2580,7 @@ def tate_pairing(self, Q, n, k, q=None): if isinstance(E, sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field): # The value returned by `elltatepairing` is the raw Miller loop # output, so we still need to do the final exponentiation. - ePQ = K(pari.elltatepairing(E, P, Q, n)) # Cast the PARI type back to the base ring + ePQ = K(pari.elltatepairing(E, P, Q, n)) # Cast the PARI type back to the base ring else: # In small cases, or in the case of pairing an element with # itself, Q could be on one of the lines in the Miller @@ -2594,7 +2592,7 @@ def tate_pairing(self, Q, n, k, q=None): R = E.random_point() return self.tate_pairing(Q + R, n, k) / self.tate_pairing(R, n, k) - exp = Integer((q**k - 1)/n) + exp = Integer((q**k - 1) / n) return ePQ**exp def ate_pairing(self, Q, n, k, t, q=None): @@ -2789,22 +2787,22 @@ def ate_pairing(self, Q, n, k, t, q=None): raise ValueError("Unexpected field degree: set keyword argument q equal to the size of the base field (big field is GF(q^%s))." % k) # check order of P - if n*P != O: + if n * P != O: raise ValueError('This point %s is not of order n=%s' % (P, n)) # check for P in kernel pi - 1: - piP = E(P[0]**q, P[1]**q) + piP = E(P[0] ** q, P[1] ** q) if piP - P != O: raise ValueError('This point %s is not in Ker(pi - 1)' % P) # check for Q in kernel pi - q: - piQ = E(Q[0]**q, Q[1]**q) - if piQ - q*Q != O: + piQ = E(Q[0] ** q, Q[1] ** q) + if piQ - q * Q != O: raise ValueError('Point %s not in Ker(pi - q)' % Q) - T = t-1 + T = t - 1 ret = Q._miller_(P, T) - e = Integer((q**k - 1)/n) + e = Integer((q**k - 1) / n) ret = ret**e return ret @@ -2849,6 +2847,7 @@ def point_of_jacobian_of_curve(self): True """ from sage.schemes.curves.constructor import Curve + C = self.curve() A = C.ambient_space() # projective plane x, y, z = self @@ -2856,14 +2855,14 @@ def point_of_jacobian_of_curve(self): X = Curve(C.defining_ideal().gens(), A) X = X.affine_patch(2).projective_closure() F = X.function_field() - P = X(z,x,y).place() + P = X(z, x, y).place() Pinf = F.places_infinite()[0] assert Pinf.degree() == 1, "no rational point at infinity" - J = X.jacobian(model='hess', base_div=F.genus()*Pinf) + J = X.jacobian(model='hess', base_div=F.genus() * Pinf) G = J.group(self.base_ring()) - return G(P - P.degree()*Pinf) + return G(P - P.degree() * Pinf) class EllipticCurvePoint_number_field(EllipticCurvePoint_field): @@ -3002,7 +3001,7 @@ def _compute_order(self, algorithm): N = E._torsion_bound() # Now self is a torsion point iff it is killed by N: - if not (N*self).is_zero(): + if not (N * self).is_zero(): return oo # Finally we find the exact order using the generic code: @@ -3116,6 +3115,7 @@ def _has_order_at_least(self, bound, *, attempts=999): from sage.sets.primes import Primes from sage.rings.finite_rings.finite_field_constructor import GF + field_deg = self.curve().base_field().absolute_degree() if field_deg > 1: K = self.curve().base_field().absolute_field('T') @@ -3138,10 +3138,10 @@ def _has_order_at_least(self, bound, *, attempts=999): no_progress = 0 for p in Primes(): try: - f,_ = K.defining_polynomial().change_ring(GF(p)).factor()[0] + f, _ = K.defining_polynomial().change_ring(GF(p)).factor()[0] except ZeroDivisionError: continue - F = GF(p).extension(f,'t') + F = GF(p).extension(f, 't') red = lambda elt: F(f.parent()(poly(elt)).change_ring(GF(p)) % f) try: @@ -3212,7 +3212,7 @@ def is_on_identity_component(self, embedding=None): sage: e1 < e2 < e3 and e(P[0]) < e3 True """ - if self.is_zero(): # trivial case + if self.is_zero(): # trivial case return True e = embedding @@ -3240,7 +3240,7 @@ def is_on_identity_component(self, embedding=None): gx = E.two_division_polynomial() gxd = gx.derivative() gxdd = gxd.derivative() - return (e(gxd(self[0])) > 0 and e(gxdd(self[0])) > 0) + return e(gxd(self[0])) > 0 and e(gxdd(self[0])) > 0 def has_good_reduction(self, P=None) -> bool: r""" @@ -3314,15 +3314,15 @@ def has_good_reduction(self, P=None) -> bool: sage: P.has_good_reduction(p) # needs sage.rings.number_field True """ - if self.is_zero(): # trivial case + if self.is_zero(): # trivial case return True E = self.curve() if P is None: - return all(self.has_good_reduction(Pr) - for Pr in E.discriminant().support()) + return all(self.has_good_reduction(Pr) for Pr in E.discriminant().support()) K = E.base_field() from sage.schemes.elliptic_curves.ell_local_data import check_prime + P = check_prime(K, P) # If the curve has good reduction at P, the result is True: @@ -3344,7 +3344,7 @@ def has_good_reduction(self, P=None) -> bool: else: pi = K.uniformizer(P) pie = pi**e - xyz = [c/pie for c in xyz] + xyz = [c / pie for c in xyz] # Evaluate the partial derivatives at the point to see if they # are zero mod P @@ -3683,8 +3683,7 @@ def height(self, precision=None, normalised=True, algorithm='pari'): h = Emin.pari_curve().ellheight(P, precision=precision) height = RealField(precision)(h) else: - height = (self.non_archimedean_local_height(prec=precision) - + self.archimedean_local_height(prec=precision)) + height = self.non_archimedean_local_height(prec=precision) + self.archimedean_local_height(prec=precision) # The cached height is the one that is independent of the base field. self.__height = height @@ -3821,14 +3820,11 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): prec = 53 if K is QQ: v = K.embeddings(RR)[0] - h = self.archimedean_local_height(v, prec+10) + h = self.archimedean_local_height(v, prec + 10) else: r1, r2 = K.signature() pl = K.places() - h = (sum(self.archimedean_local_height(pl[i], prec+10, weighted=False) - for i in range(r1)) - + 2 * sum(self.archimedean_local_height(pl[i], prec+10, weighted=False) - for i in range(r1, r1 + r2))) + h = sum(self.archimedean_local_height(pl[i], prec + 10, weighted=False) for i in range(r1)) + 2 * sum(self.archimedean_local_height(pl[i], prec + 10, weighted=False) for i in range(r1, r1 + r2)) if not weighted: h /= K.degree() return RealField(prec)(h) @@ -3851,7 +3847,7 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): if D.abs().real_number(RealField()).round(): extra_prec = 100 else: # then |D| is small - extra_prec = 10 + (1/D).abs().real_number(RealField()).round().nbits() + extra_prec = 10 + (1 / D).abs().real_number(RealField()).round().nbits() working_prec = prec + extra_prec RC = RealField(working_prec) if v_is_real else ComplexField(working_prec) @@ -3871,26 +3867,26 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): # up. The rest of the expression was wrongly transcribed in # Sage versions <5.6 (see #12509). - H = max(RC(4).abs(), b2.abs(), 2*b4.abs(), 2*b6.abs(), b8.abs()) + H = max(RC(4).abs(), b2.abs(), 2 * b4.abs(), 2 * b6.abs(), b8.abs()) absdisc = RC(v_inf(E.discriminant())).abs() adl3 = 0 if absdisc >= 1 else absdisc.log() / 3 - nterms = int(math.ceil(0.51*working_prec + 0.5 + 0.75 * (7 + 4*H.log()/3 - adl3).log())) + nterms = int(math.ceil(0.51 * working_prec + 0.5 + 0.75 * (7 + 4 * H.log() / 3 - adl3).log())) b2p = b2 - 12 b4p = b4 - b2 + 6 - b6p = b6 - 2*b4 + b2 - 4 - b8p = b8 - 3*b6 + 3*b4 - b2 + 3 + b6p = b6 - 2 * b4 + b2 - 4 + b8p = b8 - 3 * b6 + 3 * b4 - b2 + 3 - fz = lambda T: 1 - T**2 * (b4 + T*(2*b6 + T*b8)) - fzp = lambda T: 1 - T**2 * (b4p + T*(2*b6p + T*b8p)) - fw = lambda T: T*(4 + T*(b2 + T*(2*b4 + T*b6))) - fwp = lambda T: T*(4 + T*(b2p + T*(2*b4p + T*b6p))) + fz = lambda T: 1 - T**2 * (b4 + T * (2 * b6 + T * b8)) + fzp = lambda T: 1 - T**2 * (b4p + T * (2 * b6p + T * b8p)) + fw = lambda T: T * (4 + T * (b2 + T * (2 * b4 + T * b6))) + fwp = lambda T: T * (4 + T * (b2p + T * (2 * b4p + T * b6p))) - if abs(x) >= .5: - t = 1/x + if abs(x) >= 0.5: + t = 1 / x beta = True else: - t = 1/(x+1) + t = 1 / (x + 1) beta = False lam = -t.abs().log() mu = 0 @@ -3902,30 +3898,29 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): z = fz(t) if abs(w) <= 2 * z.abs(): mu += four_to_n * z.abs().log() - t = w/z + t = w / z else: - mu += four_to_n * (z+w).abs().log() - t = w/(z+w) + mu += four_to_n * (z + w).abs().log() + t = w / (z + w) beta = not beta else: w = fwp(t) z = fzp(t) if abs(w) <= 2 * z.abs(): mu += four_to_n * z.abs().log() - t = w/z + t = w / z else: - mu += four_to_n * (z-w).abs().log() - t = w/(z-w) + mu += four_to_n * (z - w).abs().log() + t = w / (z - w) beta = not beta four_to_n >>= 2 - h = RealField(prec)(lam + mu/4) + h = RealField(prec)(lam + mu / 4) if weighted and not v_is_real: h *= 2 return h - def non_archimedean_local_height(self, v=None, prec=None, - weighted=False, is_minimal=None): + def non_archimedean_local_height(self, v=None, prec=None, weighted=False, is_minimal=None): """ Compute the local height of ``self`` at non-archimedean places. @@ -4068,22 +4063,14 @@ def non_archimedean_local_height(self, v=None, prec=None, c = self[0].denominator() # The last sum is for bad primes that divide c where # the model is not minimal. - h = (log(c) - + sum(self.non_archimedean_local_height(p, prec, weighted=True, is_minimal=(e < 12)) - for p, e in factorD if not p.divides(c)) - + sum(self.non_archimedean_local_height(p, prec, weighted=True) - - c.valuation(p) * log(p) - for p, e in factorD if e >= 12 and c.valuation(p))) + h = log(c) + sum(self.non_archimedean_local_height(p, prec, weighted=True, is_minimal=(e < 12)) for p, e in factorD if not p.divides(c)) + sum(self.non_archimedean_local_height(p, prec, weighted=True) - c.valuation(p) * log(p) for p, e in factorD if e >= 12 and c.valuation(p)) else: factorD = K.factor(D) if self[0] == 0: c = K.ideal(1) else: c = K.ideal(self[0]).denominator() - h = (log(c.norm()) - + sum(self.non_archimedean_local_height(v, prec, weighted=True) - - c.valuation(v) * log(v.norm()) - for v, e in factorD)) + h = log(c.norm()) + sum(self.non_archimedean_local_height(v, prec, weighted=True) - c.valuation(v) * log(v.norm()) for v, e in factorD) if not weighted: h /= K.degree() return h @@ -4097,7 +4084,7 @@ def non_archimedean_local_height(self, v=None, prec=None, P = self.curve().isomorphism_to(E)(self) # Silverman's normalization is not invariant under change of model, # but it all cancels out in the global height. - offset = (self.curve().discriminant()/E.discriminant()).valuation(v) + offset = (self.curve().discriminant() / E.discriminant()).valuation(v) a1, a2, a3, a4, a6 = E.a_invariants() b2, b4, b6, b8 = E.b_invariants() @@ -4105,19 +4092,19 @@ def non_archimedean_local_height(self, v=None, prec=None, x, y = P.xy() D = E.discriminant() N = D.valuation(v) - A = (3*x**2 + 2*a2*x + a4 - a1*y).valuation(v) - B = (2*y+a1*x+a3).valuation(v) - C = (3*x**4 + b2*x**3 + 3*b4*x**2 + 3*b6*x + b8).valuation(v) + A = (3 * x**2 + 2 * a2 * x + a4 - a1 * y).valuation(v) + B = (2 * y + a1 * x + a3).valuation(v) + C = (3 * x**4 + b2 * x**3 + 3 * b4 * x**2 + 3 * b6 * x + b8).valuation(v) if A <= 0 or B <= 0: r = max(0, -x.valuation(v)) elif c4.valuation(v) == 0: - n = min(B, N/2) - r = -n*(N-n)/N - elif C >= 3*B: - r = -2*B/3 + n = min(B, N / 2) + r = -n * (N - n) / N + elif C >= 3 * B: + r = -2 * B / 3 else: - r = -C/4 - r -= offset/6 + r = -C / 4 + r -= offset / 6 if not r: return QQ.zero() if E.base_ring() is QQ: @@ -4128,8 +4115,7 @@ def non_archimedean_local_height(self, v=None, prec=None, r = r / (v.ramification_index() * v.residue_class_degree()) return r * log(Nv) - def elliptic_logarithm(self, embedding=None, precision=100, - algorithm='pari'): + def elliptic_logarithm(self, embedding=None, precision=100, algorithm='pari'): r""" Return the elliptic logarithm of this elliptic curve point. @@ -4278,7 +4264,7 @@ def elliptic_logarithm(self, embedding=None, precision=100, E = self.curve() K = E.base_field() - rational = (K is QQ) + rational = K is QQ emb = embedding if emb is None: @@ -4306,10 +4292,10 @@ def elliptic_logarithm(self, embedding=None, precision=100, # RealField(precision). We interface with the PARI library. x, y = self.xy() - if rational: # work with exact coordinates + if rational: # work with exact coordinates E_work = E pt_pari = pari([x, y]) - else: # use the embedding to get real coordinates + else: # use the embedding to get real coordinates ai = [emb(a) for a in E.a_invariants()] E_work = EllipticCurve(ai) # defined over RR pt_pari = pari([emb(x), emb(y)]) @@ -4322,7 +4308,7 @@ def elliptic_logarithm(self, embedding=None, precision=100, # precision. if the base field is not QQ, this # requires modifying the precision of the embedding, # the curve, and the point - working_prec = 2*working_prec + working_prec = 2 * working_prec if not rational: emb = refine_embedding(emb, working_prec) ai = [emb(a) for a in E.a_invariants()] @@ -4334,13 +4320,13 @@ def elliptic_logarithm(self, embedding=None, precision=100, # normalization step r, i = C(log_pari) wR, wI = L.basis(prec=precision) - k = (r/wR).floor() + k = (r / wR).floor() if k: - r -= k*wR + r -= k * wR if self.is_on_identity_component(emb): return C(r) # Now there are two components and P is on the non-identity one - return C(r)+C(wI/2) + return C(r) + C(wI / 2) def padic_elliptic_logarithm(self, p, absprec=20): r""" @@ -4427,24 +4413,23 @@ def padic_elliptic_logarithm(self, p, absprec=20): Q_p = Qp(p, absprec) if debug: print("x,y=", (x, y)) - f = 1 # f will be such that f*P is in the formal group E^1(Q_p) - if x.valuation() >= 0: # P is not in E^1 - if not self.has_good_reduction(p): # P is not in E^0 - n = E.tamagawa_exponent(p) # n*P has good reduction at p + f = 1 # f will be such that f*P is in the formal group E^1(Q_p) + if x.valuation() >= 0: # P is not in E^1 + if not self.has_good_reduction(p): # P is not in E^0 + n = E.tamagawa_exponent(p) # n*P has good reduction at p if debug: print("Tamagawa exponent = =", n) f = n - P = n*P # lies in E^0 + P = n * P # lies in E^0 if debug: print("P=", P) try: x, y = P.xy() except ZeroDivisionError: - raise ValueError("Insufficient precision in " - "p-adic_elliptic_logarithm()") + raise ValueError("Insufficient precision in " "p-adic_elliptic_logarithm()") if debug: print("x,y=", (x, y)) - if x.valuation() >= 0: # P is still not in E^1 + if x.valuation() >= 0: # P is still not in E^1 t = E.local_data(p).bad_reduction_type() if t is None: m = E.reduction(p).abelian_group().exponent() @@ -4455,36 +4440,34 @@ def padic_elliptic_logarithm(self, p, absprec=20): # now m*(n*P) reduces to the identity mod p, so is # in E^1(Q_p) f *= m - P = m*P # lies in E^1 + P = m * P # lies in E^1 try: x, y = P.xy() except ZeroDivisionError: - raise ValueError("Insufficient precision in " - "p-adic_elliptic_logarithm()") + raise ValueError("Insufficient precision in " "p-adic_elliptic_logarithm()") if debug: print("f=", f) print("x,y=", (x, y)) vx = x.valuation() vy = y.valuation() - v = vx-vy - if not (v > 0 and vx == -2*v and vy == -3*v): - raise ValueError("Insufficient precision in " - "p-adic_elliptic_logarithm()") + v = vx - vy + if not (v > 0 and vx == -2 * v and vy == -3 * v): + raise ValueError("Insufficient precision in " "p-adic_elliptic_logarithm()") try: - t = -x/y + t = -x / y except (ZeroDivisionError, PrecisionError): - raise ValueError("Insufficient precision in " - "p-adic_elliptic_logarithm()") + raise ValueError("Insufficient precision in " "p-adic_elliptic_logarithm()") if debug: print("t=", t, ", with valuation ", v) - phi = Ep.formal().log(prec=1+absprec//v) - return phi(t)/f + phi = Ep.formal().log(prec=1 + absprec // v) + return phi(t) / f class EllipticCurvePoint_finite_field(EllipticCurvePoint_field): r""" Class for elliptic curve points over finite fields. """ + def _magma_init_(self, magma): """ Return a string representation of ``self`` that ``MAGMA`` can @@ -4531,10 +4514,8 @@ def _acted_upon_(self, other, side): a = val.lift() N = val.mod() N1 = N.gcd(a) - N2 = N//N1 - raise ZeroDivisionError( - f"Inverse of {a} does not exist" - f" (characteristic = {N} = {N1}*{N2})") + N2 = N // N1 + raise ZeroDivisionError(f"Inverse of {a} does not exist" f" (characteristic = {N} = {N1}*{N2})") pariQ = None if pariQ is not None: @@ -4708,32 +4689,32 @@ def log(self, base): w = P1.weil_pairing(self, n) x0, y0 = v.log(z, o), w.log(z, o) - T = self - x0*P1 - y0*P2 + T = self - x0 * P1 - y0 * P2 if not T: return x0, y0 - T1 = n//n1 * T - T2 = n//n2 * T + T1 = n // n1 * T + T2 = n // n2 * T T1.set_order(multiple=n1, check=False) T2.set_order(multiple=n2, check=False) - x1 = T1.log(o*P1) - y1 = T2.log(o*P2) + x1 = T1.log(o * P1) + y1 = T2.log(o * P2) -# assert n//n1 * self == (x1*o + n//n1*x0) * P1 + n//n1*y0 * P2 -# assert n//n2 * self == n//n2*x0 * P1 + (y1*o + n//n2*y0) * P2 + # assert n//n1 * self == (x1*o + n//n1*x0) * P1 + n//n1*y0 * P2 + # assert n//n2 * self == n//n2*x0 * P1 + (y1*o + n//n2*y0) * P2 - _,u,v = (n//n1).xgcd(n//n2) + _, u, v = (n // n1).xgcd(n // n2) assert _.is_one() - x = (u * (x1*o + n//n1*x0) + v * (n//n2*x0)) % n1 - y = (u * (n//n1*y0) + v * (y1*o + n//n2*y0)) % n2 + x = (u * (x1 * o + n // n1 * x0) + v * (n // n2 * x0)) % n1 + y = (u * (n // n1 * y0) + v * (y1 * o + n // n2 * y0)) % n2 -# assert x*P1 + y*P2 == self + # assert x*P1 + y*P2 == self return x, y if base not in self.parent(): raise ValueError('not a point on the same curve') n = base.order() - if (hasattr(self, '_order') and not self._order.divides(n)) or n*self: + if (hasattr(self, '_order') and not self._order.divides(n)) or n * self: raise ValueError('ECDLog problem has no solution (order does not divide order of base)') E = self.curve() F = E.base_ring() @@ -4743,7 +4724,7 @@ def log(self, base): # Anomalous case return base.padic_elliptic_logarithm(self, p) if hasattr(E, '_order') and E._order.gcd(n**2) == n: - pass # cyclic rational n-torsion -> okay + pass # cyclic rational n-torsion -> okay elif base.weil_pairing(self, n) != 1: raise ValueError('ECDLog problem has no solution (non-trivial Weil pairing)') @@ -4824,14 +4805,14 @@ def padic_elliptic_logarithm(self, Q, p): pP = p * P_Qp pQ = p * Q_Qp - if (pP.is_zero() or pQ.is_zero()): + if pP.is_zero() or pQ.is_zero(): # Should happen with probability 1/p continue else: break - x_P,y_P = pP.xy() - x_Q,y_Q = pQ.xy() + x_P, y_P = pP.xy() + x_Q, y_Q = pQ.xy() phi_P = -(x_P / y_P) phi_Q = -(x_Q / y_Q) @@ -5001,7 +4982,6 @@ def _compute_order(self, algorithm): if algorithm in ('generic_small', 'hybrid'): return super()._compute_order(algorithm) - raise NotImplementedError(f"algorithm {algorithm!r} not implemented for " - "order of a point on an elliptic curve over finite fields") + raise NotImplementedError(f"algorithm {algorithm!r} not implemented for " "order of a point on an elliptic curve over finite fields") additive_order = order diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index 780dc2e563a..2e6d7c6ce3e 100644 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -107,9 +107,7 @@ # CMJ is a dict of pairs (j,D) where j is a rational CM j-invariant # and D is the corresponding quadratic discriminant -CMJ = { 0: -3, 54000: -12, -12288000: -27, 1728: -4, 287496: -16, - -3375: -7, 16581375: -28, 8000: -8, -32768: -11, -884736: -19, - -884736000: -43, -147197952000: -67, -262537412640768000: -163} +CMJ = {0: -3, 54000: -12, -12288000: -27, 1728: -4, 287496: -16, -3375: -7, 16581375: -28, 8000: -8, -32768: -11, -884736: -19, -884736000: -43, -147197952000: -67, -262537412640768000: -163} class EllipticCurve_rational_field(EllipticCurve_number_field): @@ -150,6 +148,7 @@ class EllipticCurve_rational_field(EllipticCurve_number_field): sage: EllipticCurve('462.f3') Elliptic Curve defined by y^2 + x*y = x^3 - 363*x + 1305 over Rational Field """ + def __init__(self, ainvs, **kwds): r""" Constructor for the EllipticCurve_rational_field class. @@ -355,6 +354,7 @@ def lmfdb_page(self): sage: E.lmfdb_page() # optional -- webbrowser """ import webbrowser + lmfdb_url = 'http://www.lmfdb.org/EllipticCurve/Q/{}' if hasattr(self, "_lmfdb_label") and self._lmfdb_label: url = lmfdb_url.format(self._lmfdb_label) @@ -479,6 +479,7 @@ def mwrank(self, options=''): from sage.interfaces.mwrank import mwrank else: from sage.interfaces.mwrank import Mwrank + mwrank = Mwrank(options=options) return mwrank(list(self.a_invariants())) @@ -571,8 +572,7 @@ def conductor(self, algorithm='pari'): N3 = self.conductor("gp") N4 = self.conductor("generic") if N1 != N2 or N2 != N3 or N2 != N4: - raise ArithmeticError("PARI, mwrank, gp and Sage compute different conductors (%s,%s,%s,%s) for %s" % ( - N1, N2, N3, N4, self)) + raise ArithmeticError("PARI, mwrank, gp and Sage compute different conductors (%s,%s,%s,%s) for %s" % (N1, N2, N3, N4, self)) return N1 else: raise ValueError("algorithm %r is not known" % algorithm) @@ -760,7 +760,7 @@ def Np(self, p): """ if self.conductor() % p == 0: return p + 1 - self.ap(p) - return p+1 - self.ap(p) + return p + 1 - self.ap(p) #################################################################### # Access to mwrank @@ -789,15 +789,11 @@ def mwrank_curve(self, verbose=False): except AttributeError: pass from sage.libs.eclib.all import mwrank_EllipticCurve + self.__mwrank_curve = mwrank_EllipticCurve(self.ainvs(), verbose=verbose) return self.__mwrank_curve - def two_descent(self, verbose=True, - selmer_only=False, - first_limit=20, - second_limit=8, - n_aux=-1, - second_descent=1): + def two_descent(self, verbose=True, selmer_only=False, first_limit=20, second_limit=8, n_aux=-1, second_descent=1): r""" Compute 2-descent data for this curve. @@ -847,9 +843,7 @@ def two_descent(self, verbose=True, """ verbose_verbose("Calling mwrank C++ library.") C = self.mwrank_curve() - C.two_descent(verbose, selmer_only, - first_limit, second_limit, - n_aux, second_descent) + C.two_descent(verbose, selmer_only, first_limit, second_limit, n_aux, second_descent) if C.certain(): gens = sorted(self.point(x, check=True) for x in C.gens()) self.__gens = (gens, True) @@ -1025,7 +1019,7 @@ def modular_form(self): try: return self.__modular_form except AttributeError: - M = sage.modular.modform.constructor.ModularForms(self.conductor(),weight=2) + M = sage.modular.modform.constructor.ModularForms(self.conductor(), weight=2) f = sage.modular.modform.element.ModularFormElement_elliptic_curve(M, self) self.__modular_form = f return f @@ -1097,11 +1091,11 @@ def _modular_symbol_normalize(self, sign, normalize, implementation, nap): sage: E.modular_symbol(implementation = 'eclib') is E.modular_symbol(implementation = 'eclib', normalize = 'L_ratio') True """ - if sign not in [1,-1]: + if sign not in [1, -1]: raise ValueError("The sign of a modular symbol must be 1 or -1") sign = ZZ(sign) if implementation == 'eclib' and nap == 0: - nap = min(100*self.conductor().isqrt(), 10000) + nap = min(100 * self.conductor().isqrt(), 10000) if normalize is None: normalize = "L_ratio" if normalize not in ["L_ratio", "period", "none"]: @@ -1303,8 +1297,9 @@ def modular_symbol(self, sign=+1, normalize=None, implementation='eclib', nap=0) M = ell_modular_symbols.ModularSymbolECLIB(self, sign, nap) elif implementation == 'sage': M = ell_modular_symbols.ModularSymbolSage(self, sign, normalize=normalize) - else: # implementation == "num": + else: # implementation == "num": from sage.schemes.elliptic_curves.mod_sym_num import ModularSymbolNumerical + M = ModularSymbolNumerical(self, sign) return M @@ -1363,10 +1358,12 @@ def modular_symbol_numerical(self, sign=1, prec=20): 2.00001004772210 """ from sage.schemes.elliptic_curves.mod_sym_num import ModularSymbolNumerical + M = ModularSymbolNumerical(self, sign=sign) def f(r): return M.approximative_value(r, prec=prec) + return f def pollack_stevens_modular_symbol(self, sign=0, implementation='eclib'): @@ -1399,7 +1396,7 @@ def pollack_stevens_modular_symbol(self, sign=0, implementation='eclib'): """ typ = (sign, implementation) try: - return self.__modular_symbol[typ] # Doesn't collide with original implementation because tuple is length two here. + return self.__modular_symbol[typ] # Doesn't collide with original implementation because tuple is length two here. except AttributeError: self.__modular_symbol = {} except KeyError: @@ -1540,6 +1537,7 @@ def analytic_rank(self, algorithm='pari', leading_coefficient=False): raise NotImplementedError("Cannot compute leading coefficient using rubinstein algorithm") try: from sage.lfunctions.lcalc import lcalc + return lcalc.analytic_rank(L=self) except TypeError as msg: raise RuntimeError("unable to compute analytic rank using rubinstein algorithm (%s)" % msg) @@ -1547,11 +1545,13 @@ def analytic_rank(self, algorithm='pari', leading_coefficient=False): if leading_coefficient: raise NotImplementedError("Cannot compute leading coefficient using sympow") from sage.lfunctions.sympow import sympow + return sympow.analytic_rank(self)[0] elif algorithm == 'magma': if leading_coefficient: raise NotImplementedError("Cannot compute leading coefficient using magma") from sage.interfaces.magma import magma + return Integer(magma(self).AnalyticRank()) elif algorithm == 'zero_sum': if leading_coefficient: @@ -1562,22 +1562,14 @@ def analytic_rank(self, algorithm='pari', leading_coefficient=False): if leading_coefficient: S = {self.analytic_rank('pari', True)} else: - S = {self.analytic_rank('pari'), - self.analytic_rank('rubinstein'), - self.analytic_rank('sympow')} + S = {self.analytic_rank('pari'), self.analytic_rank('rubinstein'), self.analytic_rank('sympow')} if len(S) != 1: raise RuntimeError("Bug in analytic_rank; algorithms don't agree! (E=%s)" % self) return list(S)[0] else: raise ValueError("algorithm %s not defined" % algorithm) - def analytic_rank_upper_bound(self, - max_Delta=None, - adaptive=True, - N=None, - root_number='compute', - bad_primes=None, - ncpus=None): + def analytic_rank_upper_bound(self, max_Delta=None, adaptive=True, N=None, root_number='compute', bad_primes=None, ncpus=None): r""" Return an upper bound for the analytic rank of ``self``, conditional on the Generalized Riemann Hypothesis, via computing @@ -1774,11 +1766,7 @@ def analytic_rank_upper_bound(self, from sage.lfunctions.zero_sums import LFunctionZeroSum_EllipticCurve Z = LFunctionZeroSum_EllipticCurve(self, N) - bound = Z.analytic_rank_upper_bound(max_Delta=max_Delta, - adaptive=adaptive, - root_number=root_number, - bad_primes=bad_primes, - ncpus=ncpus) + bound = Z.analytic_rank_upper_bound(max_Delta=max_Delta, adaptive=adaptive, root_number=root_number, bad_primes=bad_primes, ncpus=ncpus) return bound def three_selmer_rank(self, algorithm='UseSUnits'): @@ -1825,14 +1813,11 @@ def three_selmer_rank(self, algorithm='UseSUnits'): 2 """ from sage.interfaces.magma import magma + E = magma(self) return Integer(E.ThreeSelmerGroup(MethodForFinalStep=magma('"%s"' % algorithm)).Ngens()) - def rank(self, use_database=True, verbose=False, - only_use_mwrank=True, - algorithm='mwrank_lib', - proof=None, - pari_effort=0): + def rank(self, use_database=True, verbose=False, only_use_mwrank=True, algorithm='mwrank_lib', proof=None, pari_effort=0): r""" Return the rank of this elliptic curve, assuming no conjectures. @@ -1952,6 +1937,7 @@ def rank(self, use_database=True, verbose=False, """ if proof is None: from sage.structure.proof.proof import get_flag + proof = get_flag(proof, "elliptic_curve") else: proof = bool(proof) @@ -1983,7 +1969,7 @@ def rank(self, use_database=True, verbose=False, # Next try evaluate the L-function or its derivative at the # central point N = self.conductor() - prec = int(4*float(sqrt(N))) + 10 + prec = int(4 * float(sqrt(N))) + 10 if self.root_number() == 1: L, err = self.lseries().at1(prec) if abs(L) > err + R(0.0001): # definitely doesn't vanish @@ -2032,11 +2018,11 @@ def rank(self, use_database=True, verbose=False, verbose_verbose("Warning -- rank not proven correct", level=1) s = "lower bound of" - X = X[X.rfind(s)+len(s)+1:] + X = X[X.rfind(s) + len(s) + 1 :] rank = Integer(X.split()[0]) else: if proof is False: - proof = True #since we actually provably found the rank + proof = True # since we actually provably found the rank match = 'Rank =' i = X.find(match) if i == -1: @@ -2045,7 +2031,7 @@ def rank(self, use_database=True, verbose=False, if i == -1: raise RuntimeError("%s\nbug -- tried to find 'Rank =' or 'found points of rank' in mwrank output but couldn't." % X) j = i + X[i:].find('\n') - rank = Integer(X[i+len(match)+1:j]) + rank = Integer(X[i + len(match) + 1 : j]) self.__rank = (rank, proof) return rank @@ -2053,9 +2039,9 @@ def rank(self, use_database=True, verbose=False, ep = self.pari_curve() # if we know already some points in _known_points # we can give them to pari to speed it up - kpts = [ [x[0],x[1]] for x in self._known_points ] + kpts = [[x[0], x[1]] for x in self._known_points] lower, upper, s, pts = ep.ellrank(pari_effort, kpts) - ge = sorted([self.point([QQ(x[0]),QQ(x[1])], check=True) for x in pts]) + ge = sorted([self.point([QQ(x[0]), QQ(x[1])], check=True) for x in pts]) ge = self.saturation(ge)[0] self._known_points = ge # note that lower is only a conjectural @@ -2187,6 +2173,7 @@ def gens(self, proof=None, **kwds): """ if proof is None: from sage.structure.proof.proof import get_flag + proof = get_flag(proof, "elliptic_curve") else: proof = bool(proof) @@ -2203,15 +2190,7 @@ def gens(self, proof=None, **kwds): self._known_points = gens return list(gens) - def _compute_gens(self, proof, - verbose=False, - rank1_search=10, - algorithm='mwrank_lib', - only_use_mwrank=True, - use_database=True, - descent_second_limit=12, - sat_bound=1000, - pari_effort=0): + def _compute_gens(self, proof, verbose=False, rank1_search=10, algorithm='mwrank_lib', only_use_mwrank=True, use_database=True, descent_second_limit=12, sat_bound=1000, pari_effort=0): r""" Return generators for the Mordell-Weil group `E(Q)` *modulo* torsion. @@ -2295,9 +2274,9 @@ def _compute_gens(self, proof, ep = self.pari_curve() # if we know already some points in _known_points # we can give them to pari to speed it up - kpts = [ [x[0],x[1]] for x in self._known_points ] + kpts = [[x[0], x[1]] for x in self._known_points] lower, upper, s, pts = ep.ellrank(pari_effort, kpts) - ge = sorted([self.point([QQ(x[0]),QQ(x[1])], check=True) for x in pts]) + ge = sorted([self.point([QQ(x[0]), QQ(x[1])], check=True) for x in pts]) ge = self.saturation(ge)[0] self._known_points = ge # note that lower is only a conjectural @@ -2322,11 +2301,10 @@ def _compute_gens(self, proof, for a in ai: if not a.is_integral(): for p, _ in a.denom().factor(): - e = min((ai[i].valuation(p)/[1,2,3,4,6][i]) - for i in range(5)).floor() - ai = [ai[i]/p**(e*[1,2,3,4,6][i]) for i in range(5)] - xterm *= p**(2*e) - yterm *= p**(3*e) + e = min((ai[i].valuation(p) / [1, 2, 3, 4, 6][i]) for i in range(5)).floor() + ai = [ai[i] / p ** (e * [1, 2, 3, 4, 6][i]) for i in range(5)] + xterm *= p ** (2 * e) + yterm *= p ** (3 * e) E = constructor.EllipticCurve(list(ai)) else: E = self @@ -2340,10 +2318,9 @@ def _compute_gens(self, proof, G = C.gens() if proof is True and C.certain() is False: del self.__mwrank_curve - raise RuntimeError("Unable to compute the rank, hence generators, with certainty (lower bound=%s, generators found=%s). This could be because Sha(E/Q)[2] is nontrivial." % (C.rank(), G) + - "\nTry increasing descent_second_limit then trying this command again.") + raise RuntimeError("Unable to compute the rank, hence generators, with certainty (lower bound=%s, generators found=%s). This could be because Sha(E/Q)[2] is nontrivial." % (C.rank(), G) + "\nTry increasing descent_second_limit then trying this command again.") proved = C.certain() - G = [[x*xterm, y*yterm, z] for x, y, z in G] + G = [[x * xterm, y * yterm, z] for x, y, z in G] else: # when gens() calls mwrank it passes the command-line # parameter "-p 100" which helps curves with large @@ -2355,7 +2332,7 @@ def _compute_gens(self, proof, # In fact it would be much better to avoid the mwrank console at # all for gens() and just use the library. This is in # progress (see trac #1949). - X = self.mwrank('-p 100 -S '+str(sat_bound)) + X = self.mwrank('-p 100 -S ' + str(sat_bound)) verbose_verbose("Calling mwrank shell.") if 'The rank and full Mordell-Weil basis have been determined unconditionally' not in X: msg = 'Generators not provably computed.' @@ -2371,7 +2348,7 @@ def _compute_gens(self, proof, while i != -1: j = i + X[i:].find(';') k = i + X[i:].find('[') - G.append(eval(X[k:j].replace(':',','))) + G.append(eval(X[k:j].replace(':', ','))) X = X[j:] i = X.find('Generator ') G = sorted([self.point(x, check=True) for x in G]) @@ -2472,6 +2449,7 @@ def regulator(self, proof=None, precision=53, **kwds): if proof is None: from sage.structure.proof.proof import get_flag + proof = get_flag(proof, "elliptic_curve") else: proof = bool(proof) @@ -2634,12 +2612,13 @@ def saturation(self, points, verbose=False, max_prime=-1, min_prime=2): for P in points: x, y = P.xy() d = x.denominator().lcm(y.denominator()) - v.append((x*d, y*d, d)) + v.append((x * d, y * d, d)) c = Emin.mwrank_curve() from sage.libs.eclib.all import mwrank_MordellWeil + mw = mwrank_MordellWeil(c, verbose) - mw.process(v) # by default, this does no saturation yet + mw.process(v) # by default, this does no saturation yet ok, index, unsat = mw.saturate(max_prime=max_prime, min_prime=min_prime) if not ok: print("Failed to saturate failed at the primes {}".format(unsat)) @@ -2750,9 +2729,10 @@ def h(x): def h_oo(x): return log(max(abs(x), 1)) - mu = h(Delta)/12 + h_oo(j)/12 + h_oo(b2/12)/2 + log(twostar)/2 - lower = 2*(-h(j)/24 - mu - 0.961) - upper = 2*(mu + 1.07) + + mu = h(Delta) / 12 + h_oo(j) / 12 + h_oo(b2 / 12) / 2 + log(twostar) / 2 + lower = 2 * (-h(j) / 24 - mu - 0.961) + upper = 2 * (mu + 1.07) return max(abs(lower), abs(upper)) if algorithm == 'mwrank': return self.mwrank_curve().silverman_bound() @@ -3049,7 +3029,7 @@ def is_p_minimal(self, p): if not self.is_p_integral(p): return False if p > 3: - return ((self.discriminant().valuation(p) < 12) or (self.c4().valuation(p) < 4)) + return (self.discriminant().valuation(p) < 12) or (self.c4().valuation(p) < 4) # else p = 2,3 Emin = self.minimal_model() return self.discriminant().valuation(p) == Emin.discriminant().valuation(p) @@ -3106,6 +3086,7 @@ def kodaira_type_old(self, p): if p not in self.__kodaira_type: v = self.pari_mincurve().elllocalred(p) from .kodaira_symbol import KodairaSymbol + self.__kodaira_type[p] = KodairaSymbol(v[1]) self.__tamagawa_number[p] = Integer(v[3]) return self.__kodaira_type[p] @@ -3290,6 +3271,7 @@ def period_lattice(self, embedding=None): return self._period_lattice except AttributeError: from sage.schemes.elliptic_curves.period_lattice import PeriodLattice_ell + self._period_lattice = PeriodLattice_ell(self) return self._period_lattice @@ -3388,6 +3370,7 @@ def lseries(self): return self.__lseries except AttributeError: from .lseries_ell import Lseries_ell + self.__lseries = Lseries_ell(self) return self.__lseries @@ -3439,6 +3422,7 @@ def lseries_gross_zagier(self, A): pass from sage.modular.modform.l_series_gross_zagier import GrossZagierLseries + self.__lseries_gross_zagier[A] = GrossZagierLseries(self, A) return self.__lseries_gross_zagier[A] @@ -3469,8 +3453,9 @@ def Lambda(self, s, prec): sqrtN = float(N.sqrt()) def _F(n, t): - return gamma_inc(t+1, 2*pi*n/sqrtN) * C(sqrtN/(2*pi*n))**(t+1) - return sum(a[n]*(_F(n,s-1) + eps*_F(n,1-s)) for n in range(1, prec+1)) + return gamma_inc(t + 1, 2 * pi * n / sqrtN) * C(sqrtN / (2 * pi * n)) ** (t + 1) + + return sum(a[n] * (_F(n, s - 1) + eps * _F(n, 1 - s)) for n in range(1, prec + 1)) def is_local_integral_model(self, *p): r""" @@ -3511,8 +3496,8 @@ def local_integral_model(self, p): """ assert p.is_prime(), "p must be prime in local_integral_model()" ai = self.a_invariants() - e = min([(ai[i].valuation(p)/[1,2,3,4,6][i]) for i in range(5)]).floor() - return constructor.EllipticCurve([ai[i]/p**(e*[1,2,3,4,6][i]) for i in range(5)]) + e = min([(ai[i].valuation(p) / [1, 2, 3, 4, 6][i]) for i in range(5)]).floor() + return constructor.EllipticCurve([ai[i] / p ** (e * [1, 2, 3, 4, 6][i]) for i in range(5)]) def is_global_integral_model(self): r""" @@ -3545,9 +3530,8 @@ def global_integral_model(self): for a in ai: if not a.is_integral(): for p, _ in a.denom().factor(): - e = min((ai[i].valuation(p)/[1,2,3,4,6][i]) - for i in range(5)).floor() - ai = [ai[i]/p**(e*[1,2,3,4,6][i]) for i in range(5)] + e = min((ai[i].valuation(p) / [1, 2, 3, 4, 6][i]) for i in range(5)).floor() + ai = [ai[i] / p ** (e * [1, 2, 3, 4, 6][i]) for i in range(5)] for z in ai: assert z.denominator() == 1, "bug in global_integral_model: %s" % ai return constructor.EllipticCurve(list(ai)) @@ -3569,8 +3553,8 @@ def integral_short_weierstrass_model(self): _, _, _, A, B = F.ainvs() for p in [2, 3]: e = min(A.valuation(p) / 4, B.valuation(p) / 6).floor() - A /= Integer(p**(4 * e)) - B /= Integer(p**(6 * e)) + A /= Integer(p ** (4 * e)) + B /= Integer(p ** (6 * e)) return constructor.EllipticCurve([A, B]) def _generalized_congmod_numbers(self, M, invariant='both'): @@ -3624,14 +3608,14 @@ def _generalized_congmod_numbers(self, M, invariant='both'): # Cuspidal space at level MN N = self.conductor() - S = ModularSymbols(N*M,sign=1).cuspidal_subspace() + S = ModularSymbols(N * M, sign=1).cuspidal_subspace() # Cut out the subspace by hitting it with T_p for enough p A = S - d = self.dimension()*arith.sigma(M,0) + d = self.dimension() * arith.sigma(M, 0) p = 2 while A.dimension() > d: - while N*M % p == 0: + while N * M % p == 0: p = arith.next_prime(p) Tp = A.hecke_operator(p) A = (Tp - self.ap(p)).kernel() @@ -3769,9 +3753,11 @@ def modular_degree(self, algorithm='sympow', M=1): except AttributeError: if algorithm == 'sympow': from sage.lfunctions.all import sympow + m = sympow.modular_degree(self) elif algorithm == 'magma': from sage.interfaces.magma import magma + m = Integer(magma(self).ModularDegree()) else: raise ValueError("unknown algorithm %s" % algorithm) @@ -4057,7 +4043,7 @@ def _torsion_bound(self, number_of_places=20): E = self bound = Integer(0) k = 0 - p = Integer(2) # will run through odd primes + p = Integer(2) # will run through odd primes while k < number_of_places: p = p.next_prime() # check if the formal group at the place is torsion-free @@ -4420,25 +4406,25 @@ def minimal_quadratic_twist(self): Et = constructor.EllipticCurve_from_j(j) else: if j == 0: # divide c6 by largest cube - c = -2*self.c6() + c = -2 * self.c6() for p in c.support(): - e = c.valuation(p)//3 - c /= p**(3*e) - E1 = constructor.EllipticCurve([0,0,0,0,c]) - else: # j=1728 ; divide c4 by largest square - c = -3*self.c4() + e = c.valuation(p) // 3 + c /= p ** (3 * e) + E1 = constructor.EllipticCurve([0, 0, 0, 0, c]) + else: # j=1728 ; divide c4 by largest square + c = -3 * self.c4() for p in c.support(): - e = c.valuation(p)//2 - c /= p**(2*e) - E1 = constructor.EllipticCurve([0,0,0,c,0]) - tw = [-1,2,-2,3,-3,6,-6] + e = c.valuation(p) // 2 + c /= p ** (2 * e) + E1 = constructor.EllipticCurve([0, 0, 0, c, 0]) + tw = [-1, 2, -2, 3, -3, 6, -6] Elist = [E1] + [E1.quadratic_twist(t) for t in tw] Elist.sort(key=lambda E: E.conductor()) Et = Elist[0] Et = Et.minimal_model() - D = self.is_quadratic_twist(Et) # 1 or square-free + D = self.is_quadratic_twist(Et) # 1 or square-free if D % 4 != 1: D *= 4 @@ -4603,6 +4589,7 @@ class are reordered to be isomorphic with the specified isoclass = self._isoclass[algorithm] except KeyError: from sage.schemes.elliptic_curves.isogeny_class import IsogenyClass_EC_Rational + if hasattr(self, "_lmfdb_label") and self._lmfdb_label: label = self._lmfdb_label[:-1] elif hasattr(self, "_EllipticCurve_rational_field__cremona_label") and self.__cremona_label: @@ -4699,8 +4686,7 @@ def isogenies_prime_degree(self, l=None): isogs = [] i = 0 while i < len(l): - isogenies = [f for f in self.isogenies_prime_degree(l[i]) - if f not in isogs] + isogenies = [f for f in self.isogenies_prime_degree(l[i]) if f not in isogs] isogs.extend(isogenies) i += 1 return isogs @@ -4770,9 +4756,7 @@ def is_isogenous(self, other, proof=True, maxp=200): D1 = E1.discriminant() D2 = E2.discriminant() - if any(E1.change_ring(GF(p)).cardinality() != E2.change_ring(GF(p)).cardinality() - for p in prime_range(2, maxp) - if D1.valuation(p) == 0 and D2.valuation(p) == 0): + if any(E1.change_ring(GF(p)).cardinality() != E2.change_ring(GF(p)).cardinality() for p in prime_range(2, maxp) if D1.valuation(p) == 0 and D2.valuation(p) == 0): return False if E1.conductor() != E2.conductor(): @@ -4893,19 +4877,19 @@ def isogeny_degree(self, other): isocls = E1.isogeny_class() try: - return isocls.matrix(fill=True)[0,isocls.index(E2)] + return isocls.matrix(fill=True)[0, isocls.index(E2)] except ValueError: return Integer(0) -# -# The following function can be implemented once composition of -# isogenies has been implemented. -# -# def construct_isogeny(self, other): -# """ -# Return an isogeny from self to other if the two curves are in -# the same isogeny class. -# """ + # + # The following function can be implemented once composition of + # isogenies has been implemented. + # + # def construct_isogeny(self, other): + # """ + # Return an isogeny from self to other if the two curves are in + # the same isogeny class. + # """ def optimal_curve(self): r""" @@ -5059,7 +5043,7 @@ def manin_constant(self): ma = max(max(x) for x in m) OmC = C.period_lattice().basis() OmE = E.period_lattice().basis() - q_plus = QQ(gp.bestappr(OmE[0]/OmC[0],ma+1) ) + q_plus = QQ(gp.bestappr(OmE[0] / OmC[0], ma + 1)) n_plus = q_plus.numerator() cinf_E = E.real_components() @@ -5070,7 +5054,7 @@ def manin_constant(self): OmE_minus = OmE[1].imag() if cinf_E == 1: OmE_minus *= 2 - q_minus = QQ(gp.bestappr(OmE_minus/OmC_minus, ma+1)) + q_minus = QQ(gp.bestappr(OmE_minus / OmC_minus, ma + 1)) n_minus = q_minus.numerator() n = ZZ(n_minus * n_plus) @@ -5085,7 +5069,7 @@ def manin_constant(self): # if cinf_C < cinf_E: if not q_plus.denominator() % 2 and not q_minus.denominator() % 2: return n - return n*2 + return n * 2 def _shortest_paths(self): r""" @@ -5109,6 +5093,7 @@ def _shortest_paths(self): {0: 0, 1: 5, 2: 25}) """ from sage.graphs.graph import Graph + isocls = self.isogeny_class() M = isocls.matrix(fill=True).change_ring(RR) # see trac #4889 for nebulous M.list() --> M.entries() change... @@ -5118,7 +5103,7 @@ def _shortest_paths(self): G.set_vertices({v: isocls[v] for v in G.vertices(sort=False)}) v = G.shortest_path_lengths(0, by_weight=True) # Now exponentiate and round to get degrees of isogenies - v = {i: j.exp().round() if j else 0 for i,j in v.items()} + v = {i: j.exp().round() if j else 0 for i, j in v.items()} return isocls.curves, v def _multiple_of_degree_of_isogeny_to_optimal_curve(self): @@ -5199,6 +5184,7 @@ def galois_representation(self): return self.__rho except AttributeError: from .gal_reps import GaloisRepresentation + self.__rho = GaloisRepresentation(self) return self.__rho @@ -5329,10 +5315,9 @@ def supersingular_primes(self, B): [] """ v = self.aplist(max(B, 3)) - P = prime_range(max(B,3)+1) + P = prime_range(max(B, 3) + 1) N = self.conductor() - return [P[i] for i in [0,1] if P[i] <= B and v[i] % P[i] == 0 and N % P[i] != 0] + \ - [P[i] for i in range(2,len(v)) if v[i] == 0 and N % P[i] != 0] + return [P[i] for i in [0, 1] if P[i] <= B and v[i] % P[i] == 0 and N % P[i] != 0] + [P[i] for i in range(2, len(v)) if v[i] == 0 and N % P[i] != 0] def ordinary_primes(self, B): r""" @@ -5441,6 +5426,7 @@ def sha(self): return self.__sha except AttributeError: from .sha_tate import Sha + self.__sha = Sha(self) return self.__sha @@ -5498,7 +5484,7 @@ def mod5family(self): E = self.short_weierstrass_model() a = E.a4() b = E.a6() - return mod5family.mod5family(a,b) + return mod5family.mod5family(a, b) def tate_curve(self, p): r""" @@ -5590,8 +5576,8 @@ def height(self, precision=None): c4 = self.c4() c6 = self.c6() j = self.j_invariant() - log_g2 = R(c4/12).abs().log() - log_g3 = R(c6/216).abs().log() + log_g2 = R(c4 / 12).abs().log() + log_g3 = R(c6 / 216).abs().log() if j == 0: h_j = R(1) @@ -5601,11 +5587,11 @@ def height(self, precision=None): h_gs = max(1, log_g2, log_g3) elif c4 == 0: if c6 == 0: - return max(1,h_j) + return max(1, h_j) h_gs = max(1, log_g3) else: h_gs = max(1, log_g2) - return max(R(1),h_j, h_gs) + return max(R(1), h_j, h_gs) def faltings_height(self, stable=False, prec=None): r""" @@ -5681,7 +5667,7 @@ def faltings_height(self, stable=False, prec=None): """ R = RealField(prec) if prec else RealField() log_vol = self.period_lattice().complex_area(prec).log() - h = R(self.j_invariant().denominator()/self.discriminant().abs()).log() / 12 if stable else R(0) + h = R(self.j_invariant().denominator() / self.discriminant().abs()).log() / 12 if stable else R(0) return h - log_vol / 2 def antilogarithm(self, z, max_denominator=None): @@ -5955,16 +5941,17 @@ def point_preprocessing(free, tor): for i in range(r): if not free_id[i]: if i == i0: - newfree[i] = 2*newfree[i] + newfree[i] = 2 * newfree[i] else: newfree[i] += P return newfree + ############################## end ################################ # END Internal functions ############################################# ###################################################################### - if (r == 0): + if r == 0: int_points = [P for P in tors_points if not P.is_zero()] int_points = [P for P in int_points if P[0].is_integral()] if not both_signs: @@ -5982,37 +5969,38 @@ def point_preprocessing(free, tor): j = self.j_invariant() b2 = self.b2() - Qx = PolynomialRing(RationalField(),'x') - pol = Qx([-self.c6()/216,-self.c4()/12,0,4]) - if disc > 0: # two real component -> 3 roots in RR - #on curve 897e4, only one root is found with default precision! + Qx = PolynomialRing(RationalField(), 'x') + pol = Qx([-self.c6() / 216, -self.c4() / 12, 0, 4]) + if disc > 0: # two real component -> 3 roots in RR + # on curve 897e4, only one root is found with default precision! RR = R prec = RR.precision() - ei = pol.roots(RR,multiplicities=False) + ei = pol.roots(RR, multiplicities=False) while len(ei) < 3: prec *= 2 RR = RealField(prec) - ei = pol.roots(RR,multiplicities=False) - e1,e2,e3 = ei - if r >= 1: #preprocessing of mw_base only necessary if rank > 0 + ei = pol.roots(RR, multiplicities=False) + e1, e2, e3 = ei + if r >= 1: # preprocessing of mw_base only necessary if rank > 0 mw_base = point_preprocessing(mw_base, tors_points) # at most one point in E^{egg} elif disc < 0: # one real component => 1 root in RR (=: e3), # 2 roots in C (e1,e2) - roots = pol.roots(C,multiplicities=False) - e3 = pol.roots(R,multiplicities=False)[0] + roots = pol.roots(C, multiplicities=False) + e3 = pol.roots(R, multiplicities=False)[0] roots.remove(e3) - e1,e2 = roots + e1, e2 = roots from sage.symbolic.constants import pi + e = R(1).exp() pi = R(pi) M = self.height_pairing_matrix(mw_base) - mw_base, U = self.lll_reduce(mw_base,M) - M = U.transpose()*M*U + mw_base, U = self.lll_reduce(mw_base, M) + M = U.transpose() * M * U if verbose: print("Using mw_basis ", mw_base) @@ -6024,9 +6012,9 @@ def point_preprocessing(free, tor): w1, w2 = self.period_lattice().basis() mu = R(disc).abs().log() / 6 if j != 0: - mu += max(R(1),R(j).abs().log()) / 6 + mu += max(R(1), R(j).abs().log()) / 6 if b2 != 0: - mu += max(R(1),R(b2).abs().log()) + mu += max(R(1), R(b2).abs().log()) mu += log(R(2)) else: mu += 1 @@ -6039,59 +6027,59 @@ def point_preprocessing(free, tor): print("Minimal and maximal eigenvalues of height pairing matrix: {},{}".format(c2, max_eig)) sys.stdout.flush() - c3 = (w1**2)*R(b2).abs()/48 + 8 - c5 = (c1*c3).sqrt() - c7 = abs((3*pi)/((w1**2) * (w1/w2).imag())) + c3 = (w1**2) * R(b2).abs() / 48 + 8 + c5 = (c1 * c3).sqrt() + c7 = abs((3 * pi) / ((w1**2) * (w1 / w2).imag())) - mw_base_log = [] #contains \Phi(Q_i) - mod_h_list = [] #contains h_m(Q_i) + mw_base_log = [] # contains \Phi(Q_i) + mod_h_list = [] # contains h_m(Q_i) c9_help_list = [] for i in range(r): mw_base_log.append(mw_base[i].elliptic_logarithm().abs()) - mod_h_list.append(max(mw_base[i].height(),h_E,c7*mw_base_log[i]**2)) - c9_help_list.append((mod_h_list[i]).sqrt()/mw_base_log[i]) - c9 = e/c7.sqrt() * min(c9_help_list) - n = r+1 - c10 = R(2 * 10**(8+7*n) * R((2/e)**(2 * n**2)) * (n+1)**(4 * n**2 + 10 * n) * log(c9)**(-2*n - 1) * prod(mod_h_list)) + mod_h_list.append(max(mw_base[i].height(), h_E, c7 * mw_base_log[i] ** 2)) + c9_help_list.append((mod_h_list[i]).sqrt() / mw_base_log[i]) + c9 = e / c7.sqrt() * min(c9_help_list) + n = r + 1 + c10 = R(2 * 10 ** (8 + 7 * n) * R((2 / e) ** (2 * n**2)) * (n + 1) ** (4 * n**2 + 10 * n) * log(c9) ** (-2 * n - 1) * prod(mod_h_list)) top = Z(128) # arbitrary first upper bound bottom = Z(0) log_c9 = log(c9) log_c5 = log(c5) - log_r_top = log(R(r*(10**top))) + log_r_top = log(R(r * (10**top))) - while R(c10*(log_r_top+log_c9)*(log(log_r_top)+h_E+log_c9)**(n+1)) > R(c2/2 * (10**top)**2 - log_c5): - #initial bound 'top' too small, upshift of search interval + while R(c10 * (log_r_top + log_c9) * (log(log_r_top) + h_E + log_c9) ** (n + 1)) > R(c2 / 2 * (10**top) ** 2 - log_c5): + # initial bound 'top' too small, upshift of search interval bottom = top - top = 2*top - while top >= bottom: #binary-search like search for fitting exponent (bound) - bound = (bottom + (top - bottom)/2).floor() - log_r_bound = log(R(r*(10**bound))) - if R(c10*(log_r_bound+log_c9)*(log(log_r_bound)+h_E+log_c9)**(n+1)) > R(c2/2 * (10**bound)**2 - log_c5): + top = 2 * top + while top >= bottom: # binary-search like search for fitting exponent (bound) + bound = (bottom + (top - bottom) / 2).floor() + log_r_bound = log(R(r * (10**bound))) + if R(c10 * (log_r_bound + log_c9) * (log(log_r_bound) + h_E + log_c9) ** (n + 1)) > R(c2 / 2 * (10**bound) ** 2 - log_c5): bottom = bound + 1 else: top = bound - 1 - H_q = R(10)**bound - break_cond = 0 #at least one reduction step - #reduction via LLL - M = MatrixSpace(Z,n) - while break_cond < 0.9: #as long as the improvement of the new bound in comparison to the old is greater than 10% - c = R((H_q**n)*10) #c has to be greater than H_q^n + H_q = R(10) ** bound + break_cond = 0 # at least one reduction step + # reduction via LLL + M = MatrixSpace(Z, n) + while break_cond < 0.9: # as long as the improvement of the new bound in comparison to the old is greater than 10% + c = R((H_q**n) * 10) # c has to be greater than H_q^n m = copy(M.identity_matrix()) for i in range(r): - m[i, r] = R(c*mw_base_log[i]).round() - m[r,r] = max(Z(1),R(c*w1).round()) #ensures that m isn't singular + m[i, r] = R(c * mw_base_log[i]).round() + m[r, r] = max(Z(1), R(c * w1).round()) # ensures that m isn't singular - #LLL - implemented in sage - operates on rows not on columns + # LLL - implemented in sage - operates on rows not on columns m_LLL = m.LLL() m_gram = m_LLL.gram_schmidt()[0] b1_norm = R(m_LLL.row(0).norm()) - #compute constant c1 ~ c1_LLL of Corollary 2.3.17 and hence d(L,0)^2 ~ d_L_0 + # compute constant c1 ~ c1_LLL of Corollary 2.3.17 and hence d(L,0)^2 ~ d_L_0 c1_LLL = -R.one() for i in range(n): - tmp = R(b1_norm/(m_gram.row(i).norm())) + tmp = R(b1_norm / (m_gram.row(i).norm())) c1_LLL = max(tmp, c1_LLL) if c1_LLL < 0: @@ -6099,46 +6087,46 @@ def point_preprocessing(free, tor): d_L_0 = R(b1_norm**2 / c1_LLL) - #Reducing of upper bound + # Reducing of upper bound Q = r * H_q**2 - T = (1 + (Z(3)/2*r*H_q))/2 - if d_L_0 < R(T**2+Q): - d_L_0 = 10*(T**2*Q) + T = (1 + (Z(3) / 2 * r * H_q)) / 2 + if d_L_0 < R(T**2 + Q): + d_L_0 = 10 * (T**2 * Q) low_bound = (R(d_L_0 - Q).sqrt() - T) / c - #new bound according to low_bound and upper bound - #[c_5 exp((-c_2*H_q^2)/2)] provided by Corollary 8.7.3 + # new bound according to low_bound and upper bound + # [c_5 exp((-c_2*H_q^2)/2)] provided by Corollary 8.7.3 if low_bound != 0: - H_q_new = R(log(low_bound/c5)/(-c2/2)).sqrt() + H_q_new = R(log(low_bound / c5) / (-c2 / 2)).sqrt() H_q_new = H_q_new.ceil() if H_q_new == 1: - break_cond = 1 # stops reduction + break_cond = 1 # stops reduction else: - break_cond = R(H_q_new/H_q) + break_cond = R(H_q_new / H_q) H_q = H_q_new else: - break_cond = 1 # stops reduction, so using last H_q > 0 - #END LLL-Reduction loop + break_cond = 1 # stops reduction, so using last H_q > 0 + # END LLL-Reduction loop - b2_12 = b2/12 + b2_12 = b2 / 12 if disc > 0: ##Points in egg have X(P) between e1 and e2 [X(P)=x(P)+b2/12]: - x_int_points = self.integral_x_coords_in_interval((e1-b2_12).ceil(), (e2-b2_12).floor()) + x_int_points = self.integral_x_coords_in_interval((e1 - b2_12).ceil(), (e2 - b2_12).floor()) if verbose: - print('x-coords of points on compact component with ',(e1-b2_12).ceil(),'<=x<=',(e2-b2_12).floor()) - L = sorted(x_int_points) # to have the order + print('x-coords of points on compact component with ', (e1 - b2_12).ceil(), '<=x<=', (e2 - b2_12).floor()) + L = sorted(x_int_points) # to have the order print(L) sys.stdout.flush() else: x_int_points = set() ##Points in noncompact component with X(P)< 2*max(|e1|,|e2|,|e3|) , espec. X(P)>=e3 - x0 = (e3-b2_12).ceil() - x1 = (2*max(abs(e1),abs(e2),abs(e3)) - b2_12).ceil() + x0 = (e3 - b2_12).ceil() + x1 = (2 * max(abs(e1), abs(e2), abs(e3)) - b2_12).ceil() x_int_points2 = self.integral_x_coords_in_interval(x0, x1) x_int_points = x_int_points.union(x_int_points2) if verbose: - print('x-coords of points on non-compact component with ',x0,'<=x<=',x1-1) + print('x-coords of points on non-compact component with ', x0, '<=x<=', x1 - 1) L = sorted(x_int_points2) print(L) sys.stdout.flush() @@ -6148,11 +6136,11 @@ def point_preprocessing(free, tor): ht_diff_bnd = self.CPS_height_bound() except RuntimeError: ht_diff_bnd = self.silverman_height_bound() - x_bound = (ht_diff_bnd+max_eig*H_q**2).exp() + x_bound = (ht_diff_bnd + max_eig * H_q**2).exp() if verbose: - print('starting search of remaining points using coefficient bound {} and |x| bound {}'.format(H_q,x_bound)) + print('starting search of remaining points using coefficient bound {} and |x| bound {}'.format(H_q, x_bound)) sys.stdout.flush() - x_int_points3 = integral_points_with_bounded_mw_coeffs(self,mw_base,H_q,x_bound) + x_int_points3 = integral_points_with_bounded_mw_coeffs(self, mw_base, H_q, x_bound) x_int_points = x_int_points.union(x_int_points3) if verbose: print('x-coords of extra integral points:') @@ -6165,7 +6153,7 @@ def point_preprocessing(free, tor): for x in x_int_points: P = self.lift_x(x) for T in tors_points: - Q = P+T + Q = P + T if not Q.is_zero() and Q[0].is_integral(): x_int_points_t = x_int_points_t.union([Q[0]]) x_int_points = x_int_points.union(x_int_points_t) @@ -6173,12 +6161,12 @@ def point_preprocessing(free, tor): # Now we have all the x-coordinates of integral points, and we # construct the points, depending on the parameter both_signs: if both_signs: - int_points = sum([self.lift_x(x,all=True) for x in x_int_points],[]) + int_points = sum([self.lift_x(x, all=True) for x in x_int_points], []) else: int_points = [self.lift_x(x) for x in x_int_points] int_points.sort() if verbose: - print('Total number of integral points:',len(int_points)) + print('Total number of integral points:', len(int_points)) return int_points def S_integral_points(self, S, mw_base='auto', both_signs=False, verbose=False, proof=None): @@ -6351,6 +6339,7 @@ def S_integral_points(self, S, mw_base='auto', both_signs=False, verbose=False, if proof is None: from sage.structure.proof.proof import get_flag + proof = get_flag(proof, "elliptic_curve") else: proof = bool(proof) @@ -6369,7 +6358,7 @@ def S_integral_points(self, S, mw_base='auto', both_signs=False, verbose=False, S.sort() except TypeError: raise TypeError('S must be a list of primes') - except AttributeError:#catches: .sort(), .is_prime() + except AttributeError: # catches: .sort(), .is_prime() raise AttributeError('S must be a list of primes') if mw_base == 'auto': @@ -6390,33 +6379,33 @@ def S_integral_points(self, S, mw_base='auto', both_signs=False, verbose=False, if not all(P.curve() is self for P in mw_base): raise ValueError("mw_base-points are not on the correct curve") - #End Input-Check ###################################################### + # End Input-Check ###################################################### - #Internal functions ################################################### + # Internal functions ################################################### def reduction_at(p): r""" Reducing the bound `H_q` at the finite place p in S via LLL """ indexp = S.index(p) - pc = Z(p**(R(c.log()/log(p,e)).ceil())) + pc = Z(p ** (R(c.log() / log(p, e)).ceil())) m = copy(M.identity_matrix()) for i in range(r): try: m[i, r] = Z((beta[indexp][i]) % pc) - except ZeroDivisionError: #If Inverse doesn't exist, change denominator (which is only approx) + except ZeroDivisionError: # If Inverse doesn't exist, change denominator (which is only approx) val_nu = (beta[indexp][i]).numerator() val_de = (beta[indexp][i]).denominator() - m[i, r] = Z((val_nu/(val_de+1)) % pc) - m[r,r] = max(Z(1), pc) + m[i, r] = Z((val_nu / (val_de + 1)) % pc) + m[r, r] = max(Z(1), pc) - #LLL - implemented in sage - operates on rows not on columns + # LLL - implemented in sage - operates on rows not on columns m_LLL = m.LLL() m_gram = m_LLL.gram_schmidt()[0] b1_norm = R(m_LLL.row(0).norm()) c1_LLL = -R.one() for i in range(n): - tmp = R(b1_norm/(m_gram.row(i).norm())) + tmp = R(b1_norm / (m_gram.row(i).norm())) c1_LLL = max(tmp, c1_LLL) if c1_LLL < 0: raise RuntimeError('Unexpected intermediate result. Please try another Mordell-Weil base') @@ -6424,15 +6413,15 @@ def reduction_at(p): # Reducing of upper bound Q = r * H_q**2 - T = (1 + (Z(3)/2*r*H_q))/2 - if d_L_0 < R(T**2+Q): - d_L_0 = 10*(T**2*Q) + T = (1 + (Z(3) / 2 * r * H_q)) / 2 + if d_L_0 < R(T**2 + Q): + d_L_0 = 10 * (T**2 * Q) low_bound = (R(d_L_0 - Q).sqrt() - T) / c # new bound according to low_bound and upper bound # [k5*k6 exp(-k7**H_q^2)] if low_bound != 0: - H_q_infinity = R(((low_bound/(k6)).log()/(-k7)).sqrt()) + H_q_infinity = R(((low_bound / (k6)).log() / (-k7)).sqrt()) return H_q_infinity.ceil() return H_q @@ -6461,6 +6450,7 @@ def S_integral_points_with_bounded_mw_coeffs(): denominator. """ from sage.groups.generic import multiples + xs = set() N = H_q @@ -6478,11 +6468,11 @@ def test_with_T(R): Record x-coords of a 'point+torsion' if S-integral. """ for T in tors_points: - test(R+T) + test(R + T) # For small rank and small H_q perform simple search if r == 1 and N <= 10: - for P in multiples(mw_base[0],N+1): + for P in multiples(mw_base[0], N + 1): test_with_T(P) return xs @@ -6493,11 +6483,11 @@ def test_with_T(R): E0 = E(0) ni = [-N for i in range(r)] - mw_baseN = [-N*P for P in mw_base] + mw_baseN = [-N * P for P in mw_base] Pi = [0 for j in range(r)] Pi[0] = mw_baseN[0] - for i in range(1,r): - Pi[i] = Pi[i-1] + mw_baseN[i] + for i in range(1, r): + Pi[i] = Pi[i - 1] + mw_baseN[i] while True: if all(n == 0 for n in ni): @@ -6505,20 +6495,20 @@ def test_with_T(R): break # test the ni-combination which is Pi[r-1] - test_with_T(Pi[r-1]) + test_with_T(Pi[r - 1]) # increment indices and stored points - i0 = r-1 + i0 = r - 1 while ni[i0] == N: ni[i0] = -N i0 -= 1 ni[i0] += 1 - if all(n == 0 for n in ni[0:i0+1]): + if all(n == 0 for n in ni[0 : i0 + 1]): Pi[i0] = E0 else: Pi[i0] += mw_base[i0] - for i in range(i0+1,r): - Pi[i] = Pi[i-1] + mw_baseN[i] + for i in range(i0 + 1, r): + Pi[i] = Pi[i - 1] + mw_baseN[i] return xs @@ -6552,43 +6542,42 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): better to scale the equation by the maximum denominator and search for integral points on the scaled model. """ - x_min = min(self.two_division_polynomial().roots(R,multiplicities=False)) + x_min = min(self.two_division_polynomial().roots(R, multiplicities=False)) x_min_neg = bool(x_min < 0) x_min_pos = not x_min_neg log_ab = R(abs_bound.log()) - alpha = [(log_ab/R(log(p,e))).floor() for p in S] - if all(alpha_i <= 1 for alpha_i in alpha): # so alpha_i must be 0 to satisfy that denominator is a square + alpha = [(log_ab / R(log(p, e))).floor() for p in S] + if all(alpha_i <= 1 for alpha_i in alpha): # so alpha_i must be 0 to satisfy that denominator is a square int_abs_bound = abs_bound.floor() - return {x for x in range(-int_abs_bound, int_abs_bound) - if E.is_x_coord(x)} + return {x for x in range(-int_abs_bound, int_abs_bound) if E.is_x_coord(x)} xs = [] alpha_max_even = [y - y % 2 for y in alpha] p_pow_alpha = [] list_alpha = [] - for i in range(len_S-1): - list_alpha.append(range(0,alpha_max_even[i]+2,2)) - p_pow_alpha.append([S[i]**list_alpha[i][j] for j in range(len(list_alpha[i]))]) + for i in range(len_S - 1): + list_alpha.append(range(0, alpha_max_even[i] + 2, 2)) + p_pow_alpha.append([S[i] ** list_alpha[i][j] for j in range(len(list_alpha[i]))]) if verbose: print(list_alpha, p_pow_alpha) # denom_maxpa is a list of pairs (d,q) where d runs # through possible denominators, and q=p^a is the # maximum prime power divisor of d: denom_maxpa = [(prod(tmp), max(tmp)) for tmp in product(*p_pow_alpha)] -# The maximum denominator is this (not used): -# denom = [prod([pp[-1] for pp in p_pow_alpha],1)] - for de,maxpa in denom_maxpa: - n_max = (abs_bound*de).ceil() - n_min = maxpa*de + # The maximum denominator is this (not used): + # denom = [prod([pp[-1] for pp in p_pow_alpha],1)] + for de, maxpa in denom_maxpa: + n_max = (abs_bound * de).ceil() + n_min = maxpa * de if x_min_pos: pos_n_only = True if x_min > maxpa: - n_min = (x_min*de).floor() + n_min = (x_min * de).floor() else: pos_n_only = False - neg_n_max = (x_min.abs()*de).ceil() + neg_n_max = (x_min.abs() * de).ceil() - for n in arith.xsrange(n_min,n_max+1): - tmp = n/de # to save time, do not check de is the exact denominator + for n in arith.xsrange(n_min, n_max + 1): + tmp = n / de # to save time, do not check de is the exact denominator if E.is_x_coord(tmp): xs += [tmp] if not pos_n_only: @@ -6597,13 +6586,14 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): xs += [-tmp] return set(xs) + # ------------------------------------------------------------------- # End internal functions ############################################ E = self tors_points = E.torsion_points() - if (r == 0): # only Torsionpoints to consider + if r == 0: # only Torsionpoints to consider int_points = [P for P in tors_points if not P.is_zero()] int_points = [P for P in int_points if P[0].is_S_integral(S)] if not both_signs: @@ -6622,7 +6612,7 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): b2, b4, b6, b8 = E.b_invariants() c4, c6 = E.c_invariants() disc = E.discriminant() - #internal function is doing only a comparison of E and E.short_weierstass_model() so the following is easier + # internal function is doing only a comparison of E and E.short_weierstass_model() so the following is easier if a1 == a2 == a3 == 0: is_short = True else: @@ -6630,23 +6620,23 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): w1, w2 = E.period_lattice().basis() - Qx = PolynomialRing(RationalField(),'x') - pol = Qx([-54*c6,-27*c4,0,1]) - if disc > 0: # two real component -> 3 roots in RR + Qx = PolynomialRing(RationalField(), 'x') + pol = Qx([-54 * c6, -27 * c4, 0, 1]) + if disc > 0: # two real component -> 3 roots in RR # it is possible that only one root is found with default precision! (see integral_points()) RR = R prec = RR.precision() - ei = pol.roots(RR,multiplicities=False) + ei = pol.roots(RR, multiplicities=False) while len(ei) < 3: prec *= 2 RR = RealField(prec) - ei = pol.roots(RR,multiplicities=False) + ei = pol.roots(RR, multiplicities=False) e1, e2, e3 = ei elif disc < 0: # one real component => 1 root in RR (=: e3), # 2 roots in C (e1,e2) - roots = pol.roots(C,multiplicities=False) - e3 = pol.roots(R,multiplicities=False)[0] + roots = pol.roots(C, multiplicities=False) + e3 = pol.roots(R, multiplicities=False)[0] roots.remove(e3) e1, e2 = roots @@ -6654,45 +6644,45 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): n = r + 1 M = E.height_pairing_matrix(mw_base) - mw_base, U = E.lll_reduce(mw_base,M) - M = U.transpose()*M*U + mw_base, U = E.lll_reduce(mw_base, M) + M = U.transpose() * M * U # NB "lambda" is a reserved word in Python! lamda = min(M.charpoly(algorithm='hessenberg').roots(multiplicities=False)) max_S = max(S) - len_S += 1 #Counting infinity (always "included" in S) + len_S += 1 # Counting infinity (always "included" in S) if verbose: - print('max_S:',max_S,'len_S:',len_S,'len_tors:',len_tors) + print('max_S:', max_S, 'len_S:', len_S, 'len_tors:', len_tors) print('lambda', lamda) sys.stdout.flush() if is_short: - disc_0_abs = R((4*a4**3 + 27*a6**2).abs()) - k4 = R(10**4 * max(16*a4**2, 256*disc_0_abs.sqrt()**3)) - k3 = R(32/3 * disc_0_abs.sqrt() * (8 + 0.5*disc_0_abs.log())**4) + disc_0_abs = R((4 * a4**3 + 27 * a6**2).abs()) + k4 = R(10**4 * max(16 * a4**2, 256 * disc_0_abs.sqrt() ** 3)) + k3 = R(32 / 3 * disc_0_abs.sqrt() * (8 + 0.5 * disc_0_abs.log()) ** 4) else: - disc_sh = R(E.short_weierstrass_model().discriminant()) #computes y^2=x^3 -27c4x -54c6 - k4 = R(20**4 * max(3**6 * c4**2, 16*(disc_sh.abs().sqrt())**3)) - k3 = R(32/3 * disc_sh.abs().sqrt() * (8 + 0.5*disc_sh.abs().log())**4) + disc_sh = R(E.short_weierstrass_model().discriminant()) # computes y^2=x^3 -27c4x -54c6 + k4 = R(20**4 * max(3**6 * c4**2, 16 * (disc_sh.abs().sqrt()) ** 3)) + k3 = R(32 / 3 * disc_sh.abs().sqrt() * (8 + 0.5 * disc_sh.abs().log()) ** 4) - k2 = max(R(b2.abs()), R(b4.abs().sqrt()), R(b6.abs()**(1/3)), R(b8.abs()**(1/4))).log() - k1 = R(7 * 10**(38*len_S+49)) * R(len_S**(20*len_S+15)) * max_S**24 * R(max(1,log(max_S, e))**(4*len_S - 2)) * k3 * k3.log()**2 * ((20*len_S - 19)*k3 + (e*k4).log()) + 2*R(2*b2.abs()+6).log() + k2 = max(R(b2.abs()), R(b4.abs().sqrt()), R(b6.abs() ** (1 / 3)), R(b8.abs() ** (1 / 4))).log() + k1 = R(7 * 10 ** (38 * len_S + 49)) * R(len_S ** (20 * len_S + 15)) * max_S**24 * R(max(1, log(max_S, e)) ** (4 * len_S - 2)) * k3 * k3.log() ** 2 * ((20 * len_S - 19) * k3 + (e * k4).log()) + 2 * R(2 * b2.abs() + 6).log() if verbose: print('k1,k2,k3,k4', k1, k2, k3, k4) sys.stdout.flush() # H_q -> [PZGH]:N_0 (due to consistency to integral_points()) - H_q = R(((k1/2+k2)/lamda).sqrt()) + H_q = R(((k1 / 2 + k2) / lamda).sqrt()) # computation of logs - mw_base_log = [(pts.elliptic_logarithm().abs())*(len_tors/w1) for pts in mw_base] + mw_base_log = [(pts.elliptic_logarithm().abs()) * (len_tors / w1) for pts in mw_base] mw_base_p_log = [] beta = [] mp = [] for tmp, p in enumerate(S): Np = E.Np(p) cp = E.tamagawa_exponent(p) - mp_temp = Z(len_tors).lcm(cp*Np) + mp_temp = Z(len_tors).lcm(cp * Np) mp.append(mp_temp) # only necessary because of verbose below p_prec = 30 + E.discriminant().valuation(p) p_prec_ok = False @@ -6700,14 +6690,14 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): if verbose: print("p=", p, ": trying with p_prec = ", p_prec) try: - mw_base_p_log.append([mp_temp*(pts.padic_elliptic_logarithm(p,absprec=p_prec)) for pts in mw_base]) + mw_base_p_log.append([mp_temp * (pts.padic_elliptic_logarithm(p, absprec=p_prec)) for pts in mw_base]) p_prec_ok = True except ValueError: p_prec *= 2 # reorder mw_base_p: last value has minimal valuation at p mw_base_p_log_val = [mw_base_p_log[tmp][i].valuation() for i in range(r)] if verbose: - print("mw_base_p_log_val = ",mw_base_p_log_val) + print("mw_base_p_log_val = ", mw_base_p_log_val) min_index = mw_base_p_log_val.index(min(mw_base_p_log_val)) min_psi = mw_base_p_log[tmp][min_index] if verbose: @@ -6716,7 +6706,7 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): mw_base_p_log[tmp].append(min_psi) # beta needed for reduction at p later on try: - beta.append([-mw_base_p_log[tmp][j]/min_psi for j in range(r)]) + beta.append([-mw_base_p_log[tmp][j] / min_psi for j in range(r)]) except ValueError: # e.g. mw_base_p_log[tmp]==[0]: can occur e.g. [?]'172c6, S=[2] beta.append([0] for j in range(r)) @@ -6730,16 +6720,16 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): # constants in reduction # (not needed to be computed every reduction step) - k5 = R((2*len_tors)/(3*w1)) - k6 = R((k2/len_S).exp()) - k7 = R(lamda/len_S) + k5 = R((2 * len_tors) / (3 * w1)) + k6 = R((k2 / len_S).exp()) + k7 = R(lamda / len_S) if verbose: print('k5,k6,k7', k5, k6, k7) sys.stdout.flush() break_cond = 0 - M = MatrixSpace(Z,n) + M = MatrixSpace(Z, n) # Reduction of initial bound if verbose: print('initial bound', H_q) @@ -6748,36 +6738,36 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): while break_cond < 0.9: # reduction at infinity bound_list = [] - c = R((H_q**n)*100) + c = R((H_q**n) * 100) m = copy(M.identity_matrix()) for i in range(r): - m[i, r] = R(c*mw_base_log[i]).round() - m[r,r] = max(Z(1), R(c*w1).round()) + m[i, r] = R(c * mw_base_log[i]).round() + m[r, r] = max(Z(1), R(c * w1).round()) # LLL - implemented in sage - operates on rows not on columns m_LLL = m.LLL() m_gram = m_LLL.gram_schmidt()[0] b1_norm = R(m_LLL.row(0).norm()) - #compute constant c1_LLL (cf. integral_points()) + # compute constant c1_LLL (cf. integral_points()) c1_LLL = -R.one() for i in range(n): - tmp = R(b1_norm/(m_gram.row(i).norm())) + tmp = R(b1_norm / (m_gram.row(i).norm())) c1_LLL = max(tmp, c1_LLL) if c1_LLL < 0: raise RuntimeError('Unexpected intermediate result. Please try another Mordell-Weil base') d_L_0 = R(b1_norm**2 / c1_LLL) - #Reducing of upper bound + # Reducing of upper bound Q = r * H_q**2 - T = (1 + (Z(3)/2*r*H_q))/2 - if d_L_0 < R(T**2+Q): - d_L_0 = 10*(T**2*Q) + T = (1 + (Z(3) / 2 * r * H_q)) / 2 + if d_L_0 < R(T**2 + Q): + d_L_0 = 10 * (T**2 * Q) low_bound = (R(d_L_0 - Q).sqrt() - T) / c ##new bound according to low_bound and upper bound ##[k5*k6 exp(-k7**H_q^2)] if low_bound != 0: - H_q_infinity = R(((low_bound/(k5*k6)).log()/(-k7)).abs().sqrt()) + H_q_infinity = R(((low_bound / (k5 * k6)).log() / (-k7)).abs().sqrt()) bound_list.append(H_q_infinity.ceil()) else: bound_list.append(H_q) @@ -6790,18 +6780,18 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): sys.stdout.flush() H_q_new = max(bound_list) - if (H_q_new > H_q): #no improvement - break_cond = 1 #stop reduction - elif (H_q_new == 1): #best possible H_q + if H_q_new > H_q: # no improvement + break_cond = 1 # stop reduction + elif H_q_new == 1: # best possible H_q H_q = H_q_new - break_cond = 1 #stop + break_cond = 1 # stop else: - break_cond = R(H_q_new/H_q) + break_cond = R(H_q_new / H_q) H_q = H_q_new - #end of reductions + # end of reductions - #search of S-integral points - #step1: via linear combination and H_q + # search of S-integral points + # step1: via linear combination and H_q x_S_int_points = set() if verbose: print('starting search of points using coefficient bound ', H_q) @@ -6814,13 +6804,13 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): print(L) sys.stdout.flush() - #step 2: Extra search + # step 2: Extra search if e3 < 0: - M = R( max((27*c4).abs().sqrt(), R((54*c6).abs()**(1/3)) / R(2**(1/3))-1) ) + M = R(max((27 * c4).abs().sqrt(), R((54 * c6).abs() ** (1 / 3)) / R(2 ** (1 / 3)) - 1)) else: M = R(0) - e0 = max(e1+e2, 2*e3) + M - abs_bound = R((max(0,e0)+6*b2.abs())/36) + e0 = max(e1 + e2, 2 * e3) + M + abs_bound = R((max(0, e0) + 6 * b2.abs()) / 36) if proof: if verbose: @@ -6840,14 +6830,14 @@ def S_integral_x_coords_with_abs_bounded_by(abs_bound): for x in x_S_int_points: P = E.lift_x(x) for T in tors_points: - Q = P+T + Q = P + T if not Q.is_zero() and Q[0].is_S_integral(S): x_S_int_points_t = x_S_int_points_t.union([Q[0]]) x_S_int_points = x_S_int_points.union(x_S_int_points_t) # All x values collected, now considering "both_signs" if both_signs: - S_int_points = sum([self.lift_x(x,all=True) for x in x_S_int_points],[]) + S_int_points = sum([self.lift_x(x, all=True) for x in x_S_int_points], []) else: S_int_points = [self.lift_x(x) for x in x_S_int_points] S_int_points.sort() @@ -6955,6 +6945,7 @@ def integral_points_with_bounded_mw_coeffs(E, mw_base, N, x_bound): True """ from sage.groups.generic import multiples + xs = set() tors_points = E.torsion_points() r = len(mw_base) @@ -6974,12 +6965,12 @@ def use_t(R): integral. """ for T in tors_points: - use(R+T) + use(R + T) # We use a naive method when the number of possibilities is small: if r == 1 and N <= 10: - for P in multiples(mw_base[0],N+1): + for P in multiples(mw_base[0], N + 1): use_t(P) return xs @@ -6990,7 +6981,7 @@ def use_t(R): # on the x- and y-coordinates. def is_approx_integral(rx): - r""" Local function. Return P if the real number `rx` is approximately + r"""Local function. Return P if the real number `rx` is approximately integral and rounds to a valid integral x-coordinate of an integral point P on E, else 0. """ @@ -7000,7 +6991,7 @@ def is_approx_integral(rx): return 0 prec = (2 * RealField()(x_bound).log(2)).ceil() - #print("coeff bound={}, x_bound = {}, using {} bits precision".format(N,x_bound,prec)) + # print("coeff bound={}, x_bound = {}, using {} bits precision".format(N,x_bound,prec)) RR = RealField(prec) ER = E.change_ring(RR) ER0 = ER(0) @@ -7011,7 +7002,7 @@ def is_approx_integral(rx): Rgens = [ER.lift_x(P[0]) for P in mw_base] for i in range(r): - if abs(Rgens[i][1]-mw_base[i][1]) > abs((-Rgens[i])[1]-mw_base[i][1]): + if abs(Rgens[i][1] - mw_base[i][1]) > abs((-Rgens[i])[1] - mw_base[i][1]): Rgens[i] = -Rgens[i] # the ni loop through all tuples (a1,a2,...,ar) with @@ -7020,12 +7011,12 @@ def is_approx_integral(rx): # Initialization: ni = [-N for i in range(r)] - RgensN = [-N*P for P in Rgens] + RgensN = [-N * P for P in Rgens] # RPi[i] = -N*(Rgens[0]+...+Rgens[i]) RPi = [0 for j in range(r)] RPi[0] = RgensN[0] - for i in range(1,r): - RPi[i] = RPi[i-1] + RgensN[i] + for i in range(1, r): + RPi[i] = RPi[i - 1] + RgensN[i] tors_points_R = [ER(_) for _ in tors_points] while True: @@ -7034,25 +7025,25 @@ def is_approx_integral(rx): break # test the ni-combination which is RPi[r-1] - RP = RPi[r-1] + RP = RPi[r - 1] for T, TR in zip(tors_points, tors_points_R): use(is_approx_integral((RP + TR)[0])) # increment indices and stored points - i0 = r-1 + i0 = r - 1 while ni[i0] == N: ni[i0] = -N i0 -= 1 ni[i0] += 1 # The next lines are to prevent rounding error: (-P)+P behaves # badly for real points! - if all(n == 0 for n in ni[0:i0+1]): + if all(n == 0 for n in ni[0 : i0 + 1]): RPi[i0] = ER0 else: RPi[i0] += Rgens[i0] - for i in range(i0+1,r): - RPi[i] = RPi[i-1] + RgensN[i] + for i in range(i0 + 1, r): + RPi[i] = RPi[i - 1] + RgensN[i] return xs @@ -7083,6 +7074,7 @@ def elliptic_curve_congruence_graph(curves): from sage.arith.functions import lcm from sage.rings.fast_arith import prime_range from sage.misc.misc_c import prod + G = Graph() G.add_vertices([curve.cremona_label() for curve in curves]) n = len(curves) @@ -7103,6 +7095,5 @@ def elliptic_curve_congruence_graph(curves): if n != 0: p_edges = [p for p in p_edges if p.divides(n)] if p_edges: - G.add_edge(E.cremona_label(), F.cremona_label(), - p_edges) + G.add_edge(E.cremona_label(), F.cremona_label(), p_edges) return G diff --git a/src/sage/schemes/elliptic_curves/ell_tate_curve.py b/src/sage/schemes/elliptic_curves/ell_tate_curve.py index 7defaf1d50c..616f8d00823 100644 --- a/src/sage/schemes/elliptic_curves/ell_tate_curve.py +++ b/src/sage/schemes/elliptic_curves/ell_tate_curve.py @@ -25,6 +25,7 @@ - Chris Wuthrich (04/09): reformatted docstrings. """ + ###################################################################### # Copyright (C) 2007 chris wuthrich # @@ -75,6 +76,7 @@ class TateCurve(SageObject): REFERENCES: [Sil1994]_ """ + def __init__(self, E, p): r""" INPUT: @@ -191,13 +193,11 @@ def parameter(self, prec=20): def __sk(self, k, prec): q = self.parameter(prec=prec) - return sum(n ** k * q ** n / (1 - q ** n) - for n in range(1, prec + 1)) + return sum(n**k * q**n / (1 - q**n) for n in range(1, prec + 1)) def __delta(self, prec): q = self.parameter(prec=prec) - return q * prod([(1 - q**n)**24 - for n in range(1, prec + 1)]) + return q * prod([(1 - q**n) ** 24 for n in range(1, prec + 1)]) def curve(self, prec=20): r""" @@ -286,8 +286,7 @@ def E2(self, prec=20): qE = self.parameter(prec=prec) n = qE.valuation() R = Qp(p, prec) - e2 = Csq * (1 - 24 * sum(qE**i / (1 - qE**i)**2 - for i in range(1, prec // n + 5))) + e2 = Csq * (1 - 24 * sum(qE**i / (1 - qE**i) ** 2 for i in range(1, prec // n + 5))) return R(e2) def is_split(self) -> bool: @@ -349,15 +348,9 @@ def parametrisation_onto_tate_curve(self, u, prec=None): # of Elliptic curves, p. 425) powers_of_q = [(n, q**n) for n in range(1, precn)] - xx = un / (1 - un)**2 + sum(qn * un / (1 - qn * un)**2 + - qn / un / (1 - qn / un)**2 - - 2 * qn / (1 - qn)**2 - for n, qn in powers_of_q) + xx = un / (1 - un) ** 2 + sum(qn * un / (1 - qn * un) ** 2 + qn / un / (1 - qn / un) ** 2 - 2 * qn / (1 - qn) ** 2 for n, qn in powers_of_q) - yy = un**2 / (1 - un)**3 + sum(qn**2 * un**2 / (1 - qn * un)**3 - - qn / un / (1 - qn / un)**3 + - qn / (1 - qn)**2 - for n, qn in powers_of_q) + yy = un**2 / (1 - un) ** 3 + sum(qn**2 * un**2 / (1 - qn * un) ** 3 - qn / un / (1 - qn / un) ** 3 + qn / (1 - qn) ** 2 for n, qn in powers_of_q) return self.curve(prec=prec)([xx, yy]) @@ -384,11 +377,10 @@ def L_invariant(self, prec=20): 5^3 + 4*5^4 + 2*5^5 + 2*5^6 + 2*5^7 + 3*5^8 + 5^9 + O(5^10) """ if not self.is_split(): - raise RuntimeError("the curve must have split multiplicative " - "reduction") + raise RuntimeError("the curve must have split multiplicative " "reduction") qE = self.parameter(prec=prec) n = qE.valuation() - u = qE / self._p ** n + u = qE / self._p**n # the p-adic logarithm of Iwasawa normalised by log(p) = 0 return log(u) / n @@ -418,14 +410,13 @@ def _isomorphism(self, prec=20): 2 + 5 + 3*5^2 + 5^3 + 5^4 + O(5^5)] """ if not self.is_split(): - raise RuntimeError("the curve must have split multiplicative " - "reduction") + raise RuntimeError("the curve must have split multiplicative " "reduction") C = self._Csquare(prec=prec + 4).sqrt() R = Qp(self._p, prec) C = R(C) s = (C * R(self._E.a1()) - R.one()) / R(2) - r = (C ** 2 * R(self._E.a2()) + s + s ** 2) / R(3) - t = (C ** 3 * R(self._E.a3()) - r) / R(2) + r = (C**2 * R(self._E.a2()) + s + s**2) / R(3) + t = (C**3 * R(self._E.a3()) - r) / R(2) return [C, r, s, t] def _inverse_isomorphism(self, prec=20): @@ -453,10 +444,9 @@ def _inverse_isomorphism(self, prec=20): 1 + 5 + 4*5^3 + 2*5^4 + O(5^5), 5 + 2*5^2 + 3*5^4 + O(5^5)] """ if not self.is_split(): - raise RuntimeError("the curve must have split multiplicative " - "reduction") + raise RuntimeError("the curve must have split multiplicative " "reduction") u, r, s, t = self._isomorphism(prec=prec) - return [1 / u, -r / u ** 2, -s / u, (r * s - t) / u ** 3] + return [1 / u, -r / u**2, -s / u, (r * s - t) / u**3] def lift(self, P, prec=20): r""" @@ -501,8 +491,8 @@ def lift(self, P, prec=20): Eq = self.curve(prec=prec) C, r, s, t = self._isomorphism(prec=prec) - xx = r + C ** 2 * P[0] - yy = t + s * C ** 2 * P[0] + C ** 3 * P[1] + xx = r + C**2 * P[0] + yy = t + s * C**2 * P[0] + C**3 * P[1] assert Eq.defining_polynomial()(xx, yy, 1) == 0, f"bug: point ({xx}, {yy}) does not lie on the curve {Eq}" tt = -xx / yy eqhat = Eq.formal() @@ -512,7 +502,7 @@ def lift(self, P, prec=20): fac = ZZ.one() for i in range(1, 2 * prec + 1): fac *= i - u += z ** i / fac + u += z**i / fac return u def parametrisation_onto_original_curve(self, u, prec=None): @@ -549,24 +539,21 @@ def parametrisation_onto_original_curve(self, u, prec=None): (0 : 1 + O(5^30) : 0) """ if not self.is_split(): - raise ValueError("the curve must have split multiplicative " - "reduction.") + raise ValueError("the curve must have split multiplicative " "reduction.") if prec is None: prec = getattr(u, "precision_relative", lambda: 20)() P = self.parametrisation_onto_tate_curve(u, prec=prec) C, r, s, t = self._inverse_isomorphism(prec=prec) - xx = r + C ** 2 * P[0] - yy = t + s * C ** 2 * P[0] + C ** 3 * P[1] + xx = r + C**2 * P[0] + yy = t + s * C**2 * P[0] + C**3 * P[1] R = Qp(self._p, prec) E_over_Qp = self._E.base_extend(R) return E_over_Qp([xx, yy]) def __padic_sigma_square(self, u, prec): q = self.parameter(prec=prec) - return (u - 1)**2 / u * prod([((1 - q**n * u) * (1 - q**n / u) / - (1 - q**n)**2)**2 - for n in range(1, prec + 1)]) + return (u - 1) ** 2 / u * prod([((1 - q**n * u) * (1 - q**n / u) / (1 - q**n) ** 2) ** 2 for n in range(1, prec + 1)]) # the following functions are rather functions of the global curve # than the local curve @@ -597,8 +584,7 @@ def padic_height(self, prec=20): O(5^9) """ if not self.is_split(): - raise NotImplementedError("the p-adic height is not implemented " - "for non-split multiplicative reduction.") + raise NotImplementedError("the p-adic height is not implemented " "for non-split multiplicative reduction.") p = self._p @@ -618,8 +604,8 @@ def _height(P, check=True): si = self.__padic_sigma_square(uQ, prec=precp) q = self.parameter(prec=precp) nn = q.valuation() - qEu = q / p ** nn - res = -(log(si * self._Csquare(prec=precp) / cQ) + log(uQ)**2 / log(qEu)) / n**2 + qEu = q / p**nn + res = -(log(si * self._Csquare(prec=precp) / cQ) + log(uQ) ** 2 / log(qEu)) / n**2 R = Qp(self._p, prec) return R(res) @@ -653,8 +639,7 @@ def padic_regulator(self, prec=20): return K.one() if not self.is_split(): - raise NotImplementedError("the p-adic regulator is not implemented " - "for non-split multiplicative reduction.") + raise NotImplementedError("the p-adic regulator is not implemented " "for non-split multiplicative reduction.") basis = self._E.gens() M = matrix(K, rank, rank, 0) @@ -663,7 +648,7 @@ def padic_regulator(self, prec=20): point_height = [height(P) for P in basis] for i in range(rank): for j in range(i + 1, rank): - M[i, j] = M[j, i] = (- point_height[i] - point_height[j] + height(basis[i] + basis[j])) / 2 + M[i, j] = M[j, i] = (-point_height[i] - point_height[j] + height(basis[i] + basis[j])) / 2 for i in range(rank): M[i, i] = point_height[i] diff --git a/src/sage/schemes/elliptic_curves/ell_torsion.py b/src/sage/schemes/elliptic_curves/ell_torsion.py index ade14590440..a90b4828f97 100644 --- a/src/sage/schemes/elliptic_curves/ell_torsion.py +++ b/src/sage/schemes/elliptic_curves/ell_torsion.py @@ -135,6 +135,7 @@ class EllipticCurveTorsionSubgroup(groups.AdditiveAbelianGroupWrapper): - Chris Wuthrich: initial implementation over number fields. - John Cremona: additional features and unification. """ + def __init__(self, E): r""" Initialization function for EllipticCurveTorsionSubgroup class. @@ -179,9 +180,9 @@ def __init__(self, E): groups.AdditiveAbelianGroupWrapper.__init__(self, self.__E(0).parent(), self.__torsion_gens, structure) return - T1 = E(0) # these will be the two generators + T1 = E(0) # these will be the two generators T2 = E(0) - k1 = 1 # with their order + k1 = 1 # with their order k2 = 1 # find a multiple of the order of the torsion group @@ -192,10 +193,10 @@ def __init__(self, E): ptor = E._p_primary_torsion_basis(p, e) if ptor: T1 += ptor[0][0] - k1 *= p**(ptor[0][1]) + k1 *= p ** (ptor[0][1]) if len(ptor) > 1: T2 += ptor[1][0] - k2 *= p**(ptor[1][1]) + k2 *= p ** (ptor[1][1]) if k1 == 1: structure = [] @@ -207,10 +208,9 @@ def __init__(self, E): structure = [k1, k2] gens = [T1, T2] - #self.__torsion_gens = gens + # self.__torsion_gens = gens self._structure = structure - groups.AdditiveAbelianGroupWrapper.__init__(self, T1.parent(), - [T1, T2], structure) + groups.AdditiveAbelianGroupWrapper.__init__(self, T1.parent(), [T1, T2], structure) def _repr_(self): r""" @@ -380,7 +380,7 @@ def torsion_bound(E, number_of_places=20): if den != 1: x = f.parent().gen() n = f.degree() - f = den**n * f(x/den) + f = den**n * f(x / den) disc_f = f.discriminant() d = K.absolute_degree() @@ -428,6 +428,7 @@ def torsion_bound(E, number_of_places=20): def red(c): return Fq.sum(Fq(c[j]) * ai**j for j in range(d)) + new_bound = EllipticCurve([red(c) for c in ainvs]).cardinality() bound = bound.gcd(new_bound) if bound == 1: diff --git a/src/sage/schemes/elliptic_curves/ell_wp.py b/src/sage/schemes/elliptic_curves/ell_wp.py index 622f8fed5f3..773d96b18c0 100644 --- a/src/sage/schemes/elliptic_curves/ell_wp.py +++ b/src/sage/schemes/elliptic_curves/ell_wp.py @@ -38,7 +38,7 @@ for quadratic algorithm (see :issue:`15855`) """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2009 William Stein # # This program is free software: you can redistribute it and/or modify @@ -46,7 +46,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.rings.laurent_series_ring import LaurentSeriesRing from sage.rings.power_series_ring import PowerSeriesRing @@ -141,7 +141,7 @@ def weierstrass_p(E, prec=20, algorithm=None): if algorithm == "pari": if 0 < p <= prec + 2: - raise ValueError("for computing the Weierstrass p-function via pari, the characteristic (%s) of the underlying field must be greater than prec + 2 = %s" % (p,prec+2)) + raise ValueError("for computing the Weierstrass p-function via pari, the characteristic (%s) of the underlying field must be greater than prec + 2 = %s" % (p, prec + 2)) return compute_wp_pari(E, prec) # quadratic and fast algorithms require short Weierstrass model @@ -152,11 +152,11 @@ def weierstrass_p(E, prec=20, algorithm=None): if algorithm == "quadratic": if 0 < p <= prec + 2: - raise ValueError("for computing the Weierstrass p-function via the quadratic algorithm, the characteristic (%s) of the underlying field must be greater than prec + 2 = %s" % (p,prec+2)) + raise ValueError("for computing the Weierstrass p-function via the quadratic algorithm, the characteristic (%s) of the underlying field must be greater than prec + 2 = %s" % (p, prec + 2)) wp = compute_wp_quadratic(k, A, B, prec) elif algorithm == "fast": if 0 < p <= prec + 4: - raise ValueError("for computing the Weierstrass p-function via the fast algorithm, the characteristic (%s) of the underlying field must be greater than prec + 4 = %s" % (p,prec+4)) + raise ValueError("for computing the Weierstrass p-function via the fast algorithm, the characteristic (%s) of the underlying field must be greater than prec + 4 = %s" % (p, prec + 4)) wp = compute_wp_fast(k, A, B, prec) else: raise ValueError("unknown algorithm for computing the Weierstrass p-function") @@ -164,7 +164,7 @@ def weierstrass_p(E, prec=20, algorithm=None): R = wp.parent() z = R.gen() u = E.isomorphism_to(Esh).u - return wp(z*u) * u**2 + return wp(z * u) * u**2 def compute_wp_pari(E, prec): @@ -185,9 +185,9 @@ def compute_wp_pari(E, prec): ep = E.__pari__() wpp = ep.ellwp(n=prec) k = E.base_ring() - R = LaurentSeriesRing(k,'z') + R = LaurentSeriesRing(k, 'z') z = R.gen() - wp = z**(-2) + wp = z ** (-2) for i in range(prec): wp += k(wpp[i]) * z**i wp = wp.add_bigoh(prec) @@ -233,23 +233,23 @@ def compute_wp_quadratic(k, A, B, prec): sage: compute_wp_quadratic(E.base_ring(), E.a4(), E.a6(), prec=10) z^-2 + 41*z^2 + 88*z^4 + 11*z^6 + 57*z^8 + O(z^10) """ - m = (prec + 1)//2 + m = (prec + 1) // 2 c = [0 for j in range(m)] - c[0] = -A/5 - c[1] = -B/7 + c[0] = -A / 5 + c[1] = -B / 7 # first Z represent z^2 - R = LaurentSeriesRing(k,'z') + R = LaurentSeriesRing(k, 'z') Z = R.gen() - pe = Z**-1 + c[0]*Z + c[1]*Z**2 + pe = Z**-1 + c[0] * Z + c[1] * Z**2 for i in range(3, m): t = 0 for j in range(1, i - 1): - t += c[j-1]*c[i-2-j] - ci = (3*t)/((i-2)*(2*i+3)) + t += c[j - 1] * c[i - 2 - j] + ci = (3 * t) / ((i - 2) * (2 * i + 3)) pe += ci * Z**i - c[i-1] = ci + c[i - 1] = ci return pe(Z**2).add_bigoh(prec) @@ -286,20 +286,20 @@ def compute_wp_fast(k, A, B, m): sage: compute_wp_fast(k, k(1), k(8), 5) z^-2 + 22*z^2 + 20*z^4 + O(z^5) """ - R = PowerSeriesRing(k,'z',default_prec=m+5) + R = PowerSeriesRing(k, 'z', default_prec=m + 5) z = R.gen() s = 2 - f1 = z.add_bigoh(m+3) - n = 2*m + 4 + f1 = z.add_bigoh(m + 3) + n = 2 * m + 4 # solve the nonlinear differential equation - while (s < n): + while s < n: f1pr = f1.derivative() - next_s = 2*s - 1 + next_s = 2 * s - 1 - a = 2*f1pr - b = -(6*B*(f1**5) + 4*A*(f1**3)) - c = B*(f1**6) + A*f1**4 + 1 - (f1pr**2) + a = 2 * f1pr + b = -(6 * B * (f1**5) + 4 * A * (f1**3)) + c = B * (f1**6) + A * f1**4 + 1 - (f1pr**2) # we should really be computing only mod z^next_s here. # but we loose only a factor 2 @@ -312,7 +312,7 @@ def compute_wp_fast(k, A, B, m): R = f1 Q = R**2 - pe = 1/Q + pe = 1 / Q return pe diff --git a/src/sage/schemes/elliptic_curves/formal_group.py b/src/sage/schemes/elliptic_curves/formal_group.py index 82c3fd94677..6905eed685d 100644 --- a/src/sage/schemes/elliptic_curves/formal_group.py +++ b/src/sage/schemes/elliptic_curves/formal_group.py @@ -23,6 +23,7 @@ class EllipticCurveFormalGroup(SageObject): r""" The formal group associated to an elliptic curve. """ + def __init__(self, E): """ EXAMPLES:: @@ -176,10 +177,10 @@ def w(self, prec=20): a1, a2, a3, a4, a6 = self.curve().ainvs() current_prec = cached_prec - w = w.truncate() # work with polynomials instead of power series + w = w.truncate() # work with polynomials instead of power series - numerator_const = w.parent()([0, 0, 0, 1]) # z^3 - denominator_const = w.parent()([1, -a1, -a2]) # 1 - a_1 z - a_2 z^2 + numerator_const = w.parent()([0, 0, 0, 1]) # z^3 + denominator_const = w.parent()([1, -a1, -a2]) # 1 - a_1 z - a_2 z^2 last_prec = 0 for next_prec in misc.newton_method_sizes(prec): @@ -201,15 +202,9 @@ def w(self, prec=20): w_squared = w.square() w_cubed = (w_squared * w).truncate(next_prec) - numerator = numerator_const \ - - a3 * w_squared \ - - a4 * w_squared.shift(1) \ - - (2*a6) * w_cubed + numerator = numerator_const - a3 * w_squared - a4 * w_squared.shift(1) - (2 * a6) * w_cubed - denominator = denominator_const \ - - (2*a3) * w \ - - (2*a4) * w.shift(1) \ - - (3*a6) * w_squared + denominator = denominator_const - (2 * a3) * w - (2 * a4) * w.shift(1) - (3 * a6) * w_squared # todo: this is quite inefficient, because it gets # converted to a power series, then the power series @@ -263,7 +258,7 @@ def x(self, prec=20): prec = max(prec, 0) y = self.y(prec) t = y.parent().gen() - return -t*y + O(t**prec) + return -t * y + O(t**prec) def y(self, prec=20): r""" @@ -298,7 +293,7 @@ def y(self, prec=20): sage: EllipticCurve([0, 0, 1, -1, 0]).formal_group().y(10) -t^-3 + 1 - t + t^3 - 2*t^4 + t^5 + 2*t^6 - 6*t^7 + 6*t^8 + 3*t^9 + O(t^10) """ - prec = max(prec,0) + prec = max(prec, 0) try: pr, y = self.__y except AttributeError: @@ -306,9 +301,9 @@ def y(self, prec=20): if prec <= pr: t = y.parent().gen() return y + O(t**prec) - w = self.w(prec+6) # XXX why 6? + w = self.w(prec + 6) # XXX why 6? t = w.parent().gen() - y = -(w**(-1)) + O(t**prec) + y = -(w ** (-1)) + O(t**prec) self.__y = (prec, y) return self.__y[1] @@ -353,7 +348,7 @@ def differential(self, prec=20): - David Harvey (2006-09-10): factored out of log """ - prec = max(prec,0) + prec = max(prec, 0) try: cached_prec, omega = self.__omega except AttributeError: @@ -362,10 +357,10 @@ def differential(self, prec=20): return omega.add_bigoh(prec) a = self.curve().ainvs() - x = self.x(prec+1) - y = self.y(prec+1) + x = self.x(prec + 1) + y = self.y(prec + 1) xprime = x.derivative() - g = xprime / (2*y + a[0]*x + a[2]) + g = xprime / (2 * y + a[0] * x + a[2]) self.__omega = (prec, g.power_series().add_bigoh(prec)) return self.__omega[1] @@ -392,7 +387,7 @@ def log(self, prec=20): - David Harvey (2006-09-10): rewrote to use differential """ - return self.differential(prec-1).integral().add_bigoh(prec) + return self.differential(prec - 1).integral().add_bigoh(prec) def inverse(self, prec=20): r""" @@ -431,7 +426,7 @@ def inverse(self, prec=20): sage: F(i.parent().gen(), i) O(t^6) """ - prec = max(prec,0) + prec = max(prec, 0) try: pr, inv = self.__inverse except AttributeError: @@ -442,7 +437,7 @@ def inverse(self, prec=20): x = self.x(prec) y = self.y(prec) a1, _, a3, _, _ = self.curve().ainvs() - inv = x / ( y + a1*x + a3) # page 114 of Silverman, AEC I + inv = x / (y + a1 * x + a3) # page 114 of Silverman, AEC I inv = inv.power_series().add_bigoh(prec) self.__inverse = (prec, inv) return inv @@ -522,7 +517,7 @@ def group_law(self, prec=10): sage: F.coefficients()[t1*t2^2] -a2 """ - prec = max(prec,0) + prec = max(prec, 0) if prec <= 0: raise ValueError("The precision must be positive.") @@ -532,7 +527,7 @@ def group_law(self, prec=10): if prec == 1: return R(0) if prec == 2: - return t1 + t2 - self.curve().a1()*t1*t2 + return t1 + t2 - self.curve().a1() * t1 * t2 try: pr, F = self.__group_law @@ -541,18 +536,16 @@ def group_law(self, prec=10): except AttributeError: pass - w = self.w(prec+1) - lam = sum([w[n]*sum(t2**m * t1**(n-m-1) for m in range(n)) for n in range(3, prec+1)]) + w = self.w(prec + 1) + lam = sum([w[n] * sum(t2**m * t1 ** (n - m - 1) for m in range(n)) for n in range(3, prec + 1)]) lam = lam.add_bigoh(prec) - nu = w(t1) - lam*t1 + nu = w(t1) - lam * t1 a1, a2, a3, a4, a6 = self.curve().ainvs() - lam2 = lam*lam - lam3 = lam2*lam + lam2 = lam * lam + lam3 = lam2 * lam # note that the following formula differs from the one in Silverman page 119. # See github issue 9646 for the explanation and justification. - t3 = -t1 - t2 - \ - (a1*lam + a3*lam2 + a2*nu + 2*a4*lam*nu + 3*a6*lam2*nu) / \ - (1 + a2*lam + a4*lam2 + a6*lam3) + t3 = -t1 - t2 - (a1 * lam + a3 * lam2 + a2 * nu + 2 * a4 * lam * nu + 3 * a6 * lam2 * nu) / (1 + a2 * lam + a4 * lam2 + a6 * lam3) inv = self.inverse(prec) F = inv(t3).add_bigoh(prec) @@ -652,14 +645,14 @@ def mult_by_n(self, n, prec=10): # Our answer only needs prec-1 coefficients (since lowest term # is t^1), and x(t) = t^(-2) + ... and y(t) = t^(-3) + ..., # so we only need x(t) mod t^(prec-3) and y(t) mod t^(prec-4) - x = self.x(prec-3) - y = self.y(prec-4) - R = x.parent() # the Laurent series ring over the base ring + x = self.x(prec - 3) + y = self.y(prec - 4) + R = x.parent() # the Laurent series ring over the base ring X = self.curve().change_ring(R) P = X(x, y) # and multiply it by n, using the group law on E - Q = n*P + Q = n * P # express it in terms of the formal parameter return -Q[0] / Q[1] @@ -738,21 +731,21 @@ def sigma(self, prec=10): sage: F.sigma(5) t + 1/2*t^2 + 1/3*t^3 + 3/4*t^4 + O(t^5) """ - a1,a2,a3,a4,a6 = self.curve().ainvs() + a1, a2, a3, a4, a6 = self.curve().ainvs() k = self.curve().base_ring() fl = self.log(prec) F = fl.reverse() - S = LaurentSeriesRing(k,'z') + S = LaurentSeriesRing(k, 'z') z = S.gen() F = F(z + O(z**prec)) - wp = self.x()(F) + (a1**2 + 4*a2)/12 - g = (1/z**2 - wp).power_series() + wp = self.x()(F) + (a1**2 + 4 * a2) / 12 + g = (1 / z**2 - wp).power_series() h = g.integral().integral() sigma_of_z = z.power_series() * h.exp() - T = PowerSeriesRing(k,'t') - fl = fl(T.gen()+O(T.gen()**prec)) + T = PowerSeriesRing(k, 't') + fl = fl(T.gen() + O(T.gen() ** prec)) sigma_of_t = sigma_of_z(fl) return sigma_of_t diff --git a/src/sage/schemes/elliptic_curves/gal_reps.py b/src/sage/schemes/elliptic_curves/gal_reps.py index 88c6b4e4399..1c005140889 100644 --- a/src/sage/schemes/elliptic_curves/gal_reps.py +++ b/src/sage/schemes/elliptic_curves/gal_reps.py @@ -148,9 +148,9 @@ def _ex_set(p): 29 [0, 1, 2, 4, 25, 7] """ k = GF(p) - res = [ k(0), k(1), k(2), k(4) ] + res = [k(0), k(1), k(2), k(4)] R = k['X'] - f = R([1,-3,1]) #(X**2 - 3*X+1) + f = R([1, -3, 1]) # (X**2 - 3*X+1) ro = f.roots() for a in ro: if a[0] not in res: @@ -245,11 +245,12 @@ def elliptic_curve(self): True """ from copy import copy + return copy(self._E) -##################################################################### -# reducibility -##################################################################### + ##################################################################### + # reducibility + ##################################################################### def is_reducible(self, p): r""" @@ -297,7 +298,7 @@ def is_reducible(self, p): self.__is_reducible[p] = False return False # definitely not reducible isogeny_matrix = self._E.isogeny_class().matrix(fill=True) - v = isogeny_matrix.row(0) # first row + v = isogeny_matrix.row(0) # first row for a in v: if a != 0 and a % p == 0: self.__is_reducible[p] = True @@ -349,16 +350,17 @@ def reducible_primes(self): E = self._E j = E.j_invariant() from .isogeny_small_degree import sporadic_j - if j in sporadic_j: # includes all CM j-invariants + + if j in sporadic_j: # includes all CM j-invariants R = [sporadic_j[j]] else: - R = [l for l in [2,3,5,7,13] if len(E.isogenies_prime_degree(l)) > 0] + R = [l for l in [2, 3, 5, 7, 13] if len(E.isogenies_prime_degree(l)) > 0] self.__reducible_primes = R return R -##################################################################### -# image -##################################################################### + ##################################################################### + # image + ##################################################################### def is_surjective(self, p, A=1000): r""" @@ -472,19 +474,19 @@ def _is_surjective(self, p, A): if p == 2: # E is isomorphic to [0,b2,0,8*b4,16*b6] - b2,b4,b6,b8 = self._E.b_invariants() - f = x**3 + b2*x**2 + 8*b4*x + 16*b6 + b2, b4, b6, b8 = self._E.b_invariants() + f = x**3 + b2 * x**2 + 8 * b4 * x + 16 * b6 if not f.is_irreducible(): if len(f.roots()) > 2: self.__image_type[p] = "The image is trivial as all 2-torsion points are rational." else: self.__image_type[p] = "The image is cyclic of order 2 as there is exactly one rational 2-torsion point." - return False #, '2-torsion' + return False # , '2-torsion' if arith.is_square(f.discriminant()): self.__image_type[p] = "The image is cyclic of order 3." - return False #, "A3" + return False # , "A3" self.__image_type[p] = "The image is all of GL_2(F_2), i.e. a symmetric group of order 6." - return True #, None + return True # , None if p == 3: # Algorithm: Let f be the 3-division polynomial, which is @@ -506,21 +508,21 @@ def _is_surjective(self, p, A): # reason, so just used the NormalSubgroups command in MAGMA # and it output exactly one of index 2.) - #sage: G = SymmetricGroup(4) - #sage: [H.group_id() for H in G.conjugacy_classes_subgroups()] - #[[1, 1], [2, 1], [2, 1], [3, 1], [4, 2], [4, 2], [4, 1], [6, 1], [8, 3], [12, 3], [24, 12]] - #sage: G = GL(2,GF(3)).as_matrix_group().as_permutation_group() - #sage: [H.group_id() for H in G.conjugacy_classes_subgroups()] - #[[1, 1], [2, 1], [2, 1], [3, 1], [4, 2], [4, 1], [6, 2], [6, 1], [6, 1], [8, 4], [8, 1], [8, 3], [12, 4], [16, 8], [24, 3], [48, 29]] + # sage: G = SymmetricGroup(4) + # sage: [H.group_id() for H in G.conjugacy_classes_subgroups()] + # [[1, 1], [2, 1], [2, 1], [3, 1], [4, 2], [4, 2], [4, 1], [6, 1], [8, 3], [12, 3], [24, 12]] + # sage: G = GL(2,GF(3)).as_matrix_group().as_permutation_group() + # sage: [H.group_id() for H in G.conjugacy_classes_subgroups()] + # [[1, 1], [2, 1], [2, 1], [3, 1], [4, 2], [4, 1], [6, 2], [6, 1], [6, 1], [8, 4], [8, 1], [8, 3], [12, 4], [16, 8], [24, 3], [48, 29]] # Here's Noam Elkies proof for the other direction: - #> Let E be an elliptic curve over Q. Is the mod-3 - #> representation E[3] surjective if and only if the - #> (degree 4) division polynomial has Galois group S_4? I - #> can see why the group being S_4 implies the - #> representation is surjective, but the converse is not - #> clear to me. + # > Let E be an elliptic curve over Q. Is the mod-3 + # > representation E[3] surjective if and only if the + # > (degree 4) division polynomial has Galois group S_4? I + # > can see why the group being S_4 implies the + # > representation is surjective, but the converse is not + # > clear to me. # I would have thought that this is the easier part: to # say that E[3] is surjective is to say the 3-torsion # field Q(E[3]) has Galois group GL_2(Z/3) over Q. Let @@ -538,15 +540,15 @@ def _is_surjective(self, p, A): f = self._E.division_polynomial(3) if not f.is_irreducible(): - return False #, "reducible_3-divpoly" + return False # , "reducible_3-divpoly" n = pari(f).polgalois()[0] if n == 24: self.__image_type[p] = "The image is all of GL_2(F_3)." - return True #, None - return False #, "3-divpoly_galgroup_order_%s"%n + return True # , None + return False # , "3-divpoly_galgroup_order_%s"%n if self._E.has_cm(): - return False #, "CM" + return False # , "CM" # Now we try to prove that the rep IS surjective. @@ -570,21 +572,21 @@ def _is_surjective(self, p, A): a_ell = self._E.ap(ell) if a_ell % p != 0: if not exclude_exceptional_image: - u = k(a_ell)**2 * k(ell)**(-1) + u = k(a_ell) ** 2 * k(ell) ** (-1) if u not in ex_setp: exclude_exceptional_image = True - s = arith.kronecker(a_ell**2 - 4*ell, p) + s = arith.kronecker(a_ell**2 - 4 * ell, p) if s != 0 and s not in signs: signs.append(s) if len(signs) == 2 and exclude_exceptional_image: self.__image_type[p] = "The image is all of GL_2(F_%s)." % p - return True #,None + return True # ,None - if A == -1: # we came in from is reducible. Now go out with False + if A == -1: # we came in from is reducible. Now go out with False return False if self.is_reducible(p): - return False #, Borel + return False # , Borel # if we reach this, then we do not know if it is surjective. Most likely # not but we can't be certain. See trac 11271. @@ -668,25 +670,25 @@ def non_surjective(self, A=1000): elif not self._E.j_invariant().is_integral(): # prop 24 in Serre vs = self._E.j_invariant().denominator().prime_factors() - C1 = arith.gcd([-arith.valuation(self._E.j_invariant(),v) for v in vs]) + C1 = arith.gcd([-arith.valuation(self._E.j_invariant(), v) for v in vs]) p0 = 2 while self._E.has_bad_reduction(p0): - p0 = arith.next_prime(p0+1) - C2 = (sqrt(p0)+1)**8 - C = max(C1,C2) + p0 = arith.next_prime(p0 + 1) + C2 = (sqrt(p0) + 1) ** 8 + C = max(C1, C2) verbose("j is not integral -- Serre's bound is %s" % C) - C3 = 1 + 4*sqrt(6)*int(N)/3 * sqrt(mul([1+1.0/int(p) for p,_ in arith.factor(N)])) - C = min(C,C3) - verbose("conductor = %s, and bound is %s" % (N,C)) + C3 = 1 + 4 * sqrt(6) * int(N) / 3 * sqrt(mul([1 + 1.0 / int(p) for p, _ in arith.factor(N)])) + C = min(C, C3) + verbose("conductor = %s, and bound is %s" % (N, C)) else: # Cojocaru's bound (depends on the conductor) - C = 1 + 4*sqrt(6)*int(N)/3 * sqrt(mul([1+1.0/int(p) for p,_ in arith.factor(N)])) - verbose("conductor = %s, and bound is %s" % (N,C)) + C = 1 + 4 * sqrt(6) * int(N) / 3 * sqrt(mul([1 + 1.0 / int(p) for p, _ in arith.factor(N)])) + verbose("conductor = %s, and bound is %s" % (N, C)) B = [] p = 2 while p <= C: t = self.is_surjective(p, A=A) - verbose("(%s,%s)" % (p,t)) + verbose("(%s,%s)" % (p, t)) # both False and None will be appended here. if not t: B.append(p) @@ -862,7 +864,7 @@ def image_type(self, p): if n == 2: self.__image_type[p] = "The image is a cyclic group of order 4." elif n == 4: - for ell in prime_range(5,1000): + for ell in prime_range(5, 1000): if ell % 3 == 2 and self._E.ap(ell) % 3 != 0: # there is an element of order 8 in the image self.__image_type[p] = "The image is a cyclic group of order 8." @@ -899,14 +901,14 @@ def image_type(self, p): # we filter here a few cases and leave the rest to the computation of the Galois group later ell = 1 k = GF(p) - Np = self._E.conductor()*p + Np = self._E.conductor() * p has_an_el_order_4 = False has_an_el_order_3 = False while ell < 10000: ell = arith.next_prime(ell) if Np % ell != 0: a_ell = self._E.ap(ell) - u = k(a_ell)**2 * k(ell)**(-1) + u = k(a_ell) ** 2 * k(ell) ** (-1) if u == 3: verbose("found an element of order 6", level=2) # found an element of order 6: @@ -942,12 +944,13 @@ def image_type(self, p): f = self._E.division_polynomial(5) from sage.rings.number_field.splitting_field import SplittingFieldAbort + try: K = f.splitting_field('x', degree_multiple=240, abort_degree=24) except SplittingFieldAbort: pass else: - if K.degree() in (4,8,16): + if K.degree() in (4, 8, 16): self.__image_type[p] = split_str return self.__image_type[p] if K.degree() == 24: @@ -975,7 +978,7 @@ def image_type(self, p): ex_setp = _ex_set(p) ell = 1 k = GF(p) - Np = self._E.conductor()*p + Np = self._E.conductor() * p could_be_exc = 1 could_be_split = 1 could_be_non_split = 1 @@ -984,16 +987,16 @@ def image_type(self, p): ell = arith.next_prime(ell) if Np % ell != 0: a_ell = self._E.ap(ell) - u = k(a_ell)**2 * k(ell)**(-1) + u = k(a_ell) ** 2 * k(ell) ** (-1) if (u not in ex_setp) and could_be_exc == 1: # it can not be in the exceptional verbose("the image cannot be exceptional, found u=%s" % u, level=2) could_be_exc = 0 - if a_ell != 0 and arith.kronecker(a_ell**2 - 4*ell,p) == 1 and could_be_non_split == 1: + if a_ell != 0 and arith.kronecker(a_ell**2 - 4 * ell, p) == 1 and could_be_non_split == 1: # it can not be in the normalizer of the non-split Cartan verbose("the image cannot be non-split, found u=%s" % u, level=2) could_be_non_split = 0 - if a_ell != 0 and arith.kronecker(a_ell**2 - 4*ell,p) == -1 and could_be_split == 1: + if a_ell != 0 and arith.kronecker(a_ell**2 - 4 * ell, p) == -1 and could_be_split == 1: # it can not be in the normalizer of the split Cartan verbose("the image cannot be split, found u=%s" % u, level=2) could_be_split = 0 @@ -1017,14 +1020,14 @@ def image_type(self, p): could_be_a5 = 0 # elements of order 5 # bug corrected see trac 14577 R = k['X'] - f = R([1,-3,1]) #(X**2 - 3*X+1) + f = R([1, -3, 1]) # (X**2 - 3*X+1) el5 = f.roots() # loops over primes as long as we still have two options left while ell < 10000 and (could_be_s4 + could_be_a4 + could_be_a5 > 1): ell = arith.next_prime(ell) if Np % ell != 0: a_ell = self._E.ap(ell) - u = k(a_ell)**2 * k(ell)**(-1) + u = k(a_ell) ** 2 * k(ell) ** (-1) if u == 2: # it can not be A4 not A5 as they have no elements of order 4 could_be_a4 = 0 @@ -1034,7 +1037,7 @@ def image_type(self, p): could_be_a4 = 0 could_be_s4 = 0 - assert (could_be_s4 + could_be_a4 + could_be_a5 > 0), "bug in image_type." + assert could_be_s4 + could_be_a4 + could_be_a5 > 0, "bug in image_type." if could_be_s4 + could_be_a4 + could_be_a5 == 1: if could_be_s4 == 1: @@ -1215,18 +1218,18 @@ def image_classes(self, p, bound=10000): while ell <= bound: ell = arith.next_prime(ell) if ell != p and self._E.is_good(ell): - d = (self._E.ap(ell)**2 * ell.inverse_mod(p)) % p + d = (self._E.ap(ell) ** 2 * ell.inverse_mod(p)) % p res[d] += 1 co += 1 Rt = RealField(16) - res = [Rt(x)/Rt(co) for x in res] + res = [Rt(x) / Rt(co) for x in res] return res -##################################################################### -# classification of ell and p-adic reps -##################################################################### + ##################################################################### + # classification of ell and p-adic reps + ##################################################################### -# ell-adic reps + # ell-adic reps def is_unramified(self, p, ell): r""" @@ -1328,7 +1331,7 @@ def is_quasi_unipotent(self, p, ell): raise ValueError("quasi unipotent is not defined for l = p, use semistable instead.") return True -# p-adic reps + # p-adic reps def is_ordinary(self, p): r""" diff --git a/src/sage/schemes/elliptic_curves/gal_reps_number_field.py b/src/sage/schemes/elliptic_curves/gal_reps_number_field.py index fccfa16d206..0750f2fcbab 100644 --- a/src/sage/schemes/elliptic_curves/gal_reps_number_field.py +++ b/src/sage/schemes/elliptic_curves/gal_reps_number_field.py @@ -352,7 +352,7 @@ def isogeny_bound(self, A=100): E = _over_numberfield(self.E) K = E.base_field() - char = lambda P: P.smallest_integer() # cheaper than constructing the residue field + char = lambda P: P.smallest_integer() # cheaper than constructing the residue field # semistable reducible primes (we are now not in the CM case) bad_primes = _semistable_reducible_primes(E) @@ -475,7 +475,7 @@ def _non_surjective(E, patience=100): # the slower the rest of the computation is, so it is not clear that # this would help...) - char = lambda P: P.smallest_integer() # cheaper than constructing the residue field + char = lambda P: P.smallest_integer() # cheaper than constructing the residue field bad_primes = exceptional_primes bad_primes += [char(P) for P in SA] @@ -549,15 +549,15 @@ def Frobenius_filter(E, L, patience=100): E = _over_numberfield(E).global_integral_model() K = E.base_field() - L = list(set(L)) # Remove duplicates from L and makes a copy for output + L = list(set(L)) # Remove duplicates from L and makes a copy for output L.sort() include_2 = False - if 2 in L: # c.f. Section 5.3(a) of [Ser1972]. + if 2 in L: # c.f. Section 5.3(a) of [Ser1972]. L.remove(2) include_2 = not E.division_polynomial(2).is_irreducible() - K_is_Q = (K == QQ) + K_is_Q = K == QQ from sage.arith.misc import primes from sage.rings.infinity import infinity @@ -631,19 +631,19 @@ def _exceptionals(E, L, patience=1000): output = [] - L = list(set(L)) # Remove duplicates from L. + L = list(set(L)) # Remove duplicates from L. for l in L: - if l == 2: # c.f. Section 5.3(a) of [Ser1972]. + if l == 2: # c.f. Section 5.3(a) of [Ser1972]. if (E.j_invariant() - 1728).is_square(): output.append(2) elif not E.division_polynomial(2).is_irreducible(): output.append(2) - elif l == 3: # c.f. Section 5.3(b) of [Ser1972]. + elif l == 3: # c.f. Section 5.3(b) of [Ser1972]. if K(-3).is_square(): output.append(3) - elif not (K['x'].gen()**3 - E.j_invariant()).is_irreducible(): + elif not (K['x'].gen() ** 3 - E.j_invariant()).is_irreducible(): output.append(3) elif not E.division_polynomial(3).is_irreducible(): output.append(3) @@ -679,7 +679,7 @@ def _exceptionals(E, L, patience=1000): for P in deg_one_primes_iter(K): try: trace = E.change_ring(P.residue_field()).trace_of_frobenius() - except ArithmeticError: # Bad reduction at P. + except ArithmeticError: # Bad reduction at P. continue patience -= 1 @@ -687,7 +687,7 @@ def _exceptionals(E, L, patience=1000): determinant = P.norm() discriminant = trace**2 - 4 * determinant - unexc = [] # Primes we discover are unexceptional go here. + unexc = [] # Primes we discover are unexceptional go here. for l in D: tr = GF(l)(trace) @@ -716,7 +716,7 @@ def _exceptionals(E, L, patience=1000): if det != 0: # c.f. [Ser1972], Section 2.8, Prop. 19 u = trace**2 / det - if u not in (1, 2, 4) and u**2 - 3 * u + 1 != 0: + if u not in (1, 2, 4) and u ** 2 - 3 * u + 1 != 0: D[l][2] = False if D[l] == [False, False, False]: @@ -764,6 +764,7 @@ def _over_numberfield(E): if K == QQ: from sage.rings.polynomial.polynomial_ring import polygen + K = NumberField(polygen(QQ), 'a') else: K = K.absolute_field('a') @@ -806,9 +807,9 @@ def deg_one_primes_iter(K, principal_only=False): Fractional ideal (3*a - 4)] """ # imaginary quadratic fields have no principal primes of norm < disc / 4 - start = K.discriminant().abs() // 4 if principal_only and K.signature() == (0,1) else 2 + start = K.discriminant().abs() // 4 if principal_only and K.signature() == (0, 1) else 2 - K_is_Q = (K == QQ) + K_is_Q = K == QQ for p in primes(start=start, stop=Infinity): if K_is_Q: @@ -867,7 +868,7 @@ def _semistable_reducible_primes(E, verbose=False): # a generator and the characteristic polynomial of Frob_P^12. precomp = [] - last_p = 0 # The residue characteristic of the most recent prime. + last_p = 0 # The residue characteristic of the most recent prime. while len(precomp) < 2: P = next(deg_one_primes) @@ -882,16 +883,16 @@ def _semistable_reducible_primes(E, verbose=False): EmodPy = E.reduction(Py) if d > 1 else E.reduction(y) fxpol = EmodPx.frobenius_polynomial() fypol = EmodPy.frobenius_polynomial() - fx12pol = fxpol.adams_operator_on_roots(12) # roots are 12th powers of those of fxpol + fx12pol = fxpol.adams_operator_on_roots(12) # roots are 12th powers of those of fxpol fy12pol = fypol.adams_operator_on_roots(12) px = x.norm() if d > 1 else x py = y.norm() if d > 1 else x Zx = fxpol.parent() - xpol = x.charpoly() if d > 1 else Zx([-x,1]) - ypol = y.charpoly() if d > 1 else Zx([-y,1]) + xpol = x.charpoly() if d > 1 else Zx([-x, 1]) + ypol = y.charpoly() if d > 1 else Zx([-y, 1]) if verbose: - print("Finished precomp, x={} (p={}), y={} (p={})".format(x,px,y,py)) + print("Finished precomp, x={} (p={}), y={} (p={})".format(x, px, y, py)) for w in range(1 + d // 2): if verbose: @@ -934,14 +935,14 @@ def _semistable_reducible_primes(E, verbose=False): # See #19229: the names given here, which are not used, should # not be the name of the generator of the base field. - rootsa = K(a).sqrt(all=True) # otherwise if a is not a square the - # returned result is in the symbolic ring! + rootsa = K(a).sqrt(all=True) # otherwise if a is not a square the + # returned result is in the symbolic ring! try: roota = rootsa[0] except IndexError: - raise RuntimeError("error in _semistable_reducible_primes: K={} does not contain sqrt({})".format(K,a)) - K_rel = K.relativize(roota, ['name1','name2']) - iso = K_rel.structure()[1] # an isomorphism from K to K_rel + raise RuntimeError("error in _semistable_reducible_primes: K={} does not contain sqrt({})".format(K, a)) + K_rel = K.relativize(roota, ['name1', 'name2']) + iso = K_rel.structure()[1] # an isomorphism from K to K_rel ## We try again to find a nontrivial divisibility condition. ## @@ -952,7 +953,7 @@ def _semistable_reducible_primes(E, verbose=False): # TODO: Is this the best value for this parameter? while div == 0 and patience > 0: - P = next(deg_one_primes) # a prime of K not K_rel + P = next(deg_one_primes) # a prime of K not K_rel while E.has_bad_reduction(P): P = next(deg_one_primes) @@ -964,7 +965,7 @@ def _semistable_reducible_primes(E, verbose=False): print("...good reduction, frobenius poly = {}".format(fpol)) x = iso(P.gens_reduced()[0]).relative_norm() xpol = x.charpoly().adams_operator_on_roots(12) - div2 = Integer(xpol.resultant(fpol.adams_operator_on_roots(12)) // x.norm()**12) + div2 = Integer(xpol.resultant(fpol.adams_operator_on_roots(12)) // x.norm() ** 12) if div2: div = div2.isqrt() assert div2 == div**2 @@ -985,7 +986,7 @@ def _semistable_reducible_primes(E, verbose=False): xprimes = div.prime_factors() if verbose: - print("...adding prime factors {} of {} to {}...".format(xprimes,div, sorted(bad_primes))) + print("...adding prime factors {} of {} to {}...".format(xprimes, div, sorted(bad_primes))) bad_primes.update(xprimes) if verbose: print("...done, bad_primes now {}".format(sorted(bad_primes))) @@ -1036,7 +1037,7 @@ def _possible_normalizers(E, SA): K = E.base_field() SA = [K.ideal(I.gens()) for I in SA] - selmer_gens = K.selmer_generators(SA, 2) # Generators of the selmer group. + selmer_gens = K.selmer_generators(SA, 2) # Generators of the selmer group. if not selmer_gens: return [] @@ -1060,7 +1061,7 @@ def _possible_normalizers(E, SA): # to zero if any elements of the selmer group are # zero mod P (i.e. the character is ramified). - splitting_vector = [] # This will be the values of this + splitting_vector = [] # This will be the values of this # character on the generators of the Selmer group. for a in selmer_gens: @@ -1083,7 +1084,7 @@ def _possible_normalizers(E, SA): try: Etilde = E.change_ring(k) - except ArithmeticError: # Bad reduction. + except ArithmeticError: # Bad reduction. continue tr = Etilde.trace_of_frobenius() @@ -1127,7 +1128,7 @@ def _possible_normalizers(E, SA): if not k(a).is_square(): try: tr = E.change_ring(k).trace_of_frobenius() - except ArithmeticError: # Bad reduction. + except ArithmeticError: # Bad reduction. continue if tr == 0: @@ -1140,6 +1141,7 @@ def _possible_normalizers(E, SA): bad_primes = sorted(bad_primes) return bad_primes + # # Code for Billerey's algorithm to find reducible primes # @@ -1177,10 +1179,11 @@ def Billerey_P_l(E, l): # return None from sage.rings.polynomial.polynomial_ring import polygen from operator import mul - P = polygen(ZZ)-1 + + P = polygen(ZZ) - 1 for q in qq: e = K(l).valuation(q) - P = P.composed_op(E.reduction(q).frobenius_polynomial().adams_operator_on_roots(12*e), mul, monic=True) + P = P.composed_op(E.reduction(q).frobenius_polynomial().adams_operator_on_roots(12 * e), mul, monic=True) return P @@ -1219,7 +1222,7 @@ def Billerey_B_l(E, l, B=0): # We compute the factors one at a time since if any is 0 we quit: B_l = ZZ(1) for k in range(1 + d // 2): - factor = ZZ(P(l**(12*k))) + factor = ZZ(P(l ** (12 * k))) if factor: B_l *= factor.gcd(B) else: @@ -1256,7 +1259,7 @@ def Billerey_R_q(E, q, B=0): K = E.base_field() d = K.absolute_degree() h = K.class_number() - P = E.reduction(q).frobenius_polynomial().adams_operator_on_roots(12*h) + P = E.reduction(q).frobenius_polynomial().adams_operator_on_roots(12 * h) Q = ((q**h).gens_reduced()[0]).absolute_minpoly().adams_operator_on_roots(12) # We compute the factors one at a time since if any is 0 we quit: @@ -1330,20 +1333,21 @@ def Billerey_B_bound(E, max_l=200, num_l=8, small_prime_bound=0, debug=False): 1 """ if debug: - print("Computing B-bound for {} with max_l={}, num_l={}".format(E.ainvs(),max_l,num_l) + " (ignoring primes under {})".format(small_prime_bound) if small_prime_bound else "") + print("Computing B-bound for {} with max_l={}, num_l={}".format(E.ainvs(), max_l, num_l) + " (ignoring primes under {})".format(small_prime_bound) if small_prime_bound else "") B = ZZ.zero() ells = [] K = E.base_field() DK = K.discriminant() ED = E.discriminant().norm() - B0 = ZZ(6*DK*ED) + B0 = ZZ(6 * DK * ED) def remove_primes(B): B1 = B.prime_to_m_part(B0) for p in primes(small_prime_bound): B1 = B1.prime_to_m_part(p) return B1 - ll = primes(5,max_l) # iterator + + ll = primes(5, max_l) # iterator while B != 1 and len(ells) < num_l: try: l = next(ll) @@ -1353,7 +1357,7 @@ def remove_primes(B): break if debug: print("..trying l={}".format(l)) - b = Billerey_B_l(E,l,B) + b = Billerey_B_l(E, l, B) if b: if debug: print("..ok, B_l = {}".format(b)) @@ -1363,13 +1367,13 @@ def remove_primes(B): B = remove_primes(b) ells.append(l) if debug: - print("..so far, B = {} using l in {}".format(B,ells)) + print("..so far, B = {} using l in {}".format(B, ells)) else: if debug: print("..B_l=0 for l={}".format(l)) if B: - res = [p for p,e in B.factor()] + res = [p for p, e in B.factor()] if debug: print("..returning {}".format(res)) return res @@ -1440,20 +1444,21 @@ def Billerey_R_bound(E, max_l=200, num_l=8, small_prime_bound=None, debug=False) 1 """ if debug: - print("Computing R-bound for {} with max_l={}, num_l={}".format(E.ainvs(),max_l,num_l) + " (ignoring primes under {})".format(small_prime_bound) if small_prime_bound else "") + print("Computing R-bound for {} with max_l={}, num_l={}".format(E.ainvs(), max_l, num_l) + " (ignoring primes under {})".format(small_prime_bound) if small_prime_bound else "") B = ZZ.zero() ells = [] K = E.base_field() DK = K.discriminant() ED = E.discriminant().norm() - B0 = ZZ(6*DK*ED) + B0 = ZZ(6 * DK * ED) def remove_primes(B): B1 = B.prime_to_m_part(B0) for p in primes(small_prime_bound): B1 = B1.prime_to_m_part(p) return B1 - ll = primes(5, max_l) # iterator + + ll = primes(5, max_l) # iterator while len(ells) < num_l and B != 1: try: l = next(ll) @@ -1463,18 +1468,18 @@ def remove_primes(B): break q = K.prime_above(l) if debug: - print("..trying q={} above l={}".format(q,l)) - b = Billerey_R_q(E,q,B) + print("..trying q={} above l={}".format(q, l)) + b = Billerey_R_q(E, q, B) if b: if debug: - print("..ok, R_q = {}, type={}".format(b,type(b))) + print("..ok, R_q = {}, type={}".format(b, type(b))) if B: B = B.gcd(b) else: B = remove_primes(b) ells.append(l) if debug: - print("..so far, B = {} using l in {}".format(B,ells)) + print("..so far, B = {} using l in {}".format(B, ells)) if B: res = B.support() @@ -1555,7 +1560,7 @@ def reducible_primes_Billerey(E, num_l=None, max_l=None, verbose=False): sage: len(C) # long time 4 """ - #verbose=True + # verbose=True if verbose: print("E = {}, finding reducible primes using Billerey's algorithm".format(E.ainvs())) @@ -1572,7 +1577,7 @@ def reducible_primes_Billerey(E, num_l=None, max_l=None, verbose=False): # function and the helper functions need this: E1 = E.global_integral_model() ED = E1.discriminant().norm() - B0 = ZZ(6*DK*ED).prime_divisors() + B0 = ZZ(6 * DK * ED).prime_divisors() # Billeray's algorithm will be faster if we tell it to ignore # small primes; these can be tested using the naive algorithm. @@ -1590,10 +1595,10 @@ def reducible_primes_Billerey(E, num_l=None, max_l=None, verbose=False): if verbose: print("... B_bound ineffective using max_l={}, moving on to R-bound".format(max_l)) - B1 = Billerey_R_bound(E1,max_l, num_l, max_small_prime, verbose) + B1 = Billerey_R_bound(E1, max_l, num_l, max_small_prime, verbose) if B1 == [0]: if verbose: - print("... R_bound ineffective using max_l={}",format(max_l)) + print("... R_bound ineffective using max_l={}", format(max_l)) return [0] if verbose: print("... R_bound = {}".format(B1)) diff --git a/src/sage/schemes/elliptic_curves/gp_simon.py b/src/sage/schemes/elliptic_curves/gp_simon.py index a1bc0f504ac..3459a875e4a 100644 --- a/src/sage/schemes/elliptic_curves/gp_simon.py +++ b/src/sage/schemes/elliptic_curves/gp_simon.py @@ -32,8 +32,7 @@ simon_dir = Path(SAGE_EXTCODE) / 'pari' / 'simon' -def simon_two_descent(E, verbose=0, lim1=None, lim3=None, limtriv=None, - maxprob=20, limbigprime=30, known_points=[]): +def simon_two_descent(E, verbose=0, lim1=None, lim3=None, limtriv=None, maxprob=20, limbigprime=30, known_points=[]): """ Interface to Simon's gp script for two-descent. @@ -131,8 +130,7 @@ def simon_two_descent(E, verbose=0, lim1=None, lim3=None, limtriv=None, if limtriv is None: limtriv = 2 - pari('DEBUGLEVEL_ell=%s; LIM1=%s; LIM3=%s; LIMTRIV=%s; MAXPROB=%s; LIMBIGPRIME=%s;' % ( - verbose, lim1, lim3, limtriv, maxprob, limbigprime)) + pari('DEBUGLEVEL_ell=%s; LIM1=%s; LIM3=%s; LIMTRIV=%s; MAXPROB=%s; LIMBIGPRIME=%s;' % (verbose, lim1, lim3, limtriv, maxprob, limbigprime)) try: if over_QQ: diff --git a/src/sage/schemes/elliptic_curves/heegner.py b/src/sage/schemes/elliptic_curves/heegner.py index 7658101020f..c864606e88d 100644 --- a/src/sage/schemes/elliptic_curves/heegner.py +++ b/src/sage/schemes/elliptic_curves/heegner.py @@ -100,8 +100,7 @@ import sage.rings.abc from sage.arith.functions import lcm -from sage.arith.misc import (binomial, factorial, prime_divisors, - GCD as gcd, XGCD as xgcd) +from sage.arith.misc import binomial, factorial, prime_divisors, GCD as gcd, XGCD as xgcd from sage.matrix.constructor import matrix from sage.matrix.matrix_space import MatrixSpace from sage.misc.cachefunc import cached_method @@ -119,8 +118,7 @@ from sage.rings.number_field.number_field_element_base import NumberFieldElement_base from sage.rings.rational_field import QQ from sage.structure.sage_object import SageObject -from sage.structure.richcmp import (richcmp_method, richcmp, - richcmp_not_equal, rich_to_bool) +from sage.structure.richcmp import richcmp_method, richcmp, richcmp_not_equal, rich_to_bool lazy_import('sage.rings.complex_double', 'CDF') lazy_import('sage.rings.complex_mpfr', 'ComplexField') @@ -215,6 +213,7 @@ def heegner_point(N, D=None, c=1): # # ############################################################################ + class RingClassField(SageObject): """ A Ring class field of a quadratic imaginary field of given conductor. @@ -242,6 +241,7 @@ class RingClassField(SageObject): sage: loads(dumps(K_c)) == K_c True """ + def __init__(self, D, c, check=True): """ INPUT: @@ -487,13 +487,13 @@ def degree_over_H(self): F = K.factor(p) if len(F) == 2: # split case - n *= p**e - p**(e-1) + n *= p**e - p ** (e - 1) elif F[0][1] > 1: # ramified case n *= p**e else: # inert case - n *= p**e + p**(e-1) + n *= p**e + p ** (e - 1) return (n * ZZ(2)) // K.number_of_roots_of_unity() @cached_method @@ -589,8 +589,8 @@ def is_subfield(self, M) -> bool: """ if not isinstance(M, RingClassField): raise TypeError("M must be a ring class field") - return self.quadratic_field() == M.quadratic_field() and \ - M.conductor() % self.conductor() == 0 + return self.quadratic_field() == M.quadratic_field() and M.conductor() % self.conductor() == 0 + # ############################################################################## # @@ -624,6 +624,7 @@ class GaloisGroup(SageObject): sage: type(G) """ + def __init__(self, field, base=QQ) -> None: r""" INPUT: @@ -666,7 +667,7 @@ def __eq__(self, G) -> bool: sage: G == H False """ - return isinstance(G, GaloisGroup) and (G.__field,G.__base) == (self.__field,self.__base) + return isinstance(G, GaloisGroup) and (G.__field, G.__base) == (self.__field, self.__base) def __ne__(self, other) -> bool: """ @@ -932,7 +933,7 @@ def _list(self): # forms of discriminant D*c^2. D = self.base_field().discriminant() c = self.field().conductor() - Q = [f for f in BinaryQF_reduced_representatives(D*c*c) if f.is_primitive()] + Q = [f for f in BinaryQF_reduced_representatives(D * c * c) if f.is_primitive()] v = [GaloisAutomorphismQuadraticForm(self, f) for f in Q] elif self._base_is_hilbert_class_field() and self.is_kolyvagin(): @@ -980,9 +981,9 @@ def _quadratic_form_to_alpha(self, f): ... ValueError: quadratic form has the wrong discriminant """ - A,B,C = f + A, B, C = f K = self.field().quadratic_field() - if f.discriminant() != self.field().conductor()**2 * K.discriminant(): + if f.discriminant() != self.field().conductor() ** 2 * K.discriminant(): raise ValueError("quadratic form has the wrong discriminant") R = K['X'] @@ -1058,8 +1059,8 @@ def _alpha_to_p1_element(self, alpha) -> tuple: w /= n c = P1.N() w = P1.normalize(ZZ(w[0]) % c, ZZ(w[1]) % c) - if w == (0,0): - w = (1,0) + if w == (0, 0): + w = (1, 0) return w def _p1_element_to_alpha(self, uv): @@ -1250,6 +1251,7 @@ class GaloisAutomorphism(SageObject): make :class:`GaloisAutomorphism` derive from GroupElement, so that one gets powers for free, etc. """ + def __init__(self, parent) -> None: """ INPUT: @@ -1316,6 +1318,7 @@ class GaloisAutomorphismComplexConjugation(GaloisAutomorphism): sage: loads(dumps(conj)) == conj True """ + def __init__(self, parent) -> None: """ INPUT: @@ -1357,8 +1360,7 @@ def __eq__(self, right) -> bool: sage: conj == conj2 True """ - return isinstance(right, GaloisAutomorphismComplexConjugation) and \ - self.parent() == right.parent() + return isinstance(right, GaloisAutomorphismComplexConjugation) and self.parent() == right.parent() def __ne__(self, other) -> bool: """ @@ -1384,17 +1386,17 @@ def _repr_(self) -> str: """ return "Complex conjugation automorphism of %s" % self.domain() -# def __mul__(self, right): -# """ -# Return the composition of two automorphisms. + # def __mul__(self, right): + # """ + # Return the composition of two automorphisms. -# EXAMPLES:: + # EXAMPLES:: -# sage: ? -# """ -# if self.parent() != right.__parent(): -# raise TypeError("automorphisms must be of the same class field") -# raise NotImplementedError + # sage: ? + # """ + # if self.parent() != right.__parent(): + # raise TypeError("automorphisms must be of the same class field") + # raise NotImplementedError def __invert__(self): """ @@ -1435,6 +1437,7 @@ class GaloisAutomorphismQuadraticForm(GaloisAutomorphism): sage: loads(dumps(sigma)) == sigma True """ + def __init__(self, parent, quadratic_form, alpha=None) -> None: r""" INPUT: @@ -1678,7 +1681,8 @@ def ideal(self): A, B, C = f if A % c == 0: A, C = C, A - return K.fractional_ideal([A, (-B+c*sqrtD)/2]) + return K.fractional_ideal([A, (-B + c * sqrtD) / 2]) + ## def __call__(self, z): ## """ @@ -1738,6 +1742,7 @@ class HeegnerPoint(SageObject): sage: loads(dumps(x)) == x True """ + def __init__(self, N, D, c) -> None: """ INPUT: @@ -1786,8 +1791,7 @@ def __richcmp__(self, x, op) -> bool: """ if not isinstance(x, HeegnerPoint): return NotImplemented - return richcmp((self.__N, self.__D, self.__c), - (x.__N, x.__D, x.__c), op) + return richcmp((self.__N, self.__D, self.__c), (x.__N, x.__D, x.__c), op) def _repr_(self) -> str: """ @@ -1799,8 +1803,7 @@ def _repr_(self) -> str: sage: H._repr_() 'Heegner point of level 389, discriminant -7, and conductor 5' """ - return "Heegner point of level %s, discriminant %s, and conductor %s" % ( - self.__N, self.__D, self.__c) + return "Heegner point of level %s, discriminant %s, and conductor %s" % (self.__N, self.__D, self.__c) def __hash__(self) -> int: """ @@ -1911,7 +1914,7 @@ def quadratic_order(self): [1, 11*sqrt_minus_40] """ K = self.quadratic_field() - return K.order([1,self.conductor()*K.gen()]) + return K.order([1, self.conductor() * K.gen()]) @cached_method def ring_class_field(self): @@ -1950,6 +1953,7 @@ def ring_class_field(self): # # ############################################################################## + class HeegnerPoints(SageObject): """ The set of Heegner points with given parameters. @@ -1963,6 +1967,7 @@ class HeegnerPoints(SageObject): sage: isinstance(H, sage.schemes.elliptic_curves.heegner.HeegnerPoints) True """ + def __init__(self, N) -> None: """ INPUT: @@ -2008,6 +2013,7 @@ class HeegnerPoints_level(HeegnerPoints): sage: loads(dumps(H)) == H True """ + def __eq__(self, other) -> bool: """ EXAMPLES:: @@ -2134,6 +2140,7 @@ class HeegnerPoints_level_disc(HeegnerPoints): sage: loads(dumps(H)) == H True """ + def __init__(self, N, D) -> None: """ INPUT: @@ -2149,8 +2156,8 @@ def __init__(self, N, D) -> None: """ HeegnerPoints.__init__(self, N) D = ZZ(D) - if not satisfies_weak_heegner_hypothesis(N,D): - raise ValueError("D (=%s) must satisfy the weak Heegner hypothesis for N (=%s)" % (D,N)) + if not satisfies_weak_heegner_hypothesis(N, D): + raise ValueError("D (=%s) must satisfy the weak Heegner hypothesis for N (=%s)" % (D, N)) self.__D = D def __eq__(self, other) -> bool: @@ -2165,8 +2172,7 @@ def __eq__(self, other) -> bool: sage: H == heegner_points(389,-11) False """ - return isinstance(other, HeegnerPoints_level_disc) and \ - self.level() == other.level() and self.__D == other.__D + return isinstance(other, HeegnerPoints_level_disc) and self.level() == other.level() and self.__D == other.__D def __ne__(self, other) -> bool: """ @@ -2192,8 +2198,7 @@ def _repr_(self) -> str: sage: heegner_points(389,-7)._repr_() 'Set of all Heegner points on X_0(389) associated to QQ[sqrt(-7)]' """ - return "Set of all Heegner points on X_0(%s) associated to QQ[sqrt(%s)]" % ( - self.level(), self.discriminant()) + return "Set of all Heegner points on X_0(%s) associated to QQ[sqrt(%s)]" % (self.level(), self.discriminant()) def discriminant(self): r""" @@ -2261,7 +2266,7 @@ def kolyvagin_conductors(self, r=None, n=10, E=None, m=None) -> list: [85, 205, 295, 415, 697] """ D = self.__D - if not satisfies_weak_heegner_hypothesis(self.level(),D): + if not satisfies_weak_heegner_hypothesis(self.level(), D): raise ValueError("D must satisfy the weak Heegner hypothesis") n = ZZ(n) if n <= 0: @@ -2326,7 +2331,7 @@ def is_kolyvagin_conductor(N, E, D, r, n, c) -> bool: sage: is_kolyvagin_conductor(389, EllipticCurve('389a'), -7, 1, 11, 5) False """ - ND = N*D + ND = N * D if ND.gcd(c) != 1: return False if not c.is_squarefree(): @@ -2340,7 +2345,7 @@ def is_kolyvagin_conductor(N, E, D, r, n, c) -> bool: return False if E is not None and n is not None: for p in P: - if (p+1).gcd(E.ap(p)) % n != 0: + if (p + 1).gcd(E.ap(p)) % n != 0: return False return True @@ -2382,6 +2387,7 @@ class HeegnerPoints_level_disc_cond(HeegnerPoints_level, HeegnerPoints_level_dis sage: loads(dumps(H)) == H True """ + def __init__(self, N, D, c=ZZ.one()) -> None: """ Create set of Heegner points. @@ -2417,9 +2423,7 @@ def __eq__(self, other) -> bool: sage: H == 0 False """ - return isinstance(other, HeegnerPoints_level_disc_cond) and \ - self.level() == other.level() and self.discriminant() == other.discriminant() \ - and self.conductor() == other.conductor() + return isinstance(other, HeegnerPoints_level_disc_cond) and self.level() == other.level() and self.discriminant() == other.discriminant() and self.conductor() == other.conductor() def __ne__(self, other) -> bool: """ @@ -2444,8 +2448,7 @@ def _repr_(self) -> str: sage: H = heegner_points(37,-7,5); H._repr_() 'All Heegner points of conductor 5 on X_0(37) associated to QQ[sqrt(-7)]' """ - return "All Heegner points of conductor %s on X_0(%s) associated to QQ[sqrt(%s)]" % ( - self.conductor(), self.level(), self.discriminant()) + return "All Heegner points of conductor %s on X_0(%s) associated to QQ[sqrt(%s)]" % (self.conductor(), self.level(), self.discriminant()) def conductor(self): """ @@ -2474,8 +2477,7 @@ def satisfies_kolyvagin_hypothesis(self) -> bool: sage: heegner_points(389,-7,11).satisfies_kolyvagin_hypothesis() False """ - return is_kolyvagin_conductor(N=self.level(), E=None, D=self.discriminant(), - r=None, n=None, c=self.conductor()) + return is_kolyvagin_conductor(N=self.level(), E=None, D=self.discriminant(), r=None, n=None, c=self.conductor()) @cached_method def ring_class_field(self): @@ -2555,10 +2557,10 @@ def betas(self) -> tuple: [45*x^2 + 13*x*y + y^2] """ c = self.__c - D = self.discriminant()*c*c + D = self.discriminant() * c * c N = self.level() - R = Integers(4*N) - m = 2*N + R = Integers(4 * N) + m = 2 * N return tuple(sorted({a % m for a in R(D).sqrt(all=True)})) @cached_method @@ -2606,9 +2608,9 @@ def points(self, beta=None) -> tuple: c = self.conductor() N = self.level() D = self.discriminant() - b = ZZ(beta) % (2*N) + b = ZZ(beta) % (2 * N) - disc = D*c*c + disc = D * c * c U = [] R = [] @@ -2619,16 +2621,16 @@ def points(self, beta=None) -> tuple: a += 1 continue # todo (optimize) -- replace for over all s with for over solution set - y = ZZ((b*b - disc)/(4*N)) + y = ZZ((b * b - disc) / (4 * N)) for s in Integers(a): - if N*s*s + b*s + y == 0: + if N * s * s + b * s + y == 0: s = s.lift() - f = (a*N, b+2*N*s, ZZ( ((b + 2*N*s)**2 - disc)/(4*a*N)) ) + f = (a * N, b + 2 * N * s, ZZ(((b + 2 * N * s) ** 2 - disc) / (4 * a * N))) g = BinaryQF(f).reduced_form() assert g.discriminant() == disc if g not in U: U.append(g) - R.append(HeegnerPointOnX0N(N,D,c,f)) + R.append(HeegnerPointOnX0N(N, D, c, f)) if len(U) >= h: break a += 1 @@ -2682,6 +2684,7 @@ class HeegnerPointOnX0N(HeegnerPoint): sage: loads(dumps(x)) == x True """ + def __init__(self, N, D, c=ZZ.one(), f=None, check=True): r""" INPUT: @@ -2737,14 +2740,14 @@ def __init__(self, N, D, c=ZZ.one(), f=None, check=True): else: raise TypeError("f must be a 3-tuple, quadratic form, or element of the upper half plane") A, B, C = f - if B*B - 4*A*C != D*c*c: - raise ValueError("f (=%s) must have discriminant %s" % (f, D*c*c)) + if B * B - 4 * A * C != D * c * c: + raise ValueError("f (=%s) must have discriminant %s" % (f, D * c * c)) HeegnerPoint.__init__(self, N, D, c) if f is None: # We know that N|A, so A = N is optimal. A = N - B = ZZ(Integers(4*N)(D*c*c).sqrt(extend=False) % (2*N)) - C = ZZ((B*B - D*c*c)/(4*A)) + B = ZZ(Integers(4 * N)(D * c * c).sqrt(extend=False) % (2 * N)) + C = ZZ((B * B - D * c * c) / (4 * A)) f = (A, B, C) self.__f = f @@ -2779,10 +2782,7 @@ def __richcmp__(self, x, op) -> bool: """ if not isinstance(x, HeegnerPointOnX0N): return NotImplemented - return richcmp((self.level(), self.discriminant(), - self.conductor(), self.__f), - (x.level(), x.discriminant(), - x.conductor(), x.__f), op) + return richcmp((self.level(), self.discriminant(), self.conductor(), self.__f), (x.level(), x.discriminant(), x.conductor(), x.__f), op) def _repr_(self) -> str: """ @@ -2797,7 +2797,7 @@ def _repr_(self) -> str: s = " and conductor %s" % c if c != 1 else "" N = self.level() D = self.discriminant() - tau = repr(self.tau()).replace('sqrt_minus_%s' % (-D),'sqrt(%s)' % D) + tau = repr(self.tau()).replace('sqrt_minus_%s' % (-D), 'sqrt(%s)' % D) return "Heegner point %s of discriminant %s%s on X_0(%s)" % (tau, D, s, N) def atkin_lehner_act(self, Q=None): @@ -2836,9 +2836,8 @@ def atkin_lehner_act(self, Q=None): if g != Q: raise ValueError("Q must divide N and be coprime to N/Q") tau = self.tau() - WQ_tau = ((u * Q * tau + v) / (N * tau + Q)) - return HeegnerPointOnX0N(N, self.discriminant(), self.conductor(), - f=WQ_tau, check=True) + WQ_tau = (u * Q * tau + v) / (N * tau + Q) + return HeegnerPointOnX0N(N, self.discriminant(), self.conductor(), f=WQ_tau, check=True) @cached_method def quadratic_form(self): @@ -2943,9 +2942,9 @@ def galois_orbit_over_K(self): c = self.conductor() N = self.level() D = self.discriminant() - b = self.__f[1] % (2*N) # B + b = self.__f[1] % (2 * N) # B - disc = D*c*c + disc = D * c * c U = [] R = [] @@ -2956,16 +2955,16 @@ def galois_orbit_over_K(self): a += 1 continue # todo (optimize) -- replace for over all s with for over solution set - y = ZZ((b*b - disc)/(4*N)) + y = ZZ((b * b - disc) / (4 * N)) for s in Integers(a): - if N*s*s + b*s + y == 0: + if N * s * s + b * s + y == 0: s = s.lift() - f = (a*N, b+2*N*s, ZZ( ((b + 2*N*s)**2 - disc)/(4*a*N)) ) + f = (a * N, b + 2 * N * s, ZZ(((b + 2 * N * s) ** 2 - disc) / (4 * a * N))) g = BinaryQF(f).reduced_form() assert g.discriminant() == disc if g not in U: U.append(g) - R.append(HeegnerPointOnX0N(N,D,c,f)) + R.append(HeegnerPointOnX0N(N, D, c, f)) a += 1 return R @@ -2983,6 +2982,7 @@ def plot(self, **kwds): Graphics object consisting of 1 graphics primitive """ from sage.plot.point import point + return point(CDF(self.tau()), **kwds) @@ -2998,6 +2998,7 @@ class HeegnerPointOnEllipticCurve(HeegnerPoint): sage: type(P) """ + def __init__(self, E, x, check=True): r""" INPUT: @@ -3050,8 +3051,7 @@ def satisfies_kolyvagin_hypothesis(self, n=None): n = ZZ(n) if n <= 0: raise ValueError("n must be a positive integer") - return is_kolyvagin_conductor(N=self.level(), E=self.__E, D=self.discriminant(), - r=None, n=n, c=self.conductor()) + return is_kolyvagin_conductor(N=self.level(), E=self.__E, D=self.discriminant(), r=None, n=n, c=self.conductor()) def __hash__(self): """ @@ -3081,8 +3081,7 @@ def __eq__(self, right): sage: y1 == 10 False """ - return isinstance(right, HeegnerPointOnEllipticCurve) and \ - (self.__E, self.__x) == (right.__E, right.__x) + return isinstance(right, HeegnerPointOnEllipticCurve) and (self.__E, self.__x) == (right.__E, right.__x) def __ne__(self, other): """ @@ -3492,12 +3491,12 @@ def _check_poly_discriminant(self, f): disc = f.discriminant() D, c = self.discriminant(), self.conductor() for p in D.prime_divisors() + c.prime_divisors(): - disc = disc // (p**disc.valuation(p)) + disc = disc // (p ** disc.valuation(p)) if disc < 0: disc = -disc return disc.is_square() - return all(self._check_poly_discriminant(g) for g,_ in f.factor()) + return all(self._check_poly_discriminant(g) for g, _ in f.factor()) def point_exact(self, prec=53, algorithm='lll', var='a', optimize=False): """ @@ -3564,7 +3563,7 @@ def point_exact(self, prec=53, algorithm='lll', var='a', optimize=False): K = KO x = to_KO(x) if K.degree() < 2 * self.ring_class_field().degree_over_K(): - M = QuadraticField(self.discriminant(),'b') + M = QuadraticField(self.discriminant(), 'b') KD = K.composite_fields(M, names='a')[0] phi = K.embeddings(KD)[0] x = phi(x) @@ -3573,8 +3572,8 @@ def point_exact(self, prec=53, algorithm='lll', var='a', optimize=False): a1, a2, a3, a4, a6 = E.a_invariants() R = K['Y'] Y = R.gen() - g = Y**2 + a1*x*Y + a3*Y - (x**3 + a2*x**2 + a4*x + a6) - F = g.factor() # this takes a long time + g = Y**2 + a1 * x * Y + a3 * Y - (x**3 + a2 * x**2 + a4 * x + a6) + F = g.factor() # this takes a long time if len(F) == 1 and F[0][0] == 2: # reducible -- 1 factor squared y = F[0][0] @@ -3593,7 +3592,7 @@ def point_exact(self, prec=53, algorithm='lll', var='a', optimize=False): # irreducible gg, dd = make_monic(g) M = K.extension(gg, names='b') - y = M.gen()/dd + y = M.gen() / dd x = M(x) L = M.absolute_field(names=var) phi = L.structure()[1] @@ -3601,7 +3600,7 @@ def point_exact(self, prec=53, algorithm='lll', var='a', optimize=False): y = phi(y) EL = E.change_ring(L) - P = EL.point((x,y,L(1)), check=False) + P = EL.point((x, y, L(1)), check=False) return P @cached_method @@ -3685,13 +3684,13 @@ def _numerical_approx_xy_poly(self, prec=53): R = ComplexField(prec)['X'] S = RealField(prec)['X'] X = R.gen() - fx = prod(X-a[0] for a in v) + fx = prod(X - a[0] for a in v) fx = S([b.real() for b in fx]) - fy = prod(X-c[1] for c in v) + fy = prod(X - c[1] for c in v) fy = S([d.real() for d in fy]) return fx, fy - def _xy_poly_nearby(self, prec=53, max_error=10**(-10)): + def _xy_poly_nearby(self, prec=53, max_error=10 ** (-10)): """ Return polynomials with rational coefficients that for sufficiently tight bounds are the characteristic polynomial of the x and y @@ -3757,9 +3756,9 @@ def _square_roots_mod_2N_of_D_mod_4N(self): Ring of integers modulo 74 """ N = self.__E.conductor() - R = Integers(4*N) - m = 2*N - return sorted( {a % m for a in R(self.discriminant()).sqrt(all=True)} ) + R = Integers(4 * N) + m = 2 * N + return sorted({a % m for a in R(self.discriminant()).sqrt(all=True)}) def _trace_numerical_conductor_1(self, prec=53): """ @@ -3800,9 +3799,9 @@ def _trace_numerical_conductor_1(self, prec=53): s = 0 for u, weight in U: P = phi(C(self._qf_to_tau(u))) - z = F.point(list(P),check=False) + z = F.point(list(P), check=False) if abs(weight) == 2: - t = F.point(z,check=False) + F.point(tuple([x.conjugate() for x in z]), check=False) + t = F.point(z, check=False) + F.point(tuple([x.conjugate() for x in z]), check=False) if weight < 0: s -= t else: @@ -3843,15 +3842,15 @@ def _good_tau_representatives(self) -> tuple: b = b.lift() # todo (optimize) -- replace for over all s with for over solution # set that can be found quickly. - y = ZZ((b*b - D)/(4*N)) + y = ZZ((b * b - D) / (4 * N)) for s in Integers(a): - if N*s*s + b*s + y == 0: + if N * s * s + b * s + y == 0: s = s.lift() - f = (a*N, b+2*N*s, ZZ( ((b + 2*N*s)**2 - D)/(4*a*N)) ) + f = (a * N, b + 2 * N * s, ZZ(((b + 2 * N * s) ** 2 - D) / (4 * a * N))) for d in divs: - Q = d * prod(p**k for p,k in N.factor() if (b-beta) % (p**k) != 0) + Q = d * prod(p**k for p, k in N.factor() if (b - beta) % (p**k) != 0) g = self._qf_atkin_lehner_act(Q, f) - gbar = (ZZ(g[0]/N), -g[1], g[2]*N) + gbar = (ZZ(g[0] / N), -g[1], g[2] * N) g = self._qf_reduce(g) gbar = self._qf_reduce(gbar) if g in R or gbar in R: @@ -3865,8 +3864,8 @@ def _good_tau_representatives(self) -> tuple: weight = epsilon_Q else: # weight is 2*epsilon_Q - weight = 2*epsilon_Q - U.append((f,weight)) + weight = 2 * epsilon_Q + U.append((f, weight)) if len(R) == h: return R, U assert len(R) < h, "bug -- too many quadratic forms" @@ -3894,9 +3893,9 @@ def _qf_to_tau(self, f): 1/114*sqrt_minus_8 - 13/57 """ c = self.conductor() - A,B,_ = f - alpha = c * self.quadratic_field().gen() # this is sqrt(D) = sqrt(c^2*disc(K)) - return (-B + alpha)/(2*A) + A, B, _ = f + alpha = c * self.quadratic_field().gen() # this is sqrt(D) = sqrt(c^2*disc(K)) + return (-B + alpha) / (2 * A) def _qf_from_tau(self, tau): r""" @@ -3957,10 +3956,10 @@ def _qf_atkin_lehner_act(self, Q, f): True """ N = self.__E.conductor() - g, u, v = xgcd(Q*Q, -N) + g, u, v = xgcd(Q * Q, -N) assert g == Q tau = self._qf_to_tau(f) - tau2 = ((u*Q*tau + v) / (N*tau + Q)) + tau2 = (u * Q * tau + v) / (N * tau + Q) return self._qf_from_tau(tau2) def _qf_reduce(self, f): @@ -3998,6 +3997,7 @@ def kolyvagin_cohomology_class(self, n=None): """ return KolyvaginCohomologyClassEn(self.kolyvagin_point(), n) + ######################################################################################### # Kolyvagin Points P_c ######################################################################################### @@ -4036,6 +4036,7 @@ class KolyvaginPoint(HeegnerPoint): sage: loads(dumps(y)) == y True """ + def __init__(self, heegner_point): """ Create a Kolyvagin point. @@ -4055,8 +4056,7 @@ def __init__(self, heegner_point): if not heegner_point.satisfies_kolyvagin_hypothesis(): raise ValueError("Heegner point does not satisfy Kolyvagin hypothesis") self.__heegner_point = heegner_point - HeegnerPoint.__init__(self, heegner_point.level(), heegner_point.discriminant(), - heegner_point.conductor()) + HeegnerPoint.__init__(self, heegner_point.level(), heegner_point.discriminant(), heegner_point.conductor()) def satisfies_kolyvagin_hypothesis(self, n=None): r""" @@ -4121,7 +4121,7 @@ def _repr_(self): 'Kolyvagin point of discriminant -67 and conductor 7 on elliptic curve of conductor 37' """ s = repr(self.__heegner_point) - return s.replace('Heegner','Kolyvagin') + return s.replace('Heegner', 'Kolyvagin') def index(self, *args, **kwds): """ @@ -4216,7 +4216,7 @@ def point_exact(self, prec=53): return E(0) if E.root_number() == -1: - return self._recognize_point_over_QQ(P, 2*self.index()) + return self._recognize_point_over_QQ(P, 2 * self.index()) # root number +1. We use algebraic_dependency # to recognize the x # coordinate, stick it in the appropriate quadratic @@ -4246,7 +4246,7 @@ def point_exact(self, prec=53): if not Q: raise RuntimeError("insufficient precision") y = P[1] - d = [abs(C(r[1])-y) for r in Q] + d = [abs(C(r[1]) - y) for r in Q] if d[0] == d[1]: raise RuntimeError("insufficient precision to distinguish roots") if d[0] < d[1]: @@ -4306,9 +4306,9 @@ def trace_to_real_numerical(self, prec=53): # Trace this numerical approximation down to E(Q) (numerically). E = P.curve() if self.curve().root_number() == -1: - R = 2*P + R = 2 * P else: - R = P + E.point([x.conjugate() for x in P],check=False) + R = P + E.point([x.conjugate() for x in P], check=False) F = self.curve().change_ring(RealField(prec)) return F.point([x.real() for x in R], check=False) @@ -4339,7 +4339,7 @@ def _trace_exact_conductor_1(self, prec=53): raise ValueError("the conductor must be 1") P = self.trace_to_real_numerical(prec) - return self._recognize_point_over_QQ(P, 2*self.index()) + return self._recognize_point_over_QQ(P, 2 * self.index()) def _recognize_point_over_QQ(self, P, n): r""" @@ -4363,9 +4363,9 @@ def _recognize_point_over_QQ(self, P, n): # etc" mentioned in Watkins' article... which involves local # heights. E = self.curve() # over Q - v = sum([list(n*w) for w in E.gens()] + [list(w) for w in E.torsion_points()], []) + v = sum([list(n * w) for w in E.gens()] + [list(w) for w in E.torsion_points()], []) # note -- we do not claim to prove anything, so making up a factor of 100 is fine. - max_denominator = 100*max([z.denominator() for z in v]) + max_denominator = 100 * max([z.denominator() for z in v]) try: # the coercion below also checks if point is on elliptic curve return E([x.real().nearby_rational(max_denominator=max_denominator) for x in P]) @@ -4442,24 +4442,24 @@ def mod(self, p, prec=53): return E.change_ring(GF(p))(P) raise NotImplementedError -## def congruent_rational_point(self, n, prec=53): -## r""" -## Let `P` be this Kolyvagin point. Determine whether there is a -## point `z` in `E(\QQ)` such that `z - P \in n E(K_c)`, where `K_c` -## is the ring class field over which this Kolyvagin point is defined. -## If `z` exists return `z`. Otherwise return None. -## -## INPUT: -## -## - ``n`` -- positive integer -## -## - ``prec`` -- positive integer (default: 53) -## -## -## EXAMPLES:: -## -## """ -## raise NotImplementedError + ## def congruent_rational_point(self, n, prec=53): + ## r""" + ## Let `P` be this Kolyvagin point. Determine whether there is a + ## point `z` in `E(\QQ)` such that `z - P \in n E(K_c)`, where `K_c` + ## is the ring class field over which this Kolyvagin point is defined. + ## If `z` exists return `z`. Otherwise return None. + ## + ## INPUT: + ## + ## - ``n`` -- positive integer + ## + ## - ``prec`` -- positive integer (default: 53) + ## + ## + ## EXAMPLES:: + ## + ## """ + ## raise NotImplementedError def kolyvagin_cohomology_class(self, n=None): """ @@ -4500,6 +4500,7 @@ class KolyvaginCohomologyClass(SageObject): sage: y.kolyvagin_cohomology_class(5) Kolyvagin cohomology class c(1) in H^1(K,E[5]) """ + def __init__(self, kolyvagin_point, n): """ @@ -4512,7 +4513,7 @@ def __init__(self, kolyvagin_point, n): if n is None: c = kolyvagin_point.conductor() E = kolyvagin_point.curve() - n = gcd([(p+1).gcd(E.ap(p)) for p in c.prime_divisors()]) + n = gcd([(p + 1).gcd(E.ap(p)) for p in c.prime_divisors()]) if not kolyvagin_point.satisfies_kolyvagin_hypothesis(n): raise ValueError("Kolyvagin point does not satisfy Kolyvagin hypothesis for %s" % n) @@ -4535,9 +4536,7 @@ def __eq__(self, other): sage: c == 0 False """ - return isinstance(other, KolyvaginCohomologyClass) and \ - self.__kolyvagin_point == other.__kolyvagin_point and \ - self.__n == other.__n + return isinstance(other, KolyvaginCohomologyClass) and self.__kolyvagin_point == other.__kolyvagin_point and self.__n == other.__n def __ne__(self, other): """ @@ -4623,8 +4622,7 @@ def _repr_(self): sage: t._repr_() 'Kolyvagin cohomology class c(5) in H^1(K,E[2])' """ - return "Kolyvagin cohomology class c(%s) in H^1(K,E[%s])" % ( - self.conductor(), self.n()) + return "Kolyvagin cohomology class c(%s) in H^1(K,E[%s])" % (self.conductor(), self.n()) ############################################################################# @@ -4637,6 +4635,7 @@ def _repr_(self): # enough at present for that. ############################################################################# + class HeegnerQuatAlg(SageObject): r""" Heegner points viewed as supersingular points on the modular curve @@ -4651,6 +4650,7 @@ class HeegnerQuatAlg(SageObject): sage: loads(dumps(H)) == H True """ + def __init__(self, level, ell): r""" INPUT: @@ -4685,8 +4685,7 @@ def __eq__(self, other): sage: H == 0 False """ - return isinstance(other, HeegnerQuatAlg) and self.__level == other.__level \ - and self.__ell == other.__ell + return isinstance(other, HeegnerQuatAlg) and self.__level == other.__level and self.__ell == other.__ell def __ne__(self, other): """ @@ -4711,8 +4710,7 @@ def _repr_(self): sage: heegner_points(11).reduce_mod(13)._repr_() 'Heegner points on X_0(11) over F_13' """ - return "Heegner points on X_0(%s) over F_%s" % ( - self.__level, self.__ell) + return "Heegner points on X_0(%s) over F_%s" % (self.__level, self.__ell) def level(self): """ @@ -4855,15 +4853,15 @@ def optimal_embeddings(self, D, c, R): Embedding sending 2*sqrt(-7) to -2*i + 2*j + 2*k] """ Q, G = R.ternary_quadratic_form(include_basis=True) - n = -D*c*c - reps = Q.representation_vector_list(n+1)[-1] + n = -D * c * c + reps = Q.representation_vector_list(n + 1)[-1] # The representatives give elements in terms of the # subspace's basis such that the embedding is given by # phi(c*sqrt(D)) = beta E = [] for r in reps: - beta = sum(G[i]*r[i] for i in range(len(G))) + beta = sum(G[i] * r[i] for i in range(len(G))) phi = HeegnerQuatAlgEmbedding(D, c, R, beta) E.append(phi) return E @@ -4881,6 +4879,7 @@ def brandt_module(self): Brandt module of dimension 2 of level 3*11 of weight 2 over Rational Field """ from sage.modular.quatalg.all import BrandtModule + return BrandtModule(self.__ell, self.__level) @cached_method @@ -4975,12 +4974,12 @@ def heegner_divisor(self, D, c=ZZ.one()): return B.hecke_operator(c)(z) n = -D - v = [0]*B.degree() + v = [0] * B.degree() for i, R in enumerate(self.left_orders()): Q = R.ternary_quadratic_form() - a = Q.theta_series(n+1)[n] + a = Q.theta_series(n + 1)[n] if a > 0: - reps = Q.representation_vector_list(n+1)[-1] + reps = Q.representation_vector_list(n + 1)[-1] k = len([r for r in reps if gcd(r) == 1]) assert k % 2 == 0 v[i] += k // 2 @@ -5060,23 +5059,23 @@ def modp_splitting_data(self, p): raise ValueError("p (=%s) must be an unramified prime" % p) i, j, k = Q.gens() F = GF(p) - i2 = F(i*i) - j2 = F(j*j) + i2 = F(i * i) + j2 = F(j * j) M = MatrixSpace(F, 2) - I = M([0,i2,1,0]) - i2inv = 1/i2 + I = M([0, i2, 1, 0]) + i2inv = 1 / i2 a = None - #for b in reversed(list(F)): + # for b in reversed(list(F)): for b in list(F): if not b: continue - c = j2 + i2inv * b*b + c = j2 + i2inv * b * b if c.is_square(): a = -c.sqrt() break assert a is not None, "bug in that no splitting solution found" - J = M([a,b,(j2-a*a)/b, -a]) - assert I*J == -J*I, "bug in that I,J do not skew commute" + J = M([a, b, (j2 - a * a) / b, -a]) + assert I * J == -J * I, "bug in that I,J do not skew commute" return I, J def modp_splitting_map(self, p): @@ -5110,6 +5109,7 @@ def modp_splitting_map(self, p): def phi(q): v = [F(a) for a in q.coefficient_tuple()] return v[0] + I * v[1] + J * v[2] + K * v[3] + return phi def cyclic_subideal_p1(self, I, c): @@ -5153,13 +5153,13 @@ def cyclic_subideal_p1(self, I, c): for J in B.cyclic_submodules(I, c): B = J.basis() V = phi(B[0]).kernel() - for i in [1,2,3]: + for i in [1, 2, 3]: V = V.intersection(phi(B[i]).kernel()) b = V.basis() assert len(b) == 1, "common kernel must have dimension 1" uv = P1.normalize(ZZ(b[0][0]) % c, ZZ(b[0][1]) % c) ans[uv] = J - assert len(ans) == c+1 + assert len(ans) == c + 1 return ans @cached_method @@ -5315,9 +5315,9 @@ def kolyvagin_generator(self, K, p): F = K.residue_field(p) a = F.gen() - assert a*a == K.discriminant(), "bug: we assumed generator of finite field must be square root of discriminant, but for some reason this is not true" - for n in range(1,p): - if (a + n).multiplicative_order() % (p*p-1) == 0: + assert a * a == K.discriminant(), "bug: we assumed generator of finite field must be square root of discriminant, but for some reason this is not true" + for n in range(1, p): + if (a + n).multiplicative_order() % (p * p - 1) == 0: return K.gen() + n raise RuntimeError("there is a bug in kolyvagin_generator") @@ -5350,6 +5350,7 @@ def kolyvagin_generators(self, K, c): v = [] F = ZZ(c).factor() from sage.rings.integer_ring import crt_basis + B = crt_basis([x[0] for x in F]) for i, (p, e) in enumerate(F): if e > 1: @@ -5358,13 +5359,13 @@ def kolyvagin_generators(self, K, c): # Now we use the Chinese Remainder Theorem to make an element # of O_K that equals alpha modulo p and equals 1 modulo # all other prime divisors of c. - Z = [1]*len(B) + Z = [1] * len(B) Z[i] = alpha[0] - a0 = sum([Z[j]*B[j] for j in range(len(B))]) - Z = [0]*len(B) + a0 = sum([Z[j] * B[j] for j in range(len(B))]) + Z = [0] * len(B) Z[i] = alpha[1] - a1 = sum([Z[j]*B[j] for j in range(len(B))]) - v.append(alpha.parent()([a0,a1])) + a1 = sum([Z[j] * B[j] for j in range(len(B))]) + v.append(alpha.parent()([a0, a1])) return v @cached_method @@ -5718,6 +5719,7 @@ def kolyvagin_reduction_data(E, q, first_only=True): (19, 239, -311, 19, 6480, 85680) """ from .ell_generic import EllipticCurve_generic + if not isinstance(E, EllipticCurve_generic): raise TypeError("E must be an elliptic curve") @@ -5747,18 +5749,14 @@ def red(P, ell): # reduce the point P on the elliptic curve modulo ell w = list(P) d = lcm([a.denominator() for a in w]) - return E.change_ring(GF(ell))([d*a for a in w]) + return E.change_ring(GF(ell))([d * a for a in w]) def best_heegner_D(ell_1, ell_2): # return the first Heegner D satisfy all hypothesis such that # both ell_1 and ell_2 are inert D = ZZ(-5) while True: - if D.is_fundamental_discriminant() and \ - D % ell_1 and D % ell_2 and \ - E.satisfies_heegner_hypothesis(D) and \ - is_inert(D, ell_1) and is_inert(D, ell_2) and \ - twist_is_minimal(D): + if D.is_fundamental_discriminant() and D % ell_1 and D % ell_2 and E.satisfies_heegner_hypothesis(D) and is_inert(D, ell_1) and is_inert(D, ell_2) and twist_is_minimal(D): return D D -= 1 @@ -5767,16 +5765,16 @@ def best_heegner_D(ell_1, ell_2): # such that reduction is surjective to E(F_ell)/q. ell = ZZ(3) while True: - while N % ell == 0 or gcd(ell+1,E.ap(ell)) % q != 0: + while N % ell == 0 or gcd(ell + 1, E.ap(ell)) % q != 0: ell = ell.next_prime() # determine if mod ell reduction is surjective, using # partly that it is a lemma that E(F_ell)/q is cyclic. m = ZZ(E.Np(ell) / q) for P in E.gens(): - if red(P,ell) * m != 0: + if red(P, ell) * m != 0: # bingo, is surjective - D = best_heegner_D(ell,ell) - return (ell, D, class_number(D), BrandtModule(ell,N).dimension()) + D = best_heegner_D(ell, ell) + return (ell, D, class_number(D), BrandtModule(ell, N).dimension()) # end for ell = ell.next_prime() @@ -5795,7 +5793,7 @@ def kernel_of_reduction(ell): # compute first good odd prime ell_1 = ZZ(3) while True: - while N % ell_1 == 0 or gcd(ell_1+1,E.ap(ell_1)) % q != 0: + while N % ell_1 == 0 or gcd(ell_1 + 1, E.ap(ell_1)) % q != 0: ell_1 = ell_1.next_prime() # compute kernel of reduction modulo ell_1 G1 = set(kernel_of_reduction(ell_1)) @@ -5806,7 +5804,7 @@ def kernel_of_reduction(ell): # compute next good odd prime with distinct kernel of order q ell_2 = ell_1.next_prime() while True: - while N % ell_2 == 0 or gcd(ell_2+1,E.ap(ell_2)) % q != 0: + while N % ell_2 == 0 or gcd(ell_2 + 1, E.ap(ell_2)) % q != 0: ell_2 = ell_2.next_prime() G2 = set(kernel_of_reduction(ell_2)) if G1 != G2 and len(G2) == q: @@ -5815,9 +5813,7 @@ def kernel_of_reduction(ell): # Find smallest D where both ell_1 and ell_2 are inert D = best_heegner_D(ell_1, ell_2) - return (ell_1, ell_2, D, class_number(D), - BrandtModule(ell_1,N).dimension(), - BrandtModule(ell_2,N).dimension()) + return (ell_1, ell_2, D, class_number(D), BrandtModule(ell_1, N).dimension(), BrandtModule(ell_2, N).dimension()) class HeegnerQuatAlgEmbedding(SageObject): @@ -5836,6 +5832,7 @@ class HeegnerQuatAlgEmbedding(SageObject): sage: loads(dumps(f)) == f True """ + def __init__(self, D, c, R, beta): r""" INPUT: @@ -5875,11 +5872,7 @@ def __eq__(self, other): sage: f == 0 False """ - return isinstance(other, HeegnerQuatAlgEmbedding) and \ - self.__D == other.__D and \ - self.__c == other.__c and \ - self.__R == other.__R and \ - self.__beta == other.__beta + return isinstance(other, HeegnerQuatAlgEmbedding) and self.__D == other.__D and self.__c == other.__c and self.__R == other.__R and self.__beta == other.__beta def __ne__(self, other): """ @@ -5946,7 +5939,7 @@ def matrix(self): [ 1 0 0 0] [ 0 1 -1 -1] """ - return matrix(QQ,2,4,[[1,0,0,0], self.__beta.coefficient_tuple()]) + return matrix(QQ, 2, 4, [[1, 0, 0, 0], self.__beta.coefficient_tuple()]) @cached_method def domain(self): @@ -6056,8 +6049,7 @@ def conjugate(self): sage: f Embedding sending 2*sqrt(-7) to -5*i + k """ - return HeegnerQuatAlgEmbedding(self.__D, self.__c, - self.__R, self.__beta.conjugate()) + return HeegnerQuatAlgEmbedding(self.__D, self.__c, self.__R, self.__beta.conjugate()) ############################################################################# @@ -6154,7 +6146,7 @@ def is_inert(D, p): sage: sage.schemes.elliptic_curves.heegner.is_inert(-7,11) False """ - K = QuadraticField(D,'a') + K = QuadraticField(D, 'a') F = K.factor(p) return len(F) == 1 and F[0][1] == 1 @@ -6178,7 +6170,7 @@ def is_split(D, p): sage: sage.schemes.elliptic_curves.heegner.is_split(-7,11) True """ - K = QuadraticField(D,'a') + K = QuadraticField(D, 'a') F = K.factor(p) return len(F) == 2 @@ -6202,7 +6194,7 @@ def is_ramified(D, p): sage: sage.schemes.elliptic_curves.heegner.is_ramified(-1,2) True """ - return QuadraticField(D,'a').discriminant() % p == 0 + return QuadraticField(D, 'a').discriminant() % p == 0 def nearby_rational_poly(f, **kwds): @@ -6355,7 +6347,7 @@ def make_monic(f): for p, e in factor_trial_division(den, 1000000): # Round up e/expo d *= p ** ((e + expo - 1) // expo) - g = R([d**(n-i) * f[i] / lc for i in range(n+1)]) + g = R([d ** (n - i) * f[i] / lc for i in range(n + 1)]) return g, d @@ -6364,6 +6356,7 @@ def make_monic(f): # Everywhere self below is an elliptic curve over QQ. ##################################################################### + def ell_heegner_point(self, D, c=ZZ.one(), f=None, check=True): r""" Return the Heegner point on this curve associated to the @@ -6460,7 +6453,7 @@ def kolyvagin_point(self, D, c=ZZ.one(), check=True): sage: 6*g (6 : -15 : 1) """ - return self.heegner_point(D,c,check=check).kolyvagin_point() + return self.heegner_point(D, c, check=check).kolyvagin_point() def ell_heegner_discriminants(self, bound) -> list: @@ -6481,8 +6474,7 @@ def ell_heegner_discriminants(self, bound) -> list: sage: E.heegner_discriminants(30) # indirect doctest [-7, -8, -19, -24] """ - return [ZZ(-D) for D in range(1, bound) - if self.satisfies_heegner_hypothesis(-D)] + return [ZZ(-D) for D in range(1, bound) if self.satisfies_heegner_hypothesis(-D)] def ell_heegner_discriminants_list(self, n) -> list: @@ -6564,7 +6556,7 @@ def heegner_point_height(self, D, prec=2, check_rank=True): eps = self.root_number() L1_vanishes = self.lseries().L1_vanishes() - IR = RealIntervalField(20) # TODO: why 20 bits here? + IR = RealIntervalField(20) # TODO: why 20 bits here? if eps == 1 and L1_vanishes: return IR(0) # rank even hence >= 2, so Heegner point is torsion. @@ -6572,34 +6564,33 @@ def heegner_point_height(self, D, prec=2, check_rank=True): RR = RealField() from math import sqrt - alpha = RR(sqrt(abs(D)))/(2*self.period_lattice().complex_area()) + alpha = RR(sqrt(abs(D))) / (2 * self.period_lattice().complex_area()) F = self.quadratic_twist(D) E = self - k_E = prec*sqrt(E.conductor()) + 20 - k_F = prec*sqrt(F.conductor()) + 20 + k_E = prec * sqrt(E.conductor()) + 20 + k_F = prec * sqrt(F.conductor()) + 20 MIN_ERR = RR('1e-6') # we assume that regulator and - # discriminant, etc., computed to this accuracy (which is easily the case). - # this should be made more intelligent / rigorous relative - # to the rest of the system. + # discriminant, etc., computed to this accuracy (which is easily the case). + # this should be made more intelligent / rigorous relative + # to the rest of the system. - if eps == 1: # E has even rank + if eps == 1: # E has even rank LF1, err_F = F.lseries().deriv_at1(k_F) LE1, err_E = E.lseries().at1(k_E) err_F = max(err_F, MIN_ERR) err_E = max(err_E, MIN_ERR) - return IR(alpha-MIN_ERR,alpha+MIN_ERR) * IR(LE1-err_E,LE1+err_E) * IR(LF1-err_F,LF1+err_F) + return IR(alpha - MIN_ERR, alpha + MIN_ERR) * IR(LE1 - err_E, LE1 + err_E) * IR(LF1 - err_F, LF1 + err_F) # E has odd rank LE1, err_E = E.lseries().deriv_at1(k_E) LF1, err_F = F.lseries().at1(k_F) err_F = max(err_F, MIN_ERR) err_E = max(err_E, MIN_ERR) - return IR(alpha-MIN_ERR,alpha+MIN_ERR) * IR(LE1-err_E,LE1+err_E) * IR(LF1-err_F,LF1+err_F) + return IR(alpha - MIN_ERR, alpha + MIN_ERR) * IR(LE1 - err_E, LE1 + err_E) * IR(LF1 - err_F, LF1 + err_F) -def heegner_index(self, D, min_p=2, prec=5, descent_second_limit=12, - verbose_mwrank=False, check_rank=True): +def heegner_index(self, D, min_p=2, prec=5, descent_second_limit=12, verbose_mwrank=False, check_rank=True): r""" Return an interval that contains the index of the Heegner point `y_K` in the group of `K`-rational points modulo torsion @@ -6724,7 +6715,7 @@ def heegner_index(self, D, min_p=2, prec=5, descent_second_limit=12, # We divide by 2 to get the height **over Q** of the # Heegner point on the twist. - ht = h0/2 + ht = h0 / 2 verbose('Height of heegner point = %s' % ht, tm) if self.root_number() == 1: @@ -6736,7 +6727,7 @@ def heegner_index(self, D, min_p=2, prec=5, descent_second_limit=12, verbose("Heegner height bound = %s" % h) B = F.CPS_height_bound() verbose("CPS bound = %s" % B) - c = h/(min_p**2) + B + c = h / (min_p**2) + B verbose("Search would have to be up to height = %s" % c) from .ell_rational_field import _MAX_HEIGHT @@ -6749,7 +6740,7 @@ def heegner_index(self, D, min_p=2, prec=5, descent_second_limit=12, reg = F.regulator(descent_second_limit=descent_second_limit, verbose=verbose_mwrank) if F.rank(use_database=True) == 1: z = F.gens()[0] - FK = F.base_extend(QuadraticField(D,'a')) + FK = F.base_extend(QuadraticField(D, 'a')) z = FK(z) if z.is_divisible_by(2): a = 2 @@ -6761,7 +6752,7 @@ def heegner_index(self, D, min_p=2, prec=5, descent_second_limit=12, if (z + T).is_divisible_by(2): a = 2 break - return a*self._adjust_heegner_index(ht/IR(reg)) + return a * self._adjust_heegner_index(ht / IR(reg)) # Do naive search to eliminate possibility that Heegner point # is divisible by p tuple: ([2], -7, 2) """ from .ell_rational_field import _MAX_HEIGHT + if max_height is None: max_height = _MAX_HEIGHT else: @@ -6885,11 +6877,12 @@ def heegner_index_bound(self, D=0, prec=5, max_height=None) -> tuple: if self.two_torsion_rank() == 0: H = h else: - H = 4*h + H = 4 * h p = 3 from sage.arith.misc import next_prime + while True: - c = H/(2*p**2) + B + c = H / (2 * p**2) + B if c < max_height: break if p > 100: @@ -6914,15 +6907,15 @@ def _bound(P): S, I, reg = F.saturation(P) IR = RealIntervalField(20) # todo: 20? - h = IR(reg-eps,reg+eps) - ind2 = ht/(h/2) + h = IR(reg - eps, reg + eps) + ind2 = ht / (h / 2) verbose("index squared = %s" % ind2) ind = ind2.sqrt() verbose("index = %s" % ind) # Compute upper bound on square root of index. if ind.absolute_diameter() < 1: t, i = ind.is_int() - if t: # unique integer in interval, so we've found exact index squared. + if t: # unique integer in interval, so we've found exact index squared. return prime_divisors(i), D, i raise RuntimeError("Unable to compute bound for e=%s, D=%s (try increasing precision)" % (self, D)) @@ -7019,15 +7012,14 @@ def _heegner_index_in_EK(self, D): # Basis for E(Q)/tor oplus E^D(QQ)/tor in E(K): basis = [G(z) for z in E.gens()] + [G(phi(z)) for z in F.gens()] # Make a list of the 2-power order torsion points in E(K), including 0. - T = [G(z) for z in G.torsion_subgroup().list() if z.order() == 1 or - (z.order() % 2 == 0 and len(z.order().factor()) == 1)] + T = [G(z) for z in G.torsion_subgroup().list() if z.order() == 1 or (z.order() % 2 == 0 and len(z.order().factor()) == 1)] - r = len(basis) # rank + r = len(basis) # rank V = QQ**r B = [] # Iterate through reps for A/(2*A) creating vectors in (1/2)*ZZ^r - for v in GF(2)**r: + for v in GF(2) ** r: if not v: continue P = sum([basis[i] for i in range(r) if v[i]]) @@ -7161,7 +7153,7 @@ def heegner_sha_an(self, D, prec=53): # You can think this through or just type something like # f = function('f',x); g = function('g',x); diff(f*g,6) # into Sage to be convinced. - L = binomial(rE + rF, rE) * (L_E * L_F / factorial(rE+rF) ) + L = binomial(rE + rF, rE) * (L_E * L_F / factorial(rE + rF)) # - ||omega||^2 -- the period. It is twice the volume of the # period lattice. See the following paper for a derivation: @@ -7177,7 +7169,7 @@ def heegner_sha_an(self, D, prec=53): # height over QQ, i.e., for P in E(QQ) we have h_K(P,P) = # 2*h_Q(P,P). See, e.g., equation (6.4) on page 230 of # [GZ1986]_. - Reg_prod = 2**(rE + rF) * E.regulator(precision=prec) * F.regulator(precision=prec) + Reg_prod = 2 ** (rE + rF) * E.regulator(precision=prec) * F.regulator(precision=prec) # Next we call off to the _heegner_index_in_EK function, which # saturates the group E(QQ) + E^D(QQ) in E(K), given us the index, # which must be a power of 2, since E(QQ) is the +1 eigenspace for @@ -7236,25 +7228,26 @@ def _heegner_forms_list(self, D, beta=None, expected_count=None) -> list: expected_count = D.class_number() N = self.conductor() if beta is None: - beta = Integers(4*N)(D).sqrt(extend=False) + beta = Integers(4 * N)(D).sqrt(extend=False) else: - assert beta**2 == Integers(4*N)(D) + assert beta**2 == Integers(4 * N)(D) from sage.quadratic_forms.binary_qf import BinaryQF - b = ZZ(beta) % (2*N) + + b = ZZ(beta) % (2 * N) all = [] seen = [] # Note: This may give a sub-optimal list of forms. while True: - R = (b**2-D)//(4*N) + R = (b**2 - D) // (4 * N) for d in R.divisors(): - f = BinaryQF([d*N, b, R//d]) + f = BinaryQF([d * N, b, R // d]) fr = f.reduced_form() if fr not in seen: seen.append(fr) all.append(f) if len(all) == expected_count: return all - b += 2*N + b += 2 * N def _heegner_best_tau(self, D, prec=None): @@ -7279,9 +7272,9 @@ def _heegner_best_tau(self, D, prec=None): """ # We know that N|A, so A = N is optimal. N = self.conductor() - b = ZZ(Integers(4*N)(D).sqrt(extend=False) % (2*N)) + b = ZZ(Integers(4 * N)(D).sqrt(extend=False) % (2 * N)) # TODO: make sure a different choice of b is not better? - return (-b + ZZ(D).sqrt(prec=prec)) / (2*N) + return (-b + ZZ(D).sqrt(prec=prec)) / (2 * N) def satisfies_heegner_hypothesis(self, D): diff --git a/src/sage/schemes/elliptic_curves/height.py b/src/sage/schemes/elliptic_curves/height.py index d35adaa3a63..1871df87af4 100644 --- a/src/sage/schemes/elliptic_curves/height.py +++ b/src/sage/schemes/elliptic_curves/height.py @@ -11,6 +11,7 @@ - John Cremona (2014): added many docstrings and doctests """ + ############################################################################## # Copyright (C) 2010 Robert Bradshaw # 2014 John Cremona @@ -76,6 +77,7 @@ class UnionOfIntervals: Unify :class:`UnionOfIntervals` with the class ``RealSet`` introduced by :issue:`13125`; see :issue:`16063`. """ + def __init__(self, endpoints) -> None: r""" An union of intervals is initialized by giving an increasing list @@ -196,9 +198,9 @@ def __mul__(left, right): ([0.000000000000000, 0.750000000000000] U [3.00000000000000, +Infinity]) """ if not isinstance(right, UnionOfIntervals): - return UnionOfIntervals([e*right for e in left._endpoints]) + return UnionOfIntervals([e * right for e in left._endpoints]) if not isinstance(left, UnionOfIntervals): - return UnionOfIntervals([left*e for e in right._endpoints]) + return UnionOfIntervals([left * e for e in right._endpoints]) return NotImplemented def __rmul__(self, other): @@ -506,8 +508,8 @@ def nonneg_region(f): () """ roots = sorted(f.roots()) - sign_changes = [r for r,e in roots if e % 2 == 1] - if (f.leading_coefficient() * (-1)**f.degree()) > 0: + sign_changes = [r for r, e in roots if e % 2 == 1] + if (f.leading_coefficient() * (-1) ** f.degree()) > 0: sign_changes = [-infinity] + sign_changes if f.leading_coefficient() > 0: sign_changes += [infinity] @@ -552,7 +554,7 @@ def inf_max_abs(f, g, D): xs += g.roots() + g.derivative().roots() xs += (f - g).roots() + (f + g).roots() xs = [r for r, _ in xs if r in D] # ignore multiplicities and points outside D - xs += D.finite_endpoints() # include endpoints of intervals + xs += D.finite_endpoints() # include endpoints of intervals if xs: return min(max(abs(f(r)), abs(g(r))) for r in xs) return infinity @@ -597,7 +599,7 @@ def min_on_disk(f, tol, max_iter=10000): # Initially L contains one element, the whole unit box, which is # not contained in the unit square. - s = CIF(RIF(-1,1), RIF(-1,1)) + s = CIF(RIF(-1, 1), RIF(-1, 1)) fs = f(s) L = [(-fs.lower(), fs.relative_diameter(), s, False)] @@ -613,23 +615,23 @@ def min_on_disk(f, tol, max_iter=10000): for k in range(max_iter): value, err, region, in_disk = L.pop() - if err < tol: # reached desired tolerance, so return + if err < tol: # reached desired tolerance, so return return region, -value - for s in region.bisection(): # 4 sub-regions + for s in region.bisection(): # 4 sub-regions if in_disk: - s_in_disk = True # if the original region si in the disk so are all its children + s_in_disk = True # if the original region si in the disk so are all its children else: - r = abs(s) # otherwise we test each one + r = abs(s) # otherwise we test each one if r > 1: - continue # skip this subregion if it is entirely outside the disk - s_in_disk = r < 1 # meaning it is entirely inside the disk + continue # skip this subregion if it is entirely outside the disk + s_in_disk = r < 1 # meaning it is entirely inside the disk fs = f(s) if fs.upper() < min_max: # we definitely beat the record min_max = fs.upper() unneeded = bisect.bisect(L, (-min_max,)) - if unneeded > 100: # discard the worse entries (if there are many) + if unneeded > 100: # discard the worse entries (if there are many) L = L[unneeded:] if fs.lower() < min_max: @@ -668,7 +670,7 @@ def rat_term_CIF(z, try_strict=True): -0.172467461182437? + 0.?e-16*I """ two_pi_i_z = two_pi_i_CIF * z - r = (two_pi_i_z.real()).exp() # = |u| + r = (two_pi_i_z.real()).exp() # = |u| x, y = two_pi_i_z.imag().cos(), two_pi_i_z.imag().sin() real_part = imag_part = None @@ -683,18 +685,18 @@ def rat_term_CIF(z, try_strict=True): corner_reals = [] corner_imags = [] for a, b in product(z.real().endpoints(), z.imag().endpoints()): - zz = CDF(a,b) - u = (two_pi_i_CDF*zz).exp() - f = u/(1-u)**2 + zz = CDF(a, b) + u = (two_pi_i_CDF * zz).exp() + f = u / (1 - u) ** 2 corner_reals.append(f.real()) corner_imags.append(f.imag()) - p1 = (((((r+2*x)*r - 6)*r + 2*x) * r) + 1) - # = r^4 + 2*r^3*x - 6*r^2 + 2*r*x + 1 - p2 = (r*(x*(r+2*x)-4)+x) - # = r^2*x + 2*r*x^2 - 4*r + x + p1 = ((((r + 2 * x) * r - 6) * r + 2 * x) * r) + 1 + # = r^4 + 2*r^3*x - 6*r^2 + 2*r*x + 1 + p2 = r * (x * (r + 2 * x) - 4) + x + # = r^2*x + 2*r*x^2 - 4*r + x - df_dr = (r**2-1) * p2 + df_dr = (r**2 - 1) * p2 dg_dr = p1 * y dg_dx = r * df_dr / y @@ -705,11 +707,11 @@ def rat_term_CIF(z, try_strict=True): imag_part = RIF(min(corner_imags), max(corner_imags)) if real_part is None or imag_part is None: - denom = (1-r*(2*x-r))**2 + denom = (1 - r * (2 * x - r)) ** 2 if real_part is None: - real_part = r*(x*(1+r**2)-2*r)/denom + real_part = r * (x * (1 + r**2) - 2 * r) / denom if imag_part is None: - imag_part = -(r**2-1)*y*r/denom + imag_part = -(r**2 - 1) * y * r / denom return CIF(real_part, imag_part) @@ -802,9 +804,11 @@ def __init__(self, E) -> None: from an elliptic curve defined over a number field """ from sage.schemes.elliptic_curves.ell_generic import EllipticCurve_generic + if isinstance(E, EllipticCurve_generic): self.E = E from sage.rings.number_field.number_field_base import NumberField + K = E.base_ring() if isinstance(K, NumberField): self.K = K @@ -922,18 +926,19 @@ def alpha(self, v, tol=0.01): 0.347263296676126 """ from sage.rings.polynomial.polynomial_ring import polygen + b2, b4, b6, b8 = (v(b) for b in self.E.b_invariants()) x = polygen(v.codomain()) - f = 4*x**3 + b2*x**2 + 2*b4*x + b6 - g = x**4 - b4*x**2 - 2*b6*x - b8 - F = f.reverse() << (4-f.degree()) - G = g.reverse() << (4-g.degree()) + f = 4 * x**3 + b2 * x**2 + 2 * b4 * x + b6 + g = x**4 - b4 * x**2 - 2 * b6 * x - b8 + F = f.reverse() << (4 - f.degree()) + G = g.reverse() << (4 - g.degree()) if v(self.K.gen()) in RR: - I = UnionOfIntervals([-1,1]) + I = UnionOfIntervals([-1, 1]) min_fg = inf_max_abs(f, g, nonneg_region(f) & I) min_FG = inf_max_abs(F, G, nonneg_region(F) & I) - return min(min_fg, min_FG) ** (-1/QQ(3)) + return min(min_fg, min_FG) ** (-1 / QQ(3)) # def pair_max(f, g): # f = f.change_ring(CIF) @@ -945,19 +950,21 @@ def alpha(self, v, tol=0.01): def pair_max(f, g): f = f.change_ring(CDF) g = g.change_ring(CDF) - dfn = [fast_callable(f.derivative(n)/factorial(n), CDF) for n in range(f.degree()+1)] - dgn = [fast_callable(g.derivative(n)/factorial(n), CDF) for n in range(g.degree()+1)] + dfn = [fast_callable(f.derivative(n) / factorial(n), CDF) for n in range(f.degree() + 1)] + dgn = [fast_callable(g.derivative(n) / factorial(n), CDF) for n in range(g.degree() + 1)] def max_f_g(s): - (a,b), (c,d) = s.real().endpoints(), s.imag().endpoints() + (a, b), (c, d) = s.real().endpoints(), s.imag().endpoints() dx = a - b dy = c - d - eta = RDF(dx*dx + dy*dy).sqrt() + eta = RDF(dx * dx + dy * dy).sqrt() z = CDF(s.center()) - err_f = sum(eta ** n * abs(df(z)) for n, df in enumerate(dfn) if n) - err_g = sum(eta ** n * abs(dg(z)) for n, dg in enumerate(dgn) if n) + err_f = sum(eta**n * abs(df(z)) for n, df in enumerate(dfn) if n) + err_g = sum(eta**n * abs(dg(z)) for n, dg in enumerate(dgn) if n) return RIF(max(abs(f(z)), abs(g(z)))) + eps(max(err_f, err_g), True) + return max_f_g + _, min_fg = min_on_disk(pair_max(f, g), tol) _, min_FG = min_on_disk(pair_max(F, G), tol) return min(min_fg, min_FG) ** QQ((-1, 3)) @@ -1040,12 +1047,12 @@ def DE(self, n): [0, 2*log(5) + 2*log(2), 0, 2*log(13) + 2*log(5) + 4*log(2), 0] """ s = 0 - B = (n+1) ** max(2, self.K.degree()) + B = (n + 1) ** max(2, self.K.degree()) for p in self.K.primes_of_bounded_norm_iter(B): ep = self.e_p(p) if ep.divides(n): kp = self.K.residue_field(p) - s += 2*(1+(n/ep).valuation(kp.characteristic())) * log(len(kp)) + s += 2 * (1 + (n / ep).valuation(kp.characteristic())) * log(len(kp)) return s @cached_method @@ -1076,6 +1083,7 @@ def ME(self): 4096 """ from sage.misc.misc_c import prod + if self.K is QQ: return prod([p ** (e - self.E.local_data(p).discriminant_valuation()) for p, e in self.E.discriminant().factor()], QQ.one()) @@ -1182,9 +1190,10 @@ def psi(self, xi, v): L = self.E.period_lattice(v) w1, w2 = L.basis() from sage.schemes.elliptic_curves.constructor import EllipticCurve + ER = EllipticCurve([v(ai) for ai in self.E.a_invariants()]) xP, yP = ER.lift_x(xi).xy() - t = L.e_log_RC(xP,yP) / w1 + t = L.e_log_RC(xP, yP) / w1 if t < 0.5: t = 1 - t return t @@ -1227,14 +1236,14 @@ def S(self, xi1, xi2, v): """ L = self.E.period_lattice(v) w1, w2 = L.basis(prec=v.codomain().prec()) - beta = L.elliptic_exponential(w1/2)[0] + beta = L.elliptic_exponential(w1 / 2)[0] if xi2 < beta: return UnionOfIntervals([]) if xi1 < beta <= xi2: a = self.psi(xi2, v) - return UnionOfIntervals([1-a, a]) + return UnionOfIntervals([1 - a, a]) a, b = self.psi(xi1, v), self.psi(xi2, v) - return UnionOfIntervals([1-b, 1-a, a, b]) + return UnionOfIntervals([1 - b, 1 - a, a, b]) def Sn(self, xi1, xi2, n, v): r""" @@ -1280,8 +1289,8 @@ def Sn(self, xi1, xi2, n, v): sage: H.Sn(2, 3, 6, v) ([0.0236953443100124, 0.0288076194880974] U [0.137859047178569, 0.142971322356654] U [0.190362010976679, 0.195474286154764] U [0.304525713845236, 0.309637989023321] U [0.357028677643346, 0.362140952821431] U [0.471192380511903, 0.476304655689988] U [0.523695344310012, 0.528807619488097] U [0.637859047178569, 0.642971322356654] U [0.690362010976679, 0.695474286154764] U [0.804525713845236, 0.809637989023321] U [0.857028677643346, 0.862140952821431] U [0.971192380511903, 0.976304655689988]) """ - SS = 1/ZZ(n) * self.S(xi1, xi2, v) - return UnionOfIntervals.union([t/ZZ(n) + SS for t in range(n)]) + SS = 1 / ZZ(n) * self.S(xi1, xi2, v) + return UnionOfIntervals.union([t / ZZ(n) + SS for t in range(n)]) def real_intersection_is_empty(self, Bk, v): r""" @@ -1340,7 +1349,7 @@ def real_intersection_is_empty(self, Bk, v): sage: H.real_intersection_is_empty([H.B(n,0.08) for n in srange(1,5)], v) # needs sage.rings.number_field False """ - return UnionOfIntervals.intersection([self.Sn(-B, B, k+1, v) for k,B in enumerate(Bk)]).is_empty() + return UnionOfIntervals.intersection([self.Sn(-B, B, k + 1, v) for k, B in enumerate(Bk)]).is_empty() ######################################## # Empty complex intersection detection.# @@ -1405,8 +1414,7 @@ def wp_c(self, v): """ # Note that we normalise w1, w2 differently from [Tho2010]_! w2, w1 = self.E.period_lattice(v).normalised_basis() - return max(abs(v(self.E.c4()/240)) ** 0.5, - abs(v(self.E.c6()/6048)) ** (1.0/3)) * abs(w1)**2 + return max(abs(v(self.E.c4() / 240)) ** 0.5, abs(v(self.E.c6() / 6048)) ** (1.0 / 3)) * abs(w1) ** 2 def fk_intervals(self, v=None, N=20, domain=CIF): r""" @@ -1468,10 +1476,10 @@ def fk_intervals(self, v=None, N=20, domain=CIF): raise ValueError("must specify embedding") # pre-compute some constants tau = self.tau(v) - const_term = 1/CC(12) + const_term = 1 / CC(12) qn = q = (2 * CC.gen() * CC.pi() * tau).exp() for n in range(1, N): - const_term -= 2 * qn/(1-qn) ** 2 + const_term -= 2 * qn / (1 - qn) ** 2 qn *= q two_pi_i = 2 * domain.gen() * domain.pi() @@ -1481,29 +1489,28 @@ def fk_intervals(self, v=None, N=20, domain=CIF): abs_q = abs(domain(q)) abs_qN = abs(domain(qn)) - err_factor = abs(neg_four_pi2) / (1-abs_q) - err_term = 2*abs_qN/(1-abs_qN) ** 2 + err_factor = abs(neg_four_pi2) / (1 - abs_q) + err_term = 2 * abs_qN / (1 - abs_qN) ** 2 # choose u/(1-u)^2 evaluation method if domain is CIF: rat_term = rat_term_CIF else: + def rat_term(z): - u = (two_pi_i*z).exp() - return u/(1-u)**2 + u = (two_pi_i * z).exp() + return u / (1 - u) ** 2 # the actual series def fk(z): - return (const_term + - sum([rat_term(z+n*tau) for n in range(1-N,N)]) - ) * neg_four_pi2 + return (const_term + sum([rat_term(z + n * tau) for n in range(1 - N, N)])) * neg_four_pi2 # the error function def err(z): alpha = z.imag() / tau.imag() - qNa = abs_q**(N+alpha) - qNai = abs_q**(N-alpha) - return (err_factor * (qNa/(1-qNa) ** 2 + qNai/(1-qNai) ** 2 + err_term)).upper() + qNa = abs_q ** (N + alpha) + qNai = abs_q ** (N - alpha) + return (err_factor * (qNa / (1 - qNa) ** 2 + qNai / (1 - qNai) ** 2 + err_term)).upper() return fk, err @@ -1582,15 +1589,16 @@ def wp(z): # refine using an estimate that's better near the pole z_bound = abs(z).upper() - cz2 = c * z_bound ** 2 + cz2 = c * z_bound**2 if cz2 < 1: err = (c * cz2) / (1 - cz2) if abs_only: pole_approx = abs(z) ** -2 else: - pole_approx = z ** -2 + pole_approx = z**-2 approx = approx.intersection(pole_approx + eps(err, abs_only)) return approx + return wp @cached_method @@ -1642,11 +1650,11 @@ def wp_on_grid(self, v, N, half=False): fk, err = self.fk_intervals(v, 15, CDF) var_z = SR.var('z') ff = fast_callable(fk(var_z), CDF, [var_z]) - N_or_half = N // (1+half) # array is NxN or Nx(N/2) - vals = numpy.empty((N,N_or_half)) # empty array tp hold values + N_or_half = N // (1 + half) # array is NxN or Nx(N/2) + vals = numpy.empty((N, N_or_half)) # empty array tp hold values for i in range(N): for j in range(N_or_half): - vals[i,j] = abs(ff((i+.5)/N + (j+.5)*tau/N)) + vals[i, j] = abs(ff((i + 0.5) / N + (j + 0.5) * tau / N)) return vals def complex_intersection_is_empty(self, Bk, v, verbose=False, use_half=True): @@ -1708,8 +1716,8 @@ def complex_intersection_is_empty(self, Bk, v, verbose=False, use_half=True): b2 = v(self.E.b2()) # Note that we normalise w1, w2 differently from [Tho2010]_! w2, w1 = self.E.period_lattice(v).normalised_basis() - tau = w2/w1 - bounds = [RDF((B.sqrt() + abs(b2)/12) * abs(w1) ** 2) for B in Bk] + tau = w2 / w1 + bounds = [RDF((B.sqrt() + abs(b2) / 12) * abs(w1) ** 2) for B in Bk] vals = self.wp_on_grid(v, 30, half=use_half) wp = self.wp_intervals(v, abs_only=True) @@ -1719,24 +1727,24 @@ def complex_intersection_is_empty(self, Bk, v, verbose=False, use_half=True): if verbose: print("trying to prove negative result...") intersection = None - for B, n in sorted(zip(bounds, ZZ.range(1, k+1))): + for B, n in sorted(zip(bounds, ZZ.range(1, k + 1))): T = PeriodicRegion(CDF(1), CDF(tau), vals < B, full=not use_half) if intersection is None: intersection = PeriodicRegion(CDF(1), CDF(tau), vals < B, full=not use_half) else: - intersection &= T/n + intersection &= T / n if intersection.is_empty(): break else: z = CIF(intersection.innermost_point()) - if all(wp((k+1)*z).upper() < B for k, B in enumerate(bounds)): + if all(wp((k + 1) * z).upper() < B for k, B in enumerate(bounds)): return False # Now try to prove a positive result. if verbose: print("trying to prove positive result...") intersection = None - for B, n in sorted(zip(bounds, ZZ.range(1, k+1))): + for B, n in sorted(zip(bounds, ZZ.range(1, k + 1))): T = PeriodicRegion(CDF(1), CDF(tau), vals < B, full=not use_half).expand().refine() B = RIF(B) @@ -1762,7 +1770,7 @@ def check_line(z): if intersection is None: intersection = T else: - intersection &= T/n + intersection &= T / n if intersection.is_empty(): return True @@ -1852,6 +1860,7 @@ def test_mu(self, mu, N, verbose=True): # stopping if one gives a True result. from sage.rings.number_field.number_field import refine_embedding + for v in self.K.places(): ok = False while not ok: @@ -1867,7 +1876,7 @@ def test_mu(self, mu, N, verbose=True): v = refine_embedding(v) if verbose: print("Refining embedding, codomain now {}".format(v.codomain())) - return False # Couldn't prove it... + return False # Couldn't prove it... def min_gr(self, tol, n_max, verbose=False): r""" @@ -1985,14 +1994,12 @@ def min_gr(self, tol, n_max, verbose=False): eps = 2.0 while eps > tol + 1: if verbose: - print("height bound in [%r, %r] using n_max = %r" - % (mu, mu * eps, n_max)) + print("height bound in [%r, %r] using n_max = %r" % (mu, mu * eps, n_max)) eps = math.sqrt(eps) if test(mu * eps, n_max, False): mu = mu * eps if verbose: - print("height bound in [%r, %r] using n_max = %r" - % (mu, mu * eps, n_max)) + print("height bound in [%r, %r] using n_max = %r" % (mu, mu * eps, n_max)) return RDF(mu) def min(self, tol, n_max, verbose=False): @@ -2092,9 +2099,8 @@ def min(self, tol, n_max, verbose=False): if self.K == QQ: if self.E.real_components() == 2: tp *= 2 - elif any(v(self.E.discriminant()) > 0 - for v in self.K.real_places()): + elif any(v(self.E.discriminant()) > 0 for v in self.K.real_places()): tp *= 2 # Now tp is such that tp*P has good reduction at all places # for all points P: - return self.min_gr(tol, n_max, verbose) / tp ** 2 + return self.min_gr(tol, n_max, verbose) / tp**2 diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py index f906ad33776..a534db9410f 100644 --- a/src/sage/schemes/elliptic_curves/hom.py +++ b/src/sage/schemes/elliptic_curves/hom.py @@ -30,6 +30,7 @@ - Lorenz Panny (2026): :meth:`~EllipticCurveHom.kernel_subgroup`, :meth:`~EllipticCurveHom.kernel_gens` """ + from sage.misc.cachefunc import cached_method from sage.misc.lazy_import import lazy_import from sage.structure.richcmp import richcmp_not_equal, richcmp, op_EQ, op_NE @@ -44,10 +45,12 @@ lazy_import('sage.schemes.elliptic_curves', 'weierstrass_morphism', as_='wm') + class EllipticCurveHom(Morphism): """ Base class for elliptic-curve morphisms. """ + def __init__(self, *args, **kwds): r""" Constructor for elliptic-curve morphisms. @@ -134,6 +137,7 @@ def _composition_(self, other, homset): if ret is NotImplemented: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite + ret = EllipticCurveHom_composite.from_factors([other, self]) return ret @@ -154,6 +158,7 @@ def _add_(self, other): Via: (Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101, Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101) """ from sage.schemes.elliptic_curves.hom_sum import EllipticCurveHom_sum + phis = [] if isinstance(self, EllipticCurveHom_sum): phis += self.summands() @@ -164,7 +169,7 @@ def _add_(self, other): else: phis.append(other) - #TODO should probably try to simplify some more? + # TODO should probably try to simplify some more? assert other.domain() == self.domain() and other.codomain() == self.codomain() return EllipticCurveHom_sum(phis, domain=self.domain(), codomain=self.codomain()) @@ -408,7 +413,7 @@ def trace(self): raise ValueError('trace only makes sense for endomorphisms') d = self.degree() s = self.scaling_factor() - return ZZ(s + d/s) + return ZZ(s + d / s) return compute_trace_generic(self) def characteristic_polynomial(self): @@ -614,8 +619,8 @@ def kernel_subgroup(self, *, extend=False, algorithm=None): from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper - #TODO: a specialized implementation for EllipticCurveHom_composite might be beneficial - #TODO: a specialized implementation for EllipticCurveHom_fractional might be beneficial + # TODO: a specialized implementation for EllipticCurveHom_composite might be beneficial + # TODO: a specialized implementation for EllipticCurveHom_fractional might be beneficial try: return AdditiveAbelianGroupWrapper.from_generators(self.__EllipticCurveIsogeny_kernel_list) @@ -641,16 +646,17 @@ def kernel_subgroup(self, *, extend=False, algorithm=None): for imP in imPs: imP.set_order(multiple=o) if len(T2.invariants()) == 1: - R, = (g.element() for g in T2.gens()) + (R,) = (g.element() for g in T2.gens()) mylog = lambda pt: (pt.log(R),) else: R, S = (g.element() for g in T2.gens()) - mylog = lambda pt: pt.log([R,S]) + mylog = lambda pt: pt.log([R, S]) from sage.matrix.constructor import matrix from sage.matrix.special import diagonal_matrix + M = matrix(ZZ, map(mylog, imPs)).stack(diagonal_matrix([elt.order() for elt in T2.gens()])) - K = M.left_kernel_matrix()[:,:len(Ps)] + K = M.left_kernel_matrix()[:, : len(Ps)] V = K.row_space(ZZ) / diagonal_matrix([P.order() for P in Ps]).row_space(ZZ) G = [g.lift() for g in V.gens()] @@ -659,7 +665,7 @@ def kernel_subgroup(self, *, extend=False, algorithm=None): for s, row in zip(V.invariants(), G): if s.is_one(): continue - Q = sum(c * P for c,P in zip(row, Ps)) + Q = sum(c * P for c, P in zip(row, Ps)) assert not self._eval(Q) Q.set_order(s) gens.append(Q) @@ -973,6 +979,7 @@ def inverse_image(self, Q, /, *, all=False): return (K + P for K in self.kernel_points()) if not self.base_ring().is_exact(): from warnings import warn + warn('computing inverse image over inexact base ring is not guaranteed to be correct') E = self.domain() for Px in (self.x_rational_map() - Q.x()).numerator().roots(multiplicities=False): @@ -1057,11 +1064,11 @@ def formal(self, prec=20): assert not self.is_separable() or xh.valuation() == -2, f"xh has valuation {xh.valuation()} (should be -2)" yh = Eh.y(prec=prec) assert not self.is_separable() or yh.valuation() == -3, f"yh has valuation {yh.valuation()} (should be -3)" - fh = f(xh,yh) + fh = f(xh, yh) assert not self.is_separable() or fh.valuation() == -2, f"fh has valuation {fh.valuation()} (should be -2)" - gh = g(xh,yh) + gh = g(xh, yh) assert not self.is_separable() or gh.valuation() == -3, f"gh has valuation {gh.valuation()} (should be -3)" - th = -fh/gh + th = -fh / gh assert not self.is_separable() or th.valuation() == +1, f"th has valuation {th.valuation()} (should be +1)" return th @@ -1468,6 +1475,7 @@ def as_morphism(self): (0 : 1 : 0) """ from sage.schemes.curves.constructor import Curve + X_affine = Curve(self.domain()).affine_patch(2) Y_affine = Curve(self.codomain()).affine_patch(2) return X_affine.hom(self.rational_maps(), Y_affine).homogenize(2) @@ -1568,14 +1576,14 @@ def matrix_on_subgroup(self, domain_gens, codomain_gens=None): raise ValueError('basis of codomain subgroup is required for non-endomorphisms') codomain_gens = domain_gens - P,Q = domain_gens - R,S = codomain_gens + P, Q = domain_gens + R, S = codomain_gens - ords = {P.order() for P in (P,Q,R,S)} + ords = {P.order() for P in (P, Q, R, S)} if len(ords) != 1: - #TODO: Is there some meaningful way to lift this restriction? + # TODO: Is there some meaningful way to lift this restriction? raise ValueError('generator points must all have the same order') - n, = ords + (n,) = ords if P.weil_pairing(Q, n).multiplicative_order() != n: raise ValueError('generator points on domain are not independent') @@ -1590,6 +1598,7 @@ def matrix_on_subgroup(self, domain_gens, codomain_gens=None): from sage.matrix.constructor import matrix from sage.rings.finite_rings.integer_mod_ring import Zmod + return matrix(Zmod(n), [vecP, vecQ]) def __truediv__(self, other): @@ -1616,9 +1625,11 @@ def __truediv__(self, other): Denominator: 2 """ from sage.rings.integer import Integer + if not isinstance(other, (int, Integer)): return NotImplemented from sage.schemes.elliptic_curves.hom_fractional import EllipticCurveHom_fractional + return EllipticCurveHom_fractional(self, other) def divide_left(self, psi): @@ -1645,6 +1656,7 @@ def divide_left(self, psi): True """ from sage.schemes.elliptic_curves.hom_fractional import EllipticCurveHom_fractional + numer = psi.dual() * self denom = psi.degree() return EllipticCurveHom_fractional(numer, denom) @@ -1694,6 +1706,7 @@ def divide_right(self, psi): return find_post_isomorphism(psi, self) from sage.schemes.elliptic_curves.hom_fractional import EllipticCurveHom_fractional + numer = self * psi.dual() denom = psi.degree() return EllipticCurveHom_fractional(numer, denom) @@ -1737,9 +1750,9 @@ def minimal_polynomial(self): sage: phi.minimal_polynomial().factor() x^4 + (57*z2 + 65)*x^2 + 20*z2 + 25 """ - #FIXME This can probably be implemented better! + # FIXME This can probably be implemented better! h = self.kernel_polynomial() - for f,_ in reversed(h.factor()): + for f, _ in reversed(h.factor()): if self.domain().kernel_polynomial_from_divisor(f, self.degree()) == h: return f raise ValueError('not a cyclic isogeny') @@ -1888,8 +1901,8 @@ def compare_via_evaluation(left, right): # then extend to a field with enough points to conclude q = F.cardinality() - e = integer_floor(1 + 2 * (2*d.sqrt() + 1).log(q)) # from Hasse bound - e = next(i for i, n in enumerate(E.count_points(e+1), 1) if n > 4*d) + e = integer_floor(1 + 2 * (2 * d.sqrt() + 1).log(q)) # from Hasse bound + e = next(i for i, n in enumerate(E.count_points(e + 1), 1) if n > 4 * d) EE = E.base_extend(F.extension(e, 'U')) # named extension is faster Ps = EE.gens() return all(left._eval(P) == right._eval(P) for P in Ps) @@ -1897,7 +1910,7 @@ def compare_via_evaluation(left, right): if isinstance(F, number_field_base.NumberField): for _ in range(100): P = E.lift_x(F.random_element(), extend=True) - if P._has_order_at_least(4*d + 1, attempts=50): + if P._has_order_at_least(4 * d + 1, attempts=50): # if P.height(precision=250) == 0: # slow sometimes return left._eval(P) == right._eval(P) assert False, "couldn't find a point of large enough order" @@ -2076,14 +2089,14 @@ def compute_trace_generic(phi): d = phi.degree() M = 4 * d.isqrt() + 1 # |trace| <= 2 sqrt(deg) - tr = Mod(0,1) + tr = Mod(0, 1) F = E.base_field() p = F.characteristic() if p: s = phi.scaling_factor() if s: - tr = Mod(ZZ(s + d/s), p) + tr = Mod(ZZ(s + d / s), p) for l in Primes(): if tr.modulus() >= M: @@ -2091,14 +2104,14 @@ def compute_trace_generic(phi): try: P = point_of_order(E, l) except ValueError: - continue # supersingular and l == p + continue # supersingular and l == p Q = phi._eval(P) if not Q: # we learn nothing when P lies in the kernel continue R = phi._eval(Q) - t = discrete_log(R + d*P, Q, ord=l, operation='+') -# assert not R - t*Q + d*P + t = discrete_log(R + d * P, Q, ord=l, operation='+') + # assert not R - t*Q + d*P tr = tr.crt(Mod(t, l)) diff --git a/src/sage/schemes/elliptic_curves/hom_composite.py b/src/sage/schemes/elliptic_curves/hom_composite.py index 93406bef6fb..6a1ce4dfe15 100644 --- a/src/sage/schemes/elliptic_curves/hom_composite.py +++ b/src/sage/schemes/elliptic_curves/hom_composite.py @@ -123,7 +123,7 @@ def _eval_factored_isogeny(phis, P): return P -def _compute_factored_isogeny_prime_power(P, l, n, split=.8, velu_sqrt_bound=None): +def _compute_factored_isogeny_prime_power(P, l, n, split=0.8, velu_sqrt_bound=None): r""" This method takes a point `P` of order `\ell^n` and returns a sequence of degree-`\ell` isogenies whose composition has @@ -203,16 +203,17 @@ def _compute_factored_isogeny_prime_power(P, l, n, split=.8, velu_sqrt_bound=Non sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=1) True """ + def rec(Q, k): if k == 1: # base case: Q has order l - Q._order = l # This was not cached before + Q._order = l # This was not cached before return [Q.curve().isogeny(kernel=Q, velu_sqrt_bound=velu_sqrt_bound)] # recursive case: k > 1 and Q has order l^k - k1 = int(k * split + .5) + k1 = int(k * split + 0.5) k1 = max(1, min(k - 1, k1)) # clamp to [1, k - 1] Q1 = l**k1 * Q @@ -264,9 +265,9 @@ def _compute_factored_isogeny_single_generator(P, velu_sqrt_bound=None): """ phis = [] h = P.order() - for l,e in P.order().factor(): + for l, e in P.order().factor(): h //= l**e - psis = _compute_factored_isogeny_prime_power(h*P, l, e, velu_sqrt_bound=velu_sqrt_bound) + psis = _compute_factored_isogeny_prime_power(h * P, l, e, velu_sqrt_bound=velu_sqrt_bound) P = _eval_factored_isogeny(psis, P) phis += psis return phis @@ -400,6 +401,7 @@ def __init__(self, E, kernel, codomain=None, model=None, velu_sqrt_bound=None): raise ValueError("cannot specify a codomain curve and model name simultaneously") from sage.schemes.elliptic_curves.ell_field import compute_model + codomain = compute_model(self._phis[-1].codomain(), model) if codomain is not None: @@ -587,16 +589,13 @@ def _repr_(self): To: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 43 """ from itertools import groupby + degs = [phi.degree() for phi in self._phis] if len(degs) == 1: - return f'Composite morphism of degree {self._degree}:' \ - f'\n From: {self._domain}' \ - f'\n To: {self._codomain}' - grouped = [(d, sum(1 for _ in g)) for d,g in groupby(degs)] - degs_str = '*'.join(str(d) + (f'^{e}' if e > 1 else '') for d,e in grouped) - return f'Composite morphism of degree {self._degree} = {degs_str}:' \ - f'\n From: {self._domain}' \ - f'\n To: {self._codomain}' + return f'Composite morphism of degree {self._degree}:' f'\n From: {self._domain}' f'\n To: {self._codomain}' + grouped = [(d, sum(1 for _ in g)) for d, g in groupby(degs)] + degs_str = '*'.join(str(d) + (f'^{e}' if e > 1 else '') for d, e in grouped) + return f'Composite morphism of degree {self._degree} = {degs_str}:' f'\n From: {self._domain}' f'\n To: {self._codomain}' def factors(self): r""" @@ -671,7 +670,7 @@ def _composition_impl(left, right): over Number Field in I with defining polynomial x^2 + 1 with I = 1*I """ if isinstance(left, EllipticCurveHom_composite): - if isinstance(right, WeierstrassIsomorphism) and hasattr(left.factors()[0], '_set_pre_isomorphism'): # XXX bit of a hack + if isinstance(right, WeierstrassIsomorphism) and hasattr(left.factors()[0], '_set_pre_isomorphism'): # XXX bit of a hack return EllipticCurveHom_composite.from_factors((left.factors()[0] * right,) + left.factors()[1:], strict=False) if isinstance(right, EllipticCurveHom_composite): return EllipticCurveHom_composite.from_factors(right.factors() + left.factors()) diff --git a/src/sage/schemes/elliptic_curves/hom_fractional.py b/src/sage/schemes/elliptic_curves/hom_fractional.py index 395d2bc9711..e57f0596bbc 100644 --- a/src/sage/schemes/elliptic_curves/hom_fractional.py +++ b/src/sage/schemes/elliptic_curves/hom_fractional.py @@ -85,6 +85,7 @@ - Lorenz Panny (2024) """ + from sage.misc.cachefunc import cached_method from sage.structure.sequence import Sequence @@ -148,8 +149,8 @@ def __init__(self, phi, d, *, check=True) -> None: EE = E.change_ring(F) psi = E.division_polynomial(l**e).radical() - psi //= psi.gcd(E.division_polynomial(l**(e-1))) - if psi.degree() < l**2//2: + psi //= psi.gcd(E.division_polynomial(l ** (e - 1))) + if psi.degree() < l**2 // 2: assert l == E.base_field().characteristic() if psi.is_one(): # supersingular, hence [p] is the only p^2-isogeny up to isomorphism @@ -273,9 +274,7 @@ def _repr_(self) -> str: To: Elliptic Curve defined by y^2 = x^3 + 9*x over Finite Field of size 13) Denominator: 2 """ - return f'Fractional elliptic-curve morphism of degree {self._degree}:' \ - f'\n Numerator: {self._phi}' \ - f'\n Denominator: {self._d}' + return f'Fractional elliptic-curve morphism of degree {self._degree}:' f'\n Numerator: {self._phi}' f'\n Denominator: {self._d}' @cached_method def to_isogeny_chain(self): @@ -309,12 +308,12 @@ def to_isogeny_chain(self): EE = E.change_ring(F) psi = E.division_polynomial(l**e).radical() - psi //= psi.gcd(E.division_polynomial(l**(e-1))) - if psi.degree() < l**2//2: + psi //= psi.gcd(E.division_polynomial(l ** (e - 1))) + if psi.degree() < l**2 // 2: assert l == E.base_field().characteristic() if psi.is_one(): # supersingular, hence [p] is the only p^2-isogeny up to isomorphism - insep += 2*self._d.valuation(l) + insep += 2 * self._d.valuation(l) else: # ordinary, hence [p] is Frobenius times its dual insep += self._d.valuation(l) @@ -329,19 +328,20 @@ def to_isogeny_chain(self): mat = self._phi.matrix_on_subgroup((P, Q), RS) for row in filter(bool, self._d.p_primary_part(l) * mat.left_kernel_matrix()): - K = sum(ZZ(c)*T for c, T in zip(row, (P, Q))) + K = sum(ZZ(c) * T for c, T in zip(row, (P, Q))) K.set_order(multiple=l**e) assert self._eval(K) == 0 ker.append(K) from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite + chain = EllipticCurveHom_composite(E, []) ker = ker[::-1] while ker: if not (P := ker.pop()): continue - (l, e), = P.order().factor() - K = l**(e-1)*P + ((l, e),) = P.order().factor() + K = l ** (e - 1) * P if e > 1: ker.append(P) poly = E.kernel_polynomial_from_point(K, algorithm='basic') # FIXME algorithm='basic' is a workaround for #34907 @@ -376,6 +376,7 @@ def _composition_impl(left, right): To: Elliptic Curve defined by y^2 = x^3 + 418*x over Finite Field of size 419 """ from sage.schemes.elliptic_curves.hom_scalar import EllipticCurveHom_scalar + if isinstance(left, EllipticCurveHom_scalar): left, right = right, left if isinstance(left, EllipticCurveHom_fractional) and isinstance(right, EllipticCurveHom_scalar): @@ -535,13 +536,13 @@ def inseparable_degree(self): def _torsion_gens(E, EE, l, e, psi=None): if psi is None: psi = E.division_polynomial(l**e).radical() - psi //= psi.gcd(E.division_polynomial(l**(e-1))) + psi //= psi.gcd(E.division_polynomial(l ** (e - 1))) xs = iter(psi.roots(ring=EE.base_field(), multiplicities=False)) P = EE.lift_x(next(xs)) while True: Q = EE.lift_x(next(xs)) - if not (P.weil_pairing(Q, l**e)**(l**(e-1))).is_one(): + if not (P.weil_pairing(Q, l**e) ** (l ** (e - 1))).is_one(): break else: assert False, f'bug in finding {l**e}-torsion basis' diff --git a/src/sage/schemes/elliptic_curves/hom_frobenius.py b/src/sage/schemes/elliptic_curves/hom_frobenius.py index 66aa3a5b5a4..7a1bb347aeb 100644 --- a/src/sage/schemes/elliptic_curves/hom_frobenius.py +++ b/src/sage/schemes/elliptic_curves/hom_frobenius.py @@ -218,7 +218,7 @@ def __init__(self, E, power=1): if self._n < 0: raise ValueError('negative powers of Frobenius are not isogenies') - self._degree = self._p ** self._n + self._degree = self._p**self._n self._domain = E as_ = [a**self._degree for a in self._domain.a_invariants()] @@ -233,7 +233,7 @@ def __init__(self, E, power=1): self._codomain._fetch_cached_order(self._domain) self._poly_ring = PolynomialRing(self._base_ring, ['x'], sparse=True) - self._mpoly_ring = PolynomialRing(self._base_ring, ['x','y'], sparse=True) + self._mpoly_ring = PolynomialRing(self._base_ring, ['x', 'y'], sparse=True) self._xfield = self._poly_ring.fraction_field() self._xyfield = self._mpoly_ring.fraction_field() @@ -303,9 +303,7 @@ def _repr_(self): """ kind = 'endomorphism' if self._codomain == self._domain else 'isogeny' degs_str = '' if self._n == 1 else f' = {self._p}^{self._n}' - return f'Frobenius {kind} of degree {self._degree}{degs_str}:' \ - f'\n From: {self._domain}' \ - f'\n To: {self._codomain}' + return f'Frobenius {kind} of degree {self._degree}{degs_str}:' f'\n From: {self._domain}' f'\n To: {self._codomain}' # EllipticCurveHom methods @@ -331,7 +329,7 @@ def rational_maps(self): sage: pi.rational_maps()[1].parent() Fraction Field of Multivariate Polynomial Ring in x, y over Finite Field of size 11 """ - x,y = self._xyfield.gens() + x, y = self._xyfield.gens() return (x**self._degree, y**self._degree) def x_rational_map(self): @@ -354,7 +352,7 @@ def x_rational_map(self): sage: pi.x_rational_map().parent() Fraction Field of Sparse Univariate Polynomial Ring in x over Finite Field of size 11 """ - x, = self._xfield.gens() + (x,) = self._xfield.gens() return x**self._degree def scaling_factor(self): @@ -489,7 +487,7 @@ def dual(self): else: E = self._domain poly = self._domain.division_polynomial(self._p) - ker = self._poly_ring(list(poly)[::self._p]).monic() + ker = self._poly_ring(list(poly)[:: self._p]).monic() Phis = [] for _ in range(self._n): Ep = EllipticCurve([a**self._p for a in E.a_invariants()]) diff --git a/src/sage/schemes/elliptic_curves/hom_scalar.py b/src/sage/schemes/elliptic_curves/hom_scalar.py index a4dfb7f196d..d268d429086 100644 --- a/src/sage/schemes/elliptic_curves/hom_scalar.py +++ b/src/sage/schemes/elliptic_curves/hom_scalar.py @@ -171,7 +171,7 @@ def __init__(self, E, m): # TODO: should probably be in EllipticCurveHom? self._base_ring = self._domain.base_ring() self._poly_ring = PolynomialRing(self._base_ring, ['x']) - self._mpoly_ring = PolynomialRing(self._base_ring, ['x','y']) + self._mpoly_ring = PolynomialRing(self._base_ring, ['x', 'y']) self._rational_maps = None @@ -374,8 +374,7 @@ def x_rational_map(self): raise ValueError('[0] is not expressible in (x,y) coordinates') h = self._domain.multiplication_by_m(self._m, x_only=True) self._rational_maps = (self._mpoly_ring.fraction_field()(h), None) - f,g = map(self._poly_ring, (self._rational_maps[0].numerator(), - self._rational_maps[0].denominator())) + f, g = map(self._poly_ring, (self._rational_maps[0].numerator(), self._rational_maps[0].denominator())) return f / g def scaling_factor(self): @@ -527,7 +526,7 @@ def inseparable_degree(self): if not v: return ZZ.one() rk = 1 + self._domain.is_supersingular() - return p**(rk*v) + return p ** (rk * v) def __neg__(self): """ diff --git a/src/sage/schemes/elliptic_curves/hom_sum.py b/src/sage/schemes/elliptic_curves/hom_sum.py index 981367bf3f0..2430af96e58 100644 --- a/src/sage/schemes/elliptic_curves/hom_sum.py +++ b/src/sage/schemes/elliptic_curves/hom_sum.py @@ -176,10 +176,7 @@ def _repr_(self): To: Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101 Via: (Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101, Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101) """ - return f'Sum morphism:' \ - f'\n From: {self._domain}' \ - f'\n To: {self._codomain}' \ - f'\n Via: {self._phis}' + return f'Sum morphism:' f'\n From: {self._domain}' f'\n To: {self._codomain}' f'\n Via: {self._phis}' def summands(self): r""" @@ -273,37 +270,38 @@ def to_isogeny_chain(self): p = self.base_ring().characteristic() insep = self.inseparable_degree().valuation(p) if p else 0 - scalar = 1 #TODO Can we detect scalar factors earlier to save some extensions below? + scalar = 1 # TODO Can we detect scalar factors earlier to save some extensions below? ker = [] - for l,m in deg.factor(): + for l, m in deg.factor(): if l == p: # possibly inseparable if insep < m: # kernel of the separable p-power part is unique - P = point_of_order(self.domain(), p**(m-insep)) + P = point_of_order(self.domain(), p ** (m - insep)) ker.append(P) continue F = self.domain().division_field(l**m) - P,Q = self.domain().change_ring(F).torsion_basis(l**m) + P, Q = self.domain().change_ring(F).torsion_basis(l**m) if self.is_endomorphism(): - R,S = P,Q + R, S = P, Q else: - R,S = self.codomain().change_ring(F).torsion_basis(l**m) - M = self.matrix_on_subgroup((P,Q), (R,S)) + R, S = self.codomain().change_ring(F).torsion_basis(l**m) + M = self.matrix_on_subgroup((P, Q), (R, S)) g = ZZ(gcd(M.list())).p_primary_part(l) if g > 1: scalar *= g M = (M.change_ring(ZZ) / g).change_ring(M.base_ring()) K = M.left_kernel_matrix() for row in K: - u,v = map(ZZ, row) - pt = u*P + v*Q + u, v = map(ZZ, row) + pt = u * P + v * Q pt.set_order(row.additive_order()) ker.append(pt) from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite + phi = EllipticCurveHom_composite(self.domain(), []) if scalar != 1: @@ -312,15 +310,16 @@ def to_isogeny_chain(self): while ker: K = ker.pop(0) - (l,e), = K.order().factor() + ((l, e),) = K.order().factor() for i in reversed(range(e)): Kl = l**i * K Kl.set_order(l) from sage.groups.generic import multiples from sage.misc.misc_c import prod + x = polygen(Kl.base_ring()) - poly = prod(x - T.x() for T in multiples(Kl, l//2, Kl)) + poly = prod(x - T.x() for T in multiples(Kl, l // 2, Kl)) poly = poly.change_ring(self.base_ring()) psi = phi.codomain().isogeny(poly) @@ -333,6 +332,7 @@ def to_isogeny_chain(self): phi = frob * phi from sage.schemes.elliptic_curves.hom import find_post_isomorphism + iso = find_post_isomorphism(phi, self) return iso * phi @@ -379,8 +379,8 @@ def _degree_bounds(self): lo, hi = ZZ.zero(), ZZ.zero() for phi in self._phis: m = (hi * phi.degree()).isqrt() - hi += phi.degree() + 2*m - lo += phi.degree() - 2*m + hi += phi.degree() + 2 * m + lo += phi.degree() - 2 * m lo = max(lo, 0) return lo, hi @@ -425,24 +425,24 @@ def _compute_degree(self): elif len(self._phis) == 1: self._degree = self._phis[0].degree() else: - #TODO In some cases it would probably be faster to simply + # TODO In some cases it would probably be faster to simply # compute the kernel polynomial using the addition formulas? from sage.rings.finite_rings.integer_mod import Mod lo, hi = self._degree_bounds() M = hi - lo + 1 - rem = Mod(0,1) + rem = Mod(0, 1) for l in Primes(): if rem.modulus() >= M: break try: P = point_of_order(self._domain, l) except ValueError: - continue # supersingular and l == p + continue # supersingular and l == p Q = self.dual()._eval(self._eval(P)) d = discrete_log(Q, P, ord=l, operation='+') - rem = rem.crt(Mod(d-lo, l)) + rem = rem.crt(Mod(d - lo, l)) self._degree = lo + rem.lift() self.dual()._degree = self._degree @@ -469,6 +469,7 @@ def _comparison_impl(left, right, op): True """ from sage.structure.richcmp import op_EQ + if op != op_EQ: return NotImplemented try: @@ -517,7 +518,7 @@ def rational_maps(self): ALGORITHM: :meth:`to_isogeny_chain`. """ - #TODO In some cases it would probably be faster to compute this + # TODO In some cases it would probably be faster to compute this # directly using the addition formulas? return self.to_isogeny_chain().rational_maps() @@ -534,7 +535,7 @@ def x_rational_map(self): ALGORITHM: :meth:`to_isogeny_chain`. """ - #TODO In some cases it would probably be faster to compute this + # TODO In some cases it would probably be faster to compute this # directly using the addition formulas? return self.to_isogeny_chain().x_rational_map() @@ -559,7 +560,7 @@ def kernel_polynomial(self): ALGORITHM: :meth:`to_isogeny_chain`. """ - #TODO In some cases it would probably be faster to compute this + # TODO In some cases it would probably be faster to compute this # directly using the addition formulas? return self.to_isogeny_chain().kernel_polynomial() @@ -623,8 +624,7 @@ def dual(self): ALGORITHM: Taking the dual distributes over addition. """ - psi = EllipticCurveHom_sum((phi.dual() for phi in self._phis), - domain=self._codomain, codomain=self._domain) + psi = EllipticCurveHom_sum((phi.dual() for phi in self._phis), domain=self._codomain, codomain=self._domain) psi._degree = self._degree if self.trace.is_in_cache(): psi.trace.set_cache(-self.trace.cache) diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 4842d032150..e11e352b181 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -151,6 +151,7 @@ class _VeluBoundObj: sage: _velu_sqrt_bound.get() 50 """ + def __init__(self): self.bound = Integer(1000) @@ -196,11 +197,11 @@ def _choose_IJK(n): """ if n % 2 != 1 or n < 5: raise ValueError('n must be odd and >= 5') - b = (n-1).isqrt() // 2 - c = (n-1) // (4*b) - I = range(2*b, 2*b*(2*c-1)+1, 4*b) - J = range(1, 2*b, 2) - K = range(4*b*c+1, n, 2) + b = (n - 1).isqrt() // 2 + c = (n - 1) // (4 * b) + I = range(2 * b, 2 * b * (2 * c - 1) + 1, 4 * b) + J = range(1, 2 * b, 2) + K = range(4 * b * c + 1, n, 2) return I, J, K @@ -240,11 +241,11 @@ def _points_range(rr, P, Q=None): """ if not rr: return - a,b,s = rr.start, rr.stop, rr.step - R = a*P if Q is None else Q + a*P + a, b, s = rr.start, rr.stop, rr.step + R = a * P if Q is None else Q + a * P yield R - sP = s*P - for _ in range(a+s, b, s): + sP = s * P + for _ in range(a + s, b, s): yield (R := R + sP) @@ -339,6 +340,7 @@ class FastEllipticPolynomial: sage: hP(7 + t) 15*t + 19 """ + def __init__(self, E, n, P, Q=None): r""" Initialize this elliptic polynomial and precompute some @@ -358,31 +360,31 @@ def __init__(self, E, n, P, Q=None): n = Integer(n) if Q is None: - IJK = _choose_IJK(n) # [1,3,5,7,...,n-4,n-2] + IJK = _choose_IJK(n) # [1,3,5,7,...,n-4,n-2] else: - IJK = _choose_IJK(2*n+1) # [1,3,5,7,...,2n-1] = [0,1,2,3,...,n-2,n-1] + IJK = _choose_IJK(2 * n + 1) # [1,3,5,7,...,2n-1] = [0,1,2,3,...,n-2,n-1] self.base = E.base_ring() R, Z = self.base['Z'].objgen() # Cassels, Lectures on Elliptic Curves, p.132 - A,B = E.a_invariants()[-2:] - Fs = lambda X,Y: ( - (X - Y)**2, - -2 * (X*Y + A) * (X + Y) - 4*B, - (X*Y - A)**2 - 4*B*(X+Y), - ) + A, B = E.a_invariants()[-2:] + Fs = lambda X, Y: ( + (X - Y) ** 2, + -2 * (X * Y + A) * (X + Y) - 4 * B, + (X * Y - A) ** 2 - 4 * B * (X + Y), + ) I, J, K = IJK xI = (R.x() for R in _points_range(I, P, Q)) - xJ = [R.x() for R in _points_range(J, P )] + xJ = [R.x() for R in _points_range(J, P)] xK = (R.x() for R in _points_range(K, P, Q)) self.hItree = ProductTree(Z - xi for xi in xI) - self.EJparts = [Fs(Z,xj) for xj in xJ] + self.EJparts = [Fs(Z, xj) for xj in xJ] - DJ = prod(F0j for F0j,_,_ in self.EJparts) + DJ = prod(F0j for F0j, _, _ in self.EJparts) self.DeltaIJ = self._hI_resultant(DJ) self.hK = R(prod(Z - xk for xk in xK)) @@ -420,11 +422,11 @@ def __call__(self, alpha, *, derivative=False): EJparts = [tuple(F.base_extend(base) for F in part) for part in self.EJparts] - EJfacs = [(F0j * alpha + F1j) * alpha + F2j for F0j,F1j,F2j in EJparts] + EJfacs = [(F0j * alpha + F1j) * alpha + F2j for F0j, F1j, F2j in EJparts] if not derivative: EJ = prod(EJfacs) else: - dEJfacs = [2 * F0j * alpha + F1j for F0j,F1j,_ in EJparts] + dEJfacs = [2 * F0j * alpha + F1j for F0j, F1j, _ in EJparts] EJ, dEJ = prod_with_derivative(zip(EJfacs, dEJfacs)) EJrems = self.hItree.remainders(EJ) @@ -579,7 +581,7 @@ def _point_outside_subgroup(P): # assert E.cardinality() > n for _ in range(1000): Q = E.random_point() - if n*Q or not P.weil_pairing(Q,n).is_one(): + if n * Q or not P.weil_pairing(Q, n).is_one(): return Q raise NotImplementedError('could not find a point outside the kernel') @@ -674,6 +676,7 @@ class EllipticCurveHom_velusqrt(EllipticCurveHom): :class:`~sage.schemes.elliptic_curves.ell_curve_isogeny.EllipticCurveIsogeny` """ + def __init__(self, E, P, *, codomain=None, model=None, Q=None): r""" Initialize this square-root Vélu isogeny from a kernel point of odd order. @@ -825,8 +828,8 @@ def _raw_eval(self, x, y=None): h0, h0d = self._h0(x, derivative=True) h1, h1d = self._h1(x, derivative=True) -# assert h0 == prod(x - ( i*self._P).x() for i in range(1,self._P.order(),2)) -# assert h1 == prod(x - (self._Q+i*self._P).x() for i in range( self._P.order() )) + # assert h0 == prod(x - ( i*self._P).x() for i in range(1,self._P.order(),2)) + # assert h1 == prod(x - (self._Q+i*self._P).x() for i in range( self._P.order() )) if not h0: return () @@ -836,8 +839,8 @@ def _raw_eval(self, x, y=None): if y is None: return xx -# assert h0d == sum(prod(x - ( i*self._P).x() for i in range(1,self._P.order(),2) if i!=j) for j in range(1,self._P.order(),2)) -# assert h1d == sum(prod(x - (self._Q+i*self._P).x() for i in range( self._P.order() ) if i!=j) for j in range( self._P.order() )) + # assert h0d == sum(prod(x - ( i*self._P).x() for i in range(1,self._P.order(),2) if i!=j) for j in range(1,self._P.order(),2)) + # assert h1d == sum(prod(x - (self._Q+i*self._P).x() for i in range( self._P.order() ) if i!=j) for j in range( self._P.order() )) yy = y * (h1d - 2 * h1 / h0 * h0d) / h0**2 @@ -891,27 +894,28 @@ def _compute_codomain(self, model=None): poly = self._raw_domain.two_division_polynomial().monic()(Z) f = 1 - for g,_ in poly.factor(): + for g, _ in poly.factor(): if g.degree() == 1: f *= Z - self._raw_eval(-g[0]) else: - K, X0 = self._internal_base_ring.extension(g,'T').objgen() + K, X0 = self._internal_base_ring.extension(g, 'T').objgen() imX0 = self._raw_eval(X0) try: - imX0 = imX0.polynomial() # K is a FiniteField + imX0 = imX0.polynomial() # K is a FiniteField except AttributeError: - imX0 = imX0.lift() # K is a PolynomialQuotientRing + imX0 = imX0.lift() # K is a PolynomialQuotientRing V = R['V'].gen() f *= (Z - imX0(V)).resultant(g(V)) - a6,a4,a2,_ = f.monic().list() + a6, a4, a2, _ = f.monic().list() - self._raw_codomain = EllipticCurve(self._domain.base_ring(), [0,a2,0,a4,a6]) + self._raw_codomain = EllipticCurve(self._domain.base_ring(), [0, a2, 0, a4, a6]) if model is None: model = 'short_weierstrass' from sage.schemes.elliptic_curves.ell_field import compute_model + self._codomain = compute_model(self._raw_codomain, model) self._post_iso = self._raw_codomain.isomorphism_to(self._codomain) @@ -1001,9 +1005,7 @@ def _repr_(self): From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 71 To: Elliptic Curve defined by y^2 = x^3 + 19*x + 45 over Finite Field of size 71 """ - return f'Elliptic-curve isogeny (using square-root Vélu) of degree {self._degree}:' \ - f'\n From: {self._domain}' \ - f'\n To: {self._codomain}' + return f'Elliptic-curve isogeny (using square-root Vélu) of degree {self._degree}:' f'\n From: {self._domain}' f'\n To: {self._codomain}' @staticmethod def _comparison_impl(left, right, op): @@ -1101,6 +1103,7 @@ def as_EllipticCurveIsogeny(self): ker = self.kernel_polynomial() phi = self.domain().isogeny(ker, degree=self.degree(), codomain=self.codomain(), check=False) from sage.schemes.elliptic_curves.hom import find_post_isomorphism + iso = find_post_isomorphism(self, phi) return iso * phi @@ -1152,14 +1155,16 @@ def dual(self): """ if self.base_ring().characteristic().divides(self.degree()): # The dual is inseparable. - #TODO: This is a lazy workaround; it could be optimized more. + # TODO: This is a lazy workaround; it could be optimized more. return self.as_EllipticCurveIsogeny().dual() # The dual is separable. F = self._raw_domain.base_ring() from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism + isom = ~WeierstrassIsomorphism(self._raw_domain, (~F(self._degree), 0, 0, 0)) from sage.schemes.elliptic_curves.ell_curve_isogeny import EllipticCurveIsogeny + phi = EllipticCurveIsogeny(self._raw_codomain, None, isom.domain(), self._degree) return ~self._pre_iso * isom * phi * ~self._post_iso @@ -1317,6 +1322,7 @@ def kernel_subgroup(self, *, extend=False): sage: assert phi.kernel_subgroup() == psi.kernel_subgroup() """ from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper + pt = (~self._pre_iso)(self._P) return AdditiveAbelianGroupWrapper(pt.parent(), [pt], [self._degree]) @@ -1353,8 +1359,8 @@ def _random_example_for_testing(): while True: p = choice(prime_range(2, 100)) - e = randrange(1,5) - F,t = GF((p,e),'t').objgen() + e = randrange(1, 5) + F, t = GF((p, e), 't').objgen() try: E = EllipticCurve([F.random_element() for _ in range(5)]) except ArithmeticError: @@ -1375,7 +1381,7 @@ def _random_example_for_testing(): os = G.generator_orders() while True: v = [randrange(o) for o in os] - if lcm(Mod(c,o).additive_order() for c,o in zip(v,os)) == deg: + if lcm(Mod(c, o).additive_order() for c, o in zip(v, os)) == deg: break K = G(v).element() assert K.order() == deg diff --git a/src/sage/schemes/elliptic_curves/homset.py b/src/sage/schemes/elliptic_curves/homset.py index c6516f9b34b..a85d9b60a74 100644 --- a/src/sage/schemes/elliptic_curves/homset.py +++ b/src/sage/schemes/elliptic_curves/homset.py @@ -84,6 +84,7 @@ class EllipticCurveHomset(SchemeHomset_generic): sage: iso in End(E) False """ + def __init__(self, E1, E2, category=None): r""" Construct the homset for a given pair of elliptic curves @@ -148,7 +149,7 @@ def __init__(self, E1, E2, category=None): super().__init__(E1, E2, category=category, base=base) - #TODO: We should also add CommutativeRings to the category + # TODO: We should also add CommutativeRings to the category # of self whenever this holds true; see the method # EllipticCurve_field.endomorphism_ring_is_commutative(). # Is there a way to perform this check lazily? @@ -197,8 +198,10 @@ def _element_constructor_(self, data): if m: raise ValueError('domain and codomain must be equal') from sage.schemes.elliptic_curves.hom_sum import EllipticCurveHom_sum + return EllipticCurveHom_sum([], domain=self.domain(), codomain=self.codomain()) from sage.schemes.elliptic_curves.hom_scalar import EllipticCurveHom_scalar + return EllipticCurveHom_scalar(self.domain(), m) def _repr_(self): diff --git a/src/sage/schemes/elliptic_curves/isogeny_class.py b/src/sage/schemes/elliptic_curves/isogeny_class.py index 39806e573bd..ecbaf8c903f 100644 --- a/src/sage/schemes/elliptic_curves/isogeny_class.py +++ b/src/sage/schemes/elliptic_curves/isogeny_class.py @@ -156,8 +156,7 @@ def __richcmp__(self, other, op) -> bool: True """ if isinstance(other, IsogenyClass_EC): - return richcmp(sorted(e.a_invariants() for e in self.curves), - sorted(f.a_invariants() for f in other.curves), op) + return richcmp(sorted(e.a_invariants() for e in self.curves), sorted(f.a_invariants() for f in other.curves), op) return NotImplemented def __hash__(self) -> int: @@ -295,9 +294,11 @@ def matrix(self, fill=True): mat = self._mat if fill and mat[0, 0] == 0: from sage.schemes.elliptic_curves.ell_curve_isogeny import fill_isogeny_matrix + mat = fill_isogeny_matrix(mat) if not fill and mat[0, 0] == 1: from sage.schemes.elliptic_curves.ell_curve_isogeny import unfill_isogeny_matrix + mat = unfill_isogeny_matrix(mat) return mat @@ -418,7 +419,7 @@ def graph(self): return G M = self.matrix(fill=False) - n = M.nrows() # = M.ncols() + n = M.nrows() # = M.ncols() G = Graph(M, format='weighted_adjacency_matrix') N = self.matrix(fill=True) D = {v: self.curves[v] for v in G.vertices(sort=False)} @@ -445,38 +446,31 @@ def graph(self): # o--o<8 centervert = next(i for i in range(4) if max(N.row(i)) < maxdegree) other = [i for i in range(4) if i != centervert] - G.set_pos(pos={centervert: [0, 0], other[0]: [0, 1], - other[1]: [-0.8660254, -0.5], other[2]: [0.8660254, -0.5]}) + G.set_pos(pos={centervert: [0, 0], other[0]: [0, 1], other[1]: [-0.8660254, -0.5], other[2]: [0.8660254, -0.5]}) elif maxdegree == 27: # o--o--o--o centers = [i for i in range(4) if list(N.row(i)).count(3) == 2] left = next(j for j in range(4) if N[centers[0], j] == 3 and j not in centers) right = next(j for j in range(4) if N[centers[1], j] == 3 and j not in centers) - G.set_pos(pos={left: [-1.5, 0], centers[0]: [-0.5, 0], - centers[1]: [0.5, 0], right: [1.5, 0]}) + G.set_pos(pos={left: [-1.5, 0], centers[0]: [-0.5, 0], centers[1]: [0.5, 0], right: [1.5, 0]}) elif n == 4: # square opp = next(i for i in range(1, 4) if not N[0, i].is_prime()) other = [i for i in range(1, 4) if i != opp] - G.set_pos(pos={0: [1, 1], other[0]: [-1, 1], - opp: [-1, -1], other[1]: [1, -1]}) + G.set_pos(pos={0: [1, 1], other[0]: [-1, 1], opp: [-1, -1], other[1]: [1, -1]}) elif maxdegree == 8: # 8>o--o<8 centers = [i for i in range(6) if list(N.row(i)).count(2) == 3] left = [j for j in range(6) if N[centers[0], j] == 2 and j not in centers] right = [j for j in range(6) if N[centers[1], j] == 2 and j not in centers] - G.set_pos(pos={centers[0]: [-0.5, 0], left[0]: [-1, 0.8660254], - left[1]: [-1, -0.8660254], centers[1]: [0.5, 0], - right[0]: [1, 0.8660254], right[1]: [1, -0.8660254]}) + G.set_pos(pos={centers[0]: [-0.5, 0], left[0]: [-1, 0.8660254], left[1]: [-1, -0.8660254], centers[1]: [0.5, 0], right[0]: [1, 0.8660254], right[1]: [1, -0.8660254]}) elif maxdegree == 18: # two squares joined on an edge centers = [i for i in range(6) if list(N.row(i)).count(3) == 2] top = [j for j in range(6) if N[centers[0], j] == 3] bl = next(j for j in range(6) if N[top[0], j] == 2) br = next(j for j in range(6) if N[top[1], j] == 2) - G.set_pos(pos={centers[0]: [0, 0.5], centers[1]: [0, -0.5], - top[0]: [-1, 0.5], top[1]: [1, 0.5], - bl: [-1, -0.5], br: [1, -0.5]}) + G.set_pos(pos={centers[0]: [0, 0.5], centers[1]: [0, -0.5], top[0]: [-1, 0.5], top[1]: [1, 0.5], bl: [-1, -0.5], br: [1, -0.5]}) elif maxdegree == 16: # tree from bottom, 3 regular except for the leaves. centers = [i for i in range(8) if list(N.row(i)).count(2) == 3] @@ -485,9 +479,7 @@ def graph(self): bottom = next(j for j in range(8) if N[center, j] == 2 and j not in centers) left = [j for j in range(8) if N[centers[0], j] == 2 and j != center] right = [j for j in range(8) if N[centers[1], j] == 2 and j != center] - G.set_pos(pos={center: [0, 0], bottom: [0, -1], centers[0]: [-0.8660254, 0.5], - centers[1]: [0.8660254, 0.5], left[0]: [-0.8660254, 1.5], - right[0]: [0.8660254, 1.5], left[1]: [-1.7320508, 0], right[1]: [1.7320508, 0]}) + G.set_pos(pos={center: [0, 0], bottom: [0, -1], centers[0]: [-0.8660254, 0.5], centers[1]: [0.8660254, 0.5], left[0]: [-0.8660254, 1.5], right[0]: [0.8660254, 1.5], left[1]: [-1.7320508, 0], right[1]: [1.7320508, 0]}) elif maxdegree == 12: # tent centers = [i for i in range(8) if list(N.row(i)).count(2) == 3] @@ -495,9 +487,7 @@ def graph(self): right = [] for i in range(3): right.append(next(j for j in range(8) if N[centers[1], j] == 2 and N[left[i], j] == 3)) - G.set_pos(pos={centers[0]: [-0.75, 0], centers[1]: [0.75, 0], left[0]: [-0.75, 1], - right[0]: [0.75, 1], left[1]: [-1.25, -0.75], right[1]: [0.25, -0.75], - left[2]: [-0.25, -0.25], right[2]: [1.25, -0.25]}) + G.set_pos(pos={centers[0]: [-0.75, 0], centers[1]: [0.75, 0], left[0]: [-0.75, 1], right[0]: [0.75, 1], left[1]: [-1.25, -0.75], right[1]: [0.25, -0.75], left[2]: [-0.25, -0.25], right[2]: [1.25, -0.25]}) G.set_vertices(D) G.relabel(list(range(1, n + 1))) return G @@ -546,8 +536,7 @@ def reorder(self, order): return self if isinstance(order, str): if order == "lmfdb": - reordered_curves = sorted(self.curves, - key=lambda E: E.a_invariants()) + reordered_curves = sorted(self.curves, key=lambda E: E.a_invariants()) else: reordered_curves = list(self.E.isogeny_class(algorithm=order)) elif isinstance(order, (list, tuple, IsogenyClass_EC)): @@ -570,18 +559,18 @@ def reorder(self, order): raise ValueError("order does not yield a permutation of curves") curves.append(self.curves[j]) if need_perm: - perm.append(j+1) + perm.append(j + 1) cpy.curves = tuple(curves) if need_perm: from sage.groups.perm_gps.permgroup_named import SymmetricGroup + perm = SymmetricGroup(len(self.curves))(perm) cpy._mat = perm.matrix() * self._mat * (~perm).matrix() if self._maps is not None: n = len(self._maps) - cpy._maps = [self._maps[perm(i+1)-1] for i in range(n)] + cpy._maps = [self._maps[perm(i + 1) - 1] for i in range(n)] for i in range(n): - cpy._maps[i] = [cpy._maps[i][perm(jj + 1)-1] - for jj in range(n)] + cpy._maps[i] = [cpy._maps[i][perm(jj + 1) - 1] for jj in range(n)] else: cpy._mat = None cpy._maps = None @@ -592,8 +581,8 @@ class IsogenyClass_EC_NumberField(IsogenyClass_EC): """ Isogeny classes for elliptic curves over number fields. """ - def __init__(self, E, reducible_primes=None, - algorithm='Billerey', minimal_models=True) -> None: + + def __init__(self, E, reducible_primes=None, algorithm='Billerey', minimal_models=True) -> None: r""" INPUT: @@ -795,6 +784,7 @@ def _compute(self, verbose=False): from sage.schemes.elliptic_curves.ell_curve_isogeny import fill_isogeny_matrix from sage.matrix.matrix_space import MatrixSpace from sage.sets.set import Set + self._maps = None if self._minimal_models: @@ -808,6 +798,7 @@ def _compute(self, verbose=False): degs = self._reducible_primes if verbose: import sys + sys.stdout.write(" possible isogeny degrees: %s" % degs) sys.stdout.flush() isogenies = E.isogenies_prime_degree(degs, minimal_models=self._minimal_models) @@ -835,9 +826,9 @@ def add_tup(t): if not any(E2.is_isomorphic(E3) for E3 in curves): curves.append(E2) if verbose: - sys.stdout.write(" -added curve #%s (degree %s)..." % (ncurves,d)) + sys.stdout.write(" -added curve #%s (degree %s)..." % (ncurves, d)) sys.stdout.flush() - add_tup([0,ncurves,d,phi]) + add_tup([0, ncurves, d, phi]) ncurves += 1 if d not in degs: degs.append(d) @@ -858,19 +849,19 @@ def add_tup(t): for phi in isogenies: E2 = phi.codomain() d = phi.degree() - js = [j for j,E3 in enumerate(curves) if E2.is_isomorphic(E3)] - if js: # seen codomain already -- up to isomorphism + js = [j for j, E3 in enumerate(curves) if E2.is_isomorphic(E3)] + if js: # seen codomain already -- up to isomorphism j = js[0] if phi.codomain() != curves[j]: phi = E2.isomorphism_to(curves[j]) * phi assert phi.domain() == curves[i] and phi.codomain() == curves[j] - add_tup([i,j,d,phi]) + add_tup([i, j, d, phi]) else: curves.append(E2) if verbose: sys.stdout.write(" -added curve #%s..." % ncurves) sys.stdout.flush() - add_tup([i,ncurves,d,phi]) + add_tup([i, ncurves, d, phi]) ncurves += 1 i += 1 @@ -879,14 +870,12 @@ def add_tup(t): # key function for sorting if E.has_rational_cm(): - key_function = lambda E: (-E.cm_discriminant(), - flatten([list(ai) for ai in E.ainvs()])) + key_function = lambda E: (-E.cm_discriminant(), flatten([list(ai) for ai in E.ainvs()])) else: key_function = lambda E: flatten([list(ai) for ai in E.ainvs()]) self.curves = sorted(curves, key=key_function) - perm = {ind: self.curves.index(Ei) - for ind, Ei in enumerate(curves)} + perm = {ind: self.curves.index(Ei) for ind, Ei in enumerate(curves)} if verbose: print("Sorting permutation = %s" % perm) @@ -928,8 +917,8 @@ def add_tup(t): print("Creating degree matrix (CM case)") allQs = {} # keys: discriminants d - # values: lists of equivalence classes of - # primitive forms of discriminant d + # values: lists of equivalence classes of + # primitive forms of discriminant d def find_quadratic_form(d, n): if d not in allQs: @@ -940,7 +929,7 @@ def find_quadratic_form(d, n): for Q in allQs[d]: if Q.solve_integer(n): return Q - raise ValueError("No form of discriminant %d represents %s" % (d,n)) + raise ValueError("No form of discriminant %d represents %s" % (d, n)) mat = self._mat qfmat = [[0 for i in range(ncurves)] for j in range(ncurves)] @@ -948,19 +937,19 @@ def find_quadratic_form(d, n): for j, E2 in enumerate(self.curves): if j < i: qfmat[i][j] = qfmat[j][i] - mat[i,j] = mat[j,i] + mat[i, j] = mat[j, i] elif i == j: qfmat[i][j] = [1] # mat[i,j] already 1 else: d = E1.cm_discriminant() if d != E2.cm_discriminant(): - qfmat[i][j] = [mat[i,j]] + qfmat[i][j] = [mat[i, j]] # mat[i,j] already unique - else: # horizontal isogeny - q = find_quadratic_form(d,mat[i,j]) + else: # horizontal isogeny + q = find_quadratic_form(d, mat[i, j]) qfmat[i][j] = list(q) - mat[i,j] = q.small_prime_value() + mat[i, j] = q.small_prime_value() self._mat = mat self._qfmat = qfmat @@ -1003,6 +992,7 @@ class IsogenyClass_EC_Rational(IsogenyClass_EC_NumberField): r""" Isogeny classes for elliptic curves over `\QQ`. """ + def __init__(self, E, algorithm='sage', label=None, empty=False) -> None: r""" INPUT: @@ -1080,6 +1070,7 @@ def _compute(self): """ algorithm = self._algorithm from sage.matrix.matrix_space import MatrixSpace + self._maps = None if algorithm == "database": try: @@ -1092,8 +1083,7 @@ def _compute(self): raise RuntimeError("unable to find %s in the database" % self.E) # All curves will have the same conductor and isogeny class, # and there are most 8 of them, so lexicographic sorting is okay. - self.curves = tuple(sorted(curves, - key=lambda E: E.cremona_label())) + self.curves = tuple(sorted(curves, key=lambda E: E.cremona_label())) self._mat = None elif algorithm == "sage": curves = [self.E.minimal_model()] @@ -1115,16 +1105,16 @@ def _compute(self): except ValueError: j = len(curves) curves.append(Edash) - ijl_triples.append((i,j,l,phi)) + ijl_triples.append((i, j, l, phi)) if l_list is None: l_list = list({ZZ(f.degree()) for f in isogs}) i += 1 self.curves = tuple(curves) ncurves = len(curves) - self._mat = MatrixSpace(ZZ,ncurves)(0) - self._maps = [[0]*ncurves for _ in range(ncurves)] - for i,j,l,phi in ijl_triples: - self._mat[i,j] = l + self._mat = MatrixSpace(ZZ, ncurves)(0) + self._maps = [[0] * ncurves for _ in range(ncurves)] + for i, j, l, phi in ijl_triples: + self._mat[i, j] = l self._maps[i][j] = phi else: raise ValueError("unknown algorithm '%s'" % algorithm) @@ -1243,7 +1233,7 @@ def isogeny_degrees_cm(E, verbose=False): # see if the j-invariants of any proper sub-orders could lie # in the same field - n_over_2h = n//(2*h) + n_over_2h = n // (2 * h) # Collect possible primes. First put in 2, and also 3 for # discriminant -3 (special case because of units): @@ -1290,8 +1280,7 @@ def isogeny_degrees_cm(E, verbose=False): # (b) Downward split primes; the suborder has class number (l-1)*h, so # l-1 must divide n/2h: - L1 = Set([lm1+1 for lm1 in divs - if (lm1+1).is_prime() and kronecker_symbol(d,lm1+1) == +1]) + L1 = Set([lm1 + 1 for lm1 in divs if (lm1 + 1).is_prime() and kronecker_symbol(d, lm1 + 1) == +1]) L += L1 if verbose: print("downward split primes: %s" % L1) @@ -1299,8 +1288,7 @@ def isogeny_degrees_cm(E, verbose=False): # (c) Downward inert primes; the suborder has class number (l+1)*h, so # l+1 must divide n/2h: - L1 = Set([lp1-1 for lp1 in divs - if (lp1-1).is_prime() and kronecker_symbol(d,lp1-1) == -1]) + L1 = Set([lp1 - 1 for lp1 in divs if (lp1 - 1).is_prime() and kronecker_symbol(d, lp1 - 1) == -1]) L += L1 if verbose: print("downward inert primes: %s" % L1) @@ -1311,6 +1299,7 @@ def isogeny_degrees_cm(E, verbose=False): if E.has_rational_cm(): from sage.quadratic_forms.binary_qf import BinaryQF + Qs = [BinaryQF(list(q)) for q in data[2]] L1 = [Q.small_prime_value() for Q in Qs] @@ -1325,14 +1314,14 @@ def isogeny_degrees_cm(E, verbose=False): # This filter will quickly eliminate most false entries in the set from .gal_reps_number_field import Frobenius_filter + L = Frobenius_filter(E, sorted(L)) if verbose: print("List of primes after filtering: %s" % L) return L -def possible_isogeny_degrees(E, algorithm='Billerey', max_l=None, - num_l=None, exact=True, verbose=False): +def possible_isogeny_degrees(E, algorithm='Billerey', max_l=None, num_l=None, exact=True, verbose=False): r""" Return a list of primes `\ell` sufficient to generate the isogeny class of `E`. @@ -1470,6 +1459,7 @@ def possible_isogeny_degrees(E, algorithm='Billerey', max_l=None, if E.base_field() == QQ: from sage.schemes.elliptic_curves.gal_reps_number_field import reducible_primes_naive + return reducible_primes_naive(E, max_l=37, verbose=verbose) # Non-CM case @@ -1494,10 +1484,12 @@ def possible_isogeny_degrees(E, algorithm='Billerey', max_l=None, elif algorithm == 'Billerey': from sage.schemes.elliptic_curves.gal_reps_number_field import reducible_primes_Billerey + L = reducible_primes_Billerey(E, num_l=num_l, max_l=max_l, verbose=verbose) elif algorithm == 'heuristic': from sage.schemes.elliptic_curves.gal_reps_number_field import reducible_primes_naive + L = reducible_primes_naive(E, max_l=max_l, num_P=num_l, verbose=verbose) else: diff --git a/src/sage/schemes/elliptic_curves/isogeny_small_degree.py b/src/sage/schemes/elliptic_curves/isogeny_small_degree.py index 32845b7732e..861640c7911 100644 --- a/src/sage/schemes/elliptic_curves/isogeny_small_degree.py +++ b/src/sage/schemes/elliptic_curves/isogeny_small_degree.py @@ -86,15 +86,15 @@ def Fricke_polynomial(l): """ t = polygen(ZZ, 't') if l == 2: - return (t+16)**3 + return (t + 16) ** 3 if l == 3: - return (t+3)**3*(t+27) + return (t + 3) ** 3 * (t + 27) if l == 5: - return (t**2+10*t+5)**3 + return (t**2 + 10 * t + 5) ** 3 if l == 7: - return (t**2+5*t+1)**3 * (t**2+13*t+49) + return (t**2 + 5 * t + 1) ** 3 * (t**2 + 13 * t + 49) if l == 13: - return (t**2+5*t+13)*(t**4+7*t**3+20*t**2+19*t+1)**3 + return (t**2 + 5 * t + 13) * (t**4 + 7 * t**3 + 20 * t**2 + 19 * t + 1) ** 3 raise ValueError(f"{l} is not a genus 0 prime") @@ -195,7 +195,7 @@ def Psi(l, use_stored=True): if l not in [2, 3, 5, 7, 13]: raise ValueError(f"{l} is not a genus 0 prime") - R, (X, t) = PolynomialRing(ZZ, ['X','t']).objgens() + R, (X, t) = PolynomialRing(ZZ, ['X', 't']).objgens() if use_stored: if l == 2: @@ -203,29 +203,118 @@ def Psi(l, use_stored=True): if l == 3: return X + t + 27 if l == 5: - return X**2 + 2*X*(t**2 + 22*t + 125) + (t**2 + 22*t + 89) * (t**2 + 22*t + 125) + return X**2 + 2 * X * (t**2 + 22 * t + 125) + (t**2 + 22 * t + 89) * (t**2 + 22 * t + 125) if l == 7: - return (X**3 + 3*(t**2 + 13*t + 49)*X**2 - + 3*(t**2 + 13*t + 33)*(t**2 + 13*t + 49)*X - + (t**2 + 13*t + 49)*(t**4 + 26*t**3 + 219*t**2 + 778*t + 881)) + return X**3 + 3 * (t**2 + 13 * t + 49) * X**2 + 3 * (t**2 + 13 * t + 33) * (t**2 + 13 * t + 49) * X + (t**2 + 13 * t + 49) * (t**4 + 26 * t**3 + 219 * t**2 + 778 * t + 881) if l == 13: - return (t**24 + 66*t**23 + 2091*t**22 + 6*X*t**20 + 42582*t**21 + 330*X*t**19 + 627603*t**20 + 8700*X*t**18 + 7134744*t**19 + 15*X**2*t**16 + 146886*X*t**17 + 65042724*t**18 + 660*X**2*t**15 + 1784532*X*t**16 + 487778988*t**17 + 13890*X**2*t**14 + 16594230*X*t**15 + 3061861065*t**16 + 20*X**3*t**12 + 186024*X**2*t**13 + 122552328*X*t**14 + 16280123754*t**15 + 660*X**3*t**11 + 1774887*X**2*t**12 + 735836862*X*t**13 + 73911331425*t**14 + 10380*X**3*t**10 + 12787272*X**2*t**11 + 3646188342*X*t**12 + 287938949178*t**13 + 15*X**4*t**8 + 102576*X**3*t**9 + 71909658*X**2*t**10 + 15047141292*X*t**11 + 964903805434*t**12 + 330*X**4*t**7 + 707604*X**3*t**8 + 321704316*X**2*t**9 + 51955096824*X*t**10 + 2781843718722*t**11 + 3435*X**4*t**6 + 3582876*X**3*t**7 + 1155971196*X**2*t**8 + 150205315932*X*t**9 + 6885805359741*t**10 + 6*X**5*t**4 + 21714*X**4*t**5 + 13632168*X**3*t**6 + 3343499244*X**2*t**7 + 362526695094*X*t**8 + 14569390179114*t**9 + 66*X**5*t**3 + 90660*X**4*t**4 + 39215388*X**3*t**5 + 7747596090*X**2*t**6 + 725403501318*X*t**7 + 26165223178293*t**8 + 336*X**5*t**2 + 255090*X**4*t**3 + 84525732*X**3*t**4 + 14206132008*X**2*t**5 + 1189398495432*X*t**6 + 39474479008356*t**7 + X**6 + 858*X**5*t + 472143*X**4*t**2 + 132886992*X**3*t**3 + 20157510639*X**2*t**4 + 1569568001646*X*t**5 + 49303015587132*t**6 + 1014*X**5 + 525954*X**4*t + 144222780*X**3*t**2 + 21320908440*X**2*t**3 + 1622460290100*X*t**4 + 49941619724976*t**5 + 272259*X**4 + 96482100*X**3*t + 15765293778*X**2*t**2 + 1260038295438*X*t**3 + 39836631701295*t**4 + 29641924*X**3 + 7210949460*X**2*t + 686651250012*X*t**2 + 23947528862166*t**3 + 1506392823*X**2 + 231462513906*X*t + 10114876838391*t**2 + 35655266790*X + 2644809206442*t + 317295487717) -# The coefficients for l=13 are: -# X**6: 1 -# X**5: (6) * (t**2 + 5*t + 13) * (t**2 + 6*t + 13) -# X**4: (3) * (t**2 + 5*t + 13) * (t**2 + 6*t + 13) * (5*t**4 + 55*t**3 + 260*t**2 + 583*t + 537) -# X**3: (4) * (t**2 + 5*t + 13) * (t**2 + 6*t + 13)**2 * (5*t**6 + 80*t**5 + 560*t**4 + 2214*t**3 + 5128*t**2 + 6568*t + 3373) -# X**2: (3) * (t**2 + 5*t + 13)**2 * (t**2 + 6*t + 13)**2 * (5*t**8 + 110*t**7 + 1045*t**6 + 5798*t**5 + 20508*t**4 + 47134*t**3 + 67685*t**2 + 54406*t + 17581) -# X**1: (6) * (t**2 + 5*t + 13)**2 * (t**2 + 6*t + 13)**3 * (t**10 + 27*t**9 + 316*t**8 + 2225*t**7 + 10463*t**6 + 34232*t**5 + 78299*t**4 + 122305*t**3 + 122892*t**2 + 69427*t + 16005) -# X**0: (t**2 + 5*t + 13)**2 * (t**2 + 6*t + 13)**3 * (t**14 + 38*t**13 + 649*t**12 + 6844*t**11 + 50216*t**10 + 271612*t**9 + 1115174*t**8 + 3520132*t**7 + 8549270*t**6 + 15812476*t**5 + 21764840*t**4 + 21384124*t**3 + 13952929*t**2 + 5282630*t + 854569) + return ( + t**24 + + 66 * t**23 + + 2091 * t**22 + + 6 * X * t**20 + + 42582 * t**21 + + 330 * X * t**19 + + 627603 * t**20 + + 8700 * X * t**18 + + 7134744 * t**19 + + 15 * X**2 * t**16 + + 146886 * X * t**17 + + 65042724 * t**18 + + 660 * X**2 * t**15 + + 1784532 * X * t**16 + + 487778988 * t**17 + + 13890 * X**2 * t**14 + + 16594230 * X * t**15 + + 3061861065 * t**16 + + 20 * X**3 * t**12 + + 186024 * X**2 * t**13 + + 122552328 * X * t**14 + + 16280123754 * t**15 + + 660 * X**3 * t**11 + + 1774887 * X**2 * t**12 + + 735836862 * X * t**13 + + 73911331425 * t**14 + + 10380 * X**3 * t**10 + + 12787272 * X**2 * t**11 + + 3646188342 * X * t**12 + + 287938949178 * t**13 + + 15 * X**4 * t**8 + + 102576 * X**3 * t**9 + + 71909658 * X**2 * t**10 + + 15047141292 * X * t**11 + + 964903805434 * t**12 + + 330 * X**4 * t**7 + + 707604 * X**3 * t**8 + + 321704316 * X**2 * t**9 + + 51955096824 * X * t**10 + + 2781843718722 * t**11 + + 3435 * X**4 * t**6 + + 3582876 * X**3 * t**7 + + 1155971196 * X**2 * t**8 + + 150205315932 * X * t**9 + + 6885805359741 * t**10 + + 6 * X**5 * t**4 + + 21714 * X**4 * t**5 + + 13632168 * X**3 * t**6 + + 3343499244 * X**2 * t**7 + + 362526695094 * X * t**8 + + 14569390179114 * t**9 + + 66 * X**5 * t**3 + + 90660 * X**4 * t**4 + + 39215388 * X**3 * t**5 + + 7747596090 * X**2 * t**6 + + 725403501318 * X * t**7 + + 26165223178293 * t**8 + + 336 * X**5 * t**2 + + 255090 * X**4 * t**3 + + 84525732 * X**3 * t**4 + + 14206132008 * X**2 * t**5 + + 1189398495432 * X * t**6 + + 39474479008356 * t**7 + + X**6 + + 858 * X**5 * t + + 472143 * X**4 * t**2 + + 132886992 * X**3 * t**3 + + 20157510639 * X**2 * t**4 + + 1569568001646 * X * t**5 + + 49303015587132 * t**6 + + 1014 * X**5 + + 525954 * X**4 * t + + 144222780 * X**3 * t**2 + + 21320908440 * X**2 * t**3 + + 1622460290100 * X * t**4 + + 49941619724976 * t**5 + + 272259 * X**4 + + 96482100 * X**3 * t + + 15765293778 * X**2 * t**2 + + 1260038295438 * X * t**3 + + 39836631701295 * t**4 + + 29641924 * X**3 + + 7210949460 * X**2 * t + + 686651250012 * X * t**2 + + 23947528862166 * t**3 + + 1506392823 * X**2 + + 231462513906 * X * t + + 10114876838391 * t**2 + + 35655266790 * X + + 2644809206442 * t + + 317295487717 + ) + # The coefficients for l=13 are: + # X**6: 1 + # X**5: (6) * (t**2 + 5*t + 13) * (t**2 + 6*t + 13) + # X**4: (3) * (t**2 + 5*t + 13) * (t**2 + 6*t + 13) * (5*t**4 + 55*t**3 + 260*t**2 + 583*t + 537) + # X**3: (4) * (t**2 + 5*t + 13) * (t**2 + 6*t + 13)**2 * (5*t**6 + 80*t**5 + 560*t**4 + 2214*t**3 + 5128*t**2 + 6568*t + 3373) + # X**2: (3) * (t**2 + 5*t + 13)**2 * (t**2 + 6*t + 13)**2 * (5*t**8 + 110*t**7 + 1045*t**6 + 5798*t**5 + 20508*t**4 + 47134*t**3 + 67685*t**2 + 54406*t + 17581) + # X**1: (6) * (t**2 + 5*t + 13)**2 * (t**2 + 6*t + 13)**3 * (t**10 + 27*t**9 + 316*t**8 + 2225*t**7 + 10463*t**6 + 34232*t**5 + 78299*t**4 + 122305*t**3 + 122892*t**2 + 69427*t + 16005) + # X**0: (t**2 + 5*t + 13)**2 * (t**2 + 6*t + 13)**3 * (t**14 + 38*t**13 + 649*t**12 + 6844*t**11 + 50216*t**10 + 271612*t**9 + 1115174*t**8 + 3520132*t**7 + 8549270*t**6 + 15812476*t**5 + 21764840*t**4 + 21384124*t**3 + 13952929*t**2 + 5282630*t + 854569) # Here the generic kernel polynomials are actually calculated: j = Fricke_module(l) k = j - 1728 - f = prod([p for p,e in j.factor() if e == 3] - + [p for p,e in k.factor() if e == 2]) - A4 = -3*t**2*j*k // f**2 - A6 = -2*t**3*j*k**2 // f**3 + f = prod([p for p, e in j.factor() if e == 3] + [p for p, e in k.factor() if e == 2]) + A4 = -3 * t**2 * j * k // f**2 + A6 = -2 * t**3 * j * k**2 // f**3 E = EllipticCurve([A4, A6]) assert E.j_invariant() == j return E.division_polynomial(l, X).factor()[0][0] @@ -311,28 +400,27 @@ def isogenies_prime_degree_genus_0(E, l=None, minimal_models=True): return isogenies_13_1728(E, minimal_models=minimal_models) if l is None: - return [isog for ell in [2, 3, 5, 7, 13] - for isog in isogenies_prime_degree_genus_0(E, ell, minimal_models=minimal_models)] + return [isog for ell in [2, 3, 5, 7, 13] for isog in isogenies_prime_degree_genus_0(E, ell, minimal_models=minimal_models)] from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(F, NumberField) else None R, t = PolynomialRing(F, 't').objgen() f = R(Fricke_polynomial(l)) - t_list = sorted((f-j*t).roots(multiplicities=False)) + t_list = sorted((f - j * t).roots(multiplicities=False)) # The generic kernel polynomial applies to a standard curve # E_t with the correct j-invariant; we must compute the # appropriate twisting factor to scale X by: c4, c6 = E.c_invariants() - T = c4/(3*c6) + T = c4 / (3 * c6) jt = Fricke_module(l) kt = jt - 1728 psi = Psi(l) X = t - f = R(prod([p for p,e in jt.factor() if e == 3] - + [p for p,e in kt.factor() if e == 2])) + f = R(prod([p for p, e in jt.factor() if e == 3] + [p for p, e in kt.factor() if e == 2])) - E1 = EllipticCurve([-27*c4, -54*c6]) + E1 = EllipticCurve([-27 * c4, -54 * c6]) kernels = [R(psi(X * T * (j - 1728) * t0 / f(t0), t0)).monic() for t0 in t_list] isogs = [E1.isogeny(ker, model=model) for ker in kernels] @@ -349,19 +437,7 @@ def isogenies_prime_degree_genus_0(E, l=None, minimal_models=True): # sporadic_j is a dictionary holding for each possible sporadic # j-invariant, the unique l such that an l-isogeny exists. -sporadic_j = { - QQ(-121) : 11, - QQ(-32768) : 11, - QQ(-24729001) : 11, - QQ(-297756989)/2 : 17, - QQ(-882216989)/131072 : 17, - QQ(-884736) : 19, - QQ(-9317) : 37, - QQ(-162677523113838677) : 37, - QQ(-884736000) : 43, - QQ(-147197952000) : 67, - QQ(-262537412640768000) : 163 - } +sporadic_j = {QQ(-121): 11, QQ(-32768): 11, QQ(-24729001): 11, QQ(-297756989) / 2: 17, QQ(-882216989) / 131072: 17, QQ(-884736): 19, QQ(-9317): 37, QQ(-162677523113838677): 37, QQ(-884736000): 43, QQ(-147197952000): 67, QQ(-262537412640768000): 163} @cached_function @@ -546,6 +622,7 @@ def _sporadic_Q_data(j): ....: assert g % f == 0 """ from sage.rings.real_mpfr import RealField + ell = sporadic_j[j] E = EllipticCurve(j=j).short_weierstrass_model() a4a6 = [E.a4(), E.a6()] @@ -558,9 +635,9 @@ def _sporadic_Q_data(j): w1, w2 = L.basis(prec=pr) X = polygen(RealField(pr), 'X') w = w1 # real period - if j in [-121, -24729001, -162677523113838677, QQ(-882216989)/131072]: - w = 2*w2 - w1 # imaginary period - kerpol = prod(X - L.elliptic_exponential(n*w/ell)[0] for n in range(1, (ell+1)//2)) + if j in [-121, -24729001, -162677523113838677, QQ(-882216989) / 131072]: + w = 2 * w2 - w1 # imaginary period + kerpol = prod(X - L.elliptic_exponential(n * w / ell)[0] for n in range(1, (ell + 1) // 2)) if j == -162677523113838677: kerpolcoeffs = [(37 * c.real()).round() / 37 for c in kerpol] else: @@ -701,16 +778,17 @@ def isogenies_sporadic_Q(E, l=None, minimal_models=True): F = E.base_field() from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(F, NumberField) else None data = _sporadic_Q_data(j) Ew = E.short_weierstrass_model() c4, c6 = Ew.c_invariants() (a4, a6), f = data - d = (c6*a4) / (18*c4*a6) # twisting factor + d = (c6 * a4) / (18 * c4 * a6) # twisting factor R = PolynomialRing(F, 'x') n = len(f) - ker = R([d**(n-i-1) * f[i] for i in range(n)]) + ker = R([d ** (n - i - 1) * f[i] for i in range(n)]) isog = Ew.isogeny(ker, degree=l, model=model, check=False) w = E.isomorphism_to(Ew) isog = isog * w @@ -753,12 +831,13 @@ def isogenies_2(E, minimal_models=True): sage: isogenies_2(E) # not implemented # needs sage.rings.number_field """ from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(E.base_field(), NumberField) else None f2 = E.division_polynomial(2) x2 = sorted(f2.roots(multiplicities=False)) x = f2.parent().gen() - ff = [x-x2i for x2i in x2] + ff = [x - x2i for x2i in x2] isogs = [E.isogeny(f, model=model) for f in ff] return isogs @@ -802,6 +881,7 @@ def isogenies_3(E, minimal_models=True): [] """ from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(E.base_field(), NumberField) else None f3 = E.division_polynomial(3) @@ -811,6 +891,7 @@ def isogenies_3(E, minimal_models=True): isogs = [E.isogeny(f, model=model) for f in ff] return isogs + # 6 special cases: `l` = 5, 7, 13 and `j` = 0, 1728. @@ -904,18 +985,19 @@ def isogenies_5_0(E, minimal_models=True): if not F(5).is_square(): return [] from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(F, NumberField) else None Ew = E.short_weierstrass_model() b = Ew.a6() x = polygen(F) - betas = sorted((x**6-160*b*x**3-80*b**2).roots(multiplicities=False)) + betas = sorted((x**6 - 160 * b * x**3 - 80 * b**2).roots(multiplicities=False)) if not betas: return [] - gammas = [(beta**2 * (beta**3-140*b)) / (120*b) for beta in betas] + gammas = [(beta**2 * (beta**3 - 140 * b)) / (120 * b) for beta in betas] - kernels = [x**2 + beta*x + gamma for beta, gamma in zip(betas, gammas)] + kernels = [x**2 + beta * x + gamma for beta, gamma in zip(betas, gammas)] isogs = [Ew.isogeny(ker, model=model) for ker in kernels] w = E.isomorphism_to(Ew) @@ -1033,6 +1115,7 @@ def isogenies_5_1728(E, minimal_models=True): if F.characteristic() in [2, 3, 5]: raise NotImplementedError("not implemented in characteristic 2, 3 or 5") from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(F, NumberField) else None # quick test for a negative answer (from Fricke module) @@ -1050,14 +1133,14 @@ def isogenies_5_1728(E, minimal_models=True): # Type 1: if -1 is a square we have 2 endomorphisms if square1: i = F(-1).sqrt() - kernels = [x**2 + a / (1+2*i), x**2 + a / (1-2*i)] + kernels = [x**2 + a / (1 + 2 * i), x**2 + a / (1 - 2 * i)] isogs.extend(Ew.isogeny(ker, codomain=E) for ker in kernels) # Type 2: if 5 is a square we have up to 4 (non-endomorphism) isogenies if square5: - betas = sorted((x**4 + 20*a*x**2 - 80*a**2).roots(multiplicities=False)) - gammas = [(beta**2 - 2*a) / 6 for beta in betas] - kernels = [x**2 + beta*x + gamma for beta, gamma in zip(betas, gammas)] + betas = sorted((x**4 + 20 * a * x**2 - 80 * a**2).roots(multiplicities=False)) + gammas = [(beta**2 - 2 * a) / 6 for beta in betas] + kernels = [x**2 + beta * x + gamma for beta, gamma in zip(betas, gammas)] isogs.extend(Ew.isogeny(ker, model=model) for ker in kernels) w = E.isomorphism_to(Ew) @@ -1179,6 +1262,7 @@ def isogenies_7_0(E, minimal_models=True): if F.characteristic() in [2, 3, 7]: raise NotImplementedError("not implemented when the characteristic of the base field is 2, 3 or 7") from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(F, NumberField) else None x = polygen(F) @@ -1187,17 +1271,17 @@ def isogenies_7_0(E, minimal_models=True): # there will be 2 endomorphisms if -3 is a square: ts = sorted(F(-3).sqrt(all=True, extend=False)) - kernels = [7*x - (2 + 6*t) for t in ts] - kernels = [ker(x**3/b).monic() for ker in kernels] + kernels = [7 * x - (2 + 6 * t) for t in ts] + kernels = [ker(x**3 / b).monic() for ker in kernels] isogs = [Ew.isogeny(ker, codomain=E) for ker in kernels] # we may have up to 6 other isogenies: ts = sorted(F(21).sqrt(all=True, extend=False)) for t0 in ts: - s3 = b / (28 + 6*t0) + s3 = b / (28 + 6 * t0) ss = sorted((x**3 - s3).roots(multiplicities=False)) - ker = x**3 - 2*t0*x**2 - 4*t0*x + 4*t0 + 28 - kernels = [ker(x/s).monic() for s in ss] + ker = x**3 - 2 * t0 * x**2 - 4 * t0 * x + 4 * t0 + 28 + kernels = [ker(x / s).monic() for s in ss] isogs.extend(Ew.isogeny(ker, model=model) for ker in kernels) w = E.isomorphism_to(Ew) @@ -1283,6 +1367,7 @@ def isogenies_7_1728(E, minimal_models=True): if F.characteristic() in [2, 3, 7]: raise NotImplementedError("not implemented when the characteristic of the base field is 2, 3 or 7") from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(F, NumberField) else None x = polygen(F) @@ -1295,10 +1380,10 @@ def isogenies_7_1728(E, minimal_models=True): isogs = [] for t0 in ts: - s2 = a/t0 + s2 = a / t0 ss = sorted(s2.sqrt(all=True, extend=False)) - ker = 9*x**3 + (-3*t0**3 - 36*t0**2 - 123*t0)*x**2 + (-8*t0**3 - 101*t0**2 - 346*t0 + 35)*x - 7*t0**3 - 88*t0**2 - 296*t0 + 28 - kernels = [ker(x/s).monic() for s in ss] + ker = 9 * x**3 + (-3 * t0**3 - 36 * t0**2 - 123 * t0) * x**2 + (-8 * t0**3 - 101 * t0**2 - 346 * t0 + 35) * x - 7 * t0**3 - 88 * t0**2 - 296 * t0 + 28 + kernels = [ker(x / s).monic() for s in ss] isogs.extend(Ew.isogeny(ker, model=model) for ker in kernels) w = E.isomorphism_to(Ew) @@ -1426,6 +1511,7 @@ def isogenies_13_0(E, minimal_models=True): if F.characteristic() in [2, 3, 13]: raise NotImplementedError("not implemented when the characteristic of the base field is 2, 3 or 13") from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(F, NumberField) else None x = polygen(F) @@ -1434,22 +1520,17 @@ def isogenies_13_0(E, minimal_models=True): # there will be 2 endomorphisms if -3 is a square: ts = sorted(F(-3).sqrt(all=True, extend=False)) - kernels = [13*x**2 + (78*t + 26)*x + 24*t + 40 for t in ts] - kernels = [ker(x**3/b).monic() for ker in kernels] + kernels = [13 * x**2 + (78 * t + 26) * x + 24 * t + 40 for t in ts] + kernels = [ker(x**3 / b).monic() for ker in kernels] isogs = [Ew.isogeny(ker, codomain=E) for ker in kernels] # we may have up to 12 other isogenies: - ts = sorted((x**4 + 7*x**3 + 20*x**2 + 19*x + 1).roots(multiplicities=False)) + ts = sorted((x**4 + 7 * x**3 + 20 * x**2 + 19 * x + 1).roots(multiplicities=False)) for t0 in ts: - s3 = b / (6*t0**3 + 32*t0**2 + 68*t0 + 4) - ss = sorted((x**3-s3).roots(multiplicities=False)) - ker = (x**6 + (20*t0**3 + 106*t0**2 + 218*t0 + 4)*x**5 - + (-826*t0**3 - 4424*t0**2 - 9244*t0 - 494)*x**4 - + (13514*t0**3 + 72416*t0**2 + 151416*t0 + 8238)*x**3 - + (-101948*t0**3 - 546304*t0**2 - 1142288*t0 - 62116)*x**2 - + (354472*t0**3 + 1899488*t0**2 + 3971680*t0 + 215960)*x - - 459424*t0**3 - 2461888*t0**2 - 5147648*t0 - 279904) - kernels = [ker(x/s).monic() for s in ss] + s3 = b / (6 * t0**3 + 32 * t0**2 + 68 * t0 + 4) + ss = sorted((x**3 - s3).roots(multiplicities=False)) + ker = x**6 + (20 * t0**3 + 106 * t0**2 + 218 * t0 + 4) * x**5 + (-826 * t0**3 - 4424 * t0**2 - 9244 * t0 - 494) * x**4 + (13514 * t0**3 + 72416 * t0**2 + 151416 * t0 + 8238) * x**3 + (-101948 * t0**3 - 546304 * t0**2 - 1142288 * t0 - 62116) * x**2 + (354472 * t0**3 + 1899488 * t0**2 + 3971680 * t0 + 215960) * x - 459424 * t0**3 - 2461888 * t0**2 - 5147648 * t0 - 279904 + kernels = [ker(x / s).monic() for s in ss] isogs.extend(Ew.isogeny(ker, model=model) for ker in kernels) w = E.isomorphism_to(Ew) @@ -1570,6 +1651,7 @@ def isogenies_13_1728(E, minimal_models=True): if F.characteristic() in [2, 3, 13]: raise NotImplementedError("not implemented when the characteristic of the base field is 2, 3 or 13") from sage.rings.number_field.number_field_base import NumberField + model = "minimal" if minimal_models and isinstance(F, NumberField) else None x = polygen(F) @@ -1578,34 +1660,24 @@ def isogenies_13_1728(E, minimal_models=True): # we will have two endomorphisms if -1 is a square: ts = sorted(F(-1).sqrt(all=True, extend=False)) - kernels = [13*x**3 + (-26*i - 13)*x**2 + (-52*i - 13)*x - 2*i - 3 for i in ts] - kernels = [ker(x**2/a).monic() for ker in kernels] + kernels = [13 * x**3 + (-26 * i - 13) * x**2 + (-52 * i - 13) * x - 2 * i - 3 for i in ts] + kernels = [ker(x**2 / a).monic() for ker in kernels] isogs = [Ew.isogeny(ker, codomain=E) for ker in kernels] # we may have up to 12 other isogenies: - ts = sorted((x**6 + 10*x**5 + 46*x**4 + 108*x**3 + 122*x**2 + 38*x - 1).roots(multiplicities=False)) + ts = sorted((x**6 + 10 * x**5 + 46 * x**4 + 108 * x**3 + 122 * x**2 + 38 * x - 1).roots(multiplicities=False)) for t0 in ts: - s2 = a / (66*t0**5 + 630*t0**4 + 2750*t0**3 + 5882*t0**2 + 5414*t0 + 162) + s2 = a / (66 * t0**5 + 630 * t0**4 + 2750 * t0**3 + 5882 * t0**2 + 5414 * t0 + 162) ss = sorted(s2.sqrt(all=True, extend=False)) - ker = (x**6 + (-66*t0**5 - 630*t0**4 - 2750*t0**3 - 5882*t0**2 - - 5414*t0 - 162)*x**5 + (-21722*t0**5 - 205718*t0**4 - - 890146*t0**3 - 1873338*t0**2 - 1652478*t0 + 61610)*x**4 - + (-3391376*t0**5 - 32162416*t0**4 - 139397232*t0**3 - - 294310576*t0**2 - 261885968*t0 + 6105552)*x**3 + - (-241695080*t0**5 - 2291695976*t0**4 - 9930313256*t0**3 - - 20956609720*t0**2 - 18625380856*t0 + 469971320)*x**2 + - (-8085170432*t0**5 - 76663232384*t0**4 - - 332202985024*t0**3 - 701103233152*t0**2 - - 623190845440*t0 + 15598973056)*x - 101980510208*t0**5 - - 966973468160*t0**4 - 4190156868352*t0**3 - - 8843158270336*t0**2 - 7860368751232*t0 + 196854655936) - kernels = [ker(x/s).monic() for s in ss] + ker = x**6 + (-66 * t0**5 - 630 * t0**4 - 2750 * t0**3 - 5882 * t0**2 - 5414 * t0 - 162) * x**5 + (-21722 * t0**5 - 205718 * t0**4 - 890146 * t0**3 - 1873338 * t0**2 - 1652478 * t0 + 61610) * x**4 + (-3391376 * t0**5 - 32162416 * t0**4 - 139397232 * t0**3 - 294310576 * t0**2 - 261885968 * t0 + 6105552) * x**3 + (-241695080 * t0**5 - 2291695976 * t0**4 - 9930313256 * t0**3 - 20956609720 * t0**2 - 18625380856 * t0 + 469971320) * x**2 + (-8085170432 * t0**5 - 76663232384 * t0**4 - 332202985024 * t0**3 - 701103233152 * t0**2 - 623190845440 * t0 + 15598973056) * x - 101980510208 * t0**5 - 966973468160 * t0**4 - 4190156868352 * t0**3 - 8843158270336 * t0**2 - 7860368751232 * t0 + 196854655936 + kernels = [ker(x / s).monic() for s in ss] isogs.extend(Ew.isogeny(ker, model=model) for ker in kernels) w = E.isomorphism_to(Ew) isogs = [isog * w for isog in isogs] return isogs + # List of primes l for which X_0(l) is (hyper)elliptic and X_0^+(l) has genus 0 @@ -1650,107 +1722,182 @@ def _hyperelliptic_isogeny_data(l): raise ValueError(f"{l} must be one of {hyperelliptic_primes}") data = {} Zu = PolynomialRing(ZZ, 'u') - Zuv = PolynomialRing(ZZ, ['u','v']) - Zxuv, (x, u, v) = PolynomialRing(ZZ, ['x','u','v']).objgens() + Zuv = PolynomialRing(ZZ, ['u', 'v']) + Zxuv, (x, u, v) = PolynomialRing(ZZ, ['x', 'u', 'v']).objgens() if l == 11: data['hyper_poly'] = Zu([-7, 12, 2, -16, 1]) data['A2'] = Zu([-33, 55]) - data['A4'] = Zuv(Zu([-135, 738, -183])+v*Zu([-180])) - data['A6'] = Zuv(Zu([1890, 2646, -11466, 1330]) + v*Zu([-1836, 1332])) + data['A4'] = Zuv(Zu([-135, 738, -183]) + v * Zu([-180])) + data['A6'] = Zuv(Zu([1890, 2646, -11466, 1330]) + v * Zu([-1836, 1332])) data['alpha'] = Zu([-6750, 24300, 40095, -187407, 132066, 133056, -177408, 69630, -12716, 1188, -55, 1]) data['beta'] = Zu([0, -12150, 27135, 10665, -48573, 29313, -7187, 843, -47, 1]) - #beta factors as (u - 15) * (u - 6) * (u - 3) * (u - 1) * u * (u**2 - 12*u - 9) * (u**2 - 10*u + 5) + # beta factors as (u - 15) * (u - 6) * (u - 3) * (u - 1) * u * (u**2 - 12*u - 9) * (u**2 - 10*u + 5) return data if l == 17: data['hyper_poly'] = Zu([-8, 4, -3, -10, 1]) data['A2'] = Zu([68, -204, 136]) - data['A4'] = Zuv(Zu([60, 720, -2595, 2250, -435]) + v*Zu([-360, 792, -432])) - data['A6'] = Zuv(Zu([-8512, 22608, -5064, -57528, 87288, -43704, 4912] ) + v*Zu( [2520, -15372, 28098, -20160, 4914])) + data['A4'] = Zuv(Zu([60, 720, -2595, 2250, -435]) + v * Zu([-360, 792, -432])) + data['A6'] = Zuv(Zu([-8512, 22608, -5064, -57528, 87288, -43704, 4912]) + v * Zu([2520, -15372, 28098, -20160, 4914])) data['alpha'] = Zu([16000, -67200, 2720, 557600, -1392232, 1073992, 1104830, -3131026, 2450210, 73746, -1454945, 1110355, -424065, 95659, -13243, 1105, -51, 1]) data['beta'] = Zu([0, 22400, -105920, 146208, 111616, -593800, 680948, -102282, -457950, 468035, -219274, 58549, -9374, 889, -46, 1]) - #beta factors as (u - 10) * (u - 5) * (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 10*u + 7) * (u**2 - 6*u - 4) * (u**2 - 4*u + 2) * (u**3 - 9*u**2 + 8*u - 4) - data['endo'] = 17*x**8 + 17*(-4*u + 4)*v*x**6 + 17*(4*u + 6)*v**2*x**4 + 17*(4*u + 4)*v**3*x**2 + (-4*u + 1)*v**4 + # beta factors as (u - 10) * (u - 5) * (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 10*u + 7) * (u**2 - 6*u - 4) * (u**2 - 4*u + 2) * (u**3 - 9*u**2 + 8*u - 4) + data['endo'] = 17 * x**8 + 17 * (-4 * u + 4) * v * x**6 + 17 * (4 * u + 6) * v**2 * x**4 + 17 * (4 * u + 4) * v**3 * x**2 + (-4 * u + 1) * v**4 data['endo_u'] = 1 return data if l == 19: data['hyper_poly'] = Zu([-8, 20, -8, -8, 1]) data['A2'] = Zu([-114, 57, 171]) - data['A4'] = Zuv(Zu([-1020, 444, 2733, 726, -543]) + v*Zu([-180, -720, -540])) - data['A6'] = Zuv(Zu([-10080, 21816, 54324, -37386, -86742, -20070, 6858]) + v*Zu([-2968, -13748, -11284, 6356, 6860])) + data['A4'] = Zuv(Zu([-1020, 444, 2733, 726, -543]) + v * Zu([-180, -720, -540])) + data['A6'] = Zuv(Zu([-10080, 21816, 54324, -37386, -86742, -20070, 6858]) + v * Zu([-2968, -13748, -11284, 6356, 6860])) data['alpha'] = Zu([16000, -22400, -337440, 475456, 1562104, -1988616, -3025294, 3245960, 2833014, -2420087, -1140950, 932406, 129580, -180443, 21090, 11153, -4066, 570, -38, 1]) data['beta'] = Zu([0, 33600, -8160, -292400, 23472, 791244, 39282, -847909, -47024, 392654, -24046, -82469, 19162, 4833, -2652, 446, -34, 1]) - #beta factors as (u - 7) * (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 8*u - 4) * (u**2 - 6*u - 15) * (u**2 - 5*u - 5) * (u**2 - 5*u + 2) * (u**2 - 2*u - 4) * (u**2 + u - 1) - data['endo'] = 19*x**9 + 19*(-12*u - 24)*v*x**6 + 19*(-24*u - 24)*v**2*x**3 + (96*u - 224)*v**3 + # beta factors as (u - 7) * (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 8*u - 4) * (u**2 - 6*u - 15) * (u**2 - 5*u - 5) * (u**2 - 5*u + 2) * (u**2 - 2*u - 4) * (u**2 + u - 1) + data['endo'] = 19 * x**9 + 19 * (-12 * u - 24) * v * x**6 + 19 * (-24 * u - 24) * v**2 * x**3 + (96 * u - 224) * v**3 data['endo_u'] = -1 return data if l == 23: data['hyper_poly'] = Zu([-7, 10, -11, 2, 2, -8, 1]) data['A2'] = Zu([69, -230, 253]) - data['A4'] = Zuv(Zu([405, 180, -930, 2820, -795]) + v*Zu([360, -792])) - data['A6'] = Zuv(Zu([-15498, 34020, -36918, -8120, 51114, -72492, 12166]) + v*Zu([-1080, 7704, -24840, 12168])) + data['A4'] = Zuv(Zu([405, 180, -930, 2820, -795]) + v * Zu([360, -792])) + data['A6'] = Zuv(Zu([-15498, 34020, -36918, -8120, 51114, -72492, 12166]) + v * Zu([-1080, 7704, -24840, 12168])) data['alpha'] = Zu([-6750, 48600, -83835, -170775, 1115109, -2492280, 2732814, -116403, -4877702, 8362616, -6612454, 302266, 5423124, -6447728, 3209696, 336674, -1470068, 953856, -336927, 74221, -10465, 920, -46, 1]) - data['beta'] = Zu( [0, 12150, -72495, 168588, -144045, -254034, 930982, -1256170, 604358, 693650, -1563176, 1271974, -225188, -444070, 421050, -184350, 47754, -7696, 759, -42, 1]) - #beta factors as (u - 5) * (u - 3) * (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 8*u + 3) * (u**2 - 6*u - 9) * (u**3 - 7*u**2 + 3*u - 5) * (u**3 - 7*u**2 + 7*u - 3) * (u**4 - 4*u**3 - 1) + data['beta'] = Zu([0, 12150, -72495, 168588, -144045, -254034, 930982, -1256170, 604358, 693650, -1563176, 1271974, -225188, -444070, 421050, -184350, 47754, -7696, 759, -42, 1]) + # beta factors as (u - 5) * (u - 3) * (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 8*u + 3) * (u**2 - 6*u - 9) * (u**3 - 7*u**2 + 3*u - 5) * (u**3 - 7*u**2 + 7*u - 3) * (u**4 - 4*u**3 - 1) return data if l == 29: data['hyper_poly'] = Zu([-7, 8, 8, 2, -12, -4, 1]) data['A2'] = Zu([-174, -232, 348, 406]) - data['A4'] = Zuv(Zu([-1215, -3096, 132, 7614, 6504, -360, -1263] ) + v*Zu( [180, -720, -2160, -1260])) - data['A6'] = Zuv(Zu([-18900, -63504, 24696, 285068, 285264, -185136, -506268, -275520, 504, 24388] ) + v*Zu( [4482, -2448, -59868, -94968, -18144, 48276, 24390])) + data['A4'] = Zuv(Zu([-1215, -3096, 132, 7614, 6504, -360, -1263]) + v * Zu([180, -720, -2160, -1260])) + data['A6'] = Zuv(Zu([-18900, -63504, 24696, 285068, 285264, -185136, -506268, -275520, 504, 24388]) + v * Zu([4482, -2448, -59868, -94968, -18144, 48276, 24390])) data['alpha'] = Zu([-6750, -12150, 281880, 570024, -1754181, -5229135, 2357613, 19103721, 9708910, -31795426, -38397537, 19207947, 54103270, 9216142, -37142939, -18871083, 14041394, 10954634, -3592085, -3427365, 853818, 622398, -189399, -53679, 26680, -580, -1421, 319, -29, 1]) data['beta'] = Zu([0, -24300, -57510, 257850, 839187, -373185, -3602119, -2371192, 5865017, 8434433, -2363779, -10263744, -2746015, 5976011, 3151075, -2093854, -1356433, 569525, 299477, -129484, -28279, 19043, -895, -1076, 273, -27, 1]) - #beta factors as (u - 3) * (u - 1) * u * (u + 1) * (u + 2) * (u**2 - 6*u + 2) * (u**2 - 5*u - 5) * (u**2 - 5*u + 3) * (u**2 - 3*u - 9) * (u**2 - u - 3) * (u**2 - u - 1) * (u**2 + u - 1) * (u**3 - 4*u**2 - 6*u - 5) * (u**4 - 2*u**3 - 5*u**2 - 4*u - 1) - data['endo'] = 29*x**14 + 29*(-14*u + 3)*v*x**12 + 29*(-20*u + 73)*v**2*x**10 + 29*(-58*u + 115)*v**3*x**8 + 29*(-56*u + 59)*v**4*x**6 + 29*(30*u + 1)*v**5*x**4 + 29*(12*u - 5)*v**6*x**2 + (2*u + 5)*v**7 + # beta factors as (u - 3) * (u - 1) * u * (u + 1) * (u + 2) * (u**2 - 6*u + 2) * (u**2 - 5*u - 5) * (u**2 - 5*u + 3) * (u**2 - 3*u - 9) * (u**2 - u - 3) * (u**2 - u - 1) * (u**2 + u - 1) * (u**3 - 4*u**2 - 6*u - 5) * (u**4 - 2*u**3 - 5*u**2 - 4*u - 1) + data['endo'] = 29 * x**14 + 29 * (-14 * u + 3) * v * x**12 + 29 * (-20 * u + 73) * v**2 * x**10 + 29 * (-58 * u + 115) * v**3 * x**8 + 29 * (-56 * u + 59) * v**4 * x**6 + 29 * (30 * u + 1) * v**5 * x**4 + 29 * (12 * u - 5) * v**6 * x**2 + (2 * u + 5) * v**7 data['endo_u'] = -1 return data if l == 31: data['hyper_poly'] = Zu([-3, -14, -11, 18, 6, -8, 1]) data['A2'] = Zu([558, 837, -1488, 465]) - data['A4'] = Zuv(Zu([-4140, -12468, 15189, 16956, -27054, 11184, -1443]) + v*Zu([2160, -7560, 6120, -1440])) - data['A6'] = Zuv(Zu([71280, 592056, -108324, -2609730, 2373048, 1282266, -2793204, 1530882, -356976, 29790]) + v*Zu([-81312, 181664, 294728, -868392, 701400, -238840, 29792])) + data['A4'] = Zuv(Zu([-4140, -12468, 15189, 16956, -27054, 11184, -1443]) + v * Zu([2160, -7560, 6120, -1440])) + data['A6'] = Zuv(Zu([71280, 592056, -108324, -2609730, 2373048, 1282266, -2793204, 1530882, -356976, 29790]) + v * Zu([-81312, 181664, 294728, -868392, 701400, -238840, 29792])) data['alpha'] = Zu([108000, 475200, -7053120, -27353408, 90884374, 303670296, -665806437, -1361301729, 3259359840, 2249261823, -9368721606, 2279583264, 13054272515, -12759480061, -4169029296, 14390047139, -7803693550, -2988803682, 6239473912, -3296588360, 134066754, 908915598, -685615437, 294482733, -87483178, 18983315, -3052818, 361336, -30659, 1767, -62, 1]) data['beta'] = Zu([0, 712800, 1216080, -18430560, -15262464, 168899202, -12931221, -720077416, 624871714, 1239052988, -2259335558, 68648452, 2679085427, -2318039014, -229246628, 1710545918, -1243026758, 211524870, 296674626, -291810274, 145889932, -48916468, 11793961, -2085662, 269348, -24778, 1540, -58, 1]) - #beta factors as (u - 3) * (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 8*u + 11) * (u**2 - 7*u + 2) * (u**2 - 5*u - 2) * (u**2 - 5*u + 5) * (u**2 - 4*u - 4) * (u**2 - 4*u - 1) * (u**2 - 2*u - 1) * (u**2 - u - 1) * (u**3 - 9*u**2 + 21*u - 15) * (u**4 - 8*u**3 + 8*u**2 + 12*u - 9) - data['endo'] = 31*x**15 + 31*(-66*u + 86)*v*x**12 + 31*(168*u + 280)*v**2*x**9 + 31*(576*u + 1792)*v**3*x**6 + 31*(384*u + 896)*v**4*x**3 + (-3072*u - 2048)*v**5 + # beta factors as (u - 3) * (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 8*u + 11) * (u**2 - 7*u + 2) * (u**2 - 5*u - 2) * (u**2 - 5*u + 5) * (u**2 - 4*u - 4) * (u**2 - 4*u - 1) * (u**2 - 2*u - 1) * (u**2 - u - 1) * (u**3 - 9*u**2 + 21*u - 15) * (u**4 - 8*u**3 + 8*u**2 + 12*u - 9) + data['endo'] = 31 * x**15 + 31 * (-66 * u + 86) * v * x**12 + 31 * (168 * u + 280) * v**2 * x**9 + 31 * (576 * u + 1792) * v**3 * x**6 + 31 * (384 * u + 896) * v**4 * x**3 + (-3072 * u - 2048) * v**5 data['endo_u'] = 2 return data if l == 41: data['hyper_poly'] = Zu([-8, -20, -15, 8, 20, 10, -8, -4, 1]) data['A2'] = Zu([328, 656, -656, -1148, 820]) - data['A4'] = Zuv(Zu([-1380, -4008, 1701, 10872, 6144, -18378, -2160, 9732, -2523]) + v*Zu([720, -1440, -2160, 5400, -2520])) - data['A6'] = Zuv(Zu([4480, 155616, 16080, -550720, -343968, 832680, 938632, -621648, -1468608, 953920, 427632, -413016, 68920]) + v*Zu([-14616, 6804, 96390, -2016, -324324, 184464, 260568, -276192, 68922])) + data['A4'] = Zuv(Zu([-1380, -4008, 1701, 10872, 6144, -18378, -2160, 9732, -2523]) + v * Zu([720, -1440, -2160, 5400, -2520])) + data['A6'] = Zuv(Zu([4480, 155616, 16080, -550720, -343968, 832680, 938632, -621648, -1468608, 953920, 427632, -413016, 68920]) + v * Zu([-14616, 6804, 96390, -2016, -324324, 184464, 260568, -276192, 68922])) data['alpha'] = Zu([16000, 67200, -465760, -2966432, -1742664, 20985112, 46140990, -31732934, -217030548, -147139488, 436080674, 745775322, -271341362, -1542677562, -605560447, 1832223375, 1772593672, -1270633050, -2400692229, 343522723, 2179745361, 282422801, -1503727029, -421357697, 879637411, 261059095, -462271351, -61715127, 193718727, -24135265, -49355103, 20512341, 3613289, -4706595, 1099661, 163057, -162483, 46617, -7544, 738, -41, 1]) data['beta'] = Zu([0, 44800, 167040, -447040, -2734272, -1104272, 13488360, 21067652, -24681704, -83929974, -8986886, 169059382, 127641266, -196479899, -283039783, 124573790, 366614063, -12946368, -332987597, -58867672, 241909907, 60568430, -155045647, -17919564, 79114945, -12025938, -24060781, 11190142, 1979597, -2931764, 750233, 110144, -122263, 37484, -6439, 666, -39, 1]) - #beta factors as (u - 5) * (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 5*u + 5) * (u**2 - 3*u - 7) * (u**2 - 2*u - 4) * (u**2 - 2*u - 1) * (u**2 - u - 1) * (u**2 - 2) * (u**2 + u - 1) * (u**3 - 3*u**2 - 5*u - 2) * (u**3 - 2*u**2 - 2*u - 1) * (u**4 - 6*u**3 + 5*u**2 + 2*u - 1) * (u**4 - 5*u**3 + u**2 + 4) * (u**4 - 4*u**3 + 2) - data['endo'] = 41*x**20 + 41*(-12*u - 22)*v*x**18 + 41*(-252*u - 247)*v**2*x**16 + 41*(-176*u - 424)*v**3*x**14 + 41*(464*u - 254)*v**4*x**12 + 41*(1688*u - 868)*v**5*x**10 + 41*(1720*u - 1190)*v**6*x**8 + 41*(528*u - 232)*v**7*x**6 + 41*(16*u + 29)*v**8*x**4 + 41*(20*u + 10)*v**9*x**2 + (4*u + 5)*v**10 + # beta factors as (u - 5) * (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 5*u + 5) * (u**2 - 3*u - 7) * (u**2 - 2*u - 4) * (u**2 - 2*u - 1) * (u**2 - u - 1) * (u**2 - 2) * (u**2 + u - 1) * (u**3 - 3*u**2 - 5*u - 2) * (u**3 - 2*u**2 - 2*u - 1) * (u**4 - 6*u**3 + 5*u**2 + 2*u - 1) * (u**4 - 5*u**3 + u**2 + 4) * (u**4 - 4*u**3 + 2) + data['endo'] = 41 * x**20 + 41 * (-12 * u - 22) * v * x**18 + 41 * (-252 * u - 247) * v**2 * x**16 + 41 * (-176 * u - 424) * v**3 * x**14 + 41 * (464 * u - 254) * v**4 * x**12 + 41 * (1688 * u - 868) * v**5 * x**10 + 41 * (1720 * u - 1190) * v**6 * x**8 + 41 * (528 * u - 232) * v**7 * x**6 + 41 * (16 * u + 29) * v**8 * x**4 + 41 * (20 * u + 10) * v**9 * x**2 + (4 * u + 5) * v**10 data['endo_u'] = 1 return data if l == 47: data['hyper_poly'] = Zu([-11, 28, -38, 30, -13, -16, 19, -24, 11, -6, 1]) data['A2'] = Zu([376, -1504, 2209, -1598, 1081]) - data['A4'] = Zuv(Zu([2400, -4080, -1440, 18000, -26355, 34740, -22050, 12900, -3315]) + v*Zu([1152, -3384, 3672, -3312])) - data['A6'] = Zuv(Zu([-119504, 606336, -1505280, 2109392, -1509360, -515808, 2920702, -4614012, 4334322, -3260312, 1571442, -622428, 103822]) + v*Zu([2016, 48384, -235872, 438984, -627480, 503496, -311976, 103824])) + data['A4'] = Zuv(Zu([2400, -4080, -1440, 18000, -26355, 34740, -22050, 12900, -3315]) + v * Zu([1152, -3384, 3672, -3312])) + data['A6'] = Zuv(Zu([-119504, 606336, -1505280, 2109392, -1509360, -515808, 2920702, -4614012, 4334322, -3260312, 1571442, -622428, 103822]) + v * Zu([2016, 48384, -235872, 438984, -627480, 503496, -311976, 103824])) data['alpha'] = Zu([-65536, 688128, -2502656, -96256, 38598656, -187217920, 508021120, -845669120, 552981696, 1469334304, -5945275904, 11705275552, -14673798654, 9100068184, 8421580132, -34288012648, 56657584158, -60426283952, 36612252089, 9942017442, -60791892299, 93046207239, -92028642340, 59196883097, -10454018992, -33364599371, 57280402355, -57873890484, 41879296232, -20241250112, 2065827049, 8435506655, -11611941072, 10182603298, -7040645261, 4071881378, -2013138357, 856757031, -313468474, 97893151, -25770006, 5617769, -990431, 136864, -14194, 1034, -47, 1]) data['beta'] = Zu([0, 114688, -1114112, 4854784, -11205632, 7426048, 42663936, -182555136, 394092544, -508851472, 213245648, 743315936, -2203729384, 3409478688, -3280008936, 1139839970, 2576264698, -6272528962, 8005203155, -6671665088, 2744569094, 1996771588, -5520074039, 6637395180, -5455622885, 3028415830, -601645255, -1012737914, 1632999370, -1525982346, 1093778952, -644352392, 319489974, -134176208, 47566499, -14083902, 3424200, -667810, 101271, -11438, 901, -44, 1]) - #beta factors as (u - 4) * (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 5*u + 2) * (u**2 - 2*u - 1) * (u**3 - 5*u**2 + 5*u - 7) * (u**3 - 4*u**2 + 3*u - 4) * (u**3 - 4*u**2 + 3*u - 1) * (u**3 - 3*u**2 + 2*u - 4) * (u**3 - 2*u**2 + 2*u - 2) * (u**3 + u + 1) * (u**4 - 4*u**3 - 2*u**2 - 4) * (u**5 - 5*u**4 + 5*u**3 - 11*u**2 + 6*u - 4) * (u**6 - 4*u**5 + 2*u**4 - 4*u**3 - u**2 + 4*u - 2) + # beta factors as (u - 4) * (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 5*u + 2) * (u**2 - 2*u - 1) * (u**3 - 5*u**2 + 5*u - 7) * (u**3 - 4*u**2 + 3*u - 4) * (u**3 - 4*u**2 + 3*u - 1) * (u**3 - 3*u**2 + 2*u - 4) * (u**3 - 2*u**2 + 2*u - 2) * (u**3 + u + 1) * (u**4 - 4*u**3 - 2*u**2 - 4) * (u**5 - 5*u**4 + 5*u**3 - 11*u**2 + 6*u - 4) * (u**6 - 4*u**5 + 2*u**4 - 4*u**3 - u**2 + 4*u - 2) return data if l == 59: data['hyper_poly'] = Zu([-8, -4, 20, -24, -3, 40, -62, 40, 3, -28, 22, -8, 1]) data['A2'] = Zu([590, -1475, -295, 4130, -4425, 1711]) - data['A4'] = Zuv(Zu([-2460, 8844, -3843, -20718, 57153, -50418, -12600, 72762, -69339, 30978, -5223]) + v*Zu([900, 360, -7560, 10800, -5220])) - data['A6'] = Zuv(Zu([25760, -373560, 568020, 1147870, -4634370, 5318070, 1631996, -14270202, 21535998, -14119408, -2820102, 14275410, -13535292, 6790074, -1847898, 205378]) + v*Zu([-23688, 27972, 183708, -696024, 721980, 453600, -1925028, 2039184, -1027404, 205380])) + data['A4'] = Zuv(Zu([-2460, 8844, -3843, -20718, 57153, -50418, -12600, 72762, -69339, 30978, -5223]) + v * Zu([900, 360, -7560, 10800, -5220])) + data['A6'] = Zuv(Zu([25760, -373560, 568020, 1147870, -4634370, 5318070, 1631996, -14270202, 21535998, -14119408, -2820102, 14275410, -13535292, 6790074, -1847898, 205378]) + v * Zu([-23688, 27972, 183708, -696024, 721980, 453600, -1925028, 2039184, -1027404, 205380])) data['alpha'] = Zu([16000, -67200, -783520, 5573376, -5127336, -60792184, 241324042, -170978932, -1262437160, 4310971231, -3953349811, -10887235780, 41679530185, -51342089572, -33068562195, 230682514316, -372641172307, 121615007703, 682044179678, -1549365239197, 1373184591667, 614906882627, -3566756201696, 4920423266916, -2342393877496, -3589340274442, 8772457933356, -8488557160148, 1742977715620, 7131088674129, -11643540780203, 8512399456274, -315658868113, -6917286294515, 8713332734648, -5190227733987, -54249978263, 3397583328372, -3658171840037, 1987950394792, -179519591637, -748989116551, 800595050760, -459184355769, 134398080099, 28871590941, -64236756338, 46651654354, -23352309386, 9059054346, -2830320860, 721829600, -150487052, 25475079, -3452149, 365800, -29205, 1652, -59, 1]) data['beta'] = Zu([0, -56000, 320800, 391440, -7693120, 21125500, 11515130, -204780145, 486681785, -102547033, -2147060784, 5552726794, -4419031758, -9431888681, 33728080307, -42367773552, -2994127157, 105330637610, -188172973931, 127559513693, 123083802224, -421097252069, 490425751691, -161944881372, -408669953969, 799965143719, -668167261718, 69589638764, 563644022562, -787681290965, 505670881115, 2900924856, -364669742737, 407962360532, -223582547975, 9985786664, 102435489491, -105519055992, 58212400117, -14331637533, -6742538722, 10205452686, -6853903214, 3244679736, -1188153136, 347102566, -81626216, 15409226, -2307408, 268126, -23322, 1429, -55, 1]) - #beta factors as (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 4*u - 1) * (u**2 - 3*u - 5) * (u**2 - 3*u - 2) * (u**2 - 3*u + 1) * (u**2 - u - 1) * (u**3 - 6*u**2 + 10*u - 7) * (u**3 - 5*u**2 + 7*u - 5) * (u**3 - 3*u**2 + 2*u - 1) * (u**3 - u**2 + 1) * (u**4 - 5*u**3 + 4*u**2 - 1) * (u**4 - 4*u**3 + 3*u**2 + 2*u - 4) * (u**4 - 3*u**3 - u - 1) * (u**4 - u**3 + 2*u - 1) * (u**5 - 6*u**4 + 10*u**3 - 11*u**2 + 8*u - 4) * (u**6 - 5*u**5 + 5*u**4 - 5*u**2 + 5*u - 5) + # beta factors as (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 4*u - 1) * (u**2 - 3*u - 5) * (u**2 - 3*u - 2) * (u**2 - 3*u + 1) * (u**2 - u - 1) * (u**3 - 6*u**2 + 10*u - 7) * (u**3 - 5*u**2 + 7*u - 5) * (u**3 - 3*u**2 + 2*u - 1) * (u**3 - u**2 + 1) * (u**4 - 5*u**3 + 4*u**2 - 1) * (u**4 - 4*u**3 + 3*u**2 + 2*u - 4) * (u**4 - 3*u**3 - u - 1) * (u**4 - u**3 + 2*u - 1) * (u**5 - 6*u**4 + 10*u**3 - 11*u**2 + 8*u - 4) * (u**6 - 5*u**5 + 5*u**4 - 5*u**2 + 5*u - 5) return data if l == 71: data['hyper_poly'] = Zu([-7, 6, -27, 40, -58, 66, -66, 40, 15, -48, 66, -66, 37, -10, 1]) data['A2'] = Zu([213, -1420, 4260, -4970, 9940, -9088, 2485]) - data['A4'] = Zuv(Zu([2565, -10008, 18024, -26532, 23208, 7584, -104418, 189432, -251736, 275148, -182232, 60144, -7563]) + v*Zu([720, -4320, 7560, -20160, 23040, -7560])) - data['A6'] = Zuv(Zu([-69930, 382536, -1898568, 5206124, -11813256, 23115792, -35705670, 44318064, -41531952, 20674360, 23881872, -77986944, 114989770, -124612152, 103122936, -59431204, 21485688, -4294416, 357910]) + v*Zu([18576, -53856, 57672, 161856, -961920, 3199176, -5706288, 8032896, -9352584, 6786720, -2505888, 357912])) - data['alpha'] = Zu([-6750, 97200, -603855, 2263977, -4854483, -2486349, 75190491, -399596520, 1441975423, -4089818964, 9450153463, -17516526653, 23635982289, -11859874932, -53385529273, 230566737711, -585283867605, 1136695427037, -1753961304140, 2020891913264, -1147488305875, -1930304898882, 8102336330029, -17218530732347, 27006964902986, -32365758791872, 25902000374138, -468390635342, -46332664858222, 107139839089502, -162234735929274, 182582147217312, -140033523896938, 22513210292184, 152367877270246, -334009986053250, 451855980915164, -443144048889720, 284518400252142, -11142427766850, -289840331821002, 512373447321402, -576967281819172, 466024421705696, -230395084854230, -36287337331916, 241209603962570, -330646545417814, 304702155703516, -205131886553392, 87504290135653, 5131997859077, -54867900326127, 66216047255551, -54817285755105, 36239054778472, -20052219750661, 9464634765852, -3841191816845, 1343947848527, -405138280373, 104923131180, -23228729413, 4364552115, -689157169, 90223321, -9613968, 812240, -52327, 2414, -71, 1]) + data['A4'] = Zuv(Zu([2565, -10008, 18024, -26532, 23208, 7584, -104418, 189432, -251736, 275148, -182232, 60144, -7563]) + v * Zu([720, -4320, 7560, -20160, 23040, -7560])) + data['A6'] = Zuv(Zu([-69930, 382536, -1898568, 5206124, -11813256, 23115792, -35705670, 44318064, -41531952, 20674360, 23881872, -77986944, 114989770, -124612152, 103122936, -59431204, 21485688, -4294416, 357910]) + v * Zu([18576, -53856, 57672, 161856, -961920, 3199176, -5706288, 8032896, -9352584, 6786720, -2505888, 357912])) + data['alpha'] = Zu( + [ + -6750, + 97200, + -603855, + 2263977, + -4854483, + -2486349, + 75190491, + -399596520, + 1441975423, + -4089818964, + 9450153463, + -17516526653, + 23635982289, + -11859874932, + -53385529273, + 230566737711, + -585283867605, + 1136695427037, + -1753961304140, + 2020891913264, + -1147488305875, + -1930304898882, + 8102336330029, + -17218530732347, + 27006964902986, + -32365758791872, + 25902000374138, + -468390635342, + -46332664858222, + 107139839089502, + -162234735929274, + 182582147217312, + -140033523896938, + 22513210292184, + 152367877270246, + -334009986053250, + 451855980915164, + -443144048889720, + 284518400252142, + -11142427766850, + -289840331821002, + 512373447321402, + -576967281819172, + 466024421705696, + -230395084854230, + -36287337331916, + 241209603962570, + -330646545417814, + 304702155703516, + -205131886553392, + 87504290135653, + 5131997859077, + -54867900326127, + 66216047255551, + -54817285755105, + 36239054778472, + -20052219750661, + 9464634765852, + -3841191816845, + 1343947848527, + -405138280373, + 104923131180, + -23228729413, + 4364552115, + -689157169, + 90223321, + -9613968, + 812240, + -52327, + 2414, + -71, + 1, + ] + ) data['beta'] = Zu([0, 12150, -163215, 1115640, -5311143, 18820224, -50700172, 99823812, -102454041, -183909134, 1354660714, -4462311942, 10695310224, -20015395554, 28262441676, -23240987282, -17879387475, 124501604946, -315187724212, 564766450688, -765154573538, 705985549104, -115433273216, -1206098873334, 3175185881748, -5228317292044, 6292310032120, -5077451367560, 719644756530, 6451571564682, -14460150103020, 19999710623352, -19681838601268, 11819712227412, 2180981559572, -17790742756618, 29025463386612, -31179247603548, 23207078145510, -8345354986332, -7468523752270, 18486966963350, -21719818051100, 17831212433536, -10100011266030, 2336962513536, 2906983627184, -4989755986066, 4711466210012, -3361479243242, 1952316811463, -948555371584, 389878900245, -136099552242, 40341734984, -10121407164, 2136756509, -376218102, 54551634, -6399080, 591884, -41538, 2078, -66, 1]) - #beta factors as (u - 3) * (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 5*u + 5) * (u**2 - 3*u + 1) * (u**2 - 2*u - 1) * (u**2 - u - 1) * (u**3 - 5*u**2 + 5*u - 3) * (u**3 - 4*u**2 - 1) * (u**3 - 2*u**2 - 1) * (u**4 - 6*u**3 + 7*u**2 + 6*u - 9) * (u**4 - 5*u**3 + 4*u**2 + u + 3) * (u**4 - 5*u**3 + 6*u**2 - 3*u + 5) * (u**4 - 4*u**3 + u**2 - 4*u + 1) * (u**4 - 4*u**3 + 2*u**2 - u + 1) * (u**4 - 2*u**3 - 3*u**2 - 2*u - 1) * (u**4 - 2*u**3 + u - 1) * (u**6 - 5*u**5 + 8*u**4 - 7*u**3 + 6*u**2 - 3*u + 1) * (u**8 - 6*u**7 + 9*u**6 - 2*u**5 + 2*u**3 - 9*u**2 + 2*u - 1) + # beta factors as (u - 3) * (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 5*u + 5) * (u**2 - 3*u + 1) * (u**2 - 2*u - 1) * (u**2 - u - 1) * (u**3 - 5*u**2 + 5*u - 3) * (u**3 - 4*u**2 - 1) * (u**3 - 2*u**2 - 1) * (u**4 - 6*u**3 + 7*u**2 + 6*u - 9) * (u**4 - 5*u**3 + 4*u**2 + u + 3) * (u**4 - 5*u**3 + 6*u**2 - 3*u + 5) * (u**4 - 4*u**3 + u**2 - 4*u + 1) * (u**4 - 4*u**3 + 2*u**2 - u + 1) * (u**4 - 2*u**3 - 3*u**2 - 2*u - 1) * (u**4 - 2*u**3 + u - 1) * (u**6 - 5*u**5 + 8*u**4 - 7*u**3 + 6*u**2 - 3*u + 1) * (u**8 - 6*u**7 + 9*u**6 - 2*u**5 + 2*u**3 - 9*u**2 + 2*u - 1) return data @@ -1793,34 +1940,35 @@ def Psi2(l): R = PolynomialRing(QQ, 'u') L, v = PolynomialRing(R, 'v').objgen() - K = R.extension(v*v - R(data['hyper_poly']), 'v') + K = R.extension(v * v - R(data['hyper_poly']), 'v') v = K.gen() from sage.categories.homset import Hom - h = Hom(K,K)(-v) + + h = Hom(K, K)(-v) A = K(data['A4']) B = K(data['A6']) - Abar = h(A)*l**2 - Bbar = -h(B)*l**3 + Abar = h(A) * l**2 + Bbar = -h(B) * l**3 s1 = K(data['A2']) - d = (l-1)//2 + d = (l - 1) // 2 s = [K(1)] - t = [d, s1, ((1-10*d)*A - Abar) / 30] - t.append(((1-28*d)*B - 42*t[1]*A - Bbar) / 70) - c = [0, 6*t[2] + 2*A*t[0], 10*t[3] + 6*A*t[1] + 4*B*t[0]] + t = [d, s1, ((1 - 10 * d) * A - Abar) / 30] + t.append(((1 - 28 * d) * B - 42 * t[1] * A - Bbar) / 70) + c = [0, 6 * t[2] + 2 * A * t[0], 10 * t[3] + 6 * A * t[1] + 4 * B * t[0]] for n in range(2, d): - k = sum(c[i]*c[n-i] for i in range(1, n)) - c.append((3*k - (2*n-1)*(n-1)*A*c[n-1] - (2*n-2)*(n-2)*B*c[n-2]) / ((2*n+5)*(n-1))) + k = sum(c[i] * c[n - i] for i in range(1, n)) + c.append((3 * k - (2 * n - 1) * (n - 1) * A * c[n - 1] - (2 * n - 2) * (n - 2) * B * c[n - 2]) / ((2 * n + 5) * (n - 1))) for n in range(3, d): - t.append((c[n] - (4*n-2)*A*t[n-1] - (4*n-4)*B*t[n-2]) / (4*n+2)) - for n in range(1, d+1): - s.append(sum((-1)**i*t[i]*s[n-i] for i in range(1, n+1)) / -n) + t.append((c[n] - (4 * n - 2) * A * t[n - 1] - (4 * n - 4) * B * t[n - 2]) / (4 * n + 2)) + for n in range(1, d + 1): + s.append(sum((-1) ** i * t[i] * s[n - i] for i in range(1, n + 1)) / -n) - R = PolynomialRing(QQ, ['x','u','v']) + R = PolynomialRing(QQ, ['x', 'u', 'v']) x = R.gen(0) - return sum((-1)**i * x**(d-i) * s[i].lift() for i in range(d+1)) + return sum((-1) ** i * x ** (d - i) * s[i].lift() for i in range(d + 1)) def isogenies_prime_degree_genus_plus_0(E, l=None, minimal_models=True): @@ -2005,8 +2153,7 @@ def isogenies_prime_degree_genus_plus_0(E, l=None, minimal_models=True): to Elliptic Curve defined by y^2 + y = x^3 + x^2 + 5*x + 6 over Finite Field of size 13] """ if l is None: - return sum([isogenies_prime_degree_genus_plus_0(E, ell, minimal_models=minimal_models) - for ell in hyperelliptic_primes],[]) + return sum([isogenies_prime_degree_genus_plus_0(E, ell, minimal_models=minimal_models) for ell in hyperelliptic_primes], []) if l not in hyperelliptic_primes: raise ValueError(f"{l} must be one of {hyperelliptic_primes}") @@ -2022,21 +2169,21 @@ def isogenies_prime_degree_genus_plus_0(E, l=None, minimal_models=True): return isogenies_prime_degree_genus_plus_0_j1728(E, l, minimal_models=minimal_models) Fu, u = PolynomialRing(F, 'u').objgen() - Fuv = PolynomialRing(F, ['u','v']) - Fxuv = PolynomialRing(F, ['x','u','v']) + Fuv = PolynomialRing(F, ['u', 'v']) + Fxuv = PolynomialRing(F, ['x', 'u', 'v']) data = _hyperelliptic_isogeny_data(l) a = Fu(data['alpha']) b = Fu(data['beta']) f = Fu(data['hyper_poly']) - Q = Fu((a**2 - f*b**2) / 4) - u_list = (j**2 - a*j + Q).roots(multiplicities=False) + Q = Fu((a**2 - f * b**2) / 4) + u_list = (j**2 - a * j + Q).roots(multiplicities=False) S = [] for u0 in u_list: if b(u0) == 0: S.extend([u0, v0] for v0 in f(u0).sqrt(all=True, extend=False)) else: - S.append([u0, (2*j - a(u0)) / b(u0)]) + S.append([u0, (2 * j - a(u0)) / b(u0)]) if not S: return [] S.sort() @@ -2049,8 +2196,8 @@ def isogenies_prime_degree_genus_plus_0(E, l=None, minimal_models=True): for u0, v0 in S: A4 = Fuv(data['A4'])(u0, v0) # nonzero since j!=0 A6 = Fuv(data['A6'])(u0, v0) # nonzero since j!=1728 - T = (c4*A6) / (2*c6*A4) - kernels.append(psi((36*u + 3*b2) * T, u0, v0).monic()) + T = (c4 * A6) / (2 * c6 * A4) + kernels.append(psi((36 * u + 3 * b2) * T, u0, v0).monic()) return [E.isogeny(ker) for ker in kernels] @@ -2120,13 +2267,13 @@ def isogenies_prime_degree_genus_plus_0_j0(E, l, minimal_models=True): raise NotImplementedError("not implemented in characteristic 2, 3 or l") Fu, u = PolynomialRing(F, 'u').objgen() - Fuv = PolynomialRing(F, ['u','v']) - Fxuv = PolynomialRing(F, ['x','u','v']) + Fuv = PolynomialRing(F, ['u', 'v']) + Fxuv = PolynomialRing(F, ['x', 'u', 'v']) data = _hyperelliptic_isogeny_data(l) a = Fu(data['alpha']) b = Fu(data['beta']) f = Fu(data['hyper_poly']) - Q = Fu((a**2 - f*b**2) / 4) + Q = Fu((a**2 - f * b**2) / 4) u_list = Q.roots(multiplicities=False) c6, b2 = E.c6(), E.b2() kernels = [] @@ -2134,7 +2281,7 @@ def isogenies_prime_degree_genus_plus_0_j0(E, l, minimal_models=True): if l % 3 == 1 and F(-3).is_square(): endo = Fxuv(data['endo']) for p in F(-3).sqrt(all=True, extend=False): - kernels.append(endo(36*u + 3*b2, p, -54*c6).monic()) + kernels.append(endo(36 * u + 3 * b2, p, -54 * c6).monic()) S = [] for u0 in u_list: @@ -2151,7 +2298,7 @@ def isogenies_prime_degree_genus_plus_0_j0(E, l, minimal_models=True): psi = Fxuv(Psi2(l)) for u0, v0 in S: A6 = Fuv(data['A6'])(u0, v0) # nonzero since j!=1728 - kernels.extend(psi((36*u + 3*b2) * T, u0, v0).monic() for T in (u**3 - A6/(-54*c6)).roots(multiplicities=False)) + kernels.extend(psi((36 * u + 3 * b2) * T, u0, v0).monic() for T in (u**3 - A6 / (-54 * c6)).roots(multiplicities=False)) return [E.isogeny(ker) for ker in kernels] @@ -2242,21 +2389,21 @@ def isogenies_prime_degree_genus_plus_0_j1728(E, l, minimal_models=True): raise NotImplementedError("not implemented in characteristic 2, 3 or l") Fu, u = PolynomialRing(F, 'u').objgen() - Fuv = PolynomialRing(F, ['u','v']) - Fxuv = PolynomialRing(F, ['x','u','v']) + Fuv = PolynomialRing(F, ['u', 'v']) + Fxuv = PolynomialRing(F, ['x', 'u', 'v']) data = _hyperelliptic_isogeny_data(l) a = Fu(data['alpha']) b = Fu(data['beta']) f = Fu(data['hyper_poly']) - Q = Fu((a**2 - f*b**2) / 4) - u_list = (1728**2 - a*1728 + Q).roots(multiplicities=False) + Q = Fu((a**2 - f * b**2) / 4) + u_list = (1728**2 - a * 1728 + Q).roots(multiplicities=False) c4, b2 = E.c4(), E.b2() kernels = [] if l % 4 == 1 and F(-1).is_square(): endo = Fxuv(data['endo']) for i in F(-1).sqrt(all=True, extend=False): - kernels.append(endo(36*u + 3*b2, i, -27*c4).monic()) + kernels.append(endo(36 * u + 3 * b2, i, -27 * c4).monic()) S = [] for u0 in u_list: @@ -2265,7 +2412,7 @@ def isogenies_prime_degree_genus_plus_0_j1728(E, l, minimal_models=True): if b(u0) == 0: S.extend([u0, v0] for v0 in f(u0).sqrt(all=True, extend=False)) else: - S.append([u0, (2*1728 - a(u0)) / b(u0)]) + S.append([u0, (2 * 1728 - a(u0)) / b(u0)]) if not S and not kernels: return [] S.sort() @@ -2273,7 +2420,7 @@ def isogenies_prime_degree_genus_plus_0_j1728(E, l, minimal_models=True): psi = Fxuv(Psi2(l)) for u0, v0 in S: A4 = Fuv(data['A4'])(u0, v0) # nonzero since j!=0 - kernels.extend(psi((36*u + 3*b2) * T, u0, v0).monic() for T in (A4 / (-27*c4)).sqrt(all=True, extend=False)) + kernels.extend(psi((36 * u + 3 * b2) * T, u0, v0).monic() for T in (A4 / (-27 * c4)).sqrt(all=True, extend=False)) return [E.isogeny(ker) for ker in kernels] @@ -2312,11 +2459,11 @@ def _least_semi_primitive(p): from sage.arith.misc import euler_phi from sage.rings.finite_rings.integer_mod_ring import Integers + phi_p = euler_phi(p) order = phi_p if p % 4 == 1 else phi_p // 2 R = Integers(p) - return next((a for a in range(2, p) if p.gcd(a).is_one() - and R(a).multiplicative_order() >= order), 0) + return next((a for a in range(2, p) if p.gcd(a).is_one() and R(a).multiplicative_order() >= order), 0) def is_kernel_polynomial(E, m, f): @@ -2418,9 +2565,10 @@ def is_kernel_polynomial(E, m, f): # only one a will be needed. if m & 1 and m.is_prime_power(): - gens = _least_semi_primitive(m), + gens = (_least_semi_primitive(m),) else: from sage.rings.finite_rings.integer_mod_ring import Integers + gens = Integers(m).unit_gens() for a in gens: @@ -2602,7 +2750,7 @@ def isogenies_prime_degree_general(E, l, minimal_models=True): psi_l = E.division_polynomial(l) - factors = [h for h,_ in psi_l.factor() if h.degree().divides(l//2)] + factors = [h for h, _ in psi_l.factor() if h.degree().divides(l // 2)] kernels = [] # will store all kernel polynomials found @@ -2612,7 +2760,7 @@ def isogenies_prime_degree_general(E, l, minimal_models=True): ker = E.kernel_polynomial_from_divisor(h, l, check=False) except ValueError: continue - assert ker.degree() == l//2 and ker.divides(psi_l) + assert ker.degree() == l // 2 and ker.divides(psi_l) kernels.append(ker) factors = [h for h in factors if not h.divides(ker)] diff --git a/src/sage/schemes/elliptic_curves/jacobian.py b/src/sage/schemes/elliptic_curves/jacobian.py index 3b6ba815b82..f473ee2a6cb 100644 --- a/src/sage/schemes/elliptic_curves/jacobian.py +++ b/src/sage/schemes/elliptic_curves/jacobian.py @@ -114,13 +114,16 @@ def Jacobian(X, **kwds): morphism = kwds.pop('morphism', False) from sage.rings.polynomial.multi_polynomial import MPolynomial + if isinstance(X, MPolynomial): if morphism: from sage.schemes.curves.constructor import Curve + return Jacobian_of_equation(X, curve=Curve(X), **kwds) return Jacobian_of_equation(X, **kwds) from sage.schemes.generic.scheme import Scheme + if isinstance(X, Scheme) and X.dimension() == 1: return Jacobian_of_curve(X, morphism=morphism, **kwds) @@ -229,6 +232,7 @@ def Jacobian_of_equation(polynomial, variables=None, curve=None): Elliptic Curve defined by y^2 = x^3 - 24300 over Rational Field """ from sage.schemes.toric.weierstrass import WeierstrassForm + f, g = WeierstrassForm(polynomial, variables=variables) try: K = polynomial.base_ring() @@ -241,4 +245,5 @@ def Jacobian_of_equation(polynomial, variables=None, curve=None): return E X, Y, Z = WeierstrassForm(polynomial, variables=variables, transformation=True) from sage.schemes.elliptic_curves.weierstrass_transform import WeierstrassTransformation - return WeierstrassTransformation(curve, E, [X*Z, Y, Z**3], 1) + + return WeierstrassTransformation(curve, E, [X * Z, Y, Z**3], 1) diff --git a/src/sage/schemes/elliptic_curves/kodaira_symbol.py b/src/sage/schemes/elliptic_curves/kodaira_symbol.py index 8e44dc2ca73..26cf6109515 100644 --- a/src/sage/schemes/elliptic_curves/kodaira_symbol.py +++ b/src/sage/schemes/elliptic_curves/kodaira_symbol.py @@ -74,6 +74,7 @@ class KodairaSymbol_class(SageObject): Users should use the ``KodairaSymbol()`` function to construct Kodaira Symbols rather than use the class constructor directly. """ + def __init__(self, symbol): r""" Constructor for Kodaira Symbol class. @@ -153,7 +154,7 @@ def __init__(self, symbol): self._n = nu self._str = 'I%s*' % nu self._latex = 'I_{%s}^{*}' % nu - self._starred = (n < 0) + self._starred = n < 0 self._pari = n return if not symbol: @@ -165,8 +166,8 @@ def __init__(self, symbol): starred = True symbol = symbol[:-1] self._starred = starred - if symbol in ["I", "II", "V"]: # NB we have already stripped off the leading 'I' - self._roman = ["I", "II", "V"].index(symbol) + 2 # =2, 3 or 4 + if symbol in ["I", "II", "V"]: # NB we have already stripped off the leading 'I' + self._roman = ["I", "II", "V"].index(symbol) + 2 # =2, 3 or 4 self._n = None if starred: sign = -1 diff --git a/src/sage/schemes/elliptic_curves/kraus.py b/src/sage/schemes/elliptic_curves/kraus.py index da0aba51d38..c9934ebaa69 100644 --- a/src/sage/schemes/elliptic_curves/kraus.py +++ b/src/sage/schemes/elliptic_curves/kraus.py @@ -96,7 +96,7 @@ def c4c6_nonsingular(c4, c6): """ if not (c4.is_integral() and c6.is_integral()): return False - D = (c4**3-c6**2)/1728 + D = (c4**3 - c6**2) / 1728 return not D.is_zero() and D.is_integral() @@ -132,9 +132,10 @@ def c4c6_model(c4, c6, assume_nonsingular=False): Elliptic Curve defined by y^2 = x^3 - 7/3*x + 107/108 over Rational Field """ if not assume_nonsingular: - if not c4c6_nonsingular(c4,c6): + if not c4c6_nonsingular(c4, c6): return None - return EllipticCurve([0,0,0,-c4/48,-c6/864]) + return EllipticCurve([0, 0, 0, -c4 / 48, -c6 / 864]) + # Arithmetic utility functions @@ -184,7 +185,7 @@ def make_integral(a, P, e): ArithmeticError: Cannot lift 1/10*a to O_K mod (Fractional ideal (2, a))^2 """ for b in (P**e).residues(): - if (a-b).valuation(P) >= e: + if (a - b).valuation(P) >= e: return b raise ArithmeticError("Cannot lift %s to O_K mod (%s)^%s" % (a, P, e)) @@ -225,10 +226,11 @@ def sqrt_mod_4(x, P): e = P.ramification_index() P2 = P**e for r in P2.residues(): - if (r*r-x).valuation(P) >= 2*e: + if (r * r - x).valuation(P) >= 2 * e: return True, r return False, 0 + # Kraus test and check for primes dividing 3: @@ -293,8 +295,8 @@ def check_b2_local(c4, c6, P, b2, debug=False): by y^2 = x^3 + (1/4*a+1/4)*x^2 + (10091/8*a-128595/16)*x + (4097171/64*a-19392359/64) over Number Field in a with defining polynomial x^2 - 10 """ - E = c4c6_model(c4,c6).rst_transform(b2/12,0,0) - if not (c4,c6) == E.c_invariants(): + E = c4c6_model(c4, c6).rst_transform(b2 / 12, 0, 0) + if not (c4, c6) == E.c_invariants(): if debug: print("check_b2_local: wrong c-invariants at P=%s" % P) return False @@ -341,13 +343,12 @@ def check_b2_global(c4, c6, b2, debug=False): check_b2_global: not integral at all primes dividing 3 False """ - E = c4c6_model(c4,c6).rst_transform(b2/12,0,0) - if not (c4,c6) == E.c_invariants(): + E = c4c6_model(c4, c6).rst_transform(b2 / 12, 0, 0) + if not (c4, c6) == E.c_invariants(): if debug: print("check_b2_global: wrong c-invariants") return False - if not all(E.is_local_integral_model(P) - for P in c4.parent().primes_above(3)): + if not all(E.is_local_integral_model(P) for P in c4.parent().primes_above(3)): if debug: print("check_b2_global: not integral at all primes dividing 3") return False @@ -398,32 +399,33 @@ def check_Kraus_local_3(c4, c6, P, assume_nonsingular=False, debug=False): (True, a) """ if not assume_nonsingular: - if not c4c6_nonsingular(c4,c6): + if not c4c6_nonsingular(c4, c6): return False, 0 e = P.ramification_index() P3 = P**e if c4.valuation(P) == 0: - b2 = (-c6*c4.inverse_mod(P3)).mod(P3) + b2 = (-c6 * c4.inverse_mod(P3)).mod(P3) if debug: - assert check_b2_local(c4,c6,P,b2) + assert check_b2_local(c4, c6, P, b2) return True, b2 - if c6.valuation(P) >= 3*e: + if c6.valuation(P) >= 3 * e: b2 = c6.parent().zero() if debug: - assert check_b2_local(c4,c6,P,b2) + assert check_b2_local(c4, c6, P, b2) return True, b2 # check for a solution x to x^3-3*x*c4-26=0 (27), such an x must # also satisfy x*c4+c6=0 (3) and x^2=c4 (3) and x^3=-c6 (9), and # if x is a solution then so is any x'=x (3) so it is enough to # check residues mod 3. for x in P3.residues(): - if (x*c4+c6).valuation(P) >= e: - if (x*(x*x-3*c4)-2*c6).valuation(P) >= 3*e: + if (x * c4 + c6).valuation(P) >= e: + if (x * (x * x - 3 * c4) - 2 * c6).valuation(P) >= 3 * e: if debug: - assert check_b2_local(c4,c6,P,x) + assert check_b2_local(c4, c6, P, x) return True, x return False, 0 + # Kraus test and check for primes dividing 2: @@ -461,8 +463,8 @@ def check_a1a3_local(c4, c6, P, a1, a3, debug=False): check_a1a3_local: not integral at Fractional ideal (2, a) False """ - E = c4c6_model(c4,c6).rst_transform(a1**2/12,a1/2,a3/2) - if not (c4,c6) == E.c_invariants(): + E = c4c6_model(c4, c6).rst_transform(a1**2 / 12, a1 / 2, a3 / 2) + if not (c4, c6) == E.c_invariants(): if debug: print("check_a1a3_local: wrong c-invariants at P=%s" % P) return False @@ -504,13 +506,12 @@ def check_a1a3_global(c4, c6, a1, a3, debug=False): y^2 + a*x*y = x^3 + (3784/3*a-24106/3)*x + (1772120/27*a-2790758/9) over Number Field in a with defining polynomial x^2 - 10 """ - E = c4c6_model(c4,c6).rst_transform(a1**2/12,a1/2,a3/2) + E = c4c6_model(c4, c6).rst_transform(a1**2 / 12, a1 / 2, a3 / 2) if not (c4, c6) == E.c_invariants(): if debug: print("wrong c-invariants") return False - if not all(E.is_local_integral_model(P) - for P in c4.parent().primes_above(2)): + if not all(E.is_local_integral_model(P) for P in c4.parent().primes_above(2)): if debug: print("not integral at all primes above 2") return False @@ -548,8 +549,8 @@ def check_rst_global(c4, c6, r, s, t, debug=False): sage: check_rst_global(c4,c6,a, 3, -89*a, debug=False) False """ - E = c4c6_model(c4,c6).rst_transform(r,s,t) - if not (c4,c6) == E.c_invariants(): + E = c4c6_model(c4, c6).rst_transform(r, s, t) + if not (c4, c6) == E.c_invariants(): if debug: print("test_rst_global: wrong c-invariants") return False @@ -558,12 +559,13 @@ def check_rst_global(c4, c6, r, s, t, debug=False): print("test_rst_global: not integral at some prime") print(E.ainvs()) K = E.base_field() - for P in K.primes_above(2)+K.primes_above(3): + for P in K.primes_above(2) + K.primes_above(3): if not E.is_local_integral_model(P): print(" -- not integral at P=%s" % P) return False return E + # When a1 is None this function finds a pair a1, a3 such that there is # a model with these invariants and a2=0 with the given c4, c6, # integral at P. The value of a1 is unique modulo 2 (i.e. mod P^e @@ -615,55 +617,56 @@ def check_Kraus_local_2(c4, c6, P, a1=None, assume_nonsingular=False): (True, a, 0) """ if not assume_nonsingular: - if not c4c6_nonsingular(c4,c6): - return False,0,0 + if not c4c6_nonsingular(c4, c6): + return False, 0, 0 e = P.ramification_index() P2 = P**e c4val = c4.valuation(P) if c4val == 0: if a1 is None: - flag, t = sqrt_mod_4(-c6,P) + flag, t = sqrt_mod_4(-c6, P) if not flag: - return False,0,0 + return False, 0, 0 # In the assignment to a1, a3 we divide by units at P, # (note that c6+a1**6 = 0 mod P**e so dividing by 4 is OK) # but the results, which are well-defined modulo P^e, may # not be globally integral - a1 = make_integral(c4/t,P,e) + a1 = make_integral(c4 / t, P, e) a13 = a1**3 - a3 = make_integral((c6+a13**2)/(4*a13),P,2*e) - if check_a1a3_local(c4,c6,P,a1,a3): - return True, a1,a3 + a3 = make_integral((c6 + a13**2) / (4 * a13), P, 2 * e) + if check_a1a3_local(c4, c6, P, a1, a3): + return True, a1, a3 raise RuntimeError("check_Kraus_local_2 fails") - if c4val >= 4*e: + if c4val >= 4 * e: if a1 is None: - a1 = c4.parent().zero() # 0 - flag, a3 = sqrt_mod_4(c6/8,P) + a1 = c4.parent().zero() # 0 + flag, a3 = sqrt_mod_4(c6 / 8, P) if flag: - if check_a1a3_local(c4,c6,P,a1,a3): - return True, a1,a3 + if check_a1a3_local(c4, c6, P, a1, a3): + return True, a1, a3 raise RuntimeError("check_Kraus_local_2 fails") else: - return False,0,0 + return False, 0, 0 # val(c4) strictly between 0 and 4e; a1 unique mod 2, with 3 conditions to be satisfied: P2res = [a1] if a1 else P2.residues() for a1 in P2res: - Px = -a1**6+3*a1**2*c4+2*c6 - if Px.valuation(P) >= 4*e: # (i) - flag, a3 = sqrt_mod_4(Px/16,P) # (ii) + Px = -(a1**6) + 3 * a1**2 * c4 + 2 * c6 + if Px.valuation(P) >= 4 * e: # (i) + flag, a3 = sqrt_mod_4(Px / 16, P) # (ii) if flag: - a1sq = a1*a1 - if (4*a1sq*Px-(a1sq**2-c4)**2).valuation(P) >= 8*e: # (iii) - if check_a1a3_local(c4,c6,P,a1,a3): + a1sq = a1 * a1 + if (4 * a1sq * Px - (a1sq**2 - c4) ** 2).valuation(P) >= 8 * e: # (iii) + if check_a1a3_local(c4, c6, P, a1, a3): return True, a1, a3 raise RuntimeError("check_Kraus_local_2 fails") # end of loop, but no a1 found return False, 0, 0 + # Wrapper function for local Kraus check, outsources the real work to # other functions for primes dividing 2 or 3: @@ -722,24 +725,24 @@ def check_Kraus_local(c4, c6, P, assume_nonsingular=False): (False, None) """ if not assume_nonsingular: - if not c4c6_nonsingular(c4,c6): + if not c4c6_nonsingular(c4, c6): return False, None K = c4.parent() if K(2).valuation(P) > 0: - flag, a1, a3 = check_Kraus_local_2(c4,c6,P,None,True) + flag, a1, a3 = check_Kraus_local_2(c4, c6, P, None, True) if flag: - E = check_a1a3_local(c4,c6,P,a1,a3) + E = check_a1a3_local(c4, c6, P, a1, a3) if E: return (True, E) return (False, None) if K(3).valuation(P) > 0: - flag, b2 = check_Kraus_local_3(c4,c6,P,True) + flag, b2 = check_Kraus_local_3(c4, c6, P, True) if flag: - E = check_b2_local(c4,c6,P,b2) + E = check_b2_local(c4, c6, P, b2) if E: return (True, E) return (False, None) - return (True, c4c6_model(c4,c6)) + return (True, c4c6_model(c4, c6)) def check_Kraus_global(c4, c6, assume_nonsingular=False, debug=False): @@ -807,33 +810,33 @@ def check_Kraus_global(c4, c6, assume_nonsingular=False, debug=False): over Number Field in b with defining polynomial x^6 - 42*x^4 + 441*x^2 - 697 """ if not assume_nonsingular: - if not c4c6_nonsingular(c4,c6): + if not c4c6_nonsingular(c4, c6): return False # Check all primes dividing 3; for each get the value of b2 K = c4.parent() three = K.ideal(3) Plist3 = K.primes_above(3) - dat = [check_Kraus_local_3(c4,c6,P,True) for P in Plist3] + dat = [check_Kraus_local_3(c4, c6, P, True) for P in Plist3] if not all(d[0] for d in dat): if debug: - print("Local Kraus condition for (c4,c6)=(%s,%s) fails at some prime dividing 3" % (c4,c6)) + print("Local Kraus condition for (c4,c6)=(%s,%s) fails at some prime dividing 3" % (c4, c6)) return False if debug: - print("Local Kraus conditions for (c4,c6)=(%s,%s) pass at all primes dividing 3" % (c4,c6)) + print("Local Kraus conditions for (c4,c6)=(%s,%s) pass at all primes dividing 3" % (c4, c6)) # OK at all primes dividing 3; now use CRT to combine the b2 # values to get a single residue class for b2 mod 3: b2list = [d[1] for d in dat] - P3list = [P**three.valuation(P) for P in Plist3] - b2 = K.solve_CRT(b2list,P3list, check=True).mod(three) + P3list = [P ** three.valuation(P) for P in Plist3] + b2 = K.solve_CRT(b2list, P3list, check=True).mod(three) # test that this b2 value works at all P|3: if debug: - E = check_b2_global(c4,c6,b2) + E = check_b2_global(c4, c6, b2) if E: - print("Using b2=%s gives a model integral at 3:\n%s" % (b2,E.ainvs())) + print("Using b2=%s gives a model integral at 3:\n%s" % (b2, E.ainvs())) else: raise RuntimeError("Error in check_Kraus_global at some prime dividing 3") @@ -848,28 +851,28 @@ def check_Kraus_global(c4, c6, assume_nonsingular=False, debug=False): print("Local Kraus condition for (c4,c6)=(%s,%s) fails at some prime dividing 2" % (c4, c6)) return False if debug: - print("Local Kraus conditions for (c4,c6)=(%s,%s) pass at all primes dividing 2" % (c4,c6)) + print("Local Kraus conditions for (c4,c6)=(%s,%s) pass at all primes dividing 2" % (c4, c6)) # OK at all primes dividing 2; now use CRT to combine the a1 # values to get the residue classes of a1 mod 2: - P2list = [P**(two.valuation(P)) for P in Plist2] + P2list = [P ** (two.valuation(P)) for P in Plist2] a1list = [d[1] for d in dat] - a1 = K.solve_CRT(a1list,P2list, check=True) + a1 = K.solve_CRT(a1list, P2list, check=True) # See comment below: this is needed for when we combine with the primes above 3. if a1 not in three: # three.divides(a1) causes a segfault - a1 = 3*a1 + a1 = 3 * a1 # Using this a1, recompute the local a3's: - dat = [check_Kraus_local_2(c4,c6,P,a1,True) for P in Plist2] + dat = [check_Kraus_local_2(c4, c6, P, a1, True) for P in Plist2] # Use CRT to combine these: a3list = [d[2] for d in dat] - a3 = K.solve_CRT(a3list,P2list, check=True) + a3 = K.solve_CRT(a3list, P2list, check=True) # test that these a1,a3 values work at all P|2: if debug: - E = check_a1a3_global(c4,c6,a1,a3,debug) + E = check_a1a3_global(c4, c6, a1, a3, debug) if E: - print("Using (a1,a3)=(%s,%s) gives a model integral at 2:\n%s" % (a1,a3,E.ainvs())) + print("Using (a1,a3)=(%s,%s) gives a model integral at 2:\n%s" % (a1, a3, E.ainvs())) else: raise RuntimeError("Error in check_Kraus_global at some prime dividing 2") @@ -888,24 +891,24 @@ def check_Kraus_global(c4, c6, assume_nonsingular=False, debug=False): # multiplying a1 by 3 if necessary. We did this above. if debug: - print("(a1, b2, a3) = (%s, %s, %s)" % (a1,b2,a3)) + print("(a1, b2, a3) = (%s, %s, %s)" % (a1, b2, a3)) assert a1.is_integral() assert a3.is_integral() assert b2.is_integral() - s = a1/2 - r = b2/3 - s**2 - t = s*(b2-a1**2)/3 + a3/2 + s = a1 / 2 + r = b2 / 3 - s**2 + t = s * (b2 - a1**2) / 3 + a3 / 2 if debug: - print("Using (r, s, t)=(%s, %s, %s) should give a global integral model..." % (r,s,t)) + print("Using (r, s, t)=(%s, %s, %s) should give a global integral model..." % (r, s, t)) # Final computation of the curve E: - E = check_rst_global(c4,c6,r,s,t,debug) + E = check_rst_global(c4, c6, r, s, t, debug) if not E: if debug: print("Error in check_Kraus_global with combining mod-2 and mod-3 transforms") - E = c4c6_model(c4,c6).rst_transform(r,s,t) + E = c4c6_model(c4, c6).rst_transform(r, s, t) print("Transformed model is %a" % (E.ainvs(),)) - for P in Plist2+Plist3: + for P in Plist2 + Plist3: if not E.is_local_integral_model(P): print("Not integral at P=%s" % P) raise RuntimeError("Error in check_Kraus_global combining transforms at 2 and 3") diff --git a/src/sage/schemes/elliptic_curves/lseries_ell.py b/src/sage/schemes/elliptic_curves/lseries_ell.py index 569c824dcd2..f9ae783a33b 100644 --- a/src/sage/schemes/elliptic_curves/lseries_ell.py +++ b/src/sage/schemes/elliptic_curves/lseries_ell.py @@ -10,6 +10,7 @@ - William Stein et al. (2005 and later) """ + # **************************************************************************** # Copyright (C) 2005 William Stein # Copyright (C) 2013 Jeroen Demeyer @@ -33,6 +34,7 @@ class Lseries_ell(SageObject): """ An elliptic curve `L`-series. """ + def __init__(self, E) -> None: r""" Create an elliptic curve `L`-series. @@ -97,10 +99,7 @@ def _repr_(self) -> str: """ return "Complex L-series of the %s" % self.__E - def dokchitser(self, prec=53, - max_imaginary_part=0, - max_asymp_coeffs=40, - algorithm=None): + def dokchitser(self, prec=53, max_imaginary_part=0, max_asymp_coeffs=40, algorithm=None): r""" Return an interface for computing with the `L`-series of this elliptic curve. @@ -158,10 +157,12 @@ def dokchitser(self, prec=53, if algorithm == 'magma': from sage.interfaces.magma import magma + return magma(self.__E).LSeries(Precision=prec) if algorithm == 'pari': from sage.lfunctions.pari import LFunction, lfun_elliptic_curve + L = LFunction(lfun_elliptic_curve(self.__E), prec=prec) L.rename('PARI L-function associated to %s' % self.__E) return L @@ -198,6 +199,7 @@ def sympow(self, n, prec): 2.49226204427365 """ from sage.lfunctions.sympow import sympow + return sympow.L(self.__E, n, prec) def sympow_derivs(self, n, prec, d): @@ -248,6 +250,7 @@ def sympow_derivs(self, n, prec, d): 1w2: 1.545605024269432E-01 """ from sage.lfunctions.sympow import sympow + return sympow.Lderivs(self.__E, n, prec, d) def zeros(self, n): @@ -269,6 +272,7 @@ def zeros(self, n): AUTHORS: Uses Rubinstein's L-functions calculator. """ from sage.lfunctions.lcalc import lcalc + return lcalc.zeros(n, L=self.__E) def zeros_in_interval(self, x, y, stepsize): @@ -300,6 +304,7 @@ def zeros_in_interval(self, x, y, stepsize): [(6.87039122, 0.248922780), (8.01433081, -0.140168533), (9.93309835, -0.129943029)] """ from sage.lfunctions.lcalc import lcalc + return lcalc.zeros_in_interval(x, y, stepsize, L=self.__E) def values_along_line(self, s0, s1, number_samples): @@ -335,9 +340,8 @@ def values_along_line(self, s0, s1, number_samples): (0.100000000 + 16.0000000*I, -3.87043288 - 1.88049411*I)] """ from sage.lfunctions.lcalc import lcalc - return lcalc.values_along_line(s0-RationalField()('1/2'), - s1-RationalField()('1/2'), - number_samples, L=self.__E) + + return lcalc.values_along_line(s0 - RationalField()('1/2'), s1 - RationalField()('1/2'), number_samples, L=self.__E) def twist_values(self, s, dmin, dmax): r""" @@ -389,6 +393,7 @@ def twist_values(self, s, dmin, dmax): 0 """ from sage.lfunctions.lcalc import lcalc + return lcalc.twist_values(s - RationalField()('1/2'), dmin, dmax, L=self.__E) def twist_zeros(self, n, dmin, dmax): @@ -422,6 +427,7 @@ def twist_zeros(self, n, dmin, dmax): {-4: [1.60813783, 2.96144840, 3.89751747], -3: [2.06170900, 3.48216881, 4.45853219]} """ from sage.lfunctions.lcalc import lcalc + return lcalc.twist_zeros(n, dmin, dmax, L=self.__E) def at1(self, k=None, prec=None): @@ -519,7 +525,7 @@ def at1(self, k=None, prec=None): else: # Use the same precision as deriv_at1() below for # consistency - prec = int(9.065*k/sqrtN + 1.443*log(k)) + 12 + prec = int(9.065 * k / sqrtN + 1.443 * log(k)) + 12 R = RealField(prec) # Compute error term with bounded precision of 24 bits and # round towards +infinity @@ -532,14 +538,14 @@ def at1(self, k=None, prec=None): pi = R.pi() sqrtN = R(self.__E.conductor()).sqrt() - z = (-2*pi/sqrtN).exp() + z = (-2 * pi / sqrtN).exp() zpow = z # Compute series sum and accumulate floating point errors L = R.zero() error = Rerror.zero() for n in range(1, k + 1): - term = (zpow * an[n])/n + term = (zpow * an[n]) / n zpow *= z L += term # We express relative error in units of epsilon, where @@ -562,12 +568,12 @@ def at1(self, k=None, prec=None): # result. # # Multiplying everything by two gives: - error += term.epsilon(Rerror)*(16*n + 3) + L.ulp(Rerror) + error += term.epsilon(Rerror) * (16 * n + 3) + L.ulp(Rerror) L *= 2 # Add series error (we use (-2)/(z-1) instead of 2/(1-z) # because this causes 1/(1-z) to be rounded up) - error += ((-2)*Rerror(zpow)) / Rerror(z - 1) + error += ((-2) * Rerror(zpow)) / Rerror(z - 1) return (L, error) def deriv_at1(self, k=None, prec=None): @@ -672,7 +678,7 @@ def deriv_at1(self, k=None, prec=None): # 12 is an arbitrary extra number of bits (it is chosen # such that the precision is 24 bits when the conductor # equals 11 and k is the default value 4) - prec = int(9.065*k/sqrtN + 1.443*log(k)) + 12 + prec = int(9.065 * k / sqrtN + 1.443 * log(k)) + 12 R = RealField(prec) # Compute error term with bounded precision of 24 bits and # round towards +infinity @@ -688,7 +694,7 @@ def deriv_at1(self, k=None, prec=None): an = self.__E.anlist(k) # list of Sage Integers pi = R.pi() sqrtN = R(self.__E.conductor()).sqrt() - v = exponential_integral_1(2*pi/sqrtN, k) + v = exponential_integral_1(2 * pi / sqrtN, k) # Compute series sum and accumulate floating point errors L = R.zero() @@ -697,23 +703,23 @@ def deriv_at1(self, k=None, prec=None): sumann = Rerror.zero() for n in range(1, k + 1): - term = (v[n-1] * an[n])/n + term = (v[n - 1] * an[n]) / n L += term - error += term.epsilon(Rerror)*5 + L.ulp(Rerror) - sumann += Rerror(an[n].abs())/n + error += term.epsilon(Rerror) * 5 + L.ulp(Rerror) + sumann += Rerror(an[n].abs()) / n L *= 2 # Add error term for exponential_integral_1() errors. # Absolute error for 2*v[i] is 4*max(1, v[0])*2^-prec if v[0] > 1.0: sumann *= Rerror(v[0]) - error += (sumann >> (prec - 2)) + error += sumann >> (prec - 2) # Add series error (we use (-2)/(z-1) instead of 2/(1-z) # because this causes 1/(1-z) to be rounded up) - z = (-2*pi/sqrtN).exp() - zpow = ((-2*(k+1))*pi/sqrtN).exp() - error += ((-2)*Rerror(zpow)) / Rerror(z - 1) + z = (-2 * pi / sqrtN).exp() + zpow = ((-2 * (k + 1)) * pi / sqrtN).exp() + error += ((-2) * Rerror(zpow)) / Rerror(z - 1) return (L, error) def __call__(self, s): @@ -906,4 +912,5 @@ def zero_sums(self, N=None): Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field """ from sage.lfunctions.zero_sums import LFunctionZeroSum + return LFunctionZeroSum(self.__E, N=N) diff --git a/src/sage/schemes/elliptic_curves/mod5family.py b/src/sage/schemes/elliptic_curves/mod5family.py index 64069c342b7..fd580107e1b 100644 --- a/src/sage/schemes/elliptic_curves/mod5family.py +++ b/src/sage/schemes/elliptic_curves/mod5family.py @@ -7,6 +7,7 @@ - William Stein -- Sage version """ + # **************************************************************************** # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -31,70 +32,63 @@ def mod5family(a, b): sage: mod5family(0,1) Elliptic Curve defined by y^2 = x^3 + (t^30+30*t^29+435*t^28+4060*t^27+27405*t^26+142506*t^25+593775*t^24+2035800*t^23+5852925*t^22+14307150*t^21+30045015*t^20+54627300*t^19+86493225*t^18+119759850*t^17+145422675*t^16+155117520*t^15+145422675*t^14+119759850*t^13+86493225*t^12+54627300*t^11+30045015*t^10+14307150*t^9+5852925*t^8+2035800*t^7+593775*t^6+142506*t^5+27405*t^4+4060*t^3+435*t^2+30*t+1) over Fraction Field of Univariate Polynomial Ring in t over Rational Field """ - J = 4*a**3 / (4*a**3+27*b**2) + J = 4 * a**3 / (4 * a**3 + 27 * b**2) alpha = [0 for _ in range(21)] alpha[0] = 1 alpha[1] = 0 - alpha[2] = 190*(J - 1) - alpha[3] = -2280*(J - 1)**2 - alpha[4] = 855*(J - 1)**2*(-17 + 16*J) - alpha[5] = 3648*(J - 1)**3*(17 - 9*J) - alpha[6] = 11400*(J - 1)**3*(17 - 8*J) - alpha[7] = -27360*(J - 1)**4*(17 + 26*J) - alpha[8] = 7410*(J - 1)**4*(-119 - 448*J + 432*J**2) - alpha[9] = 79040*(J - 1)**5*(17 + 145*J - 108*J**2) - alpha[10] = 8892*(J - 1)**5*(187 + 2640*J - 5104*J**2 + 1152*J**3) - alpha[11] = 98800*(J - 1)**6*(-17 - 388*J + 864*J**2) - alpha[12] = 7410*(J - 1)**6*(-187 - 6160*J + 24464*J**2 - 24192*J**3) - alpha[13] = 54720*(J - 1)**7*(17 + 795*J - 3944*J**2 + 9072*J**3) - alpha[14] = 2280*(J - 1)**7*(221 + 13832*J - 103792*J**2 + 554112*J**3 - 373248*J**4) - alpha[15] = 1824*(J - 1)**8*(-119 - 9842*J + 92608*J**2 - 911520*J**3 + 373248*J**4) - alpha[16] = 4275*(J - 1)**8*(-17 - 1792*J + 23264*J**2 - 378368*J**3 + 338688*J**4) - alpha[17] = 18240*(J - 1)**9*(1 + 133*J - 2132*J**2 + 54000*J**3 - 15552*J**4) - alpha[18] = 190*(J - 1)**9*(17 + 2784*J - 58080*J**2 + 2116864*J**3 - 946944*J**4 + 2985984*J**5) - alpha[19] = 360*(J - 1)**10*(-1 + 28*J - 1152*J**2)*(1 + 228*J + 176*J**2 + 1728*J**3) - alpha[20] = (J - 1)**10*(-19 - 4560*J + 144096*J**2 - 9859328*J**3 - 8798976*J**4 - 226934784*J**5 + 429981696*J**6) + alpha[2] = 190 * (J - 1) + alpha[3] = -2280 * (J - 1) ** 2 + alpha[4] = 855 * (J - 1) ** 2 * (-17 + 16 * J) + alpha[5] = 3648 * (J - 1) ** 3 * (17 - 9 * J) + alpha[6] = 11400 * (J - 1) ** 3 * (17 - 8 * J) + alpha[7] = -27360 * (J - 1) ** 4 * (17 + 26 * J) + alpha[8] = 7410 * (J - 1) ** 4 * (-119 - 448 * J + 432 * J**2) + alpha[9] = 79040 * (J - 1) ** 5 * (17 + 145 * J - 108 * J**2) + alpha[10] = 8892 * (J - 1) ** 5 * (187 + 2640 * J - 5104 * J**2 + 1152 * J**3) + alpha[11] = 98800 * (J - 1) ** 6 * (-17 - 388 * J + 864 * J**2) + alpha[12] = 7410 * (J - 1) ** 6 * (-187 - 6160 * J + 24464 * J**2 - 24192 * J**3) + alpha[13] = 54720 * (J - 1) ** 7 * (17 + 795 * J - 3944 * J**2 + 9072 * J**3) + alpha[14] = 2280 * (J - 1) ** 7 * (221 + 13832 * J - 103792 * J**2 + 554112 * J**3 - 373248 * J**4) + alpha[15] = 1824 * (J - 1) ** 8 * (-119 - 9842 * J + 92608 * J**2 - 911520 * J**3 + 373248 * J**4) + alpha[16] = 4275 * (J - 1) ** 8 * (-17 - 1792 * J + 23264 * J**2 - 378368 * J**3 + 338688 * J**4) + alpha[17] = 18240 * (J - 1) ** 9 * (1 + 133 * J - 2132 * J**2 + 54000 * J**3 - 15552 * J**4) + alpha[18] = 190 * (J - 1) ** 9 * (17 + 2784 * J - 58080 * J**2 + 2116864 * J**3 - 946944 * J**4 + 2985984 * J**5) + alpha[19] = 360 * (J - 1) ** 10 * (-1 + 28 * J - 1152 * J**2) * (1 + 228 * J + 176 * J**2 + 1728 * J**3) + alpha[20] = (J - 1) ** 10 * (-19 - 4560 * J + 144096 * J**2 - 9859328 * J**3 - 8798976 * J**4 - 226934784 * J**5 + 429981696 * J**6) beta = [0 for _ in range(31)] beta[0] = 1 beta[1] = 30 - beta[2] = -435*(J - 1) - beta[3] = 580*(J - 1)*(-7 + 9*J) - beta[4] = 3915*(J - 1)**2*(7 - 8*J) - beta[5] = 1566*(J - 1)**2*(91 - 78*J + 48*J**2) - beta[6] = -84825*(J - 1)**3*(7 + 16*J) - beta[7] = 156600*(J - 1)**3*(-13 - 91*J + 92*J**2) - beta[8] = 450225*(J - 1)**4*(13 + 208*J - 144*J**2) - beta[9] = 100050*(J - 1)**4*(143 + 4004*J - 5632*J**2 + 1728*J**3) - beta[10] = 30015*(J - 1)**5*(-1001 - 45760*J + 44880*J**2 - 6912*J**3) - beta[11] = 600300*(J - 1)**5*(-91 - 6175*J + 9272*J**2 - 2736*J**3) - beta[12] = 950475*(J - 1)**6*(91 + 8840*J - 7824*J**2) - beta[13] = 17108550*(J - 1)**6*(7 + 926*J - 1072*J**2 + 544*J**3) - beta[14] = 145422675*(J - 1)**7*(-1 - 176*J + 48*J**2 - 384*J**3) - beta[15] = 155117520*(J - 1)**8*(1 + 228*J + 176*J**2 + 1728*J**3) - beta[16] = 145422675*(J - 1)**8*(1 + 288*J + 288*J**2 + 5120*J**3 - 6912*J**4) - beta[17] = 17108550*(J - 1)**8*(7 + 2504*J + 3584*J**2 + 93184*J**3 - 283392*J**4 + 165888*J**5) - beta[18] = 950475*(J - 1)**9*(-91 - 39936*J - 122976*J**2 - 2960384*J**3 + 11577600*J**4 - 5971968*J**5) - beta[19] = 600300*(J - 1)**9*(-91 - 48243*J - 191568*J**2 - 6310304*J**3 + 40515072*J**4 - 46455552*J**5 + 11943936*J**6) - beta[20] = 30015*(J - 1)**10*(1001 + 634920*J + 3880800*J**2 + 142879744*J**3 - 1168475904*J**4 + 1188919296*J**5 - 143327232*J**6) - beta[21] = 100050*(J - 1)**10*(143 + 107250*J + 808368*J**2 + 38518336*J**3 - 451953408*J**4 + 757651968*J**5 - 367276032*J**6) - beta[22] = 450225*(J - 1)**11*(-13 - 11440*J - 117216*J**2 - 6444800*J**3 + 94192384*J**4 - 142000128*J**5 + 95551488*J**6) - beta[23] = 156600*(J - 1)**11*(-13 - 13299*J - 163284*J**2 - 11171552*J**3 + 217203840*J**4 - 474406656*J**5 + 747740160*J**6 - 429981696*J**7) - beta[24] = 6525*(J - 1)**12*(91 + 107536*J + 1680624*J**2 + 132912128*J**3 - - 3147511552*J**4 + 6260502528*J**5 - 21054173184*J**6 + 10319560704*J**7) - beta[25] = 1566*(J - 1)**12*(91 + 123292*J + 2261248*J**2 + 216211904*J**3 - - 6487793920*J**4 + 17369596928*J**5 - 97854234624*J**6 + 96136740864*J**7 - 20639121408*J**8) - beta[26] = 3915*(J - 1)**13*(-7 - 10816*J - 242352*J**2 - 26620160*J**3 + 953885440*J**4 - - 2350596096*J**5 + 26796552192*J**6 - 13329432576*J**7) - beta[27] = 580*(J - 1)**13*(-7 - 12259*J - 317176*J**2 - 41205008*J**3 + - 1808220160*J**4 - 5714806016*J**5 + 93590857728*J**6 - 70131806208*J**7 - 36118462464*J**8) - beta[28] = 435*(J - 1)**14*(1 + 1976*J + 60720*J**2 + 8987648*J**3 - 463120640*J**4 + 1359157248*J**5 - - 40644882432*J**6 - 5016453120*J**7 + 61917364224*J**8) - beta[29] = 30*(J - 1)**14*(1 + 2218*J + 77680*J**2 + 13365152*J**3 - - 822366976*J**4 + 2990693888*J**5 - 118286217216*J**6 - 24514928640*J**7 + 509958291456*J**8 - 743008370688*J**9) - beta[30] = (J - 1)**15*(-1 - 2480*J - 101040*J**2 - 19642496*J**3 + 1399023872*J**4 - - 4759216128*J**5 + 315623485440*J**6 + 471904911360*J**7 - 2600529297408*J**8 + 8916100448256*J**9) + beta[2] = -435 * (J - 1) + beta[3] = 580 * (J - 1) * (-7 + 9 * J) + beta[4] = 3915 * (J - 1) ** 2 * (7 - 8 * J) + beta[5] = 1566 * (J - 1) ** 2 * (91 - 78 * J + 48 * J**2) + beta[6] = -84825 * (J - 1) ** 3 * (7 + 16 * J) + beta[7] = 156600 * (J - 1) ** 3 * (-13 - 91 * J + 92 * J**2) + beta[8] = 450225 * (J - 1) ** 4 * (13 + 208 * J - 144 * J**2) + beta[9] = 100050 * (J - 1) ** 4 * (143 + 4004 * J - 5632 * J**2 + 1728 * J**3) + beta[10] = 30015 * (J - 1) ** 5 * (-1001 - 45760 * J + 44880 * J**2 - 6912 * J**3) + beta[11] = 600300 * (J - 1) ** 5 * (-91 - 6175 * J + 9272 * J**2 - 2736 * J**3) + beta[12] = 950475 * (J - 1) ** 6 * (91 + 8840 * J - 7824 * J**2) + beta[13] = 17108550 * (J - 1) ** 6 * (7 + 926 * J - 1072 * J**2 + 544 * J**3) + beta[14] = 145422675 * (J - 1) ** 7 * (-1 - 176 * J + 48 * J**2 - 384 * J**3) + beta[15] = 155117520 * (J - 1) ** 8 * (1 + 228 * J + 176 * J**2 + 1728 * J**3) + beta[16] = 145422675 * (J - 1) ** 8 * (1 + 288 * J + 288 * J**2 + 5120 * J**3 - 6912 * J**4) + beta[17] = 17108550 * (J - 1) ** 8 * (7 + 2504 * J + 3584 * J**2 + 93184 * J**3 - 283392 * J**4 + 165888 * J**5) + beta[18] = 950475 * (J - 1) ** 9 * (-91 - 39936 * J - 122976 * J**2 - 2960384 * J**3 + 11577600 * J**4 - 5971968 * J**5) + beta[19] = 600300 * (J - 1) ** 9 * (-91 - 48243 * J - 191568 * J**2 - 6310304 * J**3 + 40515072 * J**4 - 46455552 * J**5 + 11943936 * J**6) + beta[20] = 30015 * (J - 1) ** 10 * (1001 + 634920 * J + 3880800 * J**2 + 142879744 * J**3 - 1168475904 * J**4 + 1188919296 * J**5 - 143327232 * J**6) + beta[21] = 100050 * (J - 1) ** 10 * (143 + 107250 * J + 808368 * J**2 + 38518336 * J**3 - 451953408 * J**4 + 757651968 * J**5 - 367276032 * J**6) + beta[22] = 450225 * (J - 1) ** 11 * (-13 - 11440 * J - 117216 * J**2 - 6444800 * J**3 + 94192384 * J**4 - 142000128 * J**5 + 95551488 * J**6) + beta[23] = 156600 * (J - 1) ** 11 * (-13 - 13299 * J - 163284 * J**2 - 11171552 * J**3 + 217203840 * J**4 - 474406656 * J**5 + 747740160 * J**6 - 429981696 * J**7) + beta[24] = 6525 * (J - 1) ** 12 * (91 + 107536 * J + 1680624 * J**2 + 132912128 * J**3 - 3147511552 * J**4 + 6260502528 * J**5 - 21054173184 * J**6 + 10319560704 * J**7) + beta[25] = 1566 * (J - 1) ** 12 * (91 + 123292 * J + 2261248 * J**2 + 216211904 * J**3 - 6487793920 * J**4 + 17369596928 * J**5 - 97854234624 * J**6 + 96136740864 * J**7 - 20639121408 * J**8) + beta[26] = 3915 * (J - 1) ** 13 * (-7 - 10816 * J - 242352 * J**2 - 26620160 * J**3 + 953885440 * J**4 - 2350596096 * J**5 + 26796552192 * J**6 - 13329432576 * J**7) + beta[27] = 580 * (J - 1) ** 13 * (-7 - 12259 * J - 317176 * J**2 - 41205008 * J**3 + 1808220160 * J**4 - 5714806016 * J**5 + 93590857728 * J**6 - 70131806208 * J**7 - 36118462464 * J**8) + beta[28] = 435 * (J - 1) ** 14 * (1 + 1976 * J + 60720 * J**2 + 8987648 * J**3 - 463120640 * J**4 + 1359157248 * J**5 - 40644882432 * J**6 - 5016453120 * J**7 + 61917364224 * J**8) + beta[29] = 30 * (J - 1) ** 14 * (1 + 2218 * J + 77680 * J**2 + 13365152 * J**3 - 822366976 * J**4 + 2990693888 * J**5 - 118286217216 * J**6 - 24514928640 * J**7 + 509958291456 * J**8 - 743008370688 * J**9) + beta[30] = (J - 1) ** 15 * (-1 - 2480 * J - 101040 * J**2 - 19642496 * J**3 + 1399023872 * J**4 - 4759216128 * J**5 + 315623485440 * J**6 + 471904911360 * J**7 - 2600529297408 * J**8 + 8916100448256 * J**9) R = PolynomialRing(QQ, 't') c2 = a * R(alpha) diff --git a/src/sage/schemes/elliptic_curves/mod_poly.py b/src/sage/schemes/elliptic_curves/mod_poly.py index a75f2a71e59..a2a8cbf1617 100644 --- a/src/sage/schemes/elliptic_curves/mod_poly.py +++ b/src/sage/schemes/elliptic_curves/mod_poly.py @@ -19,6 +19,7 @@ from cypari2.handle_error import PariError from sage.databases.db_modular_polynomials import ClassicalModularPolynomialDatabase + _db = ClassicalModularPolynomialDatabase() _cache_bound = 100 @@ -123,8 +124,7 @@ def classical_modular_polynomial(l, j=None): pari_Phi = pari.polmodular(l) except PariError: raise NotImplementedError('modular polynomial is not in database and computing it on the fly is not yet implemented') - d = {(i, j): c for i, f in enumerate(pari_Phi) - for j, c in enumerate(f)} + d = {(i, j): c for i, f in enumerate(pari_Phi) for j, c in enumerate(f)} Phi = ZZ['X,Y'](d) if l <= _cache_bound: diff --git a/src/sage/schemes/elliptic_curves/modular_parametrization.py b/src/sage/schemes/elliptic_curves/modular_parametrization.py index 2df0d64f5cc..78ad57820f2 100644 --- a/src/sage/schemes/elliptic_curves/modular_parametrization.py +++ b/src/sage/schemes/elliptic_curves/modular_parametrization.py @@ -28,6 +28,7 @@ - Chris Wuthrich (02/10): moved from ell_rational_field.py. """ + ###################################################################### # Copyright (C) 2010 William Stein # @@ -70,6 +71,7 @@ class ModularParameterization: to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field """ + def __init__(self, E): r""" EXAMPLES:: @@ -187,6 +189,7 @@ def __call__(self, z, prec=None): curve itself. """ from sage.misc.verbose import verbose + if isinstance(z, heegner.HeegnerPointOnX0N): return z.map_to_curve(self.curve()) # Map to the CC of CC/PeriodLattice. diff --git a/src/sage/schemes/elliptic_curves/padic_lseries.py b/src/sage/schemes/elliptic_curves/padic_lseries.py index 563831bc150..b20bc28bf0f 100644 --- a/src/sage/schemes/elliptic_curves/padic_lseries.py +++ b/src/sage/schemes/elliptic_curves/padic_lseries.py @@ -64,11 +64,7 @@ import sage.schemes.hyperelliptic_curves.monsky_washnitzer from sage.arith.functions import lcm as LCM -from sage.arith.misc import (binomial, - GCD as gcd, - prime_divisors, - kronecker as kronecker_symbol, - valuation) +from sage.arith.misc import binomial, GCD as gcd, prime_divisors, kronecker as kronecker_symbol, valuation from sage.misc.cachefunc import cached_method from sage.misc.functional import denominator from sage.misc.lazy_import import lazy_import @@ -150,6 +146,7 @@ class pAdicLseries(SageObject): sage: lp == loads(dumps(lp)) True """ + def __init__(self, E, p, implementation='eclib', normalize='L_ratio'): r""" INPUT: @@ -179,7 +176,7 @@ def __init__(self, E, p, implementation='eclib', normalize='L_ratio'): self._implementation = implementation if not self._p.is_prime(): raise ValueError("p (=%s) must be a prime" % p) - if E.conductor() % (self._p)**2 == 0: + if E.conductor() % (self._p) ** 2 == 0: raise NotImplementedError("p (=%s) must be a prime of semi-stable reduction" % p) try: @@ -188,9 +185,7 @@ def __init__(self, E, p, implementation='eclib', normalize='L_ratio'): if implementation != 'num': print("Warning : Curve outside Cremona's table. Computations of modular symbol space might take very long !") - self._modular_symbol = E.modular_symbol(sign=+1, - implementation=implementation, - normalize=normalize) + self._modular_symbol = E.modular_symbol(sign=+1, implementation=implementation, normalize=normalize) def __add_negative_space(self): r""" @@ -330,8 +325,7 @@ def modular_symbol(self, r, sign=+1, quadratic_twist=+1): raise NotImplementedError("Quadratic twists for negative modular symbols are not yet implemented.") if D > 0: m = self._modular_symbol - return sum([kronecker_symbol(D, u) * m(r + ZZ(u) / D) - for u in range(1, D)]) + return sum([kronecker_symbol(D, u) * m(r + ZZ(u) / D) for u in range(1, D)]) try: m = self._negative_modular_symbol @@ -339,8 +333,7 @@ def modular_symbol(self, r, sign=+1, quadratic_twist=+1): if not hasattr(self, '_modular_symbol_negative'): self.__add_negative_space() m = self._negative_modular_symbol - return -sum([kronecker_symbol(D, u) * m(r + ZZ(u) / D) - for u in range(1, -D)]) + return -sum([kronecker_symbol(D, u) * m(r + ZZ(u) / D) for u in range(1, -D)]) def measure(self, a, n, prec, quadratic_twist=+1, sign=+1): r""" @@ -417,8 +410,8 @@ def measure(self, a, n, prec, quadratic_twist=+1, sign=+1): self.__measure_data = {} p = self._p alpha = self.alpha(prec=prec) - z = 1/(alpha**n) - w = p**(n-1) + z = 1 / (alpha**n) + w = p ** (n - 1) if s == +1: f = self._modular_symbol else: @@ -432,18 +425,18 @@ def measure(self, a, n, prec, quadratic_twist=+1, sign=+1): if quadratic_twist == 1: if self._E.conductor() % p == 0: - return z * f(a/(p*w)) - return z * ( f(a/(p*w)) - f(a/w) / alpha) + return z * f(a / (p * w)) + return z * (f(a / (p * w)) - f(a / w) / alpha) D = quadratic_twist if self.is_ordinary(): - chip = kronecker_symbol(D,p) + chip = kronecker_symbol(D, p) else: - chip = 1 # alpha is +- sqrt(-p) anyway + chip = 1 # alpha is +- sqrt(-p) anyway if self._E.conductor() % p == 0: - mu = chip**n * z * sum([kronecker_symbol(D,u) * f(a/(p*w)+ZZ(u)/D) for u in range(1,D.abs())]) + mu = chip**n * z * sum([kronecker_symbol(D, u) * f(a / (p * w) + ZZ(u) / D) for u in range(1, D.abs())]) else: - mu = chip**n * z * sum([kronecker_symbol(D,u) * ( f(a/(p*w)+ZZ(u)/D) - chip / alpha * f(a/w+ZZ(u)/D) ) for u in range(1,D.abs())]) - return s*mu + mu = chip**n * z * sum([kronecker_symbol(D, u) * (f(a / (p * w) + ZZ(u) / D) - chip / alpha * f(a / w + ZZ(u) / D)) for u in range(1, D.abs())]) + return s * mu def alpha(self, prec=20): r""" @@ -508,7 +501,7 @@ def alpha(self, prec=20): self._alpha[prec] = K(a) return K(a) raise RuntimeError("bug in p-adic L-function alpha") - else: # supersingular case + else: # supersingular case f = f.change_ring(K) A = K.extension(f, names='alpha') a = A.gen() @@ -599,8 +592,7 @@ def teichmuller(self, prec): """ p = self._p K = Qp(p, prec, print_mode='series') - return [Integer(0)] + \ - [a.residue(prec).lift() for a in K.teichmuller_system()] + return [Integer(0)] + [a.residue(prec).lift() for a in K.teichmuller_system()] def _e_bounds(self, n, prec): r""" @@ -625,8 +617,8 @@ def _e_bounds(self, n, prec): pn = self._p**n enj = infinity res = [enj] - for j in range(1,prec): - bino = valuation(binomial(pn,j),self._p) + for j in range(1, prec): + bino = valuation(binomial(pn, j), self._p) enj = min(bino, enj) res.append(enj) return res @@ -649,13 +641,13 @@ def _get_series_from_cache(self, n, prec, D, eta): 5 + 4*5^2 + 4*5^3 + O(5^4) + O(5)*T + O(5)*T^2 + O(5)*T^3 + O(5)*T^4 + O(T^5) """ try: - return self.__series[(n,prec,D,eta)] + return self.__series[(n, prec, D, eta)] except AttributeError: self.__series = {} except KeyError: for _n, _prec, _D, _eta in self.__series: if _n == n and _D == D and _eta == eta and _prec >= prec: - return self.__series[(_n,_prec,_D,_eta)].add_bigoh(prec) + return self.__series[(_n, _prec, _D, _eta)].add_bigoh(prec) return None def _set_series_in_cache(self, n, prec, D, eta, f): @@ -869,20 +861,20 @@ def series(self, n=2, quadratic_twist=+1, prec=5, eta=0): if eta != 0: raise NotImplementedError("quadratic twists only implemented for the 0th Teichmueller component") if D % 4 == 0: - d = D//4 + d = D // 4 if not d.is_squarefree() or d % 4 == 1: raise ValueError("quadratic_twist (=%s) must be a fundamental discriminant of a quadratic field" % D) else: if not D.is_squarefree() or D % 4 != 1: raise ValueError("quadratic_twist (=%s) must be a fundamental discriminant of a quadratic field" % D) - if gcd(D,self._p) != 1: - raise ValueError("quadratic twist (=%s) must be coprime to p (=%s) " % (D,self._p)) + if gcd(D, self._p) != 1: + raise ValueError("quadratic twist (=%s) must be coprime to p (=%s) " % (D, self._p)) if gcd(D, self._E.conductor()) != 1: for ell in prime_divisors(D): if valuation(self._E.conductor(), ell) > valuation(D, ell): - raise ValueError("cannot twist a curve of conductor (=%s) by the quadratic twist (=%s)." % (self._E.conductor(),D)) + raise ValueError("cannot twist a curve of conductor (=%s) by the quadratic twist (=%s)." % (self._E.conductor(), D)) p = self._p - si = 1-2*(eta % 2) + si = 1 - 2 * (eta % 2) # verbose("computing L-series for p=%s, n=%s, and prec=%s" % (p,n,prec)) @@ -892,39 +884,39 @@ def series(self, n=2, quadratic_twist=+1, prec=5, eta=0): # need to do any sum as L_p(E,0) = (1-1/alpha)^2 * m(0) (good case) # set prec arbitrary to 20. K = Qp(p, 20, print_mode='series') - R = PowerSeriesRing(K,'T',1) + R = PowerSeriesRing(K, 'T', 1) L = self.modular_symbol(0, sign=+1, quadratic_twist=D) - chip = kronecker_symbol(D,p) + chip = kronecker_symbol(D, p) if self._E.conductor() % p == 0: - L *= 1 - chip/self.alpha() + L *= 1 - chip / self.alpha() else: - L *= (1-chip/self.alpha())**2 - L /= self._quotient_of_periods_to_twist(D)*self._E.real_components() + L *= (1 - chip / self.alpha()) ** 2 + L /= self._quotient_of_periods_to_twist(D) * self._E.real_components() L = R(L, 1) return L # here we need some sums anyway - bounds = self._prec_bounds(n,prec,sign=si) + bounds = self._prec_bounds(n, prec, sign=si) padic_prec = 20 else: - bounds = self._prec_bounds(n,prec,sign=si) + bounds = self._prec_bounds(n, prec, sign=si) padic_prec = max(bounds[1:]) + 5 verbose("using p-adic precision of %s" % padic_prec) if p == 2: - res_series_prec = min(p**(n-2), prec) + res_series_prec = min(p ** (n - 2), prec) else: - res_series_prec = min(p**(n-1), prec) + res_series_prec = min(p ** (n - 1), prec) verbose("using series precision of %s" % res_series_prec) - ans = self._get_series_from_cache(n, res_series_prec,D,eta) + ans = self._get_series_from_cache(n, res_series_prec, D, eta) if ans is not None: verbose("found series in cache") return ans K = QQ - R = PowerSeriesRing(K,'T',res_series_prec) - T = R(R.gen(),res_series_prec ) + R = PowerSeriesRing(K, 'T', res_series_prec) + T = R(R.gen(), res_series_prec) L = R(0) one_plus_T_factor = R(1) gamma_power = K(1) @@ -932,40 +924,39 @@ def series(self, n=2, quadratic_twist=+1, prec=5, eta=0): if p == 2: teich = [0, 1, -1] gamma = K(5) - p_power = 2**(n-2) + p_power = 2 ** (n - 2) a_range = 3 else: teich = self.teichmuller(padic_prec) gamma = K(1 + p) - p_power = p**(n-1) + p_power = p ** (n - 1) a_range = p - verbose("Now iterating over %s summands" % ((p-1)*p_power)) + verbose("Now iterating over %s summands" % ((p - 1) * p_power)) verbose_level = get_verbose() count_verb = 0 for j in range(p_power): s = K(0) - if verbose_level >= 2 and j/p_power*100 > count_verb + 3: - verbose("%.2f percent done" % (float(j)/p_power*100)) + if verbose_level >= 2 and j / p_power * 100 > count_verb + 3: + verbose("%.2f percent done" % (float(j) / p_power * 100)) count_verb += 3 - for a in range(1,a_range): + for a in range(1, a_range): b = teich[a] * gamma_power - s += teich[a]**eta * self.measure(b, n, padic_prec, quadratic_twist=D, sign=si).lift() + s += teich[a] ** eta * self.measure(b, n, padic_prec, quadratic_twist=D, sign=si).lift() L += s * one_plus_T_factor - one_plus_T_factor *= 1+T + one_plus_T_factor *= 1 + T gamma_power *= gamma verbose("the series before adjusting the precision is %s" % L) # Now create series but with each coefficient truncated # so it is proven correct: K = Qp(p, padic_prec, print_mode='series') - R = PowerSeriesRing(K,'T',res_series_prec) - L = R(L,res_series_prec) + R = PowerSeriesRing(K, 'T', res_series_prec) + L = R(L, res_series_prec) aj = L.list() if aj: - aj = [aj[0].add_bigoh(padic_prec-2)] + \ - [aj[j].add_bigoh(bounds[j]) for j in range(1,len(aj))] - L = R(aj,res_series_prec ) + aj = [aj[0].add_bigoh(padic_prec - 2)] + [aj[j].add_bigoh(bounds[j]) for j in range(1, len(aj))] + L = R(aj, res_series_prec) L /= self._quotient_of_periods_to_twist(D) if si == +1: @@ -1063,6 +1054,7 @@ def _c_bound(self, sign=+1): # else the same reasoning as in _set_denom in numerical # modular symbol. We rely on the fact that p is semistable from sage.databases.cremona import CremonaDatabase + isog = E.isogeny_class() t = 0 if N <= CremonaDatabase().largest_conductor(): @@ -1105,9 +1097,9 @@ def _c_bound(self, sign=+1): if E0.real_components() == 1: om0 *= 2 m = max(isog.matrix().list()) - q = (om/om0 * m).round()/m - t += valuation(q,p) - return max(t,0) + q = (om / om0 * m).round() / m + t += valuation(q, p) + return max(t, 0) def _prec_bounds(self, n, prec, sign=+1): r""" @@ -1218,7 +1210,7 @@ def series(self, n=3, quadratic_twist=+1, prec=5, eta=0): if eta != 0: raise NotImplementedError("quadratic twists only implemented for the 0th Teichmueller component") if D % 4 == 0: - d = D//4 + d = D // 4 if not d.is_squarefree() or d % 4 == 1: raise ValueError("quadratic_twist (=%s) must be a fundamental discriminant of a quadratic field" % D) else: @@ -1239,72 +1231,72 @@ def series(self, n=3, quadratic_twist=+1, prec=5, eta=0): # set prec arbitrary to 20. alpha = self.alpha(prec=20) K = alpha.parent() - R = PowerSeriesRing(K,'T',1) + R = PowerSeriesRing(K, 'T', 1) L = self.modular_symbol(0, sign=+1, quadratic_twist=D) - L *= (1-1/self.alpha())**2 - L /= self._quotient_of_periods_to_twist(D)*self._E.real_components() + L *= (1 - 1 / self.alpha()) ** 2 + L /= self._quotient_of_periods_to_twist(D) * self._E.real_components() L = R(L, 1) return L # here we need some sums anyway - bounds = self._prec_bounds(n,prec) + bounds = self._prec_bounds(n, prec) alphaadic_prec = 20 else: - prec = min(p**(n-1), prec) - bounds = self._prec_bounds(n,prec) + prec = min(p ** (n - 1), prec) + bounds = self._prec_bounds(n, prec) alphaadic_prec = max(bounds[1:]) + 5 - padic_prec = alphaadic_prec//2+1 + padic_prec = alphaadic_prec // 2 + 1 verbose("using alpha-adic precision of %s" % padic_prec) - ans = self._get_series_from_cache(n, prec, quadratic_twist,eta) + ans = self._get_series_from_cache(n, prec, quadratic_twist, eta) if ans is not None: verbose("found series in cache") return ans alpha = self.alpha(prec=padic_prec) K = alpha.parent() - R = PowerSeriesRing(K,'T',prec) + R = PowerSeriesRing(K, 'T', prec) T = R(R.gen(), prec) L = R(0) one_plus_T_factor = R(1) gamma_power = 1 teich = self.teichmuller(padic_prec) if p == 2: - teich = [0, 1,-1] + teich = [0, 1, -1] gamma = 5 - p_power = 2**(n-2) + p_power = 2 ** (n - 2) a_range = 3 else: teich = self.teichmuller(padic_prec) gamma = 1 + p - p_power = p**(n-1) + p_power = p ** (n - 1) a_range = p - si = 1-2*(eta % 2) + si = 1 - 2 * (eta % 2) - verbose("Now iterating over %s summands" % ((p-1)*p_power)) + verbose("Now iterating over %s summands" % ((p - 1) * p_power)) verbose_level = get_verbose() count_verb = 0 for j in range(p_power): s = K(0) - if verbose_level >= 2 and j/p_power*100 > count_verb + 3: - verbose("%.2f percent done" % (float(j)/p_power*100)) + if verbose_level >= 2 and j / p_power * 100 > count_verb + 3: + verbose("%.2f percent done" % (float(j) / p_power * 100)) count_verb += 3 - for a in range(1,a_range): + for a in range(1, a_range): b = teich[a] * gamma_power - s += teich[a]**eta * self.measure(b, n, padic_prec, quadratic_twist=D, sign=si) + s += teich[a] ** eta * self.measure(b, n, padic_prec, quadratic_twist=D, sign=si) L += s * one_plus_T_factor - one_plus_T_factor *= 1+T + one_plus_T_factor *= 1 + T gamma_power *= gamma # Now create series but with each coefficient truncated # so it is proven correct: # the coefficients are now treated as alpha-adic numbers (trac 20254) - L = R(L,prec) + L = R(L, prec) aj = L.list() if aj: - bj = [aj[0].add_bigoh(2*(padic_prec-2))] + bj = [aj[0].add_bigoh(2 * (padic_prec - 2))] j = 1 while j < len(aj): - bj.append( aj[j].add_bigoh(bounds[j]) ) + bj.append(aj[j].add_bigoh(bounds[j])) j += 1 L = R(bj, prec) L /= self._quotient_of_periods_to_twist(D) @@ -1442,8 +1434,8 @@ def Dp_valued_series(self, n=3, quadratic_twist=+1, prec=5): # now compute phi phi = matrix([[0, -1 / p], [1, E.ap(p) / p]]) - lpv = vector([G + (E.ap(p)) * H, - R(p) * H]) # this is L_p - eps = (1 - phi)**(-2) + lpv = vector([G + (E.ap(p)) * H, -R(p) * H]) # this is L_p + eps = (1 - phi) ** (-2) resu = lpv * eps.transpose() return resu @@ -1490,7 +1482,7 @@ def frobenius(self, prec=20, algorithm='mw'): Q = x**3 + modprecring(Ew.a4()) * x + modprecring(Ew.a6()) trace = Ew.ap(p) fr = sage.schemes.hyperelliptic_curves.monsky_washnitzer.matrix_of_frobenius(Q, p, adjusted_prec, trace) - fr = matrix(output_ring,2,2,fr) + fr = matrix(output_ring, 2, 2, fr) # return a vector for PARI's ellchangecurve to pass from e1 to e2 def isom(e1, e2): @@ -1499,8 +1491,8 @@ def isom(e1, e2): usq = (e1.discriminant() / e2.discriminant()).nth_root(6) u = usq.sqrt() s = (u * e2.a1() - e1.a1()) / ZZ(2) - r = (usq * e2.a2() - e1.a2() + s**2 + e1.a1()*s) / ZZ(3) - t = (u**3 * e2.a3() - e1.a3() - e1.a1()*r) / ZZ(2) + r = (usq * e2.a2() - e1.a2() + s**2 + e1.a1() * s) / ZZ(3) + t = (u**3 * e2.a3() - e1.a3() - e1.a1() * r) / ZZ(2) return [u, r, s, t] v = isom(E, Ew) @@ -1508,9 +1500,9 @@ def isom(e1, e2): r = v[1] # change basis - A = matrix([[u, -r/u], [0, 1/u]]) - frn = A * fr * A**(-1) - return 1 / p*frn + A = matrix([[u, -r / u], [0, 1 / u]]) + frn = A * fr * A ** (-1) + return 1 / p * frn def __phi_bpr(self, prec=0): r""" @@ -1546,63 +1538,61 @@ def __phi_bpr(self, prec=0): if prec > 10: print("Warning: Very large value for the precision.") if prec == 0: - prec = floor(log(10000)/log(p)) + prec = floor(log(10000) / log(p)) verbose("prec set to %s" % prec) eh = E.formal() - om = eh.differential(prec=p**prec+3) + om = eh.differential(prec=p**prec + 3) verbose("differential computed") xt = eh.x(prec=p**prec + 3) - et = xt*om + et = xt * om # c_(p^k) = cs[k] d... - cs = [om[p**k-1] for k in range(prec + 1)] - ds = [et[p**k-1] for k in range(prec + 1)] + cs = [om[p**k - 1] for k in range(prec + 1)] + ds = [et[p**k - 1] for k in range(prec + 1)] delta = 0 dpr = 0 gamma = 0 dga = 0 - for k in range(1,prec+1): + for k in range(1, prec + 1): # this is the equation eq[0]*x+eq[1]*y+eq[2] == 0 # such that delta_ = delta + d^dpr*x ... - eq = [(p**dpr*cs[k]) % p**k, - (-p**dga*ds[k]) % p**k, - (delta*cs[k]-gamma*ds[k]-cs[k-1]) % p**k] + eq = [(p**dpr * cs[k]) % p**k, (-(p**dga) * ds[k]) % p**k, (delta * cs[k] - gamma * ds[k] - cs[k - 1]) % p**k] verbose("valuations : %s" % ([x.valuation(p) for x in eq])) v = min(x.valuation(p) for x in eq) if v == infinity: verbose("no new information at step k=%s" % k) else: - eq = [ZZ(x/p**v) for x in eq] - verbose("renormalised eq mod p^%s is now %s" % (k-v,eq)) + eq = [ZZ(x / p**v) for x in eq] + verbose("renormalised eq mod p^%s is now %s" % (k - v, eq)) if eq[0].valuation(p) == 0: - l = min(eq[1].valuation(p),k-v) + l = min(eq[1].valuation(p), k - v) if l == 0: verbose("not uniquely determined at step k=%s" % k) else: ainv = eq[0].inverse_mod(p**l) - delta = delta - eq[2]*ainv*p**dpr + delta = delta - eq[2] * ainv * p**dpr dpr = dpr + l delta = delta % p**dpr - verbose("delta_prec increased to %s\n delta is now %s" % (dpr,delta)) + verbose("delta_prec increased to %s\n delta is now %s" % (dpr, delta)) elif eq[1].valuation(p) == 0: - l = min(eq[0].valuation(p),k-v) + l = min(eq[0].valuation(p), k - v) ainv = eq[1].inverse_mod(p**l) - gamma = gamma - eq[2]*ainv*p**dga + gamma = gamma - eq[2] * ainv * p**dga dga = dga + l gamma = gamma % p**dga - verbose("gamma_prec increased to %s\n gamma is now %s" % (dga,gamma)) + verbose("gamma_prec increased to %s\n gamma is now %s" % (dga, gamma)) else: raise RuntimeError("Bug: no delta or gamma can exist") # end of approximation of delta and gamma - R = Qp(p,max(dpr,dga)+1) - delta = R(delta,absprec=dpr) - gamma = R(gamma,absprec=dga) - verbose("result delta = %s\n gamma = %s\n check : %s" % (delta,gamma, [Qp(p,k)(delta * cs[k] - gamma * ds[k] - cs[k-1]) for k in range(1,prec+1)] )) + R = Qp(p, max(dpr, dga) + 1) + delta = R(delta, absprec=dpr) + gamma = R(gamma, absprec=dga) + verbose("result delta = %s\n gamma = %s\n check : %s" % (delta, gamma, [Qp(p, k)(delta * cs[k] - gamma * ds[k] - cs[k - 1]) for k in range(1, prec + 1)])) a = delta c = -gamma d = E.ap(p) - a - b = (-1/p+a*d)/c - phi = matrix([[a,b],[c,d]]) + b = (-1 / p + a * d) / c + phi = matrix([[a, b], [c, d]]) return phi def bernardi_sigma_function(self, prec=20): @@ -1624,12 +1614,12 @@ def bernardi_sigma_function(self, prec=20): lo = Eh.log(prec + 5) F = lo.reverse() - S = LaurentSeriesRing(QQ,'z') + S = LaurentSeriesRing(QQ, 'z') z = S.gen() F = F(z) xofF = Eh.x(prec + 2)(F) - #r = ( E.a1()**2 + 4*E.a2() ) / ZZ(12) - g = (1/z**2 - xofF ).power_series() + # r = ( E.a1()**2 + 4*E.a2() ) / ZZ(12) + g = (1 / z**2 - xofF).power_series() h = g.integral().integral() sigma_of_z = z.power_series() * h.exp() @@ -1666,26 +1656,27 @@ def Dp_valued_height(self, prec=20): # we will have to do it properly with David Harvey's _multiply_point() # import here to avoid circular import from sage.schemes.elliptic_curves.padics import _multiple_to_make_good_reduction + n = _multiple_to_make_good_reduction(E) - n = LCM(n, E.Np(p)) # allowed here because E has good reduction at p + n = LCM(n, E.Np(p)) # allowed here because E has good reduction at p def height(P, check=True): if P.is_finite_order(): - return Qp(p,prec)(0) + return Qp(p, prec)(0) if check: assert P.curve() == E, 'the point P must lie on the curve from which the height function was created' Q = n * P - tt = - Q[0]/Q[1] - R = Qp(p,prec+5) + tt = -Q[0] / Q[1] + R = Qp(p, prec + 5) tt = R(tt) zz = elog(tt) - homega = -zz**2 / n**2 + homega = -(zz**2) / n**2 eQ = denominator(Q[1]) / denominator(Q[0]) - si = self.bernardi_sigma_function(prec=prec+4) - heta = 2 * log(si(zz)/eQ) / n**2 + si = self.bernardi_sigma_function(prec=prec + 4) + heta = 2 * log(si(zz) / eQ) / n**2 R = Qp(p, prec) @@ -1721,7 +1712,7 @@ def Dp_valued_regulator(self, prec=20, v1=0, v2=0): # this is the height_{v} (P) for a v in D_p def hv(vec, P): hP = h(P) - return - vec[0]*hP[1] + vec[1]*hP[0] + return -vec[0] * hP[1] + vec[1] * hP[0] # def hvpairing(vec,P,Q): # return (hv(vec, P+Q) - hv(vec,P)-hv(vec,Q))/2 @@ -1743,26 +1734,26 @@ def regv(vec): M = matrix(K, rk, rk, 0) point_height = [hv(vec, P) for P in basis] for i in range(rk): - for j in range(i+1, rk): - M[i, j] = M[j, i] = (hv(vec,basis[i] + basis[j]) - point_height[i] - point_height[j] )/2 + for j in range(i + 1, rk): + M[i, j] = M[j, i] = (hv(vec, basis[i] + basis[j]) - point_height[i] - point_height[j]) / 2 for i in range(rk): M[i, i] = point_height[i] return M.determinant() def Dp_pairing(vec1, vec2): - return (vec1[0]*vec2[1]-vec1[1]*vec2[0]) + return vec1[0] * vec2[1] - vec1[1] * vec2[0] - omega_vec = vector([K(1),K(0)]) + omega_vec = vector([K(1), K(0)]) # note the correction here with respect to Perrin-Riou's definition. # only this way the result will be independent of the choice of v1 and v2. - reg1 = regv(v1) / Dp_pairing(omega_vec, v1)**(rk - 1) + reg1 = regv(v1) / Dp_pairing(omega_vec, v1) ** (rk - 1) - reg2 = regv(v2) / Dp_pairing(omega_vec, v2)**(rk - 1) + reg2 = regv(v2) / Dp_pairing(omega_vec, v2) ** (rk - 1) # the regulator in the basis omega,eta - reg_oe = (reg1 * v2 - reg2 * v1 ) / Dp_pairing(v2, v1) + reg_oe = (reg1 * v2 - reg2 * v1) / Dp_pairing(v2, v1) if p < 5: phi = self.frobenius(min(6, prec), algorithm='approx') @@ -1772,4 +1763,4 @@ def Dp_pairing(vec1, vec2): c = phi[1, 0] # this is the 'period' [omega,phi(omega)] a = phi[0, 0] - return vector([reg_oe[0] - a/c*reg_oe[1],reg_oe[1]/c]) + return vector([reg_oe[0] - a / c * reg_oe[1], reg_oe[1] / c]) diff --git a/src/sage/schemes/elliptic_curves/padics.py b/src/sage/schemes/elliptic_curves/padics.py index 2ac3305bbc3..d40f2c452df 100644 --- a/src/sage/schemes/elliptic_curves/padics.py +++ b/src/sage/schemes/elliptic_curves/padics.py @@ -106,8 +106,7 @@ def _normalize_padic_lseries(self, p, normalize, implementation, precision): @cached_method(key=_normalize_padic_lseries) -def padic_lseries(self, p, normalize=None, implementation='eclib', - precision=None): +def padic_lseries(self, p, normalize=None, implementation='eclib', precision=None): r""" Return the `p`-adic `L`-series of ``self`` at `p`, which is an object whose approx method computes @@ -211,23 +210,20 @@ def padic_lseries(self, p, normalize=None, implementation='eclib', sage: L[3] O(11^0) """ - p, normalize, implementation, precision = self._normalize_padic_lseries(p, - normalize, implementation, precision) + p, normalize, implementation, precision = self._normalize_padic_lseries(p, normalize, implementation, precision) if implementation in ['sage', 'eclib', 'num']: if self.ap(p) % p != 0: - Lp = plseries.pAdicLseriesOrdinary(self, p, - normalize=normalize, implementation=implementation) + Lp = plseries.pAdicLseriesOrdinary(self, p, normalize=normalize, implementation=implementation) else: - Lp = plseries.pAdicLseriesSupersingular(self, p, - normalize=normalize, implementation=implementation) + Lp = plseries.pAdicLseriesSupersingular(self, p, normalize=normalize, implementation=implementation) else: phi = self.pollack_stevens_modular_symbol(sign=0) if phi.parent().level() % p == 0: Phi = phi.lift(p, precision, eigensymbol=True) else: Phi = phi.p_stabilize_and_lift(p, precision, eigensymbol=True) - Lp = Phi.padic_lseries() #mm TODO should this pass precision on too ? + Lp = Phi.padic_lseries() # mm TODO should this pass precision on too ? Lp._cinf = self.real_components() return Lp @@ -318,7 +314,7 @@ def padic_regulator(self, p, prec=20, height=None, check_hypotheses=True): if not p.is_prime(): raise ValueError("p = (%s) must be prime" % p) if p == 2: - raise ValueError("p must be odd") # todo + raise ValueError("p must be odd") # todo if self.conductor() % (p**2) == 0: raise ArithmeticError("p must be a semi-stable prime") @@ -331,7 +327,7 @@ def padic_regulator(self, p, prec=20, height=None, check_hypotheses=True): reg = lp.Dp_valued_regulator(prec=prec) return reg if self.rank() == 0: - return Qp(p,prec)(1) + return Qp(p, prec)(1) if height is None: height = self.padic_height(p, prec, check_hypotheses=False) d = self.padic_height_pairing_matrix(p=p, prec=prec, height=height, check_hypotheses=False) @@ -411,10 +407,10 @@ def padic_height_pairing_matrix(self, p, prec=20, height=None, check_hypotheses= # Use =1/2*( h(P + Q) - h(P) - h(Q) ) for i in range(rank): - M[i,i] = height(basis[i]) + M[i, i] = height(basis[i]) for i in range(rank): - for j in range(i+1, rank): - M[i, j] = ( height(basis[i] + basis[j]) - M[i,i] - M[j,j] ) / 2 + for j in range(i + 1, rank): + M[i, j] = (height(basis[i] + basis[j]) - M[i, i] - M[j, j]) / 2 M[j, i] = M[i, j] return M @@ -526,12 +522,12 @@ def _multiply_point(E, R, P, m): b6 = R(E.b6()) * d**6 b8 = R(E.b8()) * d**8 - B4 = 6*alpha**2 + b2*alpha + b4 - B6 = 4*alpha**3 + b2*alpha**2 + 2*b4*alpha + b6 - B6_sqr = B6*B6 - B8 = 3*alpha**4 + b2*alpha**3 + 3*b4*alpha**2 + 3*b6*alpha + b8 + B4 = 6 * alpha**2 + b2 * alpha + b4 + B6 = 4 * alpha**3 + b2 * alpha**2 + 2 * b4 * alpha + b6 + B6_sqr = B6 * B6 + B8 = 3 * alpha**4 + b2 * alpha**3 + 3 * b4 * alpha**2 + 3 * b6 * alpha + b8 - T = 2*beta + a1*alpha + a3 + T = 2 * beta + a1 * alpha + a3 # make a list of disjoint intervals [a[i], b[i]) such that we need to # compute g(k) for all a[i] <= k <= b[i] for each i @@ -539,11 +535,10 @@ def _multiply_point(E, R, P, m): interval = (m - 2, m + 3) while interval[0] < interval[1]: intervals.append(interval) - interval = max((interval[0] - 3) >> 1, 0), \ - min((interval[1] + 5) >> 1, interval[0]) + interval = max((interval[0] - 3) >> 1, 0), min((interval[1] + 5) >> 1, interval[0]) # now walk through list and compute g(k) - g = {0 : R(0), 1 : R(1), 2 : R(-1), 3 : B8, 4 : B6**2 - B4*B8} + g = {0: R(0), 1: R(1), 2: R(-1), 3: B8, 4: B6**2 - B4 * B8} for i in reversed(intervals): k = i[0] while k < i[1]: @@ -551,27 +546,27 @@ def _multiply_point(E, R, P, m): j = k >> 1 if k & 1: t1 = g[j] - t2 = g[j+1] - prod1 = g[j+2] * t1*t1*t1 - prod2 = g[j-1] * t2*t2*t2 + t2 = g[j + 1] + prod1 = g[j + 2] * t1 * t1 * t1 + prod2 = g[j - 1] * t2 * t2 * t2 g[k] = prod1 - B6_sqr * prod2 if j & 1 else B6_sqr * prod1 - prod2 else: - t1 = g[j-1] - t2 = g[j+1] - g[k] = g[j] * (g[j-2] * t2*t2 - g[j+2] * t1*t1) + t1 = g[j - 1] + t2 = g[j + 1] + g[k] = g[j] * (g[j - 2] * t2 * t2 - g[j + 2] * t1 * t1) k = k + 1 if m & 1: psi_m = g[m] - psi_m_m1 = g[m-1] * T - psi_m_p1 = g[m+1] * T + psi_m_m1 = g[m - 1] * T + psi_m_p1 = g[m + 1] * T else: psi_m = g[m] * T - psi_m_m1 = g[m-1] - psi_m_p1 = g[m+1] + psi_m_m1 = g[m - 1] + psi_m_p1 = g[m + 1] theta = alpha * psi_m * psi_m - psi_m_m1 * psi_m_p1 - t1 = g[m-2] * g[m+1] * g[m+1] - g[m+2] * g[m-1] * g[m-1] + t1 = g[m - 2] * g[m + 1] * g[m + 1] - g[m + 2] * g[m - 1] * g[m - 1] if m & 1: t1 = t1 * T omega = (t1 + (a1 * theta + a3 * psi_m * psi_m) * psi_m) / -2 @@ -626,8 +621,7 @@ def _multiple_to_make_good_reduction(E): 4 """ if not E.is_integral(): - st = ("This only implemented for integral models. " - "Please change the model first.") + st = "This only implemented for integral models. " "Please change the model first." raise NotImplementedError(st) if E.is_minimal(): n2 = LCM(E.tamagawa_numbers()) @@ -641,15 +635,15 @@ def _multiple_to_make_good_reduction(E): for p in ps: np = u.valuation(p) if Emin.discriminant() % p != 0: - li.append(Emin.Np(p) * p**(np-1)) + li.append(Emin.Np(p) * p ** (np - 1)) elif Emin.has_additive_reduction(p): li.append(E.tamagawa_number(p) * p**np) elif E.has_split_multiplicative_reduction(p): - li.append(E.tamagawa_number(p) * (p-1) * p**(np-1)) - else: # non split - li.append(E.tamagawa_number(p) * (p+1) * p**(np-1)) + li.append(E.tamagawa_number(p) * (p - 1) * p ** (np - 1)) + else: # non split + li.append(E.tamagawa_number(p) * (p + 1) * p ** (np - 1)) otherbad = Integer(Emin.discriminant()).prime_divisors() - otherbad = [p for p in otherbad if u % p != 0 ] + otherbad = [p for p in otherbad if u % p != 0] li += [E.tamagawa_number(p) for p in otherbad] n2 = LCM(li) return n2 @@ -788,7 +782,7 @@ def padic_height(self, p, prec=20, sigma=None, check_hypotheses=True): if not p.is_prime(): raise ValueError("p = (%s) must be prime" % p) if p == 2: - raise ValueError("p must be odd") # todo + raise ValueError("p must be odd") # todo if self.conductor() % (p**2) == 0: raise ArithmeticError("p must be a semi-stable prime") @@ -812,14 +806,14 @@ def padic_height(self, p, prec=20, sigma=None, check_hypotheses=True): n = LCM(n1, n2) m = int(n / n2) - adjusted_prec = prec + 2 * valuation(n, p) # this is M' - R = Integers(p ** adjusted_prec) + adjusted_prec = prec + 2 * valuation(n, p) # this is M' + R = Integers(p**adjusted_prec) if sigma is None: sigma = self.padic_sigma(p, adjusted_prec, check_hypotheses=False) # K is the field for the final result - K = Qp(p, prec=adjusted_prec-1) + K = Qp(p, prec=adjusted_prec - 1) E = self def height(P, check=True): @@ -827,8 +821,7 @@ def height(P, check=True): return K(0) if check: - assert P.curve() == E, "the point P must lie on the curve " \ - "from which the height function was created" + assert P.curve() == E, "the point P must lie on the curve " "from which the height function was created" Q = n2 * P alpha, beta, d = _multiply_point(E, R, Q, m) @@ -846,14 +839,13 @@ def height(P, check=True): total = (-alpha / beta) * total L = Qp(p, prec=adjusted_prec) - total = L(total.lift(), adjusted_prec) # yuck... get rid of this lift! + total = L(total.lift(), adjusted_prec) # yuck... get rid of this lift! # changed sign to make it correct for p-adic bsd answer = -total.log() * 2 / n**2 if check: - assert answer.precision_absolute() >= prec, "we should have got an " \ - "answer with precision at least prec, but we didn't." + assert answer.precision_absolute() >= prec, "we should have got an " "answer with precision at least prec, but we didn't." return K(answer) # (man... I love python's local function definitions...) @@ -939,7 +931,7 @@ def padic_height_via_multiply(self, p, prec=20, E2=None, check_hypotheses=True): if not p.is_prime(): raise ValueError("p = (%s) must be prime" % p) if p == 2: - raise ValueError("p must be odd") # todo + raise ValueError("p must be odd") # todo if self.conductor() % p == 0: raise ArithmeticError("must have good reduction at p") if self.ap(p) % p == 0: @@ -958,13 +950,13 @@ def padic_height_via_multiply(self, p, prec=20, E2=None, check_hypotheses=True): lamb = int(math.floor(math.sqrt(prec))) - adjusted_prec = prec + 2 * valuation(n, p) # this is M' - R = Integers(p ** (adjusted_prec + 2*lamb)) + adjusted_prec = prec + 2 * valuation(n, p) # this is M' + R = Integers(p ** (adjusted_prec + 2 * lamb)) sigma = self.padic_sigma_truncated(p, N=adjusted_prec, E2=E2, lamb=lamb) # K is the field for the final result - K = Qp(p, prec=adjusted_prec-1) + K = Qp(p, prec=adjusted_prec - 1) E = self def height(P, check=True): @@ -972,8 +964,7 @@ def height(P, check=True): return K(0) if check: - assert P.curve() == E, "the point P must lie on the curve " \ - "from which the height function was created" + assert P.curve() == E, "the point P must lie on the curve " "from which the height function was created" Q = n2 * P alpha, beta, d = _multiply_point(E, R, Q, m * p**lamb) @@ -990,15 +981,14 @@ def height(P, check=True): t_power = t_power * t total = (-alpha / beta) * total - L = Qp(p, prec=adjusted_prec + 2*lamb) - total = L(total.lift(), adjusted_prec + 2*lamb) + L = Qp(p, prec=adjusted_prec + 2 * lamb) + total = L(total.lift(), adjusted_prec + 2 * lamb) # changed sign to make it correct for p-adic bsd - answer = -total.log() * 2 / (n * p**lamb)**2 + answer = -total.log() * 2 / (n * p**lamb) ** 2 if check: - assert answer.precision_absolute() >= prec, "we should have got an " \ - "answer with precision at least prec, but we didn't." + assert answer.precision_absolute() >= prec, "we should have got an " "answer with precision at least prec, but we didn't." return K(answer) # (man... I love python's local function definitions...) @@ -1137,32 +1127,31 @@ def padic_sigma(self, p, N=20, E2=None, check=False, check_hypotheses=True): if N == 2: # return t + a_1/2 t^2 + O(t^3) K = Qp(p, 3) - return PowerSeriesRing(K, "t")([K(0), K(1, 2), - K(self.a1()/2, 1)], prec=3) + return PowerSeriesRing(K, "t")([K(0), K(1, 2), K(self.a1() / 2, 1)], prec=3) if self.discriminant().valuation(p) != 0: raise NotImplementedError("equation of curve must be minimal at p") if E2 is None: - E2 = self.padic_E2(p, N-2, check_hypotheses=False) - elif E2.precision_absolute() < N-2: + E2 = self.padic_E2(p, N - 2, check_hypotheses=False) + elif E2.precision_absolute() < N - 2: raise ValueError("supplied E2 has insufficient precision") QQt = LaurentSeriesRing(RationalField(), "x") - R = Integers(p**(N-2)) + R = Integers(p ** (N - 2)) X = self.change_ring(R) - c = (X.a1()**2 + 4*X.a2() - R(E2)) / 12 + c = (X.a1() ** 2 + 4 * X.a2() - R(E2)) / 12 - f = X.formal_group().differential(N+2) # f = 1 + ... + O(t^{N+2}) - x = X.formal_group().x(N) # x = t^{-2} + ... + O(t^N) + f = X.formal_group().differential(N + 2) # f = 1 + ... + O(t^{N+2}) + x = X.formal_group().x(N) # x = t^{-2} + ... + O(t^N) Rt = x.parent() A = (x + c) * f # do integral over QQ, to avoid divisions by p A = Rt(QQt(A).integral()) - A = (-X.a1()/2 - A) * f + A = (-X.a1() / 2 - A) * f # Convert to a power series and remove the -1/x term. # Also we artificially bump up the accuracy from N-2 to N-1 digits; @@ -1171,9 +1160,9 @@ def padic_sigma(self, p, N=20, E2=None, check=False, check_hypotheses=True): assert A.valuation() == -1 and A[-1] == 1 A = A - A.parent().gen() ** (-1) A = A.power_series().list() - R = Integers(p**(N-1)) + R = Integers(p ** (N - 1)) A = [R(u) for u in A] - A[0] = self.change_ring(R).a1()/2 # fix constant term + A[0] = self.change_ring(R).a1() / 2 # fix constant term A = PowerSeriesRing(R, "x")(A, len(A)) theta = _brent(A, p, N) @@ -1186,37 +1175,36 @@ def padic_sigma(self, p, N=20, E2=None, check=False, check_hypotheses=True): # for p-adic height purposes anyway] K = Qp(p, N + 1) - sigma = sigma.padded_list(N+1) + sigma = sigma.padded_list(N + 1) sigma[0] = K(0, N + 1) sigma[1] = K(1, N) - for n in range(2, N+1): + for n in range(2, N + 1): sigma[n] = K(sigma[n].lift(), N - n + 1) - S = PowerSeriesRing(K, "t", N+1) - sigma = S(sigma, N+1) + S = PowerSeriesRing(K, "t", N + 1) + sigma = S(sigma, N + 1) # if requested, check that sigma satisfies the appropriate # differential equation if check: R = Integers(p**N) X = self.change_ring(R) - x = X.formal_group().x(N+5) # few extra terms for safety - f = X.formal_group().differential(N+5) - c = (X.a1()**2 + 4*X.a2() - R(E2)) / 12 + x = X.formal_group().x(N + 5) # few extra terms for safety + f = X.formal_group().differential(N + 5) + c = (X.a1() ** 2 + 4 * X.a2() - R(E2)) / 12 # convert sigma to be over Z/p^N s = f.parent()(sigma) - sinv = s**(-1) - finv = f**(-1) + sinv = s ** (-1) + finv = f ** (-1) # apply differential equation temp = (s.derivative() * sinv * finv).derivative() * finv + c + x # coefficient of t^k in the result should be zero mod p^(N-k-2) - for k in range(N-2): - assert temp[k].lift().valuation(p) >= N - k - 2, \ - "sigma correctness check failed!" + for k in range(N - 2): + assert temp[k].lift().valuation(p) >= N - k - 2, "sigma correctness check failed!" return sigma @@ -1314,38 +1302,37 @@ def padic_sigma_truncated(self, p, N=20, lamb=0, E2=None, check_hypotheses=True) if N == 2: # return t + a_1/2 t^2 + O(t^3) - K = Qp(p, 3*(lamb+1)) - return PowerSeriesRing(K, "t")([K(0), K(1, 2*(lamb+1)), - K(self.a1()/2, lamb+1)], prec=3) + K = Qp(p, 3 * (lamb + 1)) + return PowerSeriesRing(K, "t")([K(0), K(1, 2 * (lamb + 1)), K(self.a1() / 2, lamb + 1)], prec=3) if self.discriminant().valuation(p) != 0: raise NotImplementedError("equation of curve must be minimal at p") if E2 is None: - E2 = self.padic_E2(p, N-2, check_hypotheses=False) - elif E2.precision_absolute() < N-2: + E2 = self.padic_E2(p, N - 2, check_hypotheses=False) + elif E2.precision_absolute() < N - 2: raise ValueError("supplied E2 has insufficient precision") # The main part of the algorithm is exactly the same as # for padic_sigma(), but we truncate all the series earlier. # Want the answer O(t^(trunc+1)) instead of O(t^(N+1)) like in padic_sigma(). - trunc = (Integer(N-2) / (lamb + 1)).ceil() + 2 + trunc = (Integer(N - 2) / (lamb + 1)).ceil() + 2 QQt = LaurentSeriesRing(RationalField(), "x") - R = Integers(p**(N-2)) + R = Integers(p ** (N - 2)) X = self.change_ring(R) - c = (X.a1()**2 + 4*X.a2() - R(E2)) / 12 + c = (X.a1() ** 2 + 4 * X.a2() - R(E2)) / 12 - f = X.formal_group().differential(trunc+2) # f = 1 + ... + O(t^{trunc+2}) - x = X.formal_group().x(trunc) # x = t^{-2} + ... + O(t^trunc) + f = X.formal_group().differential(trunc + 2) # f = 1 + ... + O(t^{trunc+2}) + x = X.formal_group().x(trunc) # x = t^{-2} + ... + O(t^trunc) Rt = x.parent() A = (x + c) * f # do integral over QQ, to avoid divisions by p A = Rt(QQt(A).integral()) - A = (-X.a1()/2 - A) * f + A = (-X.a1() / 2 - A) * f # Convert to a power series and remove the -1/x term. # Also we artificially bump up the accuracy from N-2 to N-1+lamb digits; @@ -1354,9 +1341,9 @@ def padic_sigma_truncated(self, p, N=20, lamb=0, E2=None, check_hypotheses=True) assert A.valuation() == -1 and A[-1] == 1 A = A - A.parent().gen() ** (-1) A = A.power_series().list() - R = Integers(p**(N-1+lamb)) + R = Integers(p ** (N - 1 + lamb)) A = [R(u) for u in A] - A[0] = self.change_ring(R).a1()/2 # fix constant term + A[0] = self.change_ring(R).a1() / 2 # fix constant term A = PowerSeriesRing(R, "x")(A, len(A)) theta = _brent(A, p, trunc) @@ -1364,17 +1351,17 @@ def padic_sigma_truncated(self, p, N=20, lamb=0, E2=None, check_hypotheses=True) # Convert the answer to power series over p-adics; drop the precision # of the t^j coefficient to p^{N - 2 + (3 - j)(lamb + 1)}). - K = Qp(p, N - 2 + 3*(lamb+1)) + K = Qp(p, N - 2 + 3 * (lamb + 1)) - sigma = sigma.padded_list(trunc+1) + sigma = sigma.padded_list(trunc + 1) - sigma[0] = K(0, N - 2 + 3*(lamb+1)) - sigma[1] = K(1, N - 2 + 2*(lamb+1)) - for j in range(2, trunc+1): - sigma[j] = K(sigma[j].lift(), N - 2 + (3 - j)*(lamb+1)) + sigma[0] = K(0, N - 2 + 3 * (lamb + 1)) + sigma[1] = K(1, N - 2 + 2 * (lamb + 1)) + for j in range(2, trunc + 1): + sigma[j] = K(sigma[j].lift(), N - 2 + (3 - j) * (lamb + 1)) S = PowerSeriesRing(K, "t", trunc + 1) - sigma = S(sigma, trunc+1) + sigma = S(sigma, trunc + 1) return sigma @@ -1545,8 +1532,7 @@ def padic_E2(self, p, prec=20, check=False, check_hypotheses=True, algorithm='au # todo: think about the sign of this. Is it correct? output_ring = Qp(p, prec) - E2_of_X = output_ring( (-12 * frob_p_n[0,1] / frob_p_n[1,1]).lift() ) \ - + O(p**prec) + E2_of_X = output_ring((-12 * frob_p_n[0, 1] / frob_p_n[1, 1]).lift()) + O(p**prec) # Take into account the coordinate change. fudge_factor = (X.discriminant() / self.discriminant()).nth_root(6) @@ -1629,8 +1615,8 @@ def matrix_of_frobenius(self, p, prec=20, check=False, check_hypotheses=True, al p = __check_padic_hypotheses(self, p) if algorithm == "auto": - algorithm = "standard" if p < 6*prec else "sqrtp" - elif algorithm == "sqrtp" and p < 6*prec: + algorithm = "standard" if p < 6 * prec else "sqrtp" + elif algorithm == "sqrtp" and p < 6 * prec: raise ValueError("sqrtp algorithm is only available when p > 6*prec") if algorithm not in ["standard", "sqrtp"]: @@ -1640,8 +1626,9 @@ def matrix_of_frobenius(self, p, prec=20, check=False, check_hypotheses=True, al # and call matrix of frobenius on it if p == 3: from sage.schemes.hyperelliptic_curves.constructor import HyperellipticCurve - f,g = self.hyperelliptic_polynomials() - return HyperellipticCurve(f + (g/2)**2).matrix_of_frobenius(p,prec) + + f, g = self.hyperelliptic_polynomials() + return HyperellipticCurve(f + (g / 2) ** 2).matrix_of_frobenius(p, prec) # To run matrix_of_frobenius(), we need to have the equation in the # form y^2 = x^3 + ax + b, whose discriminant is invertible mod p. @@ -1660,9 +1647,7 @@ def matrix_of_frobenius(self, p, prec=20, check=False, check_hypotheses=True, al # TODO change the basis back to the original equation. X = self.minimal_model().short_weierstrass_model() - assert X.discriminant().valuation(p) == 0, "Something's gone wrong. " \ - "The discriminant of the Weierstrass model should be a unit " \ - " at p." + assert X.discriminant().valuation(p) == 0, "Something's gone wrong. " "The discriminant of the Weierstrass model should be a unit " " at p." if algorithm == "standard": # Need to increase precision a little to compensate for precision @@ -1679,10 +1664,9 @@ def matrix_of_frobenius(self, p, prec=20, check=False, check_hypotheses=True, al R, x = PolynomialRing(base_ring, 'x').objgen() Q = x**3 + base_ring(X.a4()) * x + base_ring(X.a6()) - frob_p = sage.schemes.hyperelliptic_curves.monsky_washnitzer.matrix_of_frobenius( - Q, p, adjusted_prec, trace) + frob_p = sage.schemes.hyperelliptic_curves.monsky_washnitzer.matrix_of_frobenius(Q, p, adjusted_prec, trace) - else: # algorithm == "sqrtp" + else: # algorithm == "sqrtp" p_to_prec = p**prec R = PolynomialRing(Integers(), "x") Q = R([X.a6() % p_to_prec, X.a4() % p_to_prec, 0, 1]) @@ -1696,9 +1680,7 @@ def matrix_of_frobenius(self, p, prec=20, check=False, check_hypotheses=True, al if check: trace_of_frobenius = frob_p.trace().lift() % p**prec correct_trace = self.ap(p) % p**prec - assert trace_of_frobenius == correct_trace, \ - "Consistency check failed! (correct = %s, actual = %s)" % \ - (correct_trace, trace_of_frobenius) + assert trace_of_frobenius == correct_trace, "Consistency check failed! (correct = %s, actual = %s)" % (correct_trace, trace_of_frobenius) return frob_p.change_ring(Zp(p, prec)) @@ -1758,7 +1740,7 @@ def _brent(F, p, N): ....: assert err[i].lift().valuation(p) >= (N - i), \ ....: "incorrect precision output" """ - Rx = F.parent() # Rx = power series ring over Z/p^{N-1} Z + Rx = F.parent() # Rx = power series ring over Z/p^{N-1} Z Qx = PowerSeriesRing(RationalField(), "x") # initial approximation: diff --git a/src/sage/schemes/elliptic_curves/period_lattice.py b/src/sage/schemes/elliptic_curves/period_lattice.py index 2dc6029eb39..2eaa5b74ee5 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice.py +++ b/src/sage/schemes/elliptic_curves/period_lattice.py @@ -129,6 +129,7 @@ class PeriodLattice(FreeModule_generic_pid): """ The class for the period lattice of an algebraic variety. """ + pass @@ -277,14 +278,14 @@ def __init__(self, E, embedding=None): self.f2 = self.Ebar.two_division_polynomial() else: self.f2 = self.E.two_division_polynomial() - if self.real_flag == 1: # positive discriminant + if self.real_flag == 1: # positive discriminant self._ei = self.f2.roots(AA if self._is_exact else K, multiplicities=False) self._ei.sort() # e1 < e2 < e3 e1, e2, e3 = self._ei - elif self.real_flag == -1: # negative discriminant + elif self.real_flag == -1: # negative discriminant self._ei = self.f2.roots(QQbar if self._is_exact else ComplexField(K.precision()), multiplicities=False) self._ei = sorted(self._ei, key=lambda z: z.imag()) - e1, e3, e2 = self._ei # so e3 is real + e1, e3, e2 = self._ei # so e3 is real if self._is_exact: e3 = AA(e3) self._ei = [e1, e2, e3] @@ -295,7 +296,7 @@ def __init__(self, E, embedding=None): # The quantities sqrt(e_i-e_j) are cached (as elements of # QQbar) to be used in period computations: - self._abc = (e3-e1).sqrt(), (e3-e2).sqrt(), (e2-e1).sqrt() + self._abc = (e3 - e1).sqrt(), (e3 - e2).sqrt(), (e2 - e1).sqrt() PeriodLattice.__init__(self, base_ring=ZZ, rank=2, degree=1, sparse=False) @@ -413,7 +414,7 @@ def __call__(self, P, prec=None): sage: L.real_period() / L(P) 5.00000000000000 """ - return self.elliptic_logarithm(P,prec) + return self.elliptic_logarithm(P, prec) @cached_method def basis(self, prec=None, algorithm='sage'): @@ -649,7 +650,7 @@ def tau(self, prec=None, algorithm='sage'): True """ w1, w2 = self.normalised_basis(prec=prec, algorithm=algorithm) - return w1/w2 + return w1 / w2 @cached_method def _compute_default_prec(self): @@ -718,18 +719,18 @@ def _compute_periods_real(self, prec=None, algorithm='sage'): pi = R.pi() # Up to now everything has been exact in AA or QQbar (if self._is_exact), # but now we must go transcendental. Only now is the desired precision used! - if self.real_flag == 1: # positive discriminant + if self.real_flag == 1: # positive discriminant a, b, c = (R(x) for x in self._abc) - w1 = R(pi/a.agm(b)) # least real period - w2 = C(0,pi/a.agm(c)) # least pure imaginary period + w1 = R(pi / a.agm(b)) # least real period + w2 = C(0, pi / a.agm(c)) # least pure imaginary period else: a = C(self._abc[0]) x, y, r = a.real().abs(), a.imag().abs(), a.abs() - w1 = R(pi/r.agm(x)) # least real period - w2 = R(pi/r.agm(y)) # least pure imaginary period /i - w2 = C(w1,w2)/2 + w1 = R(pi / r.agm(x)) # least real period + w2 = R(pi / r.agm(y)) # least pure imaginary period /i + w2 = C(w1, w2) / 2 - return (w1,w2) + return (w1, w2) @cached_method def _compute_periods_complex(self, prec=None, normalise=True): @@ -792,18 +793,18 @@ def _compute_periods_complex(self, prec=None, normalise=True): # but now we must go transcendental. Only now is the desired precision used! pi = C.pi() a, b, c = (C(x) for x in self._abc) - if (a+b).abs() < (a-b).abs(): + if (a + b).abs() < (a - b).abs(): b = -b - if (a+c).abs() < (a-c).abs(): + if (a + c).abs() < (a - c).abs(): c = -c - w1 = pi/a.agm(b) - w2 = pi*C.gen()/a.agm(c) - if (w1/w2).imag() < 0: + w1 = pi / a.agm(b) + w2 = pi * C.gen() / a.agm(c) + if (w1 / w2).imag() < 0: w2 = -w2 if normalise: - w1w2, mat = normalise_periods(w1,w2) + w1w2, mat = normalise_periods(w1, w2) return w1w2 - return (w1,w2) + return (w1, w2) def is_real(self): r""" @@ -912,7 +913,7 @@ def real_period(self, prec=None, algorithm='sage'): 3.81452977217854509 """ if self.is_real(): - return self.basis(prec,algorithm)[0] + return self.basis(prec, algorithm)[0] raise RuntimeError("Not defined for non-real lattices.") def omega(self, prec=None, bsd_normalise=False): @@ -1059,10 +1060,10 @@ def basis_matrix(self, prec=None, normalised=False): if normalised: return Matrix([list(w) for w in self.normalised_basis(prec)]) - w1,w2 = self.basis(prec) + w1, w2 = self.basis(prec) if self.is_real(): - return Matrix([[w1,0],list(w2)]) - return Matrix([list(w) for w in (w1,w2)]) + return Matrix([[w1, 0], list(w2)]) + return Matrix([list(w) for w in (w1, w2)]) def complex_area(self, prec=None): """ @@ -1092,8 +1093,8 @@ def complex_area(self, prec=None): sage: [E.period_lattice(emb).complex_area() for emb in embs] [6.02796894766694, 6.02796894766694, 5.11329270448345] """ - w1,w2 = self.basis(prec) - return (w1*w2.conjugate()).imag().abs() + w1, w2 = self.basis(prec) + return (w1 * w2.conjugate()).imag().abs() def sigma(self, z, prec=None, flag=0): r""" @@ -1192,8 +1193,8 @@ def is_approximate(self): True """ from sage.misc.superseded import deprecation - deprecation(39212, "The attribute is_approximate for period lattice is " - "deprecated, use self.curve().is_exact() instead.") + + deprecation(39212, "The attribute is_approximate for period lattice is " "deprecated, use self.curve().is_exact() instead.") return not self._is_exact def ei(self): @@ -1297,12 +1298,13 @@ def coordinates(self, z, rounding=None): prec = C.precision() from sage.matrix.constructor import Matrix from sage.modules.free_module_element import vector + if self.real_flag: w1, w2 = self.basis(prec) - M = Matrix([[w1, 0], list(w2)])**(-1) + M = Matrix([[w1, 0], list(w2)]) ** (-1) else: w1, w2 = self.normalised_basis(prec) - M = Matrix([list(w1), list(w2)])**(-1) + M = Matrix([list(w1), list(w2)]) ** (-1) u, v = vector(z) * M # Now z = u*w1+v*w2 if rounding == 'round': @@ -1363,7 +1365,7 @@ def reduce(self, z): else: w1, w2 = self.normalised_basis(prec) u, v = self.coordinates(z, rounding='floor') - z = z-u*w1-v*w2 + z = z - u * w1 - v * w2 # Final adjustments for the real case. @@ -1374,10 +1376,10 @@ def reduce(self, z): return z if self.real_flag == -1: k = (z.imag() / w2.imag()).round() - z = z-k*w2 + z = z - k * w2 return C(z.real(), 0) - if ((2*z.imag()/w2.imag()).round()) % 2: + if ((2 * z.imag() / w2.imag()).round()) % 2: return C(z.real(), w2.imag() / 2) return C(z.real(), 0) @@ -1484,23 +1486,23 @@ def e_log_RC(self, xP, yP, prec=None, reduce=True): R = RealField(prec2) C = ComplexField(prec2) - e1,e2,e3 = self._ei - a1,a2,a3 = (self.embedding(a) for a in self.E.ainvs()[:3]) + e1, e2, e3 = self._ei + a1, a2, a3 = (self.embedding(a) for a in self.E.ainvs()[:3]) - wP = 2*yP+a1*xP+a3 + wP = 2 * yP + a1 * xP + a3 # We treat the case of 2-torsion points separately. (Note # that Cohen's algorithm does not handle these properly.) if wP.is_zero(): # 2-torsion treated separately - w1,w2 = self._compute_periods_complex(prec,normalise=False) + w1, w2 = self._compute_periods_complex(prec, normalise=False) if xP == e1: - z = w2/2 + z = w2 / 2 else: if xP == e3: - z = w1/2 + z = w1 / 2 else: - z = (w1+w2)/2 + z = (w1 + w2) / 2 if reduce: z = self.reduce(z) return z @@ -1517,63 +1519,63 @@ def e_log_RC(self, xP, yP, prec=None, reduce=True): if self.real_flag == 0: # complex case - a = C((e1-e3).sqrt()) - b = C((e1-e2).sqrt()) - if (a+b).abs() < (a-b).abs(): + a = C((e1 - e3).sqrt()) + b = C((e1 - e2).sqrt()) + if (a + b).abs() < (a - b).abs(): b = -b - r = C(((xP-e3)/(xP-e2)).sqrt()) + r = C(((xP - e3) / (xP - e2)).sqrt()) if r.real() < 0: r = -r - t = -C(wP)/(2*r*(xP-e2)) + t = -C(wP) / (2 * r * (xP - e2)) # eps controls the end of the loop. Since we aim at a target # precision of prec bits, eps = 2^(-prec) is enough. eps = R(1) >> prec while True: - s = b*r+a - a, b = (a+b)/2, (a*b).sqrt() - if (a+b).abs() < (a-b).abs(): + s = b * r + a + a, b = (a + b) / 2, (a * b).sqrt() + if (a + b).abs() < (a - b).abs(): b = -b - r = (a*(r+1)/s).sqrt() - if (r.abs()-1).abs() < eps: + r = (a * (r + 1) / s).sqrt() + if (r.abs() - 1).abs() < eps: break if r.real() < 0: r = -r t *= r - z = ((a/t).arctan())/a + z = ((a / t).arctan()) / a z = ComplexField(prec)(z) if reduce: z = self.reduce(z) return z - if self.real_flag == -1: # real, connected case - z = C(self._abc[0]) # sqrt(e3-e1) + if self.real_flag == -1: # real, connected case + z = C(self._abc[0]) # sqrt(e3-e1) a, y, b = z.real(), z.imag(), z.abs() - uv = (xP-e1).sqrt() + uv = (xP - e1).sqrt() u, v = uv.real().abs(), uv.imag().abs() - r = (u*a/(u*a+v*y)).sqrt() - t = -r*R(wP)/(2*(u**2+v**2)) + r = (u * a / (u * a + v * y)).sqrt() + t = -r * R(wP) / (2 * (u**2 + v**2)) on_egg = False - else: # real, disconnected case - a = R(e3-e1).sqrt() - b = R(e3-e2).sqrt() - if (a+b).abs() < (a-b).abs(): + else: # real, disconnected case + a = R(e3 - e1).sqrt() + b = R(e3 - e2).sqrt() + if (a + b).abs() < (a - b).abs(): b = -b - on_egg = (xP < e3) + on_egg = xP < e3 if on_egg: - r = a/R(e3-xP).sqrt() - t = r*R(wP)/(2*R(xP-e1)) + r = a / R(e3 - xP).sqrt() + t = r * R(wP) / (2 * R(xP - e1)) else: - r = R((xP-e1)/(xP-e2)).sqrt() - t = -R(wP)/(2*r*R(xP-e2)) + r = R((xP - e1) / (xP - e2)).sqrt() + t = -R(wP) / (2 * r * R(xP - e2)) # eps controls the end of the loop. Since we aim at a target # precision of prec bits, eps = 2^(-prec) is enough. eps = R(1) >> prec while True: - s = b*r+a - a, b = (a+b)/2, (a*b).sqrt() - r = (a*(r+1)/s).sqrt() - if (r-1).abs() < eps: + s = b * r + a + a, b = (a + b) / 2, (a * b).sqrt() + r = (a * (r + 1) / s).sqrt() + if (r - 1).abs() < eps: break t *= r z = ((a / t).arctan()) / a @@ -2018,8 +2020,8 @@ def elliptic_exponential(self, z, to_curve=True): # test for the point at infinity: - eps = (C(2)**(-0.8*prec)).real() ## to test integrality w.r.t. lattice within 20% - if all((t.round()-t).abs() < eps for t in self.coordinates(z)): + eps = (C(2) ** (-0.8 * prec)).real() ## to test integrality w.r.t. lattice within 20% + if all((t.round() - t).abs() < eps for t in self.coordinates(z)): K = z.parent() if to_curve: return self.curve().change_ring(K)(0) @@ -2094,18 +2096,18 @@ def reduce_tau(tau): c, d = b, a k = tau.real().round() tau -= k - a -= k*c - b -= k*d + a -= k * c + b -= k * d while tau.abs() < 0.999: - tau = -1/tau + tau = -1 / tau a, b, c, d = c, d, -a, -b k = tau.real().round() tau -= k - a -= k*c - b -= k*d - assert a*d-b*c == 1 + a -= k * c + b -= k * d + assert a * d - b * c == 1 assert tau.abs() >= 0.999 and tau.real().abs() <= 0.5 - return tau, [a,b,c,d] + return tau, [a, b, c, d] def normalise_periods(w1, w2): @@ -2143,7 +2145,7 @@ def normalise_periods(w1, w2): sage: a*d-b*c # note change of orientation -1 """ - tau = w1/w2 + tau = w1 / w2 s = +1 if tau.imag() < 0: w2 = -w2 @@ -2152,8 +2154,8 @@ def normalise_periods(w1, w2): tau, abcd = reduce_tau(tau) a, b, c, d = abcd if s < 0: - abcd = (a,-b,c,-d) - return (a*w1+b*w2,c*w1+d*w2), abcd + abcd = (a, -b, c, -d) + return (a * w1 + b * w2, c * w1 + d * w2), abcd def extended_agm_iteration(a, b, c): @@ -2186,7 +2188,7 @@ def extended_agm_iteration(a, b, c): ... ValueError: values must be real or complex numbers """ - if not isinstance(a, (RealNumber,ComplexNumber)): + if not isinstance(a, (RealNumber, ComplexNumber)): raise ValueError("values must be real or complex numbers") eps = a.parent().one().real() >> (a.parent().precision() - 10) while True: diff --git a/src/sage/schemes/elliptic_curves/saturation.py b/src/sage/schemes/elliptic_curves/saturation.py index cbe99786474..a069c0e6ecf 100644 --- a/src/sage/schemes/elliptic_curves/saturation.py +++ b/src/sage/schemes/elliptic_curves/saturation.py @@ -37,7 +37,7 @@ - John Cremona """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2017 Robert Bradshaw # John Cremona # William Stein @@ -47,7 +47,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.integer_ring import ZZ @@ -86,7 +86,7 @@ def reduce_mod_q(x, amodq): Fq = amodq.parent() try: return x.lift().change_ring(Fq)(amodq) - except AttributeError: # in case x is in QQ + except AttributeError: # in case x is in QQ return Fq(x) @@ -106,6 +106,7 @@ class EllipticCurveSaturator(SageObject): may access the data via methods of the EllipticCurve classes. """ + def __init__(self, E, verbose=False): r""" Initialize the saturator. @@ -123,6 +124,7 @@ def __init__(self, E, verbose=False): if K.absolute_degree() == 1: from sage.rings.rational_field import QQ from sage.rings.polynomial.polynomial_ring import polygen + self._Kpol = polygen(QQ) else: self._Kpol = K.defining_polynomial() @@ -201,6 +203,7 @@ def add_reductions(self, q): if q.divides(self._N) or q.divides(self._D): return from sage.schemes.elliptic_curves.constructor import EllipticCurve + for amodq in sorted(self._Kpol.roots(GF(q), multiplicities=False)): Eq = EllipticCurve([reduce_mod_q(ai, amodq) for ai in self._curve.ainvs()]) nq = Eq.cardinality() @@ -271,14 +274,14 @@ def full_p_saturation(self, Plist, p): n = len(Plist) # number of points supplied & to be returned Plist = Plist + [T for T in self._torsion_gens if p.divides(T.order())] - nx = len(Plist) # number of points including relevant torsion - extra_torsion = nx-n + nx = len(Plist) # number of points including relevant torsion + extra_torsion = nx - n if extra_torsion: if verbose: - print("Adding {} torsion generators before {}-saturation".format(extra_torsion,p)) + print("Adding {} torsion generators before {}-saturation".format(extra_torsion, p)) res = self.p_saturation(Plist, p) - while res: # res is either False or (i, newP) + while res: # res is either False or (i, newP) exponent += 1 Plist[res[0]] = res[1] res = self.p_saturation(Plist, p) @@ -291,7 +294,7 @@ def full_p_saturation(self, Plist, p): if verbose: if exponent: - print("Points were not %s-saturated, exponent was %s" % (p,exponent)) + print("Points were not %s-saturated, exponent was %s" % (p, exponent)) else: print("Points were %s-saturated" % p) @@ -435,16 +438,16 @@ def p_saturation(self, Plist, p, sieve=True): from sage.groups.generic import multiples from sage.schemes.projective.projective_space import ProjectiveSpace - mults = [list(multiples(P, p)) for P in Plist[:-1]] + [list(multiples(Plist[-1],2))] + mults = [list(multiples(P, p)) for P in Plist[:-1]] + [list(multiples(Plist[-1], 2))] E0 = E(0) - for v in ProjectiveSpace(GF(p),n-1): # an iterator + for v in ProjectiveSpace(GF(p), n - 1): # an iterator w = tuple(int(x) for x in v) - P = sum([m[c] for m,c in zip(mults,w)],E0) + P = sum([m[c] for m, c in zip(mults, w)], E0) pts = P.division_points(p) if pts: if verbose: - print(" points not saturated at {}, increasing index by {}".format(p,p)) + print(" points not saturated at {}, increasing index by {}".format(p, p)) # w will certainly have a coordinate equal to 1 return (w.index(1), pts[0]) # we only get here if no linear combination is divisible by p, @@ -494,15 +497,15 @@ def p_saturation(self, Plist, p, sieve=True): for q in Primes(): if any(q.divides(m) for m in avoid): continue - if cm_test and not p.divides(q-1): + if cm_test and not p.divides(q - 1): continue - self.add_reductions(q) # does nothing if key q is already there + self.add_reductions(q) # does nothing if key q is already there for amodq in self._reductions[q]: (nq, Eq) = self._reductions[q][amodq] if not p.divides(nq): continue if verbose: - print("E has %s-torsion over %s, projecting points" % (p,GF(q))) + print("E has %s-torsion over %s, projecting points" % (p, GF(q))) projPlist = [Eq([reduce_mod_q(c, amodq) for c in pt]) for pt in Plist] if verbose: print(" --> %s" % projPlist) @@ -511,7 +514,7 @@ def p_saturation(self, Plist, p, sieve=True): except ValueError: vecs = [] for v in vecs: - A = matrix(A.rows()+[v]) + A = matrix(A.rows() + [v]) newrank = A.rank() if verbose: print(" --rank is now %s" % newrank) @@ -529,8 +532,7 @@ def p_saturation(self, Plist, p, sieve=True): vecs = A.right_kernel().basis() if verbose: print("kernel vectors: %s" % vecs) - Rlist = [sum([int(vi)*Pi for vi,Pi in zip(v,Plist)],E(0)) - for v in vecs] + Rlist = [sum([int(vi) * Pi for vi, Pi in zip(v, Plist)], E(0)) for v in vecs] if verbose: print("points generating kernel: %s" % Rlist) @@ -552,8 +554,8 @@ def p_saturation(self, Plist, p, sieve=True): # replace any for which the # coefficient of v is nonzero if verbose: - print("-- points were not {}-saturated, gaining index {}".format(p,p)) - j = next(i for i,x in enumerate(v) if x) + print("-- points were not {}-saturated, gaining index {}".format(p, p)) + j = next(i for i, x in enumerate(v) if x) return (j, pt) # R is not a p-multiple so the # points were p-saturated @@ -574,14 +576,14 @@ def p_saturation(self, Plist, p, sieve=True): # in Plist with R, where v[j] is # nonzero. if verbose: - print("-- points were not {}-saturated, gaining index {}".format(p,p)) - j = next(i for i,x in enumerate(v) if x) + print("-- points were not {}-saturated, gaining index {}".format(p, p)) + j = next(i for i, x in enumerate(v) if x) return (j, R) # points really were saturated if verbose: print("-- points were %s-saturated" % p) return False - else: # rank went up but is # @@ -137,6 +138,7 @@ class Sha(SageObject): sage: S.an_padic(5,prec=4) # very long time 1 + O(5^3) """ + def __init__(self, E): r""" The Tate-Shafarevich group associated to an elliptic curve. @@ -205,8 +207,7 @@ def __repr__(self): # Functions related to the BSD conjecture. ######################################################################## - def an_numerical(self, prec=None, - use_database=True, proof=None): + def an_numerical(self, prec=None, use_database=True, proof=None): r""" Return the numerical analytic order of `Sha`, which is a floating point number in all cases. @@ -549,7 +550,7 @@ def an_padic(self, p, prec=0, use_twists=True): E = self.Emin tam = E.tamagawa_product() - tors = E.torsion_order()**2 + tors = E.torsion_order() ** 2 r = E.rank() if r > 0: reg = E.padic_regulator(p) @@ -606,15 +607,15 @@ def an_padic(self, p, prec=0, use_twists=True): K = reg.parent() lg = log(K(1 + p)) - if (E.is_good(p) or E.ap(p) == -1): + if E.is_good(p) or E.ap(p) == -1: if not E.is_good(p): eps = 2 else: - eps = (1 - arith.kronecker_symbol(D, p) / lp.alpha())**2 + eps = (1 - arith.kronecker_symbol(D, p) / lp.alpha()) ** 2 # according to the p-adic BSD this should be equal to the leading term of the p-adic L-series divided by sha: bsdp = tam * reg * eps / tors / lg**r else: - r += 1 # exceptional zero + r += 1 # exceptional zero eq = E.tate_curve(p) Li = eq.L_invariant() @@ -685,11 +686,11 @@ def an_padic(self, p, prec=0, use_twists=True): if bsdp[0] != 0: shan0 = lstar[0] / bsdp[0] else: - shan0 = 0 # this should actually never happen + shan0 = 0 # this should actually never happen if bsdp[1] != 0: shan1 = lstar[1] / bsdp[1] else: - shan1 = 0 # this should conjecturally only happen when the rank is 0 + shan1 = 0 # this should conjecturally only happen when the rank is 0 verbose(f"the two values for Sha : {shan0}, {shan1}") # check consistency (the first two are only here to avoid a bug in the p-adic L-series @@ -750,18 +751,14 @@ def p_primary_order(self, p): # does not work if p = 2 if p == 2: raise ValueError(f"{p} is not an odd prime") - if (E.is_ordinary(p) and E.conductor() % p and - E.galois_representation().is_surjective(p)): + if E.is_ordinary(p) and E.conductor() % p and E.galois_representation().is_surjective(p): N = E.conductor() fac = N.factor() # the auxiliary prime will be one dividing the conductor - if all(E.tate_curve(ell).parameter().valuation() % p == 0 - for ell, e in fac if e == 1): - raise ValueError("The order is not provably known using Skinner-Urban.\n" + - "Try running p_primary_bound to get a bound.") + if all(E.tate_curve(ell).parameter().valuation() % p == 0 for ell, e in fac if e == 1): + raise ValueError("The order is not provably known using Skinner-Urban.\n" + "Try running p_primary_bound to get a bound.") else: - raise ValueError("The order is not provably known using Skinner-Urban.\n" + - "Try running p_primary_bound to get a bound.") + raise ValueError("The order is not provably known using Skinner-Urban.\n" + "Try running p_primary_bound to get a bound.") return self.p_primary_bound(p) def p_primary_bound(self, p): @@ -906,8 +903,7 @@ def two_selmer_bound(self): b = S - r - t return 0 if b < 0 else b - def bound_kolyvagin(self, D=0, regulator=None, - ignore_nonsurj_hypothesis=False): + def bound_kolyvagin(self, D=0, regulator=None, ignore_nonsurj_hypothesis=False): r""" Given a fundamental discriminant `D \neq -3,-4` that satisfies the Heegner hypothesis for `E`, return a list of primes so that @@ -993,7 +989,7 @@ def bound_kolyvagin(self, D=0, regulator=None, eps = E.root_number() L1_vanishes = E.lseries().L1_vanishes() if eps == 1 and L1_vanishes: - return 0, 0 # rank even hence >= 2, so Kolyvagin gives nothing. + return 0, 0 # rank even hence >= 2, so Kolyvagin gives nothing. alpha = sqrt(abs(D)) / (2 * E.period_lattice().complex_area()) F = E.quadratic_twist(D) k_E = 2 * sqrt(E.conductor()) + 10 @@ -1010,7 +1006,7 @@ def bound_kolyvagin(self, D=0, regulator=None, tries += 1 if tries >= 6: raise RuntimeError("Too many precision increases in bound_kolyvagin") - if eps == 1: # E has even rank + if eps == 1: # E has even rank verbose("Conductor of twist = %s" % F.conductor()) LF1, err_F = F.lseries().deriv_at1(k_F) LE1, err_E = E.lseries().at1(k_E) @@ -1020,9 +1016,9 @@ def bound_kolyvagin(self, D=0, regulator=None, hZ = regulator / 2 else: hZ = F.regulator(use_database=True) / 2 - I = RIF(alpha) * RIF(LE1-err_E, LE1+err_E) * RIF(LF1-err_F, LF1+err_F) / RIF(hZ) + I = RIF(alpha) * RIF(LE1 - err_E, LE1 + err_E) * RIF(LF1 - err_F, LF1 + err_F) / RIF(hZ) - else: # E has odd rank + else: # E has odd rank if regulator is not None: hZ = regulator / 2 @@ -1034,7 +1030,7 @@ def bound_kolyvagin(self, D=0, regulator=None, err_E = max(err_E, MIN_ERR) # I = alpha * LE1 * LF1 / hZ - I = RIF(alpha) * RIF(LE1-err_E, LE1+err_E) * RIF(LF1-err_F, LF1+err_F) / RIF(hZ) + I = RIF(alpha) * RIF(LE1 - err_E, LE1 + err_E) * RIF(LF1 - err_F, LF1 + err_F) / RIF(hZ) verbose('interval = %s' % I) t, n = I.is_int() @@ -1123,10 +1119,8 @@ def bound_kato(self): return False B = [2] rho = E.galois_representation() - B.extend(p for p in rho.non_surjective() - if p > 2 and p not in rho.reducible_primes()) - B.extend(p for p in E.conductor().prime_divisors() - if E.has_additive_reduction(p)) + B.extend(p for p in rho.non_surjective() if p > 2 and p not in rho.reducible_primes()) + B.extend(p for p in E.conductor().prime_divisors() if E.has_additive_reduction(p)) # The only other p that might divide B are those that divide # the integer 2*#E(Q)_tor^2 * L(E,1)/omega. So we compute @@ -1134,7 +1128,7 @@ def bound_kato(self): # we have to assume the Manin constant is <=2 in order to provably # compute L(E,1)/omega. for p, n in self.an().factor(): - if n >= 2: # use parity of Sha + if n >= 2: # use parity of Sha B.append(int(p)) return sorted(set(B)) diff --git a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py index bbd3bc1e9d6..a17ebcd4436 100644 --- a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py +++ b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py @@ -8,6 +8,7 @@ in all characteristics - Lorenz Panny (2021): :class:`EllipticCurveHom` interface """ + # **************************************************************************** # Copyright (C) 2007 Robert Bradshaw # @@ -27,7 +28,7 @@ from .constructor import EllipticCurve from sage.schemes.elliptic_curves.hom import EllipticCurveHom -from sage.structure.richcmp import (richcmp, richcmp_not_equal, op_EQ, op_NE) +from sage.structure.richcmp import richcmp, richcmp_not_equal, op_EQ, op_NE from sage.structure.sequence import Sequence from sage.rings.integer import Integer from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -59,6 +60,7 @@ class baseWI: sage: baseWI(u,r,s,t) (u, r, s, t) """ + def __init__(self, u=1, r=0, s=0, t=0): r""" Constructor: check for valid parameters (defaults to identity). @@ -113,10 +115,7 @@ def __mul__(self, other): """ u1, r1, s1, t1 = other.tuple() u2, r2, s2, t2 = self.tuple() - return baseWI(u1 * u2, - (u1**2) * r2 + r1, - u1 * s2 + s1, - (u1**3) * t2 + s1 * (u1**2) * r2 + t1) + return baseWI(u1 * u2, (u1**2) * r2 + r1, u1 * s2 + s1, (u1**3) * t2 + s1 * (u1**2) * r2 + t1) def __invert__(self): r""" @@ -140,7 +139,7 @@ def __invert__(self): (1, 0, 0, 0) """ u, r, s, t = self.tuple() - return baseWI(1/u, -r/u**2, -s/u, (r*s-t)/u**3) + return baseWI(1 / u, -r / u**2, -s / u, (r * s - t) / u**3) def __repr__(self): r""" @@ -200,22 +199,22 @@ def __call__(self, EorP): u, r, s, t = self.tuple() if len(EorP) == 5: a1, a2, a3, a4, a6 = EorP - a6 += r*(a4 + r*(a2 + r)) - t*(a3 + r*a1 + t) - a4 += -s*a3 + 2*r*a2 - (t + r*s)*a1 + 3*r*r - 2*s*t - a3 += r*a1 + t + t - a2 += -s*a1 + 3*r - s*s - a1 += 2*s - return [a1/u, a2/u**2, a3/u**3, a4/u**4, a6/u**6] + a6 += r * (a4 + r * (a2 + r)) - t * (a3 + r * a1 + t) + a4 += -s * a3 + 2 * r * a2 - (t + r * s) * a1 + 3 * r * r - 2 * s * t + a3 += r * a1 + t + t + a2 += -s * a1 + 3 * r - s * s + a1 += 2 * s + return [a1 / u, a2 / u**2, a3 / u**3, a4 / u**4, a6 / u**6] if len(EorP) == 2: x, y = EorP x -= r - y -= (s*x+t) - return [x/u**2, y/u**3] + y -= s * x + t + return [x / u**2, y / u**3] if len(EorP) == 3: x, y, z = EorP - x -= r*z - y -= (s*x+t*z) - return [x/u**2, y/u**3, z] + x -= r * z + y -= s * x + t * z + return [x / u**2, y / u**3, z] raise ValueError("baseWI(a) only for a=(x,y), (x:y:z) or (a1,a2,a3,a4,a6)") @@ -295,6 +294,7 @@ def _isomorphisms(E, F): True """ from .ell_generic import EllipticCurve_generic + if not isinstance(E, EllipticCurve_generic) or not isinstance(F, EllipticCurve_generic): raise ValueError("arguments are not elliptic curves") @@ -305,6 +305,7 @@ def _isomorphisms(E, F): K = E.base_ring() from sage.rings.polynomial.polynomial_ring import polygen + x = polygen(K, 'x') a1E, a2E, a3E, a4E, a6E = E.ainvs() @@ -314,20 +315,20 @@ def _isomorphisms(E, F): if char == 2: if j == 0: - ulist = (x**3 - a3E/a3F).roots(multiplicities=False) + ulist = (x**3 - a3E / a3F).roots(multiplicities=False) for u in ulist: - slist = (x**4 + a3E*x + (a2F**2 + a4F)*u**4 + a2E**2 + a4E).roots(multiplicities=False) + slist = (x**4 + a3E * x + (a2F**2 + a4F) * u**4 + a2E**2 + a4E).roots(multiplicities=False) for s in slist: - r = s**2 + a2E + a2F*u**2 - tlist = (x**2 + a3E*x + r**3 + a2E*r**2 + a4E*r + a6E + a6F*u**6).roots(multiplicities=False) + r = s**2 + a2E + a2F * u**2 + tlist = (x**2 + a3E * x + r**3 + a2E * r**2 + a4E * r + a6E + a6F * u**6).roots(multiplicities=False) for t in tlist: yield (u, r, s, t) else: - u = a1E/a1F - r = (a3E + a3F*u**3)/a1E - slist = (x**2 + a1E*x + r + a2E + a2F*u**2).roots(multiplicities=False) + u = a1E / a1F + r = (a3E + a3F * u**3) / a1E + slist = (x**2 + a1E * x + r + a2E + a2F * u**2).roots(multiplicities=False) for s in slist: - t = (a4E + a4F*u**4 + s*a3E + r*s*a1E + r**2) / a1E + t = (a4E + a4F * u**4 + s * a3E + r * s * a1E + r**2) / a1E yield (u, r, s, t) return @@ -336,15 +337,15 @@ def _isomorphisms(E, F): if char == 3: if j == 0: - ulist = (x**4 - b4E/b4F).roots(multiplicities=False) + ulist = (x**4 - b4E / b4F).roots(multiplicities=False) for u in ulist: - s = a1E - a1F*u - t = a3E - a3F*u**3 - rlist = (x**3 - b4E*x + b6E - b6F*u**6).roots(multiplicities=False) + s = a1E - a1F * u + t = a3E - a3F * u**3 + rlist = (x**3 - b4E * x + b6E - b6F * u**6).roots(multiplicities=False) for r in rlist: - yield (u, r, s, t + r*a1E) + yield (u, r, s, t + r * a1E) else: - ulist = (x**2 - b2E/b2F).roots(multiplicities=False) + ulist = (x**2 - b2E / b2F).roots(multiplicities=False) for u in ulist: r = (b4F * u**4 - b4E) / b2E s = a1E - a1F * u @@ -358,16 +359,16 @@ def _isomorphisms(E, F): c4F, c6F = F.c_invariants() if j == 0: - m, um = 6, c6E/c6F + m, um = 6, c6E / c6F elif j == 1728: - m, um = 4, c4E/c4F + m, um = 4, c4E / c4F else: - m, um = 2, (c6E*c4F)/(c6F*c4E) + m, um = 2, (c6E * c4F) / (c6F * c4E) ulist = (x**m - um).roots(multiplicities=False) for u in ulist: - s = (a1F*u - a1E)/2 - r = (a2F*u**2 + a1E*s + s**2 - a2E)/3 - t = (a3F*u**3 - a1E*r - a3E)/2 + s = (a1F * u - a1E) / 2 + r = (a2F * u**2 + a1E * s + s**2 - a2E) / 3 + t = (a3F * u**3 - a1E * r - a3E) / 2 yield (u, r, s, t) @@ -436,6 +437,7 @@ class WeierstrassIsomorphism(EllipticCurveHom, baseWI): sage: w._domain == E True """ + def __init__(self, E=None, urst=None, F=None): r""" Constructor for the ``WeierstrassIsomorphism`` class. @@ -505,7 +507,7 @@ def __init__(self, E=None, urst=None, F=None): if F != EllipticCurve(baseWI.__call__(self, list(E.a_invariants()))): raise ValueError("second argument is not an isomorphism from first argument to third argument") - self._mpoly_ring = PolynomialRing(base_ring, ['x','y']) + self._mpoly_ring = PolynomialRing(base_ring, ['x', 'y']) self._poly_ring = PolynomialRing(base_ring, ['x']) self._xyfield = self._mpoly_ring.fraction_field() self._xfield = self._poly_ring.fraction_field() @@ -569,9 +571,9 @@ def _comparison_impl(left, right, op): # of isomorphisms satisfying u=+-1 come first. def _sorting_key(iso): v, w = iso.tuple(), (-iso).tuple() - i = 0 if (1,0,0,0) in (v,w) else 1 + i = 0 if (1, 0, 0, 0) in (v, w) else 1 j = 0 if v[0] == 1 else 1 if w[0] == 1 else 2 - return (i,) + min(v,w) + (j,) + v + return (i,) + min(v, w) + (j,) + v return richcmp(_sorting_key(left), _sorting_key(right), op) @@ -833,7 +835,7 @@ def x_rational_map(self): sage: iso.x_rational_map().parent() Fraction Field of Univariate Polynomial Ring in x over Rational Field """ - x, = self._xfield.gens() + (x,) = self._xfield.gens() return (x - self.r) / self.u**2 def kernel_polynomial(self): @@ -931,7 +933,7 @@ def __neg__(self): sage: -t^2 == identity_morphism(E) # needs sage.rings.number_field True """ - a1,_,a3,_,_ = self._domain.a_invariants() + a1, _, a3, _, _ = self._domain.a_invariants() w = baseWI(-1, 0, -a1, -a3) urst = baseWI.__mul__(self, w).tuple() return WeierstrassIsomorphism(self._domain, urst, self._codomain) diff --git a/src/sage/schemes/elliptic_curves/weierstrass_transform.py b/src/sage/schemes/elliptic_curves/weierstrass_transform.py index fcbd4e84023..da19fe5e511 100644 --- a/src/sage/schemes/elliptic_curves/weierstrass_transform.py +++ b/src/sage/schemes/elliptic_curves/weierstrass_transform.py @@ -140,9 +140,7 @@ def post_rescaling(self): return self._post -def WeierstrassTransformationWithInverse(domain, codomain, - defining_polynomials, post_multiplication, - inv_defining_polynomials, inv_post_multiplication): +def WeierstrassTransformationWithInverse(domain, codomain, defining_polynomials, post_multiplication, inv_defining_polynomials, inv_post_multiplication): """ Construct morphism of a genus-one curve to/from the Weierstrass form with its inverse. @@ -165,10 +163,8 @@ def WeierstrassTransformationWithInverse(domain, codomain, Defn: Defined on coordinates by sending (u : v : w) to (-w : -v + w : 3*u + 3*v) """ - fwd = WeierstrassTransformationWithInverse_class( - domain, codomain, defining_polynomials, post_multiplication) - inv = WeierstrassTransformationWithInverse_class( - codomain, domain, inv_defining_polynomials, inv_post_multiplication) + fwd = WeierstrassTransformationWithInverse_class(domain, codomain, defining_polynomials, post_multiplication) + inv = WeierstrassTransformationWithInverse_class(codomain, domain, inv_defining_polynomials, inv_post_multiplication) fwd._inverse = inv inv._inverse = fwd return fwd diff --git a/src/sage/schemes/generic/algebraic_scheme.py b/src/sage/schemes/generic/algebraic_scheme.py index 8986a40ce25..879a30bf621 100644 --- a/src/sage/schemes/generic/algebraic_scheme.py +++ b/src/sage/schemes/generic/algebraic_scheme.py @@ -613,9 +613,7 @@ def _latex_(self): X \\text{ is defined by }\\text{no polynomials},\\text{ and } Y \\text{ is defined by } x - y.' """ - if isinstance( - self.ambient_space(), sage.schemes.affine.affine_space.AffineSpace_generic - ): + if isinstance(self.ambient_space(), sage.schemes.affine.affine_space.AffineSpace_generic): t = "affine" else: t = "projective" @@ -625,12 +623,7 @@ def _latex_(self): Y = ", ".join(latex(f) for f in self.__Y.defining_polynomials()) if not Y: Y = r"\text{no polynomials}" - return ( - r"\text{Quasi-%s subscheme } (X\setminus Y)\subset %s," - r"\text{ where } X \text{ is defined by }%s," - r"\text{ and } Y \text{ is defined by } %s." - % (t, latex(self.ambient_space()), X, Y) - ) + return r"\text{Quasi-%s subscheme } (X\setminus Y)\subset %s," r"\text{ where } X \text{ is defined by }%s," r"\text{ and } Y \text{ is defined by } %s." % (t, latex(self.ambient_space()), X, Y) def _repr_(self): r""" @@ -651,21 +644,15 @@ def _repr_(self): sage: U._repr_() 'Quasi-projective subscheme X - Y of Projective Space of dimension 2 over Integer Ring, where X is defined by:\n (no polynomials)\nand Y is defined by:\n x - y' """ - if isinstance( - self.ambient_space(), sage.schemes.affine.affine_space.AffineSpace_generic - ): + if isinstance(self.ambient_space(), sage.schemes.affine.affine_space.AffineSpace_generic): t = "affine" else: t = "projective" - return ( - "Quasi-%s subscheme X - Y of %s, where X is defined by:\n%s\n" - "and Y is defined by:\n%s" - % ( - t, - self.ambient_space(), - str(self.__X).split("\n", 1)[1], - str(self.__Y).split("\n", 1)[1], - ) + return "Quasi-%s subscheme X - Y of %s, where X is defined by:\n%s\n" "and Y is defined by:\n%s" % ( + t, + self.ambient_space(), + str(self.__X).split("\n", 1)[1], + str(self.__Y).split("\n", 1)[1], ) def X(self): @@ -769,9 +756,7 @@ def _check_satisfies_equations(self, v): coords = list(v) for f in self.__X.defining_polynomials(): if f(coords) != 0: - raise TypeError( - "Coordinates %s do not define a point on %s" % (v, self) - ) + raise TypeError("Coordinates %s do not define a point on %s" % (v, self)) for f in self.__Y.defining_polynomials(): if f(coords) != 0: return True @@ -891,9 +876,7 @@ def __init__(self, A, polynomials, category=None): polynomials = I.gens() if I.ring() is R: # Otherwise we will recompute I later after self.__I = I # converting generators to the correct ring - if isinstance(polynomials, (tuple, PolynomialSequence_generic)) or is_iterator( - polynomials - ): + if isinstance(polynomials, (tuple, PolynomialSequence_generic)) or is_iterator(polynomials): polynomials = list(polynomials) elif not isinstance(polynomials, list): # Looks like we got a single polynomial @@ -902,10 +885,7 @@ def __init__(self, A, polynomials, category=None): try: polynomials[n] = R(f) except TypeError: - raise TypeError( - "%s cannot be converted to a polynomial in " - "the coordinate ring of this %s!" % (f, A) - ) + raise TypeError("%s cannot be converted to a polynomial in " "the coordinate ring of this %s!" % (f, A)) polynomials = tuple(polynomials) self.__polys = A._validate(polynomials) @@ -938,15 +918,11 @@ def _check_satisfies_equations(self, v): if f(coords) != 0: # it must be "!=0" instead of "if f(v)", e.g., # because of p-adic base rings. - raise TypeError( - "Coordinates %s do not define a point on %s" % (coords, self) - ) + raise TypeError("Coordinates %s do not define a point on %s" % (coords, self)) try: return self.ambient_space()._check_satisfies_equations(coords) except TypeError: - raise TypeError( - "Coordinates %s do not define a point on %s" % (coords, self) - ) + raise TypeError("Coordinates %s do not define a point on %s" % (coords, self)) def base_extend(self, R): """ @@ -1082,11 +1058,7 @@ def normalize_defining_polynomials(self): (x^2 + 2*x*y, 3*x + 8*y) """ BR = self.base_ring() - if ( - BR == ZZ - or isinstance(BR, (sage.rings.abc.AlgebraicField, sage.rings.abc.Order)) - or BR in NumberFields() - ): + if BR == ZZ or isinstance(BR, (sage.rings.abc.AlgebraicField, sage.rings.abc.Order)) or BR in NumberFields(): normalized_polys = [] initial_polys = list(self.__polys) @@ -1096,20 +1068,14 @@ def normalize_defining_polynomials(self): P = mult * P # stores the common factor from all coefficients div = gcd(list(P.coefficients())) - poly_ring = ( - P.parent() - ) # need to coerce, since division might change base ring + poly_ring = P.parent() # need to coerce, since division might change base ring P = poly_ring((BR.one() / div) * P) normalized_polys.append(P) self.__polys = tuple(normalized_polys) else: - raise NotImplementedError( - "currently normalization is implemented " - "only for QQbar, number fields and " - "number field orders" - ) + raise NotImplementedError("currently normalization is implemented " "only for QQbar, number fields and " "number field orders") def defining_ideal(self): """ @@ -1416,15 +1382,10 @@ def union(self, other): True """ if not isinstance(other, AlgebraicScheme_subscheme): - raise TypeError( - "other (=%s) must be a closed algebraic subscheme of an ambient space" - % other - ) + raise TypeError("other (=%s) must be a closed algebraic subscheme of an ambient space" % other) A = self.ambient_space() if other.ambient_space() != A: - raise ValueError( - "other (=%s) must be in the same ambient space as self" % other - ) + raise ValueError("other (=%s) must be in the same ambient space as self" % other) return A.subscheme(self.defining_ideal().intersection(other.defining_ideal())) def __pow__(self, m): @@ -1486,11 +1447,7 @@ def __pow__(self, m): polys = [] for i in range(m): - phi = ( - self.ambient_space() - .coordinate_ring() - .hom(list(CR.gens()[n * i : n * (i + 1)]), CR) - ) + phi = self.ambient_space().coordinate_ring().hom(list(CR.gens()[n * i : n * (i + 1)]), CR) polys.extend([phi(t) for t in self.defining_polynomials()]) return AS.subscheme(polys) @@ -1593,10 +1550,7 @@ def __mul__(self, right): phi = self.ambient_space().coordinate_ring().hom(list(CR.gens()[:n]), CR) psi = right.ambient_space().coordinate_ring().hom(list(CR.gens()[n:]), CR) - return AS.subscheme( - [phi(t) for t in self.defining_polynomials()] - + [psi(t) for t in right.defining_polynomials()] - ) + return AS.subscheme([phi(t) for t in self.defining_polynomials()] + [psi(t) for t in right.defining_polynomials()]) __add__ = union @@ -1616,15 +1570,10 @@ def intersection(self, other): y """ if not isinstance(other, AlgebraicScheme_subscheme): - raise TypeError( - "other (=%s) must be a closed algebraic subscheme of an ambient space" - % other - ) + raise TypeError("other (=%s) must be a closed algebraic subscheme of an ambient space" % other) A = self.ambient_space() if other.ambient_space() != A: - raise ValueError( - "other (=%s) must be in the same ambient space as self" % other - ) + raise ValueError("other (=%s) must be in the same ambient space as self" % other) return A.subscheme(self.defining_ideal() + other.defining_ideal()) def complement(self, other=None): @@ -1680,14 +1629,9 @@ def complement(self, other=None): if other == A: other = A.subscheme([]) else: - raise TypeError( - "Argument other (=%s) must be a closed algebraic subscheme of an ambient space" - % other - ) + raise TypeError("Argument other (=%s) must be a closed algebraic subscheme of an ambient space" % other) if other.ambient_space() != A: - raise ValueError( - "other (=%s) must be in the same ambient space as self" % other - ) + raise ValueError("other (=%s) must be in the same ambient space as self" % other) return AlgebraicScheme_quasi(other, self) def rational_points(self, **kwds): @@ -1814,14 +1758,10 @@ def rational_points(self, **kwds): if F in NumberFields() or F == ZZ: X = self.base_extend(F)(F) try: - return X.points( - **kwds - ) # checks for proper bound done in points functions + return X.points(**kwds) # checks for proper bound done in points functions except TypeError: raise TypeError("Unable to enumerate points over %s." % F) - elif (self.base_ring() in NumberFields() or self.base_ring() == ZZ) and hasattr( - F, "precision" - ): + elif (self.base_ring() in NumberFields() or self.base_ring() == ZZ) and hasattr(F, "precision"): # we are numerically approximating number field points return self(self.base_ring()).numerical_points(F=F, **kwds) try: @@ -2071,9 +2011,7 @@ def specialization(self, D=None, phi=None): """ if D is None: if phi is None: - raise ValueError( - "either the dictionary or the specialization must be provided" - ) + raise ValueError("either the dictionary or the specialization must be provided") else: from sage.rings.polynomial.flatten import SpecializationMorphism diff --git a/src/sage/schemes/generic/ambient_space.py b/src/sage/schemes/generic/ambient_space.py index 3aba1404953..e07f856e7eb 100644 --- a/src/sage/schemes/generic/ambient_space.py +++ b/src/sage/schemes/generic/ambient_space.py @@ -1,6 +1,7 @@ """ Ambient spaces """ + # **************************************************************************** # Copyright (C) 2006 William Stein # @@ -27,6 +28,7 @@ class AmbientSpace(Scheme): - ``R`` -- ring """ + def __init__(self, n, R=ZZ): """ TESTS:: @@ -134,8 +136,7 @@ def _validate(self, polynomials): ... NotImplementedError: ambient spaces must override "_validate" method! """ - raise NotImplementedError('ambient spaces must override "_validate" ' - 'method!') + raise NotImplementedError('ambient spaces must override "_validate" ' 'method!') def change_ring(self, R): r""" @@ -162,8 +163,7 @@ def change_ring(self, R): ... NotImplementedError: ambient spaces must override "change_ring" method! """ - raise NotImplementedError( - 'ambient spaces must override "change_ring" method!') + raise NotImplementedError('ambient spaces must override "change_ring" method!') ####################################################################### # End overloads @@ -214,13 +214,9 @@ def base_extend(self, R): if self.base_ring() == R: return self if not R.has_coerce_map_from(self.base_ring()): - raise ValueError( - "no natural map from the base ring (=%s) to R (=%s)!" - % (self.base_ring(), R)) + raise ValueError("no natural map from the base ring (=%s) to R (=%s)!" % (self.base_ring(), R)) return self.change_ring(R) - raise NotImplementedError( - "extension of spaces over %s to %s is not implemented!" - % (self.base_ring(), R)) + raise NotImplementedError("extension of spaces over %s to %s is not implemented!" % (self.base_ring(), R)) def ambient_space(self): """ @@ -272,6 +268,7 @@ def identity_morphism(self): Defn: Identity map """ from sage.schemes.generic.morphism import SchemeMorphism_polynomial_id + return SchemeMorphism_polynomial_id(self) ###################################################################### @@ -322,18 +319,18 @@ def ngens(self): """ return len(self.gens()) -## def assign_names(self, names=None): -## """ -## EXAMPLES:: - -## sage: A = AffineSpace(2, QQ, 'ab'); A -## Affine Space of dimension 2 over Rational Field -## sage: A.coordinate_ring() -## Polynomial Ring in a, b over Rational Field -## sage: A._assign_names('xy'); A.coordinate_ring() -## Polynomial Ring in x, y over Rational Field -## """ -## self.coordinate_ring()._assign_names(names) + ## def assign_names(self, names=None): + ## """ + ## EXAMPLES:: + + ## sage: A = AffineSpace(2, QQ, 'ab'); A + ## Affine Space of dimension 2 over Rational Field + ## sage: A.coordinate_ring() + ## Polynomial Ring in a, b over Rational Field + ## sage: A._assign_names('xy'); A.coordinate_ring() + ## Polynomial Ring in x, y over Rational Field + ## """ + ## self.coordinate_ring()._assign_names(names) def dimension_absolute(self): """ diff --git a/src/sage/schemes/generic/divisor.py b/src/sage/schemes/generic/divisor.py index 2c88a65f373..36dd3d1e44a 100644 --- a/src/sage/schemes/generic/divisor.py +++ b/src/sage/schemes/generic/divisor.py @@ -83,7 +83,7 @@ def CurvePointToIdeal(C, P): if ai == 0: polys.append(x[i]) else: - polys.append(a_m*x[i]-ai*x_m) + polys.append(a_m * x[i] - ai * x_m) elif isinstance(A, AffineSpace_generic): for i in range(m + 1): ai = P[i] @@ -184,9 +184,7 @@ def _latex_(self): # straight - as the test above demonstrates, it results in the first # generator being in front of the second one terms.sort(key=lambda x: x[1], reverse=True) - return repr_lincomb([(r"\mathrm{V}\left(%s\right)" % latex(v), c) - for c, v in terms], - is_latex=True) + return repr_lincomb([(r"\mathrm{V}\left(%s\right)" % latex(v), c) for c, v in terms], is_latex=True) def _repr_(self): r""" @@ -267,6 +265,7 @@ class Divisor_curve(Divisor_generic): sage: E.divisor([(3,P), (-4,5*P)]) 3*(x, y) - 4*(x - 1/4*z, y + 5/8*z) """ + def __init__(self, v, parent=None, check=True, reduce=True): """ Construct a divisor on a curve. @@ -289,6 +288,7 @@ def __init__(self, v, parent=None, check=True, reduce=True): (x, y) """ from sage.schemes.generic.divisor_group import DivisorGroup_curve + if not isinstance(v, (list, tuple)): v = [(1, v)] @@ -334,8 +334,7 @@ def __init__(self, v, parent=None, check=True, reduce=True): know_points = False w.append((n, I)) v = w - Divisor_generic.__init__( - self, v, check=False, reduce=True, parent=parent) + Divisor_generic.__init__(self, v, check=False, reduce=True, parent=parent) if know_points: self._points = points diff --git a/src/sage/schemes/generic/divisor_group.py b/src/sage/schemes/generic/divisor_group.py index 6e9dc6a048e..0854313755e 100644 --- a/src/sage/schemes/generic/divisor_group.py +++ b/src/sage/schemes/generic/divisor_group.py @@ -8,12 +8,12 @@ - Volker Braun (2010-07-16): Documentation, doctests, coercion fixes, bugfixes. """ -#******************************************************************************* +# ******************************************************************************* # Copyright (C) 2010 Volker Braun # Copyright (C) 2006 David Kohel # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#******************************************************************************* +# ******************************************************************************* from sage.misc.lazy_import import lazy_import from sage.schemes.generic.divisor import Divisor_generic, Divisor_curve @@ -136,8 +136,8 @@ def _repr_(self): elif ring == QQ: base_ring_str = 'QQ' else: - base_ring_str = '('+str(ring)+')' - return 'Group of '+base_ring_str+'-Divisors on '+str(self._scheme) + base_ring_str = '(' + str(ring) + ')' + return 'Group of ' + base_ring_str + '-Divisors on ' + str(self._scheme) def _element_constructor_(self, x, check=True, reduce=True): r""" @@ -189,9 +189,7 @@ def _coerce_map_from_(self, other): sage: E.divisor_group()._coerce_map_from_(D.parent()) False """ - return (isinstance(other, DivisorGroup_generic) - and self.scheme().has_coerce_map_from(other.scheme()) - and super()._coerce_map_from_(other)) + return isinstance(other, DivisorGroup_generic) and self.scheme().has_coerce_map_from(other.scheme()) and super()._coerce_map_from_(other) def scheme(self): r""" diff --git a/src/sage/schemes/generic/glue.py b/src/sage/schemes/generic/glue.py index 7733030a2ab..64a6c6f752e 100644 --- a/src/sage/schemes/generic/glue.py +++ b/src/sage/schemes/generic/glue.py @@ -2,11 +2,11 @@ Scheme obtained by gluing two other schemes """ -#******************************************************************************* +# ******************************************************************************* # Copyright (C) 2006 William Stein # Distributed under the terms of the GNU General Public License (GPL) # https://www.gnu.org/licenses/ -#******************************************************************************* +# ******************************************************************************* from sage.misc.lazy_import import lazy_import from sage.schemes.generic.scheme import Scheme @@ -45,6 +45,7 @@ class GluedScheme(Scheme): Y: Spectrum of Univariate Polynomial Ring in y over Rational Field U: Spectrum of Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x*y - 1) """ + def __init__(self, f, g, check=True): if check: if not isinstance(f, SchemeMorphism): @@ -52,7 +53,7 @@ def __init__(self, f, g, check=True): if not isinstance(g, SchemeMorphism): raise TypeError("g (=%s) must be a scheme morphism" % g) if f.domain() != g.domain(): - raise ValueError("f (=%s) and g (=%s) must have the same domain" % (f,g)) + raise ValueError("f (=%s) and g (=%s) must have the same domain" % (f, g)) self.__f = f self.__g = g @@ -77,5 +78,4 @@ def gluing_maps(self): return self.__f, self.__g def _repr_(self): - return "Scheme obtained by gluing X and Y along U, where\n X: %s\n Y: %s\n U: %s" % ( - self.__f.codomain(), self.__g.codomain(), self.__f.domain()) + return "Scheme obtained by gluing X and Y along U, where\n X: %s\n Y: %s\n U: %s" % (self.__f.codomain(), self.__g.codomain(), self.__f.domain()) diff --git a/src/sage/schemes/generic/homset.py b/src/sage/schemes/generic/homset.py index ac133d53f19..cc6141667bf 100644 --- a/src/sage/schemes/generic/homset.py +++ b/src/sage/schemes/generic/homset.py @@ -44,10 +44,7 @@ from sage.categories.commutative_rings import CommutativeRings from sage.schemes.generic.scheme import AffineScheme -from sage.schemes.generic.morphism import ( - SchemeMorphism, - SchemeMorphism_structure_map, - SchemeMorphism_spec) +from sage.schemes.generic.morphism import SchemeMorphism, SchemeMorphism_structure_map, SchemeMorphism_spec lazy_import('sage.schemes.affine.affine_space', 'AffineSpace_generic', as_='AffineSpace') lazy_import('sage.schemes.generic.algebraic_scheme', 'AlgebraicScheme_subscheme') @@ -59,6 +56,7 @@ # Factory for Hom sets of schemes # ******************************************************************* + class SchemeHomsetFactory(UniqueFactory): """ Factory for Hom-sets of schemes. @@ -96,8 +94,7 @@ class SchemeHomsetFactory(UniqueFactory): Rational Field """ - def create_key_and_extra_args(self, X, Y, category=None, base=None, - check=True, as_point_homset=False): + def create_key_and_extra_args(self, X, Y, category=None, base=None, check=True, as_point_homset=False): """ Create a key that uniquely determines the Hom-set. @@ -142,6 +139,7 @@ def create_key_and_extra_args(self, X, Y, category=None, base=None, Y = AffineScheme(Y) if base is None: from sage.structure.element import coercion_model + base = coercion_model.common_parent(X.base_ring(), Y.base_ring()) if isinstance(base, AffineScheme): base_spec = base @@ -153,6 +151,7 @@ def create_key_and_extra_args(self, X, Y, category=None, base=None, raise ValueError('base must be a commutative ring or its spectrum') if not category: from sage.categories.schemes import Schemes + category = Schemes(base_spec) key = (id(X), id(Y), category, as_point_homset) extra = {'X': X, 'Y': Y, 'base_ring': base_ring, 'check': check} @@ -203,6 +202,7 @@ def create_object(self, version, key, **extra_args): # Base class # ******************************************************************* + class SchemeHomset_generic(HomsetWithBase): r""" The base class for Hom-sets of schemes. @@ -230,6 +230,7 @@ class SchemeHomset_generic(HomsetWithBase): sage: Hom.category() Category of endsets of schemes over Rational Field """ + Element = SchemeMorphism def __reduce__(self): @@ -244,8 +245,7 @@ def __reduce__(self): sage: loads(Hom.dumps()) == Hom True """ - return SchemeHomset, (self.domain(), self.codomain(), self.homset_category(), - self.base_ring(), False, False) + return SchemeHomset, (self.domain(), self.codomain(), self.homset_category(), self.base_ring(), False, False) def __call__(self, *args, **kwds): r""" @@ -371,6 +371,7 @@ def _element_constructor_(self, x, check=True): from sage.categories.map import Map from sage.categories.rings import Rings + if isinstance(x, Map) and x.category_for().is_subcategory(Rings()): # x is a morphism of Rings return SchemeMorphism_spec(self, x, check=check) @@ -382,6 +383,7 @@ def _element_constructor_(self, x, check=True): # Base class for points # ******************************************************************* + class SchemeHomset_points(SchemeHomset_generic): r""" Set of rational points of the scheme. @@ -435,8 +437,7 @@ def __reduce__(self): sage: loads(Hom.dumps()) == Hom True """ - return SchemeHomset, (self.domain(), self.codomain(), self.homset_category(), - self.base_ring(), False, True) + return SchemeHomset, (self.domain(), self.codomain(), self.homset_category(), self.base_ring(), False, True) def _coerce_map_from_(self, other): r""" @@ -550,8 +551,7 @@ def _coerce_map_from_(self, other): # and the base rings are coercible if other in CommutativeRings: try: - if (isinstance(target.ambient_space(), AffineSpace) - and target.ambient_space().dimension_relative() == 1): + if isinstance(target.ambient_space(), AffineSpace) and target.ambient_space().dimension_relative() == 1: return target.base_ring().has_coerce_map_from(other) return False except AttributeError: # no .ambient_space @@ -564,8 +564,7 @@ def _coerce_map_from_(self, other): if not isinstance(source, AlgebraicScheme_subscheme): return False if target.ambient_space() == source.ambient_space(): - if all(g in source.defining_ideal() - for g in target.defining_polynomials()): + if all(g in source.defining_ideal() for g in target.defining_polynomials()): return self.domain().coordinate_ring().has_coerce_map_from(other.domain().coordinate_ring()) else: # if the target is an ambient space, we can coerce if the base rings coerce @@ -578,16 +577,14 @@ def _coerce_map_from_(self, other): return False # for projective and affine varieties, we check dimension # and matching variable names - if ((isinstance(ta, ProjectiveSpace) and isinstance(sa, ProjectiveSpace)) - or (isinstance(ta, AffineSpace) and isinstance(sa, AffineSpace))): - if (ta.variable_names() == sa.variable_names()): + if (isinstance(ta, ProjectiveSpace) and isinstance(sa, ProjectiveSpace)) or (isinstance(ta, AffineSpace) and isinstance(sa, AffineSpace)): + if ta.variable_names() == sa.variable_names(): return self.domain().coordinate_ring().has_coerce_map_from(other.domain().coordinate_ring()) return False # for products of projective spaces, we check dimension of # components and matching variable names if isinstance(ta, ProductProjectiveSpaces) and isinstance(sa, ProductProjectiveSpaces): - if (ta.dimension_relative_components() == sa.dimension_relative_components()) \ - and (ta.variable_names() == sa.variable_names()): + if (ta.dimension_relative_components() == sa.dimension_relative_components()) and (ta.variable_names() == sa.variable_names()): return self.domain().coordinate_ring().has_coerce_map_from(other.domain().coordinate_ring()) return False @@ -768,6 +765,7 @@ def cardinality(self): """ if hasattr(self, 'is_finite') and not self.is_finite(): from sage.rings.infinity import Infinity + return Infinity return sum(ZZ.one() for point in self) diff --git a/src/sage/schemes/generic/hypersurface.py b/src/sage/schemes/generic/hypersurface.py index fd574061ff8..d6949ec0d73 100644 --- a/src/sage/schemes/generic/hypersurface.py +++ b/src/sage/schemes/generic/hypersurface.py @@ -75,7 +75,8 @@ def __init__(self, poly, ambient=None): if ambient is None: R = poly.parent() from sage.schemes.projective.projective_space import ProjectiveSpace - ambient = ProjectiveSpace(R.base_ring(), R.ngens()-1) + + ambient = ProjectiveSpace(R.base_ring(), R.ngens() - 1) ambient._coordinate_ring = R AlgebraicScheme_subscheme_projective.__init__(self, ambient, [poly]) @@ -94,8 +95,7 @@ def _repr_(self): sage: H._repr_() 'Projective hypersurface defined by y^2 + x*z in Projective Space of dimension 2 over Integer Ring' """ - return "Projective hypersurface defined by %s in %s" % ( - self.defining_polynomial(), self.ambient_space()) + return "Projective hypersurface defined by %s in %s" % (self.defining_polynomial(), self.ambient_space()) def defining_polynomial(self): """ @@ -130,6 +130,7 @@ class AffineHypersurface(AlgebraicScheme_subscheme_affine): Affine hypersurface defined by -z^3 + x*y in Affine Space of dimension 3 over Rational Field """ + def __init__(self, poly, ambient=None): """ Return the affine hypersurface in the space ambient @@ -163,6 +164,7 @@ def __init__(self, poly, ambient=None): if ambient is None: R = poly.parent() from sage.schemes.affine.affine_space import AffineSpace + ambient = AffineSpace(R.base_ring(), R.ngens()) ambient._coordinate_ring = R AlgebraicScheme_subscheme_affine.__init__(self, ambient, [poly]) @@ -182,8 +184,7 @@ def _repr_(self): sage: H._repr_() 'Affine hypersurface defined by y^2 + x*z in Affine Space of dimension 3 over Integer Ring' """ - return "Affine hypersurface defined by %s in %s" % ( - self.defining_polynomial(), self.ambient_space()) + return "Affine hypersurface defined by %s in %s" % (self.defining_polynomial(), self.ambient_space()) def defining_polynomial(self): """ diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index ce5925f4ff4..9424eec4115 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -627,6 +627,7 @@ def glue_along_domains(self, other): Defn: y |--> ybar """ from . import glue + return glue.GluedScheme(self, other) @@ -645,6 +646,7 @@ class SchemeMorphism_id(SchemeMorphism): Scheme endomorphism of Spectrum of Integer Ring Defn: Identity map """ + def __init__(self, X): """ The Python constructor. @@ -688,6 +690,7 @@ class SchemeMorphism_structure_map(SchemeMorphism): Scheme endomorphism of Spectrum of Integer Ring Defn: Structure map """ + def __init__(self, parent, codomain=None): """ The Python constructor. @@ -759,6 +762,7 @@ class SchemeMorphism_spec(SchemeMorphism): To: Rational Field Defn: x |--> 7 """ + def __init__(self, parent, phi, check=True): """ The Python constructor. @@ -779,14 +783,13 @@ def __init__(self, parent, phi, check=True): SchemeMorphism.__init__(self, parent) if check: from sage.categories.rings import Rings + if not (isinstance(phi, Map) and phi.category_for().is_subcategory(Rings())): raise TypeError("phi (=%s) must be a ring homomorphism" % phi) if phi.domain() != parent.codomain().coordinate_ring(): - raise TypeError("phi (=%s) must have domain %s" - % (phi, parent.codomain().coordinate_ring())) + raise TypeError("phi (=%s) must have domain %s" % (phi, parent.codomain().coordinate_ring())) if phi.codomain() != parent.domain().coordinate_ring(): - raise TypeError("phi (=%s) must have codomain %s" - % (phi, parent.domain().coordinate_ring())) + raise TypeError("phi (=%s) must have codomain %s" % (phi, parent.domain().coordinate_ring())) self.__ring_homomorphism = phi def _call_(self, x): @@ -883,6 +886,7 @@ def ring_homomorphism(self): # regardless of the class ############################################################################ + class SchemeMorphism_polynomial(SchemeMorphism): r""" A morphism of schemes determined by polynomials that define what @@ -928,6 +932,7 @@ class SchemeMorphism_polynomial(SchemeMorphism): TypeError: polys (=[e^x, e^y]) must be elements of Multivariate Polynomial Ring in x, y over Rational Field """ + def __init__(self, parent, polys, check=True): """ The Python constructor. @@ -1460,6 +1465,7 @@ def change_ring(self, R, check=True): if isinstance(R, Map): from sage.structure.coerce_maps import CallableConvertMap + if R.domain() == self.base_ring(): S = self.domain().ambient_space().coordinate_ring() T = T.ambient_space().coordinate_ring() @@ -1583,9 +1589,11 @@ def specialization(self, D=None, phi=None, homset=None): else: if isinstance(self[0].parent(), FractionField_generic): from sage.rings.polynomial.flatten import FractionSpecializationMorphism + phi = FractionSpecializationMorphism(self[0].parent(), D) else: from sage.rings.polynomial.flatten import SpecializationMorphism + phi = SpecializationMorphism(self[0].parent(), D) if homset is None: domain = self.domain() @@ -1707,6 +1715,7 @@ class SchemeMorphism_polynomial_id(SchemeMorphism_id, SchemeMorphism_polynomial) Scheme endomorphism of Spectrum of Integer Ring Defn: Identity map """ + def __init__(self, X): """ Initialize. @@ -1727,6 +1736,7 @@ def __init__(self, X): # by coordinates. ############################################################################ + class SchemeMorphism_point(SchemeMorphism): r""" Base class for rational points on schemes. @@ -1742,6 +1752,7 @@ class SchemeMorphism_point(SchemeMorphism): sage: type(f) """ + def _repr_(self): r""" Return a string representation of ``self``. @@ -2059,6 +2070,7 @@ def specialization(self, D=None, phi=None, ambient=None): raise ValueError("either the dictionary or the specialization must be provided") else: from sage.rings.polynomial.flatten import SpecializationMorphism + phi = SpecializationMorphism(self.codomain().ambient_space().coordinate_ring(), D) if ambient is None: ambient = self.codomain() diff --git a/src/sage/schemes/generic/point.py b/src/sage/schemes/generic/point.py index 992ac6ea946..17fc4918c50 100644 --- a/src/sage/schemes/generic/point.py +++ b/src/sage/schemes/generic/point.py @@ -22,6 +22,7 @@ class SchemePoint(Element): Base class for points on a scheme, either topological or defined by a morphism. """ + def __init__(self, S, parent=None): """ INPUT: @@ -74,10 +75,12 @@ def _repr_(self): # Topological points on a scheme ######################################################## + class SchemeTopologicalPoint(SchemePoint): """ Base class for topological points on schemes. """ + def __init__(self, S): """ INPUT: @@ -114,9 +117,7 @@ def __init__(self, u, x): self.__x = x def _repr_(self): - return "Point on %s defined by x in U, where:\n U: %s\n x: %s" % ( - self.scheme(), self.embedding_of_affine_open().domain(), - self.point_on_affine()) + return "Point on %s defined by x in U, where:\n U: %s\n x: %s" % (self.scheme(), self.embedding_of_affine_open().domain(), self.point_on_affine()) def point_on_affine(self): """ @@ -170,6 +171,7 @@ def __init__(self, S, P, check=False): """ R = S.coordinate_ring() from sage.rings.ideal import Ideal_generic + if not isinstance(P, Ideal_generic): P = R.ideal(P) elif P.ring() is not R: @@ -196,8 +198,7 @@ def _repr_(self) -> str: sage: pt._repr_() 'Point on Projective Space of dimension 2 over Rational Field defined by the Ideal (-x^2 + y*z) of Multivariate Polynomial Ring in x, y, z over Rational Field' """ - return "Point on %s defined by the %s" % (self.scheme(), - self.prime_ideal()) + return "Point on %s defined by the %s" % (self.scheme(), self.prime_ideal()) def prime_ideal(self): """ diff --git a/src/sage/schemes/generic/scheme.py b/src/sage/schemes/generic/scheme.py index 20d194e8085..f84432b66ac 100644 --- a/src/sage/schemes/generic/scheme.py +++ b/src/sage/schemes/generic/scheme.py @@ -7,6 +7,7 @@ - Volker Braun (2011-08-11): documenting, improving, refactoring. """ + # **************************************************************************** # Copyright (C) 2011 Volker Braun # Copyright (C) 2008 Kiran Kedlaya @@ -93,10 +94,10 @@ def __init__(self, X=None, category=None): # X is a morphism of Rings self._base_ring = X.codomain() else: - raise ValueError('The base must be defined by a scheme, ' - 'scheme morphism, or commutative ring.') + raise ValueError('The base must be defined by a scheme, ' 'scheme morphism, or commutative ring.') from sage.categories.schemes import Schemes + if X is None: default_category = Schemes() else: @@ -104,8 +105,7 @@ def __init__(self, X=None, category=None): if category is None: category = default_category else: - assert category.is_subcategory(default_category), \ - "%s is not a subcategory of %s" % (category, default_category) + assert category.is_subcategory(default_category), "%s is not a subcategory of %s" % (category, default_category) Parent.__init__(self, self.base_ring(), category=category) @@ -228,6 +228,7 @@ def __call__(self, *args): """ if len(args) == 1: from sage.schemes.generic.morphism import SchemeMorphism_point + S = args[0] if S in CommutativeRings(): return self.point_homset(S) @@ -276,6 +277,7 @@ def point_homset(self, S=None): S = self.base_ring() SpecS = AffineScheme(S, self.base_ring()) from sage.schemes.generic.homset import SchemeHomset + return SchemeHomset(SpecS, self, as_point_homset=True) def point(self, v, check=True): @@ -304,6 +306,7 @@ def point(self, v, check=True): """ # todo: update elliptic curve stuff to take point_homset as argument from sage.schemes.elliptic_curves.ell_generic import EllipticCurve_generic + if isinstance(self, EllipticCurve_generic): try: return self._point(self.point_homset(), v, check=check) @@ -415,6 +418,7 @@ def base_scheme(self): self._base_scheme = AffineScheme(self._base_ring) else: from sage.schemes.generic.spec import SpecZ + self._base_scheme = SpecZ return self._base_scheme @@ -446,6 +450,7 @@ def base_morphism(self): except AttributeError: from sage.categories.schemes import Schemes from sage.schemes.generic.spec import SpecZ + SCH = Schemes() if hasattr(self, '_base_scheme'): self._base_morphism = self.Hom(self._base_scheme, category=SCH).natural_map() @@ -500,7 +505,7 @@ def dimension_absolute(self): ... NotImplementedError """ - raise NotImplementedError # override in derived class + raise NotImplementedError # override in derived class dimension = dimension_absolute @@ -520,7 +525,7 @@ def dimension_relative(self): ... NotImplementedError """ - raise NotImplementedError # override in derived class + raise NotImplementedError # override in derived class def identity_morphism(self): """ @@ -536,6 +541,7 @@ def identity_morphism(self): Defn: Identity map """ from sage.schemes.generic.morphism import SchemeMorphism_id + return SchemeMorphism_id(self) def hom(self, x, Y=None, check=True): @@ -604,6 +610,7 @@ def _Hom_(self, Y, category=None, check=True): """ from sage.schemes.generic.homset import SchemeHomset + return SchemeHomset(self, Y, category=category, check=check) point_set = point_homset @@ -642,7 +649,7 @@ def count_points(self, n): if not F.is_finite(): raise TypeError("Point counting only defined for schemes over finite fields") a = [len(self.rational_points())] - for i in range(2, n+1): + for i in range(2, n + 1): F1, psi = F.extension(i, map=True) S1 = self.change_ring(psi) a.append(len(S1.rational_points())) @@ -764,6 +771,7 @@ class AffineScheme(UniqueRepresentation, Scheme): For affine spaces over a base ring and subschemes thereof, see :class:`sage.schemes.generic.algebraic_scheme.AffineSpace`. """ + def __init__(self, R, S=None, category=None): """ Construct the affine scheme with coordinate ring `R`. @@ -935,8 +943,7 @@ def __call__(self, *args): """ if len(args) == 1: x = args[0] - if ((isinstance(x, self.element_class) and (x.parent() is self or x.parent() == self)) - or (isinstance(x, Ideal_generic) and x.ring() is self.coordinate_ring())): + if (isinstance(x, self.element_class) and (x.parent() is self or x.parent() == self)) or (isinstance(x, Ideal_generic) and x.ring() is self.coordinate_ring()): # Construct a topological point from x. return self._element_constructor_(x) try: @@ -985,6 +992,7 @@ def _an_element_(self): """ if self.coordinate_ring() is ZZ: from sage.arith.misc import random_prime + return self(ZZ.ideal(random_prime(1000))) return self(self.coordinate_ring().zero_ideal()) @@ -1068,8 +1076,7 @@ def base_extend(self, R): return AffineScheme(self.coordinate_ring().base_extend(R), self.base_ring()) if not self.base_scheme() == R.base_scheme(): raise ValueError('the new base scheme must be a scheme over the old base scheme') - return AffineScheme(self.coordinate_ring().base_extend(R.coordinate_ring()), - self.base_ring()) + return AffineScheme(self.coordinate_ring().base_extend(R.coordinate_ring()), self.base_ring()) def _point_homset(self, *args, **kwds): """ @@ -1083,6 +1090,7 @@ def _point_homset(self, *args, **kwds): Set of rational points of Spectrum of Integer Ring """ from sage.schemes.affine.affine_homset import SchemeHomset_points_spec + return SchemeHomset_points_spec(*args, **kwds) def hom(self, x, Y=None): diff --git a/src/sage/schemes/generic/spec.py b/src/sage/schemes/generic/spec.py index 5c699c0d004..63bef5073af 100644 --- a/src/sage/schemes/generic/spec.py +++ b/src/sage/schemes/generic/spec.py @@ -89,6 +89,7 @@ class SpecFunctor(Functor, UniqueRepresentation): """ The Spec functor. """ + def __init__(self, base_ring=None): """ EXAMPLES:: @@ -141,8 +142,7 @@ def _latex_(self): sage: latex(SpecFunctor()) \mathrm{Spec}\colon \mathbf{CommutativeRings} \longrightarrow \mathbf{Schemes} """ - return r'\mathrm{{Spec}}\colon {} \longrightarrow {}'.format( - self.domain()._latex_(), self.codomain()._latex_()) + return r'\mathrm{{Spec}}\colon {} \longrightarrow {}'.format(self.domain()._latex_(), self.codomain()._latex_()) def _apply_functor(self, A): """ @@ -195,4 +195,5 @@ def _apply_functor_to_morphism(self, f): # Compatibility with older versions of this module from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.schemes.generic.spec', 'Spec', AffineScheme) diff --git a/src/sage/schemes/hyperelliptic_curves/constructor.py b/src/sage/schemes/hyperelliptic_curves/constructor.py index 557becec48f..cda7df3177d 100644 --- a/src/sage/schemes/hyperelliptic_curves/constructor.py +++ b/src/sage/schemes/hyperelliptic_curves/constructor.py @@ -57,9 +57,7 @@ ) -def HyperellipticCurve( - f, h=0, names = ['x', 'y'], check_squarefree: bool = True, distinguished_point=None -): +def HyperellipticCurve(f, h=0, names=['x', 'y'], check_squarefree: bool = True, distinguished_point=None): r""" Constructor function for creating a hyperelliptic curve with smooth model with polynomials `f`, `h`. @@ -252,9 +250,7 @@ def homogenize_defining_polynomial(f, h): # Compute the genus of the curve from f, h curve_genus = genus(f, h) if curve_genus == 0: - raise ValueError( - f"arguments f = {f} and h = {h} must define a curve of genus at least one." - ) + raise ValueError(f"arguments f = {f} and h = {h} must define a curve of genus at least one.") # Compute the smooth model for the hyperelliptic curve # using a weighted projective space diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py index d582c6419aa..29e9e61b182 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py @@ -95,9 +95,7 @@ class HyperellipticCurve_finite_field(hyperelliptic_generic.HyperellipticCurve_g [4, 24, 64, 288] """ - def __init__( - self, projective_model, f, h, genus: Integer, names=["x", "y"] - ) -> None: + def __init__(self, projective_model, f, h, genus: Integer, names=["x", "y"]) -> None: r""" Create a hyperelliptic curve over a finite field. @@ -354,21 +352,13 @@ def count_points_exhaustive(self, n=1, naive=False): [9, 27, 108, 675, 3069, 16302] """ g = self.genus() - a = [ - self.cardinality_exhaustive(extension_degree=i) - for i in range(1, min(n, g) + 1) - ] + a = [self.cardinality_exhaustive(extension_degree=i) for i in range(1, min(n, g) + 1)] if n <= g: return a if naive: - a.extend( - [ - self.cardinality_exhaustive(extension_degree=i) - for i in range(g + 1, n + 1) - ] - ) + a.extend([self.cardinality_exhaustive(extension_degree=i) for i in range(g + 1, n + 1)]) # let's not be too naive and compute the frobenius polynomial f = self.frobenius_polynomial_cardinalities(a=a) @@ -451,9 +441,7 @@ def count_points_hypellfrob(self, n=1, N=None, algorithm=None): lower_bound = (2 * g + 1) * (2 * N - 1) if p <= lower_bound: - raise ValueError( - f"p={p} should be greater than (2*g+1)(2*N-1)={lower_bound}" - ) + raise ValueError(f"p={p} should be greater than (2*g+1)(2*N-1)={lower_bound}") if algorithm == "traces": M = self.frobenius_matrix(N=N, algorithm="hypellfrob") @@ -943,9 +931,7 @@ def frobenius_matrix_hypellfrob(self, N=None): p = self.base_ring().characteristic() e = self.base_ring().degree() if e != 1: - raise NotImplementedError( - "Computation of Frobenius matrix only implemented for hyperelliptic curves defined over prime fields." - ) + raise NotImplementedError("Computation of Frobenius matrix only implemented for hyperelliptic curves defined over prime fields.") f, h = self.hyperelliptic_polynomials() if h != 0: @@ -1306,13 +1292,7 @@ def frobenius_polynomial(self): g = self.genus() f, h = self.hyperelliptic_polynomials() - if ( - e == 1 - and q - >= (2 * g + 1) * (2 * self._frobenius_coefficient_bound_charpoly() - 1) - and h == 0 - and f.degree() % 2 - ): + if e == 1 and q >= (2 * g + 1) * (2 * self._frobenius_coefficient_bound_charpoly() - 1) and h == 0 and f.degree() % 2: return self.frobenius_polynomial_matrix() if q % 2 == 1: return self.frobenius_polynomial_pari() diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py index 41cac187b2b..11e3e8d705c 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py @@ -48,9 +48,7 @@ """ -class HyperellipticCurve_g2( - hyperelliptic_generic.HyperellipticCurve_generic -): +class HyperellipticCurve_g2(hyperelliptic_generic.HyperellipticCurve_generic): def is_odd_degree(self): r""" Return ``True`` if the curve is an odd degree model. @@ -274,19 +272,13 @@ def absolute_igusa_invariants_kohel(self): return invariants.absolute_igusa_invariants_kohel(4 * f + h**2) -class HyperellipticCurve_g2_padic_field( - HyperellipticCurve_g2, HyperellipticCurve_padic_field -): +class HyperellipticCurve_g2_padic_field(HyperellipticCurve_g2, HyperellipticCurve_padic_field): pass -class HyperellipticCurve_g2_finite_field( - HyperellipticCurve_g2, HyperellipticCurve_finite_field -): +class HyperellipticCurve_g2_finite_field(HyperellipticCurve_g2, HyperellipticCurve_finite_field): pass -class HyperellipticCurve_g2_rational_field( - HyperellipticCurve_g2, HyperellipticCurve_rational_field -): +class HyperellipticCurve_g2_rational_field(HyperellipticCurve_g2, HyperellipticCurve_rational_field): pass diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py index 3b87ee14718..7e34c4a398f 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py @@ -201,15 +201,8 @@ def _latex_(self) -> str: y = self._printing_ring.gen() x = self._printing_ring.base_ring().gen() if h.is_zero(): - return ( - rf"\text{{Hyperelliptic Curve over ${R._latex_()}$ " - f"defined by ${(y**2)._latex_()} = {(f(x))._latex_()}$}}" - ) - return ( - rf"\text{{Hyperelliptic Curve over ${R._latex_()}$ " - f"defined by ${(y**2)._latex_()} + {(h(x) * y)._latex_()} = " - f"{(f(x))._latex_()}$}}" - ) + return rf"\text{{Hyperelliptic Curve over ${R._latex_()}$ " f"defined by ${(y**2)._latex_()} = {(f(x))._latex_()}$}}" + return rf"\text{{Hyperelliptic Curve over ${R._latex_()}$ " f"defined by ${(y**2)._latex_()} + {(h(x) * y)._latex_()} = " f"{(f(x))._latex_()}$}}" def genus(self) -> Integer: r""" @@ -516,9 +509,7 @@ def split_G_plus_minus(self): g[d] = alpha_plus for i in range(d - 1, -1, -1): # We need (g * (g + h))[x^(i + d)] to match f_{i + d} - the_rest = g[d] * h[i] + sum( - g[k] * (g[i + d - k] + h[i + d - k]) for k in range(i + 1, d) - ) + the_rest = g[d] * h[i] + sum(g[k] * (g[i + d - k] + h[i + d - k]) for k in range(i + 1, d)) g[i] = (f[i + d] - the_rest) / (2 * g[d] + h[d]) G_plus = self._polynomial_ring(g) @@ -944,9 +935,7 @@ def rational_weierstrass_points(self): f, h = self.hyperelliptic_polynomials() F = h**2 + 4 * f - affine_weierstrass_points = [ - self(r, -h(r) / 2) for r in F.roots(multiplicities=False) - ] + affine_weierstrass_points = [self(r, -h(r) / 2) for r in F.roots(multiplicities=False)] if self.is_ramified(): # the point at infinity is Weierstrass return self.points_at_infinity() + affine_weierstrass_points @@ -1018,9 +1007,7 @@ def distinguished_point(self): return self._distinguished_point if self.base_ring().characteristic() == 0: - raise ValueError( - "in characteristic 0, a distinguished_point needs to be specified with `set_distinguished_point`" - ) + raise ValueError("in characteristic 0, a distinguished_point needs to be specified with `set_distinguished_point`") # in the inert case we choose a point with minimal x-coordinate for x0 in self.base_ring(): @@ -1383,9 +1370,7 @@ def odd_degree_model(self): f, h = self._hyperelliptic_polynomials if f.base_ring().characteristic() == 2: - raise ValueError( - "There are no odd degree models over a field with characteristic 2." - ) + raise ValueError("There are no odd degree models over a field with characteristic 2.") if h: f = 4 * f + h**2 # move h to the right side of the equation if f.degree() % 2: @@ -1548,13 +1533,9 @@ def local_coordinates_at_nonweierstrass(self, P, prec=20, name="t"): - Sabrina Kunzweiler, Gareth Ma, Giacomo Pope (2024): adapt to smooth model """ if P[2] == 0: - raise TypeError( - f"P = {P} is a point at infinity. Use local_coordinates_at_infinity instead" - ) + raise TypeError(f"P = {P} is a point at infinity. Use local_coordinates_at_infinity instead") if self.is_weierstrass_point(P): - raise TypeError( - f"P = {P} is a Weierstrass point. Use local_coordinates_at_weierstrass instead" - ) + raise TypeError(f"P = {P} is a Weierstrass point. Use local_coordinates_at_weierstrass instead") f, h = self.hyperelliptic_polynomials() a, b = self.affine_coordinates(P) @@ -1624,13 +1605,9 @@ def local_coordinates_at_weierstrass(self, P, prec=20, name="t"): - Sabrina Kunzweiler, Gareth Ma, Giacomo Pope (2024): adapt to smooth model """ if P[2] == 0: - raise TypeError( - f"P = {P} is a point at infinity. Use local_coordinates_at_infinity instead" - ) + raise TypeError(f"P = {P} is a point at infinity. Use local_coordinates_at_infinity instead") if not self.is_weierstrass_point(P): - raise TypeError( - f"P = {P} is not a Weierstrass point. Use local_coordinates_at_nonweierstrass instead" - ) + raise TypeError(f"P = {P} is not a Weierstrass point. Use local_coordinates_at_nonweierstrass instead") L = PowerSeriesRing(self.base_ring(), name, default_prec=prec) t = L.gen() @@ -1705,9 +1682,7 @@ def local_coordinates_at_infinity_ramified(self, prec=20, name="t"): """ if not self.is_ramified(): - raise TypeError( - "The point at infinity is not a Weierstrass point. Use local_coordinates_at_infinity_split instead!" - ) + raise TypeError("The point at infinity is not a Weierstrass point. Use local_coordinates_at_infinity_split instead!") g = self.genus() f, h = self.hyperelliptic_polynomials() @@ -1724,9 +1699,7 @@ def local_coordinates_at_infinity_ramified(self, prec=20, name="t"): for _ in range((prec + 2).bit_length()): xt = xt - w(xt) / wprime(xt) yt = xt ** (g + 1) * t - return xt + O(t ** (prec + 2)), yt + O( - t ** (prec + 2) - ) # TODO: Why the prec+2 ? Not sure if this is adapted in the correct way. + return xt + O(t ** (prec + 2)), yt + O(t ** (prec + 2)) # TODO: Why the prec+2 ? Not sure if this is adapted in the correct way. def local_coordinates_at_infinity_split(self, P, prec=20, name="t"): r""" @@ -1782,13 +1755,9 @@ def local_coordinates_at_infinity_split(self, P, prec=20, name="t"): """ if not self.is_split(): - raise TypeError( - "The point at infinity is a Weierstrass point. Use local_coordinates_at_infinity_ramified instead!" - ) + raise TypeError("The point at infinity is a Weierstrass point. Use local_coordinates_at_infinity_ramified instead!") if not P[2] == 0: - raise TypeError( - f"P = {P} is not a point at infinity. Use local_coordinates_at_nonweierstrass or local_coordinates_at_weierstrass instead" - ) + raise TypeError(f"P = {P} is not a point at infinity. Use local_coordinates_at_nonweierstrass or local_coordinates_at_weierstrass instead") K = LaurentSeriesRing(self.base_ring(), name, default_prec=prec + 2) t = K.gen() diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py index 16b199a5637..936726f0144 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py @@ -74,9 +74,7 @@ class HyperellipticCurve_padic_field(hyperelliptic_generic.HyperellipticCurve_ge 3*7 + 4*7^2 + 5*7^4 + 2*7^5 + 2*7^6 + 6*7^7 + 4*7^8 + O(7^9) """ - def __init__( - self, projective_model, f, h, genus: Integer, names=["x", "y"] - ) -> None: + def __init__(self, projective_model, f, h, genus: Integer, names=["x", "y"]) -> None: r""" Create a hyperelliptic curve over a p-adic field. @@ -180,9 +178,7 @@ def local_analytic_interpolation(self, P, Q): raise ValueError(f"{P} and {Q} are not in the same residue disc") disc = self.residue_disc(P) t = PowerSeriesRing(self.base_ring(), "t", prec).gen(0) - if disc == self.change_ring(self.base_ring().residue_field())( - 1, 0, 0 - ): # Infinite disc + if disc == self.change_ring(self.base_ring().residue_field())(1, 0, 0): # Infinite disc x, y = self.local_coordinates_at_infinity_ramified(2 * prec) g = self.genus() return (x * t**2, y * t ** (2 * g + 2), t ** (2)) @@ -389,16 +385,12 @@ def residue_disc(self, P): if HF.is_split(): [Q1, Q2] = HF.points_at_infinity() alpha = P[1].expansion(0) / P[0].expansion(0) ** (self.genus() + 1) - if ( - alpha == Q1[1] - ): # we assume that the points at infinity are normalized, w.r.t. x ! + if alpha == Q1[1]: # we assume that the points at infinity are normalized, w.r.t. x ! return Q1 if alpha == Q2[1]: return Q2 raise ValueError("Unexpected behaviour.") - raise ValueError( - "The reduction of the hyperelliptic curve is inert. This case should not appear." - ) + raise ValueError("The reduction of the hyperelliptic curve is inert. This case should not appear.") def is_same_disc(self, P, Q) -> bool: r""" @@ -486,9 +478,7 @@ def tiny_integrals(self, F, P, Q): except TypeError: # if f is a constant, not callable f_dt = f * dt if x.valuation() != -2: - I = sum( - f_dt[n] / (n + 1) for n in range(f_dt.degree() + 1) - ) # \int_0^1 f dt + I = sum(f_dt[n] / (n + 1) for n in range(f_dt.degree() + 1)) # \int_0^1 f dt else: If_dt = f_dt.integral().laurent_polynomial() I = If_dt(Q[1] / Q[0] ** (g + 1)) - If_dt(P[1] / P[0] ** (g + 1)) @@ -715,14 +705,7 @@ def coleman_integrals_on_basis(self, P, Q, algorithm=None): offset = (2 * g - 1) * max(TPv, TQv) if offset == +Infinity: offset = (2 * g - 1) * min(TPv, TQv) - if ( - offset > prec - and (xTPv < 0 or xTQv < 0) - and ( - self.residue_disc(P) == self.change_ring(GF(p))(1, 0, 0) - or self.residue_disc(Q) == self.change_ring(GF(p))(1, 0, 0) - ) - ): + if offset > prec and (xTPv < 0 or xTQv < 0) and (self.residue_disc(P) == self.change_ring(GF(p))(1, 0, 0) or self.residue_disc(Q) == self.change_ring(GF(p))(1, 0, 0)): newprec = offset + prec K = pAdicField(p, newprec) A = PolynomialRing(RationalField(), "x") @@ -748,9 +731,7 @@ def coleman_integrals_on_basis(self, P, Q, algorithm=None): try: M_frob, forms = self._frob_calc except AttributeError: - M_frob, forms = self._frob_calc = ( - monsky_washnitzer.matrix_of_frobenius_hyperelliptic(self) - ) + M_frob, forms = self._frob_calc = monsky_washnitzer.matrix_of_frobenius_hyperelliptic(self) prof("eval f") R = forms[0].base_ring() try: @@ -946,43 +927,17 @@ def coleman_integral(self, w, P, Q, algorithm="None"): return 0 if f == 0: return sum([vec[i] * basis_values[i] for i in range(dim)]) - if ( - w._coeff(x, -y) * x.derivative() / (-2 * y) - + w._coeff(x, y) * x.derivative() / (2 * y) - == 0 - ): - return ( - self.coleman_integral( - w, self(Q[0], -Q[1]), self(Q[0], Q[1]), algorithm - ) - / 2 - ) - raise ValueError( - "The differential is not odd: use coleman_integral_from_weierstrass_via_boundary" - ) + if w._coeff(x, -y) * x.derivative() / (-2 * y) + w._coeff(x, y) * x.derivative() / (2 * y) == 0: + return self.coleman_integral(w, self(Q[0], -Q[1]), self(Q[0], Q[1]), algorithm) / 2 + raise ValueError("The differential is not odd: use coleman_integral_from_weierstrass_via_boundary") if self.is_weierstrass_point(Q): if f == 0: return sum([vec[i] * basis_values[i] for i in range(dim)]) - if ( - w._coeff(x, -y) * x.derivative() / (-2 * y) - + w._coeff(x, y) * x.derivative() / (2 * y) - == 0 - ): - return ( - -self.coleman_integral( - w, self(P[0], -P[1]), self(P[0], P[1]), algorithm - ) - / 2 - ) - raise ValueError( - "The differential is not odd: use coleman_integral_from_weierstrass_via_boundary" - ) - return ( - f(Q[0], Q[1]) - - f(P[0], P[1]) - + sum([vec[i] * basis_values[i] for i in range(dim)]) - ) # this is just a dot product... + if w._coeff(x, -y) * x.derivative() / (-2 * y) + w._coeff(x, y) * x.derivative() / (2 * y) == 0: + return -self.coleman_integral(w, self(P[0], -P[1]), self(P[0], P[1]), algorithm) / 2 + raise ValueError("The differential is not odd: use coleman_integral_from_weierstrass_via_boundary") + return f(Q[0], Q[1]) - f(P[0], P[1]) + sum([vec[i] * basis_values[i] for i in range(dim)]) # this is just a dot product... def frobenius(self, P=None): r""" @@ -1063,9 +1018,7 @@ def _frob(P): c = uN2.expansion(0) v = uN2.valuation() a = uN2.parent().gen() - uN = self.newton_sqrt( - uN2, c.sqrt() * a ** (v // 2), K.precision_cap() - ) + uN = self.newton_sqrt(uN2, c.sqrt() * a ** (v // 2), K.precision_cap()) yres = y0**p * uN xres = x0**p if (yres - y0).valuation() == 0: @@ -1239,9 +1192,7 @@ def P_to_S(self, P, S): prec2 = prec * deg x, y = self.local_coord(P, prec2) g = self.genus() - integrals = [ - ((x**k * x.derivative() / (2 * y)).integral()) for k in range(2 * g) - ] + integrals = [((x**k * x.derivative() / (2 * y)).integral()) for k in range(2 * g)] val = [I(S[1]) for I in integrals] return vector(val) @@ -1339,9 +1290,7 @@ def S_to_Q(self, S, Q): try: M_frob, forms = self._frob_calc except AttributeError: - M_frob, forms = self._frob_calc = ( - monsky_washnitzer.matrix_of_frobenius_hyperelliptic(self) - ) + M_frob, forms = self._frob_calc = monsky_washnitzer.matrix_of_frobenius_hyperelliptic(self) try: HJ = self._curve_over_ram_extn K = HJ.base_ring() @@ -1358,12 +1307,8 @@ def S_to_Q(self, S, Q): else: P = self(ZZ(FS[0].expansion(0)), ZZ(FS[1].expansion(0))) x, y = self.local_coord(P, prec2) - integrals = [ - (x**i * x.derivative() / (2 * y)).integral() for i in range(dim) - ] - S_to_FS = vector( - [I.polynomial()(FS[1]) - I.polynomial()(S[1]) for I in integrals] - ) + integrals = [(x**i * x.derivative() / (2 * y)).integral() for i in range(dim)] + S_to_FS = vector([I.polynomial()(FS[1]) - I.polynomial()(S[1]) for I in integrals]) if HJ(Q[0], Q[1], Q[2]) == HJ(FQ[0], FQ[1], FQ[2]): FQ_to_Q = V(dim * [0]) else: diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py index 1839d700cdc..03c24ef7fd2 100644 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py @@ -26,12 +26,8 @@ from sage.schemes.hyperelliptic_curves import hyperelliptic_generic -class HyperellipticCurve_rational_field( - hyperelliptic_generic.HyperellipticCurve_generic -): - def __init__( - self, projective_model, f, h, genus: Integer, names=["x", "y"] - ) -> None: +class HyperellipticCurve_rational_field(hyperelliptic_generic.HyperellipticCurve_generic): + def __init__(self, projective_model, f, h, genus: Integer, names=["x", "y"]) -> None: r""" Create a hyperelliptic curve over the rationals. @@ -87,9 +83,7 @@ def matrix_of_frobenius(self, p, prec=20): K = p else: K = pAdicField(p, prec) - frob_p, _ = monsky_washnitzer.matrix_of_frobenius_hyperelliptic( - self.change_ring(K) - ) + frob_p, _ = monsky_washnitzer.matrix_of_frobenius_hyperelliptic(self.change_ring(K)) return frob_p def lseries(self, prec=53): diff --git a/src/sage/schemes/hyperelliptic_curves/invariants.py b/src/sage/schemes/hyperelliptic_curves/invariants.py index 21d99cf9e1d..974b4cdd83f 100644 --- a/src/sage/schemes/hyperelliptic_curves/invariants.py +++ b/src/sage/schemes/hyperelliptic_curves/invariants.py @@ -88,9 +88,7 @@ def differential_operator(f, g, k): (x, y) = f.parent().gens() n = max(ZZ(f.degree()), ZZ(k)) m = max(ZZ(g.degree()), ZZ(k)) - R, (fx, fy, gx, gy) = PolynomialRing( - f.base_ring(), 4, "dfdx,dfdy,dgdx,dgdy" - ).objgens() + R, (fx, fy, gx, gy) = PolynomialRing(f.base_ring(), 4, "dfdx,dfdy,dgdx,dgdy").objgens() const = (m - k).factorial() * (n - k).factorial() / (m.factorial() * n.factorial()) return f.base_ring()(const) * (fx * gy - fy * gx) ** k @@ -116,9 +114,7 @@ def diffsymb(U, f, g): 2*x*y^4 + 3*x^2*y^2 """ (x, y) = f.parent().gens() - R, (fx, fy, gx, gy) = PolynomialRing( - f.base_ring(), 4, "dfdx,dfdy,dgdx,dgdy" - ).objgens() + R, (fx, fy, gx, gy) = PolynomialRing(f.base_ring(), 4, "dfdx,dfdy,dgdx,dgdy").objgens() res = 0 for coeff, mon in list(U): m = R(mon) @@ -246,14 +242,7 @@ def clebsch_to_igusa(A, B, C, D): I2 = -120 * A I4 = -720 * A**2 + 6750 * B I6 = 8640 * A**3 - 108000 * A * B + 202500 * C - I10 = ( - -62208 * A**5 - + 972000 * A**3 * B - + 1620000 * A**2 * C - - 3037500 * A * B**2 - - 6075000 * B * C - - 4556250 * D - ) + I10 = -62208 * A**5 + 972000 * A**3 * B + 1620000 * A**2 * C - 3037500 * A * B**2 - 6075000 * B * C - 4556250 * D return (I2, I4, I6, I10) @@ -279,17 +268,7 @@ def igusa_to_clebsch(I2, I4, I6, I10): A = -(+I2) / 120 B = -(-(I2**2) - 20 * I4) / 135000 C = -(+(I2**3) + 80 * I2 * I4 - 600 * I6) / 121500000 - D = ( - -( - +9 * I2**5 - + 700 * I2**3 * I4 - - 3600 * I2**2 * I6 - - 12400 * I2 * I4**2 - + 48000 * I4 * I6 - + 10800000 * I10 - ) - / 49207500000000 - ) + D = -(+9 * I2**5 + 700 * I2**3 * I4 - 3600 * I2**2 * I6 - 12400 * I2 * I4**2 + 48000 * I4 * I6 + 10800000 * I10) / 49207500000000 return (A, B, C, D) @@ -317,10 +296,7 @@ def clebsch_invariants(f): """ R = f.parent().base_ring() if R.characteristic() in [2, 3, 5]: - raise NotImplementedError( - "Invariants of binary sextics/genus 2 hyperelliptic " - "curves not implemented in characteristics 2, 3, and 5" - ) + raise NotImplementedError("Invariants of binary sextics/genus 2 hyperelliptic " "curves not implemented in characteristics 2, 3, and 5") U = ubs(f) L = U["A"], U["B"], U["C"], U["D"] diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py b/src/sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py index e47b37617fd..8fa593d3111 100644 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py @@ -197,11 +197,11 @@ def get_is_geom_field(f, C, bad_primes, B=200): # if f was odd to begin with, then f_odd = f assert f_odd.degree() == 5 - if (4*f_odd + h_odd**2).degree() == 5: - f_new = 4*f_odd + h_odd**2 + if (4 * f_odd + h_odd**2).degree() == 5: + f_new = 4 * f_odd + h_odd**2 if f_new.is_irreducible(): # i.e. the Jacobian is geometrically simple - f_disc_odd_prime_exponents = [v for _,v in f_new.discriminant().prime_to_S_part([ZZ(2)]).factor()] + f_disc_odd_prime_exponents = [v for _, v in f_new.discriminant().prime_to_S_part([ZZ(2)]).factor()] if 1 in f_disc_odd_prime_exponents: return (True, True) # Theorem 4.8 (2) # At this point we are in the situation of Algorithm 4.10 @@ -219,12 +219,12 @@ def get_is_geom_field(f, C, bad_primes, B=200): if G.order() in [360, 720]: return (True, True) # Algorithm 4.10 Step 2 - R = PolynomialRing(ZZ,2,"xv") - x,v = R.gens() - T = PolynomialRing(QQ,'v') + R = PolynomialRing(ZZ, 2, "xv") + x, v = R.gens() + T = PolynomialRing(QQ, 'v') g = v - x**12 - for p in prime_range(3,B): + for p in prime_range(3, B): if p not in bad_primes: fp = C.change_ring(FiniteField(p)).frobenius_polynomial() @@ -233,10 +233,10 @@ def get_is_geom_field(f, C, bad_primes, B=200): if fp12.is_irreducible(): # i.e. the Jacobian is geometrically simple - f_disc_odd_prime_exponents = [v for _,v in f.discriminant().prime_to_S_part([ZZ(2)]).factor()] + f_disc_odd_prime_exponents = [v for _, v in f.discriminant().prime_to_S_part([ZZ(2)]).factor()] if 1 in f_disc_odd_prime_exponents: return (True, True) # Theorem 4.8 (2) - return (True, False) # Algorithm 4.10 Step 3 plus Prop 4.7 as above + return (True, False) # Algorithm 4.10 Step 3 plus Prop 4.7 as above return (False, False) @@ -292,12 +292,12 @@ def is_geom_trivial_when_field(C, bad_primes, B=200): """ running_gcd = 0 - R = PolynomialRing(ZZ,2,"xv") - x,v = R.gens() - T = PolynomialRing(QQ,'v') + R = PolynomialRing(ZZ, 2, "xv") + x, v = R.gens() + T = PolynomialRing(QQ, 'v') g = v - x**4 - for p in prime_range(3,B): + for p in prime_range(3, B): if p not in bad_primes: Cp = C.change_ring(FiniteField(p)) fp = Cp.frobenius_polynomial() @@ -305,7 +305,7 @@ def is_geom_trivial_when_field(C, bad_primes, B=200): # This defines the polynomial f_v**[4] from the paper fp4 = T(R(fp).resultant(g)) if fp4.is_irreducible(): - running_gcd = gcd(running_gcd, NumberField(fp,'a').discriminant()) + running_gcd = gcd(running_gcd, NumberField(fp, 'a').discriminant()) if running_gcd <= 24: return True return False diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_g2_generic.py b/src/sage/schemes/hyperelliptic_curves/jacobian_g2_generic.py index 332e78eaef2..da675b39331 100644 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_g2_generic.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_g2_generic.py @@ -6,7 +6,6 @@ - Sabrina Kunzweiler, Gareth Ma, Giacomo Pope (2024): adapt to smooth model """ - # **************************************************************************** # Copyright (C) 2025 Sabrina Kunzweiler # 2025 Gareth Ma @@ -52,16 +51,10 @@ def _point_homset(self, *args, **kwds): """ H = self.curve() if H.is_ramified(): - return jacobian_g2_homset_ramified.HyperellipticJacobianHomsetRamified_g2( - *args, **kwds - ) + return jacobian_g2_homset_ramified.HyperellipticJacobianHomsetRamified_g2(*args, **kwds) if H.is_split(): - return jacobian_g2_homset_split.HyperellipticJacobianHomsetSplit_g2( - *args, **kwds - ) - return jacobian_g2_homset_inert.HyperellipticJacobianHomsetInert_g2( - *args, **kwds - ) + return jacobian_g2_homset_split.HyperellipticJacobianHomsetSplit_g2(*args, **kwds) + return jacobian_g2_homset_inert.HyperellipticJacobianHomsetInert_g2(*args, **kwds) def kummer_surface(self): r""" diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py b/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py index a8bcc89bbf3..3821a575b8b 100644 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py @@ -93,6 +93,7 @@ def is_parent_of(self, element): True """ from sage.structure.element import parent as get_parent + p = get_parent(element) return p == self or p == self.point_homset() @@ -146,9 +147,7 @@ def _point_homset(self, *args, **kwds): # TODO: make a constructor for this?? H = self.curve() if H.is_ramified(): - return jacobian_homset_ramified.HyperellipticJacobianHomsetRamified( - *args, **kwds - ) + return jacobian_homset_ramified.HyperellipticJacobianHomsetRamified(*args, **kwds) if H.is_split(): return jacobian_homset_split.HyperellipticJacobianHomsetSplit(*args, **kwds) return jacobian_homset_inert.HyperellipticJacobianHomsetInert(*args, **kwds) @@ -418,18 +417,12 @@ def geometric_endomorphism_algebra_is_field(self, B=200, proof=False): return True C = self.curve() if C.genus() != 2: - raise NotImplementedError( - "Current implementation requires the curve to be of genus 2" - ) + raise NotImplementedError("Current implementation requires the curve to be of genus 2") if C.base_ring() != QQ: - raise NotImplementedError( - "Current implementation requires the curve to be defined over the rationals" - ) + raise NotImplementedError("Current implementation requires the curve to be defined over the rationals") f, h = C.hyperelliptic_polynomials() if h != 0: - raise NotImplementedError( - "Current implementation requires the curve to be in the form y^2 = f(x)" - ) + raise NotImplementedError("Current implementation requires the curve to be in the form y^2 = f(x)") red_data = genus2reduction(0, f) cond_C = red_data.conductor # WARNING: this is only the prime_to_2 conductor. bad_primes = cond_C.prime_divisors() @@ -443,9 +436,7 @@ def geometric_endomorphism_algebra_is_field(self, B=200, proof=False): self._have_established_geometrically_field = True return True if proof: - raise NotImplementedError( - "Rigorous computation of lower bounds of endomorphism algebras has not yet been implemented." - ) + raise NotImplementedError("Rigorous computation of lower bounds of endomorphism algebras has not yet been implemented.") return False def geometric_endomorphism_ring_is_ZZ(self, B=200, proof=False): @@ -556,7 +547,5 @@ def geometric_endomorphism_ring_is_ZZ(self, B=200, proof=False): if is_abs_simple and is_geom_trivial_when_field(self.curve(), self._bad_primes): return True if proof: - raise NotImplementedError( - "Rigorous computation of lower bounds of endomorphism rings has not yet been implemented." - ) + raise NotImplementedError("Rigorous computation of lower bounds of endomorphism rings has not yet been implemented.") return False diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_homset_generic.py b/src/sage/schemes/hyperelliptic_curves/jacobian_homset_generic.py index 64e12ba432d..b7a9e9b0a10 100644 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_homset_generic.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_homset_generic.py @@ -197,13 +197,9 @@ def cardinality(self, extension_degree=1) -> Integer: """ K = self.extended_curve().base_ring() if not isinstance(K, FiniteField_generic): - raise NotImplementedError( - "cardinality is only implemented for Jacobians over finite fields" - ) + raise NotImplementedError("cardinality is only implemented for Jacobians over finite fields") - return Integer( - product(1 - r**extension_degree for r in self._curve_frobenius_roots()) - ) + return Integer(product(1 - r**extension_degree for r in self._curve_frobenius_roots())) def count_points(self, n=1): r""" @@ -394,20 +390,14 @@ def _element_constructor_(self, *args, check=True): # this case will now be handled below. args = P1.uv() elif isinstance(P1, SchemeMorphism_point_weighted_projective_ring): - args = args + ( - self.extended_curve().distinguished_point(), - ) # this case will now be handled below. + args = args + (self.extended_curve().distinguished_point(),) # this case will now be handled below. else: - raise ValueError( - "the input must consist of one or two points, or Mumford coordinates" - ) + raise ValueError("the input must consist of one or two points, or Mumford coordinates") if len(args) == 2: P1 = args[0] P2 = args[1] - if isinstance( - P1, SchemeMorphism_point_weighted_projective_ring - ) and isinstance(P2, SchemeMorphism_point_weighted_projective_ring): + if isinstance(P1, SchemeMorphism_point_weighted_projective_ring) and isinstance(P2, SchemeMorphism_point_weighted_projective_ring): u1, v1 = self.point_to_mumford_coordinates(P1) P2_inv = self.extended_curve().hyperelliptic_involution(P2) u2, v2 = self.point_to_mumford_coordinates(P2_inv) @@ -418,9 +408,7 @@ def _element_constructor_(self, *args, check=True): u = R(P1) v = R(P2) except ValueError: - raise ValueError( - "the input must consist of one or two points, or Mumford coordinates" - ) + raise ValueError("the input must consist of one or two points, or Mumford coordinates") if len(args) > 2: raise ValueError("at most two arguments are allowed as input") @@ -494,12 +482,8 @@ def _cantor_composition_generic(self, u1, v1, u2, v2): g = H.genus() # Ensure D1 and D2 are semi-reduced divisors - assert v1.degree() < u1.degree() and v2.degree() < u2.degree(), ( - "The degree of bi must be smaller than ai" - ) - assert u1.degree() <= 2 * g + 2 and u2.degree() <= 2 * g + 2, ( - f"The degree of ai must be smaller than 2g+2, {u1.degree()}, {u2.degree()}" - ) + assert v1.degree() < u1.degree() and v2.degree() < u2.degree(), "The degree of bi must be smaller than ai" + assert u1.degree() <= 2 * g + 2 and u2.degree() <= 2 * g + 2, f"The degree of ai must be smaller than 2g+2, {u1.degree()}, {u2.degree()}" # Special case: duplication law if u1 == u2 and v1 == v2: @@ -652,18 +636,13 @@ def lift_u(self, u, all=False): if H_is_split: if not all: return self._morphism_element(self, R.one(), R.zero(), 0) - return [ - self._morphism_element(self, R.one(), R.zero(), n) - for n in range(g + 1) - ] + return [self._morphism_element(self, R.one(), R.zero(), n) for n in range(g + 1)] if not all: return self.zero() return [self.zero()] if not isinstance(K, FiniteField_generic) or K.degree() != 1: - raise NotImplementedError( - "lift_u is only implemented for Jacobians over a finite field of prime order" - ) + raise NotImplementedError("lift_u is only implemented for Jacobians over a finite field of prime order") f, h = H.hyperelliptic_polynomials() u1, v1 = R.one(), R.zero() @@ -693,9 +672,7 @@ def postprocess_uv(u1, v1, n=None): if H.is_split(): if n is None or not (0 <= n <= g - u1.degree()): # this is an internal function - raise ValueError( - f"bug: n must be an integer between 0 and {g - u1.degree()}" - ) + raise ValueError(f"bug: n must be an integer between 0 and {g - u1.degree()}") return self._morphism_element(self, u1, v1, n, check=False) # We need to ensure the degree of u is even @@ -848,9 +825,7 @@ def random_element(self, fast=False, *args, **kwargs): 16 """ if not isinstance(self.base_ring(), FiniteField_generic): - raise NotImplementedError( - "random element of Jacobian is only implemented over Finite Fields" - ) + raise NotImplementedError("random element of Jacobian is only implemented over Finite Fields") if fast: return self._random_element_rational(*args, **kwargs) @@ -1000,6 +975,7 @@ def abelian_group(self): n = self.order() g = self.curve().genus() from sage.groups.additive_abelian.additive_abelian_wrapper import AdditiveAbelianGroupWrapper + A = AdditiveAbelianGroupWrapper(self, [], []) for fast in (True, False): for _ in range(99 * g): diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_homset_inert.py b/src/sage/schemes/hyperelliptic_curves/jacobian_homset_inert.py index cff47a6a116..75e9fdc7101 100644 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_homset_inert.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_homset_inert.py @@ -74,8 +74,6 @@ def zero(self, check=True): """ g = self.curve().genus() if g % 2: - raise ValueError( - "unable to perform arithmetic for inert models of odd genus" - ) + raise ValueError("unable to perform arithmetic for inert models of odd genus") R = self.curve().polynomial_ring() return self._morphism_element(self, R.one(), R.zero(), check=check) diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_homset_split.py b/src/sage/schemes/hyperelliptic_curves/jacobian_homset_split.py index e017e29430c..6bff8cc3c81 100644 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_homset_split.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_homset_split.py @@ -190,9 +190,7 @@ def _element_constructor_(self, *args, check=True): raise ValueError("at most three arguments are allowed as input") if len(args) == 0 or (len(args) == 1 and args[0] == ()): - return self._morphism_element( - self, R.one(), R.zero(), n=(g + 1) // 2, check=check - ) + return self._morphism_element(self, R.one(), R.zero(), n=(g + 1) // 2, check=check) if len(args) == 1 and isinstance(args[0], (list, tuple)): args = args[0] @@ -209,20 +207,14 @@ def _element_constructor_(self, *args, check=True): args = tuple(P1) elif isinstance(P1, SchemeMorphism_point_weighted_projective_ring): # TODO: Test this path when args is a tuple - args = args + ( - self.curve().distinguished_point(), - ) # this case will now be handled below. + args = args + (self.curve().distinguished_point(),) # this case will now be handled below. else: - raise ValueError( - "the input must consist of one or two points, or Mumford coordinates" - ) + raise ValueError("the input must consist of one or two points, or Mumford coordinates") if len(args) == 2 or len(args) == 3: P1 = args[0] P2 = args[1] - if isinstance( - P1, SchemeMorphism_point_weighted_projective_ring - ) and isinstance(P2, SchemeMorphism_point_weighted_projective_ring): + if isinstance(P1, SchemeMorphism_point_weighted_projective_ring) and isinstance(P2, SchemeMorphism_point_weighted_projective_ring): if len(args) == 3: raise ValueError("the input must consist of at most two points") u1, v1, n1 = self.point_to_mumford_coordinates(P1) @@ -237,13 +229,9 @@ def _element_constructor_(self, *args, check=True): if len(args) == 3 and isinstance(args[2], (int, Integer)): n = args[2] else: - n = ( - g - u.degree() + 1 - ) // 2 # TODO: do we really want to allow this input? + n = (g - u.degree() + 1) // 2 # TODO: do we really want to allow this input? else: - raise ValueError( - "the input must consist of one or two points, or Mumford coordinates" - ) + raise ValueError("the input must consist of one or two points, or Mumford coordinates") return self._morphism_element(self, u, v, n=n, check=check) diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py b/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py index 911a0a112ed..ba466cfe2e6 100644 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py @@ -70,9 +70,7 @@ def __init__(self, parent, u, v, check=True) -> None: # Ensure the divisor is valid if check: f, h = parent.curve().hyperelliptic_polynomials() - assert (v**2 + v * h - f) % u == 0, ( - f"u={u}, v={v} do not define a divisor on the Jacobian" - ) + assert (v**2 + v * h - f) % u == 0, f"u={u}, v={v} do not define a divisor on the Jacobian" # TODO: should we automatically do reduction here if the degree of u is # too large? @@ -274,9 +272,7 @@ def order(self) -> Integer: 38 """ if not isinstance(self.base_ring(), FiniteField_generic): - raise NotImplementedError( - "this is only implemented for Jacobians over a finite field" - ) + raise NotImplementedError("this is only implemented for Jacobians over a finite field") n = self.parent().order() return order_from_multiple(self, n) @@ -591,9 +587,7 @@ def _add_(self, other) -> Self: # Step three: compose and then reduce at infinity to ensure # unique representation of D while n3 < 0 or n3 > g - u3.degree(): - u3, v3, n3 = self._parent.cantor_compose_at_infinity( - u3, v3, n3, plus=(n3 >= 0) - ) + u3, v3, n3 = self._parent.cantor_compose_at_infinity(u3, v3, n3, plus=(n3 >= 0)) return self._parent(u3, v3, n3, check=False) @@ -638,9 +632,7 @@ def _neg_(self): else: # Composition at infinity always with plus=True. # want to "subtract" \infty_+ - \infty_- - (u1, v1, n1) = self._parent.cantor_compose_at_infinity( - u0, -h - v0, n0, plus=True - ) + (u1, v1, n1) = self._parent.cantor_compose_at_infinity(u0, -h - v0, n0, plus=True) n1 = n1 - n0 + m0 + 1 # Shouldn't this always be 0? (See Alg 3.8 of [Mireles2008]_) assert n1 == 0 diff --git a/src/sage/schemes/hyperelliptic_curves/kummer_surface.py b/src/sage/schemes/hyperelliptic_curves/kummer_surface.py index f18bd16b5f0..0f236f846c1 100644 --- a/src/sage/schemes/hyperelliptic_curves/kummer_surface.py +++ b/src/sage/schemes/hyperelliptic_curves/kummer_surface.py @@ -75,107 +75,22 @@ def __init__(self, J): K2 = X1**2 - 4 * X0 * X2 - K1 = ( - (4 * f0 + h0**2) * X0**3 - + (2 * f1 + h0 * h1) * X0**2 * X1 - + (h0 * h2) * X0 * X1**2 - + (h0 * h3) * X1**3 - + (4 * f2 - 2 * h0 * h2 + h1**2) * X0**2 * X2 - + (2 * f3 - 3 * h0 * h3 + h1 * h2) * X0 * X1 * X2 - + (h1 * h3) * X1**2 * X2 - + (4 * f4 - 2 * h1 * h3 + h2**2) * X0 * X2**2 - + (2 * f5 + h2 * h3) * X1 * X2**2 - + (4 * f6 + h3**2) * X2**3 - ) + K1 = (4 * f0 + h0**2) * X0**3 + (2 * f1 + h0 * h1) * X0**2 * X1 + (h0 * h2) * X0 * X1**2 + (h0 * h3) * X1**3 + (4 * f2 - 2 * h0 * h2 + h1**2) * X0**2 * X2 + (2 * f3 - 3 * h0 * h3 + h1 * h2) * X0 * X1 * X2 + (h1 * h3) * X1**2 * X2 + (4 * f4 - 2 * h1 * h3 + h2**2) * X0 * X2**2 + (2 * f5 + h2 * h3) * X1 * X2**2 + (4 * f6 + h3**2) * X2**3 K0 = ( (-4 * f0 * f2 - f0 * h1**2 + f1**2 + f1 * h0 * h1 - f2 * h0**2) * X0**4 + (-4 * f0 * f3 - 2 * f0 * h1 * h2 + f1 * h0 * h2 - f3 * h0**2) * X0**3 * X1 - + (-4 * f0 * f4 - 2 * f0 * h1 * h3 - f0 * h2**2 + f1 * h0 * h3 - f4 * h0**2) - * X0**2 - * X1**2 + + (-4 * f0 * f4 - 2 * f0 * h1 * h3 - f0 * h2**2 + f1 * h0 * h3 - f4 * h0**2) * X0**2 * X1**2 + (-4 * f0 * f5 - 2 * f0 * h2 * h3 - f5 * h0**2) * X0 * X1**3 + (-4 * f0 * f6 - f0 * h3**2 - f6 * h0**2) * X1**4 - + ( - 2 * f0 * h1 * h3 - - 2 * f1 * f3 - - f1 * h0 * h3 - - f1 * h1 * h2 - + 2 * f2 * h0 * h2 - - f3 * h0 * h1 - ) - * X0**3 - * X2 - + ( - 4 * f0 * f5 - + 2 * f0 * h2 * h3 - - 4 * f1 * f4 - - f1 * h1 * h3 - - f1 * h2**2 - + 2 * f2 * h0 * h3 - + f3 * h0 * h2 - - 2 * f4 * h0 * h1 - + f5 * h0**2 - ) - * X0**2 - * X1 - * X2 - + ( - 8 * f0 * f6 - + 2 * f0 * h3**2 - - 4 * f1 * f5 - - 2 * f1 * h2 * h3 - + f3 * h0 * h3 - - 2 * f5 * h0 * h1 - + 2 * f6 * h0**2 - ) - * X0 - * X1**2 - * X2 + + (2 * f0 * h1 * h3 - 2 * f1 * f3 - f1 * h0 * h3 - f1 * h1 * h2 + 2 * f2 * h0 * h2 - f3 * h0 * h1) * X0**3 * X2 + + (4 * f0 * f5 + 2 * f0 * h2 * h3 - 4 * f1 * f4 - f1 * h1 * h3 - f1 * h2**2 + 2 * f2 * h0 * h3 + f3 * h0 * h2 - 2 * f4 * h0 * h1 + f5 * h0**2) * X0**2 * X1 * X2 + + (8 * f0 * f6 + 2 * f0 * h3**2 - 4 * f1 * f5 - 2 * f1 * h2 * h3 + f3 * h0 * h3 - 2 * f5 * h0 * h1 + 2 * f6 * h0**2) * X0 * X1**2 * X2 + (-4 * f1 * f6 - f1 * h3**2 - 2 * f6 * h0 * h1) * X1**3 * X2 - + ( - -4 * f0 * f6 - - f0 * h3**2 - + 2 * f1 * f5 - + f1 * h2 * h3 - - 4 * f2 * f4 - - f2 * h2**2 - + f3**2 - + f3 * h0 * h3 - + f3 * h1 * h2 - - f4 * h1**2 - + f5 * h0 * h1 - - f6 * h0**2 - ) - * X0**2 - * X2**2 - + ( - 4 * f1 * f6 - + f1 * h3**2 - - 4 * f2 * f5 - - 2 * f2 * h2 * h3 - + f3 * h1 * h3 - + 2 * f4 * h0 * h3 - - f5 * h0 * h2 - - f5 * h1**2 - + 2 * f6 * h0 * h1 - ) - * X0 - * X1 - * X2**2 - + (-4 * f2 * f6 - f2 * h3**2 + f5 * h0 * h3 - 2 * f6 * h0 * h2 - f6 * h1**2) - * X1**2 - * X2**2 - + ( - -2 * f3 * f5 - - f3 * h2 * h3 - + 2 * f4 * h1 * h3 - - f5 * h0 * h3 - - f5 * h1 * h2 - + 2 * f6 * h0 * h2 - ) - * X0 - * X2**3 + + (-4 * f0 * f6 - f0 * h3**2 + 2 * f1 * f5 + f1 * h2 * h3 - 4 * f2 * f4 - f2 * h2**2 + f3**2 + f3 * h0 * h3 + f3 * h1 * h2 - f4 * h1**2 + f5 * h0 * h1 - f6 * h0**2) * X0**2 * X2**2 + + (4 * f1 * f6 + f1 * h3**2 - 4 * f2 * f5 - 2 * f2 * h2 * h3 + f3 * h1 * h3 + 2 * f4 * h0 * h3 - f5 * h0 * h2 - f5 * h1**2 + 2 * f6 * h0 * h1) * X0 * X1 * X2**2 + + (-4 * f2 * f6 - f2 * h3**2 + f5 * h0 * h3 - 2 * f6 * h0 * h2 - f6 * h1**2) * X1**2 * X2**2 + + (-2 * f3 * f5 - f3 * h2 * h3 + 2 * f4 * h1 * h3 - f5 * h0 * h3 - f5 * h1 * h2 + 2 * f6 * h0 * h2) * X0 * X2**3 + (-4 * f3 * f6 - f3 * h3**2 + f5 * h1 * h3 - 2 * f6 * h1 * h2) * X1 * X2**3 + (-4 * f4 * f6 - f4 * h3**2 + f5**2 + f5 * h2 * h3 - f6 * h2**2) * X2**4 ) @@ -238,131 +153,27 @@ def _mumford_to_kummer(self, P): # divisors of the form [P + Q - D_infty] if u2 == R.one(): # auxiliary values - F0 = ( - 2 * u0**3 * f6 - - u0**2 * u1 * f5 - + 2 * u0**2 * f4 - - u0 * u1 * f3 - + 2 * u0 * f2 - - u1 * f1 - + 2 * f0 - ) + F0 = 2 * u0**3 * f6 - u0**2 * u1 * f5 + 2 * u0**2 * f4 - u0 * u1 * f3 + 2 * u0 * f2 - u1 * f1 + 2 * f0 y1y2 = u0 * v1**2 - u1 * v0 * v1 + v0**2 - h1h2 = ( - h3**2 * u0**3 - + (-h2 * h3) * u0**2 * u1 - + (h2**2 - 2 * h1 * h3) * u0**2 - + h1 * h3 * u0 * u1**2 - + (-h1 * h2 + 3 * h0 * h3) * u0 * u1 - + (h1**2 - 2 * h0 * h2) * u0 - + (-h0 * h3) * u1**3 - + h0 * h2 * u1**2 - + (-h0 * h1) * u1 - + h0**2 - ) + h1h2 = h3**2 * u0**3 + (-h2 * h3) * u0**2 * u1 + (h2**2 - 2 * h1 * h3) * u0**2 + h1 * h3 * u0 * u1**2 + (-h1 * h2 + 3 * h0 * h3) * u0 * u1 + (h1**2 - 2 * h0 * h2) * u0 + (-h0 * h3) * u1**3 + h0 * h2 * u1**2 + (-h0 * h1) * u1 + h0**2 if u1**2 - 4 * u0 == 0: # divisor of the form [2*P - D_infty] with P = [-u1/2,v0] # TODO: Is this formula correct? - denom = 4 * ( - (4 * f6 + h3**2) * u1**6 - + (-8 * f5 - 4 * h2 * h3) * u1**5 - + (16 * f4 + 8 * h1 * h3 + 4 * h2**2) * u1**4 - + (-32 * f3 - 16 * h0 * h3 - 16 * h1 * h2) * u1**3 - + (64 * f2 + 32 * h0 * h2 + 16 * h1**2) * u1**2 - + (-128 * f1 - 64 * h0 * h1) * u1 - + (256 * f0 + 64 * h0**2) - ) + denom = 4 * ((4 * f6 + h3**2) * u1**6 + (-8 * f5 - 4 * h2 * h3) * u1**5 + (16 * f4 + 8 * h1 * h3 + 4 * h2**2) * u1**4 + (-32 * f3 - 16 * h0 * h3 - 16 * h1 * h2) * u1**3 + (64 * f2 + 32 * h0 * h2 + 16 * h1**2) * u1**2 + (-128 * f1 - 64 * h0 * h1) * u1 + (256 * f0 + 64 * h0**2)) x0 = denom x1 = -u1 * denom x2 = u0 * denom x3 = (-1) * ( - (4 * f4 * f6 + f4 * h3**2 - f5**2 - f5 * h2 * h3 + f6 * h2**2) - * u1**8 - + ( - -16 * f3 * f6 - - 4 * f3 * h3**2 - + 4 * f5 * h1 * h3 - - 8 * f6 * h1 * h2 - ) - * u1**7 - + ( - 64 * f2 * f6 - + 16 * f2 * h3**2 - + 8 * f3 * f5 - + 4 * f3 * h2 * h3 - - 8 * f4 * h1 * h3 - - 12 * f5 * h0 * h3 - + 4 * f5 * h1 * h2 - + 24 * f6 * h0 * h2 - + 16 * f6 * h1**2 - ) - * u1**6 - + ( - -192 * f1 * f6 - - 48 * f1 * h3**2 - - 64 * f2 * f5 - - 32 * f2 * h2 * h3 - + 16 * f3 * h1 * h3 - + 32 * f4 * h0 * h3 - - 16 * f5 * h0 * h2 - - 16 * f5 * h1**2 - - 96 * f6 * h0 * h1 - ) - * u1**5 - + ( - 576 * f0 * f6 - + 144 * f0 * h3**2 - + 224 * f1 * f5 - + 112 * f1 * h2 * h3 - + 64 * f2 * f4 - + 16 * f2 * h2**2 - - 16 * f3**2 - - 80 * f3 * h0 * h3 - - 16 * f3 * h1 * h2 - + 16 * f4 * h1**2 - + 112 * f5 * h0 * h1 - + 144 * f6 * h0**2 - ) - * u1**4 - + ( - -768 * f0 * f5 - - 384 * f0 * h2 * h3 - - 256 * f1 * f4 - - 64 * f1 * h1 * h3 - - 64 * f1 * h2**2 - + 128 * f2 * h0 * h3 - + 64 * f3 * h0 * h2 - - 128 * f4 * h0 * h1 - - 192 * f5 * h0**2 - ) - * u1**3 - + ( - 1024 * f0 * f4 - + 384 * f0 * h1 * h3 - + 256 * f0 * h2**2 - + 128 * f1 * f3 - - 192 * f1 * h0 * h3 - + 64 * f1 * h1 * h2 - - 128 * f2 * h0 * h2 - + 64 * f3 * h0 * h1 - + 256 * f4 * h0**2 - ) - * u1**2 - + ( - -1024 * f0 * f3 - - 512 * f0 * h1 * h2 - + 256 * f1 * h0 * h2 - - 256 * f3 * h0**2 - ) - * u1 - + ( - 1024 * f0 * f2 - + 256 * f0 * h1**2 - - 256 * f1**2 - - 256 * f1 * h0 * h1 - + 256 * f2 * h0**2 - ) + (4 * f4 * f6 + f4 * h3**2 - f5**2 - f5 * h2 * h3 + f6 * h2**2) * u1**8 + + (-16 * f3 * f6 - 4 * f3 * h3**2 + 4 * f5 * h1 * h3 - 8 * f6 * h1 * h2) * u1**7 + + (64 * f2 * f6 + 16 * f2 * h3**2 + 8 * f3 * f5 + 4 * f3 * h2 * h3 - 8 * f4 * h1 * h3 - 12 * f5 * h0 * h3 + 4 * f5 * h1 * h2 + 24 * f6 * h0 * h2 + 16 * f6 * h1**2) * u1**6 + + (-192 * f1 * f6 - 48 * f1 * h3**2 - 64 * f2 * f5 - 32 * f2 * h2 * h3 + 16 * f3 * h1 * h3 + 32 * f4 * h0 * h3 - 16 * f5 * h0 * h2 - 16 * f5 * h1**2 - 96 * f6 * h0 * h1) * u1**5 + + (576 * f0 * f6 + 144 * f0 * h3**2 + 224 * f1 * f5 + 112 * f1 * h2 * h3 + 64 * f2 * f4 + 16 * f2 * h2**2 - 16 * f3**2 - 80 * f3 * h0 * h3 - 16 * f3 * h1 * h2 + 16 * f4 * h1**2 + 112 * f5 * h0 * h1 + 144 * f6 * h0**2) * u1**4 + + (-768 * f0 * f5 - 384 * f0 * h2 * h3 - 256 * f1 * f4 - 64 * f1 * h1 * h3 - 64 * f1 * h2**2 + 128 * f2 * h0 * h3 + 64 * f3 * h0 * h2 - 128 * f4 * h0 * h1 - 192 * f5 * h0**2) * u1**3 + + (1024 * f0 * f4 + 384 * f0 * h1 * h3 + 256 * f0 * h2**2 + 128 * f1 * f3 - 192 * f1 * h0 * h3 + 64 * f1 * h1 * h2 - 128 * f2 * h0 * h2 + 64 * f3 * h0 * h1 + 256 * f4 * h0**2) * u1**2 + + (-1024 * f0 * f3 - 512 * f0 * h1 * h2 + 256 * f1 * h0 * h2 - 256 * f3 * h0**2) * u1 + + (1024 * f0 * f2 + 256 * f0 * h1**2 - 256 * f1**2 - 256 * f1 * h0 * h1 + 256 * f2 * h0**2) ) elif y1y2 == R.zero(): # divisor of the form [(a,0) + (b,0) - D_infty] @@ -377,24 +188,7 @@ def _mumford_to_kummer(self, P): x0 = denom x1 = -u1 * denom x2 = u0 * denom - term = ( - (-(f5**2) + 4 * f4 * f6) * u0**4 - + (-4 * f3 * f6) * u0**3 * u1 - + 2 * f3 * f5 * u0**3 - + 4 * f2 * f6 * u0**2 * u1**2 - + (-4 * f2 * f5 + 4 * f1 * f6) * u0**2 * u1 - + (-(f3**2) + 4 * f2 * f4 - 2 * f1 * f5 + 4 * f0 * f6) * u0**2 - + (-4 * f1 * f6) * u0 * u1**3 - + (4 * f1 * f5 - 8 * f0 * f6) * u0 * u1**2 - + (-4 * f1 * f4 + 4 * f0 * f5) * u0 * u1 - + 2 * f1 * f3 * u0 - + 4 * f0 * f6 * u1**4 - + (-4 * f0 * f5) * u1**3 - + 4 * f0 * f4 * u1**2 - + (-4 * f0 * f3) * u1 - - f1**2 - + 4 * f0 * f2 - ) + term = (-(f5**2) + 4 * f4 * f6) * u0**4 + (-4 * f3 * f6) * u0**3 * u1 + 2 * f3 * f5 * u0**3 + 4 * f2 * f6 * u0**2 * u1**2 + (-4 * f2 * f5 + 4 * f1 * f6) * u0**2 * u1 + (-(f3**2) + 4 * f2 * f4 - 2 * f1 * f5 + 4 * f0 * f6) * u0**2 + (-4 * f1 * f6) * u0 * u1**3 + (4 * f1 * f5 - 8 * f0 * f6) * u0 * u1**2 + (-4 * f1 * f4 + 4 * f0 * f5) * u0 * u1 + 2 * f1 * f3 * u0 + 4 * f0 * f6 * u1**4 + (-4 * f0 * f5) * u1**3 + 4 * f0 * f4 * u1**2 + (-4 * f0 * f3) * u1 - f1**2 + 4 * f0 * f2 x3 = 4 * (F0 + h1h2 - y1y2) * y1y2 - (term * (u1**2 - 4 * u0) + F0**2) elif u1 == R.one(): # In this case, the divisor is of the form [P + O0 - D_{\infty}], @@ -414,13 +208,7 @@ def _mumford_to_kummer(self, P): x0 = R.zero() x1 = X2**3 * Z1**3 x2 = X1 * X2**3 * Z1**2 - x3 = -( - 2 * Y1 * Y2 - + h3 * Y1 * X2**3 - + Y2 * (h3 * X1**3 + h2 * X1**2 * Z1 + h1 * X1 * Z1**2 + h0 * Z1**3) - - 2 * f6 * X1**3 * X2**3 - - f5 * X1**2 * X2**3 * Z1 - ) + x3 = -(2 * Y1 * Y2 + h3 * Y1 * X2**3 + Y2 * (h3 * X1**3 + h2 * X1**2 * Z1 + h1 * X1 * Z1**2 + h0 * Z1**3) - 2 * f6 * X1**3 * X2**3 - f5 * X1**2 * X2**3 * Z1) elif C.is_split() and P._n != 1: # divisor [P_infty+ - P_infty-] # TODO: Is this the correct image? diff --git a/src/sage/schemes/hyperelliptic_curves/mestre.py b/src/sage/schemes/hyperelliptic_curves/mestre.py index 42fff4184e1..0fc44678ff3 100644 --- a/src/sage/schemes/hyperelliptic_curves/mestre.py +++ b/src/sage/schemes/hyperelliptic_curves/mestre.py @@ -13,6 +13,7 @@ - Marco Streng """ + # ***************************************************************************** # Copyright (C) 2011, 2012, 2013 Florian Bouyer # Marco Streng @@ -35,9 +36,7 @@ # TODO: # precision is unused -def HyperellipticCurve_from_invariants( - i, reduced=True, precision=None, algorithm="default" -): +def HyperellipticCurve_from_invariants(i, reduced=True, precision=None, algorithm="default"): r""" Returns a hyperelliptic curve with the given Igusa-Clebsch invariants up to scaling. @@ -178,77 +177,30 @@ def HyperellipticCurve_from_invariants( from sage.misc.sage_eval import sage_eval if MConic.has_rational_point(algorithm="magma"): - parametrization = [ - l.replace("$.1", "t").replace("$.2", "u") - for l in str(magma(MConic).Parametrization()).splitlines()[4:7] - ] - [F1, F2, F3] = [ - sage_eval(p, locals={"t": t, "u": 1, "a": k.gen()}) - for p in parametrization - ] + parametrization = [l.replace("$.1", "t").replace("$.2", "u") for l in str(magma(MConic).Parametrization()).splitlines()[4:7]] + [F1, F2, F3] = [sage_eval(p, locals={"t": t, "u": 1, "a": k.gen()}) for p in parametrization] else: - raise ValueError( - f"No such curve exists over {k} as there are no " - f"rational points on {MConic}" - ) + raise ValueError(f"No such curve exists over {k} as there are no " f"rational points on {MConic}") elif MConic.has_rational_point(): parametrization = MConic.parametrization(morphism=False)[0] [F1, F2, F3] = [p(t, 1) for p in parametrization] else: - raise ValueError( - f"No such curve exists over {k} as there are no rational points on {MConic}" - ) + raise ValueError(f"No such curve exists over {k} as there are no rational points on {MConic}") # setting the cijk from Mestre's algorithm c111 = 12 * x * y - 2 * y / 3 - 4 * z c112 = -18 * x**3 - 12 * x * y - 36 * y**2 - 2 * z c113 = -9 * x**3 - 36 * x**2 * y - 4 * x * y - 6 * x * z - 18 * y**2 c122 = c113 - c123 = ( - -54 * x**4 - 36 * x**2 * y - 36 * x * y**2 - 6 * x * z - 4 * y**2 - 24 * y * z - ) - c133 = ( - -27 * x**4 / 2 - - 72 * x**3 * y - - 6 * x**2 * y - - 9 * x**2 * z - - 39 * x * y**2 - - 36 * y**3 - - 2 * y * z - ) + c123 = -54 * x**4 - 36 * x**2 * y - 36 * x * y**2 - 6 * x * z - 4 * y**2 - 24 * y * z + c133 = -27 * x**4 / 2 - 72 * x**3 * y - 6 * x**2 * y - 9 * x**2 * z - 39 * x * y**2 - 36 * y**3 - 2 * y * z c222 = -27 * x**4 - 18 * x**2 * y - 6 * x * y**2 - 8 * y**2 / 3 + 2 * y * z c223 = 9 * x**3 * y - 27 * x**2 * z + 6 * x * y**2 + 18 * y**3 - 8 * y * z - c233 = ( - -81 * x**5 / 2 - - 27 * x**3 * y - - 9 * x**2 * y**2 - - 4 * x * y**2 - + 3 * x * y * z - - 6 * z**2 - ) - c333 = ( - 27 * x**4 * y / 2 - - 27 * x**3 * z / 2 - + 9 * x**2 * y**2 - + 3 * x * y**3 - - 6 * x * y * z - + 4 * y**3 / 3 - - 10 * y**2 * z - ) + c233 = -81 * x**5 / 2 - 27 * x**3 * y - 9 * x**2 * y**2 - 4 * x * y**2 + 3 * x * y * z - 6 * z**2 + c333 = 27 * x**4 * y / 2 - 27 * x**3 * z / 2 + 9 * x**2 * y**2 + 3 * x * y**3 - 6 * x * y * z + 4 * y**3 / 3 - 10 * y**2 * z # writing out the hyperelliptic curve polynomial - f = ( - c111 * F1**3 - + c112 * F1**2 * F2 - + c113 * F1**2 * F3 - + c122 * F1 * F2**2 - + c123 * F1 * F2 * F3 - + c133 * F1 * F3**2 - + c222 * F2**3 - + c223 * F2**2 * F3 - + c233 * F2 * F3**2 - + c333 * F3**3 - ) + f = c111 * F1**3 + c112 * F1**2 * F2 + c113 * F1**2 * F3 + c122 * F1 * F2**2 + c123 * F1 * F2 * F3 + c133 * F1 * F3**2 + c222 * F2**3 + c223 * F2**2 * F3 + c233 * F2 * F3**2 + c333 * F3**3 try: f = f * f.denominator() # clear the denominator @@ -256,11 +208,7 @@ def HyperellipticCurve_from_invariants( pass if reduced: - raise NotImplementedError( - "Reduction of hyperelliptic curves not " - "yet implemented. " - "See issues #14755 and #14756." - ) + raise NotImplementedError("Reduction of hyperelliptic curves not " "yet implemented. " "See issues #14755 and #14756.") return HyperellipticCurve(f) @@ -340,18 +288,7 @@ def Mestre_conic(i, xyz=False, names="u,v,w"): # Setting x,y,z as in Mestre's algorithm (Using Lauter and Yang's formulas) x = 8 * (1 + 20 * I4 / (I2**2)) / 225 y = 16 * (1 + 80 * I4 / (I2**2) - 600 * I6 / (I2**3)) / 3375 - z = ( - -64 - * ( - -10800000 * I10 / (I2**5) - - 9 - - 700 * I4 / (I2**2) - + 3600 * I6 / (I2**3) - + 12400 * I4**2 / (I2**4) - - 48000 * I4 * I6 / (I2**5) - ) - / 253125 - ) + z = -64 * (-10800000 * I10 / (I2**5) - 9 - 700 * I4 / (I2**2) + 3600 * I6 / (I2**3) + 12400 * I4**2 / (I2**4) - 48000 * I4 * I6 / (I2**5)) / 253125 L = Matrix( [ diff --git a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py index 4c1a84d1796..37643b40f01 100644 --- a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +++ b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py @@ -221,9 +221,7 @@ def _latex_(self) -> str: sage: latex(f) (123 T^{2}) + (T + 1)x + (0)x^2 """ - return "(%s) + (%s)x + (%s)x^2" % tuple( - column._latex_() for column in self._triple - ) + return "(%s) + (%s)x + (%s)x^2" % tuple(column._latex_() for column in self._triple) def _add_(self, other): """ @@ -555,10 +553,7 @@ def __init__(self, Q, laurent_series=False): base_ring = Q.parent().base_ring() if not base_ring(6).is_unit(): - raise ArithmeticError( - "2 and 3 must be invertible in the " - "coefficient ring (=%s) of Q" % base_ring - ) + raise ArithmeticError("2 and 3 must be invertible in the " "coefficient ring (=%s) of Q" % base_ring) self._a = Q[1] self._b = Q[0] @@ -567,9 +562,7 @@ def __init__(self, Q, laurent_series=False): else: self._poly_ring = PolynomialRing(base_ring, "T") # R[T] self._poly_generator = self._poly_ring.gen(0) # the generator T - Parent.__init__( - self, base=base_ring, category=Algebras(base_ring).Commutative() - ) + Parent.__init__(self, base=base_ring, category=Algebras(base_ring).Commutative()) # Precompute a matrix that is used in the Toom-Cook multiplication. # This is where we need 2 and 3 invertible. @@ -898,11 +891,7 @@ def reduce_negative(Q, p, coeffs, offset, exact_form=None): exact_form += (c0 + c1 * x + c2 * x**2) * y ** (j + 1) except NotImplementedError: - raise NotImplementedError( - "It looks like you've found a " - "non-integral matrix of Frobenius! " - f"(Q={Q}, p={p})\nTime to write a paper." - ) + raise NotImplementedError("It looks like you've found a " "non-integral matrix of Frobenius! " f"(Q={Q}, p={p})\nTime to write a paper.") coeffs[int(offset)] = next_a @@ -1227,11 +1216,7 @@ def frobenius_expansion_by_newton(Q, p, M): elif initial_precision == 3: # approximation is (15 - 10 s + 3 s^2) / 8 k = 3 - X = (base_ring(1) / base_ring(8)) * ( - S(15).shift(2 * p) - - (base_ring(20) * r).shift(p) - + (base_ring(12) * r.square()) - ) + X = (base_ring(1) / base_ring(8)) * (S(15).shift(2 * p) - (base_ring(20) * r).shift(p) + (base_ring(12) * r.square())) # The key to the following calculation is that the T^{-m} coefficient # of every x_i is divisible by p^(ceil(m/p)) (for m >= 0). Therefore if # we are only expecting an answer correct mod p^k, we can truncate @@ -1749,9 +1734,7 @@ def matrix_of_frobenius(Q, p, M, trace=None, compute_exact_forms=False): F0_reduced = [base_ring(trace) - F1_reduced[1], None] # using that the determinant is p: - F0_reduced[1] = (F0_reduced[0] * F1_reduced[1] - base_ring(p)) / F1_reduced[ - 0 - ] + F0_reduced[1] = (F0_reduced[0] * F1_reduced[1] - base_ring(p)) / F1_reduced[0] else: # If the first entry is zero mod p, then F((x+1) dx/y) will be sufficient @@ -1778,9 +1761,7 @@ def matrix_of_frobenius(Q, p, M, trace=None, compute_exact_forms=False): # Figure out the second column using the trace... H1_reduced = [None, base_ring(trace) - H0_reduced[0]] # ... and using that the determinant is p: - H1_reduced[0] = (H0_reduced[0] * H1_reduced[1] - base_ring(p)) / H0_reduced[ - 1 - ] + H1_reduced[0] = (H0_reduced[0] * H1_reduced[1] - base_ring(p)) / H0_reduced[1] # Finally, change back to the usual basis (dx/y, x dx/y) F1_reduced = [H1_reduced[0], H1_reduced[0] + H1_reduced[1]] @@ -1793,12 +1774,7 @@ def matrix_of_frobenius(Q, p, M, trace=None, compute_exact_forms=False): # to the approximation we used earlier. msg = "The output matrix is not congruent mod p " msg += "to the approximation found earlier!" - assert not ( - (F1_reduced[0] - F1_modp_reduced[0]).is_unit() - or (F1_reduced[1] - F1_modp_reduced[1]).is_unit() - or F0_reduced[0].is_unit() - or F0_reduced[1].is_unit() - ), msg + assert not ((F1_reduced[0] - F1_modp_reduced[0]).is_unit() or (F1_reduced[1] - F1_modp_reduced[1]).is_unit() or F0_reduced[0].is_unit() or F0_reduced[1].is_unit()), msg if compute_exact_forms: return ( @@ -1881,9 +1857,7 @@ def matrix_of_frobenius_hyperelliptic(Q, p=None, prec=None, M=None): p = K.prime() prec = K.precision_cap() except AttributeError: - raise ValueError( - "p and prec must be specified if Q is not defined over a p-adic ring" - ) + raise ValueError("p and prec must be specified if Q is not defined over a p-adic ring") if M is None: M = adjusted_prec(p, prec) extra_prec_ring = Integers(p**M) @@ -2256,9 +2230,7 @@ def _latex_(self) -> str: """ x = PolynomialRing(QQ, "x").gen(0) coeffs = self._f.list() - return repr_lincomb( - [(x**i, coeffs[i]) for i in range(len(coeffs))], is_latex=True - ) + return repr_lincomb([(x**i, coeffs[i]) for i in range(len(coeffs))], is_latex=True) def diff(self): """ @@ -2484,15 +2456,10 @@ def __init__(self, Q, R=None, invert_y=True): ainvs = [0, self._Q[2], 0, self._Q[1], self._Q[0]] self._curve = EllipticCurve(ainvs) else: - self._curve = HyperellipticCurve( - self._Q, check_squarefree=R.is_field() - ) + self._curve = HyperellipticCurve(self._Q, check_squarefree=R.is_field()) else: - raise NotImplementedError( - "must be an elliptic curve or polynomial " - "Q for y^2 = Q(x)\n(Got element of %s)" % Q.parent() - ) + raise NotImplementedError("must be an elliptic curve or polynomial " "Q for y^2 = Q(x)\n(Got element of %s)" % Q.parent()) self._n = int(Q.degree()) self._series_ring = (LaurentSeriesRing if invert_y else PolynomialRing)(R, "y") @@ -2525,11 +2492,7 @@ def _repr_(self) -> str: sage: x.parent() # indirect doctest SpecialHyperellipticQuotientRing K[x,y,y^-1] / (y^2 = x^5 - 3*x + 1) over Rational Field """ - y_inverse = ( - ",y^-1" - if isinstance(self._series_ring, (LaurentSeriesRing, LazyLaurentSeriesRing)) - else "" - ) + y_inverse = ",y^-1" if isinstance(self._series_ring, (LaurentSeriesRing, LazyLaurentSeriesRing)) else "" return "SpecialHyperellipticQuotientRing K[x,y%s] / (y^2 = %s) over %s" % ( y_inverse, self._Q, @@ -2587,10 +2550,7 @@ def _element_constructor_(self, val, offset=0, check=True): sage: x.parent()(x^6) -(1-y^2)*x + 3*x^2 """ - if ( - isinstance(val, SpecialHyperellipticQuotientElement) - and val.parent() is self - ): + if isinstance(val, SpecialHyperellipticQuotientElement) and val.parent() is self: if offset == 0: return val return val << offset @@ -3290,9 +3250,7 @@ def reduce_neg_y_fast(self, even_degree_only=False): for i in lin_comb.nonzero_positions(): # g = lin_comb[i] x^i y^j # self -= dg - coeffs[j - offset + 1] -= ( - lin_comb[i] * S.monomial_diff_coeffs(i, j)[1] - ) + coeffs[j - offset + 1] -= lin_comb[i] * S.monomial_diff_coeffs(i, j)[1] # prof("recreate forms") f = S(forms, offset + 1) diff --git a/src/sage/schemes/jacobians/abstract_jacobian.py b/src/sage/schemes/jacobians/abstract_jacobian.py index 33a904b7f9c..f0053ad1e46 100644 --- a/src/sage/schemes/jacobians/abstract_jacobian.py +++ b/src/sage/schemes/jacobians/abstract_jacobian.py @@ -57,6 +57,7 @@ class Jacobian_generic(Scheme): sage: J = Jacobian(C); J Jacobian of Projective Plane Curve over Rational Field defined by x^3 + y^3 + z^3 """ + def __init__(self, C, category=None): """ Initialize. @@ -244,6 +245,5 @@ def base_extend(self, R): if self.base_ring() is R: return self if not R.has_coerce_map_from(self.base_ring()): - raise ValueError('no natural map from the base ring (=%s) to R (=%s)!' - % (self.base_ring(), R)) + raise ValueError('no natural map from the base ring (=%s) to R (=%s)!' % (self.base_ring(), R)) return self.change_ring(R) diff --git a/src/sage/schemes/plane_conics/all.py b/src/sage/schemes/plane_conics/all.py index 0ac534ebe27..be95606538a 100644 --- a/src/sage/schemes/plane_conics/all.py +++ b/src/sage/schemes/plane_conics/all.py @@ -1,6 +1,7 @@ """ Plane conics """ + # **************************************************************************** # # Sage: Open Source Mathematical Software diff --git a/src/sage/schemes/plane_conics/con_field.py b/src/sage/schemes/plane_conics/con_field.py index e752abba77e..ad2ede756ff 100644 --- a/src/sage/schemes/plane_conics/con_field.py +++ b/src/sage/schemes/plane_conics/con_field.py @@ -7,6 +7,7 @@ - Nick Alexander (2008-01-08) """ + # ***************************************************************************** # Copyright (C) 2008 Nick Alexander # Copyright (C) 2009/2010 Marco Streng @@ -37,6 +38,7 @@ from sage.schemes.curves.projective_curve import ProjectivePlaneCurve_field from sage.categories.fields import Fields + _Fields = Fields() @@ -58,6 +60,7 @@ class ProjectiveConic_field(ProjectivePlaneCurve_field): sage: K = FractionField(PolynomialRing(QQ, 't')) sage: Conic([K(1), 1, -1])._test_pickling() """ + def __init__(self, A, f): r""" See ``Conic`` for full documentation. @@ -70,8 +73,7 @@ def __init__(self, A, f): Projective Conic Curve over Rational Field defined by x^2 + y^2 + z^2 """ super().__init__(A, f) - self._coefficients = [f[(2, 0, 0)], f[(1, 1, 0)], f[(1, 0, 1)], - f[(0, 2, 0)], f[(0, 1, 1)], f[(0, 0, 2)]] + self._coefficients = [f[(2, 0, 0)], f[(1, 1, 0)], f[(1, 0, 1)], f[(0, 2, 0)], f[(0, 1, 1)], f[(0, 0, 2)]] self._parametrization = None self._diagonal_matrix = None @@ -115,11 +117,10 @@ def base_extend(self, S): if B == S: return self if not S.has_coerce_map_from(B): - raise ValueError("No natural map from the base ring of self " - "(= %s) to S (= %s)" % (self, S)) + raise ValueError("No natural map from the base ring of self " "(= %s) to S (= %s)" % (self, S)) from .constructor import Conic - con = Conic([S(c) for c in self.coefficients()], - self.variable_names()) + + con = Conic([S(c) for c in self.coefficients()], self.variable_names()) if self._rational_point is not None: pt = [S(c) for c in Sequence(self._rational_point)] if not pt == [0, 0, 0]: @@ -208,9 +209,7 @@ def derivative_matrix(self): [t^2 1 0] """ a, b, c, d, e, f = self.coefficients() - return matrix([[2 * a, b, c], - [b, 2 * d, e], - [c, e, 2 * f]]) + return matrix([[2 * a, b, c], [b, 2 * d, e], [c, e, 2 * f]]) def determinant(self): r""" @@ -286,26 +285,25 @@ def diagonal_matrix(self): B = self.base_ring() basis = [vector(B, {2: 0, i: 1}) for i in range(3)] for i in range(3): - zerovalue = (basis[i]*A*basis[i].column() == 0) + zerovalue = basis[i] * A * basis[i].column() == 0 if zerovalue: - for j in range(i+1, 3): - if basis[j]*A*basis[j].column() != 0: + for j in range(i + 1, 3): + if basis[j] * A * basis[j].column() != 0: b = basis[i] basis[i] = basis[j] basis[j] = b zerovalue = False if zerovalue: - for j in range(i+1, 3): - if basis[i]*A*basis[j].column() != 0: - basis[i] = basis[i]+basis[j] + for j in range(i + 1, 3): + if basis[i] * A * basis[j].column() != 0: + basis[i] = basis[i] + basis[j] zerovalue = False if not zerovalue: - l = (basis[i]*A*basis[i].column()) - for j in range(i+1, 3): - basis[j] = basis[j] - \ - (basis[i]*A*basis[j].column())/l * basis[i] + l = basis[i] * A * basis[i].column() + for j in range(i + 1, 3): + basis[j] = basis[j] - (basis[i] * A * basis[j].column()) / l * basis[i] T = matrix(basis).transpose() - return T.transpose()*A*T, T + return T.transpose() * A * T, T def diagonalization(self, names=None): r""" @@ -373,6 +371,7 @@ def diagonalization(self, names=None): if names is None: names = self.defining_polynomial().parent().variable_names() from .constructor import Conic + D, T = self.diagonal_matrix() con = Conic(D, names=names) return con, con.hom(T, self), self.hom(T.inverse(), con) @@ -402,8 +401,7 @@ def gens(self) -> tuple: """ return self.coordinate_ring().gens() - def has_rational_point(self, point=False, - algorithm='default', read_cache=True): + def has_rational_point(self, point=False, algorithm='default', read_cache=True): r""" Return ``True`` if and only if the conic ``self`` has a point over its base field `B`. @@ -488,6 +486,7 @@ def has_rational_point(self, point=False, if algorithm == 'magma': from sage.interfaces.magma import magma + M = magma(self) b = M.HasRationalPoint().sage() if not point: @@ -518,8 +517,7 @@ def has_rational_point(self, point=False, # writing) fraction field elements are not converted automatically # from Magma to Sage. try: - return True, self.point( - [B(c.Numerator().sage() / c.Denominator().sage()) for c in pt]) + return True, self.point([B(c.Numerator().sage() / c.Denominator().sage()) for c in pt]) except (TypeError, NameError): pass @@ -539,29 +537,25 @@ def has_rational_point(self, point=False, _, _, _, d, e, f = self._coefficients if d == 0: return True, self.point([0, 1, 0]) - return True, self.point([0, ((e**2-4*d*f).sqrt()-e)/(2*d), 1], - check=False) + return True, self.point([0, ((e**2 - 4 * d * f).sqrt() - e) / (2 * d), 1], check=False) return True if isinstance(B, sage.rings.abc.RealField): D, T = self.diagonal_matrix() a, b, c = [D[0, 0], D[1, 1], D[2, 2]] if a == 0: - ret = True, self.point(T*vector([1, 0, 0]), check=False) - elif a*c <= 0: - ret = True, self.point(T*vector([(-c/a).sqrt(), 0, 1]), - check=False) + ret = True, self.point(T * vector([1, 0, 0]), check=False) + elif a * c <= 0: + ret = True, self.point(T * vector([(-c / a).sqrt(), 0, 1]), check=False) elif b == 0: - ret = True, self.point(T*vector([0, 1, 0]), check=False) - elif b*c <= 0: - ret = True, self.point(T*vector([0, (-c/b).sqrt(), 0, 1]), - check=False) + ret = True, self.point(T * vector([0, 1, 0]), check=False) + elif b * c <= 0: + ret = True, self.point(T * vector([0, (-c / b).sqrt(), 0, 1]), check=False) else: ret = False, None if point: return ret return ret[0] - raise NotImplementedError("has_rational_point not implemented for " - "conics over base field %s" % B) + raise NotImplementedError("has_rational_point not implemented for " "conics over base field %s" % B) def has_singular_point(self, point=False): r""" @@ -621,11 +615,11 @@ def has_singular_point(self, point=False): for i in range(3): if [a, d, f][i] == 0: return True, self.point(vector(B, {2: 0, i: 1})) - if hasattr(a/f, 'is_square') and hasattr(a/f, 'sqrt'): - if (a/f).is_square(): - return True, self.point([1, 0, (a/f).sqrt()]) - if (d/f).is_square(): - return True, self.point([0, 1, (d/f).sqrt()]) + if hasattr(a / f, 'is_square') and hasattr(a / f, 'sqrt'): + if (a / f).is_square(): + return True, self.point([1, 0, (a / f).sqrt()]) + if (d / f).is_square(): + return True, self.point([0, 1, (d / f).sqrt()]) raise NotImplementedError("Sorry, find singular point on conics not implemented over all fields of characteristic 2.") pt = [e, c, b] if self.defining_polynomial()(pt) == 0: @@ -713,16 +707,15 @@ def hom(self, x, Y=None): """ if isinstance(x, Matrix): from .constructor import Conic + y = x.inverse() - A = y.transpose()*self.matrix()*y + A = y.transpose() * self.matrix() * y im = Conic(A) if Y is None: Y = im elif not Y == im: - raise ValueError("The matrix x (= %s) does not define a " - "map from self (= %s) to Y (= %s)" % - (x, self, Y)) - x = Sequence(x*vector(self.ambient_space().gens())) + raise ValueError("The matrix x (= %s) does not define a " "map from self (= %s) to Y (= %s)" % (x, self, Y)) + x = Sequence(x * vector(self.ambient_space().gens())) return self.Hom(Y)(x, check=False) return super().hom(x, Y) @@ -957,9 +950,7 @@ def parametrization(self, point=None, morphism=True): L[c3] = Y * T1 * point[c3] bezout = P(self.defining_polynomial()(L) / T0) t = [bezout([x, y, 0, -1]), bezout([x, y, 1, 0])] - par = (tuple([Q(p([x, y, t[0], t[1]]) / y) for p in L]), - tuple([gens[m] * point[c3] - gens[c3] * point[m] - for m in [c2, c1]])) + par = (tuple([Q(p([x, y, t[0], t[1]]) / y) for p in L]), tuple([gens[m] * point[c3] - gens[c3] * point[m] for m in [c2, c1]])) if self._parametrization is None: self._parametrization = par if not morphism: @@ -1030,8 +1021,7 @@ def random_rational_point(self, *args1, **args2): x^2 + y^2 + z^2 has no rational points over Rational Field! """ if not self.is_smooth(): - raise NotImplementedError("Sorry, random points not implemented " - "for non-smooth conics") + raise NotImplementedError("Sorry, random points not implemented " "for non-smooth conics") par = self.parametrization() x = 0 y = 0 @@ -1179,12 +1169,10 @@ def rational_point(self, algorithm='default', read_cache=True): with 53 bits of precision defined by x^2 + y^2 + z^2 has no rational points over Real Field with 53 bits of precision! """ - bl, pt = self.has_rational_point(point=True, algorithm=algorithm, - read_cache=read_cache) + bl, pt = self.has_rational_point(point=True, algorithm=algorithm, read_cache=read_cache) if bl: return pt - raise ValueError("Conic %s has no rational points over %s!" % - (self, self.ambient_space().base_ring())) + raise ValueError("Conic %s has no rational points over %s!" % (self, self.ambient_space().base_ring())) def singular_point(self): r""" @@ -1210,8 +1198,7 @@ def singular_point(self): """ b = self.has_singular_point(point=True) if not b[0]: - raise ValueError("The conic self (= %s) has no rational " - "singular point" % self) + raise ValueError("The conic self (= %s) has no rational " "singular point" % self) return b[1] def symmetric_matrix(self): @@ -1237,12 +1224,8 @@ def symmetric_matrix(self): if self.base_ring().characteristic() == 2: if b == 0 and c == 0 and e == 0: return matrix([[a, 0, 0], [0, d, 0], [0, 0, f]]) - raise ValueError("The conic self (= %s) has no symmetric matrix " - "because the base field has characteristic 2" % - self) - return matrix([[a, b / 2, c / 2], - [b / 2, d, e / 2], - [c / 2, e / 2, f]]) + raise ValueError("The conic self (= %s) has no symmetric matrix " "because the base field has characteristic 2" % self) + return matrix([[a, b / 2, c / 2], [b / 2, d, e / 2], [c / 2, e / 2, f]]) def upper_triangular_matrix(self): r""" @@ -1264,10 +1247,9 @@ def upper_triangular_matrix(self): x^2 + 2*x*y + y^2 + 3*x*z + z^2 """ from sage.matrix.constructor import matrix + a, b, c, d, e, f = self.coefficients() - return matrix([[a, b, c], - [0, d, e], - [0, 0, f]]) + return matrix([[a, b, c], [0, d, e], [0, 0, f]]) def variable_names(self): r""" diff --git a/src/sage/schemes/plane_conics/con_finite_field.py b/src/sage/schemes/plane_conics/con_finite_field.py index 3562b2e2765..e6e6586f8f3 100644 --- a/src/sage/schemes/plane_conics/con_finite_field.py +++ b/src/sage/schemes/plane_conics/con_finite_field.py @@ -46,6 +46,7 @@ class ProjectiveConic_finite_field(ProjectiveConic_field, ProjectivePlaneCurve_f sage: Conic(X^2 + Y^2 - 2*Z^2) Projective Conic Curve over Finite Field of size 5 defined by X^2 + Y^2 - 2*Z^2 """ + def __init__(self, A, f): r""" See ``Conic`` for full documentation. @@ -75,8 +76,7 @@ def count_points(self, n): q = F.cardinality() return [q**i + 1 for i in range(1, n + 1)] - def has_rational_point(self, point=False, read_cache=True, - algorithm='default'): + def has_rational_point(self, point=False, read_cache=True, algorithm='default'): r""" Always returns ``True`` because ``self`` has a point defined over its finite base field `B`. diff --git a/src/sage/schemes/plane_conics/con_number_field.py b/src/sage/schemes/plane_conics/con_number_field.py index 05da93e092f..6527468cacd 100644 --- a/src/sage/schemes/plane_conics/con_number_field.py +++ b/src/sage/schemes/plane_conics/con_number_field.py @@ -44,6 +44,7 @@ class ProjectiveConic_number_field(ProjectiveConic_field): sage: K. = NumberField(x^3 - 3, 'a') sage: Conic([a, 1, -1])._test_pickling() """ + def __init__(self, A, f): r""" See ``Conic`` for full documentation. @@ -62,8 +63,7 @@ def __init__(self, A, f): # all infinite primes such that self has no point over the completion self._infinite_obstructions = None - def has_rational_point(self, point=False, obstruction=False, - algorithm='default', read_cache=True): + def has_rational_point(self, point=False, obstruction=False, algorithm='default', read_cache=True): r""" Return ``True`` if and only if ``self`` has a point defined over its base field `B`. @@ -222,8 +222,7 @@ def has_rational_point(self, point=False, obstruction=False, return False # `_(in)finite_obstructions` is ``None`` if the cache is empty, # so we explicitly check against a list: - if (not point) and self._finite_obstructions == [] and \ - self._infinite_obstructions == []: + if (not point) and self._finite_obstructions == [] and self._infinite_obstructions == []: # list of local obstructions is computed and empty, return True if obstruction: return True, None @@ -240,21 +239,15 @@ def has_rational_point(self, point=False, obstruction=False, B = self.base_ring() if algorithm == 'default': - ret = self.has_rational_point(point=True, obstruction=False, - algorithm='rnfisnorm', - read_cache=False) + ret = self.has_rational_point(point=True, obstruction=False, algorithm='rnfisnorm', read_cache=False) if ret[0]: if point or obstruction: return ret return True if obstruction: - ret = self.has_rational_point(point=False, obstruction=True, - algorithm='local', - read_cache=False) + ret = self.has_rational_point(point=False, obstruction=True, algorithm='local', read_cache=False) if ret[0]: - raise RuntimeError("Outputs of algorithms in " - "has_rational_point disagree " - "for conic %s" % self) + raise RuntimeError("Outputs of algorithms in " "has_rational_point disagree " "for conic %s" % self) return ret if point: return False, None @@ -262,10 +255,8 @@ def has_rational_point(self, point=False, obstruction=False, if algorithm == 'local': if point: - raise ValueError("Algorithm 'local' cannot be combined " - "with point = True in has_rational_point") - obs = self.local_obstructions(infinite=True, finite=False, - read_cache=read_cache) + raise ValueError("Algorithm 'local' cannot be combined " "with point = True in has_rational_point") + obs = self.local_obstructions(infinite=True, finite=False, read_cache=read_cache) if obs: if obstruction: return False, obs[0] @@ -280,10 +271,9 @@ def has_rational_point(self, point=False, obstruction=False, return False if algorithm == 'rnfisnorm': from sage.modules.free_module_element import vector + if obstruction: - raise ValueError("Algorithm rnfisnorm cannot be combined " - "with obstruction = True in " - "has_rational_point") + raise ValueError("Algorithm rnfisnorm cannot be combined " "with obstruction = True in " "has_rational_point") D, T = self.diagonal_matrix() abc = [D[0, 0], D[1, 1], D[2, 2]] for j in range(3): @@ -315,8 +305,7 @@ def has_rational_point(self, point=False, obstruction=False, isnorm = BtoK(-abc[2] / abc[0]).is_norm(L, element=True) if isnorm[0]: - pt = self.point(T * vector([KtoB(isnorm[1][0]), - KtoB(isnorm[1][1] * den), 1])) + pt = self.point(T * vector([KtoB(isnorm[1][0]), KtoB(isnorm[1][1] * den), 1])) if point: return True, pt return True @@ -324,14 +313,11 @@ def has_rational_point(self, point=False, obstruction=False, return False, None return False if algorithm == 'qfsolve': - raise TypeError("Algorithm qfsolve in has_rational_point only " - "for conics over QQ, not over %s" % B) + raise TypeError("Algorithm qfsolve in has_rational_point only " "for conics over QQ, not over %s" % B) if obstruction: - raise ValueError("Invalid combination: obstruction=True and " - "algorithm=%s" % algorithm) + raise ValueError("Invalid combination: obstruction=True and " "algorithm=%s" % algorithm) - return ProjectiveConic_field.has_rational_point(self, point=point, - algorithm=algorithm, read_cache=False) + return ProjectiveConic_field.has_rational_point(self, point=point, algorithm=algorithm, read_cache=False) def is_locally_solvable(self, p): r""" @@ -423,6 +409,7 @@ def local_obstructions(self, finite=True, infinite=True, read_cache=True): obs0 = self._infinite_obstructions else: from sage.rings.qqbar import AA + for b in B.embeddings(AA): if not self.is_locally_solvable(b): obs0.append(b) diff --git a/src/sage/schemes/plane_conics/con_rational_field.py b/src/sage/schemes/plane_conics/con_rational_field.py index e53876ca933..035ed7bbab7 100644 --- a/src/sage/schemes/plane_conics/con_rational_field.py +++ b/src/sage/schemes/plane_conics/con_rational_field.py @@ -7,6 +7,7 @@ - Nick Alexander (2008-01-08) """ + # **************************************************************************** # Copyright (C) 2008 Nick Alexander # Copyright (C) 2009/2010 Marco Streng @@ -57,6 +58,7 @@ class ProjectiveConic_rational_field(ProjectiveConic_number_field): sage: Conic([2, 1, -1])._test_pickling() """ + def __init__(self, A, f): r""" See ``Conic`` for full documentation. @@ -68,8 +70,7 @@ def __init__(self, A, f): """ ProjectiveConic_number_field.__init__(self, A, f) - def has_rational_point(self, point=False, obstruction=False, - algorithm='default', read_cache=True) -> bool: + def has_rational_point(self, point=False, obstruction=False, algorithm='default', read_cache=True) -> bool: r""" Return ``True`` if and only if ``self`` has a point defined over `\QQ`. @@ -163,8 +164,7 @@ def has_rational_point(self, point=False, obstruction=False, if point or obstruction: return False, self._local_obstruction return False - if (not point) and self._finite_obstructions == [] and \ - self._infinite_obstructions == []: + if (not point) and self._finite_obstructions == [] and self._infinite_obstructions == []: if obstruction: return True, None return True @@ -188,14 +188,11 @@ def has_rational_point(self, point=False, obstruction=False, if point or obstruction: return True, pt return True - ret = ProjectiveConic_number_field.has_rational_point( - self, point=point, - obstruction=obstruction, - algorithm=algorithm, - read_cache=read_cache) + ret = ProjectiveConic_number_field.has_rational_point(self, point=point, obstruction=obstruction, algorithm=algorithm, read_cache=read_cache) if point or obstruction: from sage.categories.map import Map from sage.categories.rings import Rings + if isinstance(ret[1], Map) and ret[1].category_for().is_subcategory(Rings()): # ret[1] is a morphism of Rings ret[1] = -1 @@ -243,8 +240,7 @@ def is_locally_solvable(self, p) -> bool: if p.domain() is QQ and isinstance(p.codomain(), sage.rings.abc.RealField): p = -1 else: - raise TypeError("p (=%s) needs to be a prime of base field " - "B ( =`QQ`) in is_locally_solvable" % p) + raise TypeError("p (=%s) needs to be a prime of base field " "B ( =`QQ`) in is_locally_solvable" % p) if hilbert_symbol(a, b, p) == -1: if self._local_obstruction is None: self._local_obstruction = p diff --git a/src/sage/schemes/plane_conics/con_rational_function_field.py b/src/sage/schemes/plane_conics/con_rational_function_field.py index 8564149c684..4b3d0300f26 100644 --- a/src/sage/schemes/plane_conics/con_rational_function_field.py +++ b/src/sage/schemes/plane_conics/con_rational_function_field.py @@ -73,6 +73,7 @@ class ProjectiveConic_rational_function_field(ProjectiveConic_field): - [HC2006]_ - [Ack2016]_ """ + def __init__(self, A, f): r""" See ``Conic`` for full documentation. @@ -85,8 +86,7 @@ def __init__(self, A, f): """ ProjectiveConic_field.__init__(self, A, f) - def has_rational_point(self, point=False, algorithm='default', - read_cache=True): + def has_rational_point(self, point=False, algorithm='default', read_cache=True): r""" Return ``True`` if and only if the conic ``self`` has a point over its base field `F(t)`, which is a field of rational @@ -235,13 +235,14 @@ def has_rational_point(self, point=False, algorithm='default', return (True, self._rational_point) if point else True if algorithm != 'default': - return ProjectiveConic_field.has_rational_point(self, point, - algorithm, read_cache) + return ProjectiveConic_field.has_rational_point(self, point, algorithm, read_cache) # Default algorithm if self.base_ring().characteristic() == 2: - raise NotImplementedError("has_rational_point not implemented \ -for function field of characteristic 2.") + raise NotImplementedError( + "has_rational_point not implemented \ +for function field of characteristic 2." + ) new_conic, transformation, inverse = self.diagonalization() coeff = new_conic.coefficients() if coeff[0] == 0: @@ -256,15 +257,13 @@ def has_rational_point(self, point=False, algorithm='default', # to get a zero of the old conic (coeff, multipliers) = new_conic._reduce_conic() new_conic = Conic(coeff) - transformation = transformation \ - * new_conic.hom(diagonal_matrix(multipliers)) - if coeff[0].degree() % 2 == coeff[1].degree() % 2 and \ - coeff[1].degree() % 2 == coeff[2].degree() % 2: + transformation = transformation * new_conic.hom(diagonal_matrix(multipliers)) + if coeff[0].degree() % 2 == coeff[1].degree() % 2 and coeff[1].degree() % 2 == coeff[2].degree() % 2: case = 0 else: case = 1 - t, = self.base_ring().base().gens() # t in F[t] + (t,) = self.base_ring().base().gens() # t in F[t] supp = [] roots = [[], [], []] remove = None @@ -279,7 +278,7 @@ def has_rational_point(self, point=False, algorithm='default', x = p[0] / list(p[0])[-1] N = p[0].base_ring().extension(x, 'tbar') R = PolynomialRing(N, 'u') - u, = R.gens() + (u,) = R.gens() # If p[0] has degree 1, sage might forget the "defining # polynomial" of N, so we define our own modulo operation if p[0].degree() == 1: @@ -311,15 +310,11 @@ def has_rational_point(self, point=False, algorithm='default', if case == 0: # Find a solution of (5) in [HC2006] - leading_conic = Conic(self.base_ring().base_ring(), - [coeff[0].leading_coefficient(), - coeff[1].leading_coefficient(), - coeff[2].leading_coefficient()]) + leading_conic = Conic(self.base_ring().base_ring(), [coeff[0].leading_coefficient(), coeff[1].leading_coefficient(), coeff[2].leading_coefficient()]) has_point = leading_conic.has_rational_point(True) if has_point[0]: if point: - pt = new_conic.find_point(supp, roots, case, - has_point[1]) + pt = new_conic.find_point(supp, roots, case, has_point[1]) else: pt = True return (True, transformation(pt)) if point else True @@ -359,10 +354,8 @@ def _reduce_conic(self): """ # start with removing fractions - coeff = [self.coefficients()[0], self.coefficients()[3], - self.coefficients()[5]] - coeff = lcm(lcm(coeff[0].denominator(), coeff[1].denominator()), - coeff[2].denominator()) * vector(coeff) + coeff = [self.coefficients()[0], self.coefficients()[3], self.coefficients()[5]] + coeff = lcm(lcm(coeff[0].denominator(), coeff[1].denominator()), coeff[2].denominator()) * vector(coeff) # go to base ring of fraction field coeff = [self.base().base()(x) for x in coeff] coeff = vector(coeff) / gcd(coeff) @@ -472,11 +465,9 @@ def find_point(self, supports, roots, case, solution=0): """ Ft = self.base().base() F = Ft.base() - t, = Ft.gens() - coefficients = [Ft(self.coefficients()[0]), Ft(self.coefficients()[3]), - Ft(self.coefficients()[5])] - deg = [coefficients[0].degree(), coefficients[1].degree(), - coefficients[2].degree()] + (t,) = Ft.gens() + coefficients = [Ft(self.coefficients()[0]), Ft(self.coefficients()[3]), Ft(self.coefficients()[5])] + deg = [coefficients[0].degree(), coefficients[1].degree(), coefficients[2].degree()] # definitions as in [HC2006] and [Ack2016] A = ((deg[1] + deg[2]) / 2).ceil() - case B = ((deg[2] + deg[0]) / 2).ceil() - case @@ -488,7 +479,7 @@ def find_point(self, supports, roots, case, solution=0): # of monomials of x, y and z in the space V of potential solutions: # t^0, ..., t^A, t^0, ..., t^B and t^0, ..., t^C. phi = [] - for (i, p) in enumerate(supports[0]): + for i, p in enumerate(supports[0]): # lift to F[t] and map to R, with R as defined above if roots[0][i].parent().is_finite(): root = roots[0][i].polynomial() @@ -498,7 +489,7 @@ def find_point(self, supports, roots, case, solution=0): d = p.degree() # Calculate y - alpha*z mod p for all basis vectors phi_p = [[] for i in range(A + B + C + 4)] - phi_p[0:A + 1] = [vector(F, d)] * (A + 1) + phi_p[0 : A + 1] = [vector(F, d)] * (A + 1) phi_p[A + 1] = vector(F, d, {0: F(1)}) lastpoly = F(1) for n in range(B): @@ -511,7 +502,7 @@ def find_point(self, supports, roots, case, solution=0): phi_p[A + B + 3 + n] = vector(F, d, lastpoly.monomial_coefficients()) phi_p[A + B + C + 3] = vector(F, d) phi.append(matrix(phi_p).transpose()) - for (i, p) in enumerate(supports[1]): + for i, p in enumerate(supports[1]): if roots[1][i].parent().is_finite(): root = roots[1][i].polynomial() else: @@ -520,7 +511,7 @@ def find_point(self, supports, roots, case, solution=0): d = p.degree() # Calculate z - alpha*x mod p for all basis vectors phi_p = [[] for i in range(A + B + C + 4)] - phi_p[A + 1:A + B + 2] = [vector(F, d)] * (B + 1) + phi_p[A + 1 : A + B + 2] = [vector(F, d)] * (B + 1) phi_p[A + B + 2] = vector(F, d, {0: F(1)}) lastpoly = F(1) for n in range(C): @@ -533,7 +524,7 @@ def find_point(self, supports, roots, case, solution=0): phi_p[1 + n] = vector(F, d, lastpoly.monomial_coefficients()) phi_p[A + B + C + 3] = vector(F, d) phi.append(matrix(phi_p).transpose()) - for (i, p) in enumerate(supports[2]): + for i, p in enumerate(supports[2]): if roots[2][i].parent().is_finite(): root = roots[2][i].polynomial() else: @@ -542,7 +533,7 @@ def find_point(self, supports, roots, case, solution=0): d = p.degree() # Calculate x - alpha*y mod p for all basis vectors phi_p = [[] for i in range(A + B + C + 4)] - phi_p[A + B + 2:A + B + C + 3] = [vector(F, d)] * (C + 1) + phi_p[A + B + 2 : A + B + C + 3] = [vector(F, d)] * (C + 1) phi_p[0] = vector(F, d, {0: F(1)}) lastpoly = F(1) for n in range(A): @@ -561,19 +552,16 @@ def find_point(self, supports, roots, case, solution=0): ly = Ft(solution[1]).leading_coefficient() lz = Ft(solution[2]).leading_coefficient() ABC = A + B + C - phi.append(matrix([vector(F, ABC + 4, {A: 1, ABC + 3: -lx}), - vector(F, ABC + 4, {A + B + 1: 1, ABC + 3: -ly}), - vector(F, ABC + 4, {ABC + 2: 1, ABC + 3: -lz})])) + phi.append(matrix([vector(F, ABC + 4, {A: 1, ABC + 3: -lx}), vector(F, ABC + 4, {A + B + 1: 1, ABC + 3: -ly}), vector(F, ABC + 4, {ABC + 2: 1, ABC + 3: -lz})])) # Create the final matrix which we will solve M = block_matrix(phi, ncols=1, subdivide=False) solution_space = M.right_kernel() for v in solution_space.basis(): - if v[:A + B + C + 3] != 0: + if v[: A + B + C + 3] != 0: # we do not want to return a trivial solution - X = Ft(list(v[:A + 1])) - Y = Ft(list(v[A + 1:A + B + 2])) - Z = Ft(list(v[A + B + 2:A + B + C + 3])) + X = Ft(list(v[: A + 1])) + Y = Ft(list(v[A + 1 : A + B + 2])) + Z = Ft(list(v[A + B + 2 : A + B + C + 3])) return self.point([X, Y, Z]) - raise RuntimeError("No solution has been found: possibly incorrect " - "solubility certificate.") + raise RuntimeError("No solution has been found: possibly incorrect " "solubility certificate.") diff --git a/src/sage/schemes/plane_conics/constructor.py b/src/sage/schemes/plane_conics/constructor.py index 02743147aa5..9f70eb8c01a 100644 --- a/src/sage/schemes/plane_conics/constructor.py +++ b/src/sage/schemes/plane_conics/constructor.py @@ -7,6 +7,7 @@ - Nick Alexander (2008-01-08) """ + # **************************************************************************** # Copyright (C) 2008 Nick Alexander # Copyright (C) 2009/2010 Marco Streng @@ -165,21 +166,16 @@ def Conic(base_field, F=None, names=None, unique=True): if len(C) == 2: C.append(1) else: - raise TypeError("F (=%s) must be a sequence of planar " - "points" % F) + raise TypeError("F (=%s) must be a sequence of planar " "points" % F) if len(C) != 3: raise TypeError("points in F (=%s) must be planar" % F) P = C.universe() if P not in IntegralDomains(): - raise TypeError("coordinates of points in F (=%s) must " - "be in an integral domain" % F) - L.append(Sequence([C[0]**2, C[0] * C[1], - C[0] * C[2], C[1]**2, - C[1] * C[2], C[2]**2], P.fraction_field())) + raise TypeError("coordinates of points in F (=%s) must " "be in an integral domain" % F) + L.append(Sequence([C[0] ** 2, C[0] * C[1], C[0] * C[2], C[1] ** 2, C[1] * C[2], C[2] ** 2], P.fraction_field())) M = matrix(L) if unique and M.rank() != 5: - raise ValueError("points in F (=%s) do not define a unique " - "conic" % F) + raise ValueError("points in F (=%s) do not define a unique " "conic" % F) con = Conic(base_field, Sequence(M.right_kernel().gen()), names) con.point(F[0]) return con @@ -190,10 +186,8 @@ def Conic(base_field, F=None, names=None, unique=True): if len(F) == 3: return Conic(F[0] * x**2 + F[1] * y**2 + F[2] * z**2) if len(F) == 6: - return Conic(F[0] * x**2 + F[1] * x * y + F[2] * x * z + - F[3] * y**2 + F[4] * y * z + F[5] * z**2) - raise TypeError("F (=%s) must be a sequence of 3 or 6" - "coefficients" % F) + return Conic(F[0] * x**2 + F[1] * x * y + F[2] * x * z + F[3] * y**2 + F[4] * y * z + F[5] * z**2) + raise TypeError("F (=%s) must be a sequence of 3 or 6" "coefficients" % F) from sage.quadratic_forms.quadratic_form import QuadraticForm @@ -206,8 +200,7 @@ def Conic(base_field, F=None, names=None, unique=True): F = vector(temp_ring.gens()) * F * vector(temp_ring.gens()) if not isinstance(F, MPolynomial): - raise TypeError("F (=%s) must be a three-variable polynomial or " - "a sequence of points or coefficients" % F) + raise TypeError("F (=%s) must be a three-variable polynomial or " "a sequence of points or coefficients" % F) if F.total_degree() != 2: raise TypeError("F (=%s) must have degree 2" % F) @@ -229,8 +222,7 @@ def Conic(base_field, F=None, names=None, unique=True): raise ValueError("F must be nonzero over base field %s" % base_field) if F.total_degree() != 2: - raise TypeError("F (=%s) must have degree 2 over base field %s" % - (F, base_field)) + raise TypeError("F (=%s) must have degree 2 over base field %s" % (F, base_field)) if F.parent().ngens() == 3: P2 = ProjectiveSpace(2, base_field, names) diff --git a/src/sage/schemes/plane_quartics/quartic_constructor.py b/src/sage/schemes/plane_quartics/quartic_constructor.py index 29d49c2d2c4..0b45d8c0eaf 100644 --- a/src/sage/schemes/plane_quartics/quartic_constructor.py +++ b/src/sage/schemes/plane_quartics/quartic_constructor.py @@ -2,11 +2,11 @@ Quartic curve constructor """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2006 David Kohel # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.schemes.projective.projective_space import ProjectiveSpace_ring, ProjectiveSpace from sage.rings.polynomial.multi_polynomial import MPolynomial diff --git a/src/sage/schemes/product_projective/homset.py b/src/sage/schemes/product_projective/homset.py index 50b223f26a7..a2d34336c04 100644 --- a/src/sage/schemes/product_projective/homset.py +++ b/src/sage/schemes/product_projective/homset.py @@ -8,7 +8,7 @@ - Raghukul Raman (2018): code cleanup and added support for rational field """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2014 Volker Braun # Ben Hutz # @@ -16,7 +16,7 @@ # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.categories.fields import Fields from sage.categories.number_fields import NumberFields @@ -186,6 +186,7 @@ def points(self, **kwds): X = self.codomain() from sage.schemes.product_projective.space import ProductProjectiveSpaces_ring + if not isinstance(X, ProductProjectiveSpaces_ring) and X.base_ring() in Fields(): # no points if X.dimension() == -1: @@ -208,26 +209,32 @@ def points(self, **kwds): alg = kwds.pop('algorithm', None) if alg is None: # sieve should only be called for subschemes and if the bound is not very small - N = prod([k+1 for k in X.ambient_space().dimension_relative_components()]) - if isinstance(X, AlgebraicScheme_subscheme) and B**N > 5000: + N = prod([k + 1 for k in X.ambient_space().dimension_relative_components()]) + if isinstance(X, AlgebraicScheme_subscheme) and B ** N > 5000: from sage.schemes.product_projective.rational_point import sieve + return sieve(X, B) from sage.schemes.product_projective.rational_point import enum_product_projective_rational_field + return enum_product_projective_rational_field(self, B) if alg == 'sieve': from sage.schemes.product_projective.rational_point import sieve + return sieve(X, B) if alg == 'enumerate': from sage.schemes.product_projective.rational_point import enum_product_projective_rational_field + return enum_product_projective_rational_field(self, B) raise ValueError("algorithm must be 'sieve' or 'enumerate'") elif R in NumberFields(): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.product_projective.rational_point import enum_product_projective_number_field + return enum_product_projective_number_field(self, bound=B) elif isinstance(R, FiniteField): from sage.schemes.product_projective.rational_point import enum_product_projective_finite_field + return enum_product_projective_finite_field(self) else: raise TypeError("unable to enumerate points over %s" % R) diff --git a/src/sage/schemes/product_projective/morphism.py b/src/sage/schemes/product_projective/morphism.py index 95bd78fd488..777f75642f3 100644 --- a/src/sage/schemes/product_projective/morphism.py +++ b/src/sage/schemes/product_projective/morphism.py @@ -11,6 +11,7 @@ Scheme endomorphism of Product of projective spaces P^1 x P^1 over Rational Field Defn: Defined by sending (x : y , u : v) to (x^2*u : y^2*v , x*v^2 : y*u^2). """ + # **************************************************************************** # Copyright (C) 2014 Ben Hutz # @@ -103,8 +104,8 @@ def __init__(self, parent, polys, check=True): multi-homogeneous of the same degrees (by component) """ if check: - #check multi-homogeneous - #if self is a subscheme, we may need the lift of the polynomials + # check multi-homogeneous + # if self is a subscheme, we may need the lift of the polynomials try: polys[0].exponents() except AttributeError: @@ -113,6 +114,7 @@ def __init__(self, parent, polys, check=True): target = parent.codomain().ambient_space() dom = parent.domain().ambient_space() from sage.schemes.product_projective.space import ProductProjectiveSpaces_ring + if isinstance(target, ProductProjectiveSpaces_ring): splitpolys = target._factors(polys) for m in range(len(splitpolys)): @@ -120,7 +122,7 @@ def __init__(self, parent, polys, check=True): if not all(d == dom._degree(f) for f in splitpolys[m]): raise TypeError("polys (=%s) must be multi-homogeneous of the same degrees (by component)" % polys) else: - #we are mapping into some other kind of space + # we are mapping into some other kind of space target._validate(polys) SchemeMorphism_polynomial.__init__(self, parent, polys, check) @@ -223,6 +225,7 @@ def __call__(self, P, check=True): (0 : 0 , 0 : 0) """ from sage.schemes.product_projective.point import ProductProjectiveSpaces_point_ring + if check: if not isinstance(P, ProductProjectiveSpaces_point_ring): try: @@ -286,19 +289,19 @@ def __eq__(self, right): PP = self.parent().codomain() n = PP.n_components() - dim = [ P.ngens() for P in PP ] - dim_prefix = [0,dim[0]] + dim = [P.ngens() for P in PP] + dim_prefix = [0, dim[0]] - for i in range(1,n): + for i in range(1, n): dim_prefix.append(dim_prefix[i] + dim[i]) # compare ratio of coordinates for each projective component for m in range(n): l = dim_prefix[m] r = dim_prefix[m] + dim[m] - for i in range(l,r): - for j in range(i+1,r): - if self[i]*right[j] != self[j]*right[i]: + for i in range(l, r): + for j in range(i + 1, r): + if self[i] * right[j] != self[j] * right[i]: return False return True @@ -333,18 +336,18 @@ def __ne__(self, right): PP = self.parent().codomain() n = PP.n_components() - dim = [ P.ngens() for P in PP ] - dim_prefix = [0,dim[0]] + dim = [P.ngens() for P in PP] + dim_prefix = [0, dim[0]] - for i in range(1,n): + for i in range(1, n): dim_prefix.append(dim_prefix[i] + dim[i]) for m in range(n): l = dim_prefix[m] r = dim_prefix[m] + dim[m] - for i in range(l,r): - for j in range(i+1,r): - if self[i]*right[j] != self[j]*right[i]: + for i in range(l, r): + for j in range(i + 1, r): + if self[i] * right[j] != self[j] * right[i]: return True return False @@ -419,6 +422,7 @@ def as_dynamical_system(self): if not self.is_endomorphism(): raise TypeError("must be an endomorphism") from sage.dynamics.arithmetic_dynamics.product_projective_ds import DynamicalSystem_product_projective + return DynamicalSystem_product_projective(list(self), self.domain()) def global_height(self, prec=None): diff --git a/src/sage/schemes/product_projective/point.py b/src/sage/schemes/product_projective/point.py index 246fe3fe0d2..79dff578c23 100644 --- a/src/sage/schemes/product_projective/point.py +++ b/src/sage/schemes/product_projective/point.py @@ -11,6 +11,7 @@ sage: P1xP1([2, 1, 3, 1]) (2 : 1 , 3 : 1) """ + # **************************************************************************** # Copyright (C) 2014 Volker Braun # Ben Hutz @@ -46,6 +47,7 @@ class ProductProjectiveSpaces_point_ring(SchemeMorphism_point): sage: T.point([1, 2, 3, 4, 5]) (1/3 : 2/3 : 1 , 4/5 : 1) """ + def __init__(self, parent, polys, check=True): r""" The Python constructor. @@ -140,8 +142,7 @@ def _repr_(self): sage: P._repr_() '(1 : 2 : 3 , 4 : 5 : 6)' """ - return '(%s)' % (" , ".join((" : ".join(repr(f) for f in Q)) - for Q in self._points)) + return '(%s)' % (" , ".join((" : ".join(repr(f) for f in Q)) for Q in self._points)) def _richcmp_(self, right, op): r""" @@ -193,7 +194,7 @@ def _richcmp_(self, right, op): sage: P < Q True """ - #needed for Digraph + # needed for Digraph if not isinstance(right, (ProductProjectiveSpaces_point_ring)): return NotImplemented return richcmp(self._points, right._points, op) @@ -215,7 +216,7 @@ def __copy__(self): True """ P = [copy(self[i]) for i in range(self.codomain().ambient_space().n_components())] - return (self.codomain().point(P, False)) + return self.codomain().point(P, False) def __iter__(self): r""" @@ -529,6 +530,7 @@ def intersection_multiplicity(self, X): 2 """ from sage.schemes.product_projective.space import ProductProjectiveSpaces_ring + if isinstance(self.codomain(), ProductProjectiveSpaces_ring): raise TypeError("this point must be a point on a subscheme of a product of projective spaces") return self.codomain().intersection_multiplicity(X, self) @@ -557,6 +559,7 @@ def multiplicity(self): 6 """ from sage.schemes.product_projective.space import ProductProjectiveSpaces_ring + if isinstance(self.codomain(), ProductProjectiveSpaces_ring): raise TypeError("this point must be a point on a subscheme of a product of projective spaces") return self.codomain().multiplicity(self) diff --git a/src/sage/schemes/product_projective/rational_point.py b/src/sage/schemes/product_projective/rational_point.py index 97c16beb769..2df3b36f0ab 100644 --- a/src/sage/schemes/product_projective/rational_point.py +++ b/src/sage/schemes/product_projective/rational_point.py @@ -164,7 +164,7 @@ def enum_product_projective_rational_field(X, B): i = 0 except StopIteration: iters[i] = R[i].points_of_bounded_height(bound=B) - pt = next(iters[i]) # reset + pt = next(iters[i]) # reset for j in range(dim[i]): P[dim_prefix[i] + j] = pt[j] i += 1 @@ -359,19 +359,19 @@ def sieve(X, bound): num_comp = P.n_components() comp_dim_relative = [P[i].dimension_relative() + 1 for i in range(num_comp)] - dim_prefix = [0, comp_dim_relative[0]] # prefixes dim list + dim_prefix = [0, comp_dim_relative[0]] # prefixes dim list for i in range(1, len(comp_dim_relative)): dim_prefix.append(dim_prefix[i] + comp_dim_relative[i]) dim_max = max(P[i].dimension() for i in range(num_comp)) - B = RR(2**(dim_max/4+1)*bound**2*(dim_max+1).sqrt()) + B = RR(2 ** (dim_max / 4 + 1) * bound**2 * (dim_max + 1).sqrt()) m = [] def sufficient_primes(x): r""" Return a list of primes whose product is > `x`. """ - small_primes = [2,3] + small_primes = [2, 3] prod_primes = 6 while prod_primes < x: @@ -401,11 +401,11 @@ def good_primes(B): dim = X.ambient_space().dimension() while current_count > 1: - current_list = [] # stores prime which are bigger than least + current_list = [] # stores prime which are bigger than least updated_list = [] best_list = [] - least = (RR(B)**(1.00/current_count)).floor() + least = (RR(B) ** (1.00 / current_count)).floor() for i in range(current_count): current_list.append(next_prime(least)) least = current_list[-1] @@ -414,7 +414,7 @@ def good_primes(B): prod_prime = prod(current_list) least = current_list[0] while least != 2 and prod_prime > B and len(updated_list) < current_count: - best_list = updated_list + current_list[:current_count - len(updated_list)] + best_list = updated_list + current_list[: current_count - len(updated_list)] updated_list.append(previous_prime(least)) least = updated_list[-1] @@ -425,9 +425,9 @@ def good_primes(B): current_count = current_count - 1 best_size = 2 - best_time = (dim**2)*M[2][-1]**(dim) + (dim_max**5 * (prod(M[2])/M[2][-1])**dim_scheme) + best_time = (dim**2) * M[2][-1] ** (dim) + (dim_max**5 * (prod(M[2]) / M[2][-1]) ** dim_scheme) for i in range(2, max_length + 1): - current_time = (dim**2)*M[i][-1]**(dim) + (dim_max**5 * (prod(M[i])/M[i][-1])**dim_scheme) + current_time = (dim**2) * M[i][-1] ** (dim) + (dim_max**5 * (prod(M[i]) / M[i][-1]) ** dim_scheme) if current_time < best_time: best_size = i best_time = current_time @@ -449,7 +449,16 @@ def points_modulo_primes(X, primes): Return a list of rational points modulo all `p` in primes, computed parallelly. """ - normalized_input = [((X, p, ), {}) for p in primes_list] + normalized_input = [ + ( + ( + X, + p, + ), + {}, + ) + for p in primes_list + ] p_iter = p_iter_fork(ncpus()) points_pair = list(p_iter(parallel_function, normalized_input)) @@ -475,9 +484,7 @@ def parallel_function_combination(point_p_max): m[i][j] = point[dim_prefix[i] + j] # generating matrix to compute LLL reduction for each component - M = [matrix(ZZ, comp_dim_relative[i] + 1, - comp_dim_relative[i], m[i]) - for i in range(num_comp)] + M = [matrix(ZZ, comp_dim_relative[i] + 1, comp_dim_relative[i], m[i]) for i in range(num_comp)] A = [M[i].LLL() for i in range(num_comp)] point = [] for i in range(num_comp): @@ -507,7 +514,7 @@ def lift_all_points(): points = modulo_points.pop() # remove the list of points corresponding to largest prime len_modulo_points.pop() - normalized_input = [((point, ), {}) for point in points] + normalized_input = [((point,), {}) for point in points] p_iter = p_iter_fork(ncpus()) points_satisfying = list(p_iter(parallel_function_combination, normalized_input)) diff --git a/src/sage/schemes/product_projective/space.py b/src/sage/schemes/product_projective/space.py index efbcbcf3d9a..ac33d26457e 100644 --- a/src/sage/schemes/product_projective/space.py +++ b/src/sage/schemes/product_projective/space.py @@ -52,11 +52,8 @@ from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme from sage.schemes.generic.ambient_space import AmbientSpace from sage.schemes.projective.projective_space import ProjectiveSpace, ProjectiveSpace_ring -from sage.schemes.product_projective.homset import (SchemeHomset_points_product_projective_spaces_ring, - SchemeHomset_points_product_projective_spaces_field) -from sage.schemes.product_projective.point import (ProductProjectiveSpaces_point_ring, - ProductProjectiveSpaces_point_field, - ProductProjectiveSpaces_point_finite_field) +from sage.schemes.product_projective.homset import SchemeHomset_points_product_projective_spaces_ring, SchemeHomset_points_product_projective_spaces_field +from sage.schemes.product_projective.point import ProductProjectiveSpaces_point_ring, ProductProjectiveSpaces_point_field, ProductProjectiveSpaces_point_finite_field from sage.schemes.product_projective.morphism import ProductProjectiveSpaces_morphism_ring from sage.schemes.product_projective.subscheme import AlgebraicScheme_subscheme_product_projective @@ -131,6 +128,7 @@ def ProductProjectiveSpaces(n, R=None, names='x'): if R not in CommutativeRings(): raise ValueError("must be a commutative ring") from sage.structure.category_object import normalize_names + n_vars = sum(d + 1 for d in n) if isinstance(names, str): names = normalize_names(n_vars, names) @@ -175,6 +173,7 @@ class ProductProjectiveSpaces_ring(AmbientSpace): sage: f(Q) (4 : 1 , 1 : 2 : 1) """ + def __init__(self, N, R=QQ, names=None): r""" The Python constructor. @@ -219,8 +218,7 @@ def __init__(self, N, R=QQ, names=None): start = 0 self._components = [] for i, Ni in enumerate(N): - self._components.append(ProjectiveSpace(Ni, R, - names[start:start + Ni + 1])) + self._components.append(ProjectiveSpace(Ni, R, names[start : start + Ni + 1])) start += Ni + 1 # Note that the coordinate ring should really be the tensor product of # the component coordinate rings. But we just deal with them as @@ -237,9 +235,7 @@ def _repr_(self): sage: ProductProjectiveSpaces([1, 1, 1], ZZ, ['x', 'y', 'z', 'u', 'v', 'w']) Product of projective spaces P^1 x P^1 x P^1 over Integer Ring """ - return ''.join(['Product of projective spaces ', - ' x '.join('P^{}'.format(d) for d in self._dims), - ' over ', str(self.base_ring())]) + return ''.join(['Product of projective spaces ', ' x '.join('P^{}'.format(d) for d in self._dims), ' over ', str(self.base_ring())]) def _repr_generic_point(self, v=None): """ @@ -260,8 +256,7 @@ def _repr_generic_point(self, v=None): else: v = list(v) splitv = self._factors(v) - return '(%s)' % (" , ".join((" : ".join(str(t) for t in P)) - for P in splitv)) + return '(%s)' % (" , ".join((" : ".join(str(t) for t in P)) for P in splitv)) def _latex_(self): r""" @@ -603,7 +598,7 @@ def _factors(self, v): splitv = [] dims = self._dims for i in range(len(dims)): - splitv.append(v[index:index + dims[i] + 1]) + splitv.append(v[index : index + dims[i] + 1]) index += dims[i] + 1 return splitv @@ -789,7 +784,7 @@ def _check_satisfies_equations(self, v): N = self._dims start = 0 for i in range(len(N)): - if v[start:start + N[i] + 1] == [R.zero()] * (N[i] + 1): + if v[start : start + N[i] + 1] == [R.zero()] * (N[i] + 1): raise TypeError('the zero vector is not a point in projective space') start += N[i] + 1 return True @@ -913,7 +908,7 @@ def affine_patch(self, I, return_embedding=False): N = PP._dims if len(I) != len(N): raise ValueError(f'the argument I={I} must have {len(N)} entries') - I = tuple([int(i) for i in I]) # implicit type checking + I = tuple([int(i) for i in I]) # implicit type checking for i in range(len(I)): if I[i] < 0 or I[i] > N[i]: raise ValueError("argument i (= %s) must be between 0 and %s." % (I[i], N[i])) @@ -926,6 +921,7 @@ def affine_patch(self, I, return_embedding=False): except KeyError: pass from sage.schemes.affine.affine_space import AffineSpace + AA = AffineSpace(PP.base_ring(), sum(N), 'x') v = list(AA.gens()) index = 0 @@ -1011,16 +1007,14 @@ def segre_embedding(self, PP=None, var='u'): CR = self.coordinate_ring() vars = list(self.coordinate_ring().variable_names()) + [var + str(i) for i in range(M + 1)] - R = PolynomialRing(self.base_ring(), self.ngens() + M + 1, - vars, order='lex') + R = PolynomialRing(self.base_ring(), self.ngens() + M + 1, vars, order='lex') # set-up the elimination for the Segre embedding mapping = [] k = self.ngens() index = self.n_components() * [0] for count in range(M + 1): - mapping.append(R.gen(k + count) - prod([CR(self[i].gen(index[i])) - for i in range(len(index))])) + mapping.append(R.gen(k + count) - prod([CR(self[i].gen(index[i])) for i in range(len(index))])) for i in range(len(index) - 1, -1, -1): if index[i] == N[i]: index[i] = 0 @@ -1031,7 +1025,7 @@ def segre_embedding(self, PP=None, var='u'): # change the defining ideal of the subscheme into the variables I = R.ideal(list(self.defining_polynomials()) + mapping) J = I.groebner_basis() - s = set(R.gens()[:self.ngens()]) + s = set(R.gens()[: self.ngens()]) n = len(J) - 1 L = [] while s.isdisjoint(J[n].variables()): @@ -1040,7 +1034,7 @@ def segre_embedding(self, PP=None, var='u'): # create new subscheme if PP is None: - PS = ProjectiveSpace(self.base_ring(), M, R.variable_names()[self.ngens():]) + PS = ProjectiveSpace(self.base_ring(), M, R.variable_names()[self.ngens() :]) Y = PS.subscheme(L) else: if PP.dimension_relative() != M: @@ -1177,9 +1171,7 @@ def points_of_bounded_height(self, **kwds): tol = kwds.pop('tolerance', 1e-2) prec = kwds.pop('precision', 53) m = self.n_components() - iters = [self[i].points_of_bounded_height(bound=B, tolerance=tol, - precision=prec) - for i in range(m)] + iters = [self[i].points_of_bounded_height(bound=B, tolerance=tol, precision=prec) for i in range(m)] dim = [self[i].dimension_relative() + 1 for i in range(m)] dim_prefix = [0, dim[0]] # prefixes dim list diff --git a/src/sage/schemes/product_projective/subscheme.py b/src/sage/schemes/product_projective/subscheme.py index b698ab40298..c7521339157 100644 --- a/src/sage/schemes/product_projective/subscheme.py +++ b/src/sage/schemes/product_projective/subscheme.py @@ -6,14 +6,14 @@ - Ben Hutz (2014): subschemes of Cartesian products of projective space """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2014 Ben Hutz # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from sage.misc.misc_c import prod from sage.misc.cachefunc import cached_method @@ -126,57 +126,57 @@ def segre_embedding(self, PP=None): AS = self.ambient_space() CR = AS.coordinate_ring() N = AS.dimension_relative_components() - M = prod([n+1 for n in N]) - 1 + M = prod([n + 1 for n in N]) - 1 - vars = list(AS.coordinate_ring().variable_names()) + ['u' + str(i) for i in range(M+1)] - R = PolynomialRing(AS.base_ring(), AS.ngens()+M+1, vars, order='lex') + vars = list(AS.coordinate_ring().variable_names()) + ['u' + str(i) for i in range(M + 1)] + R = PolynomialRing(AS.base_ring(), AS.ngens() + M + 1, vars, order='lex') - #set-up the elimination for the segre embedding + # set-up the elimination for the segre embedding mapping = [] k = AS.ngens() - index = AS.n_components()*[0] + index = AS.n_components() * [0] for count in range(M + 1): - mapping.append(R.gen(k+count)-prod([CR(AS[i].gen(index[i])) for i in range(len(index))])) - for i in range(len(index)-1, -1, -1): + mapping.append(R.gen(k + count) - prod([CR(AS[i].gen(index[i])) for i in range(len(index))])) + for i in range(len(index) - 1, -1, -1): if index[i] == N[i]: index[i] = 0 else: index[i] += 1 - break #only increment once + break # only increment once - #change the defining ideal of the subscheme into the variables + # change the defining ideal of the subscheme into the variables I = R.ideal(list(self.defining_polynomials()) + mapping) J = I.groebner_basis() - s = set(R.gens()[:AS.ngens()]) - n = len(J)-1 + s = set(R.gens()[: AS.ngens()]) + n = len(J) - 1 L = [] while s.isdisjoint(J[n].variables()): L.append(J[n]) - n = n-1 + n = n - 1 - #create new subscheme + # create new subscheme if PP is None: - PS = ProjectiveSpace(self.base_ring(), M, R.gens()[AS.ngens():]) + PS = ProjectiveSpace(self.base_ring(), M, R.gens()[AS.ngens() :]) Y = PS.subscheme(L) else: if PP.dimension_relative() != M: raise ValueError("projective space %s must be dimension %s") % (PP, M) S = PP.coordinate_ring() - psi = R.hom([0]*k + list(S.gens()), S) + psi = R.hom([0] * k + list(S.gens()), S) L = [psi(l) for l in L] Y = PP.subscheme(L) - #create embedding for points + # create embedding for points mapping = [] - index = AS.n_components()*[0] + index = AS.n_components() * [0] for count in range(M + 1): mapping.append(prod([CR(AS[i].gen(index[i])) for i in range(len(index))])) - for i in range(len(index)-1, -1, -1): + for i in range(len(index) - 1, -1, -1): if index[i] == N[i]: index[i] = 0 else: index[i] += 1 - break #only increment once + break # only increment once phi = self.hom(mapping, Y) return phi @@ -227,17 +227,16 @@ def dimension(self): return self.__dimension except AttributeError: try: - #move to field to compute radical + # move to field to compute radical X = self.change_ring(FractionField(self.base_ring())) PP = X.ambient_space() I = X.defining_ideal().radical() - #check if the irrelevant ideal of any component is in the radical - if any(all(t in I for t in PS.gens()) - for PS in PP.components()): + # check if the irrelevant ideal of any component is in the radical + if any(all(t in I for t in PS.gens()) for PS in PP.components()): self.__dimension = -1 else: self.__dimension = I.dimension() - PP.n_components() - except TypeError: #cannot compute radical for this base ring + except TypeError: # cannot compute radical for this base ring phi = self.segre_embedding() self.__dimension = phi.codomain().defining_ideal().dimension() - 1 return self.__dimension @@ -300,12 +299,12 @@ def affine_patch(self, I, return_embedding=False): PP = self.ambient_space() N = PP.dimension_relative_components() if len(I) != len(N): - raise ValueError('The argument I=%s must have %s entries' % (I,len(N))) - I = tuple([int(i) for i in I]) # implicit type checking + raise ValueError('The argument I=%s must have %s entries' % (I, len(N))) + I = tuple([int(i) for i in I]) # implicit type checking for i in range(len(I)): if I[i] < 0 or I[i] > N[i]: raise ValueError("Argument i (= %s) must be between 0 and %s." % (I[i], N[i])) - #see if we've already created this affine patch + # see if we've already created this affine patch try: if return_embedding: return self.__affine_patches[I] @@ -314,22 +313,22 @@ def affine_patch(self, I, return_embedding=False): self.__affine_patches = {} except KeyError: pass - AA = AffineSpace(PP.base_ring(),sum(N),'x') + AA = AffineSpace(PP.base_ring(), sum(N), 'x') v = list(AA.gens()) # create the projective embedding index = 0 for i in range(len(I)): - v.insert(index+I[i],1) - index += N[i]+1 - phi = AA.hom(v,self) - #find the image of the subscheme + v.insert(index + I[i], 1) + index += N[i] + 1 + phi = AA.hom(v, self) + # find the image of the subscheme polys = self.defining_polynomials() xi = phi.defining_polynomials() - U = AA.subscheme([ f(xi) for f in polys ]) - phi = U.hom(v,self) - self.__affine_patches.update({I:(U,phi)}) + U = AA.subscheme([f(xi) for f in polys]) + phi = U.hom(v, self) + self.__affine_patches.update({I: (U, phi)}) if return_embedding: - return U,phi + return U, phi return U def intersection_multiplicity(self, X, P): @@ -388,7 +387,7 @@ def intersection_multiplicity(self, X, P): try: PP(P) except TypeError: - raise TypeError("(=%s) must be a point in the ambient space of this subscheme and (=%s)" % (P,X)) + raise TypeError("(=%s) must be a point in the ambient space of this subscheme and (=%s)" % (P, X)) # find an affine chart of the ambient space of this subscheme that contains P indices = [] aff_pt = [] @@ -400,7 +399,7 @@ def intersection_multiplicity(self, X, P): indices.append(j) T = list(Q) t = T.pop(j) - aff_pt.extend([1/t*T[k] for k in range(PP.components()[i].dimension_relative())]) + aff_pt.extend([1 / t * T[k] for k in range(PP.components()[i].dimension_relative())]) X1 = self.affine_patch(indices) X2 = X.affine_patch(indices) return X1.intersection_multiplicity(X2, X1.ambient_space()(aff_pt)) @@ -445,8 +444,7 @@ def multiplicity(self, P): try: PP(P) except TypeError: - raise TypeError("(={}) must be a point in the ambient space of this " - "subscheme and (={})".format(P, self)) + raise TypeError("(={}) must be a point in the ambient space of this " "subscheme and (={})".format(P, self)) # find an affine chart of the ambient space of this subscheme that contains P indices = [] aff_pt = [] @@ -458,6 +456,6 @@ def multiplicity(self, P): indices.append(j) T = list(Q) t = T.pop(j) - aff_pt.extend([1/t*T[k] for k in range(PP.components()[i].dimension_relative())]) + aff_pt.extend([1 / t * T[k] for k in range(PP.components()[i].dimension_relative())]) X = self.affine_patch(indices) return X.multiplicity(X.ambient_space()(aff_pt)) diff --git a/src/sage/schemes/projective/proj_bdd_height.py b/src/sage/schemes/projective/proj_bdd_height.py index 39be55337b1..d26e52afea3 100644 --- a/src/sage/schemes/projective/proj_bdd_height.py +++ b/src/sage/schemes/projective/proj_bdd_height.py @@ -79,7 +79,7 @@ def ZZ_points_of_bounded_height(PS, dim, bound): points_of_bounded_height = set() - for t in itertools.product(range(-bound, bound+1), repeat=dim+1): + for t in itertools.product(range(-bound, bound + 1), repeat=dim + 1): if gcd(t) == 1: point = PS(t) if point not in points_of_bounded_height: @@ -137,7 +137,7 @@ def QQ_points_of_bounded_height(PS, dim, bound, normalize=False): if gcd(t) == 1: for p in itertools.permutations(t): for u in unit_tuples: - point = PS([a*b for a, b in zip(u, p)] + [p[dim]]) + point = PS([a * b for a, b in zip(u, p)] + [p[dim]]) if point not in points_of_bounded_height: if normalize: point.scale_by(lcm([point[i].denominator() for i in range(dim + 1)])) @@ -329,7 +329,7 @@ def points_of_bounded_height(PS, K, dim, bound, prec=53): for c in pari(cut_fund_unit_logs).qflll().python(): new_unit = 1 for i in range(r): - new_unit *= fundamental_units[i]**c[i] + new_unit *= fundamental_units[i] ** c[i] lll_fund_units.append(new_unit) fundamental_units = lll_fund_units fund_unit_logs = list(map(log_embed, fundamental_units)) @@ -337,7 +337,7 @@ def points_of_bounded_height(PS, K, dim, bound, prec=53): possible_norm_set = set() for i in range(class_number): for k in range(1, floor(bound + 1)): - possible_norm_set.add(k*class_group_ideal_norms[i]) + possible_norm_set.add(k * class_group_ideal_norms[i]) principal_ideal_gens = {} negative_norm_units = K.elements_of_norm(-1) @@ -354,35 +354,31 @@ def points_of_bounded_height(PS, K, dim, bound, prec=53): pr_ideal_gen_logs[y] = log_embed(y) fund_parallelotope_vertices = [] - for coefficient_tuple in itertools.product([-1/2, 1/2], repeat=r): - vertex = sum([coefficient_tuple[i]*fund_unit_logs[i] for i in range(r)]) + for coefficient_tuple in itertools.product([-1 / 2, 1 / 2], repeat=r): + vertex = sum([coefficient_tuple[i] * fund_unit_logs[i] for i in range(r)]) fund_parallelotope_vertices.append(vertex) - D_numbers = [max(vertex[v] for vertex in fund_parallelotope_vertices) - for v in range(r + 1)] + D_numbers = [max(vertex[v] for vertex in fund_parallelotope_vertices) for v in range(r + 1)] - A_numbers = [min(pr_ideal_gen_logs[y][v] for y in pr_ideal_gen_logs) - for v in range(r + 1)] + A_numbers = [min(pr_ideal_gen_logs[y][v] for y in pr_ideal_gen_logs) for v in range(r + 1)] aux_constant = (1 / K_degree) * Reals(norm_bound).log() - L_numbers = [aux_constant + D_numbers[v] - A_numbers[v] - for v in range(r1)] - L_numbers.extend(2 * aux_constant + D_numbers[v] - A_numbers[v] - for v in range(r1, r + 1)) + L_numbers = [aux_constant + D_numbers[v] - A_numbers[v] for v in range(r1)] + L_numbers.extend(2 * aux_constant + D_numbers[v] - A_numbers[v] for v in range(r1, r + 1)) L_numbers = vector(L_numbers).change_ring(QQ) T = column_matrix(fund_unit_logs).delete_rows([r]).change_ring(QQ) # insert_row only takes integers, see https://github.com/sagemath/sage/issues/11328 - M = ((-1)*matrix.identity(r)).insert_row(r, [Integer(1) for i in range(r)]) + M = ((-1) * matrix.identity(r)).insert_row(r, [Integer(1) for i in range(r)]) M = M.transpose().insert_row(0, [Integer(0) for i in range(r + 1)]).transpose() M = M.change_ring(QQ) M.set_column(0, L_numbers) vertices = map(vector, Polyhedron(ieqs=list(M)).vertices()) T_it = T.inverse().transpose() - unit_polytope = Polyhedron([v*T_it for v in vertices]) + unit_polytope = Polyhedron([v * T_it for v in vertices]) coordinate_space = {} coordinate_space[0] = [[K(0), log_embed(0)]] @@ -392,8 +388,8 @@ def points_of_bounded_height(PS, K, dim, bound, prec=53): for n in int_points: new_unit = 1 for j in range(r): - new_unit *= fundamental_units[j]**n[j] - new_unit_log = sum([n[j]*fund_unit_logs[j] for j in range(r)]) + new_unit *= fundamental_units[j] ** n[j] + new_unit_log = sum([n[j] * fund_unit_logs[j] for j in range(r)]) units_with_logs[n] = [new_unit, new_unit_log] for norm in principal_ideal_gens: @@ -415,7 +411,7 @@ def points_of_bounded_height(PS, K, dim, bound, prec=53): a = class_group_ideals[m] a_norm = class_group_ideal_norms[m] log_a_norm = Reals(a_norm).log() - a_const = (logB + log_a_norm)/K_degree + a_const = (logB + log_a_norm) / K_degree a_coordinates = [] for k in range(floor(bound + 1)): @@ -440,7 +436,7 @@ def points_of_bounded_height(PS, K, dim, bound, prec=53): if log_arch_height <= log_arch_height_bound and a == K.ideal(point_coordinates): for p in itertools.permutations(point_coordinates): for u in unit_tuples: - point = PS([i*j for i, j in zip(u, p)] + [p[dim]]) + point = PS([i * j for i, j in zip(u, p)] + [p[dim]]) if point not in points_in_class_a: points_in_class_a.add(point) diff --git a/src/sage/schemes/projective/projective_homset.py b/src/sage/schemes/projective/projective_homset.py index 64fb5321eb6..7ac3d30492d 100644 --- a/src/sage/schemes/projective/projective_homset.py +++ b/src/sage/schemes/projective/projective_homset.py @@ -58,6 +58,7 @@ # Projective varieties # ******************************************************************* + class SchemeHomset_points_projective_field(SchemeHomset_points): """ Set of rational points of a projective variety over a field. @@ -72,6 +73,7 @@ class SchemeHomset_points_projective_field(SchemeHomset_points): sage: SchemeHomset_points_projective_field(Spec(QQ), ProjectiveSpace(QQ,2)) Set of rational points of Projective Space of dimension 2 over Rational Field """ + def points(self, **kwds): """ Return some or all rational points of a projective scheme. @@ -167,49 +169,50 @@ def points(self, **kwds): 6 """ from sage.schemes.projective.projective_space import ProjectiveSpace_ring + X = self.codomain() if not isinstance(X, ProjectiveSpace_ring) and X.base_ring() in Fields(): if hasattr(X.base_ring(), 'precision'): numerical = True verbose("Warning: computations in the numerical fields are inexact;points may be computed partially or incorrectly.", level=0) - pt_tol = RR(kwds.pop('point_tolerance', 10**(-10))) - zero_tol = RR(kwds.pop('zero_tolerance', 10**(-10))) + pt_tol = RR(kwds.pop('point_tolerance', 10 ** (-10))) + zero_tol = RR(kwds.pop('zero_tolerance', 10 ** (-10))) if pt_tol <= 0 or zero_tol <= 0: raise ValueError("tolerance must be positive") else: numerical = False - #Then it must be a subscheme + # Then it must be a subscheme dim_ideal = X.defining_ideal().dimension() - if dim_ideal < 1: # no points + if dim_ideal < 1: # no points return [] - if dim_ideal == 1: # if X zero-dimensional + if dim_ideal == 1: # if X zero-dimensional rat_points = set() PS = X.ambient_space() N = PS.dimension_relative() BR = X.base_ring() - #need a lexicographic ordering for elimination + # need a lexicographic ordering for elimination R = PolynomialRing(BR, N + 1, PS.variable_names(), order='lex') I = R.ideal(X.defining_polynomials()) I0 = R.ideal(0) - #Determine the points through elimination - #This is much faster than using the I.variety() function on each affine chart. + # Determine the points through elimination + # This is much faster than using the I.variety() function on each affine chart. for k in range(N + 1): - #create the elimination ideal for the kth affine patch - G = I.substitute({R.gen(k):1}).groebner_basis() + # create the elimination ideal for the kth affine patch + G = I.substitute({R.gen(k): 1}).groebner_basis() if G != [1]: P = {} - #keep track that we know the kth coordinate is 1 - P.update({R.gen(k):1}) + # keep track that we know the kth coordinate is 1 + P.update({R.gen(k): 1}) points = [P] - #work backwards from solving each equation for the possible - #values of the next coordinate + # work backwards from solving each equation for the possible + # values of the next coordinate for i in range(len(G) - 1, -1, -1): new_points = [] good = 0 for P in points: - #substitute in our dictionary entry that has the values - #of coordinates known so far. This results in a single - #variable polynomial (by elimination) + # substitute in our dictionary entry that has the values + # of coordinates known so far. This results in a single + # variable polynomial (by elimination) L = G[i].substitute(P) if R(L).degree() > 0: if numerical: @@ -217,29 +220,29 @@ def points(self, **kwds): good = 1 r = L.variables()[0] varindex = R.gens().index(r) - P.update({R.gen(varindex):pol}) + P.update({R.gen(varindex): pol}) new_points.append(copy(P)) else: L = L.factor() - #the linear factors give the possible rational values of - #this coordinate + # the linear factors give the possible rational values of + # this coordinate for pol, pow in L: if pol.degree() == 1 and len(pol.variables()) == 1: good = 1 r = pol.variables()[0] varindex = R.gens().index(r) - #add this coordinates information to - #each dictionary entry - P.update({R.gen(varindex):-pol.constant_coefficient() / pol.monomial_coefficient(r)}) + # add this coordinates information to + # each dictionary entry + P.update({R.gen(varindex): -pol.constant_coefficient() / pol.monomial_coefficient(r)}) new_points.append(copy(P)) else: new_points.append(P) good = 1 if good: points = new_points - #the dictionary entries now have values for all coordinates - #they are the rational solutions to the equations - #make them into projective points + # the dictionary entries now have values for all coordinates + # they are the rational solutions to the equations + # make them into projective points for i in range(len(points)): if numerical: if len(points[i]) == N + 1: @@ -258,10 +261,9 @@ def points(self, **kwds): dupl_points = list(rat_points) for i in range(len(dupl_points)): u = dupl_points[i] - for j in range(i+1, len(dupl_points)): + for j in range(i + 1, len(dupl_points)): v = dupl_points[j] - if all((u[k] - v[k]).abs() < pt_tol - for k in range(len(u))): + if all((u[k] - v[k]).abs() < pt_tol for k in range(len(u))): rat_points.remove(u) break @@ -274,18 +276,22 @@ def points(self, **kwds): if isinstance(R, RationalField): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) - if isinstance(X, AlgebraicScheme_subscheme): # sieve should only be called for subschemes + if isinstance(X, AlgebraicScheme_subscheme): # sieve should only be called for subschemes from sage.schemes.projective.projective_rational_point import sieve + return sieve(X, B) from sage.schemes.projective.projective_rational_point import enum_projective_rational_field + return enum_projective_rational_field(self, B) if R in NumberFields(): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.projective.projective_rational_point import enum_projective_number_field + return enum_projective_number_field(self, bound=B, tolerance=tol, precision=prec) if isinstance(R, FiniteField): from sage.schemes.projective.projective_rational_point import enum_projective_finite_field + return enum_projective_finite_field(self.extended_codomain()) raise TypeError("unable to enumerate points over %s" % R) @@ -373,6 +379,7 @@ def numerical_points(self, F=None, **kwds): TypeError: F must be a numerical field """ from sage.schemes.projective.projective_space import ProjectiveSpace_ring + if F is None: F = CC if F not in Fields() or not hasattr(F, 'precision'): @@ -383,49 +390,49 @@ def numerical_points(self, F=None, **kwds): PP = X.ambient_space().change_ring(F) if not isinstance(X, ProjectiveSpace_ring) and X.base_ring() in Fields(): - #Then it must be a subscheme + # Then it must be a subscheme dim_ideal = X.defining_ideal().dimension() - if dim_ideal < 1: # no points + if dim_ideal < 1: # no points return [] - if dim_ideal == 1: # if X zero-dimensional - pt_tol = RR(kwds.pop('point_tolerance', 10**(-10))) - zero_tol = RR(kwds.pop('zero_tolerance', 10**(-10))) + if dim_ideal == 1: # if X zero-dimensional + pt_tol = RR(kwds.pop('point_tolerance', 10 ** (-10))) + zero_tol = RR(kwds.pop('zero_tolerance', 10 ** (-10))) if pt_tol <= 0 or zero_tol <= 0: raise ValueError("tolerance must be positive") rat_points = set() PS = X.ambient_space() N = PS.dimension_relative() BR = X.base_ring() - #need a lexicographic ordering for elimination + # need a lexicographic ordering for elimination R = PolynomialRing(BR, N + 1, PS.variable_names(), order='lex') RF = R.change_ring(F) I = R.ideal(X.defining_polynomials()) - #Determine the points through elimination - #This is much faster than using the I.variety() function on each affine chart. + # Determine the points through elimination + # This is much faster than using the I.variety() function on each affine chart. for k in range(N + 1): - #create the elimination ideal for the kth affine patch - G = I.substitute({R.gen(k):1}).groebner_basis() + # create the elimination ideal for the kth affine patch + G = I.substitute({R.gen(k): 1}).groebner_basis() G = [RF(g) for g in G] if G != [1]: P = {} - #keep track that we know the kth coordinate is 1 - P.update({RF.gen(k):1}) + # keep track that we know the kth coordinate is 1 + P.update({RF.gen(k): 1}) points = [P] - #work backwards from solving each equation for the possible - #values of the next coordinate + # work backwards from solving each equation for the possible + # values of the next coordinate for i in range(len(G) - 1, -1, -1): new_points = [] good = 0 for P in points: - #substitute in our dictionary entry that has the values - #of coordinates known so far. This results in a single - #variable polynomial (by elimination) + # substitute in our dictionary entry that has the values + # of coordinates known so far. This results in a single + # variable polynomial (by elimination) L = G[i].substitute(P) if len(RF(L).variables()) == 1: for pol in L.univariate_polynomial().roots(ring=F, multiplicities=False): r = L.variables()[0] varindex = RF.gens().index(r) - P.update({RF.gen(varindex):pol}) + P.update({RF.gen(varindex): pol}) new_points.append(copy(P)) good = 1 else: @@ -433,9 +440,9 @@ def numerical_points(self, F=None, **kwds): good = 1 if good: points = new_points - #the dictionary entries now have values for all coordinates - #they are approximate solutions to the equations - #make them into projective points + # the dictionary entries now have values for all coordinates + # they are approximate solutions to the equations + # make them into projective points polys = [g.change_ring(F) for g in X.defining_polynomials()] for i in range(len(points)): if len(points[i]) == N + 1: @@ -444,14 +451,13 @@ def numerical_points(self, F=None, **kwds): if all(g(list(S)) < zero_tol for g in polys): rat_points.add(S) # remove duplicate element using tolerance - #since they are normalized we can just compare coefficients + # since they are normalized we can just compare coefficients dupl_points = list(rat_points) for i in range(len(dupl_points)): u = dupl_points[i] - for j in range(i+1, len(dupl_points)): + for j in range(i + 1, len(dupl_points)): v = dupl_points[j] - if all((u[k] - v[k]).abs() < pt_tol - for k in range(len(u))): + if all((u[k] - v[k]).abs() < pt_tol for k in range(len(u))): rat_points.remove(u) break @@ -522,7 +528,8 @@ def points(self, B=0): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.projective.projective_rational_point import enum_projective_rational_field - return enum_projective_rational_field(self,B) + + return enum_projective_rational_field(self, B) raise TypeError("unable to enumerate points over %s" % R) @@ -538,6 +545,7 @@ class SchemeHomset_polynomial_projective_space(SchemeHomset_generic): From: Projective Space of dimension 2 over Rational Field To: Projective Space of dimension 2 over Rational Field """ + def identity(self): """ Return the identity morphism of this hom-set. @@ -555,6 +563,7 @@ def identity(self): """ if self.is_endomorphism_set(): from sage.schemes.generic.morphism import SchemeMorphism_polynomial_id + return SchemeMorphism_polynomial_id(self.domain()) raise TypeError("identity map is only defined for endomorphisms") @@ -563,6 +572,7 @@ def identity(self): # Abelian varieties # ******************************************************************* + class SchemeHomset_points_abelian_variety_field(SchemeHomset_points_projective_field): r""" Set of rational points of an Abelian variety. @@ -685,8 +695,7 @@ def base_extend(self, R): implemented as modules over rings other than ZZ """ if R is not ZZ: - raise NotImplementedError('Abelian variety point sets are not ' - 'implemented as modules over rings other than ZZ') + raise NotImplementedError('Abelian variety point sets are not ' 'implemented as modules over rings other than ZZ') return self def zero(self): @@ -708,6 +717,5 @@ def zero(self): from sage.misc.persist import register_unpickle_override -register_unpickle_override('sage.schemes.generic.homset', - 'SchemeHomsetModule_abelian_variety_coordinates_field', - SchemeHomset_points_abelian_variety_field) + +register_unpickle_override('sage.schemes.generic.homset', 'SchemeHomsetModule_abelian_variety_coordinates_field', SchemeHomset_points_abelian_variety_field) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index a3ac04e1ded..ba559dec960 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -81,9 +81,7 @@ from sage.schemes.generic.morphism import SchemeMorphism_polynomial lazy_import('sage.dynamics.arithmetic_dynamics.generic_ds', 'DynamicalSystem') -lazy_import('sage.dynamics.arithmetic_dynamics.projective_ds', - ['DynamicalSystem_projective', 'DynamicalSystem_projective_field', - 'DynamicalSystem_projective_finite_field']) +lazy_import('sage.dynamics.arithmetic_dynamics.projective_ds', ['DynamicalSystem_projective', 'DynamicalSystem_projective_field', 'DynamicalSystem_projective_finite_field']) lazy_import('sage.rings.algebraic_closure_finite_field', 'AlgebraicClosureFiniteField_generic') lazy_import('sage.rings.number_field.number_field_ideal', 'NumberFieldFractionalIdeal') lazy_import('sage.rings.padics.padic_base_generic', 'pAdicGeneric') @@ -187,6 +185,7 @@ class SchemeMorphism_polynomial_projective_space(SchemeMorphism_polynomial): y, x """ + def __init__(self, parent, polys, check=True) -> None: """ Initialize. @@ -262,11 +261,8 @@ def __init__(self, parent, polys, check=True) -> None: for f in polys: num = f.numerator() den = f.denominator() - if not (num.is_homogeneous() and - den.is_homogeneous() and - num.degree() == den.degree()): - raise ValueError("polys (={}) must be quotients of " - "homogeneous polynomials of the same degree".format(polys)) + if not (num.is_homogeneous() and den.is_homogeneous() and num.degree() == den.degree()): + raise ValueError("polys (={}) must be quotients of " "homogeneous polynomials of the same degree".format(polys)) check = False except (NotImplementedError, TypeError, AttributeError): pass @@ -390,8 +386,10 @@ def __call__(self, x, check=True): (1 : 1) """ from sage.schemes.projective.projective_point import SchemeMorphism_point_projective_ring + if check: from sage.schemes.projective.projective_subscheme import AlgebraicScheme_subscheme_projective + if isinstance(x, SchemeMorphism_point_projective_ring): if self.domain() != x.codomain(): try: @@ -449,7 +447,7 @@ def _fastpolys(self): largest_value = num_terms * height * (prime - 1) ** degree # If the calculations will not overflow the float data type use domain float # Else use domain integer - if largest_value < (2 ** sys.float_info.mant_dig): + if largest_value < (2**sys.float_info.mant_dig): fastpolys.append(fast_callable(poly, domain=float)) else: fastpolys.append(fast_callable(poly, domain=ZZ)) @@ -554,8 +552,7 @@ def __eq__(self, right): if self.parent() != right.parent(): return False n = len(self._polys) - return all(self._polys[i] * right._polys[j] == self._polys[j] * right._polys[i] - for i in range(n) for j in range(i + 1, n)) + return all(self._polys[i] * right._polys[j] == self._polys[j] * right._polys[i] for i in range(n) for j in range(i + 1, n)) def __ne__(self, right) -> bool: """ @@ -592,8 +589,7 @@ def __ne__(self, right) -> bool: if self.parent() != right.parent(): return True n = len(self._polys) - return any(self._polys[i] * right._polys[j] != self._polys[j] * right._polys[i] - for i in range(n) for j in range(i + 1, n)) + return any(self._polys[i] * right._polys[j] != self._polys[j] * right._polys[i] for i in range(n) for j in range(i + 1, n)) def _matrix_times_polymap_(self, mat, h): """ @@ -675,6 +671,7 @@ def _polymap_times_matrix_(self, mat, h): (-1/3*x^2 - 1/2*y^2 : -y^2) """ from sage.modules.free_module_element import vector + if not mat.is_square(): raise ValueError("matrix must be square") if mat.nrows() != self.domain().ngens(): @@ -949,8 +946,7 @@ def normalize_coordinates(self, **kwds): raise TypeError('ideal must be an ideal of a number field, not %s' % ideal) if isinstance(ideal, NumberFieldFractionalIdeal): if ideal.number_field() != self.base_ring(): - raise ValueError('ideal must be an ideal of the base ring of this morphism ' + - ', not an ideal of %s' % ideal.number_field()) + raise ValueError('ideal must be an ideal of the base ring of this morphism ' + ', not an ideal of %s' % ideal.number_field()) if not ideal.is_prime(): raise ValueError('ideal was %s, not a prime ideal' % ideal) for generator in ideal.gens(): @@ -960,8 +956,7 @@ def normalize_coordinates(self, **kwds): else: ideal = ZZ(ideal) if self.base_ring() != QQ: - raise ValueError('ideal was an integer, but the base ring of this ' + - 'morphism is %s' % self.base_ring()) + raise ValueError('ideal was an integer, but the base ring of this ' + 'morphism is %s' % self.base_ring()) if not ideal.is_prime(): raise ValueError('ideal must be a prime, not %s' % ideal) uniformizer = ideal @@ -971,7 +966,7 @@ def normalize_coordinates(self, **kwds): if coefficient != 0: valuations.append(coefficient.valuation(ideal)) min_val = min(valuations) - self.scale_by(uniformizer**(-1 * min_val)) + self.scale_by(uniformizer ** (-1 * min_val)) return valuation = kwds.pop('valuation', None) @@ -979,8 +974,7 @@ def normalize_coordinates(self, **kwds): if not isinstance(valuation, pAdicValuation_base): raise TypeError('valuation must be a valuation on a number field, not %s' % valuation) if valuation.domain() != self.base_ring(): - raise ValueError('the domain of valuation must be the base ring of this morphism ' + - 'not %s' % valuation.domain()) + raise ValueError('the domain of valuation must be the base ring of this morphism ' + 'not %s' % valuation.domain()) uniformizer = valuation.uniformizer() ramification_index = 1 / valuation(uniformizer) valuations = [] @@ -989,7 +983,7 @@ def normalize_coordinates(self, **kwds): if coefficient != 0: valuations.append(valuation(coefficient) * ramification_index) min_val = min(valuations) - self.scale_by(uniformizer**(-1 * min_val)) + self.scale_by(uniformizer ** (-1 * min_val)) return N = self.codomain().ambient_space().dimension_relative() + 1 @@ -1222,8 +1216,7 @@ def dehomogenize(self, n): G = phi(self._polys[ind[1]]) # ind[1] is relative to codomain M = self.codomain().ambient_space().dimension_relative() - F.extend(phi(self._polys[i]) / G - for i in range(M + 1) if i != ind[1]) + F.extend(phi(self._polys[i]) / G for i in range(M + 1) if i != ind[1]) H = Hom(Aff_domain, self.codomain().affine_patch(ind[1])) # since often you dehomogenize at the same coordinate in domain # and codomain it should be stored appropriately. @@ -1531,6 +1524,7 @@ def wronskian_ideal(self): dom = self.domain() from sage.schemes.projective.projective_space import ProjectiveSpace_ring + if not (isinstance(dom, ProjectiveSpace_ring) and isinstance(self.codomain(), ProjectiveSpace_ring)): raise NotImplementedError("not implemented for subschemes") N = dom.dimension_relative() + 1 @@ -1673,6 +1667,7 @@ def rational_preimages(self, Q, k=1): raise ValueError("k (=%s) must be a positive integer" % k) # first check if subscheme from sage.schemes.projective.projective_subscheme import AlgebraicScheme_subscheme_projective + if isinstance(Q, AlgebraicScheme_subscheme_projective): return Q.preimage(self, k) @@ -1682,8 +1677,7 @@ def rational_preimages(self, Q, k=1): raise TypeError("must be an endomorphism of projective space") if Q not in self.codomain(): raise TypeError("point must be in codomain of self") - if isinstance(BR.base_ring(), (sage.rings.abc.ComplexField, sage.rings.abc.RealField, - sage.rings.abc.RealIntervalField, sage.rings.abc.ComplexIntervalField)): + if isinstance(BR.base_ring(), (sage.rings.abc.ComplexField, sage.rings.abc.RealField, sage.rings.abc.RealIntervalField, sage.rings.abc.ComplexIntervalField)): raise NotImplementedError("not implemented over precision fields") PS = self.domain().ambient_space() N = PS.dimension_relative() @@ -1692,13 +1686,11 @@ def rational_preimages(self, Q, k=1): L2 = [] for P in L: I = list(self.domain().defining_polynomials()) - I.extend(P[i] * self[j] - P[j] * self[i] - for i in range(N + 1) for j in range(i + 1, N + 1)) + I.extend(P[i] * self[j] - P[j] * self[i] for i in range(N + 1) for j in range(i + 1, N + 1)) X = PS.subscheme(I) if X.dimension() > 0: return X - L2.extend(PS(T) for T in X.rational_points() - if not all(g(tuple(T)) == 0 for g in self)) + L2.extend(PS(T) for T in X.rational_points() if not all(g(tuple(T)) == 0 for g in self)) L = L2 return L @@ -1769,8 +1761,7 @@ def _number_field_from_algebraics(self): if not (isinstance(self.domain(), ProjectiveSpace_ring) and isinstance(self.domain(), ProjectiveSpace_ring)): raise NotImplementedError("not implemented for subschemes") - K_pre, C, phi = number_field_elements_from_algebraics([c for f in self - for c in f.coefficients()], minimal=True) + K_pre, C, phi = number_field_elements_from_algebraics([c for f in self for c in f.coefficients()], minimal=True) # check if the same field if K_pre is QQ: if K_pre is self.base_ring(): @@ -1784,17 +1775,18 @@ def _number_field_from_algebraics(self): K = QQ else: from sage.rings.number_field.number_field import NumberField + K = NumberField(K_pre.polynomial(), embedding=phi(K_pre.gen()), name='a') psi = K_pre.hom([K.gen()], K) # Identification of K_pre with K C = [psi(c) for c in C] # The elements of C were in K_pre, move them to K from sage.schemes.projective.projective_space import ProjectiveSpace + N = self.domain().dimension_relative() PS = ProjectiveSpace(K, N, self.domain().variable_names()) if self.is_endomorphism(): H = End(PS) else: - PS2 = ProjectiveSpace(K, self.codomain().dimension_relative(), - self.codomain().variable_names()) + PS2 = ProjectiveSpace(K, self.codomain().dimension_relative(), self.codomain().variable_names()) H = Hom(PS, PS2) R = PS.coordinate_ring() exps = [f.exponents() for f in self] @@ -1803,7 +1795,7 @@ def _number_field_from_algebraics(self): for t in exps: G = 0 for e in t: - G += C[j] * prod([R.gen(i)**e[i] for i in range(N + 1)]) + G += C[j] * prod([R.gen(i) ** e[i] for i in range(N + 1)]) j += 1 F.append(G) return H(F) @@ -2126,8 +2118,8 @@ def reduce_base_field(self): R = PolynomialRing(K.prime_subfield(), 2, 'a') a, b = R.gens() from sage.schemes.projective.projective_space import ProjectiveSpace - new_domain = ProjectiveSpace(L, self.domain().dimension_relative(), - self.domain().variable_names()) + + new_domain = ProjectiveSpace(L, self.domain().dimension_relative(), self.domain().variable_names()) new_R = new_domain.coordinate_ring() u = phi(L.gen()) # gen of L in terms of gen of K g = R(str(u).replace(K.variable_name(), R.variable_names()[0])) # converted to R @@ -2149,9 +2141,7 @@ def reduce_base_field(self): else: new_c.append(L(str(w.lc() * v).replace(R.variable_names()[1], L.variable_name()))) # reconstruct as a poly in the new domain - new_f.append(sum(new_c[i] * prod(new_R.gen(j)**mon_deg[i][j] - for j in range(new_R.ngens())) - for i in range(len(mon)))) + new_f.append(sum(new_c[i] * prod(new_R.gen(j) ** mon_deg[i][j] for j in range(new_R.ngens())) for i in range(len(mon)))) # return the correct type of map if self.is_endomorphism(): H = Hom(new_domain, new_domain) @@ -2167,8 +2157,8 @@ def reduce_base_field(self): # get the appropriate subfield L, L_to_K = K.subfield(d) from sage.schemes.projective.projective_space import ProjectiveSpace - new_domain = ProjectiveSpace(L, self.domain().dimension_relative(), - self.domain().variable_names()) + + new_domain = ProjectiveSpace(L, self.domain().dimension_relative(), self.domain().variable_names()) new_R = new_domain.coordinate_ring() # we need to rewrite each of the coefficients in terms of the generator # of L. To do this, we'll set-up an ideal and use elimination @@ -2185,13 +2175,10 @@ def reduce_base_field(self): # find the right subfield and it's embedding if M.degree() == da: break - c = M(str(c).replace(c.as_finite_field_element()[0].variable_name(), - M.variable_name())) + c = M(str(c).replace(c.as_finite_field_element()[0].variable_name(), M.variable_name())) new_c.append(M_to_L(c)) # reconstruct as a poly in the new domain - new_f.append(sum([new_c[i] * prod(new_R.gen(j)**mon_deg[i][j] - for j in range(new_R.ngens())) - for i in range(len(mon))])) + new_f.append(sum([new_c[i] * prod(new_R.gen(j) ** mon_deg[i][j] for j in range(new_R.ngens())) for i in range(len(mon))])) # return the correct type of map if self.is_endomorphism(): H = Hom(new_domain, new_domain) @@ -2259,6 +2246,7 @@ class SchemeMorphism_polynomial_projective_subscheme_field(SchemeMorphism_polyno """ Morphisms from subschemes of projective spaces defined over fields. """ + def __call__(self, x): """ Apply this morphism to the point ``x``. @@ -2432,8 +2420,7 @@ def representatives(self): reprs.append(hom([f / f0 for f in r[1:]])) return reprs - if not (X.base_ring() in _NumberFields or - X.base_ring() in _FiniteFields): + if not (X.base_ring() in _NumberFields or X.base_ring() in _FiniteFields): raise NotImplementedError("base ring {} is not supported by Singular".format(X.base_ring())) if not X.is_irreducible(): @@ -2442,15 +2429,19 @@ def representatives(self): # prepare homogeneous coordinate ring of X in Singular from sage.interfaces.singular import singular from sage.rings.polynomial.term_order import TermOrder + T = TermOrder('degrevlex') T._singular_ringorder_column = 1 # (c,dp) in Singular S = X.ambient_space().coordinate_ring().change_ring(order=T) R = S.quotient_ring(X.defining_ideal().change_ring(S)) if R is S: # true when the defining ideal is zero + def lift(x): return x.numerator() + else: # R is an ordinary quotient ring + def lift(x): return x.lift() @@ -2688,6 +2679,7 @@ def graph(self): if any(v in AX.variable_names() for v in AY.variable_names()): from sage.schemes.product_projective.space import ProductProjectiveSpaces + AXY = ProductProjectiveSpaces([n, m], self.base_ring()) else: AXY = AX * AY # product of projective spaces diff --git a/src/sage/schemes/projective/projective_point.py b/src/sage/schemes/projective/projective_point.py index ff657981bf0..738709aa363 100644 --- a/src/sage/schemes/projective/projective_point.py +++ b/src/sage/schemes/projective/projective_point.py @@ -39,8 +39,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.quotient_ring import QuotientRing_generic from sage.rings.rational_field import QQ -from sage.schemes.generic.morphism import (SchemeMorphism, - SchemeMorphism_point) +from sage.schemes.generic.morphism import SchemeMorphism, SchemeMorphism_point from sage.structure.element import AdditiveGroupElement, RingElement from sage.structure.richcmp import richcmp, op_EQ, op_NE from sage.structure.sequence import Sequence @@ -54,6 +53,7 @@ # Projective varieties # -------------------- + class SchemeMorphism_point_projective_ring(SchemeMorphism_point): """ A rational point of projective space over a ring. @@ -178,22 +178,20 @@ def __init__(self, X, v, check=True): R = X.value_ring() v = Sequence(v, R) - if len(v) == d - 1: # very common special case + if len(v) == d - 1: # very common special case v.append(R.one()) if R in IntegralDomains(): # Over integral domains, any tuple with at least one # nonzero coordinate is a valid projective point. if not any(v): - raise ValueError(f"{v} does not define a valid projective " - "point since all entries are zero") + raise ValueError(f"{v} does not define a valid projective " "point since all entries are zero") else: # Over rings with zero divisors, a more careful check # is required: We test whether the coordinates of the # point generate the unit ideal. See #31576. if 1 not in R.ideal(v): - raise ValueError(f"{v} does not define a valid projective point " - "since it is a multiple of a zero divisor") + raise ValueError(f"{v} does not define a valid projective point " "since it is a multiple of a zero divisor") X.extended_codomain()._check_satisfies_equations(v) @@ -369,8 +367,7 @@ def _richcmp_(self, right, op): n = len(self._coords) if op in [op_EQ, op_NE]: - b = all(self[i] * right[j] == self[j] * right[i] - for i in range(n) for j in range(i + 1, n)) + b = all(self[i] * right[j] == self[j] * right[i] for i in range(n) for j in range(i + 1, n)) return b == (op == op_EQ) return richcmp(self._coords, right._coords, op) @@ -473,6 +470,7 @@ def _matrix_times_point_(self, mat, dom): ValueError: matrix must be square """ from sage.modules.free_module_element import vector + if not mat.is_square(): raise ValueError("matrix must be square") if mat.ncols() != self.codomain().ngens(): @@ -522,11 +520,11 @@ def scale_by(self, t): raise ValueError("Cannot scale by 0") R = self.codomain().base_ring() if isinstance(R, QuotientRing_generic): - for i in range(self.codomain().ambient_space().dimension_relative()+1): - new_coords = [R(u.lift()*t) for u in self._coords] + for i in range(self.codomain().ambient_space().dimension_relative() + 1): + new_coords = [R(u.lift() * t) for u in self._coords] else: - for i in range(self.codomain().ambient_space().dimension_relative()+1): - new_coords = [R(u*t) for u in self._coords] + for i in range(self.codomain().ambient_space().dimension_relative() + 1): + new_coords = [R(u * t) for u in self._coords] self._coords = tuple(new_coords) self._normalized = False @@ -609,7 +607,7 @@ def normalize_coordinates(self): while not self._coords[index]: index -= 1 last = self._coords[index].lift() - mod, = R.defining_ideal().gens() + (mod,) = R.defining_ideal().gens() unit = last while not (zdiv := mod.gcd(unit)).is_unit(): unit //= zdiv @@ -681,9 +679,7 @@ def dehomogenize(self, n): raise ValueError("can't dehomogenize at 0 coordinate") PS = self.codomain() A = PS.affine_patch(n) - Q = [self[i] / sn - for i in range(PS.ambient_space().dimension_relative() + 1) - if i != n] + Q = [self[i] / sn for i in range(PS.ambient_space().dimension_relative() + 1) if i != n] return A.point(Q) def global_height(self, prec=None): @@ -770,9 +766,8 @@ def global_height(self, prec=None): return height.log().n(prec=prec) finite = ~sum(K.ideal(xi) for xi in x).norm() - infinite = prod(max(abs(xi.complex_embedding(prec, i)) - for xi in x) for i in range(d)) - height = (finite * infinite)**(~d) + infinite = prod(max(abs(xi.complex_embedding(prec, i)) for xi in x) for i in range(d)) + height = (finite * infinite) ** (~d) return height.log() def local_height(self, v, prec=None): @@ -1146,12 +1141,12 @@ def __init__(self, X, v, check=True): pass if not isinstance(v, (list, tuple)): raise TypeError("argument v (= %s) must be a scheme point, list, or tuple" % str(v)) - if len(v) != d and len(v) != d-1: + if len(v) != d and len(v) != d - 1: raise TypeError("v (=%s) must have %s components" % (v, d)) R = X.value_ring() v = Sequence(v, R) - if len(v) == d-1: # very common special case + if len(v) == d - 1: # very common special case v.append(R.one()) for last in reversed(range(len(v))): @@ -1164,8 +1159,7 @@ def __init__(self, X, v, check=True): v[last] = R.one() break else: - raise ValueError(f"{v} does not define a valid projective " - "point since all entries are zero") + raise ValueError(f"{v} does not define a valid projective " "point since all entries are zero") self._normalized = True X.extended_codomain()._check_satisfies_equations(v) @@ -1221,7 +1215,7 @@ def normalize_coordinates(self): inv = c.inverse() new_coords = [d * inv for d in self._coords[:index]] new_coords.append(self.base_ring().one()) - new_coords.extend(self._coords[index+1:]) + new_coords.extend(self._coords[index + 1 :]) self._coords = tuple(new_coords) break else: @@ -1265,6 +1259,7 @@ def _number_field_from_algebraics(self): True """ from sage.schemes.projective.projective_space import ProjectiveSpace_ring + if not isinstance(self.codomain(), ProjectiveSpace_ring): raise NotImplementedError("not implemented for subschemes") @@ -1276,10 +1271,12 @@ def _number_field_from_algebraics(self): K = QQ else: from sage.rings.number_field.number_field import NumberField + K = NumberField(K_pre.polynomial(), embedding=phi(K_pre.gen()), name='a') psi = K_pre.hom([K.gen()], K) # Identification of K_pre with K P = [psi(p) for p in P] # The elements of P were elements of K_pre from sage.schemes.projective.projective_space import ProjectiveSpace + PS = ProjectiveSpace(K, self.codomain().dimension_relative(), 'z') return PS(P) @@ -1364,6 +1361,7 @@ def intersection_multiplicity(self, X): TypeError: this point must be a point on a projective subscheme """ from sage.schemes.projective.projective_space import ProjectiveSpace_ring + if isinstance(self.codomain(), ProjectiveSpace_ring): raise TypeError("this point must be a point on a projective subscheme") return self.codomain().intersection_multiplicity(X, self) @@ -1389,6 +1387,7 @@ def multiplicity(self): 8 """ from sage.schemes.projective.projective_space import ProjectiveSpace_ring + if isinstance(self.codomain(), ProjectiveSpace_ring): raise TypeError("this point must be a point on a projective subscheme") return self.codomain().multiplicity(self) @@ -1464,6 +1463,7 @@ def __hash__(self): # Abelian varieties # ----------------- + class SchemeMorphism_point_abelian_variety_field(AdditiveGroupElement, SchemeMorphism_point_projective_field): """ A rational point of an abelian variety over a field. @@ -1478,4 +1478,5 @@ class SchemeMorphism_point_abelian_variety_field(AdditiveGroupElement, SchemeMor sage: origin.codomain() Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field """ + pass diff --git a/src/sage/schemes/projective/projective_rational_point.py b/src/sage/schemes/projective/projective_rational_point.py index 1798b402ff5..dd31b3bd3c2 100644 --- a/src/sage/schemes/projective/projective_rational_point.py +++ b/src/sage/schemes/projective/projective_rational_point.py @@ -132,6 +132,7 @@ def enum_projective_rational_field(X, B): - John Cremona and Charlie Turner (06-2010) """ from sage.schemes.projective.projective_space import ProjectiveSpace_ring + if isinstance(X, Scheme): if not isinstance(X.ambient_space(), ProjectiveSpace_ring): raise TypeError("ambient space must be projective space over the rational field") @@ -208,6 +209,7 @@ def enum_projective_number_field(X, **kwds): tol = kwds.pop('tolerance', 1e-2) prec = kwds.pop('precision', 53) from sage.schemes.projective.projective_space import ProjectiveSpace_ring + if isinstance(X, Scheme): if not isinstance(X.ambient_space(), ProjectiveSpace_ring): raise TypeError("ambient space must be projective space over a number field") @@ -289,6 +291,7 @@ def enum_projective_finite_field(X): - John Cremona and Charlie Turner (06-2010). """ from sage.schemes.projective.projective_space import ProjectiveSpace_ring + if isinstance(X, Scheme): if not isinstance(X.ambient_space(), ProjectiveSpace_ring): raise TypeError("ambient space must be projective space over a finite") @@ -379,12 +382,12 @@ def sieve(X, bound): [(-1 : -2 : 1), (-1/2 : -1 : 1), (-1/3 : -2/3 : 1), (0 : 0 : 1), (1/3 : 2/3 : 1), (1/2 : 1 : 0), (1/2 : 1 : 1), (1 : 2 : 1)] """ - if bound < 1: # no projective rational point with height less than 1 + if bound < 1: # no projective rational point with height less than 1 return [] - modulo_points = [] # list to store point modulo primes - len_modulo_points = [] # stores number of points with respect to each prime - primes_list = [] # list of good primes + modulo_points = [] # list to store point modulo primes + len_modulo_points = [] # stores number of points with respect to each prime + primes_list = [] # list of good primes X.normalize_defining_polynomials() @@ -393,7 +396,7 @@ def sieve(X, bound): dim_scheme = X.dimension() # bound as per preposition - 4, in preperiodic points paper - B = RR(2**(N/4+1)*bound**2*(N+1).sqrt()) + B = RR(2 ** (N / 4 + 1) * bound**2 * (N + 1).sqrt()) m = [0 for _ in range(N + 1)] @@ -401,7 +404,7 @@ def sufficient_primes(x): r""" Return a list of primes whose product is > `x`. """ - small_primes = [2,3] + small_primes = [2, 3] prod_primes = 6 while prod_primes < x: @@ -428,11 +431,11 @@ def good_primes(B): current_count = max_length - 1 while current_count > 1: - current_list = [] # stores prime which are bigger than least + current_list = [] # stores prime which are bigger than least updated_list = [] best_list = [] - least = (RR(B)**(1.00/current_count)).floor() + least = (RR(B) ** (1.00 / current_count)).floor() for i in range(current_count): current_list.append(next_prime(least)) least = current_list[-1] @@ -441,7 +444,7 @@ def good_primes(B): prod_prime = prod(current_list) least = current_list[0] while least != 2 and prod_prime > B and len(updated_list) < current_count: - best_list = updated_list + current_list[:current_count - len(updated_list)] + best_list = updated_list + current_list[: current_count - len(updated_list)] updated_list.append(previous_prime(least)) least = updated_list[-1] @@ -452,9 +455,9 @@ def good_primes(B): current_count = current_count - 1 best_size = 2 - best_time = (N**2)*M[2][-1]**(N) + (N**5 * RR(prod(M[2])**dim_scheme / M[2][-1]) ) + best_time = (N**2) * M[2][-1] ** (N) + (N**5 * RR(prod(M[2]) ** dim_scheme / M[2][-1])) for i in range(2, max_length + 1): - current_time = (N**2)*M[i][-1]**(N) + (N**5 * RR(prod(M[i])**dim_scheme / M[i][-1]) ) + current_time = (N**2) * M[i][-1] ** (N) + (N**5 * RR(prod(M[i]) ** dim_scheme / M[i][-1])) if current_time < best_time: best_size = i best_time = current_time @@ -474,7 +477,16 @@ def points_modulo_primes(X, primes): Return a list of rational points modulo all `p` in primes, computed parallelly. """ - normalized_input = [((X, p, ), {}) for p in primes_list] + normalized_input = [ + ( + ( + X, + p, + ), + {}, + ) + for p in primes_list + ] p_iter = p_iter_fork(ncpus()) points_pair = list(p_iter(parallel_function, normalized_input)) @@ -493,12 +505,12 @@ def parallel_function_combination(point_p_max): # lift all coordinates of given point using chinese remainder theorem L = [modulo_points[j][tupl[j]][k].lift() for j in range(len_primes - 1)] L.append(point_p_max[k].lift()) - point.append( crt(L, primes_list) ) + point.append(crt(L, primes_list)) - for i in range(N+1): + for i in range(N + 1): m[i] = point[i] - M = matrix(ZZ, N+2, N+1, m) + M = matrix(ZZ, N + 2, N + 1, m) A = M.LLL() point = list(A[1]) @@ -527,7 +539,7 @@ def lift_all_points(): points = modulo_points.pop() # remove the list of points corresponding to largest prime len_modulo_points.pop() - normalized_input = [((point, ), {}) for point in points] + normalized_input = [((point,), {}) for point in points] p_iter = p_iter_fork(ncpus()) points_satisfying = list(p_iter(parallel_function_combination, normalized_input)) diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index b97c31bbc07..00285d88bce 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -106,15 +106,9 @@ from sage.schemes.generic.ambient_space import AmbientSpace from sage.structure.category_object import normalize_names from sage.structure.unique_representation import UniqueRepresentation -from sage.schemes.projective.projective_homset import (SchemeHomset_points_projective_ring, - SchemeHomset_points_projective_field, - SchemeHomset_polynomial_projective_space) -from sage.schemes.projective.projective_morphism import (SchemeMorphism_polynomial_projective_space, - SchemeMorphism_polynomial_projective_space_field, - SchemeMorphism_polynomial_projective_space_finite_field) -from sage.schemes.projective.projective_point import (SchemeMorphism_point_projective_ring, - SchemeMorphism_point_projective_field, - SchemeMorphism_point_projective_finite_field) +from sage.schemes.projective.projective_homset import SchemeHomset_points_projective_ring, SchemeHomset_points_projective_field, SchemeHomset_polynomial_projective_space +from sage.schemes.projective.projective_morphism import SchemeMorphism_polynomial_projective_space, SchemeMorphism_polynomial_projective_space_field, SchemeMorphism_polynomial_projective_space_finite_field +from sage.schemes.projective.projective_point import SchemeMorphism_point_projective_ring, SchemeMorphism_point_projective_field, SchemeMorphism_point_projective_finite_field lazy_import('sage.combinat.integer_vector_weighted', 'WeightedIntegerVectors') lazy_import('sage.combinat.tuple', ['Tuples', 'UnorderedTuples']) @@ -122,10 +116,8 @@ lazy_import('sage.matrix.constructor', 'matrix') lazy_import('sage.modules.free_module_element', 'prepare') lazy_import('sage.schemes.generic.algebraic_scheme', 'AlgebraicScheme_subscheme') -lazy_import('sage.schemes.product_projective.space', - ['ProductProjectiveSpaces', 'ProductProjectiveSpaces_ring']) -lazy_import('sage.schemes.projective.projective_subscheme', - ['AlgebraicScheme_subscheme_projective', 'AlgebraicScheme_subscheme_projective_field']) +lazy_import('sage.schemes.product_projective.space', ['ProductProjectiveSpaces', 'ProductProjectiveSpaces_ring']) +lazy_import('sage.schemes.projective.projective_subscheme', ['AlgebraicScheme_subscheme_projective', 'AlgebraicScheme_subscheme_projective_field']) # for better efficiency @@ -231,8 +223,7 @@ def ProjectiveSpace(n, R=None, names=None): if n.variable_names() != names: # The provided name doesn't match the name of R's variables raise NameError("variable names passed to ProjectiveSpace conflict with names in ring") - A = ProjectiveSpace(n.ngens() - 1, n.base_ring(), - names=n.variable_names()) + A = ProjectiveSpace(n.ngens() - 1, n.base_ring(), names=n.variable_names()) A._coordinate_ring = n return A if names is None: @@ -303,6 +294,7 @@ class ProjectiveSpace_ring(UniqueRepresentation, AmbientSpace): sage: hash(ProjectiveSpace(ZZ, 2, 'a')) == hash(AffineSpace(ZZ, 2, 'a')) False """ + @staticmethod def __classcall__(cls, n, R=ZZ, names=None): """ @@ -418,9 +410,7 @@ def coordinate_ring(self): try: return self._coordinate_ring except AttributeError: - self._coordinate_ring = PolynomialRing(self.base_ring(), - self.variable_names(), - self.dimension_relative() + 1) + self._coordinate_ring = PolynomialRing(self.base_ring(), self.variable_names(), self.dimension_relative() + 1) return self._coordinate_ring def _validate(self, polynomials): @@ -664,23 +654,19 @@ def _linear_system_as_kernel(self, d, pt, m): raise TypeError('the argument d=%s must be an integer' % d) if d < 0: raise ValueError('the integer d=%s must be nonnegative' % d) - if not isinstance(pt, (list, tuple, - SchemeMorphism_point_projective_ring)): - raise TypeError('the argument pt=%s must be a list, tuple, or ' - 'point on a projective space' % pt) + if not isinstance(pt, (list, tuple, SchemeMorphism_point_projective_ring)): + raise TypeError('the argument pt=%s must be a list, tuple, or ' 'point on a projective space' % pt) pt, R = prepare(pt, None) n = self.dimension_relative() if not len(pt) == n + 1: - raise TypeError('the sequence pt=%s must have %s ' - 'components' % (pt, n + 1)) + raise TypeError('the sequence pt=%s must have %s ' 'components' % (pt, n + 1)) if not R.has_coerce_map_from(self.base_ring()): raise TypeError('unable to find a common ring for all elements') try: i = pt.index(1) except Exception: - raise TypeError('at least one component of pt=%s must be equal ' - 'to 1' % pt) - pt = pt[:i] + pt[i + 1:] + raise TypeError('at least one component of pt=%s must be equal ' 'to 1' % pt) + pt = pt[:i] + pt[i + 1 :] if not isinstance(m, (int, Integer)): raise TypeError('the argument m=%s must be an integer' % m) if m < 0: @@ -693,13 +679,11 @@ def _linear_system_as_kernel(self, d, pt, m): monoms = IntegerVectors(d, n + 1).list() M = matrix(R, len(partials), len(monoms)) for row in range(M.nrows()): - e = partials[row][:i] + partials[row][i + 1:] + e = partials[row][:i] + partials[row][i + 1 :] for col in range(M.ncols()): - f = monoms[col][:i] + monoms[col][i + 1:] + f = monoms[col][:i] + monoms[col][i + 1 :] if all(f[j] >= e[j] for j in range(n)): - M[row, col] = prod(binomial(fj, ej) * ptj**(fj - ej) - for ptj, fj, ej in zip(pt, f, e) - if fj > ej) + M[row, col] = prod(binomial(fj, ej) * ptj ** (fj - ej) for ptj, fj, ej in zip(pt, f, e) if fj > ej) return M def _morphism(self, *args, **kwds): @@ -719,7 +703,7 @@ def _morphism(self, *args, **kwds): return SchemeMorphism_polynomial_projective_space(*args, **kwds) def _homset(self, *args, **kwds): - """ ii + """ii Construct the Hom-set EXAMPLES:: @@ -788,8 +772,8 @@ def point(self, v, check=True): ValueError: [+Infinity] not well defined in dimension > 1 """ from sage.rings.infinity import infinity - if v is infinity or (isinstance(v, (list, tuple)) and - len(v) == 1 and v[0] is infinity): + + if v is infinity or (isinstance(v, (list, tuple)) and len(v) == 1 and v[0] is infinity): if self.dimension_relative() > 1: raise ValueError("%s not well defined in dimension > 1" % v) v = [1, 0] @@ -899,10 +883,8 @@ def change_ring(self, R): Projective Space of dimension 2 over Algebraic Field """ if isinstance(R, Map): - return ProjectiveSpace(self.dimension_relative(), R.codomain(), - self.variable_names()) - return ProjectiveSpace(self.dimension_relative(), R, - self.variable_names()) + return ProjectiveSpace(self.dimension_relative(), R.codomain(), self.variable_names()) + return ProjectiveSpace(self.dimension_relative(), R, self.variable_names()) def is_projective(self): """ @@ -1119,12 +1101,7 @@ def points_of_bounded_height(self, **kwds): (i*a : 1), (i*a^2 : 1), (i*a^3 : 1), (-1 : 1), (-a : 1), (-a^2 : 1), (-a^3 : 1), (-i : 1), (-i*a : 1), (-i*a^2 : 1), (-i*a^3 : 1), (1 : 1)] """ - from sage.schemes.projective.proj_bdd_height import ( - ZZ_points_of_bounded_height, - QQ_points_of_bounded_height, - IQ_points_of_bounded_height, - points_of_bounded_height - ) + from sage.schemes.projective.proj_bdd_height import ZZ_points_of_bounded_height, QQ_points_of_bounded_height, IQ_points_of_bounded_height, points_of_bounded_height R = self.base_ring() @@ -1146,7 +1123,7 @@ def points_of_bounded_height(self, **kwds): prec = kwds.pop('precision', 53) # Convert between absolute and relative height for calling Krumm's algorithm - bound = bound**R.absolute_degree() + bound = bound ** R.absolute_degree() dim = self.dimension_relative() @@ -1231,7 +1208,7 @@ def affine_patch(self, i, AA=None): sage: P.affine_patch(0).projective_embedding(0).codomain() == P True """ - i = int(i) # implicit type checking + i = int(i) # implicit type checking n = self.dimension_relative() if i < 0 or i > n: raise ValueError("argument i (= %s) must be between 0 and %s" % (i, n)) @@ -1248,11 +1225,10 @@ def affine_patch(self, i, AA=None): # if no ith patch exists, we may still be here with AA==None if AA is None: from sage.schemes.affine.affine_space import AffineSpace + g = self.gens() - gens = g[:i] + g[i + 1:] - AA = AffineSpace(n, self.base_ring(), names=gens, - ambient_projective_space=self, - default_embedding_index=i) + gens = g[:i] + g[i + 1 :] + AA = AffineSpace(n, self.base_ring(), names=gens, ambient_projective_space=self, default_embedding_index=i) elif AA.dimension_relative() != n: raise ValueError("affine space must be of the dimension %s" % (n)) self.__affine_patches[i] = AA @@ -1430,7 +1406,7 @@ def chebyshev_polynomial(self, n, kind='first', monic=False): if self.dimension_relative() != 1: raise TypeError("projective space must be of dimension 1") n = ZZ(n) - if (n < 0): + if n < 0: raise ValueError("first parameter 'n' must be a nonnegative integer") # use the affine version and then homogenize. A = self.affine_patch(1) @@ -1711,16 +1687,16 @@ def point_transformation_matrix(self, points_source, points_target, normalize=Tr # [1 : 1 : 1 : ... ] ] # to the list of points S def get_matrix(S, N): - a = matrix(N+1, N+1, [S[j][i] for i in range(N+1) for j in range(N+1)]) - b = matrix(N+1, 1, list(S[N+1])) + a = matrix(N + 1, N + 1, [S[j][i] for i in range(N + 1) for j in range(N + 1)]) + b = matrix(N + 1, 1, list(S[N + 1])) X = a.solve_right(b) - m = matrix(N+1, N+1, [X[i,0]*S[i][j] for i in range(N+1) for j in range(N+1)]) + m = matrix(N + 1, N + 1, [X[i, 0] * S[i][j] for i in range(N + 1) for j in range(N + 1)]) m = m.transpose() return m m_source = get_matrix(points_source, n) m_target = get_matrix(points_target, n) - return_mat = m_target*m_source.inverse() + return_mat = m_target * m_source.inverse() if normalize: R = self.base_ring() if R.is_exact(): @@ -1729,7 +1705,7 @@ def get_matrix(S, N): last_ele = last_row.pop() while last_ele == 0: last_ele = last_row.pop() - return_mat *= ZZ(1)/last_ele + return_mat *= ZZ(1) / last_ele else: lcm = return_mat[0][0].denominator() for row in return_mat.rows(): @@ -1869,6 +1845,7 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): CR = self.coordinate_ring() points = [] from sage.rings.rational_field import QQ + P_QQ = ProjectiveSpace(QQ, N) # to determine the PGL transform, we need N+2 points source points and N+2 target points, # of which no N+1 are co-planar. Additionally, in order to map plane_1 to plane_2, N source @@ -1882,9 +1859,9 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): # we have a single linear equation with N+1 variables # first we add a point for each variable with coefficient 0 # giving us J points added in this loop - for i in range(N+1): + for i in range(N + 1): if plane.defining_polynomials()[0].coefficient(CR.gens()[i]) == 0: - L = [0]*(N+1) + L = [0] * (N + 1) L[i] = 1 source_points.append(self(L)) else: @@ -1892,11 +1869,11 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): # next we add a point for each variable with nonzero coefficient, except the last # giving us a total of (N+1) - J - 1 = N - J points added in this loop # resulting in exactly J + (N-J) = N points on the plane - for i in range(len(nonzero_places)-1): + for i in range(len(nonzero_places) - 1): nonzero_place1 = nonzero_places[i] - nonzero_place2 = nonzero_places[i+1] - L = [0]*(N+1) - L[nonzero_place1] = -1*plane.defining_polynomials()[0].coefficient(CR.gens()[nonzero_place2]) + nonzero_place2 = nonzero_places[i + 1] + L = [0] * (N + 1) + L[nonzero_place1] = -1 * plane.defining_polynomials()[0].coefficient(CR.gens()[nonzero_place2]) L[nonzero_place2] = plane.defining_polynomials()[0].coefficient(CR.gens()[nonzero_place1]) source_points.append(self(L)) @@ -1913,9 +1890,8 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): if not any(m == 0 for m in Ms.minors(N + 1)): source_points.append(self(point)) break - if len(source_points) != N+2: - raise NotImplementedError('Failed to automatically find sufficient independent points.' + - ' Please find the necessary independent points manually, then use point transformation matrix.') + if len(source_points) != N + 2: + raise NotImplementedError('Failed to automatically find sufficient independent points.' + ' Please find the necessary independent points manually, then use point transformation matrix.') points.append(source_points) return self.point_transformation_matrix(points[0], points[1]) @@ -2133,8 +2109,7 @@ def subscheme_from_Chow_form(self, Ch, dim): if binomial(n + 1, n - dim) != R.ngens(): raise ValueError("for given dimension, there should be %d variables in the Chow form" % binomial(n + 1, n - dim)) # create the brackets associated to variables - L1 = [list(t) for t in UnorderedTuples(range(n + 1), dim + 1) - if all(t[i] < t[i + 1] for i in range(dim))] + L1 = [list(t) for t in UnorderedTuples(range(n + 1), dim + 1) if all(t[i] < t[i + 1] for i in range(dim))] # create the dual brackets L2 = [] signs = [] @@ -2153,8 +2128,7 @@ def subscheme_from_Chow_form(self, Ch, dim): else: T = PolynomialRing(R.base_ring(), n + 1, 'z') M = matrix(T, n - dim, n + 1, list(T.gens())) - coords = [si * M.matrix_from_columns(L2i).det() - for si, L2i in zip(signs, L2)] + coords = [si * M.matrix_from_columns(L2i).det() for si, L2i in zip(signs, L2)] # substitute in dual brackets to chow form phi = R.hom(coords, T) ch = phi(Ch) @@ -2179,6 +2153,7 @@ def curve(self, F): Projective Plane Curve over Rational Field defined by y^2 - x*z """ from sage.schemes.curves.constructor import Curve + return Curve(F, self) def line_through(self, p, q): @@ -2292,12 +2267,12 @@ def __iter__(self): """ n = self.dimension_relative() R = self.base_ring() - zero = (R.zero(), ) - one = (R.one(), ) + zero = (R.zero(),) + one = (R.one(),) PHom = self.point_homset() C = PHom.codomain() - for k in range(n + 1): # position of last 1 before the 0's + for k in range(n + 1): # position of last 1 before the 0's for v in product(*[R for _ in range(n - k)]): yield C._point(PHom, v + one + zero * k, check=False) @@ -2423,7 +2398,7 @@ def rational_points(self, bound=0): n = self.dimension_relative() Q = [k - bound for k in range(2 * bound + 1)] # the affine coordinates - R = [(k + 1) for k in range(bound)] # the projective coordinate + R = [(k + 1) for k in range(bound)] # the projective coordinate S = [Tuples(Q, (k + 1)) for k in range(n)] pts = [] @@ -2448,10 +2423,6 @@ def rational_points(self, bound=0): # fix the pickles from moving projective_space.py -register_unpickle_override('sage.schemes.generic.projective_space', - 'ProjectiveSpace_field', - ProjectiveSpace_field) +register_unpickle_override('sage.schemes.generic.projective_space', 'ProjectiveSpace_field', ProjectiveSpace_field) -register_unpickle_override('sage.schemes.generic.projective_space', - 'ProjectiveSpace_rational_field', - ProjectiveSpace_rational_field) +register_unpickle_override('sage.schemes.generic.projective_space', 'ProjectiveSpace_rational_field', ProjectiveSpace_rational_field) diff --git a/src/sage/schemes/projective/projective_subscheme.py b/src/sage/schemes/projective/projective_subscheme.py index 352021ef1a5..861d9f55ec4 100644 --- a/src/sage/schemes/projective/projective_subscheme.py +++ b/src/sage/schemes/projective/projective_subscheme.py @@ -69,6 +69,7 @@ class AlgebraicScheme_subscheme_projective(AlgebraicScheme_subscheme): Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: x^2 - y*z """ + def point(self, v, check=True): """ Create a point on this projective subscheme. @@ -108,13 +109,14 @@ def point(self, v, check=True): x^2 + 2*y^2 """ from sage.rings.infinity import infinity - if v is infinity or\ - (isinstance(v, (list, tuple)) and len(v) == 1 and v[0] is infinity): + + if v is infinity or (isinstance(v, (list, tuple)) and len(v) == 1 and v[0] is infinity): if self.ambient_space().dimension_relative() > 1: raise ValueError("%s not well defined in dimension > 1" % v) v = [1, 0] # todo: update elliptic curve stuff to take point_homset as argument from sage.schemes.elliptic_curves.ell_generic import EllipticCurve_generic + if isinstance(self, EllipticCurve_generic): try: return self._point(self.point_homset(), v, check=check) @@ -250,7 +252,7 @@ def affine_patch(self, i, AA=None): Closed subscheme of Affine Space of dimension 2 over Integer Ring defined by: x^2 - y """ - i = int(i) # implicit type checking + i = int(i) # implicit type checking PP = self.ambient_space() n = PP.dimension_relative() if i < 0 or i > n: @@ -383,9 +385,7 @@ def neighborhood(self, point): phi[j + 1] += R.gen(j) pullback_polys = [f(phi) for f in self.defining_polynomials()] - return patch_cover.subscheme(pullback_polys, embedding_center=[0] * n, - embedding_codomain=self, - embedding_images=phi) + return patch_cover.subscheme(pullback_polys, embedding_center=[0] * n, embedding_codomain=self, embedding_images=phi) def is_smooth(self, point=None) -> bool: r""" @@ -440,7 +440,7 @@ def is_smooth(self, point=None) -> bool: sing_dim = self.Jacobian().dimension() # We really test the affine cone here; the origin is always a # singular point: - self._smooth = (sing_dim <= 0) + self._smooth = sing_dim <= 0 return self._smooth def orbit(self, f, N) -> list: @@ -995,15 +995,11 @@ def dual(self): J = self.defining_ideal() m = J.ngens() n = J.ring().ngens() - 1 - if (m != 1 or (n < 1) or J.is_zero() - or J.is_trivial() or not J.is_prime()): - raise NotImplementedError("At the present, the method is only" - " implemented for irreducible and" - " reduced hypersurfaces and the given" - " list of generators for the ideal must" - " have exactly one element.") + if m != 1 or (n < 1) or J.is_zero() or J.is_trivial() or not J.is_prime(): + raise NotImplementedError("At the present, the method is only" " implemented for irreducible and" " reduced hypersurfaces and the given" " list of generators for the ideal must" " have exactly one element.") R = PolynomialRing(K, 'x', n + 1) from sage.schemes.projective.projective_space import ProjectiveSpace + Pd = ProjectiveSpace(n, K, 'y') Rd = Pd.coordinate_ring() x = R.variable_names() @@ -1025,10 +1021,10 @@ def dual(self): except NameError: sat = ff.elim__lib.sat - max_ideal = S.ideal(z[n + 1: 2 * n + 2]) + max_ideal = S.ideal(z[n + 1 : 2 * n + 2]) J_sat_gens = sat(J, max_ideal)[0] J_sat = S.ideal(J_sat_gens) - L = J_sat.elimination_ideal(z[0: n + 1] + (z[-1],)) + L = J_sat.elimination_ideal(z[0 : n + 1] + (z[-1],)) return Pd.subscheme(L.change_ring(Rd)) def degree(self): @@ -1260,6 +1256,7 @@ class AlgebraicScheme_subscheme_projective_field(AlgebraicScheme_subscheme_proje """ Algebraic subschemes of projective spaces defined over fields. """ + def _morphism(self, *args, **kwds): r""" Construct a morphism determined by action on points of ``self``. diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 71545e93661..6fd80c5d3bc 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -297,6 +297,7 @@ class ConvergenceError(ValueError): sage: isinstance(ConvergenceError(),ValueError) True """ + pass @@ -368,11 +369,7 @@ def differential_basis_baker(f): if not h.is_squarefree(): return None x, y = f.parent().gens() - return [ - x**(a[0] - 1) * y**(a[1] - 1) - for a in P.integral_points() - if P.interior_contains(a) - ] + return [x ** (a[0] - 1) * y ** (a[1] - 1) for a in P.integral_points() if P.interior_contains(a)] def find_closest_element(item, lst): @@ -467,7 +464,7 @@ def reparameterize_differential_minpoly(minpoly, z0): if Inf: F = F.fraction_field() - mt = F(minpoly(F.gen(0)**(-1), -F.gen(0)**2 * F.gen(1))) + mt = F(minpoly(F.gen(0) ** (-1), -F.gen(0) ** 2 * F.gen(1))) mt.reduce() mt = mt.numerator() else: @@ -621,14 +618,7 @@ class RiemannSurface: True """ - def __init__( - self, - f, - prec=53, - certification=True, - differentials=None, - integration_method="rigorous" - ): + def __init__(self, f, prec=53, certification=True, differentials=None, integration_method="rigorous"): r""" TESTS:: @@ -668,9 +658,7 @@ def __init__( self._differentials = None self.genus = self._R.ideal(self.f).genus() if self.genus < 0: - raise ValueError( - "Singular reports negative genus. Specify differentials manually." - ) + raise ValueError("Singular reports negative genus. Specify differentials manually.") self.degree = self.f.degree(w) self._dfdw = self.f.derivative(w) self._dfdz = self.f.derivative(z) @@ -678,22 +666,15 @@ def __init__( # Coefficients of the polynomial for use in homotopy continuation. self._a0 = self._CCz(self.f.coefficient({w: self.degree})(self._CCz.gen(), 0)) self._a0roots = self._a0.roots(multiplicities=False) - self._aks = [ - self._CCz(self.f.coefficient({w: self.degree - k - 1})(self._CCz.gen(), 0)) - for k in range(self.degree) - ] + self._aks = [self._CCz(self.f.coefficient({w: self.degree - k - 1})(self._CCz.gen(), 0)) for k in range(self.degree)] # Compute the branch locus. Takes the square-free part of the discriminant # because of numerical issues. self.branch_locus = [] existing_factors = [x[0] for x in self._discriminant.factor()] for fac in existing_factors: - self.branch_locus += self._CCz(fac(self._CCz.gen(), 0)).roots( - multiplicities=False - ) + self.branch_locus += self._CCz(fac(self._CCz.gen(), 0)).roots(multiplicities=False) self._f_branch_locus = self.branch_locus - self._cohomology_basis_bounding_data = self._bounding_data( - self.cohomology_basis(), exact=True - ) + self._cohomology_basis_bounding_data = self._bounding_data(self.cohomology_basis(), exact=True) RBzg, bounding_data_list = self._cohomology_basis_bounding_data minpoly_list = [bd[2] for bd in bounding_data_list] # We now want to calculate the additional branchpoints associated to @@ -707,17 +688,13 @@ def __init__( self._differentials_branch_locus = [] for x in combined_discriminant.factor(): if x[0] not in existing_factors: - self._differentials_branch_locus += self._CCz( - x[0](self._CCz.gen(), 0) - ).roots(multiplicities=False) + self._differentials_branch_locus += self._CCz(x[0](self._CCz.gen(), 0)).roots(multiplicities=False) # We add these branchpoints to the existing. # self.branch_locus = self.branch_locus+self._differentials_branch_locus # We now want to also check whether Infinity is a branch point of any # of the differentials. # This will be useful when calculating the Abel-Jacobi map. - minpoly_list = [ - reparameterize_differential_minpoly(mp, Infinity) for mp in minpoly_list - ] + minpoly_list = [reparameterize_differential_minpoly(mp, Infinity) for mp in minpoly_list] discriminants = [] for minpoly in minpoly_list: F = RBzg(minpoly) @@ -742,9 +719,7 @@ def __init__( self._fastcall_f = fast_callable(f, domain=self._CC) self._fastcall_dfdw = fast_callable(self._dfdw, domain=self._CC) self._fastcall_dfdz = fast_callable(self._dfdz, domain=self._CC) - self._fastcall_cohomology_basis = [ - fast_callable(h, domain=self._CC) for h in self.cohomology_basis() - ] + self._fastcall_cohomology_basis = [fast_callable(h, domain=self._CC) for h in self.cohomology_basis()] def __repr__(self): r""" @@ -758,10 +733,7 @@ def __repr__(self): sage: RiemannSurface(f) Riemann surface defined by polynomial f = -z^4 + w^2 + 1 = 0, with 53 bits of precision """ - s = ( - "Riemann surface defined by polynomial f = %s = 0, with %s bits of precision" - % (self.f, self._prec) - ) + s = "Riemann surface defined by polynomial f = %s = 0, with %s bits of precision" % (self.f, self._prec) return s def w_values(self, z0): @@ -831,10 +803,7 @@ def downstairs_edges(self): # The regions of these points are all of the edges which do not go off # to infinity, which are exactly the ones we want. n = len(self.branch_locus) - desired_edges = [ - self.voronoi_diagram.regions[self.voronoi_diagram.point_region[i]] - for i in range(n) - ] + desired_edges = [self.voronoi_diagram.regions[self.voronoi_diagram.point_region[i]] for i in range(n)] # First construct the edges as a set because the regions will overlap # and we do not want to have two of the same edge. edges1 = set() @@ -965,38 +934,18 @@ def _compute_delta(self, z1, epsilon, wvalues=None): # For computation of rho. Need the branch locus + roots of a0. badpoints = self._f_branch_locus + self._a0roots rho = min(abs(z1 - z) for z in badpoints) / 2 - Y = max( - abs(self._fastcall_dfdz(z1, wi) / self._fastcall_dfdw(z1, wi)) - for wi in wvalues - ) + Y = max(abs(self._fastcall_dfdz(z1, wi) / self._fastcall_dfdw(z1, wi)) for wi in wvalues) # compute M - upperbounds = [ - sum(ak[k] * (abs(z1) + rho)**k for k in range(ak.degree())) - for ak in self._aks - ] + upperbounds = [sum(ak[k] * (abs(z1) + rho) ** k for k in range(ak.degree())) for ak in self._aks] upperbounds.reverse() # If a0 is a constant polynomial, it is obviously bounded below. if not self._a0roots: lowerbound = self._CC(self._a0) / 2 else: - lowerbound = ( - self._a0[self._a0.degree()] - * prod(abs((zk - z1) - rho) for zk in self._a0roots) - / 2 - ) - M = 2 * max( - (upperbounds[k] / lowerbound).abs().nth_root(k + 1) - for k in range(self.degree - 1) - ) - return ( - rho - * ( - ((rho * Y - epsilon)**2 + 4 * epsilon * M).sqrt() - - (rho * Y + epsilon) - ) - / (2 * M - 2 * rho * Y) - ) + lowerbound = self._a0[self._a0.degree()] * prod(abs((zk - z1) - rho) for zk in self._a0roots) / 2 + M = 2 * max((upperbounds[k] / lowerbound).abs().nth_root(k + 1) for k in range(self.degree - 1)) + return rho * (((rho * Y - epsilon) ** 2 + 4 * epsilon * M).sqrt() - (rho * Y + epsilon)) / (2 * M - 2 * rho * Y) # Instead, we just compute the minimum distance between branch # points and the point in question. return min(abs(b - z1) for b in self._f_branch_locus) / 2 @@ -1054,9 +1003,7 @@ def path(t): T = ZERO currw = self.w_values(path(T)) n = len(currw) - epsilon = ( - min([abs(currw[i] - currw[j]) for i in range(1, n) for j in range(i)]) / 3 - ) + epsilon = min([abs(currw[i] - currw[j]) for i in range(1, n) for j in range(i)]) / 3 datastorage += [(T, currw, epsilon)] while T < ONE: delta = self._compute_delta(path(T), epsilon, wvalues=currw) / path_length @@ -1075,10 +1022,7 @@ def path(t): else: break currw = neww - epsilon = ( - min([abs(currw[i] - currw[j]) for i in range(1, n) for j in range(i)]) - / 3 - ) + epsilon = min([abs(currw[i] - currw[j]) for i in range(1, n) for j in range(i)]) / 3 datastorage += [(T, currw, epsilon)] return datastorage @@ -1170,11 +1114,7 @@ def _determine_new_w(self, z0, oldw, epsilon): Nnew_delta = new_delta.norm() # If we found the root exactly, or if delta only affects half the digits and # stops getting smaller, we decide that we have converged. - if (new_delta == 0) or ( - Nnew_delta >= Ndelta - and Ndelta.sign_mantissa_exponent()[2] + prec - < wi.norm().sign_mantissa_exponent()[2] - ): + if (new_delta == 0) or (Nnew_delta >= Ndelta and Ndelta.sign_mantissa_exponent()[2] + prec < wi.norm().sign_mantissa_exponent()[2]): neww.append(wi) break delta = new_delta @@ -1182,9 +1122,7 @@ def _determine_new_w(self, z0, oldw, epsilon): wi -= delta # If we run 100 iterations without a result, terminate. else: - raise ConvergenceError( - "Newton iteration fails to converge after %s iterations" % j - ) + raise ConvergenceError("Newton iteration fails to converge after %s iterations" % j) return neww def _newton_iteration(self, z0, oldw, epsilon): @@ -1257,11 +1195,7 @@ def _newton_iteration(self, z0, oldw, epsilon): Nnew_delta = new_delta.norm() # If we found the root exactly, or if delta only affects half the digits and # stops getting smaller, we decide that we have converged. - if (new_delta == 0) or ( - Nnew_delta >= Ndelta - and Ndelta.sign_mantissa_exponent()[2] + prec - < neww.norm().sign_mantissa_exponent()[2] - ): + if (new_delta == 0) or (Nnew_delta >= Ndelta and Ndelta.sign_mantissa_exponent()[2] + prec < neww.norm().sign_mantissa_exponent()[2]): return neww delta = new_delta Ndelta = Nnew_delta @@ -1300,14 +1234,7 @@ def upstairs_edges(self): d_edge = (self._vertices[i0], self._vertices[i1]) # Epsilon for checking w-value later. val = self._wvalues[i1] - epsilon = ( - min( - abs(val[i] - val[n - j - 1]) - for i in range(n) - for j in range(n - i - 1) - ) - / 3 - ) + epsilon = min(abs(val[i] - val[n - j - 1]) for i in range(n) for j in range(n - i - 1)) / 3 # Homotopy continuation along e. self._L[e] = self.homotopy_continuation(d_edge) homotopycont = self._L[e][-1][1] @@ -1353,11 +1280,7 @@ def _edge_permutation(self, edge): # find all upstairs edges that are lifts of the given # downstairs edge and store the corresponding indices at # start and end that label the branches upstairs. - L = [ - (j0, j1) - for ((i0, j0), (i1, j1)) in self.upstairs_edges() - if edge == (i0, i1) - ] + L = [(j0, j1) for ((i0, j0), (i1, j1)) in self.upstairs_edges() if edge == (i0, i1)] # we should be finding exactly "degree" of these assert len(L) == self.degree # and as a corollary of how we construct them, the indices @@ -1408,7 +1331,7 @@ def edge_permutations(self) -> dict: """ D = {e: self._edge_permutation(e) for e in self.downstairs_edges()} for (a, b), p in list(D.items()): - D[(b, a)] = p**(-1) + D[(b, a)] = p ** (-1) return D @cached_method @@ -1460,14 +1383,9 @@ def monodromy_group(self): n = len(self.branch_locus) G = Graph(self.downstairs_edges()) # we get all the regions - loops = [ - self.voronoi_diagram.regions[i][:] - for i in self.voronoi_diagram.point_region - ] + loops = [self.voronoi_diagram.regions[i][:] for i in self.voronoi_diagram.point_region] # and construct their Voronoi centers as complex numbers - centers = self.branch_locus + [ - self._CC(x, y) for x, y in self.voronoi_diagram.points[n:] - ] + centers = self.branch_locus + [self._CC(x, y) for x, y in self.voronoi_diagram.points[n:]] for center, loop in zip(centers, loops): if -1 in loop: # for loops involving infinity we take the finite part of the path @@ -1500,10 +1418,7 @@ def monodromy_group(self): SG = self._Sn for c in loops: to_loop = G.shortest_path(P0, c[0]) - to_loop_perm = SG.prod( - edge_perms[(to_loop[i], to_loop[i + 1])] - for i in range(len(to_loop) - 1) - ) + to_loop_perm = SG.prod(edge_perms[(to_loop[i], to_loop[i + 1])] for i in range(len(to_loop) - 1)) c_perm = SG.prod(edge_perms[(c[i], c[i + 1])] for i in range(len(c) - 1)) monodromy_gens.append(to_loop_perm * c_perm * ~to_loop_perm) return monodromy_gens @@ -1626,32 +1541,16 @@ def direction(center, neighbour): # problems occur with that. if (b_in != a_in) and (b_in != a_out): - if ( - (a_in_arg < b_in_arg < a_out_arg) - or (b_in_arg < a_out_arg < a_in_arg) - or (a_out_arg < a_in_arg < b_in_arg) - ): + if (a_in_arg < b_in_arg < a_out_arg) or (b_in_arg < a_out_arg < a_in_arg) or (a_out_arg < a_in_arg < b_in_arg): intsum += 1 - elif ( - (a_out_arg < b_in_arg < a_in_arg) - or (b_in_arg < a_in_arg < a_out_arg) - or (a_in_arg < a_out_arg < b_in_arg) - ): + elif (a_out_arg < b_in_arg < a_in_arg) or (b_in_arg < a_in_arg < a_out_arg) or (a_in_arg < a_out_arg < b_in_arg): intsum -= 1 else: raise RuntimeError("impossible edge orientation") if (b_out != a_in) and (b_out != a_out): - if ( - (a_in_arg < b_out_arg < a_out_arg) - or (b_out_arg < a_out_arg < a_in_arg) - or (a_out_arg < a_in_arg < b_out_arg) - ): + if (a_in_arg < b_out_arg < a_out_arg) or (b_out_arg < a_out_arg < a_in_arg) or (a_out_arg < a_in_arg < b_out_arg): intsum -= 1 - elif ( - (a_out_arg < b_out_arg < a_in_arg) - or (b_out_arg < a_in_arg < a_out_arg) - or (a_in_arg < a_out_arg < b_out_arg) - ): + elif (a_out_arg < b_out_arg < a_in_arg) or (b_out_arg < a_in_arg < a_out_arg) or (a_in_arg < a_out_arg < b_out_arg): intsum += 1 else: raise RuntimeError("impossible edge orientation") @@ -1678,9 +1577,7 @@ def direction(center, neighbour): if P[i][j] != 0: acycles[i] += [(P[i][j], list(cycles[j]) + [cycles[j][0]])] if P[self.genus + i][j] != 0: - bcycles[i] += [ - (P[self.genus + i][j], list(cycles[j]) + [cycles[j][0]]) - ] + bcycles[i] += [(P[self.genus + i][j], list(cycles[j]) + [cycles[j][0]])] return acycles + bcycles def make_zw_interpolator(self, upstairs_edge, initial_continuation=None): @@ -1895,14 +1792,10 @@ def cohomology_basis(self, option=1): # We compute this by intersecting with (Z,W,U)^(degree-3). Then the # lowest degree generators are a basis of the relevant subspace. d = fnew.total_degree() - J2 = k.ideal(J).intersection( - k.ideal([k.gen(0), k.gen(1), k.gen(2)])**(d - 3) - ) + J2 = k.ideal(J).intersection(k.ideal([k.gen(0), k.gen(1), k.gen(2)]) ** (d - 3)) generators = [dehom(c) for c in J2.gens() if c.degree() == d - 3] if len(generators) != self.genus: - raise ValueError( - "computed regular differentials do not match stored genus" - ) + raise ValueError("computed regular differentials do not match stored genus") self._differentials = generators return self._differentials @@ -1956,15 +1849,13 @@ def is_hyperelliptic(self): # corresponding quadratic differentials II = self._R.ideal(self.f) diffs = self.cohomology_basis() - pairs = [II.reduce(diffs[i]*diffs[j]) for i in range(self.genus) - for j in range(i, self.genus)] + pairs = [II.reduce(diffs[i] * diffs[j]) for i in range(self.genus) for j in range(i, self.genus)] # Find the monomials present and their coefficients mons = {mon for p in pairs for mon in p.monomials()} - CM = Matrix([[p.monomial_coefficient(mon) for p in pairs] - for mon in mons]) + CM = Matrix([[p.monomial_coefficient(mon) for p in pairs] for mon in mons]) # test the number of linearly independent pairs - return CM.rank() <= 2*self.genus - 1 + return CM.rank() <= 2 * self.genus - 1 def _bounding_data(self, differentials, exact=False): r""" @@ -2049,21 +1940,14 @@ def _bounding_data(self, differentials, exact=False): # minpoly_univ gives the minimal polynomial for h, in variable x, with # coefficients given by polynomials with coefficients in P (i.e. # rational polynomials in Z). - minpoly_univ = [ - (h(P.gen(0), L.gen(0)) / dfdw_L).minpoly().numerator() - for h in differentials - ] + minpoly_univ = [(h(P.gen(0), L.gen(0)) / dfdw_L).minpoly().numerator() for h in differentials] RBzg = PolynomialRing(RB, ["z", "g"]) # The following line changes the variables in these minimal polynomials # as Z -> z, x -> G, then evaluates at G = QQzg.gens(1) ( = g ) RBzgG = PolynomialRing(RBzg, "G") - minpoly_list = [ - RBzgG([c(RBzg.gen(0)) for c in list(h)])(RBzg.gen(1)) for h in minpoly_univ - ] + minpoly_list = [RBzgG([c(RBzg.gen(0)) for c in list(h)])(RBzg.gen(1)) for h in minpoly_univ] # h(z,g)=0 --> dg/dz = - dhdz/dhdg - dgdz_list = [ - -h.derivative(RBzg.gen(0)) / h.derivative(RBzg.gen(1)) for h in minpoly_list - ] + dgdz_list = [-h.derivative(RBzg.gen(0)) / h.derivative(RBzg.gen(1)) for h in minpoly_list] CCzg = PolynomialRing(self._CC, ["z", "g"]) CCminpoly_list = [CCzg(h) for h in minpoly_list] @@ -2076,12 +1960,7 @@ def _bounding_data(self, differentials, exact=False): a0_info = [ ( self._CC(a0.leading_coefficient()), - flatten( - [ - self._CCz(F).roots(multiplicities=False) * m - for F, m in a0.factor() - ] - ), + flatten([self._CCz(F).roots(multiplicities=False) * m for F, m in a0.factor()]), ) for a0 in a0_list ] @@ -2188,9 +2067,7 @@ def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): except KeyError: initial_continuation = self.homotopy_continuation(d_edge) - zwt, z1_minus_z0 = self.make_zw_interpolator( - upstairs_edge, initial_continuation - ) + zwt, z1_minus_z0 = self.make_zw_interpolator(upstairs_edge, initial_continuation) z0 = zwt(0)[0] z1 = zwt(1)[0] @@ -2202,7 +2079,7 @@ def rigorous_line_integral(self, upstairs_edge, differentials, bounding_data): alpha = self._RR(912 / 1000) # alpha set manually for scaling purposes. Basic benchmarking shows # that ~0.9 is a sensible value. - E_global = self._RR(2)**(-self._prec + 3) + E_global = self._RR(2) ** (-self._prec + 3) # Output will iteratively store the output of the integral. V = VectorSpace(self._CC, len(differentials)) @@ -2244,36 +2121,24 @@ def local_N(ct, rt): # z1_minus_z0.abs(), so we shall compute this factor without those # multiplications as a function of rho_t / rt which should thus be # more resistance to floating-point errors. - pf2 = (alpha + (1 - alpha) * (rt / rho_t))**2 / ( - (1 - alpha) * (1 - rt / rho_t) - ) - expr = ( - rho_t / rt + ((rho_t / rt)**2 - 1).sqrt() - ) # Note this is really exp(arcosh(rho_t/rt)) + pf2 = (alpha + (1 - alpha) * (rt / rho_t)) ** 2 / ((1 - alpha) * (1 - rt / rho_t)) + expr = rho_t / rt + ((rho_t / rt) ** 2 - 1).sqrt() # Note this is really exp(arcosh(rho_t/rt)) Ni = 3 cw = zwt(ct)[1] for g, dgdz, minpoly, (a0lc, a0roots) in bounding_data_list: z_1 = a0lc.abs() * prod((cz - r).abs() - rho_z for r in a0roots) n = minpoly.degree(CCzg.gen(1)) - ai_new = [ - CCz(minpoly.coefficient({CCzg.gen(1): i}))(z=cz + self._CCz.gen(0)) - for i in range(n) - ] + ai_new = [CCz(minpoly.coefficient({CCzg.gen(1): i}))(z=cz + self._CCz.gen(0)) for i in range(n)] ai_pos = [self._RRz([c.abs() for c in h.list()]) for h in ai_new] m = [a(rho_z) / z_1 for a in ai_pos] l = len(m) - M_tilde = 2 * max( - (m[i].abs())**(1 / self._RR(l - i)) for i in range(l) - ) + M_tilde = 2 * max((m[i].abs()) ** (1 / self._RR(l - i)) for i in range(l)) cg = g(cz, cw) cdgdz = dgdz(cz, cg) M = delta_z * cdgdz.abs() + pf2 * M_tilde - N_required = ( - (M * (self._RR.pi() + 64 / (15 * (expr**2 - 1))) / E_global).log() - / (2 * expr.log()) - ) + N_required = (M * (self._RR.pi() + 64 / (15 * (expr**2 - 1))) / E_global).log() / (2 * expr.log()) if N_required.is_positive_infinity(): - return 2**max(60, self._prec) + return 2 ** max(60, self._prec) Ni = max(Ni, N_required.ceil()) return Ni @@ -2474,10 +2339,7 @@ def riemann_matrix(self): """ PeriodMatrix = self.period_matrix() Am = PeriodMatrix[0 : self.genus, 0 : self.genus] - RM = ( - numerical_inverse(Am) - * PeriodMatrix[0 : self.genus, self.genus : 2 * self.genus] - ) + RM = numerical_inverse(Am) * PeriodMatrix[0 : self.genus, self.genus : 2 * self.genus] return RM def plot_paths(self): @@ -2739,7 +2601,7 @@ def tangent_representation_algebraic(self, Rs, other=None, epscomp=None): True """ if not epscomp: - epscomp = 2**(-self._prec + 30) + epscomp = 2 ** (-self._prec + 30) QQalg = QQ.algebraic_closure() def polynomialize_element(alpha): @@ -2805,9 +2667,7 @@ def standard_symplectic_matrix(n): g = self.genus if not (R.nrows() == 2 * g == R.ncols()): - raise AssertionError( - "Matrix is not the homology representation of an endomorphism" - ) + raise AssertionError("Matrix is not the homology representation of an endomorphism") J = standard_symplectic_matrix(g) return -J * R.transpose() * J @@ -2944,9 +2804,7 @@ def __add__(self, other): """ return RiemannSurfaceSum([self, other]) - def _integrate_differentials_iteratively( - self, upstairs_edge, cutoff_individually=False, raise_errors=True, prec=None - ): + def _integrate_differentials_iteratively(self, upstairs_edge, cutoff_individually=False, raise_errors=True, prec=None): r""" Integrate the cohomology basis along a straight line edge. @@ -3037,13 +2895,13 @@ def _integrate_differentials_iteratively( CCzg = PolynomialRing(self._CC, ["zbar", "gbar"]) mp_list = [CCzg(mp) for mp in mp_list] J = 1 / z_end - endscale = -(z_end**(-2)) + endscale = -(z_end ** (-2)) def initialise(z, i): DF = ComplexField(2 * self._prec) DFw = PolynomialRing(DF, "wbar") z = DF(z) - R = DF(z**(-1)) + R = DF(z ** (-1)) wR = DFw(self.f(R, DFw.gen(0))).roots(multiplicities=False)[w_start] newg = -(R**2) * self.cohomology_basis()[i](R, wR) / self._dfdw(R, wR) err = mp_list[i](z, newg).abs() @@ -3059,9 +2917,7 @@ def initialise(z, i): endscale = 1 def initialise(z, i): - newg = self.cohomology_basis()[i](z_start, w_start) / self._dfdw( - z_start, w_start - ) + newg = self.cohomology_basis()[i](z_start, w_start) / self._dfdw(z_start, w_start) err = mp_list[i](z, newg).abs() if err > tau: rs = mp_list[i](z, self._CCw.gen(0)).roots(multiplicities=False) @@ -3073,14 +2929,12 @@ def initialise(z, i): # be required for the homotopy continuation, we create fast-callable # versions of these. fc_mp_list = [fast_callable(mp, domain=self._CC) for mp in mp_list] - fc_dmp_list = [ - fast_callable(mp.derivative(CCzg.gen(1)), domain=self._CC) for mp in mp_list - ] + fc_dmp_list = [fast_callable(mp.derivative(CCzg.gen(1)), domain=self._CC) for mp in mp_list] if prec is None: prec = self._prec # tau here is playing the role of the desired error. - tau = self._RR(2)**(-prec + 3) + tau = self._RR(2) ** (-prec + 3) one = self._RR.one() la = self._RR.pi() / 2 @@ -3102,28 +2956,14 @@ def initialise(z, i): aes = [] for mp in mp_list: d = mp.monomial_coefficients() - mp = sum( - [ - d[k] * CCzg.gen(0)**k[0] * CCzg.gen(1)**k[1] - for k in d.keys() - if d[k].abs() > tau - ] - ) + mp = sum([d[k] * CCzg.gen(0) ** k[0] * CCzg.gen(1) ** k[1] for k in d.keys() if d[k].abs() > tau]) cst = min([iz for (iz, ig) in d.keys() if ig == 0]) a = QQ(max([(cst - iz) / ig for (iz, ig) in d.keys() if ig > 0])) - sum_coeffs = sum( - [ - d[k] * A.gen(0)**k[1] - for k in d.keys() - if ((k[1] == 0 and k[0] == cst) or k[1] * a + k[0] - cst == 0) - ] - ) + sum_coeffs = sum([d[k] * A.gen(0) ** k[1] for k in d.keys() if ((k[1] == 0 and k[0] == cst) or k[1] * a + k[0] - cst == 0)]) G = max([r.abs() for r in sum_coeffs.roots(multiplicities=False)]) - cutoffs.append(((a + 1) * tau / G)**(1 / self._CC(a + 1)) / J.abs()) + cutoffs.append(((a + 1) * tau / G) ** (1 / self._CC(a + 1)) / J.abs()) aes.append(a) - cutoff_individually = bool( - not all(ai <= 0 for ai in aes) and cutoff_individually - ) + cutoff_individually = bool(not all(ai <= 0 for ai in aes) and cutoff_individually) # The `raise_errors' variable toggles what we do in the event that # newton iteration hasn't converged to the desired precision in a @@ -3178,11 +3018,7 @@ def fv(hj, previous_estimate_and_validity): for j in range(100): new_delta = F(z0, newg) / dF(z0, newg) Nnew_delta = new_delta.norm() - if (new_delta == 0) or ( - Nnew_delta >= Ndelta - and (Ndelta.sign_mantissa_exponent()[2] + self._prec) - < newg.norm().sign_mantissa_exponent()[2] - ): + if (new_delta == 0) or (Nnew_delta >= Ndelta and (Ndelta.sign_mantissa_exponent()[2] + self._prec) < newg.norm().sign_mantissa_exponent()[2]): outg.append(newg) break delta = new_delta @@ -3195,7 +3031,7 @@ def fv(hj, previous_estimate_and_validity): outg.append(newg) fj = V(outg) u1 = la * hj.cosh() - w = u1 / (2 * u2.cosh()**2) + w = u1 / (2 * u2.cosh() ** 2) return (fj, valid), w * fj f0, v0 = fv(h0, (self.genus * [0], self.genus * [False])) @@ -3217,11 +3053,7 @@ def fv(hj, previous_estimate): for j in range(100): new_delta = F(z0, newg) / dF(z0, newg) Nnew_delta = new_delta.norm() - if (new_delta == 0) or ( - Nnew_delta >= Ndelta - and (Ndelta.sign_mantissa_exponent()[2] + self._prec) - < newg.norm().sign_mantissa_exponent()[2] - ): + if (new_delta == 0) or (Nnew_delta >= Ndelta and (Ndelta.sign_mantissa_exponent()[2] + self._prec) < newg.norm().sign_mantissa_exponent()[2]): outg.append(newg) break delta = new_delta @@ -3234,7 +3066,7 @@ def fv(hj, previous_estimate): outg.append(newg) fj = V(outg) u1 = la * hj.cosh() - w = u1 / (2 * u2.cosh()**2) + w = u1 / (2 * u2.cosh() ** 2) return fj, w * fj u1, u2 = (la * h0.cosh(), la * h0.sinh()) @@ -3277,7 +3109,7 @@ def fv(hj, previous_estimate): D = min( one, max( - D1**(D1.log() / D2.log()), + D1 ** (D1.log() / D2.log()), D2**2, tau * D3_over_tau, D4, @@ -3368,22 +3200,14 @@ def _aj_based(self, P): zV += 1 upstairs_edge = (P, zV) ci = bool(self._CC(Infinity) in self._differentials_branch_locus) - AJ, endgs = self._integrate_differentials_iteratively( - upstairs_edge, cutoff_individually=ci - ) + AJ, endgs = self._integrate_differentials_iteratively(upstairs_edge, cutoff_individually=ci) AJ = -AJ g0e = endgs[0] ws = self.w_values(zV) g0s = [self.cohomology_basis()[0](zV, wi) / self._dfdw(zV, wi) for wi in ws] W_index = find_closest_element(g0e, g0s) - if ( - g0e - - self.cohomology_basis()[0](zV, ws[W_index]) - / self._dfdw(zV, ws[W_index]) - ).abs() > 1e-10: - raise ConvergenceError( - "Integrand continuation failed to get representative values, higher precision required." - ) + if (g0e - self.cohomology_basis()[0](zV, ws[W_index]) / self._dfdw(zV, ws[W_index])).abs() > 1e-10: + raise ConvergenceError("Integrand continuation failed to get representative values, higher precision required.") V_index = B[0] else: zP = self._CC(zP) @@ -3406,33 +3230,15 @@ def _aj_based(self, P): # We choose the first vertex we want to go to. # If the closest vertex is closer than the nearest branch point, just take that vertex # otherwise we need something smarter. - delta = self._RR(2)**(-self._prec + 1) - if not ( - (zP - self._vertices[V_index]).abs() < (zP - b).abs() - or (zP - b).abs() <= delta - ): - region = self.voronoi_diagram.regions[ - self.voronoi_diagram.point_region[b_index] - ] - args = [ - (self._vertices[i] - zP).argument() - (b - zP).argument() - for i in region - ] - suitable_vertex_indices = [ - region[i] - for i in range(len(region)) - if args[i].abs() - self._RR.pi() / 2 >= -self._RR(1e-15) - ] - suitable_vertices = [ - self._vertices[i] for i in suitable_vertex_indices - ] + delta = self._RR(2) ** (-self._prec + 1) + if not ((zP - self._vertices[V_index]).abs() < (zP - b).abs() or (zP - b).abs() <= delta): + region = self.voronoi_diagram.regions[self.voronoi_diagram.point_region[b_index]] + args = [(self._vertices[i] - zP).argument() - (b - zP).argument() for i in region] + suitable_vertex_indices = [region[i] for i in range(len(region)) if args[i].abs() - self._RR.pi() / 2 >= -self._RR(1e-15)] + suitable_vertices = [self._vertices[i] for i in suitable_vertex_indices] if suitable_vertices == []: - raise ValueError( - "There is no satisfactory choice of V for zP={}".format(zP) - ) - V_index = suitable_vertex_indices[ - find_closest_element(zP, suitable_vertices) - ] + raise ValueError("There is no satisfactory choice of V for zP={}".format(zP)) + V_index = suitable_vertex_indices[find_closest_element(zP, suitable_vertices)] ##### zV = self._vertices[V_index] @@ -3452,34 +3258,14 @@ def _aj_based(self, P): ##### # Here we need a block of code to change the vertex if the path # from zP to zV would go through a ramification point of the integrands - fl = [ - c - for c in self._differentials_branch_locus - if not c == self._CC(Infinity) - ] - ts = [ - ((c - zP) * (zV - zP).conjugate()).real() - / (zP - zV).norm()**2 - for c in fl - ] - ds = [ - (fl[i] - zP - ts[i] * (zV - zP)).abs() - for i in range(len(ts)) - if (ts[i] >= 0 and ts[i] <= 1) - ] + fl = [c for c in self._differentials_branch_locus if not c == self._CC(Infinity)] + ts = [((c - zP) * (zV - zP).conjugate()).real() / (zP - zV).norm() ** 2 for c in fl] + ds = [(fl[i] - zP - ts[i] * (zV - zP)).abs() for i in range(len(ts)) if (ts[i] >= 0 and ts[i] <= 1)] while len(ds) >= 1 and min(ds) < delta: V_index = suitable_vertex_indices.pop() zV = self._vertices[V_index] - ts = [ - ((c - zP) * (zV - zP).conjugate()).real() - / (zP - zV).norm()**2 - for c in fl - ] - ds = [ - (fl[i] - zP - ts[i] * (zV - zP)).abs() - for i in range(len(ts)) - if (ts[i] >= 0 and ts[i] <= 1) - ] + ts = [((c - zP) * (zV - zP).conjugate()).real() / (zP - zV).norm() ** 2 for c in fl] + ds = [(fl[i] - zP - ts[i] * (zV - zP)).abs() for i in range(len(ts)) if (ts[i] >= 0 and ts[i] <= 1)] ##### while self._dfdw(zs, ws).abs() == 0: @@ -3488,26 +3274,15 @@ def _aj_based(self, P): wP_index = find_closest_element(ws, ws_list) ws = ws_list[wP_index] upstairs_edge = ((zs, ws), zV) - AJ, endgs = self._integrate_differentials_iteratively( - upstairs_edge, cutoff_individually=False - ) + AJ, endgs = self._integrate_differentials_iteratively(upstairs_edge, cutoff_individually=False) AJ = -AJ g0e = endgs[0] ws = self.w_values(zV) - g0s = [ - self.cohomology_basis()[0](zV, wi) / self._dfdw(zV, wi) - for wi in ws - ] + g0s = [self.cohomology_basis()[0](zV, wi) / self._dfdw(zV, wi) for wi in ws] W_index = find_closest_element(g0e, g0s) - if ( - g0e - - self.cohomology_basis()[0](zV, ws[W_index]) - / self._dfdw(zV, ws[W_index]) - ).abs() > 1e-10: - raise ConvergenceError( - "Integrand continuation failed to get representative values, higher precision required." - ) + if (g0e - self.cohomology_basis()[0](zV, ws[W_index]) / self._dfdw(zV, ws[W_index])).abs() > 1e-10: + raise ConvergenceError("Integrand continuation failed to get representative values, higher precision required.") uV_index = (V_index, W_index) ##### @@ -3573,14 +3348,10 @@ def abel_jacobi(self, divisor, verbose=False): print("starting computation for p = {}".format(p)) ans += v * self._aj_based(p) if verbose: - print( - "Done, {}% complete".format(numerical_approx(100 * (i + 1) / n, 11)) - ) + print("Done, {}% complete".format(numerical_approx(100 * (i + 1) / n, 11))) return ans - def reduce_over_period_lattice( - self, vector, method='ip', b=None, r=None, normalised=False - ): + def reduce_over_period_lattice(self, vector, method='ip', b=None, r=None, normalised=False): r""" Reduce a vector over the period lattice. @@ -3665,7 +3436,7 @@ def reduce_over_period_lattice( if r is None: r = b // 4 S = 2**b - if H * S > 2**(self._prec - 4): + if H * S > 2 ** (self._prec - 4): raise ValueError("insufficient precision for b=%s" % b) def C2Z(v): @@ -3673,15 +3444,11 @@ def C2Z(v): vR += [(S * z.imag_part()).round() for z in v] return vR - M = Matrix( - ZZ, 2 * self.genus, 2 * self.genus, [C2Z(c) for c in PM.columns()] - ) + M = Matrix(ZZ, 2 * self.genus, 2 * self.genus, [C2Z(c) for c in PM.columns()]) u = C2Z(vector) L = IntegerLattice(M) u = VR(u) - VR(L.closest_vector(u)) - reduced = VC( - [self._CC(u[i] + I * u[i + self.genus]) / S for i in range(self.genus)] - ) + reduced = VC([self._CC(u[i] + I * u[i + self.genus]) / S for i in range(self.genus)]) elif method == "ip": @@ -3694,9 +3461,7 @@ def C2R(v): v_dot_e = VR([u.dot_product(e) for e in basis_vecs]) coeffs = M.solve_right(v_dot_e) u -= sum([t.round() * e for t, e in zip(coeffs, basis_vecs)]) - reduced = VC( - [self._CC(u[i] + I * u[i + self.genus]) for i in range(self.genus)] - ) + reduced = VC([self._CC(u[i] + I * u[i + self.genus]) for i in range(self.genus)]) else: raise ValueError("Must give a valid method.") @@ -3896,7 +3661,7 @@ def divisor_to_divisor_list(self, divisor, eps=None): # If this error bound is too restrictive, this method might fail and # not return. One might want to change the way this error is handled. if not eps: - eps = self._RR(2)**(-self._prec + 3) + eps = self._RR(2) ** (-self._prec + 3) dl = [] PZ = PolynomialRing(self._R.base(), "z").fraction_field() @@ -3904,17 +3669,12 @@ def divisor_to_divisor_list(self, divisor, eps=None): for d in divisor.support(): if d.is_infinite_place(): - raise NotImplementedError( - "Conversion of infinite places not implemented yet." - ) + raise NotImplementedError("Conversion of infinite places not implemented yet.") v = divisor.valuation(d) gs = d._prime.gens() g0 = self._R(gs[0]) - gis = [ - sum([PZ(gi.list()[i]) * RF.gen()**i for i in range(len(gi.list()))]) - for gi in gs[1:] - ] + gis = [sum([PZ(gi.list()[i]) * RF.gen() ** i for i in range(len(gi.list()))]) for gi in gs[1:]] rs = self._CCz(g0).roots() rys = [] @@ -3944,11 +3704,7 @@ def divisor_to_divisor_list(self, divisor, eps=None): ys = self._CCw(self.f(r, self._CCw.gen(0))).roots() dl.extend([(v * m * n, (r, y)) for y, n in ys]) if not sum([v[0] for v in dl]) == divisor.degree(): - raise ValueError( - "numerical instability, list of wrong degree, returning list {}".format( - dl - ) - ) + raise ValueError("numerical instability, list of wrong degree, returning list {}".format(dl)) return dl @@ -3999,22 +3755,17 @@ def integer_matrix_relations(M1, M2, b=None, r=None): if not (M1.is_square() and M2.is_square()): raise ValueError("matrices need to be square") prec = min(M1.base_ring().precision(), M2.base_ring().precision()) - H = max(max(abs(m.real_part()), abs(m.imag_part())) - for m in M1.list() + M2.list()) + H = max(max(abs(m.real_part()), abs(m.imag_part())) for m in M1.list() + M2.list()) if b is None: b = prec - 5 - H.log2().floor() if r is None: r = b // 4 S = 2**b - if H * S > 2**(prec - 4): + if H * S > 2 ** (prec - 4): raise ValueError("insufficient precision for b=%s" % b) g1 = M1.ncols() g2 = M2.ncols() - CC = ( - M1.base_ring() - if (M1.base_ring().precision() <= M2.base_ring().precision()) - else M2.base_ring() - ) + CC = M1.base_ring() if (M1.base_ring().precision() <= M2.base_ring().precision()) else M2.base_ring() V = ["%s%s" % (n, i) for n in ["a", "b", "c", "d"] for i in range(1, 1 + g1 * g2)] R = PolynomialRing(CC, V) vars = R.gens() @@ -4024,10 +3775,7 @@ def integer_matrix_relations(M1, M2, b=None, r=None): D = Matrix(R, g1, g2, vars[3 * g1 * g2 : 4 * g1 * g2]) W = ((M1 * A + B) - (M1 * C + D) * M2).list() vars = R.gens() - mt = Matrix(ZZ, [[1 if i == j else 0 for j in range(4 * g1 * g2)] + - [(S * w.monomial_coefficient(vi).real_part()).round() for w in W] + - [(S * w.monomial_coefficient(vi).imag_part()).round() for w in W] - for i, vi in enumerate(vars)]) + mt = Matrix(ZZ, [[1 if i == j else 0 for j in range(4 * g1 * g2)] + [(S * w.monomial_coefficient(vi).real_part()).round() for w in W] + [(S * w.monomial_coefficient(vi).imag_part()).round() for w in W] for i, vi in enumerate(vars)]) # we compute an LLL-reduced basis of this lattice: mtL = mt.LLL() diff --git a/src/sage/schemes/toric/chow_group.py b/src/sage/schemes/toric/chow_group.py index 3ee3cc6e539..9a8a66a1fe8 100644 --- a/src/sage/schemes/toric/chow_group.py +++ b/src/sage/schemes/toric/chow_group.py @@ -158,6 +158,7 @@ class ChowCycle(FGP_Element): sage: A( Cone([(1,0)]) ) ( 0 | 1 | 0 ) """ + def __init__(self, parent, v, check=True): r""" Construct a :class:`ChowCycle`. @@ -424,7 +425,7 @@ def intersection_with_divisor(self, divisor): n = gamma.relative_quotient(sigma).gen(0).lift() perp = sigma.relative_orthogonal_quotient(gamma).gen(0).lift() I_gamma = set(gamma.ambient_ray_indices()) - set(sigma.ambient_ray_indices()) - i = I_gamma.pop() # index of a ray in gamma but not sigma + i = I_gamma.pop() # index of a ray in gamma but not sigma v_i = X.fan().ray(i) a_i = D.coefficient(i) s_i = (v_i * perp) / (n * perp) @@ -515,8 +516,7 @@ def cohomology_class(self): raise ValueError('not an orbifold') HH = toric_variety.cohomology_ring() coeff = self.lift() - return sum([HH(cone) * coeff[i] - for i, cone in enumerate(self.parent()._cones)]) + return sum([HH(cone) * coeff[i] for i, cone in enumerate(self.parent()._cones)]) class ChowGroupFactory(UniqueFactory): @@ -594,6 +594,7 @@ class ChowGroup_class(FGP_Module_class, WithEqualityById): sage: A.an_element() ( 0 | 0 | 1 ) """ + Element = ChowCycle def __init__(self, toric_variety, base_ring, check): @@ -698,8 +699,7 @@ def _element_constructor_(self, x, check=True): cone = fan.embed(x) return self.element_class(self, self._cone_to_V(cone), False) if isinstance(x, ToricDivisor_generic): - v = sum(x.coefficient(i) * self._cone_to_V(onecone) - for i, onecone in enumerate(fan(1))) + v = sum(x.coefficient(i) * self._cone_to_V(onecone) for i, onecone in enumerate(fan(1))) return self.element_class(self, v, False) return super()._element_constructor_(x, check) @@ -909,8 +909,7 @@ def degree(self, k=None): """ if k is not None: return self.degree()[k] - return tuple(ChowGroup_degree_class(self, d) - for d in range(self._variety.dimension() + 1)) + return tuple(ChowGroup_degree_class(self, d) for d in range(self._variety.dimension() + 1)) def coordinate_vector(self, chow_cycle, degree=None, reduce=True): r""" @@ -1079,8 +1078,7 @@ def __init__(self, A, d) -> None: # The minimal set of generators self._module = A.submodule(gens) - self._gens = tuple([A.element_class(A, a.lift(), False) - for a in self._module.gens()]) + self._gens = tuple([A.element_class(A, a.lift(), False) for a in self._module.gens()]) def _repr_(self) -> str: """ diff --git a/src/sage/schemes/toric/divisor.py b/src/sage/schemes/toric/divisor.py index f3b891b7eee..536a0d98409 100644 --- a/src/sage/schemes/toric/divisor.py +++ b/src/sage/schemes/toric/divisor.py @@ -178,8 +178,7 @@ from sage.misc.lazy_import import lazy_import from sage.misc.misc_c import prod from sage.modules.free_module_element import vector -from sage.modules.free_module import (FreeModule_ambient_field, - FreeModule_ambient_pid) +from sage.modules.free_module import FreeModule_ambient_field, FreeModule_ambient_pid from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.schemes.generic.divisor import Divisor_generic @@ -289,18 +288,16 @@ def ToricDivisor(toric_variety, arg=None, ring=None, check=True, reduce=True): # Divisor by lattice point (corresponding to a ray) if isinstance(arg, ToricLatticeElement): if arg not in toric_variety.fan().lattice(): - raise ValueError("%s is not in the ambient lattice of %s" - % (arg, toric_variety.fan())) + raise ValueError("%s is not in the ambient lattice of %s" % (arg, toric_variety.fan())) arg = toric_variety.fan().cone_containing(arg) # Divisor by a one-cone if isinstance(arg, sage.geometry.abc.ConvexRationalPolyhedralCone): fan = toric_variety.fan() cone = fan.embed(arg) if cone.dim() != 1: - raise ValueError("only 1-dimensional cones of the toric variety " - "define divisors") + raise ValueError("only 1-dimensional cones of the toric variety " "define divisors") arg = [(1, toric_variety.gen(cone.ambient_ray_indices()[0]))] - check = True # ensure that the 1 will be coerced into the coefficient ring + check = True # ensure that the 1 will be coerced into the coefficient ring reduce = False # Divisor by monomial if arg in toric_variety.coordinate_ring(): @@ -320,9 +317,7 @@ def ToricDivisor(toric_variety, arg=None, ring=None, check=True, reduce=True): assert all(len(item) == 2 for item in arg) except (AssertionError, TypeError): n_rays = toric_variety.fan().nrays() - assert len(arg) == n_rays, \ - 'Argument list {} is not of the required length {}!' \ - .format(arg, n_rays) + assert len(arg) == n_rays, 'Argument list {} is not of the required length {}!'.format(arg, n_rays) arg = list(zip(arg, toric_variety.gens())) reduce = False @@ -332,14 +327,12 @@ def ToricDivisor(toric_variety, arg=None, ring=None, check=True, reduce=True): # if the coefficient ring was not given, try to use the most common ones. try: TDiv = ToricDivisorGroup(toric_variety, base_ring=ZZ) - return ToricDivisor_generic(arg, TDiv, - check=True, reduce=reduce) + return ToricDivisor_generic(arg, TDiv, check=True, reduce=reduce) except TypeError: pass try: TDiv = ToricDivisorGroup(toric_variety, base_ring=QQ) - return ToricDivisor_generic(arg, TDiv, - check=True, reduce=reduce) + return ToricDivisor_generic(arg, TDiv, check=True, reduce=reduce) except TypeError: raise TypeError(f"cannot deduce coefficient ring for {arg}") TDiv = ToricDivisorGroup(toric_variety, ring) @@ -505,8 +498,7 @@ def function_value(self, point): 11 """ if not self.is_QQ_Cartier(): - raise ValueError("support functions are associated to QQ-Cartier " - "divisors only, %s is not QQ-Cartier" % self) + raise ValueError("support functions are associated to QQ-Cartier " "divisors only, %s is not QQ-Cartier" % self) try: index = ZZ(point) return self.coefficient(index) @@ -592,12 +584,11 @@ def m(self, cone): m = A.solve_left(b) # A m = b else: # under-determined system; try to find integral solution - D, U, V = A.smith_form() # D = U*A*V + D, U, V = A.smith_form() # D = U*A*V bV = b * V m = D.solve_left(bV) * U except ValueError: - raise ValueError("%s is not QQ-Cartier, cannot choose a dual " - "vector on %s" % (self, cone)) + raise ValueError("%s is not QQ-Cartier, cannot choose a dual " "vector on %s" % (self, cone)) try: m = M(m) @@ -870,8 +861,7 @@ def Chow_cycle(self, ring=ZZ): toric_variety = self.parent().scheme() fan = toric_variety.fan() A = toric_variety.Chow_group(ring) - return sum(self.coefficient(i) * A(cone_1d) - for i, cone_1d in enumerate(fan(dim=1))) + return sum(self.coefficient(i) * A(cone_1d) for i, cone_1d in enumerate(fan(dim=1))) def is_ample(self) -> bool: r""" @@ -1136,8 +1126,7 @@ def sections(self): pass M = self.parent().scheme().fan().dual_lattice() - self._sections = tuple(M(m) - for m in self.polyhedron().integral_points()) + self._sections = tuple(M(m) for m in self.polyhedron().integral_points()) return self._sections def sections_monomials(self): @@ -1206,11 +1195,9 @@ def monomial(self, point): """ X = self.parent().scheme() fan = X.fan() - assert point in fan.dual_lattice(), \ - f'{point} must be a point in the M-lattice' + assert point in fan.dual_lattice(), f'{point} must be a point in the M-lattice' R = X.coordinate_ring() - return prod([R.gen(i) ** (point * fan.ray(i) + self.coefficient(i)) - for i in range(fan.nrays())]) + return prod([R.gen(i) ** (point * fan.ray(i) + self.coefficient(i)) for i in range(fan.nrays())]) def Kodaira_map(self, names='z'): r""" @@ -1259,9 +1246,11 @@ def Kodaira_map(self, names='z'): raise ValueError('the Kodaira map is not defined for divisors without sections') src = self.parent().scheme() from sage.schemes.projective.projective_space import ProjectiveSpace + ambient = ProjectiveSpace(src.base_ring(), len(sections) - 1, names=names) A = matrix(ZZ, [list(s.exponents()[0]) for s in sections]).transpose() from sage.schemes.toric.ideal import ToricIdeal + IA = ToricIdeal(A, names=names) dst = ambient.subscheme(IA) homset = src.Hom(dst) @@ -1292,8 +1281,7 @@ def _sheaf_complex(self, m): Simplicial complex with vertex set (0, 1, 3) and facets {(3,), (0, 1)} """ fan = self.parent().scheme().fan() - ray_is_negative = [m * ray + self.coefficient(i) < 0 - for i, ray in enumerate(fan.rays())] + ray_is_negative = [m * ray + self.coefficient(i) < 0 for i, ray in enumerate(fan.rays())] def cone_is_negative(cone): # and non-trivial if cone.is_trivial(): @@ -1386,8 +1374,7 @@ def _sheaf_cohomology_support(self): X = self.parent().scheme() fan = X.fan() if not X.is_complete(): - raise ValueError("%s is not complete, its cohomology is not " - "finite-dimensional" % X) + raise ValueError("%s is not complete, its cohomology is not " "finite-dimensional" % X) d = X.dimension() chamber_vertices = [] for pindexlist in Combinations(range(fan.nrays()), d): @@ -1557,8 +1544,8 @@ def cohomology(self, weight=None, deg=None, dim=False): return HH return HH[deg] from sage.modules.free_module import VectorSpace - vectorspaces = {k: VectorSpace(self.scheme().base_ring(), HH[k]) - for k in range(len(HH))} + + vectorspaces = {k: VectorSpace(self.scheme().base_ring(), HH[k]) for k in range(len(HH))} if deg is None: return vectorspaces return vectorspaces[deg] @@ -1661,8 +1648,7 @@ def _latex_(self): sage: print(toric_varieties.P2().toric_divisor_group()._latex_()) \mathrm{Div_T}\left(\mathbb{P}_{\Delta^{2}_{15}}, \Bold{Z}\right) """ - return (r"\mathrm{Div_T}\left(%s, %s\right)" - % (latex(self.scheme()), latex(self.base_ring()))) + return r"\mathrm{Div_T}\left(%s, %s\right)" % (latex(self.scheme()), latex(self.base_ring())) def _repr_(self): """ @@ -1716,8 +1702,7 @@ def gens(self) -> tuple: (V(x), V(y), V(z)) """ one = self.base_ring().one() - return tuple(ToricDivisor_generic([(one, c)], self) - for c in self.scheme().gens()) + return tuple(ToricDivisor_generic([(one, c)], self) for c in self.scheme().gens()) def gen(self, i): r""" @@ -1902,8 +1887,7 @@ def __init__(self, toric_variety): gale = fan.Gale_transform() self._projection_matrix = gale.matrix_from_columns(range(nrays)) D, U, V = self._projection_matrix.transpose().smith_form() - assert all(D[i, i] == 1 for i in range(D.ncols())), \ - 'This is a property of the Gale transform.' + assert all(D[i, i] == 1 for i in range(D.ncols())), 'This is a property of the Gale transform.' self._lift_matrix = (V * D.transpose() * U).transpose() def _repr_(self): diff --git a/src/sage/schemes/toric/fano_variety.py b/src/sage/schemes/toric/fano_variety.py index 37b19db82d5..ee9c36e8da3 100644 --- a/src/sage/schemes/toric/fano_variety.py +++ b/src/sage/schemes/toric/fano_variety.py @@ -133,11 +133,10 @@ from sage.rings.fraction_field import FractionField_generic from sage.schemes.toric.toric_subscheme import AlgebraicScheme_subscheme_toric -from sage.schemes.toric.variety import ( - ToricVariety_field, - normalize_names) +from sage.schemes.toric.variety import ToricVariety_field, normalize_names from sage.structure.all import coercion_model from sage.categories.fields import Fields + _Fields = Fields() @@ -147,17 +146,7 @@ DEFAULT_COEFFICIENTS = tuple(chr(i) for i in range(ord("a"), ord("z") + 1)) -def CPRFanoToricVariety(Delta=None, - Delta_polar=None, - coordinate_points=None, - charts=None, - coordinate_names=None, - names=None, - coordinate_name_indices=None, - make_simplicial=False, - base_ring=None, - base_field=None, - check=True): +def CPRFanoToricVariety(Delta=None, Delta_polar=None, coordinate_points=None, charts=None, coordinate_names=None, names=None, coordinate_name_indices=None, make_simplicial=False, base_ring=None, base_field=None, check=True): r""" Construct a CPR-Fano toric variety. @@ -476,24 +465,16 @@ def CPRFanoToricVariety(Delta=None, elif coordinate_points == "all but facets": coordinate_points = Delta_polar.skeleton_points(Delta_polar.dim() - 2) elif isinstance(coordinate_points, str): - raise ValueError("unrecognized description of the coordinate points!" - "\nGot: %s" % coordinate_points) + raise ValueError("unrecognized description of the coordinate points!" "\nGot: %s" % coordinate_points) elif check: cp_set = set(coordinate_points) if len(cp_set) != len(coordinate_points): - raise ValueError( - "no repetitions are allowed for coordinate points!\nGot: %s" - % coordinate_points) + raise ValueError("no repetitions are allowed for coordinate points!\nGot: %s" % coordinate_points) if not cp_set.issuperset(list(range(Delta_polar.n_vertices()))): - raise ValueError("all %d vertices of Delta_polar must be used " - "for coordinates!\nGot: %s" - % (Delta_polar.n_vertices(), coordinate_points)) + raise ValueError("all %d vertices of Delta_polar must be used " "for coordinates!\nGot: %s" % (Delta_polar.n_vertices(), coordinate_points)) if Delta_polar.origin() in cp_set: - raise ValueError("the origin (point #%d) cannot be used for a " - "coordinate!\nGot: %s" - % (Delta_polar.origin(), coordinate_points)) - point_to_ray = {point: n - for n, point in enumerate(coordinate_points)} + raise ValueError("the origin (point #%d) cannot be used for a " "coordinate!\nGot: %s" % (Delta_polar.origin(), coordinate_points)) + point_to_ray = {point: n for n, point in enumerate(coordinate_points)} # This can be simplified if LatticePolytopeClass is adjusted. rays = [Delta_polar.point(p) for p in coordinate_points] # Check/normalize charts and construct the fan based on them. @@ -505,8 +486,7 @@ def CPRFanoToricVariety(Delta=None, # single facet of Delta_polar, otherwise they do not form a # subdivision of the face fan of Delta_polar if check: - facet_sets = [frozenset(facet.ambient_point_indices()) - for facet in Delta_polar.facets()] + facet_sets = [frozenset(facet.ambient_point_indices()) for facet in Delta_polar.facets()] for chart in charts: is_bad = True for fset in facet_sets: @@ -514,29 +494,22 @@ def CPRFanoToricVariety(Delta=None, is_bad = False break if is_bad: - raise ValueError( - "%s does not form a chart of a subdivision of the " - "face fan of %s!" % (chart, Delta_polar)) + raise ValueError("%s does not form a chart of a subdivision of the " "face fan of %s!" % (chart, Delta_polar)) # We will construct the initial fan from Cone objects: since charts # may not use all of the necessary rays, alternative form is tedious # With check=False it should not be long anyway. - cones = [Cone((rays[point_to_ray[point]] for point in chart), - check=check) - for chart in charts] + cones = [Cone((rays[point_to_ray[point]] for point in chart), check=check) for chart in charts] fan = Fan(cones, check=check) if check and not fan.is_complete(): raise ValueError("given charts do not form a complete fan!") # Subdivide this fan to use all required points - fan = fan.subdivide(new_rays=(ray for ray in rays - if ray not in fan.rays().set()), - make_simplicial=make_simplicial) + fan = fan.subdivide(new_rays=(ray for ray in rays if ray not in fan.rays().set()), make_simplicial=make_simplicial) # Now create yet another fan making sure that the order of the rays is # the same as requested (it is a bit difficult to get it from the start) trans = {} for n, ray in enumerate(fan.rays()): trans[n] = rays.index(ray) - cones = tuple(tuple(sorted(trans[r] for r in cone.ambient_ray_indices())) - for cone in fan) + cones = tuple(tuple(sorted(trans[r] for r in cone.ambient_ray_indices())) for cone in fan) fan = Fan(cones, rays, check=False) # Check/normalize base_field if base_field is not None: @@ -544,12 +517,9 @@ def CPRFanoToricVariety(Delta=None, if base_ring is None: base_ring = QQ elif base_ring not in _Fields: - raise TypeError("need a field to construct a Fano toric variety!" - "\n Got %s" % base_ring) - fan._is_complete = True # At this point it must be for sure - return CPRFanoToricVariety_field( - Delta_polar, fan, coordinate_points, - point_to_ray, coordinate_names, coordinate_name_indices, base_ring) + raise TypeError("need a field to construct a Fano toric variety!" "\n Got %s" % base_ring) + fan._is_complete = True # At this point it must be for sure + return CPRFanoToricVariety_field(Delta_polar, fan, coordinate_points, point_to_ray, coordinate_names, coordinate_name_indices, base_ring) class CPRFanoToricVariety_field(ToricVariety_field): @@ -601,8 +571,7 @@ class CPRFanoToricVariety_field(ToricVariety_field): 2-d CPR-Fano toric variety covered by 4 affine patches """ - def __init__(self, Delta_polar, fan, coordinate_points, point_to_ray, - coordinate_names, coordinate_name_indices, base_field): + def __init__(self, Delta_polar, fan, coordinate_points, point_to_ray, coordinate_names, coordinate_name_indices, base_field): r""" See :class:`CPRFanoToricVariety_field` for documentation. @@ -621,8 +590,7 @@ def __init__(self, Delta_polar, fan, coordinate_points, point_to_ray, # Check/normalize coordinate_indices if coordinate_name_indices is None: coordinate_name_indices = coordinate_points - super().__init__(fan, coordinate_names, - coordinate_name_indices, base_field) + super().__init__(fan, coordinate_names, coordinate_name_indices, base_field) def _latex_(self): r""" @@ -650,8 +618,7 @@ def _repr_(self): sage: print(P1xP1._repr_()) 2-d CPR-Fano toric variety covered by 4 affine patches """ - return ("%d-d CPR-Fano toric variety covered by %d affine patches" - % (self.dimension_relative(), self.fan().ngenerating_cones())) + return "%d-d CPR-Fano toric variety covered by %d affine patches" % (self.dimension_relative(), self.fan().ngenerating_cones()) def anticanonical_hypersurface(self, **kwds): r""" @@ -831,14 +798,11 @@ def change_ring(self, F): if self.base_ring() == F: return self if F not in _Fields: - raise TypeError("need a field to construct a Fano toric variety!" - "\n Got %s" % F) + raise TypeError("need a field to construct a Fano toric variety!" "\n Got %s" % F) else: - return CPRFanoToricVariety_field(self._Delta_polar, self._fan, - self._coordinate_points, self._point_to_ray, - self.variable_names(), None, F) - # coordinate_name_indices do not matter, we give explicit - # names for all variables + return CPRFanoToricVariety_field(self._Delta_polar, self._fan, self._coordinate_points, self._point_to_ray, self.variable_names(), None, F) + # coordinate_name_indices do not matter, we give explicit + # names for all variables def coordinate_point_to_coordinate(self, point): r""" @@ -1062,8 +1026,7 @@ def nef_complete_intersection(self, nef_partition, **kwds): """ return NefCompleteIntersection(self, nef_partition, **kwds) - def cartesian_product(self, other, - coordinate_names=None, coordinate_indices=None): + def cartesian_product(self, other, coordinate_names=None, coordinate_indices=None): r""" Return the Cartesian product of ``self`` with ``other``. @@ -1112,10 +1075,7 @@ def cartesian_product(self, other, coordinate_points.append(point) point_to_ray[point] = ray_index - return CPRFanoToricVariety_field(Delta_polar, fan, - coordinate_points, point_to_ray, - coordinate_names, coordinate_indices, - self.base_ring()) + return CPRFanoToricVariety_field(Delta_polar, fan, coordinate_points, point_to_ray, coordinate_names, coordinate_indices, self.base_ring()) return super().cartesian_product(other) def resolve(self, **kwds): @@ -1174,43 +1134,34 @@ def resolve(self, **kwds): # just toric variety if subdivision involves rays if "new_rays" in kwds: if "new_points" in kwds: - raise ValueError("you cannot give new_points and new_rays at " - "the same time!") + raise ValueError("you cannot give new_points and new_rays at " "the same time!") return super().resolve(**kwds) # Now we need to construct another Fano variety new_points = kwds.pop("new_points", ()) coordinate_points = self.coordinate_points() - new_points = tuple(point for point in new_points - if point not in coordinate_points) + new_points = tuple(point for point in new_points if point not in coordinate_points) Delta_polar = self._Delta_polar if Delta_polar.origin() in new_points: - raise ValueError("the origin (point #%d) cannot be used for " - "subdivision!" % Delta_polar.origin()) + raise ValueError("the origin (point #%d) cannot be used for " "subdivision!" % Delta_polar.origin()) if new_points: coordinate_points = coordinate_points + new_points - point_to_ray = {point: n - for n, point in enumerate(coordinate_points)} + point_to_ray = {point: n for n, point in enumerate(coordinate_points)} else: point_to_ray = self._point_to_ray new_rays = [Delta_polar.point(point) for point in new_points] - coordinate_name_indices = kwds.pop("coordinate_name_indices", - coordinate_points) + coordinate_name_indices = kwds.pop("coordinate_name_indices", coordinate_points) fan = self.fan() if "coordinate_names" in kwds: coordinate_names = kwds.pop("coordinate_names") else: coordinate_names = list(self.variable_names()) - coordinate_names.extend(normalize_names(ngens=len(new_rays), - indices=coordinate_name_indices[fan.nrays():], - prefix=self._coordinate_prefix)) + coordinate_names.extend(normalize_names(ngens=len(new_rays), indices=coordinate_name_indices[fan.nrays() :], prefix=self._coordinate_prefix)) coordinate_names.append(self._coordinate_prefix + "+") rfan = fan.subdivide(new_rays=new_rays, **kwds) - resolution = CPRFanoToricVariety_field(Delta_polar, rfan, - coordinate_points, point_to_ray, coordinate_names, - coordinate_name_indices, self.base_ring()) + resolution = CPRFanoToricVariety_field(Delta_polar, rfan, coordinate_points, point_to_ray, coordinate_names, coordinate_name_indices, self.base_ring()) R = self.coordinate_ring() R_res = resolution.coordinate_ring() - resolution_map = resolution.hom(R.hom(R_res.gens()[:R.ngens()]), self) + resolution_map = resolution.hom(R.hom(R_res.gens()[: R.ngens()]), self) resolution._resolution_map = resolution_map return resolution @@ -1244,8 +1195,8 @@ class AnticanonicalHypersurface(AlgebraicScheme_subscheme_toric): See :meth:`~CPRFanoToricVariety_field.anticanonical_hypersurface()` for a more elaborate example. """ - def __init__(self, P_Delta, monomial_points=None, coefficient_names=None, - coefficient_name_indices=None, coefficients=None): + + def __init__(self, P_Delta, monomial_points=None, coefficient_names=None, coefficient_name_indices=None, coefficients=None): r""" See :meth:`CPRFanoToricVariety_field.anticanonical_hypersurface` for documentation. @@ -1271,9 +1222,7 @@ def __init__(self, P_Delta, monomial_points=None, coefficient_names=None, + t^2*x*y + s^2*y^2 + s*t*y^2 + t^2*y^2 """ if not isinstance(P_Delta, CPRFanoToricVariety_field): - raise TypeError("anticanonical hypersurfaces can only be " - "constructed for CPR-Fano toric varieties!" - "\nGot: %s" % P_Delta) + raise TypeError("anticanonical hypersurfaces can only be " "constructed for CPR-Fano toric varieties!" "\nGot: %s" % P_Delta) Delta = P_Delta.Delta() Delta_polar = Delta.polar() # Monomial points normalization @@ -1288,17 +1237,14 @@ def __init__(self, P_Delta, monomial_points=None, coefficient_names=None, monomial_points = Delta.skeleton_points(Delta.dim() - 2) monomial_points.append(Delta.origin()) elif isinstance(monomial_points, str): - raise ValueError("%s is an unsupported description of monomial " - "points!" % monomial_points) + raise ValueError("%s is an unsupported description of monomial " "points!" % monomial_points) monomial_points = tuple(monomial_points) self._monomial_points = monomial_points # Make the necessary ambient space if coefficients is None: if coefficient_name_indices is None: coefficient_name_indices = monomial_points - coefficient_names = normalize_names( - coefficient_names, len(monomial_points), - DEFAULT_COEFFICIENT, coefficient_name_indices) + coefficient_names = normalize_names(coefficient_names, len(monomial_points), DEFAULT_COEFFICIENT, coefficient_name_indices) # We probably don't want it: the analog in else-branch is unclear. # self._coefficient_names = coefficient_names F = add_variables(P_Delta.base_ring(), coefficient_names) @@ -1317,14 +1263,9 @@ def __init__(self, P_Delta, monomial_points=None, coefficient_names=None, coefficients = [F(_) for _ in coefficients] P_Delta = P_Delta.base_extend(F) if len(monomial_points) != len(coefficients): - raise ValueError("cannot construct equation of the anticanonical" - " hypersurface with %d monomials and %d coefficients" - % (len(monomial_points), len(coefficients))) + raise ValueError("cannot construct equation of the anticanonical" " hypersurface with %d monomials and %d coefficients" % (len(monomial_points), len(coefficients))) # Defining polynomial - h = sum(coef * prod(P_Delta.coordinate_point_to_coordinate(n) - ** (Delta.point(m) * Delta_polar.point(n) + 1) - for n in P_Delta.coordinate_points()) - for m, coef in zip(monomial_points, coefficients)) + h = sum(coef * prod(P_Delta.coordinate_point_to_coordinate(n) ** (Delta.point(m) * Delta_polar.point(n) + 1) for n in P_Delta.coordinate_points()) for m, coef in zip(monomial_points, coefficients)) super().__init__(P_Delta, h) @@ -1360,9 +1301,8 @@ class NefCompleteIntersection(AlgebraicScheme_subscheme_toric): See :meth:`CPRFanoToricVariety_field.nef_complete_intersection` for a more elaborate example. """ - def __init__(self, P_Delta, nef_partition, - monomial_points='all', coefficient_names=None, - coefficient_name_indices=None, coefficients=None): + + def __init__(self, P_Delta, nef_partition, monomial_points='all', coefficient_names=None, coefficient_name_indices=None, coefficients=None): r""" See :meth:`CPRFanoToricVariety_field.nef_complete_intersection` for documentation. @@ -1384,12 +1324,9 @@ def __init__(self, P_Delta, nef_partition, + b4*z2*z4*z5 + b3*z1*z5^2 + b0*z4*z5^2 """ if not isinstance(P_Delta, CPRFanoToricVariety_field): - raise TypeError("nef complete intersections can only be " - "constructed for CPR-Fano toric varieties!" - "\nGot: %s" % P_Delta) + raise TypeError("nef complete intersections can only be " "constructed for CPR-Fano toric varieties!" "\nGot: %s" % P_Delta) if nef_partition.Delta() is not P_Delta.Delta(): - raise ValueError("polytopes 'Delta' of the nef-partition and the " - "CPR-Fano toric variety must be the same!") + raise ValueError("polytopes 'Delta' of the nef-partition and the " "CPR-Fano toric variety must be the same!") self._nef_partition = nef_partition k = nef_partition.n_parts() # Pre-normalize all parameters @@ -1413,20 +1350,16 @@ def __init__(self, P_Delta, nef_partition, monomial_points[i] = list(range(Delta_i.n_points())) elif monomial_points[i] == "vertices+origin": monomial_points[i] = list(range(Delta_i.n_vertices())) - if (Delta_i.origin() is not None - and Delta_i.origin() >= Delta_i.n_vertices()): + if Delta_i.origin() is not None and Delta_i.origin() >= Delta_i.n_vertices(): monomial_points[i].append(Delta_i.origin()) elif isinstance(monomial_points[i], str): - raise ValueError("'%s' is an unsupported description of " - "monomial points!" % monomial_points[i]) + raise ValueError("'%s' is an unsupported description of " "monomial points!" % monomial_points[i]) monomial_points[i] = tuple(monomial_points[i]) # Extend the base ring of the ambient space if necessary if coefficients[i] is None: if coefficient_name_indices[i] is None: coefficient_name_indices[i] = monomial_points[i] - coefficient_names[i] = normalize_names( - coefficient_names[i], len(monomial_points[i]), - DEFAULT_COEFFICIENTS[i], coefficient_name_indices[i]) + coefficient_names[i] = normalize_names(coefficient_names[i], len(monomial_points[i]), DEFAULT_COEFFICIENTS[i], coefficient_name_indices[i]) F = add_variables(P_Delta.base_ring(), coefficient_names[i]) coefficients[i] = [F(coef) for coef in coefficient_names[i]] else: @@ -1443,15 +1376,9 @@ def __init__(self, P_Delta, nef_partition, coefficients[i] = [F(_) for _ in coefficients[i]] P_Delta = P_Delta.base_extend(F) if len(monomial_points[i]) != len(coefficients[i]): - raise ValueError("cannot construct equation %d of the complete" - " intersection with %d monomials and %d coefficients" - % (i, len(monomial_points[i]), len(coefficients[i]))) + raise ValueError("cannot construct equation %d of the complete" " intersection with %d monomials and %d coefficients" % (i, len(monomial_points[i]), len(coefficients[i]))) # Defining polynomial - h = sum(coef * prod(P_Delta.coordinate_point_to_coordinate(n) - ** (Delta_i.point(m) * Delta_polar.point(n) - + (nef_partition.part_of_point(n) == i)) - for n in P_Delta.coordinate_points()) - for m, coef in zip(monomial_points[i], coefficients[i])) + h = sum(coef * prod(P_Delta.coordinate_point_to_coordinate(n) ** (Delta_i.point(m) * Delta_polar.point(n) + (nef_partition.part_of_point(n) == i)) for n in P_Delta.coordinate_points()) for m, coef in zip(monomial_points[i], coefficients[i])) polynomials.append(h) self._monomial_points = tuple(monomial_points) super().__init__(P_Delta, polynomials) @@ -1478,9 +1405,7 @@ def cohomology_class(self): """ X = self.ambient_space() H = X.cohomology_ring() - return prod(sum(H.gen(X._point_to_ray[point]) - for point in part if point in X._coordinate_points) - for part in self.nef_partition().parts(all_points=True)) + return prod(sum(H.gen(X._point_to_ray[point]) for point in part if point in X._coordinate_points) for part in self.nef_partition().parts(all_points=True)) def nef_partition(self): r""" @@ -1549,8 +1474,7 @@ def add_variables(field, variables): if v not in new_variables: new_variables.append(v) if len(new_variables) > R.ngens(): - return PolynomialRing(R.base_ring(), - new_variables).fraction_field() + return PolynomialRing(R.base_ring(), new_variables).fraction_field() return field # "Intelligent extension" didn't work, use the "usual one." new_variables = [] diff --git a/src/sage/schemes/toric/homset.py b/src/sage/schemes/toric/homset.py index 2417165e467..35184717113 100644 --- a/src/sage/schemes/toric/homset.py +++ b/src/sage/schemes/toric/homset.py @@ -108,8 +108,7 @@ from sage.matrix.matrix_space import MatrixSpace from sage.geometry.fan_morphism import FanMorphism -from sage.schemes.generic.homset import (SchemeHomset_generic, - SchemeHomset_points) +from sage.schemes.generic.homset import SchemeHomset_generic, SchemeHomset_points class SchemeHomset_toric_variety(SchemeHomset_generic): @@ -167,6 +166,7 @@ def __init__(self, X, Y, category=None, check=True, base=ZZ): """ SchemeHomset_generic.__init__(self, X, Y, category=category, check=check, base=base) from sage.schemes.toric.variety import ToricVariety_field + if isinstance(X, ToricVariety_field) and isinstance(Y, ToricVariety_field): self.register_conversion(MatrixSpace(ZZ, X.fan().dim(), Y.fan().dim())) @@ -242,11 +242,13 @@ def _element_constructor_(self, x, check=True): [x0 : x1 : x2] """ from sage.schemes.toric.morphism import SchemeMorphism_polynomial_toric_variety + if isinstance(x, (list, tuple)): return SchemeMorphism_polynomial_toric_variety(self, x, check=check) from sage.categories.map import Map from sage.categories.rings import Rings + if isinstance(x, Map) and x.category_for().is_subcategory(Rings()): # x is a morphism of Rings assert x.domain() is self.codomain().coordinate_ring() @@ -258,8 +260,10 @@ def _element_constructor_(self, x, check=True): if isinstance(x, FanMorphism): if x.is_dominant(): from sage.schemes.toric.morphism import SchemeMorphism_fan_toric_variety_dominant + return SchemeMorphism_fan_toric_variety_dominant(self, x, check=check) from sage.schemes.toric.morphism import SchemeMorphism_fan_toric_variety + return SchemeMorphism_fan_toric_variety(self, x, check=check) raise TypeError("x must be a fan morphism or a list/tuple of polynomials") @@ -280,8 +284,8 @@ def _an_element_(self): Rational polyhedral fan in 2-d lattice N. """ from sage.matrix.constructor import zero_matrix - zero = zero_matrix(self.domain().dimension_relative(), - self.codomain().dimension_relative()) + + zero = zero_matrix(self.domain().dimension_relative(), self.codomain().dimension_relative()) return self(zero) @@ -351,6 +355,7 @@ def _naive_enumerator(self, ring=None): [0 : 0 : 1] """ from sage.schemes.toric.points import NaiveFinitePointEnumerator + variety = self.codomain() if ring is None: ring = variety.base_ring() @@ -382,6 +387,7 @@ def _finite_field_enumerator(self, finite_field=None): [0 : 0 : 1] """ from sage.schemes.toric.points import FiniteFieldPointEnumerator + variety = self.codomain() if finite_field is None: finite_field = variety.base_ring() @@ -411,6 +417,7 @@ def _enumerator(self): if ring.is_finite(): return self._naive_enumerator() from sage.schemes.toric.points import InfinitePointEnumerator + return InfinitePointEnumerator(self.codomain().fan(), ring) @@ -544,6 +551,7 @@ def cardinality(self): if variety.dimension_relative() == 0: return ZZ.one() from sage.rings.infinity import Infinity + return Infinity if not variety.is_smooth(): try: @@ -553,7 +561,7 @@ def cardinality(self): q = variety.base_ring().order() n = variety.dimension() d = map(len, variety.fan().cones()) - return sum(dk * (q - 1)**(n - k) for k, dk in enumerate(d)) + return sum(dk * (q - 1) ** (n - k) for k, dk in enumerate(d)) def __iter__(self): """ @@ -596,9 +604,11 @@ def _enumerator(self): ring = self.domain().base_ring() if ring in FiniteFields(): from sage.schemes.toric.points import FiniteFieldSubschemePointEnumerator + Enumerator = FiniteFieldSubschemePointEnumerator else: from sage.schemes.toric.points import NaiveSubschemePointEnumerator + Enumerator = NaiveSubschemePointEnumerator return Enumerator(self.codomain().defining_polynomials(), ambient) diff --git a/src/sage/schemes/toric/ideal.py b/src/sage/schemes/toric/ideal.py index 4c171595e6a..b598f1de311 100644 --- a/src/sage/schemes/toric/ideal.py +++ b/src/sage/schemes/toric/ideal.py @@ -196,10 +196,7 @@ class ToricIdeal(MPolynomialIdeal): ValueError: you must not specify both variable names and a polynomial ring """ - def __init__(self, A, - names='z', base_ring=QQ, - polynomial_ring=None, - algorithm='HostenSturmfels'): + def __init__(self, A, names='z', base_ring=QQ, polynomial_ring=None, algorithm='HostenSturmfels'): r""" Create an ideal and a multivariate polynomial ring containing it. @@ -328,8 +325,7 @@ def _init_ring(self, term_order): sage: z0 < z1 and z1 < z2 True """ - return PolynomialRing(self._base_ring, self._names, - self.nvariables(), order=term_order) + return PolynomialRing(self._base_ring, self._names, self.nvariables(), order=term_order) def _naive_ideal(self, ring): r""" @@ -354,8 +350,8 @@ def _naive_ideal(self, ring): x = ring.gens() binomials = [] for row in self.ker().matrix().rows(): - xpos = prod(x[i]**max(row[i], 0) for i in range(len(x))) - xneg = prod(x[i]**max(-row[i], 0) for i in range(len(x))) + xpos = prod(x[i] ** max(row[i], 0) for i in range(len(x))) + xneg = prod(x[i] ** max(-row[i], 0) for i in range(len(x))) binomials.append(xpos - xneg) return ring.ideal(binomials) @@ -409,9 +405,9 @@ def subtract(e, power): def divide_by_x_n(p): d_old = p.monomial_coefficients() power = min(e[0] for e in d_old) - d_new = {subtract(exponent, power): coefficient - for exponent, coefficient in d_old.items()} + d_new = {subtract(exponent, power): coefficient for exponent, coefficient in d_old.items()} return p.parent()(d_new) + basis = [divide_by_x_n(b) for b in basis] quotient = ring.ideal(basis) return quotient.subs(x_to_y) diff --git a/src/sage/schemes/toric/library.py b/src/sage/schemes/toric/library.py index 6f833c5c5d2..c42b5222288 100644 --- a/src/sage/schemes/toric/library.py +++ b/src/sage/schemes/toric/library.py @@ -49,133 +49,40 @@ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.arith.misc import GCD as gcd -from sage.schemes.toric.variety import (DEFAULT_PREFIX, - ToricVariety, - normalize_names) +from sage.schemes.toric.variety import DEFAULT_PREFIX, ToricVariety, normalize_names from sage.schemes.toric.fano_variety import CPRFanoToricVariety # The combinatorial data of the toric varieties is stored separately here # since we might want to use it later on to do the reverse lookup. toric_varieties_rays_cones = { - 'dP6': [ - [(0, 1), (-1, 0), (-1, -1), (0, -1), (1, 0), (1, 1)], - [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 0]]], - 'dP7': [ - [(0, 1), (-1, 0), (-1, -1), (0, -1), (1, 0)], - [[0, 1], [1, 2], [2, 3], [3, 4], [4, 0]]], - 'dP8': [ - [(1, 1), (0, 1), (-1, -1), (1, 0)], - [[0, 1], [1, 2], [2, 3], [3, 0]] - ], - 'P1xP1': [ - [(1, 0), (-1, 0), (0, 1), (0, -1)], - [[0, 2], [2, 1], [1, 3], [3, 0]]], - 'P1xP1_Z2': [ - [(1, 1), (-1, -1), (-1, 1), (1, -1)], - [[0, 2], [2, 1], [1, 3], [3, 0]]], - 'P1': [ - [(1,), (-1,)], - [[0], [1]]], - 'P2': [ - [(1, 0), (0, 1), (-1, -1)], - [[0, 1], [1, 2], [2, 0]]], - 'A1': [ - [(1,)], - [[0]]], - 'A2': [ - [(1, 0), (0, 1)], - [[0, 1]]], - 'A2_Z2': [ - [(1, 0), (1, 2)], - [[0, 1]]], - 'P1xA1': [ - [(1, 0), (-1, 0), (0, 1)], - [[0, 2], [2, 1]]], - 'Conifold': [ - [(0, 0, 1), (0, 1, 1), (1, 0, 1), (1, 1, 1)], - [[0, 1, 2, 3]]], - 'dP6xdP6': [ - [(0, 1, 0, 0), (-1, 0, 0, 0), (-1, -1, 0, 0), - (0, -1, 0, 0), (1, 0, 0, 0), (1, 1, 0, 0), - (0, 0, 0, 1), (0, 0, -1, 0), (0, 0, -1, -1), - (0, 0, 0, -1), (0, 0, 1, 0), (0, 0, 1, 1)], - [[0, 1, 6, 7], [0, 1, 7, 8], [0, 1, 8, 9], [0, 1, 9, 10], - [0, 1, 10, 11], [0, 1, 6, 11], [1, 2, 6, 7], [1, 2, 7, 8], - [1, 2, 8, 9], [1, 2, 9, 10], [1, 2, 10, 11], [1, 2, 6, 11], - [2, 3, 6, 7], [2, 3, 7, 8], [2, 3, 8, 9], [2, 3, 9, 10], - [2, 3, 10, 11], [2, 3, 6, 11], [3, 4, 6, 7], [3, 4, 7, 8], - [3, 4, 8, 9], [3, 4, 9, 10], [3, 4, 10, 11], [3, 4, 6, 11], - [4, 5, 6, 7], [4, 5, 7, 8], [4, 5, 8, 9], [4, 5, 9, 10], - [4, 5, 10, 11], [4, 5, 6, 11], [0, 5, 6, 7], [0, 5, 7, 8], - [0, 5, 8, 9], [0, 5, 9, 10], [0, 5, 10, 11], [0, 5, 6, 11]]], - 'Cube_face_fan': [ - [(1, 1, 1), (1, -1, 1), (-1, 1, 1), (-1, -1, 1), - (-1, -1, -1), (-1, 1, -1), (1, -1, -1), (1, 1, -1)], - [[0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 7, 6], [4, 5, 3, 2], [0, 2, 5, 7], [4, 6, 1, 3]]], - 'Cube_sublattice': [ - [(1, 0, 0), (0, 1, 0), (0, 0, 1), (-1, 1, 1), - (-1, 0, 0), (0, -1, 0), (0, 0, -1), (1, -1, -1)], - [[0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 7, 6], [4, 5, 3, 2], [0, 2, 5, 7], [4, 6, 1, 3]]], - 'Cube_nonpolyhedral': [ - [(1, 2, 3), (1, -1, 1), (-1, 1, 1), (-1, -1, 1), - (-1, -1, -1), (-1, 1, -1), (1, -1, -1), (1, 1, -1)], - [[0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 7, 6], [4, 5, 3, 2], [0, 2, 5, 7], [4, 6, 1, 3]]], + 'dP6': [[(0, 1), (-1, 0), (-1, -1), (0, -1), (1, 0), (1, 1)], [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 0]]], + 'dP7': [[(0, 1), (-1, 0), (-1, -1), (0, -1), (1, 0)], [[0, 1], [1, 2], [2, 3], [3, 4], [4, 0]]], + 'dP8': [[(1, 1), (0, 1), (-1, -1), (1, 0)], [[0, 1], [1, 2], [2, 3], [3, 0]]], + 'P1xP1': [[(1, 0), (-1, 0), (0, 1), (0, -1)], [[0, 2], [2, 1], [1, 3], [3, 0]]], + 'P1xP1_Z2': [[(1, 1), (-1, -1), (-1, 1), (1, -1)], [[0, 2], [2, 1], [1, 3], [3, 0]]], + 'P1': [[(1,), (-1,)], [[0], [1]]], + 'P2': [[(1, 0), (0, 1), (-1, -1)], [[0, 1], [1, 2], [2, 0]]], + 'A1': [[(1,)], [[0]]], + 'A2': [[(1, 0), (0, 1)], [[0, 1]]], + 'A2_Z2': [[(1, 0), (1, 2)], [[0, 1]]], + 'P1xA1': [[(1, 0), (-1, 0), (0, 1)], [[0, 2], [2, 1]]], + 'Conifold': [[(0, 0, 1), (0, 1, 1), (1, 0, 1), (1, 1, 1)], [[0, 1, 2, 3]]], + 'dP6xdP6': [[(0, 1, 0, 0), (-1, 0, 0, 0), (-1, -1, 0, 0), (0, -1, 0, 0), (1, 0, 0, 0), (1, 1, 0, 0), (0, 0, 0, 1), (0, 0, -1, 0), (0, 0, -1, -1), (0, 0, 0, -1), (0, 0, 1, 0), (0, 0, 1, 1)], [[0, 1, 6, 7], [0, 1, 7, 8], [0, 1, 8, 9], [0, 1, 9, 10], [0, 1, 10, 11], [0, 1, 6, 11], [1, 2, 6, 7], [1, 2, 7, 8], [1, 2, 8, 9], [1, 2, 9, 10], [1, 2, 10, 11], [1, 2, 6, 11], [2, 3, 6, 7], [2, 3, 7, 8], [2, 3, 8, 9], [2, 3, 9, 10], [2, 3, 10, 11], [2, 3, 6, 11], [3, 4, 6, 7], [3, 4, 7, 8], [3, 4, 8, 9], [3, 4, 9, 10], [3, 4, 10, 11], [3, 4, 6, 11], [4, 5, 6, 7], [4, 5, 7, 8], [4, 5, 8, 9], [4, 5, 9, 10], [4, 5, 10, 11], [4, 5, 6, 11], [0, 5, 6, 7], [0, 5, 7, 8], [0, 5, 8, 9], [0, 5, 9, 10], [0, 5, 10, 11], [0, 5, 6, 11]]], + 'Cube_face_fan': [[(1, 1, 1), (1, -1, 1), (-1, 1, 1), (-1, -1, 1), (-1, -1, -1), (-1, 1, -1), (1, -1, -1), (1, 1, -1)], [[0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 7, 6], [4, 5, 3, 2], [0, 2, 5, 7], [4, 6, 1, 3]]], + 'Cube_sublattice': [[(1, 0, 0), (0, 1, 0), (0, 0, 1), (-1, 1, 1), (-1, 0, 0), (0, -1, 0), (0, 0, -1), (1, -1, -1)], [[0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 7, 6], [4, 5, 3, 2], [0, 2, 5, 7], [4, 6, 1, 3]]], + 'Cube_nonpolyhedral': [[(1, 2, 3), (1, -1, 1), (-1, 1, 1), (-1, -1, 1), (-1, -1, -1), (-1, 1, -1), (1, -1, -1), (1, 1, -1)], [[0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 7, 6], [4, 5, 3, 2], [0, 2, 5, 7], [4, 6, 1, 3]]], 'BCdlOG': [ - [(-1, 0, 0, 2, 3), # 0 - (0, -1, 0, 2, 3), # 1 - (0, 0, -1, 2, 3), # 2 - (0, 0, -1, 1, 2), # 3 - (0, 0, 0, -1, 0), # 4 - (0, 0, 0, 0, -1), # 5 - (0, 0, 0, 2, 3), # 6 - (0, 0, 1, 2, 3), # 7 - (0, 0, 2, 2, 3), # 8 - (0, 0, 1, 1, 1), # 9 - (0, 1, 2, 2, 3), # 10 - (0, 1, 3, 2, 3), # 11 - (1, 0, 4, 2, 3)], # 12 - [[0, 6, 7, 1, 4], [0, 6, 10, 2, 4], [0, 6, 1, 2, 4], [0, 9, 7, 1, 5], [0, 6, 7, 1, 5], - [0, 6, 10, 2, 5], [0, 6, 1, 2, 5], [0, 9, 1, 4, 5], [0, 6, 10, 4, 11], [0, 6, 7, 4, 11], - [0, 6, 10, 5, 11], [0, 9, 7, 5, 11], [0, 6, 7, 5, 11], [0, 9, 4, 5, 11], [0, 10, 4, 5, 11], - [0, 9, 7, 1, 8], [0, 9, 1, 4, 8], [0, 7, 1, 4, 8], [0, 9, 7, 11, 8], [0, 9, 4, 11, 8], - [0, 7, 4, 11, 8], [0, 10, 2, 4, 3], [0, 1, 2, 4, 3], [0, 10, 2, 5, 3], [0, 1, 2, 5, 3], - [0, 10, 4, 5, 3], [0, 1, 4, 5, 3], [12, 6, 7, 1, 4], [12, 6, 10, 2, 4], [12, 6, 1, 2, 4], - [12, 9, 7, 1, 5], [12, 6, 7, 1, 5], [12, 6, 10, 2, 5], [12, 6, 1, 2, 5], [12, 9, 1, 4, 5], - [12, 6, 10, 4, 11], [12, 6, 7, 4, 11], [12, 6, 10, 5, 11], [12, 9, 7, 5, 11], [12, 6, 7, 5, 11], - [12, 9, 4, 5, 11], [12, 10, 4, 5, 11], [12, 9, 7, 1, 8], [12, 9, 1, 4, 8], [12, 7, 1, 4, 8], - [12, 9, 7, 11, 8], [12, 9, 4, 11, 8], [12, 7, 4, 11, 8], [12, 10, 2, 4, 3], [12, 1, 2, 4, 3], - [12, 10, 2, 5, 3], [12, 1, 2, 5, 3], [12, 10, 4, 5, 3], [12, 1, 4, 5, 3]]], - 'BCdlOG_base': [ - [(-1, 0, 0), - (0, -1, 0), - (0, 0, -1), - (0, 0, 1), - (0, 1, 2), - (0, 1, 3), - (1, 0, 4)], - [[0, 4, 2], [0, 4, 5], [0, 5, 3], [0, 1, 3], [0, 1, 2], - [6, 4, 2], [6, 4, 5], [6, 5, 3], [6, 1, 3], [6, 1, 2]]], - 'P2_112': [ - [(1, 0), (0, 1), (-1, -2)], - [[0, 1], [1, 2], [2, 0]]], - 'P2_123': [ - [(1, 0), (0, 1), (-2, -3)], - [[0, 1], [1, 2], [2, 0]]], - 'P4_11169': [ - [(1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1), (-9, -6, -1, -1)], - [[0, 1, 2, 3], [0, 1, 2, 4], [0, 1, 3, 4], [0, 2, 3, 4], [1, 2, 3, 4]]], - 'P4_11169_resolved': [ - [(1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1), (-9, -6, -1, -1), (-3, -2, 0, 0)], - [[0, 1, 2, 3], [0, 1, 3, 4], [0, 1, 2, 4], [1, 3, 4, 5], [0, 3, 4, 5], - [1, 2, 4, 5], [0, 2, 4, 5], [1, 2, 3, 5], [0, 2, 3, 5]]], - 'P4_11133': [ - [(1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1), (-3, -3, -1, -1)], - [[0, 1, 2, 3], [0, 1, 2, 4], [0, 1, 3, 4], [0, 2, 3, 4], [1, 2, 3, 4]]], - 'P4_11133_resolved': [ - [(1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1), (-3, -3, -1, -1), (-1, -1, 0, 0)], - [[0, 1, 2, 3], [0, 1, 3, 4], [0, 1, 2, 4], [1, 3, 4, 5], [0, 3, 4, 5], - [1, 2, 4, 5], [0, 2, 4, 5], [1, 2, 3, 5], [0, 2, 3, 5]]] + [(-1, 0, 0, 2, 3), (0, -1, 0, 2, 3), (0, 0, -1, 2, 3), (0, 0, -1, 1, 2), (0, 0, 0, -1, 0), (0, 0, 0, 0, -1), (0, 0, 0, 2, 3), (0, 0, 1, 2, 3), (0, 0, 2, 2, 3), (0, 0, 1, 1, 1), (0, 1, 2, 2, 3), (0, 1, 3, 2, 3), (1, 0, 4, 2, 3)], # 0 # 1 # 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 11 # 12 + [[0, 6, 7, 1, 4], [0, 6, 10, 2, 4], [0, 6, 1, 2, 4], [0, 9, 7, 1, 5], [0, 6, 7, 1, 5], [0, 6, 10, 2, 5], [0, 6, 1, 2, 5], [0, 9, 1, 4, 5], [0, 6, 10, 4, 11], [0, 6, 7, 4, 11], [0, 6, 10, 5, 11], [0, 9, 7, 5, 11], [0, 6, 7, 5, 11], [0, 9, 4, 5, 11], [0, 10, 4, 5, 11], [0, 9, 7, 1, 8], [0, 9, 1, 4, 8], [0, 7, 1, 4, 8], [0, 9, 7, 11, 8], [0, 9, 4, 11, 8], [0, 7, 4, 11, 8], [0, 10, 2, 4, 3], [0, 1, 2, 4, 3], [0, 10, 2, 5, 3], [0, 1, 2, 5, 3], [0, 10, 4, 5, 3], [0, 1, 4, 5, 3], [12, 6, 7, 1, 4], [12, 6, 10, 2, 4], [12, 6, 1, 2, 4], [12, 9, 7, 1, 5], [12, 6, 7, 1, 5], [12, 6, 10, 2, 5], [12, 6, 1, 2, 5], [12, 9, 1, 4, 5], [12, 6, 10, 4, 11], [12, 6, 7, 4, 11], [12, 6, 10, 5, 11], [12, 9, 7, 5, 11], [12, 6, 7, 5, 11], [12, 9, 4, 5, 11], [12, 10, 4, 5, 11], [12, 9, 7, 1, 8], [12, 9, 1, 4, 8], [12, 7, 1, 4, 8], [12, 9, 7, 11, 8], [12, 9, 4, 11, 8], [12, 7, 4, 11, 8], [12, 10, 2, 4, 3], [12, 1, 2, 4, 3], [12, 10, 2, 5, 3], [12, 1, 2, 5, 3], [12, 10, 4, 5, 3], [12, 1, 4, 5, 3]], + ], + 'BCdlOG_base': [[(-1, 0, 0), (0, -1, 0), (0, 0, -1), (0, 0, 1), (0, 1, 2), (0, 1, 3), (1, 0, 4)], [[0, 4, 2], [0, 4, 5], [0, 5, 3], [0, 1, 3], [0, 1, 2], [6, 4, 2], [6, 4, 5], [6, 5, 3], [6, 1, 3], [6, 1, 2]]], + 'P2_112': [[(1, 0), (0, 1), (-1, -2)], [[0, 1], [1, 2], [2, 0]]], + 'P2_123': [[(1, 0), (0, 1), (-2, -3)], [[0, 1], [1, 2], [2, 0]]], + 'P4_11169': [[(1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1), (-9, -6, -1, -1)], [[0, 1, 2, 3], [0, 1, 2, 4], [0, 1, 3, 4], [0, 2, 3, 4], [1, 2, 3, 4]]], + 'P4_11169_resolved': [[(1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1), (-9, -6, -1, -1), (-3, -2, 0, 0)], [[0, 1, 2, 3], [0, 1, 3, 4], [0, 1, 2, 4], [1, 3, 4, 5], [0, 3, 4, 5], [1, 2, 4, 5], [0, 2, 4, 5], [1, 2, 3, 5], [0, 2, 3, 5]]], + 'P4_11133': [[(1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1), (-3, -3, -1, -1)], [[0, 1, 2, 3], [0, 1, 2, 4], [0, 1, 3, 4], [0, 2, 3, 4], [1, 2, 3, 4]]], + 'P4_11133_resolved': [[(1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1), (-3, -3, -1, -1), (-1, -1, 0, 0)], [[0, 1, 2, 3], [0, 1, 3, 4], [0, 1, 2, 4], [1, 3, 4, 5], [0, 3, 4, 5], [1, 2, 4, 5], [0, 2, 4, 5], [1, 2, 3, 5], [0, 2, 3, 5]]], } @@ -218,15 +125,11 @@ def _make_ToricVariety(self, name, coordinate_names, base_ring): if coordinate_names is None: dict_key = (name, base_ring) else: - coordinate_names = normalize_names(coordinate_names, len(rays), - DEFAULT_PREFIX) + coordinate_names = normalize_names(coordinate_names, len(rays), DEFAULT_PREFIX) dict_key = (name, base_ring) + tuple(coordinate_names) if dict_key not in self.__dict__: fan = Fan(cones, rays, check=self._check) - self.__dict__[dict_key] = \ - ToricVariety(fan, - coordinate_names=coordinate_names, - base_ring=base_ring) + self.__dict__[dict_key] = ToricVariety(fan, coordinate_names=coordinate_names, base_ring=base_ring) return self.__dict__[dict_key] def _make_CPRFanoToricVariety(self, name, coordinate_names, base_ring): @@ -257,21 +160,14 @@ def _make_CPRFanoToricVariety(self, name, coordinate_names, base_ring): if coordinate_names is None: dict_key = (name, base_ring) else: - coordinate_names = normalize_names(coordinate_names, len(rays), - DEFAULT_PREFIX) + coordinate_names = normalize_names(coordinate_names, len(rays), DEFAULT_PREFIX) dict_key = (name, base_ring) + tuple(coordinate_names) if dict_key not in self.__dict__: polytope = LatticePolytope(rays, lattice=ToricLattice(len(rays[0]))) points = [tuple(_) for _ in polytope.points()] ray2point = [points.index(r) for r in rays] charts = [[ray2point[i] for i in c] for c in cones] - self.__dict__[dict_key] = \ - CPRFanoToricVariety(Delta_polar=polytope, - coordinate_points=ray2point, - charts=charts, - coordinate_names=coordinate_names, - base_ring=base_ring, - check=self._check) + self.__dict__[dict_key] = CPRFanoToricVariety(Delta_polar=polytope, coordinate_points=ray2point, charts=charts, coordinate_names=coordinate_names, base_ring=base_ring, check=self._check) return self.__dict__[dict_key] def dP6(self, names='x u y v z w', base_ring=QQ): @@ -521,20 +417,14 @@ def P(self, n, names='z+', base_ring=QQ): # We are going to eventually switch off consistency checks, so we need # to be sure that the input is acceptable. try: - n = ZZ(n) # make sure that we got a "mathematical" integer + n = ZZ(n) # make sure that we got a "mathematical" integer except TypeError: - raise TypeError("dimension of the projective space must be a " - "positive integer!\nGot: %s" % n) + raise TypeError("dimension of the projective space must be a " "positive integer!\nGot: %s" % n) if n <= 0: - raise ValueError("only projective spaces of positive dimension " - "can be constructed!\nGot: %s" % n) + raise ValueError("only projective spaces of positive dimension " "can be constructed!\nGot: %s" % n) m = identity_matrix(n).augment(matrix(n, 1, [-1] * n)) - charts = [list(range(i)) + list(range(i + 1, n + 1)) - for i in range(n + 1)] - return CPRFanoToricVariety( - Delta_polar=LatticePolytope(m.columns(), lattice=ToricLattice(n)), - charts=charts, check=self._check, coordinate_names=names, - base_ring=base_ring) + charts = [list(range(i)) + list(range(i + 1, n + 1)) for i in range(n + 1)] + return CPRFanoToricVariety(Delta_polar=LatticePolytope(m.columns(), lattice=ToricLattice(n)), charts=charts, check=self._check, coordinate_names=names, base_ring=base_ring) def A1(self, names='z', base_ring=QQ): r""" @@ -626,13 +516,11 @@ def A(self, n, names='z+', base_ring=QQ): # We are going to eventually switch off consistency checks, so we need # to be sure that the input is acceptable. try: - n = ZZ(n) # make sure that we got a "mathematical" integer + n = ZZ(n) # make sure that we got a "mathematical" integer except TypeError: - raise TypeError("dimension of the affine space must be a " - "positive integer!\nGot: %s" % n) + raise TypeError("dimension of the affine space must be a " "positive integer!\nGot: %s" % n) if n <= 0: - raise ValueError("only affine spaces of positive dimension can " - "be constructed!\nGot: %s" % n) + raise ValueError("only affine spaces of positive dimension can " "be constructed!\nGot: %s" % n) rays = identity_matrix(n).columns() cones = [list(range(n))] fan = Fan(cones, rays, check=self._check) @@ -910,22 +798,16 @@ def Cube_deformation(self, k, names=None, base_ring=QQ): # We are going to eventually switch off consistency checks, so we need # to be sure that the input is acceptable. try: - k = ZZ(k) # make sure that we got a "mathematical" integer + k = ZZ(k) # make sure that we got a "mathematical" integer except TypeError: - raise TypeError("cube deformations X_k are defined only for " - "nonnegative integer k!\nGot: %s" % k) + raise TypeError("cube deformations X_k are defined only for " "nonnegative integer k!\nGot: %s" % k) if k < 0: - raise ValueError("cube deformations X_k are defined only for " - "nonnegative k!\nGot: %s" % k) + raise ValueError("cube deformations X_k are defined only for " "nonnegative k!\nGot: %s" % k) def rays(kappa): - return matrix([[1, 1, 2 * kappa + 1], [1, -1, 1], - [-1, 1, 1], [-1, -1, 1], - [-1, -1, -1], [-1, 1, -1], - [1, -1, -1], [1, 1, -1]]) + return matrix([[1, 1, 2 * kappa + 1], [1, -1, 1], [-1, 1, 1], [-1, -1, 1], [-1, -1, -1], [-1, 1, -1], [1, -1, -1], [1, 1, -1]]) - cones = [[0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 7, 6], - [4, 5, 3, 2], [0, 2, 5, 7], [4, 6, 1, 3]] + cones = [[0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 7, 6], [4, 5, 3, 2], [0, 2, 5, 7], [4, 6, 1, 3]] fan = Fan(cones, rays(k)) return ToricVariety(fan, coordinate_names=names) @@ -1266,7 +1148,7 @@ def WP(self, *q, **kw): b = L_basis[i] v = Q.coordinate_vector(Q(b)) rays = rays + [v] - w_c = w[:i] + w[i + 1:] + w_c = w[:i] + w[i + 1 :] cones = cones + [tuple(w_c)] fan = Fan(cones, rays) return ToricVariety(fan, coordinate_names=names, base_ring=base_ring) diff --git a/src/sage/schemes/toric/morphism.py b/src/sage/schemes/toric/morphism.py index 0160ead5e9e..a9f8aaf8ea2 100644 --- a/src/sage/schemes/toric/morphism.py +++ b/src/sage/schemes/toric/morphism.py @@ -373,9 +373,7 @@ from sage.geometry.fan import Fan from sage.schemes.generic.scheme import Scheme -from sage.schemes.generic.morphism import ( - SchemeMorphism, SchemeMorphism_point, SchemeMorphism_polynomial -) +from sage.schemes.generic.morphism import SchemeMorphism, SchemeMorphism_point, SchemeMorphism_polynomial ############################################################################ @@ -410,6 +408,7 @@ class SchemeMorphism_point_toric_field(SchemeMorphism_point, Morphism): sage: P1xP1(1,2,3,4) [1 : 2 : 3 : 4] """ + # Mimicking affine/projective classes def __init__(self, X, coordinates, check=True): r""" @@ -431,12 +430,10 @@ def __init__(self, X, coordinates, check=True): if isinstance(coordinates, SchemeMorphism): coordinates = list(coordinates) if not isinstance(coordinates, (list, tuple)): - raise TypeError("coordinates must be a scheme point, list, " - "or tuple; got %s" % coordinates) + raise TypeError("coordinates must be a scheme point, list, " "or tuple; got %s" % coordinates) d = X.codomain().ambient_space().ngens() if len(coordinates) != d: - raise ValueError("there must be %d coordinates; got only %d: " - "%s" % (d, len(coordinates), coordinates)) + raise ValueError("there must be %d coordinates; got only %d: " "%s" % (d, len(coordinates), coordinates)) # Make sure the coordinates all lie in the appropriate ring coordinates = Sequence(coordinates, X.value_ring()) # Verify that the point satisfies the equations of X. @@ -532,8 +529,7 @@ def as_fan_morphism(self): NotImplementedError: expressing toric morphisms as fan morphisms is not implemented yet """ - raise NotImplementedError("expressing toric morphisms as fan " - "morphisms is not implemented yet") + raise NotImplementedError("expressing toric morphisms as fan " "morphisms is not implemented yet") ############################################################################ @@ -579,6 +575,7 @@ class SchemeMorphism_orbit_closure_toric_variety(SchemeMorphism, Morphism): sage: V.embedding_morphism()._defining_cone 1-d cone of Rational polyhedral fan in 2-d lattice N """ + def __init__(self, parent, defining_cone, ray_map): """ The Python constructor. @@ -749,6 +746,7 @@ def pullback_divisor(self, divisor): 4*V(z0) + 2*V(z1) """ from sage.schemes.toric.divisor import ToricDivisor_generic + if not (isinstance(divisor, ToricDivisor_generic) and divisor.is_QQ_Cartier()): raise ValueError('the divisor must be torus-invariant and QQ-Cartier') m = divisor.m(self._defining_cone) @@ -1031,6 +1029,7 @@ def factor(self): """ phi_i, phi_b, phi_s = self.fan_morphism().factor() from sage.schemes.toric.variety import ToricVariety + X = self.domain() X_s = ToricVariety(phi_s.codomain_fan()) X_i = ToricVariety(phi_i.domain_fan()) @@ -1093,12 +1092,10 @@ def as_polynomial_map(self): try: d = ZZ(d) except TypeError: - raise TypeError('the fan morphism cannot be written in ' - 'homogeneous polynomials') + raise TypeError('the fan morphism cannot be written in ' 'homogeneous polynomials') polys[i] *= x**d if phi.domain_fan().virtual_rays(): - raise NotImplementedError("polynomial representations for fans with" - " virtual rays are not implemented yet") + raise NotImplementedError("polynomial representations for fans with" " virtual rays are not implemented yet") return SchemeMorphism_polynomial_toric_variety(self.parent(), polys) def is_bundle(self) -> bool: @@ -1278,6 +1275,7 @@ def pullback_divisor(self, divisor): 2*V(z) """ from sage.schemes.toric.divisor import ToricDivisor_generic + if not (isinstance(divisor, ToricDivisor_generic) and divisor.is_QQ_Cartier()): raise ValueError('the divisor must be torus-invariant and QQ-Cartier') fm = self.fan_morphism() @@ -1384,10 +1382,11 @@ def fiber_generic(self): (0-d cone of Rational polyhedral fan in Sublattice ,) """ from sage.schemes.toric.variety import ToricVariety + fm = self.fan_morphism() X = ToricVariety(fm.kernel_fan()) m = X.fan().lattice().echelonized_basis_matrix() - N = fm.domain() # May be a sublattice as well + N = fm.domain() # May be a sublattice as well m *= N.basis_matrix().solve_right(identity_matrix(N.dimension())) X._embedding_morphism = X.hom(m, self.domain()) return X, fm.index() @@ -1453,8 +1452,7 @@ def fiber_component(self, domain_cone, multiplicity=False): return self.fiber_generic()[0] embedding = SchemeMorphism_fan_fiber_component_toric_variety(self, domain_cone) if multiplicity: - return embedding.domain(), \ - self.fan_morphism().index(embedding.base_cone()) + return embedding.domain(), self.fan_morphism().index(embedding.base_cone()) return embedding.domain() @cached_method @@ -1511,8 +1509,7 @@ def fiber_dimension(self, codomain_cone): dim = [] fm = self.fan_morphism() base_dim = codomain_cone.dim() - dim.extend(base_dim - c.dim() - for c in fm.primitive_preimage_cones(codomain_cone)) + dim.extend(base_dim - c.dim() for c in fm.primitive_preimage_cones(codomain_cone)) if dim: return max(dim) + self.domain().dimension() - self.codomain().dimension() return ZZ(-1) @@ -1589,6 +1586,7 @@ def is_union_in_fan(self, c0, c1): for i in range(n): m[i, i] = 0 from sage.graphs.graph import Graph + graph = Graph(m, loops=False, multiedges=False) for i in range(n): graph.set_vertex(i, self.fiber_component(prim[i])) @@ -1816,6 +1814,7 @@ def projection(ray): self._ray_index_map = ray_index_map from sage.schemes.toric.variety import ToricVariety + return ToricVariety(fiber_fan) def defining_cone(self): @@ -1941,6 +1940,7 @@ def pullback_divisor(self, divisor): -V(z0) - 3*V(z1) - 3*V(z2) """ from sage.schemes.toric.divisor import ToricDivisor_generic + if not (isinstance(divisor, ToricDivisor_generic) and divisor.is_QQ_Cartier()): raise ValueError('the divisor must be torus-invariant and QQ-Cartier') m = divisor.m(self.defining_cone()) diff --git a/src/sage/schemes/toric/points.py b/src/sage/schemes/toric/points.py index ea2f09405a3..4dd42fd7c5d 100644 --- a/src/sage/schemes/toric/points.py +++ b/src/sage/schemes/toric/points.py @@ -216,8 +216,7 @@ def _Chow_group_free(self): result = [] ker = self.rays().matrix().integer_kernel().matrix() for phases in itertools.product(units, repeat=ker.nrows()): - phases = tuple(prod(mu**exponent for mu, exponent in zip(phases, column)) - for column in ker.columns()) + phases = tuple(prod(mu**exponent for mu, exponent in zip(phases, column)) for column in ker.columns()) result.append(phases) return tuple(sorted(result)) @@ -509,8 +508,7 @@ def _Chow_group_free_generators(self): result = [] null_space = self.rays().matrix().integer_kernel() for ker in null_space.basis(): - phases = tuple(self.multiplicative_generator()**exponent - for exponent in ker) + phases = tuple(self.multiplicative_generator() ** exponent for exponent in ker) result.append(phases) return tuple(sorted(result)) @@ -613,7 +611,7 @@ def exp(self, powers): True """ base = self.multiplicative_generator() - return tuple(base ** i for i in powers) + return tuple(base**i for i in powers) @cached_method def rescaling_log_generators(self): @@ -675,18 +673,16 @@ def cone_points_iter(self): """ from sage.matrix.constructor import matrix, block_matrix, identity_matrix from sage.rings.integer_ring import ZZ + nrays = len(self.rays()) N = self.multiplicative_group_order() # Want cokernel of the log rescalings in (ZZ/N)^(#rays). But # ZZ/N is not a integral domain. Instead: work over ZZ log_generators = self.rescaling_log_generators() - log_relations = block_matrix(2, 1, [ - matrix(ZZ, len(log_generators), nrays, log_generators), - N * identity_matrix(ZZ, nrays)]) + log_relations = block_matrix(2, 1, [matrix(ZZ, len(log_generators), nrays, log_generators), N * identity_matrix(ZZ, nrays)]) for cone in self.cone_iter(): nrays = self.fan().nrays() + len(self.fan().virtual_rays()) - nonzero_coordinates = [i for i in range(nrays) - if i not in cone.ambient_ray_indices()] + nonzero_coordinates = [i for i in range(nrays) if i not in cone.ambient_ray_indices()] log_relations_nonzero = log_relations.matrix_from_columns(nonzero_coordinates) image = log_relations_nonzero.image() cokernel = image.ambient_module().quotient(image) @@ -878,6 +874,7 @@ def solutions_serial(self, inhomogeneous_equations, log_range): [(0,), (3,)] """ from itertools import product + for log_t in product(*log_range): t = self.ambient.exp(log_t) if all(poly(t) == 0 for poly in inhomogeneous_equations): @@ -916,6 +913,7 @@ def solutions(self, inhomogeneous_equations, log_range): def partial_solution(work_range): return list(self.solutions_serial(inhomogeneous_equations, work_range)) + for partial_result in parallel(partial_solution)(work): for log_t in partial_result[-1]: yield log_t @@ -954,8 +952,7 @@ def homogeneous_coordinates(self, log_t, nonzero_coordinates, cokernel): (1, 2, 0) """ z = [self.ambient.ring.zero()] * len(self.ambient.rays()) - z_nonzero = self.ambient.exp( - cokernel.linear_combination_of_smith_form_gens(log_t).lift()) + z_nonzero = self.ambient.exp(cokernel.linear_combination_of_smith_form_gens(log_t).lift()) for i, value in enumerate(z_nonzero): z[nonzero_coordinates[i]] = value return tuple(z) @@ -987,8 +984,7 @@ def __iter__(self): inhomogeneous = self.inhomogeneous_equations(R, nonzero_coordinates, cokernel) log_range = [range(I) for I in cokernel.invariants()] for log_t in self.solutions(inhomogeneous, log_range): - yield self.homogeneous_coordinates(log_t, nonzero_coordinates, - cokernel) + yield self.homogeneous_coordinates(log_t, nonzero_coordinates, cokernel) def cardinality(self): """ diff --git a/src/sage/schemes/toric/sheaf/constructor.py b/src/sage/schemes/toric/sheaf/constructor.py index 925451654ad..da20082a7d7 100644 --- a/src/sage/schemes/toric/sheaf/constructor.py +++ b/src/sage/schemes/toric/sheaf/constructor.py @@ -40,10 +40,12 @@ def TangentBundle(X): fan = X.fan() filtrations = {} from sage.modules.filtered_vector_space import FilteredVectorSpace + for i, ray in enumerate(fan.rays()): F = FilteredVectorSpace(fan.rays(), {0: range(fan.nrays()), 1: [i]}) filtrations[ray] = F from . import klyachko + return klyachko.Bundle(X, filtrations, check=True) @@ -92,9 +94,9 @@ def TrivialBundle(X, rank=1): raise ValueError('not a toric variety') base_ring = X.base_ring() - filtrations = {ray: FilteredVectorSpace(rank, 0, base_ring=base_ring) - for ray in X.fan().rays()} + filtrations = {ray: FilteredVectorSpace(rank, 0, base_ring=base_ring) for ray in X.fan().rays()} from . import klyachko + return klyachko.Bundle(X, filtrations, check=True) @@ -125,10 +127,9 @@ def LineBundle(X, D): raise ValueError('not a toric variety') base_ring = X.base_ring() - filtrations = {X.fan().ray(i): FilteredVectorSpace(1, D.function_value(i), - base_ring=base_ring) - for i in range(X.fan().nrays())} + filtrations = {X.fan().ray(i): FilteredVectorSpace(1, D.function_value(i), base_ring=base_ring) for i in range(X.fan().nrays())} from . import klyachko + return klyachko.Bundle(X, filtrations, check=True) @@ -271,6 +272,7 @@ def Klyachko(self, multi_filtration): Rank 3 bundle on 1-d CPR-Fano toric variety covered by 2 affine patches. """ from .klyachko import Bundle + return Bundle(self._variety, multi_filtration, check=True) def divisor(self, *args, **kwds): diff --git a/src/sage/schemes/toric/sheaf/klyachko.py b/src/sage/schemes/toric/sheaf/klyachko.py index 2a18a4ae291..567e3c3deec 100644 --- a/src/sage/schemes/toric/sheaf/klyachko.py +++ b/src/sage/schemes/toric/sheaf/klyachko.py @@ -102,8 +102,7 @@ def Bundle(toric_variety, multi_filtration, check=True): base_ring = toric_variety.base_ring() if not hasattr(multi_filtration, 'get_filtration'): # try to construct a MultiFilteredVectorSpace - multi_filtration = MultiFilteredVectorSpace( - multi_filtration, base_ring=base_ring, check=check) + multi_filtration = MultiFilteredVectorSpace(multi_filtration, base_ring=base_ring, check=check) if multi_filtration.base_ring() != base_ring: multi_filtration = multi_filtration.change_ring(base_ring) return KlyachkoBundle_class(toric_variety, multi_filtration, check=check) @@ -151,9 +150,9 @@ def __init__(self, toric_variety, multi_filtration, check=True): if not check: return from sage.sets.set import Set + if multi_filtration.index_set() != Set(list(toric_variety.fan().rays())): - raise ValueError('the index set of the multi-filtration must be' - ' all rays of the fan.') + raise ValueError('the index set of the multi-filtration must be' ' all rays of the fan.') if not multi_filtration.is_exhaustive(): raise ValueError('multi-filtration must be exhaustive') if not multi_filtration.is_separating(): @@ -202,6 +201,7 @@ def fiber(self): Vector space of dimension 2 over Rational Field """ from sage.modules.free_module import VectorSpace + return VectorSpace(self.base_ring(), self.rank()) def rank(self): @@ -229,7 +229,7 @@ def _repr_(self): sage: toric_varieties.P2().sheaves.tangent_bundle() Rank 2 bundle on 2-d CPR-Fano toric variety covered by 3 affine patches. """ - s = 'Rank '+str(self.rank())+' bundle on '+str(self._variety)+'.' + s = 'Rank ' + str(self.rank()) + ' bundle on ' + str(self._variety) + '.' return s def get_filtration(self, ray=None): @@ -389,7 +389,7 @@ def E_degree(self, alpha, m): if cone.dim() != 1: raise ValueError('does not determine one-dimensional cone') ray = cone.ray(0) - return self.get_degree(ray, ray*m) + return self.get_degree(ray, ray * m) @cached_method def E_intersection(self, sigma, m): @@ -581,7 +581,7 @@ def cohomology_complex(self, m): C = fan.complex() CV = [] F = self.base_ring() - for dim in range(1, fan.dim()+1): + for dim in range(1, fan.dim() + 1): codim = fan.dim() - dim d_C = C.differential(codim) d_V = [] @@ -589,7 +589,7 @@ def cohomology_complex(self, m): tau = fan(dim)[j] d_V_row = [] for i in range(d_C.nrows()): - sigma = fan(dim-1)[i] + sigma = fan(dim - 1)[i] if sigma.is_face_of(tau): pr = self.E_quotient_projection(sigma, tau, m) d = d_C[i, j] * pr.matrix().transpose() @@ -602,6 +602,7 @@ def cohomology_complex(self, m): d_V = block_matrix(d_V, ring=F) CV.append(d_V) from sage.homology.chain_complex import ChainComplex + return ChainComplex(CV, base_ring=self.base_ring()) def cohomology(self, degree=None, weight=None, dim=False): @@ -654,6 +655,7 @@ def cohomology(self, degree=None, weight=None, dim=False): H^*i(P^2, TP^2)_M(1, 0) = (1, 0, 0) """ from sage.modules.free_module import FreeModule + if weight is None: raise NotImplementedError('sum over weights is not implemented') else: @@ -665,13 +667,13 @@ def cohomology(self, degree=None, weight=None, dim=False): space_dim = self._variety.dimension() C_homology = C.homology() HH = {} - for d in range(space_dim+1): + for d in range(space_dim + 1): try: HH[d] = C_homology[d] except KeyError: HH[d] = FreeModule(self.base_ring(), 0) if dim: - HH = vector(ZZ, [HH[i].rank() for i in range(space_dim+1)]) + HH = vector(ZZ, [HH[i].rank() for i in range(space_dim + 1)]) return HH def __richcmp__(self, other, op): diff --git a/src/sage/schemes/toric/toric_subscheme.py b/src/sage/schemes/toric/toric_subscheme.py index 533234c1532..e2487ec82ec 100644 --- a/src/sage/schemes/toric/toric_subscheme.py +++ b/src/sage/schemes/toric/toric_subscheme.py @@ -135,6 +135,7 @@ def _morphism(self, *args, **kwds): [t : t : x : y] """ from sage.schemes.toric.morphism import SchemeMorphism_polynomial_toric_variety + return SchemeMorphism_polynomial_toric_variety(*args, **kwds) def _point_homset(self, *args, **kwds): @@ -160,6 +161,7 @@ def _point_homset(self, *args, **kwds): """ from sage.schemes.toric.homset import SchemeHomset_points_subscheme_toric_field + return SchemeHomset_points_subscheme_toric_field(*args, **kwds) def fan(self): @@ -217,7 +219,7 @@ def affine_patch(self, i): Closed subscheme of 2-d affine toric variety defined by: x - 1 """ - i = int(i) # implicit type checking + i = int(i) # implicit type checking try: return self._affine_patches[i] except AttributeError: @@ -226,8 +228,7 @@ def affine_patch(self, i): pass ambient_patch = self.ambient_space().affine_patch(i) phi_p = ambient_patch.embedding_morphism().defining_polynomials() - patch = ambient_patch.subscheme( - [p(phi_p) for p in self.defining_polynomials()]) + patch = ambient_patch.subscheme([p(phi_p) for p in self.defining_polynomials()]) patch._embedding_morphism = patch.hom(phi_p, self, check=False) self._affine_patches[i] = patch return patch @@ -305,6 +306,7 @@ def affine_algebraic_patch(self, cone=None, names=None): """ from sage.modules.free_module_element import vector from sage.misc.misc_c import prod + ambient = self.ambient_space() fan = ambient.fan() if cone is None: @@ -316,9 +318,7 @@ def affine_algebraic_patch(self, cone=None, names=None): R, I, dualcone = ambient._semigroup_ring(cone, names) # inhomogenize the Cox homogeneous polynomial with respect to the given cone - inhomogenize = {ambient.coordinate_ring().gen(i): 1 - for i in range(fan.nrays()) - if i not in cone.ambient_ray_indices()} + inhomogenize = {ambient.coordinate_ring().gen(i): 1 for i in range(fan.nrays()) if i not in cone.ambient_ray_indices()} polynomials = [p.subs(inhomogenize) for p in self.defining_polynomials()] # map the monomial x^{D_m} to m, see reference. @@ -331,16 +331,15 @@ def pullback_polynomial(p): exponent = [exponent[i] for i in cone.ambient_ray_indices()] exponent = vector(ZZ, exponent) m = n_rho_matrix.solve_right(exponent) - assert all(x in ZZ for x in m), \ - f'The polynomial {p} does not define a ZZ-divisor!' + assert all(x in ZZ for x in m), f'The polynomial {p} does not define a ZZ-divisor!' m_coeffs = dualcone.Hilbert_coefficients(m) - result += coefficient * prod(R.gen(i)**m_coeffs[i] - for i in range(R.ngens())) + result += coefficient * prod(R.gen(i) ** m_coeffs[i] for i in range(R.ngens())) return result # construct the affine algebraic scheme to use as patch polynomials = [pullback_polynomial(_) for _ in polynomials] from sage.schemes.affine.affine_space import AffineSpace + patch_cover = AffineSpace(R) polynomials = list(I.gens()) + polynomials polynomials = [x for x in polynomials if not x.is_zero()] @@ -360,8 +359,7 @@ def pullback_polynomial(p): phi.append(1) patch._embedding_morphism = patch.hom(phi, self) else: - patch._embedding_morphism = (NotImplementedError, - 'I only know how to construct embedding morphisms for smooth patches') + patch._embedding_morphism = (NotImplementedError, 'I only know how to construct embedding morphisms for smooth patches') try: point = self.embedding_center() @@ -371,9 +369,7 @@ def pullback_polynomial(p): # it remains to find the preimage of point # map m to the monomial x^{D_m}, see reference. F = ambient.coordinate_ring().fraction_field() - image = [prod([F.gen(i)**(m * n) - for i, n in enumerate(fan.rays())]) - for m in dualcone.Hilbert_basis()] + image = [prod([F.gen(i) ** (m * n) for i, n in enumerate(fan.rays())]) for m in dualcone.Hilbert_basis()] patch._embedding_center = tuple(f(list(point)) for f in image) return patch @@ -581,8 +577,7 @@ def is_smooth(self, point=None) -> bool: if '_smooth' in self.__dict__: return self._smooth npatches = self.ambient_space().fan().ngenerating_cones() - self._smooth = all(self.affine_patch(i).is_smooth() - for i in range(npatches)) + self._smooth = all(self.affine_patch(i).is_smooth() for i in range(npatches)) return self._smooth def is_nondegenerate(self) -> bool: @@ -670,26 +665,25 @@ def is_nondegenerate(self) -> bool: fan = X.fan() SR = X.Stanley_Reisner_ideal() from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(X.base_ring(), fan.nrays() + SR.ngens(), 't') - slack = R.gens()[fan.nrays():] + slack = R.gens()[fan.nrays() :] SR = SR.change_ring(R) def restrict(cone): patch = {} divide = {} for i in cone.ambient_ray_indices(): - patch[R.gen(i)] = R.zero() # restrict to torus orbit + patch[R.gen(i)] = R.zero() # restrict to torus orbit # divide out highest power of R.gen(i) divide[R.gen(i)] = R.one() ideal = self.defining_ideal().change_ring(R) ideal = ideal.subs(patch) - mat = jacobian(ideal.gens(), R.gens()[:fan.nrays()]) + mat = jacobian(ideal.gens(), R.gens()[: fan.nrays()]) minors = mat.minors(self.codimension()) minors = tuple([ideal.reduce(m) for m in minors]) Jac_patch = R.ideal(ideal.gens() + minors) - SR_patch = R.ideal([monomial * slack[i] - R.one() - for i, monomial in - enumerate(SR.subs(divide).gens())]) + SR_patch = R.ideal([monomial * slack[i] - R.one() for i, monomial in enumerate(SR.subs(divide).gens())]) return ideal, Jac_patch + SR_patch for dim in range(fan.dim() + 1): @@ -896,7 +890,7 @@ def is_smooth(self, point=None) -> bool: if self.ambient_space().is_smooth(): sing_dim = self.Jacobian().dimension() - self._smooth = (sing_dim == -1) + self._smooth = sing_dim == -1 else: self._smooth = self.affine_algebraic_patch().is_smooth() diff --git a/src/sage/schemes/toric/variety.py b/src/sage/schemes/toric/variety.py index ff1ef3bdb90..446cef03d8c 100644 --- a/src/sage/schemes/toric/variety.py +++ b/src/sage/schemes/toric/variety.py @@ -336,11 +336,7 @@ DEFAULT_PREFIX = "z" -def ToricVariety(fan, - coordinate_names=None, - names=None, - coordinate_indices=None, - base_ring=QQ, base_field=None): +def ToricVariety(fan, coordinate_names=None, names=None, coordinate_indices=None, base_ring=QQ, base_field=None): r""" Construct a toric variety. @@ -424,10 +420,8 @@ def ToricVariety(fan, raise ValueError('you must not specify both coordinate_names and names') coordinate_names = names if base_ring not in _Fields: - raise TypeError("need a field to construct a toric variety; got %s" - % base_ring) - return ToricVariety_field(fan, coordinate_names, coordinate_indices, - base_ring) + raise TypeError("need a field to construct a toric variety; got %s" % base_ring) + return ToricVariety_field(fan, coordinate_names, coordinate_indices, base_ring) def AffineToricVariety(cone, *args, **kwds): @@ -466,12 +460,10 @@ def AffineToricVariety(cone, *args, **kwds): are all zero. """ if not cone.is_strictly_convex(): - raise ValueError("affine toric varieties are defined for strictly " - "convex cones only") + raise ValueError("affine toric varieties are defined for strictly " "convex cones only") # We make sure that Fan constructor does not meddle with the order of # rays, this is very important for affine patches construction - fan = Fan([tuple(range(cone.nrays()))], cone.rays(), - check=False, normalize=False) + fan = Fan([tuple(range(cone.nrays()))], cone.rays(), check=False, normalize=False) return ToricVariety(fan, *args, **kwds) @@ -520,9 +512,7 @@ def __init__(self, fan, coordinate_names, coordinate_indices, base_field): self._fan = fan super().__init__(fan.lattice_dim(), base_field) self._torus_factor_dim = fan.lattice_dim() - fan.dim() - coordinate_names = normalize_names(coordinate_names, - fan.nrays() + self._torus_factor_dim, DEFAULT_PREFIX, - coordinate_indices, return_prefix=True) + coordinate_names = normalize_names(coordinate_names, fan.nrays() + self._torus_factor_dim, DEFAULT_PREFIX, coordinate_indices, return_prefix=True) # Save the prefix for use in resolutions self._coordinate_prefix = coordinate_names.pop() self._assign_names(names=coordinate_names, normalize=False) @@ -559,9 +549,7 @@ def __eq__(self, right): """ if not isinstance(right, ToricVariety_field): return False - return (self.fan() == right.fan() and - self.variable_names() == right.variable_names() and - self.base_ring() == right.base_ring()) + return self.fan() == right.fan() and self.variable_names() == right.variable_names() and self.base_ring() == right.base_ring() def __ne__(self, other): """ @@ -668,26 +656,20 @@ def _check_satisfies_equations(self, coordinates): try: coordinates = tuple(coordinates) except TypeError: - raise TypeError("%s cannot be used as coordinates; " - "use a list or a tuple" % coordinates) + raise TypeError("%s cannot be used as coordinates; " "use a list or a tuple" % coordinates) n = self.ngens() if len(coordinates) != n: - raise TypeError("coordinates %s must have %d components" - % (coordinates, n)) + raise TypeError("coordinates %s must have %d components" % (coordinates, n)) base_field = self.base_ring() for coordinate in coordinates: if coordinate not in base_field: - raise TypeError("coordinate %s is not an element of %s" - % (coordinate, base_field)) - zero_positions = {position - for position, coordinate in enumerate(coordinates) - if coordinate == 0} + raise TypeError("coordinate %s is not an element of %s" % (coordinate, base_field)) + zero_positions = {position for position, coordinate in enumerate(coordinates) if coordinate == 0} if not zero_positions: return True for i in range(n - self._torus_factor_dim, n): if i in zero_positions: - raise ValueError("coordinates on the torus factor cannot be " - "zero; got %s" % str(coordinates)) + raise ValueError("coordinates on the torus factor cannot be " "zero; got %s" % str(coordinates)) if len(zero_positions) == 1: return True fan = self.fan() @@ -695,7 +677,7 @@ def _check_satisfies_equations(self, coordinates): for i in zero_positions: possible_charts.intersection_update(fan._ray_to_cones(i)) if possible_charts: - return True # All zeros are inside one generating cone + return True # All zeros are inside one generating cone raise TypeError(f"coordinates {coordinates} are in the exceptional set") def _point_homset(self, *args, **kwds): @@ -756,8 +738,7 @@ def _latex_generic_point(self, coordinates=None): """ if coordinates is None: coordinates = self.gens() - return r"\left[%s\right]" % (" : ".join(str(latex(coord)) - for coord in coordinates)) + return r"\left[%s\right]" % (" : ".join(str(latex(coord)) for coord in coordinates)) def _point(self, *args, **kwds): r""" @@ -777,6 +758,7 @@ def _point(self, *args, **kwds): [1 : 2 : 3 : 4] """ from sage.schemes.toric.morphism import SchemeMorphism_point_toric_field + return SchemeMorphism_point_toric_field(*args, **kwds) def _homset(self, *args, **kwds): @@ -825,6 +807,7 @@ def _homset(self, *args, **kwds): [t : t : x : y] """ from sage.schemes.toric.homset import SchemeHomset_toric_variety + return SchemeHomset_toric_variety(*args, **kwds) def _repr_(self): @@ -843,8 +826,7 @@ def _repr_(self): if self.fan().ngenerating_cones() == 1: result += " affine toric variety" else: - result += (" toric variety covered by %d affine patches" - % self.fan().ngenerating_cones()) + result += " toric variety covered by %d affine patches" % self.fan().ngenerating_cones() return result def _repr_generic_point(self, coordinates=None): @@ -949,7 +931,7 @@ def affine_patch(self, i): sage: patch1 is P1xP1.affine_patch(1) True """ - i = int(i) # implicit type checking + i = int(i) # implicit type checking try: return self._affine_patches[i] except AttributeError: @@ -962,8 +944,7 @@ def affine_patch(self, i): n = self.fan().nrays() # Number of "torus factor coordinates" t = self._torus_factor_dim - names = ([names[ray] for ray in cone.ambient_ray_indices()] - + list(names[n:])) + names = [names[ray] for ray in cone.ambient_ray_indices()] + list(names[n:]) patch = AffineToricVariety(cone, names, base_field=self.base_ring()) embedding_coordinates = [1] * n for k, ray in enumerate(cone.ambient_ray_indices()): @@ -1016,11 +997,9 @@ def change_ring(self, F): if self.base_ring() == F: return self if F not in _Fields: - raise TypeError("need a field to construct a toric variety; got %s" - % F) + raise TypeError("need a field to construct a toric variety; got %s" % F) else: - return ToricVariety(self.fan(), self.variable_names(), - base_field=F) + return ToricVariety(self.fan(), self.variable_names(), base_field=F) def coordinate_ring(self): r""" @@ -1083,8 +1062,7 @@ def embedding_morphism(self): try: return self._embedding_morphism except AttributeError: - raise ValueError("no default embedding was defined for this " - "toric variety") + raise ValueError("no default embedding was defined for this " "toric variety") def fan(self, dim=None, codim=None): r""" @@ -1154,8 +1132,7 @@ def inject_coefficients(self, scope=None, verbose=True): depth = 0 while True: scope = sys._getframe(depth).f_globals - if (scope["__name__"] == "__main__" - and scope.get("__package__", None) is None): + if scope["__name__"] == "__main__" and scope.get("__package__", None) is None: break depth += 1 try: @@ -1246,9 +1223,9 @@ def is_homogeneous(self, polynomial) -> bool: if '_homogeneous_degrees_group' not in self.__dict__: fan = self.fan() from sage.modules.free_module import FreeModule + rays = fan.rays() + fan.virtual_rays() - degrees_group = FreeModule(ZZ, len(rays)).quotient( - rays.matrix().columns()) + degrees_group = FreeModule(ZZ, len(rays)).quotient(rays.matrix().columns()) self._homogeneous_degrees_group = degrees_group degrees_group = self._homogeneous_degrees_group S = self.coordinate_ring() @@ -1296,9 +1273,7 @@ def is_isomorphic(self, another) -> bool: if self is another: return True if not isinstance(another, ToricVariety_field): - raise TypeError( - "only another toric variety can be checked for isomorphism; " - "got %s" % another) + raise TypeError("only another toric variety can be checked for isomorphism; " "got %s" % another) raise NotImplementedError("isomorphism check is not yet implemented") def is_affine(self) -> bool: @@ -1414,16 +1389,13 @@ def Kaehler_cone(self): """ fan = self.fan() GT = fan.Gale_transform().columns() - from sage.schemes.toric.divisor import \ - ToricRationalDivisorClassGroup_basis_lattice - L = ToricRationalDivisorClassGroup_basis_lattice( - self.rational_class_group()) + from sage.schemes.toric.divisor import ToricRationalDivisorClassGroup_basis_lattice + + L = ToricRationalDivisorClassGroup_basis_lattice(self.rational_class_group()) n = fan.nrays() K = None for cone in fan: - sigma = Cone([GT[i] for i in range(n) - if i not in cone.ambient_ray_indices()], - lattice=L) + sigma = Cone([GT[i] for i in range(n) if i not in cone.ambient_ray_indices()], lattice=L) K = K.intersection(sigma) if K is not None else sigma return K @@ -1466,9 +1438,8 @@ def Mori_cone(self): """ # Ideally, self.Kaehler_cone().dual() should be it, but # so far this is not the case. - rays = (ray * self._fan.Gale_transform() - for ray in self.Kaehler_cone().dual().rays()) - return Cone(rays, lattice=ZZ**(self._fan.nrays() + 1)) + rays = (ray * self._fan.Gale_transform() for ray in self.Kaehler_cone().dual().rays()) + return Cone(rays, lattice=ZZ ** (self._fan.nrays() + 1)) def plot(self, **options): r""" @@ -1536,6 +1507,7 @@ def rational_class_group(self): of a 2-d toric variety covered by 2 affine patches """ from sage.schemes.toric.divisor import ToricRationalDivisorClassGroup + return ToricRationalDivisorClassGroup(self) def Chow_group(self, base_ring=ZZ): @@ -1557,10 +1529,10 @@ def Chow_group(self, base_ring=ZZ): (( 0 | 0 | 1 ), ( 0 | 1 | 0 ), ( 1 | 0 | 0 )) """ from sage.schemes.toric.chow_group import ChowGroup + return ChowGroup(self, base_ring) - def cartesian_product(self, other, - coordinate_names=None, coordinate_indices=None): + def cartesian_product(self, other, coordinate_names=None, coordinate_indices=None): r""" Return the Cartesian product of ``self`` with ``other``. @@ -1588,9 +1560,7 @@ def cartesian_product(self, other, N+N( 0, -1), N+N( 0, 1) in 2-d lattice N+N """ - return ToricVariety(self.fan().cartesian_product(other.fan()), - coordinate_names, coordinate_indices, - base_field=self.base_ring()) + return ToricVariety(self.fan().cartesian_product(other.fan()), coordinate_names, coordinate_indices, base_field=self.base_ring()) def resolve(self, **kwds): r""" @@ -1681,8 +1651,7 @@ def resolve(self, **kwds): coordinate_indices = kwds.pop("coordinate_indices", None) fan = self.fan() if fan.dim() != fan.lattice_dim(): - raise NotImplementedError("resolution of toric varieties with " - "torus factors is not yet implemented") + raise NotImplementedError("resolution of toric varieties with " "torus factors is not yet implemented") # When it is implemented, should be careful with the torus factor rfan = fan.subdivide(**kwds) if coordinate_names is None: @@ -1690,18 +1659,13 @@ def resolve(self, **kwds): if coordinate_indices is None: coordinate_indices = list(range(fan.nrays(), rfan.nrays())) else: - coordinate_indices = coordinate_indices[fan.nrays():] - coordinate_names.extend(normalize_names( - ngens=rfan.nrays() - fan.nrays(), - indices=coordinate_indices, - prefix=self._coordinate_prefix)) + coordinate_indices = coordinate_indices[fan.nrays() :] + coordinate_names.extend(normalize_names(ngens=rfan.nrays() - fan.nrays(), indices=coordinate_indices, prefix=self._coordinate_prefix)) coordinate_names.append(self._coordinate_prefix + "+") - resolution = ToricVariety(rfan, coordinate_names=coordinate_names, - coordinate_indices=coordinate_indices, - base_field=self.base_ring()) + resolution = ToricVariety(rfan, coordinate_names=coordinate_names, coordinate_indices=coordinate_indices, base_field=self.base_ring()) R = self.coordinate_ring() R_res = resolution.coordinate_ring() - resolution_map = resolution.hom(R.hom(R_res.gens()[:R.ngens()]), self) + resolution_map = resolution.hom(R.hom(R_res.gens()[: R.ngens()]), self) resolution._resolution_map = resolution_map # The above map does not have (yet) public methods to access it. # While this map is defined correctly, base classes of schemes and @@ -1783,8 +1747,8 @@ def subscheme(self, polynomials): To: Spectrum of Rational Field Defn: Structure map """ - from sage.schemes.toric.toric_subscheme import\ - AlgebraicScheme_subscheme_toric, AlgebraicScheme_subscheme_affine_toric + from sage.schemes.toric.toric_subscheme import AlgebraicScheme_subscheme_toric, AlgebraicScheme_subscheme_affine_toric + if self.is_affine(): return AlgebraicScheme_subscheme_affine_toric(self, polynomials) return AlgebraicScheme_subscheme_toric(self, polynomials) @@ -1890,8 +1854,7 @@ def cohomology_ring(self): True """ if self.base_ring().characteristic() > 0: - raise NotImplementedError('only characteristic 0 base fields ' - 'are implemented') + raise NotImplementedError('only characteristic 0 base fields ' 'are implemented') return CohomologyRing(self) @cached_method @@ -1933,8 +1896,7 @@ def cohomology_basis(self, d=None): basis[x.total_degree()].append(x) # Convert list of lists of polynomials to # tuple of tuples of cohomology classes - return tuple(tuple(H(x) for x in dbasis) - for dbasis in basis) + return tuple(tuple(H(x) for x in dbasis) for dbasis in basis) @cached_method def volume_class(self): @@ -2002,8 +1964,7 @@ def volume_class(self): 1/2 """ if not self.is_orbifold(): - raise NotImplementedError('cohomology computations are only ' - 'implemented for orbifolds') + raise NotImplementedError('cohomology computations are only ' 'implemented for orbifolds') HH = self.cohomology_ring() dim = self.dimension_relative() dVol = HH(self.fan().generating_cone(0)).part_of_degree(dim) @@ -2090,6 +2051,7 @@ def sheaves(self): Rank 1 bundle on 2-d CPR-Fano toric variety covered by 6 affine patches. """ from sage.schemes.toric.sheaf.constructor import SheafLibrary + return SheafLibrary(self) @cached_method @@ -2127,8 +2089,7 @@ def Chern_class(self, deg=None): True """ assert self.is_orbifold(), "Requires the toric variety to be an orbifold." - c = prod([1 + self.cohomology_ring().gen(i) - for i in range(self._fan.nrays())]) + c = prod([1 + self.cohomology_ring().gen(i) for i in range(self._fan.nrays())]) return c if deg is None else c.part_of_degree(deg) @cached_method @@ -2166,8 +2127,7 @@ def Chern_character(self, deg=None): """ assert self.is_orbifold(), "Requires the toric variety to be an orbifold." n_rels = self._fan.nrays() - self.dimension() - ch = sum([self.cohomology_ring().gen(i).exp() - for i in range(self._fan.nrays())]) - n_rels + ch = sum([self.cohomology_ring().gen(i).exp() for i in range(self._fan.nrays())]) - n_rels return ch if deg is None else ch.part_of_degree(deg) @cached_method @@ -2214,7 +2174,7 @@ def Todd_class(self, deg=None): if dim >= 4: c3 = self.Chern_class(3) c4 = self.Chern_class(4) - Td += -QQ.one() / 720 * (c1**4 - 4*c1**2*c2 - 3*c2**2 - c1*c3 + c4) + Td += -QQ.one() / 720 * (c1**4 - 4 * c1**2 * c2 - 3 * c2**2 - c1 * c3 + c4) if dim >= 5: raise NotImplementedError('Todd class is currently only implemented up to degree 4') return Td if deg is None else Td.part_of_degree(deg) @@ -2251,7 +2211,7 @@ def Euler_number(self): chi = 0 H = self.cohomology_basis() for d in range(self.dimension() + 1): - chi += (-1)**d * len(H[d]) + chi += (-1) ** d * len(H[d]) self._chi = chi return self._chi @@ -2273,6 +2233,7 @@ def K(self): 6 """ from sage.schemes.toric.divisor import ToricDivisor + return ToricDivisor(self, [-1] * self._fan.nrays()) def divisor(self, arg, base_ring=None, check=True, reduce=True): @@ -2327,8 +2288,8 @@ def divisor(self, arg, base_ring=None, check=True, reduce=True): check = True # 1 must be coerced into the coefficient ring reduce = False from sage.schemes.toric.divisor import ToricDivisor - return ToricDivisor(self, ring=base_ring, arg=arg, - check=check, reduce=reduce) + + return ToricDivisor(self, ring=base_ring, arg=arg, check=check, reduce=reduce) def divisor_group(self, base_ring=ZZ): r""" @@ -2365,6 +2326,7 @@ def divisor_group(self, base_ring=ZZ): V(x) """ from sage.schemes.generic.divisor_group import DivisorGroup + return DivisorGroup(self, base_ring) def toric_divisor_group(self, base_ring=ZZ): @@ -2400,6 +2362,7 @@ def toric_divisor_group(self, base_ring=ZZ): Multivariate Polynomial Ring in x, u, y, v, z, w over Rational Field """ from sage.schemes.toric.divisor import ToricDivisorGroup + return ToricDivisorGroup(self, base_ring) def _semigroup_ring(self, cone=None, names=None): @@ -2443,9 +2406,9 @@ def _semigroup_ring(self, cone=None, names=None): 2-d cone in 2-d lattice M) """ from sage.schemes.toric.ideal import ToricIdeal + if cone is None: - assert self.is_affine(), \ - 'You may only omit the cone argument for an affine toric variety!' + assert self.is_affine(), 'You may only omit the cone argument for an affine toric variety!' cone = self.fan().generating_cone(0) cone = self.fan().embed(cone) @@ -2510,6 +2473,7 @@ def Spec(self, cone=None, names=None): in u, v, t over Rational Field by the ideal (-u*v + t^2) """ from sage.schemes.generic.spec import Spec + R, I, dualcone = self._semigroup_ring(cone, names) return Spec(R.quotient(I)) @@ -2658,9 +2622,9 @@ def orbit_closure(self, cone): 0-d affine toric variety """ from sage.geometry.fan import discard_faces + cone = self.fan().embed(cone) - cones = [self._orbit_closure_projection(cone, star_cone) - for star_cone in cone.star_generators()] + cones = [self._orbit_closure_projection(cone, star_cone) for star_cone in cone.star_generators()] fan = Fan(discard_faces(cones), check=False) orbit_closure = ToricVariety(fan) @@ -2669,8 +2633,8 @@ def orbit_closure(self, cone): star_rays.update(star_cone.rays()) ray_map = {ray: self._orbit_closure_projection(cone, ray) for ray in star_rays} from sage.schemes.toric.morphism import SchemeMorphism_orbit_closure_toric_variety - orbit_closure._embedding_morphism = \ - SchemeMorphism_orbit_closure_toric_variety(orbit_closure.Hom(self), cone, ray_map) + + orbit_closure._embedding_morphism = SchemeMorphism_orbit_closure_toric_variety(orbit_closure.Hom(self), cone, ray_map) return orbit_closure @@ -2739,12 +2703,10 @@ def Demazure_roots(self): NotImplementedError: Demazure_roots is only implemented for complete toric varieties """ if not self.is_complete(): - raise NotImplementedError('Demazure_roots is only implemented ' - 'for complete toric varieties') + raise NotImplementedError('Demazure_roots is only implemented ' 'for complete toric varieties') antiK = -self.K() fan_rays = self.fan().rays() - roots = [m for m in antiK.sections() - if [ray * m for ray in fan_rays].count(-1) == 1] + roots = [m for m in antiK.sections() if [ray * m for ray in fan_rays].count(-1) == 1] return tuple(roots) def Aut_dimension(self): @@ -2781,13 +2743,11 @@ def Aut_dimension(self): NotImplementedError: Aut_dimension is only implemented for complete toric varieties """ if not self.is_complete(): - raise NotImplementedError('Aut_dimension is only implemented ' - 'for complete toric varieties') + raise NotImplementedError('Aut_dimension is only implemented ' 'for complete toric varieties') return self.fan().lattice_dim() + len(self.Demazure_roots()) -def normalize_names(names=None, ngens=None, prefix=None, indices=None, - return_prefix=False): +def normalize_names(names=None, ngens=None, prefix=None, indices=None, return_prefix=False): r""" Return a list of names in the standard form. @@ -2916,26 +2876,22 @@ def normalize_names(names=None, ngens=None, prefix=None, indices=None, try: names = list(names) except TypeError: - raise TypeError( - "names must be a string or a list or tuple of them") + raise TypeError("names must be a string or a list or tuple of them") for name in names: if not isinstance(name, str): - raise TypeError( - "names must be a string or a list or tuple of them") + raise TypeError("names must be a string or a list or tuple of them") if names and names[-1].endswith("+"): prefix = names.pop()[:-1] if ngens is None: ngens = len(names) if len(names) < ngens: if prefix is None: - raise IndexError("need %d names but only %d are given" - % (ngens, len(names))) + raise IndexError("need %d names but only %d are given" % (ngens, len(names))) if indices is None: indices = list(range(ngens)) elif len(indices) != ngens: - raise ValueError("need exactly %d indices, but got %d" - % (ngens, len(indices))) - names += [prefix + str(i) for i in indices[len(names):]] + raise ValueError("need exactly %d indices, but got %d" % (ngens, len(indices))) + names += [prefix + str(i) for i in indices[len(names) :]] if len(names) > ngens: names = names[:ngens] # Check that all given and constructed names are valid @@ -3138,8 +3094,7 @@ def _element_constructor_(self, x): cone = fan.embed(x) assert cone.ambient() is fan mult = cone.rays().column_matrix().index_in_saturation() - x = prod((self.cover_ring().gen(i) for i in cone.ambient_ray_indices()), - z=self.cover_ring().one()) * mult + x = prod((self.cover_ring().gen(i) for i in cone.ambient_ray_indices()), z=self.cover_ring().one()) * mult else: try: # divisor, for example, know how to compute their own cohomology class @@ -3187,8 +3142,7 @@ def gens(self) -> tuple: ([z], [z], [z]) """ if "_gens" not in self.__dict__: - self._gens = tuple(self.gen(i) - for i in range(self._variety.fan().nrays())) + self._gens = tuple(self.gen(i) for i in range(self._variety.fan().nrays())) return self._gens def gen(self, i): @@ -3259,8 +3213,7 @@ def __init__(self, cohomology_ring, representative): sage: CohomologyClass(H, H.defining_ideal().ring().zero() ) # needs sage.libs.singular [0] """ - assert representative in cohomology_ring.defining_ideal().ring(), \ - 'The given representative is not in the parent polynomial ring.' + assert representative in cohomology_ring.defining_ideal().ring(), 'The given representative is not in the parent polynomial ring.' super().__init__(cohomology_ring, representative) def _repr_(self): diff --git a/src/sage/schemes/toric/weierstrass.py b/src/sage/schemes/toric/weierstrass.py index 8e0feb88c2c..a2bffd9e8ae 100644 --- a/src/sage/schemes/toric/weierstrass.py +++ b/src/sage/schemes/toric/weierstrass.py @@ -177,7 +177,7 @@ def Discriminant(polynomial, variables=None): -1/16 """ f, g = WeierstrassForm(polynomial, variables) - return 4*f**3 + 27*g**2 + return 4 * f**3 + 27 * g**2 ###################################################################### @@ -221,7 +221,7 @@ def j_invariant(polynomial, variables=None): ValueError: curve is singular and has no well-defined j-invariant """ f, g = WeierstrassForm(polynomial, variables) - disc = 4*f**3 + 27*g**2 + disc = 4 * f**3 + 27 * g**2 if disc != 0: return 1728 * 4 * f**3 / disc if f != 0: @@ -286,7 +286,7 @@ def Newton_polytope_vars_coeffs(polynomial, variables): e = m.exponents()[0] v = tuple([e[i] for i in var_indices]) m_red = m // prod(x**i for x, i in zip(variables, v)) - result[v] = result.get(v, R.zero()) + c*m_red + result[v] = result.get(v, R.zero()) + c * m_red return result @@ -343,7 +343,7 @@ def Newton_polygon_embedded(polynomial, variables): embedded_polynomial = polynomial.parent().zero() for e, c in p_dict.items(): e_embed = embedding[e] - embedded_polynomial += c * x**(e_embed[0]) * y**(e_embed[1]) + embedded_polynomial += c * x ** (e_embed[0]) * y ** (e_embed[1]) return newton_polytope, embedded_polynomial, (x, y) @@ -478,16 +478,17 @@ def WeierstrassForm(polynomial, variables=None, transformation=False): """ if isinstance(polynomial, (list, tuple)): from sage.schemes.toric.weierstrass_higher import WeierstrassForm2 + return WeierstrassForm2(polynomial, variables=variables, transformation=transformation) if transformation: from sage.schemes.toric.weierstrass_covering import WeierstrassMap + return WeierstrassMap(polynomial, variables=variables) if variables is None: variables = polynomial.variables() - from sage.geometry.polyhedron.ppl_lattice_polygon import ( - polar_P2_polytope, polar_P1xP1_polytope, polar_P2_112_polytope) - newton_polytope, polynomial, variables = \ - Newton_polygon_embedded(polynomial, variables) + from sage.geometry.polyhedron.ppl_lattice_polygon import polar_P2_polytope, polar_P1xP1_polytope, polar_P2_112_polytope + + newton_polytope, polynomial, variables = Newton_polygon_embedded(polynomial, variables) polygon = newton_polytope.embed_in_reflexive_polytope('polytope') if polygon is polar_P2_polytope(): return WeierstrassForm_P2(polynomial, variables) @@ -596,10 +597,11 @@ def index(monomial): return tuple(0 for i in indices) e = monomial.exponents()[0] return tuple(e[i] for i in indices) + coeffs = {} for c, m in polynomial: i = index(m) - coeffs[i] = c*m + coeffs.pop(i, R.zero()) + coeffs[i] = c * m + coeffs.pop(i, R.zero()) result = tuple(coeffs.pop(index(m), R.zero()) // m for m in monomials) if coeffs: msg = f'the polynomial contains more monomials than given: {coeffs}' @@ -854,7 +856,7 @@ def _partial_discriminant(quadric, y0, y1=None): monomials = (y1**2, y0 * y1, y0**2) variables = [y0, y1] c = _extract_coefficients(quadric, monomials, variables) - return c[1]**2 - 4*c[0]*c[2] + return c[1] ** 2 - 4 * c[0] * c[2] ###################################################################### diff --git a/src/sage/schemes/toric/weierstrass_covering.py b/src/sage/schemes/toric/weierstrass_covering.py index 82c300c1f7a..1ec22ccc1e6 100644 --- a/src/sage/schemes/toric/weierstrass_covering.py +++ b/src/sage/schemes/toric/weierstrass_covering.py @@ -118,6 +118,7 @@ ###################################################################### + def WeierstrassMap(polynomial, variables=None): r""" Return the Weierstrass form of an anticanonical hypersurface. @@ -226,11 +227,10 @@ def WeierstrassMap(polynomial, variables=None): if variables is None: variables = polynomial.variables() # switch to suitable inhomogeneous coordinates - from sage.geometry.polyhedron.ppl_lattice_polygon import ( - polar_P2_polytope, polar_P1xP1_polytope, polar_P2_112_polytope) + from sage.geometry.polyhedron.ppl_lattice_polygon import polar_P2_polytope, polar_P1xP1_polytope, polar_P2_112_polytope from sage.schemes.toric.weierstrass import Newton_polygon_embedded - newton_polytope, polynomial_aff, variables_aff = \ - Newton_polygon_embedded(polynomial, variables) + + newton_polytope, polynomial_aff, variables_aff = Newton_polygon_embedded(polynomial, variables) polygon = newton_polytope.embed_in_reflexive_polytope('polytope') # Compute the map in inhomogeneous coordinates if polygon is polar_P2_polytope(): @@ -255,6 +255,7 @@ def homogenize(inhomog, degree): result = vector(ZZ, result) result.set_immutable() return result + X_dict = {homogenize(e, 2): v for e, v in X.monomial_coefficients().items()} Y_dict = {homogenize(e, 3): v for e, v in Y.monomial_coefficients().items()} Z_dict = {homogenize(e, 1): v for e, v in Z.monomial_coefficients().items()} @@ -279,6 +280,7 @@ def homogenize(inhomog, degree): # ###################################################################### + def WeierstrassMap_P2(polynomial, variables=None): r""" Map a cubic to its Weierstrass form. @@ -332,6 +334,7 @@ def WeierstrassMap_P2(polynomial, variables=None): # ###################################################################### + def WeierstrassMap_P1xP1(polynomial, variables=None): r""" Map an anticanonical hypersurface in @@ -376,7 +379,7 @@ def WeierstrassMap_P1xP1(polynomial, variables=None): x, y, s, t = _check_polynomial_P1xP1(polynomial, variables) a00 = polynomial.coefficient({s: 2}) V = polynomial.coefficient({s: 1}) - U = - _partial_discriminant(polynomial, s, t) / 4 + U = -_partial_discriminant(polynomial, s, t) / 4 Q = invariant_theory.binary_quartic(U, x, y) g = Q.g_covariant() h = Q.h_covariant() @@ -391,6 +394,7 @@ def WeierstrassMap_P1xP1(polynomial, variables=None): # ###################################################################### + def WeierstrassMap_P2_112(polynomial, variables=None): r""" Map an anticanonical hypersurface in `\mathbb{P}^2[1,1,2]` into Weierstrass form. @@ -447,7 +451,7 @@ def WeierstrassMap_P2_112(polynomial, variables=None): x, y, z, t = _check_polynomial_P2_112(polynomial, variables) a00 = polynomial.coefficient({y: 2}) V = polynomial.coefficient({y: 1}) - U = - _partial_discriminant(polynomial, y, t) / 4 + U = -_partial_discriminant(polynomial, y, t) / 4 Q = invariant_theory.binary_quartic(U, x, z) g = Q.g_covariant() h = Q.h_covariant() diff --git a/src/sage/schemes/toric/weierstrass_higher.py b/src/sage/schemes/toric/weierstrass_higher.py index bf83e3673ed..d201c301e4b 100644 --- a/src/sage/schemes/toric/weierstrass_higher.py +++ b/src/sage/schemes/toric/weierstrass_higher.py @@ -176,11 +176,7 @@ def _biquadratic_syzygy_quartic(quadratic1, quadratic2, variables=None): # Syzygy is J^2 = syz_rhs + (terms that vanish on the biquadratic) with # J = biquadratic.J_covariant() - syz_rhs = T**4 * biquadratic.Delta_invariant().subs(to_aux) \ - - T**3 * T_prime * biquadratic.Theta_invariant().subs(to_aux) \ - + T**2 * T_prime**2 * biquadratic.Phi_invariant().subs(to_aux) \ - - T * T_prime**3 * biquadratic.Theta_prime_invariant().subs(to_aux) \ - + T_prime**4 * biquadratic.Delta_prime_invariant().subs(to_aux) + syz_rhs = T**4 * biquadratic.Delta_invariant().subs(to_aux) - T**3 * T_prime * biquadratic.Theta_invariant().subs(to_aux) + T**2 * T_prime**2 * biquadratic.Phi_invariant().subs(to_aux) - T * T_prime**3 * biquadratic.Theta_prime_invariant().subs(to_aux) + T_prime**4 * biquadratic.Delta_prime_invariant().subs(to_aux) quartic = invariant_theory.binary_quartic(syz_rhs, [T, T_prime]) return (biquadratic, quartic, from_aux) @@ -216,8 +212,7 @@ def WeierstrassForm_P3(quadratic1, quadratic2, variables=None): sage: b.total_degree(), len(b.coefficients()) (6, 648) """ - biquadratic, quartic, from_aux = \ - _biquadratic_syzygy_quartic(quadratic1, quadratic2, variables=variables) + biquadratic, quartic, from_aux = _biquadratic_syzygy_quartic(quadratic1, quadratic2, variables=variables) a = quartic.EisensteinD().subs(from_aux) b = quartic.EisensteinE().subs(from_aux) return (-4 * a, 16 * b) @@ -278,8 +273,7 @@ def WeierstrassMap_P3(quadratic1, quadratic2, variables=None): - w*x*y*z*a0^2*a1*a3^3 + w*x*y*z*a0*a1^2*a3^3 + w*x*y*z*a0^2*a2*a3^3 - w*x*y*z*a1^2*a2*a3^3 - w*x*y*z*a0*a2^2*a3^3 + w*x*y*z*a1*a2^2*a3^3 """ - biquadratic, quartic, from_aux = \ - _biquadratic_syzygy_quartic(quadratic1, quadratic2, variables=variables) + biquadratic, quartic, from_aux = _biquadratic_syzygy_quartic(quadratic1, quadratic2, variables=variables) J = biquadratic.J_covariant() g = quartic.g_covariant().subs(from_aux) h = quartic.h_covariant().subs(from_aux) diff --git a/src/sage/schemes/weighted_projective/weighted_projective_point.py b/src/sage/schemes/weighted_projective/weighted_projective_point.py index 84f69f7abdf..c557246895a 100644 --- a/src/sage/schemes/weighted_projective/weighted_projective_point.py +++ b/src/sage/schemes/weighted_projective/weighted_projective_point.py @@ -89,9 +89,7 @@ def __init__(self, X, v, check: bool = True): ) if not isinstance(X, SchemeHomset_points_weighted_projective_ring): - raise TypeError( - f"ambient space {X} must be a weighted projective space" - ) + raise TypeError(f"ambient space {X} must be a weighted projective space") d = X.codomain().ambient_space().ngens() if isinstance(v, SchemeMorphism): @@ -103,28 +101,20 @@ def __init__(self, X, v, check: bool = True): except AttributeError: pass if not isinstance(v, (list, tuple)): - raise TypeError( - "argument v (= %s) must be a scheme point, list, or tuple" % str(v) - ) + raise TypeError("argument v (= %s) must be a scheme point, list, or tuple" % str(v)) if len(v) != d and len(v) != d - 1: raise TypeError("v (=%s) must have %s components" % (v, d)) R = X.value_ring() if not R.is_integral_domain(): - raise ValueError( - "cannot validate point over a ring that is not an integral domain, " - "pass check=False to construct the point" - ) + raise ValueError("cannot validate point over a ring that is not an integral domain, " "pass check=False to construct the point") v = Sequence(v, R) if len(v) == d - 1: # very common special case v.append(R.one()) # (0 : 0 : ... : 0) is not a valid (weighted) projective point if not any(v): - raise ValueError( - f"{v} does not define a valid projective " - "point since all entries are zero" - ) + raise ValueError(f"{v} does not define a valid projective " "point since all entries are zero") X.extended_codomain()._check_satisfies_equations(v) @@ -194,21 +184,13 @@ def _richcmp_(self, other: SchemeMorphism_point, op) -> bool: return False # check zeros - b1 = all( - c1 == c2 - for c1, c2 in zip(self._coords, other._coords) - if c1 == 0 or c2 == 0 - ) + b1 = all(c1 == c2 for c1, c2 in zip(self._coords, other._coords) if c1 == 0 or c2 == 0) if b1 != (op == op_EQ): return False # check nonzeros prod_weights = prod(weights) - ratio = [ - (c1 / c2) ** (prod_weights // w) - for c1, c2, w in zip(self._coords, other._coords, weights) - if c1 != 0 and c2 != 0 - ] + ratio = [(c1 / c2) ** (prod_weights // w) for c1, c2, w in zip(self._coords, other._coords, weights) if c1 != 0 and c2 != 0] r0 = ratio[0] b2 = all(r == r0 for r in ratio) return b2 == (op == op_EQ) @@ -274,9 +256,7 @@ def scale_by(self, t) -> None: if t.is_zero(): raise ValueError("Cannot scale by 0") R = self.codomain().base_ring() - self._coords = tuple( - R(u * t**w) for u, w in zip(self._coords, self.codomain().weights()) - ) + self._coords = tuple(R(u * t**w) for u, w in zip(self._coords, self.codomain().weights())) self._normalized = False def normalize_coordinates(self) -> None: diff --git a/src/sage/schemes/weighted_projective/weighted_projective_space.py b/src/sage/schemes/weighted_projective/weighted_projective_space.py index f20cc16a3bf..dae11956b57 100644 --- a/src/sage/schemes/weighted_projective/weighted_projective_space.py +++ b/src/sage/schemes/weighted_projective/weighted_projective_space.py @@ -45,12 +45,8 @@ def WeightedProjectiveSpace(weights, R=None, names=None): names = normalize_names(weights.ngens(), names) if weights.variable_names() != names: # The provided name doesn't match the name of R's variables - raise NameError( - "variable names passed to ProjectiveSpace conflict with names in ring" - ) - A = WeightedProjectiveSpace( - weights.ngens() - 1, weights.base_ring(), names=weights.variable_names() - ) + raise NameError("variable names passed to ProjectiveSpace conflict with names in ring") + A = WeightedProjectiveSpace(weights.ngens() - 1, weights.base_ring(), names=weights.variable_names()) A._coordinate_ring = weights return A @@ -66,9 +62,7 @@ def WeightedProjectiveSpace(weights, R=None, names=None): # Make it hashable weights = tuple(map(Integer, weights)) if any(w <= 0 for w in weights): - raise TypeError( - f"weights(={weights}) should only consist of positive integers" - ) + raise TypeError(f"weights(={weights}) should only consist of positive integers") else: raise TypeError(f"weights={weights} must be an integer, a list or a tuple") @@ -103,10 +97,7 @@ def __classcall__(cls, weights: tuple[Integer], R=ZZ, names=None): # see docs of CachedRepresentation # weights should be a tuple, also because it should be hashable if not isinstance(weights, tuple): - raise TypeError( - f"weights(={weights}) is not a tuple. Please use the" - "`WeightedProjectiveSpace` constructor" - ) + raise TypeError(f"weights(={weights}) is not a tuple. Please use the" "`WeightedProjectiveSpace` constructor") normalized_names = normalize_names(len(weights), names) return super().__classcall__(cls, weights, R, normalized_names) @@ -242,9 +233,7 @@ def _validate(self, polynomials): TypeError: the argument polynomials=x*y - z must be a list or tuple """ if not isinstance(polynomials, (list, tuple)): - raise TypeError( - f"the argument polynomials={polynomials} must be a list or tuple" - ) + raise TypeError(f"the argument polynomials={polynomials} must be a list or tuple") R = self.coordinate_ring() for f in map(R, polynomials): @@ -267,9 +256,7 @@ def _latex_(self) -> str: sage: WeightedProjectiveSpace(Zp(5), [2, 1, 3], 'y')._latex_() # needs sage.rings.padics '{\\mathbf P}_{\\Bold{Z}_{5}}^{[2, 1, 3]}' """ - return ( - fr"{{\mathbf P}}_{{{latex(self.base_ring())}}}^{{{list(self.weights())}}}" - ) + return fr"{{\mathbf P}}_{{{latex(self.base_ring())}}}^{{{list(self.weights())}}}" def _morphism(self, *_, **__): """ @@ -277,17 +264,13 @@ def _morphism(self, *_, **__): For internal use only. See :mod:`morphism` for details. """ - raise NotImplementedError( - "_morphism not implemented for weighted projective space" - ) + raise NotImplementedError("_morphism not implemented for weighted projective space") def _homset(self, *_, **__): """ Construct the Hom-set. """ - raise NotImplementedError( - "_homset not implemented for weighted projective space" - ) + raise NotImplementedError("_homset not implemented for weighted projective space") def _point_homset(self, *args, **kwds): """ @@ -320,9 +303,7 @@ def point(self, v, check: bool = True): """ from sage.rings.infinity import infinity - if v is infinity or ( - isinstance(v, (list, tuple)) and len(v) == 1 and v[0] is infinity - ): + if v is infinity or (isinstance(v, (list, tuple)) and len(v) == 1 and v[0] is infinity): if self.dimension_relative() > 1: raise ValueError("%s not well defined in dimension > 1" % v) v = [1, 0] @@ -336,6 +317,7 @@ def _point(self, *args, **kwds): For internal use only. See :mod:`morphism` for details. """ from sage.schemes.weighted_projective.weighted_projective_point import SchemeMorphism_point_weighted_projective_ring + return SchemeMorphism_point_weighted_projective_ring(*args, **kwds) def _repr_(self) -> str: @@ -348,10 +330,7 @@ def _repr_(self) -> str: Weighted Projective Space of dimension 2 with weights (1, 3, 1) over 5-adic Field with capped relative precision 20 """ - return ( - f"Weighted Projective Space of dimension {self.dimension_relative()} with weights" - f" {self.weights()} over {self.base_ring()}" - ) + return f"Weighted Projective Space of dimension {self.dimension_relative()} with weights" f" {self.weights()} over {self.base_ring()}" def change_ring(self, R): r""" @@ -380,10 +359,8 @@ def change_ring(self, R): Weighted Projective Space of dimension 2 with weights (1, 3, 1) over Finite Field of size 5 """ if isinstance(R, Map): - return WeightedProjectiveSpace(self.weights(), R.codomain(), - self.variable_names()) - return WeightedProjectiveSpace(self.weights(), R, - self.variable_names()) + return WeightedProjectiveSpace(self.weights(), R.codomain(), self.variable_names()) + return WeightedProjectiveSpace(self.weights(), R, self.variable_names()) def _an_element_(self): r""" @@ -425,7 +402,7 @@ def curve(self, F): Weighted Projective Curve over Rational Field defined by y^2 - x^5*z - 3*x^2*z^4 - 2*z^6 """ if self.base_ring() not in Fields(): - raise NotImplementedError("curves in weighted projective space over" - "rings not implemented") + raise NotImplementedError("curves in weighted projective space over" "rings not implemented") from sage.schemes.curves.constructor import Curve + return Curve(F, self) diff --git a/src/sage/sets/all.py b/src/sage/sets/all.py index 8cdd85ed269..e6b54eb65df 100644 --- a/src/sage/sets/all.py +++ b/src/sage/sets/all.py @@ -1,10 +1,12 @@ from sage.misc.lazy_import import lazy_import + lazy_import('sage.sets.real_set', 'RealSet') from sage.sets.set import Set from sage.sets.integer_range import IntegerRange from sage.sets.non_negative_integers import NonNegativeIntegers from sage.sets.positive_integers import PositiveIntegers from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + lazy_import('sage.sets.recursively_enumerated_set', 'RecursivelyEnumeratedSet') from sage.sets.totally_ordered_finite_set import TotallyOrderedFiniteSet from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets @@ -13,4 +15,5 @@ from sage.sets.disjoint_set import DisjointSet from sage.sets.condition_set import ConditionSet from sage.sets.finite_set_maps import FiniteSetMaps + del lazy_import diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index 62d56f1b324..0c1831a7d89 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -5,6 +5,7 @@ - Nicolas Thiery (2010-03): initial version """ + # **************************************************************************** # Copyright (C) 2008 Nicolas Thiery , # Mike Hansen , @@ -26,6 +27,7 @@ from sage.structure.element_wrapper import ElementWrapperCheckWrappedClass from sage.categories.rings import Rings + _Rings = Rings() @@ -51,6 +53,7 @@ class CartesianProduct(UniqueRepresentation, Parent): .. automethod:: CartesianProduct._cartesian_product_of_elements """ + def __init__(self, sets, category, flatten=False): r""" INPUT: @@ -129,8 +132,7 @@ def _element_constructor_(self, x): x = tuple(x) if len(x) != len(self._sets): - raise ValueError( - "{} should be of length {}".format(x, len(self._sets))) + raise ValueError("{} should be of length {}".format(x, len(self._sets))) x = tuple(c(xx) for c, xx in zip(self._sets, x)) return self.element_class(self, x) @@ -169,8 +171,7 @@ def __contains__(self, x): return True elif not isinstance(x, tuple): return False - return (len(x) == len(self._sets) - and all(elt in self._sets[i] for i, elt in enumerate(x))) + return len(x) == len(self._sets) and all(elt in self._sets[i] for i, elt in enumerate(x)) def cartesian_factors(self): """ @@ -203,6 +204,7 @@ def _sets_keys(self): {0, ..., 99} """ from sage.sets.integer_range import IntegerRange + return IntegerRange(len(self._sets)) @cached_method @@ -282,6 +284,7 @@ def construction(self): (Integer Ring, Rational Field)) """ from sage.categories.cartesian_product import CartesianProductFunctor + return CartesianProductFunctor(self.category()), self.cartesian_factors() def _coerce_map_from_(self, S): diff --git a/src/sage/sets/condition_set.py b/src/sage/sets/condition_set.py index a0d618ebdde..25e35a87ad2 100644 --- a/src/sage/sets/condition_set.py +++ b/src/sage/sets/condition_set.py @@ -23,8 +23,7 @@ from .set import Set, Set_base, Set_boolean_operators, Set_add_sub_operators -class ConditionSet(Set_generic, Set_base, Set_boolean_operators, Set_add_sub_operators, - UniqueRepresentation): +class ConditionSet(Set_generic, Set_base, Set_boolean_operators, Set_add_sub_operators, UniqueRepresentation): r""" Set of elements of a universe that satisfy given predicates. @@ -126,6 +125,7 @@ class ConditionSet(Set_generic, Set_base, Set_boolean_operators, Set_add_sub_ope sage: TestSuite(P_inter_B).run(skip='_test_pickling') # cannot pickle lambdas # needs sage.geometry.polyhedron sage: TestSuite(P_inter_B_again).run() # needs sage.geometry.polyhedron sage.symbolic """ + @staticmethod def __classcall_private__(cls, universe, *predicates, vars=None, names=None, category=None): r""" @@ -171,6 +171,7 @@ def __classcall_private__(cls, universe, *predicates, vars=None, names=None, cat raise TypeError('use callable symbolic expressions or provide variable names') if vars is None: from sage.symbolic.ring import SR + vars = tuple(SR.var(name) for name in names) callable_symbolic_predicates.append(predicate.function(*vars)) else: @@ -183,15 +184,13 @@ def __classcall_private__(cls, universe, *predicates, vars=None, names=None, cat # No conditions, no variable names, no category, just use Set. return Set(universe) - if any(predicate.args() != vars - for predicate in callable_symbolic_predicates): + if any(predicate.args() != vars for predicate in callable_symbolic_predicates): # TODO: Implement safe renaming of the arguments of a callable symbolic expressions raise NotImplementedError('all callable symbolic expressions must use the same arguments') if names is None: names = ("x",) - return super().__classcall__(cls, universe, *predicates, - names=names, category=category) + return super().__classcall__(cls, universe, *predicates, names=names, category=category) def __init__(self, universe, *predicates, names=None, category=None): r""" @@ -206,8 +205,7 @@ def __init__(self, universe, *predicates, names=None, category=None): facade = None if isinstance(universe, Parent): facade = universe - super().__init__(facade=facade, category=category, - names=names, normalize=False) # names already normalized by classcall + super().__init__(facade=facade, category=category, names=names, normalize=False) # names already normalized by classcall def _first_ngens(self, n): r""" @@ -276,8 +274,7 @@ def _repr_condition(self, predicate): args = args[0] condition = self._call_predicate(predicate, args) return str(condition) - comma_sep_names = ", ".join(str(name) - for name in self.variable_names()) + comma_sep_names = ", ".join(str(name) for name in self.variable_names()) return f"{predicate}({comma_sep_names})" @cached_method @@ -295,6 +292,7 @@ def arguments(self): Symbolic Ring """ from sage.symbolic.ring import SR + return SR.var(self.variable_names()) def _element_constructor_(self, *args, **kwds): @@ -331,8 +329,7 @@ def _element_constructor_(self, *args, **kwds): raise ValueError(f'{element} is not an element of the universe') else: element = universe_element_constructor(*args, **kwds) - if not all(self._call_predicate(predicate, element) - for predicate in self._predicates): + if not all(self._call_predicate(predicate, element) for predicate in self._predicates): raise ValueError(f'{element} does not satisfy the condition') return element @@ -439,6 +436,7 @@ def _sympy_(self): SageSet({ x ∈ Integer Ring : (x) }) """ from sage.interfaces.sympy import sympy_init + sympy_init() import sympy @@ -448,16 +446,12 @@ def _sympy_(self): args = args[0] try: - conditions = [self._call_predicate(predicate, args) - for predicate in self._predicates] + conditions = [self._call_predicate(predicate, args) for predicate in self._predicates] sym = tuple(x._sympy_() for x in self.arguments()) if single_arg: sym = sym[0] - result = sympy.ConditionSet(sym, - sympy.And(*[condition._sympy_() - for condition in conditions]), - base_set=self._universe._sympy_()) + result = sympy.ConditionSet(sym, sympy.And(*[condition._sympy_() for condition in conditions]), base_set=self._universe._sympy_()) result._sage_object = self return result except TypeError: @@ -503,9 +497,7 @@ def intersection(self, X): over Rational Field : 3*x^2 + y^2 <= 42 } """ if isinstance(X, ConditionSet): - return ConditionSet(self.ambient().intersection(X.ambient()), - *(self._predicates + X._predicates), - vars=self.arguments()) + return ConditionSet(self.ambient().intersection(X.ambient()), *(self._predicates + X._predicates), vars=self.arguments()) return super().intersection(X) def __iter__(self): diff --git a/src/sage/sets/disjoint_union_enumerated_sets.py b/src/sage/sets/disjoint_union_enumerated_sets.py index 0236f972545..f1f74519e73 100644 --- a/src/sage/sets/disjoint_union_enumerated_sets.py +++ b/src/sage/sets/disjoint_union_enumerated_sets.py @@ -7,6 +7,7 @@ - Florent Hivert (2010-03): classcall related stuff. - Florent Hivert (2010-12): fixed facade element construction. """ + # *************************************************************************** # Copyright (C) 2009 Florent Hivert # @@ -242,8 +243,7 @@ class DisjointUnionEnumeratedSets(UniqueRepresentation, Parent): """ @staticmethod - def __classcall_private__(cls, fam, facade=True, - keepkey=False, category=None): + def __classcall_private__(cls, fam, facade=True, keepkey=False, category=None): """ Normalization of arguments; see :class:`UniqueRepresentation`. @@ -268,9 +268,7 @@ def __classcall_private__(cls, fam, facade=True, # keepkey = options.pop('keepkey', False); assert isinstance(facade, bool) assert isinstance(keepkey, bool) - return super().__classcall__( - cls, Family(fam), - facade=facade, keepkey=keepkey, category=category) + return super().__classcall__(cls, Family(fam), facade=facade, keepkey=keepkey, category=category) def __init__(self, family, facade=True, keepkey=False, category=None): """ @@ -340,10 +338,9 @@ def _is_a(self, x): True """ if self._keepkey: - return (isinstance(x, tuple) and - x[0] in self._family.keys() and - x[1] in self._family[x[0]]) + return isinstance(x, tuple) and x[0] in self._family.keys() and x[1] in self._family[x[0]] from warnings import warn + if self._family.cardinality() == Infinity: warn("%s is an infinite union\nThe default implementation of __contains__ can loop forever. Please overload it." % (self)) return any(x in a for a in self._family) @@ -470,6 +467,7 @@ def __iter__(self): ....: (UnknowinglyFiniteSet(frozenset([1,2,3])), UnknowinglyFiniteSet(frozenset([4,5,6])))), 7)) [1, 2, 4, 3, 5, 6] """ + def wrap_element(el, k): nonlocal self if self._keepkey: @@ -517,8 +515,7 @@ def wrap_element(el, k): yield wrap_element(el, k) if any_stopped: if self._keepkey: - filtered = list(zip( - *[(k, el_iter) for k, el_iter in zip(seen_keys, el_iters) if el_iter is not None])) + filtered = list(zip(*[(k, el_iter) for k, el_iter in zip(seen_keys, el_iters) if el_iter is not None])) if filtered: seen_keys = list(filtered[0]) el_iters = list(filtered[1]) @@ -697,8 +694,7 @@ def _element_constructor_facade(self, el): raise ValueError("cannot coerce `%s` in the parent `%s`" % (el[1], P)) # Check first to see if the parent of el is in the family - if (isinstance(el, Element) and self._facade_for is not True - and el.parent() in self._facade_for): + if isinstance(el, Element) and self._facade_for is not True and el.parent() in self._facade_for: return el for P in self._family: diff --git a/src/sage/sets/finite_enumerated_set.py b/src/sage/sets/finite_enumerated_set.py index 24062f9b37e..5788a81950c 100644 --- a/src/sage/sets/finite_enumerated_set.py +++ b/src/sage/sets/finite_enumerated_set.py @@ -1,6 +1,7 @@ """ Finite Enumerated Sets """ + # **************************************************************************** # Copyright (C) 2009 Florent Hivert # @@ -244,6 +245,7 @@ def random_element(self): if not self._elements: raise EmptySetError from sage.misc.prandom import choice + return choice(self._elements) def cardinality(self): diff --git a/src/sage/sets/finite_set_maps.py b/src/sage/sets/finite_set_maps.py index 8386fc0d4cc..12af3f259fa 100644 --- a/src/sage/sets/finite_set_maps.py +++ b/src/sage/sets/finite_set_maps.py @@ -10,6 +10,7 @@ - Florent Hivert """ + # **************************************************************************** # Copyright (C) 2010 Florent Hivert , # @@ -27,9 +28,7 @@ from sage.categories.enumerated_sets import EnumeratedSets from sage.sets.finite_enumerated_set import FiniteEnumeratedSet from sage.sets.integer_range import IntegerRange -from sage.sets.finite_set_map_cy import ( - FiniteSetMap_MN, FiniteSetMap_Set, - FiniteSetEndoMap_N, FiniteSetEndoMap_Set) +from sage.sets.finite_set_map_cy import FiniteSetMap_MN, FiniteSetMap_Set, FiniteSetEndoMap_N, FiniteSetEndoMap_Set from sage.misc.cachefunc import cached_method # TODO: finite set maps should be morphisms in the category of finite sets @@ -155,6 +154,7 @@ class FiniteSetMaps(UniqueRepresentation, Parent): sage: TestSuite(FiniteSetMaps([1, 2], [])).run() sage: TestSuite(FiniteSetMaps([], [1, 2])).run() """ + @staticmethod def __classcall_private__(cls, domain, codomain=None, action='left', category=None): """ @@ -200,7 +200,7 @@ def cardinality(self): sage: FiniteSetMaps(4, 3).cardinality() 81 """ - return self.codomain().cardinality()**self.domain().cardinality() + return self.codomain().cardinality() ** self.domain().cardinality() class FiniteSetMaps_MN(FiniteSetMaps): @@ -230,8 +230,7 @@ def __init__(self, m, n, category=None): sage: TestSuite(M).run() """ - Parent.__init__(self, - category=EnumeratedSets().Finite().or_subcategory(category)) + Parent.__init__(self, category=EnumeratedSets().Finite().or_subcategory(category)) self._m = Integer(m) self._n = Integer(n) @@ -377,6 +376,7 @@ class FiniteSetMaps_Set(FiniteSetMaps_MN): constructed. It must be a sub-category of ``EnumeratedSets().Finite()`` which is the default value. """ + def __init__(self, domain, codomain, category=None): """ EXAMPLES:: @@ -405,14 +405,13 @@ def __init__(self, domain, codomain, category=None): Category of finite enumerated sets sage: TestSuite(M).run() """ - FiniteSetMaps_MN.__init__(self, domain.cardinality(), - codomain.cardinality(), - category=category) + FiniteSetMaps_MN.__init__(self, domain.cardinality(), codomain.cardinality(), category=category) self._domain = domain self._codomain = codomain from sage.combinat import ranker + ldomain = domain.list() lcodomain = codomain.list() self._unrank_domain = ranker.unrank_from_list(ldomain) @@ -554,6 +553,7 @@ class FiniteSetEndoMaps_Set(FiniteSetMaps_Set, FiniteSetEndoMaps_N): constructed. It must be a sub-category of ``Monoids().Finite()`` and ``EnumeratedSets().Finite()`` which is the default value. """ + def __init__(self, domain, action, category=None): """ TESTS:: @@ -566,14 +566,13 @@ def __init__(self, domain, action, category=None): sage: TestSuite(M).run() """ category = (EnumeratedSets() & Monoids().Finite()).or_subcategory(category) - FiniteSetMaps_MN.__init__(self, domain.cardinality(), - domain.cardinality(), - category=category) + FiniteSetMaps_MN.__init__(self, domain.cardinality(), domain.cardinality(), category=category) self._domain = domain self._codomain = domain from sage.combinat import ranker + ldomain = domain.list() self._unrank_domain = ranker.unrank_from_list(ldomain) self._rank_domain = ranker.rank_from_list(ldomain) diff --git a/src/sage/sets/image_set.py b/src/sage/sets/image_set.py index f5dda0447ea..a127bac8e90 100644 --- a/src/sage/sets/image_set.py +++ b/src/sage/sets/image_set.py @@ -68,6 +68,7 @@ class ImageSubobject(Parent): ... ValueError: The map from Integer Ring is not injective: 1 """ + def __init__(self, map, domain_subset, *, category=None, is_injective=None, inverse=None): """ Initialize ``self``. @@ -96,6 +97,7 @@ def __init__(self, map, domain_subset, *, category=None, is_injective=None, inve """ if not isinstance(domain_subset, Parent): from sage.sets.set import Set + domain_subset = Set(domain_subset) if not isinstance(map, Map) and not isinstance(map, PoorManMap): @@ -104,11 +106,13 @@ def __init__(self, map, domain_subset, *, category=None, is_injective=None, inve domain = map.parent().base() if len(map.arguments()) != 1: from sage.modules.free_module import FreeModule + domain = FreeModule(domain, len(map.arguments())) function = map def map(arg): return function(*arg) + else: domain = domain_subset map = PoorManMap(map, domain, name=map_name) @@ -177,8 +181,7 @@ def __eq__(self, other): """ if not isinstance(other, ImageSubobject): return False - return (self._map == other._map - and self._domain_subset == other._domain_subset) + return self._map == other._map and self._domain_subset == other._domain_subset def __ne__(self, other): r""" @@ -424,12 +427,12 @@ def _sympy_(self): ImageSet(Lambda(x, sin(x)), Interval.open(0, pi/4)) """ from sympy import imageset + try: sympy_map = self._map._sympy_() except AttributeError: sympy_map = self._map - return imageset(sympy_map, - self._domain_subset._sympy_()) + return imageset(sympy_map, self._domain_subset._sympy_()) class ImageSet(ImageSubobject, Set_base, Set_add_sub_operators, Set_boolean_operators): @@ -462,4 +465,5 @@ class ImageSet(ImageSubobject, Set_base, Set_add_sub_operators, Set_boolean_oper sage: _.an_element() 25 """ + pass diff --git a/src/sage/sets/integer_range.py b/src/sage/sets/integer_range.py index 38e20452214..733a85c8300 100644 --- a/src/sage/sets/integer_range.py +++ b/src/sage/sets/integer_range.py @@ -8,6 +8,7 @@ - Vincent Delecroix (2012-02): add methods rank/unrank, make it compliant with Python int. """ + # **************************************************************************** # Copyright (C) 2010 Nicolas Borie # @@ -320,6 +321,7 @@ class IntegerRangeFinite(IntegerRange): See :class:`IntegerRange` for more details. """ + def __init__(self, begin, end, step=Integer(1)): r""" TESTS:: @@ -364,9 +366,8 @@ def __contains__(self, elt): elt = x except (ValueError, TypeError): return False - if abs(self._step).divides(Integer(elt)-self._begin): - return (self._begin <= elt < self._end and self._step > 0) or \ - (self._begin >= elt > self._end and self._step < 0) + if abs(self._step).divides(Integer(elt) - self._begin): + return (self._begin <= elt < self._end and self._step > 0) or (self._begin >= elt > self._end and self._step < 0) return False def cardinality(self): @@ -382,7 +383,7 @@ def cardinality(self): sage: IntegerRange(123,12,4).cardinality() 0 """ - return (abs(self._end+self._step-self._begin)-1) // abs(self._step) + return (abs(self._end + self._step - self._begin) - 1) // abs(self._step) def _repr_(self): """ @@ -405,8 +406,7 @@ def _repr_(self): return "{" + ", ".join(str(x) for x in self) + "}" if self._step == 1: return "{%s, ..., %s}" % (self._begin, self._end - self._step) - return "{%s, %s, ..., %s}" % (self._begin, self._begin + self._step, - self._end - self._step) + return "{%s, %s, ..., %s}" % (self._begin, self._begin + self._step, self._end - self._step) def rank(self, x): r""" @@ -428,7 +428,7 @@ def rank(self, x): """ if x not in self: raise IndexError("%s not in self" % x) - return Integer((x - self._begin)/self._step) + return Integer((x - self._begin) / self._step) def __getitem__(self, i): r""" @@ -469,8 +469,8 @@ def __getitem__(self, i): if i < 0: if i < -self.cardinality(): raise IndexError("out of range") - n = (self._end - self._begin)//(self._step) - return self._begin + (n+i)*self._step + n = (self._end - self._begin) // (self._step) + return self._begin + (n + i) * self._step if i >= self.cardinality(): raise IndexError("out of range") return self._begin + i * self._step @@ -515,18 +515,19 @@ def _an_element_(self): sage: I.an_element() #indirect doctest -41 """ - p = (self._begin + 2*self._step) + p = self._begin + 2 * self._step if p in self: return p return self._begin class IntegerRangeInfinite(IntegerRange): - r""" The class of infinite enumerated sets of integers defined by infinite + r"""The class of infinite enumerated sets of integers defined by infinite arithmetic progressions. See :class:`IntegerRange` for more details. """ + def __init__(self, begin, step=Integer(1)): r""" TESTS:: @@ -556,7 +557,7 @@ def _repr_(self): sage: IntegerRange(-112,-Infinity,-13) #indirect doctest {-112, -125, ...} """ - return "{%s, %s, ...}" % (self._begin, self._begin+self._step) + return "{%s, %s, ...}" % (self._begin, self._begin + self._step) def __contains__(self, elt): r""" @@ -579,9 +580,8 @@ def __contains__(self, elt): elt = Integer(elt) except (TypeError, ValueError): return False - if abs(self._step).divides(Integer(elt)-self._begin): - return (self._step > 0 and elt >= self._begin) or \ - (self._step < 0 and elt <= self._begin) + if abs(self._step).divides(Integer(elt) - self._begin): + return (self._step > 0 and elt >= self._begin) or (self._step < 0 and elt <= self._begin) return False def rank(self, x): @@ -600,7 +600,7 @@ def rank(self, x): """ if x not in self: raise IndexError("%s not in self" % x) - return Integer((x - self._begin)/self._step) + return Integer((x - self._begin) / self._step) def __getitem__(self, i): r""" @@ -662,7 +662,7 @@ def _an_element_(self): sage: I.an_element() #indirect doctest -515 """ - return self._begin + 31*self._step + return self._begin + 31 * self._step class IntegerRangeFromMiddle(IntegerRange): @@ -672,6 +672,7 @@ class IntegerRangeFromMiddle(IntegerRange): See :class:`IntegerRange` for more details. """ + def __init__(self, begin, end, step=Integer(1), middle_point=Integer(1)): r""" TESTS:: @@ -698,8 +699,7 @@ def __init__(self, begin, end, step=Integer(1), middle_point=Integer(1)): if middle_point not in self: raise ValueError("middle_point is not in the interval") - if (begin != Infinity and begin != -Infinity and - end != Infinity and end != -Infinity): + if begin != Infinity and begin != -Infinity and end != Infinity and end != -Infinity: cat = FiniteEnumeratedSets() else: cat = InfiniteEnumeratedSets() @@ -716,8 +716,7 @@ def _repr_(self): sage: IntegerRangeFromMiddle(-100,100,10,0) #indirect doctest Integer progression containing 0 with increment 10 and bounded with -100 and 100 """ - return "Integer progression containing %s with increment %s and bounded with %s and %s" % ( - self._middle_point, self._step, self._begin, self._end) + return "Integer progression containing %s with increment %s and bounded with %s and %s" % (self._middle_point, self._step, self._begin, self._end) def __contains__(self, elt): r""" @@ -743,9 +742,8 @@ def __contains__(self, elt): elt = Integer(elt) except (TypeError, ValueError): return False - if abs(self._step).divides(Integer(elt)-self._middle_point): - return (self._begin <= elt < self._end) or \ - (self._begin >= elt > self._end) + if abs(self._step).divides(Integer(elt) - self._middle_point): + return (self._begin <= elt < self._end) or (self._begin >= elt > self._end) return False def next(self, elt): @@ -770,17 +768,17 @@ def next(self, elt): raise LookupError('%r not in %r' % (elt, self)) n = self._middle_point if (elt <= n and self._step > 0) or (elt >= n and self._step < 0): - right = 2*n-elt+self._step + right = 2 * n - elt + self._step if right in self: return right - left = elt-self._step + left = elt - self._step if left in self: return left else: - left = 2*n-elt + left = 2 * n - elt if left in self: return left - right = elt+self._step + right = elt + self._step if right in self: return right diff --git a/src/sage/sets/non_negative_integers.py b/src/sage/sets/non_negative_integers.py index ed954d62bbe..e2a188194c6 100644 --- a/src/sage/sets/non_negative_integers.py +++ b/src/sage/sets/non_negative_integers.py @@ -1,6 +1,7 @@ """ Non Negative Integers """ + # **************************************************************************** # Copyright (C) 2009 Florent Hivert # @@ -81,8 +82,8 @@ def __init__(self, category=None): sage: TestSuite(NN).run() """ from sage.rings.integer_ring import ZZ - Parent.__init__(self, facade=ZZ, - category=InfiniteEnumeratedSets().or_subcategory(category)) + + Parent.__init__(self, facade=ZZ, category=InfiniteEnumeratedSets().or_subcategory(category)) def _repr_(self): """ @@ -237,5 +238,6 @@ def _sympy_(self): from sympy import Naturals0 from sage.interfaces.sympy import sympy_init + sympy_init() return Naturals0 diff --git a/src/sage/sets/positive_integers.py b/src/sage/sets/positive_integers.py index 31502df53d8..c35cb1f8ff8 100644 --- a/src/sage/sets/positive_integers.py +++ b/src/sage/sets/positive_integers.py @@ -1,6 +1,7 @@ """ Positive Integers """ + # **************************************************************************** # Copyright (C) 2010 Nicolas Borie # @@ -47,6 +48,7 @@ class PositiveIntegers(IntegerRangeInfinite): sage: TestSuite(PositiveIntegers()).run() """ + def __init__(self): r""" EXAMPLES:: @@ -88,5 +90,6 @@ def _sympy_(self): """ from sympy import Naturals from sage.interfaces.sympy import sympy_init + sympy_init() return Naturals diff --git a/src/sage/sets/primes.py b/src/sage/sets/primes.py index f5a542cb21e..c4320d1b4e6 100644 --- a/src/sage/sets/primes.py +++ b/src/sage/sets/primes.py @@ -121,6 +121,7 @@ class Primes(Set_generic, UniqueRepresentation): sage: PQ.complement_in_primes().cardinality() 1 """ + @staticmethod def __classcall__(cls, modulus=1, classes=None, exceptions=None): """ @@ -194,14 +195,14 @@ def __classcall__(cls, modulus=1, classes=None, exceptions=None): add_false = [] add_excluded = [] for c in range(m): - cs = [indic[c + m*i] for i in range(p) if indic[c + m*i] is not None] + cs = [indic[c + m * i] for i in range(p) if indic[c + m * i] is not None] if not cs: pass elif all(cs): if m.gcd(c) == 1: add_true.append(c) for i in range(p): - j = c + m*i + j = c + m * i if indic[j] is None: if j == 0: add_excluded.append(modulus) @@ -226,8 +227,7 @@ def __classcall__(cls, modulus=1, classes=None, exceptions=None): # We format the final result and make it hashable classes = tuple([c for c in range(modulus) if indic[c] is True]) - exceptions = [(ZZ(x), b) for x, b in exceptions.items() - if ZZ(x).is_prime() and (b != (indic[x % modulus] is True))] + exceptions = [(ZZ(x), b) for x, b in exceptions.items() if ZZ(x).is_prime() and (b != (indic[x % modulus] is True))] exceptions.sort() exceptions = tuple(exceptions) @@ -802,8 +802,7 @@ def complement_in_primes(self): :meth:`intersection`, :meth:`union` """ modulus = self._modulus - classes = [c for c in range(modulus) - if c % self._modulus not in self._classes] + classes = [c for c in range(modulus) if c % self._modulus not in self._classes] exceptions = {x: not b for x, b in self._exceptions.items()} return Primes(modulus, classes, exceptions) @@ -862,13 +861,9 @@ def intersection(self, other): return self if isinstance(other, Primes): modulus = self._modulus.lcm(other._modulus) - classes = [c for c in range(modulus) - if (c % self._modulus in self._classes - and c % other._modulus in other._classes)] - exceptions = {x: b for x, b in self._exceptions.items() - if not b or x in other} - exceptions.update((x, b) for x, b in other._exceptions.items() - if not b or x in self) + classes = [c for c in range(modulus) if (c % self._modulus in self._classes and c % other._modulus in other._classes)] + exceptions = {x: b for x, b in self._exceptions.items() if not b or x in other} + exceptions.update((x, b) for x, b in other._exceptions.items() if not b or x in self) else: modulus = 1 classes = [] @@ -942,13 +937,9 @@ def union(self, other): return ZZ if isinstance(other, Primes): modulus = self._modulus.lcm(other._modulus) - classes = [c for c in range(modulus) - if (c % self._modulus in self._classes - or c % other._modulus in other._classes)] - exceptions = {x: b for x, b in self._exceptions.items() - if b or x not in other} - exceptions.update((x, b) for x, b in other._exceptions.items() - if b or x not in self) + classes = [c for c in range(modulus) if (c % self._modulus in self._classes or c % other._modulus in other._classes)] + exceptions = {x: b for x, b in self._exceptions.items() if b or x not in other} + exceptions.update((x, b) for x, b in other._exceptions.items() if b or x not in self) else: # we try to enumerate the elements of "other" if hasattr(other, "is_finite") and not other.is_finite(): diff --git a/src/sage/sets/real_set.py b/src/sage/sets/real_set.py index 607f9b213d8..f9971843072 100644 --- a/src/sage/sets/real_set.py +++ b/src/sage/sets/real_set.py @@ -159,9 +159,9 @@ def __init__(self, lower, lower_closed, upper, upper_closed, check=True): raise ValueError('upper_closed must be boolean') if lower > upper: raise ValueError('lower/upper bounds are not sorted') - if (lower_closed and lower == minus_infinity): + if lower_closed and lower == minus_infinity: raise ValueError('interval cannot be closed at -oo') - if (upper_closed and upper == infinity): + if upper_closed and upper == infinity: raise ValueError('interval cannot be closed at +oo') # TODO: take care of the empty set case. @@ -388,6 +388,7 @@ def _latex_(self) -> str: '\\{\\sqrt{2}\\}' """ from sage.misc.latex import latex + if self.is_point(): # Converting to str avoids the extra whitespace # that LatexExpr add on concatenation. We do not need @@ -457,10 +458,9 @@ def _sympy_(self): from sympy import Interval from sage.interfaces.sympy import sympy_init + sympy_init() - return Interval(self.lower(), self.upper(), - left_open=not self._lower_closed, - right_open=not self._upper_closed) + return Interval(self.lower(), self.upper(), left_open=not self._lower_closed, right_open=not self._upper_closed) def _giac_condition_(self, variable): """ @@ -514,8 +514,8 @@ def closure(self): # TODO: take care of the empty set case. # maybe not necessary because this is an interval class of # :class:`RealSet` whose intervals are all non-empty. - lower_closed = (self._lower != minus_infinity) - upper_closed = (self._upper != infinity) + lower_closed = self._lower != minus_infinity + upper_closed = self._upper != infinity return InternalRealInterval(self._lower, lower_closed, self._upper, upper_closed) def interior(self): @@ -791,8 +791,7 @@ def __mul__(self, right): lower = -infinity if upper == infinity: upper = infinity - return InternalRealInterval(lower, lower_closed, - upper, upper_closed) + return InternalRealInterval(lower, lower_closed, upper, upper_closed) def __rmul__(self, other): r""" @@ -885,8 +884,7 @@ def _scan_upper(self): @richcmp_method -class RealSet(UniqueRepresentation, Parent, Set_base, - Set_boolean_operators, Set_add_sub_operators): +class RealSet(UniqueRepresentation, Parent, Set_base, Set_boolean_operators, Set_add_sub_operators): r""" A subset of the real line, a finite union of intervals. @@ -1143,8 +1141,7 @@ def __classcall__(cls, *args, **kwds): # No other kwds should be provided. return UniqueRepresentation.__classcall__(cls, *args, normalized=True) manifold_keywords = ('structure', 'ambient', 'names', 'coordinate') - if any(kwds.get(kwd, None) - for kwd in manifold_keywords): + if any(kwds.get(kwd, None) for kwd in manifold_keywords): # Got manifold keywords real_set = cls.__classcall__(cls, *args) ambient = kwds.pop('ambient', None) @@ -1154,6 +1151,7 @@ def __classcall__(cls, *args, **kwds): raise NotImplementedError from sage.manifolds.differentiable.examples.real_line import RealLine + if real_set.is_universe(): if ambient is None: ambient = RealLine(**kwds) @@ -1175,6 +1173,7 @@ def __classcall__(cls, *args, **kwds): name = str(real_set) if latex_name is None: from sage.misc.latex import latex + latex_name = latex(real_set) return ambient.manifold().canonical_chart().pullback(real_set, name=name, latex_name=latex_name) @@ -1183,6 +1182,7 @@ def __classcall__(cls, *args, **kwds): raise TypeError(f'RealSet constructors cannot take the keyword arguments {kwds}') from sage.structure.element import Expression + if len(args) == 1 and isinstance(args[0], RealSet): return args[0] # common optimization intervals = [] @@ -1226,19 +1226,14 @@ def rel_to_interval(op, val): elif op == le: s = [InternalRealInterval(-oo, False, val, True)] elif op == ne: - s = [InternalRealInterval(-oo, False, val, False), - InternalRealInterval(val, False, oo, False)] + s = [InternalRealInterval(-oo, False, val, False), InternalRealInterval(val, False, oo, False)] else: raise ValueError(str(arg) + ' does not determine real interval') return [i for i in s if not i.is_empty()] - if (arg.lhs().is_symbol() - and (arg.rhs().is_numeric() or arg.rhs().is_constant()) - and arg.rhs().is_real()): + if arg.lhs().is_symbol() and (arg.rhs().is_numeric() or arg.rhs().is_constant()) and arg.rhs().is_real(): intervals.extend(rel_to_interval(arg.operator(), arg.rhs())) - elif (arg.rhs().is_symbol() - and (arg.lhs().is_numeric() or arg.lhs().is_constant()) - and arg.lhs().is_real()): + elif arg.rhs().is_symbol() and (arg.lhs().is_numeric() or arg.lhs().is_constant()) and arg.lhs().is_real(): op = arg.operator() if op == lt: op = gt @@ -1256,21 +1251,18 @@ def rel_to_interval(op, val): OpenInterval, ) from sage.manifolds.subsets.closure import ManifoldSubsetClosure + if isinstance(arg, OpenInterval): lower, upper = RealSet._prep(arg.lower_bound(), arg.upper_bound()) intervals.append(InternalRealInterval(lower, False, upper, False)) - elif (isinstance(arg, ManifoldSubsetClosure) - and isinstance(arg._subset, OpenInterval)): + elif isinstance(arg, ManifoldSubsetClosure) and isinstance(arg._subset, OpenInterval): interval = arg._subset - lower, upper = RealSet._prep(interval.lower_bound(), - interval.upper_bound()) + lower, upper = RealSet._prep(interval.lower_bound(), interval.upper_bound()) ambient = interval.manifold() - ambient_lower, ambient_upper = RealSet._prep(ambient.lower_bound(), - ambient.upper_bound()) + ambient_lower, ambient_upper = RealSet._prep(ambient.lower_bound(), ambient.upper_bound()) lower_closed = ambient_lower < lower upper_closed = upper < ambient_upper - intervals.append(InternalRealInterval(lower, lower_closed, - upper, upper_closed)) + intervals.append(InternalRealInterval(lower, lower_closed, upper, upper_closed)) else: raise ValueError(str(arg) + ' does not determine real interval') @@ -1305,8 +1297,7 @@ def __init__(self, *intervals, normalized=True): category = category.Subobjects() # subobject of real line if inf is not minus_infinity and sup is not infinity: # Bounded - if all(i.lower_closed() and i.upper_closed() - for i in intervals): + if all(i.lower_closed() and i.upper_closed() for i in intervals): category = category.Compact() Parent.__init__(self, category=category) self._intervals = intervals @@ -1567,6 +1558,7 @@ def _latex_(self): (0, 1) \cup [2, +\infty) """ from sage.misc.latex import latex + if self.n_components() == 0: return r'\emptyset' return r' \cup '.join(latex(i) for i in self._intervals) @@ -1638,8 +1630,7 @@ def _giac_condition_(self, variable): false = 'false' if self.n_components() == 0: return false - return ' or '.join(it._giac_condition_(x) - for it in self._intervals) + return ' or '.join(it._giac_condition_(x) for it in self._intervals) @staticmethod def _prep(lower, upper=None): @@ -2371,6 +2362,7 @@ def _an_element_(self): sage.categories.sets_cat.EmptySetError """ from sage.rings.infinity import AnInfinity + if not self._intervals: raise EmptySetError i = self._intervals[0] @@ -2403,9 +2395,7 @@ def is_open(self): sage: RealSet(-oo, +oo).is_open() True """ - return all(not i.lower_closed() - and not i.upper_closed() - for i in self._intervals) + return all(not i.lower_closed() and not i.upper_closed() for i in self._intervals) def is_closed(self): """ @@ -2424,9 +2414,7 @@ def is_closed(self): sage: RealSet(-oo, +oo).is_closed() True """ - return all((i.lower_closed() or i.lower() is minus_infinity) - and (i.upper_closed() or i.upper() is infinity) - for i in self._intervals) + return all((i.lower_closed() or i.lower() is minus_infinity) and (i.upper_closed() or i.upper() is infinity) for i in self._intervals) def closure(self): """ @@ -2683,9 +2671,9 @@ def simplest_rational(self): if interval.contains(0): return QQ(0) if lower == minus_infinity: - lower = upper - 2 # to contain at least 1 integer + lower = upper - 2 # to contain at least 1 integer elif upper == infinity: - upper = lower + 2 # to contain at least 1 integer + upper = lower + 2 # to contain at least 1 integer rs_field = RIF(lower, upper) lo_open = not interval.lower_closed() @@ -2813,8 +2801,8 @@ def _sympy_(self): from sympy import Reals, Union from sage.interfaces.sympy import sympy_init + sympy_init() if self.is_universe(): return Reals - return Union(*[interval._sympy_() - for interval in self._intervals]) + return Union(*[interval._sympy_() for interval in self._intervals]) diff --git a/src/sage/sets/set.py b/src/sage/sets/set.py index a7410993713..4a18804eca4 100644 --- a/src/sage/sets/set.py +++ b/src/sage/sets/set.py @@ -337,10 +337,9 @@ def _test_as_set_object(self, tester=None, **options): set_self = Set(self) if set_self is not self: from sage.misc.sage_unittest import TestSuite + tester.info("\n Running the test suite of Set(self)") - TestSuite(set_self).run(skip='_test_pickling', # see Issue #32025 - verbose=tester._verbose, - prefix=tester._prefix + " ") + TestSuite(set_self).run(skip='_test_pickling', verbose=tester._verbose, prefix=tester._prefix + " ") # see Issue #32025 tester.info(tester._prefix + " ", newline=False) @@ -488,6 +487,7 @@ def __init__(self, X, category=None): and 'Integer Ring' """ from sage.rings.integer import Integer + if isinstance(X, (int, Integer)): # The coercion model will try to call Set_object(0) raise ValueError('underlying object cannot be an integer') @@ -689,6 +689,7 @@ def cardinality(self): except (AttributeError, NotImplementedError): pass from sage.rings.integer import Integer + try: return Integer(len(self.__object)) except TypeError: @@ -786,6 +787,7 @@ def subsets(self, size=None): [{1, 2}, {1, 3}, {2, 3}] """ from sage.combinat.subset import Subsets + return Subsets(self, size) def subsets_lattice(self): @@ -802,24 +804,20 @@ def subsets_lattice(self): Finite lattice containing 1 elements """ if not self.is_finite(): - raise NotImplementedError( - "this method is only implemented for finite sets") + raise NotImplementedError("this method is only implemented for finite sets") from sage.combinat.posets.lattices import FiniteLatticePoset from sage.graphs.digraph import DiGraph from sage.rings.integer import Integer + n = self.cardinality() # list, contains at position 0 <= i < 2^n # the i-th subset of self - subset_of_index = [Set([self[i] for i in range(n) if v & (1 << i)]) - for v in range(2**n)] + subset_of_index = [Set([self[i] for i in range(n) if v & (1 << i)]) for v in range(2**n)] # list, contains at position 0 <= i < 2^n # the list of indices of all immediate supersets - upper_covers = [[Integer(x | (1 << y)) for y in range(n) if not x & (1 << y)] - for x in range(2**n)] + upper_covers = [[Integer(x | (1 << y)) for y in range(n) if not x & (1 << y)] for x in range(2**n)] # DiGraph, every subset points to all immediate supersets - D = DiGraph({subset_of_index[v]: - [subset_of_index[w] for w in upper_covers[v]] - for v in range(2**n)}) + D = DiGraph({subset_of_index[v]: [subset_of_index[w] for w in upper_covers[v]] for v in range(2**n)}) # Lattice poset, defined by hasse diagram D L = FiniteLatticePoset(hasse_diagram=D) return L @@ -837,6 +835,7 @@ def _sympy_(self): Integers """ from sage.interfaces.sympy import sympy_init + sympy_init() return self.__object._sympy_() @@ -845,6 +844,7 @@ class Set_object_enumerated(Set_object): """ A finite enumerated set. """ + def __init__(self, X, category=None): r""" Initialize ``self``. @@ -899,6 +899,7 @@ def cardinality(self): 998244353 """ from sage.rings.integer import Integer + o = self.object() if o is self: return Integer(len(self.set())) @@ -970,11 +971,11 @@ def _repr_(self): try: if self.cardinality() > 20: from itertools import islice + o = self.object() l = list(islice(o, 0, 20)) s = "{" + ", ".join(map(repr, l)) + ", …}" - assert len(l) == 20, (f"incorrect cardinality {self.cardinality()} " - f"reported for object type {type(self)} containing {l}") + assert len(l) == 20, f"incorrect cardinality {self.cardinality()} " f"reported for object type {type(self)} containing {l}" if o is not self: # safeguard infinite loop if subclass is weird s = f"Set of elements of {o!r} = {s}" return s @@ -1294,6 +1295,7 @@ def _sympy_(self): from sympy import EmptySet, Set from sage.interfaces.sympy import sympy_init + sympy_init() if self.is_empty(): return EmptySet @@ -1418,6 +1420,7 @@ class Set_object_union(Set_object_binary): """ A formal union of two sets. """ + def __init__(self, X, Y, category=None): r""" Initialize ``self``. @@ -1496,8 +1499,7 @@ def __richcmp__(self, right, op): return rich_to_bool(op, -1) if not isinstance(right, Set_object_union): return rich_to_bool(op, -1) - if self._X == right._X and self._Y == right._Y or \ - self._X == right._Y and self._Y == right._X: + if self._X == right._X and self._Y == right._Y or self._X == right._Y and self._Y == right._X: return rich_to_bool(op, 0) return rich_to_bool(op, -1) @@ -1565,6 +1567,7 @@ def _sympy_(self): from sympy import Union from sage.interfaces.sympy import sympy_init + sympy_init() return Union(self._X._sympy_(), self._Y._sympy_()) @@ -1605,6 +1608,7 @@ class Set_object_intersection(Set_object_binary): """ Formal intersection of two sets. """ + def __init__(self, X, Y, category=None): r""" Initialize ``self``. @@ -1700,8 +1704,7 @@ def __richcmp__(self, right, op): return rich_to_bool(op, -1) if not isinstance(right, Set_object_intersection): return rich_to_bool(op, -1) - if self._X == right._X and self._Y == right._Y or \ - self._X == right._Y and self._Y == right._X: + if self._X == right._X and self._Y == right._Y or self._X == right._Y and self._Y == right._X: return rich_to_bool(op, 0) return rich_to_bool(op, -1) @@ -1780,6 +1783,7 @@ def _sympy_(self): from sympy import Intersection from sage.interfaces.sympy import sympy_init + sympy_init() return Intersection(self._X._sympy_(), self._Y._sympy_()) @@ -1788,6 +1792,7 @@ class Set_object_difference(Set_object_binary): """ Formal difference of two sets. """ + def __init__(self, X, Y, category=None): r""" Initialize ``self``. @@ -1961,6 +1966,7 @@ def _sympy_(self): from sympy import Complement from sage.interfaces.sympy import sympy_init + sympy_init() return Complement(self._X._sympy_(), self._Y._sympy_()) @@ -1969,6 +1975,7 @@ class Set_object_symmetric_difference(Set_object_binary): """ Formal symmetric difference of two sets. """ + def __init__(self, X, Y, category=None): r""" Initialize ``self``. @@ -2045,8 +2052,7 @@ def __richcmp__(self, right, op): return rich_to_bool(op, -1) if not isinstance(right, Set_object_symmetric_difference): return rich_to_bool(op, -1) - if self._X == right._X and self._Y == right._Y or \ - self._X == right._Y and self._Y == right._X: + if self._X == right._X and self._Y == right._Y or self._X == right._Y and self._Y == right._X: return rich_to_bool(op, 0) return rich_to_bool(op, -1) @@ -2108,8 +2114,7 @@ def __contains__(self, x): sage: 3 in X False """ - return ((x in self._X and x not in self._Y) - or (x in self._Y and x not in self._X)) + return (x in self._X and x not in self._Y) or (x in self._Y and x not in self._X) @cached_method def _sympy_(self): @@ -2129,5 +2134,6 @@ def _sympy_(self): from sympy import SymmetricDifference from sage.interfaces.sympy import sympy_init + sympy_init() return SymmetricDifference(self._X._sympy_(), self._Y._sympy_()) diff --git a/src/sage/sets/set_from_iterator.py b/src/sage/sets/set_from_iterator.py index 098e3ae325c..fdcca4841d6 100644 --- a/src/sage/sets/set_from_iterator.py +++ b/src/sage/sets/set_from_iterator.py @@ -47,6 +47,7 @@ sage: f(100) {0, 1, 2, 3, 4, ...} """ + # **************************************************************************** # Copyright (C) 2012 Vincent Delecroix # @@ -145,6 +146,7 @@ class EnumeratedSetFromIterator(Parent): In order to make the ``TestSuite`` works, the elements of the set should have parents. """ + def __init__(self, f, args=None, kwds=None, name=None, category=None, cache=False): """ TESTS:: @@ -169,9 +171,7 @@ def __init__(self, f, args=None, kwds=None, name=None, category=None, cache=Fals self._kwds = kwds if cache: - self._cache = lazy_list(iter(self._func( - *getattr(self, '_args', ()), - **getattr(self, '_kwds', {})))) + self._cache = lazy_list(iter(self._func(*getattr(self, '_args', ()), **getattr(self, '_kwds', {})))) def __hash__(self): r""" @@ -188,6 +188,7 @@ def __hash__(self): return hash(self._cache[:13]) except AttributeError: from itertools import islice + return hash(tuple(islice(self, 13))) def __reduce__(self): @@ -210,14 +211,7 @@ def __reduce__(self): sage: E == F True """ - return (EnumeratedSetFromIterator, - (self._func, # func - getattr(self, '_args', None), # args - getattr(self, '_kwds', None), # kwds - self.get_custom_name(), # name - self.category(), # category - hasattr(self, '_cache')) # cache - ) + return (EnumeratedSetFromIterator, (self._func, getattr(self, '_args', None), getattr(self, '_kwds', None), self.get_custom_name(), self.category(), hasattr(self, '_cache'))) # func # args # kwds # name # category # cache def _repr_(self): r""" @@ -301,15 +295,14 @@ def __eq__(self, other): if isinstance(other, EnumeratedSetFromIterator): # trick to allow equality between infinite sets # this assume that the function does not return randomized data! - if (self._func == other._func and - getattr(self, '_args', None) == getattr(other, '_args', None) and - getattr(self, '_kwds', None) == getattr(other, '_kwds', None)): + if self._func == other._func and getattr(self, '_args', None) == getattr(other, '_args', None) and getattr(self, '_kwds', None) == getattr(other, '_kwds', None): return True if other in EnumeratedSets(): # TODO: think about what should be done at that point if self not in FiniteEnumeratedSets() and other not in FiniteEnumeratedSets(): import warnings + warnings.warn("Testing equality of infinite sets which will not end in case of equality") i1 = iter(self) @@ -439,9 +432,8 @@ def clear_cache(self): False """ if hasattr(self, '_cache'): - self._cache = lazy_list(iter(self._func( - *getattr(self, '_args', ()), - **getattr(self, '_kwds', {})))) + self._cache = lazy_list(iter(self._func(*getattr(self, '_args', ()), **getattr(self, '_kwds', {})))) + # # Decorators @@ -456,6 +448,7 @@ class Decorator: The method needs to be stored in the attribute ``self.f`` """ + def _instancedoc_(self): """ Provide documentation for the wrapped function. @@ -473,6 +466,7 @@ def _instancedoc_(self): """ # Duplicates sage.misc.cachefunc.CachedFunction._instancedoc_ from sage.misc.sageinspect import sage_getsourcelines, sage_getfile_relative, _extract_embedded_position + f = self.f doc = f.__doc__ or '' if _extract_embedded_position(doc) is None: @@ -501,6 +495,7 @@ def is_square(self): return mpq_sgn(self.value) >= 0 and mpz_perfect_square_p(mpq_numref(self.value)) and mpz_perfect_square_p(mpq_denref(self.value)) """ from sage.misc.sageinspect import sage_getsource + return sage_getsource(self.f) def _sage_src_lines_(self): @@ -522,6 +517,7 @@ def _sage_src_lines_(self): ' if not gens:\n' """ from sage.misc.sageinspect import sage_getsourcelines + return sage_getsourcelines(self.f) def _sage_argspec_(self): @@ -541,6 +537,7 @@ def _sage_argspec_(self): kwonlyargs=[], kwonlydefaults=None, annotations={}) """ from sage.misc.sageinspect import sage_getargspec + return sage_getargspec(self.f) def __call__(self, *args, **kwds): @@ -643,6 +640,7 @@ class EnumeratedSetFromIterator_function_decorator(Decorator): sage: Graphs(10) is Graphs(10) # needs sage.graphs False """ + def __init__(self, f=None, name=None, **options): r""" Initialize ``self``. @@ -699,14 +697,11 @@ def __call__(self, *args, **kwds): # potential global options if args == (): - f, = kwds.values() + (f,) = kwds.values() else: assert len(args) == 1 f = args[0] - return EnumeratedSetFromIterator_function_decorator( - f, - name=getattr(self, 'name', None), - **self.options) + return EnumeratedSetFromIterator_function_decorator(f, name=getattr(self, 'name', None), **self.options) set_from_function = EnumeratedSetFromIterator_function_decorator @@ -728,6 +723,7 @@ class EnumeratedSetFromIterator_method_caller(Decorator): - ``options`` -- any option accepted by :class:`EnumeratedSetFromIterator` """ + def __init__(self, inst, f, name=None, **options): r""" Initialize ``self``. @@ -833,10 +829,7 @@ def __get__(self, inst, cls): sage: B.f(b,2) {2, 3, 4, 5, 6, ...} """ - return EnumeratedSetFromIterator_method_caller( - inst, self.f, - self.name, - **self.options) + return EnumeratedSetFromIterator_method_caller(inst, self.f, self.name, **self.options) class EnumeratedSetFromIterator_method_decorator: @@ -908,6 +901,7 @@ class EnumeratedSetFromIterator_method_decorator: It is not yet possible to use ``set_from_method`` in conjunction with ``cached_method``. """ + def __init__(self, f=None, **options): r""" Initialize ``self``. @@ -997,6 +991,7 @@ class DummyExampleForPicklingTest: sage: DummyExampleForPicklingTest().f() {10, 11, 12, 13, 14, ...} """ + start = 10 stop = 100 @@ -1017,4 +1012,5 @@ def f(self): {4, 5, 6, 7, 8, ...} """ from sage.arith.srange import xsrange + return xsrange(self.start, self.stop) diff --git a/src/sage/sets/totally_ordered_finite_set.py b/src/sage/sets/totally_ordered_finite_set.py index 757146ed323..6ca2288c14f 100644 --- a/src/sage/sets/totally_ordered_finite_set.py +++ b/src/sage/sets/totally_ordered_finite_set.py @@ -5,6 +5,7 @@ - Stepan Starosta (2012): Initial version """ + # **************************************************************************** # Copyright (C) 2012 Stepan Starosta # @@ -41,6 +42,7 @@ class TotallyOrderedFiniteSetElement(Element): sage: x.parent() {2, 7} """ + def __init__(self, parent, data): r""" TESTS:: @@ -227,6 +229,7 @@ class TotallyOrderedFiniteSet(FiniteEnumeratedSet): sage: TotallyOrderedFiniteSet([1,1,2,1,2,2,5,4]) {1, 2, 5, 4} """ + Element = TotallyOrderedFiniteSetElement @staticmethod @@ -252,10 +255,7 @@ def __classcall__(cls, iterable, facade=True): if x not in seen: elements.append(x) seen.add(x) - return super(FiniteEnumeratedSet, cls).__classcall__( - cls, - tuple(elements), - facade) + return super(FiniteEnumeratedSet, cls).__classcall__(cls, tuple(elements), facade) def __init__(self, elements, facade=True): """ diff --git a/src/sage/stats/all.py b/src/sage/stats/all.py index 34b229fa8ac..4198953b45a 100644 --- a/src/sage/stats/all.py +++ b/src/sage/stats/all.py @@ -1,11 +1,12 @@ import sage.stats.distributions.catalog as distributions from sage.stats.r import ttest -from sage.stats.basic_stats import (mean, mode, std, variance, median, moving_average) +from sage.stats.basic_stats import mean, mode, std, variance, median, moving_average from sage.stats.hmm import all as hmm # We lazy_import the following modules since they import numpy which # slows down sage startup from sage.misc.lazy_import import lazy_import + lazy_import("sage.stats.time_series", ["TimeSeries", "autoregressive_fit"]) lazy_import("sage.stats.intlist", ["IntList"]) diff --git a/src/sage/stats/basic_stats.py b/src/sage/stats/basic_stats.py index 2703fa050c0..9fc7ce44b95 100644 --- a/src/sage/stats/basic_stats.py +++ b/src/sage/stats/basic_stats.py @@ -29,6 +29,7 @@ - Andrew Hou (11/06/2009) """ + # *********************************************************************** # Copyright (C) 2009, Andrew Hou # @@ -351,7 +352,7 @@ def variance(v, bias=False): mu = mean(v) for vi in v: - x += (vi - mu)**2 + x += (vi - mu) ** 2 if bias: # population variance if isinstance(x, int): @@ -359,8 +360,8 @@ def variance(v, bias=False): return x / len(v) # sample variance if isinstance(x, int): - return x / ZZ(len(v)-1) - return x / (len(v)-1) + return x / ZZ(len(v) - 1) + return x / (len(v) - 1) def median(v): @@ -411,9 +412,9 @@ def median(v): return NaN values = sorted(v) if len(values) % 2: - return values[((len(values))+1)//2-1] - lower = values[(len(values)+1)//2-1] - upper = values[len(values)//2] + return values[((len(values)) + 1) // 2 - 1] + lower = values[(len(values) + 1) // 2 - 1] + upper = values[len(values) // 2] return (lower + upper) / ZZ(2) @@ -467,7 +468,7 @@ def moving_average(v, n): if not v: return v if isinstance(v, TimeSeries): - return v.simple_moving_average(n)[n - 1:] + return v.simple_moving_average(n)[n - 1 :] n = int(n) if n <= 0: raise ValueError("n must be positive") diff --git a/src/sage/stats/distributions/all.py b/src/sage/stats/distributions/all.py index d37a8563ec6..bc2fe575c49 100644 --- a/src/sage/stats/distributions/all.py +++ b/src/sage/stats/distributions/all.py @@ -1,6 +1,7 @@ # We lazy_import the following modules since they import numpy which # slows down sage startup from sage.misc.lazy_import import lazy_import + lazy_import("sage.stats.distributions.discrete_gaussian_integer", ["DiscreteGaussianDistributionIntegerSampler"]) lazy_import("sage.stats.distributions.discrete_gaussian_lattice", ["DiscreteGaussianDistributionLatticeSampler"]) lazy_import("sage.stats.distributions.discrete_gaussian_polynomial", ["DiscreteGaussianDistributionPolynomialSampler"]) diff --git a/src/sage/stats/distributions/catalog.py b/src/sage/stats/distributions/catalog.py index 8ae97fb24c4..1cf66578a32 100644 --- a/src/sage/stats/distributions/catalog.py +++ b/src/sage/stats/distributions/catalog.py @@ -17,6 +17,7 @@ sage: from sage.stats.distributions.catalog import * """ + # **************************************************************************** # Copyright (C) 2024 Gareth Ma # @@ -27,6 +28,7 @@ # **************************************************************************** from sage.misc.lazy_import import lazy_import + lazy_import("sage.stats.distributions.discrete_gaussian_integer", ["DiscreteGaussianDistributionIntegerSampler"]) lazy_import("sage.stats.distributions.discrete_gaussian_lattice", ["DiscreteGaussianDistributionLatticeSampler"]) lazy_import("sage.stats.distributions.discrete_gaussian_polynomial", ["DiscreteGaussianDistributionPolynomialSampler"]) diff --git a/src/sage/stats/distributions/discrete_gaussian_lattice.py b/src/sage/stats/distributions/discrete_gaussian_lattice.py index e846888eb35..e16b89b5e1f 100644 --- a/src/sage/stats/distributions/discrete_gaussian_lattice.py +++ b/src/sage/stats/distributions/discrete_gaussian_lattice.py @@ -27,6 +27,7 @@ sage: a.parent() Ambient free module of rank 10 over the principal ideal domain Integer Ring """ + # ****************************************************************************** # # DGS - Discrete Gaussian Samplers @@ -152,6 +153,7 @@ class DiscreteGaussianDistributionLatticeSampler(SageObject): .. automethod:: __init__ .. automethod:: __call__ """ + @staticmethod def compute_precision(precision, sigma): r""" @@ -276,6 +278,7 @@ def _normalisation_factor_zz(self, tau=None, prec=None): ... NotImplementedError: lattice must be integral """ + # If σ > 1: # We use the Fourier transform g(t) of f(x) = exp(-k^2 / 2σ^2), but # taking the norm of vector t^2 as input, and with norm_factor factored. @@ -288,7 +291,7 @@ def f_or_hat(x): # RR(1 + 100 * exp(-5.0 * pi^2)) == 0 if sigma > 1: - return R(exp(-pi**2 * (2 * sigma**2) * x)) + return R(exp(-(pi**2) * (2 * sigma**2) * x)) return R(exp(-x / (2 * sigma**2))) @@ -298,16 +301,17 @@ def f_or_hat(x): # is essentially the same, but I can't figure out how to # tweak the `.qfrep` call below correctly. from warnings import warn - warn("Note: `_normalisation_factor_zz` has not been properly " - "implemented for non-spherical distributions.") + + warn("Note: `_normalisation_factor_zz` has not been properly " "implemented for non-spherical distributions.") import itertools from sage.functions.log import log + basis = self.B.LLL() base = vector(ZZ, [v.round() for v in basis.solve_left(self._c)]) # BOUND is the largest integer such that |coords| <= 10^4 # However, this might still drift from true value for larger lattices # So optimally one should fix the TODO above - BOUND = max(1, (self._RR(10**(4 / self.n)).ceil() - 1) // 2) + BOUND = max(1, (self._RR(10 ** (4 / self.n)).ceil() - 1) // 2) BOUND = min(BOUND, 10) coords = itertools.product(range(-BOUND, BOUND + 1), repeat=self.n) return sum(self.f((vector(u) + base) * self.B) for u in coords) @@ -322,13 +326,11 @@ def f_or_hat(x): raise NotImplementedError("center must be at zero and basis must be trivial") sigma = self._sigma - prec = DiscreteGaussianDistributionLatticeSampler.compute_precision( - prec, sigma - ) + prec = DiscreteGaussianDistributionLatticeSampler.compute_precision(prec, sigma) R = RealField(prec=prec) if sigma > 1: det = self.B.det() - norm_factor = (sigma * sqrt(2 * pi))**self.n / det + norm_factor = (sigma * sqrt(2 * pi)) ** self.n / det else: det = 1 norm_factor = 1 @@ -655,9 +657,7 @@ def _precompute_data(self): self.B2 = Sigma2.cholesky().T self.B2_B_inv = self.B2 * self.B_inv except ValueError: - raise ValueError("Σ₂ is not positive definite. Is your " - f"r(={self.r}) too large? It should be at most " - f"{self._maximal_r()}") + raise ValueError("Σ₂ is not positive definite. Is your " f"r(={self.r}) too large? It should be at most " f"{self._maximal_r()}") def __call__(self): r""" diff --git a/src/sage/stats/distributions/discrete_gaussian_polynomial.py b/src/sage/stats/distributions/discrete_gaussian_polynomial.py index c3931eee94f..05818536a6e 100644 --- a/src/sage/stats/distributions/discrete_gaussian_polynomial.py +++ b/src/sage/stats/distributions/discrete_gaussian_polynomial.py @@ -21,6 +21,7 @@ sage: mean(l), sqrt(64)*sigma # abs tol 5e-1 # needs numpy sage.symbolic (24.0, 24.0) """ + # ****************************************************************************** # # DGS - Discrete Gaussian Samplers @@ -80,6 +81,7 @@ class DiscreteGaussianDistributionPolynomialSampler(SageObject): .. automethod:: __init__ .. automethod:: __call__ """ + def __init__(self, P, n, sigma): r""" Construct a sampler for univariate polynomials of degree ``n-1`` diff --git a/src/sage/stats/hmm/all.py b/src/sage/stats/hmm/all.py index 4666e022fac..c40907e5b6e 100644 --- a/src/sage/stats/hmm/all.py +++ b/src/sage/stats/hmm/all.py @@ -7,8 +7,8 @@ # We lazy_import the following modules since they import numpy which slows down sage startup from sage.misc.lazy_import import lazy_import + lazy_import("sage.stats.hmm.hmm", ["DiscreteHiddenMarkovModel"]) -lazy_import("sage.stats.hmm.chmm", [ - "GaussianHiddenMarkovModel", "GaussianMixtureHiddenMarkovModel"]) +lazy_import("sage.stats.hmm.chmm", ["GaussianHiddenMarkovModel", "GaussianMixtureHiddenMarkovModel"]) lazy_import("sage.stats.hmm.distributions", ["GaussianMixtureDistribution"]) del lazy_import diff --git a/src/sage/stats/r.py b/src/sage/stats/r.py index 63398fb1a44..fb476d8b5d6 100644 --- a/src/sage/stats/r.py +++ b/src/sage/stats/r.py @@ -5,6 +5,7 @@ sage: import rpy2 # optional - rpy2 """ + # **************************************************************************** # Copyright (C) 2007 William Stein # 2007 Mike Hansen diff --git a/src/sage/structure/all.py b/src/sage/structure/all.py index fc4a1ce133e..3f79a9b1638 100644 --- a/src/sage/structure/all.py +++ b/src/sage/structure/all.py @@ -6,13 +6,7 @@ from sage.structure.sage_object import SageObject -from sage.structure.element import ( - canonical_coercion, - coercion_model, - get_coercion_model, - coercion_traceback, - parent -) +from sage.structure.element import canonical_coercion, coercion_model, get_coercion_model, coercion_traceback, parent from sage.structure.parent import Parent @@ -25,5 +19,6 @@ from sage.structure.element_wrapper import ElementWrapper from sage.misc.lazy_import import lazy_import + lazy_import('sage.structure.formal_sum', ['FormalSums', 'FormalSum']) del lazy_import diff --git a/src/sage/structure/category_object.pyi b/src/sage/structure/category_object.pyi index afd5979baba..910279d2ed5 100644 --- a/src/sage/structure/category_object.pyi +++ b/src/sage/structure/category_object.pyi @@ -29,9 +29,7 @@ class CategoryObject(SageObject): def objgen(self) -> tuple[Any, Any]: ... def _first_ngens(self, n: int) -> Any: ... def _defining_names(self) -> Any: ... - def _assign_names( - self, names: NameSpec = None, normalize: bool = True, ngens: int | None = None - ) -> None: ... + def _assign_names(self, names: NameSpec = None, normalize: bool = True, ngens: int | None = None) -> None: ... def variable_names(self) -> tuple[str, ...]: ... def variable_name(self) -> str: ... def _temporarily_change_names(self, names: Any, latex_names: Any) -> Any: ... diff --git a/src/sage/structure/coerce_actions.pyi b/src/sage/structure/coerce_actions.pyi index dd9631e8ef4..42ed5078d11 100644 --- a/src/sage/structure/coerce_actions.pyi +++ b/src/sage/structure/coerce_actions.pyi @@ -42,5 +42,4 @@ class IntegerPowAction(IntegerAction): def _repr_name_(self) -> str: ... def fast_mul(a: Any, n: int) -> Any: ... - def fast_mul_long(a: Any, s: int) -> Any: ... diff --git a/src/sage/structure/coerce_exceptions.py b/src/sage/structure/coerce_exceptions.py index 5859831e4fa..83f248ff93f 100644 --- a/src/sage/structure/coerce_exceptions.py +++ b/src/sage/structure/coerce_exceptions.py @@ -19,4 +19,5 @@ class CoercionException(TypeError): implemented/appropriate, but if there are other things to try not to immediately abort to the user. """ + pass diff --git a/src/sage/structure/coerce_maps.pyi b/src/sage/structure/coerce_maps.pyi index 247e1e1c5ca..6686fff595f 100644 --- a/src/sage/structure/coerce_maps.pyi +++ b/src/sage/structure/coerce_maps.pyi @@ -31,9 +31,7 @@ class CCallableConvertMap_class: def _repr_type(self) -> str: ... def CCallableConvertMap(domain: Any, codomain: Any, func: Any, name: Optional[str]) -> CCallableConvertMap_class: ... - def _ccall_test_function(codomain: Any, x: Any) -> Any: ... - def test_CCallableConvertMap(domain: Any, name: Optional[str] = None) -> CCallableConvertMap_class: ... class ListMorphism: diff --git a/src/sage/structure/dynamic_class.py b/src/sage/structure/dynamic_class.py index 9ab512c668b..d20dc7fffae 100644 --- a/src/sage/structure/dynamic_class.py +++ b/src/sage/structure/dynamic_class.py @@ -125,8 +125,7 @@ class MyPermutation(UniqueRepresentation, PermutationCycleType, PosetElement, Gr from sage.misc.inherit_comparison import InheritComparisonMetaclass, InheritComparisonClasscallMetaclass -def dynamic_class(name, bases, cls=None, reduction=None, doccls=None, - prepend_cls_bases=True, cache=True): +def dynamic_class(name, bases, cls=None, reduction=None, doccls=None, prepend_cls_bases=True, cache=True): r""" INPUT: @@ -466,6 +465,7 @@ class DynamicMetaclass(type): """ A metaclass implementing an appropriate reduce-by-construction method """ + def _sage_src_lines_(self): r""" Get the source lines of the dynamic class. This defers to the @@ -487,6 +487,7 @@ def _sage_src_lines_(self): except AttributeError: raise NotImplementedError("no _doccls found") from sage.misc.sageinspect import sage_getsourcelines + return sage_getsourcelines(doccls) def __reduce__(self): @@ -522,10 +523,7 @@ class DynamicInheritComparisonClasscallMetaclass(DynamicMetaclass, InheritCompar # This registers the appropriate reduction methods (see Issue #5985) -for M in [DynamicMetaclass, - DynamicClasscallMetaclass, - DynamicInheritComparisonMetaclass, - DynamicInheritComparisonClasscallMetaclass]: +for M in [DynamicMetaclass, DynamicClasscallMetaclass, DynamicInheritComparisonMetaclass, DynamicInheritComparisonClasscallMetaclass]: copyreg.pickle(M, M.__reduce__) @@ -533,6 +531,7 @@ class TestClass: """ A class used for checking that introspection works """ + def bla(): """ bla ... diff --git a/src/sage/structure/factorization.py b/src/sage/structure/factorization.py index c01e88f415c..36f80096d78 100644 --- a/src/sage/structure/factorization.py +++ b/src/sage/structure/factorization.py @@ -220,6 +220,7 @@ class Factorization(SageObject): ... TypeError: no conversion of this rational to integer """ + def __init__(self, x, unit=None, cr=False, sort=True, simplify=True): """ Create a :class:`Factorization` object. @@ -300,6 +301,7 @@ def __init__(self, x, unit=None, cr=False, sort=True, simplify=True): (Ambient free module of rank 3 over the principal ideal domain Integer Ring)^2 """ from sage.rings.integer import Integer + x = [(p, Integer(e)) for (p, e) in x] try: @@ -483,8 +485,7 @@ def __copy__(self): """ # No need to sort, since the factorization is already sorted # in whatever order is desired. - return Factorization(self.__x, unit=self.__unit, cr=self.__cr, - sort=False, simplify=False) + return Factorization(self.__x, unit=self.__unit, cr=self.__cr, sort=False, simplify=False) def __deepcopy__(self, memo): r""" @@ -523,8 +524,8 @@ def __deepcopy__(self, memo): ([1, 2])^5 * ([5, 6])^10 """ import copy - return Factorization(copy.deepcopy(list(self), memo), - cr=self.__cr, sort=False, simplify=False) + + return Factorization(copy.deepcopy(list(self), memo), cr=self.__cr, sort=False, simplify=False) def universe(self): r""" @@ -657,6 +658,7 @@ def simplify(self): repeat = False simp = [] import itertools + for obj, agroup in itertools.groupby(list(self), lambda x: x[0]): xs = list(agroup) if len(xs) > 1: @@ -722,6 +724,7 @@ def sort(self, key=None): def sort_key(f): return (f[0].dimension(), f[1], f[0]) + except (AttributeError, NotImplementedError, TypeError): pass elif hasattr(a, 'degree'): @@ -730,6 +733,7 @@ def sort_key(f): def sort_key(f): return (f[0].degree(), f[1], f[0]) + except (AttributeError, NotImplementedError, TypeError): pass @@ -844,8 +848,7 @@ def _repr_(self): mul += '\n' x = self.__x[0][0] try: - atomic = (isinstance(x, int) or - self.universe()._repr_option('element_is_atomic')) + atomic = isinstance(x, int) or self.universe()._repr_option('element_is_atomic') except AttributeError: atomic = False @@ -891,8 +894,7 @@ def _latex_(self): if len(self) == 0: return self.__unit._latex_() try: - atomic = (isinstance(self.__x[0][0], int) or - self.universe()._repr_option('element_is_atomic')) + atomic = isinstance(self.__x[0][0], int) or self.universe()._repr_option('element_is_atomic') except AttributeError: atomic = False s = '' @@ -1011,8 +1013,7 @@ def __neg__(self): 1 """ unit = -self.__unit - return Factorization(list(self), unit, self.__cr, - sort=False, simplify=False) + return Factorization(list(self), unit, self.__cr, sort=False, simplify=False) def __rmul__(self, left): """ @@ -1134,6 +1135,7 @@ def __pow__(self, n): x^3 * y^2 * x^4 * y^2 * x """ from sage.rings.integer import Integer + if not isinstance(n, Integer): try: n = Integer(n) @@ -1144,12 +1146,12 @@ def __pow__(self, n): if n == 0: return Factorization([]) if self.is_commutative(): - return Factorization([(p, n * e) for p, e in self], unit=self.unit()**n, - cr=self.__cr, sort=False, simplify=False) + return Factorization([(p, n * e) for p, e in self], unit=self.unit() ** n, cr=self.__cr, sort=False, simplify=False) if n < 0: self = ~self n = -n from sage.arith.power import generic_power + return generic_power(self, n) def __invert__(self): @@ -1169,8 +1171,7 @@ def __invert__(self): sage: F^-1 # needs sage.combinat sage.modules (1/2) * x^-1 * y^-2 * x^-3 """ - return Factorization([(p, -e) for p, e in reversed(self)], - cr=self._cr(), unit=self.unit()**(-1)) + return Factorization([(p, -e) for p, e in reversed(self)], cr=self._cr(), unit=self.unit() ** (-1)) def __truediv__(self, other): r""" @@ -1274,6 +1275,7 @@ def value(self): x^3*y^2*x """ from sage.misc.misc_c import prod + return prod([p**e for p, e in self.__x], self.__unit) # Two aliases for ``value(self)``. @@ -1402,8 +1404,7 @@ def radical(self): """ if not all(e > 0 for _, e in self.__x): raise ValueError("all exponents in the factorization must be positive") - return Factorization([(p, 1) for p, _ in self.__x], unit=self.unit().parent()(1), - cr=self.__cr, sort=False, simplify=False) + return Factorization([(p, 1) for p, _ in self.__x], unit=self.unit().parent()(1), cr=self.__cr, sort=False, simplify=False) def radical_value(self): """ @@ -1429,6 +1430,7 @@ def radical_value(self): if not all(e > 0 for _, e in self.__x): raise ValueError("all exponents in the factorization must be positive") from sage.misc.misc_c import prod + return prod([p for p, _ in self.__x]) def is_complete_factorization(self): diff --git a/src/sage/structure/factorization_integer.py b/src/sage/structure/factorization_integer.py index 03a8457ce57..325b53bfd7b 100644 --- a/src/sage/structure/factorization_integer.py +++ b/src/sage/structure/factorization_integer.py @@ -27,8 +27,7 @@ class IntegerFactorization(Factorization): - Sebastian Pancratz (2010-01-10) """ - def __init__(self, x, unit=None, cr=False, sort=True, simplify=True, - unsafe=False): + def __init__(self, x, unit=None, cr=False, sort=True, simplify=True, unsafe=False): """ Set ``self`` to the factorization object with list ``x``, which must be a sorted list of pairs, where each pair contains @@ -79,9 +78,7 @@ def __init__(self, x, unit=None, cr=False, sort=True, simplify=True, self.simplify() else: - super().__init__(x, unit=unit, cr=cr, - sort=sort, - simplify=simplify) + super().__init__(x, unit=unit, cr=cr, sort=sort, simplify=simplify) def __sort__(self, key=None): """ diff --git a/src/sage/structure/formal_sum.py b/src/sage/structure/formal_sum.py index 852ca087d5e..36a57a42729 100644 --- a/src/sage/structure/formal_sum.py +++ b/src/sage/structure/formal_sum.py @@ -83,6 +83,7 @@ class FormalSum(ModuleElement): """ A formal sum over a ring. """ + def __init__(self, x, parent=None, check=True, reduce=True): """ INPUT: @@ -140,7 +141,7 @@ def __init__(self, x, parent=None, check=True, reduce=True): assert isinstance(parent, parent.category().parent_class) if reduce: # first reduce self.reduce() - if check: # then check + if check: # then check k = parent.base_ring() try: self._data = [(k(t[0]), t[1]) for t in self._data] @@ -205,6 +206,7 @@ def _latex_(self): 2 + 5\cdot \frac{8}{9} - 3\cdot 7 """ from sage.misc.latex import repr_lincomb + symbols = [z[1] for z in self] coeffs = [z[0] for z in self] return repr_lincomb(symbols, coeffs) @@ -274,7 +276,7 @@ def _lmul_(self, s): sage: FormalSum([(1,3/7),(-2,5)])*(-3) -3*3/7 + 6*5 """ - return self.__class__([(c*s, x) for (c, x) in self], check=False, parent=self.parent()) + return self.__class__([(c * s, x) for (c, x) in self], check=False, parent=self.parent()) def _rmul_(self, s): """ @@ -283,7 +285,7 @@ def _rmul_(self, s): sage: -3*FormalSum([(1,3/7),(-2,5)]) -3*3/7 + 6*5 """ - return self.__class__([(s*c, x) for (c, x) in self], check=False, parent=self.parent()) + return self.__class__([(s * c, x) for (c, x) in self], check=False, parent=self.parent()) def __bool__(self) -> bool: """ @@ -341,6 +343,7 @@ class FormalSums(UniqueRepresentation, Module): sage: TestSuite(FormalSums(QQ)).run() """ + Element = FormalSum @staticmethod @@ -390,13 +393,10 @@ def _element_constructor_(self, x, check=True, reduce=True): return x x = x._data if isinstance(x, list): - return self.element_class(x, check=check, - reduce=reduce, parent=self) + return self.element_class(x, check=check, reduce=reduce, parent=self) if x == 0: - return self.element_class([], check=False, - reduce=False, parent=self) - return self.element_class([(self.base_ring()(1), x)], - check=False, reduce=False, parent=self) + return self.element_class([], check=False, reduce=False, parent=self) + return self.element_class([(self.base_ring()(1), x)], check=False, reduce=False, parent=self) def _coerce_map_from_(self, X): r""" @@ -474,8 +474,7 @@ def _an_element_(self, check=False, reduce=False): sage: QQ.an_element() 1/2 """ - return self.element_class([(self.base_ring().an_element(), 1)], - check=check, reduce=reduce, parent=self) + return self.element_class([(self.base_ring().an_element(), 1)], check=check, reduce=reduce, parent=self) formal_sums = FormalSums() diff --git a/src/sage/structure/gens_py.py b/src/sage/structure/gens_py.py index d0b73faba05..2aa2a6e0af2 100644 --- a/src/sage/structure/gens_py.py +++ b/src/sage/structure/gens_py.py @@ -37,28 +37,28 @@ def multiplicative_iterator(M): """ - Iterate over elements of ``M`` using multiplicative generator combinations. + Iterate over elements of ``M`` using multiplicative generator combinations. - The object ``M`` is expected to provide: + The object ``M`` is expected to provide: - - ``M.gens()``: a list/sequence of generators for the finite group. - - ``M(1)``: a callable constructor returning the identity element. - - Each generator ``g`` must implement ``g.multiplicative_order()``. + - ``M.gens()``: a list/sequence of generators for the finite group. + - ``M(1)``: a callable constructor returning the identity element. + - Each generator ``g`` must implement ``g.multiplicative_order()``. - The iterator yields each group element produced by multiplying generator - powers where the exponent of generator ``g`` runs from ``0`` up to - ``g.multiplicative_order() - 1``. + The iterator yields each group element produced by multiplying generator + powers where the exponent of generator ``g`` runs from ``0`` up to + ``g.multiplicative_order() - 1``. - INPUT: + INPUT: - - ``M`` -- a finite multiplicative group-like object + - ``M`` -- a finite multiplicative group-like object - OUTPUT: + OUTPUT: - - elements of ``M`` in a deterministic order + - elements of ``M`` in a deterministic order - If not all generators have finite multiplicative order, an - ``ArithmeticError`` is raised. + If not all generators have finite multiplicative order, an + ``ArithmeticError`` is raised. """ from sage.rings.infinity import infinity @@ -97,28 +97,28 @@ def multiplicative_iterator(M): def abelian_iterator(M): """ - Iterate over elements of ``M`` using additive generator combinations. + Iterate over elements of ``M`` using additive generator combinations. - The object ``M`` is expected to provide: + The object ``M`` is expected to provide: - - ``M.gens()``: a list/sequence of generators for the finite abelian group. - - ``M(0)``: a callable constructor returning the additive identity element. - - Each generator ``g`` must implement ``g.additive_order()``. + - ``M.gens()``: a list/sequence of generators for the finite abelian group. + - ``M(0)``: a callable constructor returning the additive identity element. + - Each generator ``g`` must implement ``g.additive_order()``. - The iterator yields each group element produced by taking sums of - generator multiples where the coefficient of generator ``g`` runs from - ``0`` up to ``g.additive_order() - 1``. + The iterator yields each group element produced by taking sums of + generator multiples where the coefficient of generator ``g`` runs from + ``0`` up to ``g.additive_order() - 1``. - INPUT: + INPUT: - - ``M`` -- a finite additive group-like object + - ``M`` -- a finite additive group-like object - OUTPUT: + OUTPUT: - - elements of ``M`` in a deterministic order + - elements of ``M`` in a deterministic order - If not all generators have finite additive order, an - ``ArithmeticError`` is raised. + If not all generators have finite additive order, an + ``ArithmeticError`` is raised. """ from sage.rings.infinity import infinity diff --git a/src/sage/structure/global_options.py b/src/sage/structure/global_options.py index 09df10f1e51..2201ed1452f 100644 --- a/src/sage/structure/global_options.py +++ b/src/sage/structure/global_options.py @@ -536,6 +536,7 @@ class Option: sage: TestSuite(Partitions.options.display).run() # needs sage.combinat """ + __name__ = 'Option class' def __init__(self, options, name): @@ -971,6 +972,7 @@ class GlobalOptions(metaclass=GlobalOptionsMeta): Current value: espresso """ + __name__ = 'options' def __init__(self, NAME=None, module='', option_class='', doc='', end_doc='', **options): @@ -1029,17 +1031,17 @@ def __init__(self, NAME=None, module='', option_class='', doc='', end_doc='', ** self._name = NAME # initialise the various dictionaries used by GlobalOptions - self._alias = {} # a dictionary of alias for the values of some options - self._alt_names = {} # a dictionary of alternative names for some options + self._alias = {} # a dictionary of alias for the values of some options + self._alt_names = {} # a dictionary of alternative names for some options self._case_sensitive = {} # a dictionary of booleans indicating to check case sensitivity - self._checker = {} # a dictionary of validity checkers for each option + self._checker = {} # a dictionary of validity checkers for each option self.__default_value = {} # a dictionary of the default options self._display_values = {} # a dictionary of the output of the values - self._doc = {} # a dictionary of doc strings, forced by the linked options - self._legal_values = {} # a dictionary of lists of the legal values for each option - self._linked_value = {} # a dictionary of linked to other global options as (link, linked_option) - self._setter = {} # a dictionary of the list of setters - self._value = {} # a dictionary of the current options + self._doc = {} # a dictionary of doc strings, forced by the linked options + self._legal_values = {} # a dictionary of lists of the legal values for each option + self._linked_value = {} # a dictionary of linked to other global options as (link, linked_option) + self._setter = {} # a dictionary of the list of setters + self._value = {} # a dictionary of the current options for option in options: self._add_option(option, options[option]) @@ -1088,8 +1090,7 @@ def __repr__(self): options.sort() width = 1 + max(len(option) for option in options) - txt = '\n'.join(' - {:{}} {}'.format(option + ':', width, self[option]) - for option in options) + txt = '\n'.join(' - {:{}} {}'.format(option + ':', width, self[option]) for option in options) return 'Current options for {}\n{}'.format(self._name, txt) def __call__(self, *get_value, **set_value): @@ -1195,7 +1196,7 @@ def __setitem__(self, option, value): if value == '?': # return help print('%s\nCurrent value: %s' % (self._doc[option], self[option])) - return # we do not want to call the setter below + return # we do not want to call the setter below if option in self._linked_value: link, linked_opt = self._linked_value[option] @@ -1394,9 +1395,9 @@ def _add_option(self, option, specifications): raise TypeError("expected dict as specification of %r, got %r" % (option, specifications)) doc = {} # will be used to build the doc string - self._case_sensitive[option] = True # ``True`` by default + self._case_sensitive[option] = True # ``True`` by default self._legal_values[option] = [] - for spec in sorted(specifications): # NB: options processed alphabetically! + for spec in sorted(specifications): # NB: options processed alphabetically! if spec == 'alias': self._alias[option] = specifications[spec] self._legal_values[option] += list(specifications[spec]) @@ -1412,8 +1413,7 @@ def _add_option(self, option, specifications): self._display_values[option] = {val.lower(): val for val in self._legal_values[option]} self._legal_values[option] = [val.lower() for val in self._legal_values[option]] if option in self._alias: - self._alias[option] = {k.lower(): v.lower() - for k, v in self._alias[option].items()} + self._alias[option] = {k.lower(): v.lower() for k, v in self._alias[option].items()} self._case_sensitive[option] = bool(specifications[spec]) elif spec == 'checker': if not callable(specifications[spec]): @@ -1422,9 +1422,7 @@ def _add_option(self, option, specifications): elif spec == 'default': self.__default_value[option] = specifications[spec] elif spec == 'link_to': - if (isinstance(specifications[spec], tuple) and - len(specifications[spec]) == 2 and - isinstance(specifications[spec][0], GlobalOptions)): + if isinstance(specifications[spec], tuple) and len(specifications[spec]) == 2 and isinstance(specifications[spec][0], GlobalOptions): link, linked_opt = specifications['link_to'] # for sanity if linked_opt in link._value: self._linked_value[option] = specifications['link_to'] @@ -1466,15 +1464,9 @@ def _add_option(self, option, specifications): else: width = max(len(v) for v in doc) + 4 if doc != {} else 4 if len(doc) > 0: - self._doc[option] = '- ``{}`` -- (default: ``{}``)\n{}\n{}\n'.format( - option, self._default_value(option), - ' %s\n' % specifications['description'] if 'description' in specifications else '', - '\n'.join(' - {:{}} -- {}'.format('``' + val + '``', width, doc[val]) - for val in sorted(doc))) + self._doc[option] = '- ``{}`` -- (default: ``{}``)\n{}\n{}\n'.format(option, self._default_value(option), ' %s\n' % specifications['description'] if 'description' in specifications else '', '\n'.join(' - {:{}} -- {}'.format('``' + val + '``', width, doc[val]) for val in sorted(doc))) else: - self._doc[option] = '- ``{}`` -- (default: ``{}``)\n{}'.format( - option, self._default_value(option), - ' %s\n' % specifications['description'] if 'description' in specifications else '') + self._doc[option] = '- ``{}`` -- (default: ``{}``)\n{}'.format(option, self._default_value(option), ' %s\n' % specifications['description'] if 'description' in specifications else '') # sanity check for non-linked options if option not in self._linked_value: @@ -1562,7 +1554,7 @@ def _match_value(self, option, value): ValueError: w is not a valid value for drink in the options for daily meal """ if value == "?": - return value # help on this value + return value # help on this value if option in self._linked_value: link, linked_opt = self._linked_value[option] diff --git a/src/sage/structure/indexed_generators.py b/src/sage/structure/indexed_generators.py index 24f75d956ca..cc85a09449a 100644 --- a/src/sage/structure/indexed_generators.py +++ b/src/sage/structure/indexed_generators.py @@ -1,6 +1,7 @@ """ Indexed Generators """ + # **************************************************************************** # Copyright (C) 2013 Travis Scrimshaw # @@ -128,6 +129,7 @@ class IndexedGenerators: sage: I._repr_generator(2) 'x|2>' """ + def __init__(self, indices, prefix='x', **kwds): """ Initialize ``self``. @@ -145,19 +147,7 @@ def __init__(self, indices, prefix='x', **kwds): # This includes self._repr_option_bracket (kept for backwards # compatibility, declared to be True by default, needs to be # overridden explicitly). - self._print_options = {'prefix': prefix, - 'names': None, - 'bracket': None, - 'latex_bracket': False, - 'latex_prefix': None, - 'latex_names': None, - 'scalar_mult': "*", - 'latex_scalar_mult': None, - 'tensor_symbol': None, - 'string_quotes': True, - 'sorting_key': lambda x: x, - 'sorting_reverse': False, - 'iterate_key': False} + self._print_options = {'prefix': prefix, 'names': None, 'bracket': None, 'latex_bracket': False, 'latex_prefix': None, 'latex_names': None, 'scalar_mult': "*", 'latex_scalar_mult': None, 'tensor_symbol': None, 'string_quotes': True, 'sorting_key': lambda x: x, 'sorting_reverse': False, 'iterate_key': False} # 'bracket': its default value here is None, meaning that # the value of self._repr_option_bracket is used; the default # value of that attribute is True -- see immediately before @@ -487,6 +477,7 @@ def _ascii_art_generator(self, m): a + 2*b """ from sage.typeset.ascii_art import AsciiArt, ascii_art + ret = self._parse_names(m, False) if ret is not None: return ascii_art(ret) @@ -528,6 +519,7 @@ def _unicode_art_generator(self, m): a + 2*b """ from sage.typeset.unicode_art import UnicodeArt, unicode_art + ret = self._parse_names(m, False) if ret is not None: return unicode_art(ret) @@ -620,8 +612,7 @@ def _latex_generator(self, m): # dictionary with left-right pairs of "brackets". put pairs # in here accept \\left and \\right as prefixes. - bracket_d = {"{": "\\}", "[": "]", "(": ")", "\\{": "\\}", - "|": "|", "||": "||"} + bracket_d = {"{": "\\}", "[": "]", "(": ")", "\\{": "\\}", "|": "|", "||": "||"} bracket = self._print_options.get('latex_bracket', False) if bracket is True: left = "\\left[" @@ -674,10 +665,7 @@ def split_index_keywords(kwds): {'base': Rational Field} """ ret = {} - for option in ['prefix', 'latex_prefix', 'bracket', 'latex_bracket', - 'scalar_mult', 'latex_scalar_mult', 'tensor_symbol', - 'sorting_key', 'sorting_reverse', - 'string_quotes']: + for option in ['prefix', 'latex_prefix', 'bracket', 'latex_bracket', 'scalar_mult', 'latex_scalar_mult', 'tensor_symbol', 'sorting_key', 'sorting_reverse', 'string_quotes']: try: ret[option] = kwds.pop(option) except KeyError: @@ -828,8 +816,7 @@ def standardize_names_index_set(names=None, index_set=None, ngens=None): if names is None: # If neither is specified, we make range(ngens) the index set if ngens is None: - raise ValueError("the index_set, names, or number of" - " generators must be specified") + raise ValueError("the index_set, names, or number of" " generators must be specified") index_set = tuple(range(ngens)) else: # If only the names are specified, then we make the indexing set @@ -837,6 +824,7 @@ def standardize_names_index_set(names=None, index_set=None, ngens=None): index_set = tuple(names) from sage.sets.finite_enumerated_set import FiniteEnumeratedSet + if isinstance(index_set, dict): # dict of {name: index} -- not likely to be used if names is not None: raise ValueError("cannot give index_set as a dict and names") @@ -850,13 +838,10 @@ def standardize_names_index_set(names=None, index_set=None, ngens=None): if ngens is None or ngens >= 0: if names is not None: if len(names) != index_set.cardinality(): - raise IndexError("the number of names must equal" - " the size of the indexing set") + raise IndexError("the number of names must equal" " the size of the indexing set") if ngens is not None and len(names) != ngens: - raise IndexError("the number of names must equal the" - " number of generators") + raise IndexError("the number of names must equal the" " number of generators") elif ngens is not None and index_set.cardinality() != ngens: - raise IndexError("the size of the indexing set must equal" - " the number of generators") + raise IndexError("the size of the indexing set must equal" " the number of generators") return (names, index_set) diff --git a/src/sage/structure/list_clone_timings.py b/src/sage/structure/list_clone_timings.py index 92b3b620f38..be0b4b272bf 100644 --- a/src/sage/structure/list_clone_timings.py +++ b/src/sage/structure/list_clone_timings.py @@ -72,6 +72,7 @@ cy_add1_mutable(e) : 625 loops, best of 3: 14.1 µs per loop cy_add1_with(e) : 625 loops, best of 3: 17.5 µs per loop """ + # **************************************************************************** # Copyright (C) 2009-2010 Florent Hivert # @@ -109,8 +110,8 @@ def check(self): ... ValueError: Lists is not increasing """ - for i in range(len(self)-1): - if self[i] >= self[i+1]: + for i in range(len(self) - 1): + if self[i] >= self[i + 1]: raise ValueError("Lists is not increasing") diff --git a/src/sage/structure/mutability.pyi b/src/sage/structure/mutability.pyi index b9c106877a3..f0df348160c 100644 --- a/src/sage/structure/mutability.pyi +++ b/src/sage/structure/mutability.pyi @@ -12,5 +12,4 @@ class Mutability: def __setstate__(self, state: dict[str, Any]) -> None: ... def require_mutable(f: Callable) -> Callable: ... - def require_immutable(f: Callable) -> Callable: ... diff --git a/src/sage/structure/nonexact.py b/src/sage/structure/nonexact.py index 89d8ef88091..d2a02ca3125 100644 --- a/src/sage/structure/nonexact.py +++ b/src/sage/structure/nonexact.py @@ -27,6 +27,7 @@ Subclasses of :class:`Nonexact` which require to change the default precision should implement a method ``set_default_prec``. """ + from sage.rings.integer import Integer @@ -39,6 +40,7 @@ class Nonexact: - ``prec`` -- nonnegative integer representing the default precision of ``self`` (default: 20) """ + def __init__(self, prec=20): if prec < 0: raise ValueError(f"prec (= {prec}) must be nonnegative") diff --git a/src/sage/structure/parent.pyi b/src/sage/structure/parent.pyi index 98b495f7b1d..e3acdd7b5af 100644 --- a/src/sage/structure/parent.pyi +++ b/src/sage/structure/parent.pyi @@ -69,9 +69,7 @@ class Parent[ElementT](CategoryObject): def coerce(self, x: Any) -> ElementT: ... def __bool__(self) -> bool: ... def __getitem__(self, n: int | slice) -> ElementT: ... - def _is_valid_homomorphism_( - self, codomain: Any, im_gens: Any, base_map: Any | None = None - ) -> bool: ... + def _is_valid_homomorphism_(self, codomain: Any, im_gens: Any, base_map: Any | None = None) -> bool: ... def Hom(self, codomain: Any, category: Category | None = None) -> Any: ... def hom( self, @@ -104,12 +102,8 @@ class Parent[ElementT](CategoryObject): def register_embedding(self, embedding: Any) -> None: ... def coerce_embedding(self) -> Any: ... def _generic_coerce_map(self, S: Any) -> Map[Any, Any]: ... - def _generic_convert_map( - self, S: Any, category: Category | None = None - ) -> Map[Any, Any]: ... - def _convert_method_map( - self, S: Any, method_name: str | None = None - ) -> Map[Any, Any]: ... + def _generic_convert_map(self, S: Any, category: Category | None = None) -> Map[Any, Any]: ... + def _convert_method_map(self, S: Any, method_name: str | None = None) -> Map[Any, Any]: ... def _coerce_map_via(self, v: Sequence[Any], S: Any) -> Map[Any, Any]: ... def has_coerce_map_from(self, S: Any) -> bool: ... def _coerce_map_from_(self, S: Any) -> Any: ... @@ -117,9 +111,7 @@ class Parent[ElementT](CategoryObject): def _internal_coerce_map_from(self, S: Any) -> Map[Any, Any] | None: ... def convert_map_from(self, S: Any) -> Map[Any, Any] | None: ... def _internal_convert_map_from(self, S: Any) -> Map[Any, Any] | None: ... - def _convert_map_from_( - self, S: Any - ) -> Map[Any, Any] | Callable[..., Any] | bool | None: ... + def _convert_map_from_(self, S: Any) -> Map[Any, Any] | Callable[..., Any] | bool | None: ... def get_action( self, S: Any, @@ -128,9 +120,7 @@ class Parent[ElementT](CategoryObject): self_el: Any = None, S_el: Any = None, ) -> Any: ... - def _get_action_( - self, S: Any, op: Callable[..., Any], self_on_left: bool - ) -> Any: ... + def _get_action_(self, S: Any, op: Callable[..., Any], self_on_left: bool) -> Any: ... def an_element(self) -> ElementT: ... def _an_element_(self) -> ElementT: ... def is_exact(self) -> bool: ... diff --git a/src/sage/structure/proof/all.py b/src/sage/structure/proof/all.py index 349d130d729..012658a6fd4 100644 --- a/src/sage/structure/proof/all.py +++ b/src/sage/structure/proof/all.py @@ -37,6 +37,7 @@ def arithmetic(t=None): True """ from sage.structure.proof.proof import _proof_prefs + return _proof_prefs.arithmetic(t) @@ -75,6 +76,7 @@ def elliptic_curve(t=None): True """ from sage.structure.proof.proof import _proof_prefs + return _proof_prefs.elliptic_curve(t) @@ -113,6 +115,7 @@ def linear_algebra(t=None): True """ from sage.structure.proof.proof import _proof_prefs + return _proof_prefs.linear_algebra(t) @@ -150,6 +153,7 @@ def number_field(t=None): True """ from sage.structure.proof.proof import _proof_prefs + return _proof_prefs.number_field(t) @@ -187,6 +191,7 @@ def polynomial(t=None): True """ from sage.structure.proof.proof import _proof_prefs + return _proof_prefs.polynomial(t) @@ -236,6 +241,7 @@ def all(t=None): True """ from sage.structure.proof.proof import _proof_prefs + if t is None: return _proof_prefs._require_proof.copy() for s in _proof_prefs._require_proof: diff --git a/src/sage/structure/proof/proof.py b/src/sage/structure/proof/proof.py index 3b0ef70ee2c..1907b0f2dde 100644 --- a/src/sage/structure/proof/proof.py +++ b/src/sage/structure/proof/proof.py @@ -17,6 +17,7 @@ class _ProofPref(SageObject): A ``False`` flag means that the subsystem can use faster methods to return answers that have a very small probability of being wrong. """ + def __init__(self, proof=True): self._require_proof = {} self._require_proof["arithmetic"] = proof @@ -224,8 +225,7 @@ def get_flag(t=None, subsystem=None): False """ if t is None: - if subsystem in ["arithmetic", "elliptic_curve", - "linear_algebra", "number_field", "polynomial"]: + if subsystem in ["arithmetic", "elliptic_curve", "linear_algebra", "number_field", "polynomial"]: return _proof_prefs._require_proof[subsystem] return _proof_prefs._require_proof["other"] return t @@ -251,6 +251,7 @@ class WithProof: sage: proof.arithmetic() True """ + def __init__(self, subsystem, t): """ TESTS:: diff --git a/src/sage/structure/sage_object_test.py b/src/sage/structure/sage_object_test.py index 721c1ad7719..5e401537d57 100644 --- a/src/sage/structure/sage_object_test.py +++ b/src/sage/structure/sage_object_test.py @@ -1,4 +1,3 @@ - import pytest from sage.structure.sage_object import SageObject @@ -15,4 +14,5 @@ def test_sage_unittest_testsuite(self, sage_object: SageObject): """ # TODO: Remove this test as soon as all old test methods are migrated from sage.misc.sage_unittest import TestSuite + TestSuite(sage_object).run(verbose=True, raise_on_failure=True) diff --git a/src/sage/structure/sequence.py b/src/sage/structure/sequence.py index 41ecb581749..f4339d993cd 100644 --- a/src/sage/structure/sequence.py +++ b/src/sage/structure/sequence.py @@ -273,28 +273,32 @@ def Sequence(x, universe=None, check=True, immutable=False, cr=False, cr_str=Non if len(x) == 0: from sage.categories.objects import Objects + universe = Objects() else: import sage.structure.element + if use_sage_types: # convert any Python built-in numerical types to Sage objects x = [sage.structure.coerce.py_scalar_to_element(e) for e in x] # start the pairwise coercion for i in range(len(x) - 1): try: - x[i], x[i+1] = sage.structure.element.canonical_coercion(x[i], x[i+1]) + x[i], x[i + 1] = sage.structure.element.canonical_coercion(x[i], x[i + 1]) except TypeError: from sage.categories.objects import Objects + universe = Objects() x = list(orig_x) check = False # no point break - if universe is None: # no type errors raised. - universe = sage.structure.element.parent(x[len(x)-1]) + if universe is None: # no type errors raised. + universe = sage.structure.element.parent(x[len(x) - 1]) from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence from sage.rings.quotient_ring import QuotientRing_nc + try: # pbori (brial) is optional, so to keep the isinstance() below # working as intended in its absence, we set it equal to the @@ -440,8 +444,8 @@ class Sequence_generic(SageObject, list): sage: v.universe() Finite Field of size 5 """ - def __init__(self, x, universe=None, check=True, immutable=False, - cr=False, cr_str=None, use_sage_types=False): + + def __init__(self, x, universe=None, check=True, immutable=False, cr=False, cr_str=None, use_sage_types=False): r""" Create a sequence. @@ -482,8 +486,7 @@ def __init__(self, x, universe=None, check=True, immutable=False, try: x[i] = universe(x[i]) except TypeError: - raise TypeError("unable to convert {} to an element of {}" - .format(x[i], universe)) + raise TypeError("unable to convert {} to an element of {}".format(x[i], universe)) list.__init__(self, x) self._is_immutable = immutable @@ -551,11 +554,7 @@ def __getitem__(self, n): [1, 2, 3, 4] """ if isinstance(n, slice): - return Sequence(list.__getitem__(self, n), - universe=self.__universe, - check=False, - immutable=False, - cr=self.__cr) + return Sequence(list.__getitem__(self, n), universe=self.__universe, check=False, immutable=False, cr=self.__cr) return list.__getitem__(self, n) @@ -732,6 +731,7 @@ def _latex_(self): \left[\sqrt{x}, e^{x}, x^{x - 1}\right] """ from sage.misc.latex import list_function as list_latex_function + return list_latex_function(self) def __str__(self): @@ -863,8 +863,7 @@ def __reduce__(self): sage: w.is_mutable() False """ - args = (list(self), self.__universe, False, - self._is_immutable, self.__cr_str) + args = (list(self), self.__universe, False, self._is_immutable, self.__cr_str) return type(self), args def __copy__(self): @@ -882,10 +881,7 @@ def __copy__(self): sage: t.is_mutable() == s.is_mutable() True """ - return Sequence(self, universe=self.__universe, - check=False, - immutable=self._is_immutable, - cr=self.__cr_str) + return Sequence(self, universe=self.__universe, check=False, immutable=self._is_immutable, cr=self.__cr_str) def __getattr__(self, name): """ diff --git a/src/sage/structure/set_factories.py b/src/sage/structure/set_factories.py index b757498d4fb..381c7c3c9eb 100644 --- a/src/sage/structure/set_factories.py +++ b/src/sage/structure/set_factories.py @@ -305,6 +305,7 @@ - Florent Hivert (2011-2012): initial revision """ + # **************************************************************************** # Copyright (C) 2012 Florent Hivert # @@ -341,6 +342,7 @@ class SetFactory(UniqueRepresentation, SageObject): ... NotImplementedError: """ + @abstract_method def __call__(self, *constraints, **consdict): r""" @@ -409,6 +411,7 @@ def add_constraints(self, cons, *args, **opts): # TODO : default policy ? + #################################################### # Policies # #################################################### @@ -431,6 +434,7 @@ class SetFactoryPolicy(UniqueRepresentation, SageObject): This class is a base class for policies, one should not try to create instances. """ + def __init__(self, factory): r""" TESTS:: @@ -507,9 +511,7 @@ def facade_element_constructor_attributes(self, parent): '_parent_for': AllPairs, 'element_class': } """ - return {'_parent_for': parent, - '_facade_for': parent, - 'element_class': parent.element_class} + return {'_parent_for': parent, '_facade_for': parent, 'element_class': parent.element_class} @abstract_method def element_constructor_attributes(self, constraints): @@ -572,6 +574,7 @@ class SelfParentPolicy(SetFactoryPolicy): sage: isinstance(el, Foo) True """ + def __init__(self, factory, Element): r""" TESTS:: @@ -637,6 +640,7 @@ class TopMostParentPolicy(SetFactoryPolicy): sage: P = XYPairs(); P.policy() Set factory policy for with parent AllPairs[=Factory for XY pairs(())] """ + def __init__(self, factory, top_constraints, Element): """ TESTS:: @@ -677,8 +681,7 @@ def element_constructor_attributes(self, constraints): factory = self._factory if constraints == self._top_constraints: return self.self_element_constructor_attributes(self._Element) - return self.facade_element_constructor_attributes( - factory(*self._top_constraints, policy=self)) + return self.facade_element_constructor_attributes(factory(*self._top_constraints, policy=self)) def _repr_(self): r""" @@ -689,9 +692,7 @@ def _repr_(self): sage: TopMostParentPolicy(XYPairs, (), XYPair) # indirect doctest Set factory policy for with parent AllPairs[=Factory for XY pairs(())] """ - return "Set factory policy for {} with parent {}[={}({})]".format( - self._Element, self._factory(*self._top_constraints, policy=self), - self._factory, self._top_constraints) + return "Set factory policy for {} with parent {}[={}({})]".format(self._Element, self._factory(*self._top_constraints, policy=self), self._factory, self._top_constraints) class FacadeParentPolicy(SetFactoryPolicy): @@ -739,6 +740,7 @@ class FacadeParentPolicy(SetFactoryPolicy): sage: type(el) is P.element_class True """ + def __init__(self, factory, parent): r""" TESTS:: @@ -775,8 +777,7 @@ def element_constructor_attributes(self, constraints): '_parent_for': AllPairs, 'element_class': } """ - return self.facade_element_constructor_attributes( - self._parent_for._parent_for) + return self.facade_element_constructor_attributes(self._parent_for._parent_for) def _repr_(self): r""" @@ -787,8 +788,7 @@ def _repr_(self): sage: FacadeParentPolicy(XYPairs, XYPairs()) # indirect doctest Set factory policy for facade parent AllPairs """ - return "Set factory policy for facade parent {}".format( - self._parent_for) + return "Set factory policy for facade parent {}".format(self._parent_for) class BareFunctionPolicy(SetFactoryPolicy): @@ -814,6 +814,7 @@ class BareFunctionPolicy(SetFactoryPolicy): sage: type(el) <... 'tuple'> """ + def __init__(self, factory, constructor): """ TESTS:: @@ -844,8 +845,7 @@ def element_constructor_attributes(self, constraints): sage: pol.element_constructor_attributes(()) {'_element_constructor_': <... 'tuple'>, '_parent_for': None} """ - return {'_element_constructor_': self._constructor, - '_parent_for': None} + return {'_element_constructor_': self._constructor, '_parent_for': None} def _repr_(self): r""" @@ -886,6 +886,7 @@ class ParentWithSetFactory(Parent): sage: P.category() Category of facade finite enumerated sets """ + def __init__(self, constraints, policy, category=None): r""" TESTS:: @@ -905,9 +906,7 @@ def __init__(self, constraints, policy, category=None): else: setattr(self, attrname, attr) assert self._parent_for is None or isinstance(self._parent_for, Parent) - Parent.__init__(self, - category=category, - facade=policy_attributes.get('_facade_for', None)) + Parent.__init__(self, category=category, facade=policy_attributes.get('_facade_for', None)) def constraints(self): r""" @@ -1011,8 +1010,7 @@ def subset(self, *args, **options): True """ factory = self.factory() - constr = factory.add_constraints(self._constraints, - (args, options)) + constr = factory.add_constraints(self._constraints, (args, options)) return factory(*constr, policy=self._policy) def _test_subset(self, **options): @@ -1105,8 +1103,7 @@ def __contains__(self, x): sage: el in XYPairs(y=4) False """ - if (isinstance(x, self.element_class) and - x.parent() == self._parent_for): # TODO: is_parent_of ??? + if isinstance(x, self.element_class) and x.parent() == self._parent_for: # TODO: is_parent_of ??? try: self.check_element(x, True) except ValueError: @@ -1137,9 +1134,7 @@ def __call__(self, *args, **keywords): ValueError: Wrong first coordinate """ # Ensure idempotence of element construction - if (len(args) == 1 and - isinstance(args[0], self.element_class) and - args[0].parent() == self._parent_for): + if len(args) == 1 and isinstance(args[0], self.element_class) and args[0].parent() == self._parent_for: check = keywords.get("check", True) if check: self.check_element(args[0], check) diff --git a/src/sage/structure/set_factories_example.py b/src/sage/structure/set_factories_example.py index e838cca9deb..506769e6a6c 100644 --- a/src/sage/structure/set_factories_example.py +++ b/src/sage/structure/set_factories_example.py @@ -24,6 +24,7 @@ S_a^b := \{(x,y) \in S \mid x = a, y = b\}. """ + # **************************************************************************** # Copyright (C) 2012 Florent Hivert # @@ -33,8 +34,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element_wrapper import ElementWrapper -from sage.structure.set_factories import ( - SetFactory, ParentWithSetFactory, TopMostParentPolicy) +from sage.structure.set_factories import SetFactory, ParentWithSetFactory, TopMostParentPolicy from sage.sets.disjoint_union_enumerated_sets import DisjointUnionEnumeratedSets from sage.sets.family import LazyFamily from sage.categories.enumerated_sets import EnumeratedSets @@ -52,6 +52,7 @@ class XYPairsFactory(SetFactory): :mod:`.set_factories` for an introduction to set factories. """ + def __call__(self, x=None, y=None, policy=None): r""" Construct the subset from constraints. @@ -130,15 +131,15 @@ def add_constraints(self, cons, args_opts): def set_args(argss): for i, v in enumerate(argss): if res[i] is not None and v is not None: - raise ValueError("Duplicate value for constraints '{}': " - "was {} now {}".format(['x', 'y'][i], - res[i], v)) + raise ValueError("Duplicate value for constraints '{}': " "was {} now {}".format(['x', 'y'][i], res[i], v)) if v is not None: res[i] = v + set_args(args) def parse_args(x=None, y=None): set_args((x, y)) + parse_args(**opts) if res == (None, None): return () @@ -185,6 +186,7 @@ class XYPair(ElementWrapper): ... ValueError: numbers must be in range(5) """ + def __init__(self, parent, value, check=True): """ TESTS:: @@ -229,6 +231,7 @@ class AllPairs(ParentWithSetFactory, DisjointUnionEnumeratedSets): sage: P = XYPairs(); P.list() [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (0, 2), (1, 2), (2, 2), (3, 2), (4, 2), (0, 3), (1, 3), (2, 3), (3, 3), (4, 3), (0, 4), (1, 4), (2, 4), (3, 4), (4, 4)] """ + def __init__(self, policy): r""" TESTS:: @@ -236,13 +239,8 @@ def __init__(self, policy): sage: from sage.structure.set_factories_example import XYPairs sage: TestSuite(XYPairs()).run() """ - ParentWithSetFactory.__init__(self, (), policy=policy, - category=EnumeratedSets().Finite()) - DisjointUnionEnumeratedSets.__init__(self, - LazyFamily(range(MAX), - self.pairs_y), - facade=True, keepkey=False, - category=self.category()) + ParentWithSetFactory.__init__(self, (), policy=policy, category=EnumeratedSets().Finite()) + DisjointUnionEnumeratedSets.__init__(self, LazyFamily(range(MAX), self.pairs_y), facade=True, keepkey=False, category=self.category()) def pairs_y(self, letter): r""" @@ -310,6 +308,7 @@ class PairsX_(ParentWithSetFactory, UniqueRepresentation): sage: P = XYPairs(0); P.list() [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4)] """ + def __init__(self, x, policy): r""" TESTS:: @@ -318,8 +317,7 @@ def __init__(self, x, policy): sage: TestSuite(XYPairs(0)).run() """ self._x = x - ParentWithSetFactory.__init__(self, (x, None), policy=policy, - category=EnumeratedSets().Finite()) + ParentWithSetFactory.__init__(self, (x, None), policy=policy, category=EnumeratedSets().Finite()) def _repr_(self): """ @@ -392,6 +390,7 @@ class Pairs_Y(ParentWithSetFactory, DisjointUnionEnumeratedSets): sage: P = XYPairs(y=1); P.list() [(0, 1), (1, 1), (2, 1), (3, 1), (4, 1)] """ + def __init__(self, y, policy): r""" TESTS:: @@ -400,12 +399,8 @@ def __init__(self, y, policy): sage: TestSuite(XYPairs(y=1)).run() """ self._y = y - ParentWithSetFactory.__init__(self, (None, y), policy=policy, - category=EnumeratedSets().Finite()) - DisjointUnionEnumeratedSets.__init__( - self, LazyFamily(range(MAX), self.single_pair), - facade=True, keepkey=False, - category=self.category()) # TODO remove and fix disjoint union. + ParentWithSetFactory.__init__(self, (None, y), policy=policy, category=EnumeratedSets().Finite()) + DisjointUnionEnumeratedSets.__init__(self, LazyFamily(range(MAX), self.single_pair), facade=True, keepkey=False, category=self.category()) # TODO remove and fix disjoint union. def _repr_(self): """ @@ -476,6 +471,7 @@ class SingletonPair(ParentWithSetFactory, UniqueRepresentation): sage: P = XYPairs(0,1); P.list() [(0, 1)] """ + def __init__(self, x, y, policy): r""" TESTS:: @@ -484,8 +480,7 @@ def __init__(self, x, y, policy): sage: TestSuite(XYPairs(0,1)).run() """ self._xy = (x, y) - ParentWithSetFactory.__init__(self, (x, y), policy=policy, - category=EnumeratedSets().Finite()) + ParentWithSetFactory.__init__(self, (x, y), policy=policy, category=EnumeratedSets().Finite()) def _repr_(self): """ diff --git a/src/sage/structure/support_view.py b/src/sage/structure/support_view.py index 3b0899c7ed3..6b6af60e7aa 100644 --- a/src/sage/structure/support_view.py +++ b/src/sage/structure/support_view.py @@ -1,6 +1,7 @@ r""" Iterable of the keys of a Mapping associated with nonzero values """ + from collections.abc import MappingView, Sequence, Set diff --git a/src/sage/structure/unique_representation.py b/src/sage/structure/unique_representation.py index 67a4cae7382..cdc400fdcf4 100644 --- a/src/sage/structure/unique_representation.py +++ b/src/sage/structure/unique_representation.py @@ -539,6 +539,7 @@ class that inherits from :class:`UniqueRepresentation`: By adding - Kwankyu Lee (2025-10): added ``__getstate__`` and ``__setstate__`` to support ``do_pickle=True`` for cached methods. """ + # **************************************************************************** # Copyright (C) 2008 Nicolas M. Thiery # Copyright (C) 2013 Simon A. King @@ -692,10 +693,10 @@ def __getstate__(self): # # Note that the same code is used to get the state of UniqueFactory objects. from sage.misc.cachefunc import CachedFunction + d = {} try: - d.update({key: value for key, value in self.__dict__.items() - if isinstance(value, CachedFunction) and value.is_pickled_with_cache()}) + d.update({key: value for key, value in self.__dict__.items() if isinstance(value, CachedFunction) and value.is_pickled_with_cache()}) except AttributeError: pass return d diff --git a/src/sage/symbolic/all.py b/src/sage/symbolic/all.py index 8e1c9600409..a248a738a69 100644 --- a/src/sage/symbolic/all.py +++ b/src/sage/symbolic/all.py @@ -1,6 +1,5 @@ from sage.symbolic.ring import SR -from sage.symbolic.constants import (pi, e, NaN, golden_ratio, log2, euler_gamma, catalan, - khinchin, twinprime, mertens, glaisher) +from sage.symbolic.constants import pi, e, NaN, golden_ratio, log2, euler_gamma, catalan, khinchin, twinprime, mertens, glaisher from sage.symbolic.expression import Expression, solve_diophantine, hold from sage.symbolic.callable import CallableSymbolicExpressionRing diff --git a/src/sage/symbolic/assumptions.py b/src/sage/symbolic/assumptions.py index 73be7880a7a..0a09ba1ad18 100644 --- a/src/sage/symbolic/assumptions.py +++ b/src/sage/symbolic/assumptions.py @@ -72,6 +72,7 @@ ValueError: Assumption is inconsistent sage: forget() """ + from sage.rings.cc import CC from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -212,14 +213,14 @@ def _validate_feature(self): ValueError: bougie not a valid assumption, must be one of ['analytic', ... 'symmetric'] """ from sage.calculus.calculus import maxima + if self._assumption in _valid_feature_strings: return # We get the list here because features may be added with time. _valid_feature_strings.update(repr(x).strip() for x in list(maxima("features"))) if self._assumption in _valid_feature_strings: return - raise ValueError("%s not a valid assumption, must be one of %s" - % (self._assumption, sorted(_valid_feature_strings))) + raise ValueError("%s not a valid assumption, must be one of %s" % (self._assumption, sorted(_valid_feature_strings))) def assume(self): """ @@ -242,6 +243,7 @@ def assume(self): if self in _assumptions: return from sage.calculus.calculus import maxima + cur = None context = None if self._context is None: @@ -309,6 +311,7 @@ def forget(self): """ self._var.decl_forget(self._assumption) from sage.calculus.calculus import maxima + if self._context is not None: try: del _assumptions[self] @@ -426,9 +429,7 @@ def preprocess_assumptions(args): if isinstance(x, str): del args[i] last = x - elif ((not hasattr(x, 'assume') - or (isinstance(x, Expression) and x.is_symbol())) - and last is not None): + elif (not hasattr(x, 'assume') or (isinstance(x, Expression) and x.is_symbol())) and last is not None: args[i] = GenericDeclaration(x, last) else: last = None @@ -776,12 +777,10 @@ def assumptions(*args): result = [] if len(args) == 1: - result.extend([statement for statement in _assumptions - if statement.has(args[0])]) + result.extend([statement for statement in _assumptions if statement.has(args[0])]) else: for v in args: - result += [statement for statement in list(_assumptions) - if str(v) in str(statement)] + result += [statement for statement in list(_assumptions) if str(v) in str(statement)] return result @@ -928,6 +927,7 @@ class assuming: ... ValueError: Assumption is inconsistent """ + def __init__(self, *args, **kwds): r""" EXAMPLES:: diff --git a/src/sage/symbolic/callable.py b/src/sage/symbolic/callable.py index 8a2e7052459..75780a46aca 100644 --- a/src/sage/symbolic/callable.py +++ b/src/sage/symbolic/callable.py @@ -60,6 +60,7 @@ ... SyntaxError: can...t assign to function call... """ + from sage.misc.lazy_import import lazy_import from sage.symbolic.ring import SymbolicRing, SR from sage.categories.pushout import ConstructionFunctor @@ -70,6 +71,7 @@ # Callable functions ###################################################################### + class CallableSymbolicExpressionFunctor(ConstructionFunctor): def __init__(self, arguments): """ @@ -90,6 +92,7 @@ def __init__(self, arguments): """ self._arguments = arguments from sage.categories.rings import Rings + self.rank = 3 ConstructionFunctor.__init__(self, Rings(), Rings()) @@ -366,6 +369,7 @@ def _latex_element_(self, x): '\\mu \\ {\\mapsto}\\ \\mu^{3}' """ from sage.misc.latex import latex + args = self.args() args = [latex(arg) for arg in args] latex_x = SymbolicRing._latex_element_(self, x) @@ -428,8 +432,9 @@ def create_key(self, args, check=True): """ if check: from sage.structure.element import Expression + if len(args) == 1 and isinstance(args[0], (list, tuple)): - args, = args + (args,) = args for arg in args: if not (isinstance(arg, Expression) and arg.is_symbol()): raise TypeError("must construct a function with a tuple (or list) of variables") diff --git a/src/sage/symbolic/callable.pyi b/src/sage/symbolic/callable.pyi index e3eead802a5..5043b9d09c0 100644 --- a/src/sage/symbolic/callable.pyi +++ b/src/sage/symbolic/callable.pyi @@ -5,61 +5,31 @@ from sage.categories.pushout import ConstructionFunctor from sage.structure.factory import UniqueFactory class CallableSymbolicExpressionFunctor(ConstructionFunctor): - def __init__(self, arguments: tuple): - ... - - def __repr__(self) -> str: - ... - - def merge(self, other: 'CallableSymbolicExpressionFunctor') -> 'CallableSymbolicExpressionFunctor': - ... - - def __call__(self, R: SymbolicRing) -> 'CallableSymbolicExpressionRing': - ... - - def arguments(self) -> tuple: - ... - - def unify_arguments(self, x: 'CallableSymbolicExpressionFunctor') -> tuple: - ... + def __init__(self, arguments: tuple): ... + def __repr__(self) -> str: ... + def merge(self, other: 'CallableSymbolicExpressionFunctor') -> 'CallableSymbolicExpressionFunctor': ... + def __call__(self, R: SymbolicRing) -> 'CallableSymbolicExpressionRing': ... + def arguments(self) -> tuple: ... + def unify_arguments(self, x: 'CallableSymbolicExpressionFunctor') -> tuple: ... class CallableSymbolicExpressionRing_class(SymbolicRing): - def __init__(self, arguments: tuple): - ... - - def _coerce_map_from_(self, R: Any) -> bool: - ... - - def construction(self) -> tuple: - ... - - def _element_constructor_(self, x: Any) -> Any: - ... - - def _repr_(self) -> str: - ... - - def arguments(self) -> tuple: - ... + def __init__(self, arguments: tuple): ... + def _coerce_map_from_(self, R: Any) -> bool: ... + def construction(self) -> tuple: ... + def _element_constructor_(self, x: Any) -> Any: ... + def _repr_(self) -> str: ... + def arguments(self) -> tuple: ... args = arguments - def _repr_element_(self, x: Any) -> str: - ... - - def _latex_element_(self, x: Any) -> str: - ... - - def _call_element_(self, _the_element: Any, *args: Any, **kwds: Any) -> Any: - ... + def _repr_element_(self, x: Any) -> str: ... + def _latex_element_(self, x: Any) -> str: ... + def _call_element_(self, _the_element: Any, *args: Any, **kwds: Any) -> Any: ... __reduce__ = object.__reduce__ class CallableSymbolicExpressionRingFactory(UniqueFactory): - def create_key(self, args: Any, check: bool = True) -> tuple: - ... - - def create_object(self, version: int, key: tuple, **extra_args: Any) -> 'CallableSymbolicExpressionRing_class': - ... + def create_key(self, args: Any, check: bool = True) -> tuple: ... + def create_object(self, version: int, key: tuple, **extra_args: Any) -> 'CallableSymbolicExpressionRing_class': ... CallableSymbolicExpressionRing = CallableSymbolicExpressionRingFactory('sage.symbolic.callable.CallableSymbolicExpressionRing') diff --git a/src/sage/symbolic/comparison_impl.pyi b/src/sage/symbolic/comparison_impl.pyi index 886ba68f28d..f4d6d4587d5 100644 --- a/src/sage/symbolic/comparison_impl.pyi +++ b/src/sage/symbolic/comparison_impl.pyi @@ -1,38 +1,23 @@ from collections.abc import Iterable from typing import Any -def print_order(lhs: Any, rhs: Any) -> int: - ... +def print_order(lhs: Any, rhs: Any) -> int: ... class _print_key: - def __init__(self, ex: Any): - ... + def __init__(self, ex: Any): ... + def __lt__(self, other: '_print_key') -> bool: ... - def __lt__(self, other: '_print_key') -> bool: - ... - -def print_sorted(expressions: Iterable) -> list: - ... +def print_sorted(expressions: Iterable) -> list: ... class _math_key: - def __init__(self, ex: Any): - ... - - def __lt__(self, other: '_math_key') -> bool: - ... + def __init__(self, ex: Any): ... + def __lt__(self, other: '_math_key') -> bool: ... -def math_sorted(expressions: Iterable) -> list: - ... - -def mixed_order(lhs: Any, rhs: Any) -> int: - ... +def math_sorted(expressions: Iterable) -> list: ... +def mixed_order(lhs: Any, rhs: Any) -> int: ... class _mixed_key: - def __init__(self, ex: Any): - ... - - def __lt__(self, other: '_mixed_key') -> bool: - ... + def __init__(self, ex: Any): ... + def __lt__(self, other: '_mixed_key') -> bool: ... -def mixed_sorted(expressions: Iterable) -> list: - ... +def mixed_sorted(expressions: Iterable) -> list: ... diff --git a/src/sage/symbolic/constants.py b/src/sage/symbolic/constants.py index 7a64bfa67e5..ab57ada3e1f 100644 --- a/src/sage/symbolic/constants.py +++ b/src/sage/symbolic/constants.py @@ -203,6 +203,7 @@ sage: maxima('minf').sage() -Infinity """ + ############################################################################### # Sage: Open Source Mathematical Software # Copyright (C) 2008 William Stein @@ -232,12 +233,8 @@ register_symbol(minus_infinity, {'maxima': 'minf'}, 0) register_symbol(unsigned_infinity, {'maxima': 'infinity'}, 0) register_symbol(I, {'mathematica': 'I'}, 0) -register_symbol(True, {'giac': 'true', - 'mathematica': 'True', - 'maxima': 'true'}, 0) -register_symbol(False, {'giac': 'false', - 'mathematica': 'False', - 'maxima': 'false'}, 0) +register_symbol(True, {'giac': 'true', 'mathematica': 'True', 'maxima': 'true'}, 0) +register_symbol(False, {'giac': 'false', 'mathematica': 'False', 'maxima': 'false'}, 0) def unpickle_Constant(class_name, name, conversions, latex, mathml, domain): @@ -262,16 +259,14 @@ def unpickle_Constant(class_name, name, conversions, latex, mathml, domain): if name in constants_name_table: return constants_name_table[name] if class_name == "Constant": - return Constant(name, conversions=conversions, latex=latex, - mathml=mathml, domain=domain) + return Constant(name, conversions=conversions, latex=latex, mathml=mathml, domain=domain) cls = globals()[class_name] return cls(name=name) @richcmp_method class Constant: - def __init__(self, name, conversions=None, latex=None, mathml='', - domain='complex'): + def __init__(self, name, conversions=None, latex=None, mathml='', domain='complex'): """ EXAMPLES:: @@ -291,6 +286,7 @@ def __init__(self, name, conversions=None, latex=None, mathml='', setattr(self, "_%s_init_" % system, partial(self._generic_interface_init, value)) from sage.symbolic.expression import PynacConstant + self._pynac = PynacConstant(self._name, self._latex, self._domain) self._serial = self._pynac.serial() constants_table[self._serial] = self @@ -341,9 +337,7 @@ def __reduce__(self): sage: loads(dumps(pi.pyobject())) pi """ - return (unpickle_Constant, (self.__class__.__name__, self._name, - self._conversions, self._latex, - self._mathml, self._domain)) + return (unpickle_Constant, (self.__class__.__name__, self._name, self._conversions, self._latex, self._mathml, self._domain)) def domain(self): """ @@ -554,13 +548,8 @@ def __init__(self, name='pi'): sage: mathml(pi) π """ - conversions = dict(axiom='%pi', fricas='%pi', maxima='%pi', giac='pi', - gp='Pi', kash='PI', - mathematica='Pi', matlab='pi', maple='Pi', - octave='pi', pari='Pi', pynac='Pi') - Constant.__init__(self, name, conversions=conversions, - latex=r"\pi", mathml="π", - domain='positive') + conversions = dict(axiom='%pi', fricas='%pi', maxima='%pi', giac='pi', gp='Pi', kash='PI', mathematica='Pi', matlab='pi', maple='Pi', octave='pi', pari='Pi', pynac='Pi') + Constant.__init__(self, name, conversions=conversions, latex=r"\pi", mathml="π", domain='positive') def __float__(self): """ @@ -600,6 +589,7 @@ def _sympy_(self): True """ import sympy + return sympy.pi @@ -690,6 +680,7 @@ class NotANumber(Constant): """ Not a Number """ + def __init__(self, name="NaN"): """ EXAMPLES:: @@ -742,6 +733,7 @@ def _sympy_(self): False """ import sympy + return sympy.nan @@ -767,6 +759,7 @@ class GoldenRatio(Constant): sage: float(grm + grm) 3.23606797749979 """ + def __init__(self, name='golden_ratio'): """ EXAMPLES:: @@ -774,12 +767,8 @@ def __init__(self, name='golden_ratio'): sage: loads(dumps(golden_ratio)) golden_ratio """ - conversions = dict(mathematica='(1+Sqrt[5])/2', gp='(1+sqrt(5))/2', - maple='(1+sqrt(5))/2', maxima='(1+sqrt(5))/2', - pari='(1+sqrt(5))/2', octave='(1+sqrt(5))/2', - kash='(1+Sqrt(5))/2', giac='(1+sqrt(5))/2') - Constant.__init__(self, name, conversions=conversions, - latex=r'\phi', domain='positive') + conversions = dict(mathematica='(1+Sqrt[5])/2', gp='(1+sqrt(5))/2', maple='(1+sqrt(5))/2', maxima='(1+sqrt(5))/2', pari='(1+sqrt(5))/2', octave='(1+sqrt(5))/2', kash='(1+Sqrt(5))/2', giac='(1+sqrt(5))/2') + Constant.__init__(self, name, conversions=conversions, latex=r'\phi', domain='positive') def minpoly(self, bits=None, degree=None, epsilon=0): """ @@ -789,6 +778,7 @@ def minpoly(self, bits=None, degree=None, epsilon=0): x^2 - x - 1 """ from sage.rings.rational_field import QQ + x = QQ['x'].gen(0) return x**2 - x - 1 @@ -833,6 +823,7 @@ def _algebraic_(self, field): 1.618033988749895? """ import sage.rings.qqbar + return field(sage.rings.qqbar.get_AA_golden_ratio()) def _sympy_(self): @@ -846,6 +837,7 @@ def _sympy_(self): True """ import sympy + return sympy.GoldenRatio @@ -883,6 +875,7 @@ class Log2(Constant): sage: giac(log2) # optional - giac ln(2) """ + def __init__(self, name='log2'): """ EXAMPLES:: @@ -890,11 +883,8 @@ def __init__(self, name='log2'): sage: loads(dumps(log2)) log2 """ - conversions = dict(mathematica='Log[2]', kash='Log(2)', - maple='log(2)', maxima='log(2)', gp='log(2)', - pari='log(2)', octave='log(2)', giac='log(2)') - Constant.__init__(self, name, conversions=conversions, - latex=r'\log(2)', domain='positive') + conversions = dict(mathematica='Log[2]', kash='Log(2)', maple='log(2)', maxima='log(2)', gp='log(2)', pari='log(2)', octave='log(2)', giac='log(2)') + Constant.__init__(self, name, conversions=conversions, latex=r'\log(2)', domain='positive') def __float__(self): """ @@ -950,6 +940,7 @@ class EulerGamma(Constant): sage: R(eg) 1.1544313298030657212130241801648048620843186718798471976115 """ + def __init__(self, name='euler_gamma'): """ EXAMPLES:: @@ -957,12 +948,8 @@ def __init__(self, name='euler_gamma'): sage: loads(dumps(euler_gamma)) euler_gamma """ - conversions = dict(kash='EulerGamma(R)', maple='gamma', - mathematica='EulerGamma', pari='Euler', - maxima='%gamma', pynac='Euler', giac='euler_gamma', - fricas='-digamma(1)') - Constant.__init__(self, name, conversions=conversions, - latex=r'\gamma', domain='positive') + conversions = dict(kash='EulerGamma(R)', maple='gamma', mathematica='EulerGamma', pari='Euler', maxima='%gamma', pynac='Euler', giac='euler_gamma', fricas='-digamma(1)') + Constant.__init__(self, name, conversions=conversions, latex=r'\gamma', domain='positive') def _mpfr_(self, R): """ @@ -1004,6 +991,7 @@ def _sympy_(self): True """ import sympy + return sympy.EulerGamma @@ -1020,6 +1008,7 @@ class Catalan(Constant): sage: catalan^2 + mertens mertens + catalan^2 """ + def __init__(self, name='catalan'): """ EXAMPLES:: @@ -1028,11 +1017,8 @@ def __init__(self, name='catalan'): catalan """ # kash: R is default prec - conversions = dict(mathematica='Catalan', kash='Catalan(R)', - maple='Catalan', maxima='catalan', - pynac='Catalan') - Constant.__init__(self, name, conversions=conversions, - domain='positive') + conversions = dict(mathematica='Catalan', kash='Catalan(R)', maple='Catalan', maxima='catalan', pynac='Catalan') + Constant.__init__(self, name, conversions=conversions, domain='positive') def _mpfr_(self, R): """ @@ -1074,6 +1060,7 @@ def _sympy_(self): True """ import sympy + return sympy.Catalan @@ -1096,6 +1083,7 @@ class Khinchin(Constant): sage: m.N(200) # optional - mathematica 2.685452001065306445309714835481795693820382293...32852204481940961807 """ + def __init__(self, name='khinchin'): """ EXAMPLES:: @@ -1103,10 +1091,8 @@ def __init__(self, name='khinchin'): sage: loads(dumps(khinchin)) khinchin """ - conversions = dict(maxima='khinchin', mathematica='Khinchin', - pynac='Khinchin') - Constant.__init__(self, name, conversions=conversions, - domain='positive') + conversions = dict(maxima='khinchin', mathematica='Khinchin', pynac='Khinchin') + Constant.__init__(self, name, conversions=conversions, domain='positive') def _mpfr_(self, R): """ @@ -1118,6 +1104,7 @@ def _mpfr_(self, R): 2.6854520010653064453097148355 """ import sage.libs.mpmath.all as a + return a.eval_constant('khinchin', R) def __float__(self): @@ -1145,6 +1132,7 @@ class TwinPrime(Constant): sage: twinprime.n(digits=60) 0.660161815846869573927812110014555778432623360284733413319448 """ + def __init__(self, name='twinprime'): """ EXAMPLES:: @@ -1153,8 +1141,7 @@ def __init__(self, name='twinprime'): twinprime """ conversions = dict(maxima='twinprime', pynac='TwinPrime') - Constant.__init__(self, name, conversions=conversions, - domain='positive') + Constant.__init__(self, name, conversions=conversions, domain='positive') def _mpfr_(self, R): """ @@ -1166,6 +1153,7 @@ def _mpfr_(self, R): 0.66016181584686957392781211001 """ import sage.libs.mpmath.all as a + return a.eval_constant('twinprime', R) def __float__(self): @@ -1193,6 +1181,7 @@ class Mertens(Constant): sage: mertens.n(digits=60) 0.261497212847642783755426838608695859051566648261199206192064 """ + def __init__(self, name='mertens'): """ EXAMPLES:: @@ -1201,8 +1190,7 @@ def __init__(self, name='mertens'): mertens """ conversions = dict(maxima='mertens', pynac='Mertens') - Constant.__init__(self, name, conversions=conversions, - domain='positive') + Constant.__init__(self, name, conversions=conversions, domain='positive') def _mpfr_(self, R): """ @@ -1214,6 +1202,7 @@ def _mpfr_(self, R): 0.26149721284764278375542683861 """ import sage.libs.mpmath.all as a + return a.eval_constant('mertens', R) def __float__(self): @@ -1245,6 +1234,7 @@ class Glaisher(Constant): sage: parent(a) Symbolic Ring """ + def __init__(self, name='glaisher'): """ EXAMPLES:: @@ -1252,10 +1242,8 @@ def __init__(self, name='glaisher'): sage: loads(dumps(glaisher)) glaisher """ - conversions = dict(maxima='glaisher', pynac='Glaisher', - mathematica='Glaisher') - Constant.__init__(self, name, conversions=conversions, - domain='positive') + conversions = dict(maxima='glaisher', pynac='Glaisher', mathematica='Glaisher') + Constant.__init__(self, name, conversions=conversions, domain='positive') def _mpfr_(self, R): """ @@ -1267,6 +1255,7 @@ def _mpfr_(self, R): 1.2824271291006226368753425689 """ import sage.libs.mpmath.all as a + return a.eval_constant('glaisher', R) def __float__(self): diff --git a/src/sage/symbolic/constants_c_impl.pyi b/src/sage/symbolic/constants_c_impl.pyi index 1d4faa88d58..6d117862315 100644 --- a/src/sage/symbolic/constants_c_impl.pyi +++ b/src/sage/symbolic/constants_c_impl.pyi @@ -3,8 +3,5 @@ from typing import Any from sage.symbolic.expression import Expression class E(Expression): - def __init__(self) -> None: - ... - - def __pow__(self, left: Any, right: Any, dummy: Any) -> Any: - ... + def __init__(self) -> None: ... + def __pow__(self, left: Any, right: Any, dummy: Any) -> Any: ... diff --git a/src/sage/symbolic/expression_conversion_algebraic.py b/src/sage/symbolic/expression_conversion_algebraic.py index e8cdc6c8778..84b9db7f57e 100644 --- a/src/sage/symbolic/expression_conversion_algebraic.py +++ b/src/sage/symbolic/expression_conversion_algebraic.py @@ -1,6 +1,7 @@ r""" Conversion of symbolic expressions to algebraic numbers """ + # **************************************************************************** # Copyright (C) 2009-2012 Mike Hansen # 2015-2018 Ralf Stephan @@ -46,6 +47,7 @@ def __init__(self, field): self.field = field from sage.functions.all import reciprocal_trig_functions + self.reciprocal_trig_functions = reciprocal_trig_functions def pyobject(self, ex, obj): @@ -104,6 +106,7 @@ def arithmetic(self, ex, operator): try: if operator is pow: from sage.rings.rational import Rational + base, expt = ex.operands() base = self.field(base) expt = Rational(expt) @@ -214,12 +217,13 @@ def composition(self, ex, operator): raise ValueError("unable to represent as an algebraic number") # Coerce (not convert, see #22571) arg to a rational from sage.rings.rational_field import QQ - arg = operand.imag()/(2*ex.parent().pi()) + + arg = operand.imag() / (2 * ex.parent().pi()) try: rat_arg = QQ.coerce(arg.pyobject()) except TypeError: raise TypeError("unable to convert %r to %s" % (ex, self.field)) - res = zeta(rat_arg.denom())**rat_arg.numer() + res = zeta(rat_arg.denom()) ** rat_arg.numer() return self.field(res) if func_name in ['sin', 'cos', 'tan']: exp_ia = exp(SR(-1).sqrt() * operand, hold=hold)._algebraic_(QQbar) @@ -231,7 +235,7 @@ def composition(self, ex, operator): res = -zeta(4) * (exp_ia - ~exp_ia) / (exp_ia + ~exp_ia) return self.field(res) if func_name in ['sinh', 'cosh', 'tanh']: - if not (SR(-1).sqrt()*operand).is_real(): + if not (SR(-1).sqrt() * operand).is_real(): raise ValueError("unable to represent as an algebraic number") exp_a = exp(operand, hold=hold)._algebraic_(QQbar) if func_name == 'sinh': diff --git a/src/sage/symbolic/expression_conversion_sympy.py b/src/sage/symbolic/expression_conversion_sympy.py index e542cb49346..7c6a38a6c5a 100644 --- a/src/sage/symbolic/expression_conversion_sympy.py +++ b/src/sage/symbolic/expression_conversion_sympy.py @@ -55,6 +55,7 @@ class SympyConverter(Converter): sage: (x+I)._sympy_() x + I """ + def __init__(self): """ TESTS:: @@ -64,6 +65,7 @@ def __init__(self): sage: TestSuite(s).run(skip='_test_pickling') """ from sage.interfaces.sympy import sympy_init + sympy_init() def __call__(self, ex=None): @@ -79,8 +81,8 @@ def __call__(self, ex=None): """ if isinstance(ex, Expression) and ex.is_callable(): from sympy import Symbol, Lambda - return Lambda(tuple(Symbol(str(arg)) for arg in ex.arguments()), - super().__call__(ex)) + + return Lambda(tuple(Symbol(str(arg)) for arg in ex.arguments()), super().__call__(ex)) return super().__call__(ex) def pyobject(self, ex, obj): @@ -111,6 +113,7 @@ def arithmetic(self, ex, operator): x + 2 """ import sympy + operator = arithmetic_operators[operator] ops = [sympy.sympify(self(a), evaluate=False) for a in ex.operands()] if operator == "+": @@ -137,6 +140,7 @@ def symbol(self, ex): """ import sympy + return sympy.symbols(repr(ex)) def relation(self, ex, op): @@ -156,6 +160,7 @@ def relation(self, ex, op): x > 0 """ from sympy import Eq, Ne, Gt, Lt, Ge, Le + ops = {eq: Eq, ne: Ne, gt: Gt, lt: Lt, ge: Ge, le: Le} return ops.get(op)(self(ex.lhs()), self(ex.rhs()), evaluate=False) diff --git a/src/sage/symbolic/expression_conversions.py b/src/sage/symbolic/expression_conversions.py index 4f7cbbd3ec2..7e17c4a5f23 100644 --- a/src/sage/symbolic/expression_conversions.py +++ b/src/sage/symbolic/expression_conversions.py @@ -6,6 +6,7 @@ which will walk the expression tree and make calls to methods overridden by subclasses. """ + ############################################################################### # Sage: Open Source Mathematical Software # Copyright (C) 2009 Mike Hansen @@ -446,10 +447,11 @@ def pyobject(self, ex, obj): sage: ii.pyobject(pi, pi.pyobject()) 'Pi' """ - if (self.interface.name() in ['pari', 'gp'] and isinstance(obj, NumberFieldElement_base)): + if self.interface.name() in ['pari', 'gp'] and isinstance(obj, NumberFieldElement_base): from sage.rings.number_field.number_field_element_quadratic import ( NumberFieldElement_gaussian, ) + if isinstance(obj, NumberFieldElement_gaussian): return repr(obj) try: @@ -469,8 +471,7 @@ def relation(self, ex, operator): sage: m.relation(x==3, operator.lt) '_SAGE_VAR_x < 3' """ - return "%s %s %s" % (self(ex.lhs()), self.relation_symbols[operator], - self(ex.rhs())) + return "%s %s %s" % (self(ex.lhs()), self.relation_symbols[operator], self(ex.rhs())) def tuple(self, ex): """ @@ -593,8 +594,7 @@ def derivative(self, ex, operator): if self.name_init != "_maxima_init_": raise NotImplementedError args = ex.operands() - if (not all(isinstance(v, Expression) and v.is_symbol() for v in args) or - len(args) != len(set(args))): + if not all(isinstance(v, Expression) and v.is_symbol() for v in args) or len(args) != len(set(args)): # An evaluated derivative of the form f'(1) is not a # symbolic variable, yet we would like to treat it like # one. So, we replace the argument `1` with a temporary @@ -607,18 +607,13 @@ def derivative(self, ex, operator): f = operator.function()(*temp_args) params = operator.parameter_set() params = ["%s, %s" % (temp_args[i]._maxima_init_(), params.count(i)) for i in set(params)] - subs = ["%s = %s" % (t._maxima_init_(), a._maxima_init_()) - for t, a in zip(temp_args, args)] - outstr = "at(diff(%s, %s), [%s])" % (f._maxima_init_(), - ", ".join(params), - ", ".join(subs)) + subs = ["%s = %s" % (t._maxima_init_(), a._maxima_init_()) for t, a in zip(temp_args, args)] + outstr = "at(diff(%s, %s), [%s])" % (f._maxima_init_(), ", ".join(params), ", ".join(subs)) else: f = operator.function()(*args) params = operator.parameter_set() - params = ["%s, %s" % (args[i]._maxima_init_(), params.count(i)) - for i in set(params)] - outstr = "diff(%s, %s)" % (f._maxima_init_(), - ", ".join(params)) + params = ["%s, %s" % (args[i]._maxima_init_(), params.count(i)) for i in set(params)] + outstr = "diff(%s, %s)" % (f._maxima_init_(), ", ".join(params)) return outstr def arithmetic(self, ex, operator): @@ -681,8 +676,10 @@ class FriCASConverter(InterfaceInit): ---------------------- y """ + def __init__(self): import sage.interfaces.fricas + super().__init__(sage.interfaces.fricas.fricas) def pyobject(self, ex, obj): @@ -748,6 +745,7 @@ def pyobject(self, ex, obj): from sage.rings.number_field.number_field_element_quadratic import ( NumberFieldElement_gaussian, ) + if isinstance(obj, NumberFieldElement_gaussian): return "((%s)::EXPR COMPLEX INT)" % result elif isinstance(obj, InfinityElement): @@ -829,8 +827,7 @@ def derivative(self, ex, operator): params = operator.parameter_set() params_set = set(params) mult = ",".join(str(params.count(i)) for i in params_set) - if (not all(isinstance(v, Expression) and v.is_symbol() for v in args) or - len(args) != len(set(args))): + if not all(isinstance(v, Expression) and v.is_symbol() for v in args) or len(args) != len(set(args)): # An evaluated derivative of the form f'(1) is not a # symbolic variable, yet we would like to treat it like # one. So, we replace the argument `1` with a temporary @@ -842,8 +839,7 @@ def derivative(self, ex, operator): temp_args = [SR.symbol("_symbol%s" % i) for i in range(len(args))] f = operator.function()(*temp_args) vars = ",".join(temp_args[i]._fricas_init_() for i in params_set) - subs = ",".join("%s = %s" % (t._fricas_init_(), a._fricas_init_()) - for t, a in zip(temp_args, args)) + subs = ",".join("%s = %s" % (t._fricas_init_(), a._fricas_init_()) for t, a in zip(temp_args, args)) outstr = "eval(D(%s, [%s], [%s]), [%s])" % (f._fricas_init_(), vars, mult, subs) else: f = operator.function()(*args) @@ -917,6 +913,7 @@ def __init__(self, ex, base_ring=None, ring=None): if len(vars) == 0: vars = ['x'] from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + self.ring = PolynomialRing(self.base_ring, names=vars) self.varnames = self.ring.variable_names() else: @@ -994,6 +991,7 @@ def relation(self, ex, op): -x^3 - y^3 + x^2 + 1 """ import operator + if op == operator.eq: return self(ex.lhs()) - self(ex.rhs()) raise ValueError("Unable to represent as a polynomial") @@ -1026,8 +1024,9 @@ def arithmetic(self, ex, operator): return self.base_ring(ex) if operator == pow: from sage.rings.integer import Integer + base, exp = ex.operands() - return self(base)**Integer(exp) + return self(base) ** Integer(exp) if operator == add_vararg: operator = add elif operator == mul_vararg: @@ -1121,8 +1120,8 @@ def __init__(self, ex, base_ring=None, ring=None): from sage.rings.polynomial.laurent_polynomial_ring import ( LaurentPolynomialRing, ) - self.ring = LaurentPolynomialRing(self.base_ring, - names=self.varnames) + + self.ring = LaurentPolynomialRing(self.base_ring, names=self.varnames) def laurent_polynomial(ex, base_ring=None, ring=None): @@ -1170,6 +1169,7 @@ def laurent_polynomial(ex, base_ring=None, ring=None): # Fast Callable # ################# + class FastCallableConverter(Converter): def __init__(self, ex, etb): """ @@ -1203,6 +1203,7 @@ def pyobject(self, ex, obj): 3.141592653589793 """ from sage.symbolic.constants import Constant + if isinstance(obj, Constant): obj = obj.expression() return self.etb.constant(obj) @@ -1265,9 +1266,11 @@ def arithmetic(self, ex, operator): return self.etb.call(truediv, 1, operands[0]) if exponent == 0.5: from sage.misc.functional import sqrt + return self.etb.call(sqrt, operands[0]) if exponent == -0.5: from sage.misc.functional import sqrt + return self.etb.call(truediv, 1, self.etb.call(sqrt, operands[0])) elif operator is neg: return self.etb.call(operator, operands[0]) @@ -1430,10 +1433,12 @@ def arithmetic(self, ex, operator): if operator is pow: from sage.rings.integer import Integer from sage.rings.rational import Rational + base, expt = operands if expt == Rational((1, 2)): from sage.misc.functional import sqrt + return sqrt(self(base)) try: expt = Integer(expt) @@ -1441,7 +1446,7 @@ def arithmetic(self, ex, operator): pass base = self(base) - return base ** expt + return base**expt if operator == add_vararg: operator = add @@ -1547,6 +1552,7 @@ def composition(self, ex, operator): True """ from sage.symbolic.function import Function + if isinstance(operator, Function): return operator(*map(self, ex.operands()), hold=True) return operator(*map(self, ex.operands())) @@ -1670,23 +1676,11 @@ class Exponentialize(ExpressionTreeWalker): from sage.rings.integer import Integer from sage.symbolic.constants import I, e from sage.symbolic.ring import SR + half = Integer(1) / Integer(2) two = Integer(2) x = SR.var("x") - CircDict = { - sin: (-half*I*exp(I*x) + half*I*exp(-I*x)).function(x), - cos: (half*exp(I*x) + half*exp(-I*x)).function(x), - sec: (two/(exp(I*x) + exp(-I*x))).function(x), - csc: (two*I/(exp(I*x) - exp(-I*x))).function(x), - tan: (-I*(exp(I*x) - exp(-I*x))/(exp(I*x) + exp(-I*x))).function(x), - cot: (I*(exp(I*x) + exp(-I*x))/(exp(I*x) - exp(-I*x))).function(x), - sinh: (-half*exp(-x) + half*exp(x)).function(x), - cosh: (half*exp(-x) + half*exp(x)).function(x), - sech: (two/(exp(-x) + exp(x))).function(x), - csch: (-two/(exp(-x) - exp(x))).function(x), - tanh: (-(exp(-x) - exp(x))/(exp(x) + exp(-x))).function(x), - coth: (-(exp(-x) + exp(x))/(exp(-x) - exp(x))).function(x) - } + CircDict = {sin: (-half * I * exp(I * x) + half * I * exp(-I * x)).function(x), cos: (half * exp(I * x) + half * exp(-I * x)).function(x), sec: (two / (exp(I * x) + exp(-I * x))).function(x), csc: (two * I / (exp(I * x) - exp(-I * x))).function(x), tan: (-I * (exp(I * x) - exp(-I * x)) / (exp(I * x) + exp(-I * x))).function(x), cot: (I * (exp(I * x) + exp(-I * x)) / (exp(I * x) - exp(-I * x))).function(x), sinh: (-half * exp(-x) + half * exp(x)).function(x), cosh: (half * exp(-x) + half * exp(x)).function(x), sech: (two / (exp(-x) + exp(x))).function(x), csch: (-two / (exp(-x) - exp(x))).function(x), tanh: (-(exp(-x) - exp(x)) / (exp(x) + exp(-x))).function(x), coth: (-(exp(-x) + exp(x)) / (exp(-x) - exp(x))).function(x)} Circs = list(CircDict) def __init__(self, ex): @@ -1721,8 +1715,7 @@ def composition(self, ex, op): -1/2*I*e^(I*x) + 1/2*I*e^(-I*x) """ if op in self.Circs: - return self.CircDict.get(op)(*[self(oper) - for oper in ex.operands()]) + return self.CircDict.get(op)(*[self(oper) for oper in ex.operands()]) return super().composition(ex, op) @@ -1771,16 +1764,17 @@ def composition(self, ex, op): from sage.functions.trig import cos, sin from sage.rings.imaginary_unit import I from sage.symbolic.ring import SR + arg = self(ex.operands()[0])() w0, w1 = (SR.wild(u) for u in range(2)) - D = arg.match(w0 + I*w1) + D = arg.match(w0 + I * w1) if D is not None: A = D.get(w1) - return exp(D.get(w0))*(cos(A) + I*sin(A)) - D = arg.match(I*w0) + return exp(D.get(w0)) * (cos(A) + I * sin(A)) + D = arg.match(I * w0) if D is not None: A = D.get(w0) - return cos(A) + I*sin(A) + return cos(A) + I * sin(A) if self.force: return cosh(arg) + sinh(arg) return exp(arg) @@ -1788,6 +1782,7 @@ def composition(self, ex, op): # Half_angle transformation. Sometimes useful in integration + class HalfAngle(ExpressionTreeWalker): """ A class that walks a symbolic expression tree, replacing each @@ -1795,31 +1790,20 @@ class HalfAngle(ExpressionTreeWalker): expression as a rational fraction in the (hyperbolic) tangent of half the original argument. """ + # Code executed once at first class reference: create canned formulae. from sage.calculus.var import function from sage.functions.hyperbolic import cosh, coth, csch, sech, sinh, tanh from sage.functions.trig import cos, cot, csc, sec, sin, tan from sage.rings.integer import Integer from sage.symbolic.ring import SR + x = SR.var("x") one = Integer(1) two = Integer(2) half = one / two halfx = half * x - HalvesDict = { - sin: two * tan(halfx) / (tan(halfx)**2 + one).function(x), - cos: -(tan(halfx)**2 - one) / (tan(halfx)**2 + one).function(x), - tan: -two * tan(halfx) / (tan(halfx)**2 - one).function(x), - csc: half * (tan(halfx)**2 + one) / tan(halfx).function(x), - sec: -(tan(halfx)**2 + one) / (tan(halfx)**2 - one).function(x), - cot: -half * (tan(halfx)**2 - one) / tan(halfx).function(x), - sinh: -two * tanh(halfx) / (tanh(halfx)**2 - one).function(x), - cosh: -(tanh(halfx)**2 + one) / (tanh(halfx)**2 - one).function(x), - tanh: two * tanh(halfx) / (tanh(halfx)**2 + one).function(x), - csch: -half * (tanh(halfx)**2 - one) / tanh(halfx).function(x), - sech: -(tanh(halfx)**2 - one) / (tanh(halfx)**2 + one).function(x), - coth: half * (tanh(halfx)**2 + one) / tanh(halfx).function(x) - } + HalvesDict = {sin: two * tan(halfx) / (tan(halfx) ** 2 + one).function(x), cos: -(tan(halfx) ** 2 - one) / (tan(halfx) ** 2 + one).function(x), tan: -two * tan(halfx) / (tan(halfx) ** 2 - one).function(x), csc: half * (tan(halfx) ** 2 + one) / tan(halfx).function(x), sec: -(tan(halfx) ** 2 + one) / (tan(halfx) ** 2 - one).function(x), cot: -half * (tan(halfx) ** 2 - one) / tan(halfx).function(x), sinh: -two * tanh(halfx) / (tanh(halfx) ** 2 - one).function(x), cosh: -(tanh(halfx) ** 2 + one) / (tanh(halfx) ** 2 - one).function(x), tanh: two * tanh(halfx) / (tanh(halfx) ** 2 + one).function(x), csch: -half * (tanh(halfx) ** 2 - one) / tanh(halfx).function(x), sech: -(tanh(halfx) ** 2 - one) / (tanh(halfx) ** 2 + one).function(x), coth: half * (tanh(halfx) ** 2 + one) / tanh(halfx).function(x)} Halves = list(HalvesDict) def __init__(self, ex): @@ -1901,6 +1885,7 @@ def composition(self, ex, operator): """ from sage.calculus.calculus import symbolic_product, symbolic_sum from sage.functions.other import Function_prod, Function_sum + if not operator: return self if isinstance(operator, Function_sum): diff --git a/src/sage/symbolic/function.pyi b/src/sage/symbolic/function.pyi index e96c7e7900d..115cd42e733 100644 --- a/src/sage/symbolic/function.pyi +++ b/src/sage/symbolic/function.pyi @@ -3,114 +3,47 @@ from collections.abc import Callable from typing import Any class Function: - def __init__(self, name: str, nargs: int, latex_name: str | None = None, conversions: dict[str, Any] | None = None, evalf_params_first: bool = True, alt_name: str | None = None): - ... - - def _evalf_try_(self, *args: Any) -> Any: - ... - - def __hash__(self) -> int: - ... - - def __repr__(self) -> str: - ... - - def _latex_(self) -> str: - ... - - def __richcmp__(self, other: Any, op: int) -> bool: - ... - - def __call__(self, *args: Any, coerce: bool = True, hold: bool = False) -> Any: - ... - - def name(self) -> str: - ... - - def number_of_arguments(self) -> int: - ... - - def variables(self) -> tuple: - ... - - def default_variable(self) -> Any: - ... - - def _is_numerical(self, x: Any) -> bool: - ... - - def _interface_init_(self, I: Any = None) -> str: - ... - - def _mathematica_init_(self) -> str: - ... - - def _sympy_init_(self, I: Any = None) -> str: - ... - + def __init__(self, name: str, nargs: int, latex_name: str | None = None, conversions: dict[str, Any] | None = None, evalf_params_first: bool = True, alt_name: str | None = None): ... + def _evalf_try_(self, *args: Any) -> Any: ... + def __hash__(self) -> int: ... + def __repr__(self) -> str: ... + def _latex_(self) -> str: ... + def __richcmp__(self, other: Any, op: int) -> bool: ... + def __call__(self, *args: Any, coerce: bool = True, hold: bool = False) -> Any: ... + def name(self) -> str: ... + def number_of_arguments(self) -> int: ... + def variables(self) -> tuple: ... + def default_variable(self) -> Any: ... + def _is_numerical(self, x: Any) -> bool: ... + def _interface_init_(self, I: Any = None) -> str: ... + def _mathematica_init_(self) -> str: ... + def _sympy_init_(self, I: Any = None) -> str: ... @property - def _sympy_(self) -> Callable: - ... - - def _maxima_init_(self, I: Any = None) -> str: - ... - - def _fast_callable_(self, etb: Any) -> Any: - ... - - def _eval_numpy_(self, *args: Any) -> Any: - ... - - def _eval_mpmath_(self, *args: Any) -> Any: - ... + def _sympy_(self) -> Callable: ... + def _maxima_init_(self, I: Any = None) -> str: ... + def _fast_callable_(self, etb: Any) -> Any: ... + def _eval_numpy_(self, *args: Any) -> Any: ... + def _eval_mpmath_(self, *args: Any) -> Any: ... class GinacFunction(Function): - def __init__(self, name: str, nargs: int = 1, latex_name: str | None = None, conversions: dict[str, Any] | None = None, ginac_name: str | None = None, evalf_params_first: bool = True, preserved_arg: int | None = None, alt_name: str | None = None): - ... + def __init__(self, name: str, nargs: int = 1, latex_name: str | None = None, conversions: dict[str, Any] | None = None, ginac_name: str | None = None, evalf_params_first: bool = True, preserved_arg: int | None = None, alt_name: str | None = None): ... class BuiltinFunction(Function): - def __init__(self, name: str, nargs: int = 1, latex_name: str | None = None, conversions: dict[str, Any] | None = None, evalf_params_first: bool = True, alt_name: str | None = None, preserved_arg: int | None = None): - ... - - def _method_arguments(self, arg: Any) -> list: - ... - - def __call__(self, *args: Any, coerce: bool = True, hold: bool = False, dont_call_method_on_arg: bool = False) -> Any: - ... - - def _is_registered(self) -> bool: - ... - - def _evalf_or_eval_(self, *args: Any) -> Any: - ... - - def __reduce__(self) -> tuple: - ... - - def __setstate__(self, state: list): - ... + def __init__(self, name: str, nargs: int = 1, latex_name: str | None = None, conversions: dict[str, Any] | None = None, evalf_params_first: bool = True, alt_name: str | None = None, preserved_arg: int | None = None): ... + def _method_arguments(self, arg: Any) -> list: ... + def __call__(self, *args: Any, coerce: bool = True, hold: bool = False, dont_call_method_on_arg: bool = False) -> Any: ... + def _is_registered(self) -> bool: ... + def _evalf_or_eval_(self, *args: Any) -> Any: ... + def __reduce__(self) -> tuple: ... + def __setstate__(self, state: list): ... class SymbolicFunction(Function): - def __init__(self, name: str, nargs: int = 0, latex_name: str | None = None, conversions: dict[str, Any] | None = None, evalf_params_first: bool = True): - ... - - def _is_registered(self) -> bool: - ... - - def _hash_(self) -> int: - ... - - def __hash__(self) -> int: - ... - - def __getstate__(self) -> tuple: - ... - - def __setstate__(self, state: tuple): - ... - -def pickle_wrapper(f: Callable | None) -> bytes | None: - ... - -def unpickle_wrapper(p: bytes | None) -> Callable | None: - ... + def __init__(self, name: str, nargs: int = 0, latex_name: str | None = None, conversions: dict[str, Any] | None = None, evalf_params_first: bool = True): ... + def _is_registered(self) -> bool: ... + def _hash_(self) -> int: ... + def __hash__(self) -> int: ... + def __getstate__(self) -> tuple: ... + def __setstate__(self, state: tuple): ... + +def pickle_wrapper(f: Callable | None) -> bytes | None: ... +def unpickle_wrapper(p: bytes | None) -> Callable | None: ... diff --git a/src/sage/symbolic/function_factory.py b/src/sage/symbolic/function_factory.py index 070b221c6ce..d04f07a0a72 100644 --- a/src/sage/symbolic/function_factory.py +++ b/src/sage/symbolic/function_factory.py @@ -11,15 +11,10 @@ ############################################################################### from __future__ import annotations -from sage.symbolic.function import (SymbolicFunction, sfunctions_funcs, - unpickle_wrapper) +from sage.symbolic.function import SymbolicFunction, sfunctions_funcs, unpickle_wrapper -def function_factory(name, nargs=0, latex_name=None, conversions=None, - evalf_params_first=True, eval_func=None, evalf_func=None, - conjugate_func=None, real_part_func=None, imag_part_func=None, - derivative_func=None, tderivative_func=None, power_func=None, - series_func=None, print_func=None, print_latex_func=None): +def function_factory(name, nargs=0, latex_name=None, conversions=None, evalf_params_first=True, eval_func=None, evalf_func=None, conjugate_func=None, real_part_func=None, imag_part_func=None, derivative_func=None, tderivative_func=None, power_func=None, series_func=None, print_func=None, print_latex_func=None): r""" Create a formal symbolic function. For an explanation of the arguments see the documentation for the method :meth:`function`. @@ -42,6 +37,7 @@ def function_factory(name, nargs=0, latex_name=None, conversions=None, sage: g(2).n() 1.00000000000000 """ + class NewSymbolicFunction(SymbolicFunction): def __init__(self): """ @@ -52,8 +48,7 @@ def __init__(self): sage: f(2,4) f(2, 4) """ - SymbolicFunction.__init__(self, name, nargs, latex_name, - conversions, evalf_params_first) + SymbolicFunction.__init__(self, name, nargs, latex_name, conversions, evalf_params_first) def _maxima_init_(self): """ @@ -83,6 +78,7 @@ def _fricas_init_(self): def _sympy_(self): from sympy import Function + return Function(self.name()) def __reduce__(self): @@ -96,12 +92,11 @@ def __reduce__(self): f(1, 2) """ pickled_functions = self.__getstate__()[6] - return (unpickle_function, (name, nargs, latex_name, conversions, - evalf_params_first, pickled_functions)) + return (unpickle_function, (name, nargs, latex_name, conversions, evalf_params_first, pickled_functions)) l = locals() for func_name in sfunctions_funcs: - func = l.get(func_name+"_func", None) + func = l.get(func_name + "_func", None) if func: if not callable(func): raise ValueError(func_name + "_func" + " parameter must be callable") @@ -110,8 +105,7 @@ def __reduce__(self): return NewSymbolicFunction() -def unpickle_function(name, nargs, latex_name, conversions, evalf_params_first, - pickled_funcs): +def unpickle_function(name, nargs, latex_name, conversions, evalf_params_first, pickled_funcs): r""" This is returned by the ``__reduce__`` method of symbolic functions to be called during unpickling to recreate the given function. diff --git a/src/sage/symbolic/function_factory.pyi b/src/sage/symbolic/function_factory.pyi index c560962c71c..f1261989923 100644 --- a/src/sage/symbolic/function_factory.pyi +++ b/src/sage/symbolic/function_factory.pyi @@ -21,9 +21,7 @@ def function_factory( series_func: Callable | None = None, print_func: Callable | None = None, print_latex_func: Callable | None = None, -) -> SymbolicFunction: - ... - +) -> SymbolicFunction: ... def unpickle_function( name: str, nargs: int, @@ -31,11 +29,5 @@ def unpickle_function( conversions: dict[str, Any] | None, evalf_params_first: bool, pickled_funcs: list[Any], -) -> SymbolicFunction: - ... - -def function( - s: str, - **kwds: Any -) -> SymbolicFunction | list[SymbolicFunction]: - ... +) -> SymbolicFunction: ... +def function(s: str, **kwds: Any) -> SymbolicFunction | list[SymbolicFunction]: ... diff --git a/src/sage/symbolic/getitem_impl.pyi b/src/sage/symbolic/getitem_impl.pyi index 5cf2055f5f2..3e8e88c082b 100644 --- a/src/sage/symbolic/getitem_impl.pyi +++ b/src/sage/symbolic/getitem_impl.pyi @@ -1,24 +1,13 @@ from collections.abc import Iterable from typing import Any -def normalize_index(arg: Any, nops: int, err_msg: str) -> int: - ... - -def normalize_index_for_doctests(arg: int, nops: int) -> int: - ... +def normalize_index(arg: Any, nops: int, err_msg: str) -> int: ... +def normalize_index_for_doctests(arg: int, nops: int) -> int: ... class OperandsWrapper: - def __getitem__(self, arg: int | slice | list[int] | tuple[int, ...]) -> Any: - ... - - def _repr_(self) -> str: - ... - - def _latex_(self) -> str: - ... - - def __reduce__(self) -> tuple: - ... + def __getitem__(self, arg: int | slice | list[int] | tuple[int, ...]) -> Any: ... + def _repr_(self) -> str: ... + def _latex_(self) -> str: ... + def __reduce__(self) -> tuple: ... -def restore_op_wrapper(expr: Any) -> OperandsWrapper: - ... +def restore_op_wrapper(expr: Any) -> OperandsWrapper: ... diff --git a/src/sage/symbolic/integration/external.py b/src/sage/symbolic/integration/external.py index 17f11b63779..a2eccb73660 100644 --- a/src/sage/symbolic/integration/external.py +++ b/src/sage/symbolic/integration/external.py @@ -7,6 +7,7 @@ sage: sympy_integrator(sin(x), x) # needs sympy -cos(x) """ + from sage.symbolic.expression import Expression from sage.symbolic.ring import SR @@ -39,6 +40,7 @@ def maxima_integrator(expression, v, a=None, b=None): + sin(x)^2 - 2*cos(x) + 1) - 2*log(log(x)))/x """ from sage.calculus.calculus import maxima + if not isinstance(expression, Expression): expression = SR(expression) if a is None: @@ -61,6 +63,7 @@ def sympy_integrator(expression, v, a=None, b=None): sin(x) """ import sympy + ex = expression._sympy_() v = v._sympy_() if a is None: @@ -110,17 +113,15 @@ def mma_free_integrator(expression, v, a=None, b=None): 1/2*sqrt(pi)*erf(x)*log(x) - x*hypergeometric((1/2, 1/2), (3/2, 3/2), -x^2) """ from sage.interfaces.mathematica import request_wolfram_alpha, parse_moutput_from_json, symbolic_expression_from_mathematica_string + math_expr = expression._mathematica_init_() variable = v._mathematica_init_() if a is None and b is None: input = "Integrate[{},{}]".format(math_expr, variable) elif a is not None and b is not None: - input = "Integrate[{},{{{},{},{}}}]".format(math_expr, variable, - a._mathematica_init_(), - b._mathematica_init_()) + input = "Integrate[{},{{{},{},{}}}]".format(math_expr, variable, a._mathematica_init_(), b._mathematica_init_()) else: - raise ValueError('a(={}) and b(={}) should be both None' - ' or both defined'.format(a, b)) + raise ValueError('a(={}) and b(={}) should be both None' ' or both defined'.format(a, b)) json_page_data = request_wolfram_alpha(input) all_outputs = parse_moutput_from_json(json_page_data) if not all_outputs: @@ -190,6 +191,7 @@ def fricas_integrator(expression, v, a=None, b=None, noPole=True): expression = SR(expression) from sage.interfaces.fricas import fricas + e_fricas = fricas(expression) v_fricas = fricas(v) @@ -209,8 +211,7 @@ def fricas_integrator(expression, v, a=None, b=None, noPole=True): result = expression.integrate(v, a, b, hold=True) elif result == "potentialPole": - raise ValueError("The integrand has a potential pole" - " in the integration interval") + raise ValueError("The integrand has a potential pole" " in the integration interval") return result @@ -257,6 +258,7 @@ def libgiac_integrator(expression, v, a=None, b=None): return expression.integrate(v, a, b, hold=True) from sage.libs.giac.giac import Pygen + # We call Pygen on first argument because otherwise some # expressions involving derivatives result in doctest failures in # sage/interfaces/sympy.py diff --git a/src/sage/symbolic/integration/integral.py b/src/sage/symbolic/integration/integral.py index e3ddb0e6c30..8fe16e4bced 100644 --- a/src/sage/symbolic/integration/integral.py +++ b/src/sage/symbolic/integration/integral.py @@ -1,6 +1,7 @@ """ Symbolic Integration """ + # **************************************************************************** # Copyright (C) 2009 Golam Mortuza Hossain # Copyright (C) 2010 Burcin Erocal @@ -88,12 +89,9 @@ def __init__(self): # The libgiac integrator may immediately return a symbolic # (unevaluated) answer if libgiac is unavailable. This essentially # causes it to be skipped. - self.integrators = [external.maxima_integrator, - external.libgiac_integrator, - external.sympy_integrator] + self.integrators = [external.maxima_integrator, external.libgiac_integrator, external.sympy_integrator] - BuiltinFunction.__init__(self, "integrate", nargs=2, conversions={'sympy': 'Integral', - 'giac': 'integrate'}) + BuiltinFunction.__init__(self, "integrate", nargs=2, conversions={'sympy': 'Integral', 'giac': 'integrate'}) def _eval_(self, f, x): """ @@ -135,8 +133,7 @@ def _eval_(self, f, x): for integrator in self.integrators: try: A = integrator(f, x) - except (NotImplementedError, TypeError, - AttributeError, RuntimeError): + except (NotImplementedError, TypeError, AttributeError, RuntimeError): pass except ValueError: # maxima is telling us something @@ -180,6 +177,7 @@ def _print_latex_(self, f, x): \int \frac{\tan\left(x\right)}{x}\,{d x} """ from sage.misc.latex import latex + if not (isinstance(x, Expression) and x.is_symbol()): dx_str = "{d \\left(%s\\right)}" % latex(x) else: @@ -219,12 +217,9 @@ def __init__(self): # in the given order. This is an attribute of the class instead of # a global variable in this module to enable customization by # creating a subclasses which define a different set of integrators - self.integrators = [external.maxima_integrator, - external.libgiac_integrator, - external.sympy_integrator] + self.integrators = [external.maxima_integrator, external.libgiac_integrator, external.sympy_integrator] - BuiltinFunction.__init__(self, "integrate", nargs=4, conversions={'sympy': 'Integral', - 'giac': 'integrate'}) + BuiltinFunction.__init__(self, "integrate", nargs=4, conversions={'sympy': 'Integral', 'giac': 'integrate'}) def _eval_(self, f, x, a, b): """ @@ -261,8 +256,7 @@ def _eval_(self, f, x, a, b): for integrator in self.integrators: try: A = integrator(*args) - except (NotImplementedError, TypeError, - AttributeError, RuntimeError): + except (NotImplementedError, TypeError, AttributeError, RuntimeError): pass except ValueError: # maxima is telling us something @@ -296,6 +290,7 @@ def _evalf_(self, f, x, a, b, parent=None, algorithm=None): 0.154572952320790 """ from sage.calculus.integration import numerical_integral + # The gsl routine returns a tuple, which also contains the error. # We only return the result. return numerical_integral(f, a, b)[0] @@ -356,12 +351,12 @@ def _print_latex_(self, f, x, a, b): \int_{0}^{1} \frac{\tan\left(x\right)}{x}\,{d x} """ from sage.misc.latex import latex + if not (isinstance(x, Expression) and x.is_symbol()): dx_str = "{d \\left(%s\\right)}" % latex(x) else: dx_str = "{d %s}" % latex(x) - return "\\int_{%s}^{%s} %s\\,%s" % (latex(a), latex(b), - latex(f), dx_str) + return "\\int_{%s}^{%s} %s\\,%s" % (latex(a), latex(b), latex(f), dx_str) def _sympy_(self, f, x, a, b): """ @@ -377,6 +372,7 @@ def _sympy_(self, f, x, a, b): 1/2 """ from sympy.integrals import Integral + return Integral(f, (x, a, b)) @@ -432,8 +428,7 @@ def _normalize_integral_input(f, v, a=None, b=None): elif len(v) == 3: # variable and two endpoints v, a, b = v else: - raise TypeError("invalid input %s - please use variable, " - "with or without two endpoints" % repr(v)) + raise TypeError("invalid input %s - please use variable, " "with or without two endpoints" % repr(v)) if (a is None) ^ (b is None): raise TypeError('only one endpoint was given!') diff --git a/src/sage/symbolic/operators.py b/src/sage/symbolic/operators.py index fcada6cdcdf..fd7c79fc933 100644 --- a/src/sage/symbolic/operators.py +++ b/src/sage/symbolic/operators.py @@ -55,21 +55,9 @@ def mul_vararg(first, *rest): return first -arithmetic_operators = {add_vararg: '+', - mul_vararg: '*', - operator.add: '+', - operator.sub: '-', - operator.mul: '*', - operator.truediv: '/', - operator.floordiv: '//', - operator.pow: '^'} - -relation_operators = {operator.eq: '==', - operator.lt: '<', - operator.gt: '>', - operator.ne: '!=', - operator.le: '<=', - operator.ge: '>='} +arithmetic_operators = {add_vararg: '+', mul_vararg: '*', operator.add: '+', operator.sub: '-', operator.mul: '*', operator.truediv: '/', operator.floordiv: '//', operator.pow: '^'} + +relation_operators = {operator.eq: '==', operator.lt: '<', operator.gt: '>', operator.ne: '!=', operator.le: '<=', operator.ge: '>='} class FDerivativeOperator: @@ -83,6 +71,7 @@ class FDerivativeOperator: a list recording the indices of the variables with respect to which the partial derivative is taken. """ + def __init__(self, function, parameter_set): r""" Initialize this function derivative operator. @@ -124,8 +113,7 @@ def __call__(self, *args): sage: op(1) D[0](f)(1) """ - if (not all(isinstance(x, Expression) and x.is_symbol() for x in args) or - len(args) != len(set(args))): + if not all(isinstance(x, Expression) and x.is_symbol() for x in args) or len(args) != len(set(args)): # An evaluated derivative of the form f'(1) is not a # symbolic variable, yet we would like to treat it # like one. So, we replace the argument `1` with a @@ -226,6 +214,7 @@ class DerivativeOperator: sage: D[0, 1](f)(x, x^2) D[0, 1](f)(x, x^2) """ + class DerivativeOperatorWithParameters: def __init__(self, parameter_set): self._parameter_set = parameter_set diff --git a/src/sage/symbolic/operators.pyi b/src/sage/symbolic/operators.pyi index 16a20359582..c737971a318 100644 --- a/src/sage/symbolic/operators.pyi +++ b/src/sage/symbolic/operators.pyi @@ -1,61 +1,25 @@ from collections.abc import Callable from typing import Any -def add_vararg(first: Any, *rest: Any) -> Any: - ... +def add_vararg(first: Any, *rest: Any) -> Any: ... +def mul_vararg(first: Any, *rest: Any) -> Any: ... -def mul_vararg(first: Any, *rest: Any) -> Any: - ... +arithmetic_operators: dict[Callable, str] = {add_vararg: '+', mul_vararg: '*', operator.add: '+', operator.sub: '-', operator.mul: '*', operator.truediv: '/', operator.floordiv: '//', operator.pow: '^'} -arithmetic_operators: dict[Callable, str] = { - add_vararg: '+', - mul_vararg: '*', - operator.add: '+', - operator.sub: '-', - operator.mul: '*', - operator.truediv: '/', - operator.floordiv: '//', - operator.pow: '^' -} - -relation_operators: dict[Callable, str] = { - operator.eq: '==', - operator.lt: '<', - operator.gt: '>', - operator.ne: '!=', - operator.le: '<=', - operator.ge: '>=' -} +relation_operators: dict[Callable, str] = {operator.eq: '==', operator.lt: '<', operator.gt: '>', operator.ne: '!=', operator.le: '<=', operator.ge: '>='} class FDerivativeOperator: - def __init__(self, function: Callable, parameter_set: list[int]) -> None: - ... - - def __call__(self, *args: Any) -> Any: - ... - - def __repr__(self) -> str: - ... - - def function(self) -> Callable: - ... - - def change_function(self, new: Callable) -> FDerivativeOperator: - ... - - def parameter_set(self) -> list[int]: - ... + def __init__(self, function: Callable, parameter_set: list[int]) -> None: ... + def __call__(self, *args: Any) -> Any: ... + def __repr__(self) -> str: ... + def function(self) -> Callable: ... + def change_function(self, new: Callable) -> FDerivativeOperator: ... + def parameter_set(self) -> list[int]: ... class DerivativeOperator: class DerivativeOperatorWithParameters: - def __init__(self, parameter_set: list[int]) -> None: - ... - - def __call__(self, function: Callable) -> FDerivativeOperator: - ... - - def __repr__(self) -> str: - ... + def __init__(self, parameter_set: list[int]) -> None: ... + def __call__(self, function: Callable) -> FDerivativeOperator: ... + def __repr__(self) -> str: ... - def __getitem__(self, args: int | tuple[int, ...]) -> DerivativeOperatorWithParameters: - ... + def __getitem__(self, args: int | tuple[int, ...]) -> DerivativeOperatorWithParameters: ... diff --git a/src/sage/symbolic/random_tests.py b/src/sage/symbolic/random_tests.py index bf74681fc18..47dfd855491 100644 --- a/src/sage/symbolic/random_tests.py +++ b/src/sage/symbolic/random_tests.py @@ -17,16 +17,16 @@ from sage.rings.rational_field import QQ from sage.symbolic.ring import SR from sage.symbolic.expression import symbol_table, mixed_order -from sage.symbolic.constants import (pi, e, golden_ratio, log2, euler_gamma, - catalan, khinchin, twinprime, mertens) +from sage.symbolic.constants import pi, e, golden_ratio, log2, euler_gamma, catalan, khinchin, twinprime, mertens from sage.functions.hypergeometric import hypergeometric -from sage.functions.other import (cases, element_of) +from sage.functions.other import cases, element_of ############################################################## # Generate random expressions for doctests # ############################################################## + def _mk_full_functions(): r""" A simple function that returns a list of all Pynac functions of known @@ -50,11 +50,7 @@ def _mk_full_functions(): """ excluded = [hypergeometric, cases, element_of] items = sorted(symbol_table['functions'].items()) - return [(1.0, f, f.number_of_arguments()) - for (name, f) in items - if hasattr(f, 'number_of_arguments') and - f.number_of_arguments() > 0 and - f not in excluded] + return [(1.0, f, f.number_of_arguments()) for (name, f) in items if hasattr(f, 'number_of_arguments') and f.number_of_arguments() > 0 and f not in excluded] # For creating simple expressions @@ -69,11 +65,8 @@ def _mk_full_functions(): full_binary = [(0.3, operator.add), (0.1, operator.sub), (0.3, operator.mul), (0.2, operator.truediv), (0.1, operator.pow)] full_unary = [(0.8, operator.neg), (0.2, operator.inv)] full_functions = _mk_full_functions() -full_nullary = [(1.0, c) for c in [pi, e]] + [(0.05, c) for c in - [golden_ratio, log2, euler_gamma, catalan, khinchin, twinprime, - mertens]] -full_internal = [(0.6, full_binary, 2), (0.2, full_unary, 1), - (0.2, full_functions)] +full_nullary = [(1.0, c) for c in [pi, e]] + [(0.05, c) for c in [golden_ratio, log2, euler_gamma, catalan, khinchin, twinprime, mertens]] +full_internal = [(0.6, full_binary, 2), (0.2, full_unary, 1), (0.2, full_functions)] def normalize_prob_list(pl, extra=()): @@ -120,8 +113,7 @@ def normalize_prob_list(pl, extra=()): p_extra = extra if isinstance(val, list): norm_val = normalize_prob_list(val, extra=p_extra) - result.extend(((prob / total) * np[0], np[1]) + np[2:] - for np in norm_val) + result.extend(((prob / total) * np[0], np[1]) + np[2:] for np in norm_val) else: result.append(((prob / total), val) + p_extra) return result @@ -258,17 +250,13 @@ def random_expr_helper(n_nodes, internal, leaves, verbose): n_spare_nodes = n_nodes - n_children n_spare_nodes = max(0, n_spare_nodes) nodes_per_child = random_integer_vector(n_spare_nodes, n_children) - children = [random_expr_helper(n + 1, internal, leaves, verbose) - for n in nodes_per_child] + children = [random_expr_helper(n + 1, internal, leaves, verbose) for n in nodes_per_child] if verbose: print("About to apply %r to %r" % (r[1], children)) return r[1](*children) -def random_expr(size, nvars=1, ncoeffs=None, var_frac=0.5, - internal=full_internal, - nullary=full_nullary, nullary_frac=0.2, - coeff_generator=QQ.random_element, verbose=False): +def random_expr(size, nvars=1, ncoeffs=None, var_frac=0.5, internal=full_internal, nullary=full_nullary, nullary_frac=0.2, coeff_generator=QQ.random_element, verbose=False): r""" Produce a random symbolic expression of the given size. By default, the expression involves (at most) one variable, an arbitrary @@ -324,6 +312,7 @@ def random_expr(size, nvars=1, ncoeffs=None, var_frac=0.5, # Test the ordering of operands # ##################################### + def assert_strict_weak_order(a, b, c, cmp_func): r""" Check that ``cmp_func`` is a strict weak order on the elements a,b,c. @@ -381,12 +370,13 @@ def assert_strict_weak_order(a, b, c, cmp_func): """ from sage.matrix.constructor import matrix from sage.combinat.permutation import Permutations + x = (a, b, c) cmp_M = matrix(3, 3) for i in range(3): for j in range(3): - cmp_M[i, j] = (cmp_func(x[i], x[j]) == 1) # or -1, doesn't matter + cmp_M[i, j] = cmp_func(x[i], x[j]) == 1 # or -1, doesn't matter msg = 'the binary relation failed to be a strict weak order on the elements \n' msg += ' a = {}\n b = {}\n c = {}\n'.format(a, b, c) @@ -411,8 +401,7 @@ def incomparable(i, j): raise ValueError(msg) # transitivity of incomparability - if (incomparable(i, j) and incomparable(j, k) and - not incomparable(i, k)): + if incomparable(i, j) and incomparable(j, k) and not incomparable(i, k): raise ValueError(msg) @@ -442,10 +431,7 @@ def coeff_generator(): def make_random_expr(): while True: try: - return random_expr( - rnd_length, nvars=nvars, ncoeffs=ncoeffs, var_frac=var_frac, - nullary_frac=nullary_frac, coeff_generator=coeff_generator, - internal=fast_nodes) + return random_expr(rnd_length, nvars=nvars, ncoeffs=ncoeffs, var_frac=var_frac, nullary_frac=nullary_frac, coeff_generator=coeff_generator, internal=fast_nodes) except (ZeroDivisionError, ValueError): pass diff --git a/src/sage/symbolic/relation.py b/src/sage/symbolic/relation.py index 72cc4eee1fa..27fe8e461f6 100644 --- a/src/sage/symbolic/relation.py +++ b/src/sage/symbolic/relation.py @@ -357,6 +357,7 @@ - William Stein (2007-07-16): added arithmetic with symbolic equations """ + import operator from itertools import product @@ -514,13 +515,13 @@ def check_relation_maxima(relation): if relation.operator() == operator.eq: # operator is equality try: - s = test_max_equal(relation.lhs(),relation.rhs()) + s = test_max_equal(relation.lhs(), relation.rhs()) except TypeError: raise ValueError("unable to evaluate the predicate '%s'" % repr(relation)) elif relation.operator() == operator.ne: # operator is not equal try: - s = test_max_notequal(relation.lhs(),relation.rhs()) + s = test_max_notequal(relation.lhs(), relation.rhs()) except TypeError: raise ValueError("unable to evaluate the predicate '%s'" % repr(relation)) @@ -580,6 +581,7 @@ def check_relation_maxima_neq_as_not_eq(relation): # This ensures bool(x != y) == not bool(x == y) for semantic consistency. if relation.operator() == operator.ne: from sage.interfaces.maxima_lib import test_max_equal + return test_max_equal(relation.lhs(), relation.rhs()) is not True # For all other relations, delegate to check_relation_maxima @@ -612,6 +614,7 @@ def string_to_list_of_solutions(s): from sage.calculus.calculus import symbolic_expression_from_maxima_string from sage.categories.objects import Objects from sage.structure.sequence import Sequence + v = symbolic_expression_from_maxima_string(s, equals_sub=True) return Sequence(v, universe=Objects(), cr_str=True) @@ -681,6 +684,7 @@ def _normalize_to_relational(f): if isinstance(f, (list, tuple)): return [_normalize_to_relational(g) for g in f] from sage.symbolic.expression import Expression + if isinstance(f, bool) or (isinstance(f, Expression) and f.is_relational()): return f return f == 0 @@ -716,6 +720,7 @@ def _normalize_to_nonrelational(f): if isinstance(f, bool): return 0 if f else 1 from sage.symbolic.expression import Expression + if isinstance(f, Expression) and f.is_relational(): assert f.operator() == operator.eq return f.lhs() - f.rhs() @@ -741,6 +746,7 @@ def _normalize_to_list_expressions(f) -> list: TypeError: must be a symbolic expression or a list of symbolic expressions """ from sage.symbolic.expression import Expression + if isinstance(f, (Expression, bool)): f = [f] if not isinstance(f, (list, tuple)) or not all(isinstance(s, (Expression, bool)) for s in f): @@ -753,8 +759,7 @@ def _normalize_to_list_expressions(f) -> list: ########### -def solve(f, *args, explicit_solutions=None, multiplicities=None, to_poly_solve=None, - solution_dict=False, algorithm=None, domain=None): +def solve(f, *args, explicit_solutions=None, multiplicities=None, to_poly_solve=None, solution_dict=False, algorithm=None, domain=None): r""" Algebraically solve an equation or system of equations (over the complex numbers) for given variables. Inequalities and systems @@ -1246,6 +1251,7 @@ def solve(f, *args, explicit_solutions=None, multiplicities=None, to_poly_solve= [[x == 1, y == 2]] """ from sage.structure.element import Expression + f = _normalize_to_list_expressions(f) # Normalize x to list of variables @@ -1281,6 +1287,7 @@ def solve(f, *args, explicit_solutions=None, multiplicities=None, to_poly_solve= if not x: if multiplicities: from sage.rings.integer_ring import ZZ + return [[]], [ZZ.one()] return [[]] @@ -1291,6 +1298,7 @@ def solve(f, *args, explicit_solutions=None, multiplicities=None, to_poly_solve= from sympy import solve as ssolve from sage.interfaces.sympy import sympy_set_to_list + sympy_f = [s._sympy_() for s in f] sympy_vars = tuple([v._sympy_() for v in x]) ret = ssolve(sympy_f, sympy_vars, dict=True) @@ -1302,19 +1310,15 @@ def solve(f, *args, explicit_solutions=None, multiplicities=None, to_poly_solve= l = [] for d in ret: r = {} - for (v, ex) in d.items(): + for v, ex in d.items(): r[v._sage_()] = ex._sage_() l.append(r) return l - return [[v._sage_() == ex._sage_() - for v, ex in d.items()] - for d in ret] + return [[v._sage_() == ex._sage_() for v, ex in d.items()] for d in ret] if isinstance(ret, list): if solution_dict: - return [{v._sage_(): ex._sage_() - for v, ex in d.items()} for d in ret] - return [[v._sage_() == ex._sage_() - for v, ex in d.items()] for d in ret] + return [{v._sage_(): ex._sage_() for v, ex in d.items()} for d in ret] + return [[v._sage_() == ex._sage_() for v, ex in d.items()] for d in ret] # it is not clear how this branch could be reached # because dict=True is passed above, however # it is kept just in case @@ -1324,6 +1328,7 @@ def solve(f, *args, explicit_solutions=None, multiplicities=None, to_poly_solve= return _giac_solver(f, x, solution_dict) from sage.calculus.calculus import maxima + m = maxima(f) try: @@ -1356,8 +1361,7 @@ def solve(f, *args, explicit_solutions=None, multiplicities=None, to_poly_solve= if not sol_list: # fixes IndexError on empty solution list (#8553) return [] if isinstance(sol_list[0], list): - sol_dict = [{eq.left(): eq.right() for eq in solution} - for solution in sol_list] + sol_dict = [{eq.left(): eq.right() for eq in solution} for solution in sol_list] else: sol_dict = [{eq.left(): eq.right()} for eq in sol_list] @@ -1365,8 +1369,7 @@ def solve(f, *args, explicit_solutions=None, multiplicities=None, to_poly_solve= return sol_list -def _solve_expression(f, x, explicit_solutions, multiplicities, - to_poly_solve, solution_dict, algorithm, domain): +def _solve_expression(f, x, explicit_solutions, multiplicities, to_poly_solve, solution_dict, algorithm, domain): """ Solve an expression ``f``. For more information, see :func:`solve`. @@ -1469,6 +1472,7 @@ def _solve_expression(f, x, explicit_solutions, multiplicities, from sympy import S, solveset from sage.interfaces.sympy import sympy_set_to_list + if isinstance(x, Expression) and x.is_symbol(): sympy_vars = (x._sympy_(),) else: @@ -1486,7 +1490,7 @@ def _solve_expression(f, x, explicit_solutions, multiplicities, except Exception: raise NotImplementedError("solving only implemented for equalities and few special inequalities, see solve_ineq") else: - f = (f == 0) + f = f == 0 if multiplicities and to_poly_solve: raise NotImplementedError("to_poly_solve does not return multiplicities") @@ -1495,10 +1499,10 @@ def _solve_expression(f, x, explicit_solutions, multiplicities, def has_integer_assumption(v) -> bool: from sage.symbolic.assumptions import GenericDeclaration, assumptions + alist = assumptions() - return any(isinstance(a, GenericDeclaration) and a.has(v) and - a._assumption in ['even', 'odd', 'integer', 'integervalued'] - for a in alist) + return any(isinstance(a, GenericDeclaration) and a.has(v) and a._assumption in ['even', 'odd', 'integer', 'integervalued'] for a in alist) + if f.variables() and all(has_integer_assumption(var) for var in f.variables()): return f.solve_diophantine(x, solution_dict=solution_dict) @@ -1506,6 +1510,7 @@ def has_integer_assumption(v) -> bool: from sympy import S, solveset from sage.interfaces.sympy import sympy_set_to_list + if isinstance(x, Expression) and x.is_symbol(): sympy_vars = (x._sympy_(),) else: @@ -1581,13 +1586,11 @@ def has_integer_assumption(v) -> bool: m = eq._maxima_() s = m.to_poly_solve(x, options='algexact:true') T = string_to_list_of_solutions(repr(s)) - X.extend(u for t in T if (u :=_to_poly_solve_unwrap_solution(t)) is not None) + X.extend(u for t in T if (u := _to_poly_solve_unwrap_solution(t)) is not None) except TypeError as mess: if ignore_exceptions: continue - elif "Error executing code in Maxima" in str(mess) or \ - "unable to make sense of Maxima expression" in \ - str(mess): + elif "Error executing code in Maxima" in str(mess) or "unable to make sense of Maxima expression" in str(mess): if not explicit_solutions: X.append(eq) # we keep this implicit solution else: @@ -1595,6 +1598,7 @@ def has_integer_assumption(v) -> bool: # make sure all the assumptions are satisfied from sage.symbolic.assumptions import assumptions + to_check = assumptions() if to_check: for ix, soln in reversed(list(enumerate(X))): @@ -1647,6 +1651,7 @@ def _giac_solver(f, x, solution_dict=False): [[2, 5], [5, 2]] """ from sage.libs.giac.giac import libgiac + f = _normalize_to_list_expressions(_normalize_to_nonrelational(f)) giac_f = libgiac(f) if isinstance(x, tuple): @@ -1891,8 +1896,7 @@ def _solve_mod_prime_power(eqns, p, m, vars): else: shifts = product(*[range(p) for _ in range(len(vars))]) pairs = product(shifts, ans) - possibles = (tuple(vector(t) + vector(shift) * (mrunning // p)) - for shift, t in pairs) + possibles = (tuple(vector(t) + vector(shift) * (mrunning // p)) for shift, t in pairs) ans = [t for t in possibles if all(e(*t) == 0 for e in eqns_mod)] if not ans: return ans @@ -1943,6 +1947,7 @@ def solve_ineq_univar(ineq): sol = ineq0.solve_rat_ineq().sage() if repr(sol) == "all": from sage.rings.infinity import Infinity + sol = [ineqvar[0] < Infinity] return sol @@ -2003,20 +2008,23 @@ def solve_ineq_fourier(ineq, vars=None): """ if vars is None: setvars = set() - for i in (ineq): + for i in ineq: setvars = setvars.union(set(i.variables())) vars = list(setvars) ineq0 = [i._maxima_() for i in ineq] ineq0[0].parent().eval("if fourier_elim_loaded#true then (fourier_elim_loaded:true,load(\"fourier_elim\"))") sol = ineq0[0].parent().fourier_elim(ineq0, vars) - ineq0[0].parent().eval("or_to_list(x):=\ + ineq0[0].parent().eval( + "or_to_list(x):=\ if not atom(x) and op(x)=\"or\" then args(x) \ - else [x]") + else [x]" + ) sol = sol.or_to_list().sage() if repr(sol) == "[emptyset]": sol = [] if repr(sol) == "[universalset]": from sage.rings.infinity import Infinity + sol = [[i < Infinity for i in vars]] return sol diff --git a/src/sage/symbolic/ring.pyi b/src/sage/symbolic/ring.pyi index 9cd5322a51e..56f2458c421 100644 --- a/src/sage/symbolic/ring.pyi +++ b/src/sage/symbolic/ring.pyi @@ -4,107 +4,45 @@ from sage.structure.element import Element from sage.structure.parent import Parent class SymbolicRing(Parent): - def __init__(self, base_ring: Any = None) -> None: - ... - - def __reduce__(self) -> tuple: - ... - - def _repr_(self) -> str: - ... - - def _latex_(self) -> str: - ... - - def _coerce_map_from_(self, R: Any) -> bool: - ... - - def _element_constructor_(self, x: Any) -> Element: - ... - - def _force_pyobject(self, x: Any, force: bool = False, recursive: bool = True) -> Element: - ... - - def wild(self, n: int = 0) -> Element: - ... - - def __contains__(self, x: Any) -> bool: - ... - - def characteristic(self) -> int: - ... - - def _an_element_(self) -> Element: - ... - - def is_field(self, proof: bool = True) -> bool: - ... - - def is_finite(self) -> bool: - ... - - def is_exact(self) -> bool: - ... - - def pi(self) -> Element: - ... - - def I(self) -> Element: - ... - - def symbol(self, name: str | None = None, latex_name: str | None = None, domain: str | None = None) -> Element: - ... - - def temp_var(self, n: int | None = None, domain: str | None = None) -> Element | tuple[Element, ...]: - ... - - def cleanup_var(self, symbol: Element | list[Element]) -> None: - ... - - def var(self, name: str, latex_name: str | None = None, n: int | None = None, domain: str | None = None) -> Element | tuple[Element, ...]: - ... - - def _repr_element_(self, x: Element) -> str: - ... - - def _latex_element_(self, x: Element) -> str: - ... - - def _call_element_(self, _the_element: Element, *args: Any, **kwds: Any) -> Element: - ... - - def subring(self, *args: Any, **kwds: Any) -> Parent: - ... - - def _fricas_init_(self) -> str: - ... - -def the_SymbolicRing() -> SymbolicRing: - ... + def __init__(self, base_ring: Any = None) -> None: ... + def __reduce__(self) -> tuple: ... + def _repr_(self) -> str: ... + def _latex_(self) -> str: ... + def _coerce_map_from_(self, R: Any) -> bool: ... + def _element_constructor_(self, x: Any) -> Element: ... + def _force_pyobject(self, x: Any, force: bool = False, recursive: bool = True) -> Element: ... + def wild(self, n: int = 0) -> Element: ... + def __contains__(self, x: Any) -> bool: ... + def characteristic(self) -> int: ... + def _an_element_(self) -> Element: ... + def is_field(self, proof: bool = True) -> bool: ... + def is_finite(self) -> bool: ... + def is_exact(self) -> bool: ... + def pi(self) -> Element: ... + def I(self) -> Element: ... + def symbol(self, name: str | None = None, latex_name: str | None = None, domain: str | None = None) -> Element: ... + def temp_var(self, n: int | None = None, domain: str | None = None) -> Element | tuple[Element, ...]: ... + def cleanup_var(self, symbol: Element | list[Element]) -> None: ... + def var(self, name: str, latex_name: str | None = None, n: int | None = None, domain: str | None = None) -> Element | tuple[Element, ...]: ... + def _repr_element_(self, x: Element) -> str: ... + def _latex_element_(self, x: Element) -> str: ... + def _call_element_(self, _the_element: Element, *args: Any, **kwds: Any) -> Element: ... + def subring(self, *args: Any, **kwds: Any) -> Parent: ... + def _fricas_init_(self) -> str: ... + +def the_SymbolicRing() -> SymbolicRing: ... class NumpyToSRMorphism: - def __init__(self, numpy_type: Any) -> None: - ... - - def _call_(self, a: Any) -> Element: - ... + def __init__(self, numpy_type: Any) -> None: ... + def _call_(self, a: Any) -> Element: ... class UnderscoreSageMorphism: - def __init__(self, t: Any, R: Any) -> None: - ... + def __init__(self, t: Any, R: Any) -> None: ... + def _call_(self, a: Any) -> Element: ... - def _call_(self, a: Any) -> Element: - ... - -def var(name: str, **kwds: Any) -> Element | tuple[Element, ...]: - ... - -def isidentifier(x: str) -> bool: - ... +def var(name: str, **kwds: Any) -> Element | tuple[Element, ...]: ... +def isidentifier(x: str) -> bool: ... class TemporaryVariables(tuple): - def __enter__(self) -> TemporaryVariables: - ... - - def __exit__(self, *args: Any) -> bool: - ... + def __enter__(self) -> TemporaryVariables: ... + def __exit__(self, *args: Any) -> bool: ... diff --git a/src/sage/symbolic/subring.py b/src/sage/symbolic/subring.py index da7a6ff0769..bc916bde7de 100644 --- a/src/sage/symbolic/subring.py +++ b/src/sage/symbolic/subring.py @@ -166,9 +166,8 @@ class SymbolicSubringFactory(UniqueFactory): sage: SymbolicSubring(rejecting_variables=tuple()) is SR True """ - def create_key_and_extra_args( - self, accepting_variables=None, rejecting_variables=None, - no_variables=False, **kwds): + + def create_key_and_extra_args(self, accepting_variables=None, rejecting_variables=None, no_variables=False, **kwds): r""" Given the arguments and keyword, create a key that uniquely determines this object. @@ -198,16 +197,10 @@ def create_key_and_extra_args( ... ValueError: cannot create a symbolic subring since input is ambiguous """ - if accepting_variables is None and \ - rejecting_variables is None and \ - not no_variables: - raise ValueError('cannot create a symbolic subring ' - 'since nothing is specified') - if accepting_variables is not None and rejecting_variables is not None or \ - rejecting_variables is not None and no_variables or \ - no_variables and accepting_variables is not None: - raise ValueError('cannot create a symbolic subring ' - 'since input is ambiguous') + if accepting_variables is None and rejecting_variables is None and not no_variables: + raise ValueError('cannot create a symbolic subring ' 'since nothing is specified') + if accepting_variables is not None and rejecting_variables is not None or rejecting_variables is not None and no_variables or no_variables and accepting_variables is not None: + raise ValueError('cannot create a symbolic subring ' 'since input is ambiguous') if accepting_variables is not None: vars = tuple(accepting_variables) @@ -278,9 +271,7 @@ def __init__(self, vars): super().__init__() self._vars_ = set(vars) if not all(v.is_symbol() for v in self._vars_): - raise ValueError('Invalid variables: {}'.format( - ', '.join(str(v) for v in sorted(self._vars_, key=str) - if not v.is_symbol()))) + raise ValueError('Invalid variables: {}'.format(', '.join(str(v) for v in sorted(self._vars_, key=str) if not v.is_symbol()))) def _repr_variables_(self): r""" @@ -351,8 +342,7 @@ def _element_constructor_(self, x): """ expression = super()._element_constructor_(x) assert expression.parent() is self - if not all(self.has_valid_variable(var) - for var in expression.variables()): + if not all(self.has_valid_variable(var) for var in expression.variables()): raise TypeError('%s is not contained in %s' % (x, self)) return expression @@ -402,15 +392,10 @@ def _coerce_map_from_(self, P): if isinstance(P, type): return SR._coerce_map_from_(P) - if RLF.has_coerce_map_from(P) or \ - CLF.has_coerce_map_from(P) or \ - AA.has_coerce_map_from(P) or \ - QQbar.has_coerce_map_from(P): + if RLF.has_coerce_map_from(P) or CLF.has_coerce_map_from(P) or AA.has_coerce_map_from(P) or QQbar.has_coerce_map_from(P): return True - if (P is InfinityRing or - isinstance(P, (sage.rings.abc.RealIntervalField, - sage.rings.abc.ComplexIntervalField))): + if P is InfinityRing or isinstance(P, (sage.rings.abc.RealIntervalField, sage.rings.abc.ComplexIntervalField)): return True if P._is_numerical(): @@ -514,6 +499,7 @@ def __init__(self, vars): """ self.vars = set(vars) from sage.categories.rings import Rings + super().__init__(Rings(), Rings()) def _repr_variables_(self): @@ -547,9 +533,7 @@ def _repr_(self): sage: SymbolicSubring(no_variables=True) # indirect doctest Symbolic Constants Subring """ - return 'Subring<%s%s%s>' % ( - self._repr_type_, ' ' if self._repr_type_ else '', - self._repr_variables_() if self.vars else 'no variable') + return 'Subring<%s%s%s>' % (self._repr_type_, ' ' if self._repr_type_ else '', self._repr_variables_() if self.vars else 'no variable') def merge(self, other): r""" @@ -627,8 +611,7 @@ def _repr_(self): sage: SymbolicSubring(accepting_variables=('a',)) # indirect doctest Symbolic Subring accepting the variable a """ - return 'Symbolic Subring accepting %s' % \ - (self._repr_variables_()) + return 'Symbolic Subring accepting %s' % (self._repr_variables_()) def has_valid_variable(self, variable): r""" @@ -771,8 +754,7 @@ def _apply_functor(self, R): symbolic ring but Symbolic Subring accepting the variable a given. """ if R is not SR: - raise NotImplementedError('This functor can only be applied on ' - 'the symbolic ring but %s given.' % (R,)) + raise NotImplementedError('This functor can only be applied on ' 'the symbolic ring but %s given.' % (R,)) return SymbolicSubring(accepting_variables=self.vars) @@ -794,8 +776,7 @@ def _repr_(self): sage: SymbolicSubring(rejecting_variables=('r',)) # indirect doctest Symbolic Subring rejecting the variable r """ - return 'Symbolic Subring rejecting %s' % \ - (self._repr_variables_()) + return 'Symbolic Subring rejecting %s' % (self._repr_variables_()) def has_valid_variable(self, variable): r""" @@ -960,8 +941,7 @@ def _apply_functor(self, R): symbolic ring but Symbolic Subring rejecting the variable r given. """ if R is not SR: - raise NotImplementedError('This functor can only be applied on ' - 'the symbolic ring but %s given.' % (R,)) + raise NotImplementedError('This functor can only be applied on ' 'the symbolic ring but %s given.' % (R,)) return SymbolicSubring(rejecting_variables=self.vars) diff --git a/src/sage/symbolic/symbols.py b/src/sage/symbolic/symbols.py index 1669aee6e67..5001effe357 100644 --- a/src/sage/symbolic/symbols.py +++ b/src/sage/symbolic/symbols.py @@ -1,6 +1,7 @@ r""" Symbol table """ + # **************************************************************************** # Copyright (C) 2009 Mike Hansen # diff --git a/src/sage/symbolic/tests.py b/src/sage/symbolic/tests.py index 6743f0b4205..cc2547f3533 100644 --- a/src/sage/symbolic/tests.py +++ b/src/sage/symbolic/tests.py @@ -29,6 +29,7 @@ def rational_powers_memleak(): """ from sage.rings.integer_ring import ZZ import gc + gc.collect() c0 = sum(1 for obj in gc.get_objects()) for i in range(1000): diff --git a/src/sage/symbolic/units.py b/src/sage/symbolic/units.py index 5e768e39aa5..258b670ef34 100644 --- a/src/sage/symbolic/units.py +++ b/src/sage/symbolic/units.py @@ -101,119 +101,26 @@ unitdict = { -'acceleration': - {'gal': one / 100, - 'galileo': one / 100, - 'gravity': '9.80665000000000'}, - -'amount_of_substance': - {'elementary_entity': '1/6.02214129000000e23', - 'mole': 1}, - -'angles': - {'arc_minute': '1/10800*pi', - 'arc_second': '1/648000*pi', - 'degree': '1/180*pi', - 'grade': '1/200*pi', - 'quadrant': '1/2*pi', - 'radian': 1, - 'right_angle': '1/2*pi'}, - -'area': - {'acre': QQ(316160658) / 78125, - 'are': 100, - 'barn': one / 10000000000000000000000000000, - 'hectare': 10000, - 'rood': QQ(158080329) / 156250, - 'section': QQ(40468564224) / 15625, - 'square_chain': QQ(158080329) / 390625, - 'square_meter': 1, - 'township': QQ(1456868312064) / 15625}, - -'capacitance': - {'abfarad': 1000000000, - 'farad': 1, - 'statfarad': QQ(25000) / 22468879468420441}, - -'charge': - {'abcoulomb': 10, - 'coulomb': 1, - 'elementary_charge': '1.60217646200000e-19', - 'faraday': '96485.3399000000', - 'franklin': one / 2997924580, - 'statcoulomb': one / 2997924580}, - -'conductance': - {'abmho': 1000000000, - 'mho': 1, - 'siemens': 1}, - -'current': - {'abampere': 10, - 'amp': 1, - 'ampere': 1, - 'biot': 10, - 'statampere': one / 2997924580}, - -'electric_potential': - {'abvolt': one / 100000000, - 'statvolt': QQ(149896229) / 500000, - 'volt': 1}, - -'energy': - {'british_thermal_unit': QQ(52752792631) / 50000000, - 'btu': QQ(52752792631) / 50000000, - 'calorie': QQ(10467) / 2500, - 'electron_volt': '1.60217733000000e-19', - 'erg': one / 10000000, - 'ev': '1.60217733000000e-19', - 'joule': 1, - 'rydberg': '2.17987200000000e-18', - 'therm': QQ(52752792631) / 500}, - -'fiber_linear_mass_density': - {'denier': one / 9000000, - 'tex': one / 1000000}, - -'force': - {'dyne': one / 100000, - 'gram_weight': QQ(196133) / 20000000, - 'kilogram_force': QQ(196133) / 20000, - 'kilogram_weight': QQ(196133) / 20000, - 'newton': 1, - 'pound_force': QQ(8896443230521) / 2000000000000, - 'pound_weight': QQ(8896443230521) / 2000000000000, - 'poundal': QQ(17281869297) / 125000000000, - 'ton_force': QQ(8896443230521) / 1000000000}, - -'frequency': - {'1/second': 1, - 'hertz': 1}, - -'illuminance': - {'foot_candle': QQ(1562500) / 145161, - 'lux': 1, - 'phot': 10000}, - -'inductance': - {'abhenry': one / 1000000000, - 'henry': 1, - 'stathenry': QQ(22468879468420441) / 25000}, - -'information': - {'bit': 1, - 'byte': 8, - 'nibble': 4}, - -'information_rate': - {'baud': 1}, - -'inverse_length': - {'diopter': 1, - 'kayser': 100}, - -'length': - {'angstrom': one / 10000000000, + 'acceleration': {'gal': one / 100, 'galileo': one / 100, 'gravity': '9.80665000000000'}, + 'amount_of_substance': {'elementary_entity': '1/6.02214129000000e23', 'mole': 1}, + 'angles': {'arc_minute': '1/10800*pi', 'arc_second': '1/648000*pi', 'degree': '1/180*pi', 'grade': '1/200*pi', 'quadrant': '1/2*pi', 'radian': 1, 'right_angle': '1/2*pi'}, + 'area': {'acre': QQ(316160658) / 78125, 'are': 100, 'barn': one / 10000000000000000000000000000, 'hectare': 10000, 'rood': QQ(158080329) / 156250, 'section': QQ(40468564224) / 15625, 'square_chain': QQ(158080329) / 390625, 'square_meter': 1, 'township': QQ(1456868312064) / 15625}, + 'capacitance': {'abfarad': 1000000000, 'farad': 1, 'statfarad': QQ(25000) / 22468879468420441}, + 'charge': {'abcoulomb': 10, 'coulomb': 1, 'elementary_charge': '1.60217646200000e-19', 'faraday': '96485.3399000000', 'franklin': one / 2997924580, 'statcoulomb': one / 2997924580}, + 'conductance': {'abmho': 1000000000, 'mho': 1, 'siemens': 1}, + 'current': {'abampere': 10, 'amp': 1, 'ampere': 1, 'biot': 10, 'statampere': one / 2997924580}, + 'electric_potential': {'abvolt': one / 100000000, 'statvolt': QQ(149896229) / 500000, 'volt': 1}, + 'energy': {'british_thermal_unit': QQ(52752792631) / 50000000, 'btu': QQ(52752792631) / 50000000, 'calorie': QQ(10467) / 2500, 'electron_volt': '1.60217733000000e-19', 'erg': one / 10000000, 'ev': '1.60217733000000e-19', 'joule': 1, 'rydberg': '2.17987200000000e-18', 'therm': QQ(52752792631) / 500}, + 'fiber_linear_mass_density': {'denier': one / 9000000, 'tex': one / 1000000}, + 'force': {'dyne': one / 100000, 'gram_weight': QQ(196133) / 20000000, 'kilogram_force': QQ(196133) / 20000, 'kilogram_weight': QQ(196133) / 20000, 'newton': 1, 'pound_force': QQ(8896443230521) / 2000000000000, 'pound_weight': QQ(8896443230521) / 2000000000000, 'poundal': QQ(17281869297) / 125000000000, 'ton_force': QQ(8896443230521) / 1000000000}, + 'frequency': {'1/second': 1, 'hertz': 1}, + 'illuminance': {'foot_candle': QQ(1562500) / 145161, 'lux': 1, 'phot': 10000}, + 'inductance': {'abhenry': one / 1000000000, 'henry': 1, 'stathenry': QQ(22468879468420441) / 25000}, + 'information': {'bit': 1, 'byte': 8, 'nibble': 4}, + 'information_rate': {'baud': 1}, + 'inverse_length': {'diopter': 1, 'kayser': 100}, + 'length': { + 'angstrom': one / 10000000000, 'astronomical_unit': 149597870691, 'bolt': QQ(4572) / 125, 'cable_international': QQ(926) / 5, @@ -256,47 +163,19 @@ 'survey_foot': QQ(1200) / 3937, 'survey_mile': QQ(6336000) / 3937, 'x_unit': '1.00210000000000e-13', - 'yard': QQ(1143) / 1250}, - -'luminance': - {'apostilb': '1/pi', - 'lambert': '10000/pi', - 'nit': 1, - 'stilb': 10000}, - -'luminous_energy': - {'lumerg': 1, - 'talbot': 1}, - -'luminous_flux': - {'lumen': 1}, - -'luminous_intensity': - {'candela': 1, - 'candle': 1, - 'hefnerkerze': QQ(1019) / 1128}, - -'magnetic_field': - {'gauss': one / 10000, - 'tesla': 1}, - -'magnetic_flux': - {'maxwell': one / 100000000, - 'weber': 1}, - -'magnetic_intensity': - {'oersted': '250/pi'}, - -'magnetic_moment': - {'bohr_magneton': '9.27400915000000e-24', - 'nuclear_magneton': '5.05078324000000e-27'}, - -'magnetomotive_force': - {'ampere_turn': 1, - 'gilbert': '5/2/pi'}, - -'mass': - {'amu': '1.66053878200000e-27', + 'yard': QQ(1143) / 1250, + }, + 'luminance': {'apostilb': '1/pi', 'lambert': '10000/pi', 'nit': 1, 'stilb': 10000}, + 'luminous_energy': {'lumerg': 1, 'talbot': 1}, + 'luminous_flux': {'lumen': 1}, + 'luminous_intensity': {'candela': 1, 'candle': 1, 'hefnerkerze': QQ(1019) / 1128}, + 'magnetic_field': {'gauss': one / 10000, 'tesla': 1}, + 'magnetic_flux': {'maxwell': one / 100000000, 'weber': 1}, + 'magnetic_intensity': {'oersted': '250/pi'}, + 'magnetic_moment': {'bohr_magneton': '9.27400915000000e-24', 'nuclear_magneton': '5.05078324000000e-27'}, + 'magnetomotive_force': {'ampere_turn': 1, 'gilbert': '5/2/pi'}, + 'mass': { + 'amu': '1.66053878200000e-27', 'assay_ton': QQ(7) / 240, 'atomic_mass_unit': '1.66053878200000e-27', 'avoirdupois_ounce': QQ(45359237) / 1600000000, @@ -334,114 +213,25 @@ 'talent': "(25.7540400000000, {'greek':6000})", 'ton': QQ(45359237) / 50000, 'tonne': 1000, - 'wey': QQ(2857631931) / 25000000}, - -'power': - {'cheval_vapeur': QQ(588399) / 800, - 'horsepower': QQ(37284993579113511) / 50000000000000, - 'watt': 1}, - -'pressure': - {'atmosphere': 101325, - 'bar': 100000, - 'barye': QQ((1, 10)), - 'inch_mercury': '3386.38900000000', - 'millimeter_mercury': '133.322400000000', - 'mmhg': '133.322400000000', - 'pa': 1, - 'pascal': 1, - 'pounds_per_square_inch': QQ(8896443230521) / 1290320000, - 'psi': QQ(8896443230521) / 1290320000, - 'torr': QQ(20265) / 152}, - -'radiation': - {'becquerel': 1, - 'curie': 37000000000, - 'rutherford': 1000000}, - -'radiation_absorbed': - {'gray': 1, - 'rad': one / 100}, - -'radiation_ionizing': - {'roentgen': '0.000258000000000000', - 'rontgen': '0.000258000000000000'}, - -'resistance': - {'abohm': one / 1000000000, - 'ohm': 1, - 'statohm': QQ(22468879468420441) / 25000}, - -'si_prefixes': - {'atto': one / 1000000000000000000, - 'centi': one / 100, - 'deca': 10, - 'deci': QQ((1, 10)), - 'exa': 1000000000000000000, - 'femto': one / 1000000000000000, - 'giga': 1000000000, - 'hecto': 100, - 'kilo': 1000, - 'mega': 1000000, - 'micro': one / 1000000, - 'milli': one / 1000, - 'nano': one / 1000000000, - 'peta': 1000000000000000, - 'pico': one / 1000000000000, - 'tera': 1000000000000, - 'yocto': one / 1000000000000000000000000, - 'yotta': 1000000000000000000000000, - 'zepto': one / 1000000000000000000000, - 'zetta': 1000000000000000000000}, - -'solid_angle': - {'steradian': 1}, - -'temperature': - {'celsius': '(x + 273.15), (x), (x*9/5 + 32), ((x+273.15)*9/5)', - 'centigrade': '(x + 273.15), (x), (x*9/5 + 32), ((x+273.15)*9/5)', - 'fahrenheit': '(5/9*(x + 459.67)), ((x - 32)*5/9), (x), (x+459.67)', - 'kelvin': '(x), (x - 273.15), (x*9/5 - 459.67), (x*9/5)', - 'rankine': '(5/9*x), ((x-491.67)*5/9), (x-459.67), (x)'}, - -'time': - {'century': 3153600000, - 'day': 86400, - 'decade': 315360000, - 'fortnight': 1209600, - 'hour': 3600, - 'millenium': 31536000000, - 'minute': 60, - 'month': 2628000, - 'second': 1, - 'sidereal_day': "(86164.0905308330, {'sidereal':86400})", - 'sidereal_second': "(0.997269566329086, {'sidereal':1})", - 'sidereal_year': '3.15581497632000e7', - 'tropical_year': '3.15569251779840e7', - 'week': 604800, - 'year': 31536000}, - -'unit_multipliers': - {'bakers_dozen': 13, - 'dozen': 12, - 'gross': 144, - 'percent': one / 100}, - -'velocity': - {'knot': '463/900'}, - -'viscosity_absolute': - {'poise': one / 10, - 'reyn': QQ(8896443230521) / 1290320000}, - -'viscosity_kinematic': - {'stokes': one / 10000}, - -'viscosity_other': - {'rhes': 10}, - -'volume': - {'bag': QQ(660732565629) / 6250000000000, + 'wey': QQ(2857631931) / 25000000, + }, + 'power': {'cheval_vapeur': QQ(588399) / 800, 'horsepower': QQ(37284993579113511) / 50000000000000, 'watt': 1}, + 'pressure': {'atmosphere': 101325, 'bar': 100000, 'barye': QQ((1, 10)), 'inch_mercury': '3386.38900000000', 'millimeter_mercury': '133.322400000000', 'mmhg': '133.322400000000', 'pa': 1, 'pascal': 1, 'pounds_per_square_inch': QQ(8896443230521) / 1290320000, 'psi': QQ(8896443230521) / 1290320000, 'torr': QQ(20265) / 152}, + 'radiation': {'becquerel': 1, 'curie': 37000000000, 'rutherford': 1000000}, + 'radiation_absorbed': {'gray': 1, 'rad': one / 100}, + 'radiation_ionizing': {'roentgen': '0.000258000000000000', 'rontgen': '0.000258000000000000'}, + 'resistance': {'abohm': one / 1000000000, 'ohm': 1, 'statohm': QQ(22468879468420441) / 25000}, + 'si_prefixes': {'atto': one / 1000000000000000000, 'centi': one / 100, 'deca': 10, 'deci': QQ((1, 10)), 'exa': 1000000000000000000, 'femto': one / 1000000000000000, 'giga': 1000000000, 'hecto': 100, 'kilo': 1000, 'mega': 1000000, 'micro': one / 1000000, 'milli': one / 1000, 'nano': one / 1000000000, 'peta': 1000000000000000, 'pico': one / 1000000000000, 'tera': 1000000000000, 'yocto': one / 1000000000000000000000000, 'yotta': 1000000000000000000000000, 'zepto': one / 1000000000000000000000, 'zetta': 1000000000000000000000}, + 'solid_angle': {'steradian': 1}, + 'temperature': {'celsius': '(x + 273.15), (x), (x*9/5 + 32), ((x+273.15)*9/5)', 'centigrade': '(x + 273.15), (x), (x*9/5 + 32), ((x+273.15)*9/5)', 'fahrenheit': '(5/9*(x + 459.67)), ((x - 32)*5/9), (x), (x+459.67)', 'kelvin': '(x), (x - 273.15), (x*9/5 - 459.67), (x*9/5)', 'rankine': '(5/9*x), ((x-491.67)*5/9), (x-459.67), (x)'}, + 'time': {'century': 3153600000, 'day': 86400, 'decade': 315360000, 'fortnight': 1209600, 'hour': 3600, 'millenium': 31536000000, 'minute': 60, 'month': 2628000, 'second': 1, 'sidereal_day': "(86164.0905308330, {'sidereal':86400})", 'sidereal_second': "(0.997269566329086, {'sidereal':1})", 'sidereal_year': '3.15581497632000e7', 'tropical_year': '3.15569251779840e7', 'week': 604800, 'year': 31536000}, + 'unit_multipliers': {'bakers_dozen': 13, 'dozen': 12, 'gross': 144, 'percent': one / 100}, + 'velocity': {'knot': '463/900'}, + 'viscosity_absolute': {'poise': one / 10, 'reyn': QQ(8896443230521) / 1290320000}, + 'viscosity_kinematic': {'stokes': one / 10000}, + 'viscosity_other': {'rhes': 10}, + 'volume': { + 'bag': QQ(660732565629) / 6250000000000, 'barrel': QQ(9936705933) / 62500000000, 'board_foot': QQ(18435447) / 7812500000, 'bucket': QQ(473176473) / 31250000000, @@ -481,7 +271,8 @@ 'tun': QQ(29810117799) / 31250000000, 'uk_gallon': QQ(454609) / 100000000, 'uk_pint': QQ(454609) / 800000000, - 'wine_bottle': QQ(3) / 4000} + 'wine_bottle': QQ(3) / 4000, + }, } unit_to_type = {} @@ -500,9 +291,9 @@ def evalunitdict(): sage: sage.symbolic.units.evalunitdict() """ from sage.misc.sage_eval import sage_eval + for key, value in unitdict.items(): - unitdict[key] = {a: (sage_eval(repr(b)) if isinstance(b, str) else b) - for a, b in value.items()} + unitdict[key] = {a: (sage_eval(repr(b)) if isinstance(b, str) else b) for a, b in value.items()} # FEATURE IDEA: create a function that would allow users to add # new entries to the table without having to know anything about @@ -528,67 +319,17 @@ def evalunitdict(): ############################################################################### unit_docs = { -'acceleration_docs': - {'gal': 'Abbreviation for galileo.\nDefined to be 1/100 meter/second^2.', - 'galileo': 'Defined to be 1/100 meter/second^2.', - 'gravity': 'Also called standard gravity.\nPhysical constant defined to be 9.80665 meter/second^2.'}, - -'amount_of_substance_docs': - {'elementary_entity': 'Defined to be one elementary unit of choice, usually atoms or other elementary particles.\nApproximately equal to 1.6605e-24 moles.', - 'mole': 'SI base unit of quantity.\nDefined to be the amount of substance that has an equal number of elementary entities as there are atoms in 12 grams of carbon-12.\nEquivalent to Avogadros constant elementary entities or approximately equal to 6.022*10^23 elementary entities.'}, - -'angles_docs': - {'arc_minute': 'Defined to be 1/60 of a degree or pi/10800 radians.', - 'arc_second': 'Defined to be 1/3600 of a degree or pi/648000 radians.', - 'degree': 'Defined to be pi/180 radians.', - 'grade': 'Defined to be pi/200 radians.', - 'quadrant': 'Equivalent to a right angle.\nDefined to be pi/2 radians.', - 'radian': 'SI derived unit of angle.\nDefined to be the angle subtended at the center of a circle by an arc that is equal in length to the radius of the circle.', - 'right_angle': 'Equivalent to a quadrant.\nDefined to be pi/2 radians.'}, - -'area_docs': - {'acre': 'Defined to be 10 square chains or 4840 square yards.\nApproximately equal to 4046.856 square meters.', - 'are': 'Defined to be 100 square meters.', - 'barn': 'Defined to be 100 square femtometers or 10^-28 square meters.', - 'hectare': 'Defined to be 10000 square meters.', - 'rood': 'Defined to be 1/4 of an acre.\nApproximately equal to 1011.714 square meters.', - 'section': 'Equivalent to a square mile.\nApproximately equal to 2.59*10^6 square meters.', - 'square_chain': 'Defined to be 4356 square feet.\nApproximately equal to 404.9856 square meters.', - 'square_meter': 'SI derived unit of area.\nDefined to be meter^2.', - 'township': 'Defined to be 36 square miles.\nApproximately equal to 9.324*10^7 square meters.'}, - -'capacitance_docs': - {'abfarad': 'Defined to be 10^9 farads.', - 'farad': 'SI derived unit of capacitance.\nDefined to be the charge in coulombs a capacitor will accept for the potential across it to change one volt.\nEquivalent to coulomb/volt.', - 'statfarad': 'CGS unit defined to be statcoulomb/statvolt.\nApproximately equal to 1.11265*10^-12 farads.'}, - -'charge_docs': - {'abcoulomb': 'CGS unit defined to be 10 coulombs.', - 'coulomb': 'SI derived unit of charge.\nDefined to be the amount of electric charge transported by 1 ampere in 1 second.', - 'elementary_charge': 'Defined to be the amount of electric charge carried by a single proton or negative charge carried by a single electron.\nApproximately equal to 1.602176462*10^-19 coulombs.', - 'faraday': 'Defined to be the magnitude of electric charge in one mole of electrons.\nApproximately equal to 96485.3399 coulombs.', - 'franklin': 'CGS unit defined to be the amount of electric charge necessary such that if two stationary objects placed one centimeter apart had one franklin of charge each they would repel each other with a force of one dyne.\nApproximately equal to 3.3356*10^-10 coulombs.', - 'statcoulomb': 'Equivalent to franklin.\nApproximately equal to 3.3356*10^-10 coulombs.'}, - -'conductance_docs': - {'abmho': 'Defined to be 10^9 siemens.', - 'mho': 'Equivalent to siemens.', - 'siemens': 'SI derived unit of conductance.\nDefined to be an ampere per volt or 1/ohm.'}, - -'current_docs': - {'abampere': 'CGS unit defined to be 10 amperes.', - 'amp': 'Abbreviation for ampere.', - 'ampere': 'SI base unit of current.\nDefined to be the constant current which will produce an attractive force of 2*10^-7 newtons per meter between two straight, parallel conductors of infinite length and negligible circular cross section placed one meter apart in free space.', - 'biot': 'Equivalent to abampere.\nEqual to 10 amperes.', - 'statampere': 'CGS unit defined to be statcoulomb/second.\nApproximately equal to 3.335641*10^-10 amperes.'}, - -'electric_potential_docs': - {'abvolt': 'Defined to be 10^-8 volts.', - 'statvolt': 'CGS unit defined to be the speed of light in a vacuum/10^6 volts or approximately 299.792 volts.', - 'volt': 'SI derived unit of electric potential.\nDefined to be the value of voltage across a conductor when a current of one ampere dissipates one watt of power.'}, - -'energy_docs': - {'british_thermal_unit': 'Defined to be the amount of energy required to raise the temperature of one pound of liquid water from 60 degrees Fahrenheit to 61 degrees Fahrenheit at a constant pressure of one atmosphere.\nApproximately equal to 1055.05585 joules.', + 'acceleration_docs': {'gal': 'Abbreviation for galileo.\nDefined to be 1/100 meter/second^2.', 'galileo': 'Defined to be 1/100 meter/second^2.', 'gravity': 'Also called standard gravity.\nPhysical constant defined to be 9.80665 meter/second^2.'}, + 'amount_of_substance_docs': {'elementary_entity': 'Defined to be one elementary unit of choice, usually atoms or other elementary particles.\nApproximately equal to 1.6605e-24 moles.', 'mole': 'SI base unit of quantity.\nDefined to be the amount of substance that has an equal number of elementary entities as there are atoms in 12 grams of carbon-12.\nEquivalent to Avogadros constant elementary entities or approximately equal to 6.022*10^23 elementary entities.'}, + 'angles_docs': {'arc_minute': 'Defined to be 1/60 of a degree or pi/10800 radians.', 'arc_second': 'Defined to be 1/3600 of a degree or pi/648000 radians.', 'degree': 'Defined to be pi/180 radians.', 'grade': 'Defined to be pi/200 radians.', 'quadrant': 'Equivalent to a right angle.\nDefined to be pi/2 radians.', 'radian': 'SI derived unit of angle.\nDefined to be the angle subtended at the center of a circle by an arc that is equal in length to the radius of the circle.', 'right_angle': 'Equivalent to a quadrant.\nDefined to be pi/2 radians.'}, + 'area_docs': {'acre': 'Defined to be 10 square chains or 4840 square yards.\nApproximately equal to 4046.856 square meters.', 'are': 'Defined to be 100 square meters.', 'barn': 'Defined to be 100 square femtometers or 10^-28 square meters.', 'hectare': 'Defined to be 10000 square meters.', 'rood': 'Defined to be 1/4 of an acre.\nApproximately equal to 1011.714 square meters.', 'section': 'Equivalent to a square mile.\nApproximately equal to 2.59*10^6 square meters.', 'square_chain': 'Defined to be 4356 square feet.\nApproximately equal to 404.9856 square meters.', 'square_meter': 'SI derived unit of area.\nDefined to be meter^2.', 'township': 'Defined to be 36 square miles.\nApproximately equal to 9.324*10^7 square meters.'}, + 'capacitance_docs': {'abfarad': 'Defined to be 10^9 farads.', 'farad': 'SI derived unit of capacitance.\nDefined to be the charge in coulombs a capacitor will accept for the potential across it to change one volt.\nEquivalent to coulomb/volt.', 'statfarad': 'CGS unit defined to be statcoulomb/statvolt.\nApproximately equal to 1.11265*10^-12 farads.'}, + 'charge_docs': {'abcoulomb': 'CGS unit defined to be 10 coulombs.', 'coulomb': 'SI derived unit of charge.\nDefined to be the amount of electric charge transported by 1 ampere in 1 second.', 'elementary_charge': 'Defined to be the amount of electric charge carried by a single proton or negative charge carried by a single electron.\nApproximately equal to 1.602176462*10^-19 coulombs.', 'faraday': 'Defined to be the magnitude of electric charge in one mole of electrons.\nApproximately equal to 96485.3399 coulombs.', 'franklin': 'CGS unit defined to be the amount of electric charge necessary such that if two stationary objects placed one centimeter apart had one franklin of charge each they would repel each other with a force of one dyne.\nApproximately equal to 3.3356*10^-10 coulombs.', 'statcoulomb': 'Equivalent to franklin.\nApproximately equal to 3.3356*10^-10 coulombs.'}, + 'conductance_docs': {'abmho': 'Defined to be 10^9 siemens.', 'mho': 'Equivalent to siemens.', 'siemens': 'SI derived unit of conductance.\nDefined to be an ampere per volt or 1/ohm.'}, + 'current_docs': {'abampere': 'CGS unit defined to be 10 amperes.', 'amp': 'Abbreviation for ampere.', 'ampere': 'SI base unit of current.\nDefined to be the constant current which will produce an attractive force of 2*10^-7 newtons per meter between two straight, parallel conductors of infinite length and negligible circular cross section placed one meter apart in free space.', 'biot': 'Equivalent to abampere.\nEqual to 10 amperes.', 'statampere': 'CGS unit defined to be statcoulomb/second.\nApproximately equal to 3.335641*10^-10 amperes.'}, + 'electric_potential_docs': {'abvolt': 'Defined to be 10^-8 volts.', 'statvolt': 'CGS unit defined to be the speed of light in a vacuum/10^6 volts or approximately 299.792 volts.', 'volt': 'SI derived unit of electric potential.\nDefined to be the value of voltage across a conductor when a current of one ampere dissipates one watt of power.'}, + 'energy_docs': { + 'british_thermal_unit': 'Defined to be the amount of energy required to raise the temperature of one pound of liquid water from 60 degrees Fahrenheit to 61 degrees Fahrenheit at a constant pressure of one atmosphere.\nApproximately equal to 1055.05585 joules.', 'btu': 'Abbreviation for British thermal unit.\nApproximately equal to 1055.05585 joules.', 'calorie': 'Defined to be the amount of energy required to raise the temperature of one gram of liquid water one degree Celsius.\nEqual to 4.1868 joules.', 'electron_volt': 'Defined to be the amount of kinetic energy gained by a single unbound electron when it accelerates through an electrostatic potential difference of 1 volt.\nApproximately equal to 1.602*10^-19 joules.', @@ -596,14 +337,11 @@ def evalunitdict(): 'ev': 'Abbreviation for electron volt.\nApproximately equal to 1.602*10^-19 joules.', 'joule': 'SI derived unit of energy.\nDefined to be kilogram*meter^2/second^2.', 'rydberg': 'Defined to be the absolute value of the binding energy of the electron in the ground state hydrogen atom.\nApproximately equal to 2.17987*10^-18 joules.', - 'therm': 'Defined to be 100,000 British thermal units.\nApproximately equal to 1.05505585*10^8 joules.'}, - -'fiber_linear_mass_density_docs': - {'denier': 'Defined to be 1 gram per 9000 meters.\nEqual to 1/9000000 of a kilogram/meter.', - 'tex': 'Defined to be 1 gram per 1000 meters.\nEqual to 1/1000000 of a kilogram/meter.'}, - -'force_docs': - {'dyne': 'CGS unit for force defined to be gram*centimeter/second^2.\nEqual to 10^-5 newtons.', + 'therm': 'Defined to be 100,000 British thermal units.\nApproximately equal to 1.05505585*10^8 joules.', + }, + 'fiber_linear_mass_density_docs': {'denier': 'Defined to be 1 gram per 9000 meters.\nEqual to 1/9000000 of a kilogram/meter.', 'tex': 'Defined to be 1 gram per 1000 meters.\nEqual to 1/1000000 of a kilogram/meter.'}, + 'force_docs': { + 'dyne': 'CGS unit for force defined to be gram*centimeter/second^2.\nEqual to 10^-5 newtons.', 'gram_weight': 'Defined to be the magnitude of the force exerted on one gram of mass by a 9.80665 meter/second^2 gravitational field.\nEqual to 1/1000 of a kilogram weight.\nEqual to 0.00980665 newtons.', 'kilogram_force': 'Equivalent to a kilogram weight.\nEqual to 9.80665 newtons.', 'kilogram_weight': 'Defined to be the magnitude of the force exerted on one kilogram of mass by a 9.80665 meter/second^2 gravitational field.\nEqual to 9.80665 newtons.', @@ -611,35 +349,16 @@ def evalunitdict(): 'pound_force': 'Equivalent to a pound weight.\nApproximately equal to 4.44822 newtons.', 'pound_weight': 'Defined to be the magnitude of the force exerted on one pound of mass by a 9.80665 meter/second^2 gravitational field.\nApproximately equal to 4.44822 newtons.', 'poundal': 'Defined to be pound*foot/second^2.\nApproximately equal to 0.13825 newtons.', - 'ton_force': 'Defined to be 2000 pounds of force.\nApproximately equal to 8896.4432 newtons.'}, - -'frequency_docs': - {'hertz': 'SI derived unit of frequency.\nDefined to be one complete cycle per second.'}, - -'illuminance_docs': - {'foot_candle': 'Defined to be lumen/foot^2.\nApproximately equal to 10.764 lux.', - 'lux': 'SI derived unit of illuminance.\nDefined to be lumen/meter^2.', - 'phot': 'CGS unit defined to be 10000 lux.'}, - -'inductance_docs': - {'abhenry': 'Defined to be 10^-9 henries.', - 'henry': 'SI derived unit of inductance./nDefined to be a volt per ampere per second.', - 'stathenry': 'CGS unit defined to be one statvolt*second/statampere.\nApproximately equal to 8.98758*10^11 henries.'}, - -'information_docs': - {'bit': 'Base unit of information.\nDefined to be the maximum amount of information that can be stored by a device of other physical system that can normally exist in only two distinct states.', - 'byte': 'Defined to be 8 bits.', - 'nibble': 'Defined to be 4 bits.'}, - -'information_rate_docs': - {'baud': 'Defined to be 1 bit/second.'}, - -'inverse_length_docs': - {'diopter': 'Defined to be 1/meter.', - 'kayser': 'Defined to be 100/meter.'}, - -'length_docs': - {'angstrom': 'Defined to be 10^-10 meters.', + 'ton_force': 'Defined to be 2000 pounds of force.\nApproximately equal to 8896.4432 newtons.', + }, + 'frequency_docs': {'hertz': 'SI derived unit of frequency.\nDefined to be one complete cycle per second.'}, + 'illuminance_docs': {'foot_candle': 'Defined to be lumen/foot^2.\nApproximately equal to 10.764 lux.', 'lux': 'SI derived unit of illuminance.\nDefined to be lumen/meter^2.', 'phot': 'CGS unit defined to be 10000 lux.'}, + 'inductance_docs': {'abhenry': 'Defined to be 10^-9 henries.', 'henry': 'SI derived unit of inductance./nDefined to be a volt per ampere per second.', 'stathenry': 'CGS unit defined to be one statvolt*second/statampere.\nApproximately equal to 8.98758*10^11 henries.'}, + 'information_docs': {'bit': 'Base unit of information.\nDefined to be the maximum amount of information that can be stored by a device of other physical system that can normally exist in only two distinct states.', 'byte': 'Defined to be 8 bits.', 'nibble': 'Defined to be 4 bits.'}, + 'information_rate_docs': {'baud': 'Defined to be 1 bit/second.'}, + 'inverse_length_docs': {'diopter': 'Defined to be 1/meter.', 'kayser': 'Defined to be 100/meter.'}, + 'length_docs': { + 'angstrom': 'Defined to be 10^-10 meters.', 'astronomical_unit': 'Originally defined as the length of the semi-major axis of the elliptical orbit of the Earth around the Sun.\nRedefined for accuracy to be the radius of an unperturbed circular Newtonian orbit about the Sun of a particle having infinitesimal mass, moving with a mean motion of 0.01720209895 radians per day.\nApproximately equal to 1.496*10^11 meters.', 'bolt': 'Defined to be 40 yards.\nEqual to 36.576 meters.', 'cable_international': 'Nautical unit defined to be 1/10 of a nautical mile.\nEqual to 185.2 meters.', @@ -682,47 +401,19 @@ def evalunitdict(): 'survey_foot': 'Defined to be 1200/3937 or approximately 0.3048006 meters.', 'survey_mile': 'Defined to be 5280 survey feet.\nApproximately equal to 1609.347 meters.', 'x_unit': 'Unit of length used to quote wavelengths of X-rays and gamma rays.\nApproximately equal to 1.0021*10^-13 meters.', - 'yard': 'Defined to be 3 feet.\nEqual to 0.9144 meters.'}, - -'luminance_docs': - {'apostilb': 'Defined to be 10^-4 lamberts.\nEqual to 1/pi*candela/meter^2.', - 'lambert': 'Defined to be 10^4/pi candela/meter^2.', - 'nit': 'Equivalent to candela/meter^2.', - 'stilb': 'CGS unit equal to 10000 candela/meter^2.'}, - -'luminous_energy_docs': - {'lumerg': 'Equivalent to lumen*second', - 'talbot': 'Equivalent to lumen*second.'}, - -'luminous_flux_docs': - {'lumen': 'SI derived unit of luminous flux.\nDefined to be candela*steradian.'}, - -'luminous_intensity_docs': - {'candela': 'SI base unit of luminous intensity.\nDefined to be the luminous intensity, in a given direction, of a source that emits monochromatic radiation of frequency 540*10^12 hertz and that has a radiant intensity in that direction of 1/683 watt per steradian.', - 'candle': 'Equivalent to candela.', - 'hefnerkerze': 'Old German unit defined to be a 8 millimeter wick burning amyl acetate with a flame height of 40 millimeters.\nApproximately equal to 0.9034 candelas.'}, - -'magnetic_field_docs': - {'gauss': 'CGS unit defined to be a maxwell/centimeter^2.\nEqual to 1/10000 of a tesla.', - 'tesla': 'SI derived unit of magnetic field.\nDefined to be the magnitude of a magnetic field such that a particle with a charge of 1 coulomb passing through that field at 1 meter/second will experience a force of 1 newton.'}, - -'magnetic_flux_docs': - {'maxwell': 'CGS unit defined to be a gauss*centimeter^2 or 10^-8 webers.', - 'weber': 'SI derived unit of magnetic flux.\nDefined to be a change in magnetic flux of 1 weber per second will induce an electromotive force of 1 volt.'}, - -'magnetic_intensity_docs': - {'oersted': 'CGS unit defined to be 1000/(4*pi) amperes per meter of flux path.'}, - -'magnetic_moment_docs': - {'bohr_magneton': 'Physical constant defined to be the magnetic moment of an electron, or elementary_charge*h_bar/2*electron_rest_mass.\nApproximately equal to 9.274*10^-24 joules/tesla.', - 'nuclear_magneton': 'Physical constant defined to be the magnetic moment of a proton, or elementary_charge*h_bar/2*proton_rest_mass.\nApproximately equal to 5.05078324*10^-27 joules/tesla.'}, - -'magnetomotive_force_docs': - {'ampere_turn': 'SI derived unit of magnetomotive force.\nDefined to be a direct current of 1 ampere flowing through a single turn loop in a vacuum.', - 'gilbert': 'CGS unit defined to be 10/(4*pi) ampere turns.'}, - -'mass_docs': - {'amu': 'Abbreviation for atomic mass unit.\nApproximately equal to 1.660538782*10^-27 kilograms.', + 'yard': 'Defined to be 3 feet.\nEqual to 0.9144 meters.', + }, + 'luminance_docs': {'apostilb': 'Defined to be 10^-4 lamberts.\nEqual to 1/pi*candela/meter^2.', 'lambert': 'Defined to be 10^4/pi candela/meter^2.', 'nit': 'Equivalent to candela/meter^2.', 'stilb': 'CGS unit equal to 10000 candela/meter^2.'}, + 'luminous_energy_docs': {'lumerg': 'Equivalent to lumen*second', 'talbot': 'Equivalent to lumen*second.'}, + 'luminous_flux_docs': {'lumen': 'SI derived unit of luminous flux.\nDefined to be candela*steradian.'}, + 'luminous_intensity_docs': {'candela': 'SI base unit of luminous intensity.\nDefined to be the luminous intensity, in a given direction, of a source that emits monochromatic radiation of frequency 540*10^12 hertz and that has a radiant intensity in that direction of 1/683 watt per steradian.', 'candle': 'Equivalent to candela.', 'hefnerkerze': 'Old German unit defined to be a 8 millimeter wick burning amyl acetate with a flame height of 40 millimeters.\nApproximately equal to 0.9034 candelas.'}, + 'magnetic_field_docs': {'gauss': 'CGS unit defined to be a maxwell/centimeter^2.\nEqual to 1/10000 of a tesla.', 'tesla': 'SI derived unit of magnetic field.\nDefined to be the magnitude of a magnetic field such that a particle with a charge of 1 coulomb passing through that field at 1 meter/second will experience a force of 1 newton.'}, + 'magnetic_flux_docs': {'maxwell': 'CGS unit defined to be a gauss*centimeter^2 or 10^-8 webers.', 'weber': 'SI derived unit of magnetic flux.\nDefined to be a change in magnetic flux of 1 weber per second will induce an electromotive force of 1 volt.'}, + 'magnetic_intensity_docs': {'oersted': 'CGS unit defined to be 1000/(4*pi) amperes per meter of flux path.'}, + 'magnetic_moment_docs': {'bohr_magneton': 'Physical constant defined to be the magnetic moment of an electron, or elementary_charge*h_bar/2*electron_rest_mass.\nApproximately equal to 9.274*10^-24 joules/tesla.', 'nuclear_magneton': 'Physical constant defined to be the magnetic moment of a proton, or elementary_charge*h_bar/2*proton_rest_mass.\nApproximately equal to 5.05078324*10^-27 joules/tesla.'}, + 'magnetomotive_force_docs': {'ampere_turn': 'SI derived unit of magnetomotive force.\nDefined to be a direct current of 1 ampere flowing through a single turn loop in a vacuum.', 'gilbert': 'CGS unit defined to be 10/(4*pi) ampere turns.'}, + 'mass_docs': { + 'amu': 'Abbreviation for atomic mass unit.\nApproximately equal to 1.660538782*10^-27 kilograms.', 'assay_ton': 'Defined to be milligram*short_ton/ounce_troy.\nEqual to 7/240 of a kilogram.', 'atomic_mass_unit': 'Defined to be one twelfth of the mass of an isolated atom of carbon-12 at rest and in its ground state.\nApproximately equal to 1.660538782*10^-27 kilograms.', 'avoirdupois_ounce': 'Equivalent to ounce.\nEqual to 1/16 of an avoirdupois pound.\nApproximately equal to 0.02835 kilograms.', @@ -760,56 +451,18 @@ def evalunitdict(): 'talent': 'Ancient Greek unit of mass.\nEqual to 6000 drachmae.\nApproximately equal to 25.754 kilograms.', 'ton': 'Equal to 2000 pounds.\nApproximately equal to 907.18 kilograms.', 'tonne': 'Equivalent to metric_ton.\nDefined to be 1000 kilograms.', - 'wey': 'Defined to be 252 pounds.\nApproximately equal to 114.305 kilograms.'}, - -'power_docs': - {'cheval_vapeur': 'Defined to be 75 kilogram force*meter/second.\nAlso known as metric horsepower.\nEqual to 735.49875 watts.', - 'horsepower': 'Defined to be 550 feet*pound force/second.\nApproximately equal to 745.7 watts.', - 'watt': 'SI derived unit of power.\nDefined to be joule/second or, in base units, kilogram*meter^2/second^3.'}, - -'pressure_docs': - {'atmosphere': 'Defined to be 101325 pascals.', - 'bar': 'Defined to be 100000 pascals.', - 'barye': 'CGS unit defined to be dyne/centimeter^2.\nEqual to 1/10 of a pascal.', - 'inch_mercury': 'Defined to be 13595.1 kilogram/meter^3*inch*gravity.\nApproximately equal to 3386.389 pascals.', - 'millimeter_mercury': 'Defined to be 13595.1 kilogram/meter^3*millimeter*gravity.\nApproximately equal to 133.3224 pascals.', - 'mmhg': 'Abbreviation for millimeter mercury.\nApproximately equal to 133.3224 pascals.', - 'pa': 'Abbreviation for pascal.', - 'pascal': 'SI derived unit of pressure.\nDefined to be newton/meter^2 or, in base units, kilogram/(meter*second^2).', - 'pounds_per_square_inch': 'Defined to be pound force/inch^2.\nApproximately equal to 6894.76 pascals.', - 'psi': 'Abbreviation for pounds per square inch.\nApproximately equal to 6894.76 pascals.', - 'torr': 'Defined to be 1/760 of an atmosphere.\nApproximately equal to 133.322 pascals.'}, - -'radiation_absorbed_docs': - {'gray': 'SI derived unit of absorbed radiation.\nDefined to be the absorption of one joule of ionizing radiation by one kilogram of matter.', - 'rad': 'Defined to be 1/100 of a gray.'}, - -'radiation_docs': - {'becquerel': 'SI derived unit of radiation.\nDefined to be the activity of a quantity of radioactive material in which one nucleus decays per second.', - 'curie': 'Defined to be 37*10^9 becquerels.', - 'rutherford': 'Defined to be 10^6 becquerels.'}, - -'radiation_ionizing_docs': - {'roentgen': 'Defined to be .000258 coulombs/kilogram.', - 'rontgen': 'Equivalent to roentgen.\nDefined to be .000258 coulombs/kilogram.'}, - -'resistance_docs': - {'abohm': 'Defined to be 10^-9 ohms.', - 'ohm': 'SI derived unit of resistance.\nDefined to be a volt per ampere.', - 'statohm': 'CGS unit defined to be statvolt/statampere.\nApproximately equal to 8.98758*10^11 ohms.'}, - -'solid_angle_docs': - {'steradian': 'SI derived unit of solid angle.\nDefined to be the solid angle subtended at the center of a sphere of radius r by a portion of the surface of the sphere having an area of r^2.'}, - -'temperature_docs': - {'celsius': 'Defined to be -273.15 at absolute zero and 0.01 at the triple point of Vienna Standard Mean Ocean Water.\nCelsius is related to kelvin by the equation K = 273.15 + degrees Celsius.\nA change of 1 degree Celsius is equivalent to a change of 1 degree kelvin.', - 'centigrade': 'Equivalent to celsius.', - 'fahrenheit': 'Defined to be 32 degrees at the freezing point of water and 212 degrees at the boiling point of water, both at standard pressure (1 atmosphere).\nFahrenheit is related to kelvin by the equation K = 5/9*(degrees Fahrenheit + 459.67).\nA change of 1 degree fahrenheit is equal to a change of 5/9 kelvin.', - 'kelvin': 'SI base unit of temperature.\nDefined to be exactly 0 at absolute zero and 273.16 at the triple point of Vienna Standard Mean Ocean Water.', - 'rankine': 'Defined to be 0 at absolute zero and to have the same degree increment as Fahrenheit.\nRankine is related to kelvin by the equation K = 5/9*R.'}, - -'time_docs': - {'century': 'Defined to be 100 years.\nEqual to 3153600000 seconds.', + 'wey': 'Defined to be 252 pounds.\nApproximately equal to 114.305 kilograms.', + }, + 'power_docs': {'cheval_vapeur': 'Defined to be 75 kilogram force*meter/second.\nAlso known as metric horsepower.\nEqual to 735.49875 watts.', 'horsepower': 'Defined to be 550 feet*pound force/second.\nApproximately equal to 745.7 watts.', 'watt': 'SI derived unit of power.\nDefined to be joule/second or, in base units, kilogram*meter^2/second^3.'}, + 'pressure_docs': {'atmosphere': 'Defined to be 101325 pascals.', 'bar': 'Defined to be 100000 pascals.', 'barye': 'CGS unit defined to be dyne/centimeter^2.\nEqual to 1/10 of a pascal.', 'inch_mercury': 'Defined to be 13595.1 kilogram/meter^3*inch*gravity.\nApproximately equal to 3386.389 pascals.', 'millimeter_mercury': 'Defined to be 13595.1 kilogram/meter^3*millimeter*gravity.\nApproximately equal to 133.3224 pascals.', 'mmhg': 'Abbreviation for millimeter mercury.\nApproximately equal to 133.3224 pascals.', 'pa': 'Abbreviation for pascal.', 'pascal': 'SI derived unit of pressure.\nDefined to be newton/meter^2 or, in base units, kilogram/(meter*second^2).', 'pounds_per_square_inch': 'Defined to be pound force/inch^2.\nApproximately equal to 6894.76 pascals.', 'psi': 'Abbreviation for pounds per square inch.\nApproximately equal to 6894.76 pascals.', 'torr': 'Defined to be 1/760 of an atmosphere.\nApproximately equal to 133.322 pascals.'}, + 'radiation_absorbed_docs': {'gray': 'SI derived unit of absorbed radiation.\nDefined to be the absorption of one joule of ionizing radiation by one kilogram of matter.', 'rad': 'Defined to be 1/100 of a gray.'}, + 'radiation_docs': {'becquerel': 'SI derived unit of radiation.\nDefined to be the activity of a quantity of radioactive material in which one nucleus decays per second.', 'curie': 'Defined to be 37*10^9 becquerels.', 'rutherford': 'Defined to be 10^6 becquerels.'}, + 'radiation_ionizing_docs': {'roentgen': 'Defined to be .000258 coulombs/kilogram.', 'rontgen': 'Equivalent to roentgen.\nDefined to be .000258 coulombs/kilogram.'}, + 'resistance_docs': {'abohm': 'Defined to be 10^-9 ohms.', 'ohm': 'SI derived unit of resistance.\nDefined to be a volt per ampere.', 'statohm': 'CGS unit defined to be statvolt/statampere.\nApproximately equal to 8.98758*10^11 ohms.'}, + 'solid_angle_docs': {'steradian': 'SI derived unit of solid angle.\nDefined to be the solid angle subtended at the center of a sphere of radius r by a portion of the surface of the sphere having an area of r^2.'}, + 'temperature_docs': {'celsius': 'Defined to be -273.15 at absolute zero and 0.01 at the triple point of Vienna Standard Mean Ocean Water.\nCelsius is related to kelvin by the equation K = 273.15 + degrees Celsius.\nA change of 1 degree Celsius is equivalent to a change of 1 degree kelvin.', 'centigrade': 'Equivalent to celsius.', 'fahrenheit': 'Defined to be 32 degrees at the freezing point of water and 212 degrees at the boiling point of water, both at standard pressure (1 atmosphere).\nFahrenheit is related to kelvin by the equation K = 5/9*(degrees Fahrenheit + 459.67).\nA change of 1 degree fahrenheit is equal to a change of 5/9 kelvin.', 'kelvin': 'SI base unit of temperature.\nDefined to be exactly 0 at absolute zero and 273.16 at the triple point of Vienna Standard Mean Ocean Water.', 'rankine': 'Defined to be 0 at absolute zero and to have the same degree increment as Fahrenheit.\nRankine is related to kelvin by the equation K = 5/9*R.'}, + 'time_docs': { + 'century': 'Defined to be 100 years.\nEqual to 3153600000 seconds.', 'day': 'Defined to be 24 hours.\nEqual to 86400 seconds.', 'decade': 'Defined to be 10 years.\nEqual to 315360000 seconds.', 'fortnight': 'Defined to be 2 weeks or 14 days.\nEqual to 1209600 seconds.', @@ -823,29 +476,15 @@ def evalunitdict(): 'sidereal_year': 'Defined to be the time taken by the Earth to orbit the Sun once with respect to the fixed stars.\nApproximately equal to 31558149.7632 seconds.', 'tropical_year': 'Defined to be the length of time that the Sun takes to return to the same position in the cycle of seasons, as seen from the Earth.\nApproximately equal to 31556925.1779840 seconds.', 'week': 'Defined to be 7 days.\nEqual to 604800 seconds.', - 'year': 'Defined to be 365 days.\nEqual to 31536000 seconds.'}, - -'unit_multipliers_docs': - {'bakers_dozen': 'Defined to be 13 items.', - 'dozen': 'Defined to be 12 items.', - 'gross': 'Defined to be 144 items.', - 'percent': 'Defined to be 1/100 of a quantity.'}, - -'velocity_docs': - {'knot': 'Nautical unit of velocity defined to be a nautical mile per hour.\nApproximately equal to 0.5144 meter/second.'}, - -'viscosity_absolute_docs': - {'poise': 'CGS unit defined to be 1/10 of pascal*second.', - 'reyn': 'Defined to be a pound_force*second/inch^2.\nApproximately equal to 6894.76 pascal*second.'}, - -'viscosity_kinematic_docs': - {'stokes': 'CGS unit defined to be 1/10000 of meter^2/second.'}, - -'viscosity_other_docs': - {'rhes': 'Defined to be 1/poise or 10/(pascal*second).'}, - -'volume_docs': - {'bag': 'Defined to be 3 bushels.\nApproximately equal to 0.10572 cubic meters.', + 'year': 'Defined to be 365 days.\nEqual to 31536000 seconds.', + }, + 'unit_multipliers_docs': {'bakers_dozen': 'Defined to be 13 items.', 'dozen': 'Defined to be 12 items.', 'gross': 'Defined to be 144 items.', 'percent': 'Defined to be 1/100 of a quantity.'}, + 'velocity_docs': {'knot': 'Nautical unit of velocity defined to be a nautical mile per hour.\nApproximately equal to 0.5144 meter/second.'}, + 'viscosity_absolute_docs': {'poise': 'CGS unit defined to be 1/10 of pascal*second.', 'reyn': 'Defined to be a pound_force*second/inch^2.\nApproximately equal to 6894.76 pascal*second.'}, + 'viscosity_kinematic_docs': {'stokes': 'CGS unit defined to be 1/10000 of meter^2/second.'}, + 'viscosity_other_docs': {'rhes': 'Defined to be 1/poise or 10/(pascal*second).'}, + 'volume_docs': { + 'bag': 'Defined to be 3 bushels.\nApproximately equal to 0.10572 cubic meters.', 'barrel': 'Defined to be 42 gallons.\nApproximately equal to 0.15899 cubic meters.', 'board_foot': 'Defined to be 144 cubic inches.\nApproximately equal to 0.0023597 cubic meters.', 'bucket': 'Defined to be 4 gallons.\nApproximately equal to 0.0151416 cubic meters.', @@ -885,7 +524,8 @@ def evalunitdict(): 'tun': 'Old English unit of wine casks defined to be 252 gallons.\nApproximately equal to 0.95392 cubic meters.', 'uk_gallon': 'Equivalent to an imperial gallon.\nEqual to 0.00454609 cubic meters.', 'uk_pint': 'Equivalent to and imperial pint.\nApproximately equal to 0.00056826 cubic meters.', - 'wine_bottle': 'Defined to be 750 milliliters.\nEqual to 0.00075 cubic meters.'} + 'wine_bottle': 'Defined to be 750 milliliters.\nEqual to 0.00075 cubic meters.', + }, } @@ -893,39 +533,40 @@ def evalunitdict(): # Dictionary for converting from derived units to base SI units. ############################################################################### -unit_derivations = {'acceleration': 'length/time^2', - 'area': 'length^2', - 'capacitance': 'time^4*current^2/(length^2*mass)', - 'charge': 'current*time', - 'conductance': 'current^2*time^3/(mass*length^2)', - 'electric_potential': 'mass*length^2/(current*time^3)', - 'energy': 'mass*length^2/time^2', - 'fiber_linear_mass_density': 'mass/length', - 'force': 'mass*length/time^2', - 'frequency': '1/time', - 'illuminance': 'luminous_intensity*solid_angle/length^2', - 'inductance': 'length^2*mass/(time^2*current^2)', - 'information_rate': 'information/time', - 'inverse_length': '1/length', - 'luminance': 'luminous_intensity/length^2', - 'luminous_energy': 'luminous_intensity*solid_angle*time', - 'luminous_flux': 'luminous_intensity*solid_angle', - 'magnetic_field': 'mass/(current*time^2)', - 'magnetic_flux': 'mass*length^2/(current*time^2)', - 'magnetic_intensity': 'current/length', - 'magnetic_moment': 'current*length^2', - 'power': 'mass*length^2/time^3', - 'pressure': 'mass/(length*time^2)', - 'radiation': '1/time', - 'radiation_absorbed': 'length^2/time^2', - 'radiation_ionizing': 'current*time/mass', - 'resistance': 'mass*length^2/(current^2*time^3)', - 'velocity': 'length/time', - 'viscosity_absolute': 'mass/(length*time)', - 'viscosity_kinematic': 'length^2/time', - 'viscosity_other': 'length*time/mass', - 'volume': 'length^3' - } +unit_derivations = { + 'acceleration': 'length/time^2', + 'area': 'length^2', + 'capacitance': 'time^4*current^2/(length^2*mass)', + 'charge': 'current*time', + 'conductance': 'current^2*time^3/(mass*length^2)', + 'electric_potential': 'mass*length^2/(current*time^3)', + 'energy': 'mass*length^2/time^2', + 'fiber_linear_mass_density': 'mass/length', + 'force': 'mass*length/time^2', + 'frequency': '1/time', + 'illuminance': 'luminous_intensity*solid_angle/length^2', + 'inductance': 'length^2*mass/(time^2*current^2)', + 'information_rate': 'information/time', + 'inverse_length': '1/length', + 'luminance': 'luminous_intensity/length^2', + 'luminous_energy': 'luminous_intensity*solid_angle*time', + 'luminous_flux': 'luminous_intensity*solid_angle', + 'magnetic_field': 'mass/(current*time^2)', + 'magnetic_flux': 'mass*length^2/(current*time^2)', + 'magnetic_intensity': 'current/length', + 'magnetic_moment': 'current*length^2', + 'power': 'mass*length^2/time^3', + 'pressure': 'mass/(length*time^2)', + 'radiation': '1/time', + 'radiation_absorbed': 'length^2/time^2', + 'radiation_ionizing': 'current*time/mass', + 'resistance': 'mass*length^2/(current^2*time^3)', + 'velocity': 'length/time', + 'viscosity_absolute': 'mass/(length*time)', + 'viscosity_kinematic': 'length^2/time', + 'viscosity_other': 'length*time/mass', + 'volume': 'length^3', +} def vars_in_str(s): @@ -979,6 +620,7 @@ def unit_derivations_expr(v): if isinstance(Z, str): d = {x: str_to_unit(x) for x in vars_in_str(Z)} from sage.misc.sage_eval import sage_eval + Z = sage_eval(Z, d) unit_derivations[v] = Z return Z @@ -1002,6 +644,7 @@ class UnitExpression(Expression): sage: type(loads(dumps(acre))) """ + def _instancedoc_(self): """ Return docstring for this unit. @@ -1046,6 +689,7 @@ class Units(ExtraTabCompletion): sage: units.power Collection of units of power: cheval_vapeur horsepower watt """ + def __init__(self, data, name=''): """ EXAMPLES:: @@ -1381,11 +1025,12 @@ def base_units(unit): x """ from sage.misc.sage_eval import sage_eval + if str(unit) not in unit_to_type: return unit if unit_to_type[str(unit)] in ['si_prefixes', 'unit_multipliers']: number = unitdict[unit_to_type[str(unit)]][str(unit)] - return (sage_eval(number) if isinstance(number, str) else number) + return sage_eval(number) if isinstance(number, str) else number v = SR.var(unit_to_type[str(unit)]) if str(v) in unit_derivations: @@ -1446,12 +1091,12 @@ def convert_temperature(expr, target): raise ValueError("cannot convert") elif target is None or unit_to_type[str(target)] == 'temperature': from sage.misc.sage_eval import sage_eval + expr_temp = expr.variables()[0] coeff = expr / expr_temp if target is not None: target_temp = target.variables()[0] - a = sage_eval(unitdict['temperature'][str(expr_temp)], - locals={'x': coeff}) + a = sage_eval(unitdict['temperature'][str(expr_temp)], locals={'x': coeff}) if target is None or target_temp == units.temperature.kelvin: return a[0] * units.temperature.kelvin if target_temp == units.temperature.celsius or target_temp == units.temperature.centigrade: diff --git a/src/sage/tensor/modules/all.py b/src/sage/tensor/modules/all.py index 4571a720ea5..efbb7ab530a 100644 --- a/src/sage/tensor/modules/all.py +++ b/src/sage/tensor/modules/all.py @@ -1,6 +1,6 @@ from sage.misc.lazy_import import lazy_import -lazy_import('sage.tensor.modules.finite_rank_free_module', - 'FiniteRankFreeModule') + +lazy_import('sage.tensor.modules.finite_rank_free_module', 'FiniteRankFreeModule') # NB: in Sage 8.8.beta2, the lazy import of FiniteRankFreeModule is necessary # to avoid some import order issue when Chart is imported in # free_module_tensor, see comments 12 to 18 in :issue:`27655`. diff --git a/src/sage/tensor/modules/alternating_contr_tensor.py b/src/sage/tensor/modules/alternating_contr_tensor.py index 8e0a7940d13..ed700794be6 100644 --- a/src/sage/tensor/modules/alternating_contr_tensor.py +++ b/src/sage/tensor/modules/alternating_contr_tensor.py @@ -27,6 +27,7 @@ class :class:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor`. - Chap. 23 of R. Godement : *Algebra* [God1968]_ - Chap. 15 of S. Lang : *Algebra* [Lan2002]_ """ + # **************************************************************************** # Copyright (C) 2017 Eric Gourgoulhon # @@ -178,6 +179,7 @@ class AlternatingContrTensor(FreeModuleTensor): sage: s.display(e) b∧b = 0 """ + def __init__(self, fmodule, degree, name=None, latex_name=None): r""" Initialize ``self``. @@ -200,10 +202,7 @@ def __init__(self, fmodule, degree, name=None, latex_name=None): sage: a1[e,0,1] = 2 sage: TestSuite(a1).run() """ - FreeModuleTensor.__init__(self, fmodule, (degree,0), name=name, - latex_name=latex_name, - antisym=range(degree), - parent=fmodule.exterior_power(degree)) + FreeModuleTensor.__init__(self, fmodule, (degree, 0), name=name, latex_name=latex_name, antisym=range(degree), parent=fmodule.exterior_power(degree)) def _repr_(self): r""" @@ -285,13 +284,9 @@ def _new_comp(self, basis): """ fmodule = self._fmodule # the base free module if self._tensor_rank == 1: - return Components(fmodule._ring, basis, 1, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter) + return Components(fmodule._ring, basis, 1, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) - return CompFullyAntiSym(fmodule._ring, basis, self._tensor_rank, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter) + return CompFullyAntiSym(fmodule._ring, basis, self._tensor_rank, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) def degree(self): r""" @@ -392,8 +387,8 @@ def display(self, basis=None, format_spec=None): from sage.misc.latex import latex from sage.typeset.unicode_characters import unicode_wedge from .format_utilities import is_atomic, FormattedExpansion - basis, format_spec = self._preparse_display(basis=basis, - format_spec=format_spec) + + basis, format_spec = self._preparse_display(basis=basis, format_spec=format_spec) comp = self.comp(basis) terms_txt = [] terms_latex = [] @@ -426,13 +421,11 @@ def display(self, basis=None, format_spec=None): if is_atomic(coef_txt): terms_txt.append(coef_txt + ' ' + basis_term_txt) else: - terms_txt.append('(' + coef_txt + ') ' + - basis_term_txt) + terms_txt.append('(' + coef_txt + ') ' + basis_term_txt) if is_atomic(coef_latex): terms_latex.append(coef_latex + basis_term_latex) else: - terms_latex.append(r'\left(' + coef_latex + - r'\right)' + basis_term_latex) + terms_latex.append(r'\left(' + coef_latex + r'\right)' + basis_term_latex) if not terms_txt: expansion_txt = '0' else: @@ -530,11 +523,11 @@ def wedge(self, other): """ from sage.typeset.unicode_characters import unicode_wedge from .format_utilities import is_atomic + if not isinstance(other, AlternatingContrTensor): - raise TypeError("the second argument for the exterior product " + - "must be an alternating contravariant tensor") + raise TypeError("the second argument for the exterior product " + "must be an alternating contravariant tensor") if other._tensor_rank == 0: - return other*self + return other * self fmodule = self._fmodule basis = self.common_basis(other) if basis is None: @@ -542,13 +535,11 @@ def wedge(self, other): rank_r = self._tensor_rank + other._tensor_rank cmp_s = self._components[basis] cmp_o = other._components[basis] - cmp_r = CompFullyAntiSym(fmodule._ring, basis, rank_r, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter) + cmp_r = CompFullyAntiSym(fmodule._ring, basis, rank_r, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) for ind_s, val_s in cmp_s._comp.items(): for ind_o, val_o in cmp_o._comp.items(): ind_r = ind_s + ind_o - if len(ind_r) == len(set(ind_r)): # all indices are different + if len(ind_r) == len(set(ind_r)): # all indices are different cmp_r[[ind_r]] += val_s * val_o result = fmodule.alternating_contravariant_tensor(rank_r) result._components[basis] = cmp_r @@ -709,27 +700,25 @@ def interior_product(self, form): """ from .format_utilities import is_atomic from .free_module_alt_form import FreeModuleAltForm + if not isinstance(form, FreeModuleAltForm): raise TypeError("{} is not an alternating form".format(form)) p_res = form._tensor_rank - self._tensor_rank # degree of the result if self._tensor_rank == 1: # Case p = 1: res = self.contract(form) # contract() deals efficiently with - # the antisymmetry for p = 1 + # the antisymmetry for p = 1 else: # Case p > 1: if form._fmodule != self._fmodule: - raise ValueError("{} is not defined on the same ".format(form) + - "module as the {}".format(self)) + raise ValueError("{} is not defined on the same ".format(form) + "module as the {}".format(self)) if form._tensor_rank < self._tensor_rank: - raise ValueError("the degree of the {} is lower ".format(form) + - "than that of the {}".format(self)) + raise ValueError("the degree of the {} is lower ".format(form) + "than that of the {}".format(self)) # Interior product at the component level: basis = self.common_basis(form) if basis is None: raise ValueError("no common basis for the interior product") - comp = self._components[basis].interior_product( - form._components[basis]) + comp = self._components[basis].interior_product(form._components[basis]) if p_res == 0: res = comp # result is a scalar else: diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 43e6443e420..760e773a3e7 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -484,8 +484,8 @@ class Components(SageObject): sage: d[0,1,2] == a[0]*b[1]*a[2] True """ - def __init__(self, ring, frame, nb_indices, start_index=0, - output_formatter=None) -> None: + + def __init__(self, ring, frame, nb_indices, start_index=0, output_formatter=None) -> None: r""" TESTS:: @@ -572,8 +572,7 @@ def _new_instance(self): sage: c._new_instance() 2-indices components w.r.t. [1, 2, 3] """ - return Components(self._ring, self._frame, self._nid, self._sindex, - self._output_formatter) + return Components(self._ring, self._frame, self._nid, self._sindex, self._output_formatter) def copy(self): r""" @@ -671,15 +670,13 @@ def _check_indices(self, indices) -> tuple: else: ind = tuple(indices) if len(ind) != self._nid: - raise ValueError(("wrong number of indices: {} expected," - " while {} are provided").format(self._nid, len(ind))) + raise ValueError(("wrong number of indices: {} expected," " while {} are provided").format(self._nid, len(ind))) si = self._sindex imax = self._dim - 1 + si for k in range(self._nid): i = ind[k] if i < si or i > imax: - raise IndexError("index out of range: " + - "{} not in [{}, {}]".format(i, si, imax)) + raise IndexError("index out of range: " + "{} not in [{}, {}]".format(i, si, imax)) return ind def __getitem__(self, args): @@ -729,7 +726,7 @@ def __getitem__(self, args): if isinstance(args[0], slice): indices = args[0] elif isinstance(args[0], (tuple, list)): # to ensure equivalence between - indices = args[0] # [[(i,j,...)]] or [[[i,j,...]]] and [[i,j,...]] + indices = args[0] # [[(i,j,...)]] or [[[i,j,...]]] and [[i,j,...]] else: indices = tuple(args) else: @@ -759,8 +756,7 @@ def __getitem__(self, args): return self._ring.zero() if format_type is None: return self._output_formatter(self._ring.zero()) - return self._output_formatter(self._ring.zero(), - format_type) + return self._output_formatter(self._ring.zero(), format_type) def _get_list(self, ind_slice, no_format=True, format_type=None): r""" @@ -826,15 +822,14 @@ def _get_list(self, ind_slice, no_format=True, format_type=None): return [self[[i]] for i in range(start, stop)] return [self[i, format_type] for i in range(start, stop)] if ind_slice.start is not None or ind_slice.stop is not None: - raise NotImplementedError("function [start:stop] not implemented " + - f"for components with {self._nid} indices") - resu = [self._gen_list([i], no_format, format_type) - for i in range(si, nsi)] + raise NotImplementedError("function [start:stop] not implemented " + f"for components with {self._nid} indices") + resu = [self._gen_list([i], no_format, format_type) for i in range(si, nsi)] if self._nid == 2: # 2-dim case: convert to matrix for a nicer output from sage.categories.rings import Rings from sage.matrix.constructor import matrix from sage.structure.element import parent + if parent(resu[0][0]) in Rings(): return matrix(resu) return resu @@ -866,8 +861,7 @@ def _gen_list(self, ind, no_format=True, format_type=None): return self[args] si = self._sindex nsi = si + self._dim - return [self._gen_list(ind + [i], no_format, format_type) - for i in range(si, nsi)] + return [self._gen_list(ind + [i], no_format, format_type) for i in range(si, nsi)] def __setitem__(self, args, value) -> None: r""" @@ -906,7 +900,7 @@ def __setitem__(self, args, value) -> None: if isinstance(args[0], slice): indices = args[0] elif isinstance(args[0], (tuple, list)): # to ensure equivalence between - indices = args[0] # [[(i,j,...)]] or [[[i,j,...]]] and [[i,j,...]] + indices = args[0] # [[(i,j,...)]] or [[[i,j,...]]] and [[i,j,...]] else: indices = tuple(args) else: @@ -986,13 +980,12 @@ def _set_list(self, ind_slice, format_type, values) -> None: if ind_slice.step is not None: raise NotImplementedError("function [start:stop:step] not implemented") for i in range(start, stop): - self[i, format_type] = values[i-start] + self[i, format_type] = values[i - start] else: if ind_slice.start is not None or ind_slice.stop is not None: - raise NotImplementedError("function [start:stop] not " + - "implemented for components with {} indices".format(self._nid)) + raise NotImplementedError("function [start:stop] not " + "implemented for components with {} indices".format(self._nid)) for i in range(si, nsi): - self._set_value_list([i], format_type, values[i-si]) + self._set_value_list([i], format_type, values[i - si]) def _set_value_list(self, ind, format_type, val): r""" @@ -1026,7 +1019,7 @@ def _set_value_list(self, ind, format_type, val): si = self._sindex nsi = si + self._dim for i in range(si, nsi): - self._set_value_list(ind + [i], format_type, val[i-si]) + self._set_value_list(ind + [i], format_type, val[i - si]) def items(self) -> Iterator: r""" @@ -1061,9 +1054,7 @@ def items(self) -> Iterator: if not zero_value: yield ind, val - def display(self, symbol, latex_symbol=None, index_positions=None, - index_labels=None, index_latex_labels=None, - format_spec=None, only_nonzero=True, only_nonredundant=False): + def display(self, symbol, latex_symbol=None, index_positions=None, index_labels=None, index_latex_labels=None, format_spec=None, only_nonzero=True, only_nonredundant=False): r""" Display all the components, one per line. @@ -1213,6 +1204,7 @@ def display(self, symbol, latex_symbol=None, index_positions=None, """ from sage.misc.latex import latex from sage.tensor.modules.format_utilities import FormattedExpansion + si = self._sindex nsi = si + self._dim if latex_symbol is None: @@ -1220,13 +1212,11 @@ def display(self, symbol, latex_symbol=None, index_positions=None, if index_positions is None: index_positions = self._nid * 'd' elif len(index_positions) != self._nid: - raise ValueError("the argument 'index_positions' must contain " + - "{} characters".format(self._nid)) + raise ValueError("the argument 'index_positions' must contain " + "{} characters".format(self._nid)) if index_labels is None: index_labels = [str(i) for i in range(si, nsi)] elif len(index_labels) != self._dim: - raise ValueError("the argument 'index_labels' must contain " + - "{} items".format(self._dim)) + raise ValueError("the argument 'index_labels' must contain " + "{} items".format(self._dim)) # Index separator: max_len_symbols = max(len(s) for s in index_labels) if max_len_symbols == 1: @@ -1236,8 +1226,7 @@ def display(self, symbol, latex_symbol=None, index_positions=None, if index_latex_labels is None: index_latex_labels = index_labels elif len(index_latex_labels) != self._dim: - raise ValueError("the argument 'index_latex_labels' must " + - "contain {} items".format(self._dim)) + raise ValueError("the argument 'index_latex_labels' must " + "contain {} items".format(self._dim)) if only_nonredundant: # To simplify the implementation of the non-redundant # index generator, it generates indices in a different @@ -1282,8 +1271,7 @@ def display(self, symbol, latex_symbol=None, index_positions=None, u_indices += r'\,' + index_latex_labels[i] previous = 'u' rtxt += symbol + indices + ' = {} \n'.format(val) - rlatex += (latex_symbol + r'_{' + d_indices + r'}^{' - + u_indices + r'} & = & ' + latex(val) + r'\\') + rlatex += latex_symbol + r'_{' + d_indices + r'}^{' + u_indices + r'} & = & ' + latex(val) + r'\\' if rtxt == '': # no component has been displayed rlatex = '' @@ -1518,7 +1506,7 @@ def __neg__(self): """ result = self._new_instance() for ind, val in self._comp.items(): - result._comp[ind] = - val + result._comp[ind] = -val return result def __add__(self, other): @@ -1562,28 +1550,24 @@ def __add__(self, other): if isinstance(other, (int, Integer)) and other == 0: return +self if not isinstance(other, Components): - raise TypeError("the second argument for the addition must be " + - "an instance of Components") + raise TypeError("the second argument for the addition must be " + "an instance of Components") if isinstance(other, CompWithSym): - return other + self # to deal properly with symmetries + return other + self # to deal properly with symmetries if other._frame != self._frame: - raise ValueError("the two sets of components are not defined on " + - "the same frame") + raise ValueError("the two sets of components are not defined on " + "the same frame") if other._nid != self._nid: - raise ValueError("the two sets of components do not have the " + - "same number of indices") + raise ValueError("the two sets of components do not have the " + "same number of indices") if other._sindex != self._sindex: - raise ValueError("the two sets of components do not have the " + - "same starting index") + raise ValueError("the two sets of components do not have the " + "same starting index") # Initialization of the result to self.copy(), so that there remains # only to add other: result = self.copy() nproc = Parallelism().get('tensor') if nproc != 1: # Parallel computation - lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] + lol = lambda lst, sz: [lst[i : i + sz] for i in range(0, len(lst), sz)] ind_list = list(other._comp) - ind_step = max(1, int(len(ind_list)/nproc/2)) + ind_step = max(1, int(len(ind_list) / nproc / 2)) local_list = lol(ind_list, ind_step) # list of input parameters listParalInput = [(self, other, ind_part) for ind_part in local_list] @@ -1592,7 +1576,7 @@ def __add__(self, other): def paral_sum(a, b, local_list_ind): partial = [] for ind in local_list_ind: - partial.append([ind, a[[ind]]+b[[ind]]]) + partial.append([ind, a[[ind]] + b[[ind]]]) return partial for ii, val in paral_sum(listParalInput): @@ -1672,7 +1656,7 @@ def __sub__(self, other): if isinstance(other, (int, Integer)) and other == 0: return +self return self + (-other) # ! # correct, deals properly with - # symmetries, but is probably not optimal + # symmetries, but is probably not optimal def __rsub__(self, other): r""" @@ -1768,33 +1752,27 @@ def __mul__(self, other): sage: Parallelism().set('tensor', nproc=1) # switch off parallelization """ if not isinstance(other, Components): - raise TypeError("the second argument for the tensor product " + - "must be an instance of Components") + raise TypeError("the second argument for the tensor product " + "must be an instance of Components") if other._frame != self._frame: - raise ValueError("the two sets of components are not defined on " + - "the same frame") + raise ValueError("the two sets of components are not defined on " + "the same frame") if other._sindex != self._sindex: - raise ValueError("the two sets of components do not have the " + - "same starting index") + raise ValueError("the two sets of components do not have the " + "same starting index") if isinstance(other, CompWithSym): sym = [] if other._sym: for s in other._sym: - ns = tuple(s[i]+self._nid for i in range(len(s))) + ns = tuple(s[i] + self._nid for i in range(len(s))) sym.append(ns) antisym = [] if other._antisym: for s in other._antisym: - ns = tuple(s[i]+self._nid for i in range(len(s))) + ns = tuple(s[i] + self._nid for i in range(len(s))) antisym.append(ns) - result = CompWithSym(self._ring, self._frame, self._nid + other._nid, - self._sindex, self._output_formatter, sym, - antisym) + result = CompWithSym(self._ring, self._frame, self._nid + other._nid, self._sindex, self._output_formatter, sym, antisym) elif self._nid == 1 and other._nid == 1: if self is other: # == would be dangerous here # The result is symmetric: - result = CompFullySym(self._ring, self._frame, 2, self._sindex, - self._output_formatter) + result = CompFullySym(self._ring, self._frame, 2, self._sindex, self._output_formatter) # The loop below on self._comp.items() and # other._comp.items() cannot be used in the present case # (it would not deal correctly with redundant indices) @@ -1804,9 +1782,9 @@ def __mul__(self, other): nproc = Parallelism().get('tensor') if nproc != 1: # Parallel computation - lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] + lol = lambda lst, sz: [lst[i : i + sz] for i in range(0, len(lst), sz)] ind_list = list(result.non_redundant_index_generator()) - ind_step = max(1, int(len(ind_list)/nproc)) + ind_step = max(1, int(len(ind_list) / nproc)) local_list = lol(ind_list, ind_step) # list of input parameters: listParalInput = [(self, ind_part) for ind_part in local_list] @@ -1815,7 +1793,7 @@ def __mul__(self, other): def paral_mul(a, local_list_ind): partial = [] for ind in local_list_ind: - partial.append([ind, a[[ind[0]]]*a[[ind[1]]]]) + partial.append([ind, a[[ind[0]]] * a[[ind[1]]]]) return partial for ii, val in paral_mul(listParalInput): @@ -1826,15 +1804,13 @@ def paral_mul(a, local_list_ind): for ind in result.non_redundant_index_generator(): result[[ind]] = self[[ind[0]]] * self[[ind[1]]] return result - result = Components(self._ring, self._frame, 2, self._sindex, - self._output_formatter) + result = Components(self._ring, self._frame, 2, self._sindex, self._output_formatter) else: - result = Components(self._ring, self._frame, self._nid + other._nid, - self._sindex, self._output_formatter) + result = Components(self._ring, self._frame, self._nid + other._nid, self._sindex, self._output_formatter) nproc = Parallelism().get('tensor') if nproc != 1: # Parallel computation - lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] + lol = lambda lst, sz: [lst[i : i + sz] for i in range(0, len(lst), sz)] ind_list = list(self._comp) ind_step = max(1, len(ind_list) // nproc) local_list = lol(ind_list, ind_step) @@ -1846,7 +1822,7 @@ def paral_mul(a, b, local_list_ind): partial = [] for ind in local_list_ind: for ind_o, val_o in b._comp.items(): - partial.append([ind + ind_o, a._comp[ind]*val_o]) + partial.append([ind + ind_o, a._comp[ind] * val_o]) return partial for ii, val in paral_mul(listParalInput): @@ -1882,7 +1858,7 @@ def __rmul__(self, other): # Left multiplication by a "scalar": result = self._new_instance() if other == 0: - return result # because a just created Components is zero + return result # because a just created Components is zero for ind, val in self._comp.items(): result._comp[ind] = other * val return result @@ -1906,8 +1882,7 @@ def __truediv__(self, other): True """ if isinstance(other, Components): - raise NotImplementedError("division by an object of type " + - "Components not implemented") + raise NotImplementedError("division by an object of type " + "Components not implemented") result = self._new_instance() for ind, val in self._comp.items(): result._comp[ind] = val / other @@ -1970,15 +1945,13 @@ def trace(self, pos1, pos2): [12, 24, 36] """ if self._nid < 2: - raise ValueError("contraction can be performed only on " + - "components with at least 2 indices") + raise ValueError("contraction can be performed only on " + "components with at least 2 indices") if pos1 < 0 or pos1 > self._nid - 1: raise IndexError("pos1 out of range") if pos2 < 0 or pos2 > self._nid - 1: raise IndexError("pos2 out of range") if pos1 == pos2: - raise IndexError("the two positions must differ for the " + - "contraction to be meaningful") + raise IndexError("the two positions must differ for the " + "contraction to be meaningful") si = self._sindex nsi = si + self._dim if self._nid == 2: @@ -1987,14 +1960,13 @@ def trace(self, pos1, pos2): res += self[[i, i]] return res # More than 2 indices - result = Components(self._ring, self._frame, self._nid - 2, - self._sindex, self._output_formatter) + result = Components(self._ring, self._frame, self._nid - 2, self._sindex, self._output_formatter) if pos1 > pos2: pos1, pos2 = (pos2, pos1) for ind, val in self._comp.items(): if ind[pos1] == ind[pos2]: # there is a contribution to the contraction - ind_res = ind[:pos1] + ind[pos1+1:pos2] + ind[pos2+1:] + ind_res = ind[:pos1] + ind[pos1 + 1 : pos2] + ind[pos2 + 1 :] result[[ind_res]] += val return result @@ -2163,27 +2135,24 @@ def contract(self, *args): it = i break else: - raise ValueError("a set of components must be provided in the " + - "argument list") + raise ValueError("a set of components must be provided in the " + "argument list") if it == 0: pos1 = (self._nid - 1,) else: pos1 = args[:it] - if it == nargs-1: + if it == nargs - 1: pos2 = (0,) else: - pos2 = args[it+1:] - ncontr = len(pos1) # number of contractions + pos2 = args[it + 1 :] + ncontr = len(pos1) # number of contractions if len(pos2) != ncontr: raise TypeError("different number of indices for the contraction") if other._frame != self._frame: - raise TypeError("the two sets of components are not defined on " + - "the same frame") + raise TypeError("the two sets of components are not defined on " + "the same frame") if other._sindex != self._sindex: - raise TypeError("the two sets of components do not have the " + - "same starting index") + raise TypeError("the two sets of components do not have the " + "same starting index") contractions = [(pos1[i], pos2[i]) for i in range(ncontr)] - res_nid = self._nid + other._nid - 2*ncontr + res_nid = self._nid + other._nid - 2 * ncontr # # Special case of a scalar result # @@ -2201,11 +2170,10 @@ def contract(self, *args): @parallel(p_iter='multiprocessing', ncpus=Parallelism().get('tensor')) def compprod(a, b): - return a*b + return a * b # parallel list of inputs - partial = list(compprod([(self[[ind_s]], other[[ind_o]]) - for ind_s, ind_o in ind_pairs])) + partial = list(compprod([(self[[ind_s]], other[[ind_o]]) for ind_s, ind_o in ind_pairs])) res = sum(map(itemgetter(1), partial)) else: # sequential computation @@ -2220,7 +2188,7 @@ def compprod(a, b): # (None = the position is involved in a contraction and therefore # does not appear in the final result) # - pos_s = [None for i in range(self._nid)] # initialization + pos_s = [None for i in range(self._nid)] # initialization pos_o = [None for i in range(other._nid)] # initialization shift = 0 for pos in range(self._nid): @@ -2237,8 +2205,8 @@ def compprod(a, b): break else: pos_o[pos] = self._nid + pos - shift - rev_s = [pos_s.index(i) for i in range(self._nid-ncontr)] - rev_o = [pos_o.index(i) for i in range(self._nid-ncontr, res_nid)] + rev_s = [pos_s.index(i) for i in range(self._nid - ncontr)] + rev_o = [pos_o.index(i) for i in range(self._nid - ncontr, res_nid)] # # Determination of the symmetries of the result # @@ -2295,52 +2263,40 @@ def compprod(a, b): # Construction of the result object in view of the remaining symmetries # if max_len_sym == 0 and max_len_antisym == 0: - res = Components(self._ring, self._frame, res_nid, - start_index=self._sindex, - output_formatter=self._output_formatter) + res = Components(self._ring, self._frame, res_nid, start_index=self._sindex, output_formatter=self._output_formatter) elif max_len_sym == res_nid: - res = CompFullySym(self._ring, self._frame, res_nid, - start_index=self._sindex, - output_formatter=self._output_formatter) + res = CompFullySym(self._ring, self._frame, res_nid, start_index=self._sindex, output_formatter=self._output_formatter) elif max_len_antisym == res_nid: - res = CompFullyAntiSym(self._ring, self._frame, res_nid, - start_index=self._sindex, - output_formatter=self._output_formatter) + res = CompFullyAntiSym(self._ring, self._frame, res_nid, start_index=self._sindex, output_formatter=self._output_formatter) else: - res = CompWithSym(self._ring, self._frame, res_nid, - start_index=self._sindex, - output_formatter=self._output_formatter, - sym=res_sym, antisym=res_antisym) + res = CompWithSym(self._ring, self._frame, res_nid, start_index=self._sindex, output_formatter=self._output_formatter, sym=res_sym, antisym=res_antisym) # # Performing the contraction # # To generate the indices tuples (of size ncontr) involved in the # the contraction, we create an empty instance of Components with # ncontr indices and call the method index_generator() on it: - comp_for_contr = Components(self._ring, self._frame, ncontr, - start_index=self._sindex) + comp_for_contr = Components(self._ring, self._frame, ncontr, start_index=self._sindex) shift_o = self._nid - ncontr if Parallelism().get('tensor') != 1: # parallel computation nproc = Parallelism().get('tensor') - lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] + lol = lambda lst, sz: [lst[i : i + sz] for i in range(0, len(lst), sz)] ind_list = list(res.non_redundant_index_generator()) - ind_step = max(1, int(len(ind_list)/nproc/2)) + ind_step = max(1, int(len(ind_list) / nproc / 2)) local_list = lol(ind_list, ind_step) listParalInput = [] for ind_part in local_list: - listParalInput.append((self, other, ind_part, rev_s, rev_o, - shift_o, contractions, comp_for_contr)) + listParalInput.append((self, other, ind_part, rev_s, rev_o, shift_o, contractions, comp_for_contr)) # definition of the parallel function @parallel(p_iter='multiprocessing', ncpus=nproc) - def make_Contraction(this, other, local_list, rev_s, rev_o, - shift_o, contractions, comp_for_contr): + def make_Contraction(this, other, local_list, rev_s, rev_o, shift_o, contractions, comp_for_contr): local_res = [] for ind in local_list: - ind_s = [None for _ in range(this._nid)] # initialization + ind_s = [None for _ in range(this._nid)] # initialization ind_o = [None for _ in range(other._nid)] # initialization for i, pos in enumerate(rev_s): ind_s[pos] = ind[i] @@ -2362,7 +2318,7 @@ def make_Contraction(this, other, local_list, rev_s, rev_o, else: # sequential computation for ind in res.non_redundant_index_generator(): - ind_s = [None for _ in range(self._nid)] # initialization + ind_s = [None for _ in range(self._nid)] # initialization ind_o = [None for _ in range(other._nid)] # initialization for i, pos in enumerate(rev_s): ind_s[pos] = ind[i] @@ -2407,7 +2363,7 @@ def index_generator(self) -> Iterator: ind = [si for k in range(self._nid)] while True: yield tuple(ind) - for pos in range(self._nid-1, -1, -1): + for pos in range(self._nid - 1, -1, -1): if ind[pos] != imax: ind[pos] += 1 break @@ -2557,21 +2513,19 @@ def symmetrize(self, *pos): True """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup + if not pos: pos = tuple(range(self._nid)) else: if len(pos) < 2: raise ValueError("at least two index positions must be given") if len(pos) > self._nid: - raise ValueError("number of index positions larger than the " - "total number of indices") - n_sym = len(pos) # number of indices involved in the symmetry + raise ValueError("number of index positions larger than the " "total number of indices") + n_sym = len(pos) # number of indices involved in the symmetry if n_sym == self._nid: - result = CompFullySym(self._ring, self._frame, self._nid, self._sindex, - self._output_formatter) + result = CompFullySym(self._ring, self._frame, self._nid, self._sindex, self._output_formatter) else: - result = CompWithSym(self._ring, self._frame, self._nid, self._sindex, - self._output_formatter, sym=pos) + result = CompWithSym(self._ring, self._frame, self._nid, self._sindex, self._output_formatter, sym=pos) sym_group = SymmetricGroup(n_sym) for ind in result.non_redundant_index_generator(): sum = 0 @@ -2705,21 +2659,19 @@ def antisymmetrize(self, *pos): True """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup + if not pos: pos = tuple(range(self._nid)) else: if len(pos) < 2: raise ValueError("at least two index positions must be given") if len(pos) > self._nid: - raise ValueError("number of index positions larger than the " - "total number of indices") - n_sym = len(pos) # number of indices involved in the antisymmetry + raise ValueError("number of index positions larger than the " "total number of indices") + n_sym = len(pos) # number of indices involved in the antisymmetry if n_sym == self._nid: - result = CompFullyAntiSym(self._ring, self._frame, self._nid, - self._sindex, self._output_formatter) + result = CompFullyAntiSym(self._ring, self._frame, self._nid, self._sindex, self._output_formatter) else: - result = CompWithSym(self._ring, self._frame, self._nid, self._sindex, - self._output_formatter, antisym=pos) + result = CompWithSym(self._ring, self._frame, self._nid, self._sindex, self._output_formatter, antisym=pos) sym_group = SymmetricGroup(n_sym) for ind in result.non_redundant_index_generator(): sum = 0 @@ -2755,6 +2707,7 @@ def _matrix_(self): True """ from sage.matrix.constructor import matrix + if self._nid != 2: raise ValueError("the set of components must have 2 indices") si = self._sindex @@ -2765,6 +2718,7 @@ def _matrix_(self): # **************************************************************************** + class CompWithSym(Components): r""" Indexed set of ring elements forming some components with respect to a @@ -2962,8 +2916,8 @@ class CompWithSym(Components): sage: e + d == d + e True """ - def __init__(self, ring, frame, nb_indices, start_index=0, - output_formatter=None, sym=None, antisym=None) -> None: + + def __init__(self, ring, frame, nb_indices, start_index=0, output_formatter=None, sym=None, antisym=None) -> None: r""" TESTS:: @@ -2971,10 +2925,8 @@ def __init__(self, ring, frame, nb_indices, start_index=0, sage: C = CompWithSym(ZZ, [1,2,3], 4, sym=(0,1), antisym=(2,3)) sage: TestSuite(C).run() """ - Components.__init__(self, ring, frame, nb_indices, start_index, - output_formatter) - self._sym, self._antisym = self._canonicalize_sym_antisym( - nb_indices, sym, antisym) + Components.__init__(self, ring, frame, nb_indices, start_index, output_formatter) + self._sym, self._antisym = self._canonicalize_sym_antisym(nb_indices, sym, antisym) @staticmethod def _canonicalize_sym_or_antisym(nb_indices, sym_or_antisym): @@ -3018,11 +2970,9 @@ def _canonicalize_sym_or_antisym(nb_indices, sym_or_antisym): continue isym = tuple(sorted(isym)) if isym[0] < 0: - raise IndexError("invalid index position: " + str(isym[0]) + - " not in [0," + str(nb_indices-1) + "]") + raise IndexError("invalid index position: " + str(isym[0]) + " not in [0," + str(nb_indices - 1) + "]") if isym[-1] > nb_indices - 1: - raise IndexError("invalid index position: " + str(isym[-1]) + - " not in [0," + str(nb_indices-1) + "]") + raise IndexError("invalid index position: " + str(isym[-1]) + " not in [0," + str(nb_indices - 1) + "]") result_sym_or_antisym.append(isym) # Canonicalize sort order, make tuples return tuple(sorted(result_sym_or_antisym)) @@ -3068,8 +3018,7 @@ def _canonicalize_sym_antisym(nb_indices, sym=None, antisym=None): index_list.extend(isym) if len(index_list) != len(set(index_list)): # There is a repeated index position: - raise IndexError("incompatible lists of symmetries: the same " + - "index position appears more than once") + raise IndexError("incompatible lists of symmetries: the same " + "index position appears more than once") return result_sym, result_antisym def _repr_symmetry(self) -> tuple[str, str]: @@ -3089,11 +3038,9 @@ def _repr_symmetry(self) -> tuple[str, str]: """ description = "" for isym in self._sym: - description += ", with symmetry on the index positions " + \ - str(tuple(isym)) + description += ", with symmetry on the index positions " + str(tuple(isym)) for isym in self._antisym: - description += ", with antisymmetry on the index positions " + \ - str(tuple(isym)) + description += ", with antisymmetry on the index positions " + str(tuple(isym)) return "", description def _new_instance(self): @@ -3108,8 +3055,7 @@ def _new_instance(self): sage: a = c._new_instance() ; a 4-indices components w.r.t. [1, 2, 3], with symmetry on the index positions (0, 1) """ - return CompWithSym(self._ring, self._frame, self._nid, self._sindex, - self._output_formatter, self._sym, self._antisym) + return CompWithSym(self._ring, self._frame, self._nid, self._sindex, self._output_formatter, self._sym, self._antisym) def _ordered_indices(self, indices) -> tuple: r""" @@ -3149,6 +3095,7 @@ def _ordered_indices(self, indices) -> tuple: (0, None) """ from sage.combinat.permutation import Permutation + ind = list(self._check_indices(indices)) for isym in self._sym: indsym = [] @@ -3175,7 +3122,7 @@ def _ordered_indices(self, indices) -> tuple: # Permutation linking indsym_ordered to indsym: # (the +1 is required to fulfill the convention of Permutation) perm = [indsym.index(i) + 1 for i in indsym_ordered] - #c# Permutation(perm).signature() + # c# Permutation(perm).signature() sign *= Permutation(perm).signature() ind = tuple(ind) return (sign, ind) @@ -3213,13 +3160,13 @@ def __getitem__(self, args): -5 """ no_format = self._output_formatter is None - format_type = None # default value, possibly redefined below + format_type = None # default value, possibly redefined below if isinstance(args, list): # case of [[...]] syntax no_format = True if isinstance(args[0], slice): indices = args[0] - elif isinstance(args[0], (tuple, list)): # to ensure equivalence between - indices = args[0] # [[(i,j,...)]] or [[[i,j,...]]] and [[i,j,...]] + elif isinstance(args[0], (tuple, list)): # to ensure equivalence between + indices = args[0] # [[(i,j,...)]] or [[[i,j,...]]] and [[i,j,...]] else: indices = tuple(args) else: @@ -3243,8 +3190,7 @@ def __getitem__(self, args): return self._ring.zero() if format_type is None: return self._output_formatter(self._ring.zero()) - return self._output_formatter(self._ring.zero(), - format_type) + return self._output_formatter(self._ring.zero(), format_type) # nonzero value if no_format: if sign == 1: @@ -3257,11 +3203,9 @@ def __getitem__(self, args): # sign = -1 return self._output_formatter(-self._comp[ind]) if sign == 1: - return self._output_formatter( - self._comp[ind], format_type) + return self._output_formatter(self._comp[ind], format_type) # sign = -1 - return self._output_formatter( - -self._comp[ind], format_type) + return self._output_formatter(-self._comp[ind], format_type) def __setitem__(self, args, value) -> None: r""" @@ -3295,12 +3239,12 @@ def __setitem__(self, args, value) -> None: ... ValueError: by antisymmetry, the component cannot have a nonzero value for the indices (2, 2) """ - format_type = None # default value, possibly redefined below + format_type = None # default value, possibly redefined below if isinstance(args, list): # case of [[...]] syntax if isinstance(args[0], slice): indices = args[0] - elif isinstance(args[0], (tuple, list)): # to ensure equivalence between - indices = args[0] # [[(i,j,...)]] or [[[i,j,...]]] and [[i,j,...]] + elif isinstance(args[0], (tuple, list)): # to ensure equivalence between + indices = args[0] # [[(i,j,...)]] or [[[i,j,...]]] and [[i,j,...]] else: indices = tuple(args) else: @@ -3329,9 +3273,7 @@ def __setitem__(self, args, value) -> None: zero_value = value == 0 if sign == 0: if not zero_value: - raise ValueError("by antisymmetry, the component cannot " + - "have a nonzero value for the indices " + - str(indices)) + raise ValueError("by antisymmetry, the component cannot " + "have a nonzero value for the indices " + str(indices)) if ind in self._comp: del self._comp[ind] # zero values are not stored elif zero_value: @@ -3341,12 +3283,12 @@ def __setitem__(self, args, value) -> None: if format_type is None: if sign == 1: self._comp[ind] = self._ring(value) - else: # sign = -1 + else: # sign = -1 self._comp[ind] = -self._ring(value) else: if sign == 1: self._comp[ind] = self._ring({format_type: value}) - else: # sign = -1 + else: # sign = -1 self._comp[ind] = -self._ring({format_type: value}) def swap_adjacent_indices(self, pos1, pos2, pos3): @@ -3409,8 +3351,7 @@ def swap_adjacent_indices(self, pos1, pos2, pos3): for s in self._antisym: new_s = [new_lpos.index(pos) for pos in s] result._antisym.append(tuple(sorted(new_s))) - result._sym, result._antisym = self._canonicalize_sym_antisym( - self._nid, result._sym, result._antisym) + result._sym, result._antisym = self._canonicalize_sym_antisym(self._nid, result._sym, result._antisym) # The values: for ind, val in self._comp.items(): new_ind = ind[:pos1] + ind[pos2:pos3] + ind[pos1:pos2] + ind[pos3:] @@ -3476,42 +3417,35 @@ def __add__(self, other): if isinstance(other, (int, Integer)) and other == 0: return +self if not isinstance(other, Components): - raise TypeError("the second argument for the addition must be a " + - "an instance of Components") + raise TypeError("the second argument for the addition must be a " + "an instance of Components") if other._frame != self._frame: - raise ValueError("the two sets of components are not defined on " + - "the same frame") + raise ValueError("the two sets of components are not defined on " + "the same frame") if other._nid != self._nid: - raise ValueError("the two sets of components do not have the " + - "same number of indices") + raise ValueError("the two sets of components do not have the " + "same number of indices") if other._sindex != self._sindex: - raise ValueError("the two sets of components do not have the " + - "same starting index") + raise ValueError("the two sets of components do not have the " + "same starting index") if isinstance(other, CompWithSym): # Are the symmetries of the same type ? diff_sym = set(self._sym).symmetric_difference(set(other._sym)) - diff_antisym = \ - set(self._antisym).symmetric_difference(set(other._antisym)) + diff_antisym = set(self._antisym).symmetric_difference(set(other._antisym)) if diff_sym == set() and diff_antisym == set(): # The symmetries/antisymmetries are identical: result = self.copy() nproc = Parallelism().get('tensor') if nproc != 1: # Parallel computation - lol = lambda lst, sz: [lst[i:i+sz] for i in - range(0, len(lst), sz)] + lol = lambda lst, sz: [lst[i : i + sz] for i in range(0, len(lst), sz)] ind_list = list(other._comp) - ind_step = max(1, int(len(ind_list)/nproc/2)) + ind_step = max(1, int(len(ind_list) / nproc / 2)) local_list = lol(ind_list, ind_step) # list of input parameters - listParalInput = [(self, other, ind_part) for ind_part in - local_list] + listParalInput = [(self, other, ind_part) for ind_part in local_list] @parallel(p_iter='multiprocessing', ncpus=nproc) def paral_sum(a, b, local_list_ind): partial = [] for ind in local_list_ind: - partial.append([ind, a[[ind]]+b[[ind]]]) + partial.append([ind, a[[ind]] + b[[ind]]]) return partial for ii, val in paral_sum(listParalInput): @@ -3538,23 +3472,19 @@ def paral_sum(a, b, local_list_ind): if len(com) > 1: common_antisym.append(com) if common_sym or common_antisym: - result = CompWithSym(self._ring, self._frame, self._nid, - self._sindex, self._output_formatter, - common_sym, common_antisym) + result = CompWithSym(self._ring, self._frame, self._nid, self._sindex, self._output_formatter, common_sym, common_antisym) else: # no common symmetry -> the result is a generic Components: - result = Components(self._ring, self._frame, self._nid, - self._sindex, self._output_formatter) + result = Components(self._ring, self._frame, self._nid, self._sindex, self._output_formatter) else: # other has no symmetry at all: - result = Components(self._ring, self._frame, self._nid, - self._sindex, self._output_formatter) + result = Components(self._ring, self._frame, self._nid, self._sindex, self._output_formatter) nproc = Parallelism().get('tensor') if nproc != 1: # Parallel computation - lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] + lol = lambda lst, sz: [lst[i : i + sz] for i in range(0, len(lst), sz)] ind_list = list(result.non_redundant_index_generator()) - ind_step = max(1, int(len(ind_list)/nproc/2)) + ind_step = max(1, int(len(ind_list) / nproc / 2)) local_list = lol(ind_list, ind_step) # definition of the list of input parameters listParalInput = [(self, other, ind_part) for ind_part in local_list] @@ -3563,7 +3493,7 @@ def paral_sum(a, b, local_list_ind): def paral_sum(a, b, local_list_ind): partial = [] for ind in local_list_ind: - partial.append([ind, a[[ind]]+b[[ind]]]) + partial.append([ind, a[[ind]] + b[[ind]]]) return partial for ii, val in paral_sum(listParalInput): @@ -3631,33 +3561,29 @@ def __mul__(self, other): sage: Parallelism().set('tensor', nproc=1) # switch off parallelization """ if not isinstance(other, Components): - raise TypeError("the second argument for the tensor product " + - "be an instance of Components") + raise TypeError("the second argument for the tensor product " + "be an instance of Components") if other._frame != self._frame: - raise ValueError("the two sets of components are not defined on " + - "the same frame") + raise ValueError("the two sets of components are not defined on " + "the same frame") if other._sindex != self._sindex: - raise ValueError("the two sets of components do not have the " + - "same starting index") + raise ValueError("the two sets of components do not have the " + "same starting index") sym = list(self._sym) antisym = list(self._antisym) if isinstance(other, CompWithSym): if other._sym: for s in other._sym: - ns = tuple(s[i]+self._nid for i in range(len(s))) + ns = tuple(s[i] + self._nid for i in range(len(s))) sym.append(ns) if other._antisym: for s in other._antisym: - ns = tuple(s[i]+self._nid for i in range(len(s))) + ns = tuple(s[i] + self._nid for i in range(len(s))) antisym.append(ns) - result = CompWithSym(self._ring, self._frame, self._nid + other._nid, - self._sindex, self._output_formatter, sym, antisym) + result = CompWithSym(self._ring, self._frame, self._nid + other._nid, self._sindex, self._output_formatter, sym, antisym) nproc = Parallelism().get('tensor') if nproc != 1: # Parallel computation - lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] + lol = lambda lst, sz: [lst[i : i + sz] for i in range(0, len(lst), sz)] ind_list = list(self._comp) - ind_step = max(1, int(len(ind_list)/nproc)) + ind_step = max(1, int(len(ind_list) / nproc)) local_list = lol(ind_list, ind_step) # list of input parameters: listParalInput = [(self, other, ind_part) for ind_part in local_list] @@ -3667,7 +3593,7 @@ def paral_mul(a, b, local_list_ind): partial = [] for ind in local_list_ind: for ind_o, val_o in b._comp.items(): - partial.append([ind + ind_o, a._comp[ind]*val_o]) + partial.append([ind + ind_o, a._comp[ind] * val_o]) return partial for ii, val in paral_mul(listParalInput): @@ -3791,15 +3717,13 @@ def trace(self, pos1, pos2): [[0, 0, 0], [-2, 1, 0], [-3, 3, -1]] """ if self._nid < 2: - raise TypeError("contraction can be performed only on " + - "components with at least 2 indices") + raise TypeError("contraction can be performed only on " + "components with at least 2 indices") if pos1 < 0 or pos1 > self._nid - 1: raise IndexError("pos1 out of range") if pos2 < 0 or pos2 > self._nid - 1: raise IndexError("pos2 out of range") if pos1 == pos2: - raise IndexError("the two positions must differ for the " + - "contraction to take place") + raise IndexError("the two positions must differ for the " + "contraction to take place") si = self._sindex nsi = si + self._dim if self._nid == 2: @@ -3818,7 +3742,7 @@ def trace(self, pos1, pos2): isym_res.remove(pos1) if pos2 in isym: isym_res.remove(pos2) - if len(isym_res) < 2: # the symmetry is lost + if len(isym_res) < 2: # the symmetry is lost sym_res.remove(isym) else: sym_res[sym_res.index(isym)] = tuple(isym_res) @@ -3829,7 +3753,7 @@ def trace(self, pos1, pos2): isym_res.remove(pos1) if pos2 in isym: isym_res.remove(pos2) - if len(isym_res) < 2: # the symmetry is lost + if len(isym_res) < 2: # the symmetry is lost antisym_res.remove(isym) else: antisym_res[antisym_res.index(isym)] = tuple(isym_res) @@ -3842,9 +3766,9 @@ def trace(self, pos1, pos2): if pos < pos1: isym_res.append(pos) elif pos < pos2: - isym_res.append(pos-1) + isym_res.append(pos - 1) else: - isym_res.append(pos-2) + isym_res.append(pos - 2) max_sym = max(max_sym, len(isym_res)) sym_res[k] = tuple(isym_res) max_antisym = 0 @@ -3854,27 +3778,22 @@ def trace(self, pos1, pos2): if pos < pos1: isym_res.append(pos) elif pos < pos2: - isym_res.append(pos-1) + isym_res.append(pos - 1) else: - isym_res.append(pos-2) + isym_res.append(pos - 2) max_antisym = max(max_antisym, len(isym_res)) antisym_res[k] = tuple(isym_res) # Construction of the appropriate object in view of the # remaining symmetries: nid_res = self._nid - 2 if max_sym == 0 and max_antisym == 0: - result = Components(self._ring, self._frame, nid_res, self._sindex, - self._output_formatter) + result = Components(self._ring, self._frame, nid_res, self._sindex, self._output_formatter) elif max_sym == nid_res: - result = CompFullySym(self._ring, self._frame, nid_res, - self._sindex, self._output_formatter) + result = CompFullySym(self._ring, self._frame, nid_res, self._sindex, self._output_formatter) elif max_antisym == nid_res: - result = CompFullyAntiSym(self._ring, self._frame, nid_res, - self._sindex, self._output_formatter) + result = CompFullyAntiSym(self._ring, self._frame, nid_res, self._sindex, self._output_formatter) else: - result = CompWithSym(self._ring, self._frame, nid_res, - self._sindex, self._output_formatter, - sym=sym_res, antisym=antisym_res) + result = CompWithSym(self._ring, self._frame, nid_res, self._sindex, self._output_formatter, sym=sym_res, antisym=antisym_res) # The contraction itself: for ind_res in result.non_redundant_index_generator(): ind = list(ind_res) @@ -3972,28 +3891,28 @@ def non_redundant_index_generator(self) -> Iterator: for isym in antisym: for k in range(1, len(isym)): if pos == isym[k]: - if ind[isym[k-1]] == imax: + if ind[isym[k - 1]] == imax: return - ind[pos] = ind[isym[k-1]] + 1 + ind[pos] = ind[isym[k - 1]] + 1 if not any(pos in isym for isym in sym) and not any(pos in isym for isym in antisym): sym.append([pos]) # treat non-symmetrized indices as being symmetrized with themselves while True: yield tuple(ind) step_finished = False # each step generates a new index - for i in range(len(sym)-1, -1, -1): + for i in range(len(sym) - 1, -1, -1): # start with symmetrized indices, loop until we find # an index which we can increase without going over # the maximum isym = sym[i] if not step_finished: - for k in range(len(isym)-1, -1, -1): + for k in range(len(isym) - 1, -1, -1): if ind[isym[k]] != imax: # we have found an index which we can # increase; adjust other indices in the # `isym` symmetrization ind[isym[k]] += 1 - for l in range(k+1, len(isym)): - ind[isym[l]] = ind[isym[l-1]] + for l in range(k + 1, len(isym)): + ind[isym[l]] = ind[isym[l - 1]] step_finished = True break else: @@ -4005,17 +3924,17 @@ def non_redundant_index_generator(self) -> Iterator: # which we can increase, thus we have generated # all indices return - for i in range(len(antisym)-1, -1, -1): + for i in range(len(antisym) - 1, -1, -1): # the antisymmetrized indices work similar to the # symmetrized ones isym = antisym[i] if not step_finished: - for k in range(len(isym)-1, -1, -1): - if ind[isym[k]] + len(isym)-1-k != imax: + for k in range(len(isym) - 1, -1, -1): + if ind[isym[k]] + len(isym) - 1 - k != imax: ind[isym[k]] += 1 - for l in range(k+1, len(isym)): + for l in range(k + 1, len(isym)): # adjust antisymmetrized index - ind[isym[l]] = ind[isym[l-1]] + 1 + ind[isym[l]] = ind[isym[l - 1]] + 1 step_finished = True break else: @@ -4233,14 +4152,14 @@ def symmetrize(self, *pos): True """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup + if not pos: pos = tuple(range(self._nid)) else: if len(pos) < 2: raise ValueError("at least two index positions must be given") if len(pos) > self._nid: - raise ValueError("number of index positions larger than the " - "total number of indices") + raise ValueError("number of index positions larger than the " "total number of indices") pos = tuple(pos) pos_set = set(pos) # If the symmetry is already present, there is nothing to do: @@ -4283,7 +4202,7 @@ def symmetrize(self, *pos): elif len(inter) == 1: # some piece of antisymmetry is lost k = inter.pop() # the symmetry index position involved in the - # antisymmetry + # antisymmetry iasym_set = set(iasym) iasym_set.remove(k) if len(iasym_set) > 1: @@ -4302,18 +4221,15 @@ def symmetrize(self, *pos): for isym in sym_res: max_sym = max(max_sym, len(isym)) if max_sym == self._nid: - result = CompFullySym(self._ring, self._frame, self._nid, self._sindex, - self._output_formatter) + result = CompFullySym(self._ring, self._frame, self._nid, self._sindex, self._output_formatter) else: - result = CompWithSym(self._ring, self._frame, self._nid, self._sindex, - self._output_formatter, sym=sym_res, - antisym=antisym_res) + result = CompWithSym(self._ring, self._frame, self._nid, self._sindex, self._output_formatter, sym=sym_res, antisym=antisym_res) if zero_result: - return result # since a just created instance is zero + return result # since a just created instance is zero # # Symmetrization # - n_sym = len(pos) # number of indices involved in the symmetry + n_sym = len(pos) # number of indices involved in the symmetry sym_group = SymmetricGroup(n_sym) for ind in result.non_redundant_index_generator(): sum = 0 @@ -4493,14 +4409,14 @@ def antisymmetrize(self, *pos): -27/2 """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup + if not pos: pos = tuple(range(self._nid)) else: if len(pos) < 2: raise ValueError("at least two index positions must be given") if len(pos) > self._nid: - raise ValueError("number of index positions larger than the " - "total number of indices") + raise ValueError("number of index positions larger than the " "total number of indices") pos = tuple(pos) pos_set = set(pos) # If the antisymmetry is already present, there is nothing to do: @@ -4545,7 +4461,7 @@ def antisymmetrize(self, *pos): elif len(inter) == 1: # some piece of the symmetry is lost k = inter.pop() # the antisymmetry index position involved in - # the symmetry + # the symmetry isym_set = set(isym) isym_set.remove(k) if len(isym_set) > 1: @@ -4564,18 +4480,15 @@ def antisymmetrize(self, *pos): for isym in antisym_res: max_sym = max(max_sym, len(isym)) if max_sym == self._nid: - result = CompFullyAntiSym(self._ring, self._frame, self._nid, - self._sindex, self._output_formatter) + result = CompFullyAntiSym(self._ring, self._frame, self._nid, self._sindex, self._output_formatter) else: - result = CompWithSym(self._ring, self._frame, self._nid, self._sindex, - self._output_formatter, sym=sym_res, - antisym=antisym_res) + result = CompWithSym(self._ring, self._frame, self._nid, self._sindex, self._output_formatter, sym=sym_res, antisym=antisym_res) if zero_result: - return result # since a just created instance is zero + return result # since a just created instance is zero # # Antisymmetrization # - n_sym = len(pos) # number of indices involved in the antisymmetry + n_sym = len(pos) # number of indices involved in the antisymmetry sym_group = SymmetricGroup(n_sym) for ind in result.non_redundant_index_generator(): sum = 0 @@ -4595,6 +4508,7 @@ def antisymmetrize(self, *pos): # **************************************************************************** + class CompFullySym(CompWithSym): r""" Indexed set of ring elements forming some components with respect to a @@ -4723,8 +4637,8 @@ class CompFullySym(CompWithSym): sage: 2*b1 + a == a + 2*b1 True """ - def __init__(self, ring, frame, nb_indices, start_index=0, - output_formatter=None) -> None: + + def __init__(self, ring, frame, nb_indices, start_index=0, output_formatter=None) -> None: r""" TESTS:: @@ -4732,8 +4646,7 @@ def __init__(self, ring, frame, nb_indices, start_index=0, sage: C = CompFullySym(ZZ, (1,2,3), 2) sage: TestSuite(C).run() """ - CompWithSym.__init__(self, ring, frame, nb_indices, start_index, - output_formatter, sym=range(nb_indices)) + CompWithSym.__init__(self, ring, frame, nb_indices, start_index, output_formatter, sym=range(nb_indices)) def _repr_symmetry(self) -> tuple[str, str]: r""" @@ -4760,8 +4673,7 @@ def _new_instance(self): sage: c._new_instance() Fully symmetric 4-indices components w.r.t. (1, 2, 3) """ - return CompFullySym(self._ring, self._frame, self._nid, self._sindex, - self._output_formatter) + return CompFullySym(self._ring, self._frame, self._nid, self._sindex, self._output_formatter) def __getitem__(self, args): r""" @@ -4794,13 +4706,13 @@ def __getitem__(self, args): [0 0 0] """ no_format = self._output_formatter is None - format_type = None # default value, possibly redefined below + format_type = None # default value, possibly redefined below if isinstance(args, list): # case of [[...]] syntax no_format = True if isinstance(args[0], slice): indices = args[0] - elif isinstance(args[0], (tuple, list)): # to ensure equivalence between - indices = args[0] # [[(i,j,...)]] or [[[i,j,...]]] and [[i,j,...]] + elif isinstance(args[0], (tuple, list)): # to ensure equivalence between + indices = args[0] # [[(i,j,...)]] or [[[i,j,...]]] and [[i,j,...]] else: indices = tuple(args) else: @@ -4821,7 +4733,7 @@ def __getitem__(self, args): return self._get_list(indices, no_format, format_type) ind = self._ordered_indices(indices)[1] # [0]=sign is not used - if ind in self._comp: # nonzero value + if ind in self._comp: # nonzero value if no_format: return self._comp[ind] if format_type is None: @@ -4833,8 +4745,7 @@ def __getitem__(self, args): return self._ring.zero() if format_type is None: return self._output_formatter(self._ring.zero()) - return self._output_formatter(self._ring.zero(), - format_type) + return self._output_formatter(self._ring.zero(), format_type) def __setitem__(self, args, value) -> None: r""" @@ -4868,12 +4779,12 @@ def __setitem__(self, args, value) -> None: [2 4 5] [3 5 6] """ - format_type = None # default value, possibly redefined below + format_type = None # default value, possibly redefined below if isinstance(args, list): # case of [[...]] syntax if isinstance(args[0], slice): indices = args[0] - elif isinstance(args[0], (tuple, list)): # to ensure equivalence between - indices = args[0] # [[(i,j,...)]] or [[[i,j,...]]] and [[i,j,...]] + elif isinstance(args[0], (tuple, list)): # to ensure equivalence between + indices = args[0] # [[(i,j,...)]] or [[[i,j,...]]] and [[i,j,...]] else: indices = tuple(args) else: @@ -4989,38 +4900,32 @@ def __add__(self, other): if isinstance(other, (int, Integer)) and other == 0: return +self if not isinstance(other, Components): - raise TypeError("the second argument for the addition must be a " + - "an instance of Components") + raise TypeError("the second argument for the addition must be a " + "an instance of Components") if isinstance(other, CompFullySym): if other._frame != self._frame: - raise ValueError("the two sets of components are not defined " + - "on the same frame") + raise ValueError("the two sets of components are not defined " + "on the same frame") if other._nid != self._nid: - raise ValueError("the two sets of components do not have the " + - "same number of indices") + raise ValueError("the two sets of components do not have the " + "same number of indices") if other._sindex != self._sindex: - raise ValueError("the two sets of components do not have the " + - "same starting index") + raise ValueError("the two sets of components do not have the " + "same starting index") # Initialization of the result to self.copy(), so that there # remains only to add other: result = self.copy() nproc = Parallelism().get('tensor') if nproc != 1: # parallel sum - lol = lambda lst, sz: [lst[i:i+sz] for i - in range(0, len(lst), sz)] + lol = lambda lst, sz: [lst[i : i + sz] for i in range(0, len(lst), sz)] ind_list = list(other._comp) - ind_step = max(1, int(len(ind_list)/nproc/2)) + ind_step = max(1, int(len(ind_list) / nproc / 2)) local_list = lol(ind_list, ind_step) # definition of the list of input parameters - listParalInput = [(self, other, ind_part) for ind_part - in local_list] + listParalInput = [(self, other, ind_part) for ind_part in local_list] @parallel(p_iter='multiprocessing', ncpus=nproc) def paral_sum(a, b, local_list_ind): partial = [] for ind in local_list_ind: - partial.append([ind, a[[ind]]+b[[ind]]]) + partial.append([ind, a[[ind]] + b[[ind]]]) return partial for ii, val in paral_sum(listParalInput): @@ -5037,6 +4942,7 @@ def paral_sum(a, b, local_list_ind): # **************************************************************************** + class CompFullyAntiSym(CompWithSym): r""" Indexed set of ring elements forming some components with respect to a @@ -5170,8 +5076,8 @@ class CompFullyAntiSym(CompWithSym): sage: 2*b1 + a == a + 2*b1 True """ - def __init__(self, ring, frame, nb_indices, start_index=0, - output_formatter=None) -> None: + + def __init__(self, ring, frame, nb_indices, start_index=0, output_formatter=None) -> None: r""" TESTS:: @@ -5179,8 +5085,7 @@ def __init__(self, ring, frame, nb_indices, start_index=0, sage: C = CompFullyAntiSym(ZZ, (1,2,3), 2) sage: TestSuite(C).run() """ - CompWithSym.__init__(self, ring, frame, nb_indices, start_index, - output_formatter, antisym=range(nb_indices)) + CompWithSym.__init__(self, ring, frame, nb_indices, start_index, output_formatter, antisym=range(nb_indices)) def _repr_symmetry(self) -> tuple[str, str]: r""" @@ -5207,8 +5112,7 @@ def _new_instance(self): sage: c._new_instance() Fully antisymmetric 4-indices components w.r.t. (1, 2, 3) """ - return CompFullyAntiSym(self._ring, self._frame, self._nid, - self._sindex, self._output_formatter) + return CompFullyAntiSym(self._ring, self._frame, self._nid, self._sindex, self._output_formatter) def __add__(self, other): r""" @@ -5282,27 +5186,23 @@ def __add__(self, other): if isinstance(other, (int, Integer)) and other == 0: return +self if not isinstance(other, Components): - raise TypeError("the second argument for the addition must be a " + - "an instance of Components") + raise TypeError("the second argument for the addition must be a " + "an instance of Components") if isinstance(other, CompFullyAntiSym): if other._frame != self._frame: - raise ValueError("the two sets of components are not defined " + - "on the same frame") + raise ValueError("the two sets of components are not defined " + "on the same frame") if other._nid != self._nid: - raise ValueError("the two sets of components do not have the " + - "same number of indices") + raise ValueError("the two sets of components do not have the " + "same number of indices") if other._sindex != self._sindex: - raise ValueError("the two sets of components do not have the " + - "same starting index") + raise ValueError("the two sets of components do not have the " + "same starting index") # Initialization of the result to self.copy(), so that there remains # only to add other: result = self.copy() nproc = Parallelism().get('tensor') if nproc != 1: # Parallel computation - lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] + lol = lambda lst, sz: [lst[i : i + sz] for i in range(0, len(lst), sz)] ind_list = list(other._comp) - ind_step = max(1, int(len(ind_list)/nproc/2)) + ind_step = max(1, int(len(ind_list) / nproc / 2)) local_list = lol(ind_list, ind_step) # list of input parameters listParalInput = [(self, other, ind_part) for ind_part in local_list] @@ -5311,7 +5211,7 @@ def __add__(self, other): def paral_sum(a, b, local_list_ind): partial = [] for ind in local_list_ind: - partial.append([ind, a[[ind]]+b[[ind]]]) + partial.append([ind, a[[ind]] + b[[ind]]]) return partial for ii, val in paral_sum(listParalInput): @@ -5433,16 +5333,14 @@ def interior_product(self, other): True """ from sage.arith.misc import factorial + # Sanity checks: if not isinstance(other, CompFullyAntiSym): - raise TypeError("{} is not a fully antisymmetric ".format(other) + - "set of components") + raise TypeError("{} is not a fully antisymmetric ".format(other) + "set of components") if other._frame != self._frame: - raise ValueError("the {} are not defined on the ".format(other) + - "same frame as the {}".format(self)) + raise ValueError("the {} are not defined on the ".format(other) + "same frame as the {}".format(self)) if other._nid < self._nid: - raise ValueError("the {} have less indices than ".format(other) + - "the {}".format(self)) + raise ValueError("the {} have less indices than ".format(other) + "the {}".format(self)) # Number of indices of the result: res_nid = other._nid - self._nid # @@ -5452,27 +5350,24 @@ def interior_product(self, other): res = 0 for ind in self.non_redundant_index_generator(): res += self[[ind]] * other[[ind]] - return factorial(self._nid)*res + return factorial(self._nid) * res # # Case of component result # if res_nid == 1: - res = Components(self._ring, self._frame, res_nid, - start_index=self._sindex, - output_formatter=self._output_formatter) + res = Components(self._ring, self._frame, res_nid, start_index=self._sindex, output_formatter=self._output_formatter) else: - res = CompFullyAntiSym(self._ring, self._frame, res_nid, - start_index=self._sindex, - output_formatter=self._output_formatter) + res = CompFullyAntiSym(self._ring, self._frame, res_nid, start_index=self._sindex, output_formatter=self._output_formatter) factorial_s = factorial(self._nid) for ind in res.non_redundant_index_generator(): sm = 0 for ind_s, cmp_s in self._comp.items(): ind_o = ind_s + ind sm += cmp_s * other[[ind_o]] - res[[ind]] = factorial_s*sm + res[[ind]] = factorial_s * sm return res + # **************************************************************************** @@ -5533,8 +5428,8 @@ class KroneckerDelta(CompFullySym): sage: d[:] [['1', '0', '0'], ['0', '1', '0'], ['0', '0', '1']] """ - def __init__(self, ring, frame, start_index=0, - output_formatter=None) -> None: + + def __init__(self, ring, frame, start_index=0, output_formatter=None) -> None: r""" TESTS:: @@ -5542,8 +5437,7 @@ def __init__(self, ring, frame, start_index=0, sage: d = KroneckerDelta(ZZ, (1,2,3)) sage: TestSuite(d).run() """ - CompFullySym.__init__(self, ring, frame, 2, start_index, - output_formatter) + CompFullySym.__init__(self, ring, frame, 2, start_index, output_formatter) for i in range(self._sindex, self._dim + self._sindex): self._comp[(i, i)] = self._ring(1) diff --git a/src/sage/tensor/modules/ext_pow_free_module.py b/src/sage/tensor/modules/ext_pow_free_module.py index bee10a40322..b1cdec0907a 100644 --- a/src/sage/tensor/modules/ext_pow_free_module.py +++ b/src/sage/tensor/modules/ext_pow_free_module.py @@ -45,6 +45,7 @@ - \K. Conrad: *Exterior powers* [Con2013]_ - Chap. 19 of S. Lang: *Algebra* [Lan2002]_ """ + # **************************************************************************** # Copyright (C) 2017 Eric Gourgoulhon # @@ -236,17 +237,15 @@ def __init__(self, fmodule, degree, name=None, latex_name=None): """ from sage.arith.misc import binomial from sage.typeset.unicode_characters import unicode_bigwedge + self._fmodule = fmodule self._degree = ZZ(degree) rank = binomial(fmodule._rank, degree) if name is None and fmodule._name is not None: - name = unicode_bigwedge + r'^{}('.format(degree) \ - + fmodule._name + ')' + name = unicode_bigwedge + r'^{}('.format(degree) + fmodule._name + ')' if latex_name is None and fmodule._latex_name is not None: - latex_name = r'\Lambda^{' + str(degree) + r'}\left(' \ - + fmodule._latex_name + r'\right)' - super().__init__(fmodule._ring, rank, - name=name, latex_name=latex_name) + latex_name = r'\Lambda^{' + str(degree) + r'}\left(' + fmodule._latex_name + r'\right)' + super().__init__(fmodule._ring, rank, name=name, latex_name=latex_name) fmodule._all_modules.add(self) def construction(self): @@ -270,8 +269,7 @@ def construction(self): #### Parent methods - def _element_constructor_(self, comp=[], basis=None, name=None, - latex_name=None): + def _element_constructor_(self, comp=[], basis=None, name=None, latex_name=None): r""" Construct an alternating contravariant tensor. @@ -292,8 +290,7 @@ def _element_constructor_(self, comp=[], basis=None, name=None, """ if isinstance(comp, (int, Integer)) and comp == 0: return self.zero() - resu = self.element_class(self._fmodule, self._degree, name=name, - latex_name=latex_name) + resu = self.element_class(self._fmodule, self._degree, name=name, latex_name=latex_name) if comp: resu.set_comp(basis)[:] = comp return resu @@ -367,7 +364,7 @@ def zero(self): for basis in self._fmodule._known_bases: resu._add_comp_unsafe(basis) # (since new components are initialized to zero) - resu._is_zero = True # This element is certainly zero + resu._is_zero = True # This element is certainly zero resu.set_immutable() return resu @@ -433,7 +430,8 @@ def degree(self): """ return self._degree -#*********************************************************************** + +# *********************************************************************** class ExtPowerDualFreeModule(FiniteRankFreeModule_abstract): @@ -613,17 +611,15 @@ def __init__(self, fmodule, degree, name=None, latex_name=None): """ from sage.arith.misc import binomial from sage.typeset.unicode_characters import unicode_bigwedge + self._fmodule = fmodule self._degree = ZZ(degree) rank = binomial(fmodule._rank, degree) if name is None and fmodule._name is not None: - name = unicode_bigwedge + r'^{}('.format(degree) \ - + fmodule._name + '*)' + name = unicode_bigwedge + r'^{}('.format(degree) + fmodule._name + '*)' if latex_name is None and fmodule._latex_name is not None: - latex_name = r'\Lambda^{' + str(degree) + r'}\left(' \ - + fmodule._latex_name + r'^*\right)' - super().__init__(fmodule._ring, rank, name=name, - latex_name=latex_name) + latex_name = r'\Lambda^{' + str(degree) + r'}\left(' + fmodule._latex_name + r'^*\right)' + super().__init__(fmodule._ring, rank, name=name, latex_name=latex_name) fmodule._all_modules.add(self) def construction(self): @@ -647,8 +643,7 @@ def construction(self): #### Parent methods - def _element_constructor_(self, comp=[], basis=None, name=None, - latex_name=None): + def _element_constructor_(self, comp=[], basis=None, name=None, latex_name=None): r""" Construct an alternating form. @@ -671,19 +666,15 @@ def _element_constructor_(self, comp=[], basis=None, name=None, return self.zero() if isinstance(comp, FreeModuleTensor): # coercion of a tensor of type (0,1) to a linear form - tensor = comp # for readability - if tensor.tensor_type() == (0,1) and self._degree == 1 and \ - tensor.base_module() is self._fmodule: - resu = self.element_class(self._fmodule, 1, name=tensor._name, - latex_name=tensor._latex_name) + tensor = comp # for readability + if tensor.tensor_type() == (0, 1) and self._degree == 1 and tensor.base_module() is self._fmodule: + resu = self.element_class(self._fmodule, 1, name=tensor._name, latex_name=tensor._latex_name) for basis, comp in tensor._components.items(): resu._components[basis] = comp.copy() return resu - raise TypeError("cannot coerce the {} ".format(tensor) + - "to an element of {}".format(self)) + raise TypeError("cannot coerce the {} ".format(tensor) + "to an element of {}".format(self)) # standard construction - resu = self.element_class(self._fmodule, self._degree, name=name, - latex_name=latex_name) + resu = self.element_class(self._fmodule, self._degree, name=name, latex_name=latex_name) if comp: resu.set_comp(basis)[:] = comp return resu @@ -755,7 +746,7 @@ def zero(self): for basis in self._fmodule._known_bases: resu._components[basis] = resu._new_comp(basis) # (since new components are initialized to zero) - resu._is_zero = True # This element is certainly zero + resu._is_zero = True # This element is certainly zero resu.set_immutable() return resu @@ -778,8 +769,7 @@ def _repr_(self): '21st exterior power of the dual of the Rank-5 free module M over the Integer Ring' """ description = "{}".format(self._degree.ordinal_str()) - description += " exterior power of the dual of the {}".format( - self._fmodule) + description += " exterior power of the dual of the {}".format(self._fmodule) return description def base_module(self): diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 16d01a418ca..2a1dd2ecc49 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -512,6 +512,7 @@ class :class:`~sage.modules.free_module.FreeModule_generic` sage: [v.coefficient(i) for i in {1,2,3}] [2, 0, -5] """ + # ****************************************************************************** # Copyright (C) 2014-2021 Eric Gourgoulhon # 2014-2016 Travis Scrimshaw @@ -584,7 +585,7 @@ def __init__( raise TypeError("the module base ring must be commutative") category = Modules(ring).FiniteDimensional().or_subcategory(category) Parent.__init__(self, base=ring, category=category) - self._ring = ring # same as self._base + self._ring = ring # same as self._base if ambient is None: self._ambient_module = self else: @@ -693,11 +694,11 @@ def zero(self): for basis in self._known_bases: resu._add_comp_unsafe(basis) # (since new components are initialized to zero) - resu._is_zero = True # This element is certainly zero + resu._is_zero = True # This element is certainly zero resu.set_immutable() return resu - def ambient_module(self): # compatible with sage.modules.free_module.FreeModule_generic + def ambient_module(self): # compatible with sage.modules.free_module.FreeModule_generic """ Return the ambient module associated to this module. @@ -715,7 +716,7 @@ def ambient_module(self): # compatible with sage.modules.free_module.FreeModule_ """ return self._ambient_module - ambient = ambient_module # compatible with sage.modules.with_basis.subquotient.SubmoduleWithBasis + ambient = ambient_module # compatible with sage.modules.with_basis.subquotient.SubmoduleWithBasis def is_submodule(self, other): """ @@ -945,12 +946,12 @@ def isomorphism_with_fixed_basis(self, basis=None, codomain=None): basis = self.default_basis() if codomain is None: from sage.combinat.free_module import CombinatorialFreeModule + if isinstance(basis._symbol, str): prefix = basis._symbol else: prefix = None - codomain = CombinatorialFreeModule(base_ring, basis.keys(), - prefix=prefix) + codomain = CombinatorialFreeModule(base_ring, basis.keys(), prefix=prefix) else: try: codomain_rank = codomain.rank() @@ -960,8 +961,7 @@ def isomorphism_with_fixed_basis(self, basis=None, codomain=None): if codomain_rank != self.rank(): raise ValueError("domain and codomain must have the same rank") if codomain.base_ring() != base_ring: - raise ValueError("domain and codomain must have the same " - "base ring") + raise ValueError("domain and codomain must have the same " "base ring") codomain_basis = Family(codomain.basis()) if isinstance(codomain_basis, TrivialFamily): @@ -981,16 +981,13 @@ def _isomorphism(x): r""" Concrete isomorphism from ``self`` to ``codomain``. """ - return codomain.sum(x[basis, domain_key] * codomain_basis[codomain_key] - for codomain_key, domain_key in key_pairs) + return codomain.sum(x[basis, domain_key] * codomain_basis[codomain_key] for codomain_key, domain_key in key_pairs) def _inverse(y): r""" Concrete isomorphism from ``codomain`` to ``self``. """ - return self.linear_combination( - (basis_by_codomain_key[codomain_key], coefficient) - for codomain_key, coefficient in y.monomial_coefficients().items()) + return self.linear_combination((basis_by_codomain_key[codomain_key], coefficient) for codomain_key, coefficient in y.monomial_coefficients().items()) category = Modules(self.base_ring()) homset = Hom(self, codomain, category) @@ -1230,8 +1227,7 @@ class :class:`~sage.modules.module.Module`. _sindex: int @staticmethod - def __classcall_private__(cls, ring, rank, name=None, latex_name=None, start_index=0, - output_formatter=None, category=None, ambient=None): + def __classcall_private__(cls, ring, rank, name=None, latex_name=None, start_index=0, output_formatter=None, category=None, ambient=None): r""" Normalize init arguments for ``UniqueRepresentation``. @@ -1253,8 +1249,7 @@ def __classcall_private__(cls, ring, rank, name=None, latex_name=None, start_ind category = Modules(ring).FiniteDimensional().or_subcategory(category) if latex_name is None: latex_name = name - return super().__classcall__( - cls, ring, rank, name, latex_name, start_index, output_formatter, category, ambient) + return super().__classcall__(cls, ring, rank, name, latex_name, start_index, output_formatter, category, ambient) def __init__( self, @@ -1279,8 +1274,7 @@ def __init__( sage: f = M.basis('f') sage: TestSuite(M).run() """ - super().__init__(ring, rank, name=name, latex_name=latex_name, - category=category, ambient=ambient) + super().__init__(ring, rank, name=name, latex_name=latex_name, category=category, ambient=ambient) self._sindex = start_index self._output_formatter = output_formatter # Dictionary of the tensor modules built on self @@ -1298,13 +1292,13 @@ def __init__( self._all_modules = {self} # List of known bases on the free module: self._known_bases = [] - self._def_basis = None # default basis - self._basis_changes = {} # Dictionary of the changes of bases + self._def_basis = None # default basis + self._basis_changes = {} # Dictionary of the changes of bases # Identity automorphism: - self._identity_map = None # to be set by self.identity_map() + self._identity_map = None # to be set by self.identity_map() # General linear group: - self._general_linear_group = None # to be set by - # self.general_linear_group() + self._general_linear_group = None # to be set by + # self.general_linear_group() def construction(self): """ @@ -1328,21 +1322,15 @@ def construction(self): if self._output_formatter: return None from sage.categories.pushout import VectorFunctor - kwds = dict(is_sparse=False, - inner_product_matrix=None, - with_basis=None, - name_mapping={self.base_ring(): self._name} if self._name else None, - latex_name_mapping={self.base_ring(): self._latex_name} if self._latex_name else None) + + kwds = dict(is_sparse=False, inner_product_matrix=None, with_basis=None, name_mapping={self.base_ring(): self._name} if self._name else None, latex_name_mapping={self.base_ring(): self._latex_name} if self._latex_name else None) if self._sindex: - return (VectorFunctor(basis_keys=list(self.irange()), **kwds), - self.base_ring()) - return (VectorFunctor(n=self.rank(), **kwds), - self.base_ring()) + return (VectorFunctor(basis_keys=list(self.irange()), **kwds), self.base_ring()) + return (VectorFunctor(n=self.rank(), **kwds), self.base_ring()) #### Parent methods - def _element_constructor_(self, comp=[], basis=None, name=None, - latex_name=None): + def _element_constructor_(self, comp=[], basis=None, name=None, latex_name=None): r""" Construct an element of ``self``. @@ -1443,6 +1431,7 @@ def _Hom_(self, other, category=None): in Category of finite dimensional modules over Integer Ring """ from .free_module_homset import FreeModuleHomset + return FreeModuleHomset(self, other) def tensor_module(self, k, l, *, sym=None, antisym=None): @@ -1540,9 +1529,11 @@ def tensor_module(self, k, l, *, sym=None, antisym=None): T = self.dual() elif sym or antisym: from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym + T = TensorFreeSubmodule_sym(self, (k, l), sym=sym, antisym=antisym) else: from sage.tensor.modules.tensor_free_module import TensorFreeModule + T = TensorFreeModule(self, (k, l)) self._tensor_modules[key] = T return T @@ -1684,6 +1675,7 @@ def exterior_power(self, p): L = self else: from sage.tensor.modules.ext_pow_free_module import ExtPowerFreeModule + L = ExtPowerFreeModule(self, p) self._exterior_powers[p] = L return L @@ -1758,6 +1750,7 @@ def dual_exterior_power(self, p): L = FiniteRankDualFreeModule(self) else: from sage.tensor.modules.ext_pow_free_module import ExtPowerDualFreeModule + L = ExtPowerDualFreeModule(self, p) self._dual_exterior_powers[p] = L return L @@ -1815,15 +1808,13 @@ def general_linear_group(self): :class:`~sage.tensor.modules.free_module_linear_group.FreeModuleLinearGroup` for more documentation. """ - from sage.tensor.modules.free_module_linear_group import \ - FreeModuleLinearGroup + from sage.tensor.modules.free_module_linear_group import FreeModuleLinearGroup + if self._general_linear_group is None: self._general_linear_group = FreeModuleLinearGroup(self) return self._general_linear_group - def basis(self, symbol, latex_symbol=None, from_family=None, - indices=None, latex_indices=None, symbol_dual=None, - latex_symbol_dual=None): + def basis(self, symbol, latex_symbol=None, from_family=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): r""" Define or return a basis of the free module ``self``. @@ -1983,19 +1974,16 @@ def basis(self, symbol, latex_symbol=None, from_family=None, :class:`~sage.tensor.modules.free_module_basis.FreeModuleBasis`. """ from .free_module_basis import FreeModuleBasis + for other in self._known_bases: if symbol == other._symbol and indices == other._indices: return other - resu = FreeModuleBasis(self, symbol, latex_symbol=latex_symbol, - indices=indices, latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) + resu = FreeModuleBasis(self, symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) if from_family: try: resu._init_from_family(from_family) except ZeroDivisionError: - raise ValueError("the provided module elements are not " - "linearly independent") + raise ValueError("the provided module elements are not " "linearly independent") return resu def _test_basis(self, tester=None, **options): @@ -2038,10 +2026,11 @@ def _test_basis(self, tester=None, **options): running ._test_some_elements() . . . pass """ from sage.misc.sage_unittest import TestSuite + # The intention is to raise an exception only if this is # run as a sub-testsuite of a larger testsuite. # (from _test_elements) - is_sub_testsuite = (tester is not None) + is_sub_testsuite = tester is not None tester = self._tester(tester=tester, **options) try: b = self.basis('test') @@ -2059,11 +2048,9 @@ def _test_basis(self, tester=None, **options): tester.assertTrue(element is b[index]) # Run test suite of the basis object (similar to _test_elements) tester.info("\n Running the test suite of self.basis('test')") - TestSuite(b).run(verbose=tester._verbose, prefix=tester._prefix + " ", - raise_on_failure=is_sub_testsuite) + TestSuite(b).run(verbose=tester._verbose, prefix=tester._prefix + " ", raise_on_failure=is_sub_testsuite) - def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, - antisym=None): + def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, antisym=None): r""" Construct a tensor on the free module ``self``. @@ -2107,25 +2094,21 @@ def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, Element t of the Rank-3 free module M over the Integer Ring """ from .comp import CompWithSym - sym, antisym = CompWithSym._canonicalize_sym_antisym( - tensor_type[0] + tensor_type[1], sym, antisym) + + sym, antisym = CompWithSym._canonicalize_sym_antisym(tensor_type[0] + tensor_type[1], sym, antisym) # Special cases: - if tensor_type == (1,0): + if tensor_type == (1, 0): return self.element_class(self, name=name, latex_name=latex_name) - if tensor_type == (0,1): + if tensor_type == (0, 1): return self.linear_form(name=name, latex_name=latex_name) if tensor_type[0] == 0 and tensor_type[1] > 1 and antisym: if len(antisym[0]) == tensor_type[1]: - return self.alternating_form(tensor_type[1], name=name, - latex_name=latex_name) + return self.alternating_form(tensor_type[1], name=name, latex_name=latex_name) elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym: if len(antisym[0]) == tensor_type[0]: - return self.alternating_contravariant_tensor(tensor_type[0], - name=name, latex_name=latex_name) + return self.alternating_contravariant_tensor(tensor_type[0], name=name, latex_name=latex_name) # Generic case: - return self.tensor_module(*tensor_type).element_class(self, - tensor_type, name=name, latex_name=latex_name, - sym=sym, antisym=antisym) + return self.tensor_module(*tensor_type).element_class(self, tensor_type, name=name, latex_name=latex_name, sym=sym, antisym=antisym) def tensor(self, *args, **kwds): r""" @@ -2275,32 +2258,23 @@ def tensor_from_comp(self, tensor_type, comp, name=None, latex_name=None): # 0/ Compatibility checks: if comp._ring is not self._ring: - raise TypeError("the components are not defined on the same" - " ring as the module") + raise TypeError("the components are not defined on the same" " ring as the module") if comp._frame not in self._known_bases: - raise TypeError("the components are not defined on a basis of" - " the module") + raise TypeError("the components are not defined on a basis of" " the module") if comp._nid != tensor_type[0] + tensor_type[1]: - raise TypeError("number of component indices not compatible with " - " the tensor type") + raise TypeError("number of component indices not compatible with " " the tensor type") # 1/ Construction of the tensor: if tensor_type == (1, 0): resu = self.element_class(self, name=name, latex_name=latex_name) elif tensor_type == (0, 1): resu = self.linear_form(name=name, latex_name=latex_name) - elif tensor_type[0] == 0 and tensor_type[1] > 1 and \ - isinstance(comp, CompFullyAntiSym): - resu = self.alternating_form(tensor_type[1], name=name, - latex_name=latex_name) - elif tensor_type[0] > 1 and tensor_type[1] == 0 and \ - isinstance(comp, CompFullyAntiSym): - resu = self.alternating_contravariant_tensor(tensor_type[0], - name=name, - latex_name=latex_name) + elif tensor_type[0] == 0 and tensor_type[1] > 1 and isinstance(comp, CompFullyAntiSym): + resu = self.alternating_form(tensor_type[1], name=name, latex_name=latex_name) + elif tensor_type[0] > 1 and tensor_type[1] == 0 and isinstance(comp, CompFullyAntiSym): + resu = self.alternating_contravariant_tensor(tensor_type[0], name=name, latex_name=latex_name) else: - resu = self.tensor_module(*tensor_type).element_class(self, - tensor_type, name=name, latex_name=latex_name) + resu = self.tensor_module(*tensor_type).element_class(self, tensor_type, name=name, latex_name=latex_name) # Tensor symmetries deduced from those of comp: if isinstance(comp, CompWithSym): resu._sym = comp._sym @@ -2311,8 +2285,7 @@ def tensor_from_comp(self, tensor_type, comp, name=None, latex_name=None): return resu - def alternating_contravariant_tensor(self, degree, name=None, - latex_name=None): + def alternating_contravariant_tensor(self, degree, name=None, latex_name=None): r""" Construct an alternating contravariant tensor on the free module. @@ -2361,10 +2334,8 @@ def alternating_contravariant_tensor(self, degree, name=None, for more documentation. """ if degree == 1: - return self.element_class(self, name=name, - latex_name=latex_name) - return self.exterior_power(degree).element_class(self, degree, - name=name, latex_name=latex_name) + return self.element_class(self, name=name, latex_name=latex_name) + return self.exterior_power(degree).element_class(self, degree, name=name, latex_name=latex_name) def alternating_form(self, degree, name=None, latex_name=None): r""" @@ -2421,13 +2392,10 @@ def alternating_form(self, degree, name=None, latex_name=None): """ if degree == 0: try: - return self._ring.element_class(self._ring, name=name, - latex_name=latex_name) + return self._ring.element_class(self._ring, name=name, latex_name=latex_name) except (KeyError, AttributeError): - raise NotImplementedError('{} apparently '.format(self._ring) + - 'does not provide generic elements') - return self.dual_exterior_power(degree).element_class(self, degree, - name=name, latex_name=latex_name) + raise NotImplementedError('{} apparently '.format(self._ring) + 'does not provide generic elements') + return self.dual_exterior_power(degree).element_class(self, degree, name=name, latex_name=latex_name) def linear_form(self, name=None, latex_name=None): r""" @@ -2478,11 +2446,9 @@ def linear_form(self, name=None, latex_name=None): :class:`~sage.tensor.modules.free_module_alt_form.FreeModuleAltForm` for more documentation. """ - return self.dual_exterior_power(1).element_class(self, 1, name=name, - latex_name=latex_name) + return self.dual_exterior_power(1).element_class(self, 1, name=name, latex_name=latex_name) - def automorphism(self, matrix=None, basis=None, name=None, - latex_name=None): + def automorphism(self, matrix=None, basis=None, name=None, latex_name=None): r""" Construct a module automorphism of ``self``. @@ -2563,8 +2529,7 @@ def automorphism(self, matrix=None, basis=None, name=None, :class:`~sage.tensor.modules.free_module_automorphism.FreeModuleAutomorphism` for more documentation. """ - resu = self.general_linear_group().element_class(self, name=name, - latex_name=latex_name) + resu = self.general_linear_group().element_class(self, name=name, latex_name=latex_name) if matrix: if basis is None: basis = self.default_basis() @@ -2667,8 +2632,7 @@ def sym_bilinear_form(self, name=None, latex_name=None): See :class:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor` for more documentation. """ - return self.tensor_module(0,2).element_class(self, (0,2), name=name, - latex_name=latex_name, sym=(0,1)) + return self.tensor_module(0, 2).element_class(self, (0, 2), name=name, latex_name=latex_name, sym=(0, 1)) #### End of methods to be redefined by derived classes #### @@ -2824,6 +2788,7 @@ def set_default_basis(self, basis): Basis (f_1,f_2,f_3) on the Rank-3 free module M over the Integer Ring """ from .free_module_basis import FreeModuleBasis + if not isinstance(basis, FreeModuleBasis): raise TypeError("the argument is not a free module basis") if basis._fmodule is not self: @@ -3007,11 +2972,9 @@ def change_of_basis(self, basis1, basis2): bc = self._basis_changes if (basis1, basis2) not in bc: if basis1 not in self._known_bases: - raise TypeError("{} is not a basis of the {}".format(basis1, - self)) + raise TypeError("{} is not a basis of the {}".format(basis1, self)) if basis2 not in self._known_bases: - raise TypeError("{} is not a basis of the {}".format(basis2, - self)) + raise TypeError("{} is not a basis of the {}".format(basis2, self)) # Is the inverse already registered ? if (basis2, basis1) in bc: inv = bc[(basis2, basis1)].inverse() @@ -3034,13 +2997,10 @@ def change_of_basis(self, basis1, basis2): bc[(basis1, basis2)] = inv.inverse() break else: - raise ValueError(("the change of basis from '{!r}' to '{!r}'" - + " cannot be computed" - ).format(basis1, basis2)) + raise ValueError(("the change of basis from '{!r}' to '{!r}'" + " cannot be computed").format(basis1, basis2)) return bc[(basis1, basis2)] - def set_change_of_basis(self, basis1, basis2, change_of_basis, - compute_inverse=True): + def set_change_of_basis(self, basis1, basis2, change_of_basis, compute_inverse=True): r""" Relates two bases by an automorphism of ``self``. @@ -3087,20 +3047,16 @@ def set_change_of_basis(self, basis1, basis2, change_of_basis, e_0 = 3/5 f_0 + 1/5 f_1 """ if basis1 not in self._known_bases: - raise TypeError("{} is not a basis of the {}".format(basis1, - self)) + raise TypeError("{} is not a basis of the {}".format(basis1, self)) if basis2 not in self._known_bases: - raise TypeError("{} is not a basis of the {}".format(basis2, - self)) + raise TypeError("{} is not a basis of the {}".format(basis2, self)) if change_of_basis not in self.general_linear_group(): - raise TypeError("{} is not an automorphism of the {}".format( - change_of_basis, self)) + raise TypeError("{} is not an automorphism of the {}".format(change_of_basis, self)) self._basis_changes[(basis1, basis2)] = change_of_basis if compute_inverse: self._basis_changes[(basis2, basis1)] = change_of_basis.inverse() - def hom(self, codomain, matrix_rep, bases=None, name=None, - latex_name=None): + def hom(self, codomain, matrix_rep, bases=None, name=None, latex_name=None): r""" Homomorphism from ``self`` to a free module. @@ -3182,8 +3138,7 @@ def hom(self, codomain, matrix_rep, bases=None, name=None, for more documentation. """ homset = Hom(self, codomain) - return homset(matrix_rep, bases=bases, name=name, - latex_name=latex_name) + return homset(matrix_rep, bases=bases, name=name, latex_name=latex_name) def endomorphism(self, matrix_rep, basis=None, name=None, latex_name=None): r""" @@ -3247,10 +3202,10 @@ def endomorphism(self, matrix_rep, basis=None, name=None, latex_name=None): for more documentation. """ from sage.categories.homset import End + if basis is None: basis = self.default_basis() - return End(self)(matrix_rep, bases=(basis,basis), name=name, - latex_name=latex_name) + return End(self)(matrix_rep, bases=(basis, basis), name=name, latex_name=latex_name) def identity_map(self, name='Id', latex_name=None): r""" @@ -3454,14 +3409,12 @@ def __init__(self, fmodule, name=None, latex_name=None): name = fmodule._name + '*' if latex_name is None and fmodule._latex_name is not None: latex_name = fmodule._latex_name + r'^*' - super().__init__(fmodule._ring, rank, name=name, - latex_name=latex_name) + super().__init__(fmodule._ring, rank, name=name, latex_name=latex_name) fmodule._all_modules.add(self) #### Parent methods - def _element_constructor_(self, comp=[], basis=None, name=None, - latex_name=None): + def _element_constructor_(self, comp=[], basis=None, name=None, latex_name=None): r""" Construct a linear form. @@ -3481,16 +3434,13 @@ def _element_constructor_(self, comp=[], basis=None, name=None, return self.zero() if isinstance(comp, FreeModuleTensor): # coercion of a tensor of type (0,1) to a linear form - tensor = comp # for readability - if tensor.tensor_type() == (0,1) and self._degree == 1 and \ - tensor.base_module() is self._fmodule: - resu = self.element_class(self._fmodule, 1, name=tensor._name, - latex_name=tensor._latex_name) + tensor = comp # for readability + if tensor.tensor_type() == (0, 1) and self._degree == 1 and tensor.base_module() is self._fmodule: + resu = self.element_class(self._fmodule, 1, name=tensor._name, latex_name=tensor._latex_name) for basis, comp in tensor._components.items(): resu._components[basis] = comp.copy() return resu - raise TypeError("cannot coerce the {} ".format(tensor) + - "to an element of {}".format(self)) + raise TypeError("cannot coerce the {} ".format(tensor) + "to an element of {}".format(self)) # standard construction resu = self.element_class(self._fmodule, 1, name=name, latex_name=latex_name) if comp: @@ -3553,7 +3503,7 @@ def zero(self): for basis in self._fmodule._known_bases: resu._components[basis] = resu._new_comp(basis) # (since new components are initialized to zero) - resu._is_zero = True # This element is certainly zero + resu._is_zero = True # This element is certainly zero resu.set_immutable() return resu diff --git a/src/sage/tensor/modules/format_utilities.py b/src/sage/tensor/modules/format_utilities.py index 0bfcd942006..d6a959d8460 100644 --- a/src/sage/tensor/modules/format_utilities.py +++ b/src/sage/tensor/modules/format_utilities.py @@ -100,7 +100,7 @@ def is_atomic(expr, sep=['+', '-']) -> bool: elif c == ')': level -= 1 continue - if any(expr[n:n + len(s)] == s for s in sep): + if any(expr[n : n + len(s)] == s for s in sep): if level == 0 and n > 0: return False return True @@ -308,6 +308,7 @@ class FormattedExpansion(SageObject): sage: latex(f) \frac{x}{2} """ + def __init__(self, txt=None, latex=None): r""" TESTS:: diff --git a/src/sage/tensor/modules/free_module_alt_form.py b/src/sage/tensor/modules/free_module_alt_form.py index aa9ded13538..6f223cf0691 100644 --- a/src/sage/tensor/modules/free_module_alt_form.py +++ b/src/sage/tensor/modules/free_module_alt_form.py @@ -27,6 +27,7 @@ - Chap. 23 of R. Godement : *Algebra* [God1968]_ - Chap. 15 of S. Lang : *Algebra* [Lan2002]_ """ + # **************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger @@ -212,6 +213,7 @@ class FreeModuleAltForm(FreeModuleTensor): sage: s.display(e) zero = 0 """ + def __init__(self, fmodule, degree, name=None, latex_name=None): r""" Initialize ``self``. @@ -234,10 +236,7 @@ def __init__(self, fmodule, degree, name=None, latex_name=None): sage: a1[e,0,1] = 2 sage: TestSuite(a1).run() """ - FreeModuleTensor.__init__(self, fmodule, (0, degree), name=name, - latex_name=latex_name, - antisym=range(degree), - parent=fmodule.dual_exterior_power(degree)) + FreeModuleTensor.__init__(self, fmodule, (0, degree), name=name, latex_name=latex_name, antisym=range(degree), parent=fmodule.dual_exterior_power(degree)) def _repr_(self): r""" @@ -323,13 +322,9 @@ def _new_comp(self, basis): """ fmodule = self._fmodule # the base free module if self._tensor_rank == 1: - return Components(fmodule._ring, basis, 1, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter) + return Components(fmodule._ring, basis, 1, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) - return CompFullyAntiSym(fmodule._ring, basis, self._tensor_rank, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter) + return CompFullyAntiSym(fmodule._ring, basis, self._tensor_rank, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) def degree(self): r""" @@ -382,8 +377,8 @@ def _display_expansion(self, basis=None, format_spec=None): from sage.misc.latex import latex from sage.typeset.unicode_characters import unicode_wedge from .format_utilities import is_atomic, FormattedExpansion - basis, format_spec = self._preparse_display(basis=basis, - format_spec=format_spec) + + basis, format_spec = self._preparse_display(basis=basis, format_spec=format_spec) cobasis = basis.dual_basis() comp = self.comp(basis) terms_txt = [] @@ -417,13 +412,11 @@ def _display_expansion(self, basis=None, format_spec=None): if is_atomic(coef_txt): terms_txt.append(coef_txt + ' ' + basis_term_txt) else: - terms_txt.append('(' + coef_txt + ') ' + - basis_term_txt) + terms_txt.append('(' + coef_txt + ') ' + basis_term_txt) if is_atomic(coef_latex): terms_latex.append(coef_latex + basis_term_latex) else: - terms_latex.append(r'\left(' + coef_latex + - r'\right)' + basis_term_latex) + terms_latex.append(r'\left(' + coef_latex + r'\right)' + basis_term_latex) if not terms_txt: expansion_txt = '0' else: @@ -558,6 +551,7 @@ def display(self, basis=None, format_spec=None): """ from sage.misc.latex import latex from sage.tensor.modules.format_utilities import FormattedExpansion + exp = self._display_expansion(basis=basis, format_spec=format_spec) if self._name is None: resu_txt = repr(exp) @@ -638,9 +632,9 @@ def wedge(self, other): """ from sage.typeset.unicode_characters import unicode_wedge from .format_utilities import is_atomic + if not isinstance(other, FreeModuleAltForm): - raise TypeError("the second argument for the exterior product " + - "must be an alternating form") + raise TypeError("the second argument for the exterior product " + "must be an alternating form") if other._tensor_rank == 0: return other * self if self._tensor_rank == 0: @@ -660,9 +654,7 @@ def wedge(self, other): raise ValueError("no common basis for the exterior product") cmp_s = self._components[basis] cmp_o = other._components[basis] - cmp_r = CompFullyAntiSym(fmodule._ring, basis, rank_r, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter) + cmp_r = CompFullyAntiSym(fmodule._ring, basis, rank_r, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) for ind_s, val_s in cmp_s._comp.items(): for ind_o, val_o in cmp_o._comp.items(): ind_r = ind_s + ind_o @@ -805,9 +797,9 @@ def interior_product(self, alt_tensor): """ from .format_utilities import is_atomic from .alternating_contr_tensor import AlternatingContrTensor + if not isinstance(alt_tensor, AlternatingContrTensor): - raise TypeError("{} is not an alternating ".format(alt_tensor) + - "contravariant tensor") + raise TypeError("{} is not an alternating ".format(alt_tensor) + "contravariant tensor") p_res = alt_tensor._tensor_rank - self._tensor_rank # degree of result if self._tensor_rank == 1: # Case p = 1: @@ -816,17 +808,14 @@ def interior_product(self, alt_tensor): else: # Case p > 1: if alt_tensor._fmodule != self._fmodule: - raise ValueError("{} is not defined on ".format(alt_tensor) + - "the same module as the {}".format(self)) + raise ValueError("{} is not defined on ".format(alt_tensor) + "the same module as the {}".format(self)) if alt_tensor._tensor_rank < self._tensor_rank: - raise ValueError("the degree of the {} ".format(alt_tensor) + - "is lower than that of the {}".format(self)) + raise ValueError("the degree of the {} ".format(alt_tensor) + "is lower than that of the {}".format(self)) # Interior product at the component level: basis = self.common_basis(alt_tensor) if basis is None: raise ValueError("no common basis for the interior product") - comp = self._components[basis].interior_product( - alt_tensor._components[basis]) + comp = self._components[basis].interior_product(alt_tensor._components[basis]) if p_res == 0: res = comp # result is a scalar else: diff --git a/src/sage/tensor/modules/free_module_automorphism.py b/src/sage/tensor/modules/free_module_automorphism.py index cdd6a1bc487..c0aa50cf2eb 100644 --- a/src/sage/tensor/modules/free_module_automorphism.py +++ b/src/sage/tensor/modules/free_module_automorphism.py @@ -22,6 +22,7 @@ - Chaps. 15, 24 of R. Godement: *Algebra* [God1968]_ """ + # ***************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # @@ -255,6 +256,7 @@ class FreeModuleAutomorphism(FreeModuleTensor, MultiplicativeGroupElement): sage: s.matrix(f) == a.matrix(f) + b.matrix(f) True """ + def __init__(self, fmodule, name=None, latex_name=None): r""" TESTS:: @@ -285,14 +287,12 @@ def __init__(self, fmodule, name=None, latex_name=None): sage: b = M.general_linear_group().an_element() sage: TestSuite(b).run() """ - FreeModuleTensor.__init__(self, fmodule, (1,1), name=name, - latex_name=latex_name, - parent=fmodule.general_linear_group()) + FreeModuleTensor.__init__(self, fmodule, (1, 1), name=name, latex_name=latex_name, parent=fmodule.general_linear_group()) # MultiplicativeGroupElement attributes: # - none # Local attributes: - self._is_identity = False # a priori - self._inverse = None # inverse automorphism not set yet + self._is_identity = False # a priori + self._inverse = None # inverse automorphism not set yet self._matrices = {} #### SageObject methods #### @@ -476,8 +476,7 @@ class :class:`~sage.tensor.modules.comp.Components`; if such Kronecker delta of size 3x3 """ if self._is_identity: - raise ValueError("the components of the identity map cannot be " - "changed") + raise ValueError("the components of the identity map cannot be " "changed") return FreeModuleTensor._set_comp_unsafe(self, basis=basis) def add_comp(self, basis=None): @@ -547,8 +546,7 @@ class :class:`~sage.tensor.modules.comp.Components`; Kronecker delta of size 3x3 """ if self._is_identity: - raise ValueError("the components of the identity map cannot be " - "changed") + raise ValueError("the components of the identity map cannot be " "changed") return FreeModuleTensor._add_comp_unsafe(self, basis=basis) def __call__(self, *arg): @@ -608,6 +606,7 @@ def __call__(self, *arg): True """ from .free_module_element import FiniteRankFreeModuleElement + if len(arg) > 1: # The automorphism acting as a type-(1,1) tensor on a pair # (linear form, module element), returning a scalar: @@ -615,12 +614,11 @@ def __call__(self, *arg): if len(arg) != 2: raise TypeError("wrong number of arguments") linform = arg[0] - if linform._tensor_type != (0,1): + if linform._tensor_type != (0, 1): raise TypeError("the first argument must be a linear form") vector = arg[1] if not isinstance(vector, FiniteRankFreeModuleElement): - raise TypeError("the second argument must be a module" + - " element") + raise TypeError("the second argument must be a module" + " element") return linform(vector) # self is not the identity automorphism: return FreeModuleTensor.__call__(self, *arg) @@ -639,7 +637,7 @@ def __call__(self, *arg): for i in fmodule.irange(): res = 0 for j in fmodule.irange(): - res += t[[i,j]]*v[[j]] + res += t[[i, j]] * v[[j]] result.set_comp(basis)[i] = res # Name of the output: result._name = None @@ -648,8 +646,7 @@ def __call__(self, *arg): # LaTeX symbol for the output: result._latex_name = None if self._latex_name is not None and vector._latex_name is not None: - result._latex_name = self._latex_name + r"\left(" + \ - vector._latex_name + r"\right)" + result._latex_name = self._latex_name + r"\left(" + vector._latex_name + r"\right)" return result #### End of FreeModuleTensor methods #### @@ -746,10 +743,12 @@ def __invert__(self): Integer Ring """ from .comp import Components + if self._is_identity: return self if self._inverse is None: from sage.tensor.modules.format_utilities import is_atomic + if self._name is None: inv_name = None else: @@ -763,8 +762,7 @@ def __invert__(self): if is_atomic(self._latex_name, ['\\circ', '\\otimes']): inv_latex_name = self._latex_name + r'^{-1}' else: - inv_latex_name = r'\left(' + self._latex_name + \ - r'\right)^{-1}' + inv_latex_name = r'\left(' + self._latex_name + r'\right)^{-1}' fmodule = self._fmodule si = fmodule._sindex nsi = fmodule._rank + si @@ -775,11 +773,10 @@ def __invert__(self): except (KeyError, ValueError): continue mat_inv = mat.inverse() - cinv = Components(fmodule._ring, basis, 2, start_index=si, - output_formatter=fmodule._output_formatter) + cinv = Components(fmodule._ring, basis, 2, start_index=si, output_formatter=fmodule._output_formatter) for i in range(si, nsi): for j in range(si, nsi): - cinv[i, j] = mat_inv[i-si,j-si] + cinv[i, j] = mat_inv[i - si, j - si] self._inverse._components[basis] = cinv self._inverse._inverse = self return self._inverse @@ -856,8 +853,7 @@ def _mul_(self, other): raise ValueError("no common basis for the composition") # The composition is performed as a tensor contraction of the last # index of self (position=1) and the first index of other (position=0): - resu._components[basis] = self._components[basis].contract(1, - other._components[basis],0) + resu._components[basis] = self._components[basis].contract(1, other._components[basis], 0) return resu #### End of MultiplicativeGroupElement methods #### @@ -1018,22 +1014,20 @@ def matrix(self, basis1=None, basis2=None): [0 0 1] """ from sage.matrix.constructor import matrix + fmodule = self._fmodule if basis1 is None: basis1 = fmodule.default_basis() elif basis1 not in fmodule.bases(): - raise TypeError("{} is not a basis on the {}".format(basis1, - fmodule)) + raise TypeError("{} is not a basis on the {}".format(basis1, fmodule)) if basis2 is None: basis2 = basis1 elif basis2 not in fmodule.bases(): - raise TypeError("{} is not a basis on the {}".format(basis2, - fmodule)) + raise TypeError("{} is not a basis on the {}".format(basis2, fmodule)) if (basis1, basis2) not in self._matrices: if basis2 == basis1: comp = self.components(basis1) - mat = [[comp[[i,j]] for j in fmodule.irange()] - for i in fmodule.irange()] + mat = [[comp[[i, j]] for j in fmodule.irange()] for i in fmodule.irange()] self._matrices[(basis1, basis1)] = matrix(mat) else: # 1/ determine the matrix w.r.t. basis1: @@ -1056,8 +1050,8 @@ def _some_matrix(self): [0 2] """ self.matrix() # forces the update of the matrix in the module's default - # basis, to make sure that the dictionary self._matrices - # is not empty + # basis, to make sure that the dictionary self._matrices + # is not empty return next(iter(self._matrices.values())) @lazy_attribute diff --git a/src/sage/tensor/modules/free_module_basis.py b/src/sage/tensor/modules/free_module_basis.py index afbbbe3f899..903c339c429 100644 --- a/src/sage/tensor/modules/free_module_basis.py +++ b/src/sage/tensor/modules/free_module_basis.py @@ -19,6 +19,7 @@ - Chap. 10 of R. Godement : *Algebra* [God1968]_ - Chap. 3 of S. Lang : *Algebra* [Lan2002]_ """ + # **************************************************************************** # Copyright (C) 2015, 2018 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger @@ -70,6 +71,7 @@ class Basis_abstract(UniqueRepresentation, AbstractFamily): (2, Element e_2 of the Rank-3 free module M over the Integer Ring), (3, Element e_3 of the Rank-3 free module M over the Integer Ring)] """ + def __init__(self, fmodule, symbol, latex_symbol, indices, latex_indices): """ Initialize ``self``. @@ -265,12 +267,11 @@ def __getitem__(self, index): start -= si if stop is not None: stop -= si - return self._vec[start:stop:index.step] + return self._vec[start : stop : index.step] n = self._fmodule._rank i = index - si - if i < 0 or i > n-1: - raise IndexError("out of range: {} not in [{},{}]".format(i+si, si, - n-1+si)) + if i < 0 or i > n - 1: + raise IndexError("out of range: {} not in [{},{}]".format(i + si, si, n - 1 + si)) return self._vec[i] def _latex_(self): @@ -315,8 +316,7 @@ def free_module(self): """ return self._fmodule - def set_name(self, symbol, latex_symbol=None, indices=None, - latex_indices=None, index_position='down'): + def set_name(self, symbol, latex_symbol=None, indices=None, latex_indices=None, index_position='down'): r""" Set (or change) the text name and LaTeX name of ``self``. @@ -397,8 +397,7 @@ def set_name(self, symbol, latex_symbol=None, indices=None, # LaTeX symbols: if isinstance(latex_symbol, (list, tuple)): if len(latex_symbol) != n: - raise ValueError( - "latex_symbol must contain {} strings".format(n)) + raise ValueError("latex_symbol must contain {} strings".format(n)) if len(set(latex_symbol)) != n: raise ValueError("the individual symbols must be different") else: @@ -417,6 +416,7 @@ def set_name(self, symbol, latex_symbol=None, indices=None, for i in range(n): self._vec[i].set_name(symbol[i], latex_name=latex_symbol[i]) + # **************************************************************************** @@ -484,8 +484,8 @@ class FreeModuleCoBasis(Basis_abstract): sage: TestSuite(f).run() """ - def __init__(self, basis, symbol, latex_symbol=None, indices=None, - latex_indices=None): + + def __init__(self, basis, symbol, latex_symbol=None, indices=None, latex_indices=None): r""" TESTS:: @@ -496,8 +496,7 @@ def __init__(self, basis, symbol, latex_symbol=None, indices=None, sage: TestSuite(f).run() """ self._basis = basis - Basis_abstract.__init__(self, basis._fmodule, symbol, latex_symbol, - indices, latex_indices) + Basis_abstract.__init__(self, basis._fmodule, symbol, latex_symbol, indices, latex_indices) # The individual linear forms: vl = [] fmodule = self._fmodule @@ -508,8 +507,7 @@ def __init__(self, basis, symbol, latex_symbol=None, indices=None, vl.append(v) self._vec = tuple(vl) # The names: - self.set_name(symbol, latex_symbol=latex_symbol, indices=indices, - latex_indices=latex_indices, index_position='up') + self.set_name(symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, index_position='up') def _test_iter_len(self, **options): r""" @@ -548,6 +546,7 @@ def _repr_(self): """ return "Dual basis {} on the {}".format(self._name, self._fmodule) + # **************************************************************************** @@ -659,13 +658,12 @@ class FreeModuleBasis(Basis_abstract): sage: TestSuite(f).run() sage: TestSuite(g).run() """ + # The following class attribute must be redefined by any derived class: _cobasis_class = FreeModuleCoBasis @staticmethod - def __classcall_private__(cls, fmodule, symbol, latex_symbol=None, - indices=None, latex_indices=None, - symbol_dual=None, latex_symbol_dual=None): + def __classcall_private__(cls, fmodule, symbol, latex_symbol=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): """ Normalize input to ensure a unique representation. @@ -693,15 +691,9 @@ def __classcall_private__(cls, fmodule, symbol, latex_symbol=None, symbol_dual = tuple(symbol_dual) if isinstance(latex_symbol_dual, list): latex_symbol_dual = tuple(latex_symbol_dual) - return super().__classcall__(cls, fmodule, symbol, - latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) - - def __init__(self, fmodule, symbol, latex_symbol=None, indices=None, - latex_indices=None, symbol_dual=None, latex_symbol_dual=None): + return super().__classcall__(cls, fmodule, symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) + + def __init__(self, fmodule, symbol, latex_symbol=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): r""" Initialize ``self``. @@ -713,8 +705,7 @@ def __init__(self, fmodule, symbol, latex_symbol=None, indices=None, sage: e = FreeModuleBasis(M, 'e', latex_symbol=r'\epsilon') sage: TestSuite(e).run() """ - Basis_abstract.__init__(self, fmodule, symbol, latex_symbol, indices, - latex_indices) + Basis_abstract.__init__(self, fmodule, symbol, latex_symbol, indices, latex_indices) # The basis is added to the module list of bases fmodule._known_bases.append(self) # The individual vectors: @@ -726,8 +717,7 @@ def __init__(self, fmodule, symbol, latex_symbol=None, indices=None, vl.append(v) self._vec = tuple(vl) # The names: - self.set_name(symbol, latex_symbol=latex_symbol, indices=indices, - latex_indices=latex_indices, index_position='down') + self.set_name(symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, index_position='down') # The first defined basis is considered as the default one: if fmodule._def_basis is None: fmodule._def_basis = self @@ -742,11 +732,9 @@ def __init__(self, fmodule, symbol, latex_symbol=None, indices=None, # identity map of the general linear group: if fmodule._general_linear_group is not None: from .comp import KroneckerDelta + gl = fmodule._general_linear_group - gl.one()._components[self] = KroneckerDelta( - fmodule._ring, self, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter) + gl.one()._components[self] = KroneckerDelta(fmodule._ring, self, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) # The dual basis: self._symbol_dual = symbol_dual self._latex_symbol_dual = latex_symbol_dual @@ -759,11 +747,7 @@ def __init__(self, fmodule, symbol, latex_symbol=None, indices=None, latex_symbol_dual = symbol_dual if latex_symbol_dual is None: latex_symbol_dual = latex_symbol - self._dual_basis = type(self)._cobasis_class( - self, symbol_dual, - latex_symbol=latex_symbol_dual, - indices=indices, - latex_indices=latex_indices) + self._dual_basis = type(self)._cobasis_class(self, symbol_dual, latex_symbol=latex_symbol_dual, indices=indices, latex_indices=latex_indices) # ##### Methods to be redefined by derived classes of FreeModuleBasis ##### @@ -784,9 +768,7 @@ def _repr_(self): """ return "Basis {} on the {}".format(self._name, self._fmodule) - def _new_instance(self, symbol, latex_symbol=None, indices=None, - latex_indices=None, symbol_dual=None, - latex_symbol_dual=None): + def _new_instance(self, symbol, latex_symbol=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): r""" Construct a new basis on the same module as ``self``. @@ -831,10 +813,7 @@ def _new_instance(self, symbol, latex_symbol=None, indices=None, sage: _.dual_basis() Dual basis (E^x,E^y,E^z) on the Rank-3 free module M over the Integer Ring """ - return FreeModuleBasis(self._fmodule, symbol, latex_symbol=latex_symbol, - indices=indices, latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) + return FreeModuleBasis(self._fmodule, symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) # ##### End of methods to be redefined by derived classes ##### @@ -874,8 +853,7 @@ def _init_from_family(self, family): # Copy of the components of each element of the family: for i, ff in enumerate(family): if ff not in fmodule: - raise TypeError("{} is not an element of {}".format(ff, - fmodule)) + raise TypeError("{} is not an element of {}".format(ff, fmodule)) vs = self._vec[i] for basis, comp in ff._components.items(): vs._components[basis] = comp.copy() @@ -952,9 +930,7 @@ def dual_basis(self): """ return self._dual_basis - def new_basis(self, change_of_basis, symbol, latex_symbol=None, - indices=None, latex_indices=None, symbol_dual=None, - latex_symbol_dual=None): + def new_basis(self, change_of_basis, symbol, latex_symbol=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): r""" Define a new module basis from ``self``. @@ -1025,48 +1001,39 @@ def new_basis(self, change_of_basis, symbol, latex_symbol=None, Rational Field """ from .free_module_automorphism import FreeModuleAutomorphism + if not isinstance(change_of_basis, FreeModuleAutomorphism): - raise TypeError("the argument change_of_basis must be some " + - "instance of FreeModuleAutomorphism") + raise TypeError("the argument change_of_basis must be some " + "instance of FreeModuleAutomorphism") fmodule = self._fmodule # self._new_instance used instead of FreeModuleBasis for a correct # construction in case of derived classes: - the_new_basis = self._new_instance(symbol, latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) + the_new_basis = self._new_instance(symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) transf = change_of_basis.copy() inv_transf = change_of_basis.inverse().copy() si = fmodule._sindex # Components of the new basis vectors in the old basis: for i in fmodule.irange(): for j in fmodule.irange(): - the_new_basis._vec[i-si].add_comp(self)[[j]] = \ - transf.comp(self)[[j, i]] + the_new_basis._vec[i - si].add_comp(self)[[j]] = transf.comp(self)[[j, i]] # Components of the new dual-basis elements in the old dual basis: for i in fmodule.irange(): for j in fmodule.irange(): - the_new_basis._dual_basis._vec[i-si].add_comp(self)[[j]] = \ - inv_transf.comp(self)[[i, j]] + the_new_basis._dual_basis._vec[i - si].add_comp(self)[[j]] = inv_transf.comp(self)[[i, j]] # The components of the transformation and its inverse are the same in # the two bases: for i in fmodule.irange(): for j in fmodule.irange(): ij = [i, j] transf.add_comp(the_new_basis)[ij] = transf.comp(self)[ij] - inv_transf.add_comp(the_new_basis)[ij] = \ - inv_transf.comp(self)[ij] + inv_transf.add_comp(the_new_basis)[ij] = inv_transf.comp(self)[ij] # Components of the old basis vectors in the new basis: for i in fmodule.irange(): for j in fmodule.irange(): - self._vec[i-si].add_comp(the_new_basis)[[j]] = \ - inv_transf.comp(self)[[j, i]] + self._vec[i - si].add_comp(the_new_basis)[[j]] = inv_transf.comp(self)[[j, i]] # Components of the old dual-basis elements in the new cobasis: for i in fmodule.irange(): for j in fmodule.irange(): - self._dual_basis._vec[i-si].add_comp(the_new_basis)[[j]] = \ - transf.comp(self)[[i, j]] + self._dual_basis._vec[i - si].add_comp(the_new_basis)[[j]] = transf.comp(self)[[i, j]] # The automorphism and its inverse are added to the module's dictionary # of changes of bases: fmodule._basis_changes[(self, the_new_basis)] = transf diff --git a/src/sage/tensor/modules/free_module_element.py b/src/sage/tensor/modules/free_module_element.py index 8cc19bd984d..9da894d72dd 100644 --- a/src/sage/tensor/modules/free_module_element.py +++ b/src/sage/tensor/modules/free_module_element.py @@ -220,8 +220,7 @@ def __init__( sage: v1[e,:] = (-2, 1, 3) sage: TestSuite(v1).run() """ - AlternatingContrTensor.__init__(self, fmodule, 1, name=name, - latex_name=latex_name) + AlternatingContrTensor.__init__(self, fmodule, 1, name=name, latex_name=latex_name) def _repr_(self) -> str: r""" @@ -265,8 +264,7 @@ def _new_comp(self, basis: FreeModuleBasis) -> Components: """ fmodule = self._fmodule # the base free module - return Components(fmodule._ring, basis, 1, start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter) + return Components(fmodule._ring, basis, 1, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) def _new_instance(self): r""" diff --git a/src/sage/tensor/modules/free_module_homset.py b/src/sage/tensor/modules/free_module_homset.py index a880583b51d..2dde83fa5f1 100644 --- a/src/sage/tensor/modules/free_module_homset.py +++ b/src/sage/tensor/modules/free_module_homset.py @@ -17,6 +17,7 @@ - Chaps. 13, 14 of R. Godement : *Algebra* [God1968]_ - Chap. 3 of S. Lang : *Algebra* [Lan2002]_ """ + # **************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger @@ -29,8 +30,7 @@ from sage.categories.homset import Homset from sage.misc.classcall_metaclass import ClasscallMetaclass -from sage.tensor.modules.free_module_morphism import ( - FiniteRankFreeModuleEndomorphism, FiniteRankFreeModuleMorphism) +from sage.tensor.modules.free_module_morphism import FiniteRankFreeModuleEndomorphism, FiniteRankFreeModuleMorphism from sage.tensor.modules.free_module_automorphism import FreeModuleAutomorphism from sage.tensor.modules.free_module_tensor import FreeModuleTensor @@ -145,21 +145,17 @@ def __classcall_private__(cls, fmodule1, fmodule2, name=None, latex_name=None): True """ from .finite_rank_free_module import FiniteRankFreeModule + if not isinstance(fmodule1, FiniteRankFreeModule): - raise TypeError("fmodule1 = {} is not an ".format(fmodule1) + - "instance of FiniteRankFreeModule") + raise TypeError("fmodule1 = {} is not an ".format(fmodule1) + "instance of FiniteRankFreeModule") if not isinstance(fmodule2, FiniteRankFreeModule): - raise TypeError("fmodule2 = {} is not an ".format(fmodule2) + - "instance of FiniteRankFreeModule") + raise TypeError("fmodule2 = {} is not an ".format(fmodule2) + "instance of FiniteRankFreeModule") if fmodule1.base_ring() != fmodule2.base_ring(): - raise TypeError("the domain and codomain are not defined over " + - "the same ring") + raise TypeError("the domain and codomain are not defined over " + "the same ring") if name is None: name = "Hom(" + fmodule1._name + "," + fmodule2._name + ")" if latex_name is None: - latex_name = \ - r"\mathrm{Hom}\left(" + fmodule1._latex_name + "," + \ - fmodule2._latex_name + r"\right)" + latex_name = r"\mathrm{Hom}\left(" + fmodule1._latex_name + "," + fmodule2._latex_name + r"\right)" if fmodule1 == fmodule2: return FreeModuleEndset(fmodule1, name, latex_name) return type.__call__(cls, fmodule1, fmodule2, name, latex_name) @@ -237,12 +233,12 @@ def __call__(self, *args, **kwds): True """ from sage.structure.parent import Parent + return Parent.__call__(self, *args, **kwds) # ### Methods required for any Parent ### - def _element_constructor_(self, matrix_rep, bases=None, name=None, - latex_name=None, is_identity=False): + def _element_constructor_(self, matrix_rep, bases=None, name=None, latex_name=None, is_identity=False): r""" Construct an element of ``self``, i.e. a homomorphism M --> N, where M is the domain of ``self`` and N its codomain. @@ -318,9 +314,7 @@ def _element_constructor_(self, matrix_rep, bases=None, name=None, True """ # Standard construction: - return self.element_class(self, matrix_rep, bases=bases, name=name, - latex_name=latex_name, - is_identity=is_identity) + return self.element_class(self, matrix_rep, bases=bases, name=name, latex_name=latex_name, is_identity=is_identity) def _an_element_(self): r""" @@ -492,23 +486,20 @@ def _coerce_map_from_(self, other): True """ from sage.tensor.modules.tensor_free_module import TensorFreeModule - from sage.tensor.modules.free_module_linear_group import \ - FreeModuleLinearGroup + from sage.tensor.modules.free_module_linear_group import FreeModuleLinearGroup + if isinstance(other, TensorFreeModule): # Coercion of a type-(1,1) tensor to an endomorphism: if other.tensor_type() == (1, 1): - return self.is_endomorphism_set() and \ - other.base_module() is self.domain() + return self.is_endomorphism_set() and other.base_module() is self.domain() if isinstance(other, FreeModuleLinearGroup): # Coercion of an automorphism to an endomorphism: - return self.is_endomorphism_set() and \ - other.base_module() is self.domain() + return self.is_endomorphism_set() and other.base_module() is self.domain() return False # ### Methods required for any Parent ### - def _element_constructor_(self, matrix_rep, bases=None, name=None, - latex_name=None, is_identity=False): + def _element_constructor_(self, matrix_rep, bases=None, name=None, latex_name=None, is_identity=False): r""" Construct an element of ``self``, i.e. a homomorphism M --> N, where M is the domain of ``self`` and N its codomain. @@ -574,21 +565,14 @@ def _element_constructor_(self, matrix_rep, bases=None, name=None, basis = tensor.pick_a_basis() tcomp = tensor.comp(basis) fmodule = tensor.base_module() - mat = [[tcomp[[i, j]] for j in fmodule.irange()] - for i in fmodule.irange()] + mat = [[tcomp[[i, j]] for j in fmodule.irange()] for i in fmodule.irange()] if isinstance(tensor, FreeModuleAutomorphism): is_identity = tensor._is_identity else: is_identity = False - return self.element_class(self, mat, bases=(basis, basis), - name=tensor._name, - latex_name=tensor._latex_name, - is_identity=is_identity) - raise TypeError("cannot coerce the {}".format(tensor) + - " to an element of {}".format(self)) - return super()._element_constructor_(matrix_rep, bases=bases, - name=name, latex_name=latex_name, - is_identity=is_identity) + return self.element_class(self, mat, bases=(basis, basis), name=tensor._name, latex_name=tensor._latex_name, is_identity=is_identity) + raise TypeError("cannot coerce the {}".format(tensor) + " to an element of {}".format(self)) + return super()._element_constructor_(matrix_rep, bases=bases, name=name, latex_name=latex_name, is_identity=is_identity) # ### Monoid methods ### diff --git a/src/sage/tensor/modules/free_module_linear_group.py b/src/sage/tensor/modules/free_module_linear_group.py index 9e5af8c31ff..45467177978 100644 --- a/src/sage/tensor/modules/free_module_linear_group.py +++ b/src/sage/tensor/modules/free_module_linear_group.py @@ -19,6 +19,7 @@ - Chap. 15 of R. Godement : *Algebra* [God1968]_ """ + # **************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # @@ -279,15 +280,13 @@ def __init__(self, fmodule): sage: TestSuite(GL).run() """ if not isinstance(fmodule, FiniteRankFreeModule): - raise TypeError("{} is not a free module of finite rank".format( - fmodule)) + raise TypeError("{} is not a free module of finite rank".format(fmodule)) Parent.__init__(self, category=Groups()) self._fmodule = fmodule #### Parent methods #### - def _element_constructor_(self, comp=[], basis=None, name=None, - latex_name=None): + def _element_constructor_(self, comp=[], basis=None, name=None, latex_name=None): r""" Construct a free module automorphism. @@ -358,16 +357,15 @@ def _element_constructor_(self, comp=[], basis=None, name=None, True """ from sage.tensor.modules.free_module_tensor import FreeModuleTensor - from sage.tensor.modules.free_module_morphism import \ - FiniteRankFreeModuleMorphism + from sage.tensor.modules.free_module_morphism import FiniteRankFreeModuleMorphism + if comp == 1: return self.one() if isinstance(comp, FreeModuleTensor): - tens = comp # for readability + tens = comp # for readability # Conversion of a type-(1,1) tensor to an automorphism - if tens.tensor_type() == (1,1): - resu = self.element_class(self._fmodule, name=tens._name, - latex_name=tens._latex_name) + if tens.tensor_type() == (1, 1): + resu = self.element_class(self._fmodule, name=tens._name, latex_name=tens._latex_name) for basis, comp in tens._components.items(): resu._components[basis] = comp.copy() # Check whether the tensor is invertible: @@ -376,14 +374,12 @@ def _element_constructor_(self, comp=[], basis=None, name=None, except (ZeroDivisionError, TypeError): raise TypeError(f"the {tens} is not invertible ") return resu - raise TypeError(f"the {tens} cannot be converted " - + "to an automorphism.") + raise TypeError(f"the {tens} cannot be converted " + "to an automorphism.") if isinstance(comp, FiniteRankFreeModuleMorphism): # Conversion of an endomorphism to an automorphism endo = comp # for readability if endo.is_endomorphism() and self._fmodule is endo.domain(): - resu = self.element_class(self._fmodule, name=endo._name, - latex_name=endo._latex_name) + resu = self.element_class(self._fmodule, name=endo._name, latex_name=endo._latex_name) for basis, mat in endo._matrices.items(): resu.add_comp(basis[0])[:] = mat # Check whether the endomorphism is invertible: @@ -392,12 +388,10 @@ def _element_constructor_(self, comp=[], basis=None, name=None, except (ZeroDivisionError, TypeError): raise TypeError("the {} is not invertible ".format(endo)) return resu - raise TypeError("cannot coerce the {}".format(endo) + - " to an element of {}".format(self)) + raise TypeError("cannot coerce the {}".format(endo) + " to an element of {}".format(self)) # standard construction - resu = self.element_class(self._fmodule, name=name, - latex_name=latex_name) + resu = self.element_class(self._fmodule, name=name, latex_name=latex_name) if comp: resu.set_comp(basis)[:] = comp return resu @@ -428,9 +422,9 @@ def _an_element_(self): comp = resu.set_comp() for i in self._fmodule.irange(): if i % 2 == 0: - comp[[i,i]] = self._fmodule._ring.one() + comp[[i, i]] = self._fmodule._ring.one() else: - comp[[i,i]] = -(self._fmodule._ring.one()) + comp[[i, i]] = -(self._fmodule._ring.one()) return resu #### End of parent methods #### @@ -502,11 +496,10 @@ def one(self): resu = self._element_constructor_(name='Id', latex_name=r'\mathrm{Id}') # Initialization of the components (Kronecker delta) in some basis: from .comp import KroneckerDelta + fmodule = self._fmodule for basis in fmodule.bases(): - resu._components[basis] = KroneckerDelta(fmodule._ring, basis, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter) + resu._components[basis] = KroneckerDelta(fmodule._ring, basis, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) resu._is_identity = True resu.set_immutable() return resu @@ -538,6 +531,7 @@ def _latex_(self): \mathrm{GL}\left( M \right) """ from sage.misc.latex import latex + return r"\mathrm{GL}\left(" + latex(self._fmodule) + r"\right)" def base_module(self): diff --git a/src/sage/tensor/modules/free_module_morphism.py b/src/sage/tensor/modules/free_module_morphism.py index 27e8a51968b..6e3c04e4516 100644 --- a/src/sage/tensor/modules/free_module_morphism.py +++ b/src/sage/tensor/modules/free_module_morphism.py @@ -17,6 +17,7 @@ - Chap. 13, 14 of R. Godement : *Algebra* [God1968]_ - Chap. 3 of S. Lang : *Algebra* [Lan2002]_ """ + # ***************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger @@ -171,8 +172,8 @@ class FiniteRankFreeModuleMorphism(Morphism): sage: phi(3*u + v) == 3*phi(u) + phi(v) True """ - def __init__(self, parent, matrix_rep, bases=None, name=None, - latex_name=None, is_identity=False): + + def __init__(self, parent, matrix_rep, bases=None, name=None, latex_name=None, is_identity=False): r""" TESTS: @@ -198,29 +199,26 @@ def __init__(self, parent, matrix_rep, bases=None, name=None, raise TypeError('use the subclass FiniteRankFreeModuleEndomorphism for the identity morphis') from sage.matrix.constructor import matrix from sage.misc.constant_function import ConstantFunction + Morphism.__init__(self, parent) fmodule1 = parent.domain() fmodule2 = parent.codomain() if bases is None: def_basis1 = fmodule1.default_basis() if def_basis1 is None: - raise ValueError("the {} has no default ".format(fmodule1) + - "basis") + raise ValueError("the {} has no default ".format(fmodule1) + "basis") def_basis2 = fmodule2.default_basis() if def_basis2 is None: - raise ValueError("the {} has no default ".format(fmodule2) + - "basis") + raise ValueError("the {} has no default ".format(fmodule2) + "basis") bases = (def_basis1, def_basis2) else: bases = tuple(bases) # insures bases is a tuple if len(bases) != 2: raise TypeError("the argument bases must contain 2 bases") if bases[0] not in fmodule1.bases(): - raise TypeError("{} is not a basis on the {}".format(bases[0], - fmodule1)) + raise TypeError("{} is not a basis on the {}".format(bases[0], fmodule1)) if bases[1] not in fmodule2.bases(): - raise TypeError("{} is not a basis on the {}".format(bases[1], - fmodule2)) + raise TypeError("{} is not a basis on the {}".format(bases[1], fmodule2)) ring = parent.base_ring() n1 = fmodule1.rank() n2 = fmodule2.rank() @@ -338,7 +336,7 @@ def __eq__(self, other): sage: phi.__eq__(Hom(M,N).zero()) True """ - if isinstance(other, (int, Integer)): # other should be 0 + if isinstance(other, (int, Integer)): # other should be 0 if other == 0: return self.is_zero() return False @@ -348,9 +346,8 @@ def __eq__(self, other): return False bases = self._common_bases(other) if bases is None: - raise ValueError("no common pair of bases has been found to " + - "compare {} and {}".format(self, other)) - return bool( self.matrix(*bases) == other.matrix(*bases) ) + raise ValueError("no common pair of bases has been found to " + "compare {} and {}".format(self, other)) + return bool(self.matrix(*bases) == other.matrix(*bases)) def __ne__(self, other): r""" @@ -477,8 +474,7 @@ def _add_(self, other): # to have the same parents bases = self._common_bases(other) if bases is None: - raise ValueError("no common pair of bases has been found to " + - "add {} and {}".format(self, other)) + raise ValueError("no common pair of bases has been found to " + "add {} and {}".format(self, other)) # Addition at the matrix level: resu_mat = self._matrices[bases] + other._matrices[bases] if self._name is not None and other._name is not None: @@ -489,8 +485,7 @@ def _add_(self, other): resu_latex_name = self._latex_name + '+' + other._latex_name else: resu_latex_name = None - return self.__class__(self.parent(), resu_mat, bases=bases, - name=resu_name, latex_name=resu_latex_name) + return self.__class__(self.parent(), resu_mat, bases=bases, name=resu_name, latex_name=resu_latex_name) def _sub_(self, other): r""" @@ -557,8 +552,7 @@ def _sub_(self, other): # to have the same parents bases = self._common_bases(other) if bases is None: - raise ValueError("no common pair of bases has been found to " + - "subtract {} from {}".format(other, self)) + raise ValueError("no common pair of bases has been found to " + "subtract {} from {}".format(other, self)) # Subtraction at the matrix level: resu_mat = self._matrices[bases] - other._matrices[bases] if self._name is not None and other._name is not None: @@ -569,8 +563,7 @@ def _sub_(self, other): resu_latex_name = self._latex_name + '-' + other._latex_name else: resu_latex_name = None - return self.__class__(self.parent(), resu_mat, bases=bases, - name=resu_name, latex_name=resu_latex_name) + return self.__class__(self.parent(), resu_mat, bases=bases, name=resu_name, latex_name=resu_latex_name) def _lmul_(self, scalar): r""" @@ -635,7 +628,7 @@ def __pos__(self): False """ resu = self.__class__(self.parent(), 0, is_identity=self._is_identity) - # 0 = provisory value + # 0 = provisory value for bases, mat in self._matrices.items(): resu._matrices[bases] = +mat if self._name is not None: @@ -682,9 +675,7 @@ def __neg__(self): # Map methods # - def _call_( - self, element: FiniteRankFreeModuleElement - ) -> FiniteRankFreeModuleElement: + def _call_(self, element: FiniteRankFreeModuleElement) -> FiniteRankFreeModuleElement: r""" Action of the homomorphism ``self`` on some free module element @@ -755,8 +746,7 @@ def _call_( except ValueError: continue else: - raise ValueError("no common basis found to evaluate the image " + - "of {} by {}".format(element,self)) + raise ValueError("no common basis found to evaluate the image " + "of {} by {}".format(element, self)) # Components of the result obtained by matrix multiplication mat = self.matrix(basis_dom, basis_codom) vcomp = element._components[basis_dom] @@ -764,7 +754,7 @@ def _call_( for i in range(codom.rank()): s = 0 for j in range(dom.rank()): - s += mat[i,j] * vcomp[[j+sindex]] + s += mat[i, j] * vcomp[[j + sindex]] tresu.append(s) # Name of the result if self._name is not None and element._name is not None: @@ -772,13 +762,11 @@ def _call_( else: resu_name = None if self._latex_name is not None and element._latex_name is not None: - resu_latex_name = self._latex_name + r'\left(' + \ - element._latex_name + r'\right)' + resu_latex_name = self._latex_name + r'\left(' + element._latex_name + r'\right)' else: resu_latex_name = None # Creation of the result - return codom(tresu, basis=basis_codom, name=resu_name, - latex_name=resu_latex_name) + return codom(tresu, basis=basis_codom, name=resu_name, latex_name=resu_latex_name) def is_injective(self): r""" @@ -861,9 +849,8 @@ def is_surjective(self): """ if self._is_identity: return True - raise NotImplementedError( - "FiniteRankFreeModuleMorphism.is_surjective() " + - "has not been implemented yet") + raise NotImplementedError("FiniteRankFreeModuleMorphism.is_surjective() " + "has not been implemented yet") + # # Morphism methods # @@ -967,16 +954,14 @@ def _modules_and_bases(self, basis1=None, basis2=None): if basis1 is None: basis1 = fmodule1.default_basis() elif basis1 not in fmodule1.bases(): - raise TypeError(str(basis1) + " is not a basis on the " + - str(fmodule1) + ".") + raise TypeError(str(basis1) + " is not a basis on the " + str(fmodule1) + ".") if basis2 is None: if self.is_endomorphism(): basis2 = basis1 else: basis2 = fmodule2.default_basis() elif basis2 not in fmodule2.bases(): - raise TypeError(str(basis2) + " is not a basis on the " + - str(fmodule2) + ".") + raise TypeError(str(basis2) + " is not a basis on the " + str(fmodule2) + ".") return fmodule1, fmodule2, basis1, basis2 def matrix(self, basis1=None, basis2=None): @@ -1065,6 +1050,7 @@ def matrix(self, basis1=None, basis2=None): [-25 54 -25] """ from sage.matrix.constructor import matrix + fmodule1, fmodule2, basis1, basis2 = self._modules_and_bases(basis1, basis2) if (basis1, basis2) not in self._matrices: if self._is_identity: @@ -1078,14 +1064,13 @@ def matrix(self, basis1=None, basis2=None): size = fmodule1.rank() mat = [] for i in range(size): - row = [zero]*size + row = [zero] * size row[i] = one mat.append(row) else: # the matrix is the change-of-basis matrix: change = fmodule1.change_of_basis(basis1, basis2) - mat = [[change[[i,j]] for j in fmodule1.irange()] - for i in fmodule1.irange()] + mat = [[change[[i, j]] for j in fmodule1.irange()] for i in fmodule1.irange()] self._matrices[(basis1, basis2)] = matrix(mat) else: # Generic homomorphism @@ -1098,43 +1083,32 @@ def matrix(self, basis1=None, basis2=None): nb2 = b2 break else: - raise ValueError("no start basis could be found for " + - "applying the change-of-basis formula") + raise ValueError("no start basis could be found for " + "applying the change-of-basis formula") change2 = fmodule2._basis_changes[(basis2, nb2)] - mat2 = matrix( [[change2[[i,j]] for j in fmodule2.irange()] - for i in fmodule2.irange()] ) - self._matrices[(basis1, basis2)] = \ - mat2 * self._matrices[(basis1,nb2)] + mat2 = matrix([[change2[[i, j]] for j in fmodule2.irange()] for i in fmodule2.irange()]) + self._matrices[(basis1, basis2)] = mat2 * self._matrices[(basis1, nb2)] elif basis2 in b2_list: for b1 in b1_list: if (b1, basis1) in fmodule1._basis_changes: nb1 = b1 break else: - raise ValueError("no start basis could be found for " + - "applying the change-of-basis formula") + raise ValueError("no start basis could be found for " + "applying the change-of-basis formula") change1 = fmodule1._basis_changes[(nb1, basis1)] - mat1 = matrix( [[change1[[i,j]] for j in fmodule1.irange()] - for i in fmodule1.irange()] ) - self._matrices[(basis1, basis2)] = \ - self._matrices[(nb1,basis2)] * mat1 - else: # most general change-of-basis formula - for (b1, b2) in self._matrices: - if (b1, basis1) in fmodule1._basis_changes and \ - (basis2, b2) in fmodule2._basis_changes: + mat1 = matrix([[change1[[i, j]] for j in fmodule1.irange()] for i in fmodule1.irange()]) + self._matrices[(basis1, basis2)] = self._matrices[(nb1, basis2)] * mat1 + else: # most general change-of-basis formula + for b1, b2 in self._matrices: + if (b1, basis1) in fmodule1._basis_changes and (basis2, b2) in fmodule2._basis_changes: nb1, nb2 = b1, b2 break else: - raise ValueError("no start basis could be found for " + - "applying the change-of-basis formula") + raise ValueError("no start basis could be found for " + "applying the change-of-basis formula") change1 = fmodule1._basis_changes[(nb1, basis1)] change2 = fmodule2._basis_changes[(basis2, nb2)] - mat1 = matrix( [[change1[[i,j]] for j in fmodule1.irange()] - for i in fmodule1.irange()] ) - mat2 = matrix( [[change2[[i,j]] for j in fmodule2.irange()] - for i in fmodule2.irange()] ) - self._matrices[(basis1, basis2)] = \ - mat2 * self._matrices[(nb1,nb2)] * mat1 + mat1 = matrix([[change1[[i, j]] for j in fmodule1.irange()] for i in fmodule1.irange()]) + mat2 = matrix([[change2[[i, j]] for j in fmodule2.irange()] for i in fmodule2.irange()]) + self._matrices[(basis1, basis2)] = mat2 * self._matrices[(nb1, nb2)] * mat1 return self._matrices[(basis1, basis2)] def _common_bases(self, other): @@ -1244,6 +1218,7 @@ def display(self, basis1=None, basis2=None): """ from sage.misc.latex import latex from .format_utilities import is_atomic, FormattedExpansion + fmodule1, fmodule2, basis1, basis2 = self._modules_and_bases(basis1, basis2) matrix = self.matrix(basis1, basis2) if all(element._name for element in basis1): @@ -1254,9 +1229,7 @@ def display(self, basis1=None, basis2=None): basis2_names = [element._name for element in basis2] else: basis2_names = None - resu_txt = matrix.str(unicode=True, - top_border=basis1_names, - left_border=basis2_names) + resu_txt = matrix.str(unicode=True, top_border=basis1_names, left_border=basis2_names) resu_latex = latex(matrix) return FormattedExpansion(resu_txt, resu_latex) @@ -1325,8 +1298,8 @@ class FiniteRankFreeModuleEndomorphism(FiniteRankFreeModuleMorphism): sage: Id(v) is v True """ - def __init__(self, parent, matrix_rep, bases=None, name=None, - latex_name=None, is_identity=False): + + def __init__(self, parent, matrix_rep, bases=None, name=None, latex_name=None, is_identity=False): r""" TESTS:: @@ -1361,19 +1334,16 @@ def __init__(self, parent, matrix_rep, bases=None, name=None, if bases is None: def_basis = fmodule.default_basis() if def_basis is None: - raise ValueError("the {} has no default ".format(fmodule) + - "basis") + raise ValueError("the {} has no default ".format(fmodule) + "basis") bases = (def_basis, def_basis) else: bases = tuple(bases) # insures bases is a tuple if len(bases) != 2: raise TypeError("the argument bases must contain 2 bases") if bases[0] not in fmodule.bases(): - raise TypeError("{} is not a basis on the {}".format(bases[0], - fmodule)) + raise TypeError("{} is not a basis on the {}".format(bases[0], fmodule)) if bases[1] not in fmodule.bases(): - raise TypeError("{} is not a basis on the {}".format(bases[1], - fmodule)) + raise TypeError("{} is not a basis on the {}".format(bases[1], fmodule)) if not is_identity: # Construction of a generic endomorphism if isinstance(matrix_rep, ConstantFunction): @@ -1385,15 +1355,13 @@ def __init__(self, parent, matrix_rep, bases=None, name=None, if is_identity: # Construction of the identity endomorphism if bases[0] != bases[1]: - raise TypeError("the two bases must coincide for " + - "constructing the identity endomorphism.") + raise TypeError("the two bases must coincide for " + "constructing the identity endomorphism.") matrix_rep = 1 if name is None: name = 'Id' if latex_name is None and name == 'Id': latex_name = r'\mathrm{Id}' - FiniteRankFreeModuleMorphism.__init__(self, parent, matrix_rep, bases, - name, latex_name) + FiniteRankFreeModuleMorphism.__init__(self, parent, matrix_rep, bases, name, latex_name) if is_identity: self._is_identity = True self._repr_type_str = 'Identity' diff --git a/src/sage/tensor/modules/free_module_tensor.py b/src/sage/tensor/modules/free_module_tensor.py index a7e13fff1a5..9a3242b6175 100644 --- a/src/sage/tensor/modules/free_module_tensor.py +++ b/src/sage/tensor/modules/free_module_tensor.py @@ -182,6 +182,7 @@ class being: sage: t(a,b) -2 """ + # ***************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger @@ -264,6 +265,7 @@ class FreeModuleTensor(ModuleElementWithMutability): sage: t.parent() is M.tensor_module(1,1) True """ + _fmodule: FiniteRankFreeModule def __init__( @@ -303,19 +305,18 @@ def __init__( self._fmodule = fmodule self._tensor_type = tuple(tensor_type) self._tensor_rank = self._tensor_type[0] + self._tensor_type[1] - self._is_zero = False # a priori, may be changed below or via - # method __bool__() + self._is_zero = False # a priori, may be changed below or via + # method __bool__() self._name = name if latex_name is None: self._latex_name = self._name else: self._latex_name = latex_name self._components: dict[FreeModuleBasis, Components] = {} # dict. of the sets of components on various - # bases, with the bases as keys (initially empty) + # bases, with the bases as keys (initially empty) # Treatment of symmetry declarations: - self._sym, self._antisym = CompWithSym._canonicalize_sym_antisym( - self._tensor_rank, sym, antisym) + self._sym, self._antisym = CompWithSym._canonicalize_sym_antisym(self._tensor_rank, sym, antisym) # Initialization of derived quantities: FreeModuleTensor._init_derived(self) @@ -376,12 +377,11 @@ def _repr_(self): Type-(2,1) tensor t on the Rank-3 free module M over the Integer Ring """ # Special cases - if self._tensor_type == (0,2) and self._sym == ((0,1),): + if self._tensor_type == (0, 2) and self._sym == ((0, 1),): description = "Symmetric bilinear form " else: # Generic case - description = "Type-({},{}) tensor".format( - self._tensor_type[0], self._tensor_type[1]) + description = "Type-({},{}) tensor".format(self._tensor_type[0], self._tensor_type[1]) if self._name is not None: description += " " + self._name description += " on the {}".format(self._fmodule) @@ -422,7 +422,7 @@ def _init_derived(self): sage: t = M.tensor((2,1), name='t') sage: t._init_derived() """ - pass # no derived quantities + pass # no derived quantities def _del_derived(self): r""" @@ -434,7 +434,7 @@ def _del_derived(self): sage: t = M.tensor((2,1), name='t') sage: t._del_derived() """ - pass # no derived quantities + pass # no derived quantities #### Simple accessors #### @@ -534,7 +534,7 @@ def symmetries(self): a = "antisymmetry: {}".format(self._antisym[0]) else: a = "antisymmetries: {}".format(list(self._antisym)) - print(s+a) + print(s + a) #### End of simple accessors ##### @@ -678,8 +678,8 @@ def display(self, basis=None, format_spec=None): from sage.misc.latex import latex from sage.typeset.unicode_characters import unicode_otimes from .format_utilities import is_atomic, FormattedExpansion - basis, format_spec = self._preparse_display(basis=basis, - format_spec=format_spec) + + basis, format_spec = self._preparse_display(basis=basis, format_spec=format_spec) cobasis = basis.dual_basis() comp = self.comp(basis) terms_txt = [] @@ -717,13 +717,11 @@ def display(self, basis=None, format_spec=None): if is_atomic(coef_txt): terms_txt.append(coef_txt + ' ' + basis_term_txt) else: - terms_txt.append('(' + coef_txt + ') ' + - basis_term_txt) + terms_txt.append('(' + coef_txt + ') ' + basis_term_txt) if is_atomic(coef_latex): terms_latex.append(coef_latex + basis_term_latex) else: - terms_latex.append(r'\left(' + coef_latex + - r'\right)' + basis_term_latex) + terms_latex.append(r'\left(' + coef_latex + r'\right)' + basis_term_latex) if terms_txt == []: expansion_txt = '0' else: @@ -754,10 +752,7 @@ def display(self, basis=None, format_spec=None): disp = display - def display_comp(self, basis=None, format_spec=None, symbol=None, - latex_symbol=None, index_labels=None, - index_latex_labels=None, only_nonzero=True, - only_nonredundant=False): + def display_comp(self, basis=None, format_spec=None, symbol=None, latex_symbol=None, index_labels=None, index_latex_labels=None, only_nonzero=True, only_nonredundant=False): r""" Display the tensor components with respect to a given module basis, one per line. @@ -876,15 +871,8 @@ def display_comp(self, basis=None, format_spec=None, symbol=None, latex_symbol = r'{' + self._latex_name + r'}' else: latex_symbol = 'X' - index_positions = self._tensor_type[0]*'u' + self._tensor_type[1]*'d' - return self.comp(basis).display(symbol, - latex_symbol=latex_symbol, - index_positions=index_positions, - index_labels=index_labels, - index_latex_labels=index_latex_labels, - format_spec=format_spec, - only_nonzero=only_nonzero, - only_nonredundant=only_nonredundant) + index_positions = self._tensor_type[0] * 'u' + self._tensor_type[1] * 'd' + return self.comp(basis).display(symbol, latex_symbol=latex_symbol, index_positions=index_positions, index_labels=index_labels, index_latex_labels=index_latex_labels, format_spec=format_spec, only_nonzero=only_nonzero, only_nonredundant=only_nonredundant) def set_name(self, name: Optional[str] = None, latex_name: Optional[str] = None): r""" @@ -932,8 +920,7 @@ def _new_instance(self): sage: t._new_instance().parent() is t.parent() True """ - return self.__class__(self._fmodule, self._tensor_type, sym=self._sym, - antisym=self._antisym) + return self.__class__(self._fmodule, self._tensor_type, sym=self._sym, antisym=self._antisym) def _new_comp(self, basis): r""" @@ -969,23 +956,14 @@ def _new_comp(self, basis): """ fmodule = self._fmodule # the base free module if not self._sym and not self._antisym: - return Components(fmodule._ring, basis, self._tensor_rank, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter) + return Components(fmodule._ring, basis, self._tensor_rank, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) for isym in self._sym: if len(isym) == self._tensor_rank: - return CompFullySym(fmodule._ring, basis, self._tensor_rank, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter) + return CompFullySym(fmodule._ring, basis, self._tensor_rank, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) for isym in self._antisym: if len(isym) == self._tensor_rank: - return CompFullyAntiSym(fmodule._ring, basis, self._tensor_rank, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter) - return CompWithSym(fmodule._ring, basis, self._tensor_rank, - start_index=fmodule._sindex, - output_formatter=fmodule._output_formatter, - sym=self._sym, antisym=self._antisym) + return CompFullyAntiSym(fmodule._ring, basis, self._tensor_rank, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) + return CompWithSym(fmodule._ring, basis, self._tensor_rank, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter, sym=self._sym, antisym=self._antisym) def components(self, basis=None, from_basis=None) -> Components: r""" @@ -1070,34 +1048,25 @@ class :class:`~sage.tensor.modules.comp.Components` # those in the basis from_basis if from_basis is None: for known_basis in self._components: - if (known_basis, basis) in self._fmodule._basis_changes \ - and (basis, known_basis) in self._fmodule._basis_changes: + if (known_basis, basis) in self._fmodule._basis_changes and (basis, known_basis) in self._fmodule._basis_changes: from_basis = known_basis break if from_basis is None: - raise ValueError("no basis could be found for computing " + - "the components in the {}".format(basis)) + raise ValueError("no basis could be found for computing " + "the components in the {}".format(basis)) elif from_basis not in self._components: - raise ValueError("the tensor components are not known in " + - "the {}".format(from_basis)) + raise ValueError("the tensor components are not known in " + "the {}".format(from_basis)) (n_con, n_cov) = self._tensor_type pp = None if n_cov > 0: if (from_basis, basis) not in fmodule._basis_changes: - raise ValueError("the change-of-basis matrix from the " + - "{} to the {}".format(from_basis, basis) - + " has not been set") - pp = \ - fmodule._basis_changes[(from_basis, basis)].comp(from_basis) + raise ValueError("the change-of-basis matrix from the " + "{} to the {}".format(from_basis, basis) + " has not been set") + pp = fmodule._basis_changes[(from_basis, basis)].comp(from_basis) # pp not used if n_cov = 0 (pure contravariant tensor) ppinv = None if n_con > 0: if (basis, from_basis) not in fmodule._basis_changes: - raise ValueError("the change-of-basis matrix from the " + - "{} to the {}".format(basis, from_basis) + - " has not been set") - ppinv = \ - fmodule._basis_changes[(basis, from_basis)].comp(from_basis) + raise ValueError("the change-of-basis matrix from the " + "{} to the {}".format(basis, from_basis) + " has not been set") + ppinv = fmodule._basis_changes[(basis, from_basis)].comp(from_basis) # ppinv not used if n_con = 0 (pure covariant tensor) old_comp = self._components[from_basis] new_comp = self._new_comp(basis) @@ -1107,9 +1076,9 @@ class :class:`~sage.tensor.modules.comp.Components` if nproc != 1: # Parallel computation - lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)] + lol = lambda lst, sz: [lst[i : i + sz] for i in range(0, len(lst), sz)] ind_list = list(new_comp.non_redundant_index_generator()) - ind_step = max(1, int(len(ind_list)/nproc/2)) + ind_step = max(1, int(len(ind_list) / nproc / 2)) local_list = lol(ind_list, ind_step) # list of input parameters listParalInput = [(old_comp, ppinv, pp, n_con, rank, ii) for ii in local_list] @@ -1123,15 +1092,15 @@ def paral_newcomp(old_comp, ppinv, pp, n_con, rank, local_list_ind): # change-of-basis matrix elements (tensor formula): for ind_old in old_comp.index_generator(): t = old_comp[[ind_old]] - for i in range(n_con): # loop on contravariant indices + for i in range(n_con): # loop on contravariant indices t *= ppinv[[ind[i], ind_old[i]]] - for i in range(n_con,rank): # loop on covariant indices + for i in range(n_con, rank): # loop on covariant indices t *= pp[[ind_old[i], ind[i]]] res += t - partial.append([ind,res]) + partial.append([ind, res]) return partial - for ii,val in paral_newcomp(listParalInput): + for ii, val in paral_newcomp(listParalInput): for jj in val: new_comp[[jj[0]]] = jj[1] @@ -1143,9 +1112,9 @@ def paral_newcomp(old_comp, ppinv, pp, n_con, rank, local_list_ind): res = 0 for ind_old in old_comp.index_generator(): t = old_comp[[ind_old]] - for i in range(n_con): # loop on contravariant indices + for i in range(n_con): # loop on contravariant indices t *= ppinv[[ind_new[i], ind_old[i]]] - for i in range(n_con,rank): # loop on covariant indices + for i in range(n_con, rank): # loop on covariant indices t *= pp[[ind_old[i], ind_new[i]]] res += t new_comp[ind_new] = res @@ -1220,10 +1189,9 @@ class :class:`~sage.tensor.modules.comp.Components`; if such basis = self._fmodule._def_basis if basis not in self._components: if basis not in self._fmodule._known_bases: - raise ValueError("the {} has not been ".format(basis) + - "defined on the {}".format(self._fmodule)) + raise ValueError("the {} has not been ".format(basis) + "defined on the {}".format(self._fmodule)) self._components[basis] = self._new_comp(basis) - self._del_derived() # deletes the derived quantities + self._del_derived() # deletes the derived quantities self.del_other_comp(basis) return self._components[basis] @@ -1295,8 +1263,7 @@ class :class:`~sage.tensor.modules.comp.Components`; if such ValueError: the components of an immutable element cannot be changed """ if self.is_immutable(): - raise ValueError("the components of an immutable element " - "cannot be changed") + raise ValueError("the components of an immutable element " "cannot be changed") self._is_zero = False # a priori return self._set_comp_unsafe(basis) @@ -1357,10 +1324,9 @@ class :class:`~sage.tensor.modules.comp.Components`; basis = self._fmodule._def_basis if basis not in self._components: if basis not in self._fmodule._known_bases: - raise ValueError("the {} has not been ".format(basis) + - "defined on the {}".format(self._fmodule)) + raise ValueError("the {} has not been ".format(basis) + "defined on the {}".format(self._fmodule)) self._components[basis] = self._new_comp(basis) - self._del_derived() # deletes the derived quantities + self._del_derived() # deletes the derived quantities return self._components[basis] def add_comp(self, basis=None): @@ -1430,8 +1396,7 @@ class :class:`~sage.tensor.modules.comp.Components`; ValueError: the components of an immutable element cannot be changed """ if self.is_immutable(): - raise ValueError("the components of an immutable element " - "cannot be changed") + raise ValueError("the components of an immutable element " "cannot be changed") self._is_zero = False # a priori return self._add_comp_unsafe(basis) @@ -1473,10 +1438,8 @@ def del_other_comp(self, basis=None): if basis is None: basis = self._fmodule._def_basis if basis not in self._components: - raise ValueError(f"the components w.r.t. the {basis}" - " have not been defined") - to_be_deleted = [other_basis for other_basis in self._components - if other_basis != basis] + raise ValueError(f"the components w.r.t. the {basis}" " have not been defined") + to_be_deleted = [other_basis for other_basis in self._components if other_basis != basis] for other_basis in to_be_deleted: del self._components[other_basis] @@ -1518,7 +1481,7 @@ def __getitem__(self, args) -> Components: sage: v.__getitem__((e, slice(None))) [3, -5, 2] """ - if isinstance(args, str): # tensor with specified indices + if isinstance(args, str): # tensor with specified indices return TensorWithIndices(self, args).update() if isinstance(args, list): # case of [[...]] syntax if isinstance(args[0], (int, Integer, slice)): @@ -1628,11 +1591,9 @@ def copy_from(self, other): False """ if self.is_immutable(): - raise ValueError("the components of an immutable element " - "cannot be changed") + raise ValueError("the components of an immutable element " "cannot be changed") if other not in self.parent(): - raise TypeError("the original must be an element " - + "of {}".format(self.parent())) + raise TypeError("the original must be an element " + "of {}".format(self.parent())) self._del_derived() self._components.clear() for basis, comp in other._components.items(): @@ -1746,15 +1707,14 @@ def common_basis(self, other): raise TypeError("the argument must be a tensor on a free module") fmodule = self._fmodule if other._fmodule != fmodule: - raise TypeError("the two tensors are not defined on the same " + - "free module") + raise TypeError("the two tensors are not defined on the same " + "free module") def_basis = fmodule._def_basis # 1/ Search for a common basis among the existing components, i.e. # without performing any component transformation. # ------------------------------------------------------------- if def_basis in self._components and def_basis in other._components: - return def_basis # the module's default basis is privileged + return def_basis # the module's default basis is privileged for basis1 in self._components: if basis1 in other._components: return basis1 @@ -1790,14 +1750,12 @@ def common_basis(self, other): # component transformation to get a common basis for sbasis in self._components: for obasis in other._components: - if (sbasis, def_basis) in fmodule._basis_changes and \ - (obasis, def_basis) in fmodule._basis_changes: + if (sbasis, def_basis) in fmodule._basis_changes and (obasis, def_basis) in fmodule._basis_changes: self.comp(def_basis, from_basis=sbasis) other.comp(def_basis, from_basis=obasis) return def_basis for basis in fmodule._known_bases: - if (sbasis, basis) in fmodule._basis_changes and \ - (obasis, basis) in fmodule._basis_changes: + if (sbasis, basis) in fmodule._basis_changes and (obasis, basis) in fmodule._basis_changes: self.comp(basis, from_basis=sbasis) other.comp(basis, from_basis=obasis) return basis @@ -1881,7 +1839,7 @@ def __eq__(self, other): if self._tensor_rank == 0: raise NotImplementedError("scalar comparison not implemented") - if isinstance(other, (int, Integer)): # other should be 0 + if isinstance(other, (int, Integer)): # other should be 0 if other == 0: return self.is_zero() return False @@ -1954,7 +1912,7 @@ def __pos__(self): """ result = self._new_instance() for basis in self._components: - result._components[basis] = + self._components[basis] + result._components[basis] = +self._components[basis] if self._name is not None: result._name = '+' + self._name if self._latex_name is not None: @@ -1984,7 +1942,7 @@ def __neg__(self): """ result = self._new_instance() for basis in self._components: - result._components[basis] = - self._components[basis] + result._components[basis] = -self._components[basis] if self._name is not None: result._name = '-' + self._name if self._latex_name is not None: @@ -2136,9 +2094,9 @@ def _rmul_(self, other): # If other has a name, set the name of the result: try: from .format_utilities import format_mul_txt, format_mul_latex + result_name = format_mul_txt(other._name, '*', self._name) - result_latex = format_mul_latex(other._latex_name, r' \cdot ', - self._latex_name) + result_latex = format_mul_latex(other._latex_name, r' \cdot ', self._latex_name) result.set_name(name=result_name, latex_name=result_latex) except AttributeError: pass @@ -2168,6 +2126,7 @@ def __mul__(self, other): """ from sage.typeset.unicode_characters import unicode_otimes from .format_utilities import format_mul_txt, format_mul_latex + if isinstance(other, FreeModuleTensor): basis = self.common_basis(other) if basis is None: @@ -2177,16 +2136,12 @@ def __mul__(self, other): k1, l1 = self._tensor_type k2, l2 = other._tensor_type if l1 != 0: - comp_result = comp_prov.swap_adjacent_indices(k1, - self._tensor_rank, - self._tensor_rank+k2) + comp_result = comp_prov.swap_adjacent_indices(k1, self._tensor_rank, self._tensor_rank + k2) else: comp_result = comp_prov # no reordering is necessary - result = self._fmodule.tensor_from_comp((k1+k2, l1+l2), - comp_result) + result = self._fmodule.tensor_from_comp((k1 + k2, l1 + l2), comp_result) result._name = format_mul_txt(self._name, unicode_otimes, other._name) - result._latex_name = format_mul_latex(self._latex_name, - r'\otimes ', other._latex_name) + result._latex_name = format_mul_latex(self._latex_name, r'\otimes ', other._latex_name) return result # multiplication by a scalar: @@ -2275,27 +2230,22 @@ def __call__(self, *args) -> Expression: # Consistency checks: p = len(args) if p != self._tensor_rank: - raise TypeError(str(self._tensor_rank) + - " arguments must be provided") + raise TypeError(str(self._tensor_rank) + " arguments must be provided") for i in range(self._tensor_type[0]): if not isinstance(args[i], FreeModuleTensor): - raise TypeError("the argument no. " + str(i+1) + - " must be a linear form") - if args[i]._tensor_type != (0,1): - raise TypeError("the argument no. " + str(i+1) + - " must be a linear form") + raise TypeError("the argument no. " + str(i + 1) + " must be a linear form") + if args[i]._tensor_type != (0, 1): + raise TypeError("the argument no. " + str(i + 1) + " must be a linear form") for i in range(self._tensor_type[0], p): if not isinstance(args[i], FreeModuleTensor): - raise TypeError("the argument no. " + str(i+1) + - " must be a module element") - if args[i]._tensor_type != (1,0): - raise TypeError("the argument no. " + str(i+1) + - " must be a module element") + raise TypeError("the argument no. " + str(i + 1) + " must be a module element") + if args[i]._tensor_type != (1, 0): + raise TypeError("the argument no. " + str(i + 1) + " must be a module element") fmodule = self._fmodule # # Specific case of a linear form acting on a vector (for efficiency): # - if self._tensor_type == (0,1): + if self._tensor_type == (0, 1): vector = args[0] basis = self.common_basis(vector) if basis is None: @@ -2304,16 +2254,14 @@ def __call__(self, *args) -> Expression: vv = vector._components[basis] resu = 0 for i in fmodule.irange(): - resu += omega[[i]]*vv[[i]] + resu += omega[[i]] * vv[[i]] # Name and LaTeX symbol of the output: if hasattr(resu, '_name'): if self._name is not None and vector._name is not None: resu._name = self._name + "(" + vector._name + ")" if hasattr(resu, '_latex_name'): - if self._latex_name is not None and \ - vector._latex_name is not None: - resu._latex_name = self._latex_name + r"\left(" + \ - vector._latex_name + r"\right)" + if self._latex_name is not None and vector._latex_name is not None: + resu._latex_name = self._latex_name + r"\left(" + vector._latex_name + r"\right)" return resu # # Generic case @@ -2336,20 +2284,20 @@ def __call__(self, *args) -> Expression: if bas not in arg._components: basis = None break - if basis is not None: # common basis found ! + if basis is not None: # common basis found ! break if basis is None: # A last attempt to find a common basis, possibly via a # change-of-components transformation for arg in args: - self.common_basis(arg) # to trigger some change of components + self.common_basis(arg) # to trigger some change of components for bas in self._components: basis = bas for arg in args: if bas not in arg._components: basis = None break - if basis is not None: # common basis found ! + if basis is not None: # common basis found ! break if basis is None: raise ValueError("no common basis for the components") @@ -2366,15 +2314,15 @@ def __call__(self, *args) -> Expression: res_name = None if self._name is not None: res_name = self._name + "(" - for i in range(p-1): + for i in range(p - 1): if args[i]._name is not None: res_name += args[i]._name + "," else: res_name = None break if res_name is not None: - if args[p-1]._name is not None: - res_name += args[p-1]._name + ")" + if args[p - 1]._name is not None: + res_name += args[p - 1]._name + ")" else: res_name = None res._name = res_name @@ -2383,15 +2331,15 @@ def __call__(self, *args) -> Expression: res_latex = None if self._latex_name is not None: res_latex = self._latex_name + r"\left(" - for i in range(p-1): + for i in range(p - 1): if args[i]._latex_name is not None: res_latex += args[i]._latex_name + "," else: res_latex = None break if res_latex is not None: - if args[p-1]._latex_name is not None: - res_latex += args[p-1]._latex_name + r"\right)" + if args[p - 1]._latex_name is not None: + res_latex += args[p - 1]._latex_name + r"\right)" else: res_latex = None res._latex_name = res_latex @@ -2401,9 +2349,7 @@ def trace( self, pos1: int = 0, pos2: int = 1, - using: Optional[ - Union[PseudoRiemannianMetric, SymplecticForm, PoissonTensorField] - ] = None, + using: Optional[Union[PseudoRiemannianMetric, SymplecticForm, PoissonTensorField]] = None, ): r""" Trace (contraction) on two slots of the tensor. @@ -2533,30 +2479,25 @@ def trace( """ if using is not None: if self.tensor_type() != (0, 2): - raise ValueError( - "trace with respect to a non-degenerate form is only defined for type-(0,2) tensor" - ) + raise ValueError("trace with respect to a non-degenerate form is only defined for type-(0,2) tensor") return self.up(using, 1).trace() # The indices at pos1 and pos2 must be of different types: k_con = self._tensor_type[0] l_cov = self._tensor_type[1] if pos1 < k_con and pos2 < k_con: - raise IndexError("contraction on two contravariant indices is " + - "not allowed") + raise IndexError("contraction on two contravariant indices is " + "not allowed") if pos1 >= k_con and pos2 >= k_con: - raise IndexError("contraction on two covariant indices is " + - "not allowed") + raise IndexError("contraction on two covariant indices is " + "not allowed") # Frame selection for the computation: if self._fmodule._def_basis in self._components: basis = self._fmodule._def_basis - else: # a basis is picked arbitrarily: + else: # a basis is picked arbitrarily: basis = self.pick_a_basis() resu_comp = self._components[basis].trace(pos1, pos2) if self._tensor_rank == 2: # result is a scalar return resu_comp - return self._fmodule.tensor_from_comp((k_con-1, l_cov-1), - resu_comp) + return self._fmodule.tensor_from_comp((k_con - 1, l_cov - 1), resu_comp) def contract(self, *args): r""" @@ -2764,11 +2705,11 @@ def contract(self, *args): pos1 = (self._tensor_rank - 1,) else: pos1 = args[:it] - if it == nargs-1: + if it == nargs - 1: pos2 = (0,) else: - pos2 = args[it+1:] - ncontr = len(pos1) # number of contractions + pos2 = args[it + 1 :] + ncontr = len(pos1) # number of contractions if len(pos2) != ncontr: raise TypeError("different number of indices for the contraction") k1, l1 = self._tensor_type @@ -2777,11 +2718,9 @@ def contract(self, *args): p1 = pos1[i] p2 = pos2[i] if p1 < k1 and p2 < k2: - raise TypeError("contraction on two contravariant indices " + - "not permitted") + raise TypeError("contraction on two contravariant indices " + "not permitted") if p1 >= k1 and p2 >= k2: - raise TypeError("contraction on two covariant indices " + - "not permitted") + raise TypeError("contraction on two covariant indices " + "not permitted") # # Contraction at the component level # @@ -2790,19 +2729,19 @@ def contract(self, *args): raise ValueError("no common basis for the contraction") args = pos1 + (other._components[basis],) + pos2 cmp_res = self._components[basis].contract(*args) - if self._tensor_rank + other._tensor_rank - 2*ncontr == 0: + if self._tensor_rank + other._tensor_rank - 2 * ncontr == 0: # Case of scalar output: return cmp_res # # Reordering of the indices to have all contravariant indices first: # nb_cov_s = 0 # Number of covariant indices of self not involved in the - # contraction + # contraction for pos in range(k1, k1 + l1): if pos not in pos1: nb_cov_s += 1 nb_con_o = 0 # Number of contravariant indices of other not involved - # in the contraction + # in the contraction for pos in range(k2): if pos not in pos2: nb_con_o += 1 @@ -2812,7 +2751,7 @@ def contract(self, *args): p1 = p2 - nb_cov_s p3 = p2 + nb_con_o cmp_res = cmp_res.swap_adjacent_indices(p1, p2, p3) - type_res = (k1+k2-ncontr, l1+l2-ncontr) + type_res = (k1 + k2 - ncontr, l1 + l2 - ncontr) return self._fmodule.tensor_from_comp(type_res, cmp_res) def symmetrize(self, *pos, **kwargs): @@ -3020,24 +2959,16 @@ def symmetrize(self, *pos, **kwargs): if not pos: pos = range(self._tensor_rank) # check whether the symmetrization is possible: - pos_cov = self._tensor_type[0] # first covariant position + pos_cov = self._tensor_type[0] # first covariant position pos0 = pos[0] if pos0 < pos_cov: # pos0 is a contravariant position - for k in range(1,len(pos)): + for k in range(1, len(pos)): if pos[k] >= pos_cov: - raise TypeError( - str(pos[0]) + " is a contravariant position, while " + - str(pos[k]) + " is a covariant position; \n" - "symmetrization is meaningful only on tensor " + - "arguments of the same type") + raise TypeError(str(pos[0]) + " is a contravariant position, while " + str(pos[k]) + " is a covariant position; \n" "symmetrization is meaningful only on tensor " + "arguments of the same type") else: # pos0 is a covariant position - for k in range(1,len(pos)): + for k in range(1, len(pos)): if pos[k] < pos_cov: - raise TypeError( - str(pos[0]) + " is a covariant position, while " + - str(pos[k]) + " is a contravariant position; \n" - "symmetrization is meaningful only on tensor " + - "arguments of the same type") + raise TypeError(str(pos[0]) + " is a covariant position, while " + str(pos[k]) + " is a contravariant position; \n" "symmetrization is meaningful only on tensor " + "arguments of the same type") if 'basis' in kwargs: basis = kwargs['basis'] else: @@ -3259,24 +3190,16 @@ def antisymmetrize(self, *pos, **kwargs): if not pos: pos = range(self._tensor_rank) # check whether the antisymmetrization is possible: - pos_cov = self._tensor_type[0] # first covariant position + pos_cov = self._tensor_type[0] # first covariant position pos0 = pos[0] if pos0 < pos_cov: # pos0 is a contravariant position - for k in range(1,len(pos)): + for k in range(1, len(pos)): if pos[k] >= pos_cov: - raise TypeError( - str(pos[0]) + " is a contravariant position, while " + - str(pos[k]) + " is a covariant position; \n" - "antisymmetrization is meaningful only on tensor " + - "arguments of the same type") + raise TypeError(str(pos[0]) + " is a contravariant position, while " + str(pos[k]) + " is a covariant position; \n" "antisymmetrization is meaningful only on tensor " + "arguments of the same type") else: # pos0 is a covariant position - for k in range(1,len(pos)): + for k in range(1, len(pos)): if pos[k] < pos_cov: - raise TypeError( - str(pos[0]) + " is a covariant position, while " + - str(pos[k]) + " is a contravariant position; \n" - "antisymmetrization is meaningful only on tensor " + - "arguments of the same type") + raise TypeError(str(pos[0]) + " is a covariant position, while " + str(pos[k]) + " is a contravariant position; \n" "antisymmetrization is meaningful only on tensor " + "arguments of the same type") if 'basis' in kwargs: basis = kwargs['basis'] else: diff --git a/src/sage/tensor/modules/reflexive_module.py b/src/sage/tensor/modules/reflexive_module.py index 073f76e4659..6fe3e7d3b9c 100644 --- a/src/sage/tensor/modules/reflexive_module.py +++ b/src/sage/tensor/modules/reflexive_module.py @@ -228,8 +228,7 @@ def map_isym(isym): running_indices += vector(tensor_type) - result = base_module.tensor_module(*result_tensor_type, - sym=result_sym, antisym=result_antisym) + result = base_module.tensor_module(*result_tensor_type, sym=result_sym, antisym=result_antisym) result._index_maps = tuple(index_maps) return result @@ -375,7 +374,7 @@ def tensor_factors(self): Dual of the Rank-3 free module M over the Integer Ring] """ tensor_type = self.tensor_type() - if tensor_type == (0,1): # case of the dual + if tensor_type == (0, 1): # case of the dual raise NotImplementedError bmodule = self.base_module() factors = [bmodule] * tensor_type[0] diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index bf0e09977dd..8630eac839d 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -47,6 +47,7 @@ - Chap. 21 (Exer. 4) of R. Godement: *Algebra* [God1968]_ - Chap. 16 of S. Lang: *Algebra* [Lan2002]_ """ + # **************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger @@ -63,8 +64,7 @@ from sage.tensor.modules.free_module_tensor import FreeModuleTensor from sage.tensor.modules.alternating_contr_tensor import AlternatingContrTensor from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm -from sage.tensor.modules.free_module_morphism import \ - FiniteRankFreeModuleMorphism +from sage.tensor.modules.free_module_morphism import FiniteRankFreeModuleMorphism from sage.tensor.modules.free_module_automorphism import FreeModuleAutomorphism from sage.tensor.modules.reflexive_module import ReflexiveModule_tensor @@ -350,7 +350,7 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, category=No self._tensor_type = tuple(tensor_type) ring = fmodule._ring rank = pow(fmodule._rank, tensor_type[0] + tensor_type[1]) - if self._tensor_type == (0,1): # case of the dual + if self._tensor_type == (0, 1): # case of the dual category = Modules(ring).FiniteDimensional().or_subcategory(category) if name is None and fmodule._name is not None: name = fmodule._name + '*' @@ -359,18 +359,15 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, category=No else: category = Modules(ring).FiniteDimensional().TensorProducts().or_subcategory(category) if name is None and fmodule._name is not None: - name = 'T^' + str(self._tensor_type) + '(' + fmodule._name + \ - ')' + name = 'T^' + str(self._tensor_type) + '(' + fmodule._name + ')' if latex_name is None and fmodule._latex_name is not None: - latex_name = r'T^{' + str(self._tensor_type) + r'}\left(' + \ - fmodule._latex_name + r'\right)' + latex_name = r'T^{' + str(self._tensor_type) + r'}\left(' + fmodule._latex_name + r'\right)' super().__init__(fmodule._ring, rank, name=name, latex_name=latex_name, category=category) fmodule._all_modules.add(self) #### Parent Methods - def _element_constructor_(self, comp=[], basis=None, name=None, - latex_name=None, sym=None, antisym=None): + def _element_constructor_(self, comp=[], basis=None, name=None, latex_name=None, sym=None, antisym=None): r""" Construct a tensor. @@ -394,89 +391,63 @@ def _element_constructor_(self, comp=[], basis=None, name=None, True """ from sage.rings.integer import Integer + if isinstance(comp, (int, Integer)) and comp == 0: return self.zero() if isinstance(comp, FiniteRankFreeModuleMorphism): # coercion of an endomorphism to a type-(1,1) tensor: endo = comp # for readability - if self._tensor_type == (1,1) and endo.is_endomorphism() and \ - self._fmodule is endo.domain(): - resu = self.element_class(self._fmodule, (1,1), - name=endo._name, - latex_name=endo._latex_name, - parent=self) + if self._tensor_type == (1, 1) and endo.is_endomorphism() and self._fmodule is endo.domain(): + resu = self.element_class(self._fmodule, (1, 1), name=endo._name, latex_name=endo._latex_name, parent=self) for basis, mat in endo._matrices.items(): resu.add_comp(basis[0])[:] = mat else: - raise TypeError("cannot coerce the {}".format(endo) + - " to an element of {}".format(self)) + raise TypeError("cannot coerce the {}".format(endo) + " to an element of {}".format(self)) elif isinstance(comp, AlternatingContrTensor): # coercion of an alternating contravariant tensor of degree # p to a type-(p,0) tensor: - tensor = comp # for readability + tensor = comp # for readability p = tensor.degree() - if self._tensor_type != (p,0) or \ - self._fmodule != tensor.base_module(): - raise TypeError("cannot coerce the {}".format(tensor) + - " to an element of {}".format(self)) + if self._tensor_type != (p, 0) or self._fmodule != tensor.base_module(): + raise TypeError("cannot coerce the {}".format(tensor) + " to an element of {}".format(self)) if p == 1: asym = None else: asym = range(p) - resu = self.element_class(self._fmodule, (p,0), - name=tensor._name, - latex_name=tensor._latex_name, - antisym=asym, - parent=self) + resu = self.element_class(self._fmodule, (p, 0), name=tensor._name, latex_name=tensor._latex_name, antisym=asym, parent=self) for basis, comp in tensor._components.items(): resu._components[basis] = comp.copy() elif isinstance(comp, FreeModuleAltForm): # coercion of an alternating form to a type-(0,p) tensor: - form = comp # for readability + form = comp # for readability p = form.degree() - if self._tensor_type != (0,p) or \ - self._fmodule != form.base_module(): - raise TypeError("cannot coerce the {}".format(form) + - " to an element of {}".format(self)) + if self._tensor_type != (0, p) or self._fmodule != form.base_module(): + raise TypeError("cannot coerce the {}".format(form) + " to an element of {}".format(self)) if p == 1: asym = None else: asym = range(p) - resu = self.element_class(self._fmodule, (0,p), name=form._name, - latex_name=form._latex_name, - antisym=asym, - parent=self) + resu = self.element_class(self._fmodule, (0, p), name=form._name, latex_name=form._latex_name, antisym=asym, parent=self) for basis, comp in form._components.items(): resu._components[basis] = comp.copy() elif isinstance(comp, FreeModuleAutomorphism): # coercion of an automorphism to a type-(1,1) tensor: - autom = comp # for readability - if self._tensor_type != (1,1) or \ - self._fmodule != autom.base_module(): - raise TypeError("cannot coerce the {}".format(autom) + - " to an element of {}".format(self)) - resu = self.element_class(self._fmodule, (1,1), name=autom._name, - latex_name=autom._latex_name, - parent=self) + autom = comp # for readability + if self._tensor_type != (1, 1) or self._fmodule != autom.base_module(): + raise TypeError("cannot coerce the {}".format(autom) + " to an element of {}".format(self)) + resu = self.element_class(self._fmodule, (1, 1), name=autom._name, latex_name=autom._latex_name, parent=self) for basis, comp in autom._components.items(): resu._components[basis] = comp.copy() elif isinstance(comp, FreeModuleTensor): tensor = comp - if self._tensor_type != tensor._tensor_type or \ - self._fmodule != tensor.base_module(): - raise TypeError("cannot coerce the {}".format(tensor) + - " to an element of {}".format(self)) - resu = self.element_class(self._fmodule, self._tensor_type, - name=name, latex_name=latex_name, - sym=sym, antisym=antisym, - parent=self) + if self._tensor_type != tensor._tensor_type or self._fmodule != tensor.base_module(): + raise TypeError("cannot coerce the {}".format(tensor) + " to an element of {}".format(self)) + resu = self.element_class(self._fmodule, self._tensor_type, name=name, latex_name=latex_name, sym=sym, antisym=antisym, parent=self) for basis, comp in tensor._components.items(): resu._components[basis] = comp.copy() else: # Standard construction: - resu = self.element_class(self._fmodule, self._tensor_type, - name=name, latex_name=latex_name, - sym=sym, antisym=antisym, parent=self) + resu = self.element_class(self._fmodule, self._tensor_type, name=name, latex_name=latex_name, sym=sym, antisym=antisym, parent=self) if comp: resu.set_comp(basis)[:] = comp return resu @@ -504,7 +475,7 @@ def zero(self): for basis in self._fmodule._known_bases: resu._add_comp_unsafe(basis) # (since new components are initialized to zero) - resu._is_zero = True # This element is certainly zero + resu._is_zero = True # This element is certainly zero resu.set_immutable() return resu @@ -599,28 +570,24 @@ def _coerce_map_from_(self, other): True """ from .free_module_homset import FreeModuleHomset - from .ext_pow_free_module import (ExtPowerFreeModule, - ExtPowerDualFreeModule) + from .ext_pow_free_module import ExtPowerFreeModule, ExtPowerDualFreeModule from .free_module_linear_group import FreeModuleLinearGroup + if isinstance(other, FreeModuleHomset): # Coercion of an endomorphism to a type-(1,1) tensor: - if self._tensor_type == (1,1): - return other.is_endomorphism_set() and \ - self._fmodule is other.domain() + if self._tensor_type == (1, 1): + return other.is_endomorphism_set() and self._fmodule is other.domain() return False if isinstance(other, ExtPowerFreeModule): # Coercion of an alternating contravariant tensor to a # type-(p,0) tensor: - return self._tensor_type == (other.degree(), 0) and \ - self._fmodule is other.base_module() + return self._tensor_type == (other.degree(), 0) and self._fmodule is other.base_module() if isinstance(other, ExtPowerDualFreeModule): # Coercion of an alternating form to a type-(0,p) tensor: - return self._tensor_type == (0, other.degree()) and \ - self._fmodule is other.base_module() + return self._tensor_type == (0, other.degree()) and self._fmodule is other.base_module() if isinstance(other, FreeModuleLinearGroup): # Coercion of an automorphism to a type-(1,1) tensor: - return self._tensor_type == (1,1) and \ - self._fmodule is other.base_module() + return self._tensor_type == (1, 1) and self._fmodule is other.base_module() try: if other.is_submodule(self): return True @@ -641,8 +608,7 @@ def _repr_(self): Free module of type-(1,1) tensors on the 2-dimensional vector space M over the Rational Field """ - description = "Free module of type-({},{}) tensors on the {}".format( - self._tensor_type[0], self._tensor_type[1], self._fmodule) + description = "Free module of type-({},{}) tensors on the {}".format(self._tensor_type[0], self._tensor_type[1], self._fmodule) return description def base_module(self): @@ -686,9 +652,7 @@ def tensor_type(self): return self._tensor_type @cached_method - def basis(self, symbol, latex_symbol=None, from_family=None, - indices=None, latex_indices=None, symbol_dual=None, - latex_symbol_dual=None): + def basis(self, symbol, latex_symbol=None, from_family=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): r""" Return the standard basis of ``self`` corresponding to a basis of the base module. @@ -752,9 +716,7 @@ def basis(self, symbol, latex_symbol=None, from_family=None, f_0⊗f_1 + f_1⊗f_0 f_1⊗f_1 """ - return TensorFreeSubmoduleBasis_sym(self, symbol=symbol, latex_symbol=latex_symbol, - indices=indices, latex_indices=latex_indices, - symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) + return TensorFreeSubmoduleBasis_sym(self, symbol=symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) @cached_method def _basis_sym(self): diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index b23e22ca04e..a0a8ee1867d 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -96,8 +96,8 @@ class TensorFreeSubmodule_sym(TensorFreeModule): sage: latex(T) T^{\{2,3\}}(M) \otimes T^{\{6,7\}}(M^*) \otimes \mathrm{Sym}^{\{0,1\}}(M) \otimes \mathrm{ASym}^{\{4,5\}}(M^*) """ - def __init__(self, fmodule, tensor_type, name=None, latex_name=None, - sym=None, antisym=None, *, category=None, ambient=None): + + def __init__(self, fmodule, tensor_type, name=None, latex_name=None, sym=None, antisym=None, *, category=None, ambient=None): r""" TESTS:: @@ -129,10 +129,8 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None, antisym = basis_sym._antisym else: sym = antisym = [] - nosym_0 = [i for i in range(tensor_type[0]) - if not any(i in s for s in sym) and not any(i in s for s in antisym)] - nosym_1 = [i for i in range(tensor_type[0], tensor_type[0] + tensor_type[1]) - if not any(i in s for s in sym) and not any(i in s for s in antisym)] + nosym_0 = [i for i in range(tensor_type[0]) if not any(i in s for s in sym) and not any(i in s for s in antisym)] + nosym_1 = [i for i in range(tensor_type[0], tensor_type[0] + tensor_type[1]) if not any(i in s for s in sym) and not any(i in s for s in antisym)] nosym = [s for s in [nosym_0, nosym_1] if s] def power_name(op, s, latex=False): @@ -160,20 +158,12 @@ def power_name(op, s, latex=False): return op + '^' + superscript + '(' + base._latex_name + ')' return op + '^' + superscript + '(' + base._name + ')' - name = unicode_otimes.join(itertools.chain( - (power_name('T', s, latex=False) for s in nosym), - (power_name('Sym', s, latex=False) for s in sym), - (power_name('ASym', s, latex=False) for s in antisym))) - latex_name = r' \otimes '.join(itertools.chain( - (power_name('T', s, latex=True) for s in nosym), - (power_name(r'\mathrm{Sym}', s, latex=True) for s in sym), - (power_name(r'\mathrm{ASym}', s, latex=True) for s in antisym))) + name = unicode_otimes.join(itertools.chain((power_name('T', s, latex=False) for s in nosym), (power_name('Sym', s, latex=False) for s in sym), (power_name('ASym', s, latex=False) for s in antisym))) + latex_name = r' \otimes '.join(itertools.chain((power_name('T', s, latex=True) for s in nosym), (power_name(r'\mathrm{Sym}', s, latex=True) for s in sym), (power_name(r'\mathrm{ASym}', s, latex=True) for s in antisym))) category = fmodule.category().TensorProducts().FiniteDimensional().Subobjects().or_subcategory(category) # Skip TensorFreeModule.__init__ - FiniteRankFreeModule_abstract.__init__(self, fmodule._ring, rank, name=name, - latex_name=latex_name, - category=category, ambient=ambient) + FiniteRankFreeModule_abstract.__init__(self, fmodule._ring, rank, name=name, latex_name=latex_name, category=category, ambient=ambient) def construction(self): # TODO: Define the symmetry group and its action (https://github.com/sagemath/sage/issues/34495), @@ -226,8 +216,7 @@ def _repr_(self): on the Rank-3 free module M over the Integer Ring """ prefix, suffix = self._basis_sym()._repr_symmetry() - return "Free module of {}type-({},{}) tensors on the {}{}".format( - prefix.lower(), self._tensor_type[0], self._tensor_type[1], self._fmodule, suffix) + return "Free module of {}type-({},{}) tensors on the {}{}".format(prefix.lower(), self._tensor_type[0], self._tensor_type[1], self._fmodule, suffix) def _is_symmetry_coarsening_of(self, coarser_comp, finer_comp): r""" @@ -307,8 +296,7 @@ def is_coarsening_of(self_sym_list, other_sym_list): return False return is_coarsening_of(coarser_antisym, finer_antisym) - def _element_constructor_(self, comp=[], basis=None, name=None, - latex_name=None, sym=None, antisym=None): + def _element_constructor_(self, comp=[], basis=None, name=None, latex_name=None, sym=None, antisym=None): r""" TESTS:: @@ -332,18 +320,14 @@ def _element_constructor_(self, comp=[], basis=None, name=None, # Refuse to create a tensor with finer symmetries # than those defining the subspace if not self._is_symmetry_coarsening_of((sym, antisym), self._basis_sym()): - raise ValueError(f"cannot create a tensor with symmetries {sym=}, {antisym=} " - f"as an element of {self}") + raise ValueError(f"cannot create a tensor with symmetries {sym=}, {antisym=} " f"as an element of {self}") if sym is None: sym = self._basis_sym()._sym if antisym is None: antisym = self._basis_sym()._antisym - resu = super()._element_constructor_(comp=comp, - basis=basis, name=name, - latex_name=latex_name, - sym=sym, antisym=antisym) + resu = super()._element_constructor_(comp=comp, basis=basis, name=name, latex_name=latex_name, sym=sym, antisym=antisym) if not resu._components: # fast path for zero tensor return resu diff --git a/src/sage/tensor/modules/tensor_free_submodule_basis.py b/src/sage/tensor/modules/tensor_free_submodule_basis.py index 8030511ecf5..e113b7ced04 100644 --- a/src/sage/tensor/modules/tensor_free_submodule_basis.py +++ b/src/sage/tensor/modules/tensor_free_submodule_basis.py @@ -39,8 +39,7 @@ class TensorFreeSubmoduleBasis_sym(Basis_abstract): e_2⊗e^2 """ - def __init__(self, tensor_module, symbol, latex_symbol=None, indices=None, - latex_indices=None, symbol_dual=None, latex_symbol_dual=None): + def __init__(self, tensor_module, symbol, latex_symbol=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): r""" TESTS:: @@ -51,8 +50,7 @@ def __init__(self, tensor_module, symbol, latex_symbol=None, indices=None, sage: TestSuite(e_T11).run() """ base_module = tensor_module.base_module() - base_module_basis = base_module.basis(symbol, latex_symbol, indices, - latex_indices, symbol_dual, latex_symbol_dual) + base_module_basis = base_module.basis(symbol, latex_symbol, indices, latex_indices, symbol_dual, latex_symbol_dual) super().__init__(tensor_module, symbol, latex_symbol, indices, latex_indices) self._base_module_basis = base_module_basis self._comp = tensor_module._basis_sym() diff --git a/src/sage/tensor/modules/tensor_with_indices.py b/src/sage/tensor/modules/tensor_with_indices.py index a7def8cb3a8..07e70ceb0a0 100644 --- a/src/sage/tensor/modules/tensor_with_indices.py +++ b/src/sage/tensor/modules/tensor_with_indices.py @@ -250,8 +250,7 @@ class TensorWithIndices(SageObject): """ @staticmethod - def _parse_indices(indices, tensor_type=None, allow_contraction=True, - allow_symmetries=True): + def _parse_indices(indices, tensor_type=None, allow_contraction=True, allow_symmetries=True): r""" Parse index notation for tensors, enforces conventions and return indices. @@ -337,8 +336,7 @@ def _parse_indices(indices, tensor_type=None, allow_contraction=True, allowed_pattern = r"(\(" + _alph_or_dot_pattern + r"{2,}\)|\[" + _alph_or_dot_pattern + r"{2,}\]|" + _alph_or_dot_pattern + r"+)*" con_then_cov = r"^(\^|)" + allowed_pattern + r"(\_" + allowed_pattern + r"|)$" cov_then_con = r"^\_" + allowed_pattern + r"(\^" + allowed_pattern + r"|)$" - if (re.match(con_then_cov, indices) is None - and re.match(cov_then_con, indices) is None): + if re.match(con_then_cov, indices) is None and re.match(cov_then_con, indices) is None: raise ValueError("index conventions not satisfied") elif re.match(con_then_cov, indices): try: @@ -356,17 +354,13 @@ def _parse_indices(indices, tensor_type=None, allow_contraction=True, for ind in con: if ind != '.' and ind in cov: raise IndexError("no contraction allowed") - con_without_sym = (con.replace("(", "").replace(")", "").replace("[", "").replace("]", "")) - cov_without_sym = (cov.replace("(", "").replace(")", "").replace("[", "").replace("]", "")) + con_without_sym = con.replace("(", "").replace(")", "").replace("[", "").replace("]", "") + cov_without_sym = cov.replace("(", "").replace(")", "").replace("[", "").replace("]", "") if allow_symmetries: - if len(con_without_sym) != len(set(con_without_sym)) \ - + max(con_without_sym.count(".")-1, 0): - raise ValueError("index conventions not satisfied: " - "repeated indices of same type") - if len(cov_without_sym) != len(set(cov_without_sym)) \ - + max(cov_without_sym.count(".")-1, 0): - raise ValueError("index conventions not satisfied: " - "repeated indices of same type") + if len(con_without_sym) != len(set(con_without_sym)) + max(con_without_sym.count(".") - 1, 0): + raise ValueError("index conventions not satisfied: " "repeated indices of same type") + if len(cov_without_sym) != len(set(cov_without_sym)) + max(cov_without_sym.count(".") - 1, 0): + raise ValueError("index conventions not satisfied: " "repeated indices of same type") else: if re.search(r"[()\[\]]", con) is not None: raise IndexError("no symmetry allowed") @@ -375,11 +369,9 @@ def _parse_indices(indices, tensor_type=None, allow_contraction=True, if tensor_type is not None: # Check number of (co/contra)variant indices if len(con_without_sym) != tensor_type[0]: - raise IndexError("number of contravariant indices not compatible " - "with the tensor type") + raise IndexError("number of contravariant indices not compatible " "with the tensor type") if len(cov_without_sym) != tensor_type[1]: - raise IndexError("number of covavariant indices not compatible " - "with the tensor type") + raise IndexError("number of covavariant indices not compatible " "with the tensor type") return con, cov def __init__(self, tensor, indices): @@ -405,11 +397,11 @@ def __init__(self, tensor, indices): sage: ti = TensorWithIndices(t, 'ab_c') sage: TestSuite(ti).run() """ - self._tensor = tensor # may be changed below - self._changed = False # indicates whether self contains an altered - # version of the original tensor (True if - # symmetries or contractions are indicated in the - # indices) + self._tensor = tensor # may be changed below + self._changed = False # indicates whether self contains an altered + # version of the original tensor (True if + # symmetries or contractions are indicated in the + # indices) # Check whether the usual convention for indices, symmetries and # contractions are respected. This includes restrictions on the @@ -419,48 +411,33 @@ def __init__(self, tensor, indices): # Latex notations '{' and '}' are totally ignored. # "^{ijkl}_{ib(cd)}" - con, cov = self._parse_indices( - indices, - tensor_type=self._tensor.tensor_type() - ) + con, cov = self._parse_indices(indices, tensor_type=self._tensor.tensor_type()) # Apply (anti)symmetrizations on contravariant indices first_sym_regex = r"(\(|\[)" + _alph_or_dot_pattern + r"*[)\]]" while re.search(first_sym_regex, con): first_sym = re.search(first_sym_regex, con) sym1 = first_sym.span()[0] - sym2 = first_sym.span()[1]-1 + sym2 = first_sym.span()[1] - 1 if first_sym.groups()[0] == "(": - self._tensor = self._tensor.symmetrize(*range( - sym1, - sym2-1 - )) + self._tensor = self._tensor.symmetrize(*range(sym1, sym2 - 1)) else: - self._tensor = self._tensor.antisymmetrize(*range( - sym1, - sym2-1 - )) + self._tensor = self._tensor.antisymmetrize(*range(sym1, sym2 - 1)) self._changed = True # self does no longer contain the original tensor - con = con[:sym1] + con[sym1+1:sym2] + con[sym2+1:] + con = con[:sym1] + con[sym1 + 1 : sym2] + con[sym2 + 1 :] self._con = con # Apply (anti)symmetrizations on covariant indices while re.search(first_sym_regex, cov): first_sym = re.search(first_sym_regex, cov) sym1 = first_sym.span()[0] - sym2 = first_sym.span()[1]-1 + sym2 = first_sym.span()[1] - 1 if first_sym.groups()[0] == "(": - self._tensor = self._tensor.symmetrize(*range( - self._tensor._tensor_type[0] + sym1, - self._tensor._tensor_type[0] + sym2-1 - )) + self._tensor = self._tensor.symmetrize(*range(self._tensor._tensor_type[0] + sym1, self._tensor._tensor_type[0] + sym2 - 1)) else: - self._tensor = self._tensor.antisymmetrize(*range( - self._tensor._tensor_type[0] + sym1, - self._tensor._tensor_type[0] + sym2-1 - )) - self._changed = True # self does no longer contain the original tensor - cov = cov[:sym1] + cov[sym1+1:sym2] + cov[sym2+1:] + self._tensor = self._tensor.antisymmetrize(*range(self._tensor._tensor_type[0] + sym1, self._tensor._tensor_type[0] + sym2 - 1)) + self._changed = True # self does no longer contain the original tensor + cov = cov[:sym1] + cov[sym1 + 1 : sym2] + cov[sym2 + 1 :] self._cov = cov # Treatment of possible self-contractions: @@ -476,12 +453,12 @@ def __init__(self, tensor, indices): self._tensor = self._tensor.trace(pos1, pos2) for contraction_pair in contraction_pair_list: if contraction_pair[0] > pos1: - contraction_pair[0] = contraction_pair[0]-1 + contraction_pair[0] = contraction_pair[0] - 1 if contraction_pair[1] > pos2: - contraction_pair[1] = contraction_pair[1]-1 - contraction_pair[1] = contraction_pair[1]-1 - self._changed = True # self does no longer contain the original - # tensor + contraction_pair[1] = contraction_pair[1] - 1 + contraction_pair[1] = contraction_pair[1] - 1 + self._changed = True # self does no longer contain the original + # tensor ind = self._con[pos1] self._con = self._con.replace(ind, '') self._cov = self._cov.replace(ind, '') @@ -564,9 +541,7 @@ def __eq__(self, other): """ if not isinstance(other, TensorWithIndices): return False - return (self._tensor == other._tensor - and self._con == other._con - and self._cov == other._cov) + return self._tensor == other._tensor and self._con == other._con and self._cov == other._cov def __ne__(self, other): r""" @@ -618,8 +593,7 @@ def __mul__(self, other): [3, -6, 9] """ if not isinstance(other, TensorWithIndices): - raise TypeError("the second item of * must be a tensor with " + - "specified indices") + raise TypeError("the second item of * must be a tensor with " + "specified indices") contraction_pairs = [] for ind in self._con: if ind != '.': @@ -628,8 +602,7 @@ def __mul__(self, other): pos2 = other._tensor._tensor_type[0] + other._cov.index(ind) contraction_pairs.append((pos1, pos2)) if ind in other._con: - raise IndexError(f"the index {ind} appears twice " - + "in a contravariant position") + raise IndexError(f"the index {ind} appears twice " + "in a contravariant position") for ind in self._cov: if ind != '.': if ind in other._con: @@ -637,8 +610,7 @@ def __mul__(self, other): pos2 = other._con.index(ind) contraction_pairs.append((pos1, pos2)) if ind in other._cov: - raise IndexError(f"the index {ind} appears twice " - + "in a covariant position") + raise IndexError(f"the index {ind} appears twice " + "in a covariant position") if not contraction_pairs: # No contraction is performed: the tensor product is returned return self._tensor * other._tensor @@ -665,8 +637,7 @@ def __rmul__(self, other): sage: s._tensor == 3*a True """ - return TensorWithIndices(other*self._tensor, - self._con + '_' + self._cov) + return TensorWithIndices(other * self._tensor, self._con + '_' + self._cov) def __add__(self, other): r""" @@ -716,11 +687,9 @@ def __add__(self, other): permutation[other_index] = self._con.index(other._con[other_index]) for other_index in range(other._tensor.tensor_type()[1]): if other._cov[other_index] == self._cov[other_index]: - permutation[other._tensor.tensor_type()[0] + other_index]\ - = other._tensor.tensor_type()[0] + other_index + permutation[other._tensor.tensor_type()[0] + other_index] = other._tensor.tensor_type()[0] + other_index else: - permutation[other._tensor.tensor_type()[0] + other_index]\ - = other._tensor.tensor_type()[0] + self._cov.index(other._cov[other_index]) + permutation[other._tensor.tensor_type()[0] + other_index] = other._tensor.tensor_type()[0] + self._cov.index(other._cov[other_index]) result = self.__pos__() result._tensor = result._tensor + other.permute_indices(permutation)._tensor @@ -851,12 +820,7 @@ def __setitem__(self, args, value): elif self._tensor.tensor_type() != value._tensor.tensor_type(): raise ValueError("the tensors are not of the same type") else: - con, cov = self._parse_indices( - args, - tensor_type=self._tensor.tensor_type(), - allow_symmetries=False, - allow_contraction=False - ) + con, cov = self._parse_indices(args, tensor_type=self._tensor.tensor_type(), allow_symmetries=False, allow_contraction=False) permutation = list(range(value._tensor.tensor_rank())) for value_index in range(value._tensor.tensor_type()[0]): @@ -866,11 +830,9 @@ def __setitem__(self, args, value): permutation[value_index] = self._con.index(value._con[value_index]) for value_index in range(value._tensor.tensor_type()[1]): if value._cov[value_index] == self._cov[value_index]: - permutation[value._tensor.tensor_type()[0] + value_index]\ - = value._tensor.tensor_type()[0] + value_index + permutation[value._tensor.tensor_type()[0] + value_index] = value._tensor.tensor_type()[0] + value_index else: - permutation[value._tensor.tensor_type()[0] + value_index]\ - = value._tensor.tensor_type()[0] + self._cov.index(value._cov[value_index]) + permutation[value._tensor.tensor_type()[0] + value_index] = value._tensor.tensor_type()[0] + self._cov.index(value._cov[value_index]) self._tensor[:] = value.permute_indices(permutation)[:] else: @@ -930,35 +892,29 @@ def permute_indices(self, permutation): # sage.tensor.modules.comp.Components.swap_adjacent_indices # A swap is determined by 3 distinct integers - swap_params = list(combinations(range(self._tensor.tensor_rank()+1), 3)) + swap_params = list(combinations(range(self._tensor.tensor_rank() + 1), 3)) # The associated permutation is as follows def swap(param, N): i, j, k = param - L = list(range(1, N+1)) + L = list(range(1, N + 1)) L = L[:i] + L[j:k] + L[i:j] + L[k:] return L # Construction of the permutation group generated by swaps from sage.groups.perm_gps.permgroup import PermutationGroup - perm_group = PermutationGroup( - [swap(param, self._tensor.tensor_rank()) for param in swap_params], - canonicalize=False - ) + perm_group = PermutationGroup([swap(param, self._tensor.tensor_rank()) for param in swap_params], canonicalize=False) # Compute a decomposition of the permutation as a product of swaps - decomposition_as_string = perm_group([x+1 for x in permutation]).word_problem( - perm_group.gens(), - display=False - )[0] + decomposition_as_string = perm_group([x + 1 for x in permutation]).word_problem(perm_group.gens(), display=False)[0] if decomposition_as_string != "": decomposition_as_string = [ # Two cases whether the term appear with an exponent or not - ("^" in term)*term.split("^") + ("^" not in term)*(term.split("^")+['1']) + ("^" in term) * term.split("^") + ("^" not in term) * (term.split("^") + ['1']) for term in decomposition_as_string.replace("x", "").split("*") ] - decomposition = [(swap_params[int(x)-1], int(y)) for x, y in decomposition_as_string] + decomposition = [(swap_params[int(x) - 1], int(y)) for x, y in decomposition_as_string] decomposition.reverse() # /!\ The symmetric group acts on the right by default /!\. else: decomposition = [] @@ -972,24 +928,15 @@ def swap(param, N): if exponent > 0: for i in range(exponent): # Apply the swap given by swap_param - swaped_components = swaped_components\ - .swap_adjacent_indices(*swap_param) + swaped_components = swaped_components.swap_adjacent_indices(*swap_param) elif exponent < 0: for i in range(-exponent): # Apply the opposite of the swap given by swap_param - swaped_components = swaped_components\ - .swap_adjacent_indices( - swap_param[0], - swap_param[0] + swap_param[2] - swap_param[1], - swap_param[2] - ) + swaped_components = swaped_components.swap_adjacent_indices(swap_param[0], swap_param[0] + swap_param[2] - swap_param[1], swap_param[2]) else: pass result = self.__pos__() - result._tensor = self._tensor._fmodule.tensor_from_comp( - self._tensor.tensor_type(), - swaped_components - ) + result._tensor = self._tensor._fmodule.tensor_from_comp(self._tensor.tensor_type(), swaped_components) return result @@ -1012,8 +959,7 @@ def __pos__(self): sage: s._tensor == a True """ - return TensorWithIndices(+self._tensor, - self._con + '_' + self._cov) + return TensorWithIndices(+self._tensor, self._con + '_' + self._cov) def __neg__(self): r""" @@ -1034,5 +980,4 @@ def __neg__(self): sage: s._tensor == -a True """ - return TensorWithIndices(-self._tensor, - self._con + '_' + self._cov) + return TensorWithIndices(-self._tensor, self._con + '_' + self._cov) diff --git a/src/sage/tests/__init__.py b/src/sage/tests/__init__.py index 22d0e792cd7..df720933546 100644 --- a/src/sage/tests/__init__.py +++ b/src/sage/tests/__init__.py @@ -57,16 +57,17 @@ def check_executable(args, input='', timeout=100.0, pydebug_ignore_warnings=Fals except KeyError: pass - __with_pydebug = hasattr(sys, 'gettotalrefcount') # This is a Python debug build (--with-pydebug) + __with_pydebug = hasattr(sys, 'gettotalrefcount') # This is a Python debug build (--with-pydebug) if __with_pydebug and pydebug_ignore_warnings: - pexpect_env['PYTHONWARNINGS'] = ','.join([ - 'ignore::DeprecationWarning', - ]) + pexpect_env['PYTHONWARNINGS'] = ','.join( + [ + 'ignore::DeprecationWarning', + ] + ) kwds['encoding'] = kwds.pop('encoding', 'utf-8') - p = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE, env=pexpect_env, - **kwds) + p = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE, env=pexpect_env, **kwds) if input: p.stdin.write(input) @@ -95,13 +96,13 @@ def check_executable(args, input='', timeout=100.0, pydebug_ignore_warnings=Fals if fdout in rlist: s = p.stdout.read(1024) if not s: - fdout = None # EOF + fdout = None # EOF p.stdout.close() out.append(s) if fderr in rlist: s = p.stderr.read(1024) if not s: - fderr = None # EOF + fderr = None # EOF p.stderr.close() err.append(s) diff --git a/src/sage/tests/arxiv_0812_2725.py b/src/sage/tests/arxiv_0812_2725.py index 25e24ca3735..b1f22112a26 100644 --- a/src/sage/tests/arxiv_0812_2725.py +++ b/src/sage/tests/arxiv_0812_2725.py @@ -110,7 +110,7 @@ def matchingsset(L): yield [] else: for k in range(1, len(L)): - for m in matchingsset(L[1: k] + L[k + 1:]): + for m in matchingsset(L[1:k] + L[k + 1 :]): yield m + [(L[0], L[k])] @@ -173,11 +173,9 @@ def dcrossing(m_): e1_ = m.pop() for e2_ in m: e1, e2 = sorted(e1_), sorted(e2_) - if (e1[0] < e2[0] and e2[0] <= e1[1] and e1[1] < e2[1] and - e1[1] - e2[0] > d): + if e1[0] < e2[0] and e2[0] <= e1[1] and e1[1] < e2[1] and e1[1] - e2[0] > d: d = e1[1] - e2[0] - if (e2[0] < e1[0] and e1[0] <= e2[1] and e2[1] < e1[1] and - e2[1] - e1[0] > d): + if e2[0] < e1[0] and e1[0] <= e2[1] and e2[1] < e1[1] and e2[1] - e1[0] > d: d = e2[1] - e1[0] return d @@ -204,7 +202,7 @@ def setp_to_edges(p): [[1, 5], [2, 4], [4, 9], [6, 12], [7, 10], [10, 11]] """ q = (sorted(b) for b in p) - return [b[n: n + 2] for b in q for n in range(len(b) - 1)] + return [b[n : n + 2] for b in q for n in range(len(b) - 1)] def dcrossvec_setp(n): diff --git a/src/sage/tests/benchmark.py b/src/sage/tests/benchmark.py index 409df7d1b15..3be0d2da84b 100644 --- a/src/sage/tests/benchmark.py +++ b/src/sage/tests/benchmark.py @@ -86,6 +86,7 @@ class Benchmark: System min avg max trials cpu or wall * python ... """ + def run(self, systems=None, timeout=60, trials=1, sort=False, optional=False): """ Run the benchmarking functions for the current benchmark on the systems @@ -114,9 +115,7 @@ def run(self, systems=None, timeout=60, trials=1, sort=False, optional=False): if sort: systems.sort() print('\n\n\n' + str(self)) - print(' %-12s%-12s%-12s%-12s%-12s%15s' % ('System', 'min', - 'avg', 'max', - 'trials', 'cpu or wall')) + print(' %-12s%-12s%-12s%-12s%-12s%15s' % ('System', 'min', 'avg', 'max', 'trials', 'cpu or wall')) if systems is None: systems = STD_SYSTEMS if optional: @@ -136,16 +135,14 @@ def run(self, systems=None, timeout=60, trials=1, sort=False, optional=False): mn = min(X) mx = max(X) av = avg(X) - s = '* %-12s%-12f%-12f%-12f%-12s' % (S, mn, av, - mx, trials) + s = '* %-12s%-12f%-12f%-12f%-12s' % (S, mn, av, mx, trials) if wall: s += '%15fw' % t else: s += '%15fc' % t print(s) except AlarmInterrupt: - print('%-12sinterrupted (timeout: %s seconds wall time)' % - (S, timeout)) + print('%-12sinterrupted (timeout: %s seconds wall time)' % (S, timeout)) except AttributeError: pass except Exception as msg: @@ -295,8 +292,7 @@ def __init__(self, nvars=2, exp=10, base=QQ, allow_singular=True): self.exp = exp self.base = base self.allow_singular = allow_singular - s = 'Compute (x_0 + ... + x_%s)^%s over %s' % ( - self.nvars - 1, self.exp, self.base) + s = 'Compute (x_0 + ... + x_%s)^%s over %s' % (self.nvars - 1, self.exp, self.base) if self.allow_singular: s += ' (use singular for Sage mult.)' self.repr_str = s @@ -391,14 +387,14 @@ def mathematica(self): (z**self.exp).Expand() return False, walltime(w) -# this doesn't really expand out -- pari has no function to do so, -# as far as I know. -# def gp(self): -# R = PolynomialRing(self.base, self.nvars) -# z = gp(str(sum(R.gens()))) -# gp.eval('gettime') -# z**self.exp -# return float(gp.eval('gettime/1000.0')) + # this doesn't really expand out -- pari has no function to do so, + # as far as I know. + # def gp(self): + # R = PolynomialRing(self.base, self.nvars) + # z = gp(str(sum(R.gens()))) + # gp.eval('gettime') + # z**self.exp + # return float(gp.eval('gettime/1000.0')) def magma(self): """ @@ -416,7 +412,7 @@ def magma(self): for i in range(2, self.nvars + 1): z += R.gen(i) t = magma.cputime() - z**magma(self.exp) + z ** magma(self.exp) return magma.cputime(t) @@ -427,8 +423,7 @@ def __init__(self, nvars=2, base=QQ, allow_singular=True): self.nvars = nvars self.base = base self.allow_singular = allow_singular - s = 'Compute (x_0 + ... + x_%s) * (x_%s + ... + x_%s) over %s' % ( - self.nvars // 2 - 1, self.nvars // 2, self.nvars, self.base) + s = 'Compute (x_0 + ... + x_%s) * (x_%s + ... + x_%s) over %s' % (self.nvars // 2 - 1, self.nvars // 2, self.nvars, self.base) if self.allow_singular: s += ' (use singular for Sage mult.)' self.repr_str = s @@ -490,14 +485,14 @@ def mathematica(self): (z0 * z1).Expand() return False, walltime(w) -# def gp(self): -# R = PolynomialRing(self.base, self.nvars) -# k = self.nvars // 2 -# z0 = gp(str(sum(R.gens()[:k]))) -# z1 = gp(str(sum(R.gens()[k:]))) -# gp.eval('gettime') -# z0*z1 -# return float(gp.eval('gettime/1000.0')) + # def gp(self): + # R = PolynomialRing(self.base, self.nvars) + # k = self.nvars // 2 + # z0 = gp(str(sum(R.gens()[:k]))) + # z1 = gp(str(sum(R.gens()[k:]))) + # gp.eval('gettime') + # z0*z1 + # return float(gp.eval('gettime/1000.0')) def sage(self): """ @@ -574,27 +569,25 @@ def __init__(self, nvars=2, base=QQ, allow_singular=True): self.nvars = nvars self.base = base self.allow_singular = allow_singular - s = 'Compute (x_1 + 2*x_2 + 3*x_3 + ... + %s*x_%s) * (%s * x_%s + ... + %s*x_%s) over %s' % ( - self.nvars // 2, self.nvars // 2, self.nvars // 2 + 1, self.nvars // 2 + 1, - self.nvars + 1, self.nvars + 1, self.base) + s = 'Compute (x_1 + 2*x_2 + 3*x_3 + ... + %s*x_%s) * (%s * x_%s + ... + %s*x_%s) over %s' % (self.nvars // 2, self.nvars // 2, self.nvars // 2 + 1, self.nvars // 2 + 1, self.nvars + 1, self.nvars + 1, self.base) if self.allow_singular: s += ' (use singular for Sage mult.)' self.repr_str = s -# def gp(self): -# R = PolynomialRing(self.base, self.nvars) -# k = self.nvars // 2 -# z0 = R(0) -# z1 = R(0) -# for i in range(k): -# z0 += (i+1)*R.gen(i) -# for i in range(k,self.nvars): -# z1 += (i+1)*R.gen(i) -# z0 = gp(str(z0)) -# z1 = gp(str(z1)) -# gp.eval('gettime') -# z0*z1 -# return float(gp.eval('gettime/1000.0')) + # def gp(self): + # R = PolynomialRing(self.base, self.nvars) + # k = self.nvars // 2 + # z0 = R(0) + # z1 = R(0) + # for i in range(k): + # z0 += (i+1)*R.gen(i) + # for i in range(k,self.nvars): + # z1 += (i+1)*R.gen(i) + # z0 = gp(str(z0)) + # z1 = gp(str(z1)) + # gp.eval('gettime') + # z0*z1 + # return float(gp.eval('gettime/1000.0')) def maxima(self): """ @@ -867,8 +860,7 @@ def magma(self): """ R = magma(self.__R) f = magma('PolynomialRing(%s)![1..%s]' % (R.name(), self.__n)) - g = magma('PolynomialRing(%s)![%s+1..2*(%s+1)]' % ( - R.name(), self.__n, self.__n)) + g = magma('PolynomialRing(%s)![%s+1..2*(%s+1)]' % (R.name(), self.__n, self.__n)) h = f * g t = magma.cputime() h.Factorization() @@ -912,7 +904,7 @@ def sage(self): sage: isinstance(B.sage(), float) True """ - n = Integer(self.base)**self.__ndigits + n = Integer(self.base) ** self.__ndigits t = cputime() n**2 return cputime(t) @@ -1008,7 +1000,7 @@ def libgap(self): sage: isinstance(B.libgap()[1], float) True """ - n = libgap(self.base)**libgap(self.__ndigits) + n = libgap(self.base) ** libgap(self.__ndigits) t = walltime() n**2 return False, walltime(t) @@ -1066,8 +1058,7 @@ def magma(self): True """ R = magma(self.__R) - f = magma('MatrixAlgebra(%s, %s)![0..%s^2-1]' % ( - R.name(), self.__n, self.__n)) + f = magma('MatrixAlgebra(%s, %s)![0..%s^2-1]' % (R.name(), self.__n, self.__n)) t = magma.cputime() f * f return magma.cputime(t) @@ -1337,8 +1328,7 @@ def magma(self): True """ R = magma(self.__R) - f = magma('RMatrixSpace(%s, %s, %s)![0..(%s*2*%s)-1]' % ( - R.name(), self.__n, 2 * self.__n, self.__n, self.__n)) + f = magma('RMatrixSpace(%s, %s, %s)![0..(%s*2*%s)-1]' % (R.name(), self.__n, 2 * self.__n, self.__n, self.__n)) t = magma.cputime() f.Kernel() return magma.cputime(t) @@ -1501,8 +1491,7 @@ def magma(self): """ m = Magma() # new instance since otherwise modsyms are cached, and cache can't be cleared t = m.cputime() - m.eval('Decomposition(ModularSymbols(%s, %s, %s),%s);' % ( - self.N, self.k, self.sign, self.bnd)) + m.eval('Decomposition(ModularSymbols(%s, %s, %s),%s);' % (self.N, self.k, self.sign, self.bnd)) return m.cputime(t) @@ -1662,8 +1651,8 @@ class FiniteExtFieldMult(Benchmark): def __init__(self, field, times): self.__times = times self.field = field - self.e = field.gen()**(field.cardinality() / 3) - self.f = field.gen()**(2 * field.cardinality() / 3) + self.e = field.gen() ** (field.cardinality() / 3) + self.f = field.gen() ** (2 * field.cardinality() / 3) self.repr_str = "Multiply a^(#K/3) with a^(2*#K/3) where a == K.gen()" def sage(self): @@ -1723,8 +1712,8 @@ class FiniteExtFieldAdd(Benchmark): def __init__(self, field, times): self.__times = times self.field = field - self.e = field.gen()**(field.cardinality() / 3) - self.f = field.gen()**(2 * field.cardinality() / 3) + self.e = field.gen() ** (field.cardinality() / 3) + self.f = field.gen() ** (2 * field.cardinality() / 3) self.repr_str = "Add a^(#K/3) to a^(2*#K/3) where a == K.gen()" def sage(self): @@ -1827,12 +1816,12 @@ def suite1(): CharPolyTp(389, 2).run() CharPolyTp(389, 2, sign=0, p=3).run() CharPolyTp(1000, 2, sign=1, p=2).run(systems=['sage', 'magma']) - CharPolyTp(1, 100, sign=1, p=5).run(systems=['sage', 'magma']) # Sage's multimodular really sucks here! (GP is way better, even) + CharPolyTp(1, 100, sign=1, p=5).run(systems=['sage', 'magma']) # Sage's multimodular really sucks here! (GP is way better, even) CharPolyTp(512, sign=1, p=3).run(systems=['sage', 'magma', 'gp']) CharPolyTp(512, sign=0, p=3).run(systems=['sage', 'magma', 'gp']) CharPolyTp(1024, sign=1, p=3).run(systems=['sage', 'magma', 'gp']) CharPolyTp(2006, sign=1, p=2).run(systems=['sage', 'magma', 'gp']) - CharPolyTp(2006, sign=1, p=2).run(systems=['sage', 'magma']) # gp takes > 1 minute. + CharPolyTp(2006, sign=1, p=2).run(systems=['sage', 'magma']) # gp takes > 1 minute. def mpoly(): @@ -1885,7 +1874,7 @@ def mpoly_all(include_maple=False): MPolynomialMult(400).run(systems=systems) MPolynomialMult2(256).run(systems=systems) MPolynomialMult2(512).run(systems=systems) - MPolynomialPower(nvars=4, exp=50).run(systems=systems) # mathematica wins + MPolynomialPower(nvars=4, exp=50).run(systems=systems) # mathematica wins MPolynomialPower(nvars=10, exp=10).run(systems=systems) @@ -1914,11 +1903,11 @@ def elliptic_curve(): Divpoly(59).run() EllipticCurvePointMul(1000).run() EllipticCurvePointMul(2000).run() - EllipticCurvePointMul(2500).run() # sage is clearly using the wrong algorithm -- maybe need a balanced rep!? + EllipticCurvePointMul(2500).run() # sage is clearly using the wrong algorithm -- maybe need a balanced rep!? # NOTE -- Sage can also do these using Simon's program, which is # *way* *way* faster than MAGMA... EllipticCurveMW([5, 6, 7, 8, 9]).run() EllipticCurveMW([50, 6, 7, 8, 9]).run() - EllipticCurveMW([1, -1, 0, -79, 289]).run(trials=1) # rank 4 - EllipticCurveMW([0, 0, 1, -79, 342]).run(trials=1) # rank 5 (Sage wins) + EllipticCurveMW([1, -1, 0, -79, 289]).run(trials=1) # rank 4 + EllipticCurveMW([0, 0, 1, -79, 342]).run(trials=1) # rank 5 (Sage wins) diff --git a/src/sage/tests/books/judson_abstract_algebra/actions-sage-exercises.py b/src/sage/tests/books/judson_abstract_algebra/actions-sage-exercises.py index c9cc977d85f..5d44c6b0026 100644 --- a/src/sage/tests/books/judson_abstract_algebra/actions-sage-exercises.py +++ b/src/sage/tests/books/judson_abstract_algebra/actions-sage-exercises.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/actions-sage.py b/src/sage/tests/books/judson_abstract_algebra/actions-sage.py index b9d9559566a..010b481f4ba 100644 --- a/src/sage/tests/books/judson_abstract_algebra/actions-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/actions-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/algcodes-sage.py b/src/sage/tests/books/judson_abstract_algebra/algcodes-sage.py index e84413ce308..17f304f1868 100644 --- a/src/sage/tests/books/judson_abstract_algebra/algcodes-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/algcodes-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/boolean-sage.py b/src/sage/tests/books/judson_abstract_algebra/boolean-sage.py index 65d125b5aa3..b166765a916 100644 --- a/src/sage/tests/books/judson_abstract_algebra/boolean-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/boolean-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/cosets-sage-exercises.py b/src/sage/tests/books/judson_abstract_algebra/cosets-sage-exercises.py index 7841f9c1300..6b080ddb54c 100644 --- a/src/sage/tests/books/judson_abstract_algebra/cosets-sage-exercises.py +++ b/src/sage/tests/books/judson_abstract_algebra/cosets-sage-exercises.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/cosets-sage.py b/src/sage/tests/books/judson_abstract_algebra/cosets-sage.py index cb261f2dddb..eefb5d13b55 100644 --- a/src/sage/tests/books/judson_abstract_algebra/cosets-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/cosets-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/crypt-sage.py b/src/sage/tests/books/judson_abstract_algebra/crypt-sage.py index 550850705ed..e5dda06b8ca 100644 --- a/src/sage/tests/books/judson_abstract_algebra/crypt-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/crypt-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/cyclic-sage.py b/src/sage/tests/books/judson_abstract_algebra/cyclic-sage.py index 75b848d6439..903dbbec237 100644 --- a/src/sage/tests/books/judson_abstract_algebra/cyclic-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/cyclic-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/domains-sage.py b/src/sage/tests/books/judson_abstract_algebra/domains-sage.py index 08705184685..207aef13b19 100644 --- a/src/sage/tests/books/judson_abstract_algebra/domains-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/domains-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/fields-sage.py b/src/sage/tests/books/judson_abstract_algebra/fields-sage.py index 1d37d74452c..b9e79e862ab 100644 --- a/src/sage/tests/books/judson_abstract_algebra/fields-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/fields-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/finite-sage.py b/src/sage/tests/books/judson_abstract_algebra/finite-sage.py index 4d24e0ae0e7..31eb51e496f 100644 --- a/src/sage/tests/books/judson_abstract_algebra/finite-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/finite-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/galois-sage.py b/src/sage/tests/books/judson_abstract_algebra/galois-sage.py index af1f6fa8e6f..bc2c3ddbdeb 100644 --- a/src/sage/tests/books/judson_abstract_algebra/galois-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/galois-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/groups-sage.py b/src/sage/tests/books/judson_abstract_algebra/groups-sage.py index fb2c96ca25b..abac30f6db2 100644 --- a/src/sage/tests/books/judson_abstract_algebra/groups-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/groups-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/homomorph-sage-exercises.py b/src/sage/tests/books/judson_abstract_algebra/homomorph-sage-exercises.py index 5bc958041d3..d4d1d88d870 100644 --- a/src/sage/tests/books/judson_abstract_algebra/homomorph-sage-exercises.py +++ b/src/sage/tests/books/judson_abstract_algebra/homomorph-sage-exercises.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/homomorph-sage.py b/src/sage/tests/books/judson_abstract_algebra/homomorph-sage.py index 0cd9dbaebe2..fa0aff64645 100644 --- a/src/sage/tests/books/judson_abstract_algebra/homomorph-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/homomorph-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/integers-sage.py b/src/sage/tests/books/judson_abstract_algebra/integers-sage.py index ca79ab8b89a..9cebbc8d5b3 100644 --- a/src/sage/tests/books/judson_abstract_algebra/integers-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/integers-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/isomorph-sage.py b/src/sage/tests/books/judson_abstract_algebra/isomorph-sage.py index 4bfe69e1963..76586f425ee 100644 --- a/src/sage/tests/books/judson_abstract_algebra/isomorph-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/isomorph-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/normal-sage.py b/src/sage/tests/books/judson_abstract_algebra/normal-sage.py index c8f26d1317b..fb9e7248629 100644 --- a/src/sage/tests/books/judson_abstract_algebra/normal-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/normal-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/permute-sage.py b/src/sage/tests/books/judson_abstract_algebra/permute-sage.py index 66e908cc056..7302ae13244 100644 --- a/src/sage/tests/books/judson_abstract_algebra/permute-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/permute-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/poly-sage.py b/src/sage/tests/books/judson_abstract_algebra/poly-sage.py index 7aaa67ac4fb..500b51c9292 100644 --- a/src/sage/tests/books/judson_abstract_algebra/poly-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/poly-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/rings-sage.py b/src/sage/tests/books/judson_abstract_algebra/rings-sage.py index 124530d5b2d..d836eb7299a 100644 --- a/src/sage/tests/books/judson_abstract_algebra/rings-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/rings-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/sets-sage.py b/src/sage/tests/books/judson_abstract_algebra/sets-sage.py index 1f331278a3b..a3f6cb296f1 100644 --- a/src/sage/tests/books/judson_abstract_algebra/sets-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/sets-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/struct-sage.py b/src/sage/tests/books/judson_abstract_algebra/struct-sage.py index 1509cf22334..8b880ec0616 100644 --- a/src/sage/tests/books/judson_abstract_algebra/struct-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/struct-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/sylow-sage.py b/src/sage/tests/books/judson_abstract_algebra/sylow-sage.py index 67b628c1571..762efeaba3a 100644 --- a/src/sage/tests/books/judson_abstract_algebra/sylow-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/sylow-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-26T21:16:30-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-26T21:16:30-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/vect-sage-exercises.py b/src/sage/tests/books/judson_abstract_algebra/vect-sage-exercises.py index fd74f44465e..ee07c30e0e2 100644 --- a/src/sage/tests/books/judson_abstract_algebra/vect-sage-exercises.py +++ b/src/sage/tests/books/judson_abstract_algebra/vect-sage-exercises.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/books/judson_abstract_algebra/vect-sage.py b/src/sage/tests/books/judson_abstract_algebra/vect-sage.py index 083f35e9972..174e7f6043e 100644 --- a/src/sage/tests/books/judson_abstract_algebra/vect-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/vect-sage.py @@ -1,11 +1,11 @@ ## Sage Doctest File ## -#**************************************# -#* Generated from PreTeXt source *# -#* on 2017-08-24T11:43:34-07:00 *# -#* *# -#* http://mathbook.pugetsound.edu *# -#* *# -#**************************************# +# **************************************# +# * Generated from PreTeXt source *# +# * on 2017-08-24T11:43:34-07:00 *# +# * *# +# * http://mathbook.pugetsound.edu *# +# * *# +# **************************************# ## """ Please contact Rob Beezer (beezer@ups.edu) with diff --git a/src/sage/tests/finite_poset.py b/src/sage/tests/finite_poset.py index 0773f6f58f2..6bdb3313397 100644 --- a/src/sage/tests/finite_poset.py +++ b/src/sage/tests/finite_poset.py @@ -13,80 +13,73 @@ from functools import reduce implications = { - 'doubling_convex': ['doubling_any'], - 'doubling_interval': ['doubling_lower', 'doubling_upper'], - 'doubling_lower': ['doubling_convex', 'meet_semidistributive'], - 'doubling_upper': ['doubling_convex', 'join_semidistributive'], - 'cosectionally_complemented': ['complemented', 'coatomic', 'regular'], - 'distributive': ['modular', 'semidistributive', 'join_distributive', 'meet_distributive', 'subdirectly_reducible', 'doubling_interval', 'extremal'], - 'geometric': ['upper_semimodular', 'relatively_complemented'], - 'isoform': ['uniform'], - 'join_distributive': ['meet_semidistributive', 'upper_semimodular'], - 'join_semidistributive': ['join_pseudocomplemented', 'interval_dismantlable'], - 'lower_semimodular': ['graded'], - 'meet_distributive': ['join_semidistributive', 'lower_semimodular'], - 'meet_semidistributive': ['pseudocomplemented', 'interval_dismantlable'], - 'modular': ['upper_semimodular', 'lower_semimodular', 'supersolvable'], - 'orthocomplemented': ['self_dual', 'complemented'], - 'planar': ['dismantlable'], - 'dismantlable': ['sublattice_dismantlable'], - 'interval_dismantlable': ['sublattice_dismantlable'], - 'relatively_complemented': ['sectionally_complemented', 'cosectionally_complemented', 'isoform'], - 'sectionally_complemented': ['complemented', 'atomic', 'regular'], - 'semidistributive': ['join_semidistributive', 'meet_semidistributive'], - 'simple': ['isoform'], - 'supersolvable': ['graded'], - 'uniform': ['regular'], - 'uniq_orthocomplemented': ['orthocomplemented'], - 'upper_semimodular': ['graded'], - 'vertically_decomposable': ['subdirectly_reducible'], + 'doubling_convex': ['doubling_any'], + 'doubling_interval': ['doubling_lower', 'doubling_upper'], + 'doubling_lower': ['doubling_convex', 'meet_semidistributive'], + 'doubling_upper': ['doubling_convex', 'join_semidistributive'], + 'cosectionally_complemented': ['complemented', 'coatomic', 'regular'], + 'distributive': ['modular', 'semidistributive', 'join_distributive', 'meet_distributive', 'subdirectly_reducible', 'doubling_interval', 'extremal'], + 'geometric': ['upper_semimodular', 'relatively_complemented'], + 'isoform': ['uniform'], + 'join_distributive': ['meet_semidistributive', 'upper_semimodular'], + 'join_semidistributive': ['join_pseudocomplemented', 'interval_dismantlable'], + 'lower_semimodular': ['graded'], + 'meet_distributive': ['join_semidistributive', 'lower_semimodular'], + 'meet_semidistributive': ['pseudocomplemented', 'interval_dismantlable'], + 'modular': ['upper_semimodular', 'lower_semimodular', 'supersolvable'], + 'orthocomplemented': ['self_dual', 'complemented'], + 'planar': ['dismantlable'], + 'dismantlable': ['sublattice_dismantlable'], + 'interval_dismantlable': ['sublattice_dismantlable'], + 'relatively_complemented': ['sectionally_complemented', 'cosectionally_complemented', 'isoform'], + 'sectionally_complemented': ['complemented', 'atomic', 'regular'], + 'semidistributive': ['join_semidistributive', 'meet_semidistributive'], + 'simple': ['isoform'], + 'supersolvable': ['graded'], + 'uniform': ['regular'], + 'uniq_orthocomplemented': ['orthocomplemented'], + 'upper_semimodular': ['graded'], + 'vertically_decomposable': ['subdirectly_reducible'], } dual_properties = [ - ['atomic', 'coatomic'], - ['upper_semimodular', 'lower_semimodular'], - ['sectionally_complemented', 'cosectionally_complemented'], - ['join_distributive', 'meet_distributive'], - ['join_semidistributive', 'meet_semidistributive'], - ['pseudocomplemented', 'join_pseudocomplemented'], - ['doubling_lower', 'doubling_upper'], + ['atomic', 'coatomic'], + ['upper_semimodular', 'lower_semimodular'], + ['sectionally_complemented', 'cosectionally_complemented'], + ['join_distributive', 'meet_distributive'], + ['join_semidistributive', 'meet_semidistributive'], + ['pseudocomplemented', 'join_pseudocomplemented'], + ['doubling_lower', 'doubling_upper'], ] -selfdual_properties = ['distributive', 'modular', 'semidistributive', 'complemented', - 'relatively_complemented', 'orthocomplemented', 'uniq_orthocomplemented', 'supersolvable', 'planar', - 'dismantlable', 'vertically_decomposable', 'simple', 'isoform', 'uniform', 'regular', - 'subdirectly_reducible', 'doubling_any', 'doubling_convex', 'doubling_interval', - 'interval_dismantlable', 'interval_dismantlable'] +selfdual_properties = ['distributive', 'modular', 'semidistributive', 'complemented', 'relatively_complemented', 'orthocomplemented', 'uniq_orthocomplemented', 'supersolvable', 'planar', 'dismantlable', 'vertically_decomposable', 'simple', 'isoform', 'uniform', 'regular', 'subdirectly_reducible', 'doubling_any', 'doubling_convex', 'doubling_interval', 'interval_dismantlable', 'interval_dismantlable'] -dual_elements = [ - ['atoms', 'coatoms'], - ['meet_irreducibles', 'join_irreducibles'], - ['meet_primes', 'join_primes'] -] +dual_elements = [['atoms', 'coatoms'], ['meet_irreducibles', 'join_irreducibles'], ['meet_primes', 'join_primes']] -two_to_one = [ ['distributive', 'dismantlable', 'planar'], - ['upper_semimodular', 'lower_semimodular', 'modular'], - ['meet_distributive', 'join_distributive', 'distributive'], - ['meet_semidistributive', 'join_semidistributive', 'semidistributive'], - ['lower_semimodular', 'meet_semidistributive', 'distributive'], - ['upper_semimodular', 'join_semidistributive', 'distributive'], - ['complemented', 'modular', 'relatively_complemented'], - ] +two_to_one = [ + ['distributive', 'dismantlable', 'planar'], + ['upper_semimodular', 'lower_semimodular', 'modular'], + ['meet_distributive', 'join_distributive', 'distributive'], + ['meet_semidistributive', 'join_semidistributive', 'semidistributive'], + ['lower_semimodular', 'meet_semidistributive', 'distributive'], + ['upper_semimodular', 'join_semidistributive', 'distributive'], + ['complemented', 'modular', 'relatively_complemented'], +] mutually_exclusive = [ - ['doubling_any', 'simple'], - ['vertically_decomposable', 'atomic'], - ['vertically_decomposable', 'coatomic'], - ['vertically_decomposable', 'regular'], + ['doubling_any', 'simple'], + ['vertically_decomposable', 'atomic'], + ['vertically_decomposable', 'coatomic'], + ['vertically_decomposable', 'regular'], ] set_inclusions = [ - ['atoms', 'join_irreducibles'], - ['coatoms', 'meet_irreducibles'], - ['double_irreducibles', 'join_irreducibles'], - ['double_irreducibles', 'meet_irreducibles'], - ['meet_primes', 'meet_irreducibles'], - ['join_primes', 'join_irreducibles'], + ['atoms', 'join_irreducibles'], + ['coatoms', 'meet_irreducibles'], + ['double_irreducibles', 'join_irreducibles'], + ['double_irreducibles', 'meet_irreducibles'], + ['meet_primes', 'meet_irreducibles'], + ['join_primes', 'join_irreducibles'], ] sublattice_closed = ['distributive', 'modular', 'semidistributive', 'join_semidistributive', 'meet_semidistributive'] @@ -192,11 +185,11 @@ def check_finite_lattice(L): Ldual = L.dual() # Selfdual properties for p in selfdual_properties: - if P[p] != check_attrcall('is_'+p, Ldual): + if P[p] != check_attrcall('is_' + p, Ldual): raise ValueError("selfdual property %s error" % p) # Dual properties and elements for p1, p2 in dual_properties: - if P[p1] != check_attrcall('is_'+p2, Ldual): + if P[p1] != check_attrcall('is_' + p2, Ldual): raise ValueError("dual properties error %s" % p1) for e1, e2 in dual_elements: if set(attrcall(e1)(L)) != set(attrcall(e2)(Ldual)): @@ -209,7 +202,7 @@ def check_finite_lattice(L): # Dirty fix first if p_[:9] == 'doubling_' or p_[:5] == 'uniq_': continue - p = "is_"+p_ + p = "is_" + p_ if 'certificate' in sage_getargspec(getattr(L, p)).args: res = attrcall(p, certificate=True)(L) if not isinstance(res, tuple) or len(res) != 2: @@ -222,13 +215,13 @@ def check_finite_lattice(L): a = L.is_supersolvable(certificate=True)[1] S = Subsets(L).random_element() if L.is_chain_of_poset(S): - if not L.sublattice(a+list(S)).is_distributive(): + if not L.sublattice(a + list(S)).is_distributive(): raise ValueError("certificate error in is_supersolvable") if P['dismantlable']: elms = L.is_dismantlable(certificate=True)[1] if len(elms) != L.cardinality(): raise ValueError("certificate error 1 in is_dismantlable") - elms = elms[:randint(0, len(elms)-1)] + elms = elms[: randint(0, len(elms) - 1)] L_ = L.sublattice([x for x in L if x not in elms]) if L_.cardinality() != L.cardinality() - len(elms): raise ValueError("certificate error 2 in is_dismantlable") @@ -314,19 +307,19 @@ def check_finite_lattice(L): if not P['simple']: c = L.is_simple(certificate=True)[1] - if len(L.congruence([c[randint(0, len(c)-1)]])) == 1: + if len(L.congruence([c[randint(0, len(c) - 1)]])) == 1: raise ValueError("certificate error in is_simple") if not P['isoform']: c = L.is_isoform(certificate=True)[1] if len(c) == 1: raise ValueError("certificate error in is_isoform") - if all(L.subposet(c[i]).is_isomorphic(L.subposet(c[i+1])) for i in range(len(c)-1)): + if all(L.subposet(c[i]).is_isomorphic(L.subposet(c[i + 1])) for i in range(len(c) - 1)): raise ValueError("certificate error in is_isoform") if not P['uniform']: c = L.is_uniform(certificate=True)[1] if len(c) == 1: raise ValueError("certificate error in is_uniform") - if all(len(c[i]) == len(c[i+1]) for i in range(len(c)-1)): + if all(len(c[i]) == len(c[i + 1]) for i in range(len(c) - 1)): raise ValueError("certificate error in is_uniform") if not P['regular']: c = L.is_regular(certificate=True)[1] @@ -397,7 +390,7 @@ def check_finite_lattice(L): # Sublattice-closed properties L_ = L.sublattice(Subsets(L).random_element()) for p in sublattice_closed: - if P[p] and not check_attrcall('is_'+p, L_): + if P[p] and not check_attrcall('is_' + p, L_): raise ValueError("property %s should apply to sublattices" % p) # Some sublattices @@ -413,9 +406,9 @@ def check_finite_lattice(L): if L.sublattice(S) == L and L.sublattice([e for e in S if e not in L_]) != L: raise ValueError("error in Frattini sublattice") L_ = L.maximal_sublattices() - L_ = L_[randint(0, len(L_)-1)] + L_ = L_[randint(0, len(L_) - 1)] e = L.random_element() - if e not in L_ and L.sublattice(list(L_)+[e]) != L: + if e not in L_ and L.sublattice(list(L_) + [e]) != L: raise ValueError("error in maximal_sublattices") # Reverse functions: vertical composition and decomposition @@ -437,7 +430,7 @@ def check_finite_lattice(L): # Misc misc e = L.neutral_elements() - e = e[randint(0, len(e)-1)] + e = e[randint(0, len(e) - 1)] a = L.random_element() b = L.random_element() if not L.sublattice([e, a, b]).is_distributive(): @@ -475,7 +468,7 @@ def check_finite_poset(P): # Cardinality if len(P) != P.cardinality(): raise ValueError("error 1 in cardinality") - if P.cardinality()-1 != P_one_less.cardinality(): + if P.cardinality() - 1 != P_one_less.cardinality(): raise ValueError("error 5 in cardinality") # Height @@ -489,7 +482,7 @@ def check_finite_poset(P): raise ValueError("error 3 in height") if len(P.random_maximal_chain()) > h1: raise ValueError("error 4 in height") - if h1-P_one_less.height() not in [0, 1]: + if h1 - P_one_less.height() not in [0, 1]: raise ValueError("error 5 in height") # Width @@ -503,7 +496,7 @@ def check_finite_poset(P): raise ValueError("error 3 in width") if len(P.random_maximal_antichain()) > w1: raise ValueError("error 4 in width") - if w1-P_one_less.width() not in [0, 1]: + if w1 - P_one_less.width() not in [0, 1]: raise ValueError("error 5 in width") # Dimension @@ -513,14 +506,14 @@ def check_finite_poset(P): raise ValueError("error 1 in dimension") if dim1 != len(linexts): raise ValueError("error 2 in dimension") - P_ = Poset( (P.list(), lambda a, b: all(linext.index(a) < linext.index(b) for linext in linexts)) ) + P_ = Poset((P.list(), lambda a, b: all(linext.index(a) < linext.index(b) for linext in linexts))) if P_ != Poset(P.hasse_diagram()): raise ValueError("error 3 in dimension") - x = [P.random_linear_extension() for _ in range(dim1-1)] - P_ = Poset( (P.list(), lambda a, b: all(linext.index(a) < linext.index(b) for linext in x)) ) + x = [P.random_linear_extension() for _ in range(dim1 - 1)] + P_ = Poset((P.list(), lambda a, b: all(linext.index(a) < linext.index(b) for linext in x))) if P_ == Poset(P.hasse_diagram()): raise ValueError("error 4 in dimension") - if dim1-P_one_less.dimension() < 0: + if dim1 - P_one_less.dimension() < 0: raise ValueError("error 5 in dimension") # Jump number @@ -534,7 +527,7 @@ def check_finite_poset(P): raise ValueError("error 3 in jump number") if P.linear_extension(P.random_linear_extension()).jump_count() < j1: raise ValueError("error 4 in jump number") - if j1-P_one_less.jump_number() not in [0, 1]: + if j1 - P_one_less.jump_number() not in [0, 1]: raise ValueError("error 5 in jump number") P_dual = P.dual() @@ -599,17 +592,16 @@ def check_finite_poset(P): raise ValueError("error in sorted") dil = P.dilworth_decomposition() - chain = dil[randint(0, len(dil)-1)] + chain = dil[randint(0, len(dil) - 1)] if not P.is_chain_of_poset(chain): raise ValueError("error in Dilworth decomposition") lev = P.level_sets() - level = lev[randint(0, len(lev)-1)] + level = lev[randint(0, len(lev) - 1)] if not P.is_antichain_of_poset(level): raise ValueError("error in level sets") # certificate=True must return a pair - bool_with_cert = ['eulerian', 'greedy', 'join_semilattice', - 'jump_critical', 'meet_semilattice', 'slender'] + bool_with_cert = ['eulerian', 'greedy', 'join_semilattice', 'jump_critical', 'meet_semilattice', 'slender'] for p in bool_with_cert: try: # some properties are not always defined for all posets res1 = attrcall('is_' + p)(P) diff --git a/src/sage/tests/functools_partial_src.py b/src/sage/tests/functools_partial_src.py index e8c983356aa..7fe181c1761 100644 --- a/src/sage/tests/functools_partial_src.py +++ b/src/sage/tests/functools_partial_src.py @@ -2,6 +2,7 @@ Ensure that ``functools.partial`` is correctly handled by :func:`~sage.misc.sageinspect.sage_getsourcelines`. """ + from functools import partial diff --git a/src/sage/tests/memcheck/run_tests.py b/src/sage/tests/memcheck/run_tests.py index 6ff4503a81b..90df7184fbf 100644 --- a/src/sage/tests/memcheck/run_tests.py +++ b/src/sage/tests/memcheck/run_tests.py @@ -6,6 +6,7 @@ def run_tests() -> None: Run all memcheck tests """ from sage.tests.memcheck import symbolic_expression + run_tests_in_module(symbolic_expression) diff --git a/src/sage/tests/memcheck/run_tests_in_valgrind.py b/src/sage/tests/memcheck/run_tests_in_valgrind.py index df5ad0e92b2..c3861d22921 100644 --- a/src/sage/tests/memcheck/run_tests_in_valgrind.py +++ b/src/sage/tests/memcheck/run_tests_in_valgrind.py @@ -20,15 +20,7 @@ def run_tests_in_valgrind() -> None: """ Run the sage.tests.memcheck.run_tests module inside valgrind """ - subprocess.check_call([ - 'valgrind', - '--suppressions=src/sage/ext_data/valgrind/valgrind-python.supp', - '--show-possibly-lost=no', - '--show-reachable=no', - './venv/bin/python', - '-m', - 'sage.tests.memcheck.run_tests' - ]) + subprocess.check_call(['valgrind', '--suppressions=src/sage/ext_data/valgrind/valgrind-python.supp', '--show-possibly-lost=no', '--show-reachable=no', './venv/bin/python', '-m', 'sage.tests.memcheck.run_tests']) if __name__ == '__main__': diff --git a/src/sage/tests/memcheck/symbolic_expression.py b/src/sage/tests/memcheck/symbolic_expression.py index 95d971bec75..dae3734738a 100644 --- a/src/sage/tests/memcheck/symbolic_expression.py +++ b/src/sage/tests/memcheck/symbolic_expression.py @@ -3,6 +3,7 @@ def check_sqrt_sqrt_2() -> None: from sage.misc.functional import sqrt + T2 = sqrt(2) def sqrt_T2() -> None: diff --git a/src/sage/tests/memcheck/verify_no_leak.py b/src/sage/tests/memcheck/verify_no_leak.py index a2378fc7da2..78f73c12531 100644 --- a/src/sage/tests/memcheck/verify_no_leak.py +++ b/src/sage/tests/memcheck/verify_no_leak.py @@ -3,16 +3,17 @@ import valgrind -def verify_no_leak(callback: Callable[[], Any], - repeat: int = 10000, - fuzzy: int = 10, - ) -> None: +def verify_no_leak( + callback: Callable[[], Any], + repeat: int = 10000, + fuzzy: int = 10, +) -> None: """ Verify that the callback does not generate new definitely lost blocks Raises an assertion if the callback leaks memory """ - callback() # warm_up + callback() # warm_up initial_blocks = (0, 0, 0, 0) valgrind.memcheck_do_leak_check() initial_blocks = valgrind.memcheck_count_leak_blocks() diff --git a/src/sage/tests/test_deprecation.py b/src/sage/tests/test_deprecation.py index a8e6ff9c99b..cfa2b8f517b 100644 --- a/src/sage/tests/test_deprecation.py +++ b/src/sage/tests/test_deprecation.py @@ -9,6 +9,7 @@ use sage.tests.test_deprecation.function_new instead. See https://github.com/sagemath/sage/issues/12345 for details. """ + from sage.misc.superseded import deprecated_function_alias diff --git a/src/sage/topology/all.py b/src/sage/topology/all.py index 18b553e873d..afd8a80ac64 100644 --- a/src/sage/topology/all.py +++ b/src/sage/topology/all.py @@ -8,6 +8,7 @@ from sage.topology.cubical_complex import CubicalComplex, cubical_complexes from sage.misc.lazy_import import lazy_import + lazy_import('sage.topology.filtered_simplicial_complex', 'FilteredSimplicialComplex') lazy_import('sage.topology', 'simplicial_complex_catalog', 'simplicial_complexes') diff --git a/src/sage/topology/cell_complex.py b/src/sage/topology/cell_complex.py index 4ac07065b56..acb71592575 100644 --- a/src/sage/topology/cell_complex.py +++ b/src/sage/topology/cell_complex.py @@ -79,6 +79,7 @@ class :class:`~sage.homology.delta_complex.DeltaComplex` sage: from sage.topology.cell_complex import GenericCellComplex sage: A = GenericCellComplex() """ + def __eq__(self, right): """ Comparisons of cell complexes are not implemented. @@ -292,7 +293,7 @@ def euler_characteristic(self): sage: cubical_complexes.KleinBottle().euler_characteristic() 0 """ - return sum((-1)**n * self.f_vector()[n + 1] for n in range(self.dimension() + 1)) + return sum((-1) ** n * self.f_vector()[n + 1] for n in range(self.dimension() + 1)) ############################################################ # end of methods using self.cells() @@ -419,9 +420,7 @@ def join(self, right): ############################################################ @abstract_method - def chain_complex(self, subcomplex=None, augmented=False, - verbose=False, check=True, dimensions=None, - base_ring=ZZ, cochain=False): + def chain_complex(self, subcomplex=None, augmented=False, verbose=False, check=True, dimensions=None, base_ring=ZZ, cochain=False): """ This is not implemented for general cell complexes. @@ -453,9 +452,7 @@ def chain_complex(self, subcomplex=None, augmented=False, NotImplementedError: """ - def homology(self, dim=None, base_ring=ZZ, subcomplex=None, - generators=False, cohomology=False, algorithm='pari', - verbose=False, reduced=True, **kwds): + def homology(self, dim=None, base_ring=ZZ, subcomplex=None, generators=False, cohomology=False, algorithm='pari', verbose=False, reduced=True, **kwds): r""" The (reduced) homology of this cell complex. @@ -566,17 +563,10 @@ def homology(self, dim=None, base_ring=ZZ, subcomplex=None, # _homology_ method. See SimplicialComplex for one example. # Those may allow for other arguments, so we pass **kwds. if hasattr(self, '_homology_'): - return self._homology_(dim, subcomplex=subcomplex, - cohomology=cohomology, base_ring=base_ring, - verbose=verbose, algorithm=algorithm, - reduced=reduced, generators=generators, - **kwds) - - C = self.chain_complex(cochain=cohomology, augmented=reduced, - dimensions=dims, subcomplex=subcomplex, - base_ring=base_ring, verbose=verbose) - answer = C.homology(base_ring=base_ring, generators=generators, - verbose=verbose, algorithm=algorithm) + return self._homology_(dim, subcomplex=subcomplex, cohomology=cohomology, base_ring=base_ring, verbose=verbose, algorithm=algorithm, reduced=reduced, generators=generators, **kwds) + + C = self.chain_complex(cochain=cohomology, augmented=reduced, dimensions=dims, subcomplex=subcomplex, base_ring=base_ring, verbose=verbose) + answer = C.homology(base_ring=base_ring, generators=generators, verbose=verbose, algorithm=algorithm) if generators: # Try to convert chain complex information to topological @@ -586,10 +576,10 @@ def homology(self, dim=None, base_ring=ZZ, subcomplex=None, if H_with_gens: chains = self.n_chains(i, base_ring=base_ring) new_H = [] - for (H, gen) in H_with_gens: + for H, gen in H_with_gens: v = gen.vector(i) new_gen = chains.zero() - for (coeff, chain) in zip(v, chains.gens()): + for coeff, chain in zip(v, chains.gens()): new_gen += coeff * chain new_H.append((H, new_gen)) answer[i] = new_H @@ -601,9 +591,7 @@ def homology(self, dim=None, base_ring=ZZ, subcomplex=None, return dict([d, answer.get(d, zero)] for d in dim) return answer.get(dim, zero) - def cohomology(self, dim=None, base_ring=ZZ, subcomplex=None, - generators=False, algorithm='pari', - verbose=False, reduced=True): + def cohomology(self, dim=None, base_ring=ZZ, subcomplex=None, generators=False, algorithm='pari', verbose=False, reduced=True): r""" The reduced cohomology of this cell complex. @@ -658,10 +646,7 @@ def cohomology(self, dim=None, base_ring=ZZ, subcomplex=None, sage: s5.cohomology(base_ring=GF(7))[5] # needs sage.modules Vector space of dimension 1 over Finite Field of size 7 """ - return self.homology(dim=dim, cohomology=True, base_ring=base_ring, - subcomplex=subcomplex, generators=generators, - algorithm=algorithm, verbose=verbose, - reduced=reduced) + return self.homology(dim=dim, cohomology=True, base_ring=base_ring, subcomplex=subcomplex, generators=generators, algorithm=algorithm, verbose=verbose, reduced=reduced) def betti(self, dim=None, subcomplex=None): r""" @@ -871,9 +856,7 @@ def homology_with_basis(self, base_ring=QQ, cohomology=False): sage: list(H.basis(3)) # needs sage.modules [h^{3,0}] """ - from sage.homology.homology_vector_space_with_basis import \ - HomologyVectorSpaceWithBasis, HomologyVectorSpaceWithBasis_mod2, \ - is_GF2 + from sage.homology.homology_vector_space_with_basis import HomologyVectorSpaceWithBasis, HomologyVectorSpaceWithBasis_mod2, is_GF2 if cohomology: return self.cohomology_ring(base_ring) @@ -985,8 +968,7 @@ def cohomology_ring(self, base_ring=QQ): Cohomology ring of Simplicial complex with 9 vertices and 18 facets over Rational Field """ - from sage.homology.homology_vector_space_with_basis import CohomologyRing, \ - CohomologyRing_mod2, is_GF2 + from sage.homology.homology_vector_space_with_basis import CohomologyRing, CohomologyRing_mod2, is_GF2 if is_GF2(base_ring): return CohomologyRing_mod2(base_ring, self) @@ -1070,6 +1052,7 @@ def face_poset(self): """ from sage.combinat.posets.posets import Poset from sage.misc.flatten import flatten + covers = {} # The code for posets seems to work better if each cell is # converted to a tuple. diff --git a/src/sage/topology/cubical_complex.py b/src/sage/topology/cubical_complex.py index ccbfedeb502..61e3d74b2ea 100644 --- a/src/sage/topology/cubical_complex.py +++ b/src/sage/topology/cubical_complex.py @@ -126,6 +126,7 @@ class Cube(SageObject): sage: Cube(()).dimension() # empty cube has dimension -1 -1 """ + def __init__(self, data): """ Define a cube for use in constructing a cubical complex. @@ -193,10 +194,9 @@ def is_face(self, other) -> bool: sage: C2.is_face(C1) True """ + def is_subinterval(i1, i2): - return ((i1[0] == i2[0] and i1[1] == i2[1]) or - (i1[0] == i2[0] and i1[1] == i2[0]) or - (i1[0] == i2[1] and i1[1] == i2[1])) + return (i1[0] == i2[0] and i1[1] == i2[1]) or (i1[0] == i2[0] and i1[1] == i2[0]) or (i1[0] == i2[1] and i1[1] == i2[1]) t = self.tuple() u = other.tuple() @@ -378,7 +378,7 @@ def face(self, n, upper=True): new = t[idx][1] else: new = t[idx][0] - return Cube(t[0:idx] + ((new, new),) + t[idx+1:]) + return Cube(t[0:idx] + ((new, new),) + t[idx + 1 :]) def faces(self): """ @@ -477,9 +477,7 @@ def _compare_for_gluing(self, other): translate = [] self_tuple = self.tuple() other_tuple = other.tuple() - nondegen = (list(zip(self.nondegenerate_intervals(), - other.nondegenerate_intervals())) - + [(len(self_tuple), len(other_tuple))]) + nondegen = list(zip(self.nondegenerate_intervals(), other.nondegenerate_intervals())) + [(len(self_tuple), len(other_tuple))] old = (-1, -1) self_added = 0 other_added = 0 @@ -491,24 +489,20 @@ def _compare_for_gluing(self, other): diff = self_diff - other_diff if diff < 0: - insert_self.append((old[0] + self_diff + self_added, - other.tuple()[current[1]+diff:current[1]])) + insert_self.append((old[0] + self_diff + self_added, other.tuple()[current[1] + diff : current[1]])) common_terms = self_diff diff = -diff self_added += diff elif diff > 0: - insert_other.append((old[1] + other_diff + other_added, - self.tuple()[current[0]-diff:current[0]])) + insert_other.append((old[1] + other_diff + other_added, self.tuple()[current[0] - diff : current[0]])) common_terms = other_diff other_added += diff else: common_terms = other_diff if old[0] > -1: - translate.extend([self_tuple[old[0]+idx][0] - - other_tuple[old[1]+idx][0] for idx in - range(common_terms)]) - translate.extend(diff*[0]) + translate.extend([self_tuple[old[0] + idx][0] - other_tuple[old[1] + idx][0] for idx in range(common_terms)]) + translate.extend(diff * [0]) old = current return (insert_self, insert_other, translate) @@ -554,15 +548,14 @@ def _triangulation_(self): 6 """ from .simplicial_complex import Simplex + if self.dimension() < 0: # the empty cube return [Simplex(())] # the empty simplex v = tuple([max(j) for j in self.tuple()]) Sv = Simplex((v,)) if self.dimension() == 0: # just v return [Sv] - return [S.join(Sv, rename_vertices=False) - for i in range(self.dimension()) - for S in self.face(i, upper=False)._triangulation_()] + return [S.join(Sv, rename_vertices=False) for i in range(self.dimension()) for S in self.face(i, upper=False)._triangulation_()] def alexander_whitney(self, dim): r""" @@ -600,6 +593,7 @@ def alexander_whitney(self, dim): [(1, [0,1] x [3,4], [1,1] x [4,4])] """ from sage.sets.set import Set + N = Set(self.nondegenerate_intervals()) result = [] for J in N.subsets(dim): @@ -622,7 +616,7 @@ def alexander_whitney(self, dim): else: left.append(t[j]) right.append(t[j]) - result.append(((-1)**nu, Cube(left), Cube(right))) + result.append(((-1) ** nu, Cube(left), Cube(right))) return result def __eq__(self, other): @@ -873,6 +867,7 @@ class :class:`Cube`, or lists or tuples suitable for conversion to Therefore, neither are cones or suspensions. """ + def __init__(self, maximal_faces=None, maximality_check=True): r""" Define a cubical complex. See ``CubicalComplex`` for more @@ -1057,9 +1052,7 @@ def is_subcomplex(self, other) -> bool: {[0,1] x [0,0]} """ other_facets = other.maximal_cells() - return all(any(cube.is_face(other_cube) - for other_cube in other_facets) - for cube in self.maximal_cells()) + return all(any(cube.is_face(other_cube) for other_cube in other_facets) for cube in self.maximal_cells()) def cells(self, subcomplex=None): """ @@ -1100,7 +1093,7 @@ def cells(self, subcomplex=None): sub_facets = {} dimension = max([cube.dimension() for cube in self._facets]) # initialize the lists: add each maximal cube to Cells and sub_facets - for i in range(-1, dimension+1): + for i in range(-1, dimension + 1): Cells[i] = set() sub_facets[i] = set() for f in self._facets: @@ -1116,11 +1109,11 @@ def cells(self, subcomplex=None): for dim in range(dimension, -1, -1): # bad_bdries = boundaries of bad_faces: things to be # discarded in dim-1 - bad_bdries = sub_facets[dim-1] + bad_bdries = sub_facets[dim - 1] for f in bad_faces: bad_bdries.update(f.faces()) for f in Cells[dim]: - Cells[dim-1].update(set(f.faces()).difference(bad_bdries)) + Cells[dim - 1].update(set(f.faces()).difference(bad_bdries)) bad_faces = bad_bdries self._cells[subcomplex] = Cells return self._cells[subcomplex] @@ -1155,9 +1148,7 @@ def n_cubes(self, n, subcomplex=None): """ return set(self.n_cells(n, subcomplex)) - def chain_complex(self, subcomplex=None, augmented=False, - verbose=False, check=False, dimensions=None, - base_ring=ZZ, cochain=False): + def chain_complex(self, subcomplex=None, augmented=False, verbose=False, check=False, dimensions=None, base_ring=ZZ, cochain=False): r""" The chain complex associated to this cubical complex. @@ -1232,20 +1223,20 @@ def chain_complex(self, subcomplex=None, augmented=False, empty_cell = 0 vertices = self._n_cells_sorted(0, subcomplex=subcomplex) n = len(vertices) - mat = matrix(base_ring, empty_cell, n, n*empty_cell*[1]) + mat = matrix(base_ring, empty_cell, n, n * empty_cell * [1]) if cochain: differentials[-1] = mat.transpose() else: differentials[0] = mat current = vertices # now loop from 1 to dimension of the complex - for dim in range(1, self.dimension()+1): + for dim in range(1, self.dimension() + 1): if verbose: print(" starting dimension %s" % dim) if (dim, subcomplex) in self._complex: if cochain: - differentials[dim-1] = self._complex[(dim, subcomplex)].transpose().change_ring(base_ring) - mat = differentials[dim-1] + differentials[dim - 1] = self._complex[(dim, subcomplex)].transpose().change_ring(base_ring) + mat = differentials[dim - 1] else: differentials[dim] = self._complex[(dim, subcomplex)].change_ring(base_ring) mat = differentials[dim] @@ -1278,7 +1269,7 @@ def chain_complex(self, subcomplex=None, augmented=False, except KeyError: pass try: - matrix_data[(old[lower], col)] = -1*sign + matrix_data[(old[lower], col)] = -1 * sign except KeyError: pass # The signs in the boundary alternate as @@ -1288,17 +1279,15 @@ def chain_complex(self, subcomplex=None, augmented=False, mat = matrix(ZZ, len(old), len(current), matrix_data) self._complex[(dim, subcomplex)] = mat if cochain: - differentials[dim-1] = mat.transpose().change_ring(base_ring) + differentials[dim - 1] = mat.transpose().change_ring(base_ring) else: differentials[dim] = mat.change_ring(base_ring) if verbose: print(" boundary matrix computed: it's {} by {}.".format(mat.nrows(), mat.ncols())) # finally, return the chain complex if cochain: - return ChainComplex(data=differentials, base_ring=base_ring, - degree=1, check=check) - return ChainComplex(data=differentials, base_ring=base_ring, - degree=-1, check=check) + return ChainComplex(data=differentials, base_ring=base_ring, degree=1, check=check) + return ChainComplex(data=differentials, base_ring=base_ring, degree=-1, check=check) def alexander_whitney(self, cube, dim_left): r""" @@ -1347,7 +1336,7 @@ def n_skeleton(self, n): if n >= self.dimension(): return self data = [] - for d in range(n+1): + for d in range(n + 1): data.extend(list(self.cells()[d])) return CubicalComplex(data) @@ -1514,11 +1503,9 @@ def disjoint_union(self, other): embedded_right = len(tuple(other.maximal_cells()[0])) zero = [0] * max(embedded_left, embedded_right) C00 = Cube([[0, 0]]) - facets = [C00.product(f._translate(zero)) - for f in self.maximal_cells()] + facets = [C00.product(f._translate(zero)) for f in self.maximal_cells()] C11 = Cube([[1, 1]]) - facets.extend(C11.product(f._translate(zero)) - for f in other.maximal_cells()) + facets.extend(C11.product(f._translate(zero)) for f in other.maximal_cells()) return CubicalComplex(facets) def wedge(self, other): @@ -1555,8 +1542,7 @@ def wedge(self, other): point_right = Cube([[0, 0]] * embedded_left) facets = [f._translate(translate_left) for f in self.maximal_cells()] - facets.extend(point_right.product(f._translate(translate_right)) - for f in other.maximal_cells()) + facets.extend(point_right.product(f._translate(translate_right)) for f in other.maximal_cells()) return CubicalComplex(facets) def connected_sum(self, other): @@ -1596,8 +1582,7 @@ def connected_sum(self, other): # more dimension, embedding the first complex as (..., 0) and # the second as (..., 1). Keep all of the other facets, but remove # C x 0 and C x 1, putting in its place (its boundary) x (0,1). - if not (self.is_pure() and other.is_pure() and - self.dimension() == other.dimension()): + if not (self.is_pure() and other.is_pure() and self.dimension() == other.dimension()): raise ValueError("complexes are not pure of the same dimension") self_facets = list(self.maximal_cells()) @@ -1608,7 +1593,7 @@ def connected_sum(self, other): (insert_self, insert_other, translate) = C1._compare_for_gluing(C2) CL = list(C1.tuple()) - for (idx, L) in insert_self: + for idx, L in insert_self: CL[idx:idx] = L removed = Cube(CL) @@ -1625,13 +1610,13 @@ def connected_sum(self, other): for cube in self_facets: CL = list(cube.tuple()) - for (idx, L) in insert_self: + for idx, L in insert_self: CL[idx:idx] = L CL.append((0, 0)) new_facets.append(Cube(CL)) for cube in other_facets: CL = list(cube.tuple()) - for (idx, L) in insert_other: + for idx, L in insert_other: CL[idx:idx] = L CL.append((1, 1)) new_facets.append(Cube(CL)._translate(translate)) @@ -1718,6 +1703,7 @@ def algebraic_topological_model(self, base_ring=None): 2: Vector space of dimension 1 over Rational Field} """ from sage.homology.algebraic_topological_model import algebraic_topological_model + if base_ring is None: base_ring = QQ return algebraic_topological_model(self, base_ring) @@ -1776,6 +1762,7 @@ def _simplicial_(self): Simplicial complex with 32 vertices and 240 facets """ from .simplicial_complex import SimplicialComplex + simplices = [] for C in self.maximal_cells(): simplices.extend(C._triangulation_()) @@ -1836,7 +1823,7 @@ def Sphere(self, n): sage: cubical_complexes.Sphere(7) Cubical complex with 256 vertices and 6560 cubes """ - return CubicalComplex(Cube([[0, 1]]*(n+1)).faces()) + return CubicalComplex(Cube([[0, 1]] * (n + 1)).faces()) def Torus(self): r""" @@ -1862,27 +1849,7 @@ def RealProjectivePlane(self): sage: cubical_complexes.RealProjectivePlane() Cubical complex with 21 vertices and 81 cubes """ - return CubicalComplex([ - ([0, 1], [0], [0], [0, 1], [0]), - ([0, 1], [0], [0], [0], [0, 1]), - ([0], [0, 1], [0, 1], [0], [0]), - ([0], [0, 1], [0], [0, 1], [0]), - ([0], [0], [0, 1], [0], [0, 1]), - ([0, 1], [0, 1], [1], [0], [0]), - ([0, 1], [1], [0, 1], [0], [0]), - ([1], [0, 1], [0, 1], [0], [0]), - ([0, 1], [0, 1], [0], [0], [1]), - ([0, 1], [1], [0], [0], [0, 1]), - ([1], [0, 1], [0], [0], [0, 1]), - ([0, 1], [0], [0, 1], [1], [0]), - ([0, 1], [0], [1], [0, 1], [0]), - ([1], [0], [0, 1], [0, 1], [0]), - ([0], [0, 1], [0], [0, 1], [1]), - ([0], [0, 1], [0], [1], [0, 1]), - ([0], [1], [0], [0, 1], [0, 1]), - ([0], [0], [0, 1], [0, 1], [1]), - ([0], [0], [0, 1], [1], [0, 1]), - ([0], [0], [1], [0, 1], [0, 1])]) + return CubicalComplex([([0, 1], [0], [0], [0, 1], [0]), ([0, 1], [0], [0], [0], [0, 1]), ([0], [0, 1], [0, 1], [0], [0]), ([0], [0, 1], [0], [0, 1], [0]), ([0], [0], [0, 1], [0], [0, 1]), ([0, 1], [0, 1], [1], [0], [0]), ([0, 1], [1], [0, 1], [0], [0]), ([1], [0, 1], [0, 1], [0], [0]), ([0, 1], [0, 1], [0], [0], [1]), ([0, 1], [1], [0], [0], [0, 1]), ([1], [0, 1], [0], [0], [0, 1]), ([0, 1], [0], [0, 1], [1], [0]), ([0, 1], [0], [1], [0, 1], [0]), ([1], [0], [0, 1], [0, 1], [0]), ([0], [0, 1], [0], [0, 1], [1]), ([0], [0, 1], [0], [1], [0, 1]), ([0], [1], [0], [0, 1], [0, 1]), ([0], [0], [0, 1], [0, 1], [1]), ([0], [0], [0, 1], [1], [0, 1]), ([0], [0], [1], [0, 1], [0, 1])]) def KleinBottle(self): r""" @@ -1939,7 +1906,7 @@ def SurfaceOfGenus(self, g, orientable=True): else: T = cubical_complexes.RealProjectivePlane() S = T - for i in range(g-1): + for i in range(g - 1): S = S.connected_sum(T) return S diff --git a/src/sage/topology/delta_complex.py b/src/sage/topology/delta_complex.py index e93b8cf5d2c..4caf2df9403 100644 --- a/src/sage/topology/delta_complex.py +++ b/src/sage/topology/delta_complex.py @@ -239,6 +239,7 @@ class DeltaComplex(GenericCellComplex): Type ``delta_complexes.`` and then hit the :kbd:`Tab` key to get the full list. """ + def __init__(self, data=None, check_validity=True): r""" Define a `\Delta`-complex. See :class:`DeltaComplex` for more @@ -253,6 +254,7 @@ def __init__(self, data=None, check_validity=True): sage: X == loads(dumps(X)) True """ + def store_bdry(simplex, faces): r""" Given a simplex of dimension d and a list of boundaries @@ -269,12 +271,12 @@ def store_bdry(simplex, faces): d = simplex.dimension() if d > 0: for f in faces: - if f in new_data[d-1]: - bdry_list.append(new_data[d-1].index(f)) + if f in new_data[d - 1]: + bdry_list.append(new_data[d - 1].index(f)) else: - bdry_list.append(len(new_data[d-1])) - new_delayed[f] = len(new_data[d-1]) - new_data[d-1].append(f) + bdry_list.append(len(new_data[d - 1])) + new_delayed[f] = len(new_data[d - 1]) + new_data[d - 1].append(f) bdry_list = tuple(bdry_list) else: bdry_list = () @@ -347,7 +349,7 @@ def store_bdry(simplex, faces): current[x] = store_bdry(x, x.faces()) old_delayed = new_delayed if dim > 0: - old_data_by_dim[dim-1].extend(old_delayed) + old_data_by_dim[dim - 1].extend(old_delayed) else: raise ValueError("data is not a list, tuple, or dictionary") for n in new_data: @@ -359,9 +361,9 @@ def store_bdry(simplex, faces): dim = max(new_data) for d in range(dim, 1, -1): for s in new_data[d]: # s is a d-simplex - faces = new_data[d-1] - for j in range(d+1): - if not all(faces[s[j]][i] == faces[s[i]][j-1] for i in range(j)): + faces = new_data[d - 1] + for j in range(d + 1): + if not all(faces[s[j]][i] == faces[s[i]][j - 1] for i in range(j)): msg = "simplicial identity d_i d_j = d_{j-1} d_i fails" msg += " for j={}, in dimension {}".format(j, d) raise ValueError(msg) @@ -449,15 +451,15 @@ def subcomplex(self, data): d_cells = cells_to_add new_data[d] = cells_to_add try: - cells_to_add = set(new_data[d-1]) # begin to populate the (d-1)-cells + cells_to_add = set(new_data[d - 1]) # begin to populate the (d-1)-cells except KeyError: cells_to_add = set() for x in d_cells: - if d+1 in new_dict: - old = new_dict[d+1] - new_dict[d+1] = [] + if d + 1 in new_dict: + old = new_dict[d + 1] + new_dict[d + 1] = [] for f in old: - new_dict[d+1].append(tuple([translate[n] for n in f])) + new_dict[d + 1].append(tuple([translate[n] for n in f])) new_dict[d].append(cells[d][x]) cells_to_add.update(cells[d][x]) new_cells = [new_dict[n] for n in range(max_dim + 1)] @@ -552,7 +554,7 @@ def cells(self, subcomplex=None): if subcomplex == self: for d in range(-1, max(cells) + 1): l = len(cells[d]) - cells[d] = [None] * l # get rid of all cells + cells[d] = [None] * l # get rid of all cells return cells raise ValueError("this is not a subcomplex of self") else: @@ -565,9 +567,7 @@ def cells(self, subcomplex=None): cells[-1] = (None,) return cells - def chain_complex(self, subcomplex=None, augmented=False, - verbose=False, check=False, dimensions=None, - base_ring=ZZ, cochain=False): + def chain_complex(self, subcomplex=None, augmented=False, verbose=False, check=False, dimensions=None, base_ring=ZZ, cochain=False): r""" The chain complex associated to this `\Delta`-complex. @@ -638,8 +638,7 @@ def chain_complex(self, subcomplex=None, augmented=False, old = vertices old_real = [x for x in old if x is not None] # remove faces not in subcomplex n = len(old_real) - differentials[0] = matrix(base_ring, empty_simplex, n, - n * empty_simplex * [1]) + differentials[0] = matrix(base_ring, empty_simplex, n, n * empty_simplex * [1]) # current is list of simplices in dimension dim # current_real is list of simplices in dimension dim, with None filtered out # old is list of simplices in dimension dim-1 @@ -671,10 +670,8 @@ def chain_complex(self, subcomplex=None, augmented=False, cochain_diffs = {} for dim in differentials: cochain_diffs[dim - 1] = differentials[dim].transpose() - return ChainComplex(data=cochain_diffs, degree=1, - base_ring=base_ring, check=check) - return ChainComplex(data=differentials, degree=-1, - base_ring=base_ring, check=check) + return ChainComplex(data=cochain_diffs, degree=1, base_ring=base_ring, check=check) + return ChainComplex(data=differentials, degree=-1, base_ring=base_ring, check=check) def alexander_whitney(self, cell, dim_left): r""" @@ -719,12 +716,12 @@ def alexander_whitney(self, cell, dim_left): idx_l = cell[0] for i in range(dim, dim_left, -1): idx_l = left_cell[i] - left_cell = self.n_cells(i-1)[idx_l] + left_cell = self.n_cells(i - 1)[idx_l] right_cell = cell[1] idx_r = cell[0] for i in range(dim, dim - dim_left, -1): idx_r = right_cell[0] - right_cell = self.n_cells(i-1)[idx_r] + right_cell = self.n_cells(i - 1)[idx_r] return [(ZZ.one(), (idx_l, left_cell), (idx_r, right_cell))] def n_skeleton(self, n): @@ -823,12 +820,12 @@ def join(self, other): # dimension of the join: maxdim = self.dimension() + other.dimension() + 1 # now for the d-cells, d>0: - for d in range(1, maxdim+1): + for d in range(1, maxdim + 1): d_cells = [] positions = {} new_idx = 0 - for k in range(-1, d+1): - n = d-1-k + for k in range(-1, d + 1): + n = d - 1 - k # d=n+k. need a k-cell from self and an n-cell from other if k == -1: left = [()] @@ -850,14 +847,14 @@ def join(self, other): if k == 0: bdry.append(bdries[(-1, 0, n, r_idx)]) else: - for i in range(k+1): - bdry.append(bdries[(k-1, l[i], n, r_idx)]) + for i in range(k + 1): + bdry.append(bdries[(k - 1, l[i], n, r_idx)]) # remaining faces come from right-hand factor if n == 0: bdry.append(bdries[(k, l_idx, -1, 0)]) else: - for i in range(n+1): - bdry.append(bdries[(k, l_idx, n-1, r[i])]) + for i in range(n + 1): + bdry.append(bdries[(k, l_idx, n - 1, r[i])]) d_cells.append(tuple(bdry)) r_idx += 1 new_idx += 1 @@ -914,7 +911,7 @@ def suspension(self, n=1): return self if n == 1: return self.join(delta_complexes.Sphere(0)) - return self.suspension().suspension(int(n-1)) + return self.suspension().suspension(int(n - 1)) def product(self, other): r""" @@ -991,45 +988,37 @@ def product(self, other): # Simplex, as well as the function # 'lattice_paths', in # simplicial_complex.py.) - for _path in lattice_paths(list(range(k + 1)), - list(range(n + 1)), - length=d+1): + for _path in lattice_paths(list(range(k + 1)), list(range(n + 1)), length=d + 1): path = tuple(_path) new[(k, k_idx, n, n_idx, path)] = len(simplices) bdry_list = [] - for i in range(d+1): - face_path = path[:i] + path[i+1:] - if ((i < d and path[i][0] == path[i+1][0]) or - (i > 0 and path[i][0] == path[i-1][0])): + for i in range(d + 1): + face_path = path[:i] + path[i + 1 :] + if (i < d and path[i][0] == path[i + 1][0]) or (i > 0 and path[i][0] == path[i - 1][0]): # this k-simplex k_face_idx = k_idx k_face_dim = k else: # face of this k-simplex k_face_idx = k_cell[path[i][0]] - k_face_dim = k-1 + k_face_dim = k - 1 tail = [] for j in range(i, d): - tail.append((face_path[j][0]-1, - face_path[j][1])) + tail.append((face_path[j][0] - 1, face_path[j][1])) face_path = face_path[:i] + tuple(tail) - if ((i < d and path[i][1] == path[i+1][1]) or - (i > 0 and path[i][1] == path[i-1][1])): + if (i < d and path[i][1] == path[i + 1][1]) or (i > 0 and path[i][1] == path[i - 1][1]): # this n-simplex n_face_idx = n_idx n_face_dim = n else: # face of this n-simplex n_face_idx = n_cell[path[i][1]] - n_face_dim = n-1 + n_face_dim = n - 1 tail = [] for j in range(i, d): - tail.append((face_path[j][0], - face_path[j][1]-1)) + tail.append((face_path[j][0], face_path[j][1] - 1)) face_path = face_path[:i] + tuple(tail) - bdry_list.append(bdries[(k_face_dim, k_face_idx, - n_face_dim, n_face_idx, - face_path)]) + bdry_list.append(bdries[(k_face_dim, k_face_idx, n_face_dim, n_face_idx, face_path)]) simplices.append(tuple(bdry_list)) # add d-simplices to data, store d-simplices in bdries, # reset simplices @@ -1188,8 +1177,7 @@ def connected_sum(self, other): renaming = {} process_now = process_later for f in glued: - renaming.update(dict(zip(right_cells[n - 1][f], - data[n - 1][glued[f]]))) + renaming.update(dict(zip(right_cells[n - 1][f], data[n - 1][glued[f]]))) # deal with vertices separately. we just need to add enough # vertices: all the vertices from Right, minus the number # being glued, which should be dim+1, the number of vertices @@ -1376,8 +1364,7 @@ def _epi_from_standard_simplex(self, idx=-1, dim=None): faces_dict = {} for cell in n_cells: if n > 1: - faces = [tuple(simplex_cells[n - 1][cell[j]]) - for j in range(n + 1)] + faces = [tuple(simplex_cells[n - 1][cell[j]]) for j in range(n + 1)] one_cell = dict(zip(faces, self_cells[n][n_cells[cell]])) else: temp = dict(zip(cell, self_cells[n][n_cells[cell]])) @@ -1430,7 +1417,7 @@ def _is_glued(self, idx=-1, dim=None): i = self.dimension() - 1 i_faces = set(simplex) # if there are enough i_faces, then no gluing is evident so far - not_glued = (len(i_faces) == binomial(dim + 1, i + 1)) + not_glued = len(i_faces) == binomial(dim + 1, i + 1) while not_glued and i > 0: # count the (i-1) cells and compare to (n+1) choose i. old_faces = i_faces @@ -1438,7 +1425,7 @@ def _is_glued(self, idx=-1, dim=None): all_cells = self.n_cells(i) for face in old_faces: i_faces.update(all_cells[face]) - not_glued = (len(i_faces) == binomial(dim + 1, i)) + not_glued = len(i_faces) == binomial(dim + 1, i) i -= 1 return not not_glued @@ -1454,6 +1441,7 @@ def face_poset(self): Finite poset containing 6 elements """ from sage.combinat.posets.posets import Poset + # given the structure of self.cells(), it's easier to compute # the dual poset, then reverse it at the end. dim = self.dimension() @@ -1526,9 +1514,9 @@ def n_chains(self, n, base_ring=None, cochains=False): return Chains(self, n, n_cells, base_ring) # the second barycentric subdivision is a simplicial complex. implement this somehow? -# def simplicial_complex(self): -# X = self.barycentric_subdivision().barycentric_subdivision() -# find facets of X and return SimplicialComplex(facets) + # def simplicial_complex(self): + # X = self.barycentric_subdivision().barycentric_subdivision() + # find facets of X and return SimplicialComplex(facets) # This is cached for speed reasons: it can be very slow to run # this function. @@ -1587,6 +1575,7 @@ def algebraic_topological_model(self, base_ring=None): 2: Vector space of dimension 1 over Rational Field} """ from sage.homology.algebraic_topological_model import algebraic_topological_model_delta_complex + if base_ring is None: base_ring = QQ return algebraic_topological_model_delta_complex(self, base_ring) @@ -1649,8 +1638,7 @@ def Sphere(self, n): """ if n == 1: return DeltaComplex([[()], [(0, 0)]]) - return DeltaComplex({Simplex(n): True, - Simplex(range(1, n + 2)): Simplex(n)}) + return DeltaComplex({Simplex(n): True, Simplex(range(1, n + 2)): Simplex(n)}) def Torus(self): r""" @@ -1664,8 +1652,7 @@ def Torus(self): sage: delta_complexes.Torus().homology(1) # needs sage.modules sage.rings.finite_rings Z x Z """ - return DeltaComplex((((),), ((0, 0), (0, 0), (0, 0)), - ((1, 2, 0), (0, 2, 1)))) + return DeltaComplex((((),), ((0, 0), (0, 0), (0, 0)), ((1, 2, 0), (0, 2, 1)))) def RealProjectivePlane(self): r""" @@ -1687,8 +1674,7 @@ def RealProjectivePlane(self): sage: P.cohomology(dim=2, base_ring=GF(2)) Vector space of dimension 1 over Finite Field of size 2 """ - return DeltaComplex((((), ()), ((1, 0), (1, 0), (0, 0)), - ((1, 0, 2), (0, 1, 2)))) + return DeltaComplex((((), ()), ((1, 0), (1, 0), (0, 0)), ((1, 0, 2), (0, 1, 2)))) def KleinBottle(self): r""" @@ -1702,8 +1688,7 @@ def KleinBottle(self): sage: delta_complexes.KleinBottle() Delta complex with 1 vertex and 7 simplices """ - return DeltaComplex((((),), ((0, 0), (0, 0), (0, 0)), - ((1, 2, 0), (0, 1, 2)))) + return DeltaComplex((((),), ((0, 0), (0, 0), (0, 0)), ((1, 2, 0), (0, 1, 2)))) def Simplex(self, n): r""" diff --git a/src/sage/topology/filtered_simplicial_complex.py b/src/sage/topology/filtered_simplicial_complex.py index 88148886243..3d302b65e2d 100644 --- a/src/sage/topology/filtered_simplicial_complex.py +++ b/src/sage/topology/filtered_simplicial_complex.py @@ -114,6 +114,7 @@ class FilteredSimplicialComplex(SageObject): Filtered complex on vertex set (0, 1, 2) and with simplices ((0,) : 0), ((1,) : 0), ((2,) : 1), ((0, 1) : 2.27000000000000) """ + def __init__(self, simplices=[], verbose=False): """ Initialize ``self``. @@ -164,9 +165,7 @@ def __eq__(self, other): sage: X == Y False """ - return (isinstance(other, FilteredSimplicialComplex) - and self._vertices == other._vertices - and self._filtration_dict == other._filtration_dict) + return isinstance(other, FilteredSimplicialComplex) and self._vertices == other._vertices and self._filtration_dict == other._filtration_dict def __ne__(self, other): """ @@ -426,12 +425,14 @@ def _persistent_homology(self, field=2, strict=True, verbose=False): sage: X.persistence_intervals(0, strict=False) # needs sage.modules [(0, 1), (1, 1), (1, 2), (0, +Infinity)] """ + # first, order the simplices in lexico order # on dimension, value and then arbitrary order # defined by the Simplex class. def key(s): d = self._get_value(s) return (s.dimension(), d, s) + simplices = list(self._filtration_dict) simplices.sort(key=key) @@ -570,7 +571,7 @@ def _remove_pivot_rows(self, s, simplices): # Initialize the boundary chain for i, f in enumerate(s.faces()): - d += (-1)**i * self._chaingroup(f) + d += (-1) ** i * self._chaingroup(f) # Remove all unmarked elements for s, x_s in d: @@ -590,7 +591,7 @@ def _remove_pivot_rows(self, s, simplices): c = self._T[max_index][1] q = c[t] - d = d - ((q**(-1)) * c) + d = d - ((q ** (-1)) * c) return d @@ -689,8 +690,7 @@ def betti_number(self, k, a, b, field=2, strict=True, verbose=None): if verbose is None: verbose = self._verbose intervals = self._persistent_homology(field, strict, verbose=verbose) - return Integer(sum(1 for i, j in intervals[k] - if (i <= a and a + b < j) and a >= 0)) + return Integer(sum(1 for i, j in intervals[k] if (i <= a and a + b < j) and a >= 0)) def _repr_(self): """ diff --git a/src/sage/topology/moment_angle_complex.py b/src/sage/topology/moment_angle_complex.py index 04c6922a99b..c35a348ae27 100644 --- a/src/sage/topology/moment_angle_complex.py +++ b/src/sage/topology/moment_angle_complex.py @@ -169,6 +169,7 @@ class MomentAngleComplex(UniqueRepresentation, SageObject): sage: TestSuite(Z).run() """ + @staticmethod def __classcall_private__(cls, simplicial_complex): """ @@ -217,9 +218,7 @@ def __init__(self, simplicial_complex) -> None: circle = simplicial_complexes.Sphere(1) # A dictionary of components indexed by facets - self._components = {facet: [disk if j in facet else circle - for j in vertices] - for facet in self._simplicial_complex.maximal_faces()} + self._components = {facet: [disk if j in facet else circle for j in vertices] for facet in self._simplicial_complex.maximal_faces()} @lazy_attribute def _moment_angle_complex(self): @@ -492,13 +491,9 @@ def _homology_group(self, i, base_ring, cohomology, algorithm, verbose, reduced) for x in combinations(vertices, j): S = self._simplicial_complex.generated_subcomplex(x) if in_field: - invfac.append(S.homology(i - j - 1, base_ring=base_ring, - cohomology=cohomology, algorithm=algorithm, - verbose=verbose, reduced=True).dimension()) + invfac.append(S.homology(i - j - 1, base_ring=base_ring, cohomology=cohomology, algorithm=algorithm, verbose=verbose, reduced=True).dimension()) else: - invfac.extend(S.homology(i - j - 1, base_ring=base_ring, - cohomology=cohomology, algorithm=algorithm, - verbose=verbose, reduced=True)._original_invts) + invfac.extend(S.homology(i - j - 1, base_ring=base_ring, cohomology=cohomology, algorithm=algorithm, verbose=verbose, reduced=True)._original_invts) if in_field: return HomologyGroup(sum(invfac), base_ring) @@ -506,8 +501,7 @@ def _homology_group(self, i, base_ring, cohomology, algorithm, verbose, reduced) m = len(invfac) return HomologyGroup(m, base_ring, invfac) - def homology(self, dim=None, base_ring=ZZ, cohomology=False, - algorithm='pari', verbose=False, reduced=True) -> dict: + def homology(self, dim=None, base_ring=ZZ, cohomology=False, algorithm='pari', verbose=False, reduced=True) -> dict: r""" The (reduced) homology of ``self``. @@ -637,11 +631,9 @@ def homology(self, dim=None, base_ring=ZZ, cohomology=False, else: dims = range(self.dimension() + 1) - return {i: self._homology_group(i, base_ring=base_ring, cohomology=cohomology, - algorithm=algorithm, verbose=verbose, reduced=reduced) for i in dims} + return {i: self._homology_group(i, base_ring=base_ring, cohomology=cohomology, algorithm=algorithm, verbose=verbose, reduced=reduced) for i in dims} - def cohomology(self, dim=None, base_ring=ZZ, algorithm='pari', - verbose=False, reduced=True) -> dict: + def cohomology(self, dim=None, base_ring=ZZ, algorithm='pari', verbose=False, reduced=True) -> dict: r""" The reduced cohomology of ``self``. @@ -669,8 +661,7 @@ def cohomology(self, dim=None, base_ring=ZZ, algorithm='pari', sage: Z.cohomology() == product_of_spheres.cohomology() # long time True """ - return self.homology(dim=dim, cohomology=True, base_ring=base_ring, - algorithm=algorithm, verbose=verbose, reduced=reduced) + return self.homology(dim=dim, cohomology=True, base_ring=base_ring, algorithm=algorithm, verbose=verbose, reduced=reduced) def betti(self, dim=None) -> dict: r""" @@ -733,8 +724,7 @@ def euler_characteristic(self): 1 """ sc = self.simplicial_complex() - return (ZZ.one() if sc.dimension() + 1 == len(sc.vertices()) - else ZZ.zero()) + return ZZ.one() if sc.dimension() + 1 == len(sc.vertices()) else ZZ.zero() def product(self, other): """ diff --git a/src/sage/topology/simplicial_complex.py b/src/sage/topology/simplicial_complex.py index 1c4ebf82250..9e02cbecb4e 100644 --- a/src/sage/topology/simplicial_complex.py +++ b/src/sage/topology/simplicial_complex.py @@ -253,10 +253,7 @@ def lattice_paths(t1, t2, length=None): return [[(v, t2[0]) for v in t1]] # recursive: paths in rectangle with either one fewer row # or column, plus the upper right corner - return ([path + [(t1[-1], t2[-1])] for path - in lattice_paths(t1[:-1], t2)] + - [path + [(t1[-1], t2[-1])] for path - in lattice_paths(t1, t2[:-1])]) + return [path + [(t1[-1], t2[-1])] for path in lattice_paths(t1[:-1], t2)] + [path + [(t1[-1], t2[-1])] for path in lattice_paths(t1, t2[:-1])] if length > len(t1) + len(t2) - 1: return [] # as above, except make sure that lengths are correct. if @@ -279,12 +276,7 @@ def lattice_paths(t1, t2, length=None): # recursive: paths of length one fewer in rectangle with # either one fewer row, one fewer column, or one fewer of # each, and then plus the upper right corner - return ([path + [(t1[-1], t2[-1])] for path - in lattice_paths(t1[:-1], t2, length=length-1)] + - [path + [(t1[-1], t2[-1])] for path - in lattice_paths(t1, t2[:-1], length=length-1)] + - [path + [(t1[-1], t2[-1])] for path - in lattice_paths(t1[:-1], t2[:-1], length=length-1)]) + return [path + [(t1[-1], t2[-1])] for path in lattice_paths(t1[:-1], t2, length=length - 1)] + [path + [(t1[-1], t2[-1])] for path in lattice_paths(t1, t2[:-1], length=length - 1)] + [path + [(t1[-1], t2[-1])] for path in lattice_paths(t1[:-1], t2[:-1], length=length - 1)] def rename_vertex(n, keep, left=True): @@ -514,7 +506,7 @@ def face(self, n): (0, 1, 2, 4) """ if n >= 0 and n <= self.dimension(): - return Simplex(self.__tuple[:n] + self.__tuple[n+1:]) + return Simplex(self.__tuple[:n] + self.__tuple[n + 1 :]) raise IndexError("{} does not have an n-th face for n={}".format(self, n)) def faces(self): @@ -586,8 +578,7 @@ def join(self, right, rename_vertices=True): ('a', 'b', 'x', 'y', 'z') """ if rename_vertices: - vertex_set = (["L" + str(v) for v in self] - + ["R" + str(w) for w in right]) + vertex_set = ["L" + str(v) for v in self] + ["R" + str(w) for w in right] else: vertex_set = self.__tuple + right.__tuple return Simplex(vertex_set) @@ -687,8 +678,7 @@ def alexander_whitney(self, dim): sage: s.alexander_whitney(2) [(1, (0, 1, 3), (3, 4))] """ - return [(ZZ.one(), Simplex(self.tuple()[:dim + 1]), - Simplex(self.tuple()[dim:]))] + return [(ZZ.one(), Simplex(self.tuple()[: dim + 1]), Simplex(self.tuple()[dim:]))] def __eq__(self, other) -> bool: """ @@ -945,15 +935,9 @@ class SimplicialComplex(Parent, GenericCellComplex): However this is close enough to being a parent with elements being the faces of ``self`` that we currently allow this abuse. """ + @rename_keyword(deprecation=41756, is_immutable='immutable') - def __init__(self, - maximal_faces=None, - from_characteristic_function=None, - maximality_check=True, - sort_facets=None, - name_check=False, - immutable=False, - category=None) -> None: + def __init__(self, maximal_faces=None, from_characteristic_function=None, maximality_check=True, sort_facets=None, name_check=False, immutable=False, category=None) -> None: """ Define a simplicial complex. See ``SimplicialComplex`` for more documentation. @@ -1002,8 +986,7 @@ def __init__(self, sage: S._vertex_to_index['b'] 3 """ - if (maximal_faces is not None and - from_characteristic_function is not None): + if maximal_faces is not None and from_characteristic_function is not None: raise ValueError("maximal_faces and from_characteristic_function cannot be both defined") category = SimplicialComplexes().Finite().or_subcategory(category) Parent.__init__(self, category=category) @@ -1012,6 +995,7 @@ def __init__(self, vertices = () if from_characteristic_function is not None: from sage.combinat.subsets_hereditary import subsets_with_hereditary_property + f, X = from_characteristic_function maximal_faces = subsets_with_hereditary_property(f, X) @@ -1085,8 +1069,7 @@ def __init__(self, for face in maximal_simplices: # check whether each given face is actually maximal - if (maximality_check and - any(face.is_face(other) for other in good_faces)): + if maximality_check and any(face.is_face(other) for other in good_faces): continue # This sorting is crucial for homology computations: face = Simplex(sorted(face.tuple(), key=vertex_to_index.__getitem__)) @@ -1333,8 +1316,7 @@ def faces(self, subcomplex=None): """ # Make the subcomplex immutable if it is not if subcomplex is not None and not subcomplex._is_immutable: - subcomplex = SimplicialComplex(subcomplex._facets, maximality_check=False, - immutable=True) + subcomplex = SimplicialComplex(subcomplex._facets, maximality_check=False, immutable=True) if subcomplex not in self._faces: # Faces is the dictionary of faces in self but not in @@ -1360,11 +1342,11 @@ def faces(self, subcomplex=None): for dim in range(dimension, -1, -1): # bad_bdries = boundaries of bad_faces: things to be # discarded in dim-1 - bad_bdries = sub_facets[dim-1] + bad_bdries = sub_facets[dim - 1] for f in bad_faces: bad_bdries.update(f.faces()) for f in Faces[dim]: - Faces[dim-1].update(set(f.faces()).difference(bad_bdries)) + Faces[dim - 1].update(set(f.faces()).difference(bad_bdries)) bad_faces = bad_bdries self._faces[subcomplex] = Faces return self._faces[subcomplex] @@ -1464,13 +1446,14 @@ def h_vector(self): [1, 3, 3, 1] """ from sage.arith.misc import binomial + d = self.dimension() f = self.f_vector() # indexed starting at 0, since it's a Python list h = [] for j in range(d + 2): s = 0 for i in range(-1, j): - s += (-1)**(j-i-1) * binomial(d-i, j-i-1) * f[i+1] + s += (-1) ** (j - i - 1) * binomial(d - i, j - i - 1) * f[i + 1] h.append(s) return h @@ -1498,7 +1481,7 @@ def g_vector(self): h = self.h_vector() g = [1] for i in range(1, (d + 1) // 2 + 1): - g.append(h[i] - h[i-1]) + g.append(h[i] - h[i - 1]) return g def face(self, simplex, i): @@ -1552,7 +1535,7 @@ def f_triangle(self): sage: X.f_triangle() [[0], [0, 0], [0, 0, 0], [1, 5, 8, 3]] """ - ret = [[0]*(i+1) for i in range(self.dimension() + 2)] + ret = [[0] * (i + 1) for i in range(self.dimension() + 2)] facets = [set(F) for F in self.facets()] faces = self.faces() for d in faces: @@ -1585,12 +1568,12 @@ def h_triangle(self): [1, 2, -1, 0]] """ from sage.arith.misc import binomial - ret = [[0]*(i+1) for i in range(self.dimension() + 2)] + + ret = [[0] * (i + 1) for i in range(self.dimension() + 2)] f = self.f_triangle() for i, row in enumerate(ret): - for j in range(i+1): - row[j] = sum((-1)**(j-k) * binomial(i-k, j-k) * f[i][k] - for k in range(j+1)) + for j in range(i + 1): + row[j] = sum((-1) ** (j - k) * binomial(i - k, j - k) * f[i][k] for k in range(j + 1)) return ret def F_triangle(self, S): @@ -1629,8 +1612,7 @@ def nega(f): def posi(f): return f.dimension() + 1 - nega(f) - poly = sum(x**posi(fa) * y**nega(fa) - for fa in self.face_iterator()) + poly = sum(x ** posi(fa) * y ** nega(fa) for fa in self.face_iterator()) return F_triangle(poly) def flip_graph(self): @@ -1700,8 +1682,8 @@ def flip_graph(self): F_tuple = sorted(F._Simplex__set) except TypeError: F_tuple = tuple(F._Simplex__set) - for i in range(d+1): - coF = tuple(F_tuple[:i]+F_tuple[i+1:]) + for i in range(d + 1): + coF = tuple(F_tuple[:i] + F_tuple[i + 1 :]) if coF in edges: for G in edges[coF]: flipG.add_edge((F, G)) @@ -1912,8 +1894,7 @@ def cone(self, immutable=False): sage: CS.facets() == set([Simplex(['L0', 'R0']), Simplex(['L1', 'R0'])]) True """ - return self.join(SimplicialComplex([["0"]], immutable=immutable), - rename_vertices=True) + return self.join(SimplicialComplex([["0"]], immutable=immutable), rename_vertices=True) def suspension(self, n=1, immutable=False): r""" @@ -1986,9 +1967,8 @@ def suspension(self, n=1, immutable=False): new_facets.append(f.join(Simplex([u]), rename_vertices=False)) new_facets.append(f.join(w, rename_vertices=False)) return SimplicialComplex(new_facets) - return self.join(SimplicialComplex([["0"], ["1"]], immutable=immutable), - rename_vertices=True) - return self.suspension(1, immutable).suspension(int(n-1), immutable) + return self.join(SimplicialComplex([["0"], ["1"]], immutable=immutable), rename_vertices=True) + return self.suspension(1, immutable).suspension(int(n - 1), immutable) def disjoint_union(self, right, immutable=False): """ @@ -2063,9 +2043,7 @@ def wedge(self, right, rename_vertices=True, immutable=False): facets = self._facets + right._facets return SimplicialComplex(facets, immutable=immutable) - def chain_complex(self, subcomplex=None, augmented=False, - verbose=False, check=False, dimensions=None, - base_ring=ZZ, cochain=False): + def chain_complex(self, subcomplex=None, augmented=False, verbose=False, check=False, dimensions=None, base_ring=ZZ, cochain=False): r""" The chain complex associated to this simplicial complex. @@ -2118,8 +2096,7 @@ def chain_complex(self, subcomplex=None, augmented=False, augmented = False # Use an immutable copy of the subcomplex if subcomplex._is_immutable: - subcomplex = SimplicialComplex(subcomplex._facets, maximality_check=False, - immutable=True) + subcomplex = SimplicialComplex(subcomplex._facets, maximality_check=False, immutable=True) # now construct the range of dimensions in which to compute if dimensions is None: dimensions = range(self.dimension() + 1) @@ -2138,11 +2115,9 @@ def chain_complex(self, subcomplex=None, augmented=False, current = self._n_cells_sorted(0, subcomplex=subcomplex) current_dim = 0 if cochain: - differentials[-1] = matrix(base_ring, len(current), 1, - [1]*len(current)) + differentials[-1] = matrix(base_ring, len(current), 1, [1] * len(current)) else: - differentials[0] = matrix(base_ring, 1, len(current), - [1]*len(current)) + differentials[0] = matrix(base_ring, 1, len(current), [1] * len(current)) elif first == 0 and not augmented: current = self._n_cells_sorted(0, subcomplex=subcomplex) current_dim = 0 @@ -2158,8 +2133,8 @@ def chain_complex(self, subcomplex=None, augmented=False, print(" starting dimension %s" % n) if (n, subcomplex) in self._complex: if cochain: - differentials[n-1] = self._complex[(n, subcomplex)].transpose().change_ring(base_ring) - mat = differentials[n-1] + differentials[n - 1] = self._complex[(n, subcomplex)].transpose().change_ring(base_ring) + mat = differentials[n - 1] else: differentials[n] = self._complex[(n, subcomplex)].change_ring(base_ring) mat = differentials[n] @@ -2174,10 +2149,10 @@ def chain_complex(self, subcomplex=None, augmented=False, # 1, 2, ... (the index of the face). finding an entry # in a dictionary seems to be faster than finding the # index of an entry in a list. - if current_dim == n-1: + if current_dim == n - 1: old = dict(zip(current, range(len(current)))) else: - set_of_faces = self._n_cells_sorted(n-1, subcomplex=subcomplex) + set_of_faces = self._n_cells_sorted(n - 1, subcomplex=subcomplex) old = dict(zip(set_of_faces, range(len(set_of_faces)))) current = self._n_cells_sorted(n, subcomplex=subcomplex) current_dim = n @@ -2191,14 +2166,14 @@ def chain_complex(self, subcomplex=None, augmented=False, for i in range(n + 1): face_i = simplex.face(i) try: - matrix_data[(old[face_i], col)] = (-1)**i + matrix_data[(old[face_i], col)] = (-1) ** i except KeyError: pass col += 1 mat = matrix(ZZ, len(old), len(current), matrix_data) if cochain: self._complex[(n, subcomplex)] = mat - differentials[n-1] = mat.transpose().change_ring(base_ring) + differentials[n - 1] = mat.transpose().change_ring(base_ring) else: self._complex[(n, subcomplex)] = mat differentials[n] = mat.change_ring(base_ring) @@ -2208,21 +2183,17 @@ def chain_complex(self, subcomplex=None, augmented=False, # hand, and don't cache it. if cochain: n = dimensions[-1] + 1 - if current_dim != n-1: - current = self._n_cells_sorted(n-1, subcomplex=subcomplex) - differentials[n-1] = matrix(base_ring, 0, len(current)) + if current_dim != n - 1: + current = self._n_cells_sorted(n - 1, subcomplex=subcomplex) + differentials[n - 1] = matrix(base_ring, 0, len(current)) # finally, return the chain complex from sage.homology.chain_complex import ChainComplex if cochain: - return ChainComplex(data=differentials, degree=1, - base_ring=base_ring, check=check) - return ChainComplex(data=differentials, degree=-1, - base_ring=base_ring, check=check) + return ChainComplex(data=differentials, degree=1, base_ring=base_ring, check=check) + return ChainComplex(data=differentials, degree=-1, base_ring=base_ring, check=check) - def _homology_(self, dim=None, base_ring=ZZ, subcomplex=None, - cohomology=False, enlarge=True, algorithm='pari', - verbose=False, reduced=True, generators=False): + def _homology_(self, dim=None, base_ring=ZZ, subcomplex=None, cohomology=False, enlarge=True, algorithm='pari', verbose=False, reduced=True, generators=False): """ The (reduced) homology of this simplicial complex. @@ -2361,7 +2332,7 @@ def _homology_(self, dim=None, base_ring=ZZ, subcomplex=None, L = self._contractible_subcomplex(verbose=verbose) if verbose: print("Done finding contractible subcomplex.") - vec = [len(self.faces(subcomplex=L)[n-1]) for n in range(self.dimension()+2)] + vec = [len(self.faces(subcomplex=L)[n - 1]) for n in range(self.dimension() + 2)] print("The difference between the f-vectors is:") print(" %s" % vec) else: @@ -2379,14 +2350,11 @@ def _homology_(self, dim=None, base_ring=ZZ, subcomplex=None, if verbose: print("Computing the chain complex...") - C = self.chain_complex(dimensions=dims, augmented=reduced, - cochain=cohomology, base_ring=base_ring, - subcomplex=L, verbose=verbose) + C = self.chain_complex(dimensions=dims, augmented=reduced, cochain=cohomology, base_ring=base_ring, subcomplex=L, verbose=verbose) if verbose: print(" Done computing the chain complex. ") print("Now computing homology...") - answer = C.homology(base_ring=base_ring, verbose=verbose, - algorithm=algorithm, generators=generators) + answer = C.homology(base_ring=base_ring, verbose=verbose, algorithm=algorithm, generators=generators) if generators: # Convert chain complex information to simplicial complex @@ -2478,6 +2446,7 @@ def algebraic_topological_model(self, base_ring=None): 2: Vector space of dimension 1 over Rational Field} """ from sage.homology.algebraic_topological_model import algebraic_topological_model + if base_ring is None: base_ring = QQ return algebraic_topological_model(self, base_ring) @@ -2629,7 +2598,7 @@ def add_face(self, face): all_new_faces = SimplicialComplex([new_face]).faces() for L in self._faces: L_complex = self._faces[L] - for dim in range(new_face.dimension()+1): + for dim in range(new_face.dimension() + 1): if dim in L_complex: if L is None: new_faces = all_new_faces[dim] @@ -2640,7 +2609,7 @@ def add_face(self, face): L_complex[dim] = all_new_faces[dim] # update self._graph if necessary if self._graph is not None: - d = new_face.dimension()+1 + d = new_face.dimension() + 1 for i in range(d): for j in range(i + 1, d): self._graph.add_edge(new_face[i], new_face[j]) @@ -2906,8 +2875,7 @@ def connected_sum(self, other, immutable=False): sage: (P + P).homology()[1] # needs sage.modules Z x C2 """ - if not (self.is_pure() and other.is_pure() and - self.dimension() == other.dimension()): + if not (self.is_pure() and other.is_pure() and self.dimension() == other.dimension()): raise ValueError("complexes are not pure of the same dimension") # first find a top-dimensional simplex to remove from each surface keep_left = self._facets[0] @@ -2915,10 +2883,7 @@ def connected_sum(self, other, immutable=False): # construct the set of facets: left = set(self._facets).difference({keep_left}) right = set(other._facets).difference({keep_right}) - facet_set = ([[rename_vertex(v, keep=list(keep_left)) - for v in face] for face in left] - + [[rename_vertex(v, keep=list(keep_right), left=False) - for v in face] for face in right]) + facet_set = [[rename_vertex(v, keep=list(keep_left)) for v in face] for face in left] + [[rename_vertex(v, keep=list(keep_right), left=False) for v in face] for face in right] # return the new surface return SimplicialComplex(facet_set, immutable=immutable) @@ -3047,6 +3012,7 @@ def is_cohen_macaulay(self, base_ring=QQ, ncpus=0) -> bool: if not ncpus: from sage.parallel.ncpus import ncpus as get_ncpus + ncpus = get_ncpus() facs = list(self.face_iterator()) @@ -3096,8 +3062,7 @@ def generated_subcomplex(self, sub_vertex_set, immutable=None): faces.append(j) if immutable is None: immutable = self._is_immutable - return SimplicialComplex(faces, maximality_check=True, - immutable=immutable) + return SimplicialComplex(faces, maximality_check=True, immutable=immutable) def is_shelling_order(self, shelling_order, certificate=False) -> bool: r""" @@ -3262,8 +3227,7 @@ def is_shellable(self, certificate=False) -> bool: common = set(F).intersection(set(cur_complex.vertices())) intersection = cur_complex.generated_subcomplex(list(common)) - if (not intersection.is_pure() - or F.dimension() - 1 != intersection.dimension()): + if not intersection.is_pure() or F.dimension() - 1 != intersection.dimension(): continue cur_complex.add_face(F) cur_order.append(F) @@ -3479,7 +3443,7 @@ def minimal_nonfaces(self): if new: set_mnf.add(set_candidate) - for candidate in combinations(vertices, dimension+2): # Checks for minimal nonfaces in the remaining dimension + for candidate in combinations(vertices, dimension + 2): # Checks for minimal nonfaces in the remaining dimension set_candidate = frozenset(candidate) new = not any(set_candidate.issuperset(mnf) for mnf in set_mnf) if new: @@ -3782,18 +3746,19 @@ def delta_complex(self, sort_simplices=False): True """ from .delta_complex import DeltaComplex + data = {} dim = self.dimension() n_cells = self._n_cells_sorted(dim) if sort_simplices: n_cells.sort() for n in range(dim, -1, -1): - bdries = self._n_cells_sorted(n-1) + bdries = self._n_cells_sorted(n - 1) if sort_simplices: bdries.sort() data[n] = [] for f in n_cells: - data[n].append([bdries.index(f.face(i)) for i in range(n+1)]) + data[n].append([bdries.index(f.face(i)) for i in range(n + 1)]) n_cells = bdries return DeltaComplex(data) @@ -3939,9 +3904,7 @@ def _enlarge_subcomplex(self, subcomplex, verbose=False): """ # Make the subcomplex immutable if not if subcomplex is not None and not subcomplex._is_immutable: - subcomplex = SimplicialComplex(subcomplex._facets, - maximality_check=False, - immutable=True) + subcomplex = SimplicialComplex(subcomplex._facets, maximality_check=False, immutable=True) if subcomplex in self.__enlarged: return self.__enlarged[subcomplex] @@ -3954,14 +3917,7 @@ def _enlarge_subcomplex(self, subcomplex, verbose=False): face_sets = {f: f.set() for f in faces} # Track nonempty intersections incrementally to avoid recomputing all # intersections from scratch in every pass. - intersections = { - f: { - inter - for a_set in new_facet_sets - if (inter := a_set.intersection(face_sets[f])) - } - for f in faces - } + intersections = {f: {inter for a_set in new_facet_sets if (inter := a_set.intersection(face_sets[f]))} for f in faces} # Cache contractibility tests for repeated intersection complexes. contractible_intersections = {} while not done: @@ -3979,7 +3935,7 @@ def _enlarge_subcomplex(self, subcomplex, verbose=False): is_contractible = contractible_intersections.get(key) if is_contractible is None: intersection = SimplicialComplex(int_facets) - is_contractible = (intersection == intersection._contractible_subcomplex()) + is_contractible = intersection == intersection._contractible_subcomplex() contractible_intersections[key] = is_contractible if is_contractible: new_facets.append(f) @@ -4002,8 +3958,7 @@ def _enlarge_subcomplex(self, subcomplex, verbose=False): face_sets.pop(f, None) if verbose: print(" now constructing a simplicial complex with {} vertices and {} facets".format(len(self.vertices()), len(new_facets))) - L = SimplicialComplex(new_facets, maximality_check=False, - immutable=self._is_immutable) + L = SimplicialComplex(new_facets, maximality_check=False, immutable=self._is_immutable) self.__enlarged[subcomplex] = L # Use the same sorting on the vertices in L as in the ambient complex. L._vertex_to_index = self._vertex_to_index @@ -4056,6 +4011,7 @@ def _cubical_(self): {0: 0, 1: Z x Z, 2: Z} """ from .cubical_complex import CubicalComplex + V = self.vertices() embed = len(V) # dictionary to translate vertices to the numbers 1, ..., embed @@ -4068,7 +4024,7 @@ def _cubical_(self): # set to 0. if not in J, set to 1. Otherwise, range # from 0 to 1 cube = [] - for n in range(1, embed+1): + for n in range(1, embed + 1): if n == i: cube.append([0]) elif n not in J: @@ -4207,14 +4163,14 @@ def fundamental_group(self, base_point=None, simplify=True): from sage.groups.free_group import FreeGroup from sage.libs.gap.libgap import libgap + G = self.graph() # Edges in the graph may be sorted differently than in the # simplicial complex, so convert the edges to frozensets so we # don't have to worry about it. Convert spanning_tree to a set # to make lookup faster. spanning_tree = {frozenset((u, v)) for u, v, _ in G.min_spanning_tree()} - gens = [e for e in G.edge_iterator(labels=False) - if frozenset(e) not in spanning_tree] + gens = [e for e in G.edge_iterator(labels=False) if frozenset(e) not in spanning_tree] if not gens: return libgap.TrivialGroup() @@ -4230,7 +4186,7 @@ def fundamental_group(self, base_point=None, simplify=True): z[i] = FG.one() else: z[i] = FG.gen(gens_dict[x]) - rels.append(z[0]*z[1].inverse()*z[2]) + rels.append(z[0] * z[1].inverse() * z[2]) if simplify: return FG.quotient(rels).simplified() return FG.quotient(rels) @@ -4267,9 +4223,7 @@ def is_isomorphic(self, other, certificate=False) -> bool: (True, {1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e', 6: 'f'}) """ # Check easy invariants agree - if (sorted(x.dimension() for x in self._facets) - != sorted(x.dimension() for x in other._facets) - or len(self.vertices()) != len(other.vertices())): + if sorted(x.dimension() for x in self._facets) != sorted(x.dimension() for x in other._facets) or len(self.vertices()) != len(other.vertices()): return False from sage.graphs.graph import Graph @@ -4285,10 +4239,8 @@ def is_isomorphic(self, other, certificate=False) -> bool: g1.add_edges((self_to_int[v], self_to_int[f], "generic edge") for f in self._facets for v in f) g2.add_edges((other_to_int[v], other_to_int[f], "generic edge") for f in other._facets for v in f) fake = -1 - g1.add_edges((fake, self_to_int[v], "special_edge") - for v in self.vertices()) - g2.add_edges((fake, other_to_int[v], "special_edge") - for v in other.vertices()) + g1.add_edges((fake, self_to_int[v], "special_edge") for v in self.vertices()) + g2.add_edges((fake, other_to_int[v], "special_edge") for v in other.vertices()) if not certificate: return g1.is_isomorphic(g2, edge_labels=True) isisom, tr = g1.is_isomorphic(g2, edge_labels=True, certificate=True) @@ -4345,13 +4297,9 @@ def automorphism_group(self): G = Graph() G.add_vertices(self.vertices()) G.add_edges((f.tuple(), v) for f in self.facets() for v in f) - group = G.automorphism_group(partition=[list(self.vertices()), - [f.tuple() - for f in self.facets()]]) + group = G.automorphism_group(partition=[list(self.vertices()), [f.tuple() for f in self.facets()]]) - gens = [[tuple(c) for c in g.cycle_tuples() - if c[0] in self.vertices()] - for g in group.gens()] + gens = [[tuple(c) for c in g.cycle_tuples() if c[0] in self.vertices()] for g in group.gens()] return PermutationGroup(gens=gens, domain=self.vertices()) @@ -4399,18 +4347,16 @@ def fixed_complex(self, G): True """ from sage.categories.groups import Groups + if G in Groups(): gens = G.gens() else: gens = G G = self.automorphism_group().subgroup(gens) - invariant_f = [tuple(u) for u in self.face_iterator() - if all(sorted(sigma(j) for j in u) == sorted(u) - for sigma in gens)] + invariant_f = [tuple(u) for u in self.face_iterator() if all(sorted(sigma(j) for j in u) == sorted(u) for sigma in gens)] new_verts = [min(o) for o in G.orbits() if o in invariant_f] - return SimplicialComplex([[s for s in f if s in new_verts] - for f in invariant_f]) + return SimplicialComplex([[s for s in f if s in new_verts] for f in invariant_f]) def _Hom_(self, other, category=None): """ @@ -4446,6 +4392,7 @@ def _Hom_(self, other, category=None): if not category.is_subcategory(SimplicialComplexes()): raise TypeError("{} is not a subcategory of SimplicialComplexes()".format(category)) from sage.topology.simplicial_complex_homset import SimplicialComplexHomset + return SimplicialComplexHomset(self, other) # @cached_method when we switch to immutable SimplicialComplex @@ -4465,8 +4412,7 @@ def _is_numeric(self): sage: s._is_numeric() False """ - return all(isinstance(v, (int, Integer)) - for v in self.vertices()) + return all(isinstance(v, (int, Integer)) for v in self.vertices()) # @cached_method when we switch to immutable SimplicialComplex def _translation_to_numeric(self): @@ -4718,8 +4664,7 @@ def is_balanced(self, check_purity=False, certificate=False) -> bool: return C return Skel.chromatic_number() == d - def is_partitionable(self, certificate=False, - *, solver=None, integrality_tolerance=1e-3): + def is_partitionable(self, certificate=False, *, solver=None, integrality_tolerance=1e-3): r""" Determine whether ``self`` is partitionable. @@ -4793,17 +4738,16 @@ def is_partitionable(self, certificate=False, False """ from sage.numerical.mip import MixedIntegerLinearProgram - RFPairs = [(Simplex(r), f, f.dimension() - len(r) + 1) - for f in self.facets() for r in Set(f).subsets()] + + RFPairs = [(Simplex(r), f, f.dimension() - len(r) + 1) for f in self.facets() for r in Set(f).subsets()] n = len(RFPairs) IP = MixedIntegerLinearProgram(solver=solver) y = IP.new_variable(binary=True) for i0, pair0 in enumerate(RFPairs): for i1, pair1 in enumerate(RFPairs): - if (i0 < i1 and pair0[0].is_face(pair1[1]) and - pair1[0].is_face(pair0[1])): + if i0 < i1 and pair0[0].is_face(pair1[1]) and pair1[0].is_face(pair0[1]): IP.add_constraint(y[i0] + y[i1] <= 1) - IP.set_objective(sum(2**RFPairs[i][2] * y[i] for i in range(n))) + IP.set_objective(sum(2 ** RFPairs[i][2] * y[i] for i in range(n))) sol = round(IP.solve()) if sol < sum(self.f_vector()): return False @@ -4913,6 +4857,7 @@ def bigraded_betti_numbers(self, base_ring=ZZ, verbose=False): return self._bbn[base_ring] from sage.homology.homology_group import HomologyGroup + L = self.vertices() n = len(L) B = {} @@ -4920,18 +4865,18 @@ def bigraded_betti_numbers(self, base_ring=ZZ, verbose=False): B[(0, 0)] = ZZ.one() - for j in range(n+1): + for j in range(n + 1): for x in combinations(L, j): S = self.generated_subcomplex(x) H = S.homology(base_ring=base_ring) for k in range(j): - if j-k-1 in H and H[j-k-1] != H0: - ind = (-k, 2*j) + if j - k - 1 in H and H[j - k - 1] != H0: + ind = (-k, 2 * j) if ind not in B: B[ind] = ZZ.zero() - B[ind] += len(H[j-k-1].gens()) + B[ind] += len(H[j - k - 1].gens()) if verbose: - print("{}: Non-trivial homology {} in dimension {} of the full subcomplex generated by a set of vertices {}".format(ind, H[j-k-1], j-k-1, x)) + print("{}: Non-trivial homology {} in dimension {} of the full subcomplex generated by a set of vertices {}".format(ind, H[j - k - 1], j - k - 1, x)) self._bbn[base_ring] = B self._bbn_all_computed.add(base_ring) @@ -5007,17 +4952,17 @@ def bigraded_betti_number(self, a, b, base_ring=ZZ, verbose=False): for x in combinations(L, b): S = self.generated_subcomplex(x) H = S.homology(base_ring=base_ring) - if b+a-1 in H and H[b+a-1] != H0: - B += len(H[b+a-1].gens()) + if b + a - 1 in H and H[b + a - 1] != H0: + B += len(H[b + a - 1].gens()) if verbose: - print("Non-trivial homology {} in dimension {} of the full subcomplex generated by a set of vertices {}".format(H[b+a-1], b+a-1, x)) + print("Non-trivial homology {} in dimension {} of the full subcomplex generated by a set of vertices {}".format(H[b + a - 1], b + a - 1, x)) B = ZZ(B) if base_ring in self._bbn: - self._bbn[base_ring][(a, 2*b)] = B + self._bbn[base_ring][(a, 2 * b)] = B else: - self._bbn[base_ring] = {(a, 2*b): B} + self._bbn[base_ring] = {(a, 2 * b): B} return B @@ -5073,6 +5018,7 @@ def is_minimally_non_golod(self) -> bool: sage: Y.is_minimally_non_golod() False """ + def test(v): X = copy(self) X.remove_face([v]) @@ -5111,6 +5057,7 @@ def moment_angle_complex(self): (0, 1, 2, 3, 4, 5, 6, 7) and 16 facets """ from .moment_angle_complex import MomentAngleComplex + return MomentAngleComplex(self) @@ -5122,6 +5069,7 @@ def moment_angle_complex(self): # hard-coded. Thus the following functions are not currently used in # the Sage library. + def facets_for_RP4(): """ Return the list of facets for a minimal triangulation of 4-dimensional @@ -5142,6 +5090,7 @@ def facets_for_RP4(): """ # Define the group: from sage.groups.perm_gps.permgroup import PermutationGroup + g1 = '(2,7)(4,10)(5,6)(11,12)' g2 = '(1, 2, 3, 4, 5, 10)(6, 8, 9)(11, 12, 13, 14, 15, 16)' G = PermutationGroup([g1, g2]) @@ -5179,8 +5128,6 @@ def facets_for_K3(): True """ from sage.groups.perm_gps.permgroup import PermutationGroup - G = PermutationGroup([[(1, 3, 8, 4, 9, 16, 15, 2, 14, 12, 6, 7, 13, 5, 10)], - [(1, 11, 16), (2, 10, 14), (3, 12, 13), - (4, 9, 15), (5, 7, 8)]]) - return ([tuple([g(i) for i in (1, 2, 3, 8, 12)]) for g in G] - + [tuple([g(i) for i in (1, 2, 5, 8, 14)]) for g in G]) + + G = PermutationGroup([[(1, 3, 8, 4, 9, 16, 15, 2, 14, 12, 6, 7, 13, 5, 10)], [(1, 11, 16), (2, 10, 14), (3, 12, 13), (4, 9, 15), (5, 7, 8)]]) + return [tuple([g(i) for i in (1, 2, 3, 8, 12)]) for g in G] + [tuple([g(i) for i in (1, 2, 5, 8, 14)]) for g in G] diff --git a/src/sage/topology/simplicial_complex_catalog.py b/src/sage/topology/simplicial_complex_catalog.py index 185b37b09ec..594c60bbed7 100644 --- a/src/sage/topology/simplicial_complex_catalog.py +++ b/src/sage/topology/simplicial_complex_catalog.py @@ -67,24 +67,7 @@ {0: 0, 1: Z^16, 2: 0} """ -from sage.topology.simplicial_complex_examples import (Sphere, Simplex, Torus, - ProjectivePlane, - RealProjectivePlane, KleinBottle, - FareyMap, GenusSix, - SurfaceOfGenus, - MooreSpace, - ComplexProjectivePlane, - QuaternionicProjectivePlane, - PoincareHomologyThreeSphere, - RealProjectiveSpace, K3Surface, - BarnetteSphere, - BrucknerGrunbaumSphere, - NotIConnectedGraphs, - MatchingComplex, - ChessboardComplex, RandomComplex, - SumComplex, - RandomTwoSphere, ShiftedComplex, - RudinBall, ZieglerBall, DunceHat) +from sage.topology.simplicial_complex_examples import Sphere, Simplex, Torus, ProjectivePlane, RealProjectivePlane, KleinBottle, FareyMap, GenusSix, SurfaceOfGenus, MooreSpace, ComplexProjectivePlane, QuaternionicProjectivePlane, PoincareHomologyThreeSphere, RealProjectiveSpace, K3Surface, BarnetteSphere, BrucknerGrunbaumSphere, NotIConnectedGraphs, MatchingComplex, ChessboardComplex, RandomComplex, SumComplex, RandomTwoSphere, ShiftedComplex, RudinBall, ZieglerBall, DunceHat from sage.combinat.posets.hochschild_lattice import hochschild_simplicial_complex as HochschildSphere diff --git a/src/sage/topology/simplicial_complex_examples.py b/src/sage/topology/simplicial_complex_examples.py index 0f7b92a9c5f..f5973bd53a2 100644 --- a/src/sage/topology/simplicial_complex_examples.py +++ b/src/sage/topology/simplicial_complex_examples.py @@ -67,6 +67,7 @@ from .simplicial_complex import SimplicialComplex from sage.structure.unique_representation import UniqueRepresentation + # Below we define a function Simplex to construct a simplex as a # simplicial complex. We also need to use actual simplices as # simplices, hence: @@ -106,6 +107,7 @@ def facets_for_RP4(): """ # Define the group: from sage.groups.perm_gps.permgroup import PermutationGroup + g1 = '(2, 7)(4, 10)(5, 6)(11, 12)' g2 = '(1, 2, 3, 4, 5, 10)(6, 8, 9)(11, 12, 13, 14, 15, 16)' G = PermutationGroup([g1, g2]) @@ -143,10 +145,9 @@ def facets_for_K3(): True """ from sage.groups.perm_gps.permgroup import PermutationGroup - G = PermutationGroup([[(1, 3, 8, 4, 9, 16, 15, 2, 14, 12, 6, 7, 13, 5, 10)], - [(1, 11, 16), (2, 10, 14), (3, 12, 13), (4, 9, 15), (5, 7, 8)]]) - return ([tuple([g(i) for i in (1, 2, 3, 8, 12)]) for g in G] + - [tuple([g(i) for i in (1, 2, 5, 8, 14)]) for g in G]) + + G = PermutationGroup([[(1, 3, 8, 4, 9, 16, 15, 2, 14, 12, 6, 7, 13, 5, 10)], [(1, 11, 16), (2, 10, 14), (3, 12, 13), (4, 9, 15), (5, 7, 8)]]) + return [tuple([g(i) for i in (1, 2, 3, 8, 12)]) for g in G] + [tuple([g(i) for i in (1, 2, 5, 8, 14)]) for g in G] def matching(A, B): @@ -208,6 +209,7 @@ class UniqueSimplicialComplex(SimplicialComplex, UniqueRepresentation): sage: UniqueSimplicialComplex([[0, 1]], name='The 1-simplex') The 1-simplex """ + @staticmethod def __classcall__(self, maximal_faces=None, name=None, **kwds): """ @@ -280,6 +282,7 @@ def _repr_(self): return self._name return SimplicialComplex._repr_(self) + # Now the functions that produce the actual examples... @@ -307,10 +310,9 @@ def Sphere(n): [1, 6, 15, 20, 15, 6], [1, 7, 21, 35, 35, 21, 7]] """ - S = TrueSimplex(n+1) + S = TrueSimplex(n + 1) facets = tuple(S.faces()) - return UniqueSimplicialComplex(facets, - name='Minimal triangulation of the {}-sphere'.format(n)) + return UniqueSimplicialComplex(facets, name='Minimal triangulation of the {}-sphere'.format(n)) def Simplex(n): @@ -331,8 +333,7 @@ def Simplex(n): sage: simplicial_complexes.Simplex(5).euler_characteristic() 1 """ - return UniqueSimplicialComplex([TrueSimplex(n)], - name='The {}-simplex'.format(n)) + return UniqueSimplicialComplex([TrueSimplex(n)], name='The {}-simplex'.format(n)) def Torus(): @@ -363,11 +364,7 @@ def Torus(): - [Lut2002]_ """ - return UniqueSimplicialComplex([[0, 1, 2], [1, 2, 4], [1, 3, 4], [1, 3, 6], - [0, 1, 5], [1, 5, 6], [2, 3, 5], [2, 4, 5], - [2, 3, 6], [0, 2, 6], [0, 3, 4], [0, 3, 5], - [4, 5, 6], [0, 4, 6]], - name='Minimal triangulation of the torus') + return UniqueSimplicialComplex([[0, 1, 2], [1, 2, 4], [1, 3, 4], [1, 3, 6], [0, 1, 5], [1, 5, 6], [2, 3, 5], [2, 4, 5], [2, 3, 6], [0, 2, 6], [0, 3, 4], [0, 3, 5], [4, 5, 6], [0, 4, 6]], name='Minimal triangulation of the torus') def RealProjectivePlane(): @@ -391,10 +388,7 @@ def RealProjectivePlane(): sage: P.cohomology(2, base_ring=GF(2)) Vector space of dimension 1 over Finite Field of size 2 """ - return UniqueSimplicialComplex([[0, 1, 2], [0, 2, 3], [0, 1, 5], [0, 4, 5], - [0, 3, 4], [1, 2, 4], [1, 3, 4], [1, 3, 5], - [2, 3, 5], [2, 4, 5]], - name='Minimal triangulation of the real projective plane') + return UniqueSimplicialComplex([[0, 1, 2], [0, 2, 3], [0, 1, 5], [0, 4, 5], [0, 3, 4], [1, 2, 4], [1, 3, 4], [1, 3, 5], [2, 3, 5], [2, 4, 5]], name='Minimal triangulation of the real projective plane') ProjectivePlane = RealProjectivePlane @@ -410,11 +404,7 @@ def KleinBottle(): sage: simplicial_complexes.KleinBottle() Minimal triangulation of the Klein bottle """ - return UniqueSimplicialComplex([[2, 3, 7], [1, 2, 3], [1, 3, 5], [1, 5, 7], - [1, 4, 7], [2, 4, 6], [1, 2, 6], [1, 6, 0], - [1, 4, 0], [2, 4, 0], [3, 4, 7], [3, 4, 6], - [3, 5, 6], [5, 6, 0], [2, 5, 0], [2, 5, 7]], - name='Minimal triangulation of the Klein bottle') + return UniqueSimplicialComplex([[2, 3, 7], [1, 2, 3], [1, 3, 5], [1, 5, 7], [1, 4, 7], [2, 4, 6], [1, 2, 6], [1, 6, 0], [1, 4, 0], [2, 4, 0], [3, 4, 7], [3, 4, 6], [3, 5, 6], [5, 6, 0], [2, 5, 0], [2, 5, 7]], name='Minimal triangulation of the Klein bottle') def SurfaceOfGenus(g, orientable=True): @@ -453,7 +443,7 @@ def SurfaceOfGenus(g, orientable=True): else: T = RealProjectivePlane() S = T - for i in range(g-1): + for i in range(g - 1): S = S.connected_sum(T) if orientable: name_str = 'Triangulation of an orientable surface of genus {}' @@ -506,7 +496,7 @@ def MooreSpace(q): facets = [] for i in range(q): Ai = "A" + str(i) - Aiplus = "A" + str((i+1) % q) + Aiplus = "A" + str((i + 1) % q) Bi = "B" + str(i) facets.append([1, 2, Ai]) facets.append([2, 3, Ai]) @@ -514,12 +504,11 @@ def MooreSpace(q): facets.append([3, Bi, Ai]) facets.append([1, Bi, Aiplus]) facets.append([Bi, Ai, Aiplus]) - for i in range(1, q-1): + for i in range(1, q - 1): Ai = "A" + str(i) - Aiplus = "A" + str((i+1) % q) + Aiplus = "A" + str((i + 1) % q) facets.append(["A0", Ai, Aiplus]) - return UniqueSimplicialComplex(facets, - name='Triangulation of the mod {} Moore space'.format(q)) + return UniqueSimplicialComplex(facets, name='Triangulation of the mod {} Moore space'.format(q)) def ComplexProjectivePlane(): @@ -538,20 +527,7 @@ def ComplexProjectivePlane(): sage: C.homology(4) # needs sage.modules Z """ - return UniqueSimplicialComplex( - [[1, 2, 4, 5, 6], [2, 3, 5, 6, 4], [3, 1, 6, 4, 5], - [1, 2, 4, 5, 9], [2, 3, 5, 6, 7], [3, 1, 6, 4, 8], - [2, 3, 6, 4, 9], [3, 1, 4, 5, 7], [1, 2, 5, 6, 8], - [3, 1, 5, 6, 9], [1, 2, 6, 4, 7], [2, 3, 4, 5, 8], - [4, 5, 7, 8, 9], [5, 6, 8, 9, 7], [6, 4, 9, 7, 8], - [4, 5, 7, 8, 3], [5, 6, 8, 9, 1], [6, 4, 9, 7, 2], - [5, 6, 9, 7, 3], [6, 4, 7, 8, 1], [4, 5, 8, 9, 2], - [6, 4, 8, 9, 3], [4, 5, 9, 7, 1], [5, 6, 7, 8, 2], - [7, 8, 1, 2, 3], [8, 9, 2, 3, 1], [9, 7, 3, 1, 2], - [7, 8, 1, 2, 6], [8, 9, 2, 3, 4], [9, 7, 3, 1, 5], - [8, 9, 3, 1, 6], [9, 7, 1, 2, 4], [7, 8, 2, 3, 5], - [9, 7, 2, 3, 6], [7, 8, 3, 1, 4], [8, 9, 1, 2, 5]], - name='Minimal triangulation of the complex projective plane') + return UniqueSimplicialComplex([[1, 2, 4, 5, 6], [2, 3, 5, 6, 4], [3, 1, 6, 4, 5], [1, 2, 4, 5, 9], [2, 3, 5, 6, 7], [3, 1, 6, 4, 8], [2, 3, 6, 4, 9], [3, 1, 4, 5, 7], [1, 2, 5, 6, 8], [3, 1, 5, 6, 9], [1, 2, 6, 4, 7], [2, 3, 4, 5, 8], [4, 5, 7, 8, 9], [5, 6, 8, 9, 7], [6, 4, 9, 7, 8], [4, 5, 7, 8, 3], [5, 6, 8, 9, 1], [6, 4, 9, 7, 2], [5, 6, 9, 7, 3], [6, 4, 7, 8, 1], [4, 5, 8, 9, 2], [6, 4, 8, 9, 3], [4, 5, 9, 7, 1], [5, 6, 7, 8, 2], [7, 8, 1, 2, 3], [8, 9, 2, 3, 1], [9, 7, 3, 1, 2], [7, 8, 1, 2, 6], [8, 9, 2, 3, 4], [9, 7, 3, 1, 5], [8, 9, 3, 1, 6], [9, 7, 1, 2, 4], [7, 8, 2, 3, 5], [9, 7, 2, 3, 6], [7, 8, 3, 1, 4], [8, 9, 1, 2, 5]], name='Minimal triangulation of the complex projective plane') def QuaternionicProjectivePlane(): @@ -584,27 +560,11 @@ def QuaternionicProjectivePlane(): True """ from sage.groups.perm_gps.permgroup import PermutationGroup + P = [(1, 2, 3, 4, 5), (6, 7, 8, 9, 10), (11, 12, 13, 14, 15)] S = [(1, 6, 11), (2, 15, 14), (3, 13, 8), (4, 7, 5), (9, 12, 10)] - start_list = [ - (1, 2, 3, 6, 8, 11, 13, 14, 15), # A - (1, 3, 6, 8, 9, 10, 11, 12, 13), # B - (1, 2, 6, 9, 10, 11, 12, 14, 15), # C - (1, 2, 3, 4, 7, 9, 12, 14, 15), # D - (1, 2, 4, 7, 9, 10, 12, 13, 14), # E - (1, 2, 6, 8, 9, 10, 11, 14, 15), # F - (1, 2, 3, 4, 5, 6, 9, 11, 13), # G - (1, 3, 5, 6, 8, 9, 10, 11, 12), # H - (1, 3, 5, 6, 7, 8, 9, 10, 11), # I - (1, 2, 3, 4, 5, 7, 10, 12, 15), # J - (1, 2, 3, 7, 8, 10, 12, 13, 14), # K - (2, 5, 6, 7, 8, 9, 10, 13, 14), # M - - (3, 4, 6, 7, 11, 12, 13, 14, 15), # L - (3, 4, 6, 7, 10, 12, 13, 14, 15)] # N - return UniqueSimplicialComplex([[g(index) for index in tup] - for tup in start_list - for g in PermutationGroup([P, S])]) + start_list = [(1, 2, 3, 6, 8, 11, 13, 14, 15), (1, 3, 6, 8, 9, 10, 11, 12, 13), (1, 2, 6, 9, 10, 11, 12, 14, 15), (1, 2, 3, 4, 7, 9, 12, 14, 15), (1, 2, 4, 7, 9, 10, 12, 13, 14), (1, 2, 6, 8, 9, 10, 11, 14, 15), (1, 2, 3, 4, 5, 6, 9, 11, 13), (1, 3, 5, 6, 8, 9, 10, 11, 12), (1, 3, 5, 6, 7, 8, 9, 10, 11), (1, 2, 3, 4, 5, 7, 10, 12, 15), (1, 2, 3, 7, 8, 10, 12, 13, 14), (2, 5, 6, 7, 8, 9, 10, 13, 14), (3, 4, 6, 7, 11, 12, 13, 14, 15), (3, 4, 6, 7, 10, 12, 13, 14, 15)] # A # B # C # D # E # F # G # H # I # J # K # M # L # N + return UniqueSimplicialComplex([[g(index) for index in tup] for tup in start_list for g in PermutationGroup([P, S])]) def PoincareHomologyThreeSphere(): @@ -627,30 +587,100 @@ def PoincareHomologyThreeSphere(): 120 """ return UniqueSimplicialComplex( - [[1, 2, 4, 9], [1, 2, 4, 15], [1, 2, 6, 14], [1, 2, 6, 15], - [1, 2, 9, 14], [1, 3, 4, 12], [1, 3, 4, 15], [1, 3, 7, 10], - [1, 3, 7, 12], [1, 3, 10, 15], [1, 4, 9, 12], [1, 5, 6, 13], - [1, 5, 6, 14], [1, 5, 8, 11], [1, 5, 8, 13], [1, 5, 11, 14], - [1, 6, 13, 15], [1, 7, 8, 10], [1, 7, 8, 11], [1, 7, 11, 12], - [1, 8, 10, 13], [1, 9, 11, 12], [1, 9, 11, 14], [1, 10, 13, 15], - [2, 3, 5, 10], [2, 3, 5, 11], [2, 3, 7, 10], [2, 3, 7, 13], - [2, 3, 11, 13], [2, 4, 9, 13], [2, 4, 11, 13], [2, 4, 11, 15], - [2, 5, 8, 11], [2, 5, 8, 12], [2, 5, 10, 12], [2, 6, 10, 12], - [2, 6, 10, 14], [2, 6, 12, 15], [2, 7, 9, 13], [2, 7, 9, 14], - [2, 7, 10, 14], [2, 8, 11, 15], [2, 8, 12, 15], [3, 4, 5, 14], - [3, 4, 5, 15], [3, 4, 12, 14], [3, 5, 10, 15], [3, 5, 11, 14], - [3, 7, 12, 13], [3, 11, 13, 14], [3, 12, 13, 14], [4, 5, 6, 7], - [4, 5, 6, 14], [4, 5, 7, 15], [4, 6, 7, 11], [4, 6, 10, 11], - [4, 6, 10, 14], [4, 7, 11, 15], [4, 8, 9, 12], [4, 8, 9, 13], - [4, 8, 10, 13], [4, 8, 10, 14], [4, 8, 12, 14], [4, 10, 11, 13], - [5, 6, 7, 13], [5, 7, 9, 13], [5, 7, 9, 15], [5, 8, 9, 12], - [5, 8, 9, 13], [5, 9, 10, 12], [5, 9, 10, 15], [6, 7, 11, 12], - [6, 7, 12, 13], [6, 10, 11, 12], [6, 12, 13, 15], [7, 8, 10, 14], - [7, 8, 11, 15], [7, 8, 14, 15], [7, 9, 14, 15], [8, 12, 14, 15], - [9, 10, 11, 12], [9, 10, 11, 16], [9, 10, 15, 16], [9, 11, 14, 16], - [9, 14, 15, 16], [10, 11, 13, 16], [10, 13, 15, 16], - [11, 13, 14, 16], [12, 13, 14, 15], [13, 14, 15, 16]], - name='Triangulation of the Poincare homology 3-sphere') + [ + [1, 2, 4, 9], + [1, 2, 4, 15], + [1, 2, 6, 14], + [1, 2, 6, 15], + [1, 2, 9, 14], + [1, 3, 4, 12], + [1, 3, 4, 15], + [1, 3, 7, 10], + [1, 3, 7, 12], + [1, 3, 10, 15], + [1, 4, 9, 12], + [1, 5, 6, 13], + [1, 5, 6, 14], + [1, 5, 8, 11], + [1, 5, 8, 13], + [1, 5, 11, 14], + [1, 6, 13, 15], + [1, 7, 8, 10], + [1, 7, 8, 11], + [1, 7, 11, 12], + [1, 8, 10, 13], + [1, 9, 11, 12], + [1, 9, 11, 14], + [1, 10, 13, 15], + [2, 3, 5, 10], + [2, 3, 5, 11], + [2, 3, 7, 10], + [2, 3, 7, 13], + [2, 3, 11, 13], + [2, 4, 9, 13], + [2, 4, 11, 13], + [2, 4, 11, 15], + [2, 5, 8, 11], + [2, 5, 8, 12], + [2, 5, 10, 12], + [2, 6, 10, 12], + [2, 6, 10, 14], + [2, 6, 12, 15], + [2, 7, 9, 13], + [2, 7, 9, 14], + [2, 7, 10, 14], + [2, 8, 11, 15], + [2, 8, 12, 15], + [3, 4, 5, 14], + [3, 4, 5, 15], + [3, 4, 12, 14], + [3, 5, 10, 15], + [3, 5, 11, 14], + [3, 7, 12, 13], + [3, 11, 13, 14], + [3, 12, 13, 14], + [4, 5, 6, 7], + [4, 5, 6, 14], + [4, 5, 7, 15], + [4, 6, 7, 11], + [4, 6, 10, 11], + [4, 6, 10, 14], + [4, 7, 11, 15], + [4, 8, 9, 12], + [4, 8, 9, 13], + [4, 8, 10, 13], + [4, 8, 10, 14], + [4, 8, 12, 14], + [4, 10, 11, 13], + [5, 6, 7, 13], + [5, 7, 9, 13], + [5, 7, 9, 15], + [5, 8, 9, 12], + [5, 8, 9, 13], + [5, 9, 10, 12], + [5, 9, 10, 15], + [6, 7, 11, 12], + [6, 7, 12, 13], + [6, 10, 11, 12], + [6, 12, 13, 15], + [7, 8, 10, 14], + [7, 8, 11, 15], + [7, 8, 14, 15], + [7, 9, 14, 15], + [8, 12, 14, 15], + [9, 10, 11, 12], + [9, 10, 11, 16], + [9, 10, 15, 16], + [9, 11, 14, 16], + [9, 14, 15, 16], + [10, 11, 13, 16], + [10, 13, 15, 16], + [11, 13, 14, 16], + [12, 13, 14, 15], + [13, 14, 15, 16], + ], + name='Triangulation of the Poincare homology 3-sphere', + ) def RealProjectiveSpace(n): @@ -757,74 +787,166 @@ def RealProjectiveSpace(n): if n == 3: # Minimal triangulation found by Walkup and given # explicitly by Lutz - return UniqueSimplicialComplex( - [[1, 2, 3, 7], [1, 4, 7, 9], [2, 3, 4, 8], [2, 5, 8, 10], - [3, 6, 7, 10], [1, 2, 3, 11], [1, 4, 7, 10], [2, 3, 4, 11], - [2, 5, 9, 10], [3, 6, 8, 9], [1, 2, 6, 9], [1, 4, 8, 9], - [2, 3, 7, 8], [2, 6, 9, 10], [3, 6, 9, 10], [1, 2, 6, 11], - [1, 4, 8, 10], [2, 4, 6, 10], [3, 4, 5, 9], [4, 5, 6, 7], - [1, 2, 7, 9], [1, 5, 6, 8], [2, 4, 6, 11], [3, 4, 5, 11], - [4, 5, 6, 11], [1, 3, 5, 10], [1, 5, 6, 11], [2, 4, 8, 10], - [3, 4, 8, 9], [4, 5, 7, 9], [1, 3, 5, 11], [1, 5, 8, 10], - [2, 5, 7, 8], [3, 5, 9, 10], [4, 6, 7, 10], [1, 3, 7, 10], - [1, 6, 8, 9], [2, 5, 7, 9], [3, 6, 7, 8], [5, 6, 7, 8]], - name='Minimal triangulation of RP^3') + return UniqueSimplicialComplex([[1, 2, 3, 7], [1, 4, 7, 9], [2, 3, 4, 8], [2, 5, 8, 10], [3, 6, 7, 10], [1, 2, 3, 11], [1, 4, 7, 10], [2, 3, 4, 11], [2, 5, 9, 10], [3, 6, 8, 9], [1, 2, 6, 9], [1, 4, 8, 9], [2, 3, 7, 8], [2, 6, 9, 10], [3, 6, 9, 10], [1, 2, 6, 11], [1, 4, 8, 10], [2, 4, 6, 10], [3, 4, 5, 9], [4, 5, 6, 7], [1, 2, 7, 9], [1, 5, 6, 8], [2, 4, 6, 11], [3, 4, 5, 11], [4, 5, 6, 11], [1, 3, 5, 10], [1, 5, 6, 11], [2, 4, 8, 10], [3, 4, 8, 9], [4, 5, 7, 9], [1, 3, 5, 11], [1, 5, 8, 10], [2, 5, 7, 8], [3, 5, 9, 10], [4, 6, 7, 10], [1, 3, 7, 10], [1, 6, 8, 9], [2, 5, 7, 9], [3, 6, 7, 8], [5, 6, 7, 8]], name='Minimal triangulation of RP^3') if n == 4: return UniqueSimplicialComplex( - [(1, 3, 8, 12, 13), (2, 7, 8, 13, 16), (4, 8, 9, 12, 14), - (2, 6, 10, 12, 16), (5, 7, 9, 10, 13), (1, 2, 7, 8, 15), - (1, 3, 9, 11, 16), (5, 6, 8, 13, 16), (1, 3, 8, 11, 13), - (3, 4, 10, 13, 15), (4, 6, 9, 12, 15), (2, 4, 6, 11, 13), - (2, 3, 9, 12, 16), (1, 6, 9, 12, 15), (2, 5, 10, 11, 12), - (1, 7, 8, 12, 15), (2, 6, 9, 13, 16), (1, 5, 9, 11, 15), - (4, 9, 10, 13, 14), (2, 7, 8, 15, 16), (2, 3, 9, 12, 14), - (1, 6, 7, 10, 14), (2, 5, 10, 11, 15), (1, 2, 4, 13, 14), - (1, 6, 10, 14, 16), (2, 6, 9, 12, 16), (1, 3, 9, 12, 16), - (4, 5, 7, 11, 16), (5, 9, 10, 11, 15), (3, 5, 8, 12, 14), - (5, 6, 9, 13, 16), (5, 6, 9, 13, 15), (1, 3, 4, 10, 16), - (1, 6, 10, 12, 16), (2, 4, 6, 9, 13), (2, 4, 6, 9, 12), - (1, 2, 4, 11, 13), (7, 9, 10, 13, 14), (1, 7, 8, 12, 13), - (4, 6, 7, 11, 12), (3, 4, 6, 11, 13), (1, 5, 6, 9, 15), - (1, 6, 7, 14, 15), (2, 3, 7, 14, 15), (2, 6, 10, 11, 12), - (5, 7, 9, 10, 11), (1, 2, 4, 5, 14), (3, 5, 10, 13, 15), - (3, 8, 9, 12, 14), (5, 9, 10, 13, 15), (2, 6, 8, 13, 16), - (1, 2, 7, 13, 14), (1, 7, 10, 12, 13), (3, 4, 6, 13, 15), - (4, 9, 10, 13, 15), (2, 3, 10, 12, 16), (1, 2, 5, 14, 15), - (2, 6, 8, 10, 11), (1, 3, 10, 12, 13), (4, 8, 9, 12, 15), - (1, 3, 8, 9, 11), (4, 6, 7, 12, 15), (1, 8, 9, 11, 15), - (4, 5, 8, 14, 16), (1, 2, 8, 11, 13), (3, 6, 8, 11, 13), - (3, 6, 8, 11, 14), (3, 5, 8, 12, 13), (3, 7, 9, 11, 14), - (4, 6, 9, 13, 15), (2, 3, 5, 10, 12), (4, 7, 8, 15, 16), - (1, 2, 7, 14, 15), (3, 7, 9, 11, 16), (3, 6, 7, 14, 15), - (2, 6, 8, 11, 13), (4, 8, 9, 10, 14), (1, 4, 10, 13, 14), - (4, 8, 9, 10, 15), (2, 7, 9, 13, 16), (1, 6, 9, 12, 16), - (2, 3, 7, 9, 14), (4, 8, 10, 15, 16), (1, 5, 9, 11, 16), - (1, 5, 6, 14, 15), (5, 7, 9, 11, 16), (4, 5, 7, 11, 12), - (5, 7, 10, 11, 12), (2, 3, 10, 15, 16), (1, 2, 7, 8, 13), - (1, 6, 7, 10, 12), (1, 3, 10, 12, 16), (7, 9, 10, 11, 14), - (1, 7, 10, 13, 14), (1, 2, 4, 5, 11), (3, 4, 6, 7, 11), - (1, 6, 7, 12, 15), (1, 3, 4, 10, 13), (1, 4, 10, 14, 16), - (2, 4, 6, 11, 12), (5, 6, 8, 14, 16), (3, 5, 6, 8, 13), - (3, 5, 6, 8, 14), (1, 2, 8, 11, 15), (1, 4, 5, 14, 16), - (2, 3, 7, 15, 16), (8, 9, 10, 11, 14), (1, 3, 4, 11, 16), - (6, 8, 10, 14, 16), (8, 9, 10, 11, 15), (1, 3, 4, 11, 13), - (2, 4, 5, 12, 14), (2, 4, 9, 13, 14), (3, 4, 7, 11, 16), - (3, 6, 7, 11, 14), (3, 8, 9, 11, 14), (2, 8, 10, 11, 15), - (1, 3, 8, 9, 12), (4, 5, 7, 8, 16), (4, 5, 8, 12, 14), - (2, 4, 9, 12, 14), (6, 8, 10, 11, 14), (3, 5, 6, 13, 15), - (1, 4, 5, 11, 16), (3, 5, 6, 14, 15), (2, 4, 5, 11, 12), - (4, 5, 7, 8, 12), (1, 8, 9, 12, 15), (5, 7, 8, 13, 16), - (2, 3, 5, 12, 14), (3, 5, 10, 12, 13), (6, 7, 10, 11, 12), - (5, 7, 9, 13, 16), (6, 7, 10, 11, 14), (5, 7, 10, 12, 13), - (1, 2, 5, 11, 15), (1, 5, 6, 9, 16), (5, 7, 8, 12, 13), - (4, 7, 8, 12, 15), (2, 3, 5, 10, 15), (2, 6, 8, 10, 16), - (3, 4, 10, 15, 16), (1, 5, 6, 14, 16), (2, 3, 5, 14, 15), - (2, 3, 7, 9, 16), (2, 7, 9, 13, 14), (3, 4, 6, 7, 15), - (4, 8, 10, 14, 16), (3, 4, 7, 15, 16), (2, 8, 10, 15, 16)], - name='Minimal triangulation of RP^4') + [ + (1, 3, 8, 12, 13), + (2, 7, 8, 13, 16), + (4, 8, 9, 12, 14), + (2, 6, 10, 12, 16), + (5, 7, 9, 10, 13), + (1, 2, 7, 8, 15), + (1, 3, 9, 11, 16), + (5, 6, 8, 13, 16), + (1, 3, 8, 11, 13), + (3, 4, 10, 13, 15), + (4, 6, 9, 12, 15), + (2, 4, 6, 11, 13), + (2, 3, 9, 12, 16), + (1, 6, 9, 12, 15), + (2, 5, 10, 11, 12), + (1, 7, 8, 12, 15), + (2, 6, 9, 13, 16), + (1, 5, 9, 11, 15), + (4, 9, 10, 13, 14), + (2, 7, 8, 15, 16), + (2, 3, 9, 12, 14), + (1, 6, 7, 10, 14), + (2, 5, 10, 11, 15), + (1, 2, 4, 13, 14), + (1, 6, 10, 14, 16), + (2, 6, 9, 12, 16), + (1, 3, 9, 12, 16), + (4, 5, 7, 11, 16), + (5, 9, 10, 11, 15), + (3, 5, 8, 12, 14), + (5, 6, 9, 13, 16), + (5, 6, 9, 13, 15), + (1, 3, 4, 10, 16), + (1, 6, 10, 12, 16), + (2, 4, 6, 9, 13), + (2, 4, 6, 9, 12), + (1, 2, 4, 11, 13), + (7, 9, 10, 13, 14), + (1, 7, 8, 12, 13), + (4, 6, 7, 11, 12), + (3, 4, 6, 11, 13), + (1, 5, 6, 9, 15), + (1, 6, 7, 14, 15), + (2, 3, 7, 14, 15), + (2, 6, 10, 11, 12), + (5, 7, 9, 10, 11), + (1, 2, 4, 5, 14), + (3, 5, 10, 13, 15), + (3, 8, 9, 12, 14), + (5, 9, 10, 13, 15), + (2, 6, 8, 13, 16), + (1, 2, 7, 13, 14), + (1, 7, 10, 12, 13), + (3, 4, 6, 13, 15), + (4, 9, 10, 13, 15), + (2, 3, 10, 12, 16), + (1, 2, 5, 14, 15), + (2, 6, 8, 10, 11), + (1, 3, 10, 12, 13), + (4, 8, 9, 12, 15), + (1, 3, 8, 9, 11), + (4, 6, 7, 12, 15), + (1, 8, 9, 11, 15), + (4, 5, 8, 14, 16), + (1, 2, 8, 11, 13), + (3, 6, 8, 11, 13), + (3, 6, 8, 11, 14), + (3, 5, 8, 12, 13), + (3, 7, 9, 11, 14), + (4, 6, 9, 13, 15), + (2, 3, 5, 10, 12), + (4, 7, 8, 15, 16), + (1, 2, 7, 14, 15), + (3, 7, 9, 11, 16), + (3, 6, 7, 14, 15), + (2, 6, 8, 11, 13), + (4, 8, 9, 10, 14), + (1, 4, 10, 13, 14), + (4, 8, 9, 10, 15), + (2, 7, 9, 13, 16), + (1, 6, 9, 12, 16), + (2, 3, 7, 9, 14), + (4, 8, 10, 15, 16), + (1, 5, 9, 11, 16), + (1, 5, 6, 14, 15), + (5, 7, 9, 11, 16), + (4, 5, 7, 11, 12), + (5, 7, 10, 11, 12), + (2, 3, 10, 15, 16), + (1, 2, 7, 8, 13), + (1, 6, 7, 10, 12), + (1, 3, 10, 12, 16), + (7, 9, 10, 11, 14), + (1, 7, 10, 13, 14), + (1, 2, 4, 5, 11), + (3, 4, 6, 7, 11), + (1, 6, 7, 12, 15), + (1, 3, 4, 10, 13), + (1, 4, 10, 14, 16), + (2, 4, 6, 11, 12), + (5, 6, 8, 14, 16), + (3, 5, 6, 8, 13), + (3, 5, 6, 8, 14), + (1, 2, 8, 11, 15), + (1, 4, 5, 14, 16), + (2, 3, 7, 15, 16), + (8, 9, 10, 11, 14), + (1, 3, 4, 11, 16), + (6, 8, 10, 14, 16), + (8, 9, 10, 11, 15), + (1, 3, 4, 11, 13), + (2, 4, 5, 12, 14), + (2, 4, 9, 13, 14), + (3, 4, 7, 11, 16), + (3, 6, 7, 11, 14), + (3, 8, 9, 11, 14), + (2, 8, 10, 11, 15), + (1, 3, 8, 9, 12), + (4, 5, 7, 8, 16), + (4, 5, 8, 12, 14), + (2, 4, 9, 12, 14), + (6, 8, 10, 11, 14), + (3, 5, 6, 13, 15), + (1, 4, 5, 11, 16), + (3, 5, 6, 14, 15), + (2, 4, 5, 11, 12), + (4, 5, 7, 8, 12), + (1, 8, 9, 12, 15), + (5, 7, 8, 13, 16), + (2, 3, 5, 12, 14), + (3, 5, 10, 12, 13), + (6, 7, 10, 11, 12), + (5, 7, 9, 13, 16), + (6, 7, 10, 11, 14), + (5, 7, 10, 12, 13), + (1, 2, 5, 11, 15), + (1, 5, 6, 9, 16), + (5, 7, 8, 12, 13), + (4, 7, 8, 12, 15), + (2, 3, 5, 10, 15), + (2, 6, 8, 10, 16), + (3, 4, 10, 15, 16), + (1, 5, 6, 14, 16), + (2, 3, 5, 14, 15), + (2, 3, 7, 9, 16), + (2, 7, 9, 13, 14), + (3, 4, 6, 7, 15), + (4, 8, 10, 14, 16), + (3, 4, 7, 15, 16), + (2, 8, 10, 15, 16), + ], + name='Minimal triangulation of RP^4', + ) if n >= 5: # Use the construction given by Datta in Example 3.21. - V = set(range(n+2)) + V = set(range(n + 2)) S = Sphere(n).barycentric_subdivision() X = S.facets() facets = set() @@ -836,8 +958,7 @@ def RealProjectiveSpace(n): else: new.append(v) facets.add(tuple(new)) - return UniqueSimplicialComplex(list(facets), - name='Triangulation of RP^{}'.format(n)) + return UniqueSimplicialComplex(list(facets), name='Triangulation of RP^{}'.format(n)) def K3Surface(): @@ -862,103 +983,298 @@ def K3Surface(): seconds. """ return UniqueSimplicialComplex( - [(2, 10, 13, 15, 16), (2, 8, 11, 15, 16), (2, 5, 7, 8, 10), - (1, 9, 11, 13, 14), (1, 2, 8, 10, 12), (1, 3, 5, 6, 11), - (1, 5, 6, 9, 12), (1, 2, 6, 13, 16), (1, 4, 10, 13, 14), - (1, 9, 10, 14, 15), (2, 4, 7, 8, 12), (3, 4, 6, 10, 12), - (1, 6, 7, 8, 9), (3, 4, 5, 7, 15), (1, 7, 12, 15, 16), - (4, 5, 7, 13, 16), (5, 8, 11, 12, 15), (2, 4, 7, 12, 14), - (1, 4, 5, 14, 16), (2, 5, 6, 10, 11), (1, 6, 8, 12, 14), - (5, 8, 9, 14, 16), (5, 10, 11, 12, 13), (2, 4, 8, 9, 12), - (7, 9, 12, 15, 16), (1, 2, 6, 9, 15), (1, 5, 14, 15, 16), - (2, 3, 4, 5, 9), (6, 8, 10, 11, 15), (1, 5, 8, 10, 12), - (1, 3, 7, 9, 10), (6, 7, 8, 9, 13), (1, 2, 9, 11, 15), - (2, 8, 11, 14, 16), (2, 4, 5, 13, 16), (1, 4, 8, 13, 15), - (4, 7, 8, 10, 11), (2, 3, 9, 11, 14), (2, 3, 4, 9, 13), - (2, 8, 10, 12, 13), (1, 2, 4, 11, 15), (2, 3, 9, 11, 15), - (3, 5, 10, 13, 15), (3, 4, 5, 9, 11), (6, 10, 13, 15, 16), - (8, 10, 11, 15, 16), (6, 7, 11, 13, 15), (1, 5, 7, 15, 16), - (4, 5, 7, 9, 15), (3, 4, 6, 7, 16), (2, 3, 11, 14, 16), - (3, 4, 9, 11, 13), (1, 2, 5, 14, 15), (2, 3, 9, 13, 14), - (1, 2, 5, 13, 16), (2, 3, 7, 8, 12), (2, 9, 11, 12, 14), - (1, 9, 11, 15, 16), (4, 6, 9, 14, 16), (1, 4, 9, 13, 14), - (1, 2, 3, 12, 16), (8, 11, 12, 14, 15), (2, 4, 11, 12, 14), - (1, 4, 10, 12, 13), (1, 2, 6, 7, 13), (1, 3, 6, 10, 11), - (1, 6, 8, 9, 12), (1, 4, 5, 6, 14), (3, 9, 10, 12, 15), - (5, 8, 11, 12, 16), (5, 9, 10, 14, 15), (3, 9, 12, 15, 16), - (3, 6, 8, 14, 15), (2, 4, 9, 10, 16), (5, 8, 9, 13, 15), - (2, 3, 6, 9, 15), (6, 11, 12, 14, 16), (2, 3, 10, 13, 15), - (2, 8, 9, 10, 13), (3, 4, 8, 11, 13), (3, 4, 5, 7, 13), - (5, 7, 8, 10, 14), (4, 12, 13, 14, 15), (6, 7, 10, 14, 16), - (5, 10, 11, 13, 14), (3, 4, 7, 13, 16), (6, 8, 9, 12, 13), - (1, 3, 4, 10, 14), (2, 4, 6, 11, 12), (1, 7, 9, 10, 14), - (4, 6, 8, 13, 14), (4, 9, 10, 11, 16), (3, 7, 8, 10, 16), - (5, 7, 9, 15, 16), (1, 7, 9, 11, 14), (6, 8, 10, 15, 16), - (5, 8, 9, 10, 14), (7, 8, 10, 14, 16), (2, 6, 7, 9, 11), - (7, 9, 10, 13, 15), (3, 6, 7, 10, 12), (2, 4, 6, 10, 11), - (4, 5, 8, 9, 11), (1, 2, 3, 8, 16), (3, 7, 9, 10, 12), - (1, 2, 6, 8, 14), (3, 5, 6, 13, 15), (1, 5, 6, 12, 14), - (2, 5, 7, 14, 15), (1, 5, 10, 11, 12), (3, 7, 8, 10, 11), - (1, 2, 6, 14, 15), (1, 2, 6, 8, 16), (7, 9, 10, 12, 15), - (3, 4, 6, 8, 14), (3, 7, 13, 14, 16), (2, 5, 7, 8, 14), - (6, 7, 9, 10, 14), (2, 3, 7, 12, 14), (4, 10, 12, 13, 14), - (2, 5, 6, 11, 13), (4, 5, 6, 7, 16), (1, 3, 12, 13, 16), - (1, 4, 11, 15, 16), (1, 3, 4, 6, 10), (1, 10, 11, 12, 13), - (6, 9, 11, 12, 14), (1, 4, 7, 8, 15), (5, 8, 9, 10, 13), - (1, 2, 5, 7, 15), (1, 7, 12, 13, 16), (3, 11, 13, 14, 16), - (1, 2, 5, 7, 13), (4, 7, 8, 9, 15), (1, 5, 6, 10, 11), - (6, 7, 10, 13, 15), (3, 4, 7, 14, 15), (7, 11, 13, 14, 16), - (3, 4, 10, 12, 14), (3, 6, 8, 10, 16), (2, 7, 8, 14, 16), - (2, 3, 4, 5, 13), (5, 8, 12, 13, 15), (4, 6, 9, 13, 14), - (2, 4, 5, 6, 12), (1, 3, 7, 8, 9), (8, 11, 12, 14, 16), - (1, 7, 12, 13, 15), (8, 12, 13, 14, 15), (2, 8, 9, 12, 13), - (4, 6, 10, 12, 15), (2, 8, 11, 14, 15), (2, 6, 9, 11, 12), - (8, 9, 10, 11, 16), (2, 3, 6, 13, 15), (2, 3, 12, 15, 16), - (1, 3, 5, 9, 12), (2, 5, 6, 9, 12), (2, 10, 12, 13, 14), - (2, 6, 13, 15, 16), (2, 3, 11, 15, 16), (3, 5, 6, 8, 15), - (2, 4, 5, 9, 12), (5, 6, 8, 11, 15), (6, 8, 12, 13, 14), - (1, 2, 3, 8, 12), (1, 4, 7, 8, 11), (3, 5, 7, 14, 15), - (3, 5, 7, 13, 14), (1, 7, 10, 11, 14), (6, 7, 11, 12, 15), - (3, 4, 6, 7, 12), (1, 2, 4, 7, 11), (6, 9, 10, 14, 16), - (4, 10, 12, 15, 16), (5, 6, 7, 12, 16), (3, 9, 11, 13, 14), - (5, 9, 14, 15, 16), (4, 5, 6, 7, 12), (1, 3, 9, 10, 15), - (4, 7, 8, 9, 12), (5, 9, 10, 13, 15), (1, 3, 8, 13, 16), - (2, 9, 12, 13, 14), (6, 7, 10, 12, 15), (2, 6, 8, 14, 15), - (3, 5, 6, 8, 11), (3, 4, 7, 12, 14), (1, 3, 10, 14, 15), - (7, 11, 12, 13, 16), (3, 11, 12, 13, 16), (3, 4, 5, 8, 15), - (2, 4, 7, 8, 10), (2, 4, 7, 14, 15), (1, 2, 10, 12, 16), - (1, 6, 8, 13, 16), (1, 7, 8, 13, 15), (3, 9, 11, 15, 16), - (4, 6, 10, 11, 15), (2, 4, 11, 14, 15), (1, 3, 8, 9, 12), - (1, 3, 6, 14, 15), (2, 4, 5, 6, 10), (1, 4, 9, 14, 16), - (5, 7, 9, 12, 16), (1, 3, 7, 10, 11), (7, 8, 9, 13, 15), - (3, 5, 10, 14, 15), (1, 4, 10, 12, 16), (3, 4, 5, 8, 11), - (1, 2, 6, 7, 9), (1, 3, 11, 12, 13), (1, 5, 7, 13, 16), - (5, 7, 10, 11, 14), (2, 10, 12, 15, 16), (3, 6, 7, 10, 16), - (1, 2, 5, 8, 10), (4, 10, 11, 15, 16), (5, 8, 10, 12, 13), - (3, 6, 8, 10, 11), (4, 5, 7, 9, 12), (6, 7, 11, 12, 16), - (3, 5, 9, 11, 16), (8, 9, 10, 14, 16), (3, 4, 6, 8, 16), - (1, 10, 11, 13, 14), (2, 9, 10, 13, 16), (1, 2, 5, 8, 14), - (2, 4, 5, 10, 16), (1, 2, 7, 9, 11), (1, 3, 5, 6, 9), - (5, 7, 11, 13, 14), (3, 5, 10, 13, 14), (2, 4, 8, 9, 10), - (4, 11, 12, 14, 15), (2, 3, 7, 14, 16), (3, 4, 8, 13, 16), - (6, 7, 9, 11, 14), (5, 6, 11, 13, 15), (4, 5, 6, 14, 16), - (3, 4, 8, 14, 15), (4, 5, 8, 9, 15), (1, 4, 8, 11, 13), - (5, 6, 12, 14, 16), (2, 3, 10, 12, 14), (1, 2, 5, 10, 16), - (2, 5, 7, 10, 11), (2, 6, 7, 11, 13), (1, 4, 5, 10, 16), - (2, 6, 8, 15, 16), (2, 3, 10, 12, 15), (7, 11, 12, 13, 15), - (1, 3, 8, 11, 13), (4, 8, 9, 10, 11), (1, 9, 14, 15, 16), - (1, 3, 6, 9, 15), (6, 9, 12, 13, 14), (2, 3, 10, 13, 14), - (2, 5, 7, 11, 13), (2, 3, 5, 6, 13), (4, 6, 8, 13, 16), - (6, 7, 9, 10, 13), (5, 8, 12, 14, 16), (4, 6, 9, 13, 16), - (5, 8, 9, 11, 16), (2, 3, 5, 6, 9), (1, 3, 5, 11, 12), - (3, 7, 8, 9, 12), (4, 6, 11, 12, 15), (3, 5, 9, 12, 16), - (5, 11, 12, 13, 15), (1, 3, 4, 6, 14), (3, 5, 11, 12, 16), - (1, 5, 8, 12, 14), (4, 8, 13, 14, 15), (1, 3, 7, 8, 11), - (6, 9, 10, 13, 16), (2, 4, 9, 13, 16), (1, 6, 7, 8, 13), - (1, 4, 12, 13, 15), (2, 4, 7, 10, 11), (1, 4, 9, 11, 13), - (6, 7, 11, 14, 16), (1, 4, 9, 11, 16), (1, 4, 12, 15, 16), - (1, 2, 4, 7, 15), (2, 3, 7, 8, 16), (1, 4, 5, 6, 10)], - name='Minimal triangulation of the K3 surface') + [ + (2, 10, 13, 15, 16), + (2, 8, 11, 15, 16), + (2, 5, 7, 8, 10), + (1, 9, 11, 13, 14), + (1, 2, 8, 10, 12), + (1, 3, 5, 6, 11), + (1, 5, 6, 9, 12), + (1, 2, 6, 13, 16), + (1, 4, 10, 13, 14), + (1, 9, 10, 14, 15), + (2, 4, 7, 8, 12), + (3, 4, 6, 10, 12), + (1, 6, 7, 8, 9), + (3, 4, 5, 7, 15), + (1, 7, 12, 15, 16), + (4, 5, 7, 13, 16), + (5, 8, 11, 12, 15), + (2, 4, 7, 12, 14), + (1, 4, 5, 14, 16), + (2, 5, 6, 10, 11), + (1, 6, 8, 12, 14), + (5, 8, 9, 14, 16), + (5, 10, 11, 12, 13), + (2, 4, 8, 9, 12), + (7, 9, 12, 15, 16), + (1, 2, 6, 9, 15), + (1, 5, 14, 15, 16), + (2, 3, 4, 5, 9), + (6, 8, 10, 11, 15), + (1, 5, 8, 10, 12), + (1, 3, 7, 9, 10), + (6, 7, 8, 9, 13), + (1, 2, 9, 11, 15), + (2, 8, 11, 14, 16), + (2, 4, 5, 13, 16), + (1, 4, 8, 13, 15), + (4, 7, 8, 10, 11), + (2, 3, 9, 11, 14), + (2, 3, 4, 9, 13), + (2, 8, 10, 12, 13), + (1, 2, 4, 11, 15), + (2, 3, 9, 11, 15), + (3, 5, 10, 13, 15), + (3, 4, 5, 9, 11), + (6, 10, 13, 15, 16), + (8, 10, 11, 15, 16), + (6, 7, 11, 13, 15), + (1, 5, 7, 15, 16), + (4, 5, 7, 9, 15), + (3, 4, 6, 7, 16), + (2, 3, 11, 14, 16), + (3, 4, 9, 11, 13), + (1, 2, 5, 14, 15), + (2, 3, 9, 13, 14), + (1, 2, 5, 13, 16), + (2, 3, 7, 8, 12), + (2, 9, 11, 12, 14), + (1, 9, 11, 15, 16), + (4, 6, 9, 14, 16), + (1, 4, 9, 13, 14), + (1, 2, 3, 12, 16), + (8, 11, 12, 14, 15), + (2, 4, 11, 12, 14), + (1, 4, 10, 12, 13), + (1, 2, 6, 7, 13), + (1, 3, 6, 10, 11), + (1, 6, 8, 9, 12), + (1, 4, 5, 6, 14), + (3, 9, 10, 12, 15), + (5, 8, 11, 12, 16), + (5, 9, 10, 14, 15), + (3, 9, 12, 15, 16), + (3, 6, 8, 14, 15), + (2, 4, 9, 10, 16), + (5, 8, 9, 13, 15), + (2, 3, 6, 9, 15), + (6, 11, 12, 14, 16), + (2, 3, 10, 13, 15), + (2, 8, 9, 10, 13), + (3, 4, 8, 11, 13), + (3, 4, 5, 7, 13), + (5, 7, 8, 10, 14), + (4, 12, 13, 14, 15), + (6, 7, 10, 14, 16), + (5, 10, 11, 13, 14), + (3, 4, 7, 13, 16), + (6, 8, 9, 12, 13), + (1, 3, 4, 10, 14), + (2, 4, 6, 11, 12), + (1, 7, 9, 10, 14), + (4, 6, 8, 13, 14), + (4, 9, 10, 11, 16), + (3, 7, 8, 10, 16), + (5, 7, 9, 15, 16), + (1, 7, 9, 11, 14), + (6, 8, 10, 15, 16), + (5, 8, 9, 10, 14), + (7, 8, 10, 14, 16), + (2, 6, 7, 9, 11), + (7, 9, 10, 13, 15), + (3, 6, 7, 10, 12), + (2, 4, 6, 10, 11), + (4, 5, 8, 9, 11), + (1, 2, 3, 8, 16), + (3, 7, 9, 10, 12), + (1, 2, 6, 8, 14), + (3, 5, 6, 13, 15), + (1, 5, 6, 12, 14), + (2, 5, 7, 14, 15), + (1, 5, 10, 11, 12), + (3, 7, 8, 10, 11), + (1, 2, 6, 14, 15), + (1, 2, 6, 8, 16), + (7, 9, 10, 12, 15), + (3, 4, 6, 8, 14), + (3, 7, 13, 14, 16), + (2, 5, 7, 8, 14), + (6, 7, 9, 10, 14), + (2, 3, 7, 12, 14), + (4, 10, 12, 13, 14), + (2, 5, 6, 11, 13), + (4, 5, 6, 7, 16), + (1, 3, 12, 13, 16), + (1, 4, 11, 15, 16), + (1, 3, 4, 6, 10), + (1, 10, 11, 12, 13), + (6, 9, 11, 12, 14), + (1, 4, 7, 8, 15), + (5, 8, 9, 10, 13), + (1, 2, 5, 7, 15), + (1, 7, 12, 13, 16), + (3, 11, 13, 14, 16), + (1, 2, 5, 7, 13), + (4, 7, 8, 9, 15), + (1, 5, 6, 10, 11), + (6, 7, 10, 13, 15), + (3, 4, 7, 14, 15), + (7, 11, 13, 14, 16), + (3, 4, 10, 12, 14), + (3, 6, 8, 10, 16), + (2, 7, 8, 14, 16), + (2, 3, 4, 5, 13), + (5, 8, 12, 13, 15), + (4, 6, 9, 13, 14), + (2, 4, 5, 6, 12), + (1, 3, 7, 8, 9), + (8, 11, 12, 14, 16), + (1, 7, 12, 13, 15), + (8, 12, 13, 14, 15), + (2, 8, 9, 12, 13), + (4, 6, 10, 12, 15), + (2, 8, 11, 14, 15), + (2, 6, 9, 11, 12), + (8, 9, 10, 11, 16), + (2, 3, 6, 13, 15), + (2, 3, 12, 15, 16), + (1, 3, 5, 9, 12), + (2, 5, 6, 9, 12), + (2, 10, 12, 13, 14), + (2, 6, 13, 15, 16), + (2, 3, 11, 15, 16), + (3, 5, 6, 8, 15), + (2, 4, 5, 9, 12), + (5, 6, 8, 11, 15), + (6, 8, 12, 13, 14), + (1, 2, 3, 8, 12), + (1, 4, 7, 8, 11), + (3, 5, 7, 14, 15), + (3, 5, 7, 13, 14), + (1, 7, 10, 11, 14), + (6, 7, 11, 12, 15), + (3, 4, 6, 7, 12), + (1, 2, 4, 7, 11), + (6, 9, 10, 14, 16), + (4, 10, 12, 15, 16), + (5, 6, 7, 12, 16), + (3, 9, 11, 13, 14), + (5, 9, 14, 15, 16), + (4, 5, 6, 7, 12), + (1, 3, 9, 10, 15), + (4, 7, 8, 9, 12), + (5, 9, 10, 13, 15), + (1, 3, 8, 13, 16), + (2, 9, 12, 13, 14), + (6, 7, 10, 12, 15), + (2, 6, 8, 14, 15), + (3, 5, 6, 8, 11), + (3, 4, 7, 12, 14), + (1, 3, 10, 14, 15), + (7, 11, 12, 13, 16), + (3, 11, 12, 13, 16), + (3, 4, 5, 8, 15), + (2, 4, 7, 8, 10), + (2, 4, 7, 14, 15), + (1, 2, 10, 12, 16), + (1, 6, 8, 13, 16), + (1, 7, 8, 13, 15), + (3, 9, 11, 15, 16), + (4, 6, 10, 11, 15), + (2, 4, 11, 14, 15), + (1, 3, 8, 9, 12), + (1, 3, 6, 14, 15), + (2, 4, 5, 6, 10), + (1, 4, 9, 14, 16), + (5, 7, 9, 12, 16), + (1, 3, 7, 10, 11), + (7, 8, 9, 13, 15), + (3, 5, 10, 14, 15), + (1, 4, 10, 12, 16), + (3, 4, 5, 8, 11), + (1, 2, 6, 7, 9), + (1, 3, 11, 12, 13), + (1, 5, 7, 13, 16), + (5, 7, 10, 11, 14), + (2, 10, 12, 15, 16), + (3, 6, 7, 10, 16), + (1, 2, 5, 8, 10), + (4, 10, 11, 15, 16), + (5, 8, 10, 12, 13), + (3, 6, 8, 10, 11), + (4, 5, 7, 9, 12), + (6, 7, 11, 12, 16), + (3, 5, 9, 11, 16), + (8, 9, 10, 14, 16), + (3, 4, 6, 8, 16), + (1, 10, 11, 13, 14), + (2, 9, 10, 13, 16), + (1, 2, 5, 8, 14), + (2, 4, 5, 10, 16), + (1, 2, 7, 9, 11), + (1, 3, 5, 6, 9), + (5, 7, 11, 13, 14), + (3, 5, 10, 13, 14), + (2, 4, 8, 9, 10), + (4, 11, 12, 14, 15), + (2, 3, 7, 14, 16), + (3, 4, 8, 13, 16), + (6, 7, 9, 11, 14), + (5, 6, 11, 13, 15), + (4, 5, 6, 14, 16), + (3, 4, 8, 14, 15), + (4, 5, 8, 9, 15), + (1, 4, 8, 11, 13), + (5, 6, 12, 14, 16), + (2, 3, 10, 12, 14), + (1, 2, 5, 10, 16), + (2, 5, 7, 10, 11), + (2, 6, 7, 11, 13), + (1, 4, 5, 10, 16), + (2, 6, 8, 15, 16), + (2, 3, 10, 12, 15), + (7, 11, 12, 13, 15), + (1, 3, 8, 11, 13), + (4, 8, 9, 10, 11), + (1, 9, 14, 15, 16), + (1, 3, 6, 9, 15), + (6, 9, 12, 13, 14), + (2, 3, 10, 13, 14), + (2, 5, 7, 11, 13), + (2, 3, 5, 6, 13), + (4, 6, 8, 13, 16), + (6, 7, 9, 10, 13), + (5, 8, 12, 14, 16), + (4, 6, 9, 13, 16), + (5, 8, 9, 11, 16), + (2, 3, 5, 6, 9), + (1, 3, 5, 11, 12), + (3, 7, 8, 9, 12), + (4, 6, 11, 12, 15), + (3, 5, 9, 12, 16), + (5, 11, 12, 13, 15), + (1, 3, 4, 6, 14), + (3, 5, 11, 12, 16), + (1, 5, 8, 12, 14), + (4, 8, 13, 14, 15), + (1, 3, 7, 8, 11), + (6, 9, 10, 13, 16), + (2, 4, 9, 13, 16), + (1, 6, 7, 8, 13), + (1, 4, 12, 13, 15), + (2, 4, 7, 10, 11), + (1, 4, 9, 11, 13), + (6, 7, 11, 14, 16), + (1, 4, 9, 11, 16), + (1, 4, 12, 15, 16), + (1, 2, 4, 7, 15), + (2, 3, 7, 8, 16), + (1, 4, 5, 6, 10), + ], + name='Minimal triangulation of the K3 surface', + ) def BarnetteSphere(): @@ -994,14 +1310,7 @@ def BarnetteSphere(): sage: BS.is_isomorphic(BS2) True """ - return UniqueSimplicialComplex([(1, 2, 4, 5), (2, 3, 5, 6), (1, 3, 4, 6), - (1, 2, 3, 7), (4, 5, 6, 7), (1, 2, 4, 7), - (2, 4, 5, 7), (2, 3, 5, 7), (3, 5, 6, 7), - (3, 1, 6, 7), (1, 6, 4, 7), (1, 2, 3, 8), - (4, 5, 6, 8), (1, 2, 5, 8), (1, 4, 5, 8), - (2, 3, 6, 8), (2, 5, 6, 8), (3, 1, 4, 8), - (3, 6, 4, 8)], - name="Barnette's triangulation of the 3-sphere") + return UniqueSimplicialComplex([(1, 2, 4, 5), (2, 3, 5, 6), (1, 3, 4, 6), (1, 2, 3, 7), (4, 5, 6, 7), (1, 2, 4, 7), (2, 4, 5, 7), (2, 3, 5, 7), (3, 5, 6, 7), (3, 1, 6, 7), (1, 6, 4, 7), (1, 2, 3, 8), (4, 5, 6, 8), (1, 2, 5, 8), (1, 4, 5, 8), (2, 3, 6, 8), (2, 5, 6, 8), (3, 1, 4, 8), (3, 6, 4, 8)], name="Barnette's triangulation of the 3-sphere") def BrucknerGrunbaumSphere(): @@ -1027,8 +1336,8 @@ def BrucknerGrunbaumSphere(): # X = ComplexProjectivePlane().link([9]) # return UniqueSimplicialComplex(X.facets(), # name="Bruckner and Grunbaum's triangulation of the 3-sphere") - return UniqueSimplicialComplex(ComplexProjectivePlane().link([9]), - name="Bruckner and Grunbaum's triangulation of the 3-sphere") + return UniqueSimplicialComplex(ComplexProjectivePlane().link([9]), name="Bruckner and Grunbaum's triangulation of the 3-sphere") + ############################################################### # examples from graph theory: @@ -1070,7 +1379,7 @@ def NotIConnectedGraphs(n, i): sage: NICG52.homology(5).ngens() # needs sage.modules 6 """ - G_list = range(1, n+1) + G_list = range(1, n + 1) G_vertices = Set(G_list) E_list = [] for w in G_list: @@ -1078,7 +1387,7 @@ def NotIConnectedGraphs(n, i): E_list.append((v, w)) E = Set(E_list) facets = [] - i_minus_one_sets = list(G_vertices.subsets(size=i-1)) + i_minus_one_sets = list(G_vertices.subsets(size=i - 1)) for A in i_minus_one_sets: G_minus_A = G_vertices.difference(A) for B in G_minus_A.subsets(): @@ -1128,13 +1437,13 @@ def MatchingComplex(n): sage: M8.homology(2) # long time (6s on sage.math, 2012), needs sage.modules Z^132 """ - G_vertices = Set(range(1, n+1)) + G_vertices = Set(range(1, n + 1)) facets = [] if is_even(n): - half = int(n/2) + half = int(n / 2) half_n_sets = list(G_vertices.subsets(size=half)) else: - half = int((n-1)/2) + half = int((n - 1) / 2) half_n_sets = list(G_vertices.subsets(size=half)) for X in half_n_sets: Xcomp = G_vertices.difference(X) @@ -1249,14 +1558,13 @@ def RandomComplex(n, d, p=0.5): sage: simplicial_complexes.RandomComplex(6, 12) The 5-simplex """ - if d+1 > n: - return Simplex(n-1) + if d + 1 > n: + return Simplex(n - 1) vertices = range(n) facets = Subsets(vertices, d).list() - maybe = Subsets(vertices, d+1) + maybe = Subsets(vertices, d + 1) facets.extend([f for f in maybe if random.random() <= p]) - return UniqueSimplicialComplex(facets, - name='Random {}-dimensional simplicial complex on {} vertices'.format(d, n)) + return UniqueSimplicialComplex(facets, name='Random {}-dimensional simplicial complex on {} vertices'.format(d, n)) def SumComplex(n, A): @@ -1354,6 +1662,7 @@ def SumComplex(n, A): 5 * 311 * 683 * 1117 * 11657 * 1948909 """ from sage.rings.finite_rings.integer_mod_ring import Integers + Zn = Integers(n) A = frozenset([Zn(x) for x in A]) facets = [] @@ -1422,8 +1731,7 @@ def RandomTwoSphere(n): graph = RandomTriangulation(n) graph = graph.relabel(inplace=False) - triangles = [(u, v, w) for u, L in graph.get_embedding().items() - for v, w in zip(L, L[1:] + [L[0]]) if u < v and u < w] + triangles = [(u, v, w) for u, L in graph.get_embedding().items() for v, w in zip(L, L[1:] + [L[0]]) if u < v and u < w] return SimplicialComplex(triangles, maximality_check=False) @@ -1466,6 +1774,7 @@ def ShiftedComplex(generators): [(1, 2, 3), (1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5), (1, 6), (2, 6)] """ from sage.combinat.partition import Partitions + Facets = [] for _G in generators: G = sorted(_G, reverse=True) @@ -1495,18 +1804,7 @@ def RudinBall(): sage: R.is_cohen_macaulay() # needs sage.modules True """ - return UniqueSimplicialComplex( - [[1, 9, 2, 5], [1, 10, 2, 5], [1, 10, 5, 11], [1, 10, 7, 11], [1, 13, 5, 11], - [1, 13, 7, 11], [2, 10, 3, 6], [2, 11, 3, 6], [2, 11, 6, 12], [2, 11, 8, 12], - [2, 14, 6, 12], [2, 14, 8, 12], [3, 11, 4, 7], [3, 12, 4, 7], [3, 12, 5, 9], - [3, 12, 7, 9], [3, 13, 5, 9], [3, 13, 7, 9], [4, 9, 1, 8], [4, 9, 6, 10], - [4, 9, 8, 10], [4, 12, 1, 8], [4, 14, 6, 10], [4, 14, 8, 10], [9, 10, 2, 5], - [9, 10, 2, 6], [9, 10, 5, 11], [9, 10, 11, 12], [9, 13, 5, 11], [10, 11, 3, 6], - [10, 11, 3, 7], [10, 11, 6, 12], [10, 14, 6, 12], [11, 12, 4, 7], [11, 12, 4, 8], - [11, 12, 7, 9], [11, 13, 7, 9], [12, 9, 1, 5], [12, 9, 1, 8], [12, 9, 8, 10], - [12, 14, 8, 10]], - name="Rudin ball" - ) + return UniqueSimplicialComplex([[1, 9, 2, 5], [1, 10, 2, 5], [1, 10, 5, 11], [1, 10, 7, 11], [1, 13, 5, 11], [1, 13, 7, 11], [2, 10, 3, 6], [2, 11, 3, 6], [2, 11, 6, 12], [2, 11, 8, 12], [2, 14, 6, 12], [2, 14, 8, 12], [3, 11, 4, 7], [3, 12, 4, 7], [3, 12, 5, 9], [3, 12, 7, 9], [3, 13, 5, 9], [3, 13, 7, 9], [4, 9, 1, 8], [4, 9, 6, 10], [4, 9, 8, 10], [4, 12, 1, 8], [4, 14, 6, 10], [4, 14, 8, 10], [9, 10, 2, 5], [9, 10, 2, 6], [9, 10, 5, 11], [9, 10, 11, 12], [9, 13, 5, 11], [10, 11, 3, 6], [10, 11, 3, 7], [10, 11, 6, 12], [10, 14, 6, 12], [11, 12, 4, 7], [11, 12, 4, 8], [11, 12, 7, 9], [11, 13, 7, 9], [12, 9, 1, 5], [12, 9, 1, 8], [12, 9, 8, 10], [12, 14, 8, 10]], name="Rudin ball") def ZieglerBall(): @@ -1529,12 +1827,7 @@ def ZieglerBall(): True """ - return UniqueSimplicialComplex( - [[1, 2, 3, 4], [1, 2, 5, 6], [1, 5, 6, 9], [2, 5, 6, 0], [3, 6, 7, 8], [4, 5, 7, 8], - [2, 3, 6, 7], [1, 6, 2, 9], [2, 6, 7, 0], [3, 2, 4, 8], [4, 1, 3, 7], [3, 4, 7, 8], - [1, 2, 4, 9], [2, 7, 3, 0], [3, 2, 6, 8], [4, 1, 5, 7], [4, 1, 8, 5], [1, 4, 8, 9], - [2, 3, 1, 0], [1, 8, 5, 9], [2, 1, 5, 0]], - name="Ziegler ball") + return UniqueSimplicialComplex([[1, 2, 3, 4], [1, 2, 5, 6], [1, 5, 6, 9], [2, 5, 6, 0], [3, 6, 7, 8], [4, 5, 7, 8], [2, 3, 6, 7], [1, 6, 2, 9], [2, 6, 7, 0], [3, 2, 4, 8], [4, 1, 3, 7], [3, 4, 7, 8], [1, 2, 4, 9], [2, 7, 3, 0], [3, 2, 6, 8], [4, 1, 5, 7], [4, 1, 8, 5], [1, 4, 8, 9], [2, 3, 1, 0], [1, 8, 5, 9], [2, 1, 5, 0]], name="Ziegler ball") def DunceHat(): @@ -1556,11 +1849,7 @@ def DunceHat(): sage: D.is_cohen_macaulay() # needs sage.modules True """ - return UniqueSimplicialComplex( - [[1, 3, 5], [2, 3, 5], [2, 4, 5], [1, 2, 4], [1, 3, 4], [3, 4, 8], - [1, 2, 8], [1, 7, 8], [1, 2, 7], [2, 3, 7], [3, 6, 7], [1, 3, 6], - [1, 5, 6], [4, 5, 6], [4, 6, 8], [6, 7, 8], [2, 3, 8]], - name="Minimal triangulation of the dunce hat") + return UniqueSimplicialComplex([[1, 3, 5], [2, 3, 5], [2, 4, 5], [1, 2, 4], [1, 3, 4], [3, 4, 8], [1, 2, 8], [1, 7, 8], [1, 2, 7], [2, 3, 7], [3, 6, 7], [1, 3, 6], [1, 5, 6], [4, 5, 6], [4, 6, 8], [6, 7, 8], [2, 3, 8]], name="Minimal triangulation of the dunce hat") def FareyMap(p): @@ -1616,18 +1905,14 @@ def normalise(pair): return (0, (-y) % p) return (x, y) - points = [(x, y) for x in range(p) for y in range(p) - if (x, y) != (0, 0) and - (x != 0 and p - x >= x or (x == 0 and p - y >= y))] + points = [(x, y) for x in range(p) for y in range(p) if (x, y) != (0, 0) and (x != 0 and p - x >= x or (x == 0 and p - y >= y))] convert = {pt: i + 1 for i, pt in enumerate(points)} F = GF(p) S = matrix(F, 2, 2, [0, -1, 1, 0]) T = matrix(F, 2, 2, [1, 1, 0, 1]) - perm_S = Permutation([convert[normalise(S * vector(pt))] - for pt in points]) - perm_T = Permutation([convert[normalise(T * vector(pt))] - for pt in points]) + perm_S = Permutation([convert[normalise(S * vector(pt))] for pt in points]) + perm_T = Permutation([convert[normalise(T * vector(pt))] for pt in points]) group = PermutationGroup([perm_S, perm_T]) triangle = [convert[normalise(pt)] for pt in [(1, 0), (0, 1), (1, 1)]] triangle = libgap.Set(triangle) @@ -1664,12 +1949,5 @@ def GenusSix(): Journal of Combinatorial Theory, Series A, 75, 148-162 (1996), :doi:`10.1006/jcta.1996.0069` """ - L = ["014", "018", "023", "027", "036", "049", - "056", "05b", "07a", "08a", "09b", - "125", "126", "137", "139", "147", "15a", - "16b", "18b", "19a", "23b", "248", - "24a", "258", "269", "279", "2ab", "345", - "34b", "35a", "367", "389", "38a", - "459", "46a", "46b", "478", "568", "579", - "57b", "67a", "689", "78b", "9ab"] + L = ["014", "018", "023", "027", "036", "049", "056", "05b", "07a", "08a", "09b", "125", "126", "137", "139", "147", "15a", "16b", "18b", "19a", "23b", "248", "24a", "258", "269", "279", "2ab", "345", "34b", "35a", "367", "389", "38a", "459", "46a", "46b", "478", "568", "579", "57b", "67a", "689", "78b", "9ab"] return SimplicialComplex([list(w) for w in L]) diff --git a/src/sage/topology/simplicial_complex_homset.py b/src/sage/topology/simplicial_complex_homset.py index 12180b91ab0..dcd121bdaae 100644 --- a/src/sage/topology/simplicial_complex_homset.py +++ b/src/sage/topology/simplicial_complex_homset.py @@ -114,8 +114,7 @@ def diagonal_morphism(self, rename_vertices=True): """ # Preserve whether the codomain is mutable when renaming the vertices. immutable = self._codomain.is_immutable() - X = self._domain.product(self._domain, rename_vertices=rename_vertices, - immutable=immutable) + X = self._domain.product(self._domain, rename_vertices=rename_vertices, immutable=immutable) if self._codomain != X: raise TypeError("diagonal morphism is only defined for Hom(X,XxX)") f = {} diff --git a/src/sage/topology/simplicial_complex_morphism.py b/src/sage/topology/simplicial_complex_morphism.py index c0cc2bbd589..59fba0c98a7 100644 --- a/src/sage/topology/simplicial_complex_morphism.py +++ b/src/sage/topology/simplicial_complex_morphism.py @@ -118,6 +118,7 @@ class SimplicialComplexMorphism(Morphism): """ An element of this class is a morphism of simplicial complexes. """ + def __init__(self, f, X, Y) -> None: """ Input is a dictionary ``f``, the domain ``X``, and the codomain ``Y``. @@ -186,10 +187,7 @@ def __eq__(self, x) -> bool: sage: k == l True """ - return (isinstance(x, SimplicialComplexMorphism) and - self.codomain() == x.codomain() and - self.domain() == x.domain() and - self._vertex_dictionary == x._vertex_dictionary) + return isinstance(x, SimplicialComplexMorphism) and self.codomain() == x.codomain() and self.domain() == x.domain() and self._vertex_dictionary == x._vertex_dictionary def __call__(self, x, orientation=False): """ @@ -308,8 +306,7 @@ def _repr_defn(self) -> str: codomain = [vd[v] for v in domain] return "{} --> {}".format(domain, codomain) - def associated_chain_complex_morphism(self, base_ring=ZZ, - augmented=False, cochain=False): + def associated_chain_complex_morphism(self, base_ring=ZZ, augmented=False, cochain=False): """ Return the associated chain complex morphism of ``self``. @@ -393,24 +390,24 @@ def associated_chain_complex_morphism(self, base_ring=ZZ, matrices[-1] = m else: matrices[-1] = m.transpose() - for dim in range(min_dim+1): + for dim in range(min_dim + 1): X_faces = self.domain()._n_cells_sorted(dim) Y_faces = self.codomain()._n_cells_sorted(dim) num_faces_X = len(X_faces) num_faces_Y = len(Y_faces) - mval = [0 for i in range(num_faces_X*num_faces_Y)] + mval = [0 for i in range(num_faces_X * num_faces_Y)] for i in X_faces: y, oriented = self(i, orientation=True) if y.dimension() < dim: pass else: - mval[X_faces.index(i)+(Y_faces.index(y)*num_faces_X)] = oriented + mval[X_faces.index(i) + (Y_faces.index(y) * num_faces_X)] = oriented m = matrix(base_ring, num_faces_Y, num_faces_X, mval, sparse=True) if not cochain: matrices[dim] = m else: matrices[dim] = m.transpose() - for dim in range(min_dim+1, max_dim+1): + for dim in range(min_dim + 1, max_dim + 1): try: l1 = len(self.codomain().n_cells(dim)) except KeyError: @@ -425,12 +422,8 @@ def associated_chain_complex_morphism(self, base_ring=ZZ, else: matrices[dim] = m.transpose() if not cochain: - return ChainComplexMorphism(matrices, - self.domain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=cochain), - self.codomain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=cochain)) - return ChainComplexMorphism(matrices, - self.codomain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=cochain), - self.domain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=cochain)) + return ChainComplexMorphism(matrices, self.domain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=cochain), self.codomain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=cochain)) + return ChainComplexMorphism(matrices, self.codomain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=cochain), self.domain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=cochain)) def image(self): """ @@ -604,8 +597,8 @@ def fiber_product(self, other, rename_vertices=True): for j in eff2: if self(Simplex([i])) == other(Simplex([j])): if rename_vertices: - v.append("L"+str(i)+"R"+str(j)) - f["L"+str(i)+"R"+str(j)] = self._vertex_dictionary[i] + v.append("L" + str(i) + "R" + str(j)) + f["L" + str(i) + "R" + str(j)] = self._vertex_dictionary[i] else: v.append((i, j)) f[(i, j)] = self._vertex_dictionary[i] @@ -654,8 +647,7 @@ def mapping_torus(self): for facet in self.domain()._facets: left = [("I0", v) for v in facet] right = [("I2", map_dict[v]) for v in facet] - facets.extend(tuple(left[:i + 1] + right[i:]) - for i in range(facet.dimension() + 1)) + facets.extend(tuple(left[: i + 1] + right[i:]) for i in range(facet.dimension() + 1)) return SimplicialComplex(facets) def induced_homology_morphism(self, base_ring=None, cohomology=False): @@ -740,6 +732,7 @@ def induced_homology_morphism(self, base_ring=None, cohomology=False): sage: h = Hom(S, S2)({0: 0, 1: 1, 2: 2}).induced_homology_morphism() # needs sage.modules """ from sage.homology.homology_morphism import InducedHomologyMorphism + return InducedHomologyMorphism(self, base_ring, cohomology) def is_contiguous_to(self, other): @@ -802,5 +795,4 @@ def is_contiguous_to(self, other): return False domain = self.domain() codomain = self.codomain() - return all(Simplex(self(sigma).set().union(other(sigma))) in codomain - for sigma in domain.facets()) + return all(Simplex(self(sigma).set().union(other(sigma))) in codomain for sigma in domain.facets()) diff --git a/src/sage/topology/simplicial_set.py b/src/sage/topology/simplicial_set.py index c4efc80ad60..4a1edf8ca1e 100644 --- a/src/sage/topology/simplicial_set.py +++ b/src/sage/topology/simplicial_set.py @@ -278,6 +278,7 @@ ######################################################################## # The classes for simplices. + class AbstractSimplex_class(SageObject): """ A simplex of dimension ``dim``. @@ -295,8 +296,7 @@ class AbstractSimplex_class(SageObject): :func:`AbstractSimplex`. See that function for more documentation. """ - def __init__(self, dim, degeneracies=(), underlying=None, name=None, - latex_name=None) -> None: + def __init__(self, dim, degeneracies=(), underlying=None, name=None, latex_name=None) -> None: """ A simplex of dimension ``dim``. @@ -382,10 +382,9 @@ def __init__(self, dim, degeneracies=(), underlying=None, name=None, self._dim = dim if degeneracies: self._degens = standardize_degeneracies(*degeneracies) - for (d, s) in enumerate(reversed(self._degens)): + for d, s in enumerate(reversed(self._degens)): if d + dim < s: - raise ValueError('invalid list of degeneracy maps ' - 'on {}-simplex'.format(dim)) + raise ValueError('invalid list of degeneracy maps ' 'on {}-simplex'.format(dim)) if underlying is None: self._underlying = NonDegenerateSimplex(dim) else: @@ -450,8 +449,7 @@ def __eq__(self, other) -> bool: """ if not isinstance(other, AbstractSimplex_class): return False - return (self._degens == other._degens - and self.nondegenerate() is other.nondegenerate()) + return self._degens == other._degens and self.nondegenerate() is other.nondegenerate() def __ne__(self, other) -> bool: """ @@ -753,9 +751,7 @@ def apply_degeneracies(self, *args): if not args: return self underlying = self.nondegenerate() - return AbstractSimplex(underlying.dimension(), - degeneracies=list(args) + self.degeneracies(), - underlying=underlying) + return AbstractSimplex(underlying.dimension(), degeneracies=list(args) + self.degeneracies(), underlying=underlying) def __copy__(self): """ @@ -960,8 +956,8 @@ def __init__(self, dim, name=None, latex_name=None) -> None: # The following function returns an instance of either # AbstractSimplex_class or NonDegenerateSimplex. -def AbstractSimplex(dim, degeneracies=(), underlying=None, - name=None, latex_name=None): + +def AbstractSimplex(dim, degeneracies=(), underlying=None, name=None, latex_name=None): r""" An abstract simplex, a building block of a simplicial set. @@ -1082,17 +1078,14 @@ def AbstractSimplex(dim, degeneracies=(), underlying=None, if degeneracies: if underlying is None: underlying = NonDegenerateSimplex(dim) - return AbstractSimplex_class(dim, degeneracies=degeneracies, - underlying=underlying, - name=name, - latex_name=latex_name) - return NonDegenerateSimplex(dim, name=name, - latex_name=latex_name) + return AbstractSimplex_class(dim, degeneracies=degeneracies, underlying=underlying, name=name, latex_name=latex_name) + return NonDegenerateSimplex(dim, name=name, latex_name=latex_name) ######################################################################## # The main classes for simplicial sets. + class SimplicialSet_arbitrary(Parent): r""" A simplicial set. @@ -1186,8 +1179,7 @@ def faces(self, simplex): return self.n_skeleton(dim).face_data()[simplex] underlying = simplex.nondegenerate() faces = [] - for J, t in [face_degeneracies(m, simplex.degeneracies()) - for m in range(dim+1)]: + for J, t in [face_degeneracies(m, simplex.degeneracies()) for m in range(dim + 1)]: if t is None: faces.append(underlying.apply_degeneracies(*J)) else: @@ -1216,8 +1208,7 @@ def face(self, simplex, i): True """ if i < 0 or i > simplex.dimension(): - raise ValueError('cannot compute face {} of {}-dimensional ' - 'simplex'.format(i, simplex.dimension())) + raise ValueError('cannot compute face {} of {}-dimensional ' 'simplex'.format(i, simplex.dimension())) faces = self.faces(simplex) if faces is not None: return self.faces(simplex)[i] @@ -1296,8 +1287,7 @@ def alexander_whitney(self, simplex, dim_left): """ dim = simplex.dimension() if dim_left < 0 or dim_left > dim: - raise ValueError('alexander_whitney is only valid if dim_left ' - 'is between 0 and the dimension of the simplex') + raise ValueError('alexander_whitney is only valid if dim_left ' 'is between 0 and the dimension of the simplex') left = simplex for i in range(dim, dim_left, -1): left = self.face(left, i) @@ -1376,8 +1366,7 @@ def nondegenerate_simplices(self, max_dim=None): return list(self._simplices) return [sigma for sigma in self._simplices if sigma.dimension() <= max_dim] if max_dim is None: - raise NotImplementedError('this simplicial set may be ' - 'infinite, so specify max_dim') + raise NotImplementedError('this simplicial set may be ' 'infinite, so specify max_dim') return list(self.n_skeleton(max_dim)._simplices) def cells(self, subcomplex=None, max_dim=None): @@ -1445,13 +1434,11 @@ def cells(self, subcomplex=None, max_dim=None): else: simplices[sigma.dimension()] = [sigma] if max_dim is not None: - return {d: sorted(simplices[d]) for d in simplices - if d <= max_dim} + return {d: sorted(simplices[d]) for d in simplices if d <= max_dim} return {d: sorted(simplices[d]) for d in simplices} # Infinite case: if max_dim is None: - raise NotImplementedError('this simplicial set may be ' - 'infinite, so specify max_dim') + raise NotImplementedError('this simplicial set may be ' 'infinite, so specify max_dim') return self.n_skeleton(max_dim).cells() # subcomplex is not None: return self.quotient(subcomplex).cells(max_dim=max_dim) @@ -1549,8 +1536,7 @@ def all_n_simplices(self, n): ans = {_ for _ in non_degen if _.dimension() == n} for sigma in non_degen: d = sigma.dimension() - ans.update([sigma.apply_degeneracies(*_) - for _ in all_degeneracies(d, n-d)]) + ans.update([sigma.apply_degeneracies(*_) for _ in all_degeneracies(d, n - d)]) return sorted(ans) def _map_from_empty_set(self): @@ -1570,6 +1556,7 @@ def _map_from_empty_set(self): Defn: [] --> [] """ from sage.topology.simplicial_set_examples import Empty + return Empty().Hom(self)({}) def identity(self): @@ -1641,6 +1628,7 @@ def constant_map(self, codomain=None, point=None): ValueError: codomain is not pointed, so specify a target for the constant map """ from sage.topology.simplicial_set_examples import Point + if codomain is None: codomain = Point() return self.Hom(codomain).constant_map(point) @@ -1836,6 +1824,7 @@ def subsimplicial_set(self, simplices): # If simplices is a simplicial complex, turn it into a list of # nondegenerate simplices. from .simplicial_set_constructions import SubSimplicialSet + if isinstance(simplices, SimplicialComplex): new = [] for f in simplices.facets(): @@ -1881,9 +1870,7 @@ def subsimplicial_set(self, simplices): data[x] = None return SubSimplicialSet(data, self) - def chain_complex(self, dimensions=None, base_ring=ZZ, augmented=False, - cochain=False, verbose=False, subcomplex=None, - check=False): + def chain_complex(self, dimensions=None, base_ring=ZZ, augmented=False, cochain=False, verbose=False, subcomplex=None, check=False): r""" Return the normalized chain complex. @@ -1936,20 +1923,14 @@ def chain_complex(self, dimensions=None, base_ring=ZZ, augmented=False, ... NotImplementedError: this simplicial set may be infinite, so specify dimensions when computing its chain complex """ - kwds = {'base_ring': base_ring, 'augmented': augmented, 'cochain': cochain, - 'verbose': verbose, 'subcomplex': subcomplex, 'check': check} + kwds = {'base_ring': base_ring, 'augmented': augmented, 'cochain': cochain, 'verbose': verbose, 'subcomplex': subcomplex, 'check': check} if not self.is_finite(): if dimensions is None: - raise NotImplementedError('this simplicial set may be infinite, ' - 'so specify dimensions when computing ' - 'its chain complex') + raise NotImplementedError('this simplicial set may be infinite, ' 'so specify dimensions when computing ' 'its chain complex') else: max_dim = max(dimensions) - return SimplicialSet_finite.chain_complex(self.n_skeleton(max_dim+1), - dimensions=dimensions, - **kwds) - return SimplicialSet_finite.chain_complex(self, dimensions=dimensions, - **kwds) + return SimplicialSet_finite.chain_complex(self.n_skeleton(max_dim + 1), dimensions=dimensions, **kwds) + return SimplicialSet_finite.chain_complex(self, dimensions=dimensions, **kwds) def homology(self, dim=None, **kwds): r""" @@ -2012,18 +1993,17 @@ def homology(self, dim=None, **kwds): """ if not self.is_finite(): if dim is None: - raise NotImplementedError('this simplicial set may be infinite, so ' - 'specify dimensions when computing homology') + raise NotImplementedError('this simplicial set may be infinite, so ' 'specify dimensions when computing homology') else: if isinstance(dim, (list, tuple, range)): dim = list(dim) max_dim = max(dim) - space = self.n_skeleton(max_dim+1) + space = self.n_skeleton(max_dim + 1) min_dim = min(dim) H = GenericCellComplex.homology(space, **kwds) return {n: H[n] for n in H if min_dim <= n <= max_dim} max_dim = dim - space = self.n_skeleton(max_dim+1) + space = self.n_skeleton(max_dim + 1) else: space = self return GenericCellComplex.homology(space, dim=dim, **kwds) @@ -2164,9 +2144,7 @@ def n_chains(self, n, base_ring=ZZ, cochains=False): [\chi_(1,2), \chi_(1,2,3), \chi_(1,3), \chi_(1,3,2), \chi_(2,3)] """ if self.is_finite(): - return GenericCellComplex.n_chains(self, n=n, - base_ring=base_ring, - cochains=cochains) + return GenericCellComplex.n_chains(self, n=n, base_ring=base_ring, cochains=cochains) from sage.homology.chains import Chains, Cochains @@ -2276,8 +2254,8 @@ def quotient(self, subcomplex, vertex_name='*'): 1 """ from .simplicial_set_constructions import SubSimplicialSet - from .simplicial_set_constructions import QuotientOfSimplicialSet, \ - QuotientOfSimplicialSet_finite + from .simplicial_set_constructions import QuotientOfSimplicialSet, QuotientOfSimplicialSet_finite + if not isinstance(subcomplex, SimplicialSet_finite): # If it's not a simplicial set, subcomplex should be a # list, tuple, or set of simplices, so form the actual @@ -2286,14 +2264,11 @@ def quotient(self, subcomplex, vertex_name='*'): else: # Test whether subcomplex is actually a subcomplex of # self. - if (not isinstance(subcomplex, SubSimplicialSet) - and subcomplex.ambient_space() == self): + if not isinstance(subcomplex, SubSimplicialSet) and subcomplex.ambient_space() == self: raise ValueError('the "subcomplex" is not actually a subcomplex') if self.is_finite(): - return QuotientOfSimplicialSet_finite(subcomplex.inclusion_map(), - vertex_name=vertex_name) - return QuotientOfSimplicialSet(subcomplex.inclusion_map(), - vertex_name=vertex_name) + return QuotientOfSimplicialSet_finite(subcomplex.inclusion_map(), vertex_name=vertex_name) + return QuotientOfSimplicialSet(subcomplex.inclusion_map(), vertex_name=vertex_name) def disjoint_union(self, *others): """ @@ -2350,8 +2325,8 @@ def disjoint_union(self, *others): sage: K.factors() (S^2, S^2, S^2) """ - from .simplicial_set_constructions import DisjointUnionOfSimplicialSets, \ - DisjointUnionOfSimplicialSets_finite + from .simplicial_set_constructions import DisjointUnionOfSimplicialSets, DisjointUnionOfSimplicialSets_finite + if all(space.is_finite() for space in [self] + list(others)): return DisjointUnionOfSimplicialSets_finite((self,) + others) return DisjointUnionOfSimplicialSets((self,) + others) @@ -2415,9 +2390,7 @@ def coproduct(self, *others): if self.is_pointed() and all(X.is_pointed() for X in others): return self.wedge(*others) if self.is_pointed() or any(X.is_pointed() for X in others): - raise ValueError('some, but not all, of the simplicial sets are pointed, ' - 'so the categorical coproduct is not defined: the ' - 'category is ambiguous') + raise ValueError('some, but not all, of the simplicial sets are pointed, ' 'so the categorical coproduct is not defined: the ' 'category is ambiguous') return self.disjoint_union(*others) def product(self, *others): @@ -2519,8 +2492,8 @@ def product(self, *others): To: S^2 x S^3 Defn: [v_0, sigma_2] --> [(v_0, v_0), (sigma_2, s_1 s_0 v_0)] """ - from .simplicial_set_constructions import ProductOfSimplicialSets, \ - ProductOfSimplicialSets_finite + from .simplicial_set_constructions import ProductOfSimplicialSets, ProductOfSimplicialSets_finite + if self.is_finite() and all(X.is_finite() for X in others): return ProductOfSimplicialSets_finite((self,) + others) return ProductOfSimplicialSets((self,) + others) @@ -2630,8 +2603,8 @@ def pushout(self, *maps): ... ValueError: the domains of the maps must be equal """ - from .simplicial_set_constructions import PushoutOfSimplicialSets, \ - PushoutOfSimplicialSets_finite + from .simplicial_set_constructions import PushoutOfSimplicialSets, PushoutOfSimplicialSets_finite + if any(self != f.domain() for f in maps): raise ValueError('the domains of the maps must be equal') if not maps: @@ -2729,8 +2702,8 @@ def pullback(self, *maps): ... ValueError: the codomains of the maps must be equal """ - from .simplicial_set_constructions import PullbackOfSimplicialSets, \ - PullbackOfSimplicialSets_finite + from .simplicial_set_constructions import PullbackOfSimplicialSets, PullbackOfSimplicialSets_finite + if any(self != f.codomain() for f in maps): raise ValueError('the codomains of the maps must be equal') if not maps: @@ -2812,8 +2785,8 @@ def wedge(self, *others): ... ValueError: the simplicial sets must be pointed """ - from .simplicial_set_constructions import WedgeOfSimplicialSets, \ - WedgeOfSimplicialSets_finite + from .simplicial_set_constructions import WedgeOfSimplicialSets, WedgeOfSimplicialSets_finite + if all(space.is_finite() for space in [self] + list(others)): return WedgeOfSimplicialSets_finite((self,) + others) return WedgeOfSimplicialSets((self,) + others) @@ -2870,9 +2843,8 @@ def cone(self): To: Reduced cone of Simplicial set with 2 non-degenerate simplices Defn: [v, e] --> [*, e] """ - from .simplicial_set_constructions import \ - ConeOfSimplicialSet, ConeOfSimplicialSet_finite, \ - ReducedConeOfSimplicialSet, ReducedConeOfSimplicialSet_finite + from .simplicial_set_constructions import ConeOfSimplicialSet, ConeOfSimplicialSet_finite, ReducedConeOfSimplicialSet, ReducedConeOfSimplicialSet_finite + if self.is_pointed(): if self.is_finite(): return ReducedConeOfSimplicialSet_finite(self) @@ -2920,8 +2892,8 @@ def suspension(self, n=1): ... ValueError: n must be nonnegative """ - from .simplicial_set_constructions import \ - SuspensionOfSimplicialSet, SuspensionOfSimplicialSet_finite + from .simplicial_set_constructions import SuspensionOfSimplicialSet, SuspensionOfSimplicialSet_finite + if n < 0: raise ValueError('n must be nonnegative') if n == 0: @@ -2932,7 +2904,7 @@ def suspension(self, n=1): Sigma = SuspensionOfSimplicialSet(self) if n == 1: return Sigma - return Sigma.suspension(n-1) + return Sigma.suspension(n - 1) def join(self, *others): """ @@ -3026,6 +2998,7 @@ def _Hom_(self, other, category=None): """ # Import this here to prevent circular imports. from sage.topology.simplicial_set_morphism import SimplicialSetHomset + # Error-checking on the ``category`` argument is done when # calling Hom(X,Y), so no need to do it again here. if category is None: @@ -3191,8 +3164,7 @@ class SimplicialSet_finite(SimplicialSet_arbitrary, GenericCellComplex): Y """ - def __init__(self, data, base_point=None, name=None, check=True, - category=None, latex_name=None) -> None: + def __init__(self, data, base_point=None, name=None, check=True, category=None, latex_name=None) -> None: r""" TESTS:: @@ -3248,6 +3220,7 @@ def __init__(self, data, base_point=None, name=None, check=True, sage: TestSuite(simplicial_sets.Sphere(5)).run(skip=skip) sage: TestSuite(simplicial_sets.RealProjectiveSpace(6)).run(skip=skip) # needs sage.groups """ + def face(sigma, i): """ Return the i-th face of sigma, a simplex in this simplicial set. @@ -3268,7 +3241,7 @@ def face(sigma, i): if isinstance(data, SimplicialComplex): simplices = {} faces = {} - for d in range(data.dimension()+1): + for d in range(data.dimension() + 1): old_faces = faces faces = {} for idx, sigma in enumerate(data.n_cells(d)): @@ -3284,7 +3257,7 @@ def face(sigma, i): elif isinstance(data, DeltaComplex): simplices = {} current = [] - for d in range(data.dimension()+1): + for d in range(data.dimension() + 1): faces = tuple(current) current = [] for idx, sigma in enumerate(data.n_cells(d)): @@ -3301,18 +3274,15 @@ def face(sigma, i): elif isinstance(data, SimplicialSet_finite): data = dict(copy.deepcopy(data._data)) else: - raise NotImplementedError('I do not know how to convert this ' - 'to a simplicial set') + raise NotImplementedError('I do not know how to convert this ' 'to a simplicial set') # Convert each value in data to a tuple, and then convert all # of data to a tuple, so that it is hashable. for x in data: if data[x]: if x.dimension() != len(data[x]) - 1: - raise ValueError('wrong number of faces for simplex ' - 'in dimension {}'.format(x.dimension())) + raise ValueError('wrong number of faces for simplex ' 'in dimension {}'.format(x.dimension())) if not all(y.dimension() == x.dimension() - 1 for y in data[x]): - raise ValueError('faces of a {}-simplex have the wrong ' - 'dimension'.format(x.dimension())) + raise ValueError('faces of a {}-simplex have the wrong ' 'dimension'.format(x.dimension())) data[x] = tuple(data[x]) # To obtain the non-degenerate simplices, look at both the @@ -3334,12 +3304,10 @@ def face(sigma, i): for sigma in simplices: d = sigma.dimension() if d >= 2: - for j in range(d+1): + for j in range(d + 1): for i in range(j): - if face(face(sigma, j), i) != face(face(sigma, i), j-1): - raise ValueError('simplicial identity d_i d_j ' - '= d_{{j-1}} d_i fails ' - 'in dimension {}'.format(d)) + if face(face(sigma, j), i) != face(face(sigma, i), j - 1): + raise ValueError('simplicial identity d_i d_j ' '= d_{{j-1}} d_i fails ' 'in dimension {}'.format(d)) # Now define the attributes for an instance of this class. # self._data: a tuple representing the defining data of the @@ -3350,8 +3318,7 @@ def face(sigma, i): # self._basepoint: the base point, or None. if base_point is not None: if base_point not in simplices: - raise ValueError('the base point is not a simplex in ' - 'this simplicial set') + raise ValueError('the base point is not a simplex in ' 'this simplicial set') if base_point.dimension() != 0: raise ValueError('the base "point" is not a zero-simplex') self._basepoint = base_point @@ -3390,13 +3357,8 @@ def __eq__(self, other) -> bool: False """ if self.is_pointed(): - return (isinstance(other, SimplicialSet_finite) - and other.is_pointed() - and sorted(self._data) == sorted(other._data) - and self.base_point() == other.base_point()) - return (isinstance(other, SimplicialSet_finite) - and not other.is_pointed() - and sorted(self._data) == sorted(other._data)) + return isinstance(other, SimplicialSet_finite) and other.is_pointed() and sorted(self._data) == sorted(other._data) and self.base_point() == other.base_point() + return isinstance(other, SimplicialSet_finite) and not other.is_pointed() and sorted(self._data) == sorted(other._data) def __ne__(self, other) -> bool: """ @@ -3516,8 +3478,7 @@ def n_skeleton(self, n): sage: Y.n_skeleton(2).nondegenerate_simplices() [v, w, tau] """ - data = [x for x in self.nondegenerate_simplices() - if x.dimension() <= n] + data = [x for x in self.nondegenerate_simplices() if x.dimension() <= n] return self.subsimplicial_set(data) def _facets_(self): @@ -3569,7 +3530,7 @@ def f_vector(self): sage: simplicial_sets.Sphere(3).f_vector() [1, 0, 0, 1] """ - return [len(self.n_cells(_)) for _ in range(self.dimension()+1)] + return [len(self.n_cells(_)) for _ in range(self.dimension() + 1)] def euler_characteristic(self): r""" @@ -3586,11 +3547,9 @@ def euler_characteristic(self): sage: simplicial_sets.KleinBottle().euler_characteristic() 0 """ - return sum([(-1)**n * num for (n, num) in enumerate(self.f_vector())]) + return sum([(-1) ** n * num for (n, num) in enumerate(self.f_vector())]) - def chain_complex(self, dimensions=None, base_ring=ZZ, augmented=False, - cochain=False, verbose=False, subcomplex=None, - check=False): + def chain_complex(self, dimensions=None, base_ring=ZZ, augmented=False, cochain=False, verbose=False, subcomplex=None, check=False): r""" Return the normalized chain complex. @@ -3666,10 +3625,8 @@ def chain_complex(self, dimensions=None, base_ring=ZZ, augmented=False, if dimensions is None: if not self.cells(): # Empty if cochain: - return ChainComplex({-1: matrix(base_ring, 0, 0)}, - degree_of_differential=1) - return ChainComplex({0: matrix(base_ring, 0, 0)}, - degree_of_differential=-1) + return ChainComplex({-1: matrix(base_ring, 0, 0)}, degree_of_differential=1) + return ChainComplex({0: matrix(base_ring, 0, 0)}, degree_of_differential=-1) dimensions = list(range(self.dimension() + 1)) else: if not isinstance(dimensions, (list, tuple, range)): @@ -3708,9 +3665,8 @@ def chain_complex(self, dimensions=None, base_ring=ZZ, augmented=False, rank = 0 current = [] if augmented and first == 0: - differentials[first-1] = matrix(base_ring, 0, 1) - differentials[first] = matrix(base_ring, 1, rank, - [1] * rank) + differentials[first - 1] = matrix(base_ring, 0, 1) + differentials[first] = matrix(base_ring, 1, rank, [1] * rank) else: differentials[first] = matrix(base_ring, 0, rank) @@ -3739,8 +3695,7 @@ def chain_complex(self, dimensions=None, base_ring=ZZ, augmented=False, matrix_data[(row, col)] = sign sign *= -1 - differentials[d] = matrix(base_ring, old_rank, - rank, matrix_data) + differentials[d] = matrix(base_ring, old_rank, rank, matrix_data) else: rank = 0 @@ -3750,11 +3705,9 @@ def chain_complex(self, dimensions=None, base_ring=ZZ, augmented=False, if cochain: new_diffs = {} for d in differentials: - new_diffs[d-1] = differentials[d].transpose() - return ChainComplex(new_diffs, degree_of_differential=1, - check=check) - return ChainComplex(differentials, degree_of_differential=-1, - check=check) + new_diffs[d - 1] = differentials[d].transpose() + return ChainComplex(new_diffs, degree_of_differential=1, check=check) + return ChainComplex(differentials, degree_of_differential=-1, check=check) @cached_method def algebraic_topological_model(self, base_ring=None): @@ -3825,6 +3778,7 @@ def algebraic_topological_model(self, base_ring=None): ######################################################################## # Functions for manipulating face and degeneracy maps. + def standardize_degeneracies(*L): r""" Return list of indices of degeneracy maps in standard (decreasing) @@ -3881,7 +3835,7 @@ def standardize_degeneracies(*L): inadmissible = True while inadmissible: inadmissible = False - for idx in range(len(J)-1): + for idx in range(len(J) - 1): if J[idx] <= J[idx + 1]: inadmissible = True tmp = J[idx] @@ -3925,11 +3879,10 @@ def all_degeneracies(n, l=1): if l == 0: return set() if l == 1: - return {(_,) for _ in range(n+1)} + return {(_,) for _ in range(n + 1)} ans = set() - for i in range(n+l): - ans.update({tuple(standardize_degeneracies(*([i] + list(_)))) - for _ in all_degeneracies(n, l-1)}) + for i in range(n + l): + ans.update({tuple(standardize_degeneracies(*([i] + list(_)))) for _ in all_degeneracies(n, l - 1)}) return ans @@ -3971,7 +3924,7 @@ def standardize_face_maps(*L): inadmissible = True while inadmissible: inadmissible = False - for idx in range(len(J)-1): + for idx in range(len(J) - 1): if J[idx] < J[idx + 1]: inadmissible = True tmp = J[idx] @@ -4030,8 +3983,8 @@ def face_degeneracies(m, I): if t is None: J.append(i) elif t < i: - J.append(i-1) - elif t == i or t == i+1: + J.append(i - 1) + elif t == i or t == i + 1: t = None else: J.append(i) @@ -4041,6 +3994,7 @@ def face_degeneracies(m, I): ######################################################################## + def shrink_simplicial_complex(K): """ Convert the simplicial complex ``K`` to a "small" simplicial set. diff --git a/src/sage/topology/simplicial_set_catalog.py b/src/sage/topology/simplicial_set_catalog.py index 0269c8f6628..6bba11836c5 100644 --- a/src/sage/topology/simplicial_set_catalog.py +++ b/src/sage/topology/simplicial_set_catalog.py @@ -46,9 +46,4 @@ {0: 0, 1: 0, 2: Z, 3: Z} """ -from .simplicial_set_examples import (Sphere, ClassifyingSpace, - RealProjectiveSpace, - KleinBottle, Torus, - Simplex, Horn, Point, - ComplexProjectiveSpace, - HopfMap, PresentationComplex) +from .simplicial_set_examples import Sphere, ClassifyingSpace, RealProjectiveSpace, KleinBottle, Torus, Simplex, Horn, Point, ComplexProjectiveSpace, HopfMap, PresentationComplex diff --git a/src/sage/topology/simplicial_set_constructions.py b/src/sage/topology/simplicial_set_constructions.py index 1053628023e..d8195c8878e 100644 --- a/src/sage/topology/simplicial_set_constructions.py +++ b/src/sage/topology/simplicial_set_constructions.py @@ -79,12 +79,11 @@ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from .simplicial_set import AbstractSimplex, \ - SimplicialSet_arbitrary, SimplicialSet_finite, \ - standardize_degeneracies, face_degeneracies +from .simplicial_set import AbstractSimplex, SimplicialSet_arbitrary, SimplicialSet_finite, standardize_degeneracies, face_degeneracies from .simplicial_set_examples import Empty, Point from sage.misc.lazy_import import lazy_import + lazy_import('sage.categories.simplicial_sets', 'SimplicialSets') @@ -98,6 +97,7 @@ # often (-1, Empty()): the (-1)-skeleton is the empty simplicial # set. It gets used and updated in the n_skeleton method. + class SubSimplicialSet(SimplicialSet_finite, UniqueRepresentation): @staticmethod def __classcall__(self, data, ambient=None): @@ -169,9 +169,7 @@ def __init__(self, data, ambient=None): data = dict(data) if ambient is None: ambient = self - if (ambient.is_pointed() - and hasattr(ambient, '_basepoint') - and ambient.base_point() in data): + if ambient.is_pointed() and hasattr(ambient, '_basepoint') and ambient.base_point() in data: SimplicialSet_finite.__init__(self, data, base_point=ambient.base_point()) else: SimplicialSet_finite.__init__(self, data) @@ -291,6 +289,7 @@ def __init__(self, maps=None): """ # Import this here to prevent circular imports. from sage.topology.simplicial_set_morphism import SimplicialSetMorphism + if maps and any(not isinstance(f, SimplicialSetMorphism) for f in maps): raise ValueError('the maps must be morphisms of simplicial sets') @@ -414,6 +413,7 @@ class PullbackOfSimplicialSets_finite(PullbackOfSimplicialSets, SimplicialSet_fi the pullback and the pullback's universal property: see :meth:`structure_map` and :meth:`universal_property`. """ + @staticmethod def __classcall_private__(self, maps=None): """ @@ -468,6 +468,7 @@ def __init__(self, maps=None): """ # Import this here to prevent circular imports. from sage.topology.simplicial_set_morphism import SimplicialSetMorphism + if maps and any(not isinstance(f, SimplicialSetMorphism) for f in maps): raise ValueError('the maps must be morphisms of simplicial sets') if not maps: @@ -479,8 +480,7 @@ def __init__(self, maps=None): if len(maps) == 1: f = maps[0] if f.is_pointed(): - SimplicialSet_finite.__init__(self, f.domain().face_data(), - base_point=f.domain().base_point()) + SimplicialSet_finite.__init__(self, f.domain().face_data(), base_point=f.domain().base_point()) else: SimplicialSet_finite.__init__(self, f.domain().face_data()) self._maps = (f,) @@ -523,15 +523,12 @@ def __init__(self, maps=None): sigma = simplices[0].apply_degeneracies(*degens[0]) target = maps[0](sigma) - if any(target != f(tau.apply_degeneracies(*degen)) - for (f, tau, degen) in zip(maps[1:], simplices[1:], degens[1:])): + if any(target != f(tau.apply_degeneracies(*degen)) for (f, tau, degen) in zip(maps[1:], simplices[1:], degens[1:])): continue simplex_factors = tuple(zip(simplices, tuple(degens))) - s = '(' + ', '.join('{}'.format(_[0].apply_degeneracies(*_[1])) - for _ in simplex_factors) + ')' - ls = '(' + ', '.join('{}'.format(latex(_[0].apply_degeneracies(*_[1]))) - for _ in simplex_factors) + ')' + s = '(' + ', '.join('{}'.format(_[0].apply_degeneracies(*_[1])) for _ in simplex_factors) + ')' + ls = '(' + ', '.join('{}'.format(latex(_[0].apply_degeneracies(*_[1]))) for _ in simplex_factors) + ')' simplex = AbstractSimplex(d, name=s, latex_name=ls) translate[simplex_factors] = simplex # Now compute the faces of simplex. @@ -540,7 +537,7 @@ def __init__(self, maps=None): faces = None else: faces = [] - for i in range(d+1): + for i in range(d + 1): # Compute d_i on simplex. # # face_degens: tuple of pairs (J, t): J is the @@ -692,21 +689,18 @@ def universal_property(self, *maps): if any(g.domain() != domain for g in maps[1:]): raise ValueError('the maps do not all have the same codomain') composite = self._maps[0] * maps[0] - if any(f*g != composite for f, g in zip(self._maps[1:], maps[1:])): + if any(f * g != composite for f, g in zip(self._maps[1:], maps[1:])): raise ValueError('the maps are not compatible') data = {} translate = dict(self._translation) for sigma in domain.nondegenerate_simplices(): - target = tuple([(f(sigma).nondegenerate(), tuple(f(sigma).degeneracies())) - for f in maps]) + target = tuple([(f(sigma).nondegenerate(), tuple(f(sigma).degeneracies())) for f in maps]) # If there any degeneracies in common, remove them: the # dictionary "translate" has nondegenerate simplices as # its keys. in_common = set.intersection(*[set(_[1]) for _ in target]) if in_common: - target = tuple((tau, tuple(sorted(set(degens).difference(in_common), - reverse=True))) - for tau, degens in target) + target = tuple((tau, tuple(sorted(set(degens).difference(in_common), reverse=True))) for tau, degens in target) in_common = sorted(in_common, reverse=True) data[sigma] = translate[target].apply_degeneracies(*in_common) return domain.Hom(self)(data) @@ -720,6 +714,7 @@ class Factors: :class:`WedgeOfSimplicialSets`, and :class:`DisjointUnionOfSimplicialSets`. """ + def factors(self): """ Return the factors involved in this construction of simplicial sets. @@ -870,8 +865,7 @@ def __init__(self, factors=None): 3: Vector space of dimension 2 over Finite Field of size 2, 4: Vector space of dimension 2 over Finite Field of size 2} """ - PullbackOfSimplicialSets.__init__(self, [space.constant_map() - for space in factors]) + PullbackOfSimplicialSets.__init__(self, [space.constant_map() for space in factors]) self._factors = factors def n_skeleton(self, n): @@ -956,16 +950,15 @@ def factor(self, i, as_subset=False): """ if as_subset: if any(not _.is_pointed() for _ in self.factors()): - raise ValueError('"as_subset=True" is only valid ' - 'if each factor is pointed') + raise ValueError('"as_subset=True" is only valid ' 'if each factor is pointed') basept_factors = [sset.base_point() for sset in self.factors()] - basept_factors = basept_factors[:i] + basept_factors[i+1:] + basept_factors = basept_factors[:i] + basept_factors[i + 1 :] to_factors = {v: k for k, v in self._translation} simps = [] for x in self.nondegenerate_simplices(): simplices = [sigma[0] for sigma in to_factors[x]] - if simplices[:i] + simplices[i+1:] == basept_factors: + if simplices[:i] + simplices[i + 1 :] == basept_factors: simps.append(x) return self.subsimplicial_set(simps) return self.factors()[i] @@ -1013,6 +1006,7 @@ class ProductOfSimplicialSets_finite(ProductOfSimplicialSets, PullbackOfSimplici wedge as a subcomplex. See :meth:`projection_map`, :meth:`wedge_as_subset`, and :meth:`fat_wedge_as_subset` """ + def __init__(self, factors=None): r""" Return the product of finite simplicial sets. @@ -1041,8 +1035,7 @@ def __init__(self, factors=None): sage: Z.base_point() (w, v) """ - PullbackOfSimplicialSets_finite.__init__(self, [space.constant_map() - for space in factors]) + PullbackOfSimplicialSets_finite.__init__(self, [space.constant_map() for space in factors]) self._factors = tuple([f.domain() for f in self._maps]) def projection_map(self, i): @@ -1148,8 +1141,7 @@ def __classcall_private__(cls, maps=None, vertex_name=None): True """ if maps: - return super().__classcall__(cls, maps=tuple(maps), - vertex_name=vertex_name) + return super().__classcall__(cls, maps=tuple(maps), vertex_name=vertex_name) return super().__classcall__(cls, vertex_name=vertex_name) def __init__(self, maps=None, vertex_name=None): @@ -1271,6 +1263,7 @@ def __init__(self, maps=None, vertex_name=None): """ # Import this here to prevent circular imports. from sage.topology.simplicial_set_morphism import SimplicialSetMorphism + if maps and any(not isinstance(f, SimplicialSetMorphism) for f in maps): raise ValueError('the maps must be morphisms of simplicial sets') Cat = SimplicialSets() @@ -1322,17 +1315,14 @@ def n_skeleton(self, n): domain = SimplicialSet_finite.n_skeleton(maps[0].domain(), n) codomains = [SimplicialSet_finite.n_skeleton(f.codomain(), n) for f in maps] new_maps = [f.n_skeleton(n, domain, c) for (f, c) in zip(maps, codomains)] - return PushoutOfSimplicialSets_finite(new_maps, - vertex_name=self._vertex_name) - return PushoutOfSimplicialSets_finite(maps, - vertex_name=self._vertex_name) + return PushoutOfSimplicialSets_finite(new_maps, vertex_name=self._vertex_name) + return PushoutOfSimplicialSets_finite(maps, vertex_name=self._vertex_name) start, skel = self._n_skeleton if start == n: return skel if start > n: return skel.n_skeleton(n) - ans = PushoutOfSimplicialSets_finite([f.n_skeleton(n) for f in self._maps], - vertex_name=self._vertex_name) + ans = PushoutOfSimplicialSets_finite([f.n_skeleton(n) for f in self._maps], vertex_name=self._vertex_name) self._n_skeleton = (n, ans) return ans @@ -1403,6 +1393,7 @@ class PushoutOfSimplicialSets_finite(PushoutOfSimplicialSets, SimplicialSet_fini pushout and the pushout's universal property: see :meth:`structure_map` and :meth:`universal_property`. """ + @staticmethod def __classcall_private__(cls, maps=None, vertex_name=None): """ @@ -1415,8 +1406,7 @@ def __classcall_private__(cls, maps=None, vertex_name=None): True """ if maps: - return super().__classcall__(cls, maps=tuple(maps), - vertex_name=vertex_name) + return super().__classcall__(cls, maps=tuple(maps), vertex_name=vertex_name) return super().__classcall__(cls, vertex_name=vertex_name) def __init__(self, maps=None, vertex_name=None): @@ -1444,6 +1434,7 @@ def __init__(self, maps=None, vertex_name=None): # Import this here to prevent circular imports. from sage.topology.simplicial_set_morphism import SimplicialSetMorphism + if maps and any(not isinstance(f, SimplicialSetMorphism) for f in maps): raise ValueError('the maps must be morphisms of simplicial sets') if not maps: @@ -1460,22 +1451,19 @@ def __init__(self, maps=None, vertex_name=None): base_point = codomain.base_point() if vertex_name is not None: base_point.rename(vertex_name) - SimplicialSet_finite.__init__(self, codomain.face_data(), - base_point=base_point) + SimplicialSet_finite.__init__(self, codomain.face_data(), base_point=base_point) elif len(domain.nondegenerate_simplices()) == 1: # X is a point. base_point = f(domain().n_cells(0)[0]) if vertex_name is not None: base_point.rename(vertex_name) - SimplicialSet_finite.__init__(self, codomain.face_data(), - base_point=base_point) + SimplicialSet_finite.__init__(self, codomain.face_data(), base_point=base_point) elif len(codomain.nondegenerate_simplices()) == 1: # Y is a point. base_point = codomain.n_cells(0)[0] if vertex_name is not None: base_point.rename(vertex_name) - SimplicialSet_finite.__init__(self, codomain.face_data(), - base_point=base_point) + SimplicialSet_finite.__init__(self, codomain.face_data(), base_point=base_point) else: SimplicialSet_finite.__init__(self, codomain.face_data()) self._maps = (f,) @@ -1489,7 +1477,7 @@ def __init__(self, maps=None, vertex_name=None): # spaces: indexed list of spaces. Entries are of the form # (space, int) where int=-1 for the domain, and for the # codomains, int is the corresponding index. - spaces = [(Y, i-1) for i, Y in enumerate([domain] + codomains)] + spaces = [(Y, i - 1) for i, Y in enumerate([domain] + codomains)] # Dictionaries to translate from simplices in domain, # codomains to simplices in the pushout. The keys are of the # form (space, int). int=-1 for the domain, and for the @@ -1524,14 +1512,14 @@ def __init__(self, maps=None, vertex_name=None): if degenerate: # Identify the degeneracies involved. degens = [] - for (sigma, j) in s: + for sigma, j in s: if len(sigma.degeneracies()) > len(degens): degens = sigma.degeneracies() - space = spaces[j+1] + space = spaces[j + 1] old = _to_P[space][sigma.nondegenerate()] for sigma, j in s: # Now update the _to_P[space] dictionaries. - space = spaces[j+1] + space = spaces[j + 1] _to_P[space][sigma] = old.apply_degeneracies(*degens) else: # nondegenerate if len(s) == 1: @@ -1544,16 +1532,14 @@ def __init__(self, maps=None, vertex_name=None): name = str(sigma) latex_name = latex(sigma) break - new = AbstractSimplex(dim, name=name, - latex_name=latex_name) + new = AbstractSimplex(dim, name=name, latex_name=latex_name) if dim == 0: faces = None for sigma, j in s: - space = spaces[j+1] + space = spaces[j + 1] _to_P[space][sigma] = new if dim > 0: - faces = [_to_P[space][tau.nondegenerate()].apply_degeneracies(*tau.degeneracies()) - for tau in space[0].faces(sigma)] + faces = [_to_P[space][tau.nondegenerate()].apply_degeneracies(*tau.degeneracies()) for tau in space[0].faces(sigma)] simplices[new] = faces some_Y_is_pt = False @@ -1578,8 +1564,7 @@ def __init__(self, maps=None, vertex_name=None): elif all(f.is_pointed() for f in maps): pt = _to_P[(codomains[0], 0)][codomains[0].base_point()] if any(_to_P[(Y, i)][Y.base_point()] != pt for Y, i in spaces[2:]): - raise ValueError('something unexpected went wrong ' - 'with base points') + raise ValueError('something unexpected went wrong ' 'with base points') base_point = _to_P[(domain, -1)][domain.base_point()] if vertex_name is not None: base_point.rename(vertex_name) @@ -1588,8 +1573,7 @@ def __init__(self, maps=None, vertex_name=None): SimplicialSet_finite.__init__(self, simplices) # The relevant maps: self._maps = maps - self._structure = tuple([Y.Hom(self)(_to_P[(Y, i)]) - for Y, i in spaces[1:]]) + self._structure = tuple([Y.Hom(self)(_to_P[(Y, i)]) for Y, i in spaces[1:]]) self._vertex_name = vertex_name def structure_map(self, i): @@ -1674,7 +1658,7 @@ def universal_property(self, *maps): if any(g.codomain() != codomain for g in maps[1:]): raise ValueError('the maps do not all have the same codomain') composite = maps[0] * self._maps[0] - if any(g*f != composite for g, f in zip(maps[1:], self._maps[1:])): + if any(g * f != composite for g, f in zip(maps[1:], self._maps[1:])): raise ValueError('the maps are not compatible') data = {} for i, g in enumerate(maps): @@ -1722,9 +1706,7 @@ def __init__(self, inclusion, vertex_name='*'): --> [*, s_0 *, s_1 s_0 *, f * f * f, f * f * f * f, f * f * f * f * f] """ subcomplex = inclusion.domain() - PushoutOfSimplicialSets.__init__(self, [inclusion, - subcomplex.constant_map()], - vertex_name=vertex_name) + PushoutOfSimplicialSets.__init__(self, [inclusion, subcomplex.constant_map()], vertex_name=vertex_name) ambient = inclusion.codomain() if ambient.is_pointed() and ambient.is_finite(): @@ -1813,8 +1795,7 @@ def n_skeleton(self, n): ambient = SimplicialSet_finite.n_skeleton(self.ambient(), n) subcomplex = SimplicialSet_finite.n_skeleton(self.subcomplex(), n) subcomplex = ambient.subsimplicial_set(subcomplex.nondegenerate_simplices()) - return QuotientOfSimplicialSet_finite(subcomplex.inclusion_map(), - vertex_name=self._vertex_name) + return QuotientOfSimplicialSet_finite(subcomplex.inclusion_map(), vertex_name=self._vertex_name) start, skel = self._n_skeleton if start == n: return skel @@ -1822,8 +1803,7 @@ def n_skeleton(self, n): return skel.n_skeleton(n) ambient = self.ambient().n_skeleton(n) subcomplex = ambient.subsimplicial_set(self.subcomplex().nondegenerate_simplices(n)) - ans = QuotientOfSimplicialSet_finite(subcomplex.inclusion_map(), - vertex_name=self._vertex_name) + ans = QuotientOfSimplicialSet_finite(subcomplex.inclusion_map(), vertex_name=self._vertex_name) self._n_skeleton = (n, ans) return ans @@ -1855,14 +1835,14 @@ def _latex_(self): return '{} / {}'.format(latex(self.ambient()), latex(self.subcomplex())) -class QuotientOfSimplicialSet_finite(QuotientOfSimplicialSet, - PushoutOfSimplicialSets_finite): +class QuotientOfSimplicialSet_finite(QuotientOfSimplicialSet, PushoutOfSimplicialSets_finite): """ The quotient of finite simplicial sets. When the simplicial sets involved are finite, there is a :meth:`quotient_map` method available. """ + def __init__(self, inclusion, vertex_name='*'): r""" Return the quotient of a simplicial set by a subsimplicial set. @@ -1884,9 +1864,7 @@ def __init__(self, inclusion, vertex_name='*'): --> [*, s_0 *, s_1 s_0 *, f * f * f, f * f * f * f, f * f * f * f * f] """ subcomplex = inclusion.domain() - PushoutOfSimplicialSets_finite.__init__(self, [inclusion, - subcomplex.constant_map()], - vertex_name=vertex_name) + PushoutOfSimplicialSets_finite.__init__(self, [inclusion, subcomplex.constant_map()], vertex_name=vertex_name) ambient = inclusion.codomain() if ambient.is_pointed(): if ambient.base_point() not in subcomplex: @@ -1915,8 +1893,7 @@ def quotient_map(self): return self.structure_map(0) -class SmashProductOfSimplicialSets_finite(QuotientOfSimplicialSet_finite, - Factors): +class SmashProductOfSimplicialSets_finite(QuotientOfSimplicialSet_finite, Factors): @staticmethod def __classcall__(cls, factors=None): """ @@ -2057,11 +2034,9 @@ def __init__(self, factors=None): """ if any(not space.is_pointed() for space in factors): raise ValueError('the simplicial sets must be pointed') - PushoutOfSimplicialSets.__init__(self, [space.base_point_map() - for space in factors]) + PushoutOfSimplicialSets.__init__(self, [space.base_point_map() for space in factors]) if factors: - vertices = PushoutOfSimplicialSets_finite([space.n_skeleton(0).base_point_map() - for space in factors]) + vertices = PushoutOfSimplicialSets_finite([space.n_skeleton(0).base_point_map() for space in factors]) self._basepoint = vertices.base_point() self.base_point().rename('*') self._factors = factors @@ -2102,6 +2077,7 @@ class WedgeOfSimplicialSets_finite(WedgeOfSimplicialSets, PushoutOfSimplicialSet """ The wedge sum of finite pointed simplicial sets. """ + def __init__(self, factors=None): r""" Return the wedge sum of finite pointed simplicial sets. @@ -2129,8 +2105,7 @@ def __init__(self, factors=None): else: if any(not space.is_pointed() for space in factors): raise ValueError('the simplicial sets must be pointed') - PushoutOfSimplicialSets_finite.__init__(self, [space.base_point_map() - for space in factors]) + PushoutOfSimplicialSets_finite.__init__(self, [space.base_point_map() for space in factors]) self.base_point().rename('*') self._factors = factors @@ -2176,10 +2151,7 @@ def projection_map(self, i): Z """ m = len(self._factors) - simplices = ([self.inclusion_map(j).image().nondegenerate_simplices() - for j in range(i)] - + [self.inclusion_map(j).image().nondegenerate_simplices() - for j in range(i+1, m)]) + simplices = [self.inclusion_map(j).image().nondegenerate_simplices() for j in range(i)] + [self.inclusion_map(j).image().nondegenerate_simplices() for j in range(i + 1, m)] return self.quotient(list(itertools.chain(*simplices))).quotient_map() @@ -2232,8 +2204,7 @@ def __init__(self, factors=None): Defn: [Delta_{0,0}, Delta_{1,0}, Delta_{1,1}, Delta_{1,2}, Delta_{2,0}, Delta_{2,1}] --> [Delta_{0,0}, Delta_{1,0}, Delta_{1,1}, Delta_{1,2}, Delta_{2,0}, Delta_{2,1}] """ - PushoutOfSimplicialSets.__init__(self, [space._map_from_empty_set() - for space in factors]) + PushoutOfSimplicialSets.__init__(self, [space._map_from_empty_set() for space in factors]) self._factors = factors self._n_skeleton = (-1, Empty()) @@ -2263,15 +2234,13 @@ def n_skeleton(self, n): {0: Z, 1: Z x Z x C2, 2: Z, 3: Z} """ if self.is_finite(): - return DisjointUnionOfSimplicialSets_finite(tuple([X.n_skeleton(n) - for X in self._factors])) + return DisjointUnionOfSimplicialSets_finite(tuple([X.n_skeleton(n) for X in self._factors])) start, skel = self._n_skeleton if start == n: return skel if start > n: return skel.n_skeleton(n) - ans = DisjointUnionOfSimplicialSets_finite(tuple([X.n_skeleton(n) - for X in self._factors])) + ans = DisjointUnionOfSimplicialSets_finite(tuple([X.n_skeleton(n) for X in self._factors])) self._n_skeleton = (n, ans) return ans @@ -2308,11 +2277,11 @@ def _latex_(self): return ' \\amalg '.join(latex(X) for X in self._factors) -class DisjointUnionOfSimplicialSets_finite(DisjointUnionOfSimplicialSets, - PushoutOfSimplicialSets_finite): +class DisjointUnionOfSimplicialSets_finite(DisjointUnionOfSimplicialSets, PushoutOfSimplicialSets_finite): """ The disjoint union of finite simplicial sets. """ + def __init__(self, factors=None): r""" Return the disjoint union of finite simplicial sets. @@ -2339,8 +2308,7 @@ def __init__(self, factors=None): if not factors: PushoutOfSimplicialSets_finite.__init__(self) else: - PushoutOfSimplicialSets_finite.__init__(self, [space._map_from_empty_set() - for space in factors]) + PushoutOfSimplicialSets_finite.__init__(self, [space._map_from_empty_set() for space in factors]) self._factors = factors def inclusion_map(self, i): @@ -2494,18 +2462,15 @@ def __init__(self, base): # (sigma, *). new_simplices = {'cone': star} for sigma in base.nondegenerate_simplices(): - new = AbstractSimplex(sigma.dimension()+1, - name='({},*)'.format(sigma), - latex_name='({},*)'.format(latex(sigma))) + new = AbstractSimplex(sigma.dimension() + 1, name='({},*)'.format(sigma), latex_name='({},*)'.format(latex(sigma))) if sigma.dimension() == 0: data[sigma] = None data[new] = (star, sigma) else: sigma_faces = base.face_data()[sigma] data[sigma] = sigma_faces - new_faces = [new_simplices[face.nondegenerate()].apply_degeneracies(*face.degeneracies()) - for face in sigma_faces] - data[new] = (new_faces + [sigma]) + new_faces = [new_simplices[face.nondegenerate()].apply_degeneracies(*face.degeneracies()) for face in sigma_faces] + data[new] = new_faces + [sigma] new_simplices[sigma] = new SimplicialSet_finite.__init__(self, data, base_point=star) # self._base: original simplicial set. @@ -2651,8 +2616,7 @@ def _latex_(self): return 'C {}'.format(latex(self._base)) -class ReducedConeOfSimplicialSet_finite(ReducedConeOfSimplicialSet, - QuotientOfSimplicialSet_finite): +class ReducedConeOfSimplicialSet_finite(ReducedConeOfSimplicialSet, QuotientOfSimplicialSet_finite): def __init__(self, base): r""" Return the reduced cone on a simplicial set. @@ -2772,9 +2736,7 @@ def __init__(self, base): Cat = SimplicialSets() if base.is_finite(): Cat = Cat.Finite() - reduced = (base.is_pointed() - and (not hasattr(base, '_reduced') - or (hasattr(base, '_reduced') and base._reduced))) + reduced = base.is_pointed() and (not hasattr(base, '_reduced') or (hasattr(base, '_reduced') and base._reduced)) if reduced: Cat = Cat.Pointed() Parent.__init__(self, category=Cat) @@ -2842,7 +2804,7 @@ def __repr_or_latex__(self, output_type=None): sage: K.__repr_or_latex__('latex') '\\Sigma^{10}(S^{1} \\times S^{1})' """ - latex_output = (output_type == 'latex') + latex_output = output_type == 'latex' base = self._base if self._reduced: # Reduced suspension. @@ -2907,13 +2869,13 @@ def _latex_(self): return self.__repr_or_latex__('latex') -class SuspensionOfSimplicialSet_finite(SuspensionOfSimplicialSet, - QuotientOfSimplicialSet_finite): +class SuspensionOfSimplicialSet_finite(SuspensionOfSimplicialSet, QuotientOfSimplicialSet_finite): """ The (reduced) suspension of a finite simplicial set. See :class:`SuspensionOfSimplicialSet` for more information. """ + def __init__(self, base): r""" INPUT: @@ -2932,9 +2894,7 @@ def __init__(self, base): S^2(Simplicial set with 2 non-degenerate simplices) """ self._base = base - reduced = (base.is_pointed() - and (not hasattr(base, '_reduced') - or (hasattr(base, '_reduced') and base._reduced))) + reduced = base.is_pointed() and (not hasattr(base, '_reduced') or (hasattr(base, '_reduced') and base._reduced)) if reduced: C = ReducedConeOfSimplicialSet_finite(base) subcomplex = C.map_from_base().image() diff --git a/src/sage/topology/simplicial_set_examples.py b/src/sage/topology/simplicial_set_examples.py index c0534917ead..54f06def7ff 100644 --- a/src/sage/topology/simplicial_set_examples.py +++ b/src/sage/topology/simplicial_set_examples.py @@ -40,12 +40,12 @@ from sage.structure.parent import Parent from .delta_complex import delta_complexes -from .simplicial_set import AbstractSimplex, \ - SimplicialSet_arbitrary, SimplicialSet_finite +from .simplicial_set import AbstractSimplex, SimplicialSet_arbitrary, SimplicialSet_finite import sage.topology.simplicial_complex_catalog as simplicial_complexes from sage.misc.lazy_import import lazy_import + lazy_import('sage.categories.simplicial_sets', 'SimplicialSets') kenzo_path = Path(SAGE_ENV['SAGE_EXTCODE']) / 'kenzo' @@ -54,6 +54,7 @@ # ###################################################################### # The nerve of a finite monoid, used in sage.categories.finite_monoid. + class Nerve(SimplicialSet_arbitrary): def __init__(self, monoid): """ @@ -85,8 +86,7 @@ def __init__(self, monoid): self.rename("Nerve of {}".format(str(monoid))) self.rename_latex("B{}".format(latex(monoid))) - e = AbstractSimplex(0, name=str(monoid.one()), - latex_name=latex(monoid.one())) + e = AbstractSimplex(0, name=str(monoid.one()), latex_name=latex(monoid.one())) self._basepoint = e vertex = SimplicialSet_finite({e: None}, base_point=e) # self._n_skeleton: cache the highest dimensional skeleton @@ -117,9 +117,7 @@ def __eq__(self, other) -> bool: sage: BC3 == BC3 True """ - return (isinstance(other, Nerve) - and self._monoid == other._monoid - and self.base_point() == other.base_point()) + return isinstance(other, Nerve) and self._monoid == other._monoid and self.base_point() == other.base_point() def __ne__(self, other) -> bool: """ @@ -184,6 +182,7 @@ def n_skeleton(self, n): False """ from .simplicial_set_constructions import SubSimplicialSet + monoid = self._monoid one = monoid.one() # Build up chains of elements inductively, from dimension d-1 @@ -230,9 +229,7 @@ def n_skeleton(self, n): # bdries: the face maps applied to chain, in a # format suitable for passing to the DeltaComplex # constructor. - x = AbstractSimplex(d, - name=' * '.join(str(_) for _ in chain), - latex_name=' * '.join(latex(_) for _ in chain)) + x = AbstractSimplex(d, name=' * '.join(str(_) for _ in chain), latex_name=' * '.join(latex(_) for _ in chain)) new_faces[chain] = x # Compute faces of x. @@ -244,12 +241,10 @@ def n_skeleton(self, n): if d == 2: face = e.apply_degeneracies(i) else: - face = (face_dict[chain[:i] - + chain[i+2:]].apply_degeneracies(i)) + face = face_dict[chain[:i] + chain[i + 2 :]].apply_degeneracies(i) else: # Non-degenerate. - face = (face_dict[chain[:i] - + (product,) + chain[i+2:]]) + face = face_dict[chain[:i] + (product,) + chain[i + 2 :]] faces.append(face) faces.append(face_dict[chain[:-1]]) simplices[x] = faces @@ -264,6 +259,7 @@ def n_skeleton(self, n): ######################################################################## # Catalog of examples. These are accessed via simplicial_set_catalog.py. + def Sphere(n): r""" Return the `n`-sphere as a simplicial set. @@ -294,15 +290,11 @@ def Sphere(n): v_0 = AbstractSimplex(0, name='v_0') if n == 0: w_0 = AbstractSimplex(0, name='w_0') - return SimplicialSet_finite({v_0: None, w_0: None}, base_point=v_0, - name='S^0') + return SimplicialSet_finite({v_0: None, w_0: None}, base_point=v_0, name='S^0') degens = range(n - 2, -1, -1) degen_v = v_0.apply_degeneracies(*degens) - sigma = AbstractSimplex(n, name='sigma_{}'.format(n), - latex_name='\\sigma_{}'.format(n)) - return SimplicialSet_finite({sigma: [degen_v] * (n + 1)}, base_point=v_0, - name='S^{}'.format(n), - latex_name='S^{{{}}}'.format(n)) + sigma = AbstractSimplex(n, name='sigma_{}'.format(n), latex_name='\\sigma_{}'.format(n)) + return SimplicialSet_finite({sigma: [degen_v] * (n + 1)}, base_point=v_0, name='S^{}'.format(n), latex_name='S^{{{}}}'.format(n)) def ClassifyingSpace(group): @@ -398,8 +390,7 @@ def KleinBottle(): """ temp = SimplicialSet_finite(delta_complexes.KleinBottle()) pt = temp.n_cells(0)[0] - return SimplicialSet_finite(temp.face_data(), base_point=pt, - name='Klein bottle') + return SimplicialSet_finite(temp.face_data(), base_point=pt, name='Klein bottle') def Torus(): @@ -443,9 +434,7 @@ def Simplex(n): sage: K.n_cells(2) [(0, 1, 2)] """ - return SimplicialSet_finite(simplicial_complexes.Simplex(n), - name='{}-simplex'.format(n), - latex_name='\\Delta^{{{}}}'.format(n)) + return SimplicialSet_finite(simplicial_complexes.Simplex(n), name='{}-simplex'.format(n), latex_name='\\Delta^{{{}}}'.format(n)) @cached_function @@ -491,9 +480,7 @@ def Point(): True """ star = AbstractSimplex(0, name='*') - return SimplicialSet_finite({star: None}, base_point=star, - name='Point', - latex_name='*') + return SimplicialSet_finite({star: None}, base_point=star, name='Point', latex_name='*') def Horn(n, k): @@ -524,7 +511,7 @@ def Horn(n, k): """ K = Simplex(n) sigma = K.n_cells(n)[0] - L = K.subsimplicial_set(K.faces(sigma)[:k] + K.faces(sigma)[k+1:]) + L = K.subsimplicial_set(K.faces(sigma)[:k] + K.faces(sigma)[k + 1 :]) L.rename('({}, {})-Horn'.format(n, k)) L.rename_latex('\\Lambda^{{{}}}_{{{}}}'.format(n, k)) return L @@ -590,45 +577,18 @@ def ComplexProjectiveSpace(n): f4_101101 = AbstractSimplex(4, name='tau_0', latex_name='\\tau_0') f4_201110 = AbstractSimplex(4, name='tau_1', latex_name='\\tau_1') f4_211010 = AbstractSimplex(4, name='tau_2', latex_name='\\tau_2') - K = SimplicialSet_finite({f2_1: (v.apply_degeneracies(0), - v.apply_degeneracies(0), - v.apply_degeneracies(0)), - f2_2: (v.apply_degeneracies(0), - v.apply_degeneracies(0), - v.apply_degeneracies(0)), - f3_110: (f2_1, f2_2, f2_1, v.apply_degeneracies(1, 0)), - f3_011: (f2_1, f2_1, f2_1, f2_1), - f3_111: (v.apply_degeneracies(1, 0), f2_1, f2_2, f2_1), - f4_101101: (f2_1.apply_degeneracies(0), - f2_1.apply_degeneracies(0), - f3_011, - f2_1.apply_degeneracies(2), - f2_1.apply_degeneracies(2)), - f4_201110: (f2_1.apply_degeneracies(1), - f3_111, - f3_011, - f3_110, - f2_1.apply_degeneracies(1)), - f4_211010: (f2_1.apply_degeneracies(2), - f3_111, - f2_1.apply_degeneracies(1), - f3_110, - f2_1.apply_degeneracies(0))}, - base_point=v, name='CP^2', - latex_name='CP^{2}') + K = SimplicialSet_finite({f2_1: (v.apply_degeneracies(0), v.apply_degeneracies(0), v.apply_degeneracies(0)), f2_2: (v.apply_degeneracies(0), v.apply_degeneracies(0), v.apply_degeneracies(0)), f3_110: (f2_1, f2_2, f2_1, v.apply_degeneracies(1, 0)), f3_011: (f2_1, f2_1, f2_1, f2_1), f3_111: (v.apply_degeneracies(1, 0), f2_1, f2_2, f2_1), f4_101101: (f2_1.apply_degeneracies(0), f2_1.apply_degeneracies(0), f3_011, f2_1.apply_degeneracies(2), f2_1.apply_degeneracies(2)), f4_201110: (f2_1.apply_degeneracies(1), f3_111, f3_011, f3_110, f2_1.apply_degeneracies(1)), f4_211010: (f2_1.apply_degeneracies(2), f3_111, f2_1.apply_degeneracies(1), f3_110, f2_1.apply_degeneracies(0))}, base_point=v, name='CP^2', latex_name='CP^{2}') return K if n == 3: file = kenzo_path / 'CP3.txt' data = simplicial_data_from_kenzo_output(file) v = [sigma for sigma in data if sigma.dimension() == 0][0] - return SimplicialSet_finite(data, base_point=v, name='CP^3', - latex_name='CP^{3}') + return SimplicialSet_finite(data, base_point=v, name='CP^3', latex_name='CP^{3}') if n == 4: file = kenzo_path / 'CP4.txt' data = simplicial_data_from_kenzo_output(file) v = [sigma for sigma in data if sigma.dimension() == 0][0] - return SimplicialSet_finite(data, base_point=v, name='CP^4', - latex_name='CP^{4}') + return SimplicialSet_finite(data, base_point=v, name='CP^4', latex_name='CP^{4}') def simplicial_data_from_kenzo_output(filename) -> dict: @@ -674,7 +634,7 @@ def simplicial_data_from_kenzo_output(filename) -> dict: else: end = new_dim_idx if dim == 0: - simplex_string = data[data.find('Vertices :') + len('Vertices :'):end] + simplex_string = data[data.find('Vertices :') + len('Vertices :') : end] vertices = OneOrMore(nested_expr()).parse_string(simplex_string).asList()[0] for v in vertices: vertex = AbstractSimplex(0, name=v) @@ -700,12 +660,11 @@ def simplicial_data_from_kenzo_output(filename) -> dict: if degen_str == '-': degens = [] else: - degens = [Integer(_) - for _ in degen_str.split('-')] + degens = [Integer(_) for _ in degen_str.split('-')] else: degens = [Integer(degen_str)] - face_name = f[m.end(0):].strip()[:-1] + face_name = f[m.end(0) :].strip()[:-1] nondegen = simplex_names[face_name] faces.append(nondegen.apply_degeneracies(*degens)) @@ -779,29 +738,8 @@ def HopfMap(): alpha_4 = AbstractSimplex(3, name='alpha_4', latex_name='\\alpha_4') alpha_5 = AbstractSimplex(3, name='alpha_5', latex_name='\\alpha_5') alpha_6 = AbstractSimplex(3, name='alpha_6', latex_name='\\alpha_6') - S3 = SimplicialSet_finite({beta_11: (w_0, w_0), beta_22: (w_0, w_0), - beta_23: (w_0, w_0), beta_44: (w_0, w_0), - beta_1: (w_1, beta_11, w_1), - beta_2: (w_1, beta_22, beta_23), - beta_3: (w_1, beta_23, w_1), - beta_4: (w_1, beta_44, w_1), - alpha_12: (beta_11, beta_23, w_1), - alpha_23: (beta_11, beta_22, w_1), - alpha_34: (beta_11, beta_22, beta_44), - alpha_45: (w_1, beta_23, beta_44), - alpha_56: (w_1, beta_23, w_1), - alpha_1: (beta_1, beta_3, alpha_12, w_2), - alpha_2: (beta_11.apply_degeneracies(1), beta_2, - alpha_23, alpha_12), - alpha_3: (beta_11.apply_degeneracies(0), alpha_34, - alpha_23, beta_4), - alpha_4: (beta_1, beta_2, alpha_34, alpha_45), - alpha_5: (w_2, alpha_45, alpha_56, beta_4), - alpha_6: (w_2, beta_3, alpha_56, w_2)}, - base_point=w_0) - return S3.Hom(S2)({alpha_1: s0_sigma, alpha_2: s1_sigma, - alpha_3: s2_sigma, alpha_4: s0_sigma, - alpha_5: s2_sigma, alpha_6: s1_sigma}) + S3 = SimplicialSet_finite({beta_11: (w_0, w_0), beta_22: (w_0, w_0), beta_23: (w_0, w_0), beta_44: (w_0, w_0), beta_1: (w_1, beta_11, w_1), beta_2: (w_1, beta_22, beta_23), beta_3: (w_1, beta_23, w_1), beta_4: (w_1, beta_44, w_1), alpha_12: (beta_11, beta_23, w_1), alpha_23: (beta_11, beta_22, w_1), alpha_34: (beta_11, beta_22, beta_44), alpha_45: (w_1, beta_23, beta_44), alpha_56: (w_1, beta_23, w_1), alpha_1: (beta_1, beta_3, alpha_12, w_2), alpha_2: (beta_11.apply_degeneracies(1), beta_2, alpha_23, alpha_12), alpha_3: (beta_11.apply_degeneracies(0), alpha_34, alpha_23, beta_4), alpha_4: (beta_1, beta_2, alpha_34, alpha_45), alpha_5: (w_2, alpha_45, alpha_56, beta_4), alpha_6: (w_2, beta_3, alpha_56, w_2)}, base_point=w_0) + return S3.Hom(S2)({alpha_1: s0_sigma, alpha_2: s1_sigma, alpha_3: s2_sigma, alpha_4: s0_sigma, alpha_5: s2_sigma, alpha_6: s1_sigma}) def PresentationComplex(G): @@ -858,7 +796,7 @@ def PresentationComplex(G): all_edges = {} all_edges.update(edges) all_edges.update(inverseedges) - triangles = {i + 1 : AbstractSimplex(2, name='T' + str(g)) for (i, g) in enumerate(G.gens())} + triangles = {i + 1: AbstractSimplex(2, name='T' + str(g)) for (i, g) in enumerate(G.gens())} face_maps = {O: None} face_maps.update({g: [O, O] for g in all_edges.values()}) face_maps.update({triangles[t]: [all_edges[t], SO, all_edges[-t]] for t in triangles}) diff --git a/src/sage/topology/simplicial_set_morphism.py b/src/sage/topology/simplicial_set_morphism.py index 5befe2b469c..1eee45c0598 100644 --- a/src/sage/topology/simplicial_set_morphism.py +++ b/src/sage/topology/simplicial_set_morphism.py @@ -77,6 +77,7 @@ class SimplicialSetHomset(Homset): To: Simplicial set with 2 non-degenerate simplices Defn: [v, w, e, f] --> [v, v, e, e] """ + def __call__(self, f, check=True): r""" INPUT: @@ -120,7 +121,7 @@ def diagonal_morphism(self): if len(factors) != 2 or factors[0] != domain or factors[1] != domain: raise ValueError('diagonal morphism is only defined for Hom(X, XxX)') f = {} - for i in range(domain.dimension()+1): + for i in range(domain.dimension() + 1): for s in domain.n_cells(i): f[s] = dict(codomain._translation)[((s, ()), (s, ()))] return self(f) @@ -141,9 +142,7 @@ def identity(self): ... TypeError: identity map is only defined for endomorphism sets """ - return SimplicialSetMorphism(domain=self.domain(), - codomain=self.codomain(), - identity=True) + return SimplicialSetMorphism(domain=self.domain(), codomain=self.codomain(), identity=True) def constant_map(self, point=None): r""" @@ -202,11 +201,8 @@ def constant_map(self, point=None): if codomain.is_pointed(): point = codomain.base_point() else: - raise ValueError('codomain is not pointed, so specify a ' - 'target for the constant map') - return SimplicialSetMorphism(domain=self.domain(), - codomain=self.codomain(), - constant=point) + raise ValueError('codomain is not pointed, so specify a ' 'target for the constant map') + return SimplicialSetMorphism(domain=self.domain(), codomain=self.codomain(), constant=point) def an_element(self): """ @@ -282,8 +278,7 @@ def __iter__(self): ] """ if not self.domain().is_finite(): - raise NotImplementedError('domain must be finite to iterate ' - 'through all morphisms') + raise NotImplementedError('domain must be finite to iterate ' 'through all morphisms') codomain = self.codomain() facets = self.domain()._facets_() dims = [f.dimension() for f in facets] @@ -313,8 +308,7 @@ def _latex_(self): class SimplicialSetMorphism(Morphism): - def __init__(self, data=None, domain=None, codomain=None, - constant=None, identity=False, check=True): + def __init__(self, data=None, domain=None, codomain=None, constant=None, identity=False, check=True): r""" Return a morphism of simplicial sets. @@ -464,8 +458,7 @@ def __init__(self, data=None, domain=None, codomain=None, self._constant = constant Morphism.__init__(self, Hom(domain, codomain, SimplicialSets())) return - raise NotImplementedError('morphisms with infinite domain ' - 'are not implemented in general') + raise NotImplementedError('morphisms with infinite domain ' 'are not implemented in general') else: if identity: self._is_identity = True @@ -479,16 +472,12 @@ def __init__(self, data=None, domain=None, codomain=None, if constant is not None: self._constant = constant check = False - data = {sigma: constant.apply_degeneracies(*range(sigma.dimension()-1, -1, -1)) - for sigma in domain.nondegenerate_simplices()} + data = {sigma: constant.apply_degeneracies(*range(sigma.dimension() - 1, -1, -1)) for sigma in domain.nondegenerate_simplices()} - if (not isinstance(domain, SimplicialSet_arbitrary) - or not isinstance(codomain, SimplicialSet_arbitrary)): + if not isinstance(domain, SimplicialSet_arbitrary) or not isinstance(codomain, SimplicialSet_arbitrary): raise TypeError('the domain and codomain must be simplicial sets') - if any(x.nondegenerate() not in - domain.nondegenerate_simplices() for x in data.keys()): - raise ValueError('at least one simplex in the defining ' - 'dictionary is not in the domain') + if any(x.nondegenerate() not in domain.nondegenerate_simplices() for x in data.keys()): + raise ValueError('at least one simplex in the defining ' 'dictionary is not in the domain') # Remove degenerate simplices from the domain specification. d = {sigma: data[sigma] for sigma in data if sigma.is_nondegenerate()} # For each simplex in d.keys(), add its faces, and the faces @@ -497,7 +486,7 @@ def __init__(self, data=None, domain=None, codomain=None, faces = domain.faces(simplex) add = [] if faces: - for (i, sigma) in enumerate(faces): + for i, sigma in enumerate(faces): nondegen = sigma.nondegenerate() if nondegen not in d: add.append((sigma, i, simplex)) @@ -525,7 +514,7 @@ def __init__(self, data=None, domain=None, codomain=None, # when applying f to it. We can skip vertices and start # with 1-simplices. bad = False - for i in range(simplex.dimension()+1): + for i in range(simplex.dimension() + 1): face_f = codomain.face(d[simplex], i) face = domain.face(simplex, i) if face is None: @@ -541,8 +530,7 @@ def __init__(self, data=None, domain=None, codomain=None, if bad: raise ValueError('the dictionary does not define a map of simplicial sets') if any(x not in d.keys() for x in domain.nondegenerate_simplices()): - raise ValueError('the image of at least one simplex in ' - 'the domain is not defined') + raise ValueError('the image of at least one simplex in ' 'the domain is not defined') self._dictionary = d Morphism.__init__(self, Hom(domain, codomain, SimplicialSets())) @@ -574,9 +562,7 @@ def __eq__(self, other): True """ if self.domain().is_finite() and other.domain().is_finite(): - return (self.domain() == other.domain() - and self.codomain() == other.codomain() - and self._dictionary == other._dictionary) + return self.domain() == other.domain() and self.codomain() == other.codomain() and self._dictionary == other._dictionary return False def __ne__(self, other): @@ -631,7 +617,7 @@ def __call__(self, x): raise ValueError('element is not a simplex in the domain') if self.is_constant(): target = self._constant - return target.apply_degeneracies(*range(x.dimension()-1, -1, -1)) + return target.apply_degeneracies(*range(x.dimension() - 1, -1, -1)) if self._is_identity: return x return self._dictionary[x.nondegenerate()].apply_degeneracies(*x.degeneracies()) @@ -764,10 +750,7 @@ def is_identity(self): sage: Hom(B,B).constant_map().is_identity() False """ - ans = (self._is_identity or - (self.domain() == self.codomain() - and self.domain().is_finite() - and all(a == b for a, b in self._dictionary.items()))) + ans = self._is_identity or (self.domain() == self.codomain() and self.domain().is_finite() and all(a == b for a, b in self._dictionary.items())) self._is_identity = ans return ans @@ -818,8 +801,7 @@ def is_injective(self): domain = self.domain() for n in range(domain.dimension() + 1): domain_cells = domain.n_cells(n) - output = {self(sigma) for sigma in domain_cells - if self(sigma).is_nondegenerate()} + output = {self(sigma) for sigma in domain_cells if self(sigma).is_nondegenerate()} if len(domain_cells) > len(output): return False return True @@ -868,8 +850,7 @@ def is_pointed(self): sage: t.is_pointed() False """ - return (self.domain().is_pointed() and self.codomain().is_pointed() - and self(self.domain().base_point()) == self.codomain().base_point()) + return self.domain().is_pointed() and self.codomain().is_pointed() and self(self.domain().base_point()) == self.codomain().base_point() def is_constant(self): """ @@ -1295,8 +1276,7 @@ def n_skeleton(self, n, domain=None, codomain=None): new = {d: old[d] for d in old if d.dimension() <= n} return Hom(domain, codomain)(new) - def associated_chain_complex_morphism(self, base_ring=ZZ, - augmented=False, cochain=False): + def associated_chain_complex_morphism(self, base_ring=ZZ, augmented=False, cochain=False): """ Return the associated chain complex morphism of ``self``. @@ -1333,7 +1313,7 @@ def associated_chain_complex_morphism(self, base_ring=ZZ, matrices[-1] = m else: matrices[-1] = m.transpose() - for dim in range(min_dim+1): + for dim in range(min_dim + 1): X_faces = list(self.domain().n_cells(dim)) Y_faces = list(self.codomain().n_cells(dim)) num_faces_X = len(X_faces) @@ -1348,7 +1328,7 @@ def associated_chain_complex_morphism(self, base_ring=ZZ, matrices[dim] = m else: matrices[dim] = m.transpose() - for dim in range(min_dim+1, max_dim+1): + for dim in range(min_dim + 1, max_dim + 1): try: l1 = len(self.codomain().n_cells(dim)) except KeyError: @@ -1363,12 +1343,8 @@ def associated_chain_complex_morphism(self, base_ring=ZZ, else: matrices[dim] = m.transpose() if not cochain: - return ChainComplexMorphism(matrices, - self.domain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=False), - self.codomain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=False)) - return ChainComplexMorphism(matrices, - self.codomain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=True), - self.domain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=True)) + return ChainComplexMorphism(matrices, self.domain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=False), self.codomain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=False)) + return ChainComplexMorphism(matrices, self.codomain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=True), self.domain().chain_complex(base_ring=base_ring, augmented=augmented, cochain=True)) def induced_homology_morphism(self, base_ring=None, cohomology=False): """ diff --git a/src/sage/typeset/ascii_art.py b/src/sage/typeset/ascii_art.py index 265a82bad81..f7796a70676 100644 --- a/src/sage/typeset/ascii_art.py +++ b/src/sage/typeset/ascii_art.py @@ -138,6 +138,7 @@ .7????$. ... . """ + # ****************************************************************************** # Copyright (C) 2013 Jean-Baptiste Priez , # @@ -183,7 +184,9 @@ class AsciiArt(CharacterArt): _ascii_art_factory = CharacterArtFactory( - AsciiArt, str, '_ascii_art_', + AsciiArt, + str, + '_ascii_art_', (symbol.ascii_left_parenthesis, symbol.ascii_right_parenthesis), (symbol.ascii_left_square_bracket, symbol.ascii_right_square_bracket), (symbol.ascii_left_curly_brace, symbol.ascii_right_curly_brace), @@ -287,7 +290,7 @@ def ascii_art(*obj, **kwds): separator = _ascii_art_factory.build(separator, baseline=sep_baseline) elif sep_baseline is not None: from copy import copy + separator = copy(separator) separator._baseline = sep_baseline - return _ascii_art_factory.concatenate(obj, separator, empty_ascii_art, - baseline=baseline) + return _ascii_art_factory.concatenate(obj, separator, empty_ascii_art, baseline=baseline) diff --git a/src/sage/typeset/character_art.py b/src/sage/typeset/character_art.py index 2ac612125c1..0e5db41c08e 100644 --- a/src/sage/typeset/character_art.py +++ b/src/sage/typeset/character_art.py @@ -217,6 +217,7 @@ def _isatty(self) -> bool: False """ from sage.doctest import DOCTEST_MODE + if DOCTEST_MODE: return False try: @@ -240,8 +241,8 @@ def _terminal_width(self): import fcntl import termios import struct - rc = fcntl.ioctl(0, termios.TIOCGWINSZ, - struct.pack('HHHH', sys.stdout.fileno(), 0, 0, 0)) + + rc = fcntl.ioctl(0, termios.TIOCGWINSZ, struct.pack('HHHH', sys.stdout.fileno(), 0, 0, 0)) h, w, hp, wp = struct.unpack('HHHH', rc) return w @@ -264,6 +265,7 @@ def _splitting_points(self, size, offset=0): sage: list(ascii_art(*(['a'] * 90))._splitting_points(20, offset=5)) [15, 35, 55, 75, 90] """ + # We implement a custom iterator instead of repeatedly using # itertools.chain to prepend elements in order to avoid quadratic time # complexity @@ -271,6 +273,7 @@ class PrependIterator: """ Iterator with support for prepending of elements. """ + def __init__(self, stack): self._stack = [iter(elems) for elems in stack] @@ -304,8 +307,7 @@ def __next__(self): except StopIteration: bp_next = None if bp_next is None or isinstance(bp_next, tuple): - raise ValueError("nested structure must be followed by a " - "regular breakpoint") + raise ValueError("nested structure must be followed by a " "regular breakpoint") if bp_next - idx > size: # substructure is too wide for the current line, so force a # line break @@ -313,8 +315,7 @@ def __next__(self): yield bp idx = bp breakpoints.prepend([bp_next]) - breakpoints.prepend(_shifted_breakpoints(sub_breakpoints, - sub_offset)) + breakpoints.prepend(_shifted_breakpoints(sub_breakpoints, sub_offset)) # at this point, we do not know the next breakpoint yet, # but have already yielded bp, so discard it bp = None @@ -357,8 +358,8 @@ def _split_repr_(self, size) -> str: for bp in self._splitting_points(size): if bp - idx > size: import warnings - warnings.warn("the console size is smaller than the pretty " - "representation of the object") + + warnings.warn("the console size is smaller than the pretty " "representation of the object") # Note that this is faster than calling self.split() repeatedly parts.append('\n'.join(line[idx:bp] for line in self)) idx = bp @@ -512,13 +513,7 @@ def _compute_new_h(obj1, obj2): | | """ - return max( - obj1.get_baseline(), - obj2.get_baseline() - ) + max( - obj1._h - obj1.get_baseline(), - obj2._h - obj2.get_baseline() - ) + return max(obj1.get_baseline(), obj2.get_baseline()) + max(obj1._h - obj1.get_baseline(), obj2._h - obj2.get_baseline()) def width(self): r""" @@ -651,8 +646,7 @@ def __add__(self, Nelt): if self._baseline is not None and Nelt._baseline is not None: # left treatment - new_matrix.extend(line + " " * (self._l - len(line)) - for line in self._matrix) + new_matrix.extend(line + " " * (self._l - len(line)) for line in self._matrix) if new_h > self._h: # | new_h > self._h @@ -662,8 +656,7 @@ def __add__(self, Nelt): # | } if new_baseline > self._baseline: l_space = " " * self._l - new_matrix.extend(l_space - for k in range(new_baseline - self._baseline)) + new_matrix.extend(l_space for k in range(new_baseline - self._baseline)) # | } new_h > self._h # | } new_h - new_baseline > self._h - self._baseline # ||<-- baseline number of white lines at the top @@ -689,8 +682,7 @@ def __add__(self, Nelt): for j in range(Nelt._h): new_matrix[i + j] += Nelt._matrix[j] else: - new_matrix.extend(line + " " * (self._l - len(line)) - for line in self._matrix) + new_matrix.extend(line + " " * (self._l - len(line)) for line in self._matrix) for i, line_i in enumerate(Nelt._matrix): if i == len(new_matrix): new_matrix.append(" " * self._l + line_i) @@ -701,8 +693,7 @@ def __add__(self, Nelt): new_breakpoints = list(self._breakpoints) if self._l and Nelt._l: new_breakpoints.append(self._l) - new_breakpoints.extend(_shifted_breakpoints(Nelt._breakpoints, - self._l)) + new_breakpoints.extend(_shifted_breakpoints(Nelt._breakpoints, self._l)) return self.__class__( lines=new_matrix, breakpoints=new_breakpoints, diff --git a/src/sage/typeset/character_art_factory.py b/src/sage/typeset/character_art_factory.py index 1daacfeff8c..137189b068f 100644 --- a/src/sage/typeset/character_art_factory.py +++ b/src/sage/typeset/character_art_factory.py @@ -1,6 +1,7 @@ r""" Factory for Character-Based Art """ + # ****************************************************************************** # Copyright (C) 2013 Jean-Baptiste Priez , # @@ -21,9 +22,7 @@ class CharacterArtFactory(SageObject): - def __init__(self, - art_type, string_type, magic_method_name, - parenthesis, square_bracet, curly_brace): + def __init__(self, art_type, string_type, magic_method_name, parenthesis, square_bracet, curly_brace): r""" Abstract base class for character art factory. @@ -110,6 +109,7 @@ def build(self, obj, baseline=None): if isinstance(obj, self.art_type): if baseline is not None: from copy import copy + obj = copy(obj) obj._baseline = baseline return obj @@ -261,6 +261,7 @@ def build_container(self, content, left_border, right_border, baseline=0): lines.append(left + pad + line.ljust(w) + pad + right) shift = len(left_border) + len(pad) from .character_art import _shifted_breakpoints + basepoints = list(_shifted_breakpoints(content._breakpoints, shift)) return self.art_type(lines, basepoints, baseline=baseline) @@ -290,9 +291,7 @@ def build_set(self, s, baseline=0): """ comma = self.art_type([', '], baseline=0) repr_elems = self.concatenate(s, comma, nested=True) - return self.build_container( - repr_elems, self.left_curly_brace, self.right_curly_brace, - baseline) + return self.build_container(repr_elems, self.left_curly_brace, self.right_curly_brace, baseline) def build_dict(self, d, baseline=0): r""" @@ -316,9 +315,7 @@ def build_dict(self, d, baseline=0): sage: ascii_art({'a': '', '': ''}) { a:, : } """ - comma = self.art_type([', '], - baseline=0, - breakpoints=[1]) + comma = self.art_type([', '], baseline=0, breakpoints=[1]) colon = self.art_type([':'], baseline=0) def concat_no_breakpoint(k, v): @@ -330,12 +327,9 @@ def concat_no_breakpoint(k, v): if v._l: elt._breakpoints.remove(k._l + 1) return elt - repr_elems = self.concatenate( - (concat_no_breakpoint(k, v) for k, v in d.items()), - comma, nested=True) - return self.build_container( - repr_elems, self.left_curly_brace, self.right_curly_brace, - baseline) + + repr_elems = self.concatenate((concat_no_breakpoint(k, v) for k, v in d.items()), comma, nested=True) + return self.build_container(repr_elems, self.left_curly_brace, self.right_curly_brace, baseline) def build_list(self, l, baseline=0): r""" @@ -371,13 +365,9 @@ def build_list(self, l, baseline=0): 22, 23, 24, 25 ], [ 1, 2, 3, 4, 5 ],\n\n [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ] ]' """ - comma = self.art_type([', '], - baseline=0, - breakpoints=[1]) + comma = self.art_type([', '], baseline=0, breakpoints=[1]) repr_elems = self.concatenate(l, comma, nested=True) - return self.build_container( - repr_elems, self.left_square_bracket, self.right_square_bracket, - baseline) + return self.build_container(repr_elems, self.left_square_bracket, self.right_square_bracket, baseline) def build_tuple(self, t, baseline=0): r""" @@ -390,16 +380,11 @@ def build_tuple(self, t, baseline=0): ( /\ /\ /\/\ / \ ) ( /\/\/\, /\/ \, / \/\, / \, / \ ) """ - comma = self.art_type([', '], - baseline=0, - breakpoints=[1]) + comma = self.art_type([', '], baseline=0, breakpoints=[1]) repr_elems = self.concatenate(t, comma, nested=True) - return self.build_container( - repr_elems, self.left_parenthesis, self.right_parenthesis, - baseline) + return self.build_container(repr_elems, self.left_parenthesis, self.right_parenthesis, baseline) - def concatenate(self, iterable, separator, empty=None, baseline=0, - nested=False): + def concatenate(self, iterable, separator, empty=None, baseline=0, nested=False): r""" Concatenate multiple character art instances. @@ -476,18 +461,16 @@ def padded_line(obj, i): return line + ' ' * (obj._l - len(line)) # Note that this scales linearly with the length of the string - new_matrix = [padded_line(separator, i).join( - padded_line(obj, i) for obj in iterable) - for i in range(top - 1, -bot - 1, -1)] + new_matrix = [padded_line(separator, i).join(padded_line(obj, i) for obj in iterable) for i in range(top - 1, -bot - 1, -1)] from .character_art import _shifted_breakpoints + breakpoints = [] bk_sep = separator._breakpoints if not bk_sep: bk_sep = [separator._l] if nested and isinstance(bk_sep[0], tuple): - raise ValueError("nested structure must be followed by a " - "regular breakpoint") + raise ValueError("nested structure must be followed by a " "regular breakpoint") idx = None for obj in iterable: if idx is None: @@ -499,13 +482,10 @@ def padded_line(obj, i): if nested: breakpoints.append((idx, obj._breakpoints)) else: - breakpoints.extend(_shifted_breakpoints(obj._breakpoints, - idx)) + breakpoints.extend(_shifted_breakpoints(obj._breakpoints, idx)) idx += obj._l baseline = bot if baseline is None else bot + baseline - return self.art_type(new_matrix, - breakpoints=breakpoints, - baseline=baseline) + return self.art_type(new_matrix, breakpoints=breakpoints, baseline=baseline) def parse_keywords(self, kwds): """ diff --git a/src/sage/typeset/symbols.py b/src/sage/typeset/symbols.py index d3d1e91b58e..4225be430e5 100644 --- a/src/sage/typeset/symbols.py +++ b/src/sage/typeset/symbols.py @@ -51,16 +51,14 @@ ⎛ ⎞ ⎜ ⎟ ⎜ ⎟ ⎡ ⎤ ⎢ ⎥ ⎢ ⎥ ⎰ ⎱ ⎨ ⎬ ⎫ ⎧ ( ) ⎝ ⎠ ⎝ ⎠ ⎝ ⎠ [ ] ⎣ ⎦ ⎣ ⎦ ⎣ ⎦ { } ⎱ ⎰ ⎩ ⎭ ⎩ ⎭ """ + import unicodedata from sage.structure.sage_object import SageObject class CompoundSymbol(SageObject): - def __init__(self, character, top, extension, bottom, - middle=None, - middle_top=None, middle_bottom=None, - top_2=None, bottom_2=None): + def __init__(self, character, top, extension, bottom, middle=None, middle_top=None, middle_bottom=None, top_2=None, bottom_2=None): """ A multi-character (ascii/unicode art) symbol. @@ -203,6 +201,7 @@ def character_art(self, num_lines): { """ from sage.typeset.ascii_art import AsciiArt + return AsciiArt(self(num_lines)) @@ -221,6 +220,7 @@ def character_art(self, num_lines): ⎩ """ from sage.typeset.unicode_art import UnicodeArt + return UnicodeArt(self(num_lines)) diff --git a/src/sage/typeset/unicode_art.py b/src/sage/typeset/unicode_art.py index 67804239854..28c8ec0b0e3 100644 --- a/src/sage/typeset/unicode_art.py +++ b/src/sage/typeset/unicode_art.py @@ -51,7 +51,9 @@ class UnicodeArt(CharacterArt): _unicode_art_factory = CharacterArtFactory( - UnicodeArt, str, '_unicode_art_', + UnicodeArt, + str, + '_unicode_art_', (symbol.unicode_left_parenthesis, symbol.unicode_right_parenthesis), (symbol.unicode_left_square_bracket, symbol.unicode_right_square_bracket), (symbol.unicode_left_curly_brace, symbol.unicode_right_curly_brace), @@ -135,20 +137,16 @@ def unicode_art(*obj, **kwds): separator = _unicode_art_factory.build(separator, baseline=sep_baseline) elif sep_baseline is not None: from copy import copy + separator = copy(separator) separator._baseline = sep_baseline - return _unicode_art_factory.concatenate(obj, separator, empty_unicode_art, - baseline=baseline) + return _unicode_art_factory.concatenate(obj, separator, empty_unicode_art, baseline=baseline) -_subscript_dict = {'0': '₀', '1': '₁', '2': '₂', '3': '₃', '4': '₄', - '5': '₅', '6': '₆', '7': '₇', '8': '₈', '9': '₉', - '-': '₋', '+': '₊'} +_subscript_dict = {'0': '₀', '1': '₁', '2': '₂', '3': '₃', '4': '₄', '5': '₅', '6': '₆', '7': '₇', '8': '₈', '9': '₉', '-': '₋', '+': '₊'} -_superscript_dict = {'0': '⁰', '1': '¹', '2': '²', '3': '³', '4': '⁴', - '5': '⁵', '6': '⁶', '7': '⁷', '8': '⁸', '9': '⁹', - '-': '⁻', '+': '⁺', '/': 'ᐟ'} +_superscript_dict = {'0': '⁰', '1': '¹', '2': '²', '3': '³', '4': '⁴', '5': '⁵', '6': '⁶', '7': '⁷', '8': '⁸', '9': '⁹', '-': '⁻', '+': '⁺', '/': 'ᐟ'} def unicode_superscript(x): diff --git a/src/sage/typeset/unicode_characters.py b/src/sage/typeset/unicode_characters.py index 67ccbff2549..c2662b8cab1 100644 --- a/src/sage/typeset/unicode_characters.py +++ b/src/sage/typeset/unicode_characters.py @@ -77,24 +77,24 @@ # Operators: -unicode_otimes = '\u2297' # '⊗' +unicode_otimes = '\u2297' # '⊗' -unicode_bigotimes = '\u2A02' # '⨂' +unicode_bigotimes = '\u2A02' # '⨂' -unicode_wedge = '\u2227' # '∧' +unicode_wedge = '\u2227' # '∧' -unicode_bigwedge = '\u22C0' # '⋀' +unicode_bigwedge = '\u22C0' # '⋀' -unicode_partial = '\u2202' # '∂' +unicode_partial = '\u2202' # '∂' # Arrows: -unicode_to = '\u2192' # '→' +unicode_to = '\u2192' # '→' -unicode_mapsto = '\u21A6' # '↦' +unicode_mapsto = '\u21A6' # '↦' # Letters: -unicode_mathbbR = '\u211D' # 'ℝ' +unicode_mathbbR = '\u211D' # 'ℝ' -unicode_mathbbC = '\u2102' # 'ℂ' +unicode_mathbbC = '\u2102' # 'ℂ' From 90e8bfd2fa80eff29eb9ad8a4c4ecf0a85ce8ac6 Mon Sep 17 00:00:00 2001 From: Vincent Macri Date: Mon, 20 Apr 2026 16:50:37 -0600 Subject: [PATCH 2/3] black line length 320 --- src/sage/algebras/fusion_rings/fusion_ring.py | 14 +- .../lie_algebras/classical_lie_algebra.py | 33 +- src/sage/algebras/lie_algebras/onsager.py | 20 +- .../n2_lie_conformal_algebra.py | 11 +- .../quantum_groups/ace_quantum_onsager.py | 36 +- src/sage/calculus/desolvers.py | 4 +- src/sage/categories/category_with_axiom.py | 49 +- src/sage/categories/crystals.py | 17 +- src/sage/categories/pushout.py | 4 +- src/sage/coding/bounds_catalog.py | 23 +- src/sage/coding/golay_code.py | 53 +- src/sage/coding/guruswami_sudan/gs_decoder.py | 10 +- src/sage/coding/self_dual_codes.py | 181 ++- src/sage/coding/two_weight_db.py | 107 +- src/sage/combinat/all.py | 21 +- src/sage/combinat/crystals/alcove_path.py | 92 +- .../crystals/highest_weight_crystals.py | 19 +- src/sage/combinat/crystals/tensor_product.py | 4 +- src/sage/combinat/designs/database.py | 684 ++++++++- .../combinat/designs/difference_family.py | 57 +- .../combinat/designs/incidence_structures.py | 9 +- src/sage/combinat/finite_state_machine.py | 17 +- src/sage/combinat/matrices/hadamard_matrix.py | 71 +- src/sage/combinat/partition.py | 16 +- src/sage/combinat/permutation.py | 21 +- src/sage/combinat/regular_sequence.py | 4 +- .../combinat/root_system/branching_rules.py | 280 +++- src/sage/combinat/root_system/cartan_type.py | 8 +- src/sage/combinat/root_system/type_E.py | 55 +- src/sage/combinat/root_system/type_F.py | 4 +- src/sage/combinat/root_system/weyl_group.py | 11 +- src/sage/combinat/skew_partition.py | 16 +- src/sage/combinat/superpartition.py | 7 +- src/sage/combinat/t_sequences.py | 14 +- src/sage/combinat/tableau.py | 8 +- src/sage/combinat/words/alphabet.py | 14 +- src/sage/crypto/block_cipher/des.py | 11 +- src/sage/crypto/block_cipher/miniaes.py | 114 +- src/sage/crypto/mq/rijndael_gf.py | 15 +- src/sage/crypto/mq/sr.py | 856 ++++++++++- src/sage/crypto/sboxes.py | 271 +++- src/sage/databases/cremona.py | 10 +- src/sage/databases/cubic_hecke_db.py | 504 ++++++- src/sage/databases/findstat.py | 27 +- src/sage/databases/knotinfo_db.py | 242 ++- src/sage/doctest/__main__.py | 21 +- .../endPN_automorphism_group.py | 42 +- .../endPN_minimal_model.py | 15 +- .../dynamics/arithmetic_dynamics/wehlerK3.py | 7 +- src/sage/features/gap.py | 12 +- src/sage/features/sagemath.py | 21 +- src/sage/functions/all.py | 30 +- src/sage/functions/jacobi.py | 32 +- src/sage/functions/special.py | 4 +- src/sage/functions/wigner.py | 5 +- .../hyperbolic_space/hyperbolic_coercion.py | 12 +- src/sage/geometry/lattice_polytope.py | 23 +- src/sage/geometry/polyhedron/base_QQ.py | 15 +- src/sage/geometry/polyhedron/base_ZZ.py | 15 +- src/sage/graphs/generators/families.py | 49 +- src/sage/graphs/generators/smallgraphs.py | 1305 ++++++++++++++++- src/sage/graphs/generic_graph.py | 7 +- src/sage/graphs/graph_database.py | 28 +- src/sage/graphs/graph_generators.py | 78 +- src/sage/graphs/graph_plot.py | 33 +- src/sage/graphs/graph_plot_js.py | 18 +- src/sage/groups/braid.py | 109 +- src/sage/groups/perm_gps/all.py | 25 +- src/sage/interfaces/expect.py | 23 +- src/sage/interfaces/fricas.py | 17 +- src/sage/interfaces/gap3.py | 19 +- src/sage/interfaces/giac.py | 4 +- src/sage/interfaces/kenzo.py | 61 +- src/sage/interfaces/magma.py | 6 +- src/sage/interfaces/mathematica.py | 20 +- src/sage/interfaces/maxima_lib.py | 9 +- src/sage/interfaces/rubik.py | 51 +- src/sage/libs/gap/gap_globals.py | 32 +- .../differentiable/integrated_curve.py | 33 +- src/sage/matroids/database_collections.py | 240 ++- src/sage/matroids/database_matroids.py | 104 +- src/sage/misc/all.py | 59 +- src/sage/misc/edit_module.py | 11 +- src/sage/misc/latex.py | 42 +- src/sage/misc/rest_index_of_methods.py | 4 +- src/sage/misc/sagedoc.py | 40 +- src/sage/modular/multiple_zeta.py | 21 +- src/sage/monoids/string_monoid.py | 58 +- .../numerical/interactive_simplex_method.py | 14 +- src/sage/plot/arc.py | 9 +- src/sage/plot/arrow.py | 32 +- src/sage/plot/bezier_path.py | 9 +- src/sage/plot/circle.py | 15 +- src/sage/plot/disk.py | 11 +- src/sage/plot/ellipse.py | 14 +- src/sage/plot/graphics.py | 59 +- src/sage/plot/hyperbolic_arc.py | 6 +- src/sage/plot/line.py | 16 +- src/sage/plot/plot3d/shapes2.py | 6 +- src/sage/plot/plot3d/tachyon.py | 4 +- src/sage/plot/plot_field.py | 10 +- src/sage/plot/point.py | 13 +- src/sage/plot/polygon.py | 13 +- src/sage/plot/scatter_plot.py | 12 +- .../quadratic_forms/quadratic_form__mass.py | 16 +- src/sage/quadratic_forms/ternary_qf.py | 111 +- .../rings/finite_rings/integer_mod_ring.py | 11 +- src/sage/rings/invariants/invariant_theory.py | 67 +- src/sage/rings/lazy_series.py | 26 +- src/sage/rings/number_field/number_field.py | 5 +- src/sage/rings/padics/factory.py | 61 +- src/sage/rings/padics/misc.py | 10 +- .../polynomial_padic_capped_relative_dense.py | 12 +- src/sage/rings/polynomial/pbori/gbcore.py | 20 +- src/sage/rings/polynomial/pbori/nf.py | 51 +- src/sage/rings/polynomial/term_order.py | 9 +- .../elliptic_curves/addition_formulas_ring.py | 67 +- .../elliptic_curves/ell_curve_isogeny.py | 13 +- .../elliptic_curves/isogeny_small_degree.py | 469 +++++- .../hyperelliptic_curves/kummer_surface.py | 32 +- src/sage/schemes/toric/library.py | 99 +- src/sage/symbolic/expression_conversions.py | 30 +- src/sage/symbolic/units.py | 175 ++- src/sage/tests/finite_poset.py | 24 +- src/sage/topology/cubical_complex.py | 25 +- .../topology/simplicial_complex_catalog.py | 30 +- .../topology/simplicial_complex_examples.py | 162 +- src/sage/topology/simplicial_set_examples.py | 41 +- 128 files changed, 8190 insertions(+), 423 deletions(-) diff --git a/src/sage/algebras/fusion_rings/fusion_ring.py b/src/sage/algebras/fusion_rings/fusion_ring.py index f4b463b0098..025042d5d19 100644 --- a/src/sage/algebras/fusion_rings/fusion_ring.py +++ b/src/sage/algebras/fusion_rings/fusion_ring.py @@ -974,7 +974,19 @@ def r_matrix(self, i, j, k, base_coercion=True): else: i0 = self.one() B = self.basis() - ret = sum(y.ribbon(base_coercion=False) ** 2 / (i.ribbon(base_coercion=False) * x.ribbon(base_coercion=False) ** 2) * self.s_ij(i0, y, base_coercion=False) * self.s_ij(i, z, base_coercion=False) * self.s_ijconj(x, z, base_coercion=False) * self.s_ijconj(k, x, base_coercion=False) * self.s_ijconj(y, z, base_coercion=False) / self.s_ij(i0, z, base_coercion=False) for x in B for y in B for z in B) / (self.total_q_order(base_coercion=False) ** 4) + ret = sum( + y.ribbon(base_coercion=False) ** 2 + / (i.ribbon(base_coercion=False) * x.ribbon(base_coercion=False) ** 2) + * self.s_ij(i0, y, base_coercion=False) + * self.s_ij(i, z, base_coercion=False) + * self.s_ijconj(x, z, base_coercion=False) + * self.s_ijconj(k, x, base_coercion=False) + * self.s_ijconj(y, z, base_coercion=False) + / self.s_ij(i0, z, base_coercion=False) + for x in B + for y in B + for z in B + ) / (self.total_q_order(base_coercion=False) ** 4) if (not base_coercion) or (self._basecoer is None): return ret return self._basecoer(ret) diff --git a/src/sage/algebras/lie_algebras/classical_lie_algebra.py b/src/sage/algebras/lie_algebras/classical_lie_algebra.py index 11e42689daa..bc0c1702b42 100644 --- a/src/sage/algebras/lie_algebras/classical_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/classical_lie_algebra.py @@ -912,7 +912,14 @@ def __init__(self, R): """ MS = MatrixSpace(R, 27, sparse=True) one = R.one() - coords = [[(0, 1), (10, 12), (13, 15), (16, 17), (18, 19), (20, 21)], [(3, 4), (5, 6), (7, 9), (18, 20), (19, 21), (22, 23)], [(1, 2), (8, 10), (11, 13), (14, 16), (19, 22), (21, 23)], [(2, 3), (6, 8), (9, 11), (16, 18), (17, 19), (23, 24)], [(3, 5), (4, 6), (11, 14), (13, 16), (15, 17), (24, 25)], [(5, 7), (6, 9), (8, 11), (10, 13), (12, 15), (25, 26)]] + coords = [ + [(0, 1), (10, 12), (13, 15), (16, 17), (18, 19), (20, 21)], + [(3, 4), (5, 6), (7, 9), (18, 20), (19, 21), (22, 23)], + [(1, 2), (8, 10), (11, 13), (14, 16), (19, 22), (21, 23)], + [(2, 3), (6, 8), (9, 11), (16, 18), (17, 19), (23, 24)], + [(3, 5), (4, 6), (11, 14), (13, 16), (15, 17), (24, 25)], + [(5, 7), (6, 9), (8, 11), (10, 13), (12, 15), (25, 26)], + ] e = [MS({c: one for c in coord}) for coord in coords] f = [MS({(c[1], c[0]): one for c in coord}) for coord in coords] ExceptionalMatrixLieAlgebra.__init__(self, R, CartanType(['E', 6]), e, f) @@ -942,7 +949,15 @@ def __init__(self, R): """ MS = MatrixSpace(R, 56, sparse=True) one = R.one() - coords = [[(6, 7), (8, 9), (10, 11), (12, 14), (15, 17), (18, 21), (34, 37), (38, 40), (41, 43), (44, 45), (46, 47), (48, 49)], [(4, 5), (6, 8), (7, 9), (19, 22), (23, 25), (26, 28), (27, 29), (30, 32), (33, 36), (46, 48), (47, 49), (50, 51)], [(4, 6), (5, 8), (11, 13), (14, 16), (17, 20), (21, 24), (31, 34), (35, 38), (39, 41), (42, 44), (47, 50), (49, 51)], [(3, 4), (8, 10), (9, 11), (16, 19), (20, 23), (24, 27), (28, 31), (32, 35), (36, 39), (44, 46), (45, 47), (51, 52)], [(2, 3), (10, 12), (11, 14), (13, 16), (23, 26), (25, 28), (27, 30), (29, 32), (39, 42), (41, 44), (43, 45), (52, 53)], [(1, 2), (12, 15), (14, 17), (16, 20), (19, 23), (22, 25), (30, 33), (32, 36), (35, 39), (38, 41), (40, 43), (53, 54)], [(0, 1), (15, 18), (17, 21), (20, 24), (23, 27), (25, 29), (26, 30), (28, 32), (31, 35), (34, 38), (37, 40), (54, 55)]] + coords = [ + [(6, 7), (8, 9), (10, 11), (12, 14), (15, 17), (18, 21), (34, 37), (38, 40), (41, 43), (44, 45), (46, 47), (48, 49)], + [(4, 5), (6, 8), (7, 9), (19, 22), (23, 25), (26, 28), (27, 29), (30, 32), (33, 36), (46, 48), (47, 49), (50, 51)], + [(4, 6), (5, 8), (11, 13), (14, 16), (17, 20), (21, 24), (31, 34), (35, 38), (39, 41), (42, 44), (47, 50), (49, 51)], + [(3, 4), (8, 10), (9, 11), (16, 19), (20, 23), (24, 27), (28, 31), (32, 35), (36, 39), (44, 46), (45, 47), (51, 52)], + [(2, 3), (10, 12), (11, 14), (13, 16), (23, 26), (25, 28), (27, 30), (29, 32), (39, 42), (41, 44), (43, 45), (52, 53)], + [(1, 2), (12, 15), (14, 17), (16, 20), (19, 23), (22, 25), (30, 33), (32, 36), (35, 39), (38, 41), (40, 43), (53, 54)], + [(0, 1), (15, 18), (17, 21), (20, 24), (23, 27), (25, 29), (26, 30), (28, 32), (31, 35), (34, 38), (37, 40), (54, 55)], + ] e = [MS({c: one for c in coord}) for coord in coords] f = [MS({(c[1], c[0]): one for c in coord}) for coord in coords] ExceptionalMatrixLieAlgebra.__init__(self, R, CartanType(['E', 7]), e, f) @@ -1012,13 +1027,23 @@ def __init__(self, R): MS = MatrixSpace(R, 26, sparse=True) one = R.one() - coords = [[(0, 1), (5, 7), (6, 9), (8, 11), (10, 12), (10, 13), (12, 14), (15, 16), (17, 18), (19, 20), (24, 25)], [(1, 2), (3, 5), (4, 6), (8, 10), (11, 12), (11, 13), (13, 15), (14, 16), (18, 21), (20, 22), (23, 24)], [(2, 3), (6, 8), (9, 11), (15, 17), (16, 18), (22, 23)], [(3, 4), (5, 6), (7, 9), (17, 19), (18, 20), (21, 22)]] + coords = [ + [(0, 1), (5, 7), (6, 9), (8, 11), (10, 12), (10, 13), (12, 14), (15, 16), (17, 18), (19, 20), (24, 25)], + [(1, 2), (3, 5), (4, 6), (8, 10), (11, 12), (11, 13), (13, 15), (14, 16), (18, 21), (20, 22), (23, 24)], + [(2, 3), (6, 8), (9, 11), (15, 17), (16, 18), (22, 23)], + [(3, 4), (5, 6), (7, 9), (17, 19), (18, 20), (21, 22)], + ] e = [MS({c: one for c in coord}) for coord in coords] # Double (10, 12) in e1 and (11,13) in e2 e[0][10, 12] = 2 * one e[1][11, 13] = 2 * one - coords = [[(1, 0), (7, 5), (9, 6), (11, 8), (12, 10), (14, 12), (14, 13), (16, 15), (18, 17), (20, 19), (25, 24)], [(2, 1), (5, 3), (6, 4), (10, 8), (13, 11), (15, 12), (15, 13), (16, 14), (21, 18), (22, 20), (24, 23)], [(3, 2), (8, 6), (11, 9), (17, 15), (18, 16), (23, 22)], [(4, 3), (6, 5), (9, 7), (19, 17), (20, 18), (22, 21)]] + coords = [ + [(1, 0), (7, 5), (9, 6), (11, 8), (12, 10), (14, 12), (14, 13), (16, 15), (18, 17), (20, 19), (25, 24)], + [(2, 1), (5, 3), (6, 4), (10, 8), (13, 11), (15, 12), (15, 13), (16, 14), (21, 18), (22, 20), (24, 23)], + [(3, 2), (8, 6), (11, 9), (17, 15), (18, 16), (23, 22)], + [(4, 3), (6, 5), (9, 7), (19, 17), (20, 18), (22, 21)], + ] f = [MS({c: one for c in coord}) for coord in coords] # Double (14, 12) in f1 and (15,13) in f2 f[0][14, 12] = 2 * one diff --git a/src/sage/algebras/lie_algebras/onsager.py b/src/sage/algebras/lie_algebras/onsager.py index a98c5dee32d..8ba07a344f7 100644 --- a/src/sage/algebras/lie_algebras/onsager.py +++ b/src/sage/algebras/lie_algebras/onsager.py @@ -832,28 +832,40 @@ def a(m, p): # [B[md], B[pd+a0]] with p < m # m = kl[1] terms += self._c * self._q_two * (q ** (-2 * (kl[1] - 1)) * self.monomial(B[0, -(kl[1] + p + 1)]) + (q**2 - q**-2) * sum(q ** (-2 * (kl[1] - 2 * p + 2 * h)) * self.monomial(B[0, -(kl[1] - p + 2 * h + 1)]) for h in range(p)) - q ** (-2 * (kl[1] - 2 * p - 1)) * self.monomial(B[0, kl[1] - p - 1])) - terms -= (q**2 - q**-2) * sum(q ** (-2 * (ell - 1)) * self.monomial(B[0, -(ell + p + 1)] * B[1, kl[1] - ell]) + (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * h)) * self.monomial(B[0, -(ell + p - 2 * h + 1)] * B[1, kl[1] - ell]) for h in range(1, ell)) - q ** (2 * (ell - 1)) * self.monomial(B[0, -(p - ell + 1)] * B[1, kl[1] - ell]) for ell in range(1, p + 1)) + terms -= (q**2 - q**-2) * sum( + q ** (-2 * (ell - 1)) * self.monomial(B[0, -(ell + p + 1)] * B[1, kl[1] - ell]) + (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * h)) * self.monomial(B[0, -(ell + p - 2 * h + 1)] * B[1, kl[1] - ell]) for h in range(1, ell)) - q ** (2 * (ell - 1)) * self.monomial(B[0, -(p - ell + 1)] * B[1, kl[1] - ell]) + for ell in range(1, p + 1) + ) terms -= (q**2 - q**-2) * sum(q ** (-2 * (ell - 1)) * self.monomial(B[0, -(ell + p + 1)] * B[1, kl[1] - ell]) + (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * h)) * self.monomial(B[0, -(ell + p - 2 * h + 1)] * B[1, kl[1] - ell]) for h in range(1, p + 1)) for ell in range(p + 1, kl[1])) terms += (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * p - 1)) * self.monomial(B[1, kl[1] - ell] * B[0, ell - p - 1]) for ell in range(p + 1, kl[1])) else: # [B[md], B[pd+a0]] with p >= m # m = kl[1] terms += self._c * self._q_two * (q ** (-2 * (kl[1] - 1)) * self.monomial(B[0, -(p + kl[1] + 1)]) + (q**2 - q**-2) * sum(q ** (2 * (kl[1] - 2 - 2 * h)) * self.monomial(B[0, -(p - kl[1] + 2 + 2 * h + 1)]) for h in range(kl[1] - 1)) - q ** (2 * (kl[1] - 1)) * self.monomial(B[0, -(p - kl[1] + 1)])) - terms -= (q**2 - q**-2) * sum(q ** (-2 * (ell - 1)) * self.monomial(B[0, -(p + ell + 1)] * B[1, kl[1] - ell]) + (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * h)) * self.monomial(B[0, -(p + ell - 2 * h + 1)] * B[1, kl[1] - ell]) for h in range(1, ell)) - q ** (2 * (ell - 1)) * self.monomial(B[0, -(p - ell + 1)] * B[1, kl[1] - ell]) for ell in range(1, kl[1])) + terms -= (q**2 - q**-2) * sum( + q ** (-2 * (ell - 1)) * self.monomial(B[0, -(p + ell + 1)] * B[1, kl[1] - ell]) + (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * h)) * self.monomial(B[0, -(p + ell - 2 * h + 1)] * B[1, kl[1] - ell]) for h in range(1, ell)) - q ** (2 * (ell - 1)) * self.monomial(B[0, -(p - ell + 1)] * B[1, kl[1] - ell]) + for ell in range(1, kl[1]) + ) else: # kl[0] == 0 and kr[0] == 1: terms = self.monomial(B[kr] * B[kl]) if kl[1] < kr[1]: # [B[pd+a1], B[md]] with p < m # p = kl[1], m = kr[1] terms += self._c * self._q_two * (q ** (-2 * (kr[1] - 1)) * self.monomial(B[0, kr[1] + kl[1]]) + (q**2 - q**-2) * sum(q ** (-2 * (kr[1] - 2 * kl[1] + 2 * h)) * self.monomial(B[0, kr[1] - kl[1] + 2 * h]) for h in range(kl[1])) - q ** (-2 * (kr[1] - 2 * kl[1] - 1)) * self.monomial(B[0, kl[1] - kr[1]])) - terms -= (q**2 - q**-2) * sum(q ** (-2 * (ell - 1)) * self.monomial(B[1, kr[1] - ell] * B[0, ell + kl[1]]) + (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * h)) * self.monomial(B[1, kr[1] - ell] * B[0, ell + kl[1] - 2 * h]) for h in range(1, ell)) - q ** (2 * (ell - 1)) * self.monomial(B[1, kr[1] - ell] * B[0, kl[1] - ell]) for ell in range(1, kl[1] + 1)) + terms -= (q**2 - q**-2) * sum( + q ** (-2 * (ell - 1)) * self.monomial(B[1, kr[1] - ell] * B[0, ell + kl[1]]) + (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * h)) * self.monomial(B[1, kr[1] - ell] * B[0, ell + kl[1] - 2 * h]) for h in range(1, ell)) - q ** (2 * (ell - 1)) * self.monomial(B[1, kr[1] - ell] * B[0, kl[1] - ell]) + for ell in range(1, kl[1] + 1) + ) terms -= (q**2 - q**-2) * sum(q ** (-2 * (ell - 1)) * self.monomial(B[1, kr[1] - ell] * B[0, ell + kl[1]]) + (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * h)) * self.monomial(B[1, kr[1] - ell] * B[0, ell + kl[1] - 2 * h]) for h in range(1, kl[1] + 1)) for ell in range(kl[1] + 1, kr[1])) terms += (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * kl[1] - 1)) * self.monomial(B[0, kl[1] - ell] * B[1, kr[1] - ell]) for ell in range(kl[1] + 1, kr[1])) else: # [B[pd+a1], B[md]] with p >= m # p = kl[1], m = kr[1] terms += self._c * self._q_two * (q ** (-2 * (kr[1] - 1)) * self.monomial(B[0, kl[1] + kr[1]]) + (q**2 - q**-2) * sum(q ** (2 * (kr[1] - 2 - 2 * h)) * self.monomial(B[0, kl[1] - kr[1] + 2 + 2 * h]) for h in range(kr[1] - 1)) - q ** (2 * (kr[1] - 1)) * self.monomial(B[0, kl[1] - kr[1]])) - terms -= (q**2 - q**-2) * sum(q ** (-2 * (ell - 1)) * self.monomial(B[1, kr[1] - ell] * B[0, kl[1] + ell]) + (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * h)) * self.monomial(B[1, kr[1] - ell] * B[0, kl[1] + ell - 2 * h]) for h in range(1, ell)) - q ** (2 * (ell - 1)) * self.monomial(B[1, kr[1] - ell] * B[0, kl[1] - ell]) for ell in range(1, kr[1])) + terms -= (q**2 - q**-2) * sum( + q ** (-2 * (ell - 1)) * self.monomial(B[1, kr[1] - ell] * B[0, kl[1] + ell]) + (q**2 - q**-2) * sum(q ** (-2 * (ell - 2 * h)) * self.monomial(B[1, kr[1] - ell] * B[0, kl[1] + ell - 2 * h]) for h in range(1, ell)) - q ** (2 * (ell - 1)) * self.monomial(B[1, kr[1] - ell] * B[0, kl[1] - ell]) + for ell in range(1, kr[1]) + ) return self.monomial(lhs // B[kl]) * terms * self.monomial(rhs // B[kr]) diff --git a/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py index 938f29bf262..fdb0be762a6 100644 --- a/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py @@ -85,7 +85,16 @@ def __init__(self, R) -> None: sage: V = lie_conformal_algebras.N2(QQ) sage: TestSuite(V).run() # long time (:issue:`39569`) """ - n2dict = {('L', 'L'): {0: {('L', 1): 1}, 1: {('L', 0): 2}, 3: {('C', 0): R(2).inverse_of_unit()}}, ('L', 'G1'): {0: {('G1', 1): 1}, 1: {('G1', 0): 3 * R(2).inverse_of_unit()}}, ('L', 'G2'): {0: {('G2', 1): 1}, 1: {('G2', 0): 3 * R(2).inverse_of_unit()}}, ('G1', 'G2'): {0: {('L', 0): 1, ('J', 1): R(2).inverse_of_unit()}, 1: {('J', 0): 1}, 2: {('C', 0): R(3).inverse_of_unit()}}, ('L', 'J'): {0: {('J', 1): 1}, 1: {('J', 0): 1}}, ('J', 'J'): {1: {('C', 0): R(3).inverse_of_unit()}}, ('J', 'G1'): {0: {('G1', 0): 1}}, ('J', 'G2'): {0: {('G2', 0): -1}}} + n2dict = { + ('L', 'L'): {0: {('L', 1): 1}, 1: {('L', 0): 2}, 3: {('C', 0): R(2).inverse_of_unit()}}, + ('L', 'G1'): {0: {('G1', 1): 1}, 1: {('G1', 0): 3 * R(2).inverse_of_unit()}}, + ('L', 'G2'): {0: {('G2', 1): 1}, 1: {('G2', 0): 3 * R(2).inverse_of_unit()}}, + ('G1', 'G2'): {0: {('L', 0): 1, ('J', 1): R(2).inverse_of_unit()}, 1: {('J', 0): 1}, 2: {('C', 0): R(3).inverse_of_unit()}}, + ('L', 'J'): {0: {('J', 1): 1}, 1: {('J', 0): 1}}, + ('J', 'J'): {1: {('C', 0): R(3).inverse_of_unit()}}, + ('J', 'G1'): {0: {('G1', 0): 1}}, + ('J', 'G2'): {0: {('G2', 0): -1}}, + } from sage.rings.rational_field import QQ weights = (2, 1, QQ(3) / 2, QQ(3) / 2) diff --git a/src/sage/algebras/quantum_groups/ace_quantum_onsager.py b/src/sage/algebras/quantum_groups/ace_quantum_onsager.py index aa995678b39..4448e9e65fc 100644 --- a/src/sage/algebras/quantum_groups/ace_quantum_onsager.py +++ b/src/sage/algebras/quantum_groups/ace_quantum_onsager.py @@ -546,33 +546,59 @@ def product_on_basis(self, lhs, rhs): i = kl[1] - 1 j = kr[1] - 1 coeff = (q**2 - q**-2) ** 3 - terms = A[0, j + 1] * A[2, i + 1] - coeff * A[1, -i] * A[1, -j] + coeff * A[1, i + 1] * A[1, j + 1] + coeff * sum(A[1, -ell] * A[1, i + j + 2 - ell] - A[1, ell - 1 - i - j] * A[1, ell + 1] for ell in range(min(i, j) + 1)) - coeff * sum(A[1, 1 - ell] * A[1, i + j + 1 - ell] - A[1, ell - i - j] * A[1, ell] for ell in range(1, min(i, j) + 1)) + terms = ( + A[0, j + 1] * A[2, i + 1] + - coeff * A[1, -i] * A[1, -j] + + coeff * A[1, i + 1] * A[1, j + 1] + + coeff * sum(A[1, -ell] * A[1, i + j + 2 - ell] - A[1, ell - 1 - i - j] * A[1, ell + 1] for ell in range(min(i, j) + 1)) + - coeff * sum(A[1, 1 - ell] * A[1, i + j + 1 - ell] - A[1, ell - i - j] * A[1, ell] for ell in range(1, min(i, j) + 1)) + ) elif kl[0] == 1 and kr[0] == 0: if kl[1] > 0: # relation (vi) i = kl[1] - 1 j = kr[1] - 1 coeff = q * (q - ~q) - terms = A[0, j + 1] * A[1, i + 1] + coeff * sum(A[0, ell] * A[1, ell - i - j] for ell in range(min(i, j) + 1)) + coeff * sum(A[0, i + j + 1 - ell] * A[1, ell + 1] - A[0, ell] * A[1, i + j + 2 - ell] for ell in range(min(i, j) + 1)) - coeff * sum(A[0, i + j + 1 - ell] * A[1, 1 - ell] for ell in range(1, min(i, j) + 1)) + terms = ( + A[0, j + 1] * A[1, i + 1] + + coeff * sum(A[0, ell] * A[1, ell - i - j] for ell in range(min(i, j) + 1)) + + coeff * sum(A[0, i + j + 1 - ell] * A[1, ell + 1] - A[0, ell] * A[1, i + j + 2 - ell] for ell in range(min(i, j) + 1)) + - coeff * sum(A[0, i + j + 1 - ell] * A[1, 1 - ell] for ell in range(1, min(i, j) + 1)) + ) else: # relation (v) i = -kl[1] j = kr[1] - 1 coeff = ~q * (q - ~q) - terms = A[0, j + 1] * A[1, -i] - coeff * sum(A[0, ell] * A[1, i + j + 1 - ell] for ell in range(min(i, j) + 1)) + coeff * sum(A[0, ell] * A[1, ell - 1 - i - j] - A[0, i + j + 1 - ell] * A[1, -ell] for ell in range(min(i, j) + 1)) + coeff * sum(A[0, i + j + 1 - ell] * A[1, ell] for ell in range(1, min(i, j) + 1)) + terms = ( + A[0, j + 1] * A[1, -i] + - coeff * sum(A[0, ell] * A[1, i + j + 1 - ell] for ell in range(min(i, j) + 1)) + + coeff * sum(A[0, ell] * A[1, ell - 1 - i - j] - A[0, i + j + 1 - ell] * A[1, -ell] for ell in range(min(i, j) + 1)) + + coeff * sum(A[0, i + j + 1 - ell] * A[1, ell] for ell in range(1, min(i, j) + 1)) + ) elif kl[0] == 2 and kr[0] == 1: if kr[1] > 0: # relation (vi) i = kl[1] - 1 j = kr[1] - 1 coeff = q * (q - ~q) - terms = A[1, j + 1] * A[2, i + 1] + coeff * sum(A[1, ell - i - j] * A[2, ell] for ell in range(min(i, j) + 1)) + coeff * sum(A[1, ell + 1] * A[2, i + j + 1 - ell] - A[1, i + j + 2 - ell] * A[2, ell] for ell in range(min(i, j) + 1)) - coeff * sum(A[1, 1 - ell] * A[2, i + j + 1 - ell] for ell in range(1, min(i, j) + 1)) + terms = ( + A[1, j + 1] * A[2, i + 1] + + coeff * sum(A[1, ell - i - j] * A[2, ell] for ell in range(min(i, j) + 1)) + + coeff * sum(A[1, ell + 1] * A[2, i + j + 1 - ell] - A[1, i + j + 2 - ell] * A[2, ell] for ell in range(min(i, j) + 1)) + - coeff * sum(A[1, 1 - ell] * A[2, i + j + 1 - ell] for ell in range(1, min(i, j) + 1)) + ) else: # relation (vii) i = kl[1] - 1 j = -kr[1] coeff = ~q * (q - ~q) - terms = A[1, -j] * A[2, i + 1] - coeff * sum(A[1, i + j + 1 - ell] * A[2, ell] for ell in range(min(i, j) + 1)) + coeff * sum(A[1, ell - 1 - i - j] * A[2, ell] - A[1, -ell] * A[2, i + j + 1 - ell] for ell in range(min(i, j) + 1)) + coeff * sum(A[1, ell] * A[2, i + j + 1 - ell] for ell in range(1, min(i, j) + 1)) + terms = ( + A[1, -j] * A[2, i + 1] + - coeff * sum(A[1, i + j + 1 - ell] * A[2, ell] for ell in range(min(i, j) + 1)) + + coeff * sum(A[1, ell - 1 - i - j] * A[2, ell] - A[1, -ell] * A[2, i + j + 1 - ell] for ell in range(min(i, j) + 1)) + + coeff * sum(A[1, ell] * A[2, i + j + 1 - ell] for ell in range(1, min(i, j) + 1)) + ) return self.monomial(lhs // B[kl]) * terms * self.monomial(rhs // B[kr]) diff --git a/src/sage/calculus/desolvers.py b/src/sage/calculus/desolvers.py index 539125cc498..06f57f76627 100644 --- a/src/sage/calculus/desolvers.py +++ b/src/sage/calculus/desolvers.py @@ -1860,7 +1860,9 @@ def desolve_tides_mpfr(f, ics, initial, final, delta, tolrel=1e-16, tolabs=1e-16 fileoutput = os.path.join(tempdir, 'output') runmefile = os.path.join(tempdir, 'runme') genfiles_mpfr(intfile, drfile, f, ics, initial, final, delta, [], [], digits, tolrel, tolabs, fileoutput) - subprocess.check_call('gcc -o ' + runmefile + ' ' + os.path.join(tempdir, '*.c ') + os.path.join('$SAGE_LOCAL', 'lib', 'libTIDES.a') + ' $LDFLAGS ' + os.path.join('-L$SAGE_LOCAL', 'lib ') + '-lmpfr -lgmp -lm -O2 -w ' + os.path.join('-I$SAGE_LOCAL', 'include '), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + subprocess.check_call( + 'gcc -o ' + runmefile + ' ' + os.path.join(tempdir, '*.c ') + os.path.join('$SAGE_LOCAL', 'lib', 'libTIDES.a') + ' $LDFLAGS ' + os.path.join('-L$SAGE_LOCAL', 'lib ') + '-lmpfr -lgmp -lm -O2 -w ' + os.path.join('-I$SAGE_LOCAL', 'include '), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) subprocess.check_call(os.path.join(tempdir, 'runme'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) with open(fileoutput) as outfile: res = outfile.readlines() diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index fa173e1041f..428bf2a452c 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -1674,7 +1674,54 @@ class ``Sets.Finite``), or in a separate file (typically in a class # ``Category of commutative unital magmas'' all_axioms = AxiomContainer() -all_axioms += ("Flying", "Blue", "Compact", "Differentiable", "Smooth", "Analytic", "AlmostComplex", "FinitelyGeneratedAsMagma", "WellGenerated", "Bounded", "Facade", "Finite", "Infinite", "Enumerated", "Complete", "Nilpotent", "FiniteDimensional", "FinitelyPresented", "Connected", "FinitelyGeneratedAsLambdaBracketAlgebra", "WithBasis", "Irreducible", "Supercommutative", "Supercocommutative", "Commutative", "Cocommutative", "Associative", "Inverse", "Unital", "Division", "NoZeroDivisors", "Cellular", "AdditiveCommutative", "AdditiveAssociative", "AdditiveInverse", "AdditiveUnital", "Extremal", "Trim", "Semidistributive", "CongruenceUniform", "ChainGraded", "Distributive", "Stone", "Endset", "Pointed", "Stratified") +all_axioms += ( + "Flying", + "Blue", + "Compact", + "Differentiable", + "Smooth", + "Analytic", + "AlmostComplex", + "FinitelyGeneratedAsMagma", + "WellGenerated", + "Bounded", + "Facade", + "Finite", + "Infinite", + "Enumerated", + "Complete", + "Nilpotent", + "FiniteDimensional", + "FinitelyPresented", + "Connected", + "FinitelyGeneratedAsLambdaBracketAlgebra", + "WithBasis", + "Irreducible", + "Supercommutative", + "Supercocommutative", + "Commutative", + "Cocommutative", + "Associative", + "Inverse", + "Unital", + "Division", + "NoZeroDivisors", + "Cellular", + "AdditiveCommutative", + "AdditiveAssociative", + "AdditiveInverse", + "AdditiveUnital", + "Extremal", + "Trim", + "Semidistributive", + "CongruenceUniform", + "ChainGraded", + "Distributive", + "Stone", + "Endset", + "Pointed", + "Stratified", +) def uncamelcase(s, separator=" "): diff --git a/src/sage/categories/crystals.py b/src/sage/categories/crystals.py index 92e8c6dcb27..7ebb4283059 100644 --- a/src/sage/categories/crystals.py +++ b/src/sage/categories/crystals.py @@ -1054,7 +1054,10 @@ def metapost(self, filename, thicklines=False, labels=True, scaling_factor=1.0, outstring = "verbatimtex\n\\magnification=600\netex\n\nbeginfig(-1);\nsx:=35; sy:=30;\n\nz1000=(%d,0);\nz1001=(%d,%d);\nz1002=(%d,%d);\nz2001=(-3,3);\nz2002=(3,3);\nz2003=(0,-3);\nz2004=(7,0);\nz2005=(0,7);\nz2006=(-7,0);\nz2007=(0,7);\n\n" % (c0, c1, c2, c3, c4) else: if labels: - outstring = "verbatimtex\n\\magnification=600\netex\n\nbeginfig(-1);\n\nsx := %d;\nsy=%d;\n\nz1000=(2*sx,0);\nz1001=(-sx,sy);\nz1002=(-16,-10);\n\nz2001=(0,-3);\nz2002=(-5,3);\nz2003=(0,3);\nz2004=(5,3);\nz2005=(10,1);\nz2006=(0,10);\nz2007=(-10,1);\nz2008=(0,-8);\n\n" % (int(scaling_factor * 40), int(tallness * scaling_factor * 40)) + outstring = "verbatimtex\n\\magnification=600\netex\n\nbeginfig(-1);\n\nsx := %d;\nsy=%d;\n\nz1000=(2*sx,0);\nz1001=(-sx,sy);\nz1002=(-16,-10);\n\nz2001=(0,-3);\nz2002=(-5,3);\nz2003=(0,3);\nz2004=(5,3);\nz2005=(10,1);\nz2006=(0,10);\nz2007=(-10,1);\nz2008=(0,-8);\n\n" % ( + int(scaling_factor * 40), + int(tallness * scaling_factor * 40), + ) else: outstring = "beginfig(-1);\n\nsx := %d;\nsy := %d;\n\nz1000=(2*sx,0);\nz1001=(-sx,sy);\nz1002=(-5,-5);\n\nz1003=(10,10);\n\n" % (int(scaling_factor * 35), int(tallness * scaling_factor * 35)) for i in range(size): @@ -1098,9 +1101,17 @@ def metapost(self, filename, thicklines=False, labels=True, scaling_factor=1.0, for i in range(self.cardinality()): if labels: if self.cartan_type()[0] == 'A': - outstring = outstring + "pickup pencircle scaled 15;\nfill z%d+z2004..z%d+z2006..z%d+z2006..z%d+z2007..cycle withcolor white;\nlabel(btex %d etex, z%d+z2001);\nlabel(btex %d etex, z%d+z2002);\nlabel(btex %d etex, z%d+z2003);\npickup pencircle scaled .5;\ndraw z%d+z2004..z%d+z2006..z%d+z2006..z%d+z2007..cycle;\n" % (i, i, i, i, string_data[i][2], i, string_data[i][1], i, string_data[i][0], i, i, i, i, i) + outstring = ( + outstring + + "pickup pencircle scaled 15;\nfill z%d+z2004..z%d+z2006..z%d+z2006..z%d+z2007..cycle withcolor white;\nlabel(btex %d etex, z%d+z2001);\nlabel(btex %d etex, z%d+z2002);\nlabel(btex %d etex, z%d+z2003);\npickup pencircle scaled .5;\ndraw z%d+z2004..z%d+z2006..z%d+z2006..z%d+z2007..cycle;\n" + % (i, i, i, i, string_data[i][2], i, string_data[i][1], i, string_data[i][0], i, i, i, i, i) + ) else: - outstring = outstring + "%%%d %d %d %d\npickup pencircle scaled 1;\nfill z%d+z2005..z%d+z2006..z%d+z2007..z%d+z2008..cycle withcolor white;\nlabel(btex %d etex, z%d+z2001);\nlabel(btex %d etex, z%d+z2002);\nlabel(btex %d etex, z%d+z2003);\nlabel(btex %d etex, z%d+z2004);\npickup pencircle scaled .5;\ndraw z%d+z2005..z%d+z2006..z%d+z2007..z%d+z2008..cycle;\n\n" % (string_data[i][0], string_data[i][1], string_data[i][2], string_data[i][3], i, i, i, i, string_data[i][0], i, string_data[i][1], i, string_data[i][2], i, string_data[i][3], i, i, i, i, i) + outstring = ( + outstring + + "%%%d %d %d %d\npickup pencircle scaled 1;\nfill z%d+z2005..z%d+z2006..z%d+z2007..z%d+z2008..cycle withcolor white;\nlabel(btex %d etex, z%d+z2001);\nlabel(btex %d etex, z%d+z2002);\nlabel(btex %d etex, z%d+z2003);\nlabel(btex %d etex, z%d+z2004);\npickup pencircle scaled .5;\ndraw z%d+z2005..z%d+z2006..z%d+z2007..z%d+z2008..cycle;\n\n" + % (string_data[i][0], string_data[i][1], string_data[i][2], string_data[i][3], i, i, i, i, string_data[i][0], i, string_data[i][1], i, string_data[i][2], i, string_data[i][3], i, i, i, i, i) + ) else: outstring += "drawdot z%d;\n" % i outstring += "\nendfig;\n\nend;\n\n" diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 539f6538a55..f2ed67977af 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -3528,7 +3528,9 @@ def __mul__(self, other): if isinstance(other, AlgebraicExtensionFunctor): if set(self.names).intersection(other.names): raise CoercionException("Overlapping names (%s,%s)" % (self.names, other.names)) - return AlgebraicExtensionFunctor(self.polys + other.polys, self.names + other.names, self.embeddings + other.embeddings, self.structures + other.structures, precs=self.precs + other.precs, implementations=self.implementations + other.implementations, latex_names=self.latex_names + other.latex_names, **self.kwds) + return AlgebraicExtensionFunctor( + self.polys + other.polys, self.names + other.names, self.embeddings + other.embeddings, self.structures + other.structures, precs=self.precs + other.precs, implementations=self.implementations + other.implementations, latex_names=self.latex_names + other.latex_names, **self.kwds + ) if isinstance(other, CompositeConstructionFunctor) and isinstance(other.all[-1], AlgebraicExtensionFunctor): return CompositeConstructionFunctor(other.all[:-1], self * other.all[-1]) return CompositeConstructionFunctor(other, self) diff --git a/src/sage/coding/bounds_catalog.py b/src/sage/coding/bounds_catalog.py index ae61228757a..3ab389f7f5f 100644 --- a/src/sage/coding/bounds_catalog.py +++ b/src/sage/coding/bounds_catalog.py @@ -12,7 +12,28 @@ from sage.misc.lazy_import import lazy_import as _lazy_import -_lazy_import("sage.coding.code_bounds", ["codesize_upper_bound", "dimension_upper_bound", "volume_hamming", "gilbert_lower_bound", "plotkin_upper_bound", "griesmer_upper_bound", "elias_upper_bound", "hamming_upper_bound", "singleton_upper_bound", "gv_info_rate", "entropy", "gv_bound_asymp", "hamming_bound_asymp", "singleton_bound_asymp", "plotkin_bound_asymp", "elias_bound_asymp", "mrrw1_bound_asymp"]) +_lazy_import( + "sage.coding.code_bounds", + [ + "codesize_upper_bound", + "dimension_upper_bound", + "volume_hamming", + "gilbert_lower_bound", + "plotkin_upper_bound", + "griesmer_upper_bound", + "elias_upper_bound", + "hamming_upper_bound", + "singleton_upper_bound", + "gv_info_rate", + "entropy", + "gv_bound_asymp", + "hamming_bound_asymp", + "singleton_bound_asymp", + "plotkin_bound_asymp", + "elias_bound_asymp", + "mrrw1_bound_asymp", + ], +) _lazy_import("sage.coding.delsarte_bounds", ["krawtchouk", "eberlein", "delsarte_bound_constant_weight_code", "delsarte_bound_hamming_space", "delsarte_bound_additive_hamming_space", "delsarte_bound_Q_matrix"]) diff --git a/src/sage/coding/golay_code.py b/src/sage/coding/golay_code.py index 64adc11fd06..49cf698c96b 100644 --- a/src/sage/coding/golay_code.py +++ b/src/sage/coding/golay_code.py @@ -284,9 +284,41 @@ def generator_matrix(self): """ n = self.length() if n == 23: - G = matrix(GF(2), [[1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1]]) + G = matrix( + GF(2), + [ + [1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1], + ], + ) elif n == 24: - G = matrix(GF(2), [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0], [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1]]) + G = matrix( + GF(2), + [ + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1], + [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0], + [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1], + [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0], + [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1], + [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1], + [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1], + [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1], + ], + ) elif n == 11: G = matrix(GF(3), [[2, 0, 1, 2, 1, 1, 0, 0, 0, 0, 0], [0, 2, 0, 1, 2, 1, 1, 0, 0, 0, 0], [0, 0, 2, 0, 1, 2, 1, 1, 0, 0, 0], [0, 0, 0, 2, 0, 1, 2, 1, 1, 0, 0], [0, 0, 0, 0, 2, 0, 1, 2, 1, 1, 0], [0, 0, 0, 0, 0, 2, 0, 1, 2, 1, 1]]) else: @@ -315,7 +347,22 @@ def parity_check_matrix(self): """ n = self.length() if n == 23: - H = matrix(GF(2), [[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1], [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1], [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1]]) + H = matrix( + GF(2), + [ + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0], + [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1], + [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0], + [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1], + [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1], + [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1], + [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1], + ], + ) elif n == 11: H = matrix(GF(3), [[1, 0, 0, 0, 0, 1, 2, 2, 2, 1, 0], [0, 1, 0, 0, 0, 0, 1, 2, 2, 2, 1], [0, 0, 1, 0, 0, 2, 1, 2, 0, 1, 2], [0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1], [0, 0, 0, 0, 1, 2, 2, 2, 1, 0, 1]]) else: diff --git a/src/sage/coding/guruswami_sudan/gs_decoder.py b/src/sage/coding/guruswami_sudan/gs_decoder.py index e7cb089ac44..c214c0f1b4c 100644 --- a/src/sage/coding/guruswami_sudan/gs_decoder.py +++ b/src/sage/coding/guruswami_sudan/gs_decoder.py @@ -671,7 +671,15 @@ def __eq__(self, other): sage: D1.__eq__(D2) True """ - return isinstance(other, GRSGuruswamiSudanDecoder) and self.code() == other.code() and self.decoding_radius() == other.decoding_radius() and self.multiplicity() == other.multiplicity() and self.list_size() == other.list_size() and self.interpolation_algorithm() == other.interpolation_algorithm() and self.rootfinding_algorithm() == other.rootfinding_algorithm() + return ( + isinstance(other, GRSGuruswamiSudanDecoder) + and self.code() == other.code() + and self.decoding_radius() == other.decoding_radius() + and self.multiplicity() == other.multiplicity() + and self.list_size() == other.list_size() + and self.interpolation_algorithm() == other.interpolation_algorithm() + and self.rootfinding_algorithm() == other.rootfinding_algorithm() + ) def interpolation_algorithm(self): r""" diff --git a/src/sage/coding/self_dual_codes.py b/src/sage/coding/self_dual_codes.py index b367b6c0033..16b3179ee23 100644 --- a/src/sage/coding/self_dual_codes.py +++ b/src/sage/coding/self_dual_codes.py @@ -533,7 +533,19 @@ def self_dual_binary_codes(n): spectrum = [1, 0, 1, 0, 12, 0, 76, 0, 166, 0, 166, 0, 76, 0, 12, 0, 1, 0, 1] self_dual_codes_18_6 = {"order autgp": 147456, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "'Exceptional'. Unique codeword of smallest nonzero wt."} # [18,7] (equiv to H18 in [P]) - genmat = _MS(n)([[1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1], [0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1], [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1]]) + genmat = _MS(n)( + [ + [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0], + [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1], + [0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1], + [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0], + [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0], + [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1], + [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1], + ] + ) # G = PermutationGroup( [ "(9,10)(16,18)", "(9,16)(10,18)", "(8,9)(14,16)",\ # "(7,11)(12,17)", "(7,12)(11,17)", "(5,6)(11,12)", "(5,7)(6,17)",\ # "(4,13)(5,8)(6,14)(7,9)(10,12)(11,18)(16,17)", "(3,4)(13,15)",\ @@ -542,8 +554,32 @@ def self_dual_binary_codes(n): spectrum = [1, 0, 0, 0, 9, 0, 75, 0, 171, 0, 171, 0, 75, 0, 9, 0, 0, 0, 1] self_dual_codes_18_7 = {"order autgp": 82944, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "'Exceptional' construction. Min dist 4."} # [18, 8] (equiv to I18 in [P]) - I18 = _MS(n)([[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]) - genmat = _MS(n)([[1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1], [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1], [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0]]) + I18 = _MS(n)( + [ + [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], + [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + ] + ) + genmat = _MS(n)( + [ + [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1], + [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1], + [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1], + [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1], + [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1], + [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1], + [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1], + [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0], + ] + ) G = PermutationGroup(["(9,15)(16,17)", "(9,16)(15,17)", "(8,9)(17,18)", "(7,8)(16,17)", "(5,6)(10,13)", "(5,10)(6,13)", "(4,5)(13,14)", "(3,4)(12,14)", "(1,2)(6,10)", "(1,3)(2,12)"]) spectrum = [1, 0, 0, 0, 17, 0, 51, 0, 187, 0, 187, 0, 51, 0, 17, 0, 0, 0, 1] self_dual_codes_18_8 = {"order autgp": 322560, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "'Exceptional' construction. Min dist 4."} @@ -554,7 +590,20 @@ def self_dual_binary_codes(n): # all of these of these are Type I; 2 of these codes # are formally equivalent but with different automorphism groups; # one of these has a unique codeword of lowest weight - A10 = MatrixSpace(_F, 10, 10)([[1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [1, 1, 1, 0, 1, 0, 1, 0, 1, 1], [1, 0, 0, 1, 0, 1, 0, 1, 0, 1], [0, 0, 0, 1, 1, 1, 0, 1, 0, 1], [0, 0, 1, 1, 0, 1, 0, 1, 0, 1], [0, 0, 0, 1, 0, 1, 1, 1, 0, 1], [0, 1, 0, 1, 0, 1, 0, 1, 0, 1], [0, 0, 0, 1, 0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 1, 0, 0, 1, 1], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]]) + A10 = MatrixSpace(_F, 10, 10)( + [ + [1, 1, 1, 1, 1, 1, 1, 1, 1, 0], + [1, 1, 1, 0, 1, 0, 1, 0, 1, 1], + [1, 0, 0, 1, 0, 1, 0, 1, 0, 1], + [0, 0, 0, 1, 1, 1, 0, 1, 0, 1], + [0, 0, 1, 1, 0, 1, 0, 1, 0, 1], + [0, 0, 0, 1, 0, 1, 1, 1, 0, 1], + [0, 1, 0, 1, 0, 1, 0, 1, 0, 1], + [0, 0, 0, 1, 0, 0, 0, 0, 1, 1], + [0, 0, 0, 0, 0, 1, 0, 0, 1, 1], + [0, 0, 0, 0, 0, 0, 0, 1, 1, 1], + ] + ) # [20,0]: genmat = _I2(n).augment(_I2(n)) # G = PermutationGroup( ["(10,20)", "(9,10)(19,20)", "(8,9)(18,19)", "(7,8)(17,18)", "(6,7)(16,17)",\ @@ -618,8 +667,34 @@ def self_dual_binary_codes(n): self_dual_codes_20_7 = {"order autgp": 589824, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "'Exceptional' construction."} # [20,8]: (genmat, J20, and genmat2 are all equiv) genmat = _I2(n).augment(_matA(n)[10]) - J20 = _MS(n)([[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]]) - genmat2 = _MS(n)([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1]]) + J20 = _MS(n)( + [ + [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0], + ] + ) + genmat2 = _MS(n)( + [ + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1], + [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1], + ] + ) # G = PermutationGroup( [ "(9,10)(19,20)", "(9,19)(10,20)", "(8,9)(18,19)", "(7,8)(17,18)",\ # "(6,7)(16,17)", "(5,6)(15,16)", "(4,5)(14,15)", "(3,4)(13,14)",\ # "(2,3)(12,13)", "(1,2)(11,12)"] ) @@ -627,7 +702,20 @@ def self_dual_binary_codes(n): self_dual_codes_20_8 = {"order autgp": 1857945600, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Huge aut gp. Min dist 4."} # [20,9]: (genmat, K20 are equiv) genmat = _I2(n).augment(A10) - K20 = _MS(n)([[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0]]) + K20 = _MS(n)( + [ + [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0], + ] + ) # genmat = K20 # not in standard form # G = PermutationGroup( [ "(4,13)(5,15)", "(4,15)(5,13)", "(3,4,13)(5,11,15)", # "(3,4,6,11,15,17)(5,13)", "(3,5,17,4,12)(6,15,7,11,13)", @@ -638,7 +726,20 @@ def self_dual_binary_codes(n): spectrum = [1, 0, 0, 0, 21, 0, 48, 0, 234, 0, 416, 0, 234, 0, 48, 0, 21, 0, 0, 0, 1] self_dual_codes_20_9 = {"order autgp": 4423680, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Min dist 4."} # [20,10] - L20 = _MS(n)([[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], [0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0], [0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0]]) + L20 = _MS(n)( + [ + [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + [0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0], + [0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], + ] + ) genmat = L20 # not in standard form # G = PermutationGroup( [ "(17,18)(19,20)", "(17,19)(18,20)", "(15,16)(19,20)", # "(15,17)(16,18)", "(10,11)(12,13)", "(10,12)(11,13)", "(9,10)(13,14)", @@ -647,7 +748,20 @@ def self_dual_binary_codes(n): spectrum = [1, 0, 0, 0, 17, 0, 56, 0, 238, 0, 400, 0, 238, 0, 56, 0, 17, 0, 0, 0, 1] self_dual_codes_20_10 = {"order autgp": 1354752, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Min dist 4."} # [20,11] - S20 = _MS(n)([[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], [1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0]]) + S20 = _MS(n)( + [ + [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + [1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0], + [1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0], + [1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0], + ] + ) genmat = S20 # not in standard form # G = PermutationGroup( [ "(17,18)(19,20)", "(17,19)(18,20)", "(13,14)(15,16)", # "(13,15)(14,16)", "(11,12)(15,16)", "(11,13)(12,14)", "(9,10)(15,16)", @@ -657,7 +771,20 @@ def self_dual_binary_codes(n): spectrum = [1, 0, 0, 0, 13, 0, 64, 0, 242, 0, 384, 0, 242, 0, 64, 0, 13, 0, 0, 0, 1] self_dual_codes_20_11 = {"order autgp": 294912, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Min dist 4."} # [20,12] - R20 = _MS(n)([[0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], [0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0], [1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1], [1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1]]) + R20 = _MS(n)( + [ + [0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + [0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0], + [1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0], + [1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1], + [1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1], + ] + ) genmat = R20 # not in standard form # G = PermutationGroup( [ "(17,18)(19,20)", "(17,19)(18,20)", "(15,16)(19,20)", # "(15,17)(16,18)", "(11,12)(13,14)", "(11,13)(12,14)", "(9,10)(13,14)", @@ -667,7 +794,20 @@ def self_dual_binary_codes(n): spectrum = [1, 0, 0, 0, 9, 0, 72, 0, 246, 0, 368, 0, 246, 0, 72, 0, 9, 0, 0, 0, 1] self_dual_codes_20_12 = {"order autgp": 82944, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "Min dist 4."} # [20,13] - M20 = _MS(n)([[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0], [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0], [0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1], [0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0]]) + M20 = _MS(n)( + [ + [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1], + [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0], + [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0], + [0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1], + [0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0], + ] + ) genmat = M20 # not in standard form # G = PermutationGroup( [ "(17,18)(19,20)", "(17,19)(18,20)", "(13,14)(15,16)", # "(13,15)(14,16)", "(9,10)(11,12)", "(9,11)(10,12)", "(5,6)(7,8)", @@ -717,7 +857,24 @@ def self_dual_binary_codes(n): # "(1,5)(2,6)(3,7)(4,12)(11,19)(13,14)(16,18)" ] ) # order 165888 spectrum = [1, 0, 1, 0, 9, 0, 84, 0, 246, 0, 342, 0, 246, 0, 84, 0, 9, 0, 1, 0, 1] self_dual_codes_20_15 = {"order autgp": 165888, "code": LinearCode(genmat), "spectrum": spectrum, "Type": "I", "Comment": "'Exceptional' construction. Unique lowest wt codeword."} - self_dual_codes["20"] = {"0": self_dual_codes_20_0, "1": self_dual_codes_20_1, "2": self_dual_codes_20_2, "3": self_dual_codes_20_3, "4": self_dual_codes_20_4, "5": self_dual_codes_20_5, "6": self_dual_codes_20_6, "7": self_dual_codes_20_7, "8": self_dual_codes_20_8, "9": self_dual_codes_20_9, "10": self_dual_codes_20_10, "11": self_dual_codes_20_11, "12": self_dual_codes_20_12, "13": self_dual_codes_20_13, "14": self_dual_codes_20_14, "15": self_dual_codes_20_15} + self_dual_codes["20"] = { + "0": self_dual_codes_20_0, + "1": self_dual_codes_20_1, + "2": self_dual_codes_20_2, + "3": self_dual_codes_20_3, + "4": self_dual_codes_20_4, + "5": self_dual_codes_20_5, + "6": self_dual_codes_20_6, + "7": self_dual_codes_20_7, + "8": self_dual_codes_20_8, + "9": self_dual_codes_20_9, + "10": self_dual_codes_20_10, + "11": self_dual_codes_20_11, + "12": self_dual_codes_20_12, + "13": self_dual_codes_20_13, + "14": self_dual_codes_20_14, + "15": self_dual_codes_20_15, + } return self_dual_codes if n == 22: diff --git a/src/sage/coding/two_weight_db.py b/src/sage/coding/two_weight_db.py index cafc022964e..efce9d27a78 100644 --- a/src/sage/coding/two_weight_db.py +++ b/src/sage/coding/two_weight_db.py @@ -43,7 +43,16 @@ 'w1': 32, 'w2': 40, 'K': GF(2), - 'M': ("10000000100111100110000001101000100111000011100101011010111111010110", "01000000010011110011000000110100010011100001110010101101011111101011", "00100000001001111101100000011010001001110000111001010110101111110101", "00010000100011011100110001100101100011111011111001100001101000101100", "00001000110110001100011001011010011110111110011001111010001011000000", "00000100111100100000001101000101101000011100101001110111111010110110", "00000010011110010000000110100010111100001110010100101011111101011011", "00000001001111001100000011010001011110000111001010010101111110101101"), + 'M': ( + "10000000100111100110000001101000100111000011100101011010111111010110", + "01000000010011110011000000110100010011100001110010101101011111101011", + "00100000001001111101100000011010001001110000111001010110101111110101", + "00010000100011011100110001100101100011111011111001100001101000101100", + "00001000110110001100011001011010011110111110011001111010001011000000", + "00000100111100100000001101000101101000011100101001110111111010110110", + "00000010011110010000000110100010111100001110010100101011111101011011", + "00000001001111001100000011010001011110000111001010010101111110101101", + ), 'source': "Shared by Eric Chen [ChenDB]_.", }, { @@ -52,7 +61,14 @@ 'w1': 90, 'w2': 99, 'K': GF(3), - 'M': ("10111011111111101110101110111100111011111011101111101001001111011011011111100100111101000111101111101100011011001111101110111110101111111001", "01220121111211011101011101112101220022120121011222010110011010120110112112001101021010101111012211011000020110012221212101011101211122020011", "22102021112110111120211021122012100012202220112110101200110101202102122120011110020201211110021210110000101200121222122010211022211210110101", "11010221121101111102210221220221000111011101121102012101101012012022222000211200202012211100111201200001122001211011120102110212212102121001", "20201121211111111012202022201210001220122121211010121011010020110121220201212002010222011001111012100011010212110021202021102112221012110011", "02022222111111110112020112011200022102212222110102210110100101102211201211220020002120110011110221100110002121100222120211021112010112220101"), + 'M': ( + "10111011111111101110101110111100111011111011101111101001001111011011011111100100111101000111101111101100011011001111101110111110101111111001", + "01220121111211011101011101112101220022120121011222010110011010120110112112001101021010101111012211011000020110012221212101011101211122020011", + "22102021112110111120211021122012100012202220112110101200110101202102122120011110020201211110021210110000101200121222122010211022211210110101", + "11010221121101111102210221220221000111011101121102012101101012012022222000211200202012211100111201200001122001211011120102110212212102121001", + "20201121211111111012202022201210001220122121211010121011010020110121220201212002010222011001111012100011010212110021202021102112221012110011", + "02022222111111110112020112011200022102212222110102210110100101102211201211220020002120110011110221100110002121100222120211021112010112220101", + ), 'source': "Found by Axel Kohnert [Koh2007]_ and shared by Alfred Wassermann.", }, { @@ -61,7 +77,14 @@ 'w1': 63, 'w2': 72, 'K': GF(3), - 'M': ("10000021022112121121110122000110112002010011100120022110120200120111220220122120012012100201110210", "01000020121020200200211101202121120002211002210100021021202220112122012212101102010210010221221201", "00100021001211011111111202120022221002201111021101021212210122101020121111002000210000101222202000", "00010022122200222202201212211112001102200112202202121201211212010210202001222120000002110021000110", "00001021201002010011020210221221012112200012020011201200111021021102212120211102012002011201210221", "00000120112212122122202110022202210010200022002120112200101002202221111102110100210212001022201202"), + 'M': ( + "10000021022112121121110122000110112002010011100120022110120200120111220220122120012012100201110210", + "01000020121020200200211101202121120002211002210100021021202220112122012212101102010210010221221201", + "00100021001211011111111202120022221002201111021101021212210122101020121111002000210000101222202000", + "00010022122200222202201212211112001102200112202202121201211212010210202001222120000002110021000110", + "00001021201002010011020210221221012112200012020011201200111021021102212120211102012002011201210221", + "00000120112212122122202110022202210010200022002120112200101002202221111102110100210212001022201202", + ), 'source': "Shared by Eric Chen [ChenDB]_.", }, { @@ -70,7 +93,14 @@ 'w1': 54, 'w2': 63, 'K': GF(3), - 'M': ("100000210221121211211212100002020022102220010202100220112211111022012202220001210020", "010000201210202002002200010022222022012112111222010212120102222221210102112001001022", "001000210012110111111202101021212221000101021021021211021221000111100202101200010122", "000100221222002222022202010121111210202200012001222011212000211200122202100120211002", "000010212010020100110002001011101112122110211102212121200111102212021122100010201120", "000001201122121221222212000110100102011101201012001102201222221110211011100001200102"), + 'M': ( + "100000210221121211211212100002020022102220010202100220112211111022012202220001210020", + "010000201210202002002200010022222022012112111222010212120102222221210102112001001022", + "001000210012110111111202101021212221000101021021021211021221000111100202101200010122", + "000100221222002222022202010121111210202200012001222011212000211200122202100120211002", + "000010212010020100110002001011101112122110211102212121200111102212021122100010201120", + "000001201122121221222212000110100102011101201012001102201222221110211011100001200102", + ), 'source': "Shared by Eric Chen [ChenDB]_.", }, { @@ -79,7 +109,14 @@ 'w1': 36, 'w2': 45, 'K': GF(3), - 'M': ("10000021022112022210202200202122221120200112100200111102", "01000020121020221101202120220001110202220110010222122212", "00100021001211211020022112222122002210122100101222020020", "00010022122200010012221111121001121211212002110020010101", "00001021201002220211121011010222000111021002011201112112", "00000120112212111201011001002111121101002212001022222010"), + 'M': ( + "10000021022112022210202200202122221120200112100200111102", + "01000020121020221101202120220001110202220110010222122212", + "00100021001211211020022112222122002210122100101222020020", + "00010022122200010012221111121001121211212002110020010101", + "00001021201002220211121011010222000111021002011201112112", + "00000120112212111201011001002111121101002212001022222010", + ), 'source': "Shared by Eric Chen [ChenDB]_.", }, { @@ -124,7 +161,14 @@ 'w1': 81, 'w2': 90, 'K': GF(3), - 'M': ("100000210221121211211101220021210000100011020200201101121021122102020111100122122221120200110001010222000021110110011211110210", "010000201210202002002111012020001001110012222220221211200120201212222102210100001110202220121001110211200120221121012001221201", "001000210012110111111112021220210102211012212122200222212000112220212011021102122002210122122101120210120100102212112112202000", "000100221222002222022012122120201012021112211112111120010221100121011012202201001121211212002211120210012201120021222121000110", "000010212010020100110202102200200102002122111011112210121010202111121212020010222000111021000222122210001011222102100121210221", "000001201122121221222021100221200012000220101001022022100122112010102222002122111121101002200020221110000122202000221222201202"), + 'M': ( + "100000210221121211211101220021210000100011020200201101121021122102020111100122122221120200110001010222000021110110011211110210", + "010000201210202002002111012020001001110012222220221211200120201212222102210100001110202220121001110211200120221121012001221201", + "001000210012110111111112021220210102211012212122200222212000112220212011021102122002210122122101120210120100102212112112202000", + "000100221222002222022012122120201012021112211112111120010221100121011012202201001121211212002211120210012201120021222121000110", + "000010212010020100110202102200200102002122111011112210121010202111121212020010222000111021000222122210001011222102100121210221", + "000001201122121221222021100221200012000220101001022022100122112010102222002122111121101002200020221110000122202000221222201202", + ), 'source': "Shared by Eric Chen [ChenDB]_.", }, { @@ -133,7 +177,14 @@ 'w1': 99, 'w2': 108, 'K': GF(3), - 'M': ("10000021022112121121110122002121000010001102020020110112102112202221021020201" + "20202212102220222022222110122210022201211222111110211101121002011102101111002", "01000020121020200200211101202000100111001222222022121120012020122110122122221" + "02222102012112111221111021101101021121002001022221202211100102212212010222102", "00100021001211011111111202122021010221101221212220022221200011221102002202120" + "20121121000101000111020212200020121210011112210001001022001012222020000100212", "00010022122200222202201212212020101202111221111211112001022110001001221210110" + "12211020202200222000021101010212001022212020002112011200021100210001100121020", "00001021201002010011020210220020010200212211101111221012101020222021111111212" + "11120012122110211222201220220201222200102101111020112221020112012102211120101", "00000120112212122122202110022120001200022010100102202210012211211120100101022" + "01011212011101110111112202111200111021221112222211222020120010222012022220012"), + 'M': ( + "10000021022112121121110122002121000010001102020020110112102112202221021020201" + "20202212102220222022222110122210022201211222111110211101121002011102101111002", + "01000020121020200200211101202000100111001222222022121120012020122110122122221" + "02222102012112111221111021101101021121002001022221202211100102212212010222102", + "00100021001211011111111202122021010221101221212220022221200011221102002202120" + "20121121000101000111020212200020121210011112210001001022001012222020000100212", + "00010022122200222202201212212020101202111221111211112001022110001001221210110" + "12211020202200222000021101010212001022212020002112011200021100210001100121020", + "00001021201002010011020210220020010200212211101111221012101020222021111111212" + "11120012122110211222201220220201222200102101111020112221020112012102211120101", + "00000120112212122122202110022120001200022010100102202210012211211120100101022" + "01011212011101110111112202111200111021221112222211222020120010222012022220012", + ), 'source': "Shared by Eric Chen [ChenDB]_.", }, { @@ -181,7 +232,17 @@ 'w1': 32, 'w2': 40, 'K': GF(2), - 'M': ("1010010100000010100000101010001100110101101101000010110010100100111011101", "0110000110000101101111001101000100111111101011011101110010110001100111100", "0001010000000001111111011010100101001111011010101100001010000001110100001", "0000100100000001111111100111000011110011110101000001010110000001011010001", "0000001010000001111110111100011000111100101110010010101100000001101001001", "0000000001000111001010110010011001101001011010110110011001010111100010010", "0000000000100100011000100100111100001100101111010001011011111000110011110", "0000000000010111001100101011111110101010000000000100111110000001111111100", "0000000000001011100001000011011010110001110101101100001100101110101110110"), + 'M': ( + "1010010100000010100000101010001100110101101101000010110010100100111011101", + "0110000110000101101111001101000100111111101011011101110010110001100111100", + "0001010000000001111111011010100101001111011010101100001010000001110100001", + "0000100100000001111111100111000011110011110101000001010110000001011010001", + "0000001010000001111110111100011000111100101110010010101100000001101001001", + "0000000001000111001010110010011001101001011010110110011001010111100010010", + "0000000000100100011000100100111100001100101111010001011011111000110011110", + "0000000000010111001100101011111110101010000000000100111110000001111111100", + "0000000000001011100001000011011010110001110101101100001100101110101110110", + ), 'source': "Shared by Eric Chen [ChenDB]_.", }, { @@ -190,7 +251,17 @@ 'w1': 32, 'w2': 40, 'K': GF(2), - 'M': ("0100011110111000001011010110110111100010001000001000001001010110101101", "1000111101110000000110101111101111000100010000010000000010101111001011", "0001111011100000011101011101011110011000100000100000000101011100010111", "0011110101000000111010111010111100110001000011000000001010111000101101", "0111101000000001110101110111111001100010000100000000010101110011001011", "1111010000000011101011101101110011010100001000000000101011100100010111", "1110100010000111000111011011100110111000010000000001000111001010101101", "1101000110001110001110110101001101110000100010000010001110010101001011", "1010001110011100001101101010011011110001000100000100001100101010010111"), + 'M': ( + "0100011110111000001011010110110111100010001000001000001001010110101101", + "1000111101110000000110101111101111000100010000010000000010101111001011", + "0001111011100000011101011101011110011000100000100000000101011100010111", + "0011110101000000111010111010111100110001000011000000001010111000101101", + "0111101000000001110101110111111001100010000100000000010101110011001011", + "1111010000000011101011101101110011010100001000000000101011100100010111", + "1110100010000111000111011011100110111000010000000001000111001010101101", + "1101000110001110001110110101001101110000100010000010001110010101001011", + "1010001110011100001101101010011011110001000100000100001100101010010111", + ), 'source': "Found by Axel Kohnert [Koh2007]_ and shared by Alfred Wassermann.", }, { @@ -199,7 +270,16 @@ 'w1': 40, 'w2': 48, 'K': GF(2), - 'M': ("1000000010011101010001000011100111000111111010110001101101000110010011001101011100001", "0100000011010011111001100010010100100100000111101001011011100101011010101011110010001", "0010000011110100101101110010101101010101111001000101000000110100111110011000100101001", "0001000011100111000111111010110001101101000110010011001101011100001100000001001110101", "0000100011101110110010111110111111110001011001111000001011101000010101001101111011011", "0000010011101010001000011100111000111111010110001101101000110010011001101011100001100", "0000001001110101000100001110011100011111101011000110110100011001001100110101110000110", "0000000100111010100010000111001110001111110101100011011010001100100110011010111000011"), + 'M': ( + "1000000010011101010001000011100111000111111010110001101101000110010011001101011100001", + "0100000011010011111001100010010100100100000111101001011011100101011010101011110010001", + "0010000011110100101101110010101101010101111001000101000000110100111110011000100101001", + "0001000011100111000111111010110001101101000110010011001101011100001100000001001110101", + "0000100011101110110010111110111111110001011001111000001011101000010101001101111011011", + "0000010011101010001000011100111000111111010110001101101000110010011001101011100001100", + "0000001001110101000100001110011100011111101011000110110100011001001100110101110000110", + "0000000100111010100010000111001110001111110101100011011010001100100110011010111000011", + ), 'source': "Shared by Eric Chen [ChenDB]_.", }, { @@ -217,7 +297,12 @@ 'w1': 24, 'w2': 28, 'K': GF(4, name='x'), - 'M': [[1, 0, 0, 0, 1, 'x', 'x', 'x^2', 1, 0, 'x', 'x', 0, 1, 'x^2', 'x', 'x', 'x^2', 'x^2', 'x^2', 'x', 'x', 'x^2', 'x^2', 'x^2', 1, 'x^2', 'x', 1, 0, 1, 'x', 'x^2', 1], [0, 1, 0, 0, 'x', 'x', 1, 'x^2', 1, 1, 'x^2', 1, 'x', 'x', 0, 0, 1, 0, 'x', 'x', 0, 1, 'x^2', 'x', 'x', 1, 0, 0, 0, 1, 'x', 'x', 'x^2', 1], [0, 0, 1, 0, 1, 0, 0, 'x', 'x', 1, 'x^2', 1, 1, 'x^2', 1, 'x', 'x', 'x', 'x^2', 1, 0, 'x', 'x', 0, 1, 'x^2', 'x', 'x', 1, 0, 0, 0, 1, 'x'], [0, 0, 0, 1, 'x', 'x', 'x^2', 1, 0, 'x', 'x', 0, 1, 'x^2', 'x', 'x', 1, 'x^2', 'x^2', 'x', 'x', 'x^2', 'x^2', 'x^2', 1, 'x^2', 'x', 1, 0, 1, 'x', 'x^2', 1, 'x^2']], + 'M': [ + [1, 0, 0, 0, 1, 'x', 'x', 'x^2', 1, 0, 'x', 'x', 0, 1, 'x^2', 'x', 'x', 'x^2', 'x^2', 'x^2', 'x', 'x', 'x^2', 'x^2', 'x^2', 1, 'x^2', 'x', 1, 0, 1, 'x', 'x^2', 1], + [0, 1, 0, 0, 'x', 'x', 1, 'x^2', 1, 1, 'x^2', 1, 'x', 'x', 0, 0, 1, 0, 'x', 'x', 0, 1, 'x^2', 'x', 'x', 1, 0, 0, 0, 1, 'x', 'x', 'x^2', 1], + [0, 0, 1, 0, 1, 0, 0, 'x', 'x', 1, 'x^2', 1, 1, 'x^2', 1, 'x', 'x', 'x', 'x^2', 1, 0, 'x', 'x', 0, 1, 'x^2', 'x', 'x', 1, 0, 0, 0, 1, 'x'], + [0, 0, 0, 1, 'x', 'x', 'x^2', 1, 0, 'x', 'x', 0, 1, 'x^2', 'x', 'x', 1, 'x^2', 'x^2', 'x', 'x', 'x^2', 'x^2', 'x^2', 1, 'x^2', 'x', 1, 0, 1, 'x', 'x^2', 1, 'x^2'], + ], 'source': "Shared by Eric Chen [ChenDB]_.", }, { diff --git a/src/sage/combinat/all.py b/src/sage/combinat/all.py index d2c64a36221..b33123e4054 100644 --- a/src/sage/combinat/all.py +++ b/src/sage/combinat/all.py @@ -53,7 +53,26 @@ from sage.misc.lazy_import import lazy_import -from sage.combinat.combinat import CombinatorialObject, bell_number, bell_polynomial, bernoulli_polynomial, catalan_number, euler_number, fibonacci, fibonacci_sequence, fibonacci_xrange, lucas_number1, lucas_number2, number_of_tuples, number_of_unordered_tuples, polygonal_number, stirling_number1, stirling_number2, tuples, unordered_tuples +from sage.combinat.combinat import ( + CombinatorialObject, + bell_number, + bell_polynomial, + bernoulli_polynomial, + catalan_number, + euler_number, + fibonacci, + fibonacci_sequence, + fibonacci_xrange, + lucas_number1, + lucas_number2, + number_of_tuples, + number_of_unordered_tuples, + polygonal_number, + stirling_number1, + stirling_number2, + tuples, + unordered_tuples, +) from sage.combinat.expnums import expnums diff --git a/src/sage/combinat/crystals/alcove_path.py b/src/sage/combinat/crystals/alcove_path.py index 1e7a0c4a6ea..38035463dad 100644 --- a/src/sage/combinat/crystals/alcove_path.py +++ b/src/sage/combinat/crystals/alcove_path.py @@ -1743,7 +1743,23 @@ def _test_some_specific_examples(clss=CrystalOfAlcovePaths): C = clss(['G', 2], [0, 1]) G = C.digraph() - GT = DiGraph({(): {(0): 2}, (0): {(0, 8): 1}, (0, 1): {(0, 1, 7): 2}, (0, 1, 2): {(0, 1, 2, 9): 1}, (0, 1, 2, 3): {(0, 1, 2, 3, 4): 2}, (0, 1, 2, 6): {(0, 1, 2, 3): 1}, (0, 1, 2, 9): {(0, 1, 2, 6): 1}, (0, 1, 7): {(0, 1, 2): 2}, (0, 1, 7, 9): {(0, 1, 2, 9): 2}, (0, 5): {(0, 1): 1, (0, 5, 7): 2}, (0, 5, 7): {(0, 5, 7, 9): 1}, (0, 5, 7, 9): {(0, 1, 7, 9): 1}, (0, 8): {(0, 5): 1}}) + GT = DiGraph( + { + (): {(0): 2}, + (0): {(0, 8): 1}, + (0, 1): {(0, 1, 7): 2}, + (0, 1, 2): {(0, 1, 2, 9): 1}, + (0, 1, 2, 3): {(0, 1, 2, 3, 4): 2}, + (0, 1, 2, 6): {(0, 1, 2, 3): 1}, + (0, 1, 2, 9): {(0, 1, 2, 6): 1}, + (0, 1, 7): {(0, 1, 2): 2}, + (0, 1, 7, 9): {(0, 1, 2, 9): 2}, + (0, 5): {(0, 1): 1, (0, 5, 7): 2}, + (0, 5, 7): {(0, 5, 7, 9): 1}, + (0, 5, 7, 9): {(0, 1, 7, 9): 1}, + (0, 8): {(0, 5): 1}, + } + ) if not G.is_isomorphic(GT): return False @@ -1754,7 +1770,23 @@ def _test_some_specific_examples(clss=CrystalOfAlcovePaths): # type C, ex. 8.3.5, pg. 189 C = clss(['C', 3], [0, 0, 1]) G = C.digraph() - GT = DiGraph({(): {(0): 3}, (0): {(0, 6): 2}, (0, 1): {(0, 1, 3): 3, (0, 1, 7): 1}, (0, 1, 2): {(0, 1, 2, 3): 3}, (0, 1, 2, 3): {(0, 1, 2, 3, 8): 2}, (0, 1, 2, 3, 4): {(0, 1, 2, 3, 4, 5): 3}, (0, 1, 2, 3, 8): {(0, 1, 2, 3, 4): 2}, (0, 1, 3): {(0, 1, 3, 7): 1}, (0, 1, 3, 7): {(0, 1, 2, 3): 1, (0, 1, 3, 7, 8): 2}, (0, 1, 3, 7, 8): {(0, 1, 2, 3, 8): 1}, (0, 1, 7): {(0, 1, 2): 1, (0, 1, 3, 7): 3}, (0, 6): {(0, 1): 2, (0, 6, 7): 1}, (0, 6, 7): {(0, 1, 7): 2}}) + GT = DiGraph( + { + (): {(0): 3}, + (0): {(0, 6): 2}, + (0, 1): {(0, 1, 3): 3, (0, 1, 7): 1}, + (0, 1, 2): {(0, 1, 2, 3): 3}, + (0, 1, 2, 3): {(0, 1, 2, 3, 8): 2}, + (0, 1, 2, 3, 4): {(0, 1, 2, 3, 4, 5): 3}, + (0, 1, 2, 3, 8): {(0, 1, 2, 3, 4): 2}, + (0, 1, 3): {(0, 1, 3, 7): 1}, + (0, 1, 3, 7): {(0, 1, 2, 3): 1, (0, 1, 3, 7, 8): 2}, + (0, 1, 3, 7, 8): {(0, 1, 2, 3, 8): 1}, + (0, 1, 7): {(0, 1, 2): 1, (0, 1, 3, 7): 3}, + (0, 6): {(0, 1): 2, (0, 6, 7): 1}, + (0, 6, 7): {(0, 1, 7): 2}, + } + ) if not G.is_isomorphic(GT): return False @@ -1764,7 +1796,36 @@ def _test_some_specific_examples(clss=CrystalOfAlcovePaths): C = clss(['B', 3], [2, 0, 0]) G = C.digraph() - GT = DiGraph({(): {(6): 1}, (0): {(0, 7): 2}, (0, 1): {(0, 1, 11): 3}, (0, 1, 2): {(0, 1, 2, 9): 2}, (0, 1, 2, 3): {(0, 1, 2, 3, 10): 1}, (0, 1, 2, 3, 10): {(0, 1, 2, 3, 4): 1}, (0, 1, 2, 9): {(0, 1, 2, 3): 2, (0, 1, 2, 9, 10): 1}, (0, 1, 2, 9, 10): {(0, 1, 2, 3, 10): 2}, (0, 1, 5): {(0, 1, 2): 3, (0, 1, 5, 9): 2}, (0, 1, 5, 9): {(0, 1, 2, 9): 3, (0, 1, 5, 9, 10): 1}, (0, 1, 5, 9, 10): {(0, 1, 2, 9, 10): 3}, (0, 1, 8): {(0, 1, 5): 3}, (0, 1, 8, 9): {(0, 1, 5, 9): 3, (0, 1, 8, 9, 10): 1}, (0, 1, 8, 9, 10): {(0, 1, 5, 9, 10): 3}, (0, 1, 11): {(0, 1, 8): 3}, (0, 7): {(0, 1): 2, (0, 7, 11): 3}, (0, 7, 8): {(0, 7, 8, 9): 2}, (0, 7, 8, 9): {(0, 1, 8, 9): 2}, (0, 7, 8, 9, 10): {(0, 1, 8, 9, 10): 2}, (0, 7, 11): {(0, 1, 11): 2, (0, 7, 8): 3}, (6): {(0): 1, (6, 7): 2}, (6, 7): {(0, 7): 1, (6, 7, 11): 3}, (6, 7, 8): {(0, 7, 8): 1, (6, 7, 8, 9): 2}, (6, 7, 8, 9): {(6, 7, 8, 9, 10): 1}, (6, 7, 8, 9, 10): {(0, 7, 8, 9, 10): 1}, (6, 7, 11): {(0, 7, 11): 1, (6, 7, 8): 3}}) + GT = DiGraph( + { + (): {(6): 1}, + (0): {(0, 7): 2}, + (0, 1): {(0, 1, 11): 3}, + (0, 1, 2): {(0, 1, 2, 9): 2}, + (0, 1, 2, 3): {(0, 1, 2, 3, 10): 1}, + (0, 1, 2, 3, 10): {(0, 1, 2, 3, 4): 1}, + (0, 1, 2, 9): {(0, 1, 2, 3): 2, (0, 1, 2, 9, 10): 1}, + (0, 1, 2, 9, 10): {(0, 1, 2, 3, 10): 2}, + (0, 1, 5): {(0, 1, 2): 3, (0, 1, 5, 9): 2}, + (0, 1, 5, 9): {(0, 1, 2, 9): 3, (0, 1, 5, 9, 10): 1}, + (0, 1, 5, 9, 10): {(0, 1, 2, 9, 10): 3}, + (0, 1, 8): {(0, 1, 5): 3}, + (0, 1, 8, 9): {(0, 1, 5, 9): 3, (0, 1, 8, 9, 10): 1}, + (0, 1, 8, 9, 10): {(0, 1, 5, 9, 10): 3}, + (0, 1, 11): {(0, 1, 8): 3}, + (0, 7): {(0, 1): 2, (0, 7, 11): 3}, + (0, 7, 8): {(0, 7, 8, 9): 2}, + (0, 7, 8, 9): {(0, 1, 8, 9): 2}, + (0, 7, 8, 9, 10): {(0, 1, 8, 9, 10): 2}, + (0, 7, 11): {(0, 1, 11): 2, (0, 7, 8): 3}, + (6): {(0): 1, (6, 7): 2}, + (6, 7): {(0, 7): 1, (6, 7, 11): 3}, + (6, 7, 8): {(0, 7, 8): 1, (6, 7, 8, 9): 2}, + (6, 7, 8, 9): {(6, 7, 8, 9, 10): 1}, + (6, 7, 8, 9, 10): {(0, 7, 8, 9, 10): 1}, + (6, 7, 11): {(0, 7, 11): 1, (6, 7, 8): 3}, + } + ) if not G.is_isomorphic(GT): return False @@ -1773,7 +1834,30 @@ def _test_some_specific_examples(clss=CrystalOfAlcovePaths): C = clss(['B', 3], [0, 1, 0]) G = C.digraph() - GT = DiGraph({(): {(0): 2}, (0): {(0, 1): 1, (0, 7): 3}, (0, 1): {(0, 1, 7): 3}, (0, 1, 2): {(0, 1, 2, 8): 2}, (0, 1, 2, 3): {(0, 1, 2, 3, 5): 1, (0, 1, 2, 3, 9): 3}, (0, 1, 2, 3, 4): {(0, 1, 2, 3, 4, 5): 1}, (0, 1, 2, 3, 4, 5): {(0, 1, 2, 3, 4, 5, 6): 2}, (0, 1, 2, 3, 5): {(0, 1, 2, 3, 5, 9): 3}, (0, 1, 2, 3, 5, 9): {(0, 1, 2, 3, 4, 5): 3}, (0, 1, 2, 3, 9): {(0, 1, 2, 3, 4): 3, (0, 1, 2, 3, 5, 9): 1}, (0, 1, 2, 5): {(0, 1, 2, 3, 5): 2}, (0, 1, 2, 8): {(0, 1, 2, 3): 2}, (0, 1, 2, 8, 9): {(0, 1, 2, 3, 9): 2}, (0, 1, 7): {(0, 1, 2): 3, (0, 1, 7, 8): 2}, (0, 1, 7, 8): {(0, 1, 7, 8, 9): 3}, (0, 1, 7, 8, 9): {(0, 1, 2, 8, 9): 3}, (0, 2): {(0, 1, 2): 1, (0, 2, 5): 2}, (0, 2, 5): {(0, 2, 5, 8): 1}, (0, 2, 5, 8): {(0, 1, 2, 5): 1}, (0, 7): {(0, 1, 7): 1, (0, 2): 3}}) + GT = DiGraph( + { + (): {(0): 2}, + (0): {(0, 1): 1, (0, 7): 3}, + (0, 1): {(0, 1, 7): 3}, + (0, 1, 2): {(0, 1, 2, 8): 2}, + (0, 1, 2, 3): {(0, 1, 2, 3, 5): 1, (0, 1, 2, 3, 9): 3}, + (0, 1, 2, 3, 4): {(0, 1, 2, 3, 4, 5): 1}, + (0, 1, 2, 3, 4, 5): {(0, 1, 2, 3, 4, 5, 6): 2}, + (0, 1, 2, 3, 5): {(0, 1, 2, 3, 5, 9): 3}, + (0, 1, 2, 3, 5, 9): {(0, 1, 2, 3, 4, 5): 3}, + (0, 1, 2, 3, 9): {(0, 1, 2, 3, 4): 3, (0, 1, 2, 3, 5, 9): 1}, + (0, 1, 2, 5): {(0, 1, 2, 3, 5): 2}, + (0, 1, 2, 8): {(0, 1, 2, 3): 2}, + (0, 1, 2, 8, 9): {(0, 1, 2, 3, 9): 2}, + (0, 1, 7): {(0, 1, 2): 3, (0, 1, 7, 8): 2}, + (0, 1, 7, 8): {(0, 1, 7, 8, 9): 3}, + (0, 1, 7, 8, 9): {(0, 1, 2, 8, 9): 3}, + (0, 2): {(0, 1, 2): 1, (0, 2, 5): 2}, + (0, 2, 5): {(0, 2, 5, 8): 1}, + (0, 2, 5, 8): {(0, 1, 2, 5): 1}, + (0, 7): {(0, 1, 7): 1, (0, 2): 3}, + } + ) if not G.is_isomorphic(GT): return False diff --git a/src/sage/combinat/crystals/highest_weight_crystals.py b/src/sage/combinat/crystals/highest_weight_crystals.py index 9a9ea3d2877..756f113a963 100644 --- a/src/sage/combinat/crystals/highest_weight_crystals.py +++ b/src/sage/combinat/crystals/highest_weight_crystals.py @@ -376,7 +376,14 @@ def __init__(self, dominant_weight): """ B1 = CrystalOfLetters(['E', 6]) B6 = CrystalOfLetters(['E', 6], dual=True) - self.column_crystal = {1: B1, 6: B6, 4: TensorProductOfCrystals(B1, B1, B1, generators=[[B1([-3, 4]), B1([-1, 3]), B1([1])]]), 3: TensorProductOfCrystals(B1, B1, generators=[[B1([-1, 3]), B1([1])]]), 5: TensorProductOfCrystals(B6, B6, generators=[[B6([5, -6]), B6([6])]]), 2: TensorProductOfCrystals(B6, B1, generators=[[B6([2, -1]), B1([1])]])} + self.column_crystal = { + 1: B1, + 6: B6, + 4: TensorProductOfCrystals(B1, B1, B1, generators=[[B1([-3, 4]), B1([-1, 3]), B1([1])]]), + 3: TensorProductOfCrystals(B1, B1, generators=[[B1([-1, 3]), B1([1])]]), + 5: TensorProductOfCrystals(B6, B6, generators=[[B6([5, -6]), B6([6])]]), + 2: TensorProductOfCrystals(B6, B1, generators=[[B6([2, -1]), B1([1])]]), + } FiniteDimensionalHighestWeightCrystal_TypeE.__init__(self, dominant_weight) @@ -419,5 +426,13 @@ def __init__(self, dominant_weight): 7371 """ B = CrystalOfLetters(['E', 7]) - self.column_crystal = {7: B, 1: TensorProductOfCrystals(B, B, generators=[[B([-7, 1]), B([7])]]), 2: TensorProductOfCrystals(B, B, B, generators=[[B([-1, 2]), B([-7, 1]), B([7])]]), 3: TensorProductOfCrystals(B, B, B, B, generators=[[B([-2, 3]), B([-1, 2]), B([-7, 1]), B([7])]]), 4: TensorProductOfCrystals(B, B, B, B, generators=[[B([-5, 4]), B([-6, 5]), B([-7, 6]), B([7])]]), 5: TensorProductOfCrystals(B, B, B, generators=[[B([-6, 5]), B([-7, 6]), B([7])]]), 6: TensorProductOfCrystals(B, B, generators=[[B([-7, 6]), B([7])]])} + self.column_crystal = { + 7: B, + 1: TensorProductOfCrystals(B, B, generators=[[B([-7, 1]), B([7])]]), + 2: TensorProductOfCrystals(B, B, B, generators=[[B([-1, 2]), B([-7, 1]), B([7])]]), + 3: TensorProductOfCrystals(B, B, B, B, generators=[[B([-2, 3]), B([-1, 2]), B([-7, 1]), B([7])]]), + 4: TensorProductOfCrystals(B, B, B, B, generators=[[B([-5, 4]), B([-6, 5]), B([-7, 6]), B([7])]]), + 5: TensorProductOfCrystals(B, B, B, generators=[[B([-6, 5]), B([-7, 6]), B([7])]]), + 6: TensorProductOfCrystals(B, B, generators=[[B([-7, 6]), B([7])]]), + } FiniteDimensionalHighestWeightCrystal_TypeE.__init__(self, dominant_weight) diff --git a/src/sage/combinat/crystals/tensor_product.py b/src/sage/combinat/crystals/tensor_product.py index 055b0dccb0f..df023c55eb8 100644 --- a/src/sage/combinat/crystals/tensor_product.py +++ b/src/sage/combinat/crystals/tensor_product.py @@ -447,7 +447,9 @@ class options(GlobalOptions): NAME = 'TensorProductOfCrystals' module = 'sage.combinat.crystals' - convention = dict(default='antiKashiwara', description='Sets the convention used for displaying/inputting tensor product of crystals', values=dict(antiKashiwara='use the anti-Kashiwara convention', Kashiwara='use the Kashiwara convention'), alias=dict(anti='antiKashiwara', opposite='antiKashiwara'), case_sensitive=False) + convention = dict( + default='antiKashiwara', description='Sets the convention used for displaying/inputting tensor product of crystals', values=dict(antiKashiwara='use the anti-Kashiwara convention', Kashiwara='use the Kashiwara convention'), alias=dict(anti='antiKashiwara', opposite='antiKashiwara'), case_sensitive=False + ) def _element_constructor_(self, *crystalElements): """ diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index 3541ff87c8d..3b231158c6d 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -113,7 +113,36 @@ def MOLS_10_2(): """ from sage.matrix.constructor import Matrix - return [Matrix([[1, 8, 9, 0, 2, 4, 6, 3, 5, 7], [7, 2, 8, 9, 0, 3, 5, 4, 6, 1], [6, 1, 3, 8, 9, 0, 4, 5, 7, 2], [5, 7, 2, 4, 8, 9, 0, 6, 1, 3], [0, 6, 1, 3, 5, 8, 9, 7, 2, 4], [9, 0, 7, 2, 4, 6, 8, 1, 3, 5], [8, 9, 0, 1, 3, 5, 7, 2, 4, 6], [2, 3, 4, 5, 6, 7, 1, 8, 9, 0], [3, 4, 5, 6, 7, 1, 2, 0, 8, 9], [4, 5, 6, 7, 1, 2, 3, 9, 0, 8]]), Matrix([[1, 7, 6, 5, 0, 9, 8, 2, 3, 4], [8, 2, 1, 7, 6, 0, 9, 3, 4, 5], [9, 8, 3, 2, 1, 7, 0, 4, 5, 6], [0, 9, 8, 4, 3, 2, 1, 5, 6, 7], [2, 0, 9, 8, 5, 4, 3, 6, 7, 1], [4, 3, 0, 9, 8, 6, 5, 7, 1, 2], [6, 5, 4, 0, 9, 8, 7, 1, 2, 3], [3, 4, 5, 6, 7, 1, 2, 8, 0, 9], [5, 6, 7, 1, 2, 3, 4, 0, 9, 8], [7, 1, 2, 3, 4, 5, 6, 9, 8, 0]])] + return [ + Matrix( + [ + [1, 8, 9, 0, 2, 4, 6, 3, 5, 7], + [7, 2, 8, 9, 0, 3, 5, 4, 6, 1], + [6, 1, 3, 8, 9, 0, 4, 5, 7, 2], + [5, 7, 2, 4, 8, 9, 0, 6, 1, 3], + [0, 6, 1, 3, 5, 8, 9, 7, 2, 4], + [9, 0, 7, 2, 4, 6, 8, 1, 3, 5], + [8, 9, 0, 1, 3, 5, 7, 2, 4, 6], + [2, 3, 4, 5, 6, 7, 1, 8, 9, 0], + [3, 4, 5, 6, 7, 1, 2, 0, 8, 9], + [4, 5, 6, 7, 1, 2, 3, 9, 0, 8], + ] + ), + Matrix( + [ + [1, 7, 6, 5, 0, 9, 8, 2, 3, 4], + [8, 2, 1, 7, 6, 0, 9, 3, 4, 5], + [9, 8, 3, 2, 1, 7, 0, 4, 5, 6], + [0, 9, 8, 4, 3, 2, 1, 5, 6, 7], + [2, 0, 9, 8, 5, 4, 3, 6, 7, 1], + [4, 3, 0, 9, 8, 6, 5, 7, 1, 2], + [6, 5, 4, 0, 9, 8, 7, 1, 2, 3], + [3, 4, 5, 6, 7, 1, 2, 8, 0, 9], + [5, 6, 7, 1, 2, 3, 4, 0, 9, 8], + [7, 1, 2, 3, 4, 5, 6, 9, 8, 0], + ] + ), + ] def MOLS_12_5(): @@ -366,7 +395,16 @@ def OA_9_40(): """ from sage.rings.finite_rings.finite_field_constructor import FiniteField - A = [[(0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None)], [(0, None), (1, None), (2, 2), (3, 2), (4, 2), (2, None), (3, None), (4, None), (0, 2), (1, 2)], [(0, None), (2, 5), (4, 5), (1, 2), (3, 6), (3, 4), (0, 0), (2, 1), (4, 1), (1, 6)], [(0, None), (3, 4), (1, 4), (4, 0), (2, 5), (3, None), (1, 0), (4, 1), (2, 2), (0, 3)], [(0, None), (4, 6), (3, None), (2, 3), (1, 4), (2, 1), (1, None), (0, 4), (4, 0), (3, 2)], [(0, None), (1, 2), (4, 6), (4, 4), (1, 0), (0, 6), (2, 3), (3, 6), (3, 5), (2, 5)], [(1, None), (0, 3), (1, 2), (4, 5), (4, None), (2, 3), (0, 0), (2, 2), (3, 0), (3, None)], [(4, None), (1, 3), (0, 0), (1, 1), (4, 0), (3, 1), (2, 5), (0, None), (2, 1), (3, None)]] + A = [ + [(0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None)], + [(0, None), (1, None), (2, 2), (3, 2), (4, 2), (2, None), (3, None), (4, None), (0, 2), (1, 2)], + [(0, None), (2, 5), (4, 5), (1, 2), (3, 6), (3, 4), (0, 0), (2, 1), (4, 1), (1, 6)], + [(0, None), (3, 4), (1, 4), (4, 0), (2, 5), (3, None), (1, 0), (4, 1), (2, 2), (0, 3)], + [(0, None), (4, 6), (3, None), (2, 3), (1, 4), (2, 1), (1, None), (0, 4), (4, 0), (3, 2)], + [(0, None), (1, 2), (4, 6), (4, 4), (1, 0), (0, 6), (2, 3), (3, 6), (3, 5), (2, 5)], + [(1, None), (0, 3), (1, 2), (4, 5), (4, None), (2, 3), (0, 0), (2, 2), (3, 0), (3, None)], + [(4, None), (1, 3), (0, 0), (1, 1), (4, 0), (3, 1), (2, 5), (0, None), (2, 1), (3, None)], + ] Y = [None, 0, 1, 6, 5, 4, 3, 2] return OA_n_times_2_pow_c_from_matrix(9, 3, FiniteField(5), A, Y, check=False) @@ -662,7 +700,18 @@ def OA_11_80(): """ from sage.rings.finite_rings.finite_field_constructor import FiniteField - A = [[(0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None)], [(0, None), (1, None), (2, 3), (3, None), (4, 3), (2, None), (3, 3), (4, None), (0, 3), (1, 3)], [(0, None), (2, 8), (4, 6), (1, 3), (3, 3), (3, 13), (0, 13), (2, 6), (4, 14), (1, 12)], [(0, None), (3, 11), (1, 0), (4, 9), (2, 0), (3, 7), (1, 8), (4, 10), (2, 10), (0, 11)], [(0, None), (4, 8), (3, 14), (2, 14), (1, 12), (2, 10), (1, 10), (0, 3), (4, 5), (3, 8)], [(0, None), (1, 8), (4, 14), (4, 12), (1, 1), (0, 1), (2, 8), (3, 12), (3, 6), (2, 1)], [(1, None), (0, 6), (1, 1), (4, 4), (4, 13), (2, 6), (0, 14), (2, 9), (3, 0), (3, 3)], [(4, None), (1, 9), (0, 7), (1, 1), (4, 8), (3, 5), (2, 14), (0, 0), (2, None), (3, 0)], [(4, None), (4, 6), (1, 2), (0, None), (1, 13), (3, 8), (3, 2), (2, 0), (0, 14), (2, None)], [(1, None), (4, 9), (4, 1), (1, 0), (0, 4), (2, 5), (3, None), (3, 5), (2, None), (0, None)]] + A = [ + [(0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (0, None)], + [(0, None), (1, None), (2, 3), (3, None), (4, 3), (2, None), (3, 3), (4, None), (0, 3), (1, 3)], + [(0, None), (2, 8), (4, 6), (1, 3), (3, 3), (3, 13), (0, 13), (2, 6), (4, 14), (1, 12)], + [(0, None), (3, 11), (1, 0), (4, 9), (2, 0), (3, 7), (1, 8), (4, 10), (2, 10), (0, 11)], + [(0, None), (4, 8), (3, 14), (2, 14), (1, 12), (2, 10), (1, 10), (0, 3), (4, 5), (3, 8)], + [(0, None), (1, 8), (4, 14), (4, 12), (1, 1), (0, 1), (2, 8), (3, 12), (3, 6), (2, 1)], + [(1, None), (0, 6), (1, 1), (4, 4), (4, 13), (2, 6), (0, 14), (2, 9), (3, 0), (3, 3)], + [(4, None), (1, 9), (0, 7), (1, 1), (4, 8), (3, 5), (2, 14), (0, 0), (2, None), (3, 0)], + [(4, None), (4, 6), (1, 2), (0, None), (1, 13), (3, 8), (3, 2), (2, 0), (0, 14), (2, None)], + [(1, None), (4, 9), (4, 1), (1, 0), (0, 4), (2, 5), (3, None), (3, 5), (2, None), (0, None)], + ] Y = [None, 0, 1, 14, 12, 7, 2, 11, 3, 6] return OA_n_times_2_pow_c_from_matrix(11, 4, FiniteField(5), A, Y, check=False) @@ -1517,7 +1566,18 @@ def OA_11_640(): """ from sage.rings.finite_rings.finite_field_constructor import FiniteField - A = [[(0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (1, None), (4, None), (4, None), (1, None)], [(0, None), (1, None), (2, 7), (3, 55), (4, 54), (1, 87), (0, 124), (1, 123), (4, 83), (4, 61)], [(0, None), (2, None), (4, 14), (1, 63), (3, 6), (4, 87), (1, 16), (0, 47), (1, 29), (4, 16)], [(0, None), (3, None), (1, 1), (4, 15), (2, 5), (4, 32), (4, 30), (1, 3), (0, 12), (1, 14)], [(0, None), (4, None), (3, 28), (2, 62), (1, 64), (1, 55), (4, 63), (4, 4), (1, 0), (0, 0)], [(0, None), (2, 6), (3, 8), (3, 7), (2, 12), (0, 1), (2, 6), (3, 97), (3, 45), (2, 0)], [(0, None), (3, 6), (0, 63), (1, 5), (1, 6), (2, 97), (0, 28), (2, 63), (3, 0), (3, 2)], [(0, None), (4, 6), (2, 4), (4, 65), (0, 6), (3, 68), (2, 1), (0, 14), (2, 1), (3, 0)], [(0, None), (0, 6), (4, 9), (2, None), (4, 29), (3, 15), (3, 0), (2, 1), (0, 7), (2, 4)], [(0, None), (1, 6), (1, 14), (0, 14), (3, 4), (2, 0), (3, None), (3, 4), (2, 0), (0, None)]] # 0,25 became 0,124 + A = [ + [(0, None), (0, None), (0, None), (0, None), (0, None), (0, None), (1, None), (4, None), (4, None), (1, None)], + [(0, None), (1, None), (2, 7), (3, 55), (4, 54), (1, 87), (0, 124), (1, 123), (4, 83), (4, 61)], + [(0, None), (2, None), (4, 14), (1, 63), (3, 6), (4, 87), (1, 16), (0, 47), (1, 29), (4, 16)], + [(0, None), (3, None), (1, 1), (4, 15), (2, 5), (4, 32), (4, 30), (1, 3), (0, 12), (1, 14)], + [(0, None), (4, None), (3, 28), (2, 62), (1, 64), (1, 55), (4, 63), (4, 4), (1, 0), (0, 0)], + [(0, None), (2, 6), (3, 8), (3, 7), (2, 12), (0, 1), (2, 6), (3, 97), (3, 45), (2, 0)], + [(0, None), (3, 6), (0, 63), (1, 5), (1, 6), (2, 97), (0, 28), (2, 63), (3, 0), (3, 2)], + [(0, None), (4, 6), (2, 4), (4, 65), (0, 6), (3, 68), (2, 1), (0, 14), (2, 1), (3, 0)], + [(0, None), (0, 6), (4, 9), (2, None), (4, 29), (3, 15), (3, 0), (2, 1), (0, 7), (2, 4)], + [(0, None), (1, 6), (1, 14), (0, 14), (3, 4), (2, 0), (3, None), (3, 4), (2, 0), (0, None)], + ] # 0,25 became 0,124 Y = [None, 0, 1, 2, 121, 66, 77, 78, 41, 100] return OA_n_times_2_pow_c_from_matrix(11, 7, FiniteField(5), list(zip(*A)), Y, check=False) @@ -2160,7 +2220,14 @@ def QDM_25_6_1_1_5(): sage: is_quasi_difference_matrix(M,G,6,1,1,5) # needs sage.modules True """ - M = [[(0, 0), None, (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)], [(0, 0), (0, 0), None, (0, 4), (0, 2), (0, 3), (0, 1)], [(0, 0), (3, 1), (3, 0), None, (4, 0), (1, 0), (2, 0)], [(0, 0), (3, 0), (0, 2), (1, 2), None, (0, 1), (0, 3)], [(0, 0), (3, 3), (1, 2), (4, 2), (2, 0), None, (0, 4)], [(0, 0), (4, 2), (2, 4), (0, 3), (2, 3), (3, 2), None]] + M = [ + [(0, 0), None, (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)], + [(0, 0), (0, 0), None, (0, 4), (0, 2), (0, 3), (0, 1)], + [(0, 0), (3, 1), (3, 0), None, (4, 0), (1, 0), (2, 0)], + [(0, 0), (3, 0), (0, 2), (1, 2), None, (0, 1), (0, 3)], + [(0, 0), (3, 3), (1, 2), (4, 2), (2, 0), None, (0, 4)], + [(0, 0), (4, 2), (2, 4), (0, 3), (2, 3), (3, 2), None], + ] from sage.groups.additive_abelian.additive_abelian_group import AdditiveAbelianGroup from sage.modules.free_module_element import free_module_element as vector @@ -2173,7 +2240,9 @@ def QDM_25_6_1_1_5(): for R in zip(*M): a, b, c, d, e, f = R for i in range(5): - Mb.append([None if a is None else a + G(vector((i, i))), None if b is None else b + G(vector((2 * i, i))), None if c is None else c + G(vector((i, 0))), None if d is None else d + G(vector((4 * i, 0))), None if e is None else e + G(vector((3 * i, 4 * i))), None if f is None else f + G(vector((4 * i, 4 * i)))]) + Mb.append( + [None if a is None else a + G(vector((i, i))), None if b is None else b + G(vector((2 * i, i))), None if c is None else c + G(vector((i, 0))), None if d is None else d + G(vector((4 * i, 0))), None if e is None else e + G(vector((3 * i, 4 * i))), None if f is None else f + G(vector((4 * i, 4 * i)))] + ) return G, Mb @@ -2335,7 +2404,15 @@ def QDM_54_7_1_1_8(): G = AdditiveCyclic(54) - M = [[0, None, None, None, 0, None, None, None, None, None], [17, 0, 0, 0, -17, 0, 0, 0, 1, 11], [29, 28, 35, 23, -29, -28, -35, -23, 3, 19], [36, 50, 5, 33, -36, -50, -5, -33, 7, 33], [31, 2, 43, 30, -31, -2, -43, -30, 34, 33], [16, 47, 44, 51, -16, -47, -44, -51, 30, 19], [41, 11, 1, 17, -41, -11, -1, -17, 28, 11]] + M = [ + [0, None, None, None, 0, None, None, None, None, None], + [17, 0, 0, 0, -17, 0, 0, 0, 1, 11], + [29, 28, 35, 23, -29, -28, -35, -23, 3, 19], + [36, 50, 5, 33, -36, -50, -5, -33, 7, 33], + [31, 2, 43, 30, -31, -2, -43, -30, 34, 33], + [16, 47, 44, 51, -16, -47, -44, -51, 30, 19], + [41, 11, 1, 17, -41, -11, -1, -17, 28, 11], + ] Mb = [] @@ -2386,7 +2463,18 @@ def QDM_57_9_1_1_8(): QDM: dict[tuple[int, int], dict] = {} -for (n, k, lmbda, mu, u), f in [((19, 6, 1, 1, 1), QDM_19_6_1_1_1), ((21, 5, 1, 1, 1), QDM_21_5_1_1_1), ((21, 6, 1, 1, 5), QDM_21_6_1_1_5), ((25, 6, 1, 1, 5), QDM_25_6_1_1_5), ((33, 6, 1, 1, 1), QDM_33_6_1_1_1), ((37, 6, 1, 1, 1), QDM_37_6_1_1_1), ((35, 7, 1, 1, 7), QDM_35_7_1_1_7), ((45, 7, 1, 1, 9), QDM_45_7_1_1_9), ((54, 7, 1, 1, 8), QDM_54_7_1_1_8), ((57, 9, 1, 1, 8), QDM_57_9_1_1_8)]: +for (n, k, lmbda, mu, u), f in [ + ((19, 6, 1, 1, 1), QDM_19_6_1_1_1), + ((21, 5, 1, 1, 1), QDM_21_5_1_1_1), + ((21, 6, 1, 1, 5), QDM_21_6_1_1_5), + ((25, 6, 1, 1, 5), QDM_25_6_1_1_5), + ((33, 6, 1, 1, 1), QDM_33_6_1_1_1), + ((37, 6, 1, 1, 1), QDM_37_6_1_1_1), + ((35, 7, 1, 1, 7), QDM_35_7_1_1_7), + ((45, 7, 1, 1, 9), QDM_45_7_1_1_9), + ((54, 7, 1, 1, 8), QDM_54_7_1_1_8), + ((57, 9, 1, 1, 8), QDM_57_9_1_1_8), +]: if (n + u, lmbda) not in QDM: QDM[n + u, lmbda] = {} QDM[n + u, lmbda][n, lmbda, mu, u] = (k, f) @@ -2730,11 +2818,29 @@ def QDM_57_9_1_1_8(): (121, 6, 1): {(11, 11): [[(0, 0), (0, 3), (0, 4), (1, 1), (1, 7), (4, 6)], [(0, 0), (0, 2), (2, 5), (4, 7), (6, 4), (8, 0)], [(0, 0), (1, 5), (2, 0), (4, 1), (6, 0), (7, 2)], [(0, 0), (1, 0), (3, 9), (4, 8), (6, 1), (9, 5)]]}, (141, 5, 1): {(141,): [[0, 33, 60, 92, 97], [0, 3, 45, 88, 110], [0, 18, 39, 68, 139], [0, 12, 67, 75, 113], [0, 1, 15, 84, 94], [0, 7, 11, 24, 30], [0, 36, 90, 116, 125]]}, (161, 5, 1): {(161,): [[0, 19, 34, 73, 80], [0, 16, 44, 71, 79], [0, 12, 33, 74, 78], [0, 13, 30, 72, 77], [0, 11, 36, 67, 76], [0, 18, 32, 69, 75], [0, 10, 48, 68, 70], [0, 3, 29, 52, 53]]}, - (175, 7, 1): {(7, 5, 5): [[(0, 0, 0), (1, 0, 0), (2, 0, 0), (3, 0, 0), (4, 0, 0), (5, 0, 0), (6, 0, 0)], [(0, 0, 0), (1, 1, 3), (1, 4, 2), (2, 2, 2), (2, 3, 3), (4, 2, 0), (4, 3, 0)], [(0, 0, 0), (1, 3, 4), (1, 2, 1), (2, 2, 3), (2, 3, 2), (4, 0, 2), (4, 0, 3)], [(0, 0, 0), (1, 1, 2), (1, 4, 3), (2, 1, 1), (2, 4, 4), (4, 0, 1), (4, 0, 4)], [(0, 0, 0), (1, 3, 1), (1, 2, 4), (2, 4, 1), (2, 1, 4), (4, 1, 0), (4, 4, 0)]]}, + (175, 7, 1): { + (7, 5, 5): [ + [(0, 0, 0), (1, 0, 0), (2, 0, 0), (3, 0, 0), (4, 0, 0), (5, 0, 0), (6, 0, 0)], + [(0, 0, 0), (1, 1, 3), (1, 4, 2), (2, 2, 2), (2, 3, 3), (4, 2, 0), (4, 3, 0)], + [(0, 0, 0), (1, 3, 4), (1, 2, 1), (2, 2, 3), (2, 3, 2), (4, 0, 2), (4, 0, 3)], + [(0, 0, 0), (1, 1, 2), (1, 4, 3), (2, 1, 1), (2, 4, 4), (4, 0, 1), (4, 0, 4)], + [(0, 0, 0), (1, 3, 1), (1, 2, 4), (2, 4, 1), (2, 1, 4), (4, 1, 0), (4, 4, 0)], + ] + }, (201, 5, 1): {(201,): [[0, 1, 45, 98, 100], [0, 3, 32, 65, 89], [0, 4, 54, 70, 75], [0, 6, 49, 69, 91], [0, 7, 58, 81, 95], [0, 8, 34, 72, 90], [0, 9, 36, 77, 96], [0, 10, 35, 83, 94], [0, 12, 40, 79, 92], [0, 15, 46, 76, 93]]}, (217, 7, 1): {(217,): [[0, 1, 37, 67, 88, 92, 149], [0, 15, 18, 65, 78, 121, 137], [0, 8, 53, 79, 85, 102, 107], [0, 11, 86, 100, 120, 144, 190], [0, 29, 64, 165, 198, 205, 207], [0, 31, 62, 93, 124, 155, 186]]}, (221, 5, 1): {(221,): [[0, 1, 24, 61, 116], [0, 3, 46, 65, 113], [0, 4, 73, 89, 130], [0, 5, 77, 122, 124], [0, 6, 39, 50, 118], [0, 7, 66, 81, 94], [0, 8, 38, 64, 139], [0, 9, 29, 80, 107], [0, 10, 35, 93, 135], [0, 12, 34, 52, 88], [0, 14, 31, 63, 84]]}, - (259, 7, 1): {(7, 37): [[(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0)], [(0, 0), (0, 1), (0, 6), (1, 4), (2, 19), (3, 25), (6, 26)], [(0, 0), (0, 10), (0, 23), (2, 3), (4, 5), (5, 1), (6, 28)], [(0, 0), (0, 8), (0, 26), (1, 13), (3, 10), (4, 30), (5, 21)], [(0, 0), (0, 4), (1, 25), (1, 34), (2, 33), (2, 35), (4, 10)], [(0, 0), (0, 3), (1, 26), (2, 7), (2, 28), (4, 17), (4, 34)], [(0, 0), (0, 30), (1, 7), (1, 22), (2, 1), (4, 21), (4, 33)]]}, # the following one is lemma 2.2 in Abel "Some new BIBDs with block size 7" + (259, 7, 1): { + (7, 37): [ + [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0)], + [(0, 0), (0, 1), (0, 6), (1, 4), (2, 19), (3, 25), (6, 26)], + [(0, 0), (0, 10), (0, 23), (2, 3), (4, 5), (5, 1), (6, 28)], + [(0, 0), (0, 8), (0, 26), (1, 13), (3, 10), (4, 30), (5, 21)], + [(0, 0), (0, 4), (1, 25), (1, 34), (2, 33), (2, 35), (4, 10)], + [(0, 0), (0, 3), (1, 26), (2, 7), (2, 28), (4, 17), (4, 34)], + [(0, 0), (0, 30), (1, 7), (1, 22), (2, 1), (4, 21), (4, 33)], + ] + }, # the following one is lemma 2.2 in Abel "Some new BIBDs with block size 7" ############## # lambda = 2 # ############## @@ -2783,10 +2889,31 @@ def QDM_57_9_1_1_8(): (61, 6, 2): {(61,): [[12, 15, 28, 34, 35, 59], [1, 13, 18, 47, 51, 53], [8, 10, 11, 21, 29, 43], [16, 20, 25, 32, 40, 50]]}, (43, 7, 2): {(43,): [[0, 1, 11, 19, 31, 38, 40], [0, 2, 10, 16, 25, 38, 42]]}, (64, 7, 2): {(64,): [[0, 1, 2, 4, 7, 28, 52], [0, 4, 9, 21, 31, 39, 53], [0, 6, 15, 23, 34, 41, 54]]}, - (75, 5, 2): {(5, 15): [[(0, 0), (1, 10), (1, 8), (4, 1), (4, 2)], [(0, 0), (2, 5), (2, 10), (3, 7), (3, 13)], [(0, 0), (1, 10), (1, 2), (4, 4), (4, 8)], [(0, 0), (2, 5), (2, 10), (3, 14), (3, 11)], [(0, 0), (1, 4), (1, 5), (4, 1), (4, 8)], [(0, 0), (1, 1), (1, 5), (4, 4), (4, 2)], [(0, 0), (2, 7), (2, 13), (3, 1), (3, 4)], [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0)], [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0)]]}, + (75, 5, 2): { + (5, 15): [ + [(0, 0), (1, 10), (1, 8), (4, 1), (4, 2)], + [(0, 0), (2, 5), (2, 10), (3, 7), (3, 13)], + [(0, 0), (1, 10), (1, 2), (4, 4), (4, 8)], + [(0, 0), (2, 5), (2, 10), (3, 14), (3, 11)], + [(0, 0), (1, 4), (1, 5), (4, 1), (4, 8)], + [(0, 0), (1, 1), (1, 5), (4, 4), (4, 2)], + [(0, 0), (2, 7), (2, 13), (3, 1), (3, 4)], + [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0)], + [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0)], + ] + }, (85, 7, 2): {(85,): [[0, 1, 11, 20, 32, 35, 39], [0, 2, 6, 16, 29, 50, 65], [0, 3, 9, 27, 55, 72, 80], [0, 5, 7, 30, 47, 48, 59]]}, (85, 8, 2): {(85,): [[24, 31, 39, 50, 67, 68, 70, 82], [20, 49, 51, 55, 56, 60, 72, 81], [9, 19, 29, 37, 43, 56, 59, 81]]}, - (153, 9, 2): {(3, 3, 17): [[(0, 0, 0), (0, 1, 0), (0, 2, 0), (1, 0, 0), (1, 1, 0), (1, 2, 0), (2, 0, 0), (2, 1, 0), (2, 2, 0)], [(0, 0, 0), (0, 1, 0), (0, 2, 0), (1, 0, 0), (1, 1, 0), (1, 2, 0), (2, 0, 0), (2, 1, 0), (2, 2, 0)], [(0, 0, 0), (0, 1, 1), (0, 1, 16), (0, 2, 4), (0, 2, 13), (1, 0, 3), (1, 0, 14), (2, 0, 5), (2, 0, 12)], [(0, 0, 0), (0, 1, 2), (0, 1, 15), (0, 2, 8), (0, 2, 9), (1, 0, 6), (1, 0, 11), (2, 0, 10), (2, 0, 7)], [(0, 0, 0), (0, 1, 3), (0, 1, 14), (0, 2, 12), (0, 2, 5), (1, 0, 9), (1, 0, 8), (2, 0, 15), (2, 0, 2)], [(0, 0, 0), (0, 1, 6), (0, 1, 11), (0, 2, 7), (0, 2, 10), (1, 0, 1), (1, 0, 16), (2, 0, 13), (2, 0, 4)]]}, + (153, 9, 2): { + (3, 3, 17): [ + [(0, 0, 0), (0, 1, 0), (0, 2, 0), (1, 0, 0), (1, 1, 0), (1, 2, 0), (2, 0, 0), (2, 1, 0), (2, 2, 0)], + [(0, 0, 0), (0, 1, 0), (0, 2, 0), (1, 0, 0), (1, 1, 0), (1, 2, 0), (2, 0, 0), (2, 1, 0), (2, 2, 0)], + [(0, 0, 0), (0, 1, 1), (0, 1, 16), (0, 2, 4), (0, 2, 13), (1, 0, 3), (1, 0, 14), (2, 0, 5), (2, 0, 12)], + [(0, 0, 0), (0, 1, 2), (0, 1, 15), (0, 2, 8), (0, 2, 9), (1, 0, 6), (1, 0, 11), (2, 0, 10), (2, 0, 7)], + [(0, 0, 0), (0, 1, 3), (0, 1, 14), (0, 2, 12), (0, 2, 5), (1, 0, 9), (1, 0, 8), (2, 0, 15), (2, 0, 2)], + [(0, 0, 0), (0, 1, 6), (0, 1, 11), (0, 2, 7), (0, 2, 10), (1, 0, 1), (1, 0, 16), (2, 0, 13), (2, 0, 4)], + ] + }, (181, 10, 2): {(181,): [[1, 7, 40, 42, 51, 59, 113, 125, 135, 151], [19, 22, 31, 35, 36, 64, 74, 133, 154, 156], [10, 15, 34, 47, 58, 65, 83, 87, 161, 164], [12, 18, 32, 52, 77, 78, 142, 157, 165, 172]]}, ############## # lambda = 3 # @@ -2803,7 +2930,14 @@ def QDM_57_9_1_1_8(): (85, 7, 3): {(85,): [[0, 7, 23, 27, 28, 31, 71], [0, 12, 22, 41, 61, 74, 79], [0, 6, 11, 13, 38, 42, 77], [0, 1, 7, 16, 19, 27, 49], [0, 9, 26, 39, 54, 56, 71], [0, 2, 3, 12, 37, 53, 63]]}, (97, 9, 3): {(97,): [[1, 2, 25, 35, 46, 58, 61, 70, 90], [3, 4, 8, 38, 43, 50, 69, 86, 87], [6, 12, 16, 32, 53, 55, 57, 75, 82], [9, 18, 24, 26, 31, 34, 37, 48, 64]]}, (49, 9, 3): {(49,): [[0, 1, 3, 5, 9, 14, 19, 25, 37], [0, 2, 12, 13, 16, 19, 34, 41, 42]]}, - (121, 10, 3): {(11, 11): [[(0, 1), (0, 3), (0, 4), (0, 5), (0, 9), (1, 8), (3, 2), (4, 10), (5, 7), (9, 6)], [(1, 2), (3, 6), (4, 8), (5, 10), (9, 7), (10, 2), (8, 6), (7, 8), (6, 10), (2, 7)], [(1, 7), (3, 10), (4, 6), (5, 2), (9, 8), (1, 4), (3, 1), (4, 5), (5, 9), (9, 3)], [(10, 10), (8, 8), (7, 7), (6, 6), (2, 2), (1, 0), (3, 0), (4, 0), (5, 0), (9, 0)]]}, + (121, 10, 3): { + (11, 11): [ + [(0, 1), (0, 3), (0, 4), (0, 5), (0, 9), (1, 8), (3, 2), (4, 10), (5, 7), (9, 6)], + [(1, 2), (3, 6), (4, 8), (5, 10), (9, 7), (10, 2), (8, 6), (7, 8), (6, 10), (2, 7)], + [(1, 7), (3, 10), (4, 6), (5, 2), (9, 8), (1, 4), (3, 1), (4, 5), (5, 9), (9, 3)], + [(10, 10), (8, 8), (7, 7), (6, 6), (2, 2), (1, 0), (3, 0), (4, 0), (5, 0), (9, 0)], + ] + }, ############### # lambda = 4 # ############### @@ -2848,7 +2982,12 @@ def QDM_57_9_1_1_8(): (43, 15, 10): {(43,): [[1, 3, 6, 13, 18, 21, 22, 25, 26, 27, 33, 35, 36, 38, 40], [9, 10, 11, 13, 16, 17, 19, 23, 26, 27, 28, 33, 35, 38, 39]]}, (45, 12, 3): {(3, 3, 5): [[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 2, 1), (0, 0, 3), (0, 1, 1), (1, 0, 0), (1, 1, 2), (1, 2, 3), (2, 0, 0), (2, 1, 3), (2, 2, 2)]]}, (46, 10, 6): {(46,): [[0, 2, 11, 13, 21, 22, 30, 33, 34, 40], [0, 2, 6, 7, 22, 23, 28, 32, 35, 38], [0, 2, 4, 7, 8, 9, 12, 23, 26, 41]]}, - (49, 21, 10): {(7, 7): [[(0, 1), (0, 2), (0, 4), (1, 1), (1, 2), (1, 4), (2, 1), (2, 2), (2, 4), (3, 1), (3, 2), (3, 4), (4, 1), (4, 2), (4, 4), (5, 1), (5, 2), (5, 4), (6, 1), (6, 2), (6, 4)], [(1, 0), (1, 1), (1, 2), (1, 4), (2, 0), (2, 1), (2, 2), (2, 4), (4, 0), (4, 1), (4, 2), (4, 4), (3, 3), (3, 5), (3, 6), (5, 3), (5, 5), (5, 6), (6, 3), (6, 5), (6, 6)]]}, + (49, 21, 10): { + (7, 7): [ + [(0, 1), (0, 2), (0, 4), (1, 1), (1, 2), (1, 4), (2, 1), (2, 2), (2, 4), (3, 1), (3, 2), (3, 4), (4, 1), (4, 2), (4, 4), (5, 1), (5, 2), (5, 4), (6, 1), (6, 2), (6, 4)], + [(1, 0), (1, 1), (1, 2), (1, 4), (2, 0), (2, 1), (2, 2), (2, 4), (4, 0), (4, 1), (4, 2), (4, 4), (3, 3), (3, 5), (3, 6), (5, 3), (5, 5), (5, 6), (6, 3), (6, 5), (6, 6)], + ] + }, (53, 13, 6): {(53,): [[1, 10, 13, 15, 16, 24, 28, 36, 42, 44, 46, 47, 49], [2, 3, 19, 20, 26, 30, 31, 32, 35, 39, 41, 45, 48]]}, (53, 14, 7): {(53,): [[0, 1, 10, 13, 15, 16, 24, 28, 36, 42, 44, 46, 47, 49], [0, 2, 3, 19, 20, 26, 30, 31, 32, 35, 39, 41, 45, 48]]}, (61, 15, 7): {(61,): [[0, 1, 3, 4, 8, 10, 13, 22, 30, 35, 44, 45, 46, 50, 58], [0, 1, 3, 5, 13, 18, 29, 34, 35, 37, 41, 43, 44, 51, 55]]}, @@ -2859,7 +2998,78 @@ def QDM_57_9_1_1_8(): # a (144,66,30) non-cyclic difference set in AbelianGroup([2,8,3,3]) # given in unpublished paper by Kroeger, Miller, Mooney, Shepard and Smith # see https://dmgordon.org/diffset - (144, 66, 30): {(2, 8, 3, 3): [[(0, 1, 0, 0), (0, 7, 0, 2), (0, 5, 0, 1), (0, 3, 0, 0), (0, 6, 0, 1), (0, 1, 0, 2), (0, 4, 0, 0), (0, 2, 0, 2), (0, 6, 0, 0), (0, 1, 0, 1), (0, 4, 0, 2), (0, 2, 0, 1), (1, 2, 2, 0), (1, 3, 2, 0), (1, 4, 2, 0), (1, 5, 2, 0), (1, 6, 2, 0), (1, 7, 2, 0), (0, 6, 1, 2), (0, 1, 1, 0), (0, 4, 1, 1), (0, 3, 1, 0), (0, 1, 1, 2), (0, 4, 1, 0), (0, 7, 1, 1), (0, 2, 1, 2), (0, 6, 1, 0), (0, 1, 1, 1), (0, 2, 1, 1), (0, 5, 1, 2), (1, 0, 0, 0), (1, 6, 0, 2), (1, 1, 0, 0), (1, 4, 0, 1), (1, 7, 0, 2), (1, 2, 0, 0), (1, 5, 0, 1), (1, 0, 0, 2), (1, 3, 0, 0), (1, 1, 0, 2), (1, 0, 0, 1), (1, 1, 0, 1), (0, 0, 2, 0), (0, 6, 2, 2), (0, 4, 2, 1), (0, 0, 2, 2), (0, 3, 2, 0), (0, 6, 2, 1), (0, 2, 2, 2), (0, 5, 2, 0), (0, 0, 2, 1), (0, 4, 2, 2), (0, 7, 2, 0), (0, 2, 2, 1), (1, 0, 1, 0), (1, 1, 1, 0), (1, 2, 1, 0), (1, 0, 1, 2), (1, 3, 1, 0), (1, 6, 1, 1), (1, 1, 1, 2), (1, 7, 1, 1), (1, 0, 1, 1), (1, 1, 1, 1), (1, 4, 1, 2), (1, 5, 1, 2)]]}, + (144, 66, 30): { + (2, 8, 3, 3): [ + [ + (0, 1, 0, 0), + (0, 7, 0, 2), + (0, 5, 0, 1), + (0, 3, 0, 0), + (0, 6, 0, 1), + (0, 1, 0, 2), + (0, 4, 0, 0), + (0, 2, 0, 2), + (0, 6, 0, 0), + (0, 1, 0, 1), + (0, 4, 0, 2), + (0, 2, 0, 1), + (1, 2, 2, 0), + (1, 3, 2, 0), + (1, 4, 2, 0), + (1, 5, 2, 0), + (1, 6, 2, 0), + (1, 7, 2, 0), + (0, 6, 1, 2), + (0, 1, 1, 0), + (0, 4, 1, 1), + (0, 3, 1, 0), + (0, 1, 1, 2), + (0, 4, 1, 0), + (0, 7, 1, 1), + (0, 2, 1, 2), + (0, 6, 1, 0), + (0, 1, 1, 1), + (0, 2, 1, 1), + (0, 5, 1, 2), + (1, 0, 0, 0), + (1, 6, 0, 2), + (1, 1, 0, 0), + (1, 4, 0, 1), + (1, 7, 0, 2), + (1, 2, 0, 0), + (1, 5, 0, 1), + (1, 0, 0, 2), + (1, 3, 0, 0), + (1, 1, 0, 2), + (1, 0, 0, 1), + (1, 1, 0, 1), + (0, 0, 2, 0), + (0, 6, 2, 2), + (0, 4, 2, 1), + (0, 0, 2, 2), + (0, 3, 2, 0), + (0, 6, 2, 1), + (0, 2, 2, 2), + (0, 5, 2, 0), + (0, 0, 2, 1), + (0, 4, 2, 2), + (0, 7, 2, 0), + (0, 2, 2, 1), + (1, 0, 1, 0), + (1, 1, 1, 0), + (1, 2, 1, 0), + (1, 0, 1, 2), + (1, 3, 1, 0), + (1, 6, 1, 1), + (1, 1, 1, 2), + (1, 7, 1, 1), + (1, 0, 1, 1), + (1, 1, 1, 1), + (1, 4, 1, 2), + (1, 5, 1, 2), + ] + ] + }, # a (320,88,24) non-cyclic difference set in AbelianGroup([4,4,4,5]), # given in Arasu and Chen, Designs, Codes and Cryptography 2001 # see https://dmgordon.org/diffset @@ -3225,7 +3435,20 @@ def DM_12_6_1(): from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic G = AdditiveCyclic(2).cartesian_product(AdditiveCyclic(6)) - M = [[(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)], [(0, 0), (0, 1), (1, 0), (0, 3), (1, 2), (0, 4)], [(0, 0), (0, 2), (1, 2), (1, 0), (0, 1), (1, 5)], [(0, 0), (0, 3), (0, 2), (0, 1), (1, 5), (1, 4)], [(0, 0), (0, 4), (1, 1), (1, 3), (0, 5), (0, 2)], [(0, 0), (0, 5), (0, 1), (1, 5), (1, 3), (1, 1)], [(0, 0), (1, 0), (1, 3), (0, 2), (0, 3), (1, 2)], [(0, 0), (1, 1), (1, 5), (1, 2), (1, 4), (1, 0)], [(0, 0), (1, 2), (0, 4), (0, 5), (0, 2), (1, 3)], [(0, 0), (1, 3), (1, 4), (0, 4), (1, 1), (0, 1)], [(0, 0), (1, 4), (0, 5), (1, 1), (1, 0), (0, 3)], [(0, 0), (1, 5), (0, 3), (1, 4), (0, 4), (0, 5)]] + M = [ + [(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)], + [(0, 0), (0, 1), (1, 0), (0, 3), (1, 2), (0, 4)], + [(0, 0), (0, 2), (1, 2), (1, 0), (0, 1), (1, 5)], + [(0, 0), (0, 3), (0, 2), (0, 1), (1, 5), (1, 4)], + [(0, 0), (0, 4), (1, 1), (1, 3), (0, 5), (0, 2)], + [(0, 0), (0, 5), (0, 1), (1, 5), (1, 3), (1, 1)], + [(0, 0), (1, 0), (1, 3), (0, 2), (0, 3), (1, 2)], + [(0, 0), (1, 1), (1, 5), (1, 2), (1, 4), (1, 0)], + [(0, 0), (1, 2), (0, 4), (0, 5), (0, 2), (1, 3)], + [(0, 0), (1, 3), (1, 4), (0, 4), (1, 1), (0, 1)], + [(0, 0), (1, 4), (0, 5), (1, 1), (1, 0), (0, 3)], + [(0, 0), (1, 5), (0, 3), (1, 4), (0, 4), (0, 5)], + ] return G, M @@ -3281,7 +3504,16 @@ def DM_24_8_1(): sage: _ = designs.difference_matrix(24,8) """ - M = "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 " + "0000 0010 0100 0110 1000 1010 1100 1110 2000 2010 2100 2110 " + "0000 0011 1001 2110 0111 2011 2111 1000 0100 1100 1101 2010 " + "0000 1010 1011 2000 1101 2110 0001 0101 2100 2001 0111 1100 " + "0000 0001 2010 1111 2111 2100 1101 0011 1010 2101 1000 0110 " + "0000 1000 2001 1011 0100 1100 0110 2101 2111 0010 1111 2011 " + "0000 1001 0111 2100 2000 0010 1110 2011 1100 1011 0101 2111 " + "0000 1011 2101 0100 2110 1001 2000 0110 0101 1111 2011 1010 " + M = ( + "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 " + + "0000 0010 0100 0110 1000 1010 1100 1110 2000 2010 2100 2110 " + + "0000 0011 1001 2110 0111 2011 2111 1000 0100 1100 1101 2010 " + + "0000 1010 1011 2000 1101 2110 0001 0101 2100 2001 0111 1100 " + + "0000 0001 2010 1111 2111 2100 1101 0011 1010 2101 1000 0110 " + + "0000 1000 2001 1011 0100 1100 0110 2101 2111 0010 1111 2011 " + + "0000 1001 0111 2100 2000 0010 1110 2011 1100 1011 0101 2111 " + + "0000 1011 2101 0100 2110 1001 2000 0110 0101 1111 2011 1010 " + ) from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic from sage.categories.cartesian_product import cartesian_product @@ -3396,7 +3628,14 @@ def DM_35_6_1(): sage: _ = designs.difference_matrix(35,6) # needs sage.rings.finite_rings """ - M = [[0, 15, 30, 10, 25, 1, 16, 31, 11, 26, 2, 17, 32, 12, 6, 3, 18, 33, 27, 21, 4, 19, 13, 7, 22, 5, 34, 28, 8, 23, 20, 14, 29, 9, 24], [0, 22, 16, 3, 4, 9, 10, 32, 26, 13, 18, 5, 27, 14, 15, 20, 7, 1, 23, 31, 29, 2, 24, 11, 19, 17, 25, 12, 6, 28, 33, 34, 21, 8, 30], [0, 29, 2, 31, 18, 10, 32, 26, 34, 28, 27, 21, 15, 9, 17, 30, 3, 4, 5, 20, 12, 6, 14, 22, 16, 8, 23, 24, 25, 33, 11, 19, 13, 7, 1], [0, 8, 9, 17, 11, 25, 19, 27, 28, 1, 15, 23, 31, 4, 26, 12, 6, 14, 29, 16, 2, 3, 18, 33, 34, 20, 7, 22, 30, 24, 10, 32, 5, 13, 21], [0, 1, 23, 24, 32, 33, 6, 7, 29, 30, 10, 11, 12, 13, 28, 8, 9, 31, 4, 5, 27, 14, 15, 16, 3, 25, 26, 34, 21, 22, 2, 17, 18, 19, 20], [0] * 35] + M = [ + [0, 15, 30, 10, 25, 1, 16, 31, 11, 26, 2, 17, 32, 12, 6, 3, 18, 33, 27, 21, 4, 19, 13, 7, 22, 5, 34, 28, 8, 23, 20, 14, 29, 9, 24], + [0, 22, 16, 3, 4, 9, 10, 32, 26, 13, 18, 5, 27, 14, 15, 20, 7, 1, 23, 31, 29, 2, 24, 11, 19, 17, 25, 12, 6, 28, 33, 34, 21, 8, 30], + [0, 29, 2, 31, 18, 10, 32, 26, 34, 28, 27, 21, 15, 9, 17, 30, 3, 4, 5, 20, 12, 6, 14, 22, 16, 8, 23, 24, 25, 33, 11, 19, 13, 7, 1], + [0, 8, 9, 17, 11, 25, 19, 27, 28, 1, 15, 23, 31, 4, 26, 12, 6, 14, 29, 16, 2, 3, 18, 33, 34, 20, 7, 22, 30, 24, 10, 32, 5, 13, 21], + [0, 1, 23, 24, 32, 33, 6, 7, 29, 30, 10, 11, 12, 13, 28, 8, 9, 31, 4, 5, 27, 14, 15, 16, 3, 25, 26, 34, 21, 22, 2, 17, 18, 19, 20], + [0] * 35, + ] from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic @@ -3513,7 +3752,14 @@ def DM_44_6_1(): G11 = AdditiveCyclic(11) G2211 = cartesian_product((G2, G2, G11)) - M = [[(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)], [(1, 1, 4), (0, 1, 4), (1, 1, 7), (1, 0, 6), (1, 1, 9), (0, 1, 2), (0, 1, 5), (0, 1, 1)], [(1, 0, 6), (0, 1, 3), (1, 0, 0), (0, 1, 9), (1, 1, 1), (0, 1, 4), (1, 1, 9), (1, 0, 9)], [(1, 1, 6), (1, 1, 9), (0, 1, 2), (1, 1, 0), (0, 1, 0), (1, 1, 5), (0, 0, 4), (0, 0, 9)], [(1, 0, 9), (0, 0, 2), (0, 0, 1), (1, 0, 2), (0, 0, 7), (1, 1, 6), (1, 1, 0), (1, 0, 7)], [(1, 0, 1), (1, 0, 6), (1, 1, 3), (0, 1, 5), (0, 0, 5), (0, 1, 3), (0, 1, 0), (1, 1, 0)]] + M = [ + [(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)], + [(1, 1, 4), (0, 1, 4), (1, 1, 7), (1, 0, 6), (1, 1, 9), (0, 1, 2), (0, 1, 5), (0, 1, 1)], + [(1, 0, 6), (0, 1, 3), (1, 0, 0), (0, 1, 9), (1, 1, 1), (0, 1, 4), (1, 1, 9), (1, 0, 9)], + [(1, 1, 6), (1, 1, 9), (0, 1, 2), (1, 1, 0), (0, 1, 0), (1, 1, 5), (0, 0, 4), (0, 0, 9)], + [(1, 0, 9), (0, 0, 2), (0, 0, 1), (1, 0, 2), (0, 0, 7), (1, 1, 6), (1, 1, 0), (1, 0, 7)], + [(1, 0, 1), (1, 0, 6), (1, 1, 3), (0, 1, 5), (0, 0, 5), (0, 1, 3), (0, 1, 0), (1, 1, 0)], + ] M = [[G2211(x) for x in L] for L in M] @@ -3557,7 +3803,15 @@ def DM_45_7_1(): G533 = cartesian_product((FiniteField(5), FiniteField(3), FiniteField(3))) - M = [[(0, 0, 0), (2, 2, 1), (3, 1, 1), (4, 1, 2), (4, 0, 1), (0, 1, 1), (0, 2, 1), (3, 2, 2)], [(0, 0, 0), (1, 2, 1), (4, 2, 2), (1, 2, 0), (4, 1, 0), (3, 1, 1), (3, 0, 0), (2, 1, 2)], [(0, 0, 0), (4, 1, 1), (2, 2, 1), (3, 2, 0), (1, 2, 0), (2, 1, 0), (1, 0, 0), (3, 2, 1)], [(0, 0, 0), (0, 1, 0), (2, 1, 1), (4, 0, 0), (0, 0, 2), (4, 2, 2), (3, 2, 2), (1, 2, 2)], [(0, 0, 0), (3, 1, 2), (2, 1, 0), (0, 2, 2), (4, 2, 1), (0, 2, 1), (2, 0, 1), (1, 1, 2)], [(0, 0, 0), (2, 1, 1), (1, 2, 2), (3, 0, 1), (2, 0, 1), (1, 0, 0), (4, 2, 1), (1, 1, 0)], [(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)]] + M = [ + [(0, 0, 0), (2, 2, 1), (3, 1, 1), (4, 1, 2), (4, 0, 1), (0, 1, 1), (0, 2, 1), (3, 2, 2)], + [(0, 0, 0), (1, 2, 1), (4, 2, 2), (1, 2, 0), (4, 1, 0), (3, 1, 1), (3, 0, 0), (2, 1, 2)], + [(0, 0, 0), (4, 1, 1), (2, 2, 1), (3, 2, 0), (1, 2, 0), (2, 1, 0), (1, 0, 0), (3, 2, 1)], + [(0, 0, 0), (0, 1, 0), (2, 1, 1), (4, 0, 0), (0, 0, 2), (4, 2, 2), (3, 2, 2), (1, 2, 2)], + [(0, 0, 0), (3, 1, 2), (2, 1, 0), (0, 2, 2), (4, 2, 1), (0, 2, 1), (2, 0, 1), (1, 1, 2)], + [(0, 0, 0), (2, 1, 1), (1, 2, 2), (3, 0, 1), (2, 0, 1), (1, 0, 0), (4, 2, 1), (1, 1, 0)], + [(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)], + ] for i in range(6): M[i].extend(M[5 - i][1:8]) @@ -3783,7 +4037,16 @@ def DM_56_8_1(): w = F8.primitive_element() assert w**3 == w + 1 - M = [[(0, 0), (w**0, 0), (w**1, 0), (w**2, 0), (w**3, 0), (w**4, 0), (w**5, 0), (w**6, 0)], [(0, 1), (w**1, 6), (w**2, 1), (w**3, 1), (w**4, 6), (w**5, 1), (w**6, 6), (w**0, 6)], [(0, 4), (w**2, 3), (w**3, 4), (w**4, 4), (w**5, 3), (w**6, 4), (w**0, 3), (w**1, 3)], [(0, 2), (w**3, 5), (w**4, 2), (w**5, 2), (w**6, 5), (w**0, 2), (w**1, 5), (w**2, 5)], [(0, 2), (w**4, 5), (w**5, 2), (w**6, 2), (w**0, 5), (w**1, 2), (w**2, 5), (w**3, 5)], [(0, 4), (w**5, 3), (w**6, 4), (w**0, 4), (w**1, 3), (w**2, 4), (w**3, 3), (w**4, 3)], [(0, 1), (w**6, 6), (w**0, 1), (w**1, 1), (w**2, 6), (w**3, 1), (w**4, 6), (w**5, 6)], [(1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0)]] + M = [ + [(0, 0), (w**0, 0), (w**1, 0), (w**2, 0), (w**3, 0), (w**4, 0), (w**5, 0), (w**6, 0)], + [(0, 1), (w**1, 6), (w**2, 1), (w**3, 1), (w**4, 6), (w**5, 1), (w**6, 6), (w**0, 6)], + [(0, 4), (w**2, 3), (w**3, 4), (w**4, 4), (w**5, 3), (w**6, 4), (w**0, 3), (w**1, 3)], + [(0, 2), (w**3, 5), (w**4, 2), (w**5, 2), (w**6, 5), (w**0, 2), (w**1, 5), (w**2, 5)], + [(0, 2), (w**4, 5), (w**5, 2), (w**6, 2), (w**0, 5), (w**1, 2), (w**2, 5), (w**3, 5)], + [(0, 4), (w**5, 3), (w**6, 4), (w**0, 4), (w**1, 3), (w**2, 4), (w**3, 3), (w**4, 3)], + [(0, 1), (w**6, 6), (w**0, 1), (w**1, 1), (w**2, 6), (w**3, 1), (w**4, 6), (w**5, 6)], + [(1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0), (1, 0)], + ] Mb = [] @@ -3853,7 +4116,14 @@ def DM_60_6_1(): sage: _ = designs.difference_matrix(60,6) """ - M60 = [[(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)], [(1, 10), (1, 6), (0, 17), (0, 7), (1, 5), (0, 9), (0, 3), (1, 13), (1, 17), (0, 13)], [(1, 22), (1, 1), (1, 8), (0, 9), (1, 21), (1, 29), (1, 0), (0, 2), (0, 12), (1, 15)], [(1, 24), (1, 1), (0, 14), (0, 0), (0, 16), (0, 18), (0, 8), (0, 28), (0, 17), (0, 7)], [(0, 17), (0, 7), (0, 20), (0, 1), (1, 4), (0, 26), (0, 19), (0, 28), (1, 21), (0, 6)], [(1, 14), (1, 9), (0, 10), (0, 27), (1, 20), (0, 11), (0, 13), (1, 12), (0, 28), (1, 18)]] + M60 = [ + [(0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), (0, 0)], + [(1, 10), (1, 6), (0, 17), (0, 7), (1, 5), (0, 9), (0, 3), (1, 13), (1, 17), (0, 13)], + [(1, 22), (1, 1), (1, 8), (0, 9), (1, 21), (1, 29), (1, 0), (0, 2), (0, 12), (1, 15)], + [(1, 24), (1, 1), (0, 14), (0, 0), (0, 16), (0, 18), (0, 8), (0, 28), (0, 17), (0, 7)], + [(0, 17), (0, 7), (0, 20), (0, 1), (1, 4), (0, 26), (0, 19), (0, 28), (1, 21), (0, 6)], + [(1, 14), (1, 9), (0, 10), (0, 27), (1, 20), (0, 11), (0, 13), (1, 12), (0, 28), (1, 18)], + ] from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as AdditiveCyclic from sage.categories.cartesian_product import cartesian_product @@ -3899,7 +4169,16 @@ def DM_75_8_1(): F5 = FiniteField(5) G = cartesian_product((F3, F5, F5)) - M = [[(2, 0, 0), (0, 0, 0), (0, 0, 0), (1, 0, 0), (0, 0, 0), (1, 0, 0), (1, 0, 0), (0, 0, 0)], [(0, 2, 3), (1, 4, 4), (1, 1, 3), (1, 0, 4), (2, 4, 3), (0, 0, 3), (1, 4, 4), (0, 0, 0)], [(1, 3, 2), (2, 1, 1), (1, 4, 0), (0, 3, 0), (1, 0, 4), (2, 4, 1), (0, 1, 2), (0, 0, 0)], [(0, 2, 4), (1, 3, 1), (2, 0, 2), (0, 0, 1), (2, 4, 0), (1, 2, 2), (0, 0, 0), (0, 0, 0)], [(1, 1, 2), (2, 2, 3), (0, 3, 1), (1, 4, 2), (2, 1, 0), (1, 4, 3), (2, 4, 4), (0, 0, 0)], [(0, 1, 4), (0, 4, 4), (2, 4, 1), (1, 3, 0), (1, 3, 1), (2, 0, 0), (2, 4, 0), (0, 0, 0)], [(0, 4, 4), (2, 0, 1), (2, 3, 3), (2, 3, 2), (0, 0, 2), (2, 1, 2), (1, 4, 2), (0, 0, 0)], [(2, 4, 2), (2, 4, 1), (2, 3, 1), (1, 2, 2), (1, 3, 0), (0, 0, 2), (2, 4, 2), (0, 0, 0)]] + M = [ + [(2, 0, 0), (0, 0, 0), (0, 0, 0), (1, 0, 0), (0, 0, 0), (1, 0, 0), (1, 0, 0), (0, 0, 0)], + [(0, 2, 3), (1, 4, 4), (1, 1, 3), (1, 0, 4), (2, 4, 3), (0, 0, 3), (1, 4, 4), (0, 0, 0)], + [(1, 3, 2), (2, 1, 1), (1, 4, 0), (0, 3, 0), (1, 0, 4), (2, 4, 1), (0, 1, 2), (0, 0, 0)], + [(0, 2, 4), (1, 3, 1), (2, 0, 2), (0, 0, 1), (2, 4, 0), (1, 2, 2), (0, 0, 0), (0, 0, 0)], + [(1, 1, 2), (2, 2, 3), (0, 3, 1), (1, 4, 2), (2, 1, 0), (1, 4, 3), (2, 4, 4), (0, 0, 0)], + [(0, 1, 4), (0, 4, 4), (2, 4, 1), (1, 3, 0), (1, 3, 1), (2, 0, 0), (2, 4, 0), (0, 0, 0)], + [(0, 4, 4), (2, 0, 1), (2, 3, 3), (2, 3, 2), (0, 0, 2), (2, 1, 2), (1, 4, 2), (0, 0, 0)], + [(2, 4, 2), (2, 4, 1), (2, 3, 1), (1, 2, 2), (1, 3, 0), (0, 0, 2), (2, 4, 2), (0, 0, 0)], + ] for i in range(8): M[i].extend(M[7 - i][:7]) @@ -4373,7 +4652,11 @@ def BIBD_66_6_1(): sage: BalancedIncompleteBlockDesign(66, BIBD_66_6_1()) (66,6,1)-Balanced Incomplete Block Design """ - BIBD = [frozenset([(x + i * 5) % 65 if x < 65 else x for x in b]) for i in range(65) for b in [[6, 38, 42, 46, 53, 62], [9, 11, 21, 49, 56, 60], [18, 31, 37, 44, 52, 60], [0, 12, 29, 46, 51, 63], [0, 6, 21, 30, 43, 48], [4, 17, 22, 36, 47, 59], [0, 1, 2, 3, 4, 65], [23, 39, 44, 53, 59, 63], [12, 22, 28, 48, 55, 60], [19, 22, 25, 40, 49, 50], [4, 30, 37, 50, 58, 61]]] + BIBD = [ + frozenset([(x + i * 5) % 65 if x < 65 else x for x in b]) + for i in range(65) + for b in [[6, 38, 42, 46, 53, 62], [9, 11, 21, 49, 56, 60], [18, 31, 37, 44, 52, 60], [0, 12, 29, 46, 51, 63], [0, 6, 21, 30, 43, 48], [4, 17, 22, 36, 47, 59], [0, 1, 2, 3, 4, 65], [23, 39, 44, 53, 59, 63], [12, 22, 28, 48, 55, 60], [19, 22, 25, 40, 49, 50], [4, 30, 37, 50, 58, 61]] + ] return [list(t) for t in frozenset(BIBD)] @@ -4391,7 +4674,11 @@ def BIBD_76_6_1(): sage: BalancedIncompleteBlockDesign(76, BIBD_76_6_1()) (76,6,1)-Balanced Incomplete Block Design """ - BIBD = [frozenset([(x + i * 4) % 76 if x < 76 else x for x in b]) for i in range(76) for b in [[3, 5, 21, 33, 72, 73], [4, 37, 57, 58, 64, 75], [7, 14, 44, 47, 59, 63], [10, 20, 61, 63, 71, 72], [13, 26, 30, 39, 45, 67], [11, 21, 25, 30, 55, 58], [2, 5, 34, 52, 54, 70], [6, 8, 29, 48, 70, 71], [10, 15, 36, 41, 44, 56], [0, 6, 13, 27, 44, 72]]] + BIBD = [ + frozenset([(x + i * 4) % 76 if x < 76 else x for x in b]) + for i in range(76) + for b in [[3, 5, 21, 33, 72, 73], [4, 37, 57, 58, 64, 75], [7, 14, 44, 47, 59, 63], [10, 20, 61, 63, 71, 72], [13, 26, 30, 39, 45, 67], [11, 21, 25, 30, 55, 58], [2, 5, 34, 52, 54, 70], [6, 8, 29, 48, 70, 71], [10, 15, 36, 41, 44, 56], [0, 6, 13, 27, 44, 72]] + ] return [list(t) for t in frozenset(BIBD)] @@ -4426,7 +4713,15 @@ def BIBD_106_6_1(): sage: BalancedIncompleteBlockDesign(106, BIBD_106_6_1()) (106,6,1)-Balanced Incomplete Block Design """ - bibd = [((0, 0), (1, 0), (3, 0), (11, 0), (38, 0), (0, 1)), ((0, 0), (13, 0), (30, 0), (23, 1), (35, 1), (51, 1)), ((0, 0), (5, 0), (19, 0), (25, 0), (36, 1), (39, 1)), ((0, 0), (4, 0), (28, 1), (30, 1), (37, 1), (47, 1)), ((0, 0), (7, 0), (29, 0), (8, 1), (16, 1), (48, 1)), ((0, 0), (2, 1), (7, 1), (25, 1), (29, 1), (49, 1)), ((0, 0), (9, 0), (21, 0), (12, 1), (13, 1), (27, 1))] + bibd = [ + ((0, 0), (1, 0), (3, 0), (11, 0), (38, 0), (0, 1)), + ((0, 0), (13, 0), (30, 0), (23, 1), (35, 1), (51, 1)), + ((0, 0), (5, 0), (19, 0), (25, 0), (36, 1), (39, 1)), + ((0, 0), (4, 0), (28, 1), (30, 1), (37, 1), (47, 1)), + ((0, 0), (7, 0), (29, 0), (8, 1), (16, 1), (48, 1)), + ((0, 0), (2, 1), (7, 1), (25, 1), (29, 1), (49, 1)), + ((0, 0), (9, 0), (21, 0), (12, 1), (13, 1), (27, 1)), + ] return [[((x + i) % 53 + y * 53) for x, y in B] for i in range(53) for B in bibd] @@ -4447,7 +4742,15 @@ def BIBD_111_6_1(): from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from .incidence_structures import IncidenceStructure - bibd = [((0, 0), (1, 0), (3, 0), (7, 0), (17, 0), (0, 1)), ((0, 0), (5, 0), (19, 1), (28, 1), (10, 2), (30, 2)), ((5, 0), (33, 0), (13, 1), (34, 1), (19, 2), (7, 2)), ((9, 0), (27, 0), (16, 1), (11, 1), (12, 2), (36, 2)), ((10, 0), (23, 0), (26, 1), (8, 1), (1, 2), (6, 2)), ((13, 0), (24, 0), (19, 1), (18, 1), (5, 2), (32, 2)), ((26, 0), (34, 0), (1, 1), (7, 1), (10, 2), (33, 2))] + bibd = [ + ((0, 0), (1, 0), (3, 0), (7, 0), (17, 0), (0, 1)), + ((0, 0), (5, 0), (19, 1), (28, 1), (10, 2), (30, 2)), + ((5, 0), (33, 0), (13, 1), (34, 1), (19, 2), (7, 2)), + ((9, 0), (27, 0), (16, 1), (11, 1), (12, 2), (36, 2)), + ((10, 0), (23, 0), (26, 1), (8, 1), (1, 2), (6, 2)), + ((13, 0), (24, 0), (19, 1), (18, 1), (5, 2), (32, 2)), + ((26, 0), (34, 0), (1, 1), (7, 1), (10, 2), (33, 2)), + ] gens = lambda B: [frozenset(((x * 10) % 37, (y + 1) % 3) for x, y in B), frozenset(((x + 1) % 37, y) for x, y in B)] bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], successors=gens) return IncidenceStructure(bibd)._blocks @@ -4468,7 +4771,11 @@ def BIBD_126_6_1(): """ from itertools import product - bibd = [[((x + xx) % 5, (y + yy) % 5, (z + zz) % 5) for x, y, z in B] for xx, yy, zz in product(range(5), repeat=3) for B in [[(0, 0, 1), (0, 0, 4), (1, 2, 2), (1, 3, 3), (4, 2, 1), (4, 3, 4)], [(0, 0, 2), (0, 0, 3), (1, 4, 4), (1, 1, 1), (4, 4, 2), (4, 1, 3)], [(0, 4, 3), (0, 1, 2), (2, 2, 0), (2, 3, 0), (3, 3, 2), (3, 2, 3)], [(0, 3, 1), (0, 2, 4), (2, 4, 0), (2, 1, 0), (3, 1, 4), (3, 4, 1)]]] + bibd = [ + [((x + xx) % 5, (y + yy) % 5, (z + zz) % 5) for x, y, z in B] + for xx, yy, zz in product(range(5), repeat=3) + for B in [[(0, 0, 1), (0, 0, 4), (1, 2, 2), (1, 3, 3), (4, 2, 1), (4, 3, 4)], [(0, 0, 2), (0, 0, 3), (1, 4, 4), (1, 1, 1), (4, 4, 2), (4, 1, 3)], [(0, 4, 3), (0, 1, 2), (2, 2, 0), (2, 3, 0), (3, 3, 2), (3, 2, 3)], [(0, 3, 1), (0, 2, 4), (2, 4, 0), (2, 1, 0), (3, 1, 4), (3, 4, 1)]] + ] bibd.extend([[(125, 0, 0), (0, x, y), (1, x, y), (2, x, y), (3, x, y), (4, x, y)] for x, y in product(range(5), repeat=2)]) return [[x + y * 5 + z * 25 for x, y, z in B] for B in bibd] @@ -4491,7 +4798,14 @@ def BIBD_136_6_1(): from .incidence_structures import IncidenceStructure inf = (None, None) - bibd = [((0, 0), (3, 0), (15, 0), (35, 0), (6, 2), (10, 2)), ((0, 0), (22, 0), (11, 1), (30, 1), (1, 2), (18, 2)), ((0, 0), (5, 0), (18, 1), (41, 1), (13, 2), (42, 2)), ((0, 0), (11, 0), (17, 0), (4, 2), (5, 2), (28, 2)), ((0, 0), (1, 0), (0, 1), (16, 1), (0, 2), (31, 2)), (inf, (0, 0), (9, 0), (18, 0), (27, 0), (36, 0))] + bibd = [ + ((0, 0), (3, 0), (15, 0), (35, 0), (6, 2), (10, 2)), + ((0, 0), (22, 0), (11, 1), (30, 1), (1, 2), (18, 2)), + ((0, 0), (5, 0), (18, 1), (41, 1), (13, 2), (42, 2)), + ((0, 0), (11, 0), (17, 0), (4, 2), (5, 2), (28, 2)), + ((0, 0), (1, 0), (0, 1), (16, 1), (0, 2), (31, 2)), + (inf, (0, 0), (9, 0), (18, 0), (27, 0), (36, 0)), + ] gens = lambda B: [frozenset(((x * 16) % 45, (y + 1) % 3) if (x, y) != inf else inf for x, y in B), frozenset(((x + 1) % 45, y) if (x, y) != inf else inf for x, y in B)] bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], successors=gens) return IncidenceStructure(bibd)._blocks @@ -4515,7 +4829,16 @@ def BIBD_141_6_1(): a = 'a' inf = (None, None) - bibd = [((0, 0), (16, 0), (24, 0), (24, 1), (15, 2), (25, 2)), ((0, 0), (3, 0), (26, 0), (13, 1), (33, 1), (34, a)), ((0, 0), (13, 0), (18, 0), (15, 1), (7, 2), (0, a)), ((0, 0), (2, 0), (14, 1), (23, 1), (26, a), (32, a)), ((0, 0), (4, 0), (29, 1), (6, 2), (9, a), (20, a)), ((0, 0), (1, 0), (12, 2), (2, a), (4, a), (19, a)), (inf, (0, 0), (7, 0), (14, 0), (21, 0), (28, 0)), (inf, (0, a), (7, a), (14, a), (21, a), (28, a))] + bibd = [ + ((0, 0), (16, 0), (24, 0), (24, 1), (15, 2), (25, 2)), + ((0, 0), (3, 0), (26, 0), (13, 1), (33, 1), (34, a)), + ((0, 0), (13, 0), (18, 0), (15, 1), (7, 2), (0, a)), + ((0, 0), (2, 0), (14, 1), (23, 1), (26, a), (32, a)), + ((0, 0), (4, 0), (29, 1), (6, 2), (9, a), (20, a)), + ((0, 0), (1, 0), (12, 2), (2, a), (4, a), (19, a)), + (inf, (0, 0), (7, 0), (14, 0), (21, 0), (28, 0)), + (inf, (0, a), (7, a), (14, a), (21, a), (28, a)), + ] gens = lambda B: [frozenset(((x * 16) % 35, (y + 1) % 3 if y != a else a) if (x, y) != inf else inf for x, y in B), frozenset(((x + 1) % 35, y) if (x, y) != inf else inf for x, y in B)] bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], successors=gens) @@ -4538,7 +4861,15 @@ def BIBD_171_6_1(): from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from .incidence_structures import IncidenceStructure - bibd = [((0, 0), (19, 0), (39, 0), (41, 0), (14, 1), (38, 2)), ((0, 0), (21, 0), (44, 0), (48, 0), (26, 1), (11, 2)), ((0, 0), (1, 0), (43, 0), (8, 2), (15, 2), (44, 2)), ((0, 0), (3, 0), (31, 0), (23, 1), (43, 1), (36, 2)), ((0, 0), (40, 0), (50, 0), (11, 1), (25, 2), (34, 2)), ((0, 0), (12, 0), (0, 1), (27, 1), (0, 2), (18, 2)), ((37, 0), (42, 0), (31, 1), (9, 1), (46, 2), (6, 2))] + bibd = [ + ((0, 0), (19, 0), (39, 0), (41, 0), (14, 1), (38, 2)), + ((0, 0), (21, 0), (44, 0), (48, 0), (26, 1), (11, 2)), + ((0, 0), (1, 0), (43, 0), (8, 2), (15, 2), (44, 2)), + ((0, 0), (3, 0), (31, 0), (23, 1), (43, 1), (36, 2)), + ((0, 0), (40, 0), (50, 0), (11, 1), (25, 2), (34, 2)), + ((0, 0), (12, 0), (0, 1), (27, 1), (0, 2), (18, 2)), + ((37, 0), (42, 0), (31, 1), (9, 1), (46, 2), (6, 2)), + ] gens = lambda B: [frozenset(((x * 7) % 57, (y + 1) % 3) for x, y in B), frozenset(((x + 1) % 57, y) for x, y in B)] bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], successors=gens) @@ -4619,7 +4950,18 @@ def BIBD_196_6_1(): from .incidence_structures import IncidenceStructure a = 'a' - bibd = [((0, 0), (2, 0), (12, 0), (45, 0), (3, 1), (11, a)), ((0, 0), (3, 0), (8, 0), (5, 1), (17, 1), (39, a)), ((0, 0), (9, 0), (36, 0), (24, 1), (44, 1), (37, a)), ((0, 0), (15, 0), (34, 1), (41, 1), (47, 2), (18, a)), ((0, 0), (7, 0), (31, 0), (13, 1), (35, 2), (41, a)), ((0, 0), (14, 0), (32, 1), (10, 2), (22, a), (44, a)), ((0, 0), (23, 0), (21, 1), (39, 1), (19, a), (25, a)), ((0, 0), (33, 1), (0, a), (5, a), (29, a), (47, a)), ((0, 0), (1, 0), (0, 1), (30, 1), (0, 2), (18, 2)), ((8, 0), (19, 0), (44, 1), (31, 1), (46, 2), (48, 2))] + bibd = [ + ((0, 0), (2, 0), (12, 0), (45, 0), (3, 1), (11, a)), + ((0, 0), (3, 0), (8, 0), (5, 1), (17, 1), (39, a)), + ((0, 0), (9, 0), (36, 0), (24, 1), (44, 1), (37, a)), + ((0, 0), (15, 0), (34, 1), (41, 1), (47, 2), (18, a)), + ((0, 0), (7, 0), (31, 0), (13, 1), (35, 2), (41, a)), + ((0, 0), (14, 0), (32, 1), (10, 2), (22, a), (44, a)), + ((0, 0), (23, 0), (21, 1), (39, 1), (19, a), (25, a)), + ((0, 0), (33, 1), (0, a), (5, a), (29, a), (47, a)), + ((0, 0), (1, 0), (0, 1), (30, 1), (0, 2), (18, 2)), + ((8, 0), (19, 0), (44, 1), (31, 1), (46, 2), (48, 2)), + ] gens = lambda B: [frozenset(((x * 30) % 49, (y + 1) % 3 if y != a else a) for x, y in B), frozenset(((x + 1) % 49, y) for x, y in B)] bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], successors=gens) @@ -4642,7 +4984,16 @@ def BIBD_201_6_1(): from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet from .incidence_structures import IncidenceStructure - bibd = [((0, 0), (1, 0), (4, 2), (9, 2), (34, 2), (62, 2)), ((0, 1), (2, 1), (15, 1), (8, 2), (27, 2), (49, 2)), ((0, 0), (3, 0), (22, 0), (54, 1), (13, 2), (40, 2)), ((0, 0), (36, 0), (40, 0), (31, 1), (34, 1), (5, 2)), ((0, 0), (50, 0), (55, 0), (6, 1), (24, 1), (26, 2)), ((0, 0), (2, 0), (3, 1), (14, 1), (35, 1), (25, 2)), ((3, 1), (20, 1), (44, 1), (36, 2), (39, 2), (59, 2)), ((0, 0), (0, 1), (30, 1), (38, 1), (66, 1), (0, 2))] + bibd = [ + ((0, 0), (1, 0), (4, 2), (9, 2), (34, 2), (62, 2)), + ((0, 1), (2, 1), (15, 1), (8, 2), (27, 2), (49, 2)), + ((0, 0), (3, 0), (22, 0), (54, 1), (13, 2), (40, 2)), + ((0, 0), (36, 0), (40, 0), (31, 1), (34, 1), (5, 2)), + ((0, 0), (50, 0), (55, 0), (6, 1), (24, 1), (26, 2)), + ((0, 0), (2, 0), (3, 1), (14, 1), (35, 1), (25, 2)), + ((3, 1), (20, 1), (44, 1), (36, 2), (39, 2), (59, 2)), + ((0, 0), (0, 1), (30, 1), (38, 1), (66, 1), (0, 2)), + ] gens = lambda B: [frozenset(((x * 29) % 67, y) for x, y in B), frozenset(((x + 1) % 67, y) for x, y in B)] bibd = RecursivelyEnumeratedSet([frozenset(e) for e in bibd], successors=gens) @@ -5128,7 +5479,21 @@ def ca_13_2_9_3(): True """ - return [[0, 0, 0, 2, 0, 2, 2, 2, 0], [0, 0, 2, 0, 1, 1, 1, 2, 1], [0, 1, 1, 1, 2, 0, 1, 2, 0], [0, 1, 2, 1, 0, 1, 2, 0, 2], [0, 2, 2, 2, 2, 1, 0, 1, 0], [1, 0, 1, 0, 2, 1, 2, 0, 0], [1, 0, 2, 1, 2, 2, 0, 2, 2], [1, 1, 0, 0, 0, 0, 0, 1, 1], [1, 2, 0, 2, 1, 0, 1, 0, 2], [2, 0, 2, 1, 1, 0, 2, 1, 0], [2, 1, 1, 2, 1, 2, 0, 0, 1], [2, 2, 0, 1, 2, 1, 2, 2, 1], [2, 2, 1, 0, 0, 2, 1, 1, 2]] + return [ + [0, 0, 0, 2, 0, 2, 2, 2, 0], + [0, 0, 2, 0, 1, 1, 1, 2, 1], + [0, 1, 1, 1, 2, 0, 1, 2, 0], + [0, 1, 2, 1, 0, 1, 2, 0, 2], + [0, 2, 2, 2, 2, 1, 0, 1, 0], + [1, 0, 1, 0, 2, 1, 2, 0, 0], + [1, 0, 2, 1, 2, 2, 0, 2, 2], + [1, 1, 0, 0, 0, 0, 0, 1, 1], + [1, 2, 0, 2, 1, 0, 1, 0, 2], + [2, 0, 2, 1, 1, 0, 2, 1, 0], + [2, 1, 1, 2, 1, 2, 0, 0, 1], + [2, 2, 0, 1, 2, 1, 2, 2, 1], + [2, 2, 1, 0, 0, 2, 1, 1, 2], + ] def ca_14_2_10_3(): @@ -5146,7 +5511,22 @@ def ca_14_2_10_3(): True """ - return [[0, 0, 0, 0, 2, 2, 2, 1, 1, 0], [0, 0, 0, 2, 1, 0, 0, 2, 1, 1], [0, 0, 1, 1, 1, 2, 1, 0, 2, 2], [0, 1, 0, 2, 0, 1, 2, 0, 1, 2], [0, 2, 2, 2, 1, 2, 2, 1, 0, 0], [1, 0, 2, 1, 0, 1, 1, 1, 1, 1], [1, 1, 1, 2, 1, 1, 1, 2, 2, 0], [1, 1, 2, 0, 0, 2, 2, 2, 2, 1], [1, 1, 2, 1, 0, 0, 0, 0, 0, 0], [1, 2, 0, 1, 2, 0, 1, 2, 2, 2], [2, 0, 0, 0, 1, 0, 1, 2, 0, 2], [2, 1, 2, 2, 2, 2, 0, 1, 2, 2], [2, 2, 1, 0, 2, 1, 0, 0, 0, 1], [2, 2, 1, 1, 0, 0, 2, 1, 1, 0]] + return [ + [0, 0, 0, 0, 2, 2, 2, 1, 1, 0], + [0, 0, 0, 2, 1, 0, 0, 2, 1, 1], + [0, 0, 1, 1, 1, 2, 1, 0, 2, 2], + [0, 1, 0, 2, 0, 1, 2, 0, 1, 2], + [0, 2, 2, 2, 1, 2, 2, 1, 0, 0], + [1, 0, 2, 1, 0, 1, 1, 1, 1, 1], + [1, 1, 1, 2, 1, 1, 1, 2, 2, 0], + [1, 1, 2, 0, 0, 2, 2, 2, 2, 1], + [1, 1, 2, 1, 0, 0, 0, 0, 0, 0], + [1, 2, 0, 1, 2, 0, 1, 2, 2, 2], + [2, 0, 0, 0, 1, 0, 1, 2, 0, 2], + [2, 1, 2, 2, 2, 2, 0, 1, 2, 2], + [2, 2, 1, 0, 2, 1, 0, 0, 0, 1], + [2, 2, 1, 1, 0, 0, 2, 1, 1, 0], + ] def ca_15_2_20_3(): @@ -5164,7 +5544,23 @@ def ca_15_2_20_3(): True """ - return [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [0, 1, 1, 1, 1, 0, 1, 2, 2, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2], [0, 2, 2, 2, 2, 2, 2, 0, 1, 0, 0, 0, 0, 1, 2, 2, 0, 1, 1, 1], [1, 0, 1, 1, 1, 2, 2, 0, 1, 0, 1, 1, 2, 0, 0, 1, 1, 0, 1, 2], [1, 1, 2, 2, 2, 1, 0, 1, 0, 2, 1, 1, 0, 0, 2, 1, 2, 2, 1, 0], [1, 2, 0, 1, 2, 0, 2, 1, 0, 2, 0, 2, 2, 1, 0, 2, 1, 0, 2, 1], [1, 2, 1, 0, 2, 2, 1, 2, 0, 1, 2, 1, 1, 0, 1, 2, 0, 2, 0, 1], [1, 2, 1, 2, 0, 2, 1, 1, 2, 2, 1, 0, 1, 2, 0, 0, 2, 1, 0, 0], [2, 0, 2, 2, 2, 0, 1, 2, 2, 1, 2, 2, 0, 2, 2, 0, 1, 0, 1, 2], [2, 1, 0, 2, 1, 2, 0, 2, 2, 2, 1, 2, 2, 0, 1, 2, 0, 1, 2, 0], [2, 1, 2, 0, 1, 1, 2, 0, 2, 1, 0, 1, 1, 2, 1, 0, 2, 0, 2, 1], [2, 1, 2, 1, 0, 1, 2, 2, 1, 1, 2, 0, 2, 1, 0, 0, 1, 2, 0, 0], [2, 2, 1, 1, 1, 1, 0, 1, 0, 0, 2, 2, 1, 2, 2, 1, 0, 1, 0, 2]] + return [ + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], + [0, 1, 1, 1, 1, 0, 1, 2, 2, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2], + [0, 2, 2, 2, 2, 2, 2, 0, 1, 0, 0, 0, 0, 1, 2, 2, 0, 1, 1, 1], + [1, 0, 1, 1, 1, 2, 2, 0, 1, 0, 1, 1, 2, 0, 0, 1, 1, 0, 1, 2], + [1, 1, 2, 2, 2, 1, 0, 1, 0, 2, 1, 1, 0, 0, 2, 1, 2, 2, 1, 0], + [1, 2, 0, 1, 2, 0, 2, 1, 0, 2, 0, 2, 2, 1, 0, 2, 1, 0, 2, 1], + [1, 2, 1, 0, 2, 2, 1, 2, 0, 1, 2, 1, 1, 0, 1, 2, 0, 2, 0, 1], + [1, 2, 1, 2, 0, 2, 1, 1, 2, 2, 1, 0, 1, 2, 0, 0, 2, 1, 0, 0], + [2, 0, 2, 2, 2, 0, 1, 2, 2, 1, 2, 2, 0, 2, 2, 0, 1, 0, 1, 2], + [2, 1, 0, 2, 1, 2, 0, 2, 2, 2, 1, 2, 2, 0, 1, 2, 0, 1, 2, 0], + [2, 1, 2, 0, 1, 1, 2, 0, 2, 1, 0, 1, 1, 2, 1, 0, 2, 0, 2, 1], + [2, 1, 2, 1, 0, 1, 2, 2, 1, 1, 2, 0, 2, 1, 0, 0, 1, 2, 0, 0], + [2, 2, 1, 1, 1, 1, 0, 1, 0, 0, 2, 2, 1, 2, 2, 1, 0, 1, 0, 2], + ] def ca_19_2_6_4(): @@ -5182,7 +5578,27 @@ def ca_19_2_6_4(): True """ - return [[0, 0, 0, 2, 0, 0], [0, 0, 1, 0, 1, 1], [0, 1, 3, 1, 2, 1], [0, 2, 2, 3, 0, 2], [0, 3, 3, 2, 3, 3], [1, 0, 3, 1, 1, 2], [1, 1, 0, 3, 1, 3], [1, 1, 2, 0, 3, 0], [1, 2, 1, 2, 2, 0], [1, 3, 1, 3, 0, 1], [2, 0, 2, 3, 2, 3], [2, 1, 1, 2, 3, 2], [2, 2, 0, 1, 3, 1], [2, 2, 3, 0, 0, 3], [2, 3, 2, 1, 1, 0], [3, 0, 3, 3, 3, 0], [3, 1, 1, 1, 0, 3], [3, 2, 2, 2, 1, 1], [3, 3, 0, 0, 2, 2]] + return [ + [0, 0, 0, 2, 0, 0], + [0, 0, 1, 0, 1, 1], + [0, 1, 3, 1, 2, 1], + [0, 2, 2, 3, 0, 2], + [0, 3, 3, 2, 3, 3], + [1, 0, 3, 1, 1, 2], + [1, 1, 0, 3, 1, 3], + [1, 1, 2, 0, 3, 0], + [1, 2, 1, 2, 2, 0], + [1, 3, 1, 3, 0, 1], + [2, 0, 2, 3, 2, 3], + [2, 1, 1, 2, 3, 2], + [2, 2, 0, 1, 3, 1], + [2, 2, 3, 0, 0, 3], + [2, 3, 2, 1, 1, 0], + [3, 0, 3, 3, 3, 0], + [3, 1, 1, 1, 0, 3], + [3, 2, 2, 2, 1, 1], + [3, 3, 0, 0, 2, 2], + ] def ca_21_2_7_4(): @@ -5201,7 +5617,29 @@ def ca_21_2_7_4(): True """ - return [[0, 0, 1, 0, 0, 0, 0], [0, 0, 3, 1, 1, 1, 1], [0, 1, 1, 2, 2, 2, 2], [0, 1, 2, 3, 0, 1, 3], [0, 2, 0, 3, 3, 0, 2], [0, 3, 1, 3, 3, 3, 1], [1, 0, 0, 3, 2, 3, 3], [1, 1, 3, 1, 3, 3, 0], [1, 2, 1, 2, 1, 0, 3], [1, 2, 3, 2, 0, 2, 1], [1, 3, 2, 0, 1, 1, 2], [2, 0, 3, 0, 3, 2, 3], [2, 1, 2, 1, 2, 0, 1], [2, 2, 1, 1, 0, 3, 2], [2, 2, 2, 3, 1, 2, 0], [2, 3, 0, 2, 3, 1, 0], [3, 0, 2, 2, 3, 3, 2], [3, 1, 0, 0, 1, 3, 1], [3, 2, 1, 0, 2, 1, 0], [3, 3, 0, 1, 0, 2, 3], [3, 3, 3, 3, 2, 0, 2]] + return [ + [0, 0, 1, 0, 0, 0, 0], + [0, 0, 3, 1, 1, 1, 1], + [0, 1, 1, 2, 2, 2, 2], + [0, 1, 2, 3, 0, 1, 3], + [0, 2, 0, 3, 3, 0, 2], + [0, 3, 1, 3, 3, 3, 1], + [1, 0, 0, 3, 2, 3, 3], + [1, 1, 3, 1, 3, 3, 0], + [1, 2, 1, 2, 1, 0, 3], + [1, 2, 3, 2, 0, 2, 1], + [1, 3, 2, 0, 1, 1, 2], + [2, 0, 3, 0, 3, 2, 3], + [2, 1, 2, 1, 2, 0, 1], + [2, 2, 1, 1, 0, 3, 2], + [2, 2, 2, 3, 1, 2, 0], + [2, 3, 0, 2, 3, 1, 0], + [3, 0, 2, 2, 3, 3, 2], + [3, 1, 0, 0, 1, 3, 1], + [3, 2, 1, 0, 2, 1, 0], + [3, 3, 0, 1, 0, 2, 3], + [3, 3, 3, 3, 2, 0, 2], + ] def ca_29_2_7_5(): @@ -5219,7 +5657,37 @@ def ca_29_2_7_5(): True """ - return [[0, 2, 2, 3, 0, 0, 0], [1, 4, 3, 4, 2, 3, 0], [2, 3, 0, 0, 4, 2, 0], [3, 0, 1, 2, 3, 4, 0], [4, 1, 4, 1, 1, 1, 0], [0, 0, 2, 4, 1, 2, 1], [1, 2, 4, 0, 2, 4, 1], [1, 3, 1, 2, 1, 0, 1], [2, 1, 2, 2, 4, 3, 1], [3, 3, 3, 1, 0, 1, 1], [4, 4, 0, 3, 3, 0, 1], [0, 1, 3, 0, 3, 0, 2], [1, 0, 3, 3, 4, 1, 2], [2, 2, 1, 4, 3, 1, 2], [2, 4, 4, 2, 0, 2, 2], [3, 2, 0, 1, 1, 3, 2], [4, 3, 2, 4, 2, 4, 2], [0, 3, 4, 3, 3, 3, 3], [1, 1, 0, 4, 0, 4, 3], [2, 0, 4, 1, 2, 0, 3], [3, 1, 1, 3, 2, 2, 3], [3, 4, 2, 0, 1, 1, 3], [4, 2, 3, 2, 4, 2, 3], [0, 0, 0, 2, 2, 1, 4], [0, 4, 1, 1, 4, 4, 4], [1, 1, 2, 1, 3, 2, 4], [2, 2, 3, 3, 1, 4, 4], [3, 3, 4, 4, 4, 0, 4], [4, 0, 1, 0, 0, 3, 4]] + return [ + [0, 2, 2, 3, 0, 0, 0], + [1, 4, 3, 4, 2, 3, 0], + [2, 3, 0, 0, 4, 2, 0], + [3, 0, 1, 2, 3, 4, 0], + [4, 1, 4, 1, 1, 1, 0], + [0, 0, 2, 4, 1, 2, 1], + [1, 2, 4, 0, 2, 4, 1], + [1, 3, 1, 2, 1, 0, 1], + [2, 1, 2, 2, 4, 3, 1], + [3, 3, 3, 1, 0, 1, 1], + [4, 4, 0, 3, 3, 0, 1], + [0, 1, 3, 0, 3, 0, 2], + [1, 0, 3, 3, 4, 1, 2], + [2, 2, 1, 4, 3, 1, 2], + [2, 4, 4, 2, 0, 2, 2], + [3, 2, 0, 1, 1, 3, 2], + [4, 3, 2, 4, 2, 4, 2], + [0, 3, 4, 3, 3, 3, 3], + [1, 1, 0, 4, 0, 4, 3], + [2, 0, 4, 1, 2, 0, 3], + [3, 1, 1, 3, 2, 2, 3], + [3, 4, 2, 0, 1, 1, 3], + [4, 2, 3, 2, 4, 2, 3], + [0, 0, 0, 2, 2, 1, 4], + [0, 4, 1, 1, 4, 4, 4], + [1, 1, 2, 1, 3, 2, 4], + [2, 2, 3, 3, 1, 4, 4], + [3, 3, 4, 4, 4, 0, 4], + [4, 0, 1, 0, 0, 3, 4], + ] def ca_37_2_4_6(): @@ -5237,7 +5705,45 @@ def ca_37_2_4_6(): True """ - return [[0, 0, 1, 0], [0, 0, 2, 1], [0, 1, 0, 2], [0, 2, 0, 5], [0, 3, 3, 3], [0, 4, 4, 4], [0, 5, 5, 5], [1, 0, 0, 4], [1, 1, 1, 5], [1, 2, 3, 1], [1, 3, 4, 0], [1, 4, 5, 3], [1, 5, 2, 2], [2, 0, 0, 3], [2, 1, 4, 1], [2, 2, 5, 4], [2, 3, 1, 2], [2, 4, 2, 5], [2, 5, 3, 0], [3, 0, 5, 2], [3, 1, 3, 4], [3, 2, 2, 0], [3, 3, 0, 5], [3, 4, 1, 1], [3, 5, 4, 3], [4, 0, 3, 5], [4, 1, 2, 3], [4, 2, 4, 2], [4, 3, 5, 1], [4, 4, 0, 0], [4, 5, 1, 4], [5, 0, 4, 5], [5, 1, 5, 0], [5, 2, 1, 3], [5, 3, 2, 4], [5, 4, 3, 2], [5, 5, 0, 1]] + return [ + [0, 0, 1, 0], + [0, 0, 2, 1], + [0, 1, 0, 2], + [0, 2, 0, 5], + [0, 3, 3, 3], + [0, 4, 4, 4], + [0, 5, 5, 5], + [1, 0, 0, 4], + [1, 1, 1, 5], + [1, 2, 3, 1], + [1, 3, 4, 0], + [1, 4, 5, 3], + [1, 5, 2, 2], + [2, 0, 0, 3], + [2, 1, 4, 1], + [2, 2, 5, 4], + [2, 3, 1, 2], + [2, 4, 2, 5], + [2, 5, 3, 0], + [3, 0, 5, 2], + [3, 1, 3, 4], + [3, 2, 2, 0], + [3, 3, 0, 5], + [3, 4, 1, 1], + [3, 5, 4, 3], + [4, 0, 3, 5], + [4, 1, 2, 3], + [4, 2, 4, 2], + [4, 3, 5, 1], + [4, 4, 0, 0], + [4, 5, 1, 4], + [5, 0, 4, 5], + [5, 1, 5, 0], + [5, 2, 1, 3], + [5, 3, 2, 4], + [5, 4, 3, 2], + [5, 5, 0, 1], + ] def ca_39_2_5_6(): @@ -5255,7 +5761,47 @@ def ca_39_2_5_6(): True """ - return [[0, 0, 1, 1, 0], [1, 5, 2, 2, 0], [2, 4, 5, 4, 0], [3, 2, 0, 3, 0], [4, 3, 4, 5, 0], [5, 1, 3, 0, 0], [0, 4, 4, 3, 1], [1, 3, 5, 0, 1], [2, 2, 1, 2, 1], [3, 0, 3, 5, 1], [4, 1, 2, 1, 1], [5, 5, 0, 4, 1], [0, 5, 5, 5, 2], [1, 1, 1, 3, 2], [2, 3, 0, 1, 2], [3, 4, 2, 0, 2], [4, 2, 3, 4, 2], [5, 0, 4, 2, 2], [0, 1, 0, 4, 3], [0, 3, 3, 2, 3], [1, 0, 2, 4, 3], [2, 2, 4, 0, 3], [3, 5, 4, 1, 3], [4, 0, 5, 3, 3], [5, 4, 1, 5, 3], [0, 0, 0, 0, 4], [1, 2, 0, 5, 4], [1, 4, 3, 1, 4], [2, 1, 4, 4, 4], [3, 1, 5, 2, 4], [4, 5, 1, 0, 4], [5, 3, 2, 3, 4], [0, 2, 2, 0, 5], [1, 1, 4, 5, 5], [2, 0, 2, 5, 5], [2, 5, 3, 3, 5], [3, 3, 1, 4, 5], [4, 4, 0, 2, 5], [5, 2, 5, 1, 5]] + return [ + [0, 0, 1, 1, 0], + [1, 5, 2, 2, 0], + [2, 4, 5, 4, 0], + [3, 2, 0, 3, 0], + [4, 3, 4, 5, 0], + [5, 1, 3, 0, 0], + [0, 4, 4, 3, 1], + [1, 3, 5, 0, 1], + [2, 2, 1, 2, 1], + [3, 0, 3, 5, 1], + [4, 1, 2, 1, 1], + [5, 5, 0, 4, 1], + [0, 5, 5, 5, 2], + [1, 1, 1, 3, 2], + [2, 3, 0, 1, 2], + [3, 4, 2, 0, 2], + [4, 2, 3, 4, 2], + [5, 0, 4, 2, 2], + [0, 1, 0, 4, 3], + [0, 3, 3, 2, 3], + [1, 0, 2, 4, 3], + [2, 2, 4, 0, 3], + [3, 5, 4, 1, 3], + [4, 0, 5, 3, 3], + [5, 4, 1, 5, 3], + [0, 0, 0, 0, 4], + [1, 2, 0, 5, 4], + [1, 4, 3, 1, 4], + [2, 1, 4, 4, 4], + [3, 1, 5, 2, 4], + [4, 5, 1, 0, 4], + [5, 3, 2, 3, 4], + [0, 2, 2, 0, 5], + [1, 1, 4, 5, 5], + [2, 0, 2, 5, 5], + [2, 5, 3, 3, 5], + [3, 3, 1, 4, 5], + [4, 4, 0, 2, 5], + [5, 2, 5, 1, 5], + ] def ca_41_2_6_6(): @@ -5274,7 +5820,49 @@ def ca_41_2_6_6(): True """ - return [[0, 0, 0, 0, 0, 0], [1, 1, 4, 5, 4, 0], [2, 3, 3, 5, 2, 0], [3, 0, 2, 3, 3, 0], [3, 5, 5, 2, 1, 0], [4, 2, 1, 4, 5, 0], [5, 4, 4, 1, 1, 0], [0, 0, 1, 1, 1, 1], [1, 2, 5, 1, 2, 1], [2, 4, 4, 3, 5, 1], [2, 5, 2, 4, 0, 1], [3, 1, 3, 0, 4, 1], [4, 4, 0, 5, 3, 1], [5, 3, 1, 2, 0, 1], [0, 1, 2, 2, 2, 2], [1, 3, 1, 3, 4, 2], [1, 5, 4, 0, 3, 2], [2, 0, 5, 5, 1, 2], [3, 3, 0, 1, 5, 2], [4, 4, 3, 2, 0, 2], [5, 2, 3, 4, 3, 2], [0, 2, 3, 3, 1, 3], [0, 5, 1, 5, 5, 3], [1, 4, 2, 1, 0, 3], [2, 2, 0, 2, 4, 3], [3, 3, 5, 4, 3, 3], [4, 0, 4, 4, 2, 3], [5, 1, 5, 0, 5, 3], [0, 3, 4, 2, 3, 4], [1, 1, 0, 4, 1, 4], [2, 2, 2, 0, 5, 4], [3, 4, 1, 0, 2, 4], [4, 1, 5, 3, 0, 4], [4, 5, 3, 1, 4, 4], [5, 0, 2, 5, 4, 4], [0, 4, 5, 4, 4, 5], [1, 0, 3, 2, 5, 5], [2, 1, 1, 1, 3, 5], [3, 2, 4, 5, 0, 5], [4, 3, 2, 0, 1, 5], [5, 5, 0, 3, 2, 5]] + return [ + [0, 0, 0, 0, 0, 0], + [1, 1, 4, 5, 4, 0], + [2, 3, 3, 5, 2, 0], + [3, 0, 2, 3, 3, 0], + [3, 5, 5, 2, 1, 0], + [4, 2, 1, 4, 5, 0], + [5, 4, 4, 1, 1, 0], + [0, 0, 1, 1, 1, 1], + [1, 2, 5, 1, 2, 1], + [2, 4, 4, 3, 5, 1], + [2, 5, 2, 4, 0, 1], + [3, 1, 3, 0, 4, 1], + [4, 4, 0, 5, 3, 1], + [5, 3, 1, 2, 0, 1], + [0, 1, 2, 2, 2, 2], + [1, 3, 1, 3, 4, 2], + [1, 5, 4, 0, 3, 2], + [2, 0, 5, 5, 1, 2], + [3, 3, 0, 1, 5, 2], + [4, 4, 3, 2, 0, 2], + [5, 2, 3, 4, 3, 2], + [0, 2, 3, 3, 1, 3], + [0, 5, 1, 5, 5, 3], + [1, 4, 2, 1, 0, 3], + [2, 2, 0, 2, 4, 3], + [3, 3, 5, 4, 3, 3], + [4, 0, 4, 4, 2, 3], + [5, 1, 5, 0, 5, 3], + [0, 3, 4, 2, 3, 4], + [1, 1, 0, 4, 1, 4], + [2, 2, 2, 0, 5, 4], + [3, 4, 1, 0, 2, 4], + [4, 1, 5, 3, 0, 4], + [4, 5, 3, 1, 4, 4], + [5, 0, 2, 5, 4, 4], + [0, 4, 5, 4, 4, 5], + [1, 0, 3, 2, 5, 5], + [2, 1, 1, 1, 3, 5], + [3, 2, 4, 5, 0, 5], + [4, 3, 2, 0, 1, 5], + [5, 5, 0, 3, 2, 5], + ] # Make dictionary with keys (t, v) and values (N, k) which are the @@ -5286,7 +5874,17 @@ def ca_41_2_6_6(): LIST_OF_CA_CONSTRUCTIONS = ", ".join(":func:`CA({},{},{},{}) `".format(N, t, k, v, N, t, k, v) for (t, v) in CA_constructions for (N, k) in CA_constructions[(t, v)]) -__doc__ = __doc__.format(LIST_OF_OA_CONSTRUCTIONS=LIST_OF_OA_CONSTRUCTIONS, LIST_OF_MOLS_CONSTRUCTIONS=LIST_OF_MOLS_CONSTRUCTIONS, LIST_OF_VMT_VECTORS=LIST_OF_VMT_VECTORS, LIST_OF_BIBD=LIST_OF_BIBD, LIST_OF_DF=LIST_OF_DF, LIST_OF_DM=LIST_OF_DM, LIST_OF_QDM=LIST_OF_QDM, LIST_OF_EDS=LIST_OF_EDS, LIST_OF_CA_CONSTRUCTIONS=LIST_OF_CA_CONSTRUCTIONS) +__doc__ = __doc__.format( + LIST_OF_OA_CONSTRUCTIONS=LIST_OF_OA_CONSTRUCTIONS, + LIST_OF_MOLS_CONSTRUCTIONS=LIST_OF_MOLS_CONSTRUCTIONS, + LIST_OF_VMT_VECTORS=LIST_OF_VMT_VECTORS, + LIST_OF_BIBD=LIST_OF_BIBD, + LIST_OF_DF=LIST_OF_DF, + LIST_OF_DM=LIST_OF_DM, + LIST_OF_QDM=LIST_OF_QDM, + LIST_OF_EDS=LIST_OF_EDS, + LIST_OF_CA_CONSTRUCTIONS=LIST_OF_CA_CONSTRUCTIONS, +) del LIST_OF_OA_CONSTRUCTIONS, LIST_OF_MOLS_CONSTRUCTIONS, LIST_OF_VMT_VECTORS, LIST_OF_DF, LIST_OF_DM, LIST_OF_QDM, LIST_OF_EDS, LIST_OF_BIBD, LIST_OF_CA_CONSTRUCTIONS del ( PolynomialRing, diff --git a/src/sage/combinat/designs/difference_family.py b/src/sage/combinat/designs/difference_family.py index 6ec1ce8fa2d..9120fbe2040 100644 --- a/src/sage/combinat/designs/difference_family.py +++ b/src/sage/combinat/designs/difference_family.py @@ -2035,7 +2035,10 @@ def skew_supplementary_difference_set_over_polynomial_ring(n, existence=False, c ... NotImplementedError: skew SDS of order 7 not yet implemented """ - data = {81: (3, lambda x: x**4 - x**3 - 1, 16, 5, [1, 2, 4, 6, 8, 10, 12, 14], [1, 2, 3, 4, 10, 11, 13], [4, 5, 6, 8, 12, 13, 14], [2, 4, 5, 6, 7, 11, 12, 13, 15]), 169: (13, lambda x: x**2 - 4 * x + 6, 24, 7, [0, 2, 5, 7, 9, 10, 12, 15, 16, 18, 21, 22], [0, 1, 2, 7, 8, 9, 13, 14, 18, 20, 23], [1, 4, 6, 7, 9, 14, 16, 17, 20, 21, 23], [3, 5, 6, 9, 10, 12, 13, 14, 15, 17, 20])} + data = { + 81: (3, lambda x: x**4 - x**3 - 1, 16, 5, [1, 2, 4, 6, 8, 10, 12, 14], [1, 2, 3, 4, 10, 11, 13], [4, 5, 6, 8, 12, 13, 14], [2, 4, 5, 6, 7, 11, 12, 13, 15]), + 169: (13, lambda x: x**2 - 4 * x + 6, 24, 7, [0, 2, 5, 7, 9, 10, 12, 15, 16, 18, 21, 22], [0, 1, 2, 7, 8, 9, 13, 14, 18, 20, 23], [1, 4, 6, 7, 9, 14, 16, 17, 20, 21, 23], [3, 5, 6, 9, 10, 12, 13, 14, 15, 17, 20]), + } if existence: return n in data @@ -2295,8 +2298,24 @@ def spin_goethals_seidel_difference_family(n, existence=False, check=True): ... NotImplementedError: Data for spin type Goethals Seidel family of order 5 not yet implemented """ - full_data = {7: ([0], [0, 1, 6], 2), 9: ([0, 3, 6], [0, 1, 8], 4), 13: ([0, 1, 4, 6], [0, 4, 6, 7, 9], 3), 19: ([4, 6, 9, 10, 13, 15], [0, 1, 5, 8, 9, 10, 11, 13], 7), 21: ([1, 4, 5, 8, 10, 11, 12, 17, 19], [1, 3, 8, 9, 12, 13, 18, 20], 4), 31: ([2, 4, 6, 12, 14, 16, 17, 19, 25, 26, 28, 29], [0, 3, 9, 11, 13, 14, 15, 16, 17, 18, 20, 22, 28], 5), 37: ([0, 3, 4, 5, 7, 13, 18, 19, 24, 30, 32, 33, 34], [0, 1, 2, 3, 4, 6, 12, 13, 18, 19, 24, 25, 31, 33, 34, 35, 36], 10), 39: ([1, 4, 6, 10, 14, 15, 16, 17, 18, 21, 22, 23, 24, 25, 29, 33, 35, 38], [0, 2, 4, 6, 7, 10, 11, 14, 16, 19, 20, 22, 26, 32, 33, 38], 16), 57: ([0, 4, 11, 12, 18, 19, 20, 25, 26, 27, 28, 29, 30, 31, 32, 37, 38, 39, 45, 46, 53], [1, 2, 5, 6, 7, 8, 9, 10, 12, 17, 19, 21, 22, 24, 25, 28, 30, 31, 34, 37, 39, 41, 42, 43, 44, 46, 53, 54], 7)} - compact_data = {73: ([1, 8, 64], [0, 9, 13, 18, 25, 26, 27, 35, 36, 43], [1, 2, 4, 9, 11, 14, 18, 21, 26, 34, 36, 43], 4), 91: ([1, 16, 74], [0, 3, 4, 5, 8, 11, 19, 25, 27, 43, 45, 50, 55], [0, 1, 4, 5, 13, 14, 15, 25, 28, 33, 38, 43, 44, 49, 55], 9), 93: ([1, 4, 16, 64, 70], [3, 10, 11, 14, 21, 23, 33, 34, 46], [3, 9, 11, 17, 23, 33, 34, 46, 62], 25), 129: ([1, 4, 16, 64, 97, 121, 127], [1, 9, 10, 14, 19, 21, 23, 26, 27], [2, 5, 9, 10, 13, 18, 22, 27, 43, 86], 13), 397: ([1, 16, 31, 99, 126, 167, 256, 273, 290, 333, 393], [3, 5, 9, 10, 11, 12, 18, 20, 21, 23, 29, 33, 36, 40, 44, 47, 61, 72], [2, 3, 6, 10, 17, 22, 24, 33, 34, 36, 40, 46, 47, 53, 58, 71, 72], 34)} + full_data = { + 7: ([0], [0, 1, 6], 2), + 9: ([0, 3, 6], [0, 1, 8], 4), + 13: ([0, 1, 4, 6], [0, 4, 6, 7, 9], 3), + 19: ([4, 6, 9, 10, 13, 15], [0, 1, 5, 8, 9, 10, 11, 13], 7), + 21: ([1, 4, 5, 8, 10, 11, 12, 17, 19], [1, 3, 8, 9, 12, 13, 18, 20], 4), + 31: ([2, 4, 6, 12, 14, 16, 17, 19, 25, 26, 28, 29], [0, 3, 9, 11, 13, 14, 15, 16, 17, 18, 20, 22, 28], 5), + 37: ([0, 3, 4, 5, 7, 13, 18, 19, 24, 30, 32, 33, 34], [0, 1, 2, 3, 4, 6, 12, 13, 18, 19, 24, 25, 31, 33, 34, 35, 36], 10), + 39: ([1, 4, 6, 10, 14, 15, 16, 17, 18, 21, 22, 23, 24, 25, 29, 33, 35, 38], [0, 2, 4, 6, 7, 10, 11, 14, 16, 19, 20, 22, 26, 32, 33, 38], 16), + 57: ([0, 4, 11, 12, 18, 19, 20, 25, 26, 27, 28, 29, 30, 31, 32, 37, 38, 39, 45, 46, 53], [1, 2, 5, 6, 7, 8, 9, 10, 12, 17, 19, 21, 22, 24, 25, 28, 30, 31, 34, 37, 39, 41, 42, 43, 44, 46, 53, 54], 7), + } + compact_data = { + 73: ([1, 8, 64], [0, 9, 13, 18, 25, 26, 27, 35, 36, 43], [1, 2, 4, 9, 11, 14, 18, 21, 26, 34, 36, 43], 4), + 91: ([1, 16, 74], [0, 3, 4, 5, 8, 11, 19, 25, 27, 43, 45, 50, 55], [0, 1, 4, 5, 13, 14, 15, 25, 28, 33, 38, 43, 44, 49, 55], 9), + 93: ([1, 4, 16, 64, 70], [3, 10, 11, 14, 21, 23, 33, 34, 46], [3, 9, 11, 17, 23, 33, 34, 46, 62], 25), + 129: ([1, 4, 16, 64, 97, 121, 127], [1, 9, 10, 14, 19, 21, 23, 26, 27], [2, 5, 9, 10, 13, 18, 22, 27, 43, 86], 13), + 397: ([1, 16, 31, 99, 126, 167, 256, 273, 290, 333, 393], [3, 5, 9, 10, 11, 12, 18, 20, 21, 23, 29, 33, 36, 40, 44, 47, 61, 72], [2, 3, 6, 10, 17, 22, 24, 33, 34, 36, 40, 46, 47, 53, 58, 71, 72], 34), + } exist = n in full_data or n in compact_data or skew_spin_goethals_seidel_difference_family(n, existence=True) if existence: @@ -2535,7 +2554,12 @@ def skew_supplementary_difference_set(n, existence=False, check=True, return_gro 247: [[0, 2, 4, 7, 8, 10, 12, 15, 16, 18, 20, 23, 25, 27, 29], [0, 2, 7, 9, 11, 12, 14, 15, 16, 18, 20, 22, 26], [2, 3, 4, 12, 13, 14, 15, 16, 18, 20, 23, 24, 26, 27, 29], [0, 3, 4, 6, 10, 11, 12, 14, 18, 19, 20, 22, 25, 29]], 267: [[0, 3, 4, 7, 8, 11, 13, 15, 16, 19, 21, 22, 25], [0, 1, 4, 5, 6, 8, 14, 15, 18, 21, 23], [0, 2, 4, 5, 7, 9, 10, 11, 14, 15, 16, 17, 25], [0, 1, 3, 4, 6, 14, 15, 16, 17, 18, 20, 22, 23, 25]], 331: [[1, 2, 4, 7, 9, 10, 12, 15, 16, 18, 21, 22, 24, 26, 28], [-1, 0, 2, 6, 9, 11, 12, 14, 15, 17, 20, 21, 24, 25, 28], [-1, 0, 1, 5, 6, 7, 8, 9, 10, 12, 15, 18, 23, 28, 29], [-1, 0, 3, 7, 8, 10, 11, 12, 14, 16, 19, 20, 21, 26, 29]], - 631: [[0, 2, 4, 6, 9, 10, 12, 15, 16, 18, 20, 23, 24, 26, 29, 30, 32, 35, 36, 38, 40], [0, 1, 2, 4, 6, 8, 9, 10, 11, 12, 13, 14, 16, 20, 23, 28, 29, 30, 32, 36, 38, 41], [0, 2, 3, 4, 6, 9, 10, 12, 14, 15, 16, 17, 18, 19, 20, 22, 24, 25, 26, 29, 34, 40], [0, 2, 4, 5, 6, 7, 8, 10, 15, 16, 18, 22, 23, 24, 26, 30, 31, 33, 35, 36, 37, 38]], + 631: [ + [0, 2, 4, 6, 9, 10, 12, 15, 16, 18, 20, 23, 24, 26, 29, 30, 32, 35, 36, 38, 40], + [0, 1, 2, 4, 6, 8, 9, 10, 11, 12, 13, 14, 16, 20, 23, 28, 29, 30, 32, 36, 38, 41], + [0, 2, 3, 4, 6, 9, 10, 12, 14, 15, 16, 17, 18, 19, 20, 22, 24, 25, 26, 29, 34, 40], + [0, 2, 4, 5, 6, 7, 8, 10, 15, 16, 18, 22, 23, 24, 26, 30, 31, 33, 35, 36, 37, 38], + ], } # If the element is a list, that is the coset. @@ -2565,7 +2589,23 @@ def skew_supplementary_difference_set(n, existence=False, check=True, return_gro 217: [1, 2, 4, 5, 7, 10, 19, [31, 62, 124]], 219: [1, 2, 3, 5, 7, 9, 11, 15, 19, 22, 23, 33, [73]], 241: [1, 2, 4, 5, 7, 13, 19, 35], - 247: [1, [2, 18, 31, 32, 41, 110, 122, 162, 223], [3, 27, 48, 165, 170, 183, 185, 211, 243], [5, 28, 45, 58, 80, 158, 187, 201, 226], [6, 54, 83, 93, 96, 119, 123, 175, 239], [7, 20, 63, 73, 112, 138, 163, 180, 232], [10, 56, 69, 90, 116, 127, 155, 160, 205], [11, 47, 99, 102, 111, 115, 150, 176, 177], [13, 52, 65, 78, 91, 117, 143, 208, 221], [14, 29, 40, 79, 113, 126, 146, 217, 224], [17, 25, 43, 49, 140, 142, 153, 194, 225], [19, 57, 171], [33, 34, 37, 50, 59, 86, 98, 141, 203], [35, 66, 68, 74, 100, 118, 159, 172, 196], [38, 95, 114]], + 247: [ + 1, + [2, 18, 31, 32, 41, 110, 122, 162, 223], + [3, 27, 48, 165, 170, 183, 185, 211, 243], + [5, 28, 45, 58, 80, 158, 187, 201, 226], + [6, 54, 83, 93, 96, 119, 123, 175, 239], + [7, 20, 63, 73, 112, 138, 163, 180, 232], + [10, 56, 69, 90, 116, 127, 155, 160, 205], + [11, 47, 99, 102, 111, 115, 150, 176, 177], + [13, 52, 65, 78, 91, 117, 143, 208, 221], + [14, 29, 40, 79, 113, 126, 146, 217, 224], + [17, 25, 43, 49, 140, 142, 153, 194, 225], + [19, 57, 171], + [33, 34, 37, 50, 59, 86, 98, 141, 203], + [35, 66, 68, 74, 100, 118, 159, 172, 196], + [38, 95, 114], + ], 267: [1, 2, 3, 5, 7, 9, 10, 13, 14, 15, 19, 39, [89]], 331: [1, 2, 4, 5, 7, 8, 10, 13, 14, 16, 19, 20, 28, 32, 56], 631: [1, 2, 3, 4, 5, 6, 7, 9, 12, 14, 17, 18, 19, 21, 23, 27, 31, 35, 38, 42, 62], @@ -2805,7 +2845,12 @@ def supplementary_difference_set_hadamard(n, existence=False, check=True): indices = { 191: [[1, 7, 9, 10, 11, 13, 17, 18, 25, 26, 30, 31, 33, 34, 35, 36, 37], [1, 4, 7, 9, 11, 12, 13, 14, 19, 21, 22, 23, 24, 25, 26, 29, 36, 37], [0, 3, 4, 5, 7, 8, 9, 16, 17, 19, 24, 25, 29, 30, 31, 33, 35, 37], [1, 3, 4, 5, 8, 11, 14, 18, 19, 20, 21, 23, 24, 25, 28, 29, 30, 32, 34, 35]], 239: [[0, 1, 2, 3, 4, 5, 6, 7, 14, 18, 19, 21, 24, 25, 29, 30], [0, 1, 3, 7, 9, 12, 15, 18, 20, 22, 26, 28, 29, 30, 31, 32, 33], [2, 3, 4, 5, 8, 9, 10, 11, 13, 17, 19, 21, 22, 24, 27, 31, 32], [0, 1, 2, 3, 6, 7, 8, 11, 13, 15, 17, 18, 19, 22, 25, 26, 27, 32, 33]], - 251: [[2, 6, 8, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 27, 28, 35, 36, 39, 41, 43, 44, 47, 48], [2, 5, 10, 11, 17, 18, 21, 23, 24, 25, 26, 28, 29, 30, 34, 35, 38, 39, 40, 41, 42, 43, 44, 49], [0, 2, 6, 7, 10, 11, 14, 15, 16, 18, 21, 22, 24, 26, 30, 35, 37, 38, 45, 46, 47, 48, 49], [1, 2, 3, 4, 8, 9, 12, 17, 21, 22, 27, 28, 29, 30, 33, 34, 39, 41, 42, 43, 46, 47, 48]], + 251: [ + [2, 6, 8, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 27, 28, 35, 36, 39, 41, 43, 44, 47, 48], + [2, 5, 10, 11, 17, 18, 21, 23, 24, 25, 26, 28, 29, 30, 34, 35, 38, 39, 40, 41, 42, 43, 44, 49], + [0, 2, 6, 7, 10, 11, 14, 15, 16, 18, 21, 22, 24, 26, 30, 35, 37, 38, 45, 46, 47, 48, 49], + [1, 2, 3, 4, 8, 9, 12, 17, 21, 22, 27, 28, 29, 30, 33, 34, 39, 41, 42, 43, 46, 47, 48], + ], } cosets_gens = { diff --git a/src/sage/combinat/designs/incidence_structures.py b/src/sage/combinat/designs/incidence_structures.py index 4d59763e7c9..b794ef44971 100644 --- a/src/sage/combinat/designs/incidence_structures.py +++ b/src/sage/combinat/designs/incidence_structures.py @@ -2260,7 +2260,14 @@ def _latex_(self) -> str: from warnings import warn - warn("\nThe hypergraph is drawn as a set of closed curves. The curve " "representing a set S goes **THROUGH** the points contained " "in S.\n A point which is encircled by a curve but is not located " "on its boundary is **NOT** included in the corresponding set.\n" "\n" "The colors are picked for readability and have no other meaning.") + warn( + "\nThe hypergraph is drawn as a set of closed curves. The curve " + "representing a set S goes **THROUGH** the points contained " + "in S.\n A point which is encircled by a curve but is not located " + "on its boundary is **NOT** included in the corresponding set.\n" + "\n" + "The colors are picked for readability and have no other meaning." + ) latex.add_package_to_preamble_if_available("tikz") diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 67808fb0f24..54f2cc89438 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -7756,7 +7756,11 @@ def _composition_explorative_(self, other): def composition_transition(states, input): state1, state2 = states - return [((new_state1, new_state2), output_second) for _, new_state1, output_first in first.process([input], list_of_outputs=True, initial_state=state1, write_final_word_out=False) for _, new_state2, output_second in second.process(output_first, list_of_outputs=True, initial_state=state2, write_final_word_out=False, always_include_output=True)] + return [ + ((new_state1, new_state2), output_second) + for _, new_state1, output_first in first.process([input], list_of_outputs=True, initial_state=state1, write_final_word_out=False) + for _, new_state2, output_second in second.process(output_first, list_of_outputs=True, initial_state=state2, write_final_word_out=False, always_include_output=True) + ] first = other if any(len(t.word_in) > 1 for t in first.iter_transitions()): @@ -8359,7 +8363,16 @@ def find_common_output(state): transition.word_out = transition.word_out + [common_output[0]] found_inbound_transition = True if not found_inbound_transition: - verbose("All transitions leaving state %s have an " "output label with prefix %s. However, " "there is no inbound transition and it is " "not an initial state. This routine " "(possibly called by simplification) " "therefore erased this prefix from all " "outbound transitions." % (state, common_output[0]), level=0) + verbose( + "All transitions leaving state %s have an " + "output label with prefix %s. However, " + "there is no inbound transition and it is " + "not an initial state. This routine " + "(possibly called by simplification) " + "therefore erased this prefix from all " + "outbound transitions." % (state, common_output[0]), + level=0, + ) def equivalence_classes(self): r""" diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index c5db1835ad2..f7836f1cf1d 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -483,7 +483,18 @@ def T(i, j): e = matrix([[1] * (2 * m)]) one = matrix([1]) - H = block_matrix([[one, -e, one, e, one, e, one, e], [-e.T, T(0, 0), e.T, T(0, 1), e.T, T(0, 2), e.T, T(0, 3)], [-one, -e, one, -e, one, e, -one, -e], [-e.T, -T(1, 0), -e.T, T(1, 1), e.T, T(1, 2), -e.T, -T(1, 3)], [-one, -e, -one, -e, one, -e, one, e], [-e.T, -T(2, 0), -e.T, -T(2, 1), -e.T, T(2, 2), e.T, T(2, 3)], [-one, -e, one, e, -one, -e, one, -e], [-e.T, -T(3, 0), e.T, T(3, 1), -e.T, -T(3, 2), -e.T, T(3, 3)]]) + H = block_matrix( + [ + [one, -e, one, e, one, e, one, e], + [-e.T, T(0, 0), e.T, T(0, 1), e.T, T(0, 2), e.T, T(0, 3)], + [-one, -e, one, -e, one, e, -one, -e], + [-e.T, -T(1, 0), -e.T, T(1, 1), e.T, T(1, 2), -e.T, -T(1, 3)], + [-one, -e, -one, -e, one, -e, one, e], + [-e.T, -T(2, 0), -e.T, -T(2, 1), -e.T, T(2, 2), e.T, T(2, 3)], + [-one, -e, one, e, -one, -e, one, -e], + [-e.T, -T(3, 0), e.T, T(3, 1), -e.T, -T(3, 2), -e.T, T(3, 3)], + ] + ) if check: assert is_hadamard_matrix(H) @@ -700,7 +711,22 @@ def hadamard_matrix_156(): A, B, C, D = map(matrix.circulant, [a, b, c, d]) - return block_matrix([[A, A, A, B, -B, C, -C, -D, B, C, -D, -D], [A, -A, B, -A, -B, -D, D, -C, -B, -D, -C, -C], [A, -B, -A, A, -D, D, -B, B, -C, -D, C, -C], [B, A, -A, -A, D, D, D, C, C, -B, -B, -C], [B, -D, D, D, A, A, A, C, -C, B, -C, B], [B, C, -D, D, A, -A, C, -A, -D, C, B, -B], [D, -C, B, -B, A, -C, -A, A, B, C, D, -D], [-C, -D, -C, -D, C, A, -A, -A, -D, B, -B, -B], [D, -C, -B, -B, -B, C, C, -D, A, A, A, D], [-D, -B, C, C, C, B, B, -D, A, -A, D, -A], [C, -B, -C, C, D, -B, -D, -B, A, -D, -A, A], [-C, -D, -D, C, -C, -B, B, B, D, A, -A, -A]]) + return block_matrix( + [ + [A, A, A, B, -B, C, -C, -D, B, C, -D, -D], + [A, -A, B, -A, -B, -D, D, -C, -B, -D, -C, -C], + [A, -B, -A, A, -D, D, -B, B, -C, -D, C, -C], + [B, A, -A, -A, D, D, D, C, C, -B, -B, -C], + [B, -D, D, D, A, A, A, C, -C, B, -C, B], + [B, C, -D, D, A, -A, C, -A, -D, C, B, -B], + [D, -C, B, -B, A, -C, -A, A, B, C, D, -D], + [-C, -D, -C, -D, C, A, -A, -A, -D, B, -B, -B], + [D, -C, -B, -B, -B, C, C, -D, A, A, A, D], + [-D, -B, C, C, C, B, B, -D, A, -A, D, -A], + [C, -B, -C, C, D, -B, -D, -B, A, -D, -A, A], + [-C, -D, -D, C, -C, -B, B, B, D, A, -A, -A], + ] + ) def construction_four_symbol_delta_code_I(X, Y, Z, W): @@ -1187,7 +1213,14 @@ def hadamard_matrix_cooper_wallis_smallcases(n, check=True, existence=False): """ assert n % 4 == 0 and n > 0 - db = {67: ([1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, -1, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, -1, 0, 1, -1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 1, 0, 0, -1, -1, -1, 0, 0, 0, 0, 0, -1, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, -1, 0, 0, 1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 1, 0, 0, 0, 0, 0, 0], [0, 0, -1, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -1, 1, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, 1, 0, 0, 0])} + db = { + 67: ( + [1, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, -1, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, -1, 0, 1, -1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + [0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 1, 0, 0, -1, -1, -1, 0, 0, 0, 0, 0, -1, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0], + [0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, -1, 0, 0, 1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, -1, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -1, 1, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, 1, 0, 0, 0], + ) + } for T_seq_len in divisors(n // 4): will_size = n // (4 * T_seq_len) @@ -1493,7 +1526,18 @@ def hadamard_matrix_spence_construction(n, existence=False, check=True): e = matrix([1] * (q - 1)) m1 = matrix([-1]) p1 = matrix([1]) - H = block_matrix([[p1, m1, p1, p1, e, e, e, e], [p1, p1, m1, p1, -e, e, -e, e], [m1, p1, p1, p1, -e, e, e, -e], [m1, m1, m1, p1, -e, -e, e, e], [-e.T, e.T, e.T, -e.T, A1, A2 * P, A3 * P, A4 * P], [-e.T, -e.T, e.T, e.T, -A2 * P, A1, -A4.T * P, A3.T * P], [-e.T, -e.T, -e.T, -e.T, -A3 * P, A4.T * P, A1, -A2.T * P], [e.T, -e.T, e.T, -e.T, -A4 * P, -A3.T * P, A2.T * P, A1]]) + H = block_matrix( + [ + [p1, m1, p1, p1, e, e, e, e], + [p1, p1, m1, p1, -e, e, -e, e], + [m1, p1, p1, p1, -e, e, e, -e], + [m1, m1, m1, p1, -e, -e, e, e], + [-e.T, e.T, e.T, -e.T, A1, A2 * P, A3 * P, A4 * P], + [-e.T, -e.T, e.T, e.T, -A2 * P, A1, -A4.T * P, A3.T * P], + [-e.T, -e.T, -e.T, -e.T, -A3 * P, A4.T * P, A1, -A2.T * P], + [e.T, -e.T, e.T, -e.T, -A4 * P, -A3.T * P, A2.T * P, A1], + ] + ) if check: assert is_hadamard_matrix(H, verbose=True) @@ -3020,7 +3064,24 @@ def skew_hadamard_matrix_from_good_matrices_smallcases(n, existence=False, check sage: skew_hadamard_matrix_from_good_matrices_smallcases(14, existence=True) False """ - E_sequences = {0: ['', '', '', ''], 1: ['+', '-', '-', '+'], 2: ['++', '-+', '--', '--'], 3: ['++-', '++-', '+-+', '-++'], 4: ['+++-', '+-+-', '---+', '++-+'], 5: ['+-+--', '+++--', '-+++-', '---+-'], 6: ['+-+---', '---+++', '+-+--+', '----+-'], 7: ['+++++--', '-++--++', '----+-+', '-+---+-'], 8: ['+--++-+-', '+--+----', '++----+-', '+---+-+-'], 9: ['-+-----++', '+-+++++--', '-+----++-', '--+-+-++-'], 10: ['+--+++++++', '++--++++-+', '--++-+-+-+', '---+++-+-+'], 11: ['++-+-------', '+----+--+--', '+-+--++---+', '--++-+-+-++'], 12: ['+-----+-+---', '+-++++-+-++-', '---+--++++--', '--+-+++--+--'], 13: ['+---+-+--++-+', '+++---++-++-+', '+++-+++-++---', '+---++++-+-+-'], 14: ['+--+----+-+-++', '+---++++-++--+', '+-+----++-+--+', '++++++---+-+-+'], 15: ['+--++----+---+-', '-++-+---+-+++--', '++---+--+--+++-', '-++++++++--+-+-']} + E_sequences = { + 0: ['', '', '', ''], + 1: ['+', '-', '-', '+'], + 2: ['++', '-+', '--', '--'], + 3: ['++-', '++-', '+-+', '-++'], + 4: ['+++-', '+-+-', '---+', '++-+'], + 5: ['+-+--', '+++--', '-+++-', '---+-'], + 6: ['+-+---', '---+++', '+-+--+', '----+-'], + 7: ['+++++--', '-++--++', '----+-+', '-+---+-'], + 8: ['+--++-+-', '+--+----', '++----+-', '+---+-+-'], + 9: ['-+-----++', '+-+++++--', '-+----++-', '--+-+-++-'], + 10: ['+--+++++++', '++--++++-+', '--++-+-+-+', '---+++-+-+'], + 11: ['++-+-------', '+----+--+--', '+-+--++---+', '--++-+-+-++'], + 12: ['+-----+-+---', '+-++++-+-++-', '---+--++++--', '--+-+++--+--'], + 13: ['+---+-+--++-+', '+++---++-++-+', '+++-+++-++---', '+---++++-+-+-'], + 14: ['+--+----+-+-++', '+---++++-++--+', '+-+----++-+--+', '++++++---+-+-+'], + 15: ['+--++----+---+-', '-++-+---+-+++--', '++---+--+--+++-', '-++++++++--+-+-'], + } def pm_to_good_matrix(s, sign=1): e1 = [1 if x == '+' else -1 for x in s] diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 94cc3a1d174..0a0c2daa73a 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -6378,8 +6378,20 @@ class options(GlobalOptions): NAME = 'Partitions' module = 'sage.combinat.partition' - display = {'default': "list", 'description': 'Specifies how partitions should be printed', 'values': {'list': 'displayed as a list', 'exp_low': 'in exponential form (lowest first)', 'exp_high': 'in exponential form (highest first)', 'diagram': 'as a Ferrers diagram', 'compact_low': 'compact form of ``exp_low``', 'compact_high': 'compact form of ``exp_high``'}, 'alias': {'exp': "exp_low", 'compact': "compact_low", 'array': "diagram", 'ferrers_diagram': "diagram", 'young_diagram': "diagram"}, 'case_sensitive': False} - latex = {'default': "young_diagram", 'description': 'Specifies how partitions should be latexed', 'values': {'diagram': 'latex as a Ferrers diagram', 'young_diagram': 'latex as a Young diagram', 'list': 'latex as a list', 'exp_high': 'latex as a list in exponential notation (highest first)', 'exp_low': 'as a list latex in exponential notation (lowest first)'}, 'alias': {'exp': "exp_low", 'array': "diagram", 'ferrers_diagram': "diagram"}, 'case_sensitive': False} + display = { + 'default': "list", + 'description': 'Specifies how partitions should be printed', + 'values': {'list': 'displayed as a list', 'exp_low': 'in exponential form (lowest first)', 'exp_high': 'in exponential form (highest first)', 'diagram': 'as a Ferrers diagram', 'compact_low': 'compact form of ``exp_low``', 'compact_high': 'compact form of ``exp_high``'}, + 'alias': {'exp': "exp_low", 'compact': "compact_low", 'array': "diagram", 'ferrers_diagram': "diagram", 'young_diagram': "diagram"}, + 'case_sensitive': False, + } + latex = { + 'default': "young_diagram", + 'description': 'Specifies how partitions should be latexed', + 'values': {'diagram': 'latex as a Ferrers diagram', 'young_diagram': 'latex as a Young diagram', 'list': 'latex as a list', 'exp_high': 'latex as a list in exponential notation (highest first)', 'exp_low': 'as a list latex in exponential notation (lowest first)'}, + 'alias': {'exp': "exp_low", 'array': "diagram", 'ferrers_diagram': "diagram"}, + 'case_sensitive': False, + } diagram_str = {'default': "*", 'description': 'The character used for the cells when printing Ferrers diagrams', 'checker': lambda char: isinstance(char, str)} latex_diagram_str = {'default': "\\ast", 'description': 'The character used for the cells when latexing Ferrers diagrams', 'checker': lambda char: isinstance(char, str)} convention = {'link_to': (tableau.Tableaux.options, 'convention')} diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index 2ede47d88f7..8a3968946ec 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -6175,8 +6175,25 @@ class options(GlobalOptions): NAME = 'Permutations' module = 'sage.combinat.permutation' - display = {'default': "list", 'description': "Specifies how the permutations should be printed", 'values': {'list': "the permutations are displayed in list notation" " (aka 1-line notation)", 'cycle': "the permutations are displayed in cycle notation" " (i. e., as products of disjoint cycles)", 'singleton': "the permutations are displayed in cycle notation" " with singleton cycles shown as well", 'reduced_word': "the permutations are displayed as reduced words"}, 'alias': {'word': "reduced_word", 'reduced_expression': "reduced_word"}, 'case_sensitive': False} - latex = {'default': "list", 'description': "Specifies how the permutations should be latexed", 'values': {'list': "latex as a list in one-line notation", 'twoline': "latex in two-line notation", 'cycle': "latex in cycle notation", 'singleton': "latex in cycle notation with singleton cycles shown as well", 'reduced_word': "latex as reduced words"}, 'alias': {'word': "reduced_word", 'reduced_expression': "reduced_word", 'oneline': "list"}, 'case_sensitive': False} + display = { + 'default': "list", + 'description': "Specifies how the permutations should be printed", + 'values': { + 'list': "the permutations are displayed in list notation" " (aka 1-line notation)", + 'cycle': "the permutations are displayed in cycle notation" " (i. e., as products of disjoint cycles)", + 'singleton': "the permutations are displayed in cycle notation" " with singleton cycles shown as well", + 'reduced_word': "the permutations are displayed as reduced words", + }, + 'alias': {'word': "reduced_word", 'reduced_expression': "reduced_word"}, + 'case_sensitive': False, + } + latex = { + 'default': "list", + 'description': "Specifies how the permutations should be latexed", + 'values': {'list': "latex as a list in one-line notation", 'twoline': "latex in two-line notation", 'cycle': "latex in cycle notation", 'singleton': "latex in cycle notation with singleton cycles shown as well", 'reduced_word': "latex as reduced words"}, + 'alias': {'word': "reduced_word", 'reduced_expression': "reduced_word", 'oneline': "list"}, + 'case_sensitive': False, + } latex_empty_str = {'default': "1", 'description': 'The LaTeX representation of a reduced word when said word is empty', 'checker': lambda char: isinstance(char, str)} generator_name = {'default': "s", 'description': "the letter used in latexing the reduced word", 'checker': lambda char: isinstance(char, str)} mult = {'default': "l2r", 'description': "The multiplication of permutations", 'values': {'l2r': r"left to right: `(p_1 \cdot p_2)(x) = p_2(p_1(x))`", 'r2l': r"right to left: `(p_1 \cdot p_2)(x) = p_1(p_2(x))`"}, 'case_sensitive': False} diff --git a/src/sage/combinat/regular_sequence.py b/src/sage/combinat/regular_sequence.py index cc1d1bc8b56..43c22bc777e 100644 --- a/src/sage/combinat/regular_sequence.py +++ b/src/sage/combinat/regular_sequence.py @@ -824,7 +824,9 @@ def matrix_row(r, c): # We explicitly set the ring when creating vectors in order to avoid # problems with the zero sequence, see issue:`37282`. - result = P.element_class(P, {r: Matrix.block([matrix_row(r, c) for c in kernel]) for r in A}, vector(P.coefficient_ring(), chain.from_iterable(b.get(c, 0) * self.left for c in kernel)), vector(P.coefficient_ring(), chain.from_iterable((self.coefficient_of_n(c, multiply_left=False) if c >= 0 else zero_R) for c in kernel))) + result = P.element_class( + P, {r: Matrix.block([matrix_row(r, c) for c in kernel]) for r in A}, vector(P.coefficient_ring(), chain.from_iterable(b.get(c, 0) * self.left for c in kernel)), vector(P.coefficient_ring(), chain.from_iterable((self.coefficient_of_n(c, multiply_left=False) if c >= 0 else zero_R) for c in kernel)) + ) return result diff --git a/src/sage/combinat/root_system/branching_rules.py b/src/sage/combinat/root_system/branching_rules.py index 348d646e054..ce1bb09ad1b 100644 --- a/src/sage/combinat/root_system/branching_rules.py +++ b/src/sage/combinat/root_system/branching_rules.py @@ -1562,11 +1562,33 @@ def f(x): M = matrix(QQ, [(5, 1, 1, 1, 1, 1, 0, 0), (-1, -5, 1, 1, 1, 1, 0, 0), (-1, 1, -5, 1, 1, 1, 0, 0), (-1, 1, 1, -5, 1, 1, 0, 0), (-1, 1, 1, 1, -5, 1, 0, 0), (-1, 1, 1, 1, 1, -5, 0, 0), (1, -1, -1, -1, -1, -1, 0, -6), (1, -1, -1, -1, -1, -1, -6, 0), (-2, 2, 2, 2, 2, 2, -3, -3)]) / 6 return BranchingRule(Rtype, Stype, lambda x: tuple(M * vector(x)), "extended") if stypes == [CartanType("A3"), CartanType("A3"), CartanType("A1")]: - M = matrix(QQ, [(0, 0, -1, -1, -1, -1, 2, -2), (0, 0, -1, -1, -1, -1, -2, 2), (-2, 2, 1, 1, 1, 1, 0, 0), (2, -2, 1, 1, 1, 1, 0, 0), (0, 0, -1, -1, -1, 3, 0, 0), (0, 0, -1, -1, 3, -1, 0, 0), (0, 0, -1, 3, -1, -1, 0, 0), (0, 0, 3, -1, -1, -1, 0, 0), (2, 2, 0, 0, 0, 0, -2, -2), (-2, -2, 0, 0, 0, 0, -2, -2)]) / 4 + M = ( + matrix( + QQ, + [ + (0, 0, -1, -1, -1, -1, 2, -2), + (0, 0, -1, -1, -1, -1, -2, 2), + (-2, 2, 1, 1, 1, 1, 0, 0), + (2, -2, 1, 1, 1, 1, 0, 0), + (0, 0, -1, -1, -1, 3, 0, 0), + (0, 0, -1, -1, 3, -1, 0, 0), + (0, 0, -1, 3, -1, -1, 0, 0), + (0, 0, 3, -1, -1, -1, 0, 0), + (2, 2, 0, 0, 0, 0, -2, -2), + (-2, -2, 0, 0, 0, 0, -2, -2), + ], + ) + / 4 + ) return BranchingRule(Rtype, Stype, lambda x: tuple(M * vector(x)), "extended") elif r == 8: if stypes == [CartanType("A4"), CartanType("A4")]: - M = matrix(QQ, [(0, 0, 0, -4, -4, -4, -4, 4), (-5, 5, 5, 1, 1, 1, 1, -1), (5, -5, 5, 1, 1, 1, 1, -1), (5, 5, -5, 1, 1, 1, 1, -1), (-5, -5, -5, 1, 1, 1, 1, -1), (0, 0, 0, -8, 2, 2, 2, -2), (0, 0, 0, 2, -8, 2, 2, -2), (0, 0, 0, 2, 2, -8, 2, -2), (0, 0, 0, 2, 2, 2, -8, -2), (0, 0, 0, 2, 2, 2, 2, 8)]) / 10 + M = ( + matrix( + QQ, [(0, 0, 0, -4, -4, -4, -4, 4), (-5, 5, 5, 1, 1, 1, 1, -1), (5, -5, 5, 1, 1, 1, 1, -1), (5, 5, -5, 1, 1, 1, 1, -1), (-5, -5, -5, 1, 1, 1, 1, -1), (0, 0, 0, -8, 2, 2, 2, -2), (0, 0, 0, 2, -8, 2, 2, -2), (0, 0, 0, 2, 2, -8, 2, -2), (0, 0, 0, 2, 2, 2, -8, -2), (0, 0, 0, 2, 2, 2, 2, 8)] + ) + / 10 + ) return BranchingRule(Rtype, Stype, lambda x: tuple(M * vector(x)), "extended") if len(stypes) == 3: if 5 in stypes[0][i]: # S is A5xA2xA1 @@ -1809,13 +1831,25 @@ def f(x): if stypes == [CartanType("G2"), CartanType("A1")]: def f(x): - return [(x[0] - x[1] + x[2] + 3 * x[3] + x[4] - x[5] + 2 * x[6]) / 2, (-3 * x[0] - x[1] - x[2] - x[3] + x[4] + x[5] - 2 * x[6]) / 2, (2 * x[0] + 2 * x[1] - 2 * x[3] - 2 * x[4]) / 2, (x[0] + x[1] + x[2] + x[3] + x[4] + x[5] - 4 * x[6]) / 2, -(x[0] + x[1] + x[2] + x[3] + x[4] + x[5] - 4 * x[6]) / 2] + return [ + (x[0] - x[1] + x[2] + 3 * x[3] + x[4] - x[5] + 2 * x[6]) / 2, + (-3 * x[0] - x[1] - x[2] - x[3] + x[4] + x[5] - 2 * x[6]) / 2, + (2 * x[0] + 2 * x[1] - 2 * x[3] - 2 * x[4]) / 2, + (x[0] + x[1] + x[2] + x[3] + x[4] + x[5] - 4 * x[6]) / 2, + -(x[0] + x[1] + x[2] + x[3] + x[4] + x[5] - 4 * x[6]) / 2, + ] return BranchingRule(Rtype, Stype, f, "miscellaneous") if stypes == [CartanType("A1"), CartanType("G2")]: def f(x): - return [(x[0] + x[1] + x[2] + x[3] + x[4] + x[5] - 4 * x[6]) / 2, -(x[0] + x[1] + x[2] + x[3] + x[4] + x[5] - 4 * x[6]) / 2, (x[0] - x[1] + x[2] + 3 * x[3] + x[4] - x[5] + 2 * x[6]) / 2, (-3 * x[0] - x[1] - x[2] - x[3] + x[4] + x[5] - 2 * x[6]) / 2, (2 * x[0] + 2 * x[1] - 2 * x[3] - 2 * x[4]) / 2] + return [ + (x[0] + x[1] + x[2] + x[3] + x[4] + x[5] - 4 * x[6]) / 2, + -(x[0] + x[1] + x[2] + x[3] + x[4] + x[5] - 4 * x[6]) / 2, + (x[0] - x[1] + x[2] + 3 * x[3] + x[4] - x[5] + 2 * x[6]) / 2, + (-3 * x[0] - x[1] - x[2] - x[3] + x[4] + x[5] - 2 * x[6]) / 2, + (2 * x[0] + 2 * x[1] - 2 * x[3] - 2 * x[4]) / 2, + ] return BranchingRule(Rtype, Stype, f, "miscellaneous") elif Stype == CartanType("A2"): @@ -1829,13 +1863,25 @@ def f(x): if stypes == [CartanType("A2"), CartanType("A1")]: def f(x): - return [(x[0] - x[1] + x[2] + x[3] + 3 * x[4] + x[5] - x[6] - x[7]) / 2, (-3 * x[0] - x[1] - x[2] - x[3] - x[4] + x[5] + x[6] + x[7]) / 2, (2 * x[0] + 2 * x[1] - 2 * x[4] - 2 * x[5]) / 2, (x[0] + x[1] + x[2] + x[3] + x[4] + x[5] + x[6] + 5 * x[7]) / 2, -(x[0] + x[1] + x[2] + x[3] + x[4] + x[5] + x[6] + 5 * x[7]) / 2] + return [ + (x[0] - x[1] + x[2] + x[3] + 3 * x[4] + x[5] - x[6] - x[7]) / 2, + (-3 * x[0] - x[1] - x[2] - x[3] - x[4] + x[5] + x[6] + x[7]) / 2, + (2 * x[0] + 2 * x[1] - 2 * x[4] - 2 * x[5]) / 2, + (x[0] + x[1] + x[2] + x[3] + x[4] + x[5] + x[6] + 5 * x[7]) / 2, + -(x[0] + x[1] + x[2] + x[3] + x[4] + x[5] + x[6] + 5 * x[7]) / 2, + ] return BranchingRule("E8", "A2xA1", f, "miscellaneous") if stypes == [CartanType("A1"), CartanType("A2")]: def f(x): - return [(x[0] + x[1] + x[2] + x[3] + x[4] + x[5] + x[6] + 5 * x[7]) / 2, -(x[0] + x[1] + x[2] + x[3] + x[4] + x[5] + x[6] + 5 * x[7]) / 2, (x[0] - x[1] + x[2] + x[3] + 3 * x[4] + x[5] - x[6] - x[7]) / 2, (-3 * x[0] - x[1] - x[2] - x[3] - x[4] + x[5] + x[6] + x[7]) / 2, (2 * x[0] + 2 * x[1] - 2 * x[4] - 2 * x[5]) / 2] + return [ + (x[0] + x[1] + x[2] + x[3] + x[4] + x[5] + x[6] + 5 * x[7]) / 2, + -(x[0] + x[1] + x[2] + x[3] + x[4] + x[5] + x[6] + 5 * x[7]) / 2, + (x[0] - x[1] + x[2] + x[3] + 3 * x[4] + x[5] - x[6] - x[7]) / 2, + (-3 * x[0] - x[1] - x[2] - x[3] - x[4] + x[5] + x[6] + x[7]) / 2, + (2 * x[0] + 2 * x[1] - 2 * x[4] - 2 * x[5]) / 2, + ] return BranchingRule("E8", "A1xA2", f, "miscellaneous") elif Stype == CartanType("B2"): @@ -1989,59 +2035,237 @@ def maximal_subgroups(ct, mode='print_rules'): elif CartanType(ct) == CartanType("A4"): rul = ["""A3:branching_rule("A4","A3","levi")""", """B2:branching_rule("A4","B2","symmetric")""", """A1xA2:branching_rule("A4","A1xA2","levi")"""] elif CartanType(ct) == CartanType("A5"): - rul = ["""A4:branching_rule("A5","A4","levi")""", """A3:branching_rule("A5","D3","symmetric")*branching_rule("D3","A3","isomorphic")""", """A3:branching_rule("A5","A3(0,1,0)","plethysm") # alternative""", """C3:branching_rule("A5","C3","symmetric")""", """A2:branching_rule("A5","A2(2,0)","plethysm")""", """A1xA2:branching_rule("A5","A1xA2","tensor")""", """A1xA3:branching_rule("A5","A1xA3","levi")""", """A2xA2:branching_rule("A5","A2xA2","levi")"""] + rul = [ + """A4:branching_rule("A5","A4","levi")""", + """A3:branching_rule("A5","D3","symmetric")*branching_rule("D3","A3","isomorphic")""", + """A3:branching_rule("A5","A3(0,1,0)","plethysm") # alternative""", + """C3:branching_rule("A5","C3","symmetric")""", + """A2:branching_rule("A5","A2(2,0)","plethysm")""", + """A1xA2:branching_rule("A5","A1xA2","tensor")""", + """A1xA3:branching_rule("A5","A1xA3","levi")""", + """A2xA2:branching_rule("A5","A2xA2","levi")""", + ] elif CartanType(ct) == CartanType("A6"): rul = ["""A5:branching_rule("A6","A5","levi")""", """B3:branching_rule("A6","B3","symmetric")""", """A1xA4:branching_rule("A6","A1xA4","levi")""", """A2xA3:branching_rule("A6","A2xA3","levi")"""] elif CartanType(ct) == CartanType("A7"): - rul = ["""A6:branching_rule("A7","A6","levi")""", """C4:branching_rule("A7","C4","symmetric")""", """D4:branching_rule("A7","D4","symmetric")""", """A1xA3:branching_rule("A7","A1xA3","tensor")""", """A1xA5:branching_rule("A7","A1xA5","levi")""", """A2xA4:branching_rule("A7","A2xA4","levi")""", """A3xA3:branching_rule("A7","A3xA3","levi")"""] + rul = [ + """A6:branching_rule("A7","A6","levi")""", + """C4:branching_rule("A7","C4","symmetric")""", + """D4:branching_rule("A7","D4","symmetric")""", + """A1xA3:branching_rule("A7","A1xA3","tensor")""", + """A1xA5:branching_rule("A7","A1xA5","levi")""", + """A2xA4:branching_rule("A7","A2xA4","levi")""", + """A3xA3:branching_rule("A7","A3xA3","levi")""", + ] elif CartanType(ct) == CartanType("A8"): rul = ["""A7:branching_rule("A8","A7","levi")""", """B4:branching_rule("A8","B4","symmetric")""", """A2xA2:branching_rule("A8","A2xA2","tensor")""", """A1xA6:branching_rule("A8","A1xA6","levi")""", """A2xA5:branching_rule("A8","A2xA5","levi")""", """A3xA4:branching_rule("A8","A3xA4","levi")"""] elif CartanType(ct) == CartanType("B3"): - rul = ["""G2:branching_rule("B3","G2","miscellaneous")""", """A3:branching_rule("B3","D3","extended")*branching_rule("D3","A3","isomorphic")""", """A1xA1xA1:branching_rule("B3","D2xB1","orthogonal_sum")*branching_rule("D2xB1","A1xA1xA1",[branching_rule("D2","A1xA1","isomorphic"),branching_rule("B1","A1","isomorphic")])"""] + rul = [ + """G2:branching_rule("B3","G2","miscellaneous")""", + """A3:branching_rule("B3","D3","extended")*branching_rule("D3","A3","isomorphic")""", + """A1xA1xA1:branching_rule("B3","D2xB1","orthogonal_sum")*branching_rule("D2xB1","A1xA1xA1",[branching_rule("D2","A1xA1","isomorphic"),branching_rule("B1","A1","isomorphic")])""", + ] elif CartanType(ct) == CartanType("B4"): - rul = ["""D4:branching_rule("B4","D4","extended")""", """A1:branching_rule("B4","A1","symmetric_power")""", """A1xA1:branching_rule("B4","B1xB1","tensor")*branching_rule("B1xB1","A1xA1",[branching_rule("B1","A1","isomorphic"),branching_rule("B1","A1","isomorphic")])""", """A1xA1xB2:branching_rule("B4","D2xB2","extended")*branching_rule("D2xB2","A1xA1xB2",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", """A1xA3:branching_rule("B4","B1xD3","extended")*branching_rule("B1xD3","A1xA3",[branching_rule("B1","A1","isomorphic"),branching_rule("D3","A3","isomorphic")])"""] + rul = [ + """D4:branching_rule("B4","D4","extended")""", + """A1:branching_rule("B4","A1","symmetric_power")""", + """A1xA1:branching_rule("B4","B1xB1","tensor")*branching_rule("B1xB1","A1xA1",[branching_rule("B1","A1","isomorphic"),branching_rule("B1","A1","isomorphic")])""", + """A1xA1xB2:branching_rule("B4","D2xB2","extended")*branching_rule("D2xB2","A1xA1xB2",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", + """A1xA3:branching_rule("B4","B1xD3","extended")*branching_rule("B1xD3","A1xA3",[branching_rule("B1","A1","isomorphic"),branching_rule("D3","A3","isomorphic")])""", + ] elif CartanType(ct) == CartanType("B5"): - rul = ["""D5:branching_rule("B5","D5","extended")""", """A1:branching_rule("B5","A1","symmetric_power")""", """A1xA2xB3:branching_rule("B5","D2xB3","extended")*branching_rule("D2xB3","A1xA2xB3",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", """A1xD4:branching_rule("B5","B1xD4","orthogonal_sum")*branching_rule("B1xD4","A1xD4",[branching_rule("B1","A1","isomorphic"),"identity"])""", """A3xB2:branching_rule("B5","D3xB2","orthogonal_sum")*branching_rule("D3xB2","A3xB2",[branching_rule("D3","A3","isomorphic"),"identity"])"""] + rul = [ + """D5:branching_rule("B5","D5","extended")""", + """A1:branching_rule("B5","A1","symmetric_power")""", + """A1xA2xB3:branching_rule("B5","D2xB3","extended")*branching_rule("D2xB3","A1xA2xB3",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", + """A1xD4:branching_rule("B5","B1xD4","orthogonal_sum")*branching_rule("B1xD4","A1xD4",[branching_rule("B1","A1","isomorphic"),"identity"])""", + """A3xB2:branching_rule("B5","D3xB2","orthogonal_sum")*branching_rule("D3xB2","A3xB2",[branching_rule("D3","A3","isomorphic"),"identity"])""", + ] elif CartanType(ct) == CartanType("B6"): - rul = ["""D6:branching_rule("B6","D6","extended")""", """A1:branching_rule("B6","A1","symmetric_power")""", """A1xA1xB4:branching_rule("B6","D2xB4","orthogonal_sum")*branching_rule("D2xB4","A1xA1xB4",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", """A1xD5:branching_rule("B6","B1xD5","orthogonal_sum")*branching_rule("B1xD5","A1xD5",[branching_rule("B1","A1","isomorphic"),"identity"])""", """A3xB3:branching_rule("B6","D3xB3","orthogonal_sum")*branching_rule("D3xB3","A3xB3",[branching_rule("D3","A3","isomorphic"),"identity"])""", """B2xD4:branching_rule("B6","B2xD4","orthogonal_sum")"""] + rul = [ + """D6:branching_rule("B6","D6","extended")""", + """A1:branching_rule("B6","A1","symmetric_power")""", + """A1xA1xB4:branching_rule("B6","D2xB4","orthogonal_sum")*branching_rule("D2xB4","A1xA1xB4",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", + """A1xD5:branching_rule("B6","B1xD5","orthogonal_sum")*branching_rule("B1xD5","A1xD5",[branching_rule("B1","A1","isomorphic"),"identity"])""", + """A3xB3:branching_rule("B6","D3xB3","orthogonal_sum")*branching_rule("D3xB3","A3xB3",[branching_rule("D3","A3","isomorphic"),"identity"])""", + """B2xD4:branching_rule("B6","B2xD4","orthogonal_sum")""", + ] elif CartanType(ct) == CartanType("B7"): - rul = ["""D7:branching_rule("B7","D7","extended")""", """A3:branching_rule("B7","A3(1,0,1)","plethysm")""", """A1:branching_rule("B7","A1","symmetric_power")""", """A1xB2:branching_rule("B7","B1xB2","tensor")*branching_rule("B1xB2","A1xB2",[branching_rule("B1","A1","isomorphic"),"identity"])""", """A1xD6:branching_rule("B7","B1xD6","extended")*branching_rule("B1xD6","A1xD6",[branching_rule("B1","A1","isomorphic"),"identity"])""", """A1xA1xB5:branching_rule("B7","D2xB5","extended")*branching_rule("D2xB5","A1xA1xB5",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", """B2xD5:branching_rule("B7","B2xD5","orthogonal_sum")""", """A3xB4:branching_rule("B7","D3xB4","orthogonal_sum")*branching_rule("D3xB4","A3xB4",[branching_rule("D3","A3","isomorphic"),"identity"])""", """B3xD4:branching_rule("B7","B3xD4","orthogonal_sum")"""] + rul = [ + """D7:branching_rule("B7","D7","extended")""", + """A3:branching_rule("B7","A3(1,0,1)","plethysm")""", + """A1:branching_rule("B7","A1","symmetric_power")""", + """A1xB2:branching_rule("B7","B1xB2","tensor")*branching_rule("B1xB2","A1xB2",[branching_rule("B1","A1","isomorphic"),"identity"])""", + """A1xD6:branching_rule("B7","B1xD6","extended")*branching_rule("B1xD6","A1xD6",[branching_rule("B1","A1","isomorphic"),"identity"])""", + """A1xA1xB5:branching_rule("B7","D2xB5","extended")*branching_rule("D2xB5","A1xA1xB5",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", + """B2xD5:branching_rule("B7","B2xD5","orthogonal_sum")""", + """A3xB4:branching_rule("B7","D3xB4","orthogonal_sum")*branching_rule("D3xB4","A3xB4",[branching_rule("D3","A3","isomorphic"),"identity"])""", + """B3xD4:branching_rule("B7","B3xD4","orthogonal_sum")""", + ] elif CartanType(ct) == CartanType("B8"): - rul = ["""D8:branching_rule("B8","D8","extended")""", """A1:branching_rule("B8","A1","symmetric_power")""", """A1xD7:branching_rule("B8","B1xD7","orthogonal_sum")*branching_rule("B1xD7","A1xD7",[branching_rule("B1","A1","isomorphic"),"identity"])""", """A1xA1xB6:branching_rule("B8","D2xB6","orthogonal_sum")*branching_rule("D2xB6","A1xA1xB6",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", """B2xD6:branching_rule("B8","B2xD6","orthogonal_sum")""", """A3xB5:branching_rule("B8","D3xB5","orthogonal_sum")*branching_rule("D3xB5","A3xB5",[branching_rule("D3","A3","isomorphic"),"identity"])""", """B3xD5:branching_rule("B8","B3xD5","orthogonal_sum")""", """B4xD4:branching_rule("B8","B4xD4","orthogonal_sum")"""] + rul = [ + """D8:branching_rule("B8","D8","extended")""", + """A1:branching_rule("B8","A1","symmetric_power")""", + """A1xD7:branching_rule("B8","B1xD7","orthogonal_sum")*branching_rule("B1xD7","A1xD7",[branching_rule("B1","A1","isomorphic"),"identity"])""", + """A1xA1xB6:branching_rule("B8","D2xB6","orthogonal_sum")*branching_rule("D2xB6","A1xA1xB6",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", + """B2xD6:branching_rule("B8","B2xD6","orthogonal_sum")""", + """A3xB5:branching_rule("B8","D3xB5","orthogonal_sum")*branching_rule("D3xB5","A3xB5",[branching_rule("D3","A3","isomorphic"),"identity"])""", + """B3xD5:branching_rule("B8","B3xD5","orthogonal_sum")""", + """B4xD4:branching_rule("B8","B4xD4","orthogonal_sum")""", + ] elif CartanType(ct) == CartanType("C2"): rul = ["""A1:branching_rule("C2","A1","symmetric_power")""", """A1xA1:branching_rule("C2","C1xC1","orthogonal_sum")*branching_rule("C1xC1","A1xA1",[branching_rule("C1","A1","isomorphic"),branching_rule("C1","A1","isomorphic")])"""] elif CartanType(ct) == CartanType("C3"): - rul = ["""A2:branching_rule("C3","A2","levi")""", """A1:branching_rule("C3","A1","symmetric_power")""", """A1xA1:branching_rule("C3","B1xC1","tensor")*branching_rule("B1xC1","A1xA1",[branching_rule("B1","A1","isomorphic"),branching_rule("C1","A1","isomorphic")])""", """A1xC2:branching_rule("C3","C1xC2","orthogonal_sum")*branching_rule("C1xC2","A1xC2",[branching_rule("C1","A1","isomorphic"),"identity"])"""] + rul = [ + """A2:branching_rule("C3","A2","levi")""", + """A1:branching_rule("C3","A1","symmetric_power")""", + """A1xA1:branching_rule("C3","B1xC1","tensor")*branching_rule("B1xC1","A1xA1",[branching_rule("B1","A1","isomorphic"),branching_rule("C1","A1","isomorphic")])""", + """A1xC2:branching_rule("C3","C1xC2","orthogonal_sum")*branching_rule("C1xC2","A1xC2",[branching_rule("C1","A1","isomorphic"),"identity"])""", + ] elif CartanType(ct) == CartanType("C4"): - rul = ["""A3:branching_rule("C4","A3","levi")""", """A1:branching_rule("C4","A1","symmetric_power")""", """A1xA3:branching_rule("C4","C1xC3","orthogonal_sum")*branching_rule("C1xC3","A1xA3",[branching_rule("C1","A1","isomorphic"),"identity"])""", """C2xC2:branching_rule("C4","C2xC2","orthogonal_sum")""", """A1xA1xA1:branching_rule("C4","C1xD2","tensor")*branching_rule("C1xD2","A1xA1xA1",[branching_rule("C1","A1","isomorphic"),branching_rule("D2","A1xA1","isomorphic")])"""] + rul = [ + """A3:branching_rule("C4","A3","levi")""", + """A1:branching_rule("C4","A1","symmetric_power")""", + """A1xA3:branching_rule("C4","C1xC3","orthogonal_sum")*branching_rule("C1xC3","A1xA3",[branching_rule("C1","A1","isomorphic"),"identity"])""", + """C2xC2:branching_rule("C4","C2xC2","orthogonal_sum")""", + """A1xA1xA1:branching_rule("C4","C1xD2","tensor")*branching_rule("C1xD2","A1xA1xA1",[branching_rule("C1","A1","isomorphic"),branching_rule("D2","A1xA1","isomorphic")])""", + ] elif CartanType(ct) == CartanType("C5"): - rul = ["""A4:branching_rule("C5","A4","levi")""", """A1:branching_rule("C5","A1","symmetric_power")""", """A1xC4:branching_rule("C5","C1xC4","orthogonal_sum")*branching_rule("C1xC4","A1xC4",[branching_rule("C1","A1","isomorphic"),"identity"])""", """C2xC3:branching_rule("C5","C2xC3","orthogonal_sum")""", """A1xB2:branching_rule("C5","C1xB2","tensor")*branching_rule("C1xB2","A1xB2",[branching_rule("C1","A1","isomorphic"),"identity"])"""] + rul = [ + """A4:branching_rule("C5","A4","levi")""", + """A1:branching_rule("C5","A1","symmetric_power")""", + """A1xC4:branching_rule("C5","C1xC4","orthogonal_sum")*branching_rule("C1xC4","A1xC4",[branching_rule("C1","A1","isomorphic"),"identity"])""", + """C2xC3:branching_rule("C5","C2xC3","orthogonal_sum")""", + """A1xB2:branching_rule("C5","C1xB2","tensor")*branching_rule("C1xB2","A1xB2",[branching_rule("C1","A1","isomorphic"),"identity"])""", + ] elif CartanType(ct) == CartanType("C6"): - rul = ["""A5:branching_rule("C6","A5","levi")""", """A1:branching_rule("C6","A1","symmetric_power")""", """A1xA3:branching_rule("C6","C1xD3","tensor")*branching_rule("C1xD3","A1xA3",[branching_rule("C1","A1","isomorphic"),branching_rule("D3","A3","isomorphic")])""", """A1xC2:branching_rule("C6","B1xC2","tensor")*branching_rule("B1xC2","A1xC2",[branching_rule("B1","A1","isomorphic"),"identity"])""", """A1xC5:branching_rule("C6","C1xC5","orthogonal_sum")*branching_rule("C1xC5","A1xC5",[branching_rule("C1","A1","isomorphic"),"identity"])""", """C2xC4:branching_rule("C6","C2xC4","orthogonal_sum")""", """C3xC3:branching_rule("C6","C3xC3","orthogonal_sum")"""] + rul = [ + """A5:branching_rule("C6","A5","levi")""", + """A1:branching_rule("C6","A1","symmetric_power")""", + """A1xA3:branching_rule("C6","C1xD3","tensor")*branching_rule("C1xD3","A1xA3",[branching_rule("C1","A1","isomorphic"),branching_rule("D3","A3","isomorphic")])""", + """A1xC2:branching_rule("C6","B1xC2","tensor")*branching_rule("B1xC2","A1xC2",[branching_rule("B1","A1","isomorphic"),"identity"])""", + """A1xC5:branching_rule("C6","C1xC5","orthogonal_sum")*branching_rule("C1xC5","A1xC5",[branching_rule("C1","A1","isomorphic"),"identity"])""", + """C2xC4:branching_rule("C6","C2xC4","orthogonal_sum")""", + """C3xC3:branching_rule("C6","C3xC3","orthogonal_sum")""", + ] elif CartanType(ct) == CartanType("C7"): - rul = ["""A6:branching_rule("C7","A6","levi")""", """A1:branching_rule("C7","A1","symmetric_power")""", """A1xB3:branching_rule("C7","C1xB3","tensor")*branching_rule("C1xB3","A1xB3",[branching_rule("C1","A1","isomorphic"),"identity"])""", """A1xC6:branching_rule("C7","C1xC6","orthogonal_sum")*branching_rule("C1xC6","A1xC6",[branching_rule("C1","A1","isomorphic"),"identity"])""", """C2xC5:branching_rule("C7","C2xC5","orthogonal_sum")""", """C3xC4:branching_rule("C7","C3xC4","orthogonal_sum")""", """C3:branching_rule("C7","C3(0,0,1)","plethysm") # overlooked by Patera and McKay"""] + rul = [ + """A6:branching_rule("C7","A6","levi")""", + """A1:branching_rule("C7","A1","symmetric_power")""", + """A1xB3:branching_rule("C7","C1xB3","tensor")*branching_rule("C1xB3","A1xB3",[branching_rule("C1","A1","isomorphic"),"identity"])""", + """A1xC6:branching_rule("C7","C1xC6","orthogonal_sum")*branching_rule("C1xC6","A1xC6",[branching_rule("C1","A1","isomorphic"),"identity"])""", + """C2xC5:branching_rule("C7","C2xC5","orthogonal_sum")""", + """C3xC4:branching_rule("C7","C3xC4","orthogonal_sum")""", + """C3:branching_rule("C7","C3(0,0,1)","plethysm") # overlooked by Patera and McKay""", + ] elif CartanType(ct) == CartanType("C8"): - rul = ["""A7:branching_rule("C8","A7","levi")""", """A1:branching_rule("C8","A1","symmetric_power")""", """C2:branching_rule("C8","C2(1,1)","plethysm")""", """A1xD4:branching_rule("C8","C1xD4","tensor")*branching_rule("C1xD4","A1xD4",[branching_rule("C1","A1","isomorphic"),"identity"])""", """A1xC7:branching_rule("C8","C1xC7","orthogonal_sum")*branching_rule("C1xC7","A1xC7",[branching_rule("C1","A1","isomorphic"),"identity"])""", """C2xC6:branching_rule("C8","C2xC6","orthogonal_sum")""", """C3xC5:branching_rule("C8","C3xC5","orthogonal_sum")""", """C4xC4:branching_rule("C8","C4xC4","orthogonal_sum")"""] + rul = [ + """A7:branching_rule("C8","A7","levi")""", + """A1:branching_rule("C8","A1","symmetric_power")""", + """C2:branching_rule("C8","C2(1,1)","plethysm")""", + """A1xD4:branching_rule("C8","C1xD4","tensor")*branching_rule("C1xD4","A1xD4",[branching_rule("C1","A1","isomorphic"),"identity"])""", + """A1xC7:branching_rule("C8","C1xC7","orthogonal_sum")*branching_rule("C1xC7","A1xC7",[branching_rule("C1","A1","isomorphic"),"identity"])""", + """C2xC6:branching_rule("C8","C2xC6","orthogonal_sum")""", + """C3xC5:branching_rule("C8","C3xC5","orthogonal_sum")""", + """C4xC4:branching_rule("C8","C4xC4","orthogonal_sum")""", + ] elif CartanType(ct) == CartanType("D4"): - rul = ["""B3:branching_rule("D4","B3","symmetric")""", """A2:branching_rule("D4","A2(1,1)","plethysm")""", """A1xC2:branching_rule("D4","C1xC2","tensor")*branching_rule("C1xC2","A1xC2",[branching_rule("C1","A1","isomorphic"),"identity"])""", """A1xA1xA1xA1:branching_rule("D4","D2xD2","orthogonal_sum")*branching_rule("D2xD2","A1xA1xA1xA1",[branching_rule("D2","A1xA1","isomorphic"),branching_rule("D2","A1xA1","isomorphic")])"""] + rul = [ + """B3:branching_rule("D4","B3","symmetric")""", + """A2:branching_rule("D4","A2(1,1)","plethysm")""", + """A1xC2:branching_rule("D4","C1xC2","tensor")*branching_rule("C1xC2","A1xC2",[branching_rule("C1","A1","isomorphic"),"identity"])""", + """A1xA1xA1xA1:branching_rule("D4","D2xD2","orthogonal_sum")*branching_rule("D2xD2","A1xA1xA1xA1",[branching_rule("D2","A1xA1","isomorphic"),branching_rule("D2","A1xA1","isomorphic")])""", + ] elif CartanType(ct) == CartanType("D5"): - rul = ["""A4:branching_rule("D5","A4","levi")""", """B4:branching_rule("D5","B4","symmetric")""", """C2:branching_rule("D5","C2(2,0)","plethysm")""", """A1xA1xA3:branching_rule("D5","D2xD3","orthogonal_sum")*branching_rule("D2xD3","A1xA1xA3",[branching_rule("D2","A1xA1","isomorphic"),branching_rule("D3","A3","isomorphic")])""", """A1xA3:branching_rule("D5","B1xB3","orthogonal_sum")*branching_rule("B1xB3","A1xA3",[branching_rule("B1","A1","isomorphic"),"identity"])""", """B2xB2:branching_rule("D5","B2xB2","orthogonal_sum")"""] + rul = [ + """A4:branching_rule("D5","A4","levi")""", + """B4:branching_rule("D5","B4","symmetric")""", + """C2:branching_rule("D5","C2(2,0)","plethysm")""", + """A1xA1xA3:branching_rule("D5","D2xD3","orthogonal_sum")*branching_rule("D2xD3","A1xA1xA3",[branching_rule("D2","A1xA1","isomorphic"),branching_rule("D3","A3","isomorphic")])""", + """A1xA3:branching_rule("D5","B1xB3","orthogonal_sum")*branching_rule("B1xB3","A1xA3",[branching_rule("B1","A1","isomorphic"),"identity"])""", + """B2xB2:branching_rule("D5","B2xB2","orthogonal_sum")""", + ] elif CartanType(ct) == CartanType("D6"): - rul = ["""A5:branching_rule("D6","A5","levi")""", """B5:branching_rule("D6","B5","symmetric")""", """A1xA3:branching_rule("D6","C1xC3","tensor")*branching_rule("C1xC3","A1xA3",[branching_rule("C1","A1","isomorphic"),"identity"])""", """A1xA1xD4:branching_rule("D6","D2xD4","orthogonal_sum")*branching_rule("D2xD4","A1xA1xD4",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", """A3xA3:branching_rule("D6","D3xD3","orthogonal_sum")*branching_rule("D3xD3","A3xA3",[branching_rule("D3","A3","isomorphic"),branching_rule("D3","A3","isomorphic")])""", """A1xB4:branching_rule("D6","B1xB4","orthogonal_sum")*branching_rule("B1xB4","A1xB4",[branching_rule("B1","A1","isomorphic"),"identity"])""", """B2xB3:branching_rule("D6","B2xB3","orthogonal_sum")""", """A1xA1xA1:branching_rule("D6","B1xD2","tensor")*branching_rule("B1xD2","A1xA1xA1",[branching_rule("B1","A1","isomorphic"),branching_rule("D2","A1xA1","isomorphic")])"""] + rul = [ + """A5:branching_rule("D6","A5","levi")""", + """B5:branching_rule("D6","B5","symmetric")""", + """A1xA3:branching_rule("D6","C1xC3","tensor")*branching_rule("C1xC3","A1xA3",[branching_rule("C1","A1","isomorphic"),"identity"])""", + """A1xA1xD4:branching_rule("D6","D2xD4","orthogonal_sum")*branching_rule("D2xD4","A1xA1xD4",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", + """A3xA3:branching_rule("D6","D3xD3","orthogonal_sum")*branching_rule("D3xD3","A3xA3",[branching_rule("D3","A3","isomorphic"),branching_rule("D3","A3","isomorphic")])""", + """A1xB4:branching_rule("D6","B1xB4","orthogonal_sum")*branching_rule("B1xB4","A1xB4",[branching_rule("B1","A1","isomorphic"),"identity"])""", + """B2xB3:branching_rule("D6","B2xB3","orthogonal_sum")""", + """A1xA1xA1:branching_rule("D6","B1xD2","tensor")*branching_rule("B1xD2","A1xA1xA1",[branching_rule("B1","A1","isomorphic"),branching_rule("D2","A1xA1","isomorphic")])""", + ] elif CartanType(ct) == CartanType("D7"): - rul = ["""A6:branching_rule("D7","A6","levi")""", """B6:branching_rule("D7","B6","symmetric")""", """C3:branching_rule("D7","C3(0,1,0)","plethysm")""", """C2:branching_rule("D7","C2(0,2)","plethysm")""", """G2:branching_rule("D7","G2(0,1)","plethysm")""", """A1xA1xD5:branching_rule("D7","D2xD5","orthogonal_sum")*branching_rule("D2xD5","A1xA1xD5",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", """A3xD4:branching_rule("D7","D3xD4","orthogonal_sum")*branching_rule("D3xD4","A3xD4",[branching_rule("D3","A3","isomorphic"),"identity"])""", """A1xB5:branching_rule("D7","B1xB5","orthogonal_sum")*branching_rule("B1xB5","A1xB5",[branching_rule("B1","A1","isomorphic"),"identity"])""", """B2xB4:branching_rule("D7","B2xB4","orthogonal_sum")""", """B3xB3:branching_rule("D7","B3xB3","orthogonal_sum")"""] + rul = [ + """A6:branching_rule("D7","A6","levi")""", + """B6:branching_rule("D7","B6","symmetric")""", + """C3:branching_rule("D7","C3(0,1,0)","plethysm")""", + """C2:branching_rule("D7","C2(0,2)","plethysm")""", + """G2:branching_rule("D7","G2(0,1)","plethysm")""", + """A1xA1xD5:branching_rule("D7","D2xD5","orthogonal_sum")*branching_rule("D2xD5","A1xA1xD5",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", + """A3xD4:branching_rule("D7","D3xD4","orthogonal_sum")*branching_rule("D3xD4","A3xD4",[branching_rule("D3","A3","isomorphic"),"identity"])""", + """A1xB5:branching_rule("D7","B1xB5","orthogonal_sum")*branching_rule("B1xB5","A1xB5",[branching_rule("B1","A1","isomorphic"),"identity"])""", + """B2xB4:branching_rule("D7","B2xB4","orthogonal_sum")""", + """B3xB3:branching_rule("D7","B3xB3","orthogonal_sum")""", + ] elif CartanType(ct) == CartanType("D8"): - rul = ["""A7:branching_rule("D8","A7","levi")""", """B7:branching_rule("D8","B7","symmetric")""", """B4:branching_rule("D8","B4(0,0,0,1)","plethysm")""", """A1xC4:branching_rule("D8","C1xC4","tensor")*branching_rule("C1xC4","A1xC4",[branching_rule("C1","A1","isomorphic"),"identity"])""", """A1xA1xD6:branching_rule("D8","D2xD6","orthogonal_sum")*branching_rule("D2xD6","A1xA1xD6",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", """A3xD5:branching_rule("D8","D3xD5","orthogonal_sum")*branching_rule("D3xD5","A3xD5",[branching_rule("D3","A3","isomorphic"),"identity"])""", """D4xD4:branching_rule("D8","D4xD4","orthogonal_sum")""", """A1xB6:branching_rule("D8","B1xB6","orthogonal_sum")*branching_rule("B1xB6","A1xB6",[branching_rule("B1","A1","isomorphic"),"identity"])""", """B2xB5:branching_rule("D8","B2xB5","orthogonal_sum")""", """B3xB4:branching_rule("D8","B3xB4","orthogonal_sum")""", """C2xC2:branching_rule("D8","C2xC2","tensor")"""] + rul = [ + """A7:branching_rule("D8","A7","levi")""", + """B7:branching_rule("D8","B7","symmetric")""", + """B4:branching_rule("D8","B4(0,0,0,1)","plethysm")""", + """A1xC4:branching_rule("D8","C1xC4","tensor")*branching_rule("C1xC4","A1xC4",[branching_rule("C1","A1","isomorphic"),"identity"])""", + """A1xA1xD6:branching_rule("D8","D2xD6","orthogonal_sum")*branching_rule("D2xD6","A1xA1xD6",[branching_rule("D2","A1xA1","isomorphic"),"identity"])""", + """A3xD5:branching_rule("D8","D3xD5","orthogonal_sum")*branching_rule("D3xD5","A3xD5",[branching_rule("D3","A3","isomorphic"),"identity"])""", + """D4xD4:branching_rule("D8","D4xD4","orthogonal_sum")""", + """A1xB6:branching_rule("D8","B1xB6","orthogonal_sum")*branching_rule("B1xB6","A1xB6",[branching_rule("B1","A1","isomorphic"),"identity"])""", + """B2xB5:branching_rule("D8","B2xB5","orthogonal_sum")""", + """B3xB4:branching_rule("D8","B3xB4","orthogonal_sum")""", + """C2xC2:branching_rule("D8","C2xC2","tensor")""", + ] elif CartanType(ct) == CartanType("G2"): rul = ["""A2:branching_rule("G2","A2","extended")""", """A1:branching_rule("G2","A1","i")""", """A1xA1:branching_rule("G2","A1xA1","extended")"""] elif CartanType(ct) == CartanType("F4"): rul = ["""B4:branching_rule("F4","B4","extended")""", """A1:branching_rule("F4","A1","ii")""", """A1xG2:branching_rule("F4","A1xG2","miscellaneous")""", """A1xC3:branching_rule("F4","A1xC3","extended")""", """A2xA2:branching_rule("F4","A2xA2","extended")"""] elif CartanType(ct) == CartanType("E6"): - rul = ["""D5:branching_rule("E6","D5","levi")""", """C4:branching_rule("E6","C4","symmetric")""", """F4:branching_rule("E6","F4","symmetric")""", """A2:branching_rule("E6","A2","miscellaneous")""", """G2:branching_rule("E6","G2","miscellaneous")""", """A2xG2:branching_rule("E6","A2xG2","miscellaneous")""", """A1xA5:branching_rule("E6","A1xA5","extended")""", """A2xA2xA2:branching_rule("E6","A2xA2xA2","extended")"""] + rul = [ + """D5:branching_rule("E6","D5","levi")""", + """C4:branching_rule("E6","C4","symmetric")""", + """F4:branching_rule("E6","F4","symmetric")""", + """A2:branching_rule("E6","A2","miscellaneous")""", + """G2:branching_rule("E6","G2","miscellaneous")""", + """A2xG2:branching_rule("E6","A2xG2","miscellaneous")""", + """A1xA5:branching_rule("E6","A1xA5","extended")""", + """A2xA2xA2:branching_rule("E6","A2xA2xA2","extended")""", + ] elif CartanType(ct) == CartanType("E7"): - rul = ["""A7:branching_rule("E7","A7","extended")""", """E6:branching_rule("E7","E6","levi")""", """A2:branching_rule("E7","A2","miscellaneous")""", """A1:branching_rule("E7","A1","iii")""", """A1:branching_rule("E7","A1","iv")""", """A1xF4:branching_rule("E7","A1xF4","miscellaneous")""", """G2xC3:branching_rule("E7","G2xC3","miscellaneous")""", """A1xG2:branching_rule("E7","A1xG2","miscellaneous")""", """A1xA1:branching_rule("E7","A1xA1","miscellaneous")""", """A1xD6:branching_rule("E7","A1xD6","extended")""", """A5xA2:branching_rule("E7","A5xA2","extended")"""] + rul = [ + """A7:branching_rule("E7","A7","extended")""", + """E6:branching_rule("E7","E6","levi")""", + """A2:branching_rule("E7","A2","miscellaneous")""", + """A1:branching_rule("E7","A1","iii")""", + """A1:branching_rule("E7","A1","iv")""", + """A1xF4:branching_rule("E7","A1xF4","miscellaneous")""", + """G2xC3:branching_rule("E7","G2xC3","miscellaneous")""", + """A1xG2:branching_rule("E7","A1xG2","miscellaneous")""", + """A1xA1:branching_rule("E7","A1xA1","miscellaneous")""", + """A1xD6:branching_rule("E7","A1xD6","extended")""", + """A5xA2:branching_rule("E7","A5xA2","extended")""", + ] elif CartanType(ct) == CartanType("E8"): - rul = ["""A4xA4:branching_rule("E8","A4xA4","extended")""", """G2xF4:branching_rule("E8","G2xF4","miscellaneous")""", """E6xA2:branching_rule("E8","E6xA2","extended")""", """E7xA1:branching_rule("E8","E7xA1","extended")""", """D8:branching_rule("E8","D8","extended")""", """A8:branching_rule("E8","A8","extended")""", """B2:branching_rule("E8","B2","miscellaneous")""", """A1xA2:branching_rule("E8","A1xA2","miscellaneous")""", """A1:branching_rule("E8","A1","v")""", """A1:branching_rule("E8","A1","vi")""", """A1:branching_rule("E8","A1","vii")"""] + rul = [ + """A4xA4:branching_rule("E8","A4xA4","extended")""", + """G2xF4:branching_rule("E8","G2xF4","miscellaneous")""", + """E6xA2:branching_rule("E8","E6xA2","extended")""", + """E7xA1:branching_rule("E8","E7xA1","extended")""", + """D8:branching_rule("E8","D8","extended")""", + """A8:branching_rule("E8","A8","extended")""", + """B2:branching_rule("E8","B2","miscellaneous")""", + """A1xA2:branching_rule("E8","A1xA2","miscellaneous")""", + """A1:branching_rule("E8","A1","v")""", + """A1:branching_rule("E8","A1","vi")""", + """A1:branching_rule("E8","A1","vii")""", + ] else: raise ValueError("Argument must be an irreducible classical Cartan Type with rank less than or equal to 8") if mode == "print_rules": diff --git a/src/sage/combinat/root_system/cartan_type.py b/src/sage/combinat/root_system/cartan_type.py index 85e9e56236d..876c6167eca 100644 --- a/src/sage/combinat/root_system/cartan_type.py +++ b/src/sage/combinat/root_system/cartan_type.py @@ -856,7 +856,13 @@ def _samples(self): # Support for hand constructed Dynkin diagrams as Cartan types is not yet ready enough for including an example here. # from sage.combinat.root_system.dynkin_diagram import DynkinDiagram_class # g = DynkinDiagram_class.an_instance() - return finite_crystallographic + [CartanType(t) for t in [["I", 5], ["H", 3], ["H", 4]]] + [t.affine() for t in finite_crystallographic if t.is_irreducible()] + [CartanType(t) for t in [["BC", 1, 2], ["BC", 5, 2]]] + [CartanType(t).dual() for t in [["B", 5, 1], ["C", 4, 1], ["F", 4, 1], ["G", 2, 1], ["BC", 1, 2], ["BC", 5, 2]]] # + \ + return ( + finite_crystallographic + + [CartanType(t) for t in [["I", 5], ["H", 3], ["H", 4]]] + + [t.affine() for t in finite_crystallographic if t.is_irreducible()] + + [CartanType(t) for t in [["BC", 1, 2], ["BC", 5, 2]]] + + [CartanType(t).dual() for t in [["B", 5, 1], ["C", 4, 1], ["F", 4, 1], ["G", 2, 1], ["BC", 1, 2], ["BC", 5, 2]]] + ) # + \ # [ g ] _colors = {1: 'blue', -1: 'blue', 2: 'red', -2: 'red', 3: 'green', -3: 'green', 4: 'cyan', -4: 'cyan', 5: 'magenta', -5: 'magenta', 6: 'yellow', -6: 'yellow'} diff --git a/src/sage/combinat/root_system/type_E.py b/src/sage/combinat/root_system/type_E.py index b6b0648dc4d..27b83e535f3 100644 --- a/src/sage/combinat/root_system/type_E.py +++ b/src/sage/combinat/root_system/type_E.py @@ -362,11 +362,24 @@ def positive_roots(self): # Note that if not hasattr(self, 'PosRoots'): if self.rank == 6: - self.PosRoots = [self.root(i, j) for i in range(self.rank - 1) for j in range(i + 1, self.rank - 1)] + [self.root(i, j, p1=1) for i in range(self.rank - 1) for j in range(i + 1, self.rank - 1)] + [v * (self.root(7) - self.root(6) - self.root(5) + self.root(0, 1, 2, 3, 4, p1=p1, p2=p2, p3=p3, p4=p4, p5=p5)) for p1 in [0, 1] for p2 in [0, 1] for p3 in [0, 1] for p4 in [0, 1] for p5 in [0, 1] if (p1 + p2 + p3 + p4 + p5) % 2 == 0] + self.PosRoots = ( + [self.root(i, j) for i in range(self.rank - 1) for j in range(i + 1, self.rank - 1)] + + [self.root(i, j, p1=1) for i in range(self.rank - 1) for j in range(i + 1, self.rank - 1)] + + [v * (self.root(7) - self.root(6) - self.root(5) + self.root(0, 1, 2, 3, 4, p1=p1, p2=p2, p3=p3, p4=p4, p5=p5)) for p1 in [0, 1] for p2 in [0, 1] for p3 in [0, 1] for p4 in [0, 1] for p5 in [0, 1] if (p1 + p2 + p3 + p4 + p5) % 2 == 0] + ) elif self.rank == 7: - self.PosRoots = [self.root(i, j) for i in range(self.rank - 1) for j in range(i + 1, self.rank - 1)] + [self.root(i, j, p1=1) for i in range(self.rank - 1) for j in range(i + 1, self.rank - 1)] + [self.root(6, 7, p1=1)] + [v * (self.root(7) - self.root(6) + self.root(0, 1, 2, 3, 4, 5, p1=p1, p2=p2, p3=p3, p4=p4, p5=p5, p6=p6)) for p1 in [0, 1] for p2 in [0, 1] for p3 in [0, 1] for p4 in [0, 1] for p5 in [0, 1] for p6 in [0, 1] if (p1 + p2 + p3 + p4 + p5 + p6) % 2 == 1] + self.PosRoots = ( + [self.root(i, j) for i in range(self.rank - 1) for j in range(i + 1, self.rank - 1)] + + [self.root(i, j, p1=1) for i in range(self.rank - 1) for j in range(i + 1, self.rank - 1)] + + [self.root(6, 7, p1=1)] + + [v * (self.root(7) - self.root(6) + self.root(0, 1, 2, 3, 4, 5, p1=p1, p2=p2, p3=p3, p4=p4, p5=p5, p6=p6)) for p1 in [0, 1] for p2 in [0, 1] for p3 in [0, 1] for p4 in [0, 1] for p5 in [0, 1] for p6 in [0, 1] if (p1 + p2 + p3 + p4 + p5 + p6) % 2 == 1] + ) elif self.rank == 8: - self.PosRoots = [self.root(i, j) for i in range(self.rank) for j in range(i + 1, self.rank)] + [self.root(i, j, p1=1) for i in range(self.rank) for j in range(i + 1, self.rank)] + [v * (self.root(7) + self.root(0, 1, 2, 3, 4, 5, 6, p1=p1, p2=p2, p3=p3, p4=p4, p5=p5, p6=p6, p7=p7)) for p1 in [0, 1] for p2 in [0, 1] for p3 in [0, 1] for p4 in [0, 1] for p5 in [0, 1] for p6 in [0, 1] for p7 in [0, 1] if (p1 + p2 + p3 + p4 + p5 + p6 + p7) % 2 == 0] + self.PosRoots = ( + [self.root(i, j) for i in range(self.rank) for j in range(i + 1, self.rank)] + + [self.root(i, j, p1=1) for i in range(self.rank) for j in range(i + 1, self.rank)] + + [v * (self.root(7) + self.root(0, 1, 2, 3, 4, 5, 6, p1=p1, p2=p2, p3=p3, p4=p4, p5=p5, p6=p6, p7=p7)) for p1 in [0, 1] for p2 in [0, 1] for p3 in [0, 1] for p4 in [0, 1] for p5 in [0, 1] for p6 in [0, 1] for p7 in [0, 1] if (p1 + p2 + p3 + p4 + p5 + p6 + p7) % 2 == 0] + ) return self.PosRoots @@ -381,11 +394,41 @@ def fundamental_weights(self): v2 = ZZ(1) / ZZ(2) v3 = ZZ(1) / ZZ(3) if self.rank == 6: - return Family({1: 2 * v3 * self.root(7, 6, 5, p2=1, p3=1), 2: v2 * self.root(0, 1, 2, 3, 4, 5, 6, 7, p6=1, p7=1), 3: 5 * v2 * v3 * self.root(7, 6, 5, p2=1, p3=1) + v2 * self.root(0, 1, 2, 3, 4, p1=1), 4: self.root(2, 3, 4, 5, 6, 7, p4=1, p5=1), 5: 2 * v3 * self.root(7, 6, 5, p2=1, p3=1) + self.root(3, 4), 6: v3 * self.root(7, 6, 5, p2=1, p3=1) + self.root(4)}) + return Family( + { + 1: 2 * v3 * self.root(7, 6, 5, p2=1, p3=1), + 2: v2 * self.root(0, 1, 2, 3, 4, 5, 6, 7, p6=1, p7=1), + 3: 5 * v2 * v3 * self.root(7, 6, 5, p2=1, p3=1) + v2 * self.root(0, 1, 2, 3, 4, p1=1), + 4: self.root(2, 3, 4, 5, 6, 7, p4=1, p5=1), + 5: 2 * v3 * self.root(7, 6, 5, p2=1, p3=1) + self.root(3, 4), + 6: v3 * self.root(7, 6, 5, p2=1, p3=1) + self.root(4), + } + ) if self.rank == 7: - return Family({1: self.root(7, 6, p2=1), 2: v2 * self.root(0, 1, 2, 3, 4, 5) + self.root(6, 7, p1=1), 3: v2 * (self.root(0, 1, 2, 3, 4, 5, p1=1) + 3 * self.root(6, 7, p1=1)), 4: self.root(2, 3, 4, 5) + 2 * self.root(6, 7, p1=1), 5: 3 * v2 * self.root(6, 7, p1=1) + self.root(3, 4, 5), 6: self.root(4, 5, 6, 7, p3=1), 7: self.root(5) + v2 * self.root(6, 7, p1=1)}) + return Family( + { + 1: self.root(7, 6, p2=1), + 2: v2 * self.root(0, 1, 2, 3, 4, 5) + self.root(6, 7, p1=1), + 3: v2 * (self.root(0, 1, 2, 3, 4, 5, p1=1) + 3 * self.root(6, 7, p1=1)), + 4: self.root(2, 3, 4, 5) + 2 * self.root(6, 7, p1=1), + 5: 3 * v2 * self.root(6, 7, p1=1) + self.root(3, 4, 5), + 6: self.root(4, 5, 6, 7, p3=1), + 7: self.root(5) + v2 * self.root(6, 7, p1=1), + } + ) if self.rank == 8: - return Family({1: 2 * self.root(7), 2: v2 * (self.root(0, 1, 2, 3, 4, 5, 6) + 5 * self.root(7)), 3: v2 * (self.root(0, 1, 2, 3, 4, 5, 6, p1=1) + 7 * self.root(7)), 4: self.root(2, 3, 4, 5, 6) + 5 * self.root(7), 5: self.root(3, 4, 5, 6) + 4 * self.root(7), 6: self.root(4, 5, 6) + 3 * self.root(7), 7: self.root(5, 6) + 2 * self.root(7), 8: self.root(6, 7)}) + return Family( + { + 1: 2 * self.root(7), + 2: v2 * (self.root(0, 1, 2, 3, 4, 5, 6) + 5 * self.root(7)), + 3: v2 * (self.root(0, 1, 2, 3, 4, 5, 6, p1=1) + 7 * self.root(7)), + 4: self.root(2, 3, 4, 5, 6) + 5 * self.root(7), + 5: self.root(3, 4, 5, 6) + 4 * self.root(7), + 6: self.root(4, 5, 6) + 3 * self.root(7), + 7: self.root(5, 6) + 2 * self.root(7), + 8: self.root(6, 7), + } + ) from .cartan_type import CartanType_standard_finite, CartanType_simple, CartanType_simply_laced diff --git a/src/sage/combinat/root_system/type_F.py b/src/sage/combinat/root_system/type_F.py index c42ea820250..4a70ed57f11 100644 --- a/src/sage/combinat/root_system/type_F.py +++ b/src/sage/combinat/root_system/type_F.py @@ -173,7 +173,9 @@ def positive_roots(self): """ v = ZZ(1) / ZZ(2) if not hasattr(self, 'PosRoots'): - self.PosRoots = [self.monomial(i) for i in range(self.n)] + [self.root(i, j, p2=0) for i in range(self.n) for j in range(i + 1, self.n)] + [self.root(i, j, p2=1) for i in range(self.n) for j in range(i + 1, self.n)] + [v * self.root(0, 1, 2, 3, 0, p2, p3, p4) for p2 in [0, 1] for p3 in [0, 1] for p4 in [0, 1]] + self.PosRoots = ( + [self.monomial(i) for i in range(self.n)] + [self.root(i, j, p2=0) for i in range(self.n) for j in range(i + 1, self.n)] + [self.root(i, j, p2=1) for i in range(self.n) for j in range(i + 1, self.n)] + [v * self.root(0, 1, 2, 3, 0, p2, p3, p4) for p2 in [0, 1] for p3 in [0, 1] for p4 in [0, 1]] + ) return self.PosRoots def fundamental_weights(self): diff --git a/src/sage/combinat/root_system/weyl_group.py b/src/sage/combinat/root_system/weyl_group.py index ff5595df90b..bb0418bd4e1 100644 --- a/src/sage/combinat/root_system/weyl_group.py +++ b/src/sage/combinat/root_system/weyl_group.py @@ -535,7 +535,16 @@ def long_element_hardcoded(self): elif typ[0] == 'E': if typ[1] == 6: half = QQ((1, 2)) - l = [[-half, -half, -half, half, 0, 0, 0, 0], [-half, -half, half, -half, 0, 0, 0, 0], [-half, half, -half, -half, 0, 0, 0, 0], [half, -half, -half, -half, 0, 0, 0, 0], [0, 0, 0, 0, half, half, half, -half], [0, 0, 0, 0, half, half, -half, half], [0, 0, 0, 0, half, -half, half, half], [0, 0, 0, 0, -half, half, half, half]] + l = [ + [-half, -half, -half, half, 0, 0, 0, 0], + [-half, -half, half, -half, 0, 0, 0, 0], + [-half, half, -half, -half, 0, 0, 0, 0], + [half, -half, -half, -half, 0, 0, 0, 0], + [0, 0, 0, 0, half, half, half, -half], + [0, 0, 0, 0, half, half, -half, half], + [0, 0, 0, 0, half, -half, half, half], + [0, 0, 0, 0, -half, half, half, half], + ] m = matrix(QQ, 8, l) else: raise NotImplementedError("not implemented yet for this type") diff --git a/src/sage/combinat/skew_partition.py b/src/sage/combinat/skew_partition.py index 6a3f288dfdb..7cac185219b 100644 --- a/src/sage/combinat/skew_partition.py +++ b/src/sage/combinat/skew_partition.py @@ -1471,8 +1471,20 @@ class options(GlobalOptions): NAME = 'SkewPartitions' module = 'sage.combinat.skew_partition' - display = dict(default='quotient', description='Specifies how skew partitions should be printed', values=dict(lists='displayed as a pair of lists', quotient='displayed as a quotient of partitions', diagram='as a skew Ferrers diagram'), alias=dict(array='diagram', ferrers_diagram='diagram', young_diagram='diagram', pair='lists'), case_sensitive=False) - latex = dict(default='young_diagram', description='Specifies how skew partitions should be latexed', values=dict(diagram='latex as a skew Ferrers diagram', young_diagram='latex as a skew Young diagram', marked='latex as a partition where the skew shape is marked'), alias=dict(array='diagram', ferrers_diagram='diagram'), case_sensitive=False) + display = dict( + default='quotient', + description='Specifies how skew partitions should be printed', + values=dict(lists='displayed as a pair of lists', quotient='displayed as a quotient of partitions', diagram='as a skew Ferrers diagram'), + alias=dict(array='diagram', ferrers_diagram='diagram', young_diagram='diagram', pair='lists'), + case_sensitive=False, + ) + latex = dict( + default='young_diagram', + description='Specifies how skew partitions should be latexed', + values=dict(diagram='latex as a skew Ferrers diagram', young_diagram='latex as a skew Young diagram', marked='latex as a partition where the skew shape is marked'), + alias=dict(array='diagram', ferrers_diagram='diagram'), + case_sensitive=False, + ) diagram_str = dict(link_to=(Partitions.options, 'diagram_str')) latex_diagram_str = dict(link_to=(Partitions.options, 'latex_diagram_str')) latex_marking_str = dict(default='X', description='The character used to marked the deleted cells when latexing marked partitions', checker=lambda char: isinstance(char, str)) diff --git a/src/sage/combinat/superpartition.py b/src/sage/combinat/superpartition.py index 7a721329aa0..08647dca033 100644 --- a/src/sage/combinat/superpartition.py +++ b/src/sage/combinat/superpartition.py @@ -861,7 +861,12 @@ class options(GlobalOptions): NAME = 'SuperPartition' module = 'sage.combinat.superpartition' - display = dict(default='default', description="Specifies how the super partitions should " "be printed", values=dict(list="the super partitions are displayed in " "a list of two lists", pair="the super partition is displayed as a " "list of integers", default="the super partition is displayed in " "a form [fermionic part; bosonic part]"), case_sensitive=False) + display = dict( + default='default', + description="Specifies how the super partitions should " "be printed", + values=dict(list="the super partitions are displayed in " "a list of two lists", pair="the super partition is displayed as a " "list of integers", default="the super partition is displayed in " "a form [fermionic part; bosonic part]"), + case_sensitive=False, + ) def _element_constructor_(self, lst, check=True): """ diff --git a/src/sage/combinat/t_sequences.py b/src/sage/combinat/t_sequences.py index 8a5f57b62f3..7e8ebac5e1a 100644 --- a/src/sage/combinat/t_sequences.py +++ b/src/sage/combinat/t_sequences.py @@ -505,9 +505,19 @@ def T_sequences_smallcases(t, existence=False, check=True): False """ db = { - 47: [[1, -1, -1, 0, 0, -1, 1, -1] + [0] * 8 + [1, -1, -1, 0, 0, -1, -1] + [0] * 24, [0, 0, 0, -1, 1, 0, 0, 0, -1, -1, -1, 1, 1, 1, 1, 1, 0, 0, 0, 1, -1, 0, 0, 1] + [0] * 23, [0] * 26 + [-1, 0, 1, 0, 0, 0, 0, 1, -1, 1, 1, 1, 0, 0, 0, 0, 1, 0, -1, 0, 0], [0] * 24 + [1, 1, 0, -1, 0, -1, 1, 1, -1, 0, 0, 0, 0, 0, -1, 1, -1, -1, 0, -1, 0, -1, 1]], + 47: [ + [1, -1, -1, 0, 0, -1, 1, -1] + [0] * 8 + [1, -1, -1, 0, 0, -1, -1] + [0] * 24, + [0, 0, 0, -1, 1, 0, 0, 0, -1, -1, -1, 1, 1, 1, 1, 1, 0, 0, 0, 1, -1, 0, 0, 1] + [0] * 23, + [0] * 26 + [-1, 0, 1, 0, 0, 0, 0, 1, -1, 1, 1, 1, 0, 0, 0, 0, 1, 0, -1, 0, 0], + [0] * 24 + [1, 1, 0, -1, 0, -1, 1, 1, -1, 0, 0, 0, 0, 0, -1, 1, -1, -1, 0, -1, 0, -1, 1], + ], 65: [[0] * 33 + [1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1], [0] * 32 + [1] + [0] * 32, [1] * 5 + [-1, -1, 1, 1, -1, 1, -1, 1, 1] + [-1] * 7 + [1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1] + [0] * 33, [0] * 65], - 93: [[0, -1, 0, 0, -1, 1, 0, -1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, -1, 0, -1, 1, 1, 1, -1, 0, 1, 0, 0, 1] + [0] * 33 + [1, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 1, 0, 1] + [0] * 15, [-1, 0, -1, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, -1, 0, 0, 0, -1, 1, 0, 1] + [0] * 5 + [-1, 0, 1, 1] + [0] * 32 + [1, 1, 0, 0, 1, 1, 0, 1, -1, 0, 1, -1, 0, 0, -1] + [0] * 16, [0] * 32 + [1, 0, 0, 1, -1, 0, 1, -1, 0, -1, -1, 0, 0, -1, -1, 1, 0, 0, -1, 0, -1, 1, 1, 1, -1, 0, 1, 0, 0, 1] + [0] * 17 + [1, 1, 0, -1] + [0] * 5 + [1, 0, 1, -1, 0], [0] * 31 + [1, 0, 1, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, -1, 1, 0, 1] + [0] * 5 + [-1, 0, 1, 1] + [0] * 17 + [-1, 0, 0, -1, 0, 1, -1, -1, -1, 1, 0, 1, 0, 0, -1]], + 93: [ + [0, -1, 0, 0, -1, 1, 0, -1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, -1, 0, -1, 1, 1, 1, -1, 0, 1, 0, 0, 1] + [0] * 33 + [1, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 1, 0, 1] + [0] * 15, + [-1, 0, -1, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, -1, 0, 0, 0, -1, 1, 0, 1] + [0] * 5 + [-1, 0, 1, 1] + [0] * 32 + [1, 1, 0, 0, 1, 1, 0, 1, -1, 0, 1, -1, 0, 0, -1] + [0] * 16, + [0] * 32 + [1, 0, 0, 1, -1, 0, 1, -1, 0, -1, -1, 0, 0, -1, -1, 1, 0, 0, -1, 0, -1, 1, 1, 1, -1, 0, 1, 0, 0, 1] + [0] * 17 + [1, 1, 0, -1] + [0] * 5 + [1, 0, 1, -1, 0], + [0] * 31 + [1, 0, 1, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, -1, 1, 0, 1] + [0] * 5 + [-1, 0, 1, 1] + [0] * 17 + [-1, 0, 0, -1, 0, 1, -1, -1, -1, 1, 0, 1, 0, 0, -1], + ], } if t in db: diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index b02e291ae11..8a2e4101f8e 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -5617,7 +5617,13 @@ class options(GlobalOptions): NAME = 'Tableaux' module = 'sage.combinat.tableau' - display = dict(default='list', description='Controls the way in which tableaux are printed', values=dict(list='print tableaux as lists', diagram='display as Young diagram (similar to :meth:`~sage.combinat.tableau.Tableau.pp()`', compact='minimal length string representation'), alias=dict(array='diagram', ferrers_diagram='diagram', young_diagram='diagram'), case_sensitive=False) + display = dict( + default='list', + description='Controls the way in which tableaux are printed', + values=dict(list='print tableaux as lists', diagram='display as Young diagram (similar to :meth:`~sage.combinat.tableau.Tableau.pp()`', compact='minimal length string representation'), + alias=dict(array='diagram', ferrers_diagram='diagram', young_diagram='diagram'), + case_sensitive=False, + ) ascii_art = dict(default='repr', description='Controls the ascii art output for tableaux', values=dict(repr='display using the diagram string representation', table='display as a table', compact='minimal length ascii art'), case_sensitive=False) latex = dict(default='diagram', description='Controls the way in which tableaux are latexed', values=dict(list='as a list', diagram='as a Young diagram'), alias=dict(array='diagram', ferrers_diagram='diagram', young_diagram='diagram'), case_sensitive=False) convention = dict( diff --git a/src/sage/combinat/words/alphabet.py b/src/sage/combinat/words/alphabet.py index c78a4ef8c07..8a3309256ac 100644 --- a/src/sage/combinat/words/alphabet.py +++ b/src/sage/combinat/words/alphabet.py @@ -42,7 +42,19 @@ from sage.sets.totally_ordered_finite_set import TotallyOrderedFiniteSet -set_of_letters = {'lower': "abcdefghijklmnopqrstuvwxyz", 'upper': "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 'space': " ", 'underscore': "_", 'punctuation': " ,.;:!?", 'printable': "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", 'binary': "01", 'octal': "01234567", 'decimal': "0123456789", 'hexadecimal': "0123456789abcdef", 'radix64': "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"} +set_of_letters = { + 'lower': "abcdefghijklmnopqrstuvwxyz", + 'upper': "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + 'space': " ", + 'underscore': "_", + 'punctuation': " ,.;:!?", + 'printable': "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", + 'binary': "01", + 'octal': "01234567", + 'decimal': "0123456789", + 'hexadecimal': "0123456789abcdef", + 'radix64': "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", +} def build_alphabet(data=None, names=None, name=None): diff --git a/src/sage/crypto/block_cipher/des.py b/src/sage/crypto/block_cipher/des.py index 1b9c1ca8845..917b8dc6bf9 100644 --- a/src/sage/crypto/block_cipher/des.py +++ b/src/sage/crypto/block_cipher/des.py @@ -91,7 +91,16 @@ from itertools import chain -sboxes = [[DES_S1_1, DES_S1_2, DES_S1_3, DES_S1_4], [DES_S2_1, DES_S2_2, DES_S2_3, DES_S2_4], [DES_S3_1, DES_S3_2, DES_S3_3, DES_S3_4], [DES_S4_1, DES_S4_2, DES_S4_3, DES_S4_4], [DES_S5_1, DES_S5_2, DES_S5_3, DES_S5_4], [DES_S6_1, DES_S6_2, DES_S6_3, DES_S6_4], [DES_S7_1, DES_S7_2, DES_S7_3, DES_S7_4], [DES_S8_1, DES_S8_2, DES_S8_3, DES_S8_4]] +sboxes = [ + [DES_S1_1, DES_S1_2, DES_S1_3, DES_S1_4], + [DES_S2_1, DES_S2_2, DES_S2_3, DES_S2_4], + [DES_S3_1, DES_S3_2, DES_S3_3, DES_S3_4], + [DES_S4_1, DES_S4_2, DES_S4_3, DES_S4_4], + [DES_S5_1, DES_S5_2, DES_S5_3, DES_S5_4], + [DES_S6_1, DES_S6_2, DES_S6_3, DES_S6_4], + [DES_S7_1, DES_S7_2, DES_S7_3, DES_S7_4], + [DES_S8_1, DES_S8_2, DES_S8_3, DES_S8_4], +] class DES(SageObject): diff --git a/src/sage/crypto/block_cipher/miniaes.py b/src/sage/crypto/block_cipher/miniaes.py index 47845b781c9..461bfb79e0d 100644 --- a/src/sage/crypto/block_cipher/miniaes.py +++ b/src/sage/crypto/block_cipher/miniaes.py @@ -158,17 +158,119 @@ def __init__(self): # the S-box for decryption self._sboxD = SBox(14, 3, 4, 8, 1, 12, 10, 15, 7, 13, 9, 6, 11, 2, 0, 5) # nibble to finite field element - self._bin_to_GF = {B("0000"): K("0"), B("0001"): K("1"), B("0010"): K("x"), B("0011"): K("x + 1"), B("0100"): K("x^2"), B("0101"): K("x^2 + 1"), B("0110"): K("x^2 + x"), B("0111"): K("x^2 + x + 1"), B("1000"): K("x^3"), B("1001"): K("x^3 + 1"), B("1010"): K("x^3 + x"), B("1011"): K("x^3 + x + 1"), B("1100"): K("x^3 + x^2"), B("1101"): K("x^3 + x^2 + 1"), B("1110"): K("x^3 + x^2 + x"), B("1111"): K("x^3 + x^2 + x+ 1")} + self._bin_to_GF = { + B("0000"): K("0"), + B("0001"): K("1"), + B("0010"): K("x"), + B("0011"): K("x + 1"), + B("0100"): K("x^2"), + B("0101"): K("x^2 + 1"), + B("0110"): K("x^2 + x"), + B("0111"): K("x^2 + x + 1"), + B("1000"): K("x^3"), + B("1001"): K("x^3 + 1"), + B("1010"): K("x^3 + x"), + B("1011"): K("x^3 + x + 1"), + B("1100"): K("x^3 + x^2"), + B("1101"): K("x^3 + x^2 + 1"), + B("1110"): K("x^3 + x^2 + x"), + B("1111"): K("x^3 + x^2 + x+ 1"), + } # nibble to integer - self._bin_to_int = {B("0000"): Integer(0), B("0001"): Integer(1), B("0010"): Integer(2), B("0011"): Integer(3), B("0100"): Integer(4), B("0101"): Integer(5), B("0110"): Integer(6), B("0111"): Integer(7), B("1000"): Integer(8), B("1001"): Integer(9), B("1010"): Integer(10), B("1011"): Integer(11), B("1100"): Integer(12), B("1101"): Integer(13), B("1110"): Integer(14), B("1111"): Integer(15)} + self._bin_to_int = { + B("0000"): Integer(0), + B("0001"): Integer(1), + B("0010"): Integer(2), + B("0011"): Integer(3), + B("0100"): Integer(4), + B("0101"): Integer(5), + B("0110"): Integer(6), + B("0111"): Integer(7), + B("1000"): Integer(8), + B("1001"): Integer(9), + B("1010"): Integer(10), + B("1011"): Integer(11), + B("1100"): Integer(12), + B("1101"): Integer(13), + B("1110"): Integer(14), + B("1111"): Integer(15), + } # finite field element to nibble - self._GF_to_bin = {K("0"): B("0000"), K("1"): B("0001"), K("x"): B("0010"), K("x + 1"): B("0011"), K("x^2"): B("0100"), K("x^2 + 1"): B("0101"), K("x^2 + x"): B("0110"), K("x^2 + x + 1"): B("0111"), K("x^3"): B("1000"), K("x^3 + 1"): B("1001"), K("x^3 + x"): B("1010"), K("x^3 + x + 1"): B("1011"), K("x^3 + x^2"): B("1100"), K("x^3 + x^2 + 1"): B("1101"), K("x^3 + x^2 + x"): B("1110"), K("x^3 + x^2 + x+ 1"): B("1111")} + self._GF_to_bin = { + K("0"): B("0000"), + K("1"): B("0001"), + K("x"): B("0010"), + K("x + 1"): B("0011"), + K("x^2"): B("0100"), + K("x^2 + 1"): B("0101"), + K("x^2 + x"): B("0110"), + K("x^2 + x + 1"): B("0111"), + K("x^3"): B("1000"), + K("x^3 + 1"): B("1001"), + K("x^3 + x"): B("1010"), + K("x^3 + x + 1"): B("1011"), + K("x^3 + x^2"): B("1100"), + K("x^3 + x^2 + 1"): B("1101"), + K("x^3 + x^2 + x"): B("1110"), + K("x^3 + x^2 + x+ 1"): B("1111"), + } # finite field element to integer - self._GF_to_int = {K("0"): Integer(0), K("1"): Integer(1), K("x"): Integer(2), K("x + 1"): Integer(3), K("x^2"): Integer(4), K("x^2 + 1"): Integer(5), K("x^2 + x"): Integer(6), K("x^2 + x + 1"): Integer(7), K("x^3"): Integer(8), K("x^3 + 1"): Integer(9), K("x^3 + x"): Integer(10), K("x^3 + x + 1"): Integer(11), K("x^3 + x^2"): Integer(12), K("x^3 + x^2 + 1"): Integer(13), K("x^3 + x^2 + x"): Integer(14), K("x^3 + x^2 + x+ 1"): Integer(15)} + self._GF_to_int = { + K("0"): Integer(0), + K("1"): Integer(1), + K("x"): Integer(2), + K("x + 1"): Integer(3), + K("x^2"): Integer(4), + K("x^2 + 1"): Integer(5), + K("x^2 + x"): Integer(6), + K("x^2 + x + 1"): Integer(7), + K("x^3"): Integer(8), + K("x^3 + 1"): Integer(9), + K("x^3 + x"): Integer(10), + K("x^3 + x + 1"): Integer(11), + K("x^3 + x^2"): Integer(12), + K("x^3 + x^2 + 1"): Integer(13), + K("x^3 + x^2 + x"): Integer(14), + K("x^3 + x^2 + x+ 1"): Integer(15), + } # integer to nibble - self._int_to_bin = {Integer(0): B("0000"), Integer(1): B("0001"), Integer(2): B("0010"), Integer(3): B("0011"), Integer(4): B("0100"), Integer(5): B("0101"), Integer(6): B("0110"), Integer(7): B("0111"), Integer(8): B("1000"), Integer(9): B("1001"), Integer(10): B("1010"), Integer(11): B("1011"), Integer(12): B("1100"), Integer(13): B("1101"), Integer(14): B("1110"), Integer(15): B("1111")} + self._int_to_bin = { + Integer(0): B("0000"), + Integer(1): B("0001"), + Integer(2): B("0010"), + Integer(3): B("0011"), + Integer(4): B("0100"), + Integer(5): B("0101"), + Integer(6): B("0110"), + Integer(7): B("0111"), + Integer(8): B("1000"), + Integer(9): B("1001"), + Integer(10): B("1010"), + Integer(11): B("1011"), + Integer(12): B("1100"), + Integer(13): B("1101"), + Integer(14): B("1110"), + Integer(15): B("1111"), + } # integer to finite field element - self._int_to_GF = {Integer(0): K("0"), Integer(1): K("1"), Integer(2): K("x"), Integer(3): K("x + 1"), Integer(4): K("x^2"), Integer(5): K("x^2 + 1"), Integer(6): K("x^2 + x"), Integer(7): K("x^2 + x + 1"), Integer(8): K("x^3"), Integer(9): K("x^3 + 1"), Integer(10): K("x^3 + x"), Integer(11): K("x^3 + x + 1"), Integer(12): K("x^3 + x^2"), Integer(13): K("x^3 + x^2 + 1"), Integer(14): K("x^3 + x^2 + x"), Integer(15): K("x^3 + x^2 + x+ 1")} + self._int_to_GF = { + Integer(0): K("0"), + Integer(1): K("1"), + Integer(2): K("x"), + Integer(3): K("x + 1"), + Integer(4): K("x^2"), + Integer(5): K("x^2 + 1"), + Integer(6): K("x^2 + x"), + Integer(7): K("x^2 + x + 1"), + Integer(8): K("x^3"), + Integer(9): K("x^3 + 1"), + Integer(10): K("x^3 + x"), + Integer(11): K("x^3 + x + 1"), + Integer(12): K("x^3 + x^2"), + Integer(13): K("x^3 + x^2 + 1"), + Integer(14): K("x^3 + x^2 + x"), + Integer(15): K("x^3 + x^2 + x+ 1"), + } def __call__(self, B, key, algorithm='encrypt'): r""" diff --git a/src/sage/crypto/mq/rijndael_gf.py b/src/sage/crypto/mq/rijndael_gf.py index d87f5eea29e..0cdcd7d1280 100644 --- a/src/sage/crypto/mq/rijndael_gf.py +++ b/src/sage/crypto/mq/rijndael_gf.py @@ -520,7 +520,16 @@ def __init__(self, Nb, Nk, state_chr='a', key_chr='k'): self._shiftrows_offsets_E = matrix([[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 4], [0, 1, 3, 4]]) self._shiftrows_offsets_D = matrix([[0, -1, -2, -3], [0, -1, -2, -3], [0, -1, -2, -3], [0, -1, -2, -4], [0, -1, -3, -4]]) self._sb_E_coeffs = [self._F("x^2 + 1"), self._F("x^3 + 1"), self._F("x^7 + x^6 + x^5 + x^4 + x^3 + 1"), self._F("x^5 + x^2 + 1"), self._F("x^7 + x^6 + x^5 + x^4 + x^2"), self._F("1"), self._F("x^7 + x^5 + x^4 + x^2 + 1"), self._F("x^7 + x^3 + x^2 + x + 1")] - self._sb_D_coeffs = [self._F("x^2 + 1"), self._F("x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x"), self._F("x^6 + x^5 + x^4 + x^3 + x^2 + x + 1"), self._F("x^6 + x^4 + x^3 + x"), self._F("x^6 + x^5 + x^4 + x^3"), self._F("x^6 + x^4 + x^3 + 1"), self._F("x^7 + x^6 + x^4 + x^3 + x + 1"), self._F("x^6 + x^5 + x^3 + x^2 + x")] + self._sb_D_coeffs = [ + self._F("x^2 + 1"), + self._F("x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x"), + self._F("x^6 + x^5 + x^4 + x^3 + x^2 + x + 1"), + self._F("x^6 + x^4 + x^3 + x"), + self._F("x^6 + x^5 + x^4 + x^3"), + self._F("x^6 + x^4 + x^3 + 1"), + self._F("x^7 + x^6 + x^4 + x^3 + x + 1"), + self._F("x^6 + x^5 + x^3 + x^2 + x"), + ] mixcols_E_row = [self._F('x'), self._F('x+1'), self._F('1'), self._F('1')] self._mixcols_E = matrix([mixcols_E_row[-i:] + mixcols_E_row[:-i] for i in range(4)]) mixcols_D_row = [self._F('x^3 + x^2 + x'), self._F('x^3 + x + 1'), self._F('x^3 + x^2 + 1'), self._F('x^3 + 1')] @@ -1064,7 +1073,9 @@ def _check_valid_PRmatrix(self, PRm, keyword): msg = "keyword '{0}' must be a {1} x {2} matrix with entries from a " "multivariate PolynomialRing over {3}" msg = msg.format(keyword, 4, self._Nb, self._F) - if (not isinstance(PRm, Matrix) or not (PRm.base_ring().is_field() and PRm.base_ring().is_finite() and PRm.base_ring().order() == 256 and PRm.dimensions() == (4, self._Nb))) and (not isinstance(PRm, Matrix) or not isinstance(PRm.base_ring(), MPolynomialRing_base) or not (PRm.base_ring().base_ring().is_field() and PRm.base_ring().base_ring().is_finite() and PRm.base_ring().base_ring().order() == 256) or not PRm.dimensions() == (4, self._Nb)): + if (not isinstance(PRm, Matrix) or not (PRm.base_ring().is_field() and PRm.base_ring().is_finite() and PRm.base_ring().order() == 256 and PRm.dimensions() == (4, self._Nb))) and ( + not isinstance(PRm, Matrix) or not isinstance(PRm.base_ring(), MPolynomialRing_base) or not (PRm.base_ring().base_ring().is_field() and PRm.base_ring().base_ring().is_finite() and PRm.base_ring().base_ring().order() == 256) or not PRm.dimensions() == (4, self._Nb) + ): raise TypeError(msg) def expand_key(self, key): diff --git a/src/sage/crypto/mq/sr.py b/src/sage/crypto/mq/sr.py index 21de1dbacb4..b01dcab8d2d 100644 --- a/src/sage/crypto/mq/sr.py +++ b/src/sage/crypto/mq/sr.py @@ -2837,7 +2837,19 @@ def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, w3, w2, w1, w0 = w x3, x2, x1, x0 = x - l = [w3 * x3 + w3 * x0 + w2 * x1 + w1 * x2 + w0 * x3, w3 * x3 + w3 * x2 + w2 * x3 + w2 * x0 + w1 * x1 + w0 * x2, w3 * x2 + w3 * x1 + w2 * x3 + w2 * x2 + w1 * x3 + w1 * x0 + w0 * x1, w3 * x3 + w3 * x2 + w3 * x0 + w2 * x2 + w1 * x3 + w1 * x1 + w0 * x3 + x3, w3 * x1 + w2 * x3 + w2 * x2 + w2 * x0 + w1 * x2 + w0 * x3 + w0 * x1 + x2, w3 * x3 + w3 * x2 + w3 * x1 + w2 * x1 + w1 * x3 + w1 * x2 + w1 * x0 + w0 * x2 + x1, w3 * x2 + w2 * x3 + w2 * x1 + w1 * x3 + w0 * x2 + w0 * x0 + x0, w3 * x3 + w3 * x1 + w3 * x0 + w3 + w2 * x3 + w2 * x2 + w1 * x1 + w0 * x3, w3 * x2 + w3 * x0 + w2 * x2 + w2 * x1 + w2 + w1 * x3 + w1 * x0 + w0 * x2, w3 * x3 + w3 * x1 + w2 * x3 + w2 * x1 + w2 * x0 + w1 * x3 + w1 * x2 + w1 + w0 * x1, w3 * x2 + w3 * x1 + w2 * x3 + w2 * x0 + w1 * x2 + w0 * x0 + w0] + l = [ + w3 * x3 + w3 * x0 + w2 * x1 + w1 * x2 + w0 * x3, + w3 * x3 + w3 * x2 + w2 * x3 + w2 * x0 + w1 * x1 + w0 * x2, + w3 * x2 + w3 * x1 + w2 * x3 + w2 * x2 + w1 * x3 + w1 * x0 + w0 * x1, + w3 * x3 + w3 * x2 + w3 * x0 + w2 * x2 + w1 * x3 + w1 * x1 + w0 * x3 + x3, + w3 * x1 + w2 * x3 + w2 * x2 + w2 * x0 + w1 * x2 + w0 * x3 + w0 * x1 + x2, + w3 * x3 + w3 * x2 + w3 * x1 + w2 * x1 + w1 * x3 + w1 * x2 + w1 * x0 + w0 * x2 + x1, + w3 * x2 + w2 * x3 + w2 * x1 + w1 * x3 + w0 * x2 + w0 * x0 + x0, + w3 * x3 + w3 * x1 + w3 * x0 + w3 + w2 * x3 + w2 * x2 + w1 * x1 + w0 * x3, + w3 * x2 + w3 * x0 + w2 * x2 + w2 * x1 + w2 + w1 * x3 + w1 * x0 + w0 * x2, + w3 * x3 + w3 * x1 + w2 * x3 + w2 * x1 + w2 * x0 + w1 * x3 + w1 * x2 + w1 + w0 * x1, + w3 * x2 + w3 * x1 + w2 * x3 + w2 * x0 + w1 * x2 + w0 * x0 + w0, + ] if not correct_only: l.append(w3 * x1 + w2 * x2 + w1 * x3 + w0 * x0 + 1) @@ -2872,7 +2884,43 @@ def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, w7 * x6 + w7 * x3 + w7 * x2 + w6 * x6 + w6 * x5 + w6 * x2 + w6 * x0 + w5 * x7 + w5 * x4 + w5 * x3 + w4 * x7 + w4 * x6 + w4 * x3 + w4 * x1 + w3 * x5 + w3 * x4 + w2 * x7 + w2 * x4 + w2 * x2 + w1 * x6 + w1 * x5 + w0 * x5 + w0 * x3 + x6, w7 * x7 + w7 * x5 + w7 * x4 + w7 * x1 + w6 * x6 + w6 * x3 + w6 * x2 + w5 * x6 + w5 * x5 + w5 * x2 + w5 * x0 + w4 * x7 + w4 * x4 + w4 * x3 + w3 * x7 + w3 * x6 + w3 * x3 + w3 * x1 + w2 * x5 + w2 * x4 + w1 * x7 + w1 * x4 + w1 * x2 + w0 * x6 + w0 * x5 + x5, w7 * x7 + w7 * x5 + w7 * x2 + w7 * x1 + w6 * x7 + w6 * x5 + w6 * x4 + w6 * x1 + w5 * x6 + w5 * x3 + w5 * x2 + w4 * x6 + w4 * x5 + w4 * x2 + w4 * x0 + w3 * x7 + w3 * x4 + w3 * x3 + w2 * x7 + w2 * x6 + w2 * x3 + w2 * x1 + w1 * x5 + w1 * x4 + w0 * x7 + w0 * x4 + w0 * x2 + x4, - w7 * x5 + w7 * x4 + w7 * x3 + w7 * x2 + w6 * x5 + w6 * x4 + w6 * x3 + w6 * x2 + w6 * x1 + w5 * x6 + w5 * x5 + w5 * x4 + w5 * x3 + w4 * x6 + w4 * x5 + w4 * x4 + w4 * x3 + w4 * x2 + w3 * x7 + w3 * x6 + w3 * x5 + w3 * x4 + w3 * x0 + w2 * x7 + w2 * x6 + w2 * x5 + w2 * x4 + w2 * x3 + w1 * x7 + w1 * x6 + w1 * x5 + w1 * x1 + w0 * x7 + w0 * x6 + w0 * x5 + w0 * x4 + x3, + w7 * x5 + + w7 * x4 + + w7 * x3 + + w7 * x2 + + w6 * x5 + + w6 * x4 + + w6 * x3 + + w6 * x2 + + w6 * x1 + + w5 * x6 + + w5 * x5 + + w5 * x4 + + w5 * x3 + + w4 * x6 + + w4 * x5 + + w4 * x4 + + w4 * x3 + + w4 * x2 + + w3 * x7 + + w3 * x6 + + w3 * x5 + + w3 * x4 + + w3 * x0 + + w2 * x7 + + w2 * x6 + + w2 * x5 + + w2 * x4 + + w2 * x3 + + w1 * x7 + + w1 * x6 + + w1 * x5 + + w1 * x1 + + w0 * x7 + + w0 * x6 + + w0 * x5 + + w0 * x4 + + x3, w7 * x7 + w7 * x6 + w7 * x5 + w7 * x4 + w7 * x3 + w7 * x1 + w6 * x7 + w6 * x5 + w6 * x2 + w5 * x7 + w5 * x6 + w5 * x5 + w5 * x4 + w5 * x2 + w4 * x6 + w4 * x3 + w3 * x7 + w3 * x6 + w3 * x5 + w3 * x3 + w2 * x7 + w2 * x4 + w2 * x0 + w1 * x7 + w1 * x6 + w1 * x4 + w0 * x5 + w0 * x1 + x2, w7 * x6 + w7 * x4 + w7 * x1 + w6 * x7 + w6 * x6 + w6 * x5 + w6 * x4 + w6 * x3 + w6 * x1 + w5 * x7 + w5 * x5 + w5 * x2 + w4 * x7 + w4 * x6 + w4 * x5 + w4 * x4 + w4 * x2 + w3 * x6 + w3 * x3 + w2 * x7 + w2 * x6 + w2 * x5 + w2 * x3 + w1 * x7 + w1 * x4 + w1 * x0 + w0 * x7 + w0 * x6 + w0 * x4 + x1, w7 * x7 + w7 * x4 + w7 * x3 + w6 * x7 + w6 * x6 + w6 * x3 + w6 * x1 + w5 * x5 + w5 * x4 + w4 * x7 + w4 * x4 + w4 * x2 + w3 * x6 + w3 * x5 + w2 * x5 + w2 * x3 + w1 * x7 + w1 * x6 + w0 * x6 + w0 * x4 + w0 * x0 + x0, @@ -2880,7 +2928,43 @@ def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, w7 * x5 + w7 * x4 + w7 * x2 + w6 * x7 + w6 * x6 + w6 * x4 + w6 * x1 + w6 + w5 * x6 + w5 * x3 + w5 * x1 + w5 * x0 + w4 * x5 + w4 * x3 + w4 * x2 + w3 * x7 + w3 * x5 + w3 * x4 + w3 * x0 + w2 * x7 + w2 * x6 + w2 * x2 + w1 * x4 + w0 * x6, w7 * x7 + w7 * x4 + w7 * x3 + w7 * x1 + w6 * x6 + w6 * x5 + w6 * x3 + w6 * x0 + w5 * x7 + w5 * x5 + w5 * x2 + w5 * x0 + w5 + w4 * x7 + w4 * x4 + w4 * x2 + w4 * x1 + w3 * x6 + w3 * x4 + w3 * x3 + w2 * x6 + w2 * x5 + w2 * x1 + w1 * x7 + w1 * x3 + w0 * x5, w7 * x7 + w7 * x6 + w7 * x3 + w7 * x2 + w7 * x0 + w6 * x5 + w6 * x4 + w6 * x2 + w5 * x7 + w5 * x6 + w5 * x4 + w5 * x1 + w4 * x6 + w4 * x3 + w4 * x1 + w4 * x0 + w4 + w3 * x5 + w3 * x3 + w3 * x2 + w2 * x7 + w2 * x5 + w2 * x4 + w2 * x0 + w1 * x7 + w1 * x6 + w1 * x2 + w0 * x4, - w7 * x3 + w7 * x2 + w7 * x1 + w7 * x0 + w6 * x5 + w6 * x4 + w6 * x3 + w6 * x2 + w6 * x1 + w6 * x0 + w5 * x7 + w5 * x6 + w5 * x5 + w5 * x4 + w5 * x3 + w5 * x2 + w5 * x1 + w5 * x0 + w4 * x7 + w4 * x6 + w4 * x5 + w4 * x4 + w4 * x3 + w4 * x2 + w4 * x0 + w3 * x7 + w3 * x6 + w3 * x5 + w3 * x4 + w3 * x2 + w3 + w2 * x7 + w2 * x6 + w2 * x4 + w1 * x6 + w1 * x1 + w0 * x3, + w7 * x3 + + w7 * x2 + + w7 * x1 + + w7 * x0 + + w6 * x5 + + w6 * x4 + + w6 * x3 + + w6 * x2 + + w6 * x1 + + w6 * x0 + + w5 * x7 + + w5 * x6 + + w5 * x5 + + w5 * x4 + + w5 * x3 + + w5 * x2 + + w5 * x1 + + w5 * x0 + + w4 * x7 + + w4 * x6 + + w4 * x5 + + w4 * x4 + + w4 * x3 + + w4 * x2 + + w4 * x0 + + w3 * x7 + + w3 * x6 + + w3 * x5 + + w3 * x4 + + w3 * x2 + + w3 + + w2 * x7 + + w2 * x6 + + w2 * x4 + + w1 * x6 + + w1 * x1 + + w0 * x3, w7 * x7 + w7 * x6 + w7 * x5 + w7 * x3 + w7 * x2 + w7 * x1 + w6 * x7 + w6 * x5 + w6 * x4 + w6 * x3 + w6 * x1 + w5 * x7 + w5 * x6 + w5 * x5 + w5 * x3 + w5 * x0 + w4 * x7 + w4 * x5 + w4 * x2 + w4 * x1 + w3 * x7 + w3 * x4 + w3 * x3 + w2 * x6 + w2 * x5 + w2 + w1 * x7 + w1 * x0 + w0 * x2, w7 * x6 + w7 * x5 + w7 * x4 + w7 * x2 + w7 * x1 + w7 * x0 + w6 * x7 + w6 * x6 + w6 * x4 + w6 * x3 + w6 * x2 + w6 * x0 + w5 * x6 + w5 * x5 + w5 * x4 + w5 * x2 + w4 * x7 + w4 * x6 + w4 * x4 + w4 * x1 + w4 * x0 + w3 * x6 + w3 * x3 + w3 * x2 + w2 * x5 + w2 * x4 + w1 * x7 + w1 * x6 + w1 + w0 * x1, w7 * x7 + w7 * x6 + w7 * x4 + w7 * x1 + w6 * x6 + w6 * x3 + w6 * x1 + w6 * x0 + w5 * x5 + w5 * x3 + w5 * x2 + w4 * x7 + w4 * x5 + w4 * x4 + w4 * x0 + w3 * x7 + w3 * x6 + w3 * x2 + w2 * x4 + w1 * x6 + w0 * x0 + w0, @@ -2892,22 +2976,756 @@ def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, if not biaffine_only: l.extend( [ - w7**2 + w7 * w6 + w7 * w3 + w7 * w1 + w7 * x7 + w7 * x6 + w7 * x5 + w7 * x2 + w7 * x1 + w7 * x0 + w6**2 + w6 * w0 + w6 * x6 + w6 * x5 + w6 * x4 + w6 * x3 + w6 * x1 + w6 * x0 + w5**2 + w5 * w4 + w5 * w3 + w5 * w2 + w5 * x7 + w5 * x5 + w5 * x4 + w5 * x1 + w5 * x0 + w4**2 + w4 * w2 + w4 * w0 + w4 * x5 + w4 * x4 + w4 * x2 + w3 * w2 + w3 * x6 + w3 * x3 + w3 * x1 + w3 * x0 + w2 * x7 + w2 * x5 + w2 * x4 + w2 * x0 + w1 * x4 + w0**2 + w0 * x0, - w7 * x6 + w7 * x4 + w7 * x1 + w6 * x7 + w6 * x6 + w6 * x5 + w6 * x2 + w5 * x7 + w5 * x6 + w5 * x5 + w5 * x4 + w5 * x3 + w5 * x1 + w4 * x5 + w4 * x4 + w4 * x3 + w4 * x1 + w4 * x0 + w3 * x7 + w3 * x5 + w3 * x2 + w2 * x7 + w2 * x6 + w2 * x3 + w1 * x7 + w1 * x6 + w1 * x5 + w1 * x4 + w1 * x2 + w0 * x6 + w0 * x5 + w0 * x4 + w0 * x2 + w0 * x1 + x7**2 + x7 * x6 + x7 * x5 + x7 * x3 + x7 * x1 + x7 * x0 + x6 * x2 + x6 * x1 + x5 * x4 + x5 * x3 + x5 * x2 + x5 * x1 + x4 * x3 + x4 * x2 + x4 * x1 + x3**2 + x3 * x2 + x2 * x1 + x2 * x0, - w7 * x5 + w7 * x4 + w7 * x3 + w7 * x1 + w7 * x0 + w6 * x7 + w6 * x5 + w6 * x2 + w5 * x7 + w5 * x6 + w5 * x3 + w4 * x7 + w4 * x6 + w4 * x5 + w4 * x4 + w4 * x2 + w3 * x6 + w3 * x5 + w3 * x4 + w3 * x2 + w3 * x1 + w2 * x6 + w2 * x3 + w1 * x7 + w1 * x4 + w0 * x7 + w0 * x6 + w0 * x5 + w0 * x3 + x7 * x3 + x7 * x2 + x6 * x5 + x6 * x4 + x6 * x3 + x6 * x2 + x6 * x0 + x5 * x4 + x5 * x3 + x5 * x2 + x4**2 + x4 * x3 + x3 * x2 + x3 * x1, - w7 * w3 + w7 * w2 + w7 * x6 + w7 * x5 + w7 * x4 + w7 * x1 + w7 * x0 + w6 * w5 + w6 * w4 + w6 * w3 + w6 * w2 + w6 * w0 + w6 * x5 + w6 * x4 + w6 * x3 + w6 * x2 + w6 * x0 + w5 * w4 + w5 * w3 + w5 * w2 + w5 * x7 + w5 * x6 + w5 * x4 + w5 * x3 + w5 * x0 + w4**2 + w4 * w3 + w4 * x7 + w4 * x4 + w4 * x3 + w4 * x1 + w3 * w2 + w3 * w1 + w3 * x7 + w3 * x5 + w3 * x2 + w3 * x0 + w2 * x6 + w2 * x4 + w2 * x3 + w1 * x7 + w1 * x3 + w0 * x7, - w7 * x5 + w7 * x2 + w7 * x1 + w6 * x7 + w6 * x6 + w6 * x5 + w6 * x4 + w6 * x2 + w6 * x1 + w5 * x5 + w5 * x3 + w5 * x2 + w4 * x3 + w4 * x2 + w4 * x1 + w3 * x6 + w3 * x3 + w3 * x2 + w3 * x0 + w2 * x7 + w2 * x6 + w2 * x5 + w2 * x3 + w2 * x2 + w1 * x6 + w1 * x4 + w1 * x3 + w0 * x4 + w0 * x3 + w0 * x2 + x7 * x5 + x7 * x4 + x7 * x1 + x7 * x0 + x6 * x0 + x5**2 + x5 * x2 + x5 * x1 + x5 * x0 + x4**2 + x4 * x0 + x3 * x2 + x3 * x0 + x1**2, - w7 * w6 + w7 * w5 + w7 * w4 + w7 * w3 + w7 * x7 + w7 * x5 + w7 * x4 + w7 * x3 + w7 * x0 + w6**2 + w6 * w5 + w6 * w4 + w6 * w2 + w6 * w1 + w6 * w0 + w6 * x7 + w6 * x4 + w6 * x3 + w6 * x2 + w6 * x1 + w5 * w4 + w5 * w1 + w5 * w0 + w5 * x7 + w5 * x6 + w5 * x5 + w5 * x3 + w5 * x2 + w4 * w2 + w4 * w1 + w4 * x7 + w4 * x6 + w4 * x3 + w4 * x2 + w4 * x0 + w3 * w0 + w3 * x7 + w3 * x6 + w3 * x4 + w3 * x1 + w2**2 + w2 * x5 + w2 * x3 + w2 * x2 + w1 * x7 + w1 * x6 + w1 * x2 + w0 * x6, - w7 * w5 + w7 * w4 + w7 * w1 + w7 * w0 + w7 * x6 + w7 * x2 + w6 * w0 + w6 * x6 + w6 * x3 + w6 * x2 + w6 * x1 + w5**2 + w5 * w2 + w5 * w1 + w5 * w0 + w5 * x7 + w5 * x6 + w5 * x5 + w5 * x2 + w4**2 + w4 * w0 + w4 * x6 + w4 * x1 + w4 * x0 + w3 * w2 + w3 * w0 + w3 * x5 + w3 * x4 + w3 * x3 + w3 * x2 + w3 * x1 + w3 * x0 + w2 * x7 + w2 * x6 + w2 * x5 + w2 * x4 + w2 * x3 + w2 * x2 + w2 * x0 + w1**2 + w1 * x7 + w1 * x6 + w1 * x4 + w0 * x3, - w7 * x7 + w7 * x6 + w7 * x5 + w7 * x2 + w6 * x7 + w6 * x6 + w6 * x5 + w6 * x4 + w6 * x3 + w6 * x1 + w5 * x5 + w5 * x4 + w5 * x3 + w5 * x1 + w5 * x0 + w4 * x7 + w4 * x5 + w4 * x2 + w3 * x7 + w3 * x6 + w3 * x3 + w2 * x7 + w2 * x6 + w2 * x5 + w2 * x4 + w2 * x2 + w1 * x6 + w1 * x5 + w1 * x4 + w1 * x2 + w1 * x1 + w0 * x6 + w0 * x3 + x7**2 + x7 * x5 + x7 * x3 + x6**2 + x6 * x5 + x6 * x2 + x6 * x0 + x5**2 + x4**2 + x4 * x3 + x4 * x2 + x4 * x1 + x3**2 + x3 * x1 + x2 * x1, - w7**2 + w7 * w6 + w7 * w5 + w7 * w3 + w7 * w1 + w7 * w0 + w7 * x6 + w7 * x5 + w7 * x3 + w7 * x2 + w7 * x1 + w6 * w2 + w6 * w1 + w6 * x7 + w6 * x6 + w6 * x5 + w6 * x2 + w6 * x1 + w6 * x0 + w5 * w4 + w5 * w3 + w5 * w2 + w5 * w1 + w5 * x6 + w5 * x5 + w5 * x4 + w5 * x3 + w5 * x1 + w5 * x0 + w4 * w3 + w4 * w2 + w4 * w1 + w4 * x7 + w4 * x5 + w4 * x4 + w4 * x1 + w4 * x0 + w3**2 + w3 * w2 + w3 * x5 + w3 * x4 + w3 * x2 + w2 * w1 + w2 * w0 + w2 * x6 + w2 * x3 + w2 * x1 + w2 * x0 + w1 * x7 + w1 * x5 + w1 * x4 + w1 * x0 + w0 * x4, - w7 * x7 + w7 * x5 + w7 * x2 + w6 * x7 + w6 * x6 + w6 * x3 + w5 * x7 + w5 * x6 + w5 * x5 + w5 * x4 + w5 * x2 + w4 * x6 + w4 * x5 + w4 * x4 + w4 * x2 + w4 * x1 + w3 * x6 + w3 * x3 + w2 * x7 + w2 * x4 + w1 * x7 + w1 * x6 + w1 * x5 + w1 * x3 + w0 * x7 + w0 * x6 + w0 * x5 + w0 * x3 + w0 * x2 + w0 * x0 + x7**2 + x7 * x6 + x7 * x3 + x7 * x1 + x6**2 + x6 * x0 + x5**2 + x5 * x4 + x5 * x3 + x5 * x2 + x4**2 + x4 * x2 + x4 * x0 + x3 * x2 + x0**2, - w7 * x7 + w7 * x6 + w7 * x5 + w7 * x4 + w7 * x3 + w7 * x1 + w6 * x5 + w6 * x4 + w6 * x3 + w6 * x1 + w6 * x0 + w5 * x7 + w5 * x5 + w5 * x2 + w4 * x7 + w4 * x6 + w4 * x3 + w3 * x7 + w3 * x6 + w3 * x5 + w3 * x4 + w3 * x2 + w2 * x6 + w2 * x5 + w2 * x4 + w2 * x2 + w2 * x1 + w1 * x6 + w1 * x3 + w0 * x7 + w0 * x4 + x7 * x6 + x7 * x5 + x7 * x4 + x7 * x3 + x6**2 + x6 * x5 + x6 * x4 + x6 * x2 + x6 * x1 + x6 * x0 + x5 * x4 + x5 * x1 + x5 * x0 + x4 * x2 + x4 * x1 + x3 * x0 + x2**2, - w7 * x5 + w7 * x4 + w7 * x3 + w7 * x2 + w6 * x7 + w6 * x1 + w5 * x5 + w5 * x4 + w5 * x3 + w5 * x2 + w5 * x1 + w4 * x7 + w4 * x6 + w4 * x4 + w4 * x3 + w3 * x6 + w3 * x5 + w3 * x4 + w3 * x3 + w2 * x2 + w2 * x0 + w1 * x6 + w1 * x5 + w1 * x4 + w1 * x3 + w1 * x2 + w0 * x7 + w0 * x5 + w0 * x4 + x7**2 + x7 * x4 + x7 * x2 + x6 * x4 + x6 * x3 + x6 * x2 + x6 * x1 + x5**2 + x5 * x4 + x5 * x3 + x5 * x2 + x5 * x0 + x4 * x3 + x4 * x2 + x4 * x1 + x3**2 + x2 * x0 + x1 * x0, - w7 * x6 + w7 * x5 + w7 * x3 + w7 * x2 + w6 * x5 + w6 * x4 + w6 * x3 + w6 * x2 + w5 * x7 + w5 * x1 + w4 * x5 + w4 * x4 + w4 * x3 + w4 * x2 + w4 * x1 + w3 * x7 + w3 * x6 + w3 * x4 + w3 * x3 + w2 * x6 + w2 * x5 + w2 * x4 + w2 * x3 + w1 * x2 + w1 * x0 + w0 * x6 + w0 * x5 + w0 * x4 + w0 * x3 + w0 * x2 + x7 * x5 + x7 * x2 + x7 * x0 + x6**2 + x6 * x5 + x6 * x2 + x6 * x1 + x6 * x0 + x5**2 + x5 * x4 + x4**2 + x4 * x2 + x4 * x1 + x4 * x0 + x3**2 + x3 * x2 + x1 * x0, - w7**2 + w7 * w5 + w7 * w3 + w7 * x7 + w7 * x6 + w7 * x4 + w7 * x3 + w7 * x2 + w6**2 + w6 * w5 + w6 * w2 + w6 * w0 + w6 * x7 + w6 * x6 + w6 * x3 + w6 * x2 + w6 * x1 + w6 * x0 + w5**2 + w5 * x7 + w5 * x6 + w5 * x5 + w5 * x4 + w5 * x2 + w5 * x1 + w4**2 + w4 * w3 + w4 * w2 + w4 * w1 + w4 * x6 + w4 * x5 + w4 * x2 + w4 * x1 + w3**2 + w3 * w1 + w3 * x6 + w3 * x5 + w3 * x3 + w3 * x0 + w2 * w1 + w2 * x7 + w2 * x4 + w2 * x2 + w2 * x1 + w1 * x6 + w1 * x5 + w1 * x1 + w0 * x5, - w7 * w5 + w7 * w2 + w7 * w0 + w7 * x5 + w7 * x3 + w6**2 + w6 * w5 + w6 * w2 + w6 * w1 + w6 * w0 + w6 * x7 + w6 * x3 + w6 * x2 + w6 * x0 + w5**2 + w5 * w4 + w5 * x7 + w5 * x6 + w5 * x4 + w5 * x2 + w5 * x0 + w4**2 + w4 * w2 + w4 * w1 + w4 * w0 + w4 * x6 + w4 * x4 + w4 * x3 + w4 * x2 + w4 * x0 + w3**2 + w3 * w2 + w3 * x7 + w3 * x6 + w3 * x4 + w3 * x3 + w3 * x2 + w3 * x0 + w2 * x7 + w2 * x6 + w2 * x4 + w2 * x1 + w2 * x0 + w1 * w0 + w1 * x5 + w1 * x4 + w0 * x1, - w7**2 + w7 * w4 + w7 * w2 + w7 * x6 + w7 * x4 + w7 * x0 + w6 * w4 + w6 * w3 + w6 * w2 + w6 * w1 + w6 * x4 + w6 * x3 + w6 * x1 + w5**2 + w5 * w4 + w5 * w3 + w5 * w2 + w5 * w0 + w5 * x7 + w5 * x5 + w5 * x3 + w5 * x1 + w5 * x0 + w4 * w3 + w4 * w2 + w4 * w1 + w4 * x7 + w4 * x5 + w4 * x4 + w4 * x3 + w4 * x1 + w4 * x0 + w3**2 + w3 * x7 + w3 * x5 + w3 * x4 + w3 * x3 + w3 * x1 + w2 * w0 + w2 * x7 + w2 * x5 + w2 * x2 + w2 * x1 + w1 * w0 + w1 * x6 + w1 * x5 + w0 * x2, + w7**2 + + w7 * w6 + + w7 * w3 + + w7 * w1 + + w7 * x7 + + w7 * x6 + + w7 * x5 + + w7 * x2 + + w7 * x1 + + w7 * x0 + + w6**2 + + w6 * w0 + + w6 * x6 + + w6 * x5 + + w6 * x4 + + w6 * x3 + + w6 * x1 + + w6 * x0 + + w5**2 + + w5 * w4 + + w5 * w3 + + w5 * w2 + + w5 * x7 + + w5 * x5 + + w5 * x4 + + w5 * x1 + + w5 * x0 + + w4**2 + + w4 * w2 + + w4 * w0 + + w4 * x5 + + w4 * x4 + + w4 * x2 + + w3 * w2 + + w3 * x6 + + w3 * x3 + + w3 * x1 + + w3 * x0 + + w2 * x7 + + w2 * x5 + + w2 * x4 + + w2 * x0 + + w1 * x4 + + w0**2 + + w0 * x0, + w7 * x6 + + w7 * x4 + + w7 * x1 + + w6 * x7 + + w6 * x6 + + w6 * x5 + + w6 * x2 + + w5 * x7 + + w5 * x6 + + w5 * x5 + + w5 * x4 + + w5 * x3 + + w5 * x1 + + w4 * x5 + + w4 * x4 + + w4 * x3 + + w4 * x1 + + w4 * x0 + + w3 * x7 + + w3 * x5 + + w3 * x2 + + w2 * x7 + + w2 * x6 + + w2 * x3 + + w1 * x7 + + w1 * x6 + + w1 * x5 + + w1 * x4 + + w1 * x2 + + w0 * x6 + + w0 * x5 + + w0 * x4 + + w0 * x2 + + w0 * x1 + + x7**2 + + x7 * x6 + + x7 * x5 + + x7 * x3 + + x7 * x1 + + x7 * x0 + + x6 * x2 + + x6 * x1 + + x5 * x4 + + x5 * x3 + + x5 * x2 + + x5 * x1 + + x4 * x3 + + x4 * x2 + + x4 * x1 + + x3**2 + + x3 * x2 + + x2 * x1 + + x2 * x0, + w7 * x5 + + w7 * x4 + + w7 * x3 + + w7 * x1 + + w7 * x0 + + w6 * x7 + + w6 * x5 + + w6 * x2 + + w5 * x7 + + w5 * x6 + + w5 * x3 + + w4 * x7 + + w4 * x6 + + w4 * x5 + + w4 * x4 + + w4 * x2 + + w3 * x6 + + w3 * x5 + + w3 * x4 + + w3 * x2 + + w3 * x1 + + w2 * x6 + + w2 * x3 + + w1 * x7 + + w1 * x4 + + w0 * x7 + + w0 * x6 + + w0 * x5 + + w0 * x3 + + x7 * x3 + + x7 * x2 + + x6 * x5 + + x6 * x4 + + x6 * x3 + + x6 * x2 + + x6 * x0 + + x5 * x4 + + x5 * x3 + + x5 * x2 + + x4**2 + + x4 * x3 + + x3 * x2 + + x3 * x1, + w7 * w3 + + w7 * w2 + + w7 * x6 + + w7 * x5 + + w7 * x4 + + w7 * x1 + + w7 * x0 + + w6 * w5 + + w6 * w4 + + w6 * w3 + + w6 * w2 + + w6 * w0 + + w6 * x5 + + w6 * x4 + + w6 * x3 + + w6 * x2 + + w6 * x0 + + w5 * w4 + + w5 * w3 + + w5 * w2 + + w5 * x7 + + w5 * x6 + + w5 * x4 + + w5 * x3 + + w5 * x0 + + w4**2 + + w4 * w3 + + w4 * x7 + + w4 * x4 + + w4 * x3 + + w4 * x1 + + w3 * w2 + + w3 * w1 + + w3 * x7 + + w3 * x5 + + w3 * x2 + + w3 * x0 + + w2 * x6 + + w2 * x4 + + w2 * x3 + + w1 * x7 + + w1 * x3 + + w0 * x7, + w7 * x5 + + w7 * x2 + + w7 * x1 + + w6 * x7 + + w6 * x6 + + w6 * x5 + + w6 * x4 + + w6 * x2 + + w6 * x1 + + w5 * x5 + + w5 * x3 + + w5 * x2 + + w4 * x3 + + w4 * x2 + + w4 * x1 + + w3 * x6 + + w3 * x3 + + w3 * x2 + + w3 * x0 + + w2 * x7 + + w2 * x6 + + w2 * x5 + + w2 * x3 + + w2 * x2 + + w1 * x6 + + w1 * x4 + + w1 * x3 + + w0 * x4 + + w0 * x3 + + w0 * x2 + + x7 * x5 + + x7 * x4 + + x7 * x1 + + x7 * x0 + + x6 * x0 + + x5**2 + + x5 * x2 + + x5 * x1 + + x5 * x0 + + x4**2 + + x4 * x0 + + x3 * x2 + + x3 * x0 + + x1**2, + w7 * w6 + + w7 * w5 + + w7 * w4 + + w7 * w3 + + w7 * x7 + + w7 * x5 + + w7 * x4 + + w7 * x3 + + w7 * x0 + + w6**2 + + w6 * w5 + + w6 * w4 + + w6 * w2 + + w6 * w1 + + w6 * w0 + + w6 * x7 + + w6 * x4 + + w6 * x3 + + w6 * x2 + + w6 * x1 + + w5 * w4 + + w5 * w1 + + w5 * w0 + + w5 * x7 + + w5 * x6 + + w5 * x5 + + w5 * x3 + + w5 * x2 + + w4 * w2 + + w4 * w1 + + w4 * x7 + + w4 * x6 + + w4 * x3 + + w4 * x2 + + w4 * x0 + + w3 * w0 + + w3 * x7 + + w3 * x6 + + w3 * x4 + + w3 * x1 + + w2**2 + + w2 * x5 + + w2 * x3 + + w2 * x2 + + w1 * x7 + + w1 * x6 + + w1 * x2 + + w0 * x6, + w7 * w5 + + w7 * w4 + + w7 * w1 + + w7 * w0 + + w7 * x6 + + w7 * x2 + + w6 * w0 + + w6 * x6 + + w6 * x3 + + w6 * x2 + + w6 * x1 + + w5**2 + + w5 * w2 + + w5 * w1 + + w5 * w0 + + w5 * x7 + + w5 * x6 + + w5 * x5 + + w5 * x2 + + w4**2 + + w4 * w0 + + w4 * x6 + + w4 * x1 + + w4 * x0 + + w3 * w2 + + w3 * w0 + + w3 * x5 + + w3 * x4 + + w3 * x3 + + w3 * x2 + + w3 * x1 + + w3 * x0 + + w2 * x7 + + w2 * x6 + + w2 * x5 + + w2 * x4 + + w2 * x3 + + w2 * x2 + + w2 * x0 + + w1**2 + + w1 * x7 + + w1 * x6 + + w1 * x4 + + w0 * x3, + w7 * x7 + + w7 * x6 + + w7 * x5 + + w7 * x2 + + w6 * x7 + + w6 * x6 + + w6 * x5 + + w6 * x4 + + w6 * x3 + + w6 * x1 + + w5 * x5 + + w5 * x4 + + w5 * x3 + + w5 * x1 + + w5 * x0 + + w4 * x7 + + w4 * x5 + + w4 * x2 + + w3 * x7 + + w3 * x6 + + w3 * x3 + + w2 * x7 + + w2 * x6 + + w2 * x5 + + w2 * x4 + + w2 * x2 + + w1 * x6 + + w1 * x5 + + w1 * x4 + + w1 * x2 + + w1 * x1 + + w0 * x6 + + w0 * x3 + + x7**2 + + x7 * x5 + + x7 * x3 + + x6**2 + + x6 * x5 + + x6 * x2 + + x6 * x0 + + x5**2 + + x4**2 + + x4 * x3 + + x4 * x2 + + x4 * x1 + + x3**2 + + x3 * x1 + + x2 * x1, + w7**2 + + w7 * w6 + + w7 * w5 + + w7 * w3 + + w7 * w1 + + w7 * w0 + + w7 * x6 + + w7 * x5 + + w7 * x3 + + w7 * x2 + + w7 * x1 + + w6 * w2 + + w6 * w1 + + w6 * x7 + + w6 * x6 + + w6 * x5 + + w6 * x2 + + w6 * x1 + + w6 * x0 + + w5 * w4 + + w5 * w3 + + w5 * w2 + + w5 * w1 + + w5 * x6 + + w5 * x5 + + w5 * x4 + + w5 * x3 + + w5 * x1 + + w5 * x0 + + w4 * w3 + + w4 * w2 + + w4 * w1 + + w4 * x7 + + w4 * x5 + + w4 * x4 + + w4 * x1 + + w4 * x0 + + w3**2 + + w3 * w2 + + w3 * x5 + + w3 * x4 + + w3 * x2 + + w2 * w1 + + w2 * w0 + + w2 * x6 + + w2 * x3 + + w2 * x1 + + w2 * x0 + + w1 * x7 + + w1 * x5 + + w1 * x4 + + w1 * x0 + + w0 * x4, + w7 * x7 + + w7 * x5 + + w7 * x2 + + w6 * x7 + + w6 * x6 + + w6 * x3 + + w5 * x7 + + w5 * x6 + + w5 * x5 + + w5 * x4 + + w5 * x2 + + w4 * x6 + + w4 * x5 + + w4 * x4 + + w4 * x2 + + w4 * x1 + + w3 * x6 + + w3 * x3 + + w2 * x7 + + w2 * x4 + + w1 * x7 + + w1 * x6 + + w1 * x5 + + w1 * x3 + + w0 * x7 + + w0 * x6 + + w0 * x5 + + w0 * x3 + + w0 * x2 + + w0 * x0 + + x7**2 + + x7 * x6 + + x7 * x3 + + x7 * x1 + + x6**2 + + x6 * x0 + + x5**2 + + x5 * x4 + + x5 * x3 + + x5 * x2 + + x4**2 + + x4 * x2 + + x4 * x0 + + x3 * x2 + + x0**2, + w7 * x7 + + w7 * x6 + + w7 * x5 + + w7 * x4 + + w7 * x3 + + w7 * x1 + + w6 * x5 + + w6 * x4 + + w6 * x3 + + w6 * x1 + + w6 * x0 + + w5 * x7 + + w5 * x5 + + w5 * x2 + + w4 * x7 + + w4 * x6 + + w4 * x3 + + w3 * x7 + + w3 * x6 + + w3 * x5 + + w3 * x4 + + w3 * x2 + + w2 * x6 + + w2 * x5 + + w2 * x4 + + w2 * x2 + + w2 * x1 + + w1 * x6 + + w1 * x3 + + w0 * x7 + + w0 * x4 + + x7 * x6 + + x7 * x5 + + x7 * x4 + + x7 * x3 + + x6**2 + + x6 * x5 + + x6 * x4 + + x6 * x2 + + x6 * x1 + + x6 * x0 + + x5 * x4 + + x5 * x1 + + x5 * x0 + + x4 * x2 + + x4 * x1 + + x3 * x0 + + x2**2, + w7 * x5 + + w7 * x4 + + w7 * x3 + + w7 * x2 + + w6 * x7 + + w6 * x1 + + w5 * x5 + + w5 * x4 + + w5 * x3 + + w5 * x2 + + w5 * x1 + + w4 * x7 + + w4 * x6 + + w4 * x4 + + w4 * x3 + + w3 * x6 + + w3 * x5 + + w3 * x4 + + w3 * x3 + + w2 * x2 + + w2 * x0 + + w1 * x6 + + w1 * x5 + + w1 * x4 + + w1 * x3 + + w1 * x2 + + w0 * x7 + + w0 * x5 + + w0 * x4 + + x7**2 + + x7 * x4 + + x7 * x2 + + x6 * x4 + + x6 * x3 + + x6 * x2 + + x6 * x1 + + x5**2 + + x5 * x4 + + x5 * x3 + + x5 * x2 + + x5 * x0 + + x4 * x3 + + x4 * x2 + + x4 * x1 + + x3**2 + + x2 * x0 + + x1 * x0, + w7 * x6 + + w7 * x5 + + w7 * x3 + + w7 * x2 + + w6 * x5 + + w6 * x4 + + w6 * x3 + + w6 * x2 + + w5 * x7 + + w5 * x1 + + w4 * x5 + + w4 * x4 + + w4 * x3 + + w4 * x2 + + w4 * x1 + + w3 * x7 + + w3 * x6 + + w3 * x4 + + w3 * x3 + + w2 * x6 + + w2 * x5 + + w2 * x4 + + w2 * x3 + + w1 * x2 + + w1 * x0 + + w0 * x6 + + w0 * x5 + + w0 * x4 + + w0 * x3 + + w0 * x2 + + x7 * x5 + + x7 * x2 + + x7 * x0 + + x6**2 + + x6 * x5 + + x6 * x2 + + x6 * x1 + + x6 * x0 + + x5**2 + + x5 * x4 + + x4**2 + + x4 * x2 + + x4 * x1 + + x4 * x0 + + x3**2 + + x3 * x2 + + x1 * x0, + w7**2 + + w7 * w5 + + w7 * w3 + + w7 * x7 + + w7 * x6 + + w7 * x4 + + w7 * x3 + + w7 * x2 + + w6**2 + + w6 * w5 + + w6 * w2 + + w6 * w0 + + w6 * x7 + + w6 * x6 + + w6 * x3 + + w6 * x2 + + w6 * x1 + + w6 * x0 + + w5**2 + + w5 * x7 + + w5 * x6 + + w5 * x5 + + w5 * x4 + + w5 * x2 + + w5 * x1 + + w4**2 + + w4 * w3 + + w4 * w2 + + w4 * w1 + + w4 * x6 + + w4 * x5 + + w4 * x2 + + w4 * x1 + + w3**2 + + w3 * w1 + + w3 * x6 + + w3 * x5 + + w3 * x3 + + w3 * x0 + + w2 * w1 + + w2 * x7 + + w2 * x4 + + w2 * x2 + + w2 * x1 + + w1 * x6 + + w1 * x5 + + w1 * x1 + + w0 * x5, + w7 * w5 + + w7 * w2 + + w7 * w0 + + w7 * x5 + + w7 * x3 + + w6**2 + + w6 * w5 + + w6 * w2 + + w6 * w1 + + w6 * w0 + + w6 * x7 + + w6 * x3 + + w6 * x2 + + w6 * x0 + + w5**2 + + w5 * w4 + + w5 * x7 + + w5 * x6 + + w5 * x4 + + w5 * x2 + + w5 * x0 + + w4**2 + + w4 * w2 + + w4 * w1 + + w4 * w0 + + w4 * x6 + + w4 * x4 + + w4 * x3 + + w4 * x2 + + w4 * x0 + + w3**2 + + w3 * w2 + + w3 * x7 + + w3 * x6 + + w3 * x4 + + w3 * x3 + + w3 * x2 + + w3 * x0 + + w2 * x7 + + w2 * x6 + + w2 * x4 + + w2 * x1 + + w2 * x0 + + w1 * w0 + + w1 * x5 + + w1 * x4 + + w0 * x1, + w7**2 + + w7 * w4 + + w7 * w2 + + w7 * x6 + + w7 * x4 + + w7 * x0 + + w6 * w4 + + w6 * w3 + + w6 * w2 + + w6 * w1 + + w6 * x4 + + w6 * x3 + + w6 * x1 + + w5**2 + + w5 * w4 + + w5 * w3 + + w5 * w2 + + w5 * w0 + + w5 * x7 + + w5 * x5 + + w5 * x3 + + w5 * x1 + + w5 * x0 + + w4 * w3 + + w4 * w2 + + w4 * w1 + + w4 * x7 + + w4 * x5 + + w4 * x4 + + w4 * x3 + + w4 * x1 + + w4 * x0 + + w3**2 + + w3 * x7 + + w3 * x5 + + w3 * x4 + + w3 * x3 + + w3 * x1 + + w2 * w0 + + w2 * x7 + + w2 * x5 + + w2 * x2 + + w2 * x1 + + w1 * w0 + + w1 * x6 + + w1 * x5 + + w0 * x2, ] ) diff --git a/src/sage/crypto/sboxes.py b/src/sage/crypto/sboxes.py index ed02bfeaceb..3cffa705c08 100644 --- a/src/sage/crypto/sboxes.py +++ b/src/sage/crypto/sboxes.py @@ -14321,14 +14321,279 @@ def chi(n): # Bijective S-Boxes mapping 7 bits to 7 # ===================================== -WAGE = SBox([0x2E, 0x1C, 0x6D, 0x2B, 0x35, 0x07, 0x7F, 0x3B, 0x28, 0x08, 0x0B, 0x5F, 0x31, 0x11, 0x1B, 0x4D, 0x6E, 0x54, 0x0D, 0x09, 0x1F, 0x45, 0x75, 0x53, 0x6A, 0x5D, 0x61, 0x00, 0x04, 0x78, 0x06, 0x1E, 0x37, 0x6F, 0x2F, 0x49, 0x64, 0x34, 0x7D, 0x19, 0x39, 0x33, 0x43, 0x57, 0x60, 0x62, 0x13, 0x05, 0x77, 0x47, 0x4F, 0x4B, 0x1D, 0x2D, 0x24, 0x48, 0x74, 0x58, 0x25, 0x5E, 0x5A, 0x76, 0x41, 0x42, 0x27, 0x3E, 0x6C, 0x01, 0x2C, 0x3C, 0x4E, 0x1A, 0x21, 0x2A, 0x0A, 0x55, 0x3A, 0x38, 0x18, 0x7E, 0x0C, 0x63, 0x67, 0x56, 0x50, 0x7C, 0x32, 0x7A, 0x68, 0x02, 0x6B, 0x17, 0x7B, 0x59, 0x71, 0x0F, 0x30, 0x10, 0x22, 0x3D, 0x40, 0x69, 0x52, 0x14, 0x36, 0x44, 0x46, 0x03, 0x16, 0x65, 0x66, 0x72, 0x12, 0x0E, 0x29, 0x4A, 0x4C, 0x70, 0x15, 0x26, 0x79, 0x51, 0x23, 0x3F, 0x73, 0x5B, 0x20, 0x5C]) +WAGE = SBox( + [ + 0x2E, + 0x1C, + 0x6D, + 0x2B, + 0x35, + 0x07, + 0x7F, + 0x3B, + 0x28, + 0x08, + 0x0B, + 0x5F, + 0x31, + 0x11, + 0x1B, + 0x4D, + 0x6E, + 0x54, + 0x0D, + 0x09, + 0x1F, + 0x45, + 0x75, + 0x53, + 0x6A, + 0x5D, + 0x61, + 0x00, + 0x04, + 0x78, + 0x06, + 0x1E, + 0x37, + 0x6F, + 0x2F, + 0x49, + 0x64, + 0x34, + 0x7D, + 0x19, + 0x39, + 0x33, + 0x43, + 0x57, + 0x60, + 0x62, + 0x13, + 0x05, + 0x77, + 0x47, + 0x4F, + 0x4B, + 0x1D, + 0x2D, + 0x24, + 0x48, + 0x74, + 0x58, + 0x25, + 0x5E, + 0x5A, + 0x76, + 0x41, + 0x42, + 0x27, + 0x3E, + 0x6C, + 0x01, + 0x2C, + 0x3C, + 0x4E, + 0x1A, + 0x21, + 0x2A, + 0x0A, + 0x55, + 0x3A, + 0x38, + 0x18, + 0x7E, + 0x0C, + 0x63, + 0x67, + 0x56, + 0x50, + 0x7C, + 0x32, + 0x7A, + 0x68, + 0x02, + 0x6B, + 0x17, + 0x7B, + 0x59, + 0x71, + 0x0F, + 0x30, + 0x10, + 0x22, + 0x3D, + 0x40, + 0x69, + 0x52, + 0x14, + 0x36, + 0x44, + 0x46, + 0x03, + 0x16, + 0x65, + 0x66, + 0x72, + 0x12, + 0x0E, + 0x29, + 0x4A, + 0x4C, + 0x70, + 0x15, + 0x26, + 0x79, + 0x51, + 0x23, + 0x3F, + 0x73, + 0x5B, + 0x20, + 0x5C, + ] +) # Bijective S-Boxes mapping 6 bits to 6 # ===================================== -Fides_6 = SBox([0x36, 0x00, 0x30, 0x0D, 0x0F, 0x12, 0x23, 0x35, 0x3F, 0x19, 0x2D, 0x34, 0x03, 0x14, 0x21, 0x29, 0x08, 0x0A, 0x39, 0x25, 0x3B, 0x24, 0x22, 0x02, 0x1A, 0x32, 0x3A, 0x18, 0x3C, 0x13, 0x0E, 0x2A, 0x2E, 0x3D, 0x05, 0x31, 0x1F, 0x0B, 0x1C, 0x04, 0x0C, 0x1E, 0x37, 0x16, 0x09, 0x06, 0x20, 0x17, 0x1B, 0x27, 0x15, 0x11, 0x10, 0x1D, 0x3E, 0x01, 0x28, 0x2F, 0x33, 0x38, 0x07, 0x2B, 0x26, 0x2C]) +Fides_6 = SBox( + [ + 0x36, + 0x00, + 0x30, + 0x0D, + 0x0F, + 0x12, + 0x23, + 0x35, + 0x3F, + 0x19, + 0x2D, + 0x34, + 0x03, + 0x14, + 0x21, + 0x29, + 0x08, + 0x0A, + 0x39, + 0x25, + 0x3B, + 0x24, + 0x22, + 0x02, + 0x1A, + 0x32, + 0x3A, + 0x18, + 0x3C, + 0x13, + 0x0E, + 0x2A, + 0x2E, + 0x3D, + 0x05, + 0x31, + 0x1F, + 0x0B, + 0x1C, + 0x04, + 0x0C, + 0x1E, + 0x37, + 0x16, + 0x09, + 0x06, + 0x20, + 0x17, + 0x1B, + 0x27, + 0x15, + 0x11, + 0x10, + 0x1D, + 0x3E, + 0x01, + 0x28, + 0x2F, + 0x33, + 0x38, + 0x07, + 0x2B, + 0x26, + 0x2C, + ] +) -APN_6 = SBox([0x0, 0x36, 0x30, 0xD, 0xF, 0x12, 0x35, 0x23, 0x19, 0x3F, 0x2D, 0x34, 0x3, 0x14, 0x29, 0x21, 0x3B, 0x24, 0x2, 0x22, 0xA, 0x8, 0x39, 0x25, 0x3C, 0x13, 0x2A, 0xE, 0x32, 0x1A, 0x3A, 0x18, 0x27, 0x1B, 0x15, 0x11, 0x10, 0x1D, 0x1, 0x3E, 0x2F, 0x28, 0x33, 0x38, 0x7, 0x2B, 0x2C, 0x26, 0x1F, 0xB, 0x4, 0x1C, 0x3D, 0x2E, 0x5, 0x31, 0x9, 0x6, 0x17, 0x20, 0x1E, 0xC, 0x37, 0x16]) +APN_6 = SBox( + [ + 0x0, + 0x36, + 0x30, + 0xD, + 0xF, + 0x12, + 0x35, + 0x23, + 0x19, + 0x3F, + 0x2D, + 0x34, + 0x3, + 0x14, + 0x29, + 0x21, + 0x3B, + 0x24, + 0x2, + 0x22, + 0xA, + 0x8, + 0x39, + 0x25, + 0x3C, + 0x13, + 0x2A, + 0xE, + 0x32, + 0x1A, + 0x3A, + 0x18, + 0x27, + 0x1B, + 0x15, + 0x11, + 0x10, + 0x1D, + 0x1, + 0x3E, + 0x2F, + 0x28, + 0x33, + 0x38, + 0x7, + 0x2B, + 0x2C, + 0x26, + 0x1F, + 0xB, + 0x4, + 0x1C, + 0x3D, + 0x2E, + 0x5, + 0x31, + 0x9, + 0x6, + 0x17, + 0x20, + 0x1E, + 0xC, + 0x37, + 0x16, + ] +) SC2000_6 = SBox([47, 59, 25, 42, 15, 23, 28, 39, 26, 38, 36, 19, 60, 24, 29, 56, 37, 63, 20, 61, 55, 2, 30, 44, 9, 10, 6, 22, 53, 48, 51, 11, 62, 52, 35, 18, 14, 46, 0, 54, 17, 40, 27, 4, 31, 8, 5, 12, 3, 16, 41, 34, 33, 7, 45, 49, 50, 58, 1, 21, 43, 57, 32, 13]) diff --git a/src/sage/databases/cremona.py b/src/sage/databases/cremona.py index 2945d43a310..6b428ed7692 100644 --- a/src/sage/databases/cremona.py +++ b/src/sage/databases/cremona.py @@ -58,8 +58,14 @@ import re import string -_cremonaSkeleton = {'t_class': {'conductor': {'sql': 'INTEGER', 'index': True}, 'class': {'sql': 'TEXT', 'primary_key': True}, 'rank': {'sql': 'INTEGER'}, 'L': {'sql': 'REAL'}, 'deg': {'sql': 'INTEGER'}}, 't_curve': {'class': {'sql': 'TEXT', 'index': True}, 'curve': {'sql': 'TEXT', 'primary_key': True}, 'eqn': {'sql': 'TEXT', 'unique': True}, 'gens': {'sql': 'TEXT'}, 'tors': {'sql': 'INTEGER'}, 'cp': {'sql': 'INTEGER'}, 'om': {'sql': 'REAL'}, 'reg': {'sql': 'REAL'}, 'sha': {'sql': 'NOTYPE'}}} -_miniCremonaSkeleton = {'t_class': {'conductor': {'sql': 'INTEGER', 'index': True}, 'class': {'sql': 'TEXT', 'primary_key': True}, 'rank': {'sql': 'INTEGER'}}, 't_curve': {'class': {'sql': 'TEXT', 'index': True}, 'curve': {'sql': 'TEXT', 'primary_key': True}, 'eqn': {'sql': 'TEXT', 'unique': True}, 'tors': {'sql': 'INTEGER'}}} +_cremonaSkeleton = { + 't_class': {'conductor': {'sql': 'INTEGER', 'index': True}, 'class': {'sql': 'TEXT', 'primary_key': True}, 'rank': {'sql': 'INTEGER'}, 'L': {'sql': 'REAL'}, 'deg': {'sql': 'INTEGER'}}, + 't_curve': {'class': {'sql': 'TEXT', 'index': True}, 'curve': {'sql': 'TEXT', 'primary_key': True}, 'eqn': {'sql': 'TEXT', 'unique': True}, 'gens': {'sql': 'TEXT'}, 'tors': {'sql': 'INTEGER'}, 'cp': {'sql': 'INTEGER'}, 'om': {'sql': 'REAL'}, 'reg': {'sql': 'REAL'}, 'sha': {'sql': 'NOTYPE'}}, +} +_miniCremonaSkeleton = { + 't_class': {'conductor': {'sql': 'INTEGER', 'index': True}, 'class': {'sql': 'TEXT', 'primary_key': True}, 'rank': {'sql': 'INTEGER'}}, + 't_curve': {'class': {'sql': 'TEXT', 'index': True}, 'curve': {'sql': 'TEXT', 'primary_key': True}, 'eqn': {'sql': 'TEXT', 'unique': True}, 'tors': {'sql': 'INTEGER'}}, +} for t in _cremonaSkeleton: for c in _cremonaSkeleton[t]: diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py index 6c660cf1907..62773bbfad1 100644 --- a/src/sage/databases/cubic_hecke_db.py +++ b/src/sage/databases/cubic_hecke_db.py @@ -594,8 +594,78 @@ def links_gould_polynomial(self): 'K4': {(2, 2): 1, (1, 3): 1, (2, 0): -1, (1, 1): -1, (0, 2): 2, (-1, 3): 1, (0, 0): -1, (-1, 1): -1, (-2, 2): 1, (-2, 0): -1}, 'K6': {(2, 2): 1, (1, 3): 1, (0, 4): 1, (-1, 5): 1, (2, 0): -1, (-1, 3): -2, (-2, 4): 2, (-3, 5): 1, (-1, 1): 2, (-2, 2): -4, (-3, 3): -3, (-4, 4): 1, (-2, 0): 1, (-3, 1): 2, (-4, 2): -3, (-4, 0): 1}, 'K7': {(-2, 2): 1, (-3, 3): 2, (-4, 4): 3, (-5, 5): 2, (-6, 6): 1, (-4, 2): -4, (-5, 3): -2, (-7, 5): 3, (-8, 6): 1, (-4, 0): 2, (-6, 2): -3, (-7, 3): -8, (-8, 4): -3, (-9, 5): 1, (-7, 1): 4, (-8, 2): 2, (-9, 3): -4, (-8, 0): -1, (-9, 1): 4}, - 'K91': {(7, 3): 1, (6, 4): 3, (5, 5): 6, (4, 6): 8, (3, 7): 6, (2, 8): 2, (5, 3): -5, (4, 4): -13, (3, 5): -8, (2, 6): 6, (1, 7): 9, (0, 8): 2, (5, 1): 2, (4, 2): 8, (3, 3): -1, (2, 4): -24, (1, 5): -24, (0, 6): -1, (-1, 7): 3, (4, 0): -2, (3, 1): 2, (2, 2): 17, (1, 3): 14, (0, 4): -11, (-1, 5): -10, (-2, 6): 1, (2, 0): -5, (1, 1): -1, (0, 2): 12, (-1, 3): 9, (-2, 4): -3, (0, 0): -3, (-1, 1): -1, (-2, 2): 3, (-2, 0): -1}, - 'K92': {(5, 5): 1, (4, 6): 4, (3, 7): 6, (2, 8): 3, (5, 3): -1, (4, 4): -7, (3, 5): -11, (2, 6): 5, (1, 7): 14, (0, 8): 3, (4, 2): 3, (3, 3): 5, (2, 4): -19, (1, 5): -26, (0, 6): 9, (-1, 7): 8, (2, 2): 10, (1, 3): 12, (0, 4): -23, (-1, 5): -10, (-2, 6): 8, (2, 0): -1, (1, 1): -1, (0, 2): 11, (-1, 3): 4, (-2, 4): -10, (-3, 5): 4, (0, 0): -1, (-1, 1): -1, (-2, 2): 4, (-3, 3): -2, (-4, 4): 1, (-2, 0): -1}, + 'K91': { + (7, 3): 1, + (6, 4): 3, + (5, 5): 6, + (4, 6): 8, + (3, 7): 6, + (2, 8): 2, + (5, 3): -5, + (4, 4): -13, + (3, 5): -8, + (2, 6): 6, + (1, 7): 9, + (0, 8): 2, + (5, 1): 2, + (4, 2): 8, + (3, 3): -1, + (2, 4): -24, + (1, 5): -24, + (0, 6): -1, + (-1, 7): 3, + (4, 0): -2, + (3, 1): 2, + (2, 2): 17, + (1, 3): 14, + (0, 4): -11, + (-1, 5): -10, + (-2, 6): 1, + (2, 0): -5, + (1, 1): -1, + (0, 2): 12, + (-1, 3): 9, + (-2, 4): -3, + (0, 0): -3, + (-1, 1): -1, + (-2, 2): 3, + (-2, 0): -1, + }, + 'K92': { + (5, 5): 1, + (4, 6): 4, + (3, 7): 6, + (2, 8): 3, + (5, 3): -1, + (4, 4): -7, + (3, 5): -11, + (2, 6): 5, + (1, 7): 14, + (0, 8): 3, + (4, 2): 3, + (3, 3): 5, + (2, 4): -19, + (1, 5): -26, + (0, 6): 9, + (-1, 7): 8, + (2, 2): 10, + (1, 3): 12, + (0, 4): -23, + (-1, 5): -10, + (-2, 6): 8, + (2, 0): -1, + (1, 1): -1, + (0, 2): 11, + (-1, 3): 4, + (-2, 4): -10, + (-3, 5): 4, + (0, 0): -1, + (-1, 1): -1, + (-2, 2): 4, + (-3, 3): -2, + (-4, 4): 1, + (-2, 0): -1, + }, } @@ -608,8 +678,98 @@ def links_gould_polynomial(self): 'K4': {(1, 1): 2, (1, 0): -3, (0, 1): -3, (1, -1): 1, (0, 0): 7, (-1, 1): 1, (0, -1): -3, (-1, 0): -3, (-1, -1): 2}, 'K6': {(2, 2): 2, (2, 1): -3, (1, 2): -3, (2, 0): 1, (1, 1): 10, (0, 2): 1, (1, 0): -10, (0, 1): -10, (1, -1): 3, (0, 0): 17, (-1, 1): 3, (0, -1): -7, (-1, 0): -7, (-1, -1): 4}, 'K7': {(4, 3): -1, (3, 4): -1, (4, 2): 1, (3, 3): 6, (2, 4): 1, (3, 2): -11, (2, 3): -11, (3, 1): 6, (2, 2): 28, (1, 3): 6, (2, 1): -27, (1, 2): -27, (2, 0): 9, (1, 1): 38, (0, 2): 9, (1, 0): -17, (0, 1): -17, (0, 0): 9}, - 'K91': {(2, 2): 6, (2, 1): -20, (1, 2): -20, (2, 0): 29, (1, 1): 76, (0, 2): 29, (2, -1): -25, (1, 0): -123, (0, 1): -123, (-1, 2): -25, (2, -2): 14, (1, -1): 116, (0, 0): 217, (-1, 1): 116, (-2, 2): 14, (2, -3): -5, (1, -2): -71, (0, -1): -216, (-1, 0): -216, (-2, 1): -71, (-3, 2): -5, (2, -4): 1, (1, -3): 27, (0, -2): 136, (-1, -1): 214, (-2, 0): 136, (-3, 1): 27, (-4, 2): 1, (1, -4): -5, (0, -3): -50, (-1, -2): -122, (-2, -1): -122, (-3, 0): -50, (-4, 1): -5, (0, -4): 8, (-1, -3): 37, (-2, -2): 52, (-3, -1): 37, (-4, 0): 8, (-1, -4): -4, (-2, -3): -9, (-3, -2): -9, (-4, -1): -4}, - 'K92': {(3, 1): 6, (2, 2): 12, (1, 3): 6, (3, 0): -15, (2, 1): -63, (1, 2): -63, (0, 3): -15, (3, -1): 14, (2, 0): 112, (1, 1): 216, (0, 2): 112, (-1, 3): 14, (3, -2): -6, (2, -1): -92, (1, 0): -334, (0, 1): -334, (-1, 2): -92, (-2, 3): -6, (3, -3): 1, (2, -2): 37, (1, -1): 262, (0, 0): 503, (-1, 1): 262, (-2, 2): 37, (-3, 3): 1, (2, -3): -6, (1, -2): -104, (0, -1): -400, (-1, 0): -400, (-2, 1): -104, (-3, 2): -6, (1, -3): 17, (0, -2): 162, (-1, -1): 330, (-2, 0): 162, (-3, 1): 17, (0, -3): -27, (-1, -2): -136, (-2, -1): -136, (-3, 0): -27, (-1, -3): 22, (-2, -2): 54, (-3, -1): 22, (-2, -3): -7, (-3, -2): -7}, + 'K91': { + (2, 2): 6, + (2, 1): -20, + (1, 2): -20, + (2, 0): 29, + (1, 1): 76, + (0, 2): 29, + (2, -1): -25, + (1, 0): -123, + (0, 1): -123, + (-1, 2): -25, + (2, -2): 14, + (1, -1): 116, + (0, 0): 217, + (-1, 1): 116, + (-2, 2): 14, + (2, -3): -5, + (1, -2): -71, + (0, -1): -216, + (-1, 0): -216, + (-2, 1): -71, + (-3, 2): -5, + (2, -4): 1, + (1, -3): 27, + (0, -2): 136, + (-1, -1): 214, + (-2, 0): 136, + (-3, 1): 27, + (-4, 2): 1, + (1, -4): -5, + (0, -3): -50, + (-1, -2): -122, + (-2, -1): -122, + (-3, 0): -50, + (-4, 1): -5, + (0, -4): 8, + (-1, -3): 37, + (-2, -2): 52, + (-3, -1): 37, + (-4, 0): 8, + (-1, -4): -4, + (-2, -3): -9, + (-3, -2): -9, + (-4, -1): -4, + }, + 'K92': { + (3, 1): 6, + (2, 2): 12, + (1, 3): 6, + (3, 0): -15, + (2, 1): -63, + (1, 2): -63, + (0, 3): -15, + (3, -1): 14, + (2, 0): 112, + (1, 1): 216, + (0, 2): 112, + (-1, 3): 14, + (3, -2): -6, + (2, -1): -92, + (1, 0): -334, + (0, 1): -334, + (-1, 2): -92, + (-2, 3): -6, + (3, -3): 1, + (2, -2): 37, + (1, -1): 262, + (0, 0): 503, + (-1, 1): 262, + (-2, 2): 37, + (-3, 3): 1, + (2, -3): -6, + (1, -2): -104, + (0, -1): -400, + (-1, 0): -400, + (-2, 1): -104, + (-3, 2): -6, + (1, -3): 17, + (0, -2): 162, + (-1, -1): 330, + (-2, 0): 162, + (-3, 1): 17, + (0, -3): -27, + (-1, -2): -136, + (-2, -1): -136, + (-3, 0): -27, + (-1, -3): 22, + (-2, -2): 54, + (-3, -1): 22, + (-2, -3): -7, + (-3, -2): -7, + }, } @@ -1289,8 +1449,24 @@ def read_irr(variables, num_strands=3): data[2] = ([1, 1, 1], [[{(0, 0): a}], [{(0, 0): c}], [{(0, 0): b}]], [[{(0, 0): 1 / a}], [{(0, 0): 1 / c}], [{(0, 0): 1 / b}]]) data[3] = ( [1, 1, 1, 2, 2, 2, 3], - [[{(0, 0): a}, {(0, 0): a}], [{(0, 0): c}, {(0, 0): c}], [{(0, 0): b}, {(0, 0): b}], [{(0, 0): b, (1, 0): b * c, (1, 1): c}, {(0, 0): c, (0, 1): -1, (1, 1): b}], [{(0, 0): a, (1, 0): a * b, (1, 1): b}, {(0, 0): b, (0, 1): -1, (1, 1): a}], [{(0, 0): a, (1, 0): a * c, (1, 1): c}, {(0, 0): c, (0, 1): -1, (1, 1): a}], [{(0, 0): c, (1, 0): a * c + b**2, (1, 1): b, (2, 0): b, (2, 1): 1, (2, 2): a}, {(0, 0): a, (0, 1): -1, (0, 2): b, (1, 1): b, (1, 2): -a * c - b**2, (2, 2): c}]], - [[{(0, 0): 1 / a}, {(0, 0): 1 / a}], [{(0, 0): 1 / c}, {(0, 0): 1 / c}], [{(0, 0): 1 / b}, {(0, 0): 1 / b}], [{(0, 0): 1 / b, (1, 0): -1, (1, 1): 1 / c}, {(0, 0): 1 / c, (0, 1): 1 / (b * c), (1, 1): 1 / b}], [{(0, 0): 1 / a, (1, 0): -1, (1, 1): 1 / b}, {(0, 0): 1 / b, (0, 1): 1 / (a * b), (1, 1): 1 / a}], [{(0, 0): 1 / a, (1, 0): -1, (1, 1): 1 / c}, {(0, 0): 1 / c, (0, 1): 1 / (a * c), (1, 1): 1 / a}], [{(0, 0): 1 / c, (1, 0): -a / b - b / c, (1, 1): 1 / b, (2, 0): 1 / b, (2, 1): -1 / (a * b), (2, 2): 1 / a}, {(0, 0): 1 / a, (0, 1): 1 / (a * b), (0, 2): 1 / b, (1, 1): 1 / b, (1, 2): a / b + b / c, (2, 2): 1 / c}]], + [ + [{(0, 0): a}, {(0, 0): a}], + [{(0, 0): c}, {(0, 0): c}], + [{(0, 0): b}, {(0, 0): b}], + [{(0, 0): b, (1, 0): b * c, (1, 1): c}, {(0, 0): c, (0, 1): -1, (1, 1): b}], + [{(0, 0): a, (1, 0): a * b, (1, 1): b}, {(0, 0): b, (0, 1): -1, (1, 1): a}], + [{(0, 0): a, (1, 0): a * c, (1, 1): c}, {(0, 0): c, (0, 1): -1, (1, 1): a}], + [{(0, 0): c, (1, 0): a * c + b**2, (1, 1): b, (2, 0): b, (2, 1): 1, (2, 2): a}, {(0, 0): a, (0, 1): -1, (0, 2): b, (1, 1): b, (1, 2): -a * c - b**2, (2, 2): c}], + ], + [ + [{(0, 0): 1 / a}, {(0, 0): 1 / a}], + [{(0, 0): 1 / c}, {(0, 0): 1 / c}], + [{(0, 0): 1 / b}, {(0, 0): 1 / b}], + [{(0, 0): 1 / b, (1, 0): -1, (1, 1): 1 / c}, {(0, 0): 1 / c, (0, 1): 1 / (b * c), (1, 1): 1 / b}], + [{(0, 0): 1 / a, (1, 0): -1, (1, 1): 1 / b}, {(0, 0): 1 / b, (0, 1): 1 / (a * b), (1, 1): 1 / a}], + [{(0, 0): 1 / a, (1, 0): -1, (1, 1): 1 / c}, {(0, 0): 1 / c, (0, 1): 1 / (a * c), (1, 1): 1 / a}], + [{(0, 0): 1 / c, (1, 0): -a / b - b / c, (1, 1): 1 / b, (2, 0): 1 / b, (2, 1): -1 / (a * b), (2, 2): 1 / a}, {(0, 0): 1 / a, (0, 1): 1 / (a * b), (0, 2): 1 / b, (1, 1): 1 / b, (1, 2): a / b + b / c, (2, 2): 1 / c}], + ], ) return data[num_strands] @@ -1322,13 +1498,159 @@ def read_regl(variables, num_strands=3): [24], [ [ - {(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w, (3, 5): -v, (3, 7): 1, (4, 6): -v, (4, 8): 1, (5, 3): 1, (5, 5): u, (6, 4): 1, (6, 6): u, (7, 5): w, (8, 6): w, (9, 9): u, (9, 15): 1, (10, 10): u, (10, 17): 1, (11, 9): w, (12, 10): w, (13, 13): u, (13, 16): 1, (14, 13): w, (15, 9): -v, (15, 11): 1, (16, 13): -v, (16, 14): 1, (17, 10): -v, (17, 12): 1, (18, 19): -v, (18, 20): 1, (19, 18): 1, (19, 19): u, (20, 19): w, (21, 22): -v, (21, 23): 1, (22, 21): 1, (22, 22): u, (23, 22): w}, - {(0, 3): -v, (0, 4): 1, (1, 15): -v, (1, 16): 1, (1, 22): -v, (1, 23): u * v / w, (2, 17): -v, (2, 18): 1, (2, 23): v * (u * v - w) / w, (3, 0): 1, (3, 3): u, (4, 3): w, (5, 9): -v, (5, 10): 1, (5, 12): -u / w, (5, 22): u, (5, 23): -(u**2) / w, (6, 11): -v, (6, 22): w, (6, 23): -u, (7, 12): -u * v / w, (7, 13): -v, (7, 19): 1, (7, 21): -v, (7, 23): -(u**2) * v / w, (8, 12): -v, (8, 14): -v, (8, 20): 1, (8, 23): -u * v, (9, 5): 1, (9, 9): u, (9, 23): u / w, (10, 9): w, (10, 11): -u, (11, 6): 1, (11, 11): u, (11, 13): u, (12, 13): w, (12, 23): -v, (13, 23): 1, (14, 8): 1, (14, 14): u, (14, 23): v, (15, 1): 1, (15, 12): u / w, (15, 15): u, (16, 11): v, (16, 15): w, (16, 23): -u, (17, 2): 1, (17, 12): u * v / w, (17, 17): u, (18, 12): v, (18, 17): w, (19, 21): w, (19, 23): v, (20, 14): w, (21, 7): 1, (21, 21): u, (21, 23): u * v / w, (22, 11): 1, (23, 12): 1, (23, 23): u}, + { + (0, 1): -v, + (0, 2): 1, + (1, 0): 1, + (1, 1): u, + (2, 1): w, + (3, 5): -v, + (3, 7): 1, + (4, 6): -v, + (4, 8): 1, + (5, 3): 1, + (5, 5): u, + (6, 4): 1, + (6, 6): u, + (7, 5): w, + (8, 6): w, + (9, 9): u, + (9, 15): 1, + (10, 10): u, + (10, 17): 1, + (11, 9): w, + (12, 10): w, + (13, 13): u, + (13, 16): 1, + (14, 13): w, + (15, 9): -v, + (15, 11): 1, + (16, 13): -v, + (16, 14): 1, + (17, 10): -v, + (17, 12): 1, + (18, 19): -v, + (18, 20): 1, + (19, 18): 1, + (19, 19): u, + (20, 19): w, + (21, 22): -v, + (21, 23): 1, + (22, 21): 1, + (22, 22): u, + (23, 22): w, + }, + { + (0, 3): -v, + (0, 4): 1, + (1, 15): -v, + (1, 16): 1, + (1, 22): -v, + (1, 23): u * v / w, + (2, 17): -v, + (2, 18): 1, + (2, 23): v * (u * v - w) / w, + (3, 0): 1, + (3, 3): u, + (4, 3): w, + (5, 9): -v, + (5, 10): 1, + (5, 12): -u / w, + (5, 22): u, + (5, 23): -(u**2) / w, + (6, 11): -v, + (6, 22): w, + (6, 23): -u, + (7, 12): -u * v / w, + (7, 13): -v, + (7, 19): 1, + (7, 21): -v, + (7, 23): -(u**2) * v / w, + (8, 12): -v, + (8, 14): -v, + (8, 20): 1, + (8, 23): -u * v, + (9, 5): 1, + (9, 9): u, + (9, 23): u / w, + (10, 9): w, + (10, 11): -u, + (11, 6): 1, + (11, 11): u, + (11, 13): u, + (12, 13): w, + (12, 23): -v, + (13, 23): 1, + (14, 8): 1, + (14, 14): u, + (14, 23): v, + (15, 1): 1, + (15, 12): u / w, + (15, 15): u, + (16, 11): v, + (16, 15): w, + (16, 23): -u, + (17, 2): 1, + (17, 12): u * v / w, + (17, 17): u, + (18, 12): v, + (18, 17): w, + (19, 21): w, + (19, 23): v, + (20, 14): w, + (21, 7): 1, + (21, 21): u, + (21, 23): u * v / w, + (22, 11): 1, + (23, 12): 1, + (23, 23): u, + }, ] ], [ [ - {(0, 1): 1, (0, 2): -u / w, (1, 2): 1 / w, (2, 0): 1, (2, 2): v / w, (3, 5): 1, (3, 7): -u / w, (4, 6): 1, (4, 8): -u / w, (5, 7): 1 / w, (6, 8): 1 / w, (7, 3): 1, (7, 7): v / w, (8, 4): 1, (8, 8): v / w, (9, 11): 1 / w, (10, 12): 1 / w, (11, 11): v / w, (11, 15): 1, (12, 12): v / w, (12, 17): 1, (13, 14): 1 / w, (14, 14): v / w, (14, 16): 1, (15, 9): 1, (15, 11): -u / w, (16, 13): 1, (16, 14): -u / w, (17, 10): 1, (17, 12): -u / w, (18, 19): 1, (18, 20): -u / w, (19, 20): 1 / w, (20, 18): 1, (20, 20): v / w, (21, 22): 1, (21, 23): -u / w, (22, 23): 1 / w, (23, 21): 1, (23, 23): v / w}, + { + (0, 1): 1, + (0, 2): -u / w, + (1, 2): 1 / w, + (2, 0): 1, + (2, 2): v / w, + (3, 5): 1, + (3, 7): -u / w, + (4, 6): 1, + (4, 8): -u / w, + (5, 7): 1 / w, + (6, 8): 1 / w, + (7, 3): 1, + (7, 7): v / w, + (8, 4): 1, + (8, 8): v / w, + (9, 11): 1 / w, + (10, 12): 1 / w, + (11, 11): v / w, + (11, 15): 1, + (12, 12): v / w, + (12, 17): 1, + (13, 14): 1 / w, + (14, 14): v / w, + (14, 16): 1, + (15, 9): 1, + (15, 11): -u / w, + (16, 13): 1, + (16, 14): -u / w, + (17, 10): 1, + (17, 12): -u / w, + (18, 19): 1, + (18, 20): -u / w, + (19, 20): 1 / w, + (20, 18): 1, + (20, 20): v / w, + (21, 22): 1, + (21, 23): -u / w, + (22, 23): 1 / w, + (23, 21): 1, + (23, 23): v / w, + }, { (0, 3): 1, (0, 4): -u / w, @@ -1428,8 +1750,112 @@ def read_regr(variables, num_strands=3): [24], [ [ - {(0, 1): -v, (0, 2): 1, (1, 0): 1, (1, 1): u, (2, 1): w, (3, 15): -v, (3, 17): 1, (4, 16): -v, (4, 18): 1, (4, 22): v**2, (4, 23): -v, (5, 9): -v, (5, 10): 1, (6, 13): -v, (6, 19): 1, (6, 21): -v, (6, 22): -u * v, (7, 11): -v, (7, 12): 1, (8, 14): -v, (8, 20): 1, (8, 22): -v * w, (9, 5): 1, (9, 9): u, (9, 23): u / w, (10, 9): w, (10, 21): -u, (10, 22): -(u**2), (11, 7): 1, (11, 11): u, (11, 21): u, (11, 23): u * v / w, (12, 11): w, (12, 22): -u * w, (13, 6): 1, (13, 13): u, (13, 22): v, (14, 8): 1, (14, 14): u, (14, 23): v, (15, 3): 1, (15, 15): u, (15, 22): u, (15, 23): -(u**2) / w, (16, 4): 1, (16, 16): u, (16, 21): v, (17, 15): w, (17, 22): u * v, (17, 23): -u, (18, 16): w, (19, 13): w, (20, 14): w, (21, 22): -v, (21, 23): 1, (22, 21): 1, (22, 22): u, (23, 22): w}, - {(0, 3): -v, (0, 4): 1, (1, 5): -v, (1, 6): 1, (2, 7): -v, (2, 8): 1, (3, 0): 1, (3, 3): u, (4, 3): w, (5, 1): 1, (5, 5): u, (6, 5): w, (7, 2): 1, (7, 7): u, (8, 7): w, (9, 9): u, (9, 15): 1, (10, 13): u, (10, 16): 1, (10, 22): -v, (11, 9): w, (12, 13): w, (12, 23): -v, (13, 23): 1, (14, 21): w, (14, 23): v, (15, 9): -v, (15, 11): 1, (16, 22): w, (16, 23): -u, (17, 13): -v, (17, 14): 1, (17, 21): -v, (18, 19): -v, (18, 20): 1, (19, 18): 1, (19, 19): u, (20, 19): w, (21, 17): 1, (21, 21): u, (22, 10): 1, (22, 22): u, (23, 12): 1, (23, 23): u}, + { + (0, 1): -v, + (0, 2): 1, + (1, 0): 1, + (1, 1): u, + (2, 1): w, + (3, 15): -v, + (3, 17): 1, + (4, 16): -v, + (4, 18): 1, + (4, 22): v**2, + (4, 23): -v, + (5, 9): -v, + (5, 10): 1, + (6, 13): -v, + (6, 19): 1, + (6, 21): -v, + (6, 22): -u * v, + (7, 11): -v, + (7, 12): 1, + (8, 14): -v, + (8, 20): 1, + (8, 22): -v * w, + (9, 5): 1, + (9, 9): u, + (9, 23): u / w, + (10, 9): w, + (10, 21): -u, + (10, 22): -(u**2), + (11, 7): 1, + (11, 11): u, + (11, 21): u, + (11, 23): u * v / w, + (12, 11): w, + (12, 22): -u * w, + (13, 6): 1, + (13, 13): u, + (13, 22): v, + (14, 8): 1, + (14, 14): u, + (14, 23): v, + (15, 3): 1, + (15, 15): u, + (15, 22): u, + (15, 23): -(u**2) / w, + (16, 4): 1, + (16, 16): u, + (16, 21): v, + (17, 15): w, + (17, 22): u * v, + (17, 23): -u, + (18, 16): w, + (19, 13): w, + (20, 14): w, + (21, 22): -v, + (21, 23): 1, + (22, 21): 1, + (22, 22): u, + (23, 22): w, + }, + { + (0, 3): -v, + (0, 4): 1, + (1, 5): -v, + (1, 6): 1, + (2, 7): -v, + (2, 8): 1, + (3, 0): 1, + (3, 3): u, + (4, 3): w, + (5, 1): 1, + (5, 5): u, + (6, 5): w, + (7, 2): 1, + (7, 7): u, + (8, 7): w, + (9, 9): u, + (9, 15): 1, + (10, 13): u, + (10, 16): 1, + (10, 22): -v, + (11, 9): w, + (12, 13): w, + (12, 23): -v, + (13, 23): 1, + (14, 21): w, + (14, 23): v, + (15, 9): -v, + (15, 11): 1, + (16, 22): w, + (16, 23): -u, + (17, 13): -v, + (17, 14): 1, + (17, 21): -v, + (18, 19): -v, + (18, 20): 1, + (19, 18): 1, + (19, 19): u, + (20, 19): w, + (21, 17): 1, + (21, 21): u, + (22, 10): 1, + (22, 22): u, + (23, 12): 1, + (23, 23): u, + }, ] ], [ @@ -1497,7 +1923,54 @@ def read_regr(variables, num_strands=3): (23, 21): 1, (23, 23): v / w, }, - {(0, 3): 1, (0, 4): -u / w, (1, 5): 1, (1, 6): -u / w, (2, 7): 1, (2, 8): -u / w, (3, 4): 1 / w, (4, 0): 1, (4, 4): v / w, (5, 6): 1 / w, (6, 1): 1, (6, 6): v / w, (7, 8): 1 / w, (8, 2): 1, (8, 8): v / w, (9, 11): 1 / w, (10, 13): -(u**2) / w, (10, 16): -u / w, (10, 22): 1, (11, 11): v / w, (11, 15): 1, (12, 13): -u, (12, 23): 1, (13, 12): 1 / w, (13, 13): v / w, (14, 12): v / w, (14, 14): v / w, (14, 17): 1, (15, 9): 1, (15, 11): -u / w, (16, 10): 1, (16, 12): -u / w, (16, 16): v / w, (17, 13): u * v / w, (17, 14): -u / w, (17, 21): 1, (18, 19): 1, (18, 20): -u / w, (19, 20): 1 / w, (20, 18): 1, (20, 20): v / w, (21, 13): -v / w, (21, 14): 1 / w, (22, 13): u / w, (22, 16): 1 / w, (23, 13): 1}, + { + (0, 3): 1, + (0, 4): -u / w, + (1, 5): 1, + (1, 6): -u / w, + (2, 7): 1, + (2, 8): -u / w, + (3, 4): 1 / w, + (4, 0): 1, + (4, 4): v / w, + (5, 6): 1 / w, + (6, 1): 1, + (6, 6): v / w, + (7, 8): 1 / w, + (8, 2): 1, + (8, 8): v / w, + (9, 11): 1 / w, + (10, 13): -(u**2) / w, + (10, 16): -u / w, + (10, 22): 1, + (11, 11): v / w, + (11, 15): 1, + (12, 13): -u, + (12, 23): 1, + (13, 12): 1 / w, + (13, 13): v / w, + (14, 12): v / w, + (14, 14): v / w, + (14, 17): 1, + (15, 9): 1, + (15, 11): -u / w, + (16, 10): 1, + (16, 12): -u / w, + (16, 16): v / w, + (17, 13): u * v / w, + (17, 14): -u / w, + (17, 21): 1, + (18, 19): 1, + (18, 20): -u / w, + (19, 20): 1 / w, + (20, 18): 1, + (20, 20): v / w, + (21, 13): -v / w, + (21, 14): 1 / w, + (22, 13): u / w, + (22, 16): 1 / w, + (23, 13): 1, + }, ] ], ) @@ -1538,6 +2011,11 @@ def read_markov(bas_ele, variables, num_strands=4): u, v, w, s = variables data = {} data[2] = {'U1': [0, s, 1 / s], 'U2': [1, 0, 0]} - data[3] = {'U1': [0, 0, 0, 0, 0, s**2, 1, 1, 1 / s**2, u * s**2 + w, 0, 0, (s**2 + v) / w, (u * s**2 + w) / s**2, 0, s**2, 1, 1, 1 / s**2, 0, (s**2 + v) / (w * s**2), (u * s**2 + w) / s**2, s**2, 0], 'U2': [0, s, 1 / s, s, 1 / s, 0, 0, 0, 0, -v * s, s, s, (-u * s) / w, (-v) / s, 1 / s, 0, 0, 0, 0, 1 / s, (-u) / (w * s), (-v) / s, 0, 0], 'U3': [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'K4': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]} + data[3] = { + 'U1': [0, 0, 0, 0, 0, s**2, 1, 1, 1 / s**2, u * s**2 + w, 0, 0, (s**2 + v) / w, (u * s**2 + w) / s**2, 0, s**2, 1, 1, 1 / s**2, 0, (s**2 + v) / (w * s**2), (u * s**2 + w) / s**2, s**2, 0], + 'U2': [0, s, 1 / s, s, 1 / s, 0, 0, 0, 0, -v * s, s, s, (-u * s) / w, (-v) / s, 1 / s, 0, 0, 0, 0, 1 / s, (-u) / (w * s), (-v) / s, 0, 0], + 'U3': [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + 'K4': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + } return data[num_strands][bas_ele] diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index d8f496ef54c..eded1875f0b 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -3553,7 +3553,12 @@ def __init__(self, data=None, values_of=None, distribution_of=None, domain=None, result.append(FindStatMatchingMap(entry["MatchingMap"], entry["Quality"])) self._result = FancyTuple(result) - FindStatFunction.__init__(self, FINDSTAT_MAP_PADDED_IDENTIFIER % 0, data={"Bibliography": {}, "Code": _get_code_from_callable(function), "Description": "", "Domain": domain, "Codomain": codomain, "Name": "a new map from %s to %s" % (domain.name("plural"), codomain.name("plural")), "References": "", "Properties": "", "SageCode": ""}, function=function) + FindStatFunction.__init__( + self, + FINDSTAT_MAP_PADDED_IDENTIFIER % 0, + data={"Bibliography": {}, "Code": _get_code_from_callable(function), "Description": "", "Domain": domain, "Codomain": codomain, "Name": "a new map from %s to %s" % (domain.name("plural"), codomain.name("plural")), "References": "", "Properties": "", "SageCode": ""}, + function=function, + ) Element.__init__(self, FindStatMaps()) # this is not completely correct, but it works def __repr__(self): @@ -4460,8 +4465,16 @@ def name(self, style='singular'): "Cores": _SupportedFindStatCollection(lambda x: Core(*literal_eval(x)), lambda X: "( " + X._repr_() + ", " + str(X.k()) + " )", lambda x: Cores(x[1], x[0]), lambda x: (x.length(), x.k()), lambda x: isinstance(x, Core)), "DyckPaths": _SupportedFindStatCollection(lambda x: DyckWord(literal_eval(x)), lambda x: str(list(DyckWord(x))), DyckWords, lambda x: x.semilength(), lambda x: isinstance(x, DyckWord)), "FiniteCartanTypes": _SupportedFindStatCollection(lambda x: CartanType(*literal_eval(str(x))), str, _finite_irreducible_cartan_types_by_rank, lambda x: x.rank(), lambda x: isinstance(x, CartanType_abstract)), - "GelfandTsetlinPatterns": _SupportedFindStatCollection(lambda x: GelfandTsetlinPattern(literal_eval(x)), str, lambda x: (P for la in Partitions(x[1], max_length=x[0]) for P in GelfandTsetlinPatterns(top_row=la + [0] * (x[0] - len(la)))), lambda x: (len(x[0]), sum(x[0])), lambda x: (x == GelfandTsetlinPatterns or isinstance(x, GelfandTsetlinPattern))), - "Graphs": _SupportedFindStatCollection(lambda x: (lambda E, V: Graph([list(range(V)), lambda i, j: (i, j) in E or (j, i) in E], immutable=True))(*literal_eval(x)), lambda X: str((X.edges(labels=False, sort=True), X.n_vertices())), lambda x: (g.copy(immutable=True) for g in graphs(x, copy=False)), lambda x: x.n_vertices(), lambda x: isinstance(x, Graph)), + "GelfandTsetlinPatterns": _SupportedFindStatCollection( + lambda x: GelfandTsetlinPattern(literal_eval(x)), str, lambda x: (P for la in Partitions(x[1], max_length=x[0]) for P in GelfandTsetlinPatterns(top_row=la + [0] * (x[0] - len(la)))), lambda x: (len(x[0]), sum(x[0])), lambda x: (x == GelfandTsetlinPatterns or isinstance(x, GelfandTsetlinPattern)) + ), + "Graphs": _SupportedFindStatCollection( + lambda x: (lambda E, V: Graph([list(range(V)), lambda i, j: (i, j) in E or (j, i) in E], immutable=True))(*literal_eval(x)), + lambda X: str((X.edges(labels=False, sort=True), X.n_vertices())), + lambda x: (g.copy(immutable=True) for g in graphs(x, copy=False)), + lambda x: x.n_vertices(), + lambda x: isinstance(x, Graph), + ), "IntegerPartitions": _SupportedFindStatCollection(lambda x: Partition(literal_eval(x)), str, Partitions, lambda x: x.size(), lambda x: isinstance(x, Partition)), "IntegerCompositions": _SupportedFindStatCollection(lambda x: Composition(literal_eval(x)), str, Compositions, lambda x: x.size(), lambda x: isinstance(x, Composition)), "OrderedTrees": _SupportedFindStatCollection(lambda x: OrderedTree(literal_eval(x)), str, OrderedTrees, lambda x: x.number_of_nodes(), lambda x: isinstance(x, OrderedTree)), @@ -4475,7 +4488,13 @@ def name(self, style='singular'): "SkewPartitions": _SupportedFindStatCollection(lambda x: SkewPartition(literal_eval(x)), str, SkewPartitions, lambda x: x.size(), lambda x: isinstance(x, SkewPartition)), "SignedPermutations": _SupportedFindStatCollection(lambda x: SignedPermutations(len(literal_eval(x)))(list(literal_eval(x))), str, SignedPermutations, lambda x: len(list(x)), lambda x: isinstance(x, SignedPermutation)), "PlanePartitions": _SupportedFindStatCollection(lambda x: PlanePartition(literal_eval(x)), lambda X: str(list(X)).replace(" ", ""), _plane_partitions_by_size, lambda x: sum(sum(la) for la in x), lambda x: isinstance(x, PlanePartition)), - "DecoratedPermutations": _SupportedFindStatCollection(lambda x: DecoratedPermutation([v if v > 0 else (i if v == 0 else -i) for i, v in enumerate(literal_eval(x.replace("+", "0").replace("-", "-1")), 1)]), lambda x: "[" + ",".join((str(v) if abs(v) != i else ("+" if v > 0 else "-") for i, v in enumerate(x, 1))) + "]", DecoratedPermutations, lambda x: x.size(), lambda x: isinstance(x, DecoratedPermutation)), + "DecoratedPermutations": _SupportedFindStatCollection( + lambda x: DecoratedPermutation([v if v > 0 else (i if v == 0 else -i) for i, v in enumerate(literal_eval(x.replace("+", "0").replace("-", "-1")), 1)]), + lambda x: "[" + ",".join((str(v) if abs(v) != i else ("+" if v > 0 else "-") for i, v in enumerate(x, 1))) + "]", + DecoratedPermutations, + lambda x: x.size(), + lambda x: isinstance(x, DecoratedPermutation), + ), "OrderedSetPartitions": _SupportedFindStatCollection(lambda x: OrderedSetPartition(literal_eval(x.replace('{', '[').replace('}', ']'))), str, OrderedSetPartitions, lambda x: x.size(), lambda x: isinstance(x, OrderedSetPartition)), } diff --git a/src/sage/databases/knotinfo_db.py b/src/sage/databases/knotinfo_db.py index cf44b7cbc7d..e68239afd67 100644 --- a/src/sage/databases/knotinfo_db.py +++ b/src/sage/databases/knotinfo_db.py @@ -858,7 +858,28 @@ def _test_database(self, **options): } -row_demo_sample = {'K0_1': [0, 1], 'K3_1': [1, 1], 'K4_1': [2, 1], 'K5_1': [3, 1], 'K5_2': [4, 1], 'K6_1': [5, 1], 'K6_2': [6, 1], 'K6_3': [7, 1], 'K7_1': [8, 1], 'K7_2': [9, 1], 'L2a1_0': [10, 2], 'L2a1_1': [11, 2], 'L4a1_0': [12, 2], 'L4a1_1': [13, 2], 'L5a1_0': [14, 2], 'L5a1_1': [15, 2], 'L6a1_0': [16, 2], 'L6a1_1': [17, 2], 'L6a2_0': [18, 2], 'L6a2_1': [19, 2]} +row_demo_sample = { + 'K0_1': [0, 1], + 'K3_1': [1, 1], + 'K4_1': [2, 1], + 'K5_1': [3, 1], + 'K5_2': [4, 1], + 'K6_1': [5, 1], + 'K6_2': [6, 1], + 'K6_3': [7, 1], + 'K7_1': [8, 1], + 'K7_2': [9, 1], + 'L2a1_0': [10, 2], + 'L2a1_1': [11, 2], + 'L4a1_0': [12, 2], + 'L4a1_1': [13, 2], + 'L5a1_0': [14, 2], + 'L5a1_1': [15, 2], + 'L6a1_0': [16, 2], + 'L6a1_1': [17, 2], + 'L6a2_0': [18, 2], + 'L6a2_1': [19, 2], +} db = KnotInfoDataBase() dc = db.columns() @@ -868,8 +889,42 @@ def _test_database(self, **options): dc.name: ['0_1', '3_1', '4_1', '5_1', '5_2', '6_1', '6_2', '6_3', '7_1', '7_2', 'L2a1{0}', 'L2a1{1}', 'L4a1{0}', 'L4a1{1}', 'L5a1{0}', 'L5a1{1}', 'L6a1{0}', 'L6a1{1}', 'L6a2{0}', 'L6a2{1}', 'L6a3{0}'], dc.name_unoriented: ['L2a1', 'L2a1', 'L4a1', 'L4a1', 'L5a1', 'L5a1', 'L6a1', 'L6a1', 'L6a2', 'L6a2', 'L6a3'], dc.crossing_number: ['0', '3', '4', '5', '5', '6', '6', '6', '7', '7', '2', '2', '4', '4', '5', '5', '6', '6', '6', '6', '6'], - dc.braid_notation: ['', '[1,1,1]', '[1,-2,1,-2]', '[1,1,1,1,1]', '[1,1,1,2,-1,2]', '[1,1,2,-1,-3,2,-3]', '[1,1,1,-2,1,-2]', '[1,1,-2,1,-2,-2]', '[1,1,1,1,1,1,1]', '[1,1,1,2,-1,2,3,-2,3]', '{2, {-1, -1}}', '{2, {1, 1}}', '{3, {-2, -2, -1, 2, -1}}', '{2, {1, 1, 1, 1}}', '{3, {-1, 2, -1, 2, -1}}', '{3, {-1, 2, -1, 2, -1}}', '{4, {1, -2, 3, -2, 1, -2, -3, -2}}', '{3, {2, 2, 2, 1, 1, -2, 1}}', '{3, {-1, 2, -1, -2, -2, -1, -1}}', '{3, {1, -2, 1, 2, 2, 1, 1}}', '{2, {-1, -1, -1, -1, -1, -1}}'], - dc.braid_notation_old: ['{2, {-1, -1}}', '{2, {1, 1}}', '{4, {1, -2, 3, -2, -1, -2, -3, -2}}', '{2, {1, 1, 1, 1}}', '{3, {-1, 2, -1, 2, -1}}', '{3, {-1, 2, -1, 2, -1}}', '{4, {1, -2, 3, -2, 1, -2, -3, -2}}', '{4, {1, 2, 3, 2, 2, -1, 2, 2, -3, 2}}', '{4, {1, -2, -2, -2, 3, -2, -1, -2, -3, -2}}', '{4, {1, 2, -3, 2, -1, 2, 3, 2, 2, 2}}', '{2, {-1, -1, -1, -1, -1, -1}}'], + dc.braid_notation: [ + '', + '[1,1,1]', + '[1,-2,1,-2]', + '[1,1,1,1,1]', + '[1,1,1,2,-1,2]', + '[1,1,2,-1,-3,2,-3]', + '[1,1,1,-2,1,-2]', + '[1,1,-2,1,-2,-2]', + '[1,1,1,1,1,1,1]', + '[1,1,1,2,-1,2,3,-2,3]', + '{2, {-1, -1}}', + '{2, {1, 1}}', + '{3, {-2, -2, -1, 2, -1}}', + '{2, {1, 1, 1, 1}}', + '{3, {-1, 2, -1, 2, -1}}', + '{3, {-1, 2, -1, 2, -1}}', + '{4, {1, -2, 3, -2, 1, -2, -3, -2}}', + '{3, {2, 2, 2, 1, 1, -2, 1}}', + '{3, {-1, 2, -1, -2, -2, -1, -1}}', + '{3, {1, -2, 1, 2, 2, 1, 1}}', + '{2, {-1, -1, -1, -1, -1, -1}}', + ], + dc.braid_notation_old: [ + '{2, {-1, -1}}', + '{2, {1, 1}}', + '{4, {1, -2, 3, -2, -1, -2, -3, -2}}', + '{2, {1, 1, 1, 1}}', + '{3, {-1, 2, -1, 2, -1}}', + '{3, {-1, 2, -1, 2, -1}}', + '{4, {1, -2, 3, -2, 1, -2, -3, -2}}', + '{4, {1, 2, 3, 2, 2, -1, 2, 2, -3, 2}}', + '{4, {1, -2, -2, -2, 3, -2, -1, -2, -3, -2}}', + '{4, {1, 2, -3, 2, -1, 2, 3, 2, 2, 2}}', + '{2, {-1, -1, -1, -1, -1, -1}}', + ], dc.braid_index: ['1', '2', '3', '2', '3', '4', '3', '3', '2', '4'], dc.braid_length: ['', '3', '4', '5', '6', '7', '6', '6', '7', '9'], dc.determinant: ['0', '3', '5', '5', '7', '9', '11', '13', '7', '11', '2', '2', '4', '4', '8', '8', '12', '12', '10', '10', '6'], @@ -888,17 +943,86 @@ def _test_database(self, **options): '[[1,9,2,8],[3,11,4,10],[5,13,6,12],[7,1,8,14],[9,3,10,2],[11,5,12,4],[13,7,14,6]]', '[[2,10,3,9],[4,14,5,13],[6,12,7,11],[8,2,9,1],[10,8,11,7],[12,6,13,5],[14,4,1,3]]', ], - dc.pd_notation_vector: ['{{4, 1, 3, 2}, {2, 3, 1, 4}}', '{{4, 2, 3, 1}, {2, 4, 1, 3}}', '{{6, 1, 7, 2}, {8, 3, 5, 4}, {2, 5, 3, 6}, {4, 7, 1, 8}}', '{{6, 2, 7, 1}, {8, 4, 5, 3}, {2, 8, 3, 7}, {4, 6, 1, 5}}', '{{6, 1, 7, 2}, {10, 7, 5, 8}, {4, 5, 1, 6}, {2, 10, 3, 9}, {8, 4, 9, 3}}', '{{8, 2, 9, 1}, {10, 7, 5, 8}, {4, 10, 1, 9}, {2, 5, 3, 6}, {6, 3, 7, 4}}', '{{6, 1, 7, 2}, {10, 3, 11, 4}, {12, 8, 5, 7}, {8, 12, 9, 11}, {2, 5, 3, 6}, {4, 9, 1, 10}}', '{{10, 2, 11, 1}, {6, 4, 7, 3}, {12, 10, 5, 9}, {8, 6, 9, 5}, {2, 12, 3, 11}, {4, 8, 1, 7}}', '{{8, 1, 9, 2}, {12, 5, 7, 6}, {10, 3, 11, 4}, {4, 11, 5, 12}, {2, 7, 3, 8}, {6, 9, 1, 10}}', '{{10, 2, 11, 1}, {12, 6, 7, 5}, {8, 4, 9, 3}, {4, 8, 5, 7}, {2, 12, 3, 11}, {6, 10, 1, 9}}', '{{8, 1, 9, 2}, {2, 9, 3, 10}, {10, 3, 11, 4}, {12, 5, 7, 6}, {6, 7, 1, 8}, {4, 11, 5, 12}}'], + dc.pd_notation_vector: [ + '{{4, 1, 3, 2}, {2, 3, 1, 4}}', + '{{4, 2, 3, 1}, {2, 4, 1, 3}}', + '{{6, 1, 7, 2}, {8, 3, 5, 4}, {2, 5, 3, 6}, {4, 7, 1, 8}}', + '{{6, 2, 7, 1}, {8, 4, 5, 3}, {2, 8, 3, 7}, {4, 6, 1, 5}}', + '{{6, 1, 7, 2}, {10, 7, 5, 8}, {4, 5, 1, 6}, {2, 10, 3, 9}, {8, 4, 9, 3}}', + '{{8, 2, 9, 1}, {10, 7, 5, 8}, {4, 10, 1, 9}, {2, 5, 3, 6}, {6, 3, 7, 4}}', + '{{6, 1, 7, 2}, {10, 3, 11, 4}, {12, 8, 5, 7}, {8, 12, 9, 11}, {2, 5, 3, 6}, {4, 9, 1, 10}}', + '{{10, 2, 11, 1}, {6, 4, 7, 3}, {12, 10, 5, 9}, {8, 6, 9, 5}, {2, 12, 3, 11}, {4, 8, 1, 7}}', + '{{8, 1, 9, 2}, {12, 5, 7, 6}, {10, 3, 11, 4}, {4, 11, 5, 12}, {2, 7, 3, 8}, {6, 9, 1, 10}}', + '{{10, 2, 11, 1}, {12, 6, 7, 5}, {8, 4, 9, 3}, {4, 8, 5, 7}, {2, 12, 3, 11}, {6, 10, 1, 9}}', + '{{8, 1, 9, 2}, {2, 9, 3, 10}, {10, 3, 11, 4}, {12, 5, 7, 6}, {6, 7, 1, 8}, {4, 11, 5, 12}}', + ], dc.dt_notation: ['', '[4, 6, 2]', '[4, 6, 8, 2]', '[6, 8, 10, 2, 4]', '[4, 8, 10, 2, 6]', '[4, 8, 12, 10, 2, 6]', '[4, 8, 10, 12, 2, 6]', '[4, 8, 10, 2, 12, 6]', '[8, 10, 12, 14, 2, 4, 6]', '[4, 10, 14, 12, 2, 8, 6]'], dc.dt_code: ['[{4}, {2}]', '[{4}, {2}]', '[{6, 8}, {2, 4}]', '[{6, 8}, {4, 2}]', '[{6, 8}, {4, 10, 2}]', '[{8, 6}, {2, 10, 4}]', '[{6, 10}, {2, 12, 4, 8}]', '[{10, 6}, {8, 4, 12, 2}]', '[{8, 10, 12}, {2, 6, 4}]', '[{10, 8, 12}, {4, 6, 2}]', '[{8, 10, 12}, {6, 2, 4}]'], - dc.gauss_notation: ['', '{1, -2, 3, -1, 2, -3}', '{-1, 2, -3, 1, -4, 3, -2, 4}', '{-1, 2, -3, 4, -5, 1, -2, 3, -4, 5}', '{1, -2, 3, -1, 4, -5, 2, -3, 5, -4}', '{1, -2, 3, -4, 2, -1, 5, -6, 4, -3, 6, -5}', '{1, -2, 3, -4, 5, -6, 2, -1, 6, -3, 4, -5}', '{-1, 2, -3, 1, -4, 5, -2, 3, -6, 4, -5, 6}', '{1, -2, 3, -4, 5, -6, 7, -1, 2, -3, 4, -5, 6, -7}', '{-1, 2, -3, 4, -5, 6, -7, 1, -2, 7, -6, 5, -4, 3}', '{{1, -2}, {2, -1}}', '{{1, -2}, {2, -1}}', '{{1, -3, 2, -4}, {3, -1, 4, -2}}', '{{1, -3, 2, -4}, {4, -1, 3, -2}}', '{{1, -4, 5, -3}, {3, -1, 2, -5, 4, -2}}', '{{1, -4, 5, -3}, {4, -5, 2, -1, 3, -2}}', '{{1, -5, 2, -6}, {5, -1, 3, -4, 6, -2, 4, -3}}', '{{1, -5, 2, -6}, {4, -2, 6, -4, 3, -1, 5, -3}}', '{{1, -5, 3, -4, 2, -6}, {5, -1, 6, -3, 4, -2}}', '{{1, -5, 3, -4, 2, -6}, {4, -3, 6, -1, 5, -2}}', '{{1, -2, 3, -6, 4, -5}, {5, -1, 2, -3, 6, -4}}'], - dc.arc_notation: ['{{4, 2}, {3, 1}, {4, 2}, {1, 3}}', '{{2, 4}, {3, 1}, {2, 4}, {3, 1}}', '{{6, 4}, {3, 5}, {4, 2}, {1, 3}, {2, 6}, {5, 1}}', '{{3, 6}, {2, 5}, {6, 4}, {1, 3}, {5, 2}, {4, 1}}', '{{6, 2}, {1, 4}, {3, 5}, {4, 7}, {2, 6}, {7, 3}, {5, 1}}', '{{3, 5}, {6, 4}, {5, 2}, {7, 3}, {1, 6}, {2, 7}, {4, 1}}', '{{8, 4}, {3, 5}, {4, 2}, {6, 3}, {5, 7}, {1, 6}, {2, 8}, {7, 1}}', '{{2, 8}, {1, 7}, {8, 4}, {5, 3}, {4, 2}, {3, 6}, {7, 5}, {6, 1}}', '{{8, 3}, {2, 7}, {3, 1}, {4, 8}, {5, 2}, {6, 4}, {7, 5}, {1, 6}}', '{{3, 8}, {2, 7}, {8, 4}, {1, 3}, {5, 2}, {4, 6}, {7, 5}, {6, 1}}', '{{8, 2}, {1, 3}, {2, 4}, {3, 5}, {4, 6}, {5, 7}, {6, 8}, {7, 1}}'], + dc.gauss_notation: [ + '', + '{1, -2, 3, -1, 2, -3}', + '{-1, 2, -3, 1, -4, 3, -2, 4}', + '{-1, 2, -3, 4, -5, 1, -2, 3, -4, 5}', + '{1, -2, 3, -1, 4, -5, 2, -3, 5, -4}', + '{1, -2, 3, -4, 2, -1, 5, -6, 4, -3, 6, -5}', + '{1, -2, 3, -4, 5, -6, 2, -1, 6, -3, 4, -5}', + '{-1, 2, -3, 1, -4, 5, -2, 3, -6, 4, -5, 6}', + '{1, -2, 3, -4, 5, -6, 7, -1, 2, -3, 4, -5, 6, -7}', + '{-1, 2, -3, 4, -5, 6, -7, 1, -2, 7, -6, 5, -4, 3}', + '{{1, -2}, {2, -1}}', + '{{1, -2}, {2, -1}}', + '{{1, -3, 2, -4}, {3, -1, 4, -2}}', + '{{1, -3, 2, -4}, {4, -1, 3, -2}}', + '{{1, -4, 5, -3}, {3, -1, 2, -5, 4, -2}}', + '{{1, -4, 5, -3}, {4, -5, 2, -1, 3, -2}}', + '{{1, -5, 2, -6}, {5, -1, 3, -4, 6, -2, 4, -3}}', + '{{1, -5, 2, -6}, {4, -2, 6, -4, 3, -1, 5, -3}}', + '{{1, -5, 3, -4, 2, -6}, {5, -1, 6, -3, 4, -2}}', + '{{1, -5, 3, -4, 2, -6}, {4, -3, 6, -1, 5, -2}}', + '{{1, -2, 3, -6, 4, -5}, {5, -1, 2, -3, 6, -4}}', + ], + dc.arc_notation: [ + '{{4, 2}, {3, 1}, {4, 2}, {1, 3}}', + '{{2, 4}, {3, 1}, {2, 4}, {3, 1}}', + '{{6, 4}, {3, 5}, {4, 2}, {1, 3}, {2, 6}, {5, 1}}', + '{{3, 6}, {2, 5}, {6, 4}, {1, 3}, {5, 2}, {4, 1}}', + '{{6, 2}, {1, 4}, {3, 5}, {4, 7}, {2, 6}, {7, 3}, {5, 1}}', + '{{3, 5}, {6, 4}, {5, 2}, {7, 3}, {1, 6}, {2, 7}, {4, 1}}', + '{{8, 4}, {3, 5}, {4, 2}, {6, 3}, {5, 7}, {1, 6}, {2, 8}, {7, 1}}', + '{{2, 8}, {1, 7}, {8, 4}, {5, 3}, {4, 2}, {3, 6}, {7, 5}, {6, 1}}', + '{{8, 3}, {2, 7}, {3, 1}, {4, 8}, {5, 2}, {6, 4}, {7, 5}, {1, 6}}', + '{{3, 8}, {2, 7}, {8, 4}, {1, 3}, {5, 2}, {4, 6}, {7, 5}, {6, 1}}', + '{{8, 2}, {1, 3}, {2, 4}, {3, 5}, {4, 6}, {5, 7}, {6, 8}, {7, 1}}', + ], dc.alternating: ['Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y'], dc.symmetry_type: ['', 'reversible', 'fully amphicheiral', 'reversible', 'reversible', 'reversible', 'reversible', 'fully amphicheiral', 'reversible', 'reversible'], dc.geometric_type: ['', 'torus knot T(2,3)', 'hyperbolic', 'torus knot T(2,5)', 'hyperbolic', 'hyperbolic', 'hyperbolic', 'hyperbolic', 'torus knot T(2,7)', 'hyperbolic'], dc.cosmetic_crossing: ['', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N', 'N'], - dc.homfly_polynomial: ['', '(2*v^2-v^4)+ v^2*z^2', '(v^(-2)-1+ v^2)-z^2', '(3*v^4-2*v^6)+ (4*v^4-v^6)*z^2+ v^4*z^4', '(v^2+ v^4-v^6)+ (v^2+ v^4)*z^2', '(v^(-2)-v^2+ v^4)+ (-1-v^2)*z^2', '(2-2*v^2+ v^4)+ (1-3*v^2+ v^4)*z^2-v^2*z^4', '(-v^(-2)+ 3-v^2)+ (-v^(-2)+ 3-v^2)*z^2+ z^4', '(4*v^6-3*v^8)+ (10*v^6-4*v^8)*z^2+ (6*v^6-v^8)*z^4+ v^6*z^6', '(v^2+ v^6-v^8)+ (v^2+ v^4+ v^6)*z^2'], - dc.homflypt_polynomial: ['1/(v^3*z)-1/(v*z)-z/v', 'v/z-v^3/z + v*z', '1/(v^5*z)-1/(v^3*z)-z/v^3-z/v', 'v^3/z-v^5/z + 3*v^3*z-v^5*z + v^3*z^3', '1/(v*z)-v/z-z/v^3 + (2*z)/v-v*z + z^3/v', '1/(v*z)-v/z-z/v^3 + (2*z)/v-v*z + z^3/v', '1/(v^5*z)-1/(v^3*z)-(2*z)/v^3 + z/v-v*z + z^3/v', 'v^3/z-v^5/z + 2*v^3*z + v^5*z-v^7*z + v^3*z^3 + v^5*z^3', '1/(v^7*z)-1/(v^5*z) + z/v^7-(2*z)/v^5-(2*z)/v^3-z^3/v^5-z^3/v^3', 'v^5/z-v^7/z + 2*v^3*z + 2*v^5*z-v^7*z + v^3*z^3 + v^5*z^3', '1/(v^7*z)-1/(v^5*z) + (3*z)/v^7-(6*z)/v^5 + z^3/v^7-(5*z^3)/v^5-z^5/v^5'], + dc.homfly_polynomial: [ + '', + '(2*v^2-v^4)+ v^2*z^2', + '(v^(-2)-1+ v^2)-z^2', + '(3*v^4-2*v^6)+ (4*v^4-v^6)*z^2+ v^4*z^4', + '(v^2+ v^4-v^6)+ (v^2+ v^4)*z^2', + '(v^(-2)-v^2+ v^4)+ (-1-v^2)*z^2', + '(2-2*v^2+ v^4)+ (1-3*v^2+ v^4)*z^2-v^2*z^4', + '(-v^(-2)+ 3-v^2)+ (-v^(-2)+ 3-v^2)*z^2+ z^4', + '(4*v^6-3*v^8)+ (10*v^6-4*v^8)*z^2+ (6*v^6-v^8)*z^4+ v^6*z^6', + '(v^2+ v^6-v^8)+ (v^2+ v^4+ v^6)*z^2', + ], + dc.homflypt_polynomial: [ + '1/(v^3*z)-1/(v*z)-z/v', + 'v/z-v^3/z + v*z', + '1/(v^5*z)-1/(v^3*z)-z/v^3-z/v', + 'v^3/z-v^5/z + 3*v^3*z-v^5*z + v^3*z^3', + '1/(v*z)-v/z-z/v^3 + (2*z)/v-v*z + z^3/v', + '1/(v*z)-v/z-z/v^3 + (2*z)/v-v*z + z^3/v', + '1/(v^5*z)-1/(v^3*z)-(2*z)/v^3 + z/v-v*z + z^3/v', + 'v^3/z-v^5/z + 2*v^3*z + v^5*z-v^7*z + v^3*z^3 + v^5*z^3', + '1/(v^7*z)-1/(v^5*z) + z/v^7-(2*z)/v^5-(2*z)/v^3-z^3/v^5-z^3/v^3', + 'v^5/z-v^7/z + 2*v^3*z + 2*v^5*z-v^7*z + v^3*z^3 + v^5*z^3', + '1/(v^7*z)-1/(v^5*z) + (3*z)/v^7-(6*z)/v^5 + z^3/v^7-(5*z^3)/v^5-z^5/v^5', + ], dc.kauffman_polynomial: [ '', '(-a^(-4)-2*a^(-2))*z^(0)+ (a^(-5)+ a^(-3))*z^(1)+ (a^(-4)+ a^(-2))*z^(2)', @@ -922,7 +1046,29 @@ def _test_database(self, **options): 'a^(-6)-1/(a^7*z)-1/(a^5*z)-(2*z)/a^9 + (3*z)/a^7 + (3*z)/a^5-(2*z)/a^3-z^2/a^8-(2*z^2)/a^6-z^2/a^4 + z^3/a^9-(2*z^3)/a^7-(2*z^3)/a^5 + z^3/a^3 + z^4/a^8 + (2*z^4)/a^6 + z^4/a^4 + z^5/a^7 + z^5/a^5', 'a^6-a^5/z-a^7/z + 6*a^5*z + 4*a^7*z-a^9*z + a^11*z-3*a^6*z^2-2*a^8*z^2 + a^10*z^2-5*a^5*z^3-4*a^7*z^3 + a^9*z^3 + a^6*z^4 + a^8*z^4 + a^5*z^5 + a^7*z^5', ], - dc.jones_polynomial: ['1', 't+ t^3-t^4', 't^(-2)-t^(-1)+ 1-t+ t^2', 't^2+ t^4-t^5+ t^6-t^7', 't-t^2+ 2*t^3-t^4+ t^5-t^6', 't^(-2)-t^(-1)+ 2-2*t+ t^2-t^3+ t^4', 't^(-1)-1+ 2*t-2*t^2+ 2*t^3-2*t^4+ t^5', '-t^(-3)+ 2*t^(-2)-2*t^(-1)+ 3-2*t+ 2*t^2-t^3', 't^3+ t^5-t^6+ t^7-t^8+ t^9-t^10', 't-t^2+ 2*t^3-2*t^4+ 2*t^5-t^6+ t^7-t^8', '-x^(-5)-x^(-1)', '-x-x^5', '-x^(-9)-x^(-5) + x^(-3)-x^(-1)', '-x^3-x^7 + x^9-x^11', 'x^(-7)-2/x^5 + x^(-3)-2/x + x-x^3', 'x^(-7)-2/x^5 + x^(-3)-2/x + x-x^3', '-x^(-9) + x^(-7)-3/x^5 + 2/x^3-2/x + 2*x-x^3', '-x^3 + x^5-3*x^7 + 2*x^9-2*x^11 + 2*x^13-x^15', '-x^(-15) + x^(-13)-2/x^11 + 2/x^9-2/x^7 + x^(-5)-x^(-3)', '-x^3 + x^5-2*x^7 + 2*x^9-2*x^11 + x^13-x^15', '-x^(-17) + x^(-15)-x^(-13) + x^(-11)-x^(-9)-x^(-5)'], + dc.jones_polynomial: [ + '1', + 't+ t^3-t^4', + 't^(-2)-t^(-1)+ 1-t+ t^2', + 't^2+ t^4-t^5+ t^6-t^7', + 't-t^2+ 2*t^3-t^4+ t^5-t^6', + 't^(-2)-t^(-1)+ 2-2*t+ t^2-t^3+ t^4', + 't^(-1)-1+ 2*t-2*t^2+ 2*t^3-2*t^4+ t^5', + '-t^(-3)+ 2*t^(-2)-2*t^(-1)+ 3-2*t+ 2*t^2-t^3', + 't^3+ t^5-t^6+ t^7-t^8+ t^9-t^10', + 't-t^2+ 2*t^3-2*t^4+ 2*t^5-t^6+ t^7-t^8', + '-x^(-5)-x^(-1)', + '-x-x^5', + '-x^(-9)-x^(-5) + x^(-3)-x^(-1)', + '-x^3-x^7 + x^9-x^11', + 'x^(-7)-2/x^5 + x^(-3)-2/x + x-x^3', + 'x^(-7)-2/x^5 + x^(-3)-2/x + x-x^3', + '-x^(-9) + x^(-7)-3/x^5 + 2/x^3-2/x + 2*x-x^3', + '-x^3 + x^5-3*x^7 + 2*x^9-2*x^11 + 2*x^13-x^15', + '-x^(-15) + x^(-13)-2/x^11 + 2/x^9-2/x^7 + x^(-5)-x^(-3)', + '-x^3 + x^5-2*x^7 + 2*x^9-2*x^11 + x^13-x^15', + '-x^(-17) + x^(-15)-x^(-13) + x^(-11)-x^(-9)-x^(-5)', + ], dc.alexander_polynomial: ['1', '1-t+ t^2', '1-3*t+ t^2', '1-t+ t^2-t^3+ t^4', '2-3*t+ 2*t^2', '2-5*t+ 2*t^2', '1-3*t+ 3*t^2-3*t^3+ t^4', '1-3*t+ 5*t^2-3*t^3+ t^4', '1-t+ t^2-t^3+ t^4-t^5+ t^6', '3-5*t+ 3*t^2'], dc.conway_polynomial: ['1', '1+z^2', '1-z^2', '1+3*z^2+z^4', '1+2*z^2', '1-2*z^2', '1-z^2-z^4', '1+z^2+z^4', '1+6*z^2+5*z^4+z^6', '1+3*z^2', '-z', 'z', '-2*z', '2*z + z^3', 'z^3', 'z^3', '-2*z + z^3', '2*z + 2*z^3', '-3*z-2*z^3', '3*z + 2*z^3', '-3*z-4*z^3-z^5'], dc.khovanov_polynomial: [ @@ -950,10 +1096,76 @@ def _test_database(self, **options): 'q^(5) + q^(7) + t^(2) q^(9) + t^(3) q^(13) + t^(4) q^(13) + t^(5) q^(17) + t^(6) q^(17) + t^(7) q^(21) + t^(3) q^(11) T^(2) + t^(5) q^(15) T^(2) + t^(7) q^(19) T^(2)', 'q + q^(3) + t q^(3) + t^(2) q^(5) + t^(2) q^(7) + t^(3) q^(7) + t^(3) q^(9) + t^(4) q^(9) + t^(4) q^(11) + t^(5) q^(13) + t^(6) q^(13) + t^(7) q^(17) + t^(2) q^(5) T^(2) + t^(3) q^(7) T^(2) + t^(4) q^(9) T^(2) + t^(5) q^(11) T^(2) + t^(7) q^(15) T^(2)', ], - dc.khovanov_reduced_integral_polynomial: ['', 'q^(2) + t^(2) q^(6) + t^(3) q^(8)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', 'q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', 'q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', 'q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', 'q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], - dc.khovanov_reduced_rational_polynomial: ['', ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], - dc.khovanov_reduced_mod2_polynomial: ['', ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], - dc.khovanov_odd_integral_polynomial: ['', 'q^(2) + t^(2) q^(6) + t^(3) q^(8)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', 'q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', 'q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', 'q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', 'q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], - dc.khovanov_odd_rational_polynomial: ['', ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], - dc.khovanov_odd_mod2_polynomial: ['', ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)'], + dc.khovanov_reduced_integral_polynomial: [ + '', + 'q^(2) + t^(2) q^(6) + t^(3) q^(8)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', + 'q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', + 'q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', + 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', + 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', + 'q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', + 'q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)', + ], + dc.khovanov_reduced_rational_polynomial: [ + '', + ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', + ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', + ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', + 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', + 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', + ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', + ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)', + ], + dc.khovanov_reduced_mod2_polynomial: [ + '', + ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', + ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', + ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', + 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', + 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', + ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', + ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)', + ], + dc.khovanov_odd_integral_polynomial: [ + '', + 'q^(2) + t^(2) q^(6) + t^(3) q^(8)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', + 'q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', + 'q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', + 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', + 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', + 'q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', + 'q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)', + ], + dc.khovanov_odd_rational_polynomial: [ + '', + ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', + ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', + ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', + 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', + 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', + ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', + ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)', + ], + dc.khovanov_odd_mod2_polynomial: [ + '', + ' q^(2) + t^(2) q^(6) + t^(3) q^(8)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 1 + t q^(2) + t^(2) q^(4)', + ' q^(4) + t^(2) q^(8) + t^(3) q^(10) + t^(4) q^(12) + t^(5) q^(14)', + ' q^(2) + t q^(4) + 2 t^(2) q^(6) + t^(3) q^(8) + t^(4) q^(10) + t^(5) q^(12)', + 't^(-2) q^(-4) + t^(-1) q^(-2) + 2 + 2 t q^(2) + t^(2) q^(4) + t^(3) q^(6) + t^(4) q^(8)', + 't^(-2) q^(-2) + t^(-1) + 2 q^(2) + 2 t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + t^(4) q^(10)', + 't^(-3) q^(-6) + 2 t^(-2) q^(-4) + 2 t^(-1) q^(-2) + 3 + 2 t q^(2) + 2 t^(2) q^(4) + t^(3) q^(6)', + ' q^(6) + t^(2) q^(10) + t^(3) q^(12) + t^(4) q^(14) + t^(5) q^(16) + t^(6) q^(18) + t^(7) q^(20)', + ' q^(2) + t q^(4) + 2 t^(2) q^(6) + 2 t^(3) q^(8) + 2 t^(4) q^(10) + t^(5) q^(12) + t^(6) q^(14) + t^(7) q^(16)', + ], } diff --git a/src/sage/doctest/__main__.py b/src/sage/doctest/__main__.py index 740f2f68c59..14f48245b4e 100644 --- a/src/sage/doctest/__main__.py +++ b/src/sage/doctest/__main__.py @@ -60,8 +60,25 @@ def _make_parser(): # By default, include all tests marked 'sagemath_doc_html' -- see # https://github.com/sagemath/sage/issues/25345 and # https://github.com/sagemath/sage/issues/26110: - parser.add_argument("--optional", metavar="FEATURES", default=_get_optional_defaults(), help='only run tests including one of the "# optional" tags listed in FEATURES (separated by commas); ' 'if "sage" is listed, will also run the standard doctests; ' 'if "sagemath_doc_html" is listed, will also run the tests relying on the HTML documentation; ' 'if "optional" is listed, will also run tests for installed optional packages or detected features; ' 'if "external" is listed, will also run tests for available external software; ' 'if set to "all", then all tests will be run; ' 'use "!FEATURE" to disable tests marked "# optional - FEATURE". ' 'Note that "!" needs to be quoted or escaped in the shell.') - parser.add_argument("--hide", metavar="FEATURES", default="", help='run tests pretending that the software listed in FEATURES (separated by commas) is not installed; ' 'if "all" is listed, will also hide features corresponding to all optional or experimental packages; ' 'if "optional" is listed, will also hide features corresponding to optional packages.') + parser.add_argument( + "--optional", + metavar="FEATURES", + default=_get_optional_defaults(), + help='only run tests including one of the "# optional" tags listed in FEATURES (separated by commas); ' + 'if "sage" is listed, will also run the standard doctests; ' + 'if "sagemath_doc_html" is listed, will also run the tests relying on the HTML documentation; ' + 'if "optional" is listed, will also run tests for installed optional packages or detected features; ' + 'if "external" is listed, will also run tests for available external software; ' + 'if set to "all", then all tests will be run; ' + 'use "!FEATURE" to disable tests marked "# optional - FEATURE". ' + 'Note that "!" needs to be quoted or escaped in the shell.', + ) + parser.add_argument( + "--hide", + metavar="FEATURES", + default="", + help='run tests pretending that the software listed in FEATURES (separated by commas) is not installed; ' 'if "all" is listed, will also hide features corresponding to all optional or experimental packages; ' 'if "optional" is listed, will also hide features corresponding to optional packages.', + ) parser.add_argument("--probe", metavar="FEATURES", default="", help='run tests that would not be run because one of the given FEATURES (separated by commas) is not installed; ' 'report the tests that pass nevertheless') parser.add_argument("--randorder", type=int, metavar="SEED", help="randomize order of tests") parser.add_argument("--random-seed", dest="random_seed", type=int, metavar="SEED", help="random seed (integer) for fuzzing doctests", default=os.environ.get("SAGE_DOCTEST_RANDOM_SEED")) diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py index 26748570b14..a55cb2bf790 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py @@ -1106,13 +1106,41 @@ def three_stable_points(rational_function, invariant_list): automorphisms = [] for t in permutations(range(len(T)), 3): - a = T[0][0] * T[1][1] * T[2][1] * T[t[0]][0] * T[t[1]][0] * T[t[2]][1] - T[0][0] * T[1][1] * T[2][1] * T[t[0]][0] * T[t[1]][1] * T[t[2]][0] - T[0][1] * T[1][0] * T[2][1] * T[t[0]][0] * T[t[1]][0] * T[t[2]][1] + T[0][1] * T[1][0] * T[2][1] * T[t[0]][1] * T[t[1]][0] * T[t[2]][0] + T[0][1] * T[1][1] * T[2][0] * T[t[0]][0] * T[t[1]][1] * T[t[2]][0] - T[0][1] * T[1][1] * T[2][0] * T[t[0]][1] * T[t[1]][0] * T[t[2]][0] - - b = T[0][0] * T[1][0] * T[2][1] * T[t[0]][0] * T[t[1]][1] * T[t[2]][0] - T[0][0] * T[1][0] * T[2][1] * T[t[0]][1] * T[t[1]][0] * T[t[2]][0] - T[0][0] * T[1][1] * T[2][0] * T[t[0]][0] * T[t[1]][0] * T[t[2]][1] + T[0][0] * T[1][1] * T[2][0] * T[t[0]][1] * T[t[1]][0] * T[t[2]][0] + T[0][1] * T[1][0] * T[2][0] * T[t[0]][0] * T[t[1]][0] * T[t[2]][1] - T[0][1] * T[1][0] * T[2][0] * T[t[0]][0] * T[t[1]][1] * T[t[2]][0] - - c = T[0][0] * T[1][1] * T[2][1] * T[t[0]][1] * T[t[1]][0] * T[t[2]][1] - T[0][0] * T[1][1] * T[2][1] * T[t[0]][1] * T[t[1]][1] * T[t[2]][0] - T[0][1] * T[1][0] * T[2][1] * T[t[0]][0] * T[t[1]][1] * T[t[2]][1] + T[0][1] * T[1][0] * T[2][1] * T[t[0]][1] * T[t[1]][1] * T[t[2]][0] + T[0][1] * T[1][1] * T[2][0] * T[t[0]][0] * T[t[1]][1] * T[t[2]][1] - T[0][1] * T[1][1] * T[2][0] * T[t[0]][1] * T[t[1]][0] * T[t[2]][1] - - d = T[0][0] * T[1][0] * T[2][1] * T[t[0]][0] * T[t[1]][1] * T[t[2]][1] - T[0][0] * T[1][0] * T[2][1] * T[t[0]][1] * T[t[1]][0] * T[t[2]][1] - T[0][0] * T[1][1] * T[2][0] * T[t[0]][0] * T[t[1]][1] * T[t[2]][1] + T[0][0] * T[1][1] * T[2][0] * T[t[0]][1] * T[t[1]][1] * T[t[2]][0] + T[0][1] * T[1][0] * T[2][0] * T[t[0]][1] * T[t[1]][0] * T[t[2]][1] - T[0][1] * T[1][0] * T[2][0] * T[t[0]][1] * T[t[1]][1] * T[t[2]][0] + a = ( + T[0][0] * T[1][1] * T[2][1] * T[t[0]][0] * T[t[1]][0] * T[t[2]][1] + - T[0][0] * T[1][1] * T[2][1] * T[t[0]][0] * T[t[1]][1] * T[t[2]][0] + - T[0][1] * T[1][0] * T[2][1] * T[t[0]][0] * T[t[1]][0] * T[t[2]][1] + + T[0][1] * T[1][0] * T[2][1] * T[t[0]][1] * T[t[1]][0] * T[t[2]][0] + + T[0][1] * T[1][1] * T[2][0] * T[t[0]][0] * T[t[1]][1] * T[t[2]][0] + - T[0][1] * T[1][1] * T[2][0] * T[t[0]][1] * T[t[1]][0] * T[t[2]][0] + ) + + b = ( + T[0][0] * T[1][0] * T[2][1] * T[t[0]][0] * T[t[1]][1] * T[t[2]][0] + - T[0][0] * T[1][0] * T[2][1] * T[t[0]][1] * T[t[1]][0] * T[t[2]][0] + - T[0][0] * T[1][1] * T[2][0] * T[t[0]][0] * T[t[1]][0] * T[t[2]][1] + + T[0][0] * T[1][1] * T[2][0] * T[t[0]][1] * T[t[1]][0] * T[t[2]][0] + + T[0][1] * T[1][0] * T[2][0] * T[t[0]][0] * T[t[1]][0] * T[t[2]][1] + - T[0][1] * T[1][0] * T[2][0] * T[t[0]][0] * T[t[1]][1] * T[t[2]][0] + ) + + c = ( + T[0][0] * T[1][1] * T[2][1] * T[t[0]][1] * T[t[1]][0] * T[t[2]][1] + - T[0][0] * T[1][1] * T[2][1] * T[t[0]][1] * T[t[1]][1] * T[t[2]][0] + - T[0][1] * T[1][0] * T[2][1] * T[t[0]][0] * T[t[1]][1] * T[t[2]][1] + + T[0][1] * T[1][0] * T[2][1] * T[t[0]][1] * T[t[1]][1] * T[t[2]][0] + + T[0][1] * T[1][1] * T[2][0] * T[t[0]][0] * T[t[1]][1] * T[t[2]][1] + - T[0][1] * T[1][1] * T[2][0] * T[t[0]][1] * T[t[1]][0] * T[t[2]][1] + ) + + d = ( + T[0][0] * T[1][0] * T[2][1] * T[t[0]][0] * T[t[1]][1] * T[t[2]][1] + - T[0][0] * T[1][0] * T[2][1] * T[t[0]][1] * T[t[1]][0] * T[t[2]][1] + - T[0][0] * T[1][1] * T[2][0] * T[t[0]][0] * T[t[1]][1] * T[t[2]][1] + + T[0][0] * T[1][1] * T[2][0] * T[t[0]][1] * T[t[1]][1] * T[t[2]][0] + + T[0][1] * T[1][0] * T[2][0] * T[t[0]][1] * T[t[1]][0] * T[t[2]][1] + - T[0][1] * T[1][0] * T[2][0] * T[t[0]][1] * T[t[1]][1] * T[t[2]][0] + ) if a * d - b * c != 0: s = K(a * z + b) / K(c * z + d) diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py b/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py index 4c5feaf0458..62505728f62 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py @@ -971,7 +971,20 @@ def coshdelta(z): C = 4 * d + 2 k = 2 else: - Ck_values = {(False, 2, 2): (322, 6), (False, 2, 3): (385034, 14), (False, 2, 4): (4088003923454, 30), (False, 3, 2): (18044, 8), (False, 4, 2): (1761410, 10), (False, 5, 2): (269283820, 12), (True, 2, 2): (43, 4), (True, 2, 3): (106459, 12), (True, 2, 4): (39216735905, 24), (True, 3, 2): (1604, 6), (True, 4, 2): (114675, 8), (True, 5, 2): (14158456, 10)} + Ck_values = { + (False, 2, 2): (322, 6), + (False, 2, 3): (385034, 14), + (False, 2, 4): (4088003923454, 30), + (False, 3, 2): (18044, 8), + (False, 4, 2): (1761410, 10), + (False, 5, 2): (269283820, 12), + (True, 2, 2): (43, 4), + (True, 2, 3): (106459, 12), + (True, 2, 4): (39216735905, 24), + (True, 3, 2): (1604, 6), + (True, 4, 2): (114675, 8), + (True, 5, 2): (14158456, 10), + } try: C, k = Ck_values[(dynatomic, d, m)] except KeyError: diff --git a/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py b/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py index 979d3a1572f..5858122cfec 100644 --- a/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py +++ b/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py @@ -423,7 +423,12 @@ def Hpoly(self, component, i, j): k = Indices[0] - return 2 * (self._Lcoeff(component, i)) * (self._Lcoeff(component, j)) * (self._Qcoeff(component, k, k)) - (self._Lcoeff(component, i)) * (self._Lcoeff(component, k)) * (self._Qcoeff(component, j, k)) - (self._Lcoeff(component, j)) * (self._Lcoeff(component, k)) * (self._Qcoeff(component, i, k)) + (self._Lcoeff(component, k) ** 2) * (self._Qcoeff(component, i, j)) + return ( + 2 * (self._Lcoeff(component, i)) * (self._Lcoeff(component, j)) * (self._Qcoeff(component, k, k)) + - (self._Lcoeff(component, i)) * (self._Lcoeff(component, k)) * (self._Qcoeff(component, j, k)) + - (self._Lcoeff(component, j)) * (self._Lcoeff(component, k)) * (self._Qcoeff(component, i, k)) + + (self._Lcoeff(component, k) ** 2) * (self._Qcoeff(component, i, j)) + ) def Lxa(self, a): r""" diff --git a/src/sage/features/gap.py b/src/sage/features/gap.py index e89e4229265..bcec1b5bc18 100644 --- a/src/sage/features/gap.py +++ b/src/sage/features/gap.py @@ -74,4 +74,14 @@ def _is_present(self): def all_features(): - return [GapPackage("atlasrep", spkg='gap_packages'), GapPackage("design", spkg='gap_packages'), GapPackage("grape", spkg='gap_packages'), GapPackage("guava", spkg='gap_packages'), GapPackage("hap", spkg='gap_packages'), GapPackage("polenta", spkg='gap_packages'), GapPackage("polycyclic", spkg='gap_packages'), GapPackage("qpa", spkg='gap_packages'), GapPackage("quagroup", spkg='gap_packages')] + return [ + GapPackage("atlasrep", spkg='gap_packages'), + GapPackage("design", spkg='gap_packages'), + GapPackage("grape", spkg='gap_packages'), + GapPackage("guava", spkg='gap_packages'), + GapPackage("hap", spkg='gap_packages'), + GapPackage("polenta", spkg='gap_packages'), + GapPackage("polycyclic", spkg='gap_packages'), + GapPackage("qpa", spkg='gap_packages'), + GapPackage("quagroup", spkg='gap_packages'), + ] diff --git a/src/sage/features/sagemath.py b/src/sage/features/sagemath.py index e6929621f61..17bb94f1a54 100644 --- a/src/sage/features/sagemath.py +++ b/src/sage/features/sagemath.py @@ -422,7 +422,26 @@ def __init__(self): sage: isinstance(sage__libs__gap(), sage__libs__gap) True """ - JoinFeature.__init__(self, 'sage.libs.gap', [PythonModule('sage.libs.gap.libgap'), PythonModule('sage.interfaces.gap'), PythonModule('sage.groups.matrix_gps.finitely_generated_gap'), PythonModule('sage.groups.matrix_gps.group_element_gap'), PythonModule('sage.groups.matrix_gps.heisenberg'), PythonModule('sage.groups.matrix_gps.isometries'), PythonModule('sage.groups.matrix_gps.linear_gap'), PythonModule('sage.groups.matrix_gps.matrix_group_gap'), PythonModule('sage.groups.matrix_gps.named_group_gap'), PythonModule('sage.groups.matrix_gps.orthogonal_gap'), PythonModule('sage.groups.matrix_gps.symplectic_gap'), PythonModule('sage.groups.matrix_gps.unitary_gap'), PythonModule('sage.matrix.matrix_gap'), PythonModule('sage.rings.universal_cyclotomic_field')]) + JoinFeature.__init__( + self, + 'sage.libs.gap', + [ + PythonModule('sage.libs.gap.libgap'), + PythonModule('sage.interfaces.gap'), + PythonModule('sage.groups.matrix_gps.finitely_generated_gap'), + PythonModule('sage.groups.matrix_gps.group_element_gap'), + PythonModule('sage.groups.matrix_gps.heisenberg'), + PythonModule('sage.groups.matrix_gps.isometries'), + PythonModule('sage.groups.matrix_gps.linear_gap'), + PythonModule('sage.groups.matrix_gps.matrix_group_gap'), + PythonModule('sage.groups.matrix_gps.named_group_gap'), + PythonModule('sage.groups.matrix_gps.orthogonal_gap'), + PythonModule('sage.groups.matrix_gps.symplectic_gap'), + PythonModule('sage.groups.matrix_gps.unitary_gap'), + PythonModule('sage.matrix.matrix_gap'), + PythonModule('sage.rings.universal_cyclotomic_field'), + ], + ) class sage__libs__linbox(JoinFeature): diff --git a/src/sage/functions/all.py b/src/sage/functions/all.py index a9f48b6cf45..acbea19f746 100644 --- a/src/sage/functions/all.py +++ b/src/sage/functions/all.py @@ -20,7 +20,35 @@ from sage.functions.special import spherical_harmonic, elliptic_e, elliptic_f, elliptic_ec, elliptic_eu, elliptic_kc, elliptic_pi, elliptic_j -from sage.functions.jacobi import jacobi, inverse_jacobi, jacobi_nd, jacobi_ns, jacobi_nc, jacobi_dn, jacobi_ds, jacobi_dc, jacobi_sn, jacobi_sd, jacobi_sc, jacobi_cn, jacobi_cd, jacobi_cs, jacobi_am, inverse_jacobi_nd, inverse_jacobi_ns, inverse_jacobi_nc, inverse_jacobi_dn, inverse_jacobi_ds, inverse_jacobi_dc, inverse_jacobi_sn, inverse_jacobi_sd, inverse_jacobi_sc, inverse_jacobi_cn, inverse_jacobi_cd, inverse_jacobi_cs +from sage.functions.jacobi import ( + jacobi, + inverse_jacobi, + jacobi_nd, + jacobi_ns, + jacobi_nc, + jacobi_dn, + jacobi_ds, + jacobi_dc, + jacobi_sn, + jacobi_sd, + jacobi_sc, + jacobi_cn, + jacobi_cd, + jacobi_cs, + jacobi_am, + inverse_jacobi_nd, + inverse_jacobi_ns, + inverse_jacobi_nc, + inverse_jacobi_dn, + inverse_jacobi_ds, + inverse_jacobi_dc, + inverse_jacobi_sn, + inverse_jacobi_sd, + inverse_jacobi_sc, + inverse_jacobi_cn, + inverse_jacobi_cd, + inverse_jacobi_cs, +) from sage.functions.orthogonal_polys import chebyshev_T, chebyshev_U, gen_laguerre, gen_legendre_P, gen_legendre_Q, hermite, jacobi_P, laguerre, legendre_P, legendre_Q, ultraspherical, gegenbauer, krawtchouk, meixner, hahn diff --git a/src/sage/functions/jacobi.py b/src/sage/functions/jacobi.py index d0e1e375040..052f61d9996 100644 --- a/src/sage/functions/jacobi.py +++ b/src/sage/functions/jacobi.py @@ -419,21 +419,33 @@ def _derivative_(self, x, m, diff_param): if self.kind == 'dn': return -HALF * (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_sn(x, m) * jacobi_cn(x, m) + HALF * jacobi_dn(x, m) * jacobi_sn(x, m) ** Integer(2) / (m - Integer(1)) if self.kind == 'ds': - return HALF * (jacobi_sn(x, m) * jacobi_cn(x, m) ** Integer(2) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_cn(x, m) / m) * jacobi_dn(x, m) / jacobi_sn(x, m) ** Integer(2) - HALF * ((x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_sn(x, m) * jacobi_cn(x, m) - jacobi_dn(x, m) * jacobi_sn(x, m) ** Integer(2) / (m - Integer(1))) / jacobi_sn(x, m) + return HALF * (jacobi_sn(x, m) * jacobi_cn(x, m) ** Integer(2) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_cn(x, m) / m) * jacobi_dn(x, m) / jacobi_sn(x, m) ** Integer(2) - HALF * ( + (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_sn(x, m) * jacobi_cn(x, m) - jacobi_dn(x, m) * jacobi_sn(x, m) ** Integer(2) / (m - Integer(1)) + ) / jacobi_sn(x, m) if self.kind == 'dc': - return -HALF * (jacobi_sn(x, m) ** Integer(2) * jacobi_cn(x, m) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_sn(x, m) / m) * jacobi_dn(x, m) / jacobi_cn(x, m) ** Integer(2) - HALF * ((x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_sn(x, m) * jacobi_cn(x, m) - jacobi_dn(x, m) * jacobi_sn(x, m) ** Integer(2) / (m - Integer(1))) / jacobi_cn(x, m) + return -HALF * (jacobi_sn(x, m) ** Integer(2) * jacobi_cn(x, m) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_sn(x, m) / m) * jacobi_dn(x, m) / jacobi_cn(x, m) ** Integer(2) - HALF * ( + (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_sn(x, m) * jacobi_cn(x, m) - jacobi_dn(x, m) * jacobi_sn(x, m) ** Integer(2) / (m - Integer(1)) + ) / jacobi_cn(x, m) if self.kind == 'sn': return -HALF * jacobi_sn(x, m) * jacobi_cn(x, m) ** Integer(2) / (m - Integer(1)) + HALF * (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_cn(x, m) / m if self.kind == 'sd': - return -HALF * (jacobi_sn(x, m) * jacobi_cn(x, m) ** Integer(2) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_cn(x, m) / m) / jacobi_dn(x, m) + HALF * ((x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_sn(x, m) * jacobi_cn(x, m) - jacobi_dn(x, m) * jacobi_sn(x, m) ** Integer(2) / (m - Integer(1))) * jacobi_sn(x, m) / jacobi_dn(x, m) ** Integer(2) + return -HALF * (jacobi_sn(x, m) * jacobi_cn(x, m) ** Integer(2) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_cn(x, m) / m) / jacobi_dn(x, m) + HALF * ( + (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_sn(x, m) * jacobi_cn(x, m) - jacobi_dn(x, m) * jacobi_sn(x, m) ** Integer(2) / (m - Integer(1)) + ) * jacobi_sn(x, m) / jacobi_dn(x, m) ** Integer(2) if self.kind == 'sc': - return -HALF * (jacobi_sn(x, m) * jacobi_cn(x, m) ** Integer(2) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_cn(x, m) / m) / jacobi_cn(x, m) - HALF * (jacobi_sn(x, m) ** Integer(2) * jacobi_cn(x, m) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_sn(x, m) / m) * jacobi_sn(x, m) / jacobi_cn(x, m) ** Integer(2) + return -HALF * (jacobi_sn(x, m) * jacobi_cn(x, m) ** Integer(2) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_cn(x, m) / m) / jacobi_cn(x, m) - HALF * ( + jacobi_sn(x, m) ** Integer(2) * jacobi_cn(x, m) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_sn(x, m) / m + ) * jacobi_sn(x, m) / jacobi_cn(x, m) ** Integer(2) if self.kind == 'cn': return HALF * jacobi_sn(x, m) ** Integer(2) * jacobi_cn(x, m) / (m - Integer(1)) - HALF * (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_sn(x, m) / m if self.kind == 'cd': - return HALF * (jacobi_sn(x, m) ** Integer(2) * jacobi_cn(x, m) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_sn(x, m) / m) / jacobi_dn(x, m) + HALF * ((x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_sn(x, m) * jacobi_cn(x, m) - jacobi_dn(x, m) * jacobi_sn(x, m) ** Integer(2) / (m - Integer(1))) * jacobi_cn(x, m) / jacobi_dn(x, m) ** Integer(2) + return HALF * (jacobi_sn(x, m) ** Integer(2) * jacobi_cn(x, m) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_sn(x, m) / m) / jacobi_dn(x, m) + HALF * ( + (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_sn(x, m) * jacobi_cn(x, m) - jacobi_dn(x, m) * jacobi_sn(x, m) ** Integer(2) / (m - Integer(1)) + ) * jacobi_cn(x, m) / jacobi_dn(x, m) ** Integer(2) if self.kind == 'cs': - return HALF * (jacobi_sn(x, m) * jacobi_cn(x, m) ** Integer(2) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_cn(x, m) / m) * jacobi_cn(x, m) / jacobi_sn(x, m) ** Integer(2) + HALF * (jacobi_sn(x, m) ** Integer(2) * jacobi_cn(x, m) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_sn(x, m) / m) / jacobi_sn(x, m) + return HALF * (jacobi_sn(x, m) * jacobi_cn(x, m) ** Integer(2) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_cn(x, m) / m) * jacobi_cn(x, m) / jacobi_sn(x, m) ** Integer(2) + HALF * ( + jacobi_sn(x, m) ** Integer(2) * jacobi_cn(x, m) / (m - Integer(1)) - (x + elliptic_e(arcsin(jacobi_sn(x, m)), m) / (m - Integer(1))) * jacobi_dn(x, m) * jacobi_sn(x, m) / m + ) / jacobi_sn(x, m) def _latex_(self): r""" @@ -747,7 +759,9 @@ def _derivative_(self, x, m, diff_param): if self.kind == 'cn': return (-(Integer(1) / (Integer(2) * (-Integer(1) + m) * m))) * (elliptic_e(jacobi_am(inverse_jacobi_cn(x, m), m), m) + (-Integer(1) + m) * inverse_jacobi_cn(x, m) - m * x * jacobi_sd(inverse_jacobi_cn(x, m), m)) if self.kind == 'cs': - return (-(Integer(1) / (Integer(2) * (-Integer(1) + m) * m * (Integer(1) + x ** Integer(2))))) * ((Integer(1) + x ** Integer(2)) * elliptic_e(jacobi_am(inverse_jacobi_cs(x, m), m), m) + (-Integer(1) + m) * (Integer(1) + x ** Integer(2)) * inverse_jacobi_cs(x, m) - m * x * jacobi_nd(inverse_jacobi_cs(x, m), m)) + return (-(Integer(1) / (Integer(2) * (-Integer(1) + m) * m * (Integer(1) + x ** Integer(2))))) * ( + (Integer(1) + x ** Integer(2)) * elliptic_e(jacobi_am(inverse_jacobi_cs(x, m), m), m) + (-Integer(1) + m) * (Integer(1) + x ** Integer(2)) * inverse_jacobi_cs(x, m) - m * x * jacobi_nd(inverse_jacobi_cs(x, m), m) + ) if self.kind == 'dc': return (Integer(1) / (Integer(2) * (Integer(1) - m) * m)) * (elliptic_e(jacobi_am(inverse_jacobi_dc(x, m), m), m) - (Integer(1) - m) * inverse_jacobi_dc(x, m)) if self.kind == 'dn': @@ -761,7 +775,9 @@ def _derivative_(self, x, m, diff_param): if self.kind == 'ns': return (Integer(1) / (Integer(2) * (m - Integer(1)) * m)) * ((Integer(1) - m) * inverse_jacobi_ns(x, m) - elliptic_e(jacobi_am(inverse_jacobi_ns(x, m), m), m) + (m / x) * jacobi_cd(inverse_jacobi_ns(x, m), m)) if self.kind == 'sc': - return (-(Integer(1) / (Integer(2) * (-Integer(1) + m) * m * (Integer(1) + x ** Integer(2))))) * ((Integer(1) + x ** Integer(2)) * elliptic_e(jacobi_am(inverse_jacobi_sc(x, m), m), m) + (-Integer(1) + m) * (Integer(1) + x ** Integer(2)) * inverse_jacobi_sc(x, m) - m * x * jacobi_nd(inverse_jacobi_sc(x, m), m)) + return (-(Integer(1) / (Integer(2) * (-Integer(1) + m) * m * (Integer(1) + x ** Integer(2))))) * ( + (Integer(1) + x ** Integer(2)) * elliptic_e(jacobi_am(inverse_jacobi_sc(x, m), m), m) + (-Integer(1) + m) * (Integer(1) + x ** Integer(2)) * inverse_jacobi_sc(x, m) - m * x * jacobi_nd(inverse_jacobi_sc(x, m), m) + ) if self.kind == 'sd': return (-(Integer(1) / (Integer(2) * (-Integer(1) + m) * m))) * (elliptic_e(jacobi_am(inverse_jacobi_sd(x, m), m), m) + (-Integer(1) + m) * inverse_jacobi_sd(x, m) - (m * x * jacobi_nc(inverse_jacobi_sd(x, m), m)) / (Integer(1) + m * x ** Integer(2))) if self.kind == 'sn': diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 5a1191d2951..f1930803abc 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -783,7 +783,9 @@ def _derivative_(self, u, m, diff_param): if diff_param == 0: return sqrt(-m * jacobi('sn', u, m) ** Integer(2) + Integer(1)) * jacobi('dn', u, m) if diff_param == 1: - return Integer(1) / Integer(2) * (elliptic_eu(u, m) - elliptic_f(jacobi_am(u, m), m)) / m - Integer(1) / Integer(2) * sqrt(-m * jacobi('sn', u, m) ** Integer(2) + Integer(1)) * (m * jacobi('sn', u, m) * jacobi('cn', u, m) - (m - Integer(1)) * u - elliptic_eu(u, m) * jacobi('dn', u, m)) / ((m - Integer(1)) * m) + return Integer(1) / Integer(2) * (elliptic_eu(u, m) - elliptic_f(jacobi_am(u, m), m)) / m - Integer(1) / Integer(2) * sqrt(-m * jacobi('sn', u, m) ** Integer(2) + Integer(1)) * (m * jacobi('sn', u, m) * jacobi('cn', u, m) - (m - Integer(1)) * u - elliptic_eu(u, m) * jacobi('dn', u, m)) / ( + (m - Integer(1)) * m + ) def _print_latex_(self, u, m): """ diff --git a/src/sage/functions/wigner.py b/src/sage/functions/wigner.py index 4a8f5a54825..4776613bf34 100644 --- a/src/sage/functions/wigner.py +++ b/src/sage/functions/wigner.py @@ -169,7 +169,10 @@ def wigner_3j(j_1, j_2, j_3, m_1, m_2, m_3, prec=None): maxfact = max(j_1 + j_2 + j_3 + 1, j_1 + abs(m_1), j_2 + abs(m_2), j_3 + abs(m_3)) _calc_factlist(maxfact) - argsqrt = Integer(_Factlist[int(j_1 + j_2 - j_3)] * _Factlist[int(j_1 - j_2 + j_3)] * _Factlist[int(-j_1 + j_2 + j_3)] * _Factlist[int(j_1 - m_1)] * _Factlist[int(j_1 + m_1)] * _Factlist[int(j_2 - m_2)] * _Factlist[int(j_2 + m_2)] * _Factlist[int(j_3 - m_3)] * _Factlist[int(j_3 + m_3)]) / _Factlist[int(j_1 + j_2 + j_3 + 1)] + argsqrt = ( + Integer(_Factlist[int(j_1 + j_2 - j_3)] * _Factlist[int(j_1 - j_2 + j_3)] * _Factlist[int(-j_1 + j_2 + j_3)] * _Factlist[int(j_1 - m_1)] * _Factlist[int(j_1 + m_1)] * _Factlist[int(j_2 - m_2)] * _Factlist[int(j_2 + m_2)] * _Factlist[int(j_3 - m_3)] * _Factlist[int(j_3 + m_3)]) + / _Factlist[int(j_1 + j_2 + j_3 + 1)] + ) ressqrt = argsqrt.sqrt(prec) if isinstance(ressqrt, ComplexNumber): diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py b/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py index d5bf28570d8..c7eb88ce265 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py @@ -682,7 +682,17 @@ def SL2R_to_SO21(A): a, b, c, d = (A / A.det().sqrt()).list() # Kill ~0 imaginary parts - components = [a * d + b * c, a * c - b * d, a * c + b * d, a * b - c * d, Integer(1) / Integer(2) * a**2 - Integer(1) / Integer(2) * b**2 - Integer(1) / Integer(2) * c**2 + Integer(1) / Integer(2) * d**2, Integer(1) / Integer(2) * a**2 + Integer(1) / Integer(2) * b**2 - Integer(1) / Integer(2) * c**2 - Integer(1) / Integer(2) * d**2, a * b + c * d, Integer(1) / Integer(2) * a**2 - Integer(1) / Integer(2) * b**2 + Integer(1) / Integer(2) * c**2 - Integer(1) / Integer(2) * d**2, Integer(1) / Integer(2) * a**2 + Integer(1) / Integer(2) * b**2 + Integer(1) / Integer(2) * c**2 + Integer(1) / Integer(2) * d**2] + components = [ + a * d + b * c, + a * c - b * d, + a * c + b * d, + a * b - c * d, + Integer(1) / Integer(2) * a**2 - Integer(1) / Integer(2) * b**2 - Integer(1) / Integer(2) * c**2 + Integer(1) / Integer(2) * d**2, + Integer(1) / Integer(2) * a**2 + Integer(1) / Integer(2) * b**2 - Integer(1) / Integer(2) * c**2 - Integer(1) / Integer(2) * d**2, + a * b + c * d, + Integer(1) / Integer(2) * a**2 - Integer(1) / Integer(2) * b**2 + Integer(1) / Integer(2) * c**2 - Integer(1) / Integer(2) * d**2, + Integer(1) / Integer(2) * a**2 + Integer(1) / Integer(2) * b**2 + Integer(1) / Integer(2) * c**2 + Integer(1) / Integer(2) * d**2, + ] B = matrix(3, [real(comp) for comp in components]) # B = B.apply_map(attrcall('real')) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index c4be42f3ed3..f4094db9073 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -3379,7 +3379,28 @@ def origin(self): except ValueError: pass - def plot3d(self, show_facets=True, facet_opacity=0.5, facet_color=(0, 1, 0), facet_colors=None, show_edges=True, edge_thickness=3, edge_color=(0.5, 0.5, 0.5), show_vertices=True, vertex_size=10, vertex_color=(1, 0, 0), show_points=True, point_size=10, point_color=(0, 0, 1), show_vindices=None, vindex_color=(0, 0, 0), vlabels=None, show_pindices=None, pindex_color=(0, 0, 0), index_shift=1.1): + def plot3d( + self, + show_facets=True, + facet_opacity=0.5, + facet_color=(0, 1, 0), + facet_colors=None, + show_edges=True, + edge_thickness=3, + edge_color=(0.5, 0.5, 0.5), + show_vertices=True, + vertex_size=10, + vertex_color=(1, 0, 0), + show_points=True, + point_size=10, + point_color=(0, 0, 1), + show_vindices=None, + vindex_color=(0, 0, 0), + vlabels=None, + show_pindices=None, + pindex_color=(0, 0, 0), + index_shift=1.1, + ): r""" Return a 3d-plot of this polytope. diff --git a/src/sage/geometry/polyhedron/base_QQ.py b/src/sage/geometry/polyhedron/base_QQ.py index 5e006d066f1..04eba0af6cd 100644 --- a/src/sage/geometry/polyhedron/base_QQ.py +++ b/src/sage/geometry/polyhedron/base_QQ.py @@ -765,7 +765,20 @@ def _ehrhart_polynomial_latte(self, verbose=False, dual=None, irrational_primal= # note: the options below are explicitly written in the function # declaration in order to keep tab completion (see #18211). - kwds.update({'dual': dual, 'irrational_primal': irrational_primal, 'irrational_all_primal': irrational_all_primal, 'maxdet': maxdet, 'no_decomposition': no_decomposition, 'compute_vertex_cones': compute_vertex_cones, 'smith_form': smith_form, 'dualization': dualization, 'triangulation': triangulation, 'triangulation_max_height': triangulation_max_height}) + kwds.update( + { + 'dual': dual, + 'irrational_primal': irrational_primal, + 'irrational_all_primal': irrational_all_primal, + 'maxdet': maxdet, + 'no_decomposition': no_decomposition, + 'compute_vertex_cones': compute_vertex_cones, + 'smith_form': smith_form, + 'dualization': dualization, + 'triangulation': triangulation, + 'triangulation_max_height': triangulation_max_height, + } + ) from sage.interfaces.latte import count diff --git a/src/sage/geometry/polyhedron/base_ZZ.py b/src/sage/geometry/polyhedron/base_ZZ.py index bb0d5a034ac..ab079682034 100644 --- a/src/sage/geometry/polyhedron/base_ZZ.py +++ b/src/sage/geometry/polyhedron/base_ZZ.py @@ -239,7 +239,20 @@ def _ehrhart_polynomial_latte(self, verbose=False, dual=None, irrational_primal= """ # note: the options below are explicitly written in the function # declaration in order to keep tab completion (see #18211). - kwds.update({'dual': dual, 'irrational_primal': irrational_primal, 'irrational_all_primal': irrational_all_primal, 'maxdet': maxdet, 'no_decomposition': no_decomposition, 'compute_vertex_cones': compute_vertex_cones, 'smith_form': smith_form, 'dualization': dualization, 'triangulation': triangulation, 'triangulation_max_height': triangulation_max_height}) + kwds.update( + { + 'dual': dual, + 'irrational_primal': irrational_primal, + 'irrational_all_primal': irrational_all_primal, + 'maxdet': maxdet, + 'no_decomposition': no_decomposition, + 'compute_vertex_cones': compute_vertex_cones, + 'smith_form': smith_form, + 'dualization': dualization, + 'triangulation': triangulation, + 'triangulation_max_height': triangulation_max_height, + } + ) from sage.interfaces.latte import count diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index 21d28ced776..ee2e81c38f5 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -3177,7 +3177,16 @@ def line_graph_forbidden_subgraphs(immutable=False): L = [ClawGraph(immutable=immutable)] - dd = [{0: [1, 2, 3], 1: [2, 3], 4: [2], 5: [3]}, {0: [1, 2, 3, 4], 1: [2, 3, 4], 3: [4], 2: [5]}, {0: [1, 2, 3], 1: [2, 3], 4: [2, 3]}, {0: [1, 2, 3], 1: [2, 3], 4: [2], 5: [3, 4]}, {0: [1, 2, 3, 4], 1: [2, 3, 4], 3: [4], 5: [2, 0, 1]}, {5: [0, 1, 2, 3, 4], 0: [1, 4], 2: [1, 3], 3: [4]}, {1: [0, 2, 3, 4], 3: [0, 4], 2: [4, 5], 4: [5]}, {0: [1, 2, 3], 1: [2, 3, 4], 2: [3, 4], 3: [4]}] + dd = [ + {0: [1, 2, 3], 1: [2, 3], 4: [2], 5: [3]}, + {0: [1, 2, 3, 4], 1: [2, 3, 4], 3: [4], 2: [5]}, + {0: [1, 2, 3], 1: [2, 3], 4: [2, 3]}, + {0: [1, 2, 3], 1: [2, 3], 4: [2], 5: [3, 4]}, + {0: [1, 2, 3, 4], 1: [2, 3, 4], 3: [4], 5: [2, 0, 1]}, + {5: [0, 1, 2, 3, 4], 0: [1, 4], 2: [1, 3], 3: [4]}, + {1: [0, 2, 3, 4], 3: [0, 4], 2: [4, 5], 4: [5]}, + {0: [1, 2, 3], 1: [2, 3, 4], 2: [3, 4], 3: [4]}, + ] for d in dd: L.append(Graph(d, format="dict_of_lists", immutable=immutable)) @@ -3329,7 +3338,43 @@ def p2_forbidden_minors(immutable=False): sage: len(graphs.families.p2_forbidden_minors()) 35 """ - p2_forbidden_minors_graph6 = ['KFz_????wF?[', 'J~{???F@oM?', 'I~{?GKF@w', 'JFz_?AB_sE?', 'I~{?CME`_', 'H~}CKMF', 'G^~EMK', 'H^|ACME', 'Himp`cr', 'Iimp_CpKO', 'IFz@GCdHO', 'IBz__aB_o', 'FQ~~w', 'GlvJ`k', 'HilKH`J', 'GjlKJs', 'HhI]ECZ', 'HiMIKSp', 'HFwO]Kf', 'I]q?a?n@o', 'IHIWuFGo_', 'IXJWMC`Eg', 'GFzfF?', 'I]o__OF@o', 'G?^vf_', 'H?]ufBo', 'GlrHhs', 'HhIWuRB', 'IXCO]FGb?', 'Fvz~o', 'GlfH]{', 'Hl`HGvV', 'HhcIHmv', 'IhEGICRiw', 'JhEIDSD?ga_'] + p2_forbidden_minors_graph6 = [ + 'KFz_????wF?[', + 'J~{???F@oM?', + 'I~{?GKF@w', + 'JFz_?AB_sE?', + 'I~{?CME`_', + 'H~}CKMF', + 'G^~EMK', + 'H^|ACME', + 'Himp`cr', + 'Iimp_CpKO', + 'IFz@GCdHO', + 'IBz__aB_o', + 'FQ~~w', + 'GlvJ`k', + 'HilKH`J', + 'GjlKJs', + 'HhI]ECZ', + 'HiMIKSp', + 'HFwO]Kf', + 'I]q?a?n@o', + 'IHIWuFGo_', + 'IXJWMC`Eg', + 'GFzfF?', + 'I]o__OF@o', + 'G?^vf_', + 'H?]ufBo', + 'GlrHhs', + 'HhIWuRB', + 'IXCO]FGb?', + 'Fvz~o', + 'GlfH]{', + 'Hl`HGvV', + 'HhcIHmv', + 'IhEGICRiw', + 'JhEIDSD?ga_', + ] return [Graph(graph_str, format="graph6", immutable=immutable) for graph_str in p2_forbidden_minors_graph6] diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index 728aefeccb2..96198799dcb 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -428,7 +428,42 @@ def WellsGraph(immutable=False): g.name("Wells graph") # Giving our graph a "not-so-bad" layout - g.relabel({(1, 3): 8, (3, 0): 18, (3, '+'): 22, (2, 1): 13, (1, '+'): 10, (0, 3): 2, (2, '+'): 16, ('inf', '-'): 31, (4, 0): 24, (1, 2): 7, (4, '+'): 28, (0, '-'): 5, (0, 4): 3, (4, 1): 25, (2, '-'): 17, (3, 2): 20, (3, '-'): 23, (1, '-'): 11, (1, 4): 9, (2, 3): 14, ('inf', '+'): 30, (4, 2): 26, (1, 0): 6, (0, 1): 0, (3, 1): 19, (0, 2): 1, (2, 0): 12, (4, '-'): 29, (0, '+'): 4, (4, 3): 27, (3, 4): 21, (2, 4): 15}) + g.relabel( + { + (1, 3): 8, + (3, 0): 18, + (3, '+'): 22, + (2, 1): 13, + (1, '+'): 10, + (0, 3): 2, + (2, '+'): 16, + ('inf', '-'): 31, + (4, 0): 24, + (1, 2): 7, + (4, '+'): 28, + (0, '-'): 5, + (0, 4): 3, + (4, 1): 25, + (2, '-'): 17, + (3, 2): 20, + (3, '-'): 23, + (1, '-'): 11, + (1, 4): 9, + (2, 3): 14, + ('inf', '+'): 30, + (4, 2): 26, + (1, 0): 6, + (0, 1): 0, + (3, 1): 19, + (0, 2): 1, + (2, 0): 12, + (4, '-'): 29, + (0, '+'): 4, + (4, 3): 27, + (3, 4): 21, + (2, 4): 15, + } + ) p = [(1, 29, 20, 13, 12, 28, 14, 7), (2, 5, 30, 23, 18, 4, 31, 22), (3, 17, 21, 9, 24, 16, 27, 25), (6, 10, 8, 15, 0, 11, 19, 26)] @@ -504,9 +539,251 @@ def Cell600(embedding=1, immutable=False): # Embedding if embedding == 1: - pos = [0, 1, 3, 13, 78, 90, 93, 110, 29, 104, 11, 48, 107, 83, 92, 55, 32, 16, 117, 24, 26, 56, 52, 47, 75, 72, 66, 112, 27, 115, 21, 33, 118, 79, 91, 37, 2, 5, 96, 31, 82, 88, 94, 74, 50, 28, 20, 105, 45, 99, 70, 25, 101, 54, 46, 51, 17, 35, 98, 41, 84, 85, 87, 73, 18, 6, 9, 97, 65, 103, 95, 36, 100, 23, 8, 43, 68, 76, 116, 60, 62, 44, 40, 59, 15, 12, 30, 113, 63, 114, 81, 69, 119, 19, 7, 49, 86, 89, 111, 67, 22, 4, 10, 14, 38, 64, 80, 102, 57, 108, 34, 61, 106, 42, 58, 39, 77, 71, 109, 53] + pos = [ + 0, + 1, + 3, + 13, + 78, + 90, + 93, + 110, + 29, + 104, + 11, + 48, + 107, + 83, + 92, + 55, + 32, + 16, + 117, + 24, + 26, + 56, + 52, + 47, + 75, + 72, + 66, + 112, + 27, + 115, + 21, + 33, + 118, + 79, + 91, + 37, + 2, + 5, + 96, + 31, + 82, + 88, + 94, + 74, + 50, + 28, + 20, + 105, + 45, + 99, + 70, + 25, + 101, + 54, + 46, + 51, + 17, + 35, + 98, + 41, + 84, + 85, + 87, + 73, + 18, + 6, + 9, + 97, + 65, + 103, + 95, + 36, + 100, + 23, + 8, + 43, + 68, + 76, + 116, + 60, + 62, + 44, + 40, + 59, + 15, + 12, + 30, + 113, + 63, + 114, + 81, + 69, + 119, + 19, + 7, + 49, + 86, + 89, + 111, + 67, + 22, + 4, + 10, + 14, + 38, + 64, + 80, + 102, + 57, + 108, + 34, + 61, + 106, + 42, + 58, + 39, + 77, + 71, + 109, + 53, + ] else: - pos = [0, 1, 2, 3, 4, 6, 7, 8, 10, 13, 14, 21, 37, 103, 36, 65, 113, 25, 80, 26, 12, 78, 24, 83, 54, 66, 114, 46, 63, 101, 109, 93, 79, 75, 51, 44, 31, 119, 43, 5, 57, 100, 11, 108, 34, 41, 69, 96, 82, 116, 68, 64, 47, 102, 52, 35, 17, 76, 110, 38, 84, 85, 86, 87, 88, 90, 91, 92, 94, 73, 74, 81, 49, 104, 48, 29, 112, 61, 20, 62, 72, 18, 60, 23, 42, 30, 115, 58, 27, 106, 98, 9, 19, 15, 39, 56, 67, 118, 55, 89, 45, 107, 95, 99, 70, 53, 33, 111, 22, 117, 32, 28, 59, 105, 40, 71, 77, 16, 97, 50] + pos = [ + 0, + 1, + 2, + 3, + 4, + 6, + 7, + 8, + 10, + 13, + 14, + 21, + 37, + 103, + 36, + 65, + 113, + 25, + 80, + 26, + 12, + 78, + 24, + 83, + 54, + 66, + 114, + 46, + 63, + 101, + 109, + 93, + 79, + 75, + 51, + 44, + 31, + 119, + 43, + 5, + 57, + 100, + 11, + 108, + 34, + 41, + 69, + 96, + 82, + 116, + 68, + 64, + 47, + 102, + 52, + 35, + 17, + 76, + 110, + 38, + 84, + 85, + 86, + 87, + 88, + 90, + 91, + 92, + 94, + 73, + 74, + 81, + 49, + 104, + 48, + 29, + 112, + 61, + 20, + 62, + 72, + 18, + 60, + 23, + 42, + 30, + 115, + 58, + 27, + 106, + 98, + 9, + 19, + 15, + 39, + 56, + 67, + 118, + 55, + 89, + 45, + 107, + 95, + 99, + 70, + 53, + 33, + 111, + 22, + 117, + 32, + 28, + 59, + 105, + 40, + 71, + 77, + 16, + 97, + 50, + ] g._circle_embedding(pos) @@ -1629,7 +1906,120 @@ def Balaban11Cage(embedding=1, immutable=False): return Graph(edge_dict, pos=pos_dict, name="Balaban 11-cage", immutable=immutable) if embedding == 2 or embedding == 3: - L = [44, 26, -47, -15, 35, -39, 11, -27, 38, -37, 43, 14, 28, 51, -29, -16, 41, -11, -26, 15, 22, -51, -35, 36, 52, -14, -33, -26, -46, 52, 26, 16, 43, 33, -15, 17, -53, 23, -42, -35, -28, 30, -22, 45, -44, 16, -38, -16, 50, -55, 20, 28, -17, -43, 47, 34, -26, -41, 11, -36, -23, -16, 41, 17, -51, 26, -33, 47, 17, -11, -20, -30, 21, 29, 36, -43, -52, 10, 39, -28, -17, -52, 51, 26, 37, -17, 10, -10, -45, -34, 17, -26, 27, -21, 46, 53, -10, 29, -50, 35, 15, -47, -29, -41, 26, 33, 55, -17, 42, -26, -36, 16] + L = [ + 44, + 26, + -47, + -15, + 35, + -39, + 11, + -27, + 38, + -37, + 43, + 14, + 28, + 51, + -29, + -16, + 41, + -11, + -26, + 15, + 22, + -51, + -35, + 36, + 52, + -14, + -33, + -26, + -46, + 52, + 26, + 16, + 43, + 33, + -15, + 17, + -53, + 23, + -42, + -35, + -28, + 30, + -22, + 45, + -44, + 16, + -38, + -16, + 50, + -55, + 20, + 28, + -17, + -43, + 47, + 34, + -26, + -41, + 11, + -36, + -23, + -16, + 41, + 17, + -51, + 26, + -33, + 47, + 17, + -11, + -20, + -30, + 21, + 29, + 36, + -43, + -52, + 10, + 39, + -28, + -17, + -52, + 51, + 26, + 37, + -17, + 10, + -10, + -45, + -34, + 17, + -26, + 27, + -21, + 46, + 53, + -10, + 29, + -50, + 35, + 15, + -47, + -29, + -41, + 26, + 33, + 55, + -17, + 42, + -26, + -36, + 16, + ] from sage.graphs.generators.families import LCFGraph @@ -1774,7 +2164,110 @@ def BiggsSmithGraph(embedding=1, immutable=False): ... ValueError: the value of embedding must be 1 or 2 """ - L = [16, 24, -38, 17, 34, 48, -19, 41, -35, 47, -20, 34, -36, 21, 14, 48, -16, -36, -43, 28, -17, 21, 29, -43, 46, -24, 28, -38, -14, -50, -45, 21, 8, 27, -21, 20, -37, 39, -34, -44, -8, 38, -21, 25, 15, -34, 18, -28, -41, 36, 8, -29, -21, -48, -28, -20, -47, 14, -8, -15, -27, 38, 24, -48, -18, 25, 38, 31, -25, 24, -46, -14, 28, 11, 21, 35, -39, 43, 36, -38, 14, 50, 43, 36, -11, -36, -24, 45, 8, 19, -25, 38, 20, -24, -14, -21, -8, 44, -31, -38, -28, 37] + L = [ + 16, + 24, + -38, + 17, + 34, + 48, + -19, + 41, + -35, + 47, + -20, + 34, + -36, + 21, + 14, + 48, + -16, + -36, + -43, + 28, + -17, + 21, + 29, + -43, + 46, + -24, + 28, + -38, + -14, + -50, + -45, + 21, + 8, + 27, + -21, + 20, + -37, + 39, + -34, + -44, + -8, + 38, + -21, + 25, + 15, + -34, + 18, + -28, + -41, + 36, + 8, + -29, + -21, + -48, + -28, + -20, + -47, + 14, + -8, + -15, + -27, + 38, + 24, + -48, + -18, + 25, + 38, + 31, + -25, + 24, + -46, + -14, + 28, + 11, + 21, + 35, + -39, + 43, + 36, + -38, + 14, + 50, + 43, + 36, + -11, + -36, + -24, + 45, + 8, + 19, + -25, + 38, + 20, + -24, + -14, + -21, + -8, + 44, + -31, + -38, + -28, + 37, + ] from sage.graphs.generators.families import LCFGraph @@ -1782,7 +2275,14 @@ def BiggsSmithGraph(embedding=1, immutable=False): if embedding == 1: - orbs = [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0], [17, 101, 25, 66, 20, 38, 53, 89, 48, 75, 56, 92, 45, 78, 34, 28, 63], [18, 36, 26, 65, 19, 37, 54, 90, 47, 76, 55, 91, 46, 77, 35, 27, 64], [21, 39, 52, 88, 49, 74, 57, 93, 44, 79, 33, 29, 62, 83, 100, 24, 67], [22, 97, 51, 96, 50, 95, 58, 94, 59, 80, 60, 81, 61, 82, 99, 23, 98], [30, 86, 84, 72, 70, 68, 42, 40, 31, 87, 85, 73, 71, 69, 43, 41, 32]] + orbs = [ + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0], + [17, 101, 25, 66, 20, 38, 53, 89, 48, 75, 56, 92, 45, 78, 34, 28, 63], + [18, 36, 26, 65, 19, 37, 54, 90, 47, 76, 55, 91, 46, 77, 35, 27, 64], + [21, 39, 52, 88, 49, 74, 57, 93, 44, 79, 33, 29, 62, 83, 100, 24, 67], + [22, 97, 51, 96, 50, 95, 58, 94, 59, 80, 60, 81, 61, 82, 99, 23, 98], + [30, 86, 84, 72, 70, 68, 42, 40, 31, 87, 85, 73, 71, 69, 43, 41, 32], + ] # central orbits g._circle_embedding(orbs[1], center=(-0.4, 0), radius=0.2) @@ -2045,7 +2545,89 @@ def BrouwerHaemersGraph(immutable=False): G = G.relabel(inplace=False, immutable=True) else: G.relabel() - ordering = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 48, 49, 50, 51, 52, 53, 45, 46, 47, 30, 31, 32, 33, 34, 35, 27, 28, 29, 39, 40, 41, 42, 43, 44, 36, 37, 38, 69, 70, 71, 63, 64, 65, 66, 67, 68, 78, 79, 80, 72, 73, 74, 75, 76, 77, 60, 61, 62, 54, 55, 56, 57, 58, 59] + ordering = [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 48, + 49, + 50, + 51, + 52, + 53, + 45, + 46, + 47, + 30, + 31, + 32, + 33, + 34, + 35, + 27, + 28, + 29, + 39, + 40, + 41, + 42, + 43, + 44, + 36, + 37, + 38, + 69, + 70, + 71, + 63, + 64, + 65, + 66, + 67, + 68, + 78, + 79, + 80, + 72, + 73, + 74, + 75, + 76, + 77, + 60, + 61, + 62, + 54, + 55, + 56, + 57, + 58, + 59, + ] G._circle_embedding(ordering) return G @@ -2097,7 +2679,98 @@ def BuckyBall(immutable=False): sage: g.is_isomorphic(h) True """ - edges = [(0, 2), (0, 48), (0, 59), (1, 3), (1, 9), (1, 58), (2, 3), (2, 36), (3, 17), (4, 6), (4, 8), (4, 12), (5, 7), (5, 9), (5, 16), (6, 7), (6, 20), (7, 21), (8, 9), (8, 56), (10, 11), (10, 12), (10, 20), (11, 27), (11, 47), (12, 13), (13, 46), (13, 54), (14, 15), (14, 16), (14, 21), (15, 25), (15, 41), (16, 17), (17, 40), (18, 19), (18, 20), (18, 26), (19, 21), (19, 24), (22, 23), (22, 31), (22, 34), (23, 25), (23, 38), (24, 25), (24, 30), (26, 27), (26, 30), (27, 29), (28, 29), (28, 31), (28, 35), (29, 44), (30, 31), (32, 34), (32, 39), (32, 50), (33, 35), (33, 45), (33, 51), (34, 35), (36, 37), (36, 40), (37, 39), (37, 52), (38, 39), (38, 41), (40, 41), (42, 43), (42, 46), (42, 55), (43, 45), (43, 53), (44, 45), (44, 47), (46, 47), (48, 49), (48, 52), (49, 53), (49, 57), (50, 51), (50, 52), (51, 53), (54, 55), (54, 56), (55, 57), (56, 58), (57, 59), (58, 59)] + edges = [ + (0, 2), + (0, 48), + (0, 59), + (1, 3), + (1, 9), + (1, 58), + (2, 3), + (2, 36), + (3, 17), + (4, 6), + (4, 8), + (4, 12), + (5, 7), + (5, 9), + (5, 16), + (6, 7), + (6, 20), + (7, 21), + (8, 9), + (8, 56), + (10, 11), + (10, 12), + (10, 20), + (11, 27), + (11, 47), + (12, 13), + (13, 46), + (13, 54), + (14, 15), + (14, 16), + (14, 21), + (15, 25), + (15, 41), + (16, 17), + (17, 40), + (18, 19), + (18, 20), + (18, 26), + (19, 21), + (19, 24), + (22, 23), + (22, 31), + (22, 34), + (23, 25), + (23, 38), + (24, 25), + (24, 30), + (26, 27), + (26, 30), + (27, 29), + (28, 29), + (28, 31), + (28, 35), + (29, 44), + (30, 31), + (32, 34), + (32, 39), + (32, 50), + (33, 35), + (33, 45), + (33, 51), + (34, 35), + (36, 37), + (36, 40), + (37, 39), + (37, 52), + (38, 39), + (38, 41), + (40, 41), + (42, 43), + (42, 46), + (42, 55), + (43, 45), + (43, 53), + (44, 45), + (44, 47), + (46, 47), + (48, 49), + (48, 52), + (49, 53), + (49, 57), + (50, 51), + (50, 52), + (51, 53), + (54, 55), + (54, 56), + (55, 57), + (56, 58), + (57, 59), + (58, 59), + ] pos = { 0: (1.00000000000000, 0.000000000000000), @@ -2251,7 +2924,38 @@ def DoubleStarSnark(immutable=False): sage: g.is_isomorphic(h) True """ - d = {0: [1, 14, 15], 1: [0, 2, 11], 2: [1, 3, 7], 3: [2, 4, 18], 4: [3, 5, 14], 5: [10, 4, 6], 6: [5, 21, 7], 7: [8, 2, 6], 8: [9, 13, 7], 9: [24, 8, 10], 10: [9, 11, 5], 11: [1, 10, 12], 12: [11, 27, 13], 13: [8, 12, 14], 14: [0, 4, 13], 15: [0, 16, 29], 16: [15, 20, 23], 17: [25, 18, 28], 18: [3, 17, 19], 19: [18, 26, 23], 20: [16, 28, 21], 21: [20, 6, 22], 22: [26, 21, 29], 23: [16, 24, 19], 24: [25, 9, 23], 25: [24, 17, 29], 26: [27, 19, 22], 27: [12, 26, 28], 28: [17, 27, 20], 29: [25, 22, 15]} + d = { + 0: [1, 14, 15], + 1: [0, 2, 11], + 2: [1, 3, 7], + 3: [2, 4, 18], + 4: [3, 5, 14], + 5: [10, 4, 6], + 6: [5, 21, 7], + 7: [8, 2, 6], + 8: [9, 13, 7], + 9: [24, 8, 10], + 10: [9, 11, 5], + 11: [1, 10, 12], + 12: [11, 27, 13], + 13: [8, 12, 14], + 14: [0, 4, 13], + 15: [0, 16, 29], + 16: [15, 20, 23], + 17: [25, 18, 28], + 18: [3, 17, 19], + 19: [18, 26, 23], + 20: [16, 28, 21], + 21: [20, 6, 22], + 22: [26, 21, 29], + 23: [16, 24, 19], + 24: [25, 9, 23], + 25: [24, 17, 29], + 26: [27, 19, 22], + 27: [12, 26, 28], + 28: [17, 27, 20], + 29: [25, 22, 15], + } g = Graph(d, format='dict_of_lists', name="Double star snark", immutable=immutable) g._circle_embedding(list(range(15)), radius=2) @@ -2347,7 +3051,36 @@ def KittellGraph(immutable=False): sage: g.chromatic_number() 4 """ - g = Graph({0: [1, 2, 4, 5, 6, 7], 1: [0, 2, 7, 10, 11, 13], 2: [0, 1, 11, 4, 14], 3: [16, 12, 4, 5, 14], 4: [0, 2, 3, 5, 14], 5: [0, 16, 3, 4, 6], 6: [0, 5, 7, 15, 16, 17, 18], 7: [0, 1, 6, 8, 13, 18], 8: [9, 18, 19, 13, 7], 9: [8, 10, 19, 20, 13], 10: [1, 9, 11, 13, 20, 21], 11: [1, 2, 10, 12, 14, 15, 21], 12: [11, 16, 3, 14, 15], 13: [8, 1, 10, 9, 7], 14: [11, 12, 2, 3, 4], 15: [6, 11, 12, 16, 17, 21, 22], 16: [3, 12, 5, 6, 15], 17: [18, 19, 22, 6, 15], 18: [8, 17, 19, 6, 7], 19: [8, 9, 17, 18, 20, 22], 20: [9, 10, 19, 21, 22], 21: [10, 11, 20, 22, 15], 22: [17, 19, 20, 21, 15]}, format="dict_of_lists", name="Kittell Graph", immutable=immutable) + g = Graph( + { + 0: [1, 2, 4, 5, 6, 7], + 1: [0, 2, 7, 10, 11, 13], + 2: [0, 1, 11, 4, 14], + 3: [16, 12, 4, 5, 14], + 4: [0, 2, 3, 5, 14], + 5: [0, 16, 3, 4, 6], + 6: [0, 5, 7, 15, 16, 17, 18], + 7: [0, 1, 6, 8, 13, 18], + 8: [9, 18, 19, 13, 7], + 9: [8, 10, 19, 20, 13], + 10: [1, 9, 11, 13, 20, 21], + 11: [1, 2, 10, 12, 14, 15, 21], + 12: [11, 16, 3, 14, 15], + 13: [8, 1, 10, 9, 7], + 14: [11, 12, 2, 3, 4], + 15: [6, 11, 12, 16, 17, 21, 22], + 16: [3, 12, 5, 6, 15], + 17: [18, 19, 22, 6, 15], + 18: [8, 17, 19, 6, 7], + 19: [8, 9, 17, 18, 20, 22], + 20: [9, 10, 19, 21, 22], + 21: [10, 11, 20, 22, 15], + 22: [17, 19, 20, 21, 15], + }, + format="dict_of_lists", + name="Kittell Graph", + immutable=immutable, + ) g._circle_embedding(list(range(3)), shift=0.75) g._circle_embedding(list(range(3, 13)), radius=0.4) @@ -3229,7 +3962,54 @@ def EllinghamHorton54Graph(immutable=False): sage: g.show() # long time # needs sage.plot """ - edge_dict = {0: [1, 11, 15], 1: [2, 47], 2: [3, 13], 3: [4, 8], 4: [5, 15], 5: [6, 10], 6: [7, 30], 7: [8, 12], 8: [9], 9: [10, 29], 10: [11], 11: [12], 12: [13], 13: [14], 14: [48, 15], 16: [17, 21, 28], 17: [24, 29], 18: [19, 23, 30], 19: [20, 31], 20: [32, 21], 21: [33], 22: [23, 27, 28], 23: [29], 24: [25, 30], 25: [26, 31], 26: [32, 27], 27: [33], 28: [31], 32: [52], 33: [53], 34: [35, 39, 46], 35: [42, 47], 36: [48, 37, 41], 37: [49, 38], 38: [50, 39], 39: [51], 40: [41, 45, 46], 41: [47], 42: [48, 43], 43: [49, 44], 44: [50, 45], 45: [51], 46: [49], 50: [52], 51: [53], 52: [53]} + edge_dict = { + 0: [1, 11, 15], + 1: [2, 47], + 2: [3, 13], + 3: [4, 8], + 4: [5, 15], + 5: [6, 10], + 6: [7, 30], + 7: [8, 12], + 8: [9], + 9: [10, 29], + 10: [11], + 11: [12], + 12: [13], + 13: [14], + 14: [48, 15], + 16: [17, 21, 28], + 17: [24, 29], + 18: [19, 23, 30], + 19: [20, 31], + 20: [32, 21], + 21: [33], + 22: [23, 27, 28], + 23: [29], + 24: [25, 30], + 25: [26, 31], + 26: [32, 27], + 27: [33], + 28: [31], + 32: [52], + 33: [53], + 34: [35, 39, 46], + 35: [42, 47], + 36: [48, 37, 41], + 37: [49, 38], + 38: [50, 39], + 39: [51], + 40: [41, 45, 46], + 41: [47], + 42: [48, 43], + 43: [49, 44], + 44: [50, 45], + 45: [51], + 46: [49], + 50: [52], + 51: [53], + 52: [53], + } g = Graph(data=edge_dict, format='dict_of_lists', name="Ellingham-Horton 54-graph", immutable=immutable) @@ -3301,7 +4081,82 @@ def EllinghamHorton78Graph(immutable=False): sage: g.show(figsize=[10, 10]) # not tested (too long) """ - g = Graph({0: [1, 5, 60], 1: [2, 12], 2: [3, 7], 3: [4, 14], 4: [5, 9], 5: [6], 6: [7, 11], 7: [15], 8: [9, 13, 22], 9: [10], 10: [11, 72], 11: [12], 12: [13], 13: [14], 14: [72], 15: [16, 20], 16: [17, 27], 17: [18, 22], 18: [19, 29], 19: [20, 24], 20: [21], 21: [22, 26], 23: [24, 28, 72], 24: [25], 25: [26, 71], 26: [27], 27: [28], 28: [29], 29: [69], 30: [31, 35, 52], 31: [32, 42], 32: [33, 37], 33: [34, 43], 34: [35, 39], 35: [36], 36: [41, 63], 37: [65, 66], 38: [39, 59, 74], 39: [40], 40: [41, 44], 41: [42], 42: [74], 43: [44, 74], 44: [45], 45: [46, 50], 46: [47, 57], 47: [48, 52], 48: [49, 75], 49: [50, 54], 50: [51], 51: [52, 56], 53: [54, 58, 73], 54: [55], 55: [56, 59], 56: [57], 57: [58], 58: [75], 59: [75], 60: [61, 64], 61: [62, 71], 62: [63, 77], 63: [67], 64: [65, 69], 65: [77], 66: [70, 73], 67: [68, 73], 68: [69, 76], 70: [71, 76], 76: [77]}, format="dict_of_lists", name="Ellingham-Horton 78-graph", immutable=immutable) + g = Graph( + { + 0: [1, 5, 60], + 1: [2, 12], + 2: [3, 7], + 3: [4, 14], + 4: [5, 9], + 5: [6], + 6: [7, 11], + 7: [15], + 8: [9, 13, 22], + 9: [10], + 10: [11, 72], + 11: [12], + 12: [13], + 13: [14], + 14: [72], + 15: [16, 20], + 16: [17, 27], + 17: [18, 22], + 18: [19, 29], + 19: [20, 24], + 20: [21], + 21: [22, 26], + 23: [24, 28, 72], + 24: [25], + 25: [26, 71], + 26: [27], + 27: [28], + 28: [29], + 29: [69], + 30: [31, 35, 52], + 31: [32, 42], + 32: [33, 37], + 33: [34, 43], + 34: [35, 39], + 35: [36], + 36: [41, 63], + 37: [65, 66], + 38: [39, 59, 74], + 39: [40], + 40: [41, 44], + 41: [42], + 42: [74], + 43: [44, 74], + 44: [45], + 45: [46, 50], + 46: [47, 57], + 47: [48, 52], + 48: [49, 75], + 49: [50, 54], + 50: [51], + 51: [52, 56], + 53: [54, 58, 73], + 54: [55], + 55: [56, 59], + 56: [57], + 57: [58], + 58: [75], + 59: [75], + 60: [61, 64], + 61: [62, 71], + 62: [63, 77], + 63: [67], + 64: [65, 69], + 65: [77], + 66: [70, 73], + 67: [68, 73], + 68: [69, 76], + 70: [71, 76], + 76: [77], + }, + format="dict_of_lists", + name="Ellingham-Horton 78-graph", + immutable=immutable, + ) g._circle_embedding(list(range(15)), center=(-2.5, 1.5)) g._circle_embedding(list(range(15, 30)), center=(-2.5, -1.5)) @@ -3698,7 +4553,18 @@ def GolombGraph(immutable=False): True """ edge_dict = {0: [1, 2, 3], 1: [2, 5], 2: [7], 3: [4, 8, 9], 4: [5, 9], 5: [6, 9], 6: [7, 9], 7: [8, 9], 8: [9]} - pos_dict = {0: [QQ('1/6'), QQ('1/6') * sqrt(11)], 1: [QQ('1/12') * sqrt(33) - QQ('1/12'), -sqrt(QQ('1/72') * sqrt(33) + QQ('7/72'))], 2: [-QQ('1/12') * sqrt(33) - QQ('1/12'), -sqrt(-QQ('1/72') * sqrt(33) + QQ('7/72'))], 3: [1, 0], 4: [QQ('1/2'), -QQ('1/2') * sqrt(3)], 5: [-QQ('1/2'), -QQ('1/2') * sqrt(3)], 6: [-1, 0], 7: [-QQ('1/2'), QQ('1/2') * sqrt(3)], 8: [QQ('1/2'), QQ('1/2') * sqrt(3)], 9: [0, 0]} + pos_dict = { + 0: [QQ('1/6'), QQ('1/6') * sqrt(11)], + 1: [QQ('1/12') * sqrt(33) - QQ('1/12'), -sqrt(QQ('1/72') * sqrt(33) + QQ('7/72'))], + 2: [-QQ('1/12') * sqrt(33) - QQ('1/12'), -sqrt(-QQ('1/72') * sqrt(33) + QQ('7/72'))], + 3: [1, 0], + 4: [QQ('1/2'), -QQ('1/2') * sqrt(3)], + 5: [-QQ('1/2'), -QQ('1/2') * sqrt(3)], + 6: [-1, 0], + 7: [-QQ('1/2'), QQ('1/2') * sqrt(3)], + 8: [QQ('1/2'), QQ('1/2') * sqrt(3)], + 9: [0, 0], + } return Graph(edge_dict, format="dict_of_lists", pos=pos_dict, name="Golomb graph", immutable=immutable) @@ -4149,7 +5015,60 @@ def HoffmanSingletonGraph(immutable=False): sage: HS.layout()[1] # random (-0.904..., 0.425...) """ - H = Graph({'q00': ['q01'], 'q01': ['q02'], 'q02': ['q03'], 'q03': ['q04'], 'q04': ['q00'], 'q10': ['q11'], 'q11': ['q12'], 'q12': ['q13'], 'q13': ['q14'], 'q14': ['q10'], 'q20': ['q21'], 'q21': ['q22'], 'q22': ['q23'], 'q23': ['q24'], 'q24': ['q20'], 'q30': ['q31'], 'q31': ['q32'], 'q32': ['q33'], 'q33': ['q34'], 'q34': ['q30'], 'q40': ['q41'], 'q41': ['q42'], 'q42': ['q43'], 'q43': ['q44'], 'q44': ['q40'], 'p00': ['p02'], 'p02': ['p04'], 'p04': ['p01'], 'p01': ['p03'], 'p03': ['p00'], 'p10': ['p12'], 'p12': ['p14'], 'p14': ['p11'], 'p11': ['p13'], 'p13': ['p10'], 'p20': ['p22'], 'p22': ['p24'], 'p24': ['p21'], 'p21': ['p23'], 'p23': ['p20'], 'p30': ['p32'], 'p32': ['p34'], 'p34': ['p31'], 'p31': ['p33'], 'p33': ['p30'], 'p40': ['p42'], 'p42': ['p44'], 'p44': ['p41'], 'p41': ['p43'], 'p43': ['p40']}) + H = Graph( + { + 'q00': ['q01'], + 'q01': ['q02'], + 'q02': ['q03'], + 'q03': ['q04'], + 'q04': ['q00'], + 'q10': ['q11'], + 'q11': ['q12'], + 'q12': ['q13'], + 'q13': ['q14'], + 'q14': ['q10'], + 'q20': ['q21'], + 'q21': ['q22'], + 'q22': ['q23'], + 'q23': ['q24'], + 'q24': ['q20'], + 'q30': ['q31'], + 'q31': ['q32'], + 'q32': ['q33'], + 'q33': ['q34'], + 'q34': ['q30'], + 'q40': ['q41'], + 'q41': ['q42'], + 'q42': ['q43'], + 'q43': ['q44'], + 'q44': ['q40'], + 'p00': ['p02'], + 'p02': ['p04'], + 'p04': ['p01'], + 'p01': ['p03'], + 'p03': ['p00'], + 'p10': ['p12'], + 'p12': ['p14'], + 'p14': ['p11'], + 'p11': ['p13'], + 'p13': ['p10'], + 'p20': ['p22'], + 'p22': ['p24'], + 'p24': ['p21'], + 'p21': ['p23'], + 'p23': ['p20'], + 'p30': ['p32'], + 'p32': ['p34'], + 'p34': ['p31'], + 'p31': ['p33'], + 'p33': ['p30'], + 'p40': ['p42'], + 'p42': ['p44'], + 'p44': ['p41'], + 'p41': ['p43'], + 'p43': ['p40'], + } + ) for j in range(5): for i in range(5): for k in range(5): @@ -4468,7 +5387,22 @@ def LjubljanaGraph(embedding=1, immutable=False): # Correspondence between the vertices of the Heawood Graph and 8-sets of # the Ljubljana Graph. - d = {0: [1, 21, 39, 57, 51, 77, 95, 107], 1: [2, 22, 38, 58, 50, 78, 94, 106], 2: [3, 23, 37, 59, 49, 79, 93, 105], 3: [4, 24, 36, 60, 48, 80, 92, 104], 4: [5, 25, 35, 61, 15, 81, 91, 71], 9: [6, 26, 44, 62, 16, 82, 100, 72], 10: [7, 27, 45, 63, 17, 83, 101, 73], 11: [8, 28, 46, 64, 18, 84, 102, 74], 12: [9, 29, 47, 65, 19, 85, 103, 75], 13: [10, 30, 0, 66, 20, 86, 56, 76], 8: [11, 31, 111, 67, 99, 87, 55, 43], 7: [12, 32, 110, 68, 98, 88, 54, 42], 6: [13, 33, 109, 69, 97, 89, 53, 41], 5: [14, 34, 108, 70, 96, 90, 52, 40]} + d = { + 0: [1, 21, 39, 57, 51, 77, 95, 107], + 1: [2, 22, 38, 58, 50, 78, 94, 106], + 2: [3, 23, 37, 59, 49, 79, 93, 105], + 3: [4, 24, 36, 60, 48, 80, 92, 104], + 4: [5, 25, 35, 61, 15, 81, 91, 71], + 9: [6, 26, 44, 62, 16, 82, 100, 72], + 10: [7, 27, 45, 63, 17, 83, 101, 73], + 11: [8, 28, 46, 64, 18, 84, 102, 74], + 12: [9, 29, 47, 65, 19, 85, 103, 75], + 13: [10, 30, 0, 66, 20, 86, 56, 76], + 8: [11, 31, 111, 67, 99, 87, 55, 43], + 7: [12, 32, 110, 68, 98, 88, 54, 42], + 6: [13, 33, 109, 69, 97, 89, 53, 41], + 5: [14, 34, 108, 70, 96, 90, 52, 40], + } # The vertices of each 8-set are plotted on a circle, and the # circles are slowly shifted to obtain a symmetric drawing. @@ -4814,7 +5748,15 @@ def MoserSpindle(immutable=False): True """ edge_dict = {0: [1, 4, 6], 1: [2, 5], 2: [3, 5], 3: [4, 5, 6], 4: [6]} - pos_dict = {0: [QQ('1/2'), 0], 1: [-QQ('1/2'), 0], 2: [-QQ('1/12') * sqrt(33) - QQ('1/4'), QQ('1/2') * sqrt(QQ('1/6') * sqrt(33) + QQ('17/6'))], 3: [0, QQ('1/2') * sqrt(11)], 4: [QQ('1/12') * sqrt(33) + QQ('1/4'), QQ('1/2') * sqrt(QQ('1/6') * sqrt(33) + QQ('17/6'))], 5: [QQ('1/12') * sqrt(33) - QQ('1/4'), QQ('1/2') * sqrt(-QQ('1/6') * sqrt(33) + QQ('17/6'))], 6: [-QQ('1/12') * sqrt(33) + QQ('1/4'), QQ('1/2') * sqrt(-QQ('1/6') * sqrt(33) + QQ('17/6'))]} + pos_dict = { + 0: [QQ('1/2'), 0], + 1: [-QQ('1/2'), 0], + 2: [-QQ('1/12') * sqrt(33) - QQ('1/4'), QQ('1/2') * sqrt(QQ('1/6') * sqrt(33) + QQ('17/6'))], + 3: [0, QQ('1/2') * sqrt(11)], + 4: [QQ('1/12') * sqrt(33) + QQ('1/4'), QQ('1/2') * sqrt(QQ('1/6') * sqrt(33) + QQ('17/6'))], + 5: [QQ('1/12') * sqrt(33) - QQ('1/4'), QQ('1/2') * sqrt(-QQ('1/6') * sqrt(33) + QQ('17/6'))], + 6: [-QQ('1/12') * sqrt(33) + QQ('1/4'), QQ('1/2') * sqrt(-QQ('1/6') * sqrt(33) + QQ('17/6'))], + } return Graph(edge_dict, format="dict_of_lists", pos=pos_dict, name="Moser spindle", immutable=immutable) @@ -5230,7 +6172,24 @@ def ShrikhandeGraph(immutable=False): for i in range(8): pos_dict[i] = [float(cos((2 * i) * pi / 8)), float(sin((2 * i) * pi / 8))] pos_dict[8 + i] = [0.5 * pos_dict[i][0], 0.5 * pos_dict[i][1]] - edge_dict = {0o00: [0o06, 0o07, 0o01, 0o02, 0o11, 0o17], 0o01: [0o07, 0o00, 0o02, 0o03, 0o12, 0o10], 0o02: [0o00, 0o01, 0o03, 0o04, 0o13, 0o11], 0o03: [0o01, 0o02, 0o04, 0o05, 0o14, 0o12], 0o04: [0o02, 0o03, 0o05, 0o06, 0o15, 0o13], 0o05: [0o03, 0o04, 0o06, 0o07, 0o16, 0o14], 0o06: [0o04, 0o05, 0o07, 0o00, 0o17, 0o15], 0o07: [0o05, 0o06, 0o00, 0o01, 0o10, 0o16], 0o10: [0o12, 0o13, 0o15, 0o16, 0o07, 0o01], 0o11: [0o13, 0o14, 0o16, 0o17, 0o00, 0o02], 0o12: [0o14, 0o15, 0o17, 0o10, 0o01, 0o03], 0o13: [0o15, 0o16, 0o10, 0o11, 0o02, 0o04], 0o14: [0o16, 0o17, 0o11, 0o12, 0o03, 0o05], 0o15: [0o17, 0o10, 0o12, 0o13, 0o04, 0o06], 0o16: [0o10, 0o11, 0o13, 0o14, 0o05, 0o07], 0o17: [0o11, 0o12, 0o14, 0o15, 0o06, 0o00]} + edge_dict = { + 0o00: [0o06, 0o07, 0o01, 0o02, 0o11, 0o17], + 0o01: [0o07, 0o00, 0o02, 0o03, 0o12, 0o10], + 0o02: [0o00, 0o01, 0o03, 0o04, 0o13, 0o11], + 0o03: [0o01, 0o02, 0o04, 0o05, 0o14, 0o12], + 0o04: [0o02, 0o03, 0o05, 0o06, 0o15, 0o13], + 0o05: [0o03, 0o04, 0o06, 0o07, 0o16, 0o14], + 0o06: [0o04, 0o05, 0o07, 0o00, 0o17, 0o15], + 0o07: [0o05, 0o06, 0o00, 0o01, 0o10, 0o16], + 0o10: [0o12, 0o13, 0o15, 0o16, 0o07, 0o01], + 0o11: [0o13, 0o14, 0o16, 0o17, 0o00, 0o02], + 0o12: [0o14, 0o15, 0o17, 0o10, 0o01, 0o03], + 0o13: [0o15, 0o16, 0o10, 0o11, 0o02, 0o04], + 0o14: [0o16, 0o17, 0o11, 0o12, 0o03, 0o05], + 0o15: [0o17, 0o10, 0o12, 0o13, 0o04, 0o06], + 0o16: [0o10, 0o11, 0o13, 0o14, 0o05, 0o07], + 0o17: [0o11, 0o12, 0o14, 0o15, 0o06, 0o00], + } return Graph(edge_dict, format="dict_of_lists", pos=pos_dict, name="Shrikhande graph", immutable=immutable) @@ -6262,8 +7221,316 @@ def JankoKharaghaniTonchevGraph(immutable=False): k = prod(prod(map(P, [(18 * x + 1, 18 * x + 10), (18 * x + 2, 18 * x + 11), (18 * x + 3, 18 * x + 12), (18 * x + 4, 18 * x + 13), (18 * x + 5, 18 * x + 14), (18 * x + 6, 18 * x + 15), (18 * x + 7, 18 * x + 16), (18 * x + 8, 18 * x + 17), (18 * x + 9, 18 * x + 18)])) for x in range(18)) G = libgap.Group([libgap.PermList(p) for p in [m1, m2, t, n1, n2, s, k]]) st = libgap.Group([libgap.PermList(p) for p in [t, s]]) - B1 = (19, 22, 25, 29, 30, 31, 33, 34, 35, 37, 40, 43, 47, 48, 49, 51, 52, 53, 55, 56, 57, 65, 66, 67, 68, 70, 72, 76, 77, 78, 79, 80, 81, 82, 86, 90, 92, 93, 95, 96, 98, 99, 100, 105, 107, 109, 110, 111, 119, 120, 121, 122, 124, 126, 128, 129, 131, 132, 134, 135, 136, 141, 143, 148, 149, 150, 151, 152, 153, 154, 158, 162, 167, 168, 170, 171, 172, 176, 177, 179, 180, 184, 186, 187, 188, 190, 191, 192, 193, 196, 202, 204, 205, 206, 208, 209, 210, 211, 214, 218, 219, 221, 225, 226, 227, 228, 229, 232, 236, 237, 238, 241, 244, 245, 246, 249, 251, 254, 255, 256, 259, 262, 265, 266, 268, 270, 272, 273, 275, 279, 280, 281, 282, 283, 286, 290, 291, 292, 295, 298, 301, 302, 304, 306, 308, 309, 310, 313, 316, 317, 318, 321, 323) - B163 = (5, 6, 8, 9, 10, 14, 15, 17, 18, 22, 24, 25, 26, 28, 29, 30, 31, 34, 40, 42, 43, 44, 46, 47, 48, 49, 52, 56, 57, 59, 63, 64, 65, 66, 67, 70, 74, 75, 76, 79, 82, 83, 84, 87, 89, 92, 93, 94, 97, 100, 103, 104, 106, 108, 110, 111, 113, 117, 118, 119, 120, 121, 124, 128, 129, 130, 133, 136, 139, 140, 142, 144, 146, 147, 148, 151, 154, 155, 156, 159, 161, 181, 185, 189, 191, 192, 194, 195, 197, 198, 199, 203, 207, 209, 210, 212, 213, 215, 216, 217, 222, 224, 229, 230, 231, 232, 233, 234, 236, 237, 238, 240, 241, 242, 244, 245, 246, 254, 255, 256, 257, 259, 261, 262, 265, 268, 271, 276, 278, 283, 284, 285, 286, 287, 288, 290, 291, 292, 293, 295, 297, 298, 301, 304, 308, 309, 310, 312, 313, 314, 316, 317, 318) + B1 = ( + 19, + 22, + 25, + 29, + 30, + 31, + 33, + 34, + 35, + 37, + 40, + 43, + 47, + 48, + 49, + 51, + 52, + 53, + 55, + 56, + 57, + 65, + 66, + 67, + 68, + 70, + 72, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 86, + 90, + 92, + 93, + 95, + 96, + 98, + 99, + 100, + 105, + 107, + 109, + 110, + 111, + 119, + 120, + 121, + 122, + 124, + 126, + 128, + 129, + 131, + 132, + 134, + 135, + 136, + 141, + 143, + 148, + 149, + 150, + 151, + 152, + 153, + 154, + 158, + 162, + 167, + 168, + 170, + 171, + 172, + 176, + 177, + 179, + 180, + 184, + 186, + 187, + 188, + 190, + 191, + 192, + 193, + 196, + 202, + 204, + 205, + 206, + 208, + 209, + 210, + 211, + 214, + 218, + 219, + 221, + 225, + 226, + 227, + 228, + 229, + 232, + 236, + 237, + 238, + 241, + 244, + 245, + 246, + 249, + 251, + 254, + 255, + 256, + 259, + 262, + 265, + 266, + 268, + 270, + 272, + 273, + 275, + 279, + 280, + 281, + 282, + 283, + 286, + 290, + 291, + 292, + 295, + 298, + 301, + 302, + 304, + 306, + 308, + 309, + 310, + 313, + 316, + 317, + 318, + 321, + 323, + ) + B163 = ( + 5, + 6, + 8, + 9, + 10, + 14, + 15, + 17, + 18, + 22, + 24, + 25, + 26, + 28, + 29, + 30, + 31, + 34, + 40, + 42, + 43, + 44, + 46, + 47, + 48, + 49, + 52, + 56, + 57, + 59, + 63, + 64, + 65, + 66, + 67, + 70, + 74, + 75, + 76, + 79, + 82, + 83, + 84, + 87, + 89, + 92, + 93, + 94, + 97, + 100, + 103, + 104, + 106, + 108, + 110, + 111, + 113, + 117, + 118, + 119, + 120, + 121, + 124, + 128, + 129, + 130, + 133, + 136, + 139, + 140, + 142, + 144, + 146, + 147, + 148, + 151, + 154, + 155, + 156, + 159, + 161, + 181, + 185, + 189, + 191, + 192, + 194, + 195, + 197, + 198, + 199, + 203, + 207, + 209, + 210, + 212, + 213, + 215, + 216, + 217, + 222, + 224, + 229, + 230, + 231, + 232, + 233, + 234, + 236, + 237, + 238, + 240, + 241, + 242, + 244, + 245, + 246, + 254, + 255, + 256, + 257, + 259, + 261, + 262, + 265, + 268, + 271, + 276, + 278, + 283, + 284, + 285, + 286, + 287, + 288, + 290, + 291, + 292, + 293, + 295, + 297, + 298, + 301, + 304, + 308, + 309, + 310, + 312, + 313, + 314, + 316, + 317, + 318, + ) Gamma = Graph(multiedges=False, name='Janko-Kharaghani-Tonchev') for i, b in ((1, B1), (163, B163)): for x in st.OrbitsDomain(b): diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 22e0f7d96e7..30ef58a5b93 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -8837,7 +8837,12 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm='MILP', # # - Both s and t are specified, but there is no path between # the two in a directed graph (the graph is connected). - if self.order() <= 1 or (s is not None and ((s not in self) or (self._directed and not self.out_degree(s)) or (not self._directed and not self.degree(s)))) or (t is not None and ((t not in self) or (self._directed and not self.in_degree(t)) or (not self._directed and not self.degree(t)))) or (self._directed and (s is not None) and (t is not None) and not self.shortest_path(s, t)): + if ( + self.order() <= 1 + or (s is not None and ((s not in self) or (self._directed and not self.out_degree(s)) or (not self._directed and not self.degree(s)))) + or (t is not None and ((t not in self) or (self._directed and not self.in_degree(t)) or (not self._directed and not self.degree(t)))) + or (self._directed and (s is not None) and (t is not None) and not self.shortest_path(s, t)) + ): if self._directed: from sage.graphs.digraph import DiGraph as MyGraph else: diff --git a/src/sage/graphs/graph_database.py b/src/sage/graphs/graph_database.py index 66f2e86d7e1..ee4d60bed2d 100644 --- a/src/sage/graphs/graph_database.py +++ b/src/sage/graphs/graph_database.py @@ -177,9 +177,33 @@ def subgraphs_to_query(subgraphs, db): # ----------------------------------------------------------------------------- aut_grp = ['aut_grp_size', 'num_orbits', 'num_fixed_points', 'vertex_transitive', 'edge_transitive'] # Integer INTEGER # Integer INTEGER # Integer INTEGER # bool BOOLEAN # bool BOOLEAN degrees = ['degree_sequence', 'min_degree', 'max_degree', 'average_degree', 'degrees_sd', 'regular'] # list INTEGER (see degseq_to_data module function) # Integer INTEGER # Integer INTEGER # Real REAL # Real REAL # bool BOOLEAN -misc = ['vertex_connectivity', 'edge_connectivity', 'num_components', 'girth', 'radius', 'diameter', 'clique_number', 'independence_number', 'num_cut_vertices', 'min_vertex_cover_size', 'num_spanning_trees', 'induced_subgraphs'] # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # String STRING +misc = [ + 'vertex_connectivity', + 'edge_connectivity', + 'num_components', + 'girth', + 'radius', + 'diameter', + 'clique_number', + 'independence_number', + 'num_cut_vertices', + 'min_vertex_cover_size', + 'num_spanning_trees', + 'induced_subgraphs', +] # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # String STRING spectrum = ['spectrum', 'min_eigenvalue', 'max_eigenvalue', 'eigenvalues_sd', 'energy'] # String STRING # Real REAL # Real REAL # Real REAL # Real REAL -graph_data = ['complement_graph6', 'eulerian', 'graph6', 'lovasz_number', 'num_cycles', 'num_edges', 'num_hamiltonian_cycles', 'num_vertices', 'perfect', 'planar'] # String STRING # bool BOOLEAN # String STRING # Real REAL # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # bool BOOLEAN # bool BOOLEAN +graph_data = [ + 'complement_graph6', + 'eulerian', + 'graph6', + 'lovasz_number', + 'num_cycles', + 'num_edges', + 'num_hamiltonian_cycles', + 'num_vertices', + 'perfect', + 'planar', +] # String STRING # bool BOOLEAN # String STRING # Real REAL # Integer INTEGER # Integer INTEGER # Integer INTEGER # Integer INTEGER # bool BOOLEAN # bool BOOLEAN valid_kwds = aut_grp + degrees + misc + spectrum + graph_data diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 9b0ad6471b0..725d083932a 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -55,7 +55,37 @@ def wrap_name(x): **Basic structures** """ -__append_to_doc(["BullGraph", "ButterflyGraph", "CircularLadderGraph", "ClawGraph", "CycleGraph", "CompleteBipartiteGraph", "CompleteGraph", "CompleteMultipartiteGraph", "CorrelationGraph", "DiamondGraph", "GemGraph", "DartGraph", "ForkGraph", "DipoleGraph", "EmptyGraph", "Grid2dGraph", "GridGraph", "HouseGraph", "HouseXGraph", "LadderGraph", "LollipopGraph", "MoebiusLadderGraph", "PathGraph", "StarGraph", "TadpoleGraph", "ToroidalGrid2dGraph", "Toroidal6RegularGrid2dGraph"]) +__append_to_doc( + [ + "BullGraph", + "ButterflyGraph", + "CircularLadderGraph", + "ClawGraph", + "CycleGraph", + "CompleteBipartiteGraph", + "CompleteGraph", + "CompleteMultipartiteGraph", + "CorrelationGraph", + "DiamondGraph", + "GemGraph", + "DartGraph", + "ForkGraph", + "DipoleGraph", + "EmptyGraph", + "Grid2dGraph", + "GridGraph", + "HouseGraph", + "HouseXGraph", + "LadderGraph", + "LollipopGraph", + "MoebiusLadderGraph", + "PathGraph", + "StarGraph", + "TadpoleGraph", + "ToroidalGrid2dGraph", + "Toroidal6RegularGrid2dGraph", + ] +) __doc__ += """ **Small Graphs** @@ -276,7 +306,26 @@ def wrap_name(x): quadrics and Hermitean varieties there. """ -__append_to_doc(["AffineOrthogonalPolarGraph", "AhrensSzekeresGeneralizedQuadrangleGraph", "NonisotropicOrthogonalPolarGraph", "NonisotropicUnitaryPolarGraph", "OrthogonalDualPolarGraph", "OrthogonalPolarGraph", "SymplecticDualPolarGraph", "SymplecticPolarGraph", "TaylorTwographDescendantSRG", "TaylorTwographSRG", "T2starGeneralizedQuadrangleGraph", "Nowhere0WordsTwoWeightCodeGraph", "HaemersGraph", "CossidentePenttilaGraph", "UnitaryDualPolarGraph", "UnitaryPolarGraph"]) +__append_to_doc( + [ + "AffineOrthogonalPolarGraph", + "AhrensSzekeresGeneralizedQuadrangleGraph", + "NonisotropicOrthogonalPolarGraph", + "NonisotropicUnitaryPolarGraph", + "OrthogonalDualPolarGraph", + "OrthogonalPolarGraph", + "SymplecticDualPolarGraph", + "SymplecticPolarGraph", + "TaylorTwographDescendantSRG", + "TaylorTwographSRG", + "T2starGeneralizedQuadrangleGraph", + "Nowhere0WordsTwoWeightCodeGraph", + "HaemersGraph", + "CossidentePenttilaGraph", + "UnitaryDualPolarGraph", + "UnitaryPolarGraph", + ] +) __doc__ += """ **Chessboard Graphs** @@ -298,7 +347,30 @@ def wrap_name(x): **Random graphs** """ -__append_to_doc(["RandomBarabasiAlbert", "RandomBicubicPlanar", "RandomBipartite", "RandomRegularBipartite", "RandomBlockGraph", "RandomBoundedToleranceGraph", "RandomChordalGraph", "RandomGNM", "RandomGNP", "RandomHolmeKim", "RandomIntervalGraph", "RandomKTree", "RandomPartialKTree", "RandomNewmanWattsStrogatz", "RandomProperIntervalGraph", "RandomRegular", "RandomShell", "RandomToleranceGraph", "RandomTriangulation", "RandomUnitDiskGraph"]) +__append_to_doc( + [ + "RandomBarabasiAlbert", + "RandomBicubicPlanar", + "RandomBipartite", + "RandomRegularBipartite", + "RandomBlockGraph", + "RandomBoundedToleranceGraph", + "RandomChordalGraph", + "RandomGNM", + "RandomGNP", + "RandomHolmeKim", + "RandomIntervalGraph", + "RandomKTree", + "RandomPartialKTree", + "RandomNewmanWattsStrogatz", + "RandomProperIntervalGraph", + "RandomRegular", + "RandomShell", + "RandomToleranceGraph", + "RandomTriangulation", + "RandomUnitDiskGraph", + ] +) __doc__ += """ **Trees** diff --git a/src/sage/graphs/graph_plot.py b/src/sage/graphs/graph_plot.py index 2bac5fc0658..1333898ca61 100644 --- a/src/sage/graphs/graph_plot.py +++ b/src/sage/graphs/graph_plot.py @@ -134,7 +134,12 @@ layout_options = { - 'layout': 'A layout algorithm -- one of : "acyclic", "circular" (plots the ' 'graph with vertices evenly distributed on a circle), "ranked", ' '"graphviz", "planar", "spring" (traditional spring layout, using ' 'the graph\'s current positions as initial positions), or "tree" ' '(the tree will be plotted in levels, depending on minimum distance ' 'for the root).', + 'layout': 'A layout algorithm -- one of : "acyclic", "circular" (plots the ' + 'graph with vertices evenly distributed on a circle), "ranked", ' + '"graphviz", "planar", "spring" (traditional spring layout, using ' + 'the graph\'s current positions as initial positions), or "tree" ' + '(the tree will be plotted in levels, depending on minimum distance ' + 'for the root).', 'iterations': 'The number of times to execute the spring layout algorithm.', 'heights': 'A dictionary mapping heights to the list of vertices at this height.', 'spring': 'Use spring layout to finalize the current layout.', @@ -189,7 +194,31 @@ DEFAULT_SHOW_OPTIONS = {'figsize': (4, 4)} -DEFAULT_PLOT_OPTIONS = {'vertex_size': 200, 'vertex_labels': True, 'vertex_label_shift': None, 'layout': None, 'edge_style': 'solid', 'edge_styles': None, 'edge_thickness': 1, 'edge_thicknesses': None, 'edge_color': 'black', 'edge_colors': None, 'edge_labels': False, 'iterations': 50, 'tree_orientation': 'down', 'heights': None, 'graph_border': False, 'talk': False, 'color_by_label': False, 'partition': None, 'dist': 0.075, 'max_dist': 1.5, 'label_fontsize': 10, 'loop_size': 0.075, 'edge_labels_background': 'white'} +DEFAULT_PLOT_OPTIONS = { + 'vertex_size': 200, + 'vertex_labels': True, + 'vertex_label_shift': None, + 'layout': None, + 'edge_style': 'solid', + 'edge_styles': None, + 'edge_thickness': 1, + 'edge_thicknesses': None, + 'edge_color': 'black', + 'edge_colors': None, + 'edge_labels': False, + 'iterations': 50, + 'tree_orientation': 'down', + 'heights': None, + 'graph_border': False, + 'talk': False, + 'color_by_label': False, + 'partition': None, + 'dist': 0.075, + 'max_dist': 1.5, + 'label_fontsize': 10, + 'loop_size': 0.075, + 'edge_labels_background': 'white', +} class GraphPlot(SageObject): diff --git a/src/sage/graphs/graph_plot_js.py b/src/sage/graphs/graph_plot_js.py index e4d26410f2b..899148d3491 100644 --- a/src/sage/graphs/graph_plot_js.py +++ b/src/sage/graphs/graph_plot_js.py @@ -286,7 +286,23 @@ def gen_html_code(G, vertex_labels=True, edge_labels=False, vertex_partition=[], # Encodes the data as a JSON string from json import JSONEncoder - string = JSONEncoder().encode({"nodes": nodes, "links": edges, "loops": loops, "pos": pos, "directed": G.is_directed(), "charge": int(charge), "link_distance": int(link_distance), "link_strength": int(link_strength), "gravity": float(gravity), "vertex_labels": bool(vertex_labels), "edge_labels": bool(edge_labels), "vertex_size": int(vertex_size), "edge_thickness": int(edge_thickness)}) + string = JSONEncoder().encode( + { + "nodes": nodes, + "links": edges, + "loops": loops, + "pos": pos, + "directed": G.is_directed(), + "charge": int(charge), + "link_distance": int(link_distance), + "link_strength": int(link_strength), + "gravity": float(gravity), + "vertex_labels": bool(vertex_labels), + "edge_labels": bool(edge_labels), + "vertex_size": int(vertex_size), + "edge_thickness": int(edge_thickness), + } + ) from sage.env import SAGE_EXTCODE, sage_data_paths diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index fae16c583b7..90ab5b0bd6a 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -96,7 +96,11 @@ from sage.structure.element import Expression from sage.structure.richcmp import rich_to_bool, richcmp -lazy_import('sage.libs.braiding', ['leftnormalform', 'rightnormalform', 'centralizer', 'supersummitset', 'greatestcommondivisor', 'leastcommonmultiple', 'conjugatingbraid', 'ultrasummitset', 'thurston_type', 'rigidity', 'sliding_circuits', 'send_to_sss', 'send_to_uss', 'send_to_sc', 'trajectory', 'cyclic_slidings'], feature=sage__libs__braiding()) +lazy_import( + 'sage.libs.braiding', + ['leftnormalform', 'rightnormalform', 'centralizer', 'supersummitset', 'greatestcommondivisor', 'leastcommonmultiple', 'conjugatingbraid', 'ultrasummitset', 'thurston_type', 'rigidity', 'sliding_circuits', 'send_to_sss', 'send_to_uss', 'send_to_sc', 'trajectory', 'cyclic_slidings'], + feature=sage__libs__braiding(), +) lazy_import('sage.knots.knot', 'Knot') @@ -591,16 +595,74 @@ def plot(self, color='rainbow', orientation='bottom-top', gap=0.05, aspect_ratio for i, m in enumerate(braid): for j in range(n): if m == j + 1: - a += bezier_path([[(j * nx + i * orx, i * ory + j * ny), (j * nx + orx * (i + 0.25), j * ny + ory * (i + 0.25)), (nx * (j + 0.5) + orx * (i + 0.5), ny * (j + 0.5) + ory * (i + 0.5))], [(nx * (j + 1) + orx * (i + 0.75), ny * (j + 1) + ory * (i + 0.75)), (nx * (j + 1) + orx * (i + 1), ny * (j + 1) + ory * (i + 1))]], color=col[j], **kwds) + a += bezier_path( + [ + [(j * nx + i * orx, i * ory + j * ny), (j * nx + orx * (i + 0.25), j * ny + ory * (i + 0.25)), (nx * (j + 0.5) + orx * (i + 0.5), ny * (j + 0.5) + ory * (i + 0.5))], + [(nx * (j + 1) + orx * (i + 0.75), ny * (j + 1) + ory * (i + 0.75)), (nx * (j + 1) + orx * (i + 1), ny * (j + 1) + ory * (i + 1))], + ], + color=col[j], + **kwds, + ) elif m == j: - a += bezier_path([[(nx * j + orx * i, ny * j + ory * i), (nx * j + orx * (i + 0.25), ny * j + ory * (i + 0.25)), (nx * (j - 0.5 + 4 * op) + orx * (i + 0.5 - 2 * op), ny * (j - 0.5 + 4 * op) + ory * (i + 0.5 - 2 * op)), (nx * (j - 0.5 + 2 * op) + orx * (i + 0.5 - op), ny * (j - 0.5 + 2 * op) + ory * (i + 0.5 - op))]], color=col[j], **kwds) - a += bezier_path([[(nx * (j - 0.5 - 2 * op) + orx * (i + 0.5 + op), ny * (j - 0.5 - 2 * op) + ory * (i + 0.5 + op)), (nx * (j - 0.5 - 4 * op) + orx * (i + 0.5 + 2 * op), ny * (j - 0.5 - 4 * op) + ory * (i + 0.5 + 2 * op)), (nx * (j - 1) + orx * (i + 0.75), ny * (j - 1) + ory * (i + 0.75)), (nx * (j - 1) + orx * (i + 1), ny * (j - 1) + ory * (i + 1))]], color=col[j], **kwds) + a += bezier_path( + [ + [ + (nx * j + orx * i, ny * j + ory * i), + (nx * j + orx * (i + 0.25), ny * j + ory * (i + 0.25)), + (nx * (j - 0.5 + 4 * op) + orx * (i + 0.5 - 2 * op), ny * (j - 0.5 + 4 * op) + ory * (i + 0.5 - 2 * op)), + (nx * (j - 0.5 + 2 * op) + orx * (i + 0.5 - op), ny * (j - 0.5 + 2 * op) + ory * (i + 0.5 - op)), + ] + ], + color=col[j], + **kwds, + ) + a += bezier_path( + [ + [ + (nx * (j - 0.5 - 2 * op) + orx * (i + 0.5 + op), ny * (j - 0.5 - 2 * op) + ory * (i + 0.5 + op)), + (nx * (j - 0.5 - 4 * op) + orx * (i + 0.5 + 2 * op), ny * (j - 0.5 - 4 * op) + ory * (i + 0.5 + 2 * op)), + (nx * (j - 1) + orx * (i + 0.75), ny * (j - 1) + ory * (i + 0.75)), + (nx * (j - 1) + orx * (i + 1), ny * (j - 1) + ory * (i + 1)), + ] + ], + color=col[j], + **kwds, + ) col[j], col[j - 1] = col[j - 1], col[j] elif -m == j + 1: - a += bezier_path([[(nx * j + orx * i, ny * j + ory * i), (nx * j + orx * (i + 0.25), ny * j + ory * (i + 0.25)), (nx * (j + 0.5 - 4 * op) + orx * (i + 0.5 - 2 * op), ny * (j + 0.5 - 4 * op) + ory * (i + 0.5 - 2 * op)), (nx * (j + 0.5 - 2 * op) + orx * (i + 0.5 - op), ny * (j + 0.5 - 2 * op) + ory * (i + 0.5 - op))]], color=col[j], **kwds) - a += bezier_path([[(nx * (j + 0.5 + 2 * op) + orx * (i + 0.5 + op), ny * (j + 0.5 + 2 * op) + ory * (i + 0.5 + op)), (nx * (j + 0.5 + 4 * op) + orx * (i + 0.5 + 2 * op), ny * (j + 0.5 + 4 * op) + ory * (i + 0.5 + 2 * op)), (nx * (j + 1) + orx * (i + 0.75), ny * (j + 1) + ory * (i + 0.75)), (nx * (j + 1) + orx * (i + 1), ny * (j + 1) + ory * (i + 1))]], color=col[j], **kwds) + a += bezier_path( + [ + [ + (nx * j + orx * i, ny * j + ory * i), + (nx * j + orx * (i + 0.25), ny * j + ory * (i + 0.25)), + (nx * (j + 0.5 - 4 * op) + orx * (i + 0.5 - 2 * op), ny * (j + 0.5 - 4 * op) + ory * (i + 0.5 - 2 * op)), + (nx * (j + 0.5 - 2 * op) + orx * (i + 0.5 - op), ny * (j + 0.5 - 2 * op) + ory * (i + 0.5 - op)), + ] + ], + color=col[j], + **kwds, + ) + a += bezier_path( + [ + [ + (nx * (j + 0.5 + 2 * op) + orx * (i + 0.5 + op), ny * (j + 0.5 + 2 * op) + ory * (i + 0.5 + op)), + (nx * (j + 0.5 + 4 * op) + orx * (i + 0.5 + 2 * op), ny * (j + 0.5 + 4 * op) + ory * (i + 0.5 + 2 * op)), + (nx * (j + 1) + orx * (i + 0.75), ny * (j + 1) + ory * (i + 0.75)), + (nx * (j + 1) + orx * (i + 1), ny * (j + 1) + ory * (i + 1)), + ] + ], + color=col[j], + **kwds, + ) elif -m == j: - a += bezier_path([[(nx * j + orx * i, ny * j + ory * i), (nx * j + orx * (i + 0.25), ny * j + ory * (i + 0.25)), (nx * (j - 0.5) + orx * (i + 0.5), ny * (j - 0.5) + ory * (i + 0.5))], [(nx * (j - 1) + orx * (i + 0.75), ny * (j - 1) + ory * (i + 0.75)), (nx * (j - 1) + orx * (i + 1), ny * (j - 1) + ory * (i + 1))]], color=col[j], **kwds) + a += bezier_path( + [ + [(nx * j + orx * i, ny * j + ory * i), (nx * j + orx * (i + 0.25), ny * j + ory * (i + 0.25)), (nx * (j - 0.5) + orx * (i + 0.5), ny * (j - 0.5) + ory * (i + 0.5))], + [(nx * (j - 1) + orx * (i + 0.75), ny * (j - 1) + ory * (i + 0.75)), (nx * (j - 1) + orx * (i + 1), ny * (j - 1) + ory * (i + 1))], + ], + color=col[j], + **kwds, + ) col[j], col[j - 1] = col[j - 1], col[j] else: a += line([(nx * j + orx * i, ny * j + ory * i), (nx * j + orx * (i + 1), ny * j + ory * (i + 1))], color=col[j], **kwds) @@ -2859,7 +2921,38 @@ def _links_gould_representation(self, symbolics=False): mu = diagonal_matrix([t0 ** (-1), -t1, -(t0 ** (-1)), t1]) if n == 2: # R-Matrix taken from I. Marin - R = matrix(BR, {(0, 0): t0, (1, 4): s0, (2, 8): s0, (3, 12): 1, (4, 1): s0, (4, 4): t0 - 1, (5, 5): -1, (6, 6): t0 * t1 - 1, (6, 9): -s0 * s1, (6, 12): -Y * s0 * s1, (7, 13): s1, (8, 2): s0, (8, 8): t0 - 1, (9, 6): -s0 * s1, (9, 12): Y, (10, 10): -1, (11, 14): s1, (12, 3): 1, (12, 6): -Y * s0 * s1, (12, 9): Y, (12, 12): -(t0 - 1) * (t1 - 1), (13, 7): s1, (13, 13): t1 - 1, (14, 11): s1, (14, 14): t1 - 1, (15, 15): t1}, sparse=sparse) + R = matrix( + BR, + { + (0, 0): t0, + (1, 4): s0, + (2, 8): s0, + (3, 12): 1, + (4, 1): s0, + (4, 4): t0 - 1, + (5, 5): -1, + (6, 6): t0 * t1 - 1, + (6, 9): -s0 * s1, + (6, 12): -Y * s0 * s1, + (7, 13): s1, + (8, 2): s0, + (8, 8): t0 - 1, + (9, 6): -s0 * s1, + (9, 12): Y, + (10, 10): -1, + (11, 14): s1, + (12, 3): 1, + (12, 6): -Y * s0 * s1, + (12, 9): Y, + (12, 12): -(t0 - 1) * (t1 - 1), + (13, 7): s1, + (13, 13): t1 - 1, + (14, 11): s1, + (14, 14): t1 - 1, + (15, 15): t1, + }, + sparse=sparse, + ) RI = (~t0 + ~t1) * (1 + R) - ~t0 * ~t1 * (R + R**2) - 1 # quantum trace operator on two fold tensor space diff --git a/src/sage/groups/perm_gps/all.py b/src/sage/groups/perm_gps/all.py index ae364c9b3af..eccfc7cee7e 100644 --- a/src/sage/groups/perm_gps/all.py +++ b/src/sage/groups/perm_gps/all.py @@ -1,4 +1,27 @@ -from sage.groups.perm_gps.permgroup_named import SymmetricGroup, AlternatingGroup, DihedralGroup, SplitMetacyclicGroup, SemidihedralGroup, CyclicPermutationGroup, DiCyclicGroup, TransitiveGroup, PGL, PSL, PSp, PSU, PGU, MathieuGroup, KleinFourGroup, QuaternionGroup, PrimitiveGroup, PrimitiveGroups, SuzukiGroup, TransitiveGroups, GeneralDihedralGroup, SmallPermutationGroup +from sage.groups.perm_gps.permgroup_named import ( + SymmetricGroup, + AlternatingGroup, + DihedralGroup, + SplitMetacyclicGroup, + SemidihedralGroup, + CyclicPermutationGroup, + DiCyclicGroup, + TransitiveGroup, + PGL, + PSL, + PSp, + PSU, + PGU, + MathieuGroup, + KleinFourGroup, + QuaternionGroup, + PrimitiveGroup, + PrimitiveGroups, + SuzukiGroup, + TransitiveGroups, + GeneralDihedralGroup, + SmallPermutationGroup, +) from sage.groups.perm_gps.permgroup import PermutationGroup, PermutationGroup_generic, PermutationGroup_subgroup, direct_product_permgroups diff --git a/src/sage/interfaces/expect.py b/src/sage/interfaces/expect.py index c110d68fd29..d29ebe1fff4 100644 --- a/src/sage/interfaces/expect.py +++ b/src/sage/interfaces/expect.py @@ -125,7 +125,28 @@ class Expect(Interface): Expect interface object. """ - def __init__(self, name, prompt, command=None, env={}, server=None, server_tmpdir=None, ulimit=None, maxread=None, script_subdirectory=None, restart_on_ctrlc=False, verbose_start=False, init_code=[], max_startup_time=None, logfile=None, eval_using_file_cutoff=0, do_cleaner=True, remote_cleaner=False, path=None, terminal_echo=True): + def __init__( + self, + name, + prompt, + command=None, + env={}, + server=None, + server_tmpdir=None, + ulimit=None, + maxread=None, + script_subdirectory=None, + restart_on_ctrlc=False, + verbose_start=False, + init_code=[], + max_startup_time=None, + logfile=None, + eval_using_file_cutoff=0, + do_cleaner=True, + remote_cleaner=False, + path=None, + terminal_echo=True, + ): Interface.__init__(self, name) diff --git a/src/sage/interfaces/fricas.py b/src/sage/interfaces/fricas.py index c3800899c46..59b310d2785 100644 --- a/src/sage/interfaces/fricas.py +++ b/src/sage/interfaces/fricas.py @@ -247,7 +247,22 @@ ")lisp (setf |$ioHook|" " (lambda (x &optional args)" " (when (member x '(|startAlgebraOutput| |endOfAlgebraOutput|" " |startKeyedMsg| |endOfKeyedMsg|))" " (prin1 x)" " (princ #\\Newline))))", ) # code (one-line!) executed after having set up the prompt -FRICAS_HELPER_CODE = 'sageprint(x:SExpression):String == ' + '(atom? x => (' + 'float? x => return float(x)::String;' + 'integer? x => return integer(x)::String;' + 'string? x => return concat(["_"", string(x)::String, "_""])$String;' + 'symbol? x => return string(symbol(x));' + 'list? x => return "()");' + 'S: List String := [sageprint y for y in destruct x];' + 'R: String := new(1 + reduce(_+, [1 + #(s)$String for s in S], 0),' + 'space()$Character);' + 'copyInto!(R, "(", 1);' + 'i := 2;' + 'for s in S repeat' '(copyInto!(R, s, i); i := i + 1 + #(s)$String);' + 'copyInto!(R, ")", i-1);' + 'return R)' +FRICAS_HELPER_CODE = ( + 'sageprint(x:SExpression):String == ' + + '(atom? x => (' + + 'float? x => return float(x)::String;' + + 'integer? x => return integer(x)::String;' + + 'string? x => return concat(["_"", string(x)::String, "_""])$String;' + + 'symbol? x => return string(symbol(x));' + + 'list? x => return "()");' + + 'S: List String := [sageprint y for y in destruct x];' + + 'R: String := new(1 + reduce(_+, [1 + #(s)$String for s in S], 0),' + + 'space()$Character);' + + 'copyInto!(R, "(", 1);' + + 'i := 2;' + + 'for s in S repeat' + '(copyInto!(R, s, i); i := i + 1 + #(s)$String);' + 'copyInto!(R, ")", i-1);' + 'return R)' +) FRICAS_LINENUMBER_OFF_CODE = ")lisp (setf |$IOindex| NIL)" FRICAS_FIRST_PROMPT = r"\(1\) -> " diff --git a/src/sage/interfaces/gap3.py b/src/sage/interfaces/gap3.py index 0167afa23b8..8c009c23b79 100644 --- a/src/sage/interfaces/gap3.py +++ b/src/sage/interfaces/gap3.py @@ -320,7 +320,24 @@ def __init__(self, command=gap3_cmd): # -y -- sets the number of lines of the terminal; controls how many # lines of text are output by GAP3 before the pager is invoked. # This option is useful in dealing with the GAP3 help system. - Expect.__init__(self, name='gap3', prompt='gap> ', command=self.__gap3_command_string + " -p -b -y 500", server=None, ulimit=None, script_subdirectory=None, restart_on_ctrlc=True, verbose_start=False, init_code=[], max_startup_time=None, logfile=None, eval_using_file_cutoff=100, do_cleaner=True, remote_cleaner=False, path=None) + Expect.__init__( + self, + name='gap3', + prompt='gap> ', + command=self.__gap3_command_string + " -p -b -y 500", + server=None, + ulimit=None, + script_subdirectory=None, + restart_on_ctrlc=True, + verbose_start=False, + init_code=[], + max_startup_time=None, + logfile=None, + eval_using_file_cutoff=100, + do_cleaner=True, + remote_cleaner=False, + path=None, + ) def _start(self): r""" diff --git a/src/sage/interfaces/giac.py b/src/sage/interfaces/giac.py index 1114352f007..340d7c9c45e 100644 --- a/src/sage/interfaces/giac.py +++ b/src/sage/interfaces/giac.py @@ -335,7 +335,9 @@ def __init__(self, maxread=None, script_subdirectory=None, server=None, server_t sage: giac == loads(dumps(giac)) True """ - Expect.__init__(self, name='giac', prompt='[0-9]*>> ', command="giac --sage", env={"LANG": "C"}, init_code=['maple_mode(0);I:=i;'], script_subdirectory=script_subdirectory, restart_on_ctrlc=False, server=server, server_tmpdir=server_tmpdir, verbose_start=False, logfile=logfile, eval_using_file_cutoff=1000) # coercion could be broken in maple_mode + Expect.__init__( + self, name='giac', prompt='[0-9]*>> ', command="giac --sage", env={"LANG": "C"}, init_code=['maple_mode(0);I:=i;'], script_subdirectory=script_subdirectory, restart_on_ctrlc=False, server=server, server_tmpdir=server_tmpdir, verbose_start=False, logfile=logfile, eval_using_file_cutoff=1000 + ) # coercion could be broken in maple_mode def _function_class(self): """ diff --git a/src/sage/interfaces/kenzo.py b/src/sage/interfaces/kenzo.py index e40b703a662..993eebee234 100644 --- a/src/sage/interfaces/kenzo.py +++ b/src/sage/interfaces/kenzo.py @@ -40,7 +40,66 @@ from sage.features.kenzo import Kenzo # defining the auxiliary functions as wrappers over the kenzo ones -kenzo_names = ['add', 'array-dimensions', 'basis_aux1', 'basis_aux1', 'bicomplex-spectral-sequence', 'build-finite-ss2', 'build-mrph-aux', 'change-sorc-trgt-aux', 'chcm-mat', 'chcm-mat2', 'classifying-space', 'cmps', 'convertmatrice', 'crts-prdc', 'degr-aux', 'dffr-aux', 'dffr_aux1', 'dgop', 'dgop-int-ext', 'dstr-change-sorc-trgt-aux', 'echcm', 'eilenberg-moore-spectral-sequence', 'evaluation-aux1', 'gmsm', 'homologie', 'homotopy-list', 'idnt-mrph', 'join', 'k-z', 'k-z2', 'k-zp', 'kabstractsimplex_aux1', 'kchaincomplex_aux1', 'kmorphismchaincomplex_aux1', 'loop-space', 'make-array-from-lists', 'make-array-to-lists', 'moore', 'ncol', 'nlig', 'nreverse', 'nth', 'opps', 'orgn_aux1', 'sbtr', 'serre-spectral-sequence-product', 'serre-whitehead-spectral-sequence', 'sfinitesimplicialset_aux1', 'smash-product', 'sorc-aux', 'spectral-sequence-differential-matrix', 'spectral-sequence-group', 'sphere', 'suspension', 'tnsr-prdc', 'trgt-aux', 'wedge', 'zero-mrph'] +kenzo_names = [ + 'add', + 'array-dimensions', + 'basis_aux1', + 'basis_aux1', + 'bicomplex-spectral-sequence', + 'build-finite-ss2', + 'build-mrph-aux', + 'change-sorc-trgt-aux', + 'chcm-mat', + 'chcm-mat2', + 'classifying-space', + 'cmps', + 'convertmatrice', + 'crts-prdc', + 'degr-aux', + 'dffr-aux', + 'dffr_aux1', + 'dgop', + 'dgop-int-ext', + 'dstr-change-sorc-trgt-aux', + 'echcm', + 'eilenberg-moore-spectral-sequence', + 'evaluation-aux1', + 'gmsm', + 'homologie', + 'homotopy-list', + 'idnt-mrph', + 'join', + 'k-z', + 'k-z2', + 'k-zp', + 'kabstractsimplex_aux1', + 'kchaincomplex_aux1', + 'kmorphismchaincomplex_aux1', + 'loop-space', + 'make-array-from-lists', + 'make-array-to-lists', + 'moore', + 'ncol', + 'nlig', + 'nreverse', + 'nth', + 'opps', + 'orgn_aux1', + 'sbtr', + 'serre-spectral-sequence-product', + 'serre-whitehead-spectral-sequence', + 'sfinitesimplicialset_aux1', + 'smash-product', + 'sorc-aux', + 'spectral-sequence-differential-matrix', + 'spectral-sequence-group', + 'sphere', + 'suspension', + 'tnsr-prdc', + 'trgt-aux', + 'wedge', + 'zero-mrph', +] # Now initialize Kenzo. For each string s in kenzo_names, the diff --git a/src/sage/interfaces/magma.py b/src/sage/interfaces/magma.py index 239dba92656..d5768a686f4 100644 --- a/src/sage/interfaces/magma.py +++ b/src/sage/interfaces/magma.py @@ -271,7 +271,11 @@ def extcode_dir(iface=None) -> str: if ans != 0: raise OSError except OSError: - out_str = 'Tried to copy the file structure in "%s/magma/" to "%s:%s/data" and failed (possibly because scp is not installed in the system).\nFor the remote Magma to work you should populate the remote directory by some other method, or install scp in the system and retry.' % (SAGE_EXTCODE, iface._server, tmp) + out_str = 'Tried to copy the file structure in "%s/magma/" to "%s:%s/data" and failed (possibly because scp is not installed in the system).\nFor the remote Magma to work you should populate the remote directory by some other method, or install scp in the system and retry.' % ( + SAGE_EXTCODE, + iface._server, + tmp, + ) from warnings import warn warn(out_str) diff --git a/src/sage/interfaces/mathematica.py b/src/sage/interfaces/mathematica.py index 1e481643ddf..d2956885866 100644 --- a/src/sage/interfaces/mathematica.py +++ b/src/sage/interfaces/mathematica.py @@ -1176,7 +1176,25 @@ def request_wolfram_alpha(input, verbose=False): # some parameters documented here: # https://products.wolframalpha.com/api/documentation/#parameter-reference # the following are the parameters used by the website - params = {'assumptionsversion': '2', 'async': 'true', 'banners': 'raw', 'debuggingdata': 'false', 'format': 'image,plaintext,imagemap,sound,minput,moutput', 'formattimeout': '8', 'input': input, 'output': 'JSON', 'parsetimeout': '5', 'podinfosasync': 'true', 'proxycode': proxy_code, 'recalcscheme': 'parallel', 'sbsdetails': 'true', 'scantimeout': '0.5', 'sponsorcategories': 'true', 'statemethod': 'deploybutton', 'storesubpodexprs': 'true'} + params = { + 'assumptionsversion': '2', + 'async': 'true', + 'banners': 'raw', + 'debuggingdata': 'false', + 'format': 'image,plaintext,imagemap,sound,minput,moutput', + 'formattimeout': '8', + 'input': input, + 'output': 'JSON', + 'parsetimeout': '5', + 'podinfosasync': 'true', + 'proxycode': proxy_code, + 'recalcscheme': 'parallel', + 'sbsdetails': 'true', + 'scantimeout': '0.5', + 'sponsorcategories': 'true', + 'statemethod': 'deploybutton', + 'storesubpodexprs': 'true', + } # # we can also change some parameters # params = { # 'assumptionsversion': '2', diff --git a/src/sage/interfaces/maxima_lib.py b/src/sage/interfaces/maxima_lib.py index 0716d482abc..33223f35bfe 100644 --- a/src/sage/interfaces/maxima_lib.py +++ b/src/sage/interfaces/maxima_lib.py @@ -1496,7 +1496,14 @@ def max_pochhammer_to_sage(expr): # The dictionaries special_max_to_sage = {mrat: mrat_to_sage, mqapply: mqapply_to_sage, mdiff: mdiff_to_sage, EclObject("%INTEGRATE"): dummy_integrate, max_at: max_at_to_sage, mlist: mlist_to_sage, max_harmo: max_harmonic_to_sage, max_pochhammer: max_pochhammer_to_sage} -special_sage_to_max = {sage.functions.log.polylog: lambda N, X: [[mqapply], [[max_li, max_array], N], X], sage.functions.gamma.psi1: lambda X: [[mqapply], [[max_psi, max_array], 0], X], sage.functions.gamma.psi2: lambda N, X: [[mqapply], [[max_psi, max_array], N], X], sage.functions.log.lambert_w: lambda N, X: [[max_lambert_w], X] if N == EclObject(0) else [[mqapply], [[max_lambert_w, max_array], N], X], sage.functions.log.harmonic_number: lambda N, X: [[max_harmo], X, N], sage.functions.hypergeometric.hypergeometric: lambda A, B, X: [[mqapply], [[max_hyper, max_array], lisp_length(A.cdr()), lisp_length(B.cdr())], A, B, X]} +special_sage_to_max = { + sage.functions.log.polylog: lambda N, X: [[mqapply], [[max_li, max_array], N], X], + sage.functions.gamma.psi1: lambda X: [[mqapply], [[max_psi, max_array], 0], X], + sage.functions.gamma.psi2: lambda N, X: [[mqapply], [[max_psi, max_array], N], X], + sage.functions.log.lambert_w: lambda N, X: [[max_lambert_w], X] if N == EclObject(0) else [[mqapply], [[max_lambert_w, max_array], N], X], + sage.functions.log.harmonic_number: lambda N, X: [[max_harmo], X, N], + sage.functions.hypergeometric.hypergeometric: lambda A, B, X: [[mqapply], [[max_hyper, max_array], lisp_length(A.cdr()), lisp_length(B.cdr())], A, B, X], +} # Dictionaries for symbols diff --git a/src/sage/interfaces/rubik.py b/src/sage/interfaces/rubik.py index db4953d7458..07d87563049 100644 --- a/src/sage/interfaces/rubik.py +++ b/src/sage/interfaces/rubik.py @@ -44,7 +44,56 @@ # Can't seem to find consistency in letter ordering # between us and them... These are copied from the source. -optimal_solver_tokens = ["UF", "UR", "UB", "UL", "DF", "DR", "DB", "DL", "FR", "FL", "BR", "BL", "FU", "RU", "BU", "LU", "FD", "RD", "BD", "LD", "RF", "LF", "RB", "LB", "UFR", "URB", "UBL", "ULF", "DRF", "DFL", "DLB", "DBR", "FRU", "RBU", "BLU", "LFU", "RFD", "FLD", "LBD", "BRD", "RUF", "BUR", "LUB", "FUL", "FDR", "LDF", "BDL", "RDB"] +optimal_solver_tokens = [ + "UF", + "UR", + "UB", + "UL", + "DF", + "DR", + "DB", + "DL", + "FR", + "FL", + "BR", + "BL", + "FU", + "RU", + "BU", + "LU", + "FD", + "RD", + "BD", + "LD", + "RF", + "LF", + "RB", + "LB", + "UFR", + "URB", + "UBL", + "ULF", + "DRF", + "DFL", + "DLB", + "DBR", + "FRU", + "RBU", + "BLU", + "LFU", + "RFD", + "FLD", + "LBD", + "BRD", + "RUF", + "BUR", + "LUB", + "FUL", + "FDR", + "LDF", + "BDL", + "RDB", +] # The input format. optimal_solver_format = "UF UR UB UL DF DR DB DL FR FL BR BL UFR URB UBL ULF DRF DFL DLB DBR" diff --git a/src/sage/libs/gap/gap_globals.py b/src/sage/libs/gap/gap_globals.py index 3de08c3a911..743dbfb1f90 100644 --- a/src/sage/libs/gap/gap_globals.py +++ b/src/sage/libs/gap/gap_globals.py @@ -17,4 +17,34 @@ # selected gap globals to use in tab completion -common_gap_globals = {'Assert', 'Cyclotomics', 'GaussianIntegers', 'GaussianRationals', 'GlobalMersenneTwister', 'GlobalRandomSource', 'InfoAlgebra', 'InfoAttributes', 'InfoBckt', 'InfoCharacterTable', 'InfoCoh', 'InfoComplement', 'InfoCoset', 'InfoFpGroup', 'InfoGroebner', 'InfoGroup', 'InfoLattice', 'InfoMatrix', 'InfoMonomial', 'InfoNumtheor', 'InfoOptions', 'InfoPackageLoading', 'InfoPcSubgroup', 'InfoWarning', 'Integers', 'NiceBasisFiltersInfo', 'Primes', 'Rationals', 'TableOfMarksComponents'} | common_gap_functions +common_gap_globals = { + 'Assert', + 'Cyclotomics', + 'GaussianIntegers', + 'GaussianRationals', + 'GlobalMersenneTwister', + 'GlobalRandomSource', + 'InfoAlgebra', + 'InfoAttributes', + 'InfoBckt', + 'InfoCharacterTable', + 'InfoCoh', + 'InfoComplement', + 'InfoCoset', + 'InfoFpGroup', + 'InfoGroebner', + 'InfoGroup', + 'InfoLattice', + 'InfoMatrix', + 'InfoMonomial', + 'InfoNumtheor', + 'InfoOptions', + 'InfoPackageLoading', + 'InfoPcSubgroup', + 'InfoWarning', + 'Integers', + 'NiceBasisFiltersInfo', + 'Primes', + 'Rationals', + 'TableOfMarksComponents', +} | common_gap_functions diff --git a/src/sage/manifolds/differentiable/integrated_curve.py b/src/sage/manifolds/differentiable/integrated_curve.py index 02353b2f0c1..3d2863363fe 100644 --- a/src/sage/manifolds/differentiable/integrated_curve.py +++ b/src/sage/manifolds/differentiable/integrated_curve.py @@ -1341,7 +1341,19 @@ def jacobian(t, y): n += 1 if n < N: - raise ValueError("the {}th point ".format(n) + "(initial point being the '0th' point) " + "of the numerical solution (obtained " + "for a curve parameter equal " + "to {}) is out ".format(sol[n][0]) + "of the chart domain; a curve with a " + "smaller maximal value of the curve " + "parameter, or a smaller initial tangent " + "vector, might be considered. You can also try " + "'solve_across_charts' in order not to be " + "confined to a single chart") + raise ValueError( + "the {}th point ".format(n) + + "(initial point being the '0th' point) " + + "of the numerical solution (obtained " + + "for a curve parameter equal " + + "to {}) is out ".format(sol[n][0]) + + "of the chart domain; a curve with a " + + "smaller maximal value of the curve " + + "parameter, or a smaller initial tangent " + + "vector, might be considered. You can also try " + + "'solve_across_charts' in order not to be " + + "confined to a single chart" + ) else: self._solutions[solution_key] = coords_sol if verbose: @@ -2274,7 +2286,24 @@ def plot_integrated(self, chart=None, ambient_coords=None, mapping=None, prange= for i in range(len(interpolation)): nb_pts = int(float(plot_points) * len(interpolation[i][1][0]) / len_tot) self._chart = interpolation[i][0] - res += self.plot_integrated(chart=chart, ambient_coords=ambient_coords, mapping=mapping, prange=prange, interpolation_key=interpolation_key + "_chart_" + str(i), include_end_point=include_end_point, end_point_offset=end_point_offset, verbose=verbose, color=color[i], style=style, label_axes=False, display_tangent=display_tangent, color_tangent=color_tangent, across_charts=False, plot_points=nb_pts, **kwds) + res += self.plot_integrated( + chart=chart, + ambient_coords=ambient_coords, + mapping=mapping, + prange=prange, + interpolation_key=interpolation_key + "_chart_" + str(i), + include_end_point=include_end_point, + end_point_offset=end_point_offset, + verbose=verbose, + color=color[i], + style=style, + label_axes=False, + display_tangent=display_tangent, + color_tangent=color_tangent, + across_charts=False, + plot_points=nb_pts, + **kwds, + ) return res diff --git a/src/sage/matroids/database_collections.py b/src/sage/matroids/database_collections.py index 78a2319513a..5b028a50259 100644 --- a/src/sage/matroids/database_collections.py +++ b/src/sage/matroids/database_collections.py @@ -240,9 +240,99 @@ def OxleyMatroids(): These matroids are the nonparametrized matroids that appear in the Appendix ``Some Interesting Matroids`` in [Oxl2011]_ (p. 639-64). """ - from sage.matroids.database_matroids import U24, U25, U35, K4, Whirl3, Q6, P6, U36, R6, Fano, FanoDual, NonFano, NonFanoDual, O7, P7, AG32, AG32prime, R8, F8, Q8, L8, S8, Vamos, T8, J, P8, P8pp, Wheel4, Whirl4, K33dual, K33, AG23, TernaryDowling3, R9, Pappus, NonPappus, K5, K5dual, R10, NonDesargues, R12, ExtendedTernaryGolayCode, T12, PG23 - - lst = [U24, U25, U35, K4, Whirl3, Q6, P6, U36, R6, Fano, FanoDual, NonFano, NonFanoDual, O7, P7, AG32, AG32prime, R8, F8, Q8, L8, S8, Vamos, T8, J, P8, P8pp, Wheel4, Whirl4, K33dual, K33, AG23, TernaryDowling3, R9, Pappus, NonPappus, K5, K5dual, R10, NonDesargues, R12, ExtendedTernaryGolayCode, T12, PG23] # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 + from sage.matroids.database_matroids import ( + U24, + U25, + U35, + K4, + Whirl3, + Q6, + P6, + U36, + R6, + Fano, + FanoDual, + NonFano, + NonFanoDual, + O7, + P7, + AG32, + AG32prime, + R8, + F8, + Q8, + L8, + S8, + Vamos, + T8, + J, + P8, + P8pp, + Wheel4, + Whirl4, + K33dual, + K33, + AG23, + TernaryDowling3, + R9, + Pappus, + NonPappus, + K5, + K5dual, + R10, + NonDesargues, + R12, + ExtendedTernaryGolayCode, + T12, + PG23, + ) + + lst = [ + U24, + U25, + U35, + K4, + Whirl3, + Q6, + P6, + U36, + R6, + Fano, + FanoDual, + NonFano, + NonFanoDual, + O7, + P7, + AG32, + AG32prime, + R8, + F8, + Q8, + L8, + S8, + Vamos, + T8, + J, + P8, + P8pp, + Wheel4, + Whirl4, + K33dual, + K33, + AG23, + TernaryDowling3, + R9, + Pappus, + NonPappus, + K5, + K5dual, + R10, + NonDesargues, + R12, + ExtendedTernaryGolayCode, + T12, + PG23, + ] # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 12 # 13 for M in lst: yield M() @@ -265,9 +355,147 @@ def BrettellMatroids(): :mod:`Matroid catalog `, under ``Brettell's matroid collection``. """ - from sage.matroids.database_matroids import RelaxedNonFano, TippedFree3spike, AG23minusDY, TQ8, P8p, KP8, Sp8, Sp8pp, LP8, WQ8, BB9, TQ9, TQ9p, M8591, PP9, BB9gDY, A9, FN9, FX9, KR9, KQ9, UG10, FF10, GP10, FZ10, UQ10, FP10, TQ10, FY10, PP10, FU10, D10, UK10, PK10, GK10, FT10, TK10, KT10, TU10, UT10, FK10, KF10, FA11, FR12, GP12, FQ12, FF12, FZ12, UQ12, FP12, FS12, UK12, UA12, AK12, FK12, KB12, AF12, NestOfTwistedCubes, XY13, N3, N3pp, UP14, VP14, FV14, OW14, FM14, FA15, N4 - - lst = [RelaxedNonFano, TippedFree3spike, AG23minusDY, TQ8, P8p, KP8, Sp8, Sp8pp, LP8, WQ8, BB9, TQ9, TQ9p, M8591, PP9, BB9gDY, A9, FN9, FX9, KR9, KQ9, UG10, FF10, GP10, FZ10, UQ10, FP10, TQ10, FY10, PP10, FU10, D10, UK10, PK10, GK10, FT10, TK10, KT10, TU10, UT10, FK10, KF10, FA11, FR12, GP12, FQ12, FF12, FZ12, UQ12, FP12, FS12, UK12, UA12, AK12, FK12, KB12, AF12, NestOfTwistedCubes, XY13, N3, N3pp, UP14, VP14, FV14, OW14, FM14, FA15, N4] # 7 # 8 # 9 # 10 # 11 # 12 # 13 # 14 # 15 # 16 + from sage.matroids.database_matroids import ( + RelaxedNonFano, + TippedFree3spike, + AG23minusDY, + TQ8, + P8p, + KP8, + Sp8, + Sp8pp, + LP8, + WQ8, + BB9, + TQ9, + TQ9p, + M8591, + PP9, + BB9gDY, + A9, + FN9, + FX9, + KR9, + KQ9, + UG10, + FF10, + GP10, + FZ10, + UQ10, + FP10, + TQ10, + FY10, + PP10, + FU10, + D10, + UK10, + PK10, + GK10, + FT10, + TK10, + KT10, + TU10, + UT10, + FK10, + KF10, + FA11, + FR12, + GP12, + FQ12, + FF12, + FZ12, + UQ12, + FP12, + FS12, + UK12, + UA12, + AK12, + FK12, + KB12, + AF12, + NestOfTwistedCubes, + XY13, + N3, + N3pp, + UP14, + VP14, + FV14, + OW14, + FM14, + FA15, + N4, + ) + + lst = [ + RelaxedNonFano, + TippedFree3spike, + AG23minusDY, + TQ8, + P8p, + KP8, + Sp8, + Sp8pp, + LP8, + WQ8, + BB9, + TQ9, + TQ9p, + M8591, + PP9, + BB9gDY, + A9, + FN9, + FX9, + KR9, + KQ9, + UG10, + FF10, + GP10, + FZ10, + UQ10, + FP10, + TQ10, + FY10, + PP10, + FU10, + D10, + UK10, + PK10, + GK10, + FT10, + TK10, + KT10, + TU10, + UT10, + FK10, + KF10, + FA11, + FR12, + GP12, + FQ12, + FF12, + FZ12, + UQ12, + FP12, + FS12, + UK12, + UA12, + AK12, + FK12, + KB12, + AF12, + NestOfTwistedCubes, + XY13, + N3, + N3pp, + UP14, + VP14, + FV14, + OW14, + FM14, + FA15, + N4, + ] # 7 # 8 # 9 # 10 # 11 # 12 # 13 # 14 # 15 # 16 for M in lst: yield M() diff --git a/src/sage/matroids/database_matroids.py b/src/sage/matroids/database_matroids.py index b7ecffad204..81760e43e35 100644 --- a/src/sage/matroids/database_matroids.py +++ b/src/sage/matroids/database_matroids.py @@ -4848,7 +4848,44 @@ def Block_10_5(groundset=None): sage: BD.is_t_design(return_parameters=True) (True, (3, 10, 5, 3)) """ - NSC = ['abcde', 'acdfg', 'bdefg', 'bcdfh', 'abefh', 'abcgh', 'adegh', 'cefgh', 'bcefi', 'adefi', 'bcdgi', 'acegi', 'abfgi', 'abdhi', 'cdehi', 'acfhi', 'beghi', 'dfghi', 'abdfj', 'acefj', 'abegj', 'cdegj', 'bcfgj', 'acdhj', 'bcehj', 'defhj', 'bdghj', 'afghj', 'abcij', 'bdeij', 'cdfij', 'adgij', 'efgij', 'aehij', 'bfhij', 'cghij'] + NSC = [ + 'abcde', + 'acdfg', + 'bdefg', + 'bcdfh', + 'abefh', + 'abcgh', + 'adegh', + 'cefgh', + 'bcefi', + 'adefi', + 'bcdgi', + 'acegi', + 'abfgi', + 'abdhi', + 'cdehi', + 'acfhi', + 'beghi', + 'dfghi', + 'abdfj', + 'acefj', + 'abegj', + 'cdegj', + 'bcfgj', + 'acdhj', + 'bcehj', + 'defhj', + 'bdghj', + 'afghj', + 'abcij', + 'bdeij', + 'cdfij', + 'adgij', + 'efgij', + 'aehij', + 'bfhij', + 'cghij', + ] M = Matroid(rank=5, nonspanning_circuits=NSC) M = _rename_and_relabel(M, "Block(10, 5)", groundset) return M @@ -4911,7 +4948,24 @@ def BetsyRoss(groundset=None): NSC = ['acf', 'acg', 'adi', 'adj', 'afg', 'ahk', 'aij', 'bdg', 'bdh', 'bef', 'bej', 'bfj', 'bgh', 'bik', 'ceh', 'cei', 'cfg', 'chi', 'cjk', 'dfk', 'dgh', 'dij', 'efj', 'egk', 'ehi'] M = Matroid(rank=3, nonspanning_circuits=NSC) M = _rename_and_relabel(M, "BetsyRoss", groundset) - pos = dict(zip(groundset or 'abcdefghijk', [(0, 1.61000000000000), (1.53120099123520, 0.497517360943665), (0.946334256190882, -1.30251736094367), (-0.946334256190882, -1.30251736094367), (-1.53120099123520, 0.497517360943665), (0.365084007635076, 0.502495027562079), (0.590718333102580, -0.191936021350899), (0, -0.621118012422360), (-0.590718333102580, -0.191936021350899), (-0.365084007635076, 0.502495027562079), (0, 0)])) + pos = dict( + zip( + groundset or 'abcdefghijk', + [ + (0, 1.61000000000000), + (1.53120099123520, 0.497517360943665), + (0.946334256190882, -1.30251736094367), + (-0.946334256190882, -1.30251736094367), + (-1.53120099123520, 0.497517360943665), + (0.365084007635076, 0.502495027562079), + (0.590718333102580, -0.191936021350899), + (0, -0.621118012422360), + (-0.590718333102580, -0.191936021350899), + (-0.365084007635076, 0.502495027562079), + (0, 0), + ], + ) + ) M._fix_positions(pos_dict=pos) return M @@ -4961,7 +5015,19 @@ def D16(groundset='abcdefghijklmnop'): # A.K.A. the Carolyn Chun Matroid [CMO2012]_ """ - A = Matrix(GF(2), [[1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0], [0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1], [0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1], [0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0]]) + A = Matrix( + GF(2), + [ + [1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0], + [0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1], + [0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1], + [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1], + [0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0], + ], + ) M = BinaryMatroid(A, groundset) M = _rename_and_relabel(M, "D16") return M @@ -4985,7 +5051,19 @@ def Terrahawk(groundset='abcdefghijklmnop'): # aka the Dillon Mayhew Matroid [CMO2011]_ """ - A = Matrix(GF(2), [[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0]]) + A = Matrix( + GF(2), + [ + [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0], + [0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0], + ], + ) M = BinaryMatroid(A, groundset) M = _rename_and_relabel(M, "Terrahawk") return M @@ -5009,7 +5087,23 @@ def ExtendedBinaryGolayCode(groundset='abcdefghijklmnopqrstuvwx'): :class:`GolayCode ` """ - A = Matrix(GF(2), [[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0], [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1], [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0], [1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0], [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0], [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]) + A = Matrix( + GF(2), + [ + [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0], + [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1], + [1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0], + [1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0], + [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0], + [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1], + [1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1], + [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1], + [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0], + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1], + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + ], + ) M = BinaryMatroid(A, groundset) M = _rename_and_relabel(M, "Extended Binary Golay Code") return M diff --git a/src/sage/misc/all.py b/src/sage/misc/all.py index 0898f6a0242..925a990d795 100644 --- a/src/sage/misc/all.py +++ b/src/sage/misc/all.py @@ -81,7 +81,64 @@ from sage.misc.func_persist import func_persist -from sage.misc.functional import additive_order, base_ring, base_field, basis, category, charpoly, characteristic_polynomial, coerce, cyclotomic_polynomial, decomposition, denominator, det, dimension, dim, discriminant, disc, eta, fcp, gen, gens, hecke_operator, image, integral, integrate, integral_closure, interval, xinterval, is_even, is_odd, kernel, krull_dimension, lift, log as log_b, minimal_polynomial, minpoly, multiplicative_order, ngens, norm, numerator, numerical_approx, n, N, objgens, objgen, order, rank, regulator, round, quotient, quo, isqrt, squarefree_part, sqrt, symbolic_sum as sum, symbolic_prod as product, transpose +from sage.misc.functional import ( + additive_order, + base_ring, + base_field, + basis, + category, + charpoly, + characteristic_polynomial, + coerce, + cyclotomic_polynomial, + decomposition, + denominator, + det, + dimension, + dim, + discriminant, + disc, + eta, + fcp, + gen, + gens, + hecke_operator, + image, + integral, + integrate, + integral_closure, + interval, + xinterval, + is_even, + is_odd, + kernel, + krull_dimension, + lift, + log as log_b, + minimal_polynomial, + minpoly, + multiplicative_order, + ngens, + norm, + numerator, + numerical_approx, + n, + N, + objgens, + objgen, + order, + rank, + regulator, + round, + quotient, + quo, + isqrt, + squarefree_part, + sqrt, + symbolic_sum as sum, + symbolic_prod as product, + transpose, +) from sage.misc.latex import LatexExpr, latex, view diff --git a/src/sage/misc/edit_module.py b/src/sage/misc/edit_module.py index df55e896cf9..4eb14ead53f 100644 --- a/src/sage/misc/edit_module.py +++ b/src/sage/misc/edit_module.py @@ -46,7 +46,16 @@ # we can set some defaults, however. Add your own if you like. -template_defaults = {'vi': Template('vi -c ${line} ${file}'), 'vim': Template('vim -c ${line} ${file}'), 'emacs': Template('emacs ${opts} +${line} ${file}'), 'nedit-nc': Template('nedit-nc -line ${line} ${file}'), 'nedit-client': Template('nedit-client -line ${line} ${file}'), 'ncl': Template('ncl -line ${line} ${file}'), 'gedit': Template('gedit +${line} ${file} &'), 'kate': Template('kate -u --line +${line} ${file} &')} +template_defaults = { + 'vi': Template('vi -c ${line} ${file}'), + 'vim': Template('vim -c ${line} ${file}'), + 'emacs': Template('emacs ${opts} +${line} ${file}'), + 'nedit-nc': Template('nedit-nc -line ${line} ${file}'), + 'nedit-client': Template('nedit-client -line ${line} ${file}'), + 'ncl': Template('ncl -line ${line} ${file}'), + 'gedit': Template('gedit +${line} ${file} &'), + 'kate': Template('kate -u --line +${line} ${file} &'), +} def file_and_line(obj): diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index 6c7b80af8a1..d26e1183c51 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -2178,7 +2178,47 @@ def repr_lincomb(symbols, coeffs): return s.replace("+ -", "- ") -common_varnames = ['alpha', 'beta', 'gamma', 'Gamma', 'delta', 'Delta', 'epsilon', 'zeta', 'eta', 'theta', 'Theta', 'iota', 'kappa', 'lambda', 'Lambda', 'mu', 'nu', 'xi', 'Xi', 'pi', 'Pi', 'rho', 'sigma', 'Sigma', 'tau', 'upsilon', 'phi', 'Phi', 'varphi', 'chi', 'psi', 'Psi', 'omega', 'Omega', 'ast', 'bullet', 'circ', 'times', 'star'] +common_varnames = [ + 'alpha', + 'beta', + 'gamma', + 'Gamma', + 'delta', + 'Delta', + 'epsilon', + 'zeta', + 'eta', + 'theta', + 'Theta', + 'iota', + 'kappa', + 'lambda', + 'Lambda', + 'mu', + 'nu', + 'xi', + 'Xi', + 'pi', + 'Pi', + 'rho', + 'sigma', + 'Sigma', + 'tau', + 'upsilon', + 'phi', + 'Phi', + 'varphi', + 'chi', + 'psi', + 'Psi', + 'omega', + 'Omega', + 'ast', + 'bullet', + 'circ', + 'times', + 'star', +] def latex_varify(a, is_fname=False): diff --git a/src/sage/misc/rest_index_of_methods.py b/src/sage/misc/rest_index_of_methods.py index fe77a268f91..8ff5fcc8147 100644 --- a/src/sage/misc/rest_index_of_methods.py +++ b/src/sage/misc/rest_index_of_methods.py @@ -275,7 +275,9 @@ def can_import(f): return False return True - functions = {getattr(root, name): name for name, f in root.__dict__.items() if (not name.startswith('_') and can_import(f) and not hasattr(f, 'issue_number') and not inspect.isclass(f) and callable(getattr(f, '__func__', f)) and local_filter(f, name))} # private functions # unresolved lazy imports # deprecated functions # classes # e.g. GenericGraph.graphics_array_defaults # possibly filter imported functions + functions = { + getattr(root, name): name for name, f in root.__dict__.items() if (not name.startswith('_') and can_import(f) and not hasattr(f, 'issue_number') and not inspect.isclass(f) and callable(getattr(f, '__func__', f)) and local_filter(f, name)) + } # private functions # unresolved lazy imports # deprecated functions # classes # e.g. GenericGraph.graphics_array_defaults # possibly filter imported functions return list(functions.keys()), functions diff --git a/src/sage/misc/sagedoc.py b/src/sage/misc/sagedoc.py index 27e5c48a219..845fdd441e8 100644 --- a/src/sage/misc/sagedoc.py +++ b/src/sage/misc/sagedoc.py @@ -59,7 +59,45 @@ # Math substitutions: don't forget the leading backslash '\\'. These # are done using regular expressions, so it works best to also make # the strings raw: r'\\blah'. -math_substitutes = [(r'\\to', '-->'), (r'\\rightarrow', '-->'), (r'\\leftarrow', '<--'), (r'\\leftrightarrow', '<->'), (r'\\longrightarrow', '--->'), (r'\\longleftarrow', '<---'), (r'\\longleftrightarrow', '<-->'), (r'\\Rightarrow', '==>'), (r'\\Leftarrow', '<=='), (r'\\Leftrightarrow', '<=>'), (r'\\Longrightarrow', '===>'), (r'\\Longleftarrow', '<==='), (r'\\Longleftrightarrow', '<==>'), (r'\\colon', ':'), (r'\\left', ''), (r'\\right', ''), (r'\\bigl', ''), (r'\\bigr', ''), (r'\\leq', '<='), (r'\\geq', '>='), (r'\\le', '<='), (r'\\ge', '>='), (r'\\cdots', '...'), (r'\\ldots', '...'), (r'\\dots', '...'), (r'\\cdot', ' *'), (r'\\ast', ' *'), (r' \\times', ' x'), (r'\\times', ' x'), (r'\\backslash', '\\'), (r'\\mapsto', ' |--> '), (r'\\longmapsto', ' |---> '), (r'\\lvert', '|'), (r'\\rvert', '|'), (r'\\mid', '|'), (r' \\circ', ' o'), (r'\\circ', ' o')] +math_substitutes = [ + (r'\\to', '-->'), + (r'\\rightarrow', '-->'), + (r'\\leftarrow', '<--'), + (r'\\leftrightarrow', '<->'), + (r'\\longrightarrow', '--->'), + (r'\\longleftarrow', '<---'), + (r'\\longleftrightarrow', '<-->'), + (r'\\Rightarrow', '==>'), + (r'\\Leftarrow', '<=='), + (r'\\Leftrightarrow', '<=>'), + (r'\\Longrightarrow', '===>'), + (r'\\Longleftarrow', '<==='), + (r'\\Longleftrightarrow', '<==>'), + (r'\\colon', ':'), + (r'\\left', ''), + (r'\\right', ''), + (r'\\bigl', ''), + (r'\\bigr', ''), + (r'\\leq', '<='), + (r'\\geq', '>='), + (r'\\le', '<='), + (r'\\ge', '>='), + (r'\\cdots', '...'), + (r'\\ldots', '...'), + (r'\\dots', '...'), + (r'\\cdot', ' *'), + (r'\\ast', ' *'), + (r' \\times', ' x'), + (r'\\times', ' x'), + (r'\\backslash', '\\'), + (r'\\mapsto', ' |--> '), + (r'\\longmapsto', ' |---> '), + (r'\\lvert', '|'), + (r'\\rvert', '|'), + (r'\\mid', '|'), + (r' \\circ', ' o'), + (r'\\circ', ' o'), +] nonmath_substitutes = [ ('\\_', '_'), ('\\item', '* '), diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index 779c114d977..57ed9aba5ca 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -205,7 +205,26 @@ # using the following convention # (3, 5) <---> (sign) * [1,0,0,1,0,0,0,0] # taken from the Maple implementation by F. Brown -B_data: list[list[tuple]] = [[], [], [(2,)], [(3,)], [], [(5,)], [], [(7,)], [(3, 5)], [(9,)], [(3, 7)], [(11,), (3, 3, 5)], [(5, 7), (5, 3, 2, 2)], [(13,), (3, 5, 5), (3, 3, 7)], [(5, 9), (3, 11), (3, 3, 3, 5)], [(15,), (3, 5, 7), (3, 3, 9), (5, 3, 3, 2, 2)], [(11, 5), (13, 3), (5, 5, 3, 3), (7, 3, 3, 3), (7, 5, 2, 2)], [(17,), (7, 5, 5), (9, 3, 5), (9, 5, 3), (11, 3, 3), (5, 3, 3, 3, 3), (5, 5, 3, 2, 2)]] +B_data: list[list[tuple]] = [ + [], + [], + [(2,)], + [(3,)], + [], + [(5,)], + [], + [(7,)], + [(3, 5)], + [(9,)], + [(3, 7)], + [(11,), (3, 3, 5)], + [(5, 7), (5, 3, 2, 2)], + [(13,), (3, 5, 5), (3, 3, 7)], + [(5, 9), (3, 11), (3, 3, 3, 5)], + [(15,), (3, 5, 7), (3, 3, 9), (5, 3, 3, 2, 2)], + [(11, 5), (13, 3), (5, 5, 3, 3), (7, 3, 3, 3), (7, 5, 2, 2)], + [(17,), (7, 5, 5), (9, 3, 5), (9, 5, 3), (11, 3, 3), (5, 3, 3, 3, 3), (5, 5, 3, 2, 2)], +] Words10 = Words((1, 0), infinite=False) diff --git a/src/sage/monoids/string_monoid.py b/src/sage/monoids/string_monoid.py index 07213d4584e..b9823abdd04 100644 --- a/src/sage/monoids/string_monoid.py +++ b/src/sage/monoids/string_monoid.py @@ -528,10 +528,64 @@ def __init__(self): RR = RealField() # The characteristic frequency probability distribution of # Robert Edward Lewand. - self._characteristic_frequency_lewand = {"A": RR(0.08167), "B": RR(0.01492), "C": RR(0.02782), "D": RR(0.04253), "E": RR(0.12702), "F": RR(0.02228), "G": RR(0.02015), "H": RR(0.06094), "I": RR(0.06966), "J": RR(0.00153), "K": RR(0.00772), "L": RR(0.04025), "M": RR(0.02406), "N": RR(0.06749), "O": RR(0.07507), "P": RR(0.01929), "Q": RR(0.00095), "R": RR(0.05987), "S": RR(0.06327), "T": RR(0.09056), "U": RR(0.02758), "V": RR(0.00978), "W": RR(0.02360), "X": RR(0.00150), "Y": RR(0.01974), "Z": RR(0.00074)} + self._characteristic_frequency_lewand = { + "A": RR(0.08167), + "B": RR(0.01492), + "C": RR(0.02782), + "D": RR(0.04253), + "E": RR(0.12702), + "F": RR(0.02228), + "G": RR(0.02015), + "H": RR(0.06094), + "I": RR(0.06966), + "J": RR(0.00153), + "K": RR(0.00772), + "L": RR(0.04025), + "M": RR(0.02406), + "N": RR(0.06749), + "O": RR(0.07507), + "P": RR(0.01929), + "Q": RR(0.00095), + "R": RR(0.05987), + "S": RR(0.06327), + "T": RR(0.09056), + "U": RR(0.02758), + "V": RR(0.00978), + "W": RR(0.02360), + "X": RR(0.00150), + "Y": RR(0.01974), + "Z": RR(0.00074), + } # The characteristic frequency probability distribution of # H. Beker and F. Piper. - self._characteristic_frequency_beker_piper = {"A": RR(0.082), "B": RR(0.015), "C": RR(0.028), "D": RR(0.043), "E": RR(0.127), "F": RR(0.022), "G": RR(0.020), "H": RR(0.061), "I": RR(0.070), "J": RR(0.002), "K": RR(0.008), "L": RR(0.040), "M": RR(0.024), "N": RR(0.067), "O": RR(0.075), "P": RR(0.019), "Q": RR(0.001), "R": RR(0.060), "S": RR(0.063), "T": RR(0.091), "U": RR(0.028), "V": RR(0.010), "W": RR(0.023), "X": RR(0.001), "Y": RR(0.020), "Z": RR(0.001)} + self._characteristic_frequency_beker_piper = { + "A": RR(0.082), + "B": RR(0.015), + "C": RR(0.028), + "D": RR(0.043), + "E": RR(0.127), + "F": RR(0.022), + "G": RR(0.020), + "H": RR(0.061), + "I": RR(0.070), + "J": RR(0.002), + "K": RR(0.008), + "L": RR(0.040), + "M": RR(0.024), + "N": RR(0.067), + "O": RR(0.075), + "P": RR(0.019), + "Q": RR(0.001), + "R": RR(0.060), + "S": RR(0.063), + "T": RR(0.091), + "U": RR(0.028), + "V": RR(0.010), + "W": RR(0.023), + "X": RR(0.001), + "Y": RR(0.020), + "Z": RR(0.001), + } alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' StringMonoid_class.__init__(self, 26, [alph[i] for i in range(26)]) diff --git a/src/sage/numerical/interactive_simplex_method.py b/src/sage/numerical/interactive_simplex_method.py index 7217bea4061..a364f5881af 100644 --- a/src/sage/numerical/interactive_simplex_method.py +++ b/src/sage/numerical/interactive_simplex_method.py @@ -724,7 +724,15 @@ def __eq__(self, other): sage: P == P3 False """ - return isinstance(other, InteractiveLPProblem) and self.Abcx() == other.Abcx() and self._constant_term == other._constant_term and self._problem_type == other._problem_type and self._is_negative == other._is_negative and self._constraint_types == other._constraint_types and self._variable_types == other._variable_types + return ( + isinstance(other, InteractiveLPProblem) + and self.Abcx() == other.Abcx() + and self._constant_term == other._constant_term + and self._problem_type == other._problem_type + and self._is_negative == other._is_negative + and self._constraint_types == other._constraint_types + and self._variable_types == other._variable_types + ) def _latex_(self): r""" @@ -2007,7 +2015,9 @@ def add_constraint(self, coefficients, constant_term, slack_variable=None): if style() == 'Vanderbei': index = self.m() + 1 slack_variable = "{}{:d}".format(slack_variable, index) - return InteractiveLPProblemStandardForm(A, b, c, x, problem_type=problem_type, slack_variables=tuple(self.slack_variables()) + (slack_variable,), auxiliary_variable=self.auxiliary_variable(), base_ring=self.base_ring(), is_primal=self._is_primal, objective_name=self._objective_name, objective_constant_term=self.objective_constant_term()) + return InteractiveLPProblemStandardForm( + A, b, c, x, problem_type=problem_type, slack_variables=tuple(self.slack_variables()) + (slack_variable,), auxiliary_variable=self.auxiliary_variable(), base_ring=self.base_ring(), is_primal=self._is_primal, objective_name=self._objective_name, objective_constant_term=self.objective_constant_term() + ) def auxiliary_problem(self, objective_name=None): r""" diff --git a/src/sage/plot/arc.py b/src/sage/plot/arc.py index 81b65b6a05a..9bc7e8e2e02 100644 --- a/src/sage/plot/arc.py +++ b/src/sage/plot/arc.py @@ -250,7 +250,14 @@ def _allowed_options(self): sage: p[0]._allowed_options()['alpha'] 'How transparent the figure is.' """ - return {'alpha': 'How transparent the figure is.', 'thickness': 'How thick the border of the arc is.', 'hue': 'The color given as a hue.', 'rgbcolor': 'The color', 'zorder': '2D only: The layer level in which to draw', 'linestyle': "2D only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively."} + return { + 'alpha': 'How transparent the figure is.', + 'thickness': 'How thick the border of the arc is.', + 'hue': 'The color given as a hue.', + 'rgbcolor': 'The color', + 'zorder': '2D only: The layer level in which to draw', + 'linestyle': "2D only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively.", + } def _matplotlib_arc(self): """ diff --git a/src/sage/plot/arrow.py b/src/sage/plot/arrow.py index 4c104b3abcd..5dfb8afbc29 100644 --- a/src/sage/plot/arrow.py +++ b/src/sage/plot/arrow.py @@ -92,7 +92,19 @@ def _allowed_options(self): ('width', 'The width of the shaft of the arrow, in points.'), ('zorder', '2-d only: The layer level in which to draw')] """ - return {'width': 'The width of the shaft of the arrow, in points.', 'rgbcolor': 'The color as an RGB tuple.', 'hue': 'The color given as a hue.', 'legend_label': 'The label for this item in the legend.', 'legend_color': 'The color of the legend text.', 'arrowstyle': 'todo', 'arrowsize': 'The size of the arrowhead', 'thickness': 'The thickness of the arrow.', 'zorder': '2-d only: The layer level in which to draw', 'head': '2-d only: Which end of the path to draw the head (one of 0 (start), 1 (end) or 2 (both)', 'linestyle': "2d only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively."} + return { + 'width': 'The width of the shaft of the arrow, in points.', + 'rgbcolor': 'The color as an RGB tuple.', + 'hue': 'The color given as a hue.', + 'legend_label': 'The label for this item in the legend.', + 'legend_color': 'The color of the legend text.', + 'arrowstyle': 'todo', + 'arrowsize': 'The size of the arrowhead', + 'thickness': 'The thickness of the arrow.', + 'zorder': '2-d only: The layer level in which to draw', + 'head': '2-d only: Which end of the path to draw the head (one of 0 (start), 1 (end) or 2 (both)', + 'linestyle': "2d only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively.", + } def _repr_(self): """ @@ -220,7 +232,19 @@ def _allowed_options(self): ('width', 'The width of the shaft of the arrow, in points.'), ('zorder', '2-d only: The layer level in which to draw')] """ - return {'width': 'The width of the shaft of the arrow, in points.', 'rgbcolor': 'The color as an RGB tuple.', 'hue': 'The color given as a hue.', 'arrowshorten': 'The length in points to shorten the arrow.', 'arrowsize': 'The size of the arrowhead', 'thickness': 'The thickness of the arrow.', 'legend_label': 'The label for this item in the legend.', 'legend_color': 'The color of the legend text.', 'zorder': '2-d only: The layer level in which to draw', 'head': '2-d only: Which end of the path to draw the head (one of 0 (start), 1 (end) or 2 (both)', 'linestyle': "2d only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively."} + return { + 'width': 'The width of the shaft of the arrow, in points.', + 'rgbcolor': 'The color as an RGB tuple.', + 'hue': 'The color given as a hue.', + 'arrowshorten': 'The length in points to shorten the arrow.', + 'arrowsize': 'The size of the arrowhead', + 'thickness': 'The thickness of the arrow.', + 'legend_label': 'The label for this item in the legend.', + 'legend_color': 'The color of the legend text.', + 'zorder': '2-d only: The layer level in which to draw', + 'head': '2-d only: Which end of the path to draw the head (one of 0 (start), 1 (end) or 2 (both)', + 'linestyle': "2d only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively.", + } def _plot3d_options(self, options=None): """ @@ -352,7 +376,9 @@ def _render_on_subplot(self, subplot): color = to_mpl_color(options['rgbcolor']) from matplotlib.patches import FancyArrowPatch - p = FancyArrowPatch((self.xtail, self.ytail), (self.xhead, self.yhead), lw=width, arrowstyle='{},head_width={},head_length={}'.format(style, head_width, head_length), shrinkA=arrowshorten_end, shrinkB=arrowshorten_end, fc=color, ec=color, linestyle=get_matplotlib_linestyle(options['linestyle'], return_type='long')) + p = FancyArrowPatch( + (self.xtail, self.ytail), (self.xhead, self.yhead), lw=width, arrowstyle='{},head_width={},head_length={}'.format(style, head_width, head_length), shrinkA=arrowshorten_end, shrinkB=arrowshorten_end, fc=color, ec=color, linestyle=get_matplotlib_linestyle(options['linestyle'], return_type='long') + ) p.set_zorder(options['zorder']) p.set_label(options['legend_label']) diff --git a/src/sage/plot/bezier_path.py b/src/sage/plot/bezier_path.py index 02befa261a8..d6acf760a8f 100644 --- a/src/sage/plot/bezier_path.py +++ b/src/sage/plot/bezier_path.py @@ -114,7 +114,14 @@ def _allowed_options(self): ('thickness', 'How thick the border of the polygon is.'), ('zorder', 'The layer level in which to draw')] """ - return {'alpha': 'How transparent the line is.', 'fill': 'Whether or not to fill the polygon.', 'thickness': 'How thick the border of the polygon is.', 'rgbcolor': 'The color as an RGB tuple.', 'zorder': 'The layer level in which to draw', 'linestyle': "The style of the line, which is one of 'dashed'," " 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.'," " respectively."} + return { + 'alpha': 'How transparent the line is.', + 'fill': 'Whether or not to fill the polygon.', + 'thickness': 'How thick the border of the polygon is.', + 'rgbcolor': 'The color as an RGB tuple.', + 'zorder': 'The layer level in which to draw', + 'linestyle': "The style of the line, which is one of 'dashed'," " 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.'," " respectively.", + } def _plot3d_options(self, options=None): """ diff --git a/src/sage/plot/circle.py b/src/sage/plot/circle.py index 55774dca79a..6f15e24b5e9 100644 --- a/src/sage/plot/circle.py +++ b/src/sage/plot/circle.py @@ -109,7 +109,20 @@ def _allowed_options(self): sage: p[0]._allowed_options()['facecolor'] '2D only: The color of the face as an RGB tuple.' """ - return {'alpha': 'How transparent the figure is.', 'fill': 'Whether or not to fill the circle.', 'legend_label': 'The label for this item in the legend.', 'legend_color': 'The color of the legend text.', 'thickness': 'How thick the border of the circle is.', 'edgecolor': '2D only: The color of the edge as an RGB tuple.', 'facecolor': '2D only: The color of the face as an RGB tuple.', 'rgbcolor': 'The color (edge and face) as an RGB tuple.', 'hue': 'The color given as a hue.', 'zorder': '2D only: The layer level in which to draw', 'linestyle': "2D only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively.", 'clip': 'Whether or not to clip the circle.'} + return { + 'alpha': 'How transparent the figure is.', + 'fill': 'Whether or not to fill the circle.', + 'legend_label': 'The label for this item in the legend.', + 'legend_color': 'The color of the legend text.', + 'thickness': 'How thick the border of the circle is.', + 'edgecolor': '2D only: The color of the edge as an RGB tuple.', + 'facecolor': '2D only: The color of the face as an RGB tuple.', + 'rgbcolor': 'The color (edge and face) as an RGB tuple.', + 'hue': 'The color given as a hue.', + 'zorder': '2D only: The layer level in which to draw', + 'linestyle': "2D only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively.", + 'clip': 'Whether or not to clip the circle.', + } def _repr_(self): """ diff --git a/src/sage/plot/disk.py b/src/sage/plot/disk.py index d48d4f1db44..0463fa15d31 100644 --- a/src/sage/plot/disk.py +++ b/src/sage/plot/disk.py @@ -129,7 +129,16 @@ def _allowed_options(self): sage: p[0]._allowed_options()['zorder'] 'The layer level in which to draw' """ - return {'alpha': 'How transparent the figure is.', 'fill': 'Whether or not to fill the disk.', 'legend_label': 'The label for this item in the legend.', 'legend_color': 'The color of the legend text.', 'thickness': 'How thick the border of the disk is.', 'rgbcolor': 'The color as an RGB tuple.', 'hue': 'The color given as a hue.', 'zorder': 'The layer level in which to draw'} + return { + 'alpha': 'How transparent the figure is.', + 'fill': 'Whether or not to fill the disk.', + 'legend_label': 'The label for this item in the legend.', + 'legend_color': 'The color of the legend text.', + 'thickness': 'How thick the border of the disk is.', + 'rgbcolor': 'The color as an RGB tuple.', + 'hue': 'The color given as a hue.', + 'zorder': 'The layer level in which to draw', + } def _repr_(self): """ diff --git a/src/sage/plot/ellipse.py b/src/sage/plot/ellipse.py index 1b77fe805ef..f33108e8a8f 100644 --- a/src/sage/plot/ellipse.py +++ b/src/sage/plot/ellipse.py @@ -142,7 +142,19 @@ def _allowed_options(self): sage: p[0]._allowed_options()['facecolor'] '2D only: The color of the face as an RGB tuple.' """ - return {'alpha': 'How transparent the figure is.', 'fill': 'Whether or not to fill the ellipse.', 'legend_label': 'The label for this item in the legend.', 'legend_color': 'The color of the legend text.', 'thickness': 'How thick the border of the ellipse is.', 'edgecolor': '2D only: The color of the edge as an RGB tuple.', 'facecolor': '2D only: The color of the face as an RGB tuple.', 'rgbcolor': 'The color (edge and face) as an RGB tuple.', 'hue': 'The color given as a hue.', 'zorder': '2D only: The layer level in which to draw', 'linestyle': "2D only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively."} + return { + 'alpha': 'How transparent the figure is.', + 'fill': 'Whether or not to fill the ellipse.', + 'legend_label': 'The label for this item in the legend.', + 'legend_color': 'The color of the legend text.', + 'thickness': 'How thick the border of the ellipse is.', + 'edgecolor': '2D only: The color of the edge as an RGB tuple.', + 'facecolor': '2D only: The color of the face as an RGB tuple.', + 'rgbcolor': 'The color (edge and face) as an RGB tuple.', + 'hue': 'The color given as a hue.', + 'zorder': '2D only: The layer level in which to draw', + 'linestyle': "2D only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively.", + } def _repr_(self): """ diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index fcfa7086f13..5a72860914e 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -1452,7 +1452,27 @@ def _set_scale(self, subplot, scale=None, base=None): # Default options for the legends: - LEGEND_OPTIONS = {'back_color': 'white', 'borderpad': 0.6, 'borderaxespad': None, 'columnspacing': None, 'fancybox': False, 'font_family': 'sans-serif', 'font_size': 'medium', 'font_style': 'normal', 'font_variant': 'normal', 'font_weight': 'medium', 'handlelength': 0.05, 'handletextpad': 0.5, 'labelspacing': 0.02, 'loc': 'best', 'markerscale': 0.6, 'ncol': 1, 'numpoints': 2, 'shadow': True, 'title': None} + LEGEND_OPTIONS = { + 'back_color': 'white', + 'borderpad': 0.6, + 'borderaxespad': None, + 'columnspacing': None, + 'fancybox': False, + 'font_family': 'sans-serif', + 'font_size': 'medium', + 'font_style': 'normal', + 'font_variant': 'normal', + 'font_weight': 'medium', + 'handlelength': 0.05, + 'handletextpad': 0.5, + 'labelspacing': 0.02, + 'loc': 'best', + 'markerscale': 0.6, + 'ncol': 1, + 'numpoints': 2, + 'shadow': True, + 'title': None, + } @suboptions('legend', **LEGEND_OPTIONS) def show(self, **kwds): @@ -2599,7 +2619,42 @@ def _get_vmin_vmax(self, vmin, vmax, basev, axes_pad): return vmin, vmax - def matplotlib(self, filename=None, xmin=None, xmax=None, ymin=None, ymax=None, figsize=None, figure=None, sub=None, axes=None, axes_labels=None, axes_labels_size=None, flip_x=False, flip_y=False, fontsize=None, frame=False, verify=True, aspect_ratio=None, gridlines=None, gridlinesstyle=None, vgridlinesstyle=None, hgridlinesstyle=None, show_legend=None, legend_options=None, axes_pad=None, ticks_integer=None, tick_formatter=None, ticks=None, title=None, title_pos=None, base=None, scale=None, stylesheet=None, typeset='default'): + def matplotlib( + self, + filename=None, + xmin=None, + xmax=None, + ymin=None, + ymax=None, + figsize=None, + figure=None, + sub=None, + axes=None, + axes_labels=None, + axes_labels_size=None, + flip_x=False, + flip_y=False, + fontsize=None, + frame=False, + verify=True, + aspect_ratio=None, + gridlines=None, + gridlinesstyle=None, + vgridlinesstyle=None, + hgridlinesstyle=None, + show_legend=None, + legend_options=None, + axes_pad=None, + ticks_integer=None, + tick_formatter=None, + ticks=None, + title=None, + title_pos=None, + base=None, + scale=None, + stylesheet=None, + typeset='default', + ): r""" Construct or modify a Matplotlib figure by drawing ``self`` on it. diff --git a/src/sage/plot/hyperbolic_arc.py b/src/sage/plot/hyperbolic_arc.py index a4a968421b3..ecbc48fea1e 100644 --- a/src/sage/plot/hyperbolic_arc.py +++ b/src/sage/plot/hyperbolic_arc.py @@ -121,7 +121,11 @@ def _bezier_path(self, z0, z1, model, first=False): points = arc0.vertices else: points = arc0.bezier_path()[0].vertices - if ((z0.is_infinity() or z0 == infinity) and abs(CC(points[0][0], points[0][1]) - z1) < EPSILON) or ((z1.is_infinity() or z1 == infinity) and abs(CC(points[1][0], points[1][1]) - z0) < EPSILON) or (abs(CC(points[0][0], points[0][1]) - z0) >= EPSILON and not (z0.is_infinity() or z0 == infinity or z1.is_infinity() or z1 == infinity)): + if ( + ((z0.is_infinity() or z0 == infinity) and abs(CC(points[0][0], points[0][1]) - z1) < EPSILON) + or ((z1.is_infinity() or z1 == infinity) and abs(CC(points[1][0], points[1][1]) - z0) < EPSILON) + or (abs(CC(points[0][0], points[0][1]) - z0) >= EPSILON and not (z0.is_infinity() or z0 == infinity or z1.is_infinity() or z1 == infinity)) + ): points = np.flipud(points) # order is important if first: diff --git a/src/sage/plot/line.py b/src/sage/plot/line.py index 4ee44d79980..8781bfa8556 100644 --- a/src/sage/plot/line.py +++ b/src/sage/plot/line.py @@ -75,7 +75,21 @@ def _allowed_options(self): ('thickness', 'How thick the line is.'), ('zorder', 'The layer level in which to draw')] """ - return {'alpha': 'How transparent the line is.', 'legend_color': 'The color of the legend text.', 'legend_label': 'The label for this item in the legend.', 'thickness': 'How thick the line is.', 'rgbcolor': 'The color as an RGB tuple.', 'hue': 'The color given as a hue.', 'linestyle': "The style of the line, which is one of '--' (dashed), '-.' (dash dot), '-' (solid), 'steps', ':' (dotted).", 'marker': "the marker symbol (see documentation for line2d for details)", 'markersize': 'the size of the marker in points', 'markeredgecolor': 'the color of the marker edge', 'markeredgewidth': 'the size of the marker edge in points', 'markerfacecolor': 'the color of the marker face', 'zorder': 'The layer level in which to draw'} + return { + 'alpha': 'How transparent the line is.', + 'legend_color': 'The color of the legend text.', + 'legend_label': 'The label for this item in the legend.', + 'thickness': 'How thick the line is.', + 'rgbcolor': 'The color as an RGB tuple.', + 'hue': 'The color given as a hue.', + 'linestyle': "The style of the line, which is one of '--' (dashed), '-.' (dash dot), '-' (solid), 'steps', ':' (dotted).", + 'marker': "the marker symbol (see documentation for line2d for details)", + 'markersize': 'the size of the marker in points', + 'markeredgecolor': 'the color of the marker edge', + 'markeredgewidth': 'the size of the marker edge in points', + 'markerfacecolor': 'the color of the marker face', + 'zorder': 'The layer level in which to draw', + } def _plot3d_options(self, options=None): """ diff --git a/src/sage/plot/plot3d/shapes2.py b/src/sage/plot/plot3d/shapes2.py index 9a139747703..39d8be3f302 100644 --- a/src/sage/plot/plot3d/shapes2.py +++ b/src/sage/plot/plot3d/shapes2.py @@ -717,7 +717,11 @@ def ruler_frame(lower_left, upper_right, ticks=4, sub_ticks=4, **kwds): from sage.plot.plot3d.shapes2 import ruler_frame sphinx_plot(ruler_frame([1,2,3],vector([2,3,4]),ticks=6, sub_ticks=2, color='red')) """ - return ruler(lower_left, (upper_right[0], lower_left[1], lower_left[2]), ticks=ticks, sub_ticks=sub_ticks, absolute=True, **kwds) + ruler(lower_left, (lower_left[0], upper_right[1], lower_left[2]), ticks=ticks, sub_ticks=sub_ticks, absolute=True, **kwds) + ruler(lower_left, (lower_left[0], lower_left[1], upper_right[2]), ticks=ticks, sub_ticks=sub_ticks, absolute=True, **kwds) + return ( + ruler(lower_left, (upper_right[0], lower_left[1], lower_left[2]), ticks=ticks, sub_ticks=sub_ticks, absolute=True, **kwds) + + ruler(lower_left, (lower_left[0], upper_right[1], lower_left[2]), ticks=ticks, sub_ticks=sub_ticks, absolute=True, **kwds) + + ruler(lower_left, (lower_left[0], lower_left[1], upper_right[2]), ticks=ticks, sub_ticks=sub_ticks, absolute=True, **kwds) + ) ########################### diff --git a/src/sage/plot/plot3d/tachyon.py b/src/sage/plot/plot3d/tachyon.py index 10d3af97a6a..a5799575fe0 100644 --- a/src/sage/plot/plot3d/tachyon.py +++ b/src/sage/plot/plot3d/tachyon.py @@ -367,7 +367,9 @@ class Tachyon(WithEqualityById, SageObject): 140658972348064 """ - def __init__(self, xres=350, yres=350, zoom=1.0, antialiasing=False, aspectratio=1.0, raydepth=8, camera_position=None, camera_center=None, updir=[0, 0, 1], look_at=[0, 0, 0], viewdir=None, projection='PERSPECTIVE', focallength='', aperture='', frustum=''): # default value (-3, 0, 0), # alternative equivalent name + def __init__( + self, xres=350, yres=350, zoom=1.0, antialiasing=False, aspectratio=1.0, raydepth=8, camera_position=None, camera_center=None, updir=[0, 0, 1], look_at=[0, 0, 0], viewdir=None, projection='PERSPECTIVE', focallength='', aperture='', frustum='' + ): # default value (-3, 0, 0), # alternative equivalent name r""" Create an instance of the Tachyon class. diff --git a/src/sage/plot/plot_field.py b/src/sage/plot/plot_field.py index d123d96db2b..a3e2fd52690 100644 --- a/src/sage/plot/plot_field.py +++ b/src/sage/plot/plot_field.py @@ -99,7 +99,15 @@ def _allowed_options(self): sage: d['pivot'] 'Where the arrow should be placed in relation to the point (tail, middle, tip)' """ - return {'plot_points': 'How many points to use for plotting precision', 'pivot': 'Where the arrow should be placed in relation to the point (tail, middle, tip)', 'headwidth': 'Head width as multiple of shaft width, default is 3', 'headlength': 'head length as multiple of shaft width, default is 5', 'headaxislength': 'head length at shaft intersection, default is 4.5', 'zorder': 'The layer level in which to draw', 'color': 'The color of the arrows'} + return { + 'plot_points': 'How many points to use for plotting precision', + 'pivot': 'Where the arrow should be placed in relation to the point (tail, middle, tip)', + 'headwidth': 'Head width as multiple of shaft width, default is 3', + 'headlength': 'head length as multiple of shaft width, default is 5', + 'headaxislength': 'head length at shaft intersection, default is 4.5', + 'zorder': 'The layer level in which to draw', + 'color': 'The color of the arrows', + } def _repr_(self): """ diff --git a/src/sage/plot/point.py b/src/sage/plot/point.py index 0e08e3c57f7..b006612d163 100644 --- a/src/sage/plot/point.py +++ b/src/sage/plot/point.py @@ -94,7 +94,18 @@ def _allowed_options(self): sage: P[0]._allowed_options()['size'] 'How big the point is (i.e., area in points^2=(1/72 inch)^2).' """ - return {'alpha': 'How transparent the point is.', 'faceted': 'If True color the edge of the point. (only for 2D plots)', 'hue': 'The color given as a hue.', 'legend_color': 'The color of the legend text', 'legend_label': 'The label for this item in the legend.', 'marker': 'the marker symbol for 2D plots only (see documentation of plot() for details)', 'markeredgecolor': 'the color of the marker edge (only for 2D plots)', 'rgbcolor': 'The color as an RGB tuple.', 'size': 'How big the point is (i.e., area in points^2=(1/72 inch)^2).', 'zorder': 'The layer level in which to draw'} + return { + 'alpha': 'How transparent the point is.', + 'faceted': 'If True color the edge of the point. (only for 2D plots)', + 'hue': 'The color given as a hue.', + 'legend_color': 'The color of the legend text', + 'legend_label': 'The label for this item in the legend.', + 'marker': 'the marker symbol for 2D plots only (see documentation of plot() for details)', + 'markeredgecolor': 'the color of the marker edge (only for 2D plots)', + 'rgbcolor': 'The color as an RGB tuple.', + 'size': 'How big the point is (i.e., area in points^2=(1/72 inch)^2).', + 'zorder': 'The layer level in which to draw', + } def _plot3d_options(self, options=None): """ diff --git a/src/sage/plot/polygon.py b/src/sage/plot/polygon.py index b4712430f7a..7c326d8cd37 100644 --- a/src/sage/plot/polygon.py +++ b/src/sage/plot/polygon.py @@ -157,7 +157,18 @@ def _allowed_options(self): sage: P[0]._allowed_options()['alpha'] 'How transparent the figure is.' """ - return {'alpha': 'How transparent the figure is.', 'thickness': 'How thick the border line is.', 'edgecolor': 'The color for the border of filled polygons.', 'fill': 'Whether or not to fill the polygon.', 'legend_label': 'The label for this item in the legend.', 'legend_color': 'The color of the legend text.', 'linestyle': 'The style of the enclosing line.', 'rgbcolor': 'The color as an RGB tuple.', 'hue': 'The color given as a hue.', 'zorder': 'The layer level in which to draw'} + return { + 'alpha': 'How transparent the figure is.', + 'thickness': 'How thick the border line is.', + 'edgecolor': 'The color for the border of filled polygons.', + 'fill': 'Whether or not to fill the polygon.', + 'legend_label': 'The label for this item in the legend.', + 'legend_color': 'The color of the legend text.', + 'linestyle': 'The style of the enclosing line.', + 'rgbcolor': 'The color as an RGB tuple.', + 'hue': 'The color given as a hue.', + 'zorder': 'The layer level in which to draw', + } def _plot3d_options(self, options=None): """ diff --git a/src/sage/plot/scatter_plot.py b/src/sage/plot/scatter_plot.py index 0d9d221748d..e2fb831e9b9 100644 --- a/src/sage/plot/scatter_plot.py +++ b/src/sage/plot/scatter_plot.py @@ -89,7 +89,17 @@ def _allowed_options(self): ('rgbcolor', 'The color as an RGB tuple.'), ('zorder', 'The layer level in which to draw.')] """ - return {'markersize': 'the size of the markers.', 'marker': 'What shape to plot the points. See the documentation of plot() for the full list of markers.', 'alpha': 'How transparent the marker border is.', 'rgbcolor': 'The color as an RGB tuple.', 'hue': 'The color given as a hue.', 'facecolor': 'The color of the marker face.', 'edgecolor': 'The color of the marker border.', 'zorder': 'The layer level in which to draw.', 'clip': 'Whether or not to clip.'} + return { + 'markersize': 'the size of the markers.', + 'marker': 'What shape to plot the points. See the documentation of plot() for the full list of markers.', + 'alpha': 'How transparent the marker border is.', + 'rgbcolor': 'The color as an RGB tuple.', + 'hue': 'The color given as a hue.', + 'facecolor': 'The color of the marker face.', + 'edgecolor': 'The color of the marker border.', + 'zorder': 'The layer level in which to draw.', + 'clip': 'Whether or not to clip.', + } def _repr_(self): """ diff --git a/src/sage/quadratic_forms/quadratic_form__mass.py b/src/sage/quadratic_forms/quadratic_form__mass.py index e259a23a702..cccd68835f6 100644 --- a/src/sage/quadratic_forms/quadratic_form__mass.py +++ b/src/sage/quadratic_forms/quadratic_form__mass.py @@ -8,7 +8,21 @@ # Import all general mass finding routines from sage.quadratic_forms.quadratic_form__mass__Siegel_densities import mass__by_Siegel_densities, Pall_mass_density_at_odd_prime, Watson_mass_at_2, Kitaoka_mass_at_2, mass_at_two_by_counting_mod_power -from sage.quadratic_forms.quadratic_form__mass__Conway_Sloane_masses import parity, is_even, is_odd, conway_species_list_at_odd_prime, conway_species_list_at_2, conway_octane_of_this_unimodular_Jordan_block_at_2, conway_diagonal_factor, conway_cross_product_doubled_power, conway_type_factor, conway_p_mass, conway_standard_p_mass, conway_standard_mass, conway_mass +from sage.quadratic_forms.quadratic_form__mass__Conway_Sloane_masses import ( + parity, + is_even, + is_odd, + conway_species_list_at_odd_prime, + conway_species_list_at_2, + conway_octane_of_this_unimodular_Jordan_block_at_2, + conway_diagonal_factor, + conway_cross_product_doubled_power, + conway_type_factor, + conway_p_mass, + conway_standard_p_mass, + conway_standard_mass, + conway_mass, +) # conway_generic_mass, \ # conway_p_mass_adjustment diff --git a/src/sage/quadratic_forms/ternary_qf.py b/src/sage/quadratic_forms/ternary_qf.py index 4f1195f3f44..f0af3a119ed 100644 --- a/src/sage/quadratic_forms/ternary_qf.py +++ b/src/sage/quadratic_forms/ternary_qf.py @@ -1278,7 +1278,20 @@ def _automorphisms_reduced_fast(self): if self._border(10): if self._border(8): # borders 4, 8, 10 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, -1, 1, 0, 0, 0, -1), (-1, 0, 0, 0, -1, 0, 0, 0, 1), (-1, 1, 0, -1, 0, 0, 0, 0, 1), (-1, 1, 0, 0, 1, 0, 0, 0, -1), (0, -1, 0, -1, 0, 0, 0, 0, -1), (0, -1, 0, 1, -1, 0, 0, 0, 1), (0, 1, 0, -1, 1, 0, 0, 0, 1), (0, 1, 0, 1, 0, 0, 0, 0, -1), (1, -1, 0, 0, -1, 0, 0, 0, -1), (1, -1, 0, 1, 0, 0, 0, 0, 1), (1, 0, 0, 1, -1, 0, 0, 0, -1)] + return [ + (1, 0, 0, 0, 1, 0, 0, 0, 1), + (-1, 0, 0, -1, 1, 0, 0, 0, -1), + (-1, 0, 0, 0, -1, 0, 0, 0, 1), + (-1, 1, 0, -1, 0, 0, 0, 0, 1), + (-1, 1, 0, 0, 1, 0, 0, 0, -1), + (0, -1, 0, -1, 0, 0, 0, 0, -1), + (0, -1, 0, 1, -1, 0, 0, 0, 1), + (0, 1, 0, -1, 1, 0, 0, 0, 1), + (0, 1, 0, 1, 0, 0, 0, 0, -1), + (1, -1, 0, 0, -1, 0, 0, 0, -1), + (1, -1, 0, 1, 0, 0, 0, 0, 1), + (1, 0, 0, 1, -1, 0, 0, 0, -1), + ] # borders 4, 10 return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, -1, 0, 0, 0, 1), (-1, 1, 0, 0, 1, 0, 0, 0, -1), (1, -1, 0, 0, -1, 0, 0, 0, -1)] # borders 4 @@ -1305,7 +1318,20 @@ def _automorphisms_reduced_fast(self): if self._border(12): if self._border(9): # borders 6, 9, 12 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, -1, 0, 0, -1, 1), (-1, 0, 0, 0, -1, 1, 0, 0, 1), (-1, 0, 0, 0, 0, -1, 0, -1, 0), (-1, 0, 0, 0, 0, 1, 0, 1, 0), (-1, 0, 0, 0, 1, -1, 0, 0, -1), (-1, 0, 0, 0, 1, 0, 0, 1, -1), (1, 0, 0, 0, -1, 0, 0, 0, -1), (1, 0, 0, 0, -1, 1, 0, -1, 0), (1, 0, 0, 0, 0, -1, 0, 1, -1), (1, 0, 0, 0, 0, 1, 0, -1, 1), (1, 0, 0, 0, 1, -1, 0, 1, 0)] + return [ + (1, 0, 0, 0, 1, 0, 0, 0, 1), + (-1, 0, 0, 0, -1, 0, 0, -1, 1), + (-1, 0, 0, 0, -1, 1, 0, 0, 1), + (-1, 0, 0, 0, 0, -1, 0, -1, 0), + (-1, 0, 0, 0, 0, 1, 0, 1, 0), + (-1, 0, 0, 0, 1, -1, 0, 0, -1), + (-1, 0, 0, 0, 1, 0, 0, 1, -1), + (1, 0, 0, 0, -1, 0, 0, 0, -1), + (1, 0, 0, 0, -1, 1, 0, -1, 0), + (1, 0, 0, 0, 0, -1, 0, 1, -1), + (1, 0, 0, 0, 0, 1, 0, -1, 1), + (1, 0, 0, 0, 1, -1, 0, 1, 0), + ] # borders 6, 12 return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, -1, 1, 0, 0, 1), (-1, 0, 0, 0, 1, -1, 0, 0, -1), (1, 0, 0, 0, -1, 0, 0, 0, -1)] # borders 6 @@ -1316,7 +1342,32 @@ def _automorphisms_reduced_fast(self): if self._border(16): if self._border(9): # borders 7, 8, 9, 15, 16 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, -1, 0, 1, -1, 1, 0), (-1, 0, 0, 0, 0, -1, 0, -1, 0), (-1, 0, 1, -1, 1, 0, -1, 0, 0), (-1, 0, 1, 0, -1, 1, 0, 0, 1), (-1, 1, 0, -1, 0, 0, -1, 0, 1), (-1, 1, 0, 0, 1, 0, 0, 1, -1), (0, -1, 0, -1, 0, 0, 0, 0, -1), (0, -1, 0, 1, -1, 0, 0, -1, 1), (0, -1, 1, 0, -1, 0, 1, -1, 0), (0, -1, 1, 0, 0, 1, -1, 0, 1), (0, 0, -1, 0, -1, 0, -1, 0, 0), (0, 0, -1, 0, 1, -1, 1, 0, -1), (0, 0, 1, -1, 0, 1, 0, -1, 1), (0, 0, 1, 1, 0, 0, 0, 1, 0), (0, 1, -1, -1, 1, 0, 0, 1, 0), (0, 1, -1, 1, 0, -1, 0, 0, -1), (0, 1, 0, 0, 0, 1, 1, 0, 0), (0, 1, 0, 0, 1, -1, -1, 1, 0), (1, -1, 0, 0, -1, 1, 0, -1, 0), (1, -1, 0, 1, 0, -1, 1, 0, 0), (1, 0, -1, 0, 0, -1, 0, 1, -1), (1, 0, -1, 1, 0, 0, 1, -1, 0), (1, 0, 0, 1, -1, 0, 1, 0, -1)] + return [ + (1, 0, 0, 0, 1, 0, 0, 0, 1), + (-1, 0, 0, -1, 0, 1, -1, 1, 0), + (-1, 0, 0, 0, 0, -1, 0, -1, 0), + (-1, 0, 1, -1, 1, 0, -1, 0, 0), + (-1, 0, 1, 0, -1, 1, 0, 0, 1), + (-1, 1, 0, -1, 0, 0, -1, 0, 1), + (-1, 1, 0, 0, 1, 0, 0, 1, -1), + (0, -1, 0, -1, 0, 0, 0, 0, -1), + (0, -1, 0, 1, -1, 0, 0, -1, 1), + (0, -1, 1, 0, -1, 0, 1, -1, 0), + (0, -1, 1, 0, 0, 1, -1, 0, 1), + (0, 0, -1, 0, -1, 0, -1, 0, 0), + (0, 0, -1, 0, 1, -1, 1, 0, -1), + (0, 0, 1, -1, 0, 1, 0, -1, 1), + (0, 0, 1, 1, 0, 0, 0, 1, 0), + (0, 1, -1, -1, 1, 0, 0, 1, 0), + (0, 1, -1, 1, 0, -1, 0, 0, -1), + (0, 1, 0, 0, 0, 1, 1, 0, 0), + (0, 1, 0, 0, 1, -1, -1, 1, 0), + (1, -1, 0, 0, -1, 1, 0, -1, 0), + (1, -1, 0, 1, 0, -1, 1, 0, 0), + (1, 0, -1, 0, 0, -1, 0, 1, -1), + (1, 0, -1, 1, 0, 0, 1, -1, 0), + (1, 0, 0, 1, -1, 0, 1, 0, -1), + ] # borders 7, 8, 15, 16 return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, -1, 0, 1, -1, 1, 0), (-1, 0, 1, 0, -1, 1, 0, 0, 1), (0, -1, 0, -1, 0, 0, 0, 0, -1), (0, -1, 1, 0, -1, 0, 1, -1, 0), (0, 1, -1, 1, 0, -1, 0, 0, -1), (0, 1, 0, 0, 1, -1, -1, 1, 0), (1, 0, -1, 1, 0, 0, 1, -1, 0)] # borders 7, 8, 15 @@ -1331,10 +1382,60 @@ def _automorphisms_reduced_fast(self): if self._border(9): if self._border(10) and self._border(11) and self._border(12): # borders 8, 9, 10, 11, 12 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, -1, 0, 0, 0, 1), (-1, 0, 0, 0, 0, -1, 0, -1, 0), (-1, 0, 0, 0, 0, 1, 0, 1, 0), (-1, 0, 0, 0, 1, 0, 0, 0, -1), (0, -1, 0, -1, 0, 0, 0, 0, -1), (0, -1, 0, 0, 0, -1, 1, 0, 0), (0, -1, 0, 0, 0, 1, -1, 0, 0), (0, -1, 0, 1, 0, 0, 0, 0, 1), (0, 0, -1, -1, 0, 0, 0, 1, 0), (0, 0, -1, 0, -1, 0, -1, 0, 0), (0, 0, -1, 0, 1, 0, 1, 0, 0), (0, 0, -1, 1, 0, 0, 0, -1, 0), (0, 0, 1, -1, 0, 0, 0, -1, 0), (0, 0, 1, 0, -1, 0, 1, 0, 0), (0, 0, 1, 0, 1, 0, -1, 0, 0), (0, 0, 1, 1, 0, 0, 0, 1, 0), (0, 1, 0, -1, 0, 0, 0, 0, 1), (0, 1, 0, 0, 0, -1, -1, 0, 0), (0, 1, 0, 0, 0, 1, 1, 0, 0), (0, 1, 0, 1, 0, 0, 0, 0, -1), (1, 0, 0, 0, -1, 0, 0, 0, -1), (1, 0, 0, 0, 0, -1, 0, 1, 0), (1, 0, 0, 0, 0, 1, 0, -1, 0)] + return [ + (1, 0, 0, 0, 1, 0, 0, 0, 1), + (-1, 0, 0, 0, -1, 0, 0, 0, 1), + (-1, 0, 0, 0, 0, -1, 0, -1, 0), + (-1, 0, 0, 0, 0, 1, 0, 1, 0), + (-1, 0, 0, 0, 1, 0, 0, 0, -1), + (0, -1, 0, -1, 0, 0, 0, 0, -1), + (0, -1, 0, 0, 0, -1, 1, 0, 0), + (0, -1, 0, 0, 0, 1, -1, 0, 0), + (0, -1, 0, 1, 0, 0, 0, 0, 1), + (0, 0, -1, -1, 0, 0, 0, 1, 0), + (0, 0, -1, 0, -1, 0, -1, 0, 0), + (0, 0, -1, 0, 1, 0, 1, 0, 0), + (0, 0, -1, 1, 0, 0, 0, -1, 0), + (0, 0, 1, -1, 0, 0, 0, -1, 0), + (0, 0, 1, 0, -1, 0, 1, 0, 0), + (0, 0, 1, 0, 1, 0, -1, 0, 0), + (0, 0, 1, 1, 0, 0, 0, 1, 0), + (0, 1, 0, -1, 0, 0, 0, 0, 1), + (0, 1, 0, 0, 0, -1, -1, 0, 0), + (0, 1, 0, 0, 0, 1, 1, 0, 0), + (0, 1, 0, 1, 0, 0, 0, 0, -1), + (1, 0, 0, 0, -1, 0, 0, 0, -1), + (1, 0, 0, 0, 0, -1, 0, 1, 0), + (1, 0, 0, 0, 0, 1, 0, -1, 0), + ] if self._border(13) and self._border(14): # borders 8, 9, 13, 14 - return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, -1, -1, 0, 0, 1, 0, 1, 0), (-1, -1, -1, 0, 1, 0, 1, 0, 0), (-1, -1, -1, 1, 0, 0, 0, 0, 1), (-1, 0, 0, 0, -1, 0, 1, 1, 1), (-1, 0, 0, 0, 0, -1, 0, -1, 0), (-1, 0, 0, 1, 1, 1, 0, 0, -1), (0, -1, 0, -1, 0, 0, 0, 0, -1), (0, -1, 0, 0, 0, -1, 1, 1, 1), (0, -1, 0, 1, 1, 1, -1, 0, 0), (0, 0, -1, -1, 0, 0, 1, 1, 1), (0, 0, -1, 0, -1, 0, -1, 0, 0), (0, 0, -1, 1, 1, 1, 0, -1, 0), (0, 0, 1, -1, -1, -1, 1, 0, 0), (0, 0, 1, 0, 1, 0, -1, -1, -1), (0, 0, 1, 1, 0, 0, 0, 1, 0), (0, 1, 0, -1, -1, -1, 0, 0, 1), (0, 1, 0, 0, 0, 1, 1, 0, 0), (0, 1, 0, 1, 0, 0, -1, -1, -1), (1, 0, 0, -1, -1, -1, 0, 1, 0), (1, 0, 0, 0, 0, 1, -1, -1, -1), (1, 1, 1, -1, 0, 0, 0, -1, 0), (1, 1, 1, 0, -1, 0, 0, 0, -1), (1, 1, 1, 0, 0, -1, -1, 0, 0)] + return [ + (1, 0, 0, 0, 1, 0, 0, 0, 1), + (-1, -1, -1, 0, 0, 1, 0, 1, 0), + (-1, -1, -1, 0, 1, 0, 1, 0, 0), + (-1, -1, -1, 1, 0, 0, 0, 0, 1), + (-1, 0, 0, 0, -1, 0, 1, 1, 1), + (-1, 0, 0, 0, 0, -1, 0, -1, 0), + (-1, 0, 0, 1, 1, 1, 0, 0, -1), + (0, -1, 0, -1, 0, 0, 0, 0, -1), + (0, -1, 0, 0, 0, -1, 1, 1, 1), + (0, -1, 0, 1, 1, 1, -1, 0, 0), + (0, 0, -1, -1, 0, 0, 1, 1, 1), + (0, 0, -1, 0, -1, 0, -1, 0, 0), + (0, 0, -1, 1, 1, 1, 0, -1, 0), + (0, 0, 1, -1, -1, -1, 1, 0, 0), + (0, 0, 1, 0, 1, 0, -1, -1, -1), + (0, 0, 1, 1, 0, 0, 0, 1, 0), + (0, 1, 0, -1, -1, -1, 0, 0, 1), + (0, 1, 0, 0, 0, 1, 1, 0, 0), + (0, 1, 0, 1, 0, 0, -1, -1, -1), + (1, 0, 0, -1, -1, -1, 0, 1, 0), + (1, 0, 0, 0, 0, 1, -1, -1, -1), + (1, 1, 1, -1, 0, 0, 0, -1, 0), + (1, 1, 1, 0, -1, 0, 0, 0, -1), + (1, 1, 1, 0, 0, -1, -1, 0, 0), + ] # borders 8, 9 return [(1, 0, 0, 0, 1, 0, 0, 0, 1), (-1, 0, 0, 0, 0, -1, 0, -1, 0), (0, -1, 0, -1, 0, 0, 0, 0, -1), (0, 0, -1, 0, -1, 0, -1, 0, 0), (0, 0, 1, 1, 0, 0, 0, 1, 0), (0, 1, 0, 0, 0, 1, 1, 0, 0)] if self._border(10): diff --git a/src/sage/rings/finite_rings/integer_mod_ring.py b/src/sage/rings/finite_rings/integer_mod_ring.py index c6bc3bcdacd..071cf6e4fa6 100644 --- a/src/sage/rings/finite_rings/integer_mod_ring.py +++ b/src/sage/rings/finite_rings/integer_mod_ring.py @@ -724,7 +724,16 @@ def is_field(self, proof=None): self._factory_data[3]['category'] = Fields() else: if self.category().is_subcategory(Fields()): - raise ValueError(("THIS SAGE SESSION MIGHT BE SERIOUSLY COMPROMISED!\n" "The order {} is not prime, but this ring has been put\n" "into the category of fields. This may already have consequences\n" "in other parts of Sage. Either it was a mistake of the user,\n" "or a probabilistic primality test has failed.\n" "In the latter case, please inform the developers.").format(self.order())) + raise ValueError( + ( + "THIS SAGE SESSION MIGHT BE SERIOUSLY COMPROMISED!\n" + "The order {} is not prime, but this ring has been put\n" + "into the category of fields. This may already have consequences\n" + "in other parts of Sage. Either it was a mistake of the user,\n" + "or a probabilistic primality test has failed.\n" + "In the latter case, please inform the developers." + ).format(self.order()) + ) return is_prime @cached_method diff --git a/src/sage/rings/invariants/invariant_theory.py b/src/sage/rings/invariants/invariant_theory.py index 6cb7269a749..5aee3a34b25 100644 --- a/src/sage/rings/invariants/invariant_theory.py +++ b/src/sage/rings/invariants/invariant_theory.py @@ -1568,7 +1568,15 @@ def h_covariant(self): xpow = [x0**6, x0**5 * x1, x0**4 * x1**2, x0**3 * x1**3, x0**2 * x1**4, x0 * x1**5, x1**6] else: xpow = [x0**6, x0**5, x0**4, x0**3, x0**2, x0, x0.parent().one()] - return (-2 * a3**3 + 3 * a2 * a3 * a4 - a1 * a4**2) * xpow[0] + (-6 * a2 * a3**2 + 9 * a2**2 * a4 - 2 * a1 * a3 * a4 - a0 * a4**2) * xpow[1] + 5 * (-2 * a1 * a3**2 + 3 * a1 * a2 * a4 - a0 * a3 * a4) * xpow[2] + 10 * (-a0 * a3**2 + a1**2 * a4) * xpow[3] + 5 * (2 * a1**2 * a3 - 3 * a0 * a2 * a3 + a0 * a1 * a4) * xpow[4] + (6 * a1**2 * a2 - 9 * a0 * a2**2 + 2 * a0 * a1 * a3 + a0**2 * a4) * xpow[5] + (2 * a1**3 - 3 * a0 * a1 * a2 + a0**2 * a3) * xpow[6] + return ( + (-2 * a3**3 + 3 * a2 * a3 * a4 - a1 * a4**2) * xpow[0] + + (-6 * a2 * a3**2 + 9 * a2**2 * a4 - 2 * a1 * a3 * a4 - a0 * a4**2) * xpow[1] + + 5 * (-2 * a1 * a3**2 + 3 * a1 * a2 * a4 - a0 * a3 * a4) * xpow[2] + + 10 * (-a0 * a3**2 + a1**2 * a4) * xpow[3] + + 5 * (2 * a1**2 * a3 - 3 * a0 * a2 * a3 + a0 * a1 * a4) * xpow[4] + + (6 * a1**2 * a2 - 9 * a0 * a2**2 + 2 * a0 * a1 * a3 + a0**2 * a4) * xpow[5] + + (2 * a1**3 - 3 * a0 * a1 * a2 + a0**2 * a3) * xpow[6] + ) ###################################################################### @@ -2438,7 +2446,14 @@ def _covariant_conic(A_scaled_coeffs, B_scaled_coeffs, monomials): """ a0, b0, c0, h0, g0, f0 = A_scaled_coeffs a1, b1, c1, h1, g1, f1 = B_scaled_coeffs - return (b0 * c1 + c0 * b1 - 2 * f0 * f1) * monomials[0] + (a0 * c1 + c0 * a1 - 2 * g0 * g1) * monomials[1] + (a0 * b1 + b0 * a1 - 2 * h0 * h1) * monomials[2] + 2 * (f0 * g1 + g0 * f1 - c0 * h1 - h0 * c1) * monomials[3] + 2 * (h0 * f1 + f0 * h1 - b0 * g1 - g0 * b1) * monomials[4] + 2 * (g0 * h1 + h0 * g1 - a0 * f1 - f0 * a1) * monomials[5] + return ( + (b0 * c1 + c0 * b1 - 2 * f0 * f1) * monomials[0] + + (a0 * c1 + c0 * a1 - 2 * g0 * g1) * monomials[1] + + (a0 * b1 + b0 * a1 - 2 * h0 * h1) * monomials[2] + + 2 * (f0 * g1 + g0 * f1 - c0 * h1 - h0 * c1) * monomials[3] + + 2 * (h0 * f1 + f0 * h1 - b0 * g1 - g0 * b1) * monomials[4] + + 2 * (g0 * h1 + h0 * g1 - a0 * f1 - f0 * a1) * monomials[5] + ) ###################################################################### @@ -2758,7 +2773,17 @@ def S_invariant(self): -1/1296 """ a, b, c, a2, a3, b1, b3, c1, c2, m = self.scaled_coeffs() - S = a * b * c * m - (b * c * a2 * a3 + c * a * b1 * b3 + a * b * c1 * c2) - m * (a * b3 * c2 + b * c1 * a3 + c * a2 * b1) + (a * b1 * c2**2 + a * c1 * b3**2 + b * a2 * c1**2 + b * c2 * a3**2 + c * b3 * a2**2 + c * a3 * b1**2) - m**4 + 2 * m**2 * (b1 * c1 + c2 * a2 + a3 * b3) - 3 * m * (a2 * b3 * c1 + a3 * b1 * c2) - (b1**2 * c1**2 + c2**2 * a2**2 + a3**2 * b3**2) + (c2 * a2 * a3 * b3 + a3 * b3 * b1 * c1 + b1 * c1 * c2 * a2) + S = ( + a * b * c * m + - (b * c * a2 * a3 + c * a * b1 * b3 + a * b * c1 * c2) + - m * (a * b3 * c2 + b * c1 * a3 + c * a2 * b1) + + (a * b1 * c2**2 + a * c1 * b3**2 + b * a2 * c1**2 + b * c2 * a3**2 + c * b3 * a2**2 + c * a3 * b1**2) + - m**4 + + 2 * m**2 * (b1 * c1 + c2 * a2 + a3 * b3) + - 3 * m * (a2 * b3 * c1 + a3 * b1 * c2) + - (b1**2 * c1**2 + c2**2 * a2**2 + a3**2 * b3**2) + + (c2 * a2 * a3 * b3 + a3 * b3 * b1 * c1 + b1 * c1 * c2 * a2) + ) return S def T_invariant(self): @@ -3452,7 +3477,19 @@ def syzygy(self, Delta, Theta, Theta_prime, Delta_prime, S, S_prime, F, J): 1/64*x^2 + 1 """ R = self._ring.base_ring() - return J**2 / R(64) + F**3 - 2 * F**2 * Theta * S_prime - 2 * F**2 * Theta_prime * S + F * S**2 * (Delta_prime * Theta + Theta_prime**2) + F * S_prime**2 * (Delta * Theta_prime + Theta**2) + 3 * F * S * S_prime * (Theta * Theta_prime - Delta * Delta_prime) + S**3 * (Delta_prime**2 * Delta - Theta * Theta_prime * Delta_prime) + S_prime**3 * (Delta**2 * Delta_prime - Theta_prime * Theta * Delta) + S**2 * S_prime * (Delta_prime * Delta * Theta_prime - Theta * Theta_prime**2) + S * S_prime**2 * (Delta * Delta_prime * Theta - Theta_prime * Theta**2) + return ( + J**2 / R(64) + + F**3 + - 2 * F**2 * Theta * S_prime + - 2 * F**2 * Theta_prime * S + + F * S**2 * (Delta_prime * Theta + Theta_prime**2) + + F * S_prime**2 * (Delta * Theta_prime + Theta**2) + + 3 * F * S * S_prime * (Theta * Theta_prime - Delta * Delta_prime) + + S**3 * (Delta_prime**2 * Delta - Theta * Theta_prime * Delta_prime) + + S_prime**3 * (Delta**2 * Delta_prime - Theta_prime * Theta * Delta) + + S**2 * S_prime * (Delta_prime * Delta * Theta_prime - Theta * Theta_prime**2) + + S * S_prime**2 * (Delta * Delta_prime * Theta - Theta_prime * Theta**2) + ) ###################################################################### @@ -4064,11 +4101,27 @@ def syzygy(self, Delta, Theta, Phi, Theta_prime, Delta_prime, U, V, T, T_prime, + ((Theta_prime**2 - 2 * Delta_prime * Phi) * T_prime**3 - (Theta_prime * Phi - 3 * Theta * Delta_prime) * T_prime**2 * T + (Theta * Theta_prime - 4 * Delta * Delta_prime) * T_prime * T**2 - (Delta * Theta_prime) * T**3) * U + ((Theta**2 - 2 * Delta * Phi) * T**3 - (Theta * Phi - 3 * Theta_prime * Delta) * T**2 * T_prime + (Theta * Theta_prime - 4 * Delta * Delta_prime) * T * T_prime**2 - (Delta_prime * Theta) * T_prime**3) * V + ((Delta * Phi * Delta_prime) * T**2 + (3 * Delta * Theta_prime * Delta_prime - Theta * Phi * Delta_prime) * T * T_prime + (2 * Delta * Delta_prime**2 - 2 * Theta * Theta_prime * Delta_prime + Phi**2 * Delta_prime) * T_prime**2) * U**2 - + ((Delta * Theta * Delta_prime + 2 * Delta * Phi * Theta_prime - Theta**2 * Theta_prime) * T**2 + (4 * Delta * Phi * Delta_prime - 3 * Theta**2 * Delta_prime - 3 * Delta * Theta_prime**2 + Theta * Phi * Theta_prime) * T * T_prime + (Delta * Theta_prime * Delta_prime + 2 * Delta_prime * Phi * Theta - Theta * Theta_prime**2) * T_prime**2) * U * V + + ( + (Delta * Theta * Delta_prime + 2 * Delta * Phi * Theta_prime - Theta**2 * Theta_prime) * T**2 + + (4 * Delta * Phi * Delta_prime - 3 * Theta**2 * Delta_prime - 3 * Delta * Theta_prime**2 + Theta * Phi * Theta_prime) * T * T_prime + + (Delta * Theta_prime * Delta_prime + 2 * Delta_prime * Phi * Theta - Theta * Theta_prime**2) * T_prime**2 + ) + * U + * V + ((2 * Delta**2 * Delta_prime - 2 * Delta * Theta * Theta_prime + Delta * Phi**2) * T**2 + (3 * Delta * Theta * Delta_prime - Delta * Phi * Theta_prime) * T * T_prime + Delta * Phi * Delta_prime * T_prime**2) * V**2 + ((-Delta * Theta * Delta_prime**2) * T + (-2 * Delta * Phi * Delta_prime**2 + Theta**2 * Delta_prime**2) * T_prime) * U**3 - + ((4 * Delta**2 * Delta_prime**2 - Delta * Theta * Theta_prime * Delta_prime - 2 * Delta * Phi**2 * Delta_prime + Theta**2 * Phi * Delta_prime) * T + (-5 * Delta * Theta * Delta_prime**2 + Delta * Phi * Theta_prime * Delta_prime + 2 * Theta**2 * Theta_prime * Delta_prime - Theta * Phi**2 * Delta_prime) * T_prime) * U**2 * V - + ((-5 * Delta**2 * Theta_prime * Delta_prime + Delta * Theta * Phi * Delta_prime + 2 * Delta * Theta * Theta_prime**2 - Delta * Phi**2 * Theta_prime) * T + (4 * Delta**2 * Delta_prime**2 - Delta * Theta * Theta_prime * Delta_prime - 2 * Delta * Phi**2 * Delta_prime + Delta * Phi * Theta_prime**2) * T_prime) * U * V**2 + + ( + (4 * Delta**2 * Delta_prime**2 - Delta * Theta * Theta_prime * Delta_prime - 2 * Delta * Phi**2 * Delta_prime + Theta**2 * Phi * Delta_prime) * T + + (-5 * Delta * Theta * Delta_prime**2 + Delta * Phi * Theta_prime * Delta_prime + 2 * Theta**2 * Theta_prime * Delta_prime - Theta * Phi**2 * Delta_prime) * T_prime + ) + * U**2 + * V + + ( + (-5 * Delta**2 * Theta_prime * Delta_prime + Delta * Theta * Phi * Delta_prime + 2 * Delta * Theta * Theta_prime**2 - Delta * Phi**2 * Theta_prime) * T + + (4 * Delta**2 * Delta_prime**2 - Delta * Theta * Theta_prime * Delta_prime - 2 * Delta * Phi**2 * Delta_prime + Delta * Phi * Theta_prime**2) * T_prime + ) + * U + * V**2 + ((-2 * Delta**2 * Phi * Delta_prime + Delta**2 * Theta_prime**2) * T + (-(Delta**2) * Theta_prime * Delta_prime) * T_prime) * V**3 + (Delta**2 * Delta_prime**3) * U**4 + (-3 * Delta**2 * Theta_prime * Delta_prime**2 + 3 * Delta * Theta * Phi * Delta_prime**2 - Theta**3 * Delta_prime**2) * U**3 * V diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 237bf92135f..5d9fc41d6d7 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -238,7 +238,31 @@ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.categories.tensor import tensor -from sage.data_structures.stream import Stream_add, Stream_cauchy_mul, Stream_cauchy_mul_commutative, Stream_sub, Stream_compose, Stream_cauchy_compose, Stream_lmul, Stream_rmul, Stream_neg, Stream_cauchy_invert, Stream_map_coefficients, Stream_zero, Stream_exact, Stream_uninitialized, Stream_shift, Stream_truncated, Stream_function, Stream_derivative, Stream_integral, Stream_dirichlet_convolve, Stream_dirichlet_invert, Stream_plethysm, Stream_pseudo_diff_mul +from sage.data_structures.stream import ( + Stream_add, + Stream_cauchy_mul, + Stream_cauchy_mul_commutative, + Stream_sub, + Stream_compose, + Stream_cauchy_compose, + Stream_lmul, + Stream_rmul, + Stream_neg, + Stream_cauchy_invert, + Stream_map_coefficients, + Stream_zero, + Stream_exact, + Stream_uninitialized, + Stream_shift, + Stream_truncated, + Stream_function, + Stream_derivative, + Stream_integral, + Stream_dirichlet_convolve, + Stream_dirichlet_invert, + Stream_plethysm, + Stream_pseudo_diff_mul, +) class LazyModuleElement(Element): diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 58bd2aa24f6..2edfaaab3f5 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -8076,7 +8076,10 @@ def maximal_order(self, v=None, assume_maximal='non-maximal-non-unique'): assume_maximal = True if assume_maximal == "non-maximal-non-unique": - deprecation(33386, 'maximal_order(v=[primes], assume_maximal="non-maximal-non-unique") has been deprecated since it can silently produce wrong results and does not play nicely with caching. An order that is maximal at some primes should be created with assume_maximal=None instead to make no assumptions about maximality at other primes.') + deprecation( + 33386, + 'maximal_order(v=[primes], assume_maximal="non-maximal-non-unique") has been deprecated since it can silently produce wrong results and does not play nicely with caching. An order that is maximal at some primes should be created with assume_maximal=None instead to make no assumptions about maximality at other primes.', + ) if assume_maximal is True: try: diff --git a/src/sage/rings/padics/factory.py b/src/sage/rings/padics/factory.py index 30493c9455d..47f9697288c 100644 --- a/src/sage/rings/padics/factory.py +++ b/src/sage/rings/padics/factory.py @@ -1358,7 +1358,24 @@ def Qq(q, prec=None, type='capped-rel', modulus=None, names=None, print_mode=Non from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF modulus = GF((p, k), res_name).modulus().change_ring(ZZ) - return ExtensionFactory(base=base, modulus=modulus, prec=prec, print_mode=print_mode, names=names, res_name=res_name, ram_name=ram_name, print_pos=print_pos, print_sep=print_sep, print_max_ram_terms=print_max_ram_terms, print_max_unram_terms=print_max_unram_terms, print_max_terse_terms=print_max_terse_terms, show_prec=show_prec, check=check, unram=True, implementation=implementation) + return ExtensionFactory( + base=base, + modulus=modulus, + prec=prec, + print_mode=print_mode, + names=names, + res_name=res_name, + ram_name=ram_name, + print_pos=print_pos, + print_sep=print_sep, + print_max_ram_terms=print_max_ram_terms, + print_max_unram_terms=print_max_unram_terms, + print_max_terse_terms=print_max_terse_terms, + show_prec=show_prec, + check=check, + unram=True, + implementation=implementation, + ) ###################################################### @@ -2565,7 +2582,24 @@ def Zq(q, prec=None, type='capped-rel', modulus=None, names=None, print_mode=Non if ram_name is None: ram_name = str(F[0][0]) modulus = GF(q, res_name).modulus().change_ring(ZZ) - return ExtensionFactory(base=base, modulus=modulus, prec=prec, print_mode=print_mode, names=names, res_name=res_name, ram_name=ram_name, print_pos=print_pos, print_sep=print_sep, print_max_ram_terms=print_max_ram_terms, print_max_unram_terms=print_max_unram_terms, print_max_terse_terms=print_max_terse_terms, show_prec=show_prec, check=check, unram=True, implementation=implementation) + return ExtensionFactory( + base=base, + modulus=modulus, + prec=prec, + print_mode=print_mode, + names=names, + res_name=res_name, + ram_name=ram_name, + print_pos=print_pos, + print_sep=print_sep, + print_max_ram_terms=print_max_ram_terms, + print_max_unram_terms=print_max_unram_terms, + print_max_terse_terms=print_max_terse_terms, + show_prec=show_prec, + check=check, + unram=True, + implementation=implementation, + ) ###################################################### @@ -3213,7 +3247,28 @@ class pAdicExtension_class(UniqueFactory): 12 """ - def create_key_and_extra_args(self, base, modulus, prec=None, print_mode=None, names=None, var_name=None, res_name=None, unram_name=None, ram_name=None, print_pos=None, print_sep=None, print_alphabet=None, print_max_ram_terms=None, print_max_unram_terms=None, print_max_terse_terms=None, show_prec=None, check=True, unram=False, implementation='FLINT'): + def create_key_and_extra_args( + self, + base, + modulus, + prec=None, + print_mode=None, + names=None, + var_name=None, + res_name=None, + unram_name=None, + ram_name=None, + print_pos=None, + print_sep=None, + print_alphabet=None, + print_max_ram_terms=None, + print_max_unram_terms=None, + print_max_terse_terms=None, + show_prec=None, + check=True, + unram=False, + implementation='FLINT', + ): r""" Create a key from input parameters for :class:`pAdicExtension`. diff --git a/src/sage/rings/padics/misc.py b/src/sage/rings/padics/misc.py index 198cf7be69e..310c5022a0e 100644 --- a/src/sage/rings/padics/misc.py +++ b/src/sage/rings/padics/misc.py @@ -203,7 +203,15 @@ def precprint(prec_type, prec_cap, p): sage: precprint('fixed-mod', 1, 17) 'of fixed modulus 17^1' """ - precD = {'capped-rel': 'with capped relative precision %s' % prec_cap, 'capped-abs': 'with capped absolute precision %s' % prec_cap, 'floating-point': 'with floating precision %s' % prec_cap, 'fixed-mod': 'of fixed modulus %s^%s' % (p, prec_cap), 'lattice-cap': 'with lattice-cap precision', 'lattice-float': 'with lattice-float precision', 'relaxed': 'handled with relaxed arithmetics'} + precD = { + 'capped-rel': 'with capped relative precision %s' % prec_cap, + 'capped-abs': 'with capped absolute precision %s' % prec_cap, + 'floating-point': 'with floating precision %s' % prec_cap, + 'fixed-mod': 'of fixed modulus %s^%s' % (p, prec_cap), + 'lattice-cap': 'with lattice-cap precision', + 'lattice-float': 'with lattice-float precision', + 'relaxed': 'handled with relaxed arithmetics', + } return precD[prec_type] diff --git a/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py b/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py index 5d723a6aa16..aca82375e9c 100644 --- a/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py +++ b/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py @@ -435,7 +435,11 @@ def _add_(self, right): else: baseval = self._valbase # Currently we don't reduce the coefficients of the answer modulo the appropriate power of p or normalize - return Polynomial_padic_capped_relative_dense(self.parent(), (selfpoly + rightpoly, baseval, [min(a + self._valbase - baseval, b + right._valbase - baseval) for (a, b) in zip(_extend_by_infinity(self._relprecs, max(len(self._relprecs), len(right._relprecs))), _extend_by_infinity(right._relprecs, max(len(self._relprecs), len(right._relprecs))))], False, None, None), construct=True) + return Polynomial_padic_capped_relative_dense( + self.parent(), + (selfpoly + rightpoly, baseval, [min(a + self._valbase - baseval, b + right._valbase - baseval) for (a, b) in zip(_extend_by_infinity(self._relprecs, max(len(self._relprecs), len(right._relprecs))), _extend_by_infinity(right._relprecs, max(len(self._relprecs), len(right._relprecs))))], False, None, None), + construct=True, + ) def _sub_(self, right): """ @@ -463,7 +467,11 @@ def _sub_(self, right): else: baseval = self._valbase # Currently we don't reduce the coefficients of the answer modulo the appropriate power of p or normalize - return Polynomial_padic_capped_relative_dense(self.parent(), (selfpoly - rightpoly, baseval, [min(a + self._valbase - baseval, b + right._valbase - baseval) for (a, b) in zip(_extend_by_infinity(self._relprecs, max(len(self._relprecs), len(right._relprecs))), _extend_by_infinity(right._relprecs, max(len(self._relprecs), len(right._relprecs))))], False, None, None), construct=True) + return Polynomial_padic_capped_relative_dense( + self.parent(), + (selfpoly - rightpoly, baseval, [min(a + self._valbase - baseval, b + right._valbase - baseval) for (a, b) in zip(_extend_by_infinity(self._relprecs, max(len(self._relprecs), len(right._relprecs))), _extend_by_infinity(right._relprecs, max(len(self._relprecs), len(right._relprecs))))], False, None, None), + construct=True, + ) def _mul_(self, right): r""" diff --git a/src/sage/rings/polynomial/pbori/gbcore.py b/src/sage/rings/polynomial/pbori/gbcore.py index dfc41cdda2d..38ffda91c53 100644 --- a/src/sage/rings/polynomial/pbori/gbcore.py +++ b/src/sage/rings/polynomial/pbori/gbcore.py @@ -514,7 +514,25 @@ def my_sort_key(l): @gb_with_pre_post_option("fix_deg_bound", if_not_option=["interpolation_gb"], post=fix_deg_bound_post, default=True) @gb_with_pre_post_option("minsb", post=minsb_post, if_not_option=["redsb", "deg_bound", "interpolation_gb", "convert_with_fglm_from_ring"], default=True) @gb_with_pre_post_option("redsb", post=redsb_post, if_not_option=["deg_bound", "interpolation_gb", "convert_with_fglm_from_ring"], default=True) -def groebner_basis(I, heuristic=True, unique_ideal_generator=False, interpolation_gb=False, clean_and_restart_algorithm=False, convert_with_fglm_from_ring=None, convert_with_fglm_to_ring=None, fglm_bound=40000, modified_linear_algebra=True, preprocessor=None, deg_bound=False, implementation='Python', full_prot=False, prot=False, draw_matrices=False, preprocess_only=False, **impl_options): +def groebner_basis( + I, + heuristic=True, + unique_ideal_generator=False, + interpolation_gb=False, + clean_and_restart_algorithm=False, + convert_with_fglm_from_ring=None, + convert_with_fglm_to_ring=None, + fglm_bound=40000, + modified_linear_algebra=True, + preprocessor=None, + deg_bound=False, + implementation='Python', + full_prot=False, + prot=False, + draw_matrices=False, + preprocess_only=False, + **impl_options, +): """Computes a Groebner basis of a given ideal I, w.r.t options.""" if not I: diff --git a/src/sage/rings/polynomial/pbori/nf.py b/src/sage/rings/polynomial/pbori/nf.py index 647b5f2f4ce..383ee3af6f5 100644 --- a/src/sage/rings/polynomial/pbori/nf.py +++ b/src/sage/rings/polynomial/pbori/nf.py @@ -213,7 +213,31 @@ def high_probability_polynomials_trick(p, strat): strat.add_as_you_wish(c) -def symmGB_F2_python(G, deg_bound=1000000000000, over_deg_bound=0, use_faugere=False, use_noro=False, opt_lazy=True, opt_red_tail=True, max_growth=2.0, step_factor=1.0, implications=False, prot=False, full_prot=False, selection_size=1000, opt_exchange=True, opt_allow_recursion=False, ll=False, opt_linear_algebra_in_last_block=True, max_generators=None, red_tail_deg_growth=True, matrix_prefix='mat', modified_linear_algebra=True, draw_matrices=False, easy_linear_polynomials=True): +def symmGB_F2_python( + G, + deg_bound=1000000000000, + over_deg_bound=0, + use_faugere=False, + use_noro=False, + opt_lazy=True, + opt_red_tail=True, + max_growth=2.0, + step_factor=1.0, + implications=False, + prot=False, + full_prot=False, + selection_size=1000, + opt_exchange=True, + opt_allow_recursion=False, + ll=False, + opt_linear_algebra_in_last_block=True, + max_generators=None, + red_tail_deg_growth=True, + matrix_prefix='mat', + modified_linear_algebra=True, + draw_matrices=False, + easy_linear_polynomials=True, +): if use_noro and use_faugere: raise ValueError('both use_noro and use_faugere specified') @@ -561,7 +585,30 @@ def branch(strat, trace, proof_path, pos): branch(strat, [], proof_path, 0) -def symmGB_F2_C(G, opt_exchange=True, deg_bound=1000000000000, opt_lazy=False, over_deg_bound=0, opt_red_tail=True, max_growth=2.0, step_factor=1.0, implications=False, prot=False, full_prot=False, selection_size=1000, opt_allow_recursion=False, use_noro=False, use_faugere=False, ll=False, opt_linear_algebra_in_last_block=True, max_generators=None, red_tail_deg_growth=True, modified_linear_algebra=True, matrix_prefix='', draw_matrices=False): +def symmGB_F2_C( + G, + opt_exchange=True, + deg_bound=1000000000000, + opt_lazy=False, + over_deg_bound=0, + opt_red_tail=True, + max_growth=2.0, + step_factor=1.0, + implications=False, + prot=False, + full_prot=False, + selection_size=1000, + opt_allow_recursion=False, + use_noro=False, + use_faugere=False, + ll=False, + opt_linear_algebra_in_last_block=True, + max_generators=None, + red_tail_deg_growth=True, + modified_linear_algebra=True, + matrix_prefix='', + draw_matrices=False, +): if use_noro: raise NotImplementedError("noro not implemented for symmgb") if isinstance(G, list): diff --git a/src/sage/rings/polynomial/term_order.py b/src/sage/rings/polynomial/term_order.py index 1c2aba8341a..03703d5e387 100644 --- a/src/sage/rings/polynomial/term_order.py +++ b/src/sage/rings/polynomial/term_order.py @@ -1939,7 +1939,14 @@ def __eq__(self, other): except Exception: return False - return self._name == other._name and self._blocks == other._blocks and (not self.is_block_order() or all(len(t1) == len(t2) for (t1, t2) in zip(self._blocks, other._blocks))) and self._weights == other._weights and self._matrix == other._matrix and self._singular_ringorder_column == other._singular_ringorder_column + return ( + self._name == other._name + and self._blocks == other._blocks + and (not self.is_block_order() or all(len(t1) == len(t2) for (t1, t2) in zip(self._blocks, other._blocks))) + and self._weights == other._weights + and self._matrix == other._matrix + and self._singular_ringorder_column == other._singular_ringorder_column + ) def __ne__(self, other): """ diff --git a/src/sage/schemes/elliptic_curves/addition_formulas_ring.py b/src/sage/schemes/elliptic_curves/addition_formulas_ring.py index 6b121360704..47ed664693e 100644 --- a/src/sage/schemes/elliptic_curves/addition_formulas_ring.py +++ b/src/sage/schemes/elliptic_curves/addition_formulas_ring.py @@ -78,13 +78,50 @@ def _add(E, P, Q): X31 = XYdif * YZsum + XZdif * Y1 * Y2 + a1 * X1 * X2 * YZdif + a1 * XYdif * XZsum - a2 * X1 * X2 * XZdif + a3 * XYdif * Z1 * Z2 + a3 * XZdif * YZsum - a4 * XZsum * XZdif - 3 * a6 * XZdif * Z1 * Z2 - Y31 = -3 * X1 * X2 * XYdif - Y1 * Y2 * YZdif - 2 * a1 * XZdif * Y1 * Y2 + (a1sq + 3 * a2) * X1 * X2 * YZdif - (a1sq + a2) * XYsum * XZdif + (a1 * a2 - 3 * a3) * X1 * X2 * XZdif - (2 * a1 * a3 + a4) * XYdif * Z1 * Z2 + a4 * XZsum * YZdif + (a1 * a4 - a2 * a3) * XZsum * XZdif + (a3sq + 3 * a6) * YZdif * Z1 * Z2 + (3 * a1 * a6 - a3 * a4) * XZdif * Z1 * Z2 + Y31 = ( + -3 * X1 * X2 * XYdif + - Y1 * Y2 * YZdif + - 2 * a1 * XZdif * Y1 * Y2 + + (a1sq + 3 * a2) * X1 * X2 * YZdif + - (a1sq + a2) * XYsum * XZdif + + (a1 * a2 - 3 * a3) * X1 * X2 * XZdif + - (2 * a1 * a3 + a4) * XYdif * Z1 * Z2 + + a4 * XZsum * YZdif + + (a1 * a4 - a2 * a3) * XZsum * XZdif + + (a3sq + 3 * a6) * YZdif * Z1 * Z2 + + (3 * a1 * a6 - a3 * a4) * XZdif * Z1 * Z2 + ) Z31 = 3 * X1 * X2 * XZdif - YZsum * YZdif + a1 * XYdif * Z1 * Z2 - a1 * XZdif * YZsum + a2 * XZsum * XZdif - a3 * YZdif * Z1 * Z2 + a4 * XZdif * Z1 * Z2 yield (X31, Y31, Z31) - X32 = Y1 * Y2 * XYsum + a1 * (2 * X1 * Y2 + X2 * Y1) * X2 * Y1 + a1sq * X1 * X2**2 * Y1 - a2 * X1 * X2 * XYsum - a1 * a2 * X1**2 * X2**2 + a3 * X2 * Y1 * (YZsum + Y2 * Z1) + a1 * a3 * X1 * X2 * YZdif - a1 * a3 * XYsum * XZdif - a4 * X1 * X2 * YZsum - a4 * XYsum * XZsum - a1sq * a3 * X1**2 * X2 * Z2 - a1 * a4 * X1 * X2 * (X1 * Z2 + XZsum) - a2 * a3 * X1 * X2**2 * Z1 - a3sq * X1 * Z2 * (Y2 * Z1 + YZsum) - 3 * a6 * XYsum * Z1 * Z2 - 3 * a6 * XZsum * YZsum - a1 * a3sq * X1 * Z2 * (XZsum + X2 * Z1) - 3 * a1 * a6 * X1 * Z2 * (XZsum + X2 * Z1) - a3 * a4 * (X1 * Z2 + XZsum) * X2 * Z1 - b8 * YZsum * Z1 * Z2 - a1 * b8 * X1 * Z1 * Z2**2 - a3**3 * XZsum * Z1 * Z2 - 3 * a3 * a6 * (XZsum + X2 * Z1) * Z1 * Z2 - a3 * b8 * Z1**2 * Z2**2 + X32 = ( + Y1 * Y2 * XYsum + + a1 * (2 * X1 * Y2 + X2 * Y1) * X2 * Y1 + + a1sq * X1 * X2**2 * Y1 + - a2 * X1 * X2 * XYsum + - a1 * a2 * X1**2 * X2**2 + + a3 * X2 * Y1 * (YZsum + Y2 * Z1) + + a1 * a3 * X1 * X2 * YZdif + - a1 * a3 * XYsum * XZdif + - a4 * X1 * X2 * YZsum + - a4 * XYsum * XZsum + - a1sq * a3 * X1**2 * X2 * Z2 + - a1 * a4 * X1 * X2 * (X1 * Z2 + XZsum) + - a2 * a3 * X1 * X2**2 * Z1 + - a3sq * X1 * Z2 * (Y2 * Z1 + YZsum) + - 3 * a6 * XYsum * Z1 * Z2 + - 3 * a6 * XZsum * YZsum + - a1 * a3sq * X1 * Z2 * (XZsum + X2 * Z1) + - 3 * a1 * a6 * X1 * Z2 * (XZsum + X2 * Z1) + - a3 * a4 * (X1 * Z2 + XZsum) * X2 * Z1 + - b8 * YZsum * Z1 * Z2 + - a1 * b8 * X1 * Z1 * Z2**2 + - a3**3 * XZsum * Z1 * Z2 + - 3 * a3 * a6 * (XZsum + X2 * Z1) * Z1 * Z2 + - a3 * b8 * Z1**2 * Z2**2 + ) Y32 = ( Y1**2 * Y2**2 @@ -104,6 +141,30 @@ def _add(E, P, Q): + (a1**3 * a3 * a6 - a1sq * a3sq * a4 + a1sq * a4 * a6 + a1 * a2 * a3**3 + 4 * a1 * a2 * a3 * a6 - 2 * a1 * a3 * a4sq + a2 * a3sq * a4 + 4 * a2 * a4 * a6 - a3**4 - 6 * a3**2 * a6 - a4**3 - 9 * a6**2) * Z1**2 * Z2**2 ) - Z32 = 3 * X1 * X2 * XYsum + Y1 * Y2 * YZsum + 3 * a1 * X1**2 * X2**2 + a1 * (2 * X1 * Y2 + Y1 * X2) * Y1 * Z2 + a1sq * X1 * Z2 * (2 * X2 * Y1 + X1 * Y2) + a2 * X1 * X2 * YZsum + a2 * XYsum * XZsum + a1**3 * X1**2 * X2 * Z2 + a1 * a2 * X1 * X2 * (2 * X1 * Z2 + X2 * Z1) + 3 * a3 * X1 * X2**2 * Z1 + a3 * Y1 * Z2 * (YZsum + Y2 * Z1) + 2 * a1 * a3 * X1 * Z2 * YZsum + 2 * a1 * a3 * X2 * Y1 * Z1 * Z2 + a4 * XYsum * Z1 * Z2 + a4 * XZsum * YZsum + (a1sq * a3 + a1 * a4) * X1 * Z2 * (XZsum + X2 * Z1) + a2 * a3 * X2 * Z1 * (2 * X1 * Z2 + X2 * Z1) + a3sq * Y1 * Z1 * Z2**2 + (a3sq + 3 * a6) * YZsum * Z1 * Z2 + a1 * a3sq * (2 * X1 * Z2 + X2 * Z1) * Z1 * Z2 + 3 * a1 * a6 * X1 * Z1 * Z2**2 + a3 * a4 * (XZsum + X2 * Z1) * Z1 * Z2 + (a3**3 + 3 * a3 * a6) * Z1**2 * Z2**2 + Z32 = ( + 3 * X1 * X2 * XYsum + + Y1 * Y2 * YZsum + + 3 * a1 * X1**2 * X2**2 + + a1 * (2 * X1 * Y2 + Y1 * X2) * Y1 * Z2 + + a1sq * X1 * Z2 * (2 * X2 * Y1 + X1 * Y2) + + a2 * X1 * X2 * YZsum + + a2 * XYsum * XZsum + + a1**3 * X1**2 * X2 * Z2 + + a1 * a2 * X1 * X2 * (2 * X1 * Z2 + X2 * Z1) + + 3 * a3 * X1 * X2**2 * Z1 + + a3 * Y1 * Z2 * (YZsum + Y2 * Z1) + + 2 * a1 * a3 * X1 * Z2 * YZsum + + 2 * a1 * a3 * X2 * Y1 * Z1 * Z2 + + a4 * XYsum * Z1 * Z2 + + a4 * XZsum * YZsum + + (a1sq * a3 + a1 * a4) * X1 * Z2 * (XZsum + X2 * Z1) + + a2 * a3 * X2 * Z1 * (2 * X1 * Z2 + X2 * Z1) + + a3sq * Y1 * Z1 * Z2**2 + + (a3sq + 3 * a6) * YZsum * Z1 * Z2 + + a1 * a3sq * (2 * X1 * Z2 + X2 * Z1) * Z1 * Z2 + + 3 * a1 * a6 * X1 * Z1 * Z2**2 + + a3 * a4 * (XZsum + X2 * Z1) * Z1 * Z2 + + (a3**3 + 3 * a3 * a6) * Z1**2 * Z2**2 + ) yield (X32, Y32, Z32) diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index 5e5641fb1c8..3299b669ac3 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -2699,7 +2699,18 @@ def __compute_omega_general(self, E, psi, psi_pr, phi, phi_pr): psi_2 = 2 * y + a1 * x + a3 - omega = phi_pr * psi * y - phi * psi_pr * psi_2 + ((a1 * x + a3) * (psi_2**2) * (psi_prpr * psi_pr - psi_prprpr * psi) + (a1 * psi_2**2 - 3 * (a1 * x + a3) * (6 * x**2 + b2 * x + b4)) * psi_prpr * psi + (a1 * x**3 + 3 * a3 * x**2 + (2 * a2 * a3 - a1 * a4) * x + (a3 * a4 - 2 * a1 * a6)) * psi_pr**2 + (-(3 * a1 * x**2 + 6 * a3 * x + (-a1 * a4 + 2 * a2 * a3)) + (a1 * x + a3) * (d * x - 2 * s1)) * psi_pr * psi + (a1 * s1 + a3 * n) * psi**2) * psi + omega = ( + phi_pr * psi * y + - phi * psi_pr * psi_2 + + ( + (a1 * x + a3) * (psi_2**2) * (psi_prpr * psi_pr - psi_prprpr * psi) + + (a1 * psi_2**2 - 3 * (a1 * x + a3) * (6 * x**2 + b2 * x + b4)) * psi_prpr * psi + + (a1 * x**3 + 3 * a3 * x**2 + (2 * a2 * a3 - a1 * a4) * x + (a3 * a4 - 2 * a1 * a6)) * psi_pr**2 + + (-(3 * a1 * x**2 + 6 * a3 * x + (-a1 * a4 + 2 * a2 * a3)) + (a1 * x + a3) * (d * x - 2 * s1)) * psi_pr * psi + + (a1 * s1 + a3 * n) * psi**2 + ) + * psi + ) return omega diff --git a/src/sage/schemes/elliptic_curves/isogeny_small_degree.py b/src/sage/schemes/elliptic_curves/isogeny_small_degree.py index 861640c7911..33e72114f27 100644 --- a/src/sage/schemes/elliptic_curves/isogeny_small_degree.py +++ b/src/sage/schemes/elliptic_curves/isogeny_small_degree.py @@ -1529,7 +1529,18 @@ def isogenies_13_0(E, minimal_models=True): for t0 in ts: s3 = b / (6 * t0**3 + 32 * t0**2 + 68 * t0 + 4) ss = sorted((x**3 - s3).roots(multiplicities=False)) - ker = x**6 + (20 * t0**3 + 106 * t0**2 + 218 * t0 + 4) * x**5 + (-826 * t0**3 - 4424 * t0**2 - 9244 * t0 - 494) * x**4 + (13514 * t0**3 + 72416 * t0**2 + 151416 * t0 + 8238) * x**3 + (-101948 * t0**3 - 546304 * t0**2 - 1142288 * t0 - 62116) * x**2 + (354472 * t0**3 + 1899488 * t0**2 + 3971680 * t0 + 215960) * x - 459424 * t0**3 - 2461888 * t0**2 - 5147648 * t0 - 279904 + ker = ( + x**6 + + (20 * t0**3 + 106 * t0**2 + 218 * t0 + 4) * x**5 + + (-826 * t0**3 - 4424 * t0**2 - 9244 * t0 - 494) * x**4 + + (13514 * t0**3 + 72416 * t0**2 + 151416 * t0 + 8238) * x**3 + + (-101948 * t0**3 - 546304 * t0**2 - 1142288 * t0 - 62116) * x**2 + + (354472 * t0**3 + 1899488 * t0**2 + 3971680 * t0 + 215960) * x + - 459424 * t0**3 + - 2461888 * t0**2 + - 5147648 * t0 + - 279904 + ) kernels = [ker(x / s).monic() for s in ss] isogs.extend(Ew.isogeny(ker, model=model) for ker in kernels) @@ -1669,7 +1680,20 @@ def isogenies_13_1728(E, minimal_models=True): for t0 in ts: s2 = a / (66 * t0**5 + 630 * t0**4 + 2750 * t0**3 + 5882 * t0**2 + 5414 * t0 + 162) ss = sorted(s2.sqrt(all=True, extend=False)) - ker = x**6 + (-66 * t0**5 - 630 * t0**4 - 2750 * t0**3 - 5882 * t0**2 - 5414 * t0 - 162) * x**5 + (-21722 * t0**5 - 205718 * t0**4 - 890146 * t0**3 - 1873338 * t0**2 - 1652478 * t0 + 61610) * x**4 + (-3391376 * t0**5 - 32162416 * t0**4 - 139397232 * t0**3 - 294310576 * t0**2 - 261885968 * t0 + 6105552) * x**3 + (-241695080 * t0**5 - 2291695976 * t0**4 - 9930313256 * t0**3 - 20956609720 * t0**2 - 18625380856 * t0 + 469971320) * x**2 + (-8085170432 * t0**5 - 76663232384 * t0**4 - 332202985024 * t0**3 - 701103233152 * t0**2 - 623190845440 * t0 + 15598973056) * x - 101980510208 * t0**5 - 966973468160 * t0**4 - 4190156868352 * t0**3 - 8843158270336 * t0**2 - 7860368751232 * t0 + 196854655936 + ker = ( + x**6 + + (-66 * t0**5 - 630 * t0**4 - 2750 * t0**3 - 5882 * t0**2 - 5414 * t0 - 162) * x**5 + + (-21722 * t0**5 - 205718 * t0**4 - 890146 * t0**3 - 1873338 * t0**2 - 1652478 * t0 + 61610) * x**4 + + (-3391376 * t0**5 - 32162416 * t0**4 - 139397232 * t0**3 - 294310576 * t0**2 - 261885968 * t0 + 6105552) * x**3 + + (-241695080 * t0**5 - 2291695976 * t0**4 - 9930313256 * t0**3 - 20956609720 * t0**2 - 18625380856 * t0 + 469971320) * x**2 + + (-8085170432 * t0**5 - 76663232384 * t0**4 - 332202985024 * t0**3 - 701103233152 * t0**2 - 623190845440 * t0 + 15598973056) * x + - 101980510208 * t0**5 + - 966973468160 * t0**4 + - 4190156868352 * t0**3 + - 8843158270336 * t0**2 + - 7860368751232 * t0 + + 196854655936 + ) kernels = [ker(x / s).monic() for s in ss] isogs.extend(Ew.isogeny(ker, model=model) for ker in kernels) @@ -1780,7 +1804,42 @@ def _hyperelliptic_isogeny_data(l): data['A2'] = Zu([558, 837, -1488, 465]) data['A4'] = Zuv(Zu([-4140, -12468, 15189, 16956, -27054, 11184, -1443]) + v * Zu([2160, -7560, 6120, -1440])) data['A6'] = Zuv(Zu([71280, 592056, -108324, -2609730, 2373048, 1282266, -2793204, 1530882, -356976, 29790]) + v * Zu([-81312, 181664, 294728, -868392, 701400, -238840, 29792])) - data['alpha'] = Zu([108000, 475200, -7053120, -27353408, 90884374, 303670296, -665806437, -1361301729, 3259359840, 2249261823, -9368721606, 2279583264, 13054272515, -12759480061, -4169029296, 14390047139, -7803693550, -2988803682, 6239473912, -3296588360, 134066754, 908915598, -685615437, 294482733, -87483178, 18983315, -3052818, 361336, -30659, 1767, -62, 1]) + data['alpha'] = Zu( + [ + 108000, + 475200, + -7053120, + -27353408, + 90884374, + 303670296, + -665806437, + -1361301729, + 3259359840, + 2249261823, + -9368721606, + 2279583264, + 13054272515, + -12759480061, + -4169029296, + 14390047139, + -7803693550, + -2988803682, + 6239473912, + -3296588360, + 134066754, + 908915598, + -685615437, + 294482733, + -87483178, + 18983315, + -3052818, + 361336, + -30659, + 1767, + -62, + 1, + ] + ) data['beta'] = Zu([0, 712800, 1216080, -18430560, -15262464, 168899202, -12931221, -720077416, 624871714, 1239052988, -2259335558, 68648452, 2679085427, -2318039014, -229246628, 1710545918, -1243026758, 211524870, 296674626, -291810274, 145889932, -48916468, 11793961, -2085662, 269348, -24778, 1540, -58, 1]) # beta factors as (u - 3) * (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 8*u + 11) * (u**2 - 7*u + 2) * (u**2 - 5*u - 2) * (u**2 - 5*u + 5) * (u**2 - 4*u - 4) * (u**2 - 4*u - 1) * (u**2 - 2*u - 1) * (u**2 - u - 1) * (u**3 - 9*u**2 + 21*u - 15) * (u**4 - 8*u**3 + 8*u**2 + 12*u - 9) data['endo'] = 31 * x**15 + 31 * (-66 * u + 86) * v * x**12 + 31 * (168 * u + 280) * v**2 * x**9 + 31 * (576 * u + 1792) * v**3 * x**6 + 31 * (384 * u + 896) * v**4 * x**3 + (-3072 * u - 2048) * v**5 @@ -1791,10 +1850,108 @@ def _hyperelliptic_isogeny_data(l): data['A2'] = Zu([328, 656, -656, -1148, 820]) data['A4'] = Zuv(Zu([-1380, -4008, 1701, 10872, 6144, -18378, -2160, 9732, -2523]) + v * Zu([720, -1440, -2160, 5400, -2520])) data['A6'] = Zuv(Zu([4480, 155616, 16080, -550720, -343968, 832680, 938632, -621648, -1468608, 953920, 427632, -413016, 68920]) + v * Zu([-14616, 6804, 96390, -2016, -324324, 184464, 260568, -276192, 68922])) - data['alpha'] = Zu([16000, 67200, -465760, -2966432, -1742664, 20985112, 46140990, -31732934, -217030548, -147139488, 436080674, 745775322, -271341362, -1542677562, -605560447, 1832223375, 1772593672, -1270633050, -2400692229, 343522723, 2179745361, 282422801, -1503727029, -421357697, 879637411, 261059095, -462271351, -61715127, 193718727, -24135265, -49355103, 20512341, 3613289, -4706595, 1099661, 163057, -162483, 46617, -7544, 738, -41, 1]) - data['beta'] = Zu([0, 44800, 167040, -447040, -2734272, -1104272, 13488360, 21067652, -24681704, -83929974, -8986886, 169059382, 127641266, -196479899, -283039783, 124573790, 366614063, -12946368, -332987597, -58867672, 241909907, 60568430, -155045647, -17919564, 79114945, -12025938, -24060781, 11190142, 1979597, -2931764, 750233, 110144, -122263, 37484, -6439, 666, -39, 1]) + data['alpha'] = Zu( + [ + 16000, + 67200, + -465760, + -2966432, + -1742664, + 20985112, + 46140990, + -31732934, + -217030548, + -147139488, + 436080674, + 745775322, + -271341362, + -1542677562, + -605560447, + 1832223375, + 1772593672, + -1270633050, + -2400692229, + 343522723, + 2179745361, + 282422801, + -1503727029, + -421357697, + 879637411, + 261059095, + -462271351, + -61715127, + 193718727, + -24135265, + -49355103, + 20512341, + 3613289, + -4706595, + 1099661, + 163057, + -162483, + 46617, + -7544, + 738, + -41, + 1, + ] + ) + data['beta'] = Zu( + [ + 0, + 44800, + 167040, + -447040, + -2734272, + -1104272, + 13488360, + 21067652, + -24681704, + -83929974, + -8986886, + 169059382, + 127641266, + -196479899, + -283039783, + 124573790, + 366614063, + -12946368, + -332987597, + -58867672, + 241909907, + 60568430, + -155045647, + -17919564, + 79114945, + -12025938, + -24060781, + 11190142, + 1979597, + -2931764, + 750233, + 110144, + -122263, + 37484, + -6439, + 666, + -39, + 1, + ] + ) # beta factors as (u - 5) * (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 5*u + 5) * (u**2 - 3*u - 7) * (u**2 - 2*u - 4) * (u**2 - 2*u - 1) * (u**2 - u - 1) * (u**2 - 2) * (u**2 + u - 1) * (u**3 - 3*u**2 - 5*u - 2) * (u**3 - 2*u**2 - 2*u - 1) * (u**4 - 6*u**3 + 5*u**2 + 2*u - 1) * (u**4 - 5*u**3 + u**2 + 4) * (u**4 - 4*u**3 + 2) - data['endo'] = 41 * x**20 + 41 * (-12 * u - 22) * v * x**18 + 41 * (-252 * u - 247) * v**2 * x**16 + 41 * (-176 * u - 424) * v**3 * x**14 + 41 * (464 * u - 254) * v**4 * x**12 + 41 * (1688 * u - 868) * v**5 * x**10 + 41 * (1720 * u - 1190) * v**6 * x**8 + 41 * (528 * u - 232) * v**7 * x**6 + 41 * (16 * u + 29) * v**8 * x**4 + 41 * (20 * u + 10) * v**9 * x**2 + (4 * u + 5) * v**10 + data['endo'] = ( + 41 * x**20 + + 41 * (-12 * u - 22) * v * x**18 + + 41 * (-252 * u - 247) * v**2 * x**16 + + 41 * (-176 * u - 424) * v**3 * x**14 + + 41 * (464 * u - 254) * v**4 * x**12 + + 41 * (1688 * u - 868) * v**5 * x**10 + + 41 * (1720 * u - 1190) * v**6 * x**8 + + 41 * (528 * u - 232) * v**7 * x**6 + + 41 * (16 * u + 29) * v**8 * x**4 + + 41 * (20 * u + 10) * v**9 * x**2 + + (4 * u + 5) * v**10 + ) data['endo_u'] = 1 return data if l == 47: @@ -1802,8 +1959,105 @@ def _hyperelliptic_isogeny_data(l): data['A2'] = Zu([376, -1504, 2209, -1598, 1081]) data['A4'] = Zuv(Zu([2400, -4080, -1440, 18000, -26355, 34740, -22050, 12900, -3315]) + v * Zu([1152, -3384, 3672, -3312])) data['A6'] = Zuv(Zu([-119504, 606336, -1505280, 2109392, -1509360, -515808, 2920702, -4614012, 4334322, -3260312, 1571442, -622428, 103822]) + v * Zu([2016, 48384, -235872, 438984, -627480, 503496, -311976, 103824])) - data['alpha'] = Zu([-65536, 688128, -2502656, -96256, 38598656, -187217920, 508021120, -845669120, 552981696, 1469334304, -5945275904, 11705275552, -14673798654, 9100068184, 8421580132, -34288012648, 56657584158, -60426283952, 36612252089, 9942017442, -60791892299, 93046207239, -92028642340, 59196883097, -10454018992, -33364599371, 57280402355, -57873890484, 41879296232, -20241250112, 2065827049, 8435506655, -11611941072, 10182603298, -7040645261, 4071881378, -2013138357, 856757031, -313468474, 97893151, -25770006, 5617769, -990431, 136864, -14194, 1034, -47, 1]) - data['beta'] = Zu([0, 114688, -1114112, 4854784, -11205632, 7426048, 42663936, -182555136, 394092544, -508851472, 213245648, 743315936, -2203729384, 3409478688, -3280008936, 1139839970, 2576264698, -6272528962, 8005203155, -6671665088, 2744569094, 1996771588, -5520074039, 6637395180, -5455622885, 3028415830, -601645255, -1012737914, 1632999370, -1525982346, 1093778952, -644352392, 319489974, -134176208, 47566499, -14083902, 3424200, -667810, 101271, -11438, 901, -44, 1]) + data['alpha'] = Zu( + [ + -65536, + 688128, + -2502656, + -96256, + 38598656, + -187217920, + 508021120, + -845669120, + 552981696, + 1469334304, + -5945275904, + 11705275552, + -14673798654, + 9100068184, + 8421580132, + -34288012648, + 56657584158, + -60426283952, + 36612252089, + 9942017442, + -60791892299, + 93046207239, + -92028642340, + 59196883097, + -10454018992, + -33364599371, + 57280402355, + -57873890484, + 41879296232, + -20241250112, + 2065827049, + 8435506655, + -11611941072, + 10182603298, + -7040645261, + 4071881378, + -2013138357, + 856757031, + -313468474, + 97893151, + -25770006, + 5617769, + -990431, + 136864, + -14194, + 1034, + -47, + 1, + ] + ) + data['beta'] = Zu( + [ + 0, + 114688, + -1114112, + 4854784, + -11205632, + 7426048, + 42663936, + -182555136, + 394092544, + -508851472, + 213245648, + 743315936, + -2203729384, + 3409478688, + -3280008936, + 1139839970, + 2576264698, + -6272528962, + 8005203155, + -6671665088, + 2744569094, + 1996771588, + -5520074039, + 6637395180, + -5455622885, + 3028415830, + -601645255, + -1012737914, + 1632999370, + -1525982346, + 1093778952, + -644352392, + 319489974, + -134176208, + 47566499, + -14083902, + 3424200, + -667810, + 101271, + -11438, + 901, + -44, + 1, + ] + ) # beta factors as (u - 4) * (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 5*u + 2) * (u**2 - 2*u - 1) * (u**3 - 5*u**2 + 5*u - 7) * (u**3 - 4*u**2 + 3*u - 4) * (u**3 - 4*u**2 + 3*u - 1) * (u**3 - 3*u**2 + 2*u - 4) * (u**3 - 2*u**2 + 2*u - 2) * (u**3 + u + 1) * (u**4 - 4*u**3 - 2*u**2 - 4) * (u**5 - 5*u**4 + 5*u**3 - 11*u**2 + 6*u - 4) * (u**6 - 4*u**5 + 2*u**4 - 4*u**3 - u**2 + 4*u - 2) return data if l == 59: @@ -1811,15 +2065,138 @@ def _hyperelliptic_isogeny_data(l): data['A2'] = Zu([590, -1475, -295, 4130, -4425, 1711]) data['A4'] = Zuv(Zu([-2460, 8844, -3843, -20718, 57153, -50418, -12600, 72762, -69339, 30978, -5223]) + v * Zu([900, 360, -7560, 10800, -5220])) data['A6'] = Zuv(Zu([25760, -373560, 568020, 1147870, -4634370, 5318070, 1631996, -14270202, 21535998, -14119408, -2820102, 14275410, -13535292, 6790074, -1847898, 205378]) + v * Zu([-23688, 27972, 183708, -696024, 721980, 453600, -1925028, 2039184, -1027404, 205380])) - data['alpha'] = Zu([16000, -67200, -783520, 5573376, -5127336, -60792184, 241324042, -170978932, -1262437160, 4310971231, -3953349811, -10887235780, 41679530185, -51342089572, -33068562195, 230682514316, -372641172307, 121615007703, 682044179678, -1549365239197, 1373184591667, 614906882627, -3566756201696, 4920423266916, -2342393877496, -3589340274442, 8772457933356, -8488557160148, 1742977715620, 7131088674129, -11643540780203, 8512399456274, -315658868113, -6917286294515, 8713332734648, -5190227733987, -54249978263, 3397583328372, -3658171840037, 1987950394792, -179519591637, -748989116551, 800595050760, -459184355769, 134398080099, 28871590941, -64236756338, 46651654354, -23352309386, 9059054346, -2830320860, 721829600, -150487052, 25475079, -3452149, 365800, -29205, 1652, -59, 1]) - data['beta'] = Zu([0, -56000, 320800, 391440, -7693120, 21125500, 11515130, -204780145, 486681785, -102547033, -2147060784, 5552726794, -4419031758, -9431888681, 33728080307, -42367773552, -2994127157, 105330637610, -188172973931, 127559513693, 123083802224, -421097252069, 490425751691, -161944881372, -408669953969, 799965143719, -668167261718, 69589638764, 563644022562, -787681290965, 505670881115, 2900924856, -364669742737, 407962360532, -223582547975, 9985786664, 102435489491, -105519055992, 58212400117, -14331637533, -6742538722, 10205452686, -6853903214, 3244679736, -1188153136, 347102566, -81626216, 15409226, -2307408, 268126, -23322, 1429, -55, 1]) + data['alpha'] = Zu( + [ + 16000, + -67200, + -783520, + 5573376, + -5127336, + -60792184, + 241324042, + -170978932, + -1262437160, + 4310971231, + -3953349811, + -10887235780, + 41679530185, + -51342089572, + -33068562195, + 230682514316, + -372641172307, + 121615007703, + 682044179678, + -1549365239197, + 1373184591667, + 614906882627, + -3566756201696, + 4920423266916, + -2342393877496, + -3589340274442, + 8772457933356, + -8488557160148, + 1742977715620, + 7131088674129, + -11643540780203, + 8512399456274, + -315658868113, + -6917286294515, + 8713332734648, + -5190227733987, + -54249978263, + 3397583328372, + -3658171840037, + 1987950394792, + -179519591637, + -748989116551, + 800595050760, + -459184355769, + 134398080099, + 28871590941, + -64236756338, + 46651654354, + -23352309386, + 9059054346, + -2830320860, + 721829600, + -150487052, + 25475079, + -3452149, + 365800, + -29205, + 1652, + -59, + 1, + ] + ) + data['beta'] = Zu( + [ + 0, + -56000, + 320800, + 391440, + -7693120, + 21125500, + 11515130, + -204780145, + 486681785, + -102547033, + -2147060784, + 5552726794, + -4419031758, + -9431888681, + 33728080307, + -42367773552, + -2994127157, + 105330637610, + -188172973931, + 127559513693, + 123083802224, + -421097252069, + 490425751691, + -161944881372, + -408669953969, + 799965143719, + -668167261718, + 69589638764, + 563644022562, + -787681290965, + 505670881115, + 2900924856, + -364669742737, + 407962360532, + -223582547975, + 9985786664, + 102435489491, + -105519055992, + 58212400117, + -14331637533, + -6742538722, + 10205452686, + -6853903214, + 3244679736, + -1188153136, + 347102566, + -81626216, + 15409226, + -2307408, + 268126, + -23322, + 1429, + -55, + 1, + ] + ) # beta factors as (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 4*u - 1) * (u**2 - 3*u - 5) * (u**2 - 3*u - 2) * (u**2 - 3*u + 1) * (u**2 - u - 1) * (u**3 - 6*u**2 + 10*u - 7) * (u**3 - 5*u**2 + 7*u - 5) * (u**3 - 3*u**2 + 2*u - 1) * (u**3 - u**2 + 1) * (u**4 - 5*u**3 + 4*u**2 - 1) * (u**4 - 4*u**3 + 3*u**2 + 2*u - 4) * (u**4 - 3*u**3 - u - 1) * (u**4 - u**3 + 2*u - 1) * (u**5 - 6*u**4 + 10*u**3 - 11*u**2 + 8*u - 4) * (u**6 - 5*u**5 + 5*u**4 - 5*u**2 + 5*u - 5) return data if l == 71: data['hyper_poly'] = Zu([-7, 6, -27, 40, -58, 66, -66, 40, 15, -48, 66, -66, 37, -10, 1]) data['A2'] = Zu([213, -1420, 4260, -4970, 9940, -9088, 2485]) data['A4'] = Zuv(Zu([2565, -10008, 18024, -26532, 23208, 7584, -104418, 189432, -251736, 275148, -182232, 60144, -7563]) + v * Zu([720, -4320, 7560, -20160, 23040, -7560])) - data['A6'] = Zuv(Zu([-69930, 382536, -1898568, 5206124, -11813256, 23115792, -35705670, 44318064, -41531952, 20674360, 23881872, -77986944, 114989770, -124612152, 103122936, -59431204, 21485688, -4294416, 357910]) + v * Zu([18576, -53856, 57672, 161856, -961920, 3199176, -5706288, 8032896, -9352584, 6786720, -2505888, 357912])) + data['A6'] = Zuv( + Zu([-69930, 382536, -1898568, 5206124, -11813256, 23115792, -35705670, 44318064, -41531952, 20674360, 23881872, -77986944, 114989770, -124612152, 103122936, -59431204, 21485688, -4294416, 357910]) + + v * Zu([18576, -53856, 57672, 161856, -961920, 3199176, -5706288, 8032896, -9352584, 6786720, -2505888, 357912]) + ) data['alpha'] = Zu( [ -6750, @@ -1896,7 +2273,75 @@ def _hyperelliptic_isogeny_data(l): 1, ] ) - data['beta'] = Zu([0, 12150, -163215, 1115640, -5311143, 18820224, -50700172, 99823812, -102454041, -183909134, 1354660714, -4462311942, 10695310224, -20015395554, 28262441676, -23240987282, -17879387475, 124501604946, -315187724212, 564766450688, -765154573538, 705985549104, -115433273216, -1206098873334, 3175185881748, -5228317292044, 6292310032120, -5077451367560, 719644756530, 6451571564682, -14460150103020, 19999710623352, -19681838601268, 11819712227412, 2180981559572, -17790742756618, 29025463386612, -31179247603548, 23207078145510, -8345354986332, -7468523752270, 18486966963350, -21719818051100, 17831212433536, -10100011266030, 2336962513536, 2906983627184, -4989755986066, 4711466210012, -3361479243242, 1952316811463, -948555371584, 389878900245, -136099552242, 40341734984, -10121407164, 2136756509, -376218102, 54551634, -6399080, 591884, -41538, 2078, -66, 1]) + data['beta'] = Zu( + [ + 0, + 12150, + -163215, + 1115640, + -5311143, + 18820224, + -50700172, + 99823812, + -102454041, + -183909134, + 1354660714, + -4462311942, + 10695310224, + -20015395554, + 28262441676, + -23240987282, + -17879387475, + 124501604946, + -315187724212, + 564766450688, + -765154573538, + 705985549104, + -115433273216, + -1206098873334, + 3175185881748, + -5228317292044, + 6292310032120, + -5077451367560, + 719644756530, + 6451571564682, + -14460150103020, + 19999710623352, + -19681838601268, + 11819712227412, + 2180981559572, + -17790742756618, + 29025463386612, + -31179247603548, + 23207078145510, + -8345354986332, + -7468523752270, + 18486966963350, + -21719818051100, + 17831212433536, + -10100011266030, + 2336962513536, + 2906983627184, + -4989755986066, + 4711466210012, + -3361479243242, + 1952316811463, + -948555371584, + 389878900245, + -136099552242, + 40341734984, + -10121407164, + 2136756509, + -376218102, + 54551634, + -6399080, + 591884, + -41538, + 2078, + -66, + 1, + ] + ) # beta factors as (u - 3) * (u - 2) * (u - 1) * u * (u + 1) * (u**2 - 5*u + 5) * (u**2 - 3*u + 1) * (u**2 - 2*u - 1) * (u**2 - u - 1) * (u**3 - 5*u**2 + 5*u - 3) * (u**3 - 4*u**2 - 1) * (u**3 - 2*u**2 - 1) * (u**4 - 6*u**3 + 7*u**2 + 6*u - 9) * (u**4 - 5*u**3 + 4*u**2 + u + 3) * (u**4 - 5*u**3 + 6*u**2 - 3*u + 5) * (u**4 - 4*u**3 + u**2 - 4*u + 1) * (u**4 - 4*u**3 + 2*u**2 - u + 1) * (u**4 - 2*u**3 - 3*u**2 - 2*u - 1) * (u**4 - 2*u**3 + u - 1) * (u**6 - 5*u**5 + 8*u**4 - 7*u**3 + 6*u**2 - 3*u + 1) * (u**8 - 6*u**7 + 9*u**6 - 2*u**5 + 2*u**3 - 9*u**2 + 2*u - 1) return data diff --git a/src/sage/schemes/hyperelliptic_curves/kummer_surface.py b/src/sage/schemes/hyperelliptic_curves/kummer_surface.py index 0f236f846c1..9c12fe0f5b1 100644 --- a/src/sage/schemes/hyperelliptic_curves/kummer_surface.py +++ b/src/sage/schemes/hyperelliptic_curves/kummer_surface.py @@ -75,7 +75,18 @@ def __init__(self, J): K2 = X1**2 - 4 * X0 * X2 - K1 = (4 * f0 + h0**2) * X0**3 + (2 * f1 + h0 * h1) * X0**2 * X1 + (h0 * h2) * X0 * X1**2 + (h0 * h3) * X1**3 + (4 * f2 - 2 * h0 * h2 + h1**2) * X0**2 * X2 + (2 * f3 - 3 * h0 * h3 + h1 * h2) * X0 * X1 * X2 + (h1 * h3) * X1**2 * X2 + (4 * f4 - 2 * h1 * h3 + h2**2) * X0 * X2**2 + (2 * f5 + h2 * h3) * X1 * X2**2 + (4 * f6 + h3**2) * X2**3 + K1 = ( + (4 * f0 + h0**2) * X0**3 + + (2 * f1 + h0 * h1) * X0**2 * X1 + + (h0 * h2) * X0 * X1**2 + + (h0 * h3) * X1**3 + + (4 * f2 - 2 * h0 * h2 + h1**2) * X0**2 * X2 + + (2 * f3 - 3 * h0 * h3 + h1 * h2) * X0 * X1 * X2 + + (h1 * h3) * X1**2 * X2 + + (4 * f4 - 2 * h1 * h3 + h2**2) * X0 * X2**2 + + (2 * f5 + h2 * h3) * X1 * X2**2 + + (4 * f6 + h3**2) * X2**3 + ) K0 = ( (-4 * f0 * f2 - f0 * h1**2 + f1**2 + f1 * h0 * h1 - f2 * h0**2) * X0**4 @@ -188,7 +199,24 @@ def _mumford_to_kummer(self, P): x0 = denom x1 = -u1 * denom x2 = u0 * denom - term = (-(f5**2) + 4 * f4 * f6) * u0**4 + (-4 * f3 * f6) * u0**3 * u1 + 2 * f3 * f5 * u0**3 + 4 * f2 * f6 * u0**2 * u1**2 + (-4 * f2 * f5 + 4 * f1 * f6) * u0**2 * u1 + (-(f3**2) + 4 * f2 * f4 - 2 * f1 * f5 + 4 * f0 * f6) * u0**2 + (-4 * f1 * f6) * u0 * u1**3 + (4 * f1 * f5 - 8 * f0 * f6) * u0 * u1**2 + (-4 * f1 * f4 + 4 * f0 * f5) * u0 * u1 + 2 * f1 * f3 * u0 + 4 * f0 * f6 * u1**4 + (-4 * f0 * f5) * u1**3 + 4 * f0 * f4 * u1**2 + (-4 * f0 * f3) * u1 - f1**2 + 4 * f0 * f2 + term = ( + (-(f5**2) + 4 * f4 * f6) * u0**4 + + (-4 * f3 * f6) * u0**3 * u1 + + 2 * f3 * f5 * u0**3 + + 4 * f2 * f6 * u0**2 * u1**2 + + (-4 * f2 * f5 + 4 * f1 * f6) * u0**2 * u1 + + (-(f3**2) + 4 * f2 * f4 - 2 * f1 * f5 + 4 * f0 * f6) * u0**2 + + (-4 * f1 * f6) * u0 * u1**3 + + (4 * f1 * f5 - 8 * f0 * f6) * u0 * u1**2 + + (-4 * f1 * f4 + 4 * f0 * f5) * u0 * u1 + + 2 * f1 * f3 * u0 + + 4 * f0 * f6 * u1**4 + + (-4 * f0 * f5) * u1**3 + + 4 * f0 * f4 * u1**2 + + (-4 * f0 * f3) * u1 + - f1**2 + + 4 * f0 * f2 + ) x3 = 4 * (F0 + h1h2 - y1y2) * y1y2 - (term * (u1**2 - 4 * u0) + F0**2) elif u1 == R.one(): # In this case, the divisor is of the form [P + O0 - D_{\infty}], diff --git a/src/sage/schemes/toric/library.py b/src/sage/schemes/toric/library.py index c42b5222288..a7804751349 100644 --- a/src/sage/schemes/toric/library.py +++ b/src/sage/schemes/toric/library.py @@ -68,13 +68,108 @@ 'A2_Z2': [[(1, 0), (1, 2)], [[0, 1]]], 'P1xA1': [[(1, 0), (-1, 0), (0, 1)], [[0, 2], [2, 1]]], 'Conifold': [[(0, 0, 1), (0, 1, 1), (1, 0, 1), (1, 1, 1)], [[0, 1, 2, 3]]], - 'dP6xdP6': [[(0, 1, 0, 0), (-1, 0, 0, 0), (-1, -1, 0, 0), (0, -1, 0, 0), (1, 0, 0, 0), (1, 1, 0, 0), (0, 0, 0, 1), (0, 0, -1, 0), (0, 0, -1, -1), (0, 0, 0, -1), (0, 0, 1, 0), (0, 0, 1, 1)], [[0, 1, 6, 7], [0, 1, 7, 8], [0, 1, 8, 9], [0, 1, 9, 10], [0, 1, 10, 11], [0, 1, 6, 11], [1, 2, 6, 7], [1, 2, 7, 8], [1, 2, 8, 9], [1, 2, 9, 10], [1, 2, 10, 11], [1, 2, 6, 11], [2, 3, 6, 7], [2, 3, 7, 8], [2, 3, 8, 9], [2, 3, 9, 10], [2, 3, 10, 11], [2, 3, 6, 11], [3, 4, 6, 7], [3, 4, 7, 8], [3, 4, 8, 9], [3, 4, 9, 10], [3, 4, 10, 11], [3, 4, 6, 11], [4, 5, 6, 7], [4, 5, 7, 8], [4, 5, 8, 9], [4, 5, 9, 10], [4, 5, 10, 11], [4, 5, 6, 11], [0, 5, 6, 7], [0, 5, 7, 8], [0, 5, 8, 9], [0, 5, 9, 10], [0, 5, 10, 11], [0, 5, 6, 11]]], + 'dP6xdP6': [ + [(0, 1, 0, 0), (-1, 0, 0, 0), (-1, -1, 0, 0), (0, -1, 0, 0), (1, 0, 0, 0), (1, 1, 0, 0), (0, 0, 0, 1), (0, 0, -1, 0), (0, 0, -1, -1), (0, 0, 0, -1), (0, 0, 1, 0), (0, 0, 1, 1)], + [ + [0, 1, 6, 7], + [0, 1, 7, 8], + [0, 1, 8, 9], + [0, 1, 9, 10], + [0, 1, 10, 11], + [0, 1, 6, 11], + [1, 2, 6, 7], + [1, 2, 7, 8], + [1, 2, 8, 9], + [1, 2, 9, 10], + [1, 2, 10, 11], + [1, 2, 6, 11], + [2, 3, 6, 7], + [2, 3, 7, 8], + [2, 3, 8, 9], + [2, 3, 9, 10], + [2, 3, 10, 11], + [2, 3, 6, 11], + [3, 4, 6, 7], + [3, 4, 7, 8], + [3, 4, 8, 9], + [3, 4, 9, 10], + [3, 4, 10, 11], + [3, 4, 6, 11], + [4, 5, 6, 7], + [4, 5, 7, 8], + [4, 5, 8, 9], + [4, 5, 9, 10], + [4, 5, 10, 11], + [4, 5, 6, 11], + [0, 5, 6, 7], + [0, 5, 7, 8], + [0, 5, 8, 9], + [0, 5, 9, 10], + [0, 5, 10, 11], + [0, 5, 6, 11], + ], + ], 'Cube_face_fan': [[(1, 1, 1), (1, -1, 1), (-1, 1, 1), (-1, -1, 1), (-1, -1, -1), (-1, 1, -1), (1, -1, -1), (1, 1, -1)], [[0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 7, 6], [4, 5, 3, 2], [0, 2, 5, 7], [4, 6, 1, 3]]], 'Cube_sublattice': [[(1, 0, 0), (0, 1, 0), (0, 0, 1), (-1, 1, 1), (-1, 0, 0), (0, -1, 0), (0, 0, -1), (1, -1, -1)], [[0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 7, 6], [4, 5, 3, 2], [0, 2, 5, 7], [4, 6, 1, 3]]], 'Cube_nonpolyhedral': [[(1, 2, 3), (1, -1, 1), (-1, 1, 1), (-1, -1, 1), (-1, -1, -1), (-1, 1, -1), (1, -1, -1), (1, 1, -1)], [[0, 1, 2, 3], [4, 5, 6, 7], [0, 1, 7, 6], [4, 5, 3, 2], [0, 2, 5, 7], [4, 6, 1, 3]]], 'BCdlOG': [ [(-1, 0, 0, 2, 3), (0, -1, 0, 2, 3), (0, 0, -1, 2, 3), (0, 0, -1, 1, 2), (0, 0, 0, -1, 0), (0, 0, 0, 0, -1), (0, 0, 0, 2, 3), (0, 0, 1, 2, 3), (0, 0, 2, 2, 3), (0, 0, 1, 1, 1), (0, 1, 2, 2, 3), (0, 1, 3, 2, 3), (1, 0, 4, 2, 3)], # 0 # 1 # 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 # 10 # 11 # 12 - [[0, 6, 7, 1, 4], [0, 6, 10, 2, 4], [0, 6, 1, 2, 4], [0, 9, 7, 1, 5], [0, 6, 7, 1, 5], [0, 6, 10, 2, 5], [0, 6, 1, 2, 5], [0, 9, 1, 4, 5], [0, 6, 10, 4, 11], [0, 6, 7, 4, 11], [0, 6, 10, 5, 11], [0, 9, 7, 5, 11], [0, 6, 7, 5, 11], [0, 9, 4, 5, 11], [0, 10, 4, 5, 11], [0, 9, 7, 1, 8], [0, 9, 1, 4, 8], [0, 7, 1, 4, 8], [0, 9, 7, 11, 8], [0, 9, 4, 11, 8], [0, 7, 4, 11, 8], [0, 10, 2, 4, 3], [0, 1, 2, 4, 3], [0, 10, 2, 5, 3], [0, 1, 2, 5, 3], [0, 10, 4, 5, 3], [0, 1, 4, 5, 3], [12, 6, 7, 1, 4], [12, 6, 10, 2, 4], [12, 6, 1, 2, 4], [12, 9, 7, 1, 5], [12, 6, 7, 1, 5], [12, 6, 10, 2, 5], [12, 6, 1, 2, 5], [12, 9, 1, 4, 5], [12, 6, 10, 4, 11], [12, 6, 7, 4, 11], [12, 6, 10, 5, 11], [12, 9, 7, 5, 11], [12, 6, 7, 5, 11], [12, 9, 4, 5, 11], [12, 10, 4, 5, 11], [12, 9, 7, 1, 8], [12, 9, 1, 4, 8], [12, 7, 1, 4, 8], [12, 9, 7, 11, 8], [12, 9, 4, 11, 8], [12, 7, 4, 11, 8], [12, 10, 2, 4, 3], [12, 1, 2, 4, 3], [12, 10, 2, 5, 3], [12, 1, 2, 5, 3], [12, 10, 4, 5, 3], [12, 1, 4, 5, 3]], + [ + [0, 6, 7, 1, 4], + [0, 6, 10, 2, 4], + [0, 6, 1, 2, 4], + [0, 9, 7, 1, 5], + [0, 6, 7, 1, 5], + [0, 6, 10, 2, 5], + [0, 6, 1, 2, 5], + [0, 9, 1, 4, 5], + [0, 6, 10, 4, 11], + [0, 6, 7, 4, 11], + [0, 6, 10, 5, 11], + [0, 9, 7, 5, 11], + [0, 6, 7, 5, 11], + [0, 9, 4, 5, 11], + [0, 10, 4, 5, 11], + [0, 9, 7, 1, 8], + [0, 9, 1, 4, 8], + [0, 7, 1, 4, 8], + [0, 9, 7, 11, 8], + [0, 9, 4, 11, 8], + [0, 7, 4, 11, 8], + [0, 10, 2, 4, 3], + [0, 1, 2, 4, 3], + [0, 10, 2, 5, 3], + [0, 1, 2, 5, 3], + [0, 10, 4, 5, 3], + [0, 1, 4, 5, 3], + [12, 6, 7, 1, 4], + [12, 6, 10, 2, 4], + [12, 6, 1, 2, 4], + [12, 9, 7, 1, 5], + [12, 6, 7, 1, 5], + [12, 6, 10, 2, 5], + [12, 6, 1, 2, 5], + [12, 9, 1, 4, 5], + [12, 6, 10, 4, 11], + [12, 6, 7, 4, 11], + [12, 6, 10, 5, 11], + [12, 9, 7, 5, 11], + [12, 6, 7, 5, 11], + [12, 9, 4, 5, 11], + [12, 10, 4, 5, 11], + [12, 9, 7, 1, 8], + [12, 9, 1, 4, 8], + [12, 7, 1, 4, 8], + [12, 9, 7, 11, 8], + [12, 9, 4, 11, 8], + [12, 7, 4, 11, 8], + [12, 10, 2, 4, 3], + [12, 1, 2, 4, 3], + [12, 10, 2, 5, 3], + [12, 1, 2, 5, 3], + [12, 10, 4, 5, 3], + [12, 1, 4, 5, 3], + ], ], 'BCdlOG_base': [[(-1, 0, 0), (0, -1, 0), (0, 0, -1), (0, 0, 1), (0, 1, 2), (0, 1, 3), (1, 0, 4)], [[0, 4, 2], [0, 4, 5], [0, 5, 3], [0, 1, 3], [0, 1, 2], [6, 4, 2], [6, 4, 5], [6, 5, 3], [6, 1, 3], [6, 1, 2]]], 'P2_112': [[(1, 0), (0, 1), (-1, -2)], [[0, 1], [1, 2], [2, 0]]], diff --git a/src/sage/symbolic/expression_conversions.py b/src/sage/symbolic/expression_conversions.py index 7e17c4a5f23..a50512ad318 100644 --- a/src/sage/symbolic/expression_conversions.py +++ b/src/sage/symbolic/expression_conversions.py @@ -1680,7 +1680,20 @@ class Exponentialize(ExpressionTreeWalker): half = Integer(1) / Integer(2) two = Integer(2) x = SR.var("x") - CircDict = {sin: (-half * I * exp(I * x) + half * I * exp(-I * x)).function(x), cos: (half * exp(I * x) + half * exp(-I * x)).function(x), sec: (two / (exp(I * x) + exp(-I * x))).function(x), csc: (two * I / (exp(I * x) - exp(-I * x))).function(x), tan: (-I * (exp(I * x) - exp(-I * x)) / (exp(I * x) + exp(-I * x))).function(x), cot: (I * (exp(I * x) + exp(-I * x)) / (exp(I * x) - exp(-I * x))).function(x), sinh: (-half * exp(-x) + half * exp(x)).function(x), cosh: (half * exp(-x) + half * exp(x)).function(x), sech: (two / (exp(-x) + exp(x))).function(x), csch: (-two / (exp(-x) - exp(x))).function(x), tanh: (-(exp(-x) - exp(x)) / (exp(x) + exp(-x))).function(x), coth: (-(exp(-x) + exp(x)) / (exp(-x) - exp(x))).function(x)} + CircDict = { + sin: (-half * I * exp(I * x) + half * I * exp(-I * x)).function(x), + cos: (half * exp(I * x) + half * exp(-I * x)).function(x), + sec: (two / (exp(I * x) + exp(-I * x))).function(x), + csc: (two * I / (exp(I * x) - exp(-I * x))).function(x), + tan: (-I * (exp(I * x) - exp(-I * x)) / (exp(I * x) + exp(-I * x))).function(x), + cot: (I * (exp(I * x) + exp(-I * x)) / (exp(I * x) - exp(-I * x))).function(x), + sinh: (-half * exp(-x) + half * exp(x)).function(x), + cosh: (half * exp(-x) + half * exp(x)).function(x), + sech: (two / (exp(-x) + exp(x))).function(x), + csch: (-two / (exp(-x) - exp(x))).function(x), + tanh: (-(exp(-x) - exp(x)) / (exp(x) + exp(-x))).function(x), + coth: (-(exp(-x) + exp(x)) / (exp(-x) - exp(x))).function(x), + } Circs = list(CircDict) def __init__(self, ex): @@ -1803,7 +1816,20 @@ class HalfAngle(ExpressionTreeWalker): two = Integer(2) half = one / two halfx = half * x - HalvesDict = {sin: two * tan(halfx) / (tan(halfx) ** 2 + one).function(x), cos: -(tan(halfx) ** 2 - one) / (tan(halfx) ** 2 + one).function(x), tan: -two * tan(halfx) / (tan(halfx) ** 2 - one).function(x), csc: half * (tan(halfx) ** 2 + one) / tan(halfx).function(x), sec: -(tan(halfx) ** 2 + one) / (tan(halfx) ** 2 - one).function(x), cot: -half * (tan(halfx) ** 2 - one) / tan(halfx).function(x), sinh: -two * tanh(halfx) / (tanh(halfx) ** 2 - one).function(x), cosh: -(tanh(halfx) ** 2 + one) / (tanh(halfx) ** 2 - one).function(x), tanh: two * tanh(halfx) / (tanh(halfx) ** 2 + one).function(x), csch: -half * (tanh(halfx) ** 2 - one) / tanh(halfx).function(x), sech: -(tanh(halfx) ** 2 - one) / (tanh(halfx) ** 2 + one).function(x), coth: half * (tanh(halfx) ** 2 + one) / tanh(halfx).function(x)} + HalvesDict = { + sin: two * tan(halfx) / (tan(halfx) ** 2 + one).function(x), + cos: -(tan(halfx) ** 2 - one) / (tan(halfx) ** 2 + one).function(x), + tan: -two * tan(halfx) / (tan(halfx) ** 2 - one).function(x), + csc: half * (tan(halfx) ** 2 + one) / tan(halfx).function(x), + sec: -(tan(halfx) ** 2 + one) / (tan(halfx) ** 2 - one).function(x), + cot: -half * (tan(halfx) ** 2 - one) / tan(halfx).function(x), + sinh: -two * tanh(halfx) / (tanh(halfx) ** 2 - one).function(x), + cosh: -(tanh(halfx) ** 2 + one) / (tanh(halfx) ** 2 - one).function(x), + tanh: two * tanh(halfx) / (tanh(halfx) ** 2 + one).function(x), + csch: -half * (tanh(halfx) ** 2 - one) / tanh(halfx).function(x), + sech: -(tanh(halfx) ** 2 - one) / (tanh(halfx) ** 2 + one).function(x), + coth: half * (tanh(halfx) ** 2 + one) / tanh(halfx).function(x), + } Halves = list(HalvesDict) def __init__(self, ex): diff --git a/src/sage/symbolic/units.py b/src/sage/symbolic/units.py index 258b670ef34..251158e2649 100644 --- a/src/sage/symbolic/units.py +++ b/src/sage/symbolic/units.py @@ -112,7 +112,17 @@ 'electric_potential': {'abvolt': one / 100000000, 'statvolt': QQ(149896229) / 500000, 'volt': 1}, 'energy': {'british_thermal_unit': QQ(52752792631) / 50000000, 'btu': QQ(52752792631) / 50000000, 'calorie': QQ(10467) / 2500, 'electron_volt': '1.60217733000000e-19', 'erg': one / 10000000, 'ev': '1.60217733000000e-19', 'joule': 1, 'rydberg': '2.17987200000000e-18', 'therm': QQ(52752792631) / 500}, 'fiber_linear_mass_density': {'denier': one / 9000000, 'tex': one / 1000000}, - 'force': {'dyne': one / 100000, 'gram_weight': QQ(196133) / 20000000, 'kilogram_force': QQ(196133) / 20000, 'kilogram_weight': QQ(196133) / 20000, 'newton': 1, 'pound_force': QQ(8896443230521) / 2000000000000, 'pound_weight': QQ(8896443230521) / 2000000000000, 'poundal': QQ(17281869297) / 125000000000, 'ton_force': QQ(8896443230521) / 1000000000}, + 'force': { + 'dyne': one / 100000, + 'gram_weight': QQ(196133) / 20000000, + 'kilogram_force': QQ(196133) / 20000, + 'kilogram_weight': QQ(196133) / 20000, + 'newton': 1, + 'pound_force': QQ(8896443230521) / 2000000000000, + 'pound_weight': QQ(8896443230521) / 2000000000000, + 'poundal': QQ(17281869297) / 125000000000, + 'ton_force': QQ(8896443230521) / 1000000000, + }, 'frequency': {'1/second': 1, 'hertz': 1}, 'illuminance': {'foot_candle': QQ(1562500) / 145161, 'lux': 1, 'phot': 10000}, 'inductance': {'abhenry': one / 1000000000, 'henry': 1, 'stathenry': QQ(22468879468420441) / 25000}, @@ -216,15 +226,70 @@ 'wey': QQ(2857631931) / 25000000, }, 'power': {'cheval_vapeur': QQ(588399) / 800, 'horsepower': QQ(37284993579113511) / 50000000000000, 'watt': 1}, - 'pressure': {'atmosphere': 101325, 'bar': 100000, 'barye': QQ((1, 10)), 'inch_mercury': '3386.38900000000', 'millimeter_mercury': '133.322400000000', 'mmhg': '133.322400000000', 'pa': 1, 'pascal': 1, 'pounds_per_square_inch': QQ(8896443230521) / 1290320000, 'psi': QQ(8896443230521) / 1290320000, 'torr': QQ(20265) / 152}, + 'pressure': { + 'atmosphere': 101325, + 'bar': 100000, + 'barye': QQ((1, 10)), + 'inch_mercury': '3386.38900000000', + 'millimeter_mercury': '133.322400000000', + 'mmhg': '133.322400000000', + 'pa': 1, + 'pascal': 1, + 'pounds_per_square_inch': QQ(8896443230521) / 1290320000, + 'psi': QQ(8896443230521) / 1290320000, + 'torr': QQ(20265) / 152, + }, 'radiation': {'becquerel': 1, 'curie': 37000000000, 'rutherford': 1000000}, 'radiation_absorbed': {'gray': 1, 'rad': one / 100}, 'radiation_ionizing': {'roentgen': '0.000258000000000000', 'rontgen': '0.000258000000000000'}, 'resistance': {'abohm': one / 1000000000, 'ohm': 1, 'statohm': QQ(22468879468420441) / 25000}, - 'si_prefixes': {'atto': one / 1000000000000000000, 'centi': one / 100, 'deca': 10, 'deci': QQ((1, 10)), 'exa': 1000000000000000000, 'femto': one / 1000000000000000, 'giga': 1000000000, 'hecto': 100, 'kilo': 1000, 'mega': 1000000, 'micro': one / 1000000, 'milli': one / 1000, 'nano': one / 1000000000, 'peta': 1000000000000000, 'pico': one / 1000000000000, 'tera': 1000000000000, 'yocto': one / 1000000000000000000000000, 'yotta': 1000000000000000000000000, 'zepto': one / 1000000000000000000000, 'zetta': 1000000000000000000000}, + 'si_prefixes': { + 'atto': one / 1000000000000000000, + 'centi': one / 100, + 'deca': 10, + 'deci': QQ((1, 10)), + 'exa': 1000000000000000000, + 'femto': one / 1000000000000000, + 'giga': 1000000000, + 'hecto': 100, + 'kilo': 1000, + 'mega': 1000000, + 'micro': one / 1000000, + 'milli': one / 1000, + 'nano': one / 1000000000, + 'peta': 1000000000000000, + 'pico': one / 1000000000000, + 'tera': 1000000000000, + 'yocto': one / 1000000000000000000000000, + 'yotta': 1000000000000000000000000, + 'zepto': one / 1000000000000000000000, + 'zetta': 1000000000000000000000, + }, 'solid_angle': {'steradian': 1}, - 'temperature': {'celsius': '(x + 273.15), (x), (x*9/5 + 32), ((x+273.15)*9/5)', 'centigrade': '(x + 273.15), (x), (x*9/5 + 32), ((x+273.15)*9/5)', 'fahrenheit': '(5/9*(x + 459.67)), ((x - 32)*5/9), (x), (x+459.67)', 'kelvin': '(x), (x - 273.15), (x*9/5 - 459.67), (x*9/5)', 'rankine': '(5/9*x), ((x-491.67)*5/9), (x-459.67), (x)'}, - 'time': {'century': 3153600000, 'day': 86400, 'decade': 315360000, 'fortnight': 1209600, 'hour': 3600, 'millenium': 31536000000, 'minute': 60, 'month': 2628000, 'second': 1, 'sidereal_day': "(86164.0905308330, {'sidereal':86400})", 'sidereal_second': "(0.997269566329086, {'sidereal':1})", 'sidereal_year': '3.15581497632000e7', 'tropical_year': '3.15569251779840e7', 'week': 604800, 'year': 31536000}, + 'temperature': { + 'celsius': '(x + 273.15), (x), (x*9/5 + 32), ((x+273.15)*9/5)', + 'centigrade': '(x + 273.15), (x), (x*9/5 + 32), ((x+273.15)*9/5)', + 'fahrenheit': '(5/9*(x + 459.67)), ((x - 32)*5/9), (x), (x+459.67)', + 'kelvin': '(x), (x - 273.15), (x*9/5 - 459.67), (x*9/5)', + 'rankine': '(5/9*x), ((x-491.67)*5/9), (x-459.67), (x)', + }, + 'time': { + 'century': 3153600000, + 'day': 86400, + 'decade': 315360000, + 'fortnight': 1209600, + 'hour': 3600, + 'millenium': 31536000000, + 'minute': 60, + 'month': 2628000, + 'second': 1, + 'sidereal_day': "(86164.0905308330, {'sidereal':86400})", + 'sidereal_second': "(0.997269566329086, {'sidereal':1})", + 'sidereal_year': '3.15581497632000e7', + 'tropical_year': '3.15569251779840e7', + 'week': 604800, + 'year': 31536000, + }, 'unit_multipliers': {'bakers_dozen': 13, 'dozen': 12, 'gross': 144, 'percent': one / 100}, 'velocity': {'knot': '463/900'}, 'viscosity_absolute': {'poise': one / 10, 'reyn': QQ(8896443230521) / 1290320000}, @@ -320,14 +385,56 @@ def evalunitdict(): unit_docs = { 'acceleration_docs': {'gal': 'Abbreviation for galileo.\nDefined to be 1/100 meter/second^2.', 'galileo': 'Defined to be 1/100 meter/second^2.', 'gravity': 'Also called standard gravity.\nPhysical constant defined to be 9.80665 meter/second^2.'}, - 'amount_of_substance_docs': {'elementary_entity': 'Defined to be one elementary unit of choice, usually atoms or other elementary particles.\nApproximately equal to 1.6605e-24 moles.', 'mole': 'SI base unit of quantity.\nDefined to be the amount of substance that has an equal number of elementary entities as there are atoms in 12 grams of carbon-12.\nEquivalent to Avogadros constant elementary entities or approximately equal to 6.022*10^23 elementary entities.'}, - 'angles_docs': {'arc_minute': 'Defined to be 1/60 of a degree or pi/10800 radians.', 'arc_second': 'Defined to be 1/3600 of a degree or pi/648000 radians.', 'degree': 'Defined to be pi/180 radians.', 'grade': 'Defined to be pi/200 radians.', 'quadrant': 'Equivalent to a right angle.\nDefined to be pi/2 radians.', 'radian': 'SI derived unit of angle.\nDefined to be the angle subtended at the center of a circle by an arc that is equal in length to the radius of the circle.', 'right_angle': 'Equivalent to a quadrant.\nDefined to be pi/2 radians.'}, - 'area_docs': {'acre': 'Defined to be 10 square chains or 4840 square yards.\nApproximately equal to 4046.856 square meters.', 'are': 'Defined to be 100 square meters.', 'barn': 'Defined to be 100 square femtometers or 10^-28 square meters.', 'hectare': 'Defined to be 10000 square meters.', 'rood': 'Defined to be 1/4 of an acre.\nApproximately equal to 1011.714 square meters.', 'section': 'Equivalent to a square mile.\nApproximately equal to 2.59*10^6 square meters.', 'square_chain': 'Defined to be 4356 square feet.\nApproximately equal to 404.9856 square meters.', 'square_meter': 'SI derived unit of area.\nDefined to be meter^2.', 'township': 'Defined to be 36 square miles.\nApproximately equal to 9.324*10^7 square meters.'}, - 'capacitance_docs': {'abfarad': 'Defined to be 10^9 farads.', 'farad': 'SI derived unit of capacitance.\nDefined to be the charge in coulombs a capacitor will accept for the potential across it to change one volt.\nEquivalent to coulomb/volt.', 'statfarad': 'CGS unit defined to be statcoulomb/statvolt.\nApproximately equal to 1.11265*10^-12 farads.'}, - 'charge_docs': {'abcoulomb': 'CGS unit defined to be 10 coulombs.', 'coulomb': 'SI derived unit of charge.\nDefined to be the amount of electric charge transported by 1 ampere in 1 second.', 'elementary_charge': 'Defined to be the amount of electric charge carried by a single proton or negative charge carried by a single electron.\nApproximately equal to 1.602176462*10^-19 coulombs.', 'faraday': 'Defined to be the magnitude of electric charge in one mole of electrons.\nApproximately equal to 96485.3399 coulombs.', 'franklin': 'CGS unit defined to be the amount of electric charge necessary such that if two stationary objects placed one centimeter apart had one franklin of charge each they would repel each other with a force of one dyne.\nApproximately equal to 3.3356*10^-10 coulombs.', 'statcoulomb': 'Equivalent to franklin.\nApproximately equal to 3.3356*10^-10 coulombs.'}, + 'amount_of_substance_docs': { + 'elementary_entity': 'Defined to be one elementary unit of choice, usually atoms or other elementary particles.\nApproximately equal to 1.6605e-24 moles.', + 'mole': 'SI base unit of quantity.\nDefined to be the amount of substance that has an equal number of elementary entities as there are atoms in 12 grams of carbon-12.\nEquivalent to Avogadros constant elementary entities or approximately equal to 6.022*10^23 elementary entities.', + }, + 'angles_docs': { + 'arc_minute': 'Defined to be 1/60 of a degree or pi/10800 radians.', + 'arc_second': 'Defined to be 1/3600 of a degree or pi/648000 radians.', + 'degree': 'Defined to be pi/180 radians.', + 'grade': 'Defined to be pi/200 radians.', + 'quadrant': 'Equivalent to a right angle.\nDefined to be pi/2 radians.', + 'radian': 'SI derived unit of angle.\nDefined to be the angle subtended at the center of a circle by an arc that is equal in length to the radius of the circle.', + 'right_angle': 'Equivalent to a quadrant.\nDefined to be pi/2 radians.', + }, + 'area_docs': { + 'acre': 'Defined to be 10 square chains or 4840 square yards.\nApproximately equal to 4046.856 square meters.', + 'are': 'Defined to be 100 square meters.', + 'barn': 'Defined to be 100 square femtometers or 10^-28 square meters.', + 'hectare': 'Defined to be 10000 square meters.', + 'rood': 'Defined to be 1/4 of an acre.\nApproximately equal to 1011.714 square meters.', + 'section': 'Equivalent to a square mile.\nApproximately equal to 2.59*10^6 square meters.', + 'square_chain': 'Defined to be 4356 square feet.\nApproximately equal to 404.9856 square meters.', + 'square_meter': 'SI derived unit of area.\nDefined to be meter^2.', + 'township': 'Defined to be 36 square miles.\nApproximately equal to 9.324*10^7 square meters.', + }, + 'capacitance_docs': { + 'abfarad': 'Defined to be 10^9 farads.', + 'farad': 'SI derived unit of capacitance.\nDefined to be the charge in coulombs a capacitor will accept for the potential across it to change one volt.\nEquivalent to coulomb/volt.', + 'statfarad': 'CGS unit defined to be statcoulomb/statvolt.\nApproximately equal to 1.11265*10^-12 farads.', + }, + 'charge_docs': { + 'abcoulomb': 'CGS unit defined to be 10 coulombs.', + 'coulomb': 'SI derived unit of charge.\nDefined to be the amount of electric charge transported by 1 ampere in 1 second.', + 'elementary_charge': 'Defined to be the amount of electric charge carried by a single proton or negative charge carried by a single electron.\nApproximately equal to 1.602176462*10^-19 coulombs.', + 'faraday': 'Defined to be the magnitude of electric charge in one mole of electrons.\nApproximately equal to 96485.3399 coulombs.', + 'franklin': 'CGS unit defined to be the amount of electric charge necessary such that if two stationary objects placed one centimeter apart had one franklin of charge each they would repel each other with a force of one dyne.\nApproximately equal to 3.3356*10^-10 coulombs.', + 'statcoulomb': 'Equivalent to franklin.\nApproximately equal to 3.3356*10^-10 coulombs.', + }, 'conductance_docs': {'abmho': 'Defined to be 10^9 siemens.', 'mho': 'Equivalent to siemens.', 'siemens': 'SI derived unit of conductance.\nDefined to be an ampere per volt or 1/ohm.'}, - 'current_docs': {'abampere': 'CGS unit defined to be 10 amperes.', 'amp': 'Abbreviation for ampere.', 'ampere': 'SI base unit of current.\nDefined to be the constant current which will produce an attractive force of 2*10^-7 newtons per meter between two straight, parallel conductors of infinite length and negligible circular cross section placed one meter apart in free space.', 'biot': 'Equivalent to abampere.\nEqual to 10 amperes.', 'statampere': 'CGS unit defined to be statcoulomb/second.\nApproximately equal to 3.335641*10^-10 amperes.'}, - 'electric_potential_docs': {'abvolt': 'Defined to be 10^-8 volts.', 'statvolt': 'CGS unit defined to be the speed of light in a vacuum/10^6 volts or approximately 299.792 volts.', 'volt': 'SI derived unit of electric potential.\nDefined to be the value of voltage across a conductor when a current of one ampere dissipates one watt of power.'}, + 'current_docs': { + 'abampere': 'CGS unit defined to be 10 amperes.', + 'amp': 'Abbreviation for ampere.', + 'ampere': 'SI base unit of current.\nDefined to be the constant current which will produce an attractive force of 2*10^-7 newtons per meter between two straight, parallel conductors of infinite length and negligible circular cross section placed one meter apart in free space.', + 'biot': 'Equivalent to abampere.\nEqual to 10 amperes.', + 'statampere': 'CGS unit defined to be statcoulomb/second.\nApproximately equal to 3.335641*10^-10 amperes.', + }, + 'electric_potential_docs': { + 'abvolt': 'Defined to be 10^-8 volts.', + 'statvolt': 'CGS unit defined to be the speed of light in a vacuum/10^6 volts or approximately 299.792 volts.', + 'volt': 'SI derived unit of electric potential.\nDefined to be the value of voltage across a conductor when a current of one ampere dissipates one watt of power.', + }, 'energy_docs': { 'british_thermal_unit': 'Defined to be the amount of energy required to raise the temperature of one pound of liquid water from 60 degrees Fahrenheit to 61 degrees Fahrenheit at a constant pressure of one atmosphere.\nApproximately equal to 1055.05585 joules.', 'btu': 'Abbreviation for British thermal unit.\nApproximately equal to 1055.05585 joules.', @@ -406,11 +513,21 @@ def evalunitdict(): 'luminance_docs': {'apostilb': 'Defined to be 10^-4 lamberts.\nEqual to 1/pi*candela/meter^2.', 'lambert': 'Defined to be 10^4/pi candela/meter^2.', 'nit': 'Equivalent to candela/meter^2.', 'stilb': 'CGS unit equal to 10000 candela/meter^2.'}, 'luminous_energy_docs': {'lumerg': 'Equivalent to lumen*second', 'talbot': 'Equivalent to lumen*second.'}, 'luminous_flux_docs': {'lumen': 'SI derived unit of luminous flux.\nDefined to be candela*steradian.'}, - 'luminous_intensity_docs': {'candela': 'SI base unit of luminous intensity.\nDefined to be the luminous intensity, in a given direction, of a source that emits monochromatic radiation of frequency 540*10^12 hertz and that has a radiant intensity in that direction of 1/683 watt per steradian.', 'candle': 'Equivalent to candela.', 'hefnerkerze': 'Old German unit defined to be a 8 millimeter wick burning amyl acetate with a flame height of 40 millimeters.\nApproximately equal to 0.9034 candelas.'}, - 'magnetic_field_docs': {'gauss': 'CGS unit defined to be a maxwell/centimeter^2.\nEqual to 1/10000 of a tesla.', 'tesla': 'SI derived unit of magnetic field.\nDefined to be the magnitude of a magnetic field such that a particle with a charge of 1 coulomb passing through that field at 1 meter/second will experience a force of 1 newton.'}, + 'luminous_intensity_docs': { + 'candela': 'SI base unit of luminous intensity.\nDefined to be the luminous intensity, in a given direction, of a source that emits monochromatic radiation of frequency 540*10^12 hertz and that has a radiant intensity in that direction of 1/683 watt per steradian.', + 'candle': 'Equivalent to candela.', + 'hefnerkerze': 'Old German unit defined to be a 8 millimeter wick burning amyl acetate with a flame height of 40 millimeters.\nApproximately equal to 0.9034 candelas.', + }, + 'magnetic_field_docs': { + 'gauss': 'CGS unit defined to be a maxwell/centimeter^2.\nEqual to 1/10000 of a tesla.', + 'tesla': 'SI derived unit of magnetic field.\nDefined to be the magnitude of a magnetic field such that a particle with a charge of 1 coulomb passing through that field at 1 meter/second will experience a force of 1 newton.', + }, 'magnetic_flux_docs': {'maxwell': 'CGS unit defined to be a gauss*centimeter^2 or 10^-8 webers.', 'weber': 'SI derived unit of magnetic flux.\nDefined to be a change in magnetic flux of 1 weber per second will induce an electromotive force of 1 volt.'}, 'magnetic_intensity_docs': {'oersted': 'CGS unit defined to be 1000/(4*pi) amperes per meter of flux path.'}, - 'magnetic_moment_docs': {'bohr_magneton': 'Physical constant defined to be the magnetic moment of an electron, or elementary_charge*h_bar/2*electron_rest_mass.\nApproximately equal to 9.274*10^-24 joules/tesla.', 'nuclear_magneton': 'Physical constant defined to be the magnetic moment of a proton, or elementary_charge*h_bar/2*proton_rest_mass.\nApproximately equal to 5.05078324*10^-27 joules/tesla.'}, + 'magnetic_moment_docs': { + 'bohr_magneton': 'Physical constant defined to be the magnetic moment of an electron, or elementary_charge*h_bar/2*electron_rest_mass.\nApproximately equal to 9.274*10^-24 joules/tesla.', + 'nuclear_magneton': 'Physical constant defined to be the magnetic moment of a proton, or elementary_charge*h_bar/2*proton_rest_mass.\nApproximately equal to 5.05078324*10^-27 joules/tesla.', + }, 'magnetomotive_force_docs': {'ampere_turn': 'SI derived unit of magnetomotive force.\nDefined to be a direct current of 1 ampere flowing through a single turn loop in a vacuum.', 'gilbert': 'CGS unit defined to be 10/(4*pi) ampere turns.'}, 'mass_docs': { 'amu': 'Abbreviation for atomic mass unit.\nApproximately equal to 1.660538782*10^-27 kilograms.', @@ -453,14 +570,36 @@ def evalunitdict(): 'tonne': 'Equivalent to metric_ton.\nDefined to be 1000 kilograms.', 'wey': 'Defined to be 252 pounds.\nApproximately equal to 114.305 kilograms.', }, - 'power_docs': {'cheval_vapeur': 'Defined to be 75 kilogram force*meter/second.\nAlso known as metric horsepower.\nEqual to 735.49875 watts.', 'horsepower': 'Defined to be 550 feet*pound force/second.\nApproximately equal to 745.7 watts.', 'watt': 'SI derived unit of power.\nDefined to be joule/second or, in base units, kilogram*meter^2/second^3.'}, - 'pressure_docs': {'atmosphere': 'Defined to be 101325 pascals.', 'bar': 'Defined to be 100000 pascals.', 'barye': 'CGS unit defined to be dyne/centimeter^2.\nEqual to 1/10 of a pascal.', 'inch_mercury': 'Defined to be 13595.1 kilogram/meter^3*inch*gravity.\nApproximately equal to 3386.389 pascals.', 'millimeter_mercury': 'Defined to be 13595.1 kilogram/meter^3*millimeter*gravity.\nApproximately equal to 133.3224 pascals.', 'mmhg': 'Abbreviation for millimeter mercury.\nApproximately equal to 133.3224 pascals.', 'pa': 'Abbreviation for pascal.', 'pascal': 'SI derived unit of pressure.\nDefined to be newton/meter^2 or, in base units, kilogram/(meter*second^2).', 'pounds_per_square_inch': 'Defined to be pound force/inch^2.\nApproximately equal to 6894.76 pascals.', 'psi': 'Abbreviation for pounds per square inch.\nApproximately equal to 6894.76 pascals.', 'torr': 'Defined to be 1/760 of an atmosphere.\nApproximately equal to 133.322 pascals.'}, + 'power_docs': { + 'cheval_vapeur': 'Defined to be 75 kilogram force*meter/second.\nAlso known as metric horsepower.\nEqual to 735.49875 watts.', + 'horsepower': 'Defined to be 550 feet*pound force/second.\nApproximately equal to 745.7 watts.', + 'watt': 'SI derived unit of power.\nDefined to be joule/second or, in base units, kilogram*meter^2/second^3.', + }, + 'pressure_docs': { + 'atmosphere': 'Defined to be 101325 pascals.', + 'bar': 'Defined to be 100000 pascals.', + 'barye': 'CGS unit defined to be dyne/centimeter^2.\nEqual to 1/10 of a pascal.', + 'inch_mercury': 'Defined to be 13595.1 kilogram/meter^3*inch*gravity.\nApproximately equal to 3386.389 pascals.', + 'millimeter_mercury': 'Defined to be 13595.1 kilogram/meter^3*millimeter*gravity.\nApproximately equal to 133.3224 pascals.', + 'mmhg': 'Abbreviation for millimeter mercury.\nApproximately equal to 133.3224 pascals.', + 'pa': 'Abbreviation for pascal.', + 'pascal': 'SI derived unit of pressure.\nDefined to be newton/meter^2 or, in base units, kilogram/(meter*second^2).', + 'pounds_per_square_inch': 'Defined to be pound force/inch^2.\nApproximately equal to 6894.76 pascals.', + 'psi': 'Abbreviation for pounds per square inch.\nApproximately equal to 6894.76 pascals.', + 'torr': 'Defined to be 1/760 of an atmosphere.\nApproximately equal to 133.322 pascals.', + }, 'radiation_absorbed_docs': {'gray': 'SI derived unit of absorbed radiation.\nDefined to be the absorption of one joule of ionizing radiation by one kilogram of matter.', 'rad': 'Defined to be 1/100 of a gray.'}, 'radiation_docs': {'becquerel': 'SI derived unit of radiation.\nDefined to be the activity of a quantity of radioactive material in which one nucleus decays per second.', 'curie': 'Defined to be 37*10^9 becquerels.', 'rutherford': 'Defined to be 10^6 becquerels.'}, 'radiation_ionizing_docs': {'roentgen': 'Defined to be .000258 coulombs/kilogram.', 'rontgen': 'Equivalent to roentgen.\nDefined to be .000258 coulombs/kilogram.'}, 'resistance_docs': {'abohm': 'Defined to be 10^-9 ohms.', 'ohm': 'SI derived unit of resistance.\nDefined to be a volt per ampere.', 'statohm': 'CGS unit defined to be statvolt/statampere.\nApproximately equal to 8.98758*10^11 ohms.'}, 'solid_angle_docs': {'steradian': 'SI derived unit of solid angle.\nDefined to be the solid angle subtended at the center of a sphere of radius r by a portion of the surface of the sphere having an area of r^2.'}, - 'temperature_docs': {'celsius': 'Defined to be -273.15 at absolute zero and 0.01 at the triple point of Vienna Standard Mean Ocean Water.\nCelsius is related to kelvin by the equation K = 273.15 + degrees Celsius.\nA change of 1 degree Celsius is equivalent to a change of 1 degree kelvin.', 'centigrade': 'Equivalent to celsius.', 'fahrenheit': 'Defined to be 32 degrees at the freezing point of water and 212 degrees at the boiling point of water, both at standard pressure (1 atmosphere).\nFahrenheit is related to kelvin by the equation K = 5/9*(degrees Fahrenheit + 459.67).\nA change of 1 degree fahrenheit is equal to a change of 5/9 kelvin.', 'kelvin': 'SI base unit of temperature.\nDefined to be exactly 0 at absolute zero and 273.16 at the triple point of Vienna Standard Mean Ocean Water.', 'rankine': 'Defined to be 0 at absolute zero and to have the same degree increment as Fahrenheit.\nRankine is related to kelvin by the equation K = 5/9*R.'}, + 'temperature_docs': { + 'celsius': 'Defined to be -273.15 at absolute zero and 0.01 at the triple point of Vienna Standard Mean Ocean Water.\nCelsius is related to kelvin by the equation K = 273.15 + degrees Celsius.\nA change of 1 degree Celsius is equivalent to a change of 1 degree kelvin.', + 'centigrade': 'Equivalent to celsius.', + 'fahrenheit': 'Defined to be 32 degrees at the freezing point of water and 212 degrees at the boiling point of water, both at standard pressure (1 atmosphere).\nFahrenheit is related to kelvin by the equation K = 5/9*(degrees Fahrenheit + 459.67).\nA change of 1 degree fahrenheit is equal to a change of 5/9 kelvin.', + 'kelvin': 'SI base unit of temperature.\nDefined to be exactly 0 at absolute zero and 273.16 at the triple point of Vienna Standard Mean Ocean Water.', + 'rankine': 'Defined to be 0 at absolute zero and to have the same degree increment as Fahrenheit.\nRankine is related to kelvin by the equation K = 5/9*R.', + }, 'time_docs': { 'century': 'Defined to be 100 years.\nEqual to 3153600000 seconds.', 'day': 'Defined to be 24 hours.\nEqual to 86400 seconds.', diff --git a/src/sage/tests/finite_poset.py b/src/sage/tests/finite_poset.py index 6bdb3313397..b0672ff9fa4 100644 --- a/src/sage/tests/finite_poset.py +++ b/src/sage/tests/finite_poset.py @@ -52,7 +52,29 @@ ['doubling_lower', 'doubling_upper'], ] -selfdual_properties = ['distributive', 'modular', 'semidistributive', 'complemented', 'relatively_complemented', 'orthocomplemented', 'uniq_orthocomplemented', 'supersolvable', 'planar', 'dismantlable', 'vertically_decomposable', 'simple', 'isoform', 'uniform', 'regular', 'subdirectly_reducible', 'doubling_any', 'doubling_convex', 'doubling_interval', 'interval_dismantlable', 'interval_dismantlable'] +selfdual_properties = [ + 'distributive', + 'modular', + 'semidistributive', + 'complemented', + 'relatively_complemented', + 'orthocomplemented', + 'uniq_orthocomplemented', + 'supersolvable', + 'planar', + 'dismantlable', + 'vertically_decomposable', + 'simple', + 'isoform', + 'uniform', + 'regular', + 'subdirectly_reducible', + 'doubling_any', + 'doubling_convex', + 'doubling_interval', + 'interval_dismantlable', + 'interval_dismantlable', +] dual_elements = [['atoms', 'coatoms'], ['meet_irreducibles', 'join_irreducibles'], ['meet_primes', 'join_primes']] diff --git a/src/sage/topology/cubical_complex.py b/src/sage/topology/cubical_complex.py index 61e3d74b2ea..c836b43e3f8 100644 --- a/src/sage/topology/cubical_complex.py +++ b/src/sage/topology/cubical_complex.py @@ -1849,7 +1849,30 @@ def RealProjectivePlane(self): sage: cubical_complexes.RealProjectivePlane() Cubical complex with 21 vertices and 81 cubes """ - return CubicalComplex([([0, 1], [0], [0], [0, 1], [0]), ([0, 1], [0], [0], [0], [0, 1]), ([0], [0, 1], [0, 1], [0], [0]), ([0], [0, 1], [0], [0, 1], [0]), ([0], [0], [0, 1], [0], [0, 1]), ([0, 1], [0, 1], [1], [0], [0]), ([0, 1], [1], [0, 1], [0], [0]), ([1], [0, 1], [0, 1], [0], [0]), ([0, 1], [0, 1], [0], [0], [1]), ([0, 1], [1], [0], [0], [0, 1]), ([1], [0, 1], [0], [0], [0, 1]), ([0, 1], [0], [0, 1], [1], [0]), ([0, 1], [0], [1], [0, 1], [0]), ([1], [0], [0, 1], [0, 1], [0]), ([0], [0, 1], [0], [0, 1], [1]), ([0], [0, 1], [0], [1], [0, 1]), ([0], [1], [0], [0, 1], [0, 1]), ([0], [0], [0, 1], [0, 1], [1]), ([0], [0], [0, 1], [1], [0, 1]), ([0], [0], [1], [0, 1], [0, 1])]) + return CubicalComplex( + [ + ([0, 1], [0], [0], [0, 1], [0]), + ([0, 1], [0], [0], [0], [0, 1]), + ([0], [0, 1], [0, 1], [0], [0]), + ([0], [0, 1], [0], [0, 1], [0]), + ([0], [0], [0, 1], [0], [0, 1]), + ([0, 1], [0, 1], [1], [0], [0]), + ([0, 1], [1], [0, 1], [0], [0]), + ([1], [0, 1], [0, 1], [0], [0]), + ([0, 1], [0, 1], [0], [0], [1]), + ([0, 1], [1], [0], [0], [0, 1]), + ([1], [0, 1], [0], [0], [0, 1]), + ([0, 1], [0], [0, 1], [1], [0]), + ([0, 1], [0], [1], [0, 1], [0]), + ([1], [0], [0, 1], [0, 1], [0]), + ([0], [0, 1], [0], [0, 1], [1]), + ([0], [0, 1], [0], [1], [0, 1]), + ([0], [1], [0], [0, 1], [0, 1]), + ([0], [0], [0, 1], [0, 1], [1]), + ([0], [0], [0, 1], [1], [0, 1]), + ([0], [0], [1], [0, 1], [0, 1]), + ] + ) def KleinBottle(self): r""" diff --git a/src/sage/topology/simplicial_complex_catalog.py b/src/sage/topology/simplicial_complex_catalog.py index 594c60bbed7..9917fc82f71 100644 --- a/src/sage/topology/simplicial_complex_catalog.py +++ b/src/sage/topology/simplicial_complex_catalog.py @@ -67,7 +67,35 @@ {0: 0, 1: Z^16, 2: 0} """ -from sage.topology.simplicial_complex_examples import Sphere, Simplex, Torus, ProjectivePlane, RealProjectivePlane, KleinBottle, FareyMap, GenusSix, SurfaceOfGenus, MooreSpace, ComplexProjectivePlane, QuaternionicProjectivePlane, PoincareHomologyThreeSphere, RealProjectiveSpace, K3Surface, BarnetteSphere, BrucknerGrunbaumSphere, NotIConnectedGraphs, MatchingComplex, ChessboardComplex, RandomComplex, SumComplex, RandomTwoSphere, ShiftedComplex, RudinBall, ZieglerBall, DunceHat +from sage.topology.simplicial_complex_examples import ( + Sphere, + Simplex, + Torus, + ProjectivePlane, + RealProjectivePlane, + KleinBottle, + FareyMap, + GenusSix, + SurfaceOfGenus, + MooreSpace, + ComplexProjectivePlane, + QuaternionicProjectivePlane, + PoincareHomologyThreeSphere, + RealProjectiveSpace, + K3Surface, + BarnetteSphere, + BrucknerGrunbaumSphere, + NotIConnectedGraphs, + MatchingComplex, + ChessboardComplex, + RandomComplex, + SumComplex, + RandomTwoSphere, + ShiftedComplex, + RudinBall, + ZieglerBall, + DunceHat, +) from sage.combinat.posets.hochschild_lattice import hochschild_simplicial_complex as HochschildSphere diff --git a/src/sage/topology/simplicial_complex_examples.py b/src/sage/topology/simplicial_complex_examples.py index f5973bd53a2..8de97b43103 100644 --- a/src/sage/topology/simplicial_complex_examples.py +++ b/src/sage/topology/simplicial_complex_examples.py @@ -527,7 +527,47 @@ def ComplexProjectivePlane(): sage: C.homology(4) # needs sage.modules Z """ - return UniqueSimplicialComplex([[1, 2, 4, 5, 6], [2, 3, 5, 6, 4], [3, 1, 6, 4, 5], [1, 2, 4, 5, 9], [2, 3, 5, 6, 7], [3, 1, 6, 4, 8], [2, 3, 6, 4, 9], [3, 1, 4, 5, 7], [1, 2, 5, 6, 8], [3, 1, 5, 6, 9], [1, 2, 6, 4, 7], [2, 3, 4, 5, 8], [4, 5, 7, 8, 9], [5, 6, 8, 9, 7], [6, 4, 9, 7, 8], [4, 5, 7, 8, 3], [5, 6, 8, 9, 1], [6, 4, 9, 7, 2], [5, 6, 9, 7, 3], [6, 4, 7, 8, 1], [4, 5, 8, 9, 2], [6, 4, 8, 9, 3], [4, 5, 9, 7, 1], [5, 6, 7, 8, 2], [7, 8, 1, 2, 3], [8, 9, 2, 3, 1], [9, 7, 3, 1, 2], [7, 8, 1, 2, 6], [8, 9, 2, 3, 4], [9, 7, 3, 1, 5], [8, 9, 3, 1, 6], [9, 7, 1, 2, 4], [7, 8, 2, 3, 5], [9, 7, 2, 3, 6], [7, 8, 3, 1, 4], [8, 9, 1, 2, 5]], name='Minimal triangulation of the complex projective plane') + return UniqueSimplicialComplex( + [ + [1, 2, 4, 5, 6], + [2, 3, 5, 6, 4], + [3, 1, 6, 4, 5], + [1, 2, 4, 5, 9], + [2, 3, 5, 6, 7], + [3, 1, 6, 4, 8], + [2, 3, 6, 4, 9], + [3, 1, 4, 5, 7], + [1, 2, 5, 6, 8], + [3, 1, 5, 6, 9], + [1, 2, 6, 4, 7], + [2, 3, 4, 5, 8], + [4, 5, 7, 8, 9], + [5, 6, 8, 9, 7], + [6, 4, 9, 7, 8], + [4, 5, 7, 8, 3], + [5, 6, 8, 9, 1], + [6, 4, 9, 7, 2], + [5, 6, 9, 7, 3], + [6, 4, 7, 8, 1], + [4, 5, 8, 9, 2], + [6, 4, 8, 9, 3], + [4, 5, 9, 7, 1], + [5, 6, 7, 8, 2], + [7, 8, 1, 2, 3], + [8, 9, 2, 3, 1], + [9, 7, 3, 1, 2], + [7, 8, 1, 2, 6], + [8, 9, 2, 3, 4], + [9, 7, 3, 1, 5], + [8, 9, 3, 1, 6], + [9, 7, 1, 2, 4], + [7, 8, 2, 3, 5], + [9, 7, 2, 3, 6], + [7, 8, 3, 1, 4], + [8, 9, 1, 2, 5], + ], + name='Minimal triangulation of the complex projective plane', + ) def QuaternionicProjectivePlane(): @@ -563,7 +603,22 @@ def QuaternionicProjectivePlane(): P = [(1, 2, 3, 4, 5), (6, 7, 8, 9, 10), (11, 12, 13, 14, 15)] S = [(1, 6, 11), (2, 15, 14), (3, 13, 8), (4, 7, 5), (9, 12, 10)] - start_list = [(1, 2, 3, 6, 8, 11, 13, 14, 15), (1, 3, 6, 8, 9, 10, 11, 12, 13), (1, 2, 6, 9, 10, 11, 12, 14, 15), (1, 2, 3, 4, 7, 9, 12, 14, 15), (1, 2, 4, 7, 9, 10, 12, 13, 14), (1, 2, 6, 8, 9, 10, 11, 14, 15), (1, 2, 3, 4, 5, 6, 9, 11, 13), (1, 3, 5, 6, 8, 9, 10, 11, 12), (1, 3, 5, 6, 7, 8, 9, 10, 11), (1, 2, 3, 4, 5, 7, 10, 12, 15), (1, 2, 3, 7, 8, 10, 12, 13, 14), (2, 5, 6, 7, 8, 9, 10, 13, 14), (3, 4, 6, 7, 11, 12, 13, 14, 15), (3, 4, 6, 7, 10, 12, 13, 14, 15)] # A # B # C # D # E # F # G # H # I # J # K # M # L # N + start_list = [ + (1, 2, 3, 6, 8, 11, 13, 14, 15), + (1, 3, 6, 8, 9, 10, 11, 12, 13), + (1, 2, 6, 9, 10, 11, 12, 14, 15), + (1, 2, 3, 4, 7, 9, 12, 14, 15), + (1, 2, 4, 7, 9, 10, 12, 13, 14), + (1, 2, 6, 8, 9, 10, 11, 14, 15), + (1, 2, 3, 4, 5, 6, 9, 11, 13), + (1, 3, 5, 6, 8, 9, 10, 11, 12), + (1, 3, 5, 6, 7, 8, 9, 10, 11), + (1, 2, 3, 4, 5, 7, 10, 12, 15), + (1, 2, 3, 7, 8, 10, 12, 13, 14), + (2, 5, 6, 7, 8, 9, 10, 13, 14), + (3, 4, 6, 7, 11, 12, 13, 14, 15), + (3, 4, 6, 7, 10, 12, 13, 14, 15), + ] # A # B # C # D # E # F # G # H # I # J # K # M # L # N return UniqueSimplicialComplex([[g(index) for index in tup] for tup in start_list for g in PermutationGroup([P, S])]) @@ -787,7 +842,51 @@ def RealProjectiveSpace(n): if n == 3: # Minimal triangulation found by Walkup and given # explicitly by Lutz - return UniqueSimplicialComplex([[1, 2, 3, 7], [1, 4, 7, 9], [2, 3, 4, 8], [2, 5, 8, 10], [3, 6, 7, 10], [1, 2, 3, 11], [1, 4, 7, 10], [2, 3, 4, 11], [2, 5, 9, 10], [3, 6, 8, 9], [1, 2, 6, 9], [1, 4, 8, 9], [2, 3, 7, 8], [2, 6, 9, 10], [3, 6, 9, 10], [1, 2, 6, 11], [1, 4, 8, 10], [2, 4, 6, 10], [3, 4, 5, 9], [4, 5, 6, 7], [1, 2, 7, 9], [1, 5, 6, 8], [2, 4, 6, 11], [3, 4, 5, 11], [4, 5, 6, 11], [1, 3, 5, 10], [1, 5, 6, 11], [2, 4, 8, 10], [3, 4, 8, 9], [4, 5, 7, 9], [1, 3, 5, 11], [1, 5, 8, 10], [2, 5, 7, 8], [3, 5, 9, 10], [4, 6, 7, 10], [1, 3, 7, 10], [1, 6, 8, 9], [2, 5, 7, 9], [3, 6, 7, 8], [5, 6, 7, 8]], name='Minimal triangulation of RP^3') + return UniqueSimplicialComplex( + [ + [1, 2, 3, 7], + [1, 4, 7, 9], + [2, 3, 4, 8], + [2, 5, 8, 10], + [3, 6, 7, 10], + [1, 2, 3, 11], + [1, 4, 7, 10], + [2, 3, 4, 11], + [2, 5, 9, 10], + [3, 6, 8, 9], + [1, 2, 6, 9], + [1, 4, 8, 9], + [2, 3, 7, 8], + [2, 6, 9, 10], + [3, 6, 9, 10], + [1, 2, 6, 11], + [1, 4, 8, 10], + [2, 4, 6, 10], + [3, 4, 5, 9], + [4, 5, 6, 7], + [1, 2, 7, 9], + [1, 5, 6, 8], + [2, 4, 6, 11], + [3, 4, 5, 11], + [4, 5, 6, 11], + [1, 3, 5, 10], + [1, 5, 6, 11], + [2, 4, 8, 10], + [3, 4, 8, 9], + [4, 5, 7, 9], + [1, 3, 5, 11], + [1, 5, 8, 10], + [2, 5, 7, 8], + [3, 5, 9, 10], + [4, 6, 7, 10], + [1, 3, 7, 10], + [1, 6, 8, 9], + [2, 5, 7, 9], + [3, 6, 7, 8], + [5, 6, 7, 8], + ], + name='Minimal triangulation of RP^3', + ) if n == 4: return UniqueSimplicialComplex( [ @@ -1310,7 +1409,10 @@ def BarnetteSphere(): sage: BS.is_isomorphic(BS2) True """ - return UniqueSimplicialComplex([(1, 2, 4, 5), (2, 3, 5, 6), (1, 3, 4, 6), (1, 2, 3, 7), (4, 5, 6, 7), (1, 2, 4, 7), (2, 4, 5, 7), (2, 3, 5, 7), (3, 5, 6, 7), (3, 1, 6, 7), (1, 6, 4, 7), (1, 2, 3, 8), (4, 5, 6, 8), (1, 2, 5, 8), (1, 4, 5, 8), (2, 3, 6, 8), (2, 5, 6, 8), (3, 1, 4, 8), (3, 6, 4, 8)], name="Barnette's triangulation of the 3-sphere") + return UniqueSimplicialComplex( + [(1, 2, 4, 5), (2, 3, 5, 6), (1, 3, 4, 6), (1, 2, 3, 7), (4, 5, 6, 7), (1, 2, 4, 7), (2, 4, 5, 7), (2, 3, 5, 7), (3, 5, 6, 7), (3, 1, 6, 7), (1, 6, 4, 7), (1, 2, 3, 8), (4, 5, 6, 8), (1, 2, 5, 8), (1, 4, 5, 8), (2, 3, 6, 8), (2, 5, 6, 8), (3, 1, 4, 8), (3, 6, 4, 8)], + name="Barnette's triangulation of the 3-sphere", + ) def BrucknerGrunbaumSphere(): @@ -1804,7 +1906,52 @@ def RudinBall(): sage: R.is_cohen_macaulay() # needs sage.modules True """ - return UniqueSimplicialComplex([[1, 9, 2, 5], [1, 10, 2, 5], [1, 10, 5, 11], [1, 10, 7, 11], [1, 13, 5, 11], [1, 13, 7, 11], [2, 10, 3, 6], [2, 11, 3, 6], [2, 11, 6, 12], [2, 11, 8, 12], [2, 14, 6, 12], [2, 14, 8, 12], [3, 11, 4, 7], [3, 12, 4, 7], [3, 12, 5, 9], [3, 12, 7, 9], [3, 13, 5, 9], [3, 13, 7, 9], [4, 9, 1, 8], [4, 9, 6, 10], [4, 9, 8, 10], [4, 12, 1, 8], [4, 14, 6, 10], [4, 14, 8, 10], [9, 10, 2, 5], [9, 10, 2, 6], [9, 10, 5, 11], [9, 10, 11, 12], [9, 13, 5, 11], [10, 11, 3, 6], [10, 11, 3, 7], [10, 11, 6, 12], [10, 14, 6, 12], [11, 12, 4, 7], [11, 12, 4, 8], [11, 12, 7, 9], [11, 13, 7, 9], [12, 9, 1, 5], [12, 9, 1, 8], [12, 9, 8, 10], [12, 14, 8, 10]], name="Rudin ball") + return UniqueSimplicialComplex( + [ + [1, 9, 2, 5], + [1, 10, 2, 5], + [1, 10, 5, 11], + [1, 10, 7, 11], + [1, 13, 5, 11], + [1, 13, 7, 11], + [2, 10, 3, 6], + [2, 11, 3, 6], + [2, 11, 6, 12], + [2, 11, 8, 12], + [2, 14, 6, 12], + [2, 14, 8, 12], + [3, 11, 4, 7], + [3, 12, 4, 7], + [3, 12, 5, 9], + [3, 12, 7, 9], + [3, 13, 5, 9], + [3, 13, 7, 9], + [4, 9, 1, 8], + [4, 9, 6, 10], + [4, 9, 8, 10], + [4, 12, 1, 8], + [4, 14, 6, 10], + [4, 14, 8, 10], + [9, 10, 2, 5], + [9, 10, 2, 6], + [9, 10, 5, 11], + [9, 10, 11, 12], + [9, 13, 5, 11], + [10, 11, 3, 6], + [10, 11, 3, 7], + [10, 11, 6, 12], + [10, 14, 6, 12], + [11, 12, 4, 7], + [11, 12, 4, 8], + [11, 12, 7, 9], + [11, 13, 7, 9], + [12, 9, 1, 5], + [12, 9, 1, 8], + [12, 9, 8, 10], + [12, 14, 8, 10], + ], + name="Rudin ball", + ) def ZieglerBall(): @@ -1827,7 +1974,10 @@ def ZieglerBall(): True """ - return UniqueSimplicialComplex([[1, 2, 3, 4], [1, 2, 5, 6], [1, 5, 6, 9], [2, 5, 6, 0], [3, 6, 7, 8], [4, 5, 7, 8], [2, 3, 6, 7], [1, 6, 2, 9], [2, 6, 7, 0], [3, 2, 4, 8], [4, 1, 3, 7], [3, 4, 7, 8], [1, 2, 4, 9], [2, 7, 3, 0], [3, 2, 6, 8], [4, 1, 5, 7], [4, 1, 8, 5], [1, 4, 8, 9], [2, 3, 1, 0], [1, 8, 5, 9], [2, 1, 5, 0]], name="Ziegler ball") + return UniqueSimplicialComplex( + [[1, 2, 3, 4], [1, 2, 5, 6], [1, 5, 6, 9], [2, 5, 6, 0], [3, 6, 7, 8], [4, 5, 7, 8], [2, 3, 6, 7], [1, 6, 2, 9], [2, 6, 7, 0], [3, 2, 4, 8], [4, 1, 3, 7], [3, 4, 7, 8], [1, 2, 4, 9], [2, 7, 3, 0], [3, 2, 6, 8], [4, 1, 5, 7], [4, 1, 8, 5], [1, 4, 8, 9], [2, 3, 1, 0], [1, 8, 5, 9], [2, 1, 5, 0]], + name="Ziegler ball", + ) def DunceHat(): diff --git a/src/sage/topology/simplicial_set_examples.py b/src/sage/topology/simplicial_set_examples.py index 54f06def7ff..632e7f73b8f 100644 --- a/src/sage/topology/simplicial_set_examples.py +++ b/src/sage/topology/simplicial_set_examples.py @@ -577,7 +577,21 @@ def ComplexProjectiveSpace(n): f4_101101 = AbstractSimplex(4, name='tau_0', latex_name='\\tau_0') f4_201110 = AbstractSimplex(4, name='tau_1', latex_name='\\tau_1') f4_211010 = AbstractSimplex(4, name='tau_2', latex_name='\\tau_2') - K = SimplicialSet_finite({f2_1: (v.apply_degeneracies(0), v.apply_degeneracies(0), v.apply_degeneracies(0)), f2_2: (v.apply_degeneracies(0), v.apply_degeneracies(0), v.apply_degeneracies(0)), f3_110: (f2_1, f2_2, f2_1, v.apply_degeneracies(1, 0)), f3_011: (f2_1, f2_1, f2_1, f2_1), f3_111: (v.apply_degeneracies(1, 0), f2_1, f2_2, f2_1), f4_101101: (f2_1.apply_degeneracies(0), f2_1.apply_degeneracies(0), f3_011, f2_1.apply_degeneracies(2), f2_1.apply_degeneracies(2)), f4_201110: (f2_1.apply_degeneracies(1), f3_111, f3_011, f3_110, f2_1.apply_degeneracies(1)), f4_211010: (f2_1.apply_degeneracies(2), f3_111, f2_1.apply_degeneracies(1), f3_110, f2_1.apply_degeneracies(0))}, base_point=v, name='CP^2', latex_name='CP^{2}') + K = SimplicialSet_finite( + { + f2_1: (v.apply_degeneracies(0), v.apply_degeneracies(0), v.apply_degeneracies(0)), + f2_2: (v.apply_degeneracies(0), v.apply_degeneracies(0), v.apply_degeneracies(0)), + f3_110: (f2_1, f2_2, f2_1, v.apply_degeneracies(1, 0)), + f3_011: (f2_1, f2_1, f2_1, f2_1), + f3_111: (v.apply_degeneracies(1, 0), f2_1, f2_2, f2_1), + f4_101101: (f2_1.apply_degeneracies(0), f2_1.apply_degeneracies(0), f3_011, f2_1.apply_degeneracies(2), f2_1.apply_degeneracies(2)), + f4_201110: (f2_1.apply_degeneracies(1), f3_111, f3_011, f3_110, f2_1.apply_degeneracies(1)), + f4_211010: (f2_1.apply_degeneracies(2), f3_111, f2_1.apply_degeneracies(1), f3_110, f2_1.apply_degeneracies(0)), + }, + base_point=v, + name='CP^2', + latex_name='CP^{2}', + ) return K if n == 3: file = kenzo_path / 'CP3.txt' @@ -738,7 +752,30 @@ def HopfMap(): alpha_4 = AbstractSimplex(3, name='alpha_4', latex_name='\\alpha_4') alpha_5 = AbstractSimplex(3, name='alpha_5', latex_name='\\alpha_5') alpha_6 = AbstractSimplex(3, name='alpha_6', latex_name='\\alpha_6') - S3 = SimplicialSet_finite({beta_11: (w_0, w_0), beta_22: (w_0, w_0), beta_23: (w_0, w_0), beta_44: (w_0, w_0), beta_1: (w_1, beta_11, w_1), beta_2: (w_1, beta_22, beta_23), beta_3: (w_1, beta_23, w_1), beta_4: (w_1, beta_44, w_1), alpha_12: (beta_11, beta_23, w_1), alpha_23: (beta_11, beta_22, w_1), alpha_34: (beta_11, beta_22, beta_44), alpha_45: (w_1, beta_23, beta_44), alpha_56: (w_1, beta_23, w_1), alpha_1: (beta_1, beta_3, alpha_12, w_2), alpha_2: (beta_11.apply_degeneracies(1), beta_2, alpha_23, alpha_12), alpha_3: (beta_11.apply_degeneracies(0), alpha_34, alpha_23, beta_4), alpha_4: (beta_1, beta_2, alpha_34, alpha_45), alpha_5: (w_2, alpha_45, alpha_56, beta_4), alpha_6: (w_2, beta_3, alpha_56, w_2)}, base_point=w_0) + S3 = SimplicialSet_finite( + { + beta_11: (w_0, w_0), + beta_22: (w_0, w_0), + beta_23: (w_0, w_0), + beta_44: (w_0, w_0), + beta_1: (w_1, beta_11, w_1), + beta_2: (w_1, beta_22, beta_23), + beta_3: (w_1, beta_23, w_1), + beta_4: (w_1, beta_44, w_1), + alpha_12: (beta_11, beta_23, w_1), + alpha_23: (beta_11, beta_22, w_1), + alpha_34: (beta_11, beta_22, beta_44), + alpha_45: (w_1, beta_23, beta_44), + alpha_56: (w_1, beta_23, w_1), + alpha_1: (beta_1, beta_3, alpha_12, w_2), + alpha_2: (beta_11.apply_degeneracies(1), beta_2, alpha_23, alpha_12), + alpha_3: (beta_11.apply_degeneracies(0), alpha_34, alpha_23, beta_4), + alpha_4: (beta_1, beta_2, alpha_34, alpha_45), + alpha_5: (w_2, alpha_45, alpha_56, beta_4), + alpha_6: (w_2, beta_3, alpha_56, w_2), + }, + base_point=w_0, + ) return S3.Hom(S2)({alpha_1: s0_sigma, alpha_2: s1_sigma, alpha_3: s2_sigma, alpha_4: s0_sigma, alpha_5: s2_sigma, alpha_6: s1_sigma}) From 17419c3bbe18ab3e0e68a57e0eac4ba4dfd604a0 Mon Sep 17 00:00:00 2001 From: Vincent Macri Date: Mon, 20 Apr 2026 16:53:06 -0600 Subject: [PATCH 3/3] ruff format --- pyproject.toml | 4 + src/sage/algebras/clifford_algebra.py | 4 +- src/sage/algebras/commutative_dga.py | 14 +- src/sage/algebras/free_zinbiel_algebra.py | 2 +- .../hecke_algebras/ariki_koike_algebra.py | 1 - .../hecke_algebras/cubic_hecke_algebra.py | 6 +- .../hecke_algebras/cubic_hecke_base_ring.py | 2 +- src/sage/algebras/iwahori_hecke_algebra.py | 2 +- src/sage/algebras/jordan_algebra.py | 2 +- src/sage/algebras/lie_algebras/bch.py | 2 +- .../lie_algebras/classical_lie_algebra.py | 2 +- src/sage/algebras/lie_algebras/lie_algebra.py | 6 +- src/sage/algebras/lie_algebras/morphism.py | 2 +- .../lie_algebras/nilpotent_lie_algebra.py | 2 +- src/sage/algebras/lie_algebras/quotient.py | 4 +- .../affine_lie_conformal_algebra.py | 2 +- .../bosonic_ghosts_lie_conformal_algebra.py | 2 +- .../fermionic_ghosts_lie_conformal_algebra.py | 2 +- .../free_bosons_lie_conformal_algebra.py | 2 +- .../free_fermions_lie_conformal_algebra.py | 2 +- .../graded_lie_conformal_algebra.py | 3 +- ..._conformal_algebra_with_structure_coefs.py | 6 +- .../weyl_lie_conformal_algebra.py | 6 +- .../algebras/quatalg/quaternion_algebra.py | 12 +- src/sage/all.py | 2 +- src/sage/all_test.py | 2 +- src/sage/arith/misc.py | 5 +- src/sage/calculus/calculus.py | 9 +- src/sage/calculus/functional.py | 1 + src/sage/calculus/functions.py | 1 + src/sage/categories/additive_magmas.py | 13 -- src/sage/categories/additive_monoids.py | 1 - src/sage/categories/additive_semigroups.py | 4 - src/sage/categories/affine_weyl_groups.py | 1 - src/sage/categories/algebra_functor.py | 1 - src/sage/categories/algebras.py | 3 - src/sage/categories/algebras_with_basis.py | 2 - src/sage/categories/bialgebras.py | 1 - src/sage/categories/bialgebras_with_basis.py | 2 - src/sage/categories/category.py | 6 +- src/sage/categories/category_types.py | 3 +- src/sage/categories/category_with_axiom.py | 5 +- src/sage/categories/classical_crystals.py | 2 - src/sage/categories/coalgebras.py | 5 - src/sage/categories/coalgebras_with_basis.py | 1 - .../categories/complete_discrete_valuation.py | 1 - .../categories/complex_reflection_groups.py | 1 - src/sage/categories/coxeter_group_algebras.py | 3 +- src/sage/categories/crystals.py | 4 +- src/sage/categories/discrete_valuation.py | 1 - ...distributive_magmas_and_additive_magmas.py | 1 - src/sage/categories/drinfeld_modules.py | 9 +- src/sage/categories/dual.py | 1 - src/sage/categories/enumerated_sets.py | 4 - src/sage/categories/examples/crystals.py | 2 +- .../examples/finite_coxeter_groups.py | 1 + .../finite_dimensional_algebras_with_basis.py | 2 +- ...ite_dimensional_lie_algebras_with_basis.py | 2 +- .../examples/finite_enumerated_sets.py | 1 - .../categories/examples/finite_weyl_groups.py | 1 - src/sage/categories/examples/lie_algebras.py | 2 +- .../examples/lie_algebras_with_basis.py | 2 +- src/sage/categories/examples/magmas.py | 2 +- src/sage/categories/examples/posets.py | 1 - .../categories/examples/with_realizations.py | 1 - src/sage/categories/facade_sets.py | 1 - .../filtered_algebras_with_basis.py | 2 +- src/sage/categories/filtered_modules.py | 1 - .../categories/filtered_modules_with_basis.py | 5 +- .../finite_complex_reflection_groups.py | 4 - src/sage/categories/finite_coxeter_groups.py | 3 +- .../finite_dimensional_algebras_with_basis.py | 2 - ...ensional_graded_lie_algebras_with_basis.py | 2 +- ...ite_dimensional_lie_algebras_with_basis.py | 2 +- .../finite_dimensional_modules_with_basis.py | 5 - ...ional_nilpotent_lie_algebras_with_basis.py | 4 +- ...ensional_semisimple_algebras_with_basis.py | 2 - src/sage/categories/finite_enumerated_sets.py | 6 +- src/sage/categories/finite_groups.py | 1 - src/sage/categories/finite_lattice_posets.py | 1 - src/sage/categories/finite_monoids.py | 1 - src/sage/categories/finite_posets.py | 1 - src/sage/categories/finite_sets.py | 4 - ...nitely_generated_lie_conformal_algebras.py | 1 - .../categories/finitely_generated_magmas.py | 1 - .../finitely_generated_semigroups.py | 2 - .../categories/graded_modules_with_basis.py | 2 +- src/sage/categories/group_algebras.py | 1 - src/sage/categories/groups.py | 1 - src/sage/categories/hecke_modules.py | 1 - .../categories/highest_weight_crystals.py | 5 +- src/sage/categories/homset.py | 9 +- src/sage/categories/homsets.py | 2 - src/sage/categories/hopf_algebras.py | 3 - .../categories/hopf_algebras_with_basis.py | 2 - .../categories/infinite_enumerated_sets.py | 2 - src/sage/categories/isomorphic_objects.py | 1 - .../categories/lambda_bracket_algebras.py | 5 +- .../lambda_bracket_algebras_with_basis.py | 4 +- src/sage/categories/lattice_posets.py | 1 - src/sage/categories/lie_algebras.py | 2 +- src/sage/categories/lie_conformal_algebras.py | 2 - .../lie_conformal_algebras_with_basis.py | 1 - src/sage/categories/loop_crystals.py | 1 - src/sage/categories/magmas.py | 17 --- .../categories/magmas_and_additive_magmas.py | 1 - src/sage/categories/magmatic_algebras.py | 3 - src/sage/categories/metric_spaces.py | 4 - .../categories/modular_abelian_varieties.py | 1 - src/sage/categories/modules.py | 8 -- src/sage/categories/modules_with_basis.py | 2 - src/sage/categories/monoids.py | 8 -- src/sage/categories/posets.py | 2 +- .../categories/principal_ideal_domains.py | 4 +- src/sage/categories/pushout.py | 3 +- .../quantum_group_representations.py | 1 - src/sage/categories/quotient_fields.py | 1 - src/sage/categories/quotients.py | 1 - src/sage/categories/regular_crystals.py | 2 - src/sage/categories/rings.py | 1 - src/sage/categories/rngs.py | 1 - src/sage/categories/schemes.py | 1 - src/sage/categories/semigroups.py | 7 - src/sage/categories/semisimple_algebras.py | 2 - src/sage/categories/sets_cat.py | 23 +--- src/sage/categories/sets_with_grading.py | 1 - src/sage/categories/simplicial_sets.py | 7 +- src/sage/categories/subobjects.py | 1 - src/sage/categories/subquotients.py | 1 - .../super_lie_conformal_algebras.py | 2 - src/sage/categories/topological_spaces.py | 1 - src/sage/categories/unital_algebras.py | 2 - src/sage/categories/vector_spaces.py | 7 - src/sage/categories/weyl_groups.py | 1 - src/sage/coding/abstract_code.py | 8 +- src/sage/coding/bch_code.py | 3 +- src/sage/coding/code_bounds.py | 6 +- src/sage/coding/cyclic_code.py | 22 ++-- src/sage/coding/databases.py | 1 + src/sage/coding/delsarte_bounds.py | 6 +- src/sage/coding/gabidulin_code.py | 3 +- src/sage/coding/goppa_code.py | 1 + src/sage/coding/grs_code.py | 2 +- .../coding/guruswami_sudan/interpolation.py | 1 - src/sage/coding/information_set_decoder.py | 14 +- src/sage/coding/linear_code.py | 14 +- src/sage/coding/linear_code_no_metric.py | 2 +- src/sage/coding/source_coding/huffman.py | 2 +- src/sage/coding/subfield_subcode.py | 2 +- src/sage/coding/two_weight_db.py | 3 +- src/sage/combinat/SJT.py | 2 +- src/sage/combinat/affine_permutation.py | 13 +- src/sage/combinat/bijectionist.py | 1 + .../combinat/binary_recurrence_sequences.py | 19 --- src/sage/combinat/binary_tree.py | 2 - .../cluster_algebra_quiver/cluster_seed.py | 37 +++--- .../combinat/cluster_algebra_quiver/quiver.py | 28 ++-- .../quiver_mutation_type.py | 13 +- src/sage/combinat/cluster_complex.py | 2 +- src/sage/combinat/combinatorial_map.py | 1 - src/sage/combinat/constellation.py | 6 +- .../combinat/crystals/affine_factorization.py | 1 - src/sage/combinat/crystals/alcove_path.py | 2 - .../fully_commutative_stable_grothendieck.py | 2 +- .../combinat/crystals/kirillov_reshetikhin.py | 2 +- src/sage/combinat/crystals/star_crystal.py | 1 - src/sage/combinat/crystals/subcrystal.py | 2 +- .../combinat/cyclic_sieving_phenomenon.py | 2 +- src/sage/combinat/designs/bibd.py | 3 - src/sage/combinat/designs/block_design.py | 10 +- .../combinat/designs/difference_family.py | 22 ++-- .../combinat/designs/incidence_structures.py | 8 +- src/sage/combinat/designs/latin_squares.py | 1 + .../combinat/designs/orthogonal_arrays.py | 7 +- .../orthogonal_arrays_build_recursive.py | 11 +- src/sage/combinat/designs/resolvable_bibd.py | 5 +- src/sage/combinat/diagram_algebras.py | 4 +- src/sage/combinat/dyck_word.py | 28 ++-- src/sage/combinat/e_one_star.py | 1 + src/sage/combinat/finite_state_machine.py | 120 +++++++++--------- .../finite_state_machine_generators.py | 6 +- src/sage/combinat/free_dendriform_algebra.py | 4 +- .../combinat/fully_commutative_elements.py | 1 + src/sage/combinat/fully_packed_loop.py | 2 +- src/sage/combinat/growth.py | 12 +- src/sage/combinat/integer_lists/lists.py | 1 - .../combinat/integer_vectors_mod_permgroup.py | 6 +- src/sage/combinat/interval_posets.py | 8 +- src/sage/combinat/k_tableau.py | 4 +- src/sage/combinat/kazhdan_lusztig.py | 1 - src/sage/combinat/key_polynomial.py | 4 +- src/sage/combinat/lr_tableau.py | 4 +- .../combinat/ncsf_qsym/generic_basis_code.py | 3 - src/sage/combinat/ncsf_qsym/ncsf.py | 9 -- src/sage/combinat/ncsf_qsym/qsym.py | 2 +- src/sage/combinat/ncsym/bases.py | 6 +- src/sage/combinat/ncsym/ncsym.py | 5 +- src/sage/combinat/nu_dyck_word.py | 3 +- src/sage/combinat/nu_tamari_lattice.py | 1 + src/sage/combinat/ordered_tree.py | 2 +- src/sage/combinat/output.py | 20 +-- src/sage/combinat/parallelogram_polyomino.py | 3 +- src/sage/combinat/partition.py | 4 +- src/sage/combinat/partition_algebra.py | 1 + .../combinat/partition_shifting_algebras.py | 1 + src/sage/combinat/partition_tuple.py | 4 +- src/sage/combinat/perfect_matching.py | 2 +- src/sage/combinat/permutation.py | 18 +-- src/sage/combinat/plane_partition.py | 42 +++--- src/sage/combinat/posets/cartesian_product.py | 1 - src/sage/combinat/posets/elements.py | 2 +- src/sage/combinat/posets/hasse_diagram.py | 2 - .../combinat/posets/incidence_algebras.py | 1 + src/sage/combinat/posets/lattices.py | 1 + src/sage/combinat/posets/poset_examples.py | 2 +- src/sage/combinat/posets/posets.py | 8 +- src/sage/combinat/recognizable_series.py | 4 +- src/sage/combinat/regular_sequence.py | 53 ++++---- src/sage/combinat/ribbon_tableau.py | 2 +- .../tensor_product_kr_tableaux.py | 2 +- .../combinat/root_system/associahedron.py | 1 + src/sage/combinat/root_system/cartan_type.py | 1 - .../combinat/root_system/dynkin_diagram.py | 1 + .../root_system/extended_affine_weyl_group.py | 3 +- .../combinat/root_system/fundamental_group.py | 1 + .../hecke_algebra_representation.py | 1 + .../root_system/integrable_representations.py | 1 + .../non_symmetric_macdonald_polynomials.py | 1 + .../combinat/root_system/pieri_factors.py | 3 +- .../root_system/reflection_group_complex.py | 2 - .../root_system/reflection_group_real.py | 1 - .../root_lattice_realization_algebras.py | 2 - .../root_system/root_lattice_realizations.py | 6 +- src/sage/combinat/root_system/type_E.py | 2 +- src/sage/combinat/root_system/type_Q.py | 1 - src/sage/combinat/root_system/type_affine.py | 1 - .../weight_lattice_realizations.py | 3 +- src/sage/combinat/root_system/weight_space.py | 3 +- src/sage/combinat/root_system/weyl_group.py | 2 +- src/sage/combinat/rsk.py | 2 +- src/sage/combinat/schubert_polynomial.py | 1 - src/sage/combinat/set_partition_ordered.py | 2 +- src/sage/combinat/sf/character.py | 1 - src/sage/combinat/sf/classical.py | 2 +- src/sage/combinat/sf/dual.py | 1 + src/sage/combinat/sf/elementary.py | 1 + src/sage/combinat/sf/hall_littlewood.py | 1 - src/sage/combinat/sf/hecke.py | 2 +- src/sage/combinat/sf/jack.py | 3 - src/sage/combinat/sf/k_dual.py | 2 - src/sage/combinat/sf/llt.py | 3 +- src/sage/combinat/sf/macdonald.py | 4 - src/sage/combinat/sf/monomial.py | 1 - src/sage/combinat/sf/multiplicative.py | 1 + src/sage/combinat/sf/new_kschur.py | 2 +- src/sage/combinat/sf/ns_macdonald.py | 1 + src/sage/combinat/sf/orthotriang.py | 1 - src/sage/combinat/sf/powersum.py | 1 + src/sage/combinat/sf/schur.py | 6 +- src/sage/combinat/sf/sf.py | 1 + src/sage/combinat/sf/sfa.py | 4 +- src/sage/combinat/sf/witt.py | 1 + src/sage/combinat/shifted_primed_tableau.py | 2 +- src/sage/combinat/sine_gordon.py | 6 +- src/sage/combinat/skew_tableau.py | 2 +- src/sage/combinat/subword_complex.py | 5 +- src/sage/combinat/super_tableau.py | 16 +-- src/sage/combinat/superpartition.py | 8 +- src/sage/combinat/symmetric_group_algebra.py | 5 +- src/sage/combinat/t_sequences.py | 2 +- src/sage/combinat/tableau.py | 11 +- src/sage/combinat/tableau_tuple.py | 2 +- src/sage/combinat/tamari_blossoming_tree.py | 14 +- src/sage/combinat/tamari_lattices.py | 1 + src/sage/combinat/tiling.py | 24 ++-- src/sage/combinat/words/finite_word.py | 11 +- src/sage/combinat/words/morphism.py | 8 +- src/sage/crypto/block_cipher/des.py | 6 +- src/sage/crypto/block_cipher/present.py | 6 +- src/sage/crypto/classical_cipher.py | 1 + src/sage/crypto/cryptosystem.py | 1 + src/sage/crypto/lattice.py | 4 +- src/sage/crypto/mq/rijndael_gf.py | 40 +++--- src/sage/crypto/mq/sr.py | 2 - src/sage/crypto/sboxes.py | 1 + src/sage/data_structures/mutable_poset.py | 4 +- src/sage/data_structures/stream.py | 4 +- src/sage/databases/cremona.py | 2 +- src/sage/databases/cubic_hecke_db.py | 4 +- src/sage/databases/findstat.py | 2 +- src/sage/databases/knotinfo_db.py | 4 +- src/sage/databases/oeis.py | 2 +- src/sage/databases/sloane.py | 6 +- src/sage/databases/sql_db.py | 8 +- src/sage/doctest/__main__.py | 20 +-- src/sage/doctest/control.py | 6 +- src/sage/doctest/fixtures.py | 2 - src/sage/doctest/forker.py | 10 +- src/sage/doctest/parsing.py | 4 +- src/sage/doctest/sources.py | 4 +- .../dynamics/arithmetic_dynamics/affine_ds.py | 1 - .../arithmetic_dynamics/berkovich_ds.py | 6 +- .../endPN_automorphism_group.py | 1 - .../product_projective_ds.py | 1 - .../arithmetic_dynamics/projective_ds.py | 10 +- .../dynamics/cellular_automata/elementary.py | 2 +- .../dynamics/cellular_automata/solitons.py | 8 +- .../dynamics/complex_dynamics/mandel_julia.py | 6 +- src/sage/ext_data/nbconvert/postprocess.py | 1 - src/sage/features/__init__.py | 2 +- src/sage/features/ffmpeg.py | 6 +- src/sage/features/imagemagick.py | 4 +- src/sage/features/kenzo.py | 1 - src/sage/features/latex.py | 2 +- src/sage/features/lrs.py | 6 +- src/sage/features/meataxe.py | 1 - src/sage/functions/airy.py | 4 +- src/sage/functions/gamma.py | 2 +- src/sage/functions/hypergeometric.py | 7 +- src/sage/functions/jacobi.py | 8 +- src/sage/functions/piecewise.py | 1 - src/sage/functions/special.py | 2 +- src/sage/functions/transcendental.py | 2 +- src/sage/game_theory/normal_form_game.py | 4 +- src/sage/geometry/cone.py | 12 +- src/sage/geometry/cone_catalog.py | 6 +- src/sage/geometry/cone_critical_angles.py | 3 +- src/sage/geometry/convex_set.py | 2 +- src/sage/geometry/fan.py | 24 ++-- src/sage/geometry/fan_morphism.py | 12 +- .../hyperbolic_space/hyperbolic_coercion.py | 2 +- .../hyperbolic_space/hyperbolic_isometry.py | 6 +- .../hyperbolic_space/hyperbolic_model.py | 2 +- .../hyperbolic_space/hyperbolic_point.py | 2 +- src/sage/geometry/lattice_polytope.py | 12 +- src/sage/geometry/newton_polygon.py | 4 +- src/sage/geometry/polyhedron/backend_cdd.py | 1 - .../geometry/polyhedron/backend_cdd_rdf.py | 1 - src/sage/geometry/polyhedron/backend_field.py | 1 - src/sage/geometry/polyhedron/base.py | 4 +- src/sage/geometry/polyhedron/base0.py | 2 +- src/sage/geometry/polyhedron/base2.py | 2 +- src/sage/geometry/polyhedron/base4.py | 2 +- src/sage/geometry/polyhedron/base7.py | 2 +- .../geometry/polyhedron/base_number_field.py | 1 - .../geometry/polyhedron/double_description.py | 2 - .../double_description_inhomogeneous.py | 3 - .../polyhedron/generating_function.py | 16 +-- .../lattice_euclidean_group_element.py | 1 - src/sage/geometry/polyhedron/palp_database.py | 2 +- src/sage/geometry/polyhedron/plot.py | 4 +- .../geometry/polyhedron/representation.py | 1 - src/sage/geometry/pseudolines.py | 7 - .../parametrized_surface3d.py | 2 +- .../surface3d_generators.py | 1 - src/sage/geometry/toric_lattice.py | 6 +- src/sage/geometry/toric_plotter.py | 4 +- .../triangulation/point_configuration.py | 1 - src/sage/geometry/voronoi_diagram.py | 2 +- src/sage/graphs/bipartite_graph.py | 18 +-- src/sage/graphs/digraph.py | 17 +-- src/sage/graphs/digraph_generators.py | 5 +- src/sage/graphs/domination.py | 2 - .../graphs/generators/classical_geometries.py | 5 +- src/sage/graphs/generators/degree_sequence.py | 2 +- src/sage/graphs/generators/families.py | 2 +- src/sage/graphs/generators/intersection.py | 4 +- src/sage/graphs/generators/random.py | 2 +- src/sage/graphs/generators/smallgraphs.py | 13 +- src/sage/graphs/generic_graph.py | 101 +++++---------- src/sage/graphs/graph.py | 19 +-- src/sage/graphs/graph_database.py | 7 +- src/sage/graphs/graph_generators.py | 10 +- src/sage/graphs/graph_input.py | 4 +- src/sage/graphs/graph_latex.py | 2 - src/sage/graphs/graph_list.py | 3 +- src/sage/graphs/graph_plot.py | 36 +++--- src/sage/graphs/graph_plot_js.py | 2 +- src/sage/graphs/hypergraph_generators.py | 1 - src/sage/graphs/isgci.py | 4 +- src/sage/graphs/matching_covered_graph.py | 51 ++++---- src/sage/graphs/morphisms.py | 1 - src/sage/graphs/orientations.py | 5 +- src/sage/graphs/pq_trees.py | 11 -- .../abelian_gps/dual_abelian_group_element.py | 1 + .../additive_abelian_wrapper.py | 1 - src/sage/groups/affine_gps/affine_group.py | 1 - src/sage/groups/artin.py | 2 +- src/sage/groups/conjugacy_classes.py | 6 +- src/sage/groups/finitely_presented.py | 2 +- src/sage/groups/generic.py | 6 +- src/sage/groups/group_semidirect_product.py | 6 +- src/sage/groups/libgap_group.py | 2 - .../groups/lie_gps/nilpotent_lie_group.py | 2 +- src/sage/groups/matrix_gps/isometries.py | 2 +- src/sage/groups/matrix_gps/linear.py | 5 +- src/sage/groups/matrix_gps/matrix_group.py | 1 - .../groups/matrix_gps/matrix_group_gap.py | 1 - src/sage/groups/matrix_gps/named_group.py | 1 - src/sage/groups/matrix_gps/named_group_gap.py | 1 - .../groups/matrix_gps/pickling_overrides.py | 3 - src/sage/groups/misc_gps/argument_groups.py | 8 +- src/sage/groups/misc_gps/imaginary_groups.py | 6 +- src/sage/groups/perm_gps/permgroup.py | 4 +- src/sage/groups/perm_gps/permgroup_named.py | 2 +- src/sage/groups/raag.py | 3 +- .../semimonomial_transformation_group.py | 1 + src/sage/homology/chain_complex.py | 5 +- src/sage/homology/chain_complex_morphism.py | 2 +- src/sage/homology/chains.py | 4 - src/sage/homology/free_resolution.py | 2 +- src/sage/homology/graded_resolution.py | 2 +- .../homology_vector_space_with_basis.py | 3 +- src/sage/interacts/algebra.py | 1 - src/sage/interfaces/axiom.py | 2 +- src/sage/interfaces/ecm.py | 1 - src/sage/interfaces/expect.py | 1 + src/sage/interfaces/four_ti_2.py | 2 +- src/sage/interfaces/fricas.py | 2 +- src/sage/interfaces/fricas_translator.py | 1 + src/sage/interfaces/gap.py | 2 +- src/sage/interfaces/giac.py | 1 - src/sage/interfaces/gp.py | 2 +- src/sage/interfaces/kash.py | 2 +- src/sage/interfaces/latte.py | 1 - src/sage/interfaces/macaulay2.py | 17 +-- src/sage/interfaces/maple.py | 1 - src/sage/interfaces/maxima.py | 4 +- src/sage/interfaces/mupad.py | 1 - src/sage/interfaces/phc.py | 1 - src/sage/interfaces/qepcad.py | 12 +- src/sage/interfaces/r.py | 1 - src/sage/interfaces/rubik.py | 2 - src/sage/interfaces/sage0.py | 3 +- src/sage/interfaces/singular.py | 8 +- src/sage/interfaces/sympy.py | 1 + src/sage/interfaces/tab_completion.py | 1 - src/sage/interfaces/tides.py | 10 +- src/sage/knots/free_knotinfo_monoid.py | 1 - src/sage/knots/gauss_code.py | 1 + src/sage/knots/knot.py | 2 +- src/sage/knots/knotinfo.py | 3 +- src/sage/libs/coxeter3/coxeter_group.py | 2 +- src/sage/libs/gap/context_managers.py | 1 - src/sage/libs/gap/gap_functions.py | 1 - src/sage/libs/gap/gap_globals.py | 1 - src/sage/libs/gap/operations.py | 1 - src/sage/libs/lrcalc/lrcalc.py | 2 +- src/sage/manifolds/continuous_map.py | 6 +- .../differentiable/affine_connection.py | 6 +- .../differentiable/bundle_connection.py | 12 +- .../characteristic_cohomology_class.py | 12 +- .../differentiable/degenerate_submanifold.py | 16 +-- .../differentiable/examples/sphere.py | 2 +- .../differentiable/integrated_curve.py | 14 +- src/sage/manifolds/differentiable/manifold.py | 6 +- src/sage/manifolds/differentiable/metric.py | 2 +- .../manifolds/differentiable/mixed_form.py | 6 +- .../differentiable/mixed_form_algebra.py | 4 +- .../differentiable/poisson_tensor.py | 1 - .../pseudo_riemannian_submanifold.py | 28 ++-- .../differentiable/tangent_vector.py | 4 +- .../manifolds/differentiable/tensorfield.py | 18 +-- .../differentiable/tensorfield_paral.py | 5 +- .../manifolds/differentiable/vector_bundle.py | 2 +- .../manifolds/differentiable/vectorfield.py | 3 +- .../differentiable/vectorfield_module.py | 6 +- .../manifolds/differentiable/vectorframe.py | 4 +- src/sage/manifolds/local_frame.py | 6 +- src/sage/manifolds/manifold.py | 2 +- src/sage/manifolds/point.py | 2 +- src/sage/manifolds/scalarfield.py | 16 +-- src/sage/manifolds/section.py | 22 ++-- src/sage/manifolds/section_module.py | 6 +- src/sage/manifolds/subsets/pullback.py | 4 - src/sage/manifolds/topological_submanifold.py | 7 +- src/sage/manifolds/vector_bundle.py | 10 +- src/sage/manifolds/vector_bundle_fiber.py | 2 +- src/sage/matrix/matrix_misc.py | 2 +- src/sage/matrix/matrix_space.py | 4 +- src/sage/matrix/operation_table.py | 1 - src/sage/matrix/special.py | 4 +- src/sage/matroids/constructor.py | 1 - src/sage/misc/cython.py | 2 +- src/sage/misc/decorators.py | 6 +- src/sage/misc/dev_tools.py | 10 +- src/sage/misc/explain_pickle.py | 1 - src/sage/misc/gperftools.py | 3 +- src/sage/misc/html.py | 1 - src/sage/misc/latex.py | 4 +- src/sage/misc/latex_standalone.py | 18 +-- src/sage/misc/multireplace.py | 1 - src/sage/misc/package.py | 1 - src/sage/misc/remote_file.py | 1 + src/sage/misc/sagedoc.py | 10 +- src/sage/misc/sageinspect.py | 4 +- src/sage/misc/superseded.py | 2 +- src/sage/misc/test_nested_class.py | 2 +- src/sage/misc/unknown.py | 1 - src/sage/modular/abvar/abvar.py | 1 - src/sage/modular/abvar/abvar_newform.py | 1 + src/sage/modular/abvar/finite_subgroup.py | 2 +- src/sage/modular/abvar/homspace.py | 2 - src/sage/modular/abvar/morphism.py | 1 - src/sage/modular/abvar/torsion_subgroup.py | 1 - .../modular/arithgroup/arithgroup_perm.py | 1 - .../modular/arithgroup/congroup_gamma1.py | 1 - .../modular/arithgroup/congroup_generic.py | 1 - src/sage/modular/arithgroup/tests.py | 1 + src/sage/modular/btquotients/btquotient.py | 4 +- .../modular/btquotients/pautomorphicform.py | 6 +- src/sage/modular/buzzard.py | 1 + src/sage/modular/cusps_nf.py | 9 +- src/sage/modular/dims.py | 4 +- src/sage/modular/dirichlet.py | 2 +- src/sage/modular/drinfeld_modform/element.py | 2 +- src/sage/modular/drinfeld_modform/ring.py | 14 +- src/sage/modular/etaproducts.py | 1 - src/sage/modular/hecke/algebra.py | 1 + src/sage/modular/hecke/ambient_module.py | 5 +- src/sage/modular/hecke/hecke_operator.py | 1 + src/sage/modular/hecke/homspace.py | 1 + src/sage/modular/hecke/module.py | 2 +- src/sage/modular/hecke/morphism.py | 1 - src/sage/modular/hecke/submodule.py | 4 +- src/sage/modular/local_comp/local_comp.py | 2 +- src/sage/modular/modform/ambient.py | 2 +- src/sage/modular/modform/eis_series.py | 2 +- .../modular/modform/eisenstein_submodule.py | 1 - src/sage/modular/modform/element.py | 4 +- src/sage/modular/modform/j_invariant.py | 1 + .../modular/modform/l_series_gross_zagier.py | 3 +- src/sage/modular/modform/ring.py | 5 +- src/sage/modular/modform/space.py | 1 - .../modform_hecketriangle/abstract_space.py | 1 + .../hecke_triangle_group_element.py | 6 +- src/sage/modular/modsym/ambient.py | 2 +- src/sage/modular/modsym/boundary.py | 1 - src/sage/modular/modsym/ghlist.py | 1 + src/sage/modular/modsym/modsym.py | 2 - src/sage/modular/modsym/modular_symbols.py | 1 + src/sage/modular/modsym/subspace.py | 2 +- src/sage/modular/multiple_zeta.py | 1 + src/sage/modular/multiple_zeta_F_algebra.py | 1 + src/sage/modular/overconvergent/genus0.py | 1 + .../modular/overconvergent/weightspace.py | 1 - .../modular/pollack_stevens/distributions.py | 3 +- .../modular/pollack_stevens/fund_domain.py | 4 - src/sage/modular/pollack_stevens/modsym.py | 5 +- src/sage/modular/pollack_stevens/sigma0.py | 1 - src/sage/modular/pollack_stevens/space.py | 9 +- src/sage/modular/quasimodform/element.py | 5 +- src/sage/modules/fg_pid/fgp_module.py | 1 - src/sage/modules/filtered_vector_space.py | 1 - src/sage/modules/fp_graded/free_module.py | 4 +- src/sage/modules/fp_graded/module.py | 2 +- src/sage/modules/fp_graded/morphism.py | 19 +-- src/sage/modules/free_module.py | 26 ++-- src/sage/modules/free_module_integer.py | 2 +- src/sage/modules/free_module_morphism.py | 1 - src/sage/modules/free_quadratic_module.py | 1 - ...free_quadratic_module_integer_symmetric.py | 10 +- src/sage/modules/matrix_morphism.py | 1 - .../modules/multi_filtered_vector_space.py | 5 +- src/sage/modules/submodule.py | 2 +- src/sage/modules/torsion_quadratic_module.py | 6 +- src/sage/modules/vector_space_homspace.py | 1 - src/sage/modules/vector_space_morphism.py | 2 - src/sage/modules/with_basis/morphism.py | 2 +- src/sage/monoids/automatic_semigroup.py | 2 - src/sage/monoids/free_abelian_monoid.py | 2 +- src/sage/monoids/hecke_monoid.py | 1 + src/sage/monoids/string_monoid.py | 3 +- src/sage/monoids/trace_monoid.py | 4 +- .../numerical/backends/cvxopt_backend_test.py | 1 - .../numerical/backends/cvxpy_backend_test.py | 1 - .../backends/generic_backend_test.py | 1 - .../numerical/backends/glpk_backend_test.py | 1 - .../backends/glpk_exact_backend_test.py | 1 - .../backends/interactivelp_backend_test.py | 1 - .../numerical/backends/logging_backend.py | 7 +- .../numerical/backends/ppl_backend_test.py | 1 - .../numerical/backends/scip_backend_test.py | 1 - .../numerical/interactive_simplex_method.py | 36 +++--- src/sage/numerical/linear_tensor.py | 1 - src/sage/parallel/map_reduce.py | 2 +- src/sage/parallel/use_fork.py | 1 - src/sage/plot/animate.py | 6 +- src/sage/plot/arc.py | 2 +- src/sage/plot/arrow.py | 5 +- src/sage/plot/bezier_path.py | 2 +- src/sage/plot/circle.py | 4 +- src/sage/plot/contour_plot.py | 8 +- src/sage/plot/disk.py | 2 +- src/sage/plot/ellipse.py | 2 +- src/sage/plot/graphics.py | 24 ++-- src/sage/plot/hyperbolic_regular_polygon.py | 2 +- src/sage/plot/misc.py | 4 +- src/sage/plot/multigraphics.py | 15 ++- src/sage/plot/plot.py | 3 +- src/sage/plot/plot3d/implicit_plot3d.py | 1 + src/sage/plot/plot3d/list_plot3d.py | 5 +- src/sage/plot/plot3d/plot3d.py | 2 +- src/sage/plot/plot3d/shapes2.py | 6 +- src/sage/plot/plot3d/tachyon.py | 44 ++----- src/sage/plot/plot3d/texture.py | 2 +- src/sage/plot/plot_field.py | 1 + src/sage/plot/streamline_plot.py | 1 + src/sage/plot/text.py | 2 +- src/sage/quadratic_forms/binary_qf.py | 8 +- src/sage/quadratic_forms/genera/genus.py | 15 +-- .../quadratic_forms/genera/spinor_genus.py | 2 +- src/sage/quadratic_forms/quadratic_form.py | 2 - .../quadratic_form__automorphisms.py | 3 +- .../quadratic_form__equivalence_testing.py | 5 - ...uadratic_form__local_density_congruence.py | 4 - .../quadratic_form__local_field_invariants.py | 2 - .../quadratic_form__local_normal_form.py | 2 - ...c_form__local_representation_conditions.py | 1 + ...dratic_form__mass__Conway_Sloane_masses.py | 3 - .../quadratic_form__mass__Siegel_densities.py | 1 - .../quadratic_form__neighbors.py | 1 - .../quadratic_form__reduction_theory.py | 6 - .../quadratic_form__split_local_covering.py | 3 - .../quadratic_forms/quadratic_form__theta.py | 2 - .../quadratic_forms/random_quadraticform.py | 3 +- src/sage/quadratic_forms/ternary_qf.py | 3 - src/sage/quivers/morphism.py | 8 +- src/sage/repl/configuration.py | 2 - src/sage/repl/display/fancy_repr.py | 1 - src/sage/repl/display/formatter.py | 2 - src/sage/repl/display/jsmol_iframe.py | 5 +- src/sage/repl/display/pretty_print.py | 2 - src/sage/repl/image.py | 1 - src/sage/repl/interface_magic.py | 2 - src/sage/repl/ipython_extension.py | 2 - src/sage/repl/ipython_kernel/install.py | 7 +- src/sage/repl/ipython_kernel/widgets.py | 1 - src/sage/repl/preparse.py | 1 - src/sage/repl/prompts.py | 3 - src/sage/repl/rich_output/backend_base.py | 1 - src/sage/repl/rich_output/backend_doctest.py | 1 - src/sage/repl/rich_output/backend_ipython.py | 4 +- src/sage/repl/rich_output/buffer.py | 2 - src/sage/repl/rich_output/display_manager.py | 6 +- src/sage/repl/rich_output/output_basic.py | 9 +- src/sage/repl/rich_output/output_browser.py | 1 - src/sage/repl/rich_output/output_catalog.py | 1 - src/sage/repl/rich_output/output_graphics.py | 6 - .../repl/rich_output/output_graphics3d.py | 4 - src/sage/repl/rich_output/output_video.py | 3 +- src/sage/repl/rich_output/preferences.py | 3 - src/sage/repl/rich_output/pretty_print.py | 1 - src/sage/repl/rich_output/test_backend.py | 3 - src/sage/repl/user_globals.py | 3 +- .../rings/algebraic_closure_finite_field.py | 1 + src/sage/rings/asymptotic/asymptotic_ring.py | 31 +++-- ...otics_multivariate_generating_functions.py | 14 +- src/sage/rings/asymptotic/growth_group.py | 40 +++--- .../asymptotic/growth_group_cartesian.py | 13 +- src/sage/rings/asymptotic/misc.py | 4 +- src/sage/rings/asymptotic/term_monoid.py | 46 +++---- src/sage/rings/big_oh.py | 4 +- src/sage/rings/continued_fraction.py | 6 +- src/sage/rings/derivation.py | 12 +- .../finite_rings/finite_field_pari_ffelt.py | 1 - .../rings/finite_rings/integer_mod_ring.py | 3 +- src/sage/rings/fraction_field.py | 2 +- .../function_field/drinfeld_modules/action.py | 4 +- .../drinfeld_modules/drinfeld_module.py | 24 ++-- .../function_field/drinfeld_modules/homset.py | 4 +- .../drinfeld_modules/morphism.py | 4 +- .../rings/function_field/function_field.py | 8 +- .../function_field/function_field_polymod.py | 4 +- .../function_field/jacobian_unique_hess.py | 1 - src/sage/rings/ideal.py | 2 +- src/sage/rings/infinity.py | 5 - src/sage/rings/invariants/invariant_theory.py | 16 +-- src/sage/rings/invariants/reconstruction.py | 14 +- src/sage/rings/laurent_series_ring.py | 1 - src/sage/rings/lazy_series.py | 10 +- src/sage/rings/lazy_series_ring.py | 2 +- src/sage/rings/localization.py | 1 - .../rings/multi_power_series_ring_element.py | 2 +- src/sage/rings/number_field/S_unit_solver.py | 9 +- src/sage/rings/number_field/number_field.py | 13 +- .../number_field/number_field_ideal_rel.py | 1 - src/sage/rings/number_field/order.py | 2 +- src/sage/rings/number_field/selmer_group.py | 1 - .../rings/number_field/totallyreal_rel.py | 4 +- .../rings/padics/padic_lattice_element.py | 1 - .../padics/unramified_extension_generic.py | 1 - src/sage/rings/padics/witt_vector.py | 7 +- src/sage/rings/padics/witt_vector_ring.py | 19 ++- src/sage/rings/polynomial/complex_roots.py | 1 - src/sage/rings/polynomial/groebner_fan.py | 3 - .../polynomial/integer_valued_polynomials.py | 1 - src/sage/rings/polynomial/msolve.py | 1 - .../polynomial/multi_polynomial_element.py | 2 +- .../polynomial/multi_polynomial_ideal.py | 2 +- src/sage/rings/polynomial/omega.py | 2 +- .../polynomial_padic_capped_relative_dense.py | 6 +- src/sage/rings/polynomial/pbori/frontend.py | 1 - src/sage/rings/polynomial/pbori/gbcore.py | 2 - src/sage/rings/polynomial/pbori/ll.py | 2 - .../polynomial/polynomial_element_generic.py | 1 - .../rings/polynomial/polynomial_fateman.py | 1 + .../polynomial/polynomial_quotient_ring.py | 1 - .../polynomial_quotient_ring_element.py | 1 - src/sage/rings/polynomial/polynomial_ring.py | 1 - .../polynomial_singular_interface.py | 2 +- .../rings/polynomial/skew_polynomial_ring.py | 2 +- src/sage/rings/polynomial/toy_buchberger.py | 1 - src/sage/rings/qqbar.py | 1 - src/sage/rings/quotient_ring_element.py | 2 +- src/sage/rings/rational_field.py | 6 +- .../rings/semirings/tropical_mpolynomial.py | 6 +- .../rings/semirings/tropical_polynomial.py | 2 +- src/sage/sat/boolean_polynomials.py | 1 + src/sage/sat/solvers/sat_lp.py | 1 + src/sage/schemes/affine/affine_morphism.py | 2 - src/sage/schemes/affine/affine_point.py | 2 - .../schemes/berkovich/berkovich_cp_element.py | 2 +- src/sage/schemes/berkovich/berkovich_space.py | 6 +- src/sage/schemes/curves/affine_curve.py | 6 +- src/sage/schemes/curves/constructor.py | 2 +- src/sage/schemes/curves/curve.py | 6 +- src/sage/schemes/curves/point.py | 2 +- src/sage/schemes/curves/projective_curve.py | 2 +- src/sage/schemes/curves/zariski_vankampen.py | 1 + .../cyclic_covers/charpoly_frobenius.py | 1 + src/sage/schemes/cyclic_covers/constructor.py | 6 +- .../schemes/elliptic_curves/cardinality.py | 1 + .../elliptic_curves/ell_curve_isogeny.py | 10 +- src/sage/schemes/elliptic_curves/ell_field.py | 1 - .../elliptic_curves/ell_finite_field.py | 2 - .../schemes/elliptic_curves/ell_generic.py | 2 +- src/sage/schemes/elliptic_curves/ell_point.py | 18 ++- .../schemes/elliptic_curves/ell_tate_curve.py | 12 +- .../elliptic_curves/gal_reps_number_field.py | 2 +- src/sage/schemes/elliptic_curves/gp_simon.py | 1 + src/sage/schemes/elliptic_curves/height.py | 2 - .../schemes/elliptic_curves/hom_composite.py | 5 +- .../schemes/elliptic_curves/hom_fractional.py | 2 +- .../schemes/elliptic_curves/hom_frobenius.py | 3 +- .../schemes/elliptic_curves/hom_scalar.py | 1 - src/sage/schemes/elliptic_curves/hom_sum.py | 3 +- .../schemes/elliptic_curves/hom_velusqrt.py | 2 +- .../schemes/elliptic_curves/isogeny_class.py | 1 - src/sage/schemes/elliptic_curves/padics.py | 12 +- .../schemes/elliptic_curves/period_lattice.py | 3 +- src/sage/schemes/elliptic_curves/sha_tate.py | 1 - .../elliptic_curves/weierstrass_transform.py | 2 - src/sage/schemes/generic/algebraic_scheme.py | 6 +- src/sage/schemes/generic/ambient_space.py | 2 +- src/sage/schemes/generic/scheme.py | 2 +- .../hyperelliptic_curves/invariants.py | 2 +- .../schemes/hyperelliptic_curves/mestre.py | 4 +- .../hyperelliptic_curves/monsky_washnitzer.py | 6 +- src/sage/schemes/plane_conics/con_field.py | 12 +- .../schemes/plane_conics/con_number_field.py | 11 +- .../plane_conics/con_rational_field.py | 2 +- .../con_rational_function_field.py | 2 +- src/sage/schemes/plane_conics/constructor.py | 10 +- .../schemes/plane_quartics/quartic_generic.py | 1 - src/sage/schemes/product_projective/homset.py | 2 +- src/sage/schemes/product_projective/point.py | 1 - .../schemes/product_projective/subscheme.py | 2 +- .../schemes/projective/projective_homset.py | 2 +- .../schemes/projective/projective_morphism.py | 4 +- .../schemes/projective/projective_point.py | 7 +- .../schemes/projective/projective_space.py | 6 +- .../projective/projective_subscheme.py | 2 +- .../riemann_surfaces/riemann_surface.py | 2 +- src/sage/schemes/toric/chow_group.py | 1 + src/sage/schemes/toric/divisor.py | 8 +- src/sage/schemes/toric/fano_variety.py | 30 ++--- src/sage/schemes/toric/homset.py | 1 - src/sage/schemes/toric/ideal.py | 1 - src/sage/schemes/toric/library.py | 12 +- src/sage/schemes/toric/morphism.py | 10 +- src/sage/schemes/toric/points.py | 5 - src/sage/schemes/toric/sheaf/constructor.py | 2 +- src/sage/schemes/toric/sheaf/klyachko.py | 3 +- src/sage/schemes/toric/variety.py | 22 ++-- .../weighted_projective_point.py | 4 +- .../weighted_projective_space.py | 8 +- src/sage/sets/cartesian_product.py | 1 - src/sage/sets/set.py | 2 +- .../discrete_gaussian_lattice.py | 6 +- src/sage/structure/global_options.py | 1 - src/sage/structure/indexed_generators.py | 8 +- src/sage/structure/list_clone_timings.py | 1 - src/sage/structure/sage_object_test.py | 1 - src/sage/structure/set_factories.py | 1 - src/sage/structure/set_factories_example.py | 2 +- src/sage/structure/test_factory.py | 1 - src/sage/symbolic/integration/external.py | 4 +- src/sage/symbolic/integration/integral.py | 2 +- src/sage/symbolic/random_tests.py | 1 - src/sage/symbolic/subring.py | 11 +- src/sage/tensor/modules/comp.py | 10 +- .../tensor/modules/finite_rank_free_module.py | 10 +- .../modules/free_module_automorphism.py | 4 +- src/sage/tensor/modules/free_module_tensor.py | 16 +-- .../tensor/modules/tensor_free_submodule.py | 2 +- .../tensor/modules/tensor_with_indices.py | 9 +- src/sage/tests/all.py | 3 +- src/sage/tests/arxiv_0812_2725.py | 1 + src/sage/tests/benchmark.py | 1 + .../book_schilling_zabrocki_kschur_primer.py | 1 + .../actions-sage-exercises.py | 1 + .../judson_abstract_algebra/actions-sage.py | 1 + .../judson_abstract_algebra/algcodes-sage.py | 1 + .../judson_abstract_algebra/boolean-sage.py | 1 + .../cosets-sage-exercises.py | 1 + .../judson_abstract_algebra/cosets-sage.py | 1 + .../judson_abstract_algebra/crypt-sage.py | 1 + .../judson_abstract_algebra/cyclic-sage.py | 1 + .../judson_abstract_algebra/domains-sage.py | 1 + .../judson_abstract_algebra/fields-sage.py | 1 + .../judson_abstract_algebra/finite-sage.py | 1 + .../judson_abstract_algebra/galois-sage.py | 1 + .../judson_abstract_algebra/groups-sage.py | 1 + .../homomorph-sage-exercises.py | 1 + .../judson_abstract_algebra/homomorph-sage.py | 1 + .../judson_abstract_algebra/integers-sage.py | 1 + .../judson_abstract_algebra/isomorph-sage.py | 1 + .../judson_abstract_algebra/normal-sage.py | 1 + .../judson_abstract_algebra/permute-sage.py | 1 + .../judson_abstract_algebra/poly-sage.py | 1 + .../judson_abstract_algebra/rings-sage.py | 1 + .../judson_abstract_algebra/sets-sage.py | 1 + .../judson_abstract_algebra/struct-sage.py | 1 + .../judson_abstract_algebra/sylow-sage.py | 1 + .../vect-sage-exercises.py | 1 + .../judson_abstract_algebra/vect-sage.py | 1 + src/sage/topology/cubical_complex.py | 1 + src/sage/topology/simplicial_set.py | 26 ++-- .../topology/simplicial_set_constructions.py | 4 +- src/sage/topology/simplicial_set_morphism.py | 10 +- src/sage/typeset/character_art.py | 5 +- src/sage/typeset/character_art_factory.py | 3 +- src/sage/typeset/symbols.py | 3 - src/sage/typeset/unicode_characters.py | 8 +- 845 files changed, 1669 insertions(+), 2331 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 5fffa6371be..09ffc41f055 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -253,6 +253,7 @@ target-version = "py312" line-length = 320 + exclude = [ # This directory is full of old autogenerated files. # Linting it would just get in the way of adding stricter linter rules @@ -263,6 +264,9 @@ exclude = [ "build/", ] +[tool.ruff.format] +quote-style = "preserve" + [tool.ruff.lint] # Rules that we deliberately do not attempt to follow, either because we diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index e028489a87c..290dc0829f0 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -195,7 +195,7 @@ def _repr_(self) -> str: return "Subsets of {0}" + extra if self._nbits == 2: return "Subsets of {0,1}" + extra - return f"Subsets of {{0,1,...,{self._nbits-1}}}" + extra + return f"Subsets of {{0,1,...,{self._nbits - 1}}}" + extra def _latex_(self) -> str: r""" @@ -225,7 +225,7 @@ def _latex_(self) -> str: return f"\\mathcal{{P}}(\\{{0\\}}{extra})" if self._nbits == 2: return f"\\mathcal{{P}}(\\{{0,1\\}}{extra})" - return f"\\mathcal{{P}}(\\{{0,1,\\ldots,{self._nbits-1}\\}}{extra})" + return f"\\mathcal{{P}}(\\{{0,1,\\ldots,{self._nbits - 1}\\}}{extra})" def __iter__(self): r""" diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index 9f324502b6f..986fdba05df 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -1307,7 +1307,7 @@ def _Hom_(self, B, category): # categories for self and B, which might be the category of # rings). if R != B.base_ring(): - raise NotImplementedError('homomorphisms of graded commutative ' 'algebras have only been implemented ' 'when the base rings are the same') + raise NotImplementedError('homomorphisms of graded commutative algebras have only been implemented when the base rings are the same') cat = Algebras(R).Graded() if category is not None and not category.is_subcategory(cat): raise TypeError("{} is not a subcategory of graded algebras".format(category)) @@ -2471,7 +2471,7 @@ def cohomology_generators(self, max_degree): {1: [e1 - e2, e3, e4], 2: [e1*e3, e1*e4]} """ if not (max_degree in ZZ and max_degree > 0): - raise ValueError('the given maximal degree must be a ' 'positive integer') + raise ValueError('the given maximal degree must be a positive integer') def vector_to_element(v, deg): """ @@ -3750,7 +3750,7 @@ def __init__(self, parent, im_gens, check=True): # Now check that the relations are respected. if check: if any(x not in codomain for x in im_gens): - raise ValueError('not all elements of im_gens are in ' 'the codomain') + raise ValueError('not all elements of im_gens are in the codomain') R = domain.cover_ring() from_R = dict(zip(R.gens(), im_gens)) if hasattr(R, 'free_algebra'): @@ -3761,21 +3761,21 @@ def __init__(self, parent, im_gens, check=True): for left in R.relations(): zero = left.subs(from_free) - R.relations()[left].subs(from_R) if zero: - raise ValueError('the proposed morphism does not respect ' 'the nc-relations') + raise ValueError('the proposed morphism does not respect the nc-relations') # Now check any extra relations, including x**2=0 for x in # odd degree. These are defined by a list of generators of # the defining ideal. for g in domain.defining_ideal().gens(): zero = g.subs(from_R) if zero: - raise ValueError('the proposed morphism does not respect ' 'the relations') + raise ValueError('the proposed morphism does not respect the relations') # If the domain and codomain have differentials, check # those, too. if isinstance(domain, DifferentialGCAlgebra) and isinstance(codomain, DifferentialGCAlgebra): dom_diff = domain.differential() cod_diff = codomain.differential() if any(cod_diff(self(g)) != self(dom_diff(g)) for g in domain.gens()): - raise ValueError('the proposed morphism does not respect ' 'the differentials') + raise ValueError('the proposed morphism does not respect the differentials') def _call_(self, x): """ @@ -3950,7 +3950,7 @@ def identity(self): False """ if self.domain() != self.codomain(): - raise TypeError('identity map is only defined for ' 'endomorphism sets') + raise TypeError('identity map is only defined for endomorphism sets') return GCAlgebraMorphism(self, self.domain().gens()) def __call__(self, im_gens, check=True): diff --git a/src/sage/algebras/free_zinbiel_algebra.py b/src/sage/algebras/free_zinbiel_algebra.py index 404a060eb39..2d6a2bb5fe8 100644 --- a/src/sage/algebras/free_zinbiel_algebra.py +++ b/src/sage/algebras/free_zinbiel_algebra.py @@ -836,7 +836,7 @@ def merge(self, other): """ if isinstance(other, ZinbielFunctor): if self._side != other._side: - raise TypeError('cannot merge free Zinbiel algebras ' 'with distinct sides') + raise TypeError('cannot merge free Zinbiel algebras with distinct sides') if self.vars == other.vars: return self diff --git a/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py b/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py index 54af0e10330..0ef35009c57 100644 --- a/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py +++ b/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py @@ -47,7 +47,6 @@ # http://www.gnu.org/licenses/ # ***************************************************************************** - from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.misc.misc_c import prod diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index 0a6ec4738c1..f26bcee83dc 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -912,7 +912,7 @@ def __init__(self, names, cubic_equation_parameters=None, cubic_equation_roots=N raise ValueError('cubic_equation_roots must consist of exactly 3 elements') if len(set(ring_of_definition_names + generic_extension_ring_names)) < 6: - raise ValueError('there is an overlap of names between cubic equation ' 'parameters (%s) and cubic equation roots (%s)' % (ring_of_definition_names, generic_extension_ring_names)) + raise ValueError('there is an overlap of names between cubic equation parameters (%s) and cubic equation roots (%s)' % (ring_of_definition_names, generic_extension_ring_names)) # ---------------------------------------------------------------------- # setting the generic rings @@ -938,7 +938,7 @@ def __init__(self, names, cubic_equation_parameters=None, cubic_equation_roots=N if cubic_equation_parameters is None and cubic_equation_roots is not None: pa, pb, pc = cubic_equation_roots cubic_equation_parameters = [pa + pb + pc, pa * pb + pb * pc + pa * pc, pa * pb * pc] - verbose('cubic_equation_parameters %s set according to ' 'cubic_equation_roots %s' % (cubic_equation_parameters, cubic_equation_roots), level=2) + verbose('cubic_equation_parameters %s set according to cubic_equation_roots %s' % (cubic_equation_parameters, cubic_equation_roots), level=2) if cubic_equation_parameters is not None: base_ring = ring_of_definition.create_specialization(cubic_equation_parameters) @@ -1519,7 +1519,7 @@ def chevie(self): from sage.interfaces.gap3 import gap3 gap3_function = gap3(gap3_function_str) - na, nb, nc = ('\"%s\"' % indet for indet in self.extension_ring(generic=True).variable_names()) + na, nb, nc = ('"%s"' % indet for indet in self.extension_ring(generic=True).variable_names()) return gap3_function(st_number, na, nb, nc) @cached_method diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py index 7238bf4beff..ef73c995d48 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py @@ -386,7 +386,7 @@ def hom(self, im_gens, codomain=None, check=True, base_map=None): verbose("hom_cycl_gen %s" % hom_cycl_gen, level=2) return super().hom(im_remain, codomain=codomain, check=check, base_map=hom_cycl_gen) if base_map is None: - raise ValueError('number of images must be four (including a ' 'third root of unity at first position) or a ' 'base_map (on %s) must be given' % self.base_ring()) + raise ValueError('number of images must be four (including a third root of unity at first position) or a base_map (on %s) must be given' % self.base_ring()) return super().hom(im_gens, codomain=codomain, check=check, base_map=base_map) def _an_element_(self): diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index ca123726eab..a9a627ec9dc 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -1783,7 +1783,7 @@ def __init__(self, IHAlgebra, prefix=None): sage: C = H.C() """ if IHAlgebra._root is None: - raise ValueError('the Kazhdan-Lusztig bases are defined ' 'only when -q_1*q_2 is a square') + raise ValueError('the Kazhdan-Lusztig bases are defined only when -q_1*q_2 is a square') if IHAlgebra._is_generic: klbasis = IwahoriHeckeAlgebra_nonstandard._KLHeckeBasis diff --git a/src/sage/algebras/jordan_algebra.py b/src/sage/algebras/jordan_algebra.py index ad4aafe62cd..13d7db25a5a 100644 --- a/src/sage/algebras/jordan_algebra.py +++ b/src/sage/algebras/jordan_algebra.py @@ -700,7 +700,7 @@ def _repr_(self) -> str: [-2 3] [ 3 4] """ - return "Jordan algebra over {} given by the symmetric bilinear" " form:\n{}".format(self.base_ring(), self._form) + return "Jordan algebra over {} given by the symmetric bilinear form:\n{}".format(self.base_ring(), self._form) def _element_constructor_(self, *args): """ diff --git a/src/sage/algebras/lie_algebras/bch.py b/src/sage/algebras/lie_algebras/bch.py index cb4f4a766b5..b451fdf0959 100644 --- a/src/sage/algebras/lie_algebras/bch.py +++ b/src/sage/algebras/lie_algebras/bch.py @@ -177,7 +177,7 @@ def bch_iterator(X=None, Y=None): R = L.base_ring() if not R.has_coerce_map_from(QQ): - raise TypeError("the BCH formula is not well defined since %s " "has no coercion from %s" % (R, QQ)) + raise TypeError("the BCH formula is not well defined since %s has no coercion from %s" % (R, QQ)) xdif = X - Y Z = [0, X + Y] # 1-based indexing for convenience diff --git a/src/sage/algebras/lie_algebras/classical_lie_algebra.py b/src/sage/algebras/lie_algebras/classical_lie_algebra.py index bc0c1702b42..3d4ceb556c1 100644 --- a/src/sage/algebras/lie_algebras/classical_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/classical_lie_algebra.py @@ -2499,4 +2499,4 @@ def _test_structure_coeffs(self, **options): sign = 1 if (r in p_roots) == (s in p_roots) else -1 if (r + s) not in p_roots: sign = -sign - tester.assertEqual(x[r + s], sign * ep[r, s], f"[{r}, {s}] = {x[r+s]} != {sign*ep[r,s]}") + tester.assertEqual(x[r + s], sign * ep[r, s], f"[{r}, {s}] = {x[r + s]} != {sign * ep[r, s]}") diff --git a/src/sage/algebras/lie_algebras/lie_algebra.py b/src/sage/algebras/lie_algebras/lie_algebra.py index 3613930a86a..355ffbc35d6 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra.py +++ b/src/sage/algebras/lie_algebras/lie_algebra.py @@ -469,7 +469,7 @@ def check_assoc(A): del kwds["step"] return FreeNilpotentLieAlgebra(R, arg1, step, names=names, **kwds) if nilpotent: - raise ValueError("free nilpotent Lie algebras must have a" " 'step' parameter given") + raise ValueError("free nilpotent Lie algebras must have a 'step' parameter given") if isinstance(arg0, str): names = arg0 @@ -481,10 +481,10 @@ def check_assoc(A): if arg1 != 1 and len(names) == 1: names = tuple('{}{}'.format(names[0], i) for i in range(arg1)) if arg1 != len(names): - raise ValueError("the number of names must equal the" " number of generators") + raise ValueError("the number of names must equal the number of generators") if "step" in kwds or nilpotent: - raise ValueError("free nilpotent Lie algebras must have both" " a number of generators and step parameters" " specified") + raise ValueError("free nilpotent Lie algebras must have both a number of generators and step parameters specified") if abelian: from sage.algebras.lie_algebras.abelian import AbelianLieAlgebra diff --git a/src/sage/algebras/lie_algebras/morphism.py b/src/sage/algebras/lie_algebras/morphism.py index fb0c9c3c95c..41f7ed33013 100644 --- a/src/sage/algebras/lie_algebras/morphism.py +++ b/src/sage/algebras/lie_algebras/morphism.py @@ -587,7 +587,7 @@ def solve_linear_system(A, b, check): try: im_gens = solve_linear_system(A, im_gens, check) except ValueError: - raise ValueError("this does not define a Lie algebra morphism; " "contradictory values for brackets of length %d" % bracketlength) + raise ValueError("this does not define a Lie algebra morphism; contradictory values for brackets of length %d" % bracketlength) spanning_set = list(sm.basis()) if n == len(spanning_set): diff --git a/src/sage/algebras/lie_algebras/nilpotent_lie_algebra.py b/src/sage/algebras/lie_algebras/nilpotent_lie_algebra.py index 37e4128652b..f39f848db3c 100644 --- a/src/sage/algebras/lie_algebras/nilpotent_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/nilpotent_lie_algebra.py @@ -358,7 +358,7 @@ def __init__(self, R, r, s, names, naming, category, **kwds) -> None: sage: TestSuite(L).run() # long time """ if r not in ZZ or r <= 0: - raise ValueError("number of generators %s is not " "a positive integer" % r) + raise ValueError("number of generators %s is not a positive integer" % r) if s not in ZZ or s <= 0: raise ValueError("step %s is not a positive integer" % s) diff --git a/src/sage/algebras/lie_algebras/quotient.py b/src/sage/algebras/lie_algebras/quotient.py index 179f7162cf8..99bed57c2e9 100644 --- a/src/sage/algebras/lie_algebras/quotient.py +++ b/src/sage/algebras/lie_algebras/quotient.py @@ -212,7 +212,7 @@ def __classcall_private__(cls, ambient, I, names=None, index_set=None, index_set I = ambient.ideal(I) if not ambient.base_ring().is_field(): - raise NotImplementedError("quotients over non-fields " "not implemented") + raise NotImplementedError("quotients over non-fields not implemented") # extract an index set from a complementary basis to the ideal I_supp = [X.leading_support() for X in I.leading_monomials()] @@ -314,7 +314,7 @@ def _repr_(self): except AttributeError: ideal_repr = repr(tuple(self._I.gens())) - return "Lie algebra quotient L/I of dimension %s" " over %s where\nL: %s\nI: Ideal %s" % (self.dimension(), self.base_ring(), self.ambient(), ideal_repr) + return "Lie algebra quotient L/I of dimension %s over %s where\nL: %s\nI: Ideal %s" % (self.dimension(), self.base_ring(), self.ambient(), ideal_repr) def _repr_generator(self, i): r""" diff --git a/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py index a736638da03..dc97953eaa5 100644 --- a/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py @@ -100,7 +100,7 @@ def __init__(self, R, ct, names=None, prefix=None, bracket=None) -> None: except IndexError: raise ValueError("ct must be a valid Cartan Type") if not (ct.is_finite() and ct.is_irreducible): - raise ValueError("only affine algebras of simple finite dimensional" "Lie algebras are implemented") + raise ValueError("only affine algebras of simple finite dimensionalLie algebras are implemented") hv = Integer(ct.dual_coxeter_number()) g = LieAlgebra(R, cartan_type=ct) B = g.basis() diff --git a/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py index cfa00218e59..8c8d77749a7 100644 --- a/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py @@ -122,4 +122,4 @@ def _repr_(self) -> str: sage: lie_conformal_algebras.BosonicGhosts(QQbar) The Bosonic ghosts Lie conformal algebra with generators (beta, gamma, K) over Algebraic Field """ - return "The Bosonic ghosts Lie conformal algebra with generators {} " "over {}".format(self.gens(), self.base_ring()) + return "The Bosonic ghosts Lie conformal algebra with generators {} over {}".format(self.gens(), self.base_ring()) diff --git a/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py index 1a8e2ceabdf..b0ddb111497 100644 --- a/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py @@ -120,4 +120,4 @@ def _repr_(self) -> str: sage: lie_conformal_algebras.FermionicGhosts(QQ) The Fermionic ghosts Lie conformal algebra with generators (b, c, K) over Rational Field """ - return "The Fermionic ghosts Lie conformal algebra with generators {} " "over {}".format(self.gens(), self.base_ring()) + return "The Fermionic ghosts Lie conformal algebra with generators {} over {}".format(self.gens(), self.base_ring()) diff --git a/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py index f6da23c8ad9..74a9beb6dbc 100644 --- a/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py @@ -146,7 +146,7 @@ def _repr_(self) -> str: sage: lie_conformal_algebras.FreeBosons(AA) The free Bosons Lie conformal algebra with generators (alpha, K) over Algebraic Real Field """ - return "The free Bosons Lie conformal algebra with generators {}" " over {}".format(self.gens(), self.base_ring()) + return "The free Bosons Lie conformal algebra with generators {} over {}".format(self.gens(), self.base_ring()) def gram_matrix(self): r""" diff --git a/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py index fbd4b0b0c0f..57302a9d507 100644 --- a/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py @@ -139,7 +139,7 @@ def _repr_(self) -> str: sage: lie_conformal_algebras.FreeFermions(QQ) The free Fermions super Lie conformal algebra with generators (psi, K) over Rational Field """ - return "The free Fermions super Lie conformal algebra " "with generators {} over {}".format(self.gens(), self.base_ring()) + return "The free Fermions super Lie conformal algebra with generators {} over {}".format(self.gens(), self.base_ring()) def gram_matrix(self): r""" diff --git a/src/sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py index f9aca160b63..3f4d103b88c 100644 --- a/src/sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py @@ -44,7 +44,6 @@ # https://www.gnu.org/licenses/ # *************************************************************************** - from sage.algebras.lie_conformal_algebras.lie_conformal_algebra_with_structure_coefs import ( LieConformalAlgebraWithStructureCoefficients, ) @@ -122,5 +121,5 @@ def __init__(self, R, s_coeff, index_set=None, central_elements=None, category=N if weights is None: weights = (1,) * (len(self._generators) - len(self.central_elements())) if len(weights) != (len(self._generators) - len(self.central_elements())): - raise ValueError("weights and (non-central) generator lists " "must be of same length") + raise ValueError("weights and (non-central) generator lists must be of same length") self._weights = weights diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py index 5d125aada20..0e9ec510163 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py @@ -168,7 +168,7 @@ def _standardize_s_coeff(s_coeff, index_set, ce, parity=None): myvals = tuple((k, tuple(v.items())) for k, v in vals.items() if v) if key in sc and sorted(sc[key]) != sorted(myvals): - raise ValueError("two distinct values given for one " "and the same bracket, skew-symmetry" "is not satisfied?") + raise ValueError("two distinct values given for one and the same bracket, skew-symmetryis not satisfied?") if myvals: sc[key] = myvals @@ -199,7 +199,7 @@ def _standardize_s_coeff(s_coeff, index_set, ce, parity=None): myvals = tuple((k, tuple(v.items())) for k, v in vals.items() if v) if key in sc and sorted(sc[key]) != sorted(myvals): - raise ValueError("two distinct values given for one " "and the same bracket. " "Skew-symmetry is not satisfied?") + raise ValueError("two distinct values given for one and the same bracket. Skew-symmetry is not satisfied?") if myvals: sc[key] = myvals return Family(sc) @@ -240,7 +240,7 @@ def __init__(self, R, s_coeff, index_set=None, central_elements=None, category=N try: assert len(parity) == index_set.cardinality() except AssertionError: - raise ValueError("parity should have the same length as the " f"number of generators, got {parity}") + raise ValueError(f"parity should have the same length as the number of generators, got {parity}") s_coeff = LieConformalAlgebraWithStructureCoefficients._standardize_s_coeff(s_coeff, index_set, central_elements, parity) diff --git a/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py index b43e708282b..869d4d76a40 100644 --- a/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py @@ -136,16 +136,16 @@ def __init__(self, R, ngens=None, gram_matrix=None, names=None, index_set=None): from sage.rings.integer_ring import ZZ if not (ngens in ZZ and not ngens % 2): - raise ValueError("ngens needs to be an even positive Integer, " f"got {ngens}") + raise ValueError(f"ngens needs to be an even positive Integer, got {ngens}") if gram_matrix is not None: if ngens is None: ngens = gram_matrix.dimensions()[0] try: assert gram_matrix in MatrixSpace(R, ngens, ngens) except AssertionError: - raise ValueError("the Gram_matrix should be a " "skew-symmetric {0} x {0} matrix, got {1}".format(ngens, gram_matrix)) + raise ValueError("the Gram_matrix should be a skew-symmetric {0} x {0} matrix, got {1}".format(ngens, gram_matrix)) if not gram_matrix.is_skew_symmetric() or gram_matrix.is_singular(): - raise ValueError("the Gram_matrix should be a non degenerate " "skew-symmetric {0} x {0} matrix, got {1}".format(ngens, gram_matrix)) + raise ValueError("the Gram_matrix should be a non degenerate skew-symmetric {0} x {0} matrix, got {1}".format(ngens, gram_matrix)) elif gram_matrix is None: if ngens is None: ngens = 2 diff --git a/src/sage/algebras/quatalg/quaternion_algebra.py b/src/sage/algebras/quatalg/quaternion_algebra.py index d27d54db299..de4ed2e5d7e 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra.py +++ b/src/sage/algebras/quatalg/quaternion_algebra.py @@ -980,7 +980,7 @@ def maximal_order(self, take_shortcuts=True, order_basis=None): True """ if self.base_ring() != QQ: - raise NotImplementedError("maximal order only implemented for " "rational quaternion algebras") + raise NotImplementedError("maximal order only implemented for rational quaternion algebras") d_A = self.discriminant() @@ -1029,7 +1029,7 @@ def maximal_order(self, take_shortcuts=True, order_basis=None): R = self.quaternion_order(order_basis) d_R = R.discriminant() except (TypeError, ValueError): - raise ValueError('order_basis is not a basis of an order of the' ' given quaternion algebra') + raise ValueError('order_basis is not a basis of an order of the given quaternion algebra') # Since Voight's algorithm only works for a starting basis having 1 as # its first vector, we derive such a basis from the given order basis @@ -4279,13 +4279,13 @@ def is_right_equivalent(self, J, B=10, certificate=False) -> bool | tuple: True """ if not isinstance(J, QuaternionFractionalIdeal_rational): - raise TypeError('J must be a fractional ideal' ' in a rational quaternion algebra') + raise TypeError('J must be a fractional ideal in a rational quaternion algebra') if self.right_order() != J.right_order(): raise ValueError('self and J must be right ideals over the same order') if not self.quaternion_algebra().is_definite(): - raise NotImplementedError('equivalence test of ideals not implemented' ' for indefinite quaternion algebras') + raise NotImplementedError('equivalence test of ideals not implemented for indefinite quaternion algebras') # Just test theta series first; if the theta series are # different, the ideals are definitely not equivalent @@ -4339,7 +4339,7 @@ def is_principal(self, certificate=False) -> bool | tuple: True """ if not self.quaternion_algebra().is_definite(): - raise NotImplementedError('principality test not implemented in' ' indefinite quaternion algebras') + raise NotImplementedError('principality test not implemented in indefinite quaternion algebras') c = self.theta_series_vector(2)[1] if not certificate: @@ -4438,7 +4438,7 @@ def __contains__(self, x) -> bool: """ try: x = self.quaternion_algebra()(x) - return self.basis_matrix().transpose().solve_right(vector(x)) in ZZ ** 4 + return self.basis_matrix().transpose().solve_right(vector(x)) in ZZ**4 except (ValueError, TypeError): return False diff --git a/src/sage/all.py b/src/sage/all.py index 73e082cbfe9..2cc92d0e6aa 100644 --- a/src/sage/all.py +++ b/src/sage/all.py @@ -107,7 +107,7 @@ # Ignore a few warnings triggered by pythran 0.12.1 warnings.filterwarnings('ignore', category=DeprecationWarning, message='\n\n `numpy.distutils` is deprecated since NumPy 1.23.0', module='pythran.dist') -warnings.filterwarnings('ignore', category=DeprecationWarning, message='pkg_resources is deprecated as an API|' 'Deprecated call to `pkg_resources.declare_namespace(.*)`', module='pkg_resources|setuptools.sandbox') +warnings.filterwarnings('ignore', category=DeprecationWarning, message='pkg_resources is deprecated as an API|Deprecated call to `pkg_resources.declare_namespace(.*)`', module='pkg_resources|setuptools.sandbox') warnings.filterwarnings('ignore', category=DeprecationWarning, message='msvccompiler is deprecated and slated to be removed', module='distutils.msvccompiler') warnings.filterwarnings('ignore', category=DeprecationWarning, message='The distutils(.sysconfig module| package) is deprecated', module='Cython|distutils|numpy|sage.env|sage.features') diff --git a/src/sage/all_test.py b/src/sage/all_test.py index 63be3bdae57..378541859a8 100644 --- a/src/sage/all_test.py +++ b/src/sage/all_test.py @@ -18,6 +18,6 @@ def test_import_sage_all_in_fresh_interpreter(): text=True, check=False, ) - assert proc.returncode == 0, "Importing 'sage.all' in a fresh interpreter failed.\n" f"Return code: {proc.returncode}\n" f"Stdout:\n{proc.stdout}\n" f"Stderr:\n{proc.stderr}" + assert proc.returncode == 0, f"Importing 'sage.all' in a fresh interpreter failed.\nReturn code: {proc.returncode}\nStdout:\n{proc.stdout}\nStderr:\n{proc.stderr}" assert proc.stderr == "" assert proc.stdout == "" diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index a79dad9ad36..c943db3af78 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -205,7 +205,6 @@ def algebraic_dependency(z, degree, known_bits=None, use_bits=None, known_digits return z.denominator() * x - z.numerator() if isinstance(z.parent(), (RealField, ComplexField)): - log2_10 = math.log(10, 2) prec = z.prec() - 6 @@ -571,9 +570,9 @@ def is_prime(n) -> bool: if R is QQ or not isinstance(R, NumberField): import warnings - s = f'Testing primality in {R}, which is a field, ' 'hence the result will always be False. ' + s = f'Testing primality in {R}, which is a field, hence the result will always be False. ' if R is QQ: - s += 'To test whether n is a prime integer, use ' 'is_prime(ZZ(n)) or ZZ(n).is_prime(). ' + s += 'To test whether n is a prime integer, use is_prime(ZZ(n)) or ZZ(n).is_prime(). ' s += 'Using n.is_prime() instead will silence this warning.' warnings.warn(s) diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index d742937b4c1..b7adf73c9ee 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -682,7 +682,7 @@ def symbolic_sum(expression, v, a, b, algorithm='maxima', hold=False): try: return result._sage_() except AttributeError: - raise AttributeError("Unable to convert SymPy result (={}) into" " Sage".format(result)) + raise AttributeError("Unable to convert SymPy result (={}) into Sage".format(result)) else: raise ValueError("unknown algorithm: %s" % algorithm) @@ -935,7 +935,7 @@ def symbolic_product(expression, v, a, b, algorithm='maxima', hold=False): try: return result._sage_() except AttributeError: - raise AttributeError("Unable to convert SymPy result (={}) into" " Sage".format(result)) + raise AttributeError("Unable to convert SymPy result (={}) into Sage".format(result)) else: raise ValueError("unknown algorithm: %s" % algorithm) @@ -1123,7 +1123,6 @@ def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0): aa = ex.numerical_approx(check_bits) for degree in degree_list: - f = QQ[var](algebraic_dependency(a, degree)) # TODO: use the known_bits parameter? # If indeed we have found a minimal polynomial, # it should be accurate to a much higher precision. @@ -1937,7 +1936,7 @@ def laplace(ex, t, s, algorithm='maxima'): (result, a, cond) = result return result._sage_(), a, cond except AttributeError: - raise AttributeError("Unable to convert SymPy result (={}) into" " Sage".format(result)) + raise AttributeError("Unable to convert SymPy result (={}) into Sage".format(result)) elif 'LaplaceTransform' in format(result): return dummy_laplace(ex, t, s) else: @@ -2123,7 +2122,7 @@ def inverse_laplace(ex, s, t, algorithm='maxima'): except AttributeError: if 'InverseLaplaceTransform' in format(result): return dummy_inverse_laplace(ex, t, s) - raise AttributeError("Unable to convert SymPy result (={}) into" " Sage".format(result)) + raise AttributeError("Unable to convert SymPy result (={}) into Sage".format(result)) elif algorithm == 'giac': from sage.interfaces.giac import giac diff --git a/src/sage/calculus/functional.py b/src/sage/calculus/functional.py index f44d481e9ca..892a8557301 100644 --- a/src/sage/calculus/functional.py +++ b/src/sage/calculus/functional.py @@ -26,6 +26,7 @@ sage: expand((x - a)^3) -a^3 + 3*a^2*x - 3*a*x^2 + x^3 """ + from sage.structure.element import Expression diff --git a/src/sage/calculus/functions.py b/src/sage/calculus/functions.py index 5d354ffde8c..98847944af9 100644 --- a/src/sage/calculus/functions.py +++ b/src/sage/calculus/functions.py @@ -2,6 +2,7 @@ r""" Calculus functions """ + from sage.misc.lazy_import import lazy_import from sage.structure.element import Matrix, Vector, Expression diff --git a/src/sage/categories/additive_magmas.py b/src/sage/categories/additive_magmas.py index 718335e77c0..65009986550 100644 --- a/src/sage/categories/additive_magmas.py +++ b/src/sage/categories/additive_magmas.py @@ -74,7 +74,6 @@ def super_categories(self): return [Sets()] class SubcategoryMethods: - @cached_method def AdditiveAssociative(self): r""" @@ -168,7 +167,6 @@ def AdditiveUnital(self): AdditiveAssociative = LazyImport('sage.categories.additive_semigroups', 'AdditiveSemigroups', at_startup=True) class ParentMethods: - def summation(self, x, y): r""" Return the sum of ``x`` and ``y``. @@ -393,7 +391,6 @@ def addition_table(self, names='letters', elements=None): return OperationTable(self, operation=operator.add, names=names, elements=elements) class ElementMethods: - @abstract_method(optional=True) def _add_(self, right): """ @@ -489,7 +486,6 @@ def _add_(self, right): return self.parent()._cartesian_product_of_elements(x + y for x, y in zip(self.cartesian_factors(), right.cartesian_factors())) class Algebras(AlgebrasCategory): - def extra_super_categories(self): """ EXAMPLES:: @@ -506,7 +502,6 @@ def extra_super_categories(self): return [MagmaticAlgebras(self.base_ring()).WithBasis()] class ParentMethods: - @cached_method def algebra_generators(self): r""" @@ -598,7 +593,6 @@ def extra_super_categories(self): return [Magmas().Commutative()] class AdditiveUnital(CategoryWithAxiom): - def additional_structure(self) -> Self: r""" Return whether ``self`` is a structure category. @@ -617,7 +611,6 @@ def additional_structure(self) -> Self: return self class SubcategoryMethods: - @cached_method def AdditiveInverse(self): r""" @@ -651,7 +644,6 @@ def AdditiveInverse(self): return self._with_axiom("AdditiveInverse") class ParentMethods: - def _test_zero(self, **options): r""" Test that ``self.zero()`` is an element of ``self`` and @@ -871,7 +863,6 @@ def extra_super_categories(self): return [AdditiveMagmas().AdditiveUnital()] class ParentMethods: - @cached_method def zero(self): """ @@ -963,7 +954,6 @@ def zero(self): return self._cartesian_product_of_elements(_.zero() for _ in self.cartesian_factors()) class Algebras(AlgebrasCategory): - def extra_super_categories(self): """ EXAMPLES:: @@ -981,7 +971,6 @@ def extra_super_categories(self): return [Magmas().Unital()] class ParentMethods: - @cached_method def one_basis(self): """ @@ -1007,9 +996,7 @@ def one_basis(self): return self.basis().keys().zero() class WithRealizations(WithRealizationsCategory): - class ParentMethods: - def zero(self): r""" Return the zero of this unital additive magma. diff --git a/src/sage/categories/additive_monoids.py b/src/sage/categories/additive_monoids.py index d50c7ecd2a3..12a9547e929 100644 --- a/src/sage/categories/additive_monoids.py +++ b/src/sage/categories/additive_monoids.py @@ -90,7 +90,6 @@ def sum(self, args): return balanced_sum(args, self.zero(), 20) class Homsets(HomsetsCategory): - def extra_super_categories(self): """ Implement the fact that a homset between two monoids is diff --git a/src/sage/categories/additive_semigroups.py b/src/sage/categories/additive_semigroups.py index 6c9dc2411cf..11cf8f863bd 100644 --- a/src/sage/categories/additive_semigroups.py +++ b/src/sage/categories/additive_semigroups.py @@ -89,7 +89,6 @@ def _test_additive_associativity(self, **options): tester.assertEqual((x + y) + z, x + (y + z)) class Homsets(HomsetsCategory): - def extra_super_categories(self): r""" Implement the fact that a homset between two semigroups is a @@ -106,7 +105,6 @@ def extra_super_categories(self): return [AdditiveSemigroups()] class CartesianProducts(CartesianProductsCategory): - def extra_super_categories(self): """ Implement the fact that a Cartesian product of additive semigroups @@ -124,7 +122,6 @@ def extra_super_categories(self): return [AdditiveSemigroups()] class Algebras(AlgebrasCategory): - def extra_super_categories(self): """ EXAMPLES:: @@ -141,7 +138,6 @@ def extra_super_categories(self): return [Semigroups()] class ParentMethods: - @cached_method def algebra_generators(self): r""" diff --git a/src/sage/categories/affine_weyl_groups.py b/src/sage/categories/affine_weyl_groups.py index 9927d5aa341..d1089f3955b 100644 --- a/src/sage/categories/affine_weyl_groups.py +++ b/src/sage/categories/affine_weyl_groups.py @@ -84,7 +84,6 @@ def _repr_object_names(self): return "affine Weyl groups" class ParentMethods: - @cached_method def special_node(self): """ diff --git a/src/sage/categories/algebra_functor.py b/src/sage/categories/algebra_functor.py index 797c6ecb500..d72d3668050 100644 --- a/src/sage/categories/algebra_functor.py +++ b/src/sage/categories/algebra_functor.py @@ -714,7 +714,6 @@ def __classcall__(cls, category=None, R=None): return cls.category_of(base_category_class(), category) class ParentMethods: - # coalgebra structure def coproduct_on_basis(self, g): diff --git a/src/sage/categories/algebras.py b/src/sage/categories/algebras.py index 1d6f8a2478b..987ef61960a 100644 --- a/src/sage/categories/algebras.py +++ b/src/sage/categories/algebras.py @@ -242,9 +242,7 @@ def _div_(self, y): return self.parent().product(self, ~y) class Quotients(QuotientsCategory): - class ParentMethods: - def algebra_generators(self): r""" Return algebra generators for ``self``. @@ -321,7 +319,6 @@ class ElementMethods: pass class DualObjects(DualObjectsCategory): - def extra_super_categories(self): r""" Return the dual category. diff --git a/src/sage/categories/algebras_with_basis.py b/src/sage/categories/algebras_with_basis.py index 26553b935c9..c58ad36daa7 100644 --- a/src/sage/categories/algebras_with_basis.py +++ b/src/sage/categories/algebras_with_basis.py @@ -129,7 +129,6 @@ def example(self, alphabet=('a', 'b', 'c')): Super = LazyImport('sage.categories.super_algebras_with_basis', 'SuperAlgebrasWithBasis') class ParentMethods: - # For backward compatibility one = UnitalAlgebras.WithBasis.ParentMethods.one @@ -158,7 +157,6 @@ def hochschild_complex(self, M): return HochschildComplex(self, M) class ElementMethods: - def __invert__(self): """ Return the inverse of ``self`` if ``self`` is a multiple of one, diff --git a/src/sage/categories/bialgebras.py b/src/sage/categories/bialgebras.py index be86cb37513..9ce3dbb7f4d 100644 --- a/src/sage/categories/bialgebras.py +++ b/src/sage/categories/bialgebras.py @@ -62,7 +62,6 @@ def additional_structure(self): return None class ElementMethods: - def is_primitive(self): """ Return whether ``self`` is a primitive element. diff --git a/src/sage/categories/bialgebras_with_basis.py b/src/sage/categories/bialgebras_with_basis.py index fdb1dbed4d2..7dc609368cb 100644 --- a/src/sage/categories/bialgebras_with_basis.py +++ b/src/sage/categories/bialgebras_with_basis.py @@ -34,7 +34,6 @@ class BialgebrasWithBasis(CategoryWithAxiom_over_base_ring): """ class ParentMethods: - def convolution_product(self, *maps): r""" Return the convolution product (a map) of the given maps. @@ -148,7 +147,6 @@ def convolution_product(self, *maps): return self.module_morphism(on_basis=onbasis, codomain=self) class ElementMethods: - def convolution_power_of_id(self, n): r""" Compute the `n`-th convolution power of the identity morphism diff --git a/src/sage/categories/category.py b/src/sage/categories/category.py index 3e70c213d7c..2dcd08a06da 100644 --- a/src/sage/categories/category.py +++ b/src/sage/categories/category.py @@ -1471,7 +1471,7 @@ def _test_category(self, **options): for category in self._all_super_categories_proper: if self.is_full_subcategory(category): - tester.assertTrue(any(cat.is_subcategory(category) for cat in self.full_super_categories()), "Every full super category should be a super category" "of some immediate full super category") + tester.assertTrue(any(cat.is_subcategory(category) for cat in self.full_super_categories()), "Every full super category should be a super categoryof some immediate full super category") if self.is_subcategory(Sets()): tester.assertTrue(isinstance(self.parent_class, type)) @@ -2056,7 +2056,7 @@ def _with_axiom_as_tuple(self, axiom): if inspect.isclass(axiom_attribute) and issubclass(axiom_attribute, CategoryWithAxiom): return (axiom_attribute(self),) - warn(("Expecting {}.{} to be a subclass of CategoryWithAxiom to" " implement a category with axiom; got {}; ignoring").format(self.__class__.__base__.__name__, axiom, axiom_attribute)) + warn(("Expecting {}.{} to be a subclass of CategoryWithAxiom to implement a category with axiom; got {}; ignoring").format(self.__class__.__base__.__name__, axiom, axiom_attribute)) # self does not implement this axiom result = (self,) + tuple(cat for category in self._super_categories for cat in category._with_axiom_as_tuple(axiom)) @@ -3237,7 +3237,7 @@ def _without_axioms(self, named=False): for category in self._super_categories: if category._with_axioms(axioms) is self: return category._without_axioms(named=named) - raise ValueError("This join category isn't built by adding axioms" " to a single category") + raise ValueError("This join category isn't built by adding axioms to a single category") def _cmp_key(self): """ diff --git a/src/sage/categories/category_types.py b/src/sage/categories/category_types.py index 744bf503e04..0a8fa3a6ab4 100644 --- a/src/sage/categories/category_types.py +++ b/src/sage/categories/category_types.py @@ -207,7 +207,7 @@ def _test_category_over_bases(self, **options): from .schemes import Schemes for cat in self.super_categories(): - tester.assertTrue(isinstance(cat, (Category_singleton, Category_over_base, CategoryWithAxiom_over_base_ring, Bimodules, Schemes)), "The super categories of a category over base should" " be a category over base (or the related Bimodules)" " or a singleton category") + tester.assertTrue(isinstance(cat, (Category_singleton, Category_over_base, CategoryWithAxiom_over_base_ring, Bimodules, Schemes)), "The super categories of a category over base should be a category over base (or the related Bimodules) or a singleton category") def _make_named_class_key(self, name): r""" @@ -576,7 +576,6 @@ class Category_module(AbelianCategory, Category_over_base_ring): class Category_ideal(Category_in_ambient): - @classmethod def an_instance(cls): """ diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index 428bf2a452c..a5bc4354889 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -1832,9 +1832,7 @@ def base_category_class_and_axiom(cls): raise TypeError( """Could not retrieve the base category class and axiom for {}. Please specify it explicitly using the attribute _base_category_class_and_axiom. -See CategoryWithAxiom for details.""".format( - cls - ) +See CategoryWithAxiom for details.""".format(cls) ) @@ -2521,7 +2519,6 @@ def axioms(self): class CategoryWithAxiom_over_base_ring(CategoryWithAxiom, Category_over_base_ring): - def __init__(self, base_category): """ TESTS:: diff --git a/src/sage/categories/classical_crystals.py b/src/sage/categories/classical_crystals.py index b0ca7ec0cac..97e492d0f50 100644 --- a/src/sage/categories/classical_crystals.py +++ b/src/sage/categories/classical_crystals.py @@ -111,7 +111,6 @@ def additional_structure(self): return None class ParentMethods: - def demazure_character(self, w, f=None): r""" Return the Demazure character associated to ``w``. @@ -424,7 +423,6 @@ def cardinality(self): return sum(self.weight_lattice_realization().weyl_dimension(x.weight()) for x in self.highest_weight_vectors()) class ElementMethods: - def lusztig_involution(self): r""" Return the Lusztig involution on the classical highest weight diff --git a/src/sage/categories/coalgebras.py b/src/sage/categories/coalgebras.py index 14400669b67..dbf8d2ec074 100644 --- a/src/sage/categories/coalgebras.py +++ b/src/sage/categories/coalgebras.py @@ -209,7 +209,6 @@ class ElementMethods: pass class DualObjects(DualObjectsCategory): - def extra_super_categories(self): r""" Return the dual category. @@ -293,9 +292,7 @@ class Filtered(FilteredModulesCategory): """ class WithRealizations(WithRealizationsCategory): - class ParentMethods: - def coproduct(self, x): r""" Return the coproduct of ``x``. @@ -343,9 +340,7 @@ def counit(self, x): return self.a_realization()(x).counit() class Realizations(RealizationsCategory): - class ParentMethods: - def coproduct_by_coercion(self, x): r""" Return the coproduct by coercion if ``coproduct_by_basis`` diff --git a/src/sage/categories/coalgebras_with_basis.py b/src/sage/categories/coalgebras_with_basis.py index 5cd7d60ef86..5374606dd84 100644 --- a/src/sage/categories/coalgebras_with_basis.py +++ b/src/sage/categories/coalgebras_with_basis.py @@ -46,7 +46,6 @@ class Filtered(FilteredModulesCategory): """ class ParentMethods: - @abstract_method(optional=True) def coproduct_on_basis(self, i): """ diff --git a/src/sage/categories/complete_discrete_valuation.py b/src/sage/categories/complete_discrete_valuation.py index 5e7d97cea2a..15c4a904f9b 100644 --- a/src/sage/categories/complete_discrete_valuation.py +++ b/src/sage/categories/complete_discrete_valuation.py @@ -9,7 +9,6 @@ # http://www.gnu.org/licenses/ # ************************************************************************** - from typing import Self from sage.categories.category_singleton import Category_singleton diff --git a/src/sage/categories/complex_reflection_groups.py b/src/sage/categories/complex_reflection_groups.py index 90ddedfc2e6..36019c4cef1 100644 --- a/src/sage/categories/complex_reflection_groups.py +++ b/src/sage/categories/complex_reflection_groups.py @@ -125,7 +125,6 @@ def example(self): return ColoredPermutations(5, 3) class ParentMethods: - @cached_method def rank(self): r""" diff --git a/src/sage/categories/coxeter_group_algebras.py b/src/sage/categories/coxeter_group_algebras.py index 9802f46426e..5d6e0913b18 100644 --- a/src/sage/categories/coxeter_group_algebras.py +++ b/src/sage/categories/coxeter_group_algebras.py @@ -2,15 +2,14 @@ r""" Coxeter Group Algebras """ + import functools from sage.misc.cachefunc import cached_method from sage.categories.algebra_functor import AlgebrasCategory class CoxeterGroupAlgebras(AlgebrasCategory): - class ParentMethods: - def demazure_lusztig_operator_on_basis(self, w, i, q1, q2, side='right'): r""" Return the result of applying the `i`-th Demazure Lusztig diff --git a/src/sage/categories/crystals.py b/src/sage/categories/crystals.py index 7ebb4283059..97ce4091f99 100644 --- a/src/sage/categories/crystals.py +++ b/src/sage/categories/crystals.py @@ -234,7 +234,6 @@ def is_strict(self) -> bool: return True class ParentMethods: - def an_element(self): """ Return an element of ``self``. @@ -883,7 +882,7 @@ def digraph(self, subset=None, index_set=None): # Parse optional arguments if subset is None: if self not in Crystals().Finite(): - raise NotImplementedError("crystals not known to be finite" " must specify the subset") + raise NotImplementedError("crystals not known to be finite must specify the subset") subset = self if index_set is None: index_set = self.index_set() @@ -1313,7 +1312,6 @@ def is_connected(self) -> bool: return self.number_of_connected_components() == 1 class ElementMethods: - @cached_method def index_set(self): """ diff --git a/src/sage/categories/discrete_valuation.py b/src/sage/categories/discrete_valuation.py index 539fc7664c9..6c0dcdf7fed 100644 --- a/src/sage/categories/discrete_valuation.py +++ b/src/sage/categories/discrete_valuation.py @@ -9,7 +9,6 @@ # http://www.gnu.org/licenses/ # ************************************************************************** - from sage.misc.abstract_method import abstract_method from sage.categories.category_singleton import Category_singleton from sage.categories.euclidean_domains import EuclideanDomains diff --git a/src/sage/categories/distributive_magmas_and_additive_magmas.py b/src/sage/categories/distributive_magmas_and_additive_magmas.py index 31c9857ae3f..2e1795b0e07 100644 --- a/src/sage/categories/distributive_magmas_and_additive_magmas.py +++ b/src/sage/categories/distributive_magmas_and_additive_magmas.py @@ -47,7 +47,6 @@ class Associative(CategoryWithAxiom): Unital = LazyImport('sage.categories.semirings', 'Semirings', at_startup=True) class ParentMethods: - def _test_distributivity(self, **options): r""" Test the distributivity of `*` on `+` on (not necessarily diff --git a/src/sage/categories/drinfeld_modules.py b/src/sage/categories/drinfeld_modules.py index d00e83cc954..d34f4786176 100644 --- a/src/sage/categories/drinfeld_modules.py +++ b/src/sage/categories/drinfeld_modules.py @@ -237,7 +237,7 @@ def __init__(self, base_morphism, name='τ'): raise TypeError('input must be a field') # Check domain of base morphism is Fq[T] if not isinstance(function_ring, PolynomialRing_generic): - raise NotImplementedError('function ring must be a polynomial ' 'ring') + raise NotImplementedError('function ring must be a polynomial ring') function_ring_base = function_ring.base_ring() if not function_ring_base.is_field() or not function_ring_base.is_finite(): raise TypeError('function ring base must be a finite field') @@ -285,7 +285,7 @@ def _latex_(self): sage: latex(C) \text{Category{ }of{ }Drinfeld{ }modules{ }over{ }\Bold{F}_{11^{4}} """ - return f'\\text{{Category{{ }}of{{ }}Drinfeld{{ }}modules{{ }}' f'over{{ }}{latex(self._base_field)}' + return f'\\text{{Category{{ }}of{{ }}Drinfeld{{ }}modules{{ }}over{{ }}{latex(self._base_field)}' def _repr_(self): r""" @@ -432,7 +432,7 @@ def characteristic(self): 0 """ if self._characteristic is None: - raise NotImplementedError('function ring characteristic not ' 'implemented in this case') + raise NotImplementedError('function ring characteristic not implemented in this case') return self._characteristic def constant_coefficient(self): @@ -505,7 +505,7 @@ def object(self, gen): gen = self._ore_polring(gen) T = self._function_ring.gen() if gen[0] != self._base_morphism(T): - raise ValueError('constant coefficient must equal that of the ' 'category') + raise ValueError('constant coefficient must equal that of the category') return DrinfeldModule(self._function_ring, gen) def ore_polring(self): @@ -578,7 +578,6 @@ def super_categories(self): return [Objects()] class ParentMethods: - def A_field(self): r""" Return the underlying `A`-field of this Drinfeld module, diff --git a/src/sage/categories/dual.py b/src/sage/categories/dual.py index cbf7ca4d872..9c8ad5a6fbb 100644 --- a/src/sage/categories/dual.py +++ b/src/sage/categories/dual.py @@ -29,7 +29,6 @@ class DualFunctor(CovariantFunctorialConstruction): class DualObjectsCategory(CovariantConstructionCategory): - _functor_category = "DualObjects" def _repr_object_names(self): diff --git a/src/sage/categories/enumerated_sets.py b/src/sage/categories/enumerated_sets.py index 4f004af1d01..da5b334f3cf 100644 --- a/src/sage/categories/enumerated_sets.py +++ b/src/sage/categories/enumerated_sets.py @@ -157,7 +157,6 @@ def _call_(self, X): raise NotImplementedError class ParentMethods: - def __iter__(self): """ An iterator for the enumerated set. @@ -1113,7 +1112,6 @@ def _test_enumerated_set_iter_list(self, **options): tester.assertEqual(i, len(ls)) class ElementMethods: - def rank(self): """ Return the rank of ``self`` in its parent. @@ -1135,9 +1133,7 @@ def rank(self): Infinite = LazyImport('sage.categories.infinite_enumerated_sets', 'InfiniteEnumeratedSets', at_startup=True) class CartesianProducts(CartesianProductsCategory): - class ParentMethods: - def first(self): r""" Return the first element. diff --git a/src/sage/categories/examples/crystals.py b/src/sage/categories/examples/crystals.py index 3bb126741ec..92e1b0ea5c8 100644 --- a/src/sage/categories/examples/crystals.py +++ b/src/sage/categories/examples/crystals.py @@ -2,6 +2,7 @@ r""" Example of a crystal """ + # **************************************************************************** # Copyright (C) 2010 Anne Schilling # @@ -125,7 +126,6 @@ def _repr_(self): _an_element_ = EnumeratedSets.ParentMethods._an_element_ class Element(ElementWrapper): - def e(self, i): r""" Return the action of `e_i` on ``self``. diff --git a/src/sage/categories/examples/finite_coxeter_groups.py b/src/sage/categories/examples/finite_coxeter_groups.py index 73daede06f0..6474f27bb41 100644 --- a/src/sage/categories/examples/finite_coxeter_groups.py +++ b/src/sage/categories/examples/finite_coxeter_groups.py @@ -2,6 +2,7 @@ r""" Examples of finite Coxeter groups """ + # **************************************************************************** # Copyright (C) 2008 Nicolas M. Thiery # Copyright (C) 2009 Nicolas Borie diff --git a/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py index b7fca33203b..283a667a1d2 100644 --- a/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_algebras_with_basis.py @@ -49,7 +49,7 @@ def _repr_(self): the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over Rational Field """ - return "An example of a finite dimensional algebra with basis: " "the path algebra of the Kronecker quiver " "(containing the arrows a:x->y and b:x->y) over %s " % (self.base_ring()) + return "An example of a finite dimensional algebra with basis: the path algebra of the Kronecker quiver (containing the arrows a:x->y and b:x->y) over %s " % (self.base_ring()) def one(self): r""" diff --git a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py index 76987f45113..ccee29a4cf7 100644 --- a/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py @@ -109,7 +109,7 @@ def _repr_(self): An example of a finite dimensional Lie algebra with basis: the 3-dimensional abelian Lie algebra over Rational Field """ - ret = "An example of a finite dimensional Lie algebra with basis:" " the {}-dimensional abelian Lie algebra over {}".format(self.dimension(), self.base_ring()) + ret = "An example of a finite dimensional Lie algebra with basis: the {}-dimensional abelian Lie algebra over {}".format(self.dimension(), self.base_ring()) B = self._M.basis_matrix() if not B.is_one(): ret += " with basis matrix:\n{!r}".format(B) diff --git a/src/sage/categories/examples/finite_enumerated_sets.py b/src/sage/categories/examples/finite_enumerated_sets.py index 427f8b83f15..a5e9541de26 100644 --- a/src/sage/categories/examples/finite_enumerated_sets.py +++ b/src/sage/categories/examples/finite_enumerated_sets.py @@ -113,7 +113,6 @@ def __iter__(self): class IsomorphicObjectOfFiniteEnumeratedSet(UniqueRepresentation, Parent): - def __init__(self, ambient=Example()): """ TESTS:: diff --git a/src/sage/categories/examples/finite_weyl_groups.py b/src/sage/categories/examples/finite_weyl_groups.py index 2d41c2e78dd..14c74c972be 100644 --- a/src/sage/categories/examples/finite_weyl_groups.py +++ b/src/sage/categories/examples/finite_weyl_groups.py @@ -172,7 +172,6 @@ def degrees(self) -> tuple[Integer, ...]: return tuple(Integer(i) for i in range(2, self.n + 1)) class Element(ElementWrapper): - def has_right_descent(self, i) -> bool: """ Implement :meth:`CoxeterGroups.ElementMethods.has_right_descent`. diff --git a/src/sage/categories/examples/lie_algebras.py b/src/sage/categories/examples/lie_algebras.py index dfd7a9e466f..449ec334719 100644 --- a/src/sage/categories/examples/lie_algebras.py +++ b/src/sage/categories/examples/lie_algebras.py @@ -104,7 +104,7 @@ def _repr_(self): Symmetric group algebra of order 3 over Rational Field generated by ([2, 1, 3], [2, 3, 1]) """ - return "An example of a Lie algebra: the Lie algebra from the" " associative algebra {} generated by {}".format(self._A, self._gens) + return "An example of a Lie algebra: the Lie algebra from the associative algebra {} generated by {}".format(self._A, self._gens) def _element_constructor_(self, value): """ diff --git a/src/sage/categories/examples/lie_algebras_with_basis.py b/src/sage/categories/examples/lie_algebras_with_basis.py index 8bb63b21b82..c669de99e44 100644 --- a/src/sage/categories/examples/lie_algebras_with_basis.py +++ b/src/sage/categories/examples/lie_algebras_with_basis.py @@ -55,7 +55,7 @@ def _repr_(self): An example of a Lie algebra: the abelian Lie algebra on the generators indexed by Partitions over Rational Field """ - return "An example of a Lie algebra: the abelian Lie algebra on the" " generators indexed by {} over {}".format(self.basis().keys(), self.base_ring()) + return "An example of a Lie algebra: the abelian Lie algebra on the generators indexed by {} over {}".format(self.basis().keys(), self.base_ring()) def lie_algebra_generators(self): """ diff --git a/src/sage/categories/examples/magmas.py b/src/sage/categories/examples/magmas.py index ae5d4a55a2c..9e14caf5744 100644 --- a/src/sage/categories/examples/magmas.py +++ b/src/sage/categories/examples/magmas.py @@ -70,7 +70,7 @@ def __init__(self, alphabet=('a', 'b', 'c', 'd')) -> None: True """ if any('(' in x or ')' in x or '*' in x for x in alphabet): - raise ValueError("alphabet must not contain characters " "'(', ')' or '*'") + raise ValueError("alphabet must not contain characters '(', ')' or '*'") if not alphabet: raise NotImplementedError("free magma must have at least one generator") diff --git a/src/sage/categories/examples/posets.py b/src/sage/categories/examples/posets.py index ab9efd06697..9eca33c6b71 100644 --- a/src/sage/categories/examples/posets.py +++ b/src/sage/categories/examples/posets.py @@ -107,7 +107,6 @@ def an_element(self): return self(Set([1, 4, 6])) class Element(ElementWrapper): - wrapped_class = Set_object_enumerated diff --git a/src/sage/categories/examples/with_realizations.py b/src/sage/categories/examples/with_realizations.py index 3ba54f1e2f6..ad5632cfea5 100644 --- a/src/sage/categories/examples/with_realizations.py +++ b/src/sage/categories/examples/with_realizations.py @@ -298,7 +298,6 @@ def super_categories(self): return [A.Realizations(), category.Realizations().WithBasis()] class ParentMethods: - def from_set(self, *args): r""" Construct the monomial indexed by the set containing the diff --git a/src/sage/categories/facade_sets.py b/src/sage/categories/facade_sets.py index 9cb41f5ac34..57c611c9f0a 100644 --- a/src/sage/categories/facade_sets.py +++ b/src/sage/categories/facade_sets.py @@ -43,7 +43,6 @@ def example(self, choice='subset'): raise TypeError("choice should be 'union' or 'subset'") class ParentMethods: - def _element_constructor_(self, element): """ Coerce ``element`` into ``self``. diff --git a/src/sage/categories/filtered_algebras_with_basis.py b/src/sage/categories/filtered_algebras_with_basis.py index e10c1101e91..4cf7ddcbc36 100644 --- a/src/sage/categories/filtered_algebras_with_basis.py +++ b/src/sage/categories/filtered_algebras_with_basis.py @@ -204,7 +204,7 @@ def projection(self, i): base_zero = self.base_ring().zero() base_one = self.base_ring().one() grA = self.graded_algebra() - proj = lambda x: (base_one if self.degree_on_basis(x) == i else base_zero) + proj = lambda x: base_one if self.degree_on_basis(x) == i else base_zero return self.module_morphism(diagonal=proj, codomain=grA) def induced_graded_map(self, other, f): diff --git a/src/sage/categories/filtered_modules.py b/src/sage/categories/filtered_modules.py index 7b5d296a3d3..22b2fb20399 100644 --- a/src/sage/categories/filtered_modules.py +++ b/src/sage/categories/filtered_modules.py @@ -179,7 +179,6 @@ def extra_super_categories(self): return [] class SubcategoryMethods: - @cached_method def Connected(self): r""" diff --git a/src/sage/categories/filtered_modules_with_basis.py b/src/sage/categories/filtered_modules_with_basis.py index c344acf8e17..cd4047a95e5 100644 --- a/src/sage/categories/filtered_modules_with_basis.py +++ b/src/sage/categories/filtered_modules_with_basis.py @@ -241,7 +241,7 @@ def homogeneous_component(self, d): from sage.categories.filtered_algebras import FilteredAlgebras if self.base_ring() in FilteredAlgebras: - raise NotImplementedError("this is only a natural module over" " the degree 0 component of the filtered" " algebra and coordinate rings are not" " yet implemented for submodules") + raise NotImplementedError("this is only a natural module over the degree 0 component of the filtered algebra and coordinate rings are not yet implemented for submodules") category = ModulesWithBasis(self.category().base_ring()) M = self.submodule(self.homogeneous_component_basis(d), category=category, already_echelonized=True) M.rename("Degree {} homogeneous component of {}".format(d, self)) @@ -444,7 +444,7 @@ def projection(self, i): base_zero = self.base_ring().zero() base_one = self.base_ring().one() grA = self.graded_algebra() - proj = lambda x: (base_one if self.degree_on_basis(x) == i else base_zero) + proj = lambda x: base_one if self.degree_on_basis(x) == i else base_zero return self.module_morphism(diagonal=proj, codomain=grA) def induced_graded_map(self, other, f): @@ -709,7 +709,6 @@ def on_basis(m): # ass one day. What do you think? class ElementMethods: - def is_homogeneous(self): r""" Return whether the element ``self`` is homogeneous. diff --git a/src/sage/categories/finite_complex_reflection_groups.py b/src/sage/categories/finite_complex_reflection_groups.py index 83b2fe01565..fcb52de9f89 100644 --- a/src/sage/categories/finite_complex_reflection_groups.py +++ b/src/sage/categories/finite_complex_reflection_groups.py @@ -85,7 +85,6 @@ def example(self): return ReflectionGroup((1, 1, 3), (2, 1, 2)) class SubcategoryMethods: - @cached_method def WellGenerated(self): r""" @@ -639,7 +638,6 @@ def milnor_fiber_poset(self): return Poset(data) class ElementMethods: - @abstract_method(optional=True) def to_matrix(self): r""" @@ -760,7 +758,6 @@ def reflection_length(self, in_unitary_group=False): return len(self.reduced_word_in_reflections()) class Irreducible(CategoryWithAxiom): - def example(self): r""" Return an example of an irreducible complex reflection group. @@ -1099,7 +1096,6 @@ def absolute_poset(self, in_unitary_group=False): return self.noncrossing_partition_lattice(L=tuple(self), in_unitary_group=in_unitary_group) class WellGenerated(CategoryWithAxiom): - def example(self): r""" Return an example of a well-generated complex reflection group. diff --git a/src/sage/categories/finite_coxeter_groups.py b/src/sage/categories/finite_coxeter_groups.py index 62c75a9cd56..06525c19ad7 100644 --- a/src/sage/categories/finite_coxeter_groups.py +++ b/src/sage/categories/finite_coxeter_groups.py @@ -575,7 +575,7 @@ def m_cambrian_lattice(self, c, m=1, on_roots=False): if on_roots: if not hasattr(self.long_element(), "reflection_to_root"): - raise ValueError("The parameter 'on_root=True' needs " "the ElementMethod 'reflection_to_root'") + raise ValueError("The parameter 'on_root=True' needs the ElementMethod 'reflection_to_root'") inv_woc = [t.reflection_to_root() for t in self.inversion_sequence(sorting_word)] S = [s.reflection_to_root() for s in self.simple_reflections()] @@ -906,7 +906,6 @@ def coxeter_complex(self): return SimplicialComplex(result) class ElementMethods: - def absolute_length(self): """ Return the absolute length of ``self``. diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 76be4fcff60..251a22efe9c 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -64,7 +64,6 @@ class FiniteDimensionalAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): """ class ParentMethods: - @cached_method def radical_basis(self): r""" @@ -1398,7 +1397,6 @@ def is_commutative(self) -> bool: return all(b * bp == bp * b for i, b in enumerate(B) for bp in B[i + 1 :]) class ElementMethods: - def to_matrix(self, base_ring=None, action=operator.mul, side='left'): """ Return the matrix of the action of ``self`` on the algebra. diff --git a/src/sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py b/src/sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py index 4aae1508e18..e3d7727e071 100644 --- a/src/sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py @@ -83,7 +83,7 @@ def _test_grading(self, **options): continue Zdeg = Z.degree() tester.assertEqual(Zdeg, i + j, msg="Lie bracket [%s, %s] has degree %s, not degree %s " % (X, Y, Zdeg, i + j)) - tester.assertIn(Z.to_vector(), self.homogeneous_component_as_submodule(i + j), msg="Lie bracket [%s, %s] is not in the " "homogeneous component of degree %s" % (X, Y, i + j)) + tester.assertIn(Z.to_vector(), self.homogeneous_component_as_submodule(i + j), msg="Lie bracket [%s, %s] is not in the homogeneous component of degree %s" % (X, Y, i + j)) @cached_method def homogeneous_component_as_submodule(self, d): diff --git a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py index 3a209589711..418748170aa 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -1093,7 +1093,7 @@ def is_ideal(self, A): if A == self: return True if A not in LieAlgebras(self.base_ring()).FiniteDimensional().WithBasis(): - raise NotImplementedError("A must be a finite dimensional" " Lie algebra with basis") + raise NotImplementedError("A must be a finite dimensional Lie algebra with basis") from sage.matrix.constructor import matrix diff --git a/src/sage/categories/finite_dimensional_modules_with_basis.py b/src/sage/categories/finite_dimensional_modules_with_basis.py index 4a20efacf7d..baa5c0b682a 100644 --- a/src/sage/categories/finite_dimensional_modules_with_basis.py +++ b/src/sage/categories/finite_dimensional_modules_with_basis.py @@ -39,7 +39,6 @@ class FiniteDimensionalModulesWithBasis(CategoryWithAxiom_over_base_ring): """ class ParentMethods: - def gens(self) -> tuple: """ Return the generators of ``self``. @@ -875,11 +874,8 @@ def image(self): return C.submodule(self.image_basis(), already_echelonized=True, category=self.category_for()) class Homsets(HomsetsCategory): - class Endset(CategoryWithAxiom): - class ElementMethods: - @lazy_attribute def characteristic_polynomial(self): r""" @@ -1035,7 +1031,6 @@ def trace(self): return self.matrix().trace class TensorProducts(TensorProductsCategory): - def extra_super_categories(self): """ Implement the fact that a (finite) tensor product of diff --git a/src/sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py b/src/sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py index a1ec817166d..1ec1b46c5e6 100644 --- a/src/sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py @@ -16,7 +16,6 @@ # http://www.gnu.org/licenses/ # ***************************************************************************** - from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from sage.categories.lie_algebras import LieAlgebras @@ -49,7 +48,6 @@ class FiniteDimensionalNilpotentLieAlgebrasWithBasis(CategoryWithAxiom_over_base _base_category_class_and_axiom = (LieAlgebras.FiniteDimensional.WithBasis, "Nilpotent") class ParentMethods: - def _test_nilpotency(self, **options): r""" Test that ``self`` is nilpotent and has the correct step. @@ -85,7 +83,7 @@ def _test_nilpotency(self, **options): tester.assertEqual(lcs[-1].dimension(), 0, msg="final term of lower central series is nonzero") step = self.step() - tester.assertEqual(len(lcs) - 1, step, msg="claimed nilpotency step %d does not match the " "actual nilpotency step %d" % (step, len(lcs) - 1)) + tester.assertEqual(len(lcs) - 1, step, msg="claimed nilpotency step %d does not match the actual nilpotency step %d" % (step, len(lcs) - 1)) def lie_group(self, name='G', **kwds): r""" diff --git a/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py b/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py index 012b486400e..2e81459b9cd 100644 --- a/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_semisimple_algebras_with_basis.py @@ -115,9 +115,7 @@ def central_orthogonal_idempotents(self): return tuple([x.lift() for x in self.center().central_orthogonal_idempotents()]) class Commutative(CategoryWithAxiom_over_base_ring): - class ParentMethods: - @cached_method def _orthogonal_decomposition(self, generators=None): r""" diff --git a/src/sage/categories/finite_enumerated_sets.py b/src/sage/categories/finite_enumerated_sets.py index 5062d5d02d4..20149bf2651 100644 --- a/src/sage/categories/finite_enumerated_sets.py +++ b/src/sage/categories/finite_enumerated_sets.py @@ -81,7 +81,6 @@ def _call_(self, X): return EnumeratedSets()._call_(X) class ParentMethods: - def __len__(self): """ Return the number of elements of ``self``. @@ -544,7 +543,7 @@ def _test_random(self, random_seed=123332938836894739865, **options): tester.assertEqual(elements[:10], [self.random_element() for _ in range(10)], f"random_element of {self} produced different elements with the same seed {random_seed}") E = float(N) / float(n) chi_2 = sum(float(o) ** 2 for o in Counter(elements).values()) / E - float(N) - tester.assertLessEqual(chi_2, critical, f"assuming random_element of {self} follows a uniform distribution, this outcome would only occur with probability {1-T.cum_distribution_function(chi_2)}") + tester.assertLessEqual(chi_2, critical, f"assuming random_element of {self} follows a uniform distribution, this outcome would only occur with probability {1 - T.cum_distribution_function(chi_2)}") def _test_rank(self, **options): r""" @@ -660,7 +659,6 @@ def _test_enumerated_set_iter_cardinality(self, **options): tester.assertEqual(card, self._cardinality_from_iterator()) class CartesianProducts(CartesianProductsCategory): - def extra_super_categories(self): """ A Cartesian product of finite enumerated sets is a finite @@ -819,7 +817,6 @@ def unrank(self, i): return self._cartesian_product_of_elements(elt) class IsomorphicObjects(IsomorphicObjectsCategory): - def example(self): """ Return an example of isomorphic object of a finite @@ -836,7 +833,6 @@ def example(self): return IsomorphicObjectOfFiniteEnumeratedSet() class ParentMethods: - def cardinality(self): r""" Return the cardinality of ``self`` which is the same diff --git a/src/sage/categories/finite_groups.py b/src/sage/categories/finite_groups.py index 55c34d0c2a4..f530f7463c5 100644 --- a/src/sage/categories/finite_groups.py +++ b/src/sage/categories/finite_groups.py @@ -46,7 +46,6 @@ def example(self): return GL(2, 3) class ParentMethods: - def semigroup_generators(self): """ Return semigroup generators for ``self``. diff --git a/src/sage/categories/finite_lattice_posets.py b/src/sage/categories/finite_lattice_posets.py index 5d9d0b7c85a..c2de3879526 100644 --- a/src/sage/categories/finite_lattice_posets.py +++ b/src/sage/categories/finite_lattice_posets.py @@ -58,7 +58,6 @@ def extra_super_categories(self): return [LatticePosets().Bounded()] class ParentMethods: - def join_irreducibles(self): r""" Return the join-irreducible elements of this finite lattice. diff --git a/src/sage/categories/finite_monoids.py b/src/sage/categories/finite_monoids.py index e2b8209de37..4f35d17a7ee 100644 --- a/src/sage/categories/finite_monoids.py +++ b/src/sage/categories/finite_monoids.py @@ -38,7 +38,6 @@ class FiniteMonoids(CategoryWithAxiom): """ class ParentMethods: - def nerve(self): r""" The nerve (classifying space) of this monoid. diff --git a/src/sage/categories/finite_posets.py b/src/sage/categories/finite_posets.py index f4e0a080a6c..0e99f31b47f 100644 --- a/src/sage/categories/finite_posets.py +++ b/src/sage/categories/finite_posets.py @@ -46,7 +46,6 @@ class FinitePosets(CategoryWithAxiom): """ class ParentMethods: - ########################################################################## # Properties of this poset diff --git a/src/sage/categories/finite_sets.py b/src/sage/categories/finite_sets.py index a2bab901d38..01d0cfd3eae 100644 --- a/src/sage/categories/finite_sets.py +++ b/src/sage/categories/finite_sets.py @@ -40,7 +40,6 @@ class FiniteSets(CategoryWithAxiom): """ class SubcategoryMethods: - def Infinite(self): """ Incompatible axiom. @@ -56,7 +55,6 @@ def Infinite(self): raise TypeError("incompatible axioms: finite and infinite") class ParentMethods: - def is_finite(self): """ Return ``True`` since ``self`` is finite. @@ -70,7 +68,6 @@ def is_finite(self): return True class Subquotients(SubquotientsCategory): - def extra_super_categories(self): r""" EXAMPLES:: @@ -91,7 +88,6 @@ def extra_super_categories(self): return [FiniteSets()] class Algebras(AlgebrasCategory): - def extra_super_categories(self): r""" EXAMPLES:: diff --git a/src/sage/categories/finitely_generated_lie_conformal_algebras.py b/src/sage/categories/finitely_generated_lie_conformal_algebras.py index 3ed7d828e4a..e6b7c02dea1 100644 --- a/src/sage/categories/finitely_generated_lie_conformal_algebras.py +++ b/src/sage/categories/finitely_generated_lie_conformal_algebras.py @@ -35,7 +35,6 @@ class FinitelyGeneratedLieConformalAlgebras(CategoryWithAxiom_over_base_ring): _base_category_class_and_axiom = (LieConformalAlgebras, "FinitelyGeneratedAsLambdaBracketAlgebra") class ParentMethods: - def some_elements(self): """ Some elements of this Lie conformal algebra. diff --git a/src/sage/categories/finitely_generated_magmas.py b/src/sage/categories/finitely_generated_magmas.py index 5ff45a6b2e2..b247356e29b 100644 --- a/src/sage/categories/finitely_generated_magmas.py +++ b/src/sage/categories/finitely_generated_magmas.py @@ -38,7 +38,6 @@ class FinitelyGeneratedMagmas(CategoryWithAxiom): _base_category_class_and_axiom = (Magmas, "FinitelyGeneratedAsMagma") class ParentMethods: - @abstract_method def magma_generators(self): """ diff --git a/src/sage/categories/finitely_generated_semigroups.py b/src/sage/categories/finitely_generated_semigroups.py index 8f88149cfdb..cc392b2a827 100644 --- a/src/sage/categories/finitely_generated_semigroups.py +++ b/src/sage/categories/finitely_generated_semigroups.py @@ -72,7 +72,6 @@ def example(self): return Semigroups().example("free") class ParentMethods: - @abstract_method def semigroup_generators(self): r""" @@ -190,7 +189,6 @@ def ideal(self, gens, side='twosided'): return RecursivelyEnumeratedSet(gens, self.succ_generators(side=side)) class Finite(CategoryWithAxiom): - class ParentMethods: def some_elements(self): r""" diff --git a/src/sage/categories/graded_modules_with_basis.py b/src/sage/categories/graded_modules_with_basis.py index 0a63a8bbfe4..082865ad782 100644 --- a/src/sage/categories/graded_modules_with_basis.py +++ b/src/sage/categories/graded_modules_with_basis.py @@ -65,7 +65,7 @@ def degree_negation(self, element): """ base_one = self.base_ring().one() base_minusone = -base_one - diag = lambda x: (base_one if self.degree_on_basis(x) % 2 == 0 else base_minusone) + diag = lambda x: base_one if self.degree_on_basis(x) % 2 == 0 else base_minusone return self.sum_of_terms([(key, diag(key) * value) for key, value in element.monomial_coefficients(copy=False).items()]) def submodule(self, gens, check=True, already_echelonized=False, unitriangular=False, support_order=None, category=None, *args, **opts): diff --git a/src/sage/categories/group_algebras.py b/src/sage/categories/group_algebras.py index 5084ecda4c2..6b3723aadce 100644 --- a/src/sage/categories/group_algebras.py +++ b/src/sage/categories/group_algebras.py @@ -367,7 +367,6 @@ def is_integral_domain(self, proof=True): # or "is identical to a prime field". class ElementMethods: - def central_form(self): r""" Return ``self`` expressed in the canonical basis of the center diff --git a/src/sage/categories/groups.py b/src/sage/categories/groups.py index d54df15f086..17cffa3207b 100644 --- a/src/sage/categories/groups.py +++ b/src/sage/categories/groups.py @@ -96,7 +96,6 @@ def free(index_set=None, names=None, **kwds): return IndexedFreeGroup(index_set, **kwds) class ParentMethods: - def group_generators(self): """ Return group generators for ``self``. diff --git a/src/sage/categories/hecke_modules.py b/src/sage/categories/hecke_modules.py index a134f6f4ec6..10d7060f4ee 100644 --- a/src/sage/categories/hecke_modules.py +++ b/src/sage/categories/hecke_modules.py @@ -103,7 +103,6 @@ def _repr_object_names(self): return "Hecke modules over {}".format(self.base()) class ParentMethods: - def _Hom_(self, Y, category): r""" Return the homset from ``self`` to ``Y`` in the category ``category``. diff --git a/src/sage/categories/highest_weight_crystals.py b/src/sage/categories/highest_weight_crystals.py index d2bdbced4c9..5d94cc38442 100644 --- a/src/sage/categories/highest_weight_crystals.py +++ b/src/sage/categories/highest_weight_crystals.py @@ -111,7 +111,6 @@ def additional_structure(self): return None class ParentMethods: - @cached_method def highest_weight_vectors(self) -> tuple: r""" @@ -495,7 +494,7 @@ def digraph(self, subset=None, index_set=None, depth=None): return Crystals().parent_class.digraph(self, subset, index_set) if self not in Crystals().Finite() and depth is None: - raise NotImplementedError("crystals not known to be finite must" " specify either the subset or depth") + raise NotImplementedError("crystals not known to be finite must specify either the subset or depth") from sage.graphs.digraph import DiGraph @@ -637,7 +636,7 @@ def string_parameters(self, word=None): """ if word is None: if not self.cartan_type().is_finite(): - raise ValueError("the word must be specified because" " the Weyl group is not finite") + raise ValueError("the word must be specified because the Weyl group is not finite") from sage.combinat.root_system.weyl_group import WeylGroup word = WeylGroup(self.cartan_type()).long_element().reduced_word() diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index 2bd43702338..5da6b74b21d 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -86,9 +86,12 @@ _cache: TripleDict[SageObject, SageObject, Category | None, Homset] = TripleDict(weak_values=True) -def Hom[ - DomainElementT: Parent, CodomainElementT: Parent -](X: DomainElementT, Y: CodomainElementT, category: Category | None = None, check: bool = True,) -> Homset[DomainElementT, CodomainElementT]: +def Hom[DomainElementT: Parent, CodomainElementT: Parent]( + X: DomainElementT, + Y: CodomainElementT, + category: Category | None = None, + check: bool = True, +) -> Homset[DomainElementT, CodomainElementT]: """ Create the space of homomorphisms from X to Y in the category ``category``. diff --git a/src/sage/categories/homsets.py b/src/sage/categories/homsets.py index 3c3bea9dd55..da3de7d418a 100644 --- a/src/sage/categories/homsets.py +++ b/src/sage/categories/homsets.py @@ -17,7 +17,6 @@ class HomsetsCategory(FunctorialConstructionCategory, CategoryWithParameters): - _functor_category = "Homsets" @classmethod @@ -282,7 +281,6 @@ def super_categories(self): return [Sets()] class SubcategoryMethods: - def Endset(self): """ Return the subcategory of the homsets of ``self`` that are endomorphism sets. diff --git a/src/sage/categories/hopf_algebras.py b/src/sage/categories/hopf_algebras.py index 1ccce1ea05a..4f0b43ea106 100644 --- a/src/sage/categories/hopf_algebras.py +++ b/src/sage/categories/hopf_algebras.py @@ -62,7 +62,6 @@ def dual(self): WithBasis = LazyImport('sage.categories.hopf_algebras_with_basis', 'HopfAlgebrasWithBasis') class ElementMethods: - def antipode(self): """ Return the antipode of ``self``. @@ -190,9 +189,7 @@ class ParentMethods: pass class Realizations(RealizationsCategory): - class ParentMethods: - # TODO: # - Use @conditionally_defined once it's in Sage, for a nicer idiom # - Do the right thing (TM): once we will have proper diff --git a/src/sage/categories/hopf_algebras_with_basis.py b/src/sage/categories/hopf_algebras_with_basis.py index ed3bbf3981d..14e022cccc4 100644 --- a/src/sage/categories/hopf_algebras_with_basis.py +++ b/src/sage/categories/hopf_algebras_with_basis.py @@ -162,7 +162,6 @@ def example(self, G=None): Super = LazyImport('sage.categories.super_hopf_algebras_with_basis', 'SuperHopfAlgebrasWithBasis') class ParentMethods: - @abstract_method(optional=True) def antipode_on_basis(self, x): """ @@ -262,7 +261,6 @@ def _test_antipode(self, **options): SI = lambda x: self.sum(c * S(self.monomial(t1)) * self.monomial(t2) for ((t1, t2), c) in x.coproduct()) for x in tester.some_elements(): - # antipode is an anti-homomorphism for y in tester.some_elements(): tester.assertEqual(S(x) * S(y), S(y * x)) diff --git a/src/sage/categories/infinite_enumerated_sets.py b/src/sage/categories/infinite_enumerated_sets.py index 15ad57d323f..31db407b116 100644 --- a/src/sage/categories/infinite_enumerated_sets.py +++ b/src/sage/categories/infinite_enumerated_sets.py @@ -13,7 +13,6 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** - from sage.categories.category_with_axiom import CategoryWithAxiom @@ -45,7 +44,6 @@ class InfiniteEnumeratedSets(CategoryWithAxiom): """ class ParentMethods: - def random_element(self): """ Raise an error because ``self`` is an infinite enumerated set. diff --git a/src/sage/categories/isomorphic_objects.py b/src/sage/categories/isomorphic_objects.py index 43c7519e668..fcaaf77f551 100644 --- a/src/sage/categories/isomorphic_objects.py +++ b/src/sage/categories/isomorphic_objects.py @@ -18,7 +18,6 @@ class IsomorphicObjectsCategory(RegressiveCovariantConstructionCategory): - _functor_category = "IsomorphicObjects" @classmethod diff --git a/src/sage/categories/lambda_bracket_algebras.py b/src/sage/categories/lambda_bracket_algebras.py index 32c2be3c010..1c3e08a0231 100644 --- a/src/sage/categories/lambda_bracket_algebras.py +++ b/src/sage/categories/lambda_bracket_algebras.py @@ -84,7 +84,6 @@ def _repr_object_names(self): return "Lambda bracket algebras over {}".format(self.base_ring()) class SubcategoryMethods: - def FinitelyGeneratedAsLambdaBracketAlgebra(self): """ The category of finitely generated Lambda bracket algebras. @@ -108,7 +107,6 @@ def FinitelyGenerated(self): return self._with_axiom("FinitelyGeneratedAsLambdaBracketAlgebra") class ParentMethods: - def ideal(self, *gens, **kwds): r""" The ideal of this Lambda bracket algebra generated by ``gens``. @@ -125,10 +123,9 @@ def ideal(self, *gens, **kwds): ... NotImplementedError: ideals of Lie Conformal algebras are not implemented yet """ - raise NotImplementedError("ideals of Lie Conformal algebras are " "not implemented yet") + raise NotImplementedError("ideals of Lie Conformal algebras are not implemented yet") class ElementMethods: - @coerce_binop def bracket(self, rhs): r""" diff --git a/src/sage/categories/lambda_bracket_algebras_with_basis.py b/src/sage/categories/lambda_bracket_algebras_with_basis.py index 220fc8eecb1..96bdc83e036 100644 --- a/src/sage/categories/lambda_bracket_algebras_with_basis.py +++ b/src/sage/categories/lambda_bracket_algebras_with_basis.py @@ -31,7 +31,6 @@ class LambdaBracketAlgebrasWithBasis(CategoryWithAxiom_over_base_ring): """ class ElementMethods: - def index(self): """ The index of this basis element. @@ -54,7 +53,7 @@ def index(self): if self.is_zero(): return None if not self.is_monomial(): - raise ValueError("index can only be computed for " "monomials, got {}".format(self)) + raise ValueError("index can only be computed for monomials, got {}".format(self)) return next(iter(self.monomial_coefficients())) @@ -91,7 +90,6 @@ class Graded(GradedModulesCategory): """ class ParentMethods: - def degree_on_basis(self, m): r""" Return the degree of the basis element indexed by ``m`` diff --git a/src/sage/categories/lattice_posets.py b/src/sage/categories/lattice_posets.py index c041f52e9ef..32c97be93fe 100644 --- a/src/sage/categories/lattice_posets.py +++ b/src/sage/categories/lattice_posets.py @@ -58,7 +58,6 @@ def super_categories(self) -> list: return [Posets()] class ParentMethods: - @abstract_method def meet(self, x, y): """ diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index 61f812fb73d..b99cc879a59 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -706,7 +706,7 @@ def bch(self, X, Y, prec=None): sage: L.options._reset() # reset the printing options """ if self not in LieAlgebras.Nilpotent and prec is None: - raise ValueError("the Lie algebra is not known to be nilpotent," " so you must specify the precision") + raise ValueError("the Lie algebra is not known to be nilpotent, so you must specify the precision") from sage.algebras.lie_algebras.bch import bch_iterator if prec is None: diff --git a/src/sage/categories/lie_conformal_algebras.py b/src/sage/categories/lie_conformal_algebras.py index 84e78915aa8..c6fcb730ae2 100644 --- a/src/sage/categories/lie_conformal_algebras.py +++ b/src/sage/categories/lie_conformal_algebras.py @@ -243,7 +243,6 @@ def _repr_object_names(self): return "Lie conformal algebras over {}".format(self.base_ring()) class ParentMethods: - def _test_jacobi(self, **options): """ Test the Jacobi axiom of this Lie conformal algebra. @@ -313,7 +312,6 @@ def _test_jacobi(self, **options): tester.assertDictEqual(jacobiator, {}) class ElementMethods: - def is_even_odd(self): """ Return ``0`` if this element is *even* and ``1`` if it is diff --git a/src/sage/categories/lie_conformal_algebras_with_basis.py b/src/sage/categories/lie_conformal_algebras_with_basis.py index db2faf9b151..c48ee7fee33 100644 --- a/src/sage/categories/lie_conformal_algebras_with_basis.py +++ b/src/sage/categories/lie_conformal_algebras_with_basis.py @@ -44,7 +44,6 @@ class Super(SuperModulesCategory): """ class ParentMethods: - def _even_odd_on_basis(self, m): """ Return the parity of the basis element indexed by ``m``. diff --git a/src/sage/categories/loop_crystals.py b/src/sage/categories/loop_crystals.py index 514676426a0..7863f3fdaa2 100644 --- a/src/sage/categories/loop_crystals.py +++ b/src/sage/categories/loop_crystals.py @@ -12,7 +12,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method from sage.categories.category_singleton import Category_singleton diff --git a/src/sage/categories/magmas.py b/src/sage/categories/magmas.py index c0d7e5e38f1..e556055411e 100644 --- a/src/sage/categories/magmas.py +++ b/src/sage/categories/magmas.py @@ -72,7 +72,6 @@ def super_categories(self): return [Sets()] class SubcategoryMethods: - @cached_method def Associative(self): r""" @@ -352,7 +351,6 @@ class JTrivial(CategoryWithAxiom): pass class Algebras(AlgebrasCategory): - def extra_super_categories(self): """ EXAMPLES:: @@ -380,7 +378,6 @@ def extra_super_categories(self): return [MagmaticAlgebras(self.base_ring())] class ParentMethods: - def is_field(self, proof=True): r""" Return ``True`` if ``self`` is a field. @@ -405,7 +402,6 @@ def is_field(self, proof=True): return self.basis().keys().cardinality() == 1 class Commutative(CategoryWithAxiom): - class ParentMethods: def is_commutative(self) -> bool: """ @@ -419,7 +415,6 @@ def is_commutative(self) -> bool: return True class Algebras(AlgebrasCategory): - def extra_super_categories(self): """ EXAMPLES:: @@ -461,7 +456,6 @@ def extra_super_categories(self): return [Magmas().Commutative()] class Unital(CategoryWithAxiom): - def additional_structure(self): r""" Return ``self``. @@ -571,7 +565,6 @@ class ElementMethods: pass class SubcategoryMethods: - @cached_method def Inverse(self): r""" @@ -638,7 +631,6 @@ def extra_super_categories(self): return [Magmas().Unital()] class ParentMethods: - @cached_method def one(self): """ @@ -696,7 +688,6 @@ def __invert__(self): return self.parent()(~x for x in self.cartesian_factors()) class Algebras(AlgebrasCategory): - def extra_super_categories(self): """ EXAMPLES:: @@ -722,9 +713,7 @@ def extra_super_categories(self): return [Magmas().Unital()] class Realizations(RealizationsCategory): - class ParentMethods: - @cached_method def one(self): r""" @@ -743,7 +732,6 @@ def one(self): return self(self.realization_of().a_realization().one()) class ParentMethods: - def product(self, x, y): """ The binary multiplication of the magma. @@ -1041,7 +1029,6 @@ def is_idempotent(self): return self * self == self class CartesianProducts(CartesianProductsCategory): - def extra_super_categories(self): """ This implements the fact that a subquotient (and therefore @@ -1081,7 +1068,6 @@ def example(self): return cartesian_product([QQ, ZZ, ZZ]) class ParentMethods: - def product(self, left, right): """ EXAMPLES:: @@ -1131,7 +1117,6 @@ class Subquotients(SubquotientsCategory): """ class ParentMethods: - def product(self, x, y): """ Return the product of two elements of ``self``. @@ -1157,9 +1142,7 @@ def product(self, x, y): return self.retract(self.lift(x) * self.lift(y)) class Realizations(RealizationsCategory): - class ParentMethods: - def product_by_coercion(self, left, right): r""" Default implementation of product for realizations. diff --git a/src/sage/categories/magmas_and_additive_magmas.py b/src/sage/categories/magmas_and_additive_magmas.py index 9fce15b7154..2fa8cd01f4a 100644 --- a/src/sage/categories/magmas_and_additive_magmas.py +++ b/src/sage/categories/magmas_and_additive_magmas.py @@ -55,7 +55,6 @@ class MagmasAndAdditiveMagmas(Category_singleton): """ class SubcategoryMethods: - @cached_method def Distributive(self): r""" diff --git a/src/sage/categories/magmatic_algebras.py b/src/sage/categories/magmatic_algebras.py index 9772f0000f9..6857369a5cc 100644 --- a/src/sage/categories/magmatic_algebras.py +++ b/src/sage/categories/magmatic_algebras.py @@ -102,7 +102,6 @@ def additional_structure(self): Unital = LazyImport('sage.categories.unital_algebras', 'UnitalAlgebras', at_startup=True) class ParentMethods: - @abstract_method(optional=True) def algebra_generators(self): """ @@ -118,9 +117,7 @@ def algebra_generators(self): """ class WithBasis(CategoryWithAxiom_over_base_ring): - class ParentMethods: - def algebra_generators(self): r""" Return generators for this algebra. diff --git a/src/sage/categories/metric_spaces.py b/src/sage/categories/metric_spaces.py index 06ff221efde..2adecc236f5 100644 --- a/src/sage/categories/metric_spaces.py +++ b/src/sage/categories/metric_spaces.py @@ -19,7 +19,6 @@ class MetricSpacesCategory(RegressiveCovariantConstructionCategory): - _functor_category = "Metric" @classmethod @@ -231,7 +230,6 @@ class Homsets(HomsetsCategory): """ class ElementMethods: - def _test_metric_map(self, **options): r""" Test that this metric space morphism is a metric map, @@ -302,7 +300,6 @@ def extra_super_categories(self): return [MetricSpaces()] class ParentMethods: - def dist(self, a, b): r""" Return the distance between ``a`` and ``b`` in ``self``. @@ -350,7 +347,6 @@ class Complete(CategoryWithAxiom): """ class CartesianProducts(CartesianProductsCategory): - def extra_super_categories(self): r""" Implement the fact that a (finite) Cartesian product of complete diff --git a/src/sage/categories/modular_abelian_varieties.py b/src/sage/categories/modular_abelian_varieties.py index 22907457027..f11d1476b1c 100644 --- a/src/sage/categories/modular_abelian_varieties.py +++ b/src/sage/categories/modular_abelian_varieties.py @@ -65,7 +65,6 @@ def super_categories(self): return [Sets()] # FIXME class Homsets(HomsetsCategory): - class Endset(CategoryWithAxiom): def extra_super_categories(self): """ diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index 3d85ad45d36..307d843ff80 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -197,7 +197,6 @@ def additional_structure(self): return None class SubcategoryMethods: - @cached_method def base_ring(self): r""" @@ -516,7 +515,6 @@ def WithBasis(self): return self._with_axiom("WithBasis") class FiniteDimensional(CategoryWithAxiom_over_base_ring): - def extra_super_categories(self): """ Implement the fact that a finite dimensional module over a finite @@ -545,7 +543,6 @@ def extra_super_categories(self): return [] class TensorProducts(TensorProductsCategory): - def extra_super_categories(self): """ Implement the fact that a (finite) tensor product of @@ -562,7 +559,6 @@ def extra_super_categories(self): return [self.base_category()] class FinitelyPresented(CategoryWithAxiom_over_base_ring): - def extra_super_categories(self): """ Implement the fact that a finitely presented module over a finite @@ -597,7 +593,6 @@ def extra_super_categories(self): WithBasis = LazyImport('sage.categories.modules_with_basis', 'ModulesWithBasis', at_startup=True) class ParentMethods: - def linear_combination(self, iter_of_elements_coeff, factor_on_left=True): r""" Return the linear combination `\lambda_1 v_1 + \cdots + @@ -744,7 +739,6 @@ def base_ring(self): return self.base_category().base_ring() class ParentMethods: - @cached_method def base_ring(self): """ @@ -856,7 +850,6 @@ def extra_super_categories(self): return [self.base_category()] class ParentMethods: - def __init_extra__(self): """ Initialise the base ring of this Cartesian product. @@ -914,7 +907,6 @@ def __init_extra__(self): self._base = R class ElementMethods: - def _lmul_(self, x): """ Return the product of `x` with ``self``. diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 8a702ac8a4f..a88a60441f0 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -2564,7 +2564,6 @@ def extra_super_categories(self): return [self.base_category()] class ParentMethods: - def _an_element_(self): """ EXAMPLES:: @@ -2748,7 +2747,6 @@ def apply_multilinear_morphism(self, f, codomain=None): return sum((c * f(*[module.monomial(t) for module, t in zip(modules, m)]) for m, c in self.items()), codomain.zero()) class DualObjects(DualObjectsCategory): - @cached_method def extra_super_categories(self): """ diff --git a/src/sage/categories/monoids.py b/src/sage/categories/monoids.py index dcc0705d072..c31425baa98 100644 --- a/src/sage/categories/monoids.py +++ b/src/sage/categories/monoids.py @@ -124,7 +124,6 @@ def free(index_set=None, names=None, **kwds): return IndexedFreeMonoid(index_set, names=names, **kwds) class ParentMethods: - def semigroup_generators(self): """ Return the generators of ``self`` as a semigroup. @@ -447,9 +446,7 @@ def free(index_set=None, names=None, **kwds): return IndexedFreeAbelianMonoid(index_set, names=names, **kwds) class WithRealizations(WithRealizationsCategory): - class ParentMethods: - def one(self): r""" Return the unit of this monoid. @@ -476,9 +473,7 @@ def one(self): return self.a_realization().one() class Subquotients(SubquotientsCategory): - class ParentMethods: - def one(self): """ Return the multiplicative unit of this monoid, @@ -492,7 +487,6 @@ def one(self): return self.retract(self.ambient().one()) class Algebras(AlgebrasCategory): - def extra_super_categories(self): """ The algebra of a monoid is a bialgebra and a monoid. @@ -513,7 +507,6 @@ def extra_super_categories(self): return [Bialgebras(self.base_ring()), Monoids()] class ParentMethods: - def is_field(self, proof=True) -> bool: r""" Return ``True`` if ``self`` is a field. @@ -612,7 +605,6 @@ def algebra_generators(self): return generators.map(self.monomial) class ElementMethods: - def is_central(self) -> bool: r""" Return whether the element ``self`` is central. diff --git a/src/sage/categories/posets.py b/src/sage/categories/posets.py index b382bc05c2e..c2b63f5f145 100644 --- a/src/sage/categories/posets.py +++ b/src/sage/categories/posets.py @@ -2,6 +2,7 @@ r""" Posets """ + # **************************************************************************** # Copyright (C) 2011 Nicolas M. Thiery # @@ -158,7 +159,6 @@ def __iter__(self): Finite = LazyImport('sage.categories.finite_posets', 'FinitePosets') class ParentMethods: - @abstract_method def le(self, x, y): r""" diff --git a/src/sage/categories/principal_ideal_domains.py b/src/sage/categories/principal_ideal_domains.py index a9661e123bd..5f223d5350e 100644 --- a/src/sage/categories/principal_ideal_domains.py +++ b/src/sage/categories/principal_ideal_domains.py @@ -112,8 +112,8 @@ def _test_gcd_vs_xgcd(self, **options): tester.assertTrue(has_gcd, "The ring {} provides a xgcd but no gcd".format(self)) for (x, y), gcd, xgcd in zip(pairs, gcds, xgcds): tester.assertTrue(gcd.parent() == self, "The parent of the gcd is {} for element of {}".format(gcd.parent(), self)) - tester.assertTrue(xgcd[0].parent() == self and xgcd[1].parent() == self == xgcd[2].parent(), "The parent of output in xgcd is different from " "the parent of input for elements in {}".format(self)) - tester.assertTrue(gcd == xgcd[0], "The methods gcd and xgcd disagree on {}:\n" " gcd({},{}) = {}\n" " xgcd({},{}) = {}\n".format(self, x, y, gcd, x, y, xgcd)) + tester.assertTrue(xgcd[0].parent() == self and xgcd[1].parent() == self == xgcd[2].parent(), "The parent of output in xgcd is different from the parent of input for elements in {}".format(self)) + tester.assertTrue(gcd == xgcd[0], "The methods gcd and xgcd disagree on {}:\n gcd({},{}) = {}\n xgcd({},{}) = {}\n".format(self, x, y, gcd, x, y, xgcd)) def is_noetherian(self) -> bool: """ diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index f2ed67977af..2fcf025512e 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -1938,7 +1938,7 @@ def _apply_functor(self, R): from sage.misc.latex import latex for latex_name in self.latex_name_mapping.values(): - latex_name = fr'{latex_name} \otimes {latex(R)}' + latex_name = rf'{latex_name} \otimes {latex(R)}' break if name is None and latex_name is None: return FreeModule(R, self.n, sparse=self.is_sparse, inner_product_matrix=self.inner_product_matrix, with_basis=self.with_basis, basis_keys=self.basis_keys) @@ -3640,7 +3640,6 @@ def merge(self, other): class PermutationGroupFunctor(ConstructionFunctor): - rank = 10 def __init__(self, gens, domain): diff --git a/src/sage/categories/quantum_group_representations.py b/src/sage/categories/quantum_group_representations.py index b2297eed9cb..594014e15f8 100644 --- a/src/sage/categories/quantum_group_representations.py +++ b/src/sage/categories/quantum_group_representations.py @@ -16,7 +16,6 @@ # http://www.gnu.org/licenses/ # ***************************************************************************** - from sage.misc.abstract_method import abstract_method from sage.misc.cachefunc import cached_method from sage.categories.modules import Modules diff --git a/src/sage/categories/quotient_fields.py b/src/sage/categories/quotient_fields.py index 98242b328c7..4b6d991f096 100644 --- a/src/sage/categories/quotient_fields.py +++ b/src/sage/categories/quotient_fields.py @@ -45,7 +45,6 @@ class ParentMethods: pass class ElementMethods: - @abstract_method def numerator(self): pass diff --git a/src/sage/categories/quotients.py b/src/sage/categories/quotients.py index 88f0c0ed0fe..78262a187b9 100644 --- a/src/sage/categories/quotients.py +++ b/src/sage/categories/quotients.py @@ -18,7 +18,6 @@ class QuotientsCategory(RegressiveCovariantConstructionCategory): - _functor_category = "Quotients" @classmethod diff --git a/src/sage/categories/regular_crystals.py b/src/sage/categories/regular_crystals.py index 0fc629ab808..659cec02ee1 100644 --- a/src/sage/categories/regular_crystals.py +++ b/src/sage/categories/regular_crystals.py @@ -160,7 +160,6 @@ def is_isomorphism(self): return self.is_strict() and self.domain().number_of_connected_components() == self.codomain().number_of_connected_components() class ParentMethods: - # TODO: this could be a method in Crystals.Algebras.ElementMethods, so that # one could do: # @@ -452,7 +451,6 @@ def wt_zero(x): return G class ElementMethods: - def epsilon(self, i): r""" Return `\varepsilon_i` of ``self``. diff --git a/src/sage/categories/rings.py b/src/sage/categories/rings.py index cd79878f107..0aa36e70a89 100644 --- a/src/sage/categories/rings.py +++ b/src/sage/categories/rings.py @@ -266,7 +266,6 @@ def extend_to_fraction_field(self): return RingHomomorphism_from_fraction_field(parent, self) class SubcategoryMethods: - def NoZeroDivisors(self): r""" Return the full subcategory of the objects of ``self`` having diff --git a/src/sage/categories/rngs.py b/src/sage/categories/rngs.py index d6cd5eaa378..2cc5a4b6a2d 100644 --- a/src/sage/categories/rngs.py +++ b/src/sage/categories/rngs.py @@ -52,7 +52,6 @@ class Rngs(CategoryWithAxiom): Unital = LazyImport('sage.categories.rings', 'Rings', at_startup=True) class ParentMethods: - @cached_method def ideal_monoid(self): """ diff --git a/src/sage/categories/schemes.py b/src/sage/categories/schemes.py index 725e7e84816..f0345c9201b 100644 --- a/src/sage/categories/schemes.py +++ b/src/sage/categories/schemes.py @@ -383,7 +383,6 @@ def _repr_object_names(self): return "Jacobians over %s" % self.base() class ParentMethods: - @abstract_method def base_curve(self): """ diff --git a/src/sage/categories/semigroups.py b/src/sage/categories/semigroups.py index a8293b253eb..bea141f57a1 100644 --- a/src/sage/categories/semigroups.py +++ b/src/sage/categories/semigroups.py @@ -90,7 +90,6 @@ def example(self, choice='leftzero', **kwds): return examples.FreeSemigroup(**kwds) class ParentMethods: - def _test_associativity(self, **options): r""" Test associativity for (not necessarily all) elements of this @@ -522,7 +521,6 @@ def representation(self, module, on_basis, side='left', *args, **kwargs): return Representation(self, module, on_basis, side, *args, **kwargs) class ElementMethods: - def _pow_int(self, n): """ Return ``self`` to the `n`-th power. @@ -552,7 +550,6 @@ def _pow_int(self, n): return generic_power(self, n) class SubcategoryMethods: - @cached_method def LTrivial(self): r""" @@ -836,7 +833,6 @@ def example(self): return QuotientOfLeftZeroSemigroup(category=self.Subquotients()) class Quotients(QuotientsCategory): - def example(self): r""" Return an example of quotient of a semigroup, as per @@ -853,7 +849,6 @@ def example(self): return QuotientOfLeftZeroSemigroup() class ParentMethods: - def semigroup_generators(self): r""" Return semigroup generators for ``self`` by @@ -867,7 +862,6 @@ def semigroup_generators(self): return self.ambient().semigroup_generators().map(self.retract) class CartesianProducts(CartesianProductsCategory): - def extra_super_categories(self): """ Implement the fact that a Cartesian product of semigroups is a @@ -906,7 +900,6 @@ def extra_super_categories(self): return [Semigroups()] class ParentMethods: - @cached_method def algebra_generators(self): r""" diff --git a/src/sage/categories/semisimple_algebras.py b/src/sage/categories/semisimple_algebras.py index d23db6e88e4..8f294af0724 100644 --- a/src/sage/categories/semisimple_algebras.py +++ b/src/sage/categories/semisimple_algebras.py @@ -88,7 +88,6 @@ def super_categories(self): return [Algebras(R)] class ParentMethods: - def radical_basis(self, **keywords): r""" Return a basis of the Jacobson radical of this algebra. @@ -111,5 +110,4 @@ def radical_basis(self, **keywords): return () class FiniteDimensional(CategoryWithAxiom_over_base_ring): - WithBasis = LazyImport('sage.categories.finite_dimensional_semisimple_algebras_with_basis', 'FiniteDimensionalSemisimpleAlgebrasWithBasis') diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 0e161ad7fd7..b94552083a3 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -308,7 +308,6 @@ def example(self, choice=None): raise ValueError("unknown choice") class SubcategoryMethods: - @cached_method def CartesianProducts(self): r""" @@ -1298,7 +1297,7 @@ def _test_elements_eq_transitive(self, **options): for z in S: if not y == z: continue - tester.assertEqual(x, z, LazyFormat("non transitive equality:\n" "%s and %s but %s") % (print_compare(x, y), print_compare(y, z), print_compare(x, z))) + tester.assertEqual(x, z, LazyFormat("non transitive equality:\n%s and %s but %s") % (print_compare(x, y), print_compare(y, z), print_compare(x, z))) def _test_elements_neq(self, **options): """ @@ -1340,7 +1339,7 @@ def _test_elements_neq(self, **options): from sage.misc.misc import some_tuples for x, y in some_tuples(S, 2, tester._max_runs): - tester.assertNotEqual(x == y, x != y, LazyFormat("__eq__ and __ne__ inconsistency:\n" " %s == %s returns %s but %s != %s returns %s") % (x, y, (x == y), x, y, (x != y))) + tester.assertNotEqual(x == y, x != y, LazyFormat("__eq__ and __ne__ inconsistency:\n %s == %s returns %s but %s != %s returns %s") % (x, y, (x == y), x, y, (x != y))) def some_elements(self): """ @@ -1686,9 +1685,7 @@ def algebra(self, base_ring, category=None, **kwds): raise TypeError( """ `S = {}` is both an additive and a multiplicative semigroup. Constructing its algebra is ambiguous. -Please use, e.g., S.algebra(QQ, category=Semigroups())""".format( - self - ) +Please use, e.g., S.algebra(QQ, category=Semigroups())""".format(self) ) from sage.categories.groups import Groups from sage.categories.additive_groups import AdditiveGroups @@ -1894,7 +1891,6 @@ def image(self, domain_subset=None): class Infinite(CategoryWithAxiom): class SubcategoryMethods: - def Finite(self): """ Incompatible axiom. @@ -1910,7 +1906,6 @@ def Finite(self): raise TypeError("incompatible axioms: finite and infinite") class ParentMethods: - def is_finite(self): """ Return whether this set is finite. @@ -1975,7 +1970,6 @@ class Subquotients(SubquotientsCategory): """ class ParentMethods: - def _repr_(self): """ EXAMPLES:: @@ -2068,7 +2062,6 @@ def retract(self, x): """ class ElementMethods: - def lift(self): """ Lift ``self`` to the ambient space for its parent. @@ -2106,7 +2099,6 @@ class Quotients(QuotientsCategory): """ class ParentMethods: - def _repr_(self): """ EXAMPLES:: @@ -2150,7 +2142,6 @@ class Subobjects(SubobjectsCategory): """ class ParentMethods: - def _repr_(self): """ EXAMPLES:: @@ -2180,7 +2171,6 @@ class IsomorphicObjects(IsomorphicObjectsCategory): """ class ParentMethods: - def _repr_(self): """ EXAMPLES:: @@ -2679,7 +2669,6 @@ def _sympy_(self): return ProductSet(*self.cartesian_factors()) class ElementMethods: - def cartesian_projection(self, i): """ Return the projection of ``self`` onto the `i`-th @@ -2732,7 +2721,6 @@ def cartesian_factors(self): # return Family(self._sets.keys(), self.projection) class Algebras(AlgebrasCategory): - def extra_super_categories(self): """ EXAMPLES:: @@ -2807,7 +2795,6 @@ def _repr_(self): return 'Algebra of {} over {}'.format(self.basis().keys(), self.base_ring()) class WithRealizations(WithRealizationsCategory): - def extra_super_categories(self): """ A set with multiple realizations is a facade parent. @@ -2846,7 +2833,6 @@ def example(self, base_ring=None, set=None): return SubsetAlgebra(base_ring, set) class ParentMethods: - def _test_with_realizations(self, **options): r""" Test that this parent with realizations is @@ -3108,7 +3094,6 @@ def facade_for(self): # Do we really want this feature? class Realizations(Category_realization_of_parent): - def super_categories(self): """ EXAMPLES:: @@ -3170,9 +3155,7 @@ def __contains__(self, x) -> bool: return any(x in realization for realization in self.realizations()) class Realizations(RealizationsCategory): - class ParentMethods: - def __init_extra__(self): """ Register ``self`` as a realization of ``self.realization_of``. diff --git a/src/sage/categories/sets_with_grading.py b/src/sage/categories/sets_with_grading.py index c84b7ce9f53..ae7774d12d2 100644 --- a/src/sage/categories/sets_with_grading.py +++ b/src/sage/categories/sets_with_grading.py @@ -113,7 +113,6 @@ def super_categories(self): return [Sets()] class ParentMethods: - def _test_graded_components(self, **options): r""" Test that some graded components of ``self`` are parent with diff --git a/src/sage/categories/simplicial_sets.py b/src/sage/categories/simplicial_sets.py index 600aea265ad..c8c313f02c9 100644 --- a/src/sage/categories/simplicial_sets.py +++ b/src/sage/categories/simplicial_sets.py @@ -153,7 +153,7 @@ def set_base_point(self, point): if point.dimension() != 0: raise ValueError('the "point" is not a zero-simplex') if point not in self._simplices: - raise ValueError('the point is not a simplex in this ' 'simplicial set') + raise ValueError('the point is not a simplex in this simplicial set') return SimplicialSet(self.face_data(), base_point=point) class Homsets(HomsetsCategory): @@ -1051,7 +1051,7 @@ def is_simply_connected(self): # code reaches this point, but there are certainly # groups for which these errors are raised. 'IsTrivial' # works for all of the examples I've seen, though. - raise ValueError('unable to determine if the fundamental ' 'group is trivial') + raise ValueError('unable to determine if the fundamental group is trivial') def connectivity(self, max_dim=None): """ @@ -1104,7 +1104,7 @@ def connectivity(self, max_dim=None): # Note: at the moment, this will never be reached, # because our only examples (so far) of infinite # simplicial sets are not simply connected. - raise ValueError('this simplicial set may be infinite, ' 'so specify a maximum dimension through ' 'which to check') + raise ValueError('this simplicial set may be infinite, so specify a maximum dimension through which to check') H = self.homology(range(2, max_dim + 1)) for i in range(2, max_dim + 1): @@ -1114,7 +1114,6 @@ def connectivity(self, max_dim=None): class Finite(CategoryWithAxiom): class ParentMethods: - def unset_base_point(self): """ Return a copy of this simplicial set in which the base point has diff --git a/src/sage/categories/subobjects.py b/src/sage/categories/subobjects.py index 4a0a7c0c3e6..364a3b6d5c8 100644 --- a/src/sage/categories/subobjects.py +++ b/src/sage/categories/subobjects.py @@ -18,7 +18,6 @@ class SubobjectsCategory(RegressiveCovariantConstructionCategory): - _functor_category = "Subobjects" @classmethod diff --git a/src/sage/categories/subquotients.py b/src/sage/categories/subquotients.py index 6cbc97d70c2..171ea79c1ce 100644 --- a/src/sage/categories/subquotients.py +++ b/src/sage/categories/subquotients.py @@ -17,5 +17,4 @@ class SubquotientsCategory(RegressiveCovariantConstructionCategory): - _functor_category = "Subquotients" diff --git a/src/sage/categories/super_lie_conformal_algebras.py b/src/sage/categories/super_lie_conformal_algebras.py index 5ef01bb72db..053747f02e3 100644 --- a/src/sage/categories/super_lie_conformal_algebras.py +++ b/src/sage/categories/super_lie_conformal_algebras.py @@ -67,7 +67,6 @@ def example(self): return NeveuSchwarzLieConformalAlgebra(self.base_ring()) class ParentMethods: - def _test_jacobi(self, **options): """ Test the Jacobi axiom of this super Lie conformal algebra. @@ -156,7 +155,6 @@ def _test_jacobi(self, **options): tester.assertDictEqual(jacobiator, {}) class ElementMethods: - @abstract_method def is_even_odd(self): """ diff --git a/src/sage/categories/topological_spaces.py b/src/sage/categories/topological_spaces.py index 30dfb6d1ecd..4e2012ac16d 100644 --- a/src/sage/categories/topological_spaces.py +++ b/src/sage/categories/topological_spaces.py @@ -17,7 +17,6 @@ class TopologicalSpacesCategory(RegressiveCovariantConstructionCategory): - _functor_category = "Topological" def _repr_object_names(self): diff --git a/src/sage/categories/unital_algebras.py b/src/sage/categories/unital_algebras.py index 07fe7f5cea9..6cd45ec3219 100644 --- a/src/sage/categories/unital_algebras.py +++ b/src/sage/categories/unital_algebras.py @@ -252,9 +252,7 @@ def _coerce_map_from_base_ring(self): return mor class WithBasis(CategoryWithAxiom_over_base_ring): - class ParentMethods: - @abstract_method(optional=True) def one_basis(self): """ diff --git a/src/sage/categories/vector_spaces.py b/src/sage/categories/vector_spaces.py index eb478281d93..d1be8678ff3 100644 --- a/src/sage/categories/vector_spaces.py +++ b/src/sage/categories/vector_spaces.py @@ -157,7 +157,6 @@ def additional_structure(self): return None class ParentMethods: - def dimension(self): """ Return the dimension of this vector space. @@ -181,7 +180,6 @@ class ElementMethods: pass class WithBasis(CategoryWithAxiom_over_base_ring): - _call_ = ModulesWithBasis.__dict__["_call_"] def is_abelian(self) -> bool: @@ -224,9 +222,7 @@ def extra_super_categories(self): return [self.base_category()] class FiniteDimensional(CategoryWithAxiom_over_base_ring): - class TensorProducts(TensorProductsCategory): - def extra_super_categories(self): """ Implement the fact that a (finite) tensor product of @@ -288,9 +284,7 @@ def example(self, base_ring=None): return FilteredPartitionModule(base_ring=base_ring) class FiniteDimensional(CategoryWithAxiom_over_base_ring): - class TensorProducts(TensorProductsCategory): - def extra_super_categories(self): """ Implement the fact that a (finite) tensor product of @@ -306,7 +300,6 @@ def extra_super_categories(self): return [self.base_category()] class DualObjects(DualObjectsCategory): - def extra_super_categories(self): r""" Return the dual category. diff --git a/src/sage/categories/weyl_groups.py b/src/sage/categories/weyl_groups.py index 5a39ba192c5..559fa04e0c4 100644 --- a/src/sage/categories/weyl_groups.py +++ b/src/sage/categories/weyl_groups.py @@ -313,7 +313,6 @@ def length(x): return DiGraph(visited, name="Parabolic Quantum Bruhat Graph of %s for nodes %s" % (self, index_set), format='dict_of_dicts', data_structure='static_sparse') class ElementMethods: - def is_pieri_factor(self): r""" Return whether ``self`` is a Pieri factor, as used for diff --git a/src/sage/coding/abstract_code.py b/src/sage/coding/abstract_code.py index c794e895615..68bae275817 100644 --- a/src/sage/coding/abstract_code.py +++ b/src/sage/coding/abstract_code.py @@ -816,9 +816,9 @@ def decoder(self, decoder_name=None, *args, **kwargs): try: return decClass(self, *args, **kwargs) except TypeError: - raise ValueError("Constructing the {0} decoder failed, possibly due " "to missing or incorrect parameters.\n{1}".format(decoder_name, _explain_constructor(decClass))) + raise ValueError("Constructing the {0} decoder failed, possibly due to missing or incorrect parameters.\n{1}".format(decoder_name, _explain_constructor(decClass))) else: - raise ValueError("There is no Decoder named '{0}'. The known Decoders are: " "{1}".format(decoder_name, self.decoders_available())) + raise ValueError("There is no Decoder named '{0}'. The known Decoders are: {1}".format(decoder_name, self.decoders_available())) def decoders_available(self, classes=False): r""" @@ -986,9 +986,9 @@ def encoder(self, encoder_name=None, *args, **kwargs): try: return encClass(self, *args, **kwargs) except TypeError: - raise ValueError("Constructing the {0} encoder failed, possibly due " "to missing or incorrect parameters.\n{1}".format(encoder_name, _explain_constructor(encClass))) + raise ValueError("Constructing the {0} encoder failed, possibly due to missing or incorrect parameters.\n{1}".format(encoder_name, _explain_constructor(encClass))) else: - raise ValueError("There is no Encoder named '{0}'. The known Encoders are: " "{1}".format(encoder_name, self.encoders_available())) + raise ValueError("There is no Encoder named '{0}'. The known Encoders are: {1}".format(encoder_name, self.encoders_available())) def encoders_available(self, classes=False): r""" diff --git a/src/sage/coding/bch_code.py b/src/sage/coding/bch_code.py index aae2b6325bb..abc79f49e19 100644 --- a/src/sage/coding/bch_code.py +++ b/src/sage/coding/bch_code.py @@ -13,6 +13,7 @@ the arithmetic sequence `b, b + \ell, b + 2 \times \ell, \dots, b + (\delta - 2) \times \ell`. """ + # ***************************************************************************** # Copyright (C) 2016 David Lucas # 2017 Julien Lavauzelle @@ -125,7 +126,7 @@ def __init__(self, base_field, length, designed_distance, primitive_root=None, o q = base_field.cardinality() s = Zmod(length)(q).multiplicative_order() if gcd(jump_size, q**s - 1) != 1: - raise ValueError("jump_size must be coprime with the order of " "the multiplicative group of the splitting field") + raise ValueError("jump_size must be coprime with the order of the multiplicative group of the splitting field") D = [(offset + jump_size * i) % length for i in range(designed_distance - 1)] diff --git a/src/sage/coding/code_bounds.py b/src/sage/coding/code_bounds.py index 3c4dda358fd..cf2dccd5abf 100644 --- a/src/sage/coding/code_bounds.py +++ b/src/sage/coding/code_bounds.py @@ -478,7 +478,7 @@ def elias_upper_bound(n, q, d, algorithm=None): def ff(n, d, w, q): return r * n * d * q**n / ((w**2 - 2 * r * n * w + r * n * d) * volume_hamming(n, q, w)) - I = (i for i in range(1, int(r * n) + 1) if i ** 2 - 2 * r * n * i + r * n * d > 0) + I = (i for i in range(1, int(r * n) + 1) if i**2 - 2 * r * n * i + r * n * d > 0) bnd = min([ff(n, d, w, q) for w in I]) return int(bnd) @@ -596,7 +596,7 @@ def entropy(x, q=2): ValueError: The value q must be an integer greater than 1 """ if x < 0 or x > 1: - raise ValueError("The entropy function is defined only for x in the" " interval [0, 1]") + raise ValueError("The entropy function is defined only for x in the interval [0, 1]") q = ZZ(q) # This will error out if q is not an integer if q < 2: # Here we check that q is actually at least 2 raise ValueError("The value q must be an integer greater than 1") @@ -640,7 +640,7 @@ def entropy_inverse(x, q=2): """ # No nice way to compute the inverse. We resort to root finding. if x < 0 or x > 1: - raise ValueError("The inverse entropy function is defined only for " "x in the interval [0, 1]") + raise ValueError("The inverse entropy function is defined only for x in the interval [0, 1]") q = ZZ(q) # This will error out if q is not an integer if q < 2: # Here we check that q is actually at least 2 raise ValueError("The value q must be an integer greater than 1") diff --git a/src/sage/coding/cyclic_code.py b/src/sage/coding/cyclic_code.py index 672b7129948..1249bbf7575 100644 --- a/src/sage/coding/cyclic_code.py +++ b/src/sage/coding/cyclic_code.py @@ -355,16 +355,16 @@ def __init__(self, generator_pol=None, length=None, code=None, check=True, D=Non if generator_pol is not None and length is not None and code is None and D is None and field is None and primitive_root is None: F = generator_pol.base_ring() if not F.is_finite() or not F.is_field(): - raise ValueError("The generator polynomial must be defined " "over a finite field.") + raise ValueError("The generator polynomial must be defined over a finite field.") q = F.cardinality() if not gcd(length, q) == 1: - raise ValueError("Only cyclic codes whose length and field " "order are coprimes are implemented.") + raise ValueError("Only cyclic codes whose length and field order are coprimes are implemented.") R = generator_pol.parent() deg = generator_pol.degree() if not isinstance(length, Integer): length = Integer(length) if not generator_pol.divides(R.gen() ** length - 1): - raise ValueError("Provided polynomial must divide x^n - 1, " "where n is the provided length.") + raise ValueError("Provided polynomial must divide x^n - 1, where n is the provided length.") self._polynomial_ring = R self._dimension = length - deg if not generator_pol.is_monic(): @@ -381,7 +381,7 @@ def __init__(self, generator_pol=None, length=None, code=None, check=True, D=Non q = F.cardinality() n = code.length() if not gcd(n, q) == 1: - raise ValueError("Only cyclic codes whose length and field " "order are coprimes are implemented.") + raise ValueError("Only cyclic codes whose length and field order are coprimes are implemented.") g = find_generator_polynomial(code, check) self._polynomial_ring = g.parent() self._generator_polynomial = g @@ -396,7 +396,7 @@ def __init__(self, generator_pol=None, length=None, code=None, check=True, D=Non n = length q = F.cardinality() if not gcd(n, q) == 1: - raise ValueError("Only cyclic codes whose length and field " "order are coprimes are implemented.") + raise ValueError("Only cyclic codes whose length and field order are coprimes are implemented.") R = F['x'] s = Zmod(n)(q).multiplicative_order() @@ -406,10 +406,10 @@ def __init__(self, generator_pol=None, length=None, code=None, check=True, D=Non try: FE = Hom(F, Fsplit)[0] except Exception: - raise ValueError("primitive_root must belong to an " "extension of the base field") + raise ValueError("primitive_root must belong to an extension of the base field") extension_degree = Fsplit.degree() // F.degree() if extension_degree != s or primitive_root.multiplicative_order() != n: - raise ValueError("primitive_root must be a primitive " "n-th root of unity") + raise ValueError("primitive_root must be a primitive n-th root of unity") alpha = primitive_root else: Fsplit, FE = F.extension(Integer(s), map=True) @@ -439,7 +439,7 @@ def __init__(self, generator_pol=None, length=None, code=None, check=True, D=Non super().__init__(F, n, "Vector", "SurroundingBCH") else: - raise AttributeError("You must provide either a code, or a list " "of powers and the length and the field, or " "a generator polynomial and the code length") + raise AttributeError("You must provide either a code, or a list of powers and the length and the field, or a generator polynomial and the code length") def __contains__(self, word) -> bool: r""" @@ -625,9 +625,9 @@ def defining_set(self, primitive_root=None): Fsplit = alpha.parent() FE = Hom(Fsplit, F)[0] except ValueError: - raise ValueError("primitive_root does not belong to the " "right splitting field") + raise ValueError("primitive_root does not belong to the right splitting field") if alpha.multiplicative_order() != n: - raise ValueError("primitive_root must have multiplicative " "order equal to the code length") + raise ValueError("primitive_root must have multiplicative order equal to the code length") Rsplit = Fsplit['xx'] gsplit = Rsplit([FE(coeff) for coeff in g]) @@ -1214,7 +1214,7 @@ def _latex_(self): sage: latex(D) \textnormal{Decoder through the surrounding BCH code of the }[15, 10] \textnormal{ Cyclic Code over } \Bold{F}_{2^{4}} """ - return "\\textnormal{Decoder through the surrounding BCH code of " "the }%s" % self.code()._latex_() + return "\\textnormal{Decoder through the surrounding BCH code of the }%s" % self.code()._latex_() def bch_code(self): r""" diff --git a/src/sage/coding/databases.py b/src/sage/coding/databases.py index f614d1ec53f..bed309f69dd 100644 --- a/src/sage/coding/databases.py +++ b/src/sage/coding/databases.py @@ -2,6 +2,7 @@ r""" Access functions to online databases for coding theory """ + from sage.misc.lazy_import import lazy_import # Import the following function so that it is available as diff --git a/src/sage/coding/delsarte_bounds.py b/src/sage/coding/delsarte_bounds.py index 2f3d052e677..363cbed609b 100644 --- a/src/sage/coding/delsarte_bounds.py +++ b/src/sage/coding/delsarte_bounds.py @@ -336,10 +336,10 @@ def delsarte_bound_constant_weight_code(n, d, w, return_data=False, solver='PPL' from sage.numerical.mip import MIPSolverException if d < 4: - raise ValueError("Violated constraint d>=4 for " "Binary Constant Weight Codes") + raise ValueError("Violated constraint d>=4 for Binary Constant Weight Codes") if d >= 2 * w or 2 * w > n: - raise ValueError("Violated constraint d<2w<=n for " "Binary Constant Weight Codes") + raise ValueError("Violated constraint d<2w<=n for Binary Constant Weight Codes") # minimum distance is even => if there is an odd lower bound on d we can # increase it by 1 @@ -690,7 +690,7 @@ def delsarte_bound_Q_matrix(q, d, return_data=False, solver='PPL', isinteger=Fal from sage.structure.element import Matrix if not isinstance(q, Matrix): - raise ValueError("Input to delsarte_bound_Q_matrix " "should be a sage Matrix()") + raise ValueError("Input to delsarte_bound_Q_matrix should be a sage Matrix()") A, p = _delsarte_Q_LP_building(q, d, solver, isinteger) try: diff --git a/src/sage/coding/gabidulin_code.py b/src/sage/coding/gabidulin_code.py index 6a6a92ff7f2..e79cc2fcaa1 100644 --- a/src/sage/coding/gabidulin_code.py +++ b/src/sage/coding/gabidulin_code.py @@ -17,6 +17,7 @@ - Arpit Merchant (2016-08-16) - Marketa Slukova (2019-08-19): initial version """ + from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector from sage.coding.encoder import Encoder @@ -378,7 +379,6 @@ def evaluation_points(self): class GabidulinVectorEvaluationEncoder(Encoder): - def __init__(self, code): """ This method constructs the vector evaluation encoder for @@ -758,7 +758,6 @@ def unencode_nocheck(self, c): class GabidulinGaoDecoder(Decoder): - def __init__(self, code): r""" Gao style decoder for Gabidulin Codes. diff --git a/src/sage/coding/goppa_code.py b/src/sage/coding/goppa_code.py index f213f38ec82..87a78ff9295 100644 --- a/src/sage/coding/goppa_code.py +++ b/src/sage/coding/goppa_code.py @@ -21,6 +21,7 @@ - Filip Ion, Marketa Slukova (2019-06): initial version """ + # ***************************************************************************** # Copyright (C) 2019 Filip Ion , # Marketa Slukova diff --git a/src/sage/coding/grs_code.py b/src/sage/coding/grs_code.py index 9d84cc34ee4..07ff5ff5337 100644 --- a/src/sage/coding/grs_code.py +++ b/src/sage/coding/grs_code.py @@ -1210,7 +1210,7 @@ def _decode_to_code_and_message(self, r): l0 = n - 1 - t l1 = n - t - k pts = C.evaluation_points() - S = matrix(C.base_field(), n, l0 + l1 + 2, lambda i, j: (pts[i] ** j if j < (l0 + 1) else r_list[i] * pts[i] ** (j - (l0 + 1)))) + S = matrix(C.base_field(), n, l0 + l1 + 2, lambda i, j: pts[i] ** j if j < (l0 + 1) else r_list[i] * pts[i] ** (j - (l0 + 1))) S = S.right_kernel() S = S.basis_matrix().row(0) R = C.base_field()['x'] diff --git a/src/sage/coding/guruswami_sudan/interpolation.py b/src/sage/coding/guruswami_sudan/interpolation.py index df0f912dc0f..60ce83c1718 100644 --- a/src/sage/coding/guruswami_sudan/interpolation.py +++ b/src/sage/coding/guruswami_sudan/interpolation.py @@ -19,7 +19,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.arith.misc import binomial from sage.matrix.constructor import matrix from sage.misc.misc_c import prod diff --git a/src/sage/coding/information_set_decoder.py b/src/sage/coding/information_set_decoder.py index 9e00141c1c6..5bb02a398ea 100644 --- a/src/sage/coding/information_set_decoder.py +++ b/src/sage/coding/information_set_decoder.py @@ -418,7 +418,7 @@ def __init__(self, code, decoding_interval, search_size=None): if not isinstance(search_size, (Integer, int)) or search_size < 0: raise ValueError("The search size parameter has to be a positive integer") if search_size > decoding_interval[1]: - raise ValueError("The search size parameter has to be at most" " the maximal number of allowed errors") + raise ValueError("The search size parameter has to be at most the maximal number of allowed errors") super().__init__(code, decoding_interval, "Lee-Brickell", parameters={'search_size': search_size}) self._parameters_specified = True else: @@ -821,9 +821,9 @@ def __init__(self, code, number_errors, algorithm=None, **kwargs): number_errors = (0, number_errors) if isinstance(number_errors, (tuple, list)) and len(number_errors) == 2 and number_errors[0] in ZZ and number_errors[1] in ZZ: if 0 > number_errors[0] or number_errors[0] > number_errors[1]: - raise ValueError("number_errors should be a positive integer or" " a valid interval within the positive integers") + raise ValueError("number_errors should be a positive integer or a valid interval within the positive integers") if number_errors[1] > code.length(): - raise ValueError("The provided number of errors should be at" " most the code's length") + raise ValueError("The provided number of errors should be at most the code's length") else: raise ValueError("number_errors should be an integer or a pair of integers") @@ -833,20 +833,20 @@ def __init__(self, code, number_errors, algorithm=None, **kwargs): if algorithm is None: if kwargs: - raise ValueError("Additional arguments to an information-set decoder" " algorithm are only allowed if a specific" " algorithm is selected by setting the algorithm" " keyword") + raise ValueError("Additional arguments to an information-set decoder algorithm are only allowed if a specific algorithm is selected by setting the algorithm keyword") algorithm = "Lee-Brickell" algorithm_names = LinearCodeInformationSetDecoder.known_algorithms(dictionary=True) if isinstance(algorithm, InformationSetAlgorithm): if kwargs: - raise ValueError("ISD algorithm arguments are not allowed when" " supplying a constructed ISD algorithm") + raise ValueError("ISD algorithm arguments are not allowed when supplying a constructed ISD algorithm") if number_errors != algorithm.decoding_interval(): - raise ValueError("number_errors must match that of the passed" " ISD algorithm") + raise ValueError("number_errors must match that of the passed ISD algorithm") self._algorithm = algorithm elif algorithm in algorithm_names: self._algorithm = algorithm_names[algorithm](code, number_errors, **kwargs) else: - raise ValueError("Unknown ISD algorithm '{}'." " The known algorithms are {}.".format(algorithm, sorted(algorithm_names))) + raise ValueError("Unknown ISD algorithm '{}'. The known algorithms are {}.".format(algorithm, sorted(algorithm_names))) _known_algorithms = {"Lee-Brickell": LeeBrickellISDAlgorithm} diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 098e61d6f4f..5ec829ab74a 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -606,9 +606,7 @@ def assmus_mattson_designs(self, t, mode=None): for w in nonzerowts: print( "The weight w={} codewords of C* form a t-(v,k,lambda) design, where\n \ - t={}, v={}, k={}, lambda={}. \nThere are {} block of this design.".format( - w, t, n, w, wts[w] * binomial(w, t) // binomial(n, t), wts[w] - ) + t={}, v={}, k={}, lambda={}. \nThere are {} block of this design.".format(w, t, n, w, wts[w] * binomial(w, t) // binomial(n, t), wts[w]) ) wtsp = Cp.weight_distribution() dp = next(i for i in range(1, len(wtsp)) if wtsp[i] != 0) @@ -618,9 +616,7 @@ def assmus_mattson_designs(self, t, mode=None): for w in nonzerowtsp: print( "The weight w={} codewords of C* form a t-(v,k,lambda) design, where\n \ - t={}, v={}, k={}, lambda={}. \nThere are {} block of this design.".format( - w, t, n, w, wts[w] * binomial(w, t) // binomial(n, t), wts[w] - ) + t={}, v={}, k={}, lambda={}. \nThere are {} block of this design.".format(w, t, n, w, wts[w] * binomial(w, t) // binomial(n, t), wts[w]) ) if s <= d - t: des = [[t, (n, w, wts[w] * binomial(w, t) // binomial(n, t))] for w in nonzerowts] @@ -929,7 +925,7 @@ def covering_radius(self): libgap.LoadPackage('guava') F = self.base_ring() if F.cardinality() > 256: - raise NotImplementedError("the GAP algorithm that Sage is using " "is limited to computing with fields " "of size at most 256") + raise NotImplementedError("the GAP algorithm that Sage is using is limited to computing with fields of size at most 256") gapG = libgap(self.generator_matrix()) C = gapG.GeneratorMatCode(libgap(F)) r = C.CoveringRadius() @@ -1402,12 +1398,12 @@ def minimum_distance(self, algorithm=None): # the user then simply return the stored value. # This is done only if algorithm is None. if algorithm not in (None, 'gap', 'guava'): - raise ValueError("The algorithm argument must be one of None, " "'gap' or 'guava'; got '{0}'".format(algorithm)) + raise ValueError("The algorithm argument must be one of None, 'gap' or 'guava'; got '{0}'".format(algorithm)) F = self.base_ring() q = F.order() if q > 256: - raise NotImplementedError("the GAP algorithm that Sage is using " "is limited to computing with fields " "of size at most 256") + raise NotImplementedError("the GAP algorithm that Sage is using is limited to computing with fields of size at most 256") G = self.generator_matrix() if (q == 2 or q == 3) and algorithm == 'guava': diff --git a/src/sage/coding/linear_code_no_metric.py b/src/sage/coding/linear_code_no_metric.py index 5388504f640..00410aaa3e8 100644 --- a/src/sage/coding/linear_code_no_metric.py +++ b/src/sage/coding/linear_code_no_metric.py @@ -795,7 +795,7 @@ def __getitem__(self, i): F = self.base_ring() maxindex = F.order() ** self.dimension() - 1 if i < 0 or i > maxindex: - raise IndexError("The value of the index 'i' (={}) must be between " "0 and 'q^k -1' (={}), inclusive, where 'q' is " "the size of the base field and 'k' is the " "dimension of the code.".format(i, maxindex)) + raise IndexError("The value of the index 'i' (={}) must be between 0 and 'q^k -1' (={}), inclusive, where 'q' is the size of the base field and 'k' is the dimension of the code.".format(i, maxindex)) a = F.primitive_element() m = F.degree() diff --git a/src/sage/coding/source_coding/huffman.py b/src/sage/coding/source_coding/huffman.py index 47dda722e1c..145cf9d8bc0 100644 --- a/src/sage/coding/source_coding/huffman.py +++ b/src/sage/coding/source_coding/huffman.py @@ -348,7 +348,7 @@ def _build_code(self, dic): def pop(): # pop the lowest weight node from the heads of the two queues (as # long as at least one of them has one node) - q = min(queues, key=lambda q: (q and q[0][0] or tot_weight)) + q = min(queues, key=lambda q: q and q[0][0] or tot_weight) return q.pop(0) while len(q0) + len(q1) > 1: diff --git a/src/sage/coding/subfield_subcode.py b/src/sage/coding/subfield_subcode.py index a553f9f0441..55d7616d0b8 100644 --- a/src/sage/coding/subfield_subcode.py +++ b/src/sage/coding/subfield_subcode.py @@ -387,7 +387,7 @@ def decode_to_code(self, y): try: cw = vector([sec(c) for c in result]) except ValueError: # not a codeword of this code - raise DecodingError("Original decoder does not output a subfield codeword. " "You may have exceeded the decoding radius.") + raise DecodingError("Original decoder does not output a subfield codeword. You may have exceeded the decoding radius.") return cw def decoding_radius(self, **kwargs): diff --git a/src/sage/coding/two_weight_db.py b/src/sage/coding/two_weight_db.py index efce9d27a78..e188b91752b 100644 --- a/src/sage/coding/two_weight_db.py +++ b/src/sage/coding/two_weight_db.py @@ -28,6 +28,7 @@ ....: w1,w2 = [w for w,f in enumerate(LinearCode(M).weight_distribution()) if w and f] ....: assert (code['w1'], code['w2']) == (w1, w2) """ + from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF from sage.matrix.constructor import Matrix @@ -381,7 +382,7 @@ for code in data: code['M'] = Matrix(code['K'], [list(R) for R in code['M']]) -DB_INDEX = ".. csv-table::\n" " :class: contentstable\n" " :widths: 7,7,7,7,7,50\n" " :delim: @\n\n" +DB_INDEX = ".. csv-table::\n :class: contentstable\n :widths: 7,7,7,7,7,50\n :delim: @\n\n" data.sort(key=lambda x: (x['K'].cardinality(), x['k'], x['n'])) for x in data: diff --git a/src/sage/combinat/SJT.py b/src/sage/combinat/SJT.py index f64e3da1262..eb868333cd6 100644 --- a/src/sage/combinat/SJT.py +++ b/src/sage/combinat/SJT.py @@ -144,7 +144,7 @@ def __init__(self, l, directions=None) -> None: if directions is None: if not all(l[i] <= l[i + 1] for i in range(self._n - 1)): - raise ValueError("no internal state directions were given for " "non-identity starting permutation for " "Steinhaus-Johnson-Trotter algorithm") + raise ValueError("no internal state directions were given for non-identity starting permutation for Steinhaus-Johnson-Trotter algorithm") self._directions = [-1] * self._n # The first element has null direction. diff --git a/src/sage/combinat/affine_permutation.py b/src/sage/combinat/affine_permutation.py index 4147116c105..bf3614c7f48 100644 --- a/src/sage/combinat/affine_permutation.py +++ b/src/sage/combinat/affine_permutation.py @@ -2,6 +2,7 @@ r""" Affine permutations """ + # **************************************************************************** # Copyright (C) 2013 Tom Denton # @@ -1319,7 +1320,7 @@ def check(self) -> None: # of the zeroth entry. s = sum(-i // self.N + 1 for j in range(1, self.N + 1) if (i := self.value(j)) < 0) if s % 2: - raise ValueError("type B affine permutations have an even number of " "entries less than 0 to the right of the 0th position") + raise ValueError("type B affine permutations have an even number of entries less than 0 to the right of the 0th position") def apply_simple_reflection_right(self, i) -> AffinePermutationTypeB: r""" @@ -1480,11 +1481,11 @@ def check(self) -> None: # the kth entry. s = sum(i // self.N + 1 - (i % self.N <= self.k) for j in range(-self.k, self.k + 1) if (i := self.value(j)) > self.k) if s % 2: - raise ValueError("type D affine permutations have an even number of entries" " greater than x.k weakly to the left of the x.k position") + raise ValueError("type D affine permutations have an even number of entries greater than x.k weakly to the left of the x.k position") # Check that we have an even number of 'small' elements right of the zeroth entry. s = sum(-i // self.N + 1 for j in range(1, self.N + 1) if (i := self.value(j)) < 0) if s % 2: - raise ValueError("type D affine permutations have an even number of entries" " less than 0 to the right of the 0th position") + raise ValueError("type D affine permutations have an even number of entries less than 0 to the right of the 0th position") def apply_simple_reflection_right(self, i) -> AffinePermutationTypeD: r""" @@ -1644,11 +1645,11 @@ def check(self) -> None: # Check that we have an even number of 'big' elements left of the 7th entry. s = sum(i // 6 - (i % 6 == 0) for i in self if i > 6) if s % 2: - raise ValueError("type G affine permutations have an even number of" " entries greater than 6 to the left of the 7th position") + raise ValueError("type G affine permutations have an even number of entries greater than 6 to the left of the 7th position") # Check that we have an even number of 'small' elements right of the zeroth entry. s = sum(-i // 6 + 1 for i in self if i <= 0) if s % 2: - raise ValueError("type G affine permutations have an even number of" " entries less than 0 to the right of the 0th position") + raise ValueError("type G affine permutations have an even number of entries less than 0 to the right of the 0th position") def value(self, i, base_window=False): r""" @@ -2051,7 +2052,7 @@ def _test_enumeration(self, n=4, **options): W = self.weyl_group() I = W.weak_order_ideal(ConstantFunction(True), side='right') n2 = len(list(I.elements_of_depth_iterator(n))) - tester.assertEqual(n1, n2, "number of (ranked) elements of affine" " permutation group disagrees with Weyl group") + tester.assertEqual(n1, n2, "number of (ranked) elements of affine permutation group disagrees with Weyl group") def weyl_group(self): r""" diff --git a/src/sage/combinat/bijectionist.py b/src/sage/combinat/bijectionist.py index d656c12eca6..9409021ffbd 100644 --- a/src/sage/combinat/bijectionist.py +++ b/src/sage/combinat/bijectionist.py @@ -362,6 +362,7 @@ ... ValueError: no possible values found for singleton block [[1, 2]] """ + # **************************************************************************** # Copyright (C) 2020 Martin Rubey # Stephan Pfannerer diff --git a/src/sage/combinat/binary_recurrence_sequences.py b/src/sage/combinat/binary_recurrence_sequences.py index d6ed543f4ed..9a2588da65c 100644 --- a/src/sage/combinat/binary_recurrence_sequences.py +++ b/src/sage/combinat/binary_recurrence_sequences.py @@ -59,7 +59,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.structure.sage_object import SageObject from sage.rings.finite_rings.integer_mod_ring import Integers from sage.rings.finite_rings.finite_field_constructor import GF @@ -633,7 +632,6 @@ def pthpowers(self, p, Bound): # may be many ``p`` th powers or no ``p`` th powers. elif (self.b**2 + 4 * self.c) == 0: - # This is the case if the matrix F is not diagonalizable, ie b^2 +4c = 0, and alpha/beta = 1. alpha = self.b / 2 @@ -644,7 +642,6 @@ def pthpowers(self, p, Bound): # Look at classes n = k mod p, for k = 1,...,p. for k in range(1, p + 1): - # The linear equation alpha^(k-1)*u_0 + (k+pm)*(alpha^(k-1)*u1 - u0*alpha^k) # must thus be a pth power. This is a linear equation in m, namely, A + B*m, where @@ -675,9 +672,7 @@ def pthpowers(self, p, Bound): # the list of known indices corresponding to ``p`` th powers is complete. else: - if Bound < 3 * p: - powers = [] ell = p + 1 @@ -690,7 +685,6 @@ def pthpowers(self, p, Bound): bf, cf = F(self.b), F(self.c) for n in range(Bound): # n is the index of the a0 - # Check whether a0 is a perfect power mod ell if _is_p_power_mod(a0, p, ell): # if a0 is a perfect power mod ell, check if nth term is ppower @@ -700,7 +694,6 @@ def pthpowers(self, p, Bound): a0, a1 = a1, bf * a1 + cf * a0 # step up the variables else: - powers = [] # documents the indices of the sequence that provably correspond to pth powers cong = [0] # list of necessary congruences on the index for it to correspond to pth powers Possible_count = {} # keeps track of the number of rounds a congruence lasts in cong @@ -713,7 +706,6 @@ def pthpowers(self, p, Bound): # This loop ups the modulus. while True: - # Try to get good data mod M2 # patience of how long we should search for a "good prime" @@ -722,11 +714,9 @@ def pthpowers(self, p, Bound): # This loop uses primes to get a small set of congruences mod M2. while True: - # only proceed if took less than patience time to find the next good prime ell = _next_good_prime(p, self, qq, patience, qqold) if ell: - # gather congruence data for the sequence mod ell, which will be mod period(ell) = modu cong1, modu = _find_cong1(p, self, ell) @@ -932,11 +922,9 @@ def _next_good_prime(p, R, qq, patience, qqold): # we require that R._ell is 1 mod p, so that p divides the order of the multiplicative # group mod R._ell, so that not all elements of GF(R._ell) are pth powers. if R._ell % p == 1: - # requiring that b^2 + 4c is a square in GF(R._ell) ensures that the period mod R._ell # divides R._ell - 1 if legendre_symbol(R.b**2 + 4 * R.c, R._ell) == 1: - N = _goodness(R._ell, R, p) # proceed only if R._ell satisfies the goodness requirements @@ -981,7 +969,6 @@ def _is_p_power_mod(a, p, N): # a is a pth power mod q^e, for all distinct prime powers q^e dividing N. for q, e in N.factor(): - # If a = q^v*x, with v = a.valuation(q) @@ -1009,12 +996,10 @@ def _is_p_power_mod(a, p, N): # mod q^2, etc. if q != p: - # aa is necessarily a pth power mod q if p does not divide the order of the multiplicative # group mod q, ie if q is not 1 mod p. if q % p == 1: - # otherwise aa if a pth power mod q iff aa^(q-1)/p == 1 if GF(q)(aa) ** ((q - 1) / p) != 1: @@ -1023,12 +1008,10 @@ def _is_p_power_mod(a, p, N): # If q = p and ee = 1, then everything is a pth power p by Fermat's little theorem. elif ee > 1: - # We use the strong statement of Hensel's lemma, which implies that if p is odd # and aa is a pth power mod p^2, then aa is a pth power mod any higher power of p if p % 2: - # ZZ/(p^2)ZZ^\times is abstractly isomorphic to ZZ/(p)ZZ cross ZZ/(p-1)ZZ. then # aa is a pth power mod p^2 if (aa)^(p*(p-1)/p) == 1, ie if aa^(p-1) == 1. @@ -1040,7 +1023,6 @@ def _is_p_power_mod(a, p, N): # is a pth power mod p^2 and p^3. elif ee == 2: - # all odd squares a 1 mod 4 if aa % 4 != 1: @@ -1127,7 +1109,6 @@ def _find_cong1(p, R, ell): cong1 = [] for n in range(modu): # n is the index of the a0 - # Check whether a0 is a perfect power mod ell if a0 in PPowers: # if a0 is a perfect power mod ell, add the index diff --git a/src/sage/combinat/binary_tree.py b/src/sage/combinat/binary_tree.py index 339cfaa7a71..0767657d2f3 100644 --- a/src/sage/combinat/binary_tree.py +++ b/src/sage/combinat/binary_tree.py @@ -750,7 +750,6 @@ def graph(self, with_leaves=True): from sage.graphs.digraph import DiGraph if with_leaves: # We want leaves and nodes. - # Special treatment for the case when self is empty. # In this case, rec(self, 0) would give a false result. if not self: @@ -4078,7 +4077,6 @@ def from_tamari_sorting_tuple(key): class BinaryTrees_all(DisjointUnionEnumeratedSets, BinaryTrees): - def __init__(self): """ TESTS:: diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index ed8c52d2997..efc58b4c320 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -256,7 +256,7 @@ def __init__(self, data, frozen=None, is_principal=False, user_labels=None, user # constructs a cluster seed from a cluster seed if isinstance(data, ClusterSeed): if frozen: - print("The input \'frozen\' is ignored") + print("The input 'frozen' is ignored") # Copy the following attributes from data self._M = copy(data._M) @@ -340,7 +340,7 @@ def __init__(self, data, frozen=None, is_principal=False, user_labels=None, user # Sanitizes our ``user_labels`` to use Integers instead of ints user_labels = [Integer(x) if x in ZZ else x for x in user_labels] if labelset != set(self._nlist + self._mlist) and labelset != set(range(self._n + self._m)): - raise ValueError('user_labels conflict with both the given' ' vertex labels and the default labels') + raise ValueError('user_labels conflict with both the given vertex labels and the default labels') # We are now updating labels from user's most recent choice. self._is_principal = is_principal @@ -687,7 +687,6 @@ def use_fpolys(self, use=True, user_labels=None, user_labels_prefix=None): self._use_fpolys = use if self._use_fpolys: - if user_labels: self._sanitize_init_vars(user_labels, user_labels_prefix) else: @@ -867,7 +866,7 @@ def _sanitize_init_vars(self, user_labels, user_labels_prefix='x'): raise ValueError("the input 'user_labels' must be a dictionary or a list") if len(self._init_vars) != self._n + self._m: - raise ValueError("the number of user-defined labels is not the" " number of exchangeable and frozen variables") + raise ValueError("the number of user-defined labels is not the number of exchangeable and frozen variables") def set_c_matrix(self, data): r""" @@ -2462,7 +2461,7 @@ def mutate(self, sequence, inplace=True, input_type=None): # check for sanitizable data if not isinstance(inplace, bool): - raise ValueError("the second parameter must be boolean; to mutate" " at a sequence of length 2, input it as a list") + raise ValueError("the second parameter must be boolean; to mutate at a sequence of length 2, input it as a list") if inplace: seed = self @@ -2522,7 +2521,7 @@ def mutate(self, sequence, inplace=True, input_type=None): if isinstance(seqq, tuple): seqq = list(seqq) if not isinstance(seqq, list): - raise ValueError("the quiver can only be mutated at a vertex" " or at a sequence of vertices") + raise ValueError("the quiver can only be mutated at a vertex or at a sequence of vertices") # These boolean variables classify the input type is_vertices = set(seqq).issubset(set(seed._nlist)) @@ -2535,30 +2534,30 @@ def mutate(self, sequence, inplace=True, input_type=None): # Ensures the sequence has elements of type input_type. if input_type: if input_type == "vertices" and not is_vertices: - raise ValueError('input_type set to "vertices" but not everything' ' in the mutation sequence is a vertex.') + raise ValueError('input_type set to "vertices" but not everything in the mutation sequence is a vertex.') elif input_type == "indices" and not is_indices: - raise ValueError('input_type set to "indices" but not everything' ' in the mutation sequence is an index.') + raise ValueError('input_type set to "indices" but not everything in the mutation sequence is an index.') elif input_type == "cluster_vars" and not is_cluster_vars: - raise ValueError('input_type set to "cluster_vars" but not' ' everything in the mutation sequence is a' ' cluster variable.') + raise ValueError('input_type set to "cluster_vars" but not everything in the mutation sequence is a cluster variable.') elif input_type not in ["vertices", "indices", "cluster_vars"]: - raise ValueError('input_type must be either "vertices",' ' "indices", or "cluster_vars"') + raise ValueError('input_type must be either "vertices", "indices", or "cluster_vars"') # Classifies the input_type. Raises warnings if the input is ambiguous, and errors if the input is not all of the same type. elif is_vertices: input_type = "vertices" for x in seqq: if is_indices and seed._nlist[x] != x: - print("Input can be ambiguously interpreted as both" " vertices and indices." " Mutating at vertices by default.") + print("Input can be ambiguously interpreted as both vertices and indices. Mutating at vertices by default.") break elif is_cluster_vars: cluster_var_index = seed.cluster_index(x) vertex_index = seed._nlist.index(x) if isinstance(cluster_var_index, int) and cluster_var_index != vertex_index: - print("Input can be ambiguously interpreted as" " both vertices and cluster variables." " Mutating at vertices by default.") + print("Input can be ambiguously interpreted as both vertices and cluster variables. Mutating at vertices by default.") break # It should be impossible to interpret an index as a cluster variable. @@ -2567,7 +2566,7 @@ def mutate(self, sequence, inplace=True, input_type=None): elif is_cluster_vars: input_type = "cluster_vars" else: - raise ValueError('mutation sequences must consist of exactly' ' one of vertices, indices, or cluster variables') + raise ValueError('mutation sequences must consist of exactly one of vertices, indices, or cluster variables') if input_type == "cluster_vars" and len(seqq) > 1: mutation_seed = deepcopy(seed) @@ -2578,7 +2577,7 @@ def mutate(self, sequence, inplace=True, input_type=None): mutation_seed.mutate(new_index, input_type='indices') index_list.append(new_index) except (ValueError, TypeError): - raise ValueError('input interpreted as cluster variables,' ' but the input sequence did not consist' ' of cluster variables') + raise ValueError('input interpreted as cluster variables, but the input sequence did not consist of cluster variables') input_type = "indices" seqq = index_list @@ -3058,9 +3057,9 @@ def universal_extension(self): True """ if self._m != 0: - raise ValueError("To have universal coefficients we need " "to start from a coefficient-free seed") + raise ValueError("To have universal coefficients we need to start from a coefficient-free seed") if not self.is_bipartite() or not self.is_finite(): - raise ValueError("Universal coefficients are defined only " "for finite type cluster algebras at a " "bipartite initial cluster") + raise ValueError("Universal coefficients are defined only for finite type cluster algebras at a bipartite initial cluster") from sage.matrix.constructor import matrix from sage.combinat.root_system.cartan_matrix import CartanMatrix @@ -3341,7 +3340,7 @@ def reset_coefficients(self): """ n, m = self._n, self._m if not n == m: - raise ValueError("The numbers of cluster variables " "and of frozen variables do not coincide.") + raise ValueError("The numbers of cluster variables and of frozen variables do not coincide.") newM = copy(self._M) for i in range(m): for j in range(n): @@ -4221,9 +4220,9 @@ def greedy(self, a1, a2, algorithm='by_recursion'): if p != 0 or q != 0: ans += coeff_recurs(p, q, a1, a2, b, c) return ans - raise ValueError("The third input should be 'by_recursion', " "'by_combinatorics', or 'just_numbers'.") + raise ValueError("The third input should be 'by_recursion', 'by_combinatorics', or 'just_numbers'.") else: - raise ValueError("Greedy elements are only currently " "defined for cluster seeds of rank two.") + raise ValueError("Greedy elements are only currently defined for cluster seeds of rank two.") def oriented_exchange_graph(self): """ diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver.py b/src/sage/combinat/cluster_algebra_quiver/quiver.py index 278b908ddf6..e0204013a57 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver.py @@ -32,6 +32,7 @@ For mutation types of combinatorial quivers, see :meth:`~sage.combinat.cluster_algebra_quiver.quiver_mutation_type.QuiverMutationType`. Cluster seeds are closely related to :meth:`~sage.combinat.cluster_algebra_quiver.cluster_seed.ClusterSeed`. """ + # **************************************************************************** # Copyright (C) 2011 Gregg Musiker # Christian Stump @@ -241,7 +242,7 @@ def __init__(self, data, frozen=None, user_labels=None) -> None: # constructs a quiver from a mutation type if isinstance(data, (QuiverMutationType_Irreducible, QuiverMutationType_Reducible)): if frozen is not None: - print('The input specifies a mutation type, so the' ' additional parameter frozen is ignored.' ' Use set_frozen to freeze vertices.') + print('The input specifies a mutation type, so the additional parameter frozen is ignored. Use set_frozen to freeze vertices.') mutation_type = data self.__init__(mutation_type.standard_quiver()) @@ -256,7 +257,7 @@ def __init__(self, data, frozen=None, user_labels=None) -> None: # in how to input a connected (irreducible) quiver. elif isinstance(data, (list, tuple)) and (isinstance(data[0], str) or all(isinstance(comp, (list, tuple)) and isinstance(comp[0], str) for comp in data)): if frozen is not None: - print('The input specifies a mutation type, so the additional' ' parameter frozen is ignored. Use set_frozen to freeze vertices.') + print('The input specifies a mutation type, so the additional parameter frozen is ignored. Use set_frozen to freeze vertices.') mutation_type = QuiverMutationType(data) # The command QuiverMutationType_Irreducible (which is not imported @@ -323,7 +324,7 @@ def __init__(self, data, frozen=None, user_labels=None) -> None: # constructs a quiver from a quiver elif isinstance(data, ClusterQuiver): if frozen is not None: - print('The input data is a quiver, therefore the additional' ' parameter frozen is ignored. Use set_frozen to freeze vertices.') + print('The input data is a quiver, therefore the additional parameter frozen is ignored. Use set_frozen to freeze vertices.') self._M = copy(data._M) self._M.set_immutable() @@ -411,7 +412,7 @@ def __init__(self, data, frozen=None, user_labels=None) -> None: multi_edges = {} for v1, v2, label in multiple_edges: if label not in ZZ: - raise ValueError("the input DiGraph contains multiple" " edges labeled by non-integers") + raise ValueError("the input DiGraph contains multiple edges labeled by non-integers") elif (v1, v2) in multi_edges: multi_edges[(v1, v2)] += label else: @@ -421,7 +422,7 @@ def __init__(self, data, frozen=None, user_labels=None) -> None: for e0, e1, lab in dg.edge_iterator(): if e0 >= n and e1 >= n: - raise ValueError("the input digraph contains edges" " within the frozen vertices") + raise ValueError("the input digraph contains edges within the frozen vertices") if lab is None: lab = (1, -1) dg.set_edge_label(e0, e1, lab) @@ -429,14 +430,14 @@ def __init__(self, data, frozen=None, user_labels=None) -> None: lab = (lab, -lab) dg.set_edge_label(e0, e1, lab) elif isinstance(lab, list) and len(lab) != 2: - raise ValueError("the input digraph contains an edge with" " the wrong type of list as a label") + raise ValueError("the input digraph contains an edge with the wrong type of list as a label") elif isinstance(lab, list) and len(lab) == 2: lab = tuple(lab) dg.set_edge_label(e0, e1, lab) elif (e0 >= n or e1 >= n) and not lab[0] == -lab[1]: - raise ValueError("the input digraph contains an edge to or" " from a frozen vertex which is not skew-symmetric") + raise ValueError("the input digraph contains an edge to or from a frozen vertex which is not skew-symmetric") if lab[0] < 0: - raise ValueError("the input digraph contains an edge of " "the form (a,-b) with negative a") + raise ValueError("the input digraph contains an edge of the form (a,-b) with negative a") M = _edge_list_to_matrix(dg.edge_iterator(), list(range(n)), list(range(n, n + m))) if not _principal_part(M).is_skew_symmetrizable(positive=True): @@ -589,7 +590,6 @@ def _graphs_concentric_circles(n, m): # For each edge in our graph we assign a color for v1, v2, ab in dg.edges(sort=True): - if v1 in nlist and v2 in nlist: if ab == (1, -1): color_dict[colors[0]].append((v1, v2)) @@ -609,7 +609,6 @@ def _graphs_concentric_circles(n, m): # If a mark is given, then we set that mark apart from the rest # The mark is assumed to be a vertex if mark is not None: - if mark in nlist: nlist.remove(mark) partition = (nlist, mlist, [mark]) @@ -619,7 +618,6 @@ def _graphs_concentric_circles(n, m): else: raise ValueError("the given mark is not a vertex of self") else: - # Partition out the green vertices for i in greens: if i in nlist: @@ -1508,7 +1506,7 @@ def mutation_sequence(self, sequence, show_sequence=False, fig_size=1.2): if isinstance(sequence, tuple): sequence = list(sequence) if not isinstance(sequence, list): - raise ValueError('the quiver can only be mutated at a vertex' ' or at a sequence of vertices') + raise ValueError('the quiver can only be mutated at a vertex or at a sequence of vertices') if any(v not in V for v in sequence): v = next(v for v in sequence if v not in V) raise ValueError(f'the quiver can only be mutated at the vertex {v}') @@ -1611,7 +1609,7 @@ def reorient(self, data): self._M.set_immutable() self._mutation_type = None else: - raise ValueError('not a total order on the vertices of the quiver' ' or a list of edges to be oriented') + raise ValueError('not a total order on the vertices of the quiver or a list of edges to be oriented') def mutation_class_iter(self, depth=infinity, show_depth=False, return_paths=False, data_type='quiver', up_to_equivalence=True, sink_source=False): """ @@ -1745,7 +1743,7 @@ def mutation_class_iter(self, depth=infinity, show_depth=False, return_paths=Fal elif data_type == "path": next_element = data[1] else: - raise ValueError("the parameter for data_type was " "not recognized") + raise ValueError("the parameter for data_type was not recognized") if return_paths: yield (next_element, data[1]) else: @@ -1851,7 +1849,7 @@ def mutation_class(self, depth=infinity, show_depth=False, return_paths=False, d True """ if depth is infinity and not self.is_mutation_finite(): - raise ValueError('the mutation class can - for infinite mutation' ' types - only be computed up to a given depth') + raise ValueError('the mutation class can - for infinite mutation types - only be computed up to a given depth') return list(self.mutation_class_iter(depth=depth, show_depth=show_depth, return_paths=return_paths, data_type=data_type, up_to_equivalence=up_to_equivalence, sink_source=sink_source)) def is_finite(self) -> bool: diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py index 8be3d2138fe..d20766bb6ad 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py @@ -8,6 +8,7 @@ - Christian Stump (2012, initial version) - Hugh Thomas (2012, initial version) """ + # **************************************************************************** # Copyright (C) 2011 Gregg Musiker # Christian Stump @@ -1628,7 +1629,7 @@ def __init__(self, letter, rank, twist=None): if self._graph.is_bipartite(): self._digraph = _bipartite_graph_to_digraph(self._graph) else: - raise ValueError('The QuiverMutationType does not have ' 'a Coxeter diagram.') + raise ValueError('The QuiverMutationType does not have a Coxeter diagram.') # in the other cases, the graph is constructed from the digraph if not self._graph: @@ -1739,7 +1740,7 @@ def class_size(self): elif self._letter in ['BB', 'CC']: # these two formulas are not yet proven - print("Warning: This method uses a formula " "which has not been proved correct.") + print("Warning: This method uses a formula which has not been proved correct.") if self.is_affine(): if self._twist == 1: n = self._rank - 1 @@ -1751,7 +1752,7 @@ def class_size(self): # type BC (affine) elif self._letter == 'BC': # this formula is not yet proven - print("Warning: This method uses a formula " "which has not been proved correct.") + print("Warning: This method uses a formula which has not been proved correct.") if self.is_affine(): if self._twist == 1: n = self._rank - 1 @@ -1760,7 +1761,7 @@ def class_size(self): # types BD and CD (affine) elif self._letter in ['BD', 'CD']: # this formula is not yet proven - print("Warning: This method uses a formula " "which has not been proved correct.") + print("Warning: This method uses a formula which has not been proved correct.") if self.is_affine(): if self._twist == 1: n = self._rank - 2 @@ -1780,7 +1781,7 @@ def class_size(self): n = self._rank - 3 if n == 2: return 9 - print("Warning: This method uses a formula " "which has not been proved correct.") + print("Warning: This method uses a formula which has not been proved correct.") if n % 2: return 2 * binomial(2 * n, n) return 2 * binomial(2 * n, n) + binomial(n, n // 2) @@ -2205,7 +2206,7 @@ def _save_data_dig6(n, types='ClassicalExceptional', verbose=False): data = {} possible_types = ['Classical', 'ClassicalExceptional', 'Exceptional'] if types not in possible_types: - raise ValueError('The third input must be either ClassicalExceptional' ' (default), Classical, or Exceptional.') + raise ValueError('The third input must be either ClassicalExceptional (default), Classical, or Exceptional.') if types in possible_types[:2]: data.update(_construct_classical_mutation_classes(n)) diff --git a/src/sage/combinat/cluster_complex.py b/src/sage/combinat/cluster_complex.py index 920bc6c0b65..be6234d2c47 100644 --- a/src/sage/combinat/cluster_complex.py +++ b/src/sage/combinat/cluster_complex.py @@ -188,7 +188,7 @@ def __classcall__(cls, W, k=1, coxeter_element=None, algorithm='inductive'): True """ if k not in NN: - raise ValueError("the additional parameter must be a " "nonnegative integer") + raise ValueError("the additional parameter must be a nonnegative integer") if W not in CoxeterGroups: W = CoxeterGroup(W) diff --git a/src/sage/combinat/combinatorial_map.py b/src/sage/combinat/combinatorial_map.py index 376bd5eab43..406a05ca1a1 100644 --- a/src/sage/combinat/combinatorial_map.py +++ b/src/sage/combinat/combinatorial_map.py @@ -55,7 +55,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from typing import Self diff --git a/src/sage/combinat/constellation.py b/src/sage/combinat/constellation.py index e372cf2c2ad..5573811665a 100644 --- a/src/sage/combinat/constellation.py +++ b/src/sage/combinat/constellation.py @@ -296,7 +296,7 @@ def switch(self, i, j0, j1): sage: c._check() """ if not self._mutable: - raise ValueError("this constellation is immutable." " Take a mutable copy first.") + raise ValueError("this constellation is immutable. Take a mutable copy first.") S = SymmetricGroup(list(range(self.degree()))) tr = S((j0, j1)) i = int(i) @@ -771,7 +771,7 @@ def relabel(self, perm=None, return_map=False): # compute canonical labels if not self.is_connected(): - raise ValueError("no canonical labels implemented for" " non connected constellation") + raise ValueError("no canonical labels implemented for non connected constellation") # get the permutations on {0, 1, ..., d-1} # compute the canonical labels @@ -1326,7 +1326,7 @@ def __init__(self, profile, domain=None, connected=True): d = Integer(sum(profile[0])) for p in profile: if sum(p) != d: - raise ValueError("all partition in the passport should " "have the same sum.") + raise ValueError("all partition in the passport should have the same sum.") if domain is None: sym = SymmetricGroup(d) else: diff --git a/src/sage/combinat/crystals/affine_factorization.py b/src/sage/combinat/crystals/affine_factorization.py index e3bafd8106d..6d2947b47ec 100644 --- a/src/sage/combinat/crystals/affine_factorization.py +++ b/src/sage/combinat/crystals/affine_factorization.py @@ -232,7 +232,6 @@ def mg_to_shape(mg): return phi class Element(ElementWrapper): - def e(self, i): r""" Return the action of `e_i` on ``self``. diff --git a/src/sage/combinat/crystals/alcove_path.py b/src/sage/combinat/crystals/alcove_path.py index 38035463dad..223ad4adb98 100644 --- a/src/sage/combinat/crystals/alcove_path.py +++ b/src/sage/combinat/crystals/alcove_path.py @@ -845,7 +845,6 @@ def _folding_data(self, i): c2 = min(max_height_Beta, J[j + 1]._cmp_v[0] * max_height_Beta + 1) for k in range(int(c1), int(c2)): - x = R(sign_Beta * Beta, k) if (j < len(J) - 1 and J[j] < x <= J[j + 1]) or (j == len(J) - 1 and J[j] < x): @@ -1004,7 +1003,6 @@ def f(self, i): m_index = gi.index(m) if finite_cartan_type and i == 0: - # python doesn't handle fractions natively M = Integer(m) / 2 + Integer(1) / 2 else: diff --git a/src/sage/combinat/crystals/fully_commutative_stable_grothendieck.py b/src/sage/combinat/crystals/fully_commutative_stable_grothendieck.py index 9bd8fd2707e..5487e6b43e2 100644 --- a/src/sage/combinat/crystals/fully_commutative_stable_grothendieck.py +++ b/src/sage/combinat/crystals/fully_commutative_stable_grothendieck.py @@ -841,7 +841,7 @@ def _check_containment(t, parent): if factors != parent.factors: raise ValueError("number of factors do not match") if w != parent.w: - raise ValueError("self and parent must be specified based " "on equivalent words") + raise ValueError("self and parent must be specified based on equivalent words") if excess != parent.excess: raise ValueError("number of excess letters do not match") diff --git a/src/sage/combinat/crystals/kirillov_reshetikhin.py b/src/sage/combinat/crystals/kirillov_reshetikhin.py index 226382beec7..c40ec7e16f0 100644 --- a/src/sage/combinat/crystals/kirillov_reshetikhin.py +++ b/src/sage/combinat/crystals/kirillov_reshetikhin.py @@ -2587,7 +2587,7 @@ def _element_constructor_(self, *args, **options): elt = args[0] # Check to make sure it can be converted if elt.cartan_type() != self.cartan_type() or elt.parent().r() != self._r or elt.parent().s() != self._s: - raise ValueError("the Kirillov-Reshetikhin tableau must have" " the same Cartan type and shape") + raise ValueError("the Kirillov-Reshetikhin tableau must have the same Cartan type and shape") to_hw = elt.to_classical_highest_weight() wt = to_hw[0].classical_weight() diff --git a/src/sage/combinat/crystals/star_crystal.py b/src/sage/combinat/crystals/star_crystal.py index 3eaf9b8265a..7635ab0b8f4 100644 --- a/src/sage/combinat/crystals/star_crystal.py +++ b/src/sage/combinat/crystals/star_crystal.py @@ -122,7 +122,6 @@ def _repr_(self): return "Star-crystal version of %s" % self._Binf class Element(ElementWrapper): - def e(self, i): r""" Return the action of `e_i^*` on ``self``. diff --git a/src/sage/combinat/crystals/subcrystal.py b/src/sage/combinat/crystals/subcrystal.py index 8c75ee7427f..938659845c0 100644 --- a/src/sage/combinat/crystals/subcrystal.py +++ b/src/sage/combinat/crystals/subcrystal.py @@ -247,7 +247,7 @@ def __contains__(self, x): # TODO: make this work for infinite crystals import warnings - warnings.warn("Testing containment in an infinite crystal" " defaults to returning True") + warnings.warn("Testing containment in an infinite crystal defaults to returning True") return True def cardinality(self): diff --git a/src/sage/combinat/cyclic_sieving_phenomenon.py b/src/sage/combinat/cyclic_sieving_phenomenon.py index 9583bd8ed62..12aedb5c6be 100644 --- a/src/sage/combinat/cyclic_sieving_phenomenon.py +++ b/src/sage/combinat/cyclic_sieving_phenomenon.py @@ -98,7 +98,7 @@ def CyclicSievingPolynomial(L, cyc_act=None, order=None, get_order=False): if order: if order.mod(n): - raise ValueError("order is not a multiple of the order" " of the cyclic action") + raise ValueError("order is not a multiple of the order of the cyclic action") else: order = n diff --git a/src/sage/combinat/designs/bibd.py b/src/sage/combinat/designs/bibd.py index 9ff0128854e..9d22c396087 100644 --- a/src/sage/combinat/designs/bibd.py +++ b/src/sage/combinat/designs/bibd.py @@ -502,7 +502,6 @@ def steiner_triple_system(n): sts = [[(i, 0), (i, 1), (i, 2)] for i in Z] + [[(i, k), (j, k), (((t + 1) * (i + j)) % (2 * t + 1), (k + 1) % 3)] for k in range(3) for i in Z for j in Z if i != j] elif n % 6 == 1: - t = (n - 1) // 6 N = list(range(2 * t)) T = lambda x_y: x_y[0] + x_y[1] * t * 2 if x_y != (-1, -1) else n - 1 @@ -601,7 +600,6 @@ def BIBD_from_TD(v, k, existence=False): """ # First construction if v % k == 0 and balanced_incomplete_block_design(v // k, k, existence=True) is True and transversal_design(k, v // k, existence=True) is True: - if existence: return True @@ -615,7 +613,6 @@ def BIBD_from_TD(v, k, existence=False): # Second construction elif ((v - 1) % k == 0 and balanced_incomplete_block_design((v - 1) // k + 1, k, existence=True) is True and transversal_design(k, (v - 1) // k, existence=True)) is True: - if existence: return True diff --git a/src/sage/combinat/designs/block_design.py b/src/sage/combinat/designs/block_design.py index 9134ea5236a..37ff9847f84 100644 --- a/src/sage/combinat/designs/block_design.py +++ b/src/sage/combinat/designs/block_design.py @@ -291,7 +291,7 @@ def ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=True, ch q = F.cardinality() if not B.is_t_design(t=2, v=q_binomial(n + 1, 1, q), k=q_binomial(d + 1, 1, q), l=q_binomial(n - 1, d - 1, q)): - raise RuntimeError("error in ProjectiveGeometryDesign " "construction. Please e-mail sage-devel@googlegroups.com") + raise RuntimeError("error in ProjectiveGeometryDesign construction. Please e-mail sage-devel@googlegroups.com") return B @@ -759,18 +759,18 @@ def projective_plane(n, check=True, existence=False): if n == 10: if existence: return False - ref = "C. Lam, L. Thiel and S. Swiercz \"The nonexistence of finite " "projective planes of order 10\" (1989), Canad. J. Math." + ref = "C. Lam, L. Thiel and S. Swiercz \"The nonexistence of finite projective planes of order 10\" (1989), Canad. J. Math." raise EmptySetError("No projective plane of order 10 exists by %s" % ref) if BruckRyserChowla_check(n * n + n + 1, n + 1, 1) is False: if existence: return False - raise EmptySetError("By the Bruck-Ryser theorem, no projective" " plane of order {} exists.".format(n)) + raise EmptySetError("By the Bruck-Ryser theorem, no projective plane of order {} exists.".format(n)) if not is_prime_power(n): if existence: return Unknown - raise NotImplementedError("If such a projective plane exists, we do " "not know how to build it.") + raise NotImplementedError("If such a projective plane exists, we do not know how to build it.") if existence: return True @@ -882,7 +882,7 @@ def AffineGeometryDesign(n, d, F, point_coordinates=True, check=True): if check: if not B.is_t_design(t=2, v=q**n, k=q**d, l=q_binomial(n - 1, d - 1, q)): - raise RuntimeError("error in AffineGeometryDesign " "construction. Please e-mail sage-devel@googlegroups.com") + raise RuntimeError("error in AffineGeometryDesign construction. Please e-mail sage-devel@googlegroups.com") return B diff --git a/src/sage/combinat/designs/difference_family.py b/src/sage/combinat/designs/difference_family.py index 9120fbe2040..2b6390b0aa5 100644 --- a/src/sage/combinat/designs/difference_family.py +++ b/src/sage/combinat/designs/difference_family.py @@ -597,7 +597,7 @@ def radical_difference_set(K, k, l=1, existence=False, check=True): x = K.multiplicative_generator() D = K.cyclotomic_cosets(x ** ((v - 1) // k), [K.one()]) if is_difference_family(K, D, v, k, l): - print("** You found a new example of radical difference set **\n" "** for the parameters (v,k,l)=({},{},{}). **\n" "** Please contact sage-devel@googlegroups.com **\n".format(v, k, l)) + print("** You found a new example of radical difference set **\n** for the parameters (v,k,l)=({},{},{}). **\n** Please contact sage-devel@googlegroups.com **\n".format(v, k, l)) if existence: return True add_zero = False @@ -606,7 +606,7 @@ def radical_difference_set(K, k, l=1, existence=False, check=True): D = K.cyclotomic_cosets(x ** ((v - 1) // (k - 1)), [K.one()]) D[0].insert(0, K.zero()) if is_difference_family(K, D, v, k, l): - print("** You found a new example of radical difference set **\n" "** for the parameters (v,k,l)=({},{},{}). **\n" "** Please contact sage-devel@googlegroups.com **\n".format(v, k, l)) + print("** You found a new example of radical difference set **\n** for the parameters (v,k,l)=({},{},{}). **\n** Please contact sage-devel@googlegroups.com **\n".format(v, k, l)) if existence: return True add_zero = True @@ -614,7 +614,7 @@ def radical_difference_set(K, k, l=1, existence=False, check=True): elif existence: return False else: - raise EmptySetError("no radical difference set exist " "for the parameters (v,k,l) = ({},{},{}".format(v, k, l)) + raise EmptySetError("no radical difference set exist for the parameters (v,k,l) = ({},{},{}".format(v, k, l)) x = K.multiplicative_generator() if add_zero: @@ -626,7 +626,7 @@ def radical_difference_set(K, k, l=1, existence=False, check=True): D = K.cyclotomic_cosets(r, [K.one()]) if check and not is_difference_family(K, D, v, k, l): - raise RuntimeError("Sage tried to build a radical difference set with " "parameters ({},{},{}) but it seems that it failed! Please " "e-mail sage-devel@googlegroups.com".format(v, k, l)) + raise RuntimeError("Sage tried to build a radical difference set with parameters ({},{},{}) but it seems that it failed! Please e-mail sage-devel@googlegroups.com".format(v, k, l)) return D @@ -913,7 +913,7 @@ def radical_difference_family(K, k, l=1, existence=False, check=True): return True if check and not is_difference_family(K, D, v, k, l): - raise RuntimeError("radical_difference_family produced a wrong " "difference family with parameters v={}, " "k={}, l={}. Please contact " "sage-devel@googlegroups.com".format(v, k, l)) + raise RuntimeError("radical_difference_family produced a wrong difference family with parameters v={}, k={}, l={}. Please contact sage-devel@googlegroups.com".format(v, k, l)) return D @@ -968,7 +968,7 @@ def twin_prime_powers_difference_set(p, check=True): G = cartesian_product([Fp, Fq]) if check and not is_difference_family(G, [d]): - raise RuntimeError("twin_prime_powers_difference_set produced a wrong " "difference set with p={}. Please contact " "sage-devel@googlegroups.com".format(p)) + raise RuntimeError("twin_prime_powers_difference_set produced a wrong difference set with p={}. Please contact sage-devel@googlegroups.com".format(p)) return G, [d] @@ -2060,7 +2060,7 @@ def skew_supplementary_difference_set_over_polynomial_ring(n, existence=False, c cosets = [] for i in range((n - 1) // (2 * order)): cosets.append([F.gen() ** i * el for el in H]) - cosets.append([-F.gen() ** i * el for el in H]) + cosets.append([-(F.gen() ** i) * el for el in H]) def generate_set(index_set, cosets): return sum((cosets[idx] for idx in index_set), []) @@ -2983,7 +2983,7 @@ def are_complementary_difference_sets(G, A, B, verbose=False): if not is_supplementary_difference_set([A, B], lmbda=m - 1, G=G): if verbose: - print(f'The sets are not supplementary difference sets with lambda = {m-1}') + print(f'The sets are not supplementary difference sets with lambda = {m - 1}') return False if not _is_skew_set(G, A): @@ -3629,7 +3629,7 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch df = [[G(i) for i in b] for b in blocks] if check and not is_difference_family(G, df, v=v, k=k, l=l): - raise RuntimeError("There is an invalid ({},{},{})-difference " "family in the database... Please contact " "sage-devel@googlegroups.com".format(v, k, l)) + raise RuntimeError("There is an invalid ({},{},{})-difference family in the database... Please contact sage-devel@googlegroups.com".format(v, k, l)) return G, df @@ -3652,7 +3652,7 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch xe = G.multiplicative_generator() ** e df = [[xe**j * b for b in B] for j in range((v - 1) // (2 * e))] if check and not is_difference_family(G, df, v=v, k=k, l=l): - raise RuntimeError("There is an invalid ({},{})-evenly distributed " "set in the database... Please contact " "sage-devel@googlegroups.com".format(v, k)) + raise RuntimeError("There is an invalid ({},{})-evenly distributed set in the database... Please contact sage-devel@googlegroups.com".format(v, k)) return G, df if k in [0, 1]: @@ -3783,7 +3783,7 @@ def difference_family(v, k, l=1, existence=False, explain_construction=False, ch raise NotImplementedError("No constructions for these parameters") if check and not is_difference_family(G, D, v=v, k=k, l=l, verbose=False): - raise RuntimeError("There is a problem. Sage built the following " "difference family on G='{}' with parameters ({},{},{}):\n " "{}\nwhich seems to not be a difference family... " "Please contact sage-devel@googlegroups.com".format(G, v, k, l, D)) + raise RuntimeError("There is a problem. Sage built the following difference family on G='{}' with parameters ({},{},{}):\n {}\nwhich seems to not be a difference family... Please contact sage-devel@googlegroups.com".format(G, v, k, l, D)) return G, D diff --git a/src/sage/combinat/designs/incidence_structures.py b/src/sage/combinat/designs/incidence_structures.py index b794ef44971..2ce25c9bfa7 100644 --- a/src/sage/combinat/designs/incidence_structures.py +++ b/src/sage/combinat/designs/incidence_structures.py @@ -2113,10 +2113,10 @@ def coloring(self, k=None, solver=None, verbose=0, *, integrality_tolerance=1e-3 raise ValueError("Only empty hypergraphs are 0-chromatic") return [] if any(len(x) == 1 for x in self._blocks): - raise RuntimeError("No coloring can be defined " "when there is a set of size 1") + raise RuntimeError("No coloring can be defined when there is a set of size 1") elif k == 1: if any(self._blocks): - raise ValueError("This hypergraph contains a set. " "It is not 1-chromatic") + raise ValueError("This hypergraph contains a set. It is not 1-chromatic") return [self.ground_set()] from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException @@ -2272,7 +2272,7 @@ def _latex_(self) -> str: latex.add_package_to_preamble_if_available("tikz") if not latex.has_file("tikz.sty"): - raise RuntimeError("You must have TikZ installed in order " "to draw a hypergraph.") + raise RuntimeError("You must have TikZ installed in order to draw a hypergraph.") domain = self.ground_set() pos = self._spring_layout() @@ -2290,7 +2290,7 @@ def _latex_(self) -> str: tex += "\\draw[color=" + str(current_color) + "," + "line width=.1cm,opacity = .6] " + str(pos[s[0]]) + " -- " + str(pos[s[1]]) + ";\n" continue - tex += "\\draw[color=" + str(current_color) + "," "line width=.1cm,opacity = .6," "line cap=round," "line join=round]" "plot [smooth cycle,tension=1] coordinates {" + tex += "\\draw[color=" + str(current_color) + ",line width=.1cm,opacity = .6,line cap=round,line join=round]plot [smooth cycle,tension=1] coordinates {" # Reorders the vertices of s according to their angle with the # "center", i.e. the vertex representing the set s diff --git a/src/sage/combinat/designs/latin_squares.py b/src/sage/combinat/designs/latin_squares.py index 9b779c8e632..f4d5ab3d3c1 100644 --- a/src/sage/combinat/designs/latin_squares.py +++ b/src/sage/combinat/designs/latin_squares.py @@ -122,6 +122,7 @@ Functions --------- """ + from itertools import repeat from sage.rings.integer import Integer from sage.categories.sets_cat import EmptySetError diff --git a/src/sage/combinat/designs/orthogonal_arrays.py b/src/sage/combinat/designs/orthogonal_arrays.py index fa99694e264..6debc90c446 100644 --- a/src/sage/combinat/designs/orthogonal_arrays.py +++ b/src/sage/combinat/designs/orthogonal_arrays.py @@ -347,7 +347,6 @@ def transversal_design(k, n, resolvable=False, check=True, existence=False): # Section 6.6 of [Stinson2004] elif orthogonal_array(k, n, existence=True) is not Unknown: - # Forwarding non-existence results if orthogonal_array(k, n, existence=True): if existence: @@ -1306,7 +1305,7 @@ def incomplete_orthogonal_array(k, n, holes, resolvable=False, existence=False): elif max_hole == 1 and number_of_holes >= 2 and k == n + 1: if existence: return False - raise EmptySetError(("There is no OA(n+1,n) - {}.OA(n+1,1) as all blocks " "intersect in a projective plane.").format(number_of_holes)) + raise EmptySetError(("There is no OA(n+1,n) - {}.OA(n+1,1) as all blocks intersect in a projective plane.").format(number_of_holes)) # Holes of size 1 from OA(k+1,n) elif max_hole == 1 and orthogonal_array(k + 1, n, existence=True) is True: @@ -1673,7 +1672,7 @@ def OA_n_times_2_pow_c_from_matrix(k, c, G, A, Y, check=True): # check that the first part of the matrix A is a (G,k-1,2)-difference matrix B = [[G(a) for a, b in R] for R in A] if check and not is_difference_matrix(list(zip(*B)), G, k - 1, 2): - raise ValueError("the first part of the matrix A must be a " "(G,k-1,2)-difference matrix") + raise ValueError("the first part of the matrix A must be a (G,k-1,2)-difference matrix") # convert: # the matrix A to a matrix over G \times GF(2^c) @@ -1702,7 +1701,7 @@ def OA_n_times_2_pow_c_from_matrix(k, c, G, A, Y, check=True): v2 = A[i][s2][1] - A[j][s2][1] if (v1 in Hij) == (v2 in Hij): - raise ValueError("B_{},{} - B_{},{} = B_{},{} - B_{},{} but" " the associated part of the matrix C does not satisfies" " the required condition".format(i, s1, j, s1, i, s2, j, s2)) + raise ValueError("B_{},{} - B_{},{} = B_{},{} - B_{},{} but the associated part of the matrix C does not satisfies the required condition".format(i, s1, j, s1, i, s2, j, s2)) # build the quasi difference matrix and return the associated OA Mb = [[e + GG((G.zero(), x * v)) for v in H for e in R] for x, R in zip(Y, A)] diff --git a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py index c3f4c5a1a86..6989b2a25f0 100644 --- a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py +++ b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py @@ -31,6 +31,7 @@ Functions --------- """ + from itertools import repeat from .orthogonal_arrays import orthogonal_array, wilson_construction, is_orthogonal_array @@ -78,7 +79,7 @@ def construction_3_3(k, n, m, i, explain_construction=False): from .orthogonal_arrays import wilson_construction, OA_relabel, incomplete_orthogonal_array if explain_construction: - return ("Construction 3.3 with n={},m={},i={} from:\n" " Julian R. Abel, Nicholas Cavenagh\n" + " Concerning eight mutually orthogonal latin squares,\n" + " Vol. 15, n.3, pp. 255-261,\n" + " Journal of Combinatorial Designs, 2007").format(n, m, i) + return ("Construction 3.3 with n={},m={},i={} from:\n Julian R. Abel, Nicholas Cavenagh\n" + " Concerning eight mutually orthogonal latin squares,\n" + " Vol. 15, n.3, pp. 255-261,\n" + " Journal of Combinatorial Designs, 2007").format(n, m, i) # Builds an OA(k+i,n) containing a block [0]*(k+i) OA = incomplete_orthogonal_array(k + i, n, (1,)) @@ -224,7 +225,7 @@ def construction_3_5(k, n, m, r, s, t, explain_construction=False): assert (q - r - 1) * (q - s) >= (q - s - 1) * (q - r) if explain_construction: - return ("Construction 3.5 with n={},m={},r={},s={},t={} from:\n" " Julian R. Abel, Nicholas Cavenagh\n" + " Concerning eight mutually orthogonal latin squares,\n" + " Vol. 15, n.3, pp. 255-261,\n" + " Journal of Combinatorial Designs, 2007").format(n, m, r, s, t) + return ("Construction 3.5 with n={},m={},r={},s={},t={} from:\n Julian R. Abel, Nicholas Cavenagh\n" + " Concerning eight mutually orthogonal latin squares,\n" + " Vol. 15, n.3, pp. 255-261,\n" + " Journal of Combinatorial Designs, 2007").format(n, m, r, s, t) master_design = orthogonal_array(k + 3, q) @@ -308,7 +309,7 @@ def construction_3_6(k, n, m, i, explain_construction=False): Journal of Combinatorial Designs, 2007 """ if explain_construction: - return ("Construction 3.6 with n={},m={},i={} from:\n" " Julian R. Abel, Nicholas Cavenagh\n" + " Concerning eight mutually orthogonal latin squares,\n" + " Vol. 15, n.3, pp. 255-261,\n" + " Journal of Combinatorial Designs, 2007").format(n, m, i) + return ("Construction 3.6 with n={},m={},i={} from:\n Julian R. Abel, Nicholas Cavenagh\n" + " Concerning eight mutually orthogonal latin squares,\n" + " Vol. 15, n.3, pp. 255-261,\n" + " Journal of Combinatorial Designs, 2007").format(n, m, i) from .orthogonal_arrays import wilson_construction @@ -1041,7 +1042,6 @@ def product_with_parallel_classes(OA1, k, g1, g2, g1_parall, parall, check=True) new_parallel_classes = [] for classs2 in g1_parall: - # Keep track of how many times we saw each point of [k]x[g2] count = [[0] * g2 for _ in range(k)] @@ -1461,7 +1461,6 @@ def brouwer_separable_design(k, t, q, x, check=False, verbose=False, explain_con # i) if x == 0: - if verbose: print("Case i) with k={},q={},t={},x={}".format(k, q, t, x)) @@ -1512,7 +1511,6 @@ def brouwer_separable_design(k, t, q, x, check=False, verbose=False, explain_con # ii) elif x == t + q and orthogonal_array(k + e3, t, existence=True) and orthogonal_array(k, t + q, existence=True) and orthogonal_array(k + 1, t + q + 1, existence=True): - if verbose: print("Case ii) with k={},q={},t={},x={},e3={}".format(k, q, t, x, e3)) @@ -1583,7 +1581,6 @@ def brouwer_separable_design(k, t, q, x, check=False, verbose=False, explain_con # iv) elif x == q**2 + 1 and orthogonal_array(k, x, existence=True) and orthogonal_array(k + e4, t + 1, existence=True) and orthogonal_array(k + 1, t + q + 1, existence=True): # d0 # d2 - e4 # d4 - 1 - if verbose: print(f"Case iv) with k={k},q={q},t={t},x={x},e4={e4}") diff --git a/src/sage/combinat/designs/resolvable_bibd.py b/src/sage/combinat/designs/resolvable_bibd.py index b97dc90ba37..d4e10ea6498 100644 --- a/src/sage/combinat/designs/resolvable_bibd.py +++ b/src/sage/combinat/designs/resolvable_bibd.py @@ -48,6 +48,7 @@ Functions --------- """ + from itertools import repeat from sage.arith.misc import is_prime_power from sage.combinat.designs.bibd import BalancedIncompleteBlockDesign @@ -694,11 +695,11 @@ def PBD_4_7_from_Y(gdd, check=True): group_sizes = set(map(len, gdd._groups)) if not block_sizes.issubset([4, 5, 7]): txt = list(block_sizes.difference([4, 5, 7])) - raise ValueError("The GDD should only contain blocks of size {{4,5,7}} " "but there are other: {}".format(txt)) + raise ValueError("The GDD should only contain blocks of size {{4,5,7}} but there are other: {}".format(txt)) for gs in group_sizes: if PBD_4_7(3 * gs + 1, existence=True) is not True: - raise RuntimeError("A group has size {} but I do not know how to " "build a ({},[4,7])-PBD".format(gs, 3 * gs + 1)) + raise RuntimeError("A group has size {} but I do not know how to build a ({},[4,7])-PBD".format(gs, 3 * gs + 1)) GDD = {} # the GDD we will need if 4 in block_sizes: diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 05b0c440473..0194be38972 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -1559,7 +1559,7 @@ def symmetric_diagrams(self, l=None, perm=None): # perm = permutation on free nodes # l = number of arcs if self.order not in ZZ: - raise NotImplementedError("only implemented for integer order," " not for order %s" % (self.order)) + raise NotImplementedError("only implemented for integer order, not for order %s" % (self.order)) n = ZZ(self.order) if l is None: l = 0 @@ -1614,7 +1614,7 @@ def from_involution_permutation_triple(self, D1_D2_pi): NotImplementedError: only implemented for integer order, not for order 5/2 """ if self.order not in ZZ: - raise NotImplementedError("only implemented for integer order," " not for order %s" % (self.order)) + raise NotImplementedError("only implemented for integer order, not for order %s" % (self.order)) try: D1, D2, pi = tuple(D1_D2_pi) except ValueError: diff --git a/src/sage/combinat/dyck_word.py b/src/sage/combinat/dyck_word.py index 6507bdcca7f..09437468acd 100644 --- a/src/sage/combinat/dyck_word.py +++ b/src/sage/combinat/dyck_word.py @@ -911,21 +911,21 @@ def _repr_svg_(self) -> str: """ N = self.length() width = 0.1 if N < 20 else N / 200 - resu = '' - resu += '' - resu += '" hori_lines = [] - path = ['') + path.append('"/>') path.append('') resu1 += " ".join(path) hori_lines.append('') resu3 += "".join(hori_lines) margin = 2 * width - resu += '\"{} {} {} {} \">'.format(-margin, -max_y - margin, N + 2 * margin, max_y + 2 * margin) + resu += '"{} {} {} {} ">'.format(-margin, -max_y - margin, N + 2 * margin, max_y + 2 * margin) return resu + resu1 + resu3 @@ -3355,7 +3355,7 @@ class options(GlobalOptions): ) latex_tikz_scale = dict(default=1, description='The default value for the tikz scale when latexed', checker=lambda x: True) # More trouble than it's worth to check latex_diagonal = dict(default=False, description='The default value for displaying the diagonal when latexed', checker=lambda x: isinstance(x, bool)) - latex_line_width_scalar = dict(default=2, description='The default value for the line width as a ' 'multiple of the tikz scale when latexed', checker=lambda x: True) # More trouble than it's worth to check + latex_line_width_scalar = dict(default=2, description='The default value for the line width as a multiple of the tikz scale when latexed', checker=lambda x: True) # More trouble than it's worth to check latex_color = dict(default='black', description='The default value for the color when latexed', checker=lambda x: isinstance(x, str)) latex_bounce_path = dict(default=False, description='The default value for displaying the bounce path when latexed', checker=lambda x: isinstance(x, bool)) latex_peaks = dict(default=False, description='The default value for displaying the peaks when latexed', checker=lambda x: isinstance(x, bool)) @@ -3870,7 +3870,7 @@ def from_area_sequence(self, code) -> DyckWord: [1, 0, 1, 0] """ if not is_area_sequence(code): - raise ValueError("the given sequence is not a sequence giving " "the number of cells between the Dyck path " "and the diagonal") + raise ValueError("the given sequence is not a sequence giving the number of cells between the Dyck path and the diagonal") dyck_word = [] for i in range(len(code)): if i: diff --git a/src/sage/combinat/e_one_star.py b/src/sage/combinat/e_one_star.py index 26ec41af542..683e6f61fdb 100644 --- a/src/sage/combinat/e_one_star.py +++ b/src/sage/combinat/e_one_star.py @@ -197,6 +197,7 @@ [(0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1), 2]* [(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1), 1]* """ + # **************************************************************************** # Copyright (C) 2010 Franco Saliola # Vincent Delecroix <20100.delecroix@gmail.com> diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 54f2cc89438..9157b86e7eb 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -1376,7 +1376,7 @@ def __init__(self, label, word_out=None, is_initial=False, is_final=False, final but state A is not final. """ if not allow_label_None and label is None: - raise ValueError("Label None reserved for a special state, " "choose another label.") + raise ValueError("Label None reserved for a special state, choose another label.") self._label_ = label if isinstance(word_out, list): @@ -1500,7 +1500,7 @@ def final_word_out(self, final_word_out): """ if not self.is_final: if final_word_out is not None: - raise ValueError("Only final states can have a " "final output word, but state %s is not final." % (self.label(),)) + raise ValueError("Only final states can have a final output word, but state %s is not final." % (self.label(),)) else: self._final_word_out_ = None elif isinstance(final_word_out, list): @@ -1596,7 +1596,7 @@ def is_final(self, is_final): if not self.final_word_out: self._final_word_out_ = None else: - raise ValueError("State %s cannot be non-final, because it " "has a final output word. Only final states " "can have a final output word. " % (self.label(),)) + raise ValueError("State %s cannot be non-final, because it has a final output word. Only final states can have a final output word. " % (self.label(),)) def label(self): """ @@ -1967,7 +1967,7 @@ def _epsilon_successors_(self, fsm=None): {0: [['a', 'b', 'c']], 1: [['a']], 2: [['a', 'b']]} """ if not hasattr(self, 'transitions'): - raise ValueError('State %s does not belong to a ' 'finite state machine.' % (self,)) + raise ValueError('State %s does not belong to a finite state machine.' % (self,)) it = _FSMProcessIteratorEpsilon_(fsm, input_tape=[], initial_state=self) # TODO: optimize the following lines (use already calculated @@ -2909,33 +2909,33 @@ def __init__(self, data=None, initial_states=None, final_states=None, input_alph if isinstance(data, FiniteStateMachine): if initial_states is not None: - raise ValueError("initial_states cannot be specified when copying " "another finite state machine.") + raise ValueError("initial_states cannot be specified when copying another finite state machine.") if final_states is not None: - raise ValueError("final_states cannot be specified when copying " "another finite state machine.") + raise ValueError("final_states cannot be specified when copying another finite state machine.") if input_alphabet is not None: - raise ValueError("input_alphabet cannot be specified when copying " "another finite state machine.") + raise ValueError("input_alphabet cannot be specified when copying another finite state machine.") if output_alphabet is not None: - raise ValueError("output_alphabet cannot be specified when copying " "another finite state machine.") + raise ValueError("output_alphabet cannot be specified when copying another finite state machine.") if on_duplicate_transition is not None: - raise ValueError("on_duplicate_transition cannot be specified when " "copying another finite state machine.") + raise ValueError("on_duplicate_transition cannot be specified when copying another finite state machine.") if determine_alphabets is not None: - raise ValueError("determine_alphabets cannot be specified when " "copying another finite state machine.") + raise ValueError("determine_alphabets cannot be specified when copying another finite state machine.") if with_final_word_out is not None: - raise ValueError("with_final_word_out cannot be specified when " "copying another finite state machine.") + raise ValueError("with_final_word_out cannot be specified when copying another finite state machine.") self._copy_from_other_(data) return if initial_states is not None: if not isinstance(initial_states, Iterable): - raise TypeError('Initial states must be iterable ' '(e.g. a list of states).') + raise TypeError('Initial states must be iterable (e.g. a list of states).') for s in initial_states: state = self.add_state(s) state.is_initial = True if final_states is not None: if not isinstance(final_states, Iterable): - raise TypeError('Final states must be iterable ' '(e.g. a list of states).') + raise TypeError('Final states must be iterable (e.g. a list of states).') for s in final_states: state = self.add_state(s) state.is_final = True @@ -3163,7 +3163,7 @@ def _copy_from_other_(self, other, memo=None, empty=False): elif hasattr(other._deepcopy_labels_, '__getitem__'): state._deepcopy_relabel_ = other._deepcopy_labels_[state.label()] else: - raise TypeError("labels must be None, a callable " "or a dictionary.") + raise TypeError("labels must be None, a callable or a dictionary.") s = deepcopy(state, memo) if relabel: del state._deepcopy_relabel_ @@ -3336,7 +3336,7 @@ def __hash__(self): """ if getattr(self, "_immutable", False): return hash((tuple(self.states()), tuple(self.transitions()))) - raise TypeError("Finite state machines are mutable, " "and thus not hashable.") + raise TypeError("Finite state machines are mutable, and thus not hashable.") # ************************************************************************ # operators @@ -4407,7 +4407,7 @@ def latex_options(self, coordinates=None, format_state_label=None, format_letter try: where = loop_where[state.label()] except TypeError: - raise TypeError("loop_where must be a " "callable or a dictionary.") + raise TypeError("loop_where must be a callable or a dictionary.") except KeyError: continue if where in permissible: @@ -4424,7 +4424,7 @@ def latex_options(self, coordinates=None, format_state_label=None, format_letter try: where = initial_where[state.label()] except TypeError: - raise TypeError("initial_where must be a " "callable or a dictionary.") + raise TypeError("initial_where must be a callable or a dictionary.") except KeyError: continue if where in permissible: @@ -4451,7 +4451,7 @@ def latex_options(self, coordinates=None, format_state_label=None, format_letter try: where = accepting_where[state.label()] except TypeError: - raise TypeError("accepting_where must be a " "callable or a dictionary.") + raise TypeError("accepting_where must be a callable or a dictionary.") except KeyError: continue if where in permissible: @@ -4460,7 +4460,7 @@ def latex_options(self, coordinates=None, format_state_label=None, format_letter if where in RR: state.accepting_where = where else: - raise ValueError('accepting_where for %s must ' 'be a real number or be in %s.' % (state.label(), sorted(permissible))) + raise ValueError('accepting_where for %s must be a real number or be in %s.' % (state.label(), sorted(permissible))) else: raise ValueError('accepting_where for %s must be in %s.' % (state.label(), sorted(permissible))) @@ -5422,7 +5422,7 @@ def is_complete(self): False """ if self.input_alphabet is None: - raise ValueError("No input alphabet is given. " "Try calling determine_alphabets().") + raise ValueError("No input alphabet is given. Try calling determine_alphabets().") for state in self.iter_states(): for transition in state.transitions: @@ -5780,9 +5780,9 @@ class is created and is used during the processing. # process output: cannot return output to due input parameters if options['list_of_outputs'] is False: if not it_output and only_accepted: - raise ValueError('No accepting output was found but according ' 'to the given options, an accepting output ' 'should be returned. Change only_accepted ' 'and/or list_of_outputs options.') + raise ValueError('No accepting output was found but according to the given options, an accepting output should be returned. Change only_accepted and/or list_of_outputs options.') elif len(it_output) > 1: - raise ValueError('Got more than one output, but only allowed ' 'to show one. Change list_of_outputs option.') + raise ValueError('Got more than one output, but only allowed to show one. Change list_of_outputs option.') # At this point it_output has length 0 or 1. # process output: create non-accepting output if needed @@ -5957,7 +5957,7 @@ def iter_process(self, input_tape=None, initial_state=None, process_iterator_cla :class:`FSMProcessIterator`. """ if automatic_output_type and 'format_output' in kwargs: - raise ValueError("Parameter 'automatic_output_type' set, but " "'format_output' specified as well.") + raise ValueError("Parameter 'automatic_output_type' set, but 'format_output' specified as well.") if automatic_output_type: try: kwargs['format_output'] = input_tape.parent() @@ -6038,13 +6038,13 @@ def _iter_process_simple_(self, iterator): return if len(current) > 1: - raise RuntimeError("Process has branched " "(%s branches exist). The " "'simple' iterator cannot be used " "here." % (len(current),)) + raise RuntimeError("Process has branched (%s branches exist). The 'simple' iterator cannot be used here." % (len(current),)) _, states = next(iter(current.items())) if len(states) > 1: - raise RuntimeError("Process has branched " "(visiting %s states in branch). The " "'simple' iterator cannot be used " "here." % (len(states),)) + raise RuntimeError("Process has branched (visiting %s states in branch). The 'simple' iterator cannot be used here." % (len(states),)) _, branch = next(iter(states.items())) if len(branch.outputs) > 1: - raise RuntimeError("Process has branched. " "(%s different outputs in branch). The " "'simple' iterator cannot be used " "here." % (len(branch.outputs),)) + raise RuntimeError("Process has branched. (%s different outputs in branch). The 'simple' iterator cannot be used here." % (len(branch.outputs),)) yield from branch.outputs[0] branch.outputs[0] = [] @@ -6323,7 +6323,7 @@ def add_from_transition_function(self, function, initial_states=None, explore_ex TypeError: ...mutable vectors are unhashable... """ if self.input_alphabet is None: - raise ValueError("No input alphabet is given. " "Try calling determine_alphabets().") + raise ValueError("No input alphabet is given. Try calling determine_alphabets().") if initial_states is None: not_done = self.initial_states() @@ -6334,7 +6334,7 @@ def add_from_transition_function(self, function, initial_states=None, explore_ex state.is_initial = True not_done.append(state) else: - raise TypeError('Initial states must be iterable ' '(e.g. a list of states).') + raise TypeError('Initial states must be iterable (e.g. a list of states).') if not not_done: raise ValueError("No state is initial.") if explore_existing_states: @@ -6359,7 +6359,7 @@ def add_from_transition_function(self, function, initial_states=None, explore_ex for st_label, word in return_value: pass except TypeError: - raise ValueError("The callback function for " "add_from_transition is expected " "to return a pair (new_state, " "output_label) or a list of such pairs. " "For the state %s and the input " "letter %s, it however returned %s, " "which is not acceptable." % (s.label(), letter, return_value)) + raise ValueError("The callback function for add_from_transition is expected to return a pair (new_state, output_label) or a list of such pairs. For the state %s and the input letter %s, it however returned %s, which is not acceptable." % (s.label(), letter, return_value)) for st_label, word in return_value: if not self.has_state(st_label): not_done.append(self.add_state(st_label)) @@ -6452,7 +6452,7 @@ def add_transitions_from_function(self, function, labels_as_input=True): transitions = return_value for t in transitions: if not hasattr(t, '__getitem__'): - raise ValueError("The callback function for " "add_transitions_from_function " "is expected to return a " "pair (word_in, word_out) or a " "list of such pairs. For " "states %s and %s however, it " "returned %s, which is not " "acceptable." % (s_from, s_to, return_value)) + raise ValueError("The callback function for add_transitions_from_function is expected to return a pair (word_in, word_out) or a list of such pairs. For states %s and %s however, it returned %s, which is not acceptable." % (s_from, s_to, return_value)) label_in = t[0] try: label_out = t[1] @@ -6969,9 +6969,9 @@ def concatenation(self, other): with a another finite state machine. """ if not isinstance(other, FiniteStateMachine): - raise TypeError('A finite state machine can only be concatenated ' 'with a another finite state machine.') + raise TypeError('A finite state machine can only be concatenated with a another finite state machine.') if isinstance(other, Automaton) != isinstance(self, Automaton): - raise TypeError('Cannot concatenate finite state machines of ' 'different types.') + raise TypeError('Cannot concatenate finite state machines of different types.') result = self.empty_copy() first_states = {} @@ -7333,11 +7333,11 @@ def default_final_function(*args): machines = [self] machines.extend(other) if not all(isinstance(m, FiniteStateMachine) for m in machines): - raise ValueError("other must be a finite state machine " "or a list of finite state machines.") + raise ValueError("other must be a finite state machine or a list of finite state machines.") elif isinstance(other, FiniteStateMachine): machines = [self, other] else: - raise ValueError("other must be a finite state machine or " "a list of finite state machines.") + raise ValueError("other must be a finite state machine or a list of finite state machines.") for transitions in itertools.product(*(m.iter_transitions() for m in machines)): try: @@ -7662,7 +7662,7 @@ def composition(self, other, algorithm=None, only_accessible_components=True): determine_alphabets(). """ if not other._allow_composition_: - raise TypeError("Composition with automaton is not " "possible.") + raise TypeError("Composition with automaton is not possible.") if algorithm is None: if any(len(t.word_out) > 1 for t in other.iter_transitions()) or any(len(t.word_in) != 1 for t in self.iter_transitions()): @@ -7779,7 +7779,7 @@ def composition_transition(states, input): if state1.is_final: final_output_second = second.process(state1.final_word_out, list_of_outputs=True, initial_state=state2, only_accepted=True, always_include_output=True) if len(final_output_second) > 1 and not equal(r[2] for r in final_output_second): - raise NotImplementedError("Stopping in state %s " "leads to " "non-deterministic final " "output." % state) + raise NotImplementedError("Stopping in state %s leads to non-deterministic final output." % state) if final_output_second: state.is_final = True state.final_word_out = final_output_second[0][2] @@ -7996,7 +7996,7 @@ def transposition(self, reverse_output_labels=True): for final in self.iter_final_states(): state = transposition.state(final.label()) if final.final_word_out: - raise NotImplementedError("Transposition for transducers " "with final output words is not " "implemented.") + raise NotImplementedError("Transposition for transducers with final output words is not implemented.") if not final.is_initial: state.is_final = False state.is_initial = True @@ -8195,7 +8195,7 @@ def completion(self, sink=None): if sink is not None: try: s = result.state(sink) - raise ValueError("The finite state machine already " "contains a state '%s'." % s.label()) + raise ValueError("The finite state machine already contains a state '%s'." % s.label()) except LookupError: pass else: @@ -8206,7 +8206,7 @@ def completion(self, sink=None): for state in result.iter_states(): for transition in state.transitions: if len(transition.word_in) != 1: - raise ValueError("Transitions with input labels of length greater " "than one are not allowed. Try calling " "split_transitions().") + raise ValueError("Transitions with input labels of length greater than one are not allowed. Try calling split_transitions().") existing = set(transition.word_in[0] for transition in state.transitions) for missing in set(result.input_alphabet) - existing: @@ -8347,7 +8347,7 @@ def find_common_output(state): if state.is_initial: continue if state.word_out: - raise NotImplementedError("prepone_output assumes that all states have " "empty output word, but state %s has output " "word %s" % (state, state.word_out)) + raise NotImplementedError("prepone_output assumes that all states have empty output word, but state %s has output word %s" % (state, state.word_out)) common_output = find_common_output(state) if common_output: changed += 1 @@ -8364,13 +8364,7 @@ def find_common_output(state): found_inbound_transition = True if not found_inbound_transition: verbose( - "All transitions leaving state %s have an " - "output label with prefix %s. However, " - "there is no inbound transition and it is " - "not an initial state. This routine " - "(possibly called by simplification) " - "therefore erased this prefix from all " - "outbound transitions." % (state, common_output[0]), + "All transitions leaving state %s have an output label with prefix %s. However, there is no inbound transition and it is not an initial state. This routine (possibly called by simplification) therefore erased this prefix from all outbound transitions." % (state, common_output[0]), level=0, ) @@ -8562,7 +8556,7 @@ def quotient(self, classes): assert new_state.word_out == state.word_out, "Class %s mixes different word_out" % (c,) assert new_state.color == state.color, "Class %s mixes different colors" % (c,) assert sorted_transitions == sorted([(state_mapping[t.to_state], t.word_in, t.word_out) for t in state.transitions]), "Transitions of state %s and %s are incompatible." % (c[0], state) - assert new_state.final_word_out == state.final_word_out, "Class %s mixes final states with different " "final output words." % (c,) + assert new_state.final_word_out == state.final_word_out, "Class %s mixes final states with different final output words." % (c,) return new def merged_transitions(self): @@ -8961,16 +8955,16 @@ def find_final_word_out(state): return cache[state, position] if (state, position) in in_progress: - raise ValueError("The finite state machine contains a cycle " "starting at state %s with input label %s " "and no final state." % (state, letter)) + raise ValueError("The finite state machine contains a cycle starting at state %s with input label %s and no final state." % (state, letter)) if any(len(t.word_in) != 1 for t in state.transitions): - raise NotImplementedError("All transitions must have input labels of length " "1. Consider calling split_transitions().") + raise NotImplementedError("All transitions must have input labels of length 1. Consider calling split_transitions().") transitions = [t for t in state.transitions if t.word_in == [letter]] if allow_non_final and not transitions: final_word_out = None elif len(transitions) != 1: - raise ValueError("No unique transition leaving state %s with input " "label %s." % (state, letter)) + raise ValueError("No unique transition leaving state %s with input label %s." % (state, letter)) else: in_progress.add((state, position)) next_word = find_final_word_out(transitions[0].to_state) @@ -9655,7 +9649,7 @@ def asymptotic_moments(self, variable=None): :doi:`10.1007/s10998-007-3081-z`. """ if self.input_alphabet is None: - raise ValueError("No input alphabet is given. " "Try calling determine_alphabets().") + raise ValueError("No input alphabet is given. Try calling determine_alphabets().") if len(self.initial_states()) != 1: raise ValueError("A unique initial state is required.") @@ -9664,15 +9658,15 @@ def asymptotic_moments(self, variable=None): raise ValueError("Not all states are final.") if not self.is_complete(): - raise NotImplementedError("This finite state machine is " "not complete.") + raise NotImplementedError("This finite state machine is not complete.") final_components = self.final_components() if len(final_components) != 1: - raise NotImplementedError("asymptotic_moments is only " "implemented for finite state machines " "with one final component.") + raise NotImplementedError("asymptotic_moments is only implemented for finite state machines with one final component.") final_component = final_components[0] if not final_component.digraph().is_aperiodic(): - raise NotImplementedError("asymptotic_moments is only " "implemented for finite state machines " "whose unique final component is " "aperiodic.") + raise NotImplementedError("asymptotic_moments is only implemented for finite state machines whose unique final component is aperiodic.") from sage.calculus.functional import derivative from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -9691,7 +9685,7 @@ def get_matrix(fsm, x, y): try: M = get_matrix(self, x, y) except (TypeError, ValueError): - verbose("Non-integer output weights lead to " "significant performance degradation.", level=0) + verbose("Non-integer output weights lead to significant performance degradation.", level=0) # fall back to symbolic ring R = SR x = R.symbol() @@ -10057,7 +10051,7 @@ def default_is_zero(expression): is_zero_function = is_zero if not self.is_Markov_chain(is_zero): - raise ValueError("Only Markov chains can compute " "moments_waiting_time.") + raise ValueError("Only Markov chains can compute moments_waiting_time.") if len(self.initial_states()) != 1: raise ValueError("Unique initial state is required.") @@ -10718,7 +10712,7 @@ def _minimization_Moore_(self): """ if self.is_deterministic(): return self.quotient(self.equivalence_classes()) - raise NotImplementedError("Minimization via Moore's Algorithm is only " "implemented for deterministic finite state machines") + raise NotImplementedError("Minimization via Moore's Algorithm is only implemented for deterministic finite state machines") def complement(self): r""" @@ -11558,7 +11552,7 @@ def intersection(self, other, only_accessible_components=True): def function(transition1, transition2): if not transition1.word_in or not transition2.word_in or not transition1.word_out or not transition2.word_out: - raise ValueError("An epsilon-transition " "(with empty input or output) was found.") + raise ValueError("An epsilon-transition (with empty input or output) was found.") if transition1.word_in == transition2.word_in and transition1.word_out == transition2.word_out: return (transition1.word_in, transition1.word_out) raise LookupError @@ -12553,7 +12547,7 @@ def preview_word(self, track_number=None, length=1, return_word=False): cache: (deque([]), deque([])) multi-tape at (5, 4) """ if not return_word and length != 1: - raise ValueError("Should return a letter, but parameter " "length is not 1.") + raise ValueError("Should return a letter, but parameter length is not 1.") if track_number is None: if self.is_multitape: result = tuple(self.preview_word(n, length, return_word) for n, _ in enumerate(self.cache)) @@ -12730,7 +12724,7 @@ def transition_possible(self, transition): else: word_in = tupleofwords_to_wordoftuples((transition.word_in,)) if any(len(t) != len(self.cache) for t in word_in): - raise TypeError('%s has bad input word (entries should be ' 'tuples of size %s).' % (transition, len(self.cache))) + raise TypeError('%s has bad input word (entries should be tuples of size %s).' % (transition, len(self.cache))) return self._transition_possible_test_(word_in) def _transition_possible_epsilon_(self, word_in): @@ -13517,7 +13511,7 @@ def _push_branches_(self, state, tape_cache, outputs): return if state._in_epsilon_cycle_(self.fsm): if not state._epsilon_cycle_output_empty_(self.fsm): - raise RuntimeError('State %s is in an epsilon cycle (no input), ' 'but output is written.' % (state,)) + raise RuntimeError('State %s is in an epsilon cycle (no input), but output is written.' % (state,)) for eps_state, eps_outputs in state._epsilon_successors_(self.fsm).items(): if eps_state == state: @@ -13644,7 +13638,7 @@ def step(current_state, input_tape, outputs): if isinstance(next_transitions, FSMTransition): next_transitions = [next_transitions] if next_transitions is not None and not isinstance(next_transitions, Iterable): - raise ValueError('hook of state should return a ' 'transition or ' 'a list/tuple of transitions.') + raise ValueError('hook of state should return a transition or a list/tuple of transitions.') # write output word of state write_word(outputs, current_state.word_out) diff --git a/src/sage/combinat/finite_state_machine_generators.py b/src/sage/combinat/finite_state_machine_generators.py index 291f542de06..3147805ba46 100644 --- a/src/sage/combinat/finite_state_machine_generators.py +++ b/src/sage/combinat/finite_state_machine_generators.py @@ -1203,7 +1203,7 @@ def to_list(output): try: polynomial_left = base_ring[var](left_side.operands()[0]) except Exception: - raise ValueError("%s is not a polynomial " "in %s." % (left_side.operands()[0], var)) + raise ValueError("%s is not a polynomial in %s." % (left_side.operands()[0], var)) if polynomial_left in base_ring and is_scalar(right_side): return {polynomial_left: to_list(right_side)} @@ -1230,7 +1230,7 @@ def to_list(output): function_calls = [o for o in right_side.operands() if o.operator() == function] other_terms = [o for o in right_side.operands() if o.operator() != function] if len(function_calls) != 1: - raise ValueError("%s does not contain exactly one summand which " "is an evaluation of %s." % (right_side, function)) + raise ValueError("%s does not contain exactly one summand which is an evaluation of %s." % (right_side, function)) next_function = function_calls[0] t = sum(other_terms) if not is_scalar(t): @@ -1739,7 +1739,7 @@ def Recursion(self, recursions, base, function=None, var=None, input_alphabet=No missing_residues = [R for R, rule in enumerate(residues[max_K]) if rule is None] if missing_residues: - raise ValueError("Missing recursions for input congruent " "to %s modulo %s." % (missing_residues, base**max_K)) + raise ValueError("Missing recursions for input congruent to %s modulo %s." % (missing_residues, base**max_K)) required_initial_values = set() diff --git a/src/sage/combinat/free_dendriform_algebra.py b/src/sage/combinat/free_dendriform_algebra.py index 7bc393fc8c5..2776f8e445d 100644 --- a/src/sage/combinat/free_dendriform_algebra.py +++ b/src/sage/combinat/free_dendriform_algebra.py @@ -421,7 +421,7 @@ def succ_product_on_basis(self, x, y): """ if y.is_empty(): if x.is_empty(): - raise ValueError("dendriform products | < | and | > | are " "not defined") + raise ValueError("dendriform products | < | and | > | are not defined") else: return [] if x.is_empty(): @@ -491,7 +491,7 @@ def prec_product_on_basis(self, x, y): ValueError: dendriform products | < | and | > | are not defined """ if x.is_empty() and y.is_empty(): - raise ValueError("dendriform products | < | and | > | are " "not defined") + raise ValueError("dendriform products | < | and | > | are not defined") if x.is_empty(): return [] if y.is_empty(): diff --git a/src/sage/combinat/fully_commutative_elements.py b/src/sage/combinat/fully_commutative_elements.py index e0cf4eedfbf..f6840d4b11f 100644 --- a/src/sage/combinat/fully_commutative_elements.py +++ b/src/sage/combinat/fully_commutative_elements.py @@ -18,6 +18,7 @@ Colorado Boulder. We thank Rachel Castro, Joel Courtney, Thomas Magnuson and Natalie Schoenhals for their contribution to the project and the code. """ + # **************************************************************************** # Copyright (C) 2020 Chase Meadors , # Tianyuan Xu diff --git a/src/sage/combinat/fully_packed_loop.py b/src/sage/combinat/fully_packed_loop.py index 49a462ab3fc..333d177110c 100644 --- a/src/sage/combinat/fully_packed_loop.py +++ b/src/sage/combinat/fully_packed_loop.py @@ -545,7 +545,7 @@ def __classcall_private__(cls, generator): SVM = generator if not SVM: - raise TypeError('generator for FullyPackedLoop must either be an ' 'AlternatingSignMatrix or a SquareIceModel.Element') + raise TypeError('generator for FullyPackedLoop must either be an AlternatingSignMatrix or a SquareIceModel.Element') FPLs = FullyPackedLoops(len(SVM)) return FPLs(generator) diff --git a/src/sage/combinat/growth.py b/src/sage/combinat/growth.py index fc6de81b410..a980fe2d8f6 100644 --- a/src/sage/combinat/growth.py +++ b/src/sage/combinat/growth.py @@ -997,14 +997,14 @@ def to_word(self): if w[i] == 0: w[i] = j + 1 else: - raise ValueError("can only convert fillings with at" " most one entry per column to words") + raise ValueError("can only convert fillings with at most one entry per column to words") elif v == -1: if w[i] == 0: w[i] = -(j + 1) else: - raise ValueError("can only convert fillings with at" " most one entry per column to words") + raise ValueError("can only convert fillings with at most one entry per column to words") else: - raise ValueError("can only convert 0-1 fillings to words;" " try 'to_biword'") + raise ValueError("can only convert 0-1 fillings to words; try 'to_biword'") return w def to_biword(self): @@ -1041,7 +1041,7 @@ def to_biword(self): w1.extend([i + 1] * v) w2.extend([j + 1] * v) else: - raise ValueError("can only convert fillings with" " nonnegative entries to words") + raise ValueError("can only convert fillings with nonnegative entries to words") return (w1, w2) def __iter__(self): @@ -1774,7 +1774,7 @@ def check_vertex(w, P, Q): UDw = [v[1] for lw in Q.incoming_edges(w) for v in P.outgoing_edges(lw[0])] UDw.extend([w] * self.r) if sorted(DUw) != sorted(UDw): - raise ValueError("D U - U D differs from %s I for vertex %s:\n" "D U = %s\n" "U D + %s I = %s" % (self.r, w, DUw, self.r, UDw)) + raise ValueError("D U - U D differs from %s I for vertex %s:\nD U = %s\nU D + %s I = %s" % (self.r, w, DUw, self.r, UDw)) else: @@ -1783,7 +1783,7 @@ def check_vertex(w, P, Q): UDw = [v for lw in Q.lower_covers(w) for v in P.upper_covers(lw)] UDw.extend([w] * self.r) if sorted(DUw) != sorted(UDw): - raise ValueError("D U - U D differs from %s I for vertex %s:\n" "D U = %s\n" "U D + %s I = %s" % (self.r, w, DUw, self.r, UDw)) + raise ValueError("D U - U D differs from %s I for vertex %s:\nD U = %s\nU D + %s I = %s" % (self.r, w, DUw, self.r, UDw)) P = self.P_graph(n + 2) Q = self.Q_graph(n + 2) diff --git a/src/sage/combinat/integer_lists/lists.py b/src/sage/combinat/integer_lists/lists.py index f0de472dd2b..ba5d1c782cb 100644 --- a/src/sage/combinat/integer_lists/lists.py +++ b/src/sage/combinat/integer_lists/lists.py @@ -19,7 +19,6 @@ # https://www.gnu.org/licenses/ # *************************************************************************** - from inspect import ismethod from sage.categories.enumerated_sets import EnumeratedSets from sage.structure.list_clone import ClonableArray diff --git a/src/sage/combinat/integer_vectors_mod_permgroup.py b/src/sage/combinat/integer_vectors_mod_permgroup.py index bbc661354a4..11146478ee1 100644 --- a/src/sage/combinat/integer_vectors_mod_permgroup.py +++ b/src/sage/combinat/integer_vectors_mod_permgroup.py @@ -688,9 +688,9 @@ def _repr_(self): """ if self._sum is not None: if self._max_part >= 0: - return "Vectors of length %s and of sum %s" " whose entries are in {0, ..., %s}" " enumerated up to the action of %s" % (self.n, self._sum, self._max_part, self.permutation_group()) - return "Integer vectors of length %s" " and of sum %s" " enumerated up to the action of %s" % (self.n, self._sum, self.permutation_group()) - return "Integer vectors of length %s" " whose entries are in {0, ..., %s}" " enumerated up to the action of %s" % (self.n, self._max_part, self.permutation_group()) + return "Vectors of length %s and of sum %s whose entries are in {0, ..., %s} enumerated up to the action of %s" % (self.n, self._sum, self._max_part, self.permutation_group()) + return "Integer vectors of length %s and of sum %s enumerated up to the action of %s" % (self.n, self._sum, self.permutation_group()) + return "Integer vectors of length %s whose entries are in {0, ..., %s} enumerated up to the action of %s" % (self.n, self._max_part, self.permutation_group()) def roots(self): r""" diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index e09860b8ce5..8cef934ac42 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -1248,7 +1248,7 @@ def insertion(self, i) -> TIP: """ n = self._size if not 0 < i <= n + 1: - raise ValueError("integer to be inserted not " "in the appropriate interval") + raise ValueError("integer to be inserted not in the appropriate interval") def add1(u): if u >= i: @@ -2937,11 +2937,11 @@ class options(GlobalOptions): NAME = 'TamariIntervalPosets' module = 'sage.combinat.interval_posets' latex_tikz_scale = dict(default=1, description='the default value for the tikz scale when latexed', checker=lambda x: True) # More trouble than it's worth to check - latex_line_width_scalar = dict(default=0.5, description='the default value for the line width as a' 'multiple of the tikz scale when latexed', checker=lambda x: True) # More trouble than it's worth to check + latex_line_width_scalar = dict(default=0.5, description='the default value for the line width as amultiple of the tikz scale when latexed', checker=lambda x: True) # More trouble than it's worth to check latex_color_decreasing = dict(default='red', description='the default color of decreasing relations when latexed', checker=lambda x: True) # More trouble than it's worth to check latex_color_increasing = dict(default='blue', description='the default color of increasing relations when latexed', checker=lambda x: True) # More trouble than it's worth to check - latex_hspace = dict(default=1, description='the default difference between horizontal' ' coordinates of vertices when latexed', checker=lambda x: True) # More trouble than it's worth to check - latex_vspace = dict(default=1, description='the default difference between vertical' ' coordinates of vertices when latexed', checker=lambda x: True) # More trouble than it's worth to check + latex_hspace = dict(default=1, description='the default difference between horizontal coordinates of vertices when latexed', checker=lambda x: True) # More trouble than it's worth to check + latex_vspace = dict(default=1, description='the default difference between vertical coordinates of vertices when latexed', checker=lambda x: True) # More trouble than it's worth to check @staticmethod def check_poset(poset) -> bool: diff --git a/src/sage/combinat/k_tableau.py b/src/sage/combinat/k_tableau.py index 9fa01e50e42..418382806d8 100644 --- a/src/sage/combinat/k_tableau.py +++ b/src/sage/combinat/k_tableau.py @@ -15,6 +15,7 @@ - Anne Schilling and Mike Zabrocki (2013): initial version - Avi Dalal and Nate Gallup (2013): implementation of `k`-charge """ + # ***************************************************************************** # Copyright (C) 2013 Anne Schilling # Mike Zabrocki @@ -1972,7 +1973,7 @@ def check(self): """ weight = tuple(self[i].length() for i in range(len(self) - 1, -1, -1)) if not self.parent()._weight == weight: - raise ValueError("The weight of the parent does not agree " "with the weight of the tableau!") + raise ValueError("The weight of the parent does not agree with the weight of the tableau!") W = self[0].parent() outer = (W.prod(self) * W((self._inner_shape).to_grassmannian())).affine_grassmannian_to_core() if self.parent()._outer_shape != outer: @@ -3856,7 +3857,6 @@ def to_transposition_sequence(self): class StrongTableaux(UniqueRepresentation, Parent): - def __init__(self, k, shape, weight): r""" TESTS:: diff --git a/src/sage/combinat/kazhdan_lusztig.py b/src/sage/combinat/kazhdan_lusztig.py index 0bd7ae9eda9..ef50af47f15 100644 --- a/src/sage/combinat/kazhdan_lusztig.py +++ b/src/sage/combinat/kazhdan_lusztig.py @@ -18,7 +18,6 @@ # https://www.gnu.org/licenses/ # *************************************************************************** - from sage.rings.polynomial.polynomial_element import Polynomial from sage.misc.cachefunc import cached_method from sage.rings.polynomial.laurent_polynomial import LaurentPolynomial diff --git a/src/sage/combinat/key_polynomial.py b/src/sage/combinat/key_polynomial.py index e3d68db86c7..2597b418bdb 100644 --- a/src/sage/combinat/key_polynomial.py +++ b/src/sage/combinat/key_polynomial.py @@ -458,7 +458,7 @@ def pi(self, w): N = max(w) + 1 if P._k is not None and N > P._k: - raise ValueError(f"pi_{N-1} does not exist for this polynomial ring") + raise ValueError(f"pi_{N - 1} does not exist for this polynomial ring") ret = P.element_class(P, {}) for m, c in self._monomial_coefficients.items(): @@ -624,7 +624,7 @@ def pibar(self, w): N = max(w) + 1 if P._k is not None and N > P._k: - raise ValueError(f"pi_{N-1} does not exist for this polynomial ring") + raise ValueError(f"pi_{N - 1} does not exist for this polynomial ring") ret = P.element_class(P, {}) for m, c in self._monomial_coefficients.items(): diff --git a/src/sage/combinat/lr_tableau.py b/src/sage/combinat/lr_tableau.py index ca2b97071ec..d62db1daf82 100644 --- a/src/sage/combinat/lr_tableau.py +++ b/src/sage/combinat/lr_tableau.py @@ -131,9 +131,9 @@ def check(self): """ super().check() if not [i for a in self.parent()._weight for i in a] == self.weight(): - raise ValueError("weight of the parent does not agree " "with the weight of the tableau") + raise ValueError("weight of the parent does not agree with the weight of the tableau") if not self.shape() == self.parent()._shape: - raise ValueError("shape of the parent does not agree " "with the shape of the tableau") + raise ValueError("shape of the parent does not agree with the shape of the tableau") class LittlewoodRichardsonTableaux(SemistandardTableaux): diff --git a/src/sage/combinat/ncsf_qsym/generic_basis_code.py b/src/sage/combinat/ncsf_qsym/generic_basis_code.py index f3dca7ca55a..a1ed27b8627 100644 --- a/src/sage/combinat/ncsf_qsym/generic_basis_code.py +++ b/src/sage/combinat/ncsf_qsym/generic_basis_code.py @@ -43,7 +43,6 @@ class BasesOfQSymOrNCSF(Category_realization_of_parent): - def _repr_object_names(self): r""" Return the name of the objects of this category. @@ -80,7 +79,6 @@ def super_categories(self): return [self.base().Realizations(), GradedHopfAlgebrasWithBasis(R), GradedHopfAlgebras(R).Realizations()] class ParentMethods: - def _repr_(self): """ TESTS:: @@ -789,7 +787,6 @@ def degree_negation(self, element): return self.sum_of_terms([(lam, (-1) ** (sum(lam) % 2) * a) for lam, a in self(element)], distinct=True) class ElementMethods: - def degree_negation(self): r""" Return the image of ``self`` under the degree negation diff --git a/src/sage/combinat/ncsf_qsym/ncsf.py b/src/sage/combinat/ncsf_qsym/ncsf.py index b9ada306095..aefabf6d21d 100644 --- a/src/sage/combinat/ncsf_qsym/ncsf.py +++ b/src/sage/combinat/ncsf_qsym/ncsf.py @@ -515,7 +515,6 @@ def super_categories(self): return [BasesOfQSymOrNCSF(self.base()), GradedModulesWithInternalProduct(R).Realizations()] class ParentMethods: - def to_symmetric_function_on_basis(self, I): r""" The image of the basis element indexed by ``I`` under the map @@ -696,7 +695,6 @@ def immaculate_function(self, xs): return self(res) class ElementMethods: - def verschiebung(self, n): r""" Return the image of the noncommutative symmetric function @@ -2023,7 +2021,6 @@ def super_categories(self): return [self.base().Bases()] class ParentMethods: - @cached_method def algebra_generators(self): """ @@ -2294,7 +2291,6 @@ def super_categories(self): return [self.base().MultiplicativeBases()] class ParentMethods: - def antipode_on_basis(self, composition): """ Return the application of the antipode to a basis element. @@ -2414,7 +2410,6 @@ def super_categories(self): return [self.base().MultiplicativeBases()] class ParentMethods: - def antipode_on_generators(self, i): r""" Return the image of a generator of a primitive basis of @@ -2670,7 +2665,6 @@ def to_symmetric_function_on_basis(self, I): return s(I.to_skew_partition()) class Element(CombinatorialFreeModule.Element): - def verschiebung(self, n): r""" Return the image of the noncommutative symmetric function @@ -3237,7 +3231,6 @@ def __init__(self, NCSF): CombinatorialFreeModule.__init__(self, NCSF.base_ring(), Compositions(), prefix='L', bracket=False, category=NCSF.MultiplicativeBasesOnGroupLikeElements()) class Element(CombinatorialFreeModule.Element): - def verschiebung(self, n): r""" Return the image of the noncommutative symmetric function @@ -3863,7 +3856,6 @@ def Gamma(K): return result class Element(CombinatorialFreeModule.Element): - def verschiebung(self, n): r""" Return the image of the noncommutative symmetric function @@ -4110,7 +4102,6 @@ def _to_complete_on_generators(self, n): return complete.sum_of_terms(((J, minus_one ** (len(J) + 1) * n / coeff_ell(J, [n])) for J in Compositions(n)), distinct=True) class Element(CombinatorialFreeModule.Element): - def verschiebung(self, n): r""" Return the image of the noncommutative symmetric function diff --git a/src/sage/combinat/ncsf_qsym/qsym.py b/src/sage/combinat/ncsf_qsym/qsym.py index 8599f050dae..82179a1e67d 100644 --- a/src/sage/combinat/ncsf_qsym/qsym.py +++ b/src/sage/combinat/ncsf_qsym/qsym.py @@ -8,6 +8,7 @@ - Chris Berg - Darij Grinberg """ + # **************************************************************************** # Copyright (C) 2010 Jason Bandlow , # 2012 Franco Saliola , @@ -2316,7 +2317,6 @@ def Eulerian(self, n, j, k=None): return self.sum_of_monomials(monomials) class Element(CombinatorialFreeModule.Element): - def internal_coproduct(self): r""" Return the inner coproduct of ``self`` in the Fundamental basis. diff --git a/src/sage/combinat/ncsym/bases.py b/src/sage/combinat/ncsym/bases.py index 34bdd97f145..4fc1f40665b 100644 --- a/src/sage/combinat/ncsym/bases.py +++ b/src/sage/combinat/ncsym/bases.py @@ -362,7 +362,7 @@ def _repr_(self): sage: NCSymBases(NCSym) Category of bases of symmetric functions in non-commuting variables over the Rational Field """ - return "Category of bases of symmetric functions in non-commuting" " variables over the {}".format(self.base().base_ring()) + return "Category of bases of symmetric functions in non-commuting variables over the {}".format(self.base().base_ring()) class ParentMethods: def from_symmetric_function(self, f): @@ -743,7 +743,7 @@ def _repr_(self): sage: MultiplicativeNCSymBases(NCSym) Category of multiplicative bases of symmetric functions in non-commuting variables over the Rational Field """ - return "Category of multiplicative bases of symmetric functions in non-commuting" " variables over the {}".format(self.base().base_ring()) + return "Category of multiplicative bases of symmetric functions in non-commuting variables over the {}".format(self.base().base_ring()) class ParentMethods: def product_on_basis(self, A, B): @@ -843,4 +843,4 @@ def _repr_(self): sage: NCSymDualBases(DNCSym) Category of bases of dual symmetric functions in non-commuting variables over the Rational Field """ - return "Category of bases of dual symmetric functions in non-commuting" " variables over the {}".format(self.base().base_ring()) + return "Category of bases of dual symmetric functions in non-commuting variables over the {}".format(self.base().base_ring()) diff --git a/src/sage/combinat/ncsym/ncsym.py b/src/sage/combinat/ncsym/ncsym.py index a59ce33e9f6..3a34aa53de1 100644 --- a/src/sage/combinat/ncsym/ncsym.py +++ b/src/sage/combinat/ncsym/ncsym.py @@ -6,6 +6,7 @@ - Travis Scrimshaw (08-04-2013): initial version """ + # **************************************************************************** # Copyright (C) 2013 Travis Scrimshaw # @@ -1088,7 +1089,7 @@ def _h_to_e_on_basis(self, A): """ e = self.realization_of().e() sign = lambda B: (-1) ** (B.size() - len(B)) - coeff = lambda B: (sign(B) * prod(factorial(sum(1 for part in B if part.issubset(big))) for big in A)) + coeff = lambda B: sign(B) * prod(factorial(sum(1 for part in B if part.issubset(big))) for big in A) R = self.base_ring() return e._from_dict({B: R(coeff(B)) for B in A.refinements()}, remove_zeros=False) @@ -1842,7 +1843,7 @@ def _m_to_rho_on_basis(self, A): ....: for A in SetPartitions(i)) True """ - coeff = lambda A, B: ((-1) ** len(set(B.arcs()).difference(A.arcs())) / self._q ** nesting(set(B).difference(A), B)) + coeff = lambda A, B: (-1) ** len(set(B.arcs()).difference(A.arcs())) / self._q ** nesting(set(B).difference(A), B) arcs = set(A.arcs()) return self._from_dict({B: coeff(A, B) for B in A.coarsenings() if arcs.issubset(B.arcs())}, remove_zeros=False) diff --git a/src/sage/combinat/nu_dyck_word.py b/src/sage/combinat/nu_dyck_word.py index 3d4e62bdeec..0634d2ad859 100644 --- a/src/sage/combinat/nu_dyck_word.py +++ b/src/sage/combinat/nu_dyck_word.py @@ -13,6 +13,7 @@ - Aram Dermenjian (2020-09-26) """ + # **************************************************************************** # Copyright (C) 2020 Aram Dermenjian , # @@ -1208,7 +1209,7 @@ class options(GlobalOptions): ascii_art = {'default': "pretty_output", 'description': 'Specifies how the ascii art of nu Dyck words should be printed', 'values': {'pretty_output': "Using pretty printing"}, 'alias': {'pretty_print': "pretty_output"}, 'case_sensitive': False} diagram_style = {'default': "grid", 'values': {'grid': 'printing as paths on a grid using N and E steps'}, 'alias': {'N-E': 'grid'}, 'case_sensitive': False} latex_tikz_scale = {'default': 1, 'description': 'The default value for the tikz scale when latexed', 'checker': lambda x: True} # More trouble than it's worth to check - latex_line_width_scalar = {'default': 2, 'description': 'The default value for the line width as a ' 'multiple of the tikz scale when latexed', 'checker': lambda x: True} # More trouble than it's worth to check + latex_line_width_scalar = {'default': 2, 'description': 'The default value for the line width as a multiple of the tikz scale when latexed', 'checker': lambda x: True} # More trouble than it's worth to check latex_color = {'default': "black", 'description': 'The default value for the color when latexed', 'checker': lambda x: isinstance(x, str)} latex_show_points = {'default': False, 'description': 'The default value for showing points', 'checker': lambda x: isinstance(x, bool)} latex_points_color = {'default': 'black', 'description': 'The default value for path color.', 'checker': lambda x: isinstance(x, str)} diff --git a/src/sage/combinat/nu_tamari_lattice.py b/src/sage/combinat/nu_tamari_lattice.py index 07275ee6706..e2ed6cf0372 100644 --- a/src/sage/combinat/nu_tamari_lattice.py +++ b/src/sage/combinat/nu_tamari_lattice.py @@ -52,6 +52,7 @@ - Clément Chenevière (2024-02-01): added the alt `\nu`-Tamari lattices """ + # **************************************************************************** # Copyright (C) 2020-2020 Aram Dermenjian # diff --git a/src/sage/combinat/ordered_tree.py b/src/sage/combinat/ordered_tree.py index 548b1ba259b..df89ba1dca3 100644 --- a/src/sage/combinat/ordered_tree.py +++ b/src/sage/combinat/ordered_tree.py @@ -309,7 +309,7 @@ def _to_binary_tree_rec(self, bijection='left'): for child in children: root = BinaryTree([child._to_binary_tree_rec(bijection), root]) else: - raise ValueError("the bijection argument should be either " "left or right") + raise ValueError("the bijection argument should be either left or right") return root @combinatorial_map(name="To binary tree, left brother = left child") diff --git a/src/sage/combinat/output.py b/src/sage/combinat/output.py index 7ac6bd4b4b4..a6e6b908d98 100644 --- a/src/sage/combinat/output.py +++ b/src/sage/combinat/output.py @@ -437,18 +437,18 @@ def svg_from_skew_array(array, with_lines=False, align='b') -> str: sage: sage.combinat.output.svg_from_skew_array(array) '' """ - resu = '' - resu += ' str: for j, content in enumerate(line): cj = 10 * j if content is not None: - resu += '{content}' + resu += '' + resu += f'{content}' return resu + '' diff --git a/src/sage/combinat/parallelogram_polyomino.py b/src/sage/combinat/parallelogram_polyomino.py index 6f2641ab906..faac78b849e 100644 --- a/src/sage/combinat/parallelogram_polyomino.py +++ b/src/sage/combinat/parallelogram_polyomino.py @@ -5,6 +5,7 @@ The goal of this module is to give some tools to manipulate the parallelogram polyominoes. """ + # ***************************************************************************** # Copyright (C) 2014,2015 Adrien Boussicault (boussica@labri.fr), # Copyright (C) 2016 Patxi Laborde-Zubieta (plaborde@labri.fr), @@ -3952,7 +3953,7 @@ def __call__(self, size=None, policy=None): return ParallelogramPolyominoes_size(size, policy) if size is None: return ParallelogramPolyominoes_all(policy) - raise ValueError("invalid argument for Parallelogram Polyominoes " "Factory") + raise ValueError("invalid argument for Parallelogram Polyominoes Factory") @lazy_attribute def _default_policy(self): diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 0a0c2daa73a..9b25007c565 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -2912,7 +2912,7 @@ def top_garnir_tableau(self, e, cell): """ row, col = cell if row + 1 >= len(self) or col >= self[row + 1]: - raise ValueError(f'({row+1},{col})=(row+1,col) must be inside the diagram') + raise ValueError(f'({row + 1},{col})=(row+1,col) must be inside the diagram') g = self.garnir_tableau(cell) # start with the Garnir tableau and modify @@ -6287,7 +6287,7 @@ def __classcall_private__(cls, n=None, **kwargs): # so we use a class inheriting from Partitions return Partitions_all_constrained(**kwargs) - raise ValueError("n must be an integer or be equal to one of " "None, NN, NonNegativeIntegers()") + raise ValueError("n must be an integer or be equal to one of None, NN, NonNegativeIntegers()") def __init__(self, is_infinite=False): """ diff --git a/src/sage/combinat/partition_algebra.py b/src/sage/combinat/partition_algebra.py index f46c2ddae70..1e75d4cd595 100644 --- a/src/sage/combinat/partition_algebra.py +++ b/src/sage/combinat/partition_algebra.py @@ -2,6 +2,7 @@ r""" Partition/diagram algebras """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # diff --git a/src/sage/combinat/partition_shifting_algebras.py b/src/sage/combinat/partition_shifting_algebras.py index d7681029feb..41e63fd2363 100644 --- a/src/sage/combinat/partition_shifting_algebras.py +++ b/src/sage/combinat/partition_shifting_algebras.py @@ -12,6 +12,7 @@ - Matthew Lancellotti, George H. Seelinger (2018): initial version """ + # **************************************************************************** # Copyright (C) 2018 Matthew Lancellotti # George H. Seelinger diff --git a/src/sage/combinat/partition_tuple.py b/src/sage/combinat/partition_tuple.py index 4afce243d31..bb4f9986e7a 100644 --- a/src/sage/combinat/partition_tuple.py +++ b/src/sage/combinat/partition_tuple.py @@ -1826,11 +1826,11 @@ def __classcall_private__(klass, level=None, size=None, regular=None): if isinstance(regular, (list, tuple)): if level is None: - raise ValueError("When no level is specified, regular must be " "a positive integer") + raise ValueError("When no level is specified, regular must be a positive integer") if len(regular) != level: raise ValueError("regular must be a list of length {}, got {}".format(level, regular)) if regular == 0: - raise ValueError("regular must be a positive integer or a tuple " "of nonnegative integers") + raise ValueError("regular must be a positive integer or a tuple of nonnegative integers") if level is None: if size is None: if regular is None: diff --git a/src/sage/combinat/perfect_matching.py b/src/sage/combinat/perfect_matching.py index 04292070fbf..2067d8cb20a 100644 --- a/src/sage/combinat/perfect_matching.py +++ b/src/sage/combinat/perfect_matching.py @@ -157,7 +157,7 @@ def __classcall_private__(cls, parts): if (isinstance(parts, list) and all(isinstance(x, (int, Integer)) for x in parts)) or isinstance(parts, Permutation): s = Permutation(parts) if not all(e == 2 for e in s.cycle_type()): - raise ValueError("permutation p (= {}) is not a " "fixed point free involution".format(s)) + raise ValueError("permutation p (= {}) is not a fixed point free involution".format(s)) parts = s.to_cycles() base_set = frozenset(e for p in parts for e in p) diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index 8a3968946ec..f1f3087c1aa 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -602,7 +602,7 @@ def __init__(self, parent, l, algorithm='lex', sjt=None, check=True) -> None: except TypeError: raise ValueError("the elements must be integer variables") if i < 1: - raise ValueError("the elements must be strictly positive " "integers") + raise ValueError("the elements must be strictly positive integers") lst.sort() @@ -951,7 +951,7 @@ def prev(self): algorithm. """ if self._algorithm == "sjt": - raise NotImplementedError("previous permutation for SJT algorithm " "is not yet implemented") + raise NotImplementedError("previous permutation for SJT algorithm is not yet implemented") p = self[:] n = len(self) @@ -6179,9 +6179,9 @@ class options(GlobalOptions): 'default': "list", 'description': "Specifies how the permutations should be printed", 'values': { - 'list': "the permutations are displayed in list notation" " (aka 1-line notation)", - 'cycle': "the permutations are displayed in cycle notation" " (i. e., as products of disjoint cycles)", - 'singleton': "the permutations are displayed in cycle notation" " with singleton cycles shown as well", + 'list': "the permutations are displayed in list notation (aka 1-line notation)", + 'cycle': "the permutations are displayed in cycle notation (i. e., as products of disjoint cycles)", + 'singleton': "the permutations are displayed in cycle notation with singleton cycles shown as well", 'reduced_word': "the permutations are displayed as reduced words", }, 'alias': {'word': "reduced_word", 'reduced_expression': "reduced_word"}, @@ -7652,7 +7652,7 @@ def element_in_conjugacy_classes(self, nu): nu = Partition(nu) if nu.size() > self.n: - raise ValueError("the size of the partition (={}) should be at most" " the size of the permutations (={})".format(nu.size(), self.n)) + raise ValueError("the size of the partition (={}) should be at most the size of the permutations (={})".format(nu.size(), self.n)) l = [] i = 0 for nui in nu: @@ -8234,11 +8234,11 @@ def from_cycles(n, cycles, parent=None): # check that the values are valid if (k < 1) or (pk < 1): - raise ValueError("all elements should be strictly positive " f"integers, but I found {min(k, pk)}") + raise ValueError(f"all elements should be strictly positive integers, but I found {min(k, pk)}") if (k > n) or (pk > n): - raise ValueError("you claimed that this is a permutation on " f"1...{n}, but it contains {max(k, pk)}") + raise ValueError(f"you claimed that this is a permutation on 1...{n}, but it contains {max(k, pk)}") if p[k - 1] is not None: - raise ValueError(f"the element {k} appears more than once" " in the input") + raise ValueError(f"the element {k} appears more than once in the input") p[k - 1] = pk # values that are not in any cycle are fixed points of the permutation diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 013ea4573e3..b3c93aa7c65 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -544,20 +544,20 @@ def _repr_svg_(self) -> str: """ colors = ["snow", "tomato", "steelblue"] - resu = '' - resu += '' - resu += '' - resu1 += '' - resu1 += '' - resu1 += '' + resu1 += '' + resu1 += '' + resu1 += '' vx = -vector([0.866, -0.5]) vy = -vector([-0.866, -0.5]) @@ -566,7 +566,7 @@ def _repr_svg_(self) -> str: # use the smallest one possible. Nx, Ny, Nz = self.bounding_box() - resu += '\"%.3f %.3f %.3f %.3f \">' % (-0.866 * Nx, -Nz, 0.866 * Nx + 0.866 * Ny, Nz + 0.5 * (Nx + Ny)) + resu += '"%.3f %.3f %.3f %.3f ">' % (-0.866 * Nx, -Nz, 0.866 * Nx + 0.866 * Ny, Nz + 0.5 * (Nx + Ny)) resu += resu1 mat = self.z_tableau() @@ -574,24 +574,24 @@ def _repr_svg_(self) -> str: for j in range(Ny): if mat[i][j]: v = i * vx + j * vy + mat[i][j] * vz - resu += '' def _latex_(self, show_box=False, colors=["white", "lightgray", "darkgray"]) -> str: diff --git a/src/sage/combinat/posets/cartesian_product.py b/src/sage/combinat/posets/cartesian_product.py index d6727e638aa..a1202fed978 100644 --- a/src/sage/combinat/posets/cartesian_product.py +++ b/src/sage/combinat/posets/cartesian_product.py @@ -295,7 +295,6 @@ def le_native(self, left, right): return left.value <= right.value class Element(CartesianProduct.Element): - def _le_(self, other): r""" Return if this element is less or equal to ``other``. diff --git a/src/sage/combinat/posets/elements.py b/src/sage/combinat/posets/elements.py index c28ecfe1db6..0f6d6a42406 100644 --- a/src/sage/combinat/posets/elements.py +++ b/src/sage/combinat/posets/elements.py @@ -2,6 +2,7 @@ r""" Elements of posets, lattices, semilattices, etc. """ + # **************************************************************************** # Copyright (C) 2008 Peter Jipsen , # Franco Saliola @@ -22,7 +23,6 @@ class PosetElement(Element): - def __init__(self, poset, element, vertex) -> None: r""" Establish the parent-child relationship between ``poset`` diff --git a/src/sage/combinat/posets/hasse_diagram.py b/src/sage/combinat/posets/hasse_diagram.py index 277bb46b7c5..96c97621935 100644 --- a/src/sage/combinat/posets/hasse_diagram.py +++ b/src/sage/combinat/posets/hasse_diagram.py @@ -2081,7 +2081,6 @@ def recursive_fit(orthocomplements, unbinded): possible_values = [y for y in possible_values if self.has_edge(orthocomplements[x], y)] for e in possible_values: - new_binded = orthocomplements[:] new_binded[next_to_fit] = e new_binded[e] = next_to_fit @@ -3271,7 +3270,6 @@ def fill_to_interval(S): todo = {cong.find(e) for part in parts for e in part} while todo: - # First check if we should stop now. for a, b in stop_pairs: if cong.find(a) == cong.find(b): diff --git a/src/sage/combinat/posets/incidence_algebras.py b/src/sage/combinat/posets/incidence_algebras.py index 73e4861bd2b..e7915b24089 100644 --- a/src/sage/combinat/posets/incidence_algebras.py +++ b/src/sage/combinat/posets/incidence_algebras.py @@ -2,6 +2,7 @@ r""" Incidence algebras """ + # **************************************************************************** # Copyright (C) 2014 Travis Scrimshaw # diff --git a/src/sage/combinat/posets/lattices.py b/src/sage/combinat/posets/lattices.py index ef48cb2d16a..b37c8a58e50 100644 --- a/src/sage/combinat/posets/lattices.py +++ b/src/sage/combinat/posets/lattices.py @@ -132,6 +132,7 @@ :meth:`~FiniteLatticePoset.quotient` | Return the quotient lattice by a congruence. :meth:`~FiniteLatticePoset.congruences_lattice` | Return the lattice of congruences. """ + # ***************************************************************************** # Copyright (C) 2008 Peter Jipsen , # Franco Saliola diff --git a/src/sage/combinat/posets/poset_examples.py b/src/sage/combinat/posets/poset_examples.py index a71cdffc409..818605ec04d 100644 --- a/src/sage/combinat/posets/poset_examples.py +++ b/src/sage/combinat/posets/poset_examples.py @@ -83,6 +83,7 @@ Constructions ------------- """ + # **************************************************************************** # Copyright (C) 2008 Peter Jipsen , # Franco Saliola @@ -1950,7 +1951,6 @@ def _random_lattice(n, p): lc_all = [[]] # No lower covers for the bottom element. for i in range(1, n): - # Look for an admissible lower cover for the next element i while True: # Generate a random antichain diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index efa0258c15d..ac58ddcbf20 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -691,7 +691,7 @@ def Poset(data=None, element_labels=None, cover_relations=False, linear_extensio """ # Avoiding some errors from the user when data should be a pair if not (element_labels is None or isinstance(element_labels, (dict, list))): - raise TypeError("element_labels should be a dict or a list if " "different from None. (Did you intend data to be " "equal to a pair ?)") + raise TypeError("element_labels should be a dict or a list if different from None. (Did you intend data to be equal to a pair ?)") if isinstance(data, FinitePoset): if element_labels is None and category is None and facade is None and linear_extension == data._with_linear_extension: @@ -768,7 +768,7 @@ def Poset(data=None, element_labels=None, cover_relations=False, linear_extensio raise ValueError("Hasse diagram contains cycles") # Check for duplicate elements elif len(elements) != len(set(elements)): - raise ValueError("the provided list of elements is not a linear " "extension for the poset as it contains " "duplicate elements") + raise ValueError("the provided list of elements is not a linear extension for the poset as it contains duplicate elements") else: elements = None return FinitePoset(D, elements=elements, category=category, facade=facade, key=key) @@ -1521,7 +1521,7 @@ def _rich_repr_(self, display_manager, **kwds): # latex() produces huge tikz environment, override tp = display_manager.types if prefs.text == 'latex' and tp.OutputLatex in display_manager.supported_output(): - return tp.OutputLatex(fr'\text{{{text}}}') + return tp.OutputLatex(rf'\text{{{text}}}') return tp.OutputPlainText(text) def __iter__(self): @@ -5119,7 +5119,6 @@ def ordinal_summands(self) -> builtins.list: upper = set(H.sources()) for e in range(n): - # update 'lower' by adding 'e' to it lower.add(e) lower.difference_update(H.neighbors_in(e)) @@ -9224,7 +9223,6 @@ def _ford_fulkerson_chronicle(G, s, t, a): capacity = [1 for _ in range(m)] while True: - # Step MC1 in Britz-Fomin, Algorithm 7.2. # Gprime: directed graph G' from Britz-Fomin, Section 7. diff --git a/src/sage/combinat/recognizable_series.py b/src/sage/combinat/recognizable_series.py index 40f39798e3c..ff69e17b86f 100644 --- a/src/sage/combinat/recognizable_series.py +++ b/src/sage/combinat/recognizable_series.py @@ -153,7 +153,7 @@ def add(self, w, check=True) -> None: ValueError: cannot add as not all prefixes of 11 are included yet """ if check and any(p not in self.elements for p in w.prefixes_iterator() if p != w): - raise ValueError('cannot add as not all prefixes of ' '{} are included yet'.format(w)) + raise ValueError('cannot add as not all prefixes of {} are included yet'.format(w)) self.elements.append(w) def iterate_possible_additions(self): @@ -1804,7 +1804,7 @@ def _repr_(self) -> str: sage: repr(RecognizableSeriesSpace(ZZ, [0, 1])) # indirect doctest 'Space of recognizable series on {0, 1} with coefficients in Integer Ring' """ - return 'Space of recognizable series on {} ' 'with coefficients in {}'.format(self.alphabet(), self.coefficient_ring()) + return 'Space of recognizable series on {} with coefficients in {}'.format(self.alphabet(), self.coefficient_ring()) def _an_element_(self): r""" diff --git a/src/sage/combinat/regular_sequence.py b/src/sage/combinat/regular_sequence.py index 43c22bc777e..47bc25d4066 100644 --- a/src/sage/combinat/regular_sequence.py +++ b/src/sage/combinat/regular_sequence.py @@ -75,6 +75,7 @@ Classes and Methods =================== """ + # **************************************************************************** # Copyright (C) 2016 Daniel Krenn # 2021 Gabriel F. Lipnik @@ -384,7 +385,7 @@ def _error_if_degenerated_(self): by a call of method .regenerated() for correcting this. """ if self.is_degenerated(): - raise DegeneratedSequenceError("degenerated sequence: mu[0]*right != right. " "Using such a sequence might lead to wrong results. " "You can use 'allow_degenerated_sequence=True' followed by " "a call of method .regenerated() " "for correcting this.") + raise DegeneratedSequenceError("degenerated sequence: mu[0]*right != right. Using such a sequence might lead to wrong results. You can use 'allow_degenerated_sequence=True' followed by a call of method .regenerated() for correcting this.") @cached_method @minimize_result @@ -2017,7 +2018,7 @@ def include(t, r): while to_branch: t_R, r_R = to_branch.pop(0) if t_R >= max_exponent: - raise RuntimeError(f'aborting as exponents would be larger ' f'than max_exponent={max_exponent}') + raise RuntimeError(f'aborting as exponents would be larger than max_exponent={max_exponent}') t_L = t_R + 1 for s_L in srange(k): @@ -2832,7 +2833,7 @@ def parse_multiplication(op, eq): return [operands[0], operands[1]] if operands[0].operator() == function: return [operands[1], operands[0]] - raise ValueError('Term %s in the equation %s ' 'does not contain %s.' % (op, eq, function)) + raise ValueError('Term %s in the equation %s does not contain %s.' % (op, eq, function)) def parse_one_summand(summand, eq): if summand.operator() == mul_vararg: @@ -2844,7 +2845,7 @@ def parse_one_summand(summand, eq): try: coeff = coefficient_ring(coeff) except (TypeError, ValueError): - raise ValueError("Term %s in the equation %s: " "%s is not a valid coefficient " "since it is not in %s." % (summand, eq, coeff, coefficient_ring)) from None + raise ValueError("Term %s in the equation %s: %s is not a valid coefficient since it is not in %s." % (summand, eq, coeff, coefficient_ring)) from None if len(op.operands()) > 1: raise ValueError('Term %s in the equation %s has more than one argument.' % (op, eq)) elif len(op.operands()) == 0: @@ -2852,15 +2853,15 @@ def parse_one_summand(summand, eq): try: poly = ZZ[var](op.operands()[0]) except TypeError: - raise ValueError('Term %s in the equation %s: ' '%s is not a polynomial in %s with integer coefficients.' % (op, eq, op.operands()[0], var)) from None + raise ValueError('Term %s in the equation %s: %s is not a polynomial in %s with integer coefficients.' % (op, eq, op.operands()[0], var)) from None if poly.degree() != 1: - raise ValueError("Term %s in the equation %s: " "polynomial %s does not have degree 1." % (op, eq, poly)) + raise ValueError("Term %s in the equation %s: polynomial %s does not have degree 1." % (op, eq, poly)) d, base_power_m = list(poly) m = log(base_power_m, base=k) try: m = ZZ(m) except (TypeError, ValueError): - raise ValueError("Term %s in the equation %s: " "%s is not a power of %s." % (summand, eq, k**m, k)) from None + raise ValueError("Term %s in the equation %s: %s is not a power of %s." % (summand, eq, k**m, k)) from None return [coeff, m, d] if not equations: @@ -2876,18 +2877,18 @@ def parse_one_summand(summand, eq): if left_side.operator() != function: raise ValueError("Term %s in the equation %s is not an evaluation of %s." % (left_side, eq, function)) if len(left_side.operands()) != 1: - raise ValueError("Term %s in the equation %s does not have " "one argument." % (left_side, eq)) + raise ValueError("Term %s in the equation %s does not have one argument." % (left_side, eq)) try: polynomial_left = ZZ[var](left_side.operands()[0]) except TypeError: - raise ValueError("Term %s in the equation %s: " "%s is not a polynomial in %s with " "integer coefficients." % (left_side, eq, left_side.operands()[0], var)) from None + raise ValueError("Term %s in the equation %s: %s is not a polynomial in %s with integer coefficients." % (left_side, eq, left_side.operands()[0], var)) from None if polynomial_left.degree() > 1: - raise ValueError("Term %s in the equation %s: " "%s is not a polynomial in %s of degree smaller than 2." % (left_side, eq, polynomial_left, var)) + raise ValueError("Term %s in the equation %s: %s is not a polynomial in %s of degree smaller than 2." % (left_side, eq, polynomial_left, var)) if polynomial_left in ZZ: try: right_side = coefficient_ring(right_side) except (TypeError, ValueError): - raise ValueError("Initial value %s given by the equation %s " "is not in %s." % (right_side, eq, coefficient_ring)) from None + raise ValueError("Initial value %s given by the equation %s is not in %s." % (right_side, eq, coefficient_ring)) from None if polynomial_left in initial_values.keys() and initial_values[polynomial_left] != right_side: raise ValueError("Initial value %s is given twice." % (function(polynomial_left))) initial_values.update({polynomial_left: right_side}) @@ -2897,19 +2898,19 @@ def parse_one_summand(summand, eq): try: M_new = ZZ(M_new) except (TypeError, ValueError): - raise ValueError("Term %s in the equation %s: " "%s is not a power of %s." % (left_side, eq, base_power_M, k)) from None + raise ValueError("Term %s in the equation %s: %s is not a power of %s." % (left_side, eq, base_power_M, k)) from None if M is not None and M != M_new: - raise ValueError(("Term {0} in the equation {1}: " "{2} does not equal {3}. Expected " "subsequence modulo {3} as in another " "equation, got subsequence modulo {2}.").format(left_side, eq, base_power_M, k**M)) + raise ValueError(("Term {0} in the equation {1}: {2} does not equal {3}. Expected subsequence modulo {3} as in another equation, got subsequence modulo {2}.").format(left_side, eq, base_power_M, k**M)) elif M is None: M = M_new if M < 1: - raise ValueError(("Term {0} in the equation {1}: " "{2} is less than {3}. Modulus must " "be at least {3}.").format(left_side, eq, base_power_M, k)) + raise ValueError(("Term {0} in the equation {1}: {2} is less than {3}. Modulus must be at least {3}.").format(left_side, eq, base_power_M, k)) if r in remainders: raise ValueError("There are more than one recurrence relation for %s." % (left_side,)) if r >= k**M: - raise ValueError("Term %s in the equation %s: " "remainder %s is not smaller than modulus %s." % (left_side, eq, r, k**M)) + raise ValueError("Term %s in the equation %s: remainder %s is not smaller than modulus %s." % (left_side, eq, r, k**M)) elif r < 0: - raise ValueError("Term %s in the equation %s: " "remainder %s is smaller than 0." % (left_side, eq, r)) + raise ValueError("Term %s in the equation %s: remainder %s is smaller than 0." % (left_side, eq, r)) else: remainders.add(r) if right_side != 0: @@ -2922,11 +2923,11 @@ def parse_one_summand(summand, eq): for summand in summands: coeff, new_m, d = parse_one_summand(summand, eq) if m is not None and m != new_m: - raise ValueError(("Term {0} in the equation {1}: " "{2} does not equal {3}. Expected " "subsequence modulo {3} as in another " "summand or equation, got subsequence " "modulo {2}.").format(summand, eq, k**new_m, k**m)) + raise ValueError(("Term {0} in the equation {1}: {2} does not equal {3}. Expected subsequence modulo {3} as in another summand or equation, got subsequence modulo {2}.").format(summand, eq, k**new_m, k**m)) elif m is None: m = new_m if M <= m: - raise ValueError("Term %s in the equation %s: " "%s is not smaller than %s." % (summand, eq, k**m, k**M)) + raise ValueError("Term %s in the equation %s: %s is not smaller than %s." % (summand, eq, k**m, k**M)) coeffs.update({(r, d): coeff}) if not M: @@ -3078,24 +3079,24 @@ def parse_direct_arguments(self, M, m, coeffs, initial_values): invalid_coeffs = [coeff for coeff in coeffs.values() if coeff not in coefficient_ring] if invalid_coeffs: - raise ValueError("Coefficients %s are not valid " "since they are not in %s." % (invalid_coeffs, coefficient_ring)) from None + raise ValueError("Coefficients %s are not valid since they are not in %s." % (invalid_coeffs, coefficient_ring)) from None coeffs_keys = coeffs.keys() invalid_coeffs_keys = [key for key in coeffs_keys if key[0] not in ZZ or key[1] not in ZZ] if invalid_coeffs_keys: - raise ValueError("Keys %s for coefficients are not valid " "since one of their components is no integer." % (invalid_coeffs_keys,)) from None + raise ValueError("Keys %s for coefficients are not valid since one of their components is no integer." % (invalid_coeffs_keys,)) from None invalid_coeffs_keys = [key for key in coeffs_keys if key[0] < 0 or key[0] >= k**M] if invalid_coeffs_keys: - raise ValueError("Keys %s for coefficients are not valid " "since their first component is either smaller than 0 " " or larger than or equal to %s." % (invalid_coeffs_keys, k**M)) from None + raise ValueError("Keys %s for coefficients are not valid since their first component is either smaller than 0 or larger than or equal to %s." % (invalid_coeffs_keys, k**M)) from None invalid_initial_values = [value for value in initial_values.values() if value not in coefficient_ring] if invalid_initial_values: - raise ValueError("Initial values %s are not valid " "since they are not in %s." % (invalid_initial_values, coefficient_ring)) from None + raise ValueError("Initial values %s are not valid since they are not in %s." % (invalid_initial_values, coefficient_ring)) from None invalid_initial_keys = [key for key in initial_values.keys() if key not in ZZ] if invalid_initial_keys: - raise ValueError("Keys %s for the initial values are not valid " "since they are no integers." % (invalid_initial_keys,)) from None + raise ValueError("Keys %s for the initial values are not valid since they are no integers." % (invalid_initial_keys,)) from None return (M, m, coeffs, initial_values) @@ -3245,13 +3246,13 @@ def parameters(self, M, m, coeffs, initial_values, offset=0, inhomogeneities={}) if inhomogeneities: invalid_indices = [i for i in inhomogeneities if i not in srange(k**M)] if invalid_indices: - raise ValueError(f"Indices {invalid_indices} for inhomogeneities are no " f"integers between 0 and {k**M - 1}.") + raise ValueError(f"Indices {invalid_indices} for inhomogeneities are no integers between 0 and {k**M - 1}.") Seq = RegularSequenceRing(k, coefficient_ring) inhomogeneities.update({i: inhomogeneities[i] * Seq.one_hadamard() for i in inhomogeneities if inhomogeneities[i] in coefficient_ring}) invalid = {i: inhomogeneities[i] for i in inhomogeneities if not (isinstance(inhomogeneities[i].parent(), RegularSequenceRing) and inhomogeneities[i].parent().k == k)} if invalid: - raise ValueError(f"Inhomogeneities {invalid} are neither {k}-regular " f"sequences nor elements of {coefficient_ring}.") + raise ValueError(f"Inhomogeneities {invalid} are neither {k}-regular sequences nor elements of {coefficient_ring}.") if not initial_values: raise ValueError("No initial values are given.") @@ -3457,7 +3458,7 @@ def f(n): for n in keys_initial: q, r = ZZ(n).quo_rem(k**M) if q >= offset and values[n] != (sum([coeff(r, j) * values[k**m * q + j] for j in srange(l, u + 1)])) + inhomogeneity(r, q): - raise ValueError("Initial value for argument %s does not match with " "the given recurrence relations." % (n,)) + raise ValueError("Initial value for argument %s does not match with the given recurrence relations." % (n,)) values.update({n: 0 for n in srange(ll, 0)}) diff --git a/src/sage/combinat/ribbon_tableau.py b/src/sage/combinat/ribbon_tableau.py index 9ca6aea8f43..27145c28595 100644 --- a/src/sage/combinat/ribbon_tableau.py +++ b/src/sage/combinat/ribbon_tableau.py @@ -96,7 +96,7 @@ def __classcall_private__(cls, rt=None, expr=None): try: rt = [tuple(row) for row in rt] except TypeError: - raise TypeError("each element of the ribbon tableau " "must be an iterable") + raise TypeError("each element of the ribbon tableau must be an iterable") if not all(row for row in rt): raise TypeError("a ribbon tableau cannot have empty rows") # calls the inherited __init__ method (of SkewTableau ) diff --git a/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py b/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py index 5c9946ee2d9..4265bf08b89 100644 --- a/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py +++ b/src/sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py @@ -316,7 +316,7 @@ def __init__(self, cartan_type, B): FullTensorProductOfRegularCrystals.__init__(self, tensor_prod, cartan_type=cartan_type) # This is needed to override the module_generators set in FullTensorProductOfRegularCrystals self.module_generators = HighestWeightTensorKRT(self) - self.rename("Tensor product of Kirillov-Reshetikhin tableaux " f"of type {cartan_type} and factor(s) {B}") + self.rename(f"Tensor product of Kirillov-Reshetikhin tableaux of type {cartan_type} and factor(s) {B}") def __iter__(self): """ diff --git a/src/sage/combinat/root_system/associahedron.py b/src/sage/combinat/root_system/associahedron.py index cb57168eb71..c764eb6ec9d 100644 --- a/src/sage/combinat/root_system/associahedron.py +++ b/src/sage/combinat/root_system/associahedron.py @@ -12,6 +12,7 @@ - Christian Stump """ + # *************************************************************************** # Copyright (C) 2011-2012 Christian Stump # diff --git a/src/sage/combinat/root_system/cartan_type.py b/src/sage/combinat/root_system/cartan_type.py index 876c6167eca..9ca9a62d835 100644 --- a/src/sage/combinat/root_system/cartan_type.py +++ b/src/sage/combinat/root_system/cartan_type.py @@ -502,7 +502,6 @@ class CartanTypeFactory(SageObject): - def __call__(self, *args): """ Construct a Cartan type object. diff --git a/src/sage/combinat/root_system/dynkin_diagram.py b/src/sage/combinat/root_system/dynkin_diagram.py index ae172c1a335..33dfeb48089 100644 --- a/src/sage/combinat/root_system/dynkin_diagram.py +++ b/src/sage/combinat/root_system/dynkin_diagram.py @@ -13,6 +13,7 @@ - Christian Stump, Travis Scrimshaw (2013-04-11): Added Cartan matrix as possible input for Dynkin diagrams. """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # Copyright (C) 2013 Travis Scrimshaw diff --git a/src/sage/combinat/root_system/extended_affine_weyl_group.py b/src/sage/combinat/root_system/extended_affine_weyl_group.py index b8ab9a5f488..d47def576bb 100644 --- a/src/sage/combinat/root_system/extended_affine_weyl_group.py +++ b/src/sage/combinat/root_system/extended_affine_weyl_group.py @@ -11,6 +11,7 @@ - Nicolas M. Thiery (2012): initial version - Mark Shimozono (2013): twisted affine root systems, multiple realizations, GL_n """ + # *************************************************************************** # Copyright (C) 2012 Daniel Bump , # 2012 Daniel Orr @@ -1079,7 +1080,6 @@ def super_categories(self): return [Groups().Realizations()] class ParentMethods: - @cached_method def from_fundamental(self, x): r""" @@ -1319,7 +1319,6 @@ def from_reduced_word(self, word): return self.from_affine_weyl(self.realization_of().affine_weyl().from_reduced_word(word)) class ElementMethods: - @abstract_method def has_descent(self, i, side='right', positive=False) -> bool: r""" diff --git a/src/sage/combinat/root_system/fundamental_group.py b/src/sage/combinat/root_system/fundamental_group.py index 0106229a089..8f9d3d7dc31 100644 --- a/src/sage/combinat/root_system/fundamental_group.py +++ b/src/sage/combinat/root_system/fundamental_group.py @@ -6,6 +6,7 @@ - Mark Shimozono (2013) initial version """ + # **************************************************************************** # Copyright (C) 2013 Mark Shimozono # diff --git a/src/sage/combinat/root_system/hecke_algebra_representation.py b/src/sage/combinat/root_system/hecke_algebra_representation.py index bb9826d2015..a4016d52276 100644 --- a/src/sage/combinat/root_system/hecke_algebra_representation.py +++ b/src/sage/combinat/root_system/hecke_algebra_representation.py @@ -2,6 +2,7 @@ r""" Hecke algebra representations """ + # *************************************************************************** # Copyright (C) 2013 Nicolas M. Thiery # Anne Schilling diff --git a/src/sage/combinat/root_system/integrable_representations.py b/src/sage/combinat/root_system/integrable_representations.py index 51d31c753dc..e7158dbab49 100644 --- a/src/sage/combinat/root_system/integrable_representations.py +++ b/src/sage/combinat/root_system/integrable_representations.py @@ -2,6 +2,7 @@ """ Integrable representations of affine Lie algebras """ + # *************************************************************************** # Copyright (C) 2014, 2105 Daniel Bump # Travis Scrimshaw diff --git a/src/sage/combinat/root_system/non_symmetric_macdonald_polynomials.py b/src/sage/combinat/root_system/non_symmetric_macdonald_polynomials.py index fabb75b2d75..a21c33b64b6 100644 --- a/src/sage/combinat/root_system/non_symmetric_macdonald_polynomials.py +++ b/src/sage/combinat/root_system/non_symmetric_macdonald_polynomials.py @@ -16,6 +16,7 @@ Special thanks go to Bogdan Ion and Mark Shimozono for their patient explanations and hand computations to check the code. """ + # **************************************************************************** # Copyright (C) 2013 Nicolas M. Thiery # Anne Schilling diff --git a/src/sage/combinat/root_system/pieri_factors.py b/src/sage/combinat/root_system/pieri_factors.py index 6b7e0a9a7e2..96a38360fae 100644 --- a/src/sage/combinat/root_system/pieri_factors.py +++ b/src/sage/combinat/root_system/pieri_factors.py @@ -335,7 +335,6 @@ def maximal_elements(self): class PieriFactors_affine_type(PieriFactors): - def maximal_elements(self): r""" Return the maximal elements of ``self`` with respect to Bruhat order. @@ -584,7 +583,7 @@ def __init__(self, W, min_length, max_length, min_support, max_support): self._max_support = frozenset(max_support) if not self._min_support.issubset(self._max_support): - raise ValueError("the min support must be a subset " "of the max support") + raise ValueError("the min support must be a subset of the max support") self._extra_support = self._max_support.difference(self._min_support) diff --git a/src/sage/combinat/root_system/reflection_group_complex.py b/src/sage/combinat/root_system/reflection_group_complex.py index 4fa33d8db22..8e2851f807d 100644 --- a/src/sage/combinat/root_system/reflection_group_complex.py +++ b/src/sage/combinat/root_system/reflection_group_complex.py @@ -2022,7 +2022,6 @@ def reflection_length(self, in_unitary_group=False): class IrreducibleComplexReflectionGroup(ComplexReflectionGroup): - def _repr_(self): r""" Return the string representation of ``self``. @@ -2038,7 +2037,6 @@ def _repr_(self): return 'Irreducible complex reflection group of rank %s and type %s' % (self._rank, type_str) class Element(ComplexReflectionGroup.Element): - # TODO: lift to ComplexReflectionGroups.Finite # this method can be defined for well-generated, finite, # irreducible complex reflection group. The current diff --git a/src/sage/combinat/root_system/reflection_group_real.py b/src/sage/combinat/root_system/reflection_group_real.py index 8582a78f740..afef1734010 100644 --- a/src/sage/combinat/root_system/reflection_group_real.py +++ b/src/sage/combinat/root_system/reflection_group_real.py @@ -782,7 +782,6 @@ def bruhat_cone(self, x, y, side='upper', backend='cdd'): return Polyhedron(vertices=[[0] * self.rank()], rays=roots, ambient_dim=self.rank(), base_ring=base_ring, backend=backend) class Element(RealReflectionGroupElement, ComplexReflectionGroup.Element): - @cached_in_parent_method def right_coset_representatives(self): r""" diff --git a/src/sage/combinat/root_system/root_lattice_realization_algebras.py b/src/sage/combinat/root_system/root_lattice_realization_algebras.py index 83c3bda44ff..cfe8cad08cd 100644 --- a/src/sage/combinat/root_system/root_lattice_realization_algebras.py +++ b/src/sage/combinat/root_system/root_lattice_realization_algebras.py @@ -36,7 +36,6 @@ class Algebras(AlgebrasCategory): """ class ParentMethods: - def _repr_(self): r""" EXAMPLES:: @@ -1145,7 +1144,6 @@ def twisted_demazure_lusztig_operators(self, q1, q2, convention='antidominant'): return HeckeAlgebraRepresentation(self.classical(), T_on_basis, self.cartan_type().classical().dual().affine().dual(), q1, q2, side='left') class ElementMethods: - def acted_upon(self, w): """ Implement the action of ``w`` on ``self``. diff --git a/src/sage/combinat/root_system/root_lattice_realizations.py b/src/sage/combinat/root_system/root_lattice_realizations.py index 9ad8999cb49..28135d33bdb 100644 --- a/src/sage/combinat/root_system/root_lattice_realizations.py +++ b/src/sage/combinat/root_system/root_lattice_realizations.py @@ -161,7 +161,6 @@ def super_categories(self): Algebras = LazyImport('sage.combinat.root_system.root_lattice_realization_algebras', 'Algebras') class ParentMethods: - def __init_extra__(self): r""" Register the embedding of the root lattice into ``self``. @@ -705,7 +704,7 @@ def positive_roots(self, index_set=None): return DisjointUnionEnumeratedSets([self.positive_real_roots(), self.positive_imaginary_roots()]) if not self.cartan_type().is_finite(): - raise NotImplementedError("Only implemented for finite and" " affine Cartan types") + raise NotImplementedError("Only implemented for finite and affine Cartan types") if index_set is None: index_set = tuple(self.cartan_type().index_set()) return RecursivelyEnumeratedSet([self.simple_root(i) for i in index_set], attrcall('pred', index_set=index_set), structure='graded', enumeration='breadth', category=EnumeratedSets().Finite()) @@ -733,7 +732,7 @@ def nonparabolic_positive_roots(self, index_set=None): alpha[2], alpha[2] + alpha[3], alpha[3]] """ if not self.cartan_type().is_finite(): - raise NotImplementedError("Only implemented for " "finite Cartan type") + raise NotImplementedError("Only implemented for finite Cartan type") if index_set is None: return [] return [x for x in self.positive_roots() if x not in self.positive_roots(index_set)] @@ -3268,7 +3267,6 @@ def to_ambient_space_morphism(self): ########################################################################## class ElementMethods: - @abstract_method def scalar(self, lambdacheck): """ diff --git a/src/sage/combinat/root_system/type_E.py b/src/sage/combinat/root_system/type_E.py index 27b83e535f3..e149db262e0 100644 --- a/src/sage/combinat/root_system/type_E.py +++ b/src/sage/combinat/root_system/type_E.py @@ -52,7 +52,7 @@ def __init__(self, root_system, baseRing): elif self.rank == 8: self.Base = [v * (self.root(0, 7) - self.root(1, 2, 3, 4, 5, 6)), self.root(0, 1), self.root(0, 1, p1=1), self.root(1, 2, p1=1), self.root(2, 3, p1=1), self.root(3, 4, p1=1), self.root(4, 5, p1=1), self.root(5, 6, p1=1)] else: - raise NotImplementedError("Type \'E\' root systems only come in flavors 6, 7, 8. Please make another choice") + raise NotImplementedError("Type 'E' root systems only come in flavors 6, 7, 8. Please make another choice") def dimension(self): """ diff --git a/src/sage/combinat/root_system/type_Q.py b/src/sage/combinat/root_system/type_Q.py index f368079d59b..07a6d6a441b 100644 --- a/src/sage/combinat/root_system/type_Q.py +++ b/src/sage/combinat/root_system/type_Q.py @@ -10,7 +10,6 @@ # http://www.gnu.org/licenses/ # ***************************************************************************** - from .cartan_type import CartanType_standard_finite from sage.combinat.root_system.root_system import RootSystem diff --git a/src/sage/combinat/root_system/type_affine.py b/src/sage/combinat/root_system/type_affine.py index 7ff28104e5e..84991632b4a 100644 --- a/src/sage/combinat/root_system/type_affine.py +++ b/src/sage/combinat/root_system/type_affine.py @@ -443,7 +443,6 @@ def _plot_projection(self, x): return vector(list(vector(classical._plot_projection(classical(x)))) + [x["deltacheck"]]) class Element(CombinatorialFreeModule.Element): - def inner_product(self, other): r""" Implement the canonical inner product of ``self`` with ``other``. diff --git a/src/sage/combinat/root_system/weight_lattice_realizations.py b/src/sage/combinat/root_system/weight_lattice_realizations.py index 4cd269884ad..e45b8b5ad42 100644 --- a/src/sage/combinat/root_system/weight_lattice_realizations.py +++ b/src/sage/combinat/root_system/weight_lattice_realizations.py @@ -130,7 +130,6 @@ def super_categories(self): return [RootLatticeRealizations(self.base_ring())] class ParentMethods: - @abstract_method def fundamental_weight(self, i): r""" @@ -983,7 +982,7 @@ def _symmetric_form_matrix(self): return self._inverse_cartan_matrix.transpose() * diag if not ct.is_affine(): - raise ValueError("only implemented for affine types when the" " Cartan matrix is singular") + raise ValueError("only implemented for affine types when the Cartan matrix is singular") r = ct.rank() a = ct.a() diff --git a/src/sage/combinat/root_system/weight_space.py b/src/sage/combinat/root_system/weight_space.py index 336140e4250..f9895a02733 100644 --- a/src/sage/combinat/root_system/weight_space.py +++ b/src/sage/combinat/root_system/weight_space.py @@ -178,7 +178,7 @@ def __init__(self, root_system, base_ring, extended): self._extended = extended if extended: if not root_system.cartan_type().is_affine(): - raise ValueError("extended weight lattices are only" " implemented for affine root systems") + raise ValueError("extended weight lattices are only implemented for affine root systems") basis_keys = tuple(basis_keys) + ("delta",) def sortkey(x): @@ -447,7 +447,6 @@ def basis_value(basis, i): class WeightSpaceElement(CombinatorialFreeModule.Element): - def scalar(self, lambdacheck): """ The canonical scalar product between the weight lattice and diff --git a/src/sage/combinat/root_system/weyl_group.py b/src/sage/combinat/root_system/weyl_group.py index bb0418bd4e1..2f76a149ce9 100644 --- a/src/sage/combinat/root_system/weyl_group.py +++ b/src/sage/combinat/root_system/weyl_group.py @@ -30,6 +30,7 @@ - Nicolas Thiéry (2008): initial version - Volker Braun (2013): LibGAP-based matrix groups """ + # **************************************************************************** # Copyright (C) 2008 Daniel Bump , # Mike Hansen @@ -217,7 +218,6 @@ def WeylGroup(x, prefix=None, implementation='matrix'): class WeylGroup_gens(UniqueRepresentation, FinitelyGeneratedMatrixGroup_gap): - @staticmethod def __classcall__(cls, domain, prefix=None): return super().__classcall__(cls, domain, prefix) diff --git a/src/sage/combinat/rsk.py b/src/sage/combinat/rsk.py index 3280216c484..f4ba2ce01bf 100644 --- a/src/sage/combinat/rsk.py +++ b/src/sage/combinat/rsk.py @@ -2459,7 +2459,7 @@ def _backward_format_output(self, lower_row, upper_row, output, q_is_standard): from sage.combinat.words.word import Word return Word(reversed(lower_row)) - raise TypeError("q must be standard to have a %s as " "valid output" % output) + raise TypeError("q must be standard to have a %s as valid output" % output) raise ValueError("invalid output option") diff --git a/src/sage/combinat/schubert_polynomial.py b/src/sage/combinat/schubert_polynomial.py index 9ef43c690bb..25dd4380bae 100644 --- a/src/sage/combinat/schubert_polynomial.py +++ b/src/sage/combinat/schubert_polynomial.py @@ -374,7 +374,6 @@ def multiply_variable(self, i): class SchubertPolynomialRing_xbasis(CombinatorialFreeModule): - Element = SchubertPolynomial_class def __init__(self, R): diff --git a/src/sage/combinat/set_partition_ordered.py b/src/sage/combinat/set_partition_ordered.py index 629fa2e888a..b1c9fed36df 100644 --- a/src/sage/combinat/set_partition_ordered.py +++ b/src/sage/combinat/set_partition_ordered.py @@ -1058,7 +1058,7 @@ def from_finite_word(self, w, check=True): except AttributeError: pass return self.element_class(self, W(w).to_ordered_set_partition()) - raise TypeError(f"`from_finite_word` expects an object of type list/tuple/str/Word " f"representing a finite word, received {w}") + raise TypeError(f"`from_finite_word` expects an object of type list/tuple/str/Word representing a finite word, received {w}") class OrderedSetPartitions_s(OrderedSetPartitions): diff --git a/src/sage/combinat/sf/character.py b/src/sage/combinat/sf/character.py index c1228b9ba87..0153bed25e7 100644 --- a/src/sage/combinat/sf/character.py +++ b/src/sage/combinat/sf/character.py @@ -32,7 +32,6 @@ class Character_generic(SFA_generic): - def _my_key(self, la): r""" A rank function for partitions. diff --git a/src/sage/combinat/sf/classical.py b/src/sage/combinat/sf/classical.py index c1000c40680..91dbdc70978 100644 --- a/src/sage/combinat/sf/classical.py +++ b/src/sage/combinat/sf/classical.py @@ -2,6 +2,7 @@ """ Classical symmetric functions """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen # 2012 Mike Zabrocki @@ -181,7 +182,6 @@ def _element_constructor_(self, x): # Classical Symmetric Functions, different basis # ################################################## if isinstance(x, SymmetricFunctionAlgebra_classical.Element): - P = x.parent() m = x.monomial_coefficients() diff --git a/src/sage/combinat/sf/dual.py b/src/sage/combinat/sf/dual.py index 60a76a59e34..41ae278adf3 100644 --- a/src/sage/combinat/sf/dual.py +++ b/src/sage/combinat/sf/dual.py @@ -2,6 +2,7 @@ """ Generic dual bases symmetric functions """ + # ***************************************************************************** # Copyright (C) 2007 Mike Hansen # 2012 Mike Zabrocki diff --git a/src/sage/combinat/sf/elementary.py b/src/sage/combinat/sf/elementary.py index a96fd296578..6ada0bf1cf6 100644 --- a/src/sage/combinat/sf/elementary.py +++ b/src/sage/combinat/sf/elementary.py @@ -2,6 +2,7 @@ """ Elementary symmetric functions """ + # *************************************************************************** # Copyright (C) 2007 Mike Hansen # 2012 Mike Zabrocki diff --git a/src/sage/combinat/sf/hall_littlewood.py b/src/sage/combinat/sf/hall_littlewood.py index db6364119b4..00f349be20d 100644 --- a/src/sage/combinat/sf/hall_littlewood.py +++ b/src/sage/combinat/sf/hall_littlewood.py @@ -899,7 +899,6 @@ def _p_to_q_normalization(self, m): class HallLittlewood_qp(HallLittlewood_generic): - class Element(HallLittlewood_generic.Element): pass diff --git a/src/sage/combinat/sf/hecke.py b/src/sage/combinat/sf/hecke.py index 749eb5f23b4..c7711fb97fd 100644 --- a/src/sage/combinat/sf/hecke.py +++ b/src/sage/combinat/sf/hecke.py @@ -225,7 +225,7 @@ def _p_to_qbar_on_generator(self, n): q = self.q if q**n == self.base_ring().one(): raise ValueError("the parameter q=%s must not be a %s root of unity" % (q, n)) - out = n * self([n]) - sum((q**i - 1) * self._p_to_qbar_on_generator(i) * self([n - i]) for i in range(1, n) if q ** i != 1) + out = n * self([n]) - sum((q**i - 1) * self._p_to_qbar_on_generator(i) * self([n - i]) for i in range(1, n) if q**i != 1) return out * (q - 1) / (q**n - 1) def _p_to_qbar_on_basis(self, mu): diff --git a/src/sage/combinat/sf/jack.py b/src/sage/combinat/sf/jack.py index 0ca797acdf8..9401783dc3a 100644 --- a/src/sage/combinat/sf/jack.py +++ b/src/sage/combinat/sf/jack.py @@ -831,7 +831,6 @@ def part_scalar_jack(part1, part2, t): class JackPolynomials_p(JackPolynomials_generic): - def __init__(self, jack): r""" The `P` basis is uni-triangularly related to the monomial basis and @@ -1035,7 +1034,6 @@ def scalar_jack(self, x, t=None): class JackPolynomials_j(JackPolynomials_generic): - def __init__(self, jack): r""" The `J` basis is a defined as a normalized form of the `P` basis. @@ -1070,7 +1068,6 @@ class Element(JackPolynomials_generic.Element): # Q basis class JackPolynomials_q(JackPolynomials_generic): - def __init__(self, jack): r""" The `Q` basis is defined as a normalized form of the `P` basis. diff --git a/src/sage/combinat/sf/k_dual.py b/src/sage/combinat/sf/k_dual.py index aea86969799..c5f35caeab4 100644 --- a/src/sage/combinat/sf/k_dual.py +++ b/src/sage/combinat/sf/k_dual.py @@ -50,7 +50,6 @@ class KBoundedQuotient(UniqueRepresentation, Parent): - def __init__(self, Sym, k, t='t'): r""" Initialization of the ring of Symmetric functions modulo the ideal of monomial @@ -496,7 +495,6 @@ def super_categories(self): return [Realizations(self.base()), category.Quotients()] class ParentMethods: - def retract(self, la): r""" Give the retract map from the symmetric functions to the quotient ring of diff --git a/src/sage/combinat/sf/llt.py b/src/sage/combinat/sf/llt.py index 638cfab2868..53daabfd204 100644 --- a/src/sage/combinat/sf/llt.py +++ b/src/sage/combinat/sf/llt.py @@ -2,6 +2,7 @@ r""" LLT symmetric functions """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen # 2012 Mike Zabrocki @@ -403,7 +404,6 @@ def hspin(self): class LLT_generic(sfa.SymmetricFunctionAlgebra_generic): - def __init__(self, llt, prefix): r""" A class of methods which are common to both the hspin and hcospin @@ -605,7 +605,6 @@ class Element(sfa.SymmetricFunctionAlgebra_generic.Element): # the H-spin basis class LLT_spin(LLT_generic): - def __init__(self, llt): r""" A class of methods for the h-spin LLT basis of the symmetric functions. diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 32cf80c31e5..e2d9b103c88 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -60,7 +60,6 @@ class Macdonald(UniqueRepresentation): - def __repr__(self): r""" The family of Macdonald symmetric function bases. @@ -693,7 +692,6 @@ def Bmu_skew(outer, inner): class MacdonaldPolynomials_generic(sfa.SymmetricFunctionAlgebra_generic): - def __init__(self, macdonald): r""" A class for methods for one of the Macdonald bases of the symmetric functions. @@ -905,7 +903,6 @@ def macdonald_family(self): return self._macdonald class Element(sfa.SymmetricFunctionAlgebra_generic.Element): - def nabla(self, q=None, t=None, power=1): r""" Return the value of the nabla operator applied to ``self``. @@ -1754,7 +1751,6 @@ def _s_cache(self, n): self._invert_morphism(n, QQqt, self._self_to_s_cache, self._s_to_self_cache, to_other_function=self._to_s) class Element(MacdonaldPolynomials_generic.Element): - def _creation_by_determinant_helper(self, k, part): r""" Formula from [LLM1998]_ Corollary 4.3 p. 970. diff --git a/src/sage/combinat/sf/monomial.py b/src/sage/combinat/sf/monomial.py index 1229b4b7b4e..5e872a0e31b 100644 --- a/src/sage/combinat/sf/monomial.py +++ b/src/sage/combinat/sf/monomial.py @@ -119,7 +119,6 @@ def product(self, left, right): z_elt = {} for left_m, left_c in left._monomial_coefficients.items(): for right_m, right_c in right._monomial_coefficients.items(): - # Hack due to symmetrica crashing when both of the # partitions are the empty partition if not left_m and not right_m: diff --git a/src/sage/combinat/sf/multiplicative.py b/src/sage/combinat/sf/multiplicative.py index d49b511c2c4..1d4e205017c 100644 --- a/src/sage/combinat/sf/multiplicative.py +++ b/src/sage/combinat/sf/multiplicative.py @@ -6,6 +6,7 @@ a partition `\lambda = (\lambda_1,\lambda_2,\ldots)` we have `h_\lambda = h_{\lambda_1} h_{\lambda_2} \cdots`. """ + # ***************************************************************************** # Copyright (C) 2007 Mike Hansen , # diff --git a/src/sage/combinat/sf/new_kschur.py b/src/sage/combinat/sf/new_kschur.py index f5150b6a6f3..7bd200bad92 100644 --- a/src/sage/combinat/sf/new_kschur.py +++ b/src/sage/combinat/sf/new_kschur.py @@ -2,6 +2,7 @@ """ `k`-Schur functions """ + # **************************************************************************** # Copyright (C) 2011 Jason Bandlow , # 2012 Anne Schilling @@ -312,7 +313,6 @@ def super_categories(self): return [Realizations(self.base()), category.Subobjects()] class ParentMethods: - def _element_constructor_(self, x): r""" Needed to rewrite the element constructor because of a bug in free_module.py. diff --git a/src/sage/combinat/sf/ns_macdonald.py b/src/sage/combinat/sf/ns_macdonald.py index d2c980377c4..f9457356595 100644 --- a/src/sage/combinat/sf/ns_macdonald.py +++ b/src/sage/combinat/sf/ns_macdonald.py @@ -2,6 +2,7 @@ """ Non-symmetric Macdonald polynomials """ + import copy from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets diff --git a/src/sage/combinat/sf/orthotriang.py b/src/sage/combinat/sf/orthotriang.py index b453cad9c7f..4e579a3830e 100644 --- a/src/sage/combinat/sf/orthotriang.py +++ b/src/sage/combinat/sf/orthotriang.py @@ -47,7 +47,6 @@ class SymmetricFunctionAlgebra_orthotriang to obtain the Schur class SymmetricFunctionAlgebra_orthotriang(sfa.SymmetricFunctionAlgebra_generic): - class Element(sfa.SymmetricFunctionAlgebra_generic.Element): pass diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index 90fd30b0cfd..82be859499c 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -2,6 +2,7 @@ """ Power sum symmetric functions """ + # *************************************************************************** # Copyright (C) 2007 Mike Hansen # 2012 Mike Zabrocki diff --git a/src/sage/combinat/sf/schur.py b/src/sage/combinat/sf/schur.py index fd09fd0e73c..5b3db36673e 100644 --- a/src/sage/combinat/sf/schur.py +++ b/src/sage/combinat/sf/schur.py @@ -702,9 +702,9 @@ def get_variable(ring, name): if q == 1: if n == infinity: raise ValueError("the stable principal specialization at q=1 is not defined") - f = lambda partition: (prod(n + j - i for (i, j) in partition.cells()) // prod(h for h in partition.hooks())) + f = lambda partition: prod(n + j - i for (i, j) in partition.cells()) // prod(h for h in partition.hooks()) elif n == infinity: - f = lambda partition: (q ** sum(i * part for i, part in enumerate(partition)) / prod(1 - q**h for h in partition.hooks())) + f = lambda partition: q ** sum(i * part for i, part in enumerate(partition)) / prod(1 - q**h for h in partition.hooks()) else: from sage.rings.integer_ring import ZZ @@ -853,7 +853,7 @@ def f(partition): elif t is None: t = get_variable(q.parent(), 't') - f = lambda partition: (t ** partition.size() * q ** sum(i * part for i, part in enumerate(partition)) / prod(sum(q**i for i in range(h)) for h in partition.hooks())) + f = lambda partition: t ** partition.size() * q ** sum(i * part for i, part in enumerate(partition)) / prod(sum(q**i for i in range(h)) for h in partition.hooks()) return self.parent()._apply_module_morphism(self, f, t.parent()) diff --git a/src/sage/combinat/sf/sf.py b/src/sage/combinat/sf/sf.py index 095fd9d229f..181f63ed817 100644 --- a/src/sage/combinat/sf/sf.py +++ b/src/sage/combinat/sf/sf.py @@ -2,6 +2,7 @@ """ Symmetric functions, with their multiple realizations """ + # *************************************************************************** # Copyright (C) 2007 Mike Hansen # 2009-2012 Jason Bandlow diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 4cea95b7ea0..40d1a239b06 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -197,6 +197,7 @@ - Mike Zabrocki, Anne Schilling (2012) - Darij Grinberg (2013) Sym over rings that are not characteristic 0 """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen # 2012 Anne Schilling @@ -345,7 +346,6 @@ def super_categories(self) -> list: return categories class ParentMethods: - def is_integral_domain(self, proof=True) -> bool: """ Return whether ``self`` is an integral domain. (It is if @@ -3542,7 +3542,7 @@ def plethysm(self, x, include=None, exclude=None): if phi is not None: x = phi(x) elif not tensorflag: - raise TypeError("only know how to compute plethysms " "between symmetric functions or tensors " "of symmetric functions") + raise TypeError("only know how to compute plethysms between symmetric functions or tensors of symmetric functions") p = parent.realization_of().power() diff --git a/src/sage/combinat/sf/witt.py b/src/sage/combinat/sf/witt.py index c2eee9d5b52..4fc00837cb6 100644 --- a/src/sage/combinat/sf/witt.py +++ b/src/sage/combinat/sf/witt.py @@ -2,6 +2,7 @@ """ Witt symmetric functions """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen # 2012 Mike Zabrocki diff --git a/src/sage/combinat/shifted_primed_tableau.py b/src/sage/combinat/shifted_primed_tableau.py index 38030e913b5..1339ae33965 100644 --- a/src/sage/combinat/shifted_primed_tableau.py +++ b/src/sage/combinat/shifted_primed_tableau.py @@ -789,7 +789,7 @@ def to_chain(self): skew shifted tableaux without repeated entries """ if any(e not in [0, 1] for e in self.weight()): - raise ValueError("can compute a chain of partitions only for skew" " shifted tableaux without repeated entries") + raise ValueError("can compute a chain of partitions only for skew shifted tableaux without repeated entries") entries = sorted(e for row in self for e in row if e is not None) if self._skew is None: mu = Partition([]) diff --git a/src/sage/combinat/sine_gordon.py b/src/sage/combinat/sine_gordon.py index 6cf378fc822..c75476289d1 100644 --- a/src/sage/combinat/sine_gordon.py +++ b/src/sage/combinat/sine_gordon.py @@ -129,12 +129,12 @@ def __init__(self, X, na): raise ValueError("the type must be either 'A' or 'D'") self._type = X if na[0] <= 2: - raise ValueError("the first integer in the defining sequence " "must be greater than 2") + raise ValueError("the first integer in the defining sequence must be greater than 2") if any(x not in NN for x in na): - raise ValueError("the defining sequence must contain only " "positive integers") + raise ValueError("the defining sequence must contain only positive integers") self._na = tuple(na) if self._na == (3,) and self._type == 'A': - raise ValueError("the integer sequence (3,) in type 'A'" " is not allowed as input") + raise ValueError("the integer sequence (3,) in type 'A' is not allowed as input") self._F = len(self._na) def _repr_(self): diff --git a/src/sage/combinat/skew_tableau.py b/src/sage/combinat/skew_tableau.py index 95fd158f359..40809c53f30 100644 --- a/src/sage/combinat/skew_tableau.py +++ b/src/sage/combinat/skew_tableau.py @@ -1011,7 +1011,7 @@ def backward_slide(self, corner=None): outer_outisde_corners = self.outer_shape().outside_corners() if corner is not None: if tuple(corner) not in outer_outisde_corners: - raise ValueError("corner must be an outside corner" " of the outer shape") + raise ValueError("corner must be an outside corner of the outer shape") else: if not outer_outisde_corners: return self diff --git a/src/sage/combinat/subword_complex.py b/src/sage/combinat/subword_complex.py index d59e2978fa4..1bce7d24ff6 100644 --- a/src/sage/combinat/subword_complex.py +++ b/src/sage/combinat/subword_complex.py @@ -99,6 +99,7 @@ - Christian Stump: initial version - Vincent Pilaud: greedy flip algorithm, minor improvements, documentation """ + # **************************************************************************** # Copyright (C) 2015 Christian Stump # @@ -1100,7 +1101,7 @@ def __init__(self, Q, w, algorithm='inductive'): elif algorithm == "greedy": Fs, Rs = _greedy_flip_algorithm(Q, w) else: - raise ValueError("the optional argument algorithm can be " "either inductive or greedy") + raise ValueError("the optional argument algorithm can be either inductive or greedy") if not Fs: raise ValueError("the word %s does not contain a reduced expression for %s" % (Q, w.reduced_word())) cat = SimplicialComplexes().Finite().Enumerated() @@ -1939,7 +1940,7 @@ def _greedy_facet(Q, w, side='negative', n=None, pos=0, l=None, elems=[]): Q = Q[::-1] w = w.inverse() else: - raise ValueError("the optional argument side is not positive " "or negative") + raise ValueError("the optional argument side is not positive or negative") if n is None: n = len(Q) diff --git a/src/sage/combinat/super_tableau.py b/src/sage/combinat/super_tableau.py index ba426c14537..17c69281823 100644 --- a/src/sage/combinat/super_tableau.py +++ b/src/sage/combinat/super_tableau.py @@ -187,23 +187,23 @@ def check(self): super().check() for row in self: if not all(isinstance(c, PrimedEntry) and c > 0 for c in row): - raise ValueError("the entries of a semistandard super tableau" " must be nonnegative primed integers") + raise ValueError("the entries of a semistandard super tableau must be nonnegative primed integers") if any(row[c] > row[c + 1] for c in range(len(row) - 1)): - raise ValueError("the entries in each row of a semistandard" " super tableau must be weakly increasing") + raise ValueError("the entries in each row of a semistandard super tableau must be weakly increasing") if self: for row, next in zip(self, self[1:]): # Check that letters are weakly increasing down columns if any(row[c] > next[c] for c in range(len(next))): - raise ValueError("the entries of each column of a " "semistandard super tableau must be " "weakly increasing") + raise ValueError("the entries of each column of a semistandard super tableau must be weakly increasing") # Check that unprimed letters are column strict if not all(row[c] < next[c] for c in range(len(next)) if (row[c].is_unprimed() or next[c].is_unprimed())): - raise ValueError("the unprimed entries of each column" " must be strictly increasing") + raise ValueError("the unprimed entries of each column must be strictly increasing") # Check that primed letters are row strict for row in self: if not all(row[c] < row[c + 1] for c in range(len(row) - 1) if (row[c].is_primed() or row[c + 1].is_primed())): - raise ValueError("the primed entries in each row must be" " strictly increasing") + raise ValueError("the primed entries in each row must be strictly increasing") class StandardSuperTableau(SemistandardSuperTableau): @@ -299,7 +299,7 @@ def check(self): a = a.increase_half() if sorted(flattened_list) != primed_list: - raise ValueError("the entries in a standard tableau must be in" " bijection with 1',1,2',2,...,n") + raise ValueError("the entries in a standard tableau must be in bijection with 1',1,2',2,...,n") def is_standard(self) -> bool: """ @@ -522,10 +522,10 @@ def __classcall_private__(cls, n=None): return StandardSuperTableaux_shape(_Partitions(n)) if n in SkewPartitions(): - raise NotImplementedError("standard super tableau for skew " "partitions is not implemented yet") + raise NotImplementedError("standard super tableau for skew partitions is not implemented yet") if not isinstance(n, (int, Integer)) or n < 0: - raise ValueError("the argument must be a nonnegative integer" " or a partition") + raise ValueError("the argument must be a nonnegative integer or a partition") return StandardSuperTableaux_size(n) diff --git a/src/sage/combinat/superpartition.py b/src/sage/combinat/superpartition.py index 08647dca033..dbf66e6c919 100644 --- a/src/sage/combinat/superpartition.py +++ b/src/sage/combinat/superpartition.py @@ -835,7 +835,8 @@ def __init__(self, is_infinite=False): Element = SuperPartition class options(GlobalOptions): - """ + ( + """ Set the global options for elements of the SuperPartition class. The defaults are for Super Partitions to be displayed in a list @@ -858,13 +859,14 @@ class options(GlobalOptions): [-1, 0, 2, 2, 1] sage: SuperPartitions.options._reset() """, + ) NAME = 'SuperPartition' module = 'sage.combinat.superpartition' display = dict( default='default', - description="Specifies how the super partitions should " "be printed", - values=dict(list="the super partitions are displayed in " "a list of two lists", pair="the super partition is displayed as a " "list of integers", default="the super partition is displayed in " "a form [fermionic part; bosonic part]"), + description="Specifies how the super partitions should be printed", + values=dict(list="the super partitions are displayed in a list of two lists", pair="the super partition is displayed as a list of integers", default="the super partition is displayed in a form [fermionic part; bosonic part]"), case_sensitive=False, ) diff --git a/src/sage/combinat/symmetric_group_algebra.py b/src/sage/combinat/symmetric_group_algebra.py index d273d21ccc3..9f11c7a248c 100644 --- a/src/sage/combinat/symmetric_group_algebra.py +++ b/src/sage/combinat/symmetric_group_algebra.py @@ -2,6 +2,7 @@ r""" Symmetric group algebra """ + # **************************************************************************** # Copyright (C) 2007 Mike Hansen , # @@ -243,7 +244,6 @@ def SymmetricGroupAlgebra(R, W, category=None): class SymmetricGroupAlgebra_n(GroupAlgebra_class): - def __init__(self, R, W, category): """ TESTS:: @@ -438,7 +438,7 @@ def _sibling(self, n): try: W = self.basis().keys().__class__(n) except (AttributeError, TypeError, ValueError): - raise NotImplementedError("Constructing the sibling algebra of a different order " "only implemented for PermutationGroup and SymmetricGroup") + raise NotImplementedError("Constructing the sibling algebra of a different order only implemented for PermutationGroup and SymmetricGroup") return SymmetricGroupAlgebra(self.base_ring(), W) # _repr_ customization: output the basis element indexed by [1,2,3] as [1,2,3] @@ -3563,7 +3563,6 @@ def _element_constructor_(self, x): class HeckeAlgebraSymmetricGroup_t(HeckeAlgebraSymmetricGroup_generic): - def __init__(self, R, n, q=None): """ TESTS:: diff --git a/src/sage/combinat/t_sequences.py b/src/sage/combinat/t_sequences.py index 7e8ebac5e1a..cb14efc9c6c 100644 --- a/src/sage/combinat/t_sequences.py +++ b/src/sage/combinat/t_sequences.py @@ -867,4 +867,4 @@ def base_sequences_smallcases(n, p, existence=False, check=True): return True return turyn_sequences_smallcases(n + p) - raise ValueError(f'Base sequences of order {n+p}, {n+p}, {n}, {n} not yet implemented.') + raise ValueError(f'Base sequences of order {n + p}, {n + p}, {n}, {n} not yet implemented.') diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index 8a2e4101f8e..809b50ed015 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -4660,7 +4660,7 @@ def check(self): # the entries of t are positive integers that increase along rows. flatx = sorted(c for row in self for c in row) if flatx != list(range(1, len(flatx) + 1)) or any(row[i] >= row[i + 1] for row in self for i in range(len(row) - 1)): - raise ValueError("the entries in a row standard tableau must increase" " along rows and contain the numbers 1,2,...,n") + raise ValueError("the entries in a row standard tableau must increase along rows and contain the numbers 1,2,...,n") class StandardTableau(SemistandardTableau): @@ -5222,14 +5222,14 @@ def check(self): for row in self: if any(c not in PI for c in row): - raise ValueError("the entries of an increasing tableau" " must be nonnegative integers") + raise ValueError("the entries of an increasing tableau must be nonnegative integers") if any(row[c] >= row[c + 1] for c in range(len(row) - 1)): - raise ValueError("the entries in each row of an increasing" " tableau must be strictly increasing") + raise ValueError("the entries in each row of an increasing tableau must be strictly increasing") # and strictly increasing down columns for row, next in zip(self, self[1:]): if not all(row[c] < next[c] for c in range(len(next))): - raise ValueError("the entries of each column of an increasing" " tableau must be strictly increasing") + raise ValueError("the entries of each column of an increasing tableau must be strictly increasing") def descent_set(self): r""" @@ -5709,7 +5709,6 @@ def __contains__(self, x): class Tableaux_all(Tableaux): - def __init__(self): r""" Initialize the class of all tableaux. @@ -8553,7 +8552,7 @@ def __classcall_private__(cls, *args, **kwargs): if shape in _Partitions: shape = Partition(shape) elif shape in SkewPartitions(): - raise NotImplementedError("skew increasing tableaux are not" " currently implemented") + raise NotImplementedError("skew increasing tableaux are not currently implemented") # from sage.combinat.skew_tableau import IncreasingSkewTableaux # return IncreasingSkewTableaux(shape, wt) else: diff --git a/src/sage/combinat/tableau_tuple.py b/src/sage/combinat/tableau_tuple.py index c5e17b10b57..a341f3589b9 100644 --- a/src/sage/combinat/tableau_tuple.py +++ b/src/sage/combinat/tableau_tuple.py @@ -1182,7 +1182,7 @@ def add_entry(self, cell, m): tab[k][r].append(m) else: - raise IndexError(f'{(k,r,c)} is not an addable cell of the tableau') + raise IndexError(f'{(k, r, c)} is not an addable cell of the tableau') # finally, try and return a tableau belonging to the same category try: diff --git a/src/sage/combinat/tamari_blossoming_tree.py b/src/sage/combinat/tamari_blossoming_tree.py index 19c799f9559..e44f2d36717 100644 --- a/src/sage/combinat/tamari_blossoming_tree.py +++ b/src/sage/combinat/tamari_blossoming_tree.py @@ -885,8 +885,8 @@ def _latex_(self) -> str: tikz.append('\\begin{tikzpicture}\n') # zorder=0 # arrows - tikz.append(f'\\foreach \\x in {{0, 2, ..., {2 * n}}} ' '\\draw[-latex, thick] (\\x, 0) -- ++(-0.6, 0);\n') - tikz.append(f'\\foreach \\x in {{0, 2, ..., {2 * n}}} ' '\\draw[-latex, thick] (\\x, 0) -- ++(0.6, 0);\n') + tikz.append(f'\\foreach \\x in {{0, 2, ..., {2 * n}}} \\draw[-latex, thick] (\\x, 0) -- ++(-0.6, 0);\n') + tikz.append(f'\\foreach \\x in {{0, 2, ..., {2 * n}}} \\draw[-latex, thick] (\\x, 0) -- ++(0.6, 0);\n') # zorder=1 # tree edges norder, eorder = self._node_order, self._edge_order @@ -894,14 +894,14 @@ def _latex_(self) -> str: nidx1, nidx2 = eorder[i] k, m = sorted((norder.index(nidx1), norder.index(nidx2))) # upper arc - tikz.append(f'\\draw[blue, very thick] ({k * 2}, 0) arc ' f'(180:0:{i - k + 0.5});\n') + tikz.append(f'\\draw[blue, very thick] ({k * 2}, 0) arc (180:0:{i - k + 0.5});\n') # lower arc - tikz.append(f'\\draw[red, very thick] ({m * 2}, 0) arc ' f'(0:-180:{m - i - 0.5});\n') + tikz.append(f'\\draw[red, very thick] ({m * 2}, 0) arc (0:-180:{m - i - 0.5});\n') # zorder=2 # trees nodes, which are circles - tikz.append(f'\\foreach \\x in {{0, 2, ..., {2 * n}}} \\filldraw[black]' ' (\\x, 0) circle (0.15);\n') + tikz.append(f'\\foreach \\x in {{0, 2, ..., {2 * n}}} \\filldraw[black] (\\x, 0) circle (0.15);\n') # square nodes for edges, which are squares - tikz.append(f'\\foreach \\x in {{1, 3, ..., {2 * n - 1}}}' '\\node[draw=black, fill=white, ' 'very thick, minimum size=0.2] ' '(square) at (\\x, 0) {};\n') + tikz.append(f'\\foreach \\x in {{1, 3, ..., {2 * n - 1}}}\\node[draw=black, fill=white, very thick, minimum size=0.2] (square) at (\\x, 0) {{}};\n') # ending tikz.append('\\end{tikzpicture}\n') return ''.join(tikz) @@ -2381,7 +2381,7 @@ def _repr_(self) -> str: sage: ModernBlossomingTreeFactory(16) Random generator of modern blossoming trees of size 16 """ - return f'Random generator of modern blossoming trees' f' of size {self._size}' + return f'Random generator of modern blossoming trees of size {self._size}' def random_element(self) -> TamariBlossomingTree: r""" diff --git a/src/sage/combinat/tamari_lattices.py b/src/sage/combinat/tamari_lattices.py index 458161d1384..1f3fb6b88b4 100644 --- a/src/sage/combinat/tamari_lattices.py +++ b/src/sage/combinat/tamari_lattices.py @@ -32,6 +32,7 @@ For more detailed information see :meth:`TamariLattice`, :meth:`GeneralizedTamariLattice`. """ + # **************************************************************************** # Copyright (C) 2012-2018 Frédéric Chapoton # diff --git a/src/sage/combinat/tiling.py b/src/sage/combinat/tiling.py index 247fbc4ca34..4652562aa28 100644 --- a/src/sage/combinat/tiling.py +++ b/src/sage/combinat/tiling.py @@ -527,7 +527,7 @@ def __init__(self, coords, color='gray', dimension=None): if coords: self._dimension = ZZ(len(coords[0])) else: - raise ValueError("dimension(={}) must be provided for" " the empty polyomino".format(dimension)) + raise ValueError("dimension(={}) must be provided for the empty polyomino".format(dimension)) else: self._dimension = dimension self._free_module = FreeModule(ZZ, self._dimension) @@ -878,7 +878,7 @@ def __rmul__(self, m): ValueError: Dimension of input matrix must match the dimension of the polyomino """ if not m.nrows() == m.ncols() == self._dimension: - raise ValueError("Dimension of input matrix must match the " "dimension of the polyomino") + raise ValueError("Dimension of input matrix must match the dimension of the polyomino") return Polyomino([m * p for p in self], color=self._color) def canonical(self): @@ -1050,7 +1050,7 @@ def translated_copies(self, box): ranges = [range(a) for a in box] box = Polyomino(itertools.product(*ranges)) if not box._dimension == self._dimension: - raise ValueError("Dimension of input box must match the " "dimension of the polyomino") + raise ValueError("Dimension of input box must match the dimension of the polyomino") minxyz, maxxyz = self.bounding_box() minxyz, maxxyz = vector(minxyz), vector(maxxyz) size = maxxyz - minxyz @@ -1101,7 +1101,7 @@ def translated_copies_intersection(self, box): ranges = [range(a) for a in box] box = Polyomino(itertools.product(*ranges)) if not box._dimension == self._dimension: - raise ValueError("Dimension of input box must match the " "dimension of the polyomino") + raise ValueError("Dimension of input box must match the dimension of the polyomino") minxyz, maxxyz = self.bounding_box() minxyz, maxxyz = vector(minxyz), vector(maxxyz) size = maxxyz - minxyz @@ -1170,10 +1170,10 @@ def isometric_copies(self, box, orientation_preserving=True, mod_box_isometries= ranges = [range(a) for a in box] box = Polyomino(itertools.product(*ranges)) if not box._dimension == self._dimension: - raise ValueError("Dimension of input box must match the " "dimension of the polyomino") + raise ValueError("Dimension of input box must match the dimension of the polyomino") box_min_coords, box_max_coords = box.bounding_box() if mod_box_isometries and len({b - a for a, b in zip(box_min_coords, box_max_coords)}) < box._dimension: - raise NotImplementedError("The code below assumes that the" " sizes of the box (={}) are all distinct when" " argument `mod_box_isometries` is True.".format(box)) + raise NotImplementedError("The code below assumes that the sizes of the box (={}) are all distinct when argument `mod_box_isometries` is True.".format(box)) all_distinct_cano = self.canonical_isometric_copies(orientation_preserving, mod_box_isometries) for cano in all_distinct_cano: yield from cano.translated_copies(box=box) @@ -1308,7 +1308,7 @@ def boundary(self): ((4.5, 5.5), (5.5, 5.5)), ((5.5, 4.5), (5.5, 5.5))] """ if self._dimension != 2: - raise NotImplementedError("The method boundary is currently " "implemented " "only for dimension 2") + raise NotImplementedError("The method boundary is currently implemented only for dimension 2") from collections import defaultdict horizontal = defaultdict(int) @@ -1457,7 +1457,7 @@ def self_surrounding(self, radius, remove_incomplete_copies=True, ncpus=None): # Solve solution = d.one_solution(ncpus=ncpus) if solution is None: - raise ValueError('No solution was found with radius={}, ' 'this tile can not be surrounded by itself'.format(radius)) + raise ValueError('No solution was found with radius={}, this tile can not be surrounded by itself'.format(radius)) # Recover the polyominoes assert forced_row_number in solution @@ -1574,7 +1574,7 @@ def __init__(self, pieces, box, rotation=True, reflection=False, reusable=False, self._rotation = rotation self._reflection = reflection if not self._rotation and self._reflection: - raise NotImplementedError("When reflection is allowed and " "rotation is not allowed") + raise NotImplementedError("When reflection is allowed and rotation is not allowed") self._reusable = reusable self._outside = outside @@ -1803,7 +1803,7 @@ def rows_for_piece(self, i, mod_box_isometries=False): it = p.isometric_copies(self._box, orientation_preserving=orientation_preserving, mod_box_isometries=mod_box_isometries) else: if self._reflection: - raise NotImplementedError("Reflection allowed, Rotation not " "allowed is not implemented") + raise NotImplementedError("Reflection allowed, Rotation not allowed is not implemented") else: if self._outside: it = p.translated_copies_intersection(self._box) @@ -2392,5 +2392,5 @@ def animate(self, partial=None, stop=None, size=0.75, axes=False): ymax = ymax + 0.5 return Animation(L, xmin=xmin - 0.5, ymin=ymin - 0.5, xmax=xmax, ymax=ymax, aspect_ratio=1, axes=axes) if dimension == 3: - raise NotImplementedError("3d Animation must be implemented " "in Jmol first") - raise NotImplementedError("Dimension must be 2 or 3 in order " "to make an animation") + raise NotImplementedError("3d Animation must be implemented in Jmol first") + raise NotImplementedError("Dimension must be 2 or 3 in order to make an animation") diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index 578afb4c975..2bb8cd88f5a 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -510,7 +510,7 @@ def fcn(n): if length in ZZ and length >= 0: return self._parent(fcn, length=length) - raise ValueError("Power of the word is not defined on the exponent {}: " "the length of the word ({}) times the exponent ({}) must " "be a positive integer".format(exp, self.length(), exp)) + raise ValueError("Power of the word is not defined on the exponent {}: the length of the word ({}) times the exponent ({}) must be a positive integer".format(exp, self.length(), exp)) def length(self): r""" @@ -2644,7 +2644,6 @@ def palindromic_lacunas_study(self, f=None): # For all the non-empty prefixes of self, for i in range(self.length()): - # Compute its longest `f`-palindromic suffix using the preceding lps (pal) pal = self[: i + 1].lps(l=pal.length(), f=f) @@ -2813,7 +2812,7 @@ def length_maximal_palindrome(self, j, m=None, f=None): # Initialize the next (left) position to check i = (jj - m - 1) / 2 if not i.is_integer(): - raise ValueError(f"(2*j-m-1)/2(={i}) must be an integer, i.e., " f"2*j(={jj}) and m(={m}) can't " "have the same parity") + raise ValueError(f"(2*j-m-1)/2(={i}) must be an integer, i.e., 2*j(={jj}) and m(={m}) can't have the same parity") i = Integer(i) # Compute @@ -5477,7 +5476,7 @@ def abelian_vectors(self, n): alphabet = self.parent().alphabet() size = alphabet.cardinality() if size == float('inf'): - raise TypeError("The alphabet of the parent is infinite; define" " the word with a parent on a finite alphabet") + raise TypeError("The alphabet of the parent is infinite; define the word with a parent on a finite alphabet") S = set() if n > self.length(): return S @@ -5904,7 +5903,7 @@ def abelian_vector(self): """ alphabet = self.parent().alphabet() if alphabet.cardinality() is Infinity: - raise TypeError("The alphabet of the parent is infinite; define " "the word with a parent on a finite alphabet " "or use evaluation_dict() instead") + raise TypeError("The alphabet of the parent is infinite; define the word with a parent on a finite alphabet or use evaluation_dict() instead") ev_dict = self.evaluation_dict() return [ev_dict.get(a, 0) for a in alphabet] @@ -6416,7 +6415,7 @@ def standard_factorization(self): """ selflen = self.length() if selflen < 2: - raise ValueError("standard factorization not defined on" " words of length less than 2") + raise ValueError("standard factorization not defined on words of length less than 2") for l in range(1, selflen): suff = self[l:] if suff.is_lyndon(): diff --git a/src/sage/combinat/words/morphism.py b/src/sage/combinat/words/morphism.py index ab020d4c8f8..7a6885ad296 100644 --- a/src/sage/combinat/words/morphism.py +++ b/src/sage/combinat/words/morphism.py @@ -880,11 +880,11 @@ def _latex_(self): A = self.domain().alphabet() latex_layout = self.latex_layout() if latex_layout == 'oneliner': - lines = (fr"{a} \mapsto {self.image(a)}" for a in A) + lines = (rf"{a} \mapsto {self.image(a)}" for a in A) return LatexExpr(r','.join(lines)) if latex_layout == 'array': s = r"\begin{array}{l}" + '\n' - lines = (fr"{a} \mapsto {self.image(a)}" for a in A) + lines = (rf"{a} \mapsto {self.image(a)}" for a in A) s += '\\\\\n'.join(lines) s += '\n' + r"\end{array}" return LatexExpr(s) @@ -2440,7 +2440,6 @@ def is_in_classP(self, f=None): # Find a common palindrome prefix for i in range(lcp.length() + 1): if lcp[:i].is_palindrome(f=f): - # If all the suffixes are palindromes, for image in images: if not image[i:].is_palindrome(f=f): @@ -2533,7 +2532,7 @@ def dual_map(self, k=1): return E1Star(self) - raise NotImplementedError("the dual map E_k^* is implemented only " "for k = 1 (not %s)" % k) + raise NotImplementedError("the dual map E_k^* is implemented only for k = 1 (not %s)" % k) @cached_method def rauzy_fractal_projection(self, eig=None, prec=53): @@ -2731,7 +2730,6 @@ def rauzy_fractal_points(self, n=None, exchange=False, eig=None, translate=None, RealField_prec = RealField(prec) if translate is not None: - if isinstance(translate, dict): for a in translate: translate[a] = [vector(RealField_prec, v) for v in translate[a]] diff --git a/src/sage/crypto/block_cipher/des.py b/src/sage/crypto/block_cipher/des.py index 917b8dc6bf9..bbe7eeb70a9 100644 --- a/src/sage/crypto/block_cipher/des.py +++ b/src/sage/crypto/block_cipher/des.py @@ -393,7 +393,7 @@ def __init__(self, rounds=None, keySchedule='DES_KS', keySize=64, doFinalRound=T self.keySchedule = DES_KS() if keySchedule == 'DES_KS' else keySchedule self._rounds = self.keySchedule._rounds if rounds is None else rounds if self._rounds > self.keySchedule._rounds: - raise ValueError('number of rounds must be less or equal to the ' 'number of rounds of the key schedule') + raise ValueError('number of rounds must be less or equal to the number of rounds of the key schedule') self._keySize = keySize if keySize not in (56, 64): raise ValueError('key size must be 56 or 64') @@ -436,7 +436,7 @@ def __call__(self, block, key, algorithm='encrypt'): return self.encrypt(block, key) if algorithm == 'decrypt': return self.decrypt(block, key) - raise ValueError('Algorithm must be \'encrypt\' or \'decrypt\' and' ' not \'%s\'' % algorithm) + raise ValueError('Algorithm must be \'encrypt\' or \'decrypt\' and not \'%s\'' % algorithm) def __eq__(self, other): r""" @@ -472,7 +472,7 @@ def __repr__(self): DES block cipher with 16 rounds and the following key schedule: Original DES key schedule with 16 rounds """ - return 'DES block cipher with %s rounds and the following key ' 'schedule:\n%s' % (self._rounds, self.keySchedule.__repr__()) + return 'DES block cipher with %s rounds and the following key schedule:\n%s' % (self._rounds, self.keySchedule.__repr__()) def encrypt(self, plaintext, key): r""" diff --git a/src/sage/crypto/block_cipher/present.py b/src/sage/crypto/block_cipher/present.py index 427d77c4e4d..daf4bc6cbcc 100644 --- a/src/sage/crypto/block_cipher/present.py +++ b/src/sage/crypto/block_cipher/present.py @@ -256,7 +256,7 @@ def __init__(self, keySchedule=80, rounds=None, doFinalRound=False): elif rounds <= self.keySchedule._rounds: self._rounds = rounds else: - raise ValueError('number of rounds must be less or equal to the ' 'number of rounds of the key schedule') + raise ValueError('number of rounds must be less or equal to the number of rounds of the key schedule') self._blocksize = 64 self.sbox = PRESENTSBOX self._permutationMatrix = _smallscale_present_linearlayer() @@ -299,7 +299,7 @@ def __call__(self, block, key, algorithm='encrypt'): return self.encrypt(block, key) if algorithm == 'decrypt': return self.decrypt(block, key) - raise ValueError('Algorithm must be \'encrypt\' or \'decrypt\' and' ' not \'%s\'' % algorithm) + raise ValueError('Algorithm must be \'encrypt\' or \'decrypt\' and not \'%s\'' % algorithm) def __eq__(self, other): r""" @@ -337,7 +337,7 @@ def __repr__(self): last round and the following key schedule: Original PRESENT key schedule with 80-bit keys and 31 rounds """ - return 'PRESENT block cipher with %s rounds, %s linear layer in last ' 'round and the following key schedule:\n%s' % (self._rounds, 'activated' if self._doFinalRound else 'deactivated', self.keySchedule.__repr__()) + return 'PRESENT block cipher with %s rounds, %s linear layer in last round and the following key schedule:\n%s' % (self._rounds, 'activated' if self._doFinalRound else 'deactivated', self.keySchedule.__repr__()) def encrypt(self, plaintext, key): r""" diff --git a/src/sage/crypto/classical_cipher.py b/src/sage/crypto/classical_cipher.py index f65ca9db3bc..38b58b534ea 100644 --- a/src/sage/crypto/classical_cipher.py +++ b/src/sage/crypto/classical_cipher.py @@ -2,6 +2,7 @@ """ Classical Ciphers """ + # **************************************************************************** # Copyright (C) 2007 David Kohel # diff --git a/src/sage/crypto/cryptosystem.py b/src/sage/crypto/cryptosystem.py index 1938094c679..84b9646a55b 100644 --- a/src/sage/crypto/cryptosystem.py +++ b/src/sage/crypto/cryptosystem.py @@ -29,6 +29,7 @@ class of | + VigenereCryptosystem + PublicKeyCryptosystem """ + # **************************************************************************** # Copyright (C) 2007 David Kohel # diff --git a/src/sage/crypto/lattice.py b/src/sage/crypto/lattice.py index 7a7531b856d..8c63c7ab2b6 100644 --- a/src/sage/crypto/lattice.py +++ b/src/sage/crypto/lattice.py @@ -275,7 +275,7 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, quotient=None, dual=F found = True break if not found: - raise ValueError("cyclotomic bases require that n " "is an image of Euler's totient function") + raise ValueError("cyclotomic bases require that n is an image of Euler's totient function") R = ZZ_q['x'].quotient(cyclotomic_polynomial(k, 'x'), 'x') for i in range(m // n): @@ -297,7 +297,7 @@ def minrep(a): B.swap_rows(i, m - i - 1) if ntl and lattice: - raise ValueError("Cannot specify ntl=True and lattice=True " "at the same time") + raise ValueError("Cannot specify ntl=True and lattice=True at the same time") if ntl: return B._ntl_() diff --git a/src/sage/crypto/mq/rijndael_gf.py b/src/sage/crypto/mq/rijndael_gf.py index 0cdcd7d1280..3b5085ae348 100644 --- a/src/sage/crypto/mq/rijndael_gf.py +++ b/src/sage/crypto/mq/rijndael_gf.py @@ -435,7 +435,6 @@ class RijndaelGF(SageObject): - def __init__(self, Nb, Nk, state_chr='a', key_chr='k'): r""" An algebraically generalized version of the AES cipher. @@ -583,7 +582,7 @@ def __call__(self, text, key, algorithm='encrypt', format='hex'): return self.encrypt(text, key, format) if algorithm == 'decrypt': return self.decrypt(text, key, format) - raise ValueError("keyword 'algorithm' must be either 'encrypt' " "or 'decrypt'") + raise ValueError("keyword 'algorithm' must be either 'encrypt' or 'decrypt'") def __repr__(self): r""" @@ -597,7 +596,7 @@ def __repr__(self): Rijndael-GF block cipher with block length 5, key length 8, and 14 rounds. """ - msg = "Rijndael-GF block cipher with block length {0}, key length " "{1}, and {2} rounds." + msg = "Rijndael-GF block cipher with block length {0}, key length {1}, and {2} rounds." return msg.format(self._Nb, self._Nk, self._Nr) def block_length(self): @@ -726,7 +725,7 @@ def _GF_to_hex(self, GF): 'e142cd5fcd9d6d94a3340793034391b5' """ if not isinstance(GF, Matrix) and not isinstance(GF, list) and not (isinstance(GF, Element) and isinstance(GF.parent(), FiniteField_base)): - msg = "keyword 'GF' must be a matrix over {0}, a list of " "elements from {0}, or a single element from {0}" + msg = "keyword 'GF' must be a matrix over {0}, a list of elements from {0}, or a single element from {0}" raise TypeError(msg.format(self._F)) if isinstance(GF, Matrix): @@ -840,7 +839,7 @@ def _GF_to_bin(self, GF): '11011000000111111111100000011011110110000001111111111000000110111101100000011111111110000001101111011000000111111111100000011011' """ if not isinstance(GF, Matrix) and not isinstance(GF, list) and not (isinstance(GF, Element) and isinstance(GF.parent(), FiniteField_base)): - msg = "keyword 'GF' must be a matrix over {0}, a list of " "elements from {0}, or a single element from {0}" + msg = "keyword 'GF' must be a matrix over {0}, a list of elements from {0}, or a single element from {0}" raise TypeError(msg.format(self)) if isinstance(GF, Matrix): @@ -898,7 +897,7 @@ def encrypt(self, plain, key, format='hex'): if not isinstance(plain, str) or any(c not in '0123456789abcdefABCDEF' for c in plain): raise TypeError("'plain' keyword must be a hex string") if len(plain) != 8 * self._Nb: - msg = "'plain' keyword\'s length must be {0}, not{1}" + msg = "'plain' keyword's length must be {0}, not{1}" raise ValueError(msg.format(8 * self._Nb, len(plain))) if not isinstance(key, str) or any(c not in '0123456789abcdefABCDEF' for c in key): raise TypeError("'key' keyword must be a hex string") @@ -923,7 +922,7 @@ def encrypt(self, plain, key, format='hex'): key_state = self._bin_to_GF(key) roundKeys = self.expand_key(key_state) else: - raise ValueError("'format' keyword must be either 'hex' or " "'binary'") + raise ValueError("'format' keyword must be either 'hex' or 'binary'") state = self.add_round_key(state, roundKeys[0]) for r in range(self._Nr - 1): @@ -994,20 +993,20 @@ def decrypt(self, ciphertext, key, format='hex'): roundKeys = self.expand_key(key_state) elif format == 'binary': if not isinstance(ciphertext, str) or any(c not in '01' for c in ciphertext): - raise TypeError("'ciphertext' keyword must be a binary " "string") + raise TypeError("'ciphertext' keyword must be a binary string") if len(ciphertext) != 32 * self._Nb: msg = "'ciphertext' keyword's length must be {0}, not {1}" raise ValueError(msg.format(32 * self._Nb, len(ciphertext))) if not isinstance(key, str) or any(c not in '01' for c in key): raise TypeError("'key' keyword must be a binary string") if len(key) != 32 * self._Nk: - msg = "'key' keyword\'s length must be {0}, not {1}" + msg = "'key' keyword's length must be {0}, not {1}" raise ValueError(msg.format(32 * self._Nk, len(key))) state = self._bin_to_GF(ciphertext) key_state = self._bin_to_GF(key) roundKeys = self.expand_key(key_state) else: - raise ValueError("'format' keyword must be either \'hex\' or " "'binary'") + raise ValueError("'format' keyword must be either 'hex' or 'binary'") state = self.add_round_key(state, roundKeys[self._Nr]) state = self.shift_rows(state, algorithm='decrypt') @@ -1071,7 +1070,7 @@ def _check_valid_PRmatrix(self, PRm, keyword): """ from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base - msg = "keyword '{0}' must be a {1} x {2} matrix with entries from a " "multivariate PolynomialRing over {3}" + msg = "keyword '{0}' must be a {1} x {2} matrix with entries from a multivariate PolynomialRing over {3}" msg = msg.format(keyword, 4, self._Nb, self._F) if (not isinstance(PRm, Matrix) or not (PRm.base_ring().is_field() and PRm.base_ring().is_finite() and PRm.base_ring().order() == 256 and PRm.dimensions() == (4, self._Nb))) and ( not isinstance(PRm, Matrix) or not isinstance(PRm.base_ring(), MPolynomialRing_base) or not (PRm.base_ring().base_ring().is_field() and PRm.base_ring().base_ring().is_finite() and PRm.base_ring().base_ring().order() == 256) or not PRm.dimensions() == (4, self._Nb) @@ -1313,7 +1312,7 @@ def apply_poly(self, state, poly_constr, algorithm='encrypt', keys=None, poly_co msg = "keyword 'poly_constr' must be a Round_Component_Poly_Constr" raise TypeError(msg) if keys is not None and (not isinstance(keys, list) or len(keys) != self._Nr + 1 or not all(isinstance(k, Matrix) for k in keys) or not all(k.dimensions() == (4, self._Nb) for k in keys) or not all(k.base_ring().is_finite() and k.base_ring().is_field() and k.base_ring().order() == 256 for k in keys)): - msg = "keys must be a length {0} array of 4 by {1} matrices" " over {2}" + msg = "keys must be a length {0} array of 4 by {1} matrices over {2}" raise TypeError(msg.format(self._Nr, self._Nb, self._F)) output = [] @@ -1461,7 +1460,7 @@ def compose(self, f, g, algorithm='encrypt', f_attr=None, g_attr=None): from sage.rings.polynomial.multi_polynomial import MPolynomial if not isinstance(g, RijndaelGF.Round_Component_Poly_Constr) and not isinstance(g, MPolynomial): - msg = "keyword 'g' must be a Round_Component_Poly_Constr or a " "polynomial over {0}" + msg = "keyword 'g' must be a Round_Component_Poly_Constr or a polynomial over {0}" raise TypeError(msg.format(self._F)) if f_attr is not None and not isinstance(f_attr, dict): raise TypeError("f_attr must be a dictionary of keywords for f") @@ -1767,7 +1766,7 @@ def _sub_bytes_pc(self, row, col, algorithm='encrypt', no_inversion=False): if no_inversion: return result return result**254 - raise ValueError("keyword 'algorithm' must be either 'encrypt' " "or 'decrypt'") + raise ValueError("keyword 'algorithm' must be either 'encrypt' or 'decrypt'") def _srd(self, el, algorithm='encrypt'): r""" @@ -1801,7 +1800,7 @@ def _srd(self, el, algorithm='encrypt'): p = self._sub_bytes_rcpc(0, 0, algorithm, no_inversion=True) state = [el] + [self._F.zero()] * ((4 * self._Nb) - 1) return p(state) ** 254 - raise ValueError("keyword 'algorithm' must be either 'encrypt' " "or 'decrypt'") + raise ValueError("keyword 'algorithm' must be either 'encrypt' or 'decrypt'") def sub_bytes(self, state, algorithm='encrypt'): r""" @@ -1900,7 +1899,7 @@ def _mix_columns_pc(self, row, col, algorithm='encrypt'): elif algorithm == 'decrypt': coeffs = self._mixcols_D else: - raise ValueError("keyword 'algorithm' must be either 'encrypt' " "or 'decrypt'") + raise ValueError("keyword 'algorithm' must be either 'encrypt' or 'decrypt'") return sum([coeffs[row, k] * self.state_vrs[k, col] for k in range(4)]) def mix_columns(self, state, algorithm='encrypt'): @@ -1998,7 +1997,7 @@ def _shift_rows_pc(self, row, col, algorithm='encrypt'): elif algorithm == 'decrypt': offs = self._shiftrows_offsets_D else: - raise ValueError("keyword 'algorithm' must be either 'encrypt' " "or 'decrypt'") + raise ValueError("keyword 'algorithm' must be either 'encrypt' or 'decrypt'") return self.state_vrs[row, (col + offs[4 - self._Nb][row]) % 4] def shift_rows(self, state, algorithm='encrypt'): @@ -2033,7 +2032,6 @@ def shift_rows(self, state, algorithm='encrypt'): return self.apply_poly(state, self._shift_rows_rcpc, algorithm) class Round_Component_Poly_Constr(SageObject): - def __init__(self, polynomial_constr, rgf, round_component_name=None): r""" An object which constructs polynomials representing round @@ -2142,11 +2140,11 @@ def __init__(self, polynomial_constr, rgf, round_component_name=None): if pc_args[0][0] == 'self': # Check number of defaulted arguments if len(pc_args[3]) != len(pc_args[0]) - 3: - msg = "keyword 'polynomial_constr' must be callable as: " "polynomial_constr(row, col, algorithm='encrypt')" + msg = "keyword 'polynomial_constr' must be callable as: polynomial_constr(row, col, algorithm='encrypt')" raise TypeError(msg) else: if len(pc_args[3]) != len(pc_args[0]) - 2: - msg = "keyword 'polynomial_constr' must be callable as: " "polynomial_constr(row, col, algorithm='encrypt')" + msg = "keyword 'polynomial_constr' must be callable as: polynomial_constr(row, col, algorithm='encrypt')" raise TypeError(msg) self._polynomial_constr = polynomial_constr self._Nb = rgf.block_length() @@ -2197,7 +2195,7 @@ def __call__(self, row, col, algorithm='encrypt', **kwargs): msg = "keyword 'col' must be in range 0 - {0}" raise ValueError(msg.format(self._Nb - 1)) if algorithm not in ['encrypt', 'decrypt']: - msg = "keyword 'algorithm' must be either 'encrypt' or " "'decrypt'" + msg = "keyword 'algorithm' must be either 'encrypt' or 'decrypt'" print(algorithm) raise ValueError(msg) return self._polynomial_constr(row, col, algorithm, **kwargs) diff --git a/src/sage/crypto/mq/sr.py b/src/sage/crypto/mq/sr.py index b01dcab8d2d..be39c20edee 100644 --- a/src/sage/crypto/mq/sr.py +++ b/src/sage/crypto/mq/sr.py @@ -1140,7 +1140,6 @@ def key_schedule(self, kj, i): ki[1, 0] = s1 elif r == 4: - if self._aes_mode: s0 = SubByte(kj[1, c - 1]) s1 = SubByte(kj[2, c - 1]) @@ -1801,7 +1800,6 @@ def round_polynomials(self, i, plaintext=None, ciphertext=None): return tuple((w1 + k0 + plaintext).list()) if i > 0 and i <= n: - if self._star and i == n: M = self.Mstar diff --git a/src/sage/crypto/sboxes.py b/src/sage/crypto/sboxes.py index 3cffa705c08..49cea4f38e3 100644 --- a/src/sage/crypto/sboxes.py +++ b/src/sage/crypto/sboxes.py @@ -164,6 +164,7 @@ - Friedrich Wiemer (2017-05-12): refactored list for inclusion in Sage - Lukas Stennes (2019-06-25): added NIST LWC round 1 candidates """ + import sys from sage.crypto.sbox import SBox diff --git a/src/sage/data_structures/mutable_poset.py b/src/sage/data_structures/mutable_poset.py index 5e7dabcd552..3fbbb10a8a8 100644 --- a/src/sage/data_structures/mutable_poset.py +++ b/src/sage/data_structures/mutable_poset.py @@ -1340,7 +1340,7 @@ def __init__(self, data=None, key=None, merge=None, can_merge=None) -> None: try: it = iter(data) except TypeError: - raise TypeError('%s is not iterable; do not know what to ' 'do with it.' % (data,)) + raise TypeError('%s is not iterable; do not know what to do with it.' % (data,)) self.union_update(it) super().__init__() @@ -3101,7 +3101,7 @@ def can_merge(other): try: next(to_merge) except StopIteration: - raise RuntimeError('Stopping merge before started; the ' 'can_merge-function is not reflexive.') + raise RuntimeError('Stopping merge before started; the can_merge-function is not reflexive.') for m in tuple(to_merge): if m.is_special(): continue diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index 1e28acb05d6..2a59c426c16 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -2913,7 +2913,7 @@ def _approximate_order(self): """ # this is not the true order, unless we have an integral domain if self._left._approximate_order <= 0 or self._right._approximate_order <= 0: - raise ValueError("Dirichlet convolution is only defined for " "coefficient streams with minimal index of " "nonzero coefficient at least 1") + raise ValueError("Dirichlet convolution is only defined for coefficient streams with minimal index of nonzero coefficient at least 1") return self._left._approximate_order * self._right._approximate_order def get_coefficient(self, n): @@ -4256,7 +4256,7 @@ def _approximate_order(self): """ # this is the true order, but we want to check first if self._series._approximate_order > 1: - raise ZeroDivisionError("the Dirichlet inverse only exists if the " "coefficient with index 1 is nonzero") + raise ZeroDivisionError("the Dirichlet inverse only exists if the coefficient with index 1 is nonzero") self._true_order = True return 1 diff --git a/src/sage/databases/cremona.py b/src/sage/databases/cremona.py index 6b428ed7692..9401131c6c0 100644 --- a/src/sage/databases/cremona.py +++ b/src/sage/databases/cremona.py @@ -1630,7 +1630,7 @@ def CremonaDatabase(name=None, mini=None): name = 'cremona mini' else: if not DatabaseCremona().is_present(): - raise ValueError('the full Cremona database is not available; ' 'consider using the mini Cremona database by setting mini=True') + raise ValueError('the full Cremona database is not available; consider using the mini Cremona database by setting mini=True') name = 'cremona' elif name == 'cremona mini': mini = True diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py index 62773bbfad1..ba458d0a167 100644 --- a/src/sage/databases/cubic_hecke_db.py +++ b/src/sage/databases/cubic_hecke_db.py @@ -1325,9 +1325,7 @@ def update_basis_extensions(self, new_basis_extensions): {}age: from sage.databases.cubic_hecke_db import %s%s {}age: %s(%s2) {} -""".format( - 'r"""', 's', 's', '"""' -) # s in the middle to hide these lines from _test_enough_doctests +""".format('r"""', 's', 's', '"""') # s in the middle to hide these lines from _test_enough_doctests def create_demo_data(filename='demo_data.py'): diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index eded1875f0b..64c51cbe60f 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -4466,7 +4466,7 @@ def name(self, style='singular'): "DyckPaths": _SupportedFindStatCollection(lambda x: DyckWord(literal_eval(x)), lambda x: str(list(DyckWord(x))), DyckWords, lambda x: x.semilength(), lambda x: isinstance(x, DyckWord)), "FiniteCartanTypes": _SupportedFindStatCollection(lambda x: CartanType(*literal_eval(str(x))), str, _finite_irreducible_cartan_types_by_rank, lambda x: x.rank(), lambda x: isinstance(x, CartanType_abstract)), "GelfandTsetlinPatterns": _SupportedFindStatCollection( - lambda x: GelfandTsetlinPattern(literal_eval(x)), str, lambda x: (P for la in Partitions(x[1], max_length=x[0]) for P in GelfandTsetlinPatterns(top_row=la + [0] * (x[0] - len(la)))), lambda x: (len(x[0]), sum(x[0])), lambda x: (x == GelfandTsetlinPatterns or isinstance(x, GelfandTsetlinPattern)) + lambda x: GelfandTsetlinPattern(literal_eval(x)), str, lambda x: (P for la in Partitions(x[1], max_length=x[0]) for P in GelfandTsetlinPatterns(top_row=la + [0] * (x[0] - len(la)))), lambda x: (len(x[0]), sum(x[0])), lambda x: x == GelfandTsetlinPatterns or isinstance(x, GelfandTsetlinPattern) ), "Graphs": _SupportedFindStatCollection( lambda x: (lambda E, V: Graph([list(range(V)), lambda i, j: (i, j) in E or (j, i) in E], immutable=True))(*literal_eval(x)), diff --git a/src/sage/databases/knotinfo_db.py b/src/sage/databases/knotinfo_db.py index e68239afd67..95525c032c9 100644 --- a/src/sage/databases/knotinfo_db.py +++ b/src/sage/databases/knotinfo_db.py @@ -546,7 +546,6 @@ def _create_col_dict_sobj(self, sobj_path=None): # Columns that exist for knots and links # ---------------------------------------------------------------- for col in knot_column_names: - name = knot_column_names[col] if not name and col not in columns_white_list: # not of interest @@ -565,7 +564,6 @@ def _create_col_dict_sobj(self, sobj_path=None): # Columns that exist for links only # ---------------------------------------------------------------- for col in link_column_names: - name = link_column_names[col] if not name and col not in columns_white_list: # not of interest @@ -815,7 +813,7 @@ def _test_database(self, **options): max_samples = 20 l = list(KnotInfo) sample = some_tuples(l, 1, len(l), max_samples=max_samples) - tester.assertTrue(all(L.is_recoverable(unique=False) for L, in sample)) + tester.assertTrue(all(L.is_recoverable(unique=False) for (L,) in sample)) column_demo_sample = { diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index f65194c2ba0..fac25f90699 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -1609,7 +1609,7 @@ def links(self, browse=None, format='guess'): """ def url_absolute(s): - return re.sub(r'\"\/', '\"' + oeis_url, s) + return re.sub(r'\"\/', '"' + oeis_url, s) if browse is None: if format == 'guess': diff --git a/src/sage/databases/sloane.py b/src/sage/databases/sloane.py index da0e54f8456..acb06fd4f36 100644 --- a/src/sage/databases/sloane.py +++ b/src/sage/databases/sloane.py @@ -281,7 +281,7 @@ def load(self): try: file_seq = bz2.BZ2File(self.__file__, 'r') except OSError: - raise OSError("The Sloane Encyclopedia database must be installed." " Use e.g. 'SloaneEncyclopedia.install()' to download and install it.") + raise OSError("The Sloane Encyclopedia database must be installed. Use e.g. 'SloaneEncyclopedia.install()' to download and install it.") self.__data__ = {} @@ -314,7 +314,7 @@ def load(self): self.__loaded_names__ = True except KeyError: # Some sequence in the names file is not in the database - raise KeyError("Sloane OEIS sequence and name files do not match." " Try reinstalling, e.g. SloaneEncyclopedia.install(overwrite=True).") + raise KeyError("Sloane OEIS sequence and name files do not match. Try reinstalling, e.g. SloaneEncyclopedia.install(overwrite=True).") except OSError: # The names database is not installed self.__loaded_names__ = False @@ -342,7 +342,7 @@ def sequence_name(self, N): """ self.load() if not self.__loaded_names__: - raise OSError("The Sloane OEIS names file is not installed." " Try reinstalling, e.g. SloaneEncyclopedia.install(overwrite=True).") + raise OSError("The Sloane OEIS names file is not installed. Try reinstalling, e.g. SloaneEncyclopedia.install(overwrite=True).") if N not in self.__data__: # sequence N does not exist return '' diff --git a/src/sage/databases/sql_db.py b/src/sage/databases/sql_db.py index d0c7cd7ddbc..a500b436c21 100644 --- a/src/sage/databases/sql_db.py +++ b/src/sage/databases/sql_db.py @@ -467,7 +467,7 @@ def row_str(row, html): field_val = '
\n' p += 1 else: - raise NotImplementedError('Cannot display plot on ' 'command line.') + raise NotImplementedError('Cannot display plot on command line.') else: if index in fcol_index: if id_col_index is None: @@ -1171,7 +1171,7 @@ def __init__(self, filename=None, read_only=None, skeleton=None): if column not in self.__skeleton__[table]: self.add_column(table, column, skeleton[table][column]) else: - print('Column attributes were ignored for ' 'table {}, column {} -- column is ' 'already in table.'.format(table, column)) + print('Column attributes were ignored for table {}, column {} -- column is already in table.'.format(table, column)) elif skeleton is not None: raise RuntimeError('Cannot update skeleton of a read only ' + 'database.') @@ -1457,7 +1457,7 @@ def get_connection(self, ignore_warning=None): if not ignore_warning: import warnings - warnings.warn('Database is read only, using the connection ' 'can alter the stored data. Set self.ignore_warnings ' 'to True in order to mute future warnings.', RuntimeWarning) + warnings.warn('Database is read only, using the connection can alter the stored data. Set self.ignore_warnings to True in order to mute future warnings.', RuntimeWarning) return self.__connection__ def create_table(self, table_name, table_skeleton): @@ -2191,7 +2191,7 @@ def delete_rows(self, query): if query.__database__ is not self: raise ValueError('%s is not associated to this database.' % query) if (query.__query_string__).find(' JOIN ') != -1: - raise ValueError(f'{query} is not a valid query. Can only ' 'delete from one table at a time.') + raise ValueError(f'{query} is not a valid query. Can only delete from one table at a time.') delete_statement = re.sub('SELECT .* FROM', 'DELETE FROM', query.__query_string__) diff --git a/src/sage/doctest/__main__.py b/src/sage/doctest/__main__.py index 14f48245b4e..c905ae00d09 100644 --- a/src/sage/doctest/__main__.py +++ b/src/sage/doctest/__main__.py @@ -44,12 +44,12 @@ def _make_parser(): optional='sage,optional', random_seed=None, stats_path='.../timings2.json') """ - parser = argparse.ArgumentParser(usage="sage -t [options] filenames", description="Run all tests in a file or a list of files whose extensions " "are one of the following: " ".py, .pyx, .pxd, .pxi, .sage, .spyx, .tex, .rst.") - parser.add_argument("-p", "--nthreads", dest="nthreads", type=int, nargs='?', const=0, default=1, metavar="N", help="test in parallel using N threads, with 0 interpreted as max(2, min(8, cpu_count())); " "when run under the control of the GNU make jobserver (make -j), request as most N job slots") + parser = argparse.ArgumentParser(usage="sage -t [options] filenames", description="Run all tests in a file or a list of files whose extensions are one of the following: .py, .pyx, .pxd, .pxi, .sage, .spyx, .tex, .rst.") + parser.add_argument("-p", "--nthreads", dest="nthreads", type=int, nargs='?', const=0, default=1, metavar="N", help="test in parallel using N threads, with 0 interpreted as max(2, min(8, cpu_count())); when run under the control of the GNU make jobserver (make -j), request as most N job slots") parser.add_argument("-T", "--timeout", type=int, default=-1, help="timeout (in seconds) for doctesting one file, 0 for no timeout") what = parser.add_mutually_exclusive_group() what.add_argument("-a", "--all", action="store_true", default=False, help="test all files in the Sage library") - what.add_argument("--all-except", type=shlex.split, default=None, help="test all files in the Sage library except the specified space-separated list " "(backslash or quote are needed to escape spaces or backslashes or quotes)") + what.add_argument("--all-except", type=shlex.split, default=None, help="test all files in the Sage library except the specified space-separated list (backslash or quote are needed to escape spaces or backslashes or quotes)") what.add_argument("--installed", action="store_true", default=False, help="test all installed modules of the Sage library") parser.add_argument("--logfile", type=argparse.FileType('a'), metavar="FILE", help="log all output to FILE") @@ -77,9 +77,9 @@ def _make_parser(): "--hide", metavar="FEATURES", default="", - help='run tests pretending that the software listed in FEATURES (separated by commas) is not installed; ' 'if "all" is listed, will also hide features corresponding to all optional or experimental packages; ' 'if "optional" is listed, will also hide features corresponding to optional packages.', + help='run tests pretending that the software listed in FEATURES (separated by commas) is not installed; if "all" is listed, will also hide features corresponding to all optional or experimental packages; if "optional" is listed, will also hide features corresponding to optional packages.', ) - parser.add_argument("--probe", metavar="FEATURES", default="", help='run tests that would not be run because one of the given FEATURES (separated by commas) is not installed; ' 'report the tests that pass nevertheless') + parser.add_argument("--probe", metavar="FEATURES", default="", help='run tests that would not be run because one of the given FEATURES (separated by commas) is not installed; report the tests that pass nevertheless') parser.add_argument("--randorder", type=int, metavar="SEED", help="randomize order of tests") parser.add_argument("--random-seed", dest="random_seed", type=int, metavar="SEED", help="random seed (integer) for fuzzing doctests", default=os.environ.get("SAGE_DOCTEST_RANDOM_SEED")) parser.add_argument("--global-iterations", "--global_iterations", type=int, default=0, help="repeat the whole testing process this many times") @@ -97,10 +97,10 @@ def _make_parser(): parser.add_argument("--gdb", action="store_true", default=False, help="run doctests under the control of gdb") parser.add_argument("--lldb", action="store_true", default=False, help="run doctests under the control of lldb") - parser.add_argument("--valgrind", "--memcheck", action="store_true", default=False, help="run doctests using Valgrind's memcheck tool. The log " "files are named sage-memcheck.PID and can be found in " + os.path.join(DOT_SAGE, "valgrind")) - parser.add_argument("--massif", action="store_true", default=False, help="run doctests using Valgrind's massif tool. The log " "files are named sage-massif.PID and can be found in " + os.path.join(DOT_SAGE, "valgrind")) - parser.add_argument("--cachegrind", action="store_true", default=False, help="run doctests using Valgrind's cachegrind tool. The log " "files are named sage-cachegrind.PID and can be found in " + os.path.join(DOT_SAGE, "valgrind")) - parser.add_argument("--omega", action="store_true", default=False, help="run doctests using Valgrind's omega tool. The log " "files are named sage-omega.PID and can be found in " + os.path.join(DOT_SAGE, "valgrind")) + parser.add_argument("--valgrind", "--memcheck", action="store_true", default=False, help="run doctests using Valgrind's memcheck tool. The log files are named sage-memcheck.PID and can be found in " + os.path.join(DOT_SAGE, "valgrind")) + parser.add_argument("--massif", action="store_true", default=False, help="run doctests using Valgrind's massif tool. The log files are named sage-massif.PID and can be found in " + os.path.join(DOT_SAGE, "valgrind")) + parser.add_argument("--cachegrind", action="store_true", default=False, help="run doctests using Valgrind's cachegrind tool. The log files are named sage-cachegrind.PID and can be found in " + os.path.join(DOT_SAGE, "valgrind")) + parser.add_argument("--omega", action="store_true", default=False, help="run doctests using Valgrind's omega tool. The log files are named sage-omega.PID and can be found in " + os.path.join(DOT_SAGE, "valgrind")) parser.add_argument("-f", "--failed", action="store_true", default=False, help="doctest only those files that failed in the previous run") what.add_argument("-n", "--new", action="store_true", default=False, help="doctest only those files that have been changed in the repository and not yet been committed") @@ -115,7 +115,7 @@ def __call__(self, parser, namespace, values, option_string=None): new_value = gcopts[values] setattr(namespace, self.dest, new_value) - parser.add_argument("--gc", choices=["DEFAULT", "ALWAYS", "NEVER"], default=0, action=GCAction, help="control garbage collection " "(ALWAYS: collect garbage before every test; NEVER: disable gc; DEFAULT: Python default)") + parser.add_argument("--gc", choices=["DEFAULT", "ALWAYS", "NEVER"], default=0, action=GCAction, help="control garbage collection (ALWAYS: collect garbage before every test; NEVER: disable gc; DEFAULT: Python default)") # The --serial option is only really for internal use, better not # document it. diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index 22ce1cc3c3f..2193bad9a11 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -1024,7 +1024,7 @@ def expand(): if self.options.all_except is not None: paths_to_remove = set(os.path.abspath(x) for x in self.options.all_except) if not paths_to_remove.issubset(paths): - raise ValueError(f"--all-except includes {paths_to_remove - set(paths)}, " f"which are not found in {paths}") + raise ValueError(f"--all-except includes {paths_to_remove - set(paths)}, which are not found in {paths}") paths = [path for path in paths if path not in paths_to_remove] # keep duplicates self.sources = [FileDocTestSource(path, self.options) for path in paths] @@ -1692,6 +1692,4 @@ def stringify(x): {prompt}: get_matrix_class(GF(25,'x'), 4, 4, False, 'meataxe') # optional - meataxe {quotmark} -""".format( - quotmark='"""', prompt='sage' -) # using prompt to hide these lines from _test_enough_doctests +""".format(quotmark='"""', prompt='sage') # using prompt to hide these lines from _test_enough_doctests diff --git a/src/sage/doctest/fixtures.py b/src/sage/doctest/fixtures.py index 49910a51913..7a6f3b9d5f2 100644 --- a/src/sage/doctest/fixtures.py +++ b/src/sage/doctest/fixtures.py @@ -136,7 +136,6 @@ def sorted_pairs(iterable, pairs=False): class AttributeAccessTracerHelper: - def __init__(self, delegate, prefix=" ", reads=True): r""" Helper to print proxied access to attributes. @@ -247,7 +246,6 @@ def set(self, name, val): class AttributeAccessTracerProxy: - def __init__(self, delegate, **kwds): r""" Proxy object which prints all attribute and method access to an object. diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index 15901a15004..6b7492aa8b0 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -749,7 +749,7 @@ def compiler(example): if exception is None: if check(example.want, got, self.optionflags): if probed_tags and probed_tags is not True: - example.warnings.append(f"The tag '{unparse_optional_tags(probed_tags)}' " f"may no longer be needed; these features are not present, " f"but we ran the doctest anyway as requested by --probe, " f"and it succeeded.") + example.warnings.append(f"The tag '{unparse_optional_tags(probed_tags)}' may no longer be needed; these features are not present, but we ran the doctest anyway as requested by --probe, and it succeeded.") outcome = SUCCESS # The example raised an exception: check if it was expected. @@ -784,7 +784,7 @@ def compiler(example): # We expected an exception: see whether it matches. elif check(example.exc_msg, exc_msg, self.optionflags): if probed_tags and probed_tags is not True: - example.warnings.append(f"The tag '{unparse_optional_tags(example.probed_tags)}' " f"may no longer be needed; these features are not present, " f"but we ran the doctest anyway as requested by --probe, " f"and it succeeded (raised the expected exception).") + example.warnings.append(f"The tag '{unparse_optional_tags(example.probed_tags)}' may no longer be needed; these features are not present, but we ran the doctest anyway as requested by --probe, and it succeeded (raised the expected exception).") outcome = SUCCESS # Another chance if they didn't care about the detail. @@ -793,7 +793,7 @@ def compiler(example): m2 = re.match(r'(?:[^:]*\.)?([^:]*:)', exc_msg) if m1 and m2 and check(m1.group(1), m2.group(1), self.optionflags): if probed_tags and probed_tags is not True: - example.warnings.append(f"The tag '{unparse_optional_tags(example.probed_tags)}' " f"may no longer be needed; these features are not present, " f"but we ran the doctest anyway as requested by --probe, " f"and it succeeded (raised an exception as expected).") + example.warnings.append(f"The tag '{unparse_optional_tags(example.probed_tags)}' may no longer be needed; these features are not present, but we ran the doctest anyway as requested by --probe, and it succeeded (raised an exception as expected).") outcome = SUCCESS check_timer.stop() @@ -1156,7 +1156,7 @@ def compile_and_execute(self, example, compiler, globs): example.probed_tags = True else: f_setter_optional_tags = "; ".join("'" + unparse_optional_tags(setter_optional_tags) + "'" for setter_optional_tags in setters_dict) - example.warnings.append(f"Variable '{name}' referenced here " f"was set only in doctest marked {f_setter_optional_tags}") + example.warnings.append(f"Variable '{name}' referenced here was set only in doctest marked {f_setter_optional_tags}") for name in globs.set: self.setters[name][example.optional_tags] = example else: @@ -1632,7 +1632,7 @@ def report_unexpected_exception(self, out, test, example, exc_info): exc_type, exc_val, exc_tb = exc_info if exc_tb is None: - raise RuntimeError("could not start the debugger for an unexpected " "exception, probably due to an unhandled error " "in a C extension module") + raise RuntimeError("could not start the debugger for an unexpected exception, probably due to an unhandled error in a C extension module") self.debugger.reset() self.debugger.interaction(None, exc_tb) except KeyboardInterrupt: diff --git a/src/sage/doctest/parsing.py b/src/sage/doctest/parsing.py index 17ba3876437..46ef938633d 100644 --- a/src/sage/doctest/parsing.py +++ b/src/sage/doctest/parsing.py @@ -1009,11 +1009,11 @@ def check_and_clear_tag_counts(): if persistent_optional_tag_setter: warning_example = persistent_optional_tag_setter index = persistent_optional_tag_setter_index - warning = f"Consider updating this block-scoped tag to '{suggested}' " f"to avoid repeating the tag {num_examples} times" + warning = f"Consider updating this block-scoped tag to '{suggested}' to avoid repeating the tag {num_examples} times" else: warning_example = first_example_in_block index = first_example_in_block_index - warning = f"Consider using a block-scoped tag by " f"inserting the line '{suggested}' just before this line " f"to avoid repeating the tag {num_examples} times" + warning = f"Consider using a block-scoped tag by inserting the line '{suggested}' just before this line to avoid repeating the tag {num_examples} times" if not (index < len(filtered) and filtered[index] == warning_example): # The example to which we want to attach our warning is diff --git a/src/sage/doctest/sources.py b/src/sage/doctest/sources.py index e3c7ee225ba..b193e9fbe5a 100644 --- a/src/sage/doctest/sources.py +++ b/src/sage/doctest/sources.py @@ -67,7 +67,7 @@ untested = re.compile("(not implemented|not tested)") # For parsing a PEP 0263 encoding declaration -pep_0263 = re.compile(br'^[ \t\v]*#.*?coding[:=]\s*([-\w.]+)') +pep_0263 = re.compile(rb'^[ \t\v]*#.*?coding[:=]\s*([-\w.]+)') # Source line number in warning output doctest_line_number = re.compile(r"^\s*doctest:[0-9]") @@ -565,7 +565,7 @@ def __init__(self, path, options): self.encoding = "utf-8" else: valid_ext = ", ".join(valid_code_ext + ('.tex', '.rst', '.rst.txt')) - raise ValueError("unknown extension for the file to test (={})," " valid extensions are: {}".format(path, valid_ext)) + raise ValueError("unknown extension for the file to test (={}), valid extensions are: {}".format(path, valid_ext)) def __iter__(self): r""" diff --git a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py index ad775b9c430..db911a93439 100644 --- a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py @@ -988,7 +988,6 @@ def reduce_base_field(self): class DynamicalSystem_affine_finite_field(DynamicalSystem_affine_field, SchemeMorphism_polynomial_affine_space_finite_field): - def orbit_structure(self, P): r""" Every point is preperiodic over a finite field. diff --git a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py index 15296bde79a..b9d8d4f3214 100644 --- a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py @@ -247,13 +247,13 @@ def __classcall_private__(cls, dynamical_system, domain=None, ideal=None): try: dynamical_system = DynamicalSystem_affine(dynamical_system) except (TypeError, ValueError): - raise TypeError('domain was affine Berkovich space, but dynamical_system did not ' 'convert to an affine dynamical system') + raise TypeError('domain was affine Berkovich space, but dynamical_system did not convert to an affine dynamical system') if isinstance(domain, Berkovich_Cp_Projective): if not isinstance(dynamical_system, DynamicalSystem_projective): try: dynamical_system = DynamicalSystem_projective(dynamical_system) except (TypeError, ValueError): - raise TypeError('domain was projective Berkovich space, but dynamical_system did not convert ' 'to a projective dynamical system') + raise TypeError('domain was projective Berkovich space, but dynamical_system did not convert to a projective dynamical system') if not isinstance(dynamical_system, DynamicalSystem): try: @@ -274,7 +274,7 @@ def __classcall_private__(cls, dynamical_system, domain=None, ideal=None): if ideal != domain.ideal(): raise ValueError('conflicting inputs for ideal and domain') else: - raise ValueError('base ring of domain of dynamical_system must be p-adic or a number field ' 'not %s' % morphism_domain.base_ring()) + raise ValueError('base ring of domain of dynamical_system must be p-adic or a number field not %s' % morphism_domain.base_ring()) if isinstance(morphism_domain, AffineSpace_generic): return DynamicalSystem_Berkovich_affine(dynamical_system, domain) diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py index a55cb2bf790..e4d5420d935 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py @@ -1375,7 +1375,6 @@ def order_p_automorphisms(rational_function, pre_image): automorphisms_p.append(u_inv(u(z) + alpha**i * zeta**j)) elif r2 < r: - if case == 'fix': T = [x[0] for x in pre_image] elif case == 'F-pre_images': diff --git a/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py index 18bb960f64a..aaef8a6005e 100644 --- a/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/product_projective_ds.py @@ -293,7 +293,6 @@ class DynamicalSystem_product_projective_field(DynamicalSystem_product_projectiv class DynamicalSystem_product_projective_finite_field(DynamicalSystem_product_projective_field): - def cyclegraph(self): r""" Return the digraph of all orbits of this morphism mod `p`. diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 07331951748..53edfd19e5b 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -4525,7 +4525,7 @@ def preperiodic_points(self, m, n, **kwds): f_sub = self.change_ring(R) R = f_sub.base_ring() # in the case when R is an embedding if isinstance(R, FractionField_1poly_field) or R in FunctionFields(): - raise NotImplementedError('Periodic points not implemented for function fields; ' 'clear denominators and use the polynomial ring instead') + raise NotImplementedError('Periodic points not implemented for function fields; clear denominators and use the polynomial ring instead') CR = f_sub.coordinate_ring() dom = f_sub.domain() PS = f_sub.codomain().ambient_space() @@ -4859,10 +4859,10 @@ def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='vari f_sub = self.change_ring(R) R = f_sub.base_ring() # in the case when R is an embedding if isinstance(R, FractionField_1poly_field) or R in FunctionFields(): - raise NotImplementedError('periodic points not implemented for fraction function fields; ' 'clear denominators and use the polynomial ring instead') + raise NotImplementedError('periodic points not implemented for fraction function fields; clear denominators and use the polynomial ring instead') if isinstance(R, FractionField_generic): if isinstance(R.ring(), MPolynomialRing_base): - raise NotImplementedError('periodic points not implemented for fraction function fields; ' 'clear denominators and use the polynomial ring instead') + raise NotImplementedError('periodic points not implemented for fraction function fields; clear denominators and use the polynomial ring instead') CR = f_sub.coordinate_ring() dom = f_sub.domain() PS = f_sub.codomain().ambient_space() @@ -5845,7 +5845,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', return else: expected_degree = sum(d ** (n * i) for i in range(N + 1)) if degree_w != expected_degree: - raise ValueError('sigma polynomial dropped degree, as multiplicities were not accounted for correctly; ' 'try setting chow=True and/or deform=True') + raise ValueError('sigma polynomial dropped degree, as multiplicities were not accounted for correctly; try setting chow=True and/or deform=True') if return_polynomial: return sigma_polynomial # if we are returning a numerical list, read off the coefficients @@ -7004,7 +7004,6 @@ def Lattes_to_curve(self, return_conjugation=False, check_lattes=False): class DynamicalSystem_projective_field(DynamicalSystem_projective, SchemeMorphism_polynomial_projective_space_field): - def lift_to_rational_periodic(self, points_modp, B=None): r""" Given a list of points in projective space over `\GF{p}`, @@ -9079,7 +9078,6 @@ def is_newton(self, return_conjugation=False): class DynamicalSystem_projective_finite_field(DynamicalSystem_projective_field, SchemeMorphism_polynomial_projective_space_finite_field): - def is_postcritically_finite(self, **kwds): r""" Every point is postcritically finite in a finite field. diff --git a/src/sage/dynamics/cellular_automata/elementary.py b/src/sage/dynamics/cellular_automata/elementary.py index b9c8f1a1d0f..cbba963673c 100644 --- a/src/sage/dynamics/cellular_automata/elementary.py +++ b/src/sage/dynamics/cellular_automata/elementary.py @@ -285,7 +285,7 @@ def __init__(self, rule, width=None, initial_state=None, boundary=(0, 0)): self._width = width initial_state = [0] * (width - len(initial_state)) + initial_state else: - raise ValueError("the width must be at least the length of" " the initial state") + raise ValueError("the width must be at least the length of the initial state") self._states = [initial_state] if boundary is not None: self._bdry = tuple(boundary) diff --git a/src/sage/dynamics/cellular_automata/solitons.py b/src/sage/dynamics/cellular_automata/solitons.py index f57be99e420..bbf74ba93f0 100644 --- a/src/sage/dynamics/cellular_automata/solitons.py +++ b/src/sage/dynamics/cellular_automata/solitons.py @@ -493,7 +493,7 @@ def evolve(self, carrier_capacity=None, carrier_index=None, number=None): if not isinstance(carrier_index, (list, tuple)): carrier_index = [carrier_index] * len(carrier_capacity) if len(carrier_index) != len(carrier_capacity): - raise ValueError("carrier_index and carrier_capacity" " must have the same length") + raise ValueError("carrier_index and carrier_capacity must have the same length") for i, r in zip(carrier_capacity, carrier_index): self.evolve(i, r) return @@ -1088,9 +1088,7 @@ def cross_repr(i): --+-- | {!s:^7} -""".format( - simple_repr(state[i]), simple_repr(final[i]) - ) +""".format(simple_repr(state[i]), simple_repr(final[i])) ) ret._baseline = 2 return ret @@ -1370,7 +1368,7 @@ def evolve(self, carrier_capacity=None, carrier_index=None, number=None): if not isinstance(carrier_index, (list, tuple)): carrier_index = [carrier_index] * len(carrier_capacity) if len(carrier_index) != len(carrier_capacity): - raise ValueError("carrier_index and carrier_capacity" " must have the same length") + raise ValueError("carrier_index and carrier_capacity must have the same length") for i, r in zip(carrier_capacity, carrier_index): self.evolve(i, r) return diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia.py b/src/sage/dynamics/complex_dynamics/mandel_julia.py index a1d45268bd4..0ce28680f0a 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia.py +++ b/src/sage/dynamics/complex_dynamics/mandel_julia.py @@ -376,7 +376,7 @@ def external_ray(theta, **kwds): # Check if theta is in the interval [0,1] for angle in theta: if angle < 0 or angle > 1: - raise ValueError("values for theta must be in " "the closed interval [0,1].") + raise ValueError("values for theta must be in the closed interval [0,1].") # Loop through each value for theta in list and plot the external ray. for angle in theta: @@ -654,7 +654,6 @@ def julia_plot(f=None, **kwds): EPS = 0.00001 if f is not None and period is None: # f user-specified and no period given - # try to coerce f to live in a polynomial ring S = PolynomialRing(CC, names='z') z = S.gen() @@ -671,13 +670,12 @@ def julia_plot(f=None, **kwds): c = f_poly - z * z else: # f is specified and not of the form z^2 + c if interacts: - raise NotImplementedError("The interactive plot is only implemented for " "polynomials of the form f = z^2 + c.") + raise NotImplementedError("The interactive plot is only implemented for polynomials of the form f = z^2 + c.") else: return general_julia(f_poly, x_center, y_center, image_width, max_iteration, pixel_count, level_sep, number_of_colors, base_color) # otherwise we can use fast_julia_plot for z^2 + c if f_is_default_after_all or f is None or period is not None: - # specify default c = -1 value if f and period were not specified if not f_is_default_after_all and period is None: c = -1 diff --git a/src/sage/ext_data/nbconvert/postprocess.py b/src/sage/ext_data/nbconvert/postprocess.py index b8136fe98a9..2bac5d46189 100755 --- a/src/sage/ext_data/nbconvert/postprocess.py +++ b/src/sage/ext_data/nbconvert/postprocess.py @@ -13,7 +13,6 @@ """ if __name__ == '__main__': - import sys import re diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index a9224df33b3..1271e1f7ed0 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -167,7 +167,7 @@ def __init__(self, name, spkg=None, url=None, description=None, type='optional') if spkg and (t := spkg_type(spkg)) not in (type, None): from warnings import warn - warn(f'Feature {name} is declared {type}, ' f'but it is provided by {spkg}, ' f'which is declared {t} in SAGE_ROOT/build/pkgs', stacklevel=3) + warn(f'Feature {name} is declared {type}, but it is provided by {spkg}, which is declared {t} in SAGE_ROOT/build/pkgs', stacklevel=3) def is_present(self): r""" diff --git a/src/sage/features/ffmpeg.py b/src/sage/features/ffmpeg.py index c260316f451..4be5d688e8b 100644 --- a/src/sage/features/ffmpeg.py +++ b/src/sage/features/ffmpeg.py @@ -78,12 +78,10 @@ def is_functional(self): # https://stackoverflow.com/questions/16523746/ffmpeg-hangs-when-run-in-background commands = [] for ext in ['.avi', '.flv', '.gif', '.mkv', '.mov', '.mp4', '.ogg', '.ogv', '.webm', '.wmv']: - cmd = ['ffmpeg', '-nostdin', '-y', '-f', 'image2', '-r', '5', '-i', filename_png, '-pix_fmt', 'rgb24', '-loop', '0', filename + ext] commands.append(cmd) for ext in ['.avi', '.flv', '.gif', '.mkv', '.mov', '.mpg', '.mp4', '.ogg', '.ogv', '.webm', '.wmv']: - cmd = ['ffmpeg', '-nostdin', '-y', '-f', 'image2', '-i', filename_png, filename + ext] commands.append(cmd) @@ -94,11 +92,11 @@ def is_functional(self): try: result = run(cmd, cwd=base, capture_output=True, text=True) except OSError as e: - return FeatureTestResult(self, False, reason='Running command "{}" ' 'raised an OSError "{}" '.format(' '.join(cmd), e)) + return FeatureTestResult(self, False, reason='Running command "{}" raised an OSError "{}" '.format(' '.join(cmd), e)) # If an error occurred, return False if result.returncode: - return FeatureTestResult(self, False, reason='Running command "{}" ' 'returned nonzero exit status "{}" with stderr ' '"{}" and stdout "{}".'.format(result.args, result.returncode, result.stderr.strip(), result.stdout.strip())) + return FeatureTestResult(self, False, reason='Running command "{}" returned nonzero exit status "{}" with stderr "{}" and stdout "{}".'.format(result.args, result.returncode, result.stderr.strip(), result.stdout.strip())) # If necessary, run more tests here # ... diff --git a/src/sage/features/imagemagick.py b/src/sage/features/imagemagick.py index 12de7508db5..b709bdfab3e 100644 --- a/src/sage/features/imagemagick.py +++ b/src/sage/features/imagemagick.py @@ -92,11 +92,11 @@ def is_functional(self): try: result = run(cmd, cwd=base, capture_output=True, text=True) except OSError as e: - return FeatureTestResult(self, False, reason='Running command "{}" ' 'raised an OSError "{}" '.format(' '.join(cmd), e)) + return FeatureTestResult(self, False, reason='Running command "{}" raised an OSError "{}" '.format(' '.join(cmd), e)) # If an error occurred, return False if result.returncode: - return FeatureTestResult(self, False, reason='Running command "{}" ' 'returned nonzero exit status "{}" with stderr ' '"{}" and stdout "{}".'.format(result.args, result.returncode, result.stderr.strip(), result.stdout.strip())) + return FeatureTestResult(self, False, reason='Running command "{}" returned nonzero exit status "{}" with stderr "{}" and stdout "{}".'.format(result.args, result.returncode, result.stderr.strip(), result.stdout.strip())) # If necessary, run more tests here # ... diff --git a/src/sage/features/kenzo.py b/src/sage/features/kenzo.py index 102898c8fbb..05e0f6e2505 100644 --- a/src/sage/features/kenzo.py +++ b/src/sage/features/kenzo.py @@ -14,7 +14,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from . import Feature, FeatureTestResult diff --git a/src/sage/features/latex.py b/src/sage/features/latex.py index 961893c72fb..8c7753bb292 100644 --- a/src/sage/features/latex.py +++ b/src/sage/features/latex.py @@ -96,7 +96,7 @@ def is_functional(self): # return if result.returncode == 0: return FeatureTestResult(self, True) - return FeatureTestResult(self, False, reason="Running latex on " "a sample file (with command='{}') returned nonzero " "exit status='{}' with stderr='{}' " "and stdout='{}'".format(result.args, result.returncode, result.stderr.strip(), result.stdout.strip())) + return FeatureTestResult(self, False, reason="Running latex on a sample file (with command='{}') returned nonzero exit status='{}' with stderr='{}' and stdout='{}'".format(result.args, result.returncode, result.stderr.strip(), result.stdout.strip())) class latex(LaTeX): diff --git a/src/sage/features/lrs.py b/src/sage/features/lrs.py index 03efd3f3db8..be21c07428b 100644 --- a/src/sage/features/lrs.py +++ b/src/sage/features/lrs.py @@ -62,7 +62,7 @@ def is_functional(self): try: result = subprocess.run(command, capture_output=True, text=True) except OSError as e: - return FeatureTestResult(self, False, reason='Running command "{}" ' 'raised an OSError "{}" '.format(' '.join(command), e)) + return FeatureTestResult(self, False, reason='Running command "{}" raised an OSError "{}" '.format(' '.join(command), e)) if result.returncode: return FeatureTestResult(self, False, reason="Call to `{command}` failed with exit code {result.returncode}.".format(command=" ".join(command), result=result)) @@ -117,9 +117,9 @@ def is_functional(self): try: result = subprocess.run(command, capture_output=True, text=True) except OSError as e: - return FeatureTestResult(self, False, reason='Running command "{}" ' 'raised an OSError "{}" '.format(' '.join(command), e)) + return FeatureTestResult(self, False, reason='Running command "{}" raised an OSError "{}" '.format(' '.join(command), e)) if result.returncode: - return FeatureTestResult(self, False, reason='Running command "{}" ' 'returned nonzero exit status "{}" with stderr ' '"{}" and stdout "{}".'.format(' '.join(result.args), result.returncode, result.stderr.strip(), result.stdout.strip())) + return FeatureTestResult(self, False, reason='Running command "{}" returned nonzero exit status "{}" with stderr "{}" and stdout "{}".'.format(' '.join(result.args), result.returncode, result.stderr.strip(), result.stdout.strip())) return FeatureTestResult(self, True) diff --git a/src/sage/features/meataxe.py b/src/sage/features/meataxe.py index 799256a4b0f..4f1bd32fd05 100644 --- a/src/sage/features/meataxe.py +++ b/src/sage/features/meataxe.py @@ -12,7 +12,6 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** - from . import PythonModule from .join_feature import JoinFeature diff --git a/src/sage/functions/airy.py b/src/sage/functions/airy.py index a136b0b9e16..4177682d961 100644 --- a/src/sage/functions/airy.py +++ b/src/sage/functions/airy.py @@ -110,7 +110,7 @@ def _derivative_(self, alpha, x, diff_param=None): in the first parameter """ if diff_param == 0: - raise NotImplementedError("cannot differentiate airy_ai in the" " first parameter") + raise NotImplementedError("cannot differentiate airy_ai in the first parameter") return airy_ai_general(alpha + 1, x) def _eval_(self, alpha, x): @@ -534,7 +534,7 @@ def _derivative_(self, alpha, x, diff_param=None): in the first parameter """ if diff_param == 0: - raise NotImplementedError("cannot differentiate airy_bi in the" " first parameter") + raise NotImplementedError("cannot differentiate airy_bi in the first parameter") return airy_bi_general(alpha + 1, x) def _eval_(self, alpha, x): diff --git a/src/sage/functions/gamma.py b/src/sage/functions/gamma.py index 4fbaf650a66..2dccc0284a4 100644 --- a/src/sage/functions/gamma.py +++ b/src/sage/functions/gamma.py @@ -612,7 +612,7 @@ def _derivative_(self, x, y, diff_param=None): NotImplementedError: cannot differentiate gamma_inc_lower in the first parameter """ if diff_param == 0: - raise NotImplementedError("cannot differentiate gamma_inc_lower in the" " first parameter") + raise NotImplementedError("cannot differentiate gamma_inc_lower in the first parameter") else: return exp(-y) * y ** (x - 1) diff --git a/src/sage/functions/hypergeometric.py b/src/sage/functions/hypergeometric.py index ff8931330cc..7d2641e2a7c 100644 --- a/src/sage/functions/hypergeometric.py +++ b/src/sage/functions/hypergeometric.py @@ -389,12 +389,11 @@ def _tderivative_(self, a, b, z, *args, **kwargs): """ diff_param = kwargs['diff_param'] if diff_param in hypergeometric(a, b, 1).variables(): # ignore z - raise NotImplementedError("derivative of hypergeometric function " "with respect to parameters. Try calling" " .simplify_hypergeometric() first.") + raise NotImplementedError("derivative of hypergeometric function with respect to parameters. Try calling .simplify_hypergeometric() first.") t = reduce(lambda x, y: x * y, a, 1) * reduce(lambda x, y: x / y, b, Integer(1)) return t * derivative(z, diff_param) * hypergeometric([c + 1 for c in a], [c + 1 for c in b], z) class EvaluationMethods: - def _fast_callable_(self, a, b, z, etb): """ Override the ``fast_callable`` method. @@ -993,7 +992,7 @@ def _derivative_(self, a, b, z, diff_param): """ if diff_param == 2: return (a / b) * hypergeometric_M(a + 1, b + 1, z) - raise NotImplementedError('derivative of hypergeometric function ' 'with respect to parameters') + raise NotImplementedError('derivative of hypergeometric function with respect to parameters') class EvaluationMethods: def generalized(self, a, b, z): @@ -1093,7 +1092,7 @@ def _derivative_(self, a, b, z, diff_param): """ if diff_param == 2: return -a * hypergeometric_U(a + 1, b + 1, z) - raise NotImplementedError('derivative of hypergeometric function ' 'with respect to parameters') + raise NotImplementedError('derivative of hypergeometric function with respect to parameters') class EvaluationMethods: def generalized(self, a, b, z): diff --git a/src/sage/functions/jacobi.py b/src/sage/functions/jacobi.py index 052f61d9996..d1e0c154657 100644 --- a/src/sage/functions/jacobi.py +++ b/src/sage/functions/jacobi.py @@ -195,7 +195,7 @@ def __init__(self, kind): jacobiDn(x,2) """ if kind not in ['nd', 'ns', 'nc', 'dn', 'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs']: - raise ValueError("kind must be one of 'nd', 'ns', 'nc', 'dn', " "'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") + raise ValueError("kind must be one of 'nd', 'ns', 'nc', 'dn', 'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") self.kind = kind BuiltinFunction.__init__(self, name=f'jacobi_{kind}', nargs=2, evalf_params_first=False, conversions=dict(maple=('Jacobi{}'.format(kind.upper())), mathematica=('Jacobi{}'.format(kind.upper())), fricas=('jacobi{}'.format(kind.capitalize())), maxima=('jacobi_{}'.format(kind)))) @@ -496,7 +496,7 @@ def __init__(self, kind): inverse_jacobi_sn """ if kind not in ['nd', 'ns', 'nc', 'dn', 'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs']: - raise ValueError("kind must be one of 'nd', 'ns', 'nc', 'dn', " "'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") + raise ValueError("kind must be one of 'nd', 'ns', 'nc', 'dn', 'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") self.kind = kind BuiltinFunction.__init__(self, name=f'inverse_jacobi_{kind}', nargs=2, evalf_params_first=False, conversions=dict(maple=('InverseJacobi{}'.format(kind.upper())), mathematica=f'InverseJacobi{kind.upper()}', maxima=(f'inverse_jacobi_{kind}'))) @@ -868,7 +868,7 @@ def jacobi(kind, z, m, **kwargs): return jacobi_cd(z, m, **kwargs) if kind == 'cs': return jacobi_cs(z, m, **kwargs) - raise ValueError("kind must be one of 'nd', 'ns', 'nc', 'dn', " "'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") + raise ValueError("kind must be one of 'nd', 'ns', 'nc', 'dn', 'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") def inverse_jacobi(kind, x, m, **kwargs): @@ -947,7 +947,7 @@ def inverse_jacobi(kind, x, m, **kwargs): return inverse_jacobi_cd(x, m, **kwargs) if kind == 'cs': return inverse_jacobi_cs(x, m, **kwargs) - raise ValueError("kind must be one of 'nd', 'ns', 'nc', 'dn', " "'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") + raise ValueError("kind must be one of 'nd', 'ns', 'nc', 'dn', 'ds', 'dc', 'sn', 'sd', 'sc', 'cn', 'cd', 'cs'.") class JacobiAmplitude(BuiltinFunction): diff --git a/src/sage/functions/piecewise.py b/src/sage/functions/piecewise.py index c9a9f576860..0063a4ab938 100644 --- a/src/sage/functions/piecewise.py +++ b/src/sage/functions/piecewise.py @@ -314,7 +314,6 @@ def _tderivative_(self, parameters, variable, *args, **kwds): return piecewise([(domain, func.derivative(*args)) for domain, func in parameters], var=variable) class EvaluationMethods: - def __pow__(self, parameters, variable, n): """ Return the `n`-th power of the piecewise function by applying the diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index f1930803abc..300e5c54ff8 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -360,7 +360,7 @@ def _derivative_(self, n, m, theta, phi, diff_param): if diff_param == 3: return I * m * spherical_harmonic(n, m, theta, phi) - raise ValueError('only derivative with respect to theta or phi' ' supported') + raise ValueError('only derivative with respect to theta or phi supported') def _latex_(self): r""" diff --git a/src/sage/functions/transcendental.py b/src/sage/functions/transcendental.py index 9d42370e63a..7eba4e6f92f 100644 --- a/src/sage/functions/transcendental.py +++ b/src/sage/functions/transcendental.py @@ -273,7 +273,7 @@ def _derivative_(self, s, x, diff_param): """ if diff_param == 1: return -s * hurwitz_zeta(s + 1, x) - raise NotImplementedError('derivative with respect to first ' 'argument') + raise NotImplementedError('derivative with respect to first argument') hurwitz_zeta_func = Function_HurwitzZeta() diff --git a/src/sage/game_theory/normal_form_game.py b/src/sage/game_theory/normal_form_game.py index c1d10f38184..7c07094b616 100644 --- a/src/sage/game_theory/normal_form_game.py +++ b/src/sage/game_theory/normal_form_game.py @@ -1674,7 +1674,7 @@ def obtain_nash(self, algorithm=False, maximization=True, solver=None): (in which case the default one is used), or a callable. """ if len(self.players) > 2: - raise NotImplementedError("Nash equilibrium for games with more " "than 2 players have not been " "implemented yet. Please see the gambit " "website (http://gambit.sourceforge.net/) that has a variety of " "available algorithms") + raise NotImplementedError("Nash equilibrium for games with more than 2 players have not been implemented yet. Please see the gambit website (http://gambit.sourceforge.net/) that has a variety of available algorithms") if not self._is_complete(): raise ValueError("utilities have not been populated") @@ -2418,7 +2418,7 @@ def is_degenerate(self, certificate=False) -> bool: games with more than two players. """ if len(self.players) > 2: - raise NotImplementedError("Tests for Degeneracy is not yet " "implemented for games with more than " "two players.") + raise NotImplementedError("Tests for Degeneracy is not yet implemented for games with more than two players.") d = self._is_degenerate_pure(certificate) if d: diff --git a/src/sage/geometry/cone.py b/src/sage/geometry/cone.py index 2dfd65e3199..af96279e07d 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -579,7 +579,7 @@ def try_base_extend(ring): if p is not None: return p if isinstance(parent(data), ToricLattice_generic): - raise TypeError("the point %s and %s have incompatible " "lattices" % (data, body)) + raise TypeError("the point %s and %s have incompatible lattices" % (data, body)) # If we don't have a lattice element, try successively # less-desirable ambient spaces until (as a last resort) we @@ -604,7 +604,7 @@ def try_base_extend(ring): return p # Raise TypeError with our own message - raise TypeError("%s does not represent a valid point in the ambient " "space of %s" % (data, body)) + raise TypeError("%s does not represent a valid point in the ambient space of %s" % (data, body)) def integral_length(v): @@ -681,7 +681,7 @@ def normalize_rays(rays, lattice): try: rays = list(rays) except TypeError: - raise TypeError("rays must be given as a list or a compatible structure!" "\nGot: %s" % rays) + raise TypeError("rays must be given as a list or a compatible structure!\nGot: %s" % rays) if rays: if lattice is None: ray_parent = parent(rays[0]) @@ -1640,7 +1640,7 @@ def _contains(self, point, region='whole cone') -> bool: point = _ambient_space_point(self, point) except TypeError as ex: if str(ex).endswith("have incompatible lattices!"): - warn("you have checked if a cone contains a point " "from an incompatible lattice, this is False!", stacklevel=3) + warn("you have checked if a cone contains a point from an incompatible lattice, this is False!", stacklevel=3) return False if region not in ("whole cone", "relative interior", "interior"): @@ -3170,7 +3170,7 @@ def is_isomorphic(self, other): return Fan([self]).is_isomorphic(Fan([other])) if self.is_strictly_convex() ^ other.is_strictly_convex(): return False - raise NotImplementedError("isomorphism check for not strictly convex " "cones is not implemented") + raise NotImplementedError("isomorphism check for not strictly convex cones is not implemented") def is_simplicial(self) -> bool: r""" @@ -6314,7 +6314,7 @@ def max_angle(self, other=None, exact=True, epsilon=0): other = self else: if other.lattice_dim() != self.lattice_dim(): - raise ValueError("lattice dimensions of self and other " "must agree") + raise ValueError("lattice dimensions of self and other must agree") if other.is_trivial(): raise ValueError("other cone cannot be trivial") diff --git a/src/sage/geometry/cone_catalog.py b/src/sage/geometry/cone_catalog.py index 6de5626aa00..14d8b271d09 100644 --- a/src/sage/geometry/cone_catalog.py +++ b/src/sage/geometry/cone_catalog.py @@ -146,7 +146,7 @@ def _preprocess_args(ambient_dim, lattice): from sage.geometry.toric_lattice import ToricLattice if ambient_dim is None and lattice is None: - raise ValueError("either the ambient dimension or the lattice " "must be specified") + raise ValueError("either the ambient dimension or the lattice must be specified") if ambient_dim is None: ambient_dim = lattice.rank() @@ -155,7 +155,7 @@ def _preprocess_args(ambient_dim, lattice): lattice = ToricLattice(ambient_dim) if lattice.rank() != ambient_dim: - raise ValueError("lattice rank=%d and ambient_dim=%d " "are incompatible" % (lattice.rank(), ambient_dim)) + raise ValueError("lattice rank=%d and ambient_dim=%d are incompatible" % (lattice.rank(), ambient_dim)) return (ambient_dim, lattice) @@ -687,7 +687,7 @@ def rearrangement(p, ambient_dim=None, lattice=None): ambient_dim, lattice = _preprocess_args(ambient_dim, lattice) if p < 1 or p > ambient_dim or p not in ZZ: - raise ValueError("order p=%s should be an integer between 1 " "and ambient_dim=%d, inclusive" % (p, ambient_dim)) + raise ValueError("order p=%s should be an integer between 1 and ambient_dim=%d, inclusive" % (p, ambient_dim)) I = matrix.identity(ZZ, ambient_dim) M = matrix.ones(ZZ, ambient_dim) - p * I diff --git a/src/sage/geometry/cone_critical_angles.py b/src/sage/geometry/cone_critical_angles.py index cd54a726acf..acc74ad7bf1 100644 --- a/src/sage/geometry/cone_critical_angles.py +++ b/src/sage/geometry/cone_critical_angles.py @@ -948,7 +948,6 @@ def max_angle(P, Q, exact, epsilon): H_J_c_T = H.matrix_from_columns(J_complement).transpose() for cos_theta, xi, eta, mult in solve_gevp_nonzero(GG, HH, M, I, J): - if cos_theta >= min_ip: # This potential critical angle is smaller than or # equal to one that we've already found. Why @@ -993,6 +992,6 @@ def max_angle(P, Q, exact, epsilon): # that the case where either P or Q is the ambient space # was handled much earlier, since in that case the maximal # angle is obviously pi.) - raise ValueError('eigenspace of dimension %d > 1 ' 'corresponding to eigenvalue %s' % (mult, cos_theta)) + raise ValueError('eigenspace of dimension %d > 1 corresponding to eigenvalue %s' % (mult, cos_theta)) return (arccos(min_ip), min_u, min_v) diff --git a/src/sage/geometry/convex_set.py b/src/sage/geometry/convex_set.py index c4270c4590d..3ce645f4f5b 100644 --- a/src/sage/geometry/convex_set.py +++ b/src/sage/geometry/convex_set.py @@ -399,7 +399,7 @@ def affine_hull_projection(self, as_convex_set=None, as_affine_map=False, orthog if as_convex_set is None: as_convex_set = not as_affine_map if not as_affine_map and not as_convex_set: - raise ValueError('combining "as_affine_map=False" and ' '"as_convex_set=False" not allowed') + raise ValueError('combining "as_affine_map=False" and "as_convex_set=False" not allowed') if return_all_data: as_convex_set = True as_affine_map = True diff --git a/src/sage/geometry/fan.py b/src/sage/geometry/fan.py index dae111a4074..97dda9822a5 100644 --- a/src/sage/geometry/fan.py +++ b/src/sage/geometry/fan.py @@ -520,7 +520,7 @@ def result(): V = PointCollection(V, lattice) d = lattice.dimension() if len(V) != d - R.dim() or (R + V).dim() != d: - raise ValueError("virtual rays must be linearly " "independent and with other rays span the ambient space.") + raise ValueError("virtual rays must be linearly independent and with other rays span the ambient space.") return RationalPolyhedralFan(cones, R, lattice, is_complete, V) if not check and not normalize and not discard_faces and not allow_arrangement: @@ -529,13 +529,13 @@ def result(): try: cones = list(cones) except TypeError: - raise TypeError("cones must be given as an iterable!" "\nGot: %s" % cones) + raise TypeError("cones must be given as an iterable!\nGot: %s" % cones) if not cones: if lattice is None: if rays is not None and rays: lattice = normalize_rays(rays, lattice)[0].parent() else: - raise ValueError("you must specify the lattice when you " "construct a fan without rays and cones!") + raise ValueError("you must specify the lattice when you construct a fan without rays and cones!") cones = ((),) rays = () return result() @@ -549,7 +549,7 @@ def result(): if check: for cone in cones: if cone.lattice() != lattice: - raise ValueError("cones belong to different lattices " "(%s and %s), cannot determine the lattice of the " "fan!" % (lattice, cone.lattice())) + raise ValueError("cones belong to different lattices (%s and %s), cannot determine the lattice of the fan!" % (lattice, cone.lattice())) for i, cone in enumerate(cones): if cone.lattice() != lattice: cones[i] = Cone(cone.rays(), lattice, check=False) @@ -580,14 +580,14 @@ def result(): is_generating = False # cone is a face of g_cone break else: - raise ValueError("these cones cannot belong to the same fan!" "\nCone 1 rays: %s\nCone 2 rays: %s" % (g_cone.rays(), cone.rays())) + raise ValueError("these cones cannot belong to the same fan!\nCone 1 rays: %s\nCone 2 rays: %s" % (g_cone.rays(), cone.rays())) if is_generating: generating_cones.append(cone) if len(cones) > len(generating_cones): if discard_faces: cones = generating_cones else: - raise ValueError("you have provided %d cones, but only %d " "of them are maximal! Use discard_faces=True if you " "indeed need to construct a fan from these cones." % (len(cones), len(generating_cones))) + raise ValueError("you have provided %d cones, but only %d of them are maximal! Use discard_faces=True if you indeed need to construct a fan from these cones." % (len(cones), len(generating_cones))) elif discard_faces: cones = _discard_faces(cones) ray_set = set() @@ -700,7 +700,7 @@ def FaceFan(polytope, lattice=None): ValueError: face fans are defined only for polytopes containing the origin as an interior point! """ - interior_point_error = ValueError("face fans are defined only for polytopes containing " "the origin as an interior point!") + interior_point_error = ValueError("face fans are defined only for polytopes containing the origin as an interior point!") if isinstance(polytope, sage.geometry.abc.LatticePolytope): if any(d <= 0 for d in polytope.distances([0] * polytope.dim())): raise interior_point_error @@ -896,7 +896,7 @@ def Fan2d(rays, lattice=None): """ if not rays: if lattice is None or lattice.dimension() != 2: - raise ValueError('you must specify a 2-dimensional lattice when ' 'you construct a fan without rays.') + raise ValueError('you must specify a 2-dimensional lattice when you construct a fan without rays.') return RationalPolyhedralFan(cones=((),), rays=(), lattice=lattice) # remove multiple rays without changing order @@ -1495,7 +1495,7 @@ def _contains(self, cone) -> bool: return False except ValueError: # cone is a cone, but wrong if not cone.lattice().is_submodule(self.lattice()): - warn("you have checked if a fan contains a cone " "from another lattice, this is always False!", stacklevel=3) + warn("you have checked if a fan contains a cone from another lattice, this is always False!", stacklevel=3) return False def support_contains(self, *args): @@ -1557,7 +1557,7 @@ def support_contains(self, *args): point = _ambient_space_point(self, point) except TypeError as ex: if str(ex).endswith("have incompatible lattices!"): - warn("you have checked if a fan contains a point " "from an incompatible lattice, this is False!", stacklevel=3) + warn("you have checked if a fan contains a point from an incompatible lattice, this is False!", stacklevel=3) return False if self.is_complete(): return True @@ -1911,7 +1911,7 @@ def cone_containing(self, *points): for ray in rays: generating_cones.intersection_update(self._ray_to_cones(ray)) if not generating_cones: - raise ValueError("there is no cone in %s containing all of " "the given rays! Ray indices: %s" % (self, rays)) + raise ValueError("there is no cone in %s containing all of the given rays! Ray indices: %s" % (self, rays)) containing_cone = self.generating_cone(generating_cones.pop()) for cone in generating_cones: containing_cone = containing_cone.intersection(self.generating_cone(cone)) @@ -1945,7 +1945,7 @@ def cone_containing(self, *points): containing_cone = cone break if containing_cone is None: - raise ValueError("there is no cone in %s containing all of " "the given points! Points: %s" % (self, points)) + raise ValueError("there is no cone in %s containing all of the given points! Points: %s" % (self, points)) # Now we take the intersection of facets that contain all points facets = containing_cone.facets() for facet in facets: diff --git a/src/sage/geometry/fan_morphism.py b/src/sage/geometry/fan_morphism.py index 8b75d4f3745..991996762b3 100644 --- a/src/sage/geometry/fan_morphism.py +++ b/src/sage/geometry/fan_morphism.py @@ -273,10 +273,10 @@ def __init__(self, morphism, domain_fan, codomain=None, subdivide=False, check=T elif isinstance(morphism, Matrix): A = morphism if codomain is None: - raise ValueError("codomain (fan) must be given explicitly if " "morphism is given by a matrix!") + raise ValueError("codomain (fan) must be given explicitly if morphism is given by a matrix!") parent = Hom(domain_fan.lattice(), codomain) else: - raise TypeError("morphism must be either a FreeModuleMorphism " "or a matrix!\nGot: %s" % morphism) + raise TypeError("morphism must be either a FreeModuleMorphism or a matrix!\nGot: %s" % morphism) super().__init__(parent, A) self._domain_fan = domain_fan self._image_cone = dict() @@ -545,7 +545,7 @@ def _repr_(self): Domain fan: Rational polyhedral fan in 2-d lattice N Codomain fan: Rational polyhedral fan in 2-d lattice N """ - return "Fan morphism defined by the matrix\n" "%s\n" "Domain fan: %s\n" "Codomain fan: %s" % (self.matrix(), self.domain_fan(), self.codomain_fan()) + return "Fan morphism defined by the matrix\n%s\nDomain fan: %s\nCodomain fan: %s" % (self.matrix(), self.domain_fan(), self.codomain_fan()) def _subdivide_domain_fan(self, check, verbose): r""" @@ -671,7 +671,7 @@ def _subdivide_domain_fan(self, check, verbose): chambers, cone_to_chamber = self._chambers() if verbose: print("(%.3f ms)" % walltime(start)) - print("Number of domain cones: %d.\n" "Number of chambers: %d." % (domain_fan.n_generating_cones(), len(chambers))) + print("Number of domain cones: %d.\nNumber of chambers: %d." % (domain_fan.n_generating_cones(), len(chambers))) # Subdivide domain_cone. if verbose: start = walltime() @@ -753,7 +753,7 @@ def _support_error(self): into the support of Rational polyhedral fan in 2-d lattice N! """ - raise ValueError("morphism defined by\n" "%s\n" "does not map\n" "%s\n" "into the support of\n" "%s!" % (self.matrix(), self.domain_fan(), self.codomain_fan())) + raise ValueError("morphism defined by\n%s\ndoes not map\n%s\ninto the support of\n%s!" % (self.matrix(), self.domain_fan(), self.codomain_fan())) def _validate(self): r""" @@ -837,7 +837,7 @@ def _validate(self): RISGIS = self._RISGIS() for n, domain_cone in enumerate(domain_fan): if not domain_cone.is_trivial() and not reduce(operator.and_, (RISGIS[i] for i in domain_cone.ambient_ray_indices())): - raise ValueError("the image of generating cone #%d of the " "domain fan is not contained in a single " "cone of the codomain fan!" % n) + raise ValueError("the image of generating cone #%d of the domain fan is not contained in a single cone of the codomain fan!" % n) def codomain_fan(self, dim=None, codim=None): r""" diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py b/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py index c7eb88ce265..d714b1e9557 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py @@ -444,7 +444,7 @@ def image_coordinates(self, x): """ if tuple(x) == (0, 1): return infinity - return -x[0] / (x[1] - 1) + I * (-(sqrt(-x[0] ** 2 - x[1] ** 2 + 1) - x[0] ** 2 - x[1] ** 2 + 1) / ((x[1] - 1) * sqrt(-x[0] ** 2 - x[1] ** 2 + 1) + x[1] - 1)) + return -x[0] / (x[1] - 1) + I * (-(sqrt(-(x[0] ** 2) - x[1] ** 2 + 1) - x[0] ** 2 - x[1] ** 2 + 1) / ((x[1] - 1) * sqrt(-(x[0] ** 2) - x[1] ** 2 + 1) + x[1] - 1)) def image_isometry_matrix(self, x): """ diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py b/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py index 5548a91905f..cc79ce66dfc 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py @@ -270,7 +270,7 @@ def __mul__(self, other): if isinstance(other, HyperbolicGeodesic): return self.codomain().get_geodesic(self(other.start()), self(other.end())) - raise NotImplementedError("multiplication is not defined between a " "hyperbolic isometry and {0}".format(other)) + raise NotImplementedError("multiplication is not defined between a hyperbolic isometry and {0}".format(other)) def _call_(self, p): r""" @@ -782,7 +782,7 @@ def fixed_point_set(self): # UHP tau = M.trace() ** 2 M_cls = self.classification() if M_cls == 'identity': - raise ValueError("the identity transformation fixes the entire " "hyperbolic plane") + raise ValueError("the identity transformation fixes the entire hyperbolic plane") pt = self.domain().get_point if M_cls == 'parabolic': @@ -1069,4 +1069,4 @@ def moebius_transform(A, z): if c * z + d == 0: return infinity return (a * z + b) / (c * z + d) - raise TypeError("A must be an invertible 2x2 matrix over the" " complex numbers or a symbolic ring") + raise TypeError("A must be an invertible 2x2 matrix over the complex numbers or a symbolic ring") diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_model.py b/src/sage/geometry/hyperbolic_space/hyperbolic_model.py index b8237acefe2..66dd8413fb0 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_model.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_model.py @@ -657,7 +657,7 @@ def coords(x): # ...and return their distance return self._dist_points(coords(p), coords(q)) - raise NotImplementedError("can only compute distance between" " ultra-parallel and intersecting geodesics") + raise NotImplementedError("can only compute distance between ultra-parallel and intersecting geodesics") # If only one is a geodesic, make sure it's b to make things easier a, b = b, a diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_point.py b/src/sage/geometry/hyperbolic_space/hyperbolic_point.py index 32a0ec3f267..09645cc4c8d 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_point.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_point.py @@ -326,7 +326,7 @@ def __rmul__(self, other): # and returns an error instead of calling this method A = self.parent().get_isometry(other) return A(self) - raise TypeError("unsupported operand type(s) for *:" "{0} and {1}".format(self, other)) + raise TypeError("unsupported operand type(s) for *:{0} and {1}".format(self, other)) ####################### # Setters and Getters # diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index f4094db9073..e996e3bb8b3 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -299,7 +299,7 @@ def LatticePolytope(data, compute_vertices=True, n=0, lattice=None): raise TypeError("cannot construct a polytope from\n%s" % data) if lattice is None: if not data: - raise ValueError("lattice must be given explicitly for " "empty polytopes!") + raise ValueError("lattice must be given explicitly for empty polytopes!") try: if isinstance(data[0].parent(), ToricLattice_generic): lattice = data[0].parent() @@ -808,7 +808,7 @@ def _contains(self, point, region='whole polytope') -> bool: point = _ambient_space_point(self, point) except TypeError as ex: if str(ex).endswith("have incompatible lattices"): - warn("you have checked if a cone contains a point " "from an incompatible lattice, this is False", stacklevel=3) + warn("you have checked if a cone contains a point from an incompatible lattice, this is False", stacklevel=3) return False if region not in ("whole polytope", "relative interior", "interior"): @@ -2737,7 +2737,7 @@ def nef_partitions(self, keep_symmetric=False, keep_products=True, keep_projecti Polytope: 3-d lattice polytope in 3-d lattice M """ if not self.is_reflexive(): - raise ValueError("the given polytope is not reflexive:\n" f"Polytope: {self}") + raise ValueError(f"the given polytope is not reflexive:\nPolytope: {self}") keys = "-N -V" if keep_symmetric: keys += " -s" @@ -3819,7 +3819,7 @@ def polar(self): """ if self.is_reflexive(): return self._polar - raise ValueError("the given polytope is not reflexive:\n" f"Polytope: {self}") + raise ValueError(f"the given polytope is not reflexive:\nPolytope: {self}") def _mul_(self, other): """ @@ -4273,7 +4273,7 @@ def __init__(self, data, Delta_polar, check=True): sage: TestSuite(np).run() # needs palp """ if check and not Delta_polar.is_reflexive(): - raise ValueError("nef-partitions can be constructed for reflexive " "polytopes only!") + raise ValueError("nef-partitions can be constructed for reflexive polytopes only!") self._vertex_to_part = tuple(int(el) for el in data) self._nparts = max(self._vertex_to_part) + 1 self._Delta_polar = Delta_polar @@ -5319,7 +5319,7 @@ def all_nef_partitions(polytopes, keep_symmetric=False): with open(result_name) as result: for p in polytopes: if not p.is_reflexive(): - raise ValueError("nef-partitions can be computed for reflexive " "polytopes only") + raise ValueError("nef-partitions can be computed for reflexive polytopes only") p._read_nef_partitions(result) p._nef_partitions_s = keep_symmetric os.remove(result_name) diff --git a/src/sage/geometry/newton_polygon.py b/src/sage/geometry/newton_polygon.py index 0f6d06598d9..f44775469bd 100644 --- a/src/sage/geometry/newton_polygon.py +++ b/src/sage/geometry/newton_polygon.py @@ -722,7 +722,7 @@ def _element_constructor_(self, arg, sort_slopes=True, last_slope=Infinity): try: arg = list(arg) except TypeError: - raise TypeError("argument must be a list of coordinates " "or a list of (rational) slopes") + raise TypeError("argument must be a list of coordinates or a list of (rational) slopes") if arg and arg[0] in self.base_ring(): if sort_slopes: arg.sort() @@ -730,7 +730,7 @@ def _element_constructor_(self, arg, sort_slopes=True, last_slope=Infinity): vertices = [(x, y)] for slope in arg: if slope not in self.base_ring(): - raise TypeError("argument must be a list of coordinates " "or a list of (rational) slopes") + raise TypeError("argument must be a list of coordinates or a list of (rational) slopes") x += 1 y += slope vertices.append((x, y)) diff --git a/src/sage/geometry/polyhedron/backend_cdd.py b/src/sage/geometry/polyhedron/backend_cdd.py index 0d2574f1e93..06cf8edf0f2 100644 --- a/src/sage/geometry/polyhedron/backend_cdd.py +++ b/src/sage/geometry/polyhedron/backend_cdd.py @@ -14,7 +14,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from subprocess import Popen, PIPE from sage.rings.integer_ring import ZZ from sage.matrix.constructor import matrix diff --git a/src/sage/geometry/polyhedron/backend_cdd_rdf.py b/src/sage/geometry/polyhedron/backend_cdd_rdf.py index 6dbdb60441c..1261d324a2e 100644 --- a/src/sage/geometry/polyhedron/backend_cdd_rdf.py +++ b/src/sage/geometry/polyhedron/backend_cdd_rdf.py @@ -15,7 +15,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from .backend_cdd import Polyhedron_cdd from .base_RDF import Polyhedron_RDF diff --git a/src/sage/geometry/polyhedron/backend_field.py b/src/sage/geometry/polyhedron/backend_field.py index 0c4e087e94e..9e65e28f882 100644 --- a/src/sage/geometry/polyhedron/backend_field.py +++ b/src/sage/geometry/polyhedron/backend_field.py @@ -31,7 +31,6 @@ # http://www.gnu.org/licenses/ # ***************************************************************************** - from .base import Polyhedron_base diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 0e99783b829..a793849f6b0 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -846,7 +846,7 @@ def barycentric_subdivision(self, subdivision_frac=None): if not self.is_compact(): raise ValueError("the polytope has to be compact") if not (0 < subdivision_frac < ZZ.one() / 2): - raise ValueError("the subdivision fraction should be " "between 0 and 1/2") + raise ValueError("the subdivision fraction should be between 0 and 1/2") barycenter = self.center() parent = self.parent().base_extend(subdivision_frac) @@ -855,13 +855,11 @@ def barycentric_subdivision(self, subdivision_frac=None): polar = (self - barycenter).polar(in_affine_span=True) for i in range(self.dimension() - 1): - new_ineq = [] subdivided_faces = list(start_polar.faces(i)) Hrep = polar.Hrepresentation() for face in subdivided_faces: - face_vertices = face.vertices() normal_vectors = [] diff --git a/src/sage/geometry/polyhedron/base0.py b/src/sage/geometry/polyhedron/base0.py index f2b5be7309e..429b2cc054a 100644 --- a/src/sage/geometry/polyhedron/base0.py +++ b/src/sage/geometry/polyhedron/base0.py @@ -129,7 +129,7 @@ def __init__(self, parent, Vrep, Hrep, Vrep_minimal=None, Hrep_minimal=None, pre Element.__init__(self, parent=parent) if Vrep is not None and Hrep is not None: if not (Vrep_minimal is True and Hrep_minimal is True): - raise ValueError("if both Vrep and Hrep are provided, they must be minimal" " and Vrep_minimal and Hrep_minimal must both be True") + raise ValueError("if both Vrep and Hrep are provided, they must be minimal and Vrep_minimal and Hrep_minimal must both be True") if hasattr(self, "_init_from_Vrepresentation_and_Hrepresentation"): self._init_from_Vrepresentation_and_Hrepresentation(Vrep, Hrep) return diff --git a/src/sage/geometry/polyhedron/base2.py b/src/sage/geometry/polyhedron/base2.py index 5ed3544a087..37c864d2bc5 100644 --- a/src/sage/geometry/polyhedron/base2.py +++ b/src/sage/geometry/polyhedron/base2.py @@ -182,7 +182,7 @@ def lattice_polytope(self, envelope=False): vertices = self.vertices_matrix(ZZ).columns() except TypeError: if not envelope: - raise ValueError('Some vertices are not integral. ' 'You probably want to add the argument ' '"envelope=True" to compute an enveloping lattice polytope.') + raise ValueError('Some vertices are not integral. You probably want to add the argument "envelope=True" to compute an enveloping lattice polytope.') from sage.arith.misc import integer_ceil as ceil from sage.arith.misc import integer_floor as floor diff --git a/src/sage/geometry/polyhedron/base4.py b/src/sage/geometry/polyhedron/base4.py index 280e661e483..b074602956c 100644 --- a/src/sage/geometry/polyhedron/base4.py +++ b/src/sage/geometry/polyhedron/base4.py @@ -252,7 +252,7 @@ def vertex_digraph(self, f, increasing=True): if f.codomain().dimension() == 1: orientation_check = lambda v: f(v) >= 0 else: - raise TypeError('the linear map f must have ' 'one-dimensional codomain') + raise TypeError('the linear map f must have one-dimensional codomain') else: try: if f.is_vector(): diff --git a/src/sage/geometry/polyhedron/base7.py b/src/sage/geometry/polyhedron/base7.py index ddaf5b0af4e..fcc00fa4316 100644 --- a/src/sage/geometry/polyhedron/base7.py +++ b/src/sage/geometry/polyhedron/base7.py @@ -928,7 +928,7 @@ def integrate(self, function, measure='ambient', **kwds): return self.integrate(function, measure='ambient', **kwds) if isinstance(function, str): - raise NotImplementedError('LattE description strings for polynomials not allowed ' 'when using measure="induced"') + raise NotImplementedError('LattE description strings for polynomials not allowed when using measure="induced"') # use an orthogonal transformation affine_hull_data = self.affine_hull_projection(orthogonal=True, return_all_data=True) diff --git a/src/sage/geometry/polyhedron/base_number_field.py b/src/sage/geometry/polyhedron/base_number_field.py index 2650669ce3c..8324d0e12a0 100644 --- a/src/sage/geometry/polyhedron/base_number_field.py +++ b/src/sage/geometry/polyhedron/base_number_field.py @@ -52,7 +52,6 @@ def _number_field_elements_from_algebraics_list_of_lists_of_lists(listss, **kwds class Polyhedron_base_number_field(Polyhedron_base): - def _compute_data_lists_and_internal_base_ring(self, data_lists, convert_QQ, convert_NF): r""" Compute data lists in Normaliz or ``number_field`` backend format and the internal base ring of the data. diff --git a/src/sage/geometry/polyhedron/double_description.py b/src/sage/geometry/polyhedron/double_description.py index fd4488bba51..0a27921d008 100644 --- a/src/sage/geometry/polyhedron/double_description.py +++ b/src/sage/geometry/polyhedron/double_description.py @@ -107,7 +107,6 @@ def random_inequalities(d, n): class DoubleDescriptionPair: - def __init__(self, problem, A_rows, R_cols): r""" Base class for a double description pair `(A, R)`. @@ -513,7 +512,6 @@ def first_coordinate_plane(self): class Problem: - pair_class = DoubleDescriptionPair def __init__(self, A): diff --git a/src/sage/geometry/polyhedron/double_description_inhomogeneous.py b/src/sage/geometry/polyhedron/double_description_inhomogeneous.py index 103a15bdade..cb702fccadb 100644 --- a/src/sage/geometry/polyhedron/double_description_inhomogeneous.py +++ b/src/sage/geometry/polyhedron/double_description_inhomogeneous.py @@ -63,7 +63,6 @@ class PivotedInequalities(SageObject): - def __init__(self, base_ring, dim): """ Base class for inequalities that may contain linear subspaces. @@ -145,7 +144,6 @@ def _unpivot_ray(self, ray): class Hrep2Vrep(PivotedInequalities): - def __init__(self, base_ring, dim, inequalities, equations): """ Convert H-representation to a minimal V-representation. @@ -371,7 +369,6 @@ def verify(self, inequalities, equations): class Vrep2Hrep(PivotedInequalities): - def __init__(self, base_ring, dim, vertices, rays, lines): """ Convert V-representation to a minimal H-representation. diff --git a/src/sage/geometry/polyhedron/generating_function.py b/src/sage/geometry/polyhedron/generating_function.py index e1b30947c1f..914aa9a2ec9 100644 --- a/src/sage/geometry/polyhedron/generating_function.py +++ b/src/sage/geometry/polyhedron/generating_function.py @@ -479,12 +479,12 @@ def generating_function_of_integral_points(polyhedron, split=False, result_as_tu return result if polyhedron.base_ring() not in (ZZ, QQ): - raise TypeError('base ring {} of the polyhedron not ' 'ZZ or QQ'.format(polyhedron.base_ring())) + raise TypeError('base ring {} of the polyhedron not ZZ or QQ'.format(polyhedron.base_ring())) d = polyhedron.ambient_dim() nonnegative_orthant = Polyhedron(ieqs=[dd * (0,) + (1,) + (d - dd) * (0,) for dd in range(1, d + 1)]) if polyhedron & nonnegative_orthant != polyhedron: - raise NotImplementedError('cannot compute the generating function of ' 'polyhedra with negative coordinates') + raise NotImplementedError('cannot compute the generating function of polyhedra with negative coordinates') logger.info('%s', polyhedron) @@ -503,11 +503,11 @@ def generating_function_of_integral_points(polyhedron, split=False, result_as_tu if result_as_tuple: return result if len(result) != 1: - raise ValueError("cannot unpack result " "(set 'result_as_tuple=True')") + raise ValueError("cannot unpack result (set 'result_as_tuple=True')") return result[0] if d <= 1: - raise ValueError('cannot do splitting with only ' 'dimension {}'.format(d)) + raise ValueError('cannot do splitting with only dimension {}'.format(d)) parts = None if split is True: @@ -542,7 +542,7 @@ def ieqs_repr_lhs(pi): logger.info('(%s) split polyhedron by %s', parts_log, pi_log) result.append(_generating_function_of_integral_points_(polyhedron & split_polyhedron, name=name, **kwds)) if not result_as_tuple: - raise ValueError("cannot unpack result" "(unset 'result_as_tuple=False')") + raise ValueError("cannot unpack result(unset 'result_as_tuple=False')") return sum(result, ()) @@ -588,9 +588,9 @@ def _generating_function_of_integral_points_(polyhedron, indices=None, **kwds): n = len(indices) + 1 if any(len(e) != n for e in inequalities): - raise ValueError('not all coefficient vectors of the inequalities ' 'have the same length') + raise ValueError('not all coefficient vectors of the inequalities have the same length') if any(len(e) != n for e in equations): - raise ValueError('not all coefficient vectors of the equations ' 'have the same length') + raise ValueError('not all coefficient vectors of the equations have the same length') mods = _TransformMod.generate_mods(equations) logger.debug('splitting by moduli %s', mods) @@ -1468,7 +1468,7 @@ def generate_mods(equations): pre_mods = _compositions_mod((tuple(ZZ(cc * m) for cc in cols[i]) for i in TEin), m, r=(-cc * m for cc in cols[0]), multidimensional=True) mods = tuple({i - 1: (aa.modulus(), ZZ(aa)) for i, aa in zip(TEin, a) if aa.modulus() > 1} for a in pre_mods) else: - raise TypeError('equations over ZZ or QQ expected, but got ' 'equations over {}.'.format(TE.base_ring())) + raise TypeError('equations over ZZ or QQ expected, but got equations over {}.'.format(TE.base_ring())) return mods diff --git a/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py b/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py index 3786392081f..1828f846725 100644 --- a/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py +++ b/src/sage/geometry/polyhedron/lattice_euclidean_group_element.py @@ -49,7 +49,6 @@ class LatticePolytopeNoEmbeddingError(LatticePolytopeError): ######################################################################## class LatticeEuclideanGroupElement(SageObject): - def __init__(self, A, b): """ An element of the lattice Euclidean group. diff --git a/src/sage/geometry/polyhedron/palp_database.py b/src/sage/geometry/polyhedron/palp_database.py index 7da9e28dbba..7282844d232 100644 --- a/src/sage/geometry/polyhedron/palp_database.py +++ b/src/sage/geometry/polyhedron/palp_database.py @@ -415,7 +415,7 @@ def __init__(self, h11, h21, data_basename=None, **kwds): data_basename = os.path.join(db.absolute_filename(), 'all') info = data_basename + '.vinfo' if not os.path.exists(info): - raise ValueError('Cannot find PALP database: {}. Did you install the ' 'polytopes_db_4d optional spkg?'.format(info)) + raise ValueError('Cannot find PALP database: {}. Did you install the polytopes_db_4d optional spkg?'.format(info)) PALPreader.__init__(self, dim, data_basename=data_basename, **kwds) self._h11 = h11 diff --git a/src/sage/geometry/polyhedron/plot.py b/src/sage/geometry/polyhedron/plot.py index bb997fe4e9c..3bef332541d 100644 --- a/src/sage/geometry/polyhedron/plot.py +++ b/src/sage/geometry/polyhedron/plot.py @@ -234,7 +234,7 @@ def __call__(self, x): img = self.house * x denom = self.psize - img[self.dim - 1] if denom.is_zero(): - raise ValueError('Point cannot coincide with ' 'coordinate singularity at ' + repr(x)) + raise ValueError('Point cannot coincide with coordinate singularity at ' + repr(x)) return vector(RDF, [img[i] / denom for i in range(self.dim - 1)]) @@ -1426,7 +1426,7 @@ def tikz(self, view=[0, 0, 1], angle=0, scale=1, edge_color='blue!95!black', fac return TikzPicture(tikz_string, standalone_config=None, usepackage=None, usetikzlibrary=None, macros=None, use_sage_preamble=False) - raise ValueError("output_type (='{}') must be 'LatexExpr' or" " 'TikzPicture'".format(output_type)) + raise ValueError("output_type (='{}') must be 'LatexExpr' or 'TikzPicture'".format(output_type)) def _tikz_2d(self, scale, edge_color, facet_color, opacity, vertex_color, axis): r""" diff --git a/src/sage/geometry/polyhedron/representation.py b/src/sage/geometry/polyhedron/representation.py index 1533fec8ce6..ed3485a26c9 100644 --- a/src/sage/geometry/polyhedron/representation.py +++ b/src/sage/geometry/polyhedron/representation.py @@ -13,7 +13,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.structure.sage_object import SageObject from sage.structure.element import Vector from sage.structure.richcmp import richcmp_method, richcmp diff --git a/src/sage/geometry/pseudolines.py b/src/sage/geometry/pseudolines.py index 2eec4c65b30..624c869985f 100644 --- a/src/sage/geometry/pseudolines.py +++ b/src/sage/geometry/pseudolines.py @@ -170,7 +170,6 @@ class PseudolineArrangement: - def __init__(self, seq, encoding='auto'): r""" Create an arrangement of pseudolines. @@ -236,7 +235,6 @@ def __init__(self, seq, encoding='auto'): # Sequence of transpositions if encoding == "transpositions" or (encoding == "auto" and len(seq[0]) == 2 and len(seq) > 3): - self._n = max(map(max, seq)) + 1 if (self._n * (self._n - 1)) / 2 != len(seq): raise ValueError("A line is numbered " + str(self._n - 1) + " but the number" + " of transpositions is different from binomial(" + str(self._n - 1) + ",2). Are the lines numbered from 0 to n-1?" + " Are they really non-parallel? Please check the documentation.") @@ -249,7 +247,6 @@ def __init__(self, seq, encoding='auto'): # Sequence of permutations elif encoding == "permutations" or (encoding == "auto" and (len(seq[0]) == len(seq) - 1) and max(seq[0]) > 1): - self._n = len(seq) self._permutations = [list(_) for _ in seq] @@ -258,7 +255,6 @@ def __init__(self, seq, encoding='auto'): # Felsner encoding elif encoding == "Felsner" or (encoding == "auto" and len(seq[0]) == len(seq) - 1): - seq = deepcopy(seq) self._n = len(seq) ordering = list(range(self._n)) @@ -270,7 +266,6 @@ def __init__(self, seq, encoding='auto'): i = 0 while crossings > 0: if seq[i] and (seq[i][0] == 0 and seq[i + 1][0] == 1): - crossings -= 1 self._permutations[ordering[i]].append(ordering[i + 1]) @@ -289,7 +284,6 @@ def __init__(self, seq, encoding='auto'): else: i += 1 else: - if encoding != "auto": raise ValueError("The value of encoding must be one of 'transpositions', 'permutations', 'Felsner' or 'auto'.") @@ -322,7 +316,6 @@ def transpositions(self): crossings = (self._n * (self._n - 1)) / 2 while crossings > 0: - i = 0 while perm[i] == []: diff --git a/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py b/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py index ff2b0682d85..14bad374e97 100644 --- a/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py +++ b/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py @@ -876,7 +876,7 @@ def orthonormal_frame(self, coordinates='ext'): from sage.symbolic.constants import pi if coordinates not in ['ext', 'int']: - raise ValueError("Coordinate system must be exterior ('ext') " "or interior ('int').") + raise ValueError("Coordinate system must be exterior ('ext') or interior ('int').") c = self.first_fundamental_form_coefficient([1, 1]) if coordinates == 'ext': diff --git a/src/sage/geometry/riemannian_manifolds/surface3d_generators.py b/src/sage/geometry/riemannian_manifolds/surface3d_generators.py index 86c133189b9..08a7c9e9a75 100644 --- a/src/sage/geometry/riemannian_manifolds/surface3d_generators.py +++ b/src/sage/geometry/riemannian_manifolds/surface3d_generators.py @@ -13,7 +13,6 @@ # http://www.gnu.org/licenses/ # ***************************************************************************** - from sage.symbolic.constants import pi from sage.functions.log import log from sage.functions.trig import sin, cos, tan diff --git a/src/sage/geometry/toric_lattice.py b/src/sage/geometry/toric_lattice.py index f9dcf397314..781d61f8f00 100644 --- a/src/sage/geometry/toric_lattice.py +++ b/src/sage/geometry/toric_lattice.py @@ -268,7 +268,7 @@ def create_key(self, rank, name=None, dual_name=None, latex_name=None, latex_dua # Should we use standard M and N lattices? if name is None: if dual_name is not None: - raise ValueError("you can name the dual lattice only if you " "also name the original one!") + raise ValueError("you can name the dual lattice only if you also name the original one!") name = "N" dual_name = "M" if latex_name is None: @@ -1071,7 +1071,7 @@ def dual(self): """ if "_dual" not in self.__dict__: if self is not self.saturation(): - raise ValueError("only dual lattices of saturated sublattices " "can be constructed! Got %s." % self) + raise ValueError("only dual lattices of saturated sublattices can be constructed! Got %s." % self) self._dual = self.ambient_module().dual() / self.basis_matrix().transpose().integer_kernel() self._dual._dual = self return self._dual @@ -1541,7 +1541,7 @@ def base_extend(self, R): return self if R is QQ: return self.V().base_extend(R) / self.W().base_extend(R) - raise NotImplementedError("quotients of toric lattices can only be " "extended to ZZ or QQ, not %s!" % R) + raise NotImplementedError("quotients of toric lattices can only be extended to ZZ or QQ, not %s!" % R) def is_torsion_free(self): r""" diff --git a/src/sage/geometry/toric_plotter.py b/src/sage/geometry/toric_plotter.py index 5aa03e20e63..56f890d54a7 100644 --- a/src/sage/geometry/toric_plotter.py +++ b/src/sage/geometry/toric_plotter.py @@ -209,7 +209,7 @@ def __init__(self, all_options, dimension, generators=None): if option not in sd: sd[option] = value if dimension not in [1, 2, 3]: - raise ValueError("toric objects can be plotted only for " "dimensions 1, 2, and 3, not %s!" % dimension) + raise ValueError("toric objects can be plotted only for dimensions 1, 2, and 3, not %s!" % dimension) self.dimension = dimension self.origin = vector(RDF, max(dimension, 2)) # 1-d is plotted in 2-d if self.mode not in ["box", "generators", "round"]: @@ -973,7 +973,7 @@ def options(option=None, **kwds): except KeyError: _unrecognized_option(option) else: - raise ValueError("you cannot specify 'option' and other arguments at " "the same time!") + raise ValueError("you cannot specify 'option' and other arguments at the same time!") def reset_options(): diff --git a/src/sage/geometry/triangulation/point_configuration.py b/src/sage/geometry/triangulation/point_configuration.py index 1d1a059faeb..6a011cd188d 100644 --- a/src/sage/geometry/triangulation/point_configuration.py +++ b/src/sage/geometry/triangulation/point_configuration.py @@ -1352,7 +1352,6 @@ def circuits_support(self): supports_k = [] for k in range(2, self.dim() + 3): - # possibly linear dependent subsets supports_knext = set() possible_dependency = set() diff --git a/src/sage/geometry/voronoi_diagram.py b/src/sage/geometry/voronoi_diagram.py index b46a6caef1d..bcc68491436 100644 --- a/src/sage/geometry/voronoi_diagram.py +++ b/src/sage/geometry/voronoi_diagram.py @@ -108,7 +108,7 @@ def __init__(self, points): self._base_ring = RDF self._points = PointConfiguration([[RDF(cor) for cor in poi] for poi in self._points]) else: - raise NotImplementedError('Base ring of the Voronoi diagram must ' 'be one of QQ, RDF, AA.') + raise NotImplementedError('Base ring of the Voronoi diagram must be one of QQ, RDF, AA.') if self._n > 0: self._d = self._points.ambient_dim() diff --git a/src/sage/graphs/bipartite_graph.py b/src/sage/graphs/bipartite_graph.py index c64e3c31506..a293f745c63 100644 --- a/src/sage/graphs/bipartite_graph.py +++ b/src/sage/graphs/bipartite_graph.py @@ -26,6 +26,7 @@ sage: type(B.copy()) """ + # **************************************************************************** # Copyright (C) 2008 Robert L. Miller # 2018 Julian Rüth @@ -485,7 +486,7 @@ def __init__(self, data=None, partition=None, check=True, hash_labels=None, *arg if check: if any(left.intersection(self.neighbor_iterator(a)) for a in left) or any(right.intersection(self.neighbor_iterator(a)) for a in right): - raise TypeError("input graph is not bipartite with " "respect to the given partition") + raise TypeError("input graph is not bipartite with respect to the given partition") else: for a in left: a_nbrs = left.intersection(self.neighbor_iterator(a)) @@ -502,7 +503,7 @@ def __init__(self, data=None, partition=None, check=True, hash_labels=None, *arg elif isinstance(data, Matrix): # sanity check for mutually exclusive keywords if kwds.get("multiedges", False) and kwds.get("weighted", False): - raise TypeError("weighted multi-edge bipartite graphs from " "reduced adjacency matrix not supported") + raise TypeError("weighted multi-edge bipartite graphs from reduced adjacency matrix not supported") ncols = data.ncols() nrows = data.nrows() self.left = set(range(ncols)) @@ -554,11 +555,11 @@ def edges(): elif data.node_type[v] == "Top": self.right.add(v) else: - raise TypeError("NetworkX node_type defies bipartite " "assumption (is not 'Top' or 'Bottom')") + raise TypeError("NetworkX node_type defies bipartite assumption (is not 'Top' or 'Bottom')") elif partition: if check: if any(left.intersection(self.neighbor_iterator(a)) for a in left) or any(right.intersection(self.neighbor_iterator(a)) for a in right): - raise TypeError("input graph is not bipartite with " "respect to the given partition") + raise TypeError("input graph is not bipartite with respect to the given partition") else: for a in left: a_nbrs = left.intersection(data.neighbor_iterator(a)) @@ -629,7 +630,7 @@ def __hash__(self): edge_items = Counter(edge_items).items() return hash((frozenset(self.left), frozenset(self.right), frozenset(edge_items))) - raise TypeError("This graph is mutable, and thus not hashable. " "Create an immutable copy by `g.copy(immutable=True)`") + raise TypeError("This graph is mutable, and thus not hashable. Create an immutable copy by `g.copy(immutable=True)`") def _upgrade_from_graph(self): """ @@ -1086,7 +1087,6 @@ def add_edge(self, u, v=None, label=None): # if endpoints are in the same partition if self.left.issuperset((u, v)) or self.right.issuperset((u, v)): - # get v's connected component v_connected_component = self.connected_component_containing_vertex(v, sort=False) @@ -1189,7 +1189,7 @@ def add_edges(self, edges, loops=True): vertex_in_left = self._check_bipartition_for_add_edges(edges_to_add) if vertex_in_left is False: - raise ValueError("the specified set of edges cannot be added while " "still preserving the bipartition property") + raise ValueError("the specified set of edges cannot be added while still preserving the bipartition property") # If we get here, then we've found a valid bipartition. # We update the bipartition @@ -2231,7 +2231,7 @@ class :class:`MixedIntegerLinearProgram if algorithm == "Hopcroft-Karp" or algorithm == "Eppstein": if use_edge_labels: - raise ValueError('use_edge_labels cannot be used with ' '"Hopcroft-Karp" or "Eppstein"') + raise ValueError('use_edge_labels cannot be used with "Hopcroft-Karp" or "Eppstein"') d = [] if self.size(): import networkx @@ -2257,7 +2257,7 @@ class :class:`MixedIntegerLinearProgram if algorithm == "Edmonds" or algorithm == "LP": return Graph.matching(self, value_only=value_only, algorithm=algorithm, use_edge_labels=use_edge_labels, solver=solver, verbose=verbose, integrality_tolerance=integrality_tolerance) - raise ValueError('algorithm must be "Hopcroft-Karp", ' '"Eppstein", "Edmonds" or "LP"') + raise ValueError('algorithm must be "Hopcroft-Karp", "Eppstein", "Edmonds" or "LP"') def vertex_cover(self, algorithm='Konig', value_only=False, reduction_rules=True, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index 597dce686f7..b2c0aaa254d 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -650,7 +650,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, weighted=None, if sparse is False: if data_structure != "sparse": - raise ValueError("the 'sparse' argument is an alias for " "'data_structure', please do not define both") + raise ValueError("the 'sparse' argument is an alias for 'data_structure', please do not define both") data_structure = "dense" if multiedges or weighted: @@ -671,7 +671,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, weighted=None, elif data_structure == "dense": CGB = DenseGraphBackend else: - raise ValueError("data_structure must be equal to 'sparse', " "'static_sparse' or 'dense'") + raise ValueError("data_structure must be equal to 'sparse', 'static_sparse' or 'dense'") self._backend = CGB(0, directed=True) if format is None and isinstance(data, str): @@ -714,7 +714,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, weighted=None, try: import igraph except ImportError: - raise ImportError("the data seems to be a igraph object, but " "igraph is not installed in Sage. To install " "it, run 'sage -i python_igraph'") + raise ImportError("the data seems to be a igraph object, but igraph is not installed in Sage. To install it, run 'sage -i python_igraph'") if format is None and isinstance(data, igraph.Graph): format = 'igraph' if format is None and isinstance(data, (int, Integer)): @@ -772,7 +772,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, weighted=None, elif not multiedges: e = data.edges(labels=False, sort=False) if len(e) != len(set(e)): - raise ValueError("no multiple edges but input digraph" " has multiple edges") + raise ValueError("no multiple edges but input digraph has multiple edges") self.allow_multiple_edges(multiedges, check=False) self.allow_loops(loops, check=False) if weighted is None: @@ -818,7 +818,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, weighted=None, elif format == 'igraph': if not data.is_directed(): - raise ValueError("a *directed* igraph graph was expected. To " "build an undirected graph, call the Graph " "constructor") + raise ValueError("a *directed* igraph graph was expected. To build an undirected graph, call the Graph constructor") self.add_vertices(range(data.vcount())) self.add_edges((e.source, e.target, e.attributes()) for e in data.es()) @@ -1058,7 +1058,7 @@ def to_undirected(self, data_structure=None, sparse=None): """ if sparse is not None: if data_structure is not None: - raise ValueError("the 'sparse' argument is an alias for " "'data_structure'. Please do not define both") + raise ValueError("the 'sparse' argument is an alias for 'data_structure'. Please do not define both") data_structure = "sparse" if sparse else "dense" if data_structure is None: @@ -1694,7 +1694,6 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, solver # Constraint Generation Implementation # ######################################## if constraint_generation: - p = MixedIntegerLinearProgram(constraint_generation=True, maximization=False, solver=solver) # A variable for each edge @@ -1707,7 +1706,6 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, solver # For as long as we do not break because the digraph is acyclic.... while True: - # Building the graph without the edges removed by the MILP p.solve(log=verbose) val = p.get_values(b, convert=bool, tolerance=integrality_tolerance) @@ -1726,7 +1724,6 @@ def feedback_edge_set(self, constraint_generation=True, value_only=False, solver # There is a circuit left. Let's add the corresponding # constraint ! while not isok: - if verbose: print("Adding a constraint on circuit : {}".format(certificate)) @@ -2046,7 +2043,7 @@ def reverse_edge(self, u, v=None, label=None, inplace=True, multiedges=None): # User is supposed to specify multiedges True or False else: - raise ValueError("reversing the given edge is about to " "create two parallel edges but input digraph " "doesn't allow them - User needs to specify " "multiedges is True or False.") + raise ValueError("reversing the given edge is about to create two parallel edges but input digraph doesn't allow them - User needs to specify multiedges is True or False.") else: tempG.delete_edge(u, v, label) tempG.add_edge(v, u, label) diff --git a/src/sage/graphs/digraph_generators.py b/src/sage/graphs/digraph_generators.py index ebfbba187b3..31c28aa4827 100644 --- a/src/sage/graphs/digraph_generators.py +++ b/src/sage/graphs/digraph_generators.py @@ -638,7 +638,6 @@ def tournaments_nauty(self, n, min_out_degree=None, max_out_degree=None, strongl gentourng_path = NautyExecutable("gentourng").absolute_filename() with subprocess.Popen(shlex.quote(gentourng_path) + " {0}".format(nauty_input), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) as sp: - if debug: yield sp.stderr.readline() @@ -1676,7 +1675,7 @@ def RandomDirectedGNM(self, n, m, loops=False, immutable=False): m = n * (n - 1) - m if not good_input: - raise ValueError("the number of edges must satisfy 0 <= m <= n(n-1) " "when no loops are allowed, and 0 <= m <= n^2 otherwise") + raise ValueError("the number of edges must satisfy 0 <= m <= n(n-1) when no loops are allowed, and 0 <= m <= n^2 otherwise") # When the given number of edges defines a density larger than 1/2, it # should be faster to compute the complement of the graph (less edges to @@ -1696,7 +1695,6 @@ def RandomDirectedGNM(self, n, m, loops=False, immutable=False): rand = _pyrand() while m > 0: - # It is better to obtain random numbers this way than by calling the # randint or randrange method. This, because they are very expensive # when trying to compute MANY random integers, and because the @@ -1922,7 +1920,6 @@ def extra_property(x): yield gg.copy(immutable=immutable) if copy or immutable else gg elif augment == 'edges': - if vertices is None: vertices = 0 while True: diff --git a/src/sage/graphs/domination.py b/src/sage/graphs/domination.py index 4616d84c886..94c724befea 100644 --- a/src/sage/graphs/domination.py +++ b/src/sage/graphs/domination.py @@ -759,7 +759,6 @@ def _aux_with_rep(H, to_dom, u_next): # When u_next is not in the DS, one of its neighbors w should be: for w in H.neighbor_iterator(u_next): - remains_to_dom = set(to_dom) remains_to_dom.difference_update(H.neighbor_iterator(w, closed=True)) # Here again we recurse on a smaller instance at it @@ -1019,7 +1018,6 @@ def tree_search(H, plng, dom, i): to_dom = V_next - set().union(*(G.neighbor_iterator(vert, closed=True) for vert in dom)) for can_ext in _cand_ext_enum(H, to_dom, u_next): - # We complete dom with can_ext -> canD canD = set().union(can_ext, dom) diff --git a/src/sage/graphs/generators/classical_geometries.py b/src/sage/graphs/generators/classical_geometries.py index 99771097e56..63970eed4e1 100644 --- a/src/sage/graphs/generators/classical_geometries.py +++ b/src/sage/graphs/generators/classical_geometries.py @@ -7,6 +7,7 @@ The methods defined here appear in :mod:`sage.graphs.graph_generators`. """ + # **************************************************************************** # Copyright (C) 2015 Sagemath project # @@ -288,10 +289,10 @@ def _orthogonal_polar_graph(m, q, sign='+', point_type=[0], immutable=False, nam if not m % 2: if sign != "+" and sign != "-": - raise ValueError("sign must be equal to either '-' or '+' when " "m is even") + raise ValueError("sign must be equal to either '-' or '+' when m is even") else: if sign != "" and sign != "+": - raise ValueError("sign must be equal to either '' or '+' when " "m is odd") + raise ValueError("sign must be equal to either '' or '+' when m is odd") sign = "" e = {'+': 1, '-': -1, '': 0}[sign] diff --git a/src/sage/graphs/generators/degree_sequence.py b/src/sage/graphs/generators/degree_sequence.py index 19862fa0ab4..1c8591d3157 100644 --- a/src/sage/graphs/generators/degree_sequence.py +++ b/src/sage/graphs/generators/degree_sequence.py @@ -128,7 +128,7 @@ def DegreeSequenceBipartite(s1, s2, immutable=False): m = gale_ryser_theorem(s1, s2) if m is False: - raise ValueError("there exists no bipartite graph corresponding to " "the given degree sequences") + raise ValueError("there exists no bipartite graph corresponding to the given degree sequences") return Graph(BipartiteGraph(m), immutable=immutable) diff --git a/src/sage/graphs/generators/families.py b/src/sage/graphs/generators/families.py index ee2e81c38f5..25095e95514 100644 --- a/src/sage/graphs/generators/families.py +++ b/src/sage/graphs/generators/families.py @@ -2239,7 +2239,7 @@ def HyperStarGraph(n, k, immutable=False): - Michael Yurko (2009-09-01) """ if n < 0 or k < 0 or k > n: - raise ValueError("parameters n and k must be nonnegative integers " "satisfying n >= k >= 0") + raise ValueError("parameters n and k must be nonnegative integers satisfying n >= k >= 0") if not n: adj = {} elif not k: diff --git a/src/sage/graphs/generators/intersection.py b/src/sage/graphs/generators/intersection.py index e1d97a7df53..655311f78f2 100644 --- a/src/sage/graphs/generators/intersection.py +++ b/src/sage/graphs/generators/intersection.py @@ -268,7 +268,7 @@ def PermutationGraph(second_permutation, first_permutation=None, immutable=False first_permutation = sorted(second_permutation) else: if set(second_permutation) != set(first_permutation): - raise ValueError("The two permutations do not contain the same " "set of elements ! It is going to be pretty " "hard to define a permutation graph from that !") + raise ValueError("The two permutations do not contain the same set of elements ! It is going to be pretty hard to define a permutation graph from that !") vertex_to_index = {} for i, v in enumerate(first_permutation): @@ -365,7 +365,7 @@ def ToleranceGraph(tolrep, immutable=False, name=None): for i in range(n): if tolrep[i][2] <= 0: - raise ValueError("Invalid tolerance representation at position " "{}; third value must be > 0".format(i)) + raise ValueError("Invalid tolerance representation at position {}; third value must be > 0".format(i)) def edges(): for i in range(n): diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index ab55641bd88..98c78073c74 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -2209,7 +2209,7 @@ def RandomTriangulation(n, set_position=False, k=3, seed=None, immutable=False): if k < 3: raise ValueError("The size 'k' of the outer face must be at least 3.") if n < k: - raise ValueError("The number 'n' of vertices must be at least the size " "'k' of the outer face.") + raise ValueError("The number 'n' of vertices must be at least the size 'k' of the outer face.") if seed is not None: set_random_seed(seed) diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index 96198799dcb..209cc44d288 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -59,7 +59,7 @@ def HarborthGraph(immutable=False): sage: g.is_isomorphic(h) True """ - g = Graph(':s_OGKI?@_?g[QABAo__YEFCp@?iIEbqHWuWLbbh?}[OfcXpGhNHdYPY_SgdYX]' 'pZkfJPuo[lfZHys^mFcDs}`pG{UNNgoHC}DIgrI[qjMhTyDQrQlVydrBYmWkn', loops=False, multiedges=False, immutable=immutable, name="Harborth Graph") + g = Graph(':s_OGKI?@_?g[QABAo__YEFCp@?iIEbqHWuWLbbh?}[OfcXpGhNHdYPY_SgdYX]pZkfJPuo[lfZHys^mFcDs}`pG{UNNgoHC}DIgrI[qjMhTyDQrQlVydrBYmWkn', loops=False, multiedges=False, immutable=immutable, name="Harborth Graph") g.set_pos( { @@ -2274,7 +2274,6 @@ def BiggsSmithGraph(embedding=1, immutable=False): g = LCFGraph(102, L, 1, immutable=immutable, name="Biggs-Smith graph") if embedding == 1: - orbs = [ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0], [17, 101, 25, 66, 20, 38, 53, 89, 48, 75, 56, 92, 45, 78, 34, 28, 63], @@ -2875,7 +2874,7 @@ def GossetGraph(immutable=False): sage: g.is_isomorphic(h) True """ - string = 'w~~~~rt{~Z\\ZxnvYZYmlfrb}|hDuhLlcmmMNf_^zzQGNYcP\\kcRZbaJjoNBx{' '?N~o^}?A`}F_Kbbm_[QZ\\_]Cj\\oN_dm{BzB{?]WIMM@tPQRYBYRPIuAyJgQv?' '|Bxb_M[kWIR@jTQcciDjShXCkFMgpwqBKxeKoS`TYqdTCcKtkdKwWQXrbEZ@OdU' 'mITZ@_e[{KXn?YPABzvY?IcO`zvYg@caC\\zlf?BaGR]zb{?@wOjv`~w??N_n_~' '~w???^_^~~{' + string = 'w~~~~rt{~Z\\ZxnvYZYmlfrb}|hDuhLlcmmMNf_^zzQGNYcP\\kcRZbaJjoNBx{?N~o^}?A`}F_Kbbm_[QZ\\_]Cj\\oN_dm{BzB{?]WIMM@tPQRYBYRPIuAyJgQv?|Bxb_M[kWIR@jTQcciDjShXCkFMgpwqBKxeKoS`TYqdTCcKtkdKwWQXrbEZ@OdUmITZ@_e[{KXn?YPABzvY?IcO`zvYg@caC\\zlf?BaGR]zb{?@wOjv`~w??N_n_~~w???^_^~~{' G = Graph(string, name="Gosset Graph", immutable=immutable) @@ -5267,7 +5266,7 @@ def Klein3RegularGraph(immutable=False): sage: g.chromatic_number() 3 """ - g3 = Graph(':w`_GKWDBap`CMWFCpWsQUNdBwwuXPHrg`U`RIqypehVLqgHupYcFJyAv^Prk]' 'EcarHwIVHAKh|\\tLVUxT]`ZDTJ{Af[o_AuKs{r_?ef', loops=False, multiedges=False, immutable=immutable, name="Klein 3-regular Graph") + g3 = Graph(':w`_GKWDBap`CMWFCpWsQUNdBwwuXPHrg`U`RIqypehVLqgHupYcFJyAv^Prk]EcarHwIVHAKh|\\tLVUxT]`ZDTJ{Af[o_AuKs{r_?ef', loops=False, multiedges=False, immutable=immutable, name="Klein 3-regular Graph") g3._circle_embedding([0, 2, 3, 4, 6, 8, 14, 1, 37, 30, 34, 48, 55, 43, 40, 45, 18, 20, 47, 42, 23, 17, 16, 10, 41, 11, 49, 25, 51, 26, 54, 9, 22, 15, 21, 12, 24, 7, 52, 31, 32, 36, 46, 35, 29, 50, 27, 19, 28, 5, 33, 13, 53, 39, 38, 44]) return g3 @@ -5299,7 +5298,7 @@ def Klein7RegularGraph(immutable=False): sage: g.chromatic_number() 4 """ - g7 = Graph(':W__@`AaBbC_CDbDcE`F_AG_@DEH_IgHIJbFGIKaFHILeFGHMdFKN_EKOPaCNP' 'Q`HOQRcGLRS`BKMSTdJKLPTU', loops=False, multiedges=False, name="Klein 7-regular Graph", immutable=immutable) + g7 = Graph(':W__@`AaBbC_CDbDcE`F_AG_@DEH_IgHIJbFGIKaFHILeFGHMdFKN_EKOPaCNPQ`HOQRcGLRS`BKMSTdJKLPTU', loops=False, multiedges=False, name="Klein 7-regular Graph", immutable=immutable) g7._circle_embedding([0, 2, 3, 1, 9, 16, 20, 21, 4, 19, 17, 7, 15, 10, 8, 13, 11, 5, 23, 22, 14, 12, 18, 6]) return g7 @@ -5586,7 +5585,6 @@ def McGeeGraph(embedding=2, immutable=False): return g if embedding == 2: - o = [[7, 2, 13, 8, 19, 14, 1, 20], [5, 4, 11, 10, 17, 16, 23, 22], [3, 12, 9, 18, 15, 0, 21, 6]] g._circle_embedding(o[0], radius=1.5) @@ -6838,7 +6836,6 @@ def TwinplexGraph(embedding='LM', immutable=False): from math import pi if embedding == 'FL': - E1 = ((i, i + 1) for i in range(11)) E2 = ((0, 11),) E3 = ((0, 8), (1, 5), (2, 9), (3, 7), (4, 11), (6, 10)) @@ -6879,7 +6876,7 @@ def TwinplexGraph(embedding='LM', immutable=False): G = Graph([range(12), edges], format="vertices_and_edges", pos=pos_dict, name='Twinplex Graph', immutable=immutable) else: - raise ValueError("parameter 'embedding' must be 'FL', 'NT'," " 'LM' or 'RST'") + raise ValueError("parameter 'embedding' must be 'FL', 'NT', 'LM' or 'RST'") return G diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 30ef58a5b93..7af1312f54a 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -757,7 +757,7 @@ def __hash__(self): edge_items = Counter(edge_items).items() return hash((frozenset(self.vertex_iterator()), self._weighted, frozenset(edge_items))) - raise TypeError("This graph is mutable, and thus not hashable. " "Create an immutable copy by `g.copy(immutable=True)`") + raise TypeError("This graph is mutable, and thus not hashable. Create an immutable copy by `g.copy(immutable=True)`") def __mul__(self, n): r""" @@ -1503,7 +1503,7 @@ def copy(self, weighted=None, data_structure=None, sparse=None, immutable=None, # data_structure is already defined so there is nothing left to do # here ! Did the user try to define too much ? if immutable is not None or sparse is not None: - raise ValueError("you cannot define 'immutable' or 'sparse' " "when 'data_structure' has a value") + raise ValueError("you cannot define 'immutable' or 'sparse' when 'data_structure' has a value") # At this point : # - data_structure is None. elif immutable is True: @@ -1726,7 +1726,7 @@ def _scream_if_not_simple(self, allow_loops=False, allow_multiple_edges=False): elif pb_with_multiple_edges: name = "multiedges" functions = "allow_multiple_edges()" - msg = "This method is not known to work on graphs with " + name + ". " "Perhaps this method can be updated to handle them, but in the " + "meantime if you want to use it please disallow " + name + " using " + functions + "." + msg = "This method is not known to work on graphs with " + name + ". Perhaps this method can be updated to handle them, but in the " + "meantime if you want to use it please disallow " + name + " using " + functions + "." raise ValueError(msg) def _scream_if_immutable(self, message=None): @@ -2221,7 +2221,7 @@ def _vertex_indices_and_keys(self, vertices=None, *, sort=None): try: vertices = self.vertices(sort=sort if sort is not None else True) except TypeError: - raise TypeError("Vertex labels are not comparable. You must " "specify an ordering using parameter 'vertices'") + raise TypeError("Vertex labels are not comparable. You must specify an ordering using parameter 'vertices'") elif len(vertices) != n or set(vertices) != set(self.vertex_iterator()): raise ValueError("parameter 'vertices' must be a permutation of the vertices") return {v: i for i, v in enumerate(vertices)}, keys @@ -2972,7 +2972,7 @@ def weighted_adjacency_matrix(self, sparse=True, vertices=None, default_weight=N def func(u, v, label): if label is None: - raise ValueError(f"cannot find the weight of ({u}, {v}, None). " "Consider setting parameter 'default_weight'") + raise ValueError(f"cannot find the weight of ({u}, {v}, None). Consider setting parameter 'default_weight'") return label else: @@ -3425,9 +3425,9 @@ def _check_embedding_validity(self, embedding=None, boolean=True): if boolean: return False if set(embedding).difference(self): - raise ValueError("vertices in {} from the embedding do not " "belong to the graph".format(list(set(embedding).difference(self)))) + raise ValueError("vertices in {} from the embedding do not belong to the graph".format(list(set(embedding).difference(self)))) else: - raise ValueError("vertices in {} have no corresponding entry " "in the embedding".format(list(set(self).difference(embedding)))) + raise ValueError("vertices in {} have no corresponding entry in the embedding".format(list(set(self).difference(embedding)))) if self._directed: @@ -3440,16 +3440,16 @@ def connected(u, v): if len(embedding[v]) != self.degree(v): if boolean: return False - raise ValueError("the list associated with vertex {} has " "length {} but d({})={}".format(v, len(embedding[v]), v, self.degree(v))) + raise ValueError("the list associated with vertex {} has length {} but d({})={}".format(v, len(embedding[v]), v, self.degree(v))) if len(embedding[v]) != len(set(embedding[v])): if boolean: return False - raise ValueError("the list associated with vertex {} contains >1 " "occurrences of {}".format(v, [x for x in set(embedding[v]) if embedding[v].count(x) > 1])) + raise ValueError("the list associated with vertex {} contains >1 occurrences of {}".format(v, [x for x in set(embedding[v]) if embedding[v].count(x) > 1])) for u in embedding[v]: if not connected(v, u): if boolean: return False - raise ValueError("{} and {} are not neighbors but {} is in " "the list associated with {}".format(u, v, u, v)) + raise ValueError("{} and {} are not neighbors but {} is in the list associated with {}".format(u, v, u, v)) return True def has_loops(self) -> bool: @@ -4600,13 +4600,10 @@ def is_bipartite(self, certificate=False): v = queue.pop(0) c = 1 - color[v] for w in self.neighbor_iterator(v): - # If the vertex has already been colored if w in color: - # The graph is not bipartite ! if color[w] == color[v]: - # Should we return an odd cycle ? if certificate: w_to_root = [] @@ -6128,7 +6125,6 @@ def is_circular_planar(self, on_embedding=None, kuratowski=False, set_embedding= # When ordered is True, we need a way to make sure that the ordering is # respected. if ordered: - # We add edges between consecutive vertices of the boundary (only # len(boundary)-1 are actually sufficient) for u, v in zip(boundary[:-1], boundary[1:]): @@ -6341,7 +6337,7 @@ def layout_planar(self, set_embedding=False, on_embedding=None, external_face=No if not self.is_connected(): if external_face: - raise NotImplementedError('cannot fix the external face for a' 'disconnected graph') + raise NotImplementedError('cannot fix the external face for adisconnected graph') # Compute the layout component by component pos = layout_split(G.__class__.layout_planar, G, set_embedding=set_embedding, on_embedding=on_embedding, external_face=None, test=test, **options) if set_embedding: @@ -6362,21 +6358,21 @@ def layout_planar(self, set_embedding=False, on_embedding=None, external_face=No elif on_embedding is not None: G._check_embedding_validity(on_embedding, boolean=False) if not G.is_planar(on_embedding=on_embedding): - raise ValueError('provided embedding is not a planar ' 'embedding for %s' % self) + raise ValueError('provided embedding is not a planar embedding for %s' % self) G.set_embedding(on_embedding) elif hasattr(G, '_embedding'): if G._check_embedding_validity(): if not G.is_planar(on_embedding=G._embedding): - raise ValueError('%s has nonplanar _embedding attribute. ' 'Try putting set_embedding=True' % self) + raise ValueError('%s has nonplanar _embedding attribute. Try putting set_embedding=True' % self) embedding_copy = {v: neighbors[:] for v, neighbors in G._embedding.items()} else: - raise ValueError('provided embedding is not a valid ' 'embedding for %s. Try putting ' 'set_embedding=True' % self) + raise ValueError('provided embedding is not a valid embedding for %s. Try putting set_embedding=True' % self) elif not G.is_planar(set_embedding=True): raise ValueError('%s is not a planar graph' % self) if external_face: if not self.has_edge(external_face): - raise ValueError('{} is not an edge of {} but has been ' 'provided as an edge of the external face' ''.format(external_face, self)) + raise ValueError('{} is not an edge of {} but has been provided as an edge of the external face'.format(external_face, self)) _triangulate(G, G._embedding) @@ -6384,7 +6380,7 @@ def layout_planar(self, set_embedding=False, on_embedding=None, external_face=No if test: if G._check_embedding_validity(): if not G.is_planar(on_embedding=G._embedding): - raise ValueError('%s has nonplanar _embedding attribute. ' 'Try putting set_embedding=True' % self) + raise ValueError('%s has nonplanar _embedding attribute. Try putting set_embedding=True' % self) test_faces = G.faces(G._embedding) for face in test_faces: if len(face) != 3: @@ -7215,7 +7211,7 @@ def steiner_tree(self, vertices, weighted=False, solver=None, verbose=0, *, inte if any(v not in cc for v in vertices): from sage.categories.sets_cat import EmptySetError - raise EmptySetError("the given vertices do not all belong to the " "same connected component. This problem has " "no solution !") + raise EmptySetError("the given vertices do not all belong to the same connected component. This problem has no solution !") # Can it be solved using the min spanning tree algorithm ? if not weighted: @@ -7452,7 +7448,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None return edge_disjoint_spanning_trees(self, k) elif algorithm != "MILP": - raise ValueError('algorithm must be None, "Rosking-Tarjan" or "MILP" ' 'for undirected graphs') + raise ValueError('algorithm must be None, "Rosking-Tarjan" or "MILP" for undirected graphs') G = self n = G.order() @@ -7466,7 +7462,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None if k == 1: E = G.min_spanning_tree(starting_vertex=root) if not E: - raise EmptySetError("this graph does not contain the required " "number of trees/arborescences") + raise EmptySetError("this graph does not contain the required number of trees/arborescences") return [DiGraph(E) if G.is_directed() else Graph(E)] D = G if G.is_directed() else DiGraph(G) @@ -7772,7 +7768,6 @@ def good_edge(e): p.add_constraint(v[t], min=1, max=1) if g.is_directed(): - # we minimize the number of edges p.set_objective(p.sum(weight(w) * b[good_edge((x, y))] for x, y, w in g.edge_iterator())) @@ -8814,7 +8809,7 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm='MILP', raise ValueError("algorithm must be either 'heuristic' or 'MILP'") if algorithm == 'heuristic': if s is not None or t is not None or use_edge_labels: - raise ValueError("parameters s, t, and use_edge_labels can not " "be used in combination with algorithm 'heuristic'") + raise ValueError("parameters s, t, and use_edge_labels can not be used in combination with algorithm 'heuristic'") if immutable is None: immutable = self.is_immutable() @@ -8891,7 +8886,6 @@ def weight(x): vertex_used = p.new_variable(binary=True) if self._directed: - # if edge uv is used, vu cannot be for u, v in self.edge_iterator(labels=False): if self.has_edge(v, u): @@ -9570,13 +9564,11 @@ def weight(label): #################################################### if constraint_generation: - p = MixedIntegerLinearProgram(maximization=maximize, solver=solver, constraint_generation=True) # Directed Case # ################# if g.is_directed(): - from sage.graphs.digraph import DiGraph b = p.new_variable(binary=True) @@ -9623,7 +9615,6 @@ def weight(label): # Undirected Case # ################### else: - from sage.graphs.graph import Graph b = p.new_variable(binary=True) @@ -10023,7 +10014,7 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, constrai 1 """ if not constraint_generation and not self.is_directed(): - raise ValueError("the only implementation available for " "undirected graphs is with constraint_generation " "set to True") + raise ValueError("the only implementation available for undirected graphs is with constraint_generation set to True") # It would be a pity to start a LP if the graph is already acyclic if (not self.is_directed() and self.is_forest()) or (self.is_directed() and self.is_directed_acyclic()): @@ -10037,7 +10028,6 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, constrai # Constraint Generation Implementation # ######################################## if constraint_generation: - p = MixedIntegerLinearProgram(constraint_generation=True, maximization=False, solver=solver) # A variable for each vertex @@ -10048,7 +10038,6 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, constrai # For as long as we do not break because the digraph is acyclic.... while True: - p.solve(log=verbose) # Building the graph without the vertices removed by the LP @@ -10070,7 +10059,6 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, constrai # There is a circuit left. Let's add the corresponding # constraint ! while not isok: - p.add_constraint(p.sum(b[v] for v in certificate), min=1) if verbose: print("Adding a constraint on circuit: ", certificate) @@ -10083,7 +10071,6 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, constrai isok, certificate = h.is_forest(certificate=True) else: - ###################################### # Ordering-based MILP Implementation # ###################################### @@ -10275,7 +10262,7 @@ def flow(self, x, y, value_only=True, integer=False, use_edge_labels=True, verte """ self._scream_if_not_simple(allow_loops=True) if vertex_bound and algorithm in ["FF", "igraph"]: - raise ValueError("this method does not support both " "vertex_bound=True and algorithm='" + algorithm + "'") + raise ValueError("this method does not support both vertex_bound=True and algorithm='" + algorithm + "'") if use_edge_labels: from sage.rings.real_mpfr import RR @@ -10341,7 +10328,7 @@ def capacity(z): return [maxflow.value, flow_digraph] if algorithm != "LP": - raise ValueError("the algorithm argument has to be equal to either " "\"FF\", \"LP\", \"igraph\", or None") + raise ValueError("the algorithm argument has to be equal to either \"FF\", \"LP\", \"igraph\", or None") from sage.numerical.mip import MixedIntegerLinearProgram @@ -10769,7 +10756,6 @@ def path_to_labelled_edges(P): flow_intensity = 0 while True: - # If there is a shortest path from s to t path = residual.shortest_path(s, t) if not path: @@ -10786,7 +10772,6 @@ def path_to_labelled_edges(P): # Updating variables for uu, vv, ll in edges: - # The flow on the back arc other = flow[vv, uu] flow[uu, vv] = flow[uu, vv] + max(0, epsilon - other) @@ -10964,14 +10949,11 @@ def capacity_sum(i, u, v): p.add_constraint(p.sum(capacity_sum(i, u, v) for i in range(len(terminals))), max=capacity(w)) if vertex_bound: - # Any vertex for v in g: - # which is an endpoint if v in set_terminals: for i, (s, t, _) in enumerate(terminals): - # only tolerates the commodities of which it is an endpoint if not (v == s or v == t): p.add_constraint(flow_leaving(i, v), max=0) @@ -13153,7 +13135,7 @@ def set_edge_label(self, u, v, l): """ if self.allows_multiple_edges(): if len(self.edge_label(u, v)) > 1: - raise RuntimeError("cannot set edge label, since there are " "multiple edges from %s to %s" % (u, v)) + raise RuntimeError("cannot set edge label, since there are multiple edges from %s to %s" % (u, v)) self._backend.set_edge_label(u, v, l, self._directed) def has_edge(self, u, v=None, label=None) -> bool: @@ -15260,14 +15242,12 @@ def is_chordal(self, certificate=False, algorithm='B'): # If the graph is not connected, we are computing the result on each # component if not self.is_connected(): - # If the user wants a certificate, we had no choice but to collect # the perfect elimination orders... But we return a hole immediately # if we find any ! if certificate: peo = [] for gg in self.connected_components_subgraphs(): - b, certif = gg.is_chordal(certificate=True) if not b: return False, certif @@ -15286,13 +15266,11 @@ def is_chordal(self, certificate=False, algorithm='B'): # They find the perfect elimination ordering or produce a hole if algorithm == "A": - peo, t_peo = self.lex_BFS(tree=True) peo.reverse() # Iteratively removing vertices and checking everything is fine. for v in peo: - if not t_peo.out_degree(v): g.delete_vertex(v) continue @@ -15301,10 +15279,8 @@ def is_chordal(self, certificate=False, algorithm='B'): S = self.neighbors(x, closed=True) if not frozenset(g.neighbor_iterator(v)).issubset(S): - # Do we need to return a hole ? if certificate: - # In this case, let us take two nonadjacent neighbors of # v. In order to do so, we pick a vertex y which is a # neighbor of v but is not adjacent to x, which we know @@ -15330,7 +15306,6 @@ def is_chordal(self, certificate=False, algorithm='B'): g.delete_vertex(v) elif algorithm == "B": - peo, t_peo = self.lex_BFS(reverse=True, tree=True) # Remembering the (closed) neighborhoods of each vertex @@ -15339,12 +15314,9 @@ def is_chordal(self, certificate=False, algorithm='B'): # Iteratively removing vertices and checking everything is fine. for v in reversed(peo): - if t_peo.out_degree(v) and not frozenset(v1 for v1 in g.neighbor_iterator(v) if pos_in_peo[v1] > pos_in_peo[v]).issubset(neighbors_subsets[next(t_peo.neighbor_out_iterator(v))]): - # Do we need to return a hole ? if certificate: - # In this case, let us take two nonadjacent neighbors of # v. In order to do so, we pick a vertex y which is a # neighbor of v but is not adjacent to x, which we know @@ -15383,7 +15355,7 @@ def is_chordal(self, certificate=False, algorithm='B'): # answer is valid, especially when it is so cheap ;-) if hole.order() <= 3 or not hole.is_regular(k=2): - raise RuntimeError("the graph is not chordal, and something went wrong " "in the computation of the certificate. Please report " "this bug, providing the graph if possible") + raise RuntimeError("the graph is not chordal, and something went wrong in the computation of the certificate. Please report this bug, providing the graph if possible") return (False, hole) @@ -15610,7 +15582,6 @@ def is_interval(self, certificate=False): g = copy(self) for cc in g.connected_components_subgraphs(): - # We pick a perfect elimination order for every connected # component. We will then iteratively take the last vertex in the # order (a simplicial vertex) and consider the clique it forms with @@ -16166,7 +16137,7 @@ def cluster_triangles(self, nbunch=None, implementation=None): from sage.graphs.base.static_dense_graph import triangles_count else: - raise ValueError("the implementation can only be 'networkx', " "'sparse_copy', 'dense_copy' or None") + raise ValueError("the implementation can only be 'networkx', 'sparse_copy', 'dense_copy' or None") if nbunch is None: return triangles_count(self) @@ -16230,7 +16201,7 @@ def clustering_average(self, implementation=None): implementation = 'sparse_copy' if implementation not in ['networkx', 'boost', 'dense_copy', 'sparse_copy']: - raise ValueError("the implementation can only be 'networkx', " "'boost', 'sparse_copy', 'dense_copy' or None") + raise ValueError("the implementation can only be 'networkx', 'boost', 'sparse_copy', 'dense_copy' or None") if self.is_directed() and implementation != 'networkx': raise ValueError("this value of 'implementation' is invalid for directed graphs") @@ -16357,7 +16328,7 @@ def clustering_coeff(self, nodes=None, weight=False, implementation=None): implementation = 'sparse_copy' if implementation not in ['networkx', 'boost', 'dense_copy', 'sparse_copy']: - raise ValueError("the implementation can only be 'networkx', " "'boost', 'sparse_copy', 'dense_copy' or None") + raise ValueError("the implementation can only be 'networkx', 'boost', 'sparse_copy', 'dense_copy' or None") if (self.is_directed() or weight) and implementation != 'networkx': raise ValueError("this value of 'implementation' is invalid for directed/weighted graphs") @@ -17412,7 +17383,7 @@ def triangles_count(self, algorithm=None): """ if self.is_directed(): if algorithm is not None and algorithm != "iter": - raise ValueError("the value of algorithm(={}) must be 'iter' " "or None for directed graphs".format(algorithm)) + raise ValueError("the value of algorithm(={}) must be 'iter' or None for directed graphs".format(algorithm)) self._scream_if_not_simple(allow_loops=True) from sage.graphs.digraph_generators import digraphs @@ -17865,7 +17836,7 @@ def _check_weight_function(self, weight_function=None): if isinstance(temp, (str, bytes)): raise ValueError() except Exception: - raise ValueError("the weight function cannot find the " "weight of " + str(e)) + raise ValueError("the weight function cannot find the weight of " + str(e)) def _get_weight_function(self, by_weight=False, weight_function=None, check_weight=True): r""" @@ -18103,7 +18074,7 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, weight_function=Non if algorithm == 'BFS': if by_weight: - raise ValueError("the 'BFS' algorithm does not work on " "weighted graphs") + raise ValueError("the 'BFS' algorithm does not work on weighted graphs") return self._backend.shortest_path_all_vertices(u, cutoff) if algorithm == 'Dijkstra_NetworkX': @@ -18626,7 +18597,7 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, weight_functi algorithm = "BFS" if by_weight and algorithm in ['BFS', "Floyd-Warshall-Cython"]: - raise ValueError("algorithm '" + algorithm + "' does not work " "with weights") + raise ValueError("algorithm '" + algorithm + "' does not work with weights") if algorithm == "BFS": from sage.graphs.distances_all_pairs import ( @@ -21427,7 +21398,7 @@ def layout_tree(self, tree_orientation='down', tree_root=None, dim=2, **options) from sage.graphs.graph import Graph if not Graph(self).is_tree(): - raise RuntimeError("cannot use tree layout on this graph: " "self.is_tree() returns False") + raise RuntimeError("cannot use tree layout on this graph: self.is_tree() returns False") emb = self.get_embedding() @@ -23358,7 +23329,7 @@ def graphviz_string(self, **options): edge_options.update(f((u, v, label))) if edge_options['edge_string'] not in ['--', '->']: - raise ValueError("edge_string(='{}') in edge_options dict for " "the edge ({}, {}) should be '--' or '->'".format(edge_options['edge_string'], u, v)) + raise ValueError("edge_string(='{}') in edge_options dict for the edge ({}, {}) should be '--' or '->'".format(edge_options['edge_string'], u, v)) dot_options = [] @@ -23393,7 +23364,7 @@ def graphviz_string(self, **options): elif edge_options['dir'] in ['forward', 'back', 'both', 'none']: dot_options.append('dir={}'.format(edge_options['dir'])) else: - raise ValueError("dir(='{}') in edge_options dict for the" " edge ({}, {}) should be 'forward', 'back'," " 'both', or 'none'".format(edge_options['dir'], u, v)) + raise ValueError("dir(='{}') in edge_options dict for the edge ({}, {}) should be 'forward', 'back', 'both', or 'none'".format(edge_options['dir'], u, v)) s += ' %s %s %s' % (key(u), edge_options['edge_string'], key(v)) if dot_options: @@ -24546,7 +24517,6 @@ def automorphism_group(self, partition=None, verbosity=0, edge_labels=False, ord have_bliss = False if algorithm == 'bliss' or (algorithm is None and have_bliss): # explicit choice from the user; or # by default - Bliss().require() from sage.graphs.bliss import automorphism_group @@ -26556,7 +26526,6 @@ def graph_isom_equivalent_non_edge_labeled_graph(g, partition=None, standard_lab # Should we pay attention to edge labels ? if ignore_edge_labels: - if g_has_multiple_edges: # An edge between u and v with label l and multiplicity k being # encoded as an uv edge with label [l,k], we must not assume that an diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 28df97e65b7..ba9740aa5e6 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1046,7 +1046,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, weighted=None, if sparse is False: if data_structure != "sparse": - raise ValueError("The 'sparse' argument is an alias for " "'data_structure'. Please do not define both.") + raise ValueError("The 'sparse' argument is an alias for 'data_structure'. Please do not define both.") data_structure = "dense" if multiedges or weighted: @@ -1066,7 +1066,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, weighted=None, elif data_structure == "dense": CGB = DenseGraphBackend else: - raise ValueError("data_structure must be equal to 'sparse', " "'static_sparse' or 'dense'") + raise ValueError("data_structure must be equal to 'sparse', 'static_sparse' or 'dense'") self._backend = CGB(0, directed=False) if format is None and isinstance(data, str): @@ -1115,7 +1115,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, weighted=None, try: import igraph except ImportError: - raise ImportError("The data seems to be a igraph object, but " "igraph is not installed in Sage. To install " "it, run 'sage -i python_igraph'") + raise ImportError("The data seems to be a igraph object, but igraph is not installed in Sage. To install it, run 'sage -i python_igraph'") if format is None and isinstance(data, igraph.Graph): format = 'igraph' if format is None and isinstance(data, (int, Integer)): @@ -1203,7 +1203,7 @@ def __init__(self, data=None, pos=None, loops=None, format=None, weighted=None, elif format == 'igraph': if data.is_directed(): - raise ValueError("An *undirected* igraph graph was expected. " "To build a directed graph, call the DiGraph " "constructor.") + raise ValueError("An *undirected* igraph graph was expected. To build a directed graph, call the DiGraph constructor.") self.add_vertices(range(data.vcount())) self.add_edges((e.source, e.target, e.attributes()) for e in data.es()) @@ -2268,7 +2268,6 @@ def is_even_hole_free(self, certificate=False): from sage.graphs.generators.basic import CycleGraph while start <= self.order(): - subgraph = self.subgraph_search(CycleGraph(start), induced=True) if subgraph is not None: @@ -2339,7 +2338,6 @@ def is_odd_hole_free(self, certificate=False): from sage.graphs.generators.basic import CycleGraph while start <= self.order(): - subgraph = self.subgraph_search(CycleGraph(start), induced=True) if subgraph is not None: @@ -4393,7 +4391,6 @@ def minor(self, H, solver=None, verbose=0, induced=False, *, integrality_toleran h_edges = p.new_variable(nonnegative=True) for h1, h2 in H.edge_iterator(labels=None): - for v1, v2 in self.edge_iterator(labels=None): fv1v2 = frozenset((v1, v2)) p.add_constraint(h_edges[(h1, h2), fv1v2] - rs[h2, v2], max=0) @@ -4517,7 +4514,7 @@ def centrality_degree(self, v=None): n_minus_one = Integer(self.order() - 1) if n_minus_one == 0: - raise ValueError("the centrality degree is not defined " "on graphs with only one vertex") + raise ValueError("the centrality degree is not defined on graphs with only one vertex") if v is None: return {v: self.degree(v) / n_minus_one for v in self} return self.degree(v) / n_minus_one @@ -5759,9 +5756,7 @@ def flow_balance(C, v): return flow_in(C, v) - flow_out(C, v) for h1, h2 in H.edge_iterator(labels=False): - for v in G: - # The flow balance depends on whether the vertex v is a # representative of h1 or h2 in G, or a representative of none p.add_constraint(flow_balance((h1, h2), v) == v_repr[h1, v] - v_repr[h2, v]) @@ -5815,7 +5810,6 @@ def flow_balance(C, v): for u, v in minor.edge_iterator(labels=False): used = False for C in H.edge_iterator(labels=False): - if flow[C, (u, v)] or flow[C, (v, u)]: used = True minor.set_edge_label(u, v, C) @@ -6500,7 +6494,6 @@ def vertex_cover(self, algorithm='Cliquer', value_only=False, reduction_rules=Tr degree_at_most_two = {u for u in g if g.degree(u) <= 2} while degree_at_most_two: - u = degree_at_most_two.pop() du = g.degree(u) @@ -6589,7 +6582,6 @@ def vertex_cover(self, algorithm='Cliquer', value_only=False, reduction_rules=Tr cover_g = set(uu for uu in g if uu not in independent) elif algorithm == "MILP": - from sage.numerical.mip import MixedIntegerLinearProgram p = MixedIntegerLinearProgram(maximization=False, solver=solver) @@ -7177,7 +7169,6 @@ def cores(self, k=None, with_labels=False): nbrs = {v: set(self.neighbors(v)) for v in self} # form vertex core building up from smallest for v in verts: - # If all the vertices have a degree larger than k, we can return # our answer if k is not None if k is not None and core[v] >= k: diff --git a/src/sage/graphs/graph_database.py b/src/sage/graphs/graph_database.py index ee4d60bed2d..8e8012e40d2 100644 --- a/src/sage/graphs/graph_database.py +++ b/src/sage/graphs/graph_database.py @@ -242,7 +242,6 @@ def graph_db_info(tablename=None): class GenericGraphQuery(SQLQuery): - def __init__(self, query_string, database=None, param_tuple=None): """ A query for a :class:`~GraphDatabase`. @@ -303,7 +302,6 @@ def __init__(self, query_string, database=None, param_tuple=None): class GraphQuery(GenericGraphQuery): - def __init__(self, graph_db=None, query_dict=None, display_cols=None, immutable=False, **kwds): r""" A query for an instance of :class:`~GraphDatabase`. @@ -754,7 +752,6 @@ def number_of(self): class GraphDatabase(SQLDatabase): - def __init__(self): """ Graph Database. @@ -989,9 +986,7 @@ def _gen_interact_func(self, display, **kwds): t = """ print('

Query Results:

') GraphQuery(display_cols=%s,%s).show(with_picture=True) - """ % tuple( - [display, ','.join(params)] - ) + """ % tuple([display, ','.join(params)]) s += '\t' + '\n\t'.join(t.split('\n')) + '\n' exec(s) return locals()[function_name] diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 725d083932a..333bfcfb322 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -29,7 +29,7 @@ def __append_to_doc(methods): global __doc__ - __doc__ += "\n.. csv-table::\n" " :class: contentstable\n" " :widths: 33, 33, 33\n" " :delim: |\n\n" + __doc__ += "\n.. csv-table::\n :class: contentstable\n :widths: 33, 33, 33\n :delim: |\n\n" h = (len(methods) + 2) // 3 # Reorders the list of methods for horizontal reading, the only one Sphinx understands @@ -1696,7 +1696,6 @@ def fullerenes(self, order, ipr=False, immutable=False): command += ' -' + ('I' if ipr else '') + 'd {0}d'.format(order) with subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) as sp: - yield from graphs._read_planar_code(sp.stdout, immutable=immutable) def fusenes(self, hexagon_count, benzenoids=False, immutable=False): @@ -1784,7 +1783,6 @@ def fusenes(self, hexagon_count, benzenoids=False, immutable=False): command += (' b' if benzenoids else '') + ' {0} p'.format(hexagon_count) with subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) as sp: - yield from graphs._read_planar_code(sp.stdout, immutable=immutable) def plantri_gen(self, options="", immutable=False): @@ -1968,7 +1966,6 @@ def plantri_gen(self, options="", immutable=False): command = '{} {}'.format(shlex.quote(Plantri().absolute_filename()), options) with subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) as sp: - try: yield from graphs._read_planar_code(sp.stdout, immutable=immutable) except (TypeError, AssertionError): @@ -2177,7 +2174,7 @@ def planar_graphs(self, order, minimum_degree=None, minimum_connectivity=None, e if maximum_edges is None: edges = '-e{}:'.format(minimum_edges) elif minimum_edges > maximum_edges: - raise ValueError("the maximum number of edges must be larger " "or equal to the minimum number of edges") + raise ValueError("the maximum number of edges must be larger or equal to the minimum number of edges") elif minimum_edges == maximum_edges: edges = '-e{}'.format(minimum_edges) else: @@ -2495,7 +2492,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None raise ValueError("Minimum degree should be None, 2 or 3.") if no_nonfacial_quadrangles and minimum_connectivity == 2: - raise NotImplementedError("Generation of no non-facial quadrangles " "and minimum connectivity 2 is not implemented") + raise NotImplementedError("Generation of no non-facial quadrangles and minimum connectivity 2 is not implemented") # check combination of values of minimum degree and minimum connectivity if minimum_connectivity is None: @@ -2923,7 +2920,6 @@ def canaug_traverse_vert(g, aut_gens, max_verts, property, dig=False, loops=Fals n = g.order() if n < max_verts: - # build a list representing C(g) - the vertex to be added # is at the end, so only specify which edges... # in the case of graphs, there are n possibilities, diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index 8eaa7491bb9..3f3e0a4243f 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -332,9 +332,9 @@ def from_incidence_matrix(G, M, loops=False, multiedges=False, weighted=False): NZ = M.nonzero_positions_in_column(i) if len(NZ) == 1: if oriented: - raise ValueError("column {} of the (oriented) incidence " "matrix contains only one nonzero value".format(i)) + raise ValueError("column {} of the (oriented) incidence matrix contains only one nonzero value".format(i)) elif M[NZ[0], i] != 2: - raise ValueError("each column of a non-oriented incidence " "matrix must sum to 2, but column {} does not".format(i)) + raise ValueError("each column of a non-oriented incidence matrix must sum to 2, but column {} does not".format(i)) if loops is None: loops = True positions.append((NZ[0], NZ[0])) diff --git a/src/sage/graphs/graph_latex.py b/src/sage/graphs/graph_latex.py index 5dd5dc7fee2..9d4628a1343 100644 --- a/src/sage/graphs/graph_latex.py +++ b/src/sage/graphs/graph_latex.py @@ -1750,7 +1750,6 @@ def translate(p): vl_color = {} vl_placement = {} for u in vertex_list: - c = dvc if u in vertex_colors: c = cc.to_rgb(vertex_colors[u]) @@ -1772,7 +1771,6 @@ def translate(p): v_size[u] = vs if vertex_labels: - c = dvlc if u in vertex_label_colors: c = cc.to_rgb(vertex_label_colors[u]) diff --git a/src/sage/graphs/graph_list.py b/src/sage/graphs/graph_list.py index 9dce6efe7c1..ff37fb3591d 100644 --- a/src/sage/graphs/graph_list.py +++ b/src/sage/graphs/graph_list.py @@ -17,7 +17,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.misc.misc import try_read @@ -112,7 +111,7 @@ def _from_whatever(data, fmt=None, immutable=False): try: lines = iter(data) except TypeError: - raise TypeError("must be a string, an iterable of strings, or a readable " "file-like object") + raise TypeError("must be a string, an iterable of strings, or a readable file-like object") if fmt == 'graph6': kwargs = {'format': fmt} diff --git a/src/sage/graphs/graph_plot.py b/src/sage/graphs/graph_plot.py index 1333898ca61..92013a331a8 100644 --- a/src/sage/graphs/graph_plot.py +++ b/src/sage/graphs/graph_plot.py @@ -143,14 +143,14 @@ 'iterations': 'The number of times to execute the spring layout algorithm.', 'heights': 'A dictionary mapping heights to the list of vertices at this height.', 'spring': 'Use spring layout to finalize the current layout.', - 'tree_root': 'A vertex designation for drawing trees. A vertex of the tree to ' 'be used as the root for the ``layout=\'tree\'`` option. If no root ' 'is specified, then one is chosen close to the center of the tree. ' 'Ignored unless ``layout=\'tree\'``.', - 'forest_roots': 'An iterable specifying which vertices to use as roots for the ' '``layout=\'forest\'`` option. If no root is specified for a tree, ' 'then one is chosen close to the center of the tree. ' 'Ignored unless ``layout=\'forest\'``.', - 'tree_orientation': 'The direction of tree branches -- \'up\', \'down\', ' '\'left\' or \'right\'.', - 'external_face': 'A list of the vertices of the external face of the graph, ' 'used for Tutte embedding layout.', - 'external_face_pos': 'A dictionary specifying the positions of the external face of the ' 'graph, used for Tutte embedding layout. If none specified, the' 'external face is a regular polygon.', + 'tree_root': 'A vertex designation for drawing trees. A vertex of the tree to be used as the root for the ``layout=\'tree\'`` option. If no root is specified, then one is chosen close to the center of the tree. Ignored unless ``layout=\'tree\'``.', + 'forest_roots': 'An iterable specifying which vertices to use as roots for the ``layout=\'forest\'`` option. If no root is specified for a tree, then one is chosen close to the center of the tree. Ignored unless ``layout=\'forest\'``.', + 'tree_orientation': 'The direction of tree branches -- \'up\', \'down\', \'left\' or \'right\'.', + 'external_face': 'A list of the vertices of the external face of the graph, used for Tutte embedding layout.', + 'external_face_pos': 'A dictionary specifying the positions of the external face of the graph, used for Tutte embedding layout. If none specified, theexternal face is a regular polygon.', 'save_pos': 'Whether or not to save the computed position for the graph.', 'dim': 'The dimension of the layout -- 2 or 3.', - 'prog': 'Which graphviz layout program to use -- one of ' '"circo", "dot", "fdp", "neato", or "twopi".', + 'prog': 'Which graphviz layout program to use -- one of "circo", "dot", "fdp", "neato", or "twopi".', 'by_component': 'Whether to do the spring layout by connected component -- boolean.', } @@ -159,21 +159,21 @@ graphplot_options.update( { 'pos': 'The position dictionary of vertices.', - 'vertex_labels': 'Vertex labels to draw. This can be ``True``/``False`` to indicate ' 'whether to print the vertex string representation of not, ' 'a dictionary keyed by vertices and associating to each vertex ' 'a label string, or a function taking as input a vertex and returning ' 'a label string.', - 'vertex_label_shift': 'If layout is circular and we have vertex labels, will shift vertices ' 'away from center of circle in coordinate fashion `(x, y)`.', - 'vertex_color': 'Default color for vertices not listed ' 'in vertex_colors dictionary.', - 'vertex_colors': 'A dictionary specifying vertex colors: ' 'each key is a color recognizable by matplotlib, ' 'and each corresponding value is a list of vertices.', + 'vertex_labels': 'Vertex labels to draw. This can be ``True``/``False`` to indicate whether to print the vertex string representation of not, a dictionary keyed by vertices and associating to each vertex a label string, or a function taking as input a vertex and returning a label string.', + 'vertex_label_shift': 'If layout is circular and we have vertex labels, will shift vertices away from center of circle in coordinate fashion `(x, y)`.', + 'vertex_color': 'Default color for vertices not listed in vertex_colors dictionary.', + 'vertex_colors': 'A dictionary specifying vertex colors: each key is a color recognizable by matplotlib, and each corresponding value is a list of vertices.', 'vertex_size': 'The size to draw the vertices.', - 'vertex_shape': 'The shape to draw the vertices. ' 'Currently unavailable for Multi-edged DiGraphs.', + 'vertex_shape': 'The shape to draw the vertices. Currently unavailable for Multi-edged DiGraphs.', 'edge_labels': 'Whether or not to draw edge labels.', - 'edge_style': 'The linestyle of the edges. It should be ' 'one of "solid", "dashed", "dotted", "dashdot", ' 'or "-", "--", ":", "-.", respectively. ', - 'edge_styles': 'A dictionary specifying edge styles: ' 'each key is an edge or a label (all same) and value is the linestyle ' 'of the edge. It should be one of "solid", "dashed", "dotted", ' '"dashdot", or "-", "--", ":", "-.", respectively.', + 'edge_style': 'The linestyle of the edges. It should be one of "solid", "dashed", "dotted", "dashdot", or "-", "--", ":", "-.", respectively. ', + 'edge_styles': 'A dictionary specifying edge styles: each key is an edge or a label (all same) and value is the linestyle of the edge. It should be one of "solid", "dashed", "dotted", "dashdot", or "-", "--", ":", "-.", respectively.', 'edge_thickness': 'The thickness of the edges.', - 'edge_thicknesses': 'A dictionary specifying edge thicknesses: ' 'each key is an edge or a label (all same) and thickness of the ' 'corresponding edge.', + 'edge_thicknesses': 'A dictionary specifying edge thicknesses: each key is an edge or a label (all same) and thickness of the corresponding edge.', 'edge_color': 'The default color for edges not listed in edge_colors.', - 'edge_colors': 'A dictionary specifying edge colors: ' 'each key is a color recognized by matplotlib, ' 'and each corresponding value is a list of edges.', - 'color_by_label': 'Whether to color the edges according to their labels. This also ' 'accepts a function or dictionary mapping labels to colors.', - 'partition': 'A partition of the vertex set. If specified, plot will show each ' 'cell in a different color; vertex_colors takes precedence.', + 'edge_colors': 'A dictionary specifying edge colors: each key is a color recognized by matplotlib, and each corresponding value is a list of edges.', + 'color_by_label': 'Whether to color the edges according to their labels. This also accepts a function or dictionary mapping labels to colors.', + 'partition': 'A partition of the vertex set. If specified, plot will show each cell in a different color; vertex_colors takes precedence.', 'loop_size': 'The radius of the smallest loop.', 'arrowsize': 'Size of arrows.', 'dist': 'The distance between multiedges.', @@ -1536,7 +1536,7 @@ def layout_tree(self, root, orientation): T = self._graph if not self._graph.is_tree(): - raise RuntimeError("cannot use tree layout on this graph: " "self.is_tree() returns False") + raise RuntimeError("cannot use tree layout on this graph: self.is_tree() returns False") children = {root: T.neighbors(root)} diff --git a/src/sage/graphs/graph_plot_js.py b/src/sage/graphs/graph_plot_js.py index 899148d3491..cf926e41675 100644 --- a/src/sage/graphs/graph_plot_js.py +++ b/src/sage/graphs/graph_plot_js.py @@ -73,6 +73,7 @@ Functions --------- """ + from pathlib import Path from sage.misc.temporary_file import tmp_filename from sage.misc.lazy_import import lazy_import @@ -233,7 +234,6 @@ def gen_html_code(G, vertex_labels=True, edge_labels=False, vertex_partition=[], seen = {} # How many times has this edge been seen ? for u, v, l in G.edge_iterator(): - # Edge color color = edge_color.get((u, v, l), edge_color_default) diff --git a/src/sage/graphs/hypergraph_generators.py b/src/sage/graphs/hypergraph_generators.py index 002f14aaba0..033c35f8008 100644 --- a/src/sage/graphs/hypergraph_generators.py +++ b/src/sage/graphs/hypergraph_generators.py @@ -177,7 +177,6 @@ def nauty(self, number_of_sets, number_of_vertices, multiple_sets=False, vertex_ nauty_input += " " + str(number_of_vertices) + " " + str(number_of_sets) + " " with subprocess.Popen(shlex.quote(genbgL_path) + " {0}".format(nauty_input), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) as sp: - if debug: yield sp.stderr.readline() diff --git a/src/sage/graphs/isgci.py b/src/sage/graphs/isgci.py index 53bd13eeedf..90f15f13f9f 100644 --- a/src/sage/graphs/isgci.py +++ b/src/sage/graphs/isgci.py @@ -600,7 +600,7 @@ def __contains__(self, g) -> bool: excluded = self.forbidden_subgraphs() if excluded is None: - raise NotImplementedError("No recognition algorithm is available " "for this class.") + raise NotImplementedError("No recognition algorithm is available for this class.") return not any(g.subgraph_search(gg, induced=True) for gg in excluded) @@ -681,7 +681,7 @@ def get_class(self, id): name = "class " + str(id) return GraphClass(name, id) - raise ValueError("The given class id does not exist in the ISGCI " "database. Is the db too old ? You can update it " "with graph_classes.update_db().") + raise ValueError("The given class id does not exist in the ISGCI database. Is the db too old ? You can update it with graph_classes.update_db().") @cached_method def classes(self): diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 2e3c89f27b5..b7d31d58d7d 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -603,7 +603,7 @@ def __init__(self, data=None, matching=None, algorithm='Edmonds', solver=None, v kwds = {'loops': False} else: if 'loops' in kwds and kwds['loops']: - raise ValueError('loops are not allowed in ' 'matching covered graphs') + raise ValueError('loops are not allowed in matching covered graphs') kwds['loops'] = False if data is None: @@ -1113,7 +1113,7 @@ def add_edge(self, u, v=None, label=None): if u in self and v in self: if u == v: - raise ValueError('loops are not allowed in ' 'matching covered graphs') + raise ValueError('loops are not allowed in matching covered graphs') # If (u, v, label) is a multiple edge/ an existing edge if self.has_edge(u, v): @@ -1131,7 +1131,7 @@ def add_edge(self, u, v=None, label=None): self._backend.add_edge(u, v, label, self._directed) return - raise ValueError('the graph obtained after the addition of edge ' '(%s) is not matching covered' % str((u, v, label))) + raise ValueError('the graph obtained after the addition of edge (%s) is not matching covered' % str((u, v, label))) @doc_index('Overwritten methods') def add_edges(self, edges, loops=False): @@ -1357,7 +1357,7 @@ def add_edges(self, edges, loops=False): TypeError: input edge None is of unknown type """ if loops: - raise ValueError('loops are not allowed in ' 'matching covered graphs') + raise ValueError('loops are not allowed in matching covered graphs') if not edges: # do nothing return @@ -1365,16 +1365,16 @@ def add_edges(self, edges, loops=False): from collections.abc import Iterable if not isinstance(edges, Iterable): - raise ValueError('expected an iterable of edges, ' 'but got a non-iterable object') + raise ValueError('expected an iterable of edges, but got a non-iterable object') links = [] # to extract the nonloop input edges for edge in edges: if hasattr(edge, '__len__'): if len(edge) <= 1: - raise ValueError('need more than 1 value to unpack ' f'for edge: {edge}') + raise ValueError(f'need more than 1 value to unpack for edge: {edge}') elif len(edge) > 3: - raise ValueError('too many values to unpack (expected 2) ' f'for edge: {edge}') + raise ValueError(f'too many values to unpack (expected 2) for edge: {edge}') else: raise TypeError(f'input edge {edge} is of unknown type') @@ -1399,7 +1399,7 @@ def add_edges(self, edges, loops=False): # Throw error if the no. of new vertices is odd if len(new_vertices) % 2: - raise ValueError('odd order is not allowed for ' 'matching covered graphs') + raise ValueError('odd order is not allowed for matching covered graphs') try: G = Graph(self, multiedges=self.allows_multiple_edges()) @@ -1407,7 +1407,7 @@ def add_edges(self, edges, loops=False): # Check if G has a vertex with at most 1 neighbor if any(len(G.neighbors(v)) <= 1 for v in G): - raise ValueError('the resulting graph after the addition of' 'the edges is not matching covered') + raise ValueError('the resulting graph after the addition ofthe edges is not matching covered') # If all the vertices are existent, the existing perfect matching # can be used. @@ -1433,7 +1433,7 @@ def add_edges(self, edges, loops=False): self.__init__(data=G, matching=M) except Exception: - raise ValueError('the resulting graph after the addition of' 'the edges is not matching covered') + raise ValueError('the resulting graph after the addition ofthe edges is not matching covered') @doc_index('Overwritten methods') def add_vertex(self, name=None): @@ -1489,7 +1489,7 @@ def add_vertex(self, name=None): ValueError: isolated vertices are not allowed in matching covered graphs """ if name not in self: - raise ValueError('isolated vertices are not allowed in ' 'matching covered graphs') + raise ValueError('isolated vertices are not allowed in matching covered graphs') @doc_index('Overwritten methods') def add_vertices(self, vertices): @@ -1558,7 +1558,7 @@ def add_vertices(self, vertices): ValueError: isolated vertices are not allowed in matching covered graphs """ if any(vertex not in self for vertex in vertices): - raise ValueError('isolated vertices are not allowed in ' 'matching covered graphs') + raise ValueError('isolated vertices are not allowed in matching covered graphs') @doc_index('Overwritten methods') def allow_loops(self, new, check=True): @@ -1612,7 +1612,7 @@ def allow_loops(self, new, check=True): - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` """ if new: - raise ValueError('loops are not allowed in ' 'matching covered graphs') + raise ValueError('loops are not allowed in matching covered graphs') @doc_index('Overwritten methods') def allows_loops(self): @@ -1795,7 +1795,7 @@ def delete_vertex(self, vertex, in_order=False): if in_order: vertex = self.vertices(sort=True)[vertex] - raise ValueError('odd order is not allowed for ' 'matching covered graphs') + raise ValueError('odd order is not allowed for matching covered graphs') @doc_index('Overwritten methods') def delete_vertices(self, vertices): @@ -1917,14 +1917,14 @@ def delete_vertices(self, vertices): vertices = set(vertices) if len(vertices) % 2: # try to remove an odd number of vertices - raise ValueError('an odd no. of distinct vertices can not be ' 'removed from a matching covered graph') + raise ValueError('an odd no. of distinct vertices can not be removed from a matching covered graph') for vertex in vertices: if vertex not in self: raise ValueError('vertex (%s) not in the graph' % str(vertex)) if self.order() == len(vertices): - raise ValueError('the resulting graph after the removal of the ' 'vertices is trivial, therefore is not ' 'matching covered') + raise ValueError('the resulting graph after the removal of the vertices is trivial, therefore is not matching covered') try: G = Graph(self, multiedges=self.allows_multiple_edges()) @@ -1943,7 +1943,7 @@ def delete_vertices(self, vertices): self.__init__(data=G, matching=M) except Exception: - raise ValueError('the resulting graph after the removal of ' 'the vertices is not matching covered') + raise ValueError('the resulting graph after the removal of the vertices is not matching covered') @doc_index('Miscellaneous methods') def get_matching(self): @@ -2322,7 +2322,7 @@ def has_perfect_matching(G, algorithm='Edmonds', solver=None, verbose=0, *, inte if algorithm in ['Edmonds', 'LP_matching', 'LP']: return True - raise ValueError('algorithm must be set to \'Edmonds\', ' '\'LP_matching\' or \'LP\'') + raise ValueError('algorithm must be set to \'Edmonds\', \'LP_matching\' or \'LP\'') @doc_index('Overwritten methods') def is_biconnected(self): @@ -2732,7 +2732,6 @@ def is_brace(self, coNP_certificate=False): # For each edge (a, b) in E(H(e)) ∩ M with a in A, b —> a in D(e). # For each edge (a, b) in E(H(e)) with a in A, a —> b in D(e). for a, b in H.edge_iterator(labels=False, sort_vertices=True): - if a in B: a, b = b, a @@ -3491,7 +3490,7 @@ def remove_loops(self, vertices=None): from collections.abc import Iterable if vertices is not None and not isinstance(vertices, Iterable): - raise TypeError(f'\'{vertices.__class__.__name__}\' ' 'object is not iterable') + raise TypeError(f'\'{vertices.__class__.__name__}\' object is not iterable') @doc_index('Overwritten methods') def subdivide_edge(self, *args): @@ -3675,7 +3674,7 @@ def subdivide_edge(self, *args): u, v, l = edge else: - raise ValueError('for two input arguments, the first one must be ' f'of the form (u, v) or (u, v, l), but found: {edge}') + raise ValueError(f'for two input arguments, the first one must be of the form (u, v) or (u, v, l), but found: {edge}') elif len(args) == 3: u, v, k = args @@ -3697,7 +3696,7 @@ def subdivide_edge(self, *args): raise ValueError(f'the given edge {(u, v, l)} does not exist') if k < 0 or k % 2: - raise ValueError('the number of subdivisions must be a ' f'nonnegative even integer, but found {k}') + raise ValueError(f'the number of subdivisions must be a nonnegative even integer, but found {k}') if not k: return @@ -3919,7 +3918,7 @@ def subdivide_edges(self, edges, k): raise ValueError('expected an iterable of edges, but got a non-iterable object') if k < 0 or k % 2: - raise ValueError('the number of subdivisions must be a ' f'nonnegative even integer, but found {k}') + raise ValueError(f'the number of subdivisions must be a nonnegative even integer, but found {k}') if not k: return @@ -3927,10 +3926,10 @@ def subdivide_edges(self, edges, k): for i, edge in enumerate(edges): if hasattr(edge, '__len__'): if len(edge) <= 1: - raise ValueError('need more than 1 value to unpack ' f'for edge: {edge}') + raise ValueError(f'need more than 1 value to unpack for edge: {edge}') elif len(edge) > 3: - raise ValueError('too many values to unpack (expected 2) ' f'for edge: {edge}') + raise ValueError(f'too many values to unpack (expected 2) for edge: {edge}') else: raise TypeError(f'input edge {edge} is of unknown type') @@ -3962,7 +3961,7 @@ def subdivide_edges(self, edges, k): c = labels.count(l) if self.allows_multiple_edges() and isinstance(labels, list) else 1 if c < n: - raise ValueError(f'input contains {n} copies of the edge ' f'{edge}, but the graph contains {c}') + raise ValueError(f'input contains {n} copies of the edge {edge}, but the graph contains {c}') M = Graph(self.get_matching()) diff --git a/src/sage/graphs/morphisms.py b/src/sage/graphs/morphisms.py index 6e40895a314..38acdf0fb95 100644 --- a/src/sage/graphs/morphisms.py +++ b/src/sage/graphs/morphisms.py @@ -438,7 +438,6 @@ def has_homomorphism_to(G, H, core=False, solver=None, verbose=0, *, integrality # Minimize the mapping's size if core: - # The value of m is one if the corresponding vertex of H is used m = p.new_variable(nonnegative=True) for uh in H: diff --git a/src/sage/graphs/orientations.py b/src/sage/graphs/orientations.py index 7f5d3bc88a4..2fcf55cf989 100644 --- a/src/sage/graphs/orientations.py +++ b/src/sage/graphs/orientations.py @@ -140,7 +140,7 @@ def _initialize_digraph(G, edges, name=None, weighted=None, sparse=None, data_st # data_structure is already defined so there is nothing left to do # here. Did the user try to define too much ? if immutable is not None or sparse is not None: - raise ValueError("you cannot define 'immutable' or 'sparse' " "when 'data_structure' has a value") + raise ValueError("you cannot define 'immutable' or 'sparse' when 'data_structure' has a value") # At this point, data_structure is None. elif immutable is True: data_structure = 'static_sparse' @@ -1157,7 +1157,7 @@ def minimum_outdegree_orientation(G, use_edge_labels=False, solver=None, verbose """ G._scream_if_not_simple() if G.is_directed(): - raise ValueError("Cannot compute an orientation of a DiGraph. " "Please convert it to a Graph if you really mean it.") + raise ValueError("Cannot compute an orientation of a DiGraph. Please convert it to a Graph if you really mean it.") if use_edge_labels: from sage.rings.real_mpfr import RR @@ -1444,7 +1444,6 @@ def eulerian_orientation(G): odd.append(v) # Stops when there is no edge left while True: - # If there is an edge adjacent to the current one if g.degree(v): e = next(g.edge_iterator(v)) diff --git a/src/sage/graphs/pq_trees.py b/src/sage/graphs/pq_trees.py index 270ff3fada1..a99faaac9ca 100644 --- a/src/sage/graphs/pq_trees.py +++ b/src/sage/graphs/pq_trees.py @@ -646,7 +646,6 @@ def set_contiguous(self, v): # empty, we just reorder the set to put it at the right end elif n_PARTIAL_ALIGNED == 1 and n_EMPTY == self.number_of_children() - 1: - self._children = set_EMPTY + set_PARTIAL_ALIGNED return (PARTIAL, ALIGNED) @@ -661,7 +660,6 @@ def set_contiguous(self, v): ################################################################ else: - self._children = [] # We first move the empty elements to the left, if any @@ -679,12 +677,10 @@ def set_contiguous(self, v): # ==> We create a Q-tree if n_PARTIAL_ALIGNED < 2: - new = [] # add the partial element, if any if n_PARTIAL_ALIGNED == 1: - subtree = set_PARTIAL_ALIGNED[0] new.extend(subtree.simplify(v, right=ALIGNED)) @@ -693,7 +689,6 @@ def set_contiguous(self, v): # elements containing v on an interval if n_FULL > 0: - new.append(_new_P(set_FULL)) # We lock all of them in a Q-tree @@ -947,7 +942,6 @@ def set_contiguous(self, v): # the set to put it at the right end elif n_PARTIAL_ALIGNED == 1 and n_EMPTY == self.number_of_children() - 1: - if set_PARTIAL_ALIGNED[0] == self._children[-1]: return (PARTIAL, ALIGNED) @@ -969,7 +963,6 @@ def set_contiguous(self, v): ############################################################## else: - new_children = [] # Two variables to remember where we are @@ -979,12 +972,10 @@ def set_contiguous(self, v): seen_right_end = False for i in self: - type, aligned = f_seq[i] # We met an empty element if type == EMPTY: - # 2 possibilities : # # * we have NOT met a non-empty element before @@ -1007,7 +998,6 @@ def set_contiguous(self, v): raise ValueError(impossible_msg) if type == PARTIAL: - # if we see an ALIGNED partial tree after # having seen a nonempty element then the # partial tree must be aligned to the left and @@ -1037,7 +1027,6 @@ def set_contiguous(self, v): seen_right_end = True elif not seen_nonempty and aligned: - # left partial subtree subtree = i diff --git a/src/sage/groups/abelian_gps/dual_abelian_group_element.py b/src/sage/groups/abelian_gps/dual_abelian_group_element.py index 79babb156bf..05ff9a27ac7 100644 --- a/src/sage/groups/abelian_gps/dual_abelian_group_element.py +++ b/src/sage/groups/abelian_gps/dual_abelian_group_element.py @@ -41,6 +41,7 @@ - Volker Braun (2012-11) port to new Parent base. Use tuples for immutables. Default to cyclotomic base ring. """ + # **************************************************************************** # Copyright (C) 2006 William Stein # Copyright (C) 2006 David Joyner diff --git a/src/sage/groups/additive_abelian/additive_abelian_wrapper.py b/src/sage/groups/additive_abelian/additive_abelian_wrapper.py index e89e036cd74..ef3e013c290 100644 --- a/src/sage/groups/additive_abelian/additive_abelian_wrapper.py +++ b/src/sage/groups/additive_abelian/additive_abelian_wrapper.py @@ -802,7 +802,6 @@ def _rec(j, k, c): x = vector([0] * len(aa)) for i in reversed(range(w)): - gamma = p ** (js[i] - j) * c - dotprod(x, subbasis(js[i], k)) v = _rec(js[i], js[i + 1], gamma) diff --git a/src/sage/groups/affine_gps/affine_group.py b/src/sage/groups/affine_gps/affine_group.py index 7e01ce79837..1830db4a642 100644 --- a/src/sage/groups/affine_gps/affine_group.py +++ b/src/sage/groups/affine_gps/affine_group.py @@ -16,7 +16,6 @@ # https://www.gnu.org/licenses/ ############################################################################## - from sage.groups.group import Group from sage.categories.groups import Groups from sage.groups.matrix_gps.linear import GL diff --git a/src/sage/groups/artin.py b/src/sage/groups/artin.py index 5e0e757e808..ea09bf5bac1 100644 --- a/src/sage/groups/artin.py +++ b/src/sage/groups/artin.py @@ -606,7 +606,7 @@ def __classcall_private__(cls, coxeter_data, names=None): names = [names + str(i) for i in coxeter_data.index_set()] names = tuple(names) if len(names) != coxeter_data.rank(): - raise ValueError("the number of generators must match" " the rank of the Coxeter type") + raise ValueError("the number of generators must match the rank of the Coxeter type") if all(m == Infinity for m in coxeter_data.coxeter_graph().edge_labels()): from sage.groups.raag import RightAngledArtinGroup diff --git a/src/sage/groups/conjugacy_classes.py b/src/sage/groups/conjugacy_classes.py index 58327a05e5a..4268ae42979 100644 --- a/src/sage/groups/conjugacy_classes.py +++ b/src/sage/groups/conjugacy_classes.py @@ -280,7 +280,7 @@ def set(self): return Set(iter(self)) # return Set(self) creates an infinite loop in __contains__ - raise NotImplementedError("listing the elements of conjugacy classes " "is not implemented for infinite groups; " "use the iter function instead") + raise NotImplementedError("listing the elements of conjugacy classes is not implemented for infinite groups; use the iter function instead") def list(self) -> list: r""" @@ -302,7 +302,7 @@ def list(self) -> list: # return list(self) creates an infinite loop because list calls # __len__ which calls list... - raise NotImplementedError("listing the elements of conjugacy classes " "is not implemented for infinite groups; " "use the iter function instead") + raise NotImplementedError("listing the elements of conjugacy classes is not implemented for infinite groups; use the iter function instead") def is_real(self) -> bool: """ @@ -331,7 +331,7 @@ def is_rational(self) -> bool: False """ g = self._representative - return all(g ** k in self.set() for k in range(2, g.order())) + return all(g**k in self.set() for k in range(2, g.order())) def representative(self): """ diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index 9d6731bbc3c..65932a6a5db 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -410,7 +410,7 @@ def __hash__(self): # Finite groups - hash by permutation representation phi = G._perm_isomorphism() if phi is None: - raise NotImplementedError("hashing requires a confluent rewriting system\n" "for infinite non-free finitely presented groups;\n" "first compute one via " "k = G.rewriting_system(); k.make_confluent();\n" "G.set_confluent_rewriting_system(k)") + raise NotImplementedError("hashing requires a confluent rewriting system\nfor infinite non-free finitely presented groups;\nfirst compute one via k = G.rewriting_system(); k.make_confluent();\nG.set_confluent_rewriting_system(k)") perm_elem = libgap.Image(phi, self.gap()) return hash(perm_elem) diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index f7fab8ea2eb..47474fd916e 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -190,7 +190,7 @@ def _parse_group_def(parent, operation, identity, inverse, op, *, check=True): if operation in multiplication_names: if identity is not None or inverse is not None or op is not None: - raise ValueError("in order to specify custom identity/inverse/op, " "operation must be 'other'") + raise ValueError("in order to specify custom identity/inverse/op, operation must be 'other'") try: identity = parent.one() except Exception: @@ -200,7 +200,7 @@ def _parse_group_def(parent, operation, identity, inverse, op, *, check=True): op = mul elif operation in addition_names: if identity is not None or inverse is not None or op is not None: - raise ValueError("in order to specify custom identity/inverse/op, " "operation must be 'other'") + raise ValueError("in order to specify custom identity/inverse/op, operation must be 'other'") try: identity = parent.zero() except Exception: @@ -210,7 +210,7 @@ def _parse_group_def(parent, operation, identity, inverse, op, *, check=True): op = add else: if check and (identity is None or inverse is None or op is None): - raise ValueError("identity, inverse and operation must all be specified " "when operation is neither addition nor multiplication") + raise ValueError("identity, inverse and operation must all be specified when operation is neither addition nor multiplication") return 'other', identity, inverse, op diff --git a/src/sage/groups/group_semidirect_product.py b/src/sage/groups/group_semidirect_product.py index 9642b092df1..29e0aa7aa65 100644 --- a/src/sage/groups/group_semidirect_product.py +++ b/src/sage/groups/group_semidirect_product.py @@ -268,9 +268,9 @@ def __init__(self, G, H, twist=None, act_to_right=True, prefix0=None, prefix1=No def check_implemented_group(x): if x in Groups(): return - error = "The semidirect product construction for groups " "is implemented only for multiplicative groups" + error = "The semidirect product construction for groups is implemented only for multiplicative groups" if x in CommutativeAdditiveGroups(): - error += f". Please change the commutative additive group {x}" " into a multiplicative group " "using the functor sage.groups.group_exp.GroupExp" + error += f". Please change the commutative additive group {x} into a multiplicative group using the functor sage.groups.group_exp.GroupExp" raise TypeError(error) check_implemented_group(G) @@ -401,7 +401,7 @@ def has_gens(G): g1 = has_gens(factors[1]) if g1 is not False: return tuple([self((x, factors[1].one())) for x in g0] + [self((factors[0].one(), x)) for x in g1]) - raise NotImplementedError("one of the factors does not " "implement 'group_generators'") + raise NotImplementedError("one of the factors does not implement 'group_generators'") def product(self, x, y): r""" diff --git a/src/sage/groups/libgap_group.py b/src/sage/groups/libgap_group.py index 81c7b9dd1df..fd76d1f73ee 100644 --- a/src/sage/groups/libgap_group.py +++ b/src/sage/groups/libgap_group.py @@ -31,14 +31,12 @@ # http://www.gnu.org/licenses/ ############################################################################## - from sage.groups.group import Group from sage.groups.libgap_wrapper import ParentLibGAP, ElementLibGAP from sage.groups.libgap_mixin import GroupMixinLibGAP class GroupLibGAP(GroupMixinLibGAP, Group, ParentLibGAP): - Element = ElementLibGAP def __init__(self, *args, **kwds): diff --git a/src/sage/groups/lie_gps/nilpotent_lie_group.py b/src/sage/groups/lie_gps/nilpotent_lie_group.py index d93a5971d72..296d073e567 100644 --- a/src/sage/groups/lie_gps/nilpotent_lie_group.py +++ b/src/sage/groups/lie_gps/nilpotent_lie_group.py @@ -220,7 +220,7 @@ def __init__(self, L, name, **kwds): required_cat = LieAlgebras(L.base_ring()).FiniteDimensional() required_cat = required_cat.WithBasis().Nilpotent() if L not in required_cat: - raise TypeError("L needs to be a finite dimensional nilpotent " "Lie algebra with basis") + raise TypeError("L needs to be a finite dimensional nilpotent Lie algebra with basis") self._lie_algebra = L R = L.base_ring() diff --git a/src/sage/groups/matrix_gps/isometries.py b/src/sage/groups/matrix_gps/isometries.py index acc50cbf3b5..6eff83a2d35 100644 --- a/src/sage/groups/matrix_gps/isometries.py +++ b/src/sage/groups/matrix_gps/isometries.py @@ -248,7 +248,7 @@ def _check_matrix(self, x, *args): """ F = self.invariant_bilinear_form() if x * F * x.transpose() != F: - raise TypeError('matrix must be orthogonal ' 'with respect to the invariant form') + raise TypeError('matrix must be orthogonal with respect to the invariant form') class GroupActionOnSubmodule(Action): diff --git a/src/sage/groups/matrix_gps/linear.py b/src/sage/groups/matrix_gps/linear.py index eef593dfa1c..ea3282cb471 100644 --- a/src/sage/groups/matrix_gps/linear.py +++ b/src/sage/groups/matrix_gps/linear.py @@ -290,7 +290,6 @@ def SL(n, R, var='a'): class LinearMatrixGroup_generic(NamedMatrixGroup_generic): - def _check_matrix(self, x, *args): r""" Check whether the matrix ``x`` is special linear. @@ -418,7 +417,7 @@ def order_over_finite_field(q, n): return ord - raise NotImplementedError("order computation of linear groups not " "fully supported for arbitrary base rings") + raise NotImplementedError("order computation of linear groups not fully supported for arbitrary base rings") if n > 1 or (R.is_field() and not self._special): return Infinity @@ -429,6 +428,6 @@ def order_over_finite_field(q, n): if R == ZZ: return ZZ(2) - raise NotImplementedError("order computation of linear groups not " "fully supported for arbitrary base rings") + raise NotImplementedError("order computation of linear groups not fully supported for arbitrary base rings") cardinality = order diff --git a/src/sage/groups/matrix_gps/matrix_group.py b/src/sage/groups/matrix_gps/matrix_group.py index ccf1bd868cf..090db186ce9 100644 --- a/src/sage/groups/matrix_gps/matrix_group.py +++ b/src/sage/groups/matrix_gps/matrix_group.py @@ -403,7 +403,6 @@ def natural_representation(self, base_ring=None): @richcmp_method class MatrixGroup_generic(MatrixGroup_base): - Element = MatrixGroupElement_generic def __init__(self, degree, base_ring, category=None): diff --git a/src/sage/groups/matrix_gps/matrix_group_gap.py b/src/sage/groups/matrix_gps/matrix_group_gap.py index e81e31eb75a..0ec782ff149 100644 --- a/src/sage/groups/matrix_gps/matrix_group_gap.py +++ b/src/sage/groups/matrix_gps/matrix_group_gap.py @@ -28,7 +28,6 @@ class MatrixGroup_gap(GroupMixinLibGAP, MatrixGroup_generic, ParentLibGAP): - Element = MatrixGroupElement_gap def __init__(self, degree, base_ring, libgap_group, ambient=None, category=None): diff --git a/src/sage/groups/matrix_gps/named_group.py b/src/sage/groups/matrix_gps/named_group.py index 6fccbcab0eb..e081ecc6053 100644 --- a/src/sage/groups/matrix_gps/named_group.py +++ b/src/sage/groups/matrix_gps/named_group.py @@ -186,7 +186,6 @@ def normalize_args_invariant_form(R, d, invariant_form): class NamedMatrixGroup_generic(CachedRepresentation, MatrixGroup_generic): - def __init__(self, degree, base_ring, special, sage_name, latex_string, category=None, invariant_form=None): """ Base class for "named" matrix groups. diff --git a/src/sage/groups/matrix_gps/named_group_gap.py b/src/sage/groups/matrix_gps/named_group_gap.py index 4a5ef1f2cfc..aec88b06271 100644 --- a/src/sage/groups/matrix_gps/named_group_gap.py +++ b/src/sage/groups/matrix_gps/named_group_gap.py @@ -20,7 +20,6 @@ class NamedMatrixGroup_gap(NamedMatrixGroup_generic, MatrixGroup_gap): - def __init__(self, degree, base_ring, special, sage_name, latex_string, gap_command_string, category=None): """ Base class for "named" matrix groups using LibGAP. diff --git a/src/sage/groups/matrix_gps/pickling_overrides.py b/src/sage/groups/matrix_gps/pickling_overrides.py index ce2de3a09c2..be7c0a05202 100644 --- a/src/sage/groups/matrix_gps/pickling_overrides.py +++ b/src/sage/groups/matrix_gps/pickling_overrides.py @@ -10,7 +10,6 @@ class LegacyMatrixGroup(FinitelyGeneratedMatrixGroup_gap): - def __setstate__(self, state): """ Restore from old pickle. @@ -43,7 +42,6 @@ def __setstate__(self, state): class LegacyMatrixGroupElement(MatrixGroupElement_gap): - def __setstate__(self, state): """ Restore from old pickle. @@ -79,7 +77,6 @@ def __setstate__(self, state): class LegacyGeneralLinearGroup(LinearMatrixGroup_generic): - def __setstate__(self, state): """ Restore from old pickle. diff --git a/src/sage/groups/misc_gps/argument_groups.py b/src/sage/groups/misc_gps/argument_groups.py index 29911bcd35d..d5eff19456b 100644 --- a/src/sage/groups/misc_gps/argument_groups.py +++ b/src/sage/groups/misc_gps/argument_groups.py @@ -216,7 +216,7 @@ def _lt_(self, other): ... RuntimeError: cannot decide '<' for the roots of unity -1 and 1 """ - raise RuntimeError("cannot decide '<' " "for the roots of unity " "{} and {}".format(self, other)) + raise RuntimeError("cannot decide '<' for the roots of unity {} and {}".format(self, other)) def _act_on_(self, other, is_left): r""" @@ -266,7 +266,7 @@ def _act_on_(self, other, is_left): except (TypeError, ValueError) as e: from sage.rings.asymptotic.misc import combine_exceptions - raise combine_exceptions(TypeError('{} ({}) cannot ({}-)act on ' '{} ({})'.format(self, self.parent(), 'left' if is_left else 'right', other, P)), e) + raise combine_exceptions(TypeError('{} ({}) cannot ({}-)act on {} ({})'.format(self, self.parent(), 'left' if is_left else 'right', other, P)), e) return self._symbolic_(S) * other def __abs__(self): @@ -762,7 +762,7 @@ def _element_constructor_(self, data, exponent=None, **kwds): raise ValueError('{} is not in {}'.format(data, self)) elif not isinstance(data, int) or data != 0: - raise ValueError('input is ambiguous: ' '{} as well as exponent={} ' 'specified'.format(data, exponent)) + raise ValueError('input is ambiguous: {} as well as exponent={} specified'.format(data, exponent)) return self.element_class(self, exponent, **kwds) @@ -1390,7 +1390,7 @@ def __init__(self, parent, element, normalize=True): """ super().__init__(parent, int(element), normalize=normalize) if self._element_ not in (-1, 1): - raise ValueError('{} is not allowed ' '(only -1 or 1 is)'.format(element)) + raise ValueError('{} is not allowed (only -1 or 1 is)'.format(element)) @staticmethod def _normalize_(element): diff --git a/src/sage/groups/misc_gps/imaginary_groups.py b/src/sage/groups/misc_gps/imaginary_groups.py index ef098d7b536..e523e583797 100644 --- a/src/sage/groups/misc_gps/imaginary_groups.py +++ b/src/sage/groups/misc_gps/imaginary_groups.py @@ -151,7 +151,7 @@ def _lt_(self, other): ... RuntimeError: cannot decide '<' for imaginary elements 2*I and I """ - raise RuntimeError("cannot decide '<' " "for imaginary elements " "{} and {}".format(self, other)) + raise RuntimeError("cannot decide '<' for imaginary elements {} and {}".format(self, other)) def _repr_(self): r""" @@ -459,7 +459,7 @@ def _element_constructor_(self, data, imag=None): if data.real() == 0: imag = data.imag() else: - raise ValueError('{} is not in {} because it is not ' 'purely imaginary'.format(data, self)) + raise ValueError('{} is not in {} because it is not purely imaginary'.format(data, self)) except AttributeError: pass @@ -467,6 +467,6 @@ def _element_constructor_(self, data, imag=None): raise ValueError('{} is not in {}'.format(data, self)) elif not isinstance(data, int) or data != 0: - raise ValueError('input is ambiguous: ' '{} as well as imag={} ' 'specified'.format(data, imag)) + raise ValueError('input is ambiguous: {} as well as imag={} specified'.format(data, imag)) return self.element_class(self, imag) diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index e54305f2d0a..39fdf06d384 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -2122,7 +2122,7 @@ def strong_generating_system(self, base_of_group=None, implementation='sage'): """ if implementation == "gap": if base_of_group is not None: - raise ValueError("the optional argument 'base_of_group'" " (='%s') must be None if 'implementation'='gap'" % base_of_group) + raise ValueError("the optional argument 'base_of_group' (='%s') must be None if 'implementation'='gap'" % base_of_group) gap_cosets = libgap.function_factory( """function ( S0 ) @@ -2182,7 +2182,7 @@ def strong_generating_system(self, base_of_group=None, implementation='sage'): stab = stab.stabilizer(j) return sgs - raise ValueError("the optional argument 'implementation'" " (='%s') must be 'sage' or 'gap'" % implementation) + raise ValueError("the optional argument 'implementation' (='%s') must be 'sage' or 'gap'" % implementation) def _repr_(self): r""" diff --git a/src/sage/groups/perm_gps/permgroup_named.py b/src/sage/groups/perm_gps/permgroup_named.py index 8e600ce66dd..2c705717b81 100644 --- a/src/sage/groups/perm_gps/permgroup_named.py +++ b/src/sage/groups/perm_gps/permgroup_named.py @@ -3271,7 +3271,7 @@ def __init__(self, m, p=None, n=None): 384 """ if p is None: - raise NotImplementedError("exceptional complex reflection groups" " are not yet implemented") + raise NotImplementedError("exceptional complex reflection groups are not yet implemented") self._m = Integer(m) self._p = Integer(p) self._n = Integer(n) diff --git a/src/sage/groups/raag.py b/src/sage/groups/raag.py index f353254e2c2..190d0275361 100644 --- a/src/sage/groups/raag.py +++ b/src/sage/groups/raag.py @@ -13,6 +13,7 @@ - Travis Scrimshaw (2018-02-05): Made compatible with :class:`~sage.groups.artin.ArtinGroup` """ + # *************************************************************************** # Copyright (C) 2013,2018 Travis Scrimshaw # @@ -174,7 +175,7 @@ def __classcall_private__(cls, G, names=None): names = [names + str(v) for v in G.vertices(sort=False)] names = tuple(names) if len(names) != G.n_vertices(): - raise ValueError("the number of generators must match the" " number of vertices of the defining graph") + raise ValueError("the number of generators must match the number of vertices of the defining graph") return super().__classcall__(cls, G, names) def __init__(self, G, names): diff --git a/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py b/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py index 55e7279f85a..f42b23d6fb1 100644 --- a/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py +++ b/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py @@ -52,6 +52,7 @@ sage: TestSuite(S).run() sage: TestSuite(S.an_element()).run() """ + from __future__ import annotations from sage.groups.group import FiniteGroup diff --git a/src/sage/homology/chain_complex.py b/src/sage/homology/chain_complex.py index d15d0c60855..b380ca3c7d4 100644 --- a/src/sage/homology/chain_complex.py +++ b/src/sage/homology/chain_complex.py @@ -303,15 +303,14 @@ def ChainComplex(data=None, base_ring=None, grading_group=None, degree_of_differ try: prod = mat1 * mat0 except TypeError: - raise TypeError('the differentials d_{{{}}} and d_{{{}}} are not compatible: ' 'their product is not defined'.format(n, n + degree)) + raise TypeError('the differentials d_{{{}}} and d_{{{}}} are not compatible: their product is not defined'.format(n, n + degree)) if not prod.is_zero(): - raise ValueError('the differentials d_{{{}}} and d_{{{}}} are not compatible: ' 'their composition is not zero.'.format(n, n + degree)) + raise ValueError('the differentials d_{{{}}} and d_{{{}}} are not compatible: their composition is not zero.'.format(n, n + degree)) return ChainComplex_class(grading_group, degree, base_ring, data_dict) class Chain_class(ModuleElement): - def __init__(self, parent, vectors, check=True) -> None: r""" A Chain in a Chain Complex. diff --git a/src/sage/homology/chain_complex_morphism.py b/src/sage/homology/chain_complex_morphism.py index ca4af1f2694..dcdbb27f2d6 100644 --- a/src/sage/homology/chain_complex_morphism.py +++ b/src/sage/homology/chain_complex_morphism.py @@ -117,7 +117,7 @@ def __init__(self, matrices, C, D, check=True) -> None: To: Chain complex with at most 1 nonzero terms over Integer Ring """ if not C.base_ring() == D.base_ring(): - raise NotImplementedError('morphisms between chain complexes of different' ' base rings are not implemented') + raise NotImplementedError('morphisms between chain complexes of different base rings are not implemented') d = C.degree_of_differential() if d != D.degree_of_differential(): raise ValueError('degree of differential does not match') diff --git a/src/sage/homology/chains.py b/src/sage/homology/chains.py index b5c3cfc9142..ae0d63fc760 100644 --- a/src/sage/homology/chains.py +++ b/src/sage/homology/chains.py @@ -19,14 +19,12 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.combinat.free_module import CombinatorialFreeModule from sage.rings.integer_ring import ZZ from sage.structure.element import coercion_model class CellComplexReference: - def __init__(self, cell_complex, degree, cells=None) -> None: """ Auxiliary base class for chains and cochains. @@ -209,7 +207,6 @@ def chain_complex(self): ) class Element(CombinatorialFreeModule.Element): - def to_complex(self): """ Return the corresponding chain complex element. @@ -428,7 +425,6 @@ def cochain_complex(self): ) class Element(CombinatorialFreeModule.Element): - def to_complex(self): """ Return the corresponding cochain complex element. diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index 637bd8bdb77..bf99bb2e3cf 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -164,7 +164,7 @@ def __classcall_private__(cls, module, *args, graded=False, degrees=None, shifts from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular if not isinstance(S, MPolynomialRing_libsingular): - raise NotImplementedError("the matrix must be over a PID or a " " polynomial ring that is using Singular") + raise NotImplementedError("the matrix must be over a PID or a polynomial ring that is using Singular") if graded: # We are computing a graded resolution diff --git a/src/sage/homology/graded_resolution.py b/src/sage/homology/graded_resolution.py index ffcc613f434..920cb1970d9 100644 --- a/src/sage/homology/graded_resolution.py +++ b/src/sage/homology/graded_resolution.py @@ -336,7 +336,7 @@ def __init__(self, module, degrees=None, *args, **kwds) -> None: super().__init__(module, degrees=degrees, *args, **kwds) if len(self._degrees) > 1 and any(d != 1 for d in self._degrees): - raise NotImplementedError("only the natural grading supported " "when more than one generator") + raise NotImplementedError("only the natural grading supported when more than one generator") @lazy_attribute def _maps(self): diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index c1165b36d16..72c243735c3 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -588,7 +588,6 @@ def __init__(self, base_ring, cell_complex, category=None) -> None: HomologyVectorSpaceWithBasis.__init__(self, base_ring, cell_complex, cohomology=False, category=category) class Element(HomologyVectorSpaceWithBasis.Element): - def _acted_upon_(self, a, self_on_left): r""" Define multiplication of ``self`` by ``a``, an @@ -1093,7 +1092,7 @@ def Sq(self, i): self = P.sum_of_terms(self.monomial_coefficients().items()) if not isinstance(scomplex, (SimplicialComplex, SimplicialSet_arbitrary)): print(scomplex, isinstance(scomplex, SimplicialComplex)) - raise NotImplementedError('Steenrod squares are not implemented for ' 'this type of cell complex') + raise NotImplementedError('Steenrod squares are not implemented for this type of cell complex') scomplex = P.complex() base_ring = P.base_ring() if not is_GF2(base_ring): diff --git a/src/sage/interacts/algebra.py b/src/sage/interacts/algebra.py index c819b9b61bd..d86fefb51ee 100644 --- a/src/sage/interacts/algebra.py +++ b/src/sage/interacts/algebra.py @@ -16,5 +16,4 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from .library import polar_prime_spiral diff --git a/src/sage/interfaces/axiom.py b/src/sage/interfaces/axiom.py index 22c6ac563bb..0cabbf91bdc 100644 --- a/src/sage/interfaces/axiom.py +++ b/src/sage/interfaces/axiom.py @@ -974,5 +974,5 @@ def axiom_console(): from sage.repl.rich_output.display_manager import get_display_manager if not get_display_manager().is_in_terminal(): - raise RuntimeError('Can use the console only in the terminal. ' 'Try %%axiom magics instead.') + raise RuntimeError('Can use the console only in the terminal. Try %%axiom magics instead.') os.system('axiom -nox') diff --git a/src/sage/interfaces/ecm.py b/src/sage/interfaces/ecm.py index 8952a708ef0..22e6b6a3e0f 100644 --- a/src/sage/interfaces/ecm.py +++ b/src/sage/interfaces/ecm.py @@ -59,7 +59,6 @@ class ECM(SageObject): - def __init__(self, B1=10, B2=None, **kwds): r""" Create an interface to the GMP-ECM elliptic curve method diff --git a/src/sage/interfaces/expect.py b/src/sage/interfaces/expect.py index d29ebe1fff4..e1df4d44065 100644 --- a/src/sage/interfaces/expect.py +++ b/src/sage/interfaces/expect.py @@ -29,6 +29,7 @@ - François Bissey, Bill Page, Jeroen Demeyer (2015-12-09): Upgrade to pexpect 4.0.1 + patches, see :issue:`10295`. """ + # **************************************************************************** # Copyright (C) 2005 William Stein # diff --git a/src/sage/interfaces/four_ti_2.py b/src/sage/interfaces/four_ti_2.py index 449491f01a8..5ec4de31b04 100644 --- a/src/sage/interfaces/four_ti_2.py +++ b/src/sage/interfaces/four_ti_2.py @@ -472,7 +472,7 @@ def minimize(self, mat=None, lat=None): ... NotImplementedError: 4ti2 command 'minimize' not implemented in Sage. """ - raise NotImplementedError("4ti2 command 'minimize' not implemented " "in Sage.") + raise NotImplementedError("4ti2 command 'minimize' not implemented in Sage.") def groebner(self, mat=None, lat=None, project=None): r""" diff --git a/src/sage/interfaces/fricas.py b/src/sage/interfaces/fricas.py index 59b310d2785..10640ce88fe 100644 --- a/src/sage/interfaces/fricas.py +++ b/src/sage/interfaces/fricas.py @@ -244,7 +244,7 @@ ")set message type off", ")set message void off", ")set output length " + str(FRICAS_LINE_LENGTH), - ")lisp (setf |$ioHook|" " (lambda (x &optional args)" " (when (member x '(|startAlgebraOutput| |endOfAlgebraOutput|" " |startKeyedMsg| |endOfKeyedMsg|))" " (prin1 x)" " (princ #\\Newline))))", + ")lisp (setf |$ioHook| (lambda (x &optional args) (when (member x '(|startAlgebraOutput| |endOfAlgebraOutput| |startKeyedMsg| |endOfKeyedMsg|)) (prin1 x) (princ #\\Newline))))", ) # code (one-line!) executed after having set up the prompt FRICAS_HELPER_CODE = ( diff --git a/src/sage/interfaces/fricas_translator.py b/src/sage/interfaces/fricas_translator.py index 3d7658ac87a..4d388caed3c 100644 --- a/src/sage/interfaces/fricas_translator.py +++ b/src/sage/interfaces/fricas_translator.py @@ -12,6 +12,7 @@ constructs the element given the parsed string produced by ``sexport``. """ + from sage.misc.cachefunc import cached_method from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer diff --git a/src/sage/interfaces/gap.py b/src/sage/interfaces/gap.py index ec87f084ced..a922ae62d8e 100644 --- a/src/sage/interfaces/gap.py +++ b/src/sage/interfaces/gap.py @@ -557,7 +557,7 @@ def _execute_line(self, line, wait_for_prompt=True, expect_eof=False): current_outputs.append(E.before) if x == 0: # @p if E.after != b'@p1.': - warnings.warn("possibly wrong version of GAP package " "interface. Crossing fingers and continuing.") + warnings.warn("possibly wrong version of GAP package interface. Crossing fingers and continuing.") elif x == 1: # @@ current_outputs.append(b'@') elif x == 2: # special char diff --git a/src/sage/interfaces/giac.py b/src/sage/interfaces/giac.py index 340d7c9c45e..86bced35ce0 100644 --- a/src/sage/interfaces/giac.py +++ b/src/sage/interfaces/giac.py @@ -1116,7 +1116,6 @@ def _sage_(self, locals=None): result = repr(self) # string representation if str(self.type()) not in ['DOM_LIST', 'vector', 'vecteur']: - # Merge the user-specified locals dictionary and the symbol_table # (locals takes priority) lsymbols = symbol_table['giac'].copy() diff --git a/src/sage/interfaces/gp.py b/src/sage/interfaces/gp.py index 6fba791260f..ea740aa603b 100644 --- a/src/sage/interfaces/gp.py +++ b/src/sage/interfaces/gp.py @@ -1067,7 +1067,7 @@ def gp_console(): from sage.repl.rich_output.display_manager import get_display_manager if not get_display_manager().is_in_terminal(): - raise RuntimeError('Can use the console only in the terminal. ' 'Try %%gp magics instead.') + raise RuntimeError('Can use the console only in the terminal. Try %%gp magics instead.') os.system('gp') diff --git a/src/sage/interfaces/kash.py b/src/sage/interfaces/kash.py index 55e613c3489..75981438e58 100644 --- a/src/sage/interfaces/kash.py +++ b/src/sage/interfaces/kash.py @@ -772,7 +772,7 @@ def kash_console(): from sage.repl.rich_output.display_manager import get_display_manager if not get_display_manager().is_in_terminal(): - raise RuntimeError('Can use the console only in the terminal. ' 'Try %%kash magics instead.') + raise RuntimeError('Can use the console only in the terminal. Try %%kash magics instead.') os.system("kash3 ") diff --git a/src/sage/interfaces/latte.py b/src/sage/interfaces/latte.py index 6a159846a08..5e319d9f6a1 100644 --- a/src/sage/interfaces/latte.py +++ b/src/sage/interfaces/latte.py @@ -12,7 +12,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.cpython.string import str_to_bytes, bytes_to_str from subprocess import Popen, PIPE diff --git a/src/sage/interfaces/macaulay2.py b/src/sage/interfaces/macaulay2.py index b973f815beb..e431ed3150a 100644 --- a/src/sage/interfaces/macaulay2.py +++ b/src/sage/interfaces/macaulay2.py @@ -211,9 +211,12 @@ def __init__(self, maxread=None, script_subdirectory=None, logfile=None, server= # Prompt changing commands 'sageLoadMode = false;' 'ZZ#{Standard,Core#"private dictionary"#"InputPrompt"} = ' - 'ZZ#{Standard,Core#"private dictionary"#"InputContinuationPrompt"} = ' + 'lineno -> if(sageLoadMode) then "%s" else "%s";' % (PROMPT_LOAD, PROMPT) + + 'ZZ#{Standard,Core#"private dictionary"#"InputContinuationPrompt"} = ' + + 'lineno -> if(sageLoadMode) then "%s" else "%s";' % (PROMPT_LOAD, PROMPT) + + # Also prevent line wrapping in Macaulay2 - "printWidth = 0;" + + "printWidth = 0;" + + # And make all output labels to be of the same width "lineNumber = 10^9;" # Assignment of internal expect variables. @@ -376,7 +379,7 @@ class options(GlobalOptions): NAME = 'Macaulay2' module = 'sage.interfaces.macaulay2' - after_print = dict(default=False, description='append AfterPrint type information to ' 'textual representations', checker=lambda val: isinstance(val, bool)) + after_print = dict(default=False, description='append AfterPrint type information to textual representations', checker=lambda val: isinstance(val, bool)) def get(self, var): """ @@ -1006,12 +1009,10 @@ def name(self, new_name=None): m := lookup(GlobalReleaseHook, class {0}); if m =!= null then m(symbol {0}, {0}); {1} = {0}; - ))()""".format( - self._name, new_name - ) + ))()""".format(self._name, new_name) ans = P.eval(cmd) if ans.find("stdio:") != -1: - raise RuntimeError("Error evaluating Macaulay2 code.\n" "IN:%s\nOUT:%s" % (cmd, ans)) + raise RuntimeError("Error evaluating Macaulay2 code.\nIN:%s\nOUT:%s" % (cmd, ans)) return P._object_class()(P, new_name, is_name=True) def __len__(self) -> int: @@ -1776,7 +1777,7 @@ def _instancedoc_(self): ... """ P = self._obj.parent() - r = P.eval('help prepend({0}, select(methods {0}, m->' 'instance({1}, m#1)))'.format(self._name, self._obj._name)) + r = P.eval('help prepend({0}, select(methods {0}, m->instance({1}, m#1)))'.format(self._name, self._obj._name)) end = r.rfind("\n\nDIV") if end != -1: r = r[:end] diff --git a/src/sage/interfaces/maple.py b/src/sage/interfaces/maple.py index 93fbae00ee1..2bc42af1f14 100644 --- a/src/sage/interfaces/maple.py +++ b/src/sage/interfaces/maple.py @@ -911,7 +911,6 @@ def _sage_src_(self): @instancedoc class MapleElement(ExtraTabCompletion, ExpectElement): - def __float__(self) -> float: """ Return a floating point version of ``self``. diff --git a/src/sage/interfaces/maxima.py b/src/sage/interfaces/maxima.py index 85095f218fa..5b1db111a54 100644 --- a/src/sage/interfaces/maxima.py +++ b/src/sage/interfaces/maxima.py @@ -747,12 +747,12 @@ def _expect_expr(self, expr=None, timeout=None): # Note that this depends on the order of self._prompt_wait if expr is self._prompt_wait and i > len(self._ask): self.quit() - raise ValueError("{}\nComputation failed due to a bug in Maxima " "-- NOTE: Maxima had to be restarted.".format(v)) + raise ValueError("{}\nComputation failed due to a bug in Maxima -- NOTE: Maxima had to be restarted.".format(v)) j = v.find('Is ') v = v[j:] k = v.find(' ', 3) - msg = "Computation failed since Maxima requested additional " "constraints (try the command " "\"maxima.assume('{}>0')\" " "before integral or limit evaluation, for example):\n" "{}{}".format(v[3:k], v, self._after()) + msg = "Computation failed since Maxima requested additional constraints (try the command \"maxima.assume('{}>0')\" before integral or limit evaluation, for example):\n{}{}".format(v[3:k], v, self._after()) self._sendline(";") self._expect_expr() raise ValueError(msg) diff --git a/src/sage/interfaces/mupad.py b/src/sage/interfaces/mupad.py index c065e749215..fac571b8b0a 100644 --- a/src/sage/interfaces/mupad.py +++ b/src/sage/interfaces/mupad.py @@ -545,7 +545,6 @@ def __call__(self, *args): @instancedoc class MupadElement(ExtraTabCompletion, ExpectElement): - def __getattr__(self, attrname): """ EXAMPLES:: diff --git a/src/sage/interfaces/phc.py b/src/sage/interfaces/phc.py index c92028049ca..126c4cddc91 100644 --- a/src/sage/interfaces/phc.py +++ b/src/sage/interfaces/phc.py @@ -175,7 +175,6 @@ def get_variable_list(output_file_contents): class PHC_Object: - def __init__(self, output_file_contents, input_ring): """ A container for data from the PHCpack program - lists of float diff --git a/src/sage/interfaces/qepcad.py b/src/sage/interfaces/qepcad.py index 0d84d5076a6..4fce4b8738a 100644 --- a/src/sage/interfaces/qepcad.py +++ b/src/sage/interfaces/qepcad.py @@ -926,7 +926,7 @@ def assume(self, assume): if len(assume.qvars): raise ValueError("assumptions cannot be quantified") if not assume.vars.issubset(frozenset(self._varlist[: self._free_vars])): - raise ValueError("assumption contains variables not " "present in formula") + raise ValueError("assumption contains variables not present in formula") assume = repr(assume) assume = assume.replace('_', '') result = self._eval_line("assume [%s]" % assume) @@ -1008,7 +1008,7 @@ def solution_extension(self, kind): {'y + x > 0', 'y^2 + x^2 - 3 = 0'} """ if kind == 'I': - raise ValueError("Interactive solution construction not " "handled by Sage interface") + raise ValueError("Interactive solution construction not handled by Sage interface") result = self._eval_line('solution-extension %s' % kind) tagline = 'An equivalent quantifier-free formula:' loc = result.find(tagline) @@ -1415,7 +1415,7 @@ def __call__(self, *args): args[0] = 'y' if args[0] else 'n' if special == 'interactive': - raise ValueError("Cannot call %s through Sage interface... " "interactive commands not handled") + raise ValueError("Cannot call %s through Sage interface... interactive commands not handled") return self._parent._function_call(self._name, args) @@ -1666,7 +1666,7 @@ def qepcad(formula, assume=None, interact=False, solution=None, vars=None, **kwa qe.quit() for c in cells: if c._dimension > 0: - raise ValueError("input formula is true for " "infinitely many points") + raise ValueError("input formula is true for infinitely many points") return [c.sample_point_dict() for c in cells] raise ValueError(f"Unknown solution type ({solution})") @@ -1882,7 +1882,7 @@ def _combine_formulas(self, formulas): for f in formulas: vars = vars | f.vars if len(f.qvars): - raise ValueError("QEPCAD formulas must be in prenex" " (quantifiers outermost) form") + raise ValueError("QEPCAD formulas must be in prenex (quantifiers outermost) form") return formula_strs, vars def atomic(self, lhs, op='=', rhs=0): @@ -2299,7 +2299,7 @@ def quantifier(self, kind, v, formula, allow_multi=True): form_str = '[' + form_str + ']' v = str(v) if v not in formula.vars: - raise ValueError("Attempting to quantify variable which " "does not occur in formula") + raise ValueError("Attempting to quantify variable which does not occur in formula") form_str = f"({kind} {v}){form_str}" return qformula(form_str, formula.vars - frozenset([v]), [v] + formula.qvars) diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py index 26fde835e28..683a67228fc 100644 --- a/src/sage/interfaces/r.py +++ b/src/sage/interfaces/r.py @@ -1459,7 +1459,6 @@ def chdir(self, dir): @instancedoc class RElement(ExtraTabCompletion, InterfaceElement): - def _tab_completion(self): """ Return a list of all methods of this object. diff --git a/src/sage/interfaces/rubik.py b/src/sage/interfaces/rubik.py index 07d87563049..578e6a2a3a8 100644 --- a/src/sage/interfaces/rubik.py +++ b/src/sage/interfaces/rubik.py @@ -212,7 +212,6 @@ def format_cube(self, facets): class CubexSolver: - def __call__(self, facets): return self.solve(facets) @@ -264,7 +263,6 @@ def format_cube(self, facets): class DikSolver: - def __call__(self, facets): return self.solve(facets) diff --git a/src/sage/interfaces/sage0.py b/src/sage/interfaces/sage0.py index 29cd4fff7ec..fa24b22f845 100644 --- a/src/sage/interfaces/sage0.py +++ b/src/sage/interfaces/sage0.py @@ -143,7 +143,7 @@ def __init__(self, logfile=None, preparse=True, init_code=None, server=None, ser try: init_code = list(init_code) except TypeError: - raise TypeError('init_code should be a string or an iterable of lines ' 'of code') + raise TypeError('init_code should be a string or an iterable of lines of code') command = 'python3 -u' prompt = re.compile(b'>>> |sage: |In : ') @@ -421,7 +421,6 @@ def _wrap_multiline(s): @instancedoc class SageElement(ExpectElement): - def _rich_repr_(self, display_manager, **kwds): """ Disable rich output. diff --git a/src/sage/interfaces/singular.py b/src/sage/interfaces/singular.py index 609f1a822c9..dc09f1b8dd4 100644 --- a/src/sage/interfaces/singular.py +++ b/src/sage/interfaces/singular.py @@ -1330,7 +1330,6 @@ def _keyboard_interrupt(self): @instancedoc class SingularElement(ExtraTabCompletion, ExpectElement, sage.interfaces.abc.SingularElement): - def __init__(self, parent, type, value, is_name=False): """ EXAMPLES:: @@ -1880,7 +1879,6 @@ def sage_poly(self, R=None, kcache=None): return R(sage_repr) if isinstance(R, PolynomialRing_generic) and (ring_is_fine or can_convert_to_singular(R)): - sage_repr = [0] * int(self.deg() + 1) for i in range(coeff_start): @@ -2291,9 +2289,7 @@ def _instancedoc_(self): sage: groebner(singular(I)) x+y, y^2-y -""" % ( - self._name, - ) +""" % (self._name,) return prefix + get_docstring(self._name, prefix=True, code=True) @@ -2383,7 +2379,7 @@ def get_docstring(name, prefix=False, code=False): from sage.features.info import Info if not Info().is_present(): - raise OSError("GNU Info is not installed. Singular's " "documentation will not be available.") + raise OSError("GNU Info is not installed. Singular's documentation will not be available.") import subprocess cmd_and_args = ["info", f"--node={name}", "singular"] diff --git a/src/sage/interfaces/sympy.py b/src/sage/interfaces/sympy.py index af6ea0319e0..363969c01a2 100644 --- a/src/sage/interfaces/sympy.py +++ b/src/sage/interfaces/sympy.py @@ -49,6 +49,7 @@ - Ralf Stephan (2017-10) """ + ################################################################ # Distributed under GNU GPL3, see www.gnu.org ################################################################ diff --git a/src/sage/interfaces/tab_completion.py b/src/sage/interfaces/tab_completion.py index b824ab66a11..48c55c3e623 100644 --- a/src/sage/interfaces/tab_completion.py +++ b/src/sage/interfaces/tab_completion.py @@ -29,7 +29,6 @@ class ExtraTabCompletion: - def __dir__(self): """ Add to the ``dir()`` output. diff --git a/src/sage/interfaces/tides.py b/src/sage/interfaces/tides.py index 765956fa85c..07133a8d272 100644 --- a/src/sage/interfaces/tides.py +++ b/src/sage/interfaces/tides.py @@ -608,9 +608,7 @@ def genfiles_mintides(integrator, driver, f, ics, initial, final, delta, tolrel= double tolrel, tolabs, tini, tend, dt; double v[VARS], p[PARS]; - """ % ( - n - 1 - ) + """ % (n - 1) outfile.write(auxstring) for i in range(len(ics)): outfile.write('\tv[{}] = {} ; \n'.format(i, RR(ics[i]).str())) @@ -805,7 +803,7 @@ def genfiles_mpfr(integrator, driver, f, ics, initial, final, delta, parameters= if aux < n: code.append(f'mpfrts_var_t(itd, var[{aux}], var[{i}], i);') else: - code.append(f'mpfrts_var_t(itd, link[{aux-n}], var[{i}], i);') + code.append(f'mpfrts_var_t(itd, link[{aux - n}], var[{i}], i);') for i in range(len(l3)): el = l3[i] @@ -829,9 +827,9 @@ def genfiles_mpfr(integrator, driver, f, ics, initial, final, delta, parameters= elif el[0] == 'exp': string += 'exp_t(itd, ' + el[1] + f', link[{i}], i);' elif el[0] == 'sin': - string += 'sin_t(itd, ' + el[1] + f', link[{i+1}], link[{i}], i);' + string += 'sin_t(itd, ' + el[1] + f', link[{i + 1}], link[{i}], i);' elif el[0] == 'cos': - string += 'cos_t(itd, ' + el[1] + f', link[{i-1}], link[{i}], i);' + string += 'cos_t(itd, ' + el[1] + f', link[{i - 1}], link[{i}], i);' elif el[0] == 'atan': indarg = l0.index(str(1 + l2[i][1] ** 2)) - n string += 'atan_t(itd, ' + el[1] + f', link[{indarg}], link[{i}], i);' diff --git a/src/sage/knots/free_knotinfo_monoid.py b/src/sage/knots/free_knotinfo_monoid.py index e63545734b1..8c2b89f0df9 100644 --- a/src/sage/knots/free_knotinfo_monoid.py +++ b/src/sage/knots/free_knotinfo_monoid.py @@ -94,7 +94,6 @@ def to_knotinfo(self): class FreeKnotInfoMonoid(IndexedFreeAbelianMonoid): - Element = FreeKnotInfoMonoidElement @staticmethod diff --git a/src/sage/knots/gauss_code.py b/src/sage/knots/gauss_code.py index 2576d9eb225..ca5900c2edd 100644 --- a/src/sage/knots/gauss_code.py +++ b/src/sage/knots/gauss_code.py @@ -16,6 +16,7 @@ .. [Kauf1999] Louis H. Kauffman, *Virtual Knot Theory*, Europ. J. Combinatorics (1999) 20, 663-691 ; http://homepages.math.uic.edu/~kauffman/VKT.pdf """ + # **************************************************************************** # Copyright (C) 2019 Frédéric Chapoton # diff --git a/src/sage/knots/knot.py b/src/sage/knots/knot.py index d548cd1f955..373757998fb 100644 --- a/src/sage/knots/knot.py +++ b/src/sage/knots/knot.py @@ -124,7 +124,7 @@ def __init__(self, data, check=True): Link.__init__(self, data) if check: if self.number_of_components() != 1: - raise ValueError("the input has more than 1 connected " "component") + raise ValueError("the input has more than 1 connected component") def _repr_(self): """ diff --git a/src/sage/knots/knotinfo.py b/src/sage/knots/knotinfo.py index 64f6f20fd0c..872b7687761 100644 --- a/src/sage/knots/knotinfo.py +++ b/src/sage/knots/knotinfo.py @@ -232,7 +232,6 @@ # https://www.gnu.org/licenses/ ############################################################################## - from enum import Enum from sage.misc.cachefunc import cached_method from sage.misc.lazy_import import lazy_import @@ -2850,7 +2849,7 @@ def is_recoverable(self, unique=True, max_samples=8) -> bool: l = self.list(oriented=True) bound = len(l) - return all(L.is_recoverable(unique=unique) for L, in some_tuples(l, 1, bound, max_samples=max_samples)) + return all(L.is_recoverable(unique=unique) for (L,) in some_tuples(l, 1, bound, max_samples=max_samples)) def _test_recover(self, **options): r""" diff --git a/src/sage/libs/coxeter3/coxeter_group.py b/src/sage/libs/coxeter3/coxeter_group.py index 2a7b1091a4f..0ae776a80e2 100644 --- a/src/sage/libs/coxeter3/coxeter_group.py +++ b/src/sage/libs/coxeter3/coxeter_group.py @@ -677,7 +677,7 @@ def action_on_rational_function(self, f): n = W.rank() if Q.ngens() != n: - raise ValueError("the number of generators for the polynomial " "ring must be the same as the rank of the " "root system") + raise ValueError("the number of generators for the polynomial ring must be the same as the rank of the root system") basis_elements = [alpha[i] for i in W.index_set()] basis_to_order = {s: i for i, s in enumerate(W.index_set())} diff --git a/src/sage/libs/gap/context_managers.py b/src/sage/libs/gap/context_managers.py index 7321bf5f539..d3c46fc3061 100644 --- a/src/sage/libs/gap/context_managers.py +++ b/src/sage/libs/gap/context_managers.py @@ -45,7 +45,6 @@ class GlobalVariableContext: - def __init__(self, variable, value): """ Context manager for GAP global variables. diff --git a/src/sage/libs/gap/gap_functions.py b/src/sage/libs/gap/gap_functions.py index ac694ab10f9..885ce337b74 100644 --- a/src/sage/libs/gap/gap_functions.py +++ b/src/sage/libs/gap/gap_functions.py @@ -12,7 +12,6 @@ # https://www.gnu.org/licenses/ ############################################################################### - # selected gap functions to use in tab completion common_gap_functions = set( [ diff --git a/src/sage/libs/gap/gap_globals.py b/src/sage/libs/gap/gap_globals.py index 743dbfb1f90..a8cdbcbacb9 100644 --- a/src/sage/libs/gap/gap_globals.py +++ b/src/sage/libs/gap/gap_globals.py @@ -12,7 +12,6 @@ # https://www.gnu.org/licenses/ ############################################################################### - from .gap_functions import common_gap_functions diff --git a/src/sage/libs/gap/operations.py b/src/sage/libs/gap/operations.py index 96ef9266ea5..7bce9b1f027 100644 --- a/src/sage/libs/gap/operations.py +++ b/src/sage/libs/gap/operations.py @@ -28,7 +28,6 @@ class OperationInspector(SageObject): - def __init__(self, libgap_element): """ Information about operations that can act on a given LibGAP element. diff --git a/src/sage/libs/lrcalc/lrcalc.py b/src/sage/libs/lrcalc/lrcalc.py index 9282bd7816b..0f920b28440 100644 --- a/src/sage/libs/lrcalc/lrcalc.py +++ b/src/sage/libs/lrcalc/lrcalc.py @@ -330,7 +330,7 @@ def mult(part1, part2, maxrows=None, level=None, quantum=None) -> dict: ValueError: missing parameters maxrows or level """ if maxrows is None and level is not None: - raise ValueError('maxrows needs to be specified if you specify' ' the level') + raise ValueError('maxrows needs to be specified if you specify the level') if quantum is not None and (level is None or maxrows is None): raise ValueError('missing parameters maxrows or level') diff --git a/src/sage/manifolds/continuous_map.py b/src/sage/manifolds/continuous_map.py index 5a2720bad80..c582d21ab08 100644 --- a/src/sage/manifolds/continuous_map.py +++ b/src/sage/manifolds/continuous_map.py @@ -411,7 +411,7 @@ def __init__( if is_isomorphism: self._is_isomorphism = True if domain.dim() != codomain.dim(): - raise ValueError("for an isomorphism, the source" " manifold and target manifold must" " have the same dimension") + raise ValueError("for an isomorphism, the source manifold and target manifold must have the same dimension") if coord_functions is not None: n2 = self._codomain.dim() for chart_pair, expression in coord_functions.items(): @@ -1857,9 +1857,9 @@ def restrict(self, subdomain, subcodomain=None): return self if (subdomain, subcodomain) not in self._restrictions: if not subdomain.is_subset(self._domain): - raise ValueError("the specified domain is not a subset" " of the domain of definition of the" " continuous map") + raise ValueError("the specified domain is not a subset of the domain of definition of the continuous map") if not subcodomain.is_subset(self._codomain): - raise ValueError("the specified codomain is not a subset" " of the codomain of the continuous map") + raise ValueError("the specified codomain is not a subset of the codomain of the continuous map") # Special case of the identity map: if self._is_identity: self._restrictions[(subdomain, subcodomain)] = subdomain.identity_map() diff --git a/src/sage/manifolds/differentiable/affine_connection.py b/src/sage/manifolds/differentiable/affine_connection.py index 0c9143f3144..5352fbe61df 100644 --- a/src/sage/manifolds/differentiable/affine_connection.py +++ b/src/sage/manifolds/differentiable/affine_connection.py @@ -768,7 +768,7 @@ class :class:`~sage.tensor.modules.comp.Components`; if such To keep them, use the method :meth:`add_coef` instead. """ if self.is_immutable(): - raise ValueError("the coefficients of an immutable element " "cannot be changed") + raise ValueError("the coefficients of an immutable element cannot be changed") if frame is None: frame = self._domain._def_frame if frame not in self._coefficients: @@ -855,7 +855,7 @@ class :class:`~sage.tensor.modules.comp.Components`; if such To delete them, use the method :meth:`set_coef` instead. """ if self.is_immutable(): - raise ValueError("the coefficients of an immutable element " "cannot be changed") + raise ValueError("the coefficients of an immutable element cannot be changed") if frame is None: frame = self._domain._def_frame if frame not in self._coefficients: @@ -2423,5 +2423,5 @@ def __hash__(self): 2 """ if self.is_mutable(): - raise ValueError('element must be immutable in order to be ' 'hashable') + raise ValueError('element must be immutable in order to be hashable') return hash((type(self).__name__, self._domain)) diff --git a/src/sage/manifolds/differentiable/bundle_connection.py b/src/sage/manifolds/differentiable/bundle_connection.py index 4803dc1b253..1d596fbcad4 100644 --- a/src/sage/manifolds/differentiable/bundle_connection.py +++ b/src/sage/manifolds/differentiable/bundle_connection.py @@ -1110,7 +1110,7 @@ def __getitem__(self, args): if isinstance(indices, slice): if indices.start is None and indices.stop is None: return [[self.connection_form(i, j, frame=frame) for j in vb.irange()] for i in vb.irange()] - raise NotImplementedError("[start:stop] syntax not " "implemented") + raise NotImplementedError("[start:stop] syntax not implemented") if len(indices) != 2: raise ValueError("index must be a pair of integers") (i, j) = indices @@ -1201,23 +1201,23 @@ def __setitem__(self, args, value): for j in vb.irange(): self[frame, i, j] = 0 elif not isinstance(value, (list, tuple)): - raise TypeError("in case of [:] syntax, zero or a " "list/tuple as value should be provided") + raise TypeError("in case of [:] syntax, zero or a list/tuple as value should be provided") elif any(not isinstance(row, (list, tuple)) for row in value): - raise TypeError("in case of [:] syntax, the list/tuple " "of value must contain lists/tuples") + raise TypeError("in case of [:] syntax, the list/tuple of value must contain lists/tuples") else: # check lengths: rk = vb._rank if len(value) != rk: - raise ValueError("value must have " "length {}".format(rk)) + raise ValueError("value must have length {}".format(rk)) if any(len(row) != rk for row in value): - raise ValueError("lists in value must have length " "{}".format(rk)) + raise ValueError("lists in value must have length {}".format(rk)) # perform designation: sind = vb._base_space._sindex for i in vb.irange(): for j in vb.irange(): self[frame, i, j] = value[i - sind][j - sind] else: - raise NotImplementedError("[start:stop] syntax not " "implemented") + raise NotImplementedError("[start:stop] syntax not implemented") def display(self, frame=None, vector_frame=None, chart=None, only_nonzero=True): r""" diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 2ce1e014b03..de920fadeb4 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -765,7 +765,7 @@ def __init__(self, base, vbundle): self._algorithm = PontryaginEulerAlgorithm() # TODO: add relation e^2=p_k for dim=2*k else: - raise TypeError(f'Characteristic cohomology classes not supported ' f'for vector bundles with ' f'field type {vbundle._field_type}') + raise TypeError(f'Characteristic cohomology classes not supported for vector bundles with field type {vbundle._field_type}') if not names or not degrees: raise ValueError('cannot find any generators') @@ -807,7 +807,7 @@ def _element_constructor_(self, x, **kwargs): elif x in self._indices: d = {self._indices(x): R.one()} else: - raise TypeError(f"do not know how to make x (= {x}) " f"an element of self (={self})") + raise TypeError(f"do not know how to make x (= {x}) an element of self (={self})") name, latex_name = kwargs.get('name'), kwargs.get('latex_name') return self.element_class(self, d, name=name, latex_name=latex_name) @@ -971,7 +971,7 @@ def _build_element(self, *args, **kwargs): # turn polynomial into a characteristic cohomology class via sequences if isinstance(val, Polynomial): if class_type is None: - raise TypeError(f'class_type must be stated if {val} ' f'is a polynomial') + raise TypeError(f'class_type must be stated if {val} is a polynomial') n = self.ngens() s = 0 # shift; important in case of Euler class generator if self._algorithm is PontryaginEulerAlgorithm(): @@ -1590,14 +1590,14 @@ def get(self, nab): - [Baer2020]_ """ if not isinstance(nab, LeviCivitaConnection): - raise TypeError('Euler forms are currently only supported for ' 'Levi-Civita connections') + raise TypeError('Euler forms are currently only supported for Levi-Civita connections') dom = nab._domain vbundle = dom.tangent_bundle() rk = vbundle._rank if not vbundle.has_orientation(): - raise ValueError('Euler forms can only be defined for orientable ' 'vector bundles') + raise ValueError('Euler forms can only be defined for orientable vector bundles') if rk % 2 != 0: - raise ValueError('Euler forms are currently only supported for ' 'vector bundles with even rank') + raise ValueError('Euler forms are currently only supported for vector bundles with even rank') res = dom.diff_form(rk) g = nab._metric for frame in dom._get_min_covering(vbundle.orientation()): diff --git a/src/sage/manifolds/differentiable/degenerate_submanifold.py b/src/sage/manifolds/differentiable/degenerate_submanifold.py index d7b941d454f..56a49b3cb07 100644 --- a/src/sage/manifolds/differentiable/degenerate_submanifold.py +++ b/src/sage/manifolds/differentiable/degenerate_submanifold.py @@ -261,10 +261,10 @@ def __init__(self, n, name, ambient=None, metric_name=None, signature=None, base ndim = self._ambient._dim try: if signature[0] == ndim or signature[1] == ndim: - raise ValueError("ambient must be a proper pseudo-Riemannian" " or a degenerate manifold") + raise ValueError("ambient must be a proper pseudo-Riemannian or a degenerate manifold") except TypeError: if signature == ndim or signature == -ndim: - raise ValueError("ambient must be a proper pseudo-Riemannian" " or a degenerate manifold") + raise ValueError("ambient must be a proper pseudo-Riemannian or a degenerate manifold") self._transverse = {} def _repr_(self): @@ -287,8 +287,8 @@ def _repr_(self): if self._ambient is None: return super(DegenerateManifold, self).__repr__() if self._ambient._dim - self._dim == 1: - return "degenerate hypersurface {} embedded " "in {}-dimensional differentiable " "manifold {}".format(self._name, self._ambient._dim, self._ambient._name) - return "{}-dimensional degenerate submanifold {} embedded " "in {}-dimensional differentiable " "manifold {}".format(self._dim, self._name, self._ambient._dim, self._ambient._name) + return "degenerate hypersurface {} embedded in {}-dimensional differentiable manifold {}".format(self._name, self._ambient._dim, self._ambient._name) + return "{}-dimensional degenerate submanifold {} embedded in {}-dimensional differentiable manifold {}".format(self._dim, self._name, self._ambient._dim, self._ambient._name) def ambient_metric(self): r""" @@ -315,7 +315,7 @@ def ambient_metric(self): """ if self._ambient_metric is None: if not self._embedded or not isinstance(self._ambient, (PseudoRiemannianManifold, DegenerateManifold)): - raise ValueError("degenerate submanifold must be embedded in a " "pseudo-Riemannian or degenerate manifold") + raise ValueError("degenerate submanifold must be embedded in a pseudo-Riemannian or degenerate manifold") self._ambient_metric = self._ambient.metric() return self._ambient_metric @@ -527,7 +527,7 @@ def screen(self, name, screen, rad, latex_name=None): if name in self._screens: if list(screen) == self._screens[name]._screen and list(rad) == self._screens[name]._rad: return self._screens[name] - raise ValueError("a different screen distribution with the " "same name had already been set") + raise ValueError("a different screen distribution with the same name had already been set") if len(screen) + len(rad) != self._dim: raise ValueError("total length screen+rad must be {}".format(self._dim)) frame = self.default_frame() @@ -968,7 +968,7 @@ def projection(self, tensor, screen=None): sage: U1 = S.projection(U) # long time """ if tensor.tensor_type()[0] != 1: - raise NotImplementedError("``projection`` is implemented only for " "tensors with 1 as contravariant order") + raise NotImplementedError("``projection`` is implemented only for tensors with 1 as contravariant order") return TangentTensor(tensor, self.immersion(), screen) def screen_projection(self, tensor, screen=None): @@ -1185,7 +1185,7 @@ def gauss_curvature(self, screen=None): (u, v, w) ↦ 0 """ if self._ambient._dim - self._dim != 1: - raise ValueError("'gauss_curvature' is defined" " only for hypersurfaces.") + raise ValueError("'gauss_curvature' is defined only for hypersurfaces.") if screen is None: screen = self.default_screen() if screen._name not in self._gauss_curvature: diff --git a/src/sage/manifolds/differentiable/examples/sphere.py b/src/sage/manifolds/differentiable/examples/sphere.py index 48eec8ecafb..bfe6a3adec2 100644 --- a/src/sage/manifolds/differentiable/examples/sphere.py +++ b/src/sage/manifolds/differentiable/examples/sphere.py @@ -415,7 +415,7 @@ def _repr_(self): sage: S2_3 # indirect doctest 2-sphere S^2_3 of radius 3 smoothly embedded in the Euclidean space E^3 """ - s = "{}-sphere {} of radius {} smoothly embedded in " "the {}".format(self._dim, self._name, self._radius, self._ambient) + s = "{}-sphere {} of radius {} smoothly embedded in the {}".format(self._dim, self._name, self._radius, self._ambient) if self._center._name: s += ' centered at the Point {}'.format(self._center._name) return s diff --git a/src/sage/manifolds/differentiable/integrated_curve.py b/src/sage/manifolds/differentiable/integrated_curve.py index 3d2863363fe..040c2817362 100644 --- a/src/sage/manifolds/differentiable/integrated_curve.py +++ b/src/sage/manifolds/differentiable/integrated_curve.py @@ -1076,7 +1076,7 @@ def solve(self, step=None, method='odeint', solution_key=None, parameters_values if self._parameters: if parameters_values is None or len(parameters_values) != len(self._parameters): - raise ValueError("numerical values should be " + "provided for each of the " + "parameters " "{}".format(sorted(self._parameters, key=str))) + raise ValueError("numerical values should be " + "provided for each of the " + "parameters {}".format(sorted(self._parameters, key=str))) for key in parameters_values: # Get numerical values in case some parameters values # contain expressions such as pi; will raise error if @@ -1550,7 +1550,7 @@ def solve_across_charts(self, charts=None, step=None, solution_key=None, paramet else: for c in charts: if not isinstance(c, Chart) or c.domain() is not self._codomain: - raise ValueError("'charts' needs to be a list of " "charts of the manifold") + raise ValueError("'charts' needs to be a list of charts of the manifold") print("Integration will take place on {} charts.".format(len(charts))) if solution_key is None: @@ -1573,7 +1573,6 @@ def solve_across_charts(self, charts=None, step=None, solution_key=None, paramet # of the initial point are known. for ichart in set(initial_pt._coordinates.keys()).intersection(charts): - initial_chart = ichart initial_pt_coords = list(initial_pt.coordinates(initial_chart)) @@ -1587,7 +1586,7 @@ def solve_across_charts(self, charts=None, step=None, solution_key=None, paramet if self._parameters: if parameters_values is None or len(parameters_values) != len(self._parameters): - raise ValueError("numerical values should be " + "provided for each of the " + "parameters " "{}".format(sorted(self._parameters, key=str))) + raise ValueError("numerical values should be " + "provided for each of the " + "parameters {}".format(sorted(self._parameters, key=str))) for key in parameters_values: parameters_values[key] = numerical_approx(parameters_values[key]) @@ -1657,7 +1656,6 @@ def solve_across_charts(self, charts=None, step=None, solution_key=None, paramet # Integration loop while i < nt: - current_sol = r.integrate(times[i]) if not r.successful(): raise RuntimeError("unsuccessful integration") @@ -1676,7 +1674,6 @@ def solve_across_charts(self, charts=None, step=None, solution_key=None, paramet for new_chart in random_order: tried_charts.add(new_chart) if new_chart not in chart._subcharts: # includes new != old - inter = chart.domain().intersection(new_chart.domain()) # The change of chart is performed here @@ -1892,7 +1889,7 @@ def interpolate(self, solution_key=None, method=None, interpolation_key=None, ve if method is None: method = 'cubic spline' if verbose: - print("Performing cubic spline interpolation by " "default...") + print("Performing cubic spline interpolation by default...") if interpolation_key is None: interpolation_key = "{}-interp-".format(method) @@ -2264,7 +2261,7 @@ def plot_integrated(self, chart=None, ambient_coords=None, mapping=None, prange= interpolation_key = key break else: - raise ValueError("Did you forget to " "integrate or interpolate the result?") + raise ValueError("Did you forget to integrate or interpolate the result?") else: interpolation_key = next(iter(self._interpolations)) # will raise error if self._interpolations empty @@ -3231,7 +3228,6 @@ def __init__(self, parent, affine_connection, curve_parameter, initial_tangent_v self._across_charts = across_charts if not across_charts: - equations_rhs = [] gamma = affine_connection.coef(frame=chart.frame()) diff --git a/src/sage/manifolds/differentiable/manifold.py b/src/sage/manifolds/differentiable/manifold.py index 4323af263a5..8065f0ec65f 100644 --- a/src/sage/manifolds/differentiable/manifold.py +++ b/src/sage/manifolds/differentiable/manifold.py @@ -2681,7 +2681,7 @@ def set_orientation(self, orientation): else: orientation = list(orientation) else: - raise TypeError("orientation must be a chart/frame or a " "list/tuple of charts/frames") + raise TypeError("orientation must be a chart/frame or a list/tuple of charts/frames") dom_union = None for frame in orientation: if not isinstance(frame, VectorFrame): @@ -3121,7 +3121,7 @@ def vector_frame(self, *args, **kwargs) -> VectorFrame: if n_args == 2: vector_fields = args[1] elif n_args > 2: - raise TypeError("vector_frame() takes at most two positional " "arguments") + raise TypeError("vector_frame() takes at most two positional arguments") latex_symbol = kwargs.pop('latex_symbol', None) dest_map = kwargs.pop('dest_map', None) from_frame = kwargs.pop('from_frame', None) @@ -3143,7 +3143,7 @@ def vector_frame(self, *args, **kwargs) -> VectorFrame: except ArithmeticError as err: linked = str(err) in ["non-invertible matrix", "input matrix must be nonsingular"] if linked: - raise ValueError("the provided vector fields are not " "linearly independent") + raise ValueError("the provided vector fields are not linearly independent") # Adding the newly generated changes of frame to the # dictionary _frame_changes of self and its supersets: for frame_pair, chge in resu._fmodule._basis_changes.items(): diff --git a/src/sage/manifolds/differentiable/metric.py b/src/sage/manifolds/differentiable/metric.py index 9df60cd26dc..8eeb93a30ed 100644 --- a/src/sage/manifolds/differentiable/metric.py +++ b/src/sage/manifolds/differentiable/metric.py @@ -1737,7 +1737,7 @@ def volume_form(self, contra=0): if not orient: raise ValueError('{} must admit an orientation'.format(dom)) if contra > ndim: - raise ValueError('The number of contravariant indices is greater ' 'than the manifold dimension') + raise ValueError('The number of contravariant indices is greater than the manifold dimension') if self._vol_forms == []: # a new computation is necessary # The result is constructed on the vector field module, diff --git a/src/sage/manifolds/differentiable/mixed_form.py b/src/sage/manifolds/differentiable/mixed_form.py index ac4a1450066..ab323bcdb37 100644 --- a/src/sage/manifolds/differentiable/mixed_form.py +++ b/src/sage/manifolds/differentiable/mixed_form.py @@ -605,7 +605,7 @@ def set_name(self, name=None, latex_name=None, apply_to_comp=True): eta = g + F_1 + F_2 + F_3 + F_4 """ if self.is_immutable(): - raise ValueError("the name of an immutable element " "cannot be changed") + raise ValueError("the name of an immutable element cannot be changed") if name is not None: self._name = name if latex_name is None: @@ -1199,7 +1199,7 @@ def __setitem__(self, index, values): A = x + y dx + x*y dx∧dy """ if self.is_immutable(): - raise ValueError("the components of an immutable element " "cannot be changed") + raise ValueError("the components of an immutable element cannot be changed") if isinstance(index, (int, Integer)): start, stop, step = index, index + 1, 1 elif isinstance(index, slice): @@ -1305,7 +1305,7 @@ def set_restriction(self, rst): if not isinstance(rst, MixedForm): raise TypeError("the argument must be a mixed form") if not rst._domain.is_subset(self._domain): - raise ValueError("the specified domain is not a subset of " "the domain of definition of the mixed form") + raise ValueError("the specified domain is not a subset of the domain of definition of the mixed form") for j in self.irange(): self[j].set_restriction(rst[j]) self._is_zero = False # a priori diff --git a/src/sage/manifolds/differentiable/mixed_form_algebra.py b/src/sage/manifolds/differentiable/mixed_form_algebra.py index bdb2c1262b4..ab08375fe47 100644 --- a/src/sage/manifolds/differentiable/mixed_form_algebra.py +++ b/src/sage/manifolds/differentiable/mixed_form_algebra.py @@ -226,7 +226,7 @@ def _element_constructor_(self, comp, name=None, latex_name=None): res = self.element_class(self, name=name, latex_name=latex_name) if isinstance(comp, (tuple, list)): if len(comp) != self._max_deg + 1: - raise IndexError("input list must have " "length {}".format(self._max_deg + 1)) + raise IndexError("input list must have length {}".format(self._max_deg + 1)) if isinstance(comp, tuple): comp = list(comp) res[:] = comp[:] @@ -238,7 +238,7 @@ def _element_constructor_(self, comp, name=None, latex_name=None): deg = d break else: - raise TypeError("cannot convert {} into an element of " "the {}".format(comp, self)) + raise TypeError("cannot convert {} into an element of the {}".format(comp, self)) # fill up with zeroes: res[:] = [0] * (self._max_deg + 1) # set comp where it belongs: diff --git a/src/sage/manifolds/differentiable/poisson_tensor.py b/src/sage/manifolds/differentiable/poisson_tensor.py index 0027e4db1f0..4c67f3917e2 100644 --- a/src/sage/manifolds/differentiable/poisson_tensor.py +++ b/src/sage/manifolds/differentiable/poisson_tensor.py @@ -15,7 +15,6 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** - from typing import Optional, Union from sage.manifolds.differentiable.diff_form import DiffForm diff --git a/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py b/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py index 63455dafc6f..ca21c24d1f2 100644 --- a/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +++ b/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py @@ -646,7 +646,7 @@ def difft(self): z/sqrt(x^2 + y^2 + z^2) dz """ if self._dim_foliation == 0: - raise ValueError("A foliation is needed to " "perform this calculation") + raise ValueError("A foliation is needed to perform this calculation") self._difft = self._t_inverse[self._var[0]].differential() self._difft.set_name("d" + self._var[0]._repr_(), r"\mathrm{d}" + self._var[0]._latex_()) return self._difft @@ -688,7 +688,7 @@ def gradt(self): + z/sqrt(x^2 + y^2 + z^2) e_z """ if self._dim_foliation == 0: - raise ValueError("A foliation is needed to perform " "this calculation") + raise ValueError("A foliation is needed to perform this calculation") param = self._var[0] self._gradt = self._t_inverse[param].gradient() self._gradt.set_name("grad({})".format(param), r"\mathrm{grad}\left(" + param._latex_() + r"\right)") @@ -937,7 +937,7 @@ def ambient_first_fundamental_form(self): [-2*x/(x^2 + 4) 4/(x^2 + 4)] """ if self._ambient._dim - self._dim != 1: - raise NotImplementedError("ambient_first_fundamental_form() is " "implemented only for hypersurfaces") + raise NotImplementedError("ambient_first_fundamental_form() is implemented only for hypersurfaces") if self._ambient_first_fundamental_form is None: g = self.ambient_metric() if self._dim_foliation == 0: # case no foliation @@ -985,7 +985,7 @@ def lapse(self): (th_E3, ph_E3, r_E3) ↦ 1 """ if self._dim_foliation == 0: - raise ValueError("A foliation is needed " "to perform this calculation") + raise ValueError("A foliation is needed to perform this calculation") self._lapse = 1 / (self._sgn * self.ambient_metric()(self.gradt(), self.gradt())).sqrt() self._lapse.set_name("N") return self._lapse @@ -1026,7 +1026,7 @@ def shift(self): beta = 0 """ if self._dim_foliation == 0: - raise ValueError("A foliation is needed " "to perform this calculation") + raise ValueError("A foliation is needed to perform this calculation") sia = self._ambient._sindex self._shift = self._adapted_charts[0].frame()[self._dim + sia] - self.lapse() * self.normal() self._shift.set_name("beta", r"\beta") @@ -1080,7 +1080,7 @@ def ambient_second_fundamental_form(self): [ 2*x/(x^2 + 4) -4/(x^2 + 4)] """ if self._ambient._dim - self._dim != 1: - raise ValueError("ambient_second_fundamental_form is defined only " "for hypersurfaces") + raise ValueError("ambient_second_fundamental_form is defined only for hypersurfaces") if self._ambient_second_fundamental_form is None: if self._dim_foliation == 0: self._ambient_second_fundamental_form = self.tensor_field(0, 2, sym=[(0, 1)], dest_map=self._immersion) @@ -1253,7 +1253,7 @@ def projector(self): 0 """ if self._ambient._dim - self._dim != 1: - raise NotImplementedError("projector() is implemented only for " "hypersurfaces") + raise NotImplementedError("projector() is implemented only for hypersurfaces") g = self.ambient_metric().inverse() if self._dim_foliation == 0: g = g.along(self._immersion) @@ -1308,7 +1308,7 @@ def project(self, tensor): Note that the output of ``project()`` is not cached. """ if self._ambient._dim - self._dim != 1: - raise NotImplementedError("project() is implemented only for " "hypersurfaces") + raise NotImplementedError("project() is implemented only for hypersurfaces") resu = tensor.copy() resu.set_name(tensor._name + "_" + self._name, r"{" + tensor._latex_() + r"}_{" + self._latex_() + r"}") for i in range(tensor.tensor_type()[0]): @@ -1387,7 +1387,7 @@ def mixed_projection(self, tensor, indices=0): (th_E3, ph_E3, r_E3) ↦ 1 """ if self._ambient._dim - self._dim != 1: - raise NotImplementedError("mixed_projection() is implemented only " "for hypersurfaces") + raise NotImplementedError("mixed_projection() is implemented only for hypersurfaces") if isinstance(indices, (Integer, int)): indices = list(range(indices)) @@ -1456,7 +1456,7 @@ def gauss_curvature(self): on V: y ↦ -1 """ if self._ambient._dim - self._dim != 1: - raise ValueError("gauss_curvature is defined only for " "hypersurfaces") + raise ValueError("gauss_curvature is defined only for hypersurfaces") a = self.shape_operator() self._gauss_curvature = self.scalar_field({chart: a[chart.frame(), :, chart].determinant() for chart in self.top_charts()}) return self._gauss_curvature @@ -1510,7 +1510,7 @@ def principal_directions(self, chart): e_0 = ∂/∂x """ if self._ambient._dim - self._dim != 1: - raise ValueError("principal directions is defined only for " "hypersurfaces") + raise ValueError("principal directions is defined only for hypersurfaces") a = self.shape_operator() pr_d = matrix([[a[chart.frame(), :, chart][i, j].expr() for i in self.irange()] for j in self.irange()]).eigenvectors_right() res = [] @@ -1575,7 +1575,7 @@ def principal_curvatures(self, chart): on W: y ↦ -1 """ if self._ambient._dim - self._dim != 1: - raise ValueError("principal_curvatures is defined only for " "hypersurfaces") + raise ValueError("principal_curvatures is defined only for hypersurfaces") a = self.shape_operator() res = matrix([[a[chart.frame(), :, chart][i, j].expr() for i in self.irange()] for j in self.irange()]).eigenvalues() counter = self.irange() @@ -1626,7 +1626,7 @@ def mean_curvature(self): on V: y ↦ -1 """ if self._ambient._dim - self._dim != 1: - raise ValueError("mean_curvature is defined only for " "hypersurfaces") + raise ValueError("mean_curvature is defined only for hypersurfaces") self._shape_operator = self.scalar_field({chart: self._sgn * sum(self.principal_curvatures(chart)).expr(chart) / self._dim for chart in self.top_charts()}) return self._shape_operator @@ -1673,7 +1673,7 @@ def shape_operator(self): -∂/∂x⊗dx """ if self._ambient._dim - self._dim != 1: - raise ValueError("shape_operator is defined only for " "hypersurfaces") + raise ValueError("shape_operator is defined only for hypersurfaces") self._shape_operator = self.second_fundamental_form().contract(self.induced_metric().inverse()) return self._shape_operator diff --git a/src/sage/manifolds/differentiable/tangent_vector.py b/src/sage/manifolds/differentiable/tangent_vector.py index 29e8c047074..dfc2d2536a3 100644 --- a/src/sage/manifolds/differentiable/tangent_vector.py +++ b/src/sage/manifolds/differentiable/tangent_vector.py @@ -595,9 +595,9 @@ def __call__(self, f): if isinstance(f, FreeModuleAltForm): # Case of self acting on a linear form if f.tensor_type() != (0, 1): - raise TypeError("the argument of __call__ must be a linear form, " "not {}".format(f)) + raise TypeError("the argument of __call__ must be a linear form, not {}".format(f)) return f(self) if not isinstance(f, DiffScalarField): - raise TypeError("the argument of __call__ must be either a linear " "form or a scalar field, not {}".format(f)) + raise TypeError("the argument of __call__ must be either a linear form or a scalar field, not {}".format(f)) # Case of self acting on a scalar field return f.differential().at(self._point)(self) diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py index cdb32e07c04..32d4967efa6 100644 --- a/src/sage/manifolds/differentiable/tensorfield.py +++ b/src/sage/manifolds/differentiable/tensorfield.py @@ -623,7 +623,7 @@ def set_name(self, name: Optional[str] = None, latex_name: Optional[str] = None) a """ if self.is_immutable(): - raise ValueError("the name of an immutable element " "cannot be changed") + raise ValueError("the name of an immutable element cannot be changed") if name is not None: self._name = name if latex_name is None: @@ -972,7 +972,7 @@ def set_restriction(self, rst: TensorField): True """ if self.is_immutable(): - raise ValueError("the restrictions of an immutable element " "cannot be changed") + raise ValueError("the restrictions of an immutable element cannot be changed") if not isinstance(rst, TensorField): raise TypeError("the argument must be a tensor field") if not rst._domain.is_subset(self._domain): @@ -1263,7 +1263,7 @@ def set_comp(self, basis=None): changed """ if self.is_immutable(): - raise ValueError("the components of an immutable element " "cannot be changed") + raise ValueError("the components of an immutable element cannot be changed") self._is_zero = False # a priori if basis is None: basis = self._domain._def_frame @@ -1390,7 +1390,7 @@ def add_comp(self, basis=None) -> Components: changed """ if self.is_immutable(): - raise ValueError("the components of an immutable element " "cannot be changed") + raise ValueError("the components of an immutable element cannot be changed") self._is_zero = False # a priori if basis is None: basis = self._domain._def_frame @@ -1463,7 +1463,7 @@ def add_comp_by_continuation(self, frame, subdomain, chart=None): and `a` is defined on the entire manifold `S^2`. """ if self.is_immutable(): - raise ValueError("the components of an immutable element " "cannot be changed") + raise ValueError("the components of an immutable element cannot be changed") dom = frame._domain if not dom.is_subset(self._domain): raise ValueError("the vector frame is not defined on a subset " + "of the tensor field domain") @@ -1560,12 +1560,12 @@ def add_expr_from_subdomain(self, frame, subdomain): on V: (xp, yp) ↦ 1/(xp^2 + yp^2) """ if self.is_immutable(): - raise ValueError("the expressions of an immutable element " "cannot be changed") + raise ValueError("the expressions of an immutable element cannot be changed") dom = frame._domain if not dom.is_subset(self._domain): raise ValueError("the vector frame is not defined on a subset " + "of the tensor field domain") if frame not in self.restrict(frame.domain())._components: - raise ValueError("the tensor doesn't have an expression in " "the frame" + frame._repr_()) + raise ValueError("the tensor doesn't have an expression in the frame" + frame._repr_()) comp = self._add_comp_unsafe(frame) # the components stay the same scomp = self.restrict(subdomain).comp(frame.restrict(subdomain)) for ind in comp.non_redundant_index_generator(): @@ -2034,9 +2034,9 @@ def copy_from(self, other): False """ if self.is_immutable(): - raise ValueError("the components of an immutable element " "cannot be changed") + raise ValueError("the components of an immutable element cannot be changed") if other not in self.parent(): - raise TypeError("the original must be an element of " f"{self.parent()}") + raise TypeError(f"the original must be an element of {self.parent()}") self._del_derived() self._del_restrictions() # delete restrictions for dom, rst in other._restrictions.items(): diff --git a/src/sage/manifolds/differentiable/tensorfield_paral.py b/src/sage/manifolds/differentiable/tensorfield_paral.py index 128314afb60..e92af60bfb0 100644 --- a/src/sage/manifolds/differentiable/tensorfield_paral.py +++ b/src/sage/manifolds/differentiable/tensorfield_paral.py @@ -913,7 +913,7 @@ class :class:`~sage.tensor.modules.comp.Components`; if such in the Vector frame (M, (e_0,e_1)) """ if self.is_immutable(): - raise ValueError("the components of an immutable element " "cannot be changed") + raise ValueError("the components of an immutable element cannot be changed") if basis is None: basis = self._fmodule._def_basis @@ -1088,7 +1088,7 @@ class :class:`~sage.tensor.modules.comp.Components`; if such t = x e_0⊗e^1 """ if self.is_immutable(): - raise ValueError("the components of an immutable element " "cannot be changed") + raise ValueError("the components of an immutable element cannot be changed") if basis is None: basis = self._fmodule._def_basis @@ -1404,7 +1404,6 @@ def lie_derivative(self, vector): # get n processes nproc = Parallelism().get('tensor') if nproc != 1: - # Parallel computation lol = lambda lst, sz: [lst[i : i + sz] for i in range(0, len(lst), sz)] ind_list = list(resc.non_redundant_index_generator()) diff --git a/src/sage/manifolds/differentiable/vector_bundle.py b/src/sage/manifolds/differentiable/vector_bundle.py index fb2a93166f1..7b707286bb3 100644 --- a/src/sage/manifolds/differentiable/vector_bundle.py +++ b/src/sage/manifolds/differentiable/vector_bundle.py @@ -769,7 +769,7 @@ def set_change_of_frame(self, frame1, frame2, change_of_frame, compute_inverse=T [0 3] """ if not frame1._domain.is_subset(self._ambient_domain): - raise ValueError("the frames must be defined on a subset of " "the {}".format(self._ambient_domain)) + raise ValueError("the frames must be defined on a subset of the {}".format(self._ambient_domain)) frame1._domain.set_change_of_frame(frame1=frame1, frame2=frame2, change_of_frame=change_of_frame, compute_inverse=compute_inverse) def change_of_frame(self, frame1, frame2): diff --git a/src/sage/manifolds/differentiable/vectorfield.py b/src/sage/manifolds/differentiable/vectorfield.py index ad3d5611e05..f8a7736c7c8 100644 --- a/src/sage/manifolds/differentiable/vectorfield.py +++ b/src/sage/manifolds/differentiable/vectorfield.py @@ -347,7 +347,7 @@ def __call__(self, scalar): else: name = None if self._latex_name is not None and scalar._latex_name is not None: - latex_name = fr"{self._latex_name}\left({scalar._latex_name}\right)" + latex_name = rf"{self._latex_name}\left({scalar._latex_name}\right)" else: latex_name = None resu.set_name(name=name, latex_name=latex_name) @@ -785,7 +785,6 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, chart_domain=None, xx[ind_coord[i]] = xmin[i] + ind[i] * step_tab[i] if chart_domain.valid_coordinates(*xx, tolerance=1e-13, parameters=parameters): - # needed a xx*1 to copy the list by value list_xx.append(xx * 1) diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index 2d9bfca08e2..b27578a6d0d 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -2191,11 +2191,11 @@ def tensor_from_comp(self, tensor_type, comp, name=None, latex_name=None): # 0/ Compatibility checks: if comp._ring is not self._ring: - raise ValueError("the components are not defined on the " "same ring as the module") + raise ValueError("the components are not defined on the same ring as the module") if comp._frame not in self._known_bases: - raise ValueError("the components are not defined on a " "basis of the module") + raise ValueError("the components are not defined on a basis of the module") if comp._nid != tensor_type[0] + tensor_type[1]: - raise ValueError("number of component indices not " "compatible with the tensor type") + raise ValueError("number of component indices not compatible with the tensor type") # # 1/ Construction of the tensor: if tensor_type == (1, 0): diff --git a/src/sage/manifolds/differentiable/vectorframe.py b/src/sage/manifolds/differentiable/vectorframe.py index 90acdf8699e..a02645bcdcf 100644 --- a/src/sage/manifolds/differentiable/vectorframe.py +++ b/src/sage/manifolds/differentiable/vectorframe.py @@ -672,7 +672,7 @@ def __init__(self, vector_field_module, symbol, latex_symbol=None, from_frame=No # Some sanity check: if not isinstance(vector_field_module, FiniteRankFreeModule): - raise ValueError("the {} has already been constructed as a " "non-free module and therefore cannot have " "a basis".format(vector_field_module)) + raise ValueError("the {} has already been constructed as a non-free module and therefore cannot have a basis".format(vector_field_module)) self._domain = vector_field_module._domain self._ambient_domain = vector_field_module._ambient_domain self._dest_map = vector_field_module._dest_map @@ -1665,7 +1665,7 @@ def __init__(self, chart): # Some sanity check: vmodule = dom._vector_field_modules.get(dom.identity_map()) if vmodule and not isinstance(vmodule, FiniteRankFreeModule): - raise ValueError("the {} has already been constructed as a " "non-free module, which implies that the {} is " "not parallelizable and hence cannot be the " "domain of a coordinate chart".format(vmodule, dom)) + raise ValueError("the {} has already been constructed as a non-free module, which implies that the {} is not parallelizable and hence cannot be the domain of a coordinate chart".format(vmodule, dom)) self._chart = chart coords = chart[:] # list of all coordinates symbol = tuple(f"{unicode_partial}/{unicode_partial}{x!s}" for x in coords) diff --git a/src/sage/manifolds/local_frame.py b/src/sage/manifolds/local_frame.py index e2d6fb7e100..c0ccb135e18 100644 --- a/src/sage/manifolds/local_frame.py +++ b/src/sage/manifolds/local_frame.py @@ -596,7 +596,7 @@ def __init__(self, section_module, symbol, latex_symbol=None, indices=None, late ### # Some sanity check: if not isinstance(section_module, FiniteRankFreeModule): - raise ValueError("the {} has already been constructed as a " "non-free module and therefore cannot have " "a basis".format(section_module)) + raise ValueError("the {} has already been constructed as a non-free module and therefore cannot have a basis".format(section_module)) self._domain = section_module.domain() self._base_space = section_module.base_space() self._vbundle = section_module.vector_bundle() @@ -1278,7 +1278,7 @@ def __init__(self, triv_frame, symbol, latex_symbol=None, indices=None, latex_in sage: TestSuite(f).run() """ if not isinstance(triv_frame, TrivializationFrame): - raise TypeError("the first argument must be a local trivialization " "frame") + raise TypeError("the first argument must be a local trivialization frame") LocalCoFrame.__init__(self, triv_frame, symbol, latex_symbol=latex_symbol, indices=indices, latex_indices=latex_indices) self._trivialization = triv_frame._trivialization @@ -1366,7 +1366,7 @@ def __init__(self, trivialization): # Some sanity check: smodule = vbundle._section_modules.get(domain) if smodule and not isinstance(smodule, FiniteRankFreeModule): - raise ValueError("the {} has already been constructed as a " "non-free module and therefore cannot have " "a basis".format(smodule)) + raise ValueError("the {} has already been constructed as a non-free module and therefore cannot have a basis".format(smodule)) ### # Set trivialization: self._trivialization = triv diff --git a/src/sage/manifolds/manifold.py b/src/sage/manifolds/manifold.py index 509e7fb7e27..9613699a8b0 100644 --- a/src/sage/manifolds/manifold.py +++ b/src/sage/manifolds/manifold.py @@ -1645,7 +1645,7 @@ def set_orientation(self, orientation): elif isinstance(orientation, (tuple, list)): orientation = list(orientation) else: - raise TypeError("orientation must be a chart or a list/tuple of " "charts") + raise TypeError("orientation must be a chart or a list/tuple of charts") dom_union = None for c in orientation: if not isinstance(c, chart_type): diff --git a/src/sage/manifolds/point.py b/src/sage/manifolds/point.py index a296cdeb569..0196af5f36c 100644 --- a/src/sage/manifolds/point.py +++ b/src/sage/manifolds/point.py @@ -932,7 +932,7 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, label=None, parame from sage.plot.text import text if self._manifold.base_field_type() != 'real': - raise NotImplementedError('plot of points on manifolds over fields different' ' from the real field is not implemented') + raise NotImplementedError('plot of points on manifolds over fields different from the real field is not implemented') # The ambient chart: if chart is None: chart = self.parent().default_chart() diff --git a/src/sage/manifolds/scalarfield.py b/src/sage/manifolds/scalarfield.py index e95dc179f41..f0b78ac3c45 100644 --- a/src/sage/manifolds/scalarfield.py +++ b/src/sage/manifolds/scalarfield.py @@ -1540,7 +1540,7 @@ def set_name(self, name=None, latex_name=None): \Phi """ if self.is_immutable(): - raise ValueError("the name of an immutable element " "cannot be changed") + raise ValueError("the name of an immutable element cannot be changed") if name is not None: self._name = name if latex_name is None: @@ -1667,9 +1667,9 @@ def copy_from(self, other): False """ if self.is_immutable(): - raise ValueError("the expressions of an immutable element " "cannot be changed") + raise ValueError("the expressions of an immutable element cannot be changed") if other not in self.parent(): - raise TypeError("the original must be an element of " f"{self.parent()}") + raise TypeError(f"the original must be an element of {self.parent()}") self._del_derived() for chart, funct in other._express.items(): self._express[chart] = funct.copy() @@ -1891,7 +1891,7 @@ def set_expr(self, coord_expression, chart=None): changed """ if self.is_immutable(): - raise ValueError("the expressions of an immutable element " "cannot be changed") + raise ValueError("the expressions of an immutable element cannot be changed") if chart is None: chart = self._domain._def_chart self._express.clear() @@ -1953,7 +1953,7 @@ def add_expr(self, coord_expression, chart=None): changed """ if self.is_immutable(): - raise ValueError("the expressions of an immutable element " "cannot be changed") + raise ValueError("the expressions of an immutable element cannot be changed") if chart is None: chart = self._domain._def_chart self._express[chart] = chart.function(coord_expression) @@ -2021,7 +2021,7 @@ def add_expr_by_continuation(self, chart, subdomain): on V: (u, v) ↦ arctan(1/(u^2 + v^2)) """ if self.is_immutable(): - raise ValueError("the expressions of an immutable element " "cannot be changed") + raise ValueError("the expressions of an immutable element cannot be changed") if not chart.domain().is_subset(self._domain): raise ValueError("the chart is not defined on a subset of " + "the scalar field domain") schart = chart.restrict(subdomain) @@ -2056,7 +2056,7 @@ def set_restriction(self, rst): True """ if self.is_immutable(): - raise ValueError("the expressions of an immutable element " "cannot be changed") + raise ValueError("the expressions of an immutable element cannot be changed") if not isinstance(rst, ScalarField): raise TypeError("the argument must be a scalar field") if not rst._domain.is_subset(self._domain): @@ -3682,5 +3682,5 @@ def __hash__(self): 1 """ if self.is_mutable(): - raise ValueError('element must be immutable in order to be ' 'hashable') + raise ValueError('element must be immutable in order to be hashable') return hash((type(self).__name__, self._domain)) diff --git a/src/sage/manifolds/section.py b/src/sage/manifolds/section.py index 82c9b91242b..2987bc713a4 100644 --- a/src/sage/manifolds/section.py +++ b/src/sage/manifolds/section.py @@ -411,7 +411,7 @@ def set_name(self, name=None, latex_name=None): a """ if self.is_immutable(): - raise ValueError("the name of an immutable element " "cannot be changed") + raise ValueError("the name of an immutable element cannot be changed") if name is not None: self._name = name if latex_name is None: @@ -608,7 +608,7 @@ def set_restriction(self, rst): True """ if self.is_immutable(): - raise ValueError("the restrictions of an immutable element " "cannot be changed") + raise ValueError("the restrictions of an immutable element cannot be changed") self._restrictions[rst._domain] = rst.copy(name=self._name, latex_name=self._latex_name) self._is_zero = False # a priori @@ -889,7 +889,7 @@ def set_comp(self, basis=None): the Trivialization frame (E|_V, ((phi_V^*e_1),(phi_V^*e_2))) """ if self.is_immutable(): - raise ValueError("the components of an immutable element " "cannot be changed") + raise ValueError("the components of an immutable element cannot be changed") if basis is None: basis = self._smodule.default_frame() if basis is None: # should be "is still None" ;-) @@ -1024,7 +1024,7 @@ def add_comp(self, basis=None): s = (u + v) (phi_V^*e_1) """ if self.is_immutable(): - raise ValueError("the components of an immutable element " "cannot be changed") + raise ValueError("the components of an immutable element cannot be changed") if basis is None: basis = self._smodule.default_frame() if basis is None: # should be "is still None" ;-) @@ -1104,7 +1104,7 @@ def add_comp_by_continuation(self, frame, subdomain, chart=None): and `a` is defined on the entire manifold `S^2`. """ if self.is_immutable(): - raise ValueError("the components of an immutable element " "cannot be changed") + raise ValueError("the components of an immutable element cannot be changed") dom = frame._domain if not dom.is_subset(self._domain): raise ValueError("the local frame is not defined on a subset " + "of the section's domain") @@ -1185,12 +1185,12 @@ def add_expr_from_subdomain(self, frame, subdomain): on V: (u, v) ↦ v/(u^2 + v^2) """ if self.is_immutable(): - raise ValueError("the expressions of an immutable element " "cannot be changed") + raise ValueError("the expressions of an immutable element cannot be changed") dom = frame._domain if not dom.is_subset(self._domain): raise ValueError("the local frame is not defined on a subset " + "of the section's domain") if frame not in self.restrict(frame.domain())._components: - raise ValueError("the section doesn't have an expression in " "the frame " + frame._repr_()) + raise ValueError("the section doesn't have an expression in the frame " + frame._repr_()) comp = self.comp(frame) scomp = self.restrict(subdomain).comp(frame.restrict(subdomain)) for ind in comp.non_redundant_index_generator(): @@ -1650,9 +1650,9 @@ def copy_from(self, other): False """ if self.is_immutable(): - raise ValueError("the components of an immutable element " "cannot be changed") + raise ValueError("the components of an immutable element cannot be changed") if other not in self.parent(): - raise TypeError("the original must be an element of " f"{self.parent()}") + raise TypeError(f"the original must be an element of {self.parent()}") self._del_derived() self._del_restrictions() # delete restrictions for dom, rst in other._restrictions.items(): @@ -2581,7 +2581,7 @@ class :class:`~sage.tensor.modules.comp.Components`; if such in the Local frame (E|_M, (f_0,f_1)) """ if self.is_immutable(): - raise ValueError("the components of an immutable element " "cannot be changed") + raise ValueError("the components of an immutable element cannot be changed") if basis is None: basis = self._smodule.default_frame() @@ -2751,7 +2751,7 @@ class :class:`~sage.tensor.modules.comp.Components`; if such s = x f_0 """ if self.is_immutable(): - raise ValueError("the components of an immutable element " "cannot be changed") + raise ValueError("the components of an immutable element cannot be changed") if basis is None: basis = self._smodule.default_frame() diff --git a/src/sage/manifolds/section_module.py b/src/sage/manifolds/section_module.py index 4519f990c92..bb8d9d99a3d 100644 --- a/src/sage/manifolds/section_module.py +++ b/src/sage/manifolds/section_module.py @@ -298,7 +298,7 @@ def _repr_(self): Module C^0(M;E) of sections on the 2-dimensional topological manifold M with values in the real vector bundle E of rank 2 """ - desc = "Module {} of sections on the {} with values in the {} vector " "bundle {} of rank {}" + desc = "Module {} of sections on the {} with values in the {} vector bundle {} of rank {}" desc = desc.format(self._name, self._domain, self._vbundle.base_field_type(), self._vbundle._name, self._vbundle.rank()) return desc @@ -461,7 +461,7 @@ def set_default_frame(self, basis): if not isinstance(basis, LocalFrame): raise ValueError("the argument is not a local frame") elif not basis._domain.is_subset(self._domain): - raise ValueError("local frame's domain must be a subset " "of the {}".format(self._domain)) + raise ValueError("local frame's domain must be a subset of the {}".format(self._domain)) self._def_frame = basis @@ -673,7 +673,7 @@ def _repr_(self): Free module C^0(M;E) of sections on the 2-dimensional topological manifold M with values in the real vector bundle E of rank 2 """ - desc = "Free module {} of sections on the {} with values in the {} " "vector bundle {} of rank {}" + desc = "Free module {} of sections on the {} with values in the {} vector bundle {} of rank {}" desc = desc.format(self._name, self._domain, self._vbundle.base_field_type(), self._vbundle._name, self._vbundle.rank()) return desc diff --git a/src/sage/manifolds/subsets/pullback.py b/src/sage/manifolds/subsets/pullback.py index b0db3d7129c..abf8cf94dc2 100644 --- a/src/sage/manifolds/subsets/pullback.py +++ b/src/sage/manifolds/subsets/pullback.py @@ -205,7 +205,6 @@ def __classcall_private__(cls, map, codomain_subset, inverse=None, name=None, la name = inverse_name + '_' + codomain_subset_name if cls._is_open(codomain_subset): - try: coord_def = cls._coord_def(map, codomain_subset) except NotImplementedError: @@ -465,7 +464,6 @@ def _polyhedron_restriction(expr, polyhedron, relint=False): expr = vector(SR, expr) for constraint in polyhedron.Hrepresentation(): - if constraint.is_inequality(): if relint: condition = constraint.eval(expr) > 0 @@ -527,11 +525,9 @@ def _coord_def(map, codomain_subset): {Chart (R^2, (x, y)): [x^2 + y^2 > 1, x^2 + y^2 < 4]} """ if isinstance(map, ScalarField) and isinstance(codomain_subset, RealSet): - return {chart: ManifoldSubsetPullback._realset_restriction(func.expr(), codomain_subset) for chart, func in map._express.items()} if isinstance(map, Chart): - chart = map if isinstance(codomain_subset, RealSet): diff --git a/src/sage/manifolds/topological_submanifold.py b/src/sage/manifolds/topological_submanifold.py index 96dca643c23..d5488b0546b 100644 --- a/src/sage/manifolds/topological_submanifold.py +++ b/src/sage/manifolds/topological_submanifold.py @@ -432,7 +432,7 @@ def set_immersion(self, phi, inverse=None, var=None, t_inverse=None): raise TypeError() except TypeError: if not isinstance(var, Expression): - raise TypeError("var must be a variable " "or list of variables") + raise TypeError("var must be a variable or list of variables") if isinstance(var, Expression): self._var = [var] @@ -481,7 +481,7 @@ def declare_embedding(self): True """ if not self._immersed: - raise ValueError("please declare an embedding using set_immersion " "before calling declare_embedding()") + raise ValueError("please declare an embedding using set_immersion before calling declare_embedding()") self._embedded = True def set_embedding(self, phi: ContinuousMap, inverse=None, var=None, t_inverse=None): @@ -618,7 +618,7 @@ def adapted_chart(self, postscript=None, latex_postscript=None): raise ValueError("an embedding is required") if self._dim_foliation + self._dim != self._ambient._dim: - raise ValueError("a foliation of dimension dim(M) - dim(N) is " "needed to find an adapted chart") + raise ValueError("a foliation of dimension dim(M) - dim(N) is needed to find an adapted chart") res = [] self._subs = [] @@ -636,7 +636,6 @@ def adapted_chart(self, postscript=None, latex_postscript=None): name = " ".join(chart1[i]._repr_() + postscript + ":{" + chart1[i]._latex_() + "}" + latex_postscript for i in self.irange()) + " " + " ".join(v._repr_() + postscript + ":{" + v._latex_() + "}" + latex_postscript for v in self._var) chart = chart2.domain().chart(name) if chart not in res: - # Construct restrictions on coordinates: subs = {chart1[:][i]: chart[:][i] for i in range(self._dim)} # NB: chart1[:][i] is used instead of chart1[i] to allow for diff --git a/src/sage/manifolds/vector_bundle.py b/src/sage/manifolds/vector_bundle.py index 91f2d04c209..4c7b0dd578d 100644 --- a/src/sage/manifolds/vector_bundle.py +++ b/src/sage/manifolds/vector_bundle.py @@ -223,7 +223,7 @@ def __init__(self, rank, name, base_space, field='real', latex_name=None, catego self._field_type = 'neither_real_nor_complex' bs_field = base_space.base_field() if not bs_field.is_subring(self._field): - raise ValueError("for concrete implementation, manifold's base " "field must be a subfield of the vector bundle's " "base field") + raise ValueError("for concrete implementation, manifold's base field must be a subfield of the vector bundle's base field") ### # Get the category: if category is None: @@ -772,7 +772,7 @@ def local_frame(self, *args, **kwargs): # Input processing n_args = len(args) if n_args < 1 or n_args > 2: - raise TypeError("local_frame() takes one or two positional " "arguments, not {}".format(n_args)) + raise TypeError("local_frame() takes one or two positional arguments, not {}".format(n_args)) symbol = args[0] sections = None if n_args == 2: @@ -793,7 +793,7 @@ def local_frame(self, *args, **kwargs): except ArithmeticError as err: linked = str(err) in ["non-invertible matrix", "input matrix must be nonsingular"] if linked: - raise ValueError("the provided sections are not linearly " "independent") + raise ValueError("the provided sections are not linearly independent") return resu def section(self, *comp, **kwargs): @@ -1149,7 +1149,7 @@ def set_orientation(self, orientation): elif isinstance(orientation, (tuple, list)): orientation = list(orientation) else: - raise TypeError("orientation must be a frame or a list/tuple of " "frames") + raise TypeError("orientation must be a frame or a list/tuple of frames") dom_union = None for frame in orientation: if frame not in self.frames(): @@ -1161,7 +1161,7 @@ def set_orientation(self, orientation): dom_union = dom base_space = self._base_space if dom_union != base_space: - raise ValueError("the frames's domains must " "cover {}".format(base_space)) + raise ValueError("the frames's domains must cover {}".format(base_space)) self._orientation = orientation def orientation(self): diff --git a/src/sage/manifolds/vector_bundle_fiber.py b/src/sage/manifolds/vector_bundle_fiber.py index 7cc88a0b92a..e65f799b202 100644 --- a/src/sage/manifolds/vector_bundle_fiber.py +++ b/src/sage/manifolds/vector_bundle_fiber.py @@ -176,7 +176,7 @@ def __init__(self, vector_bundle, point): sage: TestSuite(Ep).run() """ if point._manifold is not vector_bundle._base_space: - raise ValueError("Point must be an element " "of {}".format(vector_bundle._manifold)) + raise ValueError("Point must be an element of {}".format(vector_bundle._manifold)) name = "{}_{}".format(vector_bundle._name, point._name) latex_name = r'{}_{{{}}}'.format(vector_bundle._latex_name, point._latex_name) self._rank = vector_bundle._rank diff --git a/src/sage/matrix/matrix_misc.py b/src/sage/matrix/matrix_misc.py index 870e347f556..39267bb321e 100644 --- a/src/sage/matrix/matrix_misc.py +++ b/src/sage/matrix/matrix_misc.py @@ -306,7 +306,7 @@ def permanental_minor_polynomial(A, permanent_only=False, var='t', prec=None): return K.zero() if len(p) != 1 or 0 not in p: - raise RuntimeError("Something is wrong! Certainly a problem in the" " algorithm... please contact sage-devel@googlegroups.com") + raise RuntimeError("Something is wrong! Certainly a problem in the algorithm... please contact sage-devel@googlegroups.com") p = p[0] return p[min(nrows, ncols)] if permanent_only else p diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index c362caab6f5..f37e78dfd47 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -736,7 +736,7 @@ def __classcall__(cls, base_ring, nrows_or_row_keys=None, ncols_or_column_keys=N raise ValueError("duplicate values for ncols") ncols = n if column_keys is not None and ncols is not None and ncols != len(column_keys): - raise ValueError(f"inconsistent number of columns: should be cardinality of {column_keys} " f"but got {ncols}") + raise ValueError(f"inconsistent number of columns: should be cardinality of {column_keys} but got {ncols}") if nrows_or_row_keys is not None: try: @@ -750,7 +750,7 @@ def __classcall__(cls, base_ring, nrows_or_row_keys=None, ncols_or_column_keys=N raise ValueError("duplicate values for nrows") nrows = n if row_keys is not None and nrows is not None and nrows != len(row_keys): - raise ValueError(f"inconsistent number of rows: should be cardinality of {row_keys} " f"but got {nrows}") + raise ValueError(f"inconsistent number of rows: should be cardinality of {row_keys} but got {nrows}") if ncols is None and column_keys is None: ncols = nrows diff --git a/src/sage/matrix/operation_table.py b/src/sage/matrix/operation_table.py index c4232825937..d3feb5c81c1 100644 --- a/src/sage/matrix/operation_table.py +++ b/src/sage/matrix/operation_table.py @@ -1032,7 +1032,6 @@ def color_table(self, element_names=True, cmap=None, **options): plot = matrix_plot(Matrix(self._table), cmap=cmap, frame=False, **options) if element_names: - # adapted from ._ascii_table() # prepare widenames[] list for labelling on image n = self._n diff --git a/src/sage/matrix/special.py b/src/sage/matrix/special.py index b103c2b8a55..b5c519d9c29 100644 --- a/src/sage/matrix/special.py +++ b/src/sage/matrix/special.py @@ -3274,7 +3274,7 @@ def random_unitary_matrix(parent): # The implementation of SR.random_element() currently just # returns a random integer coerced into SR, so there is no # benefit to allowing SR here when QQ is available. - raise ValueError("base ring of parent must be a subfield " "of the complex numbers") + raise ValueError("base ring of parent must be a subfield of the complex numbers") I = identity_matrix(F, n) A = random_matrix(F, n) @@ -3390,7 +3390,7 @@ def random_bistochastic_matrix(parent): from sage.rings.real_mpfr import RR if not parent.base_ring().is_subring(RR): - raise ValueError("base ring of parent must be a subfield of the real " "numbers") + raise ValueError("base ring of parent must be a subfield of the real numbers") B = random_unitary_matrix(parent) # Squaring every entry. diff --git a/src/sage/matroids/constructor.py b/src/sage/matroids/constructor.py index b350213ce03..04750699c80 100644 --- a/src/sage/matroids/constructor.py +++ b/src/sage/matroids/constructor.py @@ -100,7 +100,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from itertools import combinations from sage.combinat.posets.lattices import FiniteLatticePoset from sage.matrix.constructor import matrix diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index 2b721b6fea5..adbbea9a5ba 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -393,7 +393,7 @@ def cython(filename, verbose=0, compile_message=False, use_cache=False, create_l if verbose >= 0: # triggered by Cython 3 with unpatched cysignals 1.11.2 - cython_messages = re.sub("^.*The keyword 'nogil' should appear at the end of the function signature line. " "Placing it before 'except' or 'noexcept' will be disallowed in a future version of Cython.\n", "", cython_messages, flags=re.MULTILINE) + cython_messages = re.sub("^.*The keyword 'nogil' should appear at the end of the function signature line. Placing it before 'except' or 'noexcept' will be disallowed in a future version of Cython.\n", "", cython_messages, flags=re.MULTILINE) sys.stderr.write(cython_messages) sys.stderr.flush() diff --git a/src/sage/misc/decorators.py b/src/sage/misc/decorators.py index b627d776fb4..ee084e6f973 100644 --- a/src/sage/misc/decorators.py +++ b/src/sage/misc/decorators.py @@ -280,7 +280,7 @@ def _left(self, right): new = copy(self) new.right = right return new - raise SyntaxError("Infix operator already has its " "right argument") + raise SyntaxError("Infix operator already has its right argument") else: return self.function(self.left, right) @@ -291,7 +291,7 @@ def _right(self, left): new = copy(self) new.left = left return new - raise SyntaxError("Infix operator already has its " "left argument") + raise SyntaxError("Infix operator already has its left argument") else: return self.function(left, self.right) @@ -654,7 +654,7 @@ def wrapper(*args, **kwds): if self.deprecation is not None: from sage.misc.superseded import deprecation - deprecation(self.deprecation, "use the option " "%r instead of %r" % (new_name, old_name)) + deprecation(self.deprecation, "use the option %r instead of %r" % (new_name, old_name)) kwds[new_name] = kwds[old_name] del kwds[old_name] return func(*args, **kwds) diff --git a/src/sage/misc/dev_tools.py b/src/sage/misc/dev_tools.py index 0269f7eae43..aa01d89c806 100644 --- a/src/sage/misc/dev_tools.py +++ b/src/sage/misc/dev_tools.py @@ -531,7 +531,7 @@ def expand_comma_separated_names(obj): modules = set() for o in obj: modules.update(find_object_modules(o)) - print("# **Warning**: distinct objects with name '{}' " "in:".format(name)) + print("# **Warning**: distinct objects with name '{}' in:".format(name)) for mod in sorted(modules): print("# - {}".format(mod)) @@ -541,7 +541,7 @@ def expand_comma_separated_names(obj): obj = obj[0] except IndexError: if deprecation: - raise LookupError("object named {!r} is deprecated (see Issue #" "{})".format(name, deprecation)) + raise LookupError("object named {!r} is deprecated (see Issue #{})".format(name, deprecation)) else: raise LookupError("no object named {!r}".format(name)) @@ -591,7 +591,7 @@ def is_ascii(s): ((module_name, obj_names),) = modules.items() if name is None: if verbose and len(obj_names) > 1: - print("# ** Warning **: several names for that object: " "{}".format(', '.join(sorted(obj_names)))) + print("# ** Warning **: several names for that object: {}".format(', '.join(sorted(obj_names)))) name = alias = obj_names[0] elif name in modules[module_name]: alias = name @@ -632,11 +632,11 @@ def is_ascii(s): all_re = re.compile(r'.+\.all(?:_\w+)?$') not_all_modules = [mod for mod in modules if not all_re.match(mod)] if not not_all_modules: - print("# ** Warning **: the object {} is only defined in " ".all modules".format(obj)) + print("# ** Warning **: the object {} is only defined in .all modules".format(obj)) module_name = next(iter(modules)) else: if len(not_all_modules) > 1: - print("# ** Warning **: several modules for the object " "{}: {}".format(obj, ', '.join(sorted(modules)))) + print("# ** Warning **: several modules for the object {}: {}".format(obj, ', '.join(sorted(modules)))) module_name = not_all_modules[0] # 3. Now that we found the module, we fix the problem of the alias diff --git a/src/sage/misc/explain_pickle.py b/src/sage/misc/explain_pickle.py index 5b1ca85f2fb..ccbd098a2db 100644 --- a/src/sage/misc/explain_pickle.py +++ b/src/sage/misc/explain_pickle.py @@ -153,7 +153,6 @@ # http://www.gnu.org/licenses/ # ***************************************************************************** - import pickletools import re import sys diff --git a/src/sage/misc/gperftools.py b/src/sage/misc/gperftools.py index a35c673a0a4..e0d5f87a7b2 100644 --- a/src/sage/misc/gperftools.py +++ b/src/sage/misc/gperftools.py @@ -48,7 +48,6 @@ class Profiler(SageObject): - def __init__(self, filename=None) -> None: """ Interface to the gperftools profiler. @@ -165,7 +164,7 @@ def stop(self): if (self._t_stop - self._t_start) < 0.1: from warnings import warn - warn('not enough samples, total runtime was ' 'less than 100ms', RuntimeWarning) + warn('not enough samples, total runtime was less than 100ms', RuntimeWarning) @cached_method def _pprof(self) -> str: diff --git a/src/sage/misc/html.py b/src/sage/misc/html.py index 533bc207351..b7eafeac6b5 100644 --- a/src/sage/misc/html.py +++ b/src/sage/misc/html.py @@ -380,7 +380,6 @@ def eval(self, x, globals=None, locals=None, mode='display', combine_all=False): class HTMLFragmentFactory(SageObject): - def _repr_(self): """ Return string representation. diff --git a/src/sage/misc/latex.py b/src/sage/misc/latex.py index d26e1183c51..eff8d164e6d 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -1388,9 +1388,7 @@ def check_file(self, file_name, more_info=""): if not self.has_file(file_name): print( """ -Warning: `{}` is not part of this computer's TeX installation.""".format( - file_name - ) +Warning: `{}` is not part of this computer's TeX installation.""".format(file_name) ) if more_info: print(more_info) diff --git a/src/sage/misc/latex_standalone.py b/src/sage/misc/latex_standalone.py index d70a5a9efaf..363da0d03fa 100644 --- a/src/sage/misc/latex_standalone.py +++ b/src/sage/misc/latex_standalone.py @@ -708,7 +708,7 @@ def pdf(self, filename=None, view=True, program=None): # If a problem with the tex source occurs, provide the log if result.returncode != 0: - print("Command \n" " '{}'\n" "returned nonzero exit status {}.\n" "Here is the content of the stderr:{}\n" "Here is the content of the stdout:" "{}\n".format(' '.join(result.args), result.returncode, result.stderr.strip(), result.stdout.strip())) + print("Command \n '{}'\nreturned nonzero exit status {}.\nHere is the content of the stderr:{}\nHere is the content of the stdout:{}\n".format(' '.join(result.args), result.returncode, result.stderr.strip(), result.stdout.strip())) result.check_returncode() temp_filename_pdf = os.path.join(base, temp_filename + '.pdf') @@ -828,7 +828,7 @@ def dvi(self, filename=None, view=True, program='latex'): # If a problem with the tex source occurs, provide the log if result.returncode != 0: - print("Command \n" " '{}'\n" "returned nonzero exit status {}.\n" "Here is the content of the stderr:{}\n" "Here is the content of the stdout:" "{}\n".format(' '.join(result.args), result.returncode, result.stderr.strip(), result.stdout.strip())) + print("Command \n '{}'\nreturned nonzero exit status {}.\nHere is the content of the stderr:{}\nHere is the content of the stdout:{}\n".format(' '.join(result.args), result.returncode, result.stderr.strip(), result.stdout.strip())) result.check_returncode() temp_filename_dvi = os.path.join(base, temp_filename + '.dvi') @@ -909,7 +909,7 @@ def png(self, filename=None, density=150, view=True): # If a problem occurs, provide the log if result.returncode != 0: - print("Command \n" " '{}'\n" "returned nonzero exit status {}.\n" "Here is the content of the stderr:{}\n" "Here is the content of the stdout:" "{}\n".format(' '.join(result.args), result.returncode, result.stderr.strip(), result.stdout.strip())) + print("Command \n '{}'\nreturned nonzero exit status {}.\nHere is the content of the stderr:{}\nHere is the content of the stdout:{}\n".format(' '.join(result.args), result.returncode, result.stderr.strip(), result.stdout.strip())) result.check_returncode() # move the png into the good location @@ -997,14 +997,14 @@ def svg(self, filename=None, view=True, program='pdftocairo'): pdf2svg().require() cmd = ['pdf2svg', temp_filename_pdf, temp_filename_svg] else: - raise ValueError("program(={}) should be 'pdftocairo' or" " 'pdf2svg'".format(program)) + raise ValueError("program(={}) should be 'pdftocairo' or 'pdf2svg'".format(program)) # convert to svg result = run(cmd, capture_output=True, text=True) # If a problem occurs, provide the log if result.returncode != 0: - print("Command \n" " '{}'\n" "returned nonzero exit status {}.\n" "Here is the content of the stderr:{}\n" "Here is the content of the stdout:" "{}\n".format(' '.join(result.args), result.returncode, result.stderr.strip(), result.stdout.strip())) + print("Command \n '{}'\nreturned nonzero exit status {}.\nHere is the content of the stderr:{}\nHere is the content of the stdout:{}\n".format(' '.join(result.args), result.returncode, result.stderr.strip(), result.stdout.strip())) result.check_returncode() # move the svg into the good location @@ -1107,14 +1107,14 @@ def eps(self, filename=None, view=True, program='dvips'): # set the command cmd = ['dvips', '-E', '-o', temp_filename_eps, temp_filename_dvi] else: - raise ValueError("program(={}) should be 'pdftocairo' or" " 'dvips'".format(program)) + raise ValueError("program(={}) should be 'pdftocairo' or 'dvips'".format(program)) # convert to eps result = run(cmd, capture_output=True, text=True) # If a problem occurs, provide the log if result.returncode != 0: - print("Command \n" " '{}'\n" "returned nonzero exit status {}.\n" "Here is the content of the stderr:{}\n" "Here is the content of the stdout:" "{}\n".format(' '.join(result.args), result.returncode, result.stderr.strip(), result.stdout.strip())) + print("Command \n '{}'\nreturned nonzero exit status {}.\nHere is the content of the stderr:{}\nHere is the content of the stdout:{}\n".format(' '.join(result.args), result.returncode, result.stderr.strip(), result.stdout.strip())) result.check_returncode() # move the eps into the good location @@ -1189,7 +1189,7 @@ def tex(self, filename=None, content_only=False, include_header=None): content_only = not include_header from sage.misc.superseded import deprecation - deprecation(20343, "When merging this code from slabbe into " "SageMath the argument include_header=False was " "replaced by content_only=True. Please update your code " "before include_header option gets removed from SageMath.") + deprecation(20343, "When merging this code from slabbe into SageMath the argument include_header=False was replaced by content_only=True. Please update your code before include_header option gets removed from SageMath.") if content_only: output = self.content() @@ -1254,7 +1254,7 @@ def save(self, filename, **kwds): elif ext == '.dvi': self.dvi(filename, **kwds) else: - raise ValueError("allowed file extensions for images are " ".pdf, .png, .svg, .eps, .dvi!") + raise ValueError("allowed file extensions for images are .pdf, .png, .svg, .eps, .dvi!") class TikzPicture(Standalone): diff --git a/src/sage/misc/multireplace.py b/src/sage/misc/multireplace.py index 2c53f542901..129a47fd391 100644 --- a/src/sage/misc/multireplace.py +++ b/src/sage/misc/multireplace.py @@ -12,7 +12,6 @@ # ########################################################################## - import re diff --git a/src/sage/misc/package.py b/src/sage/misc/package.py index 22cd6f34026..b500dd9fcea 100644 --- a/src/sage/misc/package.py +++ b/src/sage/misc/package.py @@ -309,7 +309,6 @@ def list_packages(*pkg_types: str, pkg_sources: list[str] = ['normal', 'pip', 's return pkgs for p in lp: - typ = spkg_type(p) if not typ: continue diff --git a/src/sage/misc/remote_file.py b/src/sage/misc/remote_file.py index 4efe15847c4..abb7bc050ba 100644 --- a/src/sage/misc/remote_file.py +++ b/src/sage/misc/remote_file.py @@ -1,4 +1,5 @@ "get_remote_file" + import os from pathlib import Path from urllib.request import Request, urlopen diff --git a/src/sage/misc/sagedoc.py b/src/sage/misc/sagedoc.py index 845fdd441e8..9e680976083 100644 --- a/src/sage/misc/sagedoc.py +++ b/src/sage/misc/sagedoc.py @@ -494,7 +494,7 @@ def process_dollars(s): while dollar.search(s, start, end): m = dollar.search(s, start, end) s = s[: m.end() - 1] + "`" + s[m.end() :] - deprecation(33973, "using dollar signs to mark up math in Sage docstrings " "is deprecated; use backticks instead") + deprecation(33973, "using dollar signs to mark up math in Sage docstrings is deprecated; use backticks instead") while slashdollar.search(s, start, end): m = slashdollar.search(s, start, end) s = s[: m.start()] + "$" + s[m.end() :] @@ -1613,9 +1613,7 @@ def _open(self, name, testing=False): if not os.path.exists(path): raise OSError( """The document '{0}' does not exist. Please build it -with 'sage -docbuild {0} html' and try again.""".format( - name - ) +with 'sage -docbuild {0} html' and try again.""".format(name) ) if testing: @@ -1715,7 +1713,5 @@ def help(module=None): To enter Python's interactive online help utility, type "python_help()". To get help on a Python function, module or package, type "help(MODULE)" or -"python_help(MODULE)".""".format( - sage.version.version - ) +"python_help(MODULE)".""".format(sage.version.version) ) diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 1886bb0735a..24980691b8d 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -2161,9 +2161,7 @@ def sage_getdoc(obj, obj_name='', embedded=False): skip = skipfile(f) if isinstance(skip, str): warn = """WARNING: the enclosing module is marked '{}', -so doctests may not pass.""".format( - skip - ) +so doctests may not pass.""".format(skip) s = warn + "\n\n" + s # Fix object naming diff --git a/src/sage/misc/superseded.py b/src/sage/misc/superseded.py index a40bba510f7..e7f5b8108f8 100644 --- a/src/sage/misc/superseded.py +++ b/src/sage/misc/superseded.py @@ -304,7 +304,7 @@ def __call__(self, func): @sage_wraps(func) def wrapper(*args, **kwds): if not wrapper._already_issued: - experimental_warning(self.issue_number, 'This class/method/function is marked as ' 'experimental. It, its functionality or its ' 'interface might change without a ' 'formal deprecation.', self.stacklevel) + experimental_warning(self.issue_number, 'This class/method/function is marked as experimental. It, its functionality or its interface might change without a formal deprecation.', self.stacklevel) wrapper._already_issued = True return func(*args, **kwds) diff --git a/src/sage/misc/test_nested_class.py b/src/sage/misc/test_nested_class.py index 09f29219140..e7b02e0f6ad 100644 --- a/src/sage/misc/test_nested_class.py +++ b/src/sage/misc/test_nested_class.py @@ -89,7 +89,6 @@ class Element(ElementWrapper): class TestParent3(UniqueRepresentation, Parent): - def __init__(self): """ EXAMPLES:: @@ -237,4 +236,5 @@ class TestNestedParent(UniqueRepresentation, Parent): class Element: "This is a dummy element class" + pass diff --git a/src/sage/misc/unknown.py b/src/sage/misc/unknown.py index 1225e12bfa2..ddc47d8871c 100644 --- a/src/sage/misc/unknown.py +++ b/src/sage/misc/unknown.py @@ -80,7 +80,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.structure.unique_representation import UniqueRepresentation from sage.structure.richcmp import richcmp_method, rich_to_bool diff --git a/src/sage/modular/abvar/abvar.py b/src/sage/modular/abvar/abvar.py index b8fc779e7bf..5e4226d14ac 100644 --- a/src/sage/modular/abvar/abvar.py +++ b/src/sage/modular/abvar/abvar.py @@ -4408,7 +4408,6 @@ def decomposition(self, simple=True, bound=None): class ModularAbelianVariety_modsym(ModularAbelianVariety_modsym_abstract): - def __init__(self, modsym, lattice=None, newform_level=None, is_simple=None, isogeny_number=None, number=None, check=True): """ Modular abelian variety that corresponds to a Hecke stable space of diff --git a/src/sage/modular/abvar/abvar_newform.py b/src/sage/modular/abvar/abvar_newform.py index cae2b3445d6..23aa44c5cad 100644 --- a/src/sage/modular/abvar/abvar_newform.py +++ b/src/sage/modular/abvar/abvar_newform.py @@ -8,6 +8,7 @@ sage: loads(dumps(A)) == A True """ + ########################################################################### # Copyright (C) 2008 William Stein # # Distributed under the terms of the GNU General Public License (GPL) # diff --git a/src/sage/modular/abvar/finite_subgroup.py b/src/sage/modular/abvar/finite_subgroup.py index 13b53a7774c..9c49cba9111 100644 --- a/src/sage/modular/abvar/finite_subgroup.py +++ b/src/sage/modular/abvar/finite_subgroup.py @@ -418,7 +418,7 @@ def intersection(self, other): else: amb = A if not isinstance(other, FiniteSubgroup): - raise TypeError("only intersection with a finite subgroup or " "modular abelian variety is defined") + raise TypeError("only intersection with a finite subgroup or modular abelian variety is defined") B = other.abelian_variety() if A.ambient_variety() != B.ambient_variety(): raise TypeError("finite subgroups must be in the same ambient product Jacobian") diff --git a/src/sage/modular/abvar/homspace.py b/src/sage/modular/abvar/homspace.py index 858170fcfa6..d85a807b71b 100644 --- a/src/sage/modular/abvar/homspace.py +++ b/src/sage/modular/abvar/homspace.py @@ -181,7 +181,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from copy import copy from sage.categories.homset import HomsetWithBase @@ -725,7 +724,6 @@ def _calculate_simple_gens(self): # that the input gens are give something that spans a sub*ring*, as opposed # to just a subgroup. class EndomorphismSubring(Homspace): - def __init__(self, A, gens=None, category=None): """ A subring of the endomorphism ring. diff --git a/src/sage/modular/abvar/morphism.py b/src/sage/modular/abvar/morphism.py index c65f3893d54..d3111742514 100644 --- a/src/sage/modular/abvar/morphism.py +++ b/src/sage/modular/abvar/morphism.py @@ -598,7 +598,6 @@ def _image_of_abvar(self, A): class Morphism(Morphism_abstract, sage.modules.matrix_morphism.MatrixMorphism): - def restrict_domain(self, sub): """ Restrict ``self`` to the subvariety sub of ``self.domain()``. diff --git a/src/sage/modular/abvar/torsion_subgroup.py b/src/sage/modular/abvar/torsion_subgroup.py index bc35e789172..abc061e69dc 100644 --- a/src/sage/modular/abvar/torsion_subgroup.py +++ b/src/sage/modular/abvar/torsion_subgroup.py @@ -648,7 +648,6 @@ def multiple_of_order_using_frobp(self, maxp=None): class QQbarTorsionSubgroup(Module): - Element = TorsionPoint def __init__(self, abvar): diff --git a/src/sage/modular/arithgroup/arithgroup_perm.py b/src/sage/modular/arithgroup/arithgroup_perm.py index 861345e171b..b17f231a5de 100644 --- a/src/sage/modular/arithgroup/arithgroup_perm.py +++ b/src/sage/modular/arithgroup/arithgroup_perm.py @@ -2614,7 +2614,6 @@ def odd_subgroups(self): ts = [PermutationConstructor(list(range(1, 1 + 2 * n)))] for i in range(1, n + 1): - t = PermutationConstructor([(i, n + i)], check=False) s3c = t * s3 * t diff --git a/src/sage/modular/arithgroup/congroup_gamma1.py b/src/sage/modular/arithgroup/congroup_gamma1.py index 87a88b40d46..da2fc44d994 100644 --- a/src/sage/modular/arithgroup/congroup_gamma1.py +++ b/src/sage/modular/arithgroup/congroup_gamma1.py @@ -11,7 +11,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.arith.misc import divisors, moebius from sage.arith.misc import euler_phi as phi from sage.misc.cachefunc import cached_method diff --git a/src/sage/modular/arithgroup/congroup_generic.py b/src/sage/modular/arithgroup/congroup_generic.py index 3ec449144f1..62af6963d85 100644 --- a/src/sage/modular/arithgroup/congroup_generic.py +++ b/src/sage/modular/arithgroup/congroup_generic.py @@ -116,7 +116,6 @@ def CongruenceSubgroup_constructor(*args): class CongruenceSubgroupBase(ArithmeticSubgroup): - def __init__(self, level) -> None: """ Create a congruence subgroup with given level. diff --git a/src/sage/modular/arithgroup/tests.py b/src/sage/modular/arithgroup/tests.py index 11947c217ac..86fc19a004b 100644 --- a/src/sage/modular/arithgroup/tests.py +++ b/src/sage/modular/arithgroup/tests.py @@ -2,6 +2,7 @@ r""" Testing arithmetic subgroup """ + ################################################################################ # # Copyright (C) 2009, The Sage Group -- http://www.sagemath.org/ diff --git a/src/sage/modular/btquotients/btquotient.py b/src/sage/modular/btquotients/btquotient.py index be9973262c6..e4d04fd2961 100644 --- a/src/sage/modular/btquotients/btquotient.py +++ b/src/sage/modular/btquotients/btquotient.py @@ -1921,7 +1921,7 @@ def dimension_harmonic_cocycles(self, k, lev=None, Nplus=None, character=None): f = lev.factor() if any(l[1] != 1 for l in f): - raise NotImplementedError('The level should be squarefree for ' 'this function to work... Sorry!') + raise NotImplementedError('The level should be squarefree for this function to work... Sorry!') def GH(N, ker): return Gamma0(N) if character is None else GammaH_constructor(N, ker) @@ -3542,7 +3542,7 @@ def _compute_quotient(self, check=True): print('Theoretical genus =', genus) raise RuntimeError if self.get_num_verts() != len(vertex_list): - raise RuntimeError('Number of vertices different ' 'from expected.') + raise RuntimeError('Number of vertices different from expected.') self._nontorsion_generators = nontorsion_generators self._boundary = {vv.rep: vv for vv in vertex_list} diff --git a/src/sage/modular/btquotients/pautomorphicform.py b/src/sage/modular/btquotients/pautomorphicform.py index fea273438bd..9e70cbde1e4 100644 --- a/src/sage/modular/btquotients/pautomorphicform.py +++ b/src/sage/modular/btquotients/pautomorphicform.py @@ -412,7 +412,7 @@ def _compute_element(self): minval = sum([RR(o.norm() ** 2) for o in err.list()]) verbose('Error = %s' % minval) except AttributeError: - verbose('Warning: something did not work in the ' 'computation') + verbose('Warning: something did not work in the computation') res = rest.transpose() return self.parent().free_module()(res.row(0)) @@ -708,7 +708,7 @@ def __init__(self, X, k, prec=None, basis_matrix=None, base_field=None): try: self._R = X.get_splitting_field() except AttributeError: - raise ValueError("It looks like you are not using Magma as" " backend...and still we don't know how " "to compute splittings in that case!") + raise ValueError("It looks like you are not using Magma as backend...and still we don't know how to compute splittings in that case!") else: pol = X.get_splitting_field().defining_polynomial().factor()[0][0] self._R = base_field.extension(pol, pol.variable_name()).absolute_field(name='r') @@ -1165,7 +1165,7 @@ def basis_matrix(self): x1 = self._M.right_kernel().matrix() if x1.nrows() != self.rank(): - raise RuntimeError('The computed dimension does not agree with ' 'the expectation. Consider increasing ' 'precision!') + raise RuntimeError('The computed dimension does not agree with the expectation. Consider increasing precision!') K = [c.list() for c in x1.rows()] diff --git a/src/sage/modular/buzzard.py b/src/sage/modular/buzzard.py index 71c1e11da3e..f4a36fee9cc 100644 --- a/src/sage/modular/buzzard.py +++ b/src/sage/modular/buzzard.py @@ -11,6 +11,7 @@ - Kevin Buzzard: PARI program that implements underlying functionality """ + ############################################################################# # Copyright (C) 2006 William Stein # diff --git a/src/sage/modular/cusps_nf.py b/src/sage/modular/cusps_nf.py index 3ce7d2fe9d3..cfd7dc5869f 100644 --- a/src/sage/modular/cusps_nf.py +++ b/src/sage/modular/cusps_nf.py @@ -66,6 +66,7 @@ Cusp [1: 3] of Number Field in a with defining polynomial x^2 + 5, ...] """ + # **************************************************************************** # Copyright (C) 2009, Maite Aranes # @@ -494,24 +495,24 @@ def __init__(self, number_field, a, b=None, parent=None, lreps=None): self.__b = R(r.denominator()) self.__a = R(r * self.__b) except (ValueError, TypeError): - raise TypeError(f"unable to convert {a} to a cusp " "of the number field") + raise TypeError(f"unable to convert {a} to a cusp of the number field") else: try: r = number_field(a) self.__b = R(r.denominator()) self.__a = R(r * self.__b) except (ValueError, TypeError): - raise TypeError("unable to convert %r to a cusp " "of the number field" % a) + raise TypeError("unable to convert %r to a cusp of the number field" % a) else: # 'b' is given if isinstance(b, InfinityElement): if isinstance(a, InfinityElement) or (isinstance(a, NFCusp) and a.is_infinity()): - raise TypeError("unable to convert (%r, %r) " "to a cusp of the number field" % (a, b)) + raise TypeError("unable to convert (%r, %r) to a cusp of the number field" % (a, b)) self.__a = R.zero() self.__b = R.one() return if not b: if not a: - raise TypeError("unable to convert (%r, %r) " "to a cusp of the number field" % (a, b)) + raise TypeError("unable to convert (%r, %r) to a cusp of the number field" % (a, b)) self.__a = R.one() self.__b = R.zero() return diff --git a/src/sage/modular/dims.py b/src/sage/modular/dims.py index 3e5d2edab7e..01d7a3e45a3 100644 --- a/src/sage/modular/dims.py +++ b/src/sage/modular/dims.py @@ -404,7 +404,7 @@ def dimension_cusp_forms(X, k=2): return X.dimension_cusp_forms(k) if isinstance(X, (int, Integer)): return Gamma0(X).dimension_cusp_forms(k) - raise TypeError("argument 1 must be a Dirichlet character, an integer " "or a finite index subgroup of SL2Z") + raise TypeError("argument 1 must be a Dirichlet character, an integer or a finite index subgroup of SL2Z") def dimension_eis(X, k=2): @@ -523,7 +523,7 @@ def dimension_modular_forms(X, k=2): return X.dimension_modular_forms(k) if isinstance(X, dirichlet.DirichletCharacter): return Gamma1(X.modulus()).dimension_modular_forms(k, eps=X) - raise TypeError("argument 1 must be an integer, a Dirichlet character " "or an arithmetic subgroup") + raise TypeError("argument 1 must be an integer, a Dirichlet character or an arithmetic subgroup") def sturm_bound(level, weight=2): diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index 05cbbb62aaa..9b937c3b09e 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -1619,7 +1619,7 @@ def kloosterman_sum(self, a=1, b=0): try: self(1) * zeta ** (a + b) except TypeError: - raise NotImplementedError('Kloosterman sums not implemented ' 'over this ring') + raise NotImplementedError('Kloosterman sums not implemented over this ring') n = zeta.multiplicative_order() zeta = zeta ** (n // m) for c in m.coprime_integers(m): diff --git a/src/sage/modular/drinfeld_modform/element.py b/src/sage/modular/drinfeld_modform/element.py index bf4a2a579b5..f193f2ac7ac 100644 --- a/src/sage/modular/drinfeld_modform/element.py +++ b/src/sage/modular/drinfeld_modform/element.py @@ -97,7 +97,7 @@ def __init__(self, parent, polynomial): if not isinstance(polynomial, MPolynomial): raise TypeError("input must be a multivariate polynomial") if not parent.base_ring().has_coerce_map_from(polynomial.base_ring()): - raise ValueError("unable to coerce base ring of the given " "polynomial into Drinfeld modular form ring") + raise ValueError("unable to coerce base ring of the given polynomial into Drinfeld modular form ring") poly = parent._poly_ring(polynomial) self._polynomial = poly diff --git a/src/sage/modular/drinfeld_modform/ring.py b/src/sage/modular/drinfeld_modform/ring.py index 9614589523b..4d88aa69454 100644 --- a/src/sage/modular/drinfeld_modform/ring.py +++ b/src/sage/modular/drinfeld_modform/ring.py @@ -262,9 +262,9 @@ def __classcall_private__(cls, base_ring, rank=None, group=None, has_type=False, TypeError: rank or names must be specified """ if not isinstance(base_ring, FractionField_generic): - raise TypeError("base ring must be a fraction field of a " "polynomial ring") + raise TypeError("base ring must be a fraction field of a polynomial ring") if not isinstance(base_ring.base(), PolynomialRing_generic): - raise NotImplementedError("Drinfeld modular forms are currently " "only implemented for A = Fq[T]") + raise NotImplementedError("Drinfeld modular forms are currently only implemented for A = Fq[T]") if not base_ring.characteristic(): raise ValueError("base ring characteristic must be finite") if not base_ring.base().base().is_field(): @@ -272,7 +272,7 @@ def __classcall_private__(cls, base_ring, rank=None, group=None, has_type=False, if not base_ring.base().base().is_finite(): raise ValueError("the ring of constants must be finite") if group is not None: # placeholder - raise NotImplementedError("Drinfeld modular forms are currently " "only implemented for the full group") + raise NotImplementedError("Drinfeld modular forms are currently only implemented for the full group") if names is None: # default names if rank is None: raise TypeError("rank or names must be specified") @@ -292,9 +292,9 @@ def __classcall_private__(cls, base_ring, rank=None, group=None, has_type=False, g = names[0] names = [f'{g}{i}' for i in range(1, rank + 1)] elif nb_names != rank: - raise ValueError(f"the number of generators (={nb_names}) " f"must be equal to the rank (={rank})") + raise ValueError(f"the number of generators (={nb_names}) must be equal to the rank (={rank})") else: - raise TypeError("names must be None, a comma separated string " "or a list of string") + raise TypeError("names must be None, a comma separated string or a list of string") return cls.__classcall__(cls, base_ring, rank, group, has_type, tuple(names)) def __init__(self, base_ring, rank, group, has_type, names): @@ -506,7 +506,7 @@ def coefficient_form(self, i, a=None): i = ZZ(i) if a is None: if i < 1 or i > self.rank(): - raise ValueError(f"index (={i}) must be >= 1 and <= rank " f"(={self.rank()})") + raise ValueError(f"index (={i}) must be >= 1 and <= rank (={self.rank()})") return self._generator_coefficient_form(i) try: A = self._base_ring.base() @@ -516,7 +516,7 @@ def coefficient_form(self, i, a=None): except ValueError: raise ValueError("a must be an integral element") if i < 1 or i > a.degree() * self.rank(): - raise ValueError(f"index (={i}) must be >= 1 and <= deg(a)*rank " f"(={a.degree()*self.rank()})") + raise ValueError(f"index (={i}) must be >= 1 and <= deg(a)*rank (={a.degree() * self.rank()})") coeff_forms = self._coefficient_forms(a) return coeff_forms[i - 1] diff --git a/src/sage/modular/etaproducts.py b/src/sage/modular/etaproducts.py index 8faed6ee879..53e1705dfcf 100644 --- a/src/sage/modular/etaproducts.py +++ b/src/sage/modular/etaproducts.py @@ -83,7 +83,6 @@ def EtaGroup(level): class EtaGroupElement(Element): - def __init__(self, parent, rdict) -> None: r""" Create an eta product object. Usually called implicitly via diff --git a/src/sage/modular/hecke/algebra.py b/src/sage/modular/hecke/algebra.py index 046dd0a3e3f..9c8197d3225 100644 --- a/src/sage/modular/hecke/algebra.py +++ b/src/sage/modular/hecke/algebra.py @@ -12,6 +12,7 @@ in the category of Hecke modules are not required to commute with the action of the full Hecke algebra, only with the anemic algebra. """ + # **************************************************************************** # Copyright (C) 2004 William Stein # diff --git a/src/sage/modular/hecke/ambient_module.py b/src/sage/modular/hecke/ambient_module.py index c30ed9f23b6..6379017a1ee 100644 --- a/src/sage/modular/hecke/ambient_module.py +++ b/src/sage/modular/hecke/ambient_module.py @@ -2,6 +2,7 @@ """ Ambient Hecke modules """ + # **************************************************************************** # Sage: Open Source Mathematical Software # @@ -366,11 +367,11 @@ def degeneracy_map(self, codomain, t=1): else: err = True if err: - raise ValueError(("the level of self (=%s) must be a divisor or multiple of " "level (=%s) and t (=%s) must be a divisor of the quotient") % (self.level(), level, t)) + raise ValueError(("the level of self (=%s) must be a divisor or multiple of level (=%s) and t (=%s) must be a divisor of the quotient") % (self.level(), level, t)) eps = self.character() if eps is not None and level % eps.conductor() != 0: - raise ArithmeticError("the conductor of the character of this space " "(=%s) must be divisible by the level (=%s)" % (eps.conductor(), level)) + raise ArithmeticError("the conductor of the character of this space (=%s) must be divisible by the level (=%s)" % (eps.conductor(), level)) if M is None: M = self.hecke_module_of_level(level) diff --git a/src/sage/modular/hecke/hecke_operator.py b/src/sage/modular/hecke/hecke_operator.py index 655df476dce..0b00ab68eb2 100644 --- a/src/sage/modular/hecke/hecke_operator.py +++ b/src/sage/modular/hecke/hecke_operator.py @@ -2,6 +2,7 @@ """ Hecke operators """ + # **************************************************************************** # Copyright (C) 2004 William Stein # diff --git a/src/sage/modular/hecke/homspace.py b/src/sage/modular/hecke/homspace.py index 5557b662749..96ecdd8ff7b 100644 --- a/src/sage/modular/hecke/homspace.py +++ b/src/sage/modular/hecke/homspace.py @@ -2,6 +2,7 @@ r""" Hom spaces between Hecke modules """ + # **************************************************************************** # Copyright (C) 2005 William Stein # diff --git a/src/sage/modular/hecke/module.py b/src/sage/modular/hecke/module.py index 57ddaffb4e3..61e79fb46d0 100644 --- a/src/sage/modular/hecke/module.py +++ b/src/sage/modular/hecke/module.py @@ -1606,7 +1606,7 @@ def projection(self): except AttributeError: i = self.factor_number() if i == -1: - raise NotImplementedError("Computation of projection only implemented " "for decomposition factors.") + raise NotImplementedError("Computation of projection only implemented for decomposition factors.") A = self.ambient_hecke_module() B = A.decomposition_matrix_inverse() i = A.decomposition().index(self) diff --git a/src/sage/modular/hecke/morphism.py b/src/sage/modular/hecke/morphism.py index 0c0175c1fbd..f45250316c3 100644 --- a/src/sage/modular/hecke/morphism.py +++ b/src/sage/modular/hecke/morphism.py @@ -24,7 +24,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.misc import misc from sage.modules.matrix_morphism import MatrixMorphism from sage.categories.morphism import Morphism diff --git a/src/sage/modular/hecke/submodule.py b/src/sage/modular/hecke/submodule.py index 81925e91d62..70f12a25c93 100644 --- a/src/sage/modular/hecke/submodule.py +++ b/src/sage/modular/hecke/submodule.py @@ -567,7 +567,7 @@ def dual_free_module(self, bound=None, anemic=True, use_star=True): if V2.rank() == self.rank(): return V2 - raise RuntimeError("Computation of embedded dual vector space failed " "(cut down to rank %s, but should have cut down to rank %s)." % (V.rank(), self.rank())) + raise RuntimeError("Computation of embedded dual vector space failed (cut down to rank %s, but should have cut down to rank %s)." % (V.rank(), self.rank())) def free_module(self): """ @@ -623,7 +623,7 @@ def intersection(self, other): 1 """ if self.ambient_hecke_module() != other.ambient_hecke_module(): - raise ArithmeticError("intersection only defined for subspaces of" " a common ambient modular symbols space") + raise ArithmeticError("intersection only defined for subspaces of a common ambient modular symbols space") if other.is_ambient(): return self if self.is_ambient(): diff --git a/src/sage/modular/local_comp/local_comp.py b/src/sage/modular/local_comp/local_comp.py index bf6660354d2..0bb7c56b486 100644 --- a/src/sage/modular/local_comp/local_comp.py +++ b/src/sage/modular/local_comp/local_comp.py @@ -19,6 +19,7 @@ - David Loeffler - Jared Weinstein """ + from typing import Self from sage.misc.abstract_method import abstract_method @@ -711,7 +712,6 @@ def characters(self): T = self.type_space() p = self.prime() if self.conductor() % 2 == 0: - G = SmoothCharacterGroupUnramifiedQuadratic(self.prime(), self.coefficient_field()) n = self.conductor() // 2 diff --git a/src/sage/modular/modform/ambient.py b/src/sage/modular/modform/ambient.py index 2ca85facd40..718f988624c 100644 --- a/src/sage/modular/modform/ambient.py +++ b/src/sage/modular/modform/ambient.py @@ -438,7 +438,7 @@ def eisenstein_submodule(self): """ return eisenstein_submodule.EisensteinSubmodule(self) - @cached_method(key=lambda self, p: (Integer(p) if p is not None else p)) # convert p to an Integer before looking this up in the cache + @cached_method(key=lambda self, p: Integer(p) if p is not None else p) # convert p to an Integer before looking this up in the cache def new_submodule(self, p=None): """ Return the new or `p`-new submodule of this ambient diff --git a/src/sage/modular/modform/eis_series.py b/src/sage/modular/modform/eis_series.py index 52dbd901d34..b1d6ab1ce35 100644 --- a/src/sage/modular/modform/eis_series.py +++ b/src/sage/modular/modform/eis_series.py @@ -421,7 +421,7 @@ def eisenstein_series_lseries(weight, prec=53, max_imaginary_part=0): from sage.lfunctions.pari import lfun_eisenstein, LFunction L = LFunction(lfun_eisenstein(weight), prec=prec, max_im=max_imaginary_part) - L.rename(f'L-series associated to the Eisenstein series E{weight} ' 'on SL_2(Z)') + L.rename(f'L-series associated to the Eisenstein series E{weight} on SL_2(Z)') return L diff --git a/src/sage/modular/modform/eisenstein_submodule.py b/src/sage/modular/modform/eisenstein_submodule.py index c02805acc75..de56e14d16f 100644 --- a/src/sage/modular/modform/eisenstein_submodule.py +++ b/src/sage/modular/modform/eisenstein_submodule.py @@ -122,7 +122,6 @@ def modular_symbols(self, sign=0): class EisensteinSubmodule_params(EisensteinSubmodule): - @cached_method def parameters(self): r""" diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 9f28e9340b5..f12a28d2490 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -1116,7 +1116,7 @@ def lseries(self, embedding=0, prec=53, max_imaginary_part=0, max_asymp_coeffs=4 # get global root number w = self.atkin_lehner_eigenvalue(N, embedding=emb) - e = ~C.gen() ** l * w + e = ~(C.gen() ** l) * w if self.is_cuspidal(): poles = [] # cuspidal @@ -2487,7 +2487,7 @@ def minimal_twist(self, p=None): epsg = g.character().extend(N) chisq = (epsg / self.character()).restrict(p ** (r // 2)) K = coercion_model.common_parent(self.base_ring(), g.base_ring()) - chis = [chi for chi in DirichletGroup(p ** (r // 2), K) if chi ** 2 == chisq] + chis = [chi for chi in DirichletGroup(p ** (r // 2), K) if chi**2 == chisq] if g.has_cm() and g.cm_discriminant().prime_divisors() == [p]: # Quicker to test g than self, because g has smaller level. diff --git a/src/sage/modular/modform/j_invariant.py b/src/sage/modular/modform/j_invariant.py index 45762082fc6..9e3be4ba98e 100644 --- a/src/sage/modular/modform/j_invariant.py +++ b/src/sage/modular/modform/j_invariant.py @@ -2,6 +2,7 @@ r""" `q`-expansion of `j`-invariant """ + from sage.modular.modform.eis_series import eisenstein_series_qexp from sage.modular.modform.vm_basis import delta_qexp from sage.rings.rational_field import QQ diff --git a/src/sage/modular/modform/l_series_gross_zagier.py b/src/sage/modular/modform/l_series_gross_zagier.py index 57378356b0e..41b92f40974 100644 --- a/src/sage/modular/modform/l_series_gross_zagier.py +++ b/src/sage/modular/modform/l_series_gross_zagier.py @@ -10,7 +10,6 @@ class GrossZagierLseries(SageObject): - def __init__(self, E, A, prec=53, max_imaginary_part=0) -> None: r""" Class for the Gross-Zagier `L`-series. @@ -56,7 +55,7 @@ def __init__(self, E, A, prec=53, max_imaginary_part=0) -> None: K = A.gens()[0].parent() D = K.disc() if not (K.degree() == 2 and D < 0): - raise ValueError("A is not an ideal class in an" " imaginary quadratic field") + raise ValueError("A is not an ideal class in an imaginary quadratic field") Q = ideal.quadratic_form().reduced_form() epsilon = -kronecker_character(D)(N) diff --git a/src/sage/modular/modform/ring.py b/src/sage/modular/modform/ring.py index a4395190023..34e71514aef 100644 --- a/src/sage/modular/modform/ring.py +++ b/src/sage/modular/modform/ring.py @@ -408,7 +408,7 @@ def _generators_variables_dictionary(self, poly_parent, gens): nb_var = poly_parent.ngens() nb_gens = self.ngens() if nb_var != nb_gens: - raise ValueError('the number of variables (%s) must be equal to' ' the number of generators of the modular forms' ' ring (%s)' % (nb_var, self.ngens())) + raise ValueError('the number of variables (%s) must be equal to the number of generators of the modular forms ring (%s)' % (nb_var, self.ngens())) return {poly_parent.gen(i): self(gens[i]) for i in range(nb_var)} def from_polynomial(self, polynomial, gens=None): @@ -807,7 +807,7 @@ def generators(self, maxweight=8, prec=10, start_gens=[], start_weight=2) -> lis for x in start_gens: if len(x) == 2: if x[1].prec() < prec: - raise ValueError("Requested precision cannot be higher" " than precision of approximate starting " "generators!") + raise ValueError("Requested precision cannot be higher than precision of approximate starting generators!") sgs.append((x[0], x[1], None)) else: sgs.append(x) @@ -931,7 +931,6 @@ def _find_generators(self, maxweight, start_gens, start_weight) -> list: k += 1 while k <= maxweight: - if self.modular_forms_of_weight(k).dimension() == 0: k += increment continue diff --git a/src/sage/modular/modform/space.py b/src/sage/modular/modform/space.py index a6315dfadb8..ce960ee4910 100644 --- a/src/sage/modular/modform/space.py +++ b/src/sage/modular/modform/space.py @@ -1015,7 +1015,6 @@ def _element_constructor_(self, x, check=True): 4 + 6*q + 47*q^2 + 143*q^3 + 358*q^4 + 630*q^5 + O(q^6) """ if isinstance(x, ModularFormElement): - if not check: from copy import copy diff --git a/src/sage/modular/modform_hecketriangle/abstract_space.py b/src/sage/modular/modform_hecketriangle/abstract_space.py index 7b19b00c918..045b18a7773 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_space.py +++ b/src/sage/modular/modform_hecketriangle/abstract_space.py @@ -6,6 +6,7 @@ - Jonas Jermann (2013): initial version """ + # **************************************************************************** # Copyright (C) 2013-2014 Jonas Jermann # diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py index 5d4a287b7a1..d0bd9188481 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_group_element.py @@ -813,7 +813,7 @@ def _primitive_block_decomposition_data(self): R = R * G.T().inverse() L = (one, one) else: - raise RuntimeError("There is something wrong in the method " "_primitive_block_decomposition_data. Please contact sage-devel@googlegroups.com") + raise RuntimeError("There is something wrong in the method _primitive_block_decomposition_data. Please contact sage-devel@googlegroups.com") return (L, R) @@ -1068,7 +1068,7 @@ def primitive_representative(self, method='block'): return (P, R) - raise ValueError("if the element is not elliptic, then method must " "be either be 'cf' or 'block'") + raise ValueError("if the element is not elliptic, then method must be either be 'cf' or 'block'") def primitive_part(self, method='cf'): r""" @@ -1373,7 +1373,7 @@ def primitive_power(self, method='cf'): # L = [one, ZZ(-j)] break else: - raise RuntimeError("There is a problem in the method " "'primitive_power'. Please contact sage-devel@googlegroups.com") + raise RuntimeError("There is a problem in the method 'primitive_power'. Please contact sage-devel@googlegroups.com") if abs(j) < G.n() / two: return j diff --git a/src/sage/modular/modsym/ambient.py b/src/sage/modular/modsym/ambient.py index da048841675..c8f86832b5e 100644 --- a/src/sage/modular/modsym/ambient.py +++ b/src/sage/modular/modsym/ambient.py @@ -432,7 +432,7 @@ def _element_constructor_(self, x, computed_with_hecke=False): """ if isinstance(x, FreeModuleElement): if x.degree() != self.dimension(): - raise TypeError("Incompatible degrees: x has degree " f"{x.degree()} but modular symbols space has " f"dimension {self.dimension()}") + raise TypeError(f"Incompatible degrees: x has degree {x.degree()} but modular symbols space has dimension {self.dimension()}") return self.element_class(self, x) if isinstance(x, (ManinSymbol, element.ModularSymbolsElement)): diff --git a/src/sage/modular/modsym/boundary.py b/src/sage/modular/modsym/boundary.py index 2b03ab1302e..c0b1b5610c7 100644 --- a/src/sage/modular/modsym/boundary.py +++ b/src/sage/modular/modsym/boundary.py @@ -88,7 +88,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - import sage.modular.arithgroup.all as arithgroup import sage.modular.hecke.all as hecke from sage.categories.rings import Rings diff --git a/src/sage/modular/modsym/ghlist.py b/src/sage/modular/modsym/ghlist.py index 8172d5b2064..346eb0cd4a4 100644 --- a/src/sage/modular/modsym/ghlist.py +++ b/src/sage/modular/modsym/ghlist.py @@ -2,6 +2,7 @@ r""" List of coset representatives for `\Gamma_H(N)` in `\SL_2(\ZZ)` """ + ########################################################################### # Sage: Open Source Mathematical Software # diff --git a/src/sage/modular/modsym/modsym.py b/src/sage/modular/modsym/modsym.py index 1817617add7..54be04319b6 100644 --- a/src/sage/modular/modsym/modsym.py +++ b/src/sage/modular/modsym/modsym.py @@ -371,11 +371,9 @@ def ModularSymbols(group=1, weight=2, sign=0, base_ring=None, use_cache=True, cu M = ambient.ModularSymbolsAmbient_wtk_g0(group.level(), weight, sign, base_ring, custom_init=custom_init) elif isinstance(group, arithgroup.Gamma1_class): - M = ambient.ModularSymbolsAmbient_wtk_g1(group.level(), weight, sign, base_ring, custom_init=custom_init) elif isinstance(group, arithgroup.GammaH_class): - M = ambient.ModularSymbolsAmbient_wtk_gamma_h(group, weight, sign, base_ring, custom_init=custom_init) elif isinstance(group, tuple): diff --git a/src/sage/modular/modsym/modular_symbols.py b/src/sage/modular/modsym/modular_symbols.py index ef66e0e3e07..ff1b6277da6 100644 --- a/src/sage/modular/modsym/modular_symbols.py +++ b/src/sage/modular/modsym/modular_symbols.py @@ -15,6 +15,7 @@ sage: loads(dumps(s)) == s True """ + # **************************************************************************** # Sage: Open Source Mathematical Software # diff --git a/src/sage/modular/modsym/subspace.py b/src/sage/modular/modsym/subspace.py index 708a9ba06a6..6613063174a 100644 --- a/src/sage/modular/modsym/subspace.py +++ b/src/sage/modular/modsym/subspace.py @@ -314,7 +314,7 @@ def factorization(self): r = self.dimension() s = sum([A.rank() * mult for A, mult in D]) if r != s: - raise NotImplementedError("modular symbols factorization not fully implemented yet " "-- self has dimension %s, but sum of dimensions of factors is %s" % (r, s)) + raise NotImplementedError("modular symbols factorization not fully implemented yet -- self has dimension %s, but sum of dimensions of factors is %s" % (r, s)) self._factorization = sage.structure.factorization.Factorization(D, cr=True) return self._factorization diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index 57ed9aba5ca..abb05951eba 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -156,6 +156,7 @@ Periods in Quantum Field Theory and Arithmetic, Springer Proceedings in Mathematics and Statistics 314, 2020 """ + # **************************************************************************** # Copyright (C) 2020 Frédéric Chapoton # diff --git a/src/sage/modular/multiple_zeta_F_algebra.py b/src/sage/modular/multiple_zeta_F_algebra.py index c7f304bedfe..16d374eeabd 100644 --- a/src/sage/modular/multiple_zeta_F_algebra.py +++ b/src/sage/modular/multiple_zeta_F_algebra.py @@ -19,6 +19,7 @@ - Frédéric Chapoton (2022-09): Initial version """ + # **************************************************************************** # Copyright (C) 2022 Frédéric Chapoton # diff --git a/src/sage/modular/overconvergent/genus0.py b/src/sage/modular/overconvergent/genus0.py index a6b9f9c72a4..4b1cda216fd 100644 --- a/src/sage/modular/overconvergent/genus0.py +++ b/src/sage/modular/overconvergent/genus0.py @@ -187,6 +187,7 @@ sage: efuncs[3].slope() 9 """ + # **************************************************************************** # Copyright (C) 2008 William Stein # 2008-9 David Loeffler diff --git a/src/sage/modular/overconvergent/weightspace.py b/src/sage/modular/overconvergent/weightspace.py index 88da844aef0..cdf02402cfe 100644 --- a/src/sage/modular/overconvergent/weightspace.py +++ b/src/sage/modular/overconvergent/weightspace.py @@ -677,7 +677,6 @@ def Lvalue(self): class ArbitraryWeight(WeightCharacter): - def __init__(self, parent, w, t): r""" Create the element of `p`-adic weight space in the given component diff --git a/src/sage/modular/pollack_stevens/distributions.py b/src/sage/modular/pollack_stevens/distributions.py index f6e74bb0d7b..7672ca7b826 100644 --- a/src/sage/modular/pollack_stevens/distributions.py +++ b/src/sage/modular/pollack_stevens/distributions.py @@ -520,7 +520,7 @@ def approx_module(self, M=None): elif M > self._prec_cap: raise ValueError("M (=%s) must be less than or equal to the precision cap (=%s)" % (M, self._prec_cap)) elif M < self._prec_cap and self.is_symk(): - raise ValueError("Sym^k objects do not support approximation " "modules") + raise ValueError("Sym^k objects do not support approximation modules") return self.base_ring() ** M def random_element(self, M=None, **args): @@ -623,7 +623,6 @@ def _an_element_(self): class Symk_class(OverconvergentDistributions_abstract): - def __init__(self, k, base, character, adjuster, act_on_left, dettwist, act_padic, implementation): r""" EXAMPLES:: diff --git a/src/sage/modular/pollack_stevens/fund_domain.py b/src/sage/modular/pollack_stevens/fund_domain.py index cf2d190866b..baea1615d78 100644 --- a/src/sage/modular/pollack_stevens/fund_domain.py +++ b/src/sage/modular/pollack_stevens/fund_domain.py @@ -654,7 +654,6 @@ def __init__(self, N): # ------------------------------------------------------------------ for r in range(len(coset_reps)): if not boundary_checked[r]: - # We now check if this boundary edge is glued to itself by # Gamma_0(N) @@ -698,7 +697,6 @@ def __init__(self, N): # the unimodular path described by coset_reps[r] # contains a point fixed by a 3-torsion element. if (c**2 + d**2 + c * d) % N == 0: - # the index r is adding to our list of indexes # of generators gens_index.append(r) @@ -1173,7 +1171,6 @@ def form_list_of_cusps(self): for s in range(1, len(C), 2): # range over odd indices in the final list C if C[s] == "?": - # Single out our two cusps (path from cusp2 to cusp1) cusp1 = C[s - 1] cusp2 = C[s + 1] @@ -1207,7 +1204,6 @@ def form_list_of_cusps(self): # extended no further. if (b1**2 + b2**2 + b1 * b2) % N != 0: - # this congruence is exactly equivalent to # gam * [0 -1; 1 -1] * gam^(-1) is in Gamma_0(N) # where gam is the matrix corresponding to the diff --git a/src/sage/modular/pollack_stevens/modsym.py b/src/sage/modular/pollack_stevens/modsym.py index 9facdcc2ed4..acdc6cafe60 100644 --- a/src/sage/modular/pollack_stevens/modsym.py +++ b/src/sage/modular/pollack_stevens/modsym.py @@ -1228,7 +1228,7 @@ def lift(self, p=None, M=None, alpha=None, new_base_ring=None, algorithm=None, e algorithm = 'greenberg' if eigensymbol else 'stevens' elif algorithm == 'greenberg': if not eigensymbol: - raise ValueError("Greenberg's algorithm only works" " for eigensymbols. Try 'stevens'") + raise ValueError("Greenberg's algorithm only works for eigensymbols. Try 'stevens'") elif algorithm != 'stevens': raise ValueError("algorithm %s not recognized" % algorithm) if eigensymbol: @@ -1371,7 +1371,7 @@ def _find_aq(self, p, M, check): else: eisenloss = (aq - 1).valuation(p) if q >= 50: - raise ValueError("The symbol appears to be eisenstein -- " "not implemented yet") + raise ValueError("The symbol appears to be eisenstein -- not implemented yet") return q, aq, eisenloss def _find_extraprec(self, p, M, alpha, check): @@ -1494,7 +1494,6 @@ def p_stabilize_and_lift(self, p, M, alpha=None, ap=None, new_base_ring=None, or class PSModularSymbolElement_dist(PSModularSymbolElement): - def reduce_precision(self, M): r""" Only hold on to `M` moments of each value of ``self``. diff --git a/src/sage/modular/pollack_stevens/sigma0.py b/src/sage/modular/pollack_stevens/sigma0.py index a6528b06b09..fa8fa864fc1 100644 --- a/src/sage/modular/pollack_stevens/sigma0.py +++ b/src/sage/modular/pollack_stevens/sigma0.py @@ -60,7 +60,6 @@ class Sigma0ActionAdjuster(UniqueRepresentation): - @abstract_method def __call__(self, x): r""" diff --git a/src/sage/modular/pollack_stevens/space.py b/src/sage/modular/pollack_stevens/space.py index 364aad738f6..52483afbdf4 100644 --- a/src/sage/modular/pollack_stevens/space.py +++ b/src/sage/modular/pollack_stevens/space.py @@ -56,6 +56,7 @@ sage: phi.parent() Space of modular symbols for Congruence Subgroup Gamma0(37) with sign 0 and values in Sym^0 Q^2 """ + # **************************************************************************** # Copyright (C) 2012 Robert Pollack # @@ -153,7 +154,7 @@ def create_key(self, group, weight=None, sign=0, base_ring=None, p=None, prec_ca character = None if weight is None: - raise ValueError("you must specify a weight " "or coefficient module") + raise ValueError("you must specify a weight or coefficient module") if prec_cap is None: coefficients = Symk(weight, base_ring, character) @@ -161,7 +162,7 @@ def create_key(self, group, weight=None, sign=0, base_ring=None, p=None, prec_ca coefficients = OverconvergentDistributions(weight, p, prec_cap, base_ring, character) else: if weight is not None or base_ring is not None or p is not None or prec_cap is not None: - raise ValueError("if coefficients are specified, then weight, " "base_ring, p, and prec_cap must take their " "default value None") + raise ValueError("if coefficients are specified, then weight, base_ring, p, and prec_cap must take their default value None") return (group, coefficients, sign) @@ -865,7 +866,7 @@ def ps_modsym_from_elliptic_curve(E, sign=0, implementation='eclib'): [-1/6, 1/3, 1/2, 1/6, -1/6, 1/3, -1/3, -1/2, -1/6, 1/6, 0, -1/6, -1/6] """ if E.base_ring() is not QQ: - raise ValueError("The elliptic curve must be defined over the " "rationals.") + raise ValueError("The elliptic curve must be defined over the rationals.") sign = Integer(sign) if sign not in [0, 1, -1]: raise ValueError("The sign must be either 0, 1 or -1") @@ -1037,7 +1038,7 @@ def ps_modsym_from_simple_modsym_space(A, name='alpha'): raise ValueError("A must have positive dimension") if A.sign() == 0: - raise ValueError("A must have sign +1 or -1 (otherwise it is" " not simple)") + raise ValueError("A must have sign +1 or -1 (otherwise it is not simple)") if not A.is_new(): raise ValueError("A must be new") diff --git a/src/sage/modular/quasimodform/element.py b/src/sage/modular/quasimodform/element.py index 3e387308007..c5e3023e323 100644 --- a/src/sage/modular/quasimodform/element.py +++ b/src/sage/modular/quasimodform/element.py @@ -7,6 +7,7 @@ - DAVID AYOTTE (2021-03-18): initial version - Seewoo Lee (2023-09): coefficients method """ + # **************************************************************************** # Copyright (C) 2021 David Ayotte # 2023 Seewoo Lee @@ -337,7 +338,7 @@ def depth(self): ValueError: the given graded quasiform is not an homogeneous element """ if not self.is_homogeneous(): - raise ValueError("the given graded quasiform is not an " "homogeneous element") + raise ValueError("the given graded quasiform is not an homogeneous element") return self._polynomial.degree() def is_zero(self) -> bool: @@ -573,7 +574,7 @@ def weight(self) -> Integer: """ if self.is_homogeneous(): return self._polynomial.leading_coefficient().weight() + 2 * self._polynomial.degree() - raise ValueError("the given graded quasiform is not an homogeneous " "element") + raise ValueError("the given graded quasiform is not an homogeneous element") degree = weight # alias diff --git a/src/sage/modules/fg_pid/fgp_module.py b/src/sage/modules/fg_pid/fgp_module.py index 7f967331c33..65dc3f8171e 100644 --- a/src/sage/modules/fg_pid/fgp_module.py +++ b/src/sage/modules/fg_pid/fgp_module.py @@ -1306,7 +1306,6 @@ def coordinate_vector(self, x, reduce=False): c = self._V.coordinate_vector(x.lift()) b = (c * T).change_ring(self.base_ring()) if reduce and self.base_ring() == ZZ: - I = self.invariants() return b.parent()([b[i] if I[i] == 0 else b[i] % I[i] for i in range(len(I))]) diff --git a/src/sage/modules/filtered_vector_space.py b/src/sage/modules/filtered_vector_space.py index 16382df1cd1..a2016e8a488 100644 --- a/src/sage/modules/filtered_vector_space.py +++ b/src/sage/modules/filtered_vector_space.py @@ -371,7 +371,6 @@ def construct_from_generators_indices(generators, filtration, base_ring, check): class FilteredVectorSpace_class(FreeModule_ambient_field): - def __init__(self, base_ring, dim, generators, filtration, check=True): r""" A descending filtration of a vector space. diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py index 35365706d77..043c0f9b0d3 100644 --- a/src/sage/modules/fp_graded/free_module.py +++ b/src/sage/modules/fp_graded/free_module.py @@ -744,7 +744,7 @@ def element_from_coordinates(self, coordinates, n): """ D = self.vector_presentation(n).dimension() if len(coordinates) != D: - raise ValueError('the given coordinate vector has incorrect length (%d); ' 'it should have length %d' % (len(coordinates), D)) + raise ValueError('the given coordinate vector has incorrect length (%d); it should have length %d' % (len(coordinates), D)) # Performance testing using this real life example: # @@ -850,7 +850,7 @@ def generator(self, index): try: return self.gens()[index] except IndexError: - raise ValueError('the parent module has generators in the index ' 'range [0, %s]; generator %s does not exist' % (len(self.generator_degrees()) - 1, index)) + raise ValueError('the parent module has generators in the index range [0, %s]; generator %s does not exist' % (len(self.generator_degrees()) - 1, index)) gen = generator diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py index 73d2c09b721..9c9f1653bd8 100644 --- a/src/sage/modules/fp_graded/module.py +++ b/src/sage/modules/fp_graded/module.py @@ -776,7 +776,7 @@ def element_from_coordinates(self, coordinates, n): M_n = self.vector_presentation(n) if len(coordinates) != M_n.dimension(): - raise ValueError('the given coordinate vector has incorrect length (%d); ' 'it should have length %d' % (len(coordinates), M_n.dimension())) + raise ValueError('the given coordinate vector has incorrect length (%d); it should have length %d' % (len(coordinates), M_n.dimension())) free_element = self._free_module().element_from_coordinates(M_n.lift(coordinates), n) diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py index c20b207469b..34bc3a103a0 100644 --- a/src/sage/modules/fp_graded/morphism.py +++ b/src/sage/modules/fp_graded/morphism.py @@ -107,7 +107,6 @@ def _create_relations_matrix(module, relations, source_degs, target_degs): target_space = module.vector_presentation(target_degs[i]) for j, r_ij in enumerate(r_i): - values = [] for b in module.basis_elements(source_degs[j]): w = r_ij * b @@ -216,7 +215,7 @@ def __init__(self, parent, values, check=True): # Check the homomorphism is well defined. if len(D.generator_degrees()) != len(values): - raise ValueError('the number of values must equal the number of ' 'generators in the domain; invalid argument: %s' % values) + raise ValueError('the number of values must equal the number of generators in the domain; invalid argument: %s' % values) self._values = tuple(values) @@ -1132,7 +1131,7 @@ def lift(self, f, verbose=False): # It is an error to call this function with incompatible arguments. if f.codomain() is not N: - raise ValueError('the codomains of this homomorphism and the homomorphism ' 'we are lifting over are different') + raise ValueError('the codomains of this homomorphism and the homomorphism we are lifting over are different') # The trivial map lifts over any other map. if self.is_zero(): @@ -1141,7 +1140,7 @@ def lift(self, f, verbose=False): # A non-trivial map never lifts over the trivial map. if f.is_zero(): if verbose: - print('This homomorphism cannot lift over a trivial homomorphism' ' since it is non-trivial.') + print('This homomorphism cannot lift over a trivial homomorphism since it is non-trivial.') return None xs = [f.solve(self(g)) for g in L.generators()] @@ -1150,7 +1149,7 @@ def lift(self, f, verbose=False): # hope finding a lift. if None in xs: if verbose: - print('The generators of the domain of this homomorphism do ' 'not map into the image of the homomorphism we are lifting over.') + print('The generators of the domain of this homomorphism do not map into the image of the homomorphism we are lifting over.') return None # If L is free there are no relations to take into consideration. @@ -1178,7 +1177,7 @@ def lift(self, f, verbose=False): y = iK.solve(sum([c * x for c, x in zip(r.dense_coefficient_list(), xs)])) if y is None: if verbose: - print('The homomorphism cannot be lifted in any ' 'way such that the relations of the domain are ' 'respected.') + print('The homomorphism cannot be lifted in any way such that the relations of the domain are respected.') return None if y.is_zero(): @@ -1199,7 +1198,7 @@ def lift(self, f, verbose=False): except ValueError as error: if str(error) == 'matrix equation has no solutions': if verbose: - print('The homomorphism cannot be lifted in any ' 'way such that the relations of the domain ' 'are respected: %s' % error) + print('The homomorphism cannot be lifted in any way such that the relations of the domain are respected: %s' % error) return None raise ValueError(error) @@ -1208,7 +1207,6 @@ def lift(self, f, verbose=False): # $ K_1\oplus K_2\oplus \ldots \oplus K_n $. n = 0 for j, source_degree in enumerate(source_degs): - source_dimension = block_matrix[0][j].domain().dimension() w = K.element_from_coordinates(solution[n : n + source_dimension], source_degree) @@ -1315,7 +1313,7 @@ def homology(self, f, top_dim=None, verbose=False): k = self.kernel_inclusion(top_dim, verbose) f_ = f.lift(k) if f_ is None: - raise ValueError('the image of the given homomorphism is not contained ' 'in the kernel of this homomorphism; the homology is ' 'therefore not defined for this pair of maps') + raise ValueError('the image of the given homomorphism is not contained in the kernel of this homomorphism; the homology is therefore not defined for this pair of maps') return f_.cokernel_projection() @@ -1702,7 +1700,6 @@ def _resolve_kernel(self, top_dim=None, verbose=False): # The induction loop. for n in range(dim, limit + 1): - if verbose: print(' %d' % n, end='') @@ -1829,7 +1826,6 @@ def _resolve_image(self, top_dim=None, verbose=False): print('Resolving the image in the range of dimensions [%d, %d]:' % (dim, limit), end='') for n in range(dim, limit + 1): - if verbose: print(' %d' % n, end='') @@ -1848,7 +1844,6 @@ def _resolve_image(self, top_dim=None, verbose=False): new_values = tuple([self.codomain().element_from_coordinates(q, n) for q in image_n.basis()]) else: - j_n = j.vector_presentation(n) Q_n = image_n.quotient(j_n.image()) diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 9b079ba3fa6..09bfe867b8b 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -278,7 +278,7 @@ def create_object(self, version, key): raise TypeError("Argument sparse (= %s) must be True or False" % sparse) if base_ring not in CommutativeRings(): - warn("You are constructing a free module\n" "over a noncommutative ring. Sage does not have a concept\n" "of left/right and both sided modules, so be careful.\n" "It's also not guaranteed that all multiplications are\n" "done from the right side.") + warn("You are constructing a free module\nover a noncommutative ring. Sage does not have a concept\nof left/right and both sided modules, so be careful.\nIt's also not guaranteed that all multiplications are\ndone from the right side.") # raise TypeError("the base_ring must be a commutative ring") if not sparse and isinstance(base_ring, sage.rings.abc.RealDoubleField): @@ -542,7 +542,7 @@ def FreeModule(base_ring, rank_or_basis_keys=None, sparse=False, inner_product_m rank = n if rank is not None and basis_keys is not None and rank != len(basis_keys): - raise ValueError(f"inconsistent rank: should be cardinality of {basis_keys} " f"but got {rank}") + raise ValueError(f"inconsistent rank: should be cardinality of {basis_keys} but got {rank}") if not with_basis: if inner_product_matrix is not None: @@ -566,7 +566,7 @@ def FreeModule(base_ring, rank_or_basis_keys=None, sparse=False, inner_product_m if inner_product_matrix is not None: raise NotImplementedError if rank is not None and rank != len(basis_keys): - raise ValueError(f'inconsistent basis_keys: should be of cardinality {rank}, ' f'got {basis_keys}') + raise ValueError(f'inconsistent basis_keys: should be of cardinality {rank}, got {basis_keys}') from sage.combinat.free_module import CombinatorialFreeModule return CombinatorialFreeModule(base_ring, basis_keys, **args) @@ -763,7 +763,7 @@ def span(gens, base_ring=None, check=True, already_echelonized=False): raise TypeError("generators must be given as an iterable structure") if R not in PrincipalIdealDomains(): - raise TypeError("The base_ring (= %s) must be a principal ideal " "domain." % R) + raise TypeError("The base_ring (= %s) must be a principal ideal domain." % R) if not gens: return FreeModule(R, 0) x = gens[0] @@ -773,7 +773,7 @@ def span(gens, base_ring=None, check=True, already_echelonized=False): try: x = list(x) except TypeError: - raise TypeError("generators must be lists of ring elements or " "free module elements!") + raise TypeError("generators must be lists of ring elements or free module elements!") M = FreeModule(R, len(x)) try: gens = [M(_) for _ in gens] @@ -783,7 +783,7 @@ def span(gens, base_ring=None, check=True, already_echelonized=False): try: gens = [M(_) for _ in gens] except TypeError: - raise ValueError("The elements of gens (= %s) must be " "defined over base_ring (= %s) or its " "field of fractions." % (gens, base_ring)) + raise ValueError("The elements of gens (= %s) must be defined over base_ring (= %s) or its field of fractions." % (gens, base_ring)) return M.span(gens=gens, base_ring=base_ring, check=check, already_echelonized=already_echelonized) @@ -1638,7 +1638,7 @@ def is_submodule(self, other) -> bool: return False except NotImplementedError: if not R.fraction_field().is_subring(S): - raise NotImplementedError("could not determine if %s is a " "subring of %s" % (R, S)) + raise NotImplementedError("could not determine if %s is a subring of %s" % (R, S)) if not self.gens(): # self is the zero module return True @@ -1859,7 +1859,7 @@ def submodule(self, gens, check=True, already_echelonized=False): V = self.span(gens, check=check, already_echelonized=already_echelonized) if check: if not V.is_submodule(self): - raise ArithmeticError("argument gens (= %s) does not generate " "a submodule of self" % gens) + raise ArithmeticError("argument gens (= %s) does not generate a submodule of self" % gens) return V def quotient_module(self, sub, check=True): @@ -1945,7 +1945,7 @@ def free_resolution(self, *args, **kwds): return FiniteFreeResolution_free_module(self, *args, **kwds) - raise NotImplementedError("the module must be a free module or " "have the base ring be a polynomial ring using Singular") + raise NotImplementedError("the module must be a free module or have the base ring be a polynomial ring using Singular") def graded_free_resolution(self, *args, **kwds): r""" @@ -1986,7 +1986,7 @@ def graded_free_resolution(self, *args, **kwds): return GradedFiniteFreeResolution_free_module(self, *args, **kwds) - raise NotImplementedError("the module must be a free module or " "have the base ring be a polynomial ring using Singular") + raise NotImplementedError("the module must be a free module or have the base ring be a polynomial ring using Singular") class FreeModule_generic(Module_free_ambient): @@ -2071,7 +2071,7 @@ def __init__(self, base_ring, rank, degree, sparse=False, coordinate_ring=None, """ if base_ring not in CommutativeRings(): - warn("You are constructing a free module\n" "over a noncommutative ring. Sage does not have a concept\n" "of left/right and both sided modules, so be careful.\n" "It's also not guaranteed that all multiplications are\n" "done from the right side.") + warn("You are constructing a free module\nover a noncommutative ring. Sage does not have a concept\nof left/right and both sided modules, so be careful.\nIt's also not guaranteed that all multiplications are\ndone from the right side.") if coordinate_ring is None: coordinate_ring = base_ring @@ -2454,7 +2454,7 @@ def is_submodule(self, other) -> bool: return False except NotImplementedError: if not R.fraction_field().is_subring(S): - raise NotImplementedError("could not determine if %s is a " "subring of %s" % (R, S)) + raise NotImplementedError("could not determine if %s is a subring of %s" % (R, S)) # now R is a subring of S if other.is_ambient() and S.is_field(): return True @@ -6744,7 +6744,7 @@ def __init__(self, ambient, basis, check=True, echelonize=False, echelonized_bas try: basis = [V(x) for x in basis] except TypeError: - raise TypeError("each element of basis must be in " "the ambient vector space") + raise TypeError("each element of basis must be in the ambient vector space") basis = basis_seq(V, basis) diff --git a/src/sage/modules/free_module_integer.py b/src/sage/modules/free_module_integer.py index 8b967d39a91..07696737eea 100644 --- a/src/sage/modules/free_module_integer.py +++ b/src/sage/modules/free_module_integer.py @@ -874,7 +874,7 @@ def approximate_closest_vector(self, t, delta=None, algorithm='embedding', *args for v in reversed(L.LLL(delta=delta, *args, **kwargs).rows()): if abs(v[-1]) == weight: return t - v[:-1] * v[-1].sign() - raise ValueError('No suitable vector found in basis.' 'This is a bug, please report it.') + raise ValueError('No suitable vector found in basis.This is a bug, please report it.') elif algorithm == 'nearest_plane': G = B.gram_schmidt()[0] diff --git a/src/sage/modules/free_module_morphism.py b/src/sage/modules/free_module_morphism.py index c610dc1f521..015b3bd5b09 100644 --- a/src/sage/modules/free_module_morphism.py +++ b/src/sage/modules/free_module_morphism.py @@ -49,7 +49,6 @@ class FreeModuleMorphism(matrix_morphism.MatrixMorphism): - def __init__(self, parent, A, side='left'): """ INPUT: diff --git a/src/sage/modules/free_quadratic_module.py b/src/sage/modules/free_quadratic_module.py index b3d6d479908..8f2510a9020 100644 --- a/src/sage/modules/free_quadratic_module.py +++ b/src/sage/modules/free_quadratic_module.py @@ -1061,7 +1061,6 @@ def _repr_(self) -> str: class FreeQuadraticModule_ambient_field(free_module.FreeModule_ambient_field, FreeQuadraticModule_generic_field, FreeQuadraticModule_ambient_pid): - def __init__(self, base_field, dimension, inner_product_matrix, sparse=False) -> None: """ Create the ambient vector space of given dimension over the given field. diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index 4b7b7bf62e7..f5a2b8b733f 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -640,10 +640,10 @@ def __init__(self, ambient, basis, inner_product_matrix, check=True, already_ech """ FreeQuadraticModule_submodule_with_basis_pid.__init__(self, ambient, basis, inner_product_matrix, check=check, already_echelonized=already_echelonized) if self.determinant() == 0: - raise ValueError("lattices must be nondegenerate; " "use FreeQuadraticModule instead") + raise ValueError("lattices must be nondegenerate; use FreeQuadraticModule instead") if self.gram_matrix().base_ring() is not ZZ: if self.gram_matrix().denominator() != 1: - raise ValueError("lattices must be integral; " "use FreeQuadraticModule instead") + raise ValueError("lattices must be integral; use FreeQuadraticModule instead") def _mul_(self, other, switch_sides=False): r""" @@ -933,7 +933,7 @@ def orthogonal_complement(self, M): if not isinstance(M, FreeModule_generic): M = self.span(M) elif M.ambient_vector_space() != self.ambient_vector_space(): - raise ValueError("M must have the same " "ambient vector space as this lattice") + raise ValueError("M must have the same ambient vector space as this lattice") K = (self.inner_product_matrix() * M.basis_matrix().transpose()).kernel() K = self.span(K.basis()) @@ -969,7 +969,7 @@ def sublattice(self, basis): """ M = FreeQuadraticModule_integer_symmetric(ambient=self.ambient_module(), basis=basis, inner_product_matrix=self.inner_product_matrix(), already_echelonized=False) if not M.is_submodule(self): - raise ValueError("the basis (= %s) does not span " "a submodule" % basis) + raise ValueError("the basis (= %s) does not span a submodule" % basis) return M def overlattice(self, gens): @@ -1247,7 +1247,7 @@ def orthogonal_group(self, gens=None, is_finite=None): if gens is None: sig = self.signature_pair() if not (sig[1] == 0 or sig[0] == 0): # indefinite - raise NotImplementedError("currently, we can only compute generators " "for orthogonal groups over definite lattices.") + raise NotImplementedError("currently, we can only compute generators for orthogonal groups over definite lattices.") # definite from sage.quadratic_forms.quadratic_form import QuadraticForm diff --git a/src/sage/modules/matrix_morphism.py b/src/sage/modules/matrix_morphism.py index 912a8cabb96..b233c807275 100644 --- a/src/sage/modules/matrix_morphism.py +++ b/src/sage/modules/matrix_morphism.py @@ -58,7 +58,6 @@ class MatrixMorphism_abstract(sage.categories.morphism.Morphism): - # Copy in methods that delegate to self.matrix. # This is needed because MatrixMorphism_abstract is subclassed # for use with parents that are merely set up as additive abelian groups, diff --git a/src/sage/modules/multi_filtered_vector_space.py b/src/sage/modules/multi_filtered_vector_space.py index 6de1336f419..7ae6ef08bee 100644 --- a/src/sage/modules/multi_filtered_vector_space.py +++ b/src/sage/modules/multi_filtered_vector_space.py @@ -98,7 +98,6 @@ def MultiFilteredVectorSpace(arg, base_ring=None, check=True): class MultiFilteredVectorSpace_class(FreeModule_ambient_field): - def __init__(self, base_ring, dim, filtrations, check=True): """ Python constructor. @@ -527,7 +526,7 @@ def direct_sum(self, other): b: QQ^3 >= QQ^2 >= QQ^2 >= QQ^2 >= 0 """ if not self.index_set() == other.index_set(): - raise ValueError('the index sets of the two summands' ' must be the same') + raise ValueError('the index sets of the two summands must be the same') filtrations = {} for key in self.index_set(): filtrations[key] = self._filt[key] + other._filt[key] @@ -568,7 +567,7 @@ def tensor_product(self, other): b: QQ^2 >= QQ^2 >= QQ^1 >= QQ^1 >= QQ^1 >= 0 """ if not self.index_set() == other.index_set(): - raise ValueError('the index sets of the two summands' ' must be the same') + raise ValueError('the index sets of the two summands must be the same') filtrations = {} for key in self.index_set(): filtrations[key] = self._filt[key] * other._filt[key] diff --git a/src/sage/modules/submodule.py b/src/sage/modules/submodule.py index 1c911b5f8c0..426456c8242 100644 --- a/src/sage/modules/submodule.py +++ b/src/sage/modules/submodule.py @@ -213,7 +213,7 @@ def _groebner_basis_contains(self, v): ideal_gens = [] do_lift = False else: - raise NotImplementedError("Gröbner basis membership test is not implemented for " "modules over {}".format(R)) + raise NotImplementedError("Gröbner basis membership test is not implemented for modules over {}".format(R)) # Suppress "_ is no standard basis" warning from Singular opt_verb['not_warn_sb'] = True diff --git a/src/sage/modules/torsion_quadratic_module.py b/src/sage/modules/torsion_quadratic_module.py index ea824359497..5b3ac25ae55 100644 --- a/src/sage/modules/torsion_quadratic_module.py +++ b/src/sage/modules/torsion_quadratic_module.py @@ -437,7 +437,7 @@ def brown_invariant(self): ValueError: the torsion quadratic form must have values in QQ / 2 ZZ """ if self._modulus_qf != 2: - raise ValueError("the torsion quadratic form must have values in " "QQ / 2 ZZ") + raise ValueError("the torsion quadratic form must have values in QQ / 2 ZZ") from sage.quadratic_forms.genera.normal_form import collect_small_blocks brown = IntegerModRing(8).zero() @@ -767,9 +767,9 @@ def is_genus(self, signature_pair, even=True) -> bool: if rank < len(self.invariants()): return False if even and self._modulus_qf != 2: - raise ValueError("the discriminant form of an even lattice has" "values modulo 2.") + raise ValueError("the discriminant form of an even lattice hasvalues modulo 2.") if (not even) and not (self._modulus == self._modulus_qf == 1): - raise ValueError("the discriminant form of an odd lattice has" "values modulo 1.") + raise ValueError("the discriminant form of an odd lattice hasvalues modulo 1.") if not even: raise NotImplementedError("at the moment sage knows how to do this only for even genera. " + " Help us to implement this for odd genera.") for p in D.prime_divisors(): diff --git a/src/sage/modules/vector_space_homspace.py b/src/sage/modules/vector_space_homspace.py index 1e2f9df0176..600043101ec 100644 --- a/src/sage/modules/vector_space_homspace.py +++ b/src/sage/modules/vector_space_homspace.py @@ -203,7 +203,6 @@ class VectorSpaceHomspace(sage.modules.free_module_homspace.FreeModuleHomspace): - def __call__(self, A, check=True, **kwds): r""" INPUT: diff --git a/src/sage/modules/vector_space_morphism.py b/src/sage/modules/vector_space_morphism.py index 801132b6762..2508ba52d53 100644 --- a/src/sage/modules/vector_space_morphism.py +++ b/src/sage/modules/vector_space_morphism.py @@ -328,7 +328,6 @@ # http://www.gnu.org/licenses/ #################################################################################### - from sage.modules import free_module_morphism from sage.modules import matrix_morphism from sage.modules import vector_space_homspace @@ -782,7 +781,6 @@ def linear_transformation(arg0, arg1=None, arg2=None, side='left'): class VectorSpaceMorphism(free_module_morphism.FreeModuleMorphism): - def __init__(self, homspace, A, side='left'): r""" Create a linear transformation, a morphism between vector spaces. diff --git a/src/sage/modules/with_basis/morphism.py b/src/sage/modules/with_basis/morphism.py index 226b91ed522..daed04ebfe1 100644 --- a/src/sage/modules/with_basis/morphism.py +++ b/src/sage/modules/with_basis/morphism.py @@ -1417,7 +1417,7 @@ def __init__(self, domain, diagonal, codomain=None, category=None): if codomain is None: raise ValueError("The codomain should be specified") if not (domain.basis().keys() == codomain.basis().keys() and domain.base_ring() == codomain.base_ring()): - raise ValueError("The domain and codomain should have the same base ring " "and the same basis indexing") + raise ValueError("The domain and codomain should have the same base ring and the same basis indexing") from collections.abc import Callable if not isinstance(diagonal, Callable): diff --git a/src/sage/monoids/automatic_semigroup.py b/src/sage/monoids/automatic_semigroup.py index 43ebaea5ca9..95186b6e3b2 100644 --- a/src/sage/monoids/automatic_semigroup.py +++ b/src/sage/monoids/automatic_semigroup.py @@ -855,7 +855,6 @@ def construct(self, up_to=None, n=None): pass class Element(ElementWrapper): - def __init__(self, ambient_element, parent): """ TESTS:: @@ -1010,7 +1009,6 @@ def __copy__(self, memo=None): class AutomaticMonoid(AutomaticSemigroup): - def one(self): """ Return the unit of ``self``. diff --git a/src/sage/monoids/free_abelian_monoid.py b/src/sage/monoids/free_abelian_monoid.py index d240ebd18e2..d1be89da9fe 100644 --- a/src/sage/monoids/free_abelian_monoid.py +++ b/src/sage/monoids/free_abelian_monoid.py @@ -245,7 +245,7 @@ def gen(self, i=0): """ n = self.__ngens if i < 0 or not i < n: - raise IndexError(f"argument i (= {i}) must be between 0 and {n-1}") + raise IndexError(f"argument i (= {i}) must be between 0 and {n - 1}") x = [0 for j in range(n)] x[int(i)] = 1 return self.element_class(self, x) diff --git a/src/sage/monoids/hecke_monoid.py b/src/sage/monoids/hecke_monoid.py index bc25f9769a7..f6c7094ab60 100644 --- a/src/sage/monoids/hecke_monoid.py +++ b/src/sage/monoids/hecke_monoid.py @@ -2,6 +2,7 @@ """ Hecke Monoids """ + # **************************************************************************** # Copyright (C) 2015 Nicolas M. Thiéry # diff --git a/src/sage/monoids/string_monoid.py b/src/sage/monoids/string_monoid.py index b9823abdd04..d737ad90f8f 100644 --- a/src/sage/monoids/string_monoid.py +++ b/src/sage/monoids/string_monoid.py @@ -18,7 +18,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from .free_monoid import FreeMonoid from .string_monoid_element import StringMonoidElement from .string_ops import strip_encoding @@ -108,7 +107,7 @@ def gen(self, i=0): """ n = self.ngens() if i < 0 or not i < n: - raise IndexError(f"Argument i (= {i}) must be between 0 and {n-1}.") + raise IndexError(f"Argument i (= {i}) must be between 0 and {n - 1}.") return StringMonoidElement(self, [int(i)]) diff --git a/src/sage/monoids/trace_monoid.py b/src/sage/monoids/trace_monoid.py index 80eb8a0a85e..98166801bf5 100644 --- a/src/sage/monoids/trace_monoid.py +++ b/src/sage/monoids/trace_monoid.py @@ -274,7 +274,7 @@ def hasse_diagram(self, algorithm='naive'): return self.naive_hasse_diagram() if algorithm == "min": return self.min_hasse_diagram() - raise ValueError("`alg` option must be `naive` " f"or `min`, got `{algorithm}`.") + raise ValueError(f"`alg` option must be `naive` or `min`, got `{algorithm}`.") def min_hasse_diagram(self): r""" @@ -937,7 +937,7 @@ def _repr_(self) -> str: Trace monoid on 4 generators ([a], [b], [c], [d]) with independence relation {{a, d}, {b, c}} """ - return ("Trace monoid on {!s} generators {!s} " "with independence relation {{{}}}").format(self.ngens(), self.gens(), ", ".join(f"{{{x}, {y}}}" for (x, y) in self._sorted_independence())) + return ("Trace monoid on {!s} generators {!s} with independence relation {{{}}}").format(self.ngens(), self.gens(), ", ".join(f"{{{x}, {y}}}" for (x, y) in self._sorted_independence())) def _latex_(self) -> str: r""" diff --git a/src/sage/numerical/backends/cvxopt_backend_test.py b/src/sage/numerical/backends/cvxopt_backend_test.py index 99ac999c9bd..084299b05f4 100644 --- a/src/sage/numerical/backends/cvxopt_backend_test.py +++ b/src/sage/numerical/backends/cvxopt_backend_test.py @@ -7,7 +7,6 @@ class TestCVXOPTBackend(GenericBackendTests): - @pytest.fixture def backend(self) -> GenericBackend: return MixedIntegerLinearProgram(solver="CVXOPT").get_backend() diff --git a/src/sage/numerical/backends/cvxpy_backend_test.py b/src/sage/numerical/backends/cvxpy_backend_test.py index d186a1054ce..281ce35e299 100644 --- a/src/sage/numerical/backends/cvxpy_backend_test.py +++ b/src/sage/numerical/backends/cvxpy_backend_test.py @@ -6,7 +6,6 @@ @pytest.importorskip("cvxpy") class TestCVXPYBackend(GenericBackendTests): - @pytest.fixture def backend(self) -> GenericBackend: return MixedIntegerLinearProgram(solver="CVXPY").get_backend() diff --git a/src/sage/numerical/backends/generic_backend_test.py b/src/sage/numerical/backends/generic_backend_test.py index d1abadfcc45..3e686788dae 100644 --- a/src/sage/numerical/backends/generic_backend_test.py +++ b/src/sage/numerical/backends/generic_backend_test.py @@ -5,7 +5,6 @@ class GenericBackendTests(SageObjectTests): - @pytest.fixture def backend(self, *args, **kwargs) -> GenericBackend: raise NotImplementedError diff --git a/src/sage/numerical/backends/glpk_backend_test.py b/src/sage/numerical/backends/glpk_backend_test.py index 5204b66e73d..3a1937f4b2c 100644 --- a/src/sage/numerical/backends/glpk_backend_test.py +++ b/src/sage/numerical/backends/glpk_backend_test.py @@ -6,7 +6,6 @@ class TestGLPKBackend(GenericBackendTests): - @pytest.fixture def backend(self) -> GenericBackend: return MixedIntegerLinearProgram(solver='GLPK').get_backend() diff --git a/src/sage/numerical/backends/glpk_exact_backend_test.py b/src/sage/numerical/backends/glpk_exact_backend_test.py index 67b169baa82..0c005d8d91a 100644 --- a/src/sage/numerical/backends/glpk_exact_backend_test.py +++ b/src/sage/numerical/backends/glpk_exact_backend_test.py @@ -5,7 +5,6 @@ class TestGLPKExactBackend(GenericBackendTests): - @pytest.fixture def backend(self) -> GenericBackend: return MixedIntegerLinearProgram(solver='GLPK/exact').get_backend() diff --git a/src/sage/numerical/backends/interactivelp_backend_test.py b/src/sage/numerical/backends/interactivelp_backend_test.py index d0e4b091563..4373df0923b 100644 --- a/src/sage/numerical/backends/interactivelp_backend_test.py +++ b/src/sage/numerical/backends/interactivelp_backend_test.py @@ -5,7 +5,6 @@ class TestInteractiveLPBackend(GenericBackendTests): - @pytest.fixture def backend(self) -> GenericBackend: return MixedIntegerLinearProgram(solver='InteractiveLP').get_backend() diff --git a/src/sage/numerical/backends/logging_backend.py b/src/sage/numerical/backends/logging_backend.py index 97a19a9e7fb..f0f7401ae32 100644 --- a/src/sage/numerical/backends/logging_backend.py +++ b/src/sage/numerical/backends/logging_backend.py @@ -17,7 +17,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.numerical.backends.generic_backend import GenericBackend @@ -67,7 +66,7 @@ def m(self, *args, **kwdargs): if self._printing: print("# exception: {}".format(e)) if self._doctest: - self._doctest.write(" Traceback (most recent call last):\n" " ...\n" " MIPSolverException: {}\n".format(e)) + self._doctest.write(" Traceback (most recent call last):\n ...\n MIPSolverException: {}\n".format(e)) if self._test_method: self._test_method.write((" with tester.assertRaises({}) as cm:\n" + " {}\n").format(type(e).__name__, funcall)) raise @@ -228,9 +227,7 @@ def _test_{name}(cls, tester=None, **options): p = cls() # fresh instance of the backend if tester is None: tester = p._tester(**options) -'''.replace( - "SAGE:", "sage:" -) # so that the above test does not get picked up by the doctester +'''.replace("SAGE:", "sage:") # so that the above test does not get picked up by the doctester from sage.rings.rational_field import QQ diff --git a/src/sage/numerical/backends/ppl_backend_test.py b/src/sage/numerical/backends/ppl_backend_test.py index 13ef46e1a3d..a064cdb0945 100644 --- a/src/sage/numerical/backends/ppl_backend_test.py +++ b/src/sage/numerical/backends/ppl_backend_test.py @@ -6,7 +6,6 @@ class TestPPLBackend(GenericBackendTests): - @pytest.fixture def backend(self) -> GenericBackend: return MixedIntegerLinearProgram(solver='PPL').get_backend() diff --git a/src/sage/numerical/backends/scip_backend_test.py b/src/sage/numerical/backends/scip_backend_test.py index f10f6edee46..0d703532742 100644 --- a/src/sage/numerical/backends/scip_backend_test.py +++ b/src/sage/numerical/backends/scip_backend_test.py @@ -6,7 +6,6 @@ @pytest.importorskip("pyscipopt") class TestSCIPBackend(GenericBackendTests): - @pytest.fixture def backend(self) -> GenericBackend: return MixedIntegerLinearProgram(solver="SCIP").get_backend() diff --git a/src/sage/numerical/interactive_simplex_method.py b/src/sage/numerical/interactive_simplex_method.py index a364f5881af..4c39b5435ba 100644 --- a/src/sage/numerical/interactive_simplex_method.py +++ b/src/sage/numerical/interactive_simplex_method.py @@ -1885,7 +1885,7 @@ def __init__(self, A, b, c, x='x', problem_type='max', slack_variables=None, aux sage: TestSuite(P).run() """ if problem_type not in ("max", "-max"): - raise ValueError("problems in standard form must be of (negative) " "maximization type") + raise ValueError("problems in standard form must be of (negative) maximization type") super().__init__(A, b, c, x, problem_type=problem_type, constraint_type='<=', variable_type='>=', base_ring=base_ring, is_primal=is_primal, objective_constant_term=objective_constant_term) n, m = self.n(), self.m() if slack_variables is None: @@ -2054,7 +2054,7 @@ def auxiliary_problem(self, objective_name=None): X = self.coordinate_ring().gens() m, n = self.m(), self.n() if len(X) == m + n: - raise ValueError("auxiliary variable is already among decision " "ones") + raise ValueError("auxiliary variable is already among decision ones") F = self.base_ring() A = column_matrix(F, [-1] * m).augment(self.A()) c = vector(F, [-1] + [0] * n) @@ -2471,7 +2471,7 @@ def run_revised_simplex_method(self): v = d.objective_value() if self._is_negative: v = -v - output.append(("The optimal value: ${}$. " "An optimal solution: ${}$.").format(latex(v), latex(d.basic_solution()))) + output.append(("The optimal value: ${}$. An optimal solution: ${}$.").format(latex(v), latex(d.basic_solution()))) self._final_revised_dictionary = d return HtmlFragment("\n".join(output)) @@ -2526,7 +2526,7 @@ def run_simplex_method(self): d = self.initial_dictionary() if not d.is_feasible(): output.append(d._html_()) - output.append("The initial dictionary is infeasible, " "solving auxiliary problem.") + output.append("The initial dictionary is infeasible, solving auxiliary problem.") # Phase I ad = self.auxiliary_problem().initial_dictionary() ad.enter(self.auxiliary_variable()) @@ -2545,7 +2545,7 @@ def run_simplex_method(self): v = d.objective_value() if self._is_negative: v = -v - output.append(("The optimal value: ${}$. " "An optimal solution: ${}$.").format(latex(v), latex(d.basic_solution()))) + output.append(("The optimal value: ${}$. An optimal solution: ${}$.").format(latex(v), latex(d.basic_solution()))) self._final_dictionary = d return HtmlFragment("\n".join(output)) @@ -2979,7 +2979,7 @@ def entering_coefficients(self): (1, 3) """ if self._entering is None: - raise ValueError("entering variable must be chosen to compute " "its coefficients") + raise ValueError("entering variable must be chosen to compute its coefficients") return self.column_coefficients(self._entering) def is_dual_feasible(self) -> bool: @@ -3151,7 +3151,7 @@ def leaving_coefficients(self): (-2, -1) """ if self._leaving is None: - raise ValueError("leaving variable must be chosen to compute " "its coefficients") + raise ValueError("leaving variable must be chosen to compute its coefficients") return self.row_coefficients(self._leaving) @abstract_method @@ -3253,7 +3253,7 @@ def possible_dual_simplex_method_steps(self): [(x3, [x1])] """ if not self.is_dual_feasible(): - raise ValueError("dual simplex method steps are applicable to " "dual feasible dictionaries only") + raise ValueError("dual simplex method steps are applicable to dual feasible dictionaries only") steps = [] old_entering = self._entering self._entering = None @@ -3295,7 +3295,7 @@ def possible_entering(self): return [v for r, v in ratios if r == min_ratio] if self.is_feasible(): return [v for c, v in zip(self.objective_coefficients(), self.nonbasic_variables()) if c > 0] - raise ValueError("entering variables can be determined for feasible " "dictionaries or for dual feasible dictionaries " "with a set leaving variable") + raise ValueError("entering variables can be determined for feasible dictionaries or for dual feasible dictionaries with a set leaving variable") def possible_leaving(self): r""" @@ -3329,7 +3329,7 @@ def possible_leaving(self): return [v for r, v in ratios if r == min_ratio] if self.is_dual_feasible(): return [v for b, v in zip(self.constant_terms(), self.basic_variables()) if b < 0] - raise ValueError("leaving variables can be determined for feasible " "dictionaries with a set entering variable " "or for dual feasible dictionaries") + raise ValueError("leaving variables can be determined for feasible dictionaries with a set entering variable or for dual feasible dictionaries") def possible_simplex_method_steps(self): r""" @@ -3357,7 +3357,7 @@ def possible_simplex_method_steps(self): [(x1, [x4]), (x2, [x3])] """ if not self.is_feasible(): - raise ValueError("simplex method steps are applicable to feasible " "dictionaries only") + raise ValueError("simplex method steps are applicable to feasible dictionaries only") steps = [] old_entering = self._entering old_leaving = self._leaving @@ -3510,7 +3510,7 @@ def run_dual_simplex_method(self): self.enter(min(possible)) output.append(self._html_()) if self.entering() is None: - output.append("The problem is infeasible because of " "${}$ constraint.".format(latex(self.leaving()))) + output.append("The problem is infeasible because of ${}$ constraint.".format(latex(self.leaving()))) break output.append(self._preupdate_output("dual")) self.update() @@ -4146,7 +4146,7 @@ def update(self): e = tuple(N).index(entering) Ale = A[l, e] if Ale == 0: - raise ValueError("incompatible choice of entering and leaving " "variables") + raise ValueError("incompatible choice of entering and leaving variables") # Variables B[l] = entering N[e] = leaving @@ -4305,7 +4305,7 @@ def __init__(self, problem, basic_variables): sage: TestSuite(D).run() """ if problem.auxiliary_variable() == problem.decision_variables()[0]: - raise ValueError("revised dictionaries should not be constructed " "for auxiliary problems") + raise ValueError("revised dictionaries should not be constructed for auxiliary problems") super().__init__() self._problem = problem R = problem.coordinate_ring() @@ -4626,10 +4626,10 @@ def E(self): [0 3] """ if self._entering is None: - raise ValueError("entering variable must be set to compute the " "eta matrix") + raise ValueError("entering variable must be set to compute the eta matrix") leaving = self._leaving if leaving is None: - raise ValueError("leaving variable must be set to compute the " "eta matrix") + raise ValueError("leaving variable must be set to compute the eta matrix") l = self._x_B.list().index(leaving) E = identity_matrix(self.base_ring(), self.problem().m()) E.set_column(l, self.entering_coefficients()) @@ -4661,7 +4661,7 @@ def E_inverse(self): l = self._x_B.list().index(self._leaving) d = E[l, l] if d == 0: - raise ValueError("eta matrix is not invertible due to incompatible " "choice of entering and leaving variables") + raise ValueError("eta matrix is not invertible due to incompatible choice of entering and leaving variables") E.set_col_to_multiple_of_col(l, l, -1 / d) E[l, l] = 1 / d return E @@ -4743,7 +4743,7 @@ def add_row(self, nonbasic_coefficients, constant, basic_variable=None): else: nbc_decision[i - 1] = coef if 0 in self.basic_indices() and not sum(nbc_slack) == -1: - raise ValueError("the sum of coefficients of nonbasic slack variables has to " "be equal to -1 when inserting a row into a dictionary for " "the auxiliary problem") + raise ValueError("the sum of coefficients of nonbasic slack variables has to be equal to -1 when inserting a row into a dictionary for the auxiliary problem") P_new = P.add_constraint(nbc_decision - nbc_slack * P.A(), constant - nbc_slack * P.b(), basic_variable) x_B = list(self.x_B()) + [P_new.slack_variables()[-1]] return P_new.revised_dictionary(*x_B) diff --git a/src/sage/numerical/linear_tensor.py b/src/sage/numerical/linear_tensor.py index e1b9186b871..b9d8ecdf177 100644 --- a/src/sage/numerical/linear_tensor.py +++ b/src/sage/numerical/linear_tensor.py @@ -94,7 +94,6 @@ # https://www.gnu.org/licenses/ # *************************************************************************** - from copy import copy from sage.structure.parent import Parent diff --git a/src/sage/parallel/map_reduce.py b/src/sage/parallel/map_reduce.py index 0d3f4eff583..e7e7cb0f989 100644 --- a/src/sage/parallel/map_reduce.py +++ b/src/sage/parallel/map_reduce.py @@ -1171,7 +1171,7 @@ def get_results(self, timeout=None): active_proc = self._nprocess while active_proc > 0: try: - logger.debug('Waiting on results; active_proc: {}, ' 'timeout: {}, aborted: {}'.format(active_proc, timeout, self._aborted.value)) + logger.debug('Waiting on results; active_proc: {}, timeout: {}, aborted: {}'.format(active_proc, timeout, self._aborted.value)) newres = self._results.get(timeout=timeout) except queue.Empty: logger.debug('Timed out waiting for results; aborting') diff --git a/src/sage/parallel/use_fork.py b/src/sage/parallel/use_fork.py index 94789fcafe7..7de5dacbb5f 100644 --- a/src/sage/parallel/use_fork.py +++ b/src/sage/parallel/use_fork.py @@ -12,7 +12,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - import sys import traceback from shutil import rmtree diff --git a/src/sage/plot/animate.py b/src/sage/plot/animate.py index 5f80caf8316..14298c7f28b 100644 --- a/src/sage/plot/animate.py +++ b/src/sage/plot/animate.py @@ -622,7 +622,7 @@ def gif(self, delay=20, savefile=None, iterations=0, show_path=False, use_ffmpeg from sage.features.ffmpeg import FFmpeg if not ImageMagick().is_present() and not FFmpeg().is_present(): - raise OSError("Error: Neither ImageMagick nor ffmpeg appear to " "be installed. Saving an animation to a GIF file or " "displaying an animation requires one of these " "packages, so please install one of them and try " "again. See www.imagemagick.org and www.ffmpeg.org " "for more information.") + raise OSError("Error: Neither ImageMagick nor ffmpeg appear to be installed. Saving an animation to a GIF file or displaying an animation requires one of these packages, so please install one of them and try again. See www.imagemagick.org and www.ffmpeg.org for more information.") if use_ffmpeg or not ImageMagick().is_present(): self.ffmpeg(savefile=savefile, show_path=show_path, output_format='.gif', delay=delay, iterations=iterations) @@ -698,8 +698,8 @@ def _gif_from_imagemagick(self, savefile=None, show_path=False, delay=20, iterat # If a problem with the command occurs, print the log before # raising an error (more verbose than result.check_returncode()) if result.returncode: - print('Command "{}" returned nonzero exit status "{}" ' '(with stderr "{}" and stdout "{}").'.format(result.args, result.returncode, result.stderr.strip(), result.stdout.strip())) - raise OSError("Error: Cannot generate GIF animation. " "The magick/convert command (ImageMagick) is present but does " "not seem to be functional. Verify that the objects " "passed to the animate command can be saved in PNG " "image format. " "See www.imagemagick.org more information.") + print('Command "{}" returned nonzero exit status "{}" (with stderr "{}" and stdout "{}").'.format(result.args, result.returncode, result.stderr.strip(), result.stdout.strip())) + raise OSError("Error: Cannot generate GIF animation. The magick/convert command (ImageMagick) is present but does not seem to be functional. Verify that the objects passed to the animate command can be saved in PNG image format. See www.imagemagick.org more information.") if show_path: print("Animation saved to file %s." % savefile) diff --git a/src/sage/plot/arc.py b/src/sage/plot/arc.py index 9bc7e8e2e02..cffb710c283 100644 --- a/src/sage/plot/arc.py +++ b/src/sage/plot/arc.py @@ -256,7 +256,7 @@ def _allowed_options(self): 'hue': 'The color given as a hue.', 'rgbcolor': 'The color', 'zorder': '2D only: The layer level in which to draw', - 'linestyle': "2D only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively.", + 'linestyle': "2D only: The style of the line, which is one of 'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', respectively.", } def _matplotlib_arc(self): diff --git a/src/sage/plot/arrow.py b/src/sage/plot/arrow.py index 5dfb8afbc29..ac545565425 100644 --- a/src/sage/plot/arrow.py +++ b/src/sage/plot/arrow.py @@ -103,7 +103,7 @@ def _allowed_options(self): 'thickness': 'The thickness of the arrow.', 'zorder': '2-d only: The layer level in which to draw', 'head': '2-d only: Which end of the path to draw the head (one of 0 (start), 1 (end) or 2 (both)', - 'linestyle': "2d only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively.", + 'linestyle': "2d only: The style of the line, which is one of 'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', respectively.", } def _repr_(self): @@ -243,7 +243,7 @@ def _allowed_options(self): 'legend_color': 'The color of the legend text.', 'zorder': '2-d only: The layer level in which to draw', 'head': '2-d only: Which end of the path to draw the head (one of 0 (start), 1 (end) or 2 (both)', - 'linestyle': "2d only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively.", + 'linestyle': "2d only: The style of the line, which is one of 'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', respectively.", } def _plot3d_options(self, options=None): @@ -420,7 +420,6 @@ def __call__(self, renderer, gc, tpath, affine, rgbFace): return np.array_equal(vert1, tpath.vertices) and np.array_equal(code1, tpath.codes) class ConditionalStroke(pe.RendererBase): - def __init__(self, condition_func, pe_list): """ Path effect that is only applied when the ``condition_func`` diff --git a/src/sage/plot/bezier_path.py b/src/sage/plot/bezier_path.py index d6acf760a8f..d8b4a6ae1d0 100644 --- a/src/sage/plot/bezier_path.py +++ b/src/sage/plot/bezier_path.py @@ -120,7 +120,7 @@ def _allowed_options(self): 'thickness': 'How thick the border of the polygon is.', 'rgbcolor': 'The color as an RGB tuple.', 'zorder': 'The layer level in which to draw', - 'linestyle': "The style of the line, which is one of 'dashed'," " 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.'," " respectively.", + 'linestyle': "The style of the line, which is one of 'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', respectively.", } def _plot3d_options(self, options=None): diff --git a/src/sage/plot/circle.py b/src/sage/plot/circle.py index 6f15e24b5e9..ac6adac8be2 100644 --- a/src/sage/plot/circle.py +++ b/src/sage/plot/circle.py @@ -120,7 +120,7 @@ def _allowed_options(self): 'rgbcolor': 'The color (edge and face) as an RGB tuple.', 'hue': 'The color given as a hue.', 'zorder': '2D only: The layer level in which to draw', - 'linestyle': "2D only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively.", + 'linestyle': "2D only: The style of the line, which is one of 'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', respectively.", 'clip': 'Whether or not to clip the circle.', } @@ -430,4 +430,4 @@ def circle(center, radius, **options): return g if len(center) == 3: return g[0].plot3d(z=center[2]) - raise ValueError('the center of a plotted circle should have ' 'two or three coordinates') + raise ValueError('the center of a plotted circle should have two or three coordinates') diff --git a/src/sage/plot/contour_plot.py b/src/sage/plot/contour_plot.py index 438b6275849..105749336a8 100644 --- a/src/sage/plot/contour_plot.py +++ b/src/sage/plot/contour_plot.py @@ -2,6 +2,7 @@ """ Contour plots """ + # **************************************************************************** # Copyright (C) 2006 Alex Clemesha , # William Stein , @@ -970,10 +971,9 @@ def f(x, y): return cos(x) + sin(y) # z0, and (b) if perturbing the data will actually help by # moving anything across z0. if np.all(xy_data_array >= z0) and np.any(xy_data_array - z0 < tol): - from warnings import warn - warn("pathological contour plot of a function whose " "values all lie on one side of the sole contour; " "we are adding more plot points and perturbing " "your function values.") + warn("pathological contour plot of a function whose values all lie on one side of the sole contour; we are adding more plot points and perturbing your function values.") # The choice of "4" here is not based on much of anything. # It works well enough for the examples in the doctests. @@ -1330,7 +1330,7 @@ def f(x, y): if isinstance(f, Expression) and f.is_relational(): if f.operator() != operator.eq: - raise ValueError("input to implicit plot must be function " "or equation") + raise ValueError("input to implicit plot must be function or equation") f = f.lhs() - f.rhs() linewidths = options.pop('linewidth', None) linestyles = options.pop('linestyle', None) @@ -1638,7 +1638,7 @@ def region_plot(f, xrange, yrange, **options): f = [equify(g) for g in f if not (isinstance(g, Expression) and g.operator() is operator.eq)] neqs = len(feqs) if neqs > 1: - warn("There are at least 2 equations; " "If the region is degenerated to points, " "plotting might show nothing.") + warn("There are at least 2 equations; If the region is degenerated to points, plotting might show nothing.") feqs = [sum([fn**2 for fn in feqs])] neqs = 1 if neqs and not bordercol: diff --git a/src/sage/plot/disk.py b/src/sage/plot/disk.py index 0463fa15d31..7d248d851e4 100644 --- a/src/sage/plot/disk.py +++ b/src/sage/plot/disk.py @@ -372,4 +372,4 @@ def disk(point, radius, angle, **options): return g if len(point) == 3: return g[0].plot3d(z=point[2]) - raise ValueError('the center point of a plotted disk should have ' 'two or three coordinates') + raise ValueError('the center point of a plotted disk should have two or three coordinates') diff --git a/src/sage/plot/ellipse.py b/src/sage/plot/ellipse.py index f33108e8a8f..566170263b2 100644 --- a/src/sage/plot/ellipse.py +++ b/src/sage/plot/ellipse.py @@ -153,7 +153,7 @@ def _allowed_options(self): 'rgbcolor': 'The color (edge and face) as an RGB tuple.', 'hue': 'The color given as a hue.', 'zorder': '2D only: The layer level in which to draw', - 'linestyle': "2D only: The style of the line, which is one of " "'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', " "respectively.", + 'linestyle': "2D only: The style of the line, which is one of 'dashed', 'dotted', 'solid', 'dashdot', or '--', ':', '-', '-.', respectively.", } def _repr_(self): diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index 5a72860914e..4ab30a3d686 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -82,10 +82,10 @@ def _parse_figsize(figsize): if isinstance(figsize, (list, tuple)): # figsize should be a pair of positive numbers if len(figsize) != 2: - raise ValueError("figsize should be a positive number or a list " f"of two positive numbers, not {figsize}") + raise ValueError(f"figsize should be a positive number or a list of two positive numbers, not {figsize}") figsize = (float(figsize[0]), float(figsize[1])) # floats for mpl if not (figsize[0] > 0 and figsize[1] > 0): - raise ValueError("figsize should be positive numbers, " f"not {figsize[0]} and {figsize[1]}") + raise ValueError(f"figsize should be positive numbers, not {figsize[0]} and {figsize[1]}") else: # in this case, figsize is a single number representing the width and # should be positive @@ -1365,7 +1365,7 @@ def _set_scale(self, subplot, scale=None, base=None): return ('linear', 'linear', 10, 10) if isinstance(scale, (list, tuple)): if len(scale) != 2 and len(scale) != 3: - raise ValueError("If the input is a tuple, it must be of " "the form (scale, base) or (scale, basex, basey)") + raise ValueError("If the input is a tuple, it must be of the form (scale, base) or (scale, basex, basey)") if len(scale) == 2: base = scale[1] else: @@ -1373,7 +1373,7 @@ def _set_scale(self, subplot, scale=None, base=None): scale = scale[0] if scale not in ('linear', 'loglog', 'semilogx', 'semilogy'): - raise ValueError("The scale must be one of 'linear', 'loglog'," f" 'semilogx' or 'semilogy' -- got '{scale}'") + raise ValueError(f"The scale must be one of 'linear', 'loglog', 'semilogx' or 'semilogy' -- got '{scale}'") if isinstance(base, (list, tuple)): basex, basey = base @@ -1383,7 +1383,7 @@ def _set_scale(self, subplot, scale=None, base=None): basex = basey = base if basex <= 1 or basey <= 1: - raise ValueError("The base of the logarithm must be greater " "than 1") + raise ValueError("The base of the logarithm must be greater than 1") xscale = yscale = 'linear' if scale == 'linear': @@ -2409,7 +2409,7 @@ def _matplotlib_tick_formatter(self, subplot, base=(10, 10), locator_options={}, if floor(xmax / x_locator) - ceil(xmin / x_locator) > 1: x_locator = MultipleLocator(float(x_locator)) else: # not enough room for two major ticks - raise ValueError('Expand the range of the independent ' 'variable to allow two multiples of your tick locator ' '(option `ticks`).') + raise ValueError('Expand the range of the independent variable to allow two multiples of your tick locator (option `ticks`).') # ---------------------- Location of y-ticks --------------------- if y_locator is None: @@ -2429,7 +2429,7 @@ def _matplotlib_tick_formatter(self, subplot, base=(10, 10), locator_options={}, if floor(ymax / y_locator) - ceil(ymin / y_locator) > 1: y_locator = MultipleLocator(float(y_locator)) else: # not enough room for two major ticks - raise ValueError('Expand the range of the dependent ' 'variable to allow two multiples of your tick locator ' '(option `ticks`).') + raise ValueError('Expand the range of the dependent variable to allow two multiples of your tick locator (option `ticks`).') x_formatter, y_formatter = tick_formatter from matplotlib.ticker import FuncFormatter, FixedFormatter @@ -2458,7 +2458,7 @@ def _matplotlib_tick_formatter(self, subplot, base=(10, 10), locator_options={}, x_formatter = FuncFormatter(lambda n, pos: '$%s$' % latex(n)) elif isinstance(x_formatter, (list, tuple)): if not isinstance(ticks[0], (list, tuple)) or len(ticks[0]) != len(x_formatter): - raise ValueError("If the first component of the list " "`tick_formatter` is a list then the first component " "of `ticks` must also be a list of equal length.") + raise ValueError("If the first component of the list `tick_formatter` is a list then the first component of `ticks` must also be a list of equal length.") x_formatter = FixedFormatter(x_formatter) # ---------------------- Formatting y-ticks ---------------------- if y_formatter is None: @@ -2481,7 +2481,7 @@ def _matplotlib_tick_formatter(self, subplot, base=(10, 10), locator_options={}, y_formatter = FuncFormatter(lambda n, pos: '$%s$' % latex(n)) elif isinstance(y_formatter, (list, tuple)): if not isinstance(ticks[1], (list, tuple)) or len(ticks[1]) != len(y_formatter): - raise ValueError("If the second component of the list " "`tick_formatter` is a list then the second component " "of `ticks` must also be a list of equal length.") + raise ValueError("If the second component of the list `tick_formatter` is a list then the second component of `ticks` must also be a list of equal length.") y_formatter = FixedFormatter(y_formatter) subplot.xaxis.set_major_locator(x_locator) @@ -2796,7 +2796,7 @@ def matplotlib( rcParams['pdf.use14corefonts'] = False rcParams['text.usetex'] = True elif typeset != 'default': # We won't change (maybe user-set) defaults - raise ValueError("typeset must be set to one of 'default', 'latex'," f" or 'type1'; got '{typeset}'.") + raise ValueError(f"typeset must be set to one of 'default', 'latex', or 'type1'; got '{typeset}'.") self.fontsize(fontsize) self.axes_labels(l=axes_labels) @@ -3183,7 +3183,7 @@ def matplotlib( if title is not None: if title_pos is not None: if not isinstance(title_pos, (list, tuple)) or len(title_pos) != 2: - raise ValueError("'title_pos' must be a list or tuple " "of two real numbers.") + raise ValueError("'title_pos' must be a list or tuple of two real numbers.") title_pos = (float(title_pos[0]), float(title_pos[1])) if (frame) or (axes_labels is None): @@ -3352,7 +3352,7 @@ def save(self, filename, **kwds): if lualatex().is_present(): latex_implementations.append('lualatex') if not latex_implementations: - raise ValueError("Matplotlib requires either xelatex, " "lualatex, or pdflatex.") + raise ValueError("Matplotlib requires either xelatex, lualatex, or pdflatex.") if latex_implementations[0] == "pdflatex": # use pdflatex and set font encoding as per # matplotlib documentation: diff --git a/src/sage/plot/hyperbolic_regular_polygon.py b/src/sage/plot/hyperbolic_regular_polygon.py index 6ae1e71925a..408b8b89e9d 100644 --- a/src/sage/plot/hyperbolic_regular_polygon.py +++ b/src/sage/plot/hyperbolic_regular_polygon.py @@ -119,7 +119,7 @@ def __init__(self, sides, i_angle, center, options): if i_angle <= 0 or i_angle >= pi: raise ValueError("interior angle %s must be in (0, pi) interval" % (i_angle)) if pi * (sides - 2) - sides * i_angle <= 0: - raise ValueError("there exists no hyperbolic regular compact polygon," " for sides={} the interior angle must be less than {}".format(sides, pi * (sides - 2) / sides)) + raise ValueError("there exists no hyperbolic regular compact polygon, for sides={} the interior angle must be less than {}".format(sides, pi * (sides - 2) / sides)) self.sides = sides self.i_angle = i_angle beta = 2 * pi / self.sides # compute the rotation angle to be used ahead diff --git a/src/sage/plot/misc.py b/src/sage/plot/misc.py index 28c5c235310..990173aa366 100644 --- a/src/sage/plot/misc.py +++ b/src/sage/plot/misc.py @@ -419,7 +419,7 @@ def get_matplotlib_linestyle(linestyle, return_type): return '' if linestyle in long_to_short_dict.keys(): return long_to_short_dict[linestyle] - raise ValueError("WARNING: Unrecognized linestyle '%s'. " "Possible linestyle options are:\n{'solid', " "'dashed', 'dotted', dashdot', 'None'}, " "respectively {'-', '--', ':', '-.', ''}" % (linestyle)) + raise ValueError("WARNING: Unrecognized linestyle '%s'. Possible linestyle options are:\n{'solid', 'dashed', 'dotted', dashdot', 'None'}, respectively {'-', '--', ':', '-.', ''}" % (linestyle)) elif return_type == 'long': if linestyle in long_to_short_dict.keys(): @@ -428,7 +428,7 @@ def get_matplotlib_linestyle(linestyle, return_type): return "None" if linestyle in short_to_long_dict.keys(): return short_to_long_dict[linestyle] - raise ValueError("WARNING: Unrecognized linestyle '%s'. " "Possible linestyle options are:\n{'solid', " "'dashed', 'dotted', dashdot', 'None'}, " "respectively {'-', '--', ':', '-.', ''}" % (linestyle)) + raise ValueError("WARNING: Unrecognized linestyle '%s'. Possible linestyle options are:\n{'solid', 'dashed', 'dotted', dashdot', 'None'}, respectively {'-', '--', ':', '-.', ''}" % (linestyle)) class FastCallablePlotWrapper(FastCallableFloatWrapper): diff --git a/src/sage/plot/multigraphics.py b/src/sage/plot/multigraphics.py index c2d49e0b19a..f3b0fbd7287 100644 --- a/src/sage/plot/multigraphics.py +++ b/src/sage/plot/multigraphics.py @@ -14,6 +14,7 @@ - Eric Gourgoulhon (2019-05-24): initial version, refactoring the class ``GraphicsArray`` that was defined in the module :mod:`~sage.plot.graphics`. """ + import os from sage.misc.fast_methods import WithEqualityById from sage.structure.sage_object import SageObject @@ -148,7 +149,7 @@ def __init__(self, graphics_list): self.append(ins) # default position else: if not isinstance(ins, (list, tuple)) or len(ins) != 2: - raise TypeError("a pair (Graphics, position) is " f"expected, not {ins}") + raise TypeError(f"a pair (Graphics, position) is expected, not {ins}") self.append(ins[0], pos=ins[1]) def _repr_(self): @@ -449,7 +450,7 @@ def save(self, filename, figsize=None, **kwds): if lualatex().is_present(): latex_implementations.append('lualatex') if not latex_implementations: - raise ValueError("Matplotlib requires either xelatex, " "lualatex, or pdflatex.") + raise ValueError("Matplotlib requires either xelatex, lualatex, or pdflatex.") if latex_implementations[0] == "pdflatex": # use pdflatex and set font encoding as per # Matplotlib documentation: @@ -881,7 +882,7 @@ def append(self, graphics, pos=None): from matplotlib import rcParams if not isinstance(graphics, Graphics): - raise TypeError("a Graphics object is expected, " f"not {graphics}") + raise TypeError(f"a Graphics object is expected, not {graphics}") if pos is None: # Default position: left = rcParams['figure.subplot.left'] @@ -1111,7 +1112,7 @@ def __init__(self, array): """ MultiGraphics.__init__(self, []) if not isinstance(array, (list, tuple)): - raise TypeError("array must be a list of lists of Graphics " f"objects, not {array}") + raise TypeError(f"array must be a list of lists of Graphics objects, not {array}") array = list(array) self._rows = len(array) if self._rows > 0: @@ -1123,10 +1124,10 @@ def __init__(self, array): self._cols = 0 for row in array: # basically flatten the list if not isinstance(row, (list, tuple)) or len(row) != self._cols: - raise TypeError("array must be a list of equal-size lists of " f"Graphics objects, not {array}") + raise TypeError(f"array must be a list of equal-size lists of Graphics objects, not {array}") for g in row: if not isinstance(g, Graphics): - raise TypeError("every element of array must be a " "Graphics object") + raise TypeError("every element of array must be a Graphics object") self._glist.append(g) # self._positions is not initialized since most of the time, it is not # not used. It is required only by the method inset(); it is then @@ -1235,7 +1236,7 @@ def append(self, g): implemented """ # Not clear if there is a way to do this - raise NotImplementedError('Appending to a graphics array is not ' 'yet implemented') + raise NotImplementedError('Appending to a graphics array is not yet implemented') def position(self, index): r""" diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index bdd6eb83796..86bab83ca68 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -704,7 +704,6 @@ def SelectiveFormatter(formatter, skip_values): """ global _SelectiveFormatterClass if _SelectiveFormatterClass is None: - from matplotlib.ticker import Formatter class _SelectiveFormatterClass(Formatter): @@ -3109,7 +3108,7 @@ def list_plot(data, plotjoined=False, **kwargs): except ValueError: # numpy raises ValueError if it is not empty pass if not isinstance(plotjoined, bool): - raise TypeError("The second argument 'plotjoined' should be boolean " "(True or False). If you meant to plot two lists 'x' " "and 'y' against each other, use 'list_plot(list(zip(x,y)))'.") + raise TypeError("The second argument 'plotjoined' should be boolean (True or False). If you meant to plot two lists 'x' and 'y' against each other, use 'list_plot(list(zip(x,y)))'.") if isinstance(data, dict): if plotjoined: list_data = sorted(data.items()) diff --git a/src/sage/plot/plot3d/implicit_plot3d.py b/src/sage/plot/plot3d/implicit_plot3d.py index 3a96b91d3ac..9fa208986f1 100644 --- a/src/sage/plot/plot3d/implicit_plot3d.py +++ b/src/sage/plot/plot3d/implicit_plot3d.py @@ -2,6 +2,7 @@ """ Implicit plots """ + from sage.plot.plot3d.implicit_surface import ImplicitSurface diff --git a/src/sage/plot/plot3d/list_plot3d.py b/src/sage/plot/plot3d/list_plot3d.py index 4f40ce5636c..006747aee90 100644 --- a/src/sage/plot/plot3d/list_plot3d.py +++ b/src/sage/plot/plot3d/list_plot3d.py @@ -535,7 +535,7 @@ def list_plot3d_tuples(v, interpolation_type, **kwds): from .plot3d import plot3d if len(v) < 3: - raise ValueError("we need at least 3 points to perform the " "interpolation") + raise ValueError("we need at least 3 points to perform the interpolation") x = [float(p[0]) for p in v] y = [float(p[1]) for p in v] @@ -564,7 +564,7 @@ def list_plot3d_tuples(v, interpolation_type, **kwds): for j in range(i + 1, nb_points): if x[i] == x[j] and y[i] == y[j]: if z[i] != z[j]: - raise ValueError("points with same x,y coordinates" " and different z coordinates were" " given. Interpolation cannot handle this.") + raise ValueError("points with same x,y coordinates and different z coordinates were given. Interpolation cannot handle this.") elif z[i] == z[j]: drop_list.append(j) x = [x[i] for i in range(nb_points) if i not in drop_list] @@ -595,7 +595,6 @@ def g(x, y): return G if interpolation_type == 'clough' or interpolation_type == 'default': - points = [[x[i], y[i]] for i in range(len(x))] j = complex(0, 1) f = interpolate.CloughTocher2DInterpolator(points, z) diff --git a/src/sage/plot/plot3d/plot3d.py b/src/sage/plot/plot3d/plot3d.py index 97fbc908314..9de19f29446 100644 --- a/src/sage/plot/plot3d/plot3d.py +++ b/src/sage/plot/plot3d/plot3d.py @@ -195,7 +195,7 @@ def __init__(self, dep_var, indep_vars): A = set(all_vars) B = set(indep_vars + [dep_var]) if A != B: - raise ValueError('variables were specified incorrectly for this ' 'coordinate system; incorrect variables ' 'were %s' % list(A.symmetric_difference(B))) + raise ValueError('variables were specified incorrectly for this coordinate system; incorrect variables were %s' % list(A.symmetric_difference(B))) self.dep_var = dep_var self.indep_vars = indep_vars diff --git a/src/sage/plot/plot3d/shapes2.py b/src/sage/plot/plot3d/shapes2.py index 39d8be3f302..d0335333918 100644 --- a/src/sage/plot/plot3d/shapes2.py +++ b/src/sage/plot/plot3d/shapes2.py @@ -504,7 +504,7 @@ def frame_labels(lower_left, upper_right, label_lower_left, label_upper_right, e lx0, ly0, lz0 = label_lower_left lx1, ly1, lz1 = label_upper_right if (lx1 - lx0) <= 0 or (ly1 - ly0) <= 0 or (lz1 - lz0) <= 0: - raise ValueError("ensure the upper right labels are above " "and to the right of the lower left labels") + raise ValueError("ensure the upper right labels are above and to the right of the lower left labels") # Helper function for formatting the frame labels from math import log @@ -942,7 +942,7 @@ def tachyon_repr(self, render_params): radius = self.size * TACHYON_PIXEL texture = self.texture.id - return f"Sphere center {cen[0]!r} {cen[1]!r} {cen[2]!r} " f"Rad {radius!r} {texture}" + return f"Sphere center {cen[0]!r} {cen[1]!r} {cen[2]!r} Rad {radius!r} {texture}" def obj_repr(self, render_params): """ @@ -1140,7 +1140,7 @@ def tachyon_repr(self, render_params): cmds.append(A.tachyon_repr(render_params)) render_params.pop_transform() else: - cmd = ('FCylinder base {pos[0]!r} {pos[1]!r} {pos[2]!r} ' 'apex {apex[0]!r} {apex[1]!r} {apex[2]!r} ' 'rad {radius!r} {texture}').format(pos=(px, py, pz), apex=(x, y, z), radius=radius, texture=self.texture.id) + cmd = ('FCylinder base {pos[0]!r} {pos[1]!r} {pos[2]!r} apex {apex[0]!r} {apex[1]!r} {apex[2]!r} rad {radius!r} {texture}').format(pos=(px, py, pz), apex=(x, y, z), radius=radius, texture=self.texture.id) cmds.append(cmd) px, py, pz = x, y, z return cmds diff --git a/src/sage/plot/plot3d/tachyon.py b/src/sage/plot/plot3d/tachyon.py index a5799575fe0..f2f2ca100aa 100644 --- a/src/sage/plot/plot3d/tachyon.py +++ b/src/sage/plot/plot3d/tachyon.py @@ -635,9 +635,7 @@ def _camera(self): """ camera_out = r""" camera - projection %s""" % ( - tostr(self._projection) - ) + projection %s""" % (tostr(self._projection)) if self._focallength != '': camera_out = ( camera_out @@ -654,7 +652,7 @@ def _camera(self): ) camera_out = ( camera_out - + fr""" + + rf""" zoom {float(self._zoom)} aspectratio {float(self._aspectratio)} antialiasing {int(self._antialiasing)} @@ -699,9 +697,7 @@ def str(self): {} {} {} - end_scene""".format( - self._res(), self._camera(), '\n'.join(x.str() for x in self._objects) - ) + end_scene""".format(self._res(), self._camera(), '\n'.join(x.str() for x in self._objects)) def light(self, center, radius, color): r""" @@ -1112,7 +1108,7 @@ def str(self): rad 1.0 color 1.0 1.0 1.0 """ - return fr""" + return rf""" light center {tostr(self._center)} rad {self._radius} color {tostr(self._color)} @@ -1120,7 +1116,6 @@ def str(self): class Texfunc: - def __init__(self, ttype=0, center=(0, 0, 0), rotate=(0, 0, 0), scale=(1, 1, 1), imagefile=''): r""" Create a texture function. @@ -1172,7 +1167,6 @@ def str(self): class Texture: - def __init__(self, name, ambient=0.2, diffuse=0.8, specular=0.0, opacity=1.0, color=(1.0, 0.0, 0.5), texfunc=0, phong=0, phongsize=0, phongtype='PLASTIC', imagefile=''): r""" Store texture information. @@ -1228,9 +1222,7 @@ def str(self): texdef {} ambient {} diffuse {} specular {} opacity {} phong {} {} phong_size {} color {} texfunc {} - """.format( - self._name, self._ambient, self._diffuse, self._specular, self._opacity, self._phongtype, self._phong, self._phongsize, tostr(self._color), self._texfunc - ) + """.format(self._name, self._ambient, self._diffuse, self._specular, self._opacity, self._phongtype, self._phong, self._phongsize, tostr(self._color), self._texfunc) class Sphere: @@ -1269,7 +1261,7 @@ def str(self): sage: s.str() '\n sphere center 1.0 1.0 1.0 rad 1.0 r\n ' """ - return fr""" + return rf""" sphere center {tostr(self._center)} rad {self._radius} {self._texture} """ @@ -1312,9 +1304,7 @@ def str(self): """ return r""" ring center {} normal {} inner {} outer {} {} - """.format( - tostr(self._center), tostr(self._normal), self._inner, self._outer, self._texture - ) + """.format(tostr(self._center), tostr(self._normal), self._inner, self._outer, self._texture) class FractalLandscape: @@ -1356,9 +1346,7 @@ def str(self): """ return r""" scape res {} scale {} center {} {} - """.format( - tostr(self._res, 2, int), tostr(self._scale, 2, int), tostr(self._center), self._texture - ) + """.format(tostr(self._res, 2, int), tostr(self._scale, 2, int), tostr(self._center), self._texture) class Cylinder: @@ -1399,9 +1387,7 @@ def str(self): """ return r""" cylinder center {} axis {} rad {} {} - """.format( - tostr(self._center), tostr(self._axis), self._radius, self._texture - ) + """.format(tostr(self._center), tostr(self._axis), self._radius, self._texture) class Plane: @@ -1437,7 +1423,7 @@ def str(self): sage: p.str() '\n plane center 1.0 2.0 3.0 normal 1.0 2.0 4.0 s\n ' """ - return fr""" + return rf""" plane center {tostr(self._center)} normal {tostr(self._normal)} {self._texture} """ @@ -1478,9 +1464,7 @@ def str(self): """ return r""" fcylinder base {} apex {} rad {} {} - """.format( - tostr(self._center), tostr(self._axis), self._radius, self._texture - ) + """.format(tostr(self._center), tostr(self._axis), self._radius, self._texture) class Axis_aligned_box: @@ -1516,7 +1500,7 @@ def str(self): sage: aab.str() '\n box min 0.0 0.0 0.0 max 1.0 1.0 1.0 s\n ' """ - return fr""" + return rf""" box min {tostr(self._min_p)} max {tostr(self._max_p)} {self._texture} """ @@ -1537,7 +1521,7 @@ def str(self): sage: t.str() '\n TRI V0 -1.0 -1.0 -1.0 V1 0.0 0.0 0.0 V2 1.0 2.0 3.0 \n 0\n ' """ - return fr""" + return rf""" TRI V0 {tostr(self._a)} V1 {tostr(self._b)} V2 {tostr(self._c)} {self._color} """ @@ -1559,7 +1543,7 @@ def str(self): sage: t.str() '\n STRI V0 ... 1.0 0.0 0.0 N1 0.0 1.0 0.0 N2 0.0 0.0 1.0 \n 0\n ' """ - return fr""" + return rf""" STRI V0 {tostr(self._a)} V1 {tostr(self._b)} V2 {tostr(self._c)} N0 {tostr(self._da)} N1 {tostr(self._db)} N2 {tostr(self._dc)} {self._color} diff --git a/src/sage/plot/plot3d/texture.py b/src/sage/plot/plot3d/texture.py index dad99eea86a..5fb9d8a029f 100644 --- a/src/sage/plot/plot3d/texture.py +++ b/src/sage/plot/plot3d/texture.py @@ -374,7 +374,7 @@ def x3d_str(self) -> str: sage: t.x3d_str() "" """ - return ("" "" "").format(color=self.color, shininess=self.shininess, specular=self.specular[0]) + return ("").format(color=self.color, shininess=self.shininess, specular=self.specular[0]) def mtl_str(self) -> str: r""" diff --git a/src/sage/plot/plot_field.py b/src/sage/plot/plot_field.py index a3e2fd52690..2dcfdc7906d 100644 --- a/src/sage/plot/plot_field.py +++ b/src/sage/plot/plot_field.py @@ -2,6 +2,7 @@ """ Plotting fields """ + # **************************************************************************** # Copyright (C) 2006 Alex Clemesha , # William Stein , diff --git a/src/sage/plot/streamline_plot.py b/src/sage/plot/streamline_plot.py index 1981b871d7b..b4f805225b9 100644 --- a/src/sage/plot/streamline_plot.py +++ b/src/sage/plot/streamline_plot.py @@ -2,6 +2,7 @@ """ Streamline plots """ + # **************************************************************************** # Copyright (C) 2006 Alex Clemesha , # William Stein , diff --git a/src/sage/plot/text.py b/src/sage/plot/text.py index f4976b6d53a..d8df42b1a87 100644 --- a/src/sage/plot/text.py +++ b/src/sage/plot/text.py @@ -106,7 +106,7 @@ def _allowed_options(self): return { 'fontsize': 'How big the text is. Either the size in points or a relative size, e.g. \'smaller\', \'x-large\', etc', 'fontstyle': 'A string either \'normal\', \'italic\' or \'oblique\'', - 'fontweight': 'A numeric value in the range 0-1000 or a string' '\'ultralight\', \'light\', \'normal\', \'regular\', \'book\',' '\'medium\', \'roman\', \'semibold\', \'demibold\', \'demi\',' '\'bold,\', \'heavy\', \'extra bold\', \'black\'', + 'fontweight': 'A numeric value in the range 0-1000 or a string\'ultralight\', \'light\', \'normal\', \'regular\', \'book\',\'medium\', \'roman\', \'semibold\', \'demibold\', \'demi\',\'bold,\', \'heavy\', \'extra bold\', \'black\'', 'rgbcolor': 'The color as an RGB tuple', 'background_color': 'The background color', 'bounding_box': 'A dictionary specifying a bounding box', diff --git a/src/sage/quadratic_forms/binary_qf.py b/src/sage/quadratic_forms/binary_qf.py index faf714512ab..e4da9552bf3 100644 --- a/src/sage/quadratic_forms/binary_qf.py +++ b/src/sage/quadratic_forms/binary_qf.py @@ -950,7 +950,7 @@ def reduced_form(self, transformation=False, algorithm='default'): if algorithm == 'sage': if self.discriminant() <= 0: - raise NotImplementedError('reduction of definite binary ' 'quadratic forms is not implemented ' 'in Sage') + raise NotImplementedError('reduction of definite binary quadratic forms is not implemented in Sage') return self._reduce_indef(transformation) if algorithm == 'pari': @@ -964,14 +964,14 @@ def reduced_form(self, transformation=False, algorithm='default'): return -r * M if self.is_reducible(): - raise NotImplementedError('reducible forms are not ' 'supported using PARI') + raise NotImplementedError('reducible forms are not supported using PARI') if transformation: y, g = self.__pari__().qfbredsl2() return BinaryQF(y), Matrix(ZZ, g) return BinaryQF(self.__pari__().qfbred()) - raise ValueError('unknown implementation for binary quadratic form ' 'reduction: %s' % algorithm) + raise ValueError('unknown implementation for binary quadratic form reduction: %s' % algorithm) # Buchmann/Vollmer cycle algorithm def _RhoTau(self): @@ -1190,7 +1190,7 @@ def cycle(self, proper=False): raise ValueError("%s must be indefinite and reduced" % self) if self.discriminant().is_square(): # Buchmann/Vollmer assume the discriminant to be non-square - raise NotImplementedError('computation of cycles is only ' 'implemented for non-square ' 'discriminants') + raise NotImplementedError('computation of cycles is only implemented for non-square discriminants') if proper: # Prop 6.10.5 in Buchmann Vollmer C = list(self.cycle(proper=False)) # make a copy that we can modify diff --git a/src/sage/quadratic_forms/genera/genus.py b/src/sage/quadratic_forms/genera/genus.py index 07c4f65b6a3..c0fa5bfc6c5 100644 --- a/src/sage/quadratic_forms/genera/genus.py +++ b/src/sage/quadratic_forms/genera/genus.py @@ -9,6 +9,7 @@ - Simon Brandhorst (2018): enumeration of genera - Simon Brandhorst (2020): genus representative """ + # **************************************************************************** # Copyright (C) 2007 David Kohel # Gabriele Nebe @@ -498,7 +499,6 @@ def is_2_adic_genus(genus_symbol_quintuple_list) -> bool: # TO DO: Add explicit checking for the prime p here to ensure it's p=2... not just the quintuple checking below for s in genus_symbol_quintuple_list: - # Check that we have a quintuple (i.e. that p=2 and not p >2) if len(s) != 5: raise TypeError("The genus symbols are not quintuples, so it's not a genus symbol for the prime p=2.") @@ -659,7 +659,6 @@ def canonical_2_adic_trains(genus_symbol_quintuple_list) -> list: symbol.append([symbol[-1][0] + 1, 0, 1, 0, 0]) # We have just modified the input globally! # Hence, we have to remove the last entry of symbol at the end. try: - trains = [] new_train = [0] for i in range(1, len(symbol) - 1): @@ -1346,7 +1345,7 @@ def __repr__(self): # mark the beginning of this compartment with [ CS_string += "[" block = CS[block_index] - block_string = f"{p**block[0]}^{block[2] * block[1]} " + block_string = f"{p ** block[0]}^{block[2] * block[1]} " CS_string += block_string if block_index in compartment_ends: # close this compartment with ] and remove a space @@ -1364,7 +1363,7 @@ def __repr__(self): else: for s in self._symbol: - CS_string += f" {p**s[0]}^{s[2] * s[1]}" + CS_string += f" {p ** s[0]}^{s[2] * s[1]}" rep = f"Genus symbol at {p}: {CS_string}" return rep.rstrip() @@ -1400,7 +1399,7 @@ def _latex_(self): # mark the beginning of this compartment with [ CS_string += "[" block = CS[block_index] - block_string = f"{p**block[0]}^{{{block[2] * block[1]}}} " + block_string = f"{p ** block[0]}^{{{block[2] * block[1]}}} " CS_string += block_string if block_index in compartment_ends: # close this compartment with ] and remove a space @@ -1416,8 +1415,8 @@ def _latex_(self): else: for s in self._symbol: - CS_string += f" {{{p**s[0]}}}^{{{s[2]*s[1]}}}" - return fr"\mbox{{Genus symbol at }} {p}\mbox{{: }}{CS_string}" + CS_string += f" {{{p ** s[0]}}}^{{{s[2] * s[1]}}}" + return rf"\mbox{{Genus symbol at }} {p}\mbox{{: }}{CS_string}" def __eq__(self, other): r""" @@ -2430,7 +2429,7 @@ def _latex_(self) -> str: rep += r" of}\\ %s" % self._representative._latex_() else: rep += r"}" - rep += fr"\\ \mbox{{Signature: }} {self._signature}" + rep += rf"\\ \mbox{{Signature: }} {self._signature}" for s in self._local_symbols: rep += r"\\ " + s._latex_() return rep diff --git a/src/sage/quadratic_forms/genera/spinor_genus.py b/src/sage/quadratic_forms/genera/spinor_genus.py index a8cdb0100ac..adb21b9c7ac 100644 --- a/src/sage/quadratic_forms/genera/spinor_genus.py +++ b/src/sage/quadratic_forms/genera/spinor_genus.py @@ -69,7 +69,7 @@ def _repr_(self) -> str: elif e[0] == 1 == e[1]: s += "7" for k in range(1, len(p)): - s += f", {p[k]}:{(-1)**e[k + 1]}" + s += f", {p[k]}:{(-1) ** e[k + 1]}" s += "]" return s diff --git a/src/sage/quadratic_forms/quadratic_form.py b/src/sage/quadratic_forms/quadratic_form.py index 60b7aaaf253..cae9ce333e8 100644 --- a/src/sage/quadratic_forms/quadratic_form.py +++ b/src/sage/quadratic_forms/quadratic_form.py @@ -598,7 +598,6 @@ def __init__( # Process possible forced initialization of various fields self._external_initialization_list = [] if unsafe_initialization: - # Set the number of automorphisms if number_of_automorphisms is not None: self.set_number_of_automorphisms(number_of_automorphisms) @@ -1546,7 +1545,6 @@ def level(self): try: return self.__level except AttributeError: - # Check that the base ring is a PID if self.base_ring() not in PrincipalIdealDomains(): raise TypeError("the level (as a number) is only defined over a Principal Ideal Domain ; try using level_ideal()") diff --git a/src/sage/quadratic_forms/quadratic_form__automorphisms.py b/src/sage/quadratic_forms/quadratic_form__automorphisms.py index 47075012992..a8862fe3e3f 100644 --- a/src/sage/quadratic_forms/quadratic_form__automorphisms.py +++ b/src/sage/quadratic_forms/quadratic_form__automorphisms.py @@ -2,6 +2,7 @@ """ Automorphisms of Quadratic Forms """ + # **************************************************************************** # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of @@ -176,7 +177,7 @@ def short_vector_list_up_to_length(self, len_bound, up_to_sign_flag=False): 45902280 """ if not self.is_positive_definite(): - raise ValueError("Quadratic form must be positive definite " "in order to enumerate short vectors") + raise ValueError("Quadratic form must be positive definite in order to enumerate short vectors") from sage.libs.pari import pari diff --git a/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py b/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py index 628cb8d8291..f48673ed93d 100644 --- a/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py +++ b/src/sage/quadratic_forms/quadratic_form__equivalence_testing.py @@ -156,7 +156,6 @@ def is_locally_equivalent_to(self, other, check_primes_only=False, force_jordan_ # Test equivalence over Z_p for all primes if (self.base_ring() == ZZ) and (not force_jordan_equivalence_test): - # Test equivalence with Conway-Sloane genus symbols (default over ZZ) if self.CS_genus_symbol_list() != other.CS_genus_symbol_list(): return False @@ -229,7 +228,6 @@ def has_equivalent_Jordan_decomposition_at_prime(self, other, p) -> bool: # For p = 2: Check that all Jordan Invariants are the same. if p == 2: - # Useful definition t = len(self_jordan) # Define t = Number of Jordan components @@ -268,7 +266,6 @@ def has_equivalent_Jordan_decomposition_at_prime(self, other, p) -> bool: # Test O'Meara's two conditions for i in range(t - 1): - # Condition (i): Check that their (unit) ratio is a square (but it suffices to check at most mod 8). modulus = norm_list[i] * norm_list[i + 1] / (scale_list[i] ** 2) modulus = min(modulus, 8) @@ -501,7 +498,6 @@ def is_rationally_isometric(self, other, return_matrix=False) -> bool | Any: if self.signature() != other.signature(): return False else: - M = self.rational_diagonal_form().Gram_matrix_rational() N = other.rational_diagonal_form().Gram_matrix_rational() K = self.base_ring() @@ -510,7 +506,6 @@ def is_rationally_isometric(self, other, return_matrix=False) -> bool | Any: Nentries = N.diagonal() for emb in K.real_embeddings(): - Mpos = 0 for x in Mentries: Mpos += emb(x) >= 0 diff --git a/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py b/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py index 8afe1ac41f0..3514d610727 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py +++ b/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py @@ -235,7 +235,6 @@ def local_good_density_congruence_even(self, m, Zvec, NZvec): # ------------------------------------------------------------------------------- Not8vec = [] for i in range(n): - # DIAGNOSTIC verbose(" i = " + str(i)) verbose(" n = " + str(n)) @@ -249,7 +248,6 @@ def local_good_density_congruence_even(self, m, Zvec, NZvec): # Check appropriate off-diagonal entries aren't divisible by 8 else: - # Special check for first off-diagonal entry if i == 0 and self[i, i + 1] % 8: nz_flag = True @@ -553,7 +551,6 @@ def local_badI_density_congruence(self, p, m, Zvec=None, NZvec=None): # Find the valuation of each variable (which will be the same over 2x2 blocks), # remembering those of valuation 0 and if an entry of valuation 1 exists. for i in range(n): - # Compute the valuation of each index, allowing for off-diagonal terms if self[i, i] == 0: if i == 0: @@ -699,7 +696,6 @@ def local_badII_density_congruence(self, p, m, Zvec=None, NZvec=None): S2plus = [] for i in range(n): - # Compute the valuation of each index, allowing for off-diagonal terms if self[i, i] == 0: if i == 0: diff --git a/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py b/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py index 81ced1e5462..56746e5b5ad 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py +++ b/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py @@ -264,10 +264,8 @@ def _rational_diagonal_form_and_transformation(self): # Clear the entries one row at a time. for i in range(n): - # Deal with rows where the diagonal entry is zero. if Q[i, i] == 0: - # Look for a nonzero entry and use it to make the diagonal nonzero (if it exists) for j in range(i + 1, n): if Q[i, j] != 0: diff --git a/src/sage/quadratic_forms/quadratic_form__local_normal_form.py b/src/sage/quadratic_forms/quadratic_form__local_normal_form.py index 790159342ed..7c12605fab2 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_normal_form.py +++ b/src/sage/quadratic_forms/quadratic_form__local_normal_form.py @@ -64,7 +64,6 @@ def find_entry_with_minimal_scale_at_prime(self, p): val_2 = valuation(2, p) for d in range(n): # d = difference j-i for e in range(n - d): # e is the length of the diagonal with value d. - # Compute the valuation of the entry if d == 0: tmp_val = valuation(self[e, e + d], p) @@ -322,7 +321,6 @@ def jordan_blocks_by_scale_and_unimodular(self, p, safe_flag=True): start_scale = valuation(Q1[0, 0], p) while i < n: - # Determine the size of the current block if i == n - 1 or Q1[i, i + 1] == 0: block_size = 1 diff --git a/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py b/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py index e6ae48f46bd..893aab6dcbd 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py +++ b/src/sage/quadratic_forms/quadratic_form__local_representation_conditions.py @@ -2,6 +2,7 @@ """ Local Representation Conditions """ + ######################################################################## # Class for keeping track of the local conditions for representability # # of numbers by a quadratic form over ZZ (and eventually QQ also). # diff --git a/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py b/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py index 62496984a6d..953693d7552 100644 --- a/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py +++ b/src/sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py @@ -191,7 +191,6 @@ def conway_species_list_at_odd_prime(self, p): # Make a list of species (including the two zero-dim'l forms missing at either end of the list of Jordan blocks) species_list = [] for tmp_Q in jordan_list: - # Some useful variables n = tmp_Q.dim() d = tmp_Q.det() @@ -258,7 +257,6 @@ def conway_species_list_at_2(self): species_list.append(1) for i in range(len(jordan_list)): # Add an entry for each (listed) Jordan component - # Make the number 2*t in the C-S Table 1. d = jordan_list[i].dim() if jordan_list[i].is_even(): @@ -334,7 +332,6 @@ def conway_octane_of_this_unimodular_Jordan_block_at_2(self): # Use u to diagonalize the form -- WHAT ARE THE POSSIBLE LOCAL NORMAL FORMS? while ind < n: - # Check for a 1x1 block and diagonalize it if ind == n - 1 or self[ind, ind + 1] == 0: tmp_diag_vec[ind] = self[ind, ind] diff --git a/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py b/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py index f5b434af7a1..93b03ac8a91 100644 --- a/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py +++ b/src/sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py @@ -312,7 +312,6 @@ def Kitaoka_mass_at_2(self): E = QQ.one() for j in range(s_min - 1, s_max + 2): if (diag_dict[j - 1].dim() == 0) and (diag_dict[j + 1].dim() == 0) and ((diag_dict[j].dim() != 2) or (((diag_dict[j][0, 0] - diag_dict[j][1, 1]) % 4) != 0)): - # Deal with the complicated case: tmp_m = dim2_dict[j].dim() // 2 if dim2_dict[j].is_hyperbolic(2): diff --git a/src/sage/quadratic_forms/quadratic_form__neighbors.py b/src/sage/quadratic_forms/quadratic_form__neighbors.py index d94ed9a6cbb..60f78662482 100644 --- a/src/sage/quadratic_forms/quadratic_form__neighbors.py +++ b/src/sage/quadratic_forms/quadratic_form__neighbors.py @@ -107,7 +107,6 @@ def find_primitive_p_divisible_vector__next(self, p, v=None): # Look for the next vector, until w == 0 while True: - # Look for the first non-maximal (non-normalized) entry ind = 0 while (ind < nz) and (w[ind] == p - 1): diff --git a/src/sage/quadratic_forms/quadratic_form__reduction_theory.py b/src/sage/quadratic_forms/quadratic_form__reduction_theory.py index 81d485870c5..dad6e006349 100644 --- a/src/sage/quadratic_forms/quadratic_form__reduction_theory.py +++ b/src/sage/quadratic_forms/quadratic_form__reduction_theory.py @@ -245,7 +245,6 @@ def minkowski_reduction(self): # Begin the reduction done_flag = False while not done_flag: - # Loop through possible shorted vectors until done_flag = True for j in range(n - 1, -1, -1): @@ -256,7 +255,6 @@ def minkowski_reduction(self): # Reduce if a shorter vector is found if Q(y) < Q(e_j): - # Create the transformation matrix M_new = matrix(R, n, n, 1) for k in range(n): @@ -340,7 +338,6 @@ def minkowski_reduction_for_4vars__SP(self): # Step 1: Begin the reduction done_flag = False while not done_flag: - # Loop through possible shorter vectors done_flag = True for j in range(n - 1, -1, -1): @@ -351,7 +348,6 @@ def minkowski_reduction_for_4vars__SP(self): # Reduce if a shorter vector is found if Q(y) < Q(e_j): - # Further n=4 computations B_y_vec = Q.matrix() * vector(ZZ, y) # SP's B = our self.matrix()/2 @@ -363,7 +359,6 @@ def minkowski_reduction_for_4vars__SP(self): A_max = max(abs(Q[i, j]) for i in range(4) if i != j) if B_sum < A_sum or (B_sum == A_sum and B_max < A_max): - # Create the transformation matrix M_new = matrix(R, n, n, 1) for k in range(n): @@ -383,7 +378,6 @@ def minkowski_reduction_for_4vars__SP(self): # Step 2: Order A by certain criteria for i in range(4): for j in range(i + 1, 4): - # Condition (a) if Q[i, i] > Q[j, j]: Q.swap_variables(i, j, in_place=True) diff --git a/src/sage/quadratic_forms/quadratic_form__split_local_covering.py b/src/sage/quadratic_forms/quadratic_form__split_local_covering.py index cc9efaf31e7..b4dcbc463d9 100644 --- a/src/sage/quadratic_forms/quadratic_form__split_local_covering.py +++ b/src/sage/quadratic_forms/quadratic_form__split_local_covering.py @@ -207,7 +207,6 @@ def vectors_by_length(self, bound): # Big loop which runs through all vectors while not done_flag: - # 3b. Main loop -- try to generate a complete vector x (when i=0) while i > 0: T[i - 1] = T[i] - Q[i][i] * (x[i] + U[i]) * (x[i] + U[i]) @@ -332,7 +331,6 @@ def complementary_subform_to_vector(self, v): # For each row/column, perform elementary operations to cancel them out. for i in range(1, n): - # Check if the (i,0)-entry is divisible by d, # and stretch its row/column if not. if Q1[i, 0] % d: @@ -399,7 +397,6 @@ def split_local_cover(self): # Loop until we find a split local cover... while True: - # 2. Check if any of the primitive ones produce a split local cover for v in current_vectors: Q = QuadraticForm(ZZ, 1, [current_length]) + self.complementary_subform_to_vector(v) diff --git a/src/sage/quadratic_forms/quadratic_form__theta.py b/src/sage/quadratic_forms/quadratic_form__theta.py index b37cc0238ba..ca6ccfba06f 100644 --- a/src/sage/quadratic_forms/quadratic_form__theta.py +++ b/src/sage/quadratic_forms/quadratic_form__theta.py @@ -205,10 +205,8 @@ def theta_by_cholesky(self, q_prec): # Big loop which runs through all vectors while not done_flag: - # Loop through until we get to i=1 (so we defined a vector x) while from_step3_flag or from_step4_flag: # IMPORTANT WARNING: This replaces a do...while loop, so it may have to be adjusted! - # Go to directly to step 3 if we're coming from step 4, otherwise perform step 2. if from_step4_flag: from_step4_flag = False diff --git a/src/sage/quadratic_forms/random_quadraticform.py b/src/sage/quadratic_forms/random_quadraticform.py index c5b395da1c1..de54b745909 100644 --- a/src/sage/quadratic_forms/random_quadraticform.py +++ b/src/sage/quadratic_forms/random_quadraticform.py @@ -62,7 +62,7 @@ def random_quadraticform(R, n, rand_arg_list=None): if rand_arg_list is None: rand_arg_list = [] if len(rand_arg_list) > 3: - raise TypeError("the list of randomness arguments can have " "at most 3 elements") + raise TypeError("the list of randomness arguments can have at most 3 elements") if R not in Rings(): raise TypeError("the first argument must be a ring") # Create a list of upper-triangular entries for the quadratic form @@ -107,7 +107,6 @@ def random_quadraticform_with_conditions(R, n, condition_list=[], rand_arg_list= while done_flag: done_flag = False for c in condition_list: - # Check if condition c is satisfied try: bool_ans = Q.c() diff --git a/src/sage/quadratic_forms/ternary_qf.py b/src/sage/quadratic_forms/ternary_qf.py index f0af3a119ed..b7983d833ea 100644 --- a/src/sage/quadratic_forms/ternary_qf.py +++ b/src/sage/quadratic_forms/ternary_qf.py @@ -787,17 +787,14 @@ def pseudorandom_primitive_zero_mod_p(self, p): """ a, b, c, r, s, t = self.coefficients() while True: - r1 = randint(0, p - 1) r2 = randint(0, p - 1) alpha = (b * r1**2 + t * r1 + a) % p if alpha != 0: - beta = (2 * b * r1 * r2 + t * r2 + r * r1 + s) % p gamma = (b * r2**2 + r * r2 + c) % p disc = beta**2 - 4 * alpha * gamma if mod(disc, p).is_square(): - z = (-beta + mod(disc, p).sqrt().lift()) * (2 * alpha).inverse_mod(p) # return vector((z,r1*z+r2,1))%p return z % p, (r1 * z + r2) % p, 1 diff --git a/src/sage/quivers/morphism.py b/src/sage/quivers/morphism.py index b13b3f76571..3f72dbabe25 100644 --- a/src/sage/quivers/morphism.py +++ b/src/sage/quivers/morphism.py @@ -222,11 +222,11 @@ def __init__(self, domain, codomain, data={}): # The only case left is that data is a QuiverRepElement else: if not isinstance(data, QuiverRepElement): - raise TypeError("input data must be dictionary, list, " "QuiverRepElement or vector") + raise TypeError("input data must be dictionary, list, QuiverRepElement or vector") if not isinstance(domain, QuiverRep_with_path_basis): - raise TypeError("if data is a QuiverRepElement then domain " "must be a QuiverRep_with_path_basis.") + raise TypeError("if data is a QuiverRepElement then domain must be a QuiverRep_with_path_basis.") if data not in codomain: - raise ValueError("if data is a QuiverRepElement then it must " "be an element of codomain") + raise ValueError("if data is a QuiverRepElement then it must be an element of codomain") im_list = [codomain.right_edge_action(data, p) for v in domain._quiver for p in domain._bases[v]] # WARNING: This code assumes that the function QuiverRep.gens() returns @@ -238,7 +238,7 @@ def __init__(self, domain, codomain, data={}): # Get the gens of the domain and check that im_list is the right length dom_gens = domain.gens() if len(im_list) != len(dom_gens): - raise ValueError(("domain is dimension {} but only {} images" " were supplied").format(len(dom_gens), len(im_list))) + raise ValueError(("domain is dimension {} but only {} images were supplied").format(len(dom_gens), len(im_list))) # Get the matrices of the maps start_index = 0 diff --git a/src/sage/repl/configuration.py b/src/sage/repl/configuration.py index 032f207f00c..01c4f945c7c 100644 --- a/src/sage/repl/configuration.py +++ b/src/sage/repl/configuration.py @@ -24,7 +24,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - import copy import sys @@ -37,7 +36,6 @@ class SageIpythonConfiguration: - def _doctest_mode(self): """ Whether we are in doctest mode. diff --git a/src/sage/repl/display/fancy_repr.py b/src/sage/repl/display/fancy_repr.py index c89a00b116a..626abc72d92 100644 --- a/src/sage/repl/display/fancy_repr.py +++ b/src/sage/repl/display/fancy_repr.py @@ -99,7 +99,6 @@ def format_string(self, obj): class SomeIPythonRepr(ObjectReprABC): - def __init__(self): """ Some selected representers from IPython. diff --git a/src/sage/repl/display/formatter.py b/src/sage/repl/display/formatter.py index 9857438eeab..40961e86755 100644 --- a/src/sage/repl/display/formatter.py +++ b/src/sage/repl/display/formatter.py @@ -79,7 +79,6 @@ class SageDisplayFormatter(DisplayFormatter): - def __init__(self, *args, **kwds): """ This is where the Sage rich objects are translated to IPython. @@ -249,7 +248,6 @@ def _ipython_float_precision_changed(change): class SagePlainTextFormatter(PlainTextFormatter): - def __init__(self, *args, **kwds): r""" Improved plain text IPython formatter. diff --git a/src/sage/repl/display/jsmol_iframe.py b/src/sage/repl/display/jsmol_iframe.py index 719d2d9f106..ccc1516fa00 100644 --- a/src/sage/repl/display/jsmol_iframe.py +++ b/src/sage/repl/display/jsmol_iframe.py @@ -84,13 +84,10 @@ {iframe} -""".format( - iframe=IFRAME_TEMPLATE -) +""".format(iframe=IFRAME_TEMPLATE) class JSMolHtml(SageObject): - def __init__(self, jmol, path_to_jsmol=None, width='100%', height='100%'): """ INPUT: diff --git a/src/sage/repl/display/pretty_print.py b/src/sage/repl/display/pretty_print.py index e74c3193feb..a70b9fd3dd8 100644 --- a/src/sage/repl/display/pretty_print.py +++ b/src/sage/repl/display/pretty_print.py @@ -22,14 +22,12 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from IPython.lib.pretty import PrettyPrinter from sage.repl.display.fancy_repr import TallListRepr, PlainPythonRepr, LargeMatrixHelpRepr, SomeIPythonRepr class SagePrettyPrinter(PrettyPrinter): - DEBUG = False # These object representers will be tried, in this order, until diff --git a/src/sage/repl/image.py b/src/sage/repl/image.py index 9a081216f26..59647d35a23 100644 --- a/src/sage/repl/image.py +++ b/src/sage/repl/image.py @@ -39,7 +39,6 @@ class Image(SageObject): - def __init__(self, mode, size, color='white'): """ Create a new image with the given mode and size. diff --git a/src/sage/repl/interface_magic.py b/src/sage/repl/interface_magic.py index 94f1f828a6d..377c27b74d8 100644 --- a/src/sage/repl/interface_magic.py +++ b/src/sage/repl/interface_magic.py @@ -35,7 +35,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.repl.rich_output.display_manager import get_display_manager @@ -81,7 +80,6 @@ class InterfaceMagic: - @classmethod def all_iter(cls): """ diff --git a/src/sage/repl/ipython_extension.py b/src/sage/repl/ipython_extension.py index 94545df1b70..988040a48f6 100644 --- a/src/sage/repl/ipython_extension.py +++ b/src/sage/repl/ipython_extension.py @@ -83,7 +83,6 @@ def _running_in_notebook(): @magics_class class SageMagics(Magics): - @line_magic def crun(self, s): r""" @@ -576,7 +575,6 @@ def fortran(self, line, cell): class SageCustomizations: - def __init__(self, shell=None): """ Initialize the Sage plugin. diff --git a/src/sage/repl/ipython_kernel/install.py b/src/sage/repl/ipython_kernel/install.py index 863fd8efb3e..44f3b9a04ed 100644 --- a/src/sage/repl/ipython_kernel/install.py +++ b/src/sage/repl/ipython_kernel/install.py @@ -25,7 +25,6 @@ class SageKernelSpec: - def __init__(self, prefix=None): """ Utility to manage SageMath kernels and extensions. @@ -258,7 +257,7 @@ def check(cls): try: spec = get_kernel_spec(ident) except NoSuchKernel: - warnings.warn(f'No kernel named {ident} is accessible; ' 'check your Jupyter configuration ' '(see https://docs.jupyter.org/en/latest/use/jupyter-directories.html).') + warnings.warn(f'No kernel named {ident} is accessible; check your Jupyter configuration (see https://docs.jupyter.org/en/latest/use/jupyter-directories.html).') else: import sys from pathlib import Path @@ -266,11 +265,11 @@ def check(cls): kernel_executable_feature = Executable(name=spec.argv[0], executable=spec.argv[0]) if not kernel_executable_feature.is_present(): - warnings.warn(f'The kernel named {ident} does not seem to be runnable; ' 'check your Jupyter configuration ' '(see https://docs.jupyter.org/en/latest/use/jupyter-directories.html).') + warnings.warn(f'The kernel named {ident} does not seem to be runnable; check your Jupyter configuration (see https://docs.jupyter.org/en/latest/use/jupyter-directories.html).') return kernel_executable = kernel_executable_feature.absolute_filename() if Path(kernel_executable).resolve() != Path(sys.executable).resolve(): - warnings.warn(f'The kernel named {ident} does not seem to correspond to this ' 'installation of SageMath; check your Jupyter configuration ' '(see https://docs.jupyter.org/en/latest/use/jupyter-directories.html).') + warnings.warn(f'The kernel named {ident} does not seem to correspond to this installation of SageMath; check your Jupyter configuration (see https://docs.jupyter.org/en/latest/use/jupyter-directories.html).') def have_prerequisites(debug=True) -> bool: diff --git a/src/sage/repl/ipython_kernel/widgets.py b/src/sage/repl/ipython_kernel/widgets.py index ffdd896122b..c638f787621 100644 --- a/src/sage/repl/ipython_kernel/widgets.py +++ b/src/sage/repl/ipython_kernel/widgets.py @@ -22,7 +22,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from ipywidgets.widgets import IntSlider, IntRangeSlider, FloatSlider, FloatRangeSlider, Text, Textarea, ColorPicker, HTMLMath, Label, HBox, VBox, ValueWidget from traitlets import List, Unicode, link diff --git a/src/sage/repl/preparse.py b/src/sage/repl/preparse.py index 321727e51bd..579f46c9de9 100644 --- a/src/sage/repl/preparse.py +++ b/src/sage/repl/preparse.py @@ -1285,7 +1285,6 @@ def preparse_numeric_literals(code, extract=False, quotes="'"): elif 'L' in postfix: num_name = num_make = num + postfix.replace('L', '') else: - # The Sage preparser does extra things with numbers, which we need to handle here. if '.' in num: if start > 0 and num[0] == '.': diff --git a/src/sage/repl/prompts.py b/src/sage/repl/prompts.py index 4bc2cae68e6..a5661bf9a92 100644 --- a/src/sage/repl/prompts.py +++ b/src/sage/repl/prompts.py @@ -17,7 +17,6 @@ class SagePrompts(Prompts): - def in_prompt_tokens(self, cli=None): return [ (Token.Prompt, 'sage: '), @@ -40,7 +39,6 @@ def out_prompt_tokens(self): class InterfacePrompts(Prompts): - def __init__(self, interface_name): self.__name = interface_name self.__width = len(interface_name) @@ -67,7 +65,6 @@ def out_prompt_tokens(self): class DebugPrompts(Prompts): - def in_prompt_tokens(self, cli=None): return [ (Token.Prompt, 'debug: '), diff --git a/src/sage/repl/rich_output/backend_base.py b/src/sage/repl/rich_output/backend_base.py index 8c861c44a63..2d53313fba3 100644 --- a/src/sage/repl/rich_output/backend_base.py +++ b/src/sage/repl/rich_output/backend_base.py @@ -53,7 +53,6 @@ class BackendBase(SageObject): - def _repr_(self): """ Return string representation of the backend. diff --git a/src/sage/repl/rich_output/backend_doctest.py b/src/sage/repl/rich_output/backend_doctest.py index f2e98c7b16a..199547f10f6 100644 --- a/src/sage/repl/rich_output/backend_doctest.py +++ b/src/sage/repl/rich_output/backend_doctest.py @@ -28,7 +28,6 @@ class BackendDoctest(BackendBase): - def _repr_(self): """ Return a string representation. diff --git a/src/sage/repl/rich_output/backend_ipython.py b/src/sage/repl/rich_output/backend_ipython.py index d364ee213ef..6fee6a5da34 100644 --- a/src/sage/repl/rich_output/backend_ipython.py +++ b/src/sage/repl/rich_output/backend_ipython.py @@ -638,6 +638,4 @@ def threejs_offline_scripts(self): - """.format( - Threejs().required_version(), CDN_script - ) + """.format(Threejs().required_version(), CDN_script) diff --git a/src/sage/repl/rich_output/buffer.py b/src/sage/repl/rich_output/buffer.py index 7ff2543c7f4..ba62f1f6860 100644 --- a/src/sage/repl/rich_output/buffer.py +++ b/src/sage/repl/rich_output/buffer.py @@ -30,13 +30,11 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - import os from sage.structure.sage_object import SageObject class OutputBuffer(SageObject): - def __init__(self, data): """ Data stored either in memory or as a file. diff --git a/src/sage/repl/rich_output/display_manager.py b/src/sage/repl/rich_output/display_manager.py index e1bcaedb1eb..ac2111dd6d5 100644 --- a/src/sage/repl/rich_output/display_manager.py +++ b/src/sage/repl/rich_output/display_manager.py @@ -109,7 +109,6 @@ class RichReprWarning(UserWarning): class restricted_output: - def __init__(self, display_manager, output_classes): """ Context manager to temporarily restrict the accepted output types. @@ -189,7 +188,6 @@ def __exit__(self, exception_type, value, traceback): class DisplayManager(SageObject): - _instance: Self | None = None def __init__(self): @@ -742,9 +740,7 @@ def threejs_scripts(self, online): version = Threejs().required_version() return """ - """.format( - version - ) + """.format(version) try: return self._backend.threejs_offline_scripts() except AttributeError: diff --git a/src/sage/repl/rich_output/output_basic.py b/src/sage/repl/rich_output/output_basic.py index 9c3fcd10de6..99786d9616b 100644 --- a/src/sage/repl/rich_output/output_basic.py +++ b/src/sage/repl/rich_output/output_basic.py @@ -40,7 +40,6 @@ class is independent of user preferences and of the display # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.structure.sage_object import SageObject from sage.repl.rich_output.buffer import OutputBuffer @@ -87,7 +86,6 @@ def example(cls): class OutputPlainText(OutputBase): - def __init__(self, plain_text): """ Plain Text Output. @@ -151,7 +149,6 @@ def print_to_stdout(self): class OutputAsciiArt(OutputBase): - def __init__(self, ascii_art): """ ASCII Art Output. @@ -191,7 +188,7 @@ def example(cls): sage: OutputAsciiArt.example().ascii_art.get_str() '[ * * * * ]\n[ ** ** * * * * * * ]\n[ ***, * , * , **, ** , *, * , * , * ]' """ - return cls('[ * * * * ]\n' '[ ** ** * * * * * * ]\n' '[ ***, * , * , **, ** , *, * , * , * ]') + return cls('[ * * * * ]\n[ ** ** * * * * * * ]\n[ ***, * , * , **, ** , *, * , * , * ]') def print_to_stdout(self): """ @@ -212,7 +209,6 @@ def print_to_stdout(self): class OutputUnicodeArt(OutputBase): - def __init__(self, unicode_art): """ Unicode Art Output. @@ -261,7 +257,7 @@ def example(cls): ⎜ 3 -1 0⎟ ⎝ -1 -1 0⎠ """ - return cls('⎛-11 0 1⎞\n' '⎜ 3 -1 0⎟\n' '⎝ -1 -1 0⎠') + return cls('⎛-11 0 1⎞\n⎜ 3 -1 0⎟\n⎝ -1 -1 0⎠') def print_to_stdout(self): """ @@ -282,7 +278,6 @@ def print_to_stdout(self): class OutputLatex(OutputBase): - def __init__(self, latex): """ LaTeX Output. diff --git a/src/sage/repl/rich_output/output_browser.py b/src/sage/repl/rich_output/output_browser.py index b439e437a47..023e6827de6 100644 --- a/src/sage/repl/rich_output/output_browser.py +++ b/src/sage/repl/rich_output/output_browser.py @@ -12,7 +12,6 @@ class OutputHtml(OutputBase): - def __init__(self, html): """ HTML Output. diff --git a/src/sage/repl/rich_output/output_catalog.py b/src/sage/repl/rich_output/output_catalog.py index 1758e6902a4..f3ace4935db 100644 --- a/src/sage/repl/rich_output/output_catalog.py +++ b/src/sage/repl/rich_output/output_catalog.py @@ -13,7 +13,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from .output_basic import ( OutputPlainText, OutputAsciiArt, diff --git a/src/sage/repl/rich_output/output_graphics.py b/src/sage/repl/rich_output/output_graphics.py index ee521ebf317..4d871fe9a6f 100644 --- a/src/sage/repl/rich_output/output_graphics.py +++ b/src/sage/repl/rich_output/output_graphics.py @@ -22,7 +22,6 @@ class OutputImagePng(OutputBase): - def __init__(self, png): """ PNG Image. @@ -73,7 +72,6 @@ def example(cls): class OutputImageGif(OutputBase): - def __init__(self, gif): """ GIF Image (possibly animated). @@ -136,7 +134,6 @@ def html_fragment(self): class OutputImageJpg(OutputBase): - def __init__(self, jpg): """ JPEG Image. @@ -182,7 +179,6 @@ def example(cls): class OutputImageSvg(OutputBase): - def __init__(self, svg): """ SVG Image. @@ -228,7 +224,6 @@ def example(cls): class OutputImagePdf(OutputBase): - def __init__(self, pdf): """ PDF Image. @@ -274,7 +269,6 @@ def example(cls): class OutputImageDvi(OutputBase): - def __init__(self, dvi): """ DVI Image. diff --git a/src/sage/repl/rich_output/output_graphics3d.py b/src/sage/repl/rich_output/output_graphics3d.py index 38b52172e66..1da09910376 100644 --- a/src/sage/repl/rich_output/output_graphics3d.py +++ b/src/sage/repl/rich_output/output_graphics3d.py @@ -21,7 +21,6 @@ class OutputSceneJmol(OutputBase): - def __init__(self, scene_zip, preview_png): """ JMol Scene. @@ -110,7 +109,6 @@ def example(cls): class OutputSceneCanvas3d(OutputBase): - def __init__(self, canvas3d): """ Canvas3d Scene. @@ -153,7 +151,6 @@ def example(cls): class OutputSceneThreejs(OutputBase): - def __init__(self, html): """ Three.js Scene. @@ -172,7 +169,6 @@ def __init__(self, html): class OutputSceneWavefront(OutputBase): - def __init__(self, obj, mtl): """ Wavefront `*.obj` Scene. diff --git a/src/sage/repl/rich_output/output_video.py b/src/sage/repl/rich_output/output_video.py index e1f5d7cd5ba..7b7150619a5 100644 --- a/src/sage/repl/rich_output/output_video.py +++ b/src/sage/repl/rich_output/output_video.py @@ -19,7 +19,6 @@ class OutputVideoBase(OutputBase): - def __init__(self, video, loop=True): """ Abstract base class for rich video output. @@ -97,7 +96,7 @@ def html_fragment(self, url, link_attrs=''): if self.loop: attrs['loop'] = 'loop' attrs = ''.join(' {}="{}"'.format(k, v) for k, v in sorted(attrs.items())) - txt = '' '

' '' 'Download {mimetype} video

' + txt = '

Download {mimetype} video

' return txt.format(url=url, mimetype=self.mimetype, attrs=attrs, link_attrs=link_attrs) diff --git a/src/sage/repl/rich_output/preferences.py b/src/sage/repl/rich_output/preferences.py index b0537219815..151d7702b69 100644 --- a/src/sage/repl/rich_output/preferences.py +++ b/src/sage/repl/rich_output/preferences.py @@ -72,14 +72,12 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from textwrap import dedent from sage.structure.sage_object import SageObject class Property(property): - def __init__(self, name, allowed_values, doc=None): r""" Preference item. @@ -256,7 +254,6 @@ def deleter(self, prefs): class PreferencesABC(SageObject): - def __init__(self, *args, **kwds): """ Preferences for displaying graphics. diff --git a/src/sage/repl/rich_output/pretty_print.py b/src/sage/repl/rich_output/pretty_print.py index bc30d4a63e6..1400b5c79fa 100644 --- a/src/sage/repl/rich_output/pretty_print.py +++ b/src/sage/repl/rich_output/pretty_print.py @@ -58,7 +58,6 @@ class SequencePrettyPrinter(SageObject): - def __init__(self, *args, **kwds): r""" Pretty Printer for Multiple Arguments. diff --git a/src/sage/repl/rich_output/test_backend.py b/src/sage/repl/rich_output/test_backend.py index d74afc2e069..ad309dc1955 100644 --- a/src/sage/repl/rich_output/test_backend.py +++ b/src/sage/repl/rich_output/test_backend.py @@ -38,14 +38,12 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.structure.sage_object import SageObject from sage.repl.rich_output.backend_base import BackendBase from sage.repl.rich_output.output_catalog import OutputPlainText, OutputImagePng class TestOutputPlainText(OutputPlainText): - def __init__(self, *args, **kwds): """ Backend-specific subclass of the plain text output container. @@ -129,7 +127,6 @@ def _rich_repr_(self, display_manager): class BackendTest(BackendBase): - def _repr_(self): """ Return the string representation. diff --git a/src/sage/repl/user_globals.py b/src/sage/repl/user_globals.py index 60eea5fe492..5ac5ddf9a9d 100644 --- a/src/sage/repl/user_globals.py +++ b/src/sage/repl/user_globals.py @@ -61,7 +61,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - user_globals = None @@ -80,7 +79,7 @@ def _check(): RuntimeError: the user-space globals dictionary has not been initialized... """ if user_globals is None: - raise RuntimeError("the user-space globals dictionary has not been initialized. " "Use initialize_globals() or set_globals() or use a different " "function which doesn't need these globals") + raise RuntimeError("the user-space globals dictionary has not been initialized. Use initialize_globals() or set_globals() or use a different function which doesn't need these globals") def get_globals(): diff --git a/src/sage/rings/algebraic_closure_finite_field.py b/src/sage/rings/algebraic_closure_finite_field.py index 3ef9ef0f296..4c7c837fa0d 100644 --- a/src/sage/rings/algebraic_closure_finite_field.py +++ b/src/sage/rings/algebraic_closure_finite_field.py @@ -53,6 +53,7 @@ - Vincent Delecroix (November 2013): additional methods """ + from sage.misc.abstract_method import abstract_method from sage.misc.fast_methods import WithEqualityById from sage.rings.finite_rings.finite_field_base import FiniteField diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 95f638ca11f..d5c4d0163d6 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -681,7 +681,7 @@ def __init__(self, parent, summands, simplify=True, convert=True): from sage.data_structures.mutable_poset import MutablePoset if not isinstance(summands, MutablePoset): - raise TypeError('Summands %s are not in a mutable poset as expected ' 'when creating an element of %s.' % (summands, parent)) + raise TypeError('Summands %s are not in a mutable poset as expected when creating an element of %s.' % (summands, parent)) if convert: from .misc import combine_exceptions @@ -1607,7 +1607,6 @@ def __pow__(self, exponent, precision=None): elif len(self.summands) == 1: element = next(self.summands.elements()) if isinstance(exponent, AsymptoticExpansion) and element.is_constant(): - return exponent.rpow(base=element.coefficient, precision=precision) try: return self.parent()._create_element_in_extension_(element**exponent, element.parent()) @@ -1752,9 +1751,9 @@ def __pow_number__(self, exponent, precision=None, check_convergence=False): if exponent.is_zero(): return self.parent().one() if exponent < 0: - raise ZeroDivisionError('Cannot take {} to the negative ' 'exponent {}.'.format(self, exponent)) + raise ZeroDivisionError('Cannot take {} to the negative exponent {}.'.format(self, exponent)) else: - raise ValueError('Possible division by zero, since sign of the exponent ' '{} cannot be determined.'.format(exponent)) + raise ValueError('Possible division by zero, since sign of the exponent {} cannot be determined.'.format(exponent)) elif len(self.summands) == 1: element = next(self.summands.elements()) @@ -2124,7 +2123,7 @@ def rpow(self, base, precision=None, locals=None): except (TypeError, ValueError) as e: from .misc import combine_exceptions - raise combine_exceptions(ValueError('Cannot construct the power of %s to the ' 'exponent %s in %s.' % (base, self, self.parent())), e) + raise combine_exceptions(ValueError('Cannot construct the power of %s to the exponent %s in %s.' % (base, self, self.parent())), e) # then: expand expr_o @@ -2202,7 +2201,7 @@ def _main_term_relative_error_(self, return_inverse_main_term=False): max_elem = tuple(self.summands.maximal_elements()) if len(max_elem) != 1: - raise ValueError('Cannot determine main term of {} since there ' 'are several maximal elements {}.'.format(self, ', '.join(str(e) for e in sorted(max_elem, key=str)))) + raise ValueError('Cannot determine main term of {} since there are several maximal elements {}.'.format(self, ', '.join(str(e) for e in sorted(max_elem, key=str)))) max_elem = max_elem[0] imax_elem = ~max_elem @@ -2521,10 +2520,10 @@ def subs(self, rules=None, domain=None, **kwds): if isinstance(rules, dict): for k, v in rules.items(): if not isinstance(k, str) and k not in gens: - raise TypeError('Cannot substitute %s in %s ' 'since it is neither an ' 'asymptotic expansion ' 'nor a string (but a %s).' % (k, self, type(k))) + raise TypeError('Cannot substitute %s in %s since it is neither an asymptotic expansion nor a string (but a %s).' % (k, self, type(k))) k = str(k) if k in locals and locals[k] != v: - raise ValueError('Cannot substitute in %s: ' 'duplicate key %s.' % (self, k)) + raise ValueError('Cannot substitute in %s: duplicate key %s.' % (self, k)) locals[k] = v elif rules is not None: raise TypeError('Substitution rules %s have to be a dictionary.' % (rules,)) @@ -2538,7 +2537,7 @@ def subs(self, rules=None, domain=None, **kwds): for k in locals: sk = str(k) if sk not in gens_str and not sk.startswith('_'): - raise ValueError('Cannot substitute %s in %s ' 'since it is not a generator of %s.' % (k, self, self.parent())) + raise ValueError('Cannot substitute %s in %s since it is not a generator of %s.' % (k, self, self.parent())) # determine 0 and 1 if domain is None and ('_zero_' not in locals or '_one_' not in locals): @@ -2560,7 +2559,7 @@ def subs(self, rules=None, domain=None, **kwds): from .misc import combine_exceptions rules = '{' + ', '.join('%s: %s' % (k, v) for k, v in sorted(locals.items(), key=lambda k: str(k[0])) if not k.startswith('_') and not any(k == sg and v is g for sg, g in zip(gens_str, gens))) + '}' - raise combine_exceptions(TypeError('Cannot apply the substitution rules %s on %s ' 'in %s.' % (rules, self, self.parent())), e) + raise combine_exceptions(TypeError('Cannot apply the substitution rules %s on %s in %s.' % (rules, self, self.parent())), e) def _substitute_(self, rules): r""" @@ -2729,7 +2728,7 @@ def compare_with_values(self, variable, function, values, rescaled=True, ring=RI expr = function vars = expr.variables() if len(vars) > 1: - raise NotImplementedError("expression {} has more than one " "variable".format(expr)) + raise NotImplementedError("expression {} has more than one variable".format(expr)) elif len(vars) == 1: v = vars[0] @@ -2845,7 +2844,7 @@ def plot_comparison(self, variable, function, values, rescaled=True, ring=RIF, r if isinstance(ring, sage.rings.abc.RealIntervalField): if not all(p[1].relative_diameter() <= relative_tolerance for p in points): - raise ValueError('Numerical noise is too high, the ' 'comparison is inaccurate') + raise ValueError('Numerical noise is too high, the comparison is inaccurate') # RIFs cannot be plotted, they need to be converted to RR # (see #15011). @@ -3050,7 +3049,7 @@ def factorial(self): P = cm.common_parent(self, S) return S.subs({var: P.coerce(self)}) - raise ValueError('Cannot build the factorial of {} since it is not ' 'univariate.'.format(self)) + raise ValueError('Cannot build the factorial of {} since it is not univariate.'.format(self)) def variable_names(self): r""" @@ -3882,7 +3881,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): if isinstance(data, (list, tuple)): if not all(isinstance(elem, GenericTerm) for elem in data): - raise TypeError('Not all list entries of %s ' 'are asymptotic terms, so cannot create an ' 'asymptotic expansion in %s.' % (data, self)) + raise TypeError('Not all list entries of %s are asymptotic terms, so cannot create an asymptotic expansion in %s.' % (data, self)) summands = AsymptoticRing._create_empty_summands_() summands.union_update(data) return self.element_class(self, summands, simplify=simplify, convert=convert) @@ -3926,7 +3925,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): raise combine_exceptions(ValueError('Polynomial %s is not in %s' % (data, self)), e) elif isinstance(P, (PowerSeriesRing_generic, LazyPowerSeriesRing)): - raise NotImplementedError('cannot convert %s from the %s to an asymptotic expansion ' 'in %s, since growths at other points than +oo are not yet ' 'supported' % (data, P, self)) + raise NotImplementedError('cannot convert %s from the %s to an asymptotic expansion in %s, since growths at other points than +oo are not yet supported' % (data, P, self)) # Delete lines above as soon as we can deal with growths # other than the that at going to +oo. from sage.rings.infinity import PlusInfinity @@ -4352,7 +4351,7 @@ def create_summand(self, type, data=None, **kwds): except KeyError: raise TypeError("Neither 'data' nor 'growth' are specified.") if type == 'exact' and kwds.get('coefficient') is None: - raise TypeError("Cannot create exact term: only 'growth' " "but no 'coefficient' specified.") + raise TypeError("Cannot create exact term: only 'growth' but no 'coefficient' specified.") try: return self(TM(data, **kwds), simplify=False, convert=False) diff --git a/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py b/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py index 7f4d1f7bca2..7ecf5cbe96e 100644 --- a/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +++ b/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py @@ -1750,7 +1750,7 @@ def asymptotics_smooth(self, p, alpha, N, asy_var, coordinate=None, numerical=0, # If p is a tuple of rationals, then compute with it directly. # Otherwise, compute symbolically and plug in p at the end. - if vector(p.values()) in QQ ** d: + if vector(p.values()) in QQ**d: P = p else: sP = [var('p' + str(j)) for j in range(d)] @@ -2089,7 +2089,7 @@ def asymptotics_multiple(self, p, alpha, N, asy_var, coordinate=None, numerical= # Case n < d. # If P is a tuple of rationals, then compute with it directly. # Otherwise, compute symbolically and plug in P at the end. - if vector(P.values()) not in QQ ** d: + if vector(P.values()) not in QQ**d: sP = [var('p' + str(j)) for j in range(d)] P = {X[j]: sP[j] for j in range(d)} p = {sP[j]: p[X[j]] for j in range(d)} @@ -2904,7 +2904,7 @@ def __classcall_private__(cls, denominator_ring, numerator_ring=None, category=N if numerator_ring is None: numerator_ring = denominator_ring if not numerator_ring.has_coerce_map_from(denominator_ring): - raise ValueError('numerator ring {} has no coercion map from the ' 'denominator ring {}'.format(numerator_ring, denominator_ring)) + raise ValueError('numerator ring {} has no coercion map from the denominator ring {}'.format(numerator_ring, denominator_ring)) category = Rings().Commutative().or_subcategory(category) return super().__classcall__(cls, denominator_ring, numerator_ring, category) @@ -2938,7 +2938,7 @@ def _repr_(self) -> str: Ring of fractions with factored denominator over Multivariate Polynomial Ring in X, Y over Integer Ring """ - return "Ring of fractions with factored denominator " "over {!r}".format(self.base()) + return "Ring of fractions with factored denominator over {!r}".format(self.base()) def base_ring(self): r""" @@ -2983,14 +2983,14 @@ def _element_constructor_(self, *args, **kwargs): reduce = kwargs.pop('reduce', None) if kwargs: - raise ValueError('Unknown keyword arguments ' '%s given' % (kwargs,)) + raise ValueError('Unknown keyword arguments %s given' % (kwargs,)) # process arguments if len(args) > 2: raise ValueError('too many arguments given') elif not args: - raise ValueError('No argument given. ' 'We are in serious troubles...') + raise ValueError('No argument given. We are in serious troubles...') # At this point we have one or two input arguments. @@ -3015,7 +3015,7 @@ def _element_constructor_(self, *args, **kwargs): try: denominator_factored = sorted((R(d[0]), NN(d[1])) for d in denominator_factored) except TypeError: - raise TypeError('factored denominator is not well-formed ' 'or of wrong type') + raise TypeError('factored denominator is not well-formed or of wrong type') # From now on we only have one input argument; # it's called x and has parent P. diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index d3074859174..c6ffe10874d 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -878,13 +878,13 @@ def _log_(self, base=None): log_factor = self.log_factor(base=base) if not log_factor: - raise ArithmeticError('%s is zero, ' 'which is not contained in %s.' % (log_string(self, base), self.parent())) + raise ArithmeticError('%s is zero, which is not contained in %s.' % (log_string(self, base), self.parent())) if len(log_factor) != 1: - raise ArithmeticError('Calculating %s results in a sum, ' 'which is not contained in %s.' % (log_string(self, base), self.parent())) + raise ArithmeticError('Calculating %s results in a sum, which is not contained in %s.' % (log_string(self, base), self.parent())) g, c = log_factor[0] if c != 1: - raise ArithmeticError('When calculating %s a factor %s != 1 ' 'appeared, which is not contained in %s.' % (log_string(self, base), c, self.parent())) + raise ArithmeticError('When calculating %s a factor %s != 1 appeared, which is not contained in %s.' % (log_string(self, base), c, self.parent())) return g @@ -959,7 +959,7 @@ def _log_factor_(self, base=None, locals=None): continue from .misc import log_string - raise ArithmeticError('Cannot build %s since %s ' 'is not in %s.' % (log_string(self, base), g, self.parent())) + raise ArithmeticError('Cannot build %s since %s is not in %s.' % (log_string(self, base), g, self.parent())) return log_factor @@ -1043,7 +1043,7 @@ def _rpow_(self, base): Asymptotic Ring over Symbolic Constants Subring """ if base == 0: - raise ValueError('%s is not an allowed base for calculating the ' 'power to %s.' % (base, self)) + raise ValueError('%s is not an allowed base for calculating the power to %s.' % (base, self)) var = str(self) @@ -1255,7 +1255,7 @@ def __invert__(self): sage: ~P.an_element() x^(-1) """ - raise NotImplementedError('Inversion of %s not implemented ' '(in this abstract method).' % (self,)) + raise NotImplementedError('Inversion of %s not implemented (in this abstract method).' % (self,)) _richcmp_ = richcmp_by_eq_and_lt("_eq_", "_lt_") @@ -1399,7 +1399,7 @@ def _log_factor_(self, base=None, locals=None): NotImplementedError: Cannot determine logarithmized factorization of GenericGrowthElement(1/2) in abstract base class. """ - raise NotImplementedError('Cannot determine logarithmized factorization ' 'of %s in abstract base class.' % (self,)) + raise NotImplementedError('Cannot determine logarithmized factorization of %s in abstract base class.' % (self,)) rpow = _rpow_ @@ -1468,7 +1468,7 @@ def _substitute_(self, rules): """ from .misc import substitute_raise_exception - substitute_raise_exception(self, TypeError('Cannot substitute in the abstract ' 'base class %s.' % (self.parent(),))) + substitute_raise_exception(self, TypeError('Cannot substitute in the abstract base class %s.' % (self.parent(),))) def variable_names(self): r""" @@ -1536,7 +1536,7 @@ def _singularity_analysis_(self, var, zeta, precision): NotImplementedError: singularity analysis of GenericGrowthElement(2) not implemented """ - raise NotImplementedError('singularity analysis of {} ' 'not implemented '.format(self)) + raise NotImplementedError('singularity analysis of {} not implemented '.format(self)) def _find_minimum_(self, valid_from): r""" @@ -2107,9 +2107,9 @@ def _element_constructor_(self, data, raw_element=None): elif isinstance(data, PartialConversionElement): if data.growth_group is self: - raise PartialConversionValueError(data, 'no conversion of {}: this was already unsuccessful ' 'earlier'.format(data)) + raise PartialConversionValueError(data, 'no conversion of {}: this was already unsuccessful earlier'.format(data)) if not data.is_compatible(self): - raise TypeError('cannot (partially) convert {} because its ' 'growth group {} is not compatible to this ' 'growth group {}'.format(data.raw_element, data.growth_group, self)) + raise TypeError('cannot (partially) convert {} because its growth group {} is not compatible to this growth group {}'.format(data.raw_element, data.growth_group, self)) raw_element = data.raw_element else: @@ -2118,7 +2118,7 @@ def _element_constructor_(self, data, raw_element=None): if raw_element is None: raise ValueError('%s is not in %s.' % (data, self)) elif not isinstance(data, int) or data != 0: - raise ValueError('input is ambiguous: ' '%s as well as raw_element=%s ' 'are specified' % (data, raw_element)) + raise ValueError('input is ambiguous: %s as well as raw_element=%s are specified' % (data, raw_element)) return self.element_class(self, raw_element) @@ -3166,7 +3166,7 @@ def _singularity_analysis_(self, var, zeta, precision): return asymptotic_expansions.SingularityAnalysis(var=var, zeta=zeta, alpha=self.exponent, beta=0, delta=0, precision=precision) if self.parent().gens_logarithmic(): if self.exponent not in ZZ: - raise NotImplementedError('singularity analysis of {} not implemented ' 'since exponent {} is not an integer'.format(self, self.exponent)) + raise NotImplementedError('singularity analysis of {} not implemented since exponent {} is not an integer'.format(self, self.exponent)) from sage.rings.asymptotic.asymptotic_expansion_generators import asymptotic_expansions return asymptotic_expansions.SingularityAnalysis(var=var, zeta=zeta, alpha=0, beta=ZZ(self.exponent), delta=0, precision=precision, normalized=False) @@ -4164,7 +4164,7 @@ def __init__(self, base, *args, **kwds): super().__init__(base, *args, **kwds) if isinstance(base, SymbolicRing) and not self._an_element_base_() > 0: - warn("When using the Exponential {}, make " "assumptions on the used symbolic elements.\n" "In particular, use something like " "'assume(SR.an_element() > 0)' to make " "coercions work properly.".format(self), RuntimeWarning, 2) + warn("When using the Exponential {}, make assumptions on the used symbolic elements.\nIn particular, use something like 'assume(SR.an_element() > 0)' to make coercions work properly.".format(self), RuntimeWarning, 2) def _repr_short_(self): r""" @@ -4405,7 +4405,7 @@ def _split_raw_element_(base): direction = base / size return size, direction - raise ValueError('cannot split {} ({}) into ' 'abs and arg'.format(base, parent(base))) + raise ValueError('cannot split {} ({}) into abs and arg'.format(base, parent(base))) def _an_element_(self): r""" @@ -5185,11 +5185,11 @@ def has_r_property(s, properties, invert=False) -> tuple[str, bool]: for factor in sfactors: if '^' not in factor: - raise ValueError("'{}' is not a valid substring of '{}' describing " "a growth group.".format(factor, specification)) + raise ValueError("'{}' is not a valid substring of '{}' describing a growth group.".format(factor, specification)) split = split_str_by_op(factor, '^') if len(split) != 2: - raise ValueError("'{}' is an ambiguous substring of a growth group " "description of '{}'. Use parentheses to make it " "unique.".format(factor, ' * '.join(sfactors))) + raise ValueError("'{}' is an ambiguous substring of a growth group description of '{}'. Use parentheses to make it unique.".format(factor, ' * '.join(sfactors))) b, e = split b = remove_parentheses(b) @@ -5201,7 +5201,7 @@ def has_r_property(s, properties, invert=False) -> tuple[str, bool]: e, r_E_only_imaginary_group = has_r_property(e, ['*I', '* I']) E_only_imaginary_group = l_E_only_imaginary_group or r_E_only_imaginary_group if E_only_imaginary_group and extend_E_by_non_growth_group: - raise ValueError("'{}' is not a valid substring of '{}' describing " "a growth group.".format(factor, specification)) + raise ValueError("'{}' is not a valid substring of '{}' describing a growth group.".format(factor, specification)) try: B = repr_short_to_parent(b) @@ -5219,7 +5219,7 @@ def has_r_property(s, properties, invert=False) -> tuple[str, bool]: if B is None and E is None: from .misc import combine_exceptions - raise combine_exceptions(ValueError("'{}' is not a valid substring of {} describing " "a growth group.".format(factor, ' * '.join(sfactors))), exc_b, exc_e) + raise combine_exceptions(ValueError("'{}' is not a valid substring of {} describing a growth group.".format(factor, ' * '.join(sfactors))), exc_b, exc_e) elif B is None and E is not None: if E_only_imaginary_group: E = ImaginaryGroup(E) @@ -5227,7 +5227,7 @@ def has_r_property(s, properties, invert=False) -> tuple[str, bool]: elif B is not None and E is None: factors.append(GrowthGroupFactor(cls=ExponentialGrowthGroup, base=B, var=e, extend_by_non_growth_group=extend_B_by_non_growth_group)) else: - raise ValueError("'{}' is an ambiguous substring of a growth group " "description of '{}'.".format(factor, ' * '.join(factors))) + raise ValueError("'{}' is an ambiguous substring of a growth group description of '{}'.".format(factor, ' * '.join(factors))) return tuple(factors), kwds diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 7b608e34dff..fbb71c8da31 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -229,7 +229,7 @@ def create_object(self, version, args, **kwds): # check whether variables are pairwise disjoint for u, w in product(iter(v for v, _ in vgs), repeat=2): if u != w and not set(u).isdisjoint(set(w)): - raise ValueError('The growth groups %s need to have pairwise ' 'disjoint or equal variables.' % (growth_groups,)) + raise ValueError('The growth groups %s need to have pairwise disjoint or equal variables.' % (growth_groups,)) # build Cartesian products u_groups = list() @@ -569,9 +569,9 @@ def get_factors(data): try: element, todo = e.element.split() except NotImplementedError as nie: - raise combine_exceptions(ValueError('cannot split {}: no splitting ' 'implemented'.format(e.element)), nie) + raise combine_exceptions(ValueError('cannot split {}: no splitting implemented'.format(e.element)), nie) except ValueError as ve: - raise combine_exceptions(ValueError('cannot split {} after failed ' 'conversion into element of ' '{}'.format(e.element, factor)), ve) + raise combine_exceptions(ValueError('cannot split {} after failed conversion into element of {}'.format(e.element, factor)), ve) assert todo is not None result.append((factor, element)) data = todo @@ -751,7 +751,7 @@ def subfactors(F): from sage.structure.coerce_exceptions import CoercionException - raise CoercionException('Cannot construct the pushout of %s and %s: The factors ' 'with variables %s are not overlapping, ' 'no common parent was found, and ' 'splitting the factors was unsuccessful.' % (self, other, var)) + raise CoercionException('Cannot construct the pushout of %s and %s: The factors with variables %s are not overlapping, no common parent was found, and splitting the factors was unsuccessful.' % (self, other, var)) # A wrapper around an iterator that stores additional intermediate data. # This deviates slightly from the iterator protocol: @@ -856,7 +856,6 @@ def variable_names(self): return tuple(v for v, _ in groupby(vars)) class Element(CartesianProductPoset.Element): - from .growth_group import _is_lt_one_ is_lt_one = _is_lt_one_ @@ -1244,14 +1243,14 @@ def _singularity_analysis_(self, var, zeta, precision): a, b = factors if all(isinstance(f.parent(), MonomialGrowthGroup) for f in factors) and a.parent().gens_monomial() and b.parent().gens_logarithmic() and a.parent().variable_name() == b.parent().variable_name(): if b.exponent not in ZZ: - raise NotImplementedError('singularity analysis of {} not implemented ' 'since exponent {} of {} is not an integer'.format(self, b.exponent, b.parent().gen())) + raise NotImplementedError('singularity analysis of {} not implemented since exponent {} of {} is not an integer'.format(self, b.exponent, b.parent().gen())) from sage.rings.asymptotic.asymptotic_expansion_generators import asymptotic_expansions return asymptotic_expansions.SingularityAnalysis(var=var, zeta=zeta, alpha=a.exponent, beta=ZZ(b.exponent), delta=0, precision=precision, normalized=False) raise NotImplementedError('singularity analysis of {} not implemented'.format(self)) else: - raise NotImplementedError('singularity analysis of {} not yet implemented ' 'since it has more than two factors'.format(self)) + raise NotImplementedError('singularity analysis of {} not yet implemented since it has more than two factors'.format(self)) def variable_names(self): r""" diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 5201b3b7916..1b629206a5b 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -807,7 +807,7 @@ def __init__(self, asymptotic_ring=None, var=None, exact_part=0): if var is None: var = ', '.join(str(g) for g in asymptotic_ring.gens()) - message = 'got {}\n'.format(('{} + '.format(exact_part) if exact_part else '') + 'O(0)') + 'The error term O(0) ' 'means 0 for sufficiently large {}.'.format(var) + message = 'got {}\n'.format(('{} + '.format(exact_part) if exact_part else '') + 'O(0)') + 'The error term O(0) means 0 for sufficiently large {}.'.format(var) if asymptotic_ring is not None and isinstance(exact_part, int) and exact_part == 0: exact_part = asymptotic_ring.zero() @@ -876,7 +876,7 @@ def __init__(self, asymptotic_ring=None, var=None, exact_part=0): if var is None: var = ', '.join(str(g) for g in asymptotic_ring.gens()) - message = 'got {}\n'.format(('{} + '.format(exact_part) if exact_part else '') + 'B(0)') + 'The error term B(0) ' 'means 0 for sufficiently large {}.'.format(var) + message = 'got {}\n'.format(('{} + '.format(exact_part) if exact_part else '') + 'B(0)') + 'The error term B(0) means 0 for sufficiently large {}.'.format(var) if asymptotic_ring is not None and isinstance(exact_part, int) and exact_part == 0: exact_part = asymptotic_ring.zero() diff --git a/src/sage/rings/asymptotic/term_monoid.py b/src/sage/rings/asymptotic/term_monoid.py index ee97ff906fc..0c896281f1d 100644 --- a/src/sage/rings/asymptotic/term_monoid.py +++ b/src/sage/rings/asymptotic/term_monoid.py @@ -479,7 +479,7 @@ def __invert__(self): NotImplementedError: Inversion of Generic Term with growth x^2 not implemented (in this abstract method). """ - raise NotImplementedError('Inversion of %s not implemented ' '(in this abstract method).' % (self,)) + raise NotImplementedError('Inversion of %s not implemented (in this abstract method).' % (self,)) def __pow__(self, exponent): r""" @@ -509,7 +509,7 @@ def __pow__(self, exponent): NotImplementedError: Taking powers of Generic Term with growth z not implemented (in this abstract method). """ - raise NotImplementedError('Taking powers of %s not implemented ' '(in this abstract method).' % (self,)) + raise NotImplementedError('Taking powers of %s not implemented (in this abstract method).' % (self,)) def _calculate_pow_test_zero_(self, exponent): r""" @@ -840,7 +840,7 @@ def log_term(self, base=None, locals=None): :meth:`ExactTerm.log_term`, :meth:`OTerm.log_term`. """ - raise NotImplementedError('This method is not implemented in this ' 'abstract base class.') + raise NotImplementedError('This method is not implemented in this abstract base class.') def _log_growth_(self, base=None, locals=None): r""" @@ -1113,7 +1113,7 @@ def is_little_o_of_one(self): is o(1) in the abstract base class TermWithCoefficient Monoid x^ZZ with coefficients in Rational Field. """ - raise NotImplementedError('Cannot check whether %s is o(1) in the ' 'abstract base class %s.' % (self, self.parent())) + raise NotImplementedError('Cannot check whether %s is o(1) in the abstract base class %s.' % (self, self.parent())) def rpow(self, base): r""" @@ -1139,7 +1139,7 @@ def rpow(self, base): Generic Term with growth x*log(x) in the abstract base class GenericTerm Monoid x^ZZ * log(x)^ZZ with (implicit) coefficients in Rational Field. """ - raise NotImplementedError('Cannot take %s to the exponent %s in the ' 'abstract base class %s.' % (base, self, self.parent())) + raise NotImplementedError('Cannot take %s to the exponent %s in the abstract base class %s.' % (base, self, self.parent())) def _repr_(self): r""" @@ -1214,7 +1214,7 @@ def _substitute_(self, rules): """ from .misc import substitute_raise_exception - substitute_raise_exception(self, TypeError('Cannot substitute in the abstract ' 'base class %s.' % (self.parent(),))) + substitute_raise_exception(self, TypeError('Cannot substitute in the abstract base class %s.' % (self.parent(),))) def variable_names(self): r""" @@ -1292,7 +1292,7 @@ def _singularity_analysis_(self, var, zeta, precision): NotImplementedError: singularity analysis of Generic Term with growth x not implemented """ - raise NotImplementedError('singularity analysis of {} ' 'not implemented '.format(self)) + raise NotImplementedError('singularity analysis of {} not implemented '.format(self)) class GenericTermMonoid(UniqueRepresentation, Parent, WithLocals): @@ -1756,7 +1756,7 @@ def _element_constructor_(self, data, **kwds): if isinstance(data, GenericTerm): return self.from_construction(data.construction(), **kwds) if isinstance(data, int) and data == 0: - raise ValueError('No input specified. Cannot continue ' 'creating an element of %s.' % (self,)) + raise ValueError('No input specified. Cannot continue creating an element of %s.' % (self,)) from .misc import combine_exceptions @@ -1896,7 +1896,7 @@ def _validate_coefficient_or_error_(self, kwds_construction): growth = kwds_construction['growth'] from .misc import combine_exceptions - raise combine_exceptions(ValueError(f'Cannot create {element_name}({growth}) ' f'since given coefficient {coefficient} ' f'is not valid in {self}.'), e) + raise combine_exceptions(ValueError(f'Cannot create {element_name}({growth}) since given coefficient {coefficient} is not valid in {self}.'), e) if 'coefficient' in kwds_construction: kwds_construction['coefficient'] = coefficient @@ -1959,7 +1959,7 @@ def _convert_construction_(self, kwds_construction): """ coefficient = kwds_construction.pop('coefficient', None) if coefficient is not None and coefficient != self.coefficient_ring.one(): - raise ValueError('Coefficient %s is not 1, but %s does not ' 'support coefficients.' % (coefficient, self)) + raise ValueError('Coefficient %s is not 1, but %s does not support coefficients.' % (coefficient, self)) if 'parent' in kwds_construction and isinstance(kwds_construction['parent'], BTermMonoid): try: @@ -2144,7 +2144,7 @@ def _split_growth_and_coefficient_(self, data): except (ValueError, TypeError): pass - raise ValueError('Factor %s of %s is neither a coefficient (in %s) ' 'nor growth (in %s).' % (f, data, coefficient_ring, growth_group)) + raise ValueError('Factor %s of %s is neither a coefficient (in %s) nor growth (in %s).' % (f, data, coefficient_ring, growth_group)) from sage.misc.misc_c import prod @@ -2716,7 +2716,7 @@ def _factorial_(self): since it has growth != 1. """ if not self.growth.is_one(): - raise ValueError('Cannot build the factorial of {} since it has growth ' '!= 1.'.format(self)) + raise ValueError('Cannot build the factorial of {} since it has growth != 1.'.format(self)) return self @@ -3199,7 +3199,7 @@ def _calculate_pow_(self, exponent): except (TypeError, ValueError, ZeroDivisionError) as e: from .misc import combine_exceptions - raise combine_exceptions(ArithmeticError('Cannot take %s to the exponent %s in %s since its ' 'coefficient %s cannot be taken to this exponent.' % (self, exponent, self.parent(), self.coefficient)), e) + raise combine_exceptions(ArithmeticError('Cannot take %s to the exponent %s in %s since its coefficient %s cannot be taken to this exponent.' % (self, exponent, self.parent(), self.coefficient)), e) return super()._calculate_pow_(exponent, new_coefficient=c) def _log_coefficient_(self, base=None, locals=None): @@ -3403,7 +3403,7 @@ def _validate_coefficient_or_error_(self, kwds_construction): if coefficient is None: element_name = self.Element.__name__ growth = kwds_construction['growth'] - raise ValueError(f'Cannot create {element_name}({growth}) ' f'since no coefficient is given.') + raise ValueError(f'Cannot create {element_name}({growth}) since no coefficient is given.') super()._validate_coefficient_or_error_(kwds_construction) def _default_kwds_construction_(self): @@ -3680,7 +3680,7 @@ def __invert__(self): try: c = ~self.coefficient except ZeroDivisionError: - raise ZeroDivisionError('Cannot invert %s since its coefficient %s ' 'cannot be inverted.' % (self, self.coefficient)) + raise ZeroDivisionError('Cannot invert %s since its coefficient %s cannot be inverted.' % (self, self.coefficient)) g = ~self.growth return self.parent()._create_element_in_extension_(g, c) @@ -4060,7 +4060,7 @@ def _factorial_(self): since it has growth != 1. """ if not self.growth.is_one(): - raise ValueError('Cannot build the factorial of {} since it has growth ' '!= 1.'.format(self)) + raise ValueError('Cannot build the factorial of {} since it has growth != 1.'.format(self)) from sage.functions.other import factorial @@ -4397,8 +4397,8 @@ def _repr_(self, latex=False): B(4*x^2, x >= 10, y >= 15) """ if latex: - valid_from_string = ', '.join(fr'{variable} \ge {value}' for variable, value in self.valid_from.items()) - return fr'B_{{{valid_from_string}}}\left({self._repr_product_(latex=True)}\right)' + valid_from_string = ', '.join(rf'{variable} \ge {value}' for variable, value in self.valid_from.items()) + return rf'B_{{{valid_from_string}}}\left({self._repr_product_(latex=True)}\right)' valid_from_string = ''.join(f', {variable} >= {value}' for variable, value in self.valid_from.items()) return f'B({self._repr_product_()}{valid_from_string})' @@ -4615,7 +4615,7 @@ def _repr_(self): sage: TermMonoid('B', G, QQ)._repr_() 'B-Term Monoid x^ZZ with coefficients in Rational Field' """ - return f'B-Term Monoid {self.growth_group._repr_short_()} with ' f'coefficients in {self.coefficient_ring}' + return f'B-Term Monoid {self.growth_group._repr_short_()} with coefficients in {self.coefficient_ring}' def _default_kwds_construction_(self): r""" @@ -5029,10 +5029,10 @@ def create_key_and_extra_args(self, term_monoid, growth_group=None, coefficient_ elif term_monoid == 'B': term_class = self.BTermMonoid else: - raise ValueError("Term specification '%s' has to be either 'exact', 'O', 'B' " "or an instance of an existing term." % term_monoid) + raise ValueError("Term specification '%s' has to be either 'exact', 'O', 'B' or an instance of an existing term." % term_monoid) if asymptotic_ring is not None and (growth_group is not None or coefficient_ring is not None): - raise ValueError("Input ambiguous: asymptotic ring %s as well as " "growth group %s or coefficient ring %s are given." % (asymptotic_ring, growth_group, coefficient_ring)) + raise ValueError("Input ambiguous: asymptotic ring %s as well as growth group %s or coefficient ring %s are given." % (asymptotic_ring, growth_group, coefficient_ring)) if asymptotic_ring is not None: growth_group = asymptotic_ring.growth_group @@ -5046,10 +5046,10 @@ def create_key_and_extra_args(self, term_monoid, growth_group=None, coefficient_ growth_group = GrowthGroup(growth_group) else: - raise ValueError('{} has to be an asymptotic growth ' 'group'.format(growth_group)) + raise ValueError('{} has to be an asymptotic growth group'.format(growth_group)) if coefficient_ring is None: - raise ValueError("A coefficient ring has to be specified to " "create a term monoid of type '%s'" % (term_monoid,)) + raise ValueError("A coefficient ring has to be specified to create a term monoid of type '%s'" % (term_monoid,)) return (term_class, growth_group, coefficient_ring), kwds diff --git a/src/sage/rings/big_oh.py b/src/sage/rings/big_oh.py index 445c25032b0..cb8fd930327 100644 --- a/src/sage/rings/big_oh.py +++ b/src/sage/rings/big_oh.py @@ -168,9 +168,9 @@ def O(*x, **kwds): if isinstance(x, Polynomial): if x.parent().ngens() != 1: - raise NotImplementedError("completion only currently defined " "for univariate polynomials") + raise NotImplementedError("completion only currently defined for univariate polynomials") if not x.is_monomial(): - raise NotImplementedError("completion only currently defined " "for the maximal ideal (x)") + raise NotImplementedError("completion only currently defined for the maximal ideal (x)") if isinstance(x, (int, Integer, Rational)): # p-adic number diff --git a/src/sage/rings/continued_fraction.py b/src/sage/rings/continued_fraction.py index 7b50f9eda51..1721188fcbc 100644 --- a/src/sage/rings/continued_fraction.py +++ b/src/sage/rings/continued_fraction.py @@ -2103,11 +2103,11 @@ def __init__(self, w, value=None, check=True): try: k = Integer(w[i]) except (TypeError, ValueError): - raise ValueError("the sequence must consist of" " integers") + raise ValueError("the sequence must consist of integers") self.quotient = self._Integer_quotient if not k and i: - raise ValueError("only the first partial quotient can" " be null") + raise ValueError("only the first partial quotient can be null") if check and value is not None: from sage.rings.real_mpfi import RealIntervalField @@ -2677,7 +2677,7 @@ def continued_fraction(x, value=None): return ContinuedFraction_infinite(x, value) if isinstance(x, Word_class): - raise ValueError("word with unknown length cannot be converted " "to continued fractions") + raise ValueError("word with unknown length cannot be converted to continued fractions") # input for numbers # TODO: the approach used below might be not what the user expects as we diff --git a/src/sage/rings/derivation.py b/src/sage/rings/derivation.py index 93263390c8a..8f4365e0cc1 100644 --- a/src/sage/rings/derivation.py +++ b/src/sage/rings/derivation.py @@ -274,7 +274,7 @@ def __init__(self, domain, codomain, twist=None): defining_morphism = codomain * codomain.domain().coerce_map_from(domain) codomain = defining_morphism.codomain() else: - raise TypeError("the codomain must be an algebra over the domain" " or a morphism with the correct domain") + raise TypeError("the codomain must be an algebra over the domain or a morphism with the correct domain") if twist is not None: if not (isinstance(twist, Map) and twist.category_for().is_subcategory(Rings())): @@ -282,12 +282,12 @@ def __init__(self, domain, codomain, twist=None): if twist.domain() is not domain: map = twist.domain().coerce_map_from(domain) if map is None: - raise TypeError("the domain of the derivation must coerce" " to the domain of the twisting homomorphism") + raise TypeError("the domain of the derivation must coerce to the domain of the twisting homomorphism") twist = twist * map if twist.codomain() is not codomain: map = codomain.coerce_map_from(twist.codomain()) if map is None: - raise TypeError("the codomain of the twisting homomorphism" " must coerce to the codomain of the derivation") + raise TypeError("the codomain of the twisting homomorphism must coerce to the codomain of the derivation") twist = map * twist # We check if the twisting morphism is the defining morphism try: @@ -363,7 +363,7 @@ def __init__(self, domain, codomain, twist=None): modulus = domain.modulus() for der in self._base_derivation.gens(): if der(modulus) != 0: - raise NotImplementedError("derivations over quotient rings" " are not fully supported") + raise NotImplementedError("derivations over quotient rings are not fully supported") self.Element = RingDerivationWithoutTwist_quotient try: self._gens = self._base_derivation.gens() @@ -379,7 +379,7 @@ def __init__(self, domain, codomain, twist=None): elif isinstance(domain, QuotientRing_generic): self._base_derivation = RingDerivationModule(domain.cover_ring(), defining_morphism) if any(der(modulus) != 0 for modulus in domain.defining_ideal().gens() for der in self._base_derivation.gens()): - raise NotImplementedError("derivations over quotient rings" " are not fully supported") + raise NotImplementedError("derivations over quotient rings are not fully supported") self.Element = RingDerivationWithoutTwist_quotient try: self._gens = self._base_derivation.gens() @@ -745,7 +745,7 @@ def ring_of_constants(self): Rational Field """ if not self._constants[1]: - raise NotImplementedError("the computation of the ring of constants" " is not implemented for this derivation module") + raise NotImplementedError("the computation of the ring of constants is not implemented for this derivation module") return self._constants[0] def random_element(self, *args, **kwds): diff --git a/src/sage/rings/finite_rings/finite_field_pari_ffelt.py b/src/sage/rings/finite_rings/finite_field_pari_ffelt.py index b492083ea17..fb961b1f0a5 100644 --- a/src/sage/rings/finite_rings/finite_field_pari_ffelt.py +++ b/src/sage/rings/finite_rings/finite_field_pari_ffelt.py @@ -16,7 +16,6 @@ # http://www.gnu.org/licenses/ # ***************************************************************************** - from cypari2.handle_error import PariError from sage.rings.finite_rings.element_pari_ffelt import FiniteFieldElement_pari_ffelt diff --git a/src/sage/rings/finite_rings/integer_mod_ring.py b/src/sage/rings/finite_rings/integer_mod_ring.py index 071cf6e4fa6..380366af415 100644 --- a/src/sage/rings/finite_rings/integer_mod_ring.py +++ b/src/sage/rings/finite_rings/integer_mod_ring.py @@ -61,7 +61,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - import sage.misc.prandom as random from sage.arith.misc import factor @@ -1942,7 +1941,7 @@ def _roots_univariate_polynomial(self, f, ring=None, multiplicities=True, algori if multiplicities: if deg < 0 or not self.is_field(): - raise NotImplementedError("root finding with multiplicities for this polynomial not" " implemented (try the multiplicities=False option)") + raise NotImplementedError("root finding with multiplicities for this polynomial not implemented (try the multiplicities=False option)") # Roots of non-zero polynomial over finite fields by factorization return f.change_ring(f.base_ring().field()).roots(multiplicities=multiplicities) diff --git a/src/sage/rings/fraction_field.py b/src/sage/rings/fraction_field.py index 779a17d39e2..b9a9bd201e5 100644 --- a/src/sage/rings/fraction_field.py +++ b/src/sage/rings/fraction_field.py @@ -731,7 +731,7 @@ def _element_constructor_(self, x, y=None, coerce=True): if isinstance(x, PowerSeries): from sage.misc.superseded import deprecation - deprecation(39485, "Previously conversion from power series to rational function field truncates " "instead of gives an approximation. Use .truncate() to recover the old behavior") + deprecation(39485, "Previously conversion from power series to rational function field truncates instead of gives an approximation. Use .truncate() to recover the old behavior") x = x.laurent_series() if isinstance(x, LaurentSeries): from sage.rings.infinity import infinity diff --git a/src/sage/rings/function_field/drinfeld_modules/action.py b/src/sage/rings/function_field/drinfeld_modules/action.py index 41ca076702a..695b6ece27b 100644 --- a/src/sage/rings/function_field/drinfeld_modules/action.py +++ b/src/sage/rings/function_field/drinfeld_modules/action.py @@ -156,7 +156,7 @@ def _latex_(self) -> str: sage: latex(action) \text{Action{ }on{ }}\Bold{F}_{11^{2}}\text{{ }induced{ }by{ }}\phi: T \mapsto τ^{3} + z """ - return f'\\text{{Action{{ }}on{{ }}}}' f'{latex(self._base)}\\text{{{{ }}' f'induced{{ }}by{{ }}}}{latex(self._drinfeld_module)}' + return f'\\text{{Action{{ }}on{{ }}}}{latex(self._base)}\\text{{{{ }}induced{{ }}by{{ }}}}{latex(self._drinfeld_module)}' def _repr_(self) -> str: r""" @@ -174,7 +174,7 @@ def _repr_(self) -> str: sage: action Action on Finite Field in z of size 11^2 induced by Drinfeld module defined by T |--> τ^3 + z """ - return f'Action on {self._base} induced by ' f'{self._drinfeld_module}' + return f'Action on {self._base} induced by {self._drinfeld_module}' def drinfeld_module(self): r""" diff --git a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py index 2579a2afad0..f272e3d5732 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -547,7 +547,7 @@ def __classcall_private__(cls, function_ring, gen, A_field=None, name='τ'): # here and in the category constructor, which is not ideal. # Check domain is Fq[T] if not isinstance(function_ring, PolynomialRing_generic): - raise NotImplementedError('function ring must be a polynomial ' 'ring') + raise NotImplementedError('function ring must be a polynomial ring') function_ring_base = function_ring.base_ring() if not function_ring_base.is_field() or not function_ring_base.is_finite(): raise TypeError('function ring base must be a finite field') @@ -569,7 +569,7 @@ def __classcall_private__(cls, function_ring, gen, A_field=None, name='τ'): except AttributeError: pass else: - raise TypeError('generator must be list of coefficients or Ore ' 'polynomial') + raise TypeError('generator must be list of coefficients or Ore polynomial') # The coefficients are in a base field that has coercion from Fq: if not (hasattr(A_field, 'has_coerce_map_from') and A_field.has_coerce_map_from(function_ring.base_ring())): raise ValueError('function ring base must coerce into base field') @@ -767,7 +767,7 @@ def _latex_(self) -> str: """ if self.get_custom_name() is not None: return latex_variable_name(self.get_custom_name()) - return f'\\phi: {latex(self._function_ring.gen())} \\mapsto ' f'{latex(self._gen)}' + return f'\\phi: {latex(self._function_ring.gen())} \\mapsto {latex(self._gen)}' def _repr_(self) -> str: r""" @@ -783,7 +783,7 @@ def _repr_(self) -> str: sage: phi Drinfeld module defined by T |--> z12^5*τ^2 + z12^3*τ + 2*z12^11 + 2*z12^10 + z12^9 + 3*z12^8 + z12^7 + 2*z12^5 + 2*z12^4 + 3*z12^3 + z12^2 + 2*z12 """ - return f'Drinfeld module defined by {self._function_ring.gen()} ' f'|--> {self._gen}' + return f'Drinfeld module defined by {self._function_ring.gen()} |--> {self._gen}' def _test_category(self, **options) -> None: """ @@ -1271,7 +1271,7 @@ def height(self): """ try: if self.characteristic().is_zero(): - raise ValueError('height is only defined for prime ' 'function field characteristic') + raise ValueError('height is only defined for prime function field characteristic') else: p = self.characteristic() return Integer(self(p).valuation() // p.degree()) @@ -1671,12 +1671,12 @@ def j_invariant(self, parameter=None, check=True): q = self._Fq.order() if parameter is None: if r != 2: - raise TypeError("parameter must not be None " "if the rank is greater than 2") + raise TypeError("parameter must not be None if the rank is greater than 2") return self._gen[1] ** (q + 1) / self._gen[2] if parameter in ZZ: parameter = ZZ(parameter) if parameter <= 0 or parameter >= r: - raise ValueError("integer parameter must be >= 1 and < the " f"rank (={r})") + raise ValueError(f"integer parameter must be >= 1 and < the rank (={r})") dk = Integer((q**r - 1) / (q ** gcd(parameter, r) - 1)) dr = Integer((q**parameter - 1) / (q ** gcd(parameter, r) - 1)) return self._gen[parameter] ** dk / self._gen[-1] ** dr @@ -1684,14 +1684,14 @@ def j_invariant(self, parameter=None, check=True): if len(parameter) != 2: raise ValueError("list or tuple parameter must be of length 2") if not isinstance(parameter[0], (tuple, list)) or not isinstance(parameter[1], (tuple, list)): - raise TypeError("list or tuple parameter must contain tuples " "or lists") + raise TypeError("list or tuple parameter must contain tuples or lists") if not len(parameter[0]) < r or not len(parameter[1]) == len(parameter[0]) + 1: - raise ValueError("components of tuple or list parameter have " "incorrect length") + raise ValueError("components of tuple or list parameter have incorrect length") try: # Check parameter's type parameter_0 = [ZZ(p) for p in parameter[0]] parameter_1 = [ZZ(p) for p in parameter[1]] except TypeError: - raise TypeError("components of tuple or list parameter must " "contain only integers") + raise TypeError("components of tuple or list parameter must contain only integers") # Check that the weight-0 condition is satisfied: # d_1 (q - 1) + ... + d_{r-1} (q^{r-1} - 1) # = d_r (q^r - 1) @@ -1699,9 +1699,9 @@ def j_invariant(self, parameter=None, check=True): right = parameter_1[-1] * (q**r - 1) left = sum(parameter_1[i] * (q ** (parameter_0[i]) - 1) for i in range(len(parameter_0))) if left != right: - raise ValueError("parameter does not satisfy the " "weight-0 condition") + raise ValueError("parameter does not satisfy the weight-0 condition") else: - raise TypeError("parameter must be a tuple or a list of " "length 2 or an integer") + raise TypeError("parameter must be a tuple or a list of length 2 or an integer") num = prod(self._gen[k] ** d for k, d in zip(parameter_0, parameter_1[:-1])) return num / (self._gen[-1] ** parameter_1[-1]) diff --git a/src/sage/rings/function_field/drinfeld_modules/homset.py b/src/sage/rings/function_field/drinfeld_modules/homset.py index ff5272066b1..32651b4443f 100644 --- a/src/sage/rings/function_field/drinfeld_modules/homset.py +++ b/src/sage/rings/function_field/drinfeld_modules/homset.py @@ -305,7 +305,7 @@ def _latex_(self) -> str: sage: latex(H) \text{Set{ }of{ }Drinfeld{ }module{ }morphisms{ }from{ }(gen){ }}2 τ^{2} + z_{6} τ + z_{6}\text{{ }to{ }(gen){ }}2 τ^{2} + \left(2 z_{6}^{5} + 2 z_{6}^{4} + 2 z_{6} + 1\right) τ + z_{6} """ - return f'\\text{{Set{{ }}of{{ }}Drinfeld{{ }}module{{ }}morphisms' f'{{ }}from{{ }}(gen){{ }}}}{latex(self.domain().gen())}' f'\\text{{{{ }}to{{ }}(gen){{ }}}}' f'{latex(self.codomain().gen())}' + return f'\\text{{Set{{ }}of{{ }}Drinfeld{{ }}module{{ }}morphisms{{ }}from{{ }}(gen){{ }}}}{latex(self.domain().gen())}\\text{{{{ }}to{{ }}(gen){{ }}}}{latex(self.codomain().gen())}' def _repr_(self) -> str: r""" @@ -322,7 +322,7 @@ def _repr_(self) -> str: sage: H Set of Drinfeld module morphisms from (gen) 2*τ^2 + z6*τ + z6 to (gen) 2*τ^2 + (2*z6^5 + 2*z6^4 + 2*z6 + 1)*τ + z6 """ - return f'Set of Drinfeld module morphisms from (gen) ' f'{self.domain().gen()} to (gen) {self.codomain().gen()}' + return f'Set of Drinfeld module morphisms from (gen) {self.domain().gen()} to (gen) {self.codomain().gen()}' def __contains__(self, x) -> bool: r""" diff --git a/src/sage/rings/function_field/drinfeld_modules/morphism.py b/src/sage/rings/function_field/drinfeld_modules/morphism.py index 9dd1d401959..3ae8adcf6a1 100644 --- a/src/sage/rings/function_field/drinfeld_modules/morphism.py +++ b/src/sage/rings/function_field/drinfeld_modules/morphism.py @@ -258,8 +258,8 @@ def _repr_(self) -> str: if self.is_identity(): return f'Identity morphism of {self._domain}' if self.is_endomorphism(): - return f'Endomorphism of {self._domain}\n' f' Defn: {self._ore_polynomial}' - return f'Drinfeld Module morphism:\n' f' From: {self._domain}\n' f' To: {self._codomain}\n' f' Defn: {self._ore_polynomial}' + return f'Endomorphism of {self._domain}\n Defn: {self._ore_polynomial}' + return f'Drinfeld Module morphism:\n From: {self._domain}\n To: {self._codomain}\n Defn: {self._ore_polynomial}' def __hash__(self) -> int: r""" diff --git a/src/sage/rings/function_field/function_field.py b/src/sage/rings/function_field/function_field.py index 71a0d2146f5..eb88f32853b 100644 --- a/src/sage/rings/function_field/function_field.py +++ b/src/sage/rings/function_field/function_field.py @@ -1292,7 +1292,7 @@ def hilbert_symbol(self, a, b, P) -> Integer: raise NotImplementedError('only supported for global function fields') if self.characteristic() == 2: - raise ValueError('Hilbert symbol is only defined for' ' odd characteristic function fields') + raise ValueError('Hilbert symbol is only defined for odd characteristic function fields') if not (a in self and b in self): raise ValueError('a and b must be elements of the function field') @@ -1510,19 +1510,19 @@ def jacobian(self, model: str = 'hess', base_div: FunctionFieldPlace | FunctionF if base_div is None: base_div = (2 * g + 1) * base_place if not base_div.degree() >= 2 * g + 1: - raise ValueError("Khuri-Makdisi large model requires base divisor of degree " "at least 2*g + 1 for genus g") + raise ValueError("Khuri-Makdisi large model requires base divisor of degree at least 2*g + 1 for genus g") return JacobianKhuriMakdisi(self, base_div, model='large', curve=curve) if model.endswith('medium'): if base_div is None: base_div = (2 * g + 1) * base_place if not base_div.degree() >= 2 * g + 1: - raise ValueError("Khuri-Makdisi medium model requires base divisor of degree " "at least 2*g + 1 for genus g") + raise ValueError("Khuri-Makdisi medium model requires base divisor of degree at least 2*g + 1 for genus g") return JacobianKhuriMakdisi(self, base_div, model='medium', curve=curve) if model.endswith('small'): if base_div is None: base_div = (g + 1) * base_place if not base_div.degree() >= g + 1: - raise ValueError("Khuri-Makdisi small model requires base divisor of degree " "at least g + 1 for genus g") + raise ValueError("Khuri-Makdisi small model requires base divisor of degree at least g + 1 for genus g") return JacobianKhuriMakdisi(self, base_div, model='small', curve=curve) elif model == 'hess': from .jacobian_hess import Jacobian as JacobianHess diff --git a/src/sage/rings/function_field/function_field_polymod.py b/src/sage/rings/function_field/function_field_polymod.py index 4b46f1e4d4c..4155a9b75c5 100644 --- a/src/sage/rings/function_field/function_field_polymod.py +++ b/src/sage/rings/function_field/function_field_polymod.py @@ -594,7 +594,7 @@ def _latex_(self) -> str: sage: latex(L) \text{Function field in } y \text{ defined by } y^{5} - 2 x y + \frac{-x^{4} - 1}{x} """ - return fr"\text{{Function field in }} {self.variable_name()} " fr"\text{{ defined by }} {self._polynomial._latex_()}" + return rf"\text{{Function field in }} {self.variable_name()} " rf"\text{{ defined by }} {self._polynomial._latex_()}" def base_field(self): """ @@ -1054,7 +1054,7 @@ def genus(self): singular.lib('normal.lib') # loading genus method in Singular return int(curveIdeal._singular_().genus()) - raise NotImplementedError("computation of genus over non-prime " "constant fields not implemented yet") + raise NotImplementedError("computation of genus over non-prime constant fields not implemented yet") def _simple_model(self, name='v'): r""" diff --git a/src/sage/rings/function_field/jacobian_unique_hess.py b/src/sage/rings/function_field/jacobian_unique_hess.py index 75bcb04bf92..a25fde80b42 100644 --- a/src/sage/rings/function_field/jacobian_unique_hess.py +++ b/src/sage/rings/function_field/jacobian_unique_hess.py @@ -443,7 +443,6 @@ def __iter__(self) -> Iterable[JacobianPoint_finite_field]: class Jacobian(Jacobian_base, UniqueRepresentation): - def __init__(self, function_field: FunctionField, base_div: FunctionFieldDivisor | FunctionFieldPlace, cache_infinite_ideals: bool = True, **kwds) -> None: r""" TESTS:: diff --git a/src/sage/rings/ideal.py b/src/sage/rings/ideal.py index 078acd7a770..ec570f64309 100644 --- a/src/sage/rings/ideal.py +++ b/src/sage/rings/ideal.py @@ -201,7 +201,7 @@ def Ideal(*args, **kwds): if inferred_field and not isinstance(I, Ideal_fractional): # trac 32320 import warnings - warnings.warn(f'Constructing an ideal in {R}, which is a field.' ' Did you intend to take numerators first?' ' This warning can be muted by passing the base ring to Ideal() explicitly.') + warnings.warn(f'Constructing an ideal in {R}, which is a field. Did you intend to take numerators first? This warning can be muted by passing the base ring to Ideal() explicitly.') return I diff --git a/src/sage/rings/infinity.py b/src/sage/rings/infinity.py index 310d8676448..c96f60473f2 100644 --- a/src/sage/rings/infinity.py +++ b/src/sage/rings/infinity.py @@ -559,7 +559,6 @@ def _sage_input_(self, sib, coerced): class UnsignedInfinityRing_class(Singleton, Parent): - def __init__(self): """ Initialize ``self``. @@ -882,7 +881,6 @@ def sign(self): class UnsignedInfinity(_uniq, AnInfinity, InfinityElement): - _sign = 0 _sign_char = '' @@ -1266,7 +1264,6 @@ def _pushout_(self, other): class FiniteNumber(RingElement): - def __init__(self, parent, x): """ Initialize ``self``. @@ -1529,7 +1526,6 @@ def sqrt(self): class MinusInfinity(_uniq, AnInfinity, InfinityElement): - _sign = -1 _sign_char = '-' @@ -1630,7 +1626,6 @@ def _gap_init_(self) -> str: class PlusInfinity(_uniq, AnInfinity, InfinityElement): - _sign = 1 _sign_char = '+' diff --git a/src/sage/rings/invariants/invariant_theory.py b/src/sage/rings/invariants/invariant_theory.py index 5aee3a34b25..c3f786e3081 100644 --- a/src/sage/rings/invariants/invariant_theory.py +++ b/src/sage/rings/invariants/invariant_theory.py @@ -109,7 +109,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.matrix.constructor import matrix from sage.structure.sage_object import SageObject from sage.structure.richcmp import richcmp_method, richcmp @@ -1189,7 +1188,7 @@ def invariants(self, type='discriminant'): """ if type == 'discriminant': return (self.discriminant(),) - raise ValueError('unknown type of invariants {} for a binary' ' quadratic'.format(type)) + raise ValueError('unknown type of invariants {} for a binary quadratic'.format(type)) @cached_method def dual(self): @@ -2279,7 +2278,7 @@ def invariants(self, type='clebsch'): return self.clebsch_invariants(as_tuple=True) if type == 'arithmetic': return self.arithmetic_invariants(as_tuple=True) - raise ValueError('unknown type of invariants {} for a binary' ' quintic'.format(type)) + raise ValueError('unknown type of invariants {} for a binary quintic'.format(type)) @cached_method def clebsch_invariants(self, as_tuple=False): @@ -2308,7 +2307,7 @@ def clebsch_invariants(self, as_tuple=False): -148978972828696847376/30517578125) """ if self._ring.characteristic() in [2, 3, 5]: - raise NotImplementedError('no invariants implemented for fields ' 'of characteristic 2, 3 or 5') + raise NotImplementedError('no invariants implemented for fields of characteristic 2, 3 or 5') # todo: add support else: invariants = {} @@ -3237,7 +3236,6 @@ def _check_covariant(self, method_name, g=None, invariant=False): class TwoAlgebraicForms(SeveralAlgebraicForms): - def first(self): """ Return the first of the two forms. @@ -4535,13 +4533,13 @@ def binary_form_from_invariants(self, degree, invariants, variables=None, as_for elif len(variables) == 2: x, z = variables else: - raise ValueError('incorrect number of variables provided, ' 'exactly two variables should be provided') + raise ValueError('incorrect number of variables provided, exactly two variables should be provided') if degree == 2: if len(invariants) == 1: if as_form: return QuadraticForm.from_invariants(invariants[0], x, z, *args, **kwargs) return reconstruction.binary_quadratic_coefficients_from_invariants(invariants[0], *args, **kwargs) - raise ValueError('incorrect number of invariants provided, ' 'only one invariant should be provided') + raise ValueError('incorrect number of invariants provided, only one invariant should be provided') elif degree == 3: if len(invariants) == 1: if as_form: @@ -4549,13 +4547,13 @@ def binary_form_from_invariants(self, degree, invariants, variables=None, as_for else: return reconstruction.binary_cubic_coefficients_from_invariants(invariants[0], *args, **kwargs) else: - raise ValueError('incorrect number of invariants provided, only ' 'one invariant should be provided') + raise ValueError('incorrect number of invariants provided, only one invariant should be provided') elif degree == 5: if as_form: return BinaryQuintic.from_invariants(invariants, x, z, *args, **kwargs) return reconstruction.binary_quintic_coefficients_from_invariants(invariants, *args, **kwargs) else: - raise NotImplementedError('no reconstruction for binary forms of ' 'degree {} implemented'.format(degree)) + raise NotImplementedError('no reconstruction for binary forms of degree {} implemented'.format(degree)) def ternary_quadratic(self, quadratic, *args, **kwds): """ diff --git a/src/sage/rings/invariants/reconstruction.py b/src/sage/rings/invariants/reconstruction.py index 6118ed06c21..aeb9e46dc8a 100644 --- a/src/sage/rings/invariants/reconstruction.py +++ b/src/sage/rings/invariants/reconstruction.py @@ -50,7 +50,7 @@ def binary_quadratic_coefficients_from_invariants(discriminant, invariant_choice (1, 0, 0) """ if invariant_choice not in ['default', 'discriminant']: - raise ValueError('unknown choice of invariants {} for a binary ' 'quadratic'.format(invariant_choice)) + raise ValueError('unknown choice of invariants {} for a binary quadratic'.format(invariant_choice)) if discriminant == 0: return (1, 0, 0) try: @@ -98,7 +98,7 @@ def binary_cubic_coefficients_from_invariants(discriminant, invariant_choice='de if invariant_choice not in ['default', 'discriminant']: raise ValueError('unknown choice of invariants {} for a binary cubic'.format(invariant_choice)) if discriminant == 0: - raise ValueError('no unique reconstruction possible for binary ' 'cubics with a double root') + raise ValueError('no unique reconstruction possible for binary cubics with a double root') else: return (0, 1, -1, 0) @@ -256,10 +256,10 @@ def binary_quintic_coefficients_from_invariants(invariants, K=None, invariant_ch K = FractionField(A.parent()) if K.characteristic() in [2, 3, 5]: - raise NotImplementedError('no reconstruction of binary quintics ' 'implemented for fields of characteristic 2, 3 or 5') + raise NotImplementedError('no reconstruction of binary quintics implemented for fields of characteristic 2, 3 or 5') M = 2 * A * B - 3 * C N = K(2) ** -1 * (A * C - B**2) - R2 = -K(2) ** -1 * (A * N**2 - 2 * B * M * N + C * M**2) + R2 = -(K(2) ** -1) * (A * N**2 - 2 * B * M * N + C * M**2) scale = [1, 1, 1, 1, 1, 1] from sage.arith.misc import binomial from sage.misc.functional import sqrt @@ -275,14 +275,14 @@ def binary_quintic_coefficients_from_invariants(invariants, K=None, invariant_ch R = R2**5 elif len(invariants) == 4: if invariants[3] ** 2 != R2: - raise ValueError('provided invariants do not satisfy the syzygy ' 'for Clebsch invariants of a binary quintic') + raise ValueError('provided invariants do not satisfy the syzygy for Clebsch invariants of a binary quintic') R = invariants[3] else: - raise ValueError('incorrect number of invariants provided, this ' 'method requires 3 or 4 invariants') + raise ValueError('incorrect number of invariants provided, this method requires 3 or 4 invariants') if M == 0: if N == 0: if A == 0: - raise ValueError('no unique reconstruction possible for ' 'quintics with a treefold linear factor') + raise ValueError('no unique reconstruction possible for quintics with a treefold linear factor') else: if B == 0: return (1, 0, 0, 0, 0, 1) diff --git a/src/sage/rings/laurent_series_ring.py b/src/sage/rings/laurent_series_ring.py index abc7f4dda11..46057f135f9 100644 --- a/src/sage/rings/laurent_series_ring.py +++ b/src/sage/rings/laurent_series_ring.py @@ -32,7 +32,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.categories.algebras import Algebras from sage.categories.complete_discrete_valuation import CompleteDiscreteValuationFields from sage.categories.fields import Fields diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 5d9fc41d6d7..a32e71e9b34 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -4882,7 +4882,7 @@ def integral(self, variable=None, *, constants=None): if constants is None: constants = [zero] * ZZ(variable) elif ZZ(variable) != len(constants): - raise ValueError("the number of integrations does not match" " the number of integration constants") + raise ValueError("the number of integrations does not match the number of integration constants") variable = None if constants is None: constants = [] @@ -6100,7 +6100,7 @@ def integral(self, variable=None, *, constants=None): if constants is None: constants = [zero] * ZZ(variable) elif ZZ(variable) != len(constants): - raise ValueError("the number of integrations does not match" " the number of integration constants") + raise ValueError("the number of integrations does not match the number of integration constants") variable = None if constants is None: constants = [] @@ -6765,7 +6765,6 @@ def __call__(self, *args): if len(args) == 1: g = args[0] if isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: - if not isinstance(g, LazySymmetricFunction): f = self.symmetric_function() return f(g) @@ -7397,7 +7396,6 @@ def arithmetic_product(self, *args): return P.zero() if isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: - if not isinstance(g, LazySymmetricFunction): f = self.symmetric_function() return f.arithmetic_product(g) @@ -8356,7 +8354,7 @@ def nth_root(self, n): generic = LazyPseudoDifferentialOperatorRing(DUMMY) v = val // n - F = generic(lambda n: SRfunc(f"DUM{n-v}")(DUMMY), valuation=v) + F = generic(lambda n: SRfunc(f"DUM{n - v}")(DUMMY), valuation=v) temp = F**n computed = {F[v]: lcr} @@ -8427,4 +8425,4 @@ def star(self): m = infinity mone = -ZZ.one() R = P._laurent_poly_ring - return P.sum(lambda k: (P.element_class(P, Stream_exact([R.one()], constant=R.zero(), order=k)) * P(mone**k * self[k])), self.valuation(), m) + return P.sum(lambda k: P.element_class(P, Stream_exact([R.one()], constant=R.zero(), order=k)) * P(mone**k * self[k]), self.valuation(), m) diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index cff8ae3ffdd..c3f69d368dc 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -1601,7 +1601,7 @@ def _test_revert(self, **options): except NotImplementedError: pass except (ValueError, TypeError): - tester.assertFalse(vx == 1 and x[vx].is_unit(), ("the series %s should be reversible " "- its valuation is one and its leading coefficient is a unit") % x) + tester.assertFalse(vx == 1 and x[vx].is_unit(), ("the series %s should be reversible - its valuation is one and its leading coefficient is a unit") % x) else: count += 1 e1 = y(x) diff --git a/src/sage/rings/localization.py b/src/sage/rings/localization.py index 09434238cd7..3020760a7b2 100644 --- a/src/sage/rings/localization.py +++ b/src/sage/rings/localization.py @@ -169,7 +169,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.structure.unique_representation import UniqueRepresentation from sage.categories.integral_domains import IntegralDomains from sage.structure.parent import Parent diff --git a/src/sage/rings/multi_power_series_ring_element.py b/src/sage/rings/multi_power_series_ring_element.py index 6af87bc86e1..2b5b6fb185f 100644 --- a/src/sage/rings/multi_power_series_ring_element.py +++ b/src/sage/rings/multi_power_series_ring_element.py @@ -383,7 +383,7 @@ def __init__(self, parent, x=0, prec=infinity, is_gen=False, check=False): # self._value = x self._bg_value = parent._send_to_bg(x).add_bigoh(prec) except (TypeError, AttributeError): - raise TypeError("Input does not coerce to any of the " "expected rings.") + raise TypeError("Input does not coerce to any of the expected rings.") self._go_to_fg = parent._send_to_fg self._prec = self._bg_value.prec() diff --git a/src/sage/rings/number_field/S_unit_solver.py b/src/sage/rings/number_field/S_unit_solver.py index d38f0291ea1..6c1b23fd900 100644 --- a/src/sage/rings/number_field/S_unit_solver.py +++ b/src/sage/rings/number_field/S_unit_solver.py @@ -55,7 +55,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.rings.infinity import Infinity from sage.symbolic.ring import SR from sage.rings.integer import Integer @@ -1053,7 +1052,6 @@ def reduction_step_complex_case(place, B0, list_of_gens, torsion_gen, c13): finish = False while not finish: - A = copy(identity_matrix(ZZ, n + 1)) # We redefine the imaginary parts in case any generator was negative new_imag_part_log_gens = [0 for i in imag_part_log_gens[:-1]] + [imag_part_log_gens[-1]] @@ -1082,7 +1080,6 @@ def reduction_step_complex_case(place, B0, list_of_gens, torsion_gen, c13): return max(4, w, Bnew), False else: - # the case when the real part is not 0 for all log(a_i), see Lemma 5.2 in [AKMRVW] C = R(1) S = (n - 1) * B0**2 @@ -1101,7 +1098,6 @@ def reduction_step_complex_case(place, B0, list_of_gens, torsion_gen, c13): imag_part_log_gens[new_last_gen_index] = old_last_gen_imag while not finish: - A = copy(identity_matrix(ZZ, n + 1)) A[n - 1] = vector([(g * C).round() for g in real_part_log_gens]) A[n] = vector([(g * C).round() for g in imag_part_log_gens]) @@ -1315,14 +1311,14 @@ def log_p_series_part(a, prime, prec): n += step # could use smaller stepsize to get actual smallest integer n, however this seems to run faster. w = (R(prec).log() / R(p).log()).floor() - gamma = sum([ZZ(gi % (p ** (prec + w))) * g ** i if gi.valuation(p) >= 0 else ZZ((gi * p ** (-gi.valuation(p))) % (p ** (prec + w - gi.valuation(p)))) * p ** (gi.valuation(p)) * g**i for i, gi in enumerate(gamma) if gi != 0]) + gamma = sum([ZZ(gi % (p ** (prec + w))) * g**i if gi.valuation(p) >= 0 else ZZ((gi * p ** (-gi.valuation(p))) % (p ** (prec + w - gi.valuation(p)))) * p ** (gi.valuation(p)) * g**i for i, gi in enumerate(gamma) if gi != 0]) beta = 0 delta = 1 - gamma for i in range(1, n + 1): beta -= delta / i delta *= 1 - gamma - delta = sum([ZZ(di % (p ** (prec + w))) * g ** b if di.valuation(p) >= 0 else ZZ((di * p ** (-di.valuation(p))) % (p ** (prec + w - di.valuation(p)))) * p ** (di.valuation(p)) * g**b for b, di in enumerate(delta) if di != 0]) + delta = sum([ZZ(di % (p ** (prec + w))) * g**b if di.valuation(p) >= 0 else ZZ((di * p ** (-di.valuation(p))) % (p ** (prec + w - di.valuation(p)))) * p ** (di.valuation(p)) * g**b for b, di in enumerate(delta) if di != 0]) beta = beta / (order * p**t) # we try to make the coefficients small @@ -1917,7 +1913,6 @@ def construct_rfv_to_ev(rfv_dictionary, q, d, verbose=False) -> dict: # we loop over each key of P. for rf_vector_start in P: - # each key of P provides q-2 possible keys for P_new, which we introduce and assign an empty list. for w in range(2, q): new_rf_vector_start = tuple(list(rf_vector_start) + [w]) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 2edfaaab3f5..ded34c7c4c9 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -65,6 +65,7 @@ - Anna Haensch (2018-03): added :meth:`quadratic_defect` - Michael Daub, Chris Wuthrich (2020-09-01): added Dirichlet characters for abelian fields """ + # **************************************************************************** # Copyright (C) 2004-2007 William Stein # 2014-2022 Julian Rüth @@ -4484,7 +4485,7 @@ def _gap_init_(self) -> str: E = 'E' if x != 'E' else 'F' R = G(self.base_ring()) - return f'CallFuncList(function() local {x},{E}; {x}:=Indeterminate({R.name()},"{x}"); ' f'{E}:=AlgebraicExtension({R.name()},{self.polynomial()!r},"{self.gen()}"); ' f'return {E}; end,[])' + return f'CallFuncList(function() local {x},{E}; {x}:=Indeterminate({R.name()},"{x}"); {E}:=AlgebraicExtension({R.name()},{self.polynomial()!r},"{self.gen()}"); return {E}; end,[])' def _libgap_(self): """ @@ -9481,7 +9482,6 @@ def minkowski_embedding(self, B=None, prec=None): d = {} for col in range(n): - for row in range(r): d[(row, col)] = places[row](B[col]) @@ -10432,12 +10432,12 @@ def hilbert_symbol_negative_at_S(self, S, b, check=True): if not p.is_prime(): raise ValueError("not a prime ideal") if self.quadratic_defect(b, p) == infinity.Infinity: - raise ValueError(f"{b} is a square in the completion " f"with respect to {p}") + raise ValueError(f"{b} is a square in the completion with respect to {p}") else: if p not in self.real_places(): - raise ValueError("entries of the list must be " "prime ideals or real places") + raise ValueError("entries of the list must be prime ideals or real places") if p(b) > 0: - raise ValueError(f"{b} is a square in the completion " f"with respect to {p}") + raise ValueError(f"{b} is a square in the completion with respect to {p}") # L is the list of primes that we need to consider, b must have # nonzero valuation for each prime in L, this is the set S' @@ -11195,7 +11195,7 @@ def _coerce_map_from_(self, K): return number_field_morphisms.NumberFieldEmbedding(K, self, -self.gen()) if Kn % 4 == 2 and (Kn // 2).divides(n): e = self._log_gen(ambient_field(-K.gen())) - return number_field_morphisms.NumberFieldEmbedding(K, self, -self.gen() ** e) + return number_field_morphisms.NumberFieldEmbedding(K, self, -(self.gen() ** e)) return None if self.degree() == 2: @@ -11720,7 +11720,6 @@ def different(self): return self.__different except AttributeError: - z = self.gen() n = self._n() D = self.ideal(1) diff --git a/src/sage/rings/number_field/number_field_ideal_rel.py b/src/sage/rings/number_field/number_field_ideal_rel.py index 35ab78ee2dc..a84f35a91be 100644 --- a/src/sage/rings/number_field/number_field_ideal_rel.py +++ b/src/sage/rings/number_field/number_field_ideal_rel.py @@ -31,7 +31,6 @@ # https://www.gnu.org/licenses/ # *************************************************************************** - from .number_field_ideal import NumberFieldFractionalIdeal from sage.misc.cachefunc import cached_method from sage.structure.factorization import Factorization diff --git a/src/sage/rings/number_field/order.py b/src/sage/rings/number_field/order.py index 5594db6d1ed..32302da80f7 100644 --- a/src/sage/rings/number_field/order.py +++ b/src/sage/rings/number_field/order.py @@ -1080,7 +1080,7 @@ def residue_field(self, prime, names=None, check=False): if self.is_maximal(): return self.number_field().residue_field(prime, names, check=check) - raise NotImplementedError("residue fields of non-maximal orders " "are not yet supported") + raise NotImplementedError("residue fields of non-maximal orders are not yet supported") def fraction_field(self): """ diff --git a/src/sage/rings/number_field/selmer_group.py b/src/sage/rings/number_field/selmer_group.py index 37ac4e2bddb..f34bdfe43cc 100644 --- a/src/sage/rings/number_field/selmer_group.py +++ b/src/sage/rings/number_field/selmer_group.py @@ -43,7 +43,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.rational_field import QQ from sage.misc.misc_c import prod diff --git a/src/sage/rings/number_field/totallyreal_rel.py b/src/sage/rings/number_field/totallyreal_rel.py index 895b47681fe..b4e6ff55c24 100644 --- a/src/sage/rings/number_field/totallyreal_rel.py +++ b/src/sage/rings/number_field/totallyreal_rel.py @@ -848,7 +848,7 @@ def enumerate_totallyreal_fields_rel(F, m, B, a=[], verbose=0, return_seqs=False if verbose: print("=" * 80) print("Polynomials tested: {}".format(counts[0])) - print("Polynomials with discriminant with large enough square" " divisor: {}".format(counts[1])) + print("Polynomials with discriminant with large enough square divisor: {}".format(counts[1])) print("Irreducible polynomials: {}".format(counts[2])) print("Polynomials with nfdisc <= B: {}".format(counts[3])) for i in range(len(S)): @@ -960,7 +960,7 @@ def enumerate_totallyreal_fields_all(n, B, verbose=0, return_seqs=False, return_ # Else, print to screen print("=" * 80) print("Polynomials tested: {}".format(counts[0])) - print("Polynomials with discriminant with large enough square" " divisor: {}".format(counts[1])) + print("Polynomials with discriminant with large enough square divisor: {}".format(counts[1])) print("Irreducible polynomials: {}".format(counts[2])) print("Polynomials with nfdisc <= B: {}".format(counts[3])) for i in range(len(S)): diff --git a/src/sage/rings/padics/padic_lattice_element.py b/src/sage/rings/padics/padic_lattice_element.py index 10e2c970723..8eb3ff668df 100644 --- a/src/sage/rings/padics/padic_lattice_element.py +++ b/src/sage/rings/padics/padic_lattice_element.py @@ -17,7 +17,6 @@ # http://www.gnu.org/licenses/ # **************************************************************************** - from sage.misc.abstract_method import abstract_method from sage.rings.integer import Integer diff --git a/src/sage/rings/padics/unramified_extension_generic.py b/src/sage/rings/padics/unramified_extension_generic.py index 60197467740..a660168ac30 100644 --- a/src/sage/rings/padics/unramified_extension_generic.py +++ b/src/sage/rings/padics/unramified_extension_generic.py @@ -19,7 +19,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from .padic_extension_generic import pAdicExtensionGeneric from sage.rings.finite_rings.finite_field_constructor import GF from sage.misc.cachefunc import cached_method diff --git a/src/sage/rings/padics/witt_vector.py b/src/sage/rings/padics/witt_vector.py index de8aa9effa7..9cdc7505935 100644 --- a/src/sage/rings/padics/witt_vector.py +++ b/src/sage/rings/padics/witt_vector.py @@ -21,7 +21,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.misc.cachefunc import cached_method from sage.misc.functional import log from sage.misc.latex import tuple_function @@ -93,10 +92,10 @@ def __init__(self, parent, vec=None): self._int_to_vector(vec, parent) elif isinstance(vec, (tuple, list, WittVector)): if len(vec) < self._prec: - raise ValueError(f"{vec} has not the correct length, " "expected length has to be at least " f"{self._prec}") + raise ValueError(f"{vec} has not the correct length, expected length has to be at least {self._prec}") self._coordinates = tuple(B(vec[i]) for i in range(self._prec)) else: - raise ValueError(f"{vec} cannot be interpreted as a Witt " "vector") + raise ValueError(f"{vec} cannot be interpreted as a Witt vector") else: self._coordinates = (B(0) for i in range(self._prec)) CommutativeRingElement.__init__(self, parent) @@ -503,7 +502,7 @@ def __init__(self, parent, vec=None, phantom=None): self._phantom = self._prec * [y] elif isinstance(vec, (tuple, list, WittVector)): if len(vec) < self._prec: - raise ValueError(f"{vec} has not the correct length, " "expected length has to be at least " f"{self._prec}") + raise ValueError(f"{vec} has not the correct length, expected length has to be at least {self._prec}") # We compute the phantom components self._coordinates = tuple(R(vec[i]) for i in range(self._prec)) x = [lift(v) for v in self._coordinates] diff --git a/src/sage/rings/padics/witt_vector_ring.py b/src/sage/rings/padics/witt_vector_ring.py index 6a3a5595892..adb1fa5057c 100644 --- a/src/sage/rings/padics/witt_vector_ring.py +++ b/src/sage/rings/padics/witt_vector_ring.py @@ -22,7 +22,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from collections.abc import Iterator from itertools import product @@ -268,7 +267,7 @@ def __classcall_private__(cls, coefficient_ring, prec=1, p=None, algorithm=None) if p is None: if char not in Primes(): - raise ValueError(f"{coefficient_ring} has non-prime " "characteristic and no prime was supplied") + raise ValueError(f"{coefficient_ring} has non-prime characteristic and no prime was supplied") p = char elif p not in Primes(): raise ValueError(f"p must be a prime number, here {p} was given") @@ -293,7 +292,7 @@ def __classcall_private__(cls, coefficient_ring, prec=1, p=None, algorithm=None) case 'standard': child = WittVectorRing_standard case _: - raise ValueError("algorithm must be one of None, 'standard', " "'p_invertible', 'finotti', 'phantom'") + raise ValueError("algorithm must be one of None, 'standard', 'p_invertible', 'finotti', 'phantom'") return child.__classcall__(child, coefficient_ring, prec, p) @@ -501,7 +500,7 @@ def _repr_(self) -> str: sage: WittVectorRing(QQ, p=2, prec=5) Ring of truncated 2-typical Witt vectors of length 5 over Rational Field """ - return f"Ring of truncated {self._prime}-typical Witt vectors of " f"length {self._prec} over {self._coefficient_ring}" + return f"Ring of truncated {self._prime}-typical Witt vectors of length {self._prec} over {self._coefficient_ring}" def cardinality(self): """ @@ -1029,7 +1028,7 @@ def __init__(self, coefficient_ring, prec, prime) -> None: sage: TestSuite(W).run() """ if coefficient_ring.characteristic() != prime: - raise ValueError("the 'finotti' algorithm only works for " "coefficients rings of characteristic p") + raise ValueError("the 'finotti' algorithm only works for coefficients rings of characteristic p") if isinstance(coefficient_ring, MPolynomialRing_base): self._always_coerce = [WittVectorRing_finotti, WittVectorRing_phantom, WittVectorRing_standard] @@ -1163,7 +1162,7 @@ def __init__(self, coefficient_ring, prec, prime) -> None: sage: TestSuite(W).run() """ - msg = "the 'phantom' algorithm only works when the coefficient ring is" " a finite field of char. p, or a polynomial ring on that field" + msg = "the 'phantom' algorithm only works when the coefficient ring is a finite field of char. p, or a polynomial ring on that field" if coefficient_ring.characteristic() != prime: raise ValueError(msg) @@ -1219,7 +1218,7 @@ def __init__(self, coefficient_ring, prec, prime) -> None: sage: TestSuite(W).run() """ if not coefficient_ring(prime).is_unit(): - raise ValueError("the 'p_invertible' algorithm only works when p " "is a unit in the ring of coefficients") + raise ValueError("the 'p_invertible' algorithm only works when p is a unit in the ring of coefficients") self._always_coerce = [WittVectorRing_pinvertible, WittVectorRing_standard] self._coerce_when_different = [] @@ -1345,7 +1344,7 @@ def __init__(self, domain, truncate=False): prec = domain.precision() if prec.is_one(): - raise ValueError("the ring of Witt vectors must have " "precision at least 2 when truncate=True") + raise ValueError("the ring of Witt vectors must have precision at least 2 when truncate=True") if isinstance(domain, WittVectorRing_finotti): algorithm = "finotti" @@ -1481,7 +1480,7 @@ def _repr_(self) -> str: """ if self.domain() is self.codomain(): return f"Frobenius endomorphism on the {self.domain()}" - return f"Frobenius homomorphism from the {self.domain()} to the " f"{self.codomain()}" + return f"Frobenius homomorphism from the {self.domain()} to the {self.codomain()}" class WittVectorVerschiebung(RingMap): @@ -1680,4 +1679,4 @@ def _repr_(self) -> str: """ if self.domain() is self.codomain(): return f"Verschiebung map on the {self.domain()}" - return f"Verschiebung map from the {self.domain()} to the " f"{self.codomain()}" + return f"Verschiebung map from the {self.domain()} to the {self.codomain()}" diff --git a/src/sage/rings/polynomial/complex_roots.py b/src/sage/rings/polynomial/complex_roots.py index 8cef4a83831..eee5bb7a176 100644 --- a/src/sage/rings/polynomial/complex_roots.py +++ b/src/sage/rings/polynomial/complex_roots.py @@ -38,7 +38,6 @@ # http://www.gnu.org/licenses/ # ***************************************************************************** - from copy import copy from sage.rings.complex_mpfr import ComplexField diff --git a/src/sage/rings/polynomial/groebner_fan.py b/src/sage/rings/polynomial/groebner_fan.py index e9a5fd72b3d..a4685285b84 100644 --- a/src/sage/rings/polynomial/groebner_fan.py +++ b/src/sage/rings/polynomial/groebner_fan.py @@ -157,7 +157,6 @@ def _cone_parse(fan_dict_cone) -> dict: class PolyhedralCone(SageObject): - def __init__(self, gfan_polyhedral_cone, ring=QQ) -> None: """ Convert polymake/gfan data on a polyhedral cone into a sage class. @@ -644,7 +643,6 @@ def verts_for_normal(normal, poly) -> list: class TropicalPrevariety(PolyhedralFan): - def __init__(self, gfan_polyhedral_fan, polynomial_system, poly_ring, parameters=None) -> None: """ This class is a subclass of the PolyhedralFan class, @@ -767,7 +765,6 @@ def ideal_to_gfan_format(input_ring, polys) -> str: class GroebnerFan(SageObject): - def __init__(self, I, is_groebner_basis=False, symmetry=None, verbose=False) -> None: """ This class is used to access capabilities of the program ``Gfan``. diff --git a/src/sage/rings/polynomial/integer_valued_polynomials.py b/src/sage/rings/polynomial/integer_valued_polynomials.py index 8906c95f3f8..b921f4e65c7 100644 --- a/src/sage/rings/polynomial/integer_valued_polynomials.py +++ b/src/sage/rings/polynomial/integer_valued_polynomials.py @@ -698,7 +698,6 @@ def _poly(self, i): return binomial(x + i, i) class Element(CombinatorialFreeModule.Element): - def umbra(self): """ Return the Bernoulli umbra. diff --git a/src/sage/rings/polynomial/msolve.py b/src/sage/rings/polynomial/msolve.py index 832b5c4a7b0..8ca7be6f897 100644 --- a/src/sage/rings/polynomial/msolve.py +++ b/src/sage/rings/polynomial/msolve.py @@ -290,7 +290,6 @@ def to_poly(p, d=1, *, upol=PolynomialRing(base, 't')): variety.append(point) else: - if len(data[1]) < 2 or len(data[1]) != data[1][0] + 1: raise NotImplementedError(f"unsupported msolve output format: {data}") if isinstance(ring, (RealIntervalField_class, RealBallField)): diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index bd16f873556..76f638daceb 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -1976,7 +1976,7 @@ def integral(self, var=None): Multivariate Polynomial Ring in y, z over Univariate Polynomial Ring in x over Rational Field """ if var is None: - raise ValueError("must specify which variable to integrate " "with respect to") + raise ValueError("must specify which variable to integrate with respect to") # TODO: # calling the coercion model bin_op is much more accurate than using the diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 144c9f50b27..b0c878c11e6 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -4708,7 +4708,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal gb = groebner_basis_libgiac(self, prot=prot, *args, **kwds) elif algorithm == 'msolve': if self.ring().term_order() != 'degrevlex': - raise NotImplementedError("msolve only supports the degrevlex order " "(use transformed_basis())") + raise NotImplementedError("msolve only supports the degrevlex order (use transformed_basis())") if not (deg_bound is mult_bound is None) or prot: raise NotImplementedError("unsupported options for msolve") from . import msolve diff --git a/src/sage/rings/polynomial/omega.py b/src/sage/rings/polynomial/omega.py index ba6f126b87e..ceccabb0755 100644 --- a/src/sage/rings/polynomial/omega.py +++ b/src/sage/rings/polynomial/omega.py @@ -286,7 +286,7 @@ def MacMahonOmega(var, expression, denominator=None, op=operator.ge, Factorizati if not isinstance(denominator, Factorization): denominator = factor(denominator) if not denominator.is_integral(): - raise ValueError(f'factorization {denominator} of ' 'the denominator contains negative exponents') + raise ValueError(f'factorization {denominator} of the denominator contains negative exponents') numerator *= ZZ.one() / denominator.unit() factors_denominator = tuple(factor for factor, exponent in denominator for _ in range(exponent)) # at this point we have numerator/factors_denominator diff --git a/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py b/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py index aca82375e9c..4b567b7d66f 100644 --- a/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py +++ b/src/sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py @@ -782,7 +782,7 @@ def degree(self, secure=False): self._normalize() deg = Integer(self._poly.degree()) if secure and deg < self.prec_degree(): - raise PrecisionError("the leading coefficient is " "indistinguishable from 0") + raise PrecisionError("the leading coefficient is indistinguishable from 0") return deg def prec_degree(self): @@ -1063,7 +1063,7 @@ def _quo_rem_naive(self, right): f = self.base_extend(K) g = right.base_extend(K) if g == 0: - raise ZeroDivisionError("cannot divide by a polynomial " "indistinguishable from 0") + raise ZeroDivisionError("cannot divide by a polynomial indistinguishable from 0") x = f.parent().gen() quo = f.parent()(0) while f.degree() >= g.degree(): @@ -1083,7 +1083,7 @@ def _quo_rem_list(self, right, secure): - Xavier Caruso (2013-03) """ if right.is_zero(): - raise ZeroDivisionError("cannot divide by a polynomial " "indistinguishable from 0") + raise ZeroDivisionError("cannot divide by a polynomial indistinguishable from 0") a = self.list() da = len(a) - 1 b = right.list() diff --git a/src/sage/rings/polynomial/pbori/frontend.py b/src/sage/rings/polynomial/pbori/frontend.py index 79b50053bc0..f7390178e0d 100644 --- a/src/sage/rings/polynomial/pbori/frontend.py +++ b/src/sage/rings/polynomial/pbori/frontend.py @@ -30,7 +30,6 @@ a """ - from sage.rings.polynomial.pbori.blocks import declare_ring as orig_declare_ring from sage.rings.polynomial.pbori.pbori import VariableFactory from sage.rings.polynomial.pbori.PyPolyBoRi import Ring diff --git a/src/sage/rings/polynomial/pbori/gbcore.py b/src/sage/rings/polynomial/pbori/gbcore.py index 38ffda91c53..349f5e2c968 100644 --- a/src/sage/rings/polynomial/pbori/gbcore.py +++ b/src/sage/rings/polynomial/pbori/gbcore.py @@ -146,7 +146,6 @@ def want_la(): if not (("faugere" in d and not d["faugere"]) or ("noro" in d and d["noro"])): if ("faugere" in d and d["faugere"]) or want_la(): - d["faugere"] = True if "red_tail" not in d: d["red_tail"] = False @@ -233,7 +232,6 @@ def wrapper(I, **kwds): if hasattr(f, "options"): wrapper.options = copy(f.options) else: - wrapper.options = get_options_from_function(f) wrapper.options[option] = default diff --git a/src/sage/rings/polynomial/pbori/ll.py b/src/sage/rings/polynomial/pbori/ll.py index db37db0f5c1..1be772929c7 100644 --- a/src/sage/rings/polynomial/pbori/ll.py +++ b/src/sage/rings/polynomial/pbori/ll.py @@ -61,7 +61,6 @@ def ll_encode(polys, reduce=False, prot=False, reduce_by_linear=True): last = None counter = 0 for p in linear_lead: - if prot: counter = counter + 1 progress = (counter * 100) / len(linear_lead) @@ -85,7 +84,6 @@ def eliminate(polys, on_the_fly=False, prot=False, reduction_function=None, opti continue lm = p.lex_lead() if lm.deg() == 1: - if lm not in linear_leading_monomials: linear_leading_monomials.add(lm) linear_leads.append(p) diff --git a/src/sage/rings/polynomial/polynomial_element_generic.py b/src/sage/rings/polynomial/polynomial_element_generic.py index 1573f39e42c..58c6f628f8e 100644 --- a/src/sage/rings/polynomial/polynomial_element_generic.py +++ b/src/sage/rings/polynomial/polynomial_element_generic.py @@ -1078,7 +1078,6 @@ def is_unit(self): class Polynomial_generic_field(Polynomial_singular_repr, Polynomial_generic_domain, EuclideanDomainElement): - @coerce_binop def quo_rem(self, other): """ diff --git a/src/sage/rings/polynomial/polynomial_fateman.py b/src/sage/rings/polynomial/polynomial_fateman.py index 2e0090e6287..baa99ba26a7 100644 --- a/src/sage/rings/polynomial/polynomial_fateman.py +++ b/src/sage/rings/polynomial/polynomial_fateman.py @@ -1,4 +1,5 @@ "Polynomial multiplication by Kronecker substitution" + ################################################################################ # Copyright (C) 2007 William Stein # diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring.py b/src/sage/rings/polynomial/polynomial_quotient_ring.py index a1302c04247..5678f959623 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring.py @@ -36,7 +36,6 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** - import sage.rings.rational_field from sage.arith.misc import crt from sage.categories.commutative_algebras import CommutativeAlgebras diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py index 90ebf95df42..aa41088bf02 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py @@ -545,7 +545,6 @@ def field_extension(self, names): from sage.rings.number_field.number_field_rel import NumberField_relative if isinstance(F, NumberField_relative): - base_map = F.base_field().hom([R.base_ring().gen()]) g = F.Hom(R)(x, base_map) diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 597246d7782..2c037dfb035 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -137,7 +137,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - import sys from sage import categories diff --git a/src/sage/rings/polynomial/polynomial_singular_interface.py b/src/sage/rings/polynomial/polynomial_singular_interface.py index 3dc8fcadb8d..7ea7c0195f3 100644 --- a/src/sage/rings/polynomial/polynomial_singular_interface.py +++ b/src/sage/rings/polynomial/polynomial_singular_interface.py @@ -104,7 +104,7 @@ def _do_singular_init_(singular, base_ring, char, _vars, order): if isinstance(base_ring, FiniteField) and char <= 2147483647: return make_ring(str(char)), None if char.is_power_of(2): - return make_ring(f"(integer,2,{char.nbits()-1})"), None + return make_ring(f"(integer,2,{char.nbits() - 1})"), None return make_ring(f"(integer,{char})"), None if isinstance(base_ring, FiniteField): diff --git a/src/sage/rings/polynomial/skew_polynomial_ring.py b/src/sage/rings/polynomial/skew_polynomial_ring.py index 6db6b85204b..786d43a1677 100644 --- a/src/sage/rings/polynomial/skew_polynomial_ring.py +++ b/src/sage/rings/polynomial/skew_polynomial_ring.py @@ -190,7 +190,7 @@ def _lagrange_polynomial(R, eval_pts, values): if l == 1: if eval_pts[0].is_zero(): # This is due to linear dependence among the eval_pts. - raise ValueError("the given evaluation points are linearly dependent" " over the fixed field of the twisting morphism," " so a Lagrange polynomial could not be determined" " (and might not exist)") + raise ValueError("the given evaluation points are linearly dependent over the fixed field of the twisting morphism, so a Lagrange polynomial could not be determined (and might not exist)") return (values[0] / eval_pts[0]) * R.one() t = l // 2 A = eval_pts[:t] diff --git a/src/sage/rings/polynomial/toy_buchberger.py b/src/sage/rings/polynomial/toy_buchberger.py index 568a6a18189..b8a5917e383 100644 --- a/src/sage/rings/polynomial/toy_buchberger.py +++ b/src/sage/rings/polynomial/toy_buchberger.py @@ -264,7 +264,6 @@ def buchberger_improved(F): G, B = update(G, B, f) while B: - g1, g2 = select(B) B.remove((g1, g2)) h = spol(g1, g2).reduce(G) diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index a86db99d4f2..d2f73164188 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -992,7 +992,6 @@ def _factor_multivariate_polynomial(self, f, proof=True): factorization = [] for factor, minpoly in factors: - # minpoly is in a multivariate polynomial ring # over a univariate fraction field diff --git a/src/sage/rings/quotient_ring_element.py b/src/sage/rings/quotient_ring_element.py index e74e7bb041f..1e12e89fc74 100644 --- a/src/sage/rings/quotient_ring_element.py +++ b/src/sage/rings/quotient_ring_element.py @@ -450,7 +450,7 @@ def _div_(self, right): try: XY = L.lift((R,) + tuple(B)) except ValueError: - raise ArithmeticError("Division failed. The numerator is not " "a multiple of the denominator.") + raise ArithmeticError("Division failed. The numerator is not a multiple of the denominator.") return P(XY[0]) def _im_gens_(self, codomain, im_gens, base_map=None): diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index eb665e6ed16..c7771f61625 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -866,12 +866,12 @@ def hilbert_symbol_negative_at_S(self, S, b, check=True): for p in S: if p != infty: if check and not is_prime(p): - raise ValueError("all entries in list must be prime" " or -1 for infinite place") + raise ValueError("all entries in list must be prime or -1 for infinite place") R = Qp(p) if R(b).is_square(): - raise ValueError("second argument must be a nonsquare with" " respect to every finite prime in the list") + raise ValueError("second argument must be a nonsquare with respect to every finite prime in the list") elif b > 0: - raise ValueError("if the infinite place is in the list, " "the second argument must be negative") + raise ValueError("if the infinite place is in the list, the second argument must be negative") # L is the list of primes that we need to consider, b must have # nonzero valuation for each prime in L, this is the set S' # in Kirschmer's algorithm diff --git a/src/sage/rings/semirings/tropical_mpolynomial.py b/src/sage/rings/semirings/tropical_mpolynomial.py index 9cc4dce8cb8..695fc8580cc 100644 --- a/src/sage/rings/semirings/tropical_mpolynomial.py +++ b/src/sage/rings/semirings/tropical_mpolynomial.py @@ -294,7 +294,7 @@ def plot3d(self, color='random'): from sage.symbolic.relation import solve if len(self.parent().variable_names()) != 2: - raise NotImplementedError("can only plot the graph of tropical " "multivariate polynomial in two variables") + raise NotImplementedError("can only plot the graph of tropical multivariate polynomial in two variables") tv = self.tropical_variety() axes = tv._axes() edge = set() @@ -858,8 +858,8 @@ def _repr_(self): Field with 53 bits of precision """ if self._ngens == 0: - return f"Multivariate Tropical Polynomial Semiring in no variables" f" over {self.base_ring().base_ring()}" - return f"Multivariate Tropical Polynomial Semiring in {', '.join(self.variable_names())}" f" over {self.base_ring().base_ring()}" + return f"Multivariate Tropical Polynomial Semiring in no variables over {self.base_ring().base_ring()}" + return f"Multivariate Tropical Polynomial Semiring in {', '.join(self.variable_names())} over {self.base_ring().base_ring()}" def random_element(self, degree=2, terms=None, choose_degree=False, *args, **kwargs): r""" diff --git a/src/sage/rings/semirings/tropical_polynomial.py b/src/sage/rings/semirings/tropical_polynomial.py index 2fe8ce7fa51..9df951c9cd7 100644 --- a/src/sage/rings/semirings/tropical_polynomial.py +++ b/src/sage/rings/semirings/tropical_polynomial.py @@ -748,7 +748,7 @@ def _repr_(self): sage: R. = PolynomialRing(T); R Univariate Tropical Polynomial Semiring in abc over Integer Ring """ - return f"Univariate Tropical Polynomial Semiring in {self.variable_name()}" f" over {self.base_ring().base_ring()}" + return f"Univariate Tropical Polynomial Semiring in {self.variable_name()} over {self.base_ring().base_ring()}" def gen(self, n=0): """ diff --git a/src/sage/sat/boolean_polynomials.py b/src/sage/sat/boolean_polynomials.py index dc59c8a25c6..61fcce899a9 100644 --- a/src/sage/sat/boolean_polynomials.py +++ b/src/sage/sat/boolean_polynomials.py @@ -13,6 +13,7 @@ Functions ^^^^^^^^^ """ + # ########################################################################### # Copyright (C) 2012 Martin Albrecht # Distributed under the terms of the GNU General Public License (GPL) diff --git a/src/sage/sat/solvers/sat_lp.py b/src/sage/sat/solvers/sat_lp.py index bf000d2f963..7ca989637c9 100644 --- a/src/sage/sat/solvers/sat_lp.py +++ b/src/sage/sat/solvers/sat_lp.py @@ -7,6 +7,7 @@ can be expected to be slower than when using :class:`~sage.sat.solvers.cryptominisat.cryptominisat.CryptoMiniSat`. """ + from sage.numerical.mip import MIPSolverException, MixedIntegerLinearProgram from sage.sat.solvers.satsolver import SatSolver diff --git a/src/sage/schemes/affine/affine_morphism.py b/src/sage/schemes/affine/affine_morphism.py index 7150efca79b..705f23a340e 100644 --- a/src/sage/schemes/affine/affine_morphism.py +++ b/src/sage/schemes/affine/affine_morphism.py @@ -1024,7 +1024,6 @@ def degree(self): class SchemeMorphism_polynomial_affine_space_field(SchemeMorphism_polynomial_affine_space): - @cached_method def weil_restriction(self): r""" @@ -1322,7 +1321,6 @@ def image(self): class SchemeMorphism_polynomial_affine_space_finite_field(SchemeMorphism_polynomial_affine_space_field): - def _fast_eval(self, x): """ Evaluate affine morphism at point described by ``x``. diff --git a/src/sage/schemes/affine/affine_point.py b/src/sage/schemes/affine/affine_point.py index 46378e5dbc7..1f015fba7aa 100644 --- a/src/sage/schemes/affine/affine_point.py +++ b/src/sage/schemes/affine/affine_point.py @@ -238,7 +238,6 @@ def homogenize(self, n): class SchemeMorphism_point_affine_field(SchemeMorphism_point_affine): - def __hash__(self): r""" Compute the hash value of this affine point. @@ -428,7 +427,6 @@ def as_subscheme(self): class SchemeMorphism_point_affine_finite_field(SchemeMorphism_point_affine_field): - def __hash__(self): r""" Return the integer hash of the point. diff --git a/src/sage/schemes/berkovich/berkovich_cp_element.py b/src/sage/schemes/berkovich/berkovich_cp_element.py index 6e53f63b6bc..e874c524493 100644 --- a/src/sage/schemes/berkovich/berkovich_cp_element.py +++ b/src/sage/schemes/berkovich/berkovich_cp_element.py @@ -99,7 +99,7 @@ def __init__(self, parent, center, radius=None, power=None, prec=20, space_type= if not isinstance(center, (list, tuple)): raise TypeError("center was passed a list but radius was not a list") if len(radius) != len(center): - raise ValueError("the same number of centers and radii " "must be specified to create " "a type IV point") + raise ValueError("the same number of centers and radii must be specified to create a type IV point") self._center_lst = list(center) self._radius_lst = list(radius) self._prec = len(self._radius_lst) diff --git a/src/sage/schemes/berkovich/berkovich_space.py b/src/sage/schemes/berkovich/berkovich_space.py index 9493391ac35..57298318183 100644 --- a/src/sage/schemes/berkovich/berkovich_space.py +++ b/src/sage/schemes/berkovich/berkovich_space.py @@ -419,7 +419,7 @@ def __init__(self, base, ideal=None): ideal = None self._base_type = 'padic field' else: - raise ValueError("base of Berkovich Space must be a padic field " "or a number field") + raise ValueError("base of Berkovich Space must be a padic field or a number field") self._ideal = ideal self._p = prime Parent.__init__(self, base=base, category=TopologicalSpaces()) @@ -595,7 +595,7 @@ def __init__(self, base, ideal=None): raise ValueError("base of projective Berkovich space must be projective space") if not isinstance(base.base_ring(), sage.rings.abc.pAdicField): if base.base_ring() not in NumberFields(): - raise ValueError("base of projective Berkovich space must be " "projective space over Qp or a number field") + raise ValueError("base of projective Berkovich space must be projective space over Qp or a number field") else: if ideal is None: raise ValueError('passed a number field but not an ideal') @@ -617,7 +617,7 @@ def __init__(self, base, ideal=None): ideal = None self._base_type = 'padic field' if base.dimension_relative() != 1: - raise ValueError("base of projective Berkovich space must be " "projective space of dimension 1 over Qp or a number field") + raise ValueError("base of projective Berkovich space must be projective space of dimension 1 over Qp or a number field") self._p = prime self._ideal = ideal Parent.__init__(self, base=base, category=TopologicalSpaces()) diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index b60bf224574..bf283279494 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -1010,7 +1010,7 @@ def projection(self, indices, AS=None): indices = [int(i) for i in indices] # type checking indices.sort() if indices[0] < 0 or indices[-1] > n - 1: - raise ValueError("index values must be between 0 and one " "minus the dimension of the ambient space " "of this curve") + raise ValueError("index values must be between 0 and one minus the dimension of the ambient space of this curve") # construct the projection map if AS is None: AA2 = AffineSpace(self.base_ring(), len(indices)) @@ -1587,7 +1587,7 @@ def extension(self): if C.is_smooth(): raise TypeError("this curve is already nonsingular") else: - raise TypeError("this curve has no singular points over " "its base field. If working over " "a number field use extend=True") + raise TypeError("this curve has no singular points over its base field. If working over a number field use extend=True") not_resolved = True t = 0 # loop through the patches and blow up each until no patch has singular points @@ -1922,7 +1922,7 @@ def braid_monodromy(self): from sage.rings.qqbar import QQbar if QQbar.coerce_map_from(F) is None: - raise NotImplementedError("the base field must have an embedding" " to the algebraic field") + raise NotImplementedError("the base field must have an embedding to the algebraic field") f = self.defining_polynomial() return braid_monodromy(f)[0] diff --git a/src/sage/schemes/curves/constructor.py b/src/sage/schemes/curves/constructor.py index db36e3d91ba..d238fac1eeb 100644 --- a/src/sage/schemes/curves/constructor.py +++ b/src/sage/schemes/curves/constructor.py @@ -272,7 +272,7 @@ def Curve(F, A=None): A._coordinate_ring = P elif F.parent().ngens() == 1: if not F.is_zero(): - raise ValueError("defining polynomial of curve must be zero " "if the ambient space is of dimension 1") + raise ValueError("defining polynomial of curve must be zero if the ambient space is of dimension 1") A = AffineSpace(1, P.base_ring(), names=P.variable_names()) A._coordinate_ring = P diff --git a/src/sage/schemes/curves/curve.py b/src/sage/schemes/curves/curve.py index 21a47235f1b..22459872b50 100644 --- a/src/sage/schemes/curves/curve.py +++ b/src/sage/schemes/curves/curve.py @@ -109,10 +109,10 @@ def _latex_(self): """ if self.defining_ideal().is_zero() and self.ambient_space().dimension() == 1: ambient_type, ring = self._repr_type(), latex(self.base_ring()) - return fr"\text{{{ambient_type} line over ${ring}$}}" + return rf"\text{{{ambient_type} line over ${ring}$}}" ambient_type, ring = self._repr_type(), latex(self.base_ring()) polys = ', '.join(f'${latex(p)}$' for p in self.defining_polynomials()) - return fr"\text{{{ambient_type} curve over ${ring}$ defined by {polys}}}" + return rf"\text{{{ambient_type} curve over ${ring}$ defined by {polys}}}" def dimension(self): r""" @@ -493,7 +493,7 @@ def intersection_points(self, C, F=None): F = self.base_ring() if X.dimension() == 0 or F in FiniteFields(): return X.rational_points(F=F) - raise NotImplementedError("the intersection must have dimension " "zero or (={}) must be a finite field".format(F)) + raise NotImplementedError("the intersection must have dimension zero or (={}) must be a finite field".format(F)) def change_ring(self, R): r""" diff --git a/src/sage/schemes/curves/point.py b/src/sage/schemes/curves/point.py index 44ed255e4ed..5e86deda06b 100644 --- a/src/sage/schemes/curves/point.py +++ b/src/sage/schemes/curves/point.py @@ -24,6 +24,7 @@ - Grayson Jorgenson (2016-6): initial version """ + # **************************************************************************** # Copyright (C) 2005 William Stein # @@ -251,7 +252,6 @@ class IntegralProjectivePlaneCurvePoint_finite_field(ProjectivePlaneCurvePoint_f class AffineCurvePoint_field(SchemeMorphism_point_affine_field): - def is_singular(self) -> bool: r""" Return whether this point is a singular point of the affine curve it is on. diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index bdeace202c1..6df49a89529 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -1816,7 +1816,7 @@ def fundamental_group(self): from sage.rings.qqbar import QQbar if QQbar.coerce_map_from(F) is None: - raise NotImplementedError("the base field must have an embedding" " to the algebraic field") + raise NotImplementedError("the base field must have an embedding to the algebraic field") g = self.defining_polynomial() ring = self.ambient_space().affine_patch(2).coordinate_ring() if g.degree() == 1: diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py index 353cb5e7191..7f9f2476522 100644 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -32,6 +32,7 @@ sage: fundamental_group(f) Finitely presented group < x0 | > """ + # **************************************************************************** # Copyright (C) 2015 Miguel Marco # diff --git a/src/sage/schemes/cyclic_covers/charpoly_frobenius.py b/src/sage/schemes/cyclic_covers/charpoly_frobenius.py index 86cebd47903..3ada616021c 100644 --- a/src/sage/schemes/cyclic_covers/charpoly_frobenius.py +++ b/src/sage/schemes/cyclic_covers/charpoly_frobenius.py @@ -2,6 +2,7 @@ r""" Computation of the Frobenius polynomial using Newton's identities """ + # ***************************************************************************** # Copyright (C) 2018 Edgar Costa # Distributed under the terms of the GNU General Public License (GPL) diff --git a/src/sage/schemes/cyclic_covers/constructor.py b/src/sage/schemes/cyclic_covers/constructor.py index c3fe2684248..2bd67f9f0bc 100644 --- a/src/sage/schemes/cyclic_covers/constructor.py +++ b/src/sage/schemes/cyclic_covers/constructor.py @@ -109,14 +109,14 @@ def CyclicCover(r, f, names=None, check_smooth=True): f = P(f) if check_smooth: if P(r) == 0: - raise ValueError("As the characteristic divides the order of the cover, " "this model is not smooth.") + raise ValueError("As the characteristic divides the order of the cover, this model is not smooth.") try: smooth = f.is_squarefree() except NotImplementedError as err: - raise NotImplementedError(str(err) + "Use " "check_smooth=False to skip this check.") + raise NotImplementedError(str(err) + "Use check_smooth=False to skip this check.") if not smooth: - raise ValueError("Not a smooth Cyclic Cover of P^1: " "singularity in the provided affine patch.") + raise ValueError("Not a smooth Cyclic Cover of P^1: singularity in the provided affine patch.") R = P.base_ring() if names is None: names = ["x", "y"] diff --git a/src/sage/schemes/elliptic_curves/cardinality.py b/src/sage/schemes/elliptic_curves/cardinality.py index 64e9150eac5..6f71e51e766 100644 --- a/src/sage/schemes/elliptic_curves/cardinality.py +++ b/src/sage/schemes/elliptic_curves/cardinality.py @@ -11,6 +11,7 @@ - Jeroen Demeyer (2017-2018): Refactored and moved to ``cardinality.py``. """ + # **************************************************************************** # Copyright (C) 2008-2009 John Cremona # diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index 3299b669ac3..5527b7773b9 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -438,7 +438,6 @@ def compute_codomain_kohel(E, kernel): psi_2tor = two_torsion_part(E, psi) if psi_2tor.degree() != 0: # even degree case - psi_quo = psi // psi_2tor if psi_quo.degree() != 0: @@ -447,7 +446,6 @@ def compute_codomain_kohel(E, kernel): n = psi_2tor.degree() if n == 1: # degree divisible exactly by 2 - a1, a2, a3, a4, a6 = E.a_invariants() x0 = -psi_2tor.constant_coefficient() @@ -463,7 +461,6 @@ def compute_codomain_kohel(E, kernel): v, w = compute_vw_kohel_even_deg1(x0, y0, a1, a2, a4) elif n == 3: # psi_2tor is the full 2-division polynomial - b2, b4, _, _ = E.b_invariants() s1 = -psi_2tor[n - 1] @@ -473,7 +470,6 @@ def compute_codomain_kohel(E, kernel): v, w = compute_vw_kohel_even_deg3(b2, b4, s1, s2, s3) else: # odd degree case - n = psi.degree() b2, b4, b6, _ = E.b_invariants() @@ -1050,7 +1046,6 @@ def __init__(self, E, kernel, codomain=None, degree=None, model=None, check=True self.__check = check if kernel is None and codomain is not None: - if degree is None: raise ValueError("degree must be given when specifying isogeny by domain and codomain") @@ -1471,7 +1466,7 @@ def _latex_(self): '\\left( \\frac{x^{2} + 11 x + 7}{x + 11} , \\frac{x^{2} y + 5 x y + 12 y}{x^{2} + 5 x + 2} \\right)' """ fx, fy = self.rational_maps() - return fr'\left( {fx._latex_()} , {fy._latex_()} \right)' + return rf'\left( {fx._latex_()} , {fy._latex_()} \right)' ########################### # Private Common Functions @@ -2021,7 +2016,6 @@ def __init_from_kernel_list(self): to Elliptic Curve defined by y^2 = x^3 + 2*x over Finite Field of size 7 """ for Q in self.__kernel_list: - if Q.is_zero(): continue @@ -2296,7 +2290,6 @@ def __init_from_kernel_polynomial(self, kernel_polynomial): psi_G = two_torsion_part(E, psi).monic() if psi_G.degree() != 0: # even degree case - psi_quo = psi // psi_G if psi_quo.degree() != 0: @@ -2305,7 +2298,6 @@ def __init_from_kernel_polynomial(self, kernel_polynomial): phi, omega, v, w, _, d = self.__init_even_kernel_polynomial(E, psi_G) else: # odd degree case - phi, omega, v, w, _, d = self.__init_odd_kernel_polynomial(E, psi) # diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index e62ded9c8d1..a41751c6c2b 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -30,7 +30,6 @@ class EllipticCurve_field(ell_generic.EllipticCurve_generic, ProjectivePlaneCurve_field): - def __init__(self, R, data, category=None) -> None: r""" Constructor for elliptic curves over fields. diff --git a/src/sage/schemes/elliptic_curves/ell_finite_field.py b/src/sage/schemes/elliptic_curves/ell_finite_field.py index befa3fbee3e..9bcf955a1e8 100644 --- a/src/sage/schemes/elliptic_curves/ell_finite_field.py +++ b/src/sage/schemes/elliptic_curves/ell_finite_field.py @@ -644,7 +644,6 @@ def van_tuyl(N): chi_mod_N = chi.change_ring(GF(N)) if roots := chi_mod_N.roots(multiplicities=False): - if len(roots) == 1: # repeated root assert F(N) dstar = roots[0].multiplicative_order() @@ -1116,7 +1115,6 @@ def abelian_group(self): assert len(gens) <= 2 if len(gens) == 2: - P, Q = gens n = self.cardinality() # cached n1 = P.order() # cached diff --git a/src/sage/schemes/elliptic_curves/ell_generic.py b/src/sage/schemes/elliptic_curves/ell_generic.py index e5589254169..04d995df6dc 100644 --- a/src/sage/schemes/elliptic_curves/ell_generic.py +++ b/src/sage/schemes/elliptic_curves/ell_generic.py @@ -2497,7 +2497,7 @@ def multiplication_by_m(self, m, x_only=False): if p != 0 and m % p == 0 and not isinstance(self.base_ring(), FiniteField_generic): # TODO: Implement the correct formula? - raise NotImplementedError("multiplication by integer not coprime to p " "is only implemented for curves over finite fields") + raise NotImplementedError("multiplication by integer not coprime to p is only implemented for curves over finite fields") x, y = polygens(self.base_ring(), 'x,y') # Special case of multiplication by 1 is easy. diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index 515d9c2a182..bef88550e55 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -830,8 +830,8 @@ def _compute_order(self, algorithm): lb = ub + 1 sqrt_ub *= 4 elif algorithm is None: - raise NotImplementedError("default algorithm not available for order of a point on " "an elliptic curve over general fields; you may try algorithm=generic_small " "if you are sure the order is finite and small") - raise NotImplementedError(f"algorithm {algorithm!r} not implemented for " "order of a point on an elliptic curve over general fields") + raise NotImplementedError("default algorithm not available for order of a point on an elliptic curve over general fields; you may try algorithm=generic_small if you are sure the order is finite and small") + raise NotImplementedError(f"algorithm {algorithm!r} not implemented for order of a point on an elliptic curve over general fields") additive_order = order @@ -1666,7 +1666,6 @@ def ffext(poly): coercion = F.hom(F) for q, e in d.factor(): for _ in range(e): - f = P.division_points(q, poly_only=True) try: x = f.any_root(assume_squarefree=True) @@ -3815,7 +3814,6 @@ def archimedean_local_height(self, v=None, prec=None, weighted=False): K = E.base_ring() if v is None: - if prec is None: prec = 53 if K is QQ: @@ -4426,7 +4424,7 @@ def padic_elliptic_logarithm(self, p, absprec=20): try: x, y = P.xy() except ZeroDivisionError: - raise ValueError("Insufficient precision in " "p-adic_elliptic_logarithm()") + raise ValueError("Insufficient precision in p-adic_elliptic_logarithm()") if debug: print("x,y=", (x, y)) if x.valuation() >= 0: # P is still not in E^1 @@ -4444,7 +4442,7 @@ def padic_elliptic_logarithm(self, p, absprec=20): try: x, y = P.xy() except ZeroDivisionError: - raise ValueError("Insufficient precision in " "p-adic_elliptic_logarithm()") + raise ValueError("Insufficient precision in p-adic_elliptic_logarithm()") if debug: print("f=", f) print("x,y=", (x, y)) @@ -4452,11 +4450,11 @@ def padic_elliptic_logarithm(self, p, absprec=20): vy = y.valuation() v = vx - vy if not (v > 0 and vx == -2 * v and vy == -3 * v): - raise ValueError("Insufficient precision in " "p-adic_elliptic_logarithm()") + raise ValueError("Insufficient precision in p-adic_elliptic_logarithm()") try: t = -x / y except (ZeroDivisionError, PrecisionError): - raise ValueError("Insufficient precision in " "p-adic_elliptic_logarithm()") + raise ValueError("Insufficient precision in p-adic_elliptic_logarithm()") if debug: print("t=", t, ", with valuation ", v) phi = Ep.formal().log(prec=1 + absprec // v) @@ -4515,7 +4513,7 @@ def _acted_upon_(self, other, side): N = val.mod() N1 = N.gcd(a) N2 = N // N1 - raise ZeroDivisionError(f"Inverse of {a} does not exist" f" (characteristic = {N} = {N1}*{N2})") + raise ZeroDivisionError(f"Inverse of {a} does not exist (characteristic = {N} = {N1}*{N2})") pariQ = None if pariQ is not None: @@ -4982,6 +4980,6 @@ def _compute_order(self, algorithm): if algorithm in ('generic_small', 'hybrid'): return super()._compute_order(algorithm) - raise NotImplementedError(f"algorithm {algorithm!r} not implemented for " "order of a point on an elliptic curve over finite fields") + raise NotImplementedError(f"algorithm {algorithm!r} not implemented for order of a point on an elliptic curve over finite fields") additive_order = order diff --git a/src/sage/schemes/elliptic_curves/ell_tate_curve.py b/src/sage/schemes/elliptic_curves/ell_tate_curve.py index 616f8d00823..751247156e0 100644 --- a/src/sage/schemes/elliptic_curves/ell_tate_curve.py +++ b/src/sage/schemes/elliptic_curves/ell_tate_curve.py @@ -377,7 +377,7 @@ def L_invariant(self, prec=20): 5^3 + 4*5^4 + 2*5^5 + 2*5^6 + 2*5^7 + 3*5^8 + 5^9 + O(5^10) """ if not self.is_split(): - raise RuntimeError("the curve must have split multiplicative " "reduction") + raise RuntimeError("the curve must have split multiplicative reduction") qE = self.parameter(prec=prec) n = qE.valuation() u = qE / self._p**n @@ -410,7 +410,7 @@ def _isomorphism(self, prec=20): 2 + 5 + 3*5^2 + 5^3 + 5^4 + O(5^5)] """ if not self.is_split(): - raise RuntimeError("the curve must have split multiplicative " "reduction") + raise RuntimeError("the curve must have split multiplicative reduction") C = self._Csquare(prec=prec + 4).sqrt() R = Qp(self._p, prec) C = R(C) @@ -444,7 +444,7 @@ def _inverse_isomorphism(self, prec=20): 1 + 5 + 4*5^3 + 2*5^4 + O(5^5), 5 + 2*5^2 + 3*5^4 + O(5^5)] """ if not self.is_split(): - raise RuntimeError("the curve must have split multiplicative " "reduction") + raise RuntimeError("the curve must have split multiplicative reduction") u, r, s, t = self._isomorphism(prec=prec) return [1 / u, -r / u**2, -s / u, (r * s - t) / u**3] @@ -539,7 +539,7 @@ def parametrisation_onto_original_curve(self, u, prec=None): (0 : 1 + O(5^30) : 0) """ if not self.is_split(): - raise ValueError("the curve must have split multiplicative " "reduction.") + raise ValueError("the curve must have split multiplicative reduction.") if prec is None: prec = getattr(u, "precision_relative", lambda: 20)() @@ -584,7 +584,7 @@ def padic_height(self, prec=20): O(5^9) """ if not self.is_split(): - raise NotImplementedError("the p-adic height is not implemented " "for non-split multiplicative reduction.") + raise NotImplementedError("the p-adic height is not implemented for non-split multiplicative reduction.") p = self._p @@ -639,7 +639,7 @@ def padic_regulator(self, prec=20): return K.one() if not self.is_split(): - raise NotImplementedError("the p-adic regulator is not implemented " "for non-split multiplicative reduction.") + raise NotImplementedError("the p-adic regulator is not implemented for non-split multiplicative reduction.") basis = self._E.gens() M = matrix(K, rank, rank, 0) diff --git a/src/sage/schemes/elliptic_curves/gal_reps_number_field.py b/src/sage/schemes/elliptic_curves/gal_reps_number_field.py index 0750f2fcbab..84c3f813b3d 100644 --- a/src/sage/schemes/elliptic_curves/gal_reps_number_field.py +++ b/src/sage/schemes/elliptic_curves/gal_reps_number_field.py @@ -716,7 +716,7 @@ def _exceptionals(E, L, patience=1000): if det != 0: # c.f. [Ser1972], Section 2.8, Prop. 19 u = trace**2 / det - if u not in (1, 2, 4) and u ** 2 - 3 * u + 1 != 0: + if u not in (1, 2, 4) and u**2 - 3 * u + 1 != 0: D[l][2] = False if D[l] == [False, False, False]: diff --git a/src/sage/schemes/elliptic_curves/gp_simon.py b/src/sage/schemes/elliptic_curves/gp_simon.py index 3459a875e4a..c21083f216b 100644 --- a/src/sage/schemes/elliptic_curves/gp_simon.py +++ b/src/sage/schemes/elliptic_curves/gp_simon.py @@ -2,6 +2,7 @@ """ Denis Simon's PARI scripts """ + # **************************************************************************** # Copyright (C) 2005 William Stein # diff --git a/src/sage/schemes/elliptic_curves/height.py b/src/sage/schemes/elliptic_curves/height.py index 1871df87af4..61f6f8c3bdd 100644 --- a/src/sage/schemes/elliptic_curves/height.py +++ b/src/sage/schemes/elliptic_curves/height.py @@ -679,7 +679,6 @@ def rat_term_CIF(z, try_strict=True): # determined by their values at the endpoints. if try_strict: - # evaluate the function at the four corners: corner_reals = [] @@ -1745,7 +1744,6 @@ def complex_intersection_is_empty(self, Bk, v, verbose=False, use_half=True): print("trying to prove positive result...") intersection = None for B, n in sorted(zip(bounds, ZZ.range(1, k + 1))): - T = PeriodicRegion(CDF(1), CDF(tau), vals < B, full=not use_half).expand().refine() B = RIF(B) leaning_right = tau.real() / tau.imag() >= 0 diff --git a/src/sage/schemes/elliptic_curves/hom_composite.py b/src/sage/schemes/elliptic_curves/hom_composite.py index 6a1ce4dfe15..5a18d310814 100644 --- a/src/sage/schemes/elliptic_curves/hom_composite.py +++ b/src/sage/schemes/elliptic_curves/hom_composite.py @@ -306,7 +306,6 @@ def _compute_factored_isogeny(kernel, velu_sqrt_bound=None): class EllipticCurveHom_composite(EllipticCurveHom): - _degree = None _phis = None @@ -592,10 +591,10 @@ def _repr_(self): degs = [phi.degree() for phi in self._phis] if len(degs) == 1: - return f'Composite morphism of degree {self._degree}:' f'\n From: {self._domain}' f'\n To: {self._codomain}' + return f'Composite morphism of degree {self._degree}:\n From: {self._domain}\n To: {self._codomain}' grouped = [(d, sum(1 for _ in g)) for d, g in groupby(degs)] degs_str = '*'.join(str(d) + (f'^{e}' if e > 1 else '') for d, e in grouped) - return f'Composite morphism of degree {self._degree} = {degs_str}:' f'\n From: {self._domain}' f'\n To: {self._codomain}' + return f'Composite morphism of degree {self._degree} = {degs_str}:\n From: {self._domain}\n To: {self._codomain}' def factors(self): r""" diff --git a/src/sage/schemes/elliptic_curves/hom_fractional.py b/src/sage/schemes/elliptic_curves/hom_fractional.py index e57f0596bbc..58d666097e6 100644 --- a/src/sage/schemes/elliptic_curves/hom_fractional.py +++ b/src/sage/schemes/elliptic_curves/hom_fractional.py @@ -274,7 +274,7 @@ def _repr_(self) -> str: To: Elliptic Curve defined by y^2 = x^3 + 9*x over Finite Field of size 13) Denominator: 2 """ - return f'Fractional elliptic-curve morphism of degree {self._degree}:' f'\n Numerator: {self._phi}' f'\n Denominator: {self._d}' + return f'Fractional elliptic-curve morphism of degree {self._degree}:\n Numerator: {self._phi}\n Denominator: {self._d}' @cached_method def to_isogeny_chain(self): diff --git a/src/sage/schemes/elliptic_curves/hom_frobenius.py b/src/sage/schemes/elliptic_curves/hom_frobenius.py index 7a1bb347aeb..f67cfed1d12 100644 --- a/src/sage/schemes/elliptic_curves/hom_frobenius.py +++ b/src/sage/schemes/elliptic_curves/hom_frobenius.py @@ -166,7 +166,6 @@ class EllipticCurveHom_frobenius(EllipticCurveHom): - _degree = None def __init__(self, E, power=1): @@ -303,7 +302,7 @@ def _repr_(self): """ kind = 'endomorphism' if self._codomain == self._domain else 'isogeny' degs_str = '' if self._n == 1 else f' = {self._p}^{self._n}' - return f'Frobenius {kind} of degree {self._degree}{degs_str}:' f'\n From: {self._domain}' f'\n To: {self._codomain}' + return f'Frobenius {kind} of degree {self._degree}{degs_str}:\n From: {self._domain}\n To: {self._codomain}' # EllipticCurveHom methods diff --git a/src/sage/schemes/elliptic_curves/hom_scalar.py b/src/sage/schemes/elliptic_curves/hom_scalar.py index d268d429086..48be0b1f381 100644 --- a/src/sage/schemes/elliptic_curves/hom_scalar.py +++ b/src/sage/schemes/elliptic_curves/hom_scalar.py @@ -146,7 +146,6 @@ class EllipticCurveHom_scalar(EllipticCurveHom): - def __init__(self, E, m): """ Construct a scalar-multiplication map on an elliptic curve. diff --git a/src/sage/schemes/elliptic_curves/hom_sum.py b/src/sage/schemes/elliptic_curves/hom_sum.py index 2430af96e58..e44dae4d569 100644 --- a/src/sage/schemes/elliptic_curves/hom_sum.py +++ b/src/sage/schemes/elliptic_curves/hom_sum.py @@ -59,7 +59,6 @@ class EllipticCurveHom_sum(EllipticCurveHom): - _degree = None _phis = None @@ -176,7 +175,7 @@ def _repr_(self): To: Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101 Via: (Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101, Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101) """ - return f'Sum morphism:' f'\n From: {self._domain}' f'\n To: {self._codomain}' f'\n Via: {self._phis}' + return f'Sum morphism:\n From: {self._domain}\n To: {self._codomain}\n Via: {self._phis}' def summands(self): r""" diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index e11e352b181..29312bb48ce 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -1005,7 +1005,7 @@ def _repr_(self): From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 71 To: Elliptic Curve defined by y^2 = x^3 + 19*x + 45 over Finite Field of size 71 """ - return f'Elliptic-curve isogeny (using square-root Vélu) of degree {self._degree}:' f'\n From: {self._domain}' f'\n To: {self._codomain}' + return f'Elliptic-curve isogeny (using square-root Vélu) of degree {self._degree}:\n From: {self._domain}\n To: {self._codomain}' @staticmethod def _comparison_impl(left, right, op): diff --git a/src/sage/schemes/elliptic_curves/isogeny_class.py b/src/sage/schemes/elliptic_curves/isogeny_class.py index ecbaf8c903f..0202a5f2062 100644 --- a/src/sage/schemes/elliptic_curves/isogeny_class.py +++ b/src/sage/schemes/elliptic_curves/isogeny_class.py @@ -1261,7 +1261,6 @@ def isogeny_degrees_cm(E, verbose=False): print("ramified primes: %s" % L1) else: - # "Upward" primes (index divided by l): L1 = Set([l for l in ram_l if d.valuation(l) > 1]) diff --git a/src/sage/schemes/elliptic_curves/padics.py b/src/sage/schemes/elliptic_curves/padics.py index d40f2c452df..2a98974015e 100644 --- a/src/sage/schemes/elliptic_curves/padics.py +++ b/src/sage/schemes/elliptic_curves/padics.py @@ -621,7 +621,7 @@ def _multiple_to_make_good_reduction(E): 4 """ if not E.is_integral(): - st = "This only implemented for integral models. " "Please change the model first." + st = "This only implemented for integral models. Please change the model first." raise NotImplementedError(st) if E.is_minimal(): n2 = LCM(E.tamagawa_numbers()) @@ -821,7 +821,7 @@ def height(P, check=True): return K(0) if check: - assert P.curve() == E, "the point P must lie on the curve " "from which the height function was created" + assert P.curve() == E, "the point P must lie on the curve from which the height function was created" Q = n2 * P alpha, beta, d = _multiply_point(E, R, Q, m) @@ -845,7 +845,7 @@ def height(P, check=True): answer = -total.log() * 2 / n**2 if check: - assert answer.precision_absolute() >= prec, "we should have got an " "answer with precision at least prec, but we didn't." + assert answer.precision_absolute() >= prec, "we should have got an answer with precision at least prec, but we didn't." return K(answer) # (man... I love python's local function definitions...) @@ -964,7 +964,7 @@ def height(P, check=True): return K(0) if check: - assert P.curve() == E, "the point P must lie on the curve " "from which the height function was created" + assert P.curve() == E, "the point P must lie on the curve from which the height function was created" Q = n2 * P alpha, beta, d = _multiply_point(E, R, Q, m * p**lamb) @@ -988,7 +988,7 @@ def height(P, check=True): answer = -total.log() * 2 / (n * p**lamb) ** 2 if check: - assert answer.precision_absolute() >= prec, "we should have got an " "answer with precision at least prec, but we didn't." + assert answer.precision_absolute() >= prec, "we should have got an answer with precision at least prec, but we didn't." return K(answer) # (man... I love python's local function definitions...) @@ -1647,7 +1647,7 @@ def matrix_of_frobenius(self, p, prec=20, check=False, check_hypotheses=True, al # TODO change the basis back to the original equation. X = self.minimal_model().short_weierstrass_model() - assert X.discriminant().valuation(p) == 0, "Something's gone wrong. " "The discriminant of the Weierstrass model should be a unit " " at p." + assert X.discriminant().valuation(p) == 0, "Something's gone wrong. The discriminant of the Weierstrass model should be a unit at p." if algorithm == "standard": # Need to increase precision a little to compensate for precision diff --git a/src/sage/schemes/elliptic_curves/period_lattice.py b/src/sage/schemes/elliptic_curves/period_lattice.py index 2eaa5b74ee5..5e74e9dac9b 100644 --- a/src/sage/schemes/elliptic_curves/period_lattice.py +++ b/src/sage/schemes/elliptic_curves/period_lattice.py @@ -1194,7 +1194,7 @@ def is_approximate(self): """ from sage.misc.superseded import deprecation - deprecation(39212, "The attribute is_approximate for period lattice is " "deprecated, use self.curve().is_exact() instead.") + deprecation(39212, "The attribute is_approximate for period lattice is deprecated, use self.curve().is_exact() instead.") return not self._is_exact def ei(self): @@ -1518,7 +1518,6 @@ def e_log_RC(self, xP, yP, prec=None, reduce=True): # commented out below. if self.real_flag == 0: # complex case - a = C((e1 - e3).sqrt()) b = C((e1 - e2).sqrt()) if (a + b).abs() < (a - b).abs(): diff --git a/src/sage/schemes/elliptic_curves/sha_tate.py b/src/sage/schemes/elliptic_curves/sha_tate.py index 477fb30d3a4..eb645b0f4d6 100644 --- a/src/sage/schemes/elliptic_curves/sha_tate.py +++ b/src/sage/schemes/elliptic_curves/sha_tate.py @@ -1019,7 +1019,6 @@ def bound_kolyvagin(self, D=0, regulator=None, ignore_nonsurj_hypothesis=False): I = RIF(alpha) * RIF(LE1 - err_E, LE1 + err_E) * RIF(LF1 - err_F, LF1 + err_F) / RIF(hZ) else: # E has odd rank - if regulator is not None: hZ = regulator / 2 else: diff --git a/src/sage/schemes/elliptic_curves/weierstrass_transform.py b/src/sage/schemes/elliptic_curves/weierstrass_transform.py index da19fe5e511..536ffbf9d6b 100644 --- a/src/sage/schemes/elliptic_curves/weierstrass_transform.py +++ b/src/sage/schemes/elliptic_curves/weierstrass_transform.py @@ -54,7 +54,6 @@ class WeierstrassTransformation(SchemeMorphism_polynomial): - def __init__(self, domain, codomain, defining_polynomials, post_multiplication): r""" A morphism of a genus-one curve to/from the Weierstrass form. @@ -171,7 +170,6 @@ def WeierstrassTransformationWithInverse(domain, codomain, defining_polynomials, class WeierstrassTransformationWithInverse_class(WeierstrassTransformation): - def inverse(self): """ Return the inverse. diff --git a/src/sage/schemes/generic/algebraic_scheme.py b/src/sage/schemes/generic/algebraic_scheme.py index 879a30bf621..1a08b0f5609 100644 --- a/src/sage/schemes/generic/algebraic_scheme.py +++ b/src/sage/schemes/generic/algebraic_scheme.py @@ -648,7 +648,7 @@ def _repr_(self): t = "affine" else: t = "projective" - return "Quasi-%s subscheme X - Y of %s, where X is defined by:\n%s\n" "and Y is defined by:\n%s" % ( + return "Quasi-%s subscheme X - Y of %s, where X is defined by:\n%s\nand Y is defined by:\n%s" % ( t, self.ambient_space(), str(self.__X).split("\n", 1)[1], @@ -885,7 +885,7 @@ def __init__(self, A, polynomials, category=None): try: polynomials[n] = R(f) except TypeError: - raise TypeError("%s cannot be converted to a polynomial in " "the coordinate ring of this %s!" % (f, A)) + raise TypeError("%s cannot be converted to a polynomial in the coordinate ring of this %s!" % (f, A)) polynomials = tuple(polynomials) self.__polys = A._validate(polynomials) @@ -1075,7 +1075,7 @@ def normalize_defining_polynomials(self): self.__polys = tuple(normalized_polys) else: - raise NotImplementedError("currently normalization is implemented " "only for QQbar, number fields and " "number field orders") + raise NotImplementedError("currently normalization is implemented only for QQbar, number fields and number field orders") def defining_ideal(self): """ diff --git a/src/sage/schemes/generic/ambient_space.py b/src/sage/schemes/generic/ambient_space.py index e07f856e7eb..20952832dcb 100644 --- a/src/sage/schemes/generic/ambient_space.py +++ b/src/sage/schemes/generic/ambient_space.py @@ -136,7 +136,7 @@ def _validate(self, polynomials): ... NotImplementedError: ambient spaces must override "_validate" method! """ - raise NotImplementedError('ambient spaces must override "_validate" ' 'method!') + raise NotImplementedError('ambient spaces must override "_validate" method!') def change_ring(self, R): r""" diff --git a/src/sage/schemes/generic/scheme.py b/src/sage/schemes/generic/scheme.py index f84432b66ac..089396b814b 100644 --- a/src/sage/schemes/generic/scheme.py +++ b/src/sage/schemes/generic/scheme.py @@ -94,7 +94,7 @@ def __init__(self, X=None, category=None): # X is a morphism of Rings self._base_ring = X.codomain() else: - raise ValueError('The base must be defined by a scheme, ' 'scheme morphism, or commutative ring.') + raise ValueError('The base must be defined by a scheme, scheme morphism, or commutative ring.') from sage.categories.schemes import Schemes diff --git a/src/sage/schemes/hyperelliptic_curves/invariants.py b/src/sage/schemes/hyperelliptic_curves/invariants.py index 974b4cdd83f..fb08fb6aed6 100644 --- a/src/sage/schemes/hyperelliptic_curves/invariants.py +++ b/src/sage/schemes/hyperelliptic_curves/invariants.py @@ -296,7 +296,7 @@ def clebsch_invariants(f): """ R = f.parent().base_ring() if R.characteristic() in [2, 3, 5]: - raise NotImplementedError("Invariants of binary sextics/genus 2 hyperelliptic " "curves not implemented in characteristics 2, 3, and 5") + raise NotImplementedError("Invariants of binary sextics/genus 2 hyperelliptic curves not implemented in characteristics 2, 3, and 5") U = ubs(f) L = U["A"], U["B"], U["C"], U["D"] diff --git a/src/sage/schemes/hyperelliptic_curves/mestre.py b/src/sage/schemes/hyperelliptic_curves/mestre.py index 0fc44678ff3..33f4bc33c71 100644 --- a/src/sage/schemes/hyperelliptic_curves/mestre.py +++ b/src/sage/schemes/hyperelliptic_curves/mestre.py @@ -180,7 +180,7 @@ def HyperellipticCurve_from_invariants(i, reduced=True, precision=None, algorith parametrization = [l.replace("$.1", "t").replace("$.2", "u") for l in str(magma(MConic).Parametrization()).splitlines()[4:7]] [F1, F2, F3] = [sage_eval(p, locals={"t": t, "u": 1, "a": k.gen()}) for p in parametrization] else: - raise ValueError(f"No such curve exists over {k} as there are no " f"rational points on {MConic}") + raise ValueError(f"No such curve exists over {k} as there are no rational points on {MConic}") elif MConic.has_rational_point(): parametrization = MConic.parametrization(morphism=False)[0] [F1, F2, F3] = [p(t, 1) for p in parametrization] @@ -208,7 +208,7 @@ def HyperellipticCurve_from_invariants(i, reduced=True, precision=None, algorith pass if reduced: - raise NotImplementedError("Reduction of hyperelliptic curves not " "yet implemented. " "See issues #14755 and #14756.") + raise NotImplementedError("Reduction of hyperelliptic curves not yet implemented. See issues #14755 and #14756.") return HyperellipticCurve(f) diff --git a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py index 37643b40f01..e206004b0cb 100644 --- a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +++ b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py @@ -553,7 +553,7 @@ def __init__(self, Q, laurent_series=False): base_ring = Q.parent().base_ring() if not base_ring(6).is_unit(): - raise ArithmeticError("2 and 3 must be invertible in the " "coefficient ring (=%s) of Q" % base_ring) + raise ArithmeticError("2 and 3 must be invertible in the coefficient ring (=%s) of Q" % base_ring) self._a = Q[1] self._b = Q[0] @@ -891,7 +891,7 @@ def reduce_negative(Q, p, coeffs, offset, exact_form=None): exact_form += (c0 + c1 * x + c2 * x**2) * y ** (j + 1) except NotImplementedError: - raise NotImplementedError("It looks like you've found a " "non-integral matrix of Frobenius! " f"(Q={Q}, p={p})\nTime to write a paper.") + raise NotImplementedError(f"It looks like you've found a non-integral matrix of Frobenius! (Q={Q}, p={p})\nTime to write a paper.") coeffs[int(offset)] = next_a @@ -2459,7 +2459,7 @@ def __init__(self, Q, R=None, invert_y=True): self._curve = HyperellipticCurve(self._Q, check_squarefree=R.is_field()) else: - raise NotImplementedError("must be an elliptic curve or polynomial " "Q for y^2 = Q(x)\n(Got element of %s)" % Q.parent()) + raise NotImplementedError("must be an elliptic curve or polynomial Q for y^2 = Q(x)\n(Got element of %s)" % Q.parent()) self._n = int(Q.degree()) self._series_ring = (LaurentSeriesRing if invert_y else PolynomialRing)(R, "y") diff --git a/src/sage/schemes/plane_conics/con_field.py b/src/sage/schemes/plane_conics/con_field.py index ad2ede756ff..6624f387507 100644 --- a/src/sage/schemes/plane_conics/con_field.py +++ b/src/sage/schemes/plane_conics/con_field.py @@ -117,7 +117,7 @@ def base_extend(self, S): if B == S: return self if not S.has_coerce_map_from(B): - raise ValueError("No natural map from the base ring of self " "(= %s) to S (= %s)" % (self, S)) + raise ValueError("No natural map from the base ring of self (= %s) to S (= %s)" % (self, S)) from .constructor import Conic con = Conic([S(c) for c in self.coefficients()], self.variable_names()) @@ -555,7 +555,7 @@ def has_rational_point(self, point=False, algorithm='default', read_cache=True): if point: return ret return ret[0] - raise NotImplementedError("has_rational_point not implemented for " "conics over base field %s" % B) + raise NotImplementedError("has_rational_point not implemented for conics over base field %s" % B) def has_singular_point(self, point=False): r""" @@ -714,7 +714,7 @@ def hom(self, x, Y=None): if Y is None: Y = im elif not Y == im: - raise ValueError("The matrix x (= %s) does not define a " "map from self (= %s) to Y (= %s)" % (x, self, Y)) + raise ValueError("The matrix x (= %s) does not define a map from self (= %s) to Y (= %s)" % (x, self, Y)) x = Sequence(x * vector(self.ambient_space().gens())) return self.Hom(Y)(x, check=False) return super().hom(x, Y) @@ -1021,7 +1021,7 @@ def random_rational_point(self, *args1, **args2): x^2 + y^2 + z^2 has no rational points over Rational Field! """ if not self.is_smooth(): - raise NotImplementedError("Sorry, random points not implemented " "for non-smooth conics") + raise NotImplementedError("Sorry, random points not implemented for non-smooth conics") par = self.parametrization() x = 0 y = 0 @@ -1198,7 +1198,7 @@ def singular_point(self): """ b = self.has_singular_point(point=True) if not b[0]: - raise ValueError("The conic self (= %s) has no rational " "singular point" % self) + raise ValueError("The conic self (= %s) has no rational singular point" % self) return b[1] def symmetric_matrix(self): @@ -1224,7 +1224,7 @@ def symmetric_matrix(self): if self.base_ring().characteristic() == 2: if b == 0 and c == 0 and e == 0: return matrix([[a, 0, 0], [0, d, 0], [0, 0, f]]) - raise ValueError("The conic self (= %s) has no symmetric matrix " "because the base field has characteristic 2" % self) + raise ValueError("The conic self (= %s) has no symmetric matrix because the base field has characteristic 2" % self) return matrix([[a, b / 2, c / 2], [b / 2, d, e / 2], [c / 2, e / 2, f]]) def upper_triangular_matrix(self): diff --git a/src/sage/schemes/plane_conics/con_number_field.py b/src/sage/schemes/plane_conics/con_number_field.py index 6527468cacd..ff019397396 100644 --- a/src/sage/schemes/plane_conics/con_number_field.py +++ b/src/sage/schemes/plane_conics/con_number_field.py @@ -247,7 +247,7 @@ def has_rational_point(self, point=False, obstruction=False, algorithm='default' if obstruction: ret = self.has_rational_point(point=False, obstruction=True, algorithm='local', read_cache=False) if ret[0]: - raise RuntimeError("Outputs of algorithms in " "has_rational_point disagree " "for conic %s" % self) + raise RuntimeError("Outputs of algorithms in has_rational_point disagree for conic %s" % self) return ret if point: return False, None @@ -255,7 +255,7 @@ def has_rational_point(self, point=False, obstruction=False, algorithm='default' if algorithm == 'local': if point: - raise ValueError("Algorithm 'local' cannot be combined " "with point = True in has_rational_point") + raise ValueError("Algorithm 'local' cannot be combined with point = True in has_rational_point") obs = self.local_obstructions(infinite=True, finite=False, read_cache=read_cache) if obs: if obstruction: @@ -273,7 +273,7 @@ def has_rational_point(self, point=False, obstruction=False, algorithm='default' from sage.modules.free_module_element import vector if obstruction: - raise ValueError("Algorithm rnfisnorm cannot be combined " "with obstruction = True in " "has_rational_point") + raise ValueError("Algorithm rnfisnorm cannot be combined with obstruction = True in has_rational_point") D, T = self.diagonal_matrix() abc = [D[0, 0], D[1, 1], D[2, 2]] for j in range(3): @@ -304,7 +304,6 @@ def has_rational_point(self, point=False, obstruction=False, algorithm='default' L = K.extension(X**2 - d * den**2, names='y') isnorm = BtoK(-abc[2] / abc[0]).is_norm(L, element=True) if isnorm[0]: - pt = self.point(T * vector([KtoB(isnorm[1][0]), KtoB(isnorm[1][1] * den), 1])) if point: return True, pt @@ -313,9 +312,9 @@ def has_rational_point(self, point=False, obstruction=False, algorithm='default' return False, None return False if algorithm == 'qfsolve': - raise TypeError("Algorithm qfsolve in has_rational_point only " "for conics over QQ, not over %s" % B) + raise TypeError("Algorithm qfsolve in has_rational_point only for conics over QQ, not over %s" % B) if obstruction: - raise ValueError("Invalid combination: obstruction=True and " "algorithm=%s" % algorithm) + raise ValueError("Invalid combination: obstruction=True and algorithm=%s" % algorithm) return ProjectiveConic_field.has_rational_point(self, point=point, algorithm=algorithm, read_cache=False) diff --git a/src/sage/schemes/plane_conics/con_rational_field.py b/src/sage/schemes/plane_conics/con_rational_field.py index 035ed7bbab7..fd6b1298315 100644 --- a/src/sage/schemes/plane_conics/con_rational_field.py +++ b/src/sage/schemes/plane_conics/con_rational_field.py @@ -240,7 +240,7 @@ def is_locally_solvable(self, p) -> bool: if p.domain() is QQ and isinstance(p.codomain(), sage.rings.abc.RealField): p = -1 else: - raise TypeError("p (=%s) needs to be a prime of base field " "B ( =`QQ`) in is_locally_solvable" % p) + raise TypeError("p (=%s) needs to be a prime of base field B ( =`QQ`) in is_locally_solvable" % p) if hilbert_symbol(a, b, p) == -1: if self._local_obstruction is None: self._local_obstruction = p diff --git a/src/sage/schemes/plane_conics/con_rational_function_field.py b/src/sage/schemes/plane_conics/con_rational_function_field.py index 4b3d0300f26..c4e5a0a7991 100644 --- a/src/sage/schemes/plane_conics/con_rational_function_field.py +++ b/src/sage/schemes/plane_conics/con_rational_function_field.py @@ -564,4 +564,4 @@ def find_point(self, supports, roots, case, solution=0): Z = Ft(list(v[A + B + 2 : A + B + C + 3])) return self.point([X, Y, Z]) - raise RuntimeError("No solution has been found: possibly incorrect " "solubility certificate.") + raise RuntimeError("No solution has been found: possibly incorrect solubility certificate.") diff --git a/src/sage/schemes/plane_conics/constructor.py b/src/sage/schemes/plane_conics/constructor.py index 9f70eb8c01a..60af7e7d7dd 100644 --- a/src/sage/schemes/plane_conics/constructor.py +++ b/src/sage/schemes/plane_conics/constructor.py @@ -166,16 +166,16 @@ def Conic(base_field, F=None, names=None, unique=True): if len(C) == 2: C.append(1) else: - raise TypeError("F (=%s) must be a sequence of planar " "points" % F) + raise TypeError("F (=%s) must be a sequence of planar points" % F) if len(C) != 3: raise TypeError("points in F (=%s) must be planar" % F) P = C.universe() if P not in IntegralDomains(): - raise TypeError("coordinates of points in F (=%s) must " "be in an integral domain" % F) + raise TypeError("coordinates of points in F (=%s) must be in an integral domain" % F) L.append(Sequence([C[0] ** 2, C[0] * C[1], C[0] * C[2], C[1] ** 2, C[1] * C[2], C[2] ** 2], P.fraction_field())) M = matrix(L) if unique and M.rank() != 5: - raise ValueError("points in F (=%s) do not define a unique " "conic" % F) + raise ValueError("points in F (=%s) do not define a unique conic" % F) con = Conic(base_field, Sequence(M.right_kernel().gen()), names) con.point(F[0]) return con @@ -187,7 +187,7 @@ def Conic(base_field, F=None, names=None, unique=True): return Conic(F[0] * x**2 + F[1] * y**2 + F[2] * z**2) if len(F) == 6: return Conic(F[0] * x**2 + F[1] * x * y + F[2] * x * z + F[3] * y**2 + F[4] * y * z + F[5] * z**2) - raise TypeError("F (=%s) must be a sequence of 3 or 6" "coefficients" % F) + raise TypeError("F (=%s) must be a sequence of 3 or 6coefficients" % F) from sage.quadratic_forms.quadratic_form import QuadraticForm @@ -200,7 +200,7 @@ def Conic(base_field, F=None, names=None, unique=True): F = vector(temp_ring.gens()) * F * vector(temp_ring.gens()) if not isinstance(F, MPolynomial): - raise TypeError("F (=%s) must be a three-variable polynomial or " "a sequence of points or coefficients" % F) + raise TypeError("F (=%s) must be a three-variable polynomial or a sequence of points or coefficients" % F) if F.total_degree() != 2: raise TypeError("F (=%s) must have degree 2" % F) diff --git a/src/sage/schemes/plane_quartics/quartic_generic.py b/src/sage/schemes/plane_quartics/quartic_generic.py index 37188876ff0..078f32ce7f2 100644 --- a/src/sage/schemes/plane_quartics/quartic_generic.py +++ b/src/sage/schemes/plane_quartics/quartic_generic.py @@ -18,7 +18,6 @@ # https://www.gnu.org/licenses/ # *************************************************************************** - from sage.schemes.curves import projective_curve diff --git a/src/sage/schemes/product_projective/homset.py b/src/sage/schemes/product_projective/homset.py index a2d34336c04..6d079eba6a1 100644 --- a/src/sage/schemes/product_projective/homset.py +++ b/src/sage/schemes/product_projective/homset.py @@ -210,7 +210,7 @@ def points(self, **kwds): if alg is None: # sieve should only be called for subschemes and if the bound is not very small N = prod([k + 1 for k in X.ambient_space().dimension_relative_components()]) - if isinstance(X, AlgebraicScheme_subscheme) and B ** N > 5000: + if isinstance(X, AlgebraicScheme_subscheme) and B**N > 5000: from sage.schemes.product_projective.rational_point import sieve return sieve(X, B) diff --git a/src/sage/schemes/product_projective/point.py b/src/sage/schemes/product_projective/point.py index 79dff578c23..983b89bc3e7 100644 --- a/src/sage/schemes/product_projective/point.py +++ b/src/sage/schemes/product_projective/point.py @@ -506,7 +506,6 @@ def local_height(self, v, prec=None): class ProductProjectiveSpaces_point_field(ProductProjectiveSpaces_point_ring): - def intersection_multiplicity(self, X): r""" Return the intersection multiplicity of the codomain of this point and subscheme ``X`` at this point. diff --git a/src/sage/schemes/product_projective/subscheme.py b/src/sage/schemes/product_projective/subscheme.py index c7521339157..1790820e054 100644 --- a/src/sage/schemes/product_projective/subscheme.py +++ b/src/sage/schemes/product_projective/subscheme.py @@ -444,7 +444,7 @@ def multiplicity(self, P): try: PP(P) except TypeError: - raise TypeError("(={}) must be a point in the ambient space of this " "subscheme and (={})".format(P, self)) + raise TypeError("(={}) must be a point in the ambient space of this subscheme and (={})".format(P, self)) # find an affine chart of the ambient space of this subscheme that contains P indices = [] aff_pt = [] diff --git a/src/sage/schemes/projective/projective_homset.py b/src/sage/schemes/projective/projective_homset.py index 7ac3d30492d..888879b1629 100644 --- a/src/sage/schemes/projective/projective_homset.py +++ b/src/sage/schemes/projective/projective_homset.py @@ -695,7 +695,7 @@ def base_extend(self, R): implemented as modules over rings other than ZZ """ if R is not ZZ: - raise NotImplementedError('Abelian variety point sets are not ' 'implemented as modules over rings other than ZZ') + raise NotImplementedError('Abelian variety point sets are not implemented as modules over rings other than ZZ') return self def zero(self): diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index ba559dec960..16a12da6780 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -262,7 +262,7 @@ def __init__(self, parent, polys, check=True) -> None: num = f.numerator() den = f.denominator() if not (num.is_homogeneous() and den.is_homogeneous() and num.degree() == den.degree()): - raise ValueError("polys (={}) must be quotients of " "homogeneous polynomials of the same degree".format(polys)) + raise ValueError("polys (={}) must be quotients of homogeneous polynomials of the same degree".format(polys)) check = False except (NotImplementedError, TypeError, AttributeError): pass @@ -1534,7 +1534,6 @@ def wronskian_ideal(self): class SchemeMorphism_polynomial_projective_space_field(SchemeMorphism_polynomial_projective_space): - def rational_preimages(self, Q, k=1): r""" Determine all of the rational `k`-th preimages of ``Q`` by this map. @@ -2221,7 +2220,6 @@ def image(self): class SchemeMorphism_polynomial_projective_space_finite_field(SchemeMorphism_polynomial_projective_space_field): - def _fast_eval(self, x): """ Evaluate projective morphism at point described by x. diff --git a/src/sage/schemes/projective/projective_point.py b/src/sage/schemes/projective/projective_point.py index 738709aa363..f90e0e46d65 100644 --- a/src/sage/schemes/projective/projective_point.py +++ b/src/sage/schemes/projective/projective_point.py @@ -185,13 +185,13 @@ def __init__(self, X, v, check=True): # Over integral domains, any tuple with at least one # nonzero coordinate is a valid projective point. if not any(v): - raise ValueError(f"{v} does not define a valid projective " "point since all entries are zero") + raise ValueError(f"{v} does not define a valid projective point since all entries are zero") else: # Over rings with zero divisors, a more careful check # is required: We test whether the coordinates of the # point generate the unit ideal. See #31576. if 1 not in R.ideal(v): - raise ValueError(f"{v} does not define a valid projective point " "since it is a multiple of a zero divisor") + raise ValueError(f"{v} does not define a valid projective point since it is a multiple of a zero divisor") X.extended_codomain()._check_satisfies_equations(v) @@ -1159,7 +1159,7 @@ def __init__(self, X, v, check=True): v[last] = R.one() break else: - raise ValueError(f"{v} does not define a valid projective " "point since all entries are zero") + raise ValueError(f"{v} does not define a valid projective point since all entries are zero") self._normalized = True X.extended_codomain()._check_satisfies_equations(v) @@ -1422,7 +1422,6 @@ def as_subscheme(self): class SchemeMorphism_point_projective_finite_field(SchemeMorphism_point_projective_field): - def __hash__(self): r""" Return the integer hash of this point. diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index 00285d88bce..20b3655b3b2 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -655,17 +655,17 @@ def _linear_system_as_kernel(self, d, pt, m): if d < 0: raise ValueError('the integer d=%s must be nonnegative' % d) if not isinstance(pt, (list, tuple, SchemeMorphism_point_projective_ring)): - raise TypeError('the argument pt=%s must be a list, tuple, or ' 'point on a projective space' % pt) + raise TypeError('the argument pt=%s must be a list, tuple, or point on a projective space' % pt) pt, R = prepare(pt, None) n = self.dimension_relative() if not len(pt) == n + 1: - raise TypeError('the sequence pt=%s must have %s ' 'components' % (pt, n + 1)) + raise TypeError('the sequence pt=%s must have %s components' % (pt, n + 1)) if not R.has_coerce_map_from(self.base_ring()): raise TypeError('unable to find a common ring for all elements') try: i = pt.index(1) except Exception: - raise TypeError('at least one component of pt=%s must be equal ' 'to 1' % pt) + raise TypeError('at least one component of pt=%s must be equal to 1' % pt) pt = pt[:i] + pt[i + 1 :] if not isinstance(m, (int, Integer)): raise TypeError('the argument m=%s must be an integer' % m) diff --git a/src/sage/schemes/projective/projective_subscheme.py b/src/sage/schemes/projective/projective_subscheme.py index 861d9f55ec4..c66fdb2e620 100644 --- a/src/sage/schemes/projective/projective_subscheme.py +++ b/src/sage/schemes/projective/projective_subscheme.py @@ -996,7 +996,7 @@ def dual(self): m = J.ngens() n = J.ring().ngens() - 1 if m != 1 or (n < 1) or J.is_zero() or J.is_trivial() or not J.is_prime(): - raise NotImplementedError("At the present, the method is only" " implemented for irreducible and" " reduced hypersurfaces and the given" " list of generators for the ideal must" " have exactly one element.") + raise NotImplementedError("At the present, the method is only implemented for irreducible and reduced hypersurfaces and the given list of generators for the ideal must have exactly one element.") R = PolynomialRing(K, 'x', n + 1) from sage.schemes.projective.projective_space import ProjectiveSpace diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index 6fd80c5d3bc..1ea32009116 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -464,7 +464,7 @@ def reparameterize_differential_minpoly(minpoly, z0): if Inf: F = F.fraction_field() - mt = F(minpoly(F.gen(0) ** (-1), -F.gen(0) ** 2 * F.gen(1))) + mt = F(minpoly(F.gen(0) ** (-1), -(F.gen(0) ** 2) * F.gen(1))) mt.reduce() mt = mt.numerator() else: diff --git a/src/sage/schemes/toric/chow_group.py b/src/sage/schemes/toric/chow_group.py index 9a8a66a1fe8..760f3fd6e99 100644 --- a/src/sage/schemes/toric/chow_group.py +++ b/src/sage/schemes/toric/chow_group.py @@ -110,6 +110,7 @@ sage: sum( mixed.project_to_degree(i) for i in range(X.dimension()+1) ) == mixed True """ + # **************************************************************************** # Copyright (C) 2010 Volker Braun # diff --git a/src/sage/schemes/toric/divisor.py b/src/sage/schemes/toric/divisor.py index 536a0d98409..d438c352afd 100644 --- a/src/sage/schemes/toric/divisor.py +++ b/src/sage/schemes/toric/divisor.py @@ -295,7 +295,7 @@ def ToricDivisor(toric_variety, arg=None, ring=None, check=True, reduce=True): fan = toric_variety.fan() cone = fan.embed(arg) if cone.dim() != 1: - raise ValueError("only 1-dimensional cones of the toric variety " "define divisors") + raise ValueError("only 1-dimensional cones of the toric variety define divisors") arg = [(1, toric_variety.gen(cone.ambient_ray_indices()[0]))] check = True # ensure that the 1 will be coerced into the coefficient ring reduce = False @@ -498,7 +498,7 @@ def function_value(self, point): 11 """ if not self.is_QQ_Cartier(): - raise ValueError("support functions are associated to QQ-Cartier " "divisors only, %s is not QQ-Cartier" % self) + raise ValueError("support functions are associated to QQ-Cartier divisors only, %s is not QQ-Cartier" % self) try: index = ZZ(point) return self.coefficient(index) @@ -588,7 +588,7 @@ def m(self, cone): bV = b * V m = D.solve_left(bV) * U except ValueError: - raise ValueError("%s is not QQ-Cartier, cannot choose a dual " "vector on %s" % (self, cone)) + raise ValueError("%s is not QQ-Cartier, cannot choose a dual vector on %s" % (self, cone)) try: m = M(m) @@ -1374,7 +1374,7 @@ def _sheaf_cohomology_support(self): X = self.parent().scheme() fan = X.fan() if not X.is_complete(): - raise ValueError("%s is not complete, its cohomology is not " "finite-dimensional" % X) + raise ValueError("%s is not complete, its cohomology is not finite-dimensional" % X) d = X.dimension() chamber_vertices = [] for pindexlist in Combinations(range(fan.nrays()), d): diff --git a/src/sage/schemes/toric/fano_variety.py b/src/sage/schemes/toric/fano_variety.py index ee9c36e8da3..805d46acaa1 100644 --- a/src/sage/schemes/toric/fano_variety.py +++ b/src/sage/schemes/toric/fano_variety.py @@ -465,15 +465,15 @@ def CPRFanoToricVariety(Delta=None, Delta_polar=None, coordinate_points=None, ch elif coordinate_points == "all but facets": coordinate_points = Delta_polar.skeleton_points(Delta_polar.dim() - 2) elif isinstance(coordinate_points, str): - raise ValueError("unrecognized description of the coordinate points!" "\nGot: %s" % coordinate_points) + raise ValueError("unrecognized description of the coordinate points!\nGot: %s" % coordinate_points) elif check: cp_set = set(coordinate_points) if len(cp_set) != len(coordinate_points): raise ValueError("no repetitions are allowed for coordinate points!\nGot: %s" % coordinate_points) if not cp_set.issuperset(list(range(Delta_polar.n_vertices()))): - raise ValueError("all %d vertices of Delta_polar must be used " "for coordinates!\nGot: %s" % (Delta_polar.n_vertices(), coordinate_points)) + raise ValueError("all %d vertices of Delta_polar must be used for coordinates!\nGot: %s" % (Delta_polar.n_vertices(), coordinate_points)) if Delta_polar.origin() in cp_set: - raise ValueError("the origin (point #%d) cannot be used for a " "coordinate!\nGot: %s" % (Delta_polar.origin(), coordinate_points)) + raise ValueError("the origin (point #%d) cannot be used for a coordinate!\nGot: %s" % (Delta_polar.origin(), coordinate_points)) point_to_ray = {point: n for n, point in enumerate(coordinate_points)} # This can be simplified if LatticePolytopeClass is adjusted. rays = [Delta_polar.point(p) for p in coordinate_points] @@ -494,7 +494,7 @@ def CPRFanoToricVariety(Delta=None, Delta_polar=None, coordinate_points=None, ch is_bad = False break if is_bad: - raise ValueError("%s does not form a chart of a subdivision of the " "face fan of %s!" % (chart, Delta_polar)) + raise ValueError("%s does not form a chart of a subdivision of the face fan of %s!" % (chart, Delta_polar)) # We will construct the initial fan from Cone objects: since charts # may not use all of the necessary rays, alternative form is tedious # With check=False it should not be long anyway. @@ -517,7 +517,7 @@ def CPRFanoToricVariety(Delta=None, Delta_polar=None, coordinate_points=None, ch if base_ring is None: base_ring = QQ elif base_ring not in _Fields: - raise TypeError("need a field to construct a Fano toric variety!" "\n Got %s" % base_ring) + raise TypeError("need a field to construct a Fano toric variety!\n Got %s" % base_ring) fan._is_complete = True # At this point it must be for sure return CPRFanoToricVariety_field(Delta_polar, fan, coordinate_points, point_to_ray, coordinate_names, coordinate_name_indices, base_ring) @@ -798,7 +798,7 @@ def change_ring(self, F): if self.base_ring() == F: return self if F not in _Fields: - raise TypeError("need a field to construct a Fano toric variety!" "\n Got %s" % F) + raise TypeError("need a field to construct a Fano toric variety!\n Got %s" % F) else: return CPRFanoToricVariety_field(self._Delta_polar, self._fan, self._coordinate_points, self._point_to_ray, self.variable_names(), None, F) # coordinate_name_indices do not matter, we give explicit @@ -1134,7 +1134,7 @@ def resolve(self, **kwds): # just toric variety if subdivision involves rays if "new_rays" in kwds: if "new_points" in kwds: - raise ValueError("you cannot give new_points and new_rays at " "the same time!") + raise ValueError("you cannot give new_points and new_rays at the same time!") return super().resolve(**kwds) # Now we need to construct another Fano variety new_points = kwds.pop("new_points", ()) @@ -1142,7 +1142,7 @@ def resolve(self, **kwds): new_points = tuple(point for point in new_points if point not in coordinate_points) Delta_polar = self._Delta_polar if Delta_polar.origin() in new_points: - raise ValueError("the origin (point #%d) cannot be used for " "subdivision!" % Delta_polar.origin()) + raise ValueError("the origin (point #%d) cannot be used for subdivision!" % Delta_polar.origin()) if new_points: coordinate_points = coordinate_points + new_points point_to_ray = {point: n for n, point in enumerate(coordinate_points)} @@ -1222,7 +1222,7 @@ def __init__(self, P_Delta, monomial_points=None, coefficient_names=None, coeffi + t^2*x*y + s^2*y^2 + s*t*y^2 + t^2*y^2 """ if not isinstance(P_Delta, CPRFanoToricVariety_field): - raise TypeError("anticanonical hypersurfaces can only be " "constructed for CPR-Fano toric varieties!" "\nGot: %s" % P_Delta) + raise TypeError("anticanonical hypersurfaces can only be constructed for CPR-Fano toric varieties!\nGot: %s" % P_Delta) Delta = P_Delta.Delta() Delta_polar = Delta.polar() # Monomial points normalization @@ -1237,7 +1237,7 @@ def __init__(self, P_Delta, monomial_points=None, coefficient_names=None, coeffi monomial_points = Delta.skeleton_points(Delta.dim() - 2) monomial_points.append(Delta.origin()) elif isinstance(monomial_points, str): - raise ValueError("%s is an unsupported description of monomial " "points!" % monomial_points) + raise ValueError("%s is an unsupported description of monomial points!" % monomial_points) monomial_points = tuple(monomial_points) self._monomial_points = monomial_points # Make the necessary ambient space @@ -1263,7 +1263,7 @@ def __init__(self, P_Delta, monomial_points=None, coefficient_names=None, coeffi coefficients = [F(_) for _ in coefficients] P_Delta = P_Delta.base_extend(F) if len(monomial_points) != len(coefficients): - raise ValueError("cannot construct equation of the anticanonical" " hypersurface with %d monomials and %d coefficients" % (len(monomial_points), len(coefficients))) + raise ValueError("cannot construct equation of the anticanonical hypersurface with %d monomials and %d coefficients" % (len(monomial_points), len(coefficients))) # Defining polynomial h = sum(coef * prod(P_Delta.coordinate_point_to_coordinate(n) ** (Delta.point(m) * Delta_polar.point(n) + 1) for n in P_Delta.coordinate_points()) for m, coef in zip(monomial_points, coefficients)) super().__init__(P_Delta, h) @@ -1324,9 +1324,9 @@ def __init__(self, P_Delta, nef_partition, monomial_points='all', coefficient_na + b4*z2*z4*z5 + b3*z1*z5^2 + b0*z4*z5^2 """ if not isinstance(P_Delta, CPRFanoToricVariety_field): - raise TypeError("nef complete intersections can only be " "constructed for CPR-Fano toric varieties!" "\nGot: %s" % P_Delta) + raise TypeError("nef complete intersections can only be constructed for CPR-Fano toric varieties!\nGot: %s" % P_Delta) if nef_partition.Delta() is not P_Delta.Delta(): - raise ValueError("polytopes 'Delta' of the nef-partition and the " "CPR-Fano toric variety must be the same!") + raise ValueError("polytopes 'Delta' of the nef-partition and the CPR-Fano toric variety must be the same!") self._nef_partition = nef_partition k = nef_partition.n_parts() # Pre-normalize all parameters @@ -1353,7 +1353,7 @@ def __init__(self, P_Delta, nef_partition, monomial_points='all', coefficient_na if Delta_i.origin() is not None and Delta_i.origin() >= Delta_i.n_vertices(): monomial_points[i].append(Delta_i.origin()) elif isinstance(monomial_points[i], str): - raise ValueError("'%s' is an unsupported description of " "monomial points!" % monomial_points[i]) + raise ValueError("'%s' is an unsupported description of monomial points!" % monomial_points[i]) monomial_points[i] = tuple(monomial_points[i]) # Extend the base ring of the ambient space if necessary if coefficients[i] is None: @@ -1376,7 +1376,7 @@ def __init__(self, P_Delta, nef_partition, monomial_points='all', coefficient_na coefficients[i] = [F(_) for _ in coefficients[i]] P_Delta = P_Delta.base_extend(F) if len(monomial_points[i]) != len(coefficients[i]): - raise ValueError("cannot construct equation %d of the complete" " intersection with %d monomials and %d coefficients" % (i, len(monomial_points[i]), len(coefficients[i]))) + raise ValueError("cannot construct equation %d of the complete intersection with %d monomials and %d coefficients" % (i, len(monomial_points[i]), len(coefficients[i]))) # Defining polynomial h = sum(coef * prod(P_Delta.coordinate_point_to_coordinate(n) ** (Delta_i.point(m) * Delta_polar.point(n) + (nef_partition.part_of_point(n) == i)) for n in P_Delta.coordinate_points()) for m, coef in zip(monomial_points[i], coefficients[i])) polynomials.append(h) diff --git a/src/sage/schemes/toric/homset.py b/src/sage/schemes/toric/homset.py index 35184717113..af0281bd965 100644 --- a/src/sage/schemes/toric/homset.py +++ b/src/sage/schemes/toric/homset.py @@ -583,7 +583,6 @@ def __iter__(self): class SchemeHomset_points_subscheme_toric_field(SchemeHomset_points_toric_base): - def _enumerator(self): """ Return the most suitable enumerator for points. diff --git a/src/sage/schemes/toric/ideal.py b/src/sage/schemes/toric/ideal.py index b598f1de311..bddde6b29b0 100644 --- a/src/sage/schemes/toric/ideal.py +++ b/src/sage/schemes/toric/ideal.py @@ -132,7 +132,6 @@ # * Cythonize the Buchberger algorithm for toric ideals # * Use the (multiple) weighted homogeneity during Groebner basis computations - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.misc.misc_c import prod from sage.matrix.constructor import matrix diff --git a/src/sage/schemes/toric/library.py b/src/sage/schemes/toric/library.py index a7804751349..a957f8acefd 100644 --- a/src/sage/schemes/toric/library.py +++ b/src/sage/schemes/toric/library.py @@ -514,9 +514,9 @@ def P(self, n, names='z+', base_ring=QQ): try: n = ZZ(n) # make sure that we got a "mathematical" integer except TypeError: - raise TypeError("dimension of the projective space must be a " "positive integer!\nGot: %s" % n) + raise TypeError("dimension of the projective space must be a positive integer!\nGot: %s" % n) if n <= 0: - raise ValueError("only projective spaces of positive dimension " "can be constructed!\nGot: %s" % n) + raise ValueError("only projective spaces of positive dimension can be constructed!\nGot: %s" % n) m = identity_matrix(n).augment(matrix(n, 1, [-1] * n)) charts = [list(range(i)) + list(range(i + 1, n + 1)) for i in range(n + 1)] return CPRFanoToricVariety(Delta_polar=LatticePolytope(m.columns(), lattice=ToricLattice(n)), charts=charts, check=self._check, coordinate_names=names, base_ring=base_ring) @@ -613,9 +613,9 @@ def A(self, n, names='z+', base_ring=QQ): try: n = ZZ(n) # make sure that we got a "mathematical" integer except TypeError: - raise TypeError("dimension of the affine space must be a " "positive integer!\nGot: %s" % n) + raise TypeError("dimension of the affine space must be a positive integer!\nGot: %s" % n) if n <= 0: - raise ValueError("only affine spaces of positive dimension can " "be constructed!\nGot: %s" % n) + raise ValueError("only affine spaces of positive dimension can be constructed!\nGot: %s" % n) rays = identity_matrix(n).columns() cones = [list(range(n))] fan = Fan(cones, rays, check=self._check) @@ -895,9 +895,9 @@ def Cube_deformation(self, k, names=None, base_ring=QQ): try: k = ZZ(k) # make sure that we got a "mathematical" integer except TypeError: - raise TypeError("cube deformations X_k are defined only for " "nonnegative integer k!\nGot: %s" % k) + raise TypeError("cube deformations X_k are defined only for nonnegative integer k!\nGot: %s" % k) if k < 0: - raise ValueError("cube deformations X_k are defined only for " "nonnegative k!\nGot: %s" % k) + raise ValueError("cube deformations X_k are defined only for nonnegative k!\nGot: %s" % k) def rays(kappa): return matrix([[1, 1, 2 * kappa + 1], [1, -1, 1], [-1, 1, 1], [-1, -1, 1], [-1, -1, -1], [-1, 1, -1], [1, -1, -1], [1, 1, -1]]) diff --git a/src/sage/schemes/toric/morphism.py b/src/sage/schemes/toric/morphism.py index a9f8aaf8ea2..c168e5742d9 100644 --- a/src/sage/schemes/toric/morphism.py +++ b/src/sage/schemes/toric/morphism.py @@ -430,10 +430,10 @@ def __init__(self, X, coordinates, check=True): if isinstance(coordinates, SchemeMorphism): coordinates = list(coordinates) if not isinstance(coordinates, (list, tuple)): - raise TypeError("coordinates must be a scheme point, list, " "or tuple; got %s" % coordinates) + raise TypeError("coordinates must be a scheme point, list, or tuple; got %s" % coordinates) d = X.codomain().ambient_space().ngens() if len(coordinates) != d: - raise ValueError("there must be %d coordinates; got only %d: " "%s" % (d, len(coordinates), coordinates)) + raise ValueError("there must be %d coordinates; got only %d: %s" % (d, len(coordinates), coordinates)) # Make sure the coordinates all lie in the appropriate ring coordinates = Sequence(coordinates, X.value_ring()) # Verify that the point satisfies the equations of X. @@ -529,7 +529,7 @@ def as_fan_morphism(self): NotImplementedError: expressing toric morphisms as fan morphisms is not implemented yet """ - raise NotImplementedError("expressing toric morphisms as fan " "morphisms is not implemented yet") + raise NotImplementedError("expressing toric morphisms as fan morphisms is not implemented yet") ############################################################################ @@ -1092,10 +1092,10 @@ def as_polynomial_map(self): try: d = ZZ(d) except TypeError: - raise TypeError('the fan morphism cannot be written in ' 'homogeneous polynomials') + raise TypeError('the fan morphism cannot be written in homogeneous polynomials') polys[i] *= x**d if phi.domain_fan().virtual_rays(): - raise NotImplementedError("polynomial representations for fans with" " virtual rays are not implemented yet") + raise NotImplementedError("polynomial representations for fans with virtual rays are not implemented yet") return SchemeMorphism_polynomial_toric_variety(self.parent(), polys) def is_bundle(self) -> bool: diff --git a/src/sage/schemes/toric/points.py b/src/sage/schemes/toric/points.py index 4dd42fd7c5d..1218c764b4a 100644 --- a/src/sage/schemes/toric/points.py +++ b/src/sage/schemes/toric/points.py @@ -45,7 +45,6 @@ class InfinitePointEnumerator: - def __init__(self, fan, ring): """ Point enumerator for infinite fields. @@ -105,7 +104,6 @@ def __iter__(self): class NaiveFinitePointEnumerator: - def __init__(self, fan, ring): """ The naive point enumerator. @@ -425,7 +423,6 @@ def __iter__(self): class FiniteFieldPointEnumerator(NaiveFinitePointEnumerator): - @cached_method def multiplicative_generator(self): """ @@ -750,7 +747,6 @@ def cardinality(self): class NaiveSubschemePointEnumerator: - def __init__(self, polynomials, ambient): """ Point enumerator for algebraic subschemes of toric varieties. @@ -802,7 +798,6 @@ def __iter__(self): class FiniteFieldSubschemePointEnumerator(NaiveSubschemePointEnumerator): - def inhomogeneous_equations(self, ring, nonzero_coordinates, cokernel): """ Inhomogenize the defining polynomials. diff --git a/src/sage/schemes/toric/sheaf/constructor.py b/src/sage/schemes/toric/sheaf/constructor.py index da20082a7d7..05e226d6665 100644 --- a/src/sage/schemes/toric/sheaf/constructor.py +++ b/src/sage/schemes/toric/sheaf/constructor.py @@ -5,6 +5,7 @@ A toric vector bundle (on a toric variety) is a vector bundle that is equivariant with respect to the algebraic torus action. """ + # **************************************************************************** # Copyright (C) 2013 Volker Braun # @@ -134,7 +135,6 @@ def LineBundle(X, D): class SheafLibrary: - def __init__(self, toric_variety): """ Utility object to construct sheaves on toric varieties. diff --git a/src/sage/schemes/toric/sheaf/klyachko.py b/src/sage/schemes/toric/sheaf/klyachko.py index 567e3c3deec..5089c6481ca 100644 --- a/src/sage/schemes/toric/sheaf/klyachko.py +++ b/src/sage/schemes/toric/sheaf/klyachko.py @@ -110,7 +110,6 @@ def Bundle(toric_variety, multi_filtration, check=True): @richcmp_method class KlyachkoBundle_class(SageObject): - def __init__(self, toric_variety, multi_filtration, check=True): r""" A toric bundle using Klyachko's representation. @@ -152,7 +151,7 @@ def __init__(self, toric_variety, multi_filtration, check=True): from sage.sets.set import Set if multi_filtration.index_set() != Set(list(toric_variety.fan().rays())): - raise ValueError('the index set of the multi-filtration must be' ' all rays of the fan.') + raise ValueError('the index set of the multi-filtration must be all rays of the fan.') if not multi_filtration.is_exhaustive(): raise ValueError('multi-filtration must be exhaustive') if not multi_filtration.is_separating(): diff --git a/src/sage/schemes/toric/variety.py b/src/sage/schemes/toric/variety.py index 446cef03d8c..952f0b7c17b 100644 --- a/src/sage/schemes/toric/variety.py +++ b/src/sage/schemes/toric/variety.py @@ -460,7 +460,7 @@ def AffineToricVariety(cone, *args, **kwds): are all zero. """ if not cone.is_strictly_convex(): - raise ValueError("affine toric varieties are defined for strictly " "convex cones only") + raise ValueError("affine toric varieties are defined for strictly convex cones only") # We make sure that Fan constructor does not meddle with the order of # rays, this is very important for affine patches construction fan = Fan([tuple(range(cone.nrays()))], cone.rays(), check=False, normalize=False) @@ -656,7 +656,7 @@ def _check_satisfies_equations(self, coordinates): try: coordinates = tuple(coordinates) except TypeError: - raise TypeError("%s cannot be used as coordinates; " "use a list or a tuple" % coordinates) + raise TypeError("%s cannot be used as coordinates; use a list or a tuple" % coordinates) n = self.ngens() if len(coordinates) != n: raise TypeError("coordinates %s must have %d components" % (coordinates, n)) @@ -669,7 +669,7 @@ def _check_satisfies_equations(self, coordinates): return True for i in range(n - self._torus_factor_dim, n): if i in zero_positions: - raise ValueError("coordinates on the torus factor cannot be " "zero; got %s" % str(coordinates)) + raise ValueError("coordinates on the torus factor cannot be zero; got %s" % str(coordinates)) if len(zero_positions) == 1: return True fan = self.fan() @@ -1062,7 +1062,7 @@ def embedding_morphism(self): try: return self._embedding_morphism except AttributeError: - raise ValueError("no default embedding was defined for this " "toric variety") + raise ValueError("no default embedding was defined for this toric variety") def fan(self, dim=None, codim=None): r""" @@ -1273,7 +1273,7 @@ def is_isomorphic(self, another) -> bool: if self is another: return True if not isinstance(another, ToricVariety_field): - raise TypeError("only another toric variety can be checked for isomorphism; " "got %s" % another) + raise TypeError("only another toric variety can be checked for isomorphism; got %s" % another) raise NotImplementedError("isomorphism check is not yet implemented") def is_affine(self) -> bool: @@ -1651,7 +1651,7 @@ def resolve(self, **kwds): coordinate_indices = kwds.pop("coordinate_indices", None) fan = self.fan() if fan.dim() != fan.lattice_dim(): - raise NotImplementedError("resolution of toric varieties with " "torus factors is not yet implemented") + raise NotImplementedError("resolution of toric varieties with torus factors is not yet implemented") # When it is implemented, should be careful with the torus factor rfan = fan.subdivide(**kwds) if coordinate_names is None: @@ -1854,7 +1854,7 @@ def cohomology_ring(self): True """ if self.base_ring().characteristic() > 0: - raise NotImplementedError('only characteristic 0 base fields ' 'are implemented') + raise NotImplementedError('only characteristic 0 base fields are implemented') return CohomologyRing(self) @cached_method @@ -1964,7 +1964,7 @@ def volume_class(self): 1/2 """ if not self.is_orbifold(): - raise NotImplementedError('cohomology computations are only ' 'implemented for orbifolds') + raise NotImplementedError('cohomology computations are only implemented for orbifolds') HH = self.cohomology_ring() dim = self.dimension_relative() dVol = HH(self.fan().generating_cone(0)).part_of_degree(dim) @@ -2703,7 +2703,7 @@ def Demazure_roots(self): NotImplementedError: Demazure_roots is only implemented for complete toric varieties """ if not self.is_complete(): - raise NotImplementedError('Demazure_roots is only implemented ' 'for complete toric varieties') + raise NotImplementedError('Demazure_roots is only implemented for complete toric varieties') antiK = -self.K() fan_rays = self.fan().rays() roots = [m for m in antiK.sections() if [ray * m for ray in fan_rays].count(-1) == 1] @@ -2743,7 +2743,7 @@ def Aut_dimension(self): NotImplementedError: Aut_dimension is only implemented for complete toric varieties """ if not self.is_complete(): - raise NotImplementedError('Aut_dimension is only implemented ' 'for complete toric varieties') + raise NotImplementedError('Aut_dimension is only implemented for complete toric varieties') return self.fan().lattice_dim() + len(self.Demazure_roots()) @@ -3020,7 +3020,7 @@ def _latex_(self): sage: print(cohomology_ring._latex_()) H^\ast\left(\mathbb{P}_{\Delta^{2}_{15}},\Bold{Q}\right) """ - return fr'H^\ast\left({self._variety._latex_()},{latex(QQ)}\right)' + return rf'H^\ast\left({self._variety._latex_()},{latex(QQ)}\right)' def _element_constructor_(self, x): r""" diff --git a/src/sage/schemes/weighted_projective/weighted_projective_point.py b/src/sage/schemes/weighted_projective/weighted_projective_point.py index c557246895a..0d1d2edd7b3 100644 --- a/src/sage/schemes/weighted_projective/weighted_projective_point.py +++ b/src/sage/schemes/weighted_projective/weighted_projective_point.py @@ -107,14 +107,14 @@ def __init__(self, X, v, check: bool = True): R = X.value_ring() if not R.is_integral_domain(): - raise ValueError("cannot validate point over a ring that is not an integral domain, " "pass check=False to construct the point") + raise ValueError("cannot validate point over a ring that is not an integral domain, pass check=False to construct the point") v = Sequence(v, R) if len(v) == d - 1: # very common special case v.append(R.one()) # (0 : 0 : ... : 0) is not a valid (weighted) projective point if not any(v): - raise ValueError(f"{v} does not define a valid projective " "point since all entries are zero") + raise ValueError(f"{v} does not define a valid projective point since all entries are zero") X.extended_codomain()._check_satisfies_equations(v) diff --git a/src/sage/schemes/weighted_projective/weighted_projective_space.py b/src/sage/schemes/weighted_projective/weighted_projective_space.py index dae11956b57..8501e74b075 100644 --- a/src/sage/schemes/weighted_projective/weighted_projective_space.py +++ b/src/sage/schemes/weighted_projective/weighted_projective_space.py @@ -97,7 +97,7 @@ def __classcall__(cls, weights: tuple[Integer], R=ZZ, names=None): # see docs of CachedRepresentation # weights should be a tuple, also because it should be hashable if not isinstance(weights, tuple): - raise TypeError(f"weights(={weights}) is not a tuple. Please use the" "`WeightedProjectiveSpace` constructor") + raise TypeError(f"weights(={weights}) is not a tuple. Please use the`WeightedProjectiveSpace` constructor") normalized_names = normalize_names(len(weights), names) return super().__classcall__(cls, weights, R, normalized_names) @@ -256,7 +256,7 @@ def _latex_(self) -> str: sage: WeightedProjectiveSpace(Zp(5), [2, 1, 3], 'y')._latex_() # needs sage.rings.padics '{\\mathbf P}_{\\Bold{Z}_{5}}^{[2, 1, 3]}' """ - return fr"{{\mathbf P}}_{{{latex(self.base_ring())}}}^{{{list(self.weights())}}}" + return rf"{{\mathbf P}}_{{{latex(self.base_ring())}}}^{{{list(self.weights())}}}" def _morphism(self, *_, **__): """ @@ -330,7 +330,7 @@ def _repr_(self) -> str: Weighted Projective Space of dimension 2 with weights (1, 3, 1) over 5-adic Field with capped relative precision 20 """ - return f"Weighted Projective Space of dimension {self.dimension_relative()} with weights" f" {self.weights()} over {self.base_ring()}" + return f"Weighted Projective Space of dimension {self.dimension_relative()} with weights {self.weights()} over {self.base_ring()}" def change_ring(self, R): r""" @@ -402,7 +402,7 @@ def curve(self, F): Weighted Projective Curve over Rational Field defined by y^2 - x^5*z - 3*x^2*z^4 - 2*z^6 """ if self.base_ring() not in Fields(): - raise NotImplementedError("curves in weighted projective space over" "rings not implemented") + raise NotImplementedError("curves in weighted projective space overrings not implemented") from sage.schemes.curves.constructor import Curve return Curve(F, self) diff --git a/src/sage/sets/cartesian_product.py b/src/sage/sets/cartesian_product.py index 0c1831a7d89..62b2b09f7ad 100644 --- a/src/sage/sets/cartesian_product.py +++ b/src/sage/sets/cartesian_product.py @@ -313,7 +313,6 @@ def _coerce_map_from_(self, S): random_element = Sets.CartesianProducts.ParentMethods.random_element class Element(ElementWrapperCheckWrappedClass): - wrapped_class = tuple def cartesian_projection(self, i): diff --git a/src/sage/sets/set.py b/src/sage/sets/set.py index 4a18804eca4..e77e3e81fdb 100644 --- a/src/sage/sets/set.py +++ b/src/sage/sets/set.py @@ -975,7 +975,7 @@ def _repr_(self): o = self.object() l = list(islice(o, 0, 20)) s = "{" + ", ".join(map(repr, l)) + ", …}" - assert len(l) == 20, f"incorrect cardinality {self.cardinality()} " f"reported for object type {type(self)} containing {l}" + assert len(l) == 20, f"incorrect cardinality {self.cardinality()} reported for object type {type(self)} containing {l}" if o is not self: # safeguard infinite loop if subclass is weird s = f"Set of elements of {o!r} = {s}" return s diff --git a/src/sage/stats/distributions/discrete_gaussian_lattice.py b/src/sage/stats/distributions/discrete_gaussian_lattice.py index e16b89b5e1f..6ca95a0f8f6 100644 --- a/src/sage/stats/distributions/discrete_gaussian_lattice.py +++ b/src/sage/stats/distributions/discrete_gaussian_lattice.py @@ -302,7 +302,7 @@ def f_or_hat(x): # tweak the `.qfrep` call below correctly. from warnings import warn - warn("Note: `_normalisation_factor_zz` has not been properly " "implemented for non-spherical distributions.") + warn("Note: `_normalisation_factor_zz` has not been properly implemented for non-spherical distributions.") import itertools from sage.functions.log import log @@ -657,7 +657,7 @@ def _precompute_data(self): self.B2 = Sigma2.cholesky().T self.B2_B_inv = self.B2 * self.B_inv except ValueError: - raise ValueError("Σ₂ is not positive definite. Is your " f"r(={self.r}) too large? It should be at most " f"{self._maximal_r()}") + raise ValueError(f"Σ₂ is not positive definite. Is your r(={self.r}) too large? It should be at most {self._maximal_r()}") def __call__(self): r""" @@ -717,7 +717,7 @@ def f(self, x): x = vector(self._RR, self.n, x) x -= self._c if self.is_spherical: - return exp(-x.norm() ** 2 / (2 * self._sigma**2)) + return exp(-(x.norm() ** 2) / (2 * self._sigma**2)) return exp(-x * self.sigma_inv * x / 2) def sigma(self): diff --git a/src/sage/structure/global_options.py b/src/sage/structure/global_options.py index 2201ed1452f..03feeec3190 100644 --- a/src/sage/structure/global_options.py +++ b/src/sage/structure/global_options.py @@ -505,7 +505,6 @@ class options(GlobalOptions): # https://www.gnu.org/licenses/ # **************************************************************************** - from importlib import import_module from pickle import PicklingError from textwrap import dedent diff --git a/src/sage/structure/indexed_generators.py b/src/sage/structure/indexed_generators.py index cc85a09449a..2044d4f9ff9 100644 --- a/src/sage/structure/indexed_generators.py +++ b/src/sage/structure/indexed_generators.py @@ -816,7 +816,7 @@ def standardize_names_index_set(names=None, index_set=None, ngens=None): if names is None: # If neither is specified, we make range(ngens) the index set if ngens is None: - raise ValueError("the index_set, names, or number of" " generators must be specified") + raise ValueError("the index_set, names, or number of generators must be specified") index_set = tuple(range(ngens)) else: # If only the names are specified, then we make the indexing set @@ -838,10 +838,10 @@ def standardize_names_index_set(names=None, index_set=None, ngens=None): if ngens is None or ngens >= 0: if names is not None: if len(names) != index_set.cardinality(): - raise IndexError("the number of names must equal" " the size of the indexing set") + raise IndexError("the number of names must equal the size of the indexing set") if ngens is not None and len(names) != ngens: - raise IndexError("the number of names must equal the" " number of generators") + raise IndexError("the number of names must equal the number of generators") elif ngens is not None and index_set.cardinality() != ngens: - raise IndexError("the size of the indexing set must equal" " the number of generators") + raise IndexError("the size of the indexing set must equal the number of generators") return (names, index_set) diff --git a/src/sage/structure/list_clone_timings.py b/src/sage/structure/list_clone_timings.py index be0b4b272bf..d7c0317b4cb 100644 --- a/src/sage/structure/list_clone_timings.py +++ b/src/sage/structure/list_clone_timings.py @@ -85,7 +85,6 @@ class IncreasingArraysPy(IncreasingArrays): - class Element(ClonableArray): """ A small class for testing :class:`ClonableArray`: Increasing Lists. diff --git a/src/sage/structure/sage_object_test.py b/src/sage/structure/sage_object_test.py index 5e401537d57..aa1aebacc5d 100644 --- a/src/sage/structure/sage_object_test.py +++ b/src/sage/structure/sage_object_test.py @@ -3,7 +3,6 @@ class SageObjectTests: - @pytest.fixture def sage_object(self, *args, **kwargs) -> SageObject: raise NotImplementedError diff --git a/src/sage/structure/set_factories.py b/src/sage/structure/set_factories.py index 381c7c3c9eb..bbef9b57f57 100644 --- a/src/sage/structure/set_factories.py +++ b/src/sage/structure/set_factories.py @@ -313,7 +313,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.structure.sage_object import SageObject from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation diff --git a/src/sage/structure/set_factories_example.py b/src/sage/structure/set_factories_example.py index 506769e6a6c..c93bc9c9b68 100644 --- a/src/sage/structure/set_factories_example.py +++ b/src/sage/structure/set_factories_example.py @@ -131,7 +131,7 @@ def add_constraints(self, cons, args_opts): def set_args(argss): for i, v in enumerate(argss): if res[i] is not None and v is not None: - raise ValueError("Duplicate value for constraints '{}': " "was {} now {}".format(['x', 'y'][i], res[i], v)) + raise ValueError("Duplicate value for constraints '{}': was {} now {}".format(['x', 'y'][i], res[i], v)) if v is not None: res[i] = v diff --git a/src/sage/structure/test_factory.py b/src/sage/structure/test_factory.py index 4e6f45083ee..00d21c2bb0b 100644 --- a/src/sage/structure/test_factory.py +++ b/src/sage/structure/test_factory.py @@ -26,7 +26,6 @@ class A: class UniqueFactoryTester(UniqueFactory): - def create_key(self, *args, **kwds): """ EXAMPLES:: diff --git a/src/sage/symbolic/integration/external.py b/src/sage/symbolic/integration/external.py index a2eccb73660..b50c28700d7 100644 --- a/src/sage/symbolic/integration/external.py +++ b/src/sage/symbolic/integration/external.py @@ -121,7 +121,7 @@ def mma_free_integrator(expression, v, a=None, b=None): elif a is not None and b is not None: input = "Integrate[{},{{{},{},{}}}]".format(math_expr, variable, a._mathematica_init_(), b._mathematica_init_()) else: - raise ValueError('a(={}) and b(={}) should be both None' ' or both defined'.format(a, b)) + raise ValueError('a(={}) and b(={}) should be both None or both defined'.format(a, b)) json_page_data = request_wolfram_alpha(input) all_outputs = parse_moutput_from_json(json_page_data) if not all_outputs: @@ -211,7 +211,7 @@ def fricas_integrator(expression, v, a=None, b=None, noPole=True): result = expression.integrate(v, a, b, hold=True) elif result == "potentialPole": - raise ValueError("The integrand has a potential pole" " in the integration interval") + raise ValueError("The integrand has a potential pole in the integration interval") return result diff --git a/src/sage/symbolic/integration/integral.py b/src/sage/symbolic/integration/integral.py index 8fe16e4bced..4799d978325 100644 --- a/src/sage/symbolic/integration/integral.py +++ b/src/sage/symbolic/integration/integral.py @@ -428,7 +428,7 @@ def _normalize_integral_input(f, v, a=None, b=None): elif len(v) == 3: # variable and two endpoints v, a, b = v else: - raise TypeError("invalid input %s - please use variable, " "with or without two endpoints" % repr(v)) + raise TypeError("invalid input %s - please use variable, with or without two endpoints" % repr(v)) if (a is None) ^ (b is None): raise TypeError('only one endpoint was given!') diff --git a/src/sage/symbolic/random_tests.py b/src/sage/symbolic/random_tests.py index 47dfd855491..5b525f9f92c 100644 --- a/src/sage/symbolic/random_tests.py +++ b/src/sage/symbolic/random_tests.py @@ -11,7 +11,6 @@ # https://www.gnu.org/licenses/ ############################################################################### - from sage.misc.prandom import randint, random import operator from sage.rings.rational_field import QQ diff --git a/src/sage/symbolic/subring.py b/src/sage/symbolic/subring.py index bc916bde7de..4d54e4353ac 100644 --- a/src/sage/symbolic/subring.py +++ b/src/sage/symbolic/subring.py @@ -198,9 +198,9 @@ def create_key_and_extra_args(self, accepting_variables=None, rejecting_variable ValueError: cannot create a symbolic subring since input is ambiguous """ if accepting_variables is None and rejecting_variables is None and not no_variables: - raise ValueError('cannot create a symbolic subring ' 'since nothing is specified') + raise ValueError('cannot create a symbolic subring since nothing is specified') if accepting_variables is not None and rejecting_variables is not None or rejecting_variables is not None and no_variables or no_variables and accepting_variables is not None: - raise ValueError('cannot create a symbolic subring ' 'since input is ambiguous') + raise ValueError('cannot create a symbolic subring since input is ambiguous') if accepting_variables is not None: vars = tuple(accepting_variables) @@ -240,7 +240,6 @@ def create_object(self, version, key, **kwds): class GenericSymbolicSubring(SymbolicRing): - def __init__(self, vars): r""" An abstract base class for a symbolic subring. @@ -695,7 +694,6 @@ def _an_element_(self): class SymbolicSubringAcceptingVarsFunctor(GenericSymbolicSubringFunctor): - _functor_name = 'SymbolicSubringAcceptingVarsFunctor' _repr_type_ = 'accepting' @@ -754,7 +752,7 @@ def _apply_functor(self, R): symbolic ring but Symbolic Subring accepting the variable a given. """ if R is not SR: - raise NotImplementedError('This functor can only be applied on ' 'the symbolic ring but %s given.' % (R,)) + raise NotImplementedError('This functor can only be applied on the symbolic ring but %s given.' % (R,)) return SymbolicSubring(accepting_variables=self.vars) @@ -882,7 +880,6 @@ def _an_element_(self): class SymbolicSubringRejectingVarsFunctor(GenericSymbolicSubringFunctor): - _functor_name = 'SymbolicSubringRejectingVarsFunctor' _repr_type_ = 'rejecting' @@ -941,7 +938,7 @@ def _apply_functor(self, R): symbolic ring but Symbolic Subring rejecting the variable r given. """ if R is not SR: - raise NotImplementedError('This functor can only be applied on ' 'the symbolic ring but %s given.' % (R,)) + raise NotImplementedError('This functor can only be applied on the symbolic ring but %s given.' % (R,)) return SymbolicSubring(rejecting_variables=self.vars) diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 760e773a3e7..9c255766eca 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -670,7 +670,7 @@ def _check_indices(self, indices) -> tuple: else: ind = tuple(indices) if len(ind) != self._nid: - raise ValueError(("wrong number of indices: {} expected," " while {} are provided").format(self._nid, len(ind))) + raise ValueError(("wrong number of indices: {} expected, while {} are provided").format(self._nid, len(ind))) si = self._sindex imax = self._dim - 1 + si for k in range(self._nid): @@ -2520,7 +2520,7 @@ def symmetrize(self, *pos): if len(pos) < 2: raise ValueError("at least two index positions must be given") if len(pos) > self._nid: - raise ValueError("number of index positions larger than the " "total number of indices") + raise ValueError("number of index positions larger than the total number of indices") n_sym = len(pos) # number of indices involved in the symmetry if n_sym == self._nid: result = CompFullySym(self._ring, self._frame, self._nid, self._sindex, self._output_formatter) @@ -2666,7 +2666,7 @@ def antisymmetrize(self, *pos): if len(pos) < 2: raise ValueError("at least two index positions must be given") if len(pos) > self._nid: - raise ValueError("number of index positions larger than the " "total number of indices") + raise ValueError("number of index positions larger than the total number of indices") n_sym = len(pos) # number of indices involved in the antisymmetry if n_sym == self._nid: result = CompFullyAntiSym(self._ring, self._frame, self._nid, self._sindex, self._output_formatter) @@ -4159,7 +4159,7 @@ def symmetrize(self, *pos): if len(pos) < 2: raise ValueError("at least two index positions must be given") if len(pos) > self._nid: - raise ValueError("number of index positions larger than the " "total number of indices") + raise ValueError("number of index positions larger than the total number of indices") pos = tuple(pos) pos_set = set(pos) # If the symmetry is already present, there is nothing to do: @@ -4416,7 +4416,7 @@ def antisymmetrize(self, *pos): if len(pos) < 2: raise ValueError("at least two index positions must be given") if len(pos) > self._nid: - raise ValueError("number of index positions larger than the " "total number of indices") + raise ValueError("number of index positions larger than the total number of indices") pos = tuple(pos) pos_set = set(pos) # If the antisymmetry is already present, there is nothing to do: diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 2a1dd2ecc49..447550d327f 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -961,7 +961,7 @@ def isomorphism_with_fixed_basis(self, basis=None, codomain=None): if codomain_rank != self.rank(): raise ValueError("domain and codomain must have the same rank") if codomain.base_ring() != base_ring: - raise ValueError("domain and codomain must have the same " "base ring") + raise ValueError("domain and codomain must have the same base ring") codomain_basis = Family(codomain.basis()) if isinstance(codomain_basis, TrivialFamily): @@ -1983,7 +1983,7 @@ def basis(self, symbol, latex_symbol=None, from_family=None, indices=None, latex try: resu._init_from_family(from_family) except ZeroDivisionError: - raise ValueError("the provided module elements are not " "linearly independent") + raise ValueError("the provided module elements are not linearly independent") return resu def _test_basis(self, tester=None, **options): @@ -2258,11 +2258,11 @@ def tensor_from_comp(self, tensor_type, comp, name=None, latex_name=None): # 0/ Compatibility checks: if comp._ring is not self._ring: - raise TypeError("the components are not defined on the same" " ring as the module") + raise TypeError("the components are not defined on the same ring as the module") if comp._frame not in self._known_bases: - raise TypeError("the components are not defined on a basis of" " the module") + raise TypeError("the components are not defined on a basis of the module") if comp._nid != tensor_type[0] + tensor_type[1]: - raise TypeError("number of component indices not compatible with " " the tensor type") + raise TypeError("number of component indices not compatible with the tensor type") # 1/ Construction of the tensor: if tensor_type == (1, 0): diff --git a/src/sage/tensor/modules/free_module_automorphism.py b/src/sage/tensor/modules/free_module_automorphism.py index c0aa50cf2eb..2e48372b333 100644 --- a/src/sage/tensor/modules/free_module_automorphism.py +++ b/src/sage/tensor/modules/free_module_automorphism.py @@ -476,7 +476,7 @@ class :class:`~sage.tensor.modules.comp.Components`; if such Kronecker delta of size 3x3 """ if self._is_identity: - raise ValueError("the components of the identity map cannot be " "changed") + raise ValueError("the components of the identity map cannot be changed") return FreeModuleTensor._set_comp_unsafe(self, basis=basis) def add_comp(self, basis=None): @@ -546,7 +546,7 @@ class :class:`~sage.tensor.modules.comp.Components`; Kronecker delta of size 3x3 """ if self._is_identity: - raise ValueError("the components of the identity map cannot be " "changed") + raise ValueError("the components of the identity map cannot be changed") return FreeModuleTensor._add_comp_unsafe(self, basis=basis) def __call__(self, *arg): diff --git a/src/sage/tensor/modules/free_module_tensor.py b/src/sage/tensor/modules/free_module_tensor.py index 9a3242b6175..d3de98daca7 100644 --- a/src/sage/tensor/modules/free_module_tensor.py +++ b/src/sage/tensor/modules/free_module_tensor.py @@ -1263,7 +1263,7 @@ class :class:`~sage.tensor.modules.comp.Components`; if such ValueError: the components of an immutable element cannot be changed """ if self.is_immutable(): - raise ValueError("the components of an immutable element " "cannot be changed") + raise ValueError("the components of an immutable element cannot be changed") self._is_zero = False # a priori return self._set_comp_unsafe(basis) @@ -1396,7 +1396,7 @@ class :class:`~sage.tensor.modules.comp.Components`; ValueError: the components of an immutable element cannot be changed """ if self.is_immutable(): - raise ValueError("the components of an immutable element " "cannot be changed") + raise ValueError("the components of an immutable element cannot be changed") self._is_zero = False # a priori return self._add_comp_unsafe(basis) @@ -1438,7 +1438,7 @@ def del_other_comp(self, basis=None): if basis is None: basis = self._fmodule._def_basis if basis not in self._components: - raise ValueError(f"the components w.r.t. the {basis}" " have not been defined") + raise ValueError(f"the components w.r.t. the {basis} have not been defined") to_be_deleted = [other_basis for other_basis in self._components if other_basis != basis] for other_basis in to_be_deleted: del self._components[other_basis] @@ -1591,7 +1591,7 @@ def copy_from(self, other): False """ if self.is_immutable(): - raise ValueError("the components of an immutable element " "cannot be changed") + raise ValueError("the components of an immutable element cannot be changed") if other not in self.parent(): raise TypeError("the original must be an element " + "of {}".format(self.parent())) self._del_derived() @@ -2964,11 +2964,11 @@ def symmetrize(self, *pos, **kwargs): if pos0 < pos_cov: # pos0 is a contravariant position for k in range(1, len(pos)): if pos[k] >= pos_cov: - raise TypeError(str(pos[0]) + " is a contravariant position, while " + str(pos[k]) + " is a covariant position; \n" "symmetrization is meaningful only on tensor " + "arguments of the same type") + raise TypeError(str(pos[0]) + " is a contravariant position, while " + str(pos[k]) + " is a covariant position; \nsymmetrization is meaningful only on tensor " + "arguments of the same type") else: # pos0 is a covariant position for k in range(1, len(pos)): if pos[k] < pos_cov: - raise TypeError(str(pos[0]) + " is a covariant position, while " + str(pos[k]) + " is a contravariant position; \n" "symmetrization is meaningful only on tensor " + "arguments of the same type") + raise TypeError(str(pos[0]) + " is a covariant position, while " + str(pos[k]) + " is a contravariant position; \nsymmetrization is meaningful only on tensor " + "arguments of the same type") if 'basis' in kwargs: basis = kwargs['basis'] else: @@ -3195,11 +3195,11 @@ def antisymmetrize(self, *pos, **kwargs): if pos0 < pos_cov: # pos0 is a contravariant position for k in range(1, len(pos)): if pos[k] >= pos_cov: - raise TypeError(str(pos[0]) + " is a contravariant position, while " + str(pos[k]) + " is a covariant position; \n" "antisymmetrization is meaningful only on tensor " + "arguments of the same type") + raise TypeError(str(pos[0]) + " is a contravariant position, while " + str(pos[k]) + " is a covariant position; \nantisymmetrization is meaningful only on tensor " + "arguments of the same type") else: # pos0 is a covariant position for k in range(1, len(pos)): if pos[k] < pos_cov: - raise TypeError(str(pos[0]) + " is a covariant position, while " + str(pos[k]) + " is a contravariant position; \n" "antisymmetrization is meaningful only on tensor " + "arguments of the same type") + raise TypeError(str(pos[0]) + " is a covariant position, while " + str(pos[k]) + " is a contravariant position; \nantisymmetrization is meaningful only on tensor " + "arguments of the same type") if 'basis' in kwargs: basis = kwargs['basis'] else: diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index a0a8ee1867d..6e551e4a851 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -320,7 +320,7 @@ def _element_constructor_(self, comp=[], basis=None, name=None, latex_name=None, # Refuse to create a tensor with finer symmetries # than those defining the subspace if not self._is_symmetry_coarsening_of((sym, antisym), self._basis_sym()): - raise ValueError(f"cannot create a tensor with symmetries {sym=}, {antisym=} " f"as an element of {self}") + raise ValueError(f"cannot create a tensor with symmetries {sym=}, {antisym=} as an element of {self}") if sym is None: sym = self._basis_sym()._sym diff --git a/src/sage/tensor/modules/tensor_with_indices.py b/src/sage/tensor/modules/tensor_with_indices.py index 07e70ceb0a0..59d88f5f3c6 100644 --- a/src/sage/tensor/modules/tensor_with_indices.py +++ b/src/sage/tensor/modules/tensor_with_indices.py @@ -7,6 +7,7 @@ - Eric Gourgoulhon, Michal Bejger (2014-2015): initial version - Léo Brunswic (2019): add multiple symmetries and multiple contractions """ + # **************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2015 Michal Bejger @@ -358,9 +359,9 @@ def _parse_indices(indices, tensor_type=None, allow_contraction=True, allow_symm cov_without_sym = cov.replace("(", "").replace(")", "").replace("[", "").replace("]", "") if allow_symmetries: if len(con_without_sym) != len(set(con_without_sym)) + max(con_without_sym.count(".") - 1, 0): - raise ValueError("index conventions not satisfied: " "repeated indices of same type") + raise ValueError("index conventions not satisfied: repeated indices of same type") if len(cov_without_sym) != len(set(cov_without_sym)) + max(cov_without_sym.count(".") - 1, 0): - raise ValueError("index conventions not satisfied: " "repeated indices of same type") + raise ValueError("index conventions not satisfied: repeated indices of same type") else: if re.search(r"[()\[\]]", con) is not None: raise IndexError("no symmetry allowed") @@ -369,9 +370,9 @@ def _parse_indices(indices, tensor_type=None, allow_contraction=True, allow_symm if tensor_type is not None: # Check number of (co/contra)variant indices if len(con_without_sym) != tensor_type[0]: - raise IndexError("number of contravariant indices not compatible " "with the tensor type") + raise IndexError("number of contravariant indices not compatible with the tensor type") if len(cov_without_sym) != tensor_type[1]: - raise IndexError("number of covavariant indices not compatible " "with the tensor type") + raise IndexError("number of covavariant indices not compatible with the tensor type") return con, cov def __init__(self, tensor, indices): diff --git a/src/sage/tests/all.py b/src/sage/tests/all.py index c0f6f2877d5..bc68a398c35 100644 --- a/src/sage/tests/all.py +++ b/src/sage/tests/all.py @@ -1,2 +1 @@ -""" -""" +""" """ diff --git a/src/sage/tests/arxiv_0812_2725.py b/src/sage/tests/arxiv_0812_2725.py index b1f22112a26..687d6472b7d 100644 --- a/src/sage/tests/arxiv_0812_2725.py +++ b/src/sage/tests/arxiv_0812_2725.py @@ -25,6 +25,7 @@ sage: dcrossing([(1,5), (2,4), (4,9), (6,12), (7,10), (10,11)]) 3 """ + # **************************************************************************** # Copyright (C) 2008 Dan Drake # diff --git a/src/sage/tests/benchmark.py b/src/sage/tests/benchmark.py index 3be0d2da84b..83a7d53b210 100644 --- a/src/sage/tests/benchmark.py +++ b/src/sage/tests/benchmark.py @@ -15,6 +15,7 @@ sage: import sage.tests.benchmark """ + import sys if sys.platform != 'win32': diff --git a/src/sage/tests/book_schilling_zabrocki_kschur_primer.py b/src/sage/tests/book_schilling_zabrocki_kschur_primer.py index 028ac5526bf..efd42214cb6 100644 --- a/src/sage/tests/book_schilling_zabrocki_kschur_primer.py +++ b/src/sage/tests/book_schilling_zabrocki_kschur_primer.py @@ -11,6 +11,7 @@ CONTACT Anne Schilling (anne@math.ucdavis.edu) AND Mike Zabrocki (zabrocki@mathstat.yorku.ca) REGARDING THE CHANGES! """ + """ Sage example in ./kschurnotes/notes-mike-anne.tex, line 198:: diff --git a/src/sage/tests/books/judson_abstract_algebra/actions-sage-exercises.py b/src/sage/tests/books/judson_abstract_algebra/actions-sage-exercises.py index 5d44c6b0026..fcd0ea12608 100644 --- a/src/sage/tests/books/judson_abstract_algebra/actions-sage-exercises.py +++ b/src/sage/tests/books/judson_abstract_algebra/actions-sage-exercises.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/actions-sage.py b/src/sage/tests/books/judson_abstract_algebra/actions-sage.py index 010b481f4ba..e5965026b7a 100644 --- a/src/sage/tests/books/judson_abstract_algebra/actions-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/actions-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/algcodes-sage.py b/src/sage/tests/books/judson_abstract_algebra/algcodes-sage.py index 17f304f1868..5677cdea119 100644 --- a/src/sage/tests/books/judson_abstract_algebra/algcodes-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/algcodes-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/boolean-sage.py b/src/sage/tests/books/judson_abstract_algebra/boolean-sage.py index b166765a916..6aa74a60647 100644 --- a/src/sage/tests/books/judson_abstract_algebra/boolean-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/boolean-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/cosets-sage-exercises.py b/src/sage/tests/books/judson_abstract_algebra/cosets-sage-exercises.py index 6b080ddb54c..2e49369007e 100644 --- a/src/sage/tests/books/judson_abstract_algebra/cosets-sage-exercises.py +++ b/src/sage/tests/books/judson_abstract_algebra/cosets-sage-exercises.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/cosets-sage.py b/src/sage/tests/books/judson_abstract_algebra/cosets-sage.py index eefb5d13b55..05046544b18 100644 --- a/src/sage/tests/books/judson_abstract_algebra/cosets-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/cosets-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/crypt-sage.py b/src/sage/tests/books/judson_abstract_algebra/crypt-sage.py index e5dda06b8ca..f34cd8725b4 100644 --- a/src/sage/tests/books/judson_abstract_algebra/crypt-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/crypt-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/cyclic-sage.py b/src/sage/tests/books/judson_abstract_algebra/cyclic-sage.py index 903dbbec237..f354f112a90 100644 --- a/src/sage/tests/books/judson_abstract_algebra/cyclic-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/cyclic-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/domains-sage.py b/src/sage/tests/books/judson_abstract_algebra/domains-sage.py index 207aef13b19..7ef1e444ed5 100644 --- a/src/sage/tests/books/judson_abstract_algebra/domains-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/domains-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/fields-sage.py b/src/sage/tests/books/judson_abstract_algebra/fields-sage.py index b9e79e862ab..21f927b5130 100644 --- a/src/sage/tests/books/judson_abstract_algebra/fields-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/fields-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/finite-sage.py b/src/sage/tests/books/judson_abstract_algebra/finite-sage.py index 31eb51e496f..fe0129a9b51 100644 --- a/src/sage/tests/books/judson_abstract_algebra/finite-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/finite-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/galois-sage.py b/src/sage/tests/books/judson_abstract_algebra/galois-sage.py index bc2c3ddbdeb..29d78d1a26d 100644 --- a/src/sage/tests/books/judson_abstract_algebra/galois-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/galois-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/groups-sage.py b/src/sage/tests/books/judson_abstract_algebra/groups-sage.py index abac30f6db2..a258455364b 100644 --- a/src/sage/tests/books/judson_abstract_algebra/groups-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/groups-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/homomorph-sage-exercises.py b/src/sage/tests/books/judson_abstract_algebra/homomorph-sage-exercises.py index d4d1d88d870..d9db8ee4220 100644 --- a/src/sage/tests/books/judson_abstract_algebra/homomorph-sage-exercises.py +++ b/src/sage/tests/books/judson_abstract_algebra/homomorph-sage-exercises.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/homomorph-sage.py b/src/sage/tests/books/judson_abstract_algebra/homomorph-sage.py index fa0aff64645..b7a2cbd0d49 100644 --- a/src/sage/tests/books/judson_abstract_algebra/homomorph-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/homomorph-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/integers-sage.py b/src/sage/tests/books/judson_abstract_algebra/integers-sage.py index 9cebbc8d5b3..ac24ac5025f 100644 --- a/src/sage/tests/books/judson_abstract_algebra/integers-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/integers-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/isomorph-sage.py b/src/sage/tests/books/judson_abstract_algebra/isomorph-sage.py index 76586f425ee..803e9bd0274 100644 --- a/src/sage/tests/books/judson_abstract_algebra/isomorph-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/isomorph-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/normal-sage.py b/src/sage/tests/books/judson_abstract_algebra/normal-sage.py index fb9e7248629..526b280c5d5 100644 --- a/src/sage/tests/books/judson_abstract_algebra/normal-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/normal-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/permute-sage.py b/src/sage/tests/books/judson_abstract_algebra/permute-sage.py index 7302ae13244..d46c4f3e3ad 100644 --- a/src/sage/tests/books/judson_abstract_algebra/permute-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/permute-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/poly-sage.py b/src/sage/tests/books/judson_abstract_algebra/poly-sage.py index 500b51c9292..5c3ba80c2ad 100644 --- a/src/sage/tests/books/judson_abstract_algebra/poly-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/poly-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/rings-sage.py b/src/sage/tests/books/judson_abstract_algebra/rings-sage.py index d836eb7299a..0a102814a0d 100644 --- a/src/sage/tests/books/judson_abstract_algebra/rings-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/rings-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/sets-sage.py b/src/sage/tests/books/judson_abstract_algebra/sets-sage.py index a3f6cb296f1..087d7d722ca 100644 --- a/src/sage/tests/books/judson_abstract_algebra/sets-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/sets-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/struct-sage.py b/src/sage/tests/books/judson_abstract_algebra/struct-sage.py index 8b880ec0616..88090b15cf2 100644 --- a/src/sage/tests/books/judson_abstract_algebra/struct-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/struct-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/sylow-sage.py b/src/sage/tests/books/judson_abstract_algebra/sylow-sage.py index 762efeaba3a..ab499921063 100644 --- a/src/sage/tests/books/judson_abstract_algebra/sylow-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/sylow-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/vect-sage-exercises.py b/src/sage/tests/books/judson_abstract_algebra/vect-sage-exercises.py index ee07c30e0e2..e983c134345 100644 --- a/src/sage/tests/books/judson_abstract_algebra/vect-sage-exercises.py +++ b/src/sage/tests/books/judson_abstract_algebra/vect-sage-exercises.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/tests/books/judson_abstract_algebra/vect-sage.py b/src/sage/tests/books/judson_abstract_algebra/vect-sage.py index 174e7f6043e..8407e491b3a 100644 --- a/src/sage/tests/books/judson_abstract_algebra/vect-sage.py +++ b/src/sage/tests/books/judson_abstract_algebra/vect-sage.py @@ -18,6 +18,7 @@ updated, and a replacement of this file is proposed for review. """ + ## ## To execute doctests in these files, run ## $ $SAGE_ROOT/sage -t diff --git a/src/sage/topology/cubical_complex.py b/src/sage/topology/cubical_complex.py index c836b43e3f8..2e17bd02153 100644 --- a/src/sage/topology/cubical_complex.py +++ b/src/sage/topology/cubical_complex.py @@ -67,6 +67,7 @@ see the :mod:`Generic Cell Complex ` page instead. """ + from copy import copy from functools import total_ordering diff --git a/src/sage/topology/simplicial_set.py b/src/sage/topology/simplicial_set.py index 4a1edf8ca1e..28aa971bd6e 100644 --- a/src/sage/topology/simplicial_set.py +++ b/src/sage/topology/simplicial_set.py @@ -384,7 +384,7 @@ def __init__(self, dim, degeneracies=(), underlying=None, name=None, latex_name= self._degens = standardize_degeneracies(*degeneracies) for d, s in enumerate(reversed(self._degens)): if d + dim < s: - raise ValueError('invalid list of degeneracy maps ' 'on {}-simplex'.format(dim)) + raise ValueError('invalid list of degeneracy maps on {}-simplex'.format(dim)) if underlying is None: self._underlying = NonDegenerateSimplex(dim) else: @@ -1208,7 +1208,7 @@ def face(self, simplex, i): True """ if i < 0 or i > simplex.dimension(): - raise ValueError('cannot compute face {} of {}-dimensional ' 'simplex'.format(i, simplex.dimension())) + raise ValueError('cannot compute face {} of {}-dimensional simplex'.format(i, simplex.dimension())) faces = self.faces(simplex) if faces is not None: return self.faces(simplex)[i] @@ -1287,7 +1287,7 @@ def alexander_whitney(self, simplex, dim_left): """ dim = simplex.dimension() if dim_left < 0 or dim_left > dim: - raise ValueError('alexander_whitney is only valid if dim_left ' 'is between 0 and the dimension of the simplex') + raise ValueError('alexander_whitney is only valid if dim_left is between 0 and the dimension of the simplex') left = simplex for i in range(dim, dim_left, -1): left = self.face(left, i) @@ -1366,7 +1366,7 @@ def nondegenerate_simplices(self, max_dim=None): return list(self._simplices) return [sigma for sigma in self._simplices if sigma.dimension() <= max_dim] if max_dim is None: - raise NotImplementedError('this simplicial set may be ' 'infinite, so specify max_dim') + raise NotImplementedError('this simplicial set may be infinite, so specify max_dim') return list(self.n_skeleton(max_dim)._simplices) def cells(self, subcomplex=None, max_dim=None): @@ -1438,7 +1438,7 @@ def cells(self, subcomplex=None, max_dim=None): return {d: sorted(simplices[d]) for d in simplices} # Infinite case: if max_dim is None: - raise NotImplementedError('this simplicial set may be ' 'infinite, so specify max_dim') + raise NotImplementedError('this simplicial set may be infinite, so specify max_dim') return self.n_skeleton(max_dim).cells() # subcomplex is not None: return self.quotient(subcomplex).cells(max_dim=max_dim) @@ -1926,7 +1926,7 @@ def chain_complex(self, dimensions=None, base_ring=ZZ, augmented=False, cochain= kwds = {'base_ring': base_ring, 'augmented': augmented, 'cochain': cochain, 'verbose': verbose, 'subcomplex': subcomplex, 'check': check} if not self.is_finite(): if dimensions is None: - raise NotImplementedError('this simplicial set may be infinite, ' 'so specify dimensions when computing ' 'its chain complex') + raise NotImplementedError('this simplicial set may be infinite, so specify dimensions when computing its chain complex') else: max_dim = max(dimensions) return SimplicialSet_finite.chain_complex(self.n_skeleton(max_dim + 1), dimensions=dimensions, **kwds) @@ -1993,7 +1993,7 @@ def homology(self, dim=None, **kwds): """ if not self.is_finite(): if dim is None: - raise NotImplementedError('this simplicial set may be infinite, so ' 'specify dimensions when computing homology') + raise NotImplementedError('this simplicial set may be infinite, so specify dimensions when computing homology') else: if isinstance(dim, (list, tuple, range)): dim = list(dim) @@ -2390,7 +2390,7 @@ def coproduct(self, *others): if self.is_pointed() and all(X.is_pointed() for X in others): return self.wedge(*others) if self.is_pointed() or any(X.is_pointed() for X in others): - raise ValueError('some, but not all, of the simplicial sets are pointed, ' 'so the categorical coproduct is not defined: the ' 'category is ambiguous') + raise ValueError('some, but not all, of the simplicial sets are pointed, so the categorical coproduct is not defined: the category is ambiguous') return self.disjoint_union(*others) def product(self, *others): @@ -3274,15 +3274,15 @@ def face(sigma, i): elif isinstance(data, SimplicialSet_finite): data = dict(copy.deepcopy(data._data)) else: - raise NotImplementedError('I do not know how to convert this ' 'to a simplicial set') + raise NotImplementedError('I do not know how to convert this to a simplicial set') # Convert each value in data to a tuple, and then convert all # of data to a tuple, so that it is hashable. for x in data: if data[x]: if x.dimension() != len(data[x]) - 1: - raise ValueError('wrong number of faces for simplex ' 'in dimension {}'.format(x.dimension())) + raise ValueError('wrong number of faces for simplex in dimension {}'.format(x.dimension())) if not all(y.dimension() == x.dimension() - 1 for y in data[x]): - raise ValueError('faces of a {}-simplex have the wrong ' 'dimension'.format(x.dimension())) + raise ValueError('faces of a {}-simplex have the wrong dimension'.format(x.dimension())) data[x] = tuple(data[x]) # To obtain the non-degenerate simplices, look at both the @@ -3307,7 +3307,7 @@ def face(sigma, i): for j in range(d + 1): for i in range(j): if face(face(sigma, j), i) != face(face(sigma, i), j - 1): - raise ValueError('simplicial identity d_i d_j ' '= d_{{j-1}} d_i fails ' 'in dimension {}'.format(d)) + raise ValueError('simplicial identity d_i d_j = d_{{j-1}} d_i fails in dimension {}'.format(d)) # Now define the attributes for an instance of this class. # self._data: a tuple representing the defining data of the @@ -3318,7 +3318,7 @@ def face(sigma, i): # self._basepoint: the base point, or None. if base_point is not None: if base_point not in simplices: - raise ValueError('the base point is not a simplex in ' 'this simplicial set') + raise ValueError('the base point is not a simplex in this simplicial set') if base_point.dimension() != 0: raise ValueError('the base "point" is not a zero-simplex') self._basepoint = base_point diff --git a/src/sage/topology/simplicial_set_constructions.py b/src/sage/topology/simplicial_set_constructions.py index d8195c8878e..60c549f7843 100644 --- a/src/sage/topology/simplicial_set_constructions.py +++ b/src/sage/topology/simplicial_set_constructions.py @@ -950,7 +950,7 @@ def factor(self, i, as_subset=False): """ if as_subset: if any(not _.is_pointed() for _ in self.factors()): - raise ValueError('"as_subset=True" is only valid ' 'if each factor is pointed') + raise ValueError('"as_subset=True" is only valid if each factor is pointed') basept_factors = [sset.base_point() for sset in self.factors()] basept_factors = basept_factors[:i] + basept_factors[i + 1 :] @@ -1564,7 +1564,7 @@ def __init__(self, maps=None, vertex_name=None): elif all(f.is_pointed() for f in maps): pt = _to_P[(codomains[0], 0)][codomains[0].base_point()] if any(_to_P[(Y, i)][Y.base_point()] != pt for Y, i in spaces[2:]): - raise ValueError('something unexpected went wrong ' 'with base points') + raise ValueError('something unexpected went wrong with base points') base_point = _to_P[(domain, -1)][domain.base_point()] if vertex_name is not None: base_point.rename(vertex_name) diff --git a/src/sage/topology/simplicial_set_morphism.py b/src/sage/topology/simplicial_set_morphism.py index 1eee45c0598..b7d93767759 100644 --- a/src/sage/topology/simplicial_set_morphism.py +++ b/src/sage/topology/simplicial_set_morphism.py @@ -201,7 +201,7 @@ def constant_map(self, point=None): if codomain.is_pointed(): point = codomain.base_point() else: - raise ValueError('codomain is not pointed, so specify a ' 'target for the constant map') + raise ValueError('codomain is not pointed, so specify a target for the constant map') return SimplicialSetMorphism(domain=self.domain(), codomain=self.codomain(), constant=point) def an_element(self): @@ -278,7 +278,7 @@ def __iter__(self): ] """ if not self.domain().is_finite(): - raise NotImplementedError('domain must be finite to iterate ' 'through all morphisms') + raise NotImplementedError('domain must be finite to iterate through all morphisms') codomain = self.codomain() facets = self.domain()._facets_() dims = [f.dimension() for f in facets] @@ -458,7 +458,7 @@ def __init__(self, data=None, domain=None, codomain=None, constant=None, identit self._constant = constant Morphism.__init__(self, Hom(domain, codomain, SimplicialSets())) return - raise NotImplementedError('morphisms with infinite domain ' 'are not implemented in general') + raise NotImplementedError('morphisms with infinite domain are not implemented in general') else: if identity: self._is_identity = True @@ -477,7 +477,7 @@ def __init__(self, data=None, domain=None, codomain=None, constant=None, identit if not isinstance(domain, SimplicialSet_arbitrary) or not isinstance(codomain, SimplicialSet_arbitrary): raise TypeError('the domain and codomain must be simplicial sets') if any(x.nondegenerate() not in domain.nondegenerate_simplices() for x in data.keys()): - raise ValueError('at least one simplex in the defining ' 'dictionary is not in the domain') + raise ValueError('at least one simplex in the defining dictionary is not in the domain') # Remove degenerate simplices from the domain specification. d = {sigma: data[sigma] for sigma in data if sigma.is_nondegenerate()} # For each simplex in d.keys(), add its faces, and the faces @@ -530,7 +530,7 @@ def __init__(self, data=None, domain=None, codomain=None, constant=None, identit if bad: raise ValueError('the dictionary does not define a map of simplicial sets') if any(x not in d.keys() for x in domain.nondegenerate_simplices()): - raise ValueError('the image of at least one simplex in ' 'the domain is not defined') + raise ValueError('the image of at least one simplex in the domain is not defined') self._dictionary = d Morphism.__init__(self, Hom(domain, codomain, SimplicialSets())) diff --git a/src/sage/typeset/character_art.py b/src/sage/typeset/character_art.py index 0e5db41c08e..999ad078b79 100644 --- a/src/sage/typeset/character_art.py +++ b/src/sage/typeset/character_art.py @@ -35,7 +35,6 @@ class CharacterArt(SageObject): - def __init__(self, lines=[], breakpoints=[], baseline=None) -> None: r""" Abstract base class for character art. @@ -307,7 +306,7 @@ def __next__(self): except StopIteration: bp_next = None if bp_next is None or isinstance(bp_next, tuple): - raise ValueError("nested structure must be followed by a " "regular breakpoint") + raise ValueError("nested structure must be followed by a regular breakpoint") if bp_next - idx > size: # substructure is too wide for the current line, so force a # line break @@ -359,7 +358,7 @@ def _split_repr_(self, size) -> str: if bp - idx > size: import warnings - warnings.warn("the console size is smaller than the pretty " "representation of the object") + warnings.warn("the console size is smaller than the pretty representation of the object") # Note that this is faster than calling self.split() repeatedly parts.append('\n'.join(line[idx:bp] for line in self)) idx = bp diff --git a/src/sage/typeset/character_art_factory.py b/src/sage/typeset/character_art_factory.py index 137189b068f..43d9c11dd45 100644 --- a/src/sage/typeset/character_art_factory.py +++ b/src/sage/typeset/character_art_factory.py @@ -21,7 +21,6 @@ class CharacterArtFactory(SageObject): - def __init__(self, art_type, string_type, magic_method_name, parenthesis, square_bracet, curly_brace): r""" Abstract base class for character art factory. @@ -470,7 +469,7 @@ def padded_line(obj, i): if not bk_sep: bk_sep = [separator._l] if nested and isinstance(bk_sep[0], tuple): - raise ValueError("nested structure must be followed by a " "regular breakpoint") + raise ValueError("nested structure must be followed by a regular breakpoint") idx = None for obj in iterable: if idx is None: diff --git a/src/sage/typeset/symbols.py b/src/sage/typeset/symbols.py index 4225be430e5..b69c9f8c5b0 100644 --- a/src/sage/typeset/symbols.py +++ b/src/sage/typeset/symbols.py @@ -57,7 +57,6 @@ class CompoundSymbol(SageObject): - def __init__(self, character, top, extension, bottom, middle=None, middle_top=None, middle_bottom=None, top_2=None, bottom_2=None): """ A multi-character (ascii/unicode art) symbol. @@ -187,7 +186,6 @@ def print_to_stdout(self, num_lines): class CompoundAsciiSymbol(CompoundSymbol): - def character_art(self, num_lines): """ Return the ASCII art of the symbol. @@ -206,7 +204,6 @@ def character_art(self, num_lines): class CompoundUnicodeSymbol(CompoundSymbol): - def character_art(self, num_lines): """ Return the unicode art of the symbol. diff --git a/src/sage/typeset/unicode_characters.py b/src/sage/typeset/unicode_characters.py index c2662b8cab1..463a4903303 100644 --- a/src/sage/typeset/unicode_characters.py +++ b/src/sage/typeset/unicode_characters.py @@ -79,11 +79,11 @@ unicode_otimes = '\u2297' # '⊗' -unicode_bigotimes = '\u2A02' # '⨂' +unicode_bigotimes = '\u2a02' # '⨂' unicode_wedge = '\u2227' # '∧' -unicode_bigwedge = '\u22C0' # '⋀' +unicode_bigwedge = '\u22c0' # '⋀' unicode_partial = '\u2202' # '∂' @@ -91,10 +91,10 @@ unicode_to = '\u2192' # '→' -unicode_mapsto = '\u21A6' # '↦' +unicode_mapsto = '\u21a6' # '↦' # Letters: -unicode_mathbbR = '\u211D' # 'ℝ' +unicode_mathbbR = '\u211d' # 'ℝ' unicode_mathbbC = '\u2102' # 'ℂ'
' + '%s
' % (row[index], p) + '